@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
package/README.md CHANGED
@@ -106,6 +106,7 @@ zeroshot run <input> # issue, URL, markdown file, or inline text
106
106
  zeroshot run 123 --docker # container isolation
107
107
  zeroshot run 123 --pr # worktree + pull request
108
108
  zeroshot run 123 --ship # worktree + PR + merge after approval
109
+ zeroshot run 123 --pr --pr-body $'## Summary\n\nCustom text\n\n{{issue_reference}}'
109
110
  zeroshot run 123 -d # background run
110
111
 
111
112
  zeroshot list # tasks and clusters (--json)
@@ -120,6 +121,11 @@ zeroshot settings # effective settings
120
121
  zeroshot agents list # available agents
121
122
  ```
122
123
 
124
+ `--pr-body` supplies a deterministic pull-request body for `--pr` and `--ship` runs. The
125
+ template supports `{{issue_number}}`, `{{issue_title}}`, and `{{issue_reference}}`; all three
126
+ expand to empty text for tasks without an issue, so manual runs never emit `Closes #unknown`.
127
+ The unrendered template is retained for detached and resumed runs.
128
+
123
129
  </details>
124
130
 
125
131
  <details>
package/cli/event-copy.js CHANGED
@@ -1,12 +1,13 @@
1
+ "use strict";
1
2
  const EVENT_COPY = {
2
- IMPLEMENTATION_READY: 'Implementation ready',
3
- PR_CREATED: 'Pull request created',
3
+ IMPLEMENTATION_READY: 'Implementation ready',
4
+ PR_CREATED: 'Pull request created',
4
5
  };
5
-
6
6
  function formatMergeStatus(merged) {
7
- if (merged === true || merged === 'true') return 'merged';
8
- if (merged === false || merged === 'false') return 'auto-merge pending approval';
9
- return null;
7
+ if (merged === true || merged === 'true')
8
+ return 'merged';
9
+ if (merged === false || merged === 'false')
10
+ return 'auto-merge pending approval';
11
+ return null;
10
12
  }
11
-
12
13
  module.exports = { EVENT_COPY, formatMergeStatus };
@@ -0,0 +1,12 @@
1
+ const EVENT_COPY = {
2
+ IMPLEMENTATION_READY: 'Implementation ready',
3
+ PR_CREATED: 'Pull request created',
4
+ } as const;
5
+
6
+ function formatMergeStatus(merged: unknown): string | null {
7
+ if (merged === true || merged === 'true') return 'merged';
8
+ if (merged === false || merged === 'false') return 'auto-merge pending approval';
9
+ return null;
10
+ }
11
+
12
+ export = { EVENT_COPY, formatMergeStatus };
package/cli/index.js CHANGED
@@ -35,7 +35,12 @@ const {
35
35
  formatClusterFailed,
36
36
  formatGenericMessage,
37
37
  } = require('./message-formatters-normal');
38
- const { getColorForSender, buildMessagePrefix } = require('./message-formatter-utils');
38
+ const {
39
+ getColorForSender,
40
+ buildMessagePrefix,
41
+ formatLifecycleEvent,
42
+ partitionValidationCriteria,
43
+ } = require('./message-formatter-utils');
39
44
  const {
40
45
  loadSettings,
41
46
  mutateSettings,
@@ -102,6 +107,8 @@ const {
102
107
  runLegacyUpdateIfRequested,
103
108
  } = require('./lib/update-checker');
104
109
  const { checkBinDirOnPath, printPathWarning } = require('../lib/path-check');
110
+ const { quoteShellArgument } = require('../lib/git-remote-utils');
111
+ const { renderPullRequestBody, resolveIssueContext } = require('../src/pr-body-template');
105
112
  const { StatusFooter, AGENT_STATE, ACTIVE_STATES } = require('../src/status-footer');
106
113
  const { EVENT_COPY, formatMergeStatus } = require('./event-copy');
107
114
 
@@ -2007,9 +2014,25 @@ function buildContextSummary({
2007
2014
  return contextSummary;
2008
2015
  }
2009
2016
 
2010
- function buildCompletionPrompt({ contextSummary, taskText, issueNumber, issueTitle }) {
2011
- const mergeGoal = 'CREATE PR AND MERGE IT';
2012
- const mergeStep = `
2017
+ function buildDefaultFinishPrBody({ taskText, issueNumber, issueTitle }) {
2018
+ const issueReference = renderPullRequestBody(undefined, { issueNumber, issueTitle });
2019
+ return [
2020
+ issueReference,
2021
+ issueReference ? '' : null,
2022
+ '## Summary',
2023
+ `${String(taskText || 'Unknown task').slice(0, 200)}...`,
2024
+ '',
2025
+ '## Changes',
2026
+ '- Implementation complete',
2027
+ '- All validations addressed',
2028
+ '',
2029
+ '🤖 Generated with zeroshot finish',
2030
+ ]
2031
+ .filter((line) => line !== null)
2032
+ .join('\n');
2033
+ }
2034
+
2035
+ const FINISH_MERGE_STEP = `
2013
2036
  8. MERGE THE PR - THIS IS MANDATORY:
2014
2037
  \`\`\`bash
2015
2038
  gh pr merge --merge --auto
@@ -2024,7 +2047,29 @@ function buildCompletionPrompt({ contextSummary, taskText, issueNumber, issueTit
2024
2047
 
2025
2048
  REPEAT UNTIL MERGED. DO NOT GIVE UP.`;
2026
2049
 
2027
- return `# YOUR MISSION: ${mergeGoal}
2050
+ function buildFinishCommandArguments({ taskText, issueNumber, issueTitle, prBody }) {
2051
+ const issueContext = resolveIssueContext({ issueNumber, issueTitle });
2052
+ const resolvedTitle = issueContext.issueTitle;
2053
+ const resolvedBody =
2054
+ typeof prBody === 'string'
2055
+ ? renderPullRequestBody(prBody, { issueNumber, issueTitle: resolvedTitle })
2056
+ : buildDefaultFinishPrBody({ taskText, issueNumber, issueTitle: resolvedTitle });
2057
+ return {
2058
+ commitMessage: quoteShellArgument(resolvedTitle || 'feat: implement task'),
2059
+ branch: quoteShellArgument(
2060
+ issueContext.issueNumber !== 'unknown'
2061
+ ? `issue-${issueContext.issueNumber}`
2062
+ : 'feature/implementation'
2063
+ ),
2064
+ prTitle: quoteShellArgument(resolvedTitle),
2065
+ prBody: quoteShellArgument(resolvedBody),
2066
+ };
2067
+ }
2068
+
2069
+ function buildCompletionPrompt({ contextSummary, taskText, issueNumber, issueTitle, prBody }) {
2070
+ const args = buildFinishCommandArguments({ taskText, issueNumber, issueTitle, prBody });
2071
+
2072
+ return `# YOUR MISSION: CREATE PR AND MERGE IT
2028
2073
 
2029
2074
  ${contextSummary}
2030
2075
 
@@ -2045,12 +2090,12 @@ You are the FINISHER. Your ONLY job is to take this cluster's work and push it a
2045
2090
  2. COMMIT ALL CHANGES - Stage and commit everything:
2046
2091
  \`\`\`bash
2047
2092
  git add .
2048
- git commit -m "${issueTitle || 'feat: implement task'}"
2093
+ git commit -m ${args.commitMessage}
2049
2094
  \`\`\`
2050
2095
 
2051
2096
  3. CREATE BRANCH - Use issue number if available:
2052
2097
  \`\`\`bash
2053
- ${issueNumber ? `git checkout -b issue-${issueNumber}` : 'git checkout -b feature/implementation'}
2098
+ git checkout -b ${args.branch}
2054
2099
  \`\`\`
2055
2100
 
2056
2101
  4. PUSH TO REMOTE:
@@ -2060,16 +2105,7 @@ You are the FINISHER. Your ONLY job is to take this cluster's work and push it a
2060
2105
 
2061
2106
  5. CREATE PULL REQUEST:
2062
2107
  \`\`\`bash
2063
- gh pr create --title "${issueTitle || 'Implementation'}" --body "Closes #${issueNumber || 'N/A'}
2064
-
2065
- ## Summary
2066
- ${taskText.slice(0, 200)}...
2067
-
2068
- ## Changes
2069
- - Implementation complete
2070
- - All validations addressed
2071
-
2072
- 🤖 Generated with zeroshot finish"
2108
+ gh pr create --title ${args.prTitle} --body ${args.prBody}
2073
2109
  \`\`\`
2074
2110
 
2075
2111
  6. GET PR URL:
@@ -2078,7 +2114,7 @@ ${taskText.slice(0, 200)}...
2078
2114
  \`\`\`
2079
2115
 
2080
2116
  7. OUTPUT THE PR URL - Print it clearly so user can see it
2081
- ${mergeStep}
2117
+ ${FINISH_MERGE_STEP}
2082
2118
 
2083
2119
  ## RULES
2084
2120
 
@@ -2702,6 +2738,10 @@ program
2702
2738
  'Full automation: worktree isolation + PR + auto-merge (use --docker for Docker)'
2703
2739
  )
2704
2740
  .option('--pr-base <branch>', 'Target branch for PRs (default: repo default branch)')
2741
+ .option(
2742
+ '--pr-body <template>',
2743
+ 'PR body template; supports {{issue_number}}, {{issue_title}}, and {{issue_reference}}'
2744
+ )
2705
2745
  .option('--merge-queue', 'Use GitHub merge queue instead of direct merge')
2706
2746
  .option(
2707
2747
  '--close-issue <mode>',
@@ -3709,6 +3749,10 @@ program
3709
3749
  .helpGroup('Control:')
3710
3750
  .description('Take existing cluster and create completion-focused task (creates PR and merges)')
3711
3751
  .option('-y, --yes', 'Skip confirmation if cluster is running')
3752
+ .option(
3753
+ '--pr-body <template>',
3754
+ 'PR body template; supports {{issue_number}}, {{issue_title}}, and {{issue_reference}}'
3755
+ )
3712
3756
  .action(async (id, options) => {
3713
3757
  try {
3714
3758
  const orchestrator = await getOrchestrator();
@@ -3727,6 +3771,7 @@ program
3727
3771
  taskText: context.taskText,
3728
3772
  issueNumber: context.issueNumber,
3729
3773
  issueTitle: context.issueTitle,
3774
+ prBody: options.prBody ?? cluster.prOptions?.prBody,
3730
3775
  });
3731
3776
  printCompletionPromptPreview(completionPrompt);
3732
3777
 
@@ -5325,34 +5370,6 @@ function flushAllRenderBuffers(lines, buffers) {
5325
5370
  }
5326
5371
  }
5327
5372
 
5328
- function formatLifecycleEvent(data) {
5329
- const event = data?.event;
5330
- let icon;
5331
- let eventText;
5332
-
5333
- switch (event) {
5334
- case 'STARTED': {
5335
- icon = chalk.green('▶');
5336
- const triggers = data?.triggers?.join(', ') || 'none';
5337
- eventText = `started (listening for: ${chalk.dim(triggers)})`;
5338
- break;
5339
- }
5340
- case 'TASK_STARTED':
5341
- icon = chalk.yellow('⚡');
5342
- eventText = `${chalk.cyan(data.triggeredBy)} → task #${data.iteration} (${chalk.dim(data.model)})`;
5343
- break;
5344
- case 'TASK_COMPLETED':
5345
- icon = chalk.green('✓');
5346
- eventText = `task #${data.iteration} completed`;
5347
- break;
5348
- default:
5349
- icon = chalk.dim('•');
5350
- eventText = event || 'unknown event';
5351
- }
5352
-
5353
- return { icon, eventText };
5354
- }
5355
-
5356
5373
  function handleLifecycleRender({ msg, prefix, lines }) {
5357
5374
  const data = msg.content?.data;
5358
5375
  const { icon, eventText } = formatLifecycleEvent(data);
@@ -5427,7 +5444,7 @@ function appendCriteriaGroup({ lines, prefix, label, items, color, reasonLabel }
5427
5444
  function appendCriteriaResults(lines, prefix, criteriaResults) {
5428
5445
  if (!Array.isArray(criteriaResults)) return;
5429
5446
 
5430
- const cannotValidateYet = criteriaResults.filter((c) => c.status === 'CANNOT_VALIDATE_YET');
5447
+ const { cannotValidateYet, cannotValidate } = partitionValidationCriteria(criteriaResults);
5431
5448
  appendCriteriaGroup({
5432
5449
  lines,
5433
5450
  prefix,
@@ -5437,7 +5454,6 @@ function appendCriteriaResults(lines, prefix, criteriaResults) {
5437
5454
  reasonLabel: 'work incomplete',
5438
5455
  });
5439
5456
 
5440
- const cannotValidate = criteriaResults.filter((c) => c.status === 'CANNOT_VALIDATE');
5441
5457
  appendCriteriaGroup({
5442
5458
  lines,
5443
5459
  prefix,
@@ -6214,6 +6230,9 @@ module.exports = {
6214
6230
  isStartupUpdateEligible,
6215
6231
  handleNoArgumentInvocation,
6216
6232
  shouldRunInitialSetup,
6233
+ extractFinishContext,
6234
+ buildDefaultFinishPrBody,
6235
+ buildCompletionPrompt,
6217
6236
  resolveRunMode,
6218
6237
  killRunningClusters,
6219
6238
  };
@@ -1,77 +1,74 @@
1
- const fs = require('fs');
2
-
1
+ "use strict";
2
+ const fs = require("fs");
3
+ function isInteger(value) {
4
+ return Number.isInteger(value);
5
+ }
3
6
  function indentJson(value, spaces) {
4
- const prefix = ' '.repeat(spaces);
5
- return JSON.stringify(value, null, 2)
6
- .split('\n')
7
- .map((line) => `${prefix}${line}`)
8
- .join('\n');
7
+ const prefix = ' '.repeat(spaces);
8
+ return JSON.stringify(value, null, 2)
9
+ .split('\n')
10
+ .map((line) => `${prefix}${line}`)
11
+ .join('\n');
9
12
  }
10
-
11
13
  function writeAll(fd, value) {
12
- const bytes = Buffer.from(value);
13
- let offset = 0;
14
- while (offset < bytes.length) {
15
- const written = fs.writeSync(fd, bytes, offset, bytes.length - offset);
16
- if (!Number.isInteger(written) || written <= 0) {
17
- throw new Error('JSON export destination stopped accepting bytes');
14
+ const bytes = Buffer.from(value);
15
+ let offset = 0;
16
+ while (offset < bytes.length) {
17
+ const written = fs.writeSync(fd, bytes, offset, bytes.length - offset);
18
+ if (!Number.isInteger(written) || written <= 0) {
19
+ throw new Error('JSON export destination stopped accepting bytes');
20
+ }
21
+ offset += written;
18
22
  }
19
- offset += written;
20
- }
21
23
  }
22
-
23
24
  function createDestination(outputPath, stdout) {
24
- if (outputPath) {
25
- const fd = fs.openSync(outputPath, 'w');
26
- return {
27
- close: () => fs.closeSync(fd),
28
- write: (value) => writeAll(fd, value),
29
- };
30
- }
31
-
32
- if (Number.isInteger(stdout.fd)) {
25
+ if (outputPath) {
26
+ const fd = fs.openSync(outputPath, 'w');
27
+ return {
28
+ close: () => fs.closeSync(fd),
29
+ write: (value) => writeAll(fd, value),
30
+ };
31
+ }
32
+ if (isInteger(stdout.fd)) {
33
+ const fd = stdout.fd;
34
+ return {
35
+ close() { },
36
+ write: (value) => writeAll(fd, value),
37
+ };
38
+ }
33
39
  return {
34
- close() {},
35
- write: (value) => writeAll(stdout.fd, value),
40
+ close() { },
41
+ write: (value) => {
42
+ stdout.write(value);
43
+ },
36
44
  };
37
- }
38
-
39
- return {
40
- close() {},
41
- write: (value) => stdout.write(value),
42
- };
43
45
  }
44
-
45
- function streamClusterJsonExport({
46
- ledger,
47
- clusterId,
48
- outputPath = null,
49
- stdout = process.stdout,
50
- }) {
51
- const destination = createDestination(outputPath, stdout);
52
- const iterator = ledger.iterateAll(clusterId);
53
- try {
54
- destination.write(`{\n "cluster_id": ${JSON.stringify(clusterId)},\n "messages": `);
55
- let current = iterator.next();
56
- if (current.done) {
57
- destination.write('[]\n}\n');
58
- return;
59
- }
60
-
61
- destination.write('[\n');
62
- while (!current.done) {
63
- destination.write(indentJson(current.value, 4));
64
- current = iterator.next();
65
- destination.write(current.done ? '\n' : ',\n');
66
- }
67
- destination.write(' ]\n}\n');
68
- } finally {
46
+ function streamClusterJsonExport({ ledger, clusterId, outputPath = null, stdout = process.stdout, }) {
47
+ const destination = createDestination(outputPath, stdout);
48
+ const iterator = ledger.iterateAll(clusterId);
69
49
  try {
70
- if (typeof iterator.return === 'function') iterator.return();
71
- } finally {
72
- destination.close();
50
+ destination.write(`{\n "cluster_id": ${JSON.stringify(clusterId)},\n "messages": `);
51
+ let current = iterator.next();
52
+ if (current.done) {
53
+ destination.write('[]\n}\n');
54
+ return;
55
+ }
56
+ destination.write('[\n');
57
+ while (!current.done) {
58
+ destination.write(indentJson(current.value, 4));
59
+ current = iterator.next();
60
+ destination.write(current.done ? '\n' : ',\n');
61
+ }
62
+ destination.write(' ]\n}\n');
63
+ }
64
+ finally {
65
+ try {
66
+ if (typeof iterator.return === 'function')
67
+ iterator.return();
68
+ }
69
+ finally {
70
+ destination.close();
71
+ }
73
72
  }
74
- }
75
73
  }
76
-
77
74
  module.exports = { streamClusterJsonExport };
@@ -0,0 +1,112 @@
1
+ import fs = require('fs');
2
+
3
+ interface LedgerMessageIterator extends Iterator<unknown> {
4
+ return?: () => IteratorResult<unknown>;
5
+ }
6
+
7
+ interface ClusterLedger {
8
+ iterateAll(clusterId: string): LedgerMessageIterator;
9
+ }
10
+
11
+ interface ExportStream {
12
+ readonly fd?: number;
13
+ write(value: string): unknown;
14
+ }
15
+
16
+ interface JsonExportOptions {
17
+ ledger: ClusterLedger;
18
+ clusterId: string;
19
+ outputPath?: string | null;
20
+ stdout?: ExportStream;
21
+ }
22
+
23
+ interface Destination {
24
+ close(): void;
25
+ write(value: string): void;
26
+ }
27
+
28
+ function isInteger(value: unknown): value is number {
29
+ return Number.isInteger(value);
30
+ }
31
+
32
+ function indentJson(value: unknown, spaces: number): string {
33
+ const prefix = ' '.repeat(spaces);
34
+ return JSON.stringify(value, null, 2)
35
+ .split('\n')
36
+ .map((line) => `${prefix}${line}`)
37
+ .join('\n');
38
+ }
39
+
40
+ function writeAll(fd: number, value: string): void {
41
+ const bytes = Buffer.from(value);
42
+ let offset = 0;
43
+ while (offset < bytes.length) {
44
+ const written = fs.writeSync(fd, bytes, offset, bytes.length - offset);
45
+ if (!Number.isInteger(written) || written <= 0) {
46
+ throw new Error('JSON export destination stopped accepting bytes');
47
+ }
48
+ offset += written;
49
+ }
50
+ }
51
+
52
+ function createDestination(
53
+ outputPath: string | null | undefined,
54
+ stdout: ExportStream
55
+ ): Destination {
56
+ if (outputPath) {
57
+ const fd = fs.openSync(outputPath, 'w');
58
+ return {
59
+ close: () => fs.closeSync(fd),
60
+ write: (value) => writeAll(fd, value),
61
+ };
62
+ }
63
+
64
+ if (isInteger(stdout.fd)) {
65
+ const fd = stdout.fd;
66
+ return {
67
+ close(): void {},
68
+ write: (value) => writeAll(fd, value),
69
+ };
70
+ }
71
+
72
+ return {
73
+ close(): void {},
74
+ write: (value): void => {
75
+ stdout.write(value);
76
+ },
77
+ };
78
+ }
79
+
80
+ function streamClusterJsonExport({
81
+ ledger,
82
+ clusterId,
83
+ outputPath = null,
84
+ stdout = process.stdout,
85
+ }: JsonExportOptions): void {
86
+ const destination = createDestination(outputPath, stdout);
87
+ const iterator = ledger.iterateAll(clusterId);
88
+ try {
89
+ destination.write(`{\n "cluster_id": ${JSON.stringify(clusterId)},\n "messages": `);
90
+ let current = iterator.next();
91
+ if (current.done) {
92
+ destination.write('[]\n}\n');
93
+ return;
94
+ }
95
+
96
+ destination.write('[\n');
97
+ while (!current.done) {
98
+ destination.write(indentJson(current.value, 4));
99
+ current = iterator.next();
100
+ destination.write(current.done ? '\n' : ',\n');
101
+ }
102
+ destination.write(' ]\n}\n');
103
+ } finally {
104
+ try {
105
+ if (typeof iterator.return === 'function') iterator.return();
106
+ } finally {
107
+ destination.close();
108
+ }
109
+ }
110
+ }
111
+
112
+ export = { streamClusterJsonExport };
@@ -1,75 +1,87 @@
1
+ "use strict";
2
+ const chalk = require("chalk");
1
3
  /**
2
- * Message formatting utilities for CLI output
3
- * Extracted from index.js to reduce complexity
4
- */
5
-
6
- const chalk = require('chalk');
7
-
8
- /**
9
- * Get color for sender based on consistent hashing
10
- * @param {string} sender - Sender name
11
- * @returns {Function} Chalk color function
4
+ * Get color for sender based on consistent hashing.
12
5
  */
13
6
  function getColorForSender(sender) {
14
- const colors = [chalk.cyan, chalk.magenta, chalk.yellow, chalk.green, chalk.blue];
15
- let hash = 0;
16
- for (let i = 0; i < sender.length; i++) {
17
- hash = (hash << 5) - hash + sender.charCodeAt(i);
18
- hash = hash & hash;
19
- }
20
- return colors[Math.abs(hash) % colors.length];
7
+ const colors = [chalk.cyan, chalk.magenta, chalk.yellow, chalk.green, chalk.blue];
8
+ let hash = 0;
9
+ for (let i = 0; i < sender.length; i++) {
10
+ hash = (hash << 5) - hash + sender.charCodeAt(i);
11
+ hash = hash & hash;
12
+ }
13
+ return colors[Math.abs(hash) % colors.length] ?? chalk.cyan;
21
14
  }
22
-
23
15
  /**
24
- * Build message prefix with timestamp, sender, and optional cluster ID
25
- * @param {Object} msg - Message object
26
- * @param {boolean} showClusterId - Whether to show cluster ID
27
- * @param {boolean} isActive - Whether cluster is active
28
- * @returns {string} Formatted prefix
16
+ * Build message prefix with timestamp, sender, and optional cluster ID.
29
17
  */
30
18
  function buildMessagePrefix(msg, showClusterId, isActive) {
31
- const color = isActive ? getColorForSender(msg.sender) : chalk.dim;
32
-
33
- let senderLabel = msg.sender;
34
- if (showClusterId && msg.cluster_id) {
35
- senderLabel = `${msg.cluster_id}/${msg.sender}`;
36
- }
37
-
38
- const modelSuffix = msg.sender_model ? chalk.dim(` [${msg.sender_model}]`) : '';
39
- return color(`${senderLabel.padEnd(showClusterId ? 25 : 15)} |`) + modelSuffix;
19
+ const color = isActive ? getColorForSender(msg.sender) : chalk.dim;
20
+ let senderLabel = msg.sender;
21
+ if (showClusterId && msg.cluster_id) {
22
+ senderLabel = `${msg.cluster_id}/${msg.sender}`;
23
+ }
24
+ const modelSuffix = msg.sender_model ? chalk.dim(` [${msg.sender_model}]`) : '';
25
+ return color(`${senderLabel.padEnd(showClusterId ? 25 : 15)} |`) + modelSuffix;
40
26
  }
41
-
42
27
  /**
43
- * Build cluster prefix for watch mode
44
- * @param {string} clusterId - Cluster ID
45
- * @param {boolean} isActive - Whether cluster is active
46
- * @returns {string} Formatted prefix
28
+ * Build cluster prefix for watch mode.
47
29
  */
48
30
  function buildClusterPrefix(clusterId, isActive) {
49
- return isActive
50
- ? chalk.white(`${clusterId.padEnd(20)} |`)
51
- : chalk.dim(`${clusterId.padEnd(20)} |`);
31
+ const color = isActive ? chalk.white : chalk.dim;
32
+ return color(`${clusterId.padEnd(20)} |`);
52
33
  }
53
-
54
34
  /**
55
- * Parse and normalize data fields (handles string JSON)
56
- * @param {string|Array} data - Data to parse
57
- * @returns {Array} Parsed array
35
+ * Parse and normalize data fields (handles string JSON).
58
36
  */
59
37
  function parseDataField(data) {
60
- if (typeof data === 'string') {
61
- try {
62
- return JSON.parse(data);
63
- } catch {
64
- return [];
38
+ if (typeof data === 'string') {
39
+ try {
40
+ const parsed = JSON.parse(data);
41
+ return parsed;
42
+ }
43
+ catch {
44
+ return [];
45
+ }
65
46
  }
66
- }
67
- return Array.isArray(data) ? data : [];
47
+ return Array.isArray(data) ? data : [];
48
+ }
49
+ function formatLifecycleEvent(data) {
50
+ const event = data?.event;
51
+ let icon;
52
+ let eventText;
53
+ switch (event) {
54
+ case 'STARTED': {
55
+ icon = chalk.green('▶');
56
+ const triggers = data?.triggers?.join(', ') || 'none';
57
+ eventText = `started (listening for: ${chalk.dim(triggers)})`;
58
+ break;
59
+ }
60
+ case 'TASK_STARTED':
61
+ icon = chalk.yellow('⚡');
62
+ eventText = `${chalk.cyan(data?.triggeredBy)} → task #${data?.iteration} (${chalk.dim(data?.model)})`;
63
+ break;
64
+ case 'TASK_COMPLETED':
65
+ icon = chalk.green('✓');
66
+ eventText = `task #${data?.iteration} completed`;
67
+ break;
68
+ default:
69
+ icon = chalk.dim('•');
70
+ eventText = event || 'unknown event';
71
+ }
72
+ return { icon, eventText };
73
+ }
74
+ function partitionValidationCriteria(criteria) {
75
+ return {
76
+ cannotValidateYet: criteria.filter((criterion) => criterion.status === 'CANNOT_VALIDATE_YET'),
77
+ cannotValidate: criteria.filter((criterion) => criterion.status === 'CANNOT_VALIDATE'),
78
+ };
68
79
  }
69
-
70
80
  module.exports = {
71
- getColorForSender,
72
- buildMessagePrefix,
73
- buildClusterPrefix,
74
- parseDataField,
81
+ getColorForSender,
82
+ buildMessagePrefix,
83
+ buildClusterPrefix,
84
+ parseDataField,
85
+ formatLifecycleEvent,
86
+ partitionValidationCriteria,
75
87
  };