@zhushanwen/pi-subagent-workflow 8.6.0 → 8.7.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 (347) hide show
  1. package/package.json +9 -13
  2. package/relay/relay.mjs +1 -1
  3. package/src/host/__tests__/pi-host.test.ts +214 -0
  4. package/src/host/pi-host.ts +109 -0
  5. package/src/index.ts +89 -32
  6. package/src/injectors/__tests__/engine-awareness.test.ts +292 -0
  7. package/src/injectors/__tests__/engine-section-stability.test.ts +341 -0
  8. package/src/injectors/__tests__/subagent-list-injector.test.ts +5 -5
  9. package/src/injectors/__tests__/workflow-list-injector.test.ts +5 -5
  10. package/src/injectors/engine-awareness.ts +123 -0
  11. package/src/injectors/model-list-injector.ts +1 -1
  12. package/src/injectors/subagent-list-injector.ts +8 -8
  13. package/src/injectors/workflow-list-injector.ts +8 -8
  14. package/src/interface/__tests__/detectors.test.ts +3 -3
  15. package/src/interface/__tests__/subagent-tool-path-guard.test.ts +2 -2
  16. package/src/interface/__tests__/tool-workflow-script-generate.test.ts +2 -2
  17. package/src/interface/__tests__/tool-workflow-throw-paths.test.ts +1 -1
  18. package/src/interface/bg-notify-render.ts +4 -4
  19. package/src/interface/commands.ts +3 -3
  20. package/src/interface/format.ts +2 -2
  21. package/src/interface/helpers.ts +1 -1
  22. package/src/interface/list-component.ts +4 -4
  23. package/src/interface/list-shared.ts +2 -2
  24. package/src/interface/list-view.ts +2 -2
  25. package/src/interface/subagent-actions.ts +263 -11
  26. package/src/interface/subagent-tool-schema.ts +20 -13
  27. package/src/interface/subagent-tool.ts +11 -6
  28. package/src/interface/subagents.ts +3 -3
  29. package/src/interface/tool-render.ts +34 -2
  30. package/src/interface/tool-workflow-script.ts +4 -4
  31. package/src/interface/tool-workflow.ts +6 -6
  32. package/src/interface/views/WorkflowsView.ts +5 -5
  33. package/src/interface/views/__tests__/WorkflowsView-signature.test.ts +3 -3
  34. package/src/interface/views/__tests__/detail-content-session-file.test.ts +2 -2
  35. package/src/interface/views/detail-content.ts +4 -4
  36. package/src/interface/views/format.ts +4 -4
  37. package/src/{orchestration/jsonl-run-store.ts → jsonl-run-store.ts} +11 -11
  38. package/src/execution/__tests__/__fixtures__/notifier-golden-snapshots.json +0 -53
  39. package/src/execution/__tests__/__fixtures__/truncline.snapshot.json +0 -1
  40. package/src/execution/__tests__/agent-registry.test.ts +0 -363
  41. package/src/execution/__tests__/agent-result-mapper.test.ts +0 -150
  42. package/src/execution/__tests__/alive-store.test.ts +0 -147
  43. package/src/execution/__tests__/ask-user-transit-e2e.test.ts +0 -490
  44. package/src/execution/__tests__/before-agent-start-injection.test.ts +0 -132
  45. package/src/execution/__tests__/bg-notify-render.test.ts +0 -329
  46. package/src/execution/__tests__/channel-registry-handshake.test.ts +0 -243
  47. package/src/execution/__tests__/chat-engine-routing.test.ts +0 -601
  48. package/src/execution/__tests__/chatmode-first-round-closure-service.test.ts +0 -365
  49. package/src/execution/__tests__/chatmode-first-round-closure-spawn.test.ts +0 -190
  50. package/src/execution/__tests__/chatmode-round-notify-real-chain.test.ts +0 -215
  51. package/src/execution/__tests__/concurrency-pool.test.ts +0 -250
  52. package/src/execution/__tests__/config.test.ts +0 -110
  53. package/src/execution/__tests__/conversation-wiring.test.ts +0 -198
  54. package/src/execution/__tests__/crash-recovery.test.ts +0 -320
  55. package/src/execution/__tests__/delivery-methods.test.ts +0 -422
  56. package/src/execution/__tests__/dialog-queue.test.ts +0 -299
  57. package/src/execution/__tests__/epipe-fallback.test.ts +0 -241
  58. package/src/execution/__tests__/execute-and-await-worktree.test.ts +0 -243
  59. package/src/execution/__tests__/execute-nesting.test.ts +0 -323
  60. package/src/execution/__tests__/execute-options-mapper.test.ts +0 -200
  61. package/src/execution/__tests__/execution-record.test.ts +0 -1394
  62. package/src/execution/__tests__/explicit-agent-ref-guard.test.ts +0 -171
  63. package/src/execution/__tests__/finalize-record.test.ts +0 -368
  64. package/src/execution/__tests__/finalized-marker.test.ts +0 -82
  65. package/src/execution/__tests__/format-schema-instruction.test.ts +0 -169
  66. package/src/execution/__tests__/format.test.ts +0 -458
  67. package/src/execution/__tests__/gc-timer.test.ts +0 -184
  68. package/src/execution/__tests__/get-record-for-action-restart.test.ts +0 -254
  69. package/src/execution/__tests__/gui-mode-dispatch.test.ts +0 -59
  70. package/src/execution/__tests__/helpers/mock-extension-api.ts +0 -30
  71. package/src/execution/__tests__/helpers/spawn-mock.ts +0 -242
  72. package/src/execution/__tests__/host-mode.test.ts +0 -87
  73. package/src/execution/__tests__/index-session-start-identity.test.ts +0 -371
  74. package/src/execution/__tests__/index-session-start.test.ts +0 -672
  75. package/src/execution/__tests__/lifecycle-manager-lock.test.ts +0 -211
  76. package/src/execution/__tests__/lifecycle-manager.test.ts +0 -383
  77. package/src/execution/__tests__/lifecycle-predicates.test.ts +0 -116
  78. package/src/execution/__tests__/list-component.test.ts +0 -401
  79. package/src/execution/__tests__/list-fields.test.ts +0 -140
  80. package/src/execution/__tests__/manifest-parentid.test.ts +0 -117
  81. package/src/execution/__tests__/model-resolver.test.ts +0 -465
  82. package/src/execution/__tests__/nested-visibility-env-propagation.test.ts +0 -287
  83. package/src/execution/__tests__/nested-visibility.test.ts +0 -325
  84. package/src/execution/__tests__/notifier-flush.test.ts +0 -612
  85. package/src/execution/__tests__/notifier-golden-snapshot.test.ts +0 -261
  86. package/src/execution/__tests__/notify-ledger.test.ts +0 -826
  87. package/src/execution/__tests__/one-shot-upgrade.test.ts +0 -205
  88. package/src/execution/__tests__/output-collector.test.ts +0 -358
  89. package/src/execution/__tests__/parent-child-matrix.test.ts +0 -336
  90. package/src/execution/__tests__/path-encoding.test.ts +0 -104
  91. package/src/execution/__tests__/pi-invocation.test.ts +0 -134
  92. package/src/execution/__tests__/record-store.test.ts +0 -1057
  93. package/src/execution/__tests__/records-cwd-isolation.test.ts +0 -91
  94. package/src/execution/__tests__/recursive-visibility-baseline.test.ts +0 -339
  95. package/src/execution/__tests__/recursive-visibility-env.test.ts +0 -273
  96. package/src/execution/__tests__/relay-agent.test.ts +0 -448
  97. package/src/execution/__tests__/relay-env.test.ts +0 -42
  98. package/src/execution/__tests__/resource-policy.test.ts +0 -109
  99. package/src/execution/__tests__/rpc-mode.test.ts +0 -89
  100. package/src/execution/__tests__/run-and-finalize-chatmode.test.ts +0 -267
  101. package/src/execution/__tests__/run-spawn-chatmode-settled.test.ts +0 -253
  102. package/src/execution/__tests__/run-spawn-edges.test.ts +0 -687
  103. package/src/execution/__tests__/run-spawn-integration.test.ts +0 -933
  104. package/src/execution/__tests__/run-spawn-resume.test.ts +0 -322
  105. package/src/execution/__tests__/run-spawn-rpc-mode.test.ts +0 -196
  106. package/src/execution/__tests__/run-spawn-stdout-callback-throw.test.ts +0 -199
  107. package/src/execution/__tests__/sdk-contract.test.ts +0 -273
  108. package/src/execution/__tests__/session-context-resolver.test.ts +0 -167
  109. package/src/execution/__tests__/session-file-gc.test.ts +0 -293
  110. package/src/execution/__tests__/session-pending.test.ts +0 -197
  111. package/src/execution/__tests__/session-reconstructor.test.ts +0 -379
  112. package/src/execution/__tests__/session-runner-epipe.test.ts +0 -178
  113. package/src/execution/__tests__/session-runner-schema-env.test.ts +0 -350
  114. package/src/execution/__tests__/session-start-reaper.test.ts +0 -233
  115. package/src/execution/__tests__/spawn-args.test.ts +0 -445
  116. package/src/execution/__tests__/spawn-event-adapter-rpc.test.ts +0 -189
  117. package/src/execution/__tests__/spawn-event-adapter.test.ts +0 -167
  118. package/src/execution/__tests__/spawn-worktree-guidance.test.ts +0 -207
  119. package/src/execution/__tests__/spawned-children.test.ts +0 -92
  120. package/src/execution/__tests__/start-sync-model-guard.test.ts +0 -150
  121. package/src/execution/__tests__/startup-config-declaration.test.ts +0 -35
  122. package/src/execution/__tests__/status-refactor.test.ts +0 -345
  123. package/src/execution/__tests__/stdin-writer.test.ts +0 -463
  124. package/src/execution/__tests__/stream-sink-retirement.test.ts +0 -261
  125. package/src/execution/__tests__/subagent-service-abort.test.ts +0 -60
  126. package/src/execution/__tests__/subagent-service-message-close.test.ts +0 -629
  127. package/src/execution/__tests__/subagent-service-parent-guard.test.ts +0 -180
  128. package/src/execution/__tests__/subagent-service.test.ts +0 -788
  129. package/src/execution/__tests__/subprocess-agent-runner-routing.test.ts +0 -310
  130. package/src/execution/__tests__/subprocess-agent-runner.test.ts +0 -599
  131. package/src/execution/__tests__/temp-prompt.test.ts +0 -53
  132. package/src/execution/__tests__/timeout-integration.test.ts +0 -615
  133. package/src/execution/__tests__/tombstone-store.test.ts +0 -73
  134. package/src/execution/__tests__/tool-action.test.ts +0 -476
  135. package/src/execution/__tests__/truncline-snapshot.test.ts +0 -81
  136. package/src/execution/__tests__/turn-limiter-semantics.test.ts +0 -194
  137. package/src/execution/__tests__/turn-limiter.test.ts +0 -65
  138. package/src/execution/__tests__/ui-channels.test.ts +0 -187
  139. package/src/execution/__tests__/ui-interaction-model.test.ts +0 -67
  140. package/src/execution/__tests__/ui-request-handler-factory.test.ts +0 -370
  141. package/src/execution/__tests__/ui-request-handler.test.ts +0 -204
  142. package/src/execution/__tests__/ui-request-observability.test.ts +0 -114
  143. package/src/execution/__tests__/ui-request-queue.test.ts +0 -133
  144. package/src/execution/__tests__/worktree-manager.test.ts +0 -633
  145. package/src/execution/__tests__/worktree-pid-registration.integration.test.ts +0 -229
  146. package/src/execution/__tests__/worktree-reconcile.integration.test.ts +0 -181
  147. package/src/execution/__tests__/worktree-registry.test.ts +0 -199
  148. package/src/execution/agent-registry.ts +0 -199
  149. package/src/execution/agent-result-mapper.ts +0 -90
  150. package/src/execution/alive-store.ts +0 -92
  151. package/src/execution/argv-mirror.ts +0 -113
  152. package/src/execution/best-effort.ts +0 -38
  153. package/src/execution/channel-registry-access.ts +0 -144
  154. package/src/execution/concurrency-pool.ts +0 -116
  155. package/src/execution/config.ts +0 -96
  156. package/src/execution/dialog-queue.ts +0 -330
  157. package/src/execution/engine/__tests__/common/data-dir.test.ts +0 -53
  158. package/src/execution/engine/__tests__/common/errors.test.ts +0 -132
  159. package/src/execution/engine/__tests__/common/event-journal.test.ts +0 -177
  160. package/src/execution/engine/__tests__/common/kill-chain.test.ts +0 -192
  161. package/src/execution/engine/__tests__/common/nesting-guard.test.ts +0 -81
  162. package/src/execution/engine/__tests__/common/persona-router.test.ts +0 -123
  163. package/src/execution/engine/__tests__/common/pool-manager.test.ts +0 -154
  164. package/src/execution/engine/__tests__/common/schema-emulation.test.ts +0 -128
  165. package/src/execution/engine/__tests__/conformance/__fixtures__/pi-golden-events.json +0 -28
  166. package/src/execution/engine/__tests__/conformance/agent-event-invariants.ts +0 -141
  167. package/src/execution/engine/__tests__/conformance/contract.abort.test.ts +0 -109
  168. package/src/execution/engine/__tests__/conformance/contract.agent-events.test.ts +0 -101
  169. package/src/execution/engine/__tests__/conformance/contract.probe.test.ts +0 -77
  170. package/src/execution/engine/__tests__/conformance/contract.read-degradation.test.ts +0 -104
  171. package/src/execution/engine/__tests__/conformance/contract.relay.test.ts +0 -342
  172. package/src/execution/engine/__tests__/conformance/engine-conformance.live.test.ts +0 -201
  173. package/src/execution/engine/__tests__/conformance/golden-replay.pi.test.ts +0 -76
  174. package/src/execution/engine/__tests__/conformance/golden-replay.zcode.test.ts +0 -79
  175. package/src/execution/engine/__tests__/engine-discovery.test.ts +0 -87
  176. package/src/execution/engine/__tests__/engines-declaration.test.ts +0 -36
  177. package/src/execution/engine/__tests__/model-prompt.test.ts +0 -85
  178. package/src/execution/engine/__tests__/paths.test.ts +0 -39
  179. package/src/execution/engine/__tests__/registry.test.ts +0 -120
  180. package/src/execution/engine/__tests__/routing.test.ts +0 -231
  181. package/src/execution/engine/common/data-dir.ts +0 -62
  182. package/src/execution/engine/common/errors.ts +0 -183
  183. package/src/execution/engine/common/event-journal.ts +0 -254
  184. package/src/execution/engine/common/journal-replay.ts +0 -62
  185. package/src/execution/engine/common/kill-chain.ts +0 -221
  186. package/src/execution/engine/common/nesting-guard.ts +0 -50
  187. package/src/execution/engine/common/persona-router.ts +0 -108
  188. package/src/execution/engine/common/pool-manager.ts +0 -226
  189. package/src/execution/engine/common/schema-emulation.ts +0 -189
  190. package/src/execution/engine/common/session-view-projection.ts +0 -51
  191. package/src/execution/engine/engine-discovery.ts +0 -65
  192. package/src/execution/engine/engines/pi/__tests__/pi-engine.test.ts +0 -469
  193. package/src/execution/engine/engines/pi/__tests__/reader.test.ts +0 -155
  194. package/src/execution/engine/engines/pi/__tests__/task-spec-mapper.test.ts +0 -164
  195. package/src/execution/engine/engines/pi/pi-engine.ts +0 -415
  196. package/src/execution/engine/engines/pi/reader.ts +0 -48
  197. package/src/execution/engine/engines/pi/registration.ts +0 -35
  198. package/src/execution/engine/engines/pi/task-spec-mapper.ts +0 -100
  199. package/src/execution/engine/engines/zcode/__tests__/__fixtures__/zcode-golden-spawn.json +0 -39
  200. package/src/execution/engine/engines/zcode/__tests__/launcher.test.ts +0 -150
  201. package/src/execution/engine/engines/zcode/__tests__/parser.test.ts +0 -246
  202. package/src/execution/engine/engines/zcode/__tests__/preparer.test.ts +0 -228
  203. package/src/execution/engine/engines/zcode/__tests__/reader.test.ts +0 -210
  204. package/src/execution/engine/engines/zcode/__tests__/registration.test.ts +0 -64
  205. package/src/execution/engine/engines/zcode/__tests__/zcode-engine.live.test.ts +0 -127
  206. package/src/execution/engine/engines/zcode/__tests__/zcode-engine.test.ts +0 -580
  207. package/src/execution/engine/engines/zcode/constants.ts +0 -43
  208. package/src/execution/engine/engines/zcode/golden-sample.ts +0 -39
  209. package/src/execution/engine/engines/zcode/launcher.ts +0 -161
  210. package/src/execution/engine/engines/zcode/parser.ts +0 -436
  211. package/src/execution/engine/engines/zcode/preparer.ts +0 -363
  212. package/src/execution/engine/engines/zcode/reader.ts +0 -381
  213. package/src/execution/engine/engines/zcode/registration.ts +0 -37
  214. package/src/execution/engine/engines/zcode/zcode-engine.ts +0 -658
  215. package/src/execution/engine/host-task-spec.ts +0 -47
  216. package/src/execution/engine/model-prompt.ts +0 -59
  217. package/src/execution/engine/paths.ts +0 -42
  218. package/src/execution/engine/port.ts +0 -153
  219. package/src/execution/engine/registry.ts +0 -123
  220. package/src/execution/engine/routing.ts +0 -218
  221. package/src/execution/engine/types.ts +0 -309
  222. package/src/execution/execute-options-mapper.ts +0 -112
  223. package/src/execution/execution-record.ts +0 -965
  224. package/src/execution/finalize-record.ts +0 -251
  225. package/src/execution/finalized-marker.ts +0 -51
  226. package/src/execution/get-state-handshake.ts +0 -104
  227. package/src/execution/host-mode.ts +0 -56
  228. package/src/execution/idle-gc.ts +0 -47
  229. package/src/execution/lifecycle-manager.ts +0 -513
  230. package/src/execution/lifecycle-predicates.ts +0 -65
  231. package/src/execution/manifest-store.ts +0 -256
  232. package/src/execution/model-config-service.ts +0 -219
  233. package/src/execution/model-resolver.ts +0 -248
  234. package/src/execution/notifier.ts +0 -330
  235. package/src/execution/notify-ledger.ts +0 -580
  236. package/src/execution/output-collector.ts +0 -228
  237. package/src/execution/path-encoding.ts +0 -60
  238. package/src/execution/pi-invocation.ts +0 -120
  239. package/src/execution/record-entry.ts +0 -132
  240. package/src/execution/record-store.ts +0 -1234
  241. package/src/execution/relay-env.ts +0 -37
  242. package/src/execution/session-context-resolver.ts +0 -64
  243. package/src/execution/session-file-gc.ts +0 -120
  244. package/src/execution/session-pending.ts +0 -164
  245. package/src/execution/session-reconstructor.ts +0 -678
  246. package/src/execution/session-runner.ts +0 -1781
  247. package/src/execution/sessions-index.ts +0 -304
  248. package/src/execution/spawn-event-adapter.ts +0 -363
  249. package/src/execution/stdin-writer.ts +0 -198
  250. package/src/execution/stream-sink.ts +0 -126
  251. package/src/execution/subagent-service.ts +0 -2141
  252. package/src/execution/subprocess-agent-runner.ts +0 -317
  253. package/src/execution/temp-prompt.ts +0 -62
  254. package/src/execution/tombstone-store.ts +0 -72
  255. package/src/execution/turn-limiter.ts +0 -102
  256. package/src/execution/types.ts +0 -973
  257. package/src/execution/ui-channels.ts +0 -216
  258. package/src/execution/ui-interaction-model.ts +0 -48
  259. package/src/execution/ui-request-handler-factory.ts +0 -212
  260. package/src/execution/ui-request-observability.ts +0 -81
  261. package/src/execution/ui-request-queue.ts +0 -184
  262. package/src/execution/worktree-manager.ts +0 -688
  263. package/src/execution/worktree-registry.ts +0 -222
  264. package/src/orchestration/__tests__/__fixtures__/worker-template.snapshot.txt +0 -349
  265. package/src/orchestration/__tests__/agent-call-catch-fallback.test.ts +0 -202
  266. package/src/orchestration/__tests__/agent-call-stream.test.ts +0 -152
  267. package/src/orchestration/__tests__/args-validator.test.ts +0 -143
  268. package/src/orchestration/__tests__/config-loader.test.ts +0 -503
  269. package/src/orchestration/__tests__/error-recovery-handlers.test.ts +0 -809
  270. package/src/orchestration/__tests__/error-recovery-postmessage-defense.test.ts +0 -405
  271. package/src/orchestration/__tests__/error-recovery-serialize-failed-result.test.ts +0 -56
  272. package/src/orchestration/__tests__/error-recovery-workflow-call.test.ts +0 -166
  273. package/src/orchestration/__tests__/execute-agent-call.test.ts +0 -451
  274. package/src/orchestration/__tests__/jsonl-run-store-corrupt-entry.test.ts +0 -150
  275. package/src/orchestration/__tests__/jsonl-run-store-loadall-sources.test.ts +0 -171
  276. package/src/orchestration/__tests__/jsonl-run-store-retention.test.ts +0 -202
  277. package/src/orchestration/__tests__/jsonl-run-store-session-file.test.ts +0 -1030
  278. package/src/orchestration/__tests__/launcher-nested-workflow.test.ts +0 -600
  279. package/src/orchestration/__tests__/lifecycle-runid-injection.test.ts +0 -96
  280. package/src/orchestration/__tests__/lifecycle.test.ts +0 -659
  281. package/src/orchestration/__tests__/non-cloneable-return-e2e.test.ts +0 -95
  282. package/src/orchestration/__tests__/review-fix-loop-e2e.test.ts +0 -2025
  283. package/src/orchestration/__tests__/script-lint.test.ts +0 -831
  284. package/src/orchestration/__tests__/skill-discovery.test.ts +0 -201
  285. package/src/orchestration/__tests__/test-mocks.ts +0 -197
  286. package/src/orchestration/__tests__/worker-exit-without-result.test.ts +0 -368
  287. package/src/orchestration/__tests__/worker-host.test.ts +0 -120
  288. package/src/orchestration/__tests__/worker-returnmeta-passthrough.test.ts +0 -164
  289. package/src/orchestration/__tests__/worker-script-builder-runtime.test.ts +0 -563
  290. package/src/orchestration/__tests__/worker-script-builder.test.ts +0 -309
  291. package/src/orchestration/__tests__/worker-script-template-snapshot.test.ts +0 -129
  292. package/src/orchestration/__tests__/workflow-nesting-e2e.test.ts +0 -317
  293. package/src/orchestration/__tests__/workflow-script-lint-memo.test.ts +0 -110
  294. package/src/orchestration/__tests__/workflows-e2e.test.ts +0 -537
  295. package/src/orchestration/agent-opts-resolver.ts +0 -174
  296. package/src/orchestration/args-validator.ts +0 -127
  297. package/src/orchestration/config-loader.ts +0 -315
  298. package/src/orchestration/error-recovery.ts +0 -1018
  299. package/src/orchestration/execute-agent-call.ts +0 -256
  300. package/src/orchestration/launcher.ts +0 -455
  301. package/src/orchestration/lifecycle.ts +0 -399
  302. package/src/orchestration/models/__tests__/budget.test.ts +0 -307
  303. package/src/orchestration/models/__tests__/trace.test.ts +0 -408
  304. package/src/orchestration/models/agent-call.ts +0 -83
  305. package/src/orchestration/models/budget.ts +0 -118
  306. package/src/orchestration/models/ports.ts +0 -164
  307. package/src/orchestration/models/run-runtime.ts +0 -104
  308. package/src/orchestration/models/run-spec.ts +0 -83
  309. package/src/orchestration/models/run-state.ts +0 -44
  310. package/src/orchestration/models/trace.ts +0 -183
  311. package/src/orchestration/models/types.ts +0 -301
  312. package/src/orchestration/models/workflow-run.ts +0 -254
  313. package/src/orchestration/models/workflow-script-registry.ts +0 -35
  314. package/src/orchestration/models/workflow-script.ts +0 -117
  315. package/src/orchestration/script-lint.ts +0 -766
  316. package/src/orchestration/skill-discovery.ts +0 -115
  317. package/src/orchestration/worker-handle.ts +0 -115
  318. package/src/orchestration/worker-host.ts +0 -98
  319. package/src/orchestration/worker-script-builder.ts +0 -421
  320. package/src/orchestration/workflow-files.ts +0 -85
  321. package/src/orchestration/workflow-script-registry-impl.ts +0 -133
  322. package/src/shared/__tests__/agent-ref.test.ts +0 -34
  323. package/src/shared/__tests__/meta-parser.test.ts +0 -304
  324. package/src/shared/__tests__/model-ref.test.ts +0 -306
  325. package/src/shared/__tests__/resource-discovery-manifest-cache.test.ts +0 -280
  326. package/src/shared/__tests__/resource-discovery.test.ts +0 -736
  327. package/src/shared/__tests__/resource-meta.test.ts +0 -51
  328. package/src/shared/__tests__/schema-jsonify.test.ts +0 -81
  329. package/src/shared/__tests__/timer-delay.test.ts +0 -61
  330. package/src/shared/agent-event.ts +0 -13
  331. package/src/shared/agent-ref.ts +0 -57
  332. package/src/shared/meta-parser.ts +0 -261
  333. package/src/shared/model-ref.ts +0 -286
  334. package/src/shared/resource-discovery.ts +0 -811
  335. package/src/shared/resource-meta.ts +0 -65
  336. package/src/shared/schema-env.ts +0 -44
  337. package/src/shared/schema-jsonify.ts +0 -58
  338. package/src/shared/timer-delay.ts +0 -54
  339. package/src/shared/xml-injection.ts +0 -35
  340. package/workflows/README.md +0 -81
  341. package/workflows/_shared/agent-refs.cjs +0 -40
  342. package/workflows/chain.js +0 -131
  343. package/workflows/map-reduce.js +0 -174
  344. package/workflows/parallel.js +0 -148
  345. package/workflows/review-fix-loop-utils.cjs +0 -1309
  346. package/workflows/review-fix-loop.js +0 -1404
  347. package/workflows/scatter-gather.js +0 -178
@@ -1,766 +0,0 @@
1
- /**
2
- * Workflow Extension — 静态 lint
3
- *
4
- * 在执行前捕获常见的 workflow 脚本 API 误用。纯函数,零副作用,零 IO。
5
- *
6
- * 设计:
7
- * - lint 是编排层关注(非技术资源),归属 Engine 层。
8
- * - **entry-point 检查**:脚本必须含 agent/parallel/pipeline 之一,否则视为 error。
9
- * WorkflowScript.validate 直接委托 lintScript,故 entry-point 检查必须在此。
10
- * - LintFinding/LintResult 类型规范的 canonical 源在本文件。
11
- *
12
- * 检查项:
13
- * 1. 必须含 agent/parallel/pipeline 入口(error)
14
- * 2. agent 选项中 outputSchema 当 key 用 → 应为 schema(error)
15
- * 3. result.output / result.parsedOutput / result.content → agent 返回未包装值(error)
16
- * 4. readFileSync/writeFileSync 传状态 → 脆弱(warning)
17
- * 5. unlinkSync 清理状态 → 与 subprocess 文件读竞态(warning)
18
- * 6. 顶层未 await 的异步 IIFE + 内部调 agent/parallel/pipeline → 子进程被提前 kill(error)
19
- * 7. agent() 缺 description/label → TUI /workflows 显示 '(unnamed)'(warning)
20
- * 8. meta.phases 非字符串数组(对象数组等)→ 引擎忽略(warning)
21
- * 9. meta.phases 声明与 phase() 调用不一致 → 运行时分组与声明脱节(warning)
22
- *
23
- * 层归属:Engine。
24
- *
25
- * 参考:domain-models.md §7(validate 语义)。
26
- */
27
-
28
- /** m4 W2:meta 描述字段长度上限(§5.1 注入段预算约束)。 */
29
- const DESC_MAX_LENGTH = 200;
30
- /** m4 W4:agent examples 最少条数(正反各一需 ≥2)。 */
31
- const EXAMPLES_MIN_COUNT = 2;
32
- /** m5:examples 上限(注入是每 turn 常驻成本——防数据无界膨胀)。 */
33
- const EXAMPLES_MAX_COUNT = 4;
34
-
35
- /** Lint 检查发现项。 */
36
- export interface LintFinding {
37
- /** error = 会导致运行时崩溃; warning = 可能的错误 */
38
- severity: "error" | "warning";
39
- line: number;
40
- message: string;
41
- suggestion: string;
42
- }
43
-
44
- /** Lint 检查结果。 */
45
- export interface LintResult {
46
- valid: boolean;
47
- findings: LintFinding[];
48
- }
49
-
50
- /** 必须命中其一——workflow 脚本不调用任何编排函数等于空跑。 */
51
- import type { AgentMeta } from "../shared/resource-meta.ts";
52
- import { parseResourceMeta } from "../shared/meta-parser.ts";
53
-
54
- const ENTRY_POINT_PATTERNS = [/\bagent\s*\(/, /\bparallel\s*\(/, /\bpipeline\s*\(/] as const;
55
-
56
- /**
57
- * 检查脚本是否含至少一个编排入口(agent/parallel/pipeline)。
58
- * 无入口视为 error——空跑脚本无意义。
59
- */
60
- function checkEntryPoint(source: string): LintFinding[] {
61
- const hasEntryPoint = ENTRY_POINT_PATTERNS.some((p) => p.test(source));
62
- if (hasEntryPoint) return [];
63
- return [
64
- {
65
- severity: "error",
66
- line: 0,
67
- message: "Workflow script must call agent(), parallel(), or pipeline() at least once.",
68
- suggestion: "Add at least one agent(), parallel(), or pipeline() invocation.",
69
- },
70
- ];
71
- }
72
-
73
- /**
74
- * 检查单行 lint 问题,返回该行的发现项(可能为空)。
75
- */
76
- function checkLine(lineText: string, lineNum: number): LintFinding[] {
77
- const results: LintFinding[] = [];
78
-
79
- // 跳过注释行
80
- const trimmed = lineText.trim();
81
- if (trimmed.startsWith("//") || trimmed.startsWith("*") || trimmed.startsWith("/*")) {
82
- return results;
83
- }
84
-
85
- // result.output / result.parsedOutput / result.content
86
- const resultAccessPatterns: Array<{ regex: RegExp; field: string }> = [
87
- { regex: /\bresult\s*\.\s*output\b/, field: "output" },
88
- { regex: /\bresult\s*\.\s*parsedOutput\b/, field: "parsedOutput" },
89
- { regex: /\bresult\s*\.\s*content\b/, field: "content" },
90
- ];
91
- for (const p of resultAccessPatterns) {
92
- if (p.regex.test(lineText)) {
93
- results.push({
94
- severity: "error",
95
- line: lineNum,
96
- message: `\`result.${p.field}\` does not exist. agent() returns the unwrapped value directly.`,
97
- suggestion: "Use `const value = await agent(...)` and access `value` directly.",
98
- });
99
- }
100
- }
101
-
102
- // 文件传状态(readFileSync of STATE)
103
- if (/readFileSync\(.*STATE.*\)|readFileSync\(.*state.*\.json/i.test(lineText)) {
104
- results.push({
105
- severity: "warning",
106
- line: lineNum,
107
- message: "Reading a state file between agent calls is fragile (subprocess file access).",
108
- suggestion: "Use agent() with `schema` to get structured output directly, avoiding file I/O for state passing.",
109
- });
110
- }
111
-
112
- // unlinkSync 清理状态
113
- if (/unlinkSync.*state/i.test(lineText)) {
114
- results.push({
115
- severity: "warning",
116
- line: lineNum,
117
- message: "unlinkSync in finally may race with agent subprocess file reads.",
118
- suggestion: "Avoid file-based state passing; use agent() `schema` for structured output.",
119
- });
120
- }
121
-
122
- return results;
123
- }
124
-
125
- /**
126
- * 剔除字符串字面量与注释内容(MF-4)。逐行处理,不跨行。
127
- * 用途:`\bagent\s*\(` 不命中字符串里的 "agent(s)"(review-fix-loop L281 误报根因);
128
- * checkAgentDescription 的 `description\s*:` 不把 schema 内嵌 description 字符串当已提供。
129
- */
130
- function stripStringsAndComments(line: string): string {
131
- return line
132
- .replace(/"(?:\\.|[^"\\])*"/g, "")
133
- .replace(/'(?:\\.|[^'\\])*'/g, "")
134
- .replace(/`(?:\\.|[^`\\])*`/g, "")
135
- .replace(/\/\/.*$/, "")
136
- .replace(/\/\*[\s\S]*?\*\//g, "");
137
- }
138
-
139
- /**
140
- * 遍历 source 中所有 agent 调用的行范围,对每个调用执行 callback。
141
- *
142
- * agent 调用可能跨多行,通过括号配对定位起止行:
143
- * agent({
144
- * prompt: ...,
145
- * })
146
- *
147
- * 单行 agent 调用(如 `agent({ prompt: 'x' })`)的 startLine === endLine。
148
- * 与 checkAgentCalls / checkAgentDescription 共享同一套范围定义,确保
149
- * outputSchema 检查与 description 检查覆盖完全相同的调用集合(含 parallel/pipeline
150
- * 内嵌的 agent() 调用——它们同样被 `\bagent\s*\(` 匹配)。
151
- *
152
- * 匹配前逐行剔除字符串/注释内容(MF-4):字符串字面量里的 "agent(s)" 不再误触发。
153
- * 非字面量实参(agent(callVar) / agent(expr))跳过不回调:description 等选项在调用点
154
- * 静态不可见,checkAgentDescription 无法验证运行时构造的调用——继续报 warning 即误报
155
- * (review-fix-loop 的 agent(call) 三连误报根因)。
156
- *
157
- * @param callback (startLine, endLine) 0-based 行号
158
- */
159
- function forEachAgentCallRange(
160
- source: string,
161
- callback: (startLine: number, endLine: number) => void,
162
- ): void {
163
- const lines = source.split("\n");
164
- let inAgentCall = false;
165
- let depth = 0;
166
- let agentStartLine = -1;
167
-
168
- for (let i = 0; i < lines.length; i++) {
169
- const line = lines[i];
170
- const trimmed = line.trim();
171
-
172
- // 跳过注释
173
- if (trimmed.startsWith("//") || trimmed.startsWith("*") || trimmed.startsWith("/*")) {
174
- continue;
175
- }
176
-
177
- // 匹配/计括号都用剔除字符串与注释后的行,避免字面量内容干扰
178
- const codeLine = stripStringsAndComments(line);
179
-
180
- // 检测 agent 调用开始
181
- if (!inAgentCall && /\bagent\s*\(/.test(codeLine)) {
182
- inAgentCall = true;
183
- depth = 0;
184
- agentStartLine = i;
185
- // 从 agent( 开始计括号
186
- const afterAgent = codeLine.replace(/^.*?\bagent\s*\(/, "(");
187
- // 非字面量实参(agent(callVar) / agent(expr))→ 跳过(见函数头注释)。
188
- // 形如 `agent(` 换行 `{` 的多行字面量调用(argTail 为空)保留原追踪行为。
189
- const argTail = afterAgent.trimStart().slice(1).trimStart();
190
- if (argTail.length > 0 && !argTail.startsWith("{")) {
191
- inAgentCall = false;
192
- continue;
193
- }
194
- for (const ch of afterAgent) {
195
- if (ch === "(" || ch === "{" || ch === "[") depth++;
196
- if (ch === ")" || ch === "}" || ch === "]") depth--;
197
- }
198
- if (depth <= 0) {
199
- // 单行 agent 调用
200
- callback(agentStartLine, i);
201
- inAgentCall = false;
202
- }
203
- continue;
204
- }
205
-
206
- if (inAgentCall) {
207
- for (const ch of codeLine) {
208
- if (ch === "(" || ch === "{" || ch === "[") depth++;
209
- if (ch === ")" || ch === "}" || ch === "]") depth--;
210
- }
211
- if (depth <= 0) {
212
- callback(agentStartLine, i);
213
- inAgentCall = false;
214
- }
215
- }
216
- }
217
- }
218
-
219
- /**
220
- * 找出 source 中所有 agent 调用跨度,检查错误的选项 key(outputSchema)。
221
- * 范围遍历委托 forEachAgentCallRange。
222
- */
223
- function checkAgentCalls(source: string): LintFinding[] {
224
- const lines = source.split("\n");
225
- const findings: LintFinding[] = [];
226
- forEachAgentCallRange(source, (startLine, endLine) => {
227
- checkAgentCallOptions(lines, startLine, endLine, findings);
228
- });
229
- return findings;
230
- }
231
-
232
- /**
233
- * 检查 agent 调用内的错误选项 key。
234
- * 只标记 outputSchema 作为 KEY(属性名)使用的情况,不标记作为 VALUE。
235
- *
236
- * Error: { outputSchema } ← 简写属性(outputSchema 是 key)
237
- * Error: { outputSchema: ... } ← 显式 key
238
- * OK: { schema: outputSchema } ← outputSchema 是 value,`schema` 是 key
239
- * OK: const outputSchema = {} ← 变量声明(在 agent 调用外)
240
- */
241
- function checkAgentCallOptions(
242
- lines: string[],
243
- startLine: number,
244
- endLine: number,
245
- findings: LintFinding[],
246
- ): void {
247
- for (let i = startLine; i <= endLine; i++) {
248
- const line = lines[i];
249
-
250
- // 跳过变量声明(const/let/var outputSchema = ...)
251
- if (/\b(?:const|let|var)\s+outputSchema\b/.test(line)) {
252
- continue;
253
- }
254
-
255
- // 匹配:outputSchema 作为对象 key(简写或显式)
256
- if (/\boutputSchema\s*[,\}]/.test(line) || /\boutputSchema\s*:/.test(line)) {
257
- // 排除:outputSchema 作为 value(在另一个 key 的冒号后)
258
- // e.g. "schema: outputSchema," — outputSchema 前是冒号
259
- const beforeOutput = line.substring(0, line.indexOf("outputSchema"));
260
- if (/:\s*$/.test(beforeOutput)) {
261
- continue; // outputSchema 是 value,不是 key
262
- }
263
-
264
- findings.push({
265
- severity: "error",
266
- line: i + 1,
267
- message: "`outputSchema` is not a valid agent() option.",
268
- suggestion: "Use `schema` instead of `outputSchema`.",
269
- });
270
- }
271
- }
272
- }
273
-
274
- /**
275
- * 剔除 agent 选项对象里的 schema 块(`schema: {...}` 嵌套对象,括号配对)。
276
- * 用于 checkAgentDescription:JSON Schema 的 properties 里常见 `description:` 字段
277
- * (schema 文档字段,不是 agent 选项)——只剔字符串字面量时该 key 仍保留,会把
278
- * 内嵌 description 误判为「已提供」导致漏报(I-10 修正的剩余部分)。
279
- * 输入为已剔除字符串/注释的 range(无引号内容干扰,括号配对安全)。
280
- */
281
- function stripSchemaBlocks(text: string): string {
282
- let out = "";
283
- let i = 0;
284
- while (i < text.length) {
285
- const m = text.slice(i).match(/\bschema\s*:\s*\{/);
286
- if (!m || m.index === undefined) {
287
- out += text.slice(i);
288
- break;
289
- }
290
- const start = i + m.index;
291
- const braceIdx = start + m[0].lastIndexOf("{");
292
- out += text.slice(i, start);
293
- let depth = 0;
294
- let j = braceIdx;
295
- for (; j < text.length; j++) {
296
- if (text[j] === "{") depth++;
297
- else if (text[j] === "}") {
298
- depth--;
299
- if (depth === 0) {
300
- j++;
301
- break;
302
- }
303
- }
304
- }
305
- i = j;
306
- }
307
- return out;
308
- }
309
-
310
- /**
311
- * 检查 agent 调用是否提供 description(或其别名 label)。
312
- *
313
- * worker-script-builder 取 `firstArg.label || firstArg.description` 作 TUI 显示名,
314
- * 两者都缺 → node.agent 为空 → /workflows 视图显示 '(unnamed)'。
315
- *
316
- * 实现复用 forEachAgentCallRange 的范围定义,在范围内检测 `description:` 或 `label:`
317
- * 作为对象 key。两层剔除保证只认 agent 选项层的真正 key:① 字符串字面量(
318
- * stripStringsAndComments,MF-4);② schema 块(stripSchemaBlocks——schema 内嵌的
319
- * `description:` 是 JSON Schema 字段说明不是 agent 选项,不剔除会漏报)。
320
- */
321
- function checkAgentDescription(source: string): LintFinding[] {
322
- const lines = source.split("\n");
323
- const findings: LintFinding[] = [];
324
- forEachAgentCallRange(source, (startLine, endLine) => {
325
- // range 逐行剔除字符串字面量(MF-4)后再剔除 schema 块:schema 内嵌的
326
- // `description:` 对象 key(JSON Schema 字段说明)不再被误判为「已提供」——
327
- // 只有 agent 选项层的真正 description/label key 才算数(修正 I-10 漏报方向)。
328
- const range = stripSchemaBlocks(lines.slice(startLine, endLine + 1).map(stripStringsAndComments).join("\n"));
329
- // 对象以展开开头(agent({ ...call, ... })):description 来自运行时对象、调用点静态
330
- // 不可见——无法验证即不报(review-fix-loop 的 agent({ ...call, agent: ... }) 即此形态)。
331
- if (/\{\s*\.\.\./.test(range)) return;
332
- // 匹配 description 或 label 作为对象 key(后跟冒号)
333
- if (!/\b(description|label)\s*:/.test(range)) {
334
- findings.push({
335
- severity: "warning",
336
- line: startLine + 1,
337
- message:
338
- "agent() call without `description` (or `label`) will show as '(unnamed)' in TUI.",
339
- suggestion:
340
- "Add `description: 'kebab-case-name'` to agent() opts for readable /workflows display.",
341
- });
342
- }
343
- });
344
- return findings;
345
- }
346
-
347
- // ── 顶层未 await 的异步 IIFE 检测 ───────────────────────────
348
-
349
- /**
350
- * 匹配未 await 的 async IIFE 起点(粗筛)。
351
- *
352
- * 形式:`(async function`、`(async ()`、`(async (args)` 后跟 `=>`
353
- * 不匹配:`await (async ...`(lookbehind 排除)
354
- */
355
- const BARE_ASYNC_IIFE_PATTERN = /(^|[;\n\s{}(])(?<!await\s)\(async\s+(?:function\b|\(\)|\([^)]*\)\s*=>)/g;
356
-
357
- /**
358
- * 判断 IIFE 调用表达式是否被某个上下文「接住」(return/赋值/await 链等)。
359
- *
360
- * 返回 true 表示 IIFE 的 Promise 被接住(合法或可能合法);
361
- * false 表示 IIFE 是孤立语句表达式(fire-and-forget)。
362
- *
363
- * 判断方法:扫描 IIFE 起点 `(async` 前的非空白 token:
364
- * - 遇到 `=` `return` `await` `(` `[` `,` → 接住
365
- * - 遇到 `;` `{` `}` 或行首 → 孤立语句
366
- *
367
- * 例:
368
- * `const x = (async ...` → '=' 接住
369
- * `return (async ...` → 'return' 接住
370
- * `(async ...` 行首 → 孤立
371
- * `}; (async ...` → 孤立(前一个语句结束后新起一个)
372
- */
373
- function isIIFEAwaited(source: string, iifeStart: number): boolean {
374
- let i = iifeStart - 1;
375
- while (i >= 0) {
376
- const ch = source[i];
377
- if (/\s/.test(ch)) {
378
- i--;
379
- continue;
380
- }
381
- // 当前字符是标识符字符 → 向前扫完整标识符
382
- if (/[A-Za-z0-9_$]/.test(ch)) {
383
- // return / await / yield / 变量名(如 `foo(async ...`)→ 接住
384
- return true;
385
- }
386
- // 单字符操作符
387
- if (ch === "=" || ch === "(" || ch === "[" || ch === "," || ch === "?" || ch === ":") {
388
- return true;
389
- }
390
- if (ch === ";" || ch === "{" || ch === "}" || ch === ")") {
391
- return false;
392
- }
393
- // 其他字符(如 `.` `+`),保守视为接住(避免误报)
394
- return true;
395
- }
396
- return false;
397
- }
398
-
399
- /**
400
- * 检测未 await 的 async IIFE,且其内部调用了 agent/parallel/pipeline。
401
- *
402
- * 严重度分级:
403
- * - **error**:IIFE 是孤立语句表达式(fire-and-forget)+ 内部调 agent。
404
- * 这是 daily-news-impact 的 bug 模式——worker 外层 IIFE 不等内层就 post return,
405
- * 主线程 transition done → releaseRuntime → controller.abort() → SIGKILL 子进程。
406
- * - **warning**:IIFE 被 `=`/`return`/`(` 等接住(可能后续 await),但内部调 agent。
407
- * 提醒作者确认 Promise 真的被 await,不阻断运行。
408
- *
409
- * 误报规避(不报):
410
- * - await 前缀的 IIFE(lookbehind 排除)
411
- * - IIFE 内不含 agent/parallel/pipeline(stock-screening 这类纯 execSync 合法)
412
- *
413
- * 局限:纯正则 + 括号配对,无法做数据流分析。「赋值后稍后 await」「return 给外层 await」
414
- * 都识别为「接住」(warning 而非 error),避免阻断合法写法。
415
- */
416
- function checkBareAsyncIIFE(source: string): LintFinding[] {
417
- if (!ENTRY_POINT_PATTERNS.some((p) => p.test(source))) return [];
418
-
419
- // 用 matchAll 检查所有 IIFE(脚本可能有多个,每个都需独立判断)
420
- const findings: LintFinding[] = [];
421
- for (const match of source.matchAll(BARE_ASYNC_IIFE_PATTERN)) {
422
- const iifeStart = match.index ?? 0;
423
- const finding = analyzeIIFE(source, iifeStart);
424
- if (finding) findings.push(finding);
425
- }
426
- return findings;
427
- }
428
-
429
- /**
430
- * 分析单个 IIFE 起点是否触发 finding。
431
- *
432
- * 返回 LintFinding(error 或 warning)或 undefined(IIFE 内无 agent/无闭合)。
433
- * 详见 checkBareAsyncIIFE 的 [HISTORICAL] 教训记录。
434
- */
435
- function analyzeIIFE(source: string, iifeStart: number): LintFinding | undefined {
436
- const iifeLine = source.slice(0, iifeStart).split("\n").length;
437
-
438
- const firstBrace = source.indexOf("{", iifeStart);
439
- if (firstBrace === -1) return undefined;
440
-
441
- let depth = 0;
442
- let iifeEnd = -1;
443
- for (let i = firstBrace; i < source.length; i++) {
444
- const ch = source[i];
445
- if (ch === "{") depth++;
446
- else if (ch === "}") {
447
- depth--;
448
- if (depth === 0) {
449
- iifeEnd = i;
450
- break;
451
- }
452
- }
453
- }
454
- if (iifeEnd === -1) return undefined;
455
-
456
- const iifeBody = source.slice(firstBrace, iifeEnd);
457
- const hasAgentInside = ENTRY_POINT_PATTERNS.some((p) => p.test(iifeBody));
458
- if (!hasAgentInside) return undefined;
459
-
460
- const awaited = isIIFEAwaited(source, iifeStart);
461
- if (awaited) {
462
- return {
463
- severity: "warning",
464
- line: iifeLine,
465
- message:
466
- "Async IIFE wrapping agent() is assigned/returned but must be awaited. If the surrounding context does not await this Promise, the worker will post `return` early and kill in-flight agent() subprocesses.",
467
- suggestion:
468
- "Verify the surrounding code awaits this IIFE's Promise. When unsure, prefer top-level await directly (the worker already wraps your script in an async IIFE).",
469
- };
470
- }
471
-
472
- return {
473
- severity: "error",
474
- line: iifeLine,
475
- message:
476
- "Top-level async IIFE is a fire-and-forget statement. The worker's outer IIFE will post `return` before agent() resolves, killing the subprocess via runtime abort.",
477
- suggestion:
478
- "Remove the IIFE wrapper and use top-level await directly (the worker already wraps your script in an async IIFE). Or `await` the IIFE: `await (async function main() { ... })();`.",
479
- };
480
- }
481
-
482
- // ── 显示性检查(description / phase)───────────────────────────
483
-
484
- /**
485
- * 检查 meta.phases 是否字符串数组。
486
- *
487
- * 引擎 buildPhaseGroups 只按运行时 node.phase 分组,不读 meta.phases 声明。但 meta.phases
488
- * 仍用于文档/一致性检查(见 checkPhaseConsistency),且 SSOT 约定为字符串数组。对象数组
489
- * (如 [{title,detail}])是常见误写,提醒作者改为字符串数组。
490
- */
491
- function checkMetaPhases(source: string): LintFinding[] {
492
- const findings: LintFinding[] = [];
493
- // 跨行匹配(\s* 含换行):`phases: [` 与 `{` 换行分离的多行对象数组同样命中。
494
- // 原逐行匹配只命中「`[` 与 `{` 同行」,最常见的格式化写法(phases: [ 换行 { ... })零检出(MF-5)。
495
- // 行号从 match index 反推。字符串数组(phases: [\n "a")不匹配 \s*\{,不会误报。
496
- for (const m of source.matchAll(/phases\s*:\s*\[\s*\{/g)) {
497
- if (m.index === undefined) continue;
498
- const lineNum = source.slice(0, m.index).split("\n").length;
499
- findings.push({
500
- severity: "warning",
501
- line: lineNum,
502
- message:
503
- "`meta.phases` should be a string array like ['phase1','phase2']. Object arrays are ignored by the engine.",
504
- suggestion:
505
- "Use `phases: ['analyze','fix']`. Engine groups nodes by runtime `phase()` calls, not by `meta.phases` declarations.",
506
- });
507
- }
508
- return findings;
509
- }
510
-
511
- /**
512
- * 检查 meta.phases 声明与 phase() 调用的一致性。
513
- *
514
- * - 声明了但从未 phase() 调用 → warning(运行时分组用不上,声明形同虚设)
515
- * - phase() 调用了但未声明 → warning(声明遗漏,meta.phases 失去文档价值)
516
- *
517
- * 两者都为空时跳过(脚本不使用 phase 机制,不报)。
518
- */
519
- function checkPhaseConsistency(source: string): LintFinding[] {
520
- const findings: LintFinding[] = [];
521
-
522
- // 提取 meta.phases 声明的字符串 + 声明所在行号
523
- const declared = new Map<string, number>();
524
- const phasesArrayMatch = source.match(/phases\s*:\s*\[[^\]]*\]/);
525
- if (phasesArrayMatch && phasesArrayMatch.index !== undefined) {
526
- const inner = phasesArrayMatch[0];
527
- // 对象数组(如 [{title,detail}])由 checkMetaPhases 单独报,这里跳过提取,
528
- // 避免从对象字段里误抽出字符串作 declared。
529
- if (!/\[\s*\{/.test(inner)) {
530
- const phasesLine = source.slice(0, phasesArrayMatch.index).split("\n").length;
531
- for (const m of inner.matchAll(/['"]([^'"]+)['"]/g)) {
532
- if (!declared.has(m[1])) declared.set(m[1], phasesLine);
533
- }
534
- }
535
- }
536
-
537
- // 提取所有 phase() 调用实参 + 首次出现的行号
538
- const called = new Map<string, number>();
539
- for (const m of source.matchAll(/\bphase\s*\(\s*['"]([^'"]+)['"]/g)) {
540
- if (m.index === undefined) continue;
541
- const lineNum = source.slice(0, m.index).split("\n").length;
542
- if (!called.has(m[1])) called.set(m[1], lineNum);
543
- }
544
-
545
- // 两者都为空 → 跳过(脚本不使用 phase 机制)
546
- if (declared.size === 0 && called.size === 0) return [];
547
-
548
- // 声明了但从未 phase() 调用
549
- for (const [name, line] of declared) {
550
- if (!called.has(name)) {
551
- findings.push({
552
- severity: "warning",
553
- line,
554
- message: `declared phase '${name}' never set via phase().`,
555
- suggestion: `Add phase('${name}') before the agent() calls belonging to this phase, or remove it from meta.phases.`,
556
- });
557
- }
558
- }
559
-
560
- // 调用了但未声明
561
- for (const [name, line] of called) {
562
- if (!declared.has(name)) {
563
- findings.push({
564
- severity: "warning",
565
- line,
566
- message: `phase('${name}') called but not in meta.phases.`,
567
- suggestion: `Add '${name}' to meta.phases array, e.g. phases: [..., '${name}'].`,
568
- });
569
- }
570
- }
571
-
572
- return findings;
573
- }
574
-
575
- /**
576
- * 静态检查 workflow 脚本合法性。
577
- *
578
- * @param source 脚本源码(原始文件内容)
579
- * @returns LintResult(valid = 无 error 级 finding)
580
- */
581
- /**
582
- * W2/W3 共享 helper:meta 描述字段长度上限 + 单句判定(workflow lintScript 与
583
- * agent lintAgentMeta 共用同一规则——S-5 对称,避免 agent 长 description 常驻膨胀)。
584
- *
585
- * W2:>200 字符 → error。
586
- * W3:括号内容剥离((…)/(…)与 (...))后含换行/。;/'. ' 分句 → error。
587
- * 输出格式与 severity 约定与 checkMetaQuality 一致(error / line 1 / meta.<field> 前缀)。
588
- */
589
- function checkMetaFieldQuality(field: string, value: string): LintFinding[] {
590
- const findings: LintFinding[] = [];
591
- // W2
592
- if (value.length > DESC_MAX_LENGTH) {
593
- findings.push({
594
- severity: "error",
595
- line: 1,
596
- message: `meta.${field} 长度 ${value.length} 超过 ${DESC_MAX_LENGTH} 字符(§5.1 注入段预算约束)`,
597
- suggestion: "精简为单句路由描述,细节移入 usage",
598
- });
599
- }
600
- // W3:括号剥离后分句判定
601
- const stripped = value
602
- .replace(/([^)]*)/g, "")
603
- .replace(/\([^)]*\)/g, "")
604
- .replace(/\b(?:e\.g|i\.e)\.\s/g, ""); // 缩写剔除(exec-review F8:括号外 e.g. 不误报)
605
- if (/[\n。;]|\.\s/.test(stripped)) {
606
- findings.push({
607
- severity: "error",
608
- line: 1,
609
- message: `meta.${field} 非单句(含换行/分句标点)——§5.1 注入段要求一句话路由描述`,
610
- suggestion: "精简为单句,细节移入 when/notFor/usage",
611
- });
612
- }
613
- return findings;
614
- }
615
-
616
- /**
617
- * W1-W3:SSOT lint(m4)——保 §5.1 注入段 description 短单句、不含已声明参数名。
618
- * 仅对 parseResourceMeta 解析成功的 meta 执行(旧 const meta 格式不检查)。
619
- *
620
- * W1 参数名匹配(非形态匹配):'note:'/'Example:'/'a=b' 等 prose 不误报(design-review
621
- * 探针实测形态匹配误报面);参数名集合 = meta.parameters.properties keys + patternProperties
622
- * 的 word 前缀(^word\\d+$ 转义形态)。检查面 = description + when + notFor 三字段
623
- * (同进 §5.1 注入段)。W2/W3 抽到 checkMetaFieldQuality(lintAgentMeta 共用)。
624
- */
625
- function checkMetaQuality(meta: { description?: string; when?: string; notFor?: string; parameters?: Record<string, unknown> }): LintFinding[] {
626
- const findings: LintFinding[] = [];
627
- const description = meta.description ?? "";
628
-
629
- // W1 参数名集合
630
- const paramNames = new Set<string>();
631
- if (meta.parameters && typeof meta.parameters === "object") {
632
- const props = (meta.parameters as Record<string, unknown>).properties;
633
- if (props !== null && typeof props === "object") {
634
- for (const k of Object.keys(props as Record<string, unknown>)) paramNames.add(k);
635
- }
636
- const pp = (meta.parameters as Record<string, unknown>).patternProperties;
637
- if (pp !== null && typeof pp === "object") {
638
- for (const p of Object.keys(pp as Record<string, unknown>)) {
639
- const m = p.match(/^\^([a-zA-Z]+)\\d\+\$$/);
640
- if (m) paramNames.add(m[1] as string);
641
- }
642
- }
643
- }
644
-
645
- const fields: Array<[string, string]> = [
646
- ["description", description],
647
- ["when", meta.when ?? ""],
648
- ["notFor", meta.notFor ?? ""],
649
- ];
650
- for (const [field, value] of fields) {
651
- if (value.length === 0) continue;
652
- // W1:已声明参数名的 ':'/'=' 形态(参数名转义防 RegExp 注入崩溃——exec-review F2;
653
- // ':' 形态加 \\b 前缀防子串误报(subtask: 不命中 task——exec-review F6))
654
- for (const name of paramNames) {
655
- const nameEsc = name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
656
- if (new RegExp(`\\b${nameEsc}:\\s`).test(value) || new RegExp(`\\b${nameEsc}=\\S`).test(value)) {
657
- findings.push({
658
- severity: "error",
659
- line: 1,
660
- message: `meta.${field} 包含已声明参数名 '${name}'('${name}:' / '${name}=' 形态)——参数契约请 read 脚本文件的 @pi-meta parameters 查询,description/when/notFor 只放路由信息`,
661
- suggestion: `从 meta.${field} 移除 '${name}: ...' / '${name}=...',改在 parameters/usage 中声明`,
662
- });
663
- }
664
- }
665
- findings.push(...checkMetaFieldQuality(field, value));
666
- }
667
- return findings;
668
- }
669
-
670
- /**
671
- * W2/W3 + W4(m4/m5 挂 agent 加载路径):description/when/notFor 长度与单句检查
672
- * (与 workflow 同规则,S-5 对称)+ examples 正反各一。
673
- * RoutingExample.positive 判别(action 是 string 非 null);examples 缺失 → 无 finding
674
- * (未迁移 agent 不报错——m5 挂载安全根基)。
675
- */
676
- export function lintAgentMeta(meta: AgentMeta): LintFinding[] {
677
- // W2/W3(S-5 对称):agent 的 description/when/notFor 与 workflow 同规则
678
- // (长度上限 + 单句判定)——formatAgentList 原样注入 systemPrompt,长描述是每 turn 常驻成本。
679
- const findings: LintFinding[] = [];
680
- const fields: Array<[string, string]> = [
681
- ["description", meta.description],
682
- ["when", meta.when ?? ""],
683
- ["notFor", meta.notFor ?? ""],
684
- ];
685
- for (const [field, value] of fields) {
686
- if (value.length === 0) continue;
687
- findings.push(...checkMetaFieldQuality(field, value));
688
- }
689
-
690
- const examples = meta.examples;
691
- if (examples === undefined) return findings; // 未迁移 agent(无 examples 字段)不报错
692
- if (examples.length === 0) {
693
- findings.push({
694
- severity: "error",
695
- line: 1,
696
- message: `agent '${meta.name}' 声明了 examples 但为空——需 ≥2 条且正反各一`,
697
- suggestion: "补正向样本(何时调用)+ 反向样本(何时不调用)",
698
- });
699
- return findings;
700
- }
701
- const hasPositive = examples.some((e) => e.positive === true);
702
- const hasNegative = examples.some((e) => e.positive === false);
703
- if (examples.length < EXAMPLES_MIN_COUNT || !hasPositive || !hasNegative) {
704
- findings.push({
705
- severity: "error",
706
- line: 1,
707
- message: `agent '${meta.name}' 的 examples 需 ≥2 条且正反各一(positive:true 触发路由 + positive:false 反例)`,
708
- suggestion: "补正向样本(何时调用)+ 反向样本(何时不调用)",
709
- });
710
- return findings;
711
- }
712
- if (examples.length > EXAMPLES_MAX_COUNT) {
713
- findings.push({
714
- severity: "error",
715
- line: 1,
716
- message: `agent '${meta.name}' 的 examples ${examples.length} 条超过上限 ${EXAMPLES_MAX_COUNT}(注入段是每 turn 常驻成本)`,
717
- suggestion: "精简到 2-4 条:正反各一 + 最多 2 条冗余",
718
- });
719
- }
720
- return findings;
721
- }
722
-
723
- export function lintScript(source: string): LintResult {
724
- const lines = source.split("\n");
725
- const findings: LintFinding[] = [];
726
-
727
- // 入口检查(必须有 agent/parallel/pipeline 之一)
728
- findings.push(...checkEntryPoint(source));
729
-
730
- // 逐行检查(result.output、文件传状态等)
731
- for (let i = 0; i < lines.length; i++) {
732
- findings.push(...checkLine(lines[i], i + 1));
733
- }
734
-
735
- // agent 调用上下文检查(outputSchema 作为 key)
736
- findings.push(...checkAgentCalls(source));
737
-
738
- // [HISTORICAL] 顶层未 await 的异步 IIFE + 内部调 agent——子进程被提前 kill。
739
- // 教训来源:daily-news-impact.js 用 (async function main(){...})();() 包裹整个脚本,
740
- // worker 外层 IIFE 不等内层 IIFE 就 postMessage("return"),主线程 transition done
741
- // → release runtime → controller.abort() → spawn 后 2ms SIGKILL 子进程。
742
- // 诊断耗时 4 轮:先后误判为 model 故障 / 工具缺失 / turn-signal abort / 并发门闩 gate 异常,
743
- // 最终靠 worker-host → handleReturn → release → abort 的调用栈定位。
744
- findings.push(...checkBareAsyncIIFE(source));
745
-
746
- // m4 W1-W3:meta 质量(description/when/notFor 短单句 + 不含已声明参数名)。
747
- // 仅对 IF1 解析成功的 @pi-meta 执行——旧 const meta 格式(D1 无 adapter)不检查。
748
- const meta = parseResourceMeta(source, "workflow");
749
- if (meta && meta.kind === "workflow") {
750
- findings.push(...checkMetaQuality(meta));
751
- }
752
-
753
- // 显示性检查(warning):agent 缺 description / meta.phases 形式 / phase 一致性。
754
- // 目的:让 TUI /workflows 视图避免 unnamed agent 与 (unnamed) phase 分组。
755
- findings.push(...checkAgentDescription(source));
756
- findings.push(...checkMetaPhases(source));
757
- findings.push(...checkPhaseConsistency(source));
758
-
759
- // 按行号排序,稳定输出
760
- findings.sort((a, b) => a.line - b.line);
761
-
762
- return {
763
- valid: !findings.some((f) => f.severity === "error"),
764
- findings,
765
- };
766
- }