@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,144 @@
1
+ // host-services.test.ts —— HostServices 配置态 / NULL_HOST 降级 / DEFAULT_DATA_ROOT。
2
+ //
3
+ // 三视角:①构建者——configureCore 覆盖语义与 getHostServices 解析;②使用者——
4
+ // 未配置消费 dataRoot 得到可操作错误(core_host_not_configured + 恢复指引关键词,
5
+ // 设计 §3.4 错误规格);③观察者——NULL_HOST 日志落缺省 console(warn/error),
6
+ // discoveryRoots 可选端口缺席为 undefined,DiscoveryRoot.source 标签原样透传。
7
+
8
+ import { homedir } from "node:os";
9
+ import { join } from "node:path";
10
+
11
+ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
12
+
13
+ import {
14
+ configureCore,
15
+ DEFAULT_DATA_ROOT,
16
+ getHostServices,
17
+ resetCoreForTests,
18
+ type DiscoveryRoot,
19
+ type HostServices,
20
+ } from "../host-services.ts";
21
+
22
+ beforeEach(() => {
23
+ resetCoreForTests();
24
+ });
25
+
26
+ afterEach(() => {
27
+ vi.restoreAllMocks();
28
+ resetCoreForTests();
29
+ });
30
+
31
+ function makeHost(overrides: Partial<HostServices> = {}): HostServices {
32
+ return {
33
+ dataRoot: () => "/data/root",
34
+ log: () => {},
35
+ ...overrides,
36
+ };
37
+ }
38
+
39
+ describe("getHostServices(未配置 → NULL_HOST)", () => {
40
+ it("消费 dataRoot 抛错,message 含 core_host_not_configured", () => {
41
+ expect(() => getHostServices().dataRoot()).toThrowError("core_host_not_configured");
42
+ });
43
+
44
+ it("错误文案含恢复指引:configureCore 调用时机 + pi 壳 / zsw 壳接入示例落点", () => {
45
+ try {
46
+ getHostServices().dataRoot();
47
+ expect.unreachable("dataRoot must throw before configureCore");
48
+ } catch (err) {
49
+ expect(err).toBeInstanceOf(Error);
50
+ const msg = (err as Error).message;
51
+ expect(msg).toContain("core_host_not_configured");
52
+ expect(msg).toContain("configureCore");
53
+ expect(msg).toContain("pi-host.ts");
54
+ expect(msg).toContain("README");
55
+ }
56
+ });
57
+
58
+ it("log warn → console.warn,error → console.error,带 [component] 前缀", () => {
59
+ const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => {});
60
+ const errorSpy = vi.spyOn(console, "error").mockImplementation(() => {});
61
+ const host = getHostServices();
62
+
63
+ host.log("warn", "comp-a", "w-message", { k: 1 });
64
+ expect(warnSpy).toHaveBeenCalledTimes(1);
65
+ expect(warnSpy.mock.calls[0][0]).toBe("[comp-a] w-message");
66
+ expect(warnSpy.mock.calls[0][1]).toEqual({ k: 1 });
67
+ expect(errorSpy).not.toHaveBeenCalled();
68
+
69
+ host.log("error", "comp-a", "e-message");
70
+ expect(errorSpy).toHaveBeenCalledTimes(1);
71
+ expect(errorSpy.mock.calls[0][0]).toBe("[comp-a] e-message");
72
+ });
73
+
74
+ it("data 缺省时省略第二参数(node console 会把显式 undefined 打成尾巴)", () => {
75
+ const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => {});
76
+ getHostServices().log("warn", "comp-a", "bare");
77
+ expect(warnSpy.mock.calls[0].length).toBe(1);
78
+ });
79
+
80
+ it("debug 缺省 no-op(对齐 pi-extension-logger debug 默认 no-op 语义)", () => {
81
+ const logSpy = vi.spyOn(console, "log").mockImplementation(() => {});
82
+ const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => {});
83
+ getHostServices().log("debug", "comp-a", "d-message");
84
+ expect(logSpy).not.toHaveBeenCalled();
85
+ expect(warnSpy).not.toHaveBeenCalled();
86
+ });
87
+
88
+ it("discoveryRoots 为 undefined(可选端口缺席)", () => {
89
+ expect(getHostServices().discoveryRoots).toBeUndefined();
90
+ });
91
+ });
92
+
93
+ describe("configureCore", () => {
94
+ it("配置后 dataRoot / log 路由到宿主实现", () => {
95
+ const logSpy = vi.fn<HostServices["log"]>();
96
+ configureCore(makeHost({ dataRoot: () => "/host/root", log: logSpy }));
97
+
98
+ const host = getHostServices();
99
+ expect(host.dataRoot()).toBe("/host/root");
100
+ host.log("warn", "comp", "msg", { x: 2 });
101
+ expect(logSpy).toHaveBeenCalledWith("warn", "comp", "msg", { x: 2 });
102
+ });
103
+
104
+ it("DiscoveryRoot.source 标签由宿主提供、core 原样透传(不枚举封闭集)", () => {
105
+ const roots: DiscoveryRoot[] = [
106
+ { dir: "/roots/npm", source: "npm" },
107
+ { dir: "/roots/user-pi", source: "user-pi" },
108
+ { dir: "/roots/custom-tag", source: "host-defined-anything" },
109
+ ];
110
+ configureCore(
111
+ makeHost({
112
+ discoveryRoots: () => ({ agents: roots }),
113
+ }),
114
+ );
115
+
116
+ const resolved = getHostServices().discoveryRoots?.();
117
+ expect(resolved?.agents).toEqual(roots);
118
+ expect(resolved?.agents?.[2].source).toBe("host-defined-anything");
119
+ });
120
+
121
+ it("重复调用以后者覆盖(测试切宿主依赖此语义)", () => {
122
+ const firstLog = vi.fn<HostServices["log"]>();
123
+ const secondLog = vi.fn<HostServices["log"]>();
124
+ configureCore(makeHost({ log: firstLog }));
125
+ configureCore(makeHost({ log: secondLog }));
126
+
127
+ getHostServices().log("error", "comp", "msg");
128
+ expect(firstLog).not.toHaveBeenCalled();
129
+ expect(secondLog).toHaveBeenCalledTimes(1);
130
+ });
131
+
132
+ it("resetCoreForTests 后回到未配置态(dataRoot 抛错)", () => {
133
+ configureCore(makeHost());
134
+ resetCoreForTests();
135
+ expect(() => getHostServices().dataRoot()).toThrowError("core_host_not_configured");
136
+ });
137
+ });
138
+
139
+ describe("DEFAULT_DATA_ROOT", () => {
140
+ it("等于 ~/.subagent-core(homedir 推导,不写死绝对路径)", () => {
141
+ expect(DEFAULT_DATA_ROOT).toBe(join(homedir(), ".subagent-core"));
142
+ expect(DEFAULT_DATA_ROOT.startsWith(homedir())).toBe(true);
143
+ });
144
+ });
@@ -0,0 +1,78 @@
1
+ // logger.test.ts —— core log facade 的时序契约(D2「解析时机契约」的直接守护)。
2
+ //
3
+ // 核心场景:模块顶层 `const logger = getLogger(...)` 缓存惯例(切面内 30 处既有形态)
4
+ // 下,configureCore 前后透明切换——facade 每次方法调用动态解析宿主实现,无模块加载
5
+ // 顺序依赖。另覆盖:缺省 console 行为、singleton 缓存惯例、level 逐字透传。
6
+
7
+ import { afterEach, describe, expect, it, vi } from "vitest";
8
+
9
+ import { configureCore, resetCoreForTests, type HostServices } from "../host-services.ts";
10
+ import { getLogger } from "../logger.ts";
11
+
12
+ // 模块顶层缓存 facade——复刻既有惯例的加载形态:加载期 getLogger,此时宿主必然未
13
+ // 配置。下面的时序契约用例证明:配置后该引用无需重建即路由到宿主实现。
14
+ const topLevelLogger = getLogger("top-level-comp");
15
+
16
+ afterEach(() => {
17
+ vi.restoreAllMocks();
18
+ resetCoreForTests();
19
+ });
20
+
21
+ describe("facade 顶层缓存惯例 + configureCore 前后透明切换(时序契约)", () => {
22
+ it("顶层缓存的 logger:配置前落缺省 console,配置后同一引用路由到宿主实现", () => {
23
+ // 1) configureCore 前:facade 调用落缺省 console(warn 通道)。
24
+ const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => {});
25
+ topLevelLogger.warn("before-configure", { stage: 1 });
26
+ expect(warnSpy).toHaveBeenCalledTimes(1);
27
+ expect(warnSpy.mock.calls[0][0]).toBe("[top-level-comp] before-configure");
28
+ expect(warnSpy.mock.calls[0][1]).toEqual({ stage: 1 });
29
+
30
+ // 2) configureCore:宿主 log 接线(模拟宿主壳初始化时点,晚于本模块加载)。
31
+ const hostLog = vi.fn<HostServices["log"]>();
32
+ configureCore({ dataRoot: () => "/host/root", log: hostLog });
33
+
34
+ // 3) 同一引用(未重建、未重新 getLogger)调用即刻路由到宿主实现——无模块加载
35
+ // 顺序依赖;console 缺省出口不再被消费。
36
+ topLevelLogger.warn("after-configure");
37
+ topLevelLogger.error("fatal-after-configure", { code: 7 });
38
+ expect(hostLog).toHaveBeenCalledWith("warn", "top-level-comp", "after-configure", undefined);
39
+ expect(hostLog).toHaveBeenCalledWith("error", "top-level-comp", "fatal-after-configure", {
40
+ code: 7,
41
+ });
42
+ expect(warnSpy).toHaveBeenCalledTimes(1); // 配置后不再增长
43
+ });
44
+
45
+ it("debug 也经同一动态解析链路(配置前 no-op、配置后路由宿主)", () => {
46
+ const logSpy = vi.spyOn(console, "log").mockImplementation(() => {});
47
+ topLevelLogger.debug("dbg-before");
48
+ expect(logSpy).not.toHaveBeenCalled(); // 缺省 no-op
49
+
50
+ const hostLog = vi.fn<HostServices["log"]>();
51
+ configureCore({ dataRoot: () => "/host/root", log: hostLog });
52
+ topLevelLogger.debug("dbg-after");
53
+ expect(hostLog).toHaveBeenCalledWith("debug", "top-level-comp", "dbg-after", undefined);
54
+ });
55
+ });
56
+
57
+ describe("getLogger", () => {
58
+ it("同 component 返回同一引用(singleton 缓存惯例,对齐 pi-extension-logger)", () => {
59
+ expect(getLogger("same-comp")).toBe(getLogger("same-comp"));
60
+ });
61
+
62
+ it("不同 component 返回不同 facade", () => {
63
+ expect(getLogger("comp-a")).not.toBe(getLogger("comp-b"));
64
+ });
65
+
66
+ it("level/component/message/data 四参逐字透传宿主(调用面等价替换的前提)", () => {
67
+ const hostLog = vi.fn<HostServices["log"]>();
68
+ configureCore({ dataRoot: () => "/host/root", log: hostLog });
69
+
70
+ const logger = getLogger("pass-through-comp");
71
+ logger.debug("m1", { a: 1 });
72
+ logger.warn("m2");
73
+ logger.error("m3", null);
74
+ expect(hostLog).toHaveBeenNthCalledWith(1, "debug", "pass-through-comp", "m1", { a: 1 });
75
+ expect(hostLog).toHaveBeenNthCalledWith(2, "warn", "pass-through-comp", "m2", undefined);
76
+ expect(hostLog).toHaveBeenNthCalledWith(3, "error", "pass-through-comp", "m3", null);
77
+ });
78
+ });
@@ -0,0 +1,104 @@
1
+ // notify-ports.test.ts —— NotifyDomainPorts 配置态 / 缺省降级语义 / 重置隔离。
2
+ //
3
+ // 缺席语义(设计 D2 + §3.4 core_port_missing「可选端口缺席是合法形态」):
4
+ // - 计数器缺席 → 恒 0(零活跃,pending 门全开)——缺省内聚在端口层;
5
+ // - 投递工厂缺席 → createDelivery 为 undefined,由消费方降级直发(后续单元接线)。
6
+
7
+ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
8
+
9
+ import {
10
+ configureNotifyDomain,
11
+ getNotifyDomainPorts,
12
+ resetNotifyDomainForTests,
13
+ type DeliveryConfig,
14
+ type DeliveryHandle,
15
+ type DeliveryPort,
16
+ } from "../notify-ports.ts";
17
+
18
+ beforeEach(() => {
19
+ resetNotifyDomainForTests();
20
+ });
21
+
22
+ afterEach(() => {
23
+ resetNotifyDomainForTests();
24
+ });
25
+
26
+ /** 形态对齐 pi 会话 JSONL 的 pending register/unregister custom entry(unknown[] 注入)。 */
27
+ function pendingEntries(): unknown[] {
28
+ return [
29
+ { customType: "pending:register", data: { id: "sa-1" } },
30
+ { customType: "other:entry" },
31
+ { customType: "pending:unregister", data: { id: "sa-1" } },
32
+ ];
33
+ }
34
+
35
+ function makePort(): DeliveryPort {
36
+ return {
37
+ supportedPayloads: ["custom"],
38
+ isIdle: () => true,
39
+ hasPendingMessages: () => false,
40
+ send: () => {},
41
+ };
42
+ }
43
+
44
+ describe("getNotifyDomainPorts(未注入 → 缺省降级)", () => {
45
+ it("计数器缺省恒 0(即便 entries 含 pending 形态内容也不消费)", () => {
46
+ const ports = getNotifyDomainPorts();
47
+ expect(ports.countActiveFromEntries?.([])).toBe(0);
48
+ expect(ports.countActiveFromEntries?.(pendingEntries())).toBe(0);
49
+ });
50
+
51
+ it("投递工厂缺席为 undefined(消费方降级直发的判据)", () => {
52
+ expect(getNotifyDomainPorts().createDelivery).toBeUndefined();
53
+ });
54
+ });
55
+
56
+ describe("configureNotifyDomain", () => {
57
+ it("注入计数器后按实现计数,entries 原样透传", () => {
58
+ const counter = vi.fn<(entries: unknown[]) => number>((entries) => entries.length);
59
+ configureNotifyDomain({ countActiveFromEntries: counter });
60
+
61
+ const entries = pendingEntries();
62
+ expect(getNotifyDomainPorts().countActiveFromEntries?.(entries)).toBe(3);
63
+ expect(counter).toHaveBeenCalledWith(entries);
64
+ });
65
+
66
+ it("注入投递工厂后可调用,port/options 透传、handle 原样返回", () => {
67
+ const port = makePort();
68
+ const options: DeliveryConfig = { intent: "interrupt-at-turn-boundary", mergeWindowMs: 60_000 };
69
+ const handle: DeliveryHandle = {
70
+ send: () => {},
71
+ flush: () => {},
72
+ dispose: () => {},
73
+ };
74
+ const factory = vi.fn((receivedPort: DeliveryPort, receivedOptions?: DeliveryConfig): DeliveryHandle => {
75
+ expect(receivedPort).toBe(port);
76
+ expect(receivedOptions).toBe(options);
77
+ return handle;
78
+ });
79
+ configureNotifyDomain({ createDelivery: factory });
80
+
81
+ const ports = getNotifyDomainPorts();
82
+ expect(ports.createDelivery?.(port, options)).toBe(handle);
83
+ expect(factory).toHaveBeenCalledTimes(1);
84
+ });
85
+
86
+ it("重复注入以后者覆盖", () => {
87
+ const first = vi.fn<(entries: unknown[]) => number>(() => 1);
88
+ const second = vi.fn<(entries: unknown[]) => number>(() => 2);
89
+ configureNotifyDomain({ countActiveFromEntries: first });
90
+ configureNotifyDomain({ countActiveFromEntries: second });
91
+
92
+ expect(getNotifyDomainPorts().countActiveFromEntries?.([])).toBe(2);
93
+ expect(first).not.toHaveBeenCalled();
94
+ });
95
+
96
+ it("resetNotifyDomainForTests 后回到缺省降级(计数 0 / 工厂缺席)", () => {
97
+ configureNotifyDomain({ countActiveFromEntries: () => 99 });
98
+ resetNotifyDomainForTests();
99
+
100
+ const ports = getNotifyDomainPorts();
101
+ expect(ports.countActiveFromEntries?.(pendingEntries())).toBe(0);
102
+ expect(ports.createDelivery).toBeUndefined();
103
+ });
104
+ });
@@ -0,0 +1,97 @@
1
+ // src/core/host-services.ts
2
+ //
3
+ // HostServices 宿主端口(P0 依赖闭包 port 化)。设计权威源:
4
+ // docs/design/subagent-core-package-extraction.md §3.3 D2 + §3.4 错误规格。
5
+ //
6
+ // core 与宿主(pi 壳 / zsw 壳)的唯一环境服务契约:数据根 / 结构化日志 / 资源发现根。
7
+ // 注入时机:宿主壳初始化最早期 configureCore(host),core 内模块统一经
8
+ // getHostServices() 取用——解析发生在每次调用时,宿主后续覆盖配置即刻生效。
9
+ //
10
+ // dataRoot 分段归属(计划期细化 2026-08-29):本端口只返回宿主数据根本身——env
11
+ // 覆盖段(XYZ_AGENT_DATA_DIR 优先)与 warn-once 语义留在 core data-dir.ts,壳不
12
+ // 重复实现。未 configureCore 即消费 dataRoot 抛 core_host_not_configured(§3.4):
13
+ // 「缺省静默漂目录」被显式报错取代,DEFAULT_DATA_ROOT 供宿主显式采用而非 core 内部
14
+ // 静默兜底。
15
+
16
+ import { homedir } from "node:os";
17
+ import { join } from "node:path";
18
+
19
+ import type { LogLevel } from "./logger.ts";
20
+
21
+ /** 发现根条目:dir 为扫描根路径;source 是宿主提供的语义标签(遮蔽报告透传用)。
22
+ * source 不枚举封闭集——core 只透传不解释(宿主如 pi 壳用 user-pi/npm/npm-dev)。 */
23
+ export interface DiscoveryRoot {
24
+ dir: string;
25
+ source: string;
26
+ }
27
+
28
+ export interface HostServices {
29
+ /** 数据根目录:引擎隔离池 / journal / record 派生存放的锚点。
30
+ * pi 壳返回 getAgentDir()(独立 pi 用户 journal 不漂目录);zsw 壳返回 zsw 数据根。 */
31
+ dataRoot(): string;
32
+ /** 结构化日志:对齐现 getLogger 调用面(level/component/message/data)。缺省 sink 按级分化:
33
+ * warn/error 走 console、debug no-op(对齐 pi-extension-logger 语义,见 NULL_HOST.log)。 */
34
+ log(level: LogLevel, component: string, message: string, data?: unknown): void;
35
+ /** agent/skill/workflow 资源发现根(可选端口,缺席 = 调用方降级)。宿主只提供根列表
36
+ * (按优先级低→高);扫描 / 同名遮蔽(last-writer-wins)/ 遮蔽报告语义归 core 统一。 */
37
+ discoveryRoots?(): {
38
+ agents?: DiscoveryRoot[];
39
+ skills?: DiscoveryRoot[];
40
+ workflows?: DiscoveryRoot[];
41
+ };
42
+ }
43
+
44
+ /** core 缺省数据根(~/.subagent-core,homedir 推导——禁止写死绝对路径,排查规则)。
45
+ * 供无自有数据根的轻宿主显式采用;core 自身不静默兜底到该值。 */
46
+ export const DEFAULT_DATA_ROOT: string = join(homedir(), ".subagent-core");
47
+
48
+ // 模块级配置态:configureCore 覆盖式写入(重复调用以后者覆盖——测试切宿主依赖此语义)。
49
+ let configuredHost: HostServices | undefined;
50
+
51
+ export function configureCore(host: HostServices): void {
52
+ configuredHost = host;
53
+ }
54
+
55
+ /** 测试隔离专用:清空配置态(生产禁用——生产宿主配置一次后生命周期与进程一致)。 */
56
+ export function resetCoreForTests(): void {
57
+ configuredHost = undefined;
58
+ }
59
+
60
+ const NULL_HOST: HostServices = {
61
+ dataRoot() {
62
+ // §3.4 core_host_not_configured:错误必须可操作——指出缺失动作(configureCore
63
+ // 的调用时机)+ 双宿主接入示例落点。pi 壳接入文件由后续接线单元(u0-wire)创建。
64
+ throw new Error(
65
+ "[subagent-core] core_host_not_configured: HostServices is not configured — " +
66
+ "the host shell must call configureCore(host) during initialization, before any " +
67
+ "core API that needs host services is consumed. " +
68
+ "Recovery: pi shell wires HostServices in src/host/pi-host.ts of " +
69
+ "@zhushanwen/pi-subagent-workflow; zsw shell: see the wiring example in the " +
70
+ "@zhushanwen/subagent-core package README.",
71
+ );
72
+ },
73
+ log(level, component, message, data) {
74
+ // 缺省 console 出口(configureCore 前的日志不丢)。格式对齐 pi-extension-logger
75
+ // 的 `[extName] msg` 前缀,便于 session 日志逆向检索时两形态互通。
76
+ const line = `[${component}] ${message}`;
77
+ // data 作第二参数;缺省时必须省略——node console 会把显式 undefined 格式化成
78
+ // " undefined" 尾巴污染每行输出。
79
+ if (level === "error") {
80
+ if (data === undefined) console.error(line);
81
+ else console.error(line, data);
82
+ return;
83
+ }
84
+ if (level === "warn") {
85
+ if (data === undefined) console.warn(line);
86
+ else console.warn(line, data);
87
+ return;
88
+ }
89
+ // debug 缺省 no-op:对齐 pi-extension-logger 的 debug 默认 no-op 语义(未配置期
90
+ // 多为模块加载窗口,刷屏无诊断价值);warn/error 不可静默。
91
+ },
92
+ // discoveryRoots 刻意不实现:可选端口缺席 = undefined,由调用方走缺省发现语义。
93
+ };
94
+
95
+ export function getHostServices(): HostServices {
96
+ return configuredHost ?? NULL_HOST;
97
+ }
@@ -0,0 +1,47 @@
1
+ // src/core/logger.ts
2
+ //
3
+ // core log facade(替代 @zhushanwen/pi-extension-logger 的 core 内统一入口)。
4
+ // 设计权威源:docs/design/subagent-core-package-extraction.md §3.3 D2「解析时机契约」。
5
+ //
6
+ // 为什么是 facade 代理而不是绑死实现:切面内 30 处既有惯例是模块顶层
7
+ // `const logger = getLogger(...)`(模块加载期创建并缓存实例,彼时宿主必然尚未
8
+ // configureCore)。若 getLogger 在创建时就绑定当时配置态,先加载的模块会永远落
9
+ // 缺省 console——典型时序陷阱。facade 在每次方法调用时经 host-services 配置态
10
+ // 动态解析当前宿主实现:configureCore 前落缺省 console,配置后已缓存的顶层
11
+ // logger 透明切换到宿主实现,无模块加载顺序依赖(该时序契约由 logger.test.ts
12
+ // 顶层缓存用例直接守护)。
13
+
14
+ import { getHostServices } from "./host-services.ts";
15
+
16
+ /** 日志级别。对齐 @zhushanwen/pi-extension-logger 的 LogLevel(三值,无 info)。 */
17
+ export type LogLevel = "debug" | "warn" | "error";
18
+
19
+ /** core logger 接口。与 pi-extension-logger 的 ExtensionLogger 结构兼容——
20
+ * u0-log 批次替换是纯 import 源替换,调用面(方法名/参数序)逐文件等价。 */
21
+ export interface CoreLogger {
22
+ debug(msg: string, data?: unknown): void;
23
+ warn(msg: string, data?: unknown): void;
24
+ error(msg: string, data?: unknown): void;
25
+ }
26
+
27
+ // 与 pi-extension-logger 的 getLogger singleton 惯例对齐(同 component 同引用)。
28
+ // facade 自身无状态(解析发生在方法内),缓存只为引用稳定,不影响透明切换。
29
+ const facadeCache = new Map<string, CoreLogger>();
30
+
31
+ export function getLogger(component: string): CoreLogger {
32
+ const existing = facadeCache.get(component);
33
+ if (existing) return existing;
34
+ const facade: CoreLogger = {
35
+ debug(msg, data) {
36
+ getHostServices().log("debug", component, msg, data);
37
+ },
38
+ warn(msg, data) {
39
+ getHostServices().log("warn", component, msg, data);
40
+ },
41
+ error(msg, data) {
42
+ getHostServices().log("error", component, msg, data);
43
+ },
44
+ };
45
+ facadeCache.set(component, facade);
46
+ return facade;
47
+ }
@@ -0,0 +1,126 @@
1
+ // src/core/notify-ports.ts
2
+ //
3
+ // 通知域窄端口(D2 计划期细化②)。pi 侧完成通知的两机制——@xyz-agent/session-delivery
4
+ // 投递内核工厂 / @zhushanwen/pi-pending-notifications 活跃计数——经本端口结构化注入;
5
+ // HostServices.notify 事件推送按演进纪律②(禁止无真实触点的推测性预留)推迟到 P2
6
+ // zsw 壳首个真实触点(task-notification)再落。
7
+ //
8
+ // 闭包红线:本文件是 core 对上述两包的唯一替代面——下方 Delivery* 结构化类型为手工
9
+ // 转写(与 packages/session-delivery/src/types.ts 逐字段结构兼容),禁止 import 两包
10
+ // (D9 闭包守卫扫描对象)。结构兼容由注入点 typecheck 守护:pi 壳直传真实
11
+ // createDelivery、拆 CountActiveResult.count 时,上游签名漂移即 typecheck 红。
12
+ //
13
+ // 缺席语义(设计 §3.4 core_port_missing 精神:可选端口缺席是合法形态,不报错):
14
+ // - 计数器缺席 → 恒 0(零活跃):pending 门全开,缺省内聚在本端口层。
15
+ // - 投递工厂缺席 → 消费方降级直发:直发是消费方行为,端口层无法代为执行,
16
+ // 故 createDelivery 刻意保持缺席(undefined),由消费方判缺席降级。
17
+
18
+ /** 投递意图(与 session-delivery 的 DeliveryIntent 字面量一致)。 */
19
+ export type DeliveryIntent = "interrupt-at-turn-boundary" | "after-run";
20
+
21
+ /** 文本 payload。 */
22
+ export interface DeliveryTextPayload {
23
+ kind: "text";
24
+ content: string;
25
+ }
26
+
27
+ /** custom message payload(extension 通路)。 */
28
+ export interface DeliveryCustomPayload {
29
+ kind: "custom";
30
+ customType: string;
31
+ content: string;
32
+ display: boolean;
33
+ details?: unknown;
34
+ }
35
+
36
+ /** 判别联合 payload(envelope / payload 分离)。 */
37
+ export type DeliveryPayload = DeliveryTextPayload | DeliveryCustomPayload;
38
+
39
+ /** 投递消息 envelope。 */
40
+ export interface DeliveryMessage {
41
+ payload: DeliveryPayload;
42
+ /** 缺省回落工厂 options.intent。 */
43
+ intent?: DeliveryIntent;
44
+ /** 去重 key(工厂开 dedupe 时必填)。 */
45
+ dedupeKey?: string;
46
+ }
47
+
48
+ /** port.send 的受理回执(U2 扩展位;void = 受理未知,按成功处理)。 */
49
+ export interface DeliverySendReceipt {
50
+ accepted: boolean;
51
+ reason?: string;
52
+ }
53
+
54
+ /** 投递端口:内核与外部世界的唯一接口(notifier 装配,intent→宿主参数翻译在适配器内)。 */
55
+ export interface DeliveryPort {
56
+ /** 本通路支持的 payload kind(不支持的 kind 由工厂 fail-fast)。 */
57
+ supportedPayloads: readonly DeliveryPayload["kind"][];
58
+ /** 主 agent 是否空闲(gate 投递时机)。 */
59
+ isIdle(): boolean;
60
+ /** 是否有排队中的消息。 */
61
+ hasPendingMessages(): boolean;
62
+ /** 投递消息。返回受理回执或 void(扩展位——旧实现返回 void 兼容)。 */
63
+ send(
64
+ msg: DeliveryMessage,
65
+ intent: DeliveryIntent,
66
+ ): void | DeliverySendReceipt | Promise<void | DeliverySendReceipt>;
67
+ /** agent_settled 边沿订阅。缺省时工厂退化退避轮询;返回退订函数。 */
68
+ subscribeSettled?(cb: () => void): () => void;
69
+ }
70
+
71
+ /** 投递工厂 options(notifier 实际消费的字段集;其余策略字段未入端口面)。 */
72
+ export interface DeliveryConfig {
73
+ intent?: DeliveryIntent;
74
+ busyPolicy?: "retry-force" | "park";
75
+ /** 合批窗口(ms):0 = 关;>0 = 滑动窗口合批。 */
76
+ mergeWindowMs?: number;
77
+ /** 合批依赖谓词(禁止用 isIdle 代替——D4 must-fix 语义)。 */
78
+ mergeHoldActive?: () => boolean;
79
+ backoff?: { ms: number; max: number };
80
+ dedupe?: { maxKeys: number };
81
+ /** 投递失败警告出口(U4:装配方接 logger 使警告落日志盘而非 stderr)。 */
82
+ warn?: (msg: string, err?: unknown) => void;
83
+ }
84
+
85
+ /** 投递句柄(notifier 消费面:send / flush / dispose——诊断面 depth 等不入端口)。 */
86
+ export interface DeliveryHandle {
87
+ /** 唯一常规入口(合批窗口 + 空闲零延迟立即投)。 */
88
+ send(msg: DeliveryMessage, opts?: { merge?: boolean }): void;
89
+ /** 强制投递尝试(shutdown flush 等)。 */
90
+ flush(): void;
91
+ /** 销毁(清队列 + 清 timer + 退订)。 */
92
+ dispose(): void;
93
+ }
94
+
95
+ export interface NotifyDomainPorts {
96
+ /** pending 活跃计数(pi 会话 entries 中 register − unregister 差集的数值)。
97
+ * 契约为 number 而非 pi 侧 CountActiveResult:core 消费面只读 count,契约面最窄;
98
+ * pi 壳注入时拆 `countActiveFromEntries(entries).count`。 */
99
+ countActiveFromEntries?(entries: unknown[]): number;
100
+ /** 投递内核工厂。签名与 @xyz-agent/session-delivery 的 createDelivery 结构兼容,
101
+ * pi 壳直传其本体即可。缺席 = 消费方降级直发。 */
102
+ createDelivery?(port: DeliveryPort, options?: DeliveryConfig): DeliveryHandle;
103
+ }
104
+
105
+ // 模块级配置态(与 host-services 同款覆盖式语义——重复注入以后者覆盖)。
106
+ let configuredPorts: NotifyDomainPorts | undefined;
107
+
108
+ export function configureNotifyDomain(ports: NotifyDomainPorts): void {
109
+ configuredPorts = ports;
110
+ }
111
+
112
+ /** 测试隔离专用:清空注入态(生产禁用——注入点在宿主壳初始化,生命周期与进程一致)。 */
113
+ export function resetNotifyDomainForTests(): void {
114
+ configuredPorts = undefined;
115
+ }
116
+
117
+ const DEFAULT_NOTIFY_PORTS: NotifyDomainPorts = {
118
+ // 计数缺省恒 0:零活跃是安全侧语义(pending 门全开),且把「缺席按零处理」从
119
+ // 消费方约定收敛为端口层的机器事实。
120
+ countActiveFromEntries: () => 0,
121
+ // createDelivery 刻意缺席(见文件头「缺席语义」)。
122
+ };
123
+
124
+ export function getNotifyDomainPorts(): NotifyDomainPorts {
125
+ return configuredPorts ?? DEFAULT_NOTIFY_PORTS;
126
+ }
@@ -0,0 +1,53 @@
1
+ {
2
+ "_meta": "Golden snapshots for BgNotifier.buildLlmContent — captured pre-migration (commit HEAD at time of capture). Used by migration verification to ensure zero behavioral regression.",
3
+ "single_closed_success": {
4
+ "input": { "id": "sa-ptr-7", "status": "closed", "agent": "worker", "result": "done", "startedAt": 1, "endedAt": 2 },
5
+ "output": "Subagent \"worker\" (sa-ptr-7) completed. Result:\ndone"
6
+ },
7
+ "single_closed_with_sessionfile": {
8
+ "input": { "id": "sa-ptr-2", "status": "closed", "agent": "w", "result": "final result", "sessionFile": "/tmp/sessions/child-2.jsonl", "startedAt": 1, "endedAt": 2 },
9
+ "output": "Subagent \"w\" (sa-ptr-2) completed. Result:\nfinal result\n\nFull transcript: /tmp/sessions/child-2.jsonl"
10
+ },
11
+ "single_running_round": {
12
+ "input": { "id": "sa-ptr-4", "status": "running", "agent": "w", "round": 2, "result": "round2 text", "startedAt": 1, "endedAt": 2 },
13
+ "output": "Subagent \"w\" (sa-ptr-4) finished a round. Reply:\nround2 text"
14
+ },
15
+ "single_running_round_with_sessionfile": {
16
+ "input": { "id": "sa-ptr-1", "status": "running", "agent": "w", "round": 1, "result": "round1 text", "sessionFile": "/tmp/sessions/child-1.jsonl", "startedAt": 1, "endedAt": 2 },
17
+ "output": "Subagent \"w\" (sa-ptr-1) finished a round. Reply:\nround1 text\n\nFull transcript: /tmp/sessions/child-1.jsonl"
18
+ },
19
+ "single_cancelled": {
20
+ "input": { "id": "sa-ptr-5", "status": "closed", "closedReason": "cancelled", "agent": "w", "startedAt": 1, "endedAt": 2 },
21
+ "output": "Subagent \"w\" (sa-ptr-5) cancelled."
22
+ },
23
+ "single_gc_failed": {
24
+ "input": { "id": "sa-ptr-6", "status": "closed", "closedReason": "gc", "agent": "w", "error": "spawn EPIPE", "startedAt": 1, "endedAt": 2 },
25
+ "output": "Subagent \"w\" (sa-ptr-6) failed: spawn EPIPE"
26
+ },
27
+ "single_gc_failed_with_patchfile": {
28
+ "input": { "id": "sa-ptr-8", "status": "closed", "closedReason": "gc", "agent": "w", "error": "spawn EPIPE", "patchFile": "/tmp/patches/sa-ptr-8.patch", "startedAt": 1, "endedAt": 2 },
29
+ "output": "Subagent \"w\" (sa-ptr-8) failed: spawn EPIPE"
30
+ },
31
+ "single_closed_with_patchfile_and_sessionfile": {
32
+ "input": { "id": "sa-ptr-3", "status": "closed", "agent": "w", "result": "did work", "patchFile": "/tmp/patches/sa-ptr-3.patch", "sessionFile": "/tmp/sessions/child-3.jsonl", "startedAt": 1, "endedAt": 2 },
33
+ "output_contains": "git apply /tmp/patches/sa-ptr-3.patch",
34
+ "output_ends_with": "\n\nFull transcript: /tmp/sessions/child-3.jsonl"
35
+ },
36
+ "single_closed_totalrounds": {
37
+ "input": { "id": "sa-rounds-1", "status": "closed", "agent": "w", "totalRounds": 3, "result": "", "sessionFile": "/tmp/sessions/child-rounds.jsonl", "startedAt": 1, "endedAt": 2 },
38
+ "output": "Subagent \"w\" (sa-rounds-1) completed after 3 rounds. Result:\n\n\nFull transcript: /tmp/sessions/child-rounds.jsonl"
39
+ },
40
+ "single_closed_no_totalrounds": {
41
+ "input": { "id": "sa-rounds-2", "status": "closed", "agent": "w", "result": "done", "sessionFile": "/tmp/sessions/child-oneshot.jsonl", "startedAt": 1, "endedAt": 2 },
42
+ "output": "Subagent \"w\" (sa-rounds-2) completed. Result:\ndone\n\nFull transcript: /tmp/sessions/child-oneshot.jsonl"
43
+ },
44
+ "batch_two_closed": {
45
+ "description": "Two closed records merged in one message (simulating 60s merge window)",
46
+ "records": [
47
+ { "id": "batch-1", "status": "closed", "agent": "w1", "result": "result1", "startedAt": 1, "endedAt": 2 },
48
+ { "id": "batch-2", "status": "closed", "agent": "w2", "result": "result2", "startedAt": 3, "endedAt": 4 }
49
+ ],
50
+ "separator": "\n\n---\n\n",
51
+ "details_shape": { "batch": true, "items": "array-of-records" }
52
+ }
53
+ }