@zhushanwen/pi-subagent-workflow 8.5.0 → 8.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (336) hide show
  1. package/package.json +13 -16
  2. package/relay/relay.mjs +1 -1
  3. package/src/host/__tests__/pi-host.test.ts +214 -0
  4. package/src/host/pi-host.ts +109 -0
  5. package/src/index.ts +142 -32
  6. package/src/injectors/__tests__/engine-awareness.test.ts +292 -0
  7. package/src/injectors/__tests__/engine-section-stability.test.ts +341 -0
  8. package/src/injectors/__tests__/subagent-list-injector.test.ts +5 -5
  9. package/src/injectors/__tests__/workflow-list-injector.test.ts +5 -5
  10. package/src/injectors/engine-awareness.ts +123 -0
  11. package/src/injectors/model-list-injector.ts +1 -1
  12. package/src/injectors/subagent-list-injector.ts +8 -8
  13. package/src/injectors/workflow-list-injector.ts +8 -8
  14. package/src/interface/__tests__/detectors.test.ts +3 -3
  15. package/src/interface/__tests__/subagent-tool-path-guard.test.ts +157 -0
  16. package/src/interface/__tests__/subagent-tool-prompt.test.ts +12 -0
  17. package/src/interface/__tests__/tool-workflow-script-generate.test.ts +2 -2
  18. package/src/interface/__tests__/tool-workflow-throw-paths.test.ts +1 -1
  19. package/src/interface/bg-notify-render.ts +34 -13
  20. package/src/interface/commands.ts +3 -3
  21. package/src/interface/format.ts +2 -2
  22. package/src/interface/helpers.ts +3 -3
  23. package/src/interface/list-component.ts +4 -4
  24. package/src/interface/list-shared.ts +2 -2
  25. package/src/interface/list-view.ts +2 -2
  26. package/src/interface/subagent-actions.ts +288 -19
  27. package/src/interface/subagent-tool-schema.ts +163 -0
  28. package/src/interface/subagent-tool.ts +65 -129
  29. package/src/interface/subagents.ts +5 -5
  30. package/src/interface/tool-render.ts +34 -2
  31. package/src/interface/tool-workflow-script.ts +4 -4
  32. package/src/interface/tool-workflow.ts +6 -6
  33. package/src/interface/views/WorkflowsView.ts +5 -5
  34. package/src/interface/views/__tests__/WorkflowsView-signature.test.ts +3 -3
  35. package/src/interface/views/__tests__/detail-content-session-file.test.ts +2 -2
  36. package/src/interface/views/detail-content.ts +4 -4
  37. package/src/interface/views/format.ts +4 -4
  38. package/src/{orchestration/jsonl-run-store.ts → jsonl-run-store.ts} +132 -18
  39. package/src/execution/__tests__/__fixtures__/notifier-golden-snapshots.json +0 -53
  40. package/src/execution/__tests__/__fixtures__/truncline.snapshot.json +0 -1
  41. package/src/execution/__tests__/agent-registry.test.ts +0 -363
  42. package/src/execution/__tests__/agent-result-mapper.test.ts +0 -150
  43. package/src/execution/__tests__/alive-store.test.ts +0 -147
  44. package/src/execution/__tests__/ask-user-transit-e2e.test.ts +0 -490
  45. package/src/execution/__tests__/before-agent-start-injection.test.ts +0 -132
  46. package/src/execution/__tests__/bg-notify-render.test.ts +0 -256
  47. package/src/execution/__tests__/channel-registry-handshake.test.ts +0 -243
  48. package/src/execution/__tests__/chat-engine-routing.test.ts +0 -597
  49. package/src/execution/__tests__/chatmode-first-round-closure-service.test.ts +0 -365
  50. package/src/execution/__tests__/chatmode-first-round-closure-spawn.test.ts +0 -190
  51. package/src/execution/__tests__/chatmode-round-notify-real-chain.test.ts +0 -215
  52. package/src/execution/__tests__/concurrency-pool.test.ts +0 -250
  53. package/src/execution/__tests__/config.test.ts +0 -110
  54. package/src/execution/__tests__/conversation-wiring.test.ts +0 -198
  55. package/src/execution/__tests__/crash-recovery.test.ts +0 -320
  56. package/src/execution/__tests__/delivery-methods.test.ts +0 -385
  57. package/src/execution/__tests__/dialog-queue.test.ts +0 -299
  58. package/src/execution/__tests__/epipe-fallback.test.ts +0 -241
  59. package/src/execution/__tests__/execute-and-await-worktree.test.ts +0 -243
  60. package/src/execution/__tests__/execute-nesting.test.ts +0 -323
  61. package/src/execution/__tests__/execute-options-mapper.test.ts +0 -189
  62. package/src/execution/__tests__/execution-record.test.ts +0 -1284
  63. package/src/execution/__tests__/finalize-record.test.ts +0 -368
  64. package/src/execution/__tests__/finalized-marker.test.ts +0 -82
  65. package/src/execution/__tests__/format-schema-instruction.test.ts +0 -138
  66. package/src/execution/__tests__/format.test.ts +0 -458
  67. package/src/execution/__tests__/gc-timer.test.ts +0 -184
  68. package/src/execution/__tests__/get-record-for-action-restart.test.ts +0 -254
  69. package/src/execution/__tests__/gui-mode-dispatch.test.ts +0 -59
  70. package/src/execution/__tests__/helpers/mock-extension-api.ts +0 -30
  71. package/src/execution/__tests__/helpers/spawn-mock.ts +0 -238
  72. package/src/execution/__tests__/host-mode.test.ts +0 -87
  73. package/src/execution/__tests__/index-session-start-identity.test.ts +0 -371
  74. package/src/execution/__tests__/index-session-start.test.ts +0 -593
  75. package/src/execution/__tests__/lifecycle-manager-lock.test.ts +0 -211
  76. package/src/execution/__tests__/lifecycle-manager.test.ts +0 -337
  77. package/src/execution/__tests__/lifecycle-predicates.test.ts +0 -116
  78. package/src/execution/__tests__/list-component.test.ts +0 -401
  79. package/src/execution/__tests__/list-fields.test.ts +0 -109
  80. package/src/execution/__tests__/manifest-parentid.test.ts +0 -117
  81. package/src/execution/__tests__/model-resolver.test.ts +0 -413
  82. package/src/execution/__tests__/nested-visibility-env-propagation.test.ts +0 -287
  83. package/src/execution/__tests__/nested-visibility.test.ts +0 -325
  84. package/src/execution/__tests__/notifier-flush.test.ts +0 -574
  85. package/src/execution/__tests__/notifier-golden-snapshot.test.ts +0 -261
  86. package/src/execution/__tests__/one-shot-upgrade.test.ts +0 -205
  87. package/src/execution/__tests__/output-collector.test.ts +0 -61
  88. package/src/execution/__tests__/parent-child-matrix.test.ts +0 -336
  89. package/src/execution/__tests__/path-encoding.test.ts +0 -104
  90. package/src/execution/__tests__/pi-invocation.test.ts +0 -134
  91. package/src/execution/__tests__/record-store.test.ts +0 -1057
  92. package/src/execution/__tests__/records-cwd-isolation.test.ts +0 -91
  93. package/src/execution/__tests__/recursive-visibility-baseline.test.ts +0 -339
  94. package/src/execution/__tests__/recursive-visibility-env.test.ts +0 -273
  95. package/src/execution/__tests__/relay-agent.test.ts +0 -448
  96. package/src/execution/__tests__/relay-env.test.ts +0 -42
  97. package/src/execution/__tests__/resource-policy.test.ts +0 -109
  98. package/src/execution/__tests__/rpc-mode.test.ts +0 -89
  99. package/src/execution/__tests__/run-and-finalize-chatmode.test.ts +0 -267
  100. package/src/execution/__tests__/run-spawn-chatmode-settled.test.ts +0 -253
  101. package/src/execution/__tests__/run-spawn-edges.test.ts +0 -644
  102. package/src/execution/__tests__/run-spawn-integration.test.ts +0 -933
  103. package/src/execution/__tests__/run-spawn-resume.test.ts +0 -322
  104. package/src/execution/__tests__/run-spawn-rpc-mode.test.ts +0 -196
  105. package/src/execution/__tests__/sdk-contract.test.ts +0 -273
  106. package/src/execution/__tests__/session-context-resolver.test.ts +0 -167
  107. package/src/execution/__tests__/session-file-gc.test.ts +0 -293
  108. package/src/execution/__tests__/session-pending.test.ts +0 -197
  109. package/src/execution/__tests__/session-reconstructor.test.ts +0 -379
  110. package/src/execution/__tests__/session-runner-epipe.test.ts +0 -178
  111. package/src/execution/__tests__/session-runner-schema-env.test.ts +0 -311
  112. package/src/execution/__tests__/session-start-reaper.test.ts +0 -233
  113. package/src/execution/__tests__/spawn-args.test.ts +0 -434
  114. package/src/execution/__tests__/spawn-event-adapter-rpc.test.ts +0 -189
  115. package/src/execution/__tests__/spawn-event-adapter.test.ts +0 -167
  116. package/src/execution/__tests__/spawn-worktree-guidance.test.ts +0 -207
  117. package/src/execution/__tests__/spawned-children.test.ts +0 -92
  118. package/src/execution/__tests__/startup-config-declaration.test.ts +0 -35
  119. package/src/execution/__tests__/status-refactor.test.ts +0 -345
  120. package/src/execution/__tests__/stdin-writer.test.ts +0 -463
  121. package/src/execution/__tests__/stream-sink-retirement.test.ts +0 -261
  122. package/src/execution/__tests__/subagent-service-abort.test.ts +0 -60
  123. package/src/execution/__tests__/subagent-service-message-close.test.ts +0 -629
  124. package/src/execution/__tests__/subagent-service-parent-guard.test.ts +0 -180
  125. package/src/execution/__tests__/subagent-service.test.ts +0 -788
  126. package/src/execution/__tests__/subprocess-agent-runner-routing.test.ts +0 -310
  127. package/src/execution/__tests__/subprocess-agent-runner.test.ts +0 -506
  128. package/src/execution/__tests__/temp-prompt.test.ts +0 -53
  129. package/src/execution/__tests__/timeout-integration.test.ts +0 -397
  130. package/src/execution/__tests__/tombstone-store.test.ts +0 -73
  131. package/src/execution/__tests__/tool-action.test.ts +0 -385
  132. package/src/execution/__tests__/truncline-snapshot.test.ts +0 -81
  133. package/src/execution/__tests__/turn-limiter-semantics.test.ts +0 -194
  134. package/src/execution/__tests__/turn-limiter.test.ts +0 -65
  135. package/src/execution/__tests__/ui-channels.test.ts +0 -187
  136. package/src/execution/__tests__/ui-interaction-model.test.ts +0 -67
  137. package/src/execution/__tests__/ui-request-handler-factory.test.ts +0 -370
  138. package/src/execution/__tests__/ui-request-handler.test.ts +0 -204
  139. package/src/execution/__tests__/ui-request-observability.test.ts +0 -114
  140. package/src/execution/__tests__/ui-request-queue.test.ts +0 -133
  141. package/src/execution/__tests__/worktree-manager.test.ts +0 -633
  142. package/src/execution/__tests__/worktree-pid-registration.integration.test.ts +0 -229
  143. package/src/execution/__tests__/worktree-reconcile.integration.test.ts +0 -181
  144. package/src/execution/__tests__/worktree-registry.test.ts +0 -199
  145. package/src/execution/agent-registry.ts +0 -193
  146. package/src/execution/agent-result-mapper.ts +0 -90
  147. package/src/execution/alive-store.ts +0 -92
  148. package/src/execution/argv-mirror.ts +0 -109
  149. package/src/execution/best-effort.ts +0 -38
  150. package/src/execution/channel-registry-access.ts +0 -144
  151. package/src/execution/concurrency-pool.ts +0 -116
  152. package/src/execution/config.ts +0 -96
  153. package/src/execution/dialog-queue.ts +0 -330
  154. package/src/execution/engine/__tests__/common/data-dir.test.ts +0 -53
  155. package/src/execution/engine/__tests__/common/errors.test.ts +0 -132
  156. package/src/execution/engine/__tests__/common/event-journal.test.ts +0 -177
  157. package/src/execution/engine/__tests__/common/kill-chain.test.ts +0 -192
  158. package/src/execution/engine/__tests__/common/nesting-guard.test.ts +0 -81
  159. package/src/execution/engine/__tests__/common/persona-router.test.ts +0 -123
  160. package/src/execution/engine/__tests__/common/pool-manager.test.ts +0 -154
  161. package/src/execution/engine/__tests__/common/schema-emulation.test.ts +0 -128
  162. package/src/execution/engine/__tests__/conformance/__fixtures__/pi-golden-events.json +0 -28
  163. package/src/execution/engine/__tests__/conformance/agent-event-invariants.ts +0 -141
  164. package/src/execution/engine/__tests__/conformance/contract.abort.test.ts +0 -109
  165. package/src/execution/engine/__tests__/conformance/contract.agent-events.test.ts +0 -101
  166. package/src/execution/engine/__tests__/conformance/contract.probe.test.ts +0 -77
  167. package/src/execution/engine/__tests__/conformance/contract.read-degradation.test.ts +0 -104
  168. package/src/execution/engine/__tests__/conformance/contract.relay.test.ts +0 -342
  169. package/src/execution/engine/__tests__/conformance/engine-conformance.live.test.ts +0 -201
  170. package/src/execution/engine/__tests__/conformance/golden-replay.pi.test.ts +0 -76
  171. package/src/execution/engine/__tests__/conformance/golden-replay.zcode.test.ts +0 -79
  172. package/src/execution/engine/__tests__/engine-discovery.test.ts +0 -87
  173. package/src/execution/engine/__tests__/engines-declaration.test.ts +0 -36
  174. package/src/execution/engine/__tests__/model-prompt.test.ts +0 -85
  175. package/src/execution/engine/__tests__/paths.test.ts +0 -39
  176. package/src/execution/engine/__tests__/registry.test.ts +0 -120
  177. package/src/execution/engine/__tests__/routing.test.ts +0 -231
  178. package/src/execution/engine/common/data-dir.ts +0 -62
  179. package/src/execution/engine/common/errors.ts +0 -183
  180. package/src/execution/engine/common/event-journal.ts +0 -254
  181. package/src/execution/engine/common/journal-replay.ts +0 -62
  182. package/src/execution/engine/common/kill-chain.ts +0 -221
  183. package/src/execution/engine/common/nesting-guard.ts +0 -50
  184. package/src/execution/engine/common/persona-router.ts +0 -108
  185. package/src/execution/engine/common/pool-manager.ts +0 -226
  186. package/src/execution/engine/common/schema-emulation.ts +0 -189
  187. package/src/execution/engine/common/session-view-projection.ts +0 -51
  188. package/src/execution/engine/engine-discovery.ts +0 -65
  189. package/src/execution/engine/engines/pi/__tests__/pi-engine.test.ts +0 -469
  190. package/src/execution/engine/engines/pi/__tests__/reader.test.ts +0 -155
  191. package/src/execution/engine/engines/pi/__tests__/task-spec-mapper.test.ts +0 -164
  192. package/src/execution/engine/engines/pi/pi-engine.ts +0 -415
  193. package/src/execution/engine/engines/pi/reader.ts +0 -48
  194. package/src/execution/engine/engines/pi/registration.ts +0 -35
  195. package/src/execution/engine/engines/pi/task-spec-mapper.ts +0 -100
  196. package/src/execution/engine/engines/zcode/__tests__/__fixtures__/zcode-golden-spawn.json +0 -39
  197. package/src/execution/engine/engines/zcode/__tests__/launcher.test.ts +0 -150
  198. package/src/execution/engine/engines/zcode/__tests__/parser.test.ts +0 -246
  199. package/src/execution/engine/engines/zcode/__tests__/preparer.test.ts +0 -228
  200. package/src/execution/engine/engines/zcode/__tests__/reader.test.ts +0 -210
  201. package/src/execution/engine/engines/zcode/__tests__/registration.test.ts +0 -64
  202. package/src/execution/engine/engines/zcode/__tests__/zcode-engine.live.test.ts +0 -127
  203. package/src/execution/engine/engines/zcode/__tests__/zcode-engine.test.ts +0 -567
  204. package/src/execution/engine/engines/zcode/constants.ts +0 -43
  205. package/src/execution/engine/engines/zcode/golden-sample.ts +0 -39
  206. package/src/execution/engine/engines/zcode/launcher.ts +0 -161
  207. package/src/execution/engine/engines/zcode/parser.ts +0 -436
  208. package/src/execution/engine/engines/zcode/preparer.ts +0 -363
  209. package/src/execution/engine/engines/zcode/reader.ts +0 -381
  210. package/src/execution/engine/engines/zcode/registration.ts +0 -37
  211. package/src/execution/engine/engines/zcode/zcode-engine.ts +0 -648
  212. package/src/execution/engine/host-task-spec.ts +0 -47
  213. package/src/execution/engine/model-prompt.ts +0 -59
  214. package/src/execution/engine/paths.ts +0 -42
  215. package/src/execution/engine/port.ts +0 -153
  216. package/src/execution/engine/registry.ts +0 -123
  217. package/src/execution/engine/routing.ts +0 -218
  218. package/src/execution/engine/types.ts +0 -304
  219. package/src/execution/execute-options-mapper.ts +0 -111
  220. package/src/execution/execution-record.ts +0 -906
  221. package/src/execution/finalize-record.ts +0 -251
  222. package/src/execution/finalized-marker.ts +0 -51
  223. package/src/execution/get-state-handshake.ts +0 -104
  224. package/src/execution/host-mode.ts +0 -56
  225. package/src/execution/idle-gc.ts +0 -47
  226. package/src/execution/lifecycle-manager.ts +0 -491
  227. package/src/execution/lifecycle-predicates.ts +0 -65
  228. package/src/execution/manifest-store.ts +0 -256
  229. package/src/execution/model-config-service.ts +0 -204
  230. package/src/execution/model-resolver.ts +0 -276
  231. package/src/execution/notifier.ts +0 -260
  232. package/src/execution/output-collector.ts +0 -88
  233. package/src/execution/path-encoding.ts +0 -60
  234. package/src/execution/pi-invocation.ts +0 -120
  235. package/src/execution/record-entry.ts +0 -132
  236. package/src/execution/record-store.ts +0 -1234
  237. package/src/execution/relay-env.ts +0 -37
  238. package/src/execution/session-context-resolver.ts +0 -64
  239. package/src/execution/session-file-gc.ts +0 -120
  240. package/src/execution/session-pending.ts +0 -164
  241. package/src/execution/session-reconstructor.ts +0 -678
  242. package/src/execution/session-runner.ts +0 -1548
  243. package/src/execution/sessions-index.ts +0 -304
  244. package/src/execution/spawn-event-adapter.ts +0 -363
  245. package/src/execution/stdin-writer.ts +0 -198
  246. package/src/execution/stream-sink.ts +0 -126
  247. package/src/execution/subagent-service.ts +0 -2119
  248. package/src/execution/subprocess-agent-runner.ts +0 -303
  249. package/src/execution/temp-prompt.ts +0 -62
  250. package/src/execution/tombstone-store.ts +0 -72
  251. package/src/execution/turn-limiter.ts +0 -102
  252. package/src/execution/types.ts +0 -910
  253. package/src/execution/ui-channels.ts +0 -216
  254. package/src/execution/ui-interaction-model.ts +0 -48
  255. package/src/execution/ui-request-handler-factory.ts +0 -212
  256. package/src/execution/ui-request-observability.ts +0 -81
  257. package/src/execution/ui-request-queue.ts +0 -174
  258. package/src/execution/worktree-manager.ts +0 -688
  259. package/src/execution/worktree-registry.ts +0 -222
  260. package/src/orchestration/__tests__/__fixtures__/worker-template.snapshot.txt +0 -336
  261. package/src/orchestration/__tests__/agent-call-catch-fallback.test.ts +0 -208
  262. package/src/orchestration/__tests__/agent-call-stream.test.ts +0 -157
  263. package/src/orchestration/__tests__/args-validator.test.ts +0 -143
  264. package/src/orchestration/__tests__/concurrency-gate.test.ts +0 -125
  265. package/src/orchestration/__tests__/config-loader.test.ts +0 -503
  266. package/src/orchestration/__tests__/error-recovery-handlers.test.ts +0 -724
  267. package/src/orchestration/__tests__/error-recovery-postmessage-defense.test.ts +0 -405
  268. package/src/orchestration/__tests__/error-recovery-serialize-failed-result.test.ts +0 -56
  269. package/src/orchestration/__tests__/error-recovery-workflow-call.test.ts +0 -166
  270. package/src/orchestration/__tests__/execute-agent-call.test.ts +0 -314
  271. package/src/orchestration/__tests__/jsonl-run-store-loadall-sources.test.ts +0 -171
  272. package/src/orchestration/__tests__/jsonl-run-store-session-file.test.ts +0 -1030
  273. package/src/orchestration/__tests__/launcher-nested-workflow.test.ts +0 -277
  274. package/src/orchestration/__tests__/lifecycle-runid-injection.test.ts +0 -96
  275. package/src/orchestration/__tests__/lifecycle.test.ts +0 -625
  276. package/src/orchestration/__tests__/review-fix-loop-e2e.test.ts +0 -1971
  277. package/src/orchestration/__tests__/script-lint.test.ts +0 -831
  278. package/src/orchestration/__tests__/skill-discovery.test.ts +0 -157
  279. package/src/orchestration/__tests__/test-mocks.ts +0 -197
  280. package/src/orchestration/__tests__/worker-host.test.ts +0 -120
  281. package/src/orchestration/__tests__/worker-returnmeta-passthrough.test.ts +0 -164
  282. package/src/orchestration/__tests__/worker-script-builder-runtime.test.ts +0 -520
  283. package/src/orchestration/__tests__/worker-script-builder.test.ts +0 -309
  284. package/src/orchestration/__tests__/worker-script-template-snapshot.test.ts +0 -110
  285. package/src/orchestration/__tests__/workflow-nesting-e2e.test.ts +0 -317
  286. package/src/orchestration/__tests__/workflow-script-lint-memo.test.ts +0 -110
  287. package/src/orchestration/__tests__/workflows-e2e.test.ts +0 -537
  288. package/src/orchestration/agent-opts-resolver.ts +0 -93
  289. package/src/orchestration/args-validator.ts +0 -127
  290. package/src/orchestration/concurrency-gate.ts +0 -69
  291. package/src/orchestration/config-loader.ts +0 -315
  292. package/src/orchestration/error-recovery.ts +0 -862
  293. package/src/orchestration/execute-agent-call.ts +0 -217
  294. package/src/orchestration/launcher.ts +0 -410
  295. package/src/orchestration/lifecycle.ts +0 -396
  296. package/src/orchestration/models/__tests__/budget.test.ts +0 -367
  297. package/src/orchestration/models/__tests__/trace.test.ts +0 -408
  298. package/src/orchestration/models/agent-call.ts +0 -83
  299. package/src/orchestration/models/budget.ts +0 -148
  300. package/src/orchestration/models/ports.ts +0 -164
  301. package/src/orchestration/models/run-runtime.ts +0 -89
  302. package/src/orchestration/models/run-spec.ts +0 -83
  303. package/src/orchestration/models/run-state.ts +0 -44
  304. package/src/orchestration/models/trace.ts +0 -183
  305. package/src/orchestration/models/types.ts +0 -292
  306. package/src/orchestration/models/workflow-run.ts +0 -254
  307. package/src/orchestration/models/workflow-script-registry.ts +0 -35
  308. package/src/orchestration/models/workflow-script.ts +0 -117
  309. package/src/orchestration/script-lint.ts +0 -766
  310. package/src/orchestration/skill-discovery.ts +0 -92
  311. package/src/orchestration/worker-handle.ts +0 -115
  312. package/src/orchestration/worker-host.ts +0 -98
  313. package/src/orchestration/worker-script-builder.ts +0 -408
  314. package/src/orchestration/workflow-files.ts +0 -85
  315. package/src/orchestration/workflow-script-registry-impl.ts +0 -133
  316. package/src/shared/__tests__/agent-ref.test.ts +0 -34
  317. package/src/shared/__tests__/meta-parser.test.ts +0 -304
  318. package/src/shared/__tests__/resource-discovery-manifest-cache.test.ts +0 -280
  319. package/src/shared/__tests__/resource-discovery.test.ts +0 -736
  320. package/src/shared/__tests__/resource-meta.test.ts +0 -51
  321. package/src/shared/__tests__/schema-jsonify.test.ts +0 -81
  322. package/src/shared/agent-event.ts +0 -13
  323. package/src/shared/agent-ref.ts +0 -57
  324. package/src/shared/meta-parser.ts +0 -261
  325. package/src/shared/resource-discovery.ts +0 -811
  326. package/src/shared/resource-meta.ts +0 -65
  327. package/src/shared/schema-jsonify.ts +0 -56
  328. package/src/shared/xml-injection.ts +0 -35
  329. package/workflows/README.md +0 -81
  330. package/workflows/_shared/agent-refs.cjs +0 -40
  331. package/workflows/chain.js +0 -131
  332. package/workflows/map-reduce.js +0 -174
  333. package/workflows/parallel.js +0 -148
  334. package/workflows/review-fix-loop-utils.cjs +0 -1307
  335. package/workflows/review-fix-loop.js +0 -1396
  336. package/workflows/scatter-gather.js +0 -178
@@ -1,304 +0,0 @@
1
- /**
2
- * meta-parser 测试(v5 §11.1 / TC1-TC10 + 边界 + exec-review 回归)
3
- *
4
- * [P-yaml] 探针由 TC5/TC10 承载:验证 eemeli/yaml 真实抛错对象有 linePos 字段且结构为
5
- * {line,col}(取自 linePos[0])。不 mock parseYaml——必须用真实库验证此运行时断言。
6
- *
7
- * exec-review 回归:major-1(星斜杠截断)+ minor-2(kind 串类)+ minor-3(description 必填)
8
- * + minor-4(detail 非字符串)+ minor-5(parameters 非对象)+ minor-6(空块 vs 缺块)+ minor-7(CRLF)。
9
- *
10
- * 框架:vitest(项目规范:禁 node:test,import from "vitest")。
11
- */
12
- import { describe, expect, it } from "vitest";
13
-
14
- import {
15
- parseResourceMeta,
16
- parseResourceMetaDetailed,
17
- } from "../meta-parser.ts";
18
- import type { AgentMeta, WorkflowMeta } from "../resource-meta.ts";
19
-
20
- // ── 固定 content fixtures ────────────────────────────────────
21
-
22
- const VALID_WORKFLOW = `// 顶部可有任意代码注释
23
- /* @pi-meta
24
- name: chain
25
- description: 通用编排三步链
26
- when: 用户要顺序编排
27
- phases: [analyze, transform, synthesize]
28
- parameters:
29
- type: object
30
- properties:
31
- task: { type: string }
32
- required: [task]
33
- usage: |
34
- ## 使用说明
35
- - task 必填
36
- */
37
- const agent = require("./agent");
38
- `;
39
-
40
- const VALID_AGENT = `---
41
- name: code-review
42
- description: 审查代码变更
43
- when: 用户要求 review
44
- notFor: 非 xyz-agent 项目
45
- examples:
46
- - match: "帮我 review 一下"
47
- action: 调用 code-review
48
- positive: true
49
- - match: 今天天气
50
- action: 不调用
51
- positive: false
52
- tools: [read, bash, grep]
53
- model: claude-3.5
54
- ---
55
- # code-review agent 正文
56
- `;
57
-
58
- const MALFORMED_INDENT = `/* @pi-meta
59
- name: x
60
- description: bad
61
- description: bad indent
62
- phases: [a]
63
- */`;
64
-
65
- const REGEX_SINGLE_BACKSLASH = `/* @pi-meta
66
- name: rfl
67
- description: 测试正则转义
68
- phases: [Review, Fix]
69
- parameters:
70
- type: object
71
- patternProperties:
72
- "^batch\\d+$": { type: string }
73
- */`;
74
-
75
- const LEGACY_CONST_META = `const meta = {
76
- name: chain,
77
- description: 旧格式,
78
- phases: ["a"]
79
- };
80
- const agent = require("./agent");
81
- `;
82
-
83
- const NO_META_BLOCK = `const agent = require("./agent");
84
- // 纯代码,无 @pi-meta
85
- `;
86
-
87
- const EMPTY_PI_META = `/* @pi-meta
88
-
89
- */
90
- const x = 1;
91
- `;
92
-
93
- const EMPTY_PHASES = `/* @pi-meta
94
- name: x
95
- description: 空 phases
96
- phases: []
97
- */`;
98
-
99
- // ── parseResourceMeta(IF1,discovery)──────────────────────
100
-
101
- describe("parseResourceMeta (discovery, fail-safe null)", () => {
102
- it("TC1: 合法 workflow @pi-meta 返 WorkflowMeta", () => {
103
- const meta = parseResourceMeta(VALID_WORKFLOW, "workflow");
104
- expect(meta).not.toBeNull();
105
- const wf = meta as WorkflowMeta;
106
- expect(wf.kind).toBe("workflow");
107
- expect(wf.name).toBe("chain");
108
- expect(wf.phases).toEqual(["analyze", "transform", "synthesize"]);
109
- expect(wf.when).toBe("用户要顺序编排");
110
- expect(wf.parameters).toBeDefined();
111
- expect(wf.usage).toContain("task 必填");
112
- });
113
-
114
- it("TC2: 合法 agent frontmatter 返 AgentMeta", () => {
115
- const meta = parseResourceMeta(VALID_AGENT, "agent");
116
- expect(meta).not.toBeNull();
117
- const a = meta as AgentMeta;
118
- expect(a.kind).toBe("agent");
119
- expect(a.name).toBe("code-review");
120
- expect(a.notFor).toBe("非 xyz-agent 项目");
121
- expect(a.examples).toHaveLength(2);
122
- expect(a.examples![0]).toEqual({ match: "帮我 review 一下", action: "调用 code-review", positive: true });
123
- expect(a.examples![1]!.positive).toBe(false);
124
- expect(a.tools).toEqual(["read", "bash", "grep"]);
125
- expect(a.model).toBe("claude-3.5");
126
- });
127
-
128
- it("TC3: malformed YAML(缩进错)返 null,不抛 [P-yaml]", () => {
129
- expect(() => parseResourceMeta(MALFORMED_INDENT, "workflow")).not.toThrow();
130
- expect(parseResourceMeta(MALFORMED_INDENT, "workflow")).toBeNull();
131
- });
132
-
133
- it("TC4: 缺 meta 块返 null", () => {
134
- expect(parseResourceMeta(NO_META_BLOCK, "workflow")).toBeNull();
135
- });
136
-
137
- it("TC8(修正): workflow 字段(phases)当 agent kind 解析,typecheckMeta 串类 reject [minor-2]", () => {
138
- // 用 frontmatter 包裹 workflow 字段,确保 FRONTMATTER_RE 匹配、typecheckMeta 真正被触达
139
- const content = `---
140
- name: chainlike
141
- description: has phases but parsed as agent
142
- phases: [analyze, transform]
143
- parameters:
144
- type: object
145
- ---
146
- # agent body`;
147
- expect(parseResourceMeta(content, "agent")).toBeNull();
148
- });
149
-
150
- it("TC8b: agent 字段(examples)当 workflow kind 解析,串类 reject [minor-2]", () => {
151
- const content = `/* @pi-meta
152
- name: x
153
- description: has examples but workflow
154
- phases: [A]
155
- examples:
156
- - match: m
157
- action: a
158
- positive: true
159
- */`;
160
- expect(parseResourceMeta(content, "workflow")).toBeNull();
161
- });
162
-
163
- it("TC9: legacy const meta(无 @pi-meta 块)返 null(无 adapter)[D1]", () => {
164
- expect(parseResourceMeta(LEGACY_CONST_META, "workflow")).toBeNull();
165
- });
166
-
167
- it("TC10: patternProperties 单反斜杠正则致 YAML 解析失败返 null [P-yaml]", () => {
168
- expect(parseResourceMeta(REGEX_SINGLE_BACKSLASH, "workflow")).toBeNull();
169
- });
170
-
171
- it("边界:空 @pi-meta 块(内容为空)返 null", () => {
172
- expect(parseResourceMeta(EMPTY_PI_META, "workflow")).toBeNull();
173
- });
174
-
175
- it("边界:phases: [] 空数组合法(workflow 可无 phase)", () => {
176
- const meta = parseResourceMeta(EMPTY_PHASES, "workflow");
177
- expect(meta).not.toBeNull();
178
- expect((meta as WorkflowMeta).phases).toEqual([]);
179
- });
180
-
181
- // ── exec-review 回归 ──────────────────────────────────────
182
-
183
- it("major-1: usage 块标量含 */ 不再截断,parameters 不丢失", () => {
184
- const content = `/* @pi-meta
185
- name: x
186
- description: d
187
- phases: [A]
188
- when: present
189
- usage: |
190
- see */ for details
191
- parameters:
192
- type: object
193
- properties:
194
- task: { type: string }
195
- */`;
196
- const meta = parseResourceMeta(content, "workflow");
197
- expect(meta).not.toBeNull();
198
- const wf = meta as WorkflowMeta;
199
- expect(wf.parameters).toBeDefined(); // major-1:此前被 */ 截断静默丢失
200
- expect(wf.when).toBe("present"); // 此前同样丢失
201
- expect(wf.usage).toContain("see */ for details");
202
- });
203
-
204
- it("major-1b: patternProperties 正则含 * 后接 / 不再误截断", () => {
205
- const content = `/* @pi-meta
206
- name: re
207
- description: regex
208
- phases: [A]
209
- parameters:
210
- type: object
211
- patternProperties:
212
- "^\\\\d*/\\\\w+$": { type: string }
213
- */`;
214
- const meta = parseResourceMeta(content, "workflow");
215
- expect(meta).not.toBeNull();
216
- expect((meta as WorkflowMeta).parameters).toBeDefined();
217
- });
218
-
219
- it("minor-3: 缺 description 返 null(必填,不再静默空串)", () => {
220
- const content = `/* @pi-meta
221
- name: nodesc
222
- phases: [A]
223
- */`;
224
- expect(parseResourceMeta(content, "workflow")).toBeNull();
225
- });
226
-
227
- it("minor-4: phase detail 非字符串返 null(不再静默丢弃)", () => {
228
- const content = `/* @pi-meta
229
- name: x
230
- description: d
231
- phases:
232
- - title: A
233
- detail: 123
234
- */`;
235
- expect(parseResourceMeta(content, "workflow")).toBeNull();
236
- });
237
-
238
- it("minor-5: parameters 是数组返 null(不再静默当 undefined)", () => {
239
- const content = `/* @pi-meta
240
- name: x
241
- description: d
242
- phases: [A]
243
- parameters: [a, b]
244
- */`;
245
- expect(parseResourceMeta(content, "workflow")).toBeNull();
246
- });
247
-
248
- it("minor-7: CRLF 行尾 frontmatter 正确提取", () => {
249
- const content = "---\r\nname: a\r\ndescription: d\r\n---\r\n# body";
250
- const meta = parseResourceMeta(content, "agent");
251
- expect(meta).not.toBeNull();
252
- expect((meta as AgentMeta).name).toBe("a");
253
- });
254
- });
255
-
256
- // ── parseResourceMetaDetailed(IF2,generate 闭环)──────────
257
-
258
- describe("parseResourceMetaDetailed (generate, linePos)", () => {
259
- it("TC6: 合法返 {ok:true, meta}", () => {
260
- const r = parseResourceMetaDetailed(VALID_WORKFLOW, "workflow");
261
- expect(r.ok).toBe(true);
262
- if (r.ok) expect(r.meta.name).toBe("chain");
263
- });
264
-
265
- it("TC5: malformed YAML 返 {ok:false, error, linePos:{line,col}} [P-yaml]", () => {
266
- const r = parseResourceMetaDetailed(MALFORMED_INDENT, "workflow");
267
- expect(r.ok).toBe(false);
268
- if (!r.ok) {
269
- expect(r.error).toBeTruthy();
270
- expect(r.linePos).toBeDefined();
271
- expect(typeof r.linePos!.line).toBe("number");
272
- expect(typeof r.linePos!.col).toBe("number");
273
- expect(r.linePos!.line).toBeGreaterThan(0);
274
- }
275
- });
276
-
277
- it("TC7: 缺块返 {ok:false, error} 无 linePos", () => {
278
- const r = parseResourceMetaDetailed(NO_META_BLOCK, "workflow");
279
- expect(r.ok).toBe(false);
280
- if (!r.ok) expect(r.linePos).toBeUndefined();
281
- });
282
-
283
- it("TC10: 单反斜杠正则返 {ok:false, error 含 escape, linePos} [P-yaml]", () => {
284
- const r = parseResourceMetaDetailed(REGEX_SINGLE_BACKSLASH, "workflow");
285
- expect(r.ok).toBe(false);
286
- if (!r.ok) {
287
- expect(r.error).toContain("escape");
288
- expect(r.linePos).toBeDefined();
289
- expect(r.linePos!.line).toBeGreaterThan(0);
290
- }
291
- });
292
-
293
- it("minor-6: 空块与缺块错误消息区分(空块不报「未找到」)", () => {
294
- const empty = parseResourceMetaDetailed(EMPTY_PI_META, "workflow");
295
- const missing = parseResourceMetaDetailed(NO_META_BLOCK, "workflow");
296
- expect(empty.ok).toBe(false);
297
- expect(missing.ok).toBe(false);
298
- if (!empty.ok && !missing.ok) {
299
- // 缺块报「未找到 meta 块」;空块报类型校验失败(块在但内容空/非法)
300
- expect(missing.error).toContain("未找到");
301
- expect(empty.error).not.toContain("未找到");
302
- }
303
- });
304
- });
@@ -1,280 +0,0 @@
1
- // src/shared/__tests__/resource-discovery-manifest-cache.test.ts
2
- //
3
- // manifestCache 专项测试(swf-perf-impl cleanup IF1/DM1/TC1)。
4
- // readPackageManifestSync / async readPackageManifest 共享同一 Map:
5
- // - 命中:同 mtime 二次调用不重读(readFileSync 计数不增)
6
- // - 失效:package.json 重写(mtime 变)→ 重读
7
- // - 坏 JSON:不缓存(mtime 未变时二次调用仍重新 read)、不驱逐已有好条目
8
- // (恢复原内容 + utimesSync 恢复原 mtime → 命中原条目,readFileSync 不增)
9
- // - stat 失败(文件删除)→ undefined 且条目驱逐(重建同内容同 mtime → 必重读)
10
- // - 双读者共享:sync 写入的条目被 async 命中(fs/promises readFile 零调用),反之亦然
11
- //
12
- // ESM 下 node:fs 命名空间不可直接 spyOn(resource-discovery.test.ts TC4a 注记),
13
- // 计数走 vi.mock 工厂包装(透传 actual 实现 + vi.fn 计数,行为零变化)。
14
- // mtime 控制用 utimesSync 定值(整数 ms),消除写入浮点 mtime 的精度/flake 面。
15
-
16
- import * as fs from "node:fs";
17
- import * as os from "node:os";
18
- import * as path from "node:path";
19
- import * as fsp from "node:fs/promises";
20
-
21
- import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
22
-
23
- // 隔离真实用户全局目录(homedir 推导 user-agents 源,同 resource-discovery.test.ts)
24
- vi.mock("node:os", async (importOriginal) => {
25
- const actual = await importOriginal<typeof import("node:os")>();
26
- return { ...actual, homedir: () => "/nonexistent-home-for-tests" };
27
- });
28
-
29
- vi.mock("node:fs", async (importOriginal) => {
30
- const actual = await importOriginal<typeof import("node:fs")>();
31
- return {
32
- ...actual,
33
- readFileSync: vi.fn(
34
- (...args: Parameters<typeof actual.readFileSync>) => actual.readFileSync(...args),
35
- ),
36
- statSync: vi.fn(
37
- (...args: Parameters<typeof actual.statSync>) => actual.statSync(...args),
38
- ),
39
- };
40
- });
41
-
42
- vi.mock("node:fs/promises", async (importOriginal) => {
43
- const actual = await importOriginal<typeof import("node:fs/promises")>();
44
- return {
45
- ...actual,
46
- readFile: vi.fn(
47
- (...args: Parameters<typeof actual.readFile>) => actual.readFile(...args),
48
- ),
49
- };
50
- });
51
-
52
- import { clearFileCache, discoverResources, readPackageManifestSync } from "../resource-discovery.ts";
53
-
54
- // ── helpers ──
55
-
56
- function tmpPkgDir(): string {
57
- return fs.mkdtempSync(path.join(os.tmpdir(), "manifest-cache-test-"));
58
- }
59
-
60
- function writePackageJson(pkgDir: string, pi: Record<string, unknown> | undefined): string {
61
- fs.mkdirSync(pkgDir, { recursive: true });
62
- const filePath = path.join(pkgDir, "package.json");
63
- fs.writeFileSync(filePath, JSON.stringify({ name: "test-pkg", pi }), "utf-8");
64
- return filePath;
65
- }
66
-
67
- /** 写原始(非 JSON)package.json 内容——坏 JSON 用例。 */
68
- function writeRawPackageJson(pkgDir: string, content: string): string {
69
- fs.mkdirSync(pkgDir, { recursive: true });
70
- const filePath = path.join(pkgDir, "package.json");
71
- fs.writeFileSync(filePath, content, "utf-8");
72
- return filePath;
73
- }
74
-
75
- /** 定值 mtime(整数 ms,消除浮点 mtime 与 utimesSync 恢复的精度差)。 */
76
- const T1 = new Date("2026-01-01T00:00:00Z");
77
- const T2 = new Date("2026-01-01T00:00:10Z");
78
-
79
- function setMtime(filePath: string, t: Date): void {
80
- fs.utimesSync(filePath, t, t);
81
- }
82
-
83
- function readCount(): number {
84
- return vi.mocked(fs.readFileSync).mock.calls.length;
85
- }
86
-
87
- /** node:fs/promises readFile 包装计数(异步读者)。 */
88
- function asyncReadCount(): number {
89
- return vi.mocked(fsp.readFile).mock.calls.length;
90
- }
91
-
92
- // ============================================================
93
- // manifestCache(IF1)
94
- // ============================================================
95
-
96
- describe("manifestCache(readPackageManifestSync)", () => {
97
- let pkgDir: string;
98
- let pkgJson: string;
99
-
100
- beforeEach(() => {
101
- clearFileCache();
102
- vi.mocked(fs.readFileSync).mockClear();
103
- pkgDir = tmpPkgDir();
104
- });
105
- afterEach(() => {
106
- fs.rmSync(pkgDir, { recursive: true, force: true });
107
- });
108
-
109
- it("命中:同 mtime 二次调用不重读(readFileSync 只调 1 次)", () => {
110
- pkgJson = writePackageJson(pkgDir, { agents: ["./a.md"] });
111
- setMtime(pkgJson, T1);
112
- const r1 = readPackageManifestSync(pkgDir, "agents");
113
- expect(r1).toEqual(["./a.md"]);
114
- expect(readCount()).toBe(1);
115
- const r2 = readPackageManifestSync(pkgDir, "agents");
116
- expect(r2).toEqual(["./a.md"]);
117
- // 命中缓存:statSync 每次(判 mtime)但 readFileSync 不增
118
- expect(readCount()).toBe(1);
119
- });
120
-
121
- it("kind 共享一次 parse:同 package.json 的 agents/workflows 两 kind 只读一次", () => {
122
- pkgJson = writePackageJson(pkgDir, { agents: ["./a.md"], workflows: ["./w.js"] });
123
- setMtime(pkgJson, T1);
124
- expect(readPackageManifestSync(pkgDir, "agents")).toEqual(["./a.md"]);
125
- expect(readPackageManifestSync(pkgDir, "workflows")).toEqual(["./w.js"]);
126
- expect(readCount()).toBe(1);
127
- });
128
-
129
- it("失效:package.json 重写(mtime 变)→ 重读新内容", () => {
130
- pkgJson = writePackageJson(pkgDir, { agents: ["./a.md"] });
131
- setMtime(pkgJson, T1);
132
- expect(readPackageManifestSync(pkgDir, "agents")).toEqual(["./a.md"]);
133
- writePackageJson(pkgDir, { agents: ["./b.md"] });
134
- // 不需显式设 mtime:新写入的 mtime 必 ≠ 定值 T1
135
- expect(readPackageManifestSync(pkgDir, "agents")).toEqual(["./b.md"]);
136
- expect(readCount()).toBe(2);
137
- });
138
-
139
- it("坏 JSON → undefined 且不缓存:mtime 未变时二次调用仍重新 read(计数递增)", () => {
140
- // 起点即坏 JSON(无缓存条目)——若坏结果被缓存,二次调用不会重新 readFile。
141
- // (good→bad 且 mtime 未变的场景由上一用例的命中路径覆盖:mtime 相等直接命中原好条目)
142
- pkgJson = writeRawPackageJson(pkgDir, "{ broken json");
143
- setMtime(pkgJson, T1);
144
- expect(readPackageManifestSync(pkgDir, "agents")).toBeUndefined();
145
- expect(readCount()).toBe(1);
146
- expect(readPackageManifestSync(pkgDir, "agents")).toBeUndefined();
147
- expect(readCount()).toBe(2); // 二次调用仍重新 read = 坏结果未入缓存(毒条目永不入缓存)
148
- });
149
-
150
- it("坏 JSON 不驱逐已有好条目:恢复原内容 + 恢复原 mtime → 命中原条目(readFileSync 不增)", () => {
151
- pkgJson = writePackageJson(pkgDir, { agents: ["./a.md"] });
152
- setMtime(pkgJson, T1);
153
- expect(readPackageManifestSync(pkgDir, "agents")).toEqual(["./a.md"]);
154
- expect(readCount()).toBe(1);
155
- // 改坏且 mtime 变(T2)→ undefined(read 失败路径,不驱逐 {T1, pi} 好条目)
156
- fs.writeFileSync(pkgJson, "{ broken", "utf-8");
157
- setMtime(pkgJson, T2);
158
- expect(readPackageManifestSync(pkgDir, "agents")).toBeUndefined();
159
- expect(readCount()).toBe(2);
160
- // 恢复原内容 + utimesSync 恢复原 mtime → 若好条目仍在则命中(不重 read)
161
- writePackageJson(pkgDir, { agents: ["./a.md"] });
162
- setMtime(pkgJson, T1);
163
- expect(readPackageManifestSync(pkgDir, "agents")).toEqual(["./a.md"]);
164
- expect(readCount()).toBe(2); // 无第 3 次 read = 命中保留的原条目
165
- });
166
-
167
- it("stat 失败(文件删除)→ undefined 且条目驱逐(重建同内容同 mtime → 必重读)", () => {
168
- pkgJson = writePackageJson(pkgDir, { agents: ["./a.md"] });
169
- setMtime(pkgJson, T1);
170
- expect(readPackageManifestSync(pkgDir, "agents")).toEqual(["./a.md"]);
171
- expect(readCount()).toBe(1);
172
- fs.rmSync(pkgJson);
173
- expect(readPackageManifestSync(pkgDir, "agents")).toBeUndefined();
174
- expect(readCount()).toBe(1); // stat 失败路径不触发 read
175
- // 重建同内容 + 恢复同 mtime:条目已被驱逐 → 必重 read(计数 +1)
176
- writePackageJson(pkgDir, { agents: ["./a.md"] });
177
- setMtime(pkgJson, T1);
178
- expect(readPackageManifestSync(pkgDir, "agents")).toEqual(["./a.md"]);
179
- expect(readCount()).toBe(2);
180
- });
181
-
182
- it("无 pi 字段(合法解析结果)也缓存:二次调用不重读", () => {
183
- pkgJson = writePackageJson(pkgDir, undefined);
184
- setMtime(pkgJson, T1);
185
- expect(readPackageManifestSync(pkgDir, "agents")).toBeUndefined();
186
- expect(readCount()).toBe(1);
187
- expect(readPackageManifestSync(pkgDir, "agents")).toBeUndefined();
188
- expect(readCount()).toBe(1);
189
- });
190
-
191
- // [review 修复] 非对象 JSON 结构守卫:JSON.parse 对 "42" / '"str"' / "null" 等
192
- // 合法 JSON 产出非对象值,旧 `as Record<string, unknown>` 盲断言下 .pi 访问
193
- // 「碰巧不抛」(primitive 装箱返 undefined / null 抛 TypeError 落 catch)——
194
- // 显式守卫后按「无 manifest」(undefined)处理,行为等价但不再依赖巧合。
195
- it("非对象 JSON(42 / null / string / pi 字段非对象或数组)→ undefined 不抛,按合法解析结果缓存", () => {
196
- const cases: Array<{ raw: string; label: string }> = [
197
- { raw: "42", label: "number" },
198
- { raw: "null", label: "null" },
199
- { raw: '"just-a-string"', label: "string" },
200
- { raw: '{"name":"p","pi":42}', label: "pi-field-not-object" },
201
- // [review 修复] 数组能骗过 typeof "object" 守卫(装箱对象)——非合法 pi 容器,
202
- // 显式归 undefined(语义上仍是「无 manifest」,与数组 entries 读出 undefined 一致)
203
- { raw: '{"name":"p","pi":[]}', label: "pi-field-array" },
204
- ];
205
- // 每 case 独立子目录(缓存 key = package.json 绝对路径),互不命中;
206
- // readCount 是跨 case 累积计数,断言用本 case 增量
207
- for (const { raw, label } of cases) {
208
- const before = readCount();
209
- const caseDir = path.join(pkgDir, label);
210
- pkgJson = writeRawPackageJson(caseDir, raw);
211
- setMtime(pkgJson, T1);
212
- expect(readPackageManifestSync(caseDir, "agents"), `case ${label}`).toBeUndefined();
213
- expect(readPackageManifestSync(caseDir, "workflows"), `case ${label}`).toBeUndefined();
214
- // 合法解析 + 无 manifest → 缓存 undefined 条目(同「无 pi 字段」语义,二次调用不重读)
215
- expect(readCount() - before, `case ${label}`).toBe(1);
216
- }
217
- });
218
- });
219
-
220
- // ============================================================
221
- // 双读者共享(async readPackageManifest ↔ sync 共享同一 Map)
222
- // ============================================================
223
-
224
- describe("manifestCache 双读者共享(async ↔ sync)", () => {
225
- let ws: string;
226
- let pkgDir: string;
227
- let savedEnv: string | undefined;
228
-
229
- beforeEach(() => {
230
- clearFileCache();
231
- vi.mocked(fs.readFileSync).mockClear();
232
- vi.mocked(fsp.readFile).mockClear();
233
- ws = tmpPkgDir();
234
- pkgDir = path.join(ws, "my-ext");
235
- savedEnv = process.env.XYZ_EXTENSION_PATHS;
236
- });
237
- afterEach(() => {
238
- if (savedEnv === undefined) delete process.env.XYZ_EXTENSION_PATHS;
239
- else process.env.XYZ_EXTENSION_PATHS = savedEnv;
240
- fs.rmSync(ws, { recursive: true, force: true });
241
- });
242
-
243
- it("sync 写入的条目被 async 命中:discoverResources 零 fs/promises readFile", async () => {
244
- const pkgJson = writePackageJson(pkgDir, { agents: ["./agents"] });
245
- fs.mkdirSync(path.join(pkgDir, "agents"), { recursive: true });
246
- fs.writeFileSync(path.join(pkgDir, "agents", "a.md"), "body", "utf-8");
247
- setMtime(pkgJson, T1);
248
- // sync 读者先填充缓存
249
- expect(readPackageManifestSync(pkgDir, "agents")).toEqual(["./agents"]);
250
- expect(readCount()).toBe(1);
251
- // async 读者(XYZ_EXTENSION_PATHS → processPackage → readPackageManifest)应命中共享条目
252
- process.env.XYZ_EXTENSION_PATHS = pkgDir;
253
- const result = await discoverResources({
254
- kind: "agents",
255
- workspaceRoot: ws,
256
- agentDir: path.join(ws, ".fake-agent"),
257
- });
258
- const ext = result.filter((r) => r.source === "user-extension-paths");
259
- expect(ext.map((r) => path.basename(r.path))).toEqual(["a.md"]);
260
- expect(asyncReadCount()).toBe(0); // async readFile 未被调用 = 命中共享缓存
261
- expect(readCount()).toBe(1); // sync 侧无新增 read
262
- });
263
-
264
- it("async 写入的条目被 sync 命中:async 读后 sync 不再 readFileSync", async () => {
265
- const pkgJson = writePackageJson(pkgDir, { agents: ["./agents"] });
266
- fs.mkdirSync(path.join(pkgDir, "agents"), { recursive: true });
267
- fs.writeFileSync(path.join(pkgDir, "agents", "a.md"), "body", "utf-8");
268
- setMtime(pkgJson, T1);
269
- process.env.XYZ_EXTENSION_PATHS = pkgDir;
270
- await discoverResources({
271
- kind: "agents",
272
- workspaceRoot: ws,
273
- agentDir: path.join(ws, ".fake-agent"),
274
- });
275
- expect(asyncReadCount()).toBe(1); // async 读者读了一次
276
- // sync 读者应命中 async 写入的条目(readFileSync 计数不变)
277
- expect(readPackageManifestSync(pkgDir, "agents")).toEqual(["./agents"]);
278
- expect(readCount()).toBe(0);
279
- });
280
- });