Releases: NovaRagnarok/RepoGarden
v0.9.1
[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/kas 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 viagto 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 withwarning. Still 16.7:1 on black, well above AA. - The
★ RepoGardenCredit 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.
DitherOverlaywas 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
\x1bin 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 incli-main.tsxnow 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 defaultflexShrink=1was lettingoverflow="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
marginTopbumped fromrows - 7torows - 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
paintExclusionsAPI onGardenSceneProps: a list of canvas-local rects whose cells the renderer markstransparent. The diff writer andsetCellboth short-circuit on transparent, andblockStarsForOverlaysskips star-gen work entirely for excluded cells.ReadyShellderives the toast rect fromuseToasts().activeand the shared layout constants, in canvas-local coords, and threads it through to bothGardenViewcall 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-lengthtruncate(eventSummary(...), summaryWidth)swapped for fixed-widthpadTrunc(...)so the Text length is constant between frames.
Internal
flushPending/hasPendingexports onsrc/lib/mouse.tsandsrc/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 inReadyShell.tsx. scripts/tui-observe.sh sendnow accepts any single printable char,C-*chords,Tab/Spacesynonyms, andtext:<string>for literal multi-char input — enough to drive every surface from the harness.- End-to-end QA report at
docs/manual-qa-report.mdwith 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
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=1now 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
~/.repogardenstorage location and migration expectation. - First-run and creature-system copy now use the current
awake/happy/stuck/sleepyvocabulary. - 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 -- startform and submits the disposable~/repos/rootscan path on first run.
Validation
pnpm typecheckpnpm test- 491 passingpnpm 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/repogardenv0.8.0 — drag reliability round 2 + garden polish
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.
syncGardenModelused to wipedragPreviewPlacementsand reset every wander state'smanualOffseton every call. Combined withenginePropschurning constantly (callbacks declared inline incli.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 carriesdragPreviewPlacementsacross, andengine.setPropsskips the sync entirely when only callback identities changed. - 🎯 Drag commit math no longer bakes in the wander bob. Press recorded
grabXfrom 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
findCreatureDragHandleAtCellmissed. 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
cto 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
setCellbounds 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/repogardenv0.7.0 — source-mass sizing, wide creatures, reliable drag
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/40so an accidentally-committed dump can't make the phase crawl. Markdown counts towardprimaryLanguagedetection 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.
maxArea130 → 180,charWclamp 18 → 20,charHclamp 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/WorkbenchScreennow 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/fileCountwould 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
Highlights
- 🔔 Optional terminal bell on vibe flips. New
btoggle in Settings (andbellOnVibeChangein~/.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-repovibe-changedevents for the detail the bell omits.
Docs
- README now documents the existing reduced-motion mode: open Settings (
s) and pressm, or setNO_MOTION=1(orCI=true) for a single run. The feature shipped earlier and is wired throughtheme-provider.tsx'suseMotion()— 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;
compactModethreshold bumped fromrows < 33to< 34and non-compactreservedRowsfrom 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
Highlights
- 🎬 Share the habitat. Press
xin garden/shelf to export an animated GIF of the current page to~/Downloads; presstto copy a plain-UTF-8 frame to the clipboard (Markdown-fenced, with a--discordpaste-budget fitter on the matchingrepogarden export-textCLI). 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 asmood-changedjournal events with a 24h per-repo cool-off. Closes the §5.1 "flagged for recovery" item. - ⚡ Parallel + cached repo scan. Rebuilt
scanRootsProgressiveinto 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;SnapEntryextended with optionalmood+moodAt, legacy snapshots round-trip scripts/bench-scan.tsfor runnable scan perf checks- friend-alpha label/template retired
- Test count: 356 → 443
See CHANGELOG.md for the full notes.
npm install -g @outsideheaven/repogardenv0.5.0 — pagination, density, vibe rename, onboarding affordances
Changed
- Vibe vocabulary renamed for clarity:
noisy → awake(recent local changes — the optimum/most-engaged state) andblocked → stuck(user-flagged blocker).happy(clean + in sync) andsleepy(long quiet) unchanged. Shelf display order flipped soawakesits 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:loadScanSnapshotmigrates"noisy"/"blocked"on read, andevent-summary.tsnormalises legacyfrom/topayloads before looking up the transition verb. fakeNamemixes 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.
resolvePushPlacementsnow 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.syncVisualPlacementsalso 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.
lineUpCreatureswas rewritten with proportional vertical allocation: each vibe getsceil(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 moreindicator 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 anudgeRowinteraction 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 moretally rather than getting hopped into the next vibe's rows.
Added
- Pagination toggle + density setting. Two new persistent settings in
~/.repogarden/tui.json:gardenPaginate(defaulttrue) — 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.comfortablematches the pre-0.5.0 visuals exactly;cozyis roomier (fewer per page / row),denseis tighter (~50% more before pagination kicks in). Threaded throughgardenPageCapacityandlineUpCreatures.- Settings UI:
ptoggles pagination,gcycles density. Both render their current state next tom/u/oin 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, …).ADJECTIVES140 → 206,NOUNS145 → 225. Duplicate"ember"deduped fromNOUNS(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).buildDemoNameMapnow won't hit the-2cycle suffix until 33+ creatures, and the settings preview garden fills the shelf with a more populated cast.DEMO_BRANCHES10 → 16,DEMO_SUBJECTS16 → 32,DEMO_AUTHORS6 → 10 to keep per-id hashing variety proportional.
Internal
- New
restPlacementForhelper insrc/garden/model.ts(anchor +effectivePersistentOffset, transientcurrentOffsetdeliberately excluded). NewfindNearestClearPlacementwalks Chebyshev rings outward from a base placement, bounded by canvas dimensions.resolvePushPlacementsinitialises itsplacementsmap viarestPlacementForrather thanvisualPlacements.get(...)so push decisions don't rely on transient wander bob. - New
ShelfOverflowtype insrc/lib/garden-layout.ts;ShelfLayout.overflowscarries{ vibe, canvasRow, canvasCol, slotW, hidden }per shelf that truncated.GardenSceneplumbs the array through torenderGardenFrame, which paints each+N moremarker individerLabelColor(vibe)and clips the label toslotW.placeCreatures(organic mode) returnsoverflows: []for type compatibility. - New
migrateLegacyVibehelper insrc/lib/events.tsruns innormalizeSnapEntryto coerce"noisy" → "awake"and"blocked" → "stuck"at snapshot read time. NewnormaliseLegacyVibeinsrc/lib/event-summary.tsruns before thevibeTransitionVerbswitch so historicalvibe-changedevents still hit the right verb (got busy,back in flow, etc.). Vibetype is now"awake" | "happy" | "stuck" | "sleepy".VIBE_ORDERis["awake", "happy", "stuck", "sleepy"]. The canonical creature sort insrc/lib/creature.tsand the post-save resort incli.tsxmirror that order.VIBE_WANDER/VIBE_WIGGLEkeys,dividerLabelColor,vibeBadgeVariant, and the per-screen colour ternaries inReadyShell.tsx/JournalView.tsx/SettingsScreen.tsxwere updated in lockstep.JournalViewkeeps the colour mapping permissive against unknown future vibe strings via thevibeTargettyped signal alone.- New
GardenDensitytype exported fromsrc/lib/garden-layout.ts; consumed bygardenPageCapacity,lineUpCreatures,GardenSceneProps.density, and the new settings flow. Per-density tables:SHELF_EXTRA_PADandPAGE_SLOT_DIMS.comfortablematches 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 indicatorandlineUpCreatures keeps shelves from overlapping each other verticallycover the proportional-allocation invariants.fakeName covers each casing style across many idssamples 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, andlineUpCreatures dense density fits more creatures per shelf row than cozycover the new density knob. Test count: 345 → 356.
v0.4.0
Fixed
- Mask mode now redacts the scan-root paths shown under the garden and in the multi-root scan progress UI. Pre-fix, hitting
mto 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 → topair 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 → happyrendered ashappy: clean, which read like a status line. The reason text gets a small cleanup pass too: the redundantblocker: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.
syncVisualPlacementsnow 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
blockernote 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.watchon each repo's.git/logs/HEADcatches 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 wherefs.watchis unreliable. Default-on; the settings screen exposesoas a persistent toggle, andREPOGARDEN_DISABLE_OBSERVER=1still wins for single-run launches. Closes the §4.1 "flagged for recovery" item indocs/legacy-not-ported.md. - Pull from the workbench (fast-forward only). PORTRAIT exposes
uas 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 apullevent to the journal — payload carriesok,exitCode,branch,beforeSha,afterSha,commitsPulled,summary,durationMs,timedOut. Closes the §7.3 "flagged for recovery" item indocs/legacy-not-ported.md.
Internal
- New
computeActivity+ACTIVITY_HALF_LIFE_DAYSexports insrc/lib/vibe.ts;VibeResultnow carriesactivity: number.buildWiggleProfileand a new per-creatureWanderProfile(built once increateWanderStateand stored onGardenWanderState) replace the previous directVIBE_WANDERreads in step functions, so activity-baked timing flows through the whole tick path without re-resolving on every frame. generateCreatureFramesnow returnseyeCells: { left, right }alongside frame data.GardenSpriteInfocarries those cells plus aneyesClosedflag (gated onvibe === "sleepy"inbuildScene) and a per-creatureBlinkProfile(interval scales with activity, randomised phase). The render loop insrc/garden/render.tsonly 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. NewblinkClosedAthelper insrc/garden/model.tsreturns the closed/open state from(now + phaseMs) % intervalMs.- New
spriteFullFootprinthelper insrc/lib/garden-layout.tscovers the rendered name label below each sprite;placeCreaturesnow sizes slots frommax(maxSpriteCols, maxLabelCols)horizontally andmaxSpriteRows + NAME_GAP_ROWS + NAME_Hvertically.syncVisualPlacementsinsrc/garden/model.tsresolves manually-offset placements first so wanderers see their actual visual positions. NewvibeTransitionVerb+trimVibeReasonhelpers insrc/lib/event-summary.tscover 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 thesubscribeToEventsFilepattern). Newobserverfield onTuiConfigandobserverEnabled()helper honoring the env override. cli.tsx adds oneuseEffectkeyed on the set of repo paths so commit-driven state updates don't churn the watcher list. - New module
src/lib/git-pull.ts(asyncgit pull --ff-onlywith 60 s timeout, line-streamingonLinecallback, and small sync sha helpers). New event-summary kindpull. New single-repo refresh helperrefreshOneCreatureinsrc/lib/creature.tsre-inspects one repo and re-runsenrichScansso the snapshot reconcile fires. - Contributor workflow migrated from npm to pnpm (pinned via
packageManager: "pnpm@10.32.1").package-lock.jsonremoved;pnpm-lock.yamlis the lockfile. CI (.github/workflows/ci.yml) runspnpm install --frozen-lockfileand pnpm scripts; the pack-smoke job still installs the produced tarball withnpm install -gso the same path real users hit (npm install -g @outsideheaven/repogarden) stays exercised.prepareandprepacknow inline the build command instead of callingnpm run build, so neither lifecycle hook depends on a particular package manager being present.chalk@^5.6.2is now a declared direct dependency (was previously imported bysrc/garden/diff.tsbut only available via npm's hoisted layout).
v0.3.3
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.jsonlnow propagate in ~100 ms instead of waiting up to 5 s. A 30 s safety-net poll still runs so updates arrive on filesystems wherefs.watchis unreliable (network mounts, some WSL-mounted Windows paths). - Persistent usage-bar disable toggle (#5). New
ukeypress in Settings flipsusageBarDisabledin~/.repogarden/tui.json;useUsageshort-circuits on it (no credential reads, no network).REPOGARDEN_DISABLE_USAGE=1still 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
dtoggles), and shows a dim "showing N–M of T · PgUp/PgDn to scroll" indicator when more remains.
Internal
- Test count: 280 → 283. New helpers
sectionPageSizeandsectionItemCountinsrc/lib/portrait.ts; newsubscribeToEventsFileinsrc/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-paperentries) 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/-3suffixes once the roster is exhausted. Refresheddocs/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), andSkeleton(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+2already 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.orgonce 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 withREPOGARDEN_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
~/.repogardenis safe to delete. - Animated README demo GIF, reproducible from
tape/demo.tapeviavhs. 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
--helptext 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 tracks0.2.x → 0.3.xinstead of the stale0.1.x. REPOGARDEN_DISABLE_USAGEexamples 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=1changes the symptom. CONTRIBUTING.mdgained a short "Good first issues" pointer to the labeled tracker.- Journal manual-test doc synced with
j/kcursor and arrow-driven repo-picker behavior.
Internal
- New module
src/lib/focus.ts(focus-event parser, mirrorsmouse.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
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.orgonce 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 withREPOGARDEN_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
~/.repogardenis safe to delete. - Animated README demo GIF, reproducible from
tape/demo.tapeviavhs. 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
--helptext 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 tracks0.2.x → 0.3.xinstead of the stale0.1.x. REPOGARDEN_DISABLE_USAGEexamples 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=1changes the symptom. CONTRIBUTING.mdgained a short "Good first issues" pointer to the labeled tracker.- Journal manual-test doc synced with
j/kcursor and arrow-driven repo-picker behavior.
Internal
- New module
src/lib/focus.ts(focus-event parser, mirrorsmouse.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.