@jaggerxtrm/specialists 3.17.0 → 3.18.1

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 (255) hide show
  1. package/README.md +268 -134
  2. package/config/mandatory-rules/executor-delivery.md +4 -0
  3. package/config/mandatory-rules/json-only-final-output.md +13 -0
  4. package/config/mandatory-rules/service-skills-diff-scan-mandatory.md +26 -0
  5. package/config/mandatory-rules/service-skills-gitnexus-triage.md +5 -0
  6. package/config/mandatory-rules/test-runner-execution-scope.md +4 -0
  7. package/config/skills/setup-specialists/SKILL.md +556 -0
  8. package/config/skills/specialists-creator/SKILL.md +132 -4
  9. package/config/skills/specialists-creator/scripts/audit-spec-uniformity.mjs +1 -1
  10. package/config/skills/using-specialists-v3/SKILL.md +80 -20
  11. package/config/specialists/bare.specialist.json +3 -3
  12. package/config/specialists/changelog-drafter.specialist.json +5 -4
  13. package/config/specialists/changelog-keeper.specialist.json +7 -6
  14. package/config/specialists/debugger.specialist.json +2 -2
  15. package/config/specialists/executor.specialist.json +2 -2
  16. package/config/specialists/explorer.specialist.json +4 -4
  17. package/config/specialists/memory-processor.specialist.json +3 -3
  18. package/config/specialists/node-coordinator.specialist.json +3 -3
  19. package/config/specialists/obligations-scanner.specialist.json +67 -17
  20. package/config/specialists/overthinker.specialist.json +3 -3
  21. package/config/specialists/planner.specialist.json +4 -4
  22. package/config/specialists/quant-methodologist.specialist.json +145 -0
  23. package/config/specialists/quant-researcher.specialist.json +144 -0
  24. package/config/specialists/researcher.specialist.json +5 -5
  25. package/config/specialists/reviewer.specialist.json +1 -1
  26. package/config/specialists/seconder.specialist.json +2 -2
  27. package/config/specialists/security-auditor.specialist.json +2 -2
  28. package/config/specialists/service-skills-sync.specialist.json +90 -75
  29. package/config/specialists/specialists-creator.specialist.json +4 -4
  30. package/config/specialists/sync-docs.specialist.json +4 -4
  31. package/config/specialists/test-engineer.specialist.json +3 -3
  32. package/config/specialists/test-runner.specialist.json +7 -7
  33. package/config/specialists/transcriber.specialist.json +3 -3
  34. package/config/specialists/xt-merge.specialist.json +4 -4
  35. package/dist/asset-contract.json +22 -3
  36. package/dist/index.js +28711 -18517
  37. package/dist/lib.js +10020 -6150
  38. package/dist/types/cli/console/components.d.ts +83 -0
  39. package/dist/types/cli/console/components.d.ts.map +1 -0
  40. package/dist/types/cli/console/config-source.d.ts +58 -0
  41. package/dist/types/cli/console/config-source.d.ts.map +1 -0
  42. package/dist/types/cli/console/forensic.d.ts +11 -0
  43. package/dist/types/cli/console/forensic.d.ts.map +1 -0
  44. package/dist/types/cli/console/git.d.ts +28 -0
  45. package/dist/types/cli/console/git.d.ts.map +1 -0
  46. package/dist/types/cli/console/help.d.ts +2 -0
  47. package/dist/types/cli/console/help.d.ts.map +1 -0
  48. package/dist/types/cli/console/log.d.ts +13 -0
  49. package/dist/types/cli/console/log.d.ts.map +1 -0
  50. package/dist/types/cli/console/repo-config.d.ts +26 -0
  51. package/dist/types/cli/console/repo-config.d.ts.map +1 -0
  52. package/dist/types/cli/console/repo-discovery.d.ts +12 -0
  53. package/dist/types/cli/console/repo-discovery.d.ts.map +1 -0
  54. package/dist/types/cli/console/runtime.d.ts +12 -0
  55. package/dist/types/cli/console/runtime.d.ts.map +1 -0
  56. package/dist/types/cli/console/subscribe-prototype.d.ts +18 -0
  57. package/dist/types/cli/console/subscribe-prototype.d.ts.map +1 -0
  58. package/dist/types/cli/console/theme.d.ts +91 -0
  59. package/dist/types/cli/console/theme.d.ts.map +1 -0
  60. package/dist/types/cli/console/types.d.ts +231 -0
  61. package/dist/types/cli/console/types.d.ts.map +1 -0
  62. package/dist/types/cli/console/view-model.d.ts +252 -0
  63. package/dist/types/cli/console/view-model.d.ts.map +1 -0
  64. package/dist/types/cli/console.d.ts +2 -0
  65. package/dist/types/cli/console.d.ts.map +1 -0
  66. package/dist/types/cli/db.d.ts.map +1 -1
  67. package/dist/types/cli/doctor.d.ts.map +1 -1
  68. package/dist/types/cli/edit.d.ts.map +1 -1
  69. package/dist/types/cli/epic.d.ts.map +1 -1
  70. package/dist/types/cli/feed.d.ts.map +1 -1
  71. package/dist/types/cli/forensic.d.ts +2 -0
  72. package/dist/types/cli/forensic.d.ts.map +1 -0
  73. package/dist/types/cli/format-helpers.d.ts +4 -2
  74. package/dist/types/cli/format-helpers.d.ts.map +1 -1
  75. package/dist/types/cli/help.d.ts.map +1 -1
  76. package/dist/types/cli/init.d.ts +10 -0
  77. package/dist/types/cli/init.d.ts.map +1 -1
  78. package/dist/types/cli/list.d.ts.map +1 -1
  79. package/dist/types/cli/log.d.ts.map +1 -1
  80. package/dist/types/cli/merge.d.ts.map +1 -1
  81. package/dist/types/cli/metrics.d.ts +2 -0
  82. package/dist/types/cli/metrics.d.ts.map +1 -0
  83. package/dist/types/cli/ps.d.ts.map +1 -1
  84. package/dist/types/cli/result.d.ts.map +1 -1
  85. package/dist/types/cli/run.d.ts +20 -0
  86. package/dist/types/cli/run.d.ts.map +1 -1
  87. package/dist/types/cli/script.d.ts +3 -0
  88. package/dist/types/cli/script.d.ts.map +1 -1
  89. package/dist/types/cli/serve.d.ts.map +1 -1
  90. package/dist/types/cli/setup.d.ts +19 -1
  91. package/dist/types/cli/setup.d.ts.map +1 -1
  92. package/dist/types/cli/status.d.ts.map +1 -1
  93. package/dist/types/cli/version-check.d.ts +1 -0
  94. package/dist/types/cli/version-check.d.ts.map +1 -1
  95. package/dist/types/index.d.ts +1 -1
  96. package/dist/types/pi/session.d.ts +12 -1
  97. package/dist/types/pi/session.d.ts.map +1 -1
  98. package/dist/types/server.d.ts +15 -0
  99. package/dist/types/server.d.ts.map +1 -1
  100. package/dist/types/specialist/benchmarks.d.ts +37 -0
  101. package/dist/types/specialist/benchmarks.d.ts.map +1 -0
  102. package/dist/types/specialist/chain-identity.d.ts +7 -1
  103. package/dist/types/specialist/chain-identity.d.ts.map +1 -1
  104. package/dist/types/specialist/control.d.ts.map +1 -1
  105. package/dist/types/specialist/dead-job-audit.d.ts +20 -0
  106. package/dist/types/specialist/dead-job-audit.d.ts.map +1 -0
  107. package/dist/types/specialist/forensic-events.d.ts +138 -0
  108. package/dist/types/specialist/forensic-events.d.ts.map +1 -0
  109. package/dist/types/specialist/forensic-renderer.d.ts +34 -0
  110. package/dist/types/specialist/forensic-renderer.d.ts.map +1 -0
  111. package/dist/types/specialist/git-diff-evidence.d.ts +28 -0
  112. package/dist/types/specialist/git-diff-evidence.d.ts.map +1 -0
  113. package/dist/types/specialist/global-config.d.ts +389 -0
  114. package/dist/types/specialist/global-config.d.ts.map +1 -0
  115. package/dist/types/specialist/launch.d.ts +9 -0
  116. package/dist/types/specialist/launch.d.ts.map +1 -1
  117. package/dist/types/specialist/live-aggregates.d.ts +46 -0
  118. package/dist/types/specialist/live-aggregates.d.ts.map +1 -0
  119. package/dist/types/specialist/loader.d.ts +50 -1
  120. package/dist/types/specialist/loader.d.ts.map +1 -1
  121. package/dist/types/specialist/model-chain.d.ts +7 -0
  122. package/dist/types/specialist/model-chain.d.ts.map +1 -0
  123. package/dist/types/specialist/model-probes.d.ts +28 -0
  124. package/dist/types/specialist/model-probes.d.ts.map +1 -0
  125. package/dist/types/specialist/node-contract.d.ts +18 -18
  126. package/dist/types/specialist/node-supervisor.d.ts.map +1 -1
  127. package/dist/types/specialist/observability-db.d.ts +1 -1
  128. package/dist/types/specialist/observability-db.d.ts.map +1 -1
  129. package/dist/types/specialist/observability-sqlite.d.ts +101 -0
  130. package/dist/types/specialist/observability-sqlite.d.ts.map +1 -1
  131. package/dist/types/specialist/pr-drift-refresh.d.ts +17 -0
  132. package/dist/types/specialist/pr-drift-refresh.d.ts.map +1 -0
  133. package/dist/types/specialist/preset-resolver.d.ts +56 -0
  134. package/dist/types/specialist/preset-resolver.d.ts.map +1 -0
  135. package/dist/types/specialist/prometheus-projection.d.ts +25 -0
  136. package/dist/types/specialist/prometheus-projection.d.ts.map +1 -0
  137. package/dist/types/specialist/runner.d.ts +29 -1
  138. package/dist/types/specialist/runner.d.ts.map +1 -1
  139. package/dist/types/specialist/schema.d.ts +163 -54
  140. package/dist/types/specialist/schema.d.ts.map +1 -1
  141. package/dist/types/specialist/script-runner.d.ts +5 -1
  142. package/dist/types/specialist/script-runner.d.ts.map +1 -1
  143. package/dist/types/specialist/snapshot-diff.d.ts +8 -0
  144. package/dist/types/specialist/snapshot-diff.d.ts.map +1 -0
  145. package/dist/types/specialist/source-queue.d.ts +13 -0
  146. package/dist/types/specialist/source-queue.d.ts.map +1 -0
  147. package/dist/types/specialist/status-load.d.ts.map +1 -1
  148. package/dist/types/specialist/supervisor.d.ts +25 -1
  149. package/dist/types/specialist/supervisor.d.ts.map +1 -1
  150. package/dist/types/specialist/timeline-events.d.ts +70 -1
  151. package/dist/types/specialist/timeline-events.d.ts.map +1 -1
  152. package/dist/types/tools/specialist/resume_specialist.tool.d.ts +4 -4
  153. package/dist/types/tools/specialist/specialist_status.tool.d.ts +1 -1
  154. package/dist/types/tools/specialist/steer_specialist.tool.d.ts +4 -4
  155. package/dist/types/tools/specialist/use_specialist.tool.d.ts +16 -16
  156. package/docs/ARCHITECTURE.md +1176 -0
  157. package/docs/TODO.md +9 -0
  158. package/docs/architecture.md +11 -0
  159. package/docs/archive/2026-03-13-bd-decision-context-template-plan.md +96 -0
  160. package/docs/archive/AGENT-HANDOFF.md +351 -0
  161. package/docs/archive/PARITY-ANALYSIS.md +296 -0
  162. package/docs/archive/SPECIALISTS_REFACTOR.md.md +30 -0
  163. package/docs/archive/cc-programmatic.md +216 -0
  164. package/docs/archive/claude-agent-sdk.md +594 -0
  165. package/docs/archive/decision-specialist-directory.md +41 -0
  166. package/docs/archive/discoveries.md +148 -0
  167. package/docs/archive/executor-benchmark-protocol.md +198 -0
  168. package/docs/archive/future-features.md +66 -0
  169. package/docs/archive/gzrx-completion-critique.md +183 -0
  170. package/docs/archive/gzrx-research-notes.md +401 -0
  171. package/docs/archive/gzrx-tool-catalog.md +760 -0
  172. package/docs/archive/iron-review-hardening-qa-chain-substrate.md +322 -0
  173. package/docs/archive/iron-review-hardening.html +1004 -0
  174. package/docs/archive/issuetracking.md +312 -0
  175. package/docs/archive/qa-v3.0.2.md +220 -0
  176. package/docs/archive/restructure.md +231 -0
  177. package/docs/archive/script-specialists.md +1254 -0
  178. package/docs/archive/spec-v3.md +792 -0
  179. package/docs/archive/specialist-stats.md +127 -0
  180. package/docs/archive/specialists-friction-audit.md +1347 -0
  181. package/docs/archive/specialists-runtime-critique.md +170 -0
  182. package/docs/archive/specialists-service-evaluation.md +713 -0
  183. package/docs/archive/specialists-substrate-alignment.md +255 -0
  184. package/docs/archive/substrate-review.md +1288 -0
  185. package/docs/archive/test-writer-specialist.md +254 -0
  186. package/docs/archive/using-specialists-v3-improvements-2026-05-09.md +600 -0
  187. package/docs/archive/xtrm-specialists-analysis.md +314 -0
  188. package/docs/authoring.md +701 -0
  189. package/docs/background-jobs.md +203 -0
  190. package/docs/bare-specialists.md +83 -0
  191. package/docs/benchmarks/executor-benchmark-runner.md +66 -0
  192. package/docs/bootstrap.md +161 -0
  193. package/docs/cli-reference.md +1645 -0
  194. package/docs/deploying-alongside.md +155 -0
  195. package/docs/design/README.md +36 -0
  196. package/docs/design/darth-feedor-migration.md +290 -0
  197. package/docs/design/roadmap/README.md +32 -0
  198. package/docs/design/roadmap/chain-templates/README.md +146 -0
  199. package/docs/design/roadmap/chain-templates/code-quick.formula.json +27 -0
  200. package/docs/design/roadmap/chain-templates/code-standard.formula.json +126 -0
  201. package/docs/design/roadmap/chain-templates/code-with-advisors.formula.json +128 -0
  202. package/docs/design/roadmap/chain-templates/code-with-tests.formula.json +76 -0
  203. package/docs/design/roadmap/chain-templates/debug.formula.json +128 -0
  204. package/docs/design/roadmap/chain-templates/doc-sync.formula.json +28 -0
  205. package/docs/design/roadmap/chain-templates/memory-hygiene.formula.json +27 -0
  206. package/docs/design/roadmap/chain-templates/planning.formula.json +27 -0
  207. package/docs/design/roadmap/chain-templates/premortem.formula.json +26 -0
  208. package/docs/design/roadmap/chain-templates/release-prep.formula.json +36 -0
  209. package/docs/design/roadmap/chain-templates/research-only.formula.json +28 -0
  210. package/docs/design/roadmap/chain-templates/restitch.formula.json +125 -0
  211. package/docs/design/roadmap/chain-templates/security-deep.formula.json +161 -0
  212. package/docs/design/roadmap/chain-templates/test-only.formula.json +52 -0
  213. package/docs/design/roadmap/chain-templates/triage.formula.json +35 -0
  214. package/docs/design/roadmap/history/handoff-from-substrate-design.md +87 -0
  215. package/docs/design/roadmap/history/substrate-reconciliation.md +105 -0
  216. package/docs/design/roadmap/specialists-roadmap.md +1261 -0
  217. package/docs/design/sp-console-subscribe-via-materializer.md +231 -0
  218. package/docs/design/sp-console-tui-mock-v2.html +293 -0
  219. package/docs/design/sp-console-tui-mock.html +120 -0
  220. package/docs/design/sp-console-tui.md +340 -0
  221. package/docs/design/specialist-agentops-suite.md +323 -0
  222. package/docs/design/substrate/channels.md +14 -0
  223. package/docs/design/substrate/devops-platform-engineering-prd.md +446 -0
  224. package/docs/design/substrate/html-design-example.md +339 -0
  225. package/docs/design/xtrm-tiers-architecture.svg +132 -0
  226. package/docs/devops/dependency-verdict-materialization.md +46 -0
  227. package/docs/epic-readiness.md +75 -0
  228. package/docs/examples/mercury-atomic-summarizer.specialist.json +26 -0
  229. package/docs/examples/smoke-echo-text-expected-keys.specialist.json +25 -0
  230. package/docs/examples/smoke-echo.specialist.json +25 -0
  231. package/docs/features.md +1577 -0
  232. package/docs/hooks.md +81 -0
  233. package/docs/installation.md +142 -0
  234. package/docs/manifest.md +184 -0
  235. package/docs/mcp-servers.md +73 -0
  236. package/docs/mcp-tools.md +71 -0
  237. package/docs/nodes.md +231 -0
  238. package/docs/observability-metrics.md +152 -0
  239. package/docs/operator/sp-console-v2-walkthrough.md +410 -0
  240. package/docs/overrides-guide.md +306 -0
  241. package/docs/pi-rpc-boundary.md +118 -0
  242. package/docs/pi-session.md +195 -0
  243. package/docs/release.md +22 -0
  244. package/docs/skills.md +132 -0
  245. package/docs/specialists/handoff-schema.md +181 -0
  246. package/docs/specialists-catalog.md +99 -0
  247. package/docs/specialists-service-install.md +226 -0
  248. package/docs/specialists-service.md +363 -0
  249. package/docs/surface-ownership.md +138 -0
  250. package/docs/upgrade-notes/kan-90-global-user-config.md +114 -0
  251. package/docs/upgrade-notes/kan-91-expanded-overrides.md +261 -0
  252. package/docs/workflow.md +114 -0
  253. package/docs/worktree.md +71 -0
  254. package/docs/worktrees.md +309 -0
  255. package/package.json +7 -4
@@ -0,0 +1,120 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>sp console grounded mock</title>
7
+ <link rel="preconnect" href="https://fonts.googleapis.com">
8
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
9
+ <link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
10
+ <style>
11
+ :root{
12
+ --bg:#181818;--txt:#c8c8c8;--bright:#e4e4e4;--dim:#7d7d7d;--rail:#3a3a3a;--sel:#262626;
13
+ --running:#c39a5e;--done:#8caa6a;--reviewing:#9f88bf;--waiting:#8095a8;--idle:#4a4a4a;--blocked:#c4806f;
14
+ --mono:'JetBrains Mono',ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;--lh:1.2;
15
+ }
16
+ *{box-sizing:border-box;margin:0;padding:0}
17
+ html,body{height:100%}
18
+ body{height:100vh;background:var(--bg);color:var(--txt);font-family:var(--mono);font-size:12.5px;line-height:var(--lh);font-weight:400;letter-spacing:.15px;display:flex;flex-direction:column;overflow:hidden;outline:none}
19
+ .ctx,.stats,.keys,.filter{flex:0 0 auto;padding:0 10px;white-space:pre;overflow:hidden}
20
+ .ctx{color:var(--dim)}.ctx b{color:var(--bright);font-weight:500}
21
+ .main{flex:1 1 auto;min-height:0;overflow:auto;scrollbar-width:thin}.main::-webkit-scrollbar{width:6px}.main::-webkit-scrollbar-thumb{background:#2c2c2c;border-radius:3px}
22
+ .ln{display:flex;align-items:stretch;line-height:var(--lh);padding:0 10px;white-space:pre}.ln.sel{background:var(--sel)}
23
+ .rail{flex:0 0 2ch;border-left:1px solid var(--rail)}.rail.blank{border-left-color:transparent}.c{white-space:pre}.dim{color:var(--dim)}.bright{color:var(--bright)}
24
+ .id,.meta,.payload,.bead,.next{color:var(--dim)}.group{color:var(--bright)}.branch{color:var(--dim)}
25
+ .running{color:var(--running)}.done{color:var(--done)}.reviewing{color:var(--reviewing)}.waiting{color:var(--waiting)}.idle{color:var(--idle)}.blocked,.error{color:var(--blocked)}
26
+ .stats{color:var(--dim)}.stats .ok{color:var(--done)}.stats .warn{color:var(--running)}.stats .bad{color:var(--blocked)}
27
+ .keys{color:var(--dim)}.keys .k{color:var(--txt)}.filter{color:var(--txt)}.filter .p{color:var(--dim)}.hidden{display:none}
28
+ </style>
29
+ </head>
30
+ <body tabindex="0">
31
+ <div class="ctx" id="ctx"></div>
32
+ <div class="main" id="main"></div>
33
+ <div class="filter hidden" id="filter"></div>
34
+ <div class="stats" id="stats"></div>
35
+ <div class="keys" id="keys"></div>
36
+ <script>
37
+ const E=s=>String(s??'').replace(/[&<>]/g,c=>({'&':'&amp;','<':'&lt;','>':'&gt;'}[c]));
38
+ const padR=(s,n)=>{s=String(s??'');return s.length>=n?s.slice(0,n):s+' '.repeat(n-s.length)};
39
+ const padL=(s,n)=>{s=String(s??'');return s.length>=n?s.slice(0,n):' '.repeat(n-s.length)+s};
40
+ const trunc=(s,n)=>{s=String(s??'');return s.length>n?s.slice(0,Math.max(0,n-1))+'…':s};
41
+ const GLY={running:'●',waiting:'◐',starting:'◐',done:'○',error:'✕',cancelled:'○',dead:'✕'};
42
+ const CLS={running:'running',waiting:'waiting',starting:'waiting',done:'done',error:'error',cancelled:'idle',dead:'blocked'};
43
+ const REPOS=[{name:'specialists',path:'/home/dawid/dev/specialists'},{name:'mercury',path:'/home/dawid/projects/mercury'},{name:'gitboard',path:'/home/dawid/dev/gitboard'}];
44
+ const rows=[
45
+ {kind:'epic',d:0,id:'unitAI-ye5s9',label:'release distribution hardening',state:'blocked',summary:'prep 1/2 done · chains 2/3 pass'},
46
+ {kind:'label',d:1,label:'Prep'},
47
+ {kind:'job',d:2,id:'8f31aa',spec:'researcher',status:'done',ctx:18,elapsed:'4m12s 3t·8tc·42ktok',payload:'31.0kb',ptok:'8.4kt',bead:'unitAI-prep1',next:'result',title:'npm-pack validation research'},
48
+ {kind:'label',d:1,label:'Chains'},
49
+ {kind:'chain',d:2,id:'chain:0db4',label:'root: unitAI-9b2dn · pass'},
50
+ {kind:'branch',d:3,label:'fix/unitAI-9b2dn-pack-smoke'},
51
+ {kind:'job',d:4,id:'0db4c1',spec:'executor',status:'done',ctx:41,elapsed:'7m03s 5t·19tc·91ktok',payload:'44.2kb',ptok:'12.1kt',bead:'unitAI-9b2dn',next:'result',title:'add npm pack smoke'},
52
+ {kind:'job',d:4,id:'3a912e',spec:'reviewer',status:'waiting',ctx:63,elapsed:'1m28s 2t·4tc·28ktok',payload:'38.5kb',ptok:'10.8kt',bead:'unitAI-9b2dn',next:'resume',title:'review npm pack smoke'},
53
+ {kind:'chain',d:2,id:'chain:71ab',label:'root: unitAI-yq31q · running'},
54
+ {kind:'branch',d:3,label:'fix/unitAI-yq31q-fresh-install'},
55
+ {kind:'job',d:4,id:'71ab09',spec:'executor',status:'running',ctx:57,elapsed:'2m19s 2t·7tc·36ktok',payload:'40.0kb',ptok:'11.5kt',bead:'unitAI-yq31q',next:'feed',title:'fresh install smoke paths'},
56
+ {kind:'node',d:0,id:'node:research',label:'node-coordinator · running · 3 members'},
57
+ {kind:'job',d:1,id:'44ac01',spec:'researcher',status:'running',ctx:24,elapsed:'0m51s 1t·2tc·12ktok',payload:'22.3kb',ptok:'6.2kt',bead:'unitAI-eoqxp',next:'feed',title:'AgentOps telemetry patterns'},
58
+ {kind:'worktree',d:0,label:'docs/unitAI-i29fm-sp-console-tui-grounding · unitAI-i29fm'},
59
+ {kind:'job',d:1,id:'b710da',spec:'explorer',status:'done',ctx:35,elapsed:'3m10s 3t·5tc·21ktok',payload:'19.8kb',ptok:'5.4kt',bead:'unitAI-i29fm',next:'result',title:'map sp ps/feed runtime'},
60
+ ];
61
+ const feeds={
62
+ '71ab09':[
63
+ ['run_start','executor/gpt-5.3-codex','bead=unitAI-yq31q branch=fix/unitAI-yq31q-fresh-install chain=chain:71ab'],
64
+ ['payload_breakdown','executor/gpt-5.3-codex','payload: 40.0kb · 11.5kt across 7 components'],
65
+ ['tool','executor/gpt-5.3-codex','start bash bun run build'],
66
+ ['token_usage','executor/gpt-5.3-codex','input=18240 · output=2310 · total=20550'],
67
+ ['status_change','executor/gpt-5.3-codex','running → waiting? no · current_tool=bash'],
68
+ ],
69
+ '3a912e':[
70
+ ['run_start','reviewer/gpt-5.4-mini','bead=unitAI-9b2dn reused=0db4c1 chain_root_bead=unitAI-9b2dn'],
71
+ ['tool','reviewer/gpt-5.4-mini','start read docs/pack-smoke.md'],
72
+ ['status_change','reviewer/gpt-5.4-mini','waiting'],
73
+ ['WAIT','reviewer/gpt-5.4-mini','reviewer (3a912e) is waiting for input. Use: sp resume 3a912e "..."'],
74
+ ],
75
+ };
76
+ const results={
77
+ '0db4c1':[
78
+ ['section','startup context'],['job_id','0db4c1'],['specialist','executor'],['bead_id','unitAI-9b2dn'],['chain_id','chain:0db4'],
79
+ ['section','result'],['text','Implemented npm-pack smoke and verified package asset resolution from a packed install.'],
80
+ ['section','metrics'],['tokens','input=52000 · output=3900 · total=55900'],['cost_usd','$0.0841'],
81
+ ],
82
+ '3a912e':[
83
+ ['section','latest completed output'],['text','Reviewer reached a waiting state after checking docs/pack-smoke.md. Needs operator input before final verdict.'],
84
+ ['section','waiting'],['resume','sp resume 3a912e "..."'],
85
+ ],
86
+ '71ab09':[
87
+ ['section','running'],['text','No final result yet. Use feed for live progress; previous turn output will appear here when persisted.'],
88
+ ],
89
+ };
90
+ let S={repo:0,view:'ps',sel:0,filtering:false,filter:'',job:null,follow:false,scroll:0,history:'default'};
91
+ function visible(){const q=S.filter.toLowerCase();if(!q)return rows;return rows.filter(r=>r.kind!=='label'&&(r.id+' '+r.label+' '+r.spec+' '+r.title+' '+r.bead+' '+r.status).toLowerCase().includes(q));}
92
+ function rails(d){let h='';for(let i=0;i<d;i++)h+='<span class="rail"></span>';return h}
93
+ function rowHtml(r,selected){
94
+ let body='';
95
+ if(r.kind==='job'){
96
+ const cls=CLS[r.status], glyph=GLY[r.status];
97
+ const left=`<span class="${cls}">${glyph}</span> <span class="id">${padR(r.id,8)}</span> <span>${padR(r.spec,13)}</span> <span class="${cls}">${padR(r.status,9)}</span>`;
98
+ body=left+` <span class="meta">${padL(r.ctx+'%',4)}</span> <span class="meta">${padR(r.elapsed,20)}</span> <span class="payload">${padR(r.payload,8)} ${padR(r.ptok,7)}</span> <span class="bead">${padR(r.bead,14)}</span> <span class="next">${padR(r.next,7)}</span><span class="dim">${E(trunc(r.title,42))}</span>`;
99
+ } else if(r.kind==='epic') body=`<span class="group">◆ ${r.id} · ${r.label}</span> <span class="${CLS[r.state]}">${r.state}</span> <span class="dim">· ${r.summary}</span>`;
100
+ else if(r.kind==='node') body=`<span class="group">⬢ ${r.id}</span> <span class="dim">· ${r.label}</span>`;
101
+ else if(r.kind==='chain') body=`<span class="group">◇ ${r.id}</span> <span class="dim">· ${r.label}</span>`;
102
+ else if(r.kind==='branch'||r.kind==='worktree') body=`<span class="branch">${r.label}</span>`;
103
+ else body=`<span class="dim">${r.label}</span>`;
104
+ return `<div class="ln${selected?' sel':''}">${rails(r.d)}<span class="c">${body}</span></div>`;
105
+ }
106
+ function feedRows(){return feeds[S.job]||[['run_start','sp feed',`job ${S.job} has no mock feed rows`]]}
107
+ function feedHtml(f,i){return `<div class="ln${i===S.scroll?' sel':''}"><span class="c"><span class="dim">${padR(String(i+1),4)}</span> <span class="bright">${padR(f[0],18)}</span> <span class="dim">${padR(f[1],24)}</span> ${E(f[2])}</span></div>`}
108
+ function beadHtml(item){if(item[0]==='section')return `<div class="ln"><span class="c"><span class="dim">── ${E(item[1])} ──</span></span></div>`;if(item[0]==='text')return `<div class="ln"><span class="c">${E(item[1])}</span></div>`;return `<div class="ln"><span class="c"><span class="dim">${padR(item[0],12)}</span>${E(item[1])}</span></div>`}
109
+ function selectedJob(){return visible().filter(r=>r.kind==='job')[0]&&visible()[S.sel]?.kind==='job'?visible()[S.sel]:null}
110
+ function setCtx(){const repo=REPOS[S.repo];document.getElementById('ctx').innerHTML=`<b>${S.view}</b> · ${repo.name} · ${repo.path}${S.job?' · '+S.job:''}`}
111
+ function setStats(){document.getElementById('stats').innerHTML=`health <span class="ok">OK</span> rss=512MB cpu=3.1% · jobs 6 visible/42 total · running 2 waiting 1 · history ${S.history} · epics 1 nodes 1 worktrees 3 · ctx max <span class="warn">63%</span> · tokens 184k · orphans 0`}
112
+ function key(k,d){return `<span class="k">${k}</span> ${d} `}
113
+ function setKeys(){const el=document.getElementById('keys');if(S.view==='ps')el.innerHTML=key('↑↓','nav')+key('↵','feed')+key('r','result')+key('i','inspect')+key('h','history')+key('a','all')+key('/','filter')+key('⇥','repo')+key('q','quit');else if(S.view==='feed')el.innerHTML=key('↑↓','scroll')+key('f','follow')+key('⌫','back')+key('g/G','top/end')+key('q','quit');else el.innerHTML=key('↑↓','scroll')+key('⌫','back')+key('q','quit')}
114
+ function render(){setCtx();setStats();setKeys();const main=document.getElementById('main');if(S.view==='ps'){const vis=visible();S.sel=Math.max(0,Math.min(S.sel,vis.length-1));main.innerHTML=vis.map((r,i)=>rowHtml(r,i===S.sel)).join('')||'<div class="ln"><span class="c dim">no matches</span></div>'}else if(S.view==='feed'){main.innerHTML=feedRows().map(feedHtml).join('')}else if(S.view==='job'){const r=rows.find(x=>x.id===S.job);main.innerHTML=[['job',r?.id],['specialist',r?.spec],['status',r?.status],['bead',r?.bead],['worktree','fix/'+(r?.bead||'none')],['chain_id','from worktree_owner_job_id'],['elapsed',r?.elapsed],['context',r?.ctx+'%'],['next',r?.next]].map(beadHtml).join('')}else{main.innerHTML=(results[S.job]||[['section','result'],['text','No persisted result yet. Use feed for timeline replay.']]).map(beadHtml).join('')}const fl=document.getElementById('filter');if(S.filtering){fl.classList.remove('hidden');fl.innerHTML=`<span class="p">/</span>${E(S.filter)}_`}else fl.classList.add('hidden');const sel=main.querySelector('.sel');if(sel)sel.scrollIntoView({block:'nearest'})}
115
+ function move(d){if(S.view==='ps'){S.sel=Math.max(0,Math.min(visible().length-1,S.sel+d))}else{const max=(S.view==='feed'?feedRows().length:20)-1;S.scroll=Math.max(0,Math.min(max,S.scroll+d));document.getElementById('main').scrollBy(0,d*16)}}
116
+ window.addEventListener('keydown',e=>{if(S.filtering){if(e.key==='Escape'){S.filtering=false;S.filter=''}else if(e.key==='Enter'){S.filtering=false}else if(e.key==='Backspace'){S.filter=S.filter.slice(0,-1)}else if(e.key.length===1){S.filter+=e.key}else return;e.preventDefault();render();return}const r=visible()[S.sel];switch(e.key){case'ArrowDown':case'j':move(1);break;case'ArrowUp':case'k':move(-1);break;case'Enter':if(S.view==='ps'&&r?.kind==='job'){S.view='feed';S.job=r.id;S.scroll=0}break;case'r':if(S.view==='ps'&&r?.kind==='job'){S.view='result';S.job=r.id;S.scroll=0}break;case'i':if(S.view==='ps'&&r?.kind==='job'){S.view='job';S.job=r.id;S.scroll=0}break;case'h':if(S.view==='ps'){S.history=S.history==='default'?'history':S.history==='history'?'all':'default'}break;case'a':if(S.view==='ps'){S.history=S.history==='all'?'default':'all'}break;case'Escape':case'Backspace':case'ArrowLeft':if(S.view!=='ps'){S.view='ps';S.job=null}break;case'/':if(S.view==='ps')S.filtering=true;break;case'f':if(S.view==='feed')S.follow=!S.follow;break;case'Tab':S.repo=(S.repo+1)%REPOS.length;S.view='ps';S.sel=0;break;case'1':case'2':case'3':S.repo=Number(e.key)-1;S.view='ps';S.sel=0;break;case'g':S.sel=0;S.scroll=0;document.getElementById('main').scrollTop=0;break;case'G':S.sel=visible().length-1;document.getElementById('main').scrollTop=document.getElementById('main').scrollHeight;break;default:return}e.preventDefault();render()});
117
+ document.body.focus();window.addEventListener('click',()=>document.body.focus());render();
118
+ </script>
119
+ </body>
120
+ </html>
@@ -0,0 +1,340 @@
1
+ # `sp console` — grounded TUI design
2
+
3
+ > Design target for a future `sp console` command in this repo.
4
+ >
5
+ > This is **not** a substrate mock. Bind the UI to the runtime that exists today: `sp ps`, `sp feed`, `sp result`, `sp resume/steer/stop`, `sp epic`, `sp node`, and beads (`bd`). The companion HTML is only a visual mock for density, rail, palette, and key feel.
6
+
7
+ ## 0. Reality anchors
8
+
9
+ Read these before implementation and keep the design in sync with them:
10
+
11
+ | Surface | Source of truth | What `sp console` must mirror |
12
+ |---|---|---|
13
+ | Process dashboard | `src/cli/ps.ts` | visibility rules, grouping, status icons, columns, next-action hints |
14
+ | Event stream | `src/cli/feed.ts`, `src/specialist/timeline-events.ts`, `src/specialist/timeline-query.ts` | DB-backed timeline, cursor/follow behavior, event filtering |
15
+ | Job state | `src/specialist/supervisor.ts`, `src/specialist/status-load.ts` | `SupervisorStatus`, metrics, context health, worktree/chain/epic fields |
16
+ | Runtime DB | `src/specialist/observability-sqlite.ts`, `src/specialist/observability-db.ts` | `.specialists/db/observability.db` as normal runtime store |
17
+ | Beads | `src/specialist/beads.ts`, `bd list --json` / `bd show --json` (post-v1 browser) | v1 displays linked `bead_id`/title from job status; full bead browsing is post-v1 |
18
+ | Existing TUI stack | `src/cli/chat.ts`, `src/cli/attach-tui.ts`, `src/cli/chat/feed.ts`, `src/cli/chat/status.ts` | `@earendil-works/pi-tui` lifecycle and component patterns |
19
+
20
+ Non-negotiable corrections from older mockups:
21
+
22
+ - Use **TypeScript + Bun + `@earendil-works/pi-tui`**, not Ink.
23
+ - Do **not** invent substrate containers, steps, contracts, tethers, mailboxes, or waves.
24
+ - Current `sp` does have `epic_id`, derived epic readiness, node runs, worktree reuse chains, and bead-linked jobs. Render those real entities only.
25
+ - **V1 traceability includes terminal jobs**: history toggles, completed feed replay, and result inspection.
26
+ - `bd show` / bead browser navigation is **post-v1**. V1 shows linked bead id/title in job rows but does not open bead detail.
27
+ - The performance/status strip stays one line at the bottom, immediately above shortcuts.
28
+
29
+ ## 1. Product shape
30
+
31
+ `sp console` is a full-viewport, read-mostly operator TUI for one or more specialists repos. It is a navigable version of:
32
+
33
+ ```bash
34
+ sp ps --follow
35
+ sp feed <job-id> --follow
36
+ sp ps <job-id>
37
+ sp result <job-id>
38
+ ```
39
+
40
+ One view is visible at a time. No sidebar, no split panes.
41
+
42
+ Views:
43
+
44
+ 1. **ProcessView** — default dashboard, shaped by `sp ps`.
45
+ 2. **FeedView** — compact job timeline, shaped by `sp feed`.
46
+ 3. **JobView** — focused job inspect, shaped by `sp ps <id>`.
47
+ 4. **ResultView** — final/latest assistant output, shaped by `sp result <id>`.
48
+
49
+ ## 2. Runtime architecture
50
+
51
+ Use one seam between UI and runtime. Views never shell out directly and never open SQLite directly.
52
+
53
+ ```
54
+ App/pi-tui components
55
+ ↓ dispatch actions
56
+ Store/reducer
57
+ ↓ calls
58
+ RuntimeClient
59
+ ↓ uses existing repo modules / safe bd subprocess args
60
+ specialists runtime + bd
61
+ ```
62
+
63
+ ### 2.1 `RuntimeClient`
64
+
65
+ ```ts
66
+ interface RuntimeClient {
67
+ listRepos(): Promise<RepoRef[]>;
68
+
69
+ // ProcessView = sp ps parity.
70
+ listProcessSnapshot(repo: RepoId, opts: ProcessFilter): Promise<ProcessSnapshot>;
71
+ subscribeProcessSnapshot(repo: RepoId, cb: () => void): Unsubscribe;
72
+
73
+ // FeedView = sp feed parity.
74
+ readFeed(args: { repo: RepoId; jobId: string; fromSeq?: number; limit?: number }): Promise<FeedEvent[]>;
75
+ subscribeFeed(args: { repo: RepoId; jobId?: string; nodeId?: string }, cb: (event: FeedEvent) => void): Unsubscribe;
76
+
77
+ // JobView = sp ps <id> parity.
78
+ inspectJob(repo: RepoId, jobIdPrefix: string): Promise<JobInspect>;
79
+
80
+ // ResultView = sp result parity.
81
+ readResult(repo: RepoId, jobIdPrefix: string): Promise<JobResult>;
82
+
83
+ // Post-v1 bead browser; not required for traceability v1.
84
+ listBeads?(repo: RepoId, opts: BeadListFilter): Promise<BeadListSnapshot>;
85
+ showBead?(repo: RepoId, beadId: string): Promise<BeadDetail>;
86
+
87
+ // Bottom StatsLine.
88
+ readHealth(repo: RepoId): Promise<ProcessHealthSnapshot>;
89
+ }
90
+ ```
91
+
92
+ Implementation guidance:
93
+
94
+ - Prefer importing repo modules (`loadStatuses`, `collectProcessHealth`, `queryTimeline`, `createObservabilitySqliteClient`) over spawning `sp` and parsing text.
95
+ - `bd` access can shell out with `spawnSync`/`spawn` **argument arrays only**, matching `BeadsClient`; never interpolate shell strings.
96
+ - Keep the CLI outputs as parity references. If `sp ps` semantics change, update `RuntimeClient` and this doc together.
97
+
98
+ ### 2.2 Store
99
+
100
+ A single reducer owns navigation state and buffered feed rows.
101
+
102
+ ```ts
103
+ type View = 'ps' | 'feed' | 'job' | 'result';
104
+
105
+ interface State {
106
+ repo: RepoId;
107
+ view: View;
108
+ selectedRow: number;
109
+ filter: string;
110
+ filtering: boolean;
111
+ selectedJobId?: string;
112
+ feed: Record<string, FeedEvent[]>;
113
+ historyMode: 'default' | 'history' | 'all';
114
+ follow: boolean;
115
+ health?: ProcessHealthSnapshot;
116
+ }
117
+ ```
118
+
119
+ Components are pure renderers over state. Async subscriptions dispatch actions and call `tui.requestRender()`.
120
+
121
+ ## 3. Process model to render
122
+
123
+ Render the same hierarchy `sp ps` builds today:
124
+
125
+ 1. **System health** — source: `collectProcessHealth()`; in console this becomes the bottom StatsLine, not a top block.
126
+ 2. **Epic groups** — jobs with `epic_id`, grouped into prep jobs and chains; readiness comes from `loadEpicReadinessSummary()` and is derived, not hand-entered.
127
+ 3. **Node groups** — jobs with `node_id`, using node run names/statuses from the observability DB.
128
+ 4. **Worktree trees** — jobs sharing `worktree_owner_job_id`; reused jobs appear as children via `reused_from_job_id`.
129
+ 5. **Standalone jobs** — no node/epic/worktree grouping.
130
+
131
+ Job row columns must stay aligned with `sp ps` fields:
132
+
133
+ ```text
134
+ st id specialist status ctx elapsed+metrics payload bead next title
135
+ ```
136
+
137
+ Use these real fields from `SupervisorStatus`:
138
+
139
+ - identity: `id`, `specialist`, `bead_id`, `bead_title`, `node_id`
140
+ - lifecycle: `status`, `pid`, liveness/dead flag
141
+ - workspace: `worktree_path`, `branch`, `worktree_owner_job_id`, `reused_from_job_id`
142
+ - chain/epic: `chain_kind`, `chain_id`, `chain_root_job_id`, `chain_root_bead_id`, `epic_id`
143
+ - observability: `elapsed_s`, `context_pct`, `context_health`, `metrics`, `startup_payload_json`
144
+
145
+ Do not render a row as an "issue step" unless the runtime exposes that as a job row. The selectable unit is a **job**.
146
+
147
+ ## 4. Feed model to render
148
+
149
+ FeedView is a navigable `sp feed`:
150
+
151
+ - Source events from `observability.db`; file reads are fallback/legacy only.
152
+ - Preserve cursor semantics (`jobId:seq` / `--from`) and follow semantics.
153
+ - Human mode should use the same suppression principle as `sp feed`: hide high-noise turn/message rows by default, show actionable lifecycle/tool/error/status rows.
154
+ - JSON/raw mode can be a future toggle; default is compact human progress.
155
+
156
+ Important real event families:
157
+
158
+ ```text
159
+ run_start, status_change, meta, payload_breakdown, tool, text, thinking,
160
+ token_usage, finish_reason, turn_summary, compaction, retry, error,
161
+ extension_error, model_change, run_complete
162
+ ```
163
+
164
+ Waiting jobs should show the real next action:
165
+
166
+ ```text
167
+ WAIT reviewer/gpt-5.4-mini (49adda) is waiting for input. Use: sp resume 49adda "..."
168
+ ```
169
+
170
+ ## 5. V1 traceability
171
+
172
+ Traceability is part of v1 and is grounded in current CLI behavior. It is **not** a post-v1 nice-to-have.
173
+
174
+ ### 5.1 History visibility
175
+
176
+ ProcessView must expose the same visibility modes as `sp ps`:
177
+
178
+ - default: active jobs plus unresolved terminal problems
179
+ - history: active plus uncleaned terminal history (`--include-terminal`)
180
+ - all: full audit view (`--all`, including cleaned/dead/history)
181
+ - optional cleaned toggle: rows hidden by `sp clean --ps` (`--include-cleaned`)
182
+
183
+ Use `h` / `a` or an equivalent compact cycle:
184
+
185
+ ```text
186
+ active/default → history → all
187
+ ```
188
+
189
+ ### 5.2 Feed replay after completion
190
+
191
+ `sp feed <job>` is DB-backed in normal runtime and can replay events after a job is done. FeedView must therefore work for running, waiting, done, error, and cancelled jobs. Follow mode only follows live jobs; terminal jobs open as replay.
192
+
193
+ ### 5.3 Result inspection
194
+
195
+ ResultView is v1. It mirrors `sp result <job>` semantics:
196
+
197
+ - `done` → show final result plus metrics/footer
198
+ - `waiting` → show latest completed output when available plus the real resume footer
199
+ - `running` / `starting` → show latest completed output if available, otherwise guide to feed
200
+ - `error` / `cancelled` → show terminal reason and log/feed hints where available
201
+
202
+ ### 5.4 Next-action mapping
203
+
204
+ The row's `next` action should drive the default affordance:
205
+
206
+ | Job state | Primary action | Secondary action |
207
+ |---|---|---|
208
+ | `starting` / `running` | feed | result if previous output exists |
209
+ | `waiting` | result | resume hint / feed replay |
210
+ | `done` | result | feed replay |
211
+ | `error` | result/error detail | feed/log replay |
212
+ | `cancelled` / dead | log/feed replay | result if persisted |
213
+
214
+ ### 5.5 Beads in v1 vs post-v1
215
+
216
+ V1 keeps bead traceability in job rows (`bead_id`, bead title, chain root bead) but does **not** open `bd show`. Full bead navigation is post-v1:
217
+
218
+ - `bd list --json` / `bd query --json` for a navigable bead list
219
+ - `bd show <id> --json` for expanded detail
220
+ - dependency rows selectable from detail
221
+ - breadcrumb/back stack
222
+ - repo-aware `bd` execution in selected repo cwd
223
+
224
+ ## 6. `@earendil-works/pi-tui` implementation rules
225
+
226
+ Use the runtime's existing TUI stack:
227
+
228
+ ```ts
229
+ import { TUI, ProcessTerminal, Container, Input, matchesKey, Key, truncateToWidth, wrapTextWithAnsi } from '@earendil-works/pi-tui';
230
+ ```
231
+
232
+ Patterns to follow from existing code:
233
+
234
+ - Instantiate `const terminal = new ProcessTerminal(); const tui = new TUI(terminal);`.
235
+ - Mount children with `tui.addChild(root)`; do **not** assign `tui.root`.
236
+ - `Container` is vertical composition; add custom components with `addChild()`.
237
+ - Components implement `render(width): string[]`, optional `handleInput(data)`, and `invalidate()`.
238
+ - Every rendered line must be `<= width`; use `truncateToWidth()` and `wrapTextWithAnsi()`.
239
+ - After state changes, call `tui.requestRender()`.
240
+ - Use `matchesKey(data, Key.up)` / `Key.down` / `Key.enter` / `Key.shift('enter')` patterns instead of raw escape matching where possible.
241
+ - Cache rendered rows by width and invalidate on data/theme changes.
242
+
243
+ Do not use Ink concepts like `<Static>`. For append-only feed performance, implement the same idea with a cached line buffer like `ChatFeed`: append new wrapped rows, trim to a max, and request render.
244
+
245
+ ## 7. Layout
246
+
247
+ ```text
248
+ ps · specialists · /home/dawid/dev/specialists
249
+ <main view fills available rows>
250
+ health OK rss=512MB cpu=3.1% · jobs 6 visible/42 total · running 2 waiting 1 · history default · ctx max 61% · tokens 184k
251
+ ↑↓ nav ↵ feed r result i inspect h history a all / filter tab repo q quit
252
+ ```
253
+
254
+ Rules:
255
+
256
+ - One top context line: view, repo name, repo path.
257
+ - Main area fills the viewport.
258
+ - One bottom StatsLine. It must use metrics the runtime already computes: process health, visible/total jobs, running/waiting counts, max context%, token/cost totals when available, node/worktree/epic counts.
259
+ - One bottom KeyBar, contextual to the current view.
260
+ - No empty rows.
261
+
262
+ ## 8. Style contract
263
+
264
+ This style is intentionally terminal-native.
265
+
266
+ - No panels, boxes, bordered cards, sidebars, or decorative separators.
267
+ - Monospace rows with fixed-width padded columns.
268
+ - Continuous vertical rail for nesting. The current `sp ps` text uses `├─/└─`; console may use a subtler `│` rail, but it must represent the same grouping.
269
+ - One desaturated status color; all metadata stays gray.
270
+ - Selection is a muted background bar, not saturated color.
271
+ - KeyBar is plain text; key glyph brighter than descriptions.
272
+
273
+ Palette single source (`theme.ts`):
274
+
275
+ ```ts
276
+ export const colors = {
277
+ bg: '#181818', bright: '#e4e4e4', txt: '#c8c8c8', dim: '#7d7d7d',
278
+ rail: '#3a3a3a', selected: '#262626',
279
+ running: '#c39a5e', done: '#8caa6a', reviewing: '#9f88bf',
280
+ waiting: '#8095a8', idle: '#4a4a4a', blocked: '#c4806f', error: '#c4806f',
281
+ };
282
+ ```
283
+
284
+ Status glyphs should map from actual `SupervisorStatus.status`:
285
+
286
+ ```text
287
+ running ● waiting ◐ starting ◐ done ○ error ✕ cancelled ○ dead ✕
288
+ ```
289
+
290
+ ## 9. Keybindings
291
+
292
+ | Key | ProcessView | FeedView | JobView | ResultView |
293
+ |---|---|---|---|---|
294
+ | `↑↓` / `j k` | move selection | scroll | scroll | scroll |
295
+ | `Enter` | open feed replay/follow for selected job | - | - | - |
296
+ | `r` | open result for selected job | - | - | - |
297
+ | `i` | inspect selected job (`sp ps <id>` parity) | - | - | - |
298
+ | `h` | cycle default/history | - | - | - |
299
+ | `a` | toggle all audit rows | - | - | - |
300
+ | `Esc` / `←` / `Backspace` | - | back to ps | back to ps | back to ps |
301
+ | `f` | toggle dashboard follow | toggle feed follow for live jobs | - | - |
302
+ | `/` | filter visible jobs | - | - | - |
303
+ | `g` / `G` | top/end | top/end | top/end | top/end |
304
+ | `Tab` / `1-9` | switch repo | switch repo → ps | switch repo → ps | switch repo → ps |
305
+ | `q` | quit | quit | quit | quit |
306
+
307
+ ## 10. Module sketch
308
+
309
+ ```text
310
+ src/cli/console.ts # command entry; creates TUI and RuntimeClient
311
+ src/cli/console/App.ts # root component/router
312
+ src/cli/console/theme.ts # colors, glyphs, widths, ANSI helpers
313
+ src/cli/console/store.ts # reducer and actions
314
+ src/cli/console/client.ts # RuntimeClient interface
315
+ src/cli/console/local.ts # implementation via existing runtime modules + bd
316
+ src/cli/console/views/
317
+ ProcessView.ts
318
+ FeedView.ts
319
+ JobView.ts
320
+ ResultView.ts
321
+ # post-v1: BeadsView.ts / BeadDetailView.ts
322
+ src/cli/console/components/
323
+ Row.ts
324
+ StatsLine.ts
325
+ KeyBar.ts
326
+ ```
327
+
328
+ ## 11. Definition of done
329
+
330
+ - [ ] `sp console` uses `@earendil-works/pi-tui`, not Ink.
331
+ - [ ] ProcessView matches `sp ps` grouping, visibility rules, columns, and next actions.
332
+ - [ ] FeedView reads the DB-backed timeline and matches `sp feed` follow/cursor behavior.
333
+ - [ ] JobView matches `sp ps <id>` fields.
334
+ - [ ] ResultView mirrors `sp result` for done/waiting/running/error/cancelled jobs.
335
+ - [ ] V1 history modes cover default, terminal history, and all audit rows.
336
+ - [ ] `bd show` / full bead browser is explicitly post-v1, not required for traceability v1.
337
+ - [ ] StatsLine is one bottom line and contains only real runtime metrics.
338
+ - [ ] No substrate-only concepts appear in labels or mock data.
339
+ - [ ] All rows are width-safe (`truncateToWidth` / `wrapTextWithAnsi`).
340
+ - [ ] Palette, glyphs, and column widths live in one theme module.