@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,619 +1,19 @@
1
- /**
2
- * Output Extraction Module - Multi-Provider JSON Extraction
3
- *
4
- * Clean extraction pipeline for structured JSON from AI provider outputs.
5
- * Each provider has different output formats - this module normalizes them.
6
- *
7
- * Provider formats:
8
- * - Claude: {"type":"result","result":{...}} or {"type":"result","structured_output":{...}}
9
- * - Codex: Raw text in item.created events, turn.completed has NO result field
10
- * - Gemini: Raw text in message events, result event may have NO result field
11
- *
12
- * Extraction priority (most specific → least specific):
13
- * 1. Result wrapper with content (type:result + result/structured_output field)
14
- * 2. Accumulated text from provider parser events
15
- * 3. Markdown code block extraction
16
- * 4. Direct JSON parse of entire output
17
- */
18
-
19
- const { createHash } = require('node:crypto');
20
- const { parseProviderChunk } = require('../providers');
21
-
22
- const MAX_CLI_ERROR_BYTES = 4096;
23
- const CLI_ERROR_TRUNCATION_SUFFIX = '… [truncated]';
24
-
25
- function truncateUtf8(text, maxBytes = MAX_CLI_ERROR_BYTES) {
26
- if (Buffer.byteLength(text) <= maxBytes) return text;
27
-
28
- const suffixBytes = Buffer.byteLength(CLI_ERROR_TRUNCATION_SUFFIX);
29
- const contentBudget = Math.max(0, maxBytes - suffixBytes);
30
- let bytes = 0;
31
- let truncated = '';
32
- for (const character of text) {
33
- const characterBytes = Buffer.byteLength(character);
34
- if (bytes + characterBytes > contentBudget) break;
35
- truncated += character;
36
- bytes += characterBytes;
37
- }
38
- return `${truncated}${CLI_ERROR_TRUNCATION_SUFFIX}`;
39
- }
40
-
41
- function primitiveErrorText(value) {
42
- return typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean'
43
- ? String(value)
44
- : '';
45
- }
46
-
47
- function cliErrorDetail(value, fallback) {
48
- const candidate = Array.isArray(value)
49
- ? value
50
- .map(primitiveErrorText)
51
- .filter((message) => message.trim())
52
- .join('; ')
53
- : primitiveErrorText(value);
54
- const raw = candidate.trim() ? candidate : fallback;
55
- return {
56
- error: truncateUtf8(raw.trim()),
57
- diagnostic: {
58
- byteLength: Buffer.byteLength(raw),
59
- sha256: createHash('sha256').update(raw).digest('hex'),
60
- },
61
- };
62
- }
63
-
64
- /**
65
- * Strip timestamp prefix from log lines.
66
- * Format: [epochMs]content or [epochMs]{json...}
67
- *
68
- * @param {string} line - Raw log line
69
- * @returns {string} Content without timestamp prefix
70
- */
71
- function stripTimestamp(line) {
72
- if (!line || typeof line !== 'string') return '';
73
- let trimmed = line.trim().replace(/\r$/, '');
74
- if (!trimmed) return '';
75
-
76
- const tsMatch = trimmed.match(/^\[(\d{13})\](.*)$/);
77
- if (tsMatch) trimmed = (tsMatch[2] || '').trimStart();
78
-
79
- // In cluster logs, lines are often prefixed like:
80
- // "validator | {json...}"
81
- // Strip the "<agent> | " prefix so we can JSON.parse the event line.
82
- if (!trimmed.startsWith('{') && !trimmed.startsWith('[')) {
83
- const pipeMatch = trimmed.match(/^[^|]{1,40}\|\s*(.*)$/);
84
- if (pipeMatch) {
85
- const afterPipe = (pipeMatch[1] || '').trimStart();
86
- if (afterPipe.startsWith('{') || afterPipe.startsWith('[')) return afterPipe;
87
- }
88
- }
89
-
90
- return trimmed;
91
- }
92
-
93
- /**
94
- * Strategy 1: Extract from result wrapper
95
- * Handles Claude CLI format: {"type":"result","result":{...}}
96
- *
97
- * @param {string} output - Raw output
98
- * @returns {object|null} Extracted JSON or null
99
- */
100
- function extractFromResultWrapper(output) {
101
- const lines = output.split('\n');
102
-
103
- for (const line of lines) {
104
- const content = stripTimestamp(line);
105
- if (!content.startsWith('{')) continue;
106
-
107
- try {
108
- const obj = JSON.parse(content);
109
- const extracted = extractResultContent(obj);
110
- if (extracted) return extracted;
111
- } catch {
112
- // Not valid JSON, continue to next line
113
- }
114
- }
115
-
116
- return null;
117
- }
118
-
119
- function extractResultContent(obj) {
120
- // Must be type:result WITH actual content
121
- if (obj?.type !== 'result') return null;
122
-
123
- // Check structured_output first (standard CLI format)
124
- if (obj.structured_output && typeof obj.structured_output === 'object') {
125
- return obj.structured_output;
126
- }
127
-
128
- // Check result field - can be object or string
129
- if (!obj.result) return null;
130
-
131
- if (typeof obj.result === 'object') {
132
- return obj.result;
133
- }
134
-
135
- if (typeof obj.result !== 'string') return null;
136
-
137
- // Result is string - might contain markdown-wrapped JSON
138
- return extractFromMarkdown(obj.result) || extractDirectJson(obj.result);
139
- }
140
-
141
- /**
142
- * Strategy 2: Extract from accumulated text events
143
- * Handles non-Claude providers where JSON is in text content
144
- *
145
- * @param {string} output - Raw output
146
- * @param {string} providerName - Provider name for parser selection
147
- * @returns {object|null} Extracted JSON or null
148
- */
149
- function extractFromTextEvents(output, providerName) {
150
- const normalized = output
151
- .split('\n')
152
- .map((line) => stripTimestamp(line))
153
- .filter(Boolean)
154
- .join('\n');
155
- const events = parseProviderChunk(providerName, normalized);
156
-
157
- // Fast-path: many providers eventually emit the full JSON as a single text event.
158
- // Scan from the end to find the last parseable JSON snippet without requiring
159
- // the entire concatenated stream to be valid JSON.
160
- for (let i = events.length - 1; i >= 0; i--) {
161
- const e = events[i];
162
- if (e.type !== 'text' || typeof e.text !== 'string') continue;
163
- const direct = extractDirectJson(e.text) || extractFromMarkdown(e.text);
164
- if (direct) return direct;
165
- }
166
-
167
- // Accumulate all text events
168
- const textEvents = events.filter((e) => e.type === 'text').map((e) => e.text);
169
- const textContent = textEvents.join('');
170
-
171
- if (!textContent.trim()) return null;
172
-
173
- // Try parsing accumulated text as JSON
174
- const combined = extractDirectJson(textContent) || extractFromMarkdown(textContent);
175
- if (combined) return combined;
176
-
177
- for (let i = textEvents.length - 1; i >= 0; i--) {
178
- const candidate = textEvents[i];
179
- const parsed = extractDirectJson(candidate) || extractFromMarkdown(candidate);
180
- if (parsed) return parsed;
181
- }
182
-
183
- return null;
184
- }
185
-
186
- /**
187
- * Assemble assistant text through the active provider parser. Recovery prompts
188
- * use this instead of exposing raw event envelopes when model text exists.
189
- *
190
- * @param {string} output
191
- * @param {string} providerName
192
- * @returns {string|null}
193
- */
194
- function extractModelTextFromOutput(output, providerName) {
195
- if (!output || typeof output !== 'string') return null;
196
- const normalized = output
197
- .split('\n')
198
- .map((line) => stripTimestamp(line))
199
- .filter(Boolean)
200
- .join('\n');
201
- const text = parseProviderChunk(providerName, normalized)
202
- .filter((event) => event.type === 'text' && typeof event.text === 'string')
203
- .map((event) => event.text)
204
- .join('');
205
- return text.trim() ? text : null;
206
- }
207
-
208
- /**
209
- * Strategy 3: Extract JSON from markdown code block
210
- * Handles: ```json\n{...}\n```
211
- *
212
- * @param {string} text - Text that may contain markdown
213
- * @returns {object|null} Extracted JSON or null
214
- */
215
- function extractFromMarkdown(text) {
216
- if (!text) return null;
217
-
218
- // Match ```json ... ``` with any whitespace
219
- const match = text.match(/```json\s*([\s\S]*?)```/);
220
- if (!match) return null;
221
-
222
- try {
223
- const parsed = JSON.parse(match[1].trim());
224
- if (typeof parsed === 'object' && parsed !== null) {
225
- return parsed;
226
- }
227
- } catch {
228
- // Invalid JSON in markdown block
229
- }
230
-
231
- return null;
232
- }
233
-
234
- /**
235
- * CLI metadata fields that indicate raw provider output (not agent content).
236
- * These objects should be rejected - they're wrapper metadata, not actual output.
237
- */
238
- const CLI_METADATA_FIELDS = new Set([
239
- 'duration_ms',
240
- 'duration_api_ms',
241
- 'total_cost_usd',
242
- 'session_id',
243
- 'num_turns',
244
- 'permission_denials',
245
- 'modelUsage',
246
- ]);
247
-
248
- /**
249
- * Check if an object looks like CLI metadata rather than agent output.
250
- * CLI metadata has specific fields like duration_ms, session_id, etc.
251
- *
252
- * @param {object} obj - Parsed JSON object
253
- * @returns {boolean} True if this looks like CLI metadata
254
- */
255
- function isCliMetadata(obj) {
256
- if (!obj || typeof obj !== 'object') return false;
257
-
258
- // If it has type:result, it's definitely CLI wrapper (should have been handled by extractFromResultWrapper)
259
- if (obj.type === 'result') return true;
260
-
261
- // Check for CLI-specific metadata fields
262
- const keys = Object.keys(obj);
263
- const metadataFieldCount = keys.filter((k) => CLI_METADATA_FIELDS.has(k)).length;
264
-
265
- // If 2+ CLI metadata fields present, reject as CLI output
266
- return metadataFieldCount >= 2;
267
- }
268
-
269
- /**
270
- * Strategy 4: Direct JSON parse
271
- * Handles raw JSON output (single-line or multi-line)
272
- *
273
- * IMPORTANT: Rejects CLI metadata objects to prevent schema validation
274
- * against wrong data structure (e.g., validating {duration_ms, session_id}
275
- * against agent schema expecting {summary, completionStatus}).
276
- *
277
- * @param {string} text - Text to parse
278
- * @returns {object|null} Parsed JSON or null
279
- */
280
- function extractDirectJson(text) {
281
- if (!text) return null;
282
-
283
- const trimmed = text.trim();
284
- if (!trimmed) return null;
285
-
286
- try {
287
- const parsed = JSON.parse(trimmed);
288
- if (typeof parsed === 'object' && parsed !== null && !Array.isArray(parsed)) {
289
- // Reject CLI metadata - this is wrapper output, not agent content
290
- if (isCliMetadata(parsed)) {
291
- return null;
292
- }
293
- return parsed;
294
- }
295
- } catch {
296
- // Not valid JSON
297
- }
298
-
299
- return null;
300
- }
301
-
302
- /**
303
- * Extract deterministic Claude Vertex model-unavailability metadata from the raw CLI envelope.
304
- *
305
- * @param {string} output - Raw Claude CLI output
306
- * @param {{useVertex?: boolean}} [options] - Whether the Claude task was configured for Vertex
307
- * @returns {{model: string}|null} Vertex model metadata or null
308
- */
309
- function extractClaudeVertexModelError(output, { useVertex = false } = {}) {
310
- if (!output || typeof output !== 'string') return null;
311
-
312
- for (const line of output.split('\n')) {
313
- const content = stripTimestamp(line);
314
- if (!content.startsWith('{')) continue;
315
-
316
- try {
317
- const parsed = JSON.parse(content);
318
- if (
319
- parsed.type !== 'result' ||
320
- parsed.is_error !== true ||
321
- parsed.api_error_status !== 404 ||
322
- typeof parsed.result !== 'string'
323
- ) {
324
- continue;
325
- }
326
- const modelMatch = parsed.result.match(/model\s+\(([^)]+)\)/);
327
- const hasExplicitVertexSignal = parsed.result.includes('vertex deployment');
328
- const isVertexFallback =
329
- useVertex && parsed.result.includes('may not exist or you may not have access');
330
- if (!modelMatch || (!hasExplicitVertexSignal && !isVertexFallback)) continue;
331
-
332
- return { model: modelMatch[1] };
333
- } catch {
334
- // Not a JSON result envelope.
335
- }
336
- }
337
-
338
- return null;
339
- }
340
-
341
- /**
342
- * Extract CLI error from provider output (all providers).
343
- * Returns the error message if the CLI reported an error, null otherwise.
344
- *
345
- * Provider error formats:
346
- * - Claude: {type:"result", is_error:true, errors:["msg"]} or {type:"result", subtype:"error"}
347
- * - Codex: {type:"turn.failed", error:{message:"msg"}}
348
- * - Gemini: {type:"result", status:"error", error:{message:"msg"}} or {type:"error", severity:"error"}
349
- * - Opencode: {type:"session.error", error:{message:"msg"}}
350
- * - Pi: latest assistant message_end, finalized only by a later agent_settled
351
- *
352
- * @param {string} providerName - Active provider whose terminal errors may be inspected
353
- * @returns {{error: string, provider: string}|null} Error info or null
354
- */
355
- function claudeFailureFromObject(obj) {
356
- if (obj.type !== 'result') return null;
357
- if (obj.is_error === true) {
358
- const detail = cliErrorDetail(
359
- Array.isArray(obj.errors) ? obj.errors : obj.error || obj.result,
360
- 'Unknown CLI error'
361
- );
362
- return { ...detail, provider: 'claude' };
363
- }
364
- if (obj.subtype !== 'error') return null;
365
- return {
366
- ...cliErrorDetail(obj.error || obj.result, 'CLI returned error'),
367
- provider: 'claude',
368
- };
369
- }
370
-
371
- function codexFailureFromObject(obj) {
372
- if (obj.type !== 'turn.failed') return null;
373
- return {
374
- ...cliErrorDetail(obj.error?.message || obj.error?.code || obj.error, 'Turn failed'),
375
- provider: 'codex',
376
- };
377
- }
378
-
379
- function geminiFailureFromObject(obj) {
380
- const geminiFailure =
381
- (obj.type === 'result' && obj.status === 'error') ||
382
- (obj.type === 'error' && obj.severity === 'error');
383
- if (!geminiFailure) return null;
384
- return {
385
- ...cliErrorDetail(obj.error?.message || obj.message, 'Gemini CLI error'),
386
- provider: 'gemini',
387
- };
388
- }
389
-
390
- function opencodeFailureFromObject(obj) {
391
- if (obj.type !== 'session.error' && obj.type !== 'error') return null;
392
- return {
393
- ...cliErrorDetail(
394
- obj.error?.data?.message || obj.error?.message || obj.error?.name,
395
- 'Session error'
396
- ),
397
- provider: 'opencode',
398
- };
399
- }
400
-
401
- function piFailureFromMessage(message) {
402
- const stopReason = message.stopReason;
403
- const errorMessage = message.errorMessage;
404
- if (stopReason === 'deferred') {
405
- return {
406
- ...cliErrorDetail('Pi turn deferred without completing.', 'Pi turn deferred'),
407
- provider: 'pi',
408
- };
409
- }
410
- if (stopReason !== 'error' && stopReason !== 'aborted' && !errorMessage) return null;
411
- return {
412
- ...cliErrorDetail(errorMessage || stopReason, 'Pi turn failed'),
413
- provider: 'pi',
414
- };
415
- }
416
-
417
- function failureFromProviderObject(obj, providerName) {
418
- if (providerName === 'claude') return claudeFailureFromObject(obj);
419
- if (providerName === 'codex') return codexFailureFromObject(obj);
420
- if (providerName === 'gemini') return geminiFailureFromObject(obj);
421
- if (providerName === 'opencode') return opencodeFailureFromObject(obj);
422
- return null;
423
- }
424
-
425
- function piProtocolFailure(message) {
426
- return { ...cliErrorDetail(message, message), provider: 'pi' };
427
- }
428
-
429
- const PI_STOP_REASONS = new Set(['stop', 'length', 'toolUse', 'error', 'aborted', 'deferred']);
430
- const PI_USAGE_FIELDS = ['input', 'output', 'cacheRead', 'cacheWrite', 'totalTokens'];
431
- const PI_COST_FIELDS = ['input', 'output', 'cacheRead', 'cacheWrite', 'total'];
432
-
433
- function parsePiProtocolObject(content) {
434
- if (!content.startsWith('{')) return null;
435
- try {
436
- const parsed = JSON.parse(content);
437
- return parsed && typeof parsed === 'object' && !Array.isArray(parsed) ? parsed : null;
438
- } catch {
439
- return null;
440
- }
441
- }
442
-
443
- function isPiRecord(value) {
444
- return value !== null && typeof value === 'object' && !Array.isArray(value);
445
- }
446
-
447
- function hasPiNumericFields(value, fields) {
448
- return isPiRecord(value) && fields.every((field) => typeof value[field] === 'number');
449
- }
450
-
451
- function isValidPiUsage(usage) {
452
- if (!hasPiNumericFields(usage, PI_USAGE_FIELDS)) return false;
453
- if (!hasPiNumericFields(usage.cost, PI_COST_FIELDS)) return false;
454
- return (
455
- (usage.cacheWrite1h === undefined || typeof usage.cacheWrite1h === 'number') &&
456
- (usage.reasoning === undefined || typeof usage.reasoning === 'number')
457
- );
458
- }
459
-
460
- function isValidPiAssistantMessage(message) {
461
- return (
462
- isPiRecord(message) &&
463
- message.role === 'assistant' &&
464
- Array.isArray(message.content) &&
465
- isValidPiUsage(message.usage) &&
466
- PI_STOP_REASONS.has(message.stopReason)
467
- );
468
- }
469
-
470
- function piMessageRole(message) {
471
- if (!message || typeof message !== 'object' || Array.isArray(message)) return null;
472
- return typeof message.role === 'string' ? message.role : null;
473
- }
474
-
475
- function applyPiProtocolLine(content, state) {
476
- if (!content) return null;
477
- if (
478
- content.startsWith('[ZEROSHOT] Earlier provider output omitted') ||
479
- content.startsWith('[ZEROSHOT] Provider output record retained') ||
480
- content.startsWith('[ZEROSHOT][PROVIDER_STDERR] ')
481
- ) {
482
- return null;
483
- }
484
- if (state.settled) return piProtocolFailure('Pi emitted output after agent_settled.');
485
- const parsed = parsePiProtocolObject(content);
486
- if (parsed === null) return piProtocolFailure('Pi JSON stream contained malformed output.');
487
- if (typeof parsed.type !== 'string') {
488
- return piProtocolFailure('Pi JSON stream contained an event without a valid type.');
489
- }
490
- if (parsed.type === 'message_end') {
491
- const role = piMessageRole(parsed.message);
492
- if (role === null) return piProtocolFailure('Pi message_end did not contain a valid message.');
493
- if (role !== 'assistant') return null;
494
- if (!isValidPiAssistantMessage(parsed.message)) {
495
- return piProtocolFailure('Pi message_end did not contain a valid assistant message.');
496
- }
497
- state.latestAssistant = parsed.message;
498
- } else if (parsed.type === 'agent_settled') {
499
- state.settled = true;
500
- }
501
- return null;
502
- }
503
-
504
- function extractSettledPiFailure(lines) {
505
- const state = { latestAssistant: null, settled: false };
506
- for (const line of lines) {
507
- const content = stripTimestamp(line);
508
- const failure = applyPiProtocolLine(content, state);
509
- if (failure) return failure;
510
- }
511
-
512
- if (!state.settled) return piProtocolFailure('Pi JSON stream ended before agent_settled.');
513
- if (state.latestAssistant === null) {
514
- return piProtocolFailure('Pi settled without a valid assistant message_end.');
515
- }
516
- return piFailureFromMessage(state.latestAssistant);
517
- }
518
-
519
- function extractCliFailure(output, providerName = 'claude') {
520
- if (providerName === 'pi') {
521
- const lines = typeof output === 'string' ? output.split('\n') : [];
522
- return extractSettledPiFailure(lines);
523
- }
524
- if (!output || typeof output !== 'string') return null;
525
-
526
- const lines = output.split('\n');
527
- // Codex terminal truth is a turn.failed record at the newest end of JSONL output.
528
- // Search it newest-first so a preserved terminal tail wins over older provider chatter.
529
- if (providerName === 'codex') lines.reverse();
530
-
531
- for (const line of lines) {
532
- const content = stripTimestamp(line);
533
- if (!content.startsWith('{')) continue;
534
- try {
535
- const failure = failureFromProviderObject(JSON.parse(content), providerName);
536
- if (failure) return failure;
537
- } catch {
538
- // Ignore non-JSON output lines.
539
- }
540
- }
541
-
542
- return null;
543
- }
544
-
545
- function extractCliError(output, providerName = 'claude') {
546
- const failure = extractCliFailure(output, providerName);
547
- return failure ? { error: failure.error, provider: failure.provider } : null;
548
- }
549
-
550
- /**
551
- * Detects fatal standalone output lines that indicate no task output was produced.
552
- * Only matches when the line itself is the fatal message (not when it appears inside JSON).
553
- *
554
- * @param {string} output - Raw output text
555
- * @returns {boolean} True if a standalone fatal line is present
556
- */
557
- function hasFatalStandaloneOutput(output) {
558
- if (!output || typeof output !== 'string') return false;
559
- const lines = output.split('\n');
560
- for (const line of lines) {
561
- const stripped = stripTimestamp(line).trim();
562
- if (!stripped) continue;
563
- if (/^(task not found|process terminated)\b/i.test(stripped)) {
564
- return true;
565
- }
566
- }
567
- return false;
568
- }
569
-
570
- /**
571
- * Main extraction function - tries all strategies in priority order
572
- *
573
- * @param {string} output - Raw output from AI provider CLI
574
- * @param {string} providerName - Provider name ('claude', 'codex', 'gemini')
575
- * @returns {object|null} Extracted JSON object or null if extraction failed
576
- */
577
- function extractJsonFromOutput(output, providerName = 'claude') {
578
- if (!output || typeof output !== 'string') return null;
579
-
580
- const trimmedOutput = output.trim();
581
- if (!trimmedOutput) return null;
582
-
583
- // Strategy 1: Result wrapper (Claude format)
584
- const fromWrapper = extractFromResultWrapper(trimmedOutput);
585
- if (fromWrapper) return fromWrapper;
586
-
587
- // Strategy 2: Text events (non-Claude providers)
588
- const fromText = extractFromTextEvents(trimmedOutput, providerName);
589
- if (fromText) return fromText;
590
-
591
- // Strategy 3: Markdown extraction
592
- const fromMarkdown = extractFromMarkdown(trimmedOutput);
593
- if (fromMarkdown) return fromMarkdown;
594
-
595
- // Strategy 4: Direct JSON parse (raw output)
596
- const fromDirect = extractDirectJson(trimmedOutput);
597
- if (fromDirect) return fromDirect;
598
-
599
- if (hasFatalStandaloneOutput(trimmedOutput)) {
600
- return null;
601
- }
602
-
603
- return null;
604
- }
605
-
1
+ "use strict";
2
+ const failureExtraction = require("./output-extraction-failures");
3
+ const jsonExtraction = require("./output-extraction-json");
4
+ const { MAX_CLI_ERROR_BYTES, extractClaudeVertexModelError, extractCliError, extractCliFailure } = failureExtraction;
5
+ const { extractDirectJson, extractFromMarkdown, extractFromResultWrapper, extractFromTextEvents, extractJsonFromOutput, extractModelTextFromOutput, hasFatalStandaloneOutput, stripTimestamp, } = jsonExtraction;
606
6
  module.exports = {
607
- MAX_CLI_ERROR_BYTES,
608
- extractJsonFromOutput,
609
- extractModelTextFromOutput,
610
- extractCliFailure,
611
- extractCliError,
612
- extractClaudeVertexModelError,
613
- extractFromResultWrapper,
614
- extractFromTextEvents,
615
- extractFromMarkdown,
616
- extractDirectJson,
617
- stripTimestamp,
618
- hasFatalStandaloneOutput,
7
+ MAX_CLI_ERROR_BYTES,
8
+ extractJsonFromOutput,
9
+ extractModelTextFromOutput,
10
+ extractCliFailure,
11
+ extractCliError,
12
+ extractClaudeVertexModelError,
13
+ extractFromResultWrapper,
14
+ extractFromTextEvents,
15
+ extractFromMarkdown,
16
+ extractDirectJson,
17
+ stripTimestamp,
18
+ hasFatalStandaloneOutput,
619
19
  };
@@ -0,0 +1,30 @@
1
+ import failureExtraction = require('./output-extraction-failures');
2
+ import jsonExtraction = require('./output-extraction-json');
3
+
4
+ const { MAX_CLI_ERROR_BYTES, extractClaudeVertexModelError, extractCliError, extractCliFailure } =
5
+ failureExtraction;
6
+ const {
7
+ extractDirectJson,
8
+ extractFromMarkdown,
9
+ extractFromResultWrapper,
10
+ extractFromTextEvents,
11
+ extractJsonFromOutput,
12
+ extractModelTextFromOutput,
13
+ hasFatalStandaloneOutput,
14
+ stripTimestamp,
15
+ } = jsonExtraction;
16
+
17
+ export = {
18
+ MAX_CLI_ERROR_BYTES,
19
+ extractJsonFromOutput,
20
+ extractModelTextFromOutput,
21
+ extractCliFailure,
22
+ extractCliError,
23
+ extractClaudeVertexModelError,
24
+ extractFromResultWrapper,
25
+ extractFromTextEvents,
26
+ extractFromMarkdown,
27
+ extractDirectJson,
28
+ stripTimestamp,
29
+ hasFatalStandaloneOutput,
30
+ };