Skip to content

Releases: NovaRagnarok/RepoGarden

v0.9.1

18 May 03:32
2b582df

Choose a tag to compare

[0.9.1] — 2026-05-17

Added

  • New <ScrollBar> component (src/components/ui/scroll-bar.tsx) lifted out of the TextArea's inline scroll indicator. Both the notes editor and the journal event list consume it.

Changed

  • Journal view now uses a two-pane focus model. ↑↓ (and j/k as aliases) scroll whichever pane currently has focus — the sidebar repo list or the event list. Esc toggles between panes (clearing an active filter first). Enter from the sidebar drills into the event pane instead of jumping out to the workbench; workbench access stays one keystroke away via g to garden or shelf, where Enter still opens it.
  • High Contrast theme's focus ring is now cyan (#00FFFF) instead of yellow (#FFFF00) so a focused pane border no longer shares its hue with warning. Still 16.7:1 on black, well above AA.
  • The ★ RepoGarden Credit footer no longer appends a literal (URL) fallback on terminals without OSC-8 hyperlink support — the brand mark stays on one line on narrow hotbars (Settings, Help, etc.). Hyperlink-capable terminals still get the clickable link.

Fixed

  • Journal text no longer keeps stale characters after a transition. DitherOverlay was painting "stars" over the journal area via absolute-cursor escape sequences written directly to stdout, then erasing them by writing spaces at the same screen positions. The spaces overwrote whatever Ink had rendered, and Ink's diff cache didn't repaint. Rewritten to render the stars as Ink children so the natural unmount path reconciles the cells back.
  • Single Escape now reliably closes the workbench, help, settings, usage, and edit-roots screens. The mouse and focus parsers held a trailing \x1b in a pending buffer waiting for a follow-up byte that disambiguates it (so split SGR-mouse sequences don't leak as Esc keystrokes). With no follow-up the byte sat forever. A 30 ms timer in cli-main.tsx now flushes both parsers' pending buffers after each chunk, so a paused Esc resolves on its own.
  • Workbench overview no longer renders the value on top of the label, the section tabs no longer fuse with the "1 file changed" alert at small heights, the snapshot / top-actions panels keep their borders, and the help overlay's ┌─┐ key boxes render with full top and bottom borders. Single shared root cause: Yoga's default flexShrink=1 was letting overflow="hidden" ancestors squeeze multi-row bordered children below their natural row count. flexShrink={0} applied to Panel, Badge, the workbench section rows, and the KeyboardShortcuts grid.
  • Onboarding scan-path input renders its content row (prompt + cursor) inside the box instead of on the bottom border. minHeight={3} on the bordered wrapper.
  • Toasts sit inside the garden panel instead of straddling its bottom border. Toaster marginTop bumped from rows - 7 to rows - 9; the constant is hoisted to module scope (TOASTER_MARGIN_TOP) so the paint mask below reads from one source of truth.
  • Garden engine's direct-stdout star/sprite painter no longer overpaints Ink-rendered toasts. New paintExclusions API on GardenSceneProps: a list of canvas-local rects whose cells the renderer marks transparent. The diff writer and setCell both short-circuit on transparent, and blockStarsForOverlays skips star-gen work entirely for excluded cells. ReadyShell derives the toast rect from useToasts().active and the shared layout constants, in canvas-local coords, and threads it through to both GardenView call sites.
  • Journal event-summary no longer leaves a stale tail (shipped "Refresh live mobile data on focus"ences") when a long previous-frame summary contracts. Variable-length truncate(eventSummary(...), summaryWidth) swapped for fixed-width padTrunc(...) so the Text length is constant between frames.

Internal

  • flushPending / hasPending exports on src/lib/mouse.ts and src/lib/focus.ts; cli-main schedules the 30 ms flush timer.
  • Toast layout knobs (TOASTER_MARGIN_TOP, TOAST_MAX_VISIBLE, TOAST_ROWS_EACH, TOAST_WIDTH_PADDING) hoisted to module-level constants in ReadyShell.tsx.
  • scripts/tui-observe.sh send now accepts any single printable char, C-* chords, Tab / Space synonyms, and text:<string> for literal multi-char input — enough to drive every surface from the harness.
  • End-to-end QA report at docs/manual-qa-report.md with the inventory, root causes, and verification captures for every bug fixed this release.
  • Test count: 491 → 497 (one new regression test covers the bare-Escape flush).

v0.9.0 - release candidate readiness

16 May 20:59
b6b74b3

Choose a tag to compare

Highlights

RepoGarden 0.9 is the release-candidate cut for real users before v1. It keeps the local-first posture, tightens packaging, repairs the live TUI harness, and adds smoke coverage for the real app shell.

Added

  • REPOGARDEN_REDUCED_MOTION=1 now forces reduced motion for a single run without changing saved settings.
  • CI now runs a real tmux-backed TUI smoke on Ubuntu so first-run and ready-screen regressions get caught outside unit tests.

Changed

  • User-facing docs now describe the local-first 0.9 release-candidate line, including the supported ~/.repogarden storage location and migration expectation.
  • First-run and creature-system copy now use the current awake / happy / stuck / sleepy vocabulary.
  • Claude/Codex usage bars are opt-in for fresh installs.
  • Shelf dividers now explain each vibe group: active changes, flowing, blockers to clear, quiet lately.
  • Workbench note-save feedback now distinguishes regular notes, blocker notes, and note-to-future-self notes.

Fixed

  • Release builds now clean dist/ before compiling so local packs cannot include stale ignored artifacts.
  • The CLI now exits early with a clear Node 24+ requirement message on unsupported Node versions.
  • The live TUI observation harness now accepts the documented pnpm observe:tui -- start form and submits the disposable ~/repos/root scan path on first run.

Validation

  • pnpm typecheck
  • pnpm test - 491 passing
  • pnpm build
  • pack/install smoke from the generated tarball
  • PR CI green across Ubuntu, macOS, Windows, and pack-smoke

See CHANGELOG.md for the full notes.


npm install -g @outsideheaven/repogarden

v0.8.0 — drag reliability round 2 + garden polish

16 May 00:23

Choose a tag to compare

Highlights

Round 2 of drag-and-drop reliability lands the interaction properly, with garden-rendering polish on top. Eight fixes — five drag-related, three visual.

Fixes

  • 🖱️ Drag survives any mid-flight re-render. syncGardenModel used to wipe dragPreviewPlacements and reset every wander state's manualOffset on every call. Combined with engineProps churning constantly (callbacks declared inline in cli.tsx), every parent re-render killed the in-flight drag. A toast appearing, a 30s background scan, a focus change — all enough to silently undo a drag mid-motion. The sync now carries dragPreviewPlacements across, and engine.setProps skips the sync entirely when only callback identities changed.
  • 🎯 Drag commit math no longer bakes in the wander bob. Press recorded grabX from the visual position (which includes the transient wander bob, up to ±2 cells), then commit math used the anchor — so single-cell drags landed 1–2 cells off the cursor's release point. Press now subtracts the wander offset, so cursor delta equals committed offset exactly.
  • 📐 Stale chrome measurement + post-tick hit-test miss. Two more drag misses: cached chrome row height was reused after layout shifts that changed it, and the 100ms wander tick could move a creature between paint and click so findCreatureDragHandleAtCell missed. Engine remeasures chrome on every press and falls back to a hit-test against the last-rendered snapshot.
  • 🧹 Pre-existing scene overlap no longer vetoes unrelated drags. When two creatures were already clipping somewhere in the scene, the drag solver refused any new motion until the unrelated overlap resolved itself. Body-overlap state is now scoped to the drag's footprint and immediate neighbours.
  • 🪟 Dismissing the focus card returns the bottom-right corner to the garden. Pressing c to hide the focus card used to leave the bottom-right slot reserved as a dead zone forever — creatures couldn't wander or be dragged into it. The dead zone now releases when the card is dismissed.
  • 🏷️ Names no longer disappear near the bottom of the garden. The wander/drag clamp reserved one row below the sprite, but the name strip is two rows (gap + name). Any creature that wandered or got dragged to within ~2 rows of the bottom border lost its name to a silent setCell bounds drop.
  • 🔲 Selection box hugs the visible creature instead of the sprite bounding box. The focus frame was sized to charW × charH (the sprite generator's full grid), but the body window typically allocates only 54–74% of that height and the contour walk doesn't fill every column either — so the box was puffed up with a row or two of empty cells. Now scans both animation frames for lit sub-pixels and shrinks to their union; stable through the body-bob.

Internal

  • Test count: 445 → 462.

See CHANGELOG.md for the full notes.


npm install -g @outsideheaven/repogarden

v0.7.0 — source-mass sizing, wide creatures, reliable drag

15 May 20:00

Choose a tag to compare

Highlights

  • 📐 Creature size now reflects source-file mass, not git activity. Mass = lines of code + file count, with commit count kept only as a faint 0.08 tiebreaker. Vitality signals (recent commits, ahead/behind, dirty) are dropped from the size formula — they belong to mood/confidence, not size. Files larger than 1 MB are estimated as bytes/40 so an accidentally-committed dump can't make the phase crawl. Markdown counts toward primaryLanguage detection but not toward mass, so a docs-heavy repo reports as "Markdown" without inflating its creature.
  • 🪜 Rank-based cohort scaling. The smallest repo in your garden lands at normalised 0, the largest at 1, and everyone in between spreads evenly regardless of how raw mass values bunch. The old value-relative formula crammed all small repos near 0 whenever a few large outliers stretched the range. Re-audited on a 32-repo tree: area ratio bumped from 4.25x to 5.67x, with mid-rank repos correctly growing because rank places them above the small cluster.
  • 📏 Size ceiling raised so the top of the cohort reads as chunky. maxArea 130 → 180, charW clamp 18 → 20, charH clamp 9 → 11. The biggest creatures now spread across 17x10 / 18x10 / 20x9 instead of all crowding at 17x8; small and mid creatures barely move thanks to the sqrt area→dim path.
  • 🧵 Cohort threaded into focus popup and workbench sprite. Pre-fix, the same creature was a different size in the garden vs. the focus popup vs. the workbench because the popup/workbench fell through to the absolute-only sizing path. CreatureSprite / ReadyShell / WorkbenchScreen now all accept and use the cohort.
  • 🐎 Wider-than-tall aspect bucket. A new 4th aspect bucket at cell aspect 3.2–4.4 (visual 1.6–2.2) carves 15% of rolls into genuinely horizontal silhouettes — sausage cats, not square cats with a slight tilt. The body generator and fill-bias were retuned for wide grids so a 14x3 bucket paints a wide body instead of a tall body squashed into 4–6 centre cells. Square / portrait creatures look identical to before.

Fixes

  • 🖱️ Creature drag commits reliably on release. Two bugs combined to make click-and-drag feel intermittent: the release path threw away the squishy preview when no drag step ever resolved strict (e.g. dragging onto a packed neighbour), and a missed release event (cursor left the terminal) plus a fresh press would clear the drag without committing. Release now falls back through strict@release → last strict-clean step → squishy@release → last squishy step, and a press while a drag is still live commits the prior drag's recoverable state first.
  • 🐛 Density no longer silently reshapes creatures. Density now only affects pagination (how many creatures fit per page) and shelf-row spacing — never an individual creature's size or shape. When clipping to slot bounds is genuinely needed, the clip is uniform-scale so horizontal creatures stay horizontal instead of collapsing into near-squares.

Internal

  • Scan cache schema bumps 1 → 2 to drop pre-source-mass entries. Old cache entries without sourceLines/fileCount would otherwise size every cached repo by its commit count until each happened to get re-scanned. One slow scan after upgrade.
  • Test count: 443 → 445.

See CHANGELOG.md for the full notes.


```sh
npm install -g @outsideheaven/repogarden
```

v0.6.1 — optional terminal bell on vibe flips

15 May 07:52

Choose a tag to compare

Highlights

  • 🔔 Optional terminal bell on vibe flips. New b toggle in Settings (and bellOnVibeChange in ~/.repogarden/tui.json, default off). When a live scan picks up a vibe transition on a repo that existed before, RepoGarden emits a single BEL (\x07). Gated on the ready phase so boot-time streaming partials and the workbench focus surface don't bell-storm; new repos don't count; one BEL per change-batch regardless of how many repos flipped. The journal still records the per-repo vibe-changed events for the detail the bell omits.

Docs

  • README now documents the existing reduced-motion mode: open Settings (s) and press m, or set NO_MOTION=1 (or CI=true) for a single run. The feature shipped earlier and is wired through theme-provider.tsx's useMotion() — garden tween/wander, dither cross-fade, boot scene, spinner, skeleton, privacy scramble, and the settings star animation all respect it.

Internal

  • Settings prefs panel grew a sixth row; compactMode threshold bumped from rows < 33 to < 34 and non-compact reservedRows from 29 to 30 so the new row never clips on short terminals.
  • Stale "reduced-motion mode" line pruned from `BACKLOG.md` Priority B.

See CHANGELOG.md for the full notes.


```sh
npm install -g @outsideheaven/repogarden
```

v0.6.0 — GIF/text export, mood + confidence, parallel scan + cache

14 May 20:17

Choose a tag to compare

Highlights

  • 🎬 Share the habitat. Press x in garden/shelf to export an animated GIF of the current page to ~/Downloads; press t to copy a plain-UTF-8 frame to the clipboard (Markdown-fenced, with a --discord paste-budget fitter on the matching repogarden export-text CLI). Native pixel-art rendering — no external tools.
  • 🌱 Mood + confidence axes layered onto the 4-state vibe: curious / excited / proud / anxious / confused / lonely / content, derived from blocker, ahead/behind, commit burst vs. baseline, and visit recency. Surfaces as a chip in the workbench portrait and as mood-changed journal events with a 24h per-repo cool-off. Closes the §5.1 "flagged for recovery" item.
  • Parallel + cached repo scan. Rebuilt scanRootsProgressive into a four-phase pipeline with a persistent on-disk cache at ~/.repogarden/scan-cache.json. Cold cache paints names in ~150ms (12×); warm cache lands the full 37-repo scan in ~130ms (14×). Closes #21.

Fixes

  • NOTES Backspace freeze (#16)
  • Esc-as-quit collision + mouse-sequence Esc leak (#17)
  • TextArea cursor preserved across PORTRAIT ↔ NOTES flips (#23)
  • TextArea cursor math indexes graphemes, not UTF-16 code units — emoji/ZWJ/flag-pair safe (#24)
  • Settings preference rows individually clickable with left-gutter indicators (#15)
  • Short-terminal Settings no longer clips preferences off the bottom
  • README ASCII preview replaced with a rasterised PNG so GitHub's code-font fallback can't drift the borders

Internal

  • New modules: scan-cache.ts, workbench-mode.ts
  • Mood layer additive on VibeResult; SnapEntry extended with optional mood + moodAt, legacy snapshots round-trip
  • scripts/bench-scan.ts for runnable scan perf checks
  • friend-alpha label/template retired
  • Test count: 356 → 443

See CHANGELOG.md for the full notes.


npm install -g @outsideheaven/repogarden

v0.5.0 — pagination, density, vibe rename, onboarding affordances

14 May 08:58

Choose a tag to compare

Changed

  • Vibe vocabulary renamed for clarity: noisy → awake (recent local changes — the optimum/most-engaged state) and blocked → stuck (user-flagged blocker). happy (clean + in sync) and sleepy (long quiet) unchanged. Shelf display order flipped so awake sits at the top — the shelf reads top-down as "most engaged → least." Existing journals and scan snapshots written under the old vocabulary keep rendering correctly: loadScanSnapshot migrates "noisy"/"blocked" on read, and event-summary.ts normalises legacy from/to payloads before looking up the transition verb.
  • fakeName mixes casing styles alongside word count. Output is now ~50% kebab (plum-thistle), ~20% PascalCase (PlumThistle), ~20% camelCase (plumThistle), ~10% capitalised-kebab (Plum-thistle). Reads more like the spectrum of real repo names instead of a visibly templated set. Composition stays grammatical (noun alone, adj+noun, adj+adj+noun) and the 20/60/20 word-count split is unchanged.

Fixed

  • Wandering creatures no longer overlap a dragged neighbour once it settles. resolvePushPlacements now initialises its simulation from each creature's rest position (anchor + persistent/manual offset, with the transient wander bob stripped), so a drag past a wanderer mid-cycle doesn't get certified clear only to collide once the wander envelope returns to zero. syncVisualPlacements also gained a Chebyshev-ring nearest-clear-cell search that fires before the bare-anchor fallback, so a wanderer whose anchor was claimed by a manual offset gets nudged out of the way instead of silently landing on top.
  • Shelf vibes no longer bleed into each other when one bucket overflows. lineUpCreatures was rewritten with proportional vertical allocation: each vibe gets ceil(count / cols) rows trimmed against the canvas budget, with a min of 1 row per rendered shelf. Tiles beyond the budget collapse into a single +N more indicator painted in the shelf's accent colour. Pre-fix, a happy bucket of 30 repos on a tight canvas would wrap past its strip and crash into the next vibe's divider; the bug also masked a nudgeRow interaction where dead-zone hops shifted tiles vertically but not the divider plan.
  • Shelf centring drops to left-align when it would clip the focus card. Partial rows are still centred by default, but the row offset zeroes out when the centred slot's right edge would intersect the bottom-right dead zone. Slots that still collide fold into the same +N more tally rather than getting hopped into the next vibe's rows.

Added

  • Pagination toggle + density setting. Two new persistent settings in ~/.repogarden/tui.json:
    • gardenPaginate (default true) — when off, the whole creature list lands on one page and the placer's graceful-degradation handles dense packing. For users who like seeing every repo at once instead of paging through.
    • gardenDensity ("cozy" | "comfortable" | "dense", default "comfortable") — controls per-page slot dims in garden mode and per-cell breathing room in shelf mode. comfortable matches the pre-0.5.0 visuals exactly; cozy is roomier (fewer per page / row), dense is tighter (~50% more before pagination kicks in). Threaded through gardenPageCapacity and lineUpCreatures.
    • Settings UI: p toggles pagination, g cycles density. Both render their current state next to m/u/o in the preferences panel.
  • Mask wordlists expanded with new texture / sound / scent adjectives (muffled, whispery, loamy, piney, peachy, sage, …) and time-of-day / water creature / textile nouns (gloaming, dawnling, pollywog, eft, bobbin, darning, …). ADJECTIVES 140 → 206, NOUNS 145 → 225. Duplicate "ember" deduped from NOUNS (it sat in both the lantern group and the kindling group).
  • Demo roster doubled from 16 to 32 names (acorn-rs, sprout-db, mothbot, reed-cli, driftlog, pebble-ci, clover-api, ripple-cms, nestwatch, twig-deploy, garden-lint, puddle-map, wrenpress, loamkit, lichen-sync, dawnqueue). buildDemoNameMap now won't hit the -2 cycle suffix until 33+ creatures, and the settings preview garden fills the shelf with a more populated cast. DEMO_BRANCHES 10 → 16, DEMO_SUBJECTS 16 → 32, DEMO_AUTHORS 6 → 10 to keep per-id hashing variety proportional.

Internal

  • New restPlacementFor helper in src/garden/model.ts (anchor + effectivePersistentOffset, transient currentOffset deliberately excluded). New findNearestClearPlacement walks Chebyshev rings outward from a base placement, bounded by canvas dimensions. resolvePushPlacements initialises its placements map via restPlacementFor rather than visualPlacements.get(...) so push decisions don't rely on transient wander bob.
  • New ShelfOverflow type in src/lib/garden-layout.ts; ShelfLayout.overflows carries { vibe, canvasRow, canvasCol, slotW, hidden } per shelf that truncated. GardenScene plumbs the array through to renderGardenFrame, which paints each +N more marker in dividerLabelColor(vibe) and clips the label to slotW. placeCreatures (organic mode) returns overflows: [] for type compatibility.
  • New migrateLegacyVibe helper in src/lib/events.ts runs in normalizeSnapEntry to coerce "noisy" → "awake" and "blocked" → "stuck" at snapshot read time. New normaliseLegacyVibe in src/lib/event-summary.ts runs before the vibeTransitionVerb switch so historical vibe-changed events still hit the right verb (got busy, back in flow, etc.).
  • Vibe type is now "awake" | "happy" | "stuck" | "sleepy". VIBE_ORDER is ["awake", "happy", "stuck", "sleepy"]. The canonical creature sort in src/lib/creature.ts and the post-save resort in cli.tsx mirror that order. VIBE_WANDER / VIBE_WIGGLE keys, dividerLabelColor, vibeBadgeVariant, and the per-screen colour ternaries in ReadyShell.tsx / JournalView.tsx / SettingsScreen.tsx were updated in lockstep. JournalView keeps the colour mapping permissive against unknown future vibe strings via the vibeTarget typed signal alone.
  • New GardenDensity type exported from src/lib/garden-layout.ts; consumed by gardenPageCapacity, lineUpCreatures, GardenSceneProps.density, and the new settings flow. Per-density tables: SHELF_EXTRA_PAD and PAGE_SLOT_DIMS. comfortable matches the pre-0.5.0 constants so the default visual is unchanged.
  • New tests: loadScanSnapshot migrates legacy noisy/blocked vibe strings on read (events) writes a snapshot file directly with the pre-rename vocab and asserts the loader normalises. vibe-changed with legacy noisy/blocked payloads still renders a transition verb (event-summary) exercises the call-site normaliser. lineUpCreatures emits a +N more overflow indicator and lineUpCreatures keeps shelves from overlapping each other vertically cover the proportional-allocation invariants. fakeName covers each casing style across many ids samples 1000 names and asserts each style bucket lands. gardenPageCapacity returns more creatures per page at dense than at cozy, gardenPageCapacity default density matches explicit comfortable, and lineUpCreatures dense density fits more creatures per shelf row than cozy cover the new density knob. Test count: 345 → 356.

v0.4.0

14 May 05:35

Choose a tag to compare

Fixed

  • Mask mode now redacts the scan-root paths shown under the garden and in the multi-root scan progress UI. Pre-fix, hitting m to mask names left the configured base directories visible in plaintext, leaking the same path information the per-repo masking was hiding.
  • Journal vibe-change entries read as transitions, not status snapshots. Each from → to pair now picks a verb that describes the change (back in flow, hit a blocker, wound down, settled, back at it, stirred, …) instead of falling through to the destination state. Pre-fix, blocked → happy rendered as happy: clean, which read like a status line. The reason text gets a small cleanup pass too: the redundant blocker: prefix is stripped when the verb already says it, and trailing periods are dropped before the em-dash join.
  • Garden creature labels no longer collide with neighbouring sprites. Placement now sizes each grid slot to fit the full footprint (sprite body + rendered name label), and reserves room for the label row below each sprite. Pre-fix, two sprites whose bodies didn't overlap could still have their name labels painted over each other or into an adjacent sprite, and a long name on row N could clip into the sprite on row N+1.
  • Wandering creatures no longer land on dragged neighbours. syncVisualPlacements now resolves manually-offset creatures first so wanderers iterated before them check against the dragged neighbour's actual visual position, not an anchor footprint that excluded it.

Added

  • Per-repo activity drives animation cadence. A continuous 0–1 activity scalar derived from "days since last commit" (7-day half-life exponential decay) now biases each creature's wiggle frame-cycle and wander idle gaps within its vibe-bucket's range. Fresh-commit repos sit at the fast end of their cadence range with full drift radius; long-quiet repos sit at the slow end with ~25% drift. A repo blocked by a current blocker note still gets its activity from commit recency, so a freshly-broken build keeps bustling visibly while a stalled-for-a-month one barely moves.
  • Closed eyes + blink animation. Awake creatures keep their original sub-pixel-derived eye look (the corner-cut quadrant chars from the body grid). Sleepy creatures and the brief blink window for awake creatures paint a face panel: a body-coloured cell with (lower one-quarter block) cut into it as a closed eyelid. Each awake creature blinks briefly every 3.5–7s (interval shrinks with activity) on a per-identity phase so the swarm doesn't blink in unison. Reduced-motion mode skips the blink entirely. Sleepy creatures hold their body at rest — no bob — so the closed eye sits on a stationary face; awake creatures still bob and the eye cells track the per-frame shift. Sprite generation guarantees at least one cell of body between the two eyes (so closed-eye glyphs read as two distinct eyes, not one connected bar) and at least one cell row of body below the eye row (so the closed-eye glyph sits on a face instead of dangling).
  • Background observer for live commit + new-repo backfill. fs.watch on each repo's .git/logs/HEAD catches commits / amends / pulls / resets within ~250 ms; a non-recursive watch on each scan-root catches new repos dropped into a tracked folder within ~500 ms. The existing 30 s safety-net poll still runs underneath so updates arrive on filesystems where fs.watch is unreliable. Default-on; the settings screen exposes o as a persistent toggle, and REPOGARDEN_DISABLE_OBSERVER=1 still wins for single-run launches. Closes the §4.1 "flagged for recovery" item in docs/legacy-not-ported.md.
  • Pull from the workbench (fast-forward only). PORTRAIT exposes u as a two-press confirm (first arms, second runs); the command palette has a "pull from remote" entry that runs immediately. Result lands as a sticky banner on failure / non-zero and as a transient success banner otherwise. Preflight blocks the action when the tree is dirty, HEAD is detached, the branch has no upstream, or scan errored. Each attempt appends a pull event to the journal — payload carries ok, exitCode, branch, beforeSha, afterSha, commitsPulled, summary, durationMs, timedOut. Closes the §7.3 "flagged for recovery" item in docs/legacy-not-ported.md.

Internal

  • New computeActivity + ACTIVITY_HALF_LIFE_DAYS exports in src/lib/vibe.ts; VibeResult now carries activity: number. buildWiggleProfile and a new per-creature WanderProfile (built once in createWanderState and stored on GardenWanderState) replace the previous direct VIBE_WANDER reads in step functions, so activity-baked timing flows through the whole tick path without re-resolving on every frame.
  • generateCreatureFrames now returns eyeCells: { left, right } alongside frame data. GardenSpriteInfo carries those cells plus an eyesClosed flag (gated on vibe === "sleepy" in buildScene) and a per-creature BlinkProfile (interval scales with activity, randomised phase). The render loop in src/garden/render.ts only short-circuits to a composited face panel ({ char: "▂", fg: theme.background, bg: info.body }) when eyes should be shut (sleepy or in the blink window); otherwise the body grid's natural quadrant char paints unchanged. New blinkClosedAt helper in src/garden/model.ts returns the closed/open state from (now + phaseMs) % intervalMs.
  • New spriteFullFootprint helper in src/lib/garden-layout.ts covers the rendered name label below each sprite; placeCreatures now sizes slots from max(maxSpriteCols, maxLabelCols) horizontally and maxSpriteRows + NAME_GAP_ROWS + NAME_H vertically. syncVisualPlacements in src/garden/model.ts resolves manually-offset placements first so wanderers see their actual visual positions. New vibeTransitionVerb + trimVibeReason helpers in src/lib/event-summary.ts cover all 12 from-to transitions with a defensive fallback for unknown vibe pairs. Test count: 318 → 345.
  • New module src/lib/observer.ts (per-handle debounce, watch budget cap at 150, error-tolerant per the subscribeToEventsFile pattern). New observer field on TuiConfig and observerEnabled() helper honoring the env override. cli.tsx adds one useEffect keyed on the set of repo paths so commit-driven state updates don't churn the watcher list.
  • New module src/lib/git-pull.ts (async git pull --ff-only with 60 s timeout, line-streaming onLine callback, and small sync sha helpers). New event-summary kind pull. New single-repo refresh helper refreshOneCreature in src/lib/creature.ts re-inspects one repo and re-runs enrichScans so the snapshot reconcile fires.
  • Contributor workflow migrated from npm to pnpm (pinned via packageManager: "pnpm@10.32.1"). package-lock.json removed; pnpm-lock.yaml is the lockfile. CI (.github/workflows/ci.yml) runs pnpm install --frozen-lockfile and pnpm scripts; the pack-smoke job still installs the produced tarball with npm install -g so the same path real users hit (npm install -g @outsideheaven/repogarden) stays exercised. prepare and prepack now inline the build command instead of calling npm run build, so neither lifecycle hook depends on a particular package manager being present. chalk@^5.6.2 is now a declared direct dependency (was previously imported by src/garden/diff.ts but only available via npm's hoisted layout).

v0.3.3

13 May 23:39

Choose a tag to compare

Changelog

All notable changes to RepoGarden land here. Format follows Keep a Changelog, versioning follows SemVer. Earlier history lives in git log.

[0.3.3] — 2026-05-13

Added

  • Journal updates land via fs.watch (#1). New writes to ~/.repogarden/events.jsonl now propagate in ~100 ms instead of waiting up to 5 s. A 30 s safety-net poll still runs so updates arrive on filesystems where fs.watch is unreliable (network mounts, some WSL-mounted Windows paths).
  • Persistent usage-bar disable toggle (#5). New u keypress in Settings flips usageBarDisabled in ~/.repogarden/tui.json; useUsage short-circuits on it (no credential reads, no network). REPOGARDEN_DISABLE_USAGE=1 still wins for single-run launches.
  • PORTRAIT pages with PgUp/PgDn (#4). Long actions / notes / activity / changes / commits lists no longer clip off the bottom of short terminals. Each list section paginates by its slice limit (the same one d toggles), and shows a dim "showing N–M of T · PgUp/PgDn to scroll" indicator when more remains.

Internal

  • Test count: 280 → 283. New helpers sectionPageSize and sectionItemCount in src/lib/portrait.ts; new subscribeToEventsFile in src/lib/events.ts.

[0.3.2] — 2026-05-13

Fixed

  • Demo mode roster collisions (#7). Eight scanned repos would frequently end up with two creatures sharing a name (e.g. two salt-and-paper entries) because the per-id resolver was a hash modulo into a 16-name pool. Replaced with a without-replacement assignment over the active id set, with -2/-3 suffixes once the roster is exhausted. Refreshed docs/images/demo.gif.
  • Reduced-motion polish (#6) on three sites that previously animated regardless of the setting: the privacy mode-toggle scramble (now lands settled instantly), Spinner (holds the first frame), and Skeleton (renders the static dot field with no shimmer).

Closed without changes

  • #2 (PgUp/PgDn → selection): already wired in JournalView; updated the BACKLOG and the journal manual-test doc to stop describing the old decoupled-scrolling intent.
  • #3 (workbench mode keybinding): ctrl+1 / ctrl+2 already select portrait/notes and are listed in the help overlay; updated the BACKLOG to stop calling it mouse-only.

[0.3.1] — 2026-05-13

Added

  • repogarden --version (alias -v) prints the running package version and exits.

[0.3.0] — 2026-05-13

Added

  • macOS-friendly focus-event recovery: the TUI now listens for xterm focus events (mode 1004) and, on focus-in, defensively releases the DEC 2026 Synchronized Update Mode bracket the kernel can leave half-open across a Space swipe. Fixes the "fullscreen terminal froze after swiping to another Space" symptom.
  • Quiet npm update check on startup. Hits registry.npmjs.org once per launch, cached for 24h under ~/.repogarden/update-check.json. Surfaces a single info toast when a newer version is published — never blocks boot, never modifies the install. Opt out with REPOGARDEN_NO_UPDATE_CHECK=1; auto-skipped in demo mode and on CI.
  • In-app first-run privacy notice: two dim lines on the onboarding screen noting that scans stay local and that ~/.repogarden is safe to delete.
  • Animated README demo GIF, reproducible from tape/demo.tape via vhs. Boot → onboarding → garden → shelf → journal, ending on the garden for a clean loop.
  • README "First 5 minutes" walkthrough using real key bindings sourced from the help overlay.
  • Expanded --help text covering env vars (REPOGARDEN_DISABLE_USAGE, REPOGARDEN_NO_UPDATE_CHECK, REPOGARDEN_DEMO, NO_MOTION), requirements, data path, and reset.
  • New PR template with a habitat-first check and a typecheck/test/build/manual-smoke list.

Fixed

  • macOS Space-swipe freeze (#8): fullscreen terminal swiping to another Space and back left the TUI visually frozen until relaunch. Root cause was the synchronized-update bracket landing without its matching close after a mid-write process suspension.

Changed

  • "Alpha" → "early beta" across README.md, SECURITY.md, and --help. Supported-versions table now tracks 0.2.x → 0.3.x instead of the stale 0.1.x.
  • REPOGARDEN_DISABLE_USAGE examples now show both installed (repogarden) and from-source (npm run dev) forms side by side.
  • Bug-report template asks for TUI-specific context: which screen, terminal size, install method, and whether REPOGARDEN_DISABLE_USAGE=1 changes the symptom.
  • CONTRIBUTING.md gained a short "Good first issues" pointer to the labeled tracker.
  • Journal manual-test doc synced with j/k cursor and arrow-driven repo-picker behavior.

Internal

  • New module src/lib/focus.ts (focus-event parser, mirrors mouse.ts).
  • New module src/lib/update-check.ts (pure logic, injectable I/O).
  • 8 new tests for focus parsing, 13 new tests for update-check. Test count: 247 → 268.
  • Tape scripts under tape/ regenerate the README GIF deterministically against an isolated /tmp/repogarden-demo-home.
  • Five new issue labels: journal, workbench, accessibility, privacy, demo, friend-alpha, macos.

v0.3.0

13 May 22:48

Choose a tag to compare

Changelog

All notable changes to RepoGarden land here. Format follows Keep a Changelog, versioning follows SemVer. Earlier history lives in git log.

[0.3.0] — 2026-05-13

Added

  • macOS-friendly focus-event recovery: the TUI now listens for xterm focus events (mode 1004) and, on focus-in, defensively releases the DEC 2026 Synchronized Update Mode bracket the kernel can leave half-open across a Space swipe. Fixes the "fullscreen terminal froze after swiping to another Space" symptom.
  • Quiet npm update check on startup. Hits registry.npmjs.org once per launch, cached for 24h under ~/.repogarden/update-check.json. Surfaces a single info toast when a newer version is published — never blocks boot, never modifies the install. Opt out with REPOGARDEN_NO_UPDATE_CHECK=1; auto-skipped in demo mode and on CI.
  • In-app first-run privacy notice: two dim lines on the onboarding screen noting that scans stay local and that ~/.repogarden is safe to delete.
  • Animated README demo GIF, reproducible from tape/demo.tape via vhs. Boot → onboarding → garden → shelf → journal, ending on the garden for a clean loop.
  • README "First 5 minutes" walkthrough using real key bindings sourced from the help overlay.
  • Expanded --help text covering env vars (REPOGARDEN_DISABLE_USAGE, REPOGARDEN_NO_UPDATE_CHECK, REPOGARDEN_DEMO, NO_MOTION), requirements, data path, and reset.
  • New PR template with a habitat-first check and a typecheck/test/build/manual-smoke list.

Fixed

  • macOS Space-swipe freeze (#8): fullscreen terminal swiping to another Space and back left the TUI visually frozen until relaunch. Root cause was the synchronized-update bracket landing without its matching close after a mid-write process suspension.

Changed

  • "Alpha" → "early beta" across README.md, SECURITY.md, and --help. Supported-versions table now tracks 0.2.x → 0.3.x instead of the stale 0.1.x.
  • REPOGARDEN_DISABLE_USAGE examples now show both installed (repogarden) and from-source (npm run dev) forms side by side.
  • Bug-report template asks for TUI-specific context: which screen, terminal size, install method, and whether REPOGARDEN_DISABLE_USAGE=1 changes the symptom.
  • CONTRIBUTING.md gained a short "Good first issues" pointer to the labeled tracker.
  • Journal manual-test doc synced with j/k cursor and arrow-driven repo-picker behavior.

Internal

  • New module src/lib/focus.ts (focus-event parser, mirrors mouse.ts).
  • New module src/lib/update-check.ts (pure logic, injectable I/O).
  • 8 new tests for focus parsing, 13 new tests for update-check. Test count: 247 → 268.
  • Tape scripts under tape/ regenerate the README GIF deterministically against an isolated /tmp/repogarden-demo-home.
  • Five new issue labels: journal, workbench, accessibility, privacy, demo, friend-alpha, macos.