Skip to content

feat(statusline): say how many workspace children are built when one is not - #538

Draft
Souptik96 wants to merge 2 commits into
trailhq:mainfrom
Souptik96:feat/statusline-workspace-repos-built
Draft

Souptik96 wants to merge 2 commits into
trailhq:mainfrom
Souptik96:feat/statusline-workspace-repos-built

Conversation

@Souptik96

Copy link
Copy Markdown

Depends on #445 — stacked on its head; only the last commit (0eb27fe) is new. I'll rebase onto main once #445 merges.

Follow-up to #445, as suggested by @shhdwi on #476: the workspace 1/2 repos built label, on top of #445's workspace stats.

What

At a workspace parent, #445 sums the children that have a graph, so a child that hasn't been built yet drops out of the counts without any sign. When some listed children are unbuilt, the bar now says so:

◤ graft · workspace 1/2 repos built · 10 nodes / 5 edges · ✓ synced

When every child is built, and in a plain repo, the line is the same as before.

How

  • src/claude/stats.ts: workspaceCoverage(dir) returns { built, total }, or null when dir isn't a workspace parent. A child counts as built if its <child>/graft/.graph/wiring.json exists. It only checks that the file exists and doesn't parse it, since this runs on every render. computeWorkspaceStats now uses the same two small helpers (workspaceChildren, childWiringPath), with no change in behavior.
  • src/claude/statusline.ts: main() calls workspaceCoverage on every render, not just when resolveStats falls through to the sum. After the Stop-hook sync writes real counts into the parent's cache, resolveStats returns that cache and stops summing, but a child can still be unbuilt at that point.
  • src/claude/format.ts: renderStatusline takes an optional ctx.workspace. The amber segment is added only when built < total.

Tests

  • test/claude-format.test.ts: the label shows for 1/2. It doesn't show for 2/2 or for a plain repo.
  • test/claude-statusline.test.ts: workspaceCoverage gives 1/2 and 2/2, and null for a plain repo. A spawned main() at a workspace parent shows workspace 1/2 repos built, both before and after a sync-style cache is written.
  • Negative controls: reverting format.ts makes both new rendering tests fail. Reverting only the main() wiring makes the spawned test fail. Gating the label on an empty cache makes the "after the sync" assertion fail.
  • tsc --noEmit is clean. The full npm test run gives the same failure set before and after this change on my Windows machine. That set is 110 failures, environmental: most trace to tree-sitter-kotlin having no native build here (no MSVC). The statusline and format suites pass in full. I haven't run the full suite on Linux.

This change was written with an AI coding agent and reviewed by me.

davidpru and others added 2 commits September 22, 2026 08:23
…te skeleton (trailhq#433)

A workspace parent's graft/ holds only workspace.json; the graphs live in
each child's own graft/. Three readers at the parent assumed a graph of its
own. The statusline fell from a zeroed, dirty cache (what the hooks write on
the first edit) to a wiring.json the parent never has, and said "not built"
right after a successful build. The Stop-hook sync rebuilt correctly and then
read the parent's wiring to fill the counts — null, so it left dirty set
forever and the cache at all zeros. And `skeleton` was the one query command
not federated, so it answered "no wiring graph" for a repo just built.

computeWorkspaceStats sums each built child's wiring.json, read at
<child>/graft/ with no override, exactly as the federated commands do. It
stays off loadWorkspaceGraphs on purpose: the statusline is a pure read on
the render path and that module pulls the whole ask engine in with it.
resolveStats merges the sum over the zeroed cache so the live dirty state
survives; runSync uses the same sum when there is no parent wiring, so the
cache gets real counts and dirty clears. The single-repo path is unchanged.

federateSkeleton routes `<child>/path` to that child directly, the shape
every federated pointer is printed in, and looks a bare path or basename up
in every child, which must land in exactly one. Wired into the CLI and the
MCP graft_file_api tool like the other federated commands.
…is not

At a workspace parent the bar sums the built children (trailhq#433), so a child
that has not been built yet drops out of the counts with no hint. Show
`workspace K/N repos built` (amber) before the counts when K < N, and
nothing extra when every child is built or in a plain repo.

The count is read on every render rather than taken from the sum: once
the Stop-hook sync writes real counts into the parent's cache, the
statusline reads that cache and no longer sums the children, and a child
can still be unbuilt then. It only stats each child's wiring.json.
@github-actions

github-actions Bot commented Oct 2, 2026

Copy link
Copy Markdown
Contributor

🌱 graft blast radius

4 areas changed → 1 area can be affected. 1 dependent symbol, depth 2.
Tests: no test reaches Workspace Tool Integration, Workspace Graph; 1 area updated its tests.
Tag: @anirudhkumar-nanonets — 5 of 5 areas · @shhdwi — 5 of 5 areas

flowchart TB
  A0(("MCP Server<br/>1 symbol"))
  classDef reached fill:#D9EDF3,stroke:#3AA7C9,stroke-width:1.5px,color:#0E313C;
  class A0 reached;
Loading
Can be affected Symbols Nearest hop Reached from
MCP Server 1 src/mcp/server.ts:L71-L151 startMcpServer — calls, depth 2 Workspace Tool Integration
Who knows this code — 2 people across 5 areas
Area Who knows it
Workspace Tool Integration · changed @shhdwi — 14 commits, last 2mo ago · @anirudhkumar-nanonets — 7 commits, last 30d ago
Coverage Statistics · changed @shhdwi — 15 commits, last 2mo ago · @anirudhkumar-nanonets — 8 commits, last 30d ago
Workspace Graph · changed @shhdwi — 6 commits, last 2mo ago · @anirudhkumar-nanonets — 3 commits, last 2mo ago
CLI Entry Point · changed @anirudhkumar-nanonets — 52 commits, last 3d ago · @shhdwi — 23 commits, last 2mo ago
MCP Server · affected @anirudhkumar-nanonets — 5 commits, last 1mo ago · @shhdwi — 2 commits, last 2mo ago

Ownership is git history over each area's own files, weighted towards recent work (120-day half-life). Merge commits and bots are dropped, and you are dropped from your own PR. A name with no @ has no GitHub handle in its commit email — tag them by hand, or add a .mailmap entry. A suggestion from history, not a CODEOWNERS rule.

All 1 dependent symbol, grouped by area

MCP Server — 1 symbol in 1 file

  • src/mcp/server.ts:L71-L151 — startMcpServer (calls, depth 2)
Test signal per changed area — 1 ✓ · 2 ✗ · 1 –

Reached = a node under a test path has a resolved edge into the changed symbol. It undercounts anything called indirectly — through a CLI, a spawned process or a dynamic import — so read a low ratio as “look here”, never as a coverage gate.

  • ✗ Workspace Tool Integration — 0 of 1 reached · no test file reaches it
    • not reached: callWorkspaceTool
  • ✓ Coverage Statistics — 5 of 9 reached · 3 test files changed here: test/claude-format.test.ts, test/claude-hooks.test.ts, test/claude-statusline.test.ts
    • not reached: childWiringPath, sum, workspaceChildren, main
  • ✗ Workspace Graph — 0 of 2 reached · no test file reaches it
    • not reached: runWorkspaceSkeleton, prefixed
  • – CLI Entry Point — no function, method or class changed here
5 test suites also reference this code

5 symbols, kept out of the diagram and the table so they cannot crowd out the areas a reviewer has to look at.

  • test/claude-stats.test.ts
  • test/graph-follow-submodules.test.ts
  • test/graph-load.test.ts
  • test/graph-refresh.test.ts
  • test/graph-seed.test.ts

graft blast · origin/main...HEAD · depth 2 · 13 changed files

Open the interactive graph → — click an area to see its dependent symbols at file:line.

github-actions Bot added a commit that referenced this pull request Oct 2, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants