@entelligentsia/forgecli 1.0.14 → 1.0.21

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 (363) hide show
  1. package/CHANGELOG.md +185 -0
  2. package/README.md +7 -1
  3. package/dist/CHANGELOG-forge-plugin.md +61 -0
  4. package/dist/bin/config.js +4 -4
  5. package/dist/bin/config.js.map +1 -1
  6. package/dist/bin/update-cli.d.ts +1 -1
  7. package/dist/bin/update-cli.js +1 -1
  8. package/dist/bin/update-cli.js.map +1 -1
  9. package/dist/extensions/forgecli/ask-user-tool.js +1 -1
  10. package/dist/extensions/forgecli/ask-user-tool.js.map +1 -1
  11. package/dist/extensions/forgecli/commands/add-pipeline.d.ts +19 -0
  12. package/dist/extensions/forgecli/commands/add-pipeline.js +143 -0
  13. package/dist/extensions/forgecli/commands/add-pipeline.js.map +1 -0
  14. package/dist/extensions/forgecli/commands/add-task.d.ts +20 -0
  15. package/dist/extensions/forgecli/commands/add-task.js +154 -0
  16. package/dist/extensions/forgecli/commands/add-task.js.map +1 -0
  17. package/dist/extensions/forgecli/commands/approve.d.ts +22 -0
  18. package/dist/extensions/forgecli/commands/approve.js +152 -0
  19. package/dist/extensions/forgecli/commands/approve.js.map +1 -0
  20. package/dist/extensions/forgecli/commands/collate.d.ts +22 -0
  21. package/dist/extensions/forgecli/commands/collate.js +134 -0
  22. package/dist/extensions/forgecli/commands/collate.js.map +1 -0
  23. package/dist/extensions/forgecli/commands/commit.d.ts +22 -0
  24. package/dist/extensions/forgecli/commands/commit.js +152 -0
  25. package/dist/extensions/forgecli/commands/commit.js.map +1 -0
  26. package/dist/extensions/forgecli/commands/config-command.d.ts +8 -0
  27. package/dist/extensions/forgecli/commands/config-command.js +67 -0
  28. package/dist/extensions/forgecli/commands/config-command.js.map +1 -0
  29. package/dist/extensions/forgecli/commands/enhance.d.ts +45 -0
  30. package/dist/extensions/forgecli/commands/enhance.js +219 -0
  31. package/dist/extensions/forgecli/commands/enhance.js.map +1 -0
  32. package/dist/extensions/forgecli/commands/implement.d.ts +22 -0
  33. package/dist/extensions/forgecli/commands/implement.js +170 -0
  34. package/dist/extensions/forgecli/commands/implement.js.map +1 -0
  35. package/dist/extensions/forgecli/commands/plan.d.ts +22 -0
  36. package/dist/extensions/forgecli/commands/plan.js +167 -0
  37. package/dist/extensions/forgecli/commands/plan.js.map +1 -0
  38. package/dist/extensions/forgecli/commands/quiz-agent.d.ts +17 -0
  39. package/dist/extensions/forgecli/commands/quiz-agent.js +98 -0
  40. package/dist/extensions/forgecli/commands/quiz-agent.js.map +1 -0
  41. package/dist/extensions/forgecli/commands/read-command.d.ts +2 -0
  42. package/dist/extensions/forgecli/commands/read-command.js +100 -0
  43. package/dist/extensions/forgecli/commands/read-command.js.map +1 -0
  44. package/dist/extensions/forgecli/commands/regenerate.d.ts +40 -0
  45. package/dist/extensions/forgecli/commands/regenerate.js +426 -0
  46. package/dist/extensions/forgecli/commands/regenerate.js.map +1 -0
  47. package/dist/extensions/forgecli/commands/remove-command.d.ts +17 -0
  48. package/dist/extensions/forgecli/commands/remove-command.js +124 -0
  49. package/dist/extensions/forgecli/commands/remove-command.js.map +1 -0
  50. package/dist/extensions/forgecli/commands/report-bug.d.ts +25 -0
  51. package/dist/extensions/forgecli/commands/report-bug.js +159 -0
  52. package/dist/extensions/forgecli/commands/report-bug.js.map +1 -0
  53. package/dist/extensions/forgecli/commands/retrospective.d.ts +20 -0
  54. package/dist/extensions/forgecli/commands/retrospective.js +126 -0
  55. package/dist/extensions/forgecli/commands/retrospective.js.map +1 -0
  56. package/dist/extensions/forgecli/commands/review-code.d.ts +35 -0
  57. package/dist/extensions/forgecli/commands/review-code.js +196 -0
  58. package/dist/extensions/forgecli/commands/review-code.js.map +1 -0
  59. package/dist/extensions/forgecli/commands/review-plan.d.ts +35 -0
  60. package/dist/extensions/forgecli/commands/review-plan.js +200 -0
  61. package/dist/extensions/forgecli/commands/review-plan.js.map +1 -0
  62. package/dist/extensions/forgecli/commands/sprint-intake.d.ts +10 -0
  63. package/dist/extensions/forgecli/commands/sprint-intake.js +91 -0
  64. package/dist/extensions/forgecli/commands/sprint-intake.js.map +1 -0
  65. package/dist/extensions/forgecli/commands/sprint-plan.d.ts +14 -0
  66. package/dist/extensions/forgecli/commands/sprint-plan.js +122 -0
  67. package/dist/extensions/forgecli/commands/sprint-plan.js.map +1 -0
  68. package/dist/extensions/forgecli/commands/status-command.d.ts +19 -0
  69. package/dist/extensions/forgecli/commands/status-command.js +140 -0
  70. package/dist/extensions/forgecli/commands/status-command.js.map +1 -0
  71. package/dist/extensions/forgecli/commands/store-query.d.ts +22 -0
  72. package/dist/extensions/forgecli/commands/store-query.js +107 -0
  73. package/dist/extensions/forgecli/commands/store-query.js.map +1 -0
  74. package/dist/extensions/forgecli/commands/store-repair.d.ts +17 -0
  75. package/dist/extensions/forgecli/commands/store-repair.js +123 -0
  76. package/dist/extensions/forgecli/commands/store-repair.js.map +1 -0
  77. package/dist/extensions/forgecli/commands/test-orchestrate.d.ts +2 -0
  78. package/dist/extensions/forgecli/commands/test-orchestrate.js +182 -0
  79. package/dist/extensions/forgecli/commands/test-orchestrate.js.map +1 -0
  80. package/dist/extensions/forgecli/commands/transcripts-command.d.ts +87 -0
  81. package/dist/extensions/forgecli/commands/transcripts-command.js +418 -0
  82. package/dist/extensions/forgecli/commands/transcripts-command.js.map +1 -0
  83. package/dist/extensions/forgecli/commands/validate.d.ts +22 -0
  84. package/dist/extensions/forgecli/commands/validate.js +152 -0
  85. package/dist/extensions/forgecli/commands/validate.js.map +1 -0
  86. package/dist/extensions/forgecli/config/config-layer.d.ts +53 -0
  87. package/dist/extensions/forgecli/config/config-layer.js +72 -0
  88. package/dist/extensions/forgecli/config/config-layer.js.map +1 -0
  89. package/dist/extensions/forgecli/config/config-writer.d.ts +16 -0
  90. package/dist/extensions/forgecli/config/config-writer.js +69 -0
  91. package/dist/extensions/forgecli/config/config-writer.js.map +1 -0
  92. package/dist/extensions/forgecli/config/model-registry.d.ts +61 -0
  93. package/dist/extensions/forgecli/config/model-registry.js +127 -0
  94. package/dist/extensions/forgecli/config/model-registry.js.map +1 -0
  95. package/dist/extensions/forgecli/config/model-resolver.d.ts +32 -0
  96. package/dist/extensions/forgecli/config/model-resolver.js +65 -0
  97. package/dist/extensions/forgecli/config/model-resolver.js.map +1 -0
  98. package/dist/extensions/forgecli/config/model-validator.d.ts +29 -0
  99. package/dist/extensions/forgecli/config/model-validator.js +107 -0
  100. package/dist/extensions/forgecli/config/model-validator.js.map +1 -0
  101. package/dist/extensions/forgecli/config-layer.d.ts +0 -16
  102. package/dist/extensions/forgecli/config-layer.js +0 -5
  103. package/dist/extensions/forgecli/config-layer.js.map +1 -1
  104. package/dist/extensions/forgecli/config-tui/component.js +1 -1
  105. package/dist/extensions/forgecli/config-tui/component.js.map +1 -1
  106. package/dist/extensions/forgecli/config-tui/handler.js +1 -1
  107. package/dist/extensions/forgecli/config-tui/handler.js.map +1 -1
  108. package/dist/extensions/forgecli/config-tui/screens/override-editor.js +1 -1
  109. package/dist/extensions/forgecli/config-tui/screens/override-editor.js.map +1 -1
  110. package/dist/extensions/forgecli/config-tui/screens/overrides-list-phases.js +1 -1
  111. package/dist/extensions/forgecli/config-tui/screens/overrides-list-phases.js.map +1 -1
  112. package/dist/extensions/forgecli/config-tui/screens/show-resolved.js +1 -1
  113. package/dist/extensions/forgecli/config-tui/screens/show-resolved.js.map +1 -1
  114. package/dist/extensions/forgecli/config-tui/state/buffer.d.ts +2 -2
  115. package/dist/extensions/forgecli/config-tui/state/model.d.ts +1 -1
  116. package/dist/extensions/forgecli/config-tui/state/reducer.js.map +1 -1
  117. package/dist/extensions/forgecli/config-tui/state/selectors.d.ts +2 -2
  118. package/dist/extensions/forgecli/config-tui/state/selectors.js +1 -1
  119. package/dist/extensions/forgecli/config-tui/state/selectors.js.map +1 -1
  120. package/dist/extensions/forgecli/context-governor-compaction.d.ts +94 -0
  121. package/dist/extensions/forgecli/context-governor-compaction.js +327 -0
  122. package/dist/extensions/forgecli/context-governor-compaction.js.map +1 -0
  123. package/dist/extensions/forgecli/context-governor.d.ts +169 -0
  124. package/dist/extensions/forgecli/context-governor.js +592 -0
  125. package/dist/extensions/forgecli/context-governor.js.map +1 -0
  126. package/dist/extensions/forgecli/dashboard/component.d.ts +17 -5
  127. package/dist/extensions/forgecli/dashboard/component.js +160 -115
  128. package/dist/extensions/forgecli/dashboard/component.js.map +1 -1
  129. package/dist/extensions/forgecli/dashboard/register.js +7 -21
  130. package/dist/extensions/forgecli/dashboard/register.js.map +1 -1
  131. package/dist/extensions/forgecli/dashboard/theme.d.ts +27 -0
  132. package/dist/extensions/forgecli/dashboard/theme.js +91 -0
  133. package/dist/extensions/forgecli/dashboard/theme.js.map +1 -0
  134. package/dist/extensions/forgecli/fix-bug.js +59 -5
  135. package/dist/extensions/forgecli/fix-bug.js.map +1 -1
  136. package/dist/extensions/forgecli/forge-artifact-tool.js +3 -2
  137. package/dist/extensions/forgecli/forge-artifact-tool.js.map +1 -1
  138. package/dist/extensions/forgecli/forge-cli-schema.json +0 -4
  139. package/dist/extensions/forgecli/forge-commands.js +1 -1
  140. package/dist/extensions/forgecli/forge-commands.js.map +1 -1
  141. package/dist/extensions/forgecli/forge-init/forge-init.d.ts +26 -0
  142. package/dist/extensions/forgecli/forge-init/forge-init.js +514 -0
  143. package/dist/extensions/forgecli/forge-init/forge-init.js.map +1 -0
  144. package/dist/extensions/forgecli/forge-init/init-context.d.ts +99 -0
  145. package/dist/extensions/forgecli/forge-init/init-context.js +178 -0
  146. package/dist/extensions/forgecli/forge-init/init-context.js.map +1 -0
  147. package/dist/extensions/forgecli/forge-init/init-progress.d.ts +39 -0
  148. package/dist/extensions/forgecli/forge-init/init-progress.js +117 -0
  149. package/dist/extensions/forgecli/forge-init/init-progress.js.map +1 -0
  150. package/dist/extensions/forgecli/forge-init/phase4-register.js +1 -1
  151. package/dist/extensions/forgecli/forge-init/phase4-register.js.map +1 -1
  152. package/dist/extensions/forgecli/forge-init/run-phases.js +2 -2
  153. package/dist/extensions/forgecli/forge-init/run-phases.js.map +1 -1
  154. package/dist/extensions/forgecli/forge-subagent.d.ts +42 -1
  155. package/dist/extensions/forgecli/forge-subagent.js +59 -18
  156. package/dist/extensions/forgecli/forge-subagent.js.map +1 -1
  157. package/dist/extensions/forgecli/forge-tools.d.ts +0 -25
  158. package/dist/extensions/forgecli/forge-tools.js +8 -37
  159. package/dist/extensions/forgecli/forge-tools.js.map +1 -1
  160. package/dist/extensions/forgecli/governor-config.d.ts +19 -0
  161. package/dist/extensions/forgecli/governor-config.js +58 -0
  162. package/dist/extensions/forgecli/governor-config.js.map +1 -0
  163. package/dist/extensions/forgecli/health-check.js +1 -1
  164. package/dist/extensions/forgecli/health-check.js.map +1 -1
  165. package/dist/extensions/forgecli/hook-dispatcher.d.ts +3 -1
  166. package/dist/extensions/forgecli/hook-dispatcher.js +39 -5
  167. package/dist/extensions/forgecli/hook-dispatcher.js.map +1 -1
  168. package/dist/extensions/forgecli/hooks/post-init-hook.js +11 -6
  169. package/dist/extensions/forgecli/hooks/post-init-hook.js.map +1 -1
  170. package/dist/extensions/forgecli/hooks/post-sprint-hook.js +11 -6
  171. package/dist/extensions/forgecli/hooks/post-sprint-hook.js.map +1 -1
  172. package/dist/extensions/forgecli/hooks/write-guard.js +1 -1
  173. package/dist/extensions/forgecli/hooks/write-guard.js.map +1 -1
  174. package/dist/extensions/forgecli/index.js +70 -36
  175. package/dist/extensions/forgecli/index.js.map +1 -1
  176. package/dist/extensions/forgecli/kickoff.d.ts +9 -0
  177. package/dist/extensions/forgecli/kickoff.js +15 -0
  178. package/dist/extensions/forgecli/kickoff.js.map +1 -1
  179. package/dist/extensions/forgecli/lib/forge-config.d.ts +1 -1
  180. package/dist/extensions/forgecli/lib/forge-config.js +1 -1
  181. package/dist/extensions/forgecli/lib/forge-config.js.map +1 -1
  182. package/dist/extensions/forgecli/lib/forge-root.d.ts +10 -0
  183. package/dist/extensions/forgecli/lib/forge-root.js +62 -0
  184. package/dist/extensions/forgecli/lib/forge-root.js.map +1 -0
  185. package/dist/extensions/forgecli/lib/halt-advisor.d.ts +19 -14
  186. package/dist/extensions/forgecli/lib/halt-advisor.js +36 -13
  187. package/dist/extensions/forgecli/lib/halt-advisor.js.map +1 -1
  188. package/dist/extensions/forgecli/lib/run-cjs.d.ts +26 -0
  189. package/dist/extensions/forgecli/lib/run-cjs.js +42 -0
  190. package/dist/extensions/forgecli/lib/run-cjs.js.map +1 -0
  191. package/dist/extensions/forgecli/orchestrator-status-bar.d.ts +3 -2
  192. package/dist/extensions/forgecli/orchestrator-status-bar.js +90 -60
  193. package/dist/extensions/forgecli/orchestrator-status-bar.js.map +1 -1
  194. package/dist/extensions/forgecli/orchestrator-tree.d.ts +4 -0
  195. package/dist/extensions/forgecli/orchestrator-tree.js +21 -3
  196. package/dist/extensions/forgecli/orchestrator-tree.js.map +1 -1
  197. package/dist/extensions/forgecli/orchestrators/calibrate.d.ts +64 -0
  198. package/dist/extensions/forgecli/orchestrators/calibrate.js +481 -0
  199. package/dist/extensions/forgecli/orchestrators/calibrate.js.map +1 -0
  200. package/dist/extensions/forgecli/orchestrators/fix-bug.d.ts +93 -0
  201. package/dist/extensions/forgecli/orchestrators/fix-bug.js +1705 -0
  202. package/dist/extensions/forgecli/orchestrators/fix-bug.js.map +1 -0
  203. package/dist/extensions/forgecli/orchestrators/halt-advisor.d.ts +59 -0
  204. package/dist/extensions/forgecli/orchestrators/halt-advisor.js +113 -0
  205. package/dist/extensions/forgecli/orchestrators/halt-advisor.js.map +1 -0
  206. package/dist/extensions/forgecli/orchestrators/materialize.d.ts +16 -0
  207. package/dist/extensions/forgecli/orchestrators/materialize.js +195 -0
  208. package/dist/extensions/forgecli/orchestrators/materialize.js.map +1 -0
  209. package/dist/extensions/forgecli/orchestrators/migrate.d.ts +22 -0
  210. package/dist/extensions/forgecli/orchestrators/migrate.js +260 -0
  211. package/dist/extensions/forgecli/orchestrators/migrate.js.map +1 -0
  212. package/dist/extensions/forgecli/orchestrators/orchestrator-preflight.d.ts +46 -0
  213. package/dist/extensions/forgecli/orchestrators/orchestrator-preflight.js +64 -0
  214. package/dist/extensions/forgecli/orchestrators/orchestrator-preflight.js.map +1 -0
  215. package/dist/extensions/forgecli/orchestrators/run-sprint.d.ts +27 -0
  216. package/dist/extensions/forgecli/orchestrators/run-sprint.js +734 -0
  217. package/dist/extensions/forgecli/orchestrators/run-sprint.js.map +1 -0
  218. package/dist/extensions/forgecli/orchestrators/run-task.d.ts +215 -0
  219. package/dist/extensions/forgecli/orchestrators/run-task.js +1491 -0
  220. package/dist/extensions/forgecli/orchestrators/run-task.js.map +1 -0
  221. package/dist/extensions/forgecli/paths/paths.d.ts +8 -0
  222. package/dist/extensions/forgecli/paths/paths.js +17 -0
  223. package/dist/extensions/forgecli/paths/paths.js.map +1 -1
  224. package/dist/extensions/forgecli/phase-vocab.d.ts +31 -0
  225. package/dist/extensions/forgecli/phase-vocab.js +82 -0
  226. package/dist/extensions/forgecli/phase-vocab.js.map +1 -0
  227. package/dist/extensions/forgecli/run-sprint.d.ts +3 -1
  228. package/dist/extensions/forgecli/run-sprint.js +1 -0
  229. package/dist/extensions/forgecli/run-sprint.js.map +1 -1
  230. package/dist/extensions/forgecli/run-task.d.ts +34 -1
  231. package/dist/extensions/forgecli/run-task.js +144 -6
  232. package/dist/extensions/forgecli/run-task.js.map +1 -1
  233. package/dist/extensions/forgecli/session-registry.d.ts +2 -2
  234. package/dist/extensions/forgecli/session-registry.js +6 -2
  235. package/dist/extensions/forgecli/session-registry.js.map +1 -1
  236. package/dist/extensions/forgecli/skill-curation/friction-emit.d.ts +99 -0
  237. package/dist/extensions/forgecli/skill-curation/friction-emit.js +245 -0
  238. package/dist/extensions/forgecli/skill-curation/friction-emit.js.map +1 -0
  239. package/dist/extensions/forgecli/skill-curation/skill-curation-flag.d.ts +21 -0
  240. package/dist/extensions/forgecli/skill-curation/skill-curation-flag.js +71 -0
  241. package/dist/extensions/forgecli/skill-curation/skill-curation-flag.js.map +1 -0
  242. package/dist/extensions/forgecli/skill-curation/skill-curator-subagent.d.ts +102 -0
  243. package/dist/extensions/forgecli/skill-curation/skill-curator-subagent.js +339 -0
  244. package/dist/extensions/forgecli/skill-curation/skill-curator-subagent.js.map +1 -0
  245. package/dist/extensions/forgecli/skill-curation/skill-retriever.d.ts +84 -0
  246. package/dist/extensions/forgecli/skill-curation/skill-retriever.js +246 -0
  247. package/dist/extensions/forgecli/skill-curation/skill-retriever.js.map +1 -0
  248. package/dist/extensions/forgecli/skill-curation/skill-usage-tracker.d.ts +91 -0
  249. package/dist/extensions/forgecli/skill-curation/skill-usage-tracker.js +224 -0
  250. package/dist/extensions/forgecli/skill-curation/skill-usage-tracker.js.map +1 -0
  251. package/dist/extensions/forgecli/store/store-error-remediation.d.ts +65 -0
  252. package/dist/extensions/forgecli/store/store-error-remediation.js +307 -0
  253. package/dist/extensions/forgecli/store/store-error-remediation.js.map +1 -0
  254. package/dist/extensions/forgecli/store/store-resolver.d.ts +56 -0
  255. package/dist/extensions/forgecli/store/store-resolver.js +263 -0
  256. package/dist/extensions/forgecli/store/store-resolver.js.map +1 -0
  257. package/dist/extensions/forgecli/store/store-validator.d.ts +16 -0
  258. package/dist/extensions/forgecli/store/store-validator.js +32 -0
  259. package/dist/extensions/forgecli/store/store-validator.js.map +1 -0
  260. package/dist/extensions/forgecli/store/transition-guard.d.ts +20 -0
  261. package/dist/extensions/forgecli/store/transition-guard.js +89 -0
  262. package/dist/extensions/forgecli/store/transition-guard.js.map +1 -0
  263. package/dist/extensions/forgecli/subagent/orchestrator-transcript.js +5 -0
  264. package/dist/extensions/forgecli/subagent/orchestrator-transcript.js.map +1 -1
  265. package/dist/extensions/forgecli/thread-switcher.d.ts +4 -1
  266. package/dist/extensions/forgecli/thread-switcher.js +36 -21
  267. package/dist/extensions/forgecli/thread-switcher.js.map +1 -1
  268. package/dist/extensions/forgecli/transcript-archive-types.d.ts +171 -0
  269. package/dist/extensions/forgecli/transcript-archive-types.js +130 -0
  270. package/dist/extensions/forgecli/transcript-archive-types.js.map +1 -0
  271. package/dist/extensions/forgecli/transcript-archive.d.ts +127 -0
  272. package/dist/extensions/forgecli/transcript-archive.js +656 -0
  273. package/dist/extensions/forgecli/transcript-archive.js.map +1 -0
  274. package/dist/extensions/forgecli/transcript-replay.d.ts +28 -0
  275. package/dist/extensions/forgecli/transcript-replay.js +153 -0
  276. package/dist/extensions/forgecli/transcript-replay.js.map +1 -0
  277. package/dist/extensions/forgecli/transcripts-tui/component.d.ts +36 -0
  278. package/dist/extensions/forgecli/transcripts-tui/component.js +112 -0
  279. package/dist/extensions/forgecli/transcripts-tui/component.js.map +1 -0
  280. package/dist/extensions/forgecli/transcripts-tui/index.d.ts +4 -0
  281. package/dist/extensions/forgecli/transcripts-tui/index.js +5 -0
  282. package/dist/extensions/forgecli/transcripts-tui/index.js.map +1 -0
  283. package/dist/extensions/forgecli/transcripts-tui/screens/browse.d.ts +21 -0
  284. package/dist/extensions/forgecli/transcripts-tui/screens/browse.js +172 -0
  285. package/dist/extensions/forgecli/transcripts-tui/screens/browse.js.map +1 -0
  286. package/dist/extensions/forgecli/transcripts-tui/screens/types.d.ts +22 -0
  287. package/dist/extensions/forgecli/transcripts-tui/screens/types.js +4 -0
  288. package/dist/extensions/forgecli/transcripts-tui/screens/types.js.map +1 -0
  289. package/dist/extensions/forgecli/transcripts-tui/state/index.d.ts +4 -0
  290. package/dist/extensions/forgecli/transcripts-tui/state/index.js +5 -0
  291. package/dist/extensions/forgecli/transcripts-tui/state/index.js.map +1 -0
  292. package/dist/extensions/forgecli/transcripts-tui/state/init.d.ts +8 -0
  293. package/dist/extensions/forgecli/transcripts-tui/state/init.js +18 -0
  294. package/dist/extensions/forgecli/transcripts-tui/state/init.js.map +1 -0
  295. package/dist/extensions/forgecli/transcripts-tui/state/model.d.ts +56 -0
  296. package/dist/extensions/forgecli/transcripts-tui/state/model.js +6 -0
  297. package/dist/extensions/forgecli/transcripts-tui/state/model.js.map +1 -0
  298. package/dist/extensions/forgecli/transcripts-tui/state/reducer.d.ts +2 -0
  299. package/dist/extensions/forgecli/transcripts-tui/state/reducer.js +51 -0
  300. package/dist/extensions/forgecli/transcripts-tui/state/reducer.js.map +1 -0
  301. package/dist/extensions/forgecli/transcripts-tui/state/selectors.d.ts +10 -0
  302. package/dist/extensions/forgecli/transcripts-tui/state/selectors.js +62 -0
  303. package/dist/extensions/forgecli/transcripts-tui/state/selectors.js.map +1 -0
  304. package/dist/extensions/forgecli/transcripts-tui/theme.d.ts +20 -0
  305. package/dist/extensions/forgecli/transcripts-tui/theme.js +47 -0
  306. package/dist/extensions/forgecli/transcripts-tui/theme.js.map +1 -0
  307. package/dist/extensions/forgecli/tui/banner.d.ts +10 -0
  308. package/dist/extensions/forgecli/tui/banner.js +36 -0
  309. package/dist/extensions/forgecli/tui/banner.js.map +1 -0
  310. package/dist/extensions/forgecli/tui/forge-header.d.ts +12 -0
  311. package/dist/extensions/forgecli/tui/forge-header.js +114 -0
  312. package/dist/extensions/forgecli/tui/forge-header.js.map +1 -0
  313. package/dist/extensions/forgecli/tui/input-router.d.ts +33 -0
  314. package/dist/extensions/forgecli/tui/input-router.js +136 -0
  315. package/dist/extensions/forgecli/tui/input-router.js.map +1 -0
  316. package/dist/extensions/forgecli/tui/orchestrator-status-bar.d.ts +26 -0
  317. package/dist/extensions/forgecli/tui/orchestrator-status-bar.js +213 -0
  318. package/dist/extensions/forgecli/tui/orchestrator-status-bar.js.map +1 -0
  319. package/dist/extensions/forgecli/tui/thread-switcher.d.ts +18 -0
  320. package/dist/extensions/forgecli/tui/thread-switcher.js +194 -0
  321. package/dist/extensions/forgecli/tui/thread-switcher.js.map +1 -0
  322. package/dist/extensions/forgecli/update/forge-update-command.d.ts +100 -0
  323. package/dist/extensions/forgecli/update/forge-update-command.js +435 -0
  324. package/dist/extensions/forgecli/update/forge-update-command.js.map +1 -0
  325. package/dist/extensions/forgecli/update/migration-engine.d.ts +117 -0
  326. package/dist/extensions/forgecli/update/migration-engine.js +563 -0
  327. package/dist/extensions/forgecli/update/migration-engine.js.map +1 -0
  328. package/dist/extensions/forgecli/update/update-check.d.ts +37 -0
  329. package/dist/extensions/forgecli/update/update-check.js +185 -0
  330. package/dist/extensions/forgecli/update/update-check.js.map +1 -0
  331. package/dist/extensions/forgecli/update/update-tools.d.ts +23 -0
  332. package/dist/extensions/forgecli/update/update-tools.js +135 -0
  333. package/dist/extensions/forgecli/update/update-tools.js.map +1 -0
  334. package/dist/extensions/forgecli/update/whats-new-widget.d.ts +26 -0
  335. package/dist/extensions/forgecli/update/whats-new-widget.js +376 -0
  336. package/dist/extensions/forgecli/update/whats-new-widget.js.map +1 -0
  337. package/dist/extensions/forgecli/update/whats-new.d.ts +120 -0
  338. package/dist/extensions/forgecli/update/whats-new.js +470 -0
  339. package/dist/extensions/forgecli/update/whats-new.js.map +1 -0
  340. package/dist/extensions/forgecli/viewport/events.d.ts +113 -0
  341. package/dist/extensions/forgecli/viewport/events.js +290 -0
  342. package/dist/extensions/forgecli/viewport/events.js.map +1 -0
  343. package/dist/extensions/forgecli/viewport/renderer.d.ts +102 -0
  344. package/dist/extensions/forgecli/viewport/renderer.js +277 -0
  345. package/dist/extensions/forgecli/viewport/renderer.js.map +1 -0
  346. package/dist/extensions/forgecli/viewport/theme.d.ts +11 -0
  347. package/dist/extensions/forgecli/viewport/theme.js +131 -0
  348. package/dist/extensions/forgecli/viewport/theme.js.map +1 -0
  349. package/dist/extensions/forgecli/wf-engine/engine.js +1 -1
  350. package/dist/extensions/forgecli/wf-engine/engine.js.map +1 -1
  351. package/dist/forge-payload/.base-pack/workflows/implement_plan.md +9 -0
  352. package/dist/forge-payload/.base-pack/workflows/plan_task.md +7 -0
  353. package/dist/forge-payload/.base-pack/workflows/review_code.md +4 -3
  354. package/dist/forge-payload/.base-pack/workflows/review_plan.md +4 -3
  355. package/dist/forge-payload/.base-pack/workflows/validate_task.md +4 -3
  356. package/dist/forge-payload/.claude-plugin/plugin.json +1 -1
  357. package/dist/forge-payload/.schemas/migrations.json +132 -27
  358. package/dist/forge-payload/meta/workflows/meta-review-implementation.md +4 -3
  359. package/dist/forge-payload/meta/workflows/meta-review-plan.md +4 -3
  360. package/dist/forge-payload/meta/workflows/meta-validate.md +4 -3
  361. package/dist/forge-payload/tools/collate.cjs +32 -0
  362. package/dist/forge-payload/tools/postflight-gate.cjs +56 -10
  363. package/package.json +5 -3
@@ -1,5 +1,5 @@
1
1
  import type { Theme } from "@earendil-works/pi-coding-agent";
2
- import type { Component, TUI } from "@earendil-works/pi-tui";
2
+ import type { Component, Focusable, TUI } from "@earendil-works/pi-tui";
3
3
  import type { OrchestratorTree } from "../orchestrator-tree.js";
4
4
  import type { NodeViewModel } from "./view-model.js";
5
5
  export interface DashboardState {
@@ -11,6 +11,10 @@ export interface DashboardState {
11
11
  focusPanel: "tree" | "detail";
12
12
  /** Whether the detail panel's prompt section is expanded. */
13
13
  promptExpanded: boolean;
14
+ /** Activity-log expansion (ctrl+o): false = clamp long entries to a small
15
+ * row budget, true = render full content. Display policy lives entirely in
16
+ * the view — the model stores log entries verbatim. */
17
+ logExpanded: boolean;
14
18
  /** Node ID targeted for cancellation confirmation, if active. */
15
19
  cancelTargetId: string | null;
16
20
  /** Scroll offset for the detail panel (0 = top). */
@@ -22,8 +26,12 @@ export declare class DashboardController {
22
26
  private state;
23
27
  private onInvalidate?;
24
28
  private refreshTimer?;
29
+ private disposed;
30
+ private readonly readOnly;
25
31
  private _handlers;
26
- constructor(tree: OrchestratorTree, initialCursorId?: string);
32
+ constructor(tree: OrchestratorTree, initialCursorId?: string, opts?: {
33
+ readOnly?: boolean;
34
+ });
27
35
  setOnInvalidate(cb: () => void): void;
28
36
  /** Rebuild the ViewModel from the live model. Called on every model event. */
29
37
  private rebuildViewModel;
@@ -67,6 +75,8 @@ export declare class DashboardController {
67
75
  private activateCursor;
68
76
  private toggleExpand;
69
77
  private collapseCursor;
78
+ /** Replay mode: read-only dashboards (archived trees) never cancel. */
79
+ isReadOnly(): boolean;
70
80
  private startCancel;
71
81
  private ensureAncestorsExpanded;
72
82
  autoExpandNewNode(id: string): void;
@@ -75,7 +85,11 @@ export declare class DashboardController {
75
85
  dispose(): void;
76
86
  getState(): DashboardState;
77
87
  }
78
- export declare class DashboardComponent implements Component {
88
+ export declare class DashboardComponent implements Component, Focusable {
89
+ /** IL3: Focusable — pi sets this to true when the overlay has
90
+ * keyboard focus. Without this, arrow-key and Escape events are
91
+ * swallowed at the overlay layer. (Lesson from config-TUI commit 07e886f.) */
92
+ focused: boolean;
79
93
  private controller;
80
94
  private theme;
81
95
  private tui;
@@ -86,7 +100,6 @@ export declare class DashboardComponent implements Component {
86
100
  invalidate(): void;
87
101
  dispose(): void;
88
102
  private renderTreePanel;
89
- private nodeGlyph;
90
103
  private renderDetailPanel;
91
104
  /** Render a cancel-confirmation dialog overlaid on the dashboard.
92
105
  * The dashboard content stays visible above and below the dialog.
@@ -97,6 +110,5 @@ export declare class DashboardComponent implements Component {
97
110
  * dismisses the cancel prompt, not the dashboard.
98
111
  */
99
112
  private overlayCancelConfirm;
100
- private statusLabel;
101
113
  private formatMetrics;
102
114
  }
@@ -20,11 +20,20 @@
20
20
  // manages the refresh timer, and handles input. DashboardComponent reads
21
21
  // only from the controller — never directly from the OrchestratorTree model.
22
22
  // This eliminates the boundary violations catalogued in the audit.
23
+ //
24
+ // Iron Laws conformance:
25
+ // IL1 — All visible strings route through dashboard/theme.ts helpers or
26
+ // theme.fg()/bg()/bold(). No raw glyphs.
27
+ // IL2 — Dual-layer width safety: screen renderers call truncateLines(),
28
+ // orchestrator applies truncateToWidth per line.
29
+ // IL3 — DashboardComponent implements Focusable (focused: boolean = false).
30
+ // IL7 — Timer unmount-safety: disposed flag guards interval callbacks.
23
31
  import { matchesKey, Key, truncateToWidth, visibleWidth } from "@earendil-works/pi-tui";
24
32
  import { getSessionRegistry } from "../session-registry.js";
25
33
  import { buildViewModel } from "./view-model.js";
26
- import { fmtTokenMeter } from "../viewport-renderer.js";
27
- import { paintTailLine } from "../viewport-theme.js";
34
+ import { fmtTokenMeter, toDisplayLines } from "../viewport/renderer.js";
35
+ import { paintTailLine } from "../viewport/theme.js";
36
+ import { cursor, nodeGlyph, statusLabel, dim, accentBold, warn, bold, border, collapseIndicator, promptExpandIcon, truncateLines, } from "./theme.js";
28
37
  // ── Word-wrap helper ───────────────────────────────────────────────────────────
29
38
  //
30
39
  // Splits a line (which may contain ANSI escape sequences) into multiple
@@ -32,6 +41,15 @@ import { paintTailLine } from "../viewport-theme.js";
32
41
  // Preserves ANSI styling across wrapped lines. Falls back to character-level
33
42
  // truncation for individual tokens wider than maxWidth.
34
43
  function wrapLine(line, maxWidth) {
44
+ // Row-integrity guard (layer 2 of the single-line invariant; layer 1 is
45
+ // toDisplayLines at the appendTail model boundary): a raw \n inside a
46
+ // composed pane row resets the terminal cursor to column 0 and the
47
+ // remainder renders under the LEFT pane. visibleWidth() counts \n as an
48
+ // ordinary character, so the short-line early-return below would pass a
49
+ // multi-line string through intact — split first, wrap each part.
50
+ if (/[\r\n]/.test(line)) {
51
+ return line.split(/\r\n|\r|\n/).flatMap((part) => wrapLine(part, maxWidth));
52
+ }
35
53
  if (maxWidth <= 0)
36
54
  return [line];
37
55
  const visW = visibleWidth(line);
@@ -99,8 +117,20 @@ function wrapLine(line, maxWidth) {
99
117
  lines.push(curLine);
100
118
  }
101
119
  return lines.length > 0 ? lines : [line];
102
- } // ── Refresh timer ───────────────────────────────────────────────────────────
120
+ }
121
+ /** Last-resort flatten for the pane compose loop: replace any surviving line
122
+ * break with a visible ⏎ so a single corrupted string can't shift the whole
123
+ * row grid. Upstream layers (toDisplayLines at appendTail, wrapLine split)
124
+ * should make this a no-op. */
125
+ function flattenRow(line) {
126
+ return /[\r\n]/.test(line) ? line.replace(/\r\n|\r|\n/g, " ⏎ ") : line;
127
+ }
128
+ // ── Refresh timer ───────────────────────────────────────────────────────────
103
129
  const REFRESH_INTERVAL_MS = 1000;
130
+ /** Max rendered rows per log entry when the activity log is clamped. */
131
+ const LOG_CLAMP_ROWS = 2;
132
+ /** Max prompt lines shown when expanded but not in full mode (ctrl+o). */
133
+ const PROMPT_CLAMP_LINES = 20;
104
134
  // ── Controller ──────────────────────────────────────────────────────────────
105
135
  export class DashboardController {
106
136
  tree;
@@ -108,8 +138,11 @@ export class DashboardController {
108
138
  state;
109
139
  onInvalidate;
110
140
  refreshTimer;
141
+ disposed = false; // IL7: guards interval callbacks after dispose
142
+ readOnly;
111
143
  _handlers;
112
- constructor(tree, initialCursorId) {
144
+ constructor(tree, initialCursorId, opts) {
145
+ this.readOnly = opts?.readOnly ?? false;
113
146
  this.tree = tree;
114
147
  this.vm = buildViewModel(tree);
115
148
  // Default cursor to the first active root, or empty string if tree is empty.
@@ -119,6 +152,7 @@ export class DashboardController {
119
152
  expanded: new Set(),
120
153
  focusPanel: "tree",
121
154
  promptExpanded: false,
155
+ logExpanded: false,
122
156
  cancelTargetId: null,
123
157
  detailScroll: 0,
124
158
  };
@@ -127,12 +161,14 @@ export class DashboardController {
127
161
  // On every model event, rebuild VM then invalidate the view.
128
162
  const onModelChange = () => {
129
163
  this.rebuildViewModel();
130
- this.onInvalidate?.();
164
+ if (!this.disposed)
165
+ this.onInvalidate?.();
131
166
  };
132
167
  const onTreeChange = (id) => {
133
168
  this.rebuildViewModel();
134
169
  this.autoExpandNewNode(id);
135
- this.onInvalidate?.();
170
+ if (!this.disposed)
171
+ this.onInvalidate?.();
136
172
  };
137
173
  this.tree.on("change", onModelChange);
138
174
  this.tree.on("tail", onModelChange);
@@ -268,7 +304,15 @@ export class DashboardController {
268
304
  // Cancel confirmation mode takes priority.
269
305
  if (this.state.cancelTargetId) {
270
306
  this.handleCancelConfirm(data);
271
- this.onInvalidate?.();
307
+ if (!this.disposed)
308
+ this.onInvalidate?.();
309
+ return;
310
+ }
311
+ // ctrl+o: toggle activity-log expansion (global — works in both panels).
312
+ if (matchesKey(data, Key.ctrl("o"))) {
313
+ this.state.logExpanded = !this.state.logExpanded;
314
+ if (!this.disposed)
315
+ this.onInvalidate?.();
272
316
  return;
273
317
  }
274
318
  switch (this.state.focusPanel) {
@@ -279,7 +323,8 @@ export class DashboardController {
279
323
  this.handleDetailInput(data);
280
324
  break;
281
325
  }
282
- this.onInvalidate?.();
326
+ if (!this.disposed)
327
+ this.onInvalidate?.();
283
328
  }
284
329
  handleTreeInput(data) {
285
330
  if (matchesKey(data, Key.up)) {
@@ -409,7 +454,16 @@ export class DashboardController {
409
454
  this.state.cursorId = node.parentId;
410
455
  }
411
456
  }
457
+ /** Replay mode: read-only dashboards (archived trees) never cancel. */
458
+ isReadOnly() {
459
+ return this.readOnly;
460
+ }
412
461
  startCancel() {
462
+ // Read-only replay: cancel is meaningless on an archived tree, and
463
+ // cancelNodeAndSessions would touch the LIVE SessionRegistry
464
+ // singleton. Single guard here covers both `x` entry points.
465
+ if (this.readOnly)
466
+ return;
413
467
  const node = this.vm.nodes.get(this.state.cursorId);
414
468
  if (!node)
415
469
  return;
@@ -478,6 +532,11 @@ export class DashboardController {
478
532
  if (this.refreshTimer)
479
533
  return;
480
534
  this.refreshTimer = setInterval(() => {
535
+ // IL7: guard against firing after dispose.
536
+ if (this.disposed) {
537
+ this.stopRefreshTimer();
538
+ return;
539
+ }
481
540
  if (!this.hasRunningNodes()) {
482
541
  // One last render to settle final frame, then stop timer.
483
542
  this.onInvalidate?.();
@@ -495,6 +554,7 @@ export class DashboardController {
495
554
  }
496
555
  // ── Cleanup ────────────────────────────────────────────────────────────
497
556
  dispose() {
557
+ this.disposed = true; // IL7: set before clearing timer so callback sees it
498
558
  this.stopRefreshTimer();
499
559
  for (const { event, handler } of this._handlers) {
500
560
  this.tree.off(event, handler);
@@ -507,6 +567,10 @@ export class DashboardController {
507
567
  }
508
568
  // ── View ────────────────────────────────────────────────────────────────────
509
569
  export class DashboardComponent {
570
+ /** IL3: Focusable — pi sets this to true when the overlay has
571
+ * keyboard focus. Without this, arrow-key and Escape events are
572
+ * swallowed at the overlay layer. (Lesson from config-TUI commit 07e886f.) */
573
+ focused = false;
510
574
  controller;
511
575
  theme;
512
576
  tui;
@@ -535,7 +599,7 @@ export class DashboardComponent {
535
599
  // ── Right panel: detail ─────────────────────────────────────────
536
600
  const rightLines = selectedNode
537
601
  ? this.renderDetailPanel(selectedNode, rightWidth)
538
- : [this.theme.fg("dim", "Select a node in the tree")];
602
+ : [dim("Select a node in the tree", this.theme)];
539
603
  // ── Compose ─────────────────────────────────────────────────────
540
604
  const termHeight = this.tui.terminal.rows;
541
605
  // Deduct 3 lines for top border, bottom border, and hints footer
@@ -563,35 +627,37 @@ export class DashboardComponent {
563
627
  paddedRightLines.push(rightLines[i + activeScroll] ?? "");
564
628
  }
565
629
  const lines = [];
566
- const border = (s) => this.theme.fg("border", s);
567
- const accent = (s) => this.theme.fg("accent", s);
568
630
  // ── Header ──────────────────────────────────────────────────────
569
631
  const headerText = ` Orchestrator Dashboard `;
570
- const headerPad = contentWidth - visibleWidth(border("")) - visibleWidth(accent(headerText));
571
- lines.push(border("╭") +
572
- accent(headerText) +
573
- border("─".repeat(Math.max(0, headerPad))) +
574
- border("╮"));
632
+ const headerPad = contentWidth - visibleWidth(border("", this.theme)) - visibleWidth(accentBold(headerText, this.theme));
633
+ lines.push(border("╭", this.theme) +
634
+ accentBold(headerText, this.theme) +
635
+ border("─".repeat(Math.max(0, headerPad)), this.theme) +
636
+ border("╮", this.theme));
575
637
  for (let i = 0; i < contentHeight; i++) {
576
- const left = truncateToWidth(paddedLeftLines[i], leftWidth);
577
- const right = truncateToWidth(paddedRightLines[i], rightWidth);
638
+ // Final row-integrity guard: by this point every line has passed
639
+ // wrapLine/truncate, but a stray line break would corrupt the whole
640
+ // row grid — flatten defensively (should never fire).
641
+ const left = truncateToWidth(flattenRow(paddedLeftLines[i]), leftWidth);
642
+ const right = truncateToWidth(flattenRow(paddedRightLines[i]), rightWidth);
578
643
  const lPad = leftWidth - visibleWidth(left);
579
644
  const rPad = rightWidth - visibleWidth(right);
580
- lines.push(border("│") +
645
+ lines.push(border("│", this.theme) +
581
646
  left +
582
647
  " ".repeat(Math.max(0, lPad)) +
583
- border("│") +
648
+ border("│", this.theme) +
584
649
  " " +
585
650
  right +
586
651
  " ".repeat(Math.max(0, rPad)) +
587
- border("│"));
652
+ border("│", this.theme));
588
653
  }
589
654
  // ── Footer: bottom border + key hints + model/token meter ────────
590
- const dim = (s) => this.theme.fg("dim", s);
591
655
  const hintsBase = state.cancelTargetId
592
656
  ? " y confirm · n dismiss · esc close"
593
- : " ↑↓ nav · → expand · ← back · ⏎ focus · x cancel · esc close";
594
- lines.push(border("╰") + border("─".repeat(contentWidth)) + border("╯"));
657
+ : this.controller.isReadOnly()
658
+ ? " ↑↓ nav · → expand · ← back · ⏎ focus · ^o log · esc close · replay (read-only)"
659
+ : " ↑↓ nav · → expand · ← back · ⏎ focus · ^o log · x cancel · esc close";
660
+ lines.push(border("╰", this.theme) + border("─".repeat(contentWidth), this.theme) + border("╯", this.theme));
595
661
  // Aggregate model + token footer (mirrors ViewportFooterComponent).
596
662
  const aggUsage = this.controller.getAggregateUsage();
597
663
  const aggCompression = this.controller.getAggregateCompression();
@@ -603,18 +669,18 @@ export class DashboardComponent {
603
669
  : (activeModel?.provider ?? activeModel?.model ?? "");
604
670
  let footerLine = "";
605
671
  if (modelLabel && meter) {
606
- footerLine = `${hintsBase} ${dim(modelLabel)} Σ ${meter}${compSuffix}`;
672
+ footerLine = `${hintsBase} ${dim(modelLabel, this.theme)} Σ ${meter}${compSuffix}`;
607
673
  }
608
674
  else if (meter) {
609
675
  footerLine = `${hintsBase} Σ ${meter}${compSuffix}`;
610
676
  }
611
677
  else if (modelLabel) {
612
- footerLine = `${hintsBase} ${dim(modelLabel)}`;
678
+ footerLine = `${hintsBase} ${dim(modelLabel, this.theme)}`;
613
679
  }
614
680
  else {
615
681
  footerLine = hintsBase;
616
682
  }
617
- lines.push(dim(truncateToWidth(footerLine, width)));
683
+ lines.push(dim(truncateToWidth(footerLine, width), this.theme));
618
684
  // ── Overlay cancel confirmation on top of dashboard content ────
619
685
  if (state.cancelTargetId) {
620
686
  return this.overlayCancelConfirm(lines, width, state.cancelTargetId);
@@ -641,11 +707,11 @@ export class DashboardComponent {
641
707
  // ── Tree panel renderer ─────────────────────────────────────────────────
642
708
  renderTreePanel(visibleIds, state, width) {
643
709
  if (visibleIds.length === 0) {
644
- return [this.theme.fg("dim", "No session running")];
710
+ return [dim("No session running", this.theme)];
645
711
  }
646
712
  const lines = [];
647
713
  // Header
648
- lines.push(this.theme.bold(this.theme.fg("accent", " Phases")));
714
+ lines.push(accentBold(" Phases", this.theme));
649
715
  for (const id of visibleIds) {
650
716
  const node = this.controller.getNode(id);
651
717
  if (!node)
@@ -653,110 +719,110 @@ export class DashboardComponent {
653
719
  const isCursor = id === state.cursorId;
654
720
  const depth = node.depth;
655
721
  const indent = " ".repeat(depth * 2);
722
+ // IL1: themed cursor and glyphs — no raw characters.
723
+ const cursorChar = cursor(isCursor, this.theme);
656
724
  // Status glyph
657
- const glyph = this.nodeGlyph(node);
725
+ const glyph = nodeGlyph(node.status, this.theme);
658
726
  // Progress label for orchestrators
659
727
  let label = node.label;
660
728
  if (node.kind === "orchestrator") {
661
729
  const prog = this.controller.getSubtreeProgress(id);
662
730
  label += ` ${prog.completed}/${prog.total}`;
663
731
  }
664
- // Expand indicator
732
+ // Expand/collapse indicator — themed
665
733
  const expandIndicator = node.kind === "orchestrator"
666
734
  ? state.expanded.has(id)
667
735
  ? " "
668
- : "▸"
736
+ : collapseIndicator(this.theme)
669
737
  : " ";
670
738
  // Combine
671
- const prefix = `${indent}${isCursor ? "❯" : " "} ${glyph} ${expandIndicator} `;
739
+ const prefix = `${indent}${cursorChar} ${glyph} ${expandIndicator} `;
672
740
  const styled = isCursor
673
741
  ? this.theme.bold(this.theme.fg("accent", `${prefix}${label}`))
674
742
  : `${prefix}${label}`;
675
743
  lines.push(truncateToWidth(styled, width));
676
744
  }
677
- return lines;
745
+ // IL2: dual-layer width safety — first guard in screen renderer.
746
+ return truncateLines(lines, width);
678
747
  }
679
- nodeGlyph(node) {
680
- switch (node.status) {
681
- case "completed":
682
- return this.theme.fg("success", "✔");
683
- case "running":
684
- return this.theme.fg("accent", "●");
685
- case "cancelling":
686
- return this.theme.fg("warning", "⏳");
687
- case "cancelled":
688
- return this.theme.fg("muted", "⊘");
689
- case "failed":
690
- return this.theme.fg("error", "✗");
691
- case "escalated":
692
- return this.theme.fg("error", "▲");
693
- case "pending":
694
- default:
695
- return this.theme.fg("dim", "○");
696
- }
697
- }
698
- // ── Detail panel renderer ────────────────────────────────────────────────
699
748
  renderDetailPanel(node, width) {
700
749
  const lines = [];
701
- const dim = (s) => this.theme.fg("dim", s);
702
- const accent = (s) => this.theme.fg("accent", s);
703
- const bold = (s) => this.theme.bold(s);
704
- const success = (s) => this.theme.fg("success", s);
705
- const warn = (s) => this.theme.fg("warning", s);
706
750
  // ── Header: label + status (wrap long model strings) ──────────────────
707
- const statusLabel = this.statusLabel(node.status);
751
+ const statusLabelStr = statusLabel(node.status);
708
752
  const modelPart = node.model ? ` · ${node.provider ?? ""} ${node.model}` : "";
709
- lines.push(...wrapLine(`${this.nodeGlyph(node)} ${bold(statusLabel)}${dim(modelPart)}`, width));
753
+ lines.push(...wrapLine(`${nodeGlyph(node.status, this.theme)} ${bold(statusLabelStr, this.theme)}${dim(modelPart, this.theme)}`, width));
710
754
  // ── Metrics line ────────────────────────────────────────────────
711
755
  const metrics = this.formatMetrics(node);
712
756
  if (metrics)
713
- lines.push(...wrapLine(dim(metrics), width));
757
+ lines.push(...wrapLine(dim(metrics, this.theme), width));
714
758
  lines.push("");
715
759
  // ── Orchestrator node: list children ─────────────────────────────
716
760
  if (node.kind === "orchestrator" && node.children.length > 0) {
717
761
  const children = this.controller.getChildren(node.id);
718
- lines.push(...wrapLine(dim(bold(`Agents · ${children.length}`)), width));
762
+ lines.push(...wrapLine(dim(bold(`Agents · ${children.length}`, this.theme), this.theme), width));
719
763
  for (const child of children) {
720
- const cglyph = this.nodeGlyph(child);
764
+ const cglyph = nodeGlyph(child.status, this.theme);
721
765
  const cmodel = child.model ? ` ${child.provider ?? ""} ${child.model}` : "";
722
766
  const cmetrics = this.formatMetrics(child);
723
767
  const cmetricsPart = cmetrics ? ` ${cmetrics}` : "";
724
- lines.push(...wrapLine(` ${cglyph} ${child.label}${dim(cmodel)}${dim(cmetricsPart)}`, width));
768
+ lines.push(...wrapLine(` ${cglyph} ${child.label}${dim(cmodel, this.theme)}${dim(cmetricsPart, this.theme)}`, width));
725
769
  }
726
770
  lines.push("");
727
771
  }
728
- // ── Prompt preview (expandable) ─────────────────────────────────
772
+ // ── Prompt preview (⏎ open/close, ctrl+o lifts the line cap) ────
773
+ // Model stores the full body (storage-capped only); the view owns
774
+ // clamping: ⏎ toggles the section, the clamp shows PROMPT_CLAMP_LINES,
775
+ // and ctrl+o (the global full-content toggle) reveals everything.
729
776
  if (node.promptPreview) {
730
- const expandIcon = this.controller.getState().promptExpanded ? "▼" : "▶";
731
- const lineCount = node.promptPreview.split("\n").length;
732
- lines.push(...wrapLine(dim(`${expandIcon} Prompt · ${lineCount} lines · ⏎ expand`), width));
733
- if (this.controller.getState().promptExpanded) {
734
- for (const pline of node.promptPreview.split("\n").slice(0, 20)) {
777
+ const st = this.controller.getState();
778
+ const expandIcon = promptExpandIcon(st.promptExpanded, this.theme);
779
+ const promptLines = toDisplayLines(node.promptPreview);
780
+ const lineCount = promptLines.length;
781
+ const hint = st.promptExpanded ? (st.logExpanded ? "⏎ collapse · ^o clamp" : "⏎ collapse · ^o full") : "⏎ expand";
782
+ lines.push(...wrapLine(dim(`${expandIcon} Prompt · ${lineCount} lines · ${hint}`, this.theme), width));
783
+ if (st.promptExpanded) {
784
+ const cap = st.logExpanded ? lineCount : PROMPT_CLAMP_LINES;
785
+ for (const pline of promptLines.slice(0, cap)) {
735
786
  // Indent wrapped prompt lines by 2 spaces
736
787
  const wrapped = wrapLine(pline, Math.max(0, width - 4));
737
788
  for (let i = 0; i < wrapped.length; i++) {
738
- lines.push(dim(i === 0 ? ` ${wrapped[i]}` : ` ${wrapped[i]}`));
789
+ lines.push(dim(i === 0 ? ` ${wrapped[i]}` : ` ${wrapped[i]}`, this.theme));
739
790
  }
740
791
  }
741
- if (lineCount > 20) {
742
- lines.push(dim(` … ${lineCount - 20} more lines`));
792
+ if (lineCount > cap) {
793
+ lines.push(dim(` … ${lineCount - cap} more lines · ^o expand`, this.theme));
743
794
  }
744
795
  }
745
796
  lines.push("");
746
797
  }
747
- // ── Activity: running full log of all turns ──────────────────────
798
+ // ── Activity: running log of all turns ───────────────────────────
799
+ // Entries are stored verbatim in the model (full commands, full
800
+ // errors, newlines and all); ALL display normalization happens here:
801
+ // toDisplayLines splits/sanitizes, wrapLine fits the pane width, and
802
+ // long entries clamp to LOG_CLAMP_ROWS unless expanded (ctrl+o).
748
803
  if (node.kind === "leaf" && node.tailBuffer.length > 0) {
804
+ const expanded = this.controller.getState().logExpanded;
749
805
  const total = node.tailBuffer.length;
750
- lines.push(...wrapLine(dim(`Activity · ${total} log line${total === 1 ? "" : "s"}`), width));
806
+ const modeHint = expanded ? "^o clamp" : "^o expand";
807
+ lines.push(...wrapLine(dim(`Activity · ${total} log entr${total === 1 ? "y" : "ies"} · ${modeHint}`, this.theme), width));
751
808
  for (const tline of node.tailBuffer) {
752
- const painted = paintTailLine(tline, this.theme);
753
- lines.push(...wrapLine(painted, width));
809
+ const rows = [];
810
+ for (const displayLine of toDisplayLines(tline)) {
811
+ rows.push(...wrapLine(paintTailLine(displayLine, this.theme), width));
812
+ }
813
+ if (expanded || rows.length <= LOG_CLAMP_ROWS) {
814
+ lines.push(...rows);
815
+ }
816
+ else {
817
+ lines.push(...rows.slice(0, LOG_CLAMP_ROWS));
818
+ lines.push(dim(` …(+${rows.length - LOG_CLAMP_ROWS} rows · ^o expand)`, this.theme));
819
+ }
754
820
  }
755
821
  lines.push("");
756
822
  }
757
823
  // ── Outcome ─────────────────────────────────────────────────────
758
824
  if (node.outcomePreview) {
759
- lines.push(dim("Outcome"));
825
+ lines.push(dim("Outcome", this.theme));
760
826
  for (const oline of node.outcomePreview.split("\n").slice(0, 8)) {
761
827
  const wrapped = wrapLine(oline, Math.max(0, width - 4));
762
828
  for (const wl of wrapped) {
@@ -765,10 +831,11 @@ export class DashboardComponent {
765
831
  }
766
832
  const lineCount = node.outcomePreview.split("\n").length;
767
833
  if (lineCount > 8) {
768
- lines.push(dim(` … ${lineCount - 8} more lines`));
834
+ lines.push(dim(` … ${lineCount - 8} more lines`, this.theme));
769
835
  }
770
836
  }
771
- return lines;
837
+ // IL2: dual-layer width safety — first guard in screen renderer.
838
+ return truncateLines(lines, width);
772
839
  }
773
840
  /** Render a cancel-confirmation dialog overlaid on the dashboard.
774
841
  * The dashboard content stays visible above and below the dialog.
@@ -781,34 +848,30 @@ export class DashboardComponent {
781
848
  overlayCancelConfirm(baseLines, width, targetId) {
782
849
  const node = this.controller.getNode(targetId);
783
850
  const label = node?.label ?? targetId;
784
- const dim = (s) => this.theme.fg("dim", s);
785
- const warn = (s) => this.theme.fg("warning", s);
786
- const bold = (s) => this.theme.bold(s);
787
- const brd = (s) => this.theme.fg("border", s);
788
851
  // Content width is the full width minus the two outer │ borders.
789
852
  const contentWidth = width - 2;
790
853
  // Build the dialog box (narrower than the full content area so it
791
854
  // floats with padding on each side).
792
855
  const dialogW = Math.min(contentWidth, 60);
793
856
  const diagLines = [];
794
- const prompt = warn(`⚠ Cancel ${bold(label)}?`);
795
- const actions = dim("y confirm · n dismiss · esc close");
857
+ const prompt = warn(`⚠ Cancel ${bold(label, this.theme)}?`, this.theme);
858
+ const actions = dim("y confirm · n dismiss · esc close", this.theme);
796
859
  const promptW = visibleWidth(prompt);
797
860
  const actionsW = visibleWidth(actions);
798
- diagLines.push(brd("╭") + brd("─".repeat(dialogW - 2)) + brd("╮"));
799
- diagLines.push(brd("│") + " ".repeat(dialogW - 2) + brd("│"));
861
+ diagLines.push(border("╭", this.theme) + border("─".repeat(dialogW - 2), this.theme) + border("╮", this.theme));
862
+ diagLines.push(border("│", this.theme) + " ".repeat(dialogW - 2) + border("│", this.theme));
800
863
  {
801
864
  // Place prompt and actions side by side when they fit; stack otherwise.
802
865
  const sideBySide = promptW + actionsW + 4 <= dialogW - 2;
803
866
  if (sideBySide) {
804
867
  const contentGap = Math.max(1, dialogW - 4 - promptW - actionsW);
805
- const contentLine = brd("│") + " " + prompt + " ".repeat(contentGap) + actions + " " + brd("│");
868
+ const contentLine = border("│", this.theme) + " " + prompt + " ".repeat(contentGap) + actions + " " + border("│", this.theme);
806
869
  if (visibleWidth(contentLine) < dialogW) {
807
870
  // Pad content line to full dialog width.
808
871
  const pad = dialogW - 2 - visibleWidth(contentLine.slice(1, -1));
809
- diagLines.push(brd("│") +
872
+ diagLines.push(border("│", this.theme) +
810
873
  " " + prompt + " ".repeat(contentGap + Math.max(0, pad)) + actions +
811
- " " + brd("│"));
874
+ " " + border("│", this.theme));
812
875
  }
813
876
  else {
814
877
  diagLines.push(contentLine);
@@ -817,13 +880,13 @@ export class DashboardComponent {
817
880
  else {
818
881
  // Stacked: prompt on one line, actions on the next.
819
882
  const promptPad = Math.max(0, dialogW - 2 - 1 - promptW - 1);
820
- diagLines.push(brd("│") + " " + prompt + " ".repeat(promptPad) + brd("│"));
883
+ diagLines.push(border("│", this.theme) + " " + prompt + " ".repeat(promptPad) + border("│", this.theme));
821
884
  const actionsPad = Math.max(0, dialogW - 2 - 1 - actionsW - 1);
822
- diagLines.push(brd("│") + " " + actions + " ".repeat(actionsPad) + brd("│"));
885
+ diagLines.push(border("│", this.theme) + " " + actions + " ".repeat(actionsPad) + border("│", this.theme));
823
886
  }
824
887
  }
825
- diagLines.push(brd("│") + " ".repeat(dialogW - 2) + brd("│"));
826
- diagLines.push(brd("╰") + brd("─".repeat(dialogW - 2)) + brd("╯"));
888
+ diagLines.push(border("│", this.theme) + " ".repeat(dialogW - 2) + border("│", this.theme));
889
+ diagLines.push(border("╰", this.theme) + border("─".repeat(dialogW - 2), this.theme) + border("╯", this.theme));
827
890
  // Center the dialog vertically within the content rows and
828
891
  // horizontally within the content area, preserving the outer │
829
892
  // borders on every row so the frame stays intact.
@@ -838,28 +901,10 @@ export class DashboardComponent {
838
901
  const rightPad = Math.max(0, contentWidth - leftPad - diagVisW);
839
902
  // Preserve the outer │ borders: left border + centered dialog + right border.
840
903
  result[startRow + i] =
841
- brd("│") + " ".repeat(leftPad) + diagLine + " ".repeat(rightPad) + brd("│");
904
+ border("│", this.theme) + " ".repeat(leftPad) + diagLine + " ".repeat(rightPad) + border("│", this.theme);
842
905
  }
843
906
  return result;
844
907
  }
845
- statusLabel(status) {
846
- switch (status) {
847
- case "completed":
848
- return "Completed";
849
- case "running":
850
- return "Running";
851
- case "cancelling":
852
- return "Cancelling…";
853
- case "cancelled":
854
- return "Cancelled";
855
- case "failed":
856
- return "Failed";
857
- case "escalated":
858
- return "Escalated";
859
- case "pending":
860
- return "Pending";
861
- }
862
- }
863
908
  formatMetrics(node) {
864
909
  const parts = [];
865
910
  if (node.usage.input || node.usage.output || node.usage.cacheRead) {