@zhushanwen/subagent-core 0.4.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 (272) hide show
  1. package/dist/{chunk-4KN4TTG7.js → chunk-43ONBFZX.js} +1 -1
  2. package/dist/{chunk-X7SZ5HLQ.js → chunk-V3VHZ2VX.js} +20 -27
  3. package/dist/execution/engine/engines/zcode/constants.cjs +29 -41
  4. package/dist/execution/engine/engines/zcode/constants.d.cts +65 -53
  5. package/dist/execution/engine/engines/zcode/constants.d.ts +65 -53
  6. package/dist/execution/engine/engines/zcode/constants.js +17 -27
  7. package/dist/execution/engine/engines/zcode/reader.d.cts +2 -1
  8. package/dist/execution/engine/engines/zcode/reader.d.ts +2 -1
  9. package/dist/execution/engine/engines/zcode/reader.js +2 -2
  10. package/dist/index.cjs +16418 -14070
  11. package/dist/index.d.cts +5136 -4016
  12. package/dist/index.d.ts +5136 -4016
  13. package/dist/index.js +16343 -14048
  14. package/dist/{types-DpUO16pj.d.cts → types-Dv4QhSJ_.d.cts} +215 -112
  15. package/dist/{types-DpUO16pj.d.ts → types-Dv4QhSJ_.d.ts} +215 -112
  16. package/package.json +3 -3
  17. package/src/__tests__/agent-opts-resolver-schema-prompt.test.ts +0 -1
  18. package/src/__tests__/append-system-prompt-assembly.test.ts +8 -7
  19. package/src/__tests__/fr4-get-state-handshake.test.ts +2 -2
  20. package/src/__tests__/m2-append-content-probe.test.ts +0 -1
  21. package/src/__tests__/manifest-store.test.ts +10 -9
  22. package/src/__tests__/record-store-cache.test.ts +0 -2
  23. package/src/__tests__/record-store-index.test.ts +1 -2
  24. package/src/__tests__/review-fix-loop-script.test.ts +4 -2
  25. package/src/__tests__/review-fix-loop-utils.test.ts +10 -10
  26. package/src/__tests__/robustness-low-batch1.test.ts +6 -5
  27. package/src/__tests__/robustness-medium-batch1.test.ts +2 -2
  28. package/src/__tests__/robustness-medium-batch2.test.ts +17 -6
  29. package/src/__tests__/robustness-medium-batch4.test.ts +2 -2
  30. package/src/__tests__/session-runner.test.ts +1 -1
  31. package/src/core/__tests__/host-services.test.ts +2 -2
  32. package/src/core/__tests__/logger.test.ts +1 -1
  33. package/src/core/error-message.ts +9 -0
  34. package/src/core/host-services.ts +21 -5
  35. package/src/core/notify-ports.ts +18 -5
  36. package/src/execution/__tests__/agent-profile.test.ts +4 -4
  37. package/src/execution/__tests__/agent-registry.test.ts +370 -0
  38. package/src/execution/__tests__/agent-result-mapper.test.ts +18 -2
  39. package/src/execution/__tests__/agents-assembly.test.ts +2 -2
  40. package/src/execution/__tests__/ask-user-transit-e2e.test.ts +6 -6
  41. package/src/execution/__tests__/chat-engine-routing.test.ts +68 -33
  42. package/src/execution/__tests__/chatmode-first-round-closure-spawn.test.ts +4 -4
  43. package/src/execution/__tests__/cold-resurrect.test.ts +283 -0
  44. package/src/execution/__tests__/delivery-methods.test.ts +75 -62
  45. package/src/execution/__tests__/descendant-sweep-guards.test.ts +220 -0
  46. package/src/execution/__tests__/descendant-sweep.test.ts +6 -6
  47. package/src/execution/__tests__/dialog-queue.test.ts +2 -2
  48. package/src/execution/__tests__/engine-model-validation.test.ts +741 -0
  49. package/src/execution/__tests__/epipe-fallback.test.ts +29 -24
  50. package/src/execution/__tests__/execute-and-await-worktree.test.ts +21 -91
  51. package/src/execution/__tests__/execute-nesting.test.ts +34 -188
  52. package/src/execution/__tests__/execution-record.test.ts +217 -60
  53. package/src/execution/__tests__/execution-runtime-face.test.ts +5 -5
  54. package/src/execution/__tests__/explicit-agent-ref-guard.test.ts +3 -3
  55. package/src/execution/__tests__/finalize-record.test.ts +173 -17
  56. package/src/execution/__tests__/gc-timer.test.ts +55 -2
  57. package/src/execution/__tests__/get-record-for-action-restart.test.ts +12 -12
  58. package/src/execution/__tests__/get-state-handshake.test.ts +1 -1
  59. package/src/execution/__tests__/helpers/mock-extension-api.ts +1 -1
  60. package/src/execution/__tests__/helpers/session-runner-mocks.ts +113 -0
  61. package/src/execution/__tests__/helpers/spawn-mock.ts +150 -3
  62. package/src/execution/__tests__/helpers/subagent-service-mocks.ts +137 -0
  63. package/src/execution/__tests__/keep-alive-no-progress.test.ts +50 -148
  64. package/src/execution/__tests__/kill-all-escalation.test.ts +2 -2
  65. package/src/execution/__tests__/lifecycle-predicates.test.ts +1 -2
  66. package/src/execution/__tests__/manifest-parentid.test.ts +4 -4
  67. package/src/execution/__tests__/max-turns-to-watchdog-ms.test.ts +1 -1
  68. package/src/execution/__tests__/model-resolver.test.ts +2 -2
  69. package/src/execution/__tests__/nested-visibility-env-propagation.test.ts +23 -121
  70. package/src/execution/__tests__/nested-visibility.test.ts +2 -0
  71. package/src/execution/__tests__/notify-ledger.test.ts +973 -18
  72. package/src/execution/__tests__/output-collector.test.ts +117 -6
  73. package/src/execution/__tests__/pi-invocation.test.ts +1 -1
  74. package/src/execution/__tests__/record-store.test.ts +10 -9
  75. package/src/execution/__tests__/records-cwd-isolation.test.ts +2 -2
  76. package/src/execution/__tests__/recursive-visibility-baseline.test.ts +29 -132
  77. package/src/execution/__tests__/recursive-visibility-env.test.ts +55 -179
  78. package/src/execution/__tests__/rpc-mode.test.ts +2 -2
  79. package/src/execution/__tests__/run-and-finalize-anchoring.test.ts +387 -0
  80. package/src/execution/__tests__/run-and-finalize-chatmode.test.ts +15 -9
  81. package/src/execution/__tests__/run-spawn-chatmode-settled.test.ts +4 -4
  82. package/src/execution/__tests__/run-spawn-edges.test.ts +17 -15
  83. package/src/execution/__tests__/run-spawn-integration.test.ts +2 -2
  84. package/src/execution/__tests__/run-spawn-resume.test.ts +2 -2
  85. package/src/execution/__tests__/run-spawn-rpc-mode.test.ts +2 -2
  86. package/src/execution/__tests__/run-spawn-stdout-callback-throw.test.ts +4 -4
  87. package/src/execution/__tests__/service-kill-escalation.test.ts +7 -5
  88. package/src/execution/__tests__/session-context-resolver.test.ts +0 -2
  89. package/src/execution/__tests__/session-file-gc.test.ts +35 -0
  90. package/src/execution/__tests__/session-pending.test.ts +257 -14
  91. package/src/execution/__tests__/session-reconstructor.test.ts +366 -15
  92. package/src/execution/__tests__/session-runner-branch-cache-lru.test.ts +1 -1
  93. package/src/execution/__tests__/session-runner-close-prune.test.ts +2 -2
  94. package/src/execution/__tests__/session-runner-dispatch.test.ts +489 -0
  95. package/src/execution/__tests__/session-runner-epipe.test.ts +3 -3
  96. package/src/execution/__tests__/session-runner-heartbeat-idle-fallback.test.ts +5 -4
  97. package/src/execution/__tests__/session-runner-lifecycle-helpers.test.ts +290 -0
  98. package/src/execution/__tests__/session-runner-schema-env.test.ts +7 -5
  99. package/src/execution/__tests__/settled-watchdog.test.ts +282 -47
  100. package/src/execution/__tests__/spawn-args.test.ts +11 -10
  101. package/src/execution/__tests__/spawn-event-adapter-rpc.test.ts +26 -23
  102. package/src/execution/__tests__/spawn-event-adapter.test.ts +1 -1
  103. package/src/execution/__tests__/spawn-worktree-guidance.test.ts +5 -4
  104. package/src/execution/__tests__/spawned-children.test.ts +2 -1
  105. package/src/execution/__tests__/start-sync-model-guard.test.ts +4 -4
  106. package/src/execution/__tests__/stdin-writer.test.ts +6 -4
  107. package/src/execution/__tests__/stream-sink-retirement.test.ts +6 -6
  108. package/src/execution/__tests__/subagent-actions-core.test.ts +42 -22
  109. package/src/execution/__tests__/subagent-service-message-close.test.ts +29 -26
  110. package/src/execution/__tests__/subagent-service-multiproc-guard.test.ts +8 -8
  111. package/src/execution/__tests__/subagent-service-notify-gate.test.ts +27 -22
  112. package/src/execution/__tests__/subagent-service-parent-guard.test.ts +30 -29
  113. package/src/execution/__tests__/subagent-service-recovery-bounds.test.ts +45 -20
  114. package/src/execution/__tests__/subagent-service.test.ts +37 -30
  115. package/src/execution/__tests__/subprocess-agent-runner-routing.test.ts +88 -12
  116. package/src/execution/__tests__/subprocess-agent-runner-timeout.test.ts +75 -0
  117. package/src/execution/__tests__/subprocess-agent-runner.test.ts +22 -20
  118. package/src/execution/__tests__/temp-prompt.test.ts +1 -1
  119. package/src/execution/__tests__/timeout-integration.test.ts +6 -5
  120. package/src/execution/__tests__/turn-limiter-semantics.test.ts +1 -1
  121. package/src/execution/__tests__/turn-limiter.test.ts +1 -1
  122. package/src/execution/__tests__/ui-request-handler-factory.test.ts +12 -6
  123. package/src/execution/__tests__/ui-request-handler.test.ts +4 -3
  124. package/src/execution/__tests__/ui-request-queue.test.ts +142 -2
  125. package/src/execution/__tests__/worktree-manager.test.ts +14 -5
  126. package/src/execution/__tests__/worktree-pid-registration.integration.test.ts +4 -3
  127. package/src/execution/agent-registry.ts +74 -30
  128. package/src/execution/agent-result-mapper.ts +3 -0
  129. package/src/execution/cold-resurrect.ts +199 -0
  130. package/src/execution/engine/__tests__/common/capability-gate.test.ts +91 -0
  131. package/src/execution/engine/__tests__/common/data-dir.test.ts +1 -1
  132. package/src/execution/engine/__tests__/common/journal-wiring.test.ts +84 -0
  133. package/src/execution/engine/__tests__/common/kill-chain.test.ts +34 -7
  134. package/src/execution/engine/__tests__/common/persona-router.test.ts +4 -5
  135. package/src/execution/engine/__tests__/common/pool-manager.test.ts +211 -51
  136. package/src/execution/engine/__tests__/common/session-view-service-zcode-dbpath.test.ts +149 -0
  137. package/src/execution/engine/__tests__/common/session-view-service.test.ts +499 -0
  138. package/src/execution/engine/__tests__/conformance/contract.abort.test.ts +22 -112
  139. package/src/execution/engine/__tests__/conformance/contract.agent-events.test.ts +15 -28
  140. package/src/execution/engine/__tests__/conformance/engine-conformance.live.test.ts +12 -12
  141. package/src/execution/engine/__tests__/conformance/golden-replay.pi.test.ts +1 -1
  142. package/src/execution/engine/__tests__/conformance/golden-replay.zcode.test.ts +21 -82
  143. package/src/execution/engine/__tests__/conformance/zcode-appserver-harness.ts +4 -7
  144. package/src/execution/engine/__tests__/engine-discovery.test.ts +15 -3
  145. package/src/execution/engine/__tests__/model-prompt.test.ts +15 -3
  146. package/src/execution/engine/__tests__/registry.test.ts +4 -2
  147. package/src/execution/engine/__tests__/routing.test.ts +115 -6
  148. package/src/execution/engine/common/capability-gate.ts +92 -0
  149. package/src/execution/engine/common/journal-wiring.ts +97 -0
  150. package/src/execution/engine/common/kill-chain.ts +42 -10
  151. package/src/execution/engine/common/nesting-guard.ts +66 -0
  152. package/src/execution/engine/common/persona-router.ts +18 -8
  153. package/src/execution/engine/common/pool-manager.ts +332 -78
  154. package/src/execution/engine/common/session-view-service.ts +506 -0
  155. package/src/execution/engine/common/session-view-types.ts +125 -0
  156. package/src/execution/engine/engines/pi/__tests__/pi-engine.test.ts +174 -28
  157. package/src/execution/engine/engines/pi/__tests__/spawn-opts-direct.test.ts +257 -0
  158. package/src/execution/{argv-mirror.ts → engine/engines/pi/argv-mirror.ts} +43 -21
  159. package/src/execution/{get-state-handshake.ts → engine/engines/pi/get-state-handshake.ts} +1 -1
  160. package/src/execution/{output-collector.ts → engine/engines/pi/output-collector.ts} +108 -19
  161. package/src/execution/engine/engines/pi/pi-engine.ts +434 -38
  162. package/src/execution/{pi-invocation.ts → engine/engines/pi/pi-invocation.ts} +2 -2
  163. package/src/execution/engine/engines/pi/reader.ts +11 -0
  164. package/src/execution/engine/engines/pi/registration.ts +4 -2
  165. package/src/execution/{session-runner.ts → engine/engines/pi/session-runner.ts} +617 -412
  166. package/src/execution/{spawn-event-adapter.ts → engine/engines/pi/spawn-event-adapter.ts} +75 -34
  167. package/src/execution/{stdin-writer.ts → engine/engines/pi/stdin-writer.ts} +10 -9
  168. package/src/execution/{temp-prompt.ts → engine/engines/pi/temp-prompt.ts} +2 -2
  169. package/src/execution/{turn-limiter.ts → engine/engines/pi/turn-limiter.ts} +1 -1
  170. package/src/execution/engine/engines/zcode/__tests__/__fixtures__/fake-appserver.mjs +54 -27
  171. package/src/execution/engine/engines/zcode/__tests__/appserver-launcher.test.ts +321 -0
  172. package/src/execution/engine/engines/zcode/__tests__/connection.test.ts +13 -12
  173. package/src/execution/engine/engines/zcode/__tests__/parser.test.ts +7 -210
  174. package/src/execution/engine/engines/zcode/__tests__/preparer.test.ts +6 -110
  175. package/src/execution/engine/engines/zcode/__tests__/session-channel-dispose-harvest.test.ts +247 -0
  176. package/src/execution/engine/engines/zcode/__tests__/session-channel-turn-timers.test.ts +451 -0
  177. package/src/execution/engine/engines/zcode/__tests__/session-channel.test.ts +20 -8
  178. package/src/execution/engine/engines/zcode/__tests__/zcode-engine-appserver.test.ts +77 -110
  179. package/src/execution/engine/engines/zcode/__tests__/zcode-engine-degrade.test.ts +25 -319
  180. package/src/execution/engine/engines/zcode/__tests__/zcode-engine-dispose.test.ts +210 -0
  181. package/src/execution/engine/engines/zcode/__tests__/zcode-engine-retry.test.ts +353 -0
  182. package/src/execution/engine/engines/zcode/__tests__/zcode-engine-status.test.ts +282 -0
  183. package/src/execution/engine/engines/zcode/__tests__/zcode-engine-timeout.test.ts +372 -0
  184. package/src/execution/engine/engines/zcode/__tests__/zcode-engine.live.test.ts +48 -148
  185. package/src/execution/engine/engines/zcode/appserver-launcher.ts +167 -0
  186. package/src/execution/engine/engines/zcode/connection.ts +24 -11
  187. package/src/execution/engine/engines/zcode/constants.ts +75 -71
  188. package/src/execution/engine/engines/zcode/golden-sample.ts +8 -46
  189. package/src/execution/engine/engines/zcode/parser.ts +12 -346
  190. package/src/execution/engine/engines/zcode/preparer.ts +12 -143
  191. package/src/execution/engine/engines/zcode/session-channel.ts +351 -39
  192. package/src/execution/engine/engines/zcode/zcode-engine.ts +665 -760
  193. package/src/execution/engine/host-task-spec.ts +32 -36
  194. package/src/execution/engine/model-validation.ts +177 -0
  195. package/src/execution/engine/port.ts +24 -6
  196. package/src/execution/engine/routing.ts +75 -1
  197. package/src/execution/engine/types.ts +30 -103
  198. package/src/execution/execution-record.ts +222 -144
  199. package/src/execution/finalize-record.ts +131 -93
  200. package/src/execution/idle-gc.ts +28 -0
  201. package/src/execution/lifecycle-predicates.ts +1 -1
  202. package/src/execution/notify-host.ts +212 -0
  203. package/src/execution/record-store.ts +119 -73
  204. package/src/execution/round-settlement.ts +93 -0
  205. package/src/execution/session-file-gc.ts +96 -62
  206. package/src/execution/session-reconstructor.ts +256 -143
  207. package/src/execution/sessions-index.ts +117 -47
  208. package/src/execution/settled-watchdog.ts +264 -52
  209. package/src/execution/subagent-actions-core.ts +22 -22
  210. package/src/execution/subagent-service.ts +815 -963
  211. package/src/execution/subprocess-agent-runner.ts +144 -97
  212. package/src/execution/types.ts +9 -0
  213. package/src/execution/ui-request-handler-factory.ts +102 -74
  214. package/src/execution/ui-request-queue.ts +50 -19
  215. package/src/index.ts +442 -316
  216. package/src/orchestration/__tests__/agent-call-catch-fallback.test.ts +1 -1
  217. package/src/orchestration/__tests__/agent-call-stream.test.ts +2 -2
  218. package/src/orchestration/__tests__/args-validator.test.ts +14 -0
  219. package/src/orchestration/__tests__/error-recovery-rebuild-failure.test.ts +1 -1
  220. package/src/orchestration/__tests__/error-recovery-terminal-hardening.test.ts +11 -9
  221. package/src/orchestration/__tests__/execute-agent-call.test.ts +151 -11
  222. package/src/orchestration/__tests__/file-run-store.test.ts +7 -6
  223. package/src/orchestration/__tests__/launcher-nested-workflow.test.ts +2 -2
  224. package/src/orchestration/__tests__/lifecycle-abort-broadcast-signal.test.ts +1 -1
  225. package/src/orchestration/__tests__/lifecycle-runid-injection.test.ts +3 -3
  226. package/src/orchestration/__tests__/lifecycle.test.ts +7 -5
  227. package/src/orchestration/__tests__/non-cloneable-return-e2e.test.ts +1 -1
  228. package/src/orchestration/__tests__/run-snapshot.test.ts +8 -5
  229. package/src/orchestration/__tests__/script-lint.test.ts +17 -0
  230. package/src/orchestration/__tests__/test-mocks.ts +2 -0
  231. package/src/orchestration/__tests__/worker-exit-without-result.test.ts +7 -6
  232. package/src/orchestration/__tests__/worker-message-pump-finalize-run.test.ts +229 -0
  233. package/src/orchestration/__tests__/{error-recovery-handlers.test.ts → worker-message-pump-handlers.test.ts} +27 -19
  234. package/src/orchestration/__tests__/{error-recovery-postmessage-defense.test.ts → worker-message-pump-postmessage-defense.test.ts} +8 -8
  235. package/src/orchestration/__tests__/{error-recovery-serialize-failed-result.test.ts → worker-message-pump-serialize-failed-result.test.ts} +2 -2
  236. package/src/orchestration/__tests__/{error-recovery-workflow-call.test.ts → worker-message-pump-workflow-call.test.ts} +1 -1
  237. package/src/orchestration/__tests__/worker-pending-timeout-abort.test.ts +1 -1
  238. package/src/orchestration/__tests__/worker-script-builder.test.ts +1 -1
  239. package/src/orchestration/__tests__/workflow-nesting-e2e.test.ts +1 -1
  240. package/src/orchestration/agent-opts-resolver.ts +1 -1
  241. package/src/orchestration/args-validator.ts +53 -31
  242. package/src/orchestration/execute-agent-call.ts +19 -73
  243. package/src/orchestration/launcher.ts +128 -81
  244. package/src/orchestration/lifecycle.ts +43 -45
  245. package/src/orchestration/models/ports.ts +4 -4
  246. package/src/orchestration/models/run-runtime.ts +2 -2
  247. package/src/orchestration/models/trace.ts +1 -1
  248. package/src/orchestration/models/types.ts +111 -22
  249. package/src/orchestration/models/workflow-run.ts +1 -1
  250. package/src/orchestration/script-lint.ts +91 -58
  251. package/src/orchestration/{error-recovery.ts → worker-message-pump.ts} +157 -150
  252. package/src/shared/__tests__/meta-parser.test.ts +151 -0
  253. package/src/shared/__tests__/resource-discovery.test.ts +258 -215
  254. package/src/shared/atomic-write.ts +12 -9
  255. package/src/shared/meta-parser.ts +158 -84
  256. package/src/shared/model-ref.ts +15 -2
  257. package/src/shared/resource-discovery.ts +9 -183
  258. package/src/shared/schema-jsonify.ts +1 -1
  259. package/workflows/review-fix-loop-utils.cjs +151 -89
  260. package/workflows/review-fix-loop-utils.d.cts +287 -0
  261. package/src/execution/__tests__/execute-options-mapper.test.ts +0 -200
  262. package/src/execution/engine/engines/pi/__tests__/task-spec-mapper.test.ts +0 -164
  263. package/src/execution/engine/engines/pi/task-spec-mapper.ts +0 -100
  264. package/src/execution/engine/engines/zcode/__tests__/__fixtures__/zcode-golden-spawn.json +0 -39
  265. package/src/execution/engine/engines/zcode/__tests__/launcher.test.ts +0 -150
  266. package/src/execution/engine/engines/zcode/__tests__/preparer-appserver.test.ts +0 -387
  267. package/src/execution/engine/engines/zcode/__tests__/zcode-engine.test.ts +0 -710
  268. package/src/execution/engine/engines/zcode/appserver-home.ts +0 -442
  269. package/src/execution/engine/engines/zcode/appserver-probe.ts +0 -141
  270. package/src/execution/engine/engines/zcode/launcher.ts +0 -161
  271. package/src/execution/execute-options-mapper.ts +0 -115
  272. package/src/shared/__tests__/resource-discovery-manifest-cache.test.ts +0 -288
@@ -0,0 +1,370 @@
1
+ // src/execution/__tests__/agent-registry.test.ts
2
+ //
3
+ // AgentRegistry 测试(S2 路径统一版)。u-5c 迁自壳套件 src/__tests__/agent-registry.test.ts
4
+ // (被测 module 是 core 件,唯一测试覆盖原落壳——设计 §2.2 C6 / §1 目标 6)。
5
+ //
6
+ // 「builtin agents 数据合规」段:u-5c 曾拆出留壳(feat 侧布局:资产在壳包),但
7
+ // 合并终态 10 模板资产已迁 core 包 agents/(dev 侧 C5/D-1),壳 agents/ 不存在,
8
+ // 该段随资产回归 core 测试域(C5 锚点 + D-5 去 tools 化断言)。
9
+ //
10
+ // S2 重构:AgentRegistry 从「按名查找(discoverAll + cache Map<name>)」收敛为
11
+ // 「按绝对路径加载(loadByPath)」——agentRef 唯一形态 = .md 绝对路径(注入段
12
+ // <location>),内置 agent 即包内物理路径,无 builtin 合并、无名字查找。
13
+ // 发现(注入段数据源)职责由 shared/resource-discovery + injector 承担,
14
+ // 本文件不再测发现层(见 resource-discovery.test.ts)。
15
+ import * as fs from "node:fs";
16
+ import * as os from "node:os";
17
+ import * as path from "node:path";
18
+ import { createRequire } from "node:module";
19
+
20
+ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
21
+
22
+ // 隔离真实用户全局目录(~/.agents/agents/ 可能有真实 agent 文件)
23
+ vi.mock("node:os", async (importOriginal) => {
24
+ const actual = await importOriginal<typeof import("node:os")>();
25
+ return { ...actual, homedir: () => "/nonexistent-home-for-tests" };
26
+ });
27
+
28
+ import { AgentRegistry, parseAgentFrontmatter, parseAgentWithMeta } from "../agent-registry.ts";
29
+ import { clearEngines, registerEngine } from "../engine/registry.ts";
30
+ import type { EnginePort } from "../engine/port.ts";
31
+ import { lintAgentMeta } from "../../orchestration/script-lint.ts";
32
+ import { parseResourceMeta } from "../../shared/meta-parser.ts";
33
+
34
+ // ============================================================
35
+ // helpers
36
+ // ============================================================
37
+
38
+ function tmpWorkspace(): string {
39
+ return fs.mkdtempSync(path.join(os.tmpdir(), "agent-reg-test-"));
40
+ }
41
+
42
+ function writeAgent(dir: string, name: string, body: string): string {
43
+ fs.mkdirSync(dir, { recursive: true });
44
+ const filePath = path.join(dir, `${name}.md`);
45
+ fs.writeFileSync(filePath, body, "utf-8");
46
+ return filePath;
47
+ }
48
+
49
+ // ============================================================
50
+ // parseAgentFrontmatter
51
+ // ============================================================
52
+
53
+ describe("parseAgentFrontmatter", () => {
54
+ it("parses name from filename + body as systemPrompt when no frontmatter", () => {
55
+ const cfg = parseAgentFrontmatter("/x/worker.md", "You are a worker.");
56
+ expect(cfg.name).toBe("worker");
57
+ expect(cfg.systemPrompt).toBe("You are a worker.");
58
+ });
59
+ it("extracts model/thinkingLevel/tools from frontmatter", () => {
60
+ const cfg = parseAgentFrontmatter("/x/coder.md", `---
61
+ name: coder
62
+ description: coding agent
63
+ model: anthropic/claude-3.5-sonnet
64
+ thinkingLevel: high
65
+ tools: [read, bash]
66
+ ---
67
+ body text`);
68
+ expect(cfg.name).toBe("coder");
69
+ expect(cfg.model).toBe("anthropic/claude-3.5-sonnet");
70
+ expect(cfg.thinkingLevel).toBe("high");
71
+ expect(cfg.tools).toEqual(["read", "bash"]);
72
+ expect(cfg.systemPrompt).toBe("body text");
73
+ });
74
+ });
75
+
76
+ // ============================================================
77
+ // parseAgentWithMeta(m5 T2:W4 lint 用 AgentMeta 二元组)
78
+ // ============================================================
79
+
80
+ describe("parseAgentWithMeta", () => {
81
+ it("有 frontmatter(IF1 通过):meta 非 null 且路由字段完整,config 同步正确", () => {
82
+ const { config, meta } = parseAgentWithMeta("/x/coder.md", `---
83
+ name: coder
84
+ description: 编码 agent
85
+ when: 需要写代码
86
+ notFor: 纯分析
87
+ model: anthropic/claude-3.5-sonnet
88
+ thinkingLevel: high
89
+ tools: [read, bash]
90
+ ---
91
+ body text`);
92
+ expect(meta).not.toBeNull();
93
+ expect(meta!.kind).toBe("agent");
94
+ expect(meta!.name).toBe("coder");
95
+ expect(meta!.description).toBe("编码 agent");
96
+ expect(meta!.when).toBe("需要写代码");
97
+ expect(meta!.notFor).toBe("纯分析");
98
+ expect(config.name).toBe("coder");
99
+ expect(config.systemPrompt).toBe("body text");
100
+ expect(config.model).toBe("anthropic/claude-3.5-sonnet");
101
+ expect(config.thinkingLevel).toBe("high");
102
+ expect(config.tools).toEqual(["read", "bash"]);
103
+ });
104
+
105
+ it("无 frontmatter:meta = null,整个内容作为 systemPrompt", () => {
106
+ const { config, meta } = parseAgentWithMeta("/x/plain.md", "Just a prompt body.");
107
+ expect(meta).toBeNull();
108
+ expect(config).toEqual({
109
+ name: "plain",
110
+ systemPrompt: "Just a prompt body.",
111
+ });
112
+ });
113
+
114
+ it("MF-3 fallback:缺 description(IF1 返 null)时 model/tools 经 extractYamlField 仍生效", () => {
115
+ const { config, meta } = parseAgentWithMeta("/x/legacy.md", `---
116
+ name: legacy
117
+ model: anthropic/claude-3.5-sonnet
118
+ tools: read, bash, write
119
+ ---
120
+ body text`);
121
+ // 缺 description → parseResourceMeta 返 null → meta 为 null(结构化路由不可见)
122
+ expect(meta).toBeNull();
123
+ // 但 config 的 model/tools 不丢(direct-path loadByPath 与重构前行为一致)
124
+ expect(config.name).toBe("legacy");
125
+ expect(config.model).toBe("anthropic/claude-3.5-sonnet");
126
+ expect(config.tools).toEqual(["read", "bash", "write"]);
127
+ expect(config.systemPrompt).toBe("body text");
128
+ });
129
+
130
+ it("未闭合 frontmatter:meta = null,name 经 extractYamlField fallback,其余作为 systemPrompt", () => {
131
+ const { config, meta } = parseAgentWithMeta("/x/broken.md", `---
132
+ name: broken
133
+ model: x/y`);
134
+ expect(meta).toBeNull();
135
+ expect(config.name).toBe("broken");
136
+ // 未闭合分支只取 name(原行为),不解析 model
137
+ expect(config.systemPrompt).toBe(`---\nname: broken\nmodel: x/y`);
138
+ });
139
+ });
140
+
141
+ // ============================================================
142
+ // AgentRegistry.loadByPath(S2:agentRef = .md 绝对路径)
143
+ // ============================================================
144
+
145
+ describe("AgentRegistry.loadByPath", () => {
146
+ let ws: string;
147
+ beforeEach(() => { ws = tmpWorkspace(); });
148
+ afterEach(() => { fs.rmSync(ws, { recursive: true, force: true }); });
149
+
150
+ it("按绝对路径加载 agent:frontmatter + body → AgentConfig", () => {
151
+ const file = writeAgent(path.join(ws, ".pi", "agents"), "worker", `---
152
+ name: worker
153
+ description: 通用执行 agent
154
+ tools: [read, bash]
155
+ ---
156
+ You are a worker.`);
157
+ const reg = new AgentRegistry();
158
+ const cfg = reg.loadByPath(file);
159
+ expect(cfg?.name).toBe("worker");
160
+ expect(cfg?.systemPrompt).toBe("You are a worker.");
161
+ expect(cfg?.tools).toEqual(["read", "bash"]);
162
+ });
163
+
164
+ it("无 frontmatter 文件:整个内容作为 systemPrompt", () => {
165
+ const file = writeAgent(ws, "plain", "Just a prompt body.");
166
+ const cfg = new AgentRegistry().loadByPath(file);
167
+ expect(cfg?.name).toBe("plain");
168
+ expect(cfg?.systemPrompt).toBe("Just a prompt body.");
169
+ });
170
+
171
+ it("mtime 缓存:未变文件不重读(config 引用稳定)", () => {
172
+ const file = writeAgent(ws, "cached", "v1");
173
+ const reg = new AgentRegistry();
174
+ const first = reg.loadByPath(file);
175
+ const second = reg.loadByPath(file);
176
+ expect(second).toBe(first);
177
+ // 修改后 mtime 变化 → 新 config
178
+ fs.writeFileSync(file, "v2", "utf-8");
179
+ const third = reg.loadByPath(file);
180
+ expect(third?.systemPrompt).toBe("v2");
181
+ });
182
+
183
+ it("相对路径引用返回 undefined(引用唯一形态 = 绝对路径)", () => {
184
+ const reg = new AgentRegistry();
185
+ expect(reg.loadByPath("worker")).toBeUndefined();
186
+ expect(reg.loadByPath("./agents/worker.md")).toBeUndefined();
187
+ });
188
+
189
+ it("非 .md 引用返回 undefined", () => {
190
+ const reg = new AgentRegistry();
191
+ expect(reg.loadByPath("/tmp/worker.txt")).toBeUndefined();
192
+ });
193
+
194
+ it("文件不存在返回 undefined,require=true 抛错带指引", () => {
195
+ const reg = new AgentRegistry();
196
+ expect(reg.loadByPath("/nonexistent/x.md")).toBeUndefined();
197
+ // R5(D7):三态错误文案统一带 <available_subagents> <location> 恢复指引
198
+ expect(() => reg.loadByPath("/nonexistent/x.md", true)).toThrow(/not found or unreadable/);
199
+ expect(() => reg.loadByPath("/nonexistent/x.md", true)).toThrow(/<available_subagents> <location>/);
200
+ expect(() => reg.loadByPath("relative", true)).toThrow(/Invalid agent ref/);
201
+ expect(() => reg.loadByPath("relative", true)).toThrow(/<available_subagents>/);
202
+ });
203
+
204
+ it("~/ 前缀展开", () => {
205
+ const reg = new AgentRegistry();
206
+ // homedir 被 mock 为 /nonexistent-home-for-tests → 文件必然不存在,验证展开逻辑
207
+ expect(reg.loadByPath("~/agent.md")).toBeUndefined();
208
+ });
209
+ });
210
+
211
+ // ============================================================
212
+ // 包内 agents/*.md 数据合规(S2:内置 agent = 包内路径文件)
213
+ // ============================================================
214
+
215
+ describe("builtin agents 数据合规", () => {
216
+ // C5 过渡态收口:10 模板已迁 @zhushanwen/subagent-core/agents/(C1/D-1)——经
217
+ // ./workflows/* 子入口锚点解析 core 包根(与 src/host/pi-host.ts corePackageNpmRoot
218
+ // 同一锚,workspace 与发布形态同径),数据面断言随资产指向 core。
219
+ const CORE_PKG_ROOT = path.resolve(
220
+ path.dirname(createRequire(import.meta.url).resolve("@zhushanwen/subagent-core/workflows/README.md")),
221
+ "..",
222
+ );
223
+ const AGENTS_DIR = path.join(CORE_PKG_ROOT, "agents");
224
+ const CORE = ["explorer", "coder", "reviewer", "debugger", "analyst", "planner", "researcher", "orchestrator", "general-purpose", "doc-reviewer"];
225
+
226
+ it("agents/*.md 全部 IF1 解析成功", () => {
227
+ for (const f of fs.readdirSync(AGENTS_DIR).filter((x) => x.endsWith(".md"))) {
228
+ const meta = parseResourceMeta(fs.readFileSync(path.join(AGENTS_DIR, f), "utf-8"), "agent");
229
+ expect(meta?.kind, `${f} parse 失败`).toBe("agent");
230
+ }
231
+ });
232
+
233
+ it("核心 agent 均含 when/notFor/examples 且正反各一(lintAgentMeta 无 finding)", () => {
234
+ for (const name of CORE) {
235
+ const meta = parseResourceMeta(fs.readFileSync(path.join(AGENTS_DIR, `${name}.md`), "utf-8"), "agent");
236
+ expect(meta, `${name} 解析失败`).not.toBeNull();
237
+ if (meta?.kind !== "agent") continue;
238
+ expect(meta.when, `${name} 缺 when`).toBeDefined();
239
+ expect(meta.notFor, `${name} 缺 notFor`).toBeDefined();
240
+ expect(meta.examples?.length, `${name} 缺 examples`).toBeGreaterThanOrEqual(2);
241
+ expect(meta.examples?.some((e) => e.positive), `${name} 缺正向样本`).toBe(true);
242
+ expect(meta.examples?.some((e) => !e.positive), `${name} 缺反向样本`).toBe(true);
243
+ expect(lintAgentMeta(meta), `${name} examples 不合规`).toEqual([]);
244
+ }
245
+ });
246
+
247
+ it("loadByPath 直接加载 core 包内 agent(内置 = 路径文件,无名字查找)", () => {
248
+ const reg = new AgentRegistry();
249
+ const coder = reg.loadByPath(path.join(AGENTS_DIR, "coder.md"));
250
+ expect(coder?.name).toBe("coder");
251
+ expect(coder?.systemPrompt.length).toBeGreaterThan(0);
252
+ // D-5(C1)去 tools 化:模板不再声明 tools 白名单——全部 undefined(工具约束
253
+ // 回归宿主默认面;想要白名单在 <ws>/.agents/agents/ 放同名 .md 覆写)。
254
+ // 本断言拦「tools 字段回流」——模板侧任何 tools 重新声明会在此立即报错。
255
+ for (const name of CORE) {
256
+ expect(
257
+ reg.loadByPath(path.join(AGENTS_DIR, `${name}.md`))?.tools,
258
+ `${name} 模板不应声明 tools`,
259
+ ).toBeUndefined();
260
+ }
261
+ });
262
+ });
263
+
264
+ // ============================================================
265
+ // engine 字段(P4 D9:frontmatter 主通道 + 解析期注册表校验)
266
+ // ============================================================
267
+
268
+ describe("parseAgentWithMeta engine 字段(P4 路由)", () => {
269
+ beforeEach(() => {
270
+ // 解析期校验消费注册表——测试内注册假引擎(惰性工厂无副作用)
271
+ clearEngines();
272
+ // 工厂恒 throw:解析期校验只查注册表存在性,不实例化(惰性工厂契约)
273
+ const neverInstantiate = (): EnginePort => {
274
+ throw new Error("parse-time validation must not instantiate engines");
275
+ };
276
+ registerEngine("pi", neverInstantiate);
277
+ registerEngine("zcode", neverInstantiate);
278
+ });
279
+ afterEach(() => {
280
+ clearEngines();
281
+ });
282
+
283
+ it("frontmatter engine 进 config.engine(结构化路径,IF1)", () => {
284
+ const { config, meta } = parseAgentWithMeta(
285
+ "/x/reviewer.md",
286
+ `---
287
+ name: reviewer
288
+ description: review agent
289
+ engine: zcode
290
+ ---
291
+ body`,
292
+ );
293
+ expect(config.engine).toBe("zcode");
294
+ expect(meta?.kind === "agent" && meta.engine).toBe("zcode");
295
+ });
296
+
297
+ it("IF1 未通过(缺 description)时 legacy fallback 取 engine(配置不丢,与 model 同判)", () => {
298
+ const { config } = parseAgentWithMeta(
299
+ "/x/reviewer.md",
300
+ `---
301
+ name: reviewer
302
+ engine: zcode
303
+ ---
304
+ body`,
305
+ );
306
+ expect(config.engine).toBe("zcode");
307
+ });
308
+
309
+ it("未注册 engine id:解析期抛 EngineNotFoundError,文案含注册清单与文件路径", () => {
310
+ expect(() =>
311
+ parseAgentWithMeta(
312
+ "/x/reviewer.md",
313
+ `---
314
+ name: reviewer
315
+ description: review agent
316
+ engine: nonexistent-engine
317
+ ---
318
+ body`,
319
+ ),
320
+ ).toThrowError(/engine_not_found: engine 'nonexistent-engine'/);
321
+ expect(() =>
322
+ parseAgentWithMeta(
323
+ "/x/reviewer.md",
324
+ `---
325
+ name: reviewer
326
+ description: review agent
327
+ engine: nonexistent-engine
328
+ ---
329
+ body`,
330
+ ),
331
+ ).toThrowError(/Registered engines: pi, zcode/);
332
+ expect(() =>
333
+ parseAgentWithMeta(
334
+ "/x/my-agent.md",
335
+ `---
336
+ name: my-agent
337
+ description: d
338
+ engine: nonexistent-engine
339
+ ---
340
+ body`,
341
+ ),
342
+ ).toThrowError(/Source: \/x\/my-agent\.md/);
343
+ });
344
+
345
+ it("已注册 id(pi/zcode):解析通过,不抛", () => {
346
+ expect(() =>
347
+ parseAgentWithMeta(
348
+ "/x/reviewer.md",
349
+ `---
350
+ name: reviewer
351
+ description: review agent
352
+ engine: pi
353
+ ---
354
+ body`,
355
+ ),
356
+ ).not.toThrow();
357
+ });
358
+
359
+ it("无 engine 字段:config.engine 缺省(走全局默认层)", () => {
360
+ const { config } = parseAgentWithMeta(
361
+ "/x/worker.md",
362
+ `---
363
+ name: worker
364
+ description: d
365
+ ---
366
+ body`,
367
+ );
368
+ expect(config.engine).toBeUndefined();
369
+ });
370
+ });
@@ -57,6 +57,22 @@ describe("mapToWorkflowAgentResult (D-A10)", () => {
57
57
  expect(result.parsedOutput).toEqual(parsedData);
58
58
  });
59
59
 
60
+ // ── D5-③: failureKind 分诊标签透传(产出侧 output-collector → 消费侧 executeAgentCall) ──
61
+
62
+ it("failureKind 三态逐值透传(stale_context / schema_deterministic / unknown)", () => {
63
+ for (const kind of ["stale_context", "schema_deterministic", "unknown"] as const) {
64
+ const r: SubagentsAgentResult = { ...minimalResult, success: false, error: "boom", failureKind: kind };
65
+ const result = mapToWorkflowAgentResult(r);
66
+ expect(result.failureKind).toBe(kind);
67
+ }
68
+ });
69
+
70
+ it("failureKind 缺省(成功路径/上游未写)→ 不落键(消费侧视为 unknown = 可重试)", () => {
71
+ const result = mapToWorkflowAgentResult(minimalResult);
72
+ expect(result.failureKind).toBeUndefined();
73
+ expect("failureKind" in result).toBe(false);
74
+ });
75
+
60
76
  // ── T3.14: 失败路径 ──
61
77
 
62
78
  it("映射失败: success=false 且 error → 填入 error 字段", () => {
@@ -74,7 +90,7 @@ describe("mapToWorkflowAgentResult (D-A10)", () => {
74
90
  const result = mapToWorkflowAgentResult(r);
75
91
  expect(result.error).toBeDefined();
76
92
  expect(typeof result.error).toBe("string");
77
- expect(result.error.length).toBeGreaterThan(0);
93
+ expect(result.error!.length).toBeGreaterThan(0);
78
94
  });
79
95
 
80
96
  it("映射成功: success=true 且 error 存在 → error=undefined(不误填)", () => {
@@ -143,7 +159,7 @@ describe("mapToWorkflowAgentResult (D-A10)", () => {
143
159
  });
144
160
 
145
161
  it("映射 toolCalls: 无 toolCalls → undefined", () => {
146
- const r: SubagentsAgentResult = { ...minimalResult, toolCalls: undefined };
162
+ const r = { ...minimalResult, toolCalls: undefined } as unknown as SubagentsAgentResult;
147
163
  const result = mapToWorkflowAgentResult(r);
148
164
  expect(result.toolCalls).toBeUndefined();
149
165
  });
@@ -30,9 +30,9 @@ import {
30
30
  clearFileCache,
31
31
  discoverResources,
32
32
  getCachedFileContent,
33
- type DiscoveryRoot,
34
33
  type ScanConfig,
35
34
  } from "../../shared/resource-discovery.ts";
35
+ import type { DiscoveryRoot } from "../../core/host-services.ts";
36
36
  import { discoverAgents } from "../agents-assembly.ts";
37
37
 
38
38
  // ── oracle:pi 壳 discoverAllAgents 装配循环的逐句同构(消费同一批 core 原语)──
@@ -98,7 +98,7 @@ describe("discoverAgents", () => {
98
98
  afterEach(() => {
99
99
  resetCoreForTests();
100
100
  clearFileCache();
101
- fs.rmSync(outerDir, { recursive: true, force: true });
101
+ fs.rmSync(outerDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 20 });
102
102
  });
103
103
 
104
104
  it("与 pi 壳现装配循环产出等值(同序同名同字段)——多形态 fixture 对照", async () => {
@@ -72,7 +72,7 @@ vi.mock("../alive-store.ts", () => ({
72
72
  writeAliveMarker: vi.fn(),
73
73
  }));
74
74
 
75
- vi.mock("../temp-prompt.ts", () => ({
75
+ vi.mock("../engine/engines/pi/temp-prompt.ts", () => ({
76
76
  writePromptToTempFile: vi.fn(async (agent: string) => {
77
77
  const safeName = agent.replace(/[^\w.-]+/g, "_");
78
78
  return { dir: `/tmp/fake-${safeName}`, filePath: `/tmp/fake-${safeName}/prompt-${safeName}.md` };
@@ -81,7 +81,7 @@ vi.mock("../temp-prompt.ts", () => ({
81
81
  }));
82
82
 
83
83
  import { DialogGlobalQueue } from "../dialog-queue.ts";
84
- import { runSpawn, type SessionRunnerContext } from "../session-runner.ts";
84
+ import { runSpawn, type SessionRunnerContext } from "../engine/engines/pi/session-runner.ts";
85
85
  import { type ChannelHandler,createUiChannelRegistry } from "../ui-channels.ts";
86
86
  import { createUiRequestHandlerForMode } from "../ui-request-handler-factory.ts";
87
87
  import {
@@ -168,7 +168,7 @@ function makeAskUserCtx(
168
168
  },
169
169
  modelRegistry: undefined,
170
170
  model: undefined,
171
- } as SessionRunnerContext;
171
+ } as unknown as SessionRunnerContext;
172
172
  const handler = createUiRequestHandlerForMode(ctx as never, registry, dialogQueue);
173
173
  return makeCtxBase({
174
174
  ...overrides,
@@ -315,11 +315,11 @@ describe("ask_user 跨进程 transit e2e (#34)", () => {
315
315
  // 验证:连续 emit 两个 ask_user,channel handler 按顺序被调,response 按顺序写回。
316
316
  const registry = createUiChannelRegistry();
317
317
  const callOrder: string[] = [];
318
- const channelHandler: ChannelHandler = vi.fn(async (req: { id: string }) => {
319
- callOrder.push(req.id);
318
+ const channelHandler: ChannelHandler = vi.fn(async (req: unknown) => {
319
+ callOrder.push((req as { id: string }).id);
320
320
  // 加延迟让两个请求有机会并发(若队列没串行)
321
321
  await new Promise((r) => setTimeout(r, 15));
322
- return { value: `ans-${req.id}` };
322
+ return { value: `ans-${(req as { id: string }).id}` };
323
323
  });
324
324
  registry.register("ask_user", channelHandler);
325
325