@zhushanwen/subagent-core 0.2.0 → 0.5.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 (347) hide show
  1. package/README.md +45 -2
  2. package/agents/analyst.md +60 -0
  3. package/agents/coder.md +69 -0
  4. package/agents/debugger.md +66 -0
  5. package/agents/doc-reviewer.md +49 -0
  6. package/agents/explorer.md +63 -0
  7. package/agents/general-purpose.md +32 -0
  8. package/agents/orchestrator.md +61 -0
  9. package/agents/planner.md +53 -0
  10. package/agents/researcher.md +67 -0
  11. package/agents/reviewer.md +73 -0
  12. package/dist/chunk-43ONBFZX.js +240 -0
  13. package/dist/chunk-APZY4IME.js +27 -0
  14. package/dist/chunk-V3VHZ2VX.js +59 -0
  15. package/dist/execution/engine/engines/zcode/constants.cjs +62 -9
  16. package/dist/execution/engine/engines/zcode/constants.d.cts +116 -12
  17. package/dist/execution/engine/engines/zcode/constants.d.ts +116 -12
  18. package/dist/execution/engine/engines/zcode/constants.js +39 -7
  19. package/dist/execution/engine/engines/zcode/reader.d.cts +2 -1
  20. package/dist/execution/engine/engines/zcode/reader.d.ts +2 -1
  21. package/dist/execution/engine/engines/zcode/reader.js +4 -234
  22. package/dist/execution/engine/paths.js +7 -19
  23. package/dist/index.cjs +18234 -1277
  24. package/dist/index.d.cts +5646 -673
  25. package/dist/index.d.ts +5646 -673
  26. package/dist/index.js +17828 -1277
  27. package/dist/{types-BxyAidGf.d.cts → types-Dv4QhSJ_.d.cts} +678 -112
  28. package/dist/{types-BxyAidGf.d.ts → types-Dv4QhSJ_.d.ts} +678 -112
  29. package/package.json +7 -4
  30. package/src/__tests__/agent-opts-resolver-schema-prompt.test.ts +0 -1
  31. package/src/__tests__/append-system-prompt-assembly.test.ts +8 -7
  32. package/src/__tests__/fr4-get-state-handshake.test.ts +2 -2
  33. package/src/__tests__/m2-append-content-probe.test.ts +0 -1
  34. package/src/__tests__/manifest-store.test.ts +10 -9
  35. package/src/__tests__/record-store-cache.test.ts +0 -2
  36. package/src/__tests__/record-store-index.test.ts +1 -2
  37. package/src/__tests__/review-fix-loop-script.test.ts +93 -3
  38. package/src/__tests__/review-fix-loop-utils.test.ts +31 -10
  39. package/src/__tests__/robustness-low-batch1.test.ts +6 -5
  40. package/src/__tests__/robustness-medium-batch1.test.ts +2 -2
  41. package/src/__tests__/robustness-medium-batch2.test.ts +17 -6
  42. package/src/__tests__/robustness-medium-batch4.test.ts +2 -2
  43. package/src/__tests__/session-runner.test.ts +1 -1
  44. package/src/__tests__/smoke.test.ts +9 -2
  45. package/src/core/__tests__/host-services.test.ts +2 -2
  46. package/src/core/__tests__/logger.test.ts +1 -1
  47. package/src/core/error-message.ts +9 -0
  48. package/src/core/host-services.ts +21 -5
  49. package/src/core/notify-ports.ts +18 -5
  50. package/src/execution/__tests__/agent-profile.test.ts +232 -0
  51. package/src/execution/__tests__/agent-registry.test.ts +370 -0
  52. package/src/execution/__tests__/agent-result-mapper.test.ts +18 -2
  53. package/src/execution/__tests__/agents-assembly.test.ts +219 -0
  54. package/src/execution/__tests__/ask-user-transit-e2e.test.ts +6 -6
  55. package/src/execution/__tests__/chat-engine-routing.test.ts +136 -30
  56. package/src/execution/__tests__/chatmode-first-round-closure-spawn.test.ts +5 -4
  57. package/src/execution/__tests__/cold-resurrect.test.ts +283 -0
  58. package/src/execution/__tests__/create-concurrency-pool.test.ts +194 -0
  59. package/src/execution/__tests__/delivery-methods.test.ts +77 -62
  60. package/src/execution/__tests__/descendant-sweep-guards.test.ts +220 -0
  61. package/src/execution/__tests__/descendant-sweep.test.ts +269 -0
  62. package/src/execution/__tests__/dialog-queue.test.ts +199 -1
  63. package/src/execution/__tests__/engine-model-validation.test.ts +741 -0
  64. package/src/execution/__tests__/epipe-fallback.test.ts +31 -24
  65. package/src/execution/__tests__/execute-and-await-worktree.test.ts +21 -91
  66. package/src/execution/__tests__/execute-nesting.test.ts +34 -188
  67. package/src/execution/__tests__/execution-record.test.ts +217 -60
  68. package/src/execution/__tests__/execution-runtime-face.test.ts +272 -0
  69. package/src/execution/__tests__/explicit-agent-ref-guard.test.ts +3 -3
  70. package/src/execution/__tests__/finalize-record.test.ts +278 -16
  71. package/src/execution/__tests__/gc-timer.test.ts +57 -2
  72. package/src/execution/__tests__/get-record-for-action-restart.test.ts +14 -12
  73. package/src/execution/__tests__/get-state-handshake.test.ts +127 -0
  74. package/src/execution/__tests__/helpers/mock-extension-api.ts +1 -1
  75. package/src/execution/__tests__/helpers/session-runner-mocks.ts +113 -0
  76. package/src/execution/__tests__/helpers/spawn-mock.ts +150 -3
  77. package/src/execution/__tests__/helpers/subagent-service-mocks.ts +137 -0
  78. package/src/execution/__tests__/keep-alive-no-progress.test.ts +280 -0
  79. package/src/execution/__tests__/kill-all-escalation.test.ts +196 -0
  80. package/src/execution/__tests__/lifecycle-manager-idle-timer-identity.test.ts +117 -0
  81. package/src/execution/__tests__/lifecycle-manager.test.ts +39 -0
  82. package/src/execution/__tests__/lifecycle-predicates.test.ts +1 -2
  83. package/src/execution/__tests__/manifest-parentid.test.ts +4 -4
  84. package/src/execution/__tests__/manifest-store-tmp-recovery.test.ts +99 -0
  85. package/src/execution/__tests__/max-turns-to-watchdog-ms.test.ts +113 -0
  86. package/src/execution/__tests__/model-resolver.test.ts +2 -2
  87. package/src/execution/__tests__/nested-visibility-env-propagation.test.ts +23 -121
  88. package/src/execution/__tests__/nested-visibility.test.ts +2 -0
  89. package/src/execution/__tests__/notify-ledger.test.ts +1249 -0
  90. package/src/execution/__tests__/output-collector.test.ts +117 -6
  91. package/src/execution/__tests__/pi-invocation.test.ts +1 -1
  92. package/src/execution/__tests__/record-store-orphan-revive.test.ts +159 -0
  93. package/src/execution/__tests__/record-store.test.ts +89 -5
  94. package/src/execution/__tests__/records-cwd-isolation.test.ts +2 -2
  95. package/src/execution/__tests__/recursive-visibility-baseline.test.ts +29 -132
  96. package/src/execution/__tests__/recursive-visibility-env.test.ts +55 -179
  97. package/src/execution/__tests__/rpc-mode.test.ts +2 -2
  98. package/src/execution/__tests__/run-and-finalize-anchoring.test.ts +387 -0
  99. package/src/execution/__tests__/run-and-finalize-chatmode.test.ts +19 -9
  100. package/src/execution/__tests__/run-spawn-chatmode-settled.test.ts +5 -4
  101. package/src/execution/__tests__/run-spawn-edges.test.ts +418 -26
  102. package/src/execution/__tests__/run-spawn-integration.test.ts +3 -3
  103. package/src/execution/__tests__/run-spawn-resume.test.ts +2 -2
  104. package/src/execution/__tests__/run-spawn-rpc-mode.test.ts +2 -2
  105. package/src/execution/__tests__/run-spawn-stdout-callback-throw.test.ts +16 -8
  106. package/src/execution/__tests__/service-kill-escalation.test.ts +91 -0
  107. package/src/execution/__tests__/session-context-resolver.test.ts +0 -2
  108. package/src/execution/__tests__/session-file-gc.test.ts +35 -0
  109. package/src/execution/__tests__/session-pending.test.ts +471 -0
  110. package/src/execution/__tests__/session-reconstructor.test.ts +366 -15
  111. package/src/execution/__tests__/session-runner-branch-cache-lru.test.ts +110 -0
  112. package/src/execution/__tests__/session-runner-close-prune.test.ts +181 -0
  113. package/src/execution/__tests__/session-runner-dispatch.test.ts +489 -0
  114. package/src/execution/__tests__/session-runner-epipe.test.ts +4 -3
  115. package/src/execution/__tests__/session-runner-heartbeat-idle-fallback.test.ts +227 -0
  116. package/src/execution/__tests__/session-runner-lifecycle-helpers.test.ts +290 -0
  117. package/src/execution/__tests__/session-runner-schema-env.test.ts +7 -5
  118. package/src/execution/__tests__/settled-watchdog.test.ts +524 -0
  119. package/src/execution/__tests__/spawn-args.test.ts +11 -10
  120. package/src/execution/__tests__/spawn-event-adapter-rpc.test.ts +26 -23
  121. package/src/execution/__tests__/spawn-event-adapter.test.ts +1 -1
  122. package/src/execution/__tests__/spawn-worktree-guidance.test.ts +5 -4
  123. package/src/execution/__tests__/spawned-children.test.ts +155 -11
  124. package/src/execution/__tests__/start-sync-model-guard.test.ts +4 -4
  125. package/src/execution/__tests__/stdin-writer.test.ts +6 -4
  126. package/src/execution/__tests__/stream-sink-retirement.test.ts +6 -6
  127. package/src/execution/__tests__/subagent-actions-core.test.ts +1017 -0
  128. package/src/execution/__tests__/subagent-service-message-close.test.ts +99 -35
  129. package/src/execution/__tests__/subagent-service-multiproc-guard.test.ts +174 -0
  130. package/src/execution/__tests__/subagent-service-notify-gate.test.ts +271 -0
  131. package/src/execution/__tests__/subagent-service-parent-guard.test.ts +33 -29
  132. package/src/execution/__tests__/subagent-service-recovery-bounds.test.ts +341 -0
  133. package/src/execution/__tests__/subagent-service.test.ts +37 -30
  134. package/src/execution/__tests__/subprocess-agent-runner-routing.test.ts +88 -12
  135. package/src/execution/__tests__/subprocess-agent-runner-timeout.test.ts +75 -0
  136. package/src/execution/__tests__/subprocess-agent-runner.test.ts +22 -20
  137. package/src/execution/__tests__/temp-prompt.test.ts +1 -1
  138. package/src/execution/__tests__/timeout-integration.test.ts +13 -12
  139. package/src/execution/__tests__/turn-limiter-semantics.test.ts +1 -1
  140. package/src/execution/__tests__/turn-limiter.test.ts +1 -1
  141. package/src/execution/__tests__/ui-request-handler-factory.test.ts +107 -7
  142. package/src/execution/__tests__/ui-request-handler.test.ts +4 -3
  143. package/src/execution/__tests__/ui-request-queue.test.ts +167 -2
  144. package/src/execution/__tests__/worktree-git-ops.test.ts +571 -0
  145. package/src/execution/__tests__/worktree-manager.test.ts +14 -5
  146. package/src/execution/__tests__/worktree-pid-registration.integration.test.ts +4 -3
  147. package/src/execution/__tests__/worktree-reconcile-aging.test.ts +204 -0
  148. package/src/execution/agent-registry.ts +298 -30
  149. package/src/execution/agent-result-mapper.ts +3 -0
  150. package/src/execution/agents-assembly.ts +88 -0
  151. package/src/execution/cold-resurrect.ts +199 -0
  152. package/src/execution/concurrency-pool.ts +71 -9
  153. package/src/execution/dialog-queue.ts +101 -3
  154. package/src/execution/engine/__tests__/common/capability-gate.test.ts +91 -0
  155. package/src/execution/engine/__tests__/common/data-dir.test.ts +1 -1
  156. package/src/execution/engine/__tests__/common/journal-wiring.test.ts +84 -0
  157. package/src/execution/engine/__tests__/common/kill-chain.test.ts +34 -7
  158. package/src/execution/engine/__tests__/common/persona-router.test.ts +4 -5
  159. package/src/execution/engine/__tests__/common/pool-manager.test.ts +211 -51
  160. package/src/execution/engine/__tests__/common/session-view-service-zcode-dbpath.test.ts +149 -0
  161. package/src/execution/engine/__tests__/common/session-view-service.test.ts +499 -0
  162. package/src/execution/engine/__tests__/conformance/contract.abort.test.ts +56 -99
  163. package/src/execution/engine/__tests__/conformance/contract.agent-events.test.ts +88 -15
  164. package/src/execution/engine/__tests__/conformance/engine-conformance.live.test.ts +33 -7
  165. package/src/execution/engine/__tests__/conformance/golden-replay.pi.test.ts +1 -1
  166. package/src/execution/engine/__tests__/conformance/golden-replay.zcode.test.ts +75 -54
  167. package/src/execution/engine/__tests__/conformance/zcode-appserver-harness.ts +128 -0
  168. package/src/execution/engine/__tests__/engine-discovery.test.ts +15 -3
  169. package/src/execution/engine/__tests__/model-prompt.test.ts +15 -3
  170. package/src/execution/engine/__tests__/registry.test.ts +94 -3
  171. package/src/execution/engine/__tests__/routing.test.ts +115 -6
  172. package/src/execution/engine/common/capability-gate.ts +92 -0
  173. package/src/execution/engine/common/journal-wiring.ts +97 -0
  174. package/src/execution/engine/common/kill-chain.ts +42 -10
  175. package/src/execution/engine/common/nesting-guard.ts +66 -0
  176. package/src/execution/engine/common/persona-router.ts +18 -8
  177. package/src/execution/engine/common/pool-manager.ts +332 -78
  178. package/src/execution/engine/common/session-view-service.ts +506 -0
  179. package/src/execution/engine/common/session-view-types.ts +125 -0
  180. package/src/execution/engine/engine-discovery.ts +12 -16
  181. package/src/execution/engine/engines/pi/__tests__/pi-engine.test.ts +174 -28
  182. package/src/execution/engine/engines/pi/__tests__/spawn-opts-direct.test.ts +257 -0
  183. package/src/execution/{argv-mirror.ts → engine/engines/pi/argv-mirror.ts} +43 -21
  184. package/src/execution/{get-state-handshake.ts → engine/engines/pi/get-state-handshake.ts} +86 -11
  185. package/src/execution/{output-collector.ts → engine/engines/pi/output-collector.ts} +108 -19
  186. package/src/execution/engine/engines/pi/pi-engine.ts +434 -38
  187. package/src/execution/{pi-invocation.ts → engine/engines/pi/pi-invocation.ts} +2 -2
  188. package/src/execution/engine/engines/pi/reader.ts +11 -0
  189. package/src/execution/engine/engines/pi/registration.ts +4 -2
  190. package/src/execution/engine/engines/pi/session-runner.ts +2840 -0
  191. package/src/execution/{spawn-event-adapter.ts → engine/engines/pi/spawn-event-adapter.ts} +75 -34
  192. package/src/execution/{stdin-writer.ts → engine/engines/pi/stdin-writer.ts} +10 -9
  193. package/src/execution/{temp-prompt.ts → engine/engines/pi/temp-prompt.ts} +2 -2
  194. package/src/execution/{turn-limiter.ts → engine/engines/pi/turn-limiter.ts} +1 -1
  195. package/src/execution/engine/engines/zcode/__tests__/__fixtures__/fake-appserver.mjs +301 -0
  196. package/src/execution/engine/engines/zcode/__tests__/__fixtures__/zcode-golden-appserver.json +36 -0
  197. package/src/execution/engine/engines/zcode/__tests__/appserver-launcher.test.ts +321 -0
  198. package/src/execution/engine/engines/zcode/__tests__/connection.test.ts +473 -0
  199. package/src/execution/engine/engines/zcode/__tests__/parser.test.ts +7 -210
  200. package/src/execution/engine/engines/zcode/__tests__/preparer.test.ts +6 -110
  201. package/src/execution/engine/engines/zcode/__tests__/session-channel-dispose-harvest.test.ts +247 -0
  202. package/src/execution/engine/engines/zcode/__tests__/session-channel-turn-timers.test.ts +451 -0
  203. package/src/execution/engine/engines/zcode/__tests__/session-channel.test.ts +792 -0
  204. package/src/execution/engine/engines/zcode/__tests__/zcode-engine-appserver.test.ts +782 -0
  205. package/src/execution/engine/engines/zcode/__tests__/zcode-engine-degrade.test.ts +168 -0
  206. package/src/execution/engine/engines/zcode/__tests__/zcode-engine-dispose.test.ts +210 -0
  207. package/src/execution/engine/engines/zcode/__tests__/zcode-engine-retry.test.ts +353 -0
  208. package/src/execution/engine/engines/zcode/__tests__/zcode-engine-status.test.ts +282 -0
  209. package/src/execution/engine/engines/zcode/__tests__/zcode-engine-timeout.test.ts +372 -0
  210. package/src/execution/engine/engines/zcode/__tests__/zcode-engine.live.test.ts +65 -47
  211. package/src/execution/engine/engines/zcode/appserver-launcher.ts +167 -0
  212. package/src/execution/engine/engines/zcode/connection.ts +598 -0
  213. package/src/execution/engine/engines/zcode/constants.ts +147 -14
  214. package/src/execution/engine/engines/zcode/golden-sample.ts +42 -34
  215. package/src/execution/engine/engines/zcode/parser.ts +12 -346
  216. package/src/execution/engine/engines/zcode/preparer.ts +22 -150
  217. package/src/execution/engine/engines/zcode/session-channel.ts +968 -0
  218. package/src/execution/engine/engines/zcode/zcode-engine.ts +1023 -250
  219. package/src/execution/engine/host-task-spec.ts +32 -36
  220. package/src/execution/engine/model-validation.ts +177 -0
  221. package/src/execution/engine/port.ts +65 -7
  222. package/src/execution/engine/registry.ts +53 -0
  223. package/src/execution/engine/routing.ts +75 -1
  224. package/src/execution/engine/types.ts +30 -103
  225. package/src/execution/execution-record.ts +222 -144
  226. package/src/execution/finalize-record.ts +181 -85
  227. package/src/execution/idle-gc.ts +28 -0
  228. package/src/execution/lifecycle-manager.ts +27 -3
  229. package/src/execution/lifecycle-predicates.ts +1 -1
  230. package/src/execution/manifest-store.ts +53 -62
  231. package/src/execution/notifier.ts +10 -10
  232. package/src/execution/notify-host.ts +212 -0
  233. package/src/execution/notify-ledger.ts +117 -16
  234. package/src/execution/record-entry.ts +8 -2
  235. package/src/execution/record-store.ts +148 -88
  236. package/src/execution/round-settlement.ts +93 -0
  237. package/src/execution/session-file-gc.ts +96 -62
  238. package/src/execution/session-pending.ts +213 -62
  239. package/src/execution/session-reconstructor.ts +256 -143
  240. package/src/execution/sessions-index.ts +127 -102
  241. package/src/execution/settled-watchdog.ts +311 -0
  242. package/src/execution/subagent-actions-core.ts +686 -0
  243. package/src/execution/subagent-service.ts +1106 -907
  244. package/src/execution/subprocess-agent-runner.ts +144 -97
  245. package/src/execution/types.ts +9 -0
  246. package/src/execution/ui-request-handler-factory.ts +126 -75
  247. package/src/execution/ui-request-queue.ts +50 -19
  248. package/src/execution/worktree-git-ops.ts +397 -0
  249. package/src/execution/worktree-manager.ts +72 -10
  250. package/src/execution/worktree-registry.ts +6 -12
  251. package/src/index.ts +542 -9
  252. package/src/orchestration/__tests__/__fixtures__/worker-template.snapshot.txt +42 -3
  253. package/src/orchestration/__tests__/agent-call-catch-fallback.test.ts +3 -5
  254. package/src/orchestration/__tests__/agent-call-stream.test.ts +2 -2
  255. package/src/orchestration/__tests__/args-meta.test.ts +358 -0
  256. package/src/orchestration/__tests__/args-validator.test.ts +14 -0
  257. package/src/orchestration/__tests__/error-recovery-rebuild-failure.test.ts +312 -0
  258. package/src/orchestration/__tests__/error-recovery-terminal-hardening.test.ts +384 -0
  259. package/src/orchestration/__tests__/execute-agent-call.test.ts +151 -11
  260. package/src/orchestration/__tests__/file-run-store-prune.test.ts +168 -0
  261. package/src/orchestration/__tests__/file-run-store-throttle.test.ts +168 -0
  262. package/src/orchestration/__tests__/file-run-store.test.ts +390 -0
  263. package/src/orchestration/__tests__/helpers/flush-microtasks.ts +13 -0
  264. package/src/orchestration/__tests__/launcher-nested-workflow.test.ts +34 -0
  265. package/src/orchestration/__tests__/lifecycle-abort-broadcast-signal.test.ts +357 -0
  266. package/src/orchestration/__tests__/lifecycle-recover-crashed.test.ts +289 -0
  267. package/src/orchestration/__tests__/lifecycle-runid-injection.test.ts +3 -3
  268. package/src/orchestration/__tests__/lifecycle.test.ts +84 -5
  269. package/src/orchestration/__tests__/non-cloneable-return-e2e.test.ts +1 -1
  270. package/src/orchestration/__tests__/run-snapshot.test.ts +356 -0
  271. package/src/orchestration/__tests__/script-generate.test.ts +314 -0
  272. package/src/orchestration/__tests__/script-lint.test.ts +17 -0
  273. package/src/orchestration/__tests__/test-mocks.ts +2 -0
  274. package/src/orchestration/__tests__/worker-exit-without-result.test.ts +7 -6
  275. package/src/orchestration/__tests__/worker-message-pump-finalize-run.test.ts +229 -0
  276. package/src/orchestration/__tests__/{error-recovery-handlers.test.ts → worker-message-pump-handlers.test.ts} +28 -27
  277. package/src/orchestration/__tests__/{error-recovery-postmessage-defense.test.ts → worker-message-pump-postmessage-defense.test.ts} +8 -8
  278. package/src/orchestration/__tests__/{error-recovery-serialize-failed-result.test.ts → worker-message-pump-serialize-failed-result.test.ts} +2 -2
  279. package/src/orchestration/__tests__/{error-recovery-workflow-call.test.ts → worker-message-pump-workflow-call.test.ts} +1 -1
  280. package/src/orchestration/__tests__/worker-pending-timeout-abort.test.ts +275 -0
  281. package/src/orchestration/__tests__/worker-script-builder-runtime.test.ts +78 -1
  282. package/src/orchestration/__tests__/worker-script-builder.test.ts +1 -1
  283. package/src/orchestration/__tests__/workflow-files.test.ts +186 -0
  284. package/src/orchestration/__tests__/workflow-nesting-e2e.test.ts +1 -1
  285. package/src/orchestration/__tests__/workflow-run-summary.test.ts +119 -0
  286. package/src/orchestration/__tests__/workflow-script-registry-impl.test.ts +124 -0
  287. package/src/orchestration/agent-opts-resolver.ts +8 -8
  288. package/src/orchestration/args-meta.ts +198 -0
  289. package/src/orchestration/args-validator.ts +53 -31
  290. package/src/orchestration/execute-agent-call.ts +25 -79
  291. package/src/orchestration/file-run-store.ts +327 -0
  292. package/src/orchestration/launcher.ts +160 -104
  293. package/src/orchestration/lifecycle.ts +371 -97
  294. package/src/orchestration/models/agent-call.ts +7 -7
  295. package/src/orchestration/models/budget.ts +5 -5
  296. package/src/orchestration/models/ports.ts +4 -4
  297. package/src/orchestration/models/run-runtime.ts +15 -15
  298. package/src/orchestration/models/trace.ts +9 -9
  299. package/src/orchestration/models/types.ts +111 -22
  300. package/src/orchestration/models/workflow-run.ts +28 -28
  301. package/src/orchestration/models/workflow-script.ts +4 -4
  302. package/src/orchestration/run-snapshot.ts +266 -0
  303. package/src/orchestration/script-generate.ts +154 -0
  304. package/src/orchestration/script-lint.ts +123 -90
  305. package/src/orchestration/worker-handle.ts +10 -10
  306. package/src/orchestration/worker-host.ts +10 -10
  307. package/src/orchestration/{error-recovery.ts → worker-message-pump.ts} +498 -221
  308. package/src/orchestration/worker-script-builder.ts +401 -346
  309. package/src/orchestration/workflow-files.ts +37 -11
  310. package/src/orchestration/workflow-run-summary.ts +69 -0
  311. package/src/orchestration/workflow-script-registry-impl.ts +31 -9
  312. package/src/shared/__tests__/agent-ref.test.ts +209 -2
  313. package/src/shared/__tests__/atomic-write.test.ts +267 -0
  314. package/src/shared/__tests__/bounded-serialize.test.ts +236 -0
  315. package/src/shared/__tests__/injection-render.test.ts +518 -0
  316. package/src/shared/__tests__/meta-parser.test.ts +151 -0
  317. package/src/shared/__tests__/resource-discovery-host-roots.test.ts +474 -0
  318. package/src/shared/__tests__/resource-discovery.test.ts +261 -217
  319. package/src/shared/agent-ref.ts +143 -2
  320. package/src/shared/atomic-write.ts +323 -0
  321. package/src/shared/bounded-serialize.ts +154 -0
  322. package/src/shared/injection-render.ts +279 -0
  323. package/src/shared/meta-parser.ts +182 -68
  324. package/src/shared/model-ref.ts +15 -2
  325. package/src/shared/resource-discovery.ts +97 -204
  326. package/src/shared/resource-meta.ts +14 -0
  327. package/src/shared/schema-jsonify.ts +1 -1
  328. package/src/shared/xml-injection.ts +9 -9
  329. package/workflows/README.md +9 -9
  330. package/workflows/chain.js +4 -2
  331. package/workflows/map-reduce.js +5 -3
  332. package/workflows/parallel.js +5 -3
  333. package/workflows/review-fix-loop-utils.cjs +165 -92
  334. package/workflows/review-fix-loop-utils.d.cts +287 -0
  335. package/workflows/review-fix-loop.js +18 -7
  336. package/workflows/scatter-gather.js +4 -2
  337. package/dist/chunk-3VOERJPJ.js +0 -22
  338. package/src/execution/__tests__/execute-options-mapper.test.ts +0 -200
  339. package/src/execution/engine/engines/pi/__tests__/task-spec-mapper.test.ts +0 -164
  340. package/src/execution/engine/engines/pi/task-spec-mapper.ts +0 -100
  341. package/src/execution/engine/engines/zcode/__tests__/__fixtures__/zcode-golden-spawn.json +0 -39
  342. package/src/execution/engine/engines/zcode/__tests__/launcher.test.ts +0 -150
  343. package/src/execution/engine/engines/zcode/__tests__/zcode-engine.test.ts +0 -580
  344. package/src/execution/engine/engines/zcode/launcher.ts +0 -161
  345. package/src/execution/execute-options-mapper.ts +0 -115
  346. package/src/execution/session-runner.ts +0 -1789
  347. package/src/shared/__tests__/resource-discovery-manifest-cache.test.ts +0 -288
@@ -0,0 +1,266 @@
1
+ // src/orchestration/run-snapshot.ts
2
+ //
3
+ // WorkflowRun 快照 codec(下沉收口 D4——设计件 subagent-core-sink-design.md U8)。
4
+ //
5
+ // 为什么需要它:WorkflowRun 的 JSONL 快照投影此前两宿主各写一份(core
6
+ // file-run-store.ts 的 toSnapshot/fromSnapshot 与 pi 壳 jsonl-run-store.ts 的
7
+ // serializeRun/deserializeRun)——字段集一致但语义细节分叉(live-strip、版本
8
+ // guard、budgetRef 剔除),修一处漏一处。本模块收敛为单源 codec:字段演进
9
+ // 单点(G2),两宿主(FileRunStore / pi JsonlRunStore)各自只保留 IO 策略
10
+ // (rewrite/append/去抖),投影与版本衔接语义全部经此模块。
11
+ //
12
+ // 版本衔接三裁决(D4,含审查 MF-2):
13
+ // ① 版本值沿用 pi 现有字符串 "wf-run-v2"——pi 存量逐字节可读;
14
+ // ② FileRunStore 存量行(无 v 字段)按「缺版本 = 当前版本」宽容读取,写入时
15
+ // 补 v,不做自动迁移——「缺 v 宽容」实现于 FileRunStore 层预处理(读出的行
16
+ // 先补缺省 v 再进 fromRunSnapshot),**不内聚进本 codec**:codec 层面缺 v
17
+ // 即拒绝,保 pi 侧「v1 存量静默跳过」既有语义不被宽容化误读;
18
+ // ③ guard 语义 = v 不匹配当前版本即拒(字符串版本无大小序,不引入比较逻辑);
19
+ // 「跳过 + warn」的可见性由宿主 store 层补(本 codec 只返回 undefined)。
20
+ //
21
+ // 序列化形态(键序即 JSON.stringify 输出序)逐键对齐 pi serializeRun 现网形态,
22
+ // 使 pi 切换本 codec 后存量往返逐字节一致(⛔5)。
23
+
24
+ import { AgentCall } from "./models/agent-call.ts";
25
+ import { Budget } from "./models/budget.ts";
26
+ import type { RunSpec } from "./models/run-spec.ts";
27
+ import type {
28
+ RunStatus,
29
+ DoneReason,
30
+ WorkerLogEntry,
31
+ ExecutionTraceNode,
32
+ AgentCallOpts,
33
+ AgentResult,
34
+ } from "./models/types.ts";
35
+ import { Trace } from "./models/trace.ts";
36
+ import { WorkflowRun } from "./models/workflow-run.ts";
37
+ import type { WorkflowRunMeta } from "./models/workflow-run.ts";
38
+
39
+ /**
40
+ * 快照格式版本(D4 裁决①:字符串相等比较,无大小序)。
41
+ *
42
+ * 版本历史(沿用 pi jsonl-run-store 口径):
43
+ * - wf-run-v1:status 三态(含 paused)、meta 含 pausedAt(pi 旧格式,读路径拒绝)。
44
+ * - wf-run-v2(当前):status 两态(running/done)、meta 无 pausedAt。
45
+ *
46
+ * 升级格式时 bump 此常量——旧版本快照经 fromRunSnapshot 返回 undefined,由
47
+ * 宿主 store 层决定跳过可见性(FileRunStore warn / pi 静默)。
48
+ */
49
+ export const SNAPSHOT_VERSION = "wf-run-v2" as const;
50
+
51
+ /** Budget 实例的可序列化投影(构造 opts 同形,重水合直接 new Budget(...))。 */
52
+ interface BudgetSnapshot {
53
+ maxTokens?: number;
54
+ maxCost?: number;
55
+ maxTimeMs?: number;
56
+ usedTokens: number;
57
+ usedCost: number;
58
+ totalCallCount: number;
59
+ }
60
+
61
+ /**
62
+ * AgentCall 实例的可序列化投影。traceNode 整体落盘(节点引用不可序列化,
63
+ * 落盘值拷贝;重水合后 D-10「引用共享」由 fromRunSnapshot 的 trace 回链尽力
64
+ * 恢复——Trace.fromArray 注释先例)。
65
+ */
66
+ interface CallSnapshot {
67
+ id: number;
68
+ opts: AgentCallOpts;
69
+ status: "pending" | "running" | "done";
70
+ attempts: number;
71
+ result?: AgentResult;
72
+ sessionId?: string;
73
+ sessionFile?: string;
74
+ traceNode: ExecutionTraceNode;
75
+ }
76
+
77
+ /**
78
+ * WorkflowRun 的持久化快照形态(JSONL 单行,全量而非增量)。
79
+ *
80
+ * 形态与 pi 壳 jsonl-run-store.ts 的 RunSnapshot 同构(v 字段含内)——两宿主
81
+ * 存量互读的前提,任何字段增删必须同步两处并评估存量行。
82
+ */
83
+ export interface RunSnapshot {
84
+ v: typeof SNAPSHOT_VERSION;
85
+ runId: string;
86
+ spec: RunSpec;
87
+ state: {
88
+ status: RunStatus;
89
+ reason?: DoneReason;
90
+ budget: BudgetSnapshot;
91
+ calls: CallSnapshot[];
92
+ trace: ExecutionTraceNode[];
93
+ errorLogs: WorkerLogEntry[];
94
+ error?: string;
95
+ scriptResult?: unknown;
96
+ };
97
+ meta: WorkflowRunMeta;
98
+ }
99
+
100
+ // ── 序列化 ──────────────────────────────────────────────────
101
+
102
+ /**
103
+ * WorkflowRun → 单行快照。
104
+ *
105
+ * - 补 v 字段(D4 裁决②:写入恒带当前版本)。
106
+ * - strip live(防御内聚):calls[].traceNode 与 trace 数组节点的 `live` 运行期
107
+ * 对象剥除——ExecutionRecord 含可变 turns[]/controller,不可序列化且跨进程
108
+ * 必死(重跑时由 dispatchAgentCall 重建);strip 产出新对象,不 mutate 内存
109
+ * 中的 run(save 后 run 可继续跑)。
110
+ * - spec.budgetRef 剔除:父 Budget 共享引用是进程内优化(嵌套 workflow 预算
111
+ * 共享),非持久化数据;Budget 实例若混入 spec 落盘将退化为普通对象投影
112
+ * (重水合后类型不符的脏字段)——重水合后 budget 从 state.budget 独立重建,
113
+ * 嵌套 run 的预算共享不跨进程存活。
114
+ * - runtime 不落盘(worker/controller/timer 不可序列化且跨进程必死——重水合
115
+ * 语义见 WorkflowRun.reconstruct 注释)。
116
+ */
117
+ export function toRunSnapshot(run: WorkflowRun): RunSnapshot {
118
+ const { budgetRef: _budgetRef, ...spec } = run.spec;
119
+ return {
120
+ v: SNAPSHOT_VERSION,
121
+ runId: run.runId,
122
+ spec,
123
+ state: {
124
+ status: run.state.status,
125
+ reason: run.state.reason,
126
+ budget: {
127
+ maxTokens: run.state.budget.maxTokens,
128
+ maxCost: run.state.budget.maxCost,
129
+ maxTimeMs: run.state.budget.maxTimeMs,
130
+ usedTokens: run.state.budget.usedTokens,
131
+ usedCost: run.state.budget.usedCost,
132
+ totalCallCount: run.state.budget.totalCallCount,
133
+ },
134
+ calls: Array.from(run.state.calls.values(), (c) => {
135
+ // strip live(同 trace 序列化,不持久化运行期对象)
136
+ const { live: _live, ...traceNodeRest } = c.traceNode;
137
+ return {
138
+ id: c.id,
139
+ opts: c.opts,
140
+ status: c.status,
141
+ attempts: c.attempts,
142
+ result: c.result,
143
+ sessionId: c.sessionId,
144
+ sessionFile: c.sessionFile,
145
+ traceNode: traceNodeRest,
146
+ };
147
+ }),
148
+ // trace 节点浅拷贝时 strip live 字段
149
+ trace: run.state.trace.toArray().map(({ live: _live, ...rest }) => rest),
150
+ errorLogs: run.state.errorLogs,
151
+ error: run.state.error,
152
+ scriptResult: run.state.scriptResult,
153
+ },
154
+ meta: run.meta,
155
+ };
156
+ }
157
+
158
+ // ── 重水合 ──────────────────────────────────────────────────
159
+
160
+ /** 「truthy 且 typeof object」——与原内联守卫 `!x || typeof x !== "object"` 拒绝集一致。 */
161
+ function isPresentObject(v: unknown): v is object {
162
+ return !!v && typeof v === "object";
163
+ }
164
+
165
+ /** 通过形状校验的快照视图:顶层必填字段(v/runId/spec/state/meta)均已验存在。 */
166
+ interface ValidatedSnapshot {
167
+ v: typeof SNAPSHOT_VERSION;
168
+ runId: string;
169
+ spec: RunSpec;
170
+ state: NonNullable<RunSnapshot["state"]>;
171
+ meta: WorkflowRunMeta;
172
+ }
173
+
174
+ /**
175
+ * 顶层形状校验(检查顺序与原内联守卫逐条一致)。
176
+ *
177
+ * 含 D4 裁决③ version guard(字符串相等,无大小序):v 不等于当前版本即拒
178
+ * (含缺版本——「缺 v 宽容」是 FileRunStore 层预处理职责,不内聚进本 codec;
179
+ * pi 侧对 v1 存量行的静默跳过语义依赖此拒绝行为)。
180
+ */
181
+ function isValidSnapshotShape(s: Partial<RunSnapshot>): s is ValidatedSnapshot {
182
+ if (s.v !== SNAPSHOT_VERSION) return false;
183
+ if (typeof s.runId !== "string" || !s.runId) return false;
184
+ if (!isPresentObject(s.spec)) return false;
185
+ const st = s.state;
186
+ if (!isPresentObject(st)) return false;
187
+ if (st.status !== "running" && st.status !== "done") return false;
188
+ if (!isPresentObject(st.budget)) return false;
189
+ if (!Array.isArray(st.calls) || !Array.isArray(st.trace)) return false;
190
+ if (!isPresentObject(s.meta)) return false;
191
+ return true;
192
+ }
193
+
194
+ /** call.traceNode → Trace 节点回链(D-10 尽力恢复,匹配不到退化为独立浅拷贝)。 */
195
+ function linkTraceNode(c: CallSnapshot, trace: Trace): ExecutionTraceNode | undefined {
196
+ return (
197
+ trace.toArray().find((n) => n.stepIndex === c.traceNode?.stepIndex) ??
198
+ (c.traceNode ? { ...c.traceNode } : undefined)
199
+ );
200
+ }
201
+
202
+ /**
203
+ * 单条 CallSnapshot → AgentCall。残缺条目(非对象 / id 非数 / traceNode 缺失)
204
+ * 返回 undefined,由调用方跳过——不炸整个 run。
205
+ */
206
+ function rehydrateCall(c: CallSnapshot, trace: Trace): AgentCall | undefined {
207
+ if (c === null || typeof c !== "object" || typeof c.id !== "number") return undefined;
208
+ const linked = linkTraceNode(c, trace);
209
+ if (!linked) return undefined;
210
+ const call = new AgentCall(c.id, c.opts, linked);
211
+ call.status = c.status;
212
+ call.attempts = c.attempts;
213
+ // Restore result directly — bypasses markRunning/markDone state-machine guards
214
+ // because we're reconstructing a known-good persisted state, not transitioning.
215
+ if (c.result !== undefined) call.result = c.result;
216
+ if (c.sessionId !== undefined) call.sessionId = c.sessionId;
217
+ if (c.sessionFile !== undefined) call.sessionFile = c.sessionFile;
218
+ return call;
219
+ }
220
+
221
+ function rehydrateCalls(snapshots: CallSnapshot[], trace: Trace): Map<number, AgentCall> {
222
+ const calls = new Map<number, AgentCall>();
223
+ for (const c of snapshots) {
224
+ const call = rehydrateCall(c, trace);
225
+ if (call) calls.set(c.id, call);
226
+ }
227
+ return calls;
228
+ }
229
+
230
+ /**
231
+ * 快照 → WorkflowRun 重水合。
232
+ *
233
+ * 版本 guard(D4 裁决③):v 不等于当前版本即返回 undefined(含缺版本——
234
+ * 「缺 v 宽容」是 FileRunStore 层预处理职责,不内聚进本函数;pi 侧对 v1 存量
235
+ * 行的静默跳过语义依赖此拒绝行为)。
236
+ *
237
+ * 形状校验失败同样返回 undefined(调用方按损坏行处理,本函数不抛——唯一例外:
238
+ * done 快照缺 reason 触发 WorkflowRun I2 不变式抛错,属真 bug 不可吞)。
239
+ */
240
+ export function fromRunSnapshot(snap: unknown): WorkflowRun | undefined {
241
+ if (snap === null || typeof snap !== "object") return undefined;
242
+ const s = snap as Partial<RunSnapshot>;
243
+ if (!isValidSnapshotShape(s)) return undefined;
244
+
245
+ // Trace 先重建:calls 的 traceNode 回链到 Trace 副本(D-10 尽力恢复——
246
+ // fromArray 拷贝节点,按 stepIndex 匹配使 call.traceNode 与 trace.nodes
247
+ // 共享同一副本引用;匹配不到(快照数据漂移)退化为独立浅拷贝,仅保构造不炸。
248
+ const trace = Trace.fromArray(s.state.trace);
249
+ const calls = rehydrateCalls(s.state.calls, trace);
250
+
251
+ return WorkflowRun.reconstruct(
252
+ s.runId,
253
+ s.spec,
254
+ {
255
+ status: s.state.status,
256
+ reason: s.state.reason,
257
+ budget: new Budget(s.state.budget),
258
+ calls,
259
+ trace,
260
+ errorLogs: Array.isArray(s.state.errorLogs) ? s.state.errorLogs : [],
261
+ error: s.state.error,
262
+ scriptResult: s.state.scriptResult,
263
+ },
264
+ s.meta,
265
+ );
266
+ }
@@ -0,0 +1,154 @@
1
+ /**
2
+ * Workflow 脚本创作管线(generate)——pi-sw tool-workflow-script.ts actionGenerate
3
+ * 的校验管线下沉(convergence D-6 / W4)。
4
+ *
5
+ * 五道闸 + round-trip + tmp 写盘,闸序与 pi 现版一致:
6
+ * 1. ESM import 拒绝(Worker 跑 CJS);'export const meta' 例外
7
+ * 2. 非 meta 的 export 拒绝
8
+ * 3. meta 声明必需(@pi-meta YAML 块注释或 legacy const meta,过渡期 m0)
9
+ * 4. agent() 调用必需
10
+ * 5. 语法检查(包 async IIFE,与 runtime 包裹形态一致)
11
+ * 6. round-trip:@pi-meta 存在时 parseResourceMetaDetailed 校验 YAML(报行列)
12
+ * 7. 通过全部校验 → tmp 目录写盘
13
+ *
14
+ * 与 pi 版的差异(均为宿主职责,不属纯函数边界):
15
+ * - 不含 signal aborted 检查(AbortSignal 是 pi tool 契约层关注,宿主改接时自留);
16
+ * - 返回结构化结果而非 throw——pi 只对 execute throw 置 isError:true 的契约
17
+ * 转换由宿主(C5 改接)负责,core 保持纯函数。
18
+ *
19
+ * 报错文案逐字平移自 pi 现版(含 round-trip 的 line/col 信息)——pi 侧行为
20
+ * 不变是 CA2 验收前提,任何文案改动必须同步两处。
21
+ *
22
+ * tmp 目录经 options.tmpDir 宿主注入(缺省 pi 布局,与 workflow-files.ts
23
+ * 同源常量——save/delete/generate 三入口共享同一目录参数化口径)。
24
+ *
25
+ * 层归属:orchestration(创作闭环,与 lintScript / workflow-files 同域)。
26
+ */
27
+
28
+ import { mkdirSync, writeFileSync } from "node:fs";
29
+ import { resolve } from "node:path";
30
+
31
+ import { parseResourceMetaDetailed } from "../shared/meta-parser.ts";
32
+ import { DEFAULT_WORKFLOW_TMP_DIR } from "./workflow-files.ts";
33
+
34
+ /** generate 目录注入参数:tmp 落盘目录宿主注入(缺省 DEFAULT_WORKFLOW_TMP_DIR)。 */
35
+ export interface GenerateWorkflowScriptOptions {
36
+ tmpDir?: string;
37
+ }
38
+
39
+ /**
40
+ * 管线结果:成功 = 落盘绝对路径;失败 = 报错文案(逐字对齐 pi 现版,
41
+ * 含 round-trip 的行列信息——供宿主转 throw 后 LLM 自纠正)。
42
+ */
43
+ export type GenerateWorkflowScriptResult =
44
+ | { ok: true; path: string }
45
+ | { ok: false; error: string };
46
+
47
+ // ── 校验闸(每闸返回 error 文案;undefined = 通过。文案逐字对齐 pi 现版) ──
48
+
49
+ /** 闸 0:参数完备(缺 name/script 即拒)。 */
50
+ function checkRequiredParams(name: string, script: string): string | undefined {
51
+ if (!name || !script) {
52
+ return "generate requires 'name' and 'script' parameters";
53
+ }
54
+ return undefined;
55
+ }
56
+
57
+ /** 闸 1:ESM 语法拒绝(Worker 跑 CJS);'export const meta' 例外。stripped = 注释剥离后源码。 */
58
+ function checkEsamSyntax(stripped: string): string | undefined {
59
+ if (/\bimport\s+(?:type\s+)?[\w{*]/.test(stripped)) {
60
+ return "Script uses ESM 'import' syntax. Workflow scripts run in a CJS Worker — use require() instead.";
61
+ }
62
+ const hasExportMeta = /\bexport\s+const\s+meta\s*=/.test(stripped);
63
+ const otherExports = stripped.match(/\bexport\s+(?:const|let|var|function|default|\{)/g);
64
+ if (otherExports && !hasExportMeta) {
65
+ return "Script uses ESM 'export' (non-meta). Use 'const meta = {...}' at top level instead.";
66
+ }
67
+ return undefined;
68
+ }
69
+
70
+ // 闸 2:meta 声明必需(/* @pi-meta */ YAML 块注释或 legacy const meta,过渡期 m0)
71
+ function checkMetaDeclaration(script: string, hasPiMeta: boolean): string | undefined {
72
+ const hasLegacyMeta = script.includes("const meta") || script.includes("export const meta");
73
+ if (!hasPiMeta && !hasLegacyMeta) {
74
+ return "Script must contain a meta declaration: a /* @pi-meta */ YAML block comment (preferred) or legacy const meta = { ... }. The block has the form: a block comment starting with /* @pi-meta followed by YAML (name/description/phases/parameters?/usage?), closed by */ on its own line.";
75
+ }
76
+ return undefined;
77
+ }
78
+
79
+ /** 闸 3:agent() 调用必需。 */
80
+ function checkAgentUsage(stripped: string): string | undefined {
81
+ if (!/\bagent\s*\(/.test(stripped)) {
82
+ return "Script does not contain any agent() calls. A workflow must call agent() at least once.";
83
+ }
84
+ return undefined;
85
+ }
86
+
87
+ /** 闸 4:语法检查(包 async IIFE,与 runtime 包裹形态一致)。 */
88
+ function checkSyntax(script: string): string | undefined {
89
+ const cjsScript = script.replace(/\bexport\s+const\s+meta\b/, "const meta");
90
+ try {
91
+ new Function(`(async () => { ${cjsScript} })();`);
92
+ return undefined;
93
+ } catch (err: unknown) {
94
+ const msg = err instanceof Error ? err.message : String(err);
95
+ return `Syntax error in script: ${msg}`;
96
+ }
97
+ }
98
+
99
+ /** 闸 4b:round-trip——@pi-meta 存在时 parseResourceMetaDetailed 校验 YAML(报行列)。 */
100
+ function checkMetaRoundTrip(script: string, hasPiMeta: boolean): string | undefined {
101
+ if (!hasPiMeta) return undefined;
102
+ const detailed = parseResourceMetaDetailed(script, "workflow");
103
+ if (detailed.ok) return undefined;
104
+ const loc = "linePos" in detailed && detailed.linePos
105
+ ? ` (line ${detailed.linePos.line}, col ${detailed.linePos.col})`
106
+ : "";
107
+ return `Generated /* @pi-meta */ YAML cannot be parsed${loc}: ${detailed.error}. Common causes: YAML indent errors, patternProperties regex must use double backslash (\\d not \d), or a stray star-slash inside the YAML body. Fix the meta block and retry.`;
108
+ }
109
+
110
+ /**
111
+ * 校验并落盘一个 AI 生成的 workflow 临时脚本。
112
+ *
113
+ * @param name 脚本名(落盘 <tmpDir>/{name}.js)
114
+ * @param script 完整脚本源码
115
+ * @param options 目录注入(tmpDir 缺省 pi 布局,相对 cwd resolve)
116
+ */
117
+ export function generateWorkflowScript(
118
+ name: string,
119
+ script: string,
120
+ options?: GenerateWorkflowScriptOptions,
121
+ ): GenerateWorkflowScriptResult {
122
+ const paramError = checkRequiredParams(name, script);
123
+ if (paramError) return { ok: false, error: paramError };
124
+
125
+ // 1. Reject ESM syntax (Worker runs CJS); 'export const meta' 例外
126
+ const stripped = script.replace(/\/\/.*$/gm, "").replace(/\/\*[\s\S]*?\*\//g, "");
127
+ const esamError = checkEsamSyntax(stripped);
128
+ if (esamError) return { ok: false, error: esamError };
129
+
130
+ // 2. Validate meta declaration (/* @pi-meta */ new format preferred; legacy const meta accepted during transition — m0)
131
+ const hasPiMeta = /\/\*\s*@pi-meta\s*\n/.test(script);
132
+ const metaError = checkMetaDeclaration(script, hasPiMeta);
133
+ if (metaError) return { ok: false, error: metaError };
134
+
135
+ // 3. Check agent usage
136
+ const agentError = checkAgentUsage(stripped);
137
+ if (agentError) return { ok: false, error: agentError };
138
+
139
+ // 4. Syntax check (wrap in async IIFE like runtime)
140
+ const syntaxError = checkSyntax(script);
141
+ if (syntaxError) return { ok: false, error: syntaxError };
142
+
143
+ // 4b. Round-trip: validate /* @pi-meta */ YAML before writing (v5 §4.7 / ERR4 — report linePos, don't write bad files)
144
+ const roundTripError = checkMetaRoundTrip(script, hasPiMeta);
145
+ if (roundTripError) return { ok: false, error: roundTripError };
146
+
147
+ // 5. Write to tmp directory
148
+ const tmpDir = resolve(options?.tmpDir ?? DEFAULT_WORKFLOW_TMP_DIR);
149
+ mkdirSync(tmpDir, { recursive: true });
150
+ const filePath = resolve(tmpDir, `${name}.js`);
151
+ writeFileSync(filePath, script, "utf-8");
152
+
153
+ return { ok: true, path: filePath };
154
+ }