@the-open-engine/zeroshot 6.38.1 → 6.39.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (383) hide show
  1. package/README.md +6 -0
  2. package/cli/event-copy.js +8 -7
  3. package/cli/event-copy.ts +12 -0
  4. package/cli/index.js +67 -48
  5. package/cli/json-export.js +61 -64
  6. package/cli/json-export.ts +112 -0
  7. package/cli/message-formatter-utils.js +68 -56
  8. package/cli/message-formatter-utils.ts +121 -0
  9. package/cli/message-formatters-normal.js +124 -259
  10. package/cli/message-formatters-normal.ts +250 -0
  11. package/cli/message-formatters-watch.js +81 -84
  12. package/cli/message-formatters-watch.ts +189 -0
  13. package/lib/cluster/generated/protocol-schema.cjs +1 -1
  14. package/lib/cluster/generated/protocol-schema.mjs +1 -1
  15. package/lib/cluster/generated/protocol.d.cts +8 -0
  16. package/lib/cluster/generated/protocol.d.mts +8 -0
  17. package/lib/cluster/generated/protocol.d.ts +8 -0
  18. package/lib/clusters-registry.d.ts +23 -0
  19. package/lib/clusters-registry.js +17 -29
  20. package/lib/completion.d.ts +12 -0
  21. package/lib/completion.js +84 -94
  22. package/lib/compose-utils.d.ts +32 -0
  23. package/lib/compose-utils.js +57 -72
  24. package/lib/detached-startup.d.ts +84 -0
  25. package/lib/detached-startup.js +232 -302
  26. package/lib/docker-config.d.ts +43 -0
  27. package/lib/docker-config.js +150 -325
  28. package/lib/docker-env-auth.d.ts +17 -0
  29. package/lib/docker-env-auth.js +75 -0
  30. package/lib/git-remote-utils.d.ts +48 -0
  31. package/lib/git-remote-utils.js +147 -213
  32. package/lib/id-detector.d.ts +15 -0
  33. package/lib/id-detector.js +37 -41
  34. package/lib/path-check.d.ts +30 -0
  35. package/lib/path-check.js +42 -45
  36. package/lib/process-liveness.d.ts +16 -0
  37. package/lib/process-liveness.js +19 -12
  38. package/lib/provider-credential-path.d.ts +16 -0
  39. package/lib/provider-credential-path.js +31 -29
  40. package/lib/provider-defaults.d.ts +30 -0
  41. package/lib/provider-defaults.js +47 -42
  42. package/lib/provider-detection.d.ts +11 -0
  43. package/lib/provider-detection.js +91 -54
  44. package/lib/provider-names.d.ts +38 -0
  45. package/lib/provider-names.js +56 -64
  46. package/lib/repo-settings.d.ts +28 -0
  47. package/lib/repo-settings.js +83 -59
  48. package/lib/run-mode.d.ts +21 -0
  49. package/lib/run-mode.js +21 -20
  50. package/lib/run-plan.d.ts +28 -0
  51. package/lib/run-plan.js +17 -16
  52. package/lib/settings/claude-auth.d.ts +35 -0
  53. package/lib/settings/claude-auth.js +30 -47
  54. package/lib/settings-defaults.d.ts +20 -0
  55. package/lib/settings-defaults.js +149 -0
  56. package/lib/settings-error.d.ts +7 -0
  57. package/lib/settings-error.js +8 -0
  58. package/lib/settings-issue-providers.d.ts +10 -0
  59. package/lib/settings-issue-providers.js +12 -0
  60. package/lib/settings-models.d.ts +22 -0
  61. package/lib/settings-models.js +93 -0
  62. package/lib/settings-storage.d.ts +23 -0
  63. package/lib/settings-storage.js +205 -0
  64. package/lib/settings-validation.d.ts +7 -0
  65. package/lib/settings-validation.js +182 -0
  66. package/lib/settings.d.ts +29 -0
  67. package/lib/settings.js +41 -736
  68. package/lib/setup-apply-types.d.ts +66 -0
  69. package/lib/setup-apply-types.js +2 -0
  70. package/lib/setup-apply.d.ts +39 -0
  71. package/lib/setup-apply.js +267 -264
  72. package/lib/setup-journal.d.ts +41 -0
  73. package/lib/setup-journal.js +119 -76
  74. package/lib/setup-plan-types.d.ts +102 -0
  75. package/lib/setup-plan-types.js +2 -0
  76. package/lib/setup-plan.d.ts +30 -0
  77. package/lib/setup-plan.js +300 -324
  78. package/lib/setup-undo.d.ts +44 -0
  79. package/lib/setup-undo.js +61 -74
  80. package/lib/start-cluster-config.d.ts +26 -0
  81. package/lib/start-cluster-config.js +56 -0
  82. package/lib/start-cluster-environment.d.ts +41 -0
  83. package/lib/start-cluster-environment.js +134 -0
  84. package/lib/start-cluster-run-options.d.ts +54 -0
  85. package/lib/start-cluster-run-options.js +148 -0
  86. package/lib/start-cluster.d.ts +64 -0
  87. package/lib/start-cluster.js +98 -454
  88. package/lib/stream-json-parser.d.ts +17 -0
  89. package/lib/stream-json-parser.js +51 -52
  90. package/npm-shrinkwrap.json +6 -8
  91. package/package.json +14 -8
  92. package/scripts/postinstall.js +27 -0
  93. package/scripts/rust-distribution.js +36 -45
  94. package/src/agent/agent-command-proofs-context.js +35 -45
  95. package/src/agent/agent-command-proofs-context.ts +87 -0
  96. package/src/agent/agent-config-settings.js +19 -0
  97. package/src/agent/agent-config-settings.ts +41 -0
  98. package/src/agent/agent-config.js +122 -231
  99. package/src/agent/agent-config.ts +285 -0
  100. package/src/agent/agent-context-builder.js +38 -273
  101. package/src/agent/agent-context-builder.ts +51 -0
  102. package/src/agent/agent-context-environment-sections.js +105 -0
  103. package/src/agent/agent-context-environment-sections.ts +134 -0
  104. package/src/agent/agent-context-packs.js +165 -0
  105. package/src/agent/agent-context-packs.ts +296 -0
  106. package/src/agent/agent-context-prompt-sections.js +100 -0
  107. package/src/agent/agent-context-prompt-sections.ts +148 -0
  108. package/src/agent/agent-context-sections.js +25 -334
  109. package/src/agent/agent-context-sections.ts +36 -0
  110. package/src/agent/agent-context-sources.js +96 -149
  111. package/src/agent/agent-context-sources.ts +253 -0
  112. package/src/agent/agent-context-types.js +2 -0
  113. package/src/agent/agent-context-types.ts +132 -0
  114. package/src/agent/agent-context-validation-sections.js +73 -0
  115. package/src/agent/agent-context-validation-sections.ts +129 -0
  116. package/src/agent/agent-input-injector.js +99 -118
  117. package/src/agent/agent-input-injector.ts +195 -0
  118. package/src/agent/agent-liveness-poll.js +74 -78
  119. package/src/agent/agent-liveness-poll.ts +163 -0
  120. package/src/agent/agent-quality-gate-schema.js +77 -86
  121. package/src/agent/agent-quality-gate-schema.ts +135 -0
  122. package/src/agent/agent-quality-gates-context.js +44 -50
  123. package/src/agent/agent-quality-gates-context.ts +91 -0
  124. package/src/agent/agent-stuck-detector.js +171 -239
  125. package/src/agent/agent-stuck-detector.ts +288 -0
  126. package/src/agent/agent-trigger-evaluator.js +29 -46
  127. package/src/agent/agent-trigger-evaluator.ts +98 -0
  128. package/src/agent/context-metrics.js +110 -141
  129. package/src/agent/context-metrics.ts +261 -0
  130. package/src/agent/context-pack-builder.js +72 -358
  131. package/src/agent/context-pack-builder.ts +105 -0
  132. package/src/agent/context-pack-core.js +70 -0
  133. package/src/agent/context-pack-core.ts +96 -0
  134. package/src/agent/context-pack-selection.js +119 -0
  135. package/src/agent/context-pack-selection.ts +187 -0
  136. package/src/agent/context-pack-truncation.js +139 -0
  137. package/src/agent/context-pack-truncation.ts +208 -0
  138. package/src/agent/context-pack-types.js +2 -0
  139. package/src/agent/context-pack-types.ts +98 -0
  140. package/src/agent/context-replay-policy.js +30 -39
  141. package/src/agent/context-replay-policy.ts +71 -0
  142. package/src/agent/critical-agent-policy.js +6 -10
  143. package/src/agent/critical-agent-policy.ts +20 -0
  144. package/src/agent/guidance-queue.js +74 -87
  145. package/src/agent/guidance-queue.ts +166 -0
  146. package/src/agent/output-extraction-error-detail.js +45 -0
  147. package/src/agent/output-extraction-error-detail.ts +49 -0
  148. package/src/agent/output-extraction-failures.js +125 -0
  149. package/src/agent/output-extraction-failures.ts +149 -0
  150. package/src/agent/output-extraction-json.js +234 -0
  151. package/src/agent/output-extraction-json.ts +235 -0
  152. package/src/agent/output-extraction-pi.js +124 -0
  153. package/src/agent/output-extraction-pi.ts +137 -0
  154. package/src/agent/output-extraction-types.js +2 -0
  155. package/src/agent/output-extraction-types.ts +49 -0
  156. package/src/agent/output-extraction.js +17 -617
  157. package/src/agent/output-extraction.ts +30 -0
  158. package/src/agent/output-reformatter-errors.js +83 -0
  159. package/src/agent/output-reformatter-errors.ts +106 -0
  160. package/src/agent/output-reformatter-types.js +2 -0
  161. package/src/agent/output-reformatter-types.ts +86 -0
  162. package/src/agent/output-reformatter.js +140 -185
  163. package/src/agent/output-reformatter.ts +238 -0
  164. package/src/agent/pi-terminal-lifecycle-types.js +2 -0
  165. package/src/agent/pi-terminal-lifecycle-types.ts +41 -0
  166. package/src/agent/pi-terminal-lifecycle.js +186 -206
  167. package/src/agent/pi-terminal-lifecycle.ts +297 -0
  168. package/src/agent/provider-control-plane.js +22 -21
  169. package/src/agent/provider-control-plane.ts +52 -0
  170. package/src/agent/provider-terminal-failure-types.js +2 -0
  171. package/src/agent/provider-terminal-failure-types.ts +60 -0
  172. package/src/agent/provider-terminal-failure.js +194 -191
  173. package/src/agent/provider-terminal-failure.ts +262 -0
  174. package/src/agent/rate-limit-backoff.js +31 -74
  175. package/src/agent/rate-limit-backoff.ts +71 -0
  176. package/src/agent/schema-utils.js +85 -125
  177. package/src/agent/schema-utils.ts +148 -0
  178. package/src/agent/structured-output-error.js +34 -33
  179. package/src/agent/structured-output-error.ts +105 -0
  180. package/src/agent/validation-platform.js +27 -27
  181. package/src/agent/validation-platform.ts +49 -0
  182. package/src/agents/git-pusher-template.js +17 -34
  183. package/src/attach/attach-client.js +232 -405
  184. package/src/attach/attach-client.ts +300 -0
  185. package/src/attach/attach-server-cleanup.js +43 -0
  186. package/src/attach/attach-server-cleanup.ts +39 -0
  187. package/src/attach/attach-server-clients.js +117 -0
  188. package/src/attach/attach-server-clients.ts +122 -0
  189. package/src/attach/attach-server-events.js +38 -0
  190. package/src/attach/attach-server-events.ts +36 -0
  191. package/src/attach/attach-server-pty.js +45 -0
  192. package/src/attach/attach-server-pty.ts +64 -0
  193. package/src/attach/attach-server-runtime.js +73 -0
  194. package/src/attach/attach-server-runtime.ts +62 -0
  195. package/src/attach/attach-server-socket.js +28 -0
  196. package/src/attach/attach-server-socket.ts +23 -0
  197. package/src/attach/attach-server-types.js +2 -0
  198. package/src/attach/attach-server-types.ts +82 -0
  199. package/src/attach/attach-server.js +106 -523
  200. package/src/attach/attach-server.ts +158 -0
  201. package/src/attach/index.js +18 -35
  202. package/src/attach/index.ts +18 -0
  203. package/src/attach/protocol.js +95 -184
  204. package/src/attach/protocol.ts +181 -0
  205. package/src/attach/ring-buffer.js +76 -102
  206. package/src/attach/ring-buffer.ts +109 -0
  207. package/src/attach/send-input.js +64 -75
  208. package/src/attach/send-input.ts +94 -0
  209. package/src/attach/socket-discovery.js +164 -218
  210. package/src/attach/socket-discovery.ts +230 -0
  211. package/src/attach/socket-paths.js +42 -61
  212. package/src/attach/socket-paths.ts +81 -0
  213. package/src/claude-credentials.js +51 -54
  214. package/src/claude-credentials.ts +89 -0
  215. package/src/cluster/generated/protocol-schema.ts +1 -1
  216. package/src/cluster/generated/protocol.ts +2 -1
  217. package/src/command-proofs.js +110 -141
  218. package/src/command-proofs.ts +216 -0
  219. package/src/config-router.js +81 -73
  220. package/src/config-router.ts +131 -0
  221. package/src/copy-containment.js +191 -0
  222. package/src/copy-containment.ts +259 -0
  223. package/src/copy-worker.js +53 -30
  224. package/src/copy-worker.ts +88 -0
  225. package/src/darwin-keychain-boundary.js +80 -111
  226. package/src/darwin-keychain-boundary.ts +148 -0
  227. package/src/guidance-topics.js +4 -5
  228. package/src/guidance-topics.ts +10 -0
  229. package/src/input-helpers.js +33 -54
  230. package/src/input-helpers.ts +58 -0
  231. package/src/isolation-manager.js +59 -20
  232. package/src/ledger-sequence.js +45 -48
  233. package/src/ledger-sequence.ts +63 -0
  234. package/src/legacy-lib/clusters-registry.ts +40 -0
  235. package/src/legacy-lib/completion.ts +148 -0
  236. package/src/legacy-lib/compose-utils.ts +102 -0
  237. package/src/legacy-lib/detached-startup.ts +451 -0
  238. package/src/legacy-lib/docker-config.ts +282 -0
  239. package/src/legacy-lib/docker-env-auth.ts +116 -0
  240. package/src/legacy-lib/git-remote-utils.ts +244 -0
  241. package/src/legacy-lib/id-detector.ts +57 -0
  242. package/src/legacy-lib/js-yaml.d.ts +3 -0
  243. package/src/legacy-lib/omelette.d.ts +15 -0
  244. package/src/legacy-lib/path-check.ts +89 -0
  245. package/src/legacy-lib/process-liveness.ts +36 -0
  246. package/src/legacy-lib/provider-credential-path.ts +57 -0
  247. package/src/legacy-lib/provider-defaults.ts +114 -0
  248. package/src/legacy-lib/provider-detection.ts +67 -0
  249. package/src/legacy-lib/provider-names.ts +126 -0
  250. package/src/legacy-lib/repo-settings.ts +88 -0
  251. package/src/legacy-lib/run-mode.ts +58 -0
  252. package/src/legacy-lib/run-plan.ts +49 -0
  253. package/src/legacy-lib/settings/claude-auth.ts +80 -0
  254. package/src/legacy-lib/settings-defaults.ts +212 -0
  255. package/src/legacy-lib/settings-error.ts +8 -0
  256. package/src/legacy-lib/settings-issue-providers.ts +18 -0
  257. package/src/legacy-lib/settings-models.ts +124 -0
  258. package/src/legacy-lib/settings-storage.ts +277 -0
  259. package/src/legacy-lib/settings-validation.ts +220 -0
  260. package/src/legacy-lib/settings.ts +87 -0
  261. package/src/legacy-lib/setup-apply-types.ts +70 -0
  262. package/src/legacy-lib/setup-apply.ts +456 -0
  263. package/src/legacy-lib/setup-journal.ts +185 -0
  264. package/src/legacy-lib/setup-plan-types.ts +96 -0
  265. package/src/legacy-lib/setup-plan.ts +500 -0
  266. package/src/legacy-lib/setup-undo.ts +142 -0
  267. package/src/legacy-lib/start-cluster-config.ts +124 -0
  268. package/src/legacy-lib/start-cluster-environment.ts +166 -0
  269. package/src/legacy-lib/start-cluster-run-options.ts +281 -0
  270. package/src/legacy-lib/start-cluster.ts +237 -0
  271. package/src/legacy-lib/stream-json-parser.ts +88 -0
  272. package/src/message-buffer.js +55 -71
  273. package/src/message-buffer.ts +107 -0
  274. package/src/message-bus-bridge.js +92 -133
  275. package/src/message-bus-bridge.ts +149 -0
  276. package/src/name-generator-shared.js +220 -0
  277. package/src/name-generator-shared.ts +231 -0
  278. package/src/name-generator.js +8 -217
  279. package/src/name-generator.ts +27 -0
  280. package/src/omp-blob-root.js +83 -64
  281. package/src/omp-blob-root.ts +116 -0
  282. package/src/omp-config-overlay.js +65 -38
  283. package/src/omp-config-overlay.ts +110 -0
  284. package/src/omp-execution-fingerprint.js +38 -43
  285. package/src/omp-execution-fingerprint.ts +92 -0
  286. package/src/omp-session-limits.js +10 -15
  287. package/src/omp-session-limits.ts +53 -0
  288. package/src/omp-session-partition.js +2 -2
  289. package/src/omp-session-verifier.js +1 -1
  290. package/src/orchestrator.js +32 -7
  291. package/src/pr-body-template.js +71 -0
  292. package/src/providers/anthropic/index.js +3 -1
  293. package/src/providers/anthropic/index.ts +13 -0
  294. package/src/providers/capabilities.js +19 -27
  295. package/src/providers/capabilities.ts +44 -0
  296. package/src/providers/google/index.js +3 -1
  297. package/src/providers/google/index.ts +13 -0
  298. package/src/providers/openai/index.js +3 -1
  299. package/src/providers/openai/index.ts +13 -0
  300. package/src/providers/opencode/index.js +3 -1
  301. package/src/providers/opencode/index.ts +13 -0
  302. package/src/quality-gates.js +67 -127
  303. package/src/quality-gates.ts +149 -0
  304. package/src/repo-settings-access.js +40 -0
  305. package/src/repo-settings-access.ts +64 -0
  306. package/src/schemas/sub-cluster.js +127 -183
  307. package/src/schemas/sub-cluster.ts +238 -0
  308. package/src/state-snapshot-normalization.js +224 -0
  309. package/src/state-snapshot-normalization.ts +222 -0
  310. package/src/state-snapshot.js +192 -359
  311. package/src/state-snapshot.ts +291 -0
  312. package/src/state-snapshotter.js +118 -130
  313. package/src/state-snapshotter.ts +167 -0
  314. package/src/sub-cluster-wrapper.js +4 -13
  315. package/src/task-run-model-args.js +87 -124
  316. package/src/task-run-model-args.ts +204 -0
  317. package/src/task-runner.js +5 -25
  318. package/src/task-runner.ts +28 -0
  319. package/src/task-startup-error.js +73 -58
  320. package/src/task-startup-error.ts +126 -0
  321. package/src/template-validation/consensus-gate-contracts.js +2 -0
  322. package/src/template-validation/consensus-gate-contracts.ts +70 -0
  323. package/src/template-validation/consensus-gate-scenarios.js +76 -0
  324. package/src/template-validation/consensus-gate-scenarios.ts +130 -0
  325. package/src/template-validation/consensus-gate-stage.js +34 -0
  326. package/src/template-validation/consensus-gate-stage.ts +56 -0
  327. package/src/template-validation/random-topology-contracts.js +2 -0
  328. package/src/template-validation/random-topology-contracts.ts +54 -0
  329. package/src/template-validation/random-topology-dispatch.js +25 -0
  330. package/src/template-validation/random-topology-dispatch.ts +33 -0
  331. package/src/template-validation/random-topology-message-loop.js +53 -0
  332. package/src/template-validation/random-topology-message-loop.ts +73 -0
  333. package/src/template-validation/random-topology-operations.js +79 -0
  334. package/src/template-validation/random-topology-operations.ts +101 -0
  335. package/src/template-validation/random-topology-runtime.js +25 -0
  336. package/src/template-validation/random-topology-runtime.ts +43 -0
  337. package/src/template-validation/random-topology-scenario.js +52 -0
  338. package/src/template-validation/random-topology-scenario.ts +57 -0
  339. package/src/template-validation/random-topology-schema.js +159 -0
  340. package/src/template-validation/random-topology-schema.ts +190 -0
  341. package/src/template-validation/random-topology-state.js +28 -0
  342. package/src/template-validation/random-topology-state.ts +30 -0
  343. package/src/template-validation/random-topology-trigger-evaluation.js +45 -0
  344. package/src/template-validation/random-topology-trigger-evaluation.ts +65 -0
  345. package/src/template-validation/random-topology-trigger.js +75 -0
  346. package/src/template-validation/random-topology-trigger.ts +88 -0
  347. package/src/template-validation/report-formatter.js +40 -46
  348. package/src/template-validation/report-formatter.ts +101 -0
  349. package/src/template-validation/simulate-consensus-gates.js +111 -302
  350. package/src/template-validation/simulate-consensus-gates.ts +196 -0
  351. package/src/template-validation/simulate-random-topology.js +26 -519
  352. package/src/template-validation/simulate-random-topology.ts +57 -0
  353. package/src/template-validation/simulate-two-stage-validation.js +41 -265
  354. package/src/template-validation/simulate-two-stage-validation.ts +55 -0
  355. package/src/template-validation/simulation-agent-runtime.js +25 -0
  356. package/src/template-validation/simulation-agent-runtime.ts +40 -0
  357. package/src/template-validation/simulation-agent.js +29 -0
  358. package/src/template-validation/simulation-agent.ts +73 -0
  359. package/src/template-validation/simulation-runtime.js +34 -0
  360. package/src/template-validation/simulation-runtime.ts +72 -0
  361. package/src/template-validation/two-stage-contracts.js +2 -0
  362. package/src/template-validation/two-stage-contracts.ts +41 -0
  363. package/src/template-validation/two-stage-inputs.js +21 -0
  364. package/src/template-validation/two-stage-inputs.ts +29 -0
  365. package/src/template-validation/two-stage-results.js +30 -0
  366. package/src/template-validation/two-stage-results.ts +40 -0
  367. package/src/template-validation/two-stage-scenario.js +86 -0
  368. package/src/template-validation/two-stage-scenario.ts +120 -0
  369. package/src/worktree-claude-config.js +182 -220
  370. package/src/worktree-claude-config.ts +272 -0
  371. package/src/worktree-tooling-env.js +103 -125
  372. package/src/worktree-tooling-env.ts +142 -0
  373. package/task-lib/completion.js +2 -3
  374. package/task-lib/completion.ts +9 -0
  375. package/task-lib/config.js +1 -4
  376. package/task-lib/config.ts +11 -0
  377. package/task-lib/name-generator.js +4 -226
  378. package/task-lib/name-generator.ts +11 -0
  379. package/task-lib/omp-session-cleanup.js +1 -1
  380. package/task-lib/omp-storage-root.js +8 -12
  381. package/task-lib/omp-storage-root.ts +62 -0
  382. package/task-lib/process-termination.js +143 -166
  383. package/task-lib/process-termination.ts +268 -0
@@ -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
+ };
@@ -1,104 +1,101 @@
1
- const chalk = require('chalk');
2
- const {
3
- buildClusterPrefix,
4
- getColorForSender,
5
- parseDataField,
6
- } = require('./message-formatter-utils');
7
- const { EVENT_COPY, formatMergeStatus } = require('./event-copy');
8
-
9
- const DEFAULT_WRITER = Object.freeze({ printLine: (text) => console.log(text) });
10
-
1
+ "use strict";
2
+ const chalk = require("chalk");
3
+ const formatterUtils = require("./message-formatter-utils");
4
+ const eventCopy = require("./event-copy");
5
+ const { buildClusterPrefix, getColorForSender, parseDataField } = formatterUtils;
6
+ const { EVENT_COPY, formatMergeStatus } = eventCopy;
7
+ const DEFAULT_WRITER = Object.freeze({
8
+ printLine: (text) => console.log(text),
9
+ });
10
+ function isCountableData(value) {
11
+ if (typeof value === 'string')
12
+ return true;
13
+ return (typeof value === 'object' &&
14
+ value !== null &&
15
+ 'length' in value &&
16
+ typeof value.length === 'number');
17
+ }
11
18
  function formatAgentError(msg, clusterPrefix, writer) {
12
- writer.printLine(`${clusterPrefix} ${chalk.bold.red(`Error: ${msg.sender}`)}`);
13
- if (msg.content?.text) {
14
- writer.printLine(`${clusterPrefix} ${chalk.red(msg.content.text)}`);
15
- }
16
- writer.printLine(`${clusterPrefix} Next: zeroshot logs ${msg.cluster_id} -f`);
19
+ writer.printLine(`${clusterPrefix} ${chalk.bold.red(`Error: ${msg.sender}`)}`);
20
+ if (msg.content?.text) {
21
+ writer.printLine(`${clusterPrefix} ${chalk.red(msg.content.text)}`);
22
+ }
23
+ writer.printLine(`${clusterPrefix} Next: zeroshot logs ${msg.cluster_id} -f`);
17
24
  }
18
-
19
25
  function formatIssueOpened(msg, clusterPrefix, writer) {
20
- const issueNum = msg.content?.data?.issue_number || '';
21
- const title = msg.content?.data?.title || '';
22
- const prompt = msg.content?.data?.prompt || msg.content?.text || '';
23
- const taskDesc = title === 'Manual Input' && prompt ? prompt : title;
24
- const truncatedDesc =
25
- taskDesc && taskDesc.length > 60 ? `${taskDesc.substring(0, 60)}...` : taskDesc;
26
- const eventText = `Started ${issueNum ? `#${issueNum}` : 'task'}${truncatedDesc ? chalk.dim(` - ${truncatedDesc}`) : ''}`;
27
- writer.printLine(`${clusterPrefix} ${eventText}`);
26
+ const issueNum = msg.content?.data?.issue_number || '';
27
+ const title = msg.content?.data?.title || '';
28
+ const prompt = msg.content?.data?.prompt || msg.content?.text || '';
29
+ const taskDesc = title === 'Manual Input' && prompt ? prompt : title;
30
+ const truncatedDesc = taskDesc && taskDesc.length > 60 ? `${taskDesc.substring(0, 60)}...` : taskDesc;
31
+ const issueLabel = issueNum ? `#${issueNum}` : 'task';
32
+ const description = truncatedDesc ? chalk.dim(` - ${truncatedDesc}`) : '';
33
+ const eventText = `Started ${issueLabel}${description}`;
34
+ writer.printLine(`${clusterPrefix} ${eventText}`);
28
35
  }
29
-
30
36
  function formatImplementationReady(msg, clusterPrefix, writer = DEFAULT_WRITER) {
31
- const agentName = getColorForSender(msg.sender)(msg.sender);
32
- writer.printLine(
33
- `${clusterPrefix} ${agentName} ${EVENT_COPY.IMPLEMENTATION_READY.toLowerCase()}`
34
- );
37
+ const agentName = getColorForSender(msg.sender)(msg.sender);
38
+ writer.printLine(`${clusterPrefix} ${agentName} ${EVENT_COPY.IMPLEMENTATION_READY.toLowerCase()}`);
35
39
  }
36
-
37
40
  function printRejectionDetails(data, clusterPrefix, writer) {
38
- const errors = parseDataField(data.errors);
39
- const issues = parseDataField(data.issues);
40
- if (errors.length > 0) {
41
- const count = JSON.stringify(errors).length;
42
- writer.printLine(
43
- `${clusterPrefix} ${chalk.red('•')} ${errors.length} error${errors.length > 1 ? 's' : ''} (${count} chars)`
44
- );
45
- }
46
- if (issues.length > 0) {
47
- const count = JSON.stringify(issues).length;
48
- writer.printLine(
49
- `${clusterPrefix} ${chalk.yellow('•')} ${issues.length} issue${issues.length > 1 ? 's' : ''} (${count} chars)`
50
- );
51
- }
41
+ const errors = parseDataField(data.errors);
42
+ const issues = parseDataField(data.issues);
43
+ if (isCountableData(errors) && errors.length > 0) {
44
+ const count = JSON.stringify(errors).length;
45
+ writer.printLine(`${clusterPrefix} ${chalk.red('•')} ${errors.length} error${errors.length > 1 ? 's' : ''} (${count} chars)`);
46
+ }
47
+ if (isCountableData(issues) && issues.length > 0) {
48
+ const count = JSON.stringify(issues).length;
49
+ writer.printLine(`${clusterPrefix} ${chalk.yellow('•')} ${issues.length} issue${issues.length > 1 ? 's' : ''} (${count} chars)`);
50
+ }
52
51
  }
53
-
54
52
  function formatValidationResult(msg, clusterPrefix, writer) {
55
- const agentName = getColorForSender(msg.sender)(msg.sender);
56
- const data = msg.content?.data;
57
- const approved = data?.approved === 'true' || data?.approved === true;
58
- const status = approved ? chalk.green('Approved') : chalk.red('Rejected');
59
- let eventText = `${agentName} ${status}`;
60
- if (data?.summary && !approved) eventText += chalk.dim(` - ${data.summary}`);
61
- writer.printLine(`${clusterPrefix} ${eventText}`);
62
- if (!approved) printRejectionDetails(data, clusterPrefix, writer);
53
+ const agentName = getColorForSender(msg.sender)(msg.sender);
54
+ const data = msg.content?.data;
55
+ const approved = data?.approved === 'true' || data?.approved === true;
56
+ const status = approved ? chalk.green('Approved') : chalk.red('Rejected');
57
+ let eventText = `${agentName} ${status}`;
58
+ if (data?.summary && !approved)
59
+ eventText += chalk.dim(` - ${data.summary}`);
60
+ writer.printLine(`${clusterPrefix} ${eventText}`);
61
+ if (!approved && data)
62
+ printRejectionDetails(data, clusterPrefix, writer);
63
63
  }
64
-
65
64
  function formatPrCreated(msg, clusterPrefix, writer = DEFAULT_WRITER) {
66
- const agentName = getColorForSender(msg.sender)(msg.sender);
67
- const prNum = msg.content?.data?.pr_number || '';
68
- let eventText = `${agentName} ${EVENT_COPY.PR_CREATED.toLowerCase()}${prNum ? ` #${prNum}` : ''}`;
69
- const mergeStatus = formatMergeStatus(msg.content?.data?.merged);
70
- if (mergeStatus) eventText += chalk.dim(` — ${mergeStatus}`);
71
- writer.printLine(`${clusterPrefix} ${eventText}`);
65
+ const agentName = getColorForSender(msg.sender)(msg.sender);
66
+ const prNum = msg.content?.data?.pr_number || '';
67
+ let eventText = `${agentName} ${EVENT_COPY.PR_CREATED.toLowerCase()}${prNum ? ` #${prNum}` : ''}`;
68
+ const mergeStatus = formatMergeStatus(msg.content?.data?.merged);
69
+ if (mergeStatus)
70
+ eventText += chalk.dim(` ${mergeStatus}`);
71
+ writer.printLine(`${clusterPrefix} ${eventText}`);
72
72
  }
73
-
74
73
  function formatPrMerged(msg, clusterPrefix, writer) {
75
- const agentName = getColorForSender(msg.sender)(msg.sender);
76
- writer.printLine(`${clusterPrefix} ${agentName} merged PR`);
74
+ const agentName = getColorForSender(msg.sender)(msg.sender);
75
+ writer.printLine(`${clusterPrefix} ${agentName} merged PR`);
77
76
  }
78
-
79
77
  function formatUnknownTopic(msg, clusterPrefix, writer) {
80
- const agentName = getColorForSender(msg.sender)(msg.sender);
81
- const eventText = `${agentName} ${msg.topic.toLowerCase().replace(/_/g, ' ')}`;
82
- writer.printLine(`${clusterPrefix} ${eventText}`);
78
+ const agentName = getColorForSender(msg.sender)(msg.sender);
79
+ const eventText = `${agentName} ${msg.topic.toLowerCase().replace(/_/g, ' ')}`;
80
+ writer.printLine(`${clusterPrefix} ${eventText}`);
83
81
  }
84
-
85
82
  function formatWatchMode(msg, isActive, writer = DEFAULT_WRITER) {
86
- if (msg.topic === 'AGENT_OUTPUT' || msg.topic === 'AGENT_LIFECYCLE') return true;
87
- const clusterPrefix = buildClusterPrefix(msg.cluster_id, isActive);
88
- const handlers = {
89
- AGENT_ERROR: formatAgentError,
90
- ISSUE_OPENED: formatIssueOpened,
91
- IMPLEMENTATION_READY: formatImplementationReady,
92
- VALIDATION_RESULT: formatValidationResult,
93
- PR_CREATED: formatPrCreated,
94
- PR_MERGED: formatPrMerged,
95
- };
96
- (handlers[msg.topic] || formatUnknownTopic)(msg, clusterPrefix, writer);
97
- return true;
83
+ if (msg.topic === 'AGENT_OUTPUT' || msg.topic === 'AGENT_LIFECYCLE')
84
+ return true;
85
+ const clusterPrefix = buildClusterPrefix(msg.cluster_id, isActive);
86
+ const handlers = {
87
+ AGENT_ERROR: formatAgentError,
88
+ ISSUE_OPENED: formatIssueOpened,
89
+ IMPLEMENTATION_READY: formatImplementationReady,
90
+ VALIDATION_RESULT: formatValidationResult,
91
+ PR_CREATED: formatPrCreated,
92
+ PR_MERGED: formatPrMerged,
93
+ };
94
+ (handlers[msg.topic] ?? formatUnknownTopic)(msg, clusterPrefix, writer);
95
+ return true;
98
96
  }
99
-
100
97
  module.exports = {
101
- formatWatchMode,
102
- formatImplementationReady,
103
- formatPrCreated,
98
+ formatWatchMode,
99
+ formatImplementationReady,
100
+ formatPrCreated,
104
101
  };
@@ -0,0 +1,189 @@
1
+ import chalk = require('chalk');
2
+ import formatterUtils = require('./message-formatter-utils');
3
+ import eventCopy = require('./event-copy');
4
+
5
+ const { buildClusterPrefix, getColorForSender, parseDataField } = formatterUtils;
6
+ const { EVENT_COPY, formatMergeStatus } = eventCopy;
7
+
8
+ interface WatchMessageData {
9
+ issue_number?: string | number;
10
+ title?: string;
11
+ prompt?: string;
12
+ approved?: boolean | string;
13
+ summary?: string;
14
+ errors?: unknown;
15
+ issues?: unknown;
16
+ pr_number?: string | number;
17
+ merged?: unknown;
18
+ }
19
+
20
+ interface WatchMessage {
21
+ sender: string;
22
+ cluster_id: string;
23
+ topic: string;
24
+ content?: {
25
+ text?: string;
26
+ data?: WatchMessageData;
27
+ };
28
+ }
29
+
30
+ interface LineWriter {
31
+ printLine(text: string): void;
32
+ }
33
+
34
+ type WatchMessageHandler = (
35
+ message: WatchMessage,
36
+ clusterPrefix: string,
37
+ writer: LineWriter
38
+ ) => void;
39
+
40
+ interface CountableData {
41
+ readonly length: number;
42
+ }
43
+
44
+ const DEFAULT_WRITER: Readonly<LineWriter> = Object.freeze({
45
+ printLine: (text: string) => console.log(text),
46
+ });
47
+
48
+ function isCountableData(value: unknown): value is CountableData {
49
+ if (typeof value === 'string') return true;
50
+ return (
51
+ typeof value === 'object' &&
52
+ value !== null &&
53
+ 'length' in value &&
54
+ typeof value.length === 'number'
55
+ );
56
+ }
57
+
58
+ function formatAgentError(
59
+ msg: WatchMessage,
60
+ clusterPrefix: string,
61
+ writer: LineWriter
62
+ ): void {
63
+ writer.printLine(`${clusterPrefix} ${chalk.bold.red(`Error: ${msg.sender}`)}`);
64
+ if (msg.content?.text) {
65
+ writer.printLine(`${clusterPrefix} ${chalk.red(msg.content.text)}`);
66
+ }
67
+ writer.printLine(`${clusterPrefix} Next: zeroshot logs ${msg.cluster_id} -f`);
68
+ }
69
+
70
+ function formatIssueOpened(
71
+ msg: WatchMessage,
72
+ clusterPrefix: string,
73
+ writer: LineWriter
74
+ ): void {
75
+ const issueNum = msg.content?.data?.issue_number || '';
76
+ const title = msg.content?.data?.title || '';
77
+ const prompt = msg.content?.data?.prompt || msg.content?.text || '';
78
+ const taskDesc = title === 'Manual Input' && prompt ? prompt : title;
79
+ const truncatedDesc =
80
+ taskDesc && taskDesc.length > 60 ? `${taskDesc.substring(0, 60)}...` : taskDesc;
81
+ const issueLabel = issueNum ? `#${issueNum}` : 'task';
82
+ const description = truncatedDesc ? chalk.dim(` - ${truncatedDesc}`) : '';
83
+ const eventText = `Started ${issueLabel}${description}`;
84
+ writer.printLine(`${clusterPrefix} ${eventText}`);
85
+ }
86
+
87
+ function formatImplementationReady(
88
+ msg: WatchMessage,
89
+ clusterPrefix: string,
90
+ writer: LineWriter = DEFAULT_WRITER
91
+ ): void {
92
+ const agentName = getColorForSender(msg.sender)(msg.sender);
93
+ writer.printLine(
94
+ `${clusterPrefix} ${agentName} ${EVENT_COPY.IMPLEMENTATION_READY.toLowerCase()}`
95
+ );
96
+ }
97
+
98
+ function printRejectionDetails(
99
+ data: WatchMessageData,
100
+ clusterPrefix: string,
101
+ writer: LineWriter
102
+ ): void {
103
+ const errors = parseDataField(data.errors);
104
+ const issues = parseDataField(data.issues);
105
+ if (isCountableData(errors) && errors.length > 0) {
106
+ const count = JSON.stringify(errors).length;
107
+ writer.printLine(
108
+ `${clusterPrefix} ${chalk.red('•')} ${errors.length} error${errors.length > 1 ? 's' : ''} (${count} chars)`
109
+ );
110
+ }
111
+ if (isCountableData(issues) && issues.length > 0) {
112
+ const count = JSON.stringify(issues).length;
113
+ writer.printLine(
114
+ `${clusterPrefix} ${chalk.yellow('•')} ${issues.length} issue${issues.length > 1 ? 's' : ''} (${count} chars)`
115
+ );
116
+ }
117
+ }
118
+
119
+ function formatValidationResult(
120
+ msg: WatchMessage,
121
+ clusterPrefix: string,
122
+ writer: LineWriter
123
+ ): void {
124
+ const agentName = getColorForSender(msg.sender)(msg.sender);
125
+ const data = msg.content?.data;
126
+ const approved = data?.approved === 'true' || data?.approved === true;
127
+ const status = approved ? chalk.green('Approved') : chalk.red('Rejected');
128
+ let eventText = `${agentName} ${status}`;
129
+ if (data?.summary && !approved) eventText += chalk.dim(` - ${data.summary}`);
130
+ writer.printLine(`${clusterPrefix} ${eventText}`);
131
+ if (!approved && data) printRejectionDetails(data, clusterPrefix, writer);
132
+ }
133
+
134
+ function formatPrCreated(
135
+ msg: WatchMessage,
136
+ clusterPrefix: string,
137
+ writer: LineWriter = DEFAULT_WRITER
138
+ ): void {
139
+ const agentName = getColorForSender(msg.sender)(msg.sender);
140
+ const prNum = msg.content?.data?.pr_number || '';
141
+ let eventText = `${agentName} ${EVENT_COPY.PR_CREATED.toLowerCase()}${prNum ? ` #${prNum}` : ''}`;
142
+ const mergeStatus = formatMergeStatus(msg.content?.data?.merged);
143
+ if (mergeStatus) eventText += chalk.dim(` — ${mergeStatus}`);
144
+ writer.printLine(`${clusterPrefix} ${eventText}`);
145
+ }
146
+
147
+ function formatPrMerged(
148
+ msg: WatchMessage,
149
+ clusterPrefix: string,
150
+ writer: LineWriter
151
+ ): void {
152
+ const agentName = getColorForSender(msg.sender)(msg.sender);
153
+ writer.printLine(`${clusterPrefix} ${agentName} merged PR`);
154
+ }
155
+
156
+ function formatUnknownTopic(
157
+ msg: WatchMessage,
158
+ clusterPrefix: string,
159
+ writer: LineWriter
160
+ ): void {
161
+ const agentName = getColorForSender(msg.sender)(msg.sender);
162
+ const eventText = `${agentName} ${msg.topic.toLowerCase().replace(/_/g, ' ')}`;
163
+ writer.printLine(`${clusterPrefix} ${eventText}`);
164
+ }
165
+
166
+ function formatWatchMode(
167
+ msg: WatchMessage,
168
+ isActive: boolean,
169
+ writer: LineWriter = DEFAULT_WRITER
170
+ ): true {
171
+ if (msg.topic === 'AGENT_OUTPUT' || msg.topic === 'AGENT_LIFECYCLE') return true;
172
+ const clusterPrefix = buildClusterPrefix(msg.cluster_id, isActive);
173
+ const handlers: Readonly<Record<string, WatchMessageHandler>> = {
174
+ AGENT_ERROR: formatAgentError,
175
+ ISSUE_OPENED: formatIssueOpened,
176
+ IMPLEMENTATION_READY: formatImplementationReady,
177
+ VALIDATION_RESULT: formatValidationResult,
178
+ PR_CREATED: formatPrCreated,
179
+ PR_MERGED: formatPrMerged,
180
+ };
181
+ (handlers[msg.topic] ?? formatUnknownTopic)(msg, clusterPrefix, writer);
182
+ return true;
183
+ }
184
+
185
+ export = {
186
+ formatWatchMode,
187
+ formatImplementationReady,
188
+ formatPrCreated,
189
+ };