@the-open-engine/zeroshot 6.38.1 → 6.39.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (377) hide show
  1. package/cli/event-copy.js +8 -7
  2. package/cli/event-copy.ts +12 -0
  3. package/cli/index.js +7 -31
  4. package/cli/json-export.js +61 -64
  5. package/cli/json-export.ts +112 -0
  6. package/cli/message-formatter-utils.js +68 -56
  7. package/cli/message-formatter-utils.ts +121 -0
  8. package/cli/message-formatters-normal.js +124 -259
  9. package/cli/message-formatters-normal.ts +250 -0
  10. package/cli/message-formatters-watch.js +81 -84
  11. package/cli/message-formatters-watch.ts +189 -0
  12. package/lib/cluster/generated/protocol-schema.cjs +1 -1
  13. package/lib/cluster/generated/protocol-schema.mjs +1 -1
  14. package/lib/cluster/generated/protocol.d.cts +8 -0
  15. package/lib/cluster/generated/protocol.d.mts +8 -0
  16. package/lib/cluster/generated/protocol.d.ts +8 -0
  17. package/lib/clusters-registry.d.ts +23 -0
  18. package/lib/clusters-registry.js +17 -29
  19. package/lib/completion.d.ts +12 -0
  20. package/lib/completion.js +84 -94
  21. package/lib/compose-utils.d.ts +32 -0
  22. package/lib/compose-utils.js +57 -72
  23. package/lib/detached-startup.d.ts +83 -0
  24. package/lib/detached-startup.js +231 -302
  25. package/lib/docker-config.d.ts +43 -0
  26. package/lib/docker-config.js +150 -325
  27. package/lib/docker-env-auth.d.ts +17 -0
  28. package/lib/docker-env-auth.js +75 -0
  29. package/lib/git-remote-utils.d.ts +48 -0
  30. package/lib/git-remote-utils.js +147 -213
  31. package/lib/id-detector.d.ts +15 -0
  32. package/lib/id-detector.js +37 -41
  33. package/lib/path-check.d.ts +30 -0
  34. package/lib/path-check.js +42 -45
  35. package/lib/process-liveness.d.ts +16 -0
  36. package/lib/process-liveness.js +19 -12
  37. package/lib/provider-credential-path.d.ts +16 -0
  38. package/lib/provider-credential-path.js +31 -29
  39. package/lib/provider-defaults.d.ts +30 -0
  40. package/lib/provider-defaults.js +47 -42
  41. package/lib/provider-detection.d.ts +11 -0
  42. package/lib/provider-detection.js +91 -54
  43. package/lib/provider-names.d.ts +38 -0
  44. package/lib/provider-names.js +56 -64
  45. package/lib/repo-settings.d.ts +28 -0
  46. package/lib/repo-settings.js +83 -59
  47. package/lib/run-mode.d.ts +21 -0
  48. package/lib/run-mode.js +21 -20
  49. package/lib/run-plan.d.ts +28 -0
  50. package/lib/run-plan.js +17 -16
  51. package/lib/settings/claude-auth.d.ts +35 -0
  52. package/lib/settings/claude-auth.js +30 -47
  53. package/lib/settings-defaults.d.ts +20 -0
  54. package/lib/settings-defaults.js +149 -0
  55. package/lib/settings-error.d.ts +7 -0
  56. package/lib/settings-error.js +8 -0
  57. package/lib/settings-issue-providers.d.ts +10 -0
  58. package/lib/settings-issue-providers.js +12 -0
  59. package/lib/settings-models.d.ts +22 -0
  60. package/lib/settings-models.js +93 -0
  61. package/lib/settings-storage.d.ts +23 -0
  62. package/lib/settings-storage.js +205 -0
  63. package/lib/settings-validation.d.ts +7 -0
  64. package/lib/settings-validation.js +182 -0
  65. package/lib/settings.d.ts +29 -0
  66. package/lib/settings.js +41 -736
  67. package/lib/setup-apply-types.d.ts +66 -0
  68. package/lib/setup-apply-types.js +2 -0
  69. package/lib/setup-apply.d.ts +39 -0
  70. package/lib/setup-apply.js +267 -264
  71. package/lib/setup-journal.d.ts +41 -0
  72. package/lib/setup-journal.js +119 -76
  73. package/lib/setup-plan-types.d.ts +102 -0
  74. package/lib/setup-plan-types.js +2 -0
  75. package/lib/setup-plan.d.ts +30 -0
  76. package/lib/setup-plan.js +300 -324
  77. package/lib/setup-undo.d.ts +44 -0
  78. package/lib/setup-undo.js +61 -74
  79. package/lib/start-cluster-config.d.ts +26 -0
  80. package/lib/start-cluster-config.js +56 -0
  81. package/lib/start-cluster-environment.d.ts +40 -0
  82. package/lib/start-cluster-environment.js +134 -0
  83. package/lib/start-cluster-run-options.d.ts +53 -0
  84. package/lib/start-cluster-run-options.js +147 -0
  85. package/lib/start-cluster.d.ts +64 -0
  86. package/lib/start-cluster.js +98 -454
  87. package/lib/stream-json-parser.d.ts +17 -0
  88. package/lib/stream-json-parser.js +51 -52
  89. package/npm-shrinkwrap.json +2 -2
  90. package/package.json +12 -6
  91. package/scripts/postinstall.js +27 -0
  92. package/scripts/rust-distribution.js +23 -14
  93. package/src/agent/agent-command-proofs-context.js +35 -45
  94. package/src/agent/agent-command-proofs-context.ts +87 -0
  95. package/src/agent/agent-config-settings.js +19 -0
  96. package/src/agent/agent-config-settings.ts +41 -0
  97. package/src/agent/agent-config.js +122 -231
  98. package/src/agent/agent-config.ts +285 -0
  99. package/src/agent/agent-context-builder.js +38 -273
  100. package/src/agent/agent-context-builder.ts +51 -0
  101. package/src/agent/agent-context-environment-sections.js +105 -0
  102. package/src/agent/agent-context-environment-sections.ts +134 -0
  103. package/src/agent/agent-context-packs.js +165 -0
  104. package/src/agent/agent-context-packs.ts +296 -0
  105. package/src/agent/agent-context-prompt-sections.js +100 -0
  106. package/src/agent/agent-context-prompt-sections.ts +148 -0
  107. package/src/agent/agent-context-sections.js +25 -334
  108. package/src/agent/agent-context-sections.ts +36 -0
  109. package/src/agent/agent-context-sources.js +96 -149
  110. package/src/agent/agent-context-sources.ts +253 -0
  111. package/src/agent/agent-context-types.js +2 -0
  112. package/src/agent/agent-context-types.ts +132 -0
  113. package/src/agent/agent-context-validation-sections.js +73 -0
  114. package/src/agent/agent-context-validation-sections.ts +129 -0
  115. package/src/agent/agent-input-injector.js +99 -118
  116. package/src/agent/agent-input-injector.ts +195 -0
  117. package/src/agent/agent-liveness-poll.js +74 -78
  118. package/src/agent/agent-liveness-poll.ts +163 -0
  119. package/src/agent/agent-quality-gate-schema.js +77 -86
  120. package/src/agent/agent-quality-gate-schema.ts +135 -0
  121. package/src/agent/agent-quality-gates-context.js +44 -50
  122. package/src/agent/agent-quality-gates-context.ts +91 -0
  123. package/src/agent/agent-stuck-detector.js +171 -239
  124. package/src/agent/agent-stuck-detector.ts +288 -0
  125. package/src/agent/agent-trigger-evaluator.js +29 -46
  126. package/src/agent/agent-trigger-evaluator.ts +98 -0
  127. package/src/agent/context-metrics.js +110 -141
  128. package/src/agent/context-metrics.ts +261 -0
  129. package/src/agent/context-pack-builder.js +72 -358
  130. package/src/agent/context-pack-builder.ts +105 -0
  131. package/src/agent/context-pack-core.js +70 -0
  132. package/src/agent/context-pack-core.ts +96 -0
  133. package/src/agent/context-pack-selection.js +119 -0
  134. package/src/agent/context-pack-selection.ts +187 -0
  135. package/src/agent/context-pack-truncation.js +139 -0
  136. package/src/agent/context-pack-truncation.ts +208 -0
  137. package/src/agent/context-pack-types.js +2 -0
  138. package/src/agent/context-pack-types.ts +98 -0
  139. package/src/agent/context-replay-policy.js +30 -39
  140. package/src/agent/context-replay-policy.ts +71 -0
  141. package/src/agent/critical-agent-policy.js +6 -10
  142. package/src/agent/critical-agent-policy.ts +20 -0
  143. package/src/agent/guidance-queue.js +74 -87
  144. package/src/agent/guidance-queue.ts +166 -0
  145. package/src/agent/output-extraction-error-detail.js +45 -0
  146. package/src/agent/output-extraction-error-detail.ts +49 -0
  147. package/src/agent/output-extraction-failures.js +125 -0
  148. package/src/agent/output-extraction-failures.ts +149 -0
  149. package/src/agent/output-extraction-json.js +234 -0
  150. package/src/agent/output-extraction-json.ts +235 -0
  151. package/src/agent/output-extraction-pi.js +124 -0
  152. package/src/agent/output-extraction-pi.ts +137 -0
  153. package/src/agent/output-extraction-types.js +2 -0
  154. package/src/agent/output-extraction-types.ts +49 -0
  155. package/src/agent/output-extraction.js +17 -617
  156. package/src/agent/output-extraction.ts +30 -0
  157. package/src/agent/output-reformatter-errors.js +83 -0
  158. package/src/agent/output-reformatter-errors.ts +106 -0
  159. package/src/agent/output-reformatter-types.js +2 -0
  160. package/src/agent/output-reformatter-types.ts +86 -0
  161. package/src/agent/output-reformatter.js +140 -185
  162. package/src/agent/output-reformatter.ts +238 -0
  163. package/src/agent/pi-terminal-lifecycle-types.js +2 -0
  164. package/src/agent/pi-terminal-lifecycle-types.ts +41 -0
  165. package/src/agent/pi-terminal-lifecycle.js +186 -206
  166. package/src/agent/pi-terminal-lifecycle.ts +297 -0
  167. package/src/agent/provider-control-plane.js +22 -21
  168. package/src/agent/provider-control-plane.ts +52 -0
  169. package/src/agent/provider-terminal-failure-types.js +2 -0
  170. package/src/agent/provider-terminal-failure-types.ts +60 -0
  171. package/src/agent/provider-terminal-failure.js +194 -191
  172. package/src/agent/provider-terminal-failure.ts +262 -0
  173. package/src/agent/rate-limit-backoff.js +31 -74
  174. package/src/agent/rate-limit-backoff.ts +71 -0
  175. package/src/agent/schema-utils.js +85 -125
  176. package/src/agent/schema-utils.ts +148 -0
  177. package/src/agent/structured-output-error.js +34 -33
  178. package/src/agent/structured-output-error.ts +105 -0
  179. package/src/agent/validation-platform.js +27 -27
  180. package/src/agent/validation-platform.ts +49 -0
  181. package/src/attach/attach-client.js +232 -405
  182. package/src/attach/attach-client.ts +300 -0
  183. package/src/attach/attach-server-cleanup.js +43 -0
  184. package/src/attach/attach-server-cleanup.ts +39 -0
  185. package/src/attach/attach-server-clients.js +117 -0
  186. package/src/attach/attach-server-clients.ts +122 -0
  187. package/src/attach/attach-server-events.js +38 -0
  188. package/src/attach/attach-server-events.ts +36 -0
  189. package/src/attach/attach-server-pty.js +45 -0
  190. package/src/attach/attach-server-pty.ts +64 -0
  191. package/src/attach/attach-server-runtime.js +73 -0
  192. package/src/attach/attach-server-runtime.ts +62 -0
  193. package/src/attach/attach-server-socket.js +28 -0
  194. package/src/attach/attach-server-socket.ts +23 -0
  195. package/src/attach/attach-server-types.js +2 -0
  196. package/src/attach/attach-server-types.ts +82 -0
  197. package/src/attach/attach-server.js +106 -523
  198. package/src/attach/attach-server.ts +158 -0
  199. package/src/attach/index.js +18 -35
  200. package/src/attach/index.ts +18 -0
  201. package/src/attach/protocol.js +95 -184
  202. package/src/attach/protocol.ts +181 -0
  203. package/src/attach/ring-buffer.js +76 -102
  204. package/src/attach/ring-buffer.ts +109 -0
  205. package/src/attach/send-input.js +64 -75
  206. package/src/attach/send-input.ts +94 -0
  207. package/src/attach/socket-discovery.js +164 -218
  208. package/src/attach/socket-discovery.ts +230 -0
  209. package/src/attach/socket-paths.js +42 -61
  210. package/src/attach/socket-paths.ts +81 -0
  211. package/src/claude-credentials.js +51 -54
  212. package/src/claude-credentials.ts +89 -0
  213. package/src/cluster/generated/protocol-schema.ts +1 -1
  214. package/src/cluster/generated/protocol.ts +2 -1
  215. package/src/command-proofs.js +110 -141
  216. package/src/command-proofs.ts +216 -0
  217. package/src/config-router.js +81 -73
  218. package/src/config-router.ts +131 -0
  219. package/src/copy-worker.js +53 -29
  220. package/src/copy-worker.ts +75 -0
  221. package/src/darwin-keychain-boundary.js +80 -111
  222. package/src/darwin-keychain-boundary.ts +148 -0
  223. package/src/guidance-topics.js +4 -5
  224. package/src/guidance-topics.ts +10 -0
  225. package/src/input-helpers.js +33 -54
  226. package/src/input-helpers.ts +58 -0
  227. package/src/ledger-sequence.js +45 -48
  228. package/src/ledger-sequence.ts +63 -0
  229. package/src/legacy-lib/clusters-registry.ts +40 -0
  230. package/src/legacy-lib/completion.ts +148 -0
  231. package/src/legacy-lib/compose-utils.ts +102 -0
  232. package/src/legacy-lib/detached-startup.ts +449 -0
  233. package/src/legacy-lib/docker-config.ts +282 -0
  234. package/src/legacy-lib/docker-env-auth.ts +116 -0
  235. package/src/legacy-lib/git-remote-utils.ts +244 -0
  236. package/src/legacy-lib/id-detector.ts +57 -0
  237. package/src/legacy-lib/js-yaml.d.ts +3 -0
  238. package/src/legacy-lib/omelette.d.ts +15 -0
  239. package/src/legacy-lib/path-check.ts +89 -0
  240. package/src/legacy-lib/process-liveness.ts +36 -0
  241. package/src/legacy-lib/provider-credential-path.ts +57 -0
  242. package/src/legacy-lib/provider-defaults.ts +114 -0
  243. package/src/legacy-lib/provider-detection.ts +67 -0
  244. package/src/legacy-lib/provider-names.ts +126 -0
  245. package/src/legacy-lib/repo-settings.ts +88 -0
  246. package/src/legacy-lib/run-mode.ts +58 -0
  247. package/src/legacy-lib/run-plan.ts +49 -0
  248. package/src/legacy-lib/settings/claude-auth.ts +80 -0
  249. package/src/legacy-lib/settings-defaults.ts +212 -0
  250. package/src/legacy-lib/settings-error.ts +8 -0
  251. package/src/legacy-lib/settings-issue-providers.ts +18 -0
  252. package/src/legacy-lib/settings-models.ts +124 -0
  253. package/src/legacy-lib/settings-storage.ts +277 -0
  254. package/src/legacy-lib/settings-validation.ts +220 -0
  255. package/src/legacy-lib/settings.ts +87 -0
  256. package/src/legacy-lib/setup-apply-types.ts +70 -0
  257. package/src/legacy-lib/setup-apply.ts +456 -0
  258. package/src/legacy-lib/setup-journal.ts +185 -0
  259. package/src/legacy-lib/setup-plan-types.ts +96 -0
  260. package/src/legacy-lib/setup-plan.ts +500 -0
  261. package/src/legacy-lib/setup-undo.ts +142 -0
  262. package/src/legacy-lib/start-cluster-config.ts +124 -0
  263. package/src/legacy-lib/start-cluster-environment.ts +165 -0
  264. package/src/legacy-lib/start-cluster-run-options.ts +279 -0
  265. package/src/legacy-lib/start-cluster.ts +237 -0
  266. package/src/legacy-lib/stream-json-parser.ts +88 -0
  267. package/src/message-buffer.js +55 -71
  268. package/src/message-buffer.ts +107 -0
  269. package/src/message-bus-bridge.js +92 -133
  270. package/src/message-bus-bridge.ts +149 -0
  271. package/src/name-generator-shared.js +220 -0
  272. package/src/name-generator-shared.ts +231 -0
  273. package/src/name-generator.js +8 -217
  274. package/src/name-generator.ts +27 -0
  275. package/src/omp-blob-root.js +83 -64
  276. package/src/omp-blob-root.ts +116 -0
  277. package/src/omp-config-overlay.js +65 -38
  278. package/src/omp-config-overlay.ts +110 -0
  279. package/src/omp-execution-fingerprint.js +38 -43
  280. package/src/omp-execution-fingerprint.ts +92 -0
  281. package/src/omp-session-limits.js +10 -15
  282. package/src/omp-session-limits.ts +53 -0
  283. package/src/omp-session-partition.js +2 -2
  284. package/src/omp-session-verifier.js +1 -1
  285. package/src/orchestrator.js +19 -4
  286. package/src/providers/anthropic/index.js +3 -1
  287. package/src/providers/anthropic/index.ts +13 -0
  288. package/src/providers/capabilities.js +19 -27
  289. package/src/providers/capabilities.ts +44 -0
  290. package/src/providers/google/index.js +3 -1
  291. package/src/providers/google/index.ts +13 -0
  292. package/src/providers/openai/index.js +3 -1
  293. package/src/providers/openai/index.ts +13 -0
  294. package/src/providers/opencode/index.js +3 -1
  295. package/src/providers/opencode/index.ts +13 -0
  296. package/src/quality-gates.js +67 -127
  297. package/src/quality-gates.ts +149 -0
  298. package/src/repo-settings-access.js +40 -0
  299. package/src/repo-settings-access.ts +64 -0
  300. package/src/schemas/sub-cluster.js +127 -183
  301. package/src/schemas/sub-cluster.ts +238 -0
  302. package/src/state-snapshot-normalization.js +224 -0
  303. package/src/state-snapshot-normalization.ts +222 -0
  304. package/src/state-snapshot.js +192 -359
  305. package/src/state-snapshot.ts +291 -0
  306. package/src/state-snapshotter.js +118 -130
  307. package/src/state-snapshotter.ts +167 -0
  308. package/src/sub-cluster-wrapper.js +4 -13
  309. package/src/task-run-model-args.js +87 -124
  310. package/src/task-run-model-args.ts +204 -0
  311. package/src/task-runner.js +5 -25
  312. package/src/task-runner.ts +28 -0
  313. package/src/task-startup-error.js +73 -58
  314. package/src/task-startup-error.ts +126 -0
  315. package/src/template-validation/consensus-gate-contracts.js +2 -0
  316. package/src/template-validation/consensus-gate-contracts.ts +70 -0
  317. package/src/template-validation/consensus-gate-scenarios.js +76 -0
  318. package/src/template-validation/consensus-gate-scenarios.ts +130 -0
  319. package/src/template-validation/consensus-gate-stage.js +34 -0
  320. package/src/template-validation/consensus-gate-stage.ts +56 -0
  321. package/src/template-validation/random-topology-contracts.js +2 -0
  322. package/src/template-validation/random-topology-contracts.ts +54 -0
  323. package/src/template-validation/random-topology-dispatch.js +25 -0
  324. package/src/template-validation/random-topology-dispatch.ts +33 -0
  325. package/src/template-validation/random-topology-message-loop.js +53 -0
  326. package/src/template-validation/random-topology-message-loop.ts +73 -0
  327. package/src/template-validation/random-topology-operations.js +79 -0
  328. package/src/template-validation/random-topology-operations.ts +101 -0
  329. package/src/template-validation/random-topology-runtime.js +25 -0
  330. package/src/template-validation/random-topology-runtime.ts +43 -0
  331. package/src/template-validation/random-topology-scenario.js +52 -0
  332. package/src/template-validation/random-topology-scenario.ts +57 -0
  333. package/src/template-validation/random-topology-schema.js +159 -0
  334. package/src/template-validation/random-topology-schema.ts +190 -0
  335. package/src/template-validation/random-topology-state.js +28 -0
  336. package/src/template-validation/random-topology-state.ts +30 -0
  337. package/src/template-validation/random-topology-trigger-evaluation.js +45 -0
  338. package/src/template-validation/random-topology-trigger-evaluation.ts +65 -0
  339. package/src/template-validation/random-topology-trigger.js +75 -0
  340. package/src/template-validation/random-topology-trigger.ts +88 -0
  341. package/src/template-validation/report-formatter.js +40 -46
  342. package/src/template-validation/report-formatter.ts +101 -0
  343. package/src/template-validation/simulate-consensus-gates.js +111 -302
  344. package/src/template-validation/simulate-consensus-gates.ts +196 -0
  345. package/src/template-validation/simulate-random-topology.js +26 -519
  346. package/src/template-validation/simulate-random-topology.ts +57 -0
  347. package/src/template-validation/simulate-two-stage-validation.js +41 -265
  348. package/src/template-validation/simulate-two-stage-validation.ts +55 -0
  349. package/src/template-validation/simulation-agent-runtime.js +25 -0
  350. package/src/template-validation/simulation-agent-runtime.ts +40 -0
  351. package/src/template-validation/simulation-agent.js +29 -0
  352. package/src/template-validation/simulation-agent.ts +73 -0
  353. package/src/template-validation/simulation-runtime.js +34 -0
  354. package/src/template-validation/simulation-runtime.ts +72 -0
  355. package/src/template-validation/two-stage-contracts.js +2 -0
  356. package/src/template-validation/two-stage-contracts.ts +41 -0
  357. package/src/template-validation/two-stage-inputs.js +21 -0
  358. package/src/template-validation/two-stage-inputs.ts +29 -0
  359. package/src/template-validation/two-stage-results.js +30 -0
  360. package/src/template-validation/two-stage-results.ts +40 -0
  361. package/src/template-validation/two-stage-scenario.js +86 -0
  362. package/src/template-validation/two-stage-scenario.ts +120 -0
  363. package/src/worktree-claude-config.js +182 -220
  364. package/src/worktree-claude-config.ts +272 -0
  365. package/src/worktree-tooling-env.js +103 -125
  366. package/src/worktree-tooling-env.ts +142 -0
  367. package/task-lib/completion.js +2 -3
  368. package/task-lib/completion.ts +9 -0
  369. package/task-lib/config.js +1 -4
  370. package/task-lib/config.ts +11 -0
  371. package/task-lib/name-generator.js +4 -226
  372. package/task-lib/name-generator.ts +11 -0
  373. package/task-lib/omp-session-cleanup.js +1 -1
  374. package/task-lib/omp-storage-root.js +8 -12
  375. package/task-lib/omp-storage-root.ts +62 -0
  376. package/task-lib/process-termination.js +143 -166
  377. package/task-lib/process-termination.ts +268 -0
@@ -1,283 +1,148 @@
1
- /**
2
- * Normal mode message formatters
3
- * Full-detail message display for non-watch mode
4
- *
5
- * All functions accept an optional `print` parameter for output routing.
6
- * When StatusFooter is active, pass safePrint to avoid terminal garbling.
7
- */
8
-
9
- const chalk = require('chalk');
10
- const { EVENT_COPY, formatMergeStatus } = require('./event-copy');
11
-
12
- /**
13
- * Format AGENT_LIFECYCLE events
14
- * @param {Object} msg - Message object
15
- * @param {string} prefix - Formatted message prefix
16
- * @param {Function} [print=console.log] - Print function for output
17
- * @returns {boolean} True if message was handled
18
- */
1
+ "use strict";
2
+ const chalk = require("chalk");
3
+ const eventCopy = require("./event-copy");
4
+ const formatterUtils = require("./message-formatter-utils");
5
+ const { EVENT_COPY, formatMergeStatus } = eventCopy;
6
+ const { formatLifecycleEvent, partitionValidationCriteria } = formatterUtils;
7
+ function isCriterionResults(value) {
8
+ return Array.isArray(value);
9
+ }
19
10
  function formatAgentLifecycle(msg, prefix, print = console.log) {
20
- const data = msg.content?.data;
21
- const event = data?.event;
22
-
23
- let icon, eventText;
24
- switch (event) {
25
- case 'STARTED':
26
- icon = chalk.green('▶');
27
- const triggers = data.triggers?.join(', ') || 'none';
28
- eventText = `started (listening for: ${chalk.dim(triggers)})`;
29
- break;
30
- case 'TASK_STARTED':
31
- icon = chalk.yellow('⚡');
32
- eventText = `${chalk.cyan(data.triggeredBy)} → task #${data.iteration} (${chalk.dim(data.model)})`;
33
- break;
34
- case 'TASK_COMPLETED':
35
- icon = chalk.green('✓');
36
- eventText = `task #${data.iteration} completed`;
37
- break;
38
- default:
39
- icon = chalk.dim('•');
40
- eventText = event || 'unknown event';
41
- }
42
-
43
- print(`${prefix} ${icon} ${eventText}`);
44
- return true;
11
+ const { icon, eventText } = formatLifecycleEvent(msg.content?.data);
12
+ print(`${prefix} ${icon} ${eventText}`);
13
+ return true;
45
14
  }
46
-
47
- /**
48
- * Format AGENT_ERROR events
49
- * @param {Object} msg - Message object
50
- * @param {string} prefix - Formatted message prefix
51
- * @param {string} timestamp - Formatted timestamp
52
- * @param {Function} [print=console.log] - Print function for output
53
- * @returns {boolean} True if message was handled
54
- */
55
15
  function formatAgentError(msg, prefix, timestamp, print = console.log) {
56
- print('');
57
- print(chalk.bold.red(`${'─'.repeat(60)}`));
58
- print(`${prefix} ${chalk.gray(timestamp)} ${chalk.bold.red('Error: agent failed')}`);
59
-
60
- if (msg.content?.text) {
61
- print(`${prefix} ${chalk.red(msg.content.text)}`);
62
- }
63
-
64
- if (msg.content?.data?.stack) {
65
- const stackLines = msg.content.data.stack.split('\n').slice(0, 5);
66
- for (const line of stackLines) {
67
- if (line.trim()) print(`${prefix} ${chalk.dim(line)}`);
16
+ print('');
17
+ print(chalk.bold.red(`${'─'.repeat(60)}`));
18
+ print(`${prefix} ${chalk.gray(timestamp)} ${chalk.bold.red('Error: agent failed')}`);
19
+ if (msg.content?.text) {
20
+ print(`${prefix} ${chalk.red(msg.content.text)}`);
21
+ }
22
+ if (msg.content?.data?.stack) {
23
+ const stackLines = msg.content.data.stack.split('\n').slice(0, 5);
24
+ for (const line of stackLines) {
25
+ if (line.trim())
26
+ print(`${prefix} ${chalk.dim(line)}`);
27
+ }
68
28
  }
69
- }
70
-
71
- print(`${prefix} Next: inspect the agent logs and retry after fixing the cause.`);
72
- print(chalk.bold.red(`${'─'.repeat(60)}`));
73
- return true;
29
+ print(`${prefix} Next: inspect the agent logs and retry after fixing the cause.`);
30
+ print(chalk.bold.red(`${'─'.repeat(60)}`));
31
+ return true;
74
32
  }
75
-
76
- /**
77
- * Format ISSUE_OPENED events
78
- * @param {Object} msg - Message object
79
- * @param {string} prefix - Formatted message prefix
80
- * @param {string} timestamp - Formatted timestamp
81
- * @param {Set} shownNewTaskForCluster - Set tracking shown tasks
82
- * @param {Function} [print=console.log] - Print function for output
83
- * @returns {boolean} True if message was handled
84
- */
85
33
  function formatIssueOpened(msg, prefix, timestamp, shownNewTaskForCluster, print = console.log) {
86
- // Skip duplicate - conductor re-publishes after spawning agents
87
- if (shownNewTaskForCluster.has(msg.cluster_id)) {
88
- return true;
89
- }
90
- shownNewTaskForCluster.add(msg.cluster_id);
91
-
92
- print('');
93
- print(chalk.bold.blue(`${''.repeat(60)}`));
94
- print(`${prefix} ${chalk.gray(timestamp)} ${chalk.bold.blue('📋 New task')}`);
95
-
96
- if (msg.content?.text) {
97
- const lines = msg.content.text.split('\n').slice(0, 3);
98
- for (const line of lines) {
99
- if (line.trim() && line.trim() !== '# Manual Input') {
100
- print(`${prefix} ${chalk.white(line)}`);
101
- }
34
+ // Skip duplicate - conductor re-publishes after spawning agents
35
+ if (!shownNewTaskForCluster.has(msg.cluster_id)) {
36
+ shownNewTaskForCluster.add(msg.cluster_id);
37
+ print('');
38
+ print(chalk.bold.blue(`${'─'.repeat(60)}`));
39
+ print(`${prefix} ${chalk.gray(timestamp)} ${chalk.bold.blue('📋 New task')}`);
40
+ if (msg.content?.text) {
41
+ const lines = msg.content.text.split('\n').slice(0, 3);
42
+ for (const line of lines) {
43
+ if (line.trim() && line.trim() !== '# Manual Input') {
44
+ print(`${prefix} ${chalk.white(line)}`);
45
+ }
46
+ }
47
+ }
48
+ print(chalk.bold.blue(`${'─'.repeat(60)}`));
102
49
  }
103
- }
104
-
105
- print(chalk.bold.blue(`${'─'.repeat(60)}`));
106
- return true;
50
+ return true;
107
51
  }
108
-
109
- /**
110
- * Format IMPLEMENTATION_READY events
111
- * @param {Object} msg - Message object
112
- * @param {string} prefix - Formatted message prefix
113
- * @param {string} timestamp - Formatted timestamp
114
- * @param {Function} [print=console.log] - Print function for output
115
- * @returns {boolean} True if message was handled
116
- */
117
52
  function formatImplementationReady(msg, prefix, timestamp, print = console.log) {
118
- print(
119
- `${prefix} ${chalk.gray(timestamp)} ${chalk.bold.yellow(`✅ ${EVENT_COPY.IMPLEMENTATION_READY.toUpperCase()}`)}`
120
- );
121
-
122
- if (msg.content?.data?.commit) {
123
- print(
124
- `${prefix} ${chalk.gray('Commit:')} ${chalk.cyan(msg.content.data.commit.substring(0, 8))}`
125
- );
126
- }
127
-
128
- return true;
53
+ print(`${prefix} ${chalk.gray(timestamp)} ${chalk.bold.yellow(`✅ ${EVENT_COPY.IMPLEMENTATION_READY.toUpperCase()}`)}`);
54
+ if (msg.content?.data?.commit) {
55
+ print(`${prefix} ${chalk.gray('Commit:')} ${chalk.cyan(msg.content.data.commit.substring(0, 8))}`);
56
+ }
57
+ return true;
129
58
  }
130
-
131
- /**
132
- * Format VALIDATION_RESULT events
133
- * @param {Object} msg - Message object
134
- * @param {string} prefix - Formatted message prefix
135
- * @param {string} timestamp - Formatted timestamp
136
- * @param {Function} [print=console.log] - Print function for output
137
- * @returns {boolean} True if message was handled
138
- */
139
59
  function formatValidationResult(msg, prefix, timestamp, print = console.log) {
140
- const data = msg.content?.data || {};
141
- const approved = data.approved === true || data.approved === 'true';
142
- const status = approved ? chalk.bold.green('✓ Approved') : chalk.bold.red('✗ Rejected');
143
-
144
- print(`${prefix} ${chalk.gray(timestamp)} ${status}`);
145
-
146
- // Show summary if present and not a template variable
147
- if (msg.content?.text && !msg.content.text.includes('{{')) {
148
- print(`${prefix} ${msg.content.text.substring(0, 100)}`);
149
- }
150
-
151
- // Show CANNOT_VALIDATE (permanent) as warnings, CANNOT_VALIDATE_YET (temporary) as errors
152
- const criteriaResults = data.criteriaResults;
153
- if (Array.isArray(criteriaResults)) {
154
- // CANNOT_VALIDATE_YET = temporary, treated as FAIL (work incomplete)
155
- const cannotValidateYet = criteriaResults.filter((c) => c.status === 'CANNOT_VALIDATE_YET');
156
- if (cannotValidateYet.length > 0) {
157
- print(
158
- `${prefix} ${chalk.red('❌ Cannot validate yet')} (${cannotValidateYet.length} criteria - work incomplete):`
159
- );
160
- for (const cv of cannotValidateYet) {
161
- print(`${prefix} ${chalk.red('•')} ${cv.id}: ${cv.reason || 'No reason provided'}`);
162
- }
60
+ const data = msg.content?.data || {};
61
+ const approved = data.approved === true || data.approved === 'true';
62
+ const status = approved ? chalk.bold.green('✓ Approved') : chalk.bold.red('✗ Rejected');
63
+ print(`${prefix} ${chalk.gray(timestamp)} ${status}`);
64
+ // Show summary if present and not a template variable
65
+ if (msg.content?.text && !msg.content.text.includes('{{')) {
66
+ print(`${prefix} ${msg.content.text.substring(0, 100)}`);
163
67
  }
164
-
165
- // CANNOT_VALIDATE = permanent, treated as PASS (environmental limitation)
166
- const cannotValidate = criteriaResults.filter((c) => c.status === 'CANNOT_VALIDATE');
167
- if (cannotValidate.length > 0) {
168
- print(
169
- `${prefix} ${chalk.yellow('⚠️ Could not validate')} (${cannotValidate.length} criteria - permanent):`
170
- );
171
- for (const cv of cannotValidate) {
172
- print(`${prefix} ${chalk.yellow('•')} ${cv.id}: ${cv.reason || 'No reason provided'}`);
173
- }
68
+ // Show CANNOT_VALIDATE (permanent) as warnings, CANNOT_VALIDATE_YET (temporary) as errors
69
+ const criteriaResults = data.criteriaResults;
70
+ if (isCriterionResults(criteriaResults)) {
71
+ const { cannotValidateYet, cannotValidate } = partitionValidationCriteria(criteriaResults);
72
+ if (cannotValidateYet.length > 0) {
73
+ print(`${prefix} ${chalk.red(' Cannot validate yet')} (${cannotValidateYet.length} criteria - work incomplete):`);
74
+ for (const criterion of cannotValidateYet) {
75
+ print(`${prefix} ${chalk.red('•')} ${criterion.id}: ${criterion.reason || 'No reason provided'}`);
76
+ }
77
+ }
78
+ if (cannotValidate.length > 0) {
79
+ print(`${prefix} ${chalk.yellow('⚠️ Could not validate')} (${cannotValidate.length} criteria - permanent):`);
80
+ for (const criterion of cannotValidate) {
81
+ print(`${prefix} ${chalk.yellow('•')} ${criterion.id}: ${criterion.reason || 'No reason provided'}`);
82
+ }
83
+ }
174
84
  }
175
- }
176
-
177
- // Show full JSON data structure
178
- print(`${prefix} ${chalk.dim(JSON.stringify(data, null, 2).split('\n').join(`\n${prefix} `))}`);
179
-
180
- return true;
85
+ // Show full JSON data structure
86
+ print(`${prefix} ${chalk.dim(JSON.stringify(data, null, 2).split('\n').join(`\n${prefix} `))}`);
87
+ return true;
181
88
  }
182
-
183
- /**
184
- * Format CLUSTER_COMPLETE events
185
- * @param {Object} msg - Message object
186
- * @param {string} prefix - Formatted message prefix
187
- * @param {string} timestamp - Formatted timestamp
188
- * @param {Function} [print=console.log] - Print function for output
189
- * @returns {boolean} True if message was handled
190
- */
191
89
  function formatClusterComplete(msg, prefix, timestamp, print = console.log) {
192
- print('');
193
- print(chalk.bold.green(`${'═'.repeat(60)}`));
194
- print(`${prefix} ${chalk.gray(timestamp)} ${chalk.bold.green('🎉 Cluster complete')}`);
195
- if (msg.content?.data?.reason) {
196
- print(`${prefix} ${chalk.green(msg.content.data.reason)}`);
197
- }
198
- print(chalk.bold.green(`${'═'.repeat(60)}`));
199
- return true;
90
+ print('');
91
+ print(chalk.bold.green(`${'═'.repeat(60)}`));
92
+ print(`${prefix} ${chalk.gray(timestamp)} ${chalk.bold.green('🎉 Cluster complete')}`);
93
+ if (msg.content?.data?.reason) {
94
+ print(`${prefix} ${chalk.green(msg.content.data.reason)}`);
95
+ }
96
+ print(chalk.bold.green(`${'═'.repeat(60)}`));
97
+ return true;
200
98
  }
201
-
202
- /**
203
- * Format CLUSTER_FAILED events
204
- * @param {Object} msg - Message object
205
- * @param {string} prefix - Formatted message prefix
206
- * @param {string} timestamp - Formatted timestamp
207
- * @param {Function} [print=console.log] - Print function for output
208
- * @returns {boolean} True if message was handled
209
- */
210
99
  function formatClusterFailed(msg, prefix, timestamp, print = console.log) {
211
- print('');
212
- print(chalk.bold.red(`${'═'.repeat(60)}`));
213
- print(`${prefix} ${chalk.gray(timestamp)} ${chalk.bold.red('Error: cluster failed')}`);
214
- if (msg.content?.text) print(`${prefix} ${chalk.red(msg.content.text)}`);
215
- if (msg.content?.data?.reason) print(`${prefix} ${chalk.red(msg.content.data.reason)}`);
216
- print(`${prefix} Next: inspect the cluster logs, then resume after fixing the cause.`);
217
- print(chalk.bold.red(`${'═'.repeat(60)}`));
218
- return true;
100
+ print('');
101
+ print(chalk.bold.red(`${'═'.repeat(60)}`));
102
+ print(`${prefix} ${chalk.gray(timestamp)} ${chalk.bold.red('Error: cluster failed')}`);
103
+ if (msg.content?.text)
104
+ print(`${prefix} ${chalk.red(msg.content.text)}`);
105
+ if (msg.content?.data?.reason)
106
+ print(`${prefix} ${chalk.red(msg.content.data.reason)}`);
107
+ print(`${prefix} Next: inspect the cluster logs, then resume after fixing the cause.`);
108
+ print(chalk.bold.red(`${'═'.repeat(60)}`));
109
+ return true;
219
110
  }
220
-
221
- /**
222
- * Format PR_CREATED events
223
- * @param {Object} msg - Message object
224
- * @param {string} prefix - Formatted message prefix
225
- * @param {string} timestamp - Formatted timestamp
226
- * @param {Function} [print=console.log] - Print function for output
227
- * @returns {boolean} True if message was handled
228
- */
229
111
  function formatPrCreated(msg, prefix, timestamp, print = console.log) {
230
- const prNumber = msg.content?.data?.pr_number || '';
231
- const prUrl = msg.content?.data?.pr_url || '';
232
-
233
- print(''); // Blank line before PR notification
234
- print(chalk.bold.green(`${'─'.repeat(60)}`));
235
- print(
236
- `${prefix} ${chalk.gray(timestamp)} ${chalk.bold.green(`🎉 ${EVENT_COPY.PR_CREATED.toUpperCase()}`)}`
237
- );
238
-
239
- if (prNumber) {
240
- print(`${prefix} ${chalk.gray('PR:')} ${chalk.cyan(`#${prNumber}`)}`);
241
- }
242
- if (prUrl) {
243
- print(`${prefix} ${chalk.gray('URL:')} ${chalk.blue(prUrl)}`);
244
- }
245
-
246
- const mergeStatus = formatMergeStatus(msg.content?.data?.merged);
247
- if (mergeStatus) {
248
- print(
249
- `${prefix} ${chalk.gray('Merge:')} ${mergeStatus === 'merged' ? chalk.green(mergeStatus) : chalk.yellow(mergeStatus)}`
250
- );
251
- }
252
-
253
- print(chalk.bold.green(`${'─'.repeat(60)}`));
254
- return true;
112
+ const prNumber = msg.content?.data?.pr_number || '';
113
+ const prUrl = msg.content?.data?.pr_url || '';
114
+ print(''); // Blank line before PR notification
115
+ print(chalk.bold.green(`${''.repeat(60)}`));
116
+ print(`${prefix} ${chalk.gray(timestamp)} ${chalk.bold.green(`🎉 ${EVENT_COPY.PR_CREATED.toUpperCase()}`)}`);
117
+ if (prNumber) {
118
+ print(`${prefix} ${chalk.gray('PR:')} ${chalk.cyan(`#${prNumber}`)}`);
119
+ }
120
+ if (prUrl) {
121
+ print(`${prefix} ${chalk.gray('URL:')} ${chalk.blue(prUrl)}`);
122
+ }
123
+ const mergeStatus = formatMergeStatus(msg.content?.data?.merged);
124
+ if (mergeStatus) {
125
+ const formattedMergeStatus = mergeStatus === 'merged' ? chalk.green(mergeStatus) : chalk.yellow(mergeStatus);
126
+ print(`${prefix} ${chalk.gray('Merge:')} ${formattedMergeStatus}`);
127
+ }
128
+ print(chalk.bold.green(`${'─'.repeat(60)}`));
129
+ return true;
255
130
  }
256
-
257
- /**
258
- * Format generic messages (fallback)
259
- * @param {Object} msg - Message object
260
- * @param {string} prefix - Formatted message prefix
261
- * @param {string} timestamp - Formatted timestamp
262
- * @param {Function} [print=console.log] - Print function for output
263
- * @returns {boolean} True if message was handled
264
- */
265
131
  function formatGenericMessage(msg, prefix, timestamp, print = console.log) {
266
- print(`${prefix} ${chalk.gray(timestamp)} ${chalk.bold(msg.topic)}`);
267
- if (msg.content?.text) {
268
- print(`${prefix} ${msg.content.text}`);
269
- }
270
- return true;
132
+ print(`${prefix} ${chalk.gray(timestamp)} ${chalk.bold(msg.topic)}`);
133
+ if (msg.content?.text) {
134
+ print(`${prefix} ${msg.content.text}`);
135
+ }
136
+ return true;
271
137
  }
272
-
273
138
  module.exports = {
274
- formatAgentLifecycle,
275
- formatAgentError,
276
- formatIssueOpened,
277
- formatImplementationReady,
278
- formatValidationResult,
279
- formatPrCreated,
280
- formatClusterComplete,
281
- formatClusterFailed,
282
- formatGenericMessage,
139
+ formatAgentLifecycle,
140
+ formatAgentError,
141
+ formatIssueOpened,
142
+ formatImplementationReady,
143
+ formatValidationResult,
144
+ formatPrCreated,
145
+ formatClusterComplete,
146
+ formatClusterFailed,
147
+ formatGenericMessage,
283
148
  };
@@ -0,0 +1,250 @@
1
+ import chalk = require('chalk');
2
+ import eventCopy = require('./event-copy');
3
+ import formatterUtils = require('./message-formatter-utils');
4
+
5
+ const { EVENT_COPY, formatMergeStatus } = eventCopy;
6
+ const { formatLifecycleEvent, partitionValidationCriteria } = formatterUtils;
7
+
8
+ interface CriterionResult {
9
+ status?: string;
10
+ id?: string | number;
11
+ reason?: string;
12
+ }
13
+
14
+ interface NormalMessageData {
15
+ event?: string;
16
+ triggers?: readonly string[];
17
+ triggeredBy?: string | number;
18
+ iteration?: string | number;
19
+ model?: string;
20
+ stack?: string;
21
+ commit?: string;
22
+ approved?: boolean | string;
23
+ criteriaResults?: readonly CriterionResult[];
24
+ reason?: string;
25
+ pr_number?: string | number;
26
+ pr_url?: string;
27
+ merged?: unknown;
28
+ }
29
+
30
+ interface NormalMessage {
31
+ cluster_id?: string;
32
+ topic?: string;
33
+ content?: {
34
+ text?: string;
35
+ data?: NormalMessageData;
36
+ };
37
+ }
38
+
39
+ type PrintLine = (text: string) => void;
40
+
41
+ function isCriterionResults(value: unknown): value is readonly CriterionResult[] {
42
+ return Array.isArray(value);
43
+ }
44
+
45
+ function formatAgentLifecycle(
46
+ msg: NormalMessage,
47
+ prefix: string,
48
+ print: PrintLine = console.log
49
+ ): true {
50
+ const { icon, eventText } = formatLifecycleEvent(msg.content?.data);
51
+ print(`${prefix} ${icon} ${eventText}`);
52
+ return true;
53
+ }
54
+
55
+ function formatAgentError(
56
+ msg: NormalMessage,
57
+ prefix: string,
58
+ timestamp: string,
59
+ print: PrintLine = console.log
60
+ ): true {
61
+ print('');
62
+ print(chalk.bold.red(`${'─'.repeat(60)}`));
63
+ print(`${prefix} ${chalk.gray(timestamp)} ${chalk.bold.red('Error: agent failed')}`);
64
+ if (msg.content?.text) {
65
+ print(`${prefix} ${chalk.red(msg.content.text)}`);
66
+ }
67
+ if (msg.content?.data?.stack) {
68
+ const stackLines = msg.content.data.stack.split('\n').slice(0, 5);
69
+ for (const line of stackLines) {
70
+ if (line.trim()) print(`${prefix} ${chalk.dim(line)}`);
71
+ }
72
+ }
73
+ print(`${prefix} Next: inspect the agent logs and retry after fixing the cause.`);
74
+ print(chalk.bold.red(`${'─'.repeat(60)}`));
75
+ return true;
76
+ }
77
+
78
+ function formatIssueOpened(
79
+ msg: NormalMessage,
80
+ prefix: string,
81
+ timestamp: string,
82
+ shownNewTaskForCluster: Set<string | undefined>,
83
+ print: PrintLine = console.log
84
+ ): true {
85
+ // Skip duplicate - conductor re-publishes after spawning agents
86
+ if (!shownNewTaskForCluster.has(msg.cluster_id)) {
87
+ shownNewTaskForCluster.add(msg.cluster_id);
88
+ print('');
89
+ print(chalk.bold.blue(`${'─'.repeat(60)}`));
90
+ print(`${prefix} ${chalk.gray(timestamp)} ${chalk.bold.blue('📋 New task')}`);
91
+ if (msg.content?.text) {
92
+ const lines = msg.content.text.split('\n').slice(0, 3);
93
+ for (const line of lines) {
94
+ if (line.trim() && line.trim() !== '# Manual Input') {
95
+ print(`${prefix} ${chalk.white(line)}`);
96
+ }
97
+ }
98
+ }
99
+ print(chalk.bold.blue(`${'─'.repeat(60)}`));
100
+ }
101
+ return true;
102
+ }
103
+
104
+ function formatImplementationReady(
105
+ msg: NormalMessage,
106
+ prefix: string,
107
+ timestamp: string,
108
+ print: PrintLine = console.log
109
+ ): true {
110
+ print(
111
+ `${prefix} ${chalk.gray(timestamp)} ${chalk.bold.yellow(`✅ ${EVENT_COPY.IMPLEMENTATION_READY.toUpperCase()}`)}`
112
+ );
113
+ if (msg.content?.data?.commit) {
114
+ print(
115
+ `${prefix} ${chalk.gray('Commit:')} ${chalk.cyan(msg.content.data.commit.substring(0, 8))}`
116
+ );
117
+ }
118
+ return true;
119
+ }
120
+
121
+ function formatValidationResult(
122
+ msg: NormalMessage,
123
+ prefix: string,
124
+ timestamp: string,
125
+ print: PrintLine = console.log
126
+ ): true {
127
+ const data = msg.content?.data || {};
128
+ const approved = data.approved === true || data.approved === 'true';
129
+ const status = approved ? chalk.bold.green('✓ Approved') : chalk.bold.red('✗ Rejected');
130
+ print(`${prefix} ${chalk.gray(timestamp)} ${status}`);
131
+ // Show summary if present and not a template variable
132
+ if (msg.content?.text && !msg.content.text.includes('{{')) {
133
+ print(`${prefix} ${msg.content.text.substring(0, 100)}`);
134
+ }
135
+ // Show CANNOT_VALIDATE (permanent) as warnings, CANNOT_VALIDATE_YET (temporary) as errors
136
+ const criteriaResults = data.criteriaResults;
137
+ if (isCriterionResults(criteriaResults)) {
138
+ const { cannotValidateYet, cannotValidate } =
139
+ partitionValidationCriteria(criteriaResults);
140
+ if (cannotValidateYet.length > 0) {
141
+ print(
142
+ `${prefix} ${chalk.red('❌ Cannot validate yet')} (${cannotValidateYet.length} criteria - work incomplete):`
143
+ );
144
+ for (const criterion of cannotValidateYet) {
145
+ print(
146
+ `${prefix} ${chalk.red('•')} ${criterion.id}: ${criterion.reason || 'No reason provided'}`
147
+ );
148
+ }
149
+ }
150
+ if (cannotValidate.length > 0) {
151
+ print(
152
+ `${prefix} ${chalk.yellow('⚠️ Could not validate')} (${cannotValidate.length} criteria - permanent):`
153
+ );
154
+ for (const criterion of cannotValidate) {
155
+ print(
156
+ `${prefix} ${chalk.yellow('•')} ${criterion.id}: ${criterion.reason || 'No reason provided'}`
157
+ );
158
+ }
159
+ }
160
+ }
161
+ // Show full JSON data structure
162
+ print(`${prefix} ${chalk.dim(JSON.stringify(data, null, 2).split('\n').join(`\n${prefix} `))}`);
163
+ return true;
164
+ }
165
+
166
+ function formatClusterComplete(
167
+ msg: NormalMessage,
168
+ prefix: string,
169
+ timestamp: string,
170
+ print: PrintLine = console.log
171
+ ): true {
172
+ print('');
173
+ print(chalk.bold.green(`${'═'.repeat(60)}`));
174
+ print(`${prefix} ${chalk.gray(timestamp)} ${chalk.bold.green('🎉 Cluster complete')}`);
175
+ if (msg.content?.data?.reason) {
176
+ print(`${prefix} ${chalk.green(msg.content.data.reason)}`);
177
+ }
178
+ print(chalk.bold.green(`${'═'.repeat(60)}`));
179
+ return true;
180
+ }
181
+
182
+ function formatClusterFailed(
183
+ msg: NormalMessage,
184
+ prefix: string,
185
+ timestamp: string,
186
+ print: PrintLine = console.log
187
+ ): true {
188
+ print('');
189
+ print(chalk.bold.red(`${'═'.repeat(60)}`));
190
+ print(`${prefix} ${chalk.gray(timestamp)} ${chalk.bold.red('Error: cluster failed')}`);
191
+ if (msg.content?.text) print(`${prefix} ${chalk.red(msg.content.text)}`);
192
+ if (msg.content?.data?.reason) print(`${prefix} ${chalk.red(msg.content.data.reason)}`);
193
+ print(`${prefix} Next: inspect the cluster logs, then resume after fixing the cause.`);
194
+ print(chalk.bold.red(`${'═'.repeat(60)}`));
195
+ return true;
196
+ }
197
+
198
+ function formatPrCreated(
199
+ msg: NormalMessage,
200
+ prefix: string,
201
+ timestamp: string,
202
+ print: PrintLine = console.log
203
+ ): true {
204
+ const prNumber = msg.content?.data?.pr_number || '';
205
+ const prUrl = msg.content?.data?.pr_url || '';
206
+ print(''); // Blank line before PR notification
207
+ print(chalk.bold.green(`${'─'.repeat(60)}`));
208
+ print(
209
+ `${prefix} ${chalk.gray(timestamp)} ${chalk.bold.green(`🎉 ${EVENT_COPY.PR_CREATED.toUpperCase()}`)}`
210
+ );
211
+ if (prNumber) {
212
+ print(`${prefix} ${chalk.gray('PR:')} ${chalk.cyan(`#${prNumber}`)}`);
213
+ }
214
+ if (prUrl) {
215
+ print(`${prefix} ${chalk.gray('URL:')} ${chalk.blue(prUrl)}`);
216
+ }
217
+ const mergeStatus = formatMergeStatus(msg.content?.data?.merged);
218
+ if (mergeStatus) {
219
+ const formattedMergeStatus =
220
+ mergeStatus === 'merged' ? chalk.green(mergeStatus) : chalk.yellow(mergeStatus);
221
+ print(`${prefix} ${chalk.gray('Merge:')} ${formattedMergeStatus}`);
222
+ }
223
+ print(chalk.bold.green(`${'─'.repeat(60)}`));
224
+ return true;
225
+ }
226
+
227
+ function formatGenericMessage(
228
+ msg: NormalMessage,
229
+ prefix: string,
230
+ timestamp: string,
231
+ print: PrintLine = console.log
232
+ ): true {
233
+ print(`${prefix} ${chalk.gray(timestamp)} ${chalk.bold(msg.topic)}`);
234
+ if (msg.content?.text) {
235
+ print(`${prefix} ${msg.content.text}`);
236
+ }
237
+ return true;
238
+ }
239
+
240
+ export = {
241
+ formatAgentLifecycle,
242
+ formatAgentError,
243
+ formatIssueOpened,
244
+ formatImplementationReady,
245
+ formatValidationResult,
246
+ formatPrCreated,
247
+ formatClusterComplete,
248
+ formatClusterFailed,
249
+ formatGenericMessage,
250
+ };