@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
@@ -0,0 +1,656 @@
1
+ // transcript-archive.ts — central, full-retention transcript archive core.
2
+ //
3
+ // Mirrors project-local `.forge/transcripts/<entityId>/` runs into the
4
+ // permanent cross-project archive under `~/.pi/forge-cli/transcripts/`
5
+ // (FORGE_CLI_HOME-aware via paths/paths.ts). Copy-up only: this module has
6
+ // ZERO delete paths — project-local transcripts stay untouched (live
7
+ // debugging and verify-governance.sh depend on them; the archive is the
8
+ // permanent mirror, `.forge/` is the ephemeral working copy).
9
+ //
10
+ // Compression is node:zlib gzip — byte archival of phase payloads (~10:1).
11
+ // NOT @entelligentsia/forge-compress, which is token compression for LLM
12
+ // contexts; nothing here ever re-enters a model context uncompressed.
13
+ //
14
+ // Every write path is best-effort and never throws: archiving is
15
+ // observability data, not load-bearing pipeline state. Every read path
16
+ // Value.Checks untrusted disk JSON and returns null/defaults on mismatch.
17
+ import * as crypto from "node:crypto";
18
+ import * as fs from "node:fs";
19
+ import * as path from "node:path";
20
+ import { gunzipSync, gzipSync } from "node:zlib";
21
+ import { Value } from "typebox/value";
22
+ import { getRunArchiveDir, getTranscriptArchiveRoot, getTranscriptIndexPath, getTranscriptProjectsPath, } from "./paths/paths.js";
23
+ import { IndexEntrySchema, PhaseUsageSchema, ProjectsRegistrySchema, RunManifestSchema, } from "./transcript-archive-types.js";
24
+ /**
25
+ * Read `{prefix, name, projectDir}` from a `.forge/config.json`. Defaults on
26
+ * any failure (missing file, malformed JSON, absent fields) — never throws.
27
+ * `projectDir` is derived from the config path itself (`<dir>/.forge/config.json`).
28
+ */
29
+ export function readProjectIdentity(configPath) {
30
+ const projectDir = path.dirname(path.dirname(configPath));
31
+ const fallbackName = path.basename(projectDir) || "project";
32
+ try {
33
+ const raw = JSON.parse(fs.readFileSync(configPath, "utf8"));
34
+ const prefix = typeof raw.project?.prefix === "string" && raw.project.prefix.length > 0
35
+ ? raw.project.prefix
36
+ : "project";
37
+ const name = typeof raw.project?.name === "string" && raw.project.name.length > 0
38
+ ? raw.project.name
39
+ : fallbackName;
40
+ return { prefix, name, projectDir };
41
+ }
42
+ catch {
43
+ return { prefix: "project", name: fallbackName, projectDir };
44
+ }
45
+ }
46
+ /**
47
+ * `<prefix>-<sha256(realpath(projectDir)).slice(0,8)>` — prefix alone can
48
+ * collide across projects (two repos both named "FORGE"); the path hash
49
+ * disambiguates. Falls back to the raw path when realpath throws (deleted
50
+ * or unmounted project dir — archive entries must remain addressable).
51
+ */
52
+ export function computeProjectKey(projectDir, prefix) {
53
+ let resolved;
54
+ try {
55
+ resolved = fs.realpathSync(projectDir);
56
+ }
57
+ catch {
58
+ resolved = projectDir;
59
+ }
60
+ const hash = crypto.createHash("sha256").update(resolved).digest("hex").slice(0, 8);
61
+ const slug = prefix
62
+ .toLowerCase()
63
+ .replace(/[^a-z0-9._-]/g, "_")
64
+ .slice(0, 40) || "project";
65
+ return `${slug}-${hash}`;
66
+ }
67
+ // ── Orchestrator JSONL + phase-transcript parsing ───────────────────────
68
+ /** "2026-05-28T13:35:00.123Z" → "20260528T133500Z" (compact UTC). */
69
+ function compactIso(iso) {
70
+ return iso.replace(/[-:]/g, "").replace(/\.\d+/, "");
71
+ }
72
+ /** "20260528T133500Z" → "2026-05-28T13:35:00Z" (inverse of compactIso). */
73
+ function expandCompactIso(compact) {
74
+ const m = /^(\d{4})(\d{2})(\d{2})T(\d{2})(\d{2})(\d{2})Z$/.exec(compact);
75
+ if (!m)
76
+ return compact;
77
+ return `${m[1]}-${m[2]}-${m[3]}T${m[4]}:${m[5]}:${m[6]}Z`;
78
+ }
79
+ /** Tolerant JSONL parse — skips malformed/truncated lines, never throws. */
80
+ function readJsonlEvents(filePath) {
81
+ let raw;
82
+ try {
83
+ raw = fs.readFileSync(filePath, "utf8");
84
+ }
85
+ catch {
86
+ return [];
87
+ }
88
+ const events = [];
89
+ for (const line of raw.split("\n")) {
90
+ const trimmed = line.trim();
91
+ if (!trimmed)
92
+ continue;
93
+ try {
94
+ const parsed = JSON.parse(trimmed);
95
+ if (parsed && typeof parsed === "object")
96
+ events.push(parsed);
97
+ }
98
+ catch {
99
+ // Crash-truncated tail line — skip.
100
+ }
101
+ }
102
+ return events;
103
+ }
104
+ /** Filename shape written by forge-subagent.ts / orchestrator-transcript.ts. */
105
+ const PHASE_FILE_RE = /^(\d{8}T\d{6}Z)__(.+)__(.+)\.json$/;
106
+ const ORCH_FILE_RE = /^(\d{8}T\d{6}Z)__(.+)__orchestrator\.jsonl$/;
107
+ /** Live tail-view log written by persistTailLog (viewport/events.ts). */
108
+ const TAIL_FILE_RE = /^(\d{8}T\d{6}Z)__(.+)__(.+)\.tail\.jsonl$/;
109
+ /** Extract header fields from a phase-transcript JSON; null on parse failure. */
110
+ function readPhaseHeader(absPath) {
111
+ try {
112
+ const raw = JSON.parse(fs.readFileSync(absPath, "utf8"));
113
+ const header = {};
114
+ if (typeof raw.model === "string" && raw.model.length > 0)
115
+ header.model = raw.model;
116
+ if (typeof raw.provider === "string" && raw.provider.length > 0)
117
+ header.provider = raw.provider;
118
+ if (typeof raw.startedAt === "string")
119
+ header.startedAt = raw.startedAt;
120
+ if (raw.usage && typeof raw.usage === "object") {
121
+ const candidate = raw.usage;
122
+ if (Value.Check(PhaseUsageSchema, candidate))
123
+ header.usage = candidate;
124
+ }
125
+ return header;
126
+ }
127
+ catch {
128
+ return null;
129
+ }
130
+ }
131
+ function emptyTotals() {
132
+ return {
133
+ input: 0,
134
+ output: 0,
135
+ cacheRead: 0,
136
+ cacheWrite: 0,
137
+ cost: 0,
138
+ byModel: {},
139
+ byProvider: {},
140
+ revisionLoops: 0,
141
+ };
142
+ }
143
+ function bumpAggregate(bucket, key, usage) {
144
+ const agg = bucket[key] ?? { input: 0, output: 0, cost: 0, phases: 0 };
145
+ agg.input += usage.input;
146
+ agg.output += usage.output;
147
+ agg.cost += usage.cost;
148
+ agg.phases += 1;
149
+ bucket[key] = agg;
150
+ }
151
+ function buildManifestForRun(runId, events, phaseFiles, tailFileNames, identity, projectKey, fallbackEntityId, fallbackStartIso, opts) {
152
+ const pipelineStart = events.find((e) => e.kind === "pipeline-start");
153
+ const pipelineEnd = events.find((e) => e.kind === "pipeline-end");
154
+ const phaseEnds = events.filter((e) => e.kind === "phase-end");
155
+ const revisionLoops = events.filter((e) => e.kind === "phase-loopback").length;
156
+ const entityId = typeof pipelineStart?.entityId === "string" && pipelineStart.entityId.length > 0
157
+ ? pipelineStart.entityId
158
+ : fallbackEntityId;
159
+ const rawKind = pipelineStart?.entityKind;
160
+ const entityKind = rawKind === "task" || rawKind === "bug" || rawKind === "sprint" ? rawKind : "unknown";
161
+ const rawOutcome = pipelineEnd?.outcome;
162
+ const outcome = rawOutcome === "complete" || rawOutcome === "halted" || rawOutcome === "cancelled" || rawOutcome === "error"
163
+ ? rawOutcome
164
+ : "incomplete";
165
+ // Phase records: one per phase-transcript file (chronological), decorated
166
+ // with verdict/attempt/elapsedMs from the matching phase-end event. Two
167
+ // matchers, tried in order:
168
+ // 1. phase-end.subagentTranscriptPath basename (exact, when populated)
169
+ // 2. same role, in chronological order (legacy runs without the path)
170
+ const phases = [];
171
+ const roleSeen = {};
172
+ const usedEnds = new Set();
173
+ for (const pf of [...phaseFiles].sort((a, b) => a.file.localeCompare(b.file))) {
174
+ roleSeen[pf.role] = (roleSeen[pf.role] ?? 0) + 1;
175
+ const header = readPhaseHeader(pf.absPath);
176
+ const record = {
177
+ role: pf.role,
178
+ attempt: roleSeen[pf.role],
179
+ verdict: "n/a",
180
+ file: pf.file,
181
+ };
182
+ // Pair the phase with its live tail-view log when one was persisted
183
+ // (same basename, .tail.jsonl suffix) — replay prefers it verbatim.
184
+ const tailName = `${pf.file.slice(0, -".json".length)}.tail.jsonl`;
185
+ if (tailFileNames.has(tailName))
186
+ record.tailFile = tailName;
187
+ if (header?.model)
188
+ record.model = header.model;
189
+ if (header?.provider)
190
+ record.provider = header.provider;
191
+ if (header?.usage)
192
+ record.usage = header.usage;
193
+ if (header?.startedAt)
194
+ record.startedAt = header.startedAt;
195
+ let matchIdx = phaseEnds.findIndex((e, i) => !usedEnds.has(i) &&
196
+ typeof e.subagentTranscriptPath === "string" &&
197
+ path.basename(e.subagentTranscriptPath) === pf.file);
198
+ if (matchIdx < 0) {
199
+ matchIdx = phaseEnds.findIndex((e, i) => !usedEnds.has(i) && e.phase === pf.role);
200
+ }
201
+ if (matchIdx >= 0) {
202
+ usedEnds.add(matchIdx);
203
+ const end = phaseEnds[matchIdx];
204
+ if (typeof end.verdict === "string")
205
+ record.verdict = end.verdict;
206
+ if (typeof end.attempt === "number")
207
+ record.attempt = end.attempt;
208
+ if (typeof end.elapsedMs === "number")
209
+ record.elapsedMs = end.elapsedMs;
210
+ }
211
+ phases.push(record);
212
+ }
213
+ // Phase-end events with no transcript file (export failed) still surface.
214
+ phaseEnds.forEach((end, i) => {
215
+ if (usedEnds.has(i))
216
+ return;
217
+ phases.push({
218
+ role: typeof end.phase === "string" ? end.phase : "unknown",
219
+ attempt: typeof end.attempt === "number" ? end.attempt : 1,
220
+ verdict: typeof end.verdict === "string" ? end.verdict : "n/a",
221
+ ...(typeof end.elapsedMs === "number" ? { elapsedMs: end.elapsedMs } : {}),
222
+ });
223
+ });
224
+ const totals = emptyTotals();
225
+ totals.revisionLoops = revisionLoops;
226
+ for (const p of phases) {
227
+ if (!p.usage)
228
+ continue;
229
+ totals.input += p.usage.input;
230
+ totals.output += p.usage.output;
231
+ totals.cacheRead += p.usage.cacheRead;
232
+ totals.cacheWrite += p.usage.cacheWrite;
233
+ totals.cost += p.usage.cost;
234
+ bumpAggregate(totals.byModel, p.model ?? "unknown", p.usage);
235
+ bumpAggregate(totals.byProvider, p.provider ?? "unknown", p.usage);
236
+ }
237
+ const startedAt = typeof pipelineStart?.ts === "string" ? pipelineStart.ts : undefined;
238
+ const finishedAt = typeof pipelineEnd?.ts === "string" ? pipelineEnd.ts : undefined;
239
+ const durationMs = typeof pipelineEnd?.elapsedMs === "number" ? pipelineEnd.elapsedMs : undefined;
240
+ return {
241
+ schema: "forge-run-manifest/v1",
242
+ runId,
243
+ projectKey,
244
+ projectPath: identity.projectDir,
245
+ projectName: identity.name,
246
+ projectPrefix: identity.prefix,
247
+ entityId,
248
+ entityKind,
249
+ ...(opts.sprintId ? { sprintId: opts.sprintId } : {}),
250
+ startedAt: startedAt ?? fallbackStartIso,
251
+ ...(finishedAt ? { finishedAt } : {}),
252
+ ...(durationMs !== undefined ? { durationMs } : {}),
253
+ outcome,
254
+ phases,
255
+ totals,
256
+ archivedAt: new Date().toISOString(),
257
+ };
258
+ }
259
+ /**
260
+ * Discover every run in a project-local entity transcript dir
261
+ * (`.forge/transcripts/<entityId>/`) and build a RunManifest for each.
262
+ *
263
+ * A "run" is one orchestrator JSONL file; its runId is the compact-ISO
264
+ * pipeline-start timestamp (falling back to the filename prefix). Phase
265
+ * transcript files are assigned to the latest run whose start precedes
266
+ * them — compact ISO prefixes compare lexicographically as timestamps.
267
+ */
268
+ export function buildRunsForEntityDir(entityDir, identity, projectKey, opts = {}) {
269
+ let names;
270
+ try {
271
+ names = fs.readdirSync(entityDir);
272
+ }
273
+ catch {
274
+ return [];
275
+ }
276
+ const fallbackEntityId = path.basename(entityDir);
277
+ const jsonls = [];
278
+ const phaseFiles = [];
279
+ const tailFiles = [];
280
+ for (const name of names) {
281
+ const orchMatch = ORCH_FILE_RE.exec(name);
282
+ if (orchMatch) {
283
+ jsonls.push({ absPath: path.join(entityDir, name), ts: orchMatch[1] });
284
+ continue;
285
+ }
286
+ const tailMatch = TAIL_FILE_RE.exec(name);
287
+ if (tailMatch) {
288
+ tailFiles.push({
289
+ absPath: path.join(entityDir, name),
290
+ file: name,
291
+ ts: tailMatch[1],
292
+ role: tailMatch[3],
293
+ });
294
+ continue;
295
+ }
296
+ const phaseMatch = PHASE_FILE_RE.exec(name);
297
+ if (phaseMatch) {
298
+ phaseFiles.push({
299
+ absPath: path.join(entityDir, name),
300
+ file: name,
301
+ ts: phaseMatch[1],
302
+ role: phaseMatch[3],
303
+ });
304
+ }
305
+ }
306
+ jsonls.sort((a, b) => a.ts.localeCompare(b.ts));
307
+ const runs = [];
308
+ for (let i = 0; i < jsonls.length; i++) {
309
+ const jsonl = jsonls[i];
310
+ const nextTs = jsonls[i + 1]?.ts;
311
+ const events = readJsonlEvents(jsonl.absPath);
312
+ const pipelineStart = events.find((e) => e.kind === "pipeline-start");
313
+ const runId = typeof pipelineStart?.ts === "string" ? compactIso(pipelineStart.ts) : jsonl.ts;
314
+ const inWindow = (pf) => pf.ts >= jsonl.ts && (nextTs === undefined || pf.ts < nextTs);
315
+ const runPhaseFiles = phaseFiles.filter(inWindow);
316
+ const runTailFiles = tailFiles.filter(inWindow);
317
+ runs.push({
318
+ runId,
319
+ jsonlPath: jsonl.absPath,
320
+ phaseFiles: runPhaseFiles,
321
+ tailFiles: runTailFiles,
322
+ manifest: buildManifestForRun(runId, events, runPhaseFiles, new Set(runTailFiles.map((tf) => tf.file)), identity, projectKey, fallbackEntityId, expandCompactIso(jsonl.ts), opts),
323
+ });
324
+ }
325
+ return runs;
326
+ }
327
+ // ── Archive writes ──────────────────────────────────────────────────────
328
+ function writeFileAtomic(target, content) {
329
+ const tmp = `${target}.tmp-${process.pid}`;
330
+ fs.writeFileSync(tmp, content, "utf8");
331
+ fs.renameSync(tmp, target);
332
+ }
333
+ function indexKey(projectKey, entityId, runId) {
334
+ return `${projectKey}/${entityId}/${runId}`;
335
+ }
336
+ function upsertProject(projectKey, identity, newRun) {
337
+ const registry = readProjects();
338
+ const now = new Date().toISOString();
339
+ const existing = registry.projects[projectKey];
340
+ registry.projects[projectKey] = {
341
+ path: identity.projectDir,
342
+ prefix: identity.prefix,
343
+ name: identity.name,
344
+ firstSeen: existing?.firstSeen ?? now,
345
+ lastSeen: now,
346
+ runCount: (existing?.runCount ?? 0) + (newRun ? 1 : 0),
347
+ };
348
+ writeFileAtomic(getTranscriptProjectsPath(), `${JSON.stringify(registry, null, 2)}\n`);
349
+ }
350
+ /**
351
+ * Archive one discovered run: gzip phase transcripts into the run dir, copy
352
+ * orchestrator.jsonl as-is, write manifest.json (tmp+rename), append the
353
+ * index line (only if this runId isn't already indexed — crash between
354
+ * manifest write and index append heals here), and upsert projects.json.
355
+ *
356
+ * Idempotent: re-archiving the same run (resume with the same runId, or a
357
+ * sweep racing a live pipeline) overwrites the manifest/payloads with newer,
358
+ * fuller data and appends no duplicate index line. Best-effort, never throws.
359
+ */
360
+ function writeRunArchive(run, identity, projectKey) {
361
+ try {
362
+ const { manifest } = run;
363
+ const runDir = getRunArchiveDir(projectKey, manifest.entityId, run.runId);
364
+ fs.mkdirSync(runDir, { recursive: true });
365
+ for (const pf of [...run.phaseFiles, ...run.tailFiles]) {
366
+ const gz = gzipSync(fs.readFileSync(pf.absPath));
367
+ fs.writeFileSync(path.join(runDir, `${pf.file}.gz`), gz);
368
+ }
369
+ fs.copyFileSync(run.jsonlPath, path.join(runDir, "orchestrator.jsonl"));
370
+ writeFileAtomic(path.join(runDir, "manifest.json"), `${JSON.stringify(manifest, null, 2)}\n`);
371
+ const alreadyIndexed = readIndex().some((e) => indexKey(e.projectKey, e.entityId, e.runId) === indexKey(projectKey, manifest.entityId, run.runId));
372
+ if (!alreadyIndexed) {
373
+ const entry = {
374
+ runId: run.runId,
375
+ projectKey,
376
+ entityId: manifest.entityId,
377
+ entityKind: manifest.entityKind,
378
+ ...(manifest.sprintId ? { sprintId: manifest.sprintId } : {}),
379
+ startedAt: manifest.startedAt,
380
+ outcome: manifest.outcome,
381
+ input: manifest.totals.input,
382
+ output: manifest.totals.output,
383
+ cost: manifest.totals.cost,
384
+ ...(manifest.durationMs !== undefined ? { durationMs: manifest.durationMs } : {}),
385
+ archivedAt: manifest.archivedAt,
386
+ };
387
+ // Single sub-1KB appendFileSync line — atomic on Linux.
388
+ fs.appendFileSync(getTranscriptIndexPath(), `${JSON.stringify(entry)}\n`, "utf8");
389
+ }
390
+ upsertProject(projectKey, identity, !alreadyIndexed);
391
+ return { archived: true, runDir };
392
+ }
393
+ catch (err) {
394
+ const e = err;
395
+ return { archived: false, error: e.message ?? "archive write failed" };
396
+ }
397
+ }
398
+ /**
399
+ * Archive the run identified by its project-local orchestrator transcript.
400
+ * Called by orchestrators after the pipeline result is known. Best-effort,
401
+ * never throws.
402
+ */
403
+ export function archiveRun(opts) {
404
+ try {
405
+ const configPath = opts.configPath ?? path.join(opts.cwd, ".forge", "config.json");
406
+ const identity = readProjectIdentity(configPath);
407
+ const projectKey = computeProjectKey(identity.projectDir, identity.prefix);
408
+ const entityDir = path.dirname(opts.orchestratorJsonlPath);
409
+ const runs = buildRunsForEntityDir(entityDir, identity, projectKey, { sprintId: opts.sprintId });
410
+ const wanted = path.resolve(opts.orchestratorJsonlPath);
411
+ const run = runs.find((r) => path.resolve(r.jsonlPath) === wanted);
412
+ if (!run)
413
+ return { archived: false, error: `no run found for ${opts.orchestratorJsonlPath}` };
414
+ return writeRunArchive(run, identity, projectKey);
415
+ }
416
+ catch (err) {
417
+ const e = err;
418
+ return { archived: false, error: e.message ?? "archiveRun failed" };
419
+ }
420
+ }
421
+ /**
422
+ * Adopt orphans: archive every project-local run whose runId isn't in the
423
+ * central index. Covers crash recovery (pipeline died before its archive
424
+ * call) and adoption of pre-existing history (transcripts written before
425
+ * this feature shipped). Called best-effort at pipeline start; never throws.
426
+ */
427
+ export function sweepProjectTranscripts(cwd, configPath) {
428
+ try {
429
+ const base = path.join(cwd, ".forge", "transcripts");
430
+ if (!fs.existsSync(base))
431
+ return { adopted: 0, errors: 0 };
432
+ const identity = readProjectIdentity(configPath ?? path.join(cwd, ".forge", "config.json"));
433
+ const projectKey = computeProjectKey(identity.projectDir, identity.prefix);
434
+ const indexed = new Set(readIndex().map((e) => indexKey(e.projectKey, e.entityId, e.runId)));
435
+ let adopted = 0;
436
+ let errors = 0;
437
+ for (const entry of fs.readdirSync(base, { withFileTypes: true })) {
438
+ if (!entry.isDirectory())
439
+ continue;
440
+ const runs = buildRunsForEntityDir(path.join(base, entry.name), identity, projectKey);
441
+ for (const run of runs) {
442
+ if (indexed.has(indexKey(projectKey, run.manifest.entityId, run.runId)))
443
+ continue;
444
+ const result = writeRunArchive(run, identity, projectKey);
445
+ if (result.archived)
446
+ adopted++;
447
+ else
448
+ errors++;
449
+ }
450
+ }
451
+ return { adopted, errors };
452
+ }
453
+ catch {
454
+ return { adopted: 0, errors: 1 };
455
+ }
456
+ }
457
+ // ── Archive reads ───────────────────────────────────────────────────────
458
+ /** Read index.jsonl — skips malformed/truncated lines, never throws. */
459
+ export function readIndex() {
460
+ const entries = [];
461
+ for (const event of readJsonlEvents(getTranscriptIndexPath())) {
462
+ if (Value.Check(IndexEntrySchema, event))
463
+ entries.push(event);
464
+ }
465
+ return entries;
466
+ }
467
+ /** Read projects.json — empty registry on any failure, never throws. */
468
+ export function readProjects() {
469
+ try {
470
+ const raw = JSON.parse(fs.readFileSync(getTranscriptProjectsPath(), "utf8"));
471
+ if (Value.Check(ProjectsRegistrySchema, raw))
472
+ return raw;
473
+ }
474
+ catch {
475
+ // fall through
476
+ }
477
+ return { version: 1, projects: {} };
478
+ }
479
+ /** Read `<runDir>/manifest.json` — null on missing/truncated/mismatched. */
480
+ export function readManifest(runDir) {
481
+ try {
482
+ const raw = JSON.parse(fs.readFileSync(path.join(runDir, "manifest.json"), "utf8"));
483
+ if (Value.Check(RunManifestSchema, raw))
484
+ return raw;
485
+ }
486
+ catch {
487
+ // fall through
488
+ }
489
+ return null;
490
+ }
491
+ /**
492
+ * Gunzip + parse an archived phase transcript. `file` is the manifest's
493
+ * phase `file` field (without `.gz`). Null on any failure, never throws.
494
+ */
495
+ export function gunzipPhase(runDir, file) {
496
+ try {
497
+ const gzPath = path.join(runDir, file.endsWith(".gz") ? file : `${file}.gz`);
498
+ const parsed = JSON.parse(gunzipSync(fs.readFileSync(gzPath)).toString("utf8"));
499
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
500
+ return parsed;
501
+ }
502
+ }
503
+ catch {
504
+ // fall through
505
+ }
506
+ return null;
507
+ }
508
+ /**
509
+ * Gunzip + parse an archived live tail log (`*.tail.jsonl.gz`). Returns the
510
+ * exact lines the dashboard rendered during the run, in order. Tolerant of
511
+ * truncated tails; null when the file is missing/unreadable. Never throws.
512
+ */
513
+ export function gunzipTailLog(runDir, file) {
514
+ try {
515
+ const gzPath = path.join(runDir, file.endsWith(".gz") ? file : `${file}.gz`);
516
+ const raw = gunzipSync(fs.readFileSync(gzPath)).toString("utf8");
517
+ const entries = [];
518
+ for (const line of raw.split("\n")) {
519
+ const trimmed = line.trim();
520
+ if (!trimmed)
521
+ continue;
522
+ try {
523
+ const parsed = JSON.parse(trimmed);
524
+ if (typeof parsed.line === "string") {
525
+ entries.push(parsed.warning === true ? { line: parsed.line, warning: true } : { line: parsed.line });
526
+ }
527
+ }
528
+ catch {
529
+ // truncated tail line — skip
530
+ }
531
+ }
532
+ return entries;
533
+ }
534
+ catch {
535
+ return null;
536
+ }
537
+ }
538
+ /** Resolve the archive dir for an index entry. */
539
+ export function runDirForEntry(entry) {
540
+ return getRunArchiveDir(entry.projectKey, entry.entityId, entry.runId);
541
+ }
542
+ function fmtSize(n) {
543
+ if (n >= 1_000_000)
544
+ return `${(n / 1_000_000).toFixed(1)}M`;
545
+ if (n >= 1_000)
546
+ return `${(n / 1_000).toFixed(1)}k`;
547
+ return String(n);
548
+ }
549
+ /**
550
+ * Per-turn digest of a gunzipped phase payload — never a raw JSON dump.
551
+ * Each assistant message is a turn: first text line + tool-call names;
552
+ * toolResult messages render as compact result markers.
553
+ */
554
+ export function digestPhasePayload(payload) {
555
+ const messages = Array.isArray(payload.messages) ? payload.messages : [];
556
+ const lines = [];
557
+ let turn = 0;
558
+ for (const msg of messages) {
559
+ if (msg.role === "assistant") {
560
+ turn++;
561
+ const parts = Array.isArray(msg.content) ? msg.content : [];
562
+ const textPart = parts.find((p) => p.type === "text" && typeof p.text === "string");
563
+ const firstLine = textPart ? textPart.text.trim().split("\n")[0] : "";
564
+ lines.push(` t${turn} ${firstLine ? (firstLine.length > 100 ? `${firstLine.slice(0, 100)}…` : firstLine) : "(no text)"}`);
565
+ for (const p of parts) {
566
+ if (p.type === "toolCall" && typeof p.name === "string")
567
+ lines.push(` → ${p.name}`);
568
+ }
569
+ }
570
+ else if (msg.role === "toolResult") {
571
+ const size = typeof msg.content === "string" ? msg.content.length : JSON.stringify(msg.content ?? "").length;
572
+ lines.push(` ← ${msg.toolName ?? "tool"} ${msg.isError ? "✗" : "✓"} (${fmtSize(size)} chars)`);
573
+ }
574
+ }
575
+ if (lines.length === 0)
576
+ lines.push(" (no messages in payload)");
577
+ return lines;
578
+ }
579
+ function firstLineOf(s, max = 120) {
580
+ const line = s.trim().split("\n")[0];
581
+ return line.length > max ? `${line.slice(0, max)}…` : line;
582
+ }
583
+ /** Extract readable text from a toolResult content value (string or parts array). */
584
+ function toolResultText(content) {
585
+ if (typeof content === "string")
586
+ return content;
587
+ if (Array.isArray(content)) {
588
+ return content
589
+ .filter((p) => !!p && typeof p === "object" && p.type === "text" && typeof p.text === "string")
590
+ .map((p) => p.text)
591
+ .join("\n");
592
+ }
593
+ if (content === undefined || content === null)
594
+ return "";
595
+ try {
596
+ return JSON.stringify(content);
597
+ }
598
+ catch {
599
+ return "";
600
+ }
601
+ }
602
+ /** Per-turn cap on assistant text in the verbose digest. */
603
+ const VERBOSE_TEXT_CAP = 1500;
604
+ /**
605
+ * VERBOSE digest of a gunzipped phase payload — the replay-dashboard feed.
606
+ * Unlike digestPhasePayload (compact markers for the `show` table), this
607
+ * carries the actual transcript content so a replayed run is readable:
608
+ * full assistant text (capped per turn), thinking first-lines, tool-call
609
+ * argument previews, and tool-result first-line previews.
610
+ *
611
+ * Multi-line assistant text is pushed as ONE entry — the dashboard splits
612
+ * lines at display time, and the tree's per-entry char cap still applies.
613
+ */
614
+ export function digestPhasePayloadVerbose(payload) {
615
+ const messages = Array.isArray(payload.messages) ? payload.messages : [];
616
+ const lines = [];
617
+ let turn = 0;
618
+ for (const msg of messages) {
619
+ if (msg.role === "assistant") {
620
+ turn++;
621
+ lines.push(`── t${turn} ──`);
622
+ const parts = Array.isArray(msg.content) ? msg.content : [];
623
+ for (const p of parts) {
624
+ if (p.type === "thinking" && typeof p.thinking === "string" && p.thinking.trim()) {
625
+ lines.push(`✱ thinking: ${firstLineOf(p.thinking)}`);
626
+ }
627
+ else if (p.type === "text" && typeof p.text === "string" && p.text.trim()) {
628
+ const text = p.text.trim();
629
+ lines.push(text.length > VERBOSE_TEXT_CAP ? `${text.slice(0, VERBOSE_TEXT_CAP)}…(+${text.length - VERBOSE_TEXT_CAP}c)` : text);
630
+ }
631
+ else if (p.type === "toolCall" && typeof p.name === "string") {
632
+ let argsPreview = "";
633
+ try {
634
+ argsPreview = p.arguments === undefined ? "" : JSON.stringify(p.arguments);
635
+ }
636
+ catch {
637
+ argsPreview = "";
638
+ }
639
+ if (argsPreview.length > 140)
640
+ argsPreview = `${argsPreview.slice(0, 140)}…`;
641
+ lines.push(`→ ${p.name}${argsPreview && argsPreview !== "{}" ? ` ${argsPreview}` : ""}`);
642
+ }
643
+ }
644
+ }
645
+ else if (msg.role === "toolResult") {
646
+ const text = toolResultText(msg.content);
647
+ const preview = firstLineOf(text);
648
+ lines.push(`← ${msg.toolName ?? "tool"} ${msg.isError ? "✗" : "✓"} (${fmtSize(text.length)}c)${preview ? ` ${preview}` : ""}`);
649
+ }
650
+ }
651
+ if (lines.length === 0)
652
+ lines.push("(no messages in payload)");
653
+ return lines;
654
+ }
655
+ export { getTranscriptArchiveRoot };
656
+ //# sourceMappingURL=transcript-archive.js.map