@mu-crew/mu 3.12.0 → 3.13.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 (58) hide show
  1. package/dist/chunk-3BARPJLY.js +44 -0
  2. package/dist/{chunk-R2SVBZAB.js → chunk-45KQLMEL.js} +193 -93
  3. package/dist/chunk-45KQLMEL.js.map +1 -0
  4. package/dist/{chunk-TEGZOXML.js → chunk-54WJCMJR.js} +12 -10
  5. package/dist/chunk-54WJCMJR.js.map +1 -0
  6. package/dist/{chunk-XV7J56GD.js → chunk-EPCEEDHG.js} +4 -3
  7. package/dist/{chunk-XV7J56GD.js.map → chunk-EPCEEDHG.js.map} +1 -1
  8. package/dist/{chunk-77GBZ2KR.js → chunk-QITLNZEM.js} +3 -1
  9. package/dist/{chunk-77GBZ2KR.js.map → chunk-QITLNZEM.js.map} +1 -1
  10. package/dist/{chunk-IRPTNVJC.js → chunk-TXV34VWT.js} +8614 -6029
  11. package/dist/chunk-TXV34VWT.js.map +1 -0
  12. package/dist/{chunk-L2ABBTYG.js → chunk-WI6AWCMK.js} +3 -1
  13. package/dist/{chunk-L2ABBTYG.js.map → chunk-WI6AWCMK.js.map} +1 -1
  14. package/dist/{cli-MDCJEU74.js → cli-GMJUOXPW.js} +3581 -107
  15. package/dist/cli-GMJUOXPW.js.map +1 -0
  16. package/dist/cli.js +4 -3
  17. package/dist/cli.js.map +1 -1
  18. package/dist/devtools-LS4ZEPWM.js +3772 -0
  19. package/dist/devtools-LS4ZEPWM.js.map +1 -0
  20. package/dist/extension/mu-pi.js +206 -61
  21. package/dist/extension/mu-pi.js.map +1 -1
  22. package/dist/index.d.ts +309 -228
  23. package/dist/index.js +12 -5
  24. package/dist/tui-WSDDTA4K.js +40956 -0
  25. package/dist/tui-WSDDTA4K.js.map +1 -0
  26. package/dist/tui-sync-worker.js +4 -3
  27. package/dist/tui-sync-worker.js.map +1 -1
  28. package/dist/yank-XDOONQSL.js +13 -0
  29. package/docs/ARCHITECTURE.md +4 -1
  30. package/docs/ROADMAP.md +43 -38
  31. package/docs/VISION.md +8 -0
  32. package/docs/VOCABULARY.md +3 -1
  33. package/docs/architecture/dag.md +4 -0
  34. package/docs/architecture/sync.md +8 -0
  35. package/docs/architecture/tui.md +11 -2
  36. package/docs/guide/delegate.md +6 -4
  37. package/docs/guide/recovery.md +4 -0
  38. package/docs/reference/env.md +2 -2
  39. package/package.json +2 -1
  40. package/skills/mu/SKILL.md +12 -2
  41. package/skills/mu/recipes/adversarial-review.md +3 -0
  42. package/skills/mu/recipes/backlog-triage.md +2 -0
  43. package/skills/mu/recipes/findings.md +7 -0
  44. package/skills/mu/recipes/long-run.md +3 -1
  45. package/skills/mu/recipes/loop-until-done.md +3 -1
  46. package/skills/mu/recipes/orchestrator-loop.md +4 -0
  47. package/skills/mu/recipes/ultrathink.md +3 -1
  48. package/skills/mu/recipes/watcher.md +6 -1
  49. package/dist/chunk-IRPTNVJC.js.map +0 -1
  50. package/dist/chunk-PZ5AY32C.js +0 -10
  51. package/dist/chunk-R2SVBZAB.js.map +0 -1
  52. package/dist/chunk-TEGZOXML.js.map +0 -1
  53. package/dist/cli-MDCJEU74.js.map +0 -1
  54. package/dist/tui-LO75XA3O.js +0 -6452
  55. package/dist/tui-LO75XA3O.js.map +0 -1
  56. package/dist/yank-T3AYQTVR.js +0 -12
  57. /package/dist/{chunk-PZ5AY32C.js.map → chunk-3BARPJLY.js.map} +0 -0
  58. /package/dist/{yank-T3AYQTVR.js.map → yank-XDOONQSL.js.map} +0 -0
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/cli/format.ts","../src/tasks/sort.ts"],"sourcesContent":["// mu — pure rendering helpers used by every cli/*.ts verb wrapper.\n//\n// Extracted from src/cli.ts (review_cli_ts_past_refactor_signal): the\n// table renderers, status colourers, truncators, and relative-time\n// formatter were the bulk of cli.ts's bloat (~600 LOC over the 800-LOC\n// refactor signal). Co-locating them here keeps cli.ts focused on\n// argument parsing, workstream resolution, and program wiring.\n//\n// All helpers are pure (no I/O beyond returning a string) except\n// `printLogRow` which writes a single line to stdout — kept here so\n// `mu log` and the `recent events` section of `mu state` share one\n// renderer. cli.ts re-exports every symbol for back-compat with the\n// existing import surface (tests + cli/* importers).\n\nimport { type RuntimeState, UNKNOWN_REASON } from \"../agent-state.js\";\nimport type { LiveAgent } from \"../agents.js\";\nimport { agentStateGlyph, GLYPH } from \"../glyphs.js\";\nimport { parseOpKey, renderOp } from \"../log-render.js\";\nimport type { LogRow } from \"../logs.js\";\nimport { muTable, pc, renderBoxTable } from \"../output.js\";\nimport { formatPair, type TaskPair } from \"../tasks/status.js\";\nimport type { TaskRow } from \"../tasks.js\";\nimport type { Track } from \"../tracks.js\";\nimport type { WorkspaceRow } from \"../workspace.js\";\nimport type { TornDownWorkstream, WorkstreamSummary } from \"../workstream.js\";\n\n// ─── Status colours / icons ────────────────────────────────────────────\n\n/** Per-status colour for the table view. The glyph itself comes from\n * agentStateGlyph in src/glyphs.ts — single source of truth so the\n * CLI and TUI status surfaces never drift\n * (review_code_status_emoji_two_sources caught a 2-of-7 disagreement). */\nconst STATUS_COLORS: Record<RuntimeState, (s: string) => string> = {\n busy: pc.cyan,\n needs_input: pc.dim,\n needs_permission: pc.magenta,\n unknown: pc.dim,\n};\n\nexport function statusIcon(state: RuntimeState): string {\n return STATUS_COLORS[state](agentStateGlyph(state));\n}\n\n/**\n * Glyph used to flag the derived 'idle but assigned' state\n * (`AgentRow.idle === true`; idle_assigned_agent_detection). Same\n * warning glyph the doctor card paints for a `warn` check — one\n * symbol, one meaning, from src/glyphs.ts.\n */\nexport const IDLE_GLYPH = GLYPH.warn;\n\n/** Colour a task's (status, substate) pair, rendered by formatPair:\n * bare \"OPEN\" for a default substate, \"CLOSED/wontfix\" otherwise.\n * OPEN cyan, IN_PROGRESS yellow, CLOSED/done green, any other CLOSED\n * red (not done), OPEN/parked dim (out of the ready set). */\nexport function colorPair(pair: TaskPair): string {\n const text = formatPair(pair);\n switch (pair.status) {\n case \"OPEN\":\n return pair.substate === \"parked\" || pair.substate === \"triage\"\n ? pc.dim(text)\n : pc.cyan(text);\n case \"IN_PROGRESS\":\n return pc.yellow(text);\n case \"CLOSED\":\n return pair.substate === \"done\" ? pc.green(text) : pc.red(text);\n }\n}\n\n/** Colour a bare status. Only for callers with no substate in hand\n * (e.g. the TUI status-filter toggles); task rows use colorPair. */\nexport function colorStatus(status: TaskRow[\"status\"]): string {\n switch (status) {\n case \"OPEN\":\n return pc.cyan(status);\n case \"IN_PROGRESS\":\n return pc.yellow(status);\n case \"CLOSED\":\n return pc.green(status);\n }\n}\n\n/** Ink colour equivalent of colorPair(). The TUI must not embed\n * picocolors ANSI strings inside <Text>; rows pass this value to Ink's\n * color prop instead. */\nexport type InkColor = \"cyan\" | \"yellow\" | \"green\" | \"gray\" | \"red\";\n\n/** Ink colour for a task's pair; same mapping as colorPair(). */\nexport function inkColorForPair(pair: TaskPair): InkColor {\n switch (pair.status) {\n case \"OPEN\":\n return pair.substate === \"parked\" || pair.substate === \"triage\" ? \"gray\" : \"cyan\";\n case \"IN_PROGRESS\":\n return \"yellow\";\n case \"CLOSED\":\n return pair.substate === \"done\" ? \"green\" : \"red\";\n }\n}\n\n// ─── Width / truncation helpers ───────────────────────────────────────\n\n/**\n * Default fallback when stdout isn't a TTY (e.g. output is piped to\n * less/jq) and `process.stdout.columns` is undefined. 100 fits an 80-col\n * terminal with some breathing room; 100 is wide enough to keep most\n * rows on one line.\n */\nconst DEFAULT_TERMINAL_WIDTH = 100;\n\nexport function terminalWidth(): number {\n return process.stdout.columns ?? DEFAULT_TERMINAL_WIDTH;\n}\n\n/** Truncate `s` to fit `max` columns (counting display width as length;\n * good enough for ASCII titles, undercount for emoji/CJK — acceptable\n * trade-off given the terminal will visually clip anyway). Adds an\n * ellipsis when truncated. */\nexport function truncate(s: string, max: number): string {\n if (max <= 1) return s.slice(0, max);\n if (s.length <= max) return s;\n return `${s.slice(0, max - 1)}…`;\n}\n\n/** Front-truncate `s` to fit `max` columns, prepending an ellipsis when\n * truncated. Used for paths where the trailing `<workstream>/<agent>`\n * suffix is the only useful bit (the leading `~/.local/state/mu/...`\n * prefix is identical for every row). Surfaced live by `mu workspace\n * list` blowing the terminal width on the `path` column\n * (tables_truncate_long_cols_audit). */\nexport function truncateFront(s: string, max: number): string {\n if (max <= 1) return s.slice(-max);\n if (s.length <= max) return s;\n return `…${s.slice(-(max - 1))}`;\n}\n\n/** Format an elapsed duration (in ms) as a compact relative string:\n * '12s', '3m', '1h', '2d', '3w'. Used by the task list table when\n * `--sort recency`/`--sort age` is active so the timeframe the user\n * is sorting by is visible. Mirrors the helper in src/cli/state.ts\n * (TUI renderers); kept in sync (the TUI version omits weeks because it shows tighter\n * windows, but for task list a 5w-old item is real and worth a tag).\n */\nexport function relTime(ms: number): string {\n const sec = Math.max(0, Math.floor(ms / 1000));\n if (sec < 60) return `${sec}s`;\n const min = Math.floor(sec / 60);\n if (min < 60) return `${min}m`;\n const hr = Math.floor(min / 60);\n if (hr < 24) return `${hr}h`;\n const day = Math.floor(hr / 24);\n if (day < 7) return `${day}d`;\n return `${Math.floor(day / 7)}w`;\n}\n\n/** Like {@link relTime} but with a trailing \" ago\" suffix. The TUI's\n * Recent card / popup wants past-tense formatting (\"3m ago\") while\n * the In-progress card / popup wants the bare token (\"3m\"); both\n * buckets share the rest of the arithmetic. Hoisted out of the TUI\n * cluster (review_unify_format_when_since) so the two formatters\n * can't drift the way they were starting to. */\nexport function relTimeAgo(ms: number): string {\n return `${relTime(ms)} ago`;\n}\n\n// ─── Table renderers ──────────────────────────────────────────────────\n\nexport function formatAgentsTable(agents: readonly LiveAgent[]): string {\n if (agents.length === 0) return pc.dim(\" (no agents)\");\n // Cap the variable-width columns so a long tmux window name (or a\n // future free-text role) can't push the table past the terminal.\n // Other columns are bounded by their schemas (name 32-char cap,\n // cli is one of pi/codex/claude, status is one of OPEN/...).\n const table = muTable({\n head: [\n pc.bold(\"\"),\n pc.bold(\"name\"),\n pc.bold(\"cli\"),\n pc.bold(\"state\"),\n pc.bold(\"window\"),\n pc.bold(\"role\"),\n ],\n colWidths: [null, null, null, null, 32, 14],\n style: { head: [] },\n });\n for (const a of agents) {\n // Idle (alive + assigned + no recent progress): supplement the\n // status glyph with the yellow shared warning glyph, and yellow the\n // agent name itself so the row is visually obvious. The status column\n // stays the truth ('needs_input'); GLYPH.warn is the supplement.\n const idle = a.idle === true;\n const glyphCell = idle\n ? `${pc.yellow(IDLE_GLYPH)} ${statusIcon(a.state)}`\n : statusIcon(a.state);\n const nameCell = idle ? pc.yellow(a.name) : a.name;\n table.push([\n glyphCell,\n nameCell,\n a.cli,\n a.state === \"unknown\" && a.reason !== undefined ? `${a.state}: ${a.reason}` : a.state,\n a.tab ?? a.name,\n a.role === \"read-only\" ? pc.yellow(\"read-only\") : \"\",\n ]);\n }\n const needsMurmur = agents.some(\n (a) =>\n a.state === \"unknown\" &&\n (a.reason === UNKNOWN_REASON.murmurMissing || a.reason === UNKNOWN_REASON.extensionMissing),\n );\n return needsMurmur\n ? `${table.toString()}\\n${pc.dim(\"agent state needs murmur (see mu doctor)\")}`\n : table.toString();\n}\n\nexport function formatReadyTable(tasks: readonly TaskRow[]): string {\n if (tasks.length === 0) return pc.dim(\" (no ready tasks)\");\n // Sort by ROI descending.\n const sorted = [...tasks].sort((a, b) => b.impact / b.effortDays - a.impact / a.effortDays);\n // Same title-truncation treatment as formatTaskListTable so the\n // ready-task table doesn't blow out terminal width.\n let idW = \"name\".length;\n let impactW = \"impact\".length;\n let effortW = \"effort\".length;\n let roiW = \"ROI\".length;\n let ownerW = \"owner\".length;\n for (const t of sorted) {\n idW = Math.max(idW, t.name.length);\n impactW = Math.max(impactW, String(t.impact).length);\n effortW = Math.max(effortW, String(t.effortDays).length);\n const roi = (t.impact / t.effortDays).toFixed(1);\n roiW = Math.max(roiW, roi.length);\n ownerW = Math.max(ownerW, (t.ownerName ?? \"\").length);\n }\n const padding = 6 * 3 + 1; // 6 cols\n const titleBudget = Math.max(\n 20,\n terminalWidth() - (idW + impactW + effortW + roiW + ownerW) - padding,\n );\n\n // Title is pre-truncated above; use muTable so wordWrap:false acts\n // as a safety belt for any other cell we don't pre-trim.\n const table = muTable({\n head: [\n pc.bold(\"name\"),\n pc.bold(\"title\"),\n pc.bold(\"impact\"),\n pc.bold(\"effort\"),\n pc.bold(\"ROI\"),\n pc.bold(\"owner\"),\n ],\n style: { head: [] },\n });\n for (const t of sorted) {\n const roi = (t.impact / t.effortDays).toFixed(1);\n table.push([\n t.name,\n truncate(t.title, titleBudget),\n String(t.impact),\n String(t.effortDays),\n roi,\n t.ownerName ?? \"\",\n ]);\n }\n return table.toString();\n}\n\nexport function formatTracks(tracks: readonly Track[]): string {\n if (tracks.length === 0) return pc.dim(\" (no open tracks)\");\n const lines: string[] = [];\n tracks.forEach((track, i) => {\n const rootNames = track.roots.map((r) => r.name).join(\", \");\n const verb = track.roots.length > 1 ? \"merged\" : \"track\";\n const parked = track.parked ? ` ${pc.dim(\"(parked)\")}` : \"\";\n lines.push(\n ` Track ${i + 1}: ${pc.bold(rootNames)} ${pc.dim(`(${track.taskIds.size} tasks, ${track.readyCount} ready, ${verb})`)}${parked}`,\n );\n });\n return lines.join(\"\\n\");\n}\n\n/** Workspaces table renderer. Used by `mu workspace list` and by\n * `mu state`'s Workspaces section — exported so cli/workspace.ts\n * can reuse it. The `behind` column shows how many commits the row's\n * parent_ref is behind the project's default branch HEAD; color-coded\n * green ≤2, yellow 3–9, red ≥10. Renders \"—\" when the count couldn't\n * be computed (no main resolvable, none-backend, missing parent_ref)\n * or wasn't asked for (no decorateWithStaleness call). Surfaced by\n * bug_workspace_stale_parent_silent_drift. */\nexport function formatWorkspacesTable(rows: readonly WorkspaceRow[]): string {\n // The path column is the one that bit operators today: an absolute\n // ~/.local/state/mu/workspaces/<ws>/worker-foo path runs ~70 chars\n // and pushed the table to ~200 cols. Front-truncate so the useful\n // trailing `<ws>/<agent>` suffix survives, then cap the column with\n // colWidths as a safety belt (tables_truncate_long_cols_audit).\n const PATH_BUDGET = 40;\n const table = muTable({\n head: [\"agent\", \"workstream\", \"backend\", \"path\", \"parent_ref\", \"behind\", \"created\"].map((h) =>\n pc.bold(h),\n ),\n colWidths: [null, null, null, PATH_BUDGET, null, null, null],\n });\n for (const r of rows) {\n table.push([\n r.agentName,\n r.workstreamName,\n r.backend,\n truncateFront(r.path, PATH_BUDGET - 2),\n r.parentRef ? pc.dim(r.parentRef.slice(0, 12)) : pc.dim(\"—\"),\n formatBehind(r.commitsBehindMain),\n pc.dim(r.createdAt),\n ]);\n }\n return table.toString();\n}\n\n/** Color-code the commits-behind-main count. Green ≤2 (fresh), yellow\n * 3–9 (drifting), red ≥10 (stale). Undefined / null renders as a dim\n * em-dash so the column stays well-typed even when staleness wasn't\n * computed. */\nfunction formatBehind(n: number | null | undefined): string {\n if (n === undefined || n === null) return pc.dim(\"—\");\n if (n <= 2) return pc.green(String(n));\n if (n <= 9) return pc.yellow(String(n));\n return pc.red(String(n));\n}\n\n/** One op, human-formatted. Used by `mu log` (read + tail) and by the\n * `recent events` section of `mu state`.\n *\n * All prose comes from `renderOp` (src/log-render.ts) — the ONE\n * formatter. This function only adds colour and column layout, so the\n * terminal and the TUI can never drift into two phrasings of the same\n * op. No raw JSON reaches the operator here. */\nexport function printLogRow(row: LogRow): void {\n const time = row.createdAt.replace(\"T\", \" \").replace(/\\.\\d+Z$/, \"Z\");\n const rendered = renderOp(row);\n const scope = parseOpKey(row.workstreamName).workstream;\n const where = scope === undefined ? pc.dim(\"—\") : scope;\n if (rendered === null) {\n // No intent: operator prose from `mu log \"<text>\"` or a `--kind`\n // ledger. Show it verbatim — inventing a verb for it would be\n // wrong, it is already exactly what the operator typed.\n console.log(\n `${pc.dim(`#${row.seq}`)} ${pc.dim(time)} ${pc.bold(row.source)} ${pc.yellow(row.kind)} [${where}] ${row.payload}`,\n );\n return;\n }\n const detail = rendered.detail === \"\" ? \"\" : ` ${pc.dim(rendered.detail)}`;\n console.log(\n `${pc.dim(`#${row.seq}`)} ${pc.dim(time)} ${pc.bold(row.source)} ${pc.cyan(rendered.verb)} ${rendered.subject}${detail} ${pc.dim(`[${where}]`)}`,\n );\n}\n\n/**\n * Workstreams summary table renderer. Used by `mu workstream list`\n * and the bare-`mu` empty-machine discovery fallback. Both\n * render the same shape; the helper lives here so cli/workstream.ts\n * and cli.ts can both import it without a lateral cli/* dependency.\n */\nexport function formatWorkstreamsTable(rows: WorkstreamSummary[]): string {\n // Workstream names are user-chosen free-form text; everything else\n // is a small int / fixed-shape token. Cap the name column so a long\n // workstream name doesn't push the row counts off-screen.\n const table = muTable({\n head: [\"name\", \"mux\", \"agents\", \"tasks\", \"edges\", \"notes\"].map((h) => pc.bold(h)),\n colWidths: [40, null, null, null, null, null],\n });\n for (const r of rows) {\n table.push([\n r.name,\n r.muxAlive ? pc.green(\"alive\") : pc.dim(\"—\"),\n String(r.agentCount),\n String(r.taskCount),\n String(r.edgeCount),\n String(r.noteCount),\n ]);\n }\n return table.toString();\n}\n\n/**\n * Past teardowns, newest first.\n *\n * `group` leads after the name because it is the only ACTIONABLE\n * column — the whole point of the list is to feed `mu undo <group>` —\n * and it is shown short (8 chars), which is what `mu undo` accepts.\n */\nexport function formatTornDownWorkstreamsTable(rows: readonly TornDownWorkstream[]): string {\n const table = muTable({\n head: [\"name\", \"group\", \"torn down\", \"tasks\", \"edges\", \"notes\", \"\"].map((h) => pc.bold(h)),\n colWidths: [32, null, null, null, null, null, null],\n });\n for (const r of rows) {\n // relTimeAgo takes an ELAPSED duration, not a timestamp.\n const at = Date.parse(r.at);\n table.push([\n r.name,\n r.group.slice(0, 8),\n Number.isNaN(at) ? pc.dim(\"—\") : relTimeAgo(Date.now() - at),\n String(r.tasks),\n String(r.edges),\n String(r.notes),\n r.recreated ? pc.dim(\"← recreated since\") : \"\",\n ]);\n }\n return table.toString();\n}\n\nexport function formatTaskListTable(\n tasks: readonly TaskRow[],\n opts: { withWorkstream?: boolean; relTimeBasis?: \"updatedAt\" | \"createdAt\" } = {},\n): string {\n if (tasks.length === 0) return pc.dim(\" (no tasks)\");\n // The optional relative-time column is appended at the end; header\n // mirrors the timestamp basis (\"updated\" / \"created\") so a glance\n // says which sort key is live.\n const timeHeader =\n opts.relTimeBasis === \"updatedAt\"\n ? \"updated\"\n : opts.relTimeBasis === \"createdAt\"\n ? \"created\"\n : null;\n const baseHead = opts.withWorkstream\n ? [\"name\", \"workstream\", \"status\", \"title\", \"impact\", \"effort\", \"ROI\", \"owner\"]\n : [\"name\", \"status\", \"title\", \"impact\", \"effort\", \"ROI\", \"owner\"];\n const head = timeHeader === null ? baseHead : [...baseHead, timeHeader];\n\n // Pre-compute the relative-time strings (relative to NOW) so column\n // width and row text agree.\n const now = Date.now();\n const timeCells: string[] = [];\n if (opts.relTimeBasis !== undefined) {\n const basis = opts.relTimeBasis;\n for (const t of tasks) {\n const ts = basis === \"updatedAt\" ? t.updatedAt : t.createdAt;\n const ms = now - new Date(ts).getTime();\n timeCells.push(relTime(ms));\n }\n }\n\n // Compute a budget for the title column so the table fits the terminal.\n // Other columns are mostly short fixed-shape values; figure out how\n // wide they actually are, sum them up, and give title the leftover.\n const otherCols = opts.withWorkstream\n ? ([\"localId\", \"workstream\", \"status\", \"impact\", \"effortDays\", \"roi\", \"owner\"] as const)\n : ([\"localId\", \"status\", \"impact\", \"effortDays\", \"roi\", \"owner\"] as const);\n const widths = new Map<string, number>();\n for (const col of otherCols) widths.set(col, col.length); // header is the floor\n for (const t of tasks) {\n widths.set(\"localId\", Math.max(widths.get(\"localId\") ?? 0, t.name.length));\n if (opts.withWorkstream) {\n widths.set(\"workstream\", Math.max(widths.get(\"workstream\") ?? 0, t.workstreamName.length));\n }\n widths.set(\"status\", Math.max(widths.get(\"status\") ?? 0, formatPair(t).length));\n widths.set(\"impact\", Math.max(widths.get(\"impact\") ?? 0, String(t.impact).length));\n widths.set(\"effortDays\", Math.max(widths.get(\"effortDays\") ?? 0, String(t.effortDays).length));\n const roi = t.effortDays > 0 ? (t.impact / t.effortDays).toFixed(1) : \"∞\";\n widths.set(\"roi\", Math.max(widths.get(\"roi\") ?? 0, roi.length));\n widths.set(\"owner\", Math.max(widths.get(\"owner\") ?? 0, (t.ownerName ?? \"—\").length));\n }\n let timeWidth = 0;\n if (timeHeader !== null) {\n timeWidth = timeHeader.length;\n for (const cell of timeCells) timeWidth = Math.max(timeWidth, cell.length);\n }\n // cli-table3 adds 2 chars of padding per cell + 1 char border per\n // column. Account for that to find the title budget.\n const numCols = head.length;\n const otherTotal = otherCols.reduce((acc, c) => acc + (widths.get(c) ?? 0), 0) + timeWidth;\n const padding = numCols * 3 + 1;\n const titleBudget = Math.max(20, terminalWidth() - otherTotal - padding);\n\n // Title is pre-truncated to titleBudget above. renderBoxTable, not\n // cli-table3: its layout pass is quadratic in rows\n // (f_tasklist_table_render).\n const rows: string[][] = [];\n for (let i = 0; i < tasks.length; i++) {\n const t = tasks[i];\n if (!t) continue; // noUncheckedIndexedAccess\n const roi = t.effortDays > 0 ? (t.impact / t.effortDays).toFixed(1) : \"∞\";\n const title = truncate(t.title, titleBudget);\n const baseRow = opts.withWorkstream\n ? [\n t.name,\n t.workstreamName,\n colorPair(t),\n title,\n String(t.impact),\n String(t.effortDays),\n roi,\n t.ownerName ?? pc.dim(\"—\"),\n ]\n : [\n t.name,\n colorPair(t),\n title,\n String(t.impact),\n String(t.effortDays),\n roi,\n t.ownerName ?? pc.dim(\"—\"),\n ];\n const row = timeHeader === null ? baseRow : [...baseRow, pc.dim(timeCells[i] ?? \"\")];\n rows.push(row);\n }\n return renderBoxTable(\n head.map((h) => pc.bold(h)),\n rows,\n );\n}\n","// Shared task sort keys and comparators.\n//\n// Used by the CLI task list/next verbs and by the TUI all-tasks popup.\n// Keep this below the CLI layer so TUI files never import from src/cli.ts\n// (that bundle cycle previously made `node dist/cli.js --help` exit\n// silently).\n\nimport type { TaskRow } from \"./core.js\";\n\nexport const TASK_SORT_KEYS = [\"roi\", \"recency\", \"age\", \"id\"] as const;\nexport type TaskSortKey = (typeof TASK_SORT_KEYS)[number];\n\nexport function isTaskSortKey(s: string): s is TaskSortKey {\n return (TASK_SORT_KEYS as readonly string[]).includes(s);\n}\n\nfunction roiOf(t: TaskRow): number {\n return t.effortDays > 0 ? t.impact / t.effortDays : Number.POSITIVE_INFINITY;\n}\n\nexport function byRoiDesc(a: TaskRow, b: TaskRow): number {\n const ra = roiOf(a);\n const rb = roiOf(b);\n if (rb !== ra) return rb - ra;\n if (a.effortDays !== b.effortDays) return a.effortDays - b.effortDays;\n return a.name.localeCompare(b.name);\n}\n\n/** Sort a copy of `tasks` by `key`. Pure (does not mutate input). */\nexport function sortTasks(tasks: readonly TaskRow[], key: TaskSortKey): TaskRow[] {\n const out = tasks.slice();\n switch (key) {\n case \"roi\":\n return out.sort(byRoiDesc);\n case \"recency\":\n // updated_at DESC: most-recently-touched first.\n return out.sort((a, b) => {\n const byUpdated = b.updatedAt.localeCompare(a.updatedAt);\n return byUpdated !== 0 ? byUpdated : a.name.localeCompare(b.name);\n });\n case \"age\":\n // created_at ASC: oldest first (\"what's gone stale\").\n return out.sort((a, b) => {\n const byCreated = a.createdAt.localeCompare(b.createdAt);\n return byCreated !== 0 ? byCreated : a.name.localeCompare(b.name);\n });\n case \"id\":\n return out.sort((a, b) => a.name.localeCompare(b.name));\n }\n}\n\n/** Which timestamp basis the table's relative-time column should use\n * for the active sort, or `null` if no time column should be shown. */\nexport function relTimeBasisForSort(key: TaskSortKey): \"updatedAt\" | \"createdAt\" | null {\n if (key === \"recency\") return \"updatedAt\";\n if (key === \"age\") return \"createdAt\";\n return null;\n}\n"],"mappings":"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","names":[]}