@mu-crew/mu 3.10.1 → 3.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/dist/{chunk-7OQNJWBY.js → chunk-2FJK6OOZ.js} +3 -3
  2. package/dist/{chunk-XXK7FR37.js → chunk-DXKJY3NT.js} +3 -3
  3. package/dist/{chunk-WT7IN2OD.js → chunk-JYZUNPPO.js} +44 -3
  4. package/dist/chunk-JYZUNPPO.js.map +1 -0
  5. package/dist/{chunk-YIF3X32A.js → chunk-WYBOR4FX.js} +2 -2
  6. package/dist/{chunk-YIF3X32A.js.map → chunk-WYBOR4FX.js.map} +1 -1
  7. package/dist/{cli-KJGVEZW5.js → cli-GRAPF5VC.js} +14 -9
  8. package/dist/cli-GRAPF5VC.js.map +1 -0
  9. package/dist/cli.js +1 -1
  10. package/dist/extension/mu-pi.js +2 -2
  11. package/dist/extension/mu-pi.js.map +1 -1
  12. package/dist/index.d.ts +22 -2
  13. package/dist/index.js +5 -3
  14. package/dist/{tui-X2XICJTN.js → tui-DGDEH4JX.js} +5 -5
  15. package/dist/{tui-X2XICJTN.js.map → tui-DGDEH4JX.js.map} +1 -1
  16. package/dist/tui-sync-worker.js +1 -1
  17. package/docs/VISION.md +3 -0
  18. package/docs/guide/delegate.md +1 -1
  19. package/package.json +1 -1
  20. package/skills/mu/SKILL.md +29 -37
  21. package/skills/mu/recipes/adversarial-review.md +26 -21
  22. package/skills/mu/recipes/brief.md +3 -2
  23. package/skills/mu/recipes/codemode-driver.md +9 -6
  24. package/skills/mu/recipes/deep-research.md +2 -1
  25. package/skills/mu/recipes/drift-audit.md +5 -4
  26. package/skills/mu/recipes/fan-out.md +5 -3
  27. package/skills/mu/recipes/findings.md +7 -3
  28. package/skills/mu/recipes/hypothesis-panel.md +2 -1
  29. package/skills/mu/recipes/models.md +102 -0
  30. package/skills/mu/recipes/orchestrator-loop.md +6 -8
  31. package/skills/mu/recipes/plan.md +5 -5
  32. package/skills/mu/recipes/recovery.md +9 -8
  33. package/skills/mu/recipes/refute.md +7 -4
  34. package/skills/mu/recipes/remote-workers.md +22 -14
  35. package/skills/mu/recipes/review-panel.md +4 -3
  36. package/skills/mu/recipes/rules-audit.md +7 -6
  37. package/skills/mu/recipes/tasks-or-calls.md +6 -5
  38. package/skills/mu/recipes/tournament.md +5 -2
  39. package/skills/mu/recipes/ultrathink.md +6 -4
  40. package/skills/mu/recipes/watcher.md +4 -0
  41. package/skills/mu/recipes/waves.md +5 -4
  42. package/skills/mu/recipes/worker.md +2 -2
  43. package/dist/chunk-WT7IN2OD.js.map +0 -1
  44. package/dist/cli-KJGVEZW5.js.map +0 -1
  45. /package/dist/{chunk-7OQNJWBY.js.map → chunk-2FJK6OOZ.js.map} +0 -0
  46. /package/dist/{chunk-XXK7FR37.js.map → chunk-DXKJY3NT.js.map} +0 -0
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cli/tui/index.ts","../src/cli/tui/app.tsx","../src/cli/tui/cards/agents.tsx","../src/cli/tui/agent-display.ts","../src/cli/tui/wrap-ansi.ts","../src/cli/tui/columns.ts","../src/cli/tui/layout.ts","../src/cli/tui/list-row.tsx","../src/cli/tui/popups/cursor-row.tsx","../src/cli/tui/titled-box.tsx","../src/cli/tui/use-terminal-size.ts","../src/cli/tui/cards/_placeholder.tsx","../src/cli/tui/padded-rows.tsx","../src/cli/tui/format-helpers.ts","../src/cli/tui/cards/blocked.tsx","../src/cli/tui/cards/commits.tsx","../src/cli/tui/cards/doctor.tsx","../src/cli/tui/cards/inprogress.tsx","../src/cli/tui/cards/log.tsx","../src/cli/tui/cards/ready.tsx","../src/cli/tui/cards/recent.tsx","../src/cli/tui/cards/tracks.tsx","../src/cli/tui/cards/workspaces.tsx","../src/cli/tui/help.tsx","../src/cli/tui/keymap-spec.ts","../src/cli/tui/keys.ts","../src/cli/tui/popups/scroll.ts","../src/cli/tui/mouse.ts","../src/cli/tui/escapes.ts","../src/cli/tui/popup-input.ts","../src/cli/tui/popups/agents.tsx","../src/cli/tui/popup-shell.tsx","../src/cli/tui/tmux-attach.ts","../src/cli/tui/use-popup-action-queue.ts","../src/cli/tui/use-popup-filter.tsx","../src/cli/tui/popups/drill.tsx","../src/cli/tui/popups/viewport.ts","../src/cli/tui/popups/all-tasks.tsx","../src/cli/tui/use-notes-drill.ts","../src/cli/tui/popups/task-detail.tsx","../src/cli/tui/use-status-filter.tsx","../src/cli/tui/popups/blocked.tsx","../src/cli/tui/popups/task-list-popup.tsx","../src/cli/tui/popups/commits.tsx","../src/cli/tui/lazygit.ts","../src/cli/tui/tuicr.ts","../src/cli/tui/popups/show-loader.ts","../src/cli/tui/popups/dag.tsx","../src/cli/tui/popups/doctor.tsx","../src/cli/tui/popups/inprogress.tsx","../src/cli/tui/popups/log.tsx","../src/cli/tui/popups/ready.tsx","../src/cli/tui/popups/recent.tsx","../src/cli/tui/popups/tracks.tsx","../src/cli/tui/popups/workspaces.tsx","../src/cli/tui/state.ts","../src/cli/tui/status-bar.tsx","../src/cli/tui/tab-strip.tsx","../src/cli/tui/tab-strip-layout.ts"],"sourcesContent":["// Public entrypoint for the interactive TUI. Lazy-imported by\n// src/cli/state.ts cmdState so the ink/react dependency tree only\n// loads when the user actually enters the TUI (not on `mu task list`,\n// `mu state --json`, `mu agent show`, etc.).\n\nimport { render } from \"ink\";\nimport { createElement } from \"react\";\nimport type { Db } from \"../../db.js\";\nimport { App } from \"./app.js\";\nimport { ALT_SCREEN_ENTER, ALT_SCREEN_EXIT } from \"./escapes.js\";\nimport { disableMouseMode, enableMouseMode } from \"./mouse.js\";\n\nexport interface RunTuiOptions {\n /** Resolved workstream set (≥1). Per feat_tui_multi_workstream\n * (workstream `tui-impl`): N=1 renders the TUI exactly as the\n * pre-multi-ws build did; N≥2 renders a tab strip above the\n * cards and Tab/Shift-Tab switch the active tab. cmdState is\n * responsible for the resolution + validation; runTui just\n * forwards the array. */\n workstreams: string[];\n /** Initial active tab index. Bare `mu` and `mu state --tui` share\n * the launch-focus ladder: $MU_SESSION, then tmux session name,\n * then cwd inside a workspace, then cwd equal to a workspace's\n * VCS-derived project root (latest activity breaks ties), then 0.\n * <App> clamps defensively. */\n initialActive?: number;\n}\n\nexport async function runTui(db: Db, opts: RunTuiOptions): Promise<void> {\n process.stdout.write(ALT_SCREEN_ENTER);\n enableMouseMode();\n try {\n const { waitUntilExit } = render(\n createElement(App, { db, workstreams: opts.workstreams, initialActive: opts.initialActive }),\n { exitOnCtrlC: true },\n );\n await waitUntilExit();\n } finally {\n disableMouseMode();\n process.stdout.write(ALT_SCREEN_EXIT);\n }\n}\n","// <App> — the TUI's root component.\n//\n// Owns:\n// - The dashboard snapshot poll (via useDashboardSnapshot)\n// - Card visibility flags (0-9 toggle)\n// - Tick rate (+/-/= adjust)\n// - Single-popup invariant + state-restore on close\n// - Help overlay (?)\n// - Footer line (last yanked command + [copied]/[no clipboard])\n// - Yank backend probe (memoised once per session)\n// - Quit / Ctrl-C\n//\n// Per design_card_iface + design_popup_lifecycle: card visibility +\n// tick rate + footer are preserved as a side effect of living in\n// <App> state, not the popup. The snapshot tick keeps running while\n// popups are open; drill-down bodies consume explicit fast/slow tick\n// nonces so visible details refresh without closing/reopening.\n\nimport type { EventEmitter } from \"node:events\";\nimport { Box, Text, useApp, useInput, useStdin } from \"ink\";\nimport {\n type ComponentType,\n type ReactElement,\n useCallback,\n useEffect,\n useRef,\n useState,\n} from \"react\";\nimport type { Db } from \"../../db.js\";\nimport { AgentsCard } from \"./cards/agents.js\";\nimport { BlockedCard } from \"./cards/blocked.js\";\nimport { CommitsCard } from \"./cards/commits.js\";\nimport { DoctorCard } from \"./cards/doctor.js\";\nimport { InProgressCard } from \"./cards/inprogress.js\";\nimport { LogCard } from \"./cards/log.js\";\nimport { ReadyCard } from \"./cards/ready.js\";\nimport { RecentCard } from \"./cards/recent.js\";\nimport { TracksCard } from \"./cards/tracks.js\";\nimport { WorkspacesCard } from \"./cards/workspaces.js\";\nimport { Help } from \"./help.js\";\nimport {\n dispatchGlobalKeyFromInk,\n type InputMode,\n type PopupAction,\n type PopupActionEnvelope,\n shouldSwallowGlobalKeyFromInk,\n} from \"./keys.js\";\nimport {\n allocateRowBudgets,\n balanceColumns,\n CARD_CONFIGS,\n type CardId,\n type ColumnAssignment,\n type ColumnWidth,\n columnWidths,\n cullCardsForRows,\n dashboardCardHitRegions,\n dataCountForCard,\n hitTestDashboardCard,\n layoutColumns as layoutDashboardColumns,\n type RowBudgetMap,\n} from \"./layout.js\";\nimport { type MouseEvent, useMouse } from \"./mouse.js\";\nimport { PopupInputActive } from \"./popup-input.js\";\nimport { AgentsPopup } from \"./popups/agents.js\";\nimport { AllTasksPopup } from \"./popups/all-tasks.js\";\nimport { BlockedPopup } from \"./popups/blocked.js\";\nimport { CommitsPopup } from \"./popups/commits.js\";\nimport { DagPopup } from \"./popups/dag.js\";\nimport { DoctorPopup } from \"./popups/doctor.js\";\nimport { InProgressPopup } from \"./popups/inprogress.js\";\nimport { LogPopup } from \"./popups/log.js\";\nimport { ReadyPopup } from \"./popups/ready.js\";\nimport { RecentPopup } from \"./popups/recent.js\";\nimport { TracksPopup } from \"./popups/tracks.js\";\nimport { WorkspacesPopup } from \"./popups/workspaces.js\";\nimport {\n type CardVisibility,\n DEFAULT_CARD_VISIBILITY,\n fasterTick,\n slowerTick,\n TICK_DEFAULT_MS,\n useDashboardSnapshot,\n} from \"./state.js\";\nimport { StatusBar } from \"./status-bar.js\";\nimport { TabStrip } from \"./tab-strip.js\";\nimport { useTerminalSize } from \"./use-terminal-size.js\";\nimport { type ClipboardBackend, probeClipboardBackend } from \"./yank.js\";\n\nexport interface AppProps {\n db: Db;\n /** Resolved workstream set (≥1). Per feat_tui_multi_workstream\n * (workstream `tui-impl`): the TUI shows one ws at a time;\n * Tab/Shift-Tab cycles. Length 1 is the original single-ws TUI\n * with no tab strip rendered. */\n workstreams: string[];\n /** Initial active tab index. Clamped at render time so stale env\n * values or shrinking workstream arrays fall back safely. */\n initialActive?: number;\n}\n\nexport interface FooterState {\n command: string;\n copied: boolean;\n tone?: \"normal\" | \"info\" | \"error\";\n}\n\ntype PopupId = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | \"dag\" | \"allTasks\" | null;\ntype PopupRegistryId = NonNullable<PopupId>;\nexport type PopupMode = \"list\" | \"drill\";\ntype DashboardSnapshot = ReturnType<typeof useDashboardSnapshot>[\"data\"];\n\ninterface CommonCardProps {\n snapshot: DashboardSnapshot;\n db: Db;\n workstream: string;\n rowBudget?: number;\n cols?: number;\n}\n\ninterface CommonPopupProps {\n yank: (command: string) => Promise<void>;\n onFooter: (command: string, copied: boolean, tone?: FooterState[\"tone\"]) => void;\n onClose: () => void;\n snapshot: DashboardSnapshot;\n fastTickNonce: number;\n slowTickNonce: number;\n mode: PopupMode;\n onModeChange: (mode: PopupMode) => void;\n onFilterEditingChange: (editing: boolean) => void;\n popupActions: readonly PopupActionEnvelope[];\n db: Db;\n workstream: string;\n}\n\nconst CARD_REGISTRY: Record<CardId, ComponentType<CommonCardProps>> = {\n 0: CommitsCard,\n 1: AgentsCard,\n 2: TracksCard,\n 3: ReadyCard,\n 4: LogCard,\n 5: WorkspacesCard,\n 6: InProgressCard,\n 7: BlockedCard,\n 8: RecentCard,\n 9: DoctorCard,\n};\n\nconst POPUP_REGISTRY: Record<PopupRegistryId, ComponentType<CommonPopupProps>> = {\n 0: CommitsPopup,\n 1: AgentsPopup,\n 2: TracksPopup,\n 3: ReadyPopup,\n 4: LogPopup,\n 5: WorkspacesPopup,\n 6: InProgressPopup,\n 7: BlockedPopup,\n 8: RecentPopup,\n 9: DoctorPopup,\n dag: DagPopup,\n allTasks: AllTasksPopup,\n};\n\n// Popups whose drill bodies shell out to subprocesses (git show /\n// agent scrollback / workspace commits). Their bodies must keep\n// refreshing on the slow tick even when the DB snapshot is byte-equal,\n// so the snapshot hook is told to advance slowTickNonce on no-op ticks\n// (see state.ts publishNoopSlowTicks). This is the single symbolic\n// source of truth, co-located with POPUP_REGISTRY, instead of magic\n// numeric literals scattered in the App body.\nconst EMPTY_WORKSTREAM_SET: ReadonlySet<string> = new Set();\nconst SUBPROCESS_BACKED_POPUPS: ReadonlySet<PopupRegistryId> = new Set<PopupRegistryId>([\n 0, // Commits — git show\n 1, // Agents — pane scrollback\n 5, // Workspaces — workspace commits\n]);\n\nexport const DASHBOARD_MIN_ROWS = 5;\n// Mouse SGR coordinates are 1-based. The popup fills the pane from\n// row 1 (its top border, which carries the title), so the first popup\n// body row is y=2. `event.y - POPUP_CHROME_TOP` is the 0-based body\n// row the popup receives in `clickRow`; the popup maps it through its\n// own scroll window and header strips.\nexport const POPUP_CHROME_TOP = 2;\n\nexport function dashboardAvailableRows(\n rows: number,\n opts: { hasTabStrip: boolean; hasSnapshotError: boolean },\n): number {\n const tabRows = opts.hasTabStrip ? 1 : 0;\n const snapshotErrorRows = opts.hasSnapshotError ? 3 : 0;\n const statusRows = 1;\n return Math.max(1, rows - tabRows - snapshotErrorRows - statusRows);\n}\n\ninterface PendingMouseEventRef {\n current: MouseEvent | null;\n}\n\n// Ink's `useStdin` does not advertise `internal_eventEmitter` in its\n// public TypeScript types, but the field IS what backs ink's own\n// public `useInput` hook (the field is exported from ink's stdin\n// context props but flagged `internal_*` per ink convention, meaning\n// ink reserves the right to rename or remove it without a\n// breaking-change bump). We still use it for\n// mouse-wheel scroll compatibility (scroll replays one `j`/`k` key);\n// double-click drills now use first-class PopupAction events instead\n// of replaying N synthetic row-navigation keys. Define a typed seam\n// + runtime probe so:\n// 1. The cast site is explicit, not a silent any-shaped access.\n// 2. If a future ink upgrade drops the field, we degrade gracefully\n// (mouse-wheel scroll stops emitting synthetic keys; keyboard\n// nav and double-click PopupAction routing are unaffected).\ninterface InkStdinWithEmitter extends ReturnType<typeof useStdin> {\n internal_eventEmitter: EventEmitter;\n}\n\nexport function getInkInternalEmitter(stdin: ReturnType<typeof useStdin>): EventEmitter | null {\n if (\"internal_eventEmitter\" in stdin) {\n return (stdin as InkStdinWithEmitter).internal_eventEmitter;\n }\n return null;\n}\n\nexport function replayPendingMouseEvent(\n pendingMouseEvent: PendingMouseEventRef,\n opts: {\n popupOpen: boolean;\n filterEditing: boolean;\n emitKey?: (key: string, delayMs: number) => void;\n emitAction: (action: PopupAction) => void;\n },\n): boolean {\n if (!opts.popupOpen || opts.filterEditing) return false;\n const event = pendingMouseEvent.current;\n if (event === null) return false;\n if (event.kind === \"scroll\") {\n if (opts.emitKey === undefined) return false;\n pendingMouseEvent.current = null;\n opts.emitKey(event.direction === \"up\" ? \"k\" : \"j\", 0);\n return true;\n }\n if (event.kind === \"doubleclick\") {\n pendingMouseEvent.current = null;\n opts.emitAction({ kind: \"clickRow\", row: event.y - POPUP_CHROME_TOP });\n return true;\n }\n pendingMouseEvent.current = null;\n return false;\n}\n\nexport function App({ db, workstreams, initialActive = 0 }: AppProps): ReactElement {\n const { exit } = useApp();\n const stdin = useStdin();\n\n const [visibility, setVisibility] = useState<CardVisibility>(DEFAULT_CARD_VISIBILITY);\n const [tickMs, setTickMs] = useState<number>(TICK_DEFAULT_MS);\n // Index of the active workstream tab. Tab / Shift-Tab cycles\n // through `workstreams`. Always in [0, workstreams.length).\n const [activeWs, setActiveWs] = useState<number>(initialActive);\n const [popup, setPopup] = useState<PopupId>(null);\n // Per-popup-instance mode (\"list\" → list of rows; \"drill\" →\n // inline detail view inside the popup body). Owned by <App>\n // because the StatusBar's hint cluster needs to know which mode\n // we're in. Reset to \"list\" every time a new popup opens.\n const [popupMode, setPopupMode] = useState<PopupMode>(\"list\");\n // True while ANY open popup has its '/' filter prompt in edit\n // mode. The popup pushes the flag up via onFilterEditingChange\n // (per feat_popup_search_filter); we use it solely to flip the\n // StatusBar hint cluster to the filter-mode hint.\n const [popupFilterEditing, setPopupFilterEditing] = useState<boolean>(false);\n const [helpOpen, setHelpOpen] = useState<boolean>(false);\n const [footer, setFooter] = useState<FooterState | null>(null);\n const [refreshNonce, setRefreshNonce] = useState<number>(0);\n const pendingMouseEvent = useRef<MouseEvent | null>(null);\n const [popupMouseTick, setPopupMouseTick] = useState<number>(0);\n const popupActionSeq = useRef(0);\n const [popupActions, setPopupActions] = useState<PopupActionEnvelope[]>([]);\n\n // Probe clipboard backend once per session and memoise.\n const clipboardRef = useRef<ClipboardBackend | undefined>(undefined);\n useEffect(() => {\n void probeClipboardBackend().then((b) => {\n clipboardRef.current = b;\n });\n }, []);\n\n // Bounds-clamp activeWs in case workstreams[] shrinks (defensive;\n // the TUI is launched with a fixed list today). Falls back to 0.\n const safeActive = Math.max(0, Math.min(activeWs, workstreams.length - 1));\n const workstream = workstreams[safeActive] ?? \"\";\n\n const snap = useDashboardSnapshot(db, workstream, tickMs, true, refreshNonce, undefined, {\n observedWorkstreams: workstreams,\n publishNoopSlowTicks: popup !== null && SUBPROCESS_BACKED_POPUPS.has(popup),\n });\n\n // Terminal-resize handling: useTerminalSize subscribes to stdout\n // 'resize' events so the entire tree re-renders when the pane\n // shrinks or grows. Cards self-shrink within the dashboard's flex\n // layout; the explicit guard catches the pathological 10x5 case.\n const { cols, rows } = useTerminalSize();\n const terminalTooSmall = cols < 40 || rows < DASHBOARD_MIN_ROWS;\n const tornDownWorkstreams = snap.tornDownWorkstreams ?? EMPTY_WORKSTREAM_SET;\n const hasTabStrip = workstreams.length > 1 || tornDownWorkstreams.has(workstream);\n const hasSnapshotError = snap.error !== null;\n const availableForCards = dashboardAvailableRows(rows, { hasTabStrip, hasSnapshotError });\n const dashboardModel = buildDashboardLayoutModel(cols, availableForCards, visibility, snap.data);\n const dashboardTop = 1 + (hasTabStrip ? 1 : 0) + (hasSnapshotError ? 3 : 0);\n const cardHitRegions = dashboardCardHitRegions(\n dashboardModel.assignments,\n dashboardModel.widths,\n dashboardModel.budgetsByColumn,\n { top: dashboardTop },\n );\n\n // Yank callback handed down to popups (and used by the dashboard\n // for any direct yank in the future). The popup passes the command\n // text; we update the footer regardless of whether the clipboard\n // write succeeded so the user can mouse-select if needed.\n const yankFn = useCallback(async (command: string) => {\n const { yank } = await import(\"./yank.js\");\n const r = await yank(command, clipboardRef.current ?? null);\n setFooter({ command, copied: r.copied });\n }, []);\n\n const footerFn = useCallback((command: string, copied: boolean, tone?: FooterState[\"tone\"]) => {\n setFooter({ command, copied, tone });\n }, []);\n\n const emitPopupAction = useCallback((action: PopupAction) => {\n const seq = popupActionSeq.current + 1;\n popupActionSeq.current = seq;\n setPopupActions((events) => [...events.slice(-8), { seq, action }]);\n }, []);\n\n useMouse((event) => {\n if (helpOpen || terminalTooSmall) return;\n if (popup === null) {\n if (event.kind !== \"doubleclick\") return;\n const hit = hitTestDashboardCard(cardHitRegions, event);\n if (process.env.MU_TUI_DEBUG_MOUSE === \"1\") {\n process.stderr.write(`mouse @ (${event.x},${event.y}) → card ${hit ?? \"MISS\"}\\n`);\n for (const region of cardHitRegions) {\n process.stderr.write(\n ` region ${region.id}: top=${region.top} bottom=${region.bottom} left=${region.left} right=${region.right}\\n`,\n );\n }\n }\n if (hit === null) return;\n setPopupActions([]);\n setPopupMode(\"list\");\n setPopup(hit);\n return;\n }\n if (popupFilterEditing) return;\n if (event.kind === \"scroll\" || event.kind === \"doubleclick\") {\n pendingMouseEvent.current = event;\n setPopupMouseTick((n) => n + 1);\n }\n });\n useEffect(() => {\n void popupMouseTick;\n // Ink's public useInput hook is backed by this internal emitter;\n // mouse-wheel scroll still replays the same single `j`/`k` byte\n // keyboard users type. Double-click drill bypasses this private\n // emitter and emits PopupAction objects directly. The runtime\n // probe + typed seam (getInkInternalEmitter) makes the remaining\n // private-API dependency explicit and degrades gracefully if a\n // future ink upgrade drops the field — mouse-wheel scroll stops\n // emitting synthetic keys, keyboard nav and double-click routing\n // are unaffected.\n const emitter = getInkInternalEmitter(stdin);\n if (emitter === null && process.env.MU_TUI_DEBUG_MOUSE === \"1\") {\n process.stderr.write(\n \"mu: ink stdin missing internal_eventEmitter; mouse scroll replay disabled\\n\",\n );\n }\n const emitKey =\n emitter === null\n ? undefined\n : (key: string, delayMs: number) => {\n setTimeout(() => emitter.emit(\"input\", Buffer.from(key)), delayMs);\n };\n replayPendingMouseEvent(pendingMouseEvent, {\n popupOpen: popup !== null,\n filterEditing: popupFilterEditing,\n emitKey,\n emitAction: emitPopupAction,\n });\n }, [popupMouseTick, popup, popupFilterEditing, stdin, emitPopupAction]);\n useEffect(() => {\n if (popup === null) {\n pendingMouseEvent.current = null;\n setPopupActions([]);\n }\n }, [popup]);\n\n // Global keymap. Rendered before popup rendering so popups can\n // override Esc / q / y handling locally via their own useInput\n // (later popups will register handlers; for v0 placeholder\n // popups, Esc closes via this dispatcher).\n //\n // Per review_tui_help_overlay_swallows_only_some_keys: the per-\n // mode \"do not let this key leak into the global dispatcher\"\n // rule is centralised in `shouldSwallowGlobalKey` (keys.ts) so\n // the help-overlay and popup branches share one swallow list.\n // Help and popup components own their own `useInput` for local\n // scroll/nav; ink fires every mounted useInput per keystroke, so\n // those local handlers still see `j`/`k`/etc. while this branch\n // short-circuits the global dispatcher.\n useInput(\n (input, key) => {\n // Help overlay close-keys are App-owned (the helper swallows\n // them along with everything else, so they must be handled\n // BEFORE the swallow check). Help.tsx's local useInput\n // handles scroll; the rest is consumed.\n if (helpOpen) {\n if (key.escape || input === \"q\" || input === \"Q\" || input === \"?\") {\n setHelpOpen(false);\n }\n }\n const mode: InputMode = helpOpen\n ? \"help\"\n : popup === null\n ? \"dashboard\"\n : popupFilterEditing\n ? \"popup-filter\"\n : \"popup\";\n if (shouldSwallowGlobalKeyFromInk(input, key, mode)) return;\n const action = dispatchGlobalKeyFromInk(input, key);\n\n switch (action.kind) {\n case \"quit\":\n exit();\n return;\n case \"toggleHelp\":\n setHelpOpen((o) => !o);\n return;\n case \"refreshNow\":\n setRefreshNonce((n) => n + 1);\n return;\n case \"tickFaster\":\n setTickMs((t) => fasterTick(t));\n return;\n case \"tickSlower\":\n setTickMs((t) => slowerTick(t));\n return;\n case \"clearFooter\":\n setFooter(null);\n return;\n case \"toggleCard\":\n if (popup !== null) return; // suppress while popup is open\n setVisibility((v) => ({ ...v, [action.cardId]: !v[action.cardId] }));\n return;\n case \"openPopup\":\n if (popup !== null) return; // single-popup invariant\n setPopupActions([]);\n setPopupMode(\"list\");\n setPopup(action.cardId);\n return;\n case \"nextTab\":\n if (popup !== null) return; // suppress while popup is open\n if (workstreams.length <= 1) return;\n setActiveWs((i) => (i + 1) % workstreams.length);\n return;\n case \"prevTab\":\n if (popup !== null) return;\n if (workstreams.length <= 1) return;\n setActiveWs((i) => (i - 1 + workstreams.length) % workstreams.length);\n return;\n case \"noop\":\n return;\n }\n },\n { isActive: true },\n );\n\n if (terminalTooSmall) {\n return (\n <Box borderStyle=\"round\" borderColor=\"red\" paddingX={1}>\n <Text>\n terminal too small ({cols}x{rows}) — need at least 40x{DASHBOARD_MIN_ROWS} for the TUI.\n Resize or run `mu state` for the static card.\n </Text>\n </Box>\n );\n }\n\n // Help overlay covers everything else (still gets the global\n // status bar at the bottom for consistent navigation hints).\n //\n // height={rows} + a flexGrow={1} spacer above the StatusBar pins\n // every frame to the full terminal height. Without this, ink's\n // diff-based renderer leaves \"ghost\" lines below a shrinking\n // frame on card-toggle / branch-swap (see\n // bug_tui_render_ghosting_v2). The spacer also bottom-sticks the\n // status bar so it doesn't float up against a shorter body.\n //\n // overflow=\"hidden\" pinned at the root (all three branches): when\n // total content exceeds rows ink would otherwise emit the\n // overflowing rows past the terminal bottom, scrolling the top\n // off-screen and silently dropping the topmost row's bytes (see\n // bug_tui_tab_switch_stale_render layer 2 + the single-ws sibling\n // bug_tui_dashboard_top_card_scrolls_off where the nine cards'\n // summed natural height beats `rows`). Belt-and-braces with the\n // per-card flexShrink=1 in TitledBox: that one tells Yoga it MAY\n // shrink cards, this one tells ink to clip if Yoga still didn't\n // (e.g. a card with a hardcoded `height` prop).\n //\n // With a popup open, the help overlay is rendered by the popup\n // branch below instead, so the popup stays mounted underneath.\n if (helpOpen && popup === null) {\n return (\n <Box flexDirection=\"column\" height={rows} overflow=\"hidden\">\n <Help rows={rows} />\n <Box flexGrow={1} />\n <StatusBar\n mode=\"help\"\n tickMs={tickMs}\n footer={footer}\n cols={cols}\n activeWorkstream={workstreams.length > 1 ? workstream : undefined}\n />\n </Box>\n );\n }\n\n // Popup mounted: render full-screen instead of dashboard, with\n // the popup-mode status bar pinned at the bottom.\n //\n // NOTE: no flexGrow={1} spacer here — popup bodies own their\n // bottom-fill (see sibling task bug_tui_popups_fill_pane). Adding\n // a sibling spacer would steal the space the popup wants. The\n // height={rows} pin is still required to prevent ghost lines\n // when swapping between popup ↔ dashboard ↔ help.\n //\n // `?` over a popup hides the popup (display=\"none\") instead of\n // unmounting it, and turns its keyboard off, so the cursor, filter,\n // drill pin and drill scroll are still there when help closes.\n if (popup !== null) {\n return (\n <Box flexDirection=\"column\" height={rows} overflow=\"hidden\">\n {helpOpen ? (\n <Box flexDirection=\"column\" flexGrow={1}>\n <Help rows={rows} />\n </Box>\n ) : null}\n <Box display={helpOpen ? \"none\" : \"flex\"} flexDirection=\"column\" flexGrow={1}>\n <PopupInputActive.Provider value={!helpOpen}>\n {renderPopup(popup)}\n </PopupInputActive.Provider>\n </Box>\n <StatusBar\n mode={helpOpen ? \"help\" : popupFilterEditing ? \"popup-filter\" : \"popup\"}\n tickMs={tickMs}\n footer={footer}\n cols={cols}\n popupName={popupNameForId(popup)}\n popupMode={popupMode}\n activeWorkstream={workstreams.length > 1 ? workstream : undefined}\n />\n </Box>\n );\n }\n\n // Dashboard.\n //\n // overflow=\"hidden\" pinned at the root: when total content\n // exceeds `rows` (e.g. the multi-ws TabStrip adds a row that\n // pushes the sum to rows+1), ink would otherwise emit the\n // overflowing rows past the terminal bottom, scrolling the top\n // off-screen — the user sees the topmost card lose its top\n // border. Clipping inside the height-pinned box keeps the frame\n // bounded to the terminal viewport so nothing is lost above row 1.\n // (bug_tui_tab_switch_stale_render layer 2.)\n return (\n <Box flexDirection=\"column\" height={rows} overflow=\"hidden\">\n {/* Tab strip — null when workstreams.length === 1, so the\n single-ws layout is byte-identical to the pre-multi-ws\n frame. The strip lives INSIDE the height-pinned + clipping\n parent so flexbox accounts for its 1-row height when\n allocating space to the cards below it. */}\n <TabStrip\n workstreams={workstreams}\n active={safeActive}\n terminalColumns={cols}\n tornDownWorkstreams={tornDownWorkstreams}\n />\n {hasSnapshotError && (\n <Box borderStyle=\"round\" borderColor=\"red\" paddingX={1}>\n <Text color=\"red\">snapshot error: {snap.error}</Text>\n </Box>\n )}\n <Box height={availableForCards} overflow=\"hidden\" flexDirection=\"column\">\n <DashboardColumns\n rows={availableForCards}\n model={dashboardModel}\n snapshot={snap.data}\n db={db}\n workstream={workstream}\n />\n </Box>\n <Box flexGrow={1} />\n <StatusBar\n mode=\"dashboard\"\n tickMs={tickMs}\n footer={footer}\n cols={cols}\n activeWorkstream={workstreams.length > 1 ? workstream : undefined}\n />\n </Box>\n );\n\n function renderPopup(id: PopupRegistryId): ReactElement {\n const props: CommonPopupProps = {\n yank: yankFn,\n onFooter: footerFn,\n onClose: () => {\n setPopup(null);\n setPopupMode(\"list\");\n setPopupFilterEditing(false);\n setPopupActions([]);\n },\n snapshot: snap.data,\n fastTickNonce: snap.fastTickNonce,\n slowTickNonce: snap.slowTickNonce,\n mode: popupMode,\n onModeChange: setPopupMode,\n onFilterEditingChange: setPopupFilterEditing,\n popupActions,\n db,\n workstream,\n };\n const Popup = POPUP_REGISTRY[id];\n return <Popup {...props} />;\n }\n}\n\ninterface DashboardLayoutModel {\n cardsRows: number;\n assignments: ColumnAssignment[];\n widths: ColumnWidth[];\n budgetsByColumn: RowBudgetMap[];\n hiddenCount: number;\n}\n\ninterface DashboardColumnsProps {\n rows: number;\n model: DashboardLayoutModel;\n snapshot: ReturnType<typeof useDashboardSnapshot>[\"data\"];\n db: Db;\n workstream: string;\n}\n\nfunction buildDashboardLayoutModel(\n cols: number,\n rows: number,\n visibility: CardVisibility,\n snapshot: ReturnType<typeof useDashboardSnapshot>[\"data\"],\n): DashboardLayoutModel {\n const visible = visibleCardIds(visibility);\n const firstCull = cullCardsForRows(visible, rows);\n const cullBudget = firstCull.hidden.length > 0 ? Math.max(1, rows - 1) : rows;\n const culled = cullBudget === rows ? firstCull : cullCardsForRows(visible, cullBudget);\n const cardsRows = culled.hidden.length > 0 ? Math.max(1, rows - 1) : rows;\n const packed = layoutDashboardColumns(cols, culled.cards);\n const assignments = balanceColumns(packed, (id) => dataCountForCard(id, snapshot));\n const widths = columnWidths(cols, assignments.length);\n const budgetsByColumn = assignments.map((assignment) =>\n capRowBudgetsForColumn(\n cardsRows,\n assignment.cards,\n allocateRowBudgets(\n cardsRows,\n assignment.cards.map((id) => ({ id, dataCount: dataCountForCard(id, snapshot) })),\n ),\n ),\n );\n return { cardsRows, assignments, widths, budgetsByColumn, hiddenCount: culled.hidden.length };\n}\n\nfunction DashboardColumns({\n rows,\n model,\n snapshot,\n db,\n workstream,\n}: DashboardColumnsProps): ReactElement {\n return (\n <Box flexDirection=\"column\" height={rows} overflow=\"hidden\">\n <Box flexDirection=\"row\" gap={1} height={model.cardsRows} overflow=\"hidden\">\n {model.assignments.map((assignment, i) => {\n const width = model.widths[i]?.width ?? 80;\n const budgets = model.budgetsByColumn[i];\n if (budgets === undefined) return null;\n return (\n <Box key={assignment.cards.join(\"-\")} flexDirection=\"column\" width={width}>\n {assignment.cards.map((id) =>\n renderCard(id, { snapshot, db, workstream, width, budgets }),\n )}\n </Box>\n );\n })}\n </Box>\n {model.hiddenCount > 0 ? (\n <Text dimColor>+{model.hiddenCount} cards hidden · resize taller</Text>\n ) : null}\n </Box>\n );\n}\n\nfunction capRowBudgetsForColumn(\n availableRows: number,\n cards: ReadonlyArray<CardId>,\n budgets: ReturnType<typeof allocateRowBudgets>,\n): ReturnType<typeof allocateRowBudgets> {\n const out: Record<CardId, number> = { ...budgets };\n let remaining = Math.max(0, Math.floor(availableRows));\n for (const id of cards) {\n const chrome = CARD_CONFIGS[id].chrome;\n const maxBody = Math.max(0, remaining - chrome);\n out[id] = Math.min(out[id], maxBody);\n remaining = Math.max(0, remaining - chrome - out[id]);\n }\n return out;\n}\n\ninterface RenderCardContext {\n snapshot: DashboardSnapshot;\n db: Db;\n workstream: string;\n width: number;\n budgets: ReturnType<typeof allocateRowBudgets>;\n}\n\nfunction renderCard(id: CardId, { snapshot, db, workstream, width, budgets }: RenderCardContext) {\n const Card = CARD_REGISTRY[id];\n return (\n <Card\n key={id}\n snapshot={snapshot}\n db={db}\n workstream={workstream}\n rowBudget={budgets[id]}\n cols={width}\n />\n );\n}\n\nfunction visibleCardIds(visibility: CardVisibility): CardId[] {\n const ids: CardId[] = [];\n for (const id of [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] as const) {\n if (visibility[id]) ids.push(id);\n }\n return ids;\n}\n\n// Both helpers below are pure CARD_CONFIGS table reads after\n// review_tui_card_key_from_id_redundant. They were 24-line\n// switch(id) blocks that duplicated the per-card name list already\n// living in src/cli/tui/layout.ts. The 'dag' / 'allTasks' branches\n// stay inline because they're not card slots — they're\n// keybind-only popups with no row in CARD_CONFIGS.\nfunction popupNameForId(id: NonNullable<PopupId>): string {\n if (id === \"dag\") return \"DAG\";\n if (id === \"allTasks\") return \"All tasks\";\n return CARD_CONFIGS[id].label;\n}\n","// Agents card — glanceable summary of every agent in the workstream.\n//\n// Per design_card_agents (workstream `tui`): name | status | task |\n// idle. Header includes agentStatusHistogram. Status glyph rendering goes\n// through agent-display.ts so glyph selection stays centralised.\n//\n// Aesthetic: rounded border, dim border colour, section header inset\n// into the top.\n//\n// Rows are column-aligned via src/cli/tui/columns.ts so name / task /\n// idle line up cleanly. Per feat_column_aligned_lists clipping policy:\n// glyph + agent name + idle marker are PROTECTED; the owned-task\n// summary is CLIPPABLE (it's a free-form string and the popup carries\n// the full version).\n\nimport { Text } from \"ink\";\nimport type { ReactElement } from \"react\";\nimport { GLYPH } from \"../../../glyphs.js\";\nimport {\n agentStateHistogram,\n summarizeOwnedTasks,\n type WorkstreamSnapshot,\n} from \"../../../state.js\";\nimport { IDLE_GLYPH } from \"../../format.js\";\nimport { agentStateGlyph } from \"../agent-display.js\";\nimport {\n type ColumnSpec,\n contentWidthFromCols,\n layoutColumns,\n renderRow,\n termColsForLayout,\n} from \"../columns.js\";\nimport { CARD_CONFIGS, cardRenderHeight } from \"../layout.js\";\nimport { ListRow } from \"../list-row.js\";\nimport { TitledBox } from \"../titled-box.js\";\nimport { CardPlaceholder } from \"./_placeholder.js\";\n\nexport interface AgentsCardProps {\n snapshot: WorkstreamSnapshot | null;\n rowBudget?: number;\n cols?: number;\n}\n\nexport const cardConfig = CARD_CONFIGS[1];\n\nconst COLUMN_SPECS: ReadonlyArray<ColumnSpec> = [\n { kind: \"protect\" }, // status glyph\n { kind: \"protect\" }, // agent name\n { kind: \"clip\", min: 1 }, // owned-task summary\n { kind: \"protect\" }, // idle marker\n];\n\nexport function AgentsCard({ snapshot, rowBudget, cols }: AgentsCardProps): ReactElement {\n const contentWidth = contentWidthFromCols(cols ?? termColsForLayout());\n if (snapshot === null) {\n return CardPlaceholder({\n title: \"Agents\",\n cardId: 1,\n config: cardConfig,\n rowBudget,\n cols,\n text: \"loading…\",\n });\n }\n\n const agents = snapshot.view.agents;\n const histogram = agentStateHistogram(agents);\n const histLabel = formatHistogram(histogram);\n\n if (agents.length === 0) {\n return CardPlaceholder({\n title: \"Agents\",\n cardId: 1,\n config: cardConfig,\n rowBudget,\n cols,\n children: (\n <Text dimColor>(no agents) try `mu agent spawn worker-1 -w {snapshot.workstreamName}`</Text>\n ),\n });\n }\n\n const shown = agents.slice(0, rowBudget ?? cardConfig.maxRows);\n const more = agents.length - shown.length;\n const bottomLabel = more > 0 ? `+${more} more · Shift+1` : undefined;\n\n // Build the cell matrix once so column widths consider every visible row.\n const rows = shown.map((a) => {\n const owned = snapshot.inProgress.filter((t) => t.ownerName === a.name);\n const taskBit = summarizeOwnedTasks(owned).bit;\n const idle = a.idle ? `${IDLE_GLYPH} idle` : \"\";\n // A pi agent whose control socket does not answer: flag the gap.\n const ctlBroken = a.ctl === \"missing\" || a.ctl === \"refused\";\n const glyph = ctlBroken ? `${agentStateGlyph(a.state)}${GLYPH.fail}` : agentStateGlyph(a.state);\n return [glyph, a.name, taskBit, idle];\n });\n const widths = layoutColumns(rows, COLUMN_SPECS, contentWidth);\n\n return (\n <TitledBox\n height={cardRenderHeight(cardConfig, rowBudget)}\n width={cols}\n title=\"Agents\"\n subtitle={histLabel}\n cardId={1}\n bottomLabel={bottomLabel}\n >\n {shown.map((a, i) => {\n const row = rows[i];\n if (row === undefined) return null;\n const padded = renderRow(row, widths, COLUMN_SPECS);\n const colors = [\n undefined, // glyph\n { bold: true }, // name\n { dimColor: true }, // taskBit\n a.idle ? { color: \"yellow\" } : { dimColor: true }, // idle marker\n ];\n return <ListRow key={a.name} cells={padded} contentWidth={contentWidth} colors={colors} />;\n })}\n </TitledBox>\n );\n}\n\nfunction formatHistogram(h: ReadonlyMap<string, number>): string {\n const parts: string[] = [];\n for (const [status, n] of h.entries()) {\n parts.push(`${n} ${status}`);\n }\n return parts.length === 0 ? \"(none)\" : parts.join(\" · \");\n}\n","import type { LiveAgent } from \"../../agents.js\";\nimport { agentStateGlyph } from \"../../glyphs.js\";\nimport type { WorkstreamSnapshot } from \"../../state.js\";\nimport type { TaskRow } from \"../../tasks.js\";\n\ntype AgentDisplayRow = Pick<LiveAgent, \"name\" | \"state\">;\n\nexport { agentStateGlyph };\n\n/** Return a stable lookup of live agent rows keyed by agent name. */\nexport function agentByName(\n snapshot: WorkstreamSnapshot | null,\n): ReadonlyMap<string, AgentDisplayRow> {\n const agents = snapshot?.view?.agents ?? [];\n return new Map(agents.map((a) => [a.name, a]));\n}\n\n/** Render a known live agent row with its status glyph. */\nexport function formatKnownAgentDisplayName(agent: AgentDisplayRow): string {\n return `${agentStateGlyph(agent.state)} ${agent.name}`;\n}\n\n/**\n * Render an agent reference from another TUI row.\n *\n * If the agent is present in the live-agent view, prefix the name with\n * the same status glyph used by the Agents card. If the row is an\n * owner/workspace reference whose agent is not in the live view (stale\n * snapshot, imported DB, or anonymous/self claim), keep the raw name\n * rather than inventing an unknown state. Null owners render as the\n * existing em dash.\n */\nexport function formatAgentRefDisplayName(\n agentName: string | null,\n agents: ReadonlyMap<string, AgentDisplayRow>,\n): string {\n if (agentName === null) return \"—\";\n const agent = agents.get(agentName);\n if (agent === undefined) return agentName;\n return formatKnownAgentDisplayName(agent);\n}\n\n/**\n * Render a task's owner. The live state glyph means \"this agent is\n * working on this task now\", so only IN_PROGRESS rows get it; CLOSED\n * rows (and OPEN rows that kept an owner) show the bare name.\n */\nexport function formatTaskOwnerDisplay(\n task: Pick<TaskRow, \"status\" | \"ownerName\">,\n agents: ReadonlyMap<string, AgentDisplayRow>,\n): string {\n if (task.status !== \"IN_PROGRESS\") return task.ownerName ?? \"—\";\n return formatAgentRefDisplayName(task.ownerName, agents);\n}\n","import { stripVTControlCharacters } from \"node:util\";\nimport stringWidth from \"string-width\";\n\nconst ESC = \"\\u001B\";\nconst ANSI_PATTERN = new RegExp(`${ESC}\\\\[[0-?]*[ -/]*[@-~]`, \"y\");\nconst SGR_PATTERN = new RegExp(`^${ESC}\\\\[([0-9;]*)m$`);\nconst RESET = `${ESC}[0m`;\n\n// Printable ASCII plus the width-1 glyphs mu draws (dashes/quotes/\"…\",\n// arrows incl. \"↻\", box-drawing, \"π\"), after stripping SGR: width is the\n// stripped length. string-width's per-grapheme segmentation cost\n// ~150 ms per 4.4k-line DAG body; everything else still goes through it.\nconst NARROW = /^[\\x20-\\x7e\\u03c0\\u2010-\\u2027\\u2190-\\u21ff\\u2500-\\u257f]*$/;\n\n/** Terminal-visible width of `s` (ANSI-aware, wide-char-aware). */\nexport function visibleWidth(s: string): number {\n const plain = s.includes(ESC) ? stripVTControlCharacters(s) : s;\n return NARROW.test(plain) ? plain.length : stringWidth(s);\n}\n\ninterface Token {\n text: string;\n width: number;\n}\n\n/**\n * Wrap a single line by terminal-visible width while preserving\n * ANSI SGR colour/style across hard wrap boundaries.\n */\nexport function wrapAnsi(line: string, width: number): string[] {\n if (line === \"\") return [line];\n if (width <= 0 || visibleWidth(line) <= width) {\n // Even the early-return path must guarantee SGR is closed so the ink\n // render does not leak colour into adjacent chrome (the popup right\n // border is the canonical reproducer): a short colored line like\n // `\\x1b[31m+ added` with no trailing reset would otherwise paint the\n // following border cell red. (bug_drill_ansi_state_leaks_into_border)\n return [closeIfOpen(line, computeActiveSgr(line))];\n }\n\n const out: string[] = [];\n const activeSgr: string[] = [];\n let chunk = \"\";\n let chunkWidth = 0;\n let i = 0;\n\n const emit = () => {\n if (chunkWidth === 0) return;\n out.push(closeIfOpen(chunk, activeSgr));\n chunk = activeSgr.join(\"\");\n chunkWidth = 0;\n };\n\n while (i < line.length) {\n ANSI_PATTERN.lastIndex = i;\n const ansi = ANSI_PATTERN.exec(line);\n if (ansi?.index === i) {\n const seq = ansi[0];\n chunk += seq;\n updateActiveSgr(seq, activeSgr);\n i += seq.length;\n continue;\n }\n\n const token = nextToken(line, i);\n if (chunkWidth > 0 && chunkWidth + token.width > width) emit();\n chunk += token.text;\n chunkWidth += token.width;\n i += token.text.length;\n\n if (chunkWidth >= width) emit();\n }\n\n // Same close-if-open guarantee as emit() for the trailing chunk: an\n // input whose final fragment is colored without a closing reset must\n // not bleed into ink's border render on the next row.\n if (chunkWidth > 0 || (chunk !== \"\" && out.length === 0)) {\n out.push(closeIfOpen(chunk, activeSgr));\n }\n return out.length === 0 ? [line] : out;\n}\n\nexport function padAnsiLine(line: string, width: number): string {\n const w = visibleWidth(line);\n if (w >= width) return line;\n return line + \" \".repeat(width - w);\n}\n\n// Wrapped+padded output per (width, raw line). Drill bodies are rebuilt on\n// every changed fast tick, but almost all of their lines are unchanged, so\n// a re-wrap is a split + lookups + join instead of ~4k width computations.\n// Bounded: cleared wholesale when full (a big body refills it in one pass).\nconst WRAP_CACHE_MAX = 20_000;\nconst wrapCache = new Map<string, string>();\n\nfunction wrapAndPadLine(line: string, width: number): string {\n const key = `${width}\\u0000${line}`;\n const hit = wrapCache.get(key);\n if (hit !== undefined) return hit;\n const out = wrapAnsi(line, width)\n .map((l) => padAnsiLine(l, width))\n .join(\"\\n\");\n if (wrapCache.size >= WRAP_CACHE_MAX) wrapCache.clear();\n wrapCache.set(key, out);\n return out;\n}\n\nexport function wrapAndPadAnsiLines(text: string, width: number): string {\n if (text === \"\") return \"\";\n return text\n .split(\"\\n\")\n .map((line) => wrapAndPadLine(line, width))\n .join(\"\\n\");\n}\n\n/** Test hook: number of cached wrapped lines. */\nexport function wrapCacheSizeForTests(): number {\n return wrapCache.size;\n}\n\nfunction nextToken(text: string, offset: number): Token {\n const first = text[offset];\n if (first === undefined) return { text: \"\", width: 0 };\n const codePoint = text.codePointAt(offset);\n if (codePoint === undefined) return { text: first, width: visibleWidth(first) };\n const char = String.fromCodePoint(codePoint);\n return { text: char, width: visibleWidth(char) };\n}\n\nfunction closeIfOpen(text: string, active: string[]): string {\n return active.length > 0 ? `${text}${RESET}` : text;\n}\n\nfunction computeActiveSgr(line: string): string[] {\n const active: string[] = [];\n let i = 0;\n while (i < line.length) {\n ANSI_PATTERN.lastIndex = i;\n const m = ANSI_PATTERN.exec(line);\n if (m?.index === i) {\n updateActiveSgr(m[0], active);\n i += m[0].length;\n continue;\n }\n i++;\n }\n return active;\n}\n\nfunction updateActiveSgr(seq: string, active: string[]): void {\n const match = SGR_PATTERN.exec(seq);\n if (match === null) return;\n const rawParams = match[1] ?? \"\";\n const params = rawParams === \"\" ? [0] : rawParams.split(\";\").map((p) => Number(p || \"0\"));\n if (params.some(isFullReset)) {\n active.length = 0;\n return;\n }\n active.push(seq);\n}\n\nfunction isFullReset(code: number): boolean {\n return code === 0;\n}\n","// columns.ts — column-alignment helpers for the TUI cards/popups.\n//\n// Per feat_column_aligned_lists (workstream `tui-impl`) and the\n// design_card_*/popup_* notes (workstream `tui`): rows in every card\n// and popup were rendered as free-flowing `<Text>` chunks separated by\n// single spaces. With variable-width fields (agent names, task ids,\n// status tokens, ROI numbers) they drifted visually and were hard to\n// scan. Match the static `mu task list` / `mu agent list` convention:\n// each column gets a fixed width based on the widest cell across the\n// visible rows, then we pad with spaces.\n//\n// Why no ascii grid borders inside the rounded card: the outer\n// rounded border is the only structural element; rows are just padded\n// text. Anything more (vertical bars, header rules) would compete\n// with the rounded frame.\n//\n// Width counting: `string-width` (transitive via cli-table3) handles\n// emoji / CJK / ANSI escapes correctly; bare `String.length` is wrong\n// for shared state glyphs and for any future i18n.\n//\n// Clipping policy: cells fall into two buckets per the task notes —\n// PROTECTED (task ids, agent names, status tokens, glyphs, ROI nums,\n// timestamps, event verbs) which must never be clipped because the\n// user yanks them verbatim; and CLIPPABLE (titles, payloads, role\n// descriptions, goal lists, notes previews) which degrade gracefully\n// under truncation. layoutColumns() respects the bucket: protected\n// cells take their natural width unconditionally, clippable cells\n// share whatever budget is left.\n\nimport { truncate } from \"../format.js\";\nimport { visibleWidth } from \"./wrap-ansi.js\";\n\nexport type ColumnKind = \"protect\" | \"clip\";\n\nexport interface ColumnSpec {\n /** \"protect\" — never clip; \"clip\" — truncate to share remaining budget. */\n kind: ColumnKind;\n /** Default \"left\". \"right\" pads on the left (numeric columns). */\n align?: \"left\" | \"right\";\n /** Optional minimum width (default 0). */\n min?: number;\n /** Optional maximum natural width to consider when sizing protected\n * columns — useful when a single rogue row would balloon the\n * column. Default: no cap. */\n max?: number;\n}\n\n/** Display width of `s`, ignoring ANSI escapes and counting wide chars. */\nexport function cellWidth(s: string): number {\n return visibleWidth(s);\n}\n\n/** Pad `s` to width `n` with spaces. align=\"right\" pads on the left.\n * No-op if the cell is already wider than `n` (no clipping here;\n * callers that need clipping should run truncateCell first). */\nexport function padCell(s: string, n: number, align: \"left\" | \"right\" = \"left\"): string {\n const w = cellWidth(s);\n if (w >= n) return s;\n const pad = \" \".repeat(n - w);\n return align === \"right\" ? pad + s : s + pad;\n}\n\n/** Truncate `s` to display width ≤ `n`, appending `…` if clipped.\n * Wraps src/cli/format.ts truncate() but uses string-width for the\n * threshold check so emoji / wide chars don't false-pass. */\nexport function truncateCell(s: string, n: number): string {\n if (n <= 0) return \"\";\n if (cellWidth(s) <= n) return s;\n // format.truncate works on `.length`; for ASCII titles (the\n // dominant case) this matches display width. For wide-char cells\n // we round down: chip 1 more codepoint at a time until we fit.\n let candidate = truncate(s, n);\n while (cellWidth(candidate) > n && candidate.length > 1) {\n candidate = truncate(candidate, candidate.length - 1);\n }\n return candidate;\n}\n\n/** Compute the natural (max-cell) width of every column across rows. */\nexport function naturalWidths(rows: ReadonlyArray<ReadonlyArray<string>>): number[] {\n if (rows.length === 0) return [];\n const ncols = Math.max(...rows.map((r) => r.length));\n const widths = new Array<number>(ncols).fill(0);\n for (const r of rows) {\n for (let i = 0; i < r.length; i++) {\n const cell = r[i] ?? \"\";\n const w = cellWidth(cell);\n if (w > (widths[i] ?? 0)) widths[i] = w;\n }\n }\n return widths;\n}\n\n/** Per-column padding between cells, in the rendered output. Two\n * spaces is the convention used by `mu task list` / `mu agent list`\n * (cli-table3 uses one + a vertical bar; we drop the bar). */\nexport const COL_GUTTER = 2;\n\n/** Convert a terminal-column count into the content-area width inside\n * a TitledBox / popup Shell.\n *\n * Both containers stack the same chrome on each side:\n * - 1 col rounded border\n * - 1 col paddingX\n * → 2 cols per side, 4 cols total — subtract from the outer width.\n *\n * Floored at 0 so very narrow terminals (cols < 4) don't drive a\n * negative budget into layoutColumns; the App.tsx terminal-too-small\n * guard (cols < 40) is the visible last resort.\n *\n * Per bug_tui_long_lines_overflow: every card/popup needs to pass\n * the resulting contentWidth to layoutColumns so clip columns\n * actually clip instead of overflowing the row to a second line. */\nexport function contentWidthFromCols(cols: number): number {\n return Math.max(0, cols - 4);\n}\n\n/**\n * Deprecated back-compat alias for tests and out-of-tree callers that\n * still need a non-hook fallback. Ink components should prefer\n * `useStdout()` and then pass `stdout?.columns ?? 80` to\n * `contentWidthFromCols()`.\n */\nexport function termColsForLayout(): number {\n return process.stdout.columns ?? 80;\n}\n\n/**\n * Compute the final width allocated to each column, given:\n * - rows the cell matrix (post-string conversion)\n * - specs per-column kind/align/min/max\n * - totalWidth total renderable width of the row (the inside of\n * the rounded border, i.e. terminal cols minus\n * border + paddingX). When undefined we just use\n * the natural widths (no clipping).\n *\n * Algorithm:\n * 1. Natural width per column.\n * 2. Apply per-column min/max caps.\n * 3. If totalWidth is undefined, return as-is.\n * 4. Otherwise, sum the protected widths + gutters.\n * 5. Distribute the remainder across clippable columns:\n * - Equal share by default.\n * - The LAST clippable column absorbs any rounding leftover.\n * 6. If even the protected cells overflow the budget, return the\n * natural widths anyway — App.tsx's terminal-too-small guard is\n * the last resort, and the dashboard layout will visually clip\n * regardless.\n */\nexport function layoutColumns(\n rows: ReadonlyArray<ReadonlyArray<string>>,\n specs: ReadonlyArray<ColumnSpec>,\n totalWidth?: number,\n): number[] {\n const natural = naturalWidths(rows);\n const widths = specs.map((spec, i) => {\n const nat = natural[i] ?? 0;\n let w = nat;\n if (spec.min !== undefined && w < spec.min) w = spec.min;\n if (spec.max !== undefined && w > spec.max) w = spec.max;\n return w;\n });\n\n if (totalWidth === undefined) return widths;\n\n const ncols = specs.length;\n const gutters = ncols > 1 ? (ncols - 1) * COL_GUTTER : 0;\n const protectedSum = specs.reduce(\n (acc, s, i) => (s.kind === \"protect\" ? acc + (widths[i] ?? 0) : acc),\n 0,\n );\n const remaining = totalWidth - protectedSum - gutters;\n const clipIdx = specs.map((s, i) => (s.kind === \"clip\" ? i : -1)).filter((i) => i >= 0);\n\n if (clipIdx.length === 0) return widths;\n if (remaining <= 0) {\n // Protected cells alone overflow; give clippable cols 0 each\n // so they collapse rather than push the row arbitrarily wide.\n for (const i of clipIdx) widths[i] = 0;\n return widths;\n }\n\n // Sum of clippable natural widths; if they fit, leave them as-is.\n const clipNaturalSum = clipIdx.reduce((acc, i) => acc + (widths[i] ?? 0), 0);\n if (clipNaturalSum <= remaining) return widths;\n\n // Equal share per clippable column.\n const each = Math.floor(remaining / clipIdx.length);\n const leftover = remaining - each * clipIdx.length;\n for (let k = 0; k < clipIdx.length; k++) {\n const i = clipIdx[k];\n if (i === undefined) continue;\n widths[i] = each;\n }\n // Anchor the row visually: hand any leftover to the LAST clippable\n // column (typically the title / payload).\n const lastIdx = clipIdx[clipIdx.length - 1];\n if (lastIdx !== undefined && leftover > 0) widths[lastIdx] = (widths[lastIdx] ?? 0) + leftover;\n return widths;\n}\n\n/**\n * Render one row of cells to display strings: clip clippable cells\n * to their allocated width, then pad every cell to its column width.\n * Returns one string per column — callers map into individual <Text>\n * chunks so per-cell colour still works.\n */\nexport function renderRow(\n cells: ReadonlyArray<string>,\n widths: ReadonlyArray<number>,\n specs: ReadonlyArray<ColumnSpec>,\n): string[] {\n const out: string[] = [];\n for (let i = 0; i < specs.length; i++) {\n const spec = specs[i];\n const w = widths[i] ?? 0;\n const raw = cells[i] ?? \"\";\n if (spec === undefined) {\n out.push(raw);\n continue;\n }\n const clipped = spec.kind === \"clip\" ? truncateCell(raw, w) : raw;\n out.push(padCell(clipped, w, spec.align ?? \"left\"));\n }\n return out;\n}\n","// layout.ts — pure responsive-dashboard layout helpers.\n//\n// The TUI dashboard is glanceable, not exhaustive: cards should use\n// the horizontal and vertical space available without letting one noisy\n// list crowd out the rest. This module owns the two pure pieces that\n// make that deterministic and easy to test:\n//\n// 1. layoutColumns(cols, visibleCardIds) — breakpoint + pair-aware\n// card packing into dashboard columns.\n// 2. allocateRowBudgets(availableRows, cards) — per-column body-row\n// allocator with min-row guarantees, max caps, and largest-\n// remainder leftover distribution.\n//\n// No ink/react imports here. Cards import their own config from this\n// file and re-export it as `cardConfig`; <App> imports the pure helpers\n// and the card modules separately.\n\nimport type { WorkstreamSnapshot } from \"../../state.js\";\n\nexport type CardId = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9;\n\nexport type CardGroup = \"small-pair\" | \"task-list\" | \"stream\";\n\nexport interface CardRowConfig {\n /** Stable card name (e.g. \"commits\", \"agents\", \"inProgress\"). The\n * single source of truth for the per-card identifier; replaces\n * the old hand-rolled cardKeyFromId switch in app.tsx. Used as\n * the card-toggle visibility key (alongside the numeric CardId)\n * and as a stable string handle anywhere a name is needed. */\n name: string;\n /** Human label shown in the popup status bar (e.g. \"Commits\",\n * \"In-progress\", \"Tasks\"). Replaces the old popupNameForId\n * switch in app.tsx. Distinct from `name` because some labels\n * diverge from a naive capitalise (slot 3's name is \"ready\"\n * but its popup is the all-Tasks view; slot 6 is \"In-progress\",\n * not \"InProgress\"). */\n label: string;\n /** Minimum BODY rows to reserve for the card. Empty data still gets this much budget. */\n minRows: number;\n /** Maximum BODY rows worth rendering on the dashboard. Popups are exhaustive. */\n maxRows: number;\n /** Non-body rows consumed by TitledBox chrome + footer inset when truncated. */\n chrome: number;\n /** Static neighbour preference used by the pair-aware packer. */\n group: CardGroup;\n}\n\nexport type CardConfigMap = Readonly<Record<CardId, CardRowConfig>>;\n\n// Two rows of TitledBox chrome: 1 top-border line + 1 bottom-border\n// line. The body is rendered by the inner Box (paddingY=0) and the\n// PaddedRows helper fills it to exactly `rowBudget` text rows, so the\n// declared outer height is `chrome + rowBudget` with no slack.\n// Historically this was 4 (over-reservation) which left 2 blank rows\n// at the bottom of every card and made the dashboard feel loose; the\n// pack_dashboard_cards_tighter polish lowered it to the true chrome\n// cost so cards stack flush against each other.\nconst CARD_CHROME_ROWS = 2;\n\nexport const CARD_CONFIGS: CardConfigMap = {\n 0: {\n name: \"commits\",\n label: \"Commits\",\n minRows: 3,\n maxRows: 12,\n chrome: CARD_CHROME_ROWS,\n group: \"stream\",\n },\n 1: {\n name: \"agents\",\n label: \"Agents\",\n minRows: 2,\n maxRows: 10,\n chrome: CARD_CHROME_ROWS,\n group: \"small-pair\",\n },\n 2: {\n name: \"tracks\",\n label: \"Tracks\",\n minRows: 2,\n maxRows: 8,\n chrome: CARD_CHROME_ROWS,\n group: \"small-pair\",\n },\n 3: {\n name: \"ready\",\n label: \"Tasks\",\n minRows: 3,\n maxRows: 15,\n chrome: CARD_CHROME_ROWS,\n group: \"task-list\",\n },\n 4: {\n name: \"log\",\n label: \"Log\",\n minRows: 3,\n maxRows: 12,\n chrome: CARD_CHROME_ROWS,\n group: \"stream\",\n },\n 5: {\n name: \"workspaces\",\n label: \"Workspaces\",\n minRows: 2,\n maxRows: 8,\n chrome: CARD_CHROME_ROWS,\n group: \"small-pair\",\n },\n 6: {\n name: \"inProgress\",\n label: \"In-progress\",\n minRows: 3,\n maxRows: 12,\n chrome: CARD_CHROME_ROWS,\n group: \"task-list\",\n },\n 7: {\n name: \"blocked\",\n label: \"Blocked\",\n minRows: 3,\n maxRows: 12,\n chrome: CARD_CHROME_ROWS,\n group: \"task-list\",\n },\n 8: {\n name: \"recent\",\n label: \"Recent\",\n minRows: 3,\n maxRows: 12,\n chrome: CARD_CHROME_ROWS,\n group: \"task-list\",\n },\n 9: {\n name: \"doctor\",\n label: \"Doctor\",\n minRows: 2,\n maxRows: 8,\n chrome: CARD_CHROME_ROWS,\n group: \"small-pair\",\n },\n};\n\nexport interface ColumnAssignment {\n cards: CardId[];\n}\n\nexport interface CardHitRegion {\n id: CardId;\n column: number;\n left: number;\n right: number;\n top: number;\n bottom: number;\n}\n\nexport function dashboardColumnCount(cols: number): 1 | 2 | 3 | 4 {\n if (cols >= 240) return 4;\n if (cols >= 180) return 3;\n if (cols >= 120) return 2;\n return 1;\n}\n\n/**\n * Breakpoint + pair-aware card packer.\n *\n * - <120 cols: single stack, sorted by slot with slot 0 last.\n * - 120-179: small/task columns with stream cards split as trailers.\n * - 180-239: small cards / task-list / stream.\n * - 240+: split the two natural small pairs, then task-list, then stream.\n *\n * Empty columns are filtered out so toggling a whole group off\n * redistributes the remaining columns instead of leaving a blank lane.\n */\nexport function layoutColumns(\n cols: number,\n visibleCardIds: ReadonlyArray<CardId>,\n): ColumnAssignment[] {\n const visible = normalizeVisible(visibleCardIds);\n const target = dashboardColumnCount(cols);\n if (target === 1) {\n const cards = sortCards(visible);\n return cards.length === 0 ? [] : [{ cards }];\n }\n\n const small = sortCards(visible.filter((id) => CARD_CONFIGS[id].group === \"small-pair\"));\n const task = sortCards(visible.filter((id) => CARD_CONFIGS[id].group === \"task-list\"));\n const stream = sortCards(visible.filter((id) => CARD_CONFIGS[id].group === \"stream\"));\n\n const columns = (() => {\n if (target === 2) {\n const leftStream: CardId[] = [];\n const rightStream: CardId[] = [];\n for (const [index, id] of stream.entries()) {\n if (stream.length === 1 && id === 0) {\n rightStream.push(id);\n continue;\n }\n (index % 2 === 0 ? leftStream : rightStream).push(id);\n }\n return [\n [...small, ...sortCards(leftStream)],\n [...task, ...sortCards(rightStream)],\n ];\n }\n if (target === 3) return [small, task, stream];\n const topSmall = small.filter((id) => id === 1 || id === 2);\n const bottomSmall = small.filter((id) => id === 5 || id === 9);\n return [topSmall, bottomSmall, task, stream];\n })();\n\n return columns.filter((cards) => cards.length > 0).map((cards) => ({ cards }));\n}\n\nexport interface ColumnWidth {\n width: number;\n}\n\nexport function columnWidths(totalCols: number, columnCount: number): ColumnWidth[] {\n if (columnCount <= 0) return [];\n const gaps = columnCount - 1;\n const usable = Math.max(columnCount, totalCols - gaps);\n const base = Math.floor(usable / columnCount);\n const extra = usable - base * columnCount;\n return Array.from({ length: columnCount }, (_, i) => ({ width: base + (i < extra ? 1 : 0) }));\n}\n\nexport function dashboardCardHitRegions(\n assignments: ReadonlyArray<ColumnAssignment>,\n widths: ReadonlyArray<ColumnWidth>,\n budgets: ReadonlyArray<RowBudgetMap>,\n opts: { top?: number; left?: number; columnGap?: number } = {},\n): CardHitRegion[] {\n const topBase = opts.top ?? 1;\n const leftBase = opts.left ?? 1;\n const gap = opts.columnGap ?? 1;\n const out: CardHitRegion[] = [];\n let left = leftBase;\n for (let column = 0; column < assignments.length; column++) {\n const assignment = assignments[column];\n const width = widths[column]?.width;\n const budget = budgets[column];\n if (assignment === undefined || width === undefined || budget === undefined) continue;\n let top = topBase;\n for (const id of assignment.cards) {\n const height = CARD_CONFIGS[id].chrome + budget[id];\n out.push({ id, column, left, right: left + width - 1, top, bottom: top + height - 1 });\n top += height;\n }\n left += width + gap;\n }\n return out;\n}\n\nexport function cardRenderHeight(\n config: CardRowConfig,\n rowBudget: number | undefined,\n): number | undefined {\n return rowBudget === undefined ? undefined : config.chrome + rowBudget;\n}\n\nexport function hitTestDashboardCard(\n regions: ReadonlyArray<CardHitRegion>,\n point: { x: number; y: number },\n): CardId | null {\n for (const region of regions) {\n if (\n point.x >= region.left &&\n point.x <= region.right &&\n point.y >= region.top &&\n point.y <= region.bottom\n ) {\n return region.id;\n }\n }\n return null;\n}\n\nexport interface RowBudgetInput {\n id: CardId;\n dataCount: number;\n config?: CardRowConfig;\n}\n\nexport type RowBudgetMap = Readonly<Record<CardId, number>>;\n\nconst CARD_CULL_PRIORITY: readonly CardId[] = [9, 8, 5, 2, 7, 6, 4, 0, 1, 3];\nconst CARD_CULL_LAYOUT_COLS = 140;\n\nexport interface CulledCards {\n /** Surviving cards, preserving the caller's visible-set order after de-dupe. */\n cards: CardId[];\n /** Cards hidden because the pane is too short, in cull-priority order. */\n hidden: CardId[];\n}\n\n/**\n * Trim low-priority dashboard cards until the minimum stack fits.\n *\n * The user-controlled visible set is the ceiling: toggled-off cards\n * never reappear here. We only cull further, keeping at least one\n * card (the highest-priority visible card) so a tiny-but-not-panic\n * pane still renders a useful dashboard plus the resize hint.\n */\nexport function cullCardsForRows(\n visibleCardIds: ReadonlyArray<CardId>,\n availableRows: number,\n): CulledCards {\n const cards = normalizeVisible(visibleCardIds);\n const hidden: CardId[] = [];\n if (cards.length === 0) return { cards, hidden };\n\n const remaining = new Set<CardId>(cards);\n const budget = Math.max(0, Math.floor(availableRows));\n const maxCardsForRows = Math.max(1, Math.floor(budget / CARD_CHROME_ROWS));\n for (const id of CARD_CULL_PRIORITY) {\n const surviving = cards.filter((card) => remaining.has(card));\n if (surviving.length <= maxCardsForRows && tallestMinStackRows(surviving) <= budget) break;\n if (!remaining.has(id)) continue;\n if (remaining.size <= 1) break;\n remaining.delete(id);\n hidden.push(id);\n }\n\n return { cards: cards.filter((id) => remaining.has(id)), hidden };\n}\n\n/**\n * Post-pack column rebalancer. Pure.\n *\n * `layoutColumns` packs cards by static group (small-pair / task-list\n * / stream). When the user toggles cards off, that grouping can leave\n * one column tall and another short — the spatial intuition is\n * preserved, but the screen feels half-empty.\n *\n * `balanceColumns` is a single greedy pass that moves the most-\n * spread-reducing card from the tallest column to the shortest, until\n * no further move strictly reduces (maxHeight − minHeight). The pass\n * runs after `layoutColumns` and before `allocateRowBudgets`, so the\n * downstream pipeline sees a balanced assignment.\n *\n * Invariants:\n * - Stable-when-all-visible: the default 10-card layout is never\n * touched. Balance only fires when at least one card has been\n * toggled off (totalCards < TOTAL_CARD_COUNT). User-driven\n * toggling is what triggers the reflow.\n * - Anchored cards never move: slot 0 (Commits, conventionally\n * last) and slot 3 (Ready, the task-list anchor that motivates\n * the dashboard's primary column).\n * - Slot ordering within each receiver column is preserved via\n * `compareSlot` (slot 0 trailing).\n * - Column count is preserved: the balancer never strips a donor\n * column to empty (the empty-column filter is upstream in\n * `layoutColumns`; the balancer respects whatever it produced).\n */\nconst TOTAL_CARD_COUNT = 10;\n\nexport function balanceColumns(\n assignments: ReadonlyArray<ColumnAssignment>,\n dataCountFn: (id: CardId) => number,\n): ColumnAssignment[] {\n if (assignments.length < 2) return assignments.map((a) => ({ cards: [...a.cards] }));\n const totalCards = assignments.reduce((sum, a) => sum + a.cards.length, 0);\n if (totalCards >= TOTAL_CARD_COUNT) return assignments.map((a) => ({ cards: [...a.cards] }));\n\n const cols = assignments.map((a) => [...a.cards]);\n const heightOf = (id: CardId): number => {\n const config = CARD_CONFIGS[id];\n const data = Math.max(0, Math.floor(dataCountFn(id)));\n return config.chrome + clamp(data, config.minRows, config.maxRows);\n };\n const isAnchored = (id: CardId): boolean => id === 0 || id === 3;\n const heightsOf = (lanes: ReadonlyArray<ReadonlyArray<CardId>>): number[] =>\n lanes.map((lane) => lane.reduce<number>((sum, id) => sum + heightOf(id), 0));\n\n // Greedy outer loop. Each iteration takes one strictly-improving\n // move; bounded by columnCount * cardCount as a hard safety net\n // since each move shrinks the spread (no cycles possible).\n const safetyMax = cols.length * TOTAL_CARD_COUNT;\n for (let iter = 0; iter < safetyMax; iter++) {\n const heights = heightsOf(cols);\n const startSpread = Math.max(...heights) - Math.min(...heights);\n if (startSpread <= 0) break;\n\n let best: { donor: number; receiver: number; cardIndex: number; spread: number } | null = null;\n for (let donor = 0; donor < cols.length; donor++) {\n const donorCards = cols[donor];\n const donorH = heights[donor];\n if (donorCards === undefined || donorH === undefined) continue;\n if (donorCards.length <= 1) continue; // never strip a column to empty\n for (let cardIndex = 0; cardIndex < donorCards.length; cardIndex++) {\n const card = donorCards[cardIndex];\n if (card === undefined || isAnchored(card)) continue;\n const cardH = heightOf(card);\n for (let receiver = 0; receiver < cols.length; receiver++) {\n if (receiver === donor) continue;\n const receiverH = heights[receiver];\n if (receiverH === undefined) continue;\n const newHeights = heights.slice();\n newHeights[donor] = donorH - cardH;\n newHeights[receiver] = receiverH + cardH;\n const newSpread = Math.max(...newHeights) - Math.min(...newHeights);\n if (newSpread < startSpread && (best === null || newSpread < best.spread)) {\n best = { donor, receiver, cardIndex, spread: newSpread };\n }\n }\n }\n }\n if (best === null) break;\n\n const donorCards = cols[best.donor];\n const receiverCards = cols[best.receiver];\n if (donorCards === undefined || receiverCards === undefined) break;\n const moved = donorCards.splice(best.cardIndex, 1)[0];\n if (moved === undefined) break;\n receiverCards.push(moved);\n receiverCards.sort(compareSlot);\n }\n\n return cols.map((cards) => ({ cards }));\n}\n\n/**\n * Allocate BODY rows among the cards in one dashboard column.\n *\n * `availableRows` is the total vertical budget for the column,\n * including card chrome. The returned map contains body rows (the\n * value each card should pass to slice(0, N)). Chrome is still\n * accounted for so columns with many cards don't over-allocate.\n */\nexport function allocateRowBudgets(\n availableRows: number,\n cards: ReadonlyArray<RowBudgetInput>,\n): RowBudgetMap {\n const entries = cards.map((card) => {\n const config = card.config ?? CARD_CONFIGS[card.id];\n const dataCount = Math.max(0, Math.floor(card.dataCount));\n const minRows = Math.max(0, config.minRows);\n const maxRows = Math.max(minRows, config.maxRows);\n const naturalRows = clamp(dataCount, minRows, maxRows);\n return { id: card.id, dataCount, config, minRows, maxRows, naturalRows };\n });\n\n const out = emptyBudgetMap();\n if (entries.length === 0) return out;\n\n const naturalTotal = entries.reduce((sum, e) => sum + e.naturalRows + e.config.chrome, 0);\n if (naturalTotal <= availableRows) {\n for (const e of entries) out[e.id] = e.naturalRows;\n return out;\n }\n\n const chromeTotal = entries.reduce((sum, e) => sum + e.config.chrome, 0);\n const bodyAvailable = Math.max(0, availableRows - chromeTotal);\n const minTotal = entries.reduce((sum, e) => sum + e.minRows, 0);\n\n // Min-row guarantee. If the terminal is too short to fit the\n // guarantees plus chrome, return the guarantees anyway and let the\n // App root's overflow clip be the final guard.\n if (bodyAvailable <= minTotal) {\n for (const e of entries) out[e.id] = e.minRows;\n return out;\n }\n\n for (const e of entries) out[e.id] = e.minRows;\n\n let remaining = bodyAvailable - minTotal;\n const totalWeight = entries.reduce((sum, e) => sum + clamp(e.dataCount, e.minRows, e.maxRows), 0);\n const weighted = entries.map((e, index) => {\n const weight = totalWeight === 0 ? 1 : clamp(e.dataCount, e.minRows, e.maxRows);\n const raw = totalWeight === 0 ? remaining / entries.length : (remaining * weight) / totalWeight;\n const add = Math.min(e.maxRows - e.minRows, Math.floor(raw));\n return { id: e.id, index, raw, add, capacity: e.maxRows - e.minRows };\n });\n\n for (const w of weighted) {\n out[w.id] += w.add;\n remaining -= w.add;\n }\n\n const remainders = weighted\n .map((w) => ({ ...w, remainder: w.raw - Math.floor(w.raw) }))\n .sort((a, b) => (b.remainder === a.remainder ? a.index - b.index : b.remainder - a.remainder));\n\n while (remaining > 0) {\n let changed = false;\n for (const r of remainders) {\n if (remaining <= 0) break;\n const entry = entries[r.index];\n if (entry === undefined) continue;\n if (out[r.id] >= entry.maxRows) continue;\n out[r.id] += 1;\n remaining -= 1;\n changed = true;\n }\n if (!changed) break;\n }\n\n return out;\n}\n\nexport function dataCountForCard(id: CardId, snapshot: WorkstreamSnapshot | null): number {\n if (snapshot === null) return 0;\n switch (id) {\n case 0:\n return snapshot.recentCommits.length;\n case 1:\n return snapshot.view.agents.length;\n case 2:\n return snapshot.tracks.length;\n case 3:\n return snapshot.ready.length;\n case 4:\n return snapshot.recent.length;\n case 5:\n return snapshot.workspaces.length;\n case 6:\n return snapshot.inProgress.length;\n case 7:\n return snapshot.blocked.length;\n case 8:\n return snapshot.recentClosed.length;\n case 9:\n return snapshot.doctor?.problemCount ?? 0;\n }\n}\n\nfunction compareSlot(a: CardId, b: CardId): number {\n const ka = a === 0 ? 10 : a;\n const kb = b === 0 ? 10 : b;\n return ka - kb;\n}\n\nfunction sortCards(ids: ReadonlyArray<CardId>): CardId[] {\n return [...ids].sort(compareSlot);\n}\n\nfunction normalizeVisible(ids: ReadonlyArray<CardId>): CardId[] {\n const seen = new Set<CardId>();\n const out: CardId[] = [];\n for (const id of ids) {\n if (seen.has(id)) continue;\n seen.add(id);\n out.push(id);\n }\n return out.sort((a, b) => a - b);\n}\n\nfunction emptyBudgetMap(): Record<CardId, number> {\n return { 0: 0, 1: 0, 2: 0, 3: 0, 4: 0, 5: 0, 6: 0, 7: 0, 8: 0, 9: 0 };\n}\n\nfunction tallestMinStackRows(ids: ReadonlyArray<CardId>): number {\n let tallest = 0;\n for (const assignment of layoutColumns(CARD_CULL_LAYOUT_COLS, ids)) {\n let total = 0;\n for (const id of assignment.cards) {\n const config = CARD_CONFIGS[id];\n total += Math.max(0, config.minRows) + Math.max(0, config.chrome);\n }\n tallest = Math.max(tallest, total);\n }\n return tallest;\n}\n\nfunction clamp(value: number, min: number, max: number): number {\n return Math.max(min, Math.min(max, value));\n}\n","// ListRow — the non-selected sibling of CursorRow. Centralises the\n// per-row JSX shape every popup and card was hand-rolling.\n//\n// Per feat_centralize_list_row_render (workstream `tui-impl`): the\n// user observed that \"the unaligned columns is another example of\n// copy-paste smell. we should do all this centrally.\" Two recent\n// bugs (bug_tui_log_card_columns_misaligned and\n// bug_tui_log_popup_columns_misaligned) recurred in 18 near-identical\n// row JSX blocks because every popup and card was repeating the same\n// width pin / gutter / wrap=\"truncate\" / per-cell colour mapping by\n// hand. One forgotten attribute → one popup wrapping rows to a\n// second line / drifting columns.\n//\n// ListRow owns four invariants for every list-style row in the TUI:\n// 1. width pin on the outer <Box> — bug_tui_log_popup_columns_misaligned\n// 2. canonical {\" \"} gutter (COL_GUTTER=2) — bug class for column drift\n// 3. wrap=\"truncate\" on the outer <Text> — bug_tui_log_card_columns_misaligned\n// 4. selected → CursorRow delegation — single source for cursor highlight\n//\n// CursorRow stays the highlight primitive; ListRow defers to it\n// when `selected` is true. The non-selected branch is now declarative:\n// callers pass in already-padded `cells` (output of renderRow) and an\n// optional `colors` array of per-cell styling specs. Per-cell color\n// styling stays POSSIBLE for the non-selected branch (the cards/popups\n// rely on `dimColor`, `bold`, `color=\"cyan\"` etc.); the SELECTED branch\n// trades all per-cell colour for a solid-inverse line — same trade-off\n// CursorRow already locked in (see cursor-row.tsx header).\n//\n// The component lives at src/cli/tui/list-row.tsx (sibling of\n// columns.ts and titled-box.tsx, NOT under popups/) because both\n// popups/* and cards/* consume it. Keeping it at the cluster root\n// matches the placement of the other shared primitives.\n\nimport { Box, Text } from \"ink\";\nimport type { ReactElement } from \"react\";\nimport { COL_GUTTER } from \"./columns.js\";\nimport { CursorRow } from \"./popups/cursor-row.js\";\n\n/** Per-cell styling spec. Mirrors the props ink's <Text> takes for\n * the colour palette every popup/card was hand-coding. `undefined`\n * cells (or a missing `colors` array) render as plain text. */\nexport interface CellColor {\n color?: string;\n bold?: boolean;\n dimColor?: boolean;\n}\n\nexport interface ListRowProps {\n /** Already-padded cells (output of renderRow). */\n cells: ReadonlyArray<string>;\n /** Total available content width (popup/card body width). */\n contentWidth: number;\n /** Per-cell styling. `colors[i]` applies to `cells[i]`; missing or\n * `undefined` entries render as plain text. */\n colors?: ReadonlyArray<CellColor | undefined>;\n /** When true, defer to CursorRow (solid-inverse highlight; no\n * per-cell colour). Routing the selected branch through ListRow\n * means popup authors never write a `selected ? <CursorRow> :\n * <Box>...` if-branch by hand. */\n selected?: boolean;\n}\n\nexport function ListRow({ cells, contentWidth, colors, selected }: ListRowProps): ReactElement {\n if (selected) return <CursorRow cells={cells} contentWidth={contentWidth} />;\n const gutter = \" \".repeat(COL_GUTTER);\n // Build the children list inline so React only sees one array of\n // <Text> nodes interleaved with literal gutter <Text>s. Same shape\n // ink renders today; the difference is that ListRow owns the\n // construction so a future row author can't drift the gutter or\n // forget wrap=\"truncate\".\n const children: React.ReactNode[] = [];\n for (let i = 0; i < cells.length; i++) {\n const cell = cells[i] ?? \"\";\n if (i > 0) children.push(<Text key={`g${i}`}>{gutter}</Text>);\n const c = colors?.[i];\n if (c === undefined) {\n children.push(<Text key={`c${i}`}>{cell}</Text>);\n } else {\n children.push(\n <Text key={`c${i}`} color={c.color} bold={c.bold} dimColor={c.dimColor}>\n {cell}\n </Text>,\n );\n }\n }\n return (\n <Box width={contentWidth}>\n <Text wrap=\"truncate\">{children}</Text>\n </Box>\n );\n}\n","// CursorRow — the highlight line shared by every list popup.\n//\n// Per bug_tui_popup_cursor_highlight_color_leak (workstream\n// `tui-impl`): the previous popup pattern wrapped per-cell <Text>\n// chunks (color=cyan / bold / dimColor) inside a single\n// <Text inverse={sel}>. ink emits an independent ANSI sequence per\n// nested <Text>, and inner SGR sequences (color/bold/dim) RESET the\n// outer `inverse` state — so the cursor row showed inverse video\n// only on bare-text/whitespace cells while every coloured cell broke\n// it. Plus the row <Box> was content-sized, so the highlight ended\n// at the last character of content rather than spanning the popup\n// width.\n//\n// Fix: when a row is selected, render it as PLAIN TEXT (no per-cell\n// palette), join the already-padded cells with the canonical 2-space\n// gutter (COL_GUTTER), padEnd to contentWidth, and wrap in a single\n// <Text inverse>. The cursor row trades its colour palette for a\n// solid full-width highlight — the lazygit / k9s / btop convention.\n//\n// `wrap=\"truncate\"` matches the cards/popups defensive-belt\n// invariant asserted by test/tui-card-render-width.test.ts: every\n// outer row-rendering <Text> truncates at the parent's width rather\n// than wrapping to a new line.\n\nimport { Box, Text } from \"ink\";\nimport type { ReactElement } from \"react\";\nimport { COL_GUTTER } from \"../columns.js\";\n\nexport interface CursorRowProps {\n /** Already-padded cells (output of renderRow). */\n cells: ReadonlyArray<string>;\n /** Total available content width (popup body width). */\n contentWidth: number;\n}\n\nexport function CursorRow({ cells, contentWidth }: CursorRowProps): ReactElement {\n const gutter = \" \".repeat(COL_GUTTER);\n const line = cells.join(gutter).padEnd(Math.max(contentWidth, 0));\n return (\n <Box width={contentWidth}>\n <Text inverse wrap=\"truncate\">\n {line}\n </Text>\n </Box>\n );\n}\n","// TitledBox — a rounded-border container whose section header sits\n// INSIDE the top border line (lazygit / htop / btop convention)\n// instead of consuming a row of body content.\n//\n// ╭─ ¹ Agents · 3 free ───────────────────────╮\n// │ <free> worker-1 free build_x — │\n// │ <busy> worker-2 busy review_x — │\n// ╰───────────────────────────────────────────╯\n//\n// IMPLEMENTATION\n//\n// ink v5 has no `borderTitle` prop, so we render the top border row\n// ourselves as a single <Text> (corner + dash + ' ' + [digit + ' '] +\n// title [+ ' · ' + subtitle] + ' ' + dash-fill + corner) and stack a\n// second <Box> below with `borderTop={false}` so ink's normal border\n// machinery draws the side+bottom edges and corners.\n//\n// To keep the manual top row aligned column-for-column with the body\n// Box's bottom border, both pieces share an explicit `width` derived\n// from `useStdout().columns`. v0 only stacks cards vertically (full\n// pane width); a future responsive-layout task can either (a) pass\n// an explicit `width` prop down or (b) wrap each cell in a width-\n// pinned Box. The pure helper `computeTopRowDashes` is exported so\n// either layout strategy can re-use the geometry.\n//\n// CARD-DIGIT PREFIX (feat_card_header_digit_prefix)\n//\n// Cards pass `cardId` so a Unicode superscript form of the toggle key\n// (¹ ² ³ ⁴ … ⁰) is rendered in yellow before the title. This mirrors\n// btop / htop, where the leading digit IS the toggle key. The help\n// overlay uses the same glyphs so the visual language matches.\n//\n// BOTTOM-BORDER INSET (feat_card_footer_inset)\n//\n// Cards optionally pass `bottomLabel` to render the truncation hint\n// (\"+11 more · Shift+3\") INSIDE the bottom border line, mirroring the\n// top-border title:\n//\n// ╭─ ³ Ready · 14 ─────────────────────────╮\n// │ build_x ROI 100 │\n// │ review_x ROI 60 │\n// │ ship_x ROI 50 │\n// ╰─ +11 more · Shift+3 ───────────────────╯\n//\n// Per the design correction in the task notes: NO superscript /\n// digit prefix on the bottom row — the label already says \"Shift+N\"\n// in plain text, and the superscript is a top-edge convention\n// (toggle-key affordance). When set, the inner Box's bottom border\n// is suppressed (`borderBottom={false}`) and a hand-rendered Text\n// row is stacked below it, exactly mirroring the top-row code path.\n// Geometry is shared via the pure helper `computeBorderRowDashes`.\n\nimport { Box, Text } from \"ink\";\nimport type { ReactElement, ReactNode } from \"react\";\nimport stringWidth from \"string-width\";\nimport { superscriptDigit } from \"../../glyphs.js\";\nimport { useTerminalSize } from \"./use-terminal-size.js\";\n\nconst ROUND = {\n topLeft: \"╭\",\n topRight: \"╮\",\n bottomLeft: \"╰\",\n bottomRight: \"╯\",\n horizontal: \"─\",\n} as const;\n\nexport interface TitledBoxProps {\n /** Bold/coloured headline text (e.g. \"Agents\"). */\n title: string;\n /** Optional dim subtitle rendered after \" · \" (e.g. \"3 free\"). */\n subtitle?: string;\n /** Optional 0..9 toggle key. When set, the matching superscript\n * glyph is rendered in yellow before the title (btop convention). */\n cardId?: number;\n /** Border colour. Cards default to \"gray\"; popups/help to \"cyan\". */\n borderColor?: string;\n /** Title colour (the bold part). Defaults to \"cyan\". */\n titleColor?: string;\n /** Optional inset label rendered inside the BOTTOM border line\n * (feat_card_footer_inset). Cards pass it only when the body is\n * truncated; otherwise omit and the bottom border renders as\n * plain dashes. NO superscript prefix here per the design\n * correction — the bottom-edge convention is a literal keystroke\n * hint (\"Shift+3\"), not a toggle affordance. */\n bottomLabel?: string;\n /** Optional fixed outer height in rows. Cards pass\n * `chrome + rowBudget` so dashboard hit-test rectangles and Ink\n * render geometry stay identical even when the body has fewer rows\n * than its allocated budget (empty-state cards are the common\n * case). Popups omit it and flex vertically instead. */\n height?: number;\n /** Optional Yoga flex-grow factor. Applied to BOTH the outer\n * column container AND the inner border-body Box so popup\n * Shells (which previously hand-rolled their own rounded box\n * with `flexGrow={1}` per bug_tui_popups_fill_pane) can flex\n * vertically inside an App-level height-pinned region without\n * collapsing to content size. Cards omit it (default behaviour\n * unchanged: outer Box sizes to content). */\n flexGrow?: number;\n /** Outer width in terminal columns. Defaults to the full stdout\n * width; responsive dashboard columns pass their per-column width. */\n width?: number;\n children?: ReactNode;\n}\n\n/** Default for the outer Box's flexShrink. Yoga's default is 0\n * (unlike CSS's 1), so when the dashboard's nine cards' summed\n * natural height exceeds the height-pinned root <Box height={rows}>,\n * Yoga keeps every child at its natural size and the overflow is\n * emitted past the terminal's bottom — which (because ink writes\n * the whole frame in one go and the cursor starts at row 1) makes\n * the terminal scroll and silently drops the TOPMOST border row.\n * See bug_tui_dashboard_top_card_scrolls_off for the long-form\n * diagnosis. Setting flexShrink=1 lets Yoga distribute the deficit\n * proportionally across cards, so the bottom card's body clips\n * instead of the topmost card's chrome scrolling off-screen. */\nconst TITLED_BOX_FLEX_SHRINK = 1;\n\n/**\n * Generic geometry helper for ANY border row that insets a single\n * label between the corner+dash prefix and the dash-fill+corner\n * suffix. Used by both the top-border (where the \"label\" is the\n * effective width of title + subtitle + cardId composed) and the\n * bottom-border (where the label is the raw bottomLabel string).\n *\n * Anatomy: `╭─ <label> <dashes>╮` (top)\n * `╰─ <label> <dashes>╯` (bottom)\n *\n * Per-piece column cost (5 fixed + label + dashes):\n * corner 1\n * ─ 1\n * ' ' 1\n * label L\n * ' ' 1\n * dashes D\n * corner 1\n *\n * Floors at 1 — if the terminal is too narrow, we let the line\n * overflow rather than producing an empty/negative-width fill.\n */\nexport function computeBorderRowDashes(cols: number, label: string): number {\n return Math.max(1, cols - 5 - stringWidth(label));\n}\n\n/**\n * Top-border specialization: composes title + ' · ' + subtitle and\n * an optional leading digit prefix into the effective label width,\n * then delegates to `computeBorderRowDashes`. Pure function so a\n * unit test can pin the geometry without spinning up ink.\n *\n * Per-piece column cost (relative to the generic 5-fixed base):\n * digit 1 (when cardId set; superscript glyphs are 1 col)\n * ' ' (sep) 1 (when cardId set)\n * title T\n * ' · ' 3 (when subtitle set)\n * subtitle S\n */\nexport function computeTopRowDashes(\n cols: number,\n title: string,\n subtitle?: string,\n cardId?: number,\n): number {\n const titleW = stringWidth(title);\n const subW = subtitle === undefined || subtitle.length === 0 ? 0 : stringWidth(subtitle);\n const subCost = subW === 0 ? 0 : 3 + subW; // ' · ' + S\n const digitCost = cardId === undefined ? 0 : 2; // digit + ' '\n return Math.max(1, cols - 5 - titleW - subCost - digitCost);\n}\n\nexport function TitledBox({\n title,\n subtitle,\n cardId,\n borderColor = \"gray\",\n titleColor = \"cyan\",\n bottomLabel,\n height,\n flexGrow,\n width,\n children,\n}: TitledBoxProps): ReactElement {\n const { cols: termCols } = useTerminalSize();\n const cols = width ?? termCols;\n const dashes = computeTopRowDashes(cols, title, subtitle, cardId);\n const fill = ROUND.horizontal.repeat(dashes);\n const hasSubtitle = subtitle !== undefined && subtitle.length > 0;\n const digitGlyph = cardId === undefined ? null : superscriptDigit(cardId);\n const hasBottomLabel = bottomLabel !== undefined && bottomLabel.length > 0;\n const bottomDashes = hasBottomLabel ? computeBorderRowDashes(cols, bottomLabel) : 0;\n const bottomFill = ROUND.horizontal.repeat(bottomDashes);\n\n return (\n <Box\n flexDirection=\"column\"\n width={cols}\n height={height}\n flexGrow={flexGrow}\n flexShrink={TITLED_BOX_FLEX_SHRINK}\n overflow=\"hidden\"\n >\n <Text color={borderColor}>\n {ROUND.topLeft}\n {ROUND.horizontal}{\" \"}\n {digitGlyph !== null ? (\n <>\n <Text bold color=\"yellow\">\n {digitGlyph}\n </Text>{\" \"}\n </>\n ) : null}\n <Text bold color={titleColor}>\n {title}\n </Text>\n {hasSubtitle ? (\n <>\n <Text color={borderColor}> · </Text>\n <Text dimColor>{subtitle}</Text>\n </>\n ) : null}{\" \"}\n {fill}\n {ROUND.topRight}\n </Text>\n <Box\n borderStyle=\"round\"\n borderColor={borderColor}\n borderTop={false}\n borderBottom={!hasBottomLabel}\n paddingX={1}\n flexDirection=\"column\"\n flexGrow={flexGrow}\n flexShrink={0}\n >\n {children}\n </Box>\n {hasBottomLabel ? (\n <Text color={borderColor}>\n {ROUND.bottomLeft}\n {ROUND.horizontal} <Text dimColor>{bottomLabel}</Text> {bottomFill}\n {ROUND.bottomRight}\n </Text>\n ) : null}\n </Box>\n );\n}\n","// Shared reactive terminal-size hook for all TUI surfaces.\n//\n// ink's `useStdout()` returns the raw stdout stream, but reading\n// `.columns` / `.rows` during render only captures the value at\n// that moment — ink does NOT re-render when the terminal resizes.\n// This hook subscribes to the `resize` event on stdout and bumps\n// local state so every consumer re-renders with the new dimensions.\n//\n// Usage:\n//\n// const { cols, rows } = useTerminalSize();\n//\n// Replaces the boilerplate pattern:\n//\n// const { stdout } = useStdout();\n// const cols = stdout?.columns ?? 80;\n//\n// Per ROADMAP pledge: ink/react import confined to src/cli/tui/*.\n\nimport { useStdout } from \"ink\";\nimport { useEffect, useState } from \"react\";\n\n// One \"resize\" listener per stream, fanned out to every mounted hook.\n// A listener per hook instance tripped Node's MaxListenersExceededWarning\n// (>10) once a popup + drill + cards were mounted at once.\nconst subscribers = new WeakMap<NodeJS.WriteStream, Set<() => void>>();\n\nfunction subscribeResize(stdout: NodeJS.WriteStream, fn: () => void): () => void {\n let set = subscribers.get(stdout);\n if (set === undefined) {\n const fresh = new Set<() => void>();\n set = fresh;\n subscribers.set(stdout, fresh);\n stdout.on(\"resize\", () => {\n for (const sub of [...fresh]) sub();\n });\n }\n set.add(fn);\n return () => {\n set.delete(fn);\n };\n}\n\nexport interface TerminalSize {\n cols: number;\n rows: number;\n}\n\n/**\n * Returns the current terminal dimensions and re-renders whenever\n * the terminal is resized. Falls back to 80×24 when stdout is not\n * a TTY (e.g. test capture streams without columns/rows).\n */\nexport function useTerminalSize(): TerminalSize {\n const { stdout } = useStdout();\n const [size, setSize] = useState<TerminalSize>({\n cols: stdout?.columns ?? 80,\n rows: stdout?.rows ?? 24,\n });\n\n useEffect(() => {\n if (!stdout) return;\n const onResize = () => {\n setSize((prev) => {\n const cols = stdout.columns ?? 80;\n const rows = stdout.rows ?? 24;\n // Bail when nothing changed so we don't queue a no-op re-render.\n // This matters on mount: the defensive sync below would\n // otherwise force a second render every time the hook mounts\n // (the initial useState already read the same dimensions),\n // doubling work in production and doubling captured frames in\n // ink render tests. Returning the SAME object reference makes\n // React skip the update. bug_use_terminal_size_double_render.\n if (prev.cols === cols && prev.rows === rows) return prev;\n return { cols, rows };\n });\n };\n const unsubscribe = subscribeResize(stdout, onResize);\n // Sync in case the size changed between initial render and effect\n // registration (unlikely but defensive). Now a no-op when the size\n // is unchanged — see the reference-equality bail above.\n onResize();\n return unsubscribe;\n }, [stdout]);\n\n return size;\n}\n","// CardPlaceholder — shared scaffolding for card loading + empty\n// (and other one-line) body branches.\n//\n// Before this helper, every card under src/cli/tui/cards/*.tsx\n// repeated a near-identical 10-line block for its loading branch\n// AND for its empty branch:\n//\n// <TitledBox\n// height={cardRenderHeight(cardConfig, rowBudget)}\n// width={cols}\n// title=\"<Title>\"\n// cardId={N}\n// >\n// <PaddedRows rows={rowBudget ?? cardConfig.minRows}>\n// <Text dimColor>loading…</Text> {/* or \"(none ...)\" */}\n// </PaddedRows>\n// </TitledBox>\n//\n// That's 20+ blocks across 10 files, all carrying the same chrome\n// pattern (height = chrome + rowBudget; PaddedRows = rowBudget ??\n// minRows). Adding a new card-level chrome attribute (e.g. a per-\n// card border colour, a new bottom-label rule for empty-state)\n// required editing every block. Now there's one knob.\n//\n// USAGE\n// return CardPlaceholder({\n// title: \"Agents\", cardId: 1,\n// rowBudget, cols,\n// config: cardConfig,\n// subtitle, // optional (omit for loading; threaded\n// // through for empty/healthy paths\n// // that already compute one)\n// text: \"loading…\", // dim text body (most common case)\n// });\n//\n// For richer bodies (e.g. an inline code hint that interpolates a\n// workstream name, or the doctor's coloured healthy-check line), pass\n// `children` (a ReactNode) instead of `text`. The helper\n// only injects the dimColor wrapper when `text` is used; `children`\n// is rendered verbatim so the caller controls every Text node.\n//\n// CALLED AS A FUNCTION, NOT AS JSX\n// Card render functions invoke `CardPlaceholder({...})` directly\n// instead of `<CardPlaceholder .../>`. This matches how test\n// helpers (test/_card-render.ts) treat the cards themselves: they\n// call `AgentsCard({snapshot})` and walk the returned JSX tree.\n// If we used JSX, the test walker would see a `<CardPlaceholder>`\n// element with the helper's prop names (text, config, rowBudget),\n// none of which it knows how to render — the title/height/rows\n// it greps for would be hidden one synthetic-component level\n// deeper. Calling the helper as a function eagerly evaluates it\n// to the underlying `<TitledBox>` tree, keeping the existing\n// walker contract intact.\n//\n// PURE WRAPPER, ZERO BEHAVIOUR DRIFT\n// The rendered output is byte-identical to the hand-rolled\n// blocks: same TitledBox prop set, same PaddedRows row count,\n// same single-Text body. Tests that grep for title + body text\n// via renderCardToText are unchanged.\n\nimport { Text } from \"ink\";\nimport type { ReactElement, ReactNode } from \"react\";\nimport { type CardRowConfig, cardRenderHeight } from \"../layout.js\";\nimport { PaddedRows } from \"../padded-rows.js\";\nimport { TitledBox } from \"../titled-box.js\";\n\nexport interface CardPlaceholderProps {\n /** Card title (e.g. \"Agents\"). Bold/coloured headline. */\n title: string;\n /** 0..9 toggle key — yellow superscript glyph before the title. */\n cardId: number;\n /** Card's static row config (CARD_CONFIGS[id]); used for both the\n * fixed outer height (chrome + rowBudget) and the PaddedRows\n * fallback when the dashboard hasn't allocated a row budget yet\n * (i.e. minRows). */\n config: CardRowConfig;\n /** Dashboard-allocated body row budget. Undefined → use minRows. */\n rowBudget?: number;\n /** Outer width in terminal columns; threaded through to TitledBox. */\n cols?: number;\n /** Optional dim subtitle rendered after \" · \". */\n subtitle?: string;\n /** Body text, rendered as a single <Text dimColor>{text}</Text>.\n * Mutually exclusive with `children`; if both are passed, `children`\n * wins (the richer-JSX path). */\n text?: string;\n /** Body ReactNode for richer renders (inline code hint, multi-Text\n * doctor healthy line, …). Rendered verbatim — the caller controls\n * every wrapping Text node. */\n children?: ReactNode;\n}\n\nexport function CardPlaceholder({\n title,\n cardId,\n config,\n rowBudget,\n cols,\n subtitle,\n text,\n children,\n}: CardPlaceholderProps): ReactElement {\n return (\n <TitledBox\n height={cardRenderHeight(config, rowBudget)}\n width={cols}\n title={title}\n subtitle={subtitle}\n cardId={cardId}\n >\n <PaddedRows rows={rowBudget ?? config.minRows}>\n {children ?? <Text dimColor>{text}</Text>}\n </PaddedRows>\n </TitledBox>\n );\n}\n","import { Text } from \"ink\";\nimport type { ReactElement, ReactNode } from \"react\";\n\nexport interface PaddedRowsProps {\n rows?: number;\n children: ReactNode;\n}\n\n/** Ensure one-line empty/loading card bodies still occupy their row budget. */\nexport function PaddedRows({ rows, children }: PaddedRowsProps): ReactElement {\n const targetRows = Math.max(0, Math.floor(rows ?? 0));\n const blanks = Math.max(0, targetRows - 1);\n return (\n <>\n {children}\n {Array.from({ length: blanks }, (_, i) => `blank-${i}`).map((key) => (\n <Text key={key}> </Text>\n ))}\n </>\n );\n}\n","// Pure formatters shared across the TUI cards/popups cluster.\n//\n// Hoisted out of cards/* and popups/* in a single bundled pass per:\n// - review_dedup_age_ms (4 consumers)\n// - review_dedup_color_for_bucket (3 byte-identical copies)\n// - review_dedup_format_roi (3 callsites + 2 inline dups)\n// - review_unify_format_when_since (formatSinceClaim / formatWhen\n// → relTime / relTimeAgo)\n//\n// Every helper here is pure (input → output, no I/O, no ink/react),\n// covered directly by test/tui-format-helpers.test.ts. Card / popup\n// modules import from here instead of carrying their own copies.\n//\n// New helpers belong here only when ≥2 cards/popups need them; one-\n// off card-local helpers stay co-located with their card. Keep this\n// module ink/react-free so it can be imported from anywhere.\n\nimport type { RoiBucket } from \"../../state.js\";\nimport type { TaskRow } from \"../../tasks.js\";\nimport { relTime, relTimeAgo } from \"../format.js\";\n\n/** Milliseconds since the task last had a lifecycle flip. Returns\n * null when updatedAt is unparseable (defensive — every row from\n * SQLite will be a valid ISO-8601 string). The basis is `now` so\n * tests can pin time without leaning on the wall clock.\n *\n * Used by: cards/inprogress, cards/recent, popups/inprogress,\n * popups/recent. */\nexport function ageMs(t: TaskRow, now: number): number | null {\n const ts = Date.parse(t.updatedAt);\n if (Number.isNaN(ts)) return null;\n return Math.max(0, now - ts);\n}\n\n/** Ink colour for an ROI bucket: high|infinite → green, mid →\n * yellow, low → undefined (no colour, default text colour). Pure;\n * consumers pass the result straight to a `<Text color=...>`.\n *\n * Used by: cards/ready, cards/blocked, popups/blocked. */\nexport function colorForBucket(b: RoiBucket): string | undefined {\n switch (b) {\n case \"high\":\n case \"infinite\":\n return \"green\";\n case \"mid\":\n return \"yellow\";\n case \"low\":\n return undefined;\n }\n}\n\n/** Render the ROI cell as a short integer, or \"∞\" when effortDays is\n * zero / negative (matches the convention used by every blocked /\n * ready / in-progress / recent card and popup). Pure.\n *\n * Used by: cards/blocked, cards/ready, popups/blocked,\n * popups/inprogress, popups/recent. */\nexport function formatRoi(impact: number, effortDays: number): string {\n if (effortDays <= 0) return \"∞\";\n const r = Math.round(impact / effortDays);\n return Number.isFinite(r) ? String(r) : \"∞\";\n}\n\n/** Render an in-flight age in milliseconds as a short relative-time\n * token (no suffix):\n * < 60s → \"Ns\"\n * < 60m → \"Nm\"\n * < 24h → \"Nh\"\n * < 7d → \"Nd\"\n * else → \"Nw\"\n * null / undefined → \"—\". Thin wrapper over relTime() so the TUI\n * cluster shares the canonical formatter. The \"—\" sentinel is the\n * only TUI-specific bit (CLI tables render \"—\" themselves at the\n * call site).\n *\n * Used by: cards/inprogress, popups/inprogress. */\nexport function formatSinceClaim(ms: number | null | undefined): string {\n if (ms === null || ms === undefined) return \"—\";\n return relTime(ms);\n}\n\n/** Render an age in milliseconds (the Recent views pass updated_at, a\n * proxy for close time) as a short relative-time\n * token with the trailing \" ago\" suffix:\n * < 60s → \"Ns ago\"\n * < 60m → \"Nm ago\"\n * < 24h → \"Nh ago\"\n * < 7d → \"Nd ago\"\n * else → \"Nw ago\"\n * null / undefined → \"—\". The \" ago\" suffix is the differentiator\n * vs formatSinceClaim (in-flight, present tense); here every row\n * is past tense.\n *\n * Used by: cards/recent, popups/recent. */\nexport function formatWhen(ms: number | null | undefined): string {\n if (ms === null || ms === undefined) return \"—\";\n return relTimeAgo(ms);\n}\n","// Blocked card — every OPEN task with at least one still-gating\n// blocker (i.e. a non-CLOSED prerequisite). Fills the diagnostic gap\n// described in feat_card_7_blocked (workstream `tui-impl`):\n//\n// \"What's blocking the umbrella?\" is the most common diagnostic\n// question during multi-wave orchestration. Today the operator must\n// walk the dependency tree manually via `mu task tree <id>`. One\n// glanceable card surfaces the blocked-tasks subset directly.\n//\n// Card 7 promotes a slot reserved by design_global_keymap. Mirrors\n// the shape of Card 5 — Workspaces (264585f9) and Card 6 — In-progress\n// (760fc6c) so the operator reads it the same way: TitledBox header,\n// column-aligned rows, glanceable subtitle.\n//\n// CARD LAYOUT\n// glyph id STATUS #blocks ROI title\n// <blocked> review_x OPEN 2 75 Review X\n// <blocked> cherry_x OPEN 1 60 Cherry-pick X\n//\n// The glyph is GLYPH.blocked from src/glyphs.ts (a chain link) and\n// reads as \"this is blocked / chained to something\". Coloured dim — the operator's eye is meant to land\n// on the #blockers / top-blocker subtitle, not the row glyph.\n// STATUS column is a stable \"OPEN\" string (the BLOCKED view filters\n// to OPEN by definition — see src/db.ts BLOCKED_VIEW_SQL); kept in\n// the row for visual consistency with the other task lists.\n//\n// CLIPPING POLICY (per feat_column_aligned_lists)\n// id, STATUS, #blocks, ROI → PROTECT (yankable / numeric / identifier)\n// title → CLIP (free-form prose)\n//\n// SUBTITLE\n// empty → omitted (no blocked tasks → empty-state body)\n// populated → \"<N>\" when no top blocker\n// \"<N> · top blocker: <id>\" otherwise\n//\n// \"Top blocker\" = the still-gating blocker (status ≠ CLOSED) that\n// appears most often across the visible blocked rows. Ties broken by\n// the blocker's local id (alphabetic). This surfaces the single\n// task that, if closed, would unblock the most downstream work — the\n// most actionable hint at a glance. Computed over the visible (≤\n// ROW_LIMIT) rows, not the full blocked list, so the displayed top\n// blocker is one the operator can correlate against the rendered\n// rows.\n//\n// DATA\n// - snapshot.blocked is the OPEN-with-unsatisfied-blockers slice\n// from the BLOCKED SQL view. Used directly.\n// - per-row blocker counts come from getTaskEdgesWithStatus(db, id,\n// ws), filtered to non-CLOSED. ROW_LIMIT (8) caps the per-tick\n// SQLite reads at 8 prepared-statement queries — orders of\n// magnitude cheaper than the per-row `git status --porcelain`\n// shellouts the Workspaces card already does. No SDK extension\n// per the task brief.\n//\n// POPUP / FUTURE OBLIGATIONS (when slot-7 popup ships)\n// Out of scope NOW. When the popup is added under\n// feat_more_cards_umbrella, it MUST consume:\n// (a) feat_popup_search_filter — '/' filter via usePopupFilter\n// (b) feat_track_drill_chains_to_task_drill — Enter chains rows\n// into TaskDetailDrill (rows ARE tasks)\n// Until then, Shift+7 (`&`) stays a reserved noop in keys.ts.\n\nimport type { ReactElement } from \"react\";\nimport type { Db } from \"../../../db.js\";\nimport { GLYPH as SHARED_GLYPH } from \"../../../glyphs.js\";\nimport { roiBucket, type WorkstreamSnapshot } from \"../../../state.js\";\nimport { formatPair } from \"../../../tasks/status.js\";\nimport { getTaskEdgesWithStatus, type TaskEdgeWithStatus } from \"../../../tasks.js\";\nimport { inkColorForPair } from \"../../format.js\";\nimport {\n type ColumnSpec,\n contentWidthFromCols,\n layoutColumns,\n renderRow,\n termColsForLayout,\n} from \"../columns.js\";\nimport { colorForBucket, formatRoi } from \"../format-helpers.js\";\nimport { CARD_CONFIGS, cardRenderHeight } from \"../layout.js\";\nimport { ListRow } from \"../list-row.js\";\nimport { TitledBox } from \"../titled-box.js\";\nimport { CardPlaceholder } from \"./_placeholder.js\";\n\nexport interface BlockedCardProps {\n snapshot: WorkstreamSnapshot | null;\n db: Db;\n workstream: string;\n rowBudget?: number;\n cols?: number;\n}\n\nexport const cardConfig = CARD_CONFIGS[7];\n\n/** Glyph for every blocked row. Always the chain-link. */\nexport const GLYPH = SHARED_GLYPH.blocked;\n\nconst COLUMN_SPECS: ReadonlyArray<ColumnSpec> = [\n { kind: \"protect\" }, // glyph\n { kind: \"protect\" }, // task id\n { kind: \"protect\" }, // status (always OPEN; constant for now)\n { kind: \"protect\", align: \"right\" }, // #blockers\n { kind: \"protect\", align: \"right\" }, // ROI label (e.g. \"75\")\n { kind: \"clip\", min: 1 }, // title\n];\n\nexport function BlockedCard({\n snapshot,\n db,\n workstream,\n rowBudget,\n cols,\n}: BlockedCardProps): ReactElement {\n const contentWidth = contentWidthFromCols(cols ?? termColsForLayout());\n if (snapshot === null) {\n return CardPlaceholder({\n title: \"Blocked\",\n cardId: 7,\n config: cardConfig,\n rowBudget,\n cols,\n text: \"loading…\",\n });\n }\n\n const { blocked } = snapshot;\n\n if (blocked.length === 0) {\n return CardPlaceholder({\n title: \"Blocked\",\n cardId: 7,\n config: cardConfig,\n rowBudget,\n cols,\n text: \"(none blocked)\",\n });\n }\n\n const shown = blocked.slice(0, rowBudget ?? cardConfig.maxRows);\n const more = blocked.length - shown.length;\n const bottomLabel = more > 0 ? `+${more} more · Shift+7` : undefined;\n // One getTaskEdgesWithStatus call per visible row. Cap at 8 →\n // synchronous better-sqlite3 reads on a join, vastly cheaper than\n // the per-row shellouts the Workspaces card does.\n const blockerLists = shown.map((t) =>\n stillGating(getTaskEdgesWithStatus(db, t.name, workstream).blockers),\n );\n const topBlocker = pickTopBlocker(blockerLists);\n const topEdge = blockerLists.flat().find((b) => b.name === topBlocker);\n const subtitle = formatSubtitle(blocked.length, topEdge ? blockerLabel(topEdge) : topBlocker);\n\n const meta = shown.map((t) => {\n const bucket = roiBucket(t.impact, t.effortDays);\n const roiText = formatRoi(t.impact, t.effortDays);\n return { bucket, roiText };\n });\n const rows = shown.map((t, i) => [\n GLYPH,\n t.name,\n formatPair(t),\n String(blockerLists[i]?.length ?? 0),\n meta[i]?.roiText ?? \"\",\n t.title,\n ]);\n const widths = layoutColumns(rows, COLUMN_SPECS, contentWidth);\n\n return (\n <TitledBox\n height={cardRenderHeight(cardConfig, rowBudget)}\n width={cols}\n title=\"Blocked\"\n subtitle={subtitle}\n cardId={7}\n bottomLabel={bottomLabel}\n >\n {shown.map((t, i) => {\n const row = rows[i];\n const m = meta[i];\n if (row === undefined || m === undefined) return null;\n const padded = renderRow(row, widths, COLUMN_SPECS);\n const colors = [\n { dimColor: true }, // glyph\n { bold: true }, // id\n { color: inkColorForPair(t) }, // status\n { color: \"yellow\" }, // blocks\n { color: colorForBucket(m.bucket) }, // roi\n { dimColor: true }, // title\n ];\n return <ListRow key={t.name} cells={padded} contentWidth={contentWidth} colors={colors} />;\n })}\n </TitledBox>\n );\n}\n\n// ─── pure helpers (exported for unit tests) ────────────────────────\n\n/** Filter a list of blockers to the still-gating ones. A blocker is\n * still-gating iff its status is not CLOSED (only CLOSED satisfies a\n * blocked-by edge per the BLOCKED view in src/db.ts). Returns a new\n * array; does not mutate. */\nexport function stillGating(blockers: ReadonlyArray<TaskEdgeWithStatus>): TaskEdgeWithStatus[] {\n return blockers.filter((b) => b.status !== \"CLOSED\");\n}\n\n/** A blocker's display name: \" (parked)\" appended when it is\n * OPEN/parked, since a parked blocker will not close on its own. */\nexport function blockerLabel(b: TaskEdgeWithStatus): string {\n return b.status === \"OPEN\" && b.substate === \"parked\" ? `${b.name} (parked)` : b.name;\n}\n\n/** Pick the still-gating blocker that appears most often across the\n * given per-row blocker lists. Ties broken by alphabetic blocker\n * local id. Returns null when no blockers are present (all rows\n * somehow had every blocker satisfied — defensive: shouldn't happen\n * given the BLOCKED view, but the empty-input branch keeps the\n * function total).\n *\n * Surfacing the most-shared blocker is the most actionable hint —\n * closing it unblocks the most downstream rows in one move. */\nexport function pickTopBlocker(\n blockerLists: ReadonlyArray<ReadonlyArray<TaskEdgeWithStatus>>,\n): string | null {\n const counts = new Map<string, number>();\n for (const list of blockerLists) {\n for (const b of list) {\n counts.set(b.name, (counts.get(b.name) ?? 0) + 1);\n }\n }\n if (counts.size === 0) return null;\n let best: string | null = null;\n let bestCount = -1;\n // Iterate in alphabetic order so ties resolve deterministically\n // (Map iteration is insertion order; we explicitly sort the keys).\n for (const name of [...counts.keys()].sort()) {\n const c = counts.get(name) ?? 0;\n if (c > bestCount) {\n best = name;\n bestCount = c;\n }\n }\n return best;\n}\n\n/** Build the subtitle: \"<total>\" or \"<total> · top blocker: <id>\".\n * topBlocker null → omit the leg (defensive; shouldn't happen for\n * the rendered path — populated blocked => at least one blocker\n * exists by definition of the BLOCKED view — but the formatter is\n * defensive against an empty blocker-list slice). */\nexport function formatSubtitle(total: number, topBlocker: string | null): string {\n const parts: string[] = [String(total)];\n if (topBlocker !== null) parts.push(`top blocker: ${topBlocker}`);\n return parts.join(\" · \");\n}\n","// Commits card — lazygit-style recent project commit log.\n//\n// Slot choice: Card 0 is now Commits. Recent is restored to Card 8;\n// the DAG remains a keybind-only popup on `g` instead of consuming\n// numeric slot 0.\n//\n// Data comes from snapshot.recentCommits, populated by\n// loadWorkstreamSnapshot(..., { withRecentCommits }) against\n// process.cwd() (the project root where the TUI was launched), NOT any\n// per-agent worker workspace.\n\nimport type { ReactElement } from \"react\";\nimport type { WorkstreamSnapshot } from \"../../../state.js\";\nimport {\n type ColumnSpec,\n contentWidthFromCols,\n layoutColumns,\n renderRow,\n termColsForLayout,\n} from \"../columns.js\";\nimport { CARD_CONFIGS, cardRenderHeight } from \"../layout.js\";\nimport { ListRow } from \"../list-row.js\";\nimport { TitledBox } from \"../titled-box.js\";\nimport { CardPlaceholder } from \"./_placeholder.js\";\n\nexport interface CommitsCardProps {\n snapshot: WorkstreamSnapshot | null;\n rowBudget?: number;\n cols?: number;\n}\n\nexport const cardConfig = CARD_CONFIGS[0];\n\nconst COLUMN_SPECS: ReadonlyArray<ColumnSpec> = [\n { kind: \"protect\" }, // sha short\n { kind: \"protect\", align: \"right\" }, // relative time\n { kind: \"clip\", min: 1 }, // subject\n];\n\nexport function CommitsCard({ snapshot, rowBudget, cols }: CommitsCardProps): ReactElement {\n const contentWidth = contentWidthFromCols(cols ?? termColsForLayout());\n if (snapshot === null) {\n return CardPlaceholder({\n title: \"Commits\",\n cardId: 0,\n config: cardConfig,\n rowBudget,\n cols,\n text: \"loading…\",\n });\n }\n\n const { recentCommits } = snapshot;\n const backendLabel = formatBackend(snapshot.commitsBackend ?? null);\n if (recentCommits.length === 0) {\n return CardPlaceholder({\n title: \"Commits\",\n cardId: 0,\n config: cardConfig,\n rowBudget,\n cols,\n subtitle: backendLabel,\n text: \"no commits\",\n });\n }\n\n const shown = recentCommits.slice(0, rowBudget ?? cardConfig.maxRows);\n const more = recentCommits.length - shown.length;\n const bottomLabel = more > 0 ? `+${more} more · Shift+0` : undefined;\n const subtitle = formatSubtitle(\n recentCommits.length,\n snapshot.commitsBackend ?? null,\n recentCommits[0]?.relTime,\n );\n const rows = shown.map((c) => [shortSha(c.sha), c.relTime, c.subject]);\n const widths = layoutColumns(rows, COLUMN_SPECS, contentWidth);\n\n return (\n <TitledBox\n height={cardRenderHeight(cardConfig, rowBudget)}\n width={cols}\n title=\"Commits\"\n subtitle={subtitle}\n cardId={0}\n bottomLabel={bottomLabel}\n >\n {shown.map((c, i) => {\n const row = rows[i];\n if (row === undefined) return null;\n const padded = renderRow(row, widths, COLUMN_SPECS);\n const colors = [\n { color: \"yellow\" }, // sha\n { dimColor: true }, // relTime\n undefined, // subject\n ];\n return <ListRow key={c.sha} cells={padded} contentWidth={contentWidth} colors={colors} />;\n })}\n </TitledBox>\n );\n}\n\nexport function shortSha(sha: string): string {\n return sha.slice(0, 7);\n}\n\nexport function formatBackend(backend: WorkstreamSnapshot[\"commitsBackend\"]): string {\n return backend ?? \"(no vcs)\";\n}\n\nexport function formatSubtitle(\n total: number,\n backend: WorkstreamSnapshot[\"commitsBackend\"],\n newestRelTime: string | undefined,\n): string {\n const parts = [String(total), formatBackend(backend)];\n if (newestRelTime !== undefined && newestRelTime.length > 0) parts.push(newestRelTime);\n return parts.join(\" · \");\n}\n","// Doctor card — health-check summary surfaced on the dashboard so\n// the operator notices a broken state without remembering to run\n// `mu doctor`. Aimed at the \"btop / k9s health badge\" UX: when\n// every check is OK, the card is a quiet one-liner; when something\n// is warn or fail, the failing rows surface the moment they appear.\n//\n// Per feat_card_9_doctor (workstream `tui-impl`), promoted from the\n// LAST reserved non-zero slot in design_global_keymap. Slot 0 is now\n// Commits; DAG is keybind-only.\n//\n// CARD LAYOUT\n// glyph check STATUS detail\n// <warn> agents warn 2 ghost panes; run `mu agent reconcile`\n// <fail> workspaces fail 1 orphan dir blocking spawns\n//\n// Glyph + colour priority: GLYPH.fail (red), GLYPH.warn (yellow), then\n// GLYPH.ok (green). The card BODY filters to non-OK rows; when nothing\n// is wrong, the card renders one quiet all-healthy row so the operator's\n// eye learns to read the presence of rows as \"something needs attention.\"\n//\n// CLIPPING POLICY (per feat_column_aligned_lists)\n// glyph, check, STATUS → PROTECT (identifier; yankable check name)\n// detail → CLIP (free-form prose; can truncate)\n//\n// SUBTITLE\n// problemCount === 0 → \"all healthy\"\n// problemCount > 0 → \"<problemCount>\"\n//\n// DATA\n// - snapshot.doctor is populated by loadWorkstreamSnapshot when\n// called with `withDoctor: true`. The TUI's poll-loop hook\n// (src/cli/tui/state.ts) opts in. Static `mu state` and `mu\n// doctor` itself do not — `mu doctor`'s textual card is the\n// authoritative full diagnostic; this card is the dashboard\n// SIGNAL only. See src/doctor-summary.ts for the SDK seam.\n//\n// POPUP\n// Shift+9 (`(`) opens popups/doctor.tsx: every check (OK rows\n// included), `/` filter, and an Enter drill with the remediation\n// text for the focused check.\n\nimport { Text } from \"ink\";\nimport type { ReactElement } from \"react\";\nimport type { DoctorCheck } from \"../../../doctor-summary.js\";\nimport { GLYPH } from \"../../../glyphs.js\";\nimport type { WorkstreamSnapshot } from \"../../../state.js\";\nimport {\n type ColumnSpec,\n contentWidthFromCols,\n layoutColumns,\n renderRow,\n termColsForLayout,\n} from \"../columns.js\";\nimport { CARD_CONFIGS, cardRenderHeight } from \"../layout.js\";\nimport { ListRow } from \"../list-row.js\";\nimport { TitledBox } from \"../titled-box.js\";\nimport { CardPlaceholder } from \"./_placeholder.js\";\n\nexport interface DoctorCardProps {\n snapshot: WorkstreamSnapshot | null;\n rowBudget?: number;\n cols?: number;\n}\n\nexport const cardConfig = CARD_CONFIGS[9];\n\nconst COLUMN_SPECS: ReadonlyArray<ColumnSpec> = [\n { kind: \"protect\" }, // glyph\n { kind: \"protect\" }, // check name\n { kind: \"protect\" }, // status (ok / warn / fail)\n { kind: \"clip\", min: 1 }, // detail (free-form)\n];\n\nexport function DoctorCard({ snapshot, rowBudget, cols }: DoctorCardProps): ReactElement {\n const contentWidth = contentWidthFromCols(cols ?? termColsForLayout());\n if (snapshot === null || snapshot.doctor === null) {\n return CardPlaceholder({\n title: \"Doctor\",\n cardId: 9,\n config: cardConfig,\n rowBudget,\n cols,\n text: \"loading…\",\n });\n }\n\n const { checks, problemCount } = snapshot.doctor;\n const subtitle = formatSubtitle(problemCount);\n\n // Healthy path: render the quiet \"GLYPH.ok <K> checks\" line so the\n // operator can confirm the card ran (vs. simply being empty).\n if (problemCount === 0) {\n return CardPlaceholder({\n title: \"Doctor\",\n cardId: 9,\n config: cardConfig,\n rowBudget,\n cols,\n subtitle,\n children: (\n <Text dimColor>\n <Text color=\"green\">{GLYPH.ok}</Text> {checks.length} check\n {checks.length === 1 ? \"\" : \"s\"}\n </Text>\n ),\n });\n }\n\n const problems = checks.filter((c) => c.status !== \"ok\");\n const shown = problems.slice(0, rowBudget ?? cardConfig.maxRows);\n const more = problems.length - shown.length;\n const bottomLabel = more > 0 ? `+${more} more · Shift+9` : undefined;\n const rows = shown.map((c) => [glyphFor(c), c.name, c.status, c.detail]);\n const widths = layoutColumns(rows, COLUMN_SPECS, contentWidth);\n\n return (\n <TitledBox\n height={cardRenderHeight(cardConfig, rowBudget)}\n width={cols}\n title=\"Doctor\"\n subtitle={subtitle}\n cardId={9}\n bottomLabel={bottomLabel}\n >\n {shown.map((c, i) => {\n const row = rows[i];\n if (row === undefined) return null;\n const padded = renderRow(row, widths, COLUMN_SPECS);\n const statusColor = colorForStatus(c.status);\n const colors = [\n { color: statusColor }, // glyph\n { bold: true }, // name\n { color: statusColor }, // status\n { dimColor: true }, // detail\n ];\n return <ListRow key={c.name} cells={padded} contentWidth={contentWidth} colors={colors} />;\n })}\n </TitledBox>\n );\n}\n\n// ─── pure helpers (exported for unit tests) ────────────────────────\n\n/** Per-row glyph driven by the check's status, from src/glyphs.ts —\n * the same constants the Workspaces card and the agent status map\n * use, so one symbol means one thing everywhere. */\nexport function glyphFor(c: Pick<DoctorCheck, \"status\">): string {\n switch (c.status) {\n case \"fail\":\n return GLYPH.fail;\n case \"warn\":\n return GLYPH.warn;\n case \"ok\":\n return GLYPH.ok;\n }\n}\n\n/** Picocolors-compatible colour name for the status. fail → red,\n * warn → yellow, ok → green. Used both for the glyph and the\n * STATUS column so the row reads as a single visual unit. */\nexport function colorForStatus(s: DoctorCheck[\"status\"]): string {\n switch (s) {\n case \"fail\":\n return \"red\";\n case \"warn\":\n return \"yellow\";\n case \"ok\":\n return \"green\";\n }\n}\n\n/** Subtitle: \"all healthy\" when problemCount===0, else the number.\n * Kept terse so the title bar reads at a glance — when something is\n * wrong, \"Doctor · 2\" is the load-bearing signal; the row body\n * carries the names. */\nexport function formatSubtitle(problemCount: number): string {\n if (problemCount === 0) return \"all healthy\";\n return String(problemCount);\n}\n","// In-progress card — every IN_PROGRESS task in the workstream, with\n// owner + time-since-claim. Aimed at the cross-ref pain that today\n// forces the operator to read the Agents card AND the Ready card to\n// figure out \"what's actually running right now\":\n//\n// Agents card → who's busy, but not which task they're on\n// Ready card → unblocked OPEN tasks; nothing about IN_PROGRESS\n// Tracks card → DAG shape, not the live run state\n//\n// Card 6 collapses that into one glance. Per feat_card_6_inprogress\n// (workstream `tui-impl`), promoted from the slot reserved by\n// design_global_keymap. Mirrors the shape of Card 5 — Workspaces.\n//\n// CARD LAYOUT\n// glyph id owner since-claim title\n// ▶ design_x worker-1 3m Design X\n// ▶ review_x reviewer-1 12m Review X\n//\n// Glyph ▶ matches agent-display's busy status glyph used in the Agents\n// card — the operator already reads it as \"this thing is running\".\n// Consistency over novelty.\n//\n// CLIPPING POLICY (per feat_column_aligned_lists)\n// id, owner, since-claim → PROTECT (yankable; numbers / identifiers)\n// title → CLIP (free-form prose)\n//\n// SUBTITLE (mirrors Card 5)\n// empty → omitted (no IN_PROGRESS tasks → empty-state body)\n// populated → \"<N>\" or \"<N> · <K> stale\"\n// stale := time-since-claim ≥ 5min (matches mu's idle threshold\n// default; see skills/mu/recipes/orchestrator-loop.md)\n//\n// TIME-SINCE-CLAIM\n// The cheapest accurate-enough proxy is TaskRow.updatedAt — task\n// lifecycle flips (claim, status changes) update it. A true\n// `claim_at` column would require a schema add + agent_logs scan\n// per row; OUT OF SCOPE here per the task brief. If a future task\n// needs that, it should add it as a typed SDK field, not extend\n// this card to do per-row event-log reads.\n//\n// POPUP (Shift+6 / `^`) IS OUT OF SCOPE here.\n// The umbrella feat_more_cards_umbrella tracks it. When the popup\n// does land, it MUST follow:\n// (a) feat_popup_search_filter — '/' search via usePopupFilter\n// (b) feat_track_drill_chains_to_task_drill — Enter chains rows\n// into TaskDetailDrill (rows ARE tasks, so the drill leaf\n// is exactly that primitive).\n// Until then, Shift+6 stays a reserved noop in keys.ts.\n\nimport type { ReactElement } from \"react\";\nimport type { WorkstreamSnapshot } from \"../../../state.js\";\nimport { formatPair } from \"../../../tasks/status.js\";\nimport { inkColorForPair } from \"../../format.js\";\nimport { agentByName, agentStateGlyph, formatTaskOwnerDisplay } from \"../agent-display.js\";\nimport {\n type ColumnSpec,\n contentWidthFromCols,\n layoutColumns,\n renderRow,\n termColsForLayout,\n} from \"../columns.js\";\nimport { ageMs, formatSinceClaim } from \"../format-helpers.js\";\nimport { CARD_CONFIGS, cardRenderHeight } from \"../layout.js\";\nimport { ListRow } from \"../list-row.js\";\nimport { TitledBox } from \"../titled-box.js\";\nimport { CardPlaceholder } from \"./_placeholder.js\";\n\nexport interface InProgressCardProps {\n snapshot: WorkstreamSnapshot | null;\n rowBudget?: number;\n cols?: number;\n}\n\nexport const cardConfig = CARD_CONFIGS[6];\n\n/** Glyph for every IN_PROGRESS task. Mirrors the busy agent status glyph. */\nexport const GLYPH = agentStateGlyph(\"busy\");\n\n/** ≥5min since the last lifecycle flip → \"stale claim\". Matches the\n * default value of MU_IDLE_THRESHOLD_MS (300_000ms / 5min) used by\n * the agent-side idle detector — we deliberately re-use the same\n * threshold so a stale claim and an idle agent surface together. */\nexport const STALE_CLAIM_THRESHOLD_MS = 300_000;\n\nconst COLUMN_SPECS: ReadonlyArray<ColumnSpec> = [\n { kind: \"protect\" }, // glyph\n { kind: \"protect\" }, // task id\n { kind: \"protect\" }, // status\n { kind: \"protect\" }, // owner (or \"—\")\n { kind: \"protect\", align: \"right\" }, // since-claim\n { kind: \"clip\", min: 1 }, // title\n];\n\nexport function InProgressCard({ snapshot, rowBudget, cols }: InProgressCardProps): ReactElement {\n const contentWidth = contentWidthFromCols(cols ?? termColsForLayout());\n if (snapshot === null) {\n return CardPlaceholder({\n title: \"In-progress\",\n cardId: 6,\n config: cardConfig,\n rowBudget,\n cols,\n text: \"loading…\",\n });\n }\n\n const { inProgress } = snapshot;\n\n if (inProgress.length === 0) {\n return CardPlaceholder({\n title: \"In-progress\",\n cardId: 6,\n config: cardConfig,\n rowBudget,\n cols,\n text: \"(none in progress)\",\n });\n }\n\n const now = Date.now();\n const ages = inProgress.map((t) => ageMs(t, now));\n const stale = ages.filter((ms) => isStale(ms)).length;\n const subtitle = formatSubtitle(inProgress.length, stale);\n\n const shown = inProgress.slice(0, rowBudget ?? cardConfig.maxRows);\n const more = inProgress.length - shown.length;\n const bottomLabel = more > 0 ? `+${more} more · Shift+6` : undefined;\n const agentLookup = agentByName(snapshot);\n const rows = shown.map((t, i) => [\n GLYPH,\n t.name,\n formatPair(t),\n formatTaskOwnerDisplay(t, agentLookup),\n formatSinceClaim(ages[i] ?? null),\n t.title,\n ]);\n const widths = layoutColumns(rows, COLUMN_SPECS, contentWidth);\n\n return (\n <TitledBox\n height={cardRenderHeight(cardConfig, rowBudget)}\n width={cols}\n title=\"In-progress\"\n subtitle={subtitle}\n cardId={6}\n bottomLabel={bottomLabel}\n >\n {shown.map((t, i) => {\n const row = rows[i];\n if (row === undefined) return null;\n const padded = renderRow(row, widths, COLUMN_SPECS);\n const rowAge = ages[i];\n const stale = isStale(rowAge ?? null);\n const colors = [\n { color: \"yellow\" }, // glyph\n { bold: true }, // id\n { color: inkColorForPair(t) }, // status\n { dimColor: true }, // owner\n stale ? { color: \"yellow\" } : { dimColor: true }, // since\n { dimColor: true }, // title\n ];\n return <ListRow key={t.name} cells={padded} contentWidth={contentWidth} colors={colors} />;\n })}\n </TitledBox>\n );\n}\n\n// ─── pure helpers (exported for unit tests) ────────────────────────\n\n/** True when `ms` is at or above the stale-claim threshold (5min).\n * null / undefined → false (we never paint \"stale\" without data). */\nexport function isStale(ms: number | null | undefined): boolean {\n return typeof ms === \"number\" && ms >= STALE_CLAIM_THRESHOLD_MS;\n}\n\n/** Build the subtitle: total · N stale. Suppresses the stale leg\n * when zero so a healthy workstream renders a quiet \"3\" instead\n * of \"3 · 0 stale\". */\nexport function formatSubtitle(total: number, stale: number): string {\n const parts: string[] = [String(total)];\n if (stale > 0) parts.push(`${stale} stale`);\n return parts.join(\" · \");\n}\n","// Activity-log card — fixed-height tail of the most recent N events\n// from agent_logs. Auto-updates on every tick (no scroll-pause needed\n// at the card level; the popup handles full scroll-pause behaviour).\n//\n// Per design_card_log (workstream `tui`).\n//\n// Aesthetic: rounded border, dim border, section header inset; verb\n// verb coloured cyan; prose from the shared renderOp formatter.\n//\n// Rows are column-aligned via src/cli/tui/columns.ts. Per\n// feat_column_aligned_lists clipping policy: timestamp, source, verb\n// are PROTECTED (short, identity-bearing); the rest is CLIPPABLE.\n\nimport type { ReactElement } from \"react\";\nimport { renderOp } from \"../../../log-render.js\";\nimport type { WorkstreamSnapshot } from \"../../../state.js\";\nimport {\n type ColumnSpec,\n contentWidthFromCols,\n layoutColumns,\n renderRow,\n termColsForLayout,\n} from \"../columns.js\";\nimport { CARD_CONFIGS, cardRenderHeight } from \"../layout.js\";\nimport { ListRow } from \"../list-row.js\";\nimport { TitledBox } from \"../titled-box.js\";\nimport { CardPlaceholder } from \"./_placeholder.js\";\n\nexport interface LogCardProps {\n snapshot: WorkstreamSnapshot | null;\n rowBudget?: number;\n cols?: number;\n}\n\nexport const cardConfig = CARD_CONFIGS[4];\n\nconst COLUMN_SPECS: ReadonlyArray<ColumnSpec> = [\n { kind: \"protect\" }, // ts (HH:MM:SS)\n { kind: \"protect\" }, // source\n { kind: \"protect\" }, // verb (or '·' fallback)\n { kind: \"clip\", min: 1 }, // rest / payload\n];\n\nexport function LogCard({ snapshot, rowBudget, cols }: LogCardProps): ReactElement {\n const contentWidth = contentWidthFromCols(cols ?? termColsForLayout());\n if (snapshot === null) {\n return CardPlaceholder({\n title: \"Activity log\",\n cardId: 4,\n config: cardConfig,\n rowBudget,\n cols,\n text: \"loading…\",\n });\n }\n\n const { recent } = snapshot;\n\n if (recent.length === 0) {\n return CardPlaceholder({\n title: \"Activity log\",\n cardId: 4,\n config: cardConfig,\n rowBudget,\n cols,\n text: \"(no events yet)\",\n });\n }\n\n // Show the LAST N events (newest at the bottom). listLogs returns\n // them descending-by-seq via afterSeq cursor semantics; we slice\n // the head and reverse for \"newest at bottom\" reading.\n const tail = recent.slice(0, rowBudget ?? cardConfig.maxRows).reverse();\n\n // Prose comes from renderOp — the same formatter `mu log` uses. This\n // card owns column layout and colour, never phrasing (v2-log-verb).\n const cellRows = tail.map((row) => {\n const r = renderOp(row);\n const ts = row.createdAt.slice(11, 19);\n const verb = r?.verb ?? \"·\";\n const rest = r === null ? row.payload : [r.subject, r.detail].filter((x) => x !== \"\").join(\" \");\n return [ts, row.source, verb, rest];\n });\n const widths = layoutColumns(cellRows, COLUMN_SPECS, contentWidth);\n\n return (\n <TitledBox\n height={cardRenderHeight(cardConfig, rowBudget)}\n width={cols}\n title=\"Activity log\"\n subtitle={`last ↑${tail.length}`}\n cardId={4}\n >\n {tail.map((row, i) => {\n const cells = cellRows[i];\n if (cells === undefined) return null;\n const padded = renderRow(cells, widths, COLUMN_SPECS);\n const colors = [\n { dimColor: true }, // ts\n { dimColor: true }, // source\n row.intent === null ? { dimColor: true } : { color: \"cyan\" }, // verb\n undefined, // rest\n ];\n return <ListRow key={row.seq} cells={padded} contentWidth={contentWidth} colors={colors} />;\n })}\n </TitledBox>\n );\n}\n","// Ready card — top-N OPEN tasks with no unsatisfied blockers, sorted\n// by ROI desc.\n//\n// Per design_card_ready (workstream `tui`).\n//\n// Aesthetic: rounded border, dim border, section header inset; ROI\n// bucket colours via roiBucket() — high=green, mid=yellow, low=dim.\n//\n// Rows are column-aligned via src/cli/tui/columns.ts. Per\n// feat_column_aligned_lists clipping policy: task name, ROI number,\n// owner are PROTECTED (yank affordance / numeric); the title is\n// CLIPPABLE.\n\nimport { Text } from \"ink\";\nimport type { ReactElement } from \"react\";\nimport { roiBucket, type WorkstreamSnapshot } from \"../../../state.js\";\nimport { formatPair } from \"../../../tasks/status.js\";\nimport { inkColorForPair } from \"../../format.js\";\nimport { agentByName, formatTaskOwnerDisplay } from \"../agent-display.js\";\nimport {\n type ColumnSpec,\n contentWidthFromCols,\n layoutColumns,\n renderRow,\n termColsForLayout,\n} from \"../columns.js\";\nimport { colorForBucket, formatRoi } from \"../format-helpers.js\";\nimport { CARD_CONFIGS, cardRenderHeight } from \"../layout.js\";\nimport { ListRow } from \"../list-row.js\";\nimport { TitledBox } from \"../titled-box.js\";\nimport { CardPlaceholder } from \"./_placeholder.js\";\n\nexport interface ReadyCardProps {\n snapshot: WorkstreamSnapshot | null;\n rowBudget?: number;\n cols?: number;\n}\n\nexport const cardConfig = CARD_CONFIGS[3];\n\nconst COLUMN_SPECS: ReadonlyArray<ColumnSpec> = [\n { kind: \"protect\" }, // task name\n { kind: \"protect\" }, // status\n { kind: \"protect\", align: \"right\" }, // ROI label (e.g. \"ROI 50\")\n { kind: \"clip\", min: 1 }, // title\n { kind: \"protect\" }, // owner (or \"—\")\n];\n\nexport function ReadyCard({ snapshot, rowBudget, cols }: ReadyCardProps): ReactElement {\n const contentWidth = contentWidthFromCols(cols ?? termColsForLayout());\n if (snapshot === null) {\n return CardPlaceholder({\n title: \"Ready\",\n cardId: 3,\n config: cardConfig,\n rowBudget,\n cols,\n text: \"loading…\",\n });\n }\n\n const { ready } = snapshot;\n\n if (ready.length === 0) {\n return CardPlaceholder({\n title: \"Ready\",\n cardId: 3,\n config: cardConfig,\n rowBudget,\n cols,\n children: (\n // truncate-end: a wrapped second line would spill over the\n // card's top border and erase its title.\n <Text dimColor wrap=\"truncate-end\">\n {snapshot.parkedCount > 0\n ? `(no ready tasks) ${snapshot.parkedCount} parked · the rest are blocked or closed`\n : \"(no ready tasks) every blocker is OPEN/IN_PROGRESS or every task is closed\"}\n </Text>\n ),\n });\n }\n\n const shown = ready.slice(0, rowBudget ?? cardConfig.maxRows);\n const more = ready.length - shown.length;\n const bottomLabel = more > 0 ? `+${more} more · Shift+3` : undefined;\n const meta = shown.map((t) => {\n const bucket = roiBucket(t.impact, t.effortDays);\n const roiText = formatRoi(t.impact, t.effortDays);\n return { bucket, roiText };\n });\n const agentLookup = agentByName(snapshot);\n const rows = shown.map((t, i) => [\n t.name,\n formatPair(t),\n `ROI ${meta[i]?.roiText ?? \"\"}`,\n t.title,\n formatTaskOwnerDisplay(t, agentLookup),\n ]);\n const widths = layoutColumns(rows, COLUMN_SPECS, contentWidth);\n\n return (\n <TitledBox\n height={cardRenderHeight(cardConfig, rowBudget)}\n width={cols}\n title=\"Ready\"\n subtitle={String(ready.length)}\n cardId={3}\n bottomLabel={bottomLabel}\n >\n {shown.map((t, i) => {\n const row = rows[i];\n const m = meta[i];\n if (row === undefined || m === undefined) return null;\n const padded = renderRow(row, widths, COLUMN_SPECS);\n const colors = [\n { bold: true }, // name\n { color: inkColorForPair(t) }, // status\n { color: colorForBucket(m.bucket) }, // roi\n { dimColor: true }, // title\n { dimColor: true }, // owner\n ];\n return <ListRow key={t.name} cells={padded} contentWidth={contentWidth} colors={colors} />;\n })}\n </TitledBox>\n );\n}\n","// Recent card — CLOSED tasks in the workstream, most recently updated\n// first (updated_at, a proxy for close time; see \"WHEN\" below), so the\n// operator can cherry-pick / verify / cross-reference without bouncing to a\n// separate `mu task list --status CLOSED -w <ws>` shell.\n//\n// Per feat_card_8_recent (workstream `tui-impl`), promoted from the\n// slot reserved by design_global_keymap. Mirrors the shape of\n// Card 5 — Workspaces (264585f9), Card 6 — In-progress (760fc6c),\n// and Card 7 — Blocked (4c50fc0) so the operator reads it the same\n// way: TitledBox header, column-aligned rows, glanceable subtitle.\n//\n// CARD LAYOUT\n// glyph id STATUS when title\n// <ok> feat_card_5 CLOSED 3m ago FEAT: Card 5 — Workspaces\n// <ok> feat_card_6 CLOSED 12m ago FEAT: Card 6 — In-progress\n//\n// GLYPH.ok is coloured green — every row in this card is by definition\n// CLOSED (the SDK helper listRecentClosed filters on status='CLOSED');\n// the check-circle reads as \"shipped\".\n//\n// CLIPPING POLICY (per feat_column_aligned_lists)\n// id, STATUS, when → PROTECT (yankable / identifier / numeric)\n// title → CLIP (free-form prose)\n//\n// SUBTITLE\n// empty → omitted (no recently-closed tasks → empty body)\n// populated → \"<N>\" or \"<N> · last <relTime since newest row>\"\n// — the newest updated_at is usually the latest close\n// (a later note or edge on a CLOSED task also bumps it),\n// the anchor for \"did the wave just finish?\".\n//\n// DATA\n// - snapshot.recentClosed is the listRecentClosed slice (CLOSED\n// status, ORDER BY updated_at DESC LIMIT 5). Used directly. No\n// SDK extension per the task brief — if a future task wants a\n// larger window, it should bump the SDK helper's default and\n// have the card cap at ROW_LIMIT here.\n//\n// \"WHEN\" COLUMN\n// The cheapest proxy for \"closed at\" is TaskRow.updatedAt: closeTask\n// sets it, but it is not close time. A real `closed_at` column would\n// need a schema add + agent_logs scan; OUT OF SCOPE per the brief.\n// If a row is later updated (a note appended, an edge added or\n// removed), touchTask bumps updatedAt, so the row moves up and its\n// \"when\" reads as the time of that later write. Known limitation.\n//\n// POPUP\n// Shift+8 (`*`) opens the matching Recent popup. Card slot 8 and\n// popup slot 8 now point at the same task-recent view again.\n\nimport type { ReactElement } from \"react\";\nimport { GLYPH as SHARED_GLYPH } from \"../../../glyphs.js\";\nimport type { WorkstreamSnapshot } from \"../../../state.js\";\nimport { formatPair } from \"../../../tasks/status.js\";\nimport { inkColorForPair } from \"../../format.js\";\nimport {\n type ColumnSpec,\n contentWidthFromCols,\n layoutColumns,\n renderRow,\n termColsForLayout,\n} from \"../columns.js\";\nimport { ageMs, formatWhen } from \"../format-helpers.js\";\nimport { CARD_CONFIGS, cardRenderHeight } from \"../layout.js\";\nimport { ListRow } from \"../list-row.js\";\nimport { TitledBox } from \"../titled-box.js\";\nimport { CardPlaceholder } from \"./_placeholder.js\";\n\nexport interface RecentCardProps {\n snapshot: WorkstreamSnapshot | null;\n rowBudget?: number;\n cols?: number;\n}\n\nexport const cardConfig = CARD_CONFIGS[8];\n\n/** Glyph for every recently-closed row. Always the ok check. */\nexport const GLYPH = SHARED_GLYPH.ok;\n\nconst COLUMN_SPECS: ReadonlyArray<ColumnSpec> = [\n { kind: \"protect\" }, // glyph\n { kind: \"protect\" }, // task id\n { kind: \"protect\" }, // status (always CLOSED; constant for now)\n { kind: \"protect\", align: \"right\" }, // when (e.g. \"3m ago\")\n { kind: \"clip\", min: 1 }, // title\n];\n\nexport function RecentCard({ snapshot, rowBudget, cols }: RecentCardProps): ReactElement {\n const contentWidth = contentWidthFromCols(cols ?? termColsForLayout());\n if (snapshot === null) {\n return CardPlaceholder({\n title: \"Recent\",\n cardId: 8,\n config: cardConfig,\n rowBudget,\n cols,\n text: \"loading…\",\n });\n }\n\n const { recentClosed } = snapshot;\n\n if (recentClosed.length === 0) {\n return CardPlaceholder({\n title: \"Recent\",\n cardId: 8,\n config: cardConfig,\n rowBudget,\n cols,\n text: \"(none recently closed)\",\n });\n }\n\n const now = Date.now();\n const ages = recentClosed.map((t) => ageMs(t, now));\n const subtitle = formatSubtitle(recentClosed.length, ages[0] ?? null);\n\n const shown = recentClosed.slice(0, rowBudget ?? cardConfig.maxRows);\n const more = recentClosed.length - shown.length;\n const bottomLabel = more > 0 ? `+${more} more · Shift+8` : undefined;\n const rows = shown.map((t, i) => [\n GLYPH,\n t.name,\n formatPair(t),\n formatWhen(ages[i] ?? null),\n t.title,\n ]);\n const widths = layoutColumns(rows, COLUMN_SPECS, contentWidth);\n\n return (\n <TitledBox\n height={cardRenderHeight(cardConfig, rowBudget)}\n width={cols}\n title=\"Recent\"\n subtitle={subtitle}\n cardId={8}\n bottomLabel={bottomLabel}\n >\n {shown.map((t, i) => {\n const row = rows[i];\n if (row === undefined) return null;\n const padded = renderRow(row, widths, COLUMN_SPECS);\n const colors = [\n { color: \"green\" }, // glyph\n { bold: true }, // id\n { color: inkColorForPair(t) }, // status\n { dimColor: true }, // when\n { dimColor: true }, // title\n ];\n return <ListRow key={t.name} cells={padded} contentWidth={contentWidth} colors={colors} />;\n })}\n </TitledBox>\n );\n}\n\n// ─── pure helpers (exported for unit tests) ────────────────────────\n\n/** Build the subtitle: total · last <when>. Suppresses the \"last\"\n * leg when `mostRecentMs` is null (defensive — populated path\n * always has at least one row, hence at least one age). */\nexport function formatSubtitle(total: number, mostRecentMs: number | null): string {\n const parts: string[] = [String(total)];\n if (mostRecentMs !== null) parts.push(`last ${formatWhen(mostRecentMs)}`);\n return parts.join(\" · \");\n}\n","// Tracks card — parallel-track summary. One row per track: leading\n// goal name + counts (total tasks, ready) + diamond-merge marker if\n// applicable.\n//\n// Per design_card_tracks (workstream `tui`).\n//\n// Aesthetic: section header inset into the top border (TitledBox).\n//\n// Rows are column-aligned via src/cli/tui/columns.ts. Per\n// feat_column_aligned_lists clipping policy: track number, merge glyph,\n// task counts are PROTECTED (identity / numeric); the goal-name list\n// is CLIPPABLE.\n\nimport { Text } from \"ink\";\nimport type { ReactElement } from \"react\";\nimport { GLYPH } from \"../../../glyphs.js\";\nimport type { WorkstreamSnapshot } from \"../../../state.js\";\nimport {\n type ColumnSpec,\n contentWidthFromCols,\n layoutColumns,\n renderRow,\n termColsForLayout,\n} from \"../columns.js\";\nimport { CARD_CONFIGS, cardRenderHeight } from \"../layout.js\";\nimport { ListRow } from \"../list-row.js\";\nimport { TitledBox } from \"../titled-box.js\";\nimport { CardPlaceholder } from \"./_placeholder.js\";\n\nexport interface TracksCardProps {\n snapshot: WorkstreamSnapshot | null;\n rowBudget?: number;\n cols?: number;\n}\n\nexport const cardConfig = CARD_CONFIGS[2];\n\nconst COLUMN_SPECS: ReadonlyArray<ColumnSpec> = [\n { kind: \"protect\" }, // \"Track N\"\n { kind: \"protect\" }, // diamond glyph (or empty)\n { kind: \"clip\", min: 1 }, // goal names\n { kind: \"protect\" }, // counts \"(N tasks · M ready)\"\n];\n\nexport function TracksCard({ snapshot, rowBudget, cols }: TracksCardProps): ReactElement {\n const contentWidth = contentWidthFromCols(cols ?? termColsForLayout());\n if (snapshot === null) {\n return CardPlaceholder({\n title: \"Tracks\",\n cardId: 2,\n config: cardConfig,\n rowBudget,\n cols,\n text: \"loading…\",\n });\n }\n\n const { tracks } = snapshot;\n const totalReady = tracks.reduce((acc, t) => acc + t.readyCount, 0);\n\n if (tracks.length === 0) {\n return CardPlaceholder({\n title: \"Tracks\",\n cardId: 2,\n config: cardConfig,\n rowBudget,\n cols,\n children: (\n <Text dimColor>\n (no goals) try `mu task add -w {snapshot.workstreamName} --title \"...\"`\n </Text>\n ),\n });\n }\n\n const shown = tracks.slice(0, rowBudget ?? cardConfig.maxRows);\n const more = tracks.length - shown.length;\n const bottomLabel = more > 0 ? `+${more} more · Shift+2` : undefined;\n const rows = shown.map((t, i) => {\n const goalNames = t.roots\n .slice(0, 2)\n .map((r) => r.name)\n .join(\", \");\n const diamond = t.roots.length > 1 ? GLYPH.merge : \" \";\n const taskNoun = t.taskIds.size === 1 ? \"task\" : \"tasks\";\n const parked = t.parked ? \" (parked)\" : \"\";\n const counts = `(${t.taskIds.size} ${taskNoun} · ${t.readyCount} ready)${parked}`;\n return [`Track ${i + 1}`, diamond, goalNames, counts];\n });\n const widths = layoutColumns(rows, COLUMN_SPECS, contentWidth);\n\n return (\n <TitledBox\n height={cardRenderHeight(cardConfig, rowBudget)}\n width={cols}\n title=\"Tracks\"\n subtitle={`${tracks.length} · ${totalReady} ready`}\n cardId={2}\n bottomLabel={bottomLabel}\n >\n {shown.map((t, i) => {\n const row = rows[i];\n if (row === undefined) return null;\n const padded = renderRow(row, widths, COLUMN_SPECS);\n const trackKey = `${i}-${t.roots[0]?.name ?? \"unknown\"}`;\n const ready = t.readyCount;\n const colors = [\n { color: \"cyan\" }, // trackLabel\n undefined, // diamond\n undefined, // goals\n ready > 0 ? { color: \"green\" } : { dimColor: true }, // counts\n ];\n return (\n <ListRow key={trackKey} cells={padded} contentWidth={contentWidth} colors={colors} />\n );\n })}\n </TitledBox>\n );\n}\n","// Workspaces card — per-agent VCS working copy summary, aimed at the\n// \"between-wave refresh / cherry-pick\" loop where commits-behind +\n// dirty are the load-bearing signals.\n//\n// Per feat_card_5_workspaces (workstream `tui-impl`) and the umbrella\n// note on feat_more_cards_umbrella: \"high signal for cherry-pick /\n// refresh-between-waves loops; only place that exposes commits-behind\n// + dirty\". Cards 1-4 cover agents/tracks/ready/log; this fills slot\n// 5 (Unicode superscript ⁵, btop convention via TitledBox).\n//\n// Aesthetic: rounded border, dim border colour, section header inset\n// into the top — same family as the other four cards.\n//\n// Data shape (per row):\n// - status glyph GLYPH.dirty | GLYPH.stale | GLYPH.ok\n// - agent name e.g. worker-1\n// - backend git | jj | sl | none\n// - behind coloured int (green ≤2, yellow 3-9, red ≥10)\n// - parent_ref first 12 chars (matches mu workspace list)\n//\n// Rows are column-aligned via src/cli/tui/columns.ts. Per\n// feat_column_aligned_lists clipping policy: glyph + agent name +\n// backend + behind + parent_ref are all PROTECTED (operators yank\n// them verbatim into shell commands). Nothing here is free-form prose\n// so we have no clippable column — this is a deliberate exception:\n// every cell is identity-bearing. If row-width overflows, the\n// dashboard's terminal-too-small guard already handles it.\n//\n// FOLLOW-UP (not in scope):\n// - Matching Shift+5 (`%`) popup with per-row yank intents\n// (refresh / commits / free / path). Tracked by the parent\n// feat_more_cards_umbrella; popup likely lands as a sibling task.\n\nimport { Text } from \"ink\";\nimport type { ReactElement } from \"react\";\nimport { GLYPH } from \"../../../glyphs.js\";\nimport type { WorkstreamSnapshot } from \"../../../state.js\";\nimport {\n isWorkspaceStale,\n WORKSPACE_STALE_THRESHOLD,\n type WorkspaceRow,\n} from \"../../../workspace.js\";\nimport { agentByName, formatAgentRefDisplayName } from \"../agent-display.js\";\nimport {\n type ColumnSpec,\n contentWidthFromCols,\n layoutColumns,\n renderRow,\n termColsForLayout,\n} from \"../columns.js\";\nimport { CARD_CONFIGS, cardRenderHeight } from \"../layout.js\";\nimport { ListRow } from \"../list-row.js\";\nimport { TitledBox } from \"../titled-box.js\";\nimport { CardPlaceholder } from \"./_placeholder.js\";\n\nexport interface WorkspacesCardProps {\n snapshot: WorkstreamSnapshot | null;\n rowBudget?: number;\n cols?: number;\n}\n\nexport const cardConfig = CARD_CONFIGS[5];\n\nconst COLUMN_SPECS: ReadonlyArray<ColumnSpec> = [\n { kind: \"protect\" }, // status glyph\n { kind: \"protect\" }, // agent name\n { kind: \"protect\" }, // backend\n { kind: \"protect\", align: \"right\" }, // behind count\n { kind: \"protect\" }, // parent_ref short\n];\n\nexport function WorkspacesCard({ snapshot, rowBudget, cols }: WorkspacesCardProps): ReactElement {\n const contentWidth = contentWidthFromCols(cols ?? termColsForLayout());\n if (snapshot === null) {\n return CardPlaceholder({\n title: \"Workspaces\",\n cardId: 5,\n config: cardConfig,\n rowBudget,\n cols,\n text: \"loading…\",\n });\n }\n\n const { workspaces, workstreamName } = snapshot;\n const stale = workspaces.filter((w) => isStale(w.commitsBehindMain)).length;\n const dirty = workspaces.filter((w) => w.dirty === true).length;\n const subtitle = formatSubtitle(workspaces.length, stale, dirty);\n\n if (workspaces.length === 0) {\n return CardPlaceholder({\n title: \"Workspaces\",\n cardId: 5,\n config: cardConfig,\n rowBudget,\n cols,\n children: (\n <Text dimColor>\n (no workspaces) try `mu agent spawn worker-1 -w {workstreamName} --workspace`\n </Text>\n ),\n });\n }\n\n const shown = workspaces.slice(0, rowBudget ?? cardConfig.maxRows);\n const more = workspaces.length - shown.length;\n const bottomLabel = more > 0 ? `+${more} more · Shift+5` : undefined;\n const agentLookup = agentByName(snapshot);\n const rows = shown.map((w) => [\n glyphFor(w),\n formatAgentRefDisplayName(w.agentName, agentLookup),\n w.backend,\n formatBehind(w.commitsBehindMain),\n w.parentRef ? w.parentRef.slice(0, 12) : \"—\",\n ]);\n const widths = layoutColumns(rows, COLUMN_SPECS, contentWidth);\n\n return (\n <TitledBox\n height={cardRenderHeight(cardConfig, rowBudget)}\n width={cols}\n title=\"Workspaces\"\n subtitle={subtitle}\n cardId={5}\n bottomLabel={bottomLabel}\n >\n {shown.map((w, i) => {\n const row = rows[i];\n if (row === undefined) return null;\n const padded = renderRow(row, widths, COLUMN_SPECS);\n const colors = [\n { color: colorForGlyph(w) }, // glyph\n { bold: true }, // name\n { dimColor: true }, // backend\n { color: colorForBehind(w.commitsBehindMain) }, // behind\n { dimColor: true }, // parent\n ];\n return (\n <ListRow key={w.agentName} cells={padded} contentWidth={contentWidth} colors={colors} />\n );\n })}\n </TitledBox>\n );\n}\n\n// ─── pure helpers (exported for unit tests) ────────────────────────\n\n/** True when the row's commits-behind-main is ≥10 (the red bucket\n * used by the static `mu workspace list` table). Kept in sync with\n * formatBehind's thresholds below. */\nexport function isStale(behind: number | null | undefined): boolean {\n return isWorkspaceStale(behind);\n}\n\n/** Render the behind count as a short token. \"—\" when unknown\n * (no main resolvable, none-backend, missing parent_ref, command\n * failure). Numbers render bare; the call-site colours them. */\nexport function formatBehind(n: number | null | undefined): string {\n if (n === undefined || n === null) return \"—\";\n return String(n);\n}\n\n/** Picocolors-compatible colour name for a behind count. Mirrors the\n * static table renderer (src/cli/format.ts formatBehind): green ≤2,\n * yellow 3-9, red ≥10, undefined / unknown falls through to dim. */\nexport function colorForBehind(n: number | null | undefined): string | undefined {\n if (n === undefined || n === null) return undefined;\n if (n <= 2) return \"green\";\n if (n < WORKSPACE_STALE_THRESHOLD) return \"yellow\";\n return \"red\";\n}\n\n/** Per-row status glyph (from src/glyphs.ts). Priority order:\n * 1. dirty → GLYPH.dirty (uncommitted edits — most actionable)\n * 2. stale → GLYPH.stale (commits-behind ≥10 — needs `mu workspace refresh`)\n * 3. clean → GLYPH.ok\n * When dirty is unknown (null / undefined) we fall through to the\n * staleness check; we never paint a row as clean when its dirty\n * state is unknown.\n */\nexport function glyphFor(w: WorkspaceRow): string {\n if (w.dirty === true) return GLYPH.dirty;\n if (isStale(w.commitsBehindMain)) return GLYPH.stale;\n return GLYPH.ok;\n}\n\n/** Glyph colour: red when dirty (most urgent), yellow when stale,\n * green when clean. Undefined → use ink default (matches the\n * default-colour fallthroughs elsewhere). */\nexport function colorForGlyph(w: WorkspaceRow): string | undefined {\n if (w.dirty === true) return \"red\";\n if (isStale(w.commitsBehindMain)) return \"yellow\";\n return \"green\";\n}\n\n/** Build the subtitle: total · N stale · M dirty. Suppresses zeros\n * so a healthy workstream renders a quiet \"3\" instead of\n * \"3 · 0 stale · 0 dirty\". */\nexport function formatSubtitle(total: number, stale: number, dirty: number): string {\n const parts: string[] = [String(total)];\n if (stale > 0) parts.push(`${stale} stale`);\n if (dirty > 0) parts.push(`${dirty} dirty`);\n return parts.join(\" · \");\n}\n","// Help overlay (?). Renders the TUI keymap superset from the shared\n// keymap spec. Status-bar hint clusters are intentionally smaller:\n// they show only the keys that should be always visible in the current\n// mode. The help overlay is the exhaustive reference.\n\nimport { Box, Text, useInput } from \"ink\";\nimport { type ReactElement, useMemo, useState } from \"react\";\nimport { HELP_PANES } from \"./keymap-spec.js\";\nimport { dispatchPopupKeyFromInk, type PopupAction } from \"./keys.js\";\nimport { applyScroll, clampScrollTop, isNavAction } from \"./popups/scroll.js\";\nimport { TitledBox } from \"./titled-box.js\";\nimport { useTerminalSize } from \"./use-terminal-size.js\";\n\nexport type HelpRenderRow =\n | { kind: \"header\"; text: string }\n | { kind: \"row\"; keys: string; effect: string }\n | { kind: \"separator\" };\n\nexport const HELP_CHROME_ROWS = 3;\n\nexport function flattenHelpRows(): HelpRenderRow[] {\n return HELP_PANES.flatMap((pane, paneIdx) => {\n const rows: HelpRenderRow[] = [\n ...(paneIdx > 0 ? ([{ kind: \"separator\" }] as HelpRenderRow[]) : []),\n { kind: \"header\", text: pane.title },\n ...pane.rows.map(\n (row): HelpRenderRow => ({\n kind: \"row\",\n keys: row.keys,\n effect: row.effect,\n }),\n ),\n ];\n return rows;\n });\n}\n\nexport function helpViewport(rows: number): number {\n return Math.max(1, rows - HELP_CHROME_ROWS);\n}\n\nexport function helpPositionLabel(\n scrollTop: number,\n viewport: number,\n totalRows: number,\n): string | undefined {\n if (totalRows <= viewport) return undefined;\n const start = Math.min(totalRows, scrollTop + 1);\n const end = Math.min(totalRows, scrollTop + viewport);\n return `${start}-${end}/${totalRows}`;\n}\n\nexport function applyHelpScroll(\n scrollTop: number,\n action: PopupAction,\n rows: number,\n totalRows: number,\n): number {\n if (!isNavAction(action)) return scrollTop;\n return applyScroll(scrollTop, action, totalRows, helpViewport(rows));\n}\n\nexport interface HelpProps {\n rows: number;\n}\n\nexport function Help({ rows }: HelpProps): ReactElement {\n const { cols } = useTerminalSize();\n const flatRows = useMemo(() => flattenHelpRows(), []);\n const [scrollTop, setScrollTop] = useState(0);\n const totalRows = flatRows.length;\n\n useInput((input, key) => {\n const action = dispatchPopupKeyFromInk(input, key);\n setScrollTop((s) => applyHelpScroll(s, action, rows, totalRows));\n });\n\n return <HelpView rows={rows} scrollTop={scrollTop} flatRows={flatRows} cols={cols} />;\n}\n\nexport interface HelpViewProps {\n rows: number;\n scrollTop?: number;\n flatRows?: readonly HelpRenderRow[];\n /** Terminal columns. When omitted, falls back to process.stdout. */\n cols?: number;\n}\n\nexport function HelpView({\n rows,\n scrollTop = 0,\n flatRows = flattenHelpRows(),\n cols: colsOverride,\n}: HelpViewProps): ReactElement {\n const cols = colsOverride ?? process.stdout.columns ?? 80;\n const contentWidth = Math.max(1, cols - 4); // border + paddingX on both sides\n const viewport = helpViewport(rows);\n const totalRows = flatRows.length;\n const clampedScrollTop = clampScrollTop(scrollTop, totalRows, viewport);\n const visibleRows = flatRows.slice(clampedScrollTop, clampedScrollTop + viewport);\n const positionLabel = helpPositionLabel(clampedScrollTop, viewport, totalRows);\n const title = positionLabel === undefined ? \"keys\" : `keys · ${positionLabel}`;\n\n return (\n <TitledBox title={title} borderColor=\"cyan\" titleColor=\"cyan\" width={cols}>\n <Box flexDirection=\"column\" width={contentWidth}>\n {visibleRows.map((row, idx) => renderHelpLine(row, contentWidth, clampedScrollTop + idx))}\n </Box>\n </TitledBox>\n );\n}\n\nfunction renderHelpLine(row: HelpRenderRow, contentWidth: number, index: number): ReactElement {\n switch (row.kind) {\n case \"separator\":\n return <Text key={index}> </Text>;\n case \"header\":\n return (\n <Box key={index} width={contentWidth}>\n <Text bold color=\"cyan\">\n {row.text}\n </Text>\n </Box>\n );\n case \"row\":\n return (\n <HelpRow key={index} keys={row.keys} effect={row.effect} contentWidth={contentWidth} />\n );\n }\n}\n\nfunction HelpRow({\n keys,\n effect,\n contentWidth,\n}: {\n keys: string;\n effect: string;\n contentWidth: number;\n}): ReactElement {\n return (\n <Box width={contentWidth}>\n <Box width={18}>\n <Text color=\"yellow\" wrap=\"truncate\">\n {keys}\n </Text>\n </Box>\n <Box width={Math.max(1, contentWidth - 18)}>\n <Text dimColor wrap=\"truncate\">\n {effect}\n </Text>\n </Box>\n </Box>\n );\n}\n","// Canonical TUI keymap specification for the status-bar hint\n// clusters and the `?` help overlay.\n//\n// Contract: status-bar hints are the per-mode ALWAYS-SHOWN subset\n// (keys with no better mnemonic elsewhere, and only keys that work in\n// that mode). The help overlay is the SUPERSET: every key shown in a\n// status-bar cluster must appear here too. Keep new key hints in this\n// pure data file so src/cli/tui/status-bar.tsx and help.tsx cannot\n// drift independently.\n\ntype KeyId = string;\n\nexport interface StatusHintEntry {\n kind: \"hint\" | \"label\" | \"text\";\n /** Key glyph/range rendered in yellow for kind=\"hint\". */\n key?: string;\n /** Effect label (kind=\"hint\") or literal text (label/text). */\n label: string;\n keyIds: readonly KeyId[];\n color?: \"cyan\" | \"magenta\" | \"yellow\";\n}\n\nexport interface StatusHintContext {\n mode: \"dashboard\" | \"popup-list\" | \"popup-drill\" | \"popup-filter\" | \"dag\" | \"all-tasks\";\n /** Dashboard-only: Tab hint appears only when N≥2 workstreams. */\n hasWorkstreamTabs?: boolean;\n}\n\nexport interface HelpRowSpec {\n keys: string;\n effect: string;\n keyIds: readonly KeyId[];\n}\n\nexport interface HelpPaneSpec {\n title: string;\n rows: readonly HelpRowSpec[];\n}\n\nconst DASHBOARD_BASE_HINTS: readonly StatusHintEntry[] = [\n hint(\"0-9\", \"cards\", [\"0-9\"]),\n hint(\"Shift 0-9\", \"popups\", [\"Shift 0-9\"]),\n hint(\"g\", \"DAG\", [\"g\"]),\n hint(\"t\", \"tasks\", [\"t\"]),\n];\n\nconst DASHBOARD_TRAILING_HINTS: readonly StatusHintEntry[] = [\n hint(\"?\", \"help\", [\"?\"]),\n hint(\"q\", \"quit\", [\"q\"]),\n];\n\nconst POPUP_LIST_HINTS: readonly StatusHintEntry[] = [\n hint(\"j/k\", \"nav\", [\"j\", \"k\"]),\n hint(\"/\", \"filter\", [\"/\"]),\n hint(\"Enter\", \"drill\", [\"Enter\"]),\n hint(\"y\", \"yank\", [\"y\"]),\n hint(\"?\", \"help\", [\"?\"]),\n hint(\"Esc\", \"back\", [\"Esc\"]),\n];\n\n// `t tuicr` and `l lazygit` are intentionally NOT in the global\n// drill / list status-bar clusters below. Both are per-popup verbs\n// scoped to specific surfaces:\n// - `t tuicr` fires only in git-show drills (Commits popup +\n// Workspaces popup commits drill).\n// - `l lazygit` fires only in the Commits popup list mode\n// (lazygit operates on a cwd, not a single revision, so the\n// natural surface is the list-level repo browse, not a drill).\n// Each consumer inserts the per-popup hint into its `hint` prop\n// — which TitledBox renders inset into the bottom border. Putting\n// either in a global cluster would advertise it everywhere it does\n// nothing (TaskDetailDrill notes, agent scrollback, every other\n// popup, etc).\nconst POPUP_DRILL_HINTS: readonly StatusHintEntry[] = [\n label(\"drill\", \"magenta\"),\n hint(\"j/k\", \"scroll\", [\"j\", \"k\"]),\n hint(\"Ctrl-D/U\", \"page\", [\"Ctrl-D\", \"Ctrl-U\"]),\n hint(\"y\", \"yank\", [\"y\"]),\n hint(\"?\", \"help\", [\"?\"]),\n hint(\"Esc\", \"back\", [\"Esc\"]),\n];\n\nconst POPUP_FILTER_HINTS: readonly StatusHintEntry[] = [\n label(\"filter\", \"yellow\"),\n text(\"type to match\"),\n hint(\"Enter\", \"commit\", [\"Enter\"]),\n hint(\"Esc\", \"cancel\", [\"Esc\"]),\n];\n\nconst DAG_HINTS: readonly StatusHintEntry[] = [\n label(\"drill\", \"magenta\"),\n hint(\"j/k\", \"scroll\", [\"j\", \"k\"]),\n hint(\"o/i/c/p/w\", \"filter\", [\"o\", \"i\", \"c\", \"p\", \"w\"]),\n hint(\"y\", \"yank\", [\"y\"]),\n hint(\"?\", \"help\", [\"?\"]),\n hint(\"Esc\", \"back\", [\"Esc\"]),\n];\n\nconst ALL_TASKS_HINTS: readonly StatusHintEntry[] = [\n label(\"drill\", \"magenta\"),\n hint(\"j/k\", \"nav\", [\"j\", \"k\"]),\n hint(\"o/i/c/p/w\", \"filter\", [\"o\", \"i\", \"c\", \"p\", \"w\"]),\n hint(\"s\", \"sort\", [\"s\"]),\n hint(\"/\", \"search\", [\"/\"]),\n hint(\"Enter\", \"drill\", [\"Enter\"]),\n hint(\"y\", \"yank\", [\"y\"]),\n hint(\"Esc\", \"back\", [\"Esc\"]),\n];\n\nexport function statusHintEntries(context: StatusHintContext): readonly StatusHintEntry[] {\n switch (context.mode) {\n case \"dashboard\":\n return [\n ...DASHBOARD_BASE_HINTS,\n ...(context.hasWorkstreamTabs ? [hint(\"Tab\", \"ws\", [\"Tab\"])] : []),\n ...DASHBOARD_TRAILING_HINTS,\n ];\n case \"popup-list\":\n return POPUP_LIST_HINTS;\n case \"popup-drill\":\n return POPUP_DRILL_HINTS;\n case \"popup-filter\":\n return POPUP_FILTER_HINTS;\n case \"dag\":\n return DAG_HINTS;\n case \"all-tasks\":\n return ALL_TASKS_HINTS;\n }\n}\n\nexport const HELP_PANES: readonly HelpPaneSpec[] = [\n {\n title: \"keys · dashboard\",\n rows: [\n row(\n \"0-9\",\n \"toggle Commits/Agents/Tracks/Ready/Log/Workspaces/In-progress/Blocked/Recent/Doctor cards\",\n [\"0-9\"],\n ),\n row(\"Shift 0-9\", \"open numbered popups (Shift+0 = Commits; Shift+8 = Recent)\", [\"Shift 0-9\"]),\n row(\"g\", \"DAG popup\", [\"g\"]),\n row(\"t\", \"all-tasks popup\", [\"t\"]),\n row(\"Tab / Shift-Tab\", \"next / previous workstream tab (multi-ws)\", [\"Tab\", \"Shift-Tab\"]),\n row(\"c\", \"clear footer (last yank)\", [\"c\"]),\n row(\"0\", \"Commits card (tick reset is not bound; slot 0 is a card)\", [\"0\"]),\n row(\"+/=\", \"tick faster (floor 100ms)\", [\"+\", \"=\"]),\n row(\"-\", \"tick slower (ceiling 10s)\", [\"-\"]),\n row(\"r/F5\", \"refresh now\", [\"r\", \"F5\"]),\n row(\"?\", \"toggle this overlay\", [\"?\"]),\n row(\"q/Q\", \"quit (Ctrl-C also)\", [\"q\", \"Q\", \"Ctrl-C\"]),\n ],\n },\n {\n title: \"keys · popup list\",\n rows: [\n row(\"j/k or ↑/↓\", \"move selection\", [\"j\", \"k\", \"ArrowUp\", \"ArrowDown\"]),\n row(\"g/G\", \"first / last row\", [\"g\", \"G\"]),\n row(\"Ctrl-D/U\", \"half-page down / up\", [\"Ctrl-D\", \"Ctrl-U\"]),\n row(\"PgDn/PgUp\", \"full-page down / up\", [\"PgDn\", \"PgUp\"]),\n row(\"/\", \"filter/search rows\", [\"/\"]),\n row(\"Enter\", \"drill into focused row\", [\"Enter\"]),\n row(\"y\", \"yank action for focused row\", [\"y\"]),\n row(\"a\", \"attach to focused agent's tmux pane (Agents popup only; user-driven TUI escape)\", [\n \"a\",\n ]),\n row(\"l\", \"launch lazygit in the project root (Commits popup only; user-driven TUI escape)\", [\n \"l\",\n ]),\n row(\"Esc/q\", \"back to dashboard\", [\"Esc\", \"q\"]),\n row(\"?\", \"toggle this overlay\", [\"?\"]),\n ],\n },\n {\n title: \"keys · popup drill\",\n rows: [\n row(\"j/k or ↑/↓\", \"scroll one line\", [\"j\", \"k\", \"ArrowUp\", \"ArrowDown\"]),\n row(\"Ctrl-D/U\", \"half-page down / up\", [\"Ctrl-D\", \"Ctrl-U\"]),\n row(\"PgDn/PgUp\", \"full-page down / up\", [\"PgDn\", \"PgUp\"]),\n row(\"g/G\", \"top / bottom\", [\"g\", \"G\"]),\n row(\"/\", \"filter/search when the drill is a list\", [\"/\"]),\n row(\"y\", \"yank drill-specific command\", [\"y\"]),\n row(\"t\", \"launch tuicr for the focused git-show revision (user-driven TUI escape)\", [\"t\"]),\n row(\"Esc/q\", \"back one drill level\", [\"Esc\", \"q\"]),\n row(\"?\", \"toggle this overlay\", [\"?\"]),\n ],\n },\n {\n title: \"keys · popup filter\",\n rows: [\n row(\"type\", \"append printable characters to the filter\", [\"type\"]),\n row(\"Backspace\", \"edit query\", [\"Bksp\"]),\n row(\"Enter\", \"commit filter\", [\"Enter\"]),\n row(\"Esc\", \"cancel filter\", [\"Esc\"]),\n ],\n },\n {\n title: \"keys · DAG / all-tasks\",\n rows: [\n row(\n \"o/i/c/p/w\",\n \"toggle OPEN / IN_PROGRESS / CLOSED status filters; p parked; w won't do (closed, not done)\",\n [\"o\", \"i\", \"c\", \"p\", \"w\"],\n ),\n row(\"b\", \"all-tasks blocked filter cycle (all → only → hide)\", [\"b\"]),\n row(\"s\", \"all-tasks sort cycle (roi → recency → age → id)\", [\"s\"]),\n row(\"/\", \"all-tasks row search\", [\"/\"]),\n ],\n },\n {\n title: \"mouse\",\n rows: [\n row(\"double-click card\", \"drill into popup\", [\"mouse:doubleclick-card\"]),\n row(\"double-click row\", \"drill into row detail\", [\"mouse:doubleclick-row\"]),\n row(\"scroll wheel\", \"scroll list / drill body\", [\"mouse:scroll\"]),\n row(\"back\", \"no mouse back; use Esc/q\", [\"mouse:no-back\"]),\n ],\n },\n];\n\nexport function statusHintKeyIds(context: StatusHintContext): Set<KeyId> {\n return new Set(statusHintEntries(context).flatMap((entry) => entry.keyIds));\n}\n\nexport function helpOverlayKeyIds(): Set<KeyId> {\n return new Set(HELP_PANES.flatMap((pane) => pane.rows.flatMap((row) => row.keyIds)));\n}\n\nfunction hint(key: string, labelText: string, keyIds: readonly KeyId[]): StatusHintEntry {\n return { kind: \"hint\", key, label: labelText, keyIds };\n}\n\nfunction label(textValue: string, color: \"cyan\" | \"magenta\" | \"yellow\"): StatusHintEntry {\n return { kind: \"label\", label: textValue, keyIds: [], color };\n}\n\nfunction text(textValue: string): StatusHintEntry {\n return { kind: \"text\", label: textValue, keyIds: [] };\n}\n\nfunction row(keys: string, effect: string, keyIds: readonly KeyId[]): HelpRowSpec {\n return { keys, effect, keyIds };\n}\n","// Global keymap dispatcher for the TUI dashboard. Per\n// design_global_keymap (workstream `tui`):\n//\n// 0 toggle Commits card\n// 1-4 toggle Agents/Tracks/Ready/Log card\n// 5 toggle Workspaces card (feat_card_5_workspaces)\n// 6 toggle In-progress card (feat_card_6_inprogress)\n// 7 toggle Blocked card (feat_card_7_blocked)\n// 8 toggle Recent card\n// 9 toggle Doctor card (feat_card_9_doctor)\n// g open full DAG popup (graph mnemonic; keybind-only)\n// t open all-tasks popup (task-list mnemonic; keybind-only)\n// Shift+0/) open Commits popup\n// ! @ # $ open fullscreen popup for that card (Shift+1..Shift+4\n// on US keyboards; bound by glyph because ink reports\n// the post-shift character, not the modifier).\n// Shift+8/* open Recent popup\n// + / = tick faster (floor 100ms); = is the unshifted alias\n// - tick slower (ceiling 10s)\n// r / F5 refresh now (poke poll loop)\n// ? toggle help overlay\n// q / Q quit\n// Ctrl-C quit (handled by ink's exitOnCtrlC)\n// c clear footer (most-recent-yank line)\n// Tab next workstream tab (multi-ws TUI; noop when N=1)\n// Shift-Tab previous workstream tab\n//\n// This module is pure TS: takes a keystroke (input + key flags from\n// ink's useInput) and returns a structured GlobalAction. The caller\n// (the <App> component in app.tsx) maps actions to state mutations.\n\nexport type GlobalAction =\n | { kind: \"toggleCard\"; cardId: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 }\n | {\n kind: \"openPopup\";\n cardId: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | \"dag\" | \"allTasks\";\n }\n | { kind: \"tickFaster\" }\n | { kind: \"tickSlower\" }\n | { kind: \"refreshNow\" }\n | { kind: \"toggleHelp\" }\n | { kind: \"quit\" }\n | { kind: \"clearFooter\" }\n | { kind: \"nextTab\" }\n | { kind: \"prevTab\" }\n | { kind: \"noop\" };\n\n/**\n * Subset of ink's `Key` shape we care about. Defining locally so the\n * keys module stays decoupled from ink's render-time Key type.\n */\nexport interface KeyFlags {\n ctrl?: boolean;\n shift?: boolean;\n meta?: boolean;\n escape?: boolean;\n return?: boolean;\n upArrow?: boolean;\n downArrow?: boolean;\n leftArrow?: boolean;\n rightArrow?: boolean;\n tab?: boolean;\n pageUp?: boolean;\n pageDown?: boolean;\n f5?: boolean;\n}\n\n/**\n * Structural subset of ink's `Key` object as delivered to useInput.\n * Kept local (instead of importing ink's type) so keys.ts remains a\n * pure keymap module with no render-time dependency.\n */\nexport type InkKeyLike = KeyFlags;\n\nfunction keyFlagsFromInk(key: InkKeyLike): KeyFlags {\n return {\n ctrl: key.ctrl,\n shift: key.shift,\n meta: key.meta,\n escape: key.escape,\n return: key.return,\n upArrow: key.upArrow,\n downArrow: key.downArrow,\n leftArrow: key.leftArrow,\n rightArrow: key.rightArrow,\n tab: key.tab,\n pageUp: key.pageUp,\n pageDown: key.pageDown,\n f5: key.f5,\n };\n}\n\nexport function dispatchGlobalKeyFromInk(input: string, key: InkKeyLike): GlobalAction {\n return dispatchGlobalKey(input, keyFlagsFromInk(key));\n}\n\n/**\n * Map a single keystroke (delivered by ink's useInput) to the global\n * dashboard action it represents. Returns `{kind:\"noop\"}` for any\n * unrecognised input — the caller can treat noop as \"do nothing\".\n *\n * Pure function: no side effects, no React, no ink imports. Trivially\n * unit-testable.\n */\nexport function dispatchGlobalKey(input: string, key: KeyFlags): GlobalAction {\n // Quit takes precedence over everything (including help overlay\n // suppression handled by the caller).\n if (key.ctrl && input === \"c\") return { kind: \"quit\" };\n if (input === \"q\" || input === \"Q\") return { kind: \"quit\" };\n\n // Help overlay\n if (input === \"?\") return { kind: \"toggleHelp\" };\n\n // Refresh-now poke\n if (input === \"r\" || key.f5) return { kind: \"refreshNow\" };\n\n // Footer clear (last-yank line)\n if (input === \"c\") return { kind: \"clearFooter\" };\n\n // Multi-workstream tab navigation. Tab cycles forward;\n // Shift-Tab cycles backward. Per feat_tui_multi_workstream\n // (workstream `tui-impl`): the dispatcher returns the action\n // unconditionally; the App suppresses it (via the popup-open\n // guard) when a popup is mounted, and degenerates to a noop\n // when only one workstream is loaded.\n if (key.tab === true) {\n return { kind: key.shift === true ? \"prevTab\" : \"nextTab\" };\n }\n\n // Tick rate adjust. `+` arrives as `+` (Shift+= on US); `=` is the\n // unshifted alias for users who don't bother shifting; `-` is the\n // plain minus key. Digit 0 is now a card slot (Commits), so tick\n // reset is intentionally not bound to a dashboard key.\n if (input === \"+\" || input === \"=\") return { kind: \"tickFaster\" };\n if (input === \"-\") return { kind: \"tickSlower\" };\n\n // Card toggles 0-9. Slot 0 is Commits; slot 8 is Recent. DAG stays\n // a keybind-only popup on `g` so it does not consume a card slot.\n if (input >= \"0\" && input <= \"9\") {\n const cardId = (input.charCodeAt(0) - \"0\".charCodeAt(0)) as\n | 0\n | 1\n | 2\n | 3\n | 4\n | 5\n | 6\n | 7\n | 8\n | 9;\n return { kind: \"toggleCard\", cardId };\n }\n\n if (input === \"g\") return { kind: \"openPopup\", cardId: \"dag\" };\n if (input === \"t\") return { kind: \"openPopup\", cardId: \"allTasks\" };\n\n // Popup openers !-) on US keyboards. Bound by glyph because ink\n // reports the post-shift character; key.shift is false.\n // Layout-dependent — see design_global_keymap ODDITY for non-US\n // keymaps. Shift+0 opens Commits; Shift+8 opens Recent.\n const glyphMap: Record<string, 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9> = {\n \")\": 0,\n \"!\": 1,\n \"@\": 2,\n \"#\": 3,\n $: 4,\n \"%\": 5,\n \"^\": 6,\n \"&\": 7,\n \"*\": 8,\n \"(\": 9,\n };\n const popupId = glyphMap[input];\n if (popupId !== undefined) return { kind: \"openPopup\", cardId: popupId };\n\n return { kind: \"noop\" };\n}\n\n// ─── In-popup keymap convention ────────────────────────────────────\n//\n// Per design_global_keymap, every popup honours:\n// j / ↓ moveDown\n// k / ↑ moveUp\n// g jumpTop\n// G jumpBottom\n// Ctrl-D pageDown (half)\n// Ctrl-U pageUp (half)\n// PgDn / PgUp pageDown / pageUp (full)\n// / enterFilter\n// n nextMatch\n// N prevMatch\n// Esc close (or exit drill, when in drill mode)\n// q close (alias)\n// y yank\n// Enter drill into the focused row (popup decides what to render)\n// ? toggleHelp\n//\n// Tick-rate keys (+/-/=), refresh (r/F5), and Ctrl-C remain live in\n// popups (they're global). Card toggles (0-9) and popup openers (!-))\n// are SUPPRESSED by <App>.\n\nexport type PopupAction =\n | { kind: \"moveDown\" }\n | { kind: \"moveUp\" }\n | { kind: \"jumpTop\" }\n | { kind: \"jumpBottom\" }\n | { kind: \"pageDown\"; half: boolean }\n | { kind: \"pageUp\"; half: boolean }\n // Mouse double-click on popup body row `row` (0-based from the first\n // row inside the top border). The popup maps it through its own\n // scroll window and header rows, focuses that item, and drills it.\n | { kind: \"clickRow\"; row: number }\n | { kind: \"filter\" }\n | { kind: \"nextMatch\" }\n | { kind: \"prevMatch\" }\n | { kind: \"close\" }\n | { kind: \"yank\" }\n | { kind: \"drill\" }\n | { kind: \"verb\"; key: string }\n | { kind: \"noop\" };\n\nexport interface PopupActionEnvelope {\n seq: number;\n action: PopupAction;\n}\n\n/**\n * Map a keystroke inside a popup to the popup-local action it\n * represents. Per-popup verbs (letter keys not in the reserved set\n * {j k g G n N q y c r w}) bubble up as `{kind: \"verb\", key}` so the\n * caller can switch on the literal letter.\n */\nexport function dispatchPopupKeyFromInk(input: string, key: InkKeyLike): PopupAction {\n return dispatchPopupKey(input, keyFlagsFromInk(key));\n}\n\n// ─── App-level swallow rules ───────────────────────────────────────\n//\n// Per review_tui_help_overlay_swallows_only_some_keys: the swallow\n// lists for the help-overlay branch and the popup-mode branch in\n// <App>'s useInput were duplicated — same conceptual rule (\"do not\n// let this keystroke leak into the global dashboard keymap while a\n// modal is open\") expressed twice with slightly different lists,\n// inviting drift. Centralised here so a future binding change has\n// one place to update.\n//\n// Caller contract: this helper ONLY decides whether to short-\n// circuit BEFORE the global-keymap dispatcher (`dispatchGlobalKey`)\n// runs. The caller is still responsible for App-owned actions that\n// fire BEFORE the swallow check (toggling helpOpen on close keys,\n// Ctrl-C universal exit). Every popup component owns its own\n// `useInput`; ink fires every mounted `useInput` per keystroke, so\n// the popup's local nav handler still sees `j` / `k` / etc. while\n// this helper short-circuits the global one.\n\n/** Active <App> input mode for swallow-rule selection. */\nexport type InputMode = \"dashboard\" | \"help\" | \"popup\" | \"popup-filter\";\n\n/**\n * Should this keystroke be swallowed (NOT dispatched to the global\n * dashboard keymap)?\n *\n * - `dashboard` — never swallow; the global keymap is the only\n * keymap.\n * - `help` — swallow everything. Help owns its local scroll\n * keys (j/k/Ctrl-D/Ctrl-U/PgUp/PgDn) via `Help`'s own useInput;\n * nothing else should reach the global dispatcher while the\n * overlay is up. Caller pre-handles `Esc`/`q`/`Q`/`?` close keys.\n * - `popup` — swallow close keys (popup owns close), card\n * toggles (`0`-`9` + `!@#$%^&*()`), the keybind-only popup\n * openers (`g`/`t`), and footer-clear (`c`). Tick (`+`/`-`/`=`),\n * refresh (`r`/`F5`), help toggle (`?`), and tab nav (Tab/Shift-\n * Tab) still bubble up so they remain global even inside a popup.\n * - `popup-filter` — swallow EVERY global key. The popup's `/`\n * filter prompt is the active text input; tick/refresh/help/etc.\n * would compete with the user's typing.\n *\n * Ctrl-C is NEVER swallowed regardless of mode (universal escape).\n * The caller still handles it explicitly so it remains a hard\n * `exit()` even when otherwise inside a popup.\n */\nexport function shouldSwallowGlobalKey(input: string, key: KeyFlags, mode: InputMode): boolean {\n if (key.ctrl === true && input === \"c\") return false;\n switch (mode) {\n case \"dashboard\":\n return false;\n case \"help\":\n return true;\n case \"popup-filter\":\n return true;\n case \"popup\":\n if (key.escape === true || input === \"q\" || input === \"Q\") return true;\n // Guard on length: input is \"\" for pure-flag keys (Tab,\n // arrows, Esc, F5). Without the length check, JS's\n // `.includes(\"\")` returns true for the popup-opener glyph\n // string and would swallow Tab.\n if (input.length === 0) return false;\n if (input >= \"0\" && input <= \"9\") return true;\n if (\"!@#$%^&*()\".includes(input)) return true;\n if (input === \"g\" || input === \"t\" || input === \"c\") return true;\n return false;\n }\n}\n\nexport function shouldSwallowGlobalKeyFromInk(\n input: string,\n key: InkKeyLike,\n mode: InputMode,\n): boolean {\n return shouldSwallowGlobalKey(input, keyFlagsFromInk(key), mode);\n}\n\nexport function dispatchPopupKey(input: string, key: KeyFlags): PopupAction {\n if (key.escape || input === \"q\" || input === \"Q\") return { kind: \"close\" };\n if (input === \"j\" || key.downArrow) return { kind: \"moveDown\" };\n if (input === \"k\" || key.upArrow) return { kind: \"moveUp\" };\n if (input === \"g\") return { kind: \"jumpTop\" };\n if (input === \"G\") return { kind: \"jumpBottom\" };\n if (key.ctrl && input === \"d\") return { kind: \"pageDown\", half: true };\n if (key.ctrl && input === \"u\") return { kind: \"pageUp\", half: true };\n if (key.pageDown) return { kind: \"pageDown\", half: false };\n if (key.pageUp) return { kind: \"pageUp\", half: false };\n if (input === \"/\") return { kind: \"filter\" };\n if (input === \"n\") return { kind: \"nextMatch\" };\n if (input === \"N\") return { kind: \"prevMatch\" };\n if (input === \"y\") return { kind: \"yank\" };\n // Enter drills into the focused row. The popup chooses what\n // \"drill\" renders (scrollback / sub-list / notes / no-op for\n // log). The dispatcher stays purely structural — read-only.\n if (key.return) return { kind: \"drill\" };\n // Per-popup verbs: any letter NOT in the reserved set above is a\n // candidate for a popup-specific verb. The caller decides whether\n // to act.\n if (/^[a-zA-Z]$/.test(input)) return { kind: \"verb\", key: input };\n return { kind: \"noop\" };\n}\n","// Shared scroll/navigation primitives for every popup + drill view.\n//\n// Per feat_centralize_scroll_navigation (workstream `tui-impl`):\n// before this module landed, every popup had its OWN switch over\n// PopupAction.kind with the same six scroll cases (moveUp / moveDown\n// / jumpTop / jumpBottom / pageUp / pageDown). Counted ~60\n// near-duplicate switch arms across 9 popups + drill consumers.\n// Inevitable drift — `Ctrl-D` half-page only landed in some drill\n// branches; `g` / `G` only worked in some modes; tracks.tsx had a\n// third copy for its task-detail leaf. This file is the single\n// source of truth.\n//\n// PURE: no ink imports, no React, no DB. Just integer math on\n// (cursor | scrollTop) given (action, total, viewport). Trivially\n// unit-testable; covered by test/tui-scroll.test.ts.\n//\n// Two consumer flavours:\n//\n// CURSOR-BASED (every popup's LIST mode + tracks task-list drill):\n// a focused row index that the user moves with j/k; visible rows\n// pan around the cursor; Enter on the focused row drills.\n// Use `applyCursor`.\n//\n// SCROLL-BASED (DrillScrollView and similar): a scrollTop offset\n// the user pages through; no per-row focus; the body is\n// pre-formatted text (lines). Use `applyScroll`.\n//\n// Both consume the SAME cursor/scroll action kinds (matches\n// PopupAction's nav subset from src/cli/tui/keys.ts), so the popup\n// boilerplate is:\n//\n// if (isNavAction(action)) {\n// setCursor((c) => applyCursor(c, action, items.length, viewport));\n// return;\n// }\n// switch (action.kind) { case \"yank\": ... case \"drill\": ... }\n//\n// or for a DrillScrollView:\n//\n// if (isNavAction(action)) {\n// setScrollTop((s) => applyScroll(s, action, totalLines, viewport));\n// return;\n// }\n\n/**\n * The PopupAction kinds that move the cursor or scroll the view.\n * Exact subset of PopupAction from keys.ts — kept structurally\n * compatible so `isNavAction(popupAction)` narrows in-place without\n * a remap.\n */\nexport type NavAction =\n | { kind: \"moveUp\" }\n | { kind: \"moveDown\" }\n | { kind: \"jumpTop\" }\n | { kind: \"jumpBottom\" }\n | { kind: \"pageUp\"; half: boolean }\n | { kind: \"pageDown\"; half: boolean };\n\nconst NAV_KINDS = new Set<string>([\n \"moveUp\",\n \"moveDown\",\n \"jumpTop\",\n \"jumpBottom\",\n \"pageUp\",\n \"pageDown\",\n]);\n\n/**\n * Type predicate: is this PopupAction one of the six nav cases? When\n * true, the value is structurally a NavAction and can be passed to\n * applyCursor / applyScroll directly.\n */\nexport function isNavAction(action: { kind: string }): action is NavAction {\n return NAV_KINDS.has(action.kind);\n}\n\n/**\n * Half/full page step. Matches the pre-existing per-popup formula\n * `Math.floor(viewport / (half ? 2 : 1))`. Kept literal so behaviour\n * for tiny viewports (where half=true rounds to 0 → no-op page)\n * matches what shipped before centralisation.\n */\nfunction pageStep(viewport: number, half: boolean): number {\n return Math.floor(viewport / (half ? 2 : 1));\n}\n\n/**\n * Clamp a scrollTop offset to [0, max(0, totalLines - viewport)] so\n * the visible slice never falls past the end of the body. Pure;\n * relocated from the previous home in popups/drill.tsx so that\n * applyScroll and the DrillScrollView paint helper can share one\n * implementation.\n */\nexport function clampScrollTop(scrollTop: number, totalLines: number, viewport: number): number {\n const max = Math.max(0, totalLines - viewport);\n if (scrollTop < 0) return 0;\n if (scrollTop > max) return max;\n return scrollTop;\n}\n\n/** Clamp a cursor index to [0, max(0, total - 1)]. */\nfunction clampCursor(cursor: number, total: number): number {\n const last = Math.max(0, total - 1);\n if (cursor < 0) return 0;\n if (cursor > last) return last;\n return cursor;\n}\n\n/**\n * Apply a navigation action to a cursor-based view. Returns the new\n * cursor index, clamped to [0, total-1] (or 0 when total === 0).\n *\n * cursor current cursor index\n * action one of the six NavAction kinds\n * total length of the underlying collection (rows / items)\n * viewport visible row count — used only for page-step semantics\n */\nexport function applyCursor(\n cursor: number,\n action: NavAction,\n total: number,\n viewport: number,\n): number {\n const last = Math.max(0, total - 1);\n switch (action.kind) {\n case \"moveUp\":\n return Math.max(0, cursor - 1);\n case \"moveDown\":\n return Math.min(last, cursor + 1);\n case \"jumpTop\":\n return 0;\n case \"jumpBottom\":\n return last;\n case \"pageDown\":\n return clampCursor(cursor + pageStep(viewport, action.half), total);\n case \"pageUp\":\n return clampCursor(cursor - pageStep(viewport, action.half), total);\n }\n}\n\n/**\n * Resolve a double-clicked popup body row (PopupAction `clickRow`) to\n * the item it shows. The popup passes the SAME list, cursor and\n * viewport it renders with, so the scroll window matches the screen.\n * Returns null when the click missed the data rows.\n *\n * bodyRow 0-based row inside the popup's top border\n * headerRows in-body rows rendered above the data window (filter /\n * sort strips, a drill title line)\n */\nexport function clickedItem<T>(\n items: readonly T[],\n cursor: number,\n viewport: number,\n bodyRow: number,\n headerRows = 0,\n): { index: number; item: T } | null {\n const { start, visible } = centredVisibleSlice(items, cursor, viewport);\n const offset = bodyRow - headerRows;\n if (offset < 0 || offset >= visible.length) return null;\n const index = start + offset;\n const item = items[index];\n return item === undefined ? null : { index, item };\n}\n\n/**\n * Compute the visible slice of `items` that centres `cursor` in a\n * `viewport`-sized window. Returns the start index AND the sliced\n * array, so callers don't repeat the `.slice(start, start +\n * viewport)` step.\n *\n * Per review_dedup_drill_centring_visible_slice: three drill views\n * (log events list, tracks task-list, workspaces commits-since-fork)\n * had the IDENTICAL inline `Math.max(0, Math.min(items.length -\n * viewport, cursor - Math.floor(viewport/2)))` formula. Sibling\n * helpers (applyCursor / applyScroll) own the cursor-update math\n * but NOT the visible-slice math, so the formula was drifting\n * between popups (`Math.floor` vs `Math.ceil`, half-window vs\n * explicit). One source of truth here, three callers collapse to\n * one line each.\n *\n * Boundary semantics (kept identical to the prior inline formula):\n * - empty items → start=0, visible=[]\n * - items.length <= viewport → start=0, visible=items.slice()\n * - cursor near top → start clamps to 0\n * - cursor near bottom → start clamps to items.length - viewport\n * - else → start = cursor - floor(viewport/2)\n *\n * The viewport must be > 0; a viewport of 0 (no rows visible)\n * yields start=0 and visible=[].\n */\nexport function centredVisibleSlice<T>(\n items: readonly T[],\n cursor: number,\n viewport: number,\n): { start: number; visible: T[] } {\n if (viewport <= 0 || items.length === 0) return { start: 0, visible: [] };\n const start = Math.max(0, Math.min(items.length - viewport, cursor - Math.floor(viewport / 2)));\n return { start, visible: items.slice(start, start + viewport) };\n}\n\n/**\n * Apply a navigation action to a scrollTop-based view (e.g.\n * DrillScrollView). Returns the new scrollTop, clamped via\n * clampScrollTop so the bottom of the body never scrolls past the\n * viewport.\n *\n * scrollTop current top-of-viewport line index\n * action one of the six NavAction kinds\n * totalLines length of the underlying body in lines\n * viewport visible line count\n */\nexport function applyScroll(\n scrollTop: number,\n action: NavAction,\n totalLines: number,\n viewport: number,\n): number {\n switch (action.kind) {\n case \"moveUp\":\n return clampScrollTop(scrollTop - 1, totalLines, viewport);\n case \"moveDown\":\n return clampScrollTop(scrollTop + 1, totalLines, viewport);\n case \"jumpTop\":\n return 0;\n case \"jumpBottom\":\n return clampScrollTop(totalLines, totalLines, viewport);\n case \"pageDown\":\n return clampScrollTop(scrollTop + pageStep(viewport, action.half), totalLines, viewport);\n case \"pageUp\":\n return clampScrollTop(scrollTop - pageStep(viewport, action.half), totalLines, viewport);\n }\n}\n","import { useEffect, useRef } from \"react\";\nimport { MOUSE_MODE_ENTER, MOUSE_MODE_EXIT } from \"./escapes.js\";\n\nexport const DOUBLE_CLICK_MS = 300;\n\nexport type MouseButton = 0 | 1 | 2 | number;\n\nexport interface MouseBaseEvent {\n x: number;\n y: number;\n button: MouseButton;\n ts: number;\n}\n\nexport interface MousePressEvent extends MouseBaseEvent {\n kind: \"press\";\n}\n\nexport interface MouseReleaseEvent extends MouseBaseEvent {\n kind: \"release\";\n}\n\nexport interface MouseScrollEvent extends MouseBaseEvent {\n kind: \"scroll\";\n direction: \"up\" | \"down\";\n}\n\nexport interface MouseDoubleClickEvent extends MouseBaseEvent {\n kind: \"doubleclick\";\n}\n\nexport type ParsedMouseEvent = MousePressEvent | MouseReleaseEvent | MouseScrollEvent;\nexport type MouseEvent = ParsedMouseEvent | MouseDoubleClickEvent;\n\nexport type MouseSubscriber = (event: MouseEvent) => void;\n\ntype MouseReportSubscriber = (event: ParsedMouseEvent) => void;\n\nconst subscribers = new Set<MouseReportSubscriber>();\nconst SGR_MOUSE_PATTERN = \"\\\\u001b\\\\[<(\\\\d+);(\\\\d+);(\\\\d+)([Mm])\";\nlet stdinAttached = false;\nlet pending = \"\";\n\nexport function enableMouseMode(): void {\n process.stdout.write(MOUSE_MODE_ENTER);\n}\n\nexport function disableMouseMode(): void {\n process.stdout.write(MOUSE_MODE_EXIT);\n}\n\nexport function parseSgrMouseEvents(\n input: string,\n now: () => number = Date.now,\n): ParsedMouseEvent[] {\n const events: ParsedMouseEvent[] = [];\n const re = new RegExp(SGR_MOUSE_PATTERN, \"g\");\n let match = re.exec(input);\n while (match !== null) {\n const codeText = match[1];\n const xText = match[2];\n const yText = match[3];\n const suffix = match[4];\n if (\n codeText === undefined ||\n xText === undefined ||\n yText === undefined ||\n suffix === undefined\n ) {\n match = re.exec(input);\n continue;\n }\n const code = Number.parseInt(codeText, 10);\n const x = Number.parseInt(xText, 10);\n const y = Number.parseInt(yText, 10);\n if (!Number.isFinite(code) || !Number.isFinite(x) || !Number.isFinite(y)) {\n match = re.exec(input);\n continue;\n }\n\n const ts = now();\n if (suffix === \"M\" && (code === 64 || code === 65)) {\n events.push({\n kind: \"scroll\",\n direction: code === 64 ? \"up\" : \"down\",\n x,\n y,\n button: code,\n ts,\n });\n match = re.exec(input);\n continue;\n }\n\n const button = code & 3;\n if (suffix === \"m\") {\n events.push({ kind: \"release\", x, y, button, ts });\n } else {\n events.push({ kind: \"press\", x, y, button, ts });\n }\n match = re.exec(input);\n }\n return events;\n}\n\nexport interface DoubleClickDetectorOptions {\n windowMs?: number;\n}\n\nexport interface DoubleClickDetector {\n push: (event: ParsedMouseEvent) => MouseEvent[];\n}\n\nexport function createDoubleClickDetector(\n opts: DoubleClickDetectorOptions = {},\n): DoubleClickDetector {\n const windowMs = opts.windowMs ?? DOUBLE_CLICK_MS;\n let lastPress: MousePressEvent | null = null;\n return {\n push(event) {\n if (event.kind !== \"press\") return [event];\n const previous = lastPress;\n lastPress = event;\n if (\n previous !== null &&\n event.ts - previous.ts <= windowMs &&\n event.x === previous.x &&\n event.y === previous.y &&\n event.button === previous.button\n ) {\n return [\n event,\n { kind: \"doubleclick\", x: event.x, y: event.y, button: event.button, ts: event.ts },\n ];\n }\n return [event];\n },\n };\n}\n\nexport function useMouse(\n onEvent: MouseSubscriber,\n opts: { isActive?: boolean; doubleClickMs?: number } = {},\n): void {\n const callback = useRef(onEvent);\n callback.current = onEvent;\n const detector = useRef(createDoubleClickDetector({ windowMs: opts.doubleClickMs }));\n\n useEffect(() => {\n detector.current = createDoubleClickDetector({ windowMs: opts.doubleClickMs });\n }, [opts.doubleClickMs]);\n\n useEffect(() => {\n if (opts.isActive === false) return undefined;\n return subscribeToMouseReports((event) => {\n for (const emitted of detector.current.push(event)) {\n callback.current(emitted);\n }\n });\n }, [opts.isActive]);\n}\n\nexport function mouseEventToNavAction(\n event: MouseEvent,\n): { kind: \"moveUp\" } | { kind: \"moveDown\" } | null {\n if (event.kind !== \"scroll\") return null;\n return event.direction === \"up\" ? { kind: \"moveUp\" } : { kind: \"moveDown\" };\n}\n\nfunction subscribeToMouseReports(fn: MouseReportSubscriber): () => void {\n subscribers.add(fn);\n attachStdin();\n return () => {\n subscribers.delete(fn);\n if (subscribers.size === 0) detachStdin();\n };\n}\n\nfunction attachStdin(): void {\n if (stdinAttached) return;\n process.stdin.on(\"data\", onStdinData);\n stdinAttached = true;\n}\n\nfunction detachStdin(): void {\n if (!stdinAttached) return;\n process.stdin.off(\"data\", onStdinData);\n stdinAttached = false;\n pending = \"\";\n}\n\nfunction onStdinData(chunk: Buffer | string): void {\n pending += typeof chunk === \"string\" ? chunk : chunk.toString(\"utf8\");\n const parsed: ParsedMouseEvent[] = [];\n const re = new RegExp(SGR_MOUSE_PATTERN, \"g\");\n let lastEnd = 0;\n let match = re.exec(pending);\n while (match !== null) {\n const report = match[0];\n lastEnd = re.lastIndex;\n parsed.push(...parseSgrMouseEvents(report));\n match = re.exec(pending);\n }\n if (lastEnd > 0) {\n pending = pending.slice(lastEnd);\n } else {\n const lastEscape = pending.lastIndexOf(\"\\x1b[<\");\n pending = lastEscape >= 0 ? pending.slice(lastEscape) : \"\";\n }\n for (const event of parsed) {\n for (const subscriber of subscribers) subscriber(event);\n }\n}\n","// Pure escape-sequence constants for the TUI. Lives in src/cli/tui/ but\n// imports neither ink nor react so unit tests can assert exact bytes\n// without booting an ink renderer.\n//\n// On enter:\n// \\x1b[?1049h swap to alt-screen buffer\n// \\x1b[2J clear entire screen (else stale shell text bleeds through\n// ink's diff renderer until ink overwrites it)\n// \\x1b[H home cursor to row 1, col 1 (alt-screen swap inherits the\n// cursor row from the prior buffer on most terminals —\n// iTerm2, Apple Terminal, tmux's inner terminal, ...)\n// \\x1b[?25l hide cursor (lazygit/btop convention; otherwise the\n// blinking cursor sits behind the rendered cards)\n//\n// On exit, mirror in reverse: show cursor, then restore the prior buffer.\nexport const ALT_SCREEN_ENTER = \"\\x1b[?1049h\\x1b[2J\\x1b[H\\x1b[?25l\";\nexport const ALT_SCREEN_EXIT = \"\\x1b[?25h\\x1b[?1049l\";\n\n// Mouse mode uses normal tracking + button-motion + SGR extended\n// coordinates. SGR reports arrive as ESC [ < button ; x ; y ; M/m.\n// Disable in the exact reverse order during TUI teardown so native\n// terminal selection works again after exit.\nexport const MOUSE_MODE_ENTER = \"\\x1b[?1000h\\x1b[?1002h\\x1b[?1006h\";\nexport const MOUSE_MODE_EXIT = \"\\x1b[?1006l\\x1b[?1002l\\x1b[?1000l\";\n","// Keyboard gate for popups.\n//\n// <App> keeps the open popup MOUNTED (display=\"none\") while the `?`\n// help overlay covers it, so popup-local state (cursor, filter query,\n// drill pin, drill scroll) survives a help round trip. A hidden popup\n// must not react to keys meant for the overlay, so every popup reads\n// its keyboard through `usePopupInput`, which turns ink's `useInput`\n// off while the App says the popup is covered.\n\nimport { useInput } from \"ink\";\nimport { createContext, useContext } from \"react\";\n\n/** False while the help overlay covers the open popup. */\nexport const PopupInputActive = createContext(true);\n\ntype InputHandler = Parameters<typeof useInput>[0];\n\nexport function usePopupInput(handler: InputHandler): void {\n const isActive = useContext(PopupInputActive);\n useInput(handler, { isActive });\n}\n","// Agents popup (Shift+1 → `!`). Drill-down for the Agents card.\n//\n// Per design_popup_agents (workstream `tui`): list of agents with\n// per-agent yank intents (free / close / send).\n//\n// Enter on a row drills into a read-only inline scrollback view —\n// equivalent to `mu agent read <name> -n 80` rendered as plain text\n// with j/k scroll. Esc / q in drill mode returns to the list; a\n// second Esc / q closes the popup back to the dashboard.\n//\n// Read-only: drilling never executes anything; we only call\n// readAgent which is a tmux capture-pane wrapper. The yank verbs\n// (f / x / y) still emit `mu` command strings the user must paste\n// to actually run.\n//\n// Rows are column-aligned via src/cli/tui/columns.ts. Per\n// feat_column_aligned_lists clipping policy: glyph, agent name,\n// status are PROTECTED; the role description is CLIPPABLE.\n\nimport { Box, Text } from \"ink\";\nimport { type ReactElement, useCallback, useEffect, useRef, useState } from \"react\";\nimport { type LiveAgent, readAgent } from \"../../../agents.js\";\nimport type { Db } from \"../../../db.js\";\nimport type { WorkstreamSnapshot } from \"../../../state.js\";\nimport { agentStateGlyph } from \"../agent-display.js\";\nimport { type ColumnSpec, contentWidthFromCols, layoutColumns, renderRow } from \"../columns.js\";\nimport { dispatchPopupKeyFromInk, type PopupAction, type PopupActionEnvelope } from \"../keys.js\";\nimport { ListRow } from \"../list-row.js\";\nimport { usePopupInput } from \"../popup-input.js\";\nimport { PopupShell } from \"../popup-shell.js\";\nimport { resolveAttachCommands, runTmuxAttachInteractive } from \"../tmux-attach.js\";\nimport { usePopupActionQueue } from \"../use-popup-action-queue.js\";\nimport { applyFilter, FilterPrompt, listViewport, usePopupFilter } from \"../use-popup-filter.js\";\nimport { useTerminalSize } from \"../use-terminal-size.js\";\nimport { DrillScrollView, useDrillKeymap } from \"./drill.js\";\nimport { applyCursor, centredVisibleSlice, clickedItem, isNavAction } from \"./scroll.js\";\nimport { POPUP_DRILL_CHROME_ROWS, usePopupViewport } from \"./viewport.js\";\n\nexport interface PopupProps {\n yank: (command: string) => Promise<void>;\n onClose: () => void;\n snapshot: WorkstreamSnapshot | null;\n slowTickNonce: number;\n mode: \"list\" | \"drill\";\n onModeChange: (mode: \"list\" | \"drill\") => void;\n /** Bubbles the filter-prompt edit state up to <App> for StatusBar mode. */\n onFilterEditingChange?: (editing: boolean) => void;\n popupActions?: readonly PopupActionEnvelope[];\n /** Surface tmux-attach success/error in the footer status bar.\n * Optional so existing callers / tests stay valid. */\n onFooter?: (command: string, copied: boolean, tone?: \"normal\" | \"info\" | \"error\") => void;\n db: Db;\n workstream: string;\n}\n\nconst AGENT_COLORS = [\n undefined, // glyph (plain)\n { bold: true }, // name\n { dimColor: true }, // status\n { dimColor: true }, // role\n] as const;\n\nconst COLUMN_SPECS: ReadonlyArray<ColumnSpec> = [\n { kind: \"protect\" }, // glyph\n { kind: \"protect\" }, // agent name\n { kind: \"protect\" }, // status token\n { kind: \"clip\", min: 1 }, // role\n];\n\nconst SCROLLBACK_LINES = 80;\n\nexport function AgentsPopup({\n yank,\n onClose,\n snapshot,\n slowTickNonce,\n mode,\n onModeChange,\n onFilterEditingChange,\n popupActions,\n onFooter,\n db,\n workstream,\n}: PopupProps): ReactElement {\n const { cols } = useTerminalSize();\n const contentWidth = contentWidthFromCols(cols);\n // Per-render viewport from stdout.rows minus the popup chrome budget;\n // see popups/viewport.ts. Replaces the prior hardcoded VIEWPORT = 20.\n const viewport = usePopupViewport();\n const [cursor, setCursor] = useState(0);\n const [scrollback, setScrollback] = useState<string>(\"\");\n const [scrollbackErr, setScrollbackErr] = useState<string | null>(null);\n const [loading, setLoading] = useState(false);\n const flt = usePopupFilter({ onEditingChange: onFilterEditingChange });\n const rowsViewport = listViewport(viewport, flt);\n const drillViewport = usePopupViewport(POPUP_DRILL_CHROME_ROWS);\n // Per bug_filter_drill_opens_wrong_task: text filter applied\n // UNIFORMLY across list and drill modes (the previous mode-conditional\n // dropped the filter on drill, shifting `agents` under a constant\n // cursor index).\n const sourceAgents = snapshot?.view.agents ?? [];\n const agents = applyFilter(\n sourceAgents,\n flt.query,\n (a) => `${a.name} ${a.state} ${a.cli} ${a.role}`,\n );\n const safeCursor = agents.length === 0 ? 0 : Math.min(cursor, agents.length - 1);\n const focused = agents[safeCursor];\n // Defensive: capture focused agent identity at Enter so the drill\n // stays pinned to the agent the user visually selected even if the\n // list shifts underneath us.\n const [drilledAgent, setDrilledAgent] = useState<LiveAgent | null>(null);\n const drillAgent = mode === \"drill\" ? (drilledAgent ?? focused) : focused;\n const lastFocusedAgentName = useRef<string | null>(null);\n // Load scrollback when entering drill mode (or when the focused\n // row changes while in drill mode). Read-only: capturePane is a\n // tmux read, never a write.\n const loadScrollback = useCallback(\n async (paneAgent: string) => {\n setLoading(true);\n setScrollbackErr(null);\n // Keep the previous scrollback visible during the slow-tick\n // refetch; clearing here causes a blank-flash flicker.\n try {\n const text = await readAgent(db, paneAgent, {\n workstream,\n lines: SCROLLBACK_LINES,\n });\n setScrollback(text);\n } catch (e) {\n setScrollbackErr(e instanceof Error ? e.message : String(e));\n setScrollback(\"\");\n } finally {\n setLoading(false);\n }\n },\n [db, workstream],\n );\n\n useEffect(() => {\n void slowTickNonce;\n if (mode === \"drill\" && drillAgent) {\n if (lastFocusedAgentName.current !== drillAgent.name) {\n setScrollback(\"\");\n setScrollbackErr(null);\n }\n lastFocusedAgentName.current = drillAgent.name;\n void loadScrollback(drillAgent.name);\n }\n }, [mode, drillAgent, loadScrollback, slowTickNonce]);\n\n useEffect(() => {\n if (mode !== \"drill\") {\n lastFocusedAgentName.current = null;\n setScrollback(\"\");\n setScrollbackErr(null);\n setLoading(false);\n }\n }, [mode]);\n\n const drillBody = scrollbackErr !== null ? `error: ${scrollbackErr}` : scrollback;\n const drill = useDrillKeymap({\n body: drillBody,\n viewport: drillViewport,\n onClose: () => {\n setDrilledAgent(null);\n onModeChange(\"list\");\n },\n onYank: () => {\n if (!drillAgent || !snapshot) return;\n return yank(\n `mu agent read ${drillAgent.name} -n ${SCROLLBACK_LINES} -w ${snapshot.workstreamName}`,\n );\n },\n resetKey: drillAgent?.name ?? \"\",\n });\n\n const dispatchListAction = (action: PopupAction) => {\n if (mode === \"drill\") {\n drill.dispatch(action);\n return;\n }\n if (isNavAction(action)) {\n setCursor((c) => applyCursor(c, action, agents.length, rowsViewport));\n return;\n }\n switch (action.kind) {\n case \"close\":\n onClose();\n return;\n case \"filter\":\n flt.startEdit();\n return;\n case \"drill\":\n if (focused) {\n setDrilledAgent(focused);\n onModeChange(\"drill\");\n }\n return;\n case \"clickRow\": {\n const hit = clickedItem(agents, safeCursor, rowsViewport, action.row);\n if (!hit) return;\n setCursor(hit.index);\n setDrilledAgent(hit.item);\n onModeChange(\"drill\");\n return;\n }\n case \"yank\": {\n const a = agents[safeCursor];\n if (!a || !snapshot) return;\n const ws = snapshot.workstreamName;\n // Default yank: a `mu agent send` template the user can edit.\n // The popup-verb key x covers close.\n void yank(`mu agent send ${a.name} '...' -w ${ws}`);\n return;\n }\n case \"verb\": {\n const a = agents[safeCursor];\n if (!a || !snapshot) return;\n const ws = snapshot.workstreamName;\n if (action.key === \"x\") {\n void yank(`mu agent close ${a.name} -w ${ws}`);\n return;\n }\n if (action.key === \"a\") {\n // Per-popup TUI escape: hand off to the multiplexer to put\n // the user on the agent's pane. Mirrors `t tuicr` /\n // `l lazygit`. Read-only-by-design TUI is preserved — we\n // don't mutate state, we just let the user look at /\n // interact with the pane until they navigate back.\n const session = `mu-${ws}`;\n const window = a.tab ?? a.name;\n void resolveAttachCommands({ session, window }).then((commands) => {\n const r = runTmuxAttachInteractive({ commands });\n if (!r.ok) onFooter?.(r.error ?? \"attach failed\", false, \"error\");\n else onFooter?.(`attach → ${session}:${window}`, true, \"info\");\n });\n return;\n }\n return;\n }\n }\n };\n\n usePopupActionQueue(popupActions, dispatchListAction);\n\n usePopupInput((input, key) => {\n // Filter-mode keystrokes (when the prompt is editing) consume\n // every printable + Esc/Enter/Bksp; the popup's own dispatchPopupKey\n // is bypassed for the duration of the edit.\n if (mode !== \"drill\" && flt.onKey(input, key) === \"consumed\") return;\n dispatchListAction(dispatchPopupKeyFromInk(input, key));\n });\n\n if (snapshot === null) {\n return <PopupShell title=\"Agents · popup\">{<Text dimColor>loading…</Text>}</PopupShell>;\n }\n if (sourceAgents.length === 0) {\n return (\n <PopupShell title=\"Agents · popup\">\n <Text dimColor>(no agents)</Text>\n </PopupShell>\n );\n }\n if (agents.length === 0) {\n return (\n <PopupShell title=\"Agents · popup\">\n <Box flexDirection=\"column\" flexGrow={1}>\n <Text dimColor>(no matches for \"{flt.query}\")</Text>\n </Box>\n <FilterPrompt state={flt} />\n </PopupShell>\n );\n }\n\n if (mode === \"drill\" && drillAgent) {\n return (\n <PopupShell title={`Agents · ${drillAgent.name} (scrollback)`}>\n <Box flexDirection=\"column\" flexGrow={1}>\n <DrillScrollView\n title={`mu agent read ${drillAgent.name} -n ${SCROLLBACK_LINES}`}\n body={drillBody}\n viewport={drillViewport}\n scrollTop={drill.scrollTop}\n wrappedBody={drill.wrappedBody}\n hint={`y yanks \\`mu agent read -n ${SCROLLBACK_LINES}\\``}\n emptyText={loading ? \"loading…\" : \"(no scrollback yet)\"}\n />\n </Box>\n </PopupShell>\n );\n }\n\n const { start, visible } = centredVisibleSlice(agents, safeCursor, rowsViewport);\n const rows = visible.map((a) => [agentStateGlyph(a.state), a.name, a.state, a.role]);\n const widths = layoutColumns(rows, COLUMN_SPECS, contentWidth);\n\n return (\n <PopupShell\n title={`Agents · popup (${safeCursor + 1}/${agents.length})`}\n hint=\"a attach · x close · y yanks `mu agent send`\"\n >\n <Box flexDirection=\"column\" flexGrow={1}>\n {visible.map((a, i) => {\n const sel = start + i === safeCursor;\n const row = rows[i];\n if (row === undefined) return null;\n const padded = renderRow(row, widths, COLUMN_SPECS);\n return (\n <ListRow\n key={a.name}\n cells={padded}\n contentWidth={contentWidth}\n colors={AGENT_COLORS}\n selected={sel}\n />\n );\n })}\n </Box>\n <FilterPrompt state={flt} />\n </PopupShell>\n );\n}\n","import type { ReactElement, ReactNode } from \"react\";\nimport { TitledBox } from \"./titled-box.js\";\n\nexport interface PopupShellProps {\n title: string;\n /** Per-popup hint inset into the bottom border. Null / undefined suppresses it. */\n hint?: string | null;\n children: ReactNode;\n}\n\nexport function PopupShell({ title, hint, children }: PopupShellProps): ReactElement {\n return (\n <TitledBox\n title={title}\n borderColor=\"cyan\"\n titleColor=\"cyan\"\n bottomLabel={hint ?? undefined}\n flexGrow={1}\n >\n {children}\n </TitledBox>\n );\n}\n","// Drop into a managed agent's pane from inside the TUI.\n//\n// Mirrors the `tuicr.ts` / `lazygit.ts` per-popup escape-hatch\n// pattern: leave the alt screen, hand the terminal to the multiplexer,\n// restore the alt screen on return. Bound to `a` in the Agents popup\n// (counterpart to per-revision `t tuicr` and per-cwd `l lazygit`).\n//\n// Mechanics live in the BACKEND, not here. `attachCommands()` returns\n// the argv steps for the active mux; this module only runs them with\n// stdio inherited (so any password / prompt / confirmation reaches the\n// user) and bookends them with the alt-screen dance. On tmux that is\n// `switch-client` when the caller is already inside a client and\n// `attach-session` + `select-window` otherwise, but this file does not\n// know that and must not.\n//\n// Returning to the orchestrator: the user navigates back to the\n// originating window themselves (Ctrl-B p, Ctrl-B <window>, etc.).\n// We do NOT auto-restore — the alt-screen restore happens when the\n// user re-runs `mu` or just hits whatever brings them back. This\n// matches `tuicr` / `lazygit` semantics: the escape is one-way until\n// the user explicitly comes back.\n//\n// In practice for the in-mux case (the common path): switch-client\n// returns immediately after pointing the client at the new\n// session:window, so the alt-screen restore fires almost instantly\n// and the user is now looking at the worker pane in the same client.\n// The mu TUI is still running in its original window — switching\n// back via Ctrl-B p brings it into view, alt-screen still active.\n\nimport { spawnSync } from \"node:child_process\";\nimport { activeMux, type MuxCommand } from \"../../mux.js\";\nimport { ALT_SCREEN_ENTER, ALT_SCREEN_EXIT } from \"./escapes.js\";\n\nexport interface RunTmuxAttachOptions {\n /** Mux session name, e.g. `mu-multimachine`. */\n session: string;\n /** Window name or index inside the session (the agent's `tab`\n * field, or its `name` if `tab` is null). */\n window: string;\n}\n\ninterface SpawnSyncResult {\n status: number | null;\n error?: Error;\n}\n\ntype SpawnSyncFn = (\n command: string,\n args: readonly string[],\n options: { stdio: \"inherit\"; env: NodeJS.ProcessEnv },\n) => SpawnSyncResult;\n\nexport interface RunTmuxAttachDeps {\n spawn?: SpawnSyncFn;\n write?: (text: string) => void;\n env?: NodeJS.ProcessEnv;\n /** Pre-resolved attach steps. Tests inject these to stay off a real\n * mux; production resolves them from `activeMux()`. */\n commands?: readonly MuxCommand[];\n}\n\nexport interface RunTmuxAttachResult {\n ok: boolean;\n error?: string;\n}\n\n/**\n * Resolve the attach steps for `opts` from the active backend.\n *\n * Best-effort by design: the TUI's `a` key is an escape hatch, not a\n * verb. With no reachable mux the caller gets an error string in the\n * footer instead of a crashed TUI.\n */\nexport async function resolveAttachCommands(\n opts: RunTmuxAttachOptions,\n env: NodeJS.ProcessEnv = process.env,\n): Promise<readonly MuxCommand[] | undefined> {\n try {\n const mux = await activeMux();\n // `inside` is a tmux-shaped question (\"are we in a client of this\n // mux?\"), but the ANSWER is the backend's business — we just report\n // the ambient evidence we have.\n const inside = typeof env.TMUX === \"string\" && env.TMUX.length > 0;\n return await mux.attachCommands({ session: opts.session, window: opts.window, inside });\n } catch {\n return undefined;\n }\n}\n\n/**\n * Run pre-resolved attach steps with the alt screen bookended around\n * them. Takes STEPS rather than a target because the backend owns the\n * argv and resolving it is async, while ink's key handler is not.\n */\nexport function runTmuxAttachInteractive(deps: RunTmuxAttachDeps = {}): RunTmuxAttachResult {\n const run = deps.spawn ?? (spawnSync as SpawnSyncFn);\n const write = deps.write ?? ((text: string) => process.stdout.write(text));\n const env = deps.env ?? process.env;\n const commands = deps.commands;\n if (commands === undefined || commands.length === 0) {\n return { ok: false, error: \"no multiplexer available to attach with\" };\n }\n let result: RunTmuxAttachResult = { ok: true };\n\n try {\n write(ALT_SCREEN_EXIT);\n for (const step of commands) {\n const r = run(step.command, step.args, { stdio: \"inherit\", env });\n if (step.optional === true) continue;\n if (r.error !== undefined) {\n result = { ok: false, error: tmuxAttachErrorMessage(r.error) };\n break;\n }\n if (typeof r.status === \"number\" && r.status !== 0) {\n result = {\n ok: false,\n error: `${step.command} ${step.args[0] ?? \"\"} exited ${r.status}`.trim(),\n };\n break;\n }\n }\n } catch (err) {\n result = { ok: false, error: tmuxAttachErrorMessage(err) };\n } finally {\n try {\n write(ALT_SCREEN_ENTER);\n } catch {\n // Best-effort terminal repair only. Preserve the original result.\n }\n }\n\n return result;\n}\n\nexport function tmuxAttachErrorMessage(err: unknown): string {\n if (err instanceof Error) {\n const code = (err as NodeJS.ErrnoException).code;\n if (code === \"ENOENT\") return \"multiplexer binary not found\";\n return err.message.length > 0 ? err.message : String(err);\n }\n return String(err);\n}\n","// Consume App-level PopupAction events one per render.\n//\n// App emits popup actions (today: a mouse double-click's `clickRow`)\n// as a sequenced queue. This hook dispatches only the next unseen\n// action, stores its sequence in state, and lets React render before\n// dispatching the following one, so each action sees the state the\n// previous one produced.\n\nimport { useEffect, useRef, useState } from \"react\";\nimport type { PopupAction, PopupActionEnvelope } from \"./keys.js\";\n\nexport function usePopupActionQueue(\n actions: readonly PopupActionEnvelope[] | undefined,\n dispatch: (action: PopupAction) => void,\n): void {\n const [lastSeq, setLastSeq] = useState(0);\n const dispatchRef = useRef(dispatch);\n dispatchRef.current = dispatch;\n\n useEffect(() => {\n const next = actions?.find((event) => event.seq > lastSeq);\n if (next === undefined) return;\n setLastSeq(next.seq);\n dispatchRef.current(next.action);\n }, [actions, lastSeq]);\n}\n","// Shared '/' incremental substring filter for list popups\n// (Agents/Tracks/Tasks/Log + every future card popup under\n// feat_more_cards_umbrella). Per feat_popup_search_filter\n// (workstream `tui-impl`).\n//\n// Design intent: every list popup wires this hook in ~5 LOC and\n// gets the full UX (incremental edit, Enter commit, Esc cancel,\n// status-bar mode flip, no-matches fallback) for free. New card\n// popups (Workspaces / In-progress / Blocked / Recent / Doctor)\n// MUST consume `usePopupFilter` rather than re-implement the state\n// machine — keep the substrate cheap to reuse.\n//\n// The reducer is split out as a pure function (`popupFilterReducer`)\n// so it's testable without React. The hook is a thin wrapper.\n//\n// Per ROADMAP pledge: ink/react import limited to src/cli/tui/*.\n\nimport { Box, Text } from \"ink\";\nimport { type ReactElement, useCallback, useEffect, useReducer } from \"react\";\nimport type { KeyFlags } from \"./keys.js\";\n\n/** Filter state owned by each popup. Resets on popup unmount. */\nexport interface FilterState {\n /** Current query string (case preserved for display; lower-cased for matching). */\n query: string;\n /** True while the user is typing the query; false after Enter (committed) and on cancel. */\n editing: boolean;\n}\n\nexport const INITIAL_FILTER_STATE: FilterState = { query: \"\", editing: false };\n\n/**\n * Reducer events emitted by `popupFilterOnKey`. The hook dispatches\n * these internally; tests can drive the reducer directly without\n * synthesising ink keystrokes.\n */\nexport type FilterAction =\n | { kind: \"startEdit\" }\n | { kind: \"appendChar\"; char: string }\n | { kind: \"backspace\" }\n | { kind: \"commit\" }\n | { kind: \"cancel\" }\n | { kind: \"reset\" };\n\n/** Pure reducer. */\nexport function popupFilterReducer(state: FilterState, action: FilterAction): FilterState {\n switch (action.kind) {\n case \"startEdit\":\n // Re-entering edit mode keeps the existing query (so '/' after\n // Enter pre-fills for refinement). Only flips `editing`.\n return { ...state, editing: true };\n case \"appendChar\": {\n // Printable text of any length (one keystroke, a paste, or a\n // non-ASCII glyph). Control characters are stripped; an empty\n // result is the \"consumed, no change\" sentinel.\n const text = printableText(action.char);\n if (text === \"\") return state;\n return { ...state, query: state.query + text };\n }\n case \"backspace\":\n if (state.query === \"\") return state;\n // Drop one code point, not one UTF-16 unit, so astral glyphs\n // (emoji, rare CJK) do not leave a lone surrogate behind.\n return { ...state, query: Array.from(state.query).slice(0, -1).join(\"\") };\n case \"commit\":\n // Keep query, exit edit mode. Cursor-snap is the popup's job\n // (it owns the cursor state; the filter just narrows the rows).\n return { ...state, editing: false };\n case \"cancel\":\n // Esc clears the query AND exits edit mode (full reset).\n return INITIAL_FILTER_STATE;\n case \"reset\":\n return INITIAL_FILTER_STATE;\n }\n}\n\n// C0 controls, DEL, and C1 controls. Everything else (including\n// non-ASCII letters) is filter text.\n// biome-ignore lint/suspicious/noControlCharactersInRegex: matching control chars is the point\nconst CONTROL_CHARS = /[\\u0000-\\u001f\\u007f-\\u009f]/g;\n\nfunction printableText(s: string): string {\n return s.replace(CONTROL_CHARS, \"\");\n}\n\n/**\n * Classify a keystroke for filter mode. Returns the action that the\n * reducer should consume, or `null` when the key is NOT a\n * filter-mode keystroke (and the popup should run its normal\n * dispatchPopupKey logic).\n *\n * Pure function; no React. The hook calls this then dispatches the\n * returned action.\n */\nexport function classifyFilterKey(\n state: FilterState,\n input: string,\n key: KeyFlags,\n): FilterAction | null {\n if (!state.editing) return null;\n // Esc cancels (full reset).\n if (key.escape) return { kind: \"cancel\" };\n // Enter commits.\n if (key.return) return { kind: \"commit\" };\n // Backspace pops one char (no-op if empty — reducer handles it).\n // ink reports backspace via key.backspace OR delete; many terminals\n // also send DEL (0x7f) as a literal character. Cover both.\n if (\n (key as KeyFlags & { backspace?: boolean; delete?: boolean }).backspace === true ||\n (key as KeyFlags & { backspace?: boolean; delete?: boolean }).delete === true ||\n input === \"\\x7f\" ||\n input === \"\\b\"\n ) {\n return { kind: \"backspace\" };\n }\n // Skip control / navigation keys (tab, arrows, page, function keys).\n if (\n key.tab === true ||\n key.upArrow === true ||\n key.downArrow === true ||\n key.leftArrow === true ||\n key.rightArrow === true ||\n key.pageUp === true ||\n key.pageDown === true ||\n key.f5 === true\n ) {\n // Consume so they don't navigate the underlying list while the\n // user is typing (returning null would let the popup treat them\n // as nav keys). appendChar(\"\") is the consumed-no-op sentinel:\n // the reducer leaves state unchanged.\n return { kind: \"appendChar\", char: \"\" };\n }\n // Ctrl-* combos: also consume-and-ignore. Ctrl-C is handled by ink\n // itself (exitOnCtrlC) so we don't see it here.\n if (key.ctrl === true) {\n return { kind: \"appendChar\", char: \"\" };\n }\n // Printable text. ink delivers a paste as ONE multi-character\n // `input`, and non-ASCII keys (é, 中) as one non-ASCII string, so\n // append the whole string minus control characters. Anything that\n // strips to \"\" (raw escape bytes) is consumed as a no-op so the\n // underlying popup never sees it mid-edit.\n return { kind: \"appendChar\", char: printableText(input) };\n}\n\n/**\n * Filter hook for list popups. Returns the current state plus a\n * keystroke handler the popup wires into its `useInput` callback.\n *\n * const flt = usePopupFilter();\n * useInput((input, key) => {\n * if (flt.onKey(input, key) === \"consumed\") return;\n * // ...existing dispatchPopupKey switch...\n * if (action.kind === \"filter\") { flt.startEdit(); return; }\n * });\n */\nexport interface PopupFilter {\n /** Current query (case preserved; empty = \"no filter\"). */\n query: string;\n /** True while editing (caret rendered; Enter to commit). */\n editing: boolean;\n /**\n * Handle a keystroke. Returns \"consumed\" when the key was a\n * filter-mode keystroke (caller should NOT run its own\n * dispatchPopupKey logic). Returns \"passthrough\" otherwise.\n */\n onKey(input: string, key: KeyFlags): \"consumed\" | \"passthrough\";\n /** Enter edit mode (call from the dispatchPopupKey \"filter\" branch). */\n startEdit(): void;\n /** Clear query + exit edit mode. */\n reset(): void;\n}\n\n/**\n * Optional hook options. Per review_dedup_filter_editing_effect:\n * eight list popups had the IDENTICAL `useEffect(() =>\n * onFilterEditingChange?.(flt.editing), [flt.editing,\n * onFilterEditingChange])` block immediately after `const flt =\n * usePopupFilter()`. Baking the bubble-up into the hook itself\n * collapses each call site by 3 lines and means the next popup\n * author can't forget to wire the StatusBar mode flip.\n *\n * `onEditingChange` is a callback the popup wires to its parent\n * `<App>`'s `setPopupFilterEditing`. Called WHENEVER the editing\n * flag changes (and once on mount when the initial value differs\n * from undefined-default). When omitted, the hook is silent.\n *\n * `enabled` (default true) lets popups with MULTIPLE filter\n * instances (e.g. workspaces.tsx — list view + commits drill view)\n * mark which instance is currently active. A disabled instance\n * always bubbles `false` regardless of its own `state.editing`, so\n * the StatusBar mode flip stays consistent across sub-modes\n * without hand-rolling a conditional useEffect at the call site.\n * Per review_tui_workspaces_two_filter_instances.\n */\nexport interface UsePopupFilterOpts {\n onEditingChange?: (editing: boolean) => void;\n enabled?: boolean;\n}\n\nexport function usePopupFilter(opts: UsePopupFilterOpts = {}): PopupFilter {\n const [state, dispatch] = useReducer(popupFilterReducer, INITIAL_FILTER_STATE);\n const { onEditingChange, enabled } = opts;\n const onKey = useCallback(\n (input: string, key: KeyFlags): \"consumed\" | \"passthrough\" => {\n const action = classifyFilterKey(state, input, key);\n if (action === null) return \"passthrough\";\n dispatch(action);\n return \"consumed\";\n },\n [state],\n );\n const startEdit = useCallback(() => dispatch({ kind: \"startEdit\" }), []);\n const reset = useCallback(() => dispatch({ kind: \"reset\" }), []);\n // Bubble the editing flag up to the parent (StatusBar uses it to\n // flip its hint cluster into popup-filter mode). No-op when the\n // caller doesn't pass a callback. When `enabled === false`, bubble\n // `false` regardless of state.editing so popups with multiple\n // filter instances can declaratively mark which one is active\n // (per review_tui_workspaces_two_filter_instances).\n const bubbledEditing = enabled === false ? false : state.editing;\n useEffect(() => {\n onEditingChange?.(bubbledEditing);\n }, [bubbledEditing, onEditingChange]);\n return { query: state.query, editing: state.editing, onKey, startEdit, reset };\n}\n\n/**\n * Apply a filter query to a list of items. Case-insensitive\n * substring on the per-item \"search blob\" string returned by\n * `blobOf`. Empty query → original list (identity).\n *\n * Pure; no React. New card popups call this directly:\n *\n * const filtered = applyFilter(source, flt.query, (e) => `${e.name} ${e.label}`);\n */\nexport function applyFilter<T>(\n items: readonly T[],\n query: string,\n blobOf: (item: T) => string,\n): T[] {\n if (query === \"\") return [...items];\n const q = query.toLowerCase();\n const out: T[] = [];\n for (const item of items) {\n if (blobOf(item).toLowerCase().includes(q)) out.push(item);\n }\n return out;\n}\n\n/** Body rows `<FilterPrompt>` occupies: its 1-row top margin plus the\n * prompt line while visible, 0 while idle. List popups subtract this\n * from their row viewport so the prompt never pushes the popup past\n * the pane (the App's overflow clip would eat the top border). */\nexport const FILTER_PROMPT_ROWS = 2;\n\nexport function filterPromptRows(state: Pick<PopupFilter, \"query\" | \"editing\">): number {\n return state.query === \"\" && !state.editing ? 0 : FILTER_PROMPT_ROWS;\n}\n\n/** Row viewport for a list that renders `<FilterPrompt state={flt} />`\n * below it. Never below 1 so the cursor row stays visible. */\nexport function listViewport(\n viewport: number,\n state: Pick<PopupFilter, \"query\" | \"editing\">,\n): number {\n return Math.max(1, viewport - filterPromptRows(state));\n}\n\n/**\n * Bottom-of-popup prompt. Renders nothing while idle (no query AND\n * not editing); renders `/<query>_` while editing; renders\n * `[filter] <query>` after Enter (committed). The trailing `_` is a\n * literal character used as a \"cursor\" — ink doesn't expose a real\n * text-input cursor without ink-text-input which we are NOT adding\n * (anti-feature pledge).\n */\nexport function FilterPrompt({ state }: { state: PopupFilter }): ReactElement | null {\n // Keep in sync with FILTER_PROMPT_ROWS (marginTop + one text row).\n if (filterPromptRows(state) === 0) return null;\n return (\n <Box marginTop={1}>\n <Text color={state.editing ? \"yellow\" : \"gray\"}>\n {state.editing ? \"/\" : \"[filter] \"}\n {state.query}\n {state.editing ? \"_\" : \"\"}\n </Text>\n </Box>\n );\n}\n","// Shared \"drill detail\" sub-view for popups. Renders a titled\n// scrollable block of pre-formatted text inside a popup body. Used\n// by:\n// - popups/agents.tsx → agent pane scrollback (mu agent read)\n// - popups/ready.tsx → task notes (mu task notes)\n// - popups/tracks.tsx → task list belonging to a track (already\n// a list, not a scrollback — uses ScrollList instead)\n//\n// The drill itself is read-only: it renders text, never executes\n// anything. j/k scroll one line; Ctrl-D / Ctrl-U scroll a viewport\n// half. Esc / q is the popup's responsibility (we only render).\n//\n// CHROME INSETS INTO THE BORDERS\n// (nit_tui_drill_inset_title_and_hints, Layer 2)\n//\n// Pre-Layer-2 the drill rendered its own title row (\"▸ {title}\n// (1-72/311)\") and an optional hint line as ORDINARY BODY ROWS\n// nested inside the popup Shell's rounded box — two rows of chrome\n// rendered as content. The drill now wraps the visible slice in a\n// `<TitledBox>` with magenta borders so:\n// - title + position indicator inset into the top border line\n// (`╭─ mu task notes <id> · 1-72/311 ───╮`)\n// - bottomLabel (drill-specific yank hint) insets into the bottom\n// border line (`╰─ y yanks `mu task notes <id>` ───────╯`)\n//\n// Magenta keeps the existing visual: cyan outer (popup Shell) +\n// magenta inner (drill chrome). Two nested coloured borders\n// distinguish nesting depth without doubled lines (TitledBox\n// renders single-row borders only).\n//\n// Per ROADMAP pledge: ink/react import limited to src/cli/tui/*.\n\nimport { Box, Text } from \"ink\";\nimport { type ReactElement, useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport { cellWidth, contentWidthFromCols, truncateCell } from \"../columns.js\";\nimport type { PopupAction } from \"../keys.js\";\nimport { useTerminalSize } from \"../use-terminal-size.js\";\nimport { wrapAndPadAnsiLines } from \"../wrap-ansi.js\";\nimport { applyScroll, clampScrollTop, isNavAction } from \"./scroll.js\";\n\nexport interface DrillKeymapOptions {\n /** Already-rendered text — split on \\n for scroll clamping. */\n body: string;\n /** Visible lines. Matches the DrillScrollView viewport. */\n viewport: number;\n /** Called for Esc/q. The hook resets scrollTop before invoking it. */\n onClose: () => void;\n /** Optional y action for this drill view. */\n onYank?: () => void | Promise<void>;\n /** Optional user-driven escape hatch for git-show drills. */\n onTuicr?: () => void | Promise<void>;\n /** Called after keyboard navigation computes and stores a new scroll top. */\n onScrollChange?: (newTop: number) => void;\n /**\n * Identity signal for scroll resets. Callers pass the focused row /\n * entity identity so auto-refreshes of the SAME drill preserve\n * scroll, while navigating to a DIFFERENT drill resets to the top.\n */\n resetKey: string | number;\n}\n\nexport interface WrappedDrillBody {\n wrapped: string;\n lines: readonly string[];\n totalLines: number;\n}\n\nexport interface DrillKeymap {\n scrollTop: number;\n dispatch: (action: PopupAction) => void;\n wrappedBody: WrappedDrillBody;\n wrappedLines: readonly string[];\n totalLines: number;\n}\n\nfunction useDrillWrapWidth(): number {\n const { cols } = useTerminalSize();\n return Math.max(0, contentWidthFromCols(cols) - 2);\n}\n\nexport function wrapDrillBody(body: string, wrapWidth: number): WrappedDrillBody {\n const wrapped = wrapAndPadAnsiLines(body, wrapWidth);\n const lines = wrapped === \"\" ? [] : wrapped.split(\"\\n\");\n return { wrapped, lines, totalLines: lines.length };\n}\n\nexport function useWrappedBody(body: string, wrapWidth: number): WrappedDrillBody {\n return useMemo(() => wrapDrillBody(body, wrapWidth), [body, wrapWidth]);\n}\n\n/**\n * Shared keymap for read-only DrillScrollView leaves. Centralises the\n * common drill skeleton: clamp scroll from the rendered body, Esc/q\n * backs out one level, y delegates to the caller's read-only yank.\n */\nexport function useDrillKeymap({\n body,\n viewport,\n onClose,\n onYank,\n onTuicr,\n onScrollChange,\n resetKey,\n}: DrillKeymapOptions): DrillKeymap {\n const [scrollTop, setScrollTopState] = useState(0);\n const scrollTopRef = useRef(0);\n const onScrollChangeRef = useRef(onScrollChange);\n onScrollChangeRef.current = onScrollChange;\n const updateScrollTop = useCallback(\n (update: number | ((current: number) => number), notify = false): number => {\n const nextTop = typeof update === \"function\" ? update(scrollTopRef.current) : update;\n scrollTopRef.current = nextTop;\n setScrollTopState(nextTop);\n if (notify) onScrollChangeRef.current?.(nextTop);\n return nextTop;\n },\n [],\n );\n const wrapWidth = useDrillWrapWidth();\n const wrappedBody = useWrappedBody(body, wrapWidth);\n const { totalLines } = wrappedBody;\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: resetKey is intentionally the reset trigger even though its value isn't read in the body.\n useEffect(() => {\n updateScrollTop(0);\n }, [resetKey, updateScrollTop]);\n\n useEffect(() => {\n updateScrollTop((s) => clampScrollTop(s, totalLines, viewport));\n }, [totalLines, updateScrollTop, viewport]);\n\n const dispatch = useCallback(\n (action: PopupAction) => {\n if (isNavAction(action)) {\n updateScrollTop((s) => applyScroll(s, action, totalLines, viewport), true);\n return;\n }\n switch (action.kind) {\n case \"close\":\n updateScrollTop(0);\n onClose();\n return;\n case \"yank\":\n void onYank?.();\n return;\n case \"verb\":\n if (action.key === \"t\") void onTuicr?.();\n return;\n default:\n return;\n }\n },\n [onClose, onTuicr, onYank, totalLines, updateScrollTop, viewport],\n );\n\n return {\n scrollTop,\n dispatch,\n wrappedBody,\n wrappedLines: wrappedBody.lines,\n totalLines,\n };\n}\n\nexport interface DrillScrollViewProps {\n title: string;\n /** Already-rendered text — split on \\n into lines. */\n body: string;\n /** Visible lines. Caller picks based on terminal height. */\n viewport: number;\n /** First visible line index (0-based; clamped by caller). */\n scrollTop: number;\n /** Optional dim hint rendered below the body (drill-specific\n * recipe, e.g. ``y yanks `mu task notes <id>` `` or\n * ``loading…``). The j/k/Esc/q nav cluster lives in the global\n * StatusBar (popup-mode hint), so we keep this label short —\n * single drill-specific verb hint. */\n hint?: string;\n /** Optional fallback rendered when the body is empty. */\n emptyText?: string;\n /** Already-wrapped body from useDrillKeymap; avoids wrapping twice. */\n wrappedBody?: WrappedDrillBody;\n}\n\n/**\n * Pure-render scrollable text view. Caller owns scroll state +\n * keyboard wiring; this component just paints the visible slice and\n * a dim \"L/T\" position indicator inset into the magenta top border.\n */\nexport function DrillScrollView({\n title,\n body,\n viewport,\n scrollTop,\n hint,\n emptyText,\n wrappedBody,\n}: DrillScrollViewProps): ReactElement {\n const wrapWidth = useDrillWrapWidth();\n const renderedBody = useMemo(\n () => wrappedBody ?? wrapDrillBody(body, wrapWidth),\n [body, wrapWidth, wrappedBody],\n );\n const lines = renderedBody.lines;\n const totalLines = renderedBody.totalLines;\n const start = Math.max(0, Math.min(Math.max(0, totalLines - viewport), scrollTop));\n const visible = lines.slice(start, start + viewport);\n const showFallback = totalLines === 0;\n const positionLabel = showFallback\n ? \"0/0\"\n : `${start + 1}-${Math.min(totalLines, start + viewport)}/${totalLines}`;\n const hasHint = hint !== undefined && hint !== \"\";\n const headerTitleWidth = Math.max(1, wrapWidth - cellWidth(positionLabel) - 3);\n const headerTitle = truncateCell(title, headerTitleWidth);\n const hintText = hasHint ? truncateCell(hint, wrapWidth) : undefined;\n\n // Drill body renders inline inside the popup's existing chrome\n // (cyan rounded border + paddingX). NO nested TitledBox here:\n // a second rounded box at width=stdout.columns overflows the\n // popup's inner content area by 4 cols (popup chrome) which made\n // long lines wrap / spill past the popup's right border. Single\n // border, single width budget.\n // (bug_tui_drill_text_no_width_pin — central fix replacing the\n // earlier per-line width pin.)\n //\n // Body lines have already been ANSI-aware pre-wrapped by visual\n // width and padded to exactly the drill width (`wrapAndPadAnsiLines`\n // via useDrillKeymap / wrapDrillBody). Keep every pre-wrapped logical\n // line on exactly one terminal row: Ink's truncate path can undercount\n // ANSI-coloured text and eat the popup's trailing space + right border\n // when it has to fit an over-budget line. Because drill body rows are\n // pre-sized to the exact budget, `wrap=\"truncate\"` is a no-op safety\n // belt rather than the fitting mechanism.\n return (\n <Box flexDirection=\"column\" flexGrow={1}>\n <Box>\n <Text bold color=\"magenta\" wrap=\"truncate\">\n {headerTitle}\n </Text>\n <Text dimColor wrap=\"truncate\">\n {` · ${positionLabel}`}\n </Text>\n </Box>\n <Box flexDirection=\"column\" flexGrow={1}>\n {showFallback ? (\n <Text dimColor wrap=\"truncate\">\n {emptyText ?? \"(empty)\"}\n </Text>\n ) : (\n visible.map((ln, i) => (\n // Index IS the identity here: this is a fixed scroll window over a\n // read-only line array, so a row's position is what it is. There is no\n // stable per-line id to key on and nothing reorders in place.\n // biome-ignore lint/suspicious/noArrayIndexKey: scroll-window position is the identity\n <Text key={`${start + i}`} wrap=\"truncate\">\n {ln === \"\" ? \" \" : ln}\n </Text>\n ))\n )}\n </Box>\n {hasHint ? (\n <Box>\n <Text dimColor wrap=\"truncate\">\n {hintText}\n </Text>\n </Box>\n ) : null}\n </Box>\n );\n}\n","// Per-render popup viewport sizing — fixes bug_tui_popup_data_doesnt_fill.\n//\n// Before this helper landed every popup hardcoded\n//\n// const VIEWPORT = 20;\n//\n// at module scope and used it for slice size, scroll-clamp, and\n// (in log.tsx) cursor-centring math. After bug_tui_popups_fill_pane\n// added flexGrow={1} + width={cols} so the popup Shell occupies\n// the full pane, the row data inside the Shell was still capped at\n// 20, leaving a band of empty space inside the popup border.\n//\n// The fix: each popup reads `useStdout().rows` at render time and\n// calls `popupViewport(rows[, chromeOverride])` to get the slice\n// size. The default `POPUP_CHROME_ROWS` budget (3) accounts for:\n//\n// - 2 rows: Shell rounded border (top + bottom)\n// - 1 row: the App's StatusBar below the popup (`rows` is the whole\n// terminal, and the popup branch shares it with the StatusBar)\n//\n// Title + per-popup hint cost no body rows: both inset into the top\n// and bottom border lines (nit_tui_drill_inset_title_and_hints).\n//\n// <FilterPrompt> is NOT in this budget: it is 2 rows only while a\n// filter is active, so list popups subtract it per render with\n// `listViewport(viewport, flt)` from use-popup-filter.tsx.\n//\n// Per-popup overrides: callers that render extra in-body chrome\n// (e.g. Workspaces drill's title + dim \"(L-T/T)\" indicator) pass\n// `chromeOverride`. The floor (`POPUP_VIEWPORT_FLOOR`) keeps very\n// small terminals usable at the cost of some hint clipping.\n//\n// `popupViewport(rows[, chromeOverride])` is a PURE helper (no ink,\n// no globals) so unit tests can assert the chrome math without\n// booting a render tree. The matching `usePopupViewport()` ink hook\n// (below) wraps it so every popup is one line:\n//\n// const viewport = usePopupViewport();\n//\n// instead of the boilerplate trio of `useStdout`, `stdout?.rows ??\n// 24`, and a `popupViewport(...)` call. Both ship from the same\n// module because the hook IS the centralisation seam — splitting\n// them would just make every popup import twice.\n//\n// Per ROADMAP pledge: ink/react import limited to src/cli/tui/*.\n// This module is in src/cli/tui/popups/, so the hook's `useStdout`\n// import is in-bounds.\n\nimport { useTerminalSize } from \"../use-terminal-size.js\";\n\n/** Default rows outside the popup body: the Shell's top + bottom\n * border rows and the App StatusBar. Subtracted from `stdout.rows`\n * to get the body slice budget. */\nexport const POPUP_CHROME_ROWS = 3;\n\n/** Rows a `<DrillScrollView>` renders around its scroll window: the\n * magenta title line above and the hint line below. */\nexport const DRILL_VIEW_CHROME_ROWS = 2;\n\n/** Chrome budget for a popup whose body is one `<DrillScrollView>`.\n * Pass it to `usePopupViewport` for drill bodies so the title and\n * hint lines do not push the popup's borders out of the pane. */\nexport const POPUP_DRILL_CHROME_ROWS = POPUP_CHROME_ROWS + DRILL_VIEW_CHROME_ROWS;\n\n/** Minimum body rows. Keeps very-small terminals usable: at 12\n * rows we'd otherwise compute 6 → users couldn't see the cursor. */\nexport const POPUP_VIEWPORT_FLOOR = 8;\n\n/**\n * Compute how many body rows the popup may render given the current\n * terminal height. Pure: no ink, no globals — pass `rows` from\n * `useStdout().stdout?.rows ?? 24` at render time. The optional\n * `chromeOverride` lets popups with extra in-body chrome (e.g.\n * Workspaces drill renders an additional title + indicator pair)\n * subtract more than the default budget.\n *\n * @param rows total terminal rows (NOT popup rows — caller passes\n * `stdout.rows` directly; we own the chrome subtraction)\n * @param chromeOverride override for `POPUP_CHROME_ROWS` (default 3)\n */\nexport function popupViewport(rows: number, chromeOverride?: number): number {\n const chrome = chromeOverride ?? POPUP_CHROME_ROWS;\n return Math.max(POPUP_VIEWPORT_FLOOR, rows - chrome);\n}\n\n/**\n * Ink hook: returns the popup body viewport for the current render.\n * Wraps `useStdout()` + the `stdout?.rows ?? 24` fallback + the\n * `popupViewport()` chrome math so every popup is one line:\n *\n * const viewport = usePopupViewport();\n *\n * Pass `chromeOverride` when the popup renders extra in-body chrome\n * (e.g. Workspaces drill's title + indicator pair); otherwise the\n * default `POPUP_CHROME_ROWS` budget applies.\n *\n * Replaces the prior per-popup boilerplate AND fixes the\n * inprogress + recent drill regression where a stale module-scope\n * `const VIEWPORT = 20` was clipping notes below the popup's full\n * pane height (bug_tui_inprogress_recent_drill_viewport_clipped).\n */\nexport function usePopupViewport(chromeOverride?: number): number {\n const { rows } = useTerminalSize();\n return popupViewport(rows, chromeOverride);\n}\n","// All-tasks popup (`t`). Keybind-only; no dashboard card slot.\n//\n// Read-only list/sort complement to the DAG popup: every task in the\n// active workstream, filtered by task status (o/i/c) and substate\n// slice (p parked, w closed-not-done), sorted by\n// `s` through the same sort keys as `mu task list --sort`, Enter drills\n// into TaskDetailDrill, and `y` yanks `mu task show <id>`.\n\nimport { Box, Text } from \"ink\";\nimport { type ReactElement, useMemo, useState } from \"react\";\nimport type { Db } from \"../../../db.js\";\nimport { GLYPH } from \"../../../glyphs.js\";\nimport type { WorkstreamSnapshot } from \"../../../state.js\";\nimport {\n relTimeBasisForSort,\n sortTasks,\n TASK_SORT_KEYS,\n type TaskSortKey,\n} from \"../../../tasks/sort.js\";\nimport { formatPair } from \"../../../tasks/status.js\";\nimport { listTasks, type TaskRow } from \"../../../tasks.js\";\nimport { inkColorForPair } from \"../../format.js\";\nimport { agentByName, formatTaskOwnerDisplay } from \"../agent-display.js\";\nimport { type ColumnSpec, contentWidthFromCols, layoutColumns, renderRow } from \"../columns.js\";\nimport { formatRoi } from \"../format-helpers.js\";\nimport { dispatchPopupKeyFromInk, type PopupAction, type PopupActionEnvelope } from \"../keys.js\";\nimport { ListRow } from \"../list-row.js\";\nimport { usePopupInput } from \"../popup-input.js\";\nimport { PopupShell } from \"../popup-shell.js\";\nimport { useNotesDrill } from \"../use-notes-drill.js\";\nimport { usePopupActionQueue } from \"../use-popup-action-queue.js\";\nimport { applyFilter, FilterPrompt, listViewport, usePopupFilter } from \"../use-popup-filter.js\";\nimport { passesFilter, StatusFilterStrip, useStatusFilter } from \"../use-status-filter.js\";\nimport { useTerminalSize } from \"../use-terminal-size.js\";\nimport { useDrillKeymap } from \"./drill.js\";\nimport { applyCursor, centredVisibleSlice, clickedItem, isNavAction } from \"./scroll.js\";\nimport { TaskDetailDrill } from \"./task-detail.js\";\nimport { POPUP_CHROME_ROWS, usePopupViewport } from \"./viewport.js\";\n\nexport interface PopupProps {\n yank: (command: string) => Promise<void>;\n onClose: () => void;\n snapshot: WorkstreamSnapshot | null;\n fastTickNonce: number;\n mode: \"list\" | \"drill\";\n onModeChange: (mode: \"list\" | \"drill\") => void;\n onFilterEditingChange?: (editing: boolean) => void;\n popupActions?: readonly PopupActionEnvelope[];\n db: Db;\n workstream: string;\n}\n\nconst COLUMN_SPECS: ReadonlyArray<ColumnSpec> = [\n { kind: \"protect\" }, // task id\n { kind: \"protect\" }, // status + blocked glyph\n { kind: \"protect\" }, // owner\n { kind: \"protect\", align: \"right\" }, // ROI\n { kind: \"clip\", min: 1 }, // title\n];\n\n// The list view renders three in-body strip rows above the data\n// window: StatusFilterStrip, BlockedFilterStrip, SortStrip. Account\n// for those through the central viewport hook's chrome override so\n// the popup's top border does not get clipped on shorter panes.\nconst ALL_TASKS_STRIP_ROWS = 3;\nconst ALL_TASKS_CHROME_ROWS = POPUP_CHROME_ROWS + ALL_TASKS_STRIP_ROWS;\n\nexport function AllTasksPopup({\n yank,\n onClose,\n snapshot,\n fastTickNonce,\n mode,\n onModeChange,\n onFilterEditingChange,\n popupActions,\n db,\n workstream,\n}: PopupProps): ReactElement {\n const { cols } = useTerminalSize();\n const contentWidth = contentWidthFromCols(cols);\n const viewport = usePopupViewport(ALL_TASKS_CHROME_ROWS);\n const [cursor, setCursor] = useState(0);\n const [sortKey, setSortKey] = useState<TaskSortKey>(\"roi\");\n const flt = usePopupFilter({ onEditingChange: onFilterEditingChange });\n const rowsViewport = listViewport(viewport, flt);\n const statusFilter = useStatusFilter();\n const { statuses, showParked, showNotDone } = statusFilter;\n const filterStrip = (\n <StatusFilterStrip statuses={statuses} showParked={showParked} showNotDone={showNotDone} />\n );\n\n const sourceTasks = useMemo(\n () => allTasksFromSnapshotOrDb(snapshot, db, workstream),\n [snapshot, db, workstream],\n );\n const blockedNames = useMemo(\n () => new Set((snapshot?.blocked ?? []).map((t) => t.name)),\n [snapshot?.blocked],\n );\n const [blockedFilter, setBlockedFilter] = useState<BlockedFilterMode>(\"all\");\n // Per bug_filter_drill_opens_wrong_task: text filter applied\n // UNIFORMLY across list and drill modes. The previous\n // mode-conditional dropped the filter on drill, which shifted\n // visibleTasks under a constant cursor index and resolved the\n // wrong task. mode dep removed.\n const visibleTasks = useMemo(() => {\n const filteredByStatus = sourceTasks.filter((t) =>\n passesFilter(t, { statuses, showParked, showNotDone }),\n );\n const filteredByBlocked = applyBlockedFilter(filteredByStatus, blockedNames, blockedFilter);\n const filteredByText = applyFilter(\n filteredByBlocked,\n flt.query,\n (t) => `${t.name} ${t.title} ${formatPair(t)} ${t.ownerName ?? \"\"}`,\n );\n return sortTasks(filteredByText, sortKey);\n }, [\n sourceTasks,\n statuses,\n showParked,\n showNotDone,\n blockedFilter,\n blockedNames,\n flt.query,\n sortKey,\n ]);\n const safeCursor = visibleTasks.length === 0 ? 0 : Math.min(cursor, visibleTasks.length - 1);\n const focused = visibleTasks[safeCursor];\n\n // Defensive: capture the focused task identity at the moment the\n // user pressed Enter, so even if visibleTasks shifts underneath us\n // (a future refactor re-introduces a mode-dep, snapshot tick lands\n // a new row, etc.) the drill stays pinned to the row the user\n // visually selected. Cleared on close.\n const [drilledTask, setDrilledTask] = useState<TaskRow | null>(null);\n const drillTask = mode === \"drill\" ? (drilledTask ?? focused) : focused;\n\n const notesText = useNotesDrill({\n mode,\n focused: drillTask,\n db,\n workstream,\n fastTickNonce,\n });\n\n const drill = useDrillKeymap({\n body: notesText,\n viewport,\n onClose: () => {\n setDrilledTask(null);\n onModeChange(\"list\");\n },\n onYank: () => {\n if (!drillTask) return;\n return yank(allTasksYankCommand(drillTask.name, workstream));\n },\n resetKey: drillTask?.name ?? \"\",\n });\n\n const dispatchListAction = (action: PopupAction) => {\n if (mode === \"drill\") {\n drill.dispatch(action);\n return;\n }\n if (isNavAction(action)) {\n setCursor((c) => applyCursor(c, action, visibleTasks.length, rowsViewport));\n return;\n }\n switch (action.kind) {\n case \"close\":\n onClose();\n return;\n case \"filter\":\n flt.startEdit();\n return;\n case \"drill\":\n if (focused) {\n setDrilledTask(focused);\n onModeChange(\"drill\");\n }\n return;\n case \"clickRow\": {\n const hit = clickedItem(\n visibleTasks,\n safeCursor,\n rowsViewport,\n action.row,\n ALL_TASKS_STRIP_ROWS,\n );\n if (!hit) return;\n setCursor(hit.index);\n setDrilledTask(hit.item);\n onModeChange(\"drill\");\n return;\n }\n case \"yank\":\n if (focused) void yank(allTasksYankCommand(focused.name, workstream));\n return;\n case \"verb\":\n if (action.key === \"s\") setSortKey(nextTaskSortKey);\n return;\n }\n };\n\n usePopupActionQueue(popupActions, dispatchListAction);\n\n usePopupInput((input, key) => {\n if (mode !== \"drill\" && flt.onKey(input, key) === \"consumed\") return;\n if (mode !== \"drill\" && statusFilter.onKey(input, key)) return;\n // b toggles blocked filter — intercept before generic popup dispatch\n if (mode !== \"drill\" && !key.ctrl && !key.meta && input === \"b\") {\n setBlockedFilter(nextBlockedFilter);\n return;\n }\n dispatchListAction(dispatchPopupKeyFromInk(input, key));\n });\n\n if (snapshot === null) {\n return <PopupShell title=\"All tasks · popup\">{<Text dimColor>loading…</Text>}</PopupShell>;\n }\n\n if (sourceTasks.length === 0) {\n return (\n <PopupShell title=\"All tasks · popup\">\n <Box flexDirection=\"column\" flexGrow={1}>\n {filterStrip}\n <BlockedFilterStrip mode={blockedFilter} />\n <SortStrip sortKey={sortKey} visible={0} total={0} />\n <Text dimColor>(no tasks)</Text>\n </Box>\n </PopupShell>\n );\n }\n\n if (visibleTasks.length === 0) {\n return (\n <PopupShell title=\"All tasks · popup\">\n <Box flexDirection=\"column\" flexGrow={1}>\n {filterStrip}\n <BlockedFilterStrip mode={blockedFilter} />\n <SortStrip sortKey={sortKey} visible={0} total={sourceTasks.length} />\n <Text dimColor>\n {flt.query === \"\"\n ? \"(no tasks match status filter)\"\n : `(no matches for \"${flt.query}\")`}\n </Text>\n </Box>\n <FilterPrompt state={flt} />\n </PopupShell>\n );\n }\n\n if (mode === \"drill\" && drillTask) {\n return (\n <PopupShell title={`All tasks · ${drillTask.name} (notes)`}>\n <Box flexDirection=\"column\" flexGrow={1}>\n <TaskDetailDrill\n task={drillTask}\n db={db}\n workstream={workstream}\n scrollTop={drill.scrollTop}\n viewport={viewport}\n tickNonce={fastTickNonce}\n body={notesText}\n wrappedBody={drill.wrappedBody}\n />\n </Box>\n </PopupShell>\n );\n }\n\n const { start, visible: windowed } = centredVisibleSlice(visibleTasks, safeCursor, rowsViewport);\n const agentLookup = agentByName(snapshot);\n const rows = windowed.map((t) => [\n t.name,\n statusCell(t, blockedNames.has(t.name)),\n formatTaskOwnerDisplay(t, agentLookup),\n formatRoi(t.impact, t.effortDays),\n t.title,\n ]);\n const widths = layoutColumns(rows, COLUMN_SPECS, contentWidth);\n\n return (\n <PopupShell\n title={allTasksListTitle(safeCursor, visibleTasks.length, rowsViewport)}\n hint={focused ? allTasksYankCommand(focused.name, workstream) : undefined}\n >\n <Box flexDirection=\"column\" flexGrow={1}>\n {filterStrip}\n <BlockedFilterStrip mode={blockedFilter} />\n <SortStrip sortKey={sortKey} visible={visibleTasks.length} total={sourceTasks.length} />\n {windowed.map((t, i) => {\n const row = rows[i];\n if (row === undefined) return null;\n const padded = renderRow(row, widths, COLUMN_SPECS);\n const isBlocked = blockedNames.has(t.name);\n const colors = [\n { bold: true }, // id\n { color: isBlocked ? \"yellow\" : inkColorForPair(t) }, // status + blocked glyph\n { dimColor: true }, // owner\n { dimColor: true }, // ROI\n undefined, // title\n ];\n return (\n <ListRow\n key={t.name}\n cells={padded}\n contentWidth={contentWidth}\n colors={colors}\n selected={start + i === safeCursor}\n />\n );\n })}\n </Box>\n <FilterPrompt state={flt} />\n </PopupShell>\n );\n}\n\n/** Status cell: the pair, prefixed by the parked glyph for a parked\n * row and suffixed by the blocked glyph for a blocked one. */\nfunction statusCell(t: TaskRow, blocked: boolean): string {\n const pair = formatPair(t);\n const parked = t.status === \"OPEN\" && t.substate === \"parked\" ? `${GLYPH.parked} ` : \"\";\n return `${parked}${pair}${blocked ? ` ${GLYPH.blocked}` : \"\"}`;\n}\n\nexport function allTasksFromSnapshotOrDb(\n snapshot: WorkstreamSnapshot | null,\n db: Db,\n workstream: string,\n): TaskRow[] {\n if (snapshot?.allTasks && snapshot.allTasks.length > 0) return snapshot.allTasks;\n return listTasks(db, workstream);\n}\n\nexport function allTasksYankCommand(taskId: string, workstream: string): string {\n return `mu task show ${taskId} -w ${workstream}`;\n}\n\nexport function nextTaskSortKey(current: TaskSortKey): TaskSortKey {\n const i = TASK_SORT_KEYS.indexOf(current);\n return TASK_SORT_KEYS[(i + 1) % TASK_SORT_KEYS.length] ?? \"roi\";\n}\n\nexport function sortIndicator(sortKey: TaskSortKey): string {\n const basis = relTimeBasisForSort(sortKey);\n const detail = basis === null ? \"\" : basis === \"updatedAt\" ? \" updated\" : \" created\";\n return `sort: [s]ort=${sortKey} ↓${detail}`;\n}\n\nexport function allTasksScrollPercent(\n cursor: number,\n total: number,\n viewport: number,\n): number | null {\n if (total <= viewport) return null;\n return Math.round((cursor / Math.max(1, total - 1)) * 100);\n}\n\nexport function allTasksListTitle(cursor: number, total: number, viewport: number): string {\n const percent = allTasksScrollPercent(cursor, total, viewport);\n const indicator = percent === null ? \"\" : ` · ${percent}%`;\n return `All tasks · popup (${cursor + 1}/${total})${indicator}`;\n}\n\nfunction SortStrip({\n sortKey,\n visible,\n total,\n}: {\n sortKey: TaskSortKey;\n visible: number;\n total: number;\n}): ReactElement {\n return (\n <Box>\n <Text dimColor>\n {sortIndicator(sortKey)} (filter: {visible} of {total})\n </Text>\n </Box>\n );\n}\n\n// ─── Blocked filter ───────────────────────────────────────────────\n\nexport type BlockedFilterMode = \"all\" | \"only\" | \"hide\";\n\nexport function nextBlockedFilter(current: BlockedFilterMode): BlockedFilterMode {\n switch (current) {\n case \"all\":\n return \"only\";\n case \"only\":\n return \"hide\";\n case \"hide\":\n return \"all\";\n }\n}\n\nexport function applyBlockedFilter<T extends { name: string }>(\n tasks: T[],\n blockedNames: ReadonlySet<string>,\n mode: BlockedFilterMode,\n): T[] {\n switch (mode) {\n case \"all\":\n return tasks;\n case \"only\":\n return tasks.filter((t) => blockedNames.has(t.name));\n case \"hide\":\n return tasks.filter((t) => !blockedNames.has(t.name));\n }\n}\n\nconst BLOCKED_FILTER_LABELS: Readonly<Record<BlockedFilterMode, string>> = {\n all: \"all\",\n only: \"only blocked\",\n hide: \"hide blocked\",\n};\n\nfunction BlockedFilterStrip({ mode }: { mode: BlockedFilterMode }): ReactElement {\n return (\n <Box>\n <Text dimColor>\n [<Text bold>b</Text>]locked: {BLOCKED_FILTER_LABELS[mode]}\n {mode === \"all\" ? \"\" : ` ${GLYPH.on}`}\n </Text>\n </Box>\n );\n}\n","// Shared notes-drill memo for task-list popups (Tasks/ready,\n// In-progress, Blocked, Recent, All-tasks). Pre-refactor each popup\n// shipped a byte-identical useMemo block that SELECTed task notes\n// only when the popup was in drill mode and a row was focused. The\n// block existed only because `useDrillKeymap` needs the rendered\n// body string to clamp scroll. See task\n// review_tui_task_popups_duplicated_template (workstream `tui-impl`).\n\nimport { useMemo } from \"react\";\nimport type { Db } from \"../../db.js\";\nimport type { TaskRow } from \"../../tasks.js\";\nimport { renderNotes } from \"./popups/task-detail.js\";\n\nexport interface UseNotesDrillOptions {\n mode: \"list\" | \"drill\";\n focused: TaskRow | undefined;\n db: Db;\n workstream: string;\n /** Refresh signal for SQL-backed bodies (the fast TUI tick). */\n fastTickNonce: number;\n}\n\n/** Returns \"\" until mode === \"drill\" + focused, otherwise renderNotes(...).\n * fastTickNonce sits in the memo deps so the body refreshes on each\n * fast tick while the drill stays open during a worker session. */\nexport function useNotesDrill(opts: UseNotesDrillOptions): string {\n const { mode, focused, db, workstream, fastTickNonce } = opts;\n return useMemo<string>(() => {\n void fastTickNonce;\n if (mode !== \"drill\" || !focused) return \"\";\n return renderNotes(db, focused.name, workstream);\n }, [mode, focused, db, workstream, fastTickNonce]);\n}\n","// Shared \"task detail\" leaf — read-only inline rendering of a\n// task's notes timeline. The leaf of the popup-drill recursion\n// (per feat_track_drill_chains_to_task_drill).\n//\n// Today's consumers:\n// - popups/ready.tsx → Tasks popup drill (Enter on a task row)\n// - popups/tracks.tsx → Tracks popup drill → drill row Enter\n//\n// Future consumers (when promoted): any popup whose drill is\n// itself a list of tasks (Card 6 in-progress, Card 7 blocked,\n// Card 8 recent — see feat_more_cards_umbrella). Each gets the\n// chain into this leaf \"for free\" by importing TaskDetailDrill.\n//\n// Pure presentation — the parent owns the scroll cursor (so each\n// recursion level has its own scroll state) and the keyboard.\n// This module never executes mutations; listNotes is a SQLite\n// SELECT.\n//\n// Per ROADMAP pledge: ink/react import limited to src/cli/tui/*.\n\nimport { type ReactElement, useMemo } from \"react\";\nimport type { Db } from \"../../../db.js\";\nimport { listNotes, type TaskRow } from \"../../../tasks.js\";\nimport { DrillScrollView, type WrappedDrillBody } from \"./drill.js\";\n\nexport type RenderNotesFn = (db: Db, taskId: string, workstream: string) => string;\n\nconst ANSI_BOLD_CYAN = \"\\x1b[1;36m\";\nconst ANSI_RESET = \"\\x1b[0m\";\n\nexport interface TaskDetailDrillProps {\n task: TaskRow;\n db: Db;\n workstream: string;\n /** First visible line index — owned by parent for per-level scroll. */\n scrollTop: number;\n /** Visible lines; caller picks based on terminal height. */\n viewport: number;\n /** Refresh signal for SQL-backed note bodies. */\n tickNonce: number;\n /** Already-rendered body shared with useDrillKeymap. */\n body?: string;\n /** Injection seam for behaviour tests; production uses renderNotes. */\n renderNotesFn?: RenderNotesFn;\n /** Already-wrapped body from useDrillKeymap; avoids wrapping twice. */\n wrappedBody?: WrappedDrillBody;\n}\n\n/**\n * Render a task's notes timeline. Returns a column of:\n * <DrillScrollView title=\"mu task notes <id>\" body=<rendered>… />\n *\n * Empty notes → DrillScrollView's emptyText fallback fires.\n */\nexport function TaskDetailDrill({\n task,\n db,\n workstream,\n scrollTop,\n viewport,\n tickNonce,\n body,\n renderNotesFn = renderNotes,\n wrappedBody,\n}: TaskDetailDrillProps): ReactElement {\n const renderedBody = useMemo<string>(() => {\n if (body !== undefined) return body;\n void tickNonce;\n return renderNotesFn(db, task.name, workstream);\n }, [body, db, task, workstream, tickNonce, renderNotesFn]);\n return (\n <DrillScrollView\n title={`mu task notes ${task.name}`}\n body={renderedBody}\n viewport={viewport}\n scrollTop={scrollTop}\n wrappedBody={wrappedBody}\n emptyText=\"(no notes)\"\n hint={`y yanks \\`mu task notes ${task.name}\\``}\n />\n );\n}\n\n/**\n * Pure helper: SELECTs notes via listNotes and formats them as the\n * same `── <ts> <author> ──\\n<content>` blocks the Tasks popup\n * drill rendered inline before this refactor. Exported so tests can\n * assert the exact format without booting ink.\n */\nexport function renderNotes(db: Db, taskId: string, workstream: string): string {\n const notes = listNotes(db, taskId, workstream);\n if (notes.length === 0) return \"\";\n return notes\n .map((n) => {\n const ts = n.createdAt.replace(\"T\", \" \").slice(0, 19);\n const author = n.author ?? \"?\";\n return `${ANSI_BOLD_CYAN}── ${ts} ${author} ──${ANSI_RESET}\\n${n.content}`;\n })\n .join(\"\\n\\n\");\n}\n","// Shared task-status toggle filter for TUI task-list surfaces.\n//\n// Used by the DAG and all-tasks popups. o/i/c toggle a status; p and w\n// toggle two substate slices (OPEN/parked, CLOSED-but-not-done).\n// Default is everything visible; state is deliberately local to\n// the popup instance and resets on unmount (no persistence / no config).\n//\n// Per ROADMAP pledge: ink/react imports are confined to src/cli/tui/*.\n\nimport { Box, Text } from \"ink\";\nimport { type ReactElement, useCallback, useState } from \"react\";\nimport { GLYPH } from \"../../glyphs.js\";\nimport { TASK_STATUSES, type TaskPair, type TaskStatus } from \"../../tasks/status.js\";\nimport { colorStatus } from \"../format.js\";\nimport type { KeyFlags } from \"./keys.js\";\n\nexport const STATUS_BY_KEY: Readonly<Record<string, TaskStatus>> = {\n o: \"OPEN\",\n i: \"IN_PROGRESS\",\n c: \"CLOSED\",\n};\n\nconst STATUS_LABELS: Readonly<Record<TaskStatus, { key: string; rest: string }>> = {\n OPEN: { key: \"O\", rest: \"pen\" },\n IN_PROGRESS: { key: \"I\", rest: \"n_progress\" },\n CLOSED: { key: \"C\", rest: \"losed\" },\n};\n\nexport function toggleStatusSet(\n statuses: ReadonlySet<TaskStatus>,\n status: TaskStatus,\n): Set<TaskStatus> {\n const next = new Set(statuses);\n if (next.has(status)) {\n next.delete(status);\n } else {\n next.add(status);\n }\n return next;\n}\n\nexport function statusForToggleKey(input: string, key: KeyFlags): TaskStatus | undefined {\n if (key.ctrl === true || key.meta === true) return undefined;\n return STATUS_BY_KEY[input.toLowerCase()];\n}\n\n/** The two substate slices with their own toggle: `p` OPEN/parked,\n * `w` CLOSED rows whose substate is not done (rejected, wontfix, ...). */\nexport type SubstateToggle = \"parked\" | \"notDone\";\n\nconst SUBSTATE_BY_KEY: Readonly<Record<string, SubstateToggle>> = { p: \"parked\", w: \"notDone\" };\n\nexport function substateToggleForKey(input: string, key: KeyFlags): SubstateToggle | undefined {\n if (key.ctrl === true || key.meta === true) return undefined;\n return SUBSTATE_BY_KEY[input.toLowerCase()];\n}\n\nexport interface FilterState {\n statuses: ReadonlySet<TaskStatus>;\n showParked: boolean;\n showNotDone: boolean;\n}\n\n/** True when a task survives every toggle: its status is enabled and\n * neither substate slice it belongs to is hidden. */\nexport function passesFilter(t: TaskPair, f: FilterState): boolean {\n if (!f.statuses.has(t.status)) return false;\n if (!f.showParked && t.status === \"OPEN\" && t.substate === \"parked\") return false;\n if (!f.showNotDone && t.status === \"CLOSED\" && t.substate !== \"done\") return false;\n return true;\n}\n\nexport interface StatusFilter extends FilterState {\n statuses: Set<TaskStatus>;\n toggle: (s: TaskStatus) => void;\n /** Returns true when an o/i/c/p/w toggle key was consumed. */\n onKey: (input: string, key: KeyFlags) => boolean;\n}\n\nexport function useStatusFilter(): StatusFilter {\n const [statuses, setStatuses] = useState<Set<TaskStatus>>(() => new Set(TASK_STATUSES));\n const [showParked, setShowParked] = useState(true);\n const [showNotDone, setShowNotDone] = useState(true);\n\n const toggle = useCallback((status: TaskStatus) => {\n setStatuses((prev) => toggleStatusSet(prev, status));\n }, []);\n\n const onKey = useCallback(\n (input: string, key: KeyFlags): boolean => {\n const status = statusForToggleKey(input, key);\n if (status !== undefined) {\n toggle(status);\n return true;\n }\n const sub = substateToggleForKey(input, key);\n if (sub === \"parked\") setShowParked((v) => !v);\n else if (sub === \"notDone\") setShowNotDone((v) => !v);\n return sub !== undefined;\n },\n [toggle],\n );\n\n return { statuses, showParked, showNotDone, toggle, onKey };\n}\n\nconst SUBSTATE_LABELS: ReadonlyArray<{\n id: SubstateToggle;\n key: string;\n rest: string;\n color: \"gray\" | \"red\";\n}> = [\n { id: \"parked\", key: \"P\", rest: \"arked\", color: \"gray\" },\n // Covers every non-done close (rejected, wontfix, duplicate, superseded).\n { id: \"notDone\", key: \"W\", rest: \"on't do\", color: \"red\" },\n];\n\nexport function StatusFilterStrip({\n statuses,\n showParked = true,\n showNotDone = true,\n}: {\n statuses: ReadonlySet<TaskStatus>;\n showParked?: boolean;\n showNotDone?: boolean;\n}): ReactElement {\n const substateOn: Record<SubstateToggle, boolean> = {\n parked: showParked,\n notDone: showNotDone,\n };\n return (\n <Box>\n <Text dimColor>filters: </Text>\n {TASK_STATUSES.map((status, i) => {\n const label = STATUS_LABELS[status];\n const enabled = statuses.has(status);\n return (\n <Text key={status}>\n {i > 0 ? \" \" : \"\"}\n <Text>{\"[\"}</Text>\n <Text>{colorStatus(status).replace(status, label.key)}</Text>\n <Text>{\"]\"}</Text>\n <Text>{label.rest}</Text>\n <Text> </Text>\n <Text color={enabled ? \"green\" : \"gray\"}>{enabled ? GLYPH.on : GLYPH.off}</Text>\n </Text>\n );\n })}\n {SUBSTATE_LABELS.map((label, i) => {\n const enabled = substateOn[label.id];\n return (\n <Text key={label.id}>\n {i === 0 ? \" \" : \" \"}\n <Text>{\"[\"}</Text>\n <Text color={label.color}>{label.key}</Text>\n <Text>{\"]\"}</Text>\n <Text>{label.rest}</Text>\n <Text> </Text>\n <Text color={enabled ? \"green\" : \"gray\"}>{enabled ? GLYPH.on : GLYPH.off}</Text>\n </Text>\n );\n })}\n </Box>\n );\n}\n","// Blocked popup (Shift+7 → `&`). The drill-down for the Blocked\n// card.\n//\n// Per feat_popup_7_blocked (workstream `tui-impl`): list of every\n// blocked task (OPEN with at least one still-gating blocker) with\n// j/k navigation, '/' filter (via use-popup-filter), and Enter to\n// drill into the standard TaskDetailDrill leaf — rows ARE tasks so\n// the popup-drill recursion contract applies for free\n// (feat_track_drill_chains_to_task_drill).\n//\n// Sibling of the task-list popup family (ready/inprogress/recent),\n// all of which share the TaskListPopup scaffold\n// (popups/task-list-popup.tsx). The Blocked config differs in three\n// ways:\n//\n// 1. Source rows are `snapshot.blocked` (the OPEN-with-unsatisfied-\n// blockers slice).\n// 2. The list view exposes the Card 7 layout — glyph + id + STATUS\n// + #blockers + top-blocker + ROI + title — and reads per-row\n// blockers via getTaskEdgesWithStatus (memoised so '/'-filter\n// typing doesn't re-do the SQLite reads on every keystroke).\n// 3. Yank → `mu task tree <id> -w <ws>`. The blocked-task popup's\n// most-actionable diagnostic question is \"what's blocking\n// this?\" and `mu task tree` walks the prerequisite subgraph in\n// one shot. Drill-mode yank → `mu task notes <id>` (shared).\n//\n// Per ROADMAP pledge: ink/react import limited to src/cli/tui/*.\n\nimport { type ReactElement, useMemo } from \"react\";\nimport { roiBucket, type WorkstreamSnapshot } from \"../../../state.js\";\nimport { formatPair } from \"../../../tasks/status.js\";\nimport { getTaskEdgesWithStatus } from \"../../../tasks.js\";\nimport { inkColorForPair } from \"../../format.js\";\nimport { blockerLabel, GLYPH, stillGating } from \"../cards/blocked.js\";\nimport type { ColumnSpec } from \"../columns.js\";\nimport { colorForBucket, formatRoi } from \"../format-helpers.js\";\nimport {\n type PopupProps,\n type RenderedRow,\n TaskListPopup,\n type TaskListPopupConfig,\n} from \"./task-list-popup.js\";\n\nconst COLUMN_SPECS: ReadonlyArray<ColumnSpec> = [\n { kind: \"protect\" }, // glyph\n { kind: \"protect\" }, // task id\n { kind: \"protect\" }, // status (always OPEN; constant for now)\n { kind: \"protect\", align: \"right\" }, // #blockers\n { kind: \"protect\" }, // top-blocker id (or \"—\")\n { kind: \"protect\", align: \"right\" }, // ROI\n { kind: \"clip\", min: 1 }, // title\n];\n\nexport function BlockedPopup(props: PopupProps): ReactElement {\n const { snapshot, db, workstream } = props;\n const sourceTasks = snapshot?.blocked ?? [];\n\n // Per-row blocker lookup. Memoised so '/'-filter typing doesn't\n // re-do the SQLite reads on every keystroke. Same shape as the\n // Card 7 read path: one getTaskEdgesWithStatus per source row,\n // filtered to still-gating. Indexed by task `name`.\n const blockerIndex = useMemo<Map<string, string[]>>(() => {\n const m = new Map<string, string[]>();\n for (const t of sourceTasks) {\n const gating = stillGating(getTaskEdgesWithStatus(db, t.name, workstream).blockers);\n m.set(t.name, gating.map(blockerLabel));\n }\n return m;\n }, [sourceTasks, db, workstream]);\n\n const config = useMemo<TaskListPopupConfig>(\n () => ({\n label: \"Blocked\",\n sourceTasks: (snap: WorkstreamSnapshot) => snap.blocked,\n columnSpecs: COLUMN_SPECS,\n filterBlob: (t) => {\n const blockers = blockerIndex.get(t.name) ?? [];\n return `${t.name} ${t.title} ${blockers.join(\" \")}`;\n },\n emptyText: \"(no blocked tasks — every OPEN task is ready)\",\n // Per the task spec KEY MAP block: most useful diagnostic is\n // `mu task tree <id>` — \"show me what's blocking this\".\n yankCommand: (t, ws) => `mu task tree ${t.name} -w ${ws}`,\n renderRows: (visible): RenderedRow[] =>\n visible.map((t) => {\n const blockers = blockerIndex.get(t.name) ?? [];\n const top = blockers[0] ?? \"—\";\n const bucket = roiBucket(t.impact, t.effortDays);\n return {\n cells: [\n GLYPH,\n t.name,\n formatPair(t),\n String(blockers.length),\n top,\n formatRoi(t.impact, t.effortDays),\n t.title,\n ],\n colors: [\n { dimColor: true }, // glyph\n { bold: true }, // name\n { color: inkColorForPair(t) }, // status\n { color: \"yellow\" }, // nblock\n { dimColor: true }, // top\n { color: colorForBucket(bucket) }, // roi\n undefined, // title\n ],\n };\n }),\n }),\n [blockerIndex],\n );\n\n return <TaskListPopup config={config} {...props} />;\n}\n","// Shared task-list popup scaffold.\n//\n// Per finding_4_task_list_popups_duplicate: ready.tsx, inprogress.tsx,\n// recent.tsx, and blocked.tsx all duplicated ~120 LOC of identical\n// coordination logic — usePopupFilter + applyFilter, safeCursor,\n// drilledTask pinning (bug_filter_drill_opens_wrong_task), useNotesDrill,\n// useDrillKeymap, the dispatchListAction switch, useInput wiring, the\n// three early-return states, and the drill branch. Only the source list,\n// column specs, row mapper/colors, filter blob, yank command, and titles\n// differed. This file centralises the orchestration shell so a behavioural\n// fix lands once; each popup collapses to a config object.\n//\n// Pure dedup — no new surface, identical behaviour.\n//\n// Per ROADMAP pledge: ink/react import limited to src/cli/tui/*.\n\nimport { Box, Text } from \"ink\";\nimport { type ReactElement, useState } from \"react\";\nimport type { Db } from \"../../../db.js\";\nimport type { WorkstreamSnapshot } from \"../../../state.js\";\nimport type { TaskRow } from \"../../../tasks.js\";\nimport { type ColumnSpec, contentWidthFromCols, layoutColumns, renderRow } from \"../columns.js\";\nimport { dispatchPopupKeyFromInk, type PopupAction, type PopupActionEnvelope } from \"../keys.js\";\nimport { type CellColor, ListRow } from \"../list-row.js\";\nimport { usePopupInput } from \"../popup-input.js\";\nimport { PopupShell } from \"../popup-shell.js\";\nimport { useNotesDrill } from \"../use-notes-drill.js\";\nimport { usePopupActionQueue } from \"../use-popup-action-queue.js\";\nimport { applyFilter, FilterPrompt, listViewport, usePopupFilter } from \"../use-popup-filter.js\";\nimport { useTerminalSize } from \"../use-terminal-size.js\";\nimport { useDrillKeymap } from \"./drill.js\";\nimport { applyCursor, centredVisibleSlice, clickedItem, isNavAction } from \"./scroll.js\";\nimport { TaskDetailDrill } from \"./task-detail.js\";\nimport { POPUP_DRILL_CHROME_ROWS, usePopupViewport } from \"./viewport.js\";\n\nexport interface PopupProps {\n yank: (command: string) => Promise<void>;\n onClose: () => void;\n snapshot: WorkstreamSnapshot | null;\n fastTickNonce: number;\n mode: \"list\" | \"drill\";\n onModeChange: (mode: \"list\" | \"drill\") => void;\n /** Bubbles the filter-prompt edit state up to <App> for StatusBar mode. */\n onFilterEditingChange?: (editing: boolean) => void;\n popupActions?: readonly PopupActionEnvelope[];\n db: Db;\n workstream: string;\n}\n\n/** Rendered cells + per-cell colours for a single list row. */\nexport interface RenderedRow {\n cells: ReadonlyArray<string>;\n colors: ReadonlyArray<CellColor | undefined>;\n}\n\n/**\n * Per-popup configuration. The shared scaffold reads these to wire the\n * source list, column layout, row rendering, filter blob, list-mode yank,\n * and the various title/empty strings. `now`/`ages` precompute is left to\n * the caller via the rows closure receiving the visible slice.\n */\nexport interface TaskListPopupConfig {\n /** Short popup name used in every title (e.g. \"Tasks\", \"In-progress\"). */\n label: string;\n /** Source rows selector (e.g. snapshot.ready). Null snapshot → []. */\n sourceTasks: (snapshot: WorkstreamSnapshot) => readonly TaskRow[];\n /** Column layout spec. */\n columnSpecs: ReadonlyArray<ColumnSpec>;\n /** Search blob for the '/' filter. */\n filterBlob: (task: TaskRow) => string;\n /**\n * Map the visible slice (already sliced + cursor-centred) to rendered\n * rows. Given the visible tasks, their absolute start index, and the\n * snapshot so callers can resolve agent display names / per-row reads.\n */\n renderRows: (\n visible: readonly TaskRow[],\n start: number,\n snapshot: WorkstreamSnapshot,\n ) => RenderedRow[];\n /** List-mode yank command for the focused row (null → no yank). */\n yankCommand: (task: TaskRow, workstream: string) => string | null;\n /** Text for the empty-source early return. */\n emptyText: string;\n /** Optional static hint for the list shell. */\n hint?: string;\n /**\n * Optional dynamic hint computed from the focused row + workstream\n * (e.g. ReadyPopup mirrors the yank command into the shell hint).\n */\n dynamicHint?: (focused: TaskRow, workstream: string) => string | null;\n}\n\n/**\n * Shared scaffold for the task-list popup family. Owns all the\n * coordination logic; per-popup behaviour comes entirely from `config`.\n */\nexport function TaskListPopup({\n config,\n yank,\n onClose,\n snapshot,\n fastTickNonce,\n mode,\n onModeChange,\n onFilterEditingChange,\n popupActions,\n db,\n workstream,\n}: PopupProps & { config: TaskListPopupConfig }): ReactElement {\n const { cols } = useTerminalSize();\n const contentWidth = contentWidthFromCols(cols);\n const viewport = usePopupViewport();\n const drillViewport = usePopupViewport(POPUP_DRILL_CHROME_ROWS);\n const [cursor, setCursor] = useState(0);\n const flt = usePopupFilter({ onEditingChange: onFilterEditingChange });\n const rowsViewport = listViewport(viewport, flt);\n\n const sourceTasks = snapshot ? config.sourceTasks(snapshot) : [];\n // Per bug_filter_drill_opens_wrong_task: filter applied UNIFORMLY\n // across list and drill modes (a mode-conditional dropped the filter\n // on drill, shifting `tasks` under a constant cursor index).\n const tasks = applyFilter(sourceTasks, flt.query, config.filterBlob);\n const safeCursor = tasks.length === 0 ? 0 : Math.min(cursor, tasks.length - 1);\n const focused = tasks[safeCursor];\n\n // Defensive: capture the focused task identity at the moment Enter is\n // pressed so the drill stays pinned even if `tasks` shifts.\n const [drilledTask, setDrilledTask] = useState<TaskRow | null>(null);\n const drillTask = mode === \"drill\" ? (drilledTask ?? focused) : focused;\n\n const notesText = useNotesDrill({ mode, focused: drillTask, db, workstream, fastTickNonce });\n\n const drill = useDrillKeymap({\n body: notesText,\n viewport: drillViewport,\n onClose: () => {\n setDrilledTask(null);\n onModeChange(\"list\");\n },\n onYank: () => {\n if (!drillTask || !snapshot) return;\n return yank(`mu task notes ${drillTask.name} -w ${snapshot.workstreamName}`);\n },\n resetKey: drillTask?.name ?? \"\",\n });\n\n const dispatchListAction = (action: PopupAction) => {\n if (mode === \"drill\") {\n drill.dispatch(action);\n return;\n }\n if (isNavAction(action)) {\n setCursor((c) => applyCursor(c, action, tasks.length, rowsViewport));\n return;\n }\n switch (action.kind) {\n case \"close\":\n onClose();\n return;\n case \"filter\":\n flt.startEdit();\n return;\n case \"drill\":\n if (focused) {\n setDrilledTask(focused);\n onModeChange(\"drill\");\n }\n return;\n case \"clickRow\": {\n const hit = clickedItem(tasks, safeCursor, rowsViewport, action.row);\n if (!hit) return;\n setCursor(hit.index);\n setDrilledTask(hit.item);\n onModeChange(\"drill\");\n return;\n }\n case \"yank\": {\n const t = tasks[safeCursor];\n if (!t || !snapshot) return;\n const cmd = config.yankCommand(t, snapshot.workstreamName);\n if (cmd) void yank(cmd);\n return;\n }\n }\n };\n\n usePopupActionQueue(popupActions, dispatchListAction);\n\n usePopupInput((input, key) => {\n if (mode !== \"drill\" && flt.onKey(input, key) === \"consumed\") return;\n dispatchListAction(dispatchPopupKeyFromInk(input, key));\n });\n\n if (snapshot === null) {\n return (\n <PopupShell title={`${config.label} · popup`}>{<Text dimColor>loading…</Text>}</PopupShell>\n );\n }\n if (sourceTasks.length === 0) {\n return (\n <PopupShell title={`${config.label} · popup`}>\n <Text dimColor>{config.emptyText}</Text>\n </PopupShell>\n );\n }\n if (tasks.length === 0) {\n return (\n <PopupShell title={`${config.label} · popup`}>\n <Box flexDirection=\"column\" flexGrow={1}>\n <Text dimColor>(no matches for \"{flt.query}\")</Text>\n </Box>\n <FilterPrompt state={flt} />\n </PopupShell>\n );\n }\n\n if (mode === \"drill\" && drillTask) {\n return (\n <PopupShell title={`${config.label} · ${drillTask.name} (notes)`}>\n <Box flexDirection=\"column\" flexGrow={1}>\n <TaskDetailDrill\n task={drillTask}\n db={db}\n workstream={workstream}\n scrollTop={drill.scrollTop}\n viewport={drillViewport}\n tickNonce={fastTickNonce}\n body={notesText}\n wrappedBody={drill.wrappedBody}\n />\n </Box>\n </PopupShell>\n );\n }\n\n const { start, visible } = centredVisibleSlice(tasks, safeCursor, rowsViewport);\n const rendered = config.renderRows(visible, start, snapshot);\n const rowCells = rendered.map((r) => r.cells);\n const widths = layoutColumns(rowCells, config.columnSpecs, contentWidth);\n\n const dynamicHint =\n focused && config.dynamicHint\n ? (config.dynamicHint(focused, snapshot.workstreamName) ?? undefined)\n : undefined;\n\n return (\n <PopupShell\n title={`${config.label} · popup (${safeCursor + 1}/${tasks.length})`}\n hint={dynamicHint ?? config.hint}\n >\n <Box flexDirection=\"column\" flexGrow={1}>\n {visible.map((t, i) => {\n const selected = start + i === safeCursor;\n const r = rendered[i];\n if (r === undefined) return null;\n const padded = renderRow(r.cells, widths, config.columnSpecs);\n return (\n <ListRow\n key={t.name}\n cells={padded}\n contentWidth={contentWidth}\n colors={r.colors}\n selected={selected}\n />\n );\n })}\n </Box>\n <FilterPrompt state={flt} />\n </PopupShell>\n );\n}\n","// Commits popup (Shift+0 → `)`). Fullscreen lazygit-style project\n// commit log with '/' filtering and Enter → VCS show drill.\n//\n// Uses the project-root backend (detectBackend(projectRoot)) so git,\n// jj, and sl all work through the shared VcsBackend.showCommit seam.\n// The popup never mutates: `y` yanks the backend-specific show command\n// for the focused commit.\n\nimport { Box, Text } from \"ink\";\nimport { type ReactElement, useCallback, useEffect, useState } from \"react\";\nimport type { Db } from \"../../../db.js\";\nimport type { WorkstreamSnapshot } from \"../../../state.js\";\nimport { type CommitSummary, detectBackend, type VcsBackendName } from \"../../../vcs.js\";\nimport { type ColumnSpec, contentWidthFromCols, layoutColumns, renderRow } from \"../columns.js\";\nimport { dispatchPopupKeyFromInk, type PopupAction, type PopupActionEnvelope } from \"../keys.js\";\nimport { runLazygitInteractive } from \"../lazygit.js\";\nimport { ListRow } from \"../list-row.js\";\nimport { usePopupInput } from \"../popup-input.js\";\nimport { PopupShell } from \"../popup-shell.js\";\nimport { runTuicrInteractive } from \"../tuicr.js\";\nimport { usePopupActionQueue } from \"../use-popup-action-queue.js\";\nimport { applyFilter, FilterPrompt, listViewport, usePopupFilter } from \"../use-popup-filter.js\";\nimport { useTerminalSize } from \"../use-terminal-size.js\";\nimport { DrillScrollView, useDrillKeymap } from \"./drill.js\";\nimport { applyCursor, centredVisibleSlice, clickedItem, isNavAction } from \"./scroll.js\";\nimport { loadShowPreservingBody } from \"./show-loader.js\";\nimport { usePopupViewport } from \"./viewport.js\";\n\nexport interface PopupProps {\n yank: (command: string) => Promise<void>;\n onClose: () => void;\n snapshot: WorkstreamSnapshot | null;\n slowTickNonce: number;\n mode: \"list\" | \"drill\";\n onModeChange: (mode: \"list\" | \"drill\") => void;\n onFilterEditingChange?: (editing: boolean) => void;\n popupActions?: readonly PopupActionEnvelope[];\n onFooter?: (command: string, copied: boolean, tone?: \"normal\" | \"info\" | \"error\") => void;\n db: Db;\n workstream: string;\n}\n\nconst COLUMN_SPECS: ReadonlyArray<ColumnSpec> = [\n { kind: \"protect\" }, // sha short\n { kind: \"protect\", align: \"right\" }, // relative time\n { kind: \"protect\", max: 18 }, // author\n { kind: \"clip\", min: 1 }, // subject\n];\n\nconst DRILL_CHROME_ROWS = 7;\n\nexport function CommitsPopup({\n yank,\n onClose,\n snapshot,\n slowTickNonce,\n mode,\n onModeChange,\n onFilterEditingChange,\n popupActions,\n onFooter,\n}: PopupProps): ReactElement {\n const { cols } = useTerminalSize();\n const contentWidth = contentWidthFromCols(cols);\n const viewport = usePopupViewport();\n const drillViewport = usePopupViewport(DRILL_CHROME_ROWS);\n const [cursor, setCursor] = useState(0);\n const [showText, setShowText] = useState(\"\");\n const [showLoading, setShowLoading] = useState(false);\n const [showErr, setShowErr] = useState<string | null>(null);\n const [backendName, setBackendName] = useState<VcsBackendName | null>(\n snapshot?.commitsBackend ?? null,\n );\n const flt = usePopupFilter({ onEditingChange: onFilterEditingChange });\n const rowsViewport = listViewport(viewport, flt);\n\n const sourceCommits = snapshot?.recentCommits ?? [];\n const commits = applyFilter(\n sourceCommits,\n flt.query,\n (c) => `${c.sha} ${c.subject} ${c.author} ${c.relTime}`,\n );\n const safeCursor = commits.length === 0 ? 0 : Math.min(cursor, commits.length - 1);\n const focused = commits[safeCursor];\n // Pin the drilled commit at Enter. Commits are newest-first, so a\n // new commit on the slow tick shifts every index; following the\n // cursor would switch the open `git show` to a different commit.\n const [drilledCommit, setDrilledCommit] = useState<CommitSummary | null>(null);\n const drillCommit = mode === \"drill\" ? (drilledCommit ?? focused) : focused;\n const showCommand =\n drillCommit && backendName !== null\n ? showCommandForBackend(backendName, drillCommit.sha)\n : null;\n const projectRoot = process.cwd();\n const showBody = showErr !== null ? `error: ${showErr}` : showText;\n\n const loadShow = useCallback(\n async (sha: string) => {\n await loadShowPreservingBody(\n projectRoot,\n sha,\n async (path) => {\n const backend = await detectBackend(path);\n setBackendName(backend.name);\n return backend;\n },\n {\n setText: setShowText,\n setError: setShowErr,\n setLoading: setShowLoading,\n },\n );\n },\n [projectRoot],\n );\n\n useEffect(() => {\n if (snapshot?.commitsBackend !== undefined) setBackendName(snapshot.commitsBackend);\n }, [snapshot?.commitsBackend]);\n\n useEffect(() => {\n if (mode !== \"drill\") {\n setShowText(\"\");\n setShowErr(null);\n setShowLoading(false);\n }\n }, [mode]);\n\n const drillSha = drillCommit?.sha;\n useEffect(() => {\n void slowTickNonce;\n if (mode === \"drill\" && drillSha !== undefined) {\n void loadShow(drillSha);\n }\n }, [mode, drillSha, loadShow, slowTickNonce]);\n\n const drill = useDrillKeymap({\n body: showBody,\n viewport: drillViewport,\n onClose: () => {\n setDrilledCommit(null);\n onModeChange(\"list\");\n },\n onYank: () => {\n if (showCommand !== null) return yank(showCommand);\n },\n onTuicr: () => {\n if (!drillCommit) return;\n const r = runTuicrInteractive({ rev: drillCommit.sha, cwd: projectRoot });\n if (!r.ok) onFooter?.(r.error ?? \"tuicr failed\", false, \"error\");\n else onFooter?.(`tuicr -r ${drillCommit.sha}`, true, \"info\");\n },\n resetKey: drillCommit?.sha ?? \"\",\n });\n\n const dispatchListAction = (action: PopupAction) => {\n if (mode === \"drill\") {\n drill.dispatch(action);\n return;\n }\n if (isNavAction(action)) {\n setCursor((c) => applyCursor(c, action, commits.length, rowsViewport));\n return;\n }\n switch (action.kind) {\n case \"close\":\n onClose();\n return;\n case \"filter\":\n flt.startEdit();\n return;\n case \"drill\": {\n if (!focused) return;\n setDrilledCommit(focused);\n onModeChange(\"drill\");\n return;\n }\n case \"clickRow\": {\n const hit = clickedItem(commits, safeCursor, rowsViewport, action.row);\n if (!hit) return;\n setCursor(hit.index);\n setDrilledCommit(hit.item);\n onModeChange(\"drill\");\n return;\n }\n case \"yank\": {\n const c = commits[safeCursor];\n if (!c || backendName === null) return;\n void yank(showCommandForBackend(backendName, c.sha));\n return;\n }\n case \"verb\":\n if (action.key === \"l\") {\n const r = runLazygitInteractive({ cwd: projectRoot });\n if (!r.ok) onFooter?.(r.error ?? \"lazygit failed\", false, \"error\");\n else onFooter?.(\"lazygit\", true, \"info\");\n }\n return;\n }\n };\n\n usePopupActionQueue(popupActions, dispatchListAction);\n\n usePopupInput((input, key) => {\n if (mode !== \"drill\" && flt.onKey(input, key) === \"consumed\") return;\n dispatchListAction(dispatchPopupKeyFromInk(input, key));\n });\n\n if (snapshot === null) {\n return <PopupShell title=\"Commits · loading\">{<Text dimColor>loading…</Text>}</PopupShell>;\n }\n if (mode === \"drill\" && drillCommit !== undefined) {\n const short = shortSha(drillCommit.sha);\n return (\n <PopupShell title={`Commits · ${formatBackend(backendName)} · ${short}`}>\n <Box flexDirection=\"column\" flexGrow={1}>\n <DrillScrollView\n title={`${showCommand ?? \"show\"} · ${drillCommit.subject}`}\n body={showBody}\n viewport={drillViewport}\n scrollTop={drill.scrollTop}\n wrappedBody={drill.wrappedBody}\n hint={\n showCommand === null\n ? \"y yanks show command · t tuicr\"\n : `y yanks \\`${showCommand}\\` · t tuicr`\n }\n emptyText={showLoading ? \"loading…\" : \"(empty show output)\"}\n />\n </Box>\n </PopupShell>\n );\n }\n if (sourceCommits.length === 0) {\n return (\n <PopupShell title={`Commits · ${formatBackend(backendName)}`}>\n <Text dimColor>(no commits)</Text>\n </PopupShell>\n );\n }\n if (commits.length === 0) {\n return (\n <PopupShell title={`Commits · ${formatBackend(backendName)}`}>\n <Box flexDirection=\"column\" flexGrow={1}>\n <Text dimColor>(no matches for \"{flt.query}\")</Text>\n </Box>\n <FilterPrompt state={flt} />\n </PopupShell>\n );\n }\n\n const { visible } = centredVisibleSlice(commits, safeCursor, rowsViewport);\n const rows = visible.map((c) => [shortSha(c.sha), c.relTime, c.author, c.subject]);\n const widths = layoutColumns(rows, COLUMN_SPECS, contentWidth);\n\n return (\n <PopupShell\n title={`Commits · ${formatBackend(backendName)} (${safeCursor + 1}/${commits.length})`}\n hint=\"y yanks VCS show command · l lazygit\"\n >\n <Box flexDirection=\"column\" flexGrow={1}>\n {visible.map((c, i) => {\n const row = rows[i];\n if (row === undefined) return null;\n const padded = renderRow(row, widths, COLUMN_SPECS);\n const colors = [\n { color: \"yellow\" }, // sha\n { dimColor: true }, // relTime\n { dimColor: true }, // author\n undefined, // subject\n ];\n return (\n <ListRow\n key={c.sha}\n cells={padded}\n contentWidth={contentWidth}\n colors={colors}\n selected={commits.indexOf(c) === safeCursor}\n />\n );\n })}\n </Box>\n <FilterPrompt state={flt} />\n </PopupShell>\n );\n}\n\nexport function shortSha(sha: string): string {\n return sha.slice(0, 7);\n}\n\nexport function formatBackend(backend: VcsBackendName | null): string {\n return backend ?? \"(no vcs)\";\n}\n\nexport function showCommandForBackend(backend: VcsBackendName, sha: string): string {\n switch (backend) {\n case \"git\":\n return `git show ${sha}`;\n case \"jj\":\n return `jj show ${sha}`;\n case \"sl\":\n return `sl show ${sha}`;\n case \"none\":\n return `# no VCS backend for commit ${sha}`;\n }\n}\n\n// Test-only helper: keeps the WorkstreamSnapshot import live under\n// noUnusedLocals even when source-level tests import the prop type.\nexport function commitFilterBlob(c: CommitSummary): string {\n return `${c.sha} ${c.subject} ${c.author} ${c.relTime}`;\n}\n","// Drop into `lazygit` from inside the TUI: leaves the alt screen,\n// inherits stdio so lazygit owns the terminal, restores the alt\n// screen on exit. Mirrors `runTuicrInteractive` (src/cli/tui/tuicr.ts)\n// — same dependency-injection seam, same error-shape contract — so\n// test coverage and behavioural conventions stay consistent across\n// the two TUI escape hatches.\n//\n// Bound to `l` in the Commits popup LIST mode (counterpart to\n// `t tuicr` in the per-revision git-show DRILL): lazygit operates on\n// a cwd, not on a single revision, so the natural surface is the\n// list-level \"browse this repo\" exit, not a per-row drill.\n\nimport { spawnSync } from \"node:child_process\";\nimport { ALT_SCREEN_ENTER, ALT_SCREEN_EXIT } from \"./escapes.js\";\n\nexport interface RunLazygitOptions {\n /** Project root / workspace cwd used by lazygit for repo detection. */\n cwd: string;\n}\n\ninterface SpawnSyncResult {\n status: number | null;\n error?: Error;\n}\n\ntype SpawnSyncFn = (\n command: string,\n args: readonly string[],\n options: { cwd: string; stdio: \"inherit\"; env: NodeJS.ProcessEnv },\n) => SpawnSyncResult;\n\nexport interface RunLazygitDeps {\n spawn?: SpawnSyncFn;\n write?: (text: string) => void;\n env?: NodeJS.ProcessEnv;\n}\n\nexport interface RunLazygitResult {\n ok: boolean;\n error?: string;\n}\n\nexport function runLazygitInteractive(\n opts: RunLazygitOptions,\n deps: RunLazygitDeps = {},\n): RunLazygitResult {\n const run = deps.spawn ?? (spawnSync as SpawnSyncFn);\n const write = deps.write ?? ((text: string) => process.stdout.write(text));\n const env = deps.env ?? process.env;\n let result: RunLazygitResult = { ok: true };\n\n try {\n write(ALT_SCREEN_EXIT);\n const r = run(\"lazygit\", [], {\n cwd: opts.cwd,\n stdio: \"inherit\",\n env,\n });\n if (r.error !== undefined) {\n result = { ok: false, error: lazygitErrorMessage(r.error) };\n } else if (typeof r.status === \"number\" && r.status !== 0) {\n result = { ok: false, error: `lazygit exited ${r.status}` };\n }\n } catch (err) {\n result = { ok: false, error: lazygitErrorMessage(err) };\n } finally {\n try {\n write(ALT_SCREEN_ENTER);\n } catch {\n // Best-effort terminal repair only. Preserve the original result.\n }\n }\n\n return result;\n}\n\nexport function lazygitErrorMessage(err: unknown): string {\n if (err instanceof Error) {\n const code = (err as NodeJS.ErrnoException).code;\n if (code === \"ENOENT\") {\n return \"lazygit not found · install from https://github.com/jesseduffield/lazygit\";\n }\n return err.message.length > 0 ? err.message : String(err);\n }\n return String(err);\n}\n","import { spawnSync } from \"node:child_process\";\nimport { ALT_SCREEN_ENTER, ALT_SCREEN_EXIT } from \"./escapes.js\";\n\nexport interface RunTuicrOptions {\n rev: string;\n /** Project root / workspace cwd used by tuicr for repo detection. */\n cwd: string;\n}\n\ninterface SpawnSyncResult {\n status: number | null;\n error?: Error;\n}\n\ntype SpawnSyncFn = (\n command: string,\n args: readonly string[],\n options: { cwd: string; stdio: \"inherit\"; env: NodeJS.ProcessEnv },\n) => SpawnSyncResult;\n\nexport interface RunTuicrDeps {\n spawn?: SpawnSyncFn;\n write?: (text: string) => void;\n env?: NodeJS.ProcessEnv;\n}\n\nexport interface RunTuicrResult {\n ok: boolean;\n error?: string;\n}\n\nexport function runTuicrInteractive(\n opts: RunTuicrOptions,\n deps: RunTuicrDeps = {},\n): RunTuicrResult {\n const run = deps.spawn ?? (spawnSync as SpawnSyncFn);\n const write = deps.write ?? ((text: string) => process.stdout.write(text));\n const env = deps.env ?? process.env;\n let result: RunTuicrResult = { ok: true };\n\n try {\n write(ALT_SCREEN_EXIT);\n const r = run(\"tuicr\", [\"-r\", opts.rev], {\n cwd: opts.cwd,\n stdio: \"inherit\",\n env,\n });\n if (r.error !== undefined) {\n result = { ok: false, error: tuicrErrorMessage(r.error) };\n } else if (typeof r.status === \"number\" && r.status !== 0) {\n result = { ok: false, error: `tuicr exited ${r.status}` };\n }\n } catch (err) {\n result = { ok: false, error: tuicrErrorMessage(err) };\n } finally {\n try {\n write(ALT_SCREEN_ENTER);\n } catch {\n // Best-effort terminal repair only. Preserve the original result.\n }\n }\n\n return result;\n}\n\nexport function tuicrErrorMessage(err: unknown): string {\n if (err instanceof Error) {\n const code = (err as NodeJS.ErrnoException).code;\n if (code === \"ENOENT\") return \"tuicr not found · install with cargo install tuicr\";\n return err.message.length > 0 ? err.message : String(err);\n }\n return String(err);\n}\n","// Shared tiny state machine for VCS show drills (Commits and\n// Workspaces popups). Keeps the previous successful body visible\n// while a slow-tick refetch is in flight, avoiding the blank-flash\n// flicker that came from clearing showText before each subprocess.\n//\n// Pure TS: no ink/react imports. Tests can drive the transition\n// directly without mounting a popup or shelling out to git.\n\nimport type { ShowCommitResult, VcsBackend } from \"../../../vcs.js\";\n\nexport interface ShowLoaderState {\n text: string;\n error: string | null;\n loading: boolean;\n}\n\nexport interface ShowLoaderSetters {\n setText: (text: string) => void;\n setError: (error: string | null) => void;\n setLoading: (loading: boolean) => void;\n}\n\nexport type DetectBackendFn = (path: string) => Promise<Pick<VcsBackend, \"showCommit\">>;\n\nexport async function loadShowPreservingBody(\n path: string,\n sha: string,\n detect: DetectBackendFn,\n setters: ShowLoaderSetters,\n): Promise<ShowCommitResult> {\n setters.setLoading(true);\n setters.setError(null);\n const backend = await detect(path);\n const result = await backend.showCommit(path, sha);\n if (result.error !== undefined) {\n setters.setError(result.error);\n setters.setText(\"\");\n } else {\n setters.setText(result.text);\n }\n setters.setLoading(false);\n return result;\n}\n","// Full task-DAG popup (`g`). Keybind-only; no dashboard card slot.\n//\n// Read-only forest of the current workstream: every root task (no\n// incoming blocks edge) is rendered with the same ASCII tree machinery\n// as `mu task tree --down`, separated by blank lines. No card owns this\n// popup; it is a dashboard-level graph affordance for large workstreams.\n\nimport { Box, Text } from \"ink\";\nimport { type ReactElement, useMemo, useRef, useState } from \"react\";\nimport { loadFullDag, renderForest } from \"../../../dag.js\";\nimport type { Db } from \"../../../db.js\";\nimport type { WorkstreamSnapshot } from \"../../../state.js\";\nimport type { TaskStatus } from \"../../../tasks/status.js\";\nimport { colorPair } from \"../../format.js\";\nimport { contentWidthFromCols, truncateCell } from \"../columns.js\";\nimport { dispatchPopupKeyFromInk } from \"../keys.js\";\nimport { usePopupInput } from \"../popup-input.js\";\nimport { PopupShell } from \"../popup-shell.js\";\nimport {\n type FilterState,\n passesFilter,\n StatusFilterStrip,\n useStatusFilter,\n} from \"../use-status-filter.js\";\nimport { useTerminalSize } from \"../use-terminal-size.js\";\nimport { DrillScrollView, useDrillKeymap } from \"./drill.js\";\nimport { POPUP_DRILL_CHROME_ROWS, usePopupViewport } from \"./viewport.js\";\n\nexport interface PopupProps {\n yank: (command: string) => Promise<void>;\n onClose: () => void;\n snapshot: WorkstreamSnapshot | null;\n fastTickNonce: number;\n mode: \"list\" | \"drill\";\n onModeChange: (mode: \"list\" | \"drill\") => void;\n onFilterEditingChange?: (editing: boolean) => void;\n db: Db;\n workstream: string;\n}\n\nconst DAG_STRIP_ROWS = 1;\n\ninterface DagBody {\n body: string;\n roots: string[];\n}\n\nexport function DagPopup({\n yank,\n onClose,\n db,\n workstream,\n fastTickNonce,\n}: PopupProps): ReactElement {\n // DrillScrollView (title + hint) below one StatusFilterStrip row.\n const viewport = usePopupViewport(POPUP_DRILL_CHROME_ROWS + DAG_STRIP_ROWS);\n const statusFilter = useStatusFilter();\n const { statuses, showParked, showNotDone } = statusFilter;\n const { cols } = useTerminalSize();\n const contentWidth = contentWidthFromCols(cols);\n const { body, roots } = useMemo<DagBody>(() => {\n void fastTickNonce;\n return buildDagBody(db, workstream, { statuses, showParked, showNotDone }, contentWidth);\n }, [db, workstream, statuses, showParked, showNotDone, contentWidth, fastTickNonce]);\n const [focusedRoot, setFocusedRoot] = useState<string | null>(() => roots[0] ?? null);\n const lineToRootRef = useRef<readonly string[]>([]);\n const rootsRef = useRef<readonly string[]>([]);\n rootsRef.current = roots;\n const focusedTask = focusedRoot !== null && roots.includes(focusedRoot) ? focusedRoot : roots[0];\n const drill = useDrillKeymap({\n body,\n viewport,\n onClose,\n onYank: () => {\n if (focusedTask === undefined) return;\n return yank(dagYankCommand(focusedTask, workstream));\n },\n onScrollChange: (newTop) =>\n setFocusedRoot(lineToRootRef.current[newTop] ?? rootsRef.current[0] ?? null),\n resetKey: workstream,\n });\n\n const lineToRoot = useMemo(\n () => rootForBodyLines(drill.wrappedLines, roots),\n [drill.wrappedLines, roots],\n );\n lineToRootRef.current = lineToRoot;\n\n usePopupInput((input, key) => {\n if (statusFilter.onKey(input, key)) return;\n const action = dispatchPopupKeyFromInk(input, key);\n drill.dispatch(action);\n });\n\n if (roots.length === 0) {\n return (\n <PopupShell title={`DAG · ${workstream}`}>\n <Box flexDirection=\"column\" flexGrow={1}>\n <StatusFilterStrip\n statuses={statuses}\n showParked={showParked}\n showNotDone={showNotDone}\n />\n <Text dimColor>(no tasks)</Text>\n </Box>\n </PopupShell>\n );\n }\n\n return (\n <PopupShell title={`DAG · ${workstream}`} hint=\"y yanks `mu task tree <root-id>`\">\n <Box flexDirection=\"column\" flexGrow={1}>\n <StatusFilterStrip statuses={statuses} showParked={showParked} showNotDone={showNotDone} />\n <DrillScrollView\n title=\"task DAG forest\"\n body={body}\n viewport={viewport}\n scrollTop={drill.scrollTop}\n wrappedBody={drill.wrappedBody}\n emptyText=\"(no tasks)\"\n hint=\"y yanks `mu task tree <root-id>`\"\n />\n </Box>\n </PopupShell>\n );\n}\n\nexport function dagYankCommand(taskId: string, workstream: string): string {\n return `mu task tree ${taskId} -w ${workstream}`;\n}\n\nexport function buildDagBody(\n db: Db,\n workstream: string,\n filter: ReadonlySet<TaskStatus> | FilterState,\n contentWidth: number = contentWidthFromCols(80),\n): DagBody {\n // A bare status set means \"no substate toggles\" (both slices shown).\n const f: FilterState =\n \"statuses\" in filter ? filter : { statuses: filter, showParked: true, showNotDone: true };\n const dag = loadFullDag(db, workstream, { include: (t) => passesFilter(t, f) });\n const body = renderForest(dag.roots, dag.edges, (task) => colorPair(task), dag.tasks, {\n includeTitle: false,\n });\n return {\n body: truncateDagBody(body, contentWidth),\n roots: dag.roots.map((t) => t.name),\n };\n}\n\nexport function truncateDagBody(body: string, contentWidth: number): string {\n const width = Math.max(0, contentWidth - 1);\n return body\n .split(\"\\n\")\n .map((line) => truncateCell(line, width))\n .join(\"\\n\");\n}\n\nfunction rootForBodyLines(lines: readonly string[], roots: readonly string[]): string[] {\n const rootSet = new Set(roots);\n const out: string[] = [];\n let current = roots[0] ?? \"\";\n for (const line of lines) {\n const maybeRoot = line.split(/\\s+/)[0];\n if (maybeRoot !== undefined && rootSet.has(maybeRoot)) current = maybeRoot;\n out.push(current);\n }\n return out;\n}\n","// Doctor popup (Shift+9 → `(`). The drill-down for the Doctor card.\n//\n// Per feat_popup_9_doctor (workstream `tui-impl`): list of every\n// doctor check (NOT just the non-OK subset Card 9 surfaces) with\n// j/k navigation, '/' substring filter (via use-popup-filter), `y`\n// to yank a remediation HINT (informational only — never a\n// mutating verb), and Enter to drill into a small ad-hoc detail\n// view of the focused check.\n//\n// IMPORTANT — DRILL IS NOT TaskDetailDrill. Rows are doctor checks,\n// not tasks; the popup-recursion contract from\n// feat_track_drill_chains_to_task_drill does NOT apply. The drill\n// view renders the focused check's name, status, detail, and a\n// multi-line remediation hint via the shared DrillScrollView leaf.\n//\n// COLUMN SHAPE (matches Card 9's row vocabulary):\n// glyph check STATUS detail\n// PROTECT PROTECT PROTECT CLIP\n//\n// Per feat_column_aligned_lists clipping policy: glyph + name +\n// status are PROTECTED (identity-bearing); only `detail` is\n// CLIPPABLE.\n//\n// READ-ONLY (per ROADMAP pledge). The only act-intent is `y`,\n// which yanks an INFORMATIONAL command (the row's diagnostic\n// recipe). Schema/journal_mode/foreign_keys checks have no\n// mutating recovery the operator can yank, so we yank a `# ...`\n// comment line — visibly inert, satisfies the muscle-memory of\n// \"press y, paste, see something\". No verb in the yank matrix\n// here mutates the DB or pane state.\n//\n// Per ROADMAP pledge: ink/react import limited to src/cli/tui/*.\n\nimport { Box, Text } from \"ink\";\nimport { type ReactElement, useState } from \"react\";\nimport type { Db } from \"../../../db.js\";\nimport {\n type DoctorCheck,\n loadDoctorChecks,\n remediationParagraph,\n yankCommandForCheck,\n} from \"../../../doctor-summary.js\";\nimport type { WorkstreamSnapshot } from \"../../../state.js\";\nimport { colorForStatus, glyphFor } from \"../cards/doctor.js\";\nimport { type ColumnSpec, contentWidthFromCols, layoutColumns, renderRow } from \"../columns.js\";\nimport { dispatchPopupKeyFromInk, type PopupAction, type PopupActionEnvelope } from \"../keys.js\";\nimport { ListRow } from \"../list-row.js\";\nimport { usePopupInput } from \"../popup-input.js\";\nimport { PopupShell } from \"../popup-shell.js\";\nimport { usePopupActionQueue } from \"../use-popup-action-queue.js\";\nimport { applyFilter, FilterPrompt, listViewport, usePopupFilter } from \"../use-popup-filter.js\";\nimport { useTerminalSize } from \"../use-terminal-size.js\";\nimport { DrillScrollView, useDrillKeymap } from \"./drill.js\";\nimport { applyCursor, centredVisibleSlice, clickedItem, isNavAction } from \"./scroll.js\";\nimport { POPUP_DRILL_CHROME_ROWS, usePopupViewport } from \"./viewport.js\";\n\nexport interface PopupProps {\n yank: (command: string) => Promise<void>;\n onClose: () => void;\n snapshot: WorkstreamSnapshot | null;\n mode: \"list\" | \"drill\";\n onModeChange: (mode: \"list\" | \"drill\") => void;\n /** Bubbles the filter-prompt edit state up to <App> for StatusBar mode. */\n onFilterEditingChange?: (editing: boolean) => void;\n popupActions?: readonly PopupActionEnvelope[];\n db: Db;\n workstream: string;\n}\n\nconst COLUMN_SPECS: ReadonlyArray<ColumnSpec> = [\n { kind: \"protect\" }, // glyph\n { kind: \"protect\" }, // check name\n { kind: \"protect\" }, // status (ok / warn / fail)\n { kind: \"clip\", min: 1 }, // detail (free-form; CLIPPABLE)\n];\n\nexport function DoctorPopup({\n yank,\n onClose,\n snapshot,\n mode,\n onModeChange,\n onFilterEditingChange,\n popupActions,\n db,\n workstream: _workstream,\n}: PopupProps): ReactElement {\n const { cols } = useTerminalSize();\n const contentWidth = contentWidthFromCols(cols);\n // Per-render viewport from stdout.rows minus the popup chrome\n // budget; see popups/viewport.ts.\n const viewport = usePopupViewport();\n const [cursor, setCursor] = useState(0);\n const flt = usePopupFilter({ onEditingChange: onFilterEditingChange });\n const rowsViewport = listViewport(viewport, flt);\n const drillViewport = usePopupViewport(POPUP_DRILL_CHROME_ROWS);\n\n // Source rows: ALL checks (OK + warn + fail), NOT just the non-OK\n // subset Card 9 renders. We refresh on every render — the SDK\n // call is a handful of synchronous DB pragmas + COUNT-shape\n // SELECTs (see src/doctor-summary.ts) so it's cheap even on the\n // popup's typing-intensive '/' filter loop. Snapshot.doctor (the\n // card's slice) only carries the truncated set, so we re-derive\n // the full one here, with the card's agent-state source (herdr on\n // herdr) so the murmur row agrees with the card and `mu doctor`.\n const sourceChecks: readonly DoctorCheck[] = snapshot\n ? loadDoctorChecks(db, snapshot, snapshot.doctor?.agentStateSource)\n : [];\n\n // Per spec FILTER block: blob = `${name} ${status} ${detail}`.\n // Per bug_filter_drill_opens_wrong_task: text filter applied\n // UNIFORMLY across list and drill modes (the previous mode-conditional\n // dropped the filter on drill, shifting `checks` under a constant\n // cursor index).\n const checks = applyFilter(sourceChecks, flt.query, (c) => `${c.name} ${c.status} ${c.detail}`);\n const safeCursor = checks.length === 0 ? 0 : Math.min(cursor, checks.length - 1);\n const focused = checks[safeCursor];\n\n // Defensive: capture focused check identity at Enter so the drill\n // stays pinned even if checks shift.\n const [drilledCheck, setDrilledCheck] = useState<DoctorCheck | null>(null);\n const drillCheck = mode === \"drill\" ? (drilledCheck ?? focused) : focused;\n\n // Drill body: pre-formatted text rendered via DrillScrollView.\n // Pure derivation from the captured check; no DB call.\n const drillBody = drillCheck ? renderDrillBody(drillCheck) : \"\";\n const drill = useDrillKeymap({\n body: drillBody,\n viewport: drillViewport,\n onClose: () => {\n setDrilledCheck(null);\n onModeChange(\"list\");\n },\n onYank: () => {\n if (!drillCheck) return;\n return yank(yankCommandForCheck(drillCheck));\n },\n resetKey: drillCheck?.name ?? \"\",\n });\n\n const dispatchListAction = (action: PopupAction) => {\n if (mode === \"drill\") {\n drill.dispatch(action);\n return;\n }\n if (isNavAction(action)) {\n setCursor((c) => applyCursor(c, action, checks.length, rowsViewport));\n return;\n }\n switch (action.kind) {\n case \"close\":\n onClose();\n return;\n case \"filter\":\n flt.startEdit();\n return;\n case \"drill\":\n if (focused) {\n setDrilledCheck(focused);\n onModeChange(\"drill\");\n }\n return;\n case \"clickRow\": {\n const hit = clickedItem(checks, safeCursor, rowsViewport, action.row);\n if (!hit) return;\n setCursor(hit.index);\n setDrilledCheck(hit.item);\n onModeChange(\"drill\");\n return;\n }\n case \"yank\":\n if (!focused) return;\n void yank(yankCommandForCheck(focused));\n return;\n }\n };\n\n usePopupActionQueue(popupActions, dispatchListAction);\n\n usePopupInput((input, key) => {\n if (mode !== \"drill\" && flt.onKey(input, key) === \"consumed\") return;\n dispatchListAction(dispatchPopupKeyFromInk(input, key));\n });\n\n if (snapshot === null) {\n return <PopupShell title=\"Doctor · popup\">{<Text dimColor>loading…</Text>}</PopupShell>;\n }\n if (sourceChecks.length === 0) {\n return (\n <PopupShell title=\"Doctor · popup\">\n <Text dimColor>(no checks ran — `mu doctor` should always return ≥ 1 row)</Text>\n </PopupShell>\n );\n }\n if (checks.length === 0) {\n return (\n <PopupShell title=\"Doctor · popup\">\n <Box flexDirection=\"column\" flexGrow={1}>\n <Text dimColor>(no matches for \"{flt.query}\")</Text>\n </Box>\n <FilterPrompt state={flt} />\n </PopupShell>\n );\n }\n\n if (mode === \"drill\" && drillCheck) {\n return (\n <PopupShell title={`Doctor · ${drillCheck.name} (detail)`}>\n <Box flexDirection=\"column\" flexGrow={1}>\n <DrillScrollView\n title={`${drillCheck.name} · ${drillCheck.status}`}\n body={drillBody}\n viewport={drillViewport}\n scrollTop={drill.scrollTop}\n wrappedBody={drill.wrappedBody}\n emptyText=\"(no detail)\"\n hint={`y yanks \\`${yankCommandForCheck(drillCheck)}\\``}\n />\n </Box>\n </PopupShell>\n );\n }\n\n const { start, visible } = centredVisibleSlice(checks, safeCursor, rowsViewport);\n const rows = visible.map((c) => [glyphFor(c), c.name, c.status, c.detail]);\n const widths = layoutColumns(rows, COLUMN_SPECS, contentWidth);\n\n return (\n <PopupShell\n title={`Doctor · popup (${safeCursor + 1}/${checks.length})`}\n hint=\"y yanks remediation hint (informational)\"\n >\n <Box flexDirection=\"column\" flexGrow={1}>\n {visible.map((c, i) => {\n const selected = start + i === safeCursor;\n const row = rows[i];\n if (row === undefined) return null;\n const padded = renderRow(row, widths, COLUMN_SPECS);\n const statusColor = colorForStatus(c.status);\n const colors = [\n { color: statusColor }, // glyph\n { bold: true }, // name\n { color: statusColor }, // status\n { dimColor: true }, // detail\n ];\n return (\n <ListRow\n key={c.name}\n cells={padded}\n contentWidth={contentWidth}\n colors={colors}\n selected={selected}\n />\n );\n })}\n </Box>\n <FilterPrompt state={flt} />\n </PopupShell>\n );\n}\n\n// ─── pure helpers (drill body render — pure-helpers MOVED) ──────────\n//\n// `yankCommandForCheck` + `remediationParagraph` previously lived\n// here. They moved to src/doctor-summary.ts per\n// review_tui_doctor_remediation_lives_in_popup — they have no\n// rendering concern, and keeping them next to the `DoctorCheck`\n// type means a future check is a single touchpoint instead of two.\n// `renderDrillBody` STAYS here because it interleaves\n// summary/status/detail/separator lines for the popup drill view.\n\n/**\n * Pre-format the focused check as a multi-line drill body. Pure;\n * exported for unit tests. Lines:\n *\n * <NAME>\n * status: <ok | warn | fail>\n * detail: <free-form>\n * (blank)\n * <multi-line remediation hint>\n *\n * The remediation hint is a short paragraph that explains what\n * the operator should run / look at next. Same vocabulary as the\n * yank recipe (yankCommandForCheck) so the user sees the same\n * verb in the body and on `y`.\n */\nexport function renderDrillBody(check: DoctorCheck): string {\n const lines: string[] = [];\n lines.push(check.name);\n lines.push(\"\");\n lines.push(`status: ${check.status}`);\n lines.push(`detail: ${check.detail}`);\n lines.push(\"\");\n lines.push(\"remediation hint (informational):\");\n lines.push(` ${yankCommandForCheck(check)}`);\n lines.push(\"\");\n for (const ln of remediationParagraph(check)) lines.push(ln);\n return lines.join(\"\\n\");\n}\n","// In-progress popup (Shift+6 → `^`). The drill-down for the\n// In-progress card.\n//\n// Per feat_popup_6_inprogress (workstream `tui-impl`). Sibling of\n// popups/ready.tsx — list of IN_PROGRESS tasks with j/k nav, '/'\n// substring filter, y to yank `mu task close <id> --evidence \"...\"`,\n// and Enter to chain into the shared TaskDetailDrill leaf (the\n// recursion contract from feat_track_drill_chains_to_task_drill —\n// rows ARE tasks).\n//\n// Column shape mirrors Card 6 (cards/inprogress.tsx) but adds two\n// columns the card was too narrow to fit:\n// glyph id STATUS owner since-claim ROI title\n// Per feat_column_aligned_lists clipping policy: every cell except\n// `title` is identity-bearing and PROTECTED; only `title` is\n// CLIPPABLE. Wider title column than the card (more pixels here).\n//\n// All coordination logic lives in the shared TaskListPopup scaffold\n// (popups/task-list-popup.tsx); this file is the In-progress config.\n//\n// Per ROADMAP pledge: ink/react import limited to src/cli/tui/*.\n\nimport type { ReactElement } from \"react\";\nimport { formatPair } from \"../../../tasks/status.js\";\nimport { inkColorForPair } from \"../../format.js\";\nimport { agentByName, formatTaskOwnerDisplay } from \"../agent-display.js\";\nimport { GLYPH, isStale } from \"../cards/inprogress.js\";\nimport type { ColumnSpec } from \"../columns.js\";\nimport { ageMs, formatRoi, formatSinceClaim } from \"../format-helpers.js\";\nimport {\n type PopupProps,\n type RenderedRow,\n TaskListPopup,\n type TaskListPopupConfig,\n} from \"./task-list-popup.js\";\n\nconst COLUMN_SPECS: ReadonlyArray<ColumnSpec> = [\n { kind: \"protect\" }, // glyph\n { kind: \"protect\" }, // task id\n { kind: \"protect\" }, // status (always IN_PROGRESS; constant for now)\n { kind: \"protect\" }, // owner (or \"—\")\n { kind: \"protect\", align: \"right\" }, // since-claim\n { kind: \"protect\", align: \"right\" }, // ROI label\n { kind: \"clip\", min: 1 }, // title\n];\n\nconst config: TaskListPopupConfig = {\n label: \"In-progress\",\n sourceTasks: (snapshot) => snapshot.inProgress,\n columnSpecs: COLUMN_SPECS,\n // Per spec MATCHING RULES: search blob is `${id} ${title} ${owner ?? \"\"}`.\n filterBlob: (t) => `${t.name} ${t.title} ${t.ownerName ?? \"\"}`,\n emptyText: \"(none in progress)\",\n yankCommand: (t, ws) => yankCommandForTask(t.name, ws),\n hint: \"y yanks `mu task close <id> --evidence ...`\",\n renderRows: (visible, _start, snapshot): RenderedRow[] => {\n const now = Date.now();\n const agentLookup = agentByName(snapshot);\n return visible.map((t) => {\n const age = ageMs(t, now);\n const stale = isStale(age);\n return {\n cells: [\n GLYPH,\n t.name,\n formatPair(t),\n formatTaskOwnerDisplay(t, agentLookup),\n formatSinceClaim(age),\n formatRoi(t.impact, t.effortDays),\n t.title,\n ],\n colors: [\n { color: \"yellow\" }, // glyph\n { bold: true }, // id\n { color: inkColorForPair(t) }, // status\n { dimColor: true }, // owner\n stale ? { color: \"yellow\" } : { dimColor: true }, // since-claim\n { dimColor: true }, // roi\n undefined, // title\n ],\n };\n });\n },\n};\n\nexport function InProgressPopup(props: PopupProps): ReactElement {\n return <TaskListPopup config={config} {...props} />;\n}\n\n/**\n * Yank command for an IN_PROGRESS task row. The most likely\n * act-intent on the In-progress popup is closing the task with\n * grounding evidence (per the Tasks-popup yank matrix, `mu task\n * close <id> -w <ws> --evidence \"...\"` is the canonical\n * IN_PROGRESS verb). Stays consistent with popups/ready.tsx so the\n * operator's muscle memory transfers across popups. Pure; exported\n * for unit tests.\n */\nexport function yankCommandForTask(taskName: string, workstream: string): string {\n return `mu task close ${taskName} -w ${workstream} --evidence \"...\"`;\n}\n","// Activity-log popup (Shift+4 → `$`). Per design_popup_log.\n//\n// v0: list all snapshot.recent (newest at top), with j/k navigation.\n// Auto-tail with scroll-pause + filters are deferred to v0.next.\n//\n// Enter on a focused row drills into a read-only inline view of the\n// event's full untruncated payload. Long payloads (workspace-refresh\n// events, multi-field task.claim notes, multi-line task notes\n// summaries) clip in the list view per\n// bug_tui_log_card_columns_misaligned; the drill is the\n// single-source affordance for reading the full text. j/k scroll the\n// drilled payload; q/Esc back to list. (Earlier versions of this\n// popup left Enter UNBOUND on the assumption rows were always\n// single-line atoms; user feedback proved that wrong — wrapped\n// payloads needed the explicit drill-out.)\n//\n// Rows are column-aligned via src/cli/tui/columns.ts. Per\n// feat_column_aligned_lists clipping policy: seq, ts, source, verb\n// are PROTECTED (identity / numeric / short tokens); the payload rest\n// is CLIPPABLE.\n\nimport { Box, Text } from \"ink\";\nimport { type ReactElement, useState } from \"react\";\nimport type { Db } from \"../../../db.js\";\nimport { opSubject, renderOp, renderOpLine } from \"../../../log-render.js\";\nimport type { LogRow } from \"../../../logs.js\";\nimport type { WorkstreamSnapshot } from \"../../../state.js\";\nimport { type ColumnSpec, contentWidthFromCols, layoutColumns, renderRow } from \"../columns.js\";\nimport { dispatchPopupKeyFromInk, type PopupAction, type PopupActionEnvelope } from \"../keys.js\";\nimport { ListRow } from \"../list-row.js\";\nimport { usePopupInput } from \"../popup-input.js\";\nimport { PopupShell } from \"../popup-shell.js\";\nimport { usePopupActionQueue } from \"../use-popup-action-queue.js\";\nimport { applyFilter, FilterPrompt, listViewport, usePopupFilter } from \"../use-popup-filter.js\";\nimport { useTerminalSize } from \"../use-terminal-size.js\";\nimport { DrillScrollView, useDrillKeymap } from \"./drill.js\";\nimport { applyCursor, centredVisibleSlice, clickedItem, isNavAction } from \"./scroll.js\";\nimport { POPUP_DRILL_CHROME_ROWS, usePopupViewport } from \"./viewport.js\";\n\nexport interface PopupProps {\n yank: (command: string) => Promise<void>;\n onClose: () => void;\n snapshot: WorkstreamSnapshot | null;\n mode: \"list\" | \"drill\";\n onModeChange: (mode: \"list\" | \"drill\") => void;\n /** Bubbles the filter-prompt edit state up to <App> for StatusBar mode. */\n onFilterEditingChange?: (editing: boolean) => void;\n popupActions?: readonly PopupActionEnvelope[];\n db: Db;\n workstream: string;\n}\n\nconst COLUMN_SPECS: ReadonlyArray<ColumnSpec> = [\n { kind: \"protect\", align: \"right\" }, // seq (#N)\n { kind: \"protect\" }, // ts\n { kind: \"protect\" }, // source\n { kind: \"protect\" }, // verb (or '·' fallback)\n { kind: \"clip\", min: 1 }, // rest / payload\n];\n\nexport function LogPopup({\n yank,\n onClose,\n snapshot,\n mode,\n onModeChange,\n onFilterEditingChange,\n popupActions,\n}: PopupProps): ReactElement {\n const { cols } = useTerminalSize();\n const contentWidth = contentWidthFromCols(cols);\n // Per-render viewport from stdout.rows minus the popup chrome budget;\n // see popups/viewport.ts. Replaces the prior hardcoded VIEWPORT = 20\n // — used for BOTH the slice size AND the cursor-centring half-window.\n const viewport = usePopupViewport();\n const [cursor, setCursor] = useState(0);\n const flt = usePopupFilter({ onEditingChange: onFilterEditingChange });\n const rowsViewport = listViewport(viewport, flt);\n const drillViewport = usePopupViewport(POPUP_DRILL_CHROME_ROWS);\n const sourceEvents = snapshot?.recent ?? [];\n // Per spec: blob = `${verb} ${rest} ${source}`. Built from the SAME\n // formatter the rows render with, so '/' searches match what the user\n // actually sees (searching \"task close\" finds a task.close op).\n const events = applyFilter(sourceEvents, flt.query, (e) => `${renderOpLine(e)} ${e.source}`);\n const safeCursor = events.length === 0 ? 0 : Math.min(cursor, events.length - 1);\n const focused = events[safeCursor];\n // Pin the drilled event at Enter: new events arrive at the top and\n // the 200-event cap drops the oldest, so the cursor index alone\n // would slide the open drill onto a different event.\n const [drilledEvent, setDrilledEvent] = useState<LogRow | null>(null);\n const drillEvent = mode === \"drill\" ? (drilledEvent ?? focused) : focused;\n\n // Drill shows the prose FIRST (what the row says) then the raw op\n // payload, so the detail view is readable but still lossless.\n const drillBody =\n drillEvent === undefined\n ? \"\"\n : drillEvent.intent === null\n ? drillEvent.payload\n : `${renderOpLine(drillEvent)}\\n\\nintent: ${drillEvent.intent}\\nkey: ${drillEvent.workstreamName ?? \"—\"}\\ngroup: ${drillEvent.group}\\npayload: ${drillEvent.payload}`;\n const drill = useDrillKeymap({\n body: drillBody,\n viewport: drillViewport,\n onClose: () => {\n setDrilledEvent(null);\n onModeChange(\"list\");\n },\n onYank: () => {\n if (!drillEvent || !snapshot) return;\n const since = Math.max(0, drillEvent.seq - 1);\n return yank(`mu log --since ${since} -n 1 -w ${snapshot.workstreamName}`);\n },\n resetKey: drillEvent?.seq ?? \"\",\n });\n\n const dispatchListAction = (action: PopupAction) => {\n if (mode === \"drill\") {\n drill.dispatch(action);\n return;\n }\n if (isNavAction(action)) {\n setCursor((c) => applyCursor(c, action, events.length, rowsViewport));\n return;\n }\n switch (action.kind) {\n case \"close\":\n onClose();\n return;\n case \"filter\":\n flt.startEdit();\n return;\n case \"drill\":\n if (focused !== undefined) {\n setDrilledEvent(focused);\n onModeChange(\"drill\");\n }\n return;\n case \"clickRow\": {\n const hit = clickedItem(events, safeCursor, rowsViewport, action.row);\n if (!hit) return;\n setCursor(hit.index);\n setDrilledEvent(hit.item);\n onModeChange(\"drill\");\n return;\n }\n case \"yank\": {\n const e = events[safeCursor];\n if (!e || !snapshot) return;\n // Yank the show-related-task / show-related-agent if we\n // can classify; else just yank the raw payload as a\n // reference.\n const payload = e.payload;\n // Resolve from intent + natural key where available, prose\n // otherwise (v2-retire-log-shim).\n const subject = opSubject(e);\n if (subject === null) {\n void yank(`# event: ${payload}`);\n return;\n }\n void yank(`mu ${subject.kind} show ${subject.id} -w ${snapshot.workstreamName}`);\n return;\n }\n }\n };\n\n usePopupActionQueue(popupActions, dispatchListAction);\n\n usePopupInput((input, key) => {\n if (mode !== \"drill\" && flt.onKey(input, key) === \"consumed\") return;\n dispatchListAction(dispatchPopupKeyFromInk(input, key));\n });\n\n if (snapshot === null) {\n return <PopupShell title=\"Activity log · popup\">{<Text dimColor>loading…</Text>}</PopupShell>;\n }\n if (mode === \"drill\" && drillEvent !== undefined) {\n return (\n <PopupShell\n title={`Activity log · #${drillEvent.seq} (${drillEvent.createdAt.slice(11, 19)})`}\n >\n <Box flexDirection=\"column\" flexGrow={1}>\n <DrillScrollView\n title=\"event payload\"\n body={drillBody}\n viewport={drillViewport}\n scrollTop={drill.scrollTop}\n wrappedBody={drill.wrappedBody}\n emptyText=\"(empty payload)\"\n hint=\"y yanks `mu log --since N -n 1`\"\n />\n </Box>\n </PopupShell>\n );\n }\n if (sourceEvents.length === 0) {\n return (\n <PopupShell title=\"Activity log · popup\">\n <Text dimColor>(no events yet)</Text>\n </PopupShell>\n );\n }\n if (events.length === 0) {\n return (\n <PopupShell title=\"Activity log · popup\">\n <Box flexDirection=\"column\" flexGrow={1}>\n <Text dimColor>(no matches for \"{flt.query}\")</Text>\n </Box>\n <FilterPrompt state={flt} />\n </PopupShell>\n );\n }\n\n // Centre the cursor in the viewport. `viewport` is BOTH the slice\n // size and the half-window for centring — must use the per-render\n // value consistently (see CAVEAT in bug_tui_popup_data_doesnt_fill).\n const { visible } = centredVisibleSlice(events, safeCursor, rowsViewport);\n\n const rows = visible.map((e) => {\n const r = renderOp(e);\n const ts = e.createdAt.slice(11, 19);\n const verb = r?.verb ?? \"·\";\n const rest = r === null ? e.payload : [r.subject, r.detail].filter((x) => x !== \"\").join(\" \");\n return [`#${e.seq}`, ts, e.source, verb, rest];\n });\n const widths = layoutColumns(rows, COLUMN_SPECS, contentWidth);\n\n return (\n <PopupShell\n title={`Activity log · popup (${safeCursor + 1}/${events.length})`}\n hint=\"y yanks the related `mu task/agent show` command\"\n >\n <Box flexDirection=\"column\" flexGrow={1}>\n {visible.map((e, i) => {\n const sel = events.indexOf(e) === safeCursor;\n const row = rows[i];\n if (row === undefined) return null;\n const padded = renderRow(row, widths, COLUMN_SPECS);\n const colors = [\n { dimColor: true }, // seq\n { dimColor: true }, // ts\n { dimColor: true }, // source\n e.intent === null ? { dimColor: true } : { color: \"cyan\" }, // verb\n undefined, // rest\n ];\n return (\n <ListRow\n key={e.seq}\n cells={padded}\n contentWidth={contentWidth}\n colors={colors}\n selected={sel}\n />\n );\n })}\n </Box>\n <FilterPrompt state={flt} />\n </PopupShell>\n );\n}\n","// Tasks popup (Shift+3 → `#`). The drill-down for the Ready card.\n//\n// Per design_popup_tasks (workstream `tui`): list of OPEN/IN_PROGRESS\n// tasks with a yank-matrix per task state. v0 ships the list + a\n// subset of the matrix:\n// OPEN ready (no owner) → mu task claim <id> -w <ws>\n// OPEN owned → mu task release <id> -w <ws>\n// IN_PROGRESS owned-by-self → mu task close <id> -w <ws> --evidence \"...\"\n// CLOSED → mu task open <id> -w <ws>\n// Other states yield no yank (toast says so).\n//\n// Enter on a task drills into a read-only inline view of every note\n// on the task (the equivalent of `mu task notes <id>`). j/k scroll;\n// Esc / q backs out to the list; second Esc / q closes the popup.\n//\n// All coordination logic (filter, drill pinning, yank wiring, the\n// early-return states) lives in the shared TaskListPopup scaffold\n// (popups/task-list-popup.tsx). This file is the Ready config: source\n// list, column specs, row mapper/colors, and the yank matrix.\n\nimport type { ReactElement } from \"react\";\nimport { formatPair } from \"../../../tasks/status.js\";\nimport { inkColorForPair } from \"../../format.js\";\nimport { agentByName, formatTaskOwnerDisplay } from \"../agent-display.js\";\nimport type { ColumnSpec } from \"../columns.js\";\nimport {\n type PopupProps,\n type RenderedRow,\n TaskListPopup,\n type TaskListPopupConfig,\n} from \"./task-list-popup.js\";\n\nconst COLUMN_SPECS: ReadonlyArray<ColumnSpec> = [\n { kind: \"protect\" }, // task name\n { kind: \"protect\" }, // status\n { kind: \"protect\" }, // owner (or \"—\")\n { kind: \"clip\", min: 1 }, // title\n];\n\nconst config: TaskListPopupConfig = {\n label: \"Tasks\",\n sourceTasks: (snapshot) => [...snapshot.ready, ...snapshot.inProgress],\n columnSpecs: COLUMN_SPECS,\n filterBlob: (t) => `${t.name} ${t.title} ${formatPair(t)} ${t.ownerName ?? \"\"}`,\n emptyText: \"(no open / in-progress tasks)\",\n yankCommand: (t, ws) => yankCommandForTask(t, ws),\n dynamicHint: (focused, ws) => yankCommandForTask(focused, ws),\n renderRows: (visible, _start, snapshot): RenderedRow[] => {\n const agentLookup = agentByName(snapshot);\n return visible.map((t) => ({\n cells: [t.name, formatPair(t), formatTaskOwnerDisplay(t, agentLookup), t.title],\n colors: [\n { bold: true }, // name\n { color: inkColorForPair(t) }, // status\n { dimColor: true }, // owner\n undefined, // title\n ],\n }));\n },\n};\n\nexport function ReadyPopup(props: PopupProps): ReactElement {\n return <TaskListPopup config={config} {...props} />;\n}\n\nexport function yankCommandForTask(\n t: { name: string; status: string; substate?: string; ownerName: string | null },\n ws: string,\n): string | null {\n switch (t.status) {\n case \"OPEN\":\n if (t.substate === \"parked\") return `mu task unpark ${t.name} -w ${ws}`;\n if (t.substate === \"triage\") return `mu task accept ${t.name} -w ${ws}`;\n return t.ownerName === null\n ? `mu task claim ${t.name} -w ${ws}`\n : `mu task release ${t.name} -w ${ws}`;\n case \"IN_PROGRESS\":\n return `mu task close ${t.name} -w ${ws} --evidence \"...\"`;\n case \"CLOSED\":\n return `mu task open ${t.name} -w ${ws}`;\n default:\n return null;\n }\n}\n","// Recent popup (Shift+8 → `*`). The drill-down for the Recent card.\n//\n// Per feat_popup_8_recent (workstream `tui-impl`). Sibling of\n// popups/inprogress.tsx and popups/ready.tsx — list of recently\n// CLOSED tasks with j/k nav, '/' substring filter, y to yank\n// `mu task open <id> -w <ws>` (re-open is the typical act-intent\n// for a recently-closed task per the popups/ready.tsx CLOSED\n// branch of the yank matrix), and Enter to chain into the shared\n// TaskDetailDrill leaf (the recursion contract from\n// feat_track_drill_chains_to_task_drill — rows ARE tasks).\n//\n// Column shape mirrors Card 8 (cards/recent.tsx) but adds two\n// columns the card was too narrow to fit:\n// glyph id STATUS updated impact effort ROI title\n// (\"updated\" is updated_at, a proxy for close time: a later note or\n// edge on a CLOSED task bumps it.)\n// Per feat_column_aligned_lists clipping policy: every cell except\n// `title` is identity-bearing and PROTECTED; only `title` is\n// CLIPPABLE. Wider title column than the card (more pixels here).\n//\n// All coordination logic lives in the shared TaskListPopup scaffold\n// (popups/task-list-popup.tsx); this file is the Recent config.\n//\n// Per ROADMAP pledge: ink/react import limited to src/cli/tui/*.\n\nimport type { ReactElement } from \"react\";\nimport { formatPair } from \"../../../tasks/status.js\";\nimport { inkColorForPair } from \"../../format.js\";\nimport { GLYPH } from \"../cards/recent.js\";\nimport type { ColumnSpec } from \"../columns.js\";\nimport { ageMs, formatRoi, formatWhen } from \"../format-helpers.js\";\nimport {\n type PopupProps,\n type RenderedRow,\n TaskListPopup,\n type TaskListPopupConfig,\n} from \"./task-list-popup.js\";\n\nconst COLUMN_SPECS: ReadonlyArray<ColumnSpec> = [\n { kind: \"protect\" }, // glyph\n { kind: \"protect\" }, // task id\n { kind: \"protect\" }, // status (always CLOSED; constant for now)\n { kind: \"protect\", align: \"right\" }, // updated_at age (relative-time token)\n { kind: \"protect\", align: \"right\" }, // impact\n { kind: \"protect\", align: \"right\" }, // effort\n { kind: \"protect\", align: \"right\" }, // ROI label\n { kind: \"clip\", min: 1 }, // title\n];\n\nconst config: TaskListPopupConfig = {\n label: \"Recent\",\n sourceTasks: (snapshot) => snapshot.recentClosed,\n columnSpecs: COLUMN_SPECS,\n // Per spec MATCHING RULES: search blob is `${id} ${title} ${owner ?? \"\"}`.\n filterBlob: (t) => `${t.name} ${t.title} ${t.ownerName ?? \"\"}`,\n emptyText: \"(none recently closed)\",\n yankCommand: (t, ws) => yankCommandForTask(t.name, ws),\n hint: \"Enter notes · y yanks `mu task open` · / filter · Esc/q close\",\n renderRows: (visible): RenderedRow[] => {\n const now = Date.now();\n return visible.map((t) => ({\n cells: [\n GLYPH,\n t.name,\n formatPair(t),\n formatWhen(ageMs(t, now)),\n String(t.impact),\n String(t.effortDays),\n formatRoi(t.impact, t.effortDays),\n t.title,\n ],\n colors: [\n { color: \"green\" }, // glyph\n { bold: true }, // id\n { color: inkColorForPair(t) }, // status\n { dimColor: true }, // when\n { dimColor: true }, // impact\n { dimColor: true }, // effort\n { dimColor: true }, // roi\n undefined, // title\n ],\n }));\n },\n};\n\nexport function RecentPopup(props: PopupProps): ReactElement {\n return <TaskListPopup config={config} {...props} />;\n}\n\n/**\n * Yank command for a recently-CLOSED task row. The most likely\n * act-intent on the Recent popup is re-opening the task (per the\n * popups/ready.tsx CLOSED branch of the yank matrix: `mu task open\n * <id> -w <ws>`). Stays consistent so the operator's muscle memory\n * transfers across popups. Pure; exported for unit tests.\n */\nexport function yankCommandForTask(taskName: string, workstream: string): string {\n return `mu task open ${taskName} -w ${workstream}`;\n}\n","// Tracks popup (Shift+2 → `@`). Per design_popup_tracks +\n// feat_track_drill_chains_to_task_drill.\n//\n// Recursion ladder (per popup-drill recursion contract):\n// list → list of tracks (Enter drills)\n// drill → list of tasks for focused track (Enter chains)\n// task-detail → notes timeline for focused task (LEAF; no chain)\n//\n// Esc/q transitions: task-detail → drill → list → close popup.\n//\n// The top-level `mode` prop (owned by <App>) is still a 2-state\n// union (\"list\" | \"drill\") because app.tsx is currently being\n// edited by another agent (sibling task bug_tui_render_ghosting_v2);\n// task-detail is therefore an INTERNAL sub-state of the Tracks\n// popup, kept as a local useState. From <App>'s perspective Tracks\n// is in \"drill\" mode the entire time the user is below the list of\n// tracks, which is exactly what the status-bar drill hint cluster\n// already advertises (j/k scroll · Esc back). When the union is\n// widened to include \"task-detail\" (follow-up integration), this\n// local state collapses into the prop without changing semantics.\n//\n// Read-only: drilling reads from snapshot.tracks[i].taskIds and\n// resolves each id to a TaskRow via getTask; the leaf consumes\n// TaskDetailDrill which SELECTs notes via listNotes. Never executes.\n//\n// Rows are column-aligned via src/cli/tui/columns.ts. Per\n// feat_column_aligned_lists clipping policy: track number, merge glyph,\n// counts are PROTECTED; the goal-name list is CLIPPABLE.\n\nimport { Box, Text } from \"ink\";\nimport { type ReactElement, useEffect, useMemo, useState } from \"react\";\nimport type { Db } from \"../../../db.js\";\nimport { GLYPH } from \"../../../glyphs.js\";\nimport type { WorkstreamSnapshot } from \"../../../state.js\";\nimport { formatPair, type TaskPair } from \"../../../tasks/status.js\";\nimport { listTasks, type TaskRow } from \"../../../tasks.js\";\nimport type { Track } from \"../../../tracks.js\";\nimport { inkColorForPair } from \"../../format.js\";\nimport { type ColumnSpec, contentWidthFromCols, layoutColumns, renderRow } from \"../columns.js\";\nimport { dispatchPopupKeyFromInk, type PopupAction, type PopupActionEnvelope } from \"../keys.js\";\nimport { ListRow } from \"../list-row.js\";\nimport { usePopupInput } from \"../popup-input.js\";\nimport { PopupShell } from \"../popup-shell.js\";\nimport { usePopupActionQueue } from \"../use-popup-action-queue.js\";\nimport { applyFilter, FilterPrompt, listViewport, usePopupFilter } from \"../use-popup-filter.js\";\nimport { useTerminalSize } from \"../use-terminal-size.js\";\nimport { useDrillKeymap } from \"./drill.js\";\nimport { applyCursor, centredVisibleSlice, clickedItem, isNavAction } from \"./scroll.js\";\nimport { renderNotes, TaskDetailDrill } from \"./task-detail.js\";\nimport { POPUP_DRILL_CHROME_ROWS, usePopupViewport } from \"./viewport.js\";\n\nexport interface PopupProps {\n yank: (command: string) => Promise<void>;\n onClose: () => void;\n snapshot: WorkstreamSnapshot | null;\n fastTickNonce: number;\n mode: \"list\" | \"drill\";\n onModeChange: (mode: \"list\" | \"drill\") => void;\n /** Bubbles the filter-prompt edit state up to <App> for StatusBar mode. */\n onFilterEditingChange?: (editing: boolean) => void;\n popupActions?: readonly PopupActionEnvelope[];\n db: Db;\n workstream: string;\n}\n\nconst COLUMN_SPECS: ReadonlyArray<ColumnSpec> = [\n { kind: \"protect\" }, // \"Track N\"\n { kind: \"protect\" }, // diamond glyph (or empty)\n { kind: \"clip\", min: 1 }, // goal names\n { kind: \"protect\" }, // counts\n];\n\nconst DRILL_COLUMN_SPECS: ReadonlyArray<ColumnSpec> = [\n { kind: \"protect\" }, // task id\n { kind: \"protect\" }, // status\n { kind: \"clip\", min: 1 }, // title\n];\n\nconst TRACK_COLORS = [\n { color: \"cyan\" }, // Track N\n undefined, // diamond\n undefined, // goals\n { dimColor: true }, // counts\n] as const;\n\nfunction drillColors(t: TaskPair) {\n return [\n { bold: true }, // name\n { color: inkColorForPair(t) }, // status\n undefined, // title\n ];\n}\n\n// Internal sub-state of the drill view. \"task-list\" = the visible\n// list of tasks for the focused track (where the prop `mode` is\n// `\"drill\"`); \"task-detail\" = the deeper leaf view. See the file\n// header for why this isn't a third value on the prop union.\ntype DrillSubMode = \"task-list\" | \"task-detail\";\n\nexport function TracksPopup({\n yank,\n onClose,\n snapshot,\n fastTickNonce,\n mode,\n onModeChange,\n onFilterEditingChange,\n popupActions,\n db,\n workstream,\n}: PopupProps): ReactElement {\n const { cols } = useTerminalSize();\n const contentWidth = contentWidthFromCols(cols);\n // Per-render viewport from stdout.rows minus the popup chrome budget;\n // see popups/viewport.ts. `viewport` sizes the track list (minus the\n // filter prompt) and the task-list drill; the task-detail leaf is a\n // DrillScrollView, whose title + hint lines need the drill budget.\n const viewport = usePopupViewport();\n const detailViewport = usePopupViewport(POPUP_DRILL_CHROME_ROWS);\n const [cursor, setCursor] = useState(0);\n const [drillCursor, setDrillCursor] = useState(0);\n const [drillSubMode, setDrillSubMode] = useState<DrillSubMode>(\"task-list\");\n // The task-detail leaf is pinned to the task name set when it opens.\n // drillTasks is re-queried and status-sorted on every render, so an\n // index would switch the open leaf when a task changes status.\n const [leafTaskName, setLeafTaskName] = useState<string | null>(null);\n // Filter is only active at the top-level (list-of-tracks) view\n // per spec MATCHING RULES (Tracks blob = head_id + head_title).\n // Drill sub-views own their own navigation; widening the filter\n // to the task-list drill is a follow-up.\n const flt = usePopupFilter({ onEditingChange: onFilterEditingChange });\n const rowsViewport = listViewport(viewport, flt);\n const sourceTracks = snapshot?.tracks ?? [];\n // Per bug_filter_drill_opens_wrong_task: the filter applies in every\n // mode, so the cursor always indexes the list the user sees.\n const tracks = applyFilter(sourceTracks, flt.query, (t) => {\n const head = t.roots[0];\n return `${head?.name ?? \"\"} ${head?.title ?? \"\"}`;\n });\n const safeCursor = tracks.length === 0 ? 0 : Math.min(cursor, tracks.length - 1);\n const listFocusedTrack = tracks[safeCursor];\n // Pin the drilled track at Enter, matched by goal ids on refresh\n // (Track objects are rebuilt every tick), so a reordered or\n // re-filtered list cannot swap the open drill to another track.\n const [drilledTrackKey, setDrilledTrackKey] = useState<string | null>(null);\n const drilledTrack =\n drilledTrackKey === null\n ? undefined\n : sourceTracks.find((t) => trackKey(t) === drilledTrackKey);\n const focusedTrack = mode === \"drill\" ? (drilledTrack ?? listFocusedTrack) : listFocusedTrack;\n // Same numbering as the list rows (position in the filtered list).\n const trackNumber = focusedTrack === undefined ? 0 : tracks.indexOf(focusedTrack) + 1;\n\n // Reset sub-mode + leaf scroll whenever the popup itself flips\n // out of drill mode (e.g. user pressed Esc in the task-list view\n // and we're transitioning back to the list-of-tracks). The\n // entry-into-task-detail scroll reset lives at the keymap site\n // where setDrillSubMode(\"task-detail\") is dispatched.\n useEffect(() => {\n if (mode !== \"drill\") {\n setDrillSubMode(\"task-list\");\n setLeafTaskName(null);\n }\n }, [mode]);\n\n // Resolve the focused track's tasks with one workstream query. The old\n // per-id getTask loop issued two SQL reads per task, which made opening a\n // large track noticeably pause even though the full task list is cheap.\n const drillTasks = useMemo<TaskRow[]>(() => {\n if (mode !== \"drill\" || !focusedTrack) return [];\n const out = listTasks(db, workstream).filter((task) => focusedTrack.taskIds.has(task.name));\n out.sort((a, b) => statusRank(a) - statusRank(b) || a.name.localeCompare(b.name));\n return out;\n }, [mode, focusedTrack, db, workstream]);\n\n const focusedTask =\n drillSubMode === \"task-detail\"\n ? drillTasks.find((t) => t.name === leafTaskName)\n : drillTasks[drillCursor];\n const openLeaf = (index: number) => {\n const t = drillTasks[index];\n if (!t) return;\n setDrillCursor(index);\n setLeafTaskName(t.name);\n setDrillSubMode(\"task-detail\");\n };\n const notesBody = useMemo<string>(() => {\n void fastTickNonce;\n if (mode !== \"drill\" || drillSubMode !== \"task-detail\" || !focusedTask) return \"\";\n return renderNotes(db, focusedTask.name, workstream);\n }, [mode, drillSubMode, focusedTask, db, workstream, fastTickNonce]);\n const taskDetailDrill = useDrillKeymap({\n body: notesBody,\n viewport: detailViewport,\n onClose: () => {\n // Back on the task list, keep the cursor on the task the leaf showed.\n const index = drillTasks.findIndex((t) => t.name === leafTaskName);\n if (index >= 0) setDrillCursor(index);\n setLeafTaskName(null);\n setDrillSubMode(\"task-list\");\n },\n onYank: () => {\n if (!focusedTask || !snapshot) return;\n return yank(`mu task notes ${focusedTask.name} -w ${snapshot.workstreamName}`);\n },\n resetKey: focusedTask?.name ?? \"\",\n });\n\n const dispatchListAction = (action: PopupAction) => {\n if (mode === \"drill\" && drillSubMode === \"task-detail\") {\n taskDetailDrill.dispatch(action);\n return;\n }\n if (mode === \"drill\") {\n if (isNavAction(action)) {\n setDrillCursor((c) => applyCursor(c, action, drillTasks.length, viewport));\n return;\n }\n switch (action.kind) {\n case \"close\":\n onModeChange(\"list\");\n setDrillCursor(0);\n setDrilledTrackKey(null);\n return;\n case \"clickRow\": {\n const hit = clickedItem(drillTasks, drillCursor, viewport, action.row);\n if (!hit) return;\n openLeaf(hit.index);\n return;\n }\n case \"drill\": {\n // Chain into the task-detail leaf. This is the recursion\n // step the task asks for: Enter on a Tracks-drill row\n // opens the same notes view the Tasks popup drill renders.\n openLeaf(drillCursor);\n return;\n }\n case \"yank\": {\n const t = drillTasks[drillCursor];\n if (!t || !snapshot) return;\n void yank(`mu task show ${t.name} -w ${snapshot.workstreamName}`);\n return;\n }\n default:\n return;\n }\n }\n if (isNavAction(action)) {\n setCursor((c) => applyCursor(c, action, tracks.length, rowsViewport));\n return;\n }\n switch (action.kind) {\n case \"close\":\n onClose();\n return;\n case \"filter\":\n flt.startEdit();\n return;\n case \"drill\":\n if (listFocusedTrack) {\n setDrilledTrackKey(trackKey(listFocusedTrack));\n setDrillCursor(0);\n onModeChange(\"drill\");\n }\n return;\n case \"clickRow\": {\n const hit = clickedItem(tracks, safeCursor, rowsViewport, action.row);\n if (!hit) return;\n setCursor(hit.index);\n setDrilledTrackKey(trackKey(hit.item));\n setDrillCursor(0);\n onModeChange(\"drill\");\n return;\n }\n case \"yank\": {\n const t = tracks[safeCursor];\n if (!t || !snapshot) return;\n const goal = t.roots[0]?.name;\n if (!goal) return;\n const ws = snapshot.workstreamName;\n void yank(`mu task tree ${goal} -w ${ws}`);\n return;\n }\n }\n };\n\n usePopupActionQueue(popupActions, dispatchListAction);\n\n usePopupInput((input, key) => {\n if (mode === \"list\" && flt.onKey(input, key) === \"consumed\") return;\n dispatchListAction(dispatchPopupKeyFromInk(input, key));\n });\n\n if (snapshot === null) {\n return <PopupShell title=\"Tracks · popup\">{<Text dimColor>loading…</Text>}</PopupShell>;\n }\n if (sourceTracks.length === 0) {\n return (\n <PopupShell title=\"Tracks · popup\">\n <Text dimColor>(no goals — `mu task add ... --impact ...`)</Text>\n </PopupShell>\n );\n }\n if (mode === \"list\" && tracks.length === 0) {\n return (\n <PopupShell title=\"Tracks · popup\">\n <Box flexDirection=\"column\" flexGrow={1}>\n <Text dimColor>(no matches for \"{flt.query}\")</Text>\n </Box>\n <FilterPrompt state={flt} />\n </PopupShell>\n );\n }\n\n if (mode === \"drill\" && drillSubMode === \"task-detail\" && focusedTrack) {\n const t = focusedTask;\n if (t === undefined) {\n // The pinned task left this track (deleted, or the track split);\n // back to the task list. Render a benign placeholder; the next\n // render shows the task list once setDrillSubMode runs.\n setLeafTaskName(null);\n setDrillSubMode(\"task-list\");\n return (\n <PopupShell title={`Track ${trackNumber} · (resyncing)`}>\n <Text dimColor>(refocusing…)</Text>\n </PopupShell>\n );\n }\n return (\n <PopupShell title={`Track ${trackNumber} · task: ${t.name} (notes)`}>\n <Box flexDirection=\"column\" flexGrow={1}>\n <TaskDetailDrill\n task={t}\n db={db}\n workstream={workstream}\n scrollTop={taskDetailDrill.scrollTop}\n viewport={detailViewport}\n tickNonce={fastTickNonce}\n body={notesBody}\n wrappedBody={taskDetailDrill.wrappedBody}\n />\n </Box>\n </PopupShell>\n );\n }\n\n if (mode === \"drill\" && focusedTrack) {\n const trackLabel = `Track ${trackNumber}`;\n const goalSummary = focusedTrack.roots.map((r) => r.name).join(\", \");\n if (drillTasks.length === 0) {\n return (\n <PopupShell title={`${trackLabel} · ${goalSummary}`}>\n <Text dimColor>(no tasks resolved)</Text>\n </PopupShell>\n );\n }\n const { visible } = centredVisibleSlice(drillTasks, drillCursor, viewport);\n const rows = visible.map((t) => [t.name, formatPair(t), t.title]);\n const widths = layoutColumns(rows, DRILL_COLUMN_SPECS, contentWidth);\n return (\n <PopupShell\n title={`${trackLabel} · ${goalSummary} (${drillCursor + 1}/${drillTasks.length})`}\n hint=\"y yanks `mu task show`\"\n >\n <Box flexDirection=\"column\" flexGrow={1}>\n {visible.map((t, i) => {\n const sel = drillTasks.indexOf(t) === drillCursor;\n const row = rows[i];\n if (row === undefined) return null;\n const padded = renderRow(row, widths, DRILL_COLUMN_SPECS);\n return (\n <ListRow\n key={t.name}\n cells={padded}\n contentWidth={contentWidth}\n colors={drillColors(t)}\n selected={sel}\n />\n );\n })}\n </Box>\n </PopupShell>\n );\n }\n\n const { start, visible } = centredVisibleSlice(tracks, safeCursor, rowsViewport);\n const rows = visible.map((t, i) => {\n const absoluteIndex = start + i;\n const goalNames = t.roots.map((r) => r.name).join(\", \");\n const diamond = t.roots.length > 1 ? GLYPH.merge : \" \";\n const counts = `(${t.taskIds.size} tasks · ${t.readyCount} ready)${t.parked ? \" (parked)\" : \"\"}`;\n return [`Track ${absoluteIndex + 1}`, diamond, goalNames, counts];\n });\n const widths = layoutColumns(rows, COLUMN_SPECS, contentWidth);\n\n return (\n <PopupShell\n title={`Tracks · popup (${safeCursor + 1}/${tracks.length})`}\n hint=\"y yanks `mu task tree <head-id>`\"\n >\n <Box flexDirection=\"column\" flexGrow={1}>\n {visible.map((t, i) => {\n const sel = start + i === safeCursor;\n const row = rows[i];\n if (row === undefined) return null;\n const padded = renderRow(row, widths, COLUMN_SPECS);\n return (\n <ListRow\n // biome-ignore lint/suspicious/noArrayIndexKey: scroll-window position + track root name\n key={`tr-${start + i}-${t.roots[0]?.name ?? \"?\"}`}\n cells={padded}\n contentWidth={contentWidth}\n colors={TRACK_COLORS}\n selected={sel}\n />\n );\n })}\n </Box>\n <FilterPrompt state={flt} />\n </PopupShell>\n );\n}\n\n/** Stable identity for a track across refreshes: its goal ids. */\nfunction trackKey(t: Track): string {\n return t.roots.map((r) => r.name).join(\"\\0\");\n}\n\n/** Drill-view sort rank: work in flight first, then schedulable,\n * then set aside, then finished. */\nexport function statusRank(pair: TaskPair): number {\n switch (pair.status) {\n case \"IN_PROGRESS\":\n return 0;\n case \"OPEN\":\n return pair.substate === \"parked\" ? 2 : 1;\n case \"CLOSED\":\n return 3;\n }\n}\n","// Workspaces popup (Shift+5 → `%`). Drill-down for the Workspaces card.\n//\n// Per feat_popup_5_workspaces (workstream `tui-impl`): list of every\n// per-agent workspace in the workstream, with j/k navigation, '/'\n// filter (via use-popup-filter), and Enter to drill into the\n// commits-since-fork list (same data `mu workspace commits <agent>`\n// surfaces). The drill is the actionable lookup for the cherry-pick\n// loop: orient on which workspace has unmerged commits, then yank a\n// `cd` to that workspace's path.\n//\n// Per feat_workspaces_drill_git_show: a third, deeper level. Pressing\n// Enter on a focused commit in the commits-since-fork list drills\n// ONE MORE LEVEL into a read-only inline view of the actual\n// `git show <sha> --stat -p` output, rendered via the shared\n// <DrillScrollView> primitive (same one log.tsx uses for full\n// payload view). The popup's `mode` prop from <App> stays \"drill\"\n// while in the show view — the show level is a popup-local sub-mode\n// (the localMode state below) so we don't have to widen <App>'s\n// PopupMode union for one popup. j/k Ctrl-D/U scroll the diff; Esc/q back to\n// the commits list; y yanks the bare `git show <sha>` (the operator\n// gets the command, not the captured output).\n//\n// Mirrors the data exposed by Card 5 (cards/workspaces.tsx) — the\n// same WorkstreamSnapshot.workspaces[] rows decorated by\n// withDirty: true (already wired by state.ts) — and adds two columns\n// useful in the fullscreen view: dirty? and the workspace's on-disk\n// path. The card omits both (too narrow); the popup has the room.\n//\n// Read-only: the only act-intent is `y` which yanks\n// cd $(mu workspace path <agent> -w <ws>)\n// — the canonical entry to a workspace per skills/mu (cherry-pick /\n// inspection workflow). No mutating verbs surface here. The drill\n// view is also read-only: it RUNS `listCommitsForWorkspace` (a\n// backend `git log` / `jj log` / `sl log` SELECT-equivalent), never\n// a mutation.\n//\n// Drill is NOT TaskDetailDrill — workspaces aren't tasks. We render\n// commits as a column-aligned `<sha-short> <subject>` list with an\n// independent usePopupFilter applied so '/' substring search across\n// (sha+subject) works in 30+-commit workspaces too.\n//\n// Rows are column-aligned via src/cli/tui/columns.ts. Per\n// feat_column_aligned_lists clipping policy: glyph + agent name +\n// backend + behind + dirty? + parent_ref are PROTECTED (operators\n// yank them verbatim into shell commands); only the path column is\n// CLIPPABLE.\n//\n// Per ROADMAP pledge: ink/react import limited to src/cli/tui/*.\n\nimport { Box, Text } from \"ink\";\nimport { type ReactElement, useCallback, useEffect, useReducer, useRef, useState } from \"react\";\nimport type { Db } from \"../../../db.js\";\nimport type { WorkstreamSnapshot } from \"../../../state.js\";\nimport { type CommitSummary, detectBackend } from \"../../../vcs.js\";\nimport { listCommitsForWorkspace, type WorkspaceRow } from \"../../../workspace.js\";\nimport { agentByName, formatAgentRefDisplayName } from \"../agent-display.js\";\nimport { colorForBehind, colorForGlyph, formatBehind, glyphFor } from \"../cards/workspaces.js\";\nimport { type ColumnSpec, contentWidthFromCols, layoutColumns, renderRow } from \"../columns.js\";\nimport { dispatchPopupKeyFromInk, type PopupAction, type PopupActionEnvelope } from \"../keys.js\";\nimport { ListRow } from \"../list-row.js\";\nimport { usePopupInput } from \"../popup-input.js\";\nimport { PopupShell } from \"../popup-shell.js\";\nimport { runTuicrInteractive } from \"../tuicr.js\";\nimport { usePopupActionQueue } from \"../use-popup-action-queue.js\";\nimport { applyFilter, FilterPrompt, listViewport, usePopupFilter } from \"../use-popup-filter.js\";\nimport { useTerminalSize } from \"../use-terminal-size.js\";\nimport { DrillScrollView, useDrillKeymap } from \"./drill.js\";\nimport { applyCursor, centredVisibleSlice, clickedItem, isNavAction } from \"./scroll.js\";\nimport { loadShowPreservingBody } from \"./show-loader.js\";\nimport { POPUP_DRILL_CHROME_ROWS, usePopupViewport } from \"./viewport.js\";\n\nexport interface PopupProps {\n yank: (command: string) => Promise<void>;\n onClose: () => void;\n snapshot: WorkstreamSnapshot | null;\n slowTickNonce: number;\n mode: \"list\" | \"drill\";\n onModeChange: (mode: \"list\" | \"drill\") => void;\n /** Bubbles the filter-prompt edit state up to <App> for StatusBar mode. */\n onFilterEditingChange?: (editing: boolean) => void;\n popupActions?: readonly PopupActionEnvelope[];\n onFooter?: (command: string, copied: boolean, tone?: \"normal\" | \"info\" | \"error\") => void;\n db: Db;\n workstream: string;\n}\n\nconst COLUMN_SPECS: ReadonlyArray<ColumnSpec> = [\n { kind: \"protect\" }, // status glyph\n { kind: \"protect\" }, // agent name\n { kind: \"protect\" }, // backend\n { kind: \"protect\", align: \"right\" }, // commits-behind\n { kind: \"protect\" }, // dirty? (yes / no / —)\n { kind: \"protect\" }, // parent_ref short\n { kind: \"clip\", min: 1 }, // path\n];\n\nconst DRILL_COLUMN_SPECS: ReadonlyArray<ColumnSpec> = [\n { kind: \"protect\" }, // sha short\n { kind: \"clip\", min: 1 }, // subject\n];\n\nconst COMMIT_COLORS = [\n { color: \"yellow\" }, // sha\n undefined, // subject\n] as const;\n\ntype LocalMode = \"list\" | \"commits\" | \"show\";\n\ninterface LocalModeState {\n mode: LocalMode;\n drilledWorkspace: WorkspaceRow | null;\n showSha: string | null;\n showText: string;\n showLoading: boolean;\n showErr: string | null;\n}\n\ntype LocalModeAction =\n | { kind: \"leaveDrill\" }\n | { kind: \"enterDrill\"; workspace: WorkspaceRow }\n | { kind: \"enterShow\"; sha: string }\n | { kind: \"leaveShow\" }\n | { kind: \"resetForWorkspace\"; agentName: string | undefined }\n | { kind: \"setShowText\"; text: string }\n | { kind: \"setShowLoading\"; loading: boolean }\n | { kind: \"setShowError\"; error: string | null };\n\nconst LOCAL_MODE_INITIAL_STATE: LocalModeState = {\n mode: \"list\",\n drilledWorkspace: null,\n showSha: null,\n showText: \"\",\n showLoading: false,\n showErr: null,\n};\n\nfunction clearShowState(state: LocalModeState): LocalModeState {\n return { ...state, showSha: null, showText: \"\", showLoading: false, showErr: null };\n}\n\nfunction localModeReducer(state: LocalModeState, action: LocalModeAction): LocalModeState {\n switch (action.kind) {\n case \"leaveDrill\":\n return LOCAL_MODE_INITIAL_STATE;\n case \"enterDrill\":\n return { ...clearShowState(state), mode: \"commits\", drilledWorkspace: action.workspace };\n case \"enterShow\":\n return { ...state, mode: \"show\", showSha: action.sha };\n case \"leaveShow\":\n return { ...state, mode: \"commits\", showSha: null };\n case \"resetForWorkspace\":\n if (state.mode === \"list\") return state;\n if (state.drilledWorkspace?.agentName === action.agentName) return state;\n return { ...clearShowState(state), mode: \"commits\" };\n case \"setShowText\":\n return { ...state, showText: action.text };\n case \"setShowLoading\":\n return { ...state, showLoading: action.loading };\n case \"setShowError\":\n return { ...state, showErr: action.error };\n }\n}\n\n// Both drill views render a title line above and a hint line below\n// their rows (commits list: renderDrillBody; git show: DrillScrollView),\n// so they use the drill chrome budget. List view uses the default.\nconst WORKSPACES_DRILL_CHROME = POPUP_DRILL_CHROME_ROWS;\n// The commits drill's title line sits above its first data row.\nconst COMMITS_DRILL_HEADER_ROWS = 1;\n\nexport function WorkspacesPopup({\n yank,\n onClose,\n snapshot,\n slowTickNonce,\n mode,\n onModeChange,\n onFilterEditingChange,\n popupActions,\n onFooter,\n db,\n workstream,\n}: PopupProps): ReactElement {\n const { cols } = useTerminalSize();\n const contentWidth = contentWidthFromCols(cols);\n // Per-render viewport from stdout.rows minus the popup chrome budget;\n // see popups/viewport.ts. Replaces the prior hardcoded VIEWPORT = 20.\n // Workspaces popup uses the viewport in the DRILL view (centring\n // + page nav for the commits-since-fork list); list view\n // paginates by single-row cursor moves under j/k AND also consumes\n // the viewport for the centralised Ctrl-D/U / PgUp/PgDn page-step\n // bindings (per feat_centralize_scroll_navigation). Drill subtracts\n // an extra row for its in-body title indicator\n // (see WORKSPACES_DRILL_CHROME above).\n const viewport = usePopupViewport();\n const drillViewport = usePopupViewport(WORKSPACES_DRILL_CHROME);\n const [cursor, setCursor] = useState(0);\n // Drill-mode state. Owned here (not in <App>) because it's\n // popup-local: <App> only tracks the list/drill mode flag for\n // StatusBar purposes. Cursor + commit list + load state die with\n // the popup.\n const [drillCursor, setDrillCursor] = useState(0);\n const [commits, setCommits] = useState<readonly CommitSummary[]>([]);\n const [drillErr, setDrillErr] = useState<string | null>(null);\n const [loading, setLoading] = useState(false);\n // Popup-local sub-mode. <App> still only tracks \"list\" | \"drill\"\n // for the StatusBar; inside the workspaces popup, the drill branch\n // is explicit: commits list vs git-show body. `showSha` is only\n // meaningful while localMode === \"show\".\n const [localModeState, dispatchLocalMode] = useReducer(\n localModeReducer,\n LOCAL_MODE_INITIAL_STATE,\n );\n const localMode: LocalMode = mode === \"drill\" ? localModeState.mode : \"list\";\n const inShow = localMode === \"show\";\n const { showSha, showText, showLoading, showErr } = localModeState;\n\n // Two independent filter instances: one for the workspace list,\n // one for the commits drill view. Each '/' edit applies to the\n // currently-rendered list only. The `enabled` prop tells each\n // instance whether it's the currently-active filter; the hook\n // bubbles the editing flag up to <App> for the active one and\n // bubbles `false` for the inactive one — no hand-rolled\n // conditional useEffect at the call site\n // (per review_tui_workspaces_two_filter_instances). Show-mode\n // never edits a filter (read-only diff view) so both instances\n // are disabled while localMode === \"show\".\n const flt = usePopupFilter({\n enabled: !inShow && mode !== \"drill\",\n onEditingChange: onFilterEditingChange,\n });\n const drillFlt = usePopupFilter({\n enabled: !inShow && mode === \"drill\",\n onEditingChange: onFilterEditingChange,\n });\n\n const rowsViewport = listViewport(viewport, flt);\n const commitsViewport = listViewport(drillViewport, drillFlt);\n\n const sourceWorkspaces = snapshot?.workspaces ?? [];\n // Per bug_filter_drill_opens_wrong_task: text filter applied\n // UNIFORMLY across list and drill modes (the previous mode-conditional\n // dropped the filter on drill, shifting `workspaces` under a constant\n // cursor index).\n const workspaces = applyFilter(\n sourceWorkspaces,\n flt.query,\n (w) => `${w.agentName} ${w.backend} ${w.parentRef ?? \"\"} ${w.dirty === true ? \"dirty\" : \"\"}`,\n );\n const safeCursor = workspaces.length === 0 ? 0 : Math.min(cursor, workspaces.length - 1);\n const focusedListRow = workspaces[safeCursor];\n // Defensive: capture focused workspace at Enter so the drill stays\n // pinned to the workspace the user visually selected.\n const drilledWorkspace = localModeState.drilledWorkspace;\n const focused = localMode === \"list\" ? focusedListRow : (drilledWorkspace ?? focusedListRow);\n const projectRoot = process.cwd();\n\n /** Thin React glue around the shared VcsBackend.showCommit seam. */\n const loadShow = useCallback(async (path: string, sha: string) => {\n await loadShowPreservingBody(path, sha, detectBackend, {\n setText: (text) => dispatchLocalMode({ kind: \"setShowText\", text }),\n setError: (error) => dispatchLocalMode({ kind: \"setShowError\", error }),\n setLoading: (loading) => dispatchLocalMode({ kind: \"setShowLoading\", loading }),\n });\n }, []);\n\n // Filtered commits view (drill-mode equivalent of `workspaces`).\n const filteredCommits = applyFilter(commits, drillFlt.query, (c) => `${c.sha} ${c.subject}`);\n const safeDrillCursor =\n filteredCommits.length === 0 ? 0 : Math.min(drillCursor, filteredCommits.length - 1);\n const focusedCommit = filteredCommits[safeDrillCursor];\n\n // Load commits when entering drill mode (or when the focused row\n // changes while in drill mode — same-shape lazy fetch as\n // AgentsPopup's loadScrollback). listCommitsForWorkspace is a\n // backend `git log`-equivalent; never a mutation.\n const loadCommits = useCallback(\n async (agentName: string) => {\n setLoading(true);\n setDrillErr(null);\n try {\n const r = await listCommitsForWorkspace(db, agentName, { workstream });\n // Newest-first reads better in a \"what's stacked on top of\n // fork?\" view; the backend returns oldest-first. Reverse a\n // copy (don't mutate the source).\n setCommits([...r.commits].reverse());\n } catch (e) {\n setDrillErr(e instanceof Error ? e.message : String(e));\n setCommits([]);\n } finally {\n setLoading(false);\n }\n },\n [db, workstream],\n );\n\n const focusedAgentName = focused?.agentName;\n const previousFocusedAgentName = useRef<string | undefined>(undefined);\n const resetDrillFilter = drillFlt.reset;\n useEffect(() => {\n const focusedChanged = previousFocusedAgentName.current !== focusedAgentName;\n previousFocusedAgentName.current = focusedAgentName;\n\n if (focusedChanged) {\n dispatchLocalMode({ kind: \"resetForWorkspace\", agentName: focusedAgentName });\n setDrillCursor(0);\n setCommits([]);\n resetDrillFilter();\n }\n if (mode !== \"drill\") {\n dispatchLocalMode({ kind: \"leaveDrill\" });\n setCommits([]);\n setDrillErr(null);\n setLoading(false);\n }\n }, [mode, focusedAgentName, resetDrillFilter]);\n\n useEffect(() => {\n void slowTickNonce;\n if (localMode === \"commits\" && focused) {\n void loadCommits(focused.agentName);\n }\n }, [localMode, focused, loadCommits, slowTickNonce]);\n\n const showBody = showErr !== null ? `error: ${showErr}` : showText;\n useEffect(() => {\n void slowTickNonce;\n if (localMode === \"show\" && focused !== undefined && showSha !== null) {\n void loadShow(focused.path, showSha);\n }\n }, [localMode, focused, showSha, loadShow, slowTickNonce]);\n\n const showDrill = useDrillKeymap({\n body: showBody,\n viewport: drillViewport,\n onClose: () => dispatchLocalMode({ kind: \"leaveShow\" }),\n onYank: () => {\n if (showSha !== null) return yank(`git show ${showSha}`);\n },\n onTuicr: () => {\n if (showSha === null) return;\n const r = runTuicrInteractive({ rev: showSha, cwd: projectRoot });\n if (!r.ok) onFooter?.(r.error ?? \"tuicr failed\", false, \"error\");\n else onFooter?.(`tuicr -r ${showSha}`, true, \"info\");\n },\n resetKey: showSha ?? \"\",\n });\n\n const dispatchListAction = (action: PopupAction) => {\n if (localMode === \"show\") {\n showDrill.dispatch(action);\n return;\n }\n if (localMode === \"commits\") {\n // Drill-mode commits list: nav funnels through applyCursor.\n // '/' filters the commits list, Enter drills ONE MORE LEVEL\n // into the focused commit's `git show` diff\n // (feat_workspaces_drill_git_show), Esc/q backs out to the\n // workspace list. Yank in drill mode yanks `git show <sha>`\n // for the focused commit (cherry-pick target inspection).\n if (isNavAction(action)) {\n setDrillCursor((c) => applyCursor(c, action, filteredCommits.length, commitsViewport));\n return;\n }\n switch (action.kind) {\n case \"close\":\n dispatchLocalMode({ kind: \"leaveDrill\" });\n onModeChange(\"list\");\n return;\n case \"filter\":\n drillFlt.startEdit();\n return;\n case \"drill\": {\n const c = focusedCommit;\n if (!c || !focused) return;\n dispatchLocalMode({ kind: \"enterShow\", sha: c.sha });\n return;\n }\n case \"clickRow\": {\n const hit = clickedItem(\n filteredCommits,\n safeDrillCursor,\n commitsViewport,\n action.row,\n COMMITS_DRILL_HEADER_ROWS,\n );\n if (!hit || !focused) return;\n setDrillCursor(hit.index);\n dispatchLocalMode({ kind: \"enterShow\", sha: hit.item.sha });\n return;\n }\n case \"yank\": {\n const c = focusedCommit;\n if (!c) return;\n // Cherry-pick recipe per skills/mu: `git cherry-pick <sha>`\n // is the canonical follow-on. Yank the bare `git show` for\n // the focused commit so the operator can inspect first.\n void yank(`git show ${c.sha}`);\n return;\n }\n default:\n return;\n }\n }\n if (isNavAction(action)) {\n setCursor((c) => applyCursor(c, action, workspaces.length, rowsViewport));\n return;\n }\n switch (action.kind) {\n case \"close\":\n onClose();\n return;\n case \"filter\":\n flt.startEdit();\n return;\n case \"drill\":\n if (focusedListRow) {\n dispatchLocalMode({ kind: \"enterDrill\", workspace: focusedListRow });\n onModeChange(\"drill\");\n }\n return;\n case \"clickRow\": {\n const hit = clickedItem(workspaces, safeCursor, rowsViewport, action.row);\n if (!hit) return;\n setCursor(hit.index);\n dispatchLocalMode({ kind: \"enterDrill\", workspace: hit.item });\n onModeChange(\"drill\");\n return;\n }\n case \"yank\": {\n const w = focusedListRow;\n if (!w || !snapshot) return;\n const ws = snapshot.workstreamName;\n // Default yank: `cd $(mu workspace path <agent> -w <ws>)` —\n // the canonical entry to a workspace per skills/mu's\n // cherry-pick / inspection-workflow recipe.\n void yank(`cd $(mu workspace path ${w.agentName} -w ${ws})`);\n return;\n }\n }\n };\n\n usePopupActionQueue(popupActions, dispatchListAction);\n\n usePopupInput((input, key) => {\n // Filter-mode keystrokes consume printable + Esc/Enter/Bksp.\n // The active filter depends on which view we're rendering.\n // Show-mode is read-only — no filter prompt — so we skip the\n // consume check entirely (lets Esc fire as close, not\n // filter-cancel).\n const activeFlt = localMode === \"commits\" ? drillFlt : flt;\n if (localMode !== \"show\" && activeFlt.onKey(input, key) === \"consumed\") return;\n dispatchListAction(dispatchPopupKeyFromInk(input, key));\n });\n\n if (snapshot === null) {\n return <PopupShell title=\"Workspaces · popup\">{<Text dimColor>loading…</Text>}</PopupShell>;\n }\n if (localMode === \"show\" && showSha !== null && focused) {\n const shortSha = showSha.slice(0, 12);\n return (\n <PopupShell title={`Workspaces · git show ${shortSha}`}>\n <Box flexDirection=\"column\" flexGrow={1}>\n <DrillScrollView\n title={`git show ${shortSha} (${focused.agentName})`}\n body={showBody}\n viewport={drillViewport}\n scrollTop={showDrill.scrollTop}\n wrappedBody={showDrill.wrappedBody}\n hint={`y yanks \\`git show ${shortSha}\\` · t tuicr`}\n emptyText={showLoading ? \"loading…\" : \"(empty diff)\"}\n />\n </Box>\n </PopupShell>\n );\n }\n if (sourceWorkspaces.length === 0) {\n return (\n <PopupShell title=\"Workspaces · popup\">\n <Text dimColor>\n (no workspaces) try `mu agent spawn worker-1 -w {snapshot.workstreamName} --workspace`\n </Text>\n </PopupShell>\n );\n }\n if (localMode === \"list\" && workspaces.length === 0) {\n return (\n <PopupShell title=\"Workspaces · popup\">\n <Box flexDirection=\"column\" flexGrow={1}>\n <Text dimColor>(no matches for \"{flt.query}\")</Text>\n </Box>\n <FilterPrompt state={flt} />\n </PopupShell>\n );\n }\n\n if (localMode === \"commits\" && focused) {\n return (\n <PopupShell title={`Workspaces · ${focused.agentName} (commits since fork)`}>\n <Box flexDirection=\"column\" flexGrow={1}>\n {renderDrillBody(\n commits,\n filteredCommits,\n safeDrillCursor,\n loading,\n drillErr,\n focused,\n contentWidth,\n commitsViewport,\n )}\n </Box>\n <FilterPrompt state={drillFlt} />\n </PopupShell>\n );\n }\n\n const { start, visible } = centredVisibleSlice(workspaces, safeCursor, rowsViewport);\n const agentLookup = agentByName(snapshot);\n const rows = visible.map((w) => [\n glyphFor(w),\n formatAgentRefDisplayName(w.agentName, agentLookup),\n w.backend,\n formatBehind(w.commitsBehindMain),\n formatDirty(w.dirty),\n w.parentRef ? w.parentRef.slice(0, 12) : \"—\",\n w.path,\n ]);\n const widths = layoutColumns(rows, COLUMN_SPECS, contentWidth);\n\n return (\n <PopupShell\n title={`Workspaces · popup (${safeCursor + 1}/${workspaces.length})`}\n hint=\"y yanks `cd $(mu workspace path <agent>)`\"\n >\n <Box flexDirection=\"column\" flexGrow={1}>\n {visible.map((w, i) => {\n const sel = start + i === safeCursor;\n const row = rows[i];\n if (row === undefined) return null;\n const padded = renderRow(row, widths, COLUMN_SPECS);\n const colors = [\n { color: colorForGlyph(w) }, // glyph\n { bold: true }, // name\n { dimColor: true }, // backend\n { color: colorForBehind(w.commitsBehindMain) }, // behind\n { color: colorForDirty(w.dirty) }, // dirty\n { dimColor: true }, // parent\n { dimColor: true }, // path\n ];\n return (\n <ListRow\n key={w.agentName}\n cells={padded}\n contentWidth={contentWidth}\n colors={colors}\n selected={sel}\n />\n );\n })}\n </Box>\n <FilterPrompt state={flt} />\n </PopupShell>\n );\n}\n\n// ─── pure helpers (exported for unit tests) ────────────────────────\n\n/** Render the dirty? cell. \"yes\" when dirty, \"no\" when clean,\n * \"—\" when unknown (workspace decoration failed or backend has no\n * dirty concept). Mirrors the card's three-glyph state space. */\nexport function formatDirty(d: boolean | null | undefined): string {\n if (d === undefined || d === null) return \"—\";\n return d ? \"yes\" : \"no\";\n}\n\n/** Picocolors-compatible colour name for the dirty? cell. Red for\n * dirty (load-bearing — uncommitted work to deal with); dim for\n * clean / unknown so the eye snaps to the actionable rows. */\nexport function colorForDirty(d: boolean | null | undefined): string | undefined {\n if (d === true) return \"red\";\n return undefined;\n}\n\n// ─── drill body renderer ───────────────────────────────────────────\n\nfunction renderDrillBody(\n source: readonly CommitSummary[],\n filtered: readonly CommitSummary[],\n cursor: number,\n loading: boolean,\n err: string | null,\n focused: WorkspaceRow,\n contentWidth: number,\n viewport: number,\n): ReactElement {\n const title = `commits for ${focused.agentName}`;\n const hint = \"y yanks `git show <sha>`\";\n if (loading && source.length === 0) {\n return (\n <DrillScrollView\n title={title}\n body=\"loading…\"\n viewport={viewport}\n scrollTop={0}\n hint={hint}\n />\n );\n }\n if (err !== null) {\n return (\n <DrillScrollView\n title={title}\n body={`error: ${err}`}\n viewport={viewport}\n scrollTop={0}\n hint={hint}\n />\n );\n }\n if (source.length === 0) {\n const parent = focused.parentRef ? focused.parentRef.slice(0, 12) : \"(none)\";\n return (\n <DrillScrollView\n title={title}\n body={`(no commits since fork — workspace is at parent_ref ${parent})`}\n viewport={viewport}\n scrollTop={0}\n hint={hint}\n />\n );\n }\n if (filtered.length === 0) {\n return <DrillScrollView title={title} body=\"(no matches)\" viewport={viewport} scrollTop={0} />;\n }\n\n const { visible } = centredVisibleSlice(filtered, cursor, viewport);\n const rows = visible.map((c) => [c.sha.slice(0, 12), c.subject]);\n const widths = layoutColumns(rows, DRILL_COLUMN_SPECS, contentWidth);\n // Inline render — NO nested TitledBox here. The popup's PopupShell\n // already drew the cyan rounded chrome; a nested magenta TitledBox\n // at width=stdout.columns would overflow the popup's inner content\n // area by 4 cols (popup chrome) and make rows wrap past the\n // border. Mirrors the central fix in src/cli/tui/popups/drill.tsx\n // (commit 5e334f6 — bug_tui_drill_text_no_width_pin).\n return (\n <Box flexDirection=\"column\" flexGrow={1}>\n <Box>\n <Text bold color=\"magenta\">\n {title}\n </Text>\n <Text dimColor>\n {\" \"}\n · {cursor + 1}/{filtered.length}\n </Text>\n </Box>\n <Box flexDirection=\"column\" flexGrow={1}>\n {visible.map((c, i) => {\n const sel = filtered.indexOf(c) === cursor;\n const row = rows[i];\n if (row === undefined) return null;\n const padded = renderRow(row, widths, DRILL_COLUMN_SPECS);\n return (\n <ListRow\n key={c.sha}\n cells={padded}\n contentWidth={contentWidth}\n colors={COMMIT_COLORS}\n selected={sel}\n />\n );\n })}\n </Box>\n <Box>\n <Text dimColor>{hint}</Text>\n </Box>\n </Box>\n );\n}\n","// React hook + tick-rate constants for the TUI's poll loop.\n//\n// Per design_poll_loop (workstream `tui`): simple poll, single\n// setInterval owned by <Dashboard>, synchronous better-sqlite3 reads\n// (no race possible by construction), tick rate adjustable live with\n// +/- (floor 100ms, ceiling 10s, default 1s), no persistence.\n//\n// The hook pauses fetches when `enabled === false`. <App> keeps it\n// enabled while popups are open so visible drill-down views can share\n// the same fast/slow refresh cadence as the dashboard.\n//\n// Re-render guard (bug_tui_flicker_on_every_tick, workstream\n// `tui-impl`):\n//\n// The naive unconditional setData on every tick was the bug;\n// forced React/ink to diff a brand-new top-level state object,\n// which in turn re-rendered every card body — a perceptible\n// full-frame flash 1×/sec on any stable workstream.\n//\n// Three-layer fix lives here:\n// LAYER A: stringify a `snapshotKey()` of the visible-affecting\n// fields and short-circuit setData when the key is\n// byte-equal to the previous one. The hook returns the\n// SAME `data` reference across no-op ticks so ink's\n// prop-diff bottoms out at the cards.\n// LAYER B: tick-duration and drill-refresh nonces publish only\n// when the snapshot key changes (or an error clears), so\n// no-op poll intervals do not force a whole-App render.\n// LAYER C: the dashboard fast tick does NOT preload the exhaustive\n// all-tasks list; the All-tasks popup reads SQLite\n// directly while open.\n//\n// Per-card useMemo is intentionally skipped — Layers A/B stop the\n// new-prop cascade at the top-level `data` reference, which is\n// enough in practice. Revisit only if visible flicker regresses\n// against a stable workstream.\n\nimport { existsSync } from \"node:fs\";\nimport { fileURLToPath } from \"node:url\";\nimport { Worker } from \"node:worker_threads\";\nimport { useEffect, useRef, useState } from \"react\";\nimport { type Db, tryResolveWorkstreamId } from \"../../db.js\";\nimport {\n type LoadWorkstreamSnapshotOptions,\n loadWorkstreamSnapshotFast,\n loadWorkstreamSnapshotSlow,\n mergeSnapshotFastSlow,\n type WorkstreamSnapshot,\n type WorkstreamSnapshotSlowFields,\n} from \"../../state.js\";\nimport { ambientSyncPass, syncEnabled } from \"../../sync.js\";\nimport type { CardId } from \"./layout.js\";\n\nexport const TICK_DEFAULT_MS = 1000;\nexport const TICK_FLOOR_MS = 100;\nexport const TICK_CEILING_MS = 10_000;\nexport const SLOW_TICK_MS = 10_000;\nconst NO_OBSERVED_WORKSTREAMS: readonly string[] = [];\n\n/**\n * Guard so N workstream tabs do not each run a sync pass on the same\n * 10s beat. The hook is instantiated per tab; the sync pass is a\n * whole-DB, whole-sync-dir operation with nothing per-workstream about\n * it, so one per beat is exactly right and N would be N-1 wasted\n * ingests fighting over the same file lock.\n */\nlet syncInFlight = false;\n\n/** Built next to dist/cli.js by tsup (entry `tui-sync-worker`). Absent\n * when running from source (vitest), where the pass runs in-process. */\nconst BUILT_SYNC_WORKER_PATH = fileURLToPath(new URL(\"./tui-sync-worker.js\", import.meta.url));\nlet syncWorkerPath = BUILT_SYNC_WORKER_PATH;\ntype SyncPassResult = Awaited<ReturnType<typeof ambientSyncPass>>;\ntype SyncWorkerState = { worker: Worker; done: ((r: SyncPassResult | null) => void) | null };\nlet syncWorker: SyncWorkerState | null = null;\n\n/** Test seam: point the worker path at a built bundle (or back to the\n * default with null), dropping any running worker. */\nexport async function setSyncWorkerPathForTests(path: string | null): Promise<void> {\n syncWorkerPath = path ?? BUILT_SYNC_WORKER_PATH;\n const state = syncWorker;\n syncWorker = null;\n await state?.worker.terminate();\n}\n\n/** Test seam: the live sync worker, if one is running. */\nexport function syncWorkerForTests(): Worker | null {\n return syncWorker?.worker ?? null;\n}\n\n/** One pass in the worker_thread, started lazily and kept for the TUI's\n * life (`unref`, so it never holds the process open). A worker that\n * dies settles its pass with null and is respawned on the next beat. */\nfunction workerSyncPass(dbPath: string): Promise<SyncPassResult | null> {\n if (syncWorker === null) {\n const worker = new Worker(syncWorkerPath, { workerData: { dbPath } });\n worker.unref();\n const state: SyncWorkerState = { worker, done: null };\n const settle = (result: SyncPassResult | null) => {\n const done = state.done;\n state.done = null;\n done?.(result);\n };\n worker.on(\"message\", (result: SyncPassResult | null) => settle(result));\n const drop = () => {\n if (syncWorker === state) syncWorker = null;\n settle(null);\n };\n worker.on(\"error\", drop);\n worker.on(\"exit\", drop);\n syncWorker = state;\n }\n const state = syncWorker;\n return new Promise((resolve) => {\n state.done = resolve;\n state.worker.postMessage(null);\n });\n}\n\n/**\n * The TUI's share of the AMBIENT sync hook.\n *\n * Hung off the SLOW tick (10s) and never the fast one: sync is\n * filesystem work — readdir, stat, read, a cross-process file lock —\n * and the fast tick is a repaint cadence an operator can wind down to\n * 100ms with `-`. At 100ms this would be 10 sync passes a second on a\n * shared folder.\n *\n * `quiet: true` because the TUI owns the alternate screen: a stderr\n * warning would paint garbage over the dashboard. Sync problems surface\n * through the Doctor card instead, which is where a TUI operator looks.\n *\n * Total by construction (see src/sync.ts): a broken segment or an\n * unreadable sync dir must never take the dashboard down. Resolves to\n * the pass's result, or null when skipped (sync off, a pass already in\n * flight) or failed (including a worker that died mid-pass).\n */\nexport async function tuiSyncPass(db: Db): Promise<SyncPassResult | null> {\n if (!syncEnabled() || syncInFlight) return null;\n syncInFlight = true;\n try {\n // Off ink's thread when the bundle has the worker and the DB is a\n // file a second connection can open; in-process otherwise.\n if (db.name !== \":memory:\" && existsSync(syncWorkerPath)) {\n return await workerSyncPass(db.name);\n }\n return await ambientSyncPass(db, { quiet: true });\n } catch {\n // Never let sync fail a repaint.\n return null;\n } finally {\n syncInFlight = false;\n }\n}\n\n/**\n * Per-card on/off state for the dashboard. Keyed by numeric CardId\n * (0..9) — the same key that CARD_CONFIGS, CARD_REGISTRY,\n * POPUP_REGISTRY, and dataCountForCard already use.\n *\n * Pre-review_tui_card_key_from_id_redundant this was keyed by\n * string (\"agents\", \"tracks\", \"ready\", …), which forced a\n * 24-line `cardKeyFromId` switch every keystroke and every render\n * to bridge to the numeric id. Folding the keys back into the\n * shared CardId space eliminates the bridge and keeps the per-card\n * `name` string as the human-friendly identifier on CARD_CONFIGS.\n */\nexport type CardVisibility = Record<CardId, boolean>;\n\nexport const DEFAULT_CARD_VISIBILITY: CardVisibility = {\n 0: true,\n 1: true,\n 2: true,\n 3: true,\n 4: true,\n 5: true,\n 6: true,\n 7: true,\n 8: true,\n 9: true,\n};\n\nexport interface DashboardSnapshot {\n data: WorkstreamSnapshot | null;\n /** Increments after a fast SQL-only tick publishes a changed\n * snapshot. Drill views that read SQLite directly include this in\n * memo deps, while no-op ticks stay render-silent. */\n fastTickNonce: number;\n /** Increments after a slow subprocess tick publishes a changed\n * snapshot. Drill views that shell out (tmux scrollback, VCS show)\n * include this instead of fastTickNonce to avoid 1s subprocess\n * churn; no-op slow ticks stay render-silent. */\n slowTickNonce: number;\n /** Measured fetch duration of the most recent published fast tick\n * (ms). No-op ticks intentionally leave this unchanged so the\n * status path does not repaint an otherwise stable frame. */\n lastTickMs: number;\n error: string | null;\n /** Launch-time workstreams whose DB row has since been torn down. */\n tornDownWorkstreams: ReadonlySet<string>;\n}\n\nexport interface DashboardSnapshotLoaders {\n fast: (\n db: Db,\n workstream: string,\n opts?: LoadWorkstreamSnapshotOptions,\n ) => Promise<WorkstreamSnapshot>;\n slow: (\n db: Db,\n workstream: string,\n opts?: LoadWorkstreamSnapshotOptions,\n baseSnapshot?: WorkstreamSnapshot,\n ) => Promise<WorkstreamSnapshotSlowFields>;\n}\n\nconst DEFAULT_LOADERS: DashboardSnapshotLoaders = {\n fast: loadWorkstreamSnapshotFast,\n slow: loadWorkstreamSnapshotSlow,\n};\n\nconst FAST_OPTS: LoadWorkstreamSnapshotOptions = {\n eventLimit: 200,\n};\n\nconst SLOW_OPTS: LoadWorkstreamSnapshotOptions = {\n withDirty: true,\n withDoctor: true,\n withRecentCommits: { limit: 25 },\n};\n\nexport interface DashboardSnapshotOptions {\n /** Launch-time tabs to check for teardown on every fast tick. */\n observedWorkstreams?: readonly string[];\n /**\n * When true, slowTickNonce advances even if the slow-tier snapshot\n * is byte-equal. Used only for subprocess-backed popup drills\n * (agent scrollback / git show) whose body can change without a DB\n * snapshot change. Dashboard and task-list views keep this false so\n * stable frames stay render-silent.\n */\n publishNoopSlowTicks?: boolean;\n}\n\n/**\n * Subscribe to the workstream snapshot via a setInterval-owned poll\n * loop. Re-fetches every `tickMs` while `enabled` is true.\n *\n * Re-render guard: returns the SAME `data` reference across ticks\n * whose visible content (`snapshotKey`) is unchanged, so React/ink\n * diff against the cards bottoms out cheaply. Tick-duration and\n * drill-refresh nonces publish only when the visible snapshot changes\n * (or an error clears), so stable workstreams do not repaint once per\n * poll interval.\n *\n * `refreshNonce` is the optional refresh-now signal\n * (review_dead_code_refresh_now): every distinct value forces an\n * immediate re-fetch by re-running the effect. Wired through to the\n * effect's dep list so bumping it from <App> on the `r` / F5\n * keypress restarts the interval and runs `tick()` synchronously.\n * Defaults to 0 when unwired so existing callers keep working.\n */\nexport function useDashboardSnapshot(\n db: Db,\n workstream: string,\n tickMs: number,\n enabled: boolean,\n refreshNonce = 0,\n loaders: DashboardSnapshotLoaders = DEFAULT_LOADERS,\n options: DashboardSnapshotOptions = {},\n): DashboardSnapshot {\n const publishNoopSlowTicks = options.publishNoopSlowTicks === true;\n const observedWorkstreams = options.observedWorkstreams ?? NO_OBSERVED_WORKSTREAMS;\n const [tornDownWorkstreams, setTornDownWorkstreams] = useState<ReadonlySet<string>>(new Set());\n // Layer A: data + error (the stuff the cards read).\n const [data, setData] = useState<{ data: WorkstreamSnapshot | null; error: string | null }>({\n data: null,\n error: null,\n });\n // Layer B: tick duration + explicit nonces only publish when\n // snapshotKey changes, so no-op poll intervals do not force <App>\n // (and therefore the whole Ink tree) to repaint.\n const [lastTickMs, setLastTickMs] = useState(0);\n const [fastTickNonce, setFastTickNonce] = useState(0);\n const [slowTickNonce, setSlowTickNonce] = useState(0);\n const latestFastRef = useRef<WorkstreamSnapshot | null>(null);\n const slowRef = useRef<WorkstreamSnapshotSlowFields | null>(null);\n const publishedKeyRef = useRef(\"\");\n const errorRef = useRef<string | null>(null);\n\n // Snap-to-null on workstream change\n // (bug_tui_tab_switch_stale_render, workstream `tui-impl`).\n //\n // Without this, Tab/Shift-Tab on the multi-ws TUI flips the\n // `workstream` prop but the hook still has the OLD ws's\n // WorkstreamSnapshot in `data` until the new effect's first\n // tick resolves (~10-50ms for the SQLite read). React renders\n // the cards against the stale snapshot in that gap → a mixed\n // frame whose CARDS are old-ws but whose TAB STRIP is new-ws.\n //\n // Fix: when the workstream prop changes, synchronously reset\n // data to null during render. Cards already handle the null /\n // loading-state case. The next tick (started by the effect's\n // re-run on the workstream dep) repopulates fresh data within\n // one tick.\n //\n // This is the React-officially-blessed pattern for \"derive\n // state from props\": store the previous value in a ref, compare\n // during render, and call setState if they diverge. React\n // re-renders immediately with the new state and skips any\n // intervening commit, so cards never see the stale snapshot.\n const lastWsRef = useRef(workstream);\n if (shouldDiscardForWorkstream(lastWsRef.current, workstream)) {\n lastWsRef.current = workstream;\n slowRef.current = null;\n latestFastRef.current = null;\n publishedKeyRef.current = \"\";\n errorRef.current = null;\n setData({ data: null, error: null });\n setLastTickMs(0);\n }\n\n useEffect(() => {\n if (!enabled) return;\n // Touch refreshNonce so biome's useExhaustiveDependencies sees\n // it as read-inside-effect; the actual purpose of listing it in\n // the dep array is to force the effect to re-run on every bump\n // from <App> (the `r` / F5 keypress), which tears down the\n // setInterval and synchronously fires `tick()` below — i.e.\n // an immediate refresh. (review_dead_code_refresh_now)\n void refreshNonce;\n let cancelled = false;\n const tick = async () => {\n if (cancelled) return;\n const t0 = performance.now();\n try {\n const tornDown = new Set(\n observedWorkstreams.filter((name) => tryResolveWorkstreamId(db, name) === null),\n );\n setTornDownWorkstreams((previous) =>\n sameStringSet(previous, tornDown) ? previous : tornDown,\n );\n const fast = await loaders.fast(db, workstream, FAST_OPTS);\n if (cancelled) return;\n latestFastRef.current = fast;\n const fresh = mergeSnapshotFastSlow(fast, slowRef.current);\n const dur = performance.now() - t0;\n if (publishSnapshot(fresh, setData, publishedKeyRef, errorRef)) {\n setLastTickMs(dur);\n setFastTickNonce((n) => n + 1);\n }\n } catch (err) {\n if (cancelled) return;\n publishError(String(err), setData, errorRef);\n }\n };\n void tick();\n const id = setInterval(() => void tick(), tickMs);\n return () => {\n cancelled = true;\n clearInterval(id);\n };\n // `refreshNonce` participates in the dep list so the `r` / F5\n // keypress (App bumps the nonce) tears down the interval and\n // re-runs the effect, which fires `tick()` immediately. Without\n // this, the binding existed but never poked the poll loop\n // (review_dead_code_refresh_now).\n }, [db, workstream, tickMs, enabled, refreshNonce, loaders, observedWorkstreams]);\n\n useEffect(() => {\n if (!enabled) return;\n void refreshNonce;\n let cancelled = false;\n const slowTick = async () => {\n if (cancelled) return;\n // BEFORE the slow load, so anything a peer just delivered is\n // already in the tables this tick is about to read.\n await tuiSyncPass(db);\n if (cancelled) return;\n try {\n const slow = await loaders.slow(\n db,\n workstream,\n SLOW_OPTS,\n latestFastRef.current ?? undefined,\n );\n if (cancelled) return;\n slowRef.current = slow;\n const fast = latestFastRef.current;\n const changed =\n fast !== null &&\n publishSnapshot(mergeSnapshotFastSlow(fast, slow), setData, publishedKeyRef, errorRef);\n if (changed || (fast !== null && publishNoopSlowTicks)) {\n setSlowTickNonce((n) => n + 1);\n }\n } catch (err) {\n if (cancelled) return;\n publishError(String(err), setData, errorRef);\n }\n };\n void slowTick();\n const id = setInterval(() => void slowTick(), SLOW_TICK_MS);\n return () => {\n cancelled = true;\n clearInterval(id);\n };\n }, [db, workstream, enabled, refreshNonce, loaders, publishNoopSlowTicks]);\n\n return {\n data: data.data,\n fastTickNonce,\n slowTickNonce,\n lastTickMs,\n error: data.error,\n tornDownWorkstreams,\n };\n}\n\nfunction sameStringSet(a: ReadonlySet<string>, b: ReadonlySet<string>): boolean {\n return a.size === b.size && [...a].every((value) => b.has(value));\n}\n\n/**\n * Pure helper: returns true when a workstream-prop change must\n * discard the cached snapshot. Today this is just an identity\n * check, but factoring it out (a) makes the snap-to-null branch in\n * useDashboardSnapshot unit-testable without driving the hook, and\n * (b) gives future work (e.g. ws-aliases / case-insensitive\n * matching) a single seam to extend. See bug_tui_tab_switch_stale_render.\n */\nexport function shouldDiscardForWorkstream(prev: string, next: string): boolean {\n return prev !== next;\n}\n\nfunction publishSnapshot(\n fresh: WorkstreamSnapshot,\n writeData: (\n updater: (prev: { data: WorkstreamSnapshot | null; error: string | null }) => {\n data: WorkstreamSnapshot | null;\n error: string | null;\n },\n ) => void,\n publishedKeyRef: { current: string },\n errorRef: { current: string | null },\n): boolean {\n const freshKey = snapshotKeyString(fresh);\n if (errorRef.current === null && publishedKeyRef.current === freshKey) return false;\n publishedKeyRef.current = freshKey;\n errorRef.current = null;\n writeData(() => ({ data: fresh, error: null }));\n return true;\n}\n\nfunction publishError(\n message: string,\n writeData: (\n updater: (prev: { data: WorkstreamSnapshot | null; error: string | null }) => {\n data: WorkstreamSnapshot | null;\n error: string | null;\n },\n ) => void,\n errorRef: { current: string | null },\n): void {\n if (errorRef.current === message) return;\n errorRef.current = message;\n writeData((prev) => ({ ...prev, error: message }));\n}\n\n/** Clamp a desired tick rate to [floor, ceiling]. */\nexport function clampTick(ms: number): number {\n return Math.max(TICK_FLOOR_MS, Math.min(TICK_CEILING_MS, ms));\n}\n\n/** Compute the next-faster tick (halve, floor 100ms). */\nexport function fasterTick(current: number): number {\n return clampTick(Math.floor(current / 2));\n}\n\n/** Compute the next-slower tick (double, ceiling 10s). */\nexport function slowerTick(current: number): number {\n return clampTick(current * 2);\n}\n\n// ─── snapshotKey ───────────────────────────────────────────────────\n//\n// Pure projection of the WorkstreamSnapshot fields that actually\n// affect what the user sees on screen. Two snapshots with the same\n// snapshotKey() are guaranteed to render identical frames — so the\n// hook can safely skip setData for them.\n//\n// Design notes:\n// - Picks ONE of every visible-affecting field per row, no more.\n// Adding a field that DOES affect rendering but ISN'T listed\n// here is a regression (cards will lag a tick); adding a field\n// that DOESN'T affect rendering is a regression (we'll re-render\n// unnecessarily).\n// - tracks[i].taskIds is a Set<string>; serialise it as a sorted\n// array so JSON.stringify is deterministic.\n// - We DO NOT include workspaceOrphans because no card surfaces\n// them today (the TUI shows orphans only on the static\n// `mu state` card). If a future card reads them, add it here.\n// - We DO NOT include reconcile report counters (prunedGhosts,\n// prune counts) — they are diagnostic, not rendered.\n\n/**\n * Pure projection of the visible-affecting fields of a snapshot.\n * Two snapshots that produce equal `snapshotKey` render identical\n * frames. Exported for unit tests; consumers should prefer\n * `snapshotKeyString` (which JSON-encodes the result for cheap\n * byte-equality checks).\n */\nexport function snapshotKey(s: WorkstreamSnapshot): unknown {\n return {\n workstreamName: s.workstreamName,\n // ctl drives the Agents card's broken-control-socket glyph.\n agents: s.view.agents.map((a) => [\n a.name,\n a.state,\n a.role,\n a.idle === true ? 1 : 0,\n a.ctl ?? \"\",\n ]),\n orphanPaneIds: s.view.orphans.map((o) => o.paneId).sort(),\n tracks: s.tracks.map((t) => ({\n roots: t.roots.map((r) => r.name),\n readyCount: t.readyCount,\n parked: t.parked,\n // Set → sorted array; deterministic JSON.\n taskIds: [...t.taskIds].sort(),\n })),\n ready: s.ready.map(taskKey),\n inProgress: s.inProgress.map(taskKey),\n blocked: s.blocked.map(taskKey),\n recentClosed: s.recentClosed.map(taskKey),\n parkedCount: s.parkedCount,\n triage: s.triage.map(taskKey),\n allTasks: s.allTasks.map(taskKey),\n commitsBackend: s.commitsBackend ?? null,\n recentCommits: s.recentCommits.map((c) => [c.sha, c.subject, c.author, c.relTime]),\n workspaces: s.workspaces.map((w) => [\n w.agentName,\n w.backend,\n w.parentRef ?? \"\",\n w.commitsBehindMain ?? \"\",\n w.dirty === true ? 1 : 0,\n ]),\n // Recent log entries: seq is monotonic, so eq-by-seq is enough\n // for ordered membership; payload bytes drive what shows.\n recent: s.recent.map((l) => [l.seq, l.source, l.kind, l.payload]),\n // Doctor card renders every check row (name/status/detail) and\n // the problem count; null means \"loading…\".\n doctor: s.doctor\n ? [s.doctor.problemCount, s.doctor.checks.map((c) => [c.name, c.status, c.detail])]\n : null,\n };\n}\n\n/** Stable JSON encoding of `snapshotKey`. Cheap byte-equal check. */\nexport function snapshotKeyString(s: WorkstreamSnapshot): string {\n return JSON.stringify(snapshotKey(s));\n}\n\n// One row of every visible-affecting task field. impact + effortDays\n// drive the ROI bucket / sort; status + substate drive glyph + colour;\n// createdAt / updatedAt drive the all-tasks popup's age / recency\n// sorts; ownerName + title are rendered verbatim.\nfunction taskKey(t: {\n name: string;\n status: string;\n substate: string;\n impact: number;\n effortDays: number;\n ownerName: string | null;\n title: string;\n createdAt: string;\n updatedAt: string;\n}): (string | number)[] {\n return [\n t.name,\n t.status,\n t.substate,\n t.impact,\n t.effortDays,\n t.ownerName ?? \"\",\n t.title,\n t.createdAt,\n t.updatedAt,\n ];\n}\n","// Status bar — single dedicated row at the very bottom of the\n// dashboard, btop / lazygit / k9s convention. Replaces the prior\n// \"footer line + tick indicator\" pair.\n//\n// Per feat_status_bar (workstream `tui-impl`):\n// LEFT : last yank line (was the ad-hoc \"footer:\" text +\n// [copied] / [no clipboard] suffix).\n// CENTER : context-sensitive key-hint cluster\n// - dashboard mode → global keys\n// - popup mode → popup-local keys\n// - help mode → \"Esc/?/q close help\"\n// RIGHT : active workstream label (multi-ws only) + tick rate.\n//\n// Per feat_tui_multi_workstream (workstream `tui-impl`): when the\n// TUI is launched with multiple workstreams, the right zone gains\n// a `[ws]` prefix so the operator sees which tab is active without\n// having to look at the top tab strip. Single-ws TUI is unchanged.\n//\n// Single line, no border, dim by default; bright colour for the\n// single-key glyphs so the eye picks them out at a glance.\n//\n// Truncation policy: when the terminal is too narrow to fit all\n// three zones, drop the LEFT zone first (keys are critical;\n// last-yank is recoverable from the clipboard). The RIGHT zone is\n// short and never dropped.\n\nimport { Box, Text } from \"ink\";\nimport type { ReactElement } from \"react\";\nimport type { FooterState, PopupMode } from \"./app.js\";\nimport { truncateCell } from \"./columns.js\";\nimport { type StatusHintEntry, statusHintEntries } from \"./keymap-spec.js\";\n\nexport type StatusMode = \"dashboard\" | \"popup\" | \"popup-filter\" | \"help\";\n\nexport interface StatusBarProps {\n mode: StatusMode;\n tickMs: number;\n footer: FooterState | null;\n /** Total terminal width — drives the LEFT-truncation policy. */\n cols: number;\n /** Optional label for the popup mode (e.g. \"Tasks\"). */\n popupName?: string;\n /** Sub-mode inside a popup: \"list\" (default) or \"drill\". Drives\n * the per-popup hint cluster (Enter drills vs Esc backs out). */\n popupMode?: PopupMode;\n /** Active workstream label (multi-ws TUI only). When set, the\n * RIGHT zone renders `[<name>] <tick>` so the operator never\n * loses sight of which tab they are looking at. Undefined for\n * the single-ws TUI keeps the right zone byte-identical to the\n * pre-multi-ws layout. */\n activeWorkstream?: string;\n}\n\nexport function StatusBar({\n mode,\n tickMs,\n footer,\n cols,\n popupName,\n popupMode,\n activeWorkstream,\n}: StatusBarProps): ReactElement {\n const tickLabel = `${(tickMs / 1000).toFixed(2)}s ⏱`;\n const wsLabel = activeWorkstream !== undefined ? `[${activeWorkstream}]` : \"\";\n const rightPlain = wsLabel === \"\" ? tickLabel : `${wsLabel} ${tickLabel}`;\n const left = footer ? formatFooter(footer) : \"\";\n // Budget for the LEFT zone: total cols - right zone - hint cluster\n // - 4 chars of inter-zone padding. Hint cluster width is its\n // *plain* (non-coloured) length, derived from the same token list\n // that renders the JSX so the two cannot drift.\n const hintTokens = buildHints(mode, popupName, popupMode, activeWorkstream !== undefined);\n const hintsWidth = hintsPlain(hintTokens).length;\n const rightWidth = rightPlain.length;\n const padding = 4;\n const leftBudget = Math.max(0, cols - rightWidth - hintsWidth - padding);\n const leftClipped = leftBudget > 0 ? truncateCell(left, leftBudget) : \"\";\n\n return (\n <Box justifyContent=\"space-between\" width={cols}>\n <Box>\n {footer?.tone === \"error\" ? (\n <Text color=\"red\" dimColor>\n {leftClipped}\n </Text>\n ) : (\n <Text dimColor>{leftClipped}</Text>\n )}\n </Box>\n <Box>{renderHints(hintTokens)}</Box>\n <Box>\n {wsLabel !== \"\" && (\n <Text bold color=\"cyan\">\n {`${wsLabel} `}\n </Text>\n )}\n <Text dimColor>{tickLabel}</Text>\n </Box>\n </Box>\n );\n}\n\n// Hint cluster rendering is driven by keymap-spec.ts. That spec is\n// also consumed by the help overlay, making the contract explicit:\n// the status-bar cluster is the always-shown subset, and `?` is the\n// superset.\n//\n// Render order: tokens are space-separated. The plain text is\n// `tokens.map(t => t.text).join(\" \")`; the JSX wraps each token in\n// the styling implied by its `kind`, separated by literal \" \"\n// strings so width matches byte-for-byte.\ntype HintToken =\n | { kind: \"key\"; text: string }\n | { kind: \"dim\"; text: string }\n | { kind: \"label\"; text: string; color: \"cyan\" | \"magenta\" | \"yellow\" };\n\nfunction buildHints(\n mode: StatusMode,\n popupName: string | undefined,\n popupMode: PopupMode | undefined,\n hasWorkstreamTabs: boolean,\n): HintToken[] {\n if (mode === \"help\") {\n return [\n { kind: \"key\", text: \"Esc/?/q\" },\n { kind: \"dim\", text: \"close help\" },\n ];\n }\n\n const popupLabel: HintToken[] = popupName\n ? [\n { kind: \"label\", text: popupName, color: \"cyan\" },\n { kind: \"dim\", text: \"·\" },\n ]\n : [];\n const specMode =\n mode === \"dashboard\"\n ? \"dashboard\"\n : mode === \"popup-filter\"\n ? \"popup-filter\"\n : popupMode === \"drill\"\n ? \"popup-drill\"\n : popupName === \"DAG\"\n ? \"dag\"\n : popupName === \"All tasks\"\n ? \"all-tasks\"\n : \"popup-list\";\n const entries = statusHintEntries({ mode: specMode, hasWorkstreamTabs });\n return [...(mode === \"dashboard\" ? [] : popupLabel), ...tokensFromSpec(entries)];\n}\n\nfunction tokensFromSpec(entries: readonly StatusHintEntry[]): HintToken[] {\n const tokens: HintToken[] = [];\n entries.forEach((entry, index) => {\n if (entry.kind === \"hint\") {\n if (entry.key !== undefined) tokens.push({ kind: \"key\", text: entry.key });\n tokens.push({\n kind: \"dim\",\n text: `${entry.label}${index === entries.length - 1 ? \"\" : \" ·\"}`,\n });\n return;\n }\n if (entry.kind === \"label\") {\n tokens.push({ kind: \"label\", text: entry.label, color: entry.color ?? \"cyan\" });\n } else {\n tokens.push({ kind: \"dim\", text: entry.label });\n }\n if (index !== entries.length - 1) tokens.push({ kind: \"dim\", text: \"·\" });\n });\n return tokens;\n}\n\nfunction hintsPlain(tokens: HintToken[]): string {\n return tokens.map((t) => t.text).join(\" \");\n}\n\nfunction renderHints(tokens: HintToken[]): ReactElement {\n // Interleave tokens with literal \" \" separators so the rendered\n // width matches `hintsPlain(tokens)` byte-for-byte. ink flattens\n // children into a single inline run, so no per-child keys are\n // required (and react treats string children as keyed by index).\n const children: React.ReactNode[] = [];\n for (let i = 0; i < tokens.length; i++) {\n if (i > 0) children.push(\" \");\n children.push(renderToken(tokens[i] as HintToken, i));\n }\n return <Text>{children}</Text>;\n}\n\nfunction renderToken(t: HintToken, key: number): ReactElement {\n switch (t.kind) {\n case \"key\":\n return (\n <Text key={key} color=\"yellow\">\n {t.text}\n </Text>\n );\n case \"dim\":\n return (\n <Text key={key} dimColor>\n {t.text}\n </Text>\n );\n case \"label\":\n return (\n <Text key={key} bold color={t.color}>\n {t.text}\n </Text>\n );\n }\n}\n\nfunction formatFooter(f: FooterState): string {\n const tag = f.copied ? \"[copied]\" : \"[no clipboard]\";\n return `last: ${f.command} ${tag}`;\n}\n","// TabStrip — workstream switcher rendered above the dashboard when\n// the TUI is launched with multiple workstreams.\n//\n// The pure layout algorithm lives in tab-strip-layout.ts. This\n// component is a PURE presentational component: it takes the\n// terminal column count as a prop (the parent <App> reads useStdout\n// once for its own use and threads `cols` down). No hooks here —\n// previously a `useStdout()` helper was called from this module,\n// which produced a 'Rendered fewer hooks than expected' crash on\n// small panes because the early-return guard upstairs caused the\n// hook to be called on some renders and skipped on others.\n\nimport { Box, Text } from \"ink\";\nimport type { ReactElement } from \"react\";\n\nimport { isScratchWorkstream } from \"../../workstream.js\";\nimport { layoutTabStrip } from \"./tab-strip-layout.js\";\n\nexport interface TabStripProps {\n /** Resolved workstream set, in order. Length must be ≥ 1; the\n * caller skips rendering when length ≤ 1 (see <App>). */\n workstreams: readonly string[];\n /** Index of the active tab. Caller guarantees 0 ≤ active < workstreams.length. */\n active: number;\n /** Terminal columns. Required: the parent <App> reads ink's\n * useStdout() once and threads this down so the strip can stay\n * hook-free (and therefore safe to call from outside an ink\n * render tree, e.g. unit tests). */\n terminalColumns: number;\n /** Launch-time tabs whose workstream row no longer exists. */\n tornDownWorkstreams?: ReadonlySet<string>;\n}\n\nexport function TabStrip({\n workstreams,\n active,\n terminalColumns,\n tornDownWorkstreams = new Set(),\n}: TabStripProps): ReactElement | null {\n const onlyWorkstream = workstreams[0];\n if (workstreams.length <= 1) {\n if (onlyWorkstream === undefined || !tornDownWorkstreams.has(onlyWorkstream)) return null;\n return (\n <Box flexDirection=\"row\">\n <Text dimColor>workstreams: </Text>\n <Text bold color=\"cyan\" dimColor strikethrough>\n {`▸ ${isScratchWorkstream(onlyWorkstream) ? `*${onlyWorkstream}` : onlyWorkstream}`}\n </Text>\n </Box>\n );\n }\n const layout = layoutTabStrip(workstreams, active, terminalColumns);\n if (layout === null) return null;\n // The `*` cue signals \"ephemeral, not a durable crew\" so the\n // operator doesn't mistake a scratch workstream for a real one.\n const decorate = (name: string): string => (isScratchWorkstream(name) ? `*${name}` : name);\n const tabs: ReactElement[] = [];\n for (let i = 0; i < layout.visible.length; i++) {\n const tab = layout.visible[i];\n if (tab === undefined) continue;\n const tornDown = tornDownWorkstreams.has(tab.name);\n if (tab.isActive) {\n tabs.push(\n <Text key={`t-${i}`} bold color=\"cyan\" dimColor={tornDown} strikethrough={tornDown}>\n {`▸ ${decorate(tab.name)}`}\n </Text>,\n );\n } else {\n tabs.push(\n <Text key={`t-${i}`} dimColor strikethrough={tornDown}>\n {decorate(tab.name)}\n </Text>,\n );\n }\n if (i < layout.visible.length - 1) {\n tabs.push(\n <Text key={`s-${i}`} dimColor>\n {\" · \"}\n </Text>,\n );\n }\n }\n return (\n <Box flexDirection=\"row\">\n <Text dimColor>workstreams: </Text>\n {layout.leftHidden > 0 && <Text dimColor>{`‹${layout.leftHidden} `}</Text>}\n {tabs}\n {layout.rightHidden > 0 && <Text dimColor>{` ›${layout.rightHidden}`}</Text>}\n {layout.showHint && (\n <Text dimColor>\n {layout.leftHidden > 0 || layout.rightHidden > 0\n ? \" (Tab/Shift-Tab)\"\n : \" (Tab / Shift-Tab)\"}\n </Text>\n )}\n </Box>\n );\n}\n","// Pure tab-strip layout helper. Keeps the React component small and\n// makes overflow behaviour testable without booting ink.\n\nimport stringWidth from \"string-width\";\n\nconst PREFIX = \"workstreams: \";\nconst WIDE_HINT = \" (Tab / Shift-Tab)\";\nconst NARROW_HINT = \" (Tab/Shift-Tab)\";\nconst SEP = \" · \";\nconst ELLIPSIS = \"…\";\n\nexport interface VisibleTab {\n name: string;\n isActive: boolean;\n}\n\nexport interface TabStripLayout {\n leftHidden: number;\n rightHidden: number;\n visible: VisibleTab[];\n showHint: boolean;\n}\n\nexport function layoutTabStrip(\n workstreams: readonly string[],\n active: number,\n availableCols: number,\n): TabStripLayout | null {\n if (workstreams.length <= 1) return null;\n const safeActive = clamp(active, 0, workstreams.length - 1);\n const maxCols = Math.max(0, Math.floor(availableCols));\n const allRange = range(0, workstreams.length - 1);\n if (fits(workstreams, safeActive, allRange, maxCols, true)) {\n return {\n leftHidden: 0,\n rightHidden: 0,\n visible: tabsForRange(workstreams, safeActive, allRange),\n showHint: true,\n };\n }\n\n let start = safeActive;\n let end = safeActive;\n let growLeft = true;\n while (true) {\n let changed = false;\n if (\n growLeft &&\n start > 0 &&\n fits(workstreams, safeActive, range(start - 1, end), maxCols, true)\n ) {\n start--;\n changed = true;\n }\n if (\n !changed &&\n end < workstreams.length - 1 &&\n fits(workstreams, safeActive, range(start, end + 1), maxCols, true)\n ) {\n end++;\n changed = true;\n }\n if (\n !changed &&\n !growLeft &&\n start > 0 &&\n fits(workstreams, safeActive, range(start - 1, end), maxCols, true)\n ) {\n start--;\n changed = true;\n }\n if (!changed) break;\n growLeft = !growLeft;\n }\n\n const activeRange = range(safeActive, safeActive);\n if (!fits(workstreams, safeActive, activeRange, maxCols, true)) {\n const noHintCols = Math.max(\n 0,\n maxCols - chromeWidth(hiddenLeft(safeActive), hiddenRight(workstreams, safeActive), false),\n );\n const nameCols = Math.max(0, noHintCols - stringWidth(\"▸ \"));\n return {\n leftHidden: hiddenLeft(safeActive),\n rightHidden: hiddenRight(workstreams, safeActive),\n visible: [{ name: truncateToWidth(workstreams[safeActive] ?? \"\", nameCols), isActive: true }],\n showHint: false,\n };\n }\n\n return {\n leftHidden: start,\n rightHidden: workstreams.length - end - 1,\n visible: tabsForRange(workstreams, safeActive, range(start, end)),\n showHint: true,\n };\n}\n\nfunction range(start: number, end: number): number[] {\n const out: number[] = [];\n for (let i = start; i <= end; i++) out.push(i);\n return out;\n}\n\nfunction hiddenLeft(active: number): number {\n return active;\n}\n\nfunction hiddenRight(workstreams: readonly string[], active: number): number {\n return Math.max(0, workstreams.length - active - 1);\n}\n\nfunction tabsForRange(\n workstreams: readonly string[],\n active: number,\n indexes: readonly number[],\n): VisibleTab[] {\n return indexes.map((i) => ({ name: workstreams[i] ?? \"\", isActive: i === active }));\n}\n\nfunction fits(\n workstreams: readonly string[],\n active: number,\n indexes: readonly number[],\n availableCols: number,\n showHint: boolean,\n): boolean {\n const first = indexes[0];\n const last = indexes[indexes.length - 1];\n if (first === undefined || last === undefined) return false;\n const leftHidden = first;\n const rightHidden = workstreams.length - last - 1;\n return rowWidth(workstreams, active, indexes, leftHidden, rightHidden, showHint) <= availableCols;\n}\n\nfunction rowWidth(\n workstreams: readonly string[],\n active: number,\n indexes: readonly number[],\n leftHidden: number,\n rightHidden: number,\n showHint: boolean,\n): number {\n return (\n chromeWidth(leftHidden, rightHidden, showHint) +\n indexes.reduce((sum, i, idx) => {\n const prefix = i === active ? \"▸ \" : \"\";\n const sep = idx < indexes.length - 1 ? SEP : \"\";\n return sum + stringWidth(prefix) + stringWidth(workstreams[i] ?? \"\") + stringWidth(sep);\n }, 0)\n );\n}\n\nfunction chromeWidth(leftHidden: number, rightHidden: number, showHint: boolean): number {\n return (\n stringWidth(PREFIX) +\n counterWidth(\"‹\", leftHidden) +\n counterWidth(\"›\", rightHidden) +\n (showHint ? stringWidth(leftHidden > 0 || rightHidden > 0 ? NARROW_HINT : WIDE_HINT) : 0)\n );\n}\n\nfunction counterWidth(prefix: \"‹\" | \"›\", count: number): number {\n return count > 0 ? stringWidth(`${prefix}${count} `) : 0;\n}\n\nfunction truncateToWidth(text: string, width: number): string {\n if (width <= 0) return \"\";\n if (stringWidth(text) <= width) return text;\n if (width <= stringWidth(ELLIPSIS)) return ELLIPSIS.slice(0, width);\n let out = \"\";\n const budget = width - stringWidth(ELLIPSIS);\n for (const ch of text) {\n if (stringWidth(out + ch) > budget) break;\n out += ch;\n }\n return `${out}${ELLIPSIS}`;\n}\n\nfunction clamp(value: number, min: number, max: number): number {\n return Math.max(min, Math.min(value, max));\n}\n"],"mappings":"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","names":["Box","Text","useInput","useCallback","useEffect","useRef","useState","Text","text","text","layoutColumns","visibleCardIds","config","donorCards","Box","Text","jsx","Text","Box","Box","Text","stringWidth","jsx","label","stringWidth","Box","Text","Text","Text","Fragment","jsx","jsxs","jsx","config","text","Text","jsx","jsxs","Text","row","jsx","cardConfig","GLYPH","COLUMN_SPECS","row","jsx","cardConfig","COLUMN_SPECS","formatSubtitle","row","Text","jsx","jsxs","cardConfig","COLUMN_SPECS","formatSubtitle","Text","row","jsx","cardConfig","GLYPH","COLUMN_SPECS","formatSubtitle","row","stale","jsx","cardConfig","COLUMN_SPECS","row","Text","jsx","cardConfig","COLUMN_SPECS","Text","row","jsx","cardConfig","GLYPH","COLUMN_SPECS","formatSubtitle","row","Text","jsx","jsxs","cardConfig","COLUMN_SPECS","Text","row","trackKey","Text","jsx","jsxs","cardConfig","COLUMN_SPECS","isStale","formatSubtitle","Text","glyphFor","row","Box","Text","useState","jsx","jsxs","row","useState","Box","Text","useEffect","subscribers","useEffect","subscribers","useInput","Box","Text","useCallback","useEffect","useRef","useState","jsx","hint","text","useEffect","useRef","useState","Box","Text","useEffect","jsx","jsxs","text","Box","Text","useCallback","useEffect","useMemo","useRef","useState","jsx","jsxs","useMemo","useState","useRef","useCallback","useEffect","hint","Box","Text","jsx","jsxs","COLUMN_SPECS","useState","useRef","useCallback","text","useEffect","Text","Box","row","Box","Text","useMemo","useState","useMemo","useMemo","jsx","useMemo","useMemo","Box","Text","useCallback","useState","jsx","jsxs","useState","useCallback","Box","Text","label","jsx","jsxs","COLUMN_SPECS","useState","useMemo","Text","Box","row","useMemo","Box","Text","useState","jsx","jsxs","config","useState","Text","Box","jsx","COLUMN_SPECS","useMemo","config","GLYPH","Box","Text","useCallback","useEffect","useState","spawnSync","spawnSync","text","spawnSync","spawnSync","text","jsx","jsxs","COLUMN_SPECS","useState","useCallback","useEffect","Text","shortSha","formatBackend","Box","row","Box","Text","useMemo","useRef","useState","jsx","jsxs","useMemo","useState","useRef","Box","Text","Box","Text","useState","jsx","jsxs","COLUMN_SPECS","useState","Text","Box","row","jsx","COLUMN_SPECS","GLYPH","Box","Text","useState","jsx","jsxs","COLUMN_SPECS","useState","Text","Box","row","jsx","COLUMN_SPECS","config","yankCommandForTask","jsx","COLUMN_SPECS","config","yankCommandForTask","GLYPH","Box","Text","useEffect","useMemo","useState","jsx","jsxs","COLUMN_SPECS","useState","useEffect","useMemo","Text","Box","visible","rows","widths","row","Box","Text","useCallback","useEffect","useReducer","useRef","useState","jsx","jsxs","COLUMN_SPECS","DRILL_COLUMN_SPECS","useState","useReducer","useCallback","text","loading","useRef","useEffect","Text","shortSha","Box","renderDrillBody","glyphFor","row","hint","useEffect","useRef","useState","state","useState","useRef","useEffect","Box","Text","jsx","jsxs","Box","Text","Box","Text","stringWidth","clamp","text","jsx","jsxs","Box","Text","jsx","jsxs","useState","useRef","useEffect","useCallback","useInput","Box","Text","layoutColumns"]}
1
+ {"version":3,"sources":["../src/cli/tui/index.ts","../src/cli/tui/app.tsx","../src/cli/tui/cards/agents.tsx","../src/cli/tui/agent-display.ts","../src/cli/tui/wrap-ansi.ts","../src/cli/tui/columns.ts","../src/cli/tui/layout.ts","../src/cli/tui/list-row.tsx","../src/cli/tui/popups/cursor-row.tsx","../src/cli/tui/titled-box.tsx","../src/cli/tui/use-terminal-size.ts","../src/cli/tui/cards/_placeholder.tsx","../src/cli/tui/padded-rows.tsx","../src/cli/tui/format-helpers.ts","../src/cli/tui/cards/blocked.tsx","../src/cli/tui/cards/commits.tsx","../src/cli/tui/cards/doctor.tsx","../src/cli/tui/cards/inprogress.tsx","../src/cli/tui/cards/log.tsx","../src/cli/tui/cards/ready.tsx","../src/cli/tui/cards/recent.tsx","../src/cli/tui/cards/tracks.tsx","../src/cli/tui/cards/workspaces.tsx","../src/cli/tui/help.tsx","../src/cli/tui/keymap-spec.ts","../src/cli/tui/keys.ts","../src/cli/tui/popups/scroll.ts","../src/cli/tui/mouse.ts","../src/cli/tui/escapes.ts","../src/cli/tui/popup-input.ts","../src/cli/tui/popups/agents.tsx","../src/cli/tui/popup-shell.tsx","../src/cli/tui/tmux-attach.ts","../src/cli/tui/use-popup-action-queue.ts","../src/cli/tui/use-popup-filter.tsx","../src/cli/tui/popups/drill.tsx","../src/cli/tui/popups/viewport.ts","../src/cli/tui/popups/all-tasks.tsx","../src/cli/tui/use-notes-drill.ts","../src/cli/tui/popups/task-detail.tsx","../src/cli/tui/use-status-filter.tsx","../src/cli/tui/popups/blocked.tsx","../src/cli/tui/popups/task-list-popup.tsx","../src/cli/tui/popups/commits.tsx","../src/cli/tui/lazygit.ts","../src/cli/tui/tuicr.ts","../src/cli/tui/popups/show-loader.ts","../src/cli/tui/popups/dag.tsx","../src/cli/tui/popups/doctor.tsx","../src/cli/tui/popups/inprogress.tsx","../src/cli/tui/popups/log.tsx","../src/cli/tui/popups/ready.tsx","../src/cli/tui/popups/recent.tsx","../src/cli/tui/popups/tracks.tsx","../src/cli/tui/popups/workspaces.tsx","../src/cli/tui/state.ts","../src/cli/tui/status-bar.tsx","../src/cli/tui/tab-strip.tsx","../src/cli/tui/tab-strip-layout.ts"],"sourcesContent":["// Public entrypoint for the interactive TUI. Lazy-imported by\n// src/cli/state.ts cmdState so the ink/react dependency tree only\n// loads when the user actually enters the TUI (not on `mu task list`,\n// `mu state --json`, `mu agent show`, etc.).\n\nimport { render } from \"ink\";\nimport { createElement } from \"react\";\nimport type { Db } from \"../../db.js\";\nimport { App } from \"./app.js\";\nimport { ALT_SCREEN_ENTER, ALT_SCREEN_EXIT } from \"./escapes.js\";\nimport { disableMouseMode, enableMouseMode } from \"./mouse.js\";\n\nexport interface RunTuiOptions {\n /** Resolved workstream set (≥1). Per feat_tui_multi_workstream\n * (workstream `tui-impl`): N=1 renders the TUI exactly as the\n * pre-multi-ws build did; N≥2 renders a tab strip above the\n * cards and Tab/Shift-Tab switch the active tab. cmdState is\n * responsible for the resolution + validation; runTui just\n * forwards the array. */\n workstreams: string[];\n /** Initial active tab index. Bare `mu` and `mu state --tui` share\n * the launch-focus ladder: $MU_SESSION, then tmux session name,\n * then cwd inside a workspace, then cwd equal to a workspace's\n * VCS-derived project root (latest activity breaks ties), then 0.\n * <App> clamps defensively. */\n initialActive?: number;\n}\n\nexport async function runTui(db: Db, opts: RunTuiOptions): Promise<void> {\n process.stdout.write(ALT_SCREEN_ENTER);\n enableMouseMode();\n try {\n const { waitUntilExit } = render(\n createElement(App, { db, workstreams: opts.workstreams, initialActive: opts.initialActive }),\n { exitOnCtrlC: true },\n );\n await waitUntilExit();\n } finally {\n disableMouseMode();\n process.stdout.write(ALT_SCREEN_EXIT);\n }\n}\n","// <App> — the TUI's root component.\n//\n// Owns:\n// - The dashboard snapshot poll (via useDashboardSnapshot)\n// - Card visibility flags (0-9 toggle)\n// - Tick rate (+/-/= adjust)\n// - Single-popup invariant + state-restore on close\n// - Help overlay (?)\n// - Footer line (last yanked command + [copied]/[no clipboard])\n// - Yank backend probe (memoised once per session)\n// - Quit / Ctrl-C\n//\n// Per design_card_iface + design_popup_lifecycle: card visibility +\n// tick rate + footer are preserved as a side effect of living in\n// <App> state, not the popup. The snapshot tick keeps running while\n// popups are open; drill-down bodies consume explicit fast/slow tick\n// nonces so visible details refresh without closing/reopening.\n\nimport type { EventEmitter } from \"node:events\";\nimport { Box, Text, useApp, useInput, useStdin } from \"ink\";\nimport {\n type ComponentType,\n type ReactElement,\n useCallback,\n useEffect,\n useRef,\n useState,\n} from \"react\";\nimport type { Db } from \"../../db.js\";\nimport { AgentsCard } from \"./cards/agents.js\";\nimport { BlockedCard } from \"./cards/blocked.js\";\nimport { CommitsCard } from \"./cards/commits.js\";\nimport { DoctorCard } from \"./cards/doctor.js\";\nimport { InProgressCard } from \"./cards/inprogress.js\";\nimport { LogCard } from \"./cards/log.js\";\nimport { ReadyCard } from \"./cards/ready.js\";\nimport { RecentCard } from \"./cards/recent.js\";\nimport { TracksCard } from \"./cards/tracks.js\";\nimport { WorkspacesCard } from \"./cards/workspaces.js\";\nimport { Help } from \"./help.js\";\nimport {\n dispatchGlobalKeyFromInk,\n type InputMode,\n type PopupAction,\n type PopupActionEnvelope,\n shouldSwallowGlobalKeyFromInk,\n} from \"./keys.js\";\nimport {\n allocateRowBudgets,\n balanceColumns,\n CARD_CONFIGS,\n type CardId,\n type ColumnAssignment,\n type ColumnWidth,\n columnWidths,\n cullCardsForRows,\n dashboardCardHitRegions,\n dataCountForCard,\n hitTestDashboardCard,\n layoutColumns as layoutDashboardColumns,\n type RowBudgetMap,\n} from \"./layout.js\";\nimport { type MouseEvent, useMouse } from \"./mouse.js\";\nimport { PopupInputActive } from \"./popup-input.js\";\nimport { AgentsPopup } from \"./popups/agents.js\";\nimport { AllTasksPopup } from \"./popups/all-tasks.js\";\nimport { BlockedPopup } from \"./popups/blocked.js\";\nimport { CommitsPopup } from \"./popups/commits.js\";\nimport { DagPopup } from \"./popups/dag.js\";\nimport { DoctorPopup } from \"./popups/doctor.js\";\nimport { InProgressPopup } from \"./popups/inprogress.js\";\nimport { LogPopup } from \"./popups/log.js\";\nimport { ReadyPopup } from \"./popups/ready.js\";\nimport { RecentPopup } from \"./popups/recent.js\";\nimport { TracksPopup } from \"./popups/tracks.js\";\nimport { WorkspacesPopup } from \"./popups/workspaces.js\";\nimport {\n type CardVisibility,\n DEFAULT_CARD_VISIBILITY,\n fasterTick,\n slowerTick,\n TICK_DEFAULT_MS,\n useDashboardSnapshot,\n} from \"./state.js\";\nimport { StatusBar } from \"./status-bar.js\";\nimport { TabStrip } from \"./tab-strip.js\";\nimport { useTerminalSize } from \"./use-terminal-size.js\";\nimport { type ClipboardBackend, probeClipboardBackend } from \"./yank.js\";\n\nexport interface AppProps {\n db: Db;\n /** Resolved workstream set (≥1). Per feat_tui_multi_workstream\n * (workstream `tui-impl`): the TUI shows one ws at a time;\n * Tab/Shift-Tab cycles. Length 1 is the original single-ws TUI\n * with no tab strip rendered. */\n workstreams: string[];\n /** Initial active tab index. Clamped at render time so stale env\n * values or shrinking workstream arrays fall back safely. */\n initialActive?: number;\n}\n\nexport interface FooterState {\n command: string;\n copied: boolean;\n tone?: \"normal\" | \"info\" | \"error\";\n}\n\ntype PopupId = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | \"dag\" | \"allTasks\" | null;\ntype PopupRegistryId = NonNullable<PopupId>;\nexport type PopupMode = \"list\" | \"drill\";\ntype DashboardSnapshot = ReturnType<typeof useDashboardSnapshot>[\"data\"];\n\ninterface CommonCardProps {\n snapshot: DashboardSnapshot;\n db: Db;\n workstream: string;\n rowBudget?: number;\n cols?: number;\n}\n\ninterface CommonPopupProps {\n yank: (command: string) => Promise<void>;\n onFooter: (command: string, copied: boolean, tone?: FooterState[\"tone\"]) => void;\n onClose: () => void;\n snapshot: DashboardSnapshot;\n fastTickNonce: number;\n slowTickNonce: number;\n mode: PopupMode;\n onModeChange: (mode: PopupMode) => void;\n onFilterEditingChange: (editing: boolean) => void;\n popupActions: readonly PopupActionEnvelope[];\n db: Db;\n workstream: string;\n}\n\nconst CARD_REGISTRY: Record<CardId, ComponentType<CommonCardProps>> = {\n 0: CommitsCard,\n 1: AgentsCard,\n 2: TracksCard,\n 3: ReadyCard,\n 4: LogCard,\n 5: WorkspacesCard,\n 6: InProgressCard,\n 7: BlockedCard,\n 8: RecentCard,\n 9: DoctorCard,\n};\n\nconst POPUP_REGISTRY: Record<PopupRegistryId, ComponentType<CommonPopupProps>> = {\n 0: CommitsPopup,\n 1: AgentsPopup,\n 2: TracksPopup,\n 3: ReadyPopup,\n 4: LogPopup,\n 5: WorkspacesPopup,\n 6: InProgressPopup,\n 7: BlockedPopup,\n 8: RecentPopup,\n 9: DoctorPopup,\n dag: DagPopup,\n allTasks: AllTasksPopup,\n};\n\n// Popups whose drill bodies shell out to subprocesses (git show /\n// agent scrollback / workspace commits). Their bodies must keep\n// refreshing on the slow tick even when the DB snapshot is byte-equal,\n// so the snapshot hook is told to advance slowTickNonce on no-op ticks\n// (see state.ts publishNoopSlowTicks). This is the single symbolic\n// source of truth, co-located with POPUP_REGISTRY, instead of magic\n// numeric literals scattered in the App body.\nconst EMPTY_WORKSTREAM_SET: ReadonlySet<string> = new Set();\nconst SUBPROCESS_BACKED_POPUPS: ReadonlySet<PopupRegistryId> = new Set<PopupRegistryId>([\n 0, // Commits — git show\n 1, // Agents — pane scrollback\n 5, // Workspaces — workspace commits\n]);\n\nexport const DASHBOARD_MIN_ROWS = 5;\n// Mouse SGR coordinates are 1-based. The popup fills the pane from\n// row 1 (its top border, which carries the title), so the first popup\n// body row is y=2. `event.y - POPUP_CHROME_TOP` is the 0-based body\n// row the popup receives in `clickRow`; the popup maps it through its\n// own scroll window and header strips.\nexport const POPUP_CHROME_TOP = 2;\n\nexport function dashboardAvailableRows(\n rows: number,\n opts: { hasTabStrip: boolean; hasSnapshotError: boolean },\n): number {\n const tabRows = opts.hasTabStrip ? 1 : 0;\n const snapshotErrorRows = opts.hasSnapshotError ? 3 : 0;\n const statusRows = 1;\n return Math.max(1, rows - tabRows - snapshotErrorRows - statusRows);\n}\n\ninterface PendingMouseEventRef {\n current: MouseEvent | null;\n}\n\n// Ink's `useStdin` does not advertise `internal_eventEmitter` in its\n// public TypeScript types, but the field IS what backs ink's own\n// public `useInput` hook (the field is exported from ink's stdin\n// context props but flagged `internal_*` per ink convention, meaning\n// ink reserves the right to rename or remove it without a\n// breaking-change bump). We still use it for\n// mouse-wheel scroll compatibility (scroll replays one `j`/`k` key);\n// double-click drills now use first-class PopupAction events instead\n// of replaying N synthetic row-navigation keys. Define a typed seam\n// + runtime probe so:\n// 1. The cast site is explicit, not a silent any-shaped access.\n// 2. If a future ink upgrade drops the field, we degrade gracefully\n// (mouse-wheel scroll stops emitting synthetic keys; keyboard\n// nav and double-click PopupAction routing are unaffected).\ninterface InkStdinWithEmitter extends ReturnType<typeof useStdin> {\n internal_eventEmitter: EventEmitter;\n}\n\nexport function getInkInternalEmitter(stdin: ReturnType<typeof useStdin>): EventEmitter | null {\n if (\"internal_eventEmitter\" in stdin) {\n return (stdin as InkStdinWithEmitter).internal_eventEmitter;\n }\n return null;\n}\n\nexport function replayPendingMouseEvent(\n pendingMouseEvent: PendingMouseEventRef,\n opts: {\n popupOpen: boolean;\n filterEditing: boolean;\n emitKey?: (key: string, delayMs: number) => void;\n emitAction: (action: PopupAction) => void;\n },\n): boolean {\n if (!opts.popupOpen || opts.filterEditing) return false;\n const event = pendingMouseEvent.current;\n if (event === null) return false;\n if (event.kind === \"scroll\") {\n if (opts.emitKey === undefined) return false;\n pendingMouseEvent.current = null;\n opts.emitKey(event.direction === \"up\" ? \"k\" : \"j\", 0);\n return true;\n }\n if (event.kind === \"doubleclick\") {\n pendingMouseEvent.current = null;\n opts.emitAction({ kind: \"clickRow\", row: event.y - POPUP_CHROME_TOP });\n return true;\n }\n pendingMouseEvent.current = null;\n return false;\n}\n\nexport function App({ db, workstreams, initialActive = 0 }: AppProps): ReactElement {\n const { exit } = useApp();\n const stdin = useStdin();\n\n const [visibility, setVisibility] = useState<CardVisibility>(DEFAULT_CARD_VISIBILITY);\n const [tickMs, setTickMs] = useState<number>(TICK_DEFAULT_MS);\n // Index of the active workstream tab. Tab / Shift-Tab cycles\n // through `workstreams`. Always in [0, workstreams.length).\n const [activeWs, setActiveWs] = useState<number>(initialActive);\n const [popup, setPopup] = useState<PopupId>(null);\n // Per-popup-instance mode (\"list\" → list of rows; \"drill\" →\n // inline detail view inside the popup body). Owned by <App>\n // because the StatusBar's hint cluster needs to know which mode\n // we're in. Reset to \"list\" every time a new popup opens.\n const [popupMode, setPopupMode] = useState<PopupMode>(\"list\");\n // True while ANY open popup has its '/' filter prompt in edit\n // mode. The popup pushes the flag up via onFilterEditingChange\n // (per feat_popup_search_filter); we use it solely to flip the\n // StatusBar hint cluster to the filter-mode hint.\n const [popupFilterEditing, setPopupFilterEditing] = useState<boolean>(false);\n const [helpOpen, setHelpOpen] = useState<boolean>(false);\n const [footer, setFooter] = useState<FooterState | null>(null);\n const [refreshNonce, setRefreshNonce] = useState<number>(0);\n const pendingMouseEvent = useRef<MouseEvent | null>(null);\n const [popupMouseTick, setPopupMouseTick] = useState<number>(0);\n const popupActionSeq = useRef(0);\n const [popupActions, setPopupActions] = useState<PopupActionEnvelope[]>([]);\n\n // Probe clipboard backend once per session and memoise.\n const clipboardRef = useRef<ClipboardBackend | undefined>(undefined);\n useEffect(() => {\n void probeClipboardBackend().then((b) => {\n clipboardRef.current = b;\n });\n }, []);\n\n // Bounds-clamp activeWs in case workstreams[] shrinks (defensive;\n // the TUI is launched with a fixed list today). Falls back to 0.\n const safeActive = Math.max(0, Math.min(activeWs, workstreams.length - 1));\n const workstream = workstreams[safeActive] ?? \"\";\n\n const snap = useDashboardSnapshot(db, workstream, tickMs, true, refreshNonce, undefined, {\n observedWorkstreams: workstreams,\n publishNoopSlowTicks: popup !== null && SUBPROCESS_BACKED_POPUPS.has(popup),\n });\n\n // Terminal-resize handling: useTerminalSize subscribes to stdout\n // 'resize' events so the entire tree re-renders when the pane\n // shrinks or grows. Cards self-shrink within the dashboard's flex\n // layout; the explicit guard catches the pathological 10x5 case.\n const { cols, rows } = useTerminalSize();\n const terminalTooSmall = cols < 40 || rows < DASHBOARD_MIN_ROWS;\n const tornDownWorkstreams = snap.tornDownWorkstreams ?? EMPTY_WORKSTREAM_SET;\n const hasTabStrip = workstreams.length > 1 || tornDownWorkstreams.has(workstream);\n const hasSnapshotError = snap.error !== null;\n const availableForCards = dashboardAvailableRows(rows, { hasTabStrip, hasSnapshotError });\n const dashboardModel = buildDashboardLayoutModel(cols, availableForCards, visibility, snap.data);\n const dashboardTop = 1 + (hasTabStrip ? 1 : 0) + (hasSnapshotError ? 3 : 0);\n const cardHitRegions = dashboardCardHitRegions(\n dashboardModel.assignments,\n dashboardModel.widths,\n dashboardModel.budgetsByColumn,\n { top: dashboardTop },\n );\n\n // Yank callback handed down to popups (and used by the dashboard\n // for any direct yank in the future). The popup passes the command\n // text; we update the footer regardless of whether the clipboard\n // write succeeded so the user can mouse-select if needed.\n const yankFn = useCallback(async (command: string) => {\n const { yank } = await import(\"./yank.js\");\n const r = await yank(command, clipboardRef.current ?? null);\n setFooter({ command, copied: r.copied });\n }, []);\n\n const footerFn = useCallback((command: string, copied: boolean, tone?: FooterState[\"tone\"]) => {\n setFooter({ command, copied, tone });\n }, []);\n\n const emitPopupAction = useCallback((action: PopupAction) => {\n const seq = popupActionSeq.current + 1;\n popupActionSeq.current = seq;\n setPopupActions((events) => [...events.slice(-8), { seq, action }]);\n }, []);\n\n useMouse((event) => {\n if (helpOpen || terminalTooSmall) return;\n if (popup === null) {\n if (event.kind !== \"doubleclick\") return;\n const hit = hitTestDashboardCard(cardHitRegions, event);\n if (process.env.MU_TUI_DEBUG_MOUSE === \"1\") {\n process.stderr.write(`mouse @ (${event.x},${event.y}) → card ${hit ?? \"MISS\"}\\n`);\n for (const region of cardHitRegions) {\n process.stderr.write(\n ` region ${region.id}: top=${region.top} bottom=${region.bottom} left=${region.left} right=${region.right}\\n`,\n );\n }\n }\n if (hit === null) return;\n setPopupActions([]);\n setPopupMode(\"list\");\n setPopup(hit);\n return;\n }\n if (popupFilterEditing) return;\n if (event.kind === \"scroll\" || event.kind === \"doubleclick\") {\n pendingMouseEvent.current = event;\n setPopupMouseTick((n) => n + 1);\n }\n });\n useEffect(() => {\n void popupMouseTick;\n // Ink's public useInput hook is backed by this internal emitter;\n // mouse-wheel scroll still replays the same single `j`/`k` byte\n // keyboard users type. Double-click drill bypasses this private\n // emitter and emits PopupAction objects directly. The runtime\n // probe + typed seam (getInkInternalEmitter) makes the remaining\n // private-API dependency explicit and degrades gracefully if a\n // future ink upgrade drops the field — mouse-wheel scroll stops\n // emitting synthetic keys, keyboard nav and double-click routing\n // are unaffected.\n const emitter = getInkInternalEmitter(stdin);\n if (emitter === null && process.env.MU_TUI_DEBUG_MOUSE === \"1\") {\n process.stderr.write(\n \"mu: ink stdin missing internal_eventEmitter; mouse scroll replay disabled\\n\",\n );\n }\n const emitKey =\n emitter === null\n ? undefined\n : (key: string, delayMs: number) => {\n setTimeout(() => emitter.emit(\"input\", Buffer.from(key)), delayMs);\n };\n replayPendingMouseEvent(pendingMouseEvent, {\n popupOpen: popup !== null,\n filterEditing: popupFilterEditing,\n emitKey,\n emitAction: emitPopupAction,\n });\n }, [popupMouseTick, popup, popupFilterEditing, stdin, emitPopupAction]);\n useEffect(() => {\n if (popup === null) {\n pendingMouseEvent.current = null;\n setPopupActions([]);\n }\n }, [popup]);\n\n // Global keymap. Rendered before popup rendering so popups can\n // override Esc / q / y handling locally via their own useInput\n // (later popups will register handlers; for v0 placeholder\n // popups, Esc closes via this dispatcher).\n //\n // Per review_tui_help_overlay_swallows_only_some_keys: the per-\n // mode \"do not let this key leak into the global dispatcher\"\n // rule is centralised in `shouldSwallowGlobalKey` (keys.ts) so\n // the help-overlay and popup branches share one swallow list.\n // Help and popup components own their own `useInput` for local\n // scroll/nav; ink fires every mounted useInput per keystroke, so\n // those local handlers still see `j`/`k`/etc. while this branch\n // short-circuits the global dispatcher.\n useInput(\n (input, key) => {\n // Help overlay close-keys are App-owned (the helper swallows\n // them along with everything else, so they must be handled\n // BEFORE the swallow check). Help.tsx's local useInput\n // handles scroll; the rest is consumed.\n if (helpOpen) {\n if (key.escape || input === \"q\" || input === \"Q\" || input === \"?\") {\n setHelpOpen(false);\n }\n }\n const mode: InputMode = helpOpen\n ? \"help\"\n : popup === null\n ? \"dashboard\"\n : popupFilterEditing\n ? \"popup-filter\"\n : \"popup\";\n if (shouldSwallowGlobalKeyFromInk(input, key, mode)) return;\n const action = dispatchGlobalKeyFromInk(input, key);\n\n switch (action.kind) {\n case \"quit\":\n exit();\n return;\n case \"toggleHelp\":\n setHelpOpen((o) => !o);\n return;\n case \"refreshNow\":\n setRefreshNonce((n) => n + 1);\n return;\n case \"tickFaster\":\n setTickMs((t) => fasterTick(t));\n return;\n case \"tickSlower\":\n setTickMs((t) => slowerTick(t));\n return;\n case \"clearFooter\":\n setFooter(null);\n return;\n case \"toggleCard\":\n if (popup !== null) return; // suppress while popup is open\n setVisibility((v) => ({ ...v, [action.cardId]: !v[action.cardId] }));\n return;\n case \"openPopup\":\n if (popup !== null) return; // single-popup invariant\n setPopupActions([]);\n setPopupMode(\"list\");\n setPopup(action.cardId);\n return;\n case \"nextTab\":\n if (popup !== null) return; // suppress while popup is open\n if (workstreams.length <= 1) return;\n setActiveWs((i) => (i + 1) % workstreams.length);\n return;\n case \"prevTab\":\n if (popup !== null) return;\n if (workstreams.length <= 1) return;\n setActiveWs((i) => (i - 1 + workstreams.length) % workstreams.length);\n return;\n case \"noop\":\n return;\n }\n },\n { isActive: true },\n );\n\n if (terminalTooSmall) {\n return (\n <Box borderStyle=\"round\" borderColor=\"red\" paddingX={1}>\n <Text>\n terminal too small ({cols}x{rows}) — need at least 40x{DASHBOARD_MIN_ROWS} for the TUI.\n Resize or run `mu state` for the static card.\n </Text>\n </Box>\n );\n }\n\n // Help overlay covers everything else (still gets the global\n // status bar at the bottom for consistent navigation hints).\n //\n // height={rows} + a flexGrow={1} spacer above the StatusBar pins\n // every frame to the full terminal height. Without this, ink's\n // diff-based renderer leaves \"ghost\" lines below a shrinking\n // frame on card-toggle / branch-swap (see\n // bug_tui_render_ghosting_v2). The spacer also bottom-sticks the\n // status bar so it doesn't float up against a shorter body.\n //\n // overflow=\"hidden\" pinned at the root (all three branches): when\n // total content exceeds rows ink would otherwise emit the\n // overflowing rows past the terminal bottom, scrolling the top\n // off-screen and silently dropping the topmost row's bytes (see\n // bug_tui_tab_switch_stale_render layer 2 + the single-ws sibling\n // bug_tui_dashboard_top_card_scrolls_off where the nine cards'\n // summed natural height beats `rows`). Belt-and-braces with the\n // per-card flexShrink=1 in TitledBox: that one tells Yoga it MAY\n // shrink cards, this one tells ink to clip if Yoga still didn't\n // (e.g. a card with a hardcoded `height` prop).\n //\n // With a popup open, the help overlay is rendered by the popup\n // branch below instead, so the popup stays mounted underneath.\n if (helpOpen && popup === null) {\n return (\n <Box flexDirection=\"column\" height={rows} overflow=\"hidden\">\n <Help rows={rows} />\n <Box flexGrow={1} />\n <StatusBar\n mode=\"help\"\n tickMs={tickMs}\n footer={footer}\n cols={cols}\n activeWorkstream={workstreams.length > 1 ? workstream : undefined}\n />\n </Box>\n );\n }\n\n // Popup mounted: render full-screen instead of dashboard, with\n // the popup-mode status bar pinned at the bottom.\n //\n // NOTE: no flexGrow={1} spacer here — popup bodies own their\n // bottom-fill (see sibling task bug_tui_popups_fill_pane). Adding\n // a sibling spacer would steal the space the popup wants. The\n // height={rows} pin is still required to prevent ghost lines\n // when swapping between popup ↔ dashboard ↔ help.\n //\n // `?` over a popup hides the popup (display=\"none\") instead of\n // unmounting it, and turns its keyboard off, so the cursor, filter,\n // drill pin and drill scroll are still there when help closes.\n if (popup !== null) {\n return (\n <Box flexDirection=\"column\" height={rows} overflow=\"hidden\">\n {helpOpen ? (\n <Box flexDirection=\"column\" flexGrow={1}>\n <Help rows={rows} />\n </Box>\n ) : null}\n <Box display={helpOpen ? \"none\" : \"flex\"} flexDirection=\"column\" flexGrow={1}>\n <PopupInputActive.Provider value={!helpOpen}>\n {renderPopup(popup)}\n </PopupInputActive.Provider>\n </Box>\n <StatusBar\n mode={helpOpen ? \"help\" : popupFilterEditing ? \"popup-filter\" : \"popup\"}\n tickMs={tickMs}\n footer={footer}\n cols={cols}\n popupName={popupNameForId(popup)}\n popupMode={popupMode}\n activeWorkstream={workstreams.length > 1 ? workstream : undefined}\n />\n </Box>\n );\n }\n\n // Dashboard.\n //\n // overflow=\"hidden\" pinned at the root: when total content\n // exceeds `rows` (e.g. the multi-ws TabStrip adds a row that\n // pushes the sum to rows+1), ink would otherwise emit the\n // overflowing rows past the terminal bottom, scrolling the top\n // off-screen — the user sees the topmost card lose its top\n // border. Clipping inside the height-pinned box keeps the frame\n // bounded to the terminal viewport so nothing is lost above row 1.\n // (bug_tui_tab_switch_stale_render layer 2.)\n return (\n <Box flexDirection=\"column\" height={rows} overflow=\"hidden\">\n {/* Tab strip — null when workstreams.length === 1, so the\n single-ws layout is byte-identical to the pre-multi-ws\n frame. The strip lives INSIDE the height-pinned + clipping\n parent so flexbox accounts for its 1-row height when\n allocating space to the cards below it. */}\n <TabStrip\n workstreams={workstreams}\n active={safeActive}\n terminalColumns={cols}\n tornDownWorkstreams={tornDownWorkstreams}\n />\n {hasSnapshotError && (\n <Box borderStyle=\"round\" borderColor=\"red\" paddingX={1}>\n <Text color=\"red\">snapshot error: {snap.error}</Text>\n </Box>\n )}\n <Box height={availableForCards} overflow=\"hidden\" flexDirection=\"column\">\n <DashboardColumns\n rows={availableForCards}\n model={dashboardModel}\n snapshot={snap.data}\n db={db}\n workstream={workstream}\n />\n </Box>\n <Box flexGrow={1} />\n <StatusBar\n mode=\"dashboard\"\n tickMs={tickMs}\n footer={footer}\n cols={cols}\n activeWorkstream={workstreams.length > 1 ? workstream : undefined}\n />\n </Box>\n );\n\n function renderPopup(id: PopupRegistryId): ReactElement {\n const props: CommonPopupProps = {\n yank: yankFn,\n onFooter: footerFn,\n onClose: () => {\n setPopup(null);\n setPopupMode(\"list\");\n setPopupFilterEditing(false);\n setPopupActions([]);\n },\n snapshot: snap.data,\n fastTickNonce: snap.fastTickNonce,\n slowTickNonce: snap.slowTickNonce,\n mode: popupMode,\n onModeChange: setPopupMode,\n onFilterEditingChange: setPopupFilterEditing,\n popupActions,\n db,\n workstream,\n };\n const Popup = POPUP_REGISTRY[id];\n return <Popup {...props} />;\n }\n}\n\ninterface DashboardLayoutModel {\n cardsRows: number;\n assignments: ColumnAssignment[];\n widths: ColumnWidth[];\n budgetsByColumn: RowBudgetMap[];\n hiddenCount: number;\n}\n\ninterface DashboardColumnsProps {\n rows: number;\n model: DashboardLayoutModel;\n snapshot: ReturnType<typeof useDashboardSnapshot>[\"data\"];\n db: Db;\n workstream: string;\n}\n\nfunction buildDashboardLayoutModel(\n cols: number,\n rows: number,\n visibility: CardVisibility,\n snapshot: ReturnType<typeof useDashboardSnapshot>[\"data\"],\n): DashboardLayoutModel {\n const visible = visibleCardIds(visibility);\n const firstCull = cullCardsForRows(visible, rows);\n const cullBudget = firstCull.hidden.length > 0 ? Math.max(1, rows - 1) : rows;\n const culled = cullBudget === rows ? firstCull : cullCardsForRows(visible, cullBudget);\n const cardsRows = culled.hidden.length > 0 ? Math.max(1, rows - 1) : rows;\n const packed = layoutDashboardColumns(cols, culled.cards);\n const assignments = balanceColumns(packed, (id) => dataCountForCard(id, snapshot));\n const widths = columnWidths(cols, assignments.length);\n const budgetsByColumn = assignments.map((assignment) =>\n capRowBudgetsForColumn(\n cardsRows,\n assignment.cards,\n allocateRowBudgets(\n cardsRows,\n assignment.cards.map((id) => ({ id, dataCount: dataCountForCard(id, snapshot) })),\n ),\n ),\n );\n return { cardsRows, assignments, widths, budgetsByColumn, hiddenCount: culled.hidden.length };\n}\n\nfunction DashboardColumns({\n rows,\n model,\n snapshot,\n db,\n workstream,\n}: DashboardColumnsProps): ReactElement {\n return (\n <Box flexDirection=\"column\" height={rows} overflow=\"hidden\">\n <Box flexDirection=\"row\" gap={1} height={model.cardsRows} overflow=\"hidden\">\n {model.assignments.map((assignment, i) => {\n const width = model.widths[i]?.width ?? 80;\n const budgets = model.budgetsByColumn[i];\n if (budgets === undefined) return null;\n return (\n <Box key={assignment.cards.join(\"-\")} flexDirection=\"column\" width={width}>\n {assignment.cards.map((id) =>\n renderCard(id, { snapshot, db, workstream, width, budgets }),\n )}\n </Box>\n );\n })}\n </Box>\n {model.hiddenCount > 0 ? (\n <Text dimColor>+{model.hiddenCount} cards hidden · resize taller</Text>\n ) : null}\n </Box>\n );\n}\n\nfunction capRowBudgetsForColumn(\n availableRows: number,\n cards: ReadonlyArray<CardId>,\n budgets: ReturnType<typeof allocateRowBudgets>,\n): ReturnType<typeof allocateRowBudgets> {\n const out: Record<CardId, number> = { ...budgets };\n let remaining = Math.max(0, Math.floor(availableRows));\n for (const id of cards) {\n const chrome = CARD_CONFIGS[id].chrome;\n const maxBody = Math.max(0, remaining - chrome);\n out[id] = Math.min(out[id], maxBody);\n remaining = Math.max(0, remaining - chrome - out[id]);\n }\n return out;\n}\n\ninterface RenderCardContext {\n snapshot: DashboardSnapshot;\n db: Db;\n workstream: string;\n width: number;\n budgets: ReturnType<typeof allocateRowBudgets>;\n}\n\nfunction renderCard(id: CardId, { snapshot, db, workstream, width, budgets }: RenderCardContext) {\n const Card = CARD_REGISTRY[id];\n return (\n <Card\n key={id}\n snapshot={snapshot}\n db={db}\n workstream={workstream}\n rowBudget={budgets[id]}\n cols={width}\n />\n );\n}\n\nfunction visibleCardIds(visibility: CardVisibility): CardId[] {\n const ids: CardId[] = [];\n for (const id of [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] as const) {\n if (visibility[id]) ids.push(id);\n }\n return ids;\n}\n\n// Both helpers below are pure CARD_CONFIGS table reads after\n// review_tui_card_key_from_id_redundant. They were 24-line\n// switch(id) blocks that duplicated the per-card name list already\n// living in src/cli/tui/layout.ts. The 'dag' / 'allTasks' branches\n// stay inline because they're not card slots — they're\n// keybind-only popups with no row in CARD_CONFIGS.\nfunction popupNameForId(id: NonNullable<PopupId>): string {\n if (id === \"dag\") return \"DAG\";\n if (id === \"allTasks\") return \"All tasks\";\n return CARD_CONFIGS[id].label;\n}\n","// Agents card — glanceable summary of every agent in the workstream.\n//\n// Per design_card_agents (workstream `tui`): name | status | task |\n// idle. Header includes agentStatusHistogram. Status glyph rendering goes\n// through agent-display.ts so glyph selection stays centralised.\n//\n// Aesthetic: rounded border, dim border colour, section header inset\n// into the top.\n//\n// Rows are column-aligned via src/cli/tui/columns.ts so name / task /\n// idle line up cleanly. Per feat_column_aligned_lists clipping policy:\n// glyph + agent name + idle marker are PROTECTED; the owned-task\n// summary is CLIPPABLE (it's a free-form string and the popup carries\n// the full version).\n\nimport { Text } from \"ink\";\nimport type { ReactElement } from \"react\";\nimport { GLYPH } from \"../../../glyphs.js\";\nimport {\n agentStateHistogram,\n summarizeOwnedTasks,\n type WorkstreamSnapshot,\n} from \"../../../state.js\";\nimport { IDLE_GLYPH } from \"../../format.js\";\nimport { agentStateGlyph } from \"../agent-display.js\";\nimport {\n type ColumnSpec,\n contentWidthFromCols,\n layoutColumns,\n renderRow,\n termColsForLayout,\n} from \"../columns.js\";\nimport { CARD_CONFIGS, cardRenderHeight } from \"../layout.js\";\nimport { ListRow } from \"../list-row.js\";\nimport { TitledBox } from \"../titled-box.js\";\nimport { CardPlaceholder } from \"./_placeholder.js\";\n\nexport interface AgentsCardProps {\n snapshot: WorkstreamSnapshot | null;\n rowBudget?: number;\n cols?: number;\n}\n\nexport const cardConfig = CARD_CONFIGS[1];\n\nconst COLUMN_SPECS: ReadonlyArray<ColumnSpec> = [\n { kind: \"protect\" }, // status glyph\n { kind: \"protect\" }, // agent name\n { kind: \"clip\", min: 1 }, // owned-task summary\n { kind: \"protect\" }, // idle marker\n];\n\nexport function AgentsCard({ snapshot, rowBudget, cols }: AgentsCardProps): ReactElement {\n const contentWidth = contentWidthFromCols(cols ?? termColsForLayout());\n if (snapshot === null) {\n return CardPlaceholder({\n title: \"Agents\",\n cardId: 1,\n config: cardConfig,\n rowBudget,\n cols,\n text: \"loading…\",\n });\n }\n\n const agents = snapshot.view.agents;\n const histogram = agentStateHistogram(agents);\n const histLabel = formatHistogram(histogram);\n\n if (agents.length === 0) {\n return CardPlaceholder({\n title: \"Agents\",\n cardId: 1,\n config: cardConfig,\n rowBudget,\n cols,\n children: (\n <Text dimColor>(no agents) try `mu agent spawn worker-1 -w {snapshot.workstreamName}`</Text>\n ),\n });\n }\n\n const shown = agents.slice(0, rowBudget ?? cardConfig.maxRows);\n const more = agents.length - shown.length;\n const bottomLabel = more > 0 ? `+${more} more · Shift+1` : undefined;\n\n // Build the cell matrix once so column widths consider every visible row.\n const rows = shown.map((a) => {\n const owned = snapshot.inProgress.filter((t) => t.ownerName === a.name);\n const taskBit = summarizeOwnedTasks(owned).bit;\n const idle = a.idle ? `${IDLE_GLYPH} idle` : \"\";\n // A pi agent whose control socket does not answer: flag the gap.\n const ctlBroken = a.ctl === \"missing\" || a.ctl === \"refused\";\n const glyph = ctlBroken ? `${agentStateGlyph(a.state)}${GLYPH.fail}` : agentStateGlyph(a.state);\n return [glyph, a.name, taskBit, idle];\n });\n const widths = layoutColumns(rows, COLUMN_SPECS, contentWidth);\n\n return (\n <TitledBox\n height={cardRenderHeight(cardConfig, rowBudget)}\n width={cols}\n title=\"Agents\"\n subtitle={histLabel}\n cardId={1}\n bottomLabel={bottomLabel}\n >\n {shown.map((a, i) => {\n const row = rows[i];\n if (row === undefined) return null;\n const padded = renderRow(row, widths, COLUMN_SPECS);\n const colors = [\n undefined, // glyph\n { bold: true }, // name\n { dimColor: true }, // taskBit\n a.idle ? { color: \"yellow\" } : { dimColor: true }, // idle marker\n ];\n return <ListRow key={a.name} cells={padded} contentWidth={contentWidth} colors={colors} />;\n })}\n </TitledBox>\n );\n}\n\nfunction formatHistogram(h: ReadonlyMap<string, number>): string {\n const parts: string[] = [];\n for (const [status, n] of h.entries()) {\n parts.push(`${n} ${status}`);\n }\n return parts.length === 0 ? \"(none)\" : parts.join(\" · \");\n}\n","import type { LiveAgent } from \"../../agents.js\";\nimport { agentStateGlyph } from \"../../glyphs.js\";\nimport type { WorkstreamSnapshot } from \"../../state.js\";\nimport type { TaskRow } from \"../../tasks.js\";\n\ntype AgentDisplayRow = Pick<LiveAgent, \"name\" | \"state\">;\n\nexport { agentStateGlyph };\n\n/** Return a stable lookup of live agent rows keyed by agent name. */\nexport function agentByName(\n snapshot: WorkstreamSnapshot | null,\n): ReadonlyMap<string, AgentDisplayRow> {\n const agents = snapshot?.view?.agents ?? [];\n return new Map(agents.map((a) => [a.name, a]));\n}\n\n/** Render a known live agent row with its status glyph. */\nexport function formatKnownAgentDisplayName(agent: AgentDisplayRow): string {\n return `${agentStateGlyph(agent.state)} ${agent.name}`;\n}\n\n/**\n * Render an agent reference from another TUI row.\n *\n * If the agent is present in the live-agent view, prefix the name with\n * the same status glyph used by the Agents card. If the row is an\n * owner/workspace reference whose agent is not in the live view (stale\n * snapshot, imported DB, or anonymous/self claim), keep the raw name\n * rather than inventing an unknown state. Null owners render as the\n * existing em dash.\n */\nexport function formatAgentRefDisplayName(\n agentName: string | null,\n agents: ReadonlyMap<string, AgentDisplayRow>,\n): string {\n if (agentName === null) return \"—\";\n const agent = agents.get(agentName);\n if (agent === undefined) return agentName;\n return formatKnownAgentDisplayName(agent);\n}\n\n/**\n * Render a task's owner. The live state glyph means \"this agent is\n * working on this task now\", so only IN_PROGRESS rows get it; CLOSED\n * rows (and OPEN rows that kept an owner) show the bare name.\n */\nexport function formatTaskOwnerDisplay(\n task: Pick<TaskRow, \"status\" | \"ownerName\">,\n agents: ReadonlyMap<string, AgentDisplayRow>,\n): string {\n if (task.status !== \"IN_PROGRESS\") return task.ownerName ?? \"—\";\n return formatAgentRefDisplayName(task.ownerName, agents);\n}\n","import { stripVTControlCharacters } from \"node:util\";\nimport stringWidth from \"string-width\";\n\nconst ESC = \"\\u001B\";\nconst ANSI_PATTERN = new RegExp(`${ESC}\\\\[[0-?]*[ -/]*[@-~]`, \"y\");\nconst SGR_PATTERN = new RegExp(`^${ESC}\\\\[([0-9;]*)m$`);\nconst RESET = `${ESC}[0m`;\n\n// Printable ASCII plus the width-1 glyphs mu draws (dashes/quotes/\"…\",\n// arrows incl. \"↻\", box-drawing, \"π\"), after stripping SGR: width is the\n// stripped length. string-width's per-grapheme segmentation cost\n// ~150 ms per 4.4k-line DAG body; everything else still goes through it.\nconst NARROW = /^[\\x20-\\x7e\\u03c0\\u2010-\\u2027\\u2190-\\u21ff\\u2500-\\u257f]*$/;\n\n/** Terminal-visible width of `s` (ANSI-aware, wide-char-aware). */\nexport function visibleWidth(s: string): number {\n const plain = s.includes(ESC) ? stripVTControlCharacters(s) : s;\n return NARROW.test(plain) ? plain.length : stringWidth(s);\n}\n\ninterface Token {\n text: string;\n width: number;\n}\n\n/**\n * Wrap a single line by terminal-visible width while preserving\n * ANSI SGR colour/style across hard wrap boundaries.\n */\nexport function wrapAnsi(line: string, width: number): string[] {\n if (line === \"\") return [line];\n if (width <= 0 || visibleWidth(line) <= width) {\n // Even the early-return path must guarantee SGR is closed so the ink\n // render does not leak colour into adjacent chrome (the popup right\n // border is the canonical reproducer): a short colored line like\n // `\\x1b[31m+ added` with no trailing reset would otherwise paint the\n // following border cell red. (bug_drill_ansi_state_leaks_into_border)\n return [closeIfOpen(line, computeActiveSgr(line))];\n }\n\n const out: string[] = [];\n const activeSgr: string[] = [];\n let chunk = \"\";\n let chunkWidth = 0;\n let i = 0;\n\n const emit = () => {\n if (chunkWidth === 0) return;\n out.push(closeIfOpen(chunk, activeSgr));\n chunk = activeSgr.join(\"\");\n chunkWidth = 0;\n };\n\n while (i < line.length) {\n ANSI_PATTERN.lastIndex = i;\n const ansi = ANSI_PATTERN.exec(line);\n if (ansi?.index === i) {\n const seq = ansi[0];\n chunk += seq;\n updateActiveSgr(seq, activeSgr);\n i += seq.length;\n continue;\n }\n\n const token = nextToken(line, i);\n if (chunkWidth > 0 && chunkWidth + token.width > width) emit();\n chunk += token.text;\n chunkWidth += token.width;\n i += token.text.length;\n\n if (chunkWidth >= width) emit();\n }\n\n // Same close-if-open guarantee as emit() for the trailing chunk: an\n // input whose final fragment is colored without a closing reset must\n // not bleed into ink's border render on the next row.\n if (chunkWidth > 0 || (chunk !== \"\" && out.length === 0)) {\n out.push(closeIfOpen(chunk, activeSgr));\n }\n return out.length === 0 ? [line] : out;\n}\n\nexport function padAnsiLine(line: string, width: number): string {\n const w = visibleWidth(line);\n if (w >= width) return line;\n return line + \" \".repeat(width - w);\n}\n\n// Wrapped+padded output per (width, raw line). Drill bodies are rebuilt on\n// every changed fast tick, but almost all of their lines are unchanged, so\n// a re-wrap is a split + lookups + join instead of ~4k width computations.\n// Bounded: cleared wholesale when full (a big body refills it in one pass).\nconst WRAP_CACHE_MAX = 20_000;\nconst wrapCache = new Map<string, string>();\n\nfunction wrapAndPadLine(line: string, width: number): string {\n const key = `${width}\\u0000${line}`;\n const hit = wrapCache.get(key);\n if (hit !== undefined) return hit;\n const out = wrapAnsi(line, width)\n .map((l) => padAnsiLine(l, width))\n .join(\"\\n\");\n if (wrapCache.size >= WRAP_CACHE_MAX) wrapCache.clear();\n wrapCache.set(key, out);\n return out;\n}\n\nexport function wrapAndPadAnsiLines(text: string, width: number): string {\n if (text === \"\") return \"\";\n return text\n .split(\"\\n\")\n .map((line) => wrapAndPadLine(line, width))\n .join(\"\\n\");\n}\n\n/** Test hook: number of cached wrapped lines. */\nexport function wrapCacheSizeForTests(): number {\n return wrapCache.size;\n}\n\nfunction nextToken(text: string, offset: number): Token {\n const first = text[offset];\n if (first === undefined) return { text: \"\", width: 0 };\n const codePoint = text.codePointAt(offset);\n if (codePoint === undefined) return { text: first, width: visibleWidth(first) };\n const char = String.fromCodePoint(codePoint);\n return { text: char, width: visibleWidth(char) };\n}\n\nfunction closeIfOpen(text: string, active: string[]): string {\n return active.length > 0 ? `${text}${RESET}` : text;\n}\n\nfunction computeActiveSgr(line: string): string[] {\n const active: string[] = [];\n let i = 0;\n while (i < line.length) {\n ANSI_PATTERN.lastIndex = i;\n const m = ANSI_PATTERN.exec(line);\n if (m?.index === i) {\n updateActiveSgr(m[0], active);\n i += m[0].length;\n continue;\n }\n i++;\n }\n return active;\n}\n\nfunction updateActiveSgr(seq: string, active: string[]): void {\n const match = SGR_PATTERN.exec(seq);\n if (match === null) return;\n const rawParams = match[1] ?? \"\";\n const params = rawParams === \"\" ? [0] : rawParams.split(\";\").map((p) => Number(p || \"0\"));\n if (params.some(isFullReset)) {\n active.length = 0;\n return;\n }\n active.push(seq);\n}\n\nfunction isFullReset(code: number): boolean {\n return code === 0;\n}\n","// columns.ts — column-alignment helpers for the TUI cards/popups.\n//\n// Per feat_column_aligned_lists (workstream `tui-impl`) and the\n// design_card_*/popup_* notes (workstream `tui`): rows in every card\n// and popup were rendered as free-flowing `<Text>` chunks separated by\n// single spaces. With variable-width fields (agent names, task ids,\n// status tokens, ROI numbers) they drifted visually and were hard to\n// scan. Match the static `mu task list` / `mu agent list` convention:\n// each column gets a fixed width based on the widest cell across the\n// visible rows, then we pad with spaces.\n//\n// Why no ascii grid borders inside the rounded card: the outer\n// rounded border is the only structural element; rows are just padded\n// text. Anything more (vertical bars, header rules) would compete\n// with the rounded frame.\n//\n// Width counting: `string-width` (transitive via cli-table3) handles\n// emoji / CJK / ANSI escapes correctly; bare `String.length` is wrong\n// for shared state glyphs and for any future i18n.\n//\n// Clipping policy: cells fall into two buckets per the task notes —\n// PROTECTED (task ids, agent names, status tokens, glyphs, ROI nums,\n// timestamps, event verbs) which must never be clipped because the\n// user yanks them verbatim; and CLIPPABLE (titles, payloads, role\n// descriptions, goal lists, notes previews) which degrade gracefully\n// under truncation. layoutColumns() respects the bucket: protected\n// cells take their natural width unconditionally, clippable cells\n// share whatever budget is left.\n\nimport { truncate } from \"../format.js\";\nimport { visibleWidth } from \"./wrap-ansi.js\";\n\nexport type ColumnKind = \"protect\" | \"clip\";\n\nexport interface ColumnSpec {\n /** \"protect\" — never clip; \"clip\" — truncate to share remaining budget. */\n kind: ColumnKind;\n /** Default \"left\". \"right\" pads on the left (numeric columns). */\n align?: \"left\" | \"right\";\n /** Optional minimum width (default 0). */\n min?: number;\n /** Optional maximum natural width to consider when sizing protected\n * columns — useful when a single rogue row would balloon the\n * column. Default: no cap. */\n max?: number;\n}\n\n/** Display width of `s`, ignoring ANSI escapes and counting wide chars. */\nexport function cellWidth(s: string): number {\n return visibleWidth(s);\n}\n\n/** Pad `s` to width `n` with spaces. align=\"right\" pads on the left.\n * No-op if the cell is already wider than `n` (no clipping here;\n * callers that need clipping should run truncateCell first). */\nexport function padCell(s: string, n: number, align: \"left\" | \"right\" = \"left\"): string {\n const w = cellWidth(s);\n if (w >= n) return s;\n const pad = \" \".repeat(n - w);\n return align === \"right\" ? pad + s : s + pad;\n}\n\n/** Truncate `s` to display width ≤ `n`, appending `…` if clipped.\n * Wraps src/cli/format.ts truncate() but uses string-width for the\n * threshold check so emoji / wide chars don't false-pass. */\nexport function truncateCell(s: string, n: number): string {\n if (n <= 0) return \"\";\n if (cellWidth(s) <= n) return s;\n // format.truncate works on `.length`; for ASCII titles (the\n // dominant case) this matches display width. For wide-char cells\n // we round down: chip 1 more codepoint at a time until we fit.\n let candidate = truncate(s, n);\n while (cellWidth(candidate) > n && candidate.length > 1) {\n candidate = truncate(candidate, candidate.length - 1);\n }\n return candidate;\n}\n\n/** Compute the natural (max-cell) width of every column across rows. */\nexport function naturalWidths(rows: ReadonlyArray<ReadonlyArray<string>>): number[] {\n if (rows.length === 0) return [];\n const ncols = Math.max(...rows.map((r) => r.length));\n const widths = new Array<number>(ncols).fill(0);\n for (const r of rows) {\n for (let i = 0; i < r.length; i++) {\n const cell = r[i] ?? \"\";\n const w = cellWidth(cell);\n if (w > (widths[i] ?? 0)) widths[i] = w;\n }\n }\n return widths;\n}\n\n/** Per-column padding between cells, in the rendered output. Two\n * spaces is the convention used by `mu task list` / `mu agent list`\n * (cli-table3 uses one + a vertical bar; we drop the bar). */\nexport const COL_GUTTER = 2;\n\n/** Convert a terminal-column count into the content-area width inside\n * a TitledBox / popup Shell.\n *\n * Both containers stack the same chrome on each side:\n * - 1 col rounded border\n * - 1 col paddingX\n * → 2 cols per side, 4 cols total — subtract from the outer width.\n *\n * Floored at 0 so very narrow terminals (cols < 4) don't drive a\n * negative budget into layoutColumns; the App.tsx terminal-too-small\n * guard (cols < 40) is the visible last resort.\n *\n * Per bug_tui_long_lines_overflow: every card/popup needs to pass\n * the resulting contentWidth to layoutColumns so clip columns\n * actually clip instead of overflowing the row to a second line. */\nexport function contentWidthFromCols(cols: number): number {\n return Math.max(0, cols - 4);\n}\n\n/**\n * Deprecated back-compat alias for tests and out-of-tree callers that\n * still need a non-hook fallback. Ink components should prefer\n * `useStdout()` and then pass `stdout?.columns ?? 80` to\n * `contentWidthFromCols()`.\n */\nexport function termColsForLayout(): number {\n return process.stdout.columns ?? 80;\n}\n\n/**\n * Compute the final width allocated to each column, given:\n * - rows the cell matrix (post-string conversion)\n * - specs per-column kind/align/min/max\n * - totalWidth total renderable width of the row (the inside of\n * the rounded border, i.e. terminal cols minus\n * border + paddingX). When undefined we just use\n * the natural widths (no clipping).\n *\n * Algorithm:\n * 1. Natural width per column.\n * 2. Apply per-column min/max caps.\n * 3. If totalWidth is undefined, return as-is.\n * 4. Otherwise, sum the protected widths + gutters.\n * 5. Distribute the remainder across clippable columns:\n * - Equal share by default.\n * - The LAST clippable column absorbs any rounding leftover.\n * 6. If even the protected cells overflow the budget, return the\n * natural widths anyway — App.tsx's terminal-too-small guard is\n * the last resort, and the dashboard layout will visually clip\n * regardless.\n */\nexport function layoutColumns(\n rows: ReadonlyArray<ReadonlyArray<string>>,\n specs: ReadonlyArray<ColumnSpec>,\n totalWidth?: number,\n): number[] {\n const natural = naturalWidths(rows);\n const widths = specs.map((spec, i) => {\n const nat = natural[i] ?? 0;\n let w = nat;\n if (spec.min !== undefined && w < spec.min) w = spec.min;\n if (spec.max !== undefined && w > spec.max) w = spec.max;\n return w;\n });\n\n if (totalWidth === undefined) return widths;\n\n const ncols = specs.length;\n const gutters = ncols > 1 ? (ncols - 1) * COL_GUTTER : 0;\n const protectedSum = specs.reduce(\n (acc, s, i) => (s.kind === \"protect\" ? acc + (widths[i] ?? 0) : acc),\n 0,\n );\n const remaining = totalWidth - protectedSum - gutters;\n const clipIdx = specs.map((s, i) => (s.kind === \"clip\" ? i : -1)).filter((i) => i >= 0);\n\n if (clipIdx.length === 0) return widths;\n if (remaining <= 0) {\n // Protected cells alone overflow; give clippable cols 0 each\n // so they collapse rather than push the row arbitrarily wide.\n for (const i of clipIdx) widths[i] = 0;\n return widths;\n }\n\n // Sum of clippable natural widths; if they fit, leave them as-is.\n const clipNaturalSum = clipIdx.reduce((acc, i) => acc + (widths[i] ?? 0), 0);\n if (clipNaturalSum <= remaining) return widths;\n\n // Equal share per clippable column.\n const each = Math.floor(remaining / clipIdx.length);\n const leftover = remaining - each * clipIdx.length;\n for (let k = 0; k < clipIdx.length; k++) {\n const i = clipIdx[k];\n if (i === undefined) continue;\n widths[i] = each;\n }\n // Anchor the row visually: hand any leftover to the LAST clippable\n // column (typically the title / payload).\n const lastIdx = clipIdx[clipIdx.length - 1];\n if (lastIdx !== undefined && leftover > 0) widths[lastIdx] = (widths[lastIdx] ?? 0) + leftover;\n return widths;\n}\n\n/**\n * Render one row of cells to display strings: clip clippable cells\n * to their allocated width, then pad every cell to its column width.\n * Returns one string per column — callers map into individual <Text>\n * chunks so per-cell colour still works.\n */\nexport function renderRow(\n cells: ReadonlyArray<string>,\n widths: ReadonlyArray<number>,\n specs: ReadonlyArray<ColumnSpec>,\n): string[] {\n const out: string[] = [];\n for (let i = 0; i < specs.length; i++) {\n const spec = specs[i];\n const w = widths[i] ?? 0;\n const raw = cells[i] ?? \"\";\n if (spec === undefined) {\n out.push(raw);\n continue;\n }\n const clipped = spec.kind === \"clip\" ? truncateCell(raw, w) : raw;\n out.push(padCell(clipped, w, spec.align ?? \"left\"));\n }\n return out;\n}\n","// layout.ts — pure responsive-dashboard layout helpers.\n//\n// The TUI dashboard is glanceable, not exhaustive: cards should use\n// the horizontal and vertical space available without letting one noisy\n// list crowd out the rest. This module owns the two pure pieces that\n// make that deterministic and easy to test:\n//\n// 1. layoutColumns(cols, visibleCardIds) — breakpoint + pair-aware\n// card packing into dashboard columns.\n// 2. allocateRowBudgets(availableRows, cards) — per-column body-row\n// allocator with min-row guarantees, max caps, and largest-\n// remainder leftover distribution.\n//\n// No ink/react imports here. Cards import their own config from this\n// file and re-export it as `cardConfig`; <App> imports the pure helpers\n// and the card modules separately.\n\nimport type { WorkstreamSnapshot } from \"../../state.js\";\n\nexport type CardId = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9;\n\nexport type CardGroup = \"small-pair\" | \"task-list\" | \"stream\";\n\nexport interface CardRowConfig {\n /** Stable card name (e.g. \"commits\", \"agents\", \"inProgress\"). The\n * single source of truth for the per-card identifier; replaces\n * the old hand-rolled cardKeyFromId switch in app.tsx. Used as\n * the card-toggle visibility key (alongside the numeric CardId)\n * and as a stable string handle anywhere a name is needed. */\n name: string;\n /** Human label shown in the popup status bar (e.g. \"Commits\",\n * \"In-progress\", \"Tasks\"). Replaces the old popupNameForId\n * switch in app.tsx. Distinct from `name` because some labels\n * diverge from a naive capitalise (slot 3's name is \"ready\"\n * but its popup is the all-Tasks view; slot 6 is \"In-progress\",\n * not \"InProgress\"). */\n label: string;\n /** Minimum BODY rows to reserve for the card. Empty data still gets this much budget. */\n minRows: number;\n /** Maximum BODY rows worth rendering on the dashboard. Popups are exhaustive. */\n maxRows: number;\n /** Non-body rows consumed by TitledBox chrome + footer inset when truncated. */\n chrome: number;\n /** Static neighbour preference used by the pair-aware packer. */\n group: CardGroup;\n}\n\nexport type CardConfigMap = Readonly<Record<CardId, CardRowConfig>>;\n\n// Two rows of TitledBox chrome: 1 top-border line + 1 bottom-border\n// line. The body is rendered by the inner Box (paddingY=0) and the\n// PaddedRows helper fills it to exactly `rowBudget` text rows, so the\n// declared outer height is `chrome + rowBudget` with no slack.\n// Historically this was 4 (over-reservation) which left 2 blank rows\n// at the bottom of every card and made the dashboard feel loose; the\n// pack_dashboard_cards_tighter polish lowered it to the true chrome\n// cost so cards stack flush against each other.\nconst CARD_CHROME_ROWS = 2;\n\nexport const CARD_CONFIGS: CardConfigMap = {\n 0: {\n name: \"commits\",\n label: \"Commits\",\n minRows: 3,\n maxRows: 12,\n chrome: CARD_CHROME_ROWS,\n group: \"stream\",\n },\n 1: {\n name: \"agents\",\n label: \"Agents\",\n minRows: 2,\n maxRows: 10,\n chrome: CARD_CHROME_ROWS,\n group: \"small-pair\",\n },\n 2: {\n name: \"tracks\",\n label: \"Tracks\",\n minRows: 2,\n maxRows: 8,\n chrome: CARD_CHROME_ROWS,\n group: \"small-pair\",\n },\n 3: {\n name: \"ready\",\n label: \"Tasks\",\n minRows: 3,\n maxRows: 15,\n chrome: CARD_CHROME_ROWS,\n group: \"task-list\",\n },\n 4: {\n name: \"log\",\n label: \"Log\",\n minRows: 3,\n maxRows: 12,\n chrome: CARD_CHROME_ROWS,\n group: \"stream\",\n },\n 5: {\n name: \"workspaces\",\n label: \"Workspaces\",\n minRows: 2,\n maxRows: 8,\n chrome: CARD_CHROME_ROWS,\n group: \"small-pair\",\n },\n 6: {\n name: \"inProgress\",\n label: \"In-progress\",\n minRows: 3,\n maxRows: 12,\n chrome: CARD_CHROME_ROWS,\n group: \"task-list\",\n },\n 7: {\n name: \"blocked\",\n label: \"Blocked\",\n minRows: 3,\n maxRows: 12,\n chrome: CARD_CHROME_ROWS,\n group: \"task-list\",\n },\n 8: {\n name: \"recent\",\n label: \"Recent\",\n minRows: 3,\n maxRows: 12,\n chrome: CARD_CHROME_ROWS,\n group: \"task-list\",\n },\n 9: {\n name: \"doctor\",\n label: \"Doctor\",\n minRows: 2,\n maxRows: 8,\n chrome: CARD_CHROME_ROWS,\n group: \"small-pair\",\n },\n};\n\nexport interface ColumnAssignment {\n cards: CardId[];\n}\n\nexport interface CardHitRegion {\n id: CardId;\n column: number;\n left: number;\n right: number;\n top: number;\n bottom: number;\n}\n\nexport function dashboardColumnCount(cols: number): 1 | 2 | 3 | 4 {\n if (cols >= 240) return 4;\n if (cols >= 180) return 3;\n if (cols >= 120) return 2;\n return 1;\n}\n\n/**\n * Breakpoint + pair-aware card packer.\n *\n * - <120 cols: single stack, sorted by slot with slot 0 last.\n * - 120-179: small/task columns with stream cards split as trailers.\n * - 180-239: small cards / task-list / stream.\n * - 240+: split the two natural small pairs, then task-list, then stream.\n *\n * Empty columns are filtered out so toggling a whole group off\n * redistributes the remaining columns instead of leaving a blank lane.\n */\nexport function layoutColumns(\n cols: number,\n visibleCardIds: ReadonlyArray<CardId>,\n): ColumnAssignment[] {\n const visible = normalizeVisible(visibleCardIds);\n const target = dashboardColumnCount(cols);\n if (target === 1) {\n const cards = sortCards(visible);\n return cards.length === 0 ? [] : [{ cards }];\n }\n\n const small = sortCards(visible.filter((id) => CARD_CONFIGS[id].group === \"small-pair\"));\n const task = sortCards(visible.filter((id) => CARD_CONFIGS[id].group === \"task-list\"));\n const stream = sortCards(visible.filter((id) => CARD_CONFIGS[id].group === \"stream\"));\n\n const columns = (() => {\n if (target === 2) {\n const leftStream: CardId[] = [];\n const rightStream: CardId[] = [];\n for (const [index, id] of stream.entries()) {\n if (stream.length === 1 && id === 0) {\n rightStream.push(id);\n continue;\n }\n (index % 2 === 0 ? leftStream : rightStream).push(id);\n }\n return [\n [...small, ...sortCards(leftStream)],\n [...task, ...sortCards(rightStream)],\n ];\n }\n if (target === 3) return [small, task, stream];\n const topSmall = small.filter((id) => id === 1 || id === 2);\n const bottomSmall = small.filter((id) => id === 5 || id === 9);\n return [topSmall, bottomSmall, task, stream];\n })();\n\n return columns.filter((cards) => cards.length > 0).map((cards) => ({ cards }));\n}\n\nexport interface ColumnWidth {\n width: number;\n}\n\nexport function columnWidths(totalCols: number, columnCount: number): ColumnWidth[] {\n if (columnCount <= 0) return [];\n const gaps = columnCount - 1;\n const usable = Math.max(columnCount, totalCols - gaps);\n const base = Math.floor(usable / columnCount);\n const extra = usable - base * columnCount;\n return Array.from({ length: columnCount }, (_, i) => ({ width: base + (i < extra ? 1 : 0) }));\n}\n\nexport function dashboardCardHitRegions(\n assignments: ReadonlyArray<ColumnAssignment>,\n widths: ReadonlyArray<ColumnWidth>,\n budgets: ReadonlyArray<RowBudgetMap>,\n opts: { top?: number; left?: number; columnGap?: number } = {},\n): CardHitRegion[] {\n const topBase = opts.top ?? 1;\n const leftBase = opts.left ?? 1;\n const gap = opts.columnGap ?? 1;\n const out: CardHitRegion[] = [];\n let left = leftBase;\n for (let column = 0; column < assignments.length; column++) {\n const assignment = assignments[column];\n const width = widths[column]?.width;\n const budget = budgets[column];\n if (assignment === undefined || width === undefined || budget === undefined) continue;\n let top = topBase;\n for (const id of assignment.cards) {\n const height = CARD_CONFIGS[id].chrome + budget[id];\n out.push({ id, column, left, right: left + width - 1, top, bottom: top + height - 1 });\n top += height;\n }\n left += width + gap;\n }\n return out;\n}\n\nexport function cardRenderHeight(\n config: CardRowConfig,\n rowBudget: number | undefined,\n): number | undefined {\n return rowBudget === undefined ? undefined : config.chrome + rowBudget;\n}\n\nexport function hitTestDashboardCard(\n regions: ReadonlyArray<CardHitRegion>,\n point: { x: number; y: number },\n): CardId | null {\n for (const region of regions) {\n if (\n point.x >= region.left &&\n point.x <= region.right &&\n point.y >= region.top &&\n point.y <= region.bottom\n ) {\n return region.id;\n }\n }\n return null;\n}\n\nexport interface RowBudgetInput {\n id: CardId;\n dataCount: number;\n config?: CardRowConfig;\n}\n\nexport type RowBudgetMap = Readonly<Record<CardId, number>>;\n\nconst CARD_CULL_PRIORITY: readonly CardId[] = [9, 8, 5, 2, 7, 6, 4, 0, 1, 3];\nconst CARD_CULL_LAYOUT_COLS = 140;\n\nexport interface CulledCards {\n /** Surviving cards, preserving the caller's visible-set order after de-dupe. */\n cards: CardId[];\n /** Cards hidden because the pane is too short, in cull-priority order. */\n hidden: CardId[];\n}\n\n/**\n * Trim low-priority dashboard cards until the minimum stack fits.\n *\n * The user-controlled visible set is the ceiling: toggled-off cards\n * never reappear here. We only cull further, keeping at least one\n * card (the highest-priority visible card) so a tiny-but-not-panic\n * pane still renders a useful dashboard plus the resize hint.\n */\nexport function cullCardsForRows(\n visibleCardIds: ReadonlyArray<CardId>,\n availableRows: number,\n): CulledCards {\n const cards = normalizeVisible(visibleCardIds);\n const hidden: CardId[] = [];\n if (cards.length === 0) return { cards, hidden };\n\n const remaining = new Set<CardId>(cards);\n const budget = Math.max(0, Math.floor(availableRows));\n const maxCardsForRows = Math.max(1, Math.floor(budget / CARD_CHROME_ROWS));\n for (const id of CARD_CULL_PRIORITY) {\n const surviving = cards.filter((card) => remaining.has(card));\n if (surviving.length <= maxCardsForRows && tallestMinStackRows(surviving) <= budget) break;\n if (!remaining.has(id)) continue;\n if (remaining.size <= 1) break;\n remaining.delete(id);\n hidden.push(id);\n }\n\n return { cards: cards.filter((id) => remaining.has(id)), hidden };\n}\n\n/**\n * Post-pack column rebalancer. Pure.\n *\n * `layoutColumns` packs cards by static group (small-pair / task-list\n * / stream). When the user toggles cards off, that grouping can leave\n * one column tall and another short — the spatial intuition is\n * preserved, but the screen feels half-empty.\n *\n * `balanceColumns` is a single greedy pass that moves the most-\n * spread-reducing card from the tallest column to the shortest, until\n * no further move strictly reduces (maxHeight − minHeight). The pass\n * runs after `layoutColumns` and before `allocateRowBudgets`, so the\n * downstream pipeline sees a balanced assignment.\n *\n * Invariants:\n * - Stable-when-all-visible: the default 10-card layout is never\n * touched. Balance only fires when at least one card has been\n * toggled off (totalCards < TOTAL_CARD_COUNT). User-driven\n * toggling is what triggers the reflow.\n * - Anchored cards never move: slot 0 (Commits, conventionally\n * last) and slot 3 (Ready, the task-list anchor that motivates\n * the dashboard's primary column).\n * - Slot ordering within each receiver column is preserved via\n * `compareSlot` (slot 0 trailing).\n * - Column count is preserved: the balancer never strips a donor\n * column to empty (the empty-column filter is upstream in\n * `layoutColumns`; the balancer respects whatever it produced).\n */\nconst TOTAL_CARD_COUNT = 10;\n\nexport function balanceColumns(\n assignments: ReadonlyArray<ColumnAssignment>,\n dataCountFn: (id: CardId) => number,\n): ColumnAssignment[] {\n if (assignments.length < 2) return assignments.map((a) => ({ cards: [...a.cards] }));\n const totalCards = assignments.reduce((sum, a) => sum + a.cards.length, 0);\n if (totalCards >= TOTAL_CARD_COUNT) return assignments.map((a) => ({ cards: [...a.cards] }));\n\n const cols = assignments.map((a) => [...a.cards]);\n const heightOf = (id: CardId): number => {\n const config = CARD_CONFIGS[id];\n const data = Math.max(0, Math.floor(dataCountFn(id)));\n return config.chrome + clamp(data, config.minRows, config.maxRows);\n };\n const isAnchored = (id: CardId): boolean => id === 0 || id === 3;\n const heightsOf = (lanes: ReadonlyArray<ReadonlyArray<CardId>>): number[] =>\n lanes.map((lane) => lane.reduce<number>((sum, id) => sum + heightOf(id), 0));\n\n // Greedy outer loop. Each iteration takes one strictly-improving\n // move; bounded by columnCount * cardCount as a hard safety net\n // since each move shrinks the spread (no cycles possible).\n const safetyMax = cols.length * TOTAL_CARD_COUNT;\n for (let iter = 0; iter < safetyMax; iter++) {\n const heights = heightsOf(cols);\n const startSpread = Math.max(...heights) - Math.min(...heights);\n if (startSpread <= 0) break;\n\n let best: { donor: number; receiver: number; cardIndex: number; spread: number } | null = null;\n for (let donor = 0; donor < cols.length; donor++) {\n const donorCards = cols[donor];\n const donorH = heights[donor];\n if (donorCards === undefined || donorH === undefined) continue;\n if (donorCards.length <= 1) continue; // never strip a column to empty\n for (let cardIndex = 0; cardIndex < donorCards.length; cardIndex++) {\n const card = donorCards[cardIndex];\n if (card === undefined || isAnchored(card)) continue;\n const cardH = heightOf(card);\n for (let receiver = 0; receiver < cols.length; receiver++) {\n if (receiver === donor) continue;\n const receiverH = heights[receiver];\n if (receiverH === undefined) continue;\n const newHeights = heights.slice();\n newHeights[donor] = donorH - cardH;\n newHeights[receiver] = receiverH + cardH;\n const newSpread = Math.max(...newHeights) - Math.min(...newHeights);\n if (newSpread < startSpread && (best === null || newSpread < best.spread)) {\n best = { donor, receiver, cardIndex, spread: newSpread };\n }\n }\n }\n }\n if (best === null) break;\n\n const donorCards = cols[best.donor];\n const receiverCards = cols[best.receiver];\n if (donorCards === undefined || receiverCards === undefined) break;\n const moved = donorCards.splice(best.cardIndex, 1)[0];\n if (moved === undefined) break;\n receiverCards.push(moved);\n receiverCards.sort(compareSlot);\n }\n\n return cols.map((cards) => ({ cards }));\n}\n\n/**\n * Allocate BODY rows among the cards in one dashboard column.\n *\n * `availableRows` is the total vertical budget for the column,\n * including card chrome. The returned map contains body rows (the\n * value each card should pass to slice(0, N)). Chrome is still\n * accounted for so columns with many cards don't over-allocate.\n */\nexport function allocateRowBudgets(\n availableRows: number,\n cards: ReadonlyArray<RowBudgetInput>,\n): RowBudgetMap {\n const entries = cards.map((card) => {\n const config = card.config ?? CARD_CONFIGS[card.id];\n const dataCount = Math.max(0, Math.floor(card.dataCount));\n const minRows = Math.max(0, config.minRows);\n const maxRows = Math.max(minRows, config.maxRows);\n const naturalRows = clamp(dataCount, minRows, maxRows);\n return { id: card.id, dataCount, config, minRows, maxRows, naturalRows };\n });\n\n const out = emptyBudgetMap();\n if (entries.length === 0) return out;\n\n const naturalTotal = entries.reduce((sum, e) => sum + e.naturalRows + e.config.chrome, 0);\n if (naturalTotal <= availableRows) {\n for (const e of entries) out[e.id] = e.naturalRows;\n return out;\n }\n\n const chromeTotal = entries.reduce((sum, e) => sum + e.config.chrome, 0);\n const bodyAvailable = Math.max(0, availableRows - chromeTotal);\n const minTotal = entries.reduce((sum, e) => sum + e.minRows, 0);\n\n // Min-row guarantee. If the terminal is too short to fit the\n // guarantees plus chrome, return the guarantees anyway and let the\n // App root's overflow clip be the final guard.\n if (bodyAvailable <= minTotal) {\n for (const e of entries) out[e.id] = e.minRows;\n return out;\n }\n\n for (const e of entries) out[e.id] = e.minRows;\n\n let remaining = bodyAvailable - minTotal;\n const totalWeight = entries.reduce((sum, e) => sum + clamp(e.dataCount, e.minRows, e.maxRows), 0);\n const weighted = entries.map((e, index) => {\n const weight = totalWeight === 0 ? 1 : clamp(e.dataCount, e.minRows, e.maxRows);\n const raw = totalWeight === 0 ? remaining / entries.length : (remaining * weight) / totalWeight;\n const add = Math.min(e.maxRows - e.minRows, Math.floor(raw));\n return { id: e.id, index, raw, add, capacity: e.maxRows - e.minRows };\n });\n\n for (const w of weighted) {\n out[w.id] += w.add;\n remaining -= w.add;\n }\n\n const remainders = weighted\n .map((w) => ({ ...w, remainder: w.raw - Math.floor(w.raw) }))\n .sort((a, b) => (b.remainder === a.remainder ? a.index - b.index : b.remainder - a.remainder));\n\n while (remaining > 0) {\n let changed = false;\n for (const r of remainders) {\n if (remaining <= 0) break;\n const entry = entries[r.index];\n if (entry === undefined) continue;\n if (out[r.id] >= entry.maxRows) continue;\n out[r.id] += 1;\n remaining -= 1;\n changed = true;\n }\n if (!changed) break;\n }\n\n return out;\n}\n\nexport function dataCountForCard(id: CardId, snapshot: WorkstreamSnapshot | null): number {\n if (snapshot === null) return 0;\n switch (id) {\n case 0:\n return snapshot.recentCommits.length;\n case 1:\n return snapshot.view.agents.length;\n case 2:\n return snapshot.tracks.length;\n case 3:\n return snapshot.ready.length;\n case 4:\n return snapshot.recent.length;\n case 5:\n return snapshot.workspaces.length;\n case 6:\n return snapshot.inProgress.length;\n case 7:\n return snapshot.blocked.length;\n case 8:\n return snapshot.recentClosed.length;\n case 9:\n return snapshot.doctor?.problemCount ?? 0;\n }\n}\n\nfunction compareSlot(a: CardId, b: CardId): number {\n const ka = a === 0 ? 10 : a;\n const kb = b === 0 ? 10 : b;\n return ka - kb;\n}\n\nfunction sortCards(ids: ReadonlyArray<CardId>): CardId[] {\n return [...ids].sort(compareSlot);\n}\n\nfunction normalizeVisible(ids: ReadonlyArray<CardId>): CardId[] {\n const seen = new Set<CardId>();\n const out: CardId[] = [];\n for (const id of ids) {\n if (seen.has(id)) continue;\n seen.add(id);\n out.push(id);\n }\n return out.sort((a, b) => a - b);\n}\n\nfunction emptyBudgetMap(): Record<CardId, number> {\n return { 0: 0, 1: 0, 2: 0, 3: 0, 4: 0, 5: 0, 6: 0, 7: 0, 8: 0, 9: 0 };\n}\n\nfunction tallestMinStackRows(ids: ReadonlyArray<CardId>): number {\n let tallest = 0;\n for (const assignment of layoutColumns(CARD_CULL_LAYOUT_COLS, ids)) {\n let total = 0;\n for (const id of assignment.cards) {\n const config = CARD_CONFIGS[id];\n total += Math.max(0, config.minRows) + Math.max(0, config.chrome);\n }\n tallest = Math.max(tallest, total);\n }\n return tallest;\n}\n\nfunction clamp(value: number, min: number, max: number): number {\n return Math.max(min, Math.min(max, value));\n}\n","// ListRow — the non-selected sibling of CursorRow. Centralises the\n// per-row JSX shape every popup and card was hand-rolling.\n//\n// Per feat_centralize_list_row_render (workstream `tui-impl`): the\n// user observed that \"the unaligned columns is another example of\n// copy-paste smell. we should do all this centrally.\" Two recent\n// bugs (bug_tui_log_card_columns_misaligned and\n// bug_tui_log_popup_columns_misaligned) recurred in 18 near-identical\n// row JSX blocks because every popup and card was repeating the same\n// width pin / gutter / wrap=\"truncate\" / per-cell colour mapping by\n// hand. One forgotten attribute → one popup wrapping rows to a\n// second line / drifting columns.\n//\n// ListRow owns four invariants for every list-style row in the TUI:\n// 1. width pin on the outer <Box> — bug_tui_log_popup_columns_misaligned\n// 2. canonical {\" \"} gutter (COL_GUTTER=2) — bug class for column drift\n// 3. wrap=\"truncate\" on the outer <Text> — bug_tui_log_card_columns_misaligned\n// 4. selected → CursorRow delegation — single source for cursor highlight\n//\n// CursorRow stays the highlight primitive; ListRow defers to it\n// when `selected` is true. The non-selected branch is now declarative:\n// callers pass in already-padded `cells` (output of renderRow) and an\n// optional `colors` array of per-cell styling specs. Per-cell color\n// styling stays POSSIBLE for the non-selected branch (the cards/popups\n// rely on `dimColor`, `bold`, `color=\"cyan\"` etc.); the SELECTED branch\n// trades all per-cell colour for a solid-inverse line — same trade-off\n// CursorRow already locked in (see cursor-row.tsx header).\n//\n// The component lives at src/cli/tui/list-row.tsx (sibling of\n// columns.ts and titled-box.tsx, NOT under popups/) because both\n// popups/* and cards/* consume it. Keeping it at the cluster root\n// matches the placement of the other shared primitives.\n\nimport { Box, Text } from \"ink\";\nimport type { ReactElement } from \"react\";\nimport { COL_GUTTER } from \"./columns.js\";\nimport { CursorRow } from \"./popups/cursor-row.js\";\n\n/** Per-cell styling spec. Mirrors the props ink's <Text> takes for\n * the colour palette every popup/card was hand-coding. `undefined`\n * cells (or a missing `colors` array) render as plain text. */\nexport interface CellColor {\n color?: string;\n bold?: boolean;\n dimColor?: boolean;\n}\n\nexport interface ListRowProps {\n /** Already-padded cells (output of renderRow). */\n cells: ReadonlyArray<string>;\n /** Total available content width (popup/card body width). */\n contentWidth: number;\n /** Per-cell styling. `colors[i]` applies to `cells[i]`; missing or\n * `undefined` entries render as plain text. */\n colors?: ReadonlyArray<CellColor | undefined>;\n /** When true, defer to CursorRow (solid-inverse highlight; no\n * per-cell colour). Routing the selected branch through ListRow\n * means popup authors never write a `selected ? <CursorRow> :\n * <Box>...` if-branch by hand. */\n selected?: boolean;\n}\n\nexport function ListRow({ cells, contentWidth, colors, selected }: ListRowProps): ReactElement {\n if (selected) return <CursorRow cells={cells} contentWidth={contentWidth} />;\n const gutter = \" \".repeat(COL_GUTTER);\n // Build the children list inline so React only sees one array of\n // <Text> nodes interleaved with literal gutter <Text>s. Same shape\n // ink renders today; the difference is that ListRow owns the\n // construction so a future row author can't drift the gutter or\n // forget wrap=\"truncate\".\n const children: React.ReactNode[] = [];\n for (let i = 0; i < cells.length; i++) {\n const cell = cells[i] ?? \"\";\n if (i > 0) children.push(<Text key={`g${i}`}>{gutter}</Text>);\n const c = colors?.[i];\n if (c === undefined) {\n children.push(<Text key={`c${i}`}>{cell}</Text>);\n } else {\n children.push(\n <Text key={`c${i}`} color={c.color} bold={c.bold} dimColor={c.dimColor}>\n {cell}\n </Text>,\n );\n }\n }\n return (\n <Box width={contentWidth}>\n <Text wrap=\"truncate\">{children}</Text>\n </Box>\n );\n}\n","// CursorRow — the highlight line shared by every list popup.\n//\n// Per bug_tui_popup_cursor_highlight_color_leak (workstream\n// `tui-impl`): the previous popup pattern wrapped per-cell <Text>\n// chunks (color=cyan / bold / dimColor) inside a single\n// <Text inverse={sel}>. ink emits an independent ANSI sequence per\n// nested <Text>, and inner SGR sequences (color/bold/dim) RESET the\n// outer `inverse` state — so the cursor row showed inverse video\n// only on bare-text/whitespace cells while every coloured cell broke\n// it. Plus the row <Box> was content-sized, so the highlight ended\n// at the last character of content rather than spanning the popup\n// width.\n//\n// Fix: when a row is selected, render it as PLAIN TEXT (no per-cell\n// palette), join the already-padded cells with the canonical 2-space\n// gutter (COL_GUTTER), padEnd to contentWidth, and wrap in a single\n// <Text inverse>. The cursor row trades its colour palette for a\n// solid full-width highlight — the lazygit / k9s / btop convention.\n//\n// `wrap=\"truncate\"` matches the cards/popups defensive-belt\n// invariant asserted by test/tui-card-render-width.test.ts: every\n// outer row-rendering <Text> truncates at the parent's width rather\n// than wrapping to a new line.\n\nimport { Box, Text } from \"ink\";\nimport type { ReactElement } from \"react\";\nimport { COL_GUTTER } from \"../columns.js\";\n\nexport interface CursorRowProps {\n /** Already-padded cells (output of renderRow). */\n cells: ReadonlyArray<string>;\n /** Total available content width (popup body width). */\n contentWidth: number;\n}\n\nexport function CursorRow({ cells, contentWidth }: CursorRowProps): ReactElement {\n const gutter = \" \".repeat(COL_GUTTER);\n const line = cells.join(gutter).padEnd(Math.max(contentWidth, 0));\n return (\n <Box width={contentWidth}>\n <Text inverse wrap=\"truncate\">\n {line}\n </Text>\n </Box>\n );\n}\n","// TitledBox — a rounded-border container whose section header sits\n// INSIDE the top border line (lazygit / htop / btop convention)\n// instead of consuming a row of body content.\n//\n// ╭─ ¹ Agents · 3 free ───────────────────────╮\n// │ <free> worker-1 free build_x — │\n// │ <busy> worker-2 busy review_x — │\n// ╰───────────────────────────────────────────╯\n//\n// IMPLEMENTATION\n//\n// ink v5 has no `borderTitle` prop, so we render the top border row\n// ourselves as a single <Text> (corner + dash + ' ' + [digit + ' '] +\n// title [+ ' · ' + subtitle] + ' ' + dash-fill + corner) and stack a\n// second <Box> below with `borderTop={false}` so ink's normal border\n// machinery draws the side+bottom edges and corners.\n//\n// To keep the manual top row aligned column-for-column with the body\n// Box's bottom border, both pieces share an explicit `width` derived\n// from `useStdout().columns`. v0 only stacks cards vertically (full\n// pane width); a future responsive-layout task can either (a) pass\n// an explicit `width` prop down or (b) wrap each cell in a width-\n// pinned Box. The pure helper `computeTopRowDashes` is exported so\n// either layout strategy can re-use the geometry.\n//\n// CARD-DIGIT PREFIX (feat_card_header_digit_prefix)\n//\n// Cards pass `cardId` so a Unicode superscript form of the toggle key\n// (¹ ² ³ ⁴ … ⁰) is rendered in yellow before the title. This mirrors\n// btop / htop, where the leading digit IS the toggle key. The help\n// overlay uses the same glyphs so the visual language matches.\n//\n// BOTTOM-BORDER INSET (feat_card_footer_inset)\n//\n// Cards optionally pass `bottomLabel` to render the truncation hint\n// (\"+11 more · Shift+3\") INSIDE the bottom border line, mirroring the\n// top-border title:\n//\n// ╭─ ³ Ready · 14 ─────────────────────────╮\n// │ build_x ROI 100 │\n// │ review_x ROI 60 │\n// │ ship_x ROI 50 │\n// ╰─ +11 more · Shift+3 ───────────────────╯\n//\n// Per the design correction in the task notes: NO superscript /\n// digit prefix on the bottom row — the label already says \"Shift+N\"\n// in plain text, and the superscript is a top-edge convention\n// (toggle-key affordance). When set, the inner Box's bottom border\n// is suppressed (`borderBottom={false}`) and a hand-rendered Text\n// row is stacked below it, exactly mirroring the top-row code path.\n// Geometry is shared via the pure helper `computeBorderRowDashes`.\n\nimport { Box, Text } from \"ink\";\nimport type { ReactElement, ReactNode } from \"react\";\nimport stringWidth from \"string-width\";\nimport { superscriptDigit } from \"../../glyphs.js\";\nimport { useTerminalSize } from \"./use-terminal-size.js\";\n\nconst ROUND = {\n topLeft: \"╭\",\n topRight: \"╮\",\n bottomLeft: \"╰\",\n bottomRight: \"╯\",\n horizontal: \"─\",\n} as const;\n\nexport interface TitledBoxProps {\n /** Bold/coloured headline text (e.g. \"Agents\"). */\n title: string;\n /** Optional dim subtitle rendered after \" · \" (e.g. \"3 free\"). */\n subtitle?: string;\n /** Optional 0..9 toggle key. When set, the matching superscript\n * glyph is rendered in yellow before the title (btop convention). */\n cardId?: number;\n /** Border colour. Cards default to \"gray\"; popups/help to \"cyan\". */\n borderColor?: string;\n /** Title colour (the bold part). Defaults to \"cyan\". */\n titleColor?: string;\n /** Optional inset label rendered inside the BOTTOM border line\n * (feat_card_footer_inset). Cards pass it only when the body is\n * truncated; otherwise omit and the bottom border renders as\n * plain dashes. NO superscript prefix here per the design\n * correction — the bottom-edge convention is a literal keystroke\n * hint (\"Shift+3\"), not a toggle affordance. */\n bottomLabel?: string;\n /** Optional fixed outer height in rows. Cards pass\n * `chrome + rowBudget` so dashboard hit-test rectangles and Ink\n * render geometry stay identical even when the body has fewer rows\n * than its allocated budget (empty-state cards are the common\n * case). Popups omit it and flex vertically instead. */\n height?: number;\n /** Optional Yoga flex-grow factor. Applied to BOTH the outer\n * column container AND the inner border-body Box so popup\n * Shells (which previously hand-rolled their own rounded box\n * with `flexGrow={1}` per bug_tui_popups_fill_pane) can flex\n * vertically inside an App-level height-pinned region without\n * collapsing to content size. Cards omit it (default behaviour\n * unchanged: outer Box sizes to content). */\n flexGrow?: number;\n /** Outer width in terminal columns. Defaults to the full stdout\n * width; responsive dashboard columns pass their per-column width. */\n width?: number;\n children?: ReactNode;\n}\n\n/** Default for the outer Box's flexShrink. Yoga's default is 0\n * (unlike CSS's 1), so when the dashboard's nine cards' summed\n * natural height exceeds the height-pinned root <Box height={rows}>,\n * Yoga keeps every child at its natural size and the overflow is\n * emitted past the terminal's bottom — which (because ink writes\n * the whole frame in one go and the cursor starts at row 1) makes\n * the terminal scroll and silently drops the TOPMOST border row.\n * See bug_tui_dashboard_top_card_scrolls_off for the long-form\n * diagnosis. Setting flexShrink=1 lets Yoga distribute the deficit\n * proportionally across cards, so the bottom card's body clips\n * instead of the topmost card's chrome scrolling off-screen. */\nconst TITLED_BOX_FLEX_SHRINK = 1;\n\n/**\n * Generic geometry helper for ANY border row that insets a single\n * label between the corner+dash prefix and the dash-fill+corner\n * suffix. Used by both the top-border (where the \"label\" is the\n * effective width of title + subtitle + cardId composed) and the\n * bottom-border (where the label is the raw bottomLabel string).\n *\n * Anatomy: `╭─ <label> <dashes>╮` (top)\n * `╰─ <label> <dashes>╯` (bottom)\n *\n * Per-piece column cost (5 fixed + label + dashes):\n * corner 1\n * ─ 1\n * ' ' 1\n * label L\n * ' ' 1\n * dashes D\n * corner 1\n *\n * Floors at 1 — if the terminal is too narrow, we let the line\n * overflow rather than producing an empty/negative-width fill.\n */\nexport function computeBorderRowDashes(cols: number, label: string): number {\n return Math.max(1, cols - 5 - stringWidth(label));\n}\n\n/**\n * Top-border specialization: composes title + ' · ' + subtitle and\n * an optional leading digit prefix into the effective label width,\n * then delegates to `computeBorderRowDashes`. Pure function so a\n * unit test can pin the geometry without spinning up ink.\n *\n * Per-piece column cost (relative to the generic 5-fixed base):\n * digit 1 (when cardId set; superscript glyphs are 1 col)\n * ' ' (sep) 1 (when cardId set)\n * title T\n * ' · ' 3 (when subtitle set)\n * subtitle S\n */\nexport function computeTopRowDashes(\n cols: number,\n title: string,\n subtitle?: string,\n cardId?: number,\n): number {\n const titleW = stringWidth(title);\n const subW = subtitle === undefined || subtitle.length === 0 ? 0 : stringWidth(subtitle);\n const subCost = subW === 0 ? 0 : 3 + subW; // ' · ' + S\n const digitCost = cardId === undefined ? 0 : 2; // digit + ' '\n return Math.max(1, cols - 5 - titleW - subCost - digitCost);\n}\n\nexport function TitledBox({\n title,\n subtitle,\n cardId,\n borderColor = \"gray\",\n titleColor = \"cyan\",\n bottomLabel,\n height,\n flexGrow,\n width,\n children,\n}: TitledBoxProps): ReactElement {\n const { cols: termCols } = useTerminalSize();\n const cols = width ?? termCols;\n const dashes = computeTopRowDashes(cols, title, subtitle, cardId);\n const fill = ROUND.horizontal.repeat(dashes);\n const hasSubtitle = subtitle !== undefined && subtitle.length > 0;\n const digitGlyph = cardId === undefined ? null : superscriptDigit(cardId);\n const hasBottomLabel = bottomLabel !== undefined && bottomLabel.length > 0;\n const bottomDashes = hasBottomLabel ? computeBorderRowDashes(cols, bottomLabel) : 0;\n const bottomFill = ROUND.horizontal.repeat(bottomDashes);\n\n return (\n <Box\n flexDirection=\"column\"\n width={cols}\n height={height}\n flexGrow={flexGrow}\n flexShrink={TITLED_BOX_FLEX_SHRINK}\n overflow=\"hidden\"\n >\n <Text color={borderColor}>\n {ROUND.topLeft}\n {ROUND.horizontal}{\" \"}\n {digitGlyph !== null ? (\n <>\n <Text bold color=\"yellow\">\n {digitGlyph}\n </Text>{\" \"}\n </>\n ) : null}\n <Text bold color={titleColor}>\n {title}\n </Text>\n {hasSubtitle ? (\n <>\n <Text color={borderColor}> · </Text>\n <Text dimColor>{subtitle}</Text>\n </>\n ) : null}{\" \"}\n {fill}\n {ROUND.topRight}\n </Text>\n <Box\n borderStyle=\"round\"\n borderColor={borderColor}\n borderTop={false}\n borderBottom={!hasBottomLabel}\n paddingX={1}\n flexDirection=\"column\"\n flexGrow={flexGrow}\n flexShrink={0}\n >\n {children}\n </Box>\n {hasBottomLabel ? (\n <Text color={borderColor}>\n {ROUND.bottomLeft}\n {ROUND.horizontal} <Text dimColor>{bottomLabel}</Text> {bottomFill}\n {ROUND.bottomRight}\n </Text>\n ) : null}\n </Box>\n );\n}\n","// Shared reactive terminal-size hook for all TUI surfaces.\n//\n// ink's `useStdout()` returns the raw stdout stream, but reading\n// `.columns` / `.rows` during render only captures the value at\n// that moment — ink does NOT re-render when the terminal resizes.\n// This hook subscribes to the `resize` event on stdout and bumps\n// local state so every consumer re-renders with the new dimensions.\n//\n// Usage:\n//\n// const { cols, rows } = useTerminalSize();\n//\n// Replaces the boilerplate pattern:\n//\n// const { stdout } = useStdout();\n// const cols = stdout?.columns ?? 80;\n//\n// Per ROADMAP pledge: ink/react import confined to src/cli/tui/*.\n\nimport { useStdout } from \"ink\";\nimport { useEffect, useState } from \"react\";\n\n// One \"resize\" listener per stream, fanned out to every mounted hook.\n// A listener per hook instance tripped Node's MaxListenersExceededWarning\n// (>10) once a popup + drill + cards were mounted at once.\nconst subscribers = new WeakMap<NodeJS.WriteStream, Set<() => void>>();\n\nfunction subscribeResize(stdout: NodeJS.WriteStream, fn: () => void): () => void {\n let set = subscribers.get(stdout);\n if (set === undefined) {\n const fresh = new Set<() => void>();\n set = fresh;\n subscribers.set(stdout, fresh);\n stdout.on(\"resize\", () => {\n for (const sub of [...fresh]) sub();\n });\n }\n set.add(fn);\n return () => {\n set.delete(fn);\n };\n}\n\nexport interface TerminalSize {\n cols: number;\n rows: number;\n}\n\n/**\n * Returns the current terminal dimensions and re-renders whenever\n * the terminal is resized. Falls back to 80×24 when stdout is not\n * a TTY (e.g. test capture streams without columns/rows).\n */\nexport function useTerminalSize(): TerminalSize {\n const { stdout } = useStdout();\n const [size, setSize] = useState<TerminalSize>({\n cols: stdout?.columns ?? 80,\n rows: stdout?.rows ?? 24,\n });\n\n useEffect(() => {\n if (!stdout) return;\n const onResize = () => {\n setSize((prev) => {\n const cols = stdout.columns ?? 80;\n const rows = stdout.rows ?? 24;\n // Bail when nothing changed so we don't queue a no-op re-render.\n // This matters on mount: the defensive sync below would\n // otherwise force a second render every time the hook mounts\n // (the initial useState already read the same dimensions),\n // doubling work in production and doubling captured frames in\n // ink render tests. Returning the SAME object reference makes\n // React skip the update. bug_use_terminal_size_double_render.\n if (prev.cols === cols && prev.rows === rows) return prev;\n return { cols, rows };\n });\n };\n const unsubscribe = subscribeResize(stdout, onResize);\n // Sync in case the size changed between initial render and effect\n // registration (unlikely but defensive). Now a no-op when the size\n // is unchanged — see the reference-equality bail above.\n onResize();\n return unsubscribe;\n }, [stdout]);\n\n return size;\n}\n","// CardPlaceholder — shared scaffolding for card loading + empty\n// (and other one-line) body branches.\n//\n// Before this helper, every card under src/cli/tui/cards/*.tsx\n// repeated a near-identical 10-line block for its loading branch\n// AND for its empty branch:\n//\n// <TitledBox\n// height={cardRenderHeight(cardConfig, rowBudget)}\n// width={cols}\n// title=\"<Title>\"\n// cardId={N}\n// >\n// <PaddedRows rows={rowBudget ?? cardConfig.minRows}>\n// <Text dimColor>loading…</Text> {/* or \"(none ...)\" */}\n// </PaddedRows>\n// </TitledBox>\n//\n// That's 20+ blocks across 10 files, all carrying the same chrome\n// pattern (height = chrome + rowBudget; PaddedRows = rowBudget ??\n// minRows). Adding a new card-level chrome attribute (e.g. a per-\n// card border colour, a new bottom-label rule for empty-state)\n// required editing every block. Now there's one knob.\n//\n// USAGE\n// return CardPlaceholder({\n// title: \"Agents\", cardId: 1,\n// rowBudget, cols,\n// config: cardConfig,\n// subtitle, // optional (omit for loading; threaded\n// // through for empty/healthy paths\n// // that already compute one)\n// text: \"loading…\", // dim text body (most common case)\n// });\n//\n// For richer bodies (e.g. an inline code hint that interpolates a\n// workstream name, or the doctor's coloured healthy-check line), pass\n// `children` (a ReactNode) instead of `text`. The helper\n// only injects the dimColor wrapper when `text` is used; `children`\n// is rendered verbatim so the caller controls every Text node.\n//\n// CALLED AS A FUNCTION, NOT AS JSX\n// Card render functions invoke `CardPlaceholder({...})` directly\n// instead of `<CardPlaceholder .../>`. This matches how test\n// helpers (test/_card-render.ts) treat the cards themselves: they\n// call `AgentsCard({snapshot})` and walk the returned JSX tree.\n// If we used JSX, the test walker would see a `<CardPlaceholder>`\n// element with the helper's prop names (text, config, rowBudget),\n// none of which it knows how to render — the title/height/rows\n// it greps for would be hidden one synthetic-component level\n// deeper. Calling the helper as a function eagerly evaluates it\n// to the underlying `<TitledBox>` tree, keeping the existing\n// walker contract intact.\n//\n// PURE WRAPPER, ZERO BEHAVIOUR DRIFT\n// The rendered output is byte-identical to the hand-rolled\n// blocks: same TitledBox prop set, same PaddedRows row count,\n// same single-Text body. Tests that grep for title + body text\n// via renderCardToText are unchanged.\n\nimport { Text } from \"ink\";\nimport type { ReactElement, ReactNode } from \"react\";\nimport { type CardRowConfig, cardRenderHeight } from \"../layout.js\";\nimport { PaddedRows } from \"../padded-rows.js\";\nimport { TitledBox } from \"../titled-box.js\";\n\nexport interface CardPlaceholderProps {\n /** Card title (e.g. \"Agents\"). Bold/coloured headline. */\n title: string;\n /** 0..9 toggle key — yellow superscript glyph before the title. */\n cardId: number;\n /** Card's static row config (CARD_CONFIGS[id]); used for both the\n * fixed outer height (chrome + rowBudget) and the PaddedRows\n * fallback when the dashboard hasn't allocated a row budget yet\n * (i.e. minRows). */\n config: CardRowConfig;\n /** Dashboard-allocated body row budget. Undefined → use minRows. */\n rowBudget?: number;\n /** Outer width in terminal columns; threaded through to TitledBox. */\n cols?: number;\n /** Optional dim subtitle rendered after \" · \". */\n subtitle?: string;\n /** Body text, rendered as a single <Text dimColor>{text}</Text>.\n * Mutually exclusive with `children`; if both are passed, `children`\n * wins (the richer-JSX path). */\n text?: string;\n /** Body ReactNode for richer renders (inline code hint, multi-Text\n * doctor healthy line, …). Rendered verbatim — the caller controls\n * every wrapping Text node. */\n children?: ReactNode;\n}\n\nexport function CardPlaceholder({\n title,\n cardId,\n config,\n rowBudget,\n cols,\n subtitle,\n text,\n children,\n}: CardPlaceholderProps): ReactElement {\n return (\n <TitledBox\n height={cardRenderHeight(config, rowBudget)}\n width={cols}\n title={title}\n subtitle={subtitle}\n cardId={cardId}\n >\n <PaddedRows rows={rowBudget ?? config.minRows}>\n {children ?? <Text dimColor>{text}</Text>}\n </PaddedRows>\n </TitledBox>\n );\n}\n","import { Text } from \"ink\";\nimport type { ReactElement, ReactNode } from \"react\";\n\nexport interface PaddedRowsProps {\n rows?: number;\n children: ReactNode;\n}\n\n/** Ensure one-line empty/loading card bodies still occupy their row budget. */\nexport function PaddedRows({ rows, children }: PaddedRowsProps): ReactElement {\n const targetRows = Math.max(0, Math.floor(rows ?? 0));\n const blanks = Math.max(0, targetRows - 1);\n return (\n <>\n {children}\n {Array.from({ length: blanks }, (_, i) => `blank-${i}`).map((key) => (\n <Text key={key}> </Text>\n ))}\n </>\n );\n}\n","// Pure formatters shared across the TUI cards/popups cluster.\n//\n// Hoisted out of cards/* and popups/* in a single bundled pass per:\n// - review_dedup_age_ms (4 consumers)\n// - review_dedup_color_for_bucket (3 byte-identical copies)\n// - review_dedup_format_roi (3 callsites + 2 inline dups)\n// - review_unify_format_when_since (formatSinceClaim / formatWhen\n// → relTime / relTimeAgo)\n//\n// Every helper here is pure (input → output, no I/O, no ink/react),\n// covered directly by test/tui-format-helpers.test.ts. Card / popup\n// modules import from here instead of carrying their own copies.\n//\n// New helpers belong here only when ≥2 cards/popups need them; one-\n// off card-local helpers stay co-located with their card. Keep this\n// module ink/react-free so it can be imported from anywhere.\n\nimport type { RoiBucket } from \"../../state.js\";\nimport type { TaskRow } from \"../../tasks.js\";\nimport { relTime, relTimeAgo } from \"../format.js\";\n\n/** Milliseconds since the task last had a lifecycle flip. Returns\n * null when updatedAt is unparseable (defensive — every row from\n * SQLite will be a valid ISO-8601 string). The basis is `now` so\n * tests can pin time without leaning on the wall clock.\n *\n * Used by: cards/inprogress, cards/recent, popups/inprogress,\n * popups/recent. */\nexport function ageMs(t: TaskRow, now: number): number | null {\n const ts = Date.parse(t.updatedAt);\n if (Number.isNaN(ts)) return null;\n return Math.max(0, now - ts);\n}\n\n/** Ink colour for an ROI bucket: high|infinite → green, mid →\n * yellow, low → undefined (no colour, default text colour). Pure;\n * consumers pass the result straight to a `<Text color=...>`.\n *\n * Used by: cards/ready, cards/blocked, popups/blocked. */\nexport function colorForBucket(b: RoiBucket): string | undefined {\n switch (b) {\n case \"high\":\n case \"infinite\":\n return \"green\";\n case \"mid\":\n return \"yellow\";\n case \"low\":\n return undefined;\n }\n}\n\n/** Render the ROI cell as a short integer, or \"∞\" when effortDays is\n * zero / negative (matches the convention used by every blocked /\n * ready / in-progress / recent card and popup). Pure.\n *\n * Used by: cards/blocked, cards/ready, popups/blocked,\n * popups/inprogress, popups/recent. */\nexport function formatRoi(impact: number, effortDays: number): string {\n if (effortDays <= 0) return \"∞\";\n const r = Math.round(impact / effortDays);\n return Number.isFinite(r) ? String(r) : \"∞\";\n}\n\n/** Render an in-flight age in milliseconds as a short relative-time\n * token (no suffix):\n * < 60s → \"Ns\"\n * < 60m → \"Nm\"\n * < 24h → \"Nh\"\n * < 7d → \"Nd\"\n * else → \"Nw\"\n * null / undefined → \"—\". Thin wrapper over relTime() so the TUI\n * cluster shares the canonical formatter. The \"—\" sentinel is the\n * only TUI-specific bit (CLI tables render \"—\" themselves at the\n * call site).\n *\n * Used by: cards/inprogress, popups/inprogress. */\nexport function formatSinceClaim(ms: number | null | undefined): string {\n if (ms === null || ms === undefined) return \"—\";\n return relTime(ms);\n}\n\n/** Render an age in milliseconds (the Recent views pass updated_at, a\n * proxy for close time) as a short relative-time\n * token with the trailing \" ago\" suffix:\n * < 60s → \"Ns ago\"\n * < 60m → \"Nm ago\"\n * < 24h → \"Nh ago\"\n * < 7d → \"Nd ago\"\n * else → \"Nw ago\"\n * null / undefined → \"—\". The \" ago\" suffix is the differentiator\n * vs formatSinceClaim (in-flight, present tense); here every row\n * is past tense.\n *\n * Used by: cards/recent, popups/recent. */\nexport function formatWhen(ms: number | null | undefined): string {\n if (ms === null || ms === undefined) return \"—\";\n return relTimeAgo(ms);\n}\n","// Blocked card — every OPEN task with at least one still-gating\n// blocker (i.e. a non-CLOSED prerequisite). Fills the diagnostic gap\n// described in feat_card_7_blocked (workstream `tui-impl`):\n//\n// \"What's blocking the umbrella?\" is the most common diagnostic\n// question during multi-wave orchestration. Today the operator must\n// walk the dependency tree manually via `mu task tree <id>`. One\n// glanceable card surfaces the blocked-tasks subset directly.\n//\n// Card 7 promotes a slot reserved by design_global_keymap. Mirrors\n// the shape of Card 5 — Workspaces (264585f9) and Card 6 — In-progress\n// (760fc6c) so the operator reads it the same way: TitledBox header,\n// column-aligned rows, glanceable subtitle.\n//\n// CARD LAYOUT\n// glyph id STATUS #blocks ROI title\n// <blocked> review_x OPEN 2 75 Review X\n// <blocked> cherry_x OPEN 1 60 Cherry-pick X\n//\n// The glyph is GLYPH.blocked from src/glyphs.ts (a chain link) and\n// reads as \"this is blocked / chained to something\". Coloured dim — the operator's eye is meant to land\n// on the #blockers / top-blocker subtitle, not the row glyph.\n// STATUS column is a stable \"OPEN\" string (the BLOCKED view filters\n// to OPEN by definition — see src/db.ts BLOCKED_VIEW_SQL); kept in\n// the row for visual consistency with the other task lists.\n//\n// CLIPPING POLICY (per feat_column_aligned_lists)\n// id, STATUS, #blocks, ROI → PROTECT (yankable / numeric / identifier)\n// title → CLIP (free-form prose)\n//\n// SUBTITLE\n// empty → omitted (no blocked tasks → empty-state body)\n// populated → \"<N>\" when no top blocker\n// \"<N> · top blocker: <id>\" otherwise\n//\n// \"Top blocker\" = the still-gating blocker (status ≠ CLOSED) that\n// appears most often across the visible blocked rows. Ties broken by\n// the blocker's local id (alphabetic). This surfaces the single\n// task that, if closed, would unblock the most downstream work — the\n// most actionable hint at a glance. Computed over the visible (≤\n// ROW_LIMIT) rows, not the full blocked list, so the displayed top\n// blocker is one the operator can correlate against the rendered\n// rows.\n//\n// DATA\n// - snapshot.blocked is the OPEN-with-unsatisfied-blockers slice\n// from the BLOCKED SQL view. Used directly.\n// - per-row blocker counts come from getTaskEdgesWithStatus(db, id,\n// ws), filtered to non-CLOSED. ROW_LIMIT (8) caps the per-tick\n// SQLite reads at 8 prepared-statement queries — orders of\n// magnitude cheaper than the per-row `git status --porcelain`\n// shellouts the Workspaces card already does. No SDK extension\n// per the task brief.\n//\n// POPUP / FUTURE OBLIGATIONS (when slot-7 popup ships)\n// Out of scope NOW. When the popup is added under\n// feat_more_cards_umbrella, it MUST consume:\n// (a) feat_popup_search_filter — '/' filter via usePopupFilter\n// (b) feat_track_drill_chains_to_task_drill — Enter chains rows\n// into TaskDetailDrill (rows ARE tasks)\n// Until then, Shift+7 (`&`) stays a reserved noop in keys.ts.\n\nimport type { ReactElement } from \"react\";\nimport type { Db } from \"../../../db.js\";\nimport { GLYPH as SHARED_GLYPH } from \"../../../glyphs.js\";\nimport { roiBucket, type WorkstreamSnapshot } from \"../../../state.js\";\nimport { formatPair } from \"../../../tasks/status.js\";\nimport { getTaskEdgesWithStatus, type TaskEdgeWithStatus } from \"../../../tasks.js\";\nimport { inkColorForPair } from \"../../format.js\";\nimport {\n type ColumnSpec,\n contentWidthFromCols,\n layoutColumns,\n renderRow,\n termColsForLayout,\n} from \"../columns.js\";\nimport { colorForBucket, formatRoi } from \"../format-helpers.js\";\nimport { CARD_CONFIGS, cardRenderHeight } from \"../layout.js\";\nimport { ListRow } from \"../list-row.js\";\nimport { TitledBox } from \"../titled-box.js\";\nimport { CardPlaceholder } from \"./_placeholder.js\";\n\nexport interface BlockedCardProps {\n snapshot: WorkstreamSnapshot | null;\n db: Db;\n workstream: string;\n rowBudget?: number;\n cols?: number;\n}\n\nexport const cardConfig = CARD_CONFIGS[7];\n\n/** Glyph for every blocked row. Always the chain-link. */\nexport const GLYPH = SHARED_GLYPH.blocked;\n\nconst COLUMN_SPECS: ReadonlyArray<ColumnSpec> = [\n { kind: \"protect\" }, // glyph\n { kind: \"protect\" }, // task id\n { kind: \"protect\" }, // status (always OPEN; constant for now)\n { kind: \"protect\", align: \"right\" }, // #blockers\n { kind: \"protect\", align: \"right\" }, // ROI label (e.g. \"75\")\n { kind: \"clip\", min: 1 }, // title\n];\n\nexport function BlockedCard({\n snapshot,\n db,\n workstream,\n rowBudget,\n cols,\n}: BlockedCardProps): ReactElement {\n const contentWidth = contentWidthFromCols(cols ?? termColsForLayout());\n if (snapshot === null) {\n return CardPlaceholder({\n title: \"Blocked\",\n cardId: 7,\n config: cardConfig,\n rowBudget,\n cols,\n text: \"loading…\",\n });\n }\n\n const { blocked } = snapshot;\n\n if (blocked.length === 0) {\n return CardPlaceholder({\n title: \"Blocked\",\n cardId: 7,\n config: cardConfig,\n rowBudget,\n cols,\n text: \"(none blocked)\",\n });\n }\n\n const shown = blocked.slice(0, rowBudget ?? cardConfig.maxRows);\n const more = blocked.length - shown.length;\n const bottomLabel = more > 0 ? `+${more} more · Shift+7` : undefined;\n // One getTaskEdgesWithStatus call per visible row. Cap at 8 →\n // synchronous better-sqlite3 reads on a join, vastly cheaper than\n // the per-row shellouts the Workspaces card does.\n const blockerLists = shown.map((t) =>\n stillGating(getTaskEdgesWithStatus(db, t.name, workstream).blockers),\n );\n const topBlocker = pickTopBlocker(blockerLists);\n const topEdge = blockerLists.flat().find((b) => b.name === topBlocker);\n const subtitle = formatSubtitle(blocked.length, topEdge ? blockerLabel(topEdge) : topBlocker);\n\n const meta = shown.map((t) => {\n const bucket = roiBucket(t.impact, t.effortDays);\n const roiText = formatRoi(t.impact, t.effortDays);\n return { bucket, roiText };\n });\n const rows = shown.map((t, i) => [\n GLYPH,\n t.name,\n formatPair(t),\n String(blockerLists[i]?.length ?? 0),\n meta[i]?.roiText ?? \"\",\n t.title,\n ]);\n const widths = layoutColumns(rows, COLUMN_SPECS, contentWidth);\n\n return (\n <TitledBox\n height={cardRenderHeight(cardConfig, rowBudget)}\n width={cols}\n title=\"Blocked\"\n subtitle={subtitle}\n cardId={7}\n bottomLabel={bottomLabel}\n >\n {shown.map((t, i) => {\n const row = rows[i];\n const m = meta[i];\n if (row === undefined || m === undefined) return null;\n const padded = renderRow(row, widths, COLUMN_SPECS);\n const colors = [\n { dimColor: true }, // glyph\n { bold: true }, // id\n { color: inkColorForPair(t) }, // status\n { color: \"yellow\" }, // blocks\n { color: colorForBucket(m.bucket) }, // roi\n { dimColor: true }, // title\n ];\n return <ListRow key={t.name} cells={padded} contentWidth={contentWidth} colors={colors} />;\n })}\n </TitledBox>\n );\n}\n\n// ─── pure helpers (exported for unit tests) ────────────────────────\n\n/** Filter a list of blockers to the still-gating ones. A blocker is\n * still-gating iff its status is not CLOSED (only CLOSED satisfies a\n * blocked-by edge per the BLOCKED view in src/db.ts). Returns a new\n * array; does not mutate. */\nexport function stillGating(blockers: ReadonlyArray<TaskEdgeWithStatus>): TaskEdgeWithStatus[] {\n return blockers.filter((b) => b.status !== \"CLOSED\");\n}\n\n/** A blocker's display name: \" (parked)\" appended when it is\n * OPEN/parked, since a parked blocker will not close on its own. */\nexport function blockerLabel(b: TaskEdgeWithStatus): string {\n return b.status === \"OPEN\" && b.substate === \"parked\" ? `${b.name} (parked)` : b.name;\n}\n\n/** Pick the still-gating blocker that appears most often across the\n * given per-row blocker lists. Ties broken by alphabetic blocker\n * local id. Returns null when no blockers are present (all rows\n * somehow had every blocker satisfied — defensive: shouldn't happen\n * given the BLOCKED view, but the empty-input branch keeps the\n * function total).\n *\n * Surfacing the most-shared blocker is the most actionable hint —\n * closing it unblocks the most downstream rows in one move. */\nexport function pickTopBlocker(\n blockerLists: ReadonlyArray<ReadonlyArray<TaskEdgeWithStatus>>,\n): string | null {\n const counts = new Map<string, number>();\n for (const list of blockerLists) {\n for (const b of list) {\n counts.set(b.name, (counts.get(b.name) ?? 0) + 1);\n }\n }\n if (counts.size === 0) return null;\n let best: string | null = null;\n let bestCount = -1;\n // Iterate in alphabetic order so ties resolve deterministically\n // (Map iteration is insertion order; we explicitly sort the keys).\n for (const name of [...counts.keys()].sort()) {\n const c = counts.get(name) ?? 0;\n if (c > bestCount) {\n best = name;\n bestCount = c;\n }\n }\n return best;\n}\n\n/** Build the subtitle: \"<total>\" or \"<total> · top blocker: <id>\".\n * topBlocker null → omit the leg (defensive; shouldn't happen for\n * the rendered path — populated blocked => at least one blocker\n * exists by definition of the BLOCKED view — but the formatter is\n * defensive against an empty blocker-list slice). */\nexport function formatSubtitle(total: number, topBlocker: string | null): string {\n const parts: string[] = [String(total)];\n if (topBlocker !== null) parts.push(`top blocker: ${topBlocker}`);\n return parts.join(\" · \");\n}\n","// Commits card — lazygit-style recent project commit log.\n//\n// Slot choice: Card 0 is now Commits. Recent is restored to Card 8;\n// the DAG remains a keybind-only popup on `g` instead of consuming\n// numeric slot 0.\n//\n// Data comes from snapshot.recentCommits, populated by\n// loadWorkstreamSnapshot(..., { withRecentCommits }) against\n// process.cwd() (the project root where the TUI was launched), NOT any\n// per-agent worker workspace.\n\nimport type { ReactElement } from \"react\";\nimport type { WorkstreamSnapshot } from \"../../../state.js\";\nimport {\n type ColumnSpec,\n contentWidthFromCols,\n layoutColumns,\n renderRow,\n termColsForLayout,\n} from \"../columns.js\";\nimport { CARD_CONFIGS, cardRenderHeight } from \"../layout.js\";\nimport { ListRow } from \"../list-row.js\";\nimport { TitledBox } from \"../titled-box.js\";\nimport { CardPlaceholder } from \"./_placeholder.js\";\n\nexport interface CommitsCardProps {\n snapshot: WorkstreamSnapshot | null;\n rowBudget?: number;\n cols?: number;\n}\n\nexport const cardConfig = CARD_CONFIGS[0];\n\nconst COLUMN_SPECS: ReadonlyArray<ColumnSpec> = [\n { kind: \"protect\" }, // sha short\n { kind: \"protect\", align: \"right\" }, // relative time\n { kind: \"clip\", min: 1 }, // subject\n];\n\nexport function CommitsCard({ snapshot, rowBudget, cols }: CommitsCardProps): ReactElement {\n const contentWidth = contentWidthFromCols(cols ?? termColsForLayout());\n if (snapshot === null) {\n return CardPlaceholder({\n title: \"Commits\",\n cardId: 0,\n config: cardConfig,\n rowBudget,\n cols,\n text: \"loading…\",\n });\n }\n\n const { recentCommits } = snapshot;\n const backendLabel = formatBackend(snapshot.commitsBackend ?? null);\n if (recentCommits.length === 0) {\n return CardPlaceholder({\n title: \"Commits\",\n cardId: 0,\n config: cardConfig,\n rowBudget,\n cols,\n subtitle: backendLabel,\n text: \"no commits\",\n });\n }\n\n const shown = recentCommits.slice(0, rowBudget ?? cardConfig.maxRows);\n const more = recentCommits.length - shown.length;\n const bottomLabel = more > 0 ? `+${more} more · Shift+0` : undefined;\n const subtitle = formatSubtitle(\n recentCommits.length,\n snapshot.commitsBackend ?? null,\n recentCommits[0]?.relTime,\n );\n const rows = shown.map((c) => [shortSha(c.sha), c.relTime, c.subject]);\n const widths = layoutColumns(rows, COLUMN_SPECS, contentWidth);\n\n return (\n <TitledBox\n height={cardRenderHeight(cardConfig, rowBudget)}\n width={cols}\n title=\"Commits\"\n subtitle={subtitle}\n cardId={0}\n bottomLabel={bottomLabel}\n >\n {shown.map((c, i) => {\n const row = rows[i];\n if (row === undefined) return null;\n const padded = renderRow(row, widths, COLUMN_SPECS);\n const colors = [\n { color: \"yellow\" }, // sha\n { dimColor: true }, // relTime\n undefined, // subject\n ];\n return <ListRow key={c.sha} cells={padded} contentWidth={contentWidth} colors={colors} />;\n })}\n </TitledBox>\n );\n}\n\nexport function shortSha(sha: string): string {\n return sha.slice(0, 7);\n}\n\nexport function formatBackend(backend: WorkstreamSnapshot[\"commitsBackend\"]): string {\n return backend ?? \"(no vcs)\";\n}\n\nexport function formatSubtitle(\n total: number,\n backend: WorkstreamSnapshot[\"commitsBackend\"],\n newestRelTime: string | undefined,\n): string {\n const parts = [String(total), formatBackend(backend)];\n if (newestRelTime !== undefined && newestRelTime.length > 0) parts.push(newestRelTime);\n return parts.join(\" · \");\n}\n","// Doctor card — health-check summary surfaced on the dashboard so\n// the operator notices a broken state without remembering to run\n// `mu doctor`. Aimed at the \"btop / k9s health badge\" UX: when\n// every check is OK, the card is a quiet one-liner; when something\n// is warn or fail, the failing rows surface the moment they appear.\n//\n// Per feat_card_9_doctor (workstream `tui-impl`), promoted from the\n// LAST reserved non-zero slot in design_global_keymap. Slot 0 is now\n// Commits; DAG is keybind-only.\n//\n// CARD LAYOUT\n// glyph check STATUS detail\n// <warn> agents warn 2 ghost panes; run `mu agent reconcile`\n// <fail> workspaces fail 1 orphan dir blocking spawns\n//\n// Glyph + colour priority: GLYPH.fail (red), GLYPH.warn (yellow), then\n// GLYPH.ok (green). The card BODY filters to non-OK rows; when nothing\n// is wrong, the card renders one quiet all-healthy row so the operator's\n// eye learns to read the presence of rows as \"something needs attention.\"\n//\n// CLIPPING POLICY (per feat_column_aligned_lists)\n// glyph, check, STATUS → PROTECT (identifier; yankable check name)\n// detail → CLIP (free-form prose; can truncate)\n//\n// SUBTITLE\n// problemCount === 0 → \"all healthy\"\n// problemCount > 0 → \"<problemCount>\"\n//\n// DATA\n// - snapshot.doctor is populated by loadWorkstreamSnapshot when\n// called with `withDoctor: true`. The TUI's poll-loop hook\n// (src/cli/tui/state.ts) opts in. Static `mu state` and `mu\n// doctor` itself do not — `mu doctor`'s textual card is the\n// authoritative full diagnostic; this card is the dashboard\n// SIGNAL only. See src/doctor-summary.ts for the SDK seam.\n//\n// POPUP\n// Shift+9 (`(`) opens popups/doctor.tsx: every check (OK rows\n// included), `/` filter, and an Enter drill with the remediation\n// text for the focused check.\n\nimport { Text } from \"ink\";\nimport type { ReactElement } from \"react\";\nimport type { DoctorCheck } from \"../../../doctor-summary.js\";\nimport { GLYPH } from \"../../../glyphs.js\";\nimport type { WorkstreamSnapshot } from \"../../../state.js\";\nimport {\n type ColumnSpec,\n contentWidthFromCols,\n layoutColumns,\n renderRow,\n termColsForLayout,\n} from \"../columns.js\";\nimport { CARD_CONFIGS, cardRenderHeight } from \"../layout.js\";\nimport { ListRow } from \"../list-row.js\";\nimport { TitledBox } from \"../titled-box.js\";\nimport { CardPlaceholder } from \"./_placeholder.js\";\n\nexport interface DoctorCardProps {\n snapshot: WorkstreamSnapshot | null;\n rowBudget?: number;\n cols?: number;\n}\n\nexport const cardConfig = CARD_CONFIGS[9];\n\nconst COLUMN_SPECS: ReadonlyArray<ColumnSpec> = [\n { kind: \"protect\" }, // glyph\n { kind: \"protect\" }, // check name\n { kind: \"protect\" }, // status (ok / warn / fail)\n { kind: \"clip\", min: 1 }, // detail (free-form)\n];\n\nexport function DoctorCard({ snapshot, rowBudget, cols }: DoctorCardProps): ReactElement {\n const contentWidth = contentWidthFromCols(cols ?? termColsForLayout());\n if (snapshot === null || snapshot.doctor === null) {\n return CardPlaceholder({\n title: \"Doctor\",\n cardId: 9,\n config: cardConfig,\n rowBudget,\n cols,\n text: \"loading…\",\n });\n }\n\n const { checks, problemCount } = snapshot.doctor;\n const subtitle = formatSubtitle(problemCount);\n\n // Healthy path: render the quiet \"GLYPH.ok <K> checks\" line so the\n // operator can confirm the card ran (vs. simply being empty).\n if (problemCount === 0) {\n return CardPlaceholder({\n title: \"Doctor\",\n cardId: 9,\n config: cardConfig,\n rowBudget,\n cols,\n subtitle,\n children: (\n <Text dimColor>\n <Text color=\"green\">{GLYPH.ok}</Text> {checks.length} check\n {checks.length === 1 ? \"\" : \"s\"}\n </Text>\n ),\n });\n }\n\n const problems = checks.filter((c) => c.status !== \"ok\");\n const shown = problems.slice(0, rowBudget ?? cardConfig.maxRows);\n const more = problems.length - shown.length;\n const bottomLabel = more > 0 ? `+${more} more · Shift+9` : undefined;\n const rows = shown.map((c) => [glyphFor(c), c.name, c.status, c.detail]);\n const widths = layoutColumns(rows, COLUMN_SPECS, contentWidth);\n\n return (\n <TitledBox\n height={cardRenderHeight(cardConfig, rowBudget)}\n width={cols}\n title=\"Doctor\"\n subtitle={subtitle}\n cardId={9}\n bottomLabel={bottomLabel}\n >\n {shown.map((c, i) => {\n const row = rows[i];\n if (row === undefined) return null;\n const padded = renderRow(row, widths, COLUMN_SPECS);\n const statusColor = colorForStatus(c.status);\n const colors = [\n { color: statusColor }, // glyph\n { bold: true }, // name\n { color: statusColor }, // status\n { dimColor: true }, // detail\n ];\n return <ListRow key={c.name} cells={padded} contentWidth={contentWidth} colors={colors} />;\n })}\n </TitledBox>\n );\n}\n\n// ─── pure helpers (exported for unit tests) ────────────────────────\n\n/** Per-row glyph driven by the check's status, from src/glyphs.ts —\n * the same constants the Workspaces card and the agent status map\n * use, so one symbol means one thing everywhere. */\nexport function glyphFor(c: Pick<DoctorCheck, \"status\">): string {\n switch (c.status) {\n case \"fail\":\n return GLYPH.fail;\n case \"warn\":\n return GLYPH.warn;\n case \"ok\":\n return GLYPH.ok;\n }\n}\n\n/** Picocolors-compatible colour name for the status. fail → red,\n * warn → yellow, ok → green. Used both for the glyph and the\n * STATUS column so the row reads as a single visual unit. */\nexport function colorForStatus(s: DoctorCheck[\"status\"]): string {\n switch (s) {\n case \"fail\":\n return \"red\";\n case \"warn\":\n return \"yellow\";\n case \"ok\":\n return \"green\";\n }\n}\n\n/** Subtitle: \"all healthy\" when problemCount===0, else the number.\n * Kept terse so the title bar reads at a glance — when something is\n * wrong, \"Doctor · 2\" is the load-bearing signal; the row body\n * carries the names. */\nexport function formatSubtitle(problemCount: number): string {\n if (problemCount === 0) return \"all healthy\";\n return String(problemCount);\n}\n","// In-progress card — every IN_PROGRESS task in the workstream, with\n// owner + time-since-claim. Aimed at the cross-ref pain that today\n// forces the operator to read the Agents card AND the Ready card to\n// figure out \"what's actually running right now\":\n//\n// Agents card → who's busy, but not which task they're on\n// Ready card → unblocked OPEN tasks; nothing about IN_PROGRESS\n// Tracks card → DAG shape, not the live run state\n//\n// Card 6 collapses that into one glance. Per feat_card_6_inprogress\n// (workstream `tui-impl`), promoted from the slot reserved by\n// design_global_keymap. Mirrors the shape of Card 5 — Workspaces.\n//\n// CARD LAYOUT\n// glyph id owner since-claim title\n// ▶ design_x worker-1 3m Design X\n// ▶ review_x reviewer-1 12m Review X\n//\n// Glyph ▶ matches agent-display's busy status glyph used in the Agents\n// card — the operator already reads it as \"this thing is running\".\n// Consistency over novelty.\n//\n// CLIPPING POLICY (per feat_column_aligned_lists)\n// id, owner, since-claim → PROTECT (yankable; numbers / identifiers)\n// title → CLIP (free-form prose)\n//\n// SUBTITLE (mirrors Card 5)\n// empty → omitted (no IN_PROGRESS tasks → empty-state body)\n// populated → \"<N>\" or \"<N> · <K> stale\"\n// stale := time-since-claim ≥ 5min (matches mu's idle threshold\n// default; see skills/mu/recipes/orchestrator-loop.md)\n//\n// TIME-SINCE-CLAIM\n// The cheapest accurate-enough proxy is TaskRow.updatedAt — task\n// lifecycle flips (claim, status changes) update it. A true\n// `claim_at` column would require a schema add + agent_logs scan\n// per row; OUT OF SCOPE here per the task brief. If a future task\n// needs that, it should add it as a typed SDK field, not extend\n// this card to do per-row event-log reads.\n//\n// POPUP (Shift+6 / `^`) IS OUT OF SCOPE here.\n// The umbrella feat_more_cards_umbrella tracks it. When the popup\n// does land, it MUST follow:\n// (a) feat_popup_search_filter — '/' search via usePopupFilter\n// (b) feat_track_drill_chains_to_task_drill — Enter chains rows\n// into TaskDetailDrill (rows ARE tasks, so the drill leaf\n// is exactly that primitive).\n// Until then, Shift+6 stays a reserved noop in keys.ts.\n\nimport type { ReactElement } from \"react\";\nimport type { WorkstreamSnapshot } from \"../../../state.js\";\nimport { formatPair } from \"../../../tasks/status.js\";\nimport { inkColorForPair } from \"../../format.js\";\nimport { agentByName, agentStateGlyph, formatTaskOwnerDisplay } from \"../agent-display.js\";\nimport {\n type ColumnSpec,\n contentWidthFromCols,\n layoutColumns,\n renderRow,\n termColsForLayout,\n} from \"../columns.js\";\nimport { ageMs, formatSinceClaim } from \"../format-helpers.js\";\nimport { CARD_CONFIGS, cardRenderHeight } from \"../layout.js\";\nimport { ListRow } from \"../list-row.js\";\nimport { TitledBox } from \"../titled-box.js\";\nimport { CardPlaceholder } from \"./_placeholder.js\";\n\nexport interface InProgressCardProps {\n snapshot: WorkstreamSnapshot | null;\n rowBudget?: number;\n cols?: number;\n}\n\nexport const cardConfig = CARD_CONFIGS[6];\n\n/** Glyph for every IN_PROGRESS task. Mirrors the busy agent status glyph. */\nexport const GLYPH = agentStateGlyph(\"busy\");\n\n/** ≥5min since the last lifecycle flip → \"stale claim\". Matches the\n * default value of MU_IDLE_THRESHOLD_MS (300_000ms / 5min) used by\n * the agent-side idle detector — we deliberately re-use the same\n * threshold so a stale claim and an idle agent surface together. */\nexport const STALE_CLAIM_THRESHOLD_MS = 300_000;\n\nconst COLUMN_SPECS: ReadonlyArray<ColumnSpec> = [\n { kind: \"protect\" }, // glyph\n { kind: \"protect\" }, // task id\n { kind: \"protect\" }, // status\n { kind: \"protect\" }, // owner (or \"—\")\n { kind: \"protect\", align: \"right\" }, // since-claim\n { kind: \"clip\", min: 1 }, // title\n];\n\nexport function InProgressCard({ snapshot, rowBudget, cols }: InProgressCardProps): ReactElement {\n const contentWidth = contentWidthFromCols(cols ?? termColsForLayout());\n if (snapshot === null) {\n return CardPlaceholder({\n title: \"In-progress\",\n cardId: 6,\n config: cardConfig,\n rowBudget,\n cols,\n text: \"loading…\",\n });\n }\n\n const { inProgress } = snapshot;\n\n if (inProgress.length === 0) {\n return CardPlaceholder({\n title: \"In-progress\",\n cardId: 6,\n config: cardConfig,\n rowBudget,\n cols,\n text: \"(none in progress)\",\n });\n }\n\n const now = Date.now();\n const ages = inProgress.map((t) => ageMs(t, now));\n const stale = ages.filter((ms) => isStale(ms)).length;\n const subtitle = formatSubtitle(inProgress.length, stale);\n\n const shown = inProgress.slice(0, rowBudget ?? cardConfig.maxRows);\n const more = inProgress.length - shown.length;\n const bottomLabel = more > 0 ? `+${more} more · Shift+6` : undefined;\n const agentLookup = agentByName(snapshot);\n const rows = shown.map((t, i) => [\n GLYPH,\n t.name,\n formatPair(t),\n formatTaskOwnerDisplay(t, agentLookup),\n formatSinceClaim(ages[i] ?? null),\n t.title,\n ]);\n const widths = layoutColumns(rows, COLUMN_SPECS, contentWidth);\n\n return (\n <TitledBox\n height={cardRenderHeight(cardConfig, rowBudget)}\n width={cols}\n title=\"In-progress\"\n subtitle={subtitle}\n cardId={6}\n bottomLabel={bottomLabel}\n >\n {shown.map((t, i) => {\n const row = rows[i];\n if (row === undefined) return null;\n const padded = renderRow(row, widths, COLUMN_SPECS);\n const rowAge = ages[i];\n const stale = isStale(rowAge ?? null);\n const colors = [\n { color: \"yellow\" }, // glyph\n { bold: true }, // id\n { color: inkColorForPair(t) }, // status\n { dimColor: true }, // owner\n stale ? { color: \"yellow\" } : { dimColor: true }, // since\n { dimColor: true }, // title\n ];\n return <ListRow key={t.name} cells={padded} contentWidth={contentWidth} colors={colors} />;\n })}\n </TitledBox>\n );\n}\n\n// ─── pure helpers (exported for unit tests) ────────────────────────\n\n/** True when `ms` is at or above the stale-claim threshold (5min).\n * null / undefined → false (we never paint \"stale\" without data). */\nexport function isStale(ms: number | null | undefined): boolean {\n return typeof ms === \"number\" && ms >= STALE_CLAIM_THRESHOLD_MS;\n}\n\n/** Build the subtitle: total · N stale. Suppresses the stale leg\n * when zero so a healthy workstream renders a quiet \"3\" instead\n * of \"3 · 0 stale\". */\nexport function formatSubtitle(total: number, stale: number): string {\n const parts: string[] = [String(total)];\n if (stale > 0) parts.push(`${stale} stale`);\n return parts.join(\" · \");\n}\n","// Activity-log card — fixed-height tail of the most recent N events\n// from agent_logs. Auto-updates on every tick (no scroll-pause needed\n// at the card level; the popup handles full scroll-pause behaviour).\n//\n// Per design_card_log (workstream `tui`).\n//\n// Aesthetic: rounded border, dim border, section header inset; verb\n// verb coloured cyan; prose from the shared renderOp formatter.\n//\n// Rows are column-aligned via src/cli/tui/columns.ts. Per\n// feat_column_aligned_lists clipping policy: timestamp, source, verb\n// are PROTECTED (short, identity-bearing); the rest is CLIPPABLE.\n\nimport type { ReactElement } from \"react\";\nimport { renderOp } from \"../../../log-render.js\";\nimport type { WorkstreamSnapshot } from \"../../../state.js\";\nimport {\n type ColumnSpec,\n contentWidthFromCols,\n layoutColumns,\n renderRow,\n termColsForLayout,\n} from \"../columns.js\";\nimport { CARD_CONFIGS, cardRenderHeight } from \"../layout.js\";\nimport { ListRow } from \"../list-row.js\";\nimport { TitledBox } from \"../titled-box.js\";\nimport { CardPlaceholder } from \"./_placeholder.js\";\n\nexport interface LogCardProps {\n snapshot: WorkstreamSnapshot | null;\n rowBudget?: number;\n cols?: number;\n}\n\nexport const cardConfig = CARD_CONFIGS[4];\n\nconst COLUMN_SPECS: ReadonlyArray<ColumnSpec> = [\n { kind: \"protect\" }, // ts (HH:MM:SS)\n { kind: \"protect\" }, // source\n { kind: \"protect\" }, // verb (or '·' fallback)\n { kind: \"clip\", min: 1 }, // rest / payload\n];\n\nexport function LogCard({ snapshot, rowBudget, cols }: LogCardProps): ReactElement {\n const contentWidth = contentWidthFromCols(cols ?? termColsForLayout());\n if (snapshot === null) {\n return CardPlaceholder({\n title: \"Activity log\",\n cardId: 4,\n config: cardConfig,\n rowBudget,\n cols,\n text: \"loading…\",\n });\n }\n\n const { recent } = snapshot;\n\n if (recent.length === 0) {\n return CardPlaceholder({\n title: \"Activity log\",\n cardId: 4,\n config: cardConfig,\n rowBudget,\n cols,\n text: \"(no events yet)\",\n });\n }\n\n // Show the LAST N events (newest at the bottom). listLogs returns\n // them descending-by-seq via afterSeq cursor semantics; we slice\n // the head and reverse for \"newest at bottom\" reading.\n const tail = recent.slice(0, rowBudget ?? cardConfig.maxRows).reverse();\n\n // Prose comes from renderOp — the same formatter `mu log` uses. This\n // card owns column layout and colour, never phrasing (v2-log-verb).\n const cellRows = tail.map((row) => {\n const r = renderOp(row);\n const ts = row.createdAt.slice(11, 19);\n const verb = r?.verb ?? \"·\";\n const rest = r === null ? row.payload : [r.subject, r.detail].filter((x) => x !== \"\").join(\" \");\n return [ts, row.source, verb, rest];\n });\n const widths = layoutColumns(cellRows, COLUMN_SPECS, contentWidth);\n\n return (\n <TitledBox\n height={cardRenderHeight(cardConfig, rowBudget)}\n width={cols}\n title=\"Activity log\"\n subtitle={`last ↑${tail.length}`}\n cardId={4}\n >\n {tail.map((row, i) => {\n const cells = cellRows[i];\n if (cells === undefined) return null;\n const padded = renderRow(cells, widths, COLUMN_SPECS);\n const colors = [\n { dimColor: true }, // ts\n { dimColor: true }, // source\n row.intent === null ? { dimColor: true } : { color: \"cyan\" }, // verb\n undefined, // rest\n ];\n return <ListRow key={row.seq} cells={padded} contentWidth={contentWidth} colors={colors} />;\n })}\n </TitledBox>\n );\n}\n","// Ready card — top-N OPEN tasks with no unsatisfied blockers, sorted\n// by ROI desc.\n//\n// Per design_card_ready (workstream `tui`).\n//\n// Aesthetic: rounded border, dim border, section header inset; ROI\n// bucket colours via roiBucket() — high=green, mid=yellow, low=dim.\n//\n// Rows are column-aligned via src/cli/tui/columns.ts. Per\n// feat_column_aligned_lists clipping policy: task name, ROI number,\n// owner are PROTECTED (yank affordance / numeric); the title is\n// CLIPPABLE.\n\nimport { Text } from \"ink\";\nimport type { ReactElement } from \"react\";\nimport { roiBucket, type WorkstreamSnapshot } from \"../../../state.js\";\nimport { formatPair } from \"../../../tasks/status.js\";\nimport { inkColorForPair } from \"../../format.js\";\nimport { agentByName, formatTaskOwnerDisplay } from \"../agent-display.js\";\nimport {\n type ColumnSpec,\n contentWidthFromCols,\n layoutColumns,\n renderRow,\n termColsForLayout,\n} from \"../columns.js\";\nimport { colorForBucket, formatRoi } from \"../format-helpers.js\";\nimport { CARD_CONFIGS, cardRenderHeight } from \"../layout.js\";\nimport { ListRow } from \"../list-row.js\";\nimport { TitledBox } from \"../titled-box.js\";\nimport { CardPlaceholder } from \"./_placeholder.js\";\n\nexport interface ReadyCardProps {\n snapshot: WorkstreamSnapshot | null;\n rowBudget?: number;\n cols?: number;\n}\n\nexport const cardConfig = CARD_CONFIGS[3];\n\nconst COLUMN_SPECS: ReadonlyArray<ColumnSpec> = [\n { kind: \"protect\" }, // task name\n { kind: \"protect\" }, // status\n { kind: \"protect\", align: \"right\" }, // ROI label (e.g. \"ROI 50\")\n { kind: \"clip\", min: 1 }, // title\n { kind: \"protect\" }, // owner (or \"—\")\n];\n\nexport function ReadyCard({ snapshot, rowBudget, cols }: ReadyCardProps): ReactElement {\n const contentWidth = contentWidthFromCols(cols ?? termColsForLayout());\n if (snapshot === null) {\n return CardPlaceholder({\n title: \"Ready\",\n cardId: 3,\n config: cardConfig,\n rowBudget,\n cols,\n text: \"loading…\",\n });\n }\n\n const { ready } = snapshot;\n\n if (ready.length === 0) {\n return CardPlaceholder({\n title: \"Ready\",\n cardId: 3,\n config: cardConfig,\n rowBudget,\n cols,\n children: (\n // truncate-end: a wrapped second line would spill over the\n // card's top border and erase its title.\n <Text dimColor wrap=\"truncate-end\">\n {snapshot.parkedCount > 0\n ? `(no ready tasks) ${snapshot.parkedCount} parked · the rest are blocked or closed`\n : \"(no ready tasks) every blocker is OPEN/IN_PROGRESS or every task is closed\"}\n </Text>\n ),\n });\n }\n\n const shown = ready.slice(0, rowBudget ?? cardConfig.maxRows);\n const more = ready.length - shown.length;\n const bottomLabel = more > 0 ? `+${more} more · Shift+3` : undefined;\n const meta = shown.map((t) => {\n const bucket = roiBucket(t.impact, t.effortDays);\n const roiText = formatRoi(t.impact, t.effortDays);\n return { bucket, roiText };\n });\n const agentLookup = agentByName(snapshot);\n const rows = shown.map((t, i) => [\n t.name,\n formatPair(t),\n `ROI ${meta[i]?.roiText ?? \"\"}`,\n t.title,\n formatTaskOwnerDisplay(t, agentLookup),\n ]);\n const widths = layoutColumns(rows, COLUMN_SPECS, contentWidth);\n\n return (\n <TitledBox\n height={cardRenderHeight(cardConfig, rowBudget)}\n width={cols}\n title=\"Ready\"\n subtitle={String(ready.length)}\n cardId={3}\n bottomLabel={bottomLabel}\n >\n {shown.map((t, i) => {\n const row = rows[i];\n const m = meta[i];\n if (row === undefined || m === undefined) return null;\n const padded = renderRow(row, widths, COLUMN_SPECS);\n const colors = [\n { bold: true }, // name\n { color: inkColorForPair(t) }, // status\n { color: colorForBucket(m.bucket) }, // roi\n { dimColor: true }, // title\n { dimColor: true }, // owner\n ];\n return <ListRow key={t.name} cells={padded} contentWidth={contentWidth} colors={colors} />;\n })}\n </TitledBox>\n );\n}\n","// Recent card — CLOSED tasks in the workstream, most recently updated\n// first (updated_at, a proxy for close time; see \"WHEN\" below), so the\n// operator can cherry-pick / verify / cross-reference without bouncing to a\n// separate `mu task list --status CLOSED -w <ws>` shell.\n//\n// Per feat_card_8_recent (workstream `tui-impl`), promoted from the\n// slot reserved by design_global_keymap. Mirrors the shape of\n// Card 5 — Workspaces (264585f9), Card 6 — In-progress (760fc6c),\n// and Card 7 — Blocked (4c50fc0) so the operator reads it the same\n// way: TitledBox header, column-aligned rows, glanceable subtitle.\n//\n// CARD LAYOUT\n// glyph id STATUS when title\n// <ok> feat_card_5 CLOSED 3m ago FEAT: Card 5 — Workspaces\n// <ok> feat_card_6 CLOSED 12m ago FEAT: Card 6 — In-progress\n//\n// GLYPH.ok is coloured green — every row in this card is by definition\n// CLOSED (the SDK helper listRecentClosed filters on status='CLOSED');\n// the check-circle reads as \"shipped\".\n//\n// CLIPPING POLICY (per feat_column_aligned_lists)\n// id, STATUS, when → PROTECT (yankable / identifier / numeric)\n// title → CLIP (free-form prose)\n//\n// SUBTITLE\n// empty → omitted (no recently-closed tasks → empty body)\n// populated → \"<N>\" or \"<N> · last <relTime since newest row>\"\n// — the newest updated_at is usually the latest close\n// (a later note or edge on a CLOSED task also bumps it),\n// the anchor for \"did the wave just finish?\".\n//\n// DATA\n// - snapshot.recentClosed is the listRecentClosed slice (CLOSED\n// status, ORDER BY updated_at DESC LIMIT 5). Used directly. No\n// SDK extension per the task brief — if a future task wants a\n// larger window, it should bump the SDK helper's default and\n// have the card cap at ROW_LIMIT here.\n//\n// \"WHEN\" COLUMN\n// The cheapest proxy for \"closed at\" is TaskRow.updatedAt: closeTask\n// sets it, but it is not close time. A real `closed_at` column would\n// need a schema add + agent_logs scan; OUT OF SCOPE per the brief.\n// If a row is later updated (a note appended, an edge added or\n// removed), touchTask bumps updatedAt, so the row moves up and its\n// \"when\" reads as the time of that later write. Known limitation.\n//\n// POPUP\n// Shift+8 (`*`) opens the matching Recent popup. Card slot 8 and\n// popup slot 8 now point at the same task-recent view again.\n\nimport type { ReactElement } from \"react\";\nimport { GLYPH as SHARED_GLYPH } from \"../../../glyphs.js\";\nimport type { WorkstreamSnapshot } from \"../../../state.js\";\nimport { formatPair } from \"../../../tasks/status.js\";\nimport { inkColorForPair } from \"../../format.js\";\nimport {\n type ColumnSpec,\n contentWidthFromCols,\n layoutColumns,\n renderRow,\n termColsForLayout,\n} from \"../columns.js\";\nimport { ageMs, formatWhen } from \"../format-helpers.js\";\nimport { CARD_CONFIGS, cardRenderHeight } from \"../layout.js\";\nimport { ListRow } from \"../list-row.js\";\nimport { TitledBox } from \"../titled-box.js\";\nimport { CardPlaceholder } from \"./_placeholder.js\";\n\nexport interface RecentCardProps {\n snapshot: WorkstreamSnapshot | null;\n rowBudget?: number;\n cols?: number;\n}\n\nexport const cardConfig = CARD_CONFIGS[8];\n\n/** Glyph for every recently-closed row. Always the ok check. */\nexport const GLYPH = SHARED_GLYPH.ok;\n\nconst COLUMN_SPECS: ReadonlyArray<ColumnSpec> = [\n { kind: \"protect\" }, // glyph\n { kind: \"protect\" }, // task id\n { kind: \"protect\" }, // status (always CLOSED; constant for now)\n { kind: \"protect\", align: \"right\" }, // when (e.g. \"3m ago\")\n { kind: \"clip\", min: 1 }, // title\n];\n\nexport function RecentCard({ snapshot, rowBudget, cols }: RecentCardProps): ReactElement {\n const contentWidth = contentWidthFromCols(cols ?? termColsForLayout());\n if (snapshot === null) {\n return CardPlaceholder({\n title: \"Recent\",\n cardId: 8,\n config: cardConfig,\n rowBudget,\n cols,\n text: \"loading…\",\n });\n }\n\n const { recentClosed } = snapshot;\n\n if (recentClosed.length === 0) {\n return CardPlaceholder({\n title: \"Recent\",\n cardId: 8,\n config: cardConfig,\n rowBudget,\n cols,\n text: \"(none recently closed)\",\n });\n }\n\n const now = Date.now();\n const ages = recentClosed.map((t) => ageMs(t, now));\n const subtitle = formatSubtitle(recentClosed.length, ages[0] ?? null);\n\n const shown = recentClosed.slice(0, rowBudget ?? cardConfig.maxRows);\n const more = recentClosed.length - shown.length;\n const bottomLabel = more > 0 ? `+${more} more · Shift+8` : undefined;\n const rows = shown.map((t, i) => [\n GLYPH,\n t.name,\n formatPair(t),\n formatWhen(ages[i] ?? null),\n t.title,\n ]);\n const widths = layoutColumns(rows, COLUMN_SPECS, contentWidth);\n\n return (\n <TitledBox\n height={cardRenderHeight(cardConfig, rowBudget)}\n width={cols}\n title=\"Recent\"\n subtitle={subtitle}\n cardId={8}\n bottomLabel={bottomLabel}\n >\n {shown.map((t, i) => {\n const row = rows[i];\n if (row === undefined) return null;\n const padded = renderRow(row, widths, COLUMN_SPECS);\n const colors = [\n { color: \"green\" }, // glyph\n { bold: true }, // id\n { color: inkColorForPair(t) }, // status\n { dimColor: true }, // when\n { dimColor: true }, // title\n ];\n return <ListRow key={t.name} cells={padded} contentWidth={contentWidth} colors={colors} />;\n })}\n </TitledBox>\n );\n}\n\n// ─── pure helpers (exported for unit tests) ────────────────────────\n\n/** Build the subtitle: total · last <when>. Suppresses the \"last\"\n * leg when `mostRecentMs` is null (defensive — populated path\n * always has at least one row, hence at least one age). */\nexport function formatSubtitle(total: number, mostRecentMs: number | null): string {\n const parts: string[] = [String(total)];\n if (mostRecentMs !== null) parts.push(`last ${formatWhen(mostRecentMs)}`);\n return parts.join(\" · \");\n}\n","// Tracks card — parallel-track summary. One row per track: leading\n// goal name + counts (total tasks, ready) + diamond-merge marker if\n// applicable.\n//\n// Per design_card_tracks (workstream `tui`).\n//\n// Aesthetic: section header inset into the top border (TitledBox).\n//\n// Rows are column-aligned via src/cli/tui/columns.ts. Per\n// feat_column_aligned_lists clipping policy: track number, merge glyph,\n// task counts are PROTECTED (identity / numeric); the goal-name list\n// is CLIPPABLE.\n\nimport { Text } from \"ink\";\nimport type { ReactElement } from \"react\";\nimport { GLYPH } from \"../../../glyphs.js\";\nimport type { WorkstreamSnapshot } from \"../../../state.js\";\nimport {\n type ColumnSpec,\n contentWidthFromCols,\n layoutColumns,\n renderRow,\n termColsForLayout,\n} from \"../columns.js\";\nimport { CARD_CONFIGS, cardRenderHeight } from \"../layout.js\";\nimport { ListRow } from \"../list-row.js\";\nimport { TitledBox } from \"../titled-box.js\";\nimport { CardPlaceholder } from \"./_placeholder.js\";\n\nexport interface TracksCardProps {\n snapshot: WorkstreamSnapshot | null;\n rowBudget?: number;\n cols?: number;\n}\n\nexport const cardConfig = CARD_CONFIGS[2];\n\nconst COLUMN_SPECS: ReadonlyArray<ColumnSpec> = [\n { kind: \"protect\" }, // \"Track N\"\n { kind: \"protect\" }, // diamond glyph (or empty)\n { kind: \"clip\", min: 1 }, // goal names\n { kind: \"protect\" }, // counts \"(N tasks · M ready)\"\n];\n\nexport function TracksCard({ snapshot, rowBudget, cols }: TracksCardProps): ReactElement {\n const contentWidth = contentWidthFromCols(cols ?? termColsForLayout());\n if (snapshot === null) {\n return CardPlaceholder({\n title: \"Tracks\",\n cardId: 2,\n config: cardConfig,\n rowBudget,\n cols,\n text: \"loading…\",\n });\n }\n\n const { tracks } = snapshot;\n const totalReady = tracks.reduce((acc, t) => acc + t.readyCount, 0);\n\n if (tracks.length === 0) {\n return CardPlaceholder({\n title: \"Tracks\",\n cardId: 2,\n config: cardConfig,\n rowBudget,\n cols,\n children: (\n <Text dimColor>\n (no goals) try `mu task add -w {snapshot.workstreamName} --title \"...\"`\n </Text>\n ),\n });\n }\n\n const shown = tracks.slice(0, rowBudget ?? cardConfig.maxRows);\n const more = tracks.length - shown.length;\n const bottomLabel = more > 0 ? `+${more} more · Shift+2` : undefined;\n const rows = shown.map((t, i) => {\n const goalNames = t.roots\n .slice(0, 2)\n .map((r) => r.name)\n .join(\", \");\n const diamond = t.roots.length > 1 ? GLYPH.merge : \" \";\n const taskNoun = t.taskIds.size === 1 ? \"task\" : \"tasks\";\n const parked = t.parked ? \" (parked)\" : \"\";\n const counts = `(${t.taskIds.size} ${taskNoun} · ${t.readyCount} ready)${parked}`;\n return [`Track ${i + 1}`, diamond, goalNames, counts];\n });\n const widths = layoutColumns(rows, COLUMN_SPECS, contentWidth);\n\n return (\n <TitledBox\n height={cardRenderHeight(cardConfig, rowBudget)}\n width={cols}\n title=\"Tracks\"\n subtitle={`${tracks.length} · ${totalReady} ready`}\n cardId={2}\n bottomLabel={bottomLabel}\n >\n {shown.map((t, i) => {\n const row = rows[i];\n if (row === undefined) return null;\n const padded = renderRow(row, widths, COLUMN_SPECS);\n const trackKey = `${i}-${t.roots[0]?.name ?? \"unknown\"}`;\n const ready = t.readyCount;\n const colors = [\n { color: \"cyan\" }, // trackLabel\n undefined, // diamond\n undefined, // goals\n ready > 0 ? { color: \"green\" } : { dimColor: true }, // counts\n ];\n return (\n <ListRow key={trackKey} cells={padded} contentWidth={contentWidth} colors={colors} />\n );\n })}\n </TitledBox>\n );\n}\n","// Workspaces card — per-agent VCS working copy summary, aimed at the\n// \"between-wave refresh / cherry-pick\" loop where commits-behind +\n// dirty are the load-bearing signals.\n//\n// Per feat_card_5_workspaces (workstream `tui-impl`) and the umbrella\n// note on feat_more_cards_umbrella: \"high signal for cherry-pick /\n// refresh-between-waves loops; only place that exposes commits-behind\n// + dirty\". Cards 1-4 cover agents/tracks/ready/log; this fills slot\n// 5 (Unicode superscript ⁵, btop convention via TitledBox).\n//\n// Aesthetic: rounded border, dim border colour, section header inset\n// into the top — same family as the other four cards.\n//\n// Data shape (per row):\n// - status glyph GLYPH.dirty | GLYPH.stale | GLYPH.ok\n// - agent name e.g. worker-1\n// - backend git | jj | sl | none\n// - behind coloured int (green ≤2, yellow 3-9, red ≥10)\n// - parent_ref first 12 chars (matches mu workspace list)\n//\n// Rows are column-aligned via src/cli/tui/columns.ts. Per\n// feat_column_aligned_lists clipping policy: glyph + agent name +\n// backend + behind + parent_ref are all PROTECTED (operators yank\n// them verbatim into shell commands). Nothing here is free-form prose\n// so we have no clippable column — this is a deliberate exception:\n// every cell is identity-bearing. If row-width overflows, the\n// dashboard's terminal-too-small guard already handles it.\n//\n// FOLLOW-UP (not in scope):\n// - Matching Shift+5 (`%`) popup with per-row yank intents\n// (refresh / commits / free / path). Tracked by the parent\n// feat_more_cards_umbrella; popup likely lands as a sibling task.\n\nimport { Text } from \"ink\";\nimport type { ReactElement } from \"react\";\nimport { GLYPH } from \"../../../glyphs.js\";\nimport type { WorkstreamSnapshot } from \"../../../state.js\";\nimport {\n isWorkspaceStale,\n WORKSPACE_STALE_THRESHOLD,\n type WorkspaceRow,\n} from \"../../../workspace.js\";\nimport { agentByName, formatAgentRefDisplayName } from \"../agent-display.js\";\nimport {\n type ColumnSpec,\n contentWidthFromCols,\n layoutColumns,\n renderRow,\n termColsForLayout,\n} from \"../columns.js\";\nimport { CARD_CONFIGS, cardRenderHeight } from \"../layout.js\";\nimport { ListRow } from \"../list-row.js\";\nimport { TitledBox } from \"../titled-box.js\";\nimport { CardPlaceholder } from \"./_placeholder.js\";\n\nexport interface WorkspacesCardProps {\n snapshot: WorkstreamSnapshot | null;\n rowBudget?: number;\n cols?: number;\n}\n\nexport const cardConfig = CARD_CONFIGS[5];\n\nconst COLUMN_SPECS: ReadonlyArray<ColumnSpec> = [\n { kind: \"protect\" }, // status glyph\n { kind: \"protect\" }, // agent name\n { kind: \"protect\" }, // backend\n { kind: \"protect\", align: \"right\" }, // behind count\n { kind: \"protect\" }, // parent_ref short\n];\n\nexport function WorkspacesCard({ snapshot, rowBudget, cols }: WorkspacesCardProps): ReactElement {\n const contentWidth = contentWidthFromCols(cols ?? termColsForLayout());\n if (snapshot === null) {\n return CardPlaceholder({\n title: \"Workspaces\",\n cardId: 5,\n config: cardConfig,\n rowBudget,\n cols,\n text: \"loading…\",\n });\n }\n\n const { workspaces, workstreamName } = snapshot;\n const stale = workspaces.filter((w) => isStale(w.commitsBehindMain)).length;\n const dirty = workspaces.filter((w) => w.dirty === true).length;\n const subtitle = formatSubtitle(workspaces.length, stale, dirty);\n\n if (workspaces.length === 0) {\n return CardPlaceholder({\n title: \"Workspaces\",\n cardId: 5,\n config: cardConfig,\n rowBudget,\n cols,\n children: (\n <Text dimColor>\n (no workspaces) try `mu agent spawn worker-1 -w {workstreamName} --workspace`\n </Text>\n ),\n });\n }\n\n const shown = workspaces.slice(0, rowBudget ?? cardConfig.maxRows);\n const more = workspaces.length - shown.length;\n const bottomLabel = more > 0 ? `+${more} more · Shift+5` : undefined;\n const agentLookup = agentByName(snapshot);\n const rows = shown.map((w) => [\n glyphFor(w),\n formatAgentRefDisplayName(w.agentName, agentLookup),\n w.backend,\n formatBehind(w.commitsBehindMain),\n w.parentRef ? w.parentRef.slice(0, 12) : \"—\",\n ]);\n const widths = layoutColumns(rows, COLUMN_SPECS, contentWidth);\n\n return (\n <TitledBox\n height={cardRenderHeight(cardConfig, rowBudget)}\n width={cols}\n title=\"Workspaces\"\n subtitle={subtitle}\n cardId={5}\n bottomLabel={bottomLabel}\n >\n {shown.map((w, i) => {\n const row = rows[i];\n if (row === undefined) return null;\n const padded = renderRow(row, widths, COLUMN_SPECS);\n const colors = [\n { color: colorForGlyph(w) }, // glyph\n { bold: true }, // name\n { dimColor: true }, // backend\n { color: colorForBehind(w.commitsBehindMain) }, // behind\n { dimColor: true }, // parent\n ];\n return (\n <ListRow key={w.agentName} cells={padded} contentWidth={contentWidth} colors={colors} />\n );\n })}\n </TitledBox>\n );\n}\n\n// ─── pure helpers (exported for unit tests) ────────────────────────\n\n/** True when the row's commits-behind-main is ≥10 (the red bucket\n * used by the static `mu workspace list` table). Kept in sync with\n * formatBehind's thresholds below. */\nexport function isStale(behind: number | null | undefined): boolean {\n return isWorkspaceStale(behind);\n}\n\n/** Render the behind count as a short token. \"—\" when unknown\n * (no main resolvable, none-backend, missing parent_ref, command\n * failure). Numbers render bare; the call-site colours them. */\nexport function formatBehind(n: number | null | undefined): string {\n if (n === undefined || n === null) return \"—\";\n return String(n);\n}\n\n/** Picocolors-compatible colour name for a behind count. Mirrors the\n * static table renderer (src/cli/format.ts formatBehind): green ≤2,\n * yellow 3-9, red ≥10, undefined / unknown falls through to dim. */\nexport function colorForBehind(n: number | null | undefined): string | undefined {\n if (n === undefined || n === null) return undefined;\n if (n <= 2) return \"green\";\n if (n < WORKSPACE_STALE_THRESHOLD) return \"yellow\";\n return \"red\";\n}\n\n/** Per-row status glyph (from src/glyphs.ts). Priority order:\n * 1. dirty → GLYPH.dirty (uncommitted edits — most actionable)\n * 2. stale → GLYPH.stale (commits-behind ≥10 — needs `mu workspace refresh`)\n * 3. clean → GLYPH.ok\n * When dirty is unknown (null / undefined) we fall through to the\n * staleness check; we never paint a row as clean when its dirty\n * state is unknown.\n */\nexport function glyphFor(w: WorkspaceRow): string {\n if (w.dirty === true) return GLYPH.dirty;\n if (isStale(w.commitsBehindMain)) return GLYPH.stale;\n return GLYPH.ok;\n}\n\n/** Glyph colour: red when dirty (most urgent), yellow when stale,\n * green when clean. Undefined → use ink default (matches the\n * default-colour fallthroughs elsewhere). */\nexport function colorForGlyph(w: WorkspaceRow): string | undefined {\n if (w.dirty === true) return \"red\";\n if (isStale(w.commitsBehindMain)) return \"yellow\";\n return \"green\";\n}\n\n/** Build the subtitle: total · N stale · M dirty. Suppresses zeros\n * so a healthy workstream renders a quiet \"3\" instead of\n * \"3 · 0 stale · 0 dirty\". */\nexport function formatSubtitle(total: number, stale: number, dirty: number): string {\n const parts: string[] = [String(total)];\n if (stale > 0) parts.push(`${stale} stale`);\n if (dirty > 0) parts.push(`${dirty} dirty`);\n return parts.join(\" · \");\n}\n","// Help overlay (?). Renders the TUI keymap superset from the shared\n// keymap spec. Status-bar hint clusters are intentionally smaller:\n// they show only the keys that should be always visible in the current\n// mode. The help overlay is the exhaustive reference.\n\nimport { Box, Text, useInput } from \"ink\";\nimport { type ReactElement, useMemo, useState } from \"react\";\nimport { HELP_PANES } from \"./keymap-spec.js\";\nimport { dispatchPopupKeyFromInk, type PopupAction } from \"./keys.js\";\nimport { applyScroll, clampScrollTop, isNavAction } from \"./popups/scroll.js\";\nimport { TitledBox } from \"./titled-box.js\";\nimport { useTerminalSize } from \"./use-terminal-size.js\";\n\nexport type HelpRenderRow =\n | { kind: \"header\"; text: string }\n | { kind: \"row\"; keys: string; effect: string }\n | { kind: \"separator\" };\n\nexport const HELP_CHROME_ROWS = 3;\n\nexport function flattenHelpRows(): HelpRenderRow[] {\n return HELP_PANES.flatMap((pane, paneIdx) => {\n const rows: HelpRenderRow[] = [\n ...(paneIdx > 0 ? ([{ kind: \"separator\" }] as HelpRenderRow[]) : []),\n { kind: \"header\", text: pane.title },\n ...pane.rows.map(\n (row): HelpRenderRow => ({\n kind: \"row\",\n keys: row.keys,\n effect: row.effect,\n }),\n ),\n ];\n return rows;\n });\n}\n\nexport function helpViewport(rows: number): number {\n return Math.max(1, rows - HELP_CHROME_ROWS);\n}\n\nexport function helpPositionLabel(\n scrollTop: number,\n viewport: number,\n totalRows: number,\n): string | undefined {\n if (totalRows <= viewport) return undefined;\n const start = Math.min(totalRows, scrollTop + 1);\n const end = Math.min(totalRows, scrollTop + viewport);\n return `${start}-${end}/${totalRows}`;\n}\n\nexport function applyHelpScroll(\n scrollTop: number,\n action: PopupAction,\n rows: number,\n totalRows: number,\n): number {\n if (!isNavAction(action)) return scrollTop;\n return applyScroll(scrollTop, action, totalRows, helpViewport(rows));\n}\n\nexport interface HelpProps {\n rows: number;\n}\n\nexport function Help({ rows }: HelpProps): ReactElement {\n const { cols } = useTerminalSize();\n const flatRows = useMemo(() => flattenHelpRows(), []);\n const [scrollTop, setScrollTop] = useState(0);\n const totalRows = flatRows.length;\n\n useInput((input, key) => {\n const action = dispatchPopupKeyFromInk(input, key);\n setScrollTop((s) => applyHelpScroll(s, action, rows, totalRows));\n });\n\n return <HelpView rows={rows} scrollTop={scrollTop} flatRows={flatRows} cols={cols} />;\n}\n\nexport interface HelpViewProps {\n rows: number;\n scrollTop?: number;\n flatRows?: readonly HelpRenderRow[];\n /** Terminal columns. When omitted, falls back to process.stdout. */\n cols?: number;\n}\n\nexport function HelpView({\n rows,\n scrollTop = 0,\n flatRows = flattenHelpRows(),\n cols: colsOverride,\n}: HelpViewProps): ReactElement {\n const cols = colsOverride ?? process.stdout.columns ?? 80;\n const contentWidth = Math.max(1, cols - 4); // border + paddingX on both sides\n const viewport = helpViewport(rows);\n const totalRows = flatRows.length;\n const clampedScrollTop = clampScrollTop(scrollTop, totalRows, viewport);\n const visibleRows = flatRows.slice(clampedScrollTop, clampedScrollTop + viewport);\n const positionLabel = helpPositionLabel(clampedScrollTop, viewport, totalRows);\n const title = positionLabel === undefined ? \"keys\" : `keys · ${positionLabel}`;\n\n return (\n <TitledBox title={title} borderColor=\"cyan\" titleColor=\"cyan\" width={cols}>\n <Box flexDirection=\"column\" width={contentWidth}>\n {visibleRows.map((row, idx) => renderHelpLine(row, contentWidth, clampedScrollTop + idx))}\n </Box>\n </TitledBox>\n );\n}\n\nfunction renderHelpLine(row: HelpRenderRow, contentWidth: number, index: number): ReactElement {\n switch (row.kind) {\n case \"separator\":\n return <Text key={index}> </Text>;\n case \"header\":\n return (\n <Box key={index} width={contentWidth}>\n <Text bold color=\"cyan\">\n {row.text}\n </Text>\n </Box>\n );\n case \"row\":\n return (\n <HelpRow key={index} keys={row.keys} effect={row.effect} contentWidth={contentWidth} />\n );\n }\n}\n\nfunction HelpRow({\n keys,\n effect,\n contentWidth,\n}: {\n keys: string;\n effect: string;\n contentWidth: number;\n}): ReactElement {\n return (\n <Box width={contentWidth}>\n <Box width={18}>\n <Text color=\"yellow\" wrap=\"truncate\">\n {keys}\n </Text>\n </Box>\n <Box width={Math.max(1, contentWidth - 18)}>\n <Text dimColor wrap=\"truncate\">\n {effect}\n </Text>\n </Box>\n </Box>\n );\n}\n","// Canonical TUI keymap specification for the status-bar hint\n// clusters and the `?` help overlay.\n//\n// Contract: status-bar hints are the per-mode ALWAYS-SHOWN subset\n// (keys with no better mnemonic elsewhere, and only keys that work in\n// that mode). The help overlay is the SUPERSET: every key shown in a\n// status-bar cluster must appear here too. Keep new key hints in this\n// pure data file so src/cli/tui/status-bar.tsx and help.tsx cannot\n// drift independently.\n\ntype KeyId = string;\n\nexport interface StatusHintEntry {\n kind: \"hint\" | \"label\" | \"text\";\n /** Key glyph/range rendered in yellow for kind=\"hint\". */\n key?: string;\n /** Effect label (kind=\"hint\") or literal text (label/text). */\n label: string;\n keyIds: readonly KeyId[];\n color?: \"cyan\" | \"magenta\" | \"yellow\";\n}\n\nexport interface StatusHintContext {\n mode: \"dashboard\" | \"popup-list\" | \"popup-drill\" | \"popup-filter\" | \"dag\" | \"all-tasks\";\n /** Dashboard-only: Tab hint appears only when N≥2 workstreams. */\n hasWorkstreamTabs?: boolean;\n}\n\nexport interface HelpRowSpec {\n keys: string;\n effect: string;\n keyIds: readonly KeyId[];\n}\n\nexport interface HelpPaneSpec {\n title: string;\n rows: readonly HelpRowSpec[];\n}\n\nconst DASHBOARD_BASE_HINTS: readonly StatusHintEntry[] = [\n hint(\"0-9\", \"cards\", [\"0-9\"]),\n hint(\"Shift 0-9\", \"popups\", [\"Shift 0-9\"]),\n hint(\"g\", \"DAG\", [\"g\"]),\n hint(\"t\", \"tasks\", [\"t\"]),\n];\n\nconst DASHBOARD_TRAILING_HINTS: readonly StatusHintEntry[] = [\n hint(\"?\", \"help\", [\"?\"]),\n hint(\"q\", \"quit\", [\"q\"]),\n];\n\nconst POPUP_LIST_HINTS: readonly StatusHintEntry[] = [\n hint(\"j/k\", \"nav\", [\"j\", \"k\"]),\n hint(\"/\", \"filter\", [\"/\"]),\n hint(\"Enter\", \"drill\", [\"Enter\"]),\n hint(\"y\", \"yank\", [\"y\"]),\n hint(\"?\", \"help\", [\"?\"]),\n hint(\"Esc\", \"back\", [\"Esc\"]),\n];\n\n// `t tuicr` and `l lazygit` are intentionally NOT in the global\n// drill / list status-bar clusters below. Both are per-popup verbs\n// scoped to specific surfaces:\n// - `t tuicr` fires only in git-show drills (Commits popup +\n// Workspaces popup commits drill).\n// - `l lazygit` fires only in the Commits popup list mode\n// (lazygit operates on a cwd, not a single revision, so the\n// natural surface is the list-level repo browse, not a drill).\n// Each consumer inserts the per-popup hint into its `hint` prop\n// — which TitledBox renders inset into the bottom border. Putting\n// either in a global cluster would advertise it everywhere it does\n// nothing (TaskDetailDrill notes, agent scrollback, every other\n// popup, etc).\nconst POPUP_DRILL_HINTS: readonly StatusHintEntry[] = [\n label(\"drill\", \"magenta\"),\n hint(\"j/k\", \"scroll\", [\"j\", \"k\"]),\n hint(\"Ctrl-D/U\", \"page\", [\"Ctrl-D\", \"Ctrl-U\"]),\n hint(\"y\", \"yank\", [\"y\"]),\n hint(\"?\", \"help\", [\"?\"]),\n hint(\"Esc\", \"back\", [\"Esc\"]),\n];\n\nconst POPUP_FILTER_HINTS: readonly StatusHintEntry[] = [\n label(\"filter\", \"yellow\"),\n text(\"type to match\"),\n hint(\"Enter\", \"commit\", [\"Enter\"]),\n hint(\"Esc\", \"cancel\", [\"Esc\"]),\n];\n\nconst DAG_HINTS: readonly StatusHintEntry[] = [\n label(\"drill\", \"magenta\"),\n hint(\"j/k\", \"scroll\", [\"j\", \"k\"]),\n hint(\"o/i/c/p/w\", \"filter\", [\"o\", \"i\", \"c\", \"p\", \"w\"]),\n hint(\"y\", \"yank\", [\"y\"]),\n hint(\"?\", \"help\", [\"?\"]),\n hint(\"Esc\", \"back\", [\"Esc\"]),\n];\n\nconst ALL_TASKS_HINTS: readonly StatusHintEntry[] = [\n label(\"drill\", \"magenta\"),\n hint(\"j/k\", \"nav\", [\"j\", \"k\"]),\n hint(\"o/i/c/p/w\", \"filter\", [\"o\", \"i\", \"c\", \"p\", \"w\"]),\n hint(\"s\", \"sort\", [\"s\"]),\n hint(\"/\", \"search\", [\"/\"]),\n hint(\"Enter\", \"drill\", [\"Enter\"]),\n hint(\"y\", \"yank\", [\"y\"]),\n hint(\"Esc\", \"back\", [\"Esc\"]),\n];\n\nexport function statusHintEntries(context: StatusHintContext): readonly StatusHintEntry[] {\n switch (context.mode) {\n case \"dashboard\":\n return [\n ...DASHBOARD_BASE_HINTS,\n ...(context.hasWorkstreamTabs ? [hint(\"Tab\", \"ws\", [\"Tab\"])] : []),\n ...DASHBOARD_TRAILING_HINTS,\n ];\n case \"popup-list\":\n return POPUP_LIST_HINTS;\n case \"popup-drill\":\n return POPUP_DRILL_HINTS;\n case \"popup-filter\":\n return POPUP_FILTER_HINTS;\n case \"dag\":\n return DAG_HINTS;\n case \"all-tasks\":\n return ALL_TASKS_HINTS;\n }\n}\n\nexport const HELP_PANES: readonly HelpPaneSpec[] = [\n {\n title: \"keys · dashboard\",\n rows: [\n row(\n \"0-9\",\n \"toggle Commits/Agents/Tracks/Ready/Log/Workspaces/In-progress/Blocked/Recent/Doctor cards\",\n [\"0-9\"],\n ),\n row(\"Shift 0-9\", \"open numbered popups (Shift+0 = Commits; Shift+8 = Recent)\", [\"Shift 0-9\"]),\n row(\"g\", \"DAG popup\", [\"g\"]),\n row(\"t\", \"all-tasks popup\", [\"t\"]),\n row(\"Tab / Shift-Tab\", \"next / previous workstream tab (multi-ws)\", [\"Tab\", \"Shift-Tab\"]),\n row(\"c\", \"clear footer (last yank)\", [\"c\"]),\n row(\"0\", \"Commits card (tick reset is not bound; slot 0 is a card)\", [\"0\"]),\n row(\"+/=\", \"tick faster (floor 100ms)\", [\"+\", \"=\"]),\n row(\"-\", \"tick slower (ceiling 10s)\", [\"-\"]),\n row(\"r/F5\", \"refresh now\", [\"r\", \"F5\"]),\n row(\"?\", \"toggle this overlay\", [\"?\"]),\n row(\"q/Q\", \"quit (Ctrl-C also)\", [\"q\", \"Q\", \"Ctrl-C\"]),\n ],\n },\n {\n title: \"keys · popup list\",\n rows: [\n row(\"j/k or ↑/↓\", \"move selection\", [\"j\", \"k\", \"ArrowUp\", \"ArrowDown\"]),\n row(\"g/G\", \"first / last row\", [\"g\", \"G\"]),\n row(\"Ctrl-D/U\", \"half-page down / up\", [\"Ctrl-D\", \"Ctrl-U\"]),\n row(\"PgDn/PgUp\", \"full-page down / up\", [\"PgDn\", \"PgUp\"]),\n row(\"/\", \"filter/search rows\", [\"/\"]),\n row(\"Enter\", \"drill into focused row\", [\"Enter\"]),\n row(\"y\", \"yank action for focused row\", [\"y\"]),\n row(\"a\", \"attach to focused agent's tmux pane (Agents popup only; user-driven TUI escape)\", [\n \"a\",\n ]),\n row(\"l\", \"launch lazygit in the project root (Commits popup only; user-driven TUI escape)\", [\n \"l\",\n ]),\n row(\"Esc/q\", \"back to dashboard\", [\"Esc\", \"q\"]),\n row(\"?\", \"toggle this overlay\", [\"?\"]),\n ],\n },\n {\n title: \"keys · popup drill\",\n rows: [\n row(\"j/k or ↑/↓\", \"scroll one line\", [\"j\", \"k\", \"ArrowUp\", \"ArrowDown\"]),\n row(\"Ctrl-D/U\", \"half-page down / up\", [\"Ctrl-D\", \"Ctrl-U\"]),\n row(\"PgDn/PgUp\", \"full-page down / up\", [\"PgDn\", \"PgUp\"]),\n row(\"g/G\", \"top / bottom\", [\"g\", \"G\"]),\n row(\"/\", \"filter/search when the drill is a list\", [\"/\"]),\n row(\"y\", \"yank drill-specific command\", [\"y\"]),\n row(\"t\", \"launch tuicr for the focused git-show revision (user-driven TUI escape)\", [\"t\"]),\n row(\"Esc/q\", \"back one drill level\", [\"Esc\", \"q\"]),\n row(\"?\", \"toggle this overlay\", [\"?\"]),\n ],\n },\n {\n title: \"keys · popup filter\",\n rows: [\n row(\"type\", \"append printable characters to the filter\", [\"type\"]),\n row(\"Backspace\", \"edit query\", [\"Bksp\"]),\n row(\"Enter\", \"commit filter\", [\"Enter\"]),\n row(\"Esc\", \"cancel filter\", [\"Esc\"]),\n ],\n },\n {\n title: \"keys · DAG / all-tasks\",\n rows: [\n row(\n \"o/i/c/p/w\",\n \"toggle OPEN / IN_PROGRESS / CLOSED status filters; p parked; w won't do (closed, not done)\",\n [\"o\", \"i\", \"c\", \"p\", \"w\"],\n ),\n row(\"b\", \"all-tasks blocked filter cycle (all → only → hide)\", [\"b\"]),\n row(\"s\", \"all-tasks sort cycle (roi → recency → age → id)\", [\"s\"]),\n row(\"/\", \"all-tasks row search\", [\"/\"]),\n ],\n },\n {\n title: \"mouse\",\n rows: [\n row(\"double-click card\", \"drill into popup\", [\"mouse:doubleclick-card\"]),\n row(\"double-click row\", \"drill into row detail\", [\"mouse:doubleclick-row\"]),\n row(\"scroll wheel\", \"scroll list / drill body\", [\"mouse:scroll\"]),\n row(\"back\", \"no mouse back; use Esc/q\", [\"mouse:no-back\"]),\n ],\n },\n];\n\nexport function statusHintKeyIds(context: StatusHintContext): Set<KeyId> {\n return new Set(statusHintEntries(context).flatMap((entry) => entry.keyIds));\n}\n\nexport function helpOverlayKeyIds(): Set<KeyId> {\n return new Set(HELP_PANES.flatMap((pane) => pane.rows.flatMap((row) => row.keyIds)));\n}\n\nfunction hint(key: string, labelText: string, keyIds: readonly KeyId[]): StatusHintEntry {\n return { kind: \"hint\", key, label: labelText, keyIds };\n}\n\nfunction label(textValue: string, color: \"cyan\" | \"magenta\" | \"yellow\"): StatusHintEntry {\n return { kind: \"label\", label: textValue, keyIds: [], color };\n}\n\nfunction text(textValue: string): StatusHintEntry {\n return { kind: \"text\", label: textValue, keyIds: [] };\n}\n\nfunction row(keys: string, effect: string, keyIds: readonly KeyId[]): HelpRowSpec {\n return { keys, effect, keyIds };\n}\n","// Global keymap dispatcher for the TUI dashboard. Per\n// design_global_keymap (workstream `tui`):\n//\n// 0 toggle Commits card\n// 1-4 toggle Agents/Tracks/Ready/Log card\n// 5 toggle Workspaces card (feat_card_5_workspaces)\n// 6 toggle In-progress card (feat_card_6_inprogress)\n// 7 toggle Blocked card (feat_card_7_blocked)\n// 8 toggle Recent card\n// 9 toggle Doctor card (feat_card_9_doctor)\n// g open full DAG popup (graph mnemonic; keybind-only)\n// t open all-tasks popup (task-list mnemonic; keybind-only)\n// Shift+0/) open Commits popup\n// ! @ # $ open fullscreen popup for that card (Shift+1..Shift+4\n// on US keyboards; bound by glyph because ink reports\n// the post-shift character, not the modifier).\n// Shift+8/* open Recent popup\n// + / = tick faster (floor 100ms); = is the unshifted alias\n// - tick slower (ceiling 10s)\n// r / F5 refresh now (poke poll loop)\n// ? toggle help overlay\n// q / Q quit\n// Ctrl-C quit (handled by ink's exitOnCtrlC)\n// c clear footer (most-recent-yank line)\n// Tab next workstream tab (multi-ws TUI; noop when N=1)\n// Shift-Tab previous workstream tab\n//\n// This module is pure TS: takes a keystroke (input + key flags from\n// ink's useInput) and returns a structured GlobalAction. The caller\n// (the <App> component in app.tsx) maps actions to state mutations.\n\nexport type GlobalAction =\n | { kind: \"toggleCard\"; cardId: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 }\n | {\n kind: \"openPopup\";\n cardId: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | \"dag\" | \"allTasks\";\n }\n | { kind: \"tickFaster\" }\n | { kind: \"tickSlower\" }\n | { kind: \"refreshNow\" }\n | { kind: \"toggleHelp\" }\n | { kind: \"quit\" }\n | { kind: \"clearFooter\" }\n | { kind: \"nextTab\" }\n | { kind: \"prevTab\" }\n | { kind: \"noop\" };\n\n/**\n * Subset of ink's `Key` shape we care about. Defining locally so the\n * keys module stays decoupled from ink's render-time Key type.\n */\nexport interface KeyFlags {\n ctrl?: boolean;\n shift?: boolean;\n meta?: boolean;\n escape?: boolean;\n return?: boolean;\n upArrow?: boolean;\n downArrow?: boolean;\n leftArrow?: boolean;\n rightArrow?: boolean;\n tab?: boolean;\n pageUp?: boolean;\n pageDown?: boolean;\n f5?: boolean;\n}\n\n/**\n * Structural subset of ink's `Key` object as delivered to useInput.\n * Kept local (instead of importing ink's type) so keys.ts remains a\n * pure keymap module with no render-time dependency.\n */\nexport type InkKeyLike = KeyFlags;\n\nfunction keyFlagsFromInk(key: InkKeyLike): KeyFlags {\n return {\n ctrl: key.ctrl,\n shift: key.shift,\n meta: key.meta,\n escape: key.escape,\n return: key.return,\n upArrow: key.upArrow,\n downArrow: key.downArrow,\n leftArrow: key.leftArrow,\n rightArrow: key.rightArrow,\n tab: key.tab,\n pageUp: key.pageUp,\n pageDown: key.pageDown,\n f5: key.f5,\n };\n}\n\nexport function dispatchGlobalKeyFromInk(input: string, key: InkKeyLike): GlobalAction {\n return dispatchGlobalKey(input, keyFlagsFromInk(key));\n}\n\n/**\n * Map a single keystroke (delivered by ink's useInput) to the global\n * dashboard action it represents. Returns `{kind:\"noop\"}` for any\n * unrecognised input — the caller can treat noop as \"do nothing\".\n *\n * Pure function: no side effects, no React, no ink imports. Trivially\n * unit-testable.\n */\nexport function dispatchGlobalKey(input: string, key: KeyFlags): GlobalAction {\n // Quit takes precedence over everything (including help overlay\n // suppression handled by the caller).\n if (key.ctrl && input === \"c\") return { kind: \"quit\" };\n if (input === \"q\" || input === \"Q\") return { kind: \"quit\" };\n\n // Help overlay\n if (input === \"?\") return { kind: \"toggleHelp\" };\n\n // Refresh-now poke\n if (input === \"r\" || key.f5) return { kind: \"refreshNow\" };\n\n // Footer clear (last-yank line)\n if (input === \"c\") return { kind: \"clearFooter\" };\n\n // Multi-workstream tab navigation. Tab cycles forward;\n // Shift-Tab cycles backward. Per feat_tui_multi_workstream\n // (workstream `tui-impl`): the dispatcher returns the action\n // unconditionally; the App suppresses it (via the popup-open\n // guard) when a popup is mounted, and degenerates to a noop\n // when only one workstream is loaded.\n if (key.tab === true) {\n return { kind: key.shift === true ? \"prevTab\" : \"nextTab\" };\n }\n\n // Tick rate adjust. `+` arrives as `+` (Shift+= on US); `=` is the\n // unshifted alias for users who don't bother shifting; `-` is the\n // plain minus key. Digit 0 is now a card slot (Commits), so tick\n // reset is intentionally not bound to a dashboard key.\n if (input === \"+\" || input === \"=\") return { kind: \"tickFaster\" };\n if (input === \"-\") return { kind: \"tickSlower\" };\n\n // Card toggles 0-9. Slot 0 is Commits; slot 8 is Recent. DAG stays\n // a keybind-only popup on `g` so it does not consume a card slot.\n if (input >= \"0\" && input <= \"9\") {\n const cardId = (input.charCodeAt(0) - \"0\".charCodeAt(0)) as\n | 0\n | 1\n | 2\n | 3\n | 4\n | 5\n | 6\n | 7\n | 8\n | 9;\n return { kind: \"toggleCard\", cardId };\n }\n\n if (input === \"g\") return { kind: \"openPopup\", cardId: \"dag\" };\n if (input === \"t\") return { kind: \"openPopup\", cardId: \"allTasks\" };\n\n // Popup openers !-) on US keyboards. Bound by glyph because ink\n // reports the post-shift character; key.shift is false.\n // Layout-dependent — see design_global_keymap ODDITY for non-US\n // keymaps. Shift+0 opens Commits; Shift+8 opens Recent.\n const glyphMap: Record<string, 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9> = {\n \")\": 0,\n \"!\": 1,\n \"@\": 2,\n \"#\": 3,\n $: 4,\n \"%\": 5,\n \"^\": 6,\n \"&\": 7,\n \"*\": 8,\n \"(\": 9,\n };\n const popupId = glyphMap[input];\n if (popupId !== undefined) return { kind: \"openPopup\", cardId: popupId };\n\n return { kind: \"noop\" };\n}\n\n// ─── In-popup keymap convention ────────────────────────────────────\n//\n// Per design_global_keymap, every popup honours:\n// j / ↓ moveDown\n// k / ↑ moveUp\n// g jumpTop\n// G jumpBottom\n// Ctrl-D pageDown (half)\n// Ctrl-U pageUp (half)\n// PgDn / PgUp pageDown / pageUp (full)\n// / enterFilter\n// n nextMatch\n// N prevMatch\n// Esc close (or exit drill, when in drill mode)\n// q close (alias)\n// y yank\n// Enter drill into the focused row (popup decides what to render)\n// ? toggleHelp\n//\n// Tick-rate keys (+/-/=), refresh (r/F5), and Ctrl-C remain live in\n// popups (they're global). Card toggles (0-9) and popup openers (!-))\n// are SUPPRESSED by <App>.\n\nexport type PopupAction =\n | { kind: \"moveDown\" }\n | { kind: \"moveUp\" }\n | { kind: \"jumpTop\" }\n | { kind: \"jumpBottom\" }\n | { kind: \"pageDown\"; half: boolean }\n | { kind: \"pageUp\"; half: boolean }\n // Mouse double-click on popup body row `row` (0-based from the first\n // row inside the top border). The popup maps it through its own\n // scroll window and header rows, focuses that item, and drills it.\n | { kind: \"clickRow\"; row: number }\n | { kind: \"filter\" }\n | { kind: \"nextMatch\" }\n | { kind: \"prevMatch\" }\n | { kind: \"close\" }\n | { kind: \"yank\" }\n | { kind: \"drill\" }\n | { kind: \"verb\"; key: string }\n | { kind: \"noop\" };\n\nexport interface PopupActionEnvelope {\n seq: number;\n action: PopupAction;\n}\n\n/**\n * Map a keystroke inside a popup to the popup-local action it\n * represents. Per-popup verbs (letter keys not in the reserved set\n * {j k g G n N q y c r w}) bubble up as `{kind: \"verb\", key}` so the\n * caller can switch on the literal letter.\n */\nexport function dispatchPopupKeyFromInk(input: string, key: InkKeyLike): PopupAction {\n return dispatchPopupKey(input, keyFlagsFromInk(key));\n}\n\n// ─── App-level swallow rules ───────────────────────────────────────\n//\n// Per review_tui_help_overlay_swallows_only_some_keys: the swallow\n// lists for the help-overlay branch and the popup-mode branch in\n// <App>'s useInput were duplicated — same conceptual rule (\"do not\n// let this keystroke leak into the global dashboard keymap while a\n// modal is open\") expressed twice with slightly different lists,\n// inviting drift. Centralised here so a future binding change has\n// one place to update.\n//\n// Caller contract: this helper ONLY decides whether to short-\n// circuit BEFORE the global-keymap dispatcher (`dispatchGlobalKey`)\n// runs. The caller is still responsible for App-owned actions that\n// fire BEFORE the swallow check (toggling helpOpen on close keys,\n// Ctrl-C universal exit). Every popup component owns its own\n// `useInput`; ink fires every mounted `useInput` per keystroke, so\n// the popup's local nav handler still sees `j` / `k` / etc. while\n// this helper short-circuits the global one.\n\n/** Active <App> input mode for swallow-rule selection. */\nexport type InputMode = \"dashboard\" | \"help\" | \"popup\" | \"popup-filter\";\n\n/**\n * Should this keystroke be swallowed (NOT dispatched to the global\n * dashboard keymap)?\n *\n * - `dashboard` — never swallow; the global keymap is the only\n * keymap.\n * - `help` — swallow everything. Help owns its local scroll\n * keys (j/k/Ctrl-D/Ctrl-U/PgUp/PgDn) via `Help`'s own useInput;\n * nothing else should reach the global dispatcher while the\n * overlay is up. Caller pre-handles `Esc`/`q`/`Q`/`?` close keys.\n * - `popup` — swallow close keys (popup owns close), card\n * toggles (`0`-`9` + `!@#$%^&*()`), the keybind-only popup\n * openers (`g`/`t`), and footer-clear (`c`). Tick (`+`/`-`/`=`),\n * refresh (`r`/`F5`), help toggle (`?`), and tab nav (Tab/Shift-\n * Tab) still bubble up so they remain global even inside a popup.\n * - `popup-filter` — swallow EVERY global key. The popup's `/`\n * filter prompt is the active text input; tick/refresh/help/etc.\n * would compete with the user's typing.\n *\n * Ctrl-C is NEVER swallowed regardless of mode (universal escape).\n * The caller still handles it explicitly so it remains a hard\n * `exit()` even when otherwise inside a popup.\n */\nexport function shouldSwallowGlobalKey(input: string, key: KeyFlags, mode: InputMode): boolean {\n if (key.ctrl === true && input === \"c\") return false;\n switch (mode) {\n case \"dashboard\":\n return false;\n case \"help\":\n return true;\n case \"popup-filter\":\n return true;\n case \"popup\":\n if (key.escape === true || input === \"q\" || input === \"Q\") return true;\n // Guard on length: input is \"\" for pure-flag keys (Tab,\n // arrows, Esc, F5). Without the length check, JS's\n // `.includes(\"\")` returns true for the popup-opener glyph\n // string and would swallow Tab.\n if (input.length === 0) return false;\n if (input >= \"0\" && input <= \"9\") return true;\n if (\"!@#$%^&*()\".includes(input)) return true;\n if (input === \"g\" || input === \"t\" || input === \"c\") return true;\n return false;\n }\n}\n\nexport function shouldSwallowGlobalKeyFromInk(\n input: string,\n key: InkKeyLike,\n mode: InputMode,\n): boolean {\n return shouldSwallowGlobalKey(input, keyFlagsFromInk(key), mode);\n}\n\nexport function dispatchPopupKey(input: string, key: KeyFlags): PopupAction {\n if (key.escape || input === \"q\" || input === \"Q\") return { kind: \"close\" };\n if (input === \"j\" || key.downArrow) return { kind: \"moveDown\" };\n if (input === \"k\" || key.upArrow) return { kind: \"moveUp\" };\n if (input === \"g\") return { kind: \"jumpTop\" };\n if (input === \"G\") return { kind: \"jumpBottom\" };\n if (key.ctrl && input === \"d\") return { kind: \"pageDown\", half: true };\n if (key.ctrl && input === \"u\") return { kind: \"pageUp\", half: true };\n if (key.pageDown) return { kind: \"pageDown\", half: false };\n if (key.pageUp) return { kind: \"pageUp\", half: false };\n if (input === \"/\") return { kind: \"filter\" };\n if (input === \"n\") return { kind: \"nextMatch\" };\n if (input === \"N\") return { kind: \"prevMatch\" };\n if (input === \"y\") return { kind: \"yank\" };\n // Enter drills into the focused row. The popup chooses what\n // \"drill\" renders (scrollback / sub-list / notes / no-op for\n // log). The dispatcher stays purely structural — read-only.\n if (key.return) return { kind: \"drill\" };\n // Per-popup verbs: any letter NOT in the reserved set above is a\n // candidate for a popup-specific verb. The caller decides whether\n // to act.\n if (/^[a-zA-Z]$/.test(input)) return { kind: \"verb\", key: input };\n return { kind: \"noop\" };\n}\n","// Shared scroll/navigation primitives for every popup + drill view.\n//\n// Per feat_centralize_scroll_navigation (workstream `tui-impl`):\n// before this module landed, every popup had its OWN switch over\n// PopupAction.kind with the same six scroll cases (moveUp / moveDown\n// / jumpTop / jumpBottom / pageUp / pageDown). Counted ~60\n// near-duplicate switch arms across 9 popups + drill consumers.\n// Inevitable drift — `Ctrl-D` half-page only landed in some drill\n// branches; `g` / `G` only worked in some modes; tracks.tsx had a\n// third copy for its task-detail leaf. This file is the single\n// source of truth.\n//\n// PURE: no ink imports, no React, no DB. Just integer math on\n// (cursor | scrollTop) given (action, total, viewport). Trivially\n// unit-testable; covered by test/tui-scroll.test.ts.\n//\n// Two consumer flavours:\n//\n// CURSOR-BASED (every popup's LIST mode + tracks task-list drill):\n// a focused row index that the user moves with j/k; visible rows\n// pan around the cursor; Enter on the focused row drills.\n// Use `applyCursor`.\n//\n// SCROLL-BASED (DrillScrollView and similar): a scrollTop offset\n// the user pages through; no per-row focus; the body is\n// pre-formatted text (lines). Use `applyScroll`.\n//\n// Both consume the SAME cursor/scroll action kinds (matches\n// PopupAction's nav subset from src/cli/tui/keys.ts), so the popup\n// boilerplate is:\n//\n// if (isNavAction(action)) {\n// setCursor((c) => applyCursor(c, action, items.length, viewport));\n// return;\n// }\n// switch (action.kind) { case \"yank\": ... case \"drill\": ... }\n//\n// or for a DrillScrollView:\n//\n// if (isNavAction(action)) {\n// setScrollTop((s) => applyScroll(s, action, totalLines, viewport));\n// return;\n// }\n\n/**\n * The PopupAction kinds that move the cursor or scroll the view.\n * Exact subset of PopupAction from keys.ts — kept structurally\n * compatible so `isNavAction(popupAction)` narrows in-place without\n * a remap.\n */\nexport type NavAction =\n | { kind: \"moveUp\" }\n | { kind: \"moveDown\" }\n | { kind: \"jumpTop\" }\n | { kind: \"jumpBottom\" }\n | { kind: \"pageUp\"; half: boolean }\n | { kind: \"pageDown\"; half: boolean };\n\nconst NAV_KINDS = new Set<string>([\n \"moveUp\",\n \"moveDown\",\n \"jumpTop\",\n \"jumpBottom\",\n \"pageUp\",\n \"pageDown\",\n]);\n\n/**\n * Type predicate: is this PopupAction one of the six nav cases? When\n * true, the value is structurally a NavAction and can be passed to\n * applyCursor / applyScroll directly.\n */\nexport function isNavAction(action: { kind: string }): action is NavAction {\n return NAV_KINDS.has(action.kind);\n}\n\n/**\n * Half/full page step. Matches the pre-existing per-popup formula\n * `Math.floor(viewport / (half ? 2 : 1))`. Kept literal so behaviour\n * for tiny viewports (where half=true rounds to 0 → no-op page)\n * matches what shipped before centralisation.\n */\nfunction pageStep(viewport: number, half: boolean): number {\n return Math.floor(viewport / (half ? 2 : 1));\n}\n\n/**\n * Clamp a scrollTop offset to [0, max(0, totalLines - viewport)] so\n * the visible slice never falls past the end of the body. Pure;\n * relocated from the previous home in popups/drill.tsx so that\n * applyScroll and the DrillScrollView paint helper can share one\n * implementation.\n */\nexport function clampScrollTop(scrollTop: number, totalLines: number, viewport: number): number {\n const max = Math.max(0, totalLines - viewport);\n if (scrollTop < 0) return 0;\n if (scrollTop > max) return max;\n return scrollTop;\n}\n\n/** Clamp a cursor index to [0, max(0, total - 1)]. */\nfunction clampCursor(cursor: number, total: number): number {\n const last = Math.max(0, total - 1);\n if (cursor < 0) return 0;\n if (cursor > last) return last;\n return cursor;\n}\n\n/**\n * Apply a navigation action to a cursor-based view. Returns the new\n * cursor index, clamped to [0, total-1] (or 0 when total === 0).\n *\n * cursor current cursor index\n * action one of the six NavAction kinds\n * total length of the underlying collection (rows / items)\n * viewport visible row count — used only for page-step semantics\n */\nexport function applyCursor(\n cursor: number,\n action: NavAction,\n total: number,\n viewport: number,\n): number {\n const last = Math.max(0, total - 1);\n switch (action.kind) {\n case \"moveUp\":\n return Math.max(0, cursor - 1);\n case \"moveDown\":\n return Math.min(last, cursor + 1);\n case \"jumpTop\":\n return 0;\n case \"jumpBottom\":\n return last;\n case \"pageDown\":\n return clampCursor(cursor + pageStep(viewport, action.half), total);\n case \"pageUp\":\n return clampCursor(cursor - pageStep(viewport, action.half), total);\n }\n}\n\n/**\n * Resolve a double-clicked popup body row (PopupAction `clickRow`) to\n * the item it shows. The popup passes the SAME list, cursor and\n * viewport it renders with, so the scroll window matches the screen.\n * Returns null when the click missed the data rows.\n *\n * bodyRow 0-based row inside the popup's top border\n * headerRows in-body rows rendered above the data window (filter /\n * sort strips, a drill title line)\n */\nexport function clickedItem<T>(\n items: readonly T[],\n cursor: number,\n viewport: number,\n bodyRow: number,\n headerRows = 0,\n): { index: number; item: T } | null {\n const { start, visible } = centredVisibleSlice(items, cursor, viewport);\n const offset = bodyRow - headerRows;\n if (offset < 0 || offset >= visible.length) return null;\n const index = start + offset;\n const item = items[index];\n return item === undefined ? null : { index, item };\n}\n\n/**\n * Compute the visible slice of `items` that centres `cursor` in a\n * `viewport`-sized window. Returns the start index AND the sliced\n * array, so callers don't repeat the `.slice(start, start +\n * viewport)` step.\n *\n * Per review_dedup_drill_centring_visible_slice: three drill views\n * (log events list, tracks task-list, workspaces commits-since-fork)\n * had the IDENTICAL inline `Math.max(0, Math.min(items.length -\n * viewport, cursor - Math.floor(viewport/2)))` formula. Sibling\n * helpers (applyCursor / applyScroll) own the cursor-update math\n * but NOT the visible-slice math, so the formula was drifting\n * between popups (`Math.floor` vs `Math.ceil`, half-window vs\n * explicit). One source of truth here, three callers collapse to\n * one line each.\n *\n * Boundary semantics (kept identical to the prior inline formula):\n * - empty items → start=0, visible=[]\n * - items.length <= viewport → start=0, visible=items.slice()\n * - cursor near top → start clamps to 0\n * - cursor near bottom → start clamps to items.length - viewport\n * - else → start = cursor - floor(viewport/2)\n *\n * The viewport must be > 0; a viewport of 0 (no rows visible)\n * yields start=0 and visible=[].\n */\nexport function centredVisibleSlice<T>(\n items: readonly T[],\n cursor: number,\n viewport: number,\n): { start: number; visible: T[] } {\n if (viewport <= 0 || items.length === 0) return { start: 0, visible: [] };\n const start = Math.max(0, Math.min(items.length - viewport, cursor - Math.floor(viewport / 2)));\n return { start, visible: items.slice(start, start + viewport) };\n}\n\n/**\n * Apply a navigation action to a scrollTop-based view (e.g.\n * DrillScrollView). Returns the new scrollTop, clamped via\n * clampScrollTop so the bottom of the body never scrolls past the\n * viewport.\n *\n * scrollTop current top-of-viewport line index\n * action one of the six NavAction kinds\n * totalLines length of the underlying body in lines\n * viewport visible line count\n */\nexport function applyScroll(\n scrollTop: number,\n action: NavAction,\n totalLines: number,\n viewport: number,\n): number {\n switch (action.kind) {\n case \"moveUp\":\n return clampScrollTop(scrollTop - 1, totalLines, viewport);\n case \"moveDown\":\n return clampScrollTop(scrollTop + 1, totalLines, viewport);\n case \"jumpTop\":\n return 0;\n case \"jumpBottom\":\n return clampScrollTop(totalLines, totalLines, viewport);\n case \"pageDown\":\n return clampScrollTop(scrollTop + pageStep(viewport, action.half), totalLines, viewport);\n case \"pageUp\":\n return clampScrollTop(scrollTop - pageStep(viewport, action.half), totalLines, viewport);\n }\n}\n","import { useEffect, useRef } from \"react\";\nimport { MOUSE_MODE_ENTER, MOUSE_MODE_EXIT } from \"./escapes.js\";\n\nexport const DOUBLE_CLICK_MS = 300;\n\nexport type MouseButton = 0 | 1 | 2 | number;\n\nexport interface MouseBaseEvent {\n x: number;\n y: number;\n button: MouseButton;\n ts: number;\n}\n\nexport interface MousePressEvent extends MouseBaseEvent {\n kind: \"press\";\n}\n\nexport interface MouseReleaseEvent extends MouseBaseEvent {\n kind: \"release\";\n}\n\nexport interface MouseScrollEvent extends MouseBaseEvent {\n kind: \"scroll\";\n direction: \"up\" | \"down\";\n}\n\nexport interface MouseDoubleClickEvent extends MouseBaseEvent {\n kind: \"doubleclick\";\n}\n\nexport type ParsedMouseEvent = MousePressEvent | MouseReleaseEvent | MouseScrollEvent;\nexport type MouseEvent = ParsedMouseEvent | MouseDoubleClickEvent;\n\nexport type MouseSubscriber = (event: MouseEvent) => void;\n\ntype MouseReportSubscriber = (event: ParsedMouseEvent) => void;\n\nconst subscribers = new Set<MouseReportSubscriber>();\nconst SGR_MOUSE_PATTERN = \"\\\\u001b\\\\[<(\\\\d+);(\\\\d+);(\\\\d+)([Mm])\";\nlet stdinAttached = false;\nlet pending = \"\";\n\nexport function enableMouseMode(): void {\n process.stdout.write(MOUSE_MODE_ENTER);\n}\n\nexport function disableMouseMode(): void {\n process.stdout.write(MOUSE_MODE_EXIT);\n}\n\nexport function parseSgrMouseEvents(\n input: string,\n now: () => number = Date.now,\n): ParsedMouseEvent[] {\n const events: ParsedMouseEvent[] = [];\n const re = new RegExp(SGR_MOUSE_PATTERN, \"g\");\n let match = re.exec(input);\n while (match !== null) {\n const codeText = match[1];\n const xText = match[2];\n const yText = match[3];\n const suffix = match[4];\n if (\n codeText === undefined ||\n xText === undefined ||\n yText === undefined ||\n suffix === undefined\n ) {\n match = re.exec(input);\n continue;\n }\n const code = Number.parseInt(codeText, 10);\n const x = Number.parseInt(xText, 10);\n const y = Number.parseInt(yText, 10);\n if (!Number.isFinite(code) || !Number.isFinite(x) || !Number.isFinite(y)) {\n match = re.exec(input);\n continue;\n }\n\n const ts = now();\n if (suffix === \"M\" && (code === 64 || code === 65)) {\n events.push({\n kind: \"scroll\",\n direction: code === 64 ? \"up\" : \"down\",\n x,\n y,\n button: code,\n ts,\n });\n match = re.exec(input);\n continue;\n }\n\n const button = code & 3;\n if (suffix === \"m\") {\n events.push({ kind: \"release\", x, y, button, ts });\n } else {\n events.push({ kind: \"press\", x, y, button, ts });\n }\n match = re.exec(input);\n }\n return events;\n}\n\nexport interface DoubleClickDetectorOptions {\n windowMs?: number;\n}\n\nexport interface DoubleClickDetector {\n push: (event: ParsedMouseEvent) => MouseEvent[];\n}\n\nexport function createDoubleClickDetector(\n opts: DoubleClickDetectorOptions = {},\n): DoubleClickDetector {\n const windowMs = opts.windowMs ?? DOUBLE_CLICK_MS;\n let lastPress: MousePressEvent | null = null;\n return {\n push(event) {\n if (event.kind !== \"press\") return [event];\n const previous = lastPress;\n lastPress = event;\n if (\n previous !== null &&\n event.ts - previous.ts <= windowMs &&\n event.x === previous.x &&\n event.y === previous.y &&\n event.button === previous.button\n ) {\n return [\n event,\n { kind: \"doubleclick\", x: event.x, y: event.y, button: event.button, ts: event.ts },\n ];\n }\n return [event];\n },\n };\n}\n\nexport function useMouse(\n onEvent: MouseSubscriber,\n opts: { isActive?: boolean; doubleClickMs?: number } = {},\n): void {\n const callback = useRef(onEvent);\n callback.current = onEvent;\n const detector = useRef(createDoubleClickDetector({ windowMs: opts.doubleClickMs }));\n\n useEffect(() => {\n detector.current = createDoubleClickDetector({ windowMs: opts.doubleClickMs });\n }, [opts.doubleClickMs]);\n\n useEffect(() => {\n if (opts.isActive === false) return undefined;\n return subscribeToMouseReports((event) => {\n for (const emitted of detector.current.push(event)) {\n callback.current(emitted);\n }\n });\n }, [opts.isActive]);\n}\n\nexport function mouseEventToNavAction(\n event: MouseEvent,\n): { kind: \"moveUp\" } | { kind: \"moveDown\" } | null {\n if (event.kind !== \"scroll\") return null;\n return event.direction === \"up\" ? { kind: \"moveUp\" } : { kind: \"moveDown\" };\n}\n\nfunction subscribeToMouseReports(fn: MouseReportSubscriber): () => void {\n subscribers.add(fn);\n attachStdin();\n return () => {\n subscribers.delete(fn);\n if (subscribers.size === 0) detachStdin();\n };\n}\n\nfunction attachStdin(): void {\n if (stdinAttached) return;\n process.stdin.on(\"data\", onStdinData);\n stdinAttached = true;\n}\n\nfunction detachStdin(): void {\n if (!stdinAttached) return;\n process.stdin.off(\"data\", onStdinData);\n stdinAttached = false;\n pending = \"\";\n}\n\nfunction onStdinData(chunk: Buffer | string): void {\n pending += typeof chunk === \"string\" ? chunk : chunk.toString(\"utf8\");\n const parsed: ParsedMouseEvent[] = [];\n const re = new RegExp(SGR_MOUSE_PATTERN, \"g\");\n let lastEnd = 0;\n let match = re.exec(pending);\n while (match !== null) {\n const report = match[0];\n lastEnd = re.lastIndex;\n parsed.push(...parseSgrMouseEvents(report));\n match = re.exec(pending);\n }\n if (lastEnd > 0) {\n pending = pending.slice(lastEnd);\n } else {\n const lastEscape = pending.lastIndexOf(\"\\x1b[<\");\n pending = lastEscape >= 0 ? pending.slice(lastEscape) : \"\";\n }\n for (const event of parsed) {\n for (const subscriber of subscribers) subscriber(event);\n }\n}\n","// Pure escape-sequence constants for the TUI. Lives in src/cli/tui/ but\n// imports neither ink nor react so unit tests can assert exact bytes\n// without booting an ink renderer.\n//\n// On enter:\n// \\x1b[?1049h swap to alt-screen buffer\n// \\x1b[2J clear entire screen (else stale shell text bleeds through\n// ink's diff renderer until ink overwrites it)\n// \\x1b[H home cursor to row 1, col 1 (alt-screen swap inherits the\n// cursor row from the prior buffer on most terminals —\n// iTerm2, Apple Terminal, tmux's inner terminal, ...)\n// \\x1b[?25l hide cursor (lazygit/btop convention; otherwise the\n// blinking cursor sits behind the rendered cards)\n//\n// On exit, mirror in reverse: show cursor, then restore the prior buffer.\nexport const ALT_SCREEN_ENTER = \"\\x1b[?1049h\\x1b[2J\\x1b[H\\x1b[?25l\";\nexport const ALT_SCREEN_EXIT = \"\\x1b[?25h\\x1b[?1049l\";\n\n// Mouse mode uses normal tracking + button-motion + SGR extended\n// coordinates. SGR reports arrive as ESC [ < button ; x ; y ; M/m.\n// Disable in the exact reverse order during TUI teardown so native\n// terminal selection works again after exit.\nexport const MOUSE_MODE_ENTER = \"\\x1b[?1000h\\x1b[?1002h\\x1b[?1006h\";\nexport const MOUSE_MODE_EXIT = \"\\x1b[?1006l\\x1b[?1002l\\x1b[?1000l\";\n","// Keyboard gate for popups.\n//\n// <App> keeps the open popup MOUNTED (display=\"none\") while the `?`\n// help overlay covers it, so popup-local state (cursor, filter query,\n// drill pin, drill scroll) survives a help round trip. A hidden popup\n// must not react to keys meant for the overlay, so every popup reads\n// its keyboard through `usePopupInput`, which turns ink's `useInput`\n// off while the App says the popup is covered.\n\nimport { useInput } from \"ink\";\nimport { createContext, useContext } from \"react\";\n\n/** False while the help overlay covers the open popup. */\nexport const PopupInputActive = createContext(true);\n\ntype InputHandler = Parameters<typeof useInput>[0];\n\nexport function usePopupInput(handler: InputHandler): void {\n const isActive = useContext(PopupInputActive);\n useInput(handler, { isActive });\n}\n","// Agents popup (Shift+1 → `!`). Drill-down for the Agents card.\n//\n// Per design_popup_agents (workstream `tui`): list of agents with\n// per-agent yank intents (free / close / send).\n//\n// Enter on a row drills into a read-only inline scrollback view —\n// equivalent to `mu agent read <name> -n 80` rendered as plain text\n// with j/k scroll. Esc / q in drill mode returns to the list; a\n// second Esc / q closes the popup back to the dashboard.\n//\n// Read-only: drilling never executes anything; we only call\n// readAgent which is a tmux capture-pane wrapper. The yank verbs\n// (f / x / y) still emit `mu` command strings the user must paste\n// to actually run.\n//\n// Rows are column-aligned via src/cli/tui/columns.ts. Per\n// feat_column_aligned_lists clipping policy: glyph, agent name,\n// status are PROTECTED; the role description is CLIPPABLE.\n\nimport { Box, Text } from \"ink\";\nimport { type ReactElement, useCallback, useEffect, useRef, useState } from \"react\";\nimport { type LiveAgent, readAgent } from \"../../../agents.js\";\nimport type { Db } from \"../../../db.js\";\nimport type { WorkstreamSnapshot } from \"../../../state.js\";\nimport { agentStateGlyph } from \"../agent-display.js\";\nimport { type ColumnSpec, contentWidthFromCols, layoutColumns, renderRow } from \"../columns.js\";\nimport { dispatchPopupKeyFromInk, type PopupAction, type PopupActionEnvelope } from \"../keys.js\";\nimport { ListRow } from \"../list-row.js\";\nimport { usePopupInput } from \"../popup-input.js\";\nimport { PopupShell } from \"../popup-shell.js\";\nimport { resolveAttachCommands, runTmuxAttachInteractive } from \"../tmux-attach.js\";\nimport { usePopupActionQueue } from \"../use-popup-action-queue.js\";\nimport { applyFilter, FilterPrompt, listViewport, usePopupFilter } from \"../use-popup-filter.js\";\nimport { useTerminalSize } from \"../use-terminal-size.js\";\nimport { DrillScrollView, useDrillKeymap } from \"./drill.js\";\nimport { applyCursor, centredVisibleSlice, clickedItem, isNavAction } from \"./scroll.js\";\nimport { POPUP_DRILL_CHROME_ROWS, usePopupViewport } from \"./viewport.js\";\n\nexport interface PopupProps {\n yank: (command: string) => Promise<void>;\n onClose: () => void;\n snapshot: WorkstreamSnapshot | null;\n slowTickNonce: number;\n mode: \"list\" | \"drill\";\n onModeChange: (mode: \"list\" | \"drill\") => void;\n /** Bubbles the filter-prompt edit state up to <App> for StatusBar mode. */\n onFilterEditingChange?: (editing: boolean) => void;\n popupActions?: readonly PopupActionEnvelope[];\n /** Surface tmux-attach success/error in the footer status bar.\n * Optional so existing callers / tests stay valid. */\n onFooter?: (command: string, copied: boolean, tone?: \"normal\" | \"info\" | \"error\") => void;\n db: Db;\n workstream: string;\n}\n\nconst AGENT_COLORS = [\n undefined, // glyph (plain)\n { bold: true }, // name\n { dimColor: true }, // status\n { dimColor: true }, // role\n] as const;\n\nconst COLUMN_SPECS: ReadonlyArray<ColumnSpec> = [\n { kind: \"protect\" }, // glyph\n { kind: \"protect\" }, // agent name\n { kind: \"protect\" }, // status token\n { kind: \"clip\", min: 1 }, // role\n];\n\nconst SCROLLBACK_LINES = 80;\n\nexport function AgentsPopup({\n yank,\n onClose,\n snapshot,\n slowTickNonce,\n mode,\n onModeChange,\n onFilterEditingChange,\n popupActions,\n onFooter,\n db,\n workstream,\n}: PopupProps): ReactElement {\n const { cols } = useTerminalSize();\n const contentWidth = contentWidthFromCols(cols);\n // Per-render viewport from stdout.rows minus the popup chrome budget;\n // see popups/viewport.ts. Replaces the prior hardcoded VIEWPORT = 20.\n const viewport = usePopupViewport();\n const [cursor, setCursor] = useState(0);\n const [scrollback, setScrollback] = useState<string>(\"\");\n const [scrollbackErr, setScrollbackErr] = useState<string | null>(null);\n const [loading, setLoading] = useState(false);\n const flt = usePopupFilter({ onEditingChange: onFilterEditingChange });\n const rowsViewport = listViewport(viewport, flt);\n const drillViewport = usePopupViewport(POPUP_DRILL_CHROME_ROWS);\n // Per bug_filter_drill_opens_wrong_task: text filter applied\n // UNIFORMLY across list and drill modes (the previous mode-conditional\n // dropped the filter on drill, shifting `agents` under a constant\n // cursor index).\n const sourceAgents = snapshot?.view.agents ?? [];\n const agents = applyFilter(\n sourceAgents,\n flt.query,\n (a) => `${a.name} ${a.state} ${a.cli} ${a.role}`,\n );\n const safeCursor = agents.length === 0 ? 0 : Math.min(cursor, agents.length - 1);\n const focused = agents[safeCursor];\n // Defensive: capture focused agent identity at Enter so the drill\n // stays pinned to the agent the user visually selected even if the\n // list shifts underneath us.\n const [drilledAgent, setDrilledAgent] = useState<LiveAgent | null>(null);\n const drillAgent = mode === \"drill\" ? (drilledAgent ?? focused) : focused;\n const lastFocusedAgentName = useRef<string | null>(null);\n // Load scrollback when entering drill mode (or when the focused\n // row changes while in drill mode). Read-only: capturePane is a\n // tmux read, never a write.\n const loadScrollback = useCallback(\n async (paneAgent: string) => {\n setLoading(true);\n setScrollbackErr(null);\n // Keep the previous scrollback visible during the slow-tick\n // refetch; clearing here causes a blank-flash flicker.\n try {\n const text = await readAgent(db, paneAgent, {\n workstream,\n lines: SCROLLBACK_LINES,\n });\n setScrollback(text);\n } catch (e) {\n setScrollbackErr(e instanceof Error ? e.message : String(e));\n setScrollback(\"\");\n } finally {\n setLoading(false);\n }\n },\n [db, workstream],\n );\n\n useEffect(() => {\n void slowTickNonce;\n if (mode === \"drill\" && drillAgent) {\n if (lastFocusedAgentName.current !== drillAgent.name) {\n setScrollback(\"\");\n setScrollbackErr(null);\n }\n lastFocusedAgentName.current = drillAgent.name;\n void loadScrollback(drillAgent.name);\n }\n }, [mode, drillAgent, loadScrollback, slowTickNonce]);\n\n useEffect(() => {\n if (mode !== \"drill\") {\n lastFocusedAgentName.current = null;\n setScrollback(\"\");\n setScrollbackErr(null);\n setLoading(false);\n }\n }, [mode]);\n\n const drillBody = scrollbackErr !== null ? `error: ${scrollbackErr}` : scrollback;\n const drill = useDrillKeymap({\n body: drillBody,\n viewport: drillViewport,\n onClose: () => {\n setDrilledAgent(null);\n onModeChange(\"list\");\n },\n onYank: () => {\n if (!drillAgent || !snapshot) return;\n return yank(\n `mu agent read ${drillAgent.name} -n ${SCROLLBACK_LINES} -w ${snapshot.workstreamName}`,\n );\n },\n resetKey: drillAgent?.name ?? \"\",\n });\n\n const dispatchListAction = (action: PopupAction) => {\n if (mode === \"drill\") {\n drill.dispatch(action);\n return;\n }\n if (isNavAction(action)) {\n setCursor((c) => applyCursor(c, action, agents.length, rowsViewport));\n return;\n }\n switch (action.kind) {\n case \"close\":\n onClose();\n return;\n case \"filter\":\n flt.startEdit();\n return;\n case \"drill\":\n if (focused) {\n setDrilledAgent(focused);\n onModeChange(\"drill\");\n }\n return;\n case \"clickRow\": {\n const hit = clickedItem(agents, safeCursor, rowsViewport, action.row);\n if (!hit) return;\n setCursor(hit.index);\n setDrilledAgent(hit.item);\n onModeChange(\"drill\");\n return;\n }\n case \"yank\": {\n const a = agents[safeCursor];\n if (!a || !snapshot) return;\n const ws = snapshot.workstreamName;\n // Default yank: a `mu agent send` template the user can edit.\n // The popup-verb key x covers close.\n void yank(`mu agent send ${a.name} '...' -w ${ws}`);\n return;\n }\n case \"verb\": {\n const a = agents[safeCursor];\n if (!a || !snapshot) return;\n const ws = snapshot.workstreamName;\n if (action.key === \"x\") {\n void yank(`mu agent close ${a.name} -w ${ws}`);\n return;\n }\n if (action.key === \"a\") {\n // Per-popup TUI escape: hand off to the multiplexer to put\n // the user on the agent's pane. Mirrors `t tuicr` /\n // `l lazygit`. Read-only-by-design TUI is preserved — we\n // don't mutate state, we just let the user look at /\n // interact with the pane until they navigate back.\n const session = `mu-${ws}`;\n const window = a.tab ?? a.name;\n void resolveAttachCommands({ session, window }).then((commands) => {\n const r = runTmuxAttachInteractive({ commands });\n if (!r.ok) onFooter?.(r.error ?? \"attach failed\", false, \"error\");\n else onFooter?.(`attach → ${session}:${window}`, true, \"info\");\n });\n return;\n }\n return;\n }\n }\n };\n\n usePopupActionQueue(popupActions, dispatchListAction);\n\n usePopupInput((input, key) => {\n // Filter-mode keystrokes (when the prompt is editing) consume\n // every printable + Esc/Enter/Bksp; the popup's own dispatchPopupKey\n // is bypassed for the duration of the edit.\n if (mode !== \"drill\" && flt.onKey(input, key) === \"consumed\") return;\n dispatchListAction(dispatchPopupKeyFromInk(input, key));\n });\n\n if (snapshot === null) {\n return <PopupShell title=\"Agents · popup\">{<Text dimColor>loading…</Text>}</PopupShell>;\n }\n if (sourceAgents.length === 0) {\n return (\n <PopupShell title=\"Agents · popup\">\n <Text dimColor>(no agents)</Text>\n </PopupShell>\n );\n }\n if (agents.length === 0) {\n return (\n <PopupShell title=\"Agents · popup\">\n <Box flexDirection=\"column\" flexGrow={1}>\n <Text dimColor>(no matches for \"{flt.query}\")</Text>\n </Box>\n <FilterPrompt state={flt} />\n </PopupShell>\n );\n }\n\n if (mode === \"drill\" && drillAgent) {\n return (\n <PopupShell title={`Agents · ${drillAgent.name} (scrollback)`}>\n <Box flexDirection=\"column\" flexGrow={1}>\n <DrillScrollView\n title={`mu agent read ${drillAgent.name} -n ${SCROLLBACK_LINES}`}\n body={drillBody}\n viewport={drillViewport}\n scrollTop={drill.scrollTop}\n wrappedBody={drill.wrappedBody}\n hint={`y yanks \\`mu agent read -n ${SCROLLBACK_LINES}\\``}\n emptyText={loading ? \"loading…\" : \"(no scrollback yet)\"}\n />\n </Box>\n </PopupShell>\n );\n }\n\n const { start, visible } = centredVisibleSlice(agents, safeCursor, rowsViewport);\n const rows = visible.map((a) => [agentStateGlyph(a.state), a.name, a.state, a.role]);\n const widths = layoutColumns(rows, COLUMN_SPECS, contentWidth);\n\n return (\n <PopupShell\n title={`Agents · popup (${safeCursor + 1}/${agents.length})`}\n hint=\"a attach · x close · y yanks `mu agent send`\"\n >\n <Box flexDirection=\"column\" flexGrow={1}>\n {visible.map((a, i) => {\n const sel = start + i === safeCursor;\n const row = rows[i];\n if (row === undefined) return null;\n const padded = renderRow(row, widths, COLUMN_SPECS);\n return (\n <ListRow\n key={a.name}\n cells={padded}\n contentWidth={contentWidth}\n colors={AGENT_COLORS}\n selected={sel}\n />\n );\n })}\n </Box>\n <FilterPrompt state={flt} />\n </PopupShell>\n );\n}\n","import type { ReactElement, ReactNode } from \"react\";\nimport { TitledBox } from \"./titled-box.js\";\n\nexport interface PopupShellProps {\n title: string;\n /** Per-popup hint inset into the bottom border. Null / undefined suppresses it. */\n hint?: string | null;\n children: ReactNode;\n}\n\nexport function PopupShell({ title, hint, children }: PopupShellProps): ReactElement {\n return (\n <TitledBox\n title={title}\n borderColor=\"cyan\"\n titleColor=\"cyan\"\n bottomLabel={hint ?? undefined}\n flexGrow={1}\n >\n {children}\n </TitledBox>\n );\n}\n","// Drop into a managed agent's pane from inside the TUI.\n//\n// Mirrors the `tuicr.ts` / `lazygit.ts` per-popup escape-hatch\n// pattern: leave the alt screen, hand the terminal to the multiplexer,\n// restore the alt screen on return. Bound to `a` in the Agents popup\n// (counterpart to per-revision `t tuicr` and per-cwd `l lazygit`).\n//\n// Mechanics live in the BACKEND, not here. `attachCommands()` returns\n// the argv steps for the active mux; this module only runs them with\n// stdio inherited (so any password / prompt / confirmation reaches the\n// user) and bookends them with the alt-screen dance. On tmux that is\n// `switch-client` when the caller is already inside a client and\n// `attach-session` + `select-window` otherwise, but this file does not\n// know that and must not.\n//\n// Returning to the orchestrator: the user navigates back to the\n// originating window themselves (Ctrl-B p, Ctrl-B <window>, etc.).\n// We do NOT auto-restore — the alt-screen restore happens when the\n// user re-runs `mu` or just hits whatever brings them back. This\n// matches `tuicr` / `lazygit` semantics: the escape is one-way until\n// the user explicitly comes back.\n//\n// In practice for the in-mux case (the common path): switch-client\n// returns immediately after pointing the client at the new\n// session:window, so the alt-screen restore fires almost instantly\n// and the user is now looking at the worker pane in the same client.\n// The mu TUI is still running in its original window — switching\n// back via Ctrl-B p brings it into view, alt-screen still active.\n\nimport { spawnSync } from \"node:child_process\";\nimport { activeMux, type MuxCommand } from \"../../mux.js\";\nimport { ALT_SCREEN_ENTER, ALT_SCREEN_EXIT } from \"./escapes.js\";\n\nexport interface RunTmuxAttachOptions {\n /** Mux session name, e.g. `mu-multimachine`. */\n session: string;\n /** Window name or index inside the session (the agent's `tab`\n * field, or its `name` if `tab` is null). */\n window: string;\n}\n\ninterface SpawnSyncResult {\n status: number | null;\n error?: Error;\n}\n\ntype SpawnSyncFn = (\n command: string,\n args: readonly string[],\n options: { stdio: \"inherit\"; env: NodeJS.ProcessEnv },\n) => SpawnSyncResult;\n\nexport interface RunTmuxAttachDeps {\n spawn?: SpawnSyncFn;\n write?: (text: string) => void;\n env?: NodeJS.ProcessEnv;\n /** Pre-resolved attach steps. Tests inject these to stay off a real\n * mux; production resolves them from `activeMux()`. */\n commands?: readonly MuxCommand[];\n}\n\nexport interface RunTmuxAttachResult {\n ok: boolean;\n error?: string;\n}\n\n/**\n * Resolve the attach steps for `opts` from the active backend.\n *\n * Best-effort by design: the TUI's `a` key is an escape hatch, not a\n * verb. With no reachable mux the caller gets an error string in the\n * footer instead of a crashed TUI.\n */\nexport async function resolveAttachCommands(\n opts: RunTmuxAttachOptions,\n env: NodeJS.ProcessEnv = process.env,\n): Promise<readonly MuxCommand[] | undefined> {\n try {\n const mux = await activeMux();\n // `inside` is a tmux-shaped question (\"are we in a client of this\n // mux?\"), but the ANSWER is the backend's business — we just report\n // the ambient evidence we have.\n const inside = typeof env.TMUX === \"string\" && env.TMUX.length > 0;\n return await mux.attachCommands({ session: opts.session, window: opts.window, inside });\n } catch {\n return undefined;\n }\n}\n\n/**\n * Run pre-resolved attach steps with the alt screen bookended around\n * them. Takes STEPS rather than a target because the backend owns the\n * argv and resolving it is async, while ink's key handler is not.\n */\nexport function runTmuxAttachInteractive(deps: RunTmuxAttachDeps = {}): RunTmuxAttachResult {\n const run = deps.spawn ?? (spawnSync as SpawnSyncFn);\n const write = deps.write ?? ((text: string) => process.stdout.write(text));\n const env = deps.env ?? process.env;\n const commands = deps.commands;\n if (commands === undefined || commands.length === 0) {\n return { ok: false, error: \"no multiplexer available to attach with\" };\n }\n let result: RunTmuxAttachResult = { ok: true };\n\n try {\n write(ALT_SCREEN_EXIT);\n for (const step of commands) {\n const r = run(step.command, step.args, { stdio: \"inherit\", env });\n if (step.optional === true) continue;\n if (r.error !== undefined) {\n result = { ok: false, error: tmuxAttachErrorMessage(r.error) };\n break;\n }\n if (typeof r.status === \"number\" && r.status !== 0) {\n result = {\n ok: false,\n error: `${step.command} ${step.args[0] ?? \"\"} exited ${r.status}`.trim(),\n };\n break;\n }\n }\n } catch (err) {\n result = { ok: false, error: tmuxAttachErrorMessage(err) };\n } finally {\n try {\n write(ALT_SCREEN_ENTER);\n } catch {\n // Best-effort terminal repair only. Preserve the original result.\n }\n }\n\n return result;\n}\n\nexport function tmuxAttachErrorMessage(err: unknown): string {\n if (err instanceof Error) {\n const code = (err as NodeJS.ErrnoException).code;\n if (code === \"ENOENT\") return \"multiplexer binary not found\";\n return err.message.length > 0 ? err.message : String(err);\n }\n return String(err);\n}\n","// Consume App-level PopupAction events one per render.\n//\n// App emits popup actions (today: a mouse double-click's `clickRow`)\n// as a sequenced queue. This hook dispatches only the next unseen\n// action, stores its sequence in state, and lets React render before\n// dispatching the following one, so each action sees the state the\n// previous one produced.\n\nimport { useEffect, useRef, useState } from \"react\";\nimport type { PopupAction, PopupActionEnvelope } from \"./keys.js\";\n\nexport function usePopupActionQueue(\n actions: readonly PopupActionEnvelope[] | undefined,\n dispatch: (action: PopupAction) => void,\n): void {\n const [lastSeq, setLastSeq] = useState(0);\n const dispatchRef = useRef(dispatch);\n dispatchRef.current = dispatch;\n\n useEffect(() => {\n const next = actions?.find((event) => event.seq > lastSeq);\n if (next === undefined) return;\n setLastSeq(next.seq);\n dispatchRef.current(next.action);\n }, [actions, lastSeq]);\n}\n","// Shared '/' incremental substring filter for list popups\n// (Agents/Tracks/Tasks/Log + every future card popup under\n// feat_more_cards_umbrella). Per feat_popup_search_filter\n// (workstream `tui-impl`).\n//\n// Design intent: every list popup wires this hook in ~5 LOC and\n// gets the full UX (incremental edit, Enter commit, Esc cancel,\n// status-bar mode flip, no-matches fallback) for free. New card\n// popups (Workspaces / In-progress / Blocked / Recent / Doctor)\n// MUST consume `usePopupFilter` rather than re-implement the state\n// machine — keep the substrate cheap to reuse.\n//\n// The reducer is split out as a pure function (`popupFilterReducer`)\n// so it's testable without React. The hook is a thin wrapper.\n//\n// Per ROADMAP pledge: ink/react import limited to src/cli/tui/*.\n\nimport { Box, Text } from \"ink\";\nimport { type ReactElement, useCallback, useEffect, useReducer } from \"react\";\nimport type { KeyFlags } from \"./keys.js\";\n\n/** Filter state owned by each popup. Resets on popup unmount. */\nexport interface FilterState {\n /** Current query string (case preserved for display; lower-cased for matching). */\n query: string;\n /** True while the user is typing the query; false after Enter (committed) and on cancel. */\n editing: boolean;\n}\n\nexport const INITIAL_FILTER_STATE: FilterState = { query: \"\", editing: false };\n\n/**\n * Reducer events emitted by `popupFilterOnKey`. The hook dispatches\n * these internally; tests can drive the reducer directly without\n * synthesising ink keystrokes.\n */\nexport type FilterAction =\n | { kind: \"startEdit\" }\n | { kind: \"appendChar\"; char: string }\n | { kind: \"backspace\" }\n | { kind: \"commit\" }\n | { kind: \"cancel\" }\n | { kind: \"reset\" };\n\n/** Pure reducer. */\nexport function popupFilterReducer(state: FilterState, action: FilterAction): FilterState {\n switch (action.kind) {\n case \"startEdit\":\n // Re-entering edit mode keeps the existing query (so '/' after\n // Enter pre-fills for refinement). Only flips `editing`.\n return { ...state, editing: true };\n case \"appendChar\": {\n // Printable text of any length (one keystroke, a paste, or a\n // non-ASCII glyph). Control characters are stripped; an empty\n // result is the \"consumed, no change\" sentinel.\n const text = printableText(action.char);\n if (text === \"\") return state;\n return { ...state, query: state.query + text };\n }\n case \"backspace\":\n if (state.query === \"\") return state;\n // Drop one code point, not one UTF-16 unit, so astral glyphs\n // (emoji, rare CJK) do not leave a lone surrogate behind.\n return { ...state, query: Array.from(state.query).slice(0, -1).join(\"\") };\n case \"commit\":\n // Keep query, exit edit mode. Cursor-snap is the popup's job\n // (it owns the cursor state; the filter just narrows the rows).\n return { ...state, editing: false };\n case \"cancel\":\n // Esc clears the query AND exits edit mode (full reset).\n return INITIAL_FILTER_STATE;\n case \"reset\":\n return INITIAL_FILTER_STATE;\n }\n}\n\n// C0 controls, DEL, and C1 controls. Everything else (including\n// non-ASCII letters) is filter text.\n// biome-ignore lint/suspicious/noControlCharactersInRegex: matching control chars is the point\nconst CONTROL_CHARS = /[\\u0000-\\u001f\\u007f-\\u009f]/g;\n\nfunction printableText(s: string): string {\n return s.replace(CONTROL_CHARS, \"\");\n}\n\n/**\n * Classify a keystroke for filter mode. Returns the action that the\n * reducer should consume, or `null` when the key is NOT a\n * filter-mode keystroke (and the popup should run its normal\n * dispatchPopupKey logic).\n *\n * Pure function; no React. The hook calls this then dispatches the\n * returned action.\n */\nexport function classifyFilterKey(\n state: FilterState,\n input: string,\n key: KeyFlags,\n): FilterAction | null {\n if (!state.editing) return null;\n // Esc cancels (full reset).\n if (key.escape) return { kind: \"cancel\" };\n // Enter commits.\n if (key.return) return { kind: \"commit\" };\n // Backspace pops one char (no-op if empty — reducer handles it).\n // ink reports backspace via key.backspace OR delete; many terminals\n // also send DEL (0x7f) as a literal character. Cover both.\n if (\n (key as KeyFlags & { backspace?: boolean; delete?: boolean }).backspace === true ||\n (key as KeyFlags & { backspace?: boolean; delete?: boolean }).delete === true ||\n input === \"\\x7f\" ||\n input === \"\\b\"\n ) {\n return { kind: \"backspace\" };\n }\n // Skip control / navigation keys (tab, arrows, page, function keys).\n if (\n key.tab === true ||\n key.upArrow === true ||\n key.downArrow === true ||\n key.leftArrow === true ||\n key.rightArrow === true ||\n key.pageUp === true ||\n key.pageDown === true ||\n key.f5 === true\n ) {\n // Consume so they don't navigate the underlying list while the\n // user is typing (returning null would let the popup treat them\n // as nav keys). appendChar(\"\") is the consumed-no-op sentinel:\n // the reducer leaves state unchanged.\n return { kind: \"appendChar\", char: \"\" };\n }\n // Ctrl-* combos: also consume-and-ignore. Ctrl-C is handled by ink\n // itself (exitOnCtrlC) so we don't see it here.\n if (key.ctrl === true) {\n return { kind: \"appendChar\", char: \"\" };\n }\n // Printable text. ink delivers a paste as ONE multi-character\n // `input`, and non-ASCII keys (é, 中) as one non-ASCII string, so\n // append the whole string minus control characters. Anything that\n // strips to \"\" (raw escape bytes) is consumed as a no-op so the\n // underlying popup never sees it mid-edit.\n return { kind: \"appendChar\", char: printableText(input) };\n}\n\n/**\n * Filter hook for list popups. Returns the current state plus a\n * keystroke handler the popup wires into its `useInput` callback.\n *\n * const flt = usePopupFilter();\n * useInput((input, key) => {\n * if (flt.onKey(input, key) === \"consumed\") return;\n * // ...existing dispatchPopupKey switch...\n * if (action.kind === \"filter\") { flt.startEdit(); return; }\n * });\n */\nexport interface PopupFilter {\n /** Current query (case preserved; empty = \"no filter\"). */\n query: string;\n /** True while editing (caret rendered; Enter to commit). */\n editing: boolean;\n /**\n * Handle a keystroke. Returns \"consumed\" when the key was a\n * filter-mode keystroke (caller should NOT run its own\n * dispatchPopupKey logic). Returns \"passthrough\" otherwise.\n */\n onKey(input: string, key: KeyFlags): \"consumed\" | \"passthrough\";\n /** Enter edit mode (call from the dispatchPopupKey \"filter\" branch). */\n startEdit(): void;\n /** Clear query + exit edit mode. */\n reset(): void;\n}\n\n/**\n * Optional hook options. Per review_dedup_filter_editing_effect:\n * eight list popups had the IDENTICAL `useEffect(() =>\n * onFilterEditingChange?.(flt.editing), [flt.editing,\n * onFilterEditingChange])` block immediately after `const flt =\n * usePopupFilter()`. Baking the bubble-up into the hook itself\n * collapses each call site by 3 lines and means the next popup\n * author can't forget to wire the StatusBar mode flip.\n *\n * `onEditingChange` is a callback the popup wires to its parent\n * `<App>`'s `setPopupFilterEditing`. Called WHENEVER the editing\n * flag changes (and once on mount when the initial value differs\n * from undefined-default). When omitted, the hook is silent.\n *\n * `enabled` (default true) lets popups with MULTIPLE filter\n * instances (e.g. workspaces.tsx — list view + commits drill view)\n * mark which instance is currently active. A disabled instance\n * always bubbles `false` regardless of its own `state.editing`, so\n * the StatusBar mode flip stays consistent across sub-modes\n * without hand-rolling a conditional useEffect at the call site.\n * Per review_tui_workspaces_two_filter_instances.\n */\nexport interface UsePopupFilterOpts {\n onEditingChange?: (editing: boolean) => void;\n enabled?: boolean;\n}\n\nexport function usePopupFilter(opts: UsePopupFilterOpts = {}): PopupFilter {\n const [state, dispatch] = useReducer(popupFilterReducer, INITIAL_FILTER_STATE);\n const { onEditingChange, enabled } = opts;\n const onKey = useCallback(\n (input: string, key: KeyFlags): \"consumed\" | \"passthrough\" => {\n const action = classifyFilterKey(state, input, key);\n if (action === null) return \"passthrough\";\n dispatch(action);\n return \"consumed\";\n },\n [state],\n );\n const startEdit = useCallback(() => dispatch({ kind: \"startEdit\" }), []);\n const reset = useCallback(() => dispatch({ kind: \"reset\" }), []);\n // Bubble the editing flag up to the parent (StatusBar uses it to\n // flip its hint cluster into popup-filter mode). No-op when the\n // caller doesn't pass a callback. When `enabled === false`, bubble\n // `false` regardless of state.editing so popups with multiple\n // filter instances can declaratively mark which one is active\n // (per review_tui_workspaces_two_filter_instances).\n const bubbledEditing = enabled === false ? false : state.editing;\n useEffect(() => {\n onEditingChange?.(bubbledEditing);\n }, [bubbledEditing, onEditingChange]);\n return { query: state.query, editing: state.editing, onKey, startEdit, reset };\n}\n\n/**\n * Apply a filter query to a list of items. Case-insensitive\n * substring on the per-item \"search blob\" string returned by\n * `blobOf`. Empty query → original list (identity).\n *\n * Pure; no React. New card popups call this directly:\n *\n * const filtered = applyFilter(source, flt.query, (e) => `${e.name} ${e.label}`);\n */\nexport function applyFilter<T>(\n items: readonly T[],\n query: string,\n blobOf: (item: T) => string,\n): T[] {\n if (query === \"\") return [...items];\n const q = query.toLowerCase();\n const out: T[] = [];\n for (const item of items) {\n if (blobOf(item).toLowerCase().includes(q)) out.push(item);\n }\n return out;\n}\n\n/** Body rows `<FilterPrompt>` occupies: its 1-row top margin plus the\n * prompt line while visible, 0 while idle. List popups subtract this\n * from their row viewport so the prompt never pushes the popup past\n * the pane (the App's overflow clip would eat the top border). */\nexport const FILTER_PROMPT_ROWS = 2;\n\nexport function filterPromptRows(state: Pick<PopupFilter, \"query\" | \"editing\">): number {\n return state.query === \"\" && !state.editing ? 0 : FILTER_PROMPT_ROWS;\n}\n\n/** Row viewport for a list that renders `<FilterPrompt state={flt} />`\n * below it. Never below 1 so the cursor row stays visible. */\nexport function listViewport(\n viewport: number,\n state: Pick<PopupFilter, \"query\" | \"editing\">,\n): number {\n return Math.max(1, viewport - filterPromptRows(state));\n}\n\n/**\n * Bottom-of-popup prompt. Renders nothing while idle (no query AND\n * not editing); renders `/<query>_` while editing; renders\n * `[filter] <query>` after Enter (committed). The trailing `_` is a\n * literal character used as a \"cursor\" — ink doesn't expose a real\n * text-input cursor without ink-text-input which we are NOT adding\n * (anti-feature pledge).\n */\nexport function FilterPrompt({ state }: { state: PopupFilter }): ReactElement | null {\n // Keep in sync with FILTER_PROMPT_ROWS (marginTop + one text row).\n if (filterPromptRows(state) === 0) return null;\n return (\n <Box marginTop={1}>\n <Text color={state.editing ? \"yellow\" : \"gray\"}>\n {state.editing ? \"/\" : \"[filter] \"}\n {state.query}\n {state.editing ? \"_\" : \"\"}\n </Text>\n </Box>\n );\n}\n","// Shared \"drill detail\" sub-view for popups. Renders a titled\n// scrollable block of pre-formatted text inside a popup body. Used\n// by:\n// - popups/agents.tsx → agent pane scrollback (mu agent read)\n// - popups/ready.tsx → task notes (mu task notes)\n// - popups/tracks.tsx → task list belonging to a track (already\n// a list, not a scrollback — uses ScrollList instead)\n//\n// The drill itself is read-only: it renders text, never executes\n// anything. j/k scroll one line; Ctrl-D / Ctrl-U scroll a viewport\n// half. Esc / q is the popup's responsibility (we only render).\n//\n// CHROME INSETS INTO THE BORDERS\n// (nit_tui_drill_inset_title_and_hints, Layer 2)\n//\n// Pre-Layer-2 the drill rendered its own title row (\"▸ {title}\n// (1-72/311)\") and an optional hint line as ORDINARY BODY ROWS\n// nested inside the popup Shell's rounded box — two rows of chrome\n// rendered as content. The drill now wraps the visible slice in a\n// `<TitledBox>` with magenta borders so:\n// - title + position indicator inset into the top border line\n// (`╭─ mu task notes <id> · 1-72/311 ───╮`)\n// - bottomLabel (drill-specific yank hint) insets into the bottom\n// border line (`╰─ y yanks `mu task notes <id>` ───────╯`)\n//\n// Magenta keeps the existing visual: cyan outer (popup Shell) +\n// magenta inner (drill chrome). Two nested coloured borders\n// distinguish nesting depth without doubled lines (TitledBox\n// renders single-row borders only).\n//\n// Per ROADMAP pledge: ink/react import limited to src/cli/tui/*.\n\nimport { Box, Text } from \"ink\";\nimport { type ReactElement, useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport { cellWidth, contentWidthFromCols, truncateCell } from \"../columns.js\";\nimport type { PopupAction } from \"../keys.js\";\nimport { useTerminalSize } from \"../use-terminal-size.js\";\nimport { wrapAndPadAnsiLines } from \"../wrap-ansi.js\";\nimport { applyScroll, clampScrollTop, isNavAction } from \"./scroll.js\";\n\nexport interface DrillKeymapOptions {\n /** Already-rendered text — split on \\n for scroll clamping. */\n body: string;\n /** Visible lines. Matches the DrillScrollView viewport. */\n viewport: number;\n /** Called for Esc/q. The hook resets scrollTop before invoking it. */\n onClose: () => void;\n /** Optional y action for this drill view. */\n onYank?: () => void | Promise<void>;\n /** Optional user-driven escape hatch for git-show drills. */\n onTuicr?: () => void | Promise<void>;\n /** Called after keyboard navigation computes and stores a new scroll top. */\n onScrollChange?: (newTop: number) => void;\n /**\n * Identity signal for scroll resets. Callers pass the focused row /\n * entity identity so auto-refreshes of the SAME drill preserve\n * scroll, while navigating to a DIFFERENT drill resets to the top.\n */\n resetKey: string | number;\n}\n\nexport interface WrappedDrillBody {\n wrapped: string;\n lines: readonly string[];\n totalLines: number;\n}\n\nexport interface DrillKeymap {\n scrollTop: number;\n dispatch: (action: PopupAction) => void;\n wrappedBody: WrappedDrillBody;\n wrappedLines: readonly string[];\n totalLines: number;\n}\n\nfunction useDrillWrapWidth(): number {\n const { cols } = useTerminalSize();\n return Math.max(0, contentWidthFromCols(cols) - 2);\n}\n\nexport function wrapDrillBody(body: string, wrapWidth: number): WrappedDrillBody {\n const wrapped = wrapAndPadAnsiLines(body, wrapWidth);\n const lines = wrapped === \"\" ? [] : wrapped.split(\"\\n\");\n return { wrapped, lines, totalLines: lines.length };\n}\n\nexport function useWrappedBody(body: string, wrapWidth: number): WrappedDrillBody {\n return useMemo(() => wrapDrillBody(body, wrapWidth), [body, wrapWidth]);\n}\n\n/**\n * Shared keymap for read-only DrillScrollView leaves. Centralises the\n * common drill skeleton: clamp scroll from the rendered body, Esc/q\n * backs out one level, y delegates to the caller's read-only yank.\n */\nexport function useDrillKeymap({\n body,\n viewport,\n onClose,\n onYank,\n onTuicr,\n onScrollChange,\n resetKey,\n}: DrillKeymapOptions): DrillKeymap {\n const [scrollTop, setScrollTopState] = useState(0);\n const scrollTopRef = useRef(0);\n const onScrollChangeRef = useRef(onScrollChange);\n onScrollChangeRef.current = onScrollChange;\n const updateScrollTop = useCallback(\n (update: number | ((current: number) => number), notify = false): number => {\n const nextTop = typeof update === \"function\" ? update(scrollTopRef.current) : update;\n scrollTopRef.current = nextTop;\n setScrollTopState(nextTop);\n if (notify) onScrollChangeRef.current?.(nextTop);\n return nextTop;\n },\n [],\n );\n const wrapWidth = useDrillWrapWidth();\n const wrappedBody = useWrappedBody(body, wrapWidth);\n const { totalLines } = wrappedBody;\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: resetKey is intentionally the reset trigger even though its value isn't read in the body.\n useEffect(() => {\n updateScrollTop(0);\n }, [resetKey, updateScrollTop]);\n\n useEffect(() => {\n updateScrollTop((s) => clampScrollTop(s, totalLines, viewport));\n }, [totalLines, updateScrollTop, viewport]);\n\n const dispatch = useCallback(\n (action: PopupAction) => {\n if (isNavAction(action)) {\n updateScrollTop((s) => applyScroll(s, action, totalLines, viewport), true);\n return;\n }\n switch (action.kind) {\n case \"close\":\n updateScrollTop(0);\n onClose();\n return;\n case \"yank\":\n void onYank?.();\n return;\n case \"verb\":\n if (action.key === \"t\") void onTuicr?.();\n return;\n default:\n return;\n }\n },\n [onClose, onTuicr, onYank, totalLines, updateScrollTop, viewport],\n );\n\n return {\n scrollTop,\n dispatch,\n wrappedBody,\n wrappedLines: wrappedBody.lines,\n totalLines,\n };\n}\n\nexport interface DrillScrollViewProps {\n title: string;\n /** Already-rendered text — split on \\n into lines. */\n body: string;\n /** Visible lines. Caller picks based on terminal height. */\n viewport: number;\n /** First visible line index (0-based; clamped by caller). */\n scrollTop: number;\n /** Optional dim hint rendered below the body (drill-specific\n * recipe, e.g. ``y yanks `mu task notes <id>` `` or\n * ``loading…``). The j/k/Esc/q nav cluster lives in the global\n * StatusBar (popup-mode hint), so we keep this label short —\n * single drill-specific verb hint. */\n hint?: string;\n /** Optional fallback rendered when the body is empty. */\n emptyText?: string;\n /** Already-wrapped body from useDrillKeymap; avoids wrapping twice. */\n wrappedBody?: WrappedDrillBody;\n}\n\n/**\n * Pure-render scrollable text view. Caller owns scroll state +\n * keyboard wiring; this component just paints the visible slice and\n * a dim \"L/T\" position indicator inset into the magenta top border.\n */\nexport function DrillScrollView({\n title,\n body,\n viewport,\n scrollTop,\n hint,\n emptyText,\n wrappedBody,\n}: DrillScrollViewProps): ReactElement {\n const wrapWidth = useDrillWrapWidth();\n const renderedBody = useMemo(\n () => wrappedBody ?? wrapDrillBody(body, wrapWidth),\n [body, wrapWidth, wrappedBody],\n );\n const lines = renderedBody.lines;\n const totalLines = renderedBody.totalLines;\n const start = Math.max(0, Math.min(Math.max(0, totalLines - viewport), scrollTop));\n const visible = lines.slice(start, start + viewport);\n const showFallback = totalLines === 0;\n const positionLabel = showFallback\n ? \"0/0\"\n : `${start + 1}-${Math.min(totalLines, start + viewport)}/${totalLines}`;\n const hasHint = hint !== undefined && hint !== \"\";\n const headerTitleWidth = Math.max(1, wrapWidth - cellWidth(positionLabel) - 3);\n const headerTitle = truncateCell(title, headerTitleWidth);\n const hintText = hasHint ? truncateCell(hint, wrapWidth) : undefined;\n\n // Drill body renders inline inside the popup's existing chrome\n // (cyan rounded border + paddingX). NO nested TitledBox here:\n // a second rounded box at width=stdout.columns overflows the\n // popup's inner content area by 4 cols (popup chrome) which made\n // long lines wrap / spill past the popup's right border. Single\n // border, single width budget.\n // (bug_tui_drill_text_no_width_pin — central fix replacing the\n // earlier per-line width pin.)\n //\n // Body lines have already been ANSI-aware pre-wrapped by visual\n // width and padded to exactly the drill width (`wrapAndPadAnsiLines`\n // via useDrillKeymap / wrapDrillBody). Keep every pre-wrapped logical\n // line on exactly one terminal row: Ink's truncate path can undercount\n // ANSI-coloured text and eat the popup's trailing space + right border\n // when it has to fit an over-budget line. Because drill body rows are\n // pre-sized to the exact budget, `wrap=\"truncate\"` is a no-op safety\n // belt rather than the fitting mechanism.\n return (\n <Box flexDirection=\"column\" flexGrow={1}>\n <Box>\n <Text bold color=\"magenta\" wrap=\"truncate\">\n {headerTitle}\n </Text>\n <Text dimColor wrap=\"truncate\">\n {` · ${positionLabel}`}\n </Text>\n </Box>\n <Box flexDirection=\"column\" flexGrow={1}>\n {showFallback ? (\n <Text dimColor wrap=\"truncate\">\n {emptyText ?? \"(empty)\"}\n </Text>\n ) : (\n visible.map((ln, i) => (\n // Index IS the identity here: this is a fixed scroll window over a\n // read-only line array, so a row's position is what it is. There is no\n // stable per-line id to key on and nothing reorders in place.\n // biome-ignore lint/suspicious/noArrayIndexKey: scroll-window position is the identity\n <Text key={`${start + i}`} wrap=\"truncate\">\n {ln === \"\" ? \" \" : ln}\n </Text>\n ))\n )}\n </Box>\n {hasHint ? (\n <Box>\n <Text dimColor wrap=\"truncate\">\n {hintText}\n </Text>\n </Box>\n ) : null}\n </Box>\n );\n}\n","// Per-render popup viewport sizing — fixes bug_tui_popup_data_doesnt_fill.\n//\n// Before this helper landed every popup hardcoded\n//\n// const VIEWPORT = 20;\n//\n// at module scope and used it for slice size, scroll-clamp, and\n// (in log.tsx) cursor-centring math. After bug_tui_popups_fill_pane\n// added flexGrow={1} + width={cols} so the popup Shell occupies\n// the full pane, the row data inside the Shell was still capped at\n// 20, leaving a band of empty space inside the popup border.\n//\n// The fix: each popup reads `useStdout().rows` at render time and\n// calls `popupViewport(rows[, chromeOverride])` to get the slice\n// size. The default `POPUP_CHROME_ROWS` budget (3) accounts for:\n//\n// - 2 rows: Shell rounded border (top + bottom)\n// - 1 row: the App's StatusBar below the popup (`rows` is the whole\n// terminal, and the popup branch shares it with the StatusBar)\n//\n// Title + per-popup hint cost no body rows: both inset into the top\n// and bottom border lines (nit_tui_drill_inset_title_and_hints).\n//\n// <FilterPrompt> is NOT in this budget: it is 2 rows only while a\n// filter is active, so list popups subtract it per render with\n// `listViewport(viewport, flt)` from use-popup-filter.tsx.\n//\n// Per-popup overrides: callers that render extra in-body chrome\n// (e.g. Workspaces drill's title + dim \"(L-T/T)\" indicator) pass\n// `chromeOverride`. The floor (`POPUP_VIEWPORT_FLOOR`) keeps very\n// small terminals usable at the cost of some hint clipping.\n//\n// `popupViewport(rows[, chromeOverride])` is a PURE helper (no ink,\n// no globals) so unit tests can assert the chrome math without\n// booting a render tree. The matching `usePopupViewport()` ink hook\n// (below) wraps it so every popup is one line:\n//\n// const viewport = usePopupViewport();\n//\n// instead of the boilerplate trio of `useStdout`, `stdout?.rows ??\n// 24`, and a `popupViewport(...)` call. Both ship from the same\n// module because the hook IS the centralisation seam — splitting\n// them would just make every popup import twice.\n//\n// Per ROADMAP pledge: ink/react import limited to src/cli/tui/*.\n// This module is in src/cli/tui/popups/, so the hook's `useStdout`\n// import is in-bounds.\n\nimport { useTerminalSize } from \"../use-terminal-size.js\";\n\n/** Default rows outside the popup body: the Shell's top + bottom\n * border rows and the App StatusBar. Subtracted from `stdout.rows`\n * to get the body slice budget. */\nexport const POPUP_CHROME_ROWS = 3;\n\n/** Rows a `<DrillScrollView>` renders around its scroll window: the\n * magenta title line above and the hint line below. */\nexport const DRILL_VIEW_CHROME_ROWS = 2;\n\n/** Chrome budget for a popup whose body is one `<DrillScrollView>`.\n * Pass it to `usePopupViewport` for drill bodies so the title and\n * hint lines do not push the popup's borders out of the pane. */\nexport const POPUP_DRILL_CHROME_ROWS = POPUP_CHROME_ROWS + DRILL_VIEW_CHROME_ROWS;\n\n/** Minimum body rows. Keeps very-small terminals usable: at 12\n * rows we'd otherwise compute 6 → users couldn't see the cursor. */\nexport const POPUP_VIEWPORT_FLOOR = 8;\n\n/**\n * Compute how many body rows the popup may render given the current\n * terminal height. Pure: no ink, no globals — pass `rows` from\n * `useStdout().stdout?.rows ?? 24` at render time. The optional\n * `chromeOverride` lets popups with extra in-body chrome (e.g.\n * Workspaces drill renders an additional title + indicator pair)\n * subtract more than the default budget.\n *\n * @param rows total terminal rows (NOT popup rows — caller passes\n * `stdout.rows` directly; we own the chrome subtraction)\n * @param chromeOverride override for `POPUP_CHROME_ROWS` (default 3)\n */\nexport function popupViewport(rows: number, chromeOverride?: number): number {\n const chrome = chromeOverride ?? POPUP_CHROME_ROWS;\n return Math.max(POPUP_VIEWPORT_FLOOR, rows - chrome);\n}\n\n/**\n * Ink hook: returns the popup body viewport for the current render.\n * Wraps `useStdout()` + the `stdout?.rows ?? 24` fallback + the\n * `popupViewport()` chrome math so every popup is one line:\n *\n * const viewport = usePopupViewport();\n *\n * Pass `chromeOverride` when the popup renders extra in-body chrome\n * (e.g. Workspaces drill's title + indicator pair); otherwise the\n * default `POPUP_CHROME_ROWS` budget applies.\n *\n * Replaces the prior per-popup boilerplate AND fixes the\n * inprogress + recent drill regression where a stale module-scope\n * `const VIEWPORT = 20` was clipping notes below the popup's full\n * pane height (bug_tui_inprogress_recent_drill_viewport_clipped).\n */\nexport function usePopupViewport(chromeOverride?: number): number {\n const { rows } = useTerminalSize();\n return popupViewport(rows, chromeOverride);\n}\n","// All-tasks popup (`t`). Keybind-only; no dashboard card slot.\n//\n// Read-only list/sort complement to the DAG popup: every task in the\n// active workstream, filtered by task status (o/i/c) and substate\n// slice (p parked, w closed-not-done), sorted by\n// `s` through the same sort keys as `mu task list --sort`, Enter drills\n// into TaskDetailDrill, and `y` yanks `mu task show <id>`.\n\nimport { Box, Text } from \"ink\";\nimport { type ReactElement, useMemo, useState } from \"react\";\nimport type { Db } from \"../../../db.js\";\nimport { GLYPH } from \"../../../glyphs.js\";\nimport type { WorkstreamSnapshot } from \"../../../state.js\";\nimport {\n relTimeBasisForSort,\n sortTasks,\n TASK_SORT_KEYS,\n type TaskSortKey,\n} from \"../../../tasks/sort.js\";\nimport { formatPair } from \"../../../tasks/status.js\";\nimport { listTasks, type TaskRow } from \"../../../tasks.js\";\nimport { inkColorForPair } from \"../../format.js\";\nimport { agentByName, formatTaskOwnerDisplay } from \"../agent-display.js\";\nimport { type ColumnSpec, contentWidthFromCols, layoutColumns, renderRow } from \"../columns.js\";\nimport { formatRoi } from \"../format-helpers.js\";\nimport { dispatchPopupKeyFromInk, type PopupAction, type PopupActionEnvelope } from \"../keys.js\";\nimport { ListRow } from \"../list-row.js\";\nimport { usePopupInput } from \"../popup-input.js\";\nimport { PopupShell } from \"../popup-shell.js\";\nimport { useNotesDrill } from \"../use-notes-drill.js\";\nimport { usePopupActionQueue } from \"../use-popup-action-queue.js\";\nimport { applyFilter, FilterPrompt, listViewport, usePopupFilter } from \"../use-popup-filter.js\";\nimport { passesFilter, StatusFilterStrip, useStatusFilter } from \"../use-status-filter.js\";\nimport { useTerminalSize } from \"../use-terminal-size.js\";\nimport { useDrillKeymap } from \"./drill.js\";\nimport { applyCursor, centredVisibleSlice, clickedItem, isNavAction } from \"./scroll.js\";\nimport { TaskDetailDrill } from \"./task-detail.js\";\nimport { POPUP_CHROME_ROWS, usePopupViewport } from \"./viewport.js\";\n\nexport interface PopupProps {\n yank: (command: string) => Promise<void>;\n onClose: () => void;\n snapshot: WorkstreamSnapshot | null;\n fastTickNonce: number;\n mode: \"list\" | \"drill\";\n onModeChange: (mode: \"list\" | \"drill\") => void;\n onFilterEditingChange?: (editing: boolean) => void;\n popupActions?: readonly PopupActionEnvelope[];\n db: Db;\n workstream: string;\n}\n\nconst COLUMN_SPECS: ReadonlyArray<ColumnSpec> = [\n { kind: \"protect\" }, // task id\n { kind: \"protect\" }, // status + blocked glyph\n { kind: \"protect\" }, // owner\n { kind: \"protect\", align: \"right\" }, // ROI\n { kind: \"clip\", min: 1 }, // title\n];\n\n// The list view renders three in-body strip rows above the data\n// window: StatusFilterStrip, BlockedFilterStrip, SortStrip. Account\n// for those through the central viewport hook's chrome override so\n// the popup's top border does not get clipped on shorter panes.\nconst ALL_TASKS_STRIP_ROWS = 3;\nconst ALL_TASKS_CHROME_ROWS = POPUP_CHROME_ROWS + ALL_TASKS_STRIP_ROWS;\n\nexport function AllTasksPopup({\n yank,\n onClose,\n snapshot,\n fastTickNonce,\n mode,\n onModeChange,\n onFilterEditingChange,\n popupActions,\n db,\n workstream,\n}: PopupProps): ReactElement {\n const { cols } = useTerminalSize();\n const contentWidth = contentWidthFromCols(cols);\n const viewport = usePopupViewport(ALL_TASKS_CHROME_ROWS);\n const [cursor, setCursor] = useState(0);\n const [sortKey, setSortKey] = useState<TaskSortKey>(\"roi\");\n const flt = usePopupFilter({ onEditingChange: onFilterEditingChange });\n const rowsViewport = listViewport(viewport, flt);\n const statusFilter = useStatusFilter();\n const { statuses, showParked, showNotDone } = statusFilter;\n const filterStrip = (\n <StatusFilterStrip statuses={statuses} showParked={showParked} showNotDone={showNotDone} />\n );\n\n const sourceTasks = useMemo(\n () => allTasksFromSnapshotOrDb(snapshot, db, workstream),\n [snapshot, db, workstream],\n );\n const blockedNames = useMemo(\n () => new Set((snapshot?.blocked ?? []).map((t) => t.name)),\n [snapshot?.blocked],\n );\n const [blockedFilter, setBlockedFilter] = useState<BlockedFilterMode>(\"all\");\n // Per bug_filter_drill_opens_wrong_task: text filter applied\n // UNIFORMLY across list and drill modes. The previous\n // mode-conditional dropped the filter on drill, which shifted\n // visibleTasks under a constant cursor index and resolved the\n // wrong task. mode dep removed.\n const visibleTasks = useMemo(() => {\n const filteredByStatus = sourceTasks.filter((t) =>\n passesFilter(t, { statuses, showParked, showNotDone }),\n );\n const filteredByBlocked = applyBlockedFilter(filteredByStatus, blockedNames, blockedFilter);\n const filteredByText = applyFilter(\n filteredByBlocked,\n flt.query,\n (t) => `${t.name} ${t.title} ${formatPair(t)} ${t.ownerName ?? \"\"}`,\n );\n return sortTasks(filteredByText, sortKey);\n }, [\n sourceTasks,\n statuses,\n showParked,\n showNotDone,\n blockedFilter,\n blockedNames,\n flt.query,\n sortKey,\n ]);\n const safeCursor = visibleTasks.length === 0 ? 0 : Math.min(cursor, visibleTasks.length - 1);\n const focused = visibleTasks[safeCursor];\n\n // Defensive: capture the focused task identity at the moment the\n // user pressed Enter, so even if visibleTasks shifts underneath us\n // (a future refactor re-introduces a mode-dep, snapshot tick lands\n // a new row, etc.) the drill stays pinned to the row the user\n // visually selected. Cleared on close.\n const [drilledTask, setDrilledTask] = useState<TaskRow | null>(null);\n const drillTask = mode === \"drill\" ? (drilledTask ?? focused) : focused;\n\n const notesText = useNotesDrill({\n mode,\n focused: drillTask,\n db,\n workstream,\n fastTickNonce,\n });\n\n const drill = useDrillKeymap({\n body: notesText,\n viewport,\n onClose: () => {\n setDrilledTask(null);\n onModeChange(\"list\");\n },\n onYank: () => {\n if (!drillTask) return;\n return yank(allTasksYankCommand(drillTask.name, workstream));\n },\n resetKey: drillTask?.name ?? \"\",\n });\n\n const dispatchListAction = (action: PopupAction) => {\n if (mode === \"drill\") {\n drill.dispatch(action);\n return;\n }\n if (isNavAction(action)) {\n setCursor((c) => applyCursor(c, action, visibleTasks.length, rowsViewport));\n return;\n }\n switch (action.kind) {\n case \"close\":\n onClose();\n return;\n case \"filter\":\n flt.startEdit();\n return;\n case \"drill\":\n if (focused) {\n setDrilledTask(focused);\n onModeChange(\"drill\");\n }\n return;\n case \"clickRow\": {\n const hit = clickedItem(\n visibleTasks,\n safeCursor,\n rowsViewport,\n action.row,\n ALL_TASKS_STRIP_ROWS,\n );\n if (!hit) return;\n setCursor(hit.index);\n setDrilledTask(hit.item);\n onModeChange(\"drill\");\n return;\n }\n case \"yank\":\n if (focused) void yank(allTasksYankCommand(focused.name, workstream));\n return;\n case \"verb\":\n if (action.key === \"s\") setSortKey(nextTaskSortKey);\n return;\n }\n };\n\n usePopupActionQueue(popupActions, dispatchListAction);\n\n usePopupInput((input, key) => {\n if (mode !== \"drill\" && flt.onKey(input, key) === \"consumed\") return;\n if (mode !== \"drill\" && statusFilter.onKey(input, key)) return;\n // b toggles blocked filter — intercept before generic popup dispatch\n if (mode !== \"drill\" && !key.ctrl && !key.meta && input === \"b\") {\n setBlockedFilter(nextBlockedFilter);\n return;\n }\n dispatchListAction(dispatchPopupKeyFromInk(input, key));\n });\n\n if (snapshot === null) {\n return <PopupShell title=\"All tasks · popup\">{<Text dimColor>loading…</Text>}</PopupShell>;\n }\n\n if (sourceTasks.length === 0) {\n return (\n <PopupShell title=\"All tasks · popup\">\n <Box flexDirection=\"column\" flexGrow={1}>\n {filterStrip}\n <BlockedFilterStrip mode={blockedFilter} />\n <SortStrip sortKey={sortKey} visible={0} total={0} />\n <Text dimColor>(no tasks)</Text>\n </Box>\n </PopupShell>\n );\n }\n\n if (visibleTasks.length === 0) {\n return (\n <PopupShell title=\"All tasks · popup\">\n <Box flexDirection=\"column\" flexGrow={1}>\n {filterStrip}\n <BlockedFilterStrip mode={blockedFilter} />\n <SortStrip sortKey={sortKey} visible={0} total={sourceTasks.length} />\n <Text dimColor>\n {flt.query === \"\"\n ? \"(no tasks match status filter)\"\n : `(no matches for \"${flt.query}\")`}\n </Text>\n </Box>\n <FilterPrompt state={flt} />\n </PopupShell>\n );\n }\n\n if (mode === \"drill\" && drillTask) {\n return (\n <PopupShell title={`All tasks · ${drillTask.name} (notes)`}>\n <Box flexDirection=\"column\" flexGrow={1}>\n <TaskDetailDrill\n task={drillTask}\n db={db}\n workstream={workstream}\n scrollTop={drill.scrollTop}\n viewport={viewport}\n tickNonce={fastTickNonce}\n body={notesText}\n wrappedBody={drill.wrappedBody}\n />\n </Box>\n </PopupShell>\n );\n }\n\n const { start, visible: windowed } = centredVisibleSlice(visibleTasks, safeCursor, rowsViewport);\n const agentLookup = agentByName(snapshot);\n const rows = windowed.map((t) => [\n t.name,\n statusCell(t, blockedNames.has(t.name)),\n formatTaskOwnerDisplay(t, agentLookup),\n formatRoi(t.impact, t.effortDays),\n t.title,\n ]);\n const widths = layoutColumns(rows, COLUMN_SPECS, contentWidth);\n\n return (\n <PopupShell\n title={allTasksListTitle(safeCursor, visibleTasks.length, rowsViewport)}\n hint={focused ? allTasksYankCommand(focused.name, workstream) : undefined}\n >\n <Box flexDirection=\"column\" flexGrow={1}>\n {filterStrip}\n <BlockedFilterStrip mode={blockedFilter} />\n <SortStrip sortKey={sortKey} visible={visibleTasks.length} total={sourceTasks.length} />\n {windowed.map((t, i) => {\n const row = rows[i];\n if (row === undefined) return null;\n const padded = renderRow(row, widths, COLUMN_SPECS);\n const isBlocked = blockedNames.has(t.name);\n const colors = [\n { bold: true }, // id\n { color: isBlocked ? \"yellow\" : inkColorForPair(t) }, // status + blocked glyph\n { dimColor: true }, // owner\n { dimColor: true }, // ROI\n undefined, // title\n ];\n return (\n <ListRow\n key={t.name}\n cells={padded}\n contentWidth={contentWidth}\n colors={colors}\n selected={start + i === safeCursor}\n />\n );\n })}\n </Box>\n <FilterPrompt state={flt} />\n </PopupShell>\n );\n}\n\n/** Status cell: the pair, prefixed by the parked glyph for a parked\n * row and suffixed by the blocked glyph for a blocked one. */\nfunction statusCell(t: TaskRow, blocked: boolean): string {\n const pair = formatPair(t);\n const parked = t.status === \"OPEN\" && t.substate === \"parked\" ? `${GLYPH.parked} ` : \"\";\n return `${parked}${pair}${blocked ? ` ${GLYPH.blocked}` : \"\"}`;\n}\n\nexport function allTasksFromSnapshotOrDb(\n snapshot: WorkstreamSnapshot | null,\n db: Db,\n workstream: string,\n): TaskRow[] {\n if (snapshot?.allTasks && snapshot.allTasks.length > 0) return snapshot.allTasks;\n return listTasks(db, workstream);\n}\n\nexport function allTasksYankCommand(taskId: string, workstream: string): string {\n return `mu task show ${taskId} -w ${workstream}`;\n}\n\nexport function nextTaskSortKey(current: TaskSortKey): TaskSortKey {\n const i = TASK_SORT_KEYS.indexOf(current);\n return TASK_SORT_KEYS[(i + 1) % TASK_SORT_KEYS.length] ?? \"roi\";\n}\n\nexport function sortIndicator(sortKey: TaskSortKey): string {\n const basis = relTimeBasisForSort(sortKey);\n const detail = basis === null ? \"\" : basis === \"updatedAt\" ? \" updated\" : \" created\";\n return `sort: [s]ort=${sortKey} ↓${detail}`;\n}\n\nexport function allTasksScrollPercent(\n cursor: number,\n total: number,\n viewport: number,\n): number | null {\n if (total <= viewport) return null;\n return Math.round((cursor / Math.max(1, total - 1)) * 100);\n}\n\nexport function allTasksListTitle(cursor: number, total: number, viewport: number): string {\n const percent = allTasksScrollPercent(cursor, total, viewport);\n const indicator = percent === null ? \"\" : ` · ${percent}%`;\n return `All tasks · popup (${cursor + 1}/${total})${indicator}`;\n}\n\nfunction SortStrip({\n sortKey,\n visible,\n total,\n}: {\n sortKey: TaskSortKey;\n visible: number;\n total: number;\n}): ReactElement {\n return (\n <Box>\n <Text dimColor>\n {sortIndicator(sortKey)} (filter: {visible} of {total})\n </Text>\n </Box>\n );\n}\n\n// ─── Blocked filter ───────────────────────────────────────────────\n\nexport type BlockedFilterMode = \"all\" | \"only\" | \"hide\";\n\nexport function nextBlockedFilter(current: BlockedFilterMode): BlockedFilterMode {\n switch (current) {\n case \"all\":\n return \"only\";\n case \"only\":\n return \"hide\";\n case \"hide\":\n return \"all\";\n }\n}\n\nexport function applyBlockedFilter<T extends { name: string }>(\n tasks: T[],\n blockedNames: ReadonlySet<string>,\n mode: BlockedFilterMode,\n): T[] {\n switch (mode) {\n case \"all\":\n return tasks;\n case \"only\":\n return tasks.filter((t) => blockedNames.has(t.name));\n case \"hide\":\n return tasks.filter((t) => !blockedNames.has(t.name));\n }\n}\n\nconst BLOCKED_FILTER_LABELS: Readonly<Record<BlockedFilterMode, string>> = {\n all: \"all\",\n only: \"only blocked\",\n hide: \"hide blocked\",\n};\n\nfunction BlockedFilterStrip({ mode }: { mode: BlockedFilterMode }): ReactElement {\n return (\n <Box>\n <Text dimColor>\n [<Text bold>b</Text>]locked: {BLOCKED_FILTER_LABELS[mode]}\n {mode === \"all\" ? \"\" : ` ${GLYPH.on}`}\n </Text>\n </Box>\n );\n}\n","// Shared notes-drill memo for task-list popups (Tasks/ready,\n// In-progress, Blocked, Recent, All-tasks). Pre-refactor each popup\n// shipped a byte-identical useMemo block that SELECTed task notes\n// only when the popup was in drill mode and a row was focused. The\n// block existed only because `useDrillKeymap` needs the rendered\n// body string to clamp scroll. See task\n// review_tui_task_popups_duplicated_template (workstream `tui-impl`).\n\nimport { useMemo } from \"react\";\nimport type { Db } from \"../../db.js\";\nimport type { TaskRow } from \"../../tasks.js\";\nimport { renderNotes } from \"./popups/task-detail.js\";\n\nexport interface UseNotesDrillOptions {\n mode: \"list\" | \"drill\";\n focused: TaskRow | undefined;\n db: Db;\n workstream: string;\n /** Refresh signal for SQL-backed bodies (the fast TUI tick). */\n fastTickNonce: number;\n}\n\n/** Returns \"\" until mode === \"drill\" + focused, otherwise renderNotes(...).\n * fastTickNonce sits in the memo deps so the body refreshes on each\n * fast tick while the drill stays open during a worker session. */\nexport function useNotesDrill(opts: UseNotesDrillOptions): string {\n const { mode, focused, db, workstream, fastTickNonce } = opts;\n return useMemo<string>(() => {\n void fastTickNonce;\n if (mode !== \"drill\" || !focused) return \"\";\n return renderNotes(db, focused.name, workstream);\n }, [mode, focused, db, workstream, fastTickNonce]);\n}\n","// Shared \"task detail\" leaf — read-only inline rendering of a\n// task's notes timeline. The leaf of the popup-drill recursion\n// (per feat_track_drill_chains_to_task_drill).\n//\n// Today's consumers:\n// - popups/ready.tsx → Tasks popup drill (Enter on a task row)\n// - popups/tracks.tsx → Tracks popup drill → drill row Enter\n//\n// Future consumers (when promoted): any popup whose drill is\n// itself a list of tasks (Card 6 in-progress, Card 7 blocked,\n// Card 8 recent — see feat_more_cards_umbrella). Each gets the\n// chain into this leaf \"for free\" by importing TaskDetailDrill.\n//\n// Pure presentation — the parent owns the scroll cursor (so each\n// recursion level has its own scroll state) and the keyboard.\n// This module never executes mutations; listNotes is a SQLite\n// SELECT.\n//\n// Per ROADMAP pledge: ink/react import limited to src/cli/tui/*.\n\nimport { type ReactElement, useMemo } from \"react\";\nimport type { Db } from \"../../../db.js\";\nimport { listNotes, type TaskRow } from \"../../../tasks.js\";\nimport { DrillScrollView, type WrappedDrillBody } from \"./drill.js\";\n\nexport type RenderNotesFn = (db: Db, taskId: string, workstream: string) => string;\n\nconst ANSI_BOLD_CYAN = \"\\x1b[1;36m\";\nconst ANSI_RESET = \"\\x1b[0m\";\n\nexport interface TaskDetailDrillProps {\n task: TaskRow;\n db: Db;\n workstream: string;\n /** First visible line index — owned by parent for per-level scroll. */\n scrollTop: number;\n /** Visible lines; caller picks based on terminal height. */\n viewport: number;\n /** Refresh signal for SQL-backed note bodies. */\n tickNonce: number;\n /** Already-rendered body shared with useDrillKeymap. */\n body?: string;\n /** Injection seam for behaviour tests; production uses renderNotes. */\n renderNotesFn?: RenderNotesFn;\n /** Already-wrapped body from useDrillKeymap; avoids wrapping twice. */\n wrappedBody?: WrappedDrillBody;\n}\n\n/**\n * Render a task's notes timeline. Returns a column of:\n * <DrillScrollView title=\"mu task notes <id>\" body=<rendered>… />\n *\n * Empty notes → DrillScrollView's emptyText fallback fires.\n */\nexport function TaskDetailDrill({\n task,\n db,\n workstream,\n scrollTop,\n viewport,\n tickNonce,\n body,\n renderNotesFn = renderNotes,\n wrappedBody,\n}: TaskDetailDrillProps): ReactElement {\n const renderedBody = useMemo<string>(() => {\n if (body !== undefined) return body;\n void tickNonce;\n return renderNotesFn(db, task.name, workstream);\n }, [body, db, task, workstream, tickNonce, renderNotesFn]);\n return (\n <DrillScrollView\n title={`mu task notes ${task.name}`}\n body={renderedBody}\n viewport={viewport}\n scrollTop={scrollTop}\n wrappedBody={wrappedBody}\n emptyText=\"(no notes)\"\n hint={`y yanks \\`mu task notes ${task.name}\\``}\n />\n );\n}\n\n/**\n * Pure helper: SELECTs notes via listNotes and formats them as the\n * same `── <ts> <author> ──\\n<content>` blocks the Tasks popup\n * drill rendered inline before this refactor. Exported so tests can\n * assert the exact format without booting ink.\n */\nexport function renderNotes(db: Db, taskId: string, workstream: string): string {\n const notes = listNotes(db, taskId, workstream);\n if (notes.length === 0) return \"\";\n return notes\n .map((n) => {\n const ts = n.createdAt.replace(\"T\", \" \").slice(0, 19);\n const author = n.author ?? \"?\";\n return `${ANSI_BOLD_CYAN}── ${ts} ${author} ──${ANSI_RESET}\\n${n.content}`;\n })\n .join(\"\\n\\n\");\n}\n","// Shared task-status toggle filter for TUI task-list surfaces.\n//\n// Used by the DAG and all-tasks popups. o/i/c toggle a status; p and w\n// toggle two substate slices (OPEN/parked, CLOSED-but-not-done).\n// Default is everything visible; state is deliberately local to\n// the popup instance and resets on unmount (no persistence / no config).\n//\n// Per ROADMAP pledge: ink/react imports are confined to src/cli/tui/*.\n\nimport { Box, Text } from \"ink\";\nimport { type ReactElement, useCallback, useState } from \"react\";\nimport { GLYPH } from \"../../glyphs.js\";\nimport { TASK_STATUSES, type TaskPair, type TaskStatus } from \"../../tasks/status.js\";\nimport { colorStatus } from \"../format.js\";\nimport type { KeyFlags } from \"./keys.js\";\n\nexport const STATUS_BY_KEY: Readonly<Record<string, TaskStatus>> = {\n o: \"OPEN\",\n i: \"IN_PROGRESS\",\n c: \"CLOSED\",\n};\n\nconst STATUS_LABELS: Readonly<Record<TaskStatus, { key: string; rest: string }>> = {\n OPEN: { key: \"O\", rest: \"pen\" },\n IN_PROGRESS: { key: \"I\", rest: \"n_progress\" },\n CLOSED: { key: \"C\", rest: \"losed\" },\n};\n\nexport function toggleStatusSet(\n statuses: ReadonlySet<TaskStatus>,\n status: TaskStatus,\n): Set<TaskStatus> {\n const next = new Set(statuses);\n if (next.has(status)) {\n next.delete(status);\n } else {\n next.add(status);\n }\n return next;\n}\n\nexport function statusForToggleKey(input: string, key: KeyFlags): TaskStatus | undefined {\n if (key.ctrl === true || key.meta === true) return undefined;\n return STATUS_BY_KEY[input.toLowerCase()];\n}\n\n/** The two substate slices with their own toggle: `p` OPEN/parked,\n * `w` CLOSED rows whose substate is not done (rejected, wontfix, ...). */\nexport type SubstateToggle = \"parked\" | \"notDone\";\n\nconst SUBSTATE_BY_KEY: Readonly<Record<string, SubstateToggle>> = { p: \"parked\", w: \"notDone\" };\n\nexport function substateToggleForKey(input: string, key: KeyFlags): SubstateToggle | undefined {\n if (key.ctrl === true || key.meta === true) return undefined;\n return SUBSTATE_BY_KEY[input.toLowerCase()];\n}\n\nexport interface FilterState {\n statuses: ReadonlySet<TaskStatus>;\n showParked: boolean;\n showNotDone: boolean;\n}\n\n/** True when a task survives every toggle: its status is enabled and\n * neither substate slice it belongs to is hidden. */\nexport function passesFilter(t: TaskPair, f: FilterState): boolean {\n if (!f.statuses.has(t.status)) return false;\n if (!f.showParked && t.status === \"OPEN\" && t.substate === \"parked\") return false;\n if (!f.showNotDone && t.status === \"CLOSED\" && t.substate !== \"done\") return false;\n return true;\n}\n\nexport interface StatusFilter extends FilterState {\n statuses: Set<TaskStatus>;\n toggle: (s: TaskStatus) => void;\n /** Returns true when an o/i/c/p/w toggle key was consumed. */\n onKey: (input: string, key: KeyFlags) => boolean;\n}\n\nexport function useStatusFilter(): StatusFilter {\n const [statuses, setStatuses] = useState<Set<TaskStatus>>(() => new Set(TASK_STATUSES));\n const [showParked, setShowParked] = useState(true);\n const [showNotDone, setShowNotDone] = useState(true);\n\n const toggle = useCallback((status: TaskStatus) => {\n setStatuses((prev) => toggleStatusSet(prev, status));\n }, []);\n\n const onKey = useCallback(\n (input: string, key: KeyFlags): boolean => {\n const status = statusForToggleKey(input, key);\n if (status !== undefined) {\n toggle(status);\n return true;\n }\n const sub = substateToggleForKey(input, key);\n if (sub === \"parked\") setShowParked((v) => !v);\n else if (sub === \"notDone\") setShowNotDone((v) => !v);\n return sub !== undefined;\n },\n [toggle],\n );\n\n return { statuses, showParked, showNotDone, toggle, onKey };\n}\n\nconst SUBSTATE_LABELS: ReadonlyArray<{\n id: SubstateToggle;\n key: string;\n rest: string;\n color: \"gray\" | \"red\";\n}> = [\n { id: \"parked\", key: \"P\", rest: \"arked\", color: \"gray\" },\n // Covers every non-done close (rejected, wontfix, duplicate, superseded).\n { id: \"notDone\", key: \"W\", rest: \"on't do\", color: \"red\" },\n];\n\nexport function StatusFilterStrip({\n statuses,\n showParked = true,\n showNotDone = true,\n}: {\n statuses: ReadonlySet<TaskStatus>;\n showParked?: boolean;\n showNotDone?: boolean;\n}): ReactElement {\n const substateOn: Record<SubstateToggle, boolean> = {\n parked: showParked,\n notDone: showNotDone,\n };\n return (\n <Box>\n <Text dimColor>filters: </Text>\n {TASK_STATUSES.map((status, i) => {\n const label = STATUS_LABELS[status];\n const enabled = statuses.has(status);\n return (\n <Text key={status}>\n {i > 0 ? \" \" : \"\"}\n <Text>{\"[\"}</Text>\n <Text>{colorStatus(status).replace(status, label.key)}</Text>\n <Text>{\"]\"}</Text>\n <Text>{label.rest}</Text>\n <Text> </Text>\n <Text color={enabled ? \"green\" : \"gray\"}>{enabled ? GLYPH.on : GLYPH.off}</Text>\n </Text>\n );\n })}\n {SUBSTATE_LABELS.map((label, i) => {\n const enabled = substateOn[label.id];\n return (\n <Text key={label.id}>\n {i === 0 ? \" \" : \" \"}\n <Text>{\"[\"}</Text>\n <Text color={label.color}>{label.key}</Text>\n <Text>{\"]\"}</Text>\n <Text>{label.rest}</Text>\n <Text> </Text>\n <Text color={enabled ? \"green\" : \"gray\"}>{enabled ? GLYPH.on : GLYPH.off}</Text>\n </Text>\n );\n })}\n </Box>\n );\n}\n","// Blocked popup (Shift+7 → `&`). The drill-down for the Blocked\n// card.\n//\n// Per feat_popup_7_blocked (workstream `tui-impl`): list of every\n// blocked task (OPEN with at least one still-gating blocker) with\n// j/k navigation, '/' filter (via use-popup-filter), and Enter to\n// drill into the standard TaskDetailDrill leaf — rows ARE tasks so\n// the popup-drill recursion contract applies for free\n// (feat_track_drill_chains_to_task_drill).\n//\n// Sibling of the task-list popup family (ready/inprogress/recent),\n// all of which share the TaskListPopup scaffold\n// (popups/task-list-popup.tsx). The Blocked config differs in three\n// ways:\n//\n// 1. Source rows are `snapshot.blocked` (the OPEN-with-unsatisfied-\n// blockers slice).\n// 2. The list view exposes the Card 7 layout — glyph + id + STATUS\n// + #blockers + top-blocker + ROI + title — and reads per-row\n// blockers via getTaskEdgesWithStatus (memoised so '/'-filter\n// typing doesn't re-do the SQLite reads on every keystroke).\n// 3. Yank → `mu task tree <id> -w <ws>`. The blocked-task popup's\n// most-actionable diagnostic question is \"what's blocking\n// this?\" and `mu task tree` walks the prerequisite subgraph in\n// one shot. Drill-mode yank → `mu task notes <id>` (shared).\n//\n// Per ROADMAP pledge: ink/react import limited to src/cli/tui/*.\n\nimport { type ReactElement, useMemo } from \"react\";\nimport { roiBucket, type WorkstreamSnapshot } from \"../../../state.js\";\nimport { formatPair } from \"../../../tasks/status.js\";\nimport { getTaskEdgesWithStatus } from \"../../../tasks.js\";\nimport { inkColorForPair } from \"../../format.js\";\nimport { blockerLabel, GLYPH, stillGating } from \"../cards/blocked.js\";\nimport type { ColumnSpec } from \"../columns.js\";\nimport { colorForBucket, formatRoi } from \"../format-helpers.js\";\nimport {\n type PopupProps,\n type RenderedRow,\n TaskListPopup,\n type TaskListPopupConfig,\n} from \"./task-list-popup.js\";\n\nconst COLUMN_SPECS: ReadonlyArray<ColumnSpec> = [\n { kind: \"protect\" }, // glyph\n { kind: \"protect\" }, // task id\n { kind: \"protect\" }, // status (always OPEN; constant for now)\n { kind: \"protect\", align: \"right\" }, // #blockers\n { kind: \"protect\" }, // top-blocker id (or \"—\")\n { kind: \"protect\", align: \"right\" }, // ROI\n { kind: \"clip\", min: 1 }, // title\n];\n\nexport function BlockedPopup(props: PopupProps): ReactElement {\n const { snapshot, db, workstream } = props;\n const sourceTasks = snapshot?.blocked ?? [];\n\n // Per-row blocker lookup. Memoised so '/'-filter typing doesn't\n // re-do the SQLite reads on every keystroke. Same shape as the\n // Card 7 read path: one getTaskEdgesWithStatus per source row,\n // filtered to still-gating. Indexed by task `name`.\n const blockerIndex = useMemo<Map<string, string[]>>(() => {\n const m = new Map<string, string[]>();\n for (const t of sourceTasks) {\n const gating = stillGating(getTaskEdgesWithStatus(db, t.name, workstream).blockers);\n m.set(t.name, gating.map(blockerLabel));\n }\n return m;\n }, [sourceTasks, db, workstream]);\n\n const config = useMemo<TaskListPopupConfig>(\n () => ({\n label: \"Blocked\",\n sourceTasks: (snap: WorkstreamSnapshot) => snap.blocked,\n columnSpecs: COLUMN_SPECS,\n filterBlob: (t) => {\n const blockers = blockerIndex.get(t.name) ?? [];\n return `${t.name} ${t.title} ${blockers.join(\" \")}`;\n },\n emptyText: \"(no blocked tasks — every OPEN task is ready)\",\n // Per the task spec KEY MAP block: most useful diagnostic is\n // `mu task tree <id>` — \"show me what's blocking this\".\n yankCommand: (t, ws) => `mu task tree ${t.name} -w ${ws}`,\n renderRows: (visible): RenderedRow[] =>\n visible.map((t) => {\n const blockers = blockerIndex.get(t.name) ?? [];\n const top = blockers[0] ?? \"—\";\n const bucket = roiBucket(t.impact, t.effortDays);\n return {\n cells: [\n GLYPH,\n t.name,\n formatPair(t),\n String(blockers.length),\n top,\n formatRoi(t.impact, t.effortDays),\n t.title,\n ],\n colors: [\n { dimColor: true }, // glyph\n { bold: true }, // name\n { color: inkColorForPair(t) }, // status\n { color: \"yellow\" }, // nblock\n { dimColor: true }, // top\n { color: colorForBucket(bucket) }, // roi\n undefined, // title\n ],\n };\n }),\n }),\n [blockerIndex],\n );\n\n return <TaskListPopup config={config} {...props} />;\n}\n","// Shared task-list popup scaffold.\n//\n// Per finding_4_task_list_popups_duplicate: ready.tsx, inprogress.tsx,\n// recent.tsx, and blocked.tsx all duplicated ~120 LOC of identical\n// coordination logic — usePopupFilter + applyFilter, safeCursor,\n// drilledTask pinning (bug_filter_drill_opens_wrong_task), useNotesDrill,\n// useDrillKeymap, the dispatchListAction switch, useInput wiring, the\n// three early-return states, and the drill branch. Only the source list,\n// column specs, row mapper/colors, filter blob, yank command, and titles\n// differed. This file centralises the orchestration shell so a behavioural\n// fix lands once; each popup collapses to a config object.\n//\n// Pure dedup — no new surface, identical behaviour.\n//\n// Per ROADMAP pledge: ink/react import limited to src/cli/tui/*.\n\nimport { Box, Text } from \"ink\";\nimport { type ReactElement, useState } from \"react\";\nimport type { Db } from \"../../../db.js\";\nimport type { WorkstreamSnapshot } from \"../../../state.js\";\nimport type { TaskRow } from \"../../../tasks.js\";\nimport { type ColumnSpec, contentWidthFromCols, layoutColumns, renderRow } from \"../columns.js\";\nimport { dispatchPopupKeyFromInk, type PopupAction, type PopupActionEnvelope } from \"../keys.js\";\nimport { type CellColor, ListRow } from \"../list-row.js\";\nimport { usePopupInput } from \"../popup-input.js\";\nimport { PopupShell } from \"../popup-shell.js\";\nimport { useNotesDrill } from \"../use-notes-drill.js\";\nimport { usePopupActionQueue } from \"../use-popup-action-queue.js\";\nimport { applyFilter, FilterPrompt, listViewport, usePopupFilter } from \"../use-popup-filter.js\";\nimport { useTerminalSize } from \"../use-terminal-size.js\";\nimport { useDrillKeymap } from \"./drill.js\";\nimport { applyCursor, centredVisibleSlice, clickedItem, isNavAction } from \"./scroll.js\";\nimport { TaskDetailDrill } from \"./task-detail.js\";\nimport { POPUP_DRILL_CHROME_ROWS, usePopupViewport } from \"./viewport.js\";\n\nexport interface PopupProps {\n yank: (command: string) => Promise<void>;\n onClose: () => void;\n snapshot: WorkstreamSnapshot | null;\n fastTickNonce: number;\n mode: \"list\" | \"drill\";\n onModeChange: (mode: \"list\" | \"drill\") => void;\n /** Bubbles the filter-prompt edit state up to <App> for StatusBar mode. */\n onFilterEditingChange?: (editing: boolean) => void;\n popupActions?: readonly PopupActionEnvelope[];\n db: Db;\n workstream: string;\n}\n\n/** Rendered cells + per-cell colours for a single list row. */\nexport interface RenderedRow {\n cells: ReadonlyArray<string>;\n colors: ReadonlyArray<CellColor | undefined>;\n}\n\n/**\n * Per-popup configuration. The shared scaffold reads these to wire the\n * source list, column layout, row rendering, filter blob, list-mode yank,\n * and the various title/empty strings. `now`/`ages` precompute is left to\n * the caller via the rows closure receiving the visible slice.\n */\nexport interface TaskListPopupConfig {\n /** Short popup name used in every title (e.g. \"Tasks\", \"In-progress\"). */\n label: string;\n /** Source rows selector (e.g. snapshot.ready). Null snapshot → []. */\n sourceTasks: (snapshot: WorkstreamSnapshot) => readonly TaskRow[];\n /** Column layout spec. */\n columnSpecs: ReadonlyArray<ColumnSpec>;\n /** Search blob for the '/' filter. */\n filterBlob: (task: TaskRow) => string;\n /**\n * Map the visible slice (already sliced + cursor-centred) to rendered\n * rows. Given the visible tasks, their absolute start index, and the\n * snapshot so callers can resolve agent display names / per-row reads.\n */\n renderRows: (\n visible: readonly TaskRow[],\n start: number,\n snapshot: WorkstreamSnapshot,\n ) => RenderedRow[];\n /** List-mode yank command for the focused row (null → no yank). */\n yankCommand: (task: TaskRow, workstream: string) => string | null;\n /** Text for the empty-source early return. */\n emptyText: string;\n /** Optional static hint for the list shell. */\n hint?: string;\n /**\n * Optional dynamic hint computed from the focused row + workstream\n * (e.g. ReadyPopup mirrors the yank command into the shell hint).\n */\n dynamicHint?: (focused: TaskRow, workstream: string) => string | null;\n}\n\n/**\n * Shared scaffold for the task-list popup family. Owns all the\n * coordination logic; per-popup behaviour comes entirely from `config`.\n */\nexport function TaskListPopup({\n config,\n yank,\n onClose,\n snapshot,\n fastTickNonce,\n mode,\n onModeChange,\n onFilterEditingChange,\n popupActions,\n db,\n workstream,\n}: PopupProps & { config: TaskListPopupConfig }): ReactElement {\n const { cols } = useTerminalSize();\n const contentWidth = contentWidthFromCols(cols);\n const viewport = usePopupViewport();\n const drillViewport = usePopupViewport(POPUP_DRILL_CHROME_ROWS);\n const [cursor, setCursor] = useState(0);\n const flt = usePopupFilter({ onEditingChange: onFilterEditingChange });\n const rowsViewport = listViewport(viewport, flt);\n\n const sourceTasks = snapshot ? config.sourceTasks(snapshot) : [];\n // Per bug_filter_drill_opens_wrong_task: filter applied UNIFORMLY\n // across list and drill modes (a mode-conditional dropped the filter\n // on drill, shifting `tasks` under a constant cursor index).\n const tasks = applyFilter(sourceTasks, flt.query, config.filterBlob);\n const safeCursor = tasks.length === 0 ? 0 : Math.min(cursor, tasks.length - 1);\n const focused = tasks[safeCursor];\n\n // Defensive: capture the focused task identity at the moment Enter is\n // pressed so the drill stays pinned even if `tasks` shifts.\n const [drilledTask, setDrilledTask] = useState<TaskRow | null>(null);\n const drillTask = mode === \"drill\" ? (drilledTask ?? focused) : focused;\n\n const notesText = useNotesDrill({ mode, focused: drillTask, db, workstream, fastTickNonce });\n\n const drill = useDrillKeymap({\n body: notesText,\n viewport: drillViewport,\n onClose: () => {\n setDrilledTask(null);\n onModeChange(\"list\");\n },\n onYank: () => {\n if (!drillTask || !snapshot) return;\n return yank(`mu task notes ${drillTask.name} -w ${snapshot.workstreamName}`);\n },\n resetKey: drillTask?.name ?? \"\",\n });\n\n const dispatchListAction = (action: PopupAction) => {\n if (mode === \"drill\") {\n drill.dispatch(action);\n return;\n }\n if (isNavAction(action)) {\n setCursor((c) => applyCursor(c, action, tasks.length, rowsViewport));\n return;\n }\n switch (action.kind) {\n case \"close\":\n onClose();\n return;\n case \"filter\":\n flt.startEdit();\n return;\n case \"drill\":\n if (focused) {\n setDrilledTask(focused);\n onModeChange(\"drill\");\n }\n return;\n case \"clickRow\": {\n const hit = clickedItem(tasks, safeCursor, rowsViewport, action.row);\n if (!hit) return;\n setCursor(hit.index);\n setDrilledTask(hit.item);\n onModeChange(\"drill\");\n return;\n }\n case \"yank\": {\n const t = tasks[safeCursor];\n if (!t || !snapshot) return;\n const cmd = config.yankCommand(t, snapshot.workstreamName);\n if (cmd) void yank(cmd);\n return;\n }\n }\n };\n\n usePopupActionQueue(popupActions, dispatchListAction);\n\n usePopupInput((input, key) => {\n if (mode !== \"drill\" && flt.onKey(input, key) === \"consumed\") return;\n dispatchListAction(dispatchPopupKeyFromInk(input, key));\n });\n\n if (snapshot === null) {\n return (\n <PopupShell title={`${config.label} · popup`}>{<Text dimColor>loading…</Text>}</PopupShell>\n );\n }\n if (sourceTasks.length === 0) {\n return (\n <PopupShell title={`${config.label} · popup`}>\n <Text dimColor>{config.emptyText}</Text>\n </PopupShell>\n );\n }\n if (tasks.length === 0) {\n return (\n <PopupShell title={`${config.label} · popup`}>\n <Box flexDirection=\"column\" flexGrow={1}>\n <Text dimColor>(no matches for \"{flt.query}\")</Text>\n </Box>\n <FilterPrompt state={flt} />\n </PopupShell>\n );\n }\n\n if (mode === \"drill\" && drillTask) {\n return (\n <PopupShell title={`${config.label} · ${drillTask.name} (notes)`}>\n <Box flexDirection=\"column\" flexGrow={1}>\n <TaskDetailDrill\n task={drillTask}\n db={db}\n workstream={workstream}\n scrollTop={drill.scrollTop}\n viewport={drillViewport}\n tickNonce={fastTickNonce}\n body={notesText}\n wrappedBody={drill.wrappedBody}\n />\n </Box>\n </PopupShell>\n );\n }\n\n const { start, visible } = centredVisibleSlice(tasks, safeCursor, rowsViewport);\n const rendered = config.renderRows(visible, start, snapshot);\n const rowCells = rendered.map((r) => r.cells);\n const widths = layoutColumns(rowCells, config.columnSpecs, contentWidth);\n\n const dynamicHint =\n focused && config.dynamicHint\n ? (config.dynamicHint(focused, snapshot.workstreamName) ?? undefined)\n : undefined;\n\n return (\n <PopupShell\n title={`${config.label} · popup (${safeCursor + 1}/${tasks.length})`}\n hint={dynamicHint ?? config.hint}\n >\n <Box flexDirection=\"column\" flexGrow={1}>\n {visible.map((t, i) => {\n const selected = start + i === safeCursor;\n const r = rendered[i];\n if (r === undefined) return null;\n const padded = renderRow(r.cells, widths, config.columnSpecs);\n return (\n <ListRow\n key={t.name}\n cells={padded}\n contentWidth={contentWidth}\n colors={r.colors}\n selected={selected}\n />\n );\n })}\n </Box>\n <FilterPrompt state={flt} />\n </PopupShell>\n );\n}\n","// Commits popup (Shift+0 → `)`). Fullscreen lazygit-style project\n// commit log with '/' filtering and Enter → VCS show drill.\n//\n// Uses the project-root backend (detectBackend(projectRoot)) so git,\n// jj, and sl all work through the shared VcsBackend.showCommit seam.\n// The popup never mutates: `y` yanks the backend-specific show command\n// for the focused commit.\n\nimport { Box, Text } from \"ink\";\nimport { type ReactElement, useCallback, useEffect, useState } from \"react\";\nimport type { Db } from \"../../../db.js\";\nimport type { WorkstreamSnapshot } from \"../../../state.js\";\nimport { type CommitSummary, detectBackend, type VcsBackendName } from \"../../../vcs.js\";\nimport { type ColumnSpec, contentWidthFromCols, layoutColumns, renderRow } from \"../columns.js\";\nimport { dispatchPopupKeyFromInk, type PopupAction, type PopupActionEnvelope } from \"../keys.js\";\nimport { runLazygitInteractive } from \"../lazygit.js\";\nimport { ListRow } from \"../list-row.js\";\nimport { usePopupInput } from \"../popup-input.js\";\nimport { PopupShell } from \"../popup-shell.js\";\nimport { runTuicrInteractive } from \"../tuicr.js\";\nimport { usePopupActionQueue } from \"../use-popup-action-queue.js\";\nimport { applyFilter, FilterPrompt, listViewport, usePopupFilter } from \"../use-popup-filter.js\";\nimport { useTerminalSize } from \"../use-terminal-size.js\";\nimport { DrillScrollView, useDrillKeymap } from \"./drill.js\";\nimport { applyCursor, centredVisibleSlice, clickedItem, isNavAction } from \"./scroll.js\";\nimport { loadShowPreservingBody } from \"./show-loader.js\";\nimport { usePopupViewport } from \"./viewport.js\";\n\nexport interface PopupProps {\n yank: (command: string) => Promise<void>;\n onClose: () => void;\n snapshot: WorkstreamSnapshot | null;\n slowTickNonce: number;\n mode: \"list\" | \"drill\";\n onModeChange: (mode: \"list\" | \"drill\") => void;\n onFilterEditingChange?: (editing: boolean) => void;\n popupActions?: readonly PopupActionEnvelope[];\n onFooter?: (command: string, copied: boolean, tone?: \"normal\" | \"info\" | \"error\") => void;\n db: Db;\n workstream: string;\n}\n\nconst COLUMN_SPECS: ReadonlyArray<ColumnSpec> = [\n { kind: \"protect\" }, // sha short\n { kind: \"protect\", align: \"right\" }, // relative time\n { kind: \"protect\", max: 18 }, // author\n { kind: \"clip\", min: 1 }, // subject\n];\n\nconst DRILL_CHROME_ROWS = 7;\n\nexport function CommitsPopup({\n yank,\n onClose,\n snapshot,\n slowTickNonce,\n mode,\n onModeChange,\n onFilterEditingChange,\n popupActions,\n onFooter,\n}: PopupProps): ReactElement {\n const { cols } = useTerminalSize();\n const contentWidth = contentWidthFromCols(cols);\n const viewport = usePopupViewport();\n const drillViewport = usePopupViewport(DRILL_CHROME_ROWS);\n const [cursor, setCursor] = useState(0);\n const [showText, setShowText] = useState(\"\");\n const [showLoading, setShowLoading] = useState(false);\n const [showErr, setShowErr] = useState<string | null>(null);\n const [backendName, setBackendName] = useState<VcsBackendName | null>(\n snapshot?.commitsBackend ?? null,\n );\n const flt = usePopupFilter({ onEditingChange: onFilterEditingChange });\n const rowsViewport = listViewport(viewport, flt);\n\n const sourceCommits = snapshot?.recentCommits ?? [];\n const commits = applyFilter(\n sourceCommits,\n flt.query,\n (c) => `${c.sha} ${c.subject} ${c.author} ${c.relTime}`,\n );\n const safeCursor = commits.length === 0 ? 0 : Math.min(cursor, commits.length - 1);\n const focused = commits[safeCursor];\n // Pin the drilled commit at Enter. Commits are newest-first, so a\n // new commit on the slow tick shifts every index; following the\n // cursor would switch the open `git show` to a different commit.\n const [drilledCommit, setDrilledCommit] = useState<CommitSummary | null>(null);\n const drillCommit = mode === \"drill\" ? (drilledCommit ?? focused) : focused;\n const showCommand =\n drillCommit && backendName !== null\n ? showCommandForBackend(backendName, drillCommit.sha)\n : null;\n const projectRoot = process.cwd();\n const showBody = showErr !== null ? `error: ${showErr}` : showText;\n\n const loadShow = useCallback(\n async (sha: string) => {\n await loadShowPreservingBody(\n projectRoot,\n sha,\n async (path) => {\n const backend = await detectBackend(path);\n setBackendName(backend.name);\n return backend;\n },\n {\n setText: setShowText,\n setError: setShowErr,\n setLoading: setShowLoading,\n },\n );\n },\n [projectRoot],\n );\n\n useEffect(() => {\n if (snapshot?.commitsBackend !== undefined) setBackendName(snapshot.commitsBackend);\n }, [snapshot?.commitsBackend]);\n\n useEffect(() => {\n if (mode !== \"drill\") {\n setShowText(\"\");\n setShowErr(null);\n setShowLoading(false);\n }\n }, [mode]);\n\n const drillSha = drillCommit?.sha;\n useEffect(() => {\n void slowTickNonce;\n if (mode === \"drill\" && drillSha !== undefined) {\n void loadShow(drillSha);\n }\n }, [mode, drillSha, loadShow, slowTickNonce]);\n\n const drill = useDrillKeymap({\n body: showBody,\n viewport: drillViewport,\n onClose: () => {\n setDrilledCommit(null);\n onModeChange(\"list\");\n },\n onYank: () => {\n if (showCommand !== null) return yank(showCommand);\n },\n onTuicr: () => {\n if (!drillCommit) return;\n const r = runTuicrInteractive({ rev: drillCommit.sha, cwd: projectRoot });\n if (!r.ok) onFooter?.(r.error ?? \"tuicr failed\", false, \"error\");\n else onFooter?.(`tuicr -r ${drillCommit.sha}`, true, \"info\");\n },\n resetKey: drillCommit?.sha ?? \"\",\n });\n\n const dispatchListAction = (action: PopupAction) => {\n if (mode === \"drill\") {\n drill.dispatch(action);\n return;\n }\n if (isNavAction(action)) {\n setCursor((c) => applyCursor(c, action, commits.length, rowsViewport));\n return;\n }\n switch (action.kind) {\n case \"close\":\n onClose();\n return;\n case \"filter\":\n flt.startEdit();\n return;\n case \"drill\": {\n if (!focused) return;\n setDrilledCommit(focused);\n onModeChange(\"drill\");\n return;\n }\n case \"clickRow\": {\n const hit = clickedItem(commits, safeCursor, rowsViewport, action.row);\n if (!hit) return;\n setCursor(hit.index);\n setDrilledCommit(hit.item);\n onModeChange(\"drill\");\n return;\n }\n case \"yank\": {\n const c = commits[safeCursor];\n if (!c || backendName === null) return;\n void yank(showCommandForBackend(backendName, c.sha));\n return;\n }\n case \"verb\":\n if (action.key === \"l\") {\n const r = runLazygitInteractive({ cwd: projectRoot });\n if (!r.ok) onFooter?.(r.error ?? \"lazygit failed\", false, \"error\");\n else onFooter?.(\"lazygit\", true, \"info\");\n }\n return;\n }\n };\n\n usePopupActionQueue(popupActions, dispatchListAction);\n\n usePopupInput((input, key) => {\n if (mode !== \"drill\" && flt.onKey(input, key) === \"consumed\") return;\n dispatchListAction(dispatchPopupKeyFromInk(input, key));\n });\n\n if (snapshot === null) {\n return <PopupShell title=\"Commits · loading\">{<Text dimColor>loading…</Text>}</PopupShell>;\n }\n if (mode === \"drill\" && drillCommit !== undefined) {\n const short = shortSha(drillCommit.sha);\n return (\n <PopupShell title={`Commits · ${formatBackend(backendName)} · ${short}`}>\n <Box flexDirection=\"column\" flexGrow={1}>\n <DrillScrollView\n title={`${showCommand ?? \"show\"} · ${drillCommit.subject}`}\n body={showBody}\n viewport={drillViewport}\n scrollTop={drill.scrollTop}\n wrappedBody={drill.wrappedBody}\n hint={\n showCommand === null\n ? \"y yanks show command · t tuicr\"\n : `y yanks \\`${showCommand}\\` · t tuicr`\n }\n emptyText={showLoading ? \"loading…\" : \"(empty show output)\"}\n />\n </Box>\n </PopupShell>\n );\n }\n if (sourceCommits.length === 0) {\n return (\n <PopupShell title={`Commits · ${formatBackend(backendName)}`}>\n <Text dimColor>(no commits)</Text>\n </PopupShell>\n );\n }\n if (commits.length === 0) {\n return (\n <PopupShell title={`Commits · ${formatBackend(backendName)}`}>\n <Box flexDirection=\"column\" flexGrow={1}>\n <Text dimColor>(no matches for \"{flt.query}\")</Text>\n </Box>\n <FilterPrompt state={flt} />\n </PopupShell>\n );\n }\n\n const { visible } = centredVisibleSlice(commits, safeCursor, rowsViewport);\n const rows = visible.map((c) => [shortSha(c.sha), c.relTime, c.author, c.subject]);\n const widths = layoutColumns(rows, COLUMN_SPECS, contentWidth);\n\n return (\n <PopupShell\n title={`Commits · ${formatBackend(backendName)} (${safeCursor + 1}/${commits.length})`}\n hint=\"y yanks VCS show command · l lazygit\"\n >\n <Box flexDirection=\"column\" flexGrow={1}>\n {visible.map((c, i) => {\n const row = rows[i];\n if (row === undefined) return null;\n const padded = renderRow(row, widths, COLUMN_SPECS);\n const colors = [\n { color: \"yellow\" }, // sha\n { dimColor: true }, // relTime\n { dimColor: true }, // author\n undefined, // subject\n ];\n return (\n <ListRow\n key={c.sha}\n cells={padded}\n contentWidth={contentWidth}\n colors={colors}\n selected={commits.indexOf(c) === safeCursor}\n />\n );\n })}\n </Box>\n <FilterPrompt state={flt} />\n </PopupShell>\n );\n}\n\nexport function shortSha(sha: string): string {\n return sha.slice(0, 7);\n}\n\nexport function formatBackend(backend: VcsBackendName | null): string {\n return backend ?? \"(no vcs)\";\n}\n\nexport function showCommandForBackend(backend: VcsBackendName, sha: string): string {\n switch (backend) {\n case \"git\":\n return `git show ${sha}`;\n case \"jj\":\n return `jj show ${sha}`;\n case \"sl\":\n return `sl show ${sha}`;\n case \"none\":\n return `# no VCS backend for commit ${sha}`;\n }\n}\n\n// Test-only helper: keeps the WorkstreamSnapshot import live under\n// noUnusedLocals even when source-level tests import the prop type.\nexport function commitFilterBlob(c: CommitSummary): string {\n return `${c.sha} ${c.subject} ${c.author} ${c.relTime}`;\n}\n","// Drop into `lazygit` from inside the TUI: leaves the alt screen,\n// inherits stdio so lazygit owns the terminal, restores the alt\n// screen on exit. Mirrors `runTuicrInteractive` (src/cli/tui/tuicr.ts)\n// — same dependency-injection seam, same error-shape contract — so\n// test coverage and behavioural conventions stay consistent across\n// the two TUI escape hatches.\n//\n// Bound to `l` in the Commits popup LIST mode (counterpart to\n// `t tuicr` in the per-revision git-show DRILL): lazygit operates on\n// a cwd, not on a single revision, so the natural surface is the\n// list-level \"browse this repo\" exit, not a per-row drill.\n\nimport { spawnSync } from \"node:child_process\";\nimport { ALT_SCREEN_ENTER, ALT_SCREEN_EXIT } from \"./escapes.js\";\n\nexport interface RunLazygitOptions {\n /** Project root / workspace cwd used by lazygit for repo detection. */\n cwd: string;\n}\n\ninterface SpawnSyncResult {\n status: number | null;\n error?: Error;\n}\n\ntype SpawnSyncFn = (\n command: string,\n args: readonly string[],\n options: { cwd: string; stdio: \"inherit\"; env: NodeJS.ProcessEnv },\n) => SpawnSyncResult;\n\nexport interface RunLazygitDeps {\n spawn?: SpawnSyncFn;\n write?: (text: string) => void;\n env?: NodeJS.ProcessEnv;\n}\n\nexport interface RunLazygitResult {\n ok: boolean;\n error?: string;\n}\n\nexport function runLazygitInteractive(\n opts: RunLazygitOptions,\n deps: RunLazygitDeps = {},\n): RunLazygitResult {\n const run = deps.spawn ?? (spawnSync as SpawnSyncFn);\n const write = deps.write ?? ((text: string) => process.stdout.write(text));\n const env = deps.env ?? process.env;\n let result: RunLazygitResult = { ok: true };\n\n try {\n write(ALT_SCREEN_EXIT);\n const r = run(\"lazygit\", [], {\n cwd: opts.cwd,\n stdio: \"inherit\",\n env,\n });\n if (r.error !== undefined) {\n result = { ok: false, error: lazygitErrorMessage(r.error) };\n } else if (typeof r.status === \"number\" && r.status !== 0) {\n result = { ok: false, error: `lazygit exited ${r.status}` };\n }\n } catch (err) {\n result = { ok: false, error: lazygitErrorMessage(err) };\n } finally {\n try {\n write(ALT_SCREEN_ENTER);\n } catch {\n // Best-effort terminal repair only. Preserve the original result.\n }\n }\n\n return result;\n}\n\nexport function lazygitErrorMessage(err: unknown): string {\n if (err instanceof Error) {\n const code = (err as NodeJS.ErrnoException).code;\n if (code === \"ENOENT\") {\n return \"lazygit not found · install from https://github.com/jesseduffield/lazygit\";\n }\n return err.message.length > 0 ? err.message : String(err);\n }\n return String(err);\n}\n","import { spawnSync } from \"node:child_process\";\nimport { ALT_SCREEN_ENTER, ALT_SCREEN_EXIT } from \"./escapes.js\";\n\nexport interface RunTuicrOptions {\n rev: string;\n /** Project root / workspace cwd used by tuicr for repo detection. */\n cwd: string;\n}\n\ninterface SpawnSyncResult {\n status: number | null;\n error?: Error;\n}\n\ntype SpawnSyncFn = (\n command: string,\n args: readonly string[],\n options: { cwd: string; stdio: \"inherit\"; env: NodeJS.ProcessEnv },\n) => SpawnSyncResult;\n\nexport interface RunTuicrDeps {\n spawn?: SpawnSyncFn;\n write?: (text: string) => void;\n env?: NodeJS.ProcessEnv;\n}\n\nexport interface RunTuicrResult {\n ok: boolean;\n error?: string;\n}\n\nexport function runTuicrInteractive(\n opts: RunTuicrOptions,\n deps: RunTuicrDeps = {},\n): RunTuicrResult {\n const run = deps.spawn ?? (spawnSync as SpawnSyncFn);\n const write = deps.write ?? ((text: string) => process.stdout.write(text));\n const env = deps.env ?? process.env;\n let result: RunTuicrResult = { ok: true };\n\n try {\n write(ALT_SCREEN_EXIT);\n const r = run(\"tuicr\", [\"-r\", opts.rev], {\n cwd: opts.cwd,\n stdio: \"inherit\",\n env,\n });\n if (r.error !== undefined) {\n result = { ok: false, error: tuicrErrorMessage(r.error) };\n } else if (typeof r.status === \"number\" && r.status !== 0) {\n result = { ok: false, error: `tuicr exited ${r.status}` };\n }\n } catch (err) {\n result = { ok: false, error: tuicrErrorMessage(err) };\n } finally {\n try {\n write(ALT_SCREEN_ENTER);\n } catch {\n // Best-effort terminal repair only. Preserve the original result.\n }\n }\n\n return result;\n}\n\nexport function tuicrErrorMessage(err: unknown): string {\n if (err instanceof Error) {\n const code = (err as NodeJS.ErrnoException).code;\n if (code === \"ENOENT\") return \"tuicr not found · install with cargo install tuicr\";\n return err.message.length > 0 ? err.message : String(err);\n }\n return String(err);\n}\n","// Shared tiny state machine for VCS show drills (Commits and\n// Workspaces popups). Keeps the previous successful body visible\n// while a slow-tick refetch is in flight, avoiding the blank-flash\n// flicker that came from clearing showText before each subprocess.\n//\n// Pure TS: no ink/react imports. Tests can drive the transition\n// directly without mounting a popup or shelling out to git.\n\nimport type { ShowCommitResult, VcsBackend } from \"../../../vcs.js\";\n\nexport interface ShowLoaderState {\n text: string;\n error: string | null;\n loading: boolean;\n}\n\nexport interface ShowLoaderSetters {\n setText: (text: string) => void;\n setError: (error: string | null) => void;\n setLoading: (loading: boolean) => void;\n}\n\nexport type DetectBackendFn = (path: string) => Promise<Pick<VcsBackend, \"showCommit\">>;\n\nexport async function loadShowPreservingBody(\n path: string,\n sha: string,\n detect: DetectBackendFn,\n setters: ShowLoaderSetters,\n): Promise<ShowCommitResult> {\n setters.setLoading(true);\n setters.setError(null);\n const backend = await detect(path);\n const result = await backend.showCommit(path, sha);\n if (result.error !== undefined) {\n setters.setError(result.error);\n setters.setText(\"\");\n } else {\n setters.setText(result.text);\n }\n setters.setLoading(false);\n return result;\n}\n","// Full task-DAG popup (`g`). Keybind-only; no dashboard card slot.\n//\n// Read-only forest of the current workstream: every root task (no\n// incoming blocks edge) is rendered with the same ASCII tree machinery\n// as `mu task tree --down`, separated by blank lines. No card owns this\n// popup; it is a dashboard-level graph affordance for large workstreams.\n\nimport { Box, Text } from \"ink\";\nimport { type ReactElement, useMemo, useRef, useState } from \"react\";\nimport { loadFullDag, renderForest } from \"../../../dag.js\";\nimport type { Db } from \"../../../db.js\";\nimport type { WorkstreamSnapshot } from \"../../../state.js\";\nimport type { TaskStatus } from \"../../../tasks/status.js\";\nimport { colorPair } from \"../../format.js\";\nimport { contentWidthFromCols, truncateCell } from \"../columns.js\";\nimport { dispatchPopupKeyFromInk } from \"../keys.js\";\nimport { usePopupInput } from \"../popup-input.js\";\nimport { PopupShell } from \"../popup-shell.js\";\nimport {\n type FilterState,\n passesFilter,\n StatusFilterStrip,\n useStatusFilter,\n} from \"../use-status-filter.js\";\nimport { useTerminalSize } from \"../use-terminal-size.js\";\nimport { DrillScrollView, useDrillKeymap } from \"./drill.js\";\nimport { POPUP_DRILL_CHROME_ROWS, usePopupViewport } from \"./viewport.js\";\n\nexport interface PopupProps {\n yank: (command: string) => Promise<void>;\n onClose: () => void;\n snapshot: WorkstreamSnapshot | null;\n fastTickNonce: number;\n mode: \"list\" | \"drill\";\n onModeChange: (mode: \"list\" | \"drill\") => void;\n onFilterEditingChange?: (editing: boolean) => void;\n db: Db;\n workstream: string;\n}\n\nconst DAG_STRIP_ROWS = 1;\n\ninterface DagBody {\n body: string;\n roots: string[];\n}\n\nexport function DagPopup({\n yank,\n onClose,\n db,\n workstream,\n fastTickNonce,\n}: PopupProps): ReactElement {\n // DrillScrollView (title + hint) below one StatusFilterStrip row.\n const viewport = usePopupViewport(POPUP_DRILL_CHROME_ROWS + DAG_STRIP_ROWS);\n const statusFilter = useStatusFilter();\n const { statuses, showParked, showNotDone } = statusFilter;\n const { cols } = useTerminalSize();\n const contentWidth = contentWidthFromCols(cols);\n const { body, roots } = useMemo<DagBody>(() => {\n void fastTickNonce;\n return buildDagBody(db, workstream, { statuses, showParked, showNotDone }, contentWidth);\n }, [db, workstream, statuses, showParked, showNotDone, contentWidth, fastTickNonce]);\n const [focusedRoot, setFocusedRoot] = useState<string | null>(() => roots[0] ?? null);\n const lineToRootRef = useRef<readonly string[]>([]);\n const rootsRef = useRef<readonly string[]>([]);\n rootsRef.current = roots;\n const focusedTask = focusedRoot !== null && roots.includes(focusedRoot) ? focusedRoot : roots[0];\n const drill = useDrillKeymap({\n body,\n viewport,\n onClose,\n onYank: () => {\n if (focusedTask === undefined) return;\n return yank(dagYankCommand(focusedTask, workstream));\n },\n onScrollChange: (newTop) =>\n setFocusedRoot(lineToRootRef.current[newTop] ?? rootsRef.current[0] ?? null),\n resetKey: workstream,\n });\n\n const lineToRoot = useMemo(\n () => rootForBodyLines(drill.wrappedLines, roots),\n [drill.wrappedLines, roots],\n );\n lineToRootRef.current = lineToRoot;\n\n usePopupInput((input, key) => {\n if (statusFilter.onKey(input, key)) return;\n const action = dispatchPopupKeyFromInk(input, key);\n drill.dispatch(action);\n });\n\n if (roots.length === 0) {\n return (\n <PopupShell title={`DAG · ${workstream}`}>\n <Box flexDirection=\"column\" flexGrow={1}>\n <StatusFilterStrip\n statuses={statuses}\n showParked={showParked}\n showNotDone={showNotDone}\n />\n <Text dimColor>(no tasks)</Text>\n </Box>\n </PopupShell>\n );\n }\n\n return (\n <PopupShell title={`DAG · ${workstream}`} hint=\"y yanks `mu task tree <root-id>`\">\n <Box flexDirection=\"column\" flexGrow={1}>\n <StatusFilterStrip statuses={statuses} showParked={showParked} showNotDone={showNotDone} />\n <DrillScrollView\n title=\"task DAG forest\"\n body={body}\n viewport={viewport}\n scrollTop={drill.scrollTop}\n wrappedBody={drill.wrappedBody}\n emptyText=\"(no tasks)\"\n hint=\"y yanks `mu task tree <root-id>`\"\n />\n </Box>\n </PopupShell>\n );\n}\n\nexport function dagYankCommand(taskId: string, workstream: string): string {\n return `mu task tree ${taskId} -w ${workstream}`;\n}\n\nexport function buildDagBody(\n db: Db,\n workstream: string,\n filter: ReadonlySet<TaskStatus> | FilterState,\n contentWidth: number = contentWidthFromCols(80),\n): DagBody {\n // A bare status set means \"no substate toggles\" (both slices shown).\n const f: FilterState =\n \"statuses\" in filter ? filter : { statuses: filter, showParked: true, showNotDone: true };\n const dag = loadFullDag(db, workstream, { include: (t) => passesFilter(t, f) });\n const body = renderForest(dag.roots, dag.edges, (task) => colorPair(task), dag.tasks, {\n includeTitle: false,\n });\n return {\n body: truncateDagBody(body, contentWidth),\n roots: dag.roots.map((t) => t.name),\n };\n}\n\nexport function truncateDagBody(body: string, contentWidth: number): string {\n const width = Math.max(0, contentWidth - 1);\n return body\n .split(\"\\n\")\n .map((line) => truncateCell(line, width))\n .join(\"\\n\");\n}\n\nfunction rootForBodyLines(lines: readonly string[], roots: readonly string[]): string[] {\n const rootSet = new Set(roots);\n const out: string[] = [];\n let current = roots[0] ?? \"\";\n for (const line of lines) {\n const maybeRoot = line.split(/\\s+/)[0];\n if (maybeRoot !== undefined && rootSet.has(maybeRoot)) current = maybeRoot;\n out.push(current);\n }\n return out;\n}\n","// Doctor popup (Shift+9 → `(`). The drill-down for the Doctor card.\n//\n// Per feat_popup_9_doctor (workstream `tui-impl`): list of every\n// doctor check (NOT just the non-OK subset Card 9 surfaces) with\n// j/k navigation, '/' substring filter (via use-popup-filter), `y`\n// to yank a remediation HINT (informational only — never a\n// mutating verb), and Enter to drill into a small ad-hoc detail\n// view of the focused check.\n//\n// IMPORTANT — DRILL IS NOT TaskDetailDrill. Rows are doctor checks,\n// not tasks; the popup-recursion contract from\n// feat_track_drill_chains_to_task_drill does NOT apply. The drill\n// view renders the focused check's name, status, detail, and a\n// multi-line remediation hint via the shared DrillScrollView leaf.\n//\n// COLUMN SHAPE (matches Card 9's row vocabulary):\n// glyph check STATUS detail\n// PROTECT PROTECT PROTECT CLIP\n//\n// Per feat_column_aligned_lists clipping policy: glyph + name +\n// status are PROTECTED (identity-bearing); only `detail` is\n// CLIPPABLE.\n//\n// READ-ONLY (per ROADMAP pledge). The only act-intent is `y`,\n// which yanks an INFORMATIONAL command (the row's diagnostic\n// recipe). Schema/journal_mode/foreign_keys checks have no\n// mutating recovery the operator can yank, so we yank a `# ...`\n// comment line — visibly inert, satisfies the muscle-memory of\n// \"press y, paste, see something\". No verb in the yank matrix\n// here mutates the DB or pane state.\n//\n// Per ROADMAP pledge: ink/react import limited to src/cli/tui/*.\n\nimport { Box, Text } from \"ink\";\nimport { type ReactElement, useState } from \"react\";\nimport type { Db } from \"../../../db.js\";\nimport {\n type DoctorCheck,\n loadDoctorChecks,\n remediationParagraph,\n yankCommandForCheck,\n} from \"../../../doctor-summary.js\";\nimport type { WorkstreamSnapshot } from \"../../../state.js\";\nimport { colorForStatus, glyphFor } from \"../cards/doctor.js\";\nimport { type ColumnSpec, contentWidthFromCols, layoutColumns, renderRow } from \"../columns.js\";\nimport { dispatchPopupKeyFromInk, type PopupAction, type PopupActionEnvelope } from \"../keys.js\";\nimport { ListRow } from \"../list-row.js\";\nimport { usePopupInput } from \"../popup-input.js\";\nimport { PopupShell } from \"../popup-shell.js\";\nimport { usePopupActionQueue } from \"../use-popup-action-queue.js\";\nimport { applyFilter, FilterPrompt, listViewport, usePopupFilter } from \"../use-popup-filter.js\";\nimport { useTerminalSize } from \"../use-terminal-size.js\";\nimport { DrillScrollView, useDrillKeymap } from \"./drill.js\";\nimport { applyCursor, centredVisibleSlice, clickedItem, isNavAction } from \"./scroll.js\";\nimport { POPUP_DRILL_CHROME_ROWS, usePopupViewport } from \"./viewport.js\";\n\nexport interface PopupProps {\n yank: (command: string) => Promise<void>;\n onClose: () => void;\n snapshot: WorkstreamSnapshot | null;\n mode: \"list\" | \"drill\";\n onModeChange: (mode: \"list\" | \"drill\") => void;\n /** Bubbles the filter-prompt edit state up to <App> for StatusBar mode. */\n onFilterEditingChange?: (editing: boolean) => void;\n popupActions?: readonly PopupActionEnvelope[];\n db: Db;\n workstream: string;\n}\n\nconst COLUMN_SPECS: ReadonlyArray<ColumnSpec> = [\n { kind: \"protect\" }, // glyph\n { kind: \"protect\" }, // check name\n { kind: \"protect\" }, // status (ok / warn / fail)\n { kind: \"clip\", min: 1 }, // detail (free-form; CLIPPABLE)\n];\n\nexport function DoctorPopup({\n yank,\n onClose,\n snapshot,\n mode,\n onModeChange,\n onFilterEditingChange,\n popupActions,\n db,\n workstream: _workstream,\n}: PopupProps): ReactElement {\n const { cols } = useTerminalSize();\n const contentWidth = contentWidthFromCols(cols);\n // Per-render viewport from stdout.rows minus the popup chrome\n // budget; see popups/viewport.ts.\n const viewport = usePopupViewport();\n const [cursor, setCursor] = useState(0);\n const flt = usePopupFilter({ onEditingChange: onFilterEditingChange });\n const rowsViewport = listViewport(viewport, flt);\n const drillViewport = usePopupViewport(POPUP_DRILL_CHROME_ROWS);\n\n // Source rows: ALL checks (OK + warn + fail), NOT just the non-OK\n // subset Card 9 renders. We refresh on every render — the SDK\n // call is a handful of synchronous DB pragmas + COUNT-shape\n // SELECTs (see src/doctor-summary.ts) so it's cheap even on the\n // popup's typing-intensive '/' filter loop. Snapshot.doctor (the\n // card's slice) only carries the truncated set, so we re-derive\n // the full one here, with the card's agent-state source (herdr on\n // herdr) so the murmur row agrees with the card and `mu doctor`.\n const sourceChecks: readonly DoctorCheck[] = snapshot\n ? loadDoctorChecks(db, snapshot, snapshot.doctor?.agentStateSource)\n : [];\n\n // Per spec FILTER block: blob = `${name} ${status} ${detail}`.\n // Per bug_filter_drill_opens_wrong_task: text filter applied\n // UNIFORMLY across list and drill modes (the previous mode-conditional\n // dropped the filter on drill, shifting `checks` under a constant\n // cursor index).\n const checks = applyFilter(sourceChecks, flt.query, (c) => `${c.name} ${c.status} ${c.detail}`);\n const safeCursor = checks.length === 0 ? 0 : Math.min(cursor, checks.length - 1);\n const focused = checks[safeCursor];\n\n // Defensive: capture focused check identity at Enter so the drill\n // stays pinned even if checks shift.\n const [drilledCheck, setDrilledCheck] = useState<DoctorCheck | null>(null);\n const drillCheck = mode === \"drill\" ? (drilledCheck ?? focused) : focused;\n\n // Drill body: pre-formatted text rendered via DrillScrollView.\n // Pure derivation from the captured check; no DB call.\n const drillBody = drillCheck ? renderDrillBody(drillCheck) : \"\";\n const drill = useDrillKeymap({\n body: drillBody,\n viewport: drillViewport,\n onClose: () => {\n setDrilledCheck(null);\n onModeChange(\"list\");\n },\n onYank: () => {\n if (!drillCheck) return;\n return yank(yankCommandForCheck(drillCheck));\n },\n resetKey: drillCheck?.name ?? \"\",\n });\n\n const dispatchListAction = (action: PopupAction) => {\n if (mode === \"drill\") {\n drill.dispatch(action);\n return;\n }\n if (isNavAction(action)) {\n setCursor((c) => applyCursor(c, action, checks.length, rowsViewport));\n return;\n }\n switch (action.kind) {\n case \"close\":\n onClose();\n return;\n case \"filter\":\n flt.startEdit();\n return;\n case \"drill\":\n if (focused) {\n setDrilledCheck(focused);\n onModeChange(\"drill\");\n }\n return;\n case \"clickRow\": {\n const hit = clickedItem(checks, safeCursor, rowsViewport, action.row);\n if (!hit) return;\n setCursor(hit.index);\n setDrilledCheck(hit.item);\n onModeChange(\"drill\");\n return;\n }\n case \"yank\":\n if (!focused) return;\n void yank(yankCommandForCheck(focused));\n return;\n }\n };\n\n usePopupActionQueue(popupActions, dispatchListAction);\n\n usePopupInput((input, key) => {\n if (mode !== \"drill\" && flt.onKey(input, key) === \"consumed\") return;\n dispatchListAction(dispatchPopupKeyFromInk(input, key));\n });\n\n if (snapshot === null) {\n return <PopupShell title=\"Doctor · popup\">{<Text dimColor>loading…</Text>}</PopupShell>;\n }\n if (sourceChecks.length === 0) {\n return (\n <PopupShell title=\"Doctor · popup\">\n <Text dimColor>(no checks ran — `mu doctor` should always return ≥ 1 row)</Text>\n </PopupShell>\n );\n }\n if (checks.length === 0) {\n return (\n <PopupShell title=\"Doctor · popup\">\n <Box flexDirection=\"column\" flexGrow={1}>\n <Text dimColor>(no matches for \"{flt.query}\")</Text>\n </Box>\n <FilterPrompt state={flt} />\n </PopupShell>\n );\n }\n\n if (mode === \"drill\" && drillCheck) {\n return (\n <PopupShell title={`Doctor · ${drillCheck.name} (detail)`}>\n <Box flexDirection=\"column\" flexGrow={1}>\n <DrillScrollView\n title={`${drillCheck.name} · ${drillCheck.status}`}\n body={drillBody}\n viewport={drillViewport}\n scrollTop={drill.scrollTop}\n wrappedBody={drill.wrappedBody}\n emptyText=\"(no detail)\"\n hint={`y yanks \\`${yankCommandForCheck(drillCheck)}\\``}\n />\n </Box>\n </PopupShell>\n );\n }\n\n const { start, visible } = centredVisibleSlice(checks, safeCursor, rowsViewport);\n const rows = visible.map((c) => [glyphFor(c), c.name, c.status, c.detail]);\n const widths = layoutColumns(rows, COLUMN_SPECS, contentWidth);\n\n return (\n <PopupShell\n title={`Doctor · popup (${safeCursor + 1}/${checks.length})`}\n hint=\"y yanks remediation hint (informational)\"\n >\n <Box flexDirection=\"column\" flexGrow={1}>\n {visible.map((c, i) => {\n const selected = start + i === safeCursor;\n const row = rows[i];\n if (row === undefined) return null;\n const padded = renderRow(row, widths, COLUMN_SPECS);\n const statusColor = colorForStatus(c.status);\n const colors = [\n { color: statusColor }, // glyph\n { bold: true }, // name\n { color: statusColor }, // status\n { dimColor: true }, // detail\n ];\n return (\n <ListRow\n key={c.name}\n cells={padded}\n contentWidth={contentWidth}\n colors={colors}\n selected={selected}\n />\n );\n })}\n </Box>\n <FilterPrompt state={flt} />\n </PopupShell>\n );\n}\n\n// ─── pure helpers (drill body render — pure-helpers MOVED) ──────────\n//\n// `yankCommandForCheck` + `remediationParagraph` previously lived\n// here. They moved to src/doctor-summary.ts per\n// review_tui_doctor_remediation_lives_in_popup — they have no\n// rendering concern, and keeping them next to the `DoctorCheck`\n// type means a future check is a single touchpoint instead of two.\n// `renderDrillBody` STAYS here because it interleaves\n// summary/status/detail/separator lines for the popup drill view.\n\n/**\n * Pre-format the focused check as a multi-line drill body. Pure;\n * exported for unit tests. Lines:\n *\n * <NAME>\n * status: <ok | warn | fail>\n * detail: <free-form>\n * (blank)\n * <multi-line remediation hint>\n *\n * The remediation hint is a short paragraph that explains what\n * the operator should run / look at next. Same vocabulary as the\n * yank recipe (yankCommandForCheck) so the user sees the same\n * verb in the body and on `y`.\n */\nexport function renderDrillBody(check: DoctorCheck): string {\n const lines: string[] = [];\n lines.push(check.name);\n lines.push(\"\");\n lines.push(`status: ${check.status}`);\n lines.push(`detail: ${check.detail}`);\n lines.push(\"\");\n lines.push(\"remediation hint (informational):\");\n lines.push(` ${yankCommandForCheck(check)}`);\n lines.push(\"\");\n for (const ln of remediationParagraph(check)) lines.push(ln);\n return lines.join(\"\\n\");\n}\n","// In-progress popup (Shift+6 → `^`). The drill-down for the\n// In-progress card.\n//\n// Per feat_popup_6_inprogress (workstream `tui-impl`). Sibling of\n// popups/ready.tsx — list of IN_PROGRESS tasks with j/k nav, '/'\n// substring filter, y to yank `mu task close <id> --evidence \"...\"`,\n// and Enter to chain into the shared TaskDetailDrill leaf (the\n// recursion contract from feat_track_drill_chains_to_task_drill —\n// rows ARE tasks).\n//\n// Column shape mirrors Card 6 (cards/inprogress.tsx) but adds two\n// columns the card was too narrow to fit:\n// glyph id STATUS owner since-claim ROI title\n// Per feat_column_aligned_lists clipping policy: every cell except\n// `title` is identity-bearing and PROTECTED; only `title` is\n// CLIPPABLE. Wider title column than the card (more pixels here).\n//\n// All coordination logic lives in the shared TaskListPopup scaffold\n// (popups/task-list-popup.tsx); this file is the In-progress config.\n//\n// Per ROADMAP pledge: ink/react import limited to src/cli/tui/*.\n\nimport type { ReactElement } from \"react\";\nimport { formatPair } from \"../../../tasks/status.js\";\nimport { inkColorForPair } from \"../../format.js\";\nimport { agentByName, formatTaskOwnerDisplay } from \"../agent-display.js\";\nimport { GLYPH, isStale } from \"../cards/inprogress.js\";\nimport type { ColumnSpec } from \"../columns.js\";\nimport { ageMs, formatRoi, formatSinceClaim } from \"../format-helpers.js\";\nimport {\n type PopupProps,\n type RenderedRow,\n TaskListPopup,\n type TaskListPopupConfig,\n} from \"./task-list-popup.js\";\n\nconst COLUMN_SPECS: ReadonlyArray<ColumnSpec> = [\n { kind: \"protect\" }, // glyph\n { kind: \"protect\" }, // task id\n { kind: \"protect\" }, // status (always IN_PROGRESS; constant for now)\n { kind: \"protect\" }, // owner (or \"—\")\n { kind: \"protect\", align: \"right\" }, // since-claim\n { kind: \"protect\", align: \"right\" }, // ROI label\n { kind: \"clip\", min: 1 }, // title\n];\n\nconst config: TaskListPopupConfig = {\n label: \"In-progress\",\n sourceTasks: (snapshot) => snapshot.inProgress,\n columnSpecs: COLUMN_SPECS,\n // Per spec MATCHING RULES: search blob is `${id} ${title} ${owner ?? \"\"}`.\n filterBlob: (t) => `${t.name} ${t.title} ${t.ownerName ?? \"\"}`,\n emptyText: \"(none in progress)\",\n yankCommand: (t, ws) => yankCommandForTask(t.name, ws),\n hint: \"y yanks `mu task close <id> --evidence ...`\",\n renderRows: (visible, _start, snapshot): RenderedRow[] => {\n const now = Date.now();\n const agentLookup = agentByName(snapshot);\n return visible.map((t) => {\n const age = ageMs(t, now);\n const stale = isStale(age);\n return {\n cells: [\n GLYPH,\n t.name,\n formatPair(t),\n formatTaskOwnerDisplay(t, agentLookup),\n formatSinceClaim(age),\n formatRoi(t.impact, t.effortDays),\n t.title,\n ],\n colors: [\n { color: \"yellow\" }, // glyph\n { bold: true }, // id\n { color: inkColorForPair(t) }, // status\n { dimColor: true }, // owner\n stale ? { color: \"yellow\" } : { dimColor: true }, // since-claim\n { dimColor: true }, // roi\n undefined, // title\n ],\n };\n });\n },\n};\n\nexport function InProgressPopup(props: PopupProps): ReactElement {\n return <TaskListPopup config={config} {...props} />;\n}\n\n/**\n * Yank command for an IN_PROGRESS task row. The most likely\n * act-intent on the In-progress popup is closing the task with\n * grounding evidence (per the Tasks-popup yank matrix, `mu task\n * close <id> -w <ws> --evidence \"...\"` is the canonical\n * IN_PROGRESS verb). Stays consistent with popups/ready.tsx so the\n * operator's muscle memory transfers across popups. Pure; exported\n * for unit tests.\n */\nexport function yankCommandForTask(taskName: string, workstream: string): string {\n return `mu task close ${taskName} -w ${workstream} --evidence \"...\"`;\n}\n","// Activity-log popup (Shift+4 → `$`). Per design_popup_log.\n//\n// v0: list all snapshot.recent (newest at top), with j/k navigation.\n// Auto-tail with scroll-pause + filters are deferred to v0.next.\n//\n// Enter on a focused row drills into a read-only inline view of the\n// event's full untruncated payload. Long payloads (workspace-refresh\n// events, multi-field task.claim notes, multi-line task notes\n// summaries) clip in the list view per\n// bug_tui_log_card_columns_misaligned; the drill is the\n// single-source affordance for reading the full text. j/k scroll the\n// drilled payload; q/Esc back to list. (Earlier versions of this\n// popup left Enter UNBOUND on the assumption rows were always\n// single-line atoms; user feedback proved that wrong — wrapped\n// payloads needed the explicit drill-out.)\n//\n// Rows are column-aligned via src/cli/tui/columns.ts. Per\n// feat_column_aligned_lists clipping policy: seq, ts, source, verb\n// are PROTECTED (identity / numeric / short tokens); the payload rest\n// is CLIPPABLE.\n\nimport { Box, Text } from \"ink\";\nimport { type ReactElement, useState } from \"react\";\nimport type { Db } from \"../../../db.js\";\nimport { opSubject, renderOp, renderOpLine } from \"../../../log-render.js\";\nimport type { LogRow } from \"../../../logs.js\";\nimport type { WorkstreamSnapshot } from \"../../../state.js\";\nimport { type ColumnSpec, contentWidthFromCols, layoutColumns, renderRow } from \"../columns.js\";\nimport { dispatchPopupKeyFromInk, type PopupAction, type PopupActionEnvelope } from \"../keys.js\";\nimport { ListRow } from \"../list-row.js\";\nimport { usePopupInput } from \"../popup-input.js\";\nimport { PopupShell } from \"../popup-shell.js\";\nimport { usePopupActionQueue } from \"../use-popup-action-queue.js\";\nimport { applyFilter, FilterPrompt, listViewport, usePopupFilter } from \"../use-popup-filter.js\";\nimport { useTerminalSize } from \"../use-terminal-size.js\";\nimport { DrillScrollView, useDrillKeymap } from \"./drill.js\";\nimport { applyCursor, centredVisibleSlice, clickedItem, isNavAction } from \"./scroll.js\";\nimport { POPUP_DRILL_CHROME_ROWS, usePopupViewport } from \"./viewport.js\";\n\nexport interface PopupProps {\n yank: (command: string) => Promise<void>;\n onClose: () => void;\n snapshot: WorkstreamSnapshot | null;\n mode: \"list\" | \"drill\";\n onModeChange: (mode: \"list\" | \"drill\") => void;\n /** Bubbles the filter-prompt edit state up to <App> for StatusBar mode. */\n onFilterEditingChange?: (editing: boolean) => void;\n popupActions?: readonly PopupActionEnvelope[];\n db: Db;\n workstream: string;\n}\n\nconst COLUMN_SPECS: ReadonlyArray<ColumnSpec> = [\n { kind: \"protect\", align: \"right\" }, // seq (#N)\n { kind: \"protect\" }, // ts\n { kind: \"protect\" }, // source\n { kind: \"protect\" }, // verb (or '·' fallback)\n { kind: \"clip\", min: 1 }, // rest / payload\n];\n\nexport function LogPopup({\n yank,\n onClose,\n snapshot,\n mode,\n onModeChange,\n onFilterEditingChange,\n popupActions,\n}: PopupProps): ReactElement {\n const { cols } = useTerminalSize();\n const contentWidth = contentWidthFromCols(cols);\n // Per-render viewport from stdout.rows minus the popup chrome budget;\n // see popups/viewport.ts. Replaces the prior hardcoded VIEWPORT = 20\n // — used for BOTH the slice size AND the cursor-centring half-window.\n const viewport = usePopupViewport();\n const [cursor, setCursor] = useState(0);\n const flt = usePopupFilter({ onEditingChange: onFilterEditingChange });\n const rowsViewport = listViewport(viewport, flt);\n const drillViewport = usePopupViewport(POPUP_DRILL_CHROME_ROWS);\n const sourceEvents = snapshot?.recent ?? [];\n // Per spec: blob = `${verb} ${rest} ${source}`. Built from the SAME\n // formatter the rows render with, so '/' searches match what the user\n // actually sees (searching \"task close\" finds a task.close op).\n const events = applyFilter(sourceEvents, flt.query, (e) => `${renderOpLine(e)} ${e.source}`);\n const safeCursor = events.length === 0 ? 0 : Math.min(cursor, events.length - 1);\n const focused = events[safeCursor];\n // Pin the drilled event at Enter: new events arrive at the top and\n // the 200-event cap drops the oldest, so the cursor index alone\n // would slide the open drill onto a different event.\n const [drilledEvent, setDrilledEvent] = useState<LogRow | null>(null);\n const drillEvent = mode === \"drill\" ? (drilledEvent ?? focused) : focused;\n\n // Drill shows the prose FIRST (what the row says) then the raw op\n // payload, so the detail view is readable but still lossless.\n const drillBody =\n drillEvent === undefined\n ? \"\"\n : drillEvent.intent === null\n ? drillEvent.payload\n : `${renderOpLine(drillEvent)}\\n\\nintent: ${drillEvent.intent}\\nkey: ${drillEvent.workstreamName ?? \"—\"}\\ngroup: ${drillEvent.group}\\npayload: ${drillEvent.payload}`;\n const drill = useDrillKeymap({\n body: drillBody,\n viewport: drillViewport,\n onClose: () => {\n setDrilledEvent(null);\n onModeChange(\"list\");\n },\n onYank: () => {\n if (!drillEvent || !snapshot) return;\n const since = Math.max(0, drillEvent.seq - 1);\n return yank(`mu log --since ${since} -n 1 -w ${snapshot.workstreamName}`);\n },\n resetKey: drillEvent?.seq ?? \"\",\n });\n\n const dispatchListAction = (action: PopupAction) => {\n if (mode === \"drill\") {\n drill.dispatch(action);\n return;\n }\n if (isNavAction(action)) {\n setCursor((c) => applyCursor(c, action, events.length, rowsViewport));\n return;\n }\n switch (action.kind) {\n case \"close\":\n onClose();\n return;\n case \"filter\":\n flt.startEdit();\n return;\n case \"drill\":\n if (focused !== undefined) {\n setDrilledEvent(focused);\n onModeChange(\"drill\");\n }\n return;\n case \"clickRow\": {\n const hit = clickedItem(events, safeCursor, rowsViewport, action.row);\n if (!hit) return;\n setCursor(hit.index);\n setDrilledEvent(hit.item);\n onModeChange(\"drill\");\n return;\n }\n case \"yank\": {\n const e = events[safeCursor];\n if (!e || !snapshot) return;\n // Yank the show-related-task / show-related-agent if we\n // can classify; else just yank the raw payload as a\n // reference.\n const payload = e.payload;\n // Resolve from intent + natural key where available, prose\n // otherwise (v2-retire-log-shim).\n const subject = opSubject(e);\n if (subject === null) {\n void yank(`# event: ${payload}`);\n return;\n }\n void yank(`mu ${subject.kind} show ${subject.id} -w ${snapshot.workstreamName}`);\n return;\n }\n }\n };\n\n usePopupActionQueue(popupActions, dispatchListAction);\n\n usePopupInput((input, key) => {\n if (mode !== \"drill\" && flt.onKey(input, key) === \"consumed\") return;\n dispatchListAction(dispatchPopupKeyFromInk(input, key));\n });\n\n if (snapshot === null) {\n return <PopupShell title=\"Activity log · popup\">{<Text dimColor>loading…</Text>}</PopupShell>;\n }\n if (mode === \"drill\" && drillEvent !== undefined) {\n return (\n <PopupShell\n title={`Activity log · #${drillEvent.seq} (${drillEvent.createdAt.slice(11, 19)})`}\n >\n <Box flexDirection=\"column\" flexGrow={1}>\n <DrillScrollView\n title=\"event payload\"\n body={drillBody}\n viewport={drillViewport}\n scrollTop={drill.scrollTop}\n wrappedBody={drill.wrappedBody}\n emptyText=\"(empty payload)\"\n hint=\"y yanks `mu log --since N -n 1`\"\n />\n </Box>\n </PopupShell>\n );\n }\n if (sourceEvents.length === 0) {\n return (\n <PopupShell title=\"Activity log · popup\">\n <Text dimColor>(no events yet)</Text>\n </PopupShell>\n );\n }\n if (events.length === 0) {\n return (\n <PopupShell title=\"Activity log · popup\">\n <Box flexDirection=\"column\" flexGrow={1}>\n <Text dimColor>(no matches for \"{flt.query}\")</Text>\n </Box>\n <FilterPrompt state={flt} />\n </PopupShell>\n );\n }\n\n // Centre the cursor in the viewport. `viewport` is BOTH the slice\n // size and the half-window for centring — must use the per-render\n // value consistently (see CAVEAT in bug_tui_popup_data_doesnt_fill).\n const { visible } = centredVisibleSlice(events, safeCursor, rowsViewport);\n\n const rows = visible.map((e) => {\n const r = renderOp(e);\n const ts = e.createdAt.slice(11, 19);\n const verb = r?.verb ?? \"·\";\n const rest = r === null ? e.payload : [r.subject, r.detail].filter((x) => x !== \"\").join(\" \");\n return [`#${e.seq}`, ts, e.source, verb, rest];\n });\n const widths = layoutColumns(rows, COLUMN_SPECS, contentWidth);\n\n return (\n <PopupShell\n title={`Activity log · popup (${safeCursor + 1}/${events.length})`}\n hint=\"y yanks the related `mu task/agent show` command\"\n >\n <Box flexDirection=\"column\" flexGrow={1}>\n {visible.map((e, i) => {\n const sel = events.indexOf(e) === safeCursor;\n const row = rows[i];\n if (row === undefined) return null;\n const padded = renderRow(row, widths, COLUMN_SPECS);\n const colors = [\n { dimColor: true }, // seq\n { dimColor: true }, // ts\n { dimColor: true }, // source\n e.intent === null ? { dimColor: true } : { color: \"cyan\" }, // verb\n undefined, // rest\n ];\n return (\n <ListRow\n key={e.seq}\n cells={padded}\n contentWidth={contentWidth}\n colors={colors}\n selected={sel}\n />\n );\n })}\n </Box>\n <FilterPrompt state={flt} />\n </PopupShell>\n );\n}\n","// Tasks popup (Shift+3 → `#`). The drill-down for the Ready card.\n//\n// Per design_popup_tasks (workstream `tui`): list of OPEN/IN_PROGRESS\n// tasks with a yank-matrix per task state. v0 ships the list + a\n// subset of the matrix:\n// OPEN ready (no owner) → mu task claim <id> -w <ws>\n// OPEN owned → mu task release <id> -w <ws>\n// IN_PROGRESS owned-by-self → mu task close <id> -w <ws> --evidence \"...\"\n// CLOSED → mu task open <id> -w <ws>\n// Other states yield no yank (toast says so).\n//\n// Enter on a task drills into a read-only inline view of every note\n// on the task (the equivalent of `mu task notes <id>`). j/k scroll;\n// Esc / q backs out to the list; second Esc / q closes the popup.\n//\n// All coordination logic (filter, drill pinning, yank wiring, the\n// early-return states) lives in the shared TaskListPopup scaffold\n// (popups/task-list-popup.tsx). This file is the Ready config: source\n// list, column specs, row mapper/colors, and the yank matrix.\n\nimport type { ReactElement } from \"react\";\nimport { formatPair } from \"../../../tasks/status.js\";\nimport { inkColorForPair } from \"../../format.js\";\nimport { agentByName, formatTaskOwnerDisplay } from \"../agent-display.js\";\nimport type { ColumnSpec } from \"../columns.js\";\nimport {\n type PopupProps,\n type RenderedRow,\n TaskListPopup,\n type TaskListPopupConfig,\n} from \"./task-list-popup.js\";\n\nconst COLUMN_SPECS: ReadonlyArray<ColumnSpec> = [\n { kind: \"protect\" }, // task name\n { kind: \"protect\" }, // status\n { kind: \"protect\" }, // owner (or \"—\")\n { kind: \"clip\", min: 1 }, // title\n];\n\nconst config: TaskListPopupConfig = {\n label: \"Tasks\",\n sourceTasks: (snapshot) => [...snapshot.ready, ...snapshot.inProgress],\n columnSpecs: COLUMN_SPECS,\n filterBlob: (t) => `${t.name} ${t.title} ${formatPair(t)} ${t.ownerName ?? \"\"}`,\n emptyText: \"(no open / in-progress tasks)\",\n yankCommand: (t, ws) => yankCommandForTask(t, ws),\n dynamicHint: (focused, ws) => yankCommandForTask(focused, ws),\n renderRows: (visible, _start, snapshot): RenderedRow[] => {\n const agentLookup = agentByName(snapshot);\n return visible.map((t) => ({\n cells: [t.name, formatPair(t), formatTaskOwnerDisplay(t, agentLookup), t.title],\n colors: [\n { bold: true }, // name\n { color: inkColorForPair(t) }, // status\n { dimColor: true }, // owner\n undefined, // title\n ],\n }));\n },\n};\n\nexport function ReadyPopup(props: PopupProps): ReactElement {\n return <TaskListPopup config={config} {...props} />;\n}\n\nexport function yankCommandForTask(\n t: { name: string; status: string; substate?: string; ownerName: string | null },\n ws: string,\n): string | null {\n switch (t.status) {\n case \"OPEN\":\n if (t.substate === \"parked\") return `mu task unpark ${t.name} -w ${ws}`;\n if (t.substate === \"triage\") return `mu task accept ${t.name} -w ${ws}`;\n return t.ownerName === null\n ? `mu task claim ${t.name} -w ${ws}`\n : `mu task release ${t.name} -w ${ws}`;\n case \"IN_PROGRESS\":\n return `mu task close ${t.name} -w ${ws} --evidence \"...\"`;\n case \"CLOSED\":\n return `mu task open ${t.name} -w ${ws}`;\n default:\n return null;\n }\n}\n","// Recent popup (Shift+8 → `*`). The drill-down for the Recent card.\n//\n// Per feat_popup_8_recent (workstream `tui-impl`). Sibling of\n// popups/inprogress.tsx and popups/ready.tsx — list of recently\n// CLOSED tasks with j/k nav, '/' substring filter, y to yank\n// `mu task open <id> -w <ws>` (re-open is the typical act-intent\n// for a recently-closed task per the popups/ready.tsx CLOSED\n// branch of the yank matrix), and Enter to chain into the shared\n// TaskDetailDrill leaf (the recursion contract from\n// feat_track_drill_chains_to_task_drill — rows ARE tasks).\n//\n// Column shape mirrors Card 8 (cards/recent.tsx) but adds two\n// columns the card was too narrow to fit:\n// glyph id STATUS updated impact effort ROI title\n// (\"updated\" is updated_at, a proxy for close time: a later note or\n// edge on a CLOSED task bumps it.)\n// Per feat_column_aligned_lists clipping policy: every cell except\n// `title` is identity-bearing and PROTECTED; only `title` is\n// CLIPPABLE. Wider title column than the card (more pixels here).\n//\n// All coordination logic lives in the shared TaskListPopup scaffold\n// (popups/task-list-popup.tsx); this file is the Recent config.\n//\n// Per ROADMAP pledge: ink/react import limited to src/cli/tui/*.\n\nimport type { ReactElement } from \"react\";\nimport { formatPair } from \"../../../tasks/status.js\";\nimport { inkColorForPair } from \"../../format.js\";\nimport { GLYPH } from \"../cards/recent.js\";\nimport type { ColumnSpec } from \"../columns.js\";\nimport { ageMs, formatRoi, formatWhen } from \"../format-helpers.js\";\nimport {\n type PopupProps,\n type RenderedRow,\n TaskListPopup,\n type TaskListPopupConfig,\n} from \"./task-list-popup.js\";\n\nconst COLUMN_SPECS: ReadonlyArray<ColumnSpec> = [\n { kind: \"protect\" }, // glyph\n { kind: \"protect\" }, // task id\n { kind: \"protect\" }, // status (always CLOSED; constant for now)\n { kind: \"protect\", align: \"right\" }, // updated_at age (relative-time token)\n { kind: \"protect\", align: \"right\" }, // impact\n { kind: \"protect\", align: \"right\" }, // effort\n { kind: \"protect\", align: \"right\" }, // ROI label\n { kind: \"clip\", min: 1 }, // title\n];\n\nconst config: TaskListPopupConfig = {\n label: \"Recent\",\n sourceTasks: (snapshot) => snapshot.recentClosed,\n columnSpecs: COLUMN_SPECS,\n // Per spec MATCHING RULES: search blob is `${id} ${title} ${owner ?? \"\"}`.\n filterBlob: (t) => `${t.name} ${t.title} ${t.ownerName ?? \"\"}`,\n emptyText: \"(none recently closed)\",\n yankCommand: (t, ws) => yankCommandForTask(t.name, ws),\n hint: \"Enter notes · y yanks `mu task open` · / filter · Esc/q close\",\n renderRows: (visible): RenderedRow[] => {\n const now = Date.now();\n return visible.map((t) => ({\n cells: [\n GLYPH,\n t.name,\n formatPair(t),\n formatWhen(ageMs(t, now)),\n String(t.impact),\n String(t.effortDays),\n formatRoi(t.impact, t.effortDays),\n t.title,\n ],\n colors: [\n { color: \"green\" }, // glyph\n { bold: true }, // id\n { color: inkColorForPair(t) }, // status\n { dimColor: true }, // when\n { dimColor: true }, // impact\n { dimColor: true }, // effort\n { dimColor: true }, // roi\n undefined, // title\n ],\n }));\n },\n};\n\nexport function RecentPopup(props: PopupProps): ReactElement {\n return <TaskListPopup config={config} {...props} />;\n}\n\n/**\n * Yank command for a recently-CLOSED task row. The most likely\n * act-intent on the Recent popup is re-opening the task (per the\n * popups/ready.tsx CLOSED branch of the yank matrix: `mu task open\n * <id> -w <ws>`). Stays consistent so the operator's muscle memory\n * transfers across popups. Pure; exported for unit tests.\n */\nexport function yankCommandForTask(taskName: string, workstream: string): string {\n return `mu task open ${taskName} -w ${workstream}`;\n}\n","// Tracks popup (Shift+2 → `@`). Per design_popup_tracks +\n// feat_track_drill_chains_to_task_drill.\n//\n// Recursion ladder (per popup-drill recursion contract):\n// list → list of tracks (Enter drills)\n// drill → list of tasks for focused track (Enter chains)\n// task-detail → notes timeline for focused task (LEAF; no chain)\n//\n// Esc/q transitions: task-detail → drill → list → close popup.\n//\n// The top-level `mode` prop (owned by <App>) is still a 2-state\n// union (\"list\" | \"drill\") because app.tsx is currently being\n// edited by another agent (sibling task bug_tui_render_ghosting_v2);\n// task-detail is therefore an INTERNAL sub-state of the Tracks\n// popup, kept as a local useState. From <App>'s perspective Tracks\n// is in \"drill\" mode the entire time the user is below the list of\n// tracks, which is exactly what the status-bar drill hint cluster\n// already advertises (j/k scroll · Esc back). When the union is\n// widened to include \"task-detail\" (follow-up integration), this\n// local state collapses into the prop without changing semantics.\n//\n// Read-only: drilling reads from snapshot.tracks[i].taskIds and\n// resolves each id to a TaskRow via getTask; the leaf consumes\n// TaskDetailDrill which SELECTs notes via listNotes. Never executes.\n//\n// Rows are column-aligned via src/cli/tui/columns.ts. Per\n// feat_column_aligned_lists clipping policy: track number, merge glyph,\n// counts are PROTECTED; the goal-name list is CLIPPABLE.\n\nimport { Box, Text } from \"ink\";\nimport { type ReactElement, useEffect, useMemo, useState } from \"react\";\nimport type { Db } from \"../../../db.js\";\nimport { GLYPH } from \"../../../glyphs.js\";\nimport type { WorkstreamSnapshot } from \"../../../state.js\";\nimport { formatPair, type TaskPair } from \"../../../tasks/status.js\";\nimport { listTasks, type TaskRow } from \"../../../tasks.js\";\nimport type { Track } from \"../../../tracks.js\";\nimport { inkColorForPair } from \"../../format.js\";\nimport { type ColumnSpec, contentWidthFromCols, layoutColumns, renderRow } from \"../columns.js\";\nimport { dispatchPopupKeyFromInk, type PopupAction, type PopupActionEnvelope } from \"../keys.js\";\nimport { ListRow } from \"../list-row.js\";\nimport { usePopupInput } from \"../popup-input.js\";\nimport { PopupShell } from \"../popup-shell.js\";\nimport { usePopupActionQueue } from \"../use-popup-action-queue.js\";\nimport { applyFilter, FilterPrompt, listViewport, usePopupFilter } from \"../use-popup-filter.js\";\nimport { useTerminalSize } from \"../use-terminal-size.js\";\nimport { useDrillKeymap } from \"./drill.js\";\nimport { applyCursor, centredVisibleSlice, clickedItem, isNavAction } from \"./scroll.js\";\nimport { renderNotes, TaskDetailDrill } from \"./task-detail.js\";\nimport { POPUP_DRILL_CHROME_ROWS, usePopupViewport } from \"./viewport.js\";\n\nexport interface PopupProps {\n yank: (command: string) => Promise<void>;\n onClose: () => void;\n snapshot: WorkstreamSnapshot | null;\n fastTickNonce: number;\n mode: \"list\" | \"drill\";\n onModeChange: (mode: \"list\" | \"drill\") => void;\n /** Bubbles the filter-prompt edit state up to <App> for StatusBar mode. */\n onFilterEditingChange?: (editing: boolean) => void;\n popupActions?: readonly PopupActionEnvelope[];\n db: Db;\n workstream: string;\n}\n\nconst COLUMN_SPECS: ReadonlyArray<ColumnSpec> = [\n { kind: \"protect\" }, // \"Track N\"\n { kind: \"protect\" }, // diamond glyph (or empty)\n { kind: \"clip\", min: 1 }, // goal names\n { kind: \"protect\" }, // counts\n];\n\nconst DRILL_COLUMN_SPECS: ReadonlyArray<ColumnSpec> = [\n { kind: \"protect\" }, // task id\n { kind: \"protect\" }, // status\n { kind: \"clip\", min: 1 }, // title\n];\n\nconst TRACK_COLORS = [\n { color: \"cyan\" }, // Track N\n undefined, // diamond\n undefined, // goals\n { dimColor: true }, // counts\n] as const;\n\nfunction drillColors(t: TaskPair) {\n return [\n { bold: true }, // name\n { color: inkColorForPair(t) }, // status\n undefined, // title\n ];\n}\n\n// Internal sub-state of the drill view. \"task-list\" = the visible\n// list of tasks for the focused track (where the prop `mode` is\n// `\"drill\"`); \"task-detail\" = the deeper leaf view. See the file\n// header for why this isn't a third value on the prop union.\ntype DrillSubMode = \"task-list\" | \"task-detail\";\n\nexport function TracksPopup({\n yank,\n onClose,\n snapshot,\n fastTickNonce,\n mode,\n onModeChange,\n onFilterEditingChange,\n popupActions,\n db,\n workstream,\n}: PopupProps): ReactElement {\n const { cols } = useTerminalSize();\n const contentWidth = contentWidthFromCols(cols);\n // Per-render viewport from stdout.rows minus the popup chrome budget;\n // see popups/viewport.ts. `viewport` sizes the track list (minus the\n // filter prompt) and the task-list drill; the task-detail leaf is a\n // DrillScrollView, whose title + hint lines need the drill budget.\n const viewport = usePopupViewport();\n const detailViewport = usePopupViewport(POPUP_DRILL_CHROME_ROWS);\n const [cursor, setCursor] = useState(0);\n const [drillCursor, setDrillCursor] = useState(0);\n const [drillSubMode, setDrillSubMode] = useState<DrillSubMode>(\"task-list\");\n // The task-detail leaf is pinned to the task name set when it opens.\n // drillTasks is re-queried and status-sorted on every render, so an\n // index would switch the open leaf when a task changes status.\n const [leafTaskName, setLeafTaskName] = useState<string | null>(null);\n // Filter is only active at the top-level (list-of-tracks) view\n // per spec MATCHING RULES (Tracks blob = head_id + head_title).\n // Drill sub-views own their own navigation; widening the filter\n // to the task-list drill is a follow-up.\n const flt = usePopupFilter({ onEditingChange: onFilterEditingChange });\n const rowsViewport = listViewport(viewport, flt);\n const sourceTracks = snapshot?.tracks ?? [];\n // Per bug_filter_drill_opens_wrong_task: the filter applies in every\n // mode, so the cursor always indexes the list the user sees.\n const tracks = applyFilter(sourceTracks, flt.query, (t) => {\n const head = t.roots[0];\n return `${head?.name ?? \"\"} ${head?.title ?? \"\"}`;\n });\n const safeCursor = tracks.length === 0 ? 0 : Math.min(cursor, tracks.length - 1);\n const listFocusedTrack = tracks[safeCursor];\n // Pin the drilled track at Enter, matched by goal ids on refresh\n // (Track objects are rebuilt every tick), so a reordered or\n // re-filtered list cannot swap the open drill to another track.\n const [drilledTrackKey, setDrilledTrackKey] = useState<string | null>(null);\n const drilledTrack =\n drilledTrackKey === null\n ? undefined\n : sourceTracks.find((t) => trackKey(t) === drilledTrackKey);\n const focusedTrack = mode === \"drill\" ? (drilledTrack ?? listFocusedTrack) : listFocusedTrack;\n // Same numbering as the list rows (position in the filtered list).\n const trackNumber = focusedTrack === undefined ? 0 : tracks.indexOf(focusedTrack) + 1;\n\n // Reset sub-mode + leaf scroll whenever the popup itself flips\n // out of drill mode (e.g. user pressed Esc in the task-list view\n // and we're transitioning back to the list-of-tracks). The\n // entry-into-task-detail scroll reset lives at the keymap site\n // where setDrillSubMode(\"task-detail\") is dispatched.\n useEffect(() => {\n if (mode !== \"drill\") {\n setDrillSubMode(\"task-list\");\n setLeafTaskName(null);\n }\n }, [mode]);\n\n // Resolve the focused track's tasks with one workstream query. The old\n // per-id getTask loop issued two SQL reads per task, which made opening a\n // large track noticeably pause even though the full task list is cheap.\n const drillTasks = useMemo<TaskRow[]>(() => {\n if (mode !== \"drill\" || !focusedTrack) return [];\n const out = listTasks(db, workstream).filter((task) => focusedTrack.taskIds.has(task.name));\n out.sort((a, b) => statusRank(a) - statusRank(b) || a.name.localeCompare(b.name));\n return out;\n }, [mode, focusedTrack, db, workstream]);\n\n const focusedTask =\n drillSubMode === \"task-detail\"\n ? drillTasks.find((t) => t.name === leafTaskName)\n : drillTasks[drillCursor];\n const openLeaf = (index: number) => {\n const t = drillTasks[index];\n if (!t) return;\n setDrillCursor(index);\n setLeafTaskName(t.name);\n setDrillSubMode(\"task-detail\");\n };\n const notesBody = useMemo<string>(() => {\n void fastTickNonce;\n if (mode !== \"drill\" || drillSubMode !== \"task-detail\" || !focusedTask) return \"\";\n return renderNotes(db, focusedTask.name, workstream);\n }, [mode, drillSubMode, focusedTask, db, workstream, fastTickNonce]);\n const taskDetailDrill = useDrillKeymap({\n body: notesBody,\n viewport: detailViewport,\n onClose: () => {\n // Back on the task list, keep the cursor on the task the leaf showed.\n const index = drillTasks.findIndex((t) => t.name === leafTaskName);\n if (index >= 0) setDrillCursor(index);\n setLeafTaskName(null);\n setDrillSubMode(\"task-list\");\n },\n onYank: () => {\n if (!focusedTask || !snapshot) return;\n return yank(`mu task notes ${focusedTask.name} -w ${snapshot.workstreamName}`);\n },\n resetKey: focusedTask?.name ?? \"\",\n });\n\n const dispatchListAction = (action: PopupAction) => {\n if (mode === \"drill\" && drillSubMode === \"task-detail\") {\n taskDetailDrill.dispatch(action);\n return;\n }\n if (mode === \"drill\") {\n if (isNavAction(action)) {\n setDrillCursor((c) => applyCursor(c, action, drillTasks.length, viewport));\n return;\n }\n switch (action.kind) {\n case \"close\":\n onModeChange(\"list\");\n setDrillCursor(0);\n setDrilledTrackKey(null);\n return;\n case \"clickRow\": {\n const hit = clickedItem(drillTasks, drillCursor, viewport, action.row);\n if (!hit) return;\n openLeaf(hit.index);\n return;\n }\n case \"drill\": {\n // Chain into the task-detail leaf. This is the recursion\n // step the task asks for: Enter on a Tracks-drill row\n // opens the same notes view the Tasks popup drill renders.\n openLeaf(drillCursor);\n return;\n }\n case \"yank\": {\n const t = drillTasks[drillCursor];\n if (!t || !snapshot) return;\n void yank(`mu task show ${t.name} -w ${snapshot.workstreamName}`);\n return;\n }\n default:\n return;\n }\n }\n if (isNavAction(action)) {\n setCursor((c) => applyCursor(c, action, tracks.length, rowsViewport));\n return;\n }\n switch (action.kind) {\n case \"close\":\n onClose();\n return;\n case \"filter\":\n flt.startEdit();\n return;\n case \"drill\":\n if (listFocusedTrack) {\n setDrilledTrackKey(trackKey(listFocusedTrack));\n setDrillCursor(0);\n onModeChange(\"drill\");\n }\n return;\n case \"clickRow\": {\n const hit = clickedItem(tracks, safeCursor, rowsViewport, action.row);\n if (!hit) return;\n setCursor(hit.index);\n setDrilledTrackKey(trackKey(hit.item));\n setDrillCursor(0);\n onModeChange(\"drill\");\n return;\n }\n case \"yank\": {\n const t = tracks[safeCursor];\n if (!t || !snapshot) return;\n const goal = t.roots[0]?.name;\n if (!goal) return;\n const ws = snapshot.workstreamName;\n void yank(`mu task tree ${goal} -w ${ws}`);\n return;\n }\n }\n };\n\n usePopupActionQueue(popupActions, dispatchListAction);\n\n usePopupInput((input, key) => {\n if (mode === \"list\" && flt.onKey(input, key) === \"consumed\") return;\n dispatchListAction(dispatchPopupKeyFromInk(input, key));\n });\n\n if (snapshot === null) {\n return <PopupShell title=\"Tracks · popup\">{<Text dimColor>loading…</Text>}</PopupShell>;\n }\n if (sourceTracks.length === 0) {\n return (\n <PopupShell title=\"Tracks · popup\">\n <Text dimColor>(no goals — `mu task add ... --impact ...`)</Text>\n </PopupShell>\n );\n }\n if (mode === \"list\" && tracks.length === 0) {\n return (\n <PopupShell title=\"Tracks · popup\">\n <Box flexDirection=\"column\" flexGrow={1}>\n <Text dimColor>(no matches for \"{flt.query}\")</Text>\n </Box>\n <FilterPrompt state={flt} />\n </PopupShell>\n );\n }\n\n if (mode === \"drill\" && drillSubMode === \"task-detail\" && focusedTrack) {\n const t = focusedTask;\n if (t === undefined) {\n // The pinned task left this track (deleted, or the track split);\n // back to the task list. Render a benign placeholder; the next\n // render shows the task list once setDrillSubMode runs.\n setLeafTaskName(null);\n setDrillSubMode(\"task-list\");\n return (\n <PopupShell title={`Track ${trackNumber} · (resyncing)`}>\n <Text dimColor>(refocusing…)</Text>\n </PopupShell>\n );\n }\n return (\n <PopupShell title={`Track ${trackNumber} · task: ${t.name} (notes)`}>\n <Box flexDirection=\"column\" flexGrow={1}>\n <TaskDetailDrill\n task={t}\n db={db}\n workstream={workstream}\n scrollTop={taskDetailDrill.scrollTop}\n viewport={detailViewport}\n tickNonce={fastTickNonce}\n body={notesBody}\n wrappedBody={taskDetailDrill.wrappedBody}\n />\n </Box>\n </PopupShell>\n );\n }\n\n if (mode === \"drill\" && focusedTrack) {\n const trackLabel = `Track ${trackNumber}`;\n const goalSummary = focusedTrack.roots.map((r) => r.name).join(\", \");\n if (drillTasks.length === 0) {\n return (\n <PopupShell title={`${trackLabel} · ${goalSummary}`}>\n <Text dimColor>(no tasks resolved)</Text>\n </PopupShell>\n );\n }\n const { visible } = centredVisibleSlice(drillTasks, drillCursor, viewport);\n const rows = visible.map((t) => [t.name, formatPair(t), t.title]);\n const widths = layoutColumns(rows, DRILL_COLUMN_SPECS, contentWidth);\n return (\n <PopupShell\n title={`${trackLabel} · ${goalSummary} (${drillCursor + 1}/${drillTasks.length})`}\n hint=\"y yanks `mu task show`\"\n >\n <Box flexDirection=\"column\" flexGrow={1}>\n {visible.map((t, i) => {\n const sel = drillTasks.indexOf(t) === drillCursor;\n const row = rows[i];\n if (row === undefined) return null;\n const padded = renderRow(row, widths, DRILL_COLUMN_SPECS);\n return (\n <ListRow\n key={t.name}\n cells={padded}\n contentWidth={contentWidth}\n colors={drillColors(t)}\n selected={sel}\n />\n );\n })}\n </Box>\n </PopupShell>\n );\n }\n\n const { start, visible } = centredVisibleSlice(tracks, safeCursor, rowsViewport);\n const rows = visible.map((t, i) => {\n const absoluteIndex = start + i;\n const goalNames = t.roots.map((r) => r.name).join(\", \");\n const diamond = t.roots.length > 1 ? GLYPH.merge : \" \";\n const counts = `(${t.taskIds.size} tasks · ${t.readyCount} ready)${t.parked ? \" (parked)\" : \"\"}`;\n return [`Track ${absoluteIndex + 1}`, diamond, goalNames, counts];\n });\n const widths = layoutColumns(rows, COLUMN_SPECS, contentWidth);\n\n return (\n <PopupShell\n title={`Tracks · popup (${safeCursor + 1}/${tracks.length})`}\n hint=\"y yanks `mu task tree <head-id>`\"\n >\n <Box flexDirection=\"column\" flexGrow={1}>\n {visible.map((t, i) => {\n const sel = start + i === safeCursor;\n const row = rows[i];\n if (row === undefined) return null;\n const padded = renderRow(row, widths, COLUMN_SPECS);\n return (\n <ListRow\n // biome-ignore lint/suspicious/noArrayIndexKey: scroll-window position + track root name\n key={`tr-${start + i}-${t.roots[0]?.name ?? \"?\"}`}\n cells={padded}\n contentWidth={contentWidth}\n colors={TRACK_COLORS}\n selected={sel}\n />\n );\n })}\n </Box>\n <FilterPrompt state={flt} />\n </PopupShell>\n );\n}\n\n/** Stable identity for a track across refreshes: its goal ids. */\nfunction trackKey(t: Track): string {\n return t.roots.map((r) => r.name).join(\"\\0\");\n}\n\n/** Drill-view sort rank: work in flight first, then schedulable,\n * then set aside, then finished. */\nexport function statusRank(pair: TaskPair): number {\n switch (pair.status) {\n case \"IN_PROGRESS\":\n return 0;\n case \"OPEN\":\n return pair.substate === \"parked\" ? 2 : 1;\n case \"CLOSED\":\n return 3;\n }\n}\n","// Workspaces popup (Shift+5 → `%`). Drill-down for the Workspaces card.\n//\n// Per feat_popup_5_workspaces (workstream `tui-impl`): list of every\n// per-agent workspace in the workstream, with j/k navigation, '/'\n// filter (via use-popup-filter), and Enter to drill into the\n// commits-since-fork list (same data `mu workspace commits <agent>`\n// surfaces). The drill is the actionable lookup for the cherry-pick\n// loop: orient on which workspace has unmerged commits, then yank a\n// `cd` to that workspace's path.\n//\n// Per feat_workspaces_drill_git_show: a third, deeper level. Pressing\n// Enter on a focused commit in the commits-since-fork list drills\n// ONE MORE LEVEL into a read-only inline view of the actual\n// `git show <sha> --stat -p` output, rendered via the shared\n// <DrillScrollView> primitive (same one log.tsx uses for full\n// payload view). The popup's `mode` prop from <App> stays \"drill\"\n// while in the show view — the show level is a popup-local sub-mode\n// (the localMode state below) so we don't have to widen <App>'s\n// PopupMode union for one popup. j/k Ctrl-D/U scroll the diff; Esc/q back to\n// the commits list; y yanks the bare `git show <sha>` (the operator\n// gets the command, not the captured output).\n//\n// Mirrors the data exposed by Card 5 (cards/workspaces.tsx) — the\n// same WorkstreamSnapshot.workspaces[] rows decorated by\n// withDirty: true (already wired by state.ts) — and adds two columns\n// useful in the fullscreen view: dirty? and the workspace's on-disk\n// path. The card omits both (too narrow); the popup has the room.\n//\n// Read-only: the only act-intent is `y` which yanks\n// cd $(mu workspace path <agent> -w <ws>)\n// — the canonical entry to a workspace per skills/mu (cherry-pick /\n// inspection workflow). No mutating verbs surface here. The drill\n// view is also read-only: it RUNS `listCommitsForWorkspace` (a\n// backend `git log` / `jj log` / `sl log` SELECT-equivalent), never\n// a mutation.\n//\n// Drill is NOT TaskDetailDrill — workspaces aren't tasks. We render\n// commits as a column-aligned `<sha-short> <subject>` list with an\n// independent usePopupFilter applied so '/' substring search across\n// (sha+subject) works in 30+-commit workspaces too.\n//\n// Rows are column-aligned via src/cli/tui/columns.ts. Per\n// feat_column_aligned_lists clipping policy: glyph + agent name +\n// backend + behind + dirty? + parent_ref are PROTECTED (operators\n// yank them verbatim into shell commands); only the path column is\n// CLIPPABLE.\n//\n// Per ROADMAP pledge: ink/react import limited to src/cli/tui/*.\n\nimport { Box, Text } from \"ink\";\nimport { type ReactElement, useCallback, useEffect, useReducer, useRef, useState } from \"react\";\nimport type { Db } from \"../../../db.js\";\nimport type { WorkstreamSnapshot } from \"../../../state.js\";\nimport { type CommitSummary, detectBackend } from \"../../../vcs.js\";\nimport { listCommitsForWorkspace, type WorkspaceRow } from \"../../../workspace.js\";\nimport { agentByName, formatAgentRefDisplayName } from \"../agent-display.js\";\nimport { colorForBehind, colorForGlyph, formatBehind, glyphFor } from \"../cards/workspaces.js\";\nimport { type ColumnSpec, contentWidthFromCols, layoutColumns, renderRow } from \"../columns.js\";\nimport { dispatchPopupKeyFromInk, type PopupAction, type PopupActionEnvelope } from \"../keys.js\";\nimport { ListRow } from \"../list-row.js\";\nimport { usePopupInput } from \"../popup-input.js\";\nimport { PopupShell } from \"../popup-shell.js\";\nimport { runTuicrInteractive } from \"../tuicr.js\";\nimport { usePopupActionQueue } from \"../use-popup-action-queue.js\";\nimport { applyFilter, FilterPrompt, listViewport, usePopupFilter } from \"../use-popup-filter.js\";\nimport { useTerminalSize } from \"../use-terminal-size.js\";\nimport { DrillScrollView, useDrillKeymap } from \"./drill.js\";\nimport { applyCursor, centredVisibleSlice, clickedItem, isNavAction } from \"./scroll.js\";\nimport { loadShowPreservingBody } from \"./show-loader.js\";\nimport { POPUP_DRILL_CHROME_ROWS, usePopupViewport } from \"./viewport.js\";\n\nexport interface PopupProps {\n yank: (command: string) => Promise<void>;\n onClose: () => void;\n snapshot: WorkstreamSnapshot | null;\n slowTickNonce: number;\n mode: \"list\" | \"drill\";\n onModeChange: (mode: \"list\" | \"drill\") => void;\n /** Bubbles the filter-prompt edit state up to <App> for StatusBar mode. */\n onFilterEditingChange?: (editing: boolean) => void;\n popupActions?: readonly PopupActionEnvelope[];\n onFooter?: (command: string, copied: boolean, tone?: \"normal\" | \"info\" | \"error\") => void;\n db: Db;\n workstream: string;\n}\n\nconst COLUMN_SPECS: ReadonlyArray<ColumnSpec> = [\n { kind: \"protect\" }, // status glyph\n { kind: \"protect\" }, // agent name\n { kind: \"protect\" }, // backend\n { kind: \"protect\", align: \"right\" }, // commits-behind\n { kind: \"protect\" }, // dirty? (yes / no / —)\n { kind: \"protect\" }, // parent_ref short\n { kind: \"clip\", min: 1 }, // path\n];\n\nconst DRILL_COLUMN_SPECS: ReadonlyArray<ColumnSpec> = [\n { kind: \"protect\" }, // sha short\n { kind: \"clip\", min: 1 }, // subject\n];\n\nconst COMMIT_COLORS = [\n { color: \"yellow\" }, // sha\n undefined, // subject\n] as const;\n\ntype LocalMode = \"list\" | \"commits\" | \"show\";\n\ninterface LocalModeState {\n mode: LocalMode;\n drilledWorkspace: WorkspaceRow | null;\n showSha: string | null;\n showText: string;\n showLoading: boolean;\n showErr: string | null;\n}\n\ntype LocalModeAction =\n | { kind: \"leaveDrill\" }\n | { kind: \"enterDrill\"; workspace: WorkspaceRow }\n | { kind: \"enterShow\"; sha: string }\n | { kind: \"leaveShow\" }\n | { kind: \"resetForWorkspace\"; agentName: string | undefined }\n | { kind: \"setShowText\"; text: string }\n | { kind: \"setShowLoading\"; loading: boolean }\n | { kind: \"setShowError\"; error: string | null };\n\nconst LOCAL_MODE_INITIAL_STATE: LocalModeState = {\n mode: \"list\",\n drilledWorkspace: null,\n showSha: null,\n showText: \"\",\n showLoading: false,\n showErr: null,\n};\n\nfunction clearShowState(state: LocalModeState): LocalModeState {\n return { ...state, showSha: null, showText: \"\", showLoading: false, showErr: null };\n}\n\nfunction localModeReducer(state: LocalModeState, action: LocalModeAction): LocalModeState {\n switch (action.kind) {\n case \"leaveDrill\":\n return LOCAL_MODE_INITIAL_STATE;\n case \"enterDrill\":\n return { ...clearShowState(state), mode: \"commits\", drilledWorkspace: action.workspace };\n case \"enterShow\":\n return { ...state, mode: \"show\", showSha: action.sha };\n case \"leaveShow\":\n return { ...state, mode: \"commits\", showSha: null };\n case \"resetForWorkspace\":\n if (state.mode === \"list\") return state;\n if (state.drilledWorkspace?.agentName === action.agentName) return state;\n return { ...clearShowState(state), mode: \"commits\" };\n case \"setShowText\":\n return { ...state, showText: action.text };\n case \"setShowLoading\":\n return { ...state, showLoading: action.loading };\n case \"setShowError\":\n return { ...state, showErr: action.error };\n }\n}\n\n// Both drill views render a title line above and a hint line below\n// their rows (commits list: renderDrillBody; git show: DrillScrollView),\n// so they use the drill chrome budget. List view uses the default.\nconst WORKSPACES_DRILL_CHROME = POPUP_DRILL_CHROME_ROWS;\n// The commits drill's title line sits above its first data row.\nconst COMMITS_DRILL_HEADER_ROWS = 1;\n\nexport function WorkspacesPopup({\n yank,\n onClose,\n snapshot,\n slowTickNonce,\n mode,\n onModeChange,\n onFilterEditingChange,\n popupActions,\n onFooter,\n db,\n workstream,\n}: PopupProps): ReactElement {\n const { cols } = useTerminalSize();\n const contentWidth = contentWidthFromCols(cols);\n // Per-render viewport from stdout.rows minus the popup chrome budget;\n // see popups/viewport.ts. Replaces the prior hardcoded VIEWPORT = 20.\n // Workspaces popup uses the viewport in the DRILL view (centring\n // + page nav for the commits-since-fork list); list view\n // paginates by single-row cursor moves under j/k AND also consumes\n // the viewport for the centralised Ctrl-D/U / PgUp/PgDn page-step\n // bindings (per feat_centralize_scroll_navigation). Drill subtracts\n // an extra row for its in-body title indicator\n // (see WORKSPACES_DRILL_CHROME above).\n const viewport = usePopupViewport();\n const drillViewport = usePopupViewport(WORKSPACES_DRILL_CHROME);\n const [cursor, setCursor] = useState(0);\n // Drill-mode state. Owned here (not in <App>) because it's\n // popup-local: <App> only tracks the list/drill mode flag for\n // StatusBar purposes. Cursor + commit list + load state die with\n // the popup.\n const [drillCursor, setDrillCursor] = useState(0);\n const [commits, setCommits] = useState<readonly CommitSummary[]>([]);\n const [drillErr, setDrillErr] = useState<string | null>(null);\n const [loading, setLoading] = useState(false);\n // Popup-local sub-mode. <App> still only tracks \"list\" | \"drill\"\n // for the StatusBar; inside the workspaces popup, the drill branch\n // is explicit: commits list vs git-show body. `showSha` is only\n // meaningful while localMode === \"show\".\n const [localModeState, dispatchLocalMode] = useReducer(\n localModeReducer,\n LOCAL_MODE_INITIAL_STATE,\n );\n const localMode: LocalMode = mode === \"drill\" ? localModeState.mode : \"list\";\n const inShow = localMode === \"show\";\n const { showSha, showText, showLoading, showErr } = localModeState;\n\n // Two independent filter instances: one for the workspace list,\n // one for the commits drill view. Each '/' edit applies to the\n // currently-rendered list only. The `enabled` prop tells each\n // instance whether it's the currently-active filter; the hook\n // bubbles the editing flag up to <App> for the active one and\n // bubbles `false` for the inactive one — no hand-rolled\n // conditional useEffect at the call site\n // (per review_tui_workspaces_two_filter_instances). Show-mode\n // never edits a filter (read-only diff view) so both instances\n // are disabled while localMode === \"show\".\n const flt = usePopupFilter({\n enabled: !inShow && mode !== \"drill\",\n onEditingChange: onFilterEditingChange,\n });\n const drillFlt = usePopupFilter({\n enabled: !inShow && mode === \"drill\",\n onEditingChange: onFilterEditingChange,\n });\n\n const rowsViewport = listViewport(viewport, flt);\n const commitsViewport = listViewport(drillViewport, drillFlt);\n\n const sourceWorkspaces = snapshot?.workspaces ?? [];\n // Per bug_filter_drill_opens_wrong_task: text filter applied\n // UNIFORMLY across list and drill modes (the previous mode-conditional\n // dropped the filter on drill, shifting `workspaces` under a constant\n // cursor index).\n const workspaces = applyFilter(\n sourceWorkspaces,\n flt.query,\n (w) => `${w.agentName} ${w.backend} ${w.parentRef ?? \"\"} ${w.dirty === true ? \"dirty\" : \"\"}`,\n );\n const safeCursor = workspaces.length === 0 ? 0 : Math.min(cursor, workspaces.length - 1);\n const focusedListRow = workspaces[safeCursor];\n // Defensive: capture focused workspace at Enter so the drill stays\n // pinned to the workspace the user visually selected.\n const drilledWorkspace = localModeState.drilledWorkspace;\n const focused = localMode === \"list\" ? focusedListRow : (drilledWorkspace ?? focusedListRow);\n const projectRoot = process.cwd();\n\n /** Thin React glue around the shared VcsBackend.showCommit seam. */\n const loadShow = useCallback(async (path: string, sha: string) => {\n await loadShowPreservingBody(path, sha, detectBackend, {\n setText: (text) => dispatchLocalMode({ kind: \"setShowText\", text }),\n setError: (error) => dispatchLocalMode({ kind: \"setShowError\", error }),\n setLoading: (loading) => dispatchLocalMode({ kind: \"setShowLoading\", loading }),\n });\n }, []);\n\n // Filtered commits view (drill-mode equivalent of `workspaces`).\n const filteredCommits = applyFilter(commits, drillFlt.query, (c) => `${c.sha} ${c.subject}`);\n const safeDrillCursor =\n filteredCommits.length === 0 ? 0 : Math.min(drillCursor, filteredCommits.length - 1);\n const focusedCommit = filteredCommits[safeDrillCursor];\n\n // Load commits when entering drill mode (or when the focused row\n // changes while in drill mode — same-shape lazy fetch as\n // AgentsPopup's loadScrollback). listCommitsForWorkspace is a\n // backend `git log`-equivalent; never a mutation.\n const loadCommits = useCallback(\n async (agentName: string) => {\n setLoading(true);\n setDrillErr(null);\n try {\n const r = await listCommitsForWorkspace(db, agentName, { workstream });\n // Newest-first reads better in a \"what's stacked on top of\n // fork?\" view; the backend returns oldest-first. Reverse a\n // copy (don't mutate the source).\n setCommits([...r.commits].reverse());\n } catch (e) {\n setDrillErr(e instanceof Error ? e.message : String(e));\n setCommits([]);\n } finally {\n setLoading(false);\n }\n },\n [db, workstream],\n );\n\n const focusedAgentName = focused?.agentName;\n const previousFocusedAgentName = useRef<string | undefined>(undefined);\n const resetDrillFilter = drillFlt.reset;\n useEffect(() => {\n const focusedChanged = previousFocusedAgentName.current !== focusedAgentName;\n previousFocusedAgentName.current = focusedAgentName;\n\n if (focusedChanged) {\n dispatchLocalMode({ kind: \"resetForWorkspace\", agentName: focusedAgentName });\n setDrillCursor(0);\n setCommits([]);\n resetDrillFilter();\n }\n if (mode !== \"drill\") {\n dispatchLocalMode({ kind: \"leaveDrill\" });\n setCommits([]);\n setDrillErr(null);\n setLoading(false);\n }\n }, [mode, focusedAgentName, resetDrillFilter]);\n\n useEffect(() => {\n void slowTickNonce;\n if (localMode === \"commits\" && focused) {\n void loadCommits(focused.agentName);\n }\n }, [localMode, focused, loadCommits, slowTickNonce]);\n\n const showBody = showErr !== null ? `error: ${showErr}` : showText;\n useEffect(() => {\n void slowTickNonce;\n if (localMode === \"show\" && focused !== undefined && showSha !== null) {\n void loadShow(focused.path, showSha);\n }\n }, [localMode, focused, showSha, loadShow, slowTickNonce]);\n\n const showDrill = useDrillKeymap({\n body: showBody,\n viewport: drillViewport,\n onClose: () => dispatchLocalMode({ kind: \"leaveShow\" }),\n onYank: () => {\n if (showSha !== null) return yank(`git show ${showSha}`);\n },\n onTuicr: () => {\n if (showSha === null) return;\n const r = runTuicrInteractive({ rev: showSha, cwd: projectRoot });\n if (!r.ok) onFooter?.(r.error ?? \"tuicr failed\", false, \"error\");\n else onFooter?.(`tuicr -r ${showSha}`, true, \"info\");\n },\n resetKey: showSha ?? \"\",\n });\n\n const dispatchListAction = (action: PopupAction) => {\n if (localMode === \"show\") {\n showDrill.dispatch(action);\n return;\n }\n if (localMode === \"commits\") {\n // Drill-mode commits list: nav funnels through applyCursor.\n // '/' filters the commits list, Enter drills ONE MORE LEVEL\n // into the focused commit's `git show` diff\n // (feat_workspaces_drill_git_show), Esc/q backs out to the\n // workspace list. Yank in drill mode yanks `git show <sha>`\n // for the focused commit (cherry-pick target inspection).\n if (isNavAction(action)) {\n setDrillCursor((c) => applyCursor(c, action, filteredCommits.length, commitsViewport));\n return;\n }\n switch (action.kind) {\n case \"close\":\n dispatchLocalMode({ kind: \"leaveDrill\" });\n onModeChange(\"list\");\n return;\n case \"filter\":\n drillFlt.startEdit();\n return;\n case \"drill\": {\n const c = focusedCommit;\n if (!c || !focused) return;\n dispatchLocalMode({ kind: \"enterShow\", sha: c.sha });\n return;\n }\n case \"clickRow\": {\n const hit = clickedItem(\n filteredCommits,\n safeDrillCursor,\n commitsViewport,\n action.row,\n COMMITS_DRILL_HEADER_ROWS,\n );\n if (!hit || !focused) return;\n setDrillCursor(hit.index);\n dispatchLocalMode({ kind: \"enterShow\", sha: hit.item.sha });\n return;\n }\n case \"yank\": {\n const c = focusedCommit;\n if (!c) return;\n // Cherry-pick recipe per skills/mu: `git cherry-pick <sha>`\n // is the canonical follow-on. Yank the bare `git show` for\n // the focused commit so the operator can inspect first.\n void yank(`git show ${c.sha}`);\n return;\n }\n default:\n return;\n }\n }\n if (isNavAction(action)) {\n setCursor((c) => applyCursor(c, action, workspaces.length, rowsViewport));\n return;\n }\n switch (action.kind) {\n case \"close\":\n onClose();\n return;\n case \"filter\":\n flt.startEdit();\n return;\n case \"drill\":\n if (focusedListRow) {\n dispatchLocalMode({ kind: \"enterDrill\", workspace: focusedListRow });\n onModeChange(\"drill\");\n }\n return;\n case \"clickRow\": {\n const hit = clickedItem(workspaces, safeCursor, rowsViewport, action.row);\n if (!hit) return;\n setCursor(hit.index);\n dispatchLocalMode({ kind: \"enterDrill\", workspace: hit.item });\n onModeChange(\"drill\");\n return;\n }\n case \"yank\": {\n const w = focusedListRow;\n if (!w || !snapshot) return;\n const ws = snapshot.workstreamName;\n // Default yank: `cd $(mu workspace path <agent> -w <ws>)` —\n // the canonical entry to a workspace per skills/mu's\n // cherry-pick / inspection-workflow recipe.\n void yank(`cd $(mu workspace path ${w.agentName} -w ${ws})`);\n return;\n }\n }\n };\n\n usePopupActionQueue(popupActions, dispatchListAction);\n\n usePopupInput((input, key) => {\n // Filter-mode keystrokes consume printable + Esc/Enter/Bksp.\n // The active filter depends on which view we're rendering.\n // Show-mode is read-only — no filter prompt — so we skip the\n // consume check entirely (lets Esc fire as close, not\n // filter-cancel).\n const activeFlt = localMode === \"commits\" ? drillFlt : flt;\n if (localMode !== \"show\" && activeFlt.onKey(input, key) === \"consumed\") return;\n dispatchListAction(dispatchPopupKeyFromInk(input, key));\n });\n\n if (snapshot === null) {\n return <PopupShell title=\"Workspaces · popup\">{<Text dimColor>loading…</Text>}</PopupShell>;\n }\n if (localMode === \"show\" && showSha !== null && focused) {\n const shortSha = showSha.slice(0, 12);\n return (\n <PopupShell title={`Workspaces · git show ${shortSha}`}>\n <Box flexDirection=\"column\" flexGrow={1}>\n <DrillScrollView\n title={`git show ${shortSha} (${focused.agentName})`}\n body={showBody}\n viewport={drillViewport}\n scrollTop={showDrill.scrollTop}\n wrappedBody={showDrill.wrappedBody}\n hint={`y yanks \\`git show ${shortSha}\\` · t tuicr`}\n emptyText={showLoading ? \"loading…\" : \"(empty diff)\"}\n />\n </Box>\n </PopupShell>\n );\n }\n if (sourceWorkspaces.length === 0) {\n return (\n <PopupShell title=\"Workspaces · popup\">\n <Text dimColor>\n (no workspaces) try `mu agent spawn worker-1 -w {snapshot.workstreamName} --workspace`\n </Text>\n </PopupShell>\n );\n }\n if (localMode === \"list\" && workspaces.length === 0) {\n return (\n <PopupShell title=\"Workspaces · popup\">\n <Box flexDirection=\"column\" flexGrow={1}>\n <Text dimColor>(no matches for \"{flt.query}\")</Text>\n </Box>\n <FilterPrompt state={flt} />\n </PopupShell>\n );\n }\n\n if (localMode === \"commits\" && focused) {\n return (\n <PopupShell title={`Workspaces · ${focused.agentName} (commits since fork)`}>\n <Box flexDirection=\"column\" flexGrow={1}>\n {renderDrillBody(\n commits,\n filteredCommits,\n safeDrillCursor,\n loading,\n drillErr,\n focused,\n contentWidth,\n commitsViewport,\n )}\n </Box>\n <FilterPrompt state={drillFlt} />\n </PopupShell>\n );\n }\n\n const { start, visible } = centredVisibleSlice(workspaces, safeCursor, rowsViewport);\n const agentLookup = agentByName(snapshot);\n const rows = visible.map((w) => [\n glyphFor(w),\n formatAgentRefDisplayName(w.agentName, agentLookup),\n w.backend,\n formatBehind(w.commitsBehindMain),\n formatDirty(w.dirty),\n w.parentRef ? w.parentRef.slice(0, 12) : \"—\",\n w.path,\n ]);\n const widths = layoutColumns(rows, COLUMN_SPECS, contentWidth);\n\n return (\n <PopupShell\n title={`Workspaces · popup (${safeCursor + 1}/${workspaces.length})`}\n hint=\"y yanks `cd $(mu workspace path <agent>)`\"\n >\n <Box flexDirection=\"column\" flexGrow={1}>\n {visible.map((w, i) => {\n const sel = start + i === safeCursor;\n const row = rows[i];\n if (row === undefined) return null;\n const padded = renderRow(row, widths, COLUMN_SPECS);\n const colors = [\n { color: colorForGlyph(w) }, // glyph\n { bold: true }, // name\n { dimColor: true }, // backend\n { color: colorForBehind(w.commitsBehindMain) }, // behind\n { color: colorForDirty(w.dirty) }, // dirty\n { dimColor: true }, // parent\n { dimColor: true }, // path\n ];\n return (\n <ListRow\n key={w.agentName}\n cells={padded}\n contentWidth={contentWidth}\n colors={colors}\n selected={sel}\n />\n );\n })}\n </Box>\n <FilterPrompt state={flt} />\n </PopupShell>\n );\n}\n\n// ─── pure helpers (exported for unit tests) ────────────────────────\n\n/** Render the dirty? cell. \"yes\" when dirty, \"no\" when clean,\n * \"—\" when unknown (workspace decoration failed or backend has no\n * dirty concept). Mirrors the card's three-glyph state space. */\nexport function formatDirty(d: boolean | null | undefined): string {\n if (d === undefined || d === null) return \"—\";\n return d ? \"yes\" : \"no\";\n}\n\n/** Picocolors-compatible colour name for the dirty? cell. Red for\n * dirty (load-bearing — uncommitted work to deal with); dim for\n * clean / unknown so the eye snaps to the actionable rows. */\nexport function colorForDirty(d: boolean | null | undefined): string | undefined {\n if (d === true) return \"red\";\n return undefined;\n}\n\n// ─── drill body renderer ───────────────────────────────────────────\n\nfunction renderDrillBody(\n source: readonly CommitSummary[],\n filtered: readonly CommitSummary[],\n cursor: number,\n loading: boolean,\n err: string | null,\n focused: WorkspaceRow,\n contentWidth: number,\n viewport: number,\n): ReactElement {\n const title = `commits for ${focused.agentName}`;\n const hint = \"y yanks `git show <sha>`\";\n if (loading && source.length === 0) {\n return (\n <DrillScrollView\n title={title}\n body=\"loading…\"\n viewport={viewport}\n scrollTop={0}\n hint={hint}\n />\n );\n }\n if (err !== null) {\n return (\n <DrillScrollView\n title={title}\n body={`error: ${err}`}\n viewport={viewport}\n scrollTop={0}\n hint={hint}\n />\n );\n }\n if (source.length === 0) {\n const parent = focused.parentRef ? focused.parentRef.slice(0, 12) : \"(none)\";\n return (\n <DrillScrollView\n title={title}\n body={`(no commits since fork — workspace is at parent_ref ${parent})`}\n viewport={viewport}\n scrollTop={0}\n hint={hint}\n />\n );\n }\n if (filtered.length === 0) {\n return <DrillScrollView title={title} body=\"(no matches)\" viewport={viewport} scrollTop={0} />;\n }\n\n const { visible } = centredVisibleSlice(filtered, cursor, viewport);\n const rows = visible.map((c) => [c.sha.slice(0, 12), c.subject]);\n const widths = layoutColumns(rows, DRILL_COLUMN_SPECS, contentWidth);\n // Inline render — NO nested TitledBox here. The popup's PopupShell\n // already drew the cyan rounded chrome; a nested magenta TitledBox\n // at width=stdout.columns would overflow the popup's inner content\n // area by 4 cols (popup chrome) and make rows wrap past the\n // border. Mirrors the central fix in src/cli/tui/popups/drill.tsx\n // (commit 5e334f6 — bug_tui_drill_text_no_width_pin).\n return (\n <Box flexDirection=\"column\" flexGrow={1}>\n <Box>\n <Text bold color=\"magenta\">\n {title}\n </Text>\n <Text dimColor>\n {\" \"}\n · {cursor + 1}/{filtered.length}\n </Text>\n </Box>\n <Box flexDirection=\"column\" flexGrow={1}>\n {visible.map((c, i) => {\n const sel = filtered.indexOf(c) === cursor;\n const row = rows[i];\n if (row === undefined) return null;\n const padded = renderRow(row, widths, DRILL_COLUMN_SPECS);\n return (\n <ListRow\n key={c.sha}\n cells={padded}\n contentWidth={contentWidth}\n colors={COMMIT_COLORS}\n selected={sel}\n />\n );\n })}\n </Box>\n <Box>\n <Text dimColor>{hint}</Text>\n </Box>\n </Box>\n );\n}\n","// React hook + tick-rate constants for the TUI's poll loop.\n//\n// Per design_poll_loop (workstream `tui`): simple poll, single\n// setInterval owned by <Dashboard>, synchronous better-sqlite3 reads\n// (no race possible by construction), tick rate adjustable live with\n// +/- (floor 100ms, ceiling 10s, default 1s), no persistence.\n//\n// The hook pauses fetches when `enabled === false`. <App> keeps it\n// enabled while popups are open so visible drill-down views can share\n// the same fast/slow refresh cadence as the dashboard.\n//\n// Re-render guard (bug_tui_flicker_on_every_tick, workstream\n// `tui-impl`):\n//\n// The naive unconditional setData on every tick was the bug;\n// forced React/ink to diff a brand-new top-level state object,\n// which in turn re-rendered every card body — a perceptible\n// full-frame flash 1×/sec on any stable workstream.\n//\n// Three-layer fix lives here:\n// LAYER A: stringify a `snapshotKey()` of the visible-affecting\n// fields and short-circuit setData when the key is\n// byte-equal to the previous one. The hook returns the\n// SAME `data` reference across no-op ticks so ink's\n// prop-diff bottoms out at the cards.\n// LAYER B: tick-duration and drill-refresh nonces publish only\n// when the snapshot key changes (or an error clears), so\n// no-op poll intervals do not force a whole-App render.\n// LAYER C: the dashboard fast tick does NOT preload the exhaustive\n// all-tasks list; the All-tasks popup reads SQLite\n// directly while open.\n//\n// Per-card useMemo is intentionally skipped — Layers A/B stop the\n// new-prop cascade at the top-level `data` reference, which is\n// enough in practice. Revisit only if visible flicker regresses\n// against a stable workstream.\n\nimport { existsSync } from \"node:fs\";\nimport { fileURLToPath } from \"node:url\";\nimport { Worker } from \"node:worker_threads\";\nimport { useEffect, useRef, useState } from \"react\";\nimport { type Db, tryResolveWorkstreamId } from \"../../db.js\";\nimport {\n type LoadWorkstreamSnapshotOptions,\n loadWorkstreamSnapshotFast,\n loadWorkstreamSnapshotSlow,\n mergeSnapshotFastSlow,\n type WorkstreamSnapshot,\n type WorkstreamSnapshotSlowFields,\n} from \"../../state.js\";\nimport { ambientSyncPass, syncEnabled } from \"../../sync.js\";\nimport type { CardId } from \"./layout.js\";\n\nexport const TICK_DEFAULT_MS = 1000;\nexport const TICK_FLOOR_MS = 100;\nexport const TICK_CEILING_MS = 10_000;\nexport const SLOW_TICK_MS = 10_000;\nconst NO_OBSERVED_WORKSTREAMS: readonly string[] = [];\n\n/**\n * Guard so N workstream tabs do not each run a sync pass on the same\n * 10s beat. The hook is instantiated per tab; the sync pass is a\n * whole-DB, whole-sync-dir operation with nothing per-workstream about\n * it, so one per beat is exactly right and N would be N-1 wasted\n * ingests fighting over the same file lock.\n */\nlet syncInFlight = false;\n\n/** Built next to dist/cli.js by tsup (entry `tui-sync-worker`). Absent\n * when running from source (vitest), where the pass runs in-process. */\nconst BUILT_SYNC_WORKER_PATH = fileURLToPath(new URL(\"./tui-sync-worker.js\", import.meta.url));\nlet syncWorkerPath = BUILT_SYNC_WORKER_PATH;\ntype SyncPassResult = Awaited<ReturnType<typeof ambientSyncPass>>;\ntype SyncWorkerState = { worker: Worker; done: ((r: SyncPassResult | null) => void) | null };\nlet syncWorker: SyncWorkerState | null = null;\n\n/** Test seam: point the worker path at a built bundle (or back to the\n * default with null), dropping any running worker. */\nexport async function setSyncWorkerPathForTests(path: string | null): Promise<void> {\n syncWorkerPath = path ?? BUILT_SYNC_WORKER_PATH;\n const state = syncWorker;\n syncWorker = null;\n await state?.worker.terminate();\n}\n\n/** Test seam: the live sync worker, if one is running. */\nexport function syncWorkerForTests(): Worker | null {\n return syncWorker?.worker ?? null;\n}\n\n/** One pass in the worker_thread, started lazily and kept for the TUI's\n * life (`unref`, so it never holds the process open). A worker that\n * dies settles its pass with null and is respawned on the next beat. */\nfunction workerSyncPass(dbPath: string): Promise<SyncPassResult | null> {\n if (syncWorker === null) {\n const worker = new Worker(syncWorkerPath, { workerData: { dbPath } });\n const state: SyncWorkerState = { worker, done: null };\n const settle = (result: SyncPassResult | null) => {\n const done = state.done;\n state.done = null;\n done?.(result);\n };\n worker.on(\"message\", (result: SyncPassResult | null) => settle(result));\n const drop = () => {\n if (syncWorker === state) syncWorker = null;\n settle(null);\n };\n worker.on(\"error\", drop);\n worker.on(\"exit\", drop);\n // AFTER the listeners: adding a \"message\" listener re-refs the\n // worker's port, so an earlier unref() is silently undone and the\n // process hangs on exit after `q`.\n worker.unref();\n syncWorker = state;\n }\n const state = syncWorker;\n return new Promise((resolve) => {\n state.done = resolve;\n state.worker.postMessage(null);\n });\n}\n\n/**\n * The TUI's share of the AMBIENT sync hook.\n *\n * Hung off the SLOW tick (10s) and never the fast one: sync is\n * filesystem work — readdir, stat, read, a cross-process file lock —\n * and the fast tick is a repaint cadence an operator can wind down to\n * 100ms with `-`. At 100ms this would be 10 sync passes a second on a\n * shared folder.\n *\n * `quiet: true` because the TUI owns the alternate screen: a stderr\n * warning would paint garbage over the dashboard. Sync problems surface\n * through the Doctor card instead, which is where a TUI operator looks.\n *\n * Total by construction (see src/sync.ts): a broken segment or an\n * unreadable sync dir must never take the dashboard down. Resolves to\n * the pass's result, or null when skipped (sync off, a pass already in\n * flight) or failed (including a worker that died mid-pass).\n */\nexport async function tuiSyncPass(db: Db): Promise<SyncPassResult | null> {\n if (!syncEnabled() || syncInFlight) return null;\n syncInFlight = true;\n try {\n // Off ink's thread when the bundle has the worker and the DB is a\n // file a second connection can open; in-process otherwise.\n if (db.name !== \":memory:\" && existsSync(syncWorkerPath)) {\n return await workerSyncPass(db.name);\n }\n return await ambientSyncPass(db, { quiet: true });\n } catch {\n // Never let sync fail a repaint.\n return null;\n } finally {\n syncInFlight = false;\n }\n}\n\n/**\n * Per-card on/off state for the dashboard. Keyed by numeric CardId\n * (0..9) — the same key that CARD_CONFIGS, CARD_REGISTRY,\n * POPUP_REGISTRY, and dataCountForCard already use.\n *\n * Pre-review_tui_card_key_from_id_redundant this was keyed by\n * string (\"agents\", \"tracks\", \"ready\", …), which forced a\n * 24-line `cardKeyFromId` switch every keystroke and every render\n * to bridge to the numeric id. Folding the keys back into the\n * shared CardId space eliminates the bridge and keeps the per-card\n * `name` string as the human-friendly identifier on CARD_CONFIGS.\n */\nexport type CardVisibility = Record<CardId, boolean>;\n\nexport const DEFAULT_CARD_VISIBILITY: CardVisibility = {\n 0: true,\n 1: true,\n 2: true,\n 3: true,\n 4: true,\n 5: true,\n 6: true,\n 7: true,\n 8: true,\n 9: true,\n};\n\nexport interface DashboardSnapshot {\n data: WorkstreamSnapshot | null;\n /** Increments after a fast SQL-only tick publishes a changed\n * snapshot. Drill views that read SQLite directly include this in\n * memo deps, while no-op ticks stay render-silent. */\n fastTickNonce: number;\n /** Increments after a slow subprocess tick publishes a changed\n * snapshot. Drill views that shell out (tmux scrollback, VCS show)\n * include this instead of fastTickNonce to avoid 1s subprocess\n * churn; no-op slow ticks stay render-silent. */\n slowTickNonce: number;\n /** Measured fetch duration of the most recent published fast tick\n * (ms). No-op ticks intentionally leave this unchanged so the\n * status path does not repaint an otherwise stable frame. */\n lastTickMs: number;\n error: string | null;\n /** Launch-time workstreams whose DB row has since been torn down. */\n tornDownWorkstreams: ReadonlySet<string>;\n}\n\nexport interface DashboardSnapshotLoaders {\n fast: (\n db: Db,\n workstream: string,\n opts?: LoadWorkstreamSnapshotOptions,\n ) => Promise<WorkstreamSnapshot>;\n slow: (\n db: Db,\n workstream: string,\n opts?: LoadWorkstreamSnapshotOptions,\n baseSnapshot?: WorkstreamSnapshot,\n ) => Promise<WorkstreamSnapshotSlowFields>;\n}\n\nconst DEFAULT_LOADERS: DashboardSnapshotLoaders = {\n fast: loadWorkstreamSnapshotFast,\n slow: loadWorkstreamSnapshotSlow,\n};\n\nconst FAST_OPTS: LoadWorkstreamSnapshotOptions = {\n eventLimit: 200,\n};\n\nconst SLOW_OPTS: LoadWorkstreamSnapshotOptions = {\n withDirty: true,\n withDoctor: true,\n withRecentCommits: { limit: 25 },\n};\n\nexport interface DashboardSnapshotOptions {\n /** Launch-time tabs to check for teardown on every fast tick. */\n observedWorkstreams?: readonly string[];\n /**\n * When true, slowTickNonce advances even if the slow-tier snapshot\n * is byte-equal. Used only for subprocess-backed popup drills\n * (agent scrollback / git show) whose body can change without a DB\n * snapshot change. Dashboard and task-list views keep this false so\n * stable frames stay render-silent.\n */\n publishNoopSlowTicks?: boolean;\n}\n\n/**\n * Subscribe to the workstream snapshot via a setInterval-owned poll\n * loop. Re-fetches every `tickMs` while `enabled` is true.\n *\n * Re-render guard: returns the SAME `data` reference across ticks\n * whose visible content (`snapshotKey`) is unchanged, so React/ink\n * diff against the cards bottoms out cheaply. Tick-duration and\n * drill-refresh nonces publish only when the visible snapshot changes\n * (or an error clears), so stable workstreams do not repaint once per\n * poll interval.\n *\n * `refreshNonce` is the optional refresh-now signal\n * (review_dead_code_refresh_now): every distinct value forces an\n * immediate re-fetch by re-running the effect. Wired through to the\n * effect's dep list so bumping it from <App> on the `r` / F5\n * keypress restarts the interval and runs `tick()` synchronously.\n * Defaults to 0 when unwired so existing callers keep working.\n */\nexport function useDashboardSnapshot(\n db: Db,\n workstream: string,\n tickMs: number,\n enabled: boolean,\n refreshNonce = 0,\n loaders: DashboardSnapshotLoaders = DEFAULT_LOADERS,\n options: DashboardSnapshotOptions = {},\n): DashboardSnapshot {\n const publishNoopSlowTicks = options.publishNoopSlowTicks === true;\n const observedWorkstreams = options.observedWorkstreams ?? NO_OBSERVED_WORKSTREAMS;\n const [tornDownWorkstreams, setTornDownWorkstreams] = useState<ReadonlySet<string>>(new Set());\n // Layer A: data + error (the stuff the cards read).\n const [data, setData] = useState<{ data: WorkstreamSnapshot | null; error: string | null }>({\n data: null,\n error: null,\n });\n // Layer B: tick duration + explicit nonces only publish when\n // snapshotKey changes, so no-op poll intervals do not force <App>\n // (and therefore the whole Ink tree) to repaint.\n const [lastTickMs, setLastTickMs] = useState(0);\n const [fastTickNonce, setFastTickNonce] = useState(0);\n const [slowTickNonce, setSlowTickNonce] = useState(0);\n const latestFastRef = useRef<WorkstreamSnapshot | null>(null);\n const slowRef = useRef<WorkstreamSnapshotSlowFields | null>(null);\n const publishedKeyRef = useRef(\"\");\n const errorRef = useRef<string | null>(null);\n\n // Snap-to-null on workstream change\n // (bug_tui_tab_switch_stale_render, workstream `tui-impl`).\n //\n // Without this, Tab/Shift-Tab on the multi-ws TUI flips the\n // `workstream` prop but the hook still has the OLD ws's\n // WorkstreamSnapshot in `data` until the new effect's first\n // tick resolves (~10-50ms for the SQLite read). React renders\n // the cards against the stale snapshot in that gap → a mixed\n // frame whose CARDS are old-ws but whose TAB STRIP is new-ws.\n //\n // Fix: when the workstream prop changes, synchronously reset\n // data to null during render. Cards already handle the null /\n // loading-state case. The next tick (started by the effect's\n // re-run on the workstream dep) repopulates fresh data within\n // one tick.\n //\n // This is the React-officially-blessed pattern for \"derive\n // state from props\": store the previous value in a ref, compare\n // during render, and call setState if they diverge. React\n // re-renders immediately with the new state and skips any\n // intervening commit, so cards never see the stale snapshot.\n const lastWsRef = useRef(workstream);\n if (shouldDiscardForWorkstream(lastWsRef.current, workstream)) {\n lastWsRef.current = workstream;\n slowRef.current = null;\n latestFastRef.current = null;\n publishedKeyRef.current = \"\";\n errorRef.current = null;\n setData({ data: null, error: null });\n setLastTickMs(0);\n }\n\n useEffect(() => {\n if (!enabled) return;\n // Touch refreshNonce so biome's useExhaustiveDependencies sees\n // it as read-inside-effect; the actual purpose of listing it in\n // the dep array is to force the effect to re-run on every bump\n // from <App> (the `r` / F5 keypress), which tears down the\n // setInterval and synchronously fires `tick()` below — i.e.\n // an immediate refresh. (review_dead_code_refresh_now)\n void refreshNonce;\n let cancelled = false;\n const tick = async () => {\n if (cancelled) return;\n const t0 = performance.now();\n try {\n const tornDown = new Set(\n observedWorkstreams.filter((name) => tryResolveWorkstreamId(db, name) === null),\n );\n setTornDownWorkstreams((previous) =>\n sameStringSet(previous, tornDown) ? previous : tornDown,\n );\n const fast = await loaders.fast(db, workstream, FAST_OPTS);\n if (cancelled) return;\n latestFastRef.current = fast;\n const fresh = mergeSnapshotFastSlow(fast, slowRef.current);\n const dur = performance.now() - t0;\n if (publishSnapshot(fresh, setData, publishedKeyRef, errorRef)) {\n setLastTickMs(dur);\n setFastTickNonce((n) => n + 1);\n }\n } catch (err) {\n if (cancelled) return;\n publishError(String(err), setData, errorRef);\n }\n };\n void tick();\n const id = setInterval(() => void tick(), tickMs);\n return () => {\n cancelled = true;\n clearInterval(id);\n };\n // `refreshNonce` participates in the dep list so the `r` / F5\n // keypress (App bumps the nonce) tears down the interval and\n // re-runs the effect, which fires `tick()` immediately. Without\n // this, the binding existed but never poked the poll loop\n // (review_dead_code_refresh_now).\n }, [db, workstream, tickMs, enabled, refreshNonce, loaders, observedWorkstreams]);\n\n useEffect(() => {\n if (!enabled) return;\n void refreshNonce;\n let cancelled = false;\n const slowTick = async () => {\n if (cancelled) return;\n // BEFORE the slow load, so anything a peer just delivered is\n // already in the tables this tick is about to read.\n await tuiSyncPass(db);\n if (cancelled) return;\n try {\n const slow = await loaders.slow(\n db,\n workstream,\n SLOW_OPTS,\n latestFastRef.current ?? undefined,\n );\n if (cancelled) return;\n slowRef.current = slow;\n const fast = latestFastRef.current;\n const changed =\n fast !== null &&\n publishSnapshot(mergeSnapshotFastSlow(fast, slow), setData, publishedKeyRef, errorRef);\n if (changed || (fast !== null && publishNoopSlowTicks)) {\n setSlowTickNonce((n) => n + 1);\n }\n } catch (err) {\n if (cancelled) return;\n publishError(String(err), setData, errorRef);\n }\n };\n void slowTick();\n const id = setInterval(() => void slowTick(), SLOW_TICK_MS);\n return () => {\n cancelled = true;\n clearInterval(id);\n };\n }, [db, workstream, enabled, refreshNonce, loaders, publishNoopSlowTicks]);\n\n return {\n data: data.data,\n fastTickNonce,\n slowTickNonce,\n lastTickMs,\n error: data.error,\n tornDownWorkstreams,\n };\n}\n\nfunction sameStringSet(a: ReadonlySet<string>, b: ReadonlySet<string>): boolean {\n return a.size === b.size && [...a].every((value) => b.has(value));\n}\n\n/**\n * Pure helper: returns true when a workstream-prop change must\n * discard the cached snapshot. Today this is just an identity\n * check, but factoring it out (a) makes the snap-to-null branch in\n * useDashboardSnapshot unit-testable without driving the hook, and\n * (b) gives future work (e.g. ws-aliases / case-insensitive\n * matching) a single seam to extend. See bug_tui_tab_switch_stale_render.\n */\nexport function shouldDiscardForWorkstream(prev: string, next: string): boolean {\n return prev !== next;\n}\n\nfunction publishSnapshot(\n fresh: WorkstreamSnapshot,\n writeData: (\n updater: (prev: { data: WorkstreamSnapshot | null; error: string | null }) => {\n data: WorkstreamSnapshot | null;\n error: string | null;\n },\n ) => void,\n publishedKeyRef: { current: string },\n errorRef: { current: string | null },\n): boolean {\n const freshKey = snapshotKeyString(fresh);\n if (errorRef.current === null && publishedKeyRef.current === freshKey) return false;\n publishedKeyRef.current = freshKey;\n errorRef.current = null;\n writeData(() => ({ data: fresh, error: null }));\n return true;\n}\n\nfunction publishError(\n message: string,\n writeData: (\n updater: (prev: { data: WorkstreamSnapshot | null; error: string | null }) => {\n data: WorkstreamSnapshot | null;\n error: string | null;\n },\n ) => void,\n errorRef: { current: string | null },\n): void {\n if (errorRef.current === message) return;\n errorRef.current = message;\n writeData((prev) => ({ ...prev, error: message }));\n}\n\n/** Clamp a desired tick rate to [floor, ceiling]. */\nexport function clampTick(ms: number): number {\n return Math.max(TICK_FLOOR_MS, Math.min(TICK_CEILING_MS, ms));\n}\n\n/** Compute the next-faster tick (halve, floor 100ms). */\nexport function fasterTick(current: number): number {\n return clampTick(Math.floor(current / 2));\n}\n\n/** Compute the next-slower tick (double, ceiling 10s). */\nexport function slowerTick(current: number): number {\n return clampTick(current * 2);\n}\n\n// ─── snapshotKey ───────────────────────────────────────────────────\n//\n// Pure projection of the WorkstreamSnapshot fields that actually\n// affect what the user sees on screen. Two snapshots with the same\n// snapshotKey() are guaranteed to render identical frames — so the\n// hook can safely skip setData for them.\n//\n// Design notes:\n// - Picks ONE of every visible-affecting field per row, no more.\n// Adding a field that DOES affect rendering but ISN'T listed\n// here is a regression (cards will lag a tick); adding a field\n// that DOESN'T affect rendering is a regression (we'll re-render\n// unnecessarily).\n// - tracks[i].taskIds is a Set<string>; serialise it as a sorted\n// array so JSON.stringify is deterministic.\n// - We DO NOT include workspaceOrphans because no card surfaces\n// them today (the TUI shows orphans only on the static\n// `mu state` card). If a future card reads them, add it here.\n// - We DO NOT include reconcile report counters (prunedGhosts,\n// prune counts) — they are diagnostic, not rendered.\n\n/**\n * Pure projection of the visible-affecting fields of a snapshot.\n * Two snapshots that produce equal `snapshotKey` render identical\n * frames. Exported for unit tests; consumers should prefer\n * `snapshotKeyString` (which JSON-encodes the result for cheap\n * byte-equality checks).\n */\nexport function snapshotKey(s: WorkstreamSnapshot): unknown {\n return {\n workstreamName: s.workstreamName,\n // ctl drives the Agents card's broken-control-socket glyph.\n agents: s.view.agents.map((a) => [\n a.name,\n a.state,\n a.role,\n a.idle === true ? 1 : 0,\n a.ctl ?? \"\",\n ]),\n orphanPaneIds: s.view.orphans.map((o) => o.paneId).sort(),\n tracks: s.tracks.map((t) => ({\n roots: t.roots.map((r) => r.name),\n readyCount: t.readyCount,\n parked: t.parked,\n // Set → sorted array; deterministic JSON.\n taskIds: [...t.taskIds].sort(),\n })),\n ready: s.ready.map(taskKey),\n inProgress: s.inProgress.map(taskKey),\n blocked: s.blocked.map(taskKey),\n recentClosed: s.recentClosed.map(taskKey),\n parkedCount: s.parkedCount,\n triage: s.triage.map(taskKey),\n allTasks: s.allTasks.map(taskKey),\n commitsBackend: s.commitsBackend ?? null,\n recentCommits: s.recentCommits.map((c) => [c.sha, c.subject, c.author, c.relTime]),\n workspaces: s.workspaces.map((w) => [\n w.agentName,\n w.backend,\n w.parentRef ?? \"\",\n w.commitsBehindMain ?? \"\",\n w.dirty === true ? 1 : 0,\n ]),\n // Recent log entries: seq is monotonic, so eq-by-seq is enough\n // for ordered membership; payload bytes drive what shows.\n recent: s.recent.map((l) => [l.seq, l.source, l.kind, l.payload]),\n // Doctor card renders every check row (name/status/detail) and\n // the problem count; null means \"loading…\".\n doctor: s.doctor\n ? [s.doctor.problemCount, s.doctor.checks.map((c) => [c.name, c.status, c.detail])]\n : null,\n };\n}\n\n/** Stable JSON encoding of `snapshotKey`. Cheap byte-equal check. */\nexport function snapshotKeyString(s: WorkstreamSnapshot): string {\n return JSON.stringify(snapshotKey(s));\n}\n\n// One row of every visible-affecting task field. impact + effortDays\n// drive the ROI bucket / sort; status + substate drive glyph + colour;\n// createdAt / updatedAt drive the all-tasks popup's age / recency\n// sorts; ownerName + title are rendered verbatim.\nfunction taskKey(t: {\n name: string;\n status: string;\n substate: string;\n impact: number;\n effortDays: number;\n ownerName: string | null;\n title: string;\n createdAt: string;\n updatedAt: string;\n}): (string | number)[] {\n return [\n t.name,\n t.status,\n t.substate,\n t.impact,\n t.effortDays,\n t.ownerName ?? \"\",\n t.title,\n t.createdAt,\n t.updatedAt,\n ];\n}\n","// Status bar — single dedicated row at the very bottom of the\n// dashboard, btop / lazygit / k9s convention. Replaces the prior\n// \"footer line + tick indicator\" pair.\n//\n// Per feat_status_bar (workstream `tui-impl`):\n// LEFT : last yank line (was the ad-hoc \"footer:\" text +\n// [copied] / [no clipboard] suffix).\n// CENTER : context-sensitive key-hint cluster\n// - dashboard mode → global keys\n// - popup mode → popup-local keys\n// - help mode → \"Esc/?/q close help\"\n// RIGHT : active workstream label (multi-ws only) + tick rate.\n//\n// Per feat_tui_multi_workstream (workstream `tui-impl`): when the\n// TUI is launched with multiple workstreams, the right zone gains\n// a `[ws]` prefix so the operator sees which tab is active without\n// having to look at the top tab strip. Single-ws TUI is unchanged.\n//\n// Single line, no border, dim by default; bright colour for the\n// single-key glyphs so the eye picks them out at a glance.\n//\n// Truncation policy: when the terminal is too narrow to fit all\n// three zones, drop the LEFT zone first (keys are critical;\n// last-yank is recoverable from the clipboard). The RIGHT zone is\n// short and never dropped.\n\nimport { Box, Text } from \"ink\";\nimport type { ReactElement } from \"react\";\nimport type { FooterState, PopupMode } from \"./app.js\";\nimport { truncateCell } from \"./columns.js\";\nimport { type StatusHintEntry, statusHintEntries } from \"./keymap-spec.js\";\n\nexport type StatusMode = \"dashboard\" | \"popup\" | \"popup-filter\" | \"help\";\n\nexport interface StatusBarProps {\n mode: StatusMode;\n tickMs: number;\n footer: FooterState | null;\n /** Total terminal width — drives the LEFT-truncation policy. */\n cols: number;\n /** Optional label for the popup mode (e.g. \"Tasks\"). */\n popupName?: string;\n /** Sub-mode inside a popup: \"list\" (default) or \"drill\". Drives\n * the per-popup hint cluster (Enter drills vs Esc backs out). */\n popupMode?: PopupMode;\n /** Active workstream label (multi-ws TUI only). When set, the\n * RIGHT zone renders `[<name>] <tick>` so the operator never\n * loses sight of which tab they are looking at. Undefined for\n * the single-ws TUI keeps the right zone byte-identical to the\n * pre-multi-ws layout. */\n activeWorkstream?: string;\n}\n\nexport function StatusBar({\n mode,\n tickMs,\n footer,\n cols,\n popupName,\n popupMode,\n activeWorkstream,\n}: StatusBarProps): ReactElement {\n const tickLabel = `${(tickMs / 1000).toFixed(2)}s ⏱`;\n const wsLabel = activeWorkstream !== undefined ? `[${activeWorkstream}]` : \"\";\n const rightPlain = wsLabel === \"\" ? tickLabel : `${wsLabel} ${tickLabel}`;\n const left = footer ? formatFooter(footer) : \"\";\n // Budget for the LEFT zone: total cols - right zone - hint cluster\n // - 4 chars of inter-zone padding. Hint cluster width is its\n // *plain* (non-coloured) length, derived from the same token list\n // that renders the JSX so the two cannot drift.\n const hintTokens = buildHints(mode, popupName, popupMode, activeWorkstream !== undefined);\n const hintsWidth = hintsPlain(hintTokens).length;\n const rightWidth = rightPlain.length;\n const padding = 4;\n const leftBudget = Math.max(0, cols - rightWidth - hintsWidth - padding);\n const leftClipped = leftBudget > 0 ? truncateCell(left, leftBudget) : \"\";\n\n return (\n <Box justifyContent=\"space-between\" width={cols}>\n <Box>\n {footer?.tone === \"error\" ? (\n <Text color=\"red\" dimColor>\n {leftClipped}\n </Text>\n ) : (\n <Text dimColor>{leftClipped}</Text>\n )}\n </Box>\n <Box>{renderHints(hintTokens)}</Box>\n <Box>\n {wsLabel !== \"\" && (\n <Text bold color=\"cyan\">\n {`${wsLabel} `}\n </Text>\n )}\n <Text dimColor>{tickLabel}</Text>\n </Box>\n </Box>\n );\n}\n\n// Hint cluster rendering is driven by keymap-spec.ts. That spec is\n// also consumed by the help overlay, making the contract explicit:\n// the status-bar cluster is the always-shown subset, and `?` is the\n// superset.\n//\n// Render order: tokens are space-separated. The plain text is\n// `tokens.map(t => t.text).join(\" \")`; the JSX wraps each token in\n// the styling implied by its `kind`, separated by literal \" \"\n// strings so width matches byte-for-byte.\ntype HintToken =\n | { kind: \"key\"; text: string }\n | { kind: \"dim\"; text: string }\n | { kind: \"label\"; text: string; color: \"cyan\" | \"magenta\" | \"yellow\" };\n\nfunction buildHints(\n mode: StatusMode,\n popupName: string | undefined,\n popupMode: PopupMode | undefined,\n hasWorkstreamTabs: boolean,\n): HintToken[] {\n if (mode === \"help\") {\n return [\n { kind: \"key\", text: \"Esc/?/q\" },\n { kind: \"dim\", text: \"close help\" },\n ];\n }\n\n const popupLabel: HintToken[] = popupName\n ? [\n { kind: \"label\", text: popupName, color: \"cyan\" },\n { kind: \"dim\", text: \"·\" },\n ]\n : [];\n const specMode =\n mode === \"dashboard\"\n ? \"dashboard\"\n : mode === \"popup-filter\"\n ? \"popup-filter\"\n : popupMode === \"drill\"\n ? \"popup-drill\"\n : popupName === \"DAG\"\n ? \"dag\"\n : popupName === \"All tasks\"\n ? \"all-tasks\"\n : \"popup-list\";\n const entries = statusHintEntries({ mode: specMode, hasWorkstreamTabs });\n return [...(mode === \"dashboard\" ? [] : popupLabel), ...tokensFromSpec(entries)];\n}\n\nfunction tokensFromSpec(entries: readonly StatusHintEntry[]): HintToken[] {\n const tokens: HintToken[] = [];\n entries.forEach((entry, index) => {\n if (entry.kind === \"hint\") {\n if (entry.key !== undefined) tokens.push({ kind: \"key\", text: entry.key });\n tokens.push({\n kind: \"dim\",\n text: `${entry.label}${index === entries.length - 1 ? \"\" : \" ·\"}`,\n });\n return;\n }\n if (entry.kind === \"label\") {\n tokens.push({ kind: \"label\", text: entry.label, color: entry.color ?? \"cyan\" });\n } else {\n tokens.push({ kind: \"dim\", text: entry.label });\n }\n if (index !== entries.length - 1) tokens.push({ kind: \"dim\", text: \"·\" });\n });\n return tokens;\n}\n\nfunction hintsPlain(tokens: HintToken[]): string {\n return tokens.map((t) => t.text).join(\" \");\n}\n\nfunction renderHints(tokens: HintToken[]): ReactElement {\n // Interleave tokens with literal \" \" separators so the rendered\n // width matches `hintsPlain(tokens)` byte-for-byte. ink flattens\n // children into a single inline run, so no per-child keys are\n // required (and react treats string children as keyed by index).\n const children: React.ReactNode[] = [];\n for (let i = 0; i < tokens.length; i++) {\n if (i > 0) children.push(\" \");\n children.push(renderToken(tokens[i] as HintToken, i));\n }\n return <Text>{children}</Text>;\n}\n\nfunction renderToken(t: HintToken, key: number): ReactElement {\n switch (t.kind) {\n case \"key\":\n return (\n <Text key={key} color=\"yellow\">\n {t.text}\n </Text>\n );\n case \"dim\":\n return (\n <Text key={key} dimColor>\n {t.text}\n </Text>\n );\n case \"label\":\n return (\n <Text key={key} bold color={t.color}>\n {t.text}\n </Text>\n );\n }\n}\n\nfunction formatFooter(f: FooterState): string {\n const tag = f.copied ? \"[copied]\" : \"[no clipboard]\";\n return `last: ${f.command} ${tag}`;\n}\n","// TabStrip — workstream switcher rendered above the dashboard when\n// the TUI is launched with multiple workstreams.\n//\n// The pure layout algorithm lives in tab-strip-layout.ts. This\n// component is a PURE presentational component: it takes the\n// terminal column count as a prop (the parent <App> reads useStdout\n// once for its own use and threads `cols` down). No hooks here —\n// previously a `useStdout()` helper was called from this module,\n// which produced a 'Rendered fewer hooks than expected' crash on\n// small panes because the early-return guard upstairs caused the\n// hook to be called on some renders and skipped on others.\n\nimport { Box, Text } from \"ink\";\nimport type { ReactElement } from \"react\";\n\nimport { isScratchWorkstream } from \"../../workstream.js\";\nimport { layoutTabStrip } from \"./tab-strip-layout.js\";\n\nexport interface TabStripProps {\n /** Resolved workstream set, in order. Length must be ≥ 1; the\n * caller skips rendering when length ≤ 1 (see <App>). */\n workstreams: readonly string[];\n /** Index of the active tab. Caller guarantees 0 ≤ active < workstreams.length. */\n active: number;\n /** Terminal columns. Required: the parent <App> reads ink's\n * useStdout() once and threads this down so the strip can stay\n * hook-free (and therefore safe to call from outside an ink\n * render tree, e.g. unit tests). */\n terminalColumns: number;\n /** Launch-time tabs whose workstream row no longer exists. */\n tornDownWorkstreams?: ReadonlySet<string>;\n}\n\nexport function TabStrip({\n workstreams,\n active,\n terminalColumns,\n tornDownWorkstreams = new Set(),\n}: TabStripProps): ReactElement | null {\n const onlyWorkstream = workstreams[0];\n if (workstreams.length <= 1) {\n if (onlyWorkstream === undefined || !tornDownWorkstreams.has(onlyWorkstream)) return null;\n return (\n <Box flexDirection=\"row\">\n <Text dimColor>workstreams: </Text>\n <Text bold color=\"cyan\" dimColor strikethrough>\n {`▸ ${isScratchWorkstream(onlyWorkstream) ? `*${onlyWorkstream}` : onlyWorkstream}`}\n </Text>\n </Box>\n );\n }\n const layout = layoutTabStrip(workstreams, active, terminalColumns);\n if (layout === null) return null;\n // The `*` cue signals \"ephemeral, not a durable crew\" so the\n // operator doesn't mistake a scratch workstream for a real one.\n const decorate = (name: string): string => (isScratchWorkstream(name) ? `*${name}` : name);\n const tabs: ReactElement[] = [];\n for (let i = 0; i < layout.visible.length; i++) {\n const tab = layout.visible[i];\n if (tab === undefined) continue;\n const tornDown = tornDownWorkstreams.has(tab.name);\n if (tab.isActive) {\n tabs.push(\n <Text key={`t-${i}`} bold color=\"cyan\" dimColor={tornDown} strikethrough={tornDown}>\n {`▸ ${decorate(tab.name)}`}\n </Text>,\n );\n } else {\n tabs.push(\n <Text key={`t-${i}`} dimColor strikethrough={tornDown}>\n {decorate(tab.name)}\n </Text>,\n );\n }\n if (i < layout.visible.length - 1) {\n tabs.push(\n <Text key={`s-${i}`} dimColor>\n {\" · \"}\n </Text>,\n );\n }\n }\n return (\n <Box flexDirection=\"row\">\n <Text dimColor>workstreams: </Text>\n {layout.leftHidden > 0 && <Text dimColor>{`‹${layout.leftHidden} `}</Text>}\n {tabs}\n {layout.rightHidden > 0 && <Text dimColor>{` ›${layout.rightHidden}`}</Text>}\n {layout.showHint && (\n <Text dimColor>\n {layout.leftHidden > 0 || layout.rightHidden > 0\n ? \" (Tab/Shift-Tab)\"\n : \" (Tab / Shift-Tab)\"}\n </Text>\n )}\n </Box>\n );\n}\n","// Pure tab-strip layout helper. Keeps the React component small and\n// makes overflow behaviour testable without booting ink.\n\nimport stringWidth from \"string-width\";\n\nconst PREFIX = \"workstreams: \";\nconst WIDE_HINT = \" (Tab / Shift-Tab)\";\nconst NARROW_HINT = \" (Tab/Shift-Tab)\";\nconst SEP = \" · \";\nconst ELLIPSIS = \"…\";\n\nexport interface VisibleTab {\n name: string;\n isActive: boolean;\n}\n\nexport interface TabStripLayout {\n leftHidden: number;\n rightHidden: number;\n visible: VisibleTab[];\n showHint: boolean;\n}\n\nexport function layoutTabStrip(\n workstreams: readonly string[],\n active: number,\n availableCols: number,\n): TabStripLayout | null {\n if (workstreams.length <= 1) return null;\n const safeActive = clamp(active, 0, workstreams.length - 1);\n const maxCols = Math.max(0, Math.floor(availableCols));\n const allRange = range(0, workstreams.length - 1);\n if (fits(workstreams, safeActive, allRange, maxCols, true)) {\n return {\n leftHidden: 0,\n rightHidden: 0,\n visible: tabsForRange(workstreams, safeActive, allRange),\n showHint: true,\n };\n }\n\n let start = safeActive;\n let end = safeActive;\n let growLeft = true;\n while (true) {\n let changed = false;\n if (\n growLeft &&\n start > 0 &&\n fits(workstreams, safeActive, range(start - 1, end), maxCols, true)\n ) {\n start--;\n changed = true;\n }\n if (\n !changed &&\n end < workstreams.length - 1 &&\n fits(workstreams, safeActive, range(start, end + 1), maxCols, true)\n ) {\n end++;\n changed = true;\n }\n if (\n !changed &&\n !growLeft &&\n start > 0 &&\n fits(workstreams, safeActive, range(start - 1, end), maxCols, true)\n ) {\n start--;\n changed = true;\n }\n if (!changed) break;\n growLeft = !growLeft;\n }\n\n const activeRange = range(safeActive, safeActive);\n if (!fits(workstreams, safeActive, activeRange, maxCols, true)) {\n const noHintCols = Math.max(\n 0,\n maxCols - chromeWidth(hiddenLeft(safeActive), hiddenRight(workstreams, safeActive), false),\n );\n const nameCols = Math.max(0, noHintCols - stringWidth(\"▸ \"));\n return {\n leftHidden: hiddenLeft(safeActive),\n rightHidden: hiddenRight(workstreams, safeActive),\n visible: [{ name: truncateToWidth(workstreams[safeActive] ?? \"\", nameCols), isActive: true }],\n showHint: false,\n };\n }\n\n return {\n leftHidden: start,\n rightHidden: workstreams.length - end - 1,\n visible: tabsForRange(workstreams, safeActive, range(start, end)),\n showHint: true,\n };\n}\n\nfunction range(start: number, end: number): number[] {\n const out: number[] = [];\n for (let i = start; i <= end; i++) out.push(i);\n return out;\n}\n\nfunction hiddenLeft(active: number): number {\n return active;\n}\n\nfunction hiddenRight(workstreams: readonly string[], active: number): number {\n return Math.max(0, workstreams.length - active - 1);\n}\n\nfunction tabsForRange(\n workstreams: readonly string[],\n active: number,\n indexes: readonly number[],\n): VisibleTab[] {\n return indexes.map((i) => ({ name: workstreams[i] ?? \"\", isActive: i === active }));\n}\n\nfunction fits(\n workstreams: readonly string[],\n active: number,\n indexes: readonly number[],\n availableCols: number,\n showHint: boolean,\n): boolean {\n const first = indexes[0];\n const last = indexes[indexes.length - 1];\n if (first === undefined || last === undefined) return false;\n const leftHidden = first;\n const rightHidden = workstreams.length - last - 1;\n return rowWidth(workstreams, active, indexes, leftHidden, rightHidden, showHint) <= availableCols;\n}\n\nfunction rowWidth(\n workstreams: readonly string[],\n active: number,\n indexes: readonly number[],\n leftHidden: number,\n rightHidden: number,\n showHint: boolean,\n): number {\n return (\n chromeWidth(leftHidden, rightHidden, showHint) +\n indexes.reduce((sum, i, idx) => {\n const prefix = i === active ? \"▸ \" : \"\";\n const sep = idx < indexes.length - 1 ? SEP : \"\";\n return sum + stringWidth(prefix) + stringWidth(workstreams[i] ?? \"\") + stringWidth(sep);\n }, 0)\n );\n}\n\nfunction chromeWidth(leftHidden: number, rightHidden: number, showHint: boolean): number {\n return (\n stringWidth(PREFIX) +\n counterWidth(\"‹\", leftHidden) +\n counterWidth(\"›\", rightHidden) +\n (showHint ? stringWidth(leftHidden > 0 || rightHidden > 0 ? NARROW_HINT : WIDE_HINT) : 0)\n );\n}\n\nfunction counterWidth(prefix: \"‹\" | \"›\", count: number): number {\n return count > 0 ? stringWidth(`${prefix}${count} `) : 0;\n}\n\nfunction truncateToWidth(text: string, width: number): string {\n if (width <= 0) return \"\";\n if (stringWidth(text) <= width) return text;\n if (width <= stringWidth(ELLIPSIS)) return ELLIPSIS.slice(0, width);\n let out = \"\";\n const budget = width - stringWidth(ELLIPSIS);\n for (const ch of text) {\n if (stringWidth(out + ch) > budget) break;\n out += ch;\n }\n return `${out}${ELLIPSIS}`;\n}\n\nfunction clamp(value: number, min: number, max: number): number {\n return Math.max(min, Math.min(value, max));\n}\n"],"mappings":"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","names":["Box","Text","useInput","useCallback","useEffect","useRef","useState","Text","text","text","layoutColumns","visibleCardIds","config","donorCards","Box","Text","jsx","Text","Box","Box","Text","stringWidth","jsx","label","stringWidth","Box","Text","Text","Text","Fragment","jsx","jsxs","jsx","config","text","Text","jsx","jsxs","Text","row","jsx","cardConfig","GLYPH","COLUMN_SPECS","row","jsx","cardConfig","COLUMN_SPECS","formatSubtitle","row","Text","jsx","jsxs","cardConfig","COLUMN_SPECS","formatSubtitle","Text","row","jsx","cardConfig","GLYPH","COLUMN_SPECS","formatSubtitle","row","stale","jsx","cardConfig","COLUMN_SPECS","row","Text","jsx","cardConfig","COLUMN_SPECS","Text","row","jsx","cardConfig","GLYPH","COLUMN_SPECS","formatSubtitle","row","Text","jsx","jsxs","cardConfig","COLUMN_SPECS","Text","row","trackKey","Text","jsx","jsxs","cardConfig","COLUMN_SPECS","isStale","formatSubtitle","Text","glyphFor","row","Box","Text","useState","jsx","jsxs","row","useState","Box","Text","useEffect","subscribers","useEffect","subscribers","useInput","Box","Text","useCallback","useEffect","useRef","useState","jsx","hint","text","useEffect","useRef","useState","Box","Text","useEffect","jsx","jsxs","text","Box","Text","useCallback","useEffect","useMemo","useRef","useState","jsx","jsxs","useMemo","useState","useRef","useCallback","useEffect","hint","Box","Text","jsx","jsxs","COLUMN_SPECS","useState","useRef","useCallback","text","useEffect","Text","Box","row","Box","Text","useMemo","useState","useMemo","useMemo","jsx","useMemo","useMemo","Box","Text","useCallback","useState","jsx","jsxs","useState","useCallback","Box","Text","label","jsx","jsxs","COLUMN_SPECS","useState","useMemo","Text","Box","row","useMemo","Box","Text","useState","jsx","jsxs","config","useState","Text","Box","jsx","COLUMN_SPECS","useMemo","config","GLYPH","Box","Text","useCallback","useEffect","useState","spawnSync","spawnSync","text","spawnSync","spawnSync","text","jsx","jsxs","COLUMN_SPECS","useState","useCallback","useEffect","Text","shortSha","formatBackend","Box","row","Box","Text","useMemo","useRef","useState","jsx","jsxs","useMemo","useState","useRef","Box","Text","Box","Text","useState","jsx","jsxs","COLUMN_SPECS","useState","Text","Box","row","jsx","COLUMN_SPECS","GLYPH","Box","Text","useState","jsx","jsxs","COLUMN_SPECS","useState","Text","Box","row","jsx","COLUMN_SPECS","config","yankCommandForTask","jsx","COLUMN_SPECS","config","yankCommandForTask","GLYPH","Box","Text","useEffect","useMemo","useState","jsx","jsxs","COLUMN_SPECS","useState","useEffect","useMemo","Text","Box","visible","rows","widths","row","Box","Text","useCallback","useEffect","useReducer","useRef","useState","jsx","jsxs","COLUMN_SPECS","DRILL_COLUMN_SPECS","useState","useReducer","useCallback","text","loading","useRef","useEffect","Text","shortSha","Box","renderDrillBody","glyphFor","row","hint","useEffect","useRef","useState","state","useState","useRef","useEffect","Box","Text","jsx","jsxs","Box","Text","Box","Text","stringWidth","clamp","text","jsx","jsxs","Box","Text","jsx","jsxs","useState","useRef","useEffect","useCallback","useInput","Box","Text","layoutColumns"]}