Skip to content

v0.4.0

Choose a tag to compare

@NovaRagnarok NovaRagnarok released this 14 May 05:35
· 148 commits to main since this release

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).