@zhushanwen/subagent-core 0.2.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 (330) hide show
  1. package/README.md +114 -0
  2. package/dist/chunk-3VOERJPJ.js +22 -0
  3. package/dist/chunk-A4IVZWVX.js +31 -0
  4. package/dist/execution/engine/engines/zcode/constants.cjs +54 -0
  5. package/dist/execution/engine/engines/zcode/constants.d.cts +31 -0
  6. package/dist/execution/engine/engines/zcode/constants.d.ts +31 -0
  7. package/dist/execution/engine/engines/zcode/constants.js +22 -0
  8. package/dist/execution/engine/engines/zcode/reader.cjs +276 -0
  9. package/dist/execution/engine/engines/zcode/reader.d.cts +20 -0
  10. package/dist/execution/engine/engines/zcode/reader.d.ts +20 -0
  11. package/dist/execution/engine/engines/zcode/reader.js +239 -0
  12. package/dist/execution/engine/paths.cjs +55 -0
  13. package/dist/execution/engine/paths.d.cts +8 -0
  14. package/dist/execution/engine/paths.d.ts +8 -0
  15. package/dist/execution/engine/paths.js +26 -0
  16. package/dist/execution/relay-env.cjs +62 -0
  17. package/dist/execution/relay-env.d.cts +33 -0
  18. package/dist/execution/relay-env.d.ts +33 -0
  19. package/dist/execution/relay-env.js +20 -0
  20. package/dist/index.cjs +1852 -0
  21. package/dist/index.d.cts +1184 -0
  22. package/dist/index.d.ts +1184 -0
  23. package/dist/index.js +1810 -0
  24. package/dist/types-BxyAidGf.d.cts +875 -0
  25. package/dist/types-BxyAidGf.d.ts +875 -0
  26. package/package.json +99 -0
  27. package/src/__tests__/agent-opts-resolver-schema-prompt.test.ts +142 -0
  28. package/src/__tests__/append-system-prompt-assembly.test.ts +242 -0
  29. package/src/__tests__/builtin-workflows-structure.test.ts +180 -0
  30. package/src/__tests__/derive-closed-display-parity.test.ts +93 -0
  31. package/src/__tests__/fr4-get-state-handshake.test.ts +125 -0
  32. package/src/__tests__/fr8-orphan-recovery.test.ts +259 -0
  33. package/src/__tests__/m2-append-content-probe.test.ts +73 -0
  34. package/src/__tests__/manifest-store.test.ts +368 -0
  35. package/src/__tests__/record-store-cache.test.ts +335 -0
  36. package/src/__tests__/record-store-index.test.ts +560 -0
  37. package/src/__tests__/record-store-last-line.test.ts +129 -0
  38. package/src/__tests__/review-fix-loop-script.test.ts +288 -0
  39. package/src/__tests__/review-fix-loop-utils.test.ts +2377 -0
  40. package/src/__tests__/robustness-low-batch1.test.ts +286 -0
  41. package/src/__tests__/robustness-medium-batch1.test.ts +69 -0
  42. package/src/__tests__/robustness-medium-batch2.test.ts +65 -0
  43. package/src/__tests__/robustness-medium-batch3.test.ts +30 -0
  44. package/src/__tests__/robustness-medium-batch4.test.ts +358 -0
  45. package/src/__tests__/session-runner.test.ts +69 -0
  46. package/src/__tests__/smoke.test.ts +9 -0
  47. package/src/__tests__/stream-sink.test.ts +203 -0
  48. package/src/core/__tests__/host-services.test.ts +144 -0
  49. package/src/core/__tests__/logger.test.ts +78 -0
  50. package/src/core/__tests__/notify-ports.test.ts +104 -0
  51. package/src/core/host-services.ts +97 -0
  52. package/src/core/logger.ts +47 -0
  53. package/src/core/notify-ports.ts +126 -0
  54. package/src/execution/__tests__/__fixtures__/notifier-golden-snapshots.json +53 -0
  55. package/src/execution/__tests__/__fixtures__/truncline.snapshot.json +1 -0
  56. package/src/execution/__tests__/agent-result-mapper.test.ts +150 -0
  57. package/src/execution/__tests__/alive-store.test.ts +147 -0
  58. package/src/execution/__tests__/ask-user-transit-e2e.test.ts +490 -0
  59. package/src/execution/__tests__/channel-registry-handshake.test.ts +242 -0
  60. package/src/execution/__tests__/chat-engine-routing.test.ts +610 -0
  61. package/src/execution/__tests__/chatmode-first-round-closure-spawn.test.ts +190 -0
  62. package/src/execution/__tests__/concurrency-pool.test.ts +250 -0
  63. package/src/execution/__tests__/config.test.ts +302 -0
  64. package/src/execution/__tests__/delivery-methods.test.ts +424 -0
  65. package/src/execution/__tests__/dialog-queue.test.ts +299 -0
  66. package/src/execution/__tests__/epipe-fallback.test.ts +241 -0
  67. package/src/execution/__tests__/execute-and-await-worktree.test.ts +243 -0
  68. package/src/execution/__tests__/execute-nesting.test.ts +323 -0
  69. package/src/execution/__tests__/execute-options-mapper.test.ts +200 -0
  70. package/src/execution/__tests__/execution-record.test.ts +1394 -0
  71. package/src/execution/__tests__/explicit-agent-ref-guard.test.ts +171 -0
  72. package/src/execution/__tests__/finalize-record.test.ts +367 -0
  73. package/src/execution/__tests__/finalized-marker.test.ts +104 -0
  74. package/src/execution/__tests__/format-schema-instruction.test.ts +169 -0
  75. package/src/execution/__tests__/gc-timer.test.ts +184 -0
  76. package/src/execution/__tests__/get-record-for-action-restart.test.ts +254 -0
  77. package/src/execution/__tests__/helpers/mock-extension-api.ts +30 -0
  78. package/src/execution/__tests__/helpers/spawn-mock.ts +242 -0
  79. package/src/execution/__tests__/host-mode.test.ts +87 -0
  80. package/src/execution/__tests__/lifecycle-manager-lock.test.ts +211 -0
  81. package/src/execution/__tests__/lifecycle-manager.test.ts +383 -0
  82. package/src/execution/__tests__/lifecycle-predicates.test.ts +116 -0
  83. package/src/execution/__tests__/manifest-parentid.test.ts +117 -0
  84. package/src/execution/__tests__/model-resolver.test.ts +465 -0
  85. package/src/execution/__tests__/nested-visibility-env-propagation.test.ts +287 -0
  86. package/src/execution/__tests__/nested-visibility.test.ts +325 -0
  87. package/src/execution/__tests__/output-collector.test.ts +358 -0
  88. package/src/execution/__tests__/path-encoding.test.ts +104 -0
  89. package/src/execution/__tests__/pi-invocation.test.ts +134 -0
  90. package/src/execution/__tests__/record-store.test.ts +1057 -0
  91. package/src/execution/__tests__/records-cwd-isolation.test.ts +91 -0
  92. package/src/execution/__tests__/recursive-visibility-baseline.test.ts +339 -0
  93. package/src/execution/__tests__/recursive-visibility-env.test.ts +273 -0
  94. package/src/execution/__tests__/relay-env.test.ts +42 -0
  95. package/src/execution/__tests__/resource-policy.test.ts +109 -0
  96. package/src/execution/__tests__/rpc-mode.test.ts +89 -0
  97. package/src/execution/__tests__/run-and-finalize-chatmode.test.ts +267 -0
  98. package/src/execution/__tests__/run-spawn-chatmode-settled.test.ts +253 -0
  99. package/src/execution/__tests__/run-spawn-edges.test.ts +687 -0
  100. package/src/execution/__tests__/run-spawn-integration.test.ts +933 -0
  101. package/src/execution/__tests__/run-spawn-resume.test.ts +322 -0
  102. package/src/execution/__tests__/run-spawn-rpc-mode.test.ts +196 -0
  103. package/src/execution/__tests__/run-spawn-stdout-callback-throw.test.ts +199 -0
  104. package/src/execution/__tests__/session-context-resolver.test.ts +167 -0
  105. package/src/execution/__tests__/session-file-gc.test.ts +293 -0
  106. package/src/execution/__tests__/session-reconstructor.test.ts +379 -0
  107. package/src/execution/__tests__/session-runner-epipe.test.ts +178 -0
  108. package/src/execution/__tests__/session-runner-schema-env.test.ts +350 -0
  109. package/src/execution/__tests__/spawn-args.test.ts +445 -0
  110. package/src/execution/__tests__/spawn-event-adapter-rpc.test.ts +189 -0
  111. package/src/execution/__tests__/spawn-event-adapter.test.ts +167 -0
  112. package/src/execution/__tests__/spawn-worktree-guidance.test.ts +207 -0
  113. package/src/execution/__tests__/spawned-children.test.ts +92 -0
  114. package/src/execution/__tests__/start-sync-model-guard.test.ts +150 -0
  115. package/src/execution/__tests__/stdin-writer.test.ts +462 -0
  116. package/src/execution/__tests__/stream-sink-retirement.test.ts +261 -0
  117. package/src/execution/__tests__/subagent-service-abort.test.ts +60 -0
  118. package/src/execution/__tests__/subagent-service-message-close.test.ts +629 -0
  119. package/src/execution/__tests__/subagent-service-parent-guard.test.ts +180 -0
  120. package/src/execution/__tests__/subagent-service.test.ts +788 -0
  121. package/src/execution/__tests__/subprocess-agent-runner-routing.test.ts +310 -0
  122. package/src/execution/__tests__/subprocess-agent-runner.test.ts +612 -0
  123. package/src/execution/__tests__/temp-prompt.test.ts +53 -0
  124. package/src/execution/__tests__/timeout-integration.test.ts +615 -0
  125. package/src/execution/__tests__/tombstone-store.test.ts +73 -0
  126. package/src/execution/__tests__/turn-limiter-semantics.test.ts +194 -0
  127. package/src/execution/__tests__/turn-limiter.test.ts +65 -0
  128. package/src/execution/__tests__/ui-channels.test.ts +187 -0
  129. package/src/execution/__tests__/ui-interaction-model.test.ts +67 -0
  130. package/src/execution/__tests__/ui-request-handler-factory.test.ts +369 -0
  131. package/src/execution/__tests__/ui-request-handler.test.ts +204 -0
  132. package/src/execution/__tests__/ui-request-observability.test.ts +113 -0
  133. package/src/execution/__tests__/ui-request-queue.test.ts +133 -0
  134. package/src/execution/__tests__/worktree-manager.test.ts +633 -0
  135. package/src/execution/__tests__/worktree-pid-registration.integration.test.ts +229 -0
  136. package/src/execution/__tests__/worktree-reconcile.integration.test.ts +181 -0
  137. package/src/execution/__tests__/worktree-registry.test.ts +199 -0
  138. package/src/execution/agent-registry.ts +199 -0
  139. package/src/execution/agent-result-mapper.ts +90 -0
  140. package/src/execution/alive-store.ts +119 -0
  141. package/src/execution/argv-mirror.ts +113 -0
  142. package/src/execution/best-effort.ts +38 -0
  143. package/src/execution/channel-registry-access.ts +144 -0
  144. package/src/execution/concurrency-pool.ts +116 -0
  145. package/src/execution/config.ts +165 -0
  146. package/src/execution/dialog-queue.ts +330 -0
  147. package/src/execution/engine/__tests__/common/data-dir.test.ts +78 -0
  148. package/src/execution/engine/__tests__/common/errors.test.ts +132 -0
  149. package/src/execution/engine/__tests__/common/event-journal.test.ts +177 -0
  150. package/src/execution/engine/__tests__/common/kill-chain.test.ts +192 -0
  151. package/src/execution/engine/__tests__/common/nesting-guard.test.ts +81 -0
  152. package/src/execution/engine/__tests__/common/persona-router.test.ts +123 -0
  153. package/src/execution/engine/__tests__/common/pool-manager.test.ts +154 -0
  154. package/src/execution/engine/__tests__/common/schema-emulation.test.ts +128 -0
  155. package/src/execution/engine/__tests__/conformance/__fixtures__/pi-golden-events.json +28 -0
  156. package/src/execution/engine/__tests__/conformance/agent-event-invariants.ts +141 -0
  157. package/src/execution/engine/__tests__/conformance/contract.abort.test.ts +109 -0
  158. package/src/execution/engine/__tests__/conformance/contract.agent-events.test.ts +101 -0
  159. package/src/execution/engine/__tests__/conformance/contract.probe.test.ts +77 -0
  160. package/src/execution/engine/__tests__/conformance/contract.read-degradation.test.ts +104 -0
  161. package/src/execution/engine/__tests__/conformance/engine-conformance.live.test.ts +201 -0
  162. package/src/execution/engine/__tests__/conformance/golden-replay.pi.test.ts +76 -0
  163. package/src/execution/engine/__tests__/conformance/golden-replay.zcode.test.ts +79 -0
  164. package/src/execution/engine/__tests__/engine-discovery.test.ts +87 -0
  165. package/src/execution/engine/__tests__/model-prompt.test.ts +197 -0
  166. package/src/execution/engine/__tests__/paths.test.ts +39 -0
  167. package/src/execution/engine/__tests__/registry.test.ts +120 -0
  168. package/src/execution/engine/__tests__/routing.test.ts +231 -0
  169. package/src/execution/engine/common/data-dir.ts +66 -0
  170. package/src/execution/engine/common/errors.ts +183 -0
  171. package/src/execution/engine/common/event-journal.ts +254 -0
  172. package/src/execution/engine/common/journal-replay.ts +62 -0
  173. package/src/execution/engine/common/kill-chain.ts +221 -0
  174. package/src/execution/engine/common/nesting-guard.ts +50 -0
  175. package/src/execution/engine/common/persona-router.ts +108 -0
  176. package/src/execution/engine/common/pool-manager.ts +226 -0
  177. package/src/execution/engine/common/schema-emulation.ts +189 -0
  178. package/src/execution/engine/common/session-view-projection.ts +51 -0
  179. package/src/execution/engine/engine-discovery.ts +65 -0
  180. package/src/execution/engine/engines/pi/__tests__/pi-engine.test.ts +469 -0
  181. package/src/execution/engine/engines/pi/__tests__/reader.test.ts +155 -0
  182. package/src/execution/engine/engines/pi/__tests__/task-spec-mapper.test.ts +164 -0
  183. package/src/execution/engine/engines/pi/pi-engine.ts +415 -0
  184. package/src/execution/engine/engines/pi/reader.ts +48 -0
  185. package/src/execution/engine/engines/pi/registration.ts +35 -0
  186. package/src/execution/engine/engines/pi/task-spec-mapper.ts +100 -0
  187. package/src/execution/engine/engines/zcode/__tests__/__fixtures__/zcode-golden-spawn.json +39 -0
  188. package/src/execution/engine/engines/zcode/__tests__/launcher.test.ts +150 -0
  189. package/src/execution/engine/engines/zcode/__tests__/parser.test.ts +246 -0
  190. package/src/execution/engine/engines/zcode/__tests__/preparer.test.ts +228 -0
  191. package/src/execution/engine/engines/zcode/__tests__/reader.test.ts +210 -0
  192. package/src/execution/engine/engines/zcode/__tests__/registration.test.ts +71 -0
  193. package/src/execution/engine/engines/zcode/__tests__/zcode-engine.live.test.ts +127 -0
  194. package/src/execution/engine/engines/zcode/__tests__/zcode-engine.test.ts +580 -0
  195. package/src/execution/engine/engines/zcode/constants.ts +43 -0
  196. package/src/execution/engine/engines/zcode/golden-sample.ts +39 -0
  197. package/src/execution/engine/engines/zcode/launcher.ts +161 -0
  198. package/src/execution/engine/engines/zcode/parser.ts +436 -0
  199. package/src/execution/engine/engines/zcode/preparer.ts +363 -0
  200. package/src/execution/engine/engines/zcode/reader.ts +381 -0
  201. package/src/execution/engine/engines/zcode/registration.ts +37 -0
  202. package/src/execution/engine/engines/zcode/zcode-engine.ts +658 -0
  203. package/src/execution/engine/host-task-spec.ts +47 -0
  204. package/src/execution/engine/model-prompt.ts +158 -0
  205. package/src/execution/engine/paths.ts +42 -0
  206. package/src/execution/engine/port.ts +153 -0
  207. package/src/execution/engine/registry.ts +133 -0
  208. package/src/execution/engine/routing.ts +218 -0
  209. package/src/execution/engine/types.ts +309 -0
  210. package/src/execution/execute-options-mapper.ts +115 -0
  211. package/src/execution/execution-record.ts +984 -0
  212. package/src/execution/finalize-record.ts +254 -0
  213. package/src/execution/finalized-marker.ts +70 -0
  214. package/src/execution/get-state-handshake.ts +104 -0
  215. package/src/execution/host-mode.ts +56 -0
  216. package/src/execution/idle-gc.ts +47 -0
  217. package/src/execution/lifecycle-manager.ts +513 -0
  218. package/src/execution/lifecycle-predicates.ts +65 -0
  219. package/src/execution/manifest-store.ts +256 -0
  220. package/src/execution/model-config-service.ts +250 -0
  221. package/src/execution/model-resolver.ts +248 -0
  222. package/src/execution/notifier.ts +372 -0
  223. package/src/execution/notify-ledger.ts +580 -0
  224. package/src/execution/output-collector.ts +228 -0
  225. package/src/execution/path-encoding.ts +60 -0
  226. package/src/execution/pi-invocation.ts +120 -0
  227. package/src/execution/record-entry.ts +132 -0
  228. package/src/execution/record-store.ts +1265 -0
  229. package/src/execution/relay-env.ts +37 -0
  230. package/src/execution/session-context-resolver.ts +64 -0
  231. package/src/execution/session-file-gc.ts +120 -0
  232. package/src/execution/session-pending.ts +170 -0
  233. package/src/execution/session-reconstructor.ts +678 -0
  234. package/src/execution/session-runner.ts +1789 -0
  235. package/src/execution/sessions-index.ts +304 -0
  236. package/src/execution/spawn-event-adapter.ts +363 -0
  237. package/src/execution/stdin-writer.ts +198 -0
  238. package/src/execution/stream-sink.ts +126 -0
  239. package/src/execution/subagent-service.ts +2268 -0
  240. package/src/execution/subprocess-agent-runner.ts +317 -0
  241. package/src/execution/temp-prompt.ts +62 -0
  242. package/src/execution/tombstone-store.ts +72 -0
  243. package/src/execution/turn-limiter.ts +102 -0
  244. package/src/execution/types.ts +1023 -0
  245. package/src/execution/ui-channels.ts +216 -0
  246. package/src/execution/ui-interaction-model.ts +48 -0
  247. package/src/execution/ui-request-handler-factory.ts +243 -0
  248. package/src/execution/ui-request-observability.ts +81 -0
  249. package/src/execution/ui-request-queue.ts +184 -0
  250. package/src/execution/worktree-manager.ts +688 -0
  251. package/src/execution/worktree-registry.ts +279 -0
  252. package/src/index.ts +87 -0
  253. package/src/orchestration/__tests__/__fixtures__/worker-template.snapshot.txt +349 -0
  254. package/src/orchestration/__tests__/agent-call-catch-fallback.test.ts +202 -0
  255. package/src/orchestration/__tests__/agent-call-stream.test.ts +152 -0
  256. package/src/orchestration/__tests__/args-validator.test.ts +143 -0
  257. package/src/orchestration/__tests__/config-loader.test.ts +503 -0
  258. package/src/orchestration/__tests__/error-recovery-handlers.test.ts +809 -0
  259. package/src/orchestration/__tests__/error-recovery-postmessage-defense.test.ts +404 -0
  260. package/src/orchestration/__tests__/error-recovery-serialize-failed-result.test.ts +56 -0
  261. package/src/orchestration/__tests__/error-recovery-workflow-call.test.ts +166 -0
  262. package/src/orchestration/__tests__/execute-agent-call.test.ts +451 -0
  263. package/src/orchestration/__tests__/launcher-nested-workflow.test.ts +600 -0
  264. package/src/orchestration/__tests__/lifecycle-runid-injection.test.ts +96 -0
  265. package/src/orchestration/__tests__/lifecycle.test.ts +659 -0
  266. package/src/orchestration/__tests__/non-cloneable-return-e2e.test.ts +95 -0
  267. package/src/orchestration/__tests__/review-fix-loop-scriptpath-failfast.test.ts +183 -0
  268. package/src/orchestration/__tests__/script-lint.test.ts +831 -0
  269. package/src/orchestration/__tests__/skill-discovery.test.ts +210 -0
  270. package/src/orchestration/__tests__/test-mocks.ts +197 -0
  271. package/src/orchestration/__tests__/worker-exit-without-result.test.ts +368 -0
  272. package/src/orchestration/__tests__/worker-host.test.ts +120 -0
  273. package/src/orchestration/__tests__/worker-returnmeta-passthrough.test.ts +164 -0
  274. package/src/orchestration/__tests__/worker-script-builder-runtime.test.ts +563 -0
  275. package/src/orchestration/__tests__/worker-script-builder.test.ts +309 -0
  276. package/src/orchestration/__tests__/worker-script-template-snapshot.test.ts +129 -0
  277. package/src/orchestration/__tests__/workflow-nesting-e2e.test.ts +317 -0
  278. package/src/orchestration/__tests__/workflow-script-lint-memo.test.ts +110 -0
  279. package/src/orchestration/agent-opts-resolver.ts +174 -0
  280. package/src/orchestration/args-validator.ts +127 -0
  281. package/src/orchestration/config-loader.ts +316 -0
  282. package/src/orchestration/error-recovery.ts +1018 -0
  283. package/src/orchestration/execute-agent-call.ts +256 -0
  284. package/src/orchestration/launcher.ts +455 -0
  285. package/src/orchestration/lifecycle.ts +399 -0
  286. package/src/orchestration/models/__tests__/budget.test.ts +307 -0
  287. package/src/orchestration/models/agent-call.ts +83 -0
  288. package/src/orchestration/models/budget.ts +118 -0
  289. package/src/orchestration/models/ports.ts +164 -0
  290. package/src/orchestration/models/run-runtime.ts +104 -0
  291. package/src/orchestration/models/run-spec.ts +83 -0
  292. package/src/orchestration/models/run-state.ts +44 -0
  293. package/src/orchestration/models/trace.ts +183 -0
  294. package/src/orchestration/models/types.ts +301 -0
  295. package/src/orchestration/models/workflow-run.ts +254 -0
  296. package/src/orchestration/models/workflow-script-registry.ts +35 -0
  297. package/src/orchestration/models/workflow-script.ts +117 -0
  298. package/src/orchestration/script-lint.ts +766 -0
  299. package/src/orchestration/skill-discovery.ts +135 -0
  300. package/src/orchestration/worker-handle.ts +115 -0
  301. package/src/orchestration/worker-host.ts +98 -0
  302. package/src/orchestration/worker-script-builder.ts +421 -0
  303. package/src/orchestration/workflow-files.ts +85 -0
  304. package/src/orchestration/workflow-script-registry-impl.ts +133 -0
  305. package/src/shared/__tests__/agent-ref.test.ts +34 -0
  306. package/src/shared/__tests__/meta-parser.test.ts +304 -0
  307. package/src/shared/__tests__/model-ref.test.ts +306 -0
  308. package/src/shared/__tests__/resource-discovery-manifest-cache.test.ts +288 -0
  309. package/src/shared/__tests__/resource-discovery.test.ts +749 -0
  310. package/src/shared/__tests__/resource-meta.test.ts +51 -0
  311. package/src/shared/__tests__/schema-jsonify.test.ts +81 -0
  312. package/src/shared/__tests__/timer-delay.test.ts +61 -0
  313. package/src/shared/agent-event.ts +13 -0
  314. package/src/shared/agent-ref.ts +57 -0
  315. package/src/shared/meta-parser.ts +261 -0
  316. package/src/shared/model-ref.ts +286 -0
  317. package/src/shared/resource-discovery.ts +835 -0
  318. package/src/shared/resource-meta.ts +65 -0
  319. package/src/shared/schema-env.ts +44 -0
  320. package/src/shared/schema-jsonify.ts +58 -0
  321. package/src/shared/timer-delay.ts +54 -0
  322. package/src/shared/xml-injection.ts +35 -0
  323. package/workflows/README.md +81 -0
  324. package/workflows/_shared/agent-refs.cjs +40 -0
  325. package/workflows/chain.js +137 -0
  326. package/workflows/map-reduce.js +180 -0
  327. package/workflows/parallel.js +154 -0
  328. package/workflows/review-fix-loop-utils.cjs +1542 -0
  329. package/workflows/review-fix-loop.js +1605 -0
  330. package/workflows/scatter-gather.js +184 -0
@@ -0,0 +1,129 @@
1
+ /**
2
+ * readLastJsonlLine 孤儿终态判定用例(W2 移交 CRAP 43.1;私有函数,经公共 API
3
+ * RecordStore.recoverOrphanRecords 驱动——appendEntry 捕获判定结果)。
4
+ *
5
+ * [HISTORICAL] 回归锚点(record-store.ts 窗口扩容注释 / V1 探针):真实库存在
6
+ * 28 个末行 65KB-776KB 的完整 entry(subagent-identity 的 task 内嵌大 payload)。
7
+ * 旧实现固定 64KB 尾窗把超长末行从中间切开 → JSON.parse 失败 → 误判「截断」→
8
+ * 孤儿恢复错落 error。本文件的 300KB 完整末行用例在旧实现上会红。
9
+ *
10
+ * 判定矩阵(finalizeOrphanRecord):
11
+ * - 末行完整 JSON(含超长行)→ closed/gc 且无 error
12
+ * - 末行截断(无尾换行的半行 JSON)→ closed/gc + error "truncated last line"
13
+ * - 超长且截断的组合 → 仍按截断判 error(不因行长放宽)
14
+ */
15
+ import * as fs from "node:fs";
16
+ import * as os from "node:os";
17
+ import * as path from "node:path";
18
+
19
+ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
20
+
21
+ import { ManifestStore } from "../execution/manifest-store";
22
+ import { RecordStore } from "../execution/record-store";
23
+
24
+ interface CapturedEntry {
25
+ type: string;
26
+ data: Record<string, unknown>;
27
+ }
28
+
29
+ function makePiHook() {
30
+ const entries: CapturedEntry[] = [];
31
+ return {
32
+ entries,
33
+ pi: { appendEntry: vi.fn((type: string, entry: unknown) => { entries.push({ type, data: entry as Record<string, unknown> }); }) },
34
+ };
35
+ }
36
+
37
+ describe("readLastJsonlLine 孤儿终态判定(超长末行 / 截断行)", () => {
38
+ let rootDir: string;
39
+ let sessionsDir: string;
40
+
41
+ beforeEach(() => {
42
+ rootDir = fs.mkdtempSync(path.join(os.tmpdir(), "lastline-"));
43
+ sessionsDir = path.join(rootDir, "sessions");
44
+ fs.mkdirSync(sessionsDir);
45
+ });
46
+
47
+ afterEach(() => {
48
+ fs.rmSync(rootDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 20 });
49
+ });
50
+
51
+ /** 写一个会被重建为 running 孤儿的子 session 文件(首行 identity + 自定义末行)。 */
52
+ function writeOrphanSession(id: string, lastLine: string, opts: { trailingNewline?: boolean } = {}): string {
53
+ const identity = JSON.stringify({
54
+ type: "custom",
55
+ customType: "subagent-identity",
56
+ data: {
57
+ id, agent: "worker", mode: "background", task: "t", slug: "s",
58
+ startedAt: 1000, rootSessionId: "session-main", depth: 0,
59
+ },
60
+ });
61
+ const file = path.join(sessionsDir, `2026-07-18T12-00-00-000Z_${id}.jsonl`);
62
+ const middle = JSON.stringify({ type: "message", role: "assistant", content: "mid" });
63
+ const body = [identity, middle, lastLine].join("\n") + (opts.trailingNewline === false ? "" : "\n");
64
+ fs.writeFileSync(file, body, "utf8");
65
+ return file;
66
+ }
67
+
68
+ function recovered(id: string) {
69
+ const { pi, entries } = makePiHook();
70
+ const store = new RecordStore(sessionsDir, new ManifestStore(path.join(rootDir, "records")), pi);
71
+ store.recoverOrphanRecords("session-main");
72
+ const hits = entries.filter((e) => e.data && (e.data as { id?: string }).id === id);
73
+ if (hits.length === 0) throw new Error("orphan record not reported for " + id);
74
+ return hits[hits.length - 1].data as Record<string, unknown>;
75
+ }
76
+
77
+ it("300KB 完整超长末行 → closed/gc 无 error(64KB 固定尾窗的旧实现会误判截断)", () => {
78
+ // 300KB 单行 entry:> 64KB 初始窗 × 4 扩窗一档(64K→256K 仍不够 → 1M 覆盖到文件头)
79
+ const bigPayload = "x".repeat(300 * 1024);
80
+ writeOrphanSession("orphan-bigline", JSON.stringify({ type: "custom", customType: "subagent-record", data: { task: bigPayload, status: "done" } }));
81
+ const rec = recovered("orphan-bigline");
82
+ expect(rec.status).toBe("closed");
83
+ expect(rec.closedReason).toBe("gc");
84
+ expect(rec.error).toBeUndefined();
85
+ });
86
+
87
+ it("末行截断(无尾换行的半行 JSON)→ closed/gc + error 标记截断", () => {
88
+ // 半写入形态:最后一行 JSON 被切断且无尾换行
89
+ const truncated = '{"type":"message","role":"assistant","content":"half-written line without clos';
90
+ writeOrphanSession("orphan-truncated", truncated, { trailingNewline: false });
91
+ const rec = recovered("orphan-truncated");
92
+ expect(rec.status).toBe("closed");
93
+ expect(rec.closedReason).toBe("gc");
94
+ expect(rec.error).toContain("truncated last line");
95
+ });
96
+
97
+ it("超长且截断的末行 → 仍判截断 error(扩窗是为完整行服务,不放宽截断判定)", () => {
98
+ const bigTruncated = JSON.stringify({ type: "custom", customType: "subagent-record", data: { task: "y".repeat(300 * 1024) } }).slice(0, 300 * 1024);
99
+ writeOrphanSession("orphan-bigcut", bigTruncated, { trailingNewline: false });
100
+ const rec = recovered("orphan-bigcut");
101
+ expect(rec.status).toBe("closed");
102
+ expect(rec.error).toContain("truncated last line");
103
+ });
104
+
105
+ it("常规末行(多行文件、完整 JSON)→ closed/gc 无 error", () => {
106
+ writeOrphanSession("orphan-normal", JSON.stringify({ type: "message", role: "assistant", content: "final" }));
107
+ const rec = recovered("orphan-normal");
108
+ expect(rec.status).toBe("closed");
109
+ expect(rec.closedReason).toBe("gc");
110
+ expect(rec.error).toBeUndefined();
111
+ });
112
+
113
+ it("仅 identity 单行文件(首行即末行,合法 JSON)→ closed 无 error", () => {
114
+ const identity = JSON.stringify({
115
+ type: "custom",
116
+ customType: "subagent-identity",
117
+ data: {
118
+ id: "orphan-empty", agent: "worker", mode: "background", task: "t", slug: "s",
119
+ startedAt: 1000, rootSessionId: "session-main", depth: 0,
120
+ },
121
+ });
122
+ // identity 首行 + 紧跟空行结尾:非空段只剩 identity(窗口到文件头,首段完整)
123
+ fs.writeFileSync(path.join(sessionsDir, "2026-07-18T12-00-00-000Z_orphan-empty.jsonl"), identity + "\n", "utf8");
124
+ const rec = recovered("orphan-empty");
125
+ // 唯一非空行 = identity 首行(合法 JSON)→ 不判 error
126
+ expect(rec.status).toBe("closed");
127
+ expect(rec.error).toBeUndefined();
128
+ });
129
+ });
@@ -0,0 +1,288 @@
1
+ // review-fix-loop.js workflow 脚本内纯函数直测(W2 移交 CRAP 240/110 最高项)。
2
+ //
3
+ // 测试方法(限制见文末 import 用例):review-fix-loop.js 是 pi worker 模板脚本——
4
+ // 顶层执行 + 顶层 return,不可作为 ES module import(vite/esbuild 直接 SyntaxError)。
5
+ // 因此用 vm.Script 对源码文本做「函数段抽取求值」:从源文件按函数名定位 + brace
6
+ // 配平截取 normUsage / warnTelemetryMissingOnce / buildCallRecord 三段,在注入
7
+ // log/Buffer 的沙箱里求值后取回引用。抽取定位失败(函数改名/移动)会显式 throw,
8
+ // 不会静默测到旧副本。
9
+ //
10
+ // 回归锚点(对照修复史,断言在旧实现上会红):
11
+ // - W1:失败调用(returnMeta={value,error})不得触发 telemetry-missing WARN
12
+ // (旧实现不排除 error 分支,agent 失败被误诊为引擎透传未上线并烧掉 once 名额)
13
+ // - A11:model 缺省回退 "(default)"(请求时参数语义)
14
+ // - A12:promptMode=null(aggregator/fixer)必须保持 null,不被 || 误转 "full"
15
+ import { readFileSync } from "node:fs";
16
+ import { join } from "node:path";
17
+ import vm from "node:vm";
18
+
19
+ import { describe, expect, it } from "vitest";
20
+
21
+ const WORKFLOW_SOURCE = readFileSync(
22
+ join(__dirname, "..", "..", "workflows", "review-fix-loop.js"),
23
+ "utf8",
24
+ );
25
+
26
+ /** 按函数名从源码文本截取完整函数段(参数括号配平后 brace 配平函数体)。
27
+ * 抽取不到 → 显式报错(防漂移)。buildCallRecord 的解构参数含花括号,
28
+ * 函数体起点必须从参数列表闭合括号之后找,不能直接 indexOf("{")。 */
29
+ function extractFn(name: string): string {
30
+ const marker = "function " + name + "(";
31
+ const start = WORKFLOW_SOURCE.indexOf(marker);
32
+ if (start < 0) {
33
+ throw new Error("extraction guard failed: " + marker + " not found — function renamed/moved?");
34
+ }
35
+ // 参数列表括号配平(解构参数内嵌的 () {} 不影响外层括号深度)
36
+ const paramOpen = start + marker.length - 1;
37
+ let parenDepth = 0;
38
+ let paramClose = -1;
39
+ for (let i = paramOpen; i < WORKFLOW_SOURCE.length; i++) {
40
+ if (WORKFLOW_SOURCE[i] === "(") parenDepth++;
41
+ else if (WORKFLOW_SOURCE[i] === ")") {
42
+ parenDepth--;
43
+ if (parenDepth === 0) { paramClose = i; break; }
44
+ }
45
+ }
46
+ if (paramClose < 0) throw new Error("extraction guard failed: unbalanced params for " + name);
47
+ // 函数体 brace 配平
48
+ const open = WORKFLOW_SOURCE.indexOf("{", paramClose);
49
+ let depth = 0;
50
+ for (let i = open; i < WORKFLOW_SOURCE.length; i++) {
51
+ if (WORKFLOW_SOURCE[i] === "{") depth++;
52
+ else if (WORKFLOW_SOURCE[i] === "}") {
53
+ depth--;
54
+ if (depth === 0) return WORKFLOW_SOURCE.slice(start, i + 1);
55
+ }
56
+ }
57
+ throw new Error("extraction guard failed: unbalanced braces for " + name);
58
+ }
59
+
60
+ interface NormUsage {
61
+ input: number; output: number;
62
+ cacheRead: number; cacheWrite: number; cost: number;
63
+ }
64
+
65
+ interface CallRecord {
66
+ batch: number; round: number; role: string; name: string;
67
+ model: string;
68
+ durationMs: number | null;
69
+ usage: NormUsage | undefined;
70
+ promptMode: string | null;
71
+ promptBytes: number;
72
+ sessionId: string | undefined;
73
+ }
74
+
75
+ interface ScriptFns {
76
+ normUsage: (meta: unknown) => NormUsage | undefined;
77
+ buildCallRecord: (args: {
78
+ batch: number; round: number; role: string; name?: string;
79
+ model?: string; prompt: unknown; promptMode?: string | null;
80
+ meta?: unknown;
81
+ }) => CallRecord;
82
+ /** 重置 once-WARN 名额(模块级 warnedTelemetryMissing 是闭包状态,逐用例归零) */
83
+ resetWarnFlag: () => void;
84
+ }
85
+
86
+ /** 求值抽取段:注入 log(数组记录)与 Buffer(buildCallRecord 的 promptBytes 依赖)。 */
87
+ function loadScriptFns(logs: string[]): ScriptFns {
88
+ const src = [
89
+ "let warnedTelemetryMissing = false;",
90
+ extractFn("normUsage"),
91
+ extractFn("warnTelemetryMissingOnce"),
92
+ extractFn("buildCallRecord"),
93
+ "({ normUsage, buildCallRecord, resetWarnFlag: () => { warnedTelemetryMissing = false; } })",
94
+ ].join("\n");
95
+ const sandbox: vm.Context = {
96
+ Buffer,
97
+ log: (msg: string) => { logs.push(String(msg)); },
98
+ };
99
+ return vm.runInNewContext(src, sandbox) as ScriptFns;
100
+ }
101
+
102
+ const FULL_USAGE: NormUsage = { input: 1200, output: 340, cacheRead: 5600, cacheWrite: 800, cost: 0.042 };
103
+
104
+ describe("review-fix-loop.js normUsage(usage 归一)", () => {
105
+ it("meta 缺失/非对象 → undefined", () => {
106
+ const { normUsage } = loadScriptFns([]);
107
+ expect(normUsage(undefined)).toBeUndefined();
108
+ expect(normUsage(null)).toBeUndefined();
109
+ expect(normUsage("string")).toBeUndefined();
110
+ expect(normUsage(42)).toBeUndefined();
111
+ });
112
+
113
+ it("meta.usage 缺失/非对象 → undefined(旧引擎无 usage 键)", () => {
114
+ const { normUsage } = loadScriptFns([]);
115
+ expect(normUsage({})).toBeUndefined();
116
+ expect(normUsage({ durationMs: 100 })).toBeUndefined();
117
+ expect(normUsage({ usage: null })).toBeUndefined();
118
+ expect(normUsage({ usage: "1200" })).toBeUndefined();
119
+ });
120
+
121
+ it("usage 空对象(字段全缺)→ 五分量全部补 0,不产生 undefined 字段", () => {
122
+ const { normUsage } = loadScriptFns([]);
123
+ expect(normUsage({ usage: {} })).toEqual({ input: 0, output: 0, cacheRead: 0, cacheWrite: 0, cost: 0 });
124
+ });
125
+
126
+ it("usage 分量缺失 → 缺省分量 0,给定分量原值(部分维度)", () => {
127
+ const { normUsage } = loadScriptFns([]);
128
+ expect(normUsage({ usage: { input: 500, output: 20 } })).toEqual({
129
+ input: 500, output: 20, cacheRead: 0, cacheWrite: 0, cost: 0,
130
+ });
131
+ });
132
+
133
+ it("usage 分量为 null → ?? 0 兜底(null 维度不计 NaN)", () => {
134
+ const { normUsage } = loadScriptFns([]);
135
+ expect(normUsage({ usage: { input: null, output: 10, cacheRead: null, cacheWrite: null, cost: null } })).toEqual({
136
+ input: 0, output: 10, cacheRead: 0, cacheWrite: 0, cost: 0,
137
+ });
138
+ });
139
+
140
+ it("usage 完整 → 五分量精确透传", () => {
141
+ const { normUsage } = loadScriptFns([]);
142
+ expect(normUsage({ usage: { ...FULL_USAGE } })).toEqual(FULL_USAGE);
143
+ });
144
+ });
145
+
146
+ describe("review-fix-loop.js buildCallRecord(calls[] 十字段条目)", () => {
147
+ it("完整 returnMeta → 十字段精确形状(promptBytes 按 utf8 字节计)", () => {
148
+ const { buildCallRecord } = loadScriptFns([]);
149
+ const rec = buildCallRecord({
150
+ batch: 2, round: 3, role: "reviewer", name: "code-reviewer",
151
+ model: "x/y", prompt: "审查 a√", promptMode: "scoped",
152
+ meta: { durationMs: 12345, usage: { ...FULL_USAGE }, sessionId: "sess-1" },
153
+ });
154
+ // "审查 a√" = 审(3B)+查(3B)+空格(1B)+a(1B)+√(3B) = 11 字节(utf8 多字节验证)
155
+ expect(rec).toEqual({
156
+ batch: 2, round: 3, role: "reviewer", name: "code-reviewer",
157
+ model: "x/y", durationMs: 12345, usage: FULL_USAGE,
158
+ promptMode: "scoped", promptBytes: 11, sessionId: "sess-1",
159
+ });
160
+ });
161
+
162
+ it("多批多角色连续构造 → 各条目独立(批/角色/usage 互不污染)", () => {
163
+ const { buildCallRecord } = loadScriptFns([]);
164
+ const r1 = buildCallRecord({
165
+ batch: 1, round: 1, role: "reviewer", name: "a", model: "m",
166
+ prompt: "p1", meta: { durationMs: 1, usage: { input: 10 }, sessionId: "s1" },
167
+ });
168
+ const r2 = buildCallRecord({
169
+ batch: 2, round: 1, role: "aggregator", model: "m2",
170
+ prompt: "p2", promptMode: null, meta: { durationMs: 2, usage: { input: 20 } },
171
+ });
172
+ expect(r1.batch).toBe(1);
173
+ expect(r1.usage?.input).toBe(10);
174
+ expect(r2.batch).toBe(2);
175
+ expect(r2.usage?.input).toBe(20);
176
+ expect(r1.promptMode).toBe("full"); // 缺省回退(reviewer 全量模式)
177
+ });
178
+
179
+ it("W1 回归:失败调用(returnMeta={value,error})不触发 telemetry-missing WARN", () => {
180
+ const logs: string[] = [];
181
+ const { buildCallRecord } = loadScriptFns(logs);
182
+ const rec = buildCallRecord({
183
+ batch: 1, round: 1, role: "reviewer", name: "a", model: "m",
184
+ prompt: "p", meta: { value: "", error: "agent timeout" },
185
+ });
186
+ // 旧实现不排除 error 分支:失败调用被误诊「透传未上线」并 WARN(本断言会红)
187
+ expect(logs).toEqual([]);
188
+ // 失败调用天然无 usage/durationMs——降级形态如实记录
189
+ expect(rec.usage).toBeUndefined();
190
+ expect(rec.durationMs).toBeNull();
191
+ });
192
+
193
+ it("W1 之后真正缺 usage 的成功调用仍能 WARN(once 名额未被失败调用烧掉)", () => {
194
+ const logs: string[] = [];
195
+ const { buildCallRecord } = loadScriptFns(logs);
196
+ buildCallRecord({
197
+ batch: 1, round: 1, role: "reviewer", name: "a", model: "m",
198
+ prompt: "p", meta: { value: "ok", error: "agent timeout" },
199
+ });
200
+ buildCallRecord({
201
+ batch: 1, round: 1, role: "reviewer", name: "a", model: "m",
202
+ prompt: "p", meta: { durationMs: 5 }, // returnMeta 在但 usage 缺失
203
+ });
204
+ expect(logs).toHaveLength(1);
205
+ expect(logs[0]).toContain("returnMeta usage/durationMs missing");
206
+ });
207
+
208
+ it("A10 回归:多次降级调用只 WARN 一次(不逐调用刷屏)", () => {
209
+ const logs: string[] = [];
210
+ const { buildCallRecord } = loadScriptFns(logs);
211
+ for (let i = 0; i < 3; i++) {
212
+ buildCallRecord({
213
+ batch: 1, round: 1, role: "reviewer", name: "a", model: "m",
214
+ prompt: "p", meta: { durationMs: 5 }, // usage 缺失
215
+ });
216
+ }
217
+ expect(logs).toHaveLength(1);
218
+ });
219
+
220
+ it("A11 回归:model 空/缺省 → \"(default)\"(请求时参数语义,非实际运行模型)", () => {
221
+ const { buildCallRecord } = loadScriptFns([]);
222
+ const rec = buildCallRecord({
223
+ batch: 1, round: 1, role: "fixer", model: undefined, prompt: "p",
224
+ meta: { durationMs: 1 },
225
+ });
226
+ expect(rec.model).toBe("(default)");
227
+ expect(buildCallRecord({ batch: 1, round: 1, role: "fixer", model: "", prompt: "p", meta: {} }).model).toBe("(default)");
228
+ });
229
+
230
+ it("A12 回归:promptMode=null(aggregator/fixer)保持 null,不被误转 \"full\"", () => {
231
+ const { buildCallRecord } = loadScriptFns([]);
232
+ // 旧实现 `promptMode || \"full\"` 会把 null 转成 "full"(本断言会红)
233
+ expect(buildCallRecord({ batch: 1, round: 1, role: "aggregator", prompt: "p", promptMode: null, meta: {} }).promptMode).toBeNull();
234
+ });
235
+
236
+ it("A12 边界:promptMode 空串保持空串(空串 ≠ 缺省,不回退 full)", () => {
237
+ const { buildCallRecord } = loadScriptFns([]);
238
+ expect(buildCallRecord({ batch: 1, round: 1, role: "reviewer", prompt: "p", promptMode: "", meta: {} }).promptMode).toBe("");
239
+ });
240
+
241
+ it("promptMode 缺省(undefined)→ \"full\"(reviewer 默认全量模式)", () => {
242
+ const { buildCallRecord } = loadScriptFns([]);
243
+ expect(buildCallRecord({ batch: 1, round: 1, role: "reviewer", prompt: "p", meta: {} }).promptMode).toBe("full");
244
+ });
245
+
246
+ it("name 缺省/空 → role 兜底", () => {
247
+ const { buildCallRecord } = loadScriptFns([]);
248
+ expect(buildCallRecord({ batch: 1, round: 1, role: "fixer", name: undefined, prompt: "p", meta: {} }).name).toBe("fixer");
249
+ expect(buildCallRecord({ batch: 1, round: 1, role: "fixer", name: "", prompt: "p", meta: {} }).name).toBe("fixer");
250
+ });
251
+
252
+ it("durationMs 非数(字符串/null)→ 条目记 null + WARN", () => {
253
+ const logs: string[] = [];
254
+ const { buildCallRecord } = loadScriptFns(logs);
255
+ expect(buildCallRecord({ batch: 1, round: 1, role: "reviewer", prompt: "p", meta: { durationMs: "1200", usage: {} } }).durationMs).toBeNull();
256
+ expect(buildCallRecord({ batch: 1, round: 1, role: "reviewer", prompt: "p", meta: { durationMs: null, usage: {} } }).durationMs).toBeNull();
257
+ expect(logs).toHaveLength(1);
258
+ });
259
+
260
+ it("meta 缺失(旧引擎无 returnMeta)→ 降级条目且不触发 WARN(判定前提是 metaObj 存在)", () => {
261
+ const logs: string[] = [];
262
+ const { buildCallRecord } = loadScriptFns(logs);
263
+ const rec = buildCallRecord({ batch: 1, round: 1, role: "reviewer", prompt: "p", meta: undefined });
264
+ expect(rec.durationMs).toBeNull();
265
+ expect(rec.usage).toBeUndefined();
266
+ expect(rec.sessionId).toBeUndefined();
267
+ expect(logs).toEqual([]);
268
+ });
269
+
270
+ it("prompt 非字符串 → promptBytes 0;sessionId 非字符串 → undefined", () => {
271
+ const { buildCallRecord } = loadScriptFns([]);
272
+ const rec = buildCallRecord({
273
+ batch: 1, round: 1, role: "reviewer", prompt: undefined,
274
+ meta: { durationMs: 1, sessionId: 12345 },
275
+ });
276
+ expect(rec.promptBytes).toBe(0);
277
+ expect(rec.sessionId).toBeUndefined();
278
+ });
279
+ });
280
+
281
+ describe("review-fix-loop.js 模块形态约束", () => {
282
+ it("顶层 return 使其不可作为 ES module import(pi worker 脚本,非可导入模块)", async () => {
283
+ // 本 import 语句同时是静态依赖边:让依赖分析把该 workflow 文件纳入测试可达域
284
+ // (CRAP 覆盖估算)。顶层 return / require 决定了 import 必然 reject——这是
285
+ // workflow 脚本的固有形态,抽取测试法(本文件)因此是唯一可行的直测途径。
286
+ await expect(import("../../workflows/review-fix-loop.js")).rejects.toThrow();
287
+ });
288
+ });