minimal-agent 0.13.0 → 0.14.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 (470) hide show
  1. package/README.md +6 -5
  2. package/package.json +60 -4
  3. package/plugins/computer_use/.claude-plugin/plugin.json +1 -1
  4. package/plugins/cron-runner/src/commands.js +4 -4
  5. package/plugins/cron-runner/src/commands.ts +4 -4
  6. package/plugins/workflow-runner/.claude-plugin/plugin.json +2 -2
  7. package/plugins/workflow-runner/commands/workflow.md +57 -90
  8. package/plugins/workflow-runner/commands/workflows.md +4 -4
  9. package/plugins/workflow-runner/plugin.js +24 -13
  10. package/plugins/workflow-runner/plugin.ts +28 -13
  11. package/plugins/workflow-runner/src/discovery.js +160 -0
  12. package/plugins/workflow-runner/src/discovery.ts +194 -0
  13. package/plugins/workflow-runner/src/goalAnchor.js +53 -0
  14. package/plugins/workflow-runner/src/goalAnchor.ts +59 -0
  15. package/plugins/workflow-runner/src/index.js +197 -206
  16. package/plugins/workflow-runner/src/index.ts +248 -249
  17. package/plugins/workflow-runner/src/inputCoercion.js +40 -0
  18. package/plugins/workflow-runner/src/inputCoercion.ts +43 -0
  19. package/plugins/workflow-runner/src/journal.js +224 -0
  20. package/plugins/workflow-runner/src/journal.ts +274 -0
  21. package/plugins/workflow-runner/src/jsonSchema.js +132 -0
  22. package/plugins/workflow-runner/src/jsonSchema.ts +162 -0
  23. package/plugins/workflow-runner/src/moduleResolution.js +64 -0
  24. package/plugins/workflow-runner/src/moduleResolution.ts +71 -0
  25. package/plugins/workflow-runner/src/resourceInputs.js +220 -0
  26. package/plugins/workflow-runner/src/resourceInputs.ts +300 -0
  27. package/plugins/workflow-runner/src/runner.js +400 -489
  28. package/plugins/workflow-runner/src/runner.ts +488 -560
  29. package/plugins/workflow-runner/src/runtime/config.js +46 -0
  30. package/plugins/workflow-runner/src/runtime/config.ts +69 -0
  31. package/plugins/workflow-runner/src/runtime/context.js +1304 -0
  32. package/plugins/workflow-runner/src/runtime/context.ts +1786 -0
  33. package/plugins/workflow-runner/src/runtime/exec.js +34 -0
  34. package/plugins/workflow-runner/src/runtime/exec.ts +53 -0
  35. package/plugins/workflow-runner/src/runtime/flow.js +8 -0
  36. package/plugins/workflow-runner/src/runtime/flow.ts +12 -0
  37. package/plugins/workflow-runner/src/runtime/fs.js +27 -0
  38. package/plugins/workflow-runner/src/runtime/fs.ts +41 -0
  39. package/plugins/workflow-runner/src/runtime/model.js +6 -0
  40. package/plugins/workflow-runner/src/runtime/model.ts +8 -0
  41. package/plugins/workflow-runner/src/runtime/output.js +7 -0
  42. package/plugins/workflow-runner/src/runtime/output.ts +21 -0
  43. package/plugins/workflow-runner/src/runtime/scheduler.js +141 -0
  44. package/plugins/workflow-runner/src/runtime/scheduler.ts +166 -0
  45. package/plugins/workflow-runner/src/runtime/state.js +16 -0
  46. package/plugins/workflow-runner/src/runtime/state.ts +19 -0
  47. package/plugins/workflow-runner/src/runtime/tools.js +3 -0
  48. package/plugins/workflow-runner/src/runtime/tools.ts +6 -0
  49. package/plugins/workflow-runner/src/sandbox.js +141 -0
  50. package/plugins/workflow-runner/src/sandbox.ts +182 -0
  51. package/plugins/workflow-runner/src/scriptGuard.d.mts +38 -0
  52. package/plugins/workflow-runner/src/scriptGuard.mjs +449 -0
  53. package/plugins/workflow-runner/src/taskIdentity.js +151 -307
  54. package/plugins/workflow-runner/src/taskIdentity.ts +207 -355
  55. package/plugins/workflow-runner/src/toolRuntime.js +29 -8
  56. package/plugins/workflow-runner/src/toolRuntime.ts +36 -11
  57. package/plugins/workflow-runner/src/types.js +7 -211
  58. package/plugins/workflow-runner/src/types.ts +154 -623
  59. package/plugins/workflow-runner/src/util.js +47 -0
  60. package/plugins/workflow-runner/src/util.ts +51 -0
  61. package/plugins/workflow-runner/src/workflowContext.js +20 -0
  62. package/plugins/workflow-runner/src/workflowContext.ts +58 -0
  63. package/plugins/workflow-runner/src/workflowDependencies.js +36 -0
  64. package/plugins/workflow-runner/src/workflowDependencies.ts +59 -0
  65. package/plugins/workflow-runner/src/workflowFingerprint.js +118 -0
  66. package/plugins/workflow-runner/src/workflowFingerprint.ts +122 -0
  67. package/plugins/workflow-runner/src/workflowState.js +474 -802
  68. package/plugins/workflow-runner/src/workflowState.ts +575 -970
  69. package/plugins/workflow-runner/test/api.test.ts +223 -0
  70. package/plugins/workflow-runner/test/apiCapabilities.test.ts +614 -0
  71. package/plugins/workflow-runner/test/apiConcurrencyGate.test.ts +104 -0
  72. package/plugins/workflow-runner/test/apiEcho.test.ts +210 -0
  73. package/plugins/workflow-runner/test/apiReadText.test.ts +178 -0
  74. package/plugins/workflow-runner/test/apiResourceLedger.test.ts +184 -0
  75. package/plugins/workflow-runner/test/childWorkflow.test.ts +304 -0
  76. package/plugins/workflow-runner/test/discovery.test.ts +234 -0
  77. package/plugins/workflow-runner/test/goalAnchor.test.ts +106 -0
  78. package/plugins/workflow-runner/test/goalController.test.ts +317 -0
  79. package/plugins/workflow-runner/test/journalLanes.test.ts +198 -0
  80. package/plugins/workflow-runner/test/listResources.test.ts +106 -0
  81. package/plugins/workflow-runner/test/resourceInputs.test.ts +294 -0
  82. package/plugins/workflow-runner/test/sandbox.test.ts +126 -0
  83. package/plugins/workflow-runner/test/scheduler.test.ts +70 -0
  84. package/plugins/workflow-runner/test/scriptGuard.test.ts +276 -0
  85. package/plugins/workflow-runner/test/skillDocSync.test.ts +78 -0
  86. package/plugins/workflow-runner/test/taskIdentity.test.ts +288 -179
  87. package/plugins/workflow-runner/test/workflowFingerprint.test.ts +106 -0
  88. package/plugins/workflow-runner/test/workflowState.test.ts +429 -0
  89. package/skills/pptx/examples/assets/cover-bg.svg +23 -0
  90. package/skills/pptx/examples/assets/icon-spark.svg +5 -0
  91. package/skills/ui-design/SKILL.md +5 -2
  92. package/skills/ui-design/references/layout-composition.md +1 -1
  93. package/skills/workflow-creator/SKILL.md +344 -0
  94. package/skills/workflow-creator/assets/template/workflow.mjs +48 -0
  95. package/skills/workflow-creator/references/api.md +216 -0
  96. package/skills/workflow-creator/references/migration.md +103 -0
  97. package/skills/workflow-creator/references/patterns.md +779 -0
  98. package/skills/workflow-creator/scripts/list-resources.mjs +205 -0
  99. package/skills/workflow-creator/scripts/scaffold.mjs +148 -0
  100. package/skills/workflow-creator/scripts/validate.mjs +275 -0
  101. package/skills/workflow-creator/scripts/workflow-creator.test.mjs +82 -0
  102. package/src/advisor/advisorCoordinator.js +503 -0
  103. package/src/advisor/advisorCoordinator.ts +657 -0
  104. package/src/cli/configMenu.tsx +0 -1
  105. package/src/cli/print.js +27 -6
  106. package/src/cli/print.ts +48 -4
  107. package/src/cli/streamJson.js +5 -6
  108. package/src/cli/streamJson.ts +8 -4
  109. package/src/cli/wizards/advisorWizard.js +4 -2
  110. package/src/cli/wizards/advisorWizard.tsx +8 -2
  111. package/src/cli/wizards/contextAdvisorWizard.js +5 -4
  112. package/src/cli/wizards/contextAdvisorWizard.tsx +7 -6
  113. package/src/collaboration/taskFlow.js +115 -0
  114. package/src/collaboration/taskFlow.ts +169 -0
  115. package/src/config/configDefaults.js +41 -1
  116. package/src/config/configDefaults.ts +43 -1
  117. package/src/config/configDiagnostics.ts +2 -2
  118. package/src/config/configFile.js +40 -9
  119. package/src/config/configFile.ts +60 -11
  120. package/src/config/configService.js +419 -74
  121. package/src/config/configService.ts +703 -145
  122. package/src/config/numericLimits.js +22 -0
  123. package/src/config/numericLimits.ts +24 -0
  124. package/src/config.js +1 -0
  125. package/src/config.ts +3 -2
  126. package/src/context/budgetPlan.js +1 -1
  127. package/src/context/budgetPlan.ts +1 -1
  128. package/src/context/compact.js +7 -2
  129. package/src/context/compact.ts +9 -2
  130. package/src/context/microCompactLite.js +212 -13
  131. package/src/context/microCompactLite.ts +261 -12
  132. package/src/context/sessionRegistry.js +8 -1
  133. package/src/context/sessionRegistry.ts +18 -5
  134. package/src/context/toolResultArchive.js +72 -0
  135. package/src/context/toolResultArchive.ts +95 -0
  136. package/src/goal/errors.js +8 -0
  137. package/src/goal/errors.ts +18 -0
  138. package/src/goal/goalRuntime.js +344 -0
  139. package/src/goal/goalRuntime.ts +466 -0
  140. package/src/goal/goalStore.js +200 -0
  141. package/src/goal/goalStore.ts +219 -0
  142. package/src/goal/index.js +4 -0
  143. package/src/goal/index.ts +4 -0
  144. package/src/goal/statusMapping.js +71 -0
  145. package/src/goal/statusMapping.ts +95 -0
  146. package/src/goal/types.js +7 -0
  147. package/src/goal/types.ts +179 -0
  148. package/src/goal/workflowController.js +306 -0
  149. package/src/goal/workflowController.ts +360 -0
  150. package/src/harness/evidenceLedger.js +2 -0
  151. package/src/harness/evidenceLedger.ts +1 -0
  152. package/src/harness/stallGuard.js +9 -3
  153. package/src/harness/stallGuard.ts +7 -3
  154. package/src/images/imageResolver.js +161 -0
  155. package/src/images/imageResolver.ts +189 -0
  156. package/src/infra/verification.js +34 -5
  157. package/src/infra/verification.ts +39 -4
  158. package/src/llm/client.js +79 -21
  159. package/src/llm/client.ts +182 -35
  160. package/src/llm/gatewayClient.js +201 -0
  161. package/src/llm/gatewayClient.ts +299 -0
  162. package/src/llm/messageProvenance.js +46 -0
  163. package/src/llm/messageProvenance.ts +58 -0
  164. package/src/llm/modelProvider.js +1 -0
  165. package/src/llm/modelProvider.ts +22 -0
  166. package/src/llm/providers/anthropicFormat.js +108 -1
  167. package/src/llm/providers/anthropicFormat.ts +115 -4
  168. package/src/llm/providers/openaiFormat.js +9 -0
  169. package/src/llm/providers/openaiFormat.ts +12 -3
  170. package/src/loop.js +319 -54
  171. package/src/loop.ts +373 -57
  172. package/src/main.js +4 -1
  173. package/src/main.tsx +4 -1
  174. package/src/managedExecution/index.js +2 -0
  175. package/src/managedExecution/index.ts +2 -0
  176. package/src/managedExecution/registry.js +15 -0
  177. package/src/managedExecution/registry.ts +20 -0
  178. package/src/managedExecution/types.js +1 -0
  179. package/src/managedExecution/types.ts +86 -0
  180. package/src/modelRef.js +9 -0
  181. package/src/modelRef.ts +31 -0
  182. package/src/multimodal.js +14 -28
  183. package/src/multimodal.ts +17 -33
  184. package/src/net/lanDiscovery.js +65 -0
  185. package/src/net/lanDiscovery.ts +82 -0
  186. package/src/plugin-sdk.js +28 -3
  187. package/src/plugin-sdk.ts +39 -6
  188. package/src/plugins/pluginApi.ts +16 -1
  189. package/src/plugins/pluginLoader.js +4 -0
  190. package/src/plugins/pluginLoader.ts +6 -0
  191. package/src/plugins/pluginRunner.js +139 -7
  192. package/src/plugins/pluginRunner.ts +173 -9
  193. package/src/plugins/slashFallback.js +113 -0
  194. package/src/plugins/slashFallback.ts +137 -0
  195. package/src/prompts/policyRegistry.js +12 -32
  196. package/src/prompts/policyRegistry.ts +15 -32
  197. package/src/prompts/promptAssembly.js +103 -12
  198. package/src/prompts/promptAssembly.ts +114 -12
  199. package/src/prompts/skillList.js +21 -3
  200. package/src/prompts/skillList.ts +27 -2
  201. package/src/prompts/stableSystemPrompt.js +18 -0
  202. package/src/prompts/stableSystemPrompt.ts +33 -0
  203. package/src/runtime/agentRuntimeContext.js +8 -2
  204. package/src/runtime/agentRuntimeContext.ts +17 -4
  205. package/src/session/runAgentTurn.js +78 -12
  206. package/src/session/runAgentTurn.ts +105 -23
  207. package/src/session/runTurn.js +10 -9
  208. package/src/session/runTurn.ts +17 -8
  209. package/src/session/sessionState.ts +2 -0
  210. package/src/team/auth.js +186 -0
  211. package/src/team/auth.ts +298 -0
  212. package/src/team/cli.js +105 -0
  213. package/src/team/cli.ts +122 -0
  214. package/src/team/onlineToolContract.js +64 -0
  215. package/src/team/onlineToolContract.ts +109 -0
  216. package/src/team/toolPolicy.js +36 -0
  217. package/src/team/toolPolicy.ts +75 -0
  218. package/src/tools/advisor/advisor.js +90 -46
  219. package/src/tools/advisor/advisor.ts +100 -47
  220. package/src/tools/advisor/advisorDecision.js +71 -0
  221. package/src/tools/advisor/advisorDecision.ts +85 -0
  222. package/src/tools/agent/agent.js +18 -5
  223. package/src/tools/agent/agent.ts +21 -7
  224. package/src/tools/agent/agentControl.js +246 -0
  225. package/src/tools/agent/agentControl.ts +284 -0
  226. package/src/tools/agent/agentTaskService.js +40 -1
  227. package/src/tools/agent/agentTaskService.ts +44 -1
  228. package/src/tools/agent/agentTypes.js +14 -2
  229. package/src/tools/agent/agentTypes.ts +15 -2
  230. package/src/tools/applypatch/applyPatch.js +362 -0
  231. package/src/tools/applypatch/applyPatch.ts +428 -0
  232. package/src/tools/bash/bash.js +22 -15
  233. package/src/tools/bash/bash.ts +23 -17
  234. package/src/tools/capabilities.js +10 -5
  235. package/src/tools/capabilities.ts +10 -5
  236. package/src/tools/computeruse/computerIntent.js +32 -0
  237. package/src/tools/computeruse/computerIntent.ts +46 -0
  238. package/src/tools/computeruse/telemetryLog.js +12 -0
  239. package/src/tools/computeruse/telemetryLog.ts +16 -0
  240. package/src/tools/computeruse/vision/telemetry.js +1 -0
  241. package/src/tools/computeruse/vision/telemetry.ts +1 -0
  242. package/src/tools/effectiveToolSet.js +4 -0
  243. package/src/tools/effectiveToolSet.ts +4 -0
  244. package/src/tools/index.js +21 -2
  245. package/src/tools/index.ts +33 -2
  246. package/src/tools/presentresult/presentresult.js +6 -15
  247. package/src/tools/presentresult/presentresult.ts +6 -15
  248. package/src/tools/read/read.js +62 -9
  249. package/src/tools/read/read.ts +63 -9
  250. package/src/tools/shared/fileUtils.js +1 -2
  251. package/src/tools/shared/fileUtils.ts +1 -2
  252. package/src/tools/shared/toolOutputStore.js +23 -1
  253. package/src/tools/shared/toolOutputStore.ts +22 -1
  254. package/src/tools/skill/skill.js +9 -3
  255. package/src/tools/skill/skill.ts +8 -4
  256. package/src/tools/toolPromptGuides.js +117 -0
  257. package/src/tools/toolPromptGuides.ts +137 -0
  258. package/src/tools/webbrowser/agentBrowserPath.js +19 -9
  259. package/src/tools/webbrowser/agentBrowserPath.ts +70 -28
  260. package/src/tools/webbrowser/browser.js +27 -11
  261. package/src/tools/webbrowser/browser.ts +68 -24
  262. package/src/tools/webbrowser/browserAutomation.js +329 -0
  263. package/src/tools/webbrowser/browserAutomation.ts +467 -0
  264. package/src/tools/webbrowser/browserAxState.js +97 -0
  265. package/src/tools/webbrowser/browserAxState.ts +142 -0
  266. package/src/tools/webbrowser/browserBatch.js +1578 -0
  267. package/src/tools/webbrowser/browserBatch.ts +2382 -0
  268. package/src/tools/webbrowser/browserCdp.js +208 -0
  269. package/src/tools/webbrowser/browserCdp.ts +255 -0
  270. package/src/tools/webbrowser/browserConditions.js +24 -0
  271. package/src/tools/webbrowser/browserConditions.ts +45 -0
  272. package/src/tools/webbrowser/browserContent.js +281 -0
  273. package/src/tools/webbrowser/browserContent.ts +438 -0
  274. package/src/tools/webbrowser/browserControl.js +131 -34
  275. package/src/tools/webbrowser/browserControl.ts +210 -56
  276. package/src/tools/webbrowser/browserDaemon.js +22 -14
  277. package/src/tools/webbrowser/browserDaemon.ts +54 -21
  278. package/src/tools/webbrowser/browserFrames.js +47 -0
  279. package/src/tools/webbrowser/browserFrames.ts +54 -0
  280. package/src/tools/webbrowser/browserInteractionResolver.js +17 -0
  281. package/src/tools/webbrowser/browserInteractionResolver.ts +40 -0
  282. package/src/tools/webbrowser/browserLocator.js +140 -0
  283. package/src/tools/webbrowser/browserLocator.ts +194 -0
  284. package/src/tools/webbrowser/browserOutcome.js +10 -17
  285. package/src/tools/webbrowser/browserOutcome.ts +48 -31
  286. package/src/tools/webbrowser/browserRecovery.js +58 -0
  287. package/src/tools/webbrowser/browserRecovery.ts +83 -0
  288. package/src/tools/webbrowser/browserRunRegistry.js +35 -3
  289. package/src/tools/webbrowser/browserRunRegistry.ts +91 -15
  290. package/src/tools/webbrowser/browserService.js +28 -2
  291. package/src/tools/webbrowser/browserService.ts +49 -9
  292. package/src/tools/webbrowser/browserStream.js +132 -33
  293. package/src/tools/webbrowser/browserStream.ts +224 -50
  294. package/src/tools/webbrowser/browserTabs.js +48 -15
  295. package/src/tools/webbrowser/browserTabs.ts +178 -96
  296. package/src/tools/webbrowser/webbrowser.js +679 -144
  297. package/src/tools/webbrowser/webbrowser.ts +975 -236
  298. package/src/tools/webfetch/preapproved.js +0 -2
  299. package/src/tools/webfetch/preapproved.ts +0 -2
  300. package/src/tools/websearch/websearch.js +129 -8
  301. package/src/tools/websearch/websearch.ts +138 -6
  302. package/src/types.ts +440 -38
  303. package/src/ui/App.js +377 -58
  304. package/src/ui/App.tsx +576 -111
  305. package/src/ui/LiveArea.js +14 -8
  306. package/src/ui/LiveArea.tsx +14 -10
  307. package/src/ui/MessageList.js +63 -20
  308. package/src/ui/MessageList.tsx +101 -16
  309. package/src/ui/ModelPicker.js +7 -4
  310. package/src/ui/ModelPicker.tsx +55 -8
  311. package/src/ui/hooks/useChat.js +152 -163
  312. package/src/ui/hooks/useChat.ts +396 -334
  313. package/src/ui/loginCommand.js +56 -0
  314. package/src/ui/loginCommand.ts +63 -0
  315. package/src/ui/toolProgress.js +41 -0
  316. package/src/ui/toolProgress.ts +44 -0
  317. package/src/web/browserBridge.js +20 -2
  318. package/src/web/browserBridge.ts +20 -2
  319. package/src/web/protocol.ts +1897 -194
  320. package/workflows/adaptive-research/workflow.mjs +86 -0
  321. package/workflows/e2e-capabilities/workflow.mjs +102 -0
  322. package/workflows/e2e-llm/workflow.mjs +52 -0
  323. package/workflows/e2e-smoke/workflow.mjs +59 -0
  324. package/workflows/e2e-vision-schema/README.md +48 -0
  325. package/workflows/e2e-vision-schema/workflow.mjs +149 -0
  326. package/workflows/e2e-write-greet/workflow.mjs +37 -0
  327. package/workflows/file-census/README.md +14 -0
  328. package/workflows/file-census/scripts/.gitkeep +2 -0
  329. package/workflows/file-census/workflow.mjs +110 -0
  330. package/workflows/goal/README.md +166 -0
  331. package/workflows/goal/prompts/audit.md +57 -0
  332. package/workflows/goal/prompts/contract.md +56 -0
  333. package/workflows/goal/prompts/iterate.md +37 -0
  334. package/workflows/goal/workflow.mjs +501 -0
  335. package/workflows/illustrate/README.md +90 -0
  336. package/workflows/illustrate/assets/engines.json +20 -0
  337. package/workflows/illustrate/assets/extract-baidu.js +21 -0
  338. package/workflows/illustrate/assets/extract-bing.js +33 -0
  339. package/workflows/illustrate/assets/extract-google.js +31 -0
  340. package/workflows/illustrate/workflow.mjs +301 -0
  341. package/workflows/plan/workflow.mjs +389 -0
  342. package/workflows/question-crops/README.md +35 -0
  343. package/workflows/question-crops/prompts/inventory.md +23 -0
  344. package/workflows/question-crops/scripts/image-ops.mjs +305 -0
  345. package/workflows/question-crops/scripts/image-ops.test.mjs +95 -0
  346. package/workflows/question-crops/workflow.mjs +172 -0
  347. package/workflows/ralph-loop/workflow.mjs +162 -0
  348. package/workflows/research/README.md +74 -0
  349. package/workflows/research/prompts/s0-goal.md +43 -0
  350. package/workflows/research/prompts/s1-early-exit.md +22 -0
  351. package/workflows/research/prompts/s1-map.md +58 -0
  352. package/workflows/research/prompts/s2-options.md +53 -0
  353. package/workflows/research/prompts/s3-deep-dive.md +56 -0
  354. package/workflows/research/prompts/s4-verify.md +74 -0
  355. package/workflows/research/prompts/s5-synthesis.md +81 -0
  356. package/workflows/research/prompts/s5b-fill-gaps.md +32 -0
  357. package/workflows/research/prompts/s6-package.md +32 -0
  358. package/workflows/research/scripts/build-report.mjs +98 -0
  359. package/workflows/research/workflow.mjs +288 -0
  360. package/workflows/wechat-reading-shots/prompts/collect-params.md +16 -0
  361. package/workflows/wechat-reading-shots/prompts/evaluate.md +20 -0
  362. package/workflows/wechat-reading-shots/prompts/open-book.md +28 -0
  363. package/workflows/wechat-reading-shots/prompts/read-page.md +13 -0
  364. package/workflows/wechat-reading-shots/prompts/turn-batch.md +24 -0
  365. package/workflows/wechat-reading-shots/test/control-flow.test.ts +329 -0
  366. package/workflows/wechat-reading-shots/workflow.mjs +266 -0
  367. package/workflows/wrong-question-docx/README.md +55 -0
  368. package/workflows/wrong-question-docx/prompts/figure-qa.md +8 -0
  369. package/workflows/wrong-question-docx/prompts/transcribe.md +25 -0
  370. package/workflows/wrong-question-docx/scripts/workbook.mjs +857 -0
  371. package/workflows/wrong-question-docx/test/control-flow.test.ts +165 -0
  372. package/workflows/wrong-question-docx/test/workbook.test.mjs +303 -0
  373. package/workflows/wrong-question-docx/workflow.mjs +485 -0
  374. package/plugins/workflow-runner/src/agentCommon.js +0 -354
  375. package/plugins/workflow-runner/src/agentCommon.ts +0 -435
  376. package/plugins/workflow-runner/src/controlFlow/branch.js +0 -40
  377. package/plugins/workflow-runner/src/controlFlow/branch.ts +0 -46
  378. package/plugins/workflow-runner/src/controlFlow/loop.js +0 -211
  379. package/plugins/workflow-runner/src/controlFlow/loop.ts +0 -248
  380. package/plugins/workflow-runner/src/controlFlow/pause.js +0 -129
  381. package/plugins/workflow-runner/src/controlFlow/pause.ts +0 -141
  382. package/plugins/workflow-runner/src/controlFlow/signal.js +0 -21
  383. package/plugins/workflow-runner/src/controlFlow/signal.ts +0 -29
  384. package/plugins/workflow-runner/src/controlFlow/types.js +0 -18
  385. package/plugins/workflow-runner/src/controlFlow/types.ts +0 -63
  386. package/plugins/workflow-runner/src/dslManifest.js +0 -72
  387. package/plugins/workflow-runner/src/dslManifest.ts +0 -127
  388. package/plugins/workflow-runner/src/expressions.js +0 -639
  389. package/plugins/workflow-runner/src/expressions.ts +0 -640
  390. package/plugins/workflow-runner/src/loader.js +0 -573
  391. package/plugins/workflow-runner/src/loader.ts +0 -721
  392. package/plugins/workflow-runner/src/multimodal.js +0 -38
  393. package/plugins/workflow-runner/src/multimodal.ts +0 -64
  394. package/plugins/workflow-runner/src/recovery.js +0 -126
  395. package/plugins/workflow-runner/src/recovery.ts +0 -156
  396. package/plugins/workflow-runner/src/stepExecutors/agent.js +0 -173
  397. package/plugins/workflow-runner/src/stepExecutors/agent.ts +0 -234
  398. package/plugins/workflow-runner/src/stepExecutors/assert.js +0 -42
  399. package/plugins/workflow-runner/src/stepExecutors/assert.ts +0 -52
  400. package/plugins/workflow-runner/src/stepExecutors/echo.js +0 -31
  401. package/plugins/workflow-runner/src/stepExecutors/echo.ts +0 -38
  402. package/plugins/workflow-runner/src/stepExecutors/llm.js +0 -99
  403. package/plugins/workflow-runner/src/stepExecutors/llm.ts +0 -133
  404. package/plugins/workflow-runner/src/stepExecutors/set.js +0 -49
  405. package/plugins/workflow-runner/src/stepExecutors/set.ts +0 -56
  406. package/plugins/workflow-runner/src/stepExecutors/skill.js +0 -111
  407. package/plugins/workflow-runner/src/stepExecutors/skill.ts +0 -140
  408. package/plugins/workflow-runner/src/stepExecutors/tool.js +0 -227
  409. package/plugins/workflow-runner/src/stepExecutors/tool.ts +0 -274
  410. package/plugins/workflow-runner/src/stepExecutors/verify.js +0 -61
  411. package/plugins/workflow-runner/src/stepExecutors/verify.ts +0 -72
  412. package/plugins/workflow-runner/src/stepPipeline.js +0 -277
  413. package/plugins/workflow-runner/src/stepPipeline.ts +0 -366
  414. package/plugins/workflow-runner/test/agent.test.ts +0 -587
  415. package/plugins/workflow-runner/test/agentLlmError.test.ts +0 -373
  416. package/plugins/workflow-runner/test/bashBlacklist.sweep.test.ts +0 -65
  417. package/plugins/workflow-runner/test/captureMisbind.test.ts +0 -99
  418. package/plugins/workflow-runner/test/cli.e2e.test.ts +0 -167
  419. package/plugins/workflow-runner/test/context-files.test.ts +0 -320
  420. package/plugins/workflow-runner/test/e2e.test.ts +0 -370
  421. package/plugins/workflow-runner/test/e2eNewLayout.test.ts +0 -314
  422. package/plugins/workflow-runner/test/engineRobustness.test.ts +0 -234
  423. package/plugins/workflow-runner/test/expressions.test.ts +0 -439
  424. package/plugins/workflow-runner/test/foundation.test.ts +0 -126
  425. package/plugins/workflow-runner/test/graceful.test.ts +0 -139
  426. package/plugins/workflow-runner/test/greedyInputs.load.test.ts +0 -47
  427. package/plugins/workflow-runner/test/hostCapability.test.ts +0 -108
  428. package/plugins/workflow-runner/test/illustrate.load.test.ts +0 -183
  429. package/plugins/workflow-runner/test/jsonPayload.test.ts +0 -83
  430. package/plugins/workflow-runner/test/loader.test.ts +0 -617
  431. package/plugins/workflow-runner/test/maxTurnsRetryDelay.test.ts +0 -33
  432. package/plugins/workflow-runner/test/multimodal.test.ts +0 -342
  433. package/plugins/workflow-runner/test/output-schema.test.ts +0 -213
  434. package/plugins/workflow-runner/test/parseWorkflowArgs.test.ts +0 -106
  435. package/plugins/workflow-runner/test/pluginRunner.isolation.test.ts +0 -269
  436. package/plugins/workflow-runner/test/ppt.load.test.ts +0 -1220
  437. package/plugins/workflow-runner/test/ralphLoop.e2e.test.ts +0 -221
  438. package/plugins/workflow-runner/test/recovery.test.ts +0 -265
  439. package/plugins/workflow-runner/test/research.load.test.ts +0 -328
  440. package/plugins/workflow-runner/test/runner.test.ts +0 -911
  441. package/plugins/workflow-runner/test/runnerPreflight.test.ts +0 -436
  442. package/plugins/workflow-runner/test/skillTurnDone.test.ts +0 -71
  443. package/plugins/workflow-runner/test/stateLifecycle.test.ts +0 -198
  444. package/plugins/workflow-runner/test/stepPipeline.test.ts +0 -114
  445. package/plugins/workflow-runner/test/taskArbitration.test.ts +0 -354
  446. package/plugins/workflow-runner/test/taskLifecycle.test.ts +0 -324
  447. package/plugins/workflow-runner/test/toolArtifactOverwrite.test.ts +0 -221
  448. package/plugins/workflow-runner/test/toolCapabilityBoundary.test.ts +0 -29
  449. package/plugins/workflow-runner/test/toolRuntimeIntegration.test.ts +0 -168
  450. package/plugins/workflow-runner/test/webppt.load.test.ts +0 -250
  451. package/plugins/workflow-runner/test/word.load.test.ts +0 -208
  452. package/plugins/workflow-runner/test/workflows.smoke.test.ts +0 -76
  453. package/plugins/workflow-runner/test/yamlGuardConditions.test.ts +0 -207
  454. package/src/advisorState.js +0 -22
  455. package/src/cli/configWizard.js +0 -293
  456. package/src/tools/toolProgressBridge.js +0 -48
  457. package/workflows/adaptive-research.yaml +0 -50
  458. package/workflows/book-review-short.yaml +0 -125
  459. package/workflows/e2e-write-greet.yaml +0 -31
  460. package/workflows/illustrate.yaml +0 -227
  461. package/workflows/plan.yaml +0 -470
  462. package/workflows/ppt.yaml +0 -1670
  463. package/workflows/ralph-loop.yaml +0 -201
  464. package/workflows/research.yaml +0 -873
  465. package/workflows/schema.json +0 -176
  466. package/workflows/webppt.yaml +0 -496
  467. package/workflows/wechat-reading-shots.yaml +0 -315
  468. package/workflows/word.yaml +0 -720
  469. package/workflows/youtube-shorts.yaml +0 -202
  470. /package/workflows/{research.md → research/DESIGN.md} +0 -0
@@ -1,370 +0,0 @@
1
- /**
2
- * ============================================================
3
- * test/workflows/e2e.test.ts —— /workflow 端到端测试
4
- * ------------------------------------------------------------
5
- * 从用户敲 `/workflow hello-workflow --input ...` 这一最外层入口开始,
6
- * 穿过:
7
- *
8
- * runWithPlugins
9
- * → discoverPlugins (扫到真实 workflow-runner 插件)
10
- * → resolveCommand (识别 /workflow)
11
- * → cmd.executionMode === 'workflow' 路径
12
- * → lazy import workflows/index.ts
13
- * → parseWorkflowArgs + coerceInputs
14
- * → findWorkflowByName (从 tmp/workflows/ 加载 fixture)
15
- * → runWorkflow → step executors (真实 executeTool('Write'))
16
- *
17
- * 断言:
18
- * - 整个事件序列形态合理(workflow_start → step_start/end ×N → workflow_done → turn_done)
19
- * 注:经命令路径(runWithPlugins→runWorkflowFromCommand)成功后补发通用 turn_done 收口,
20
- * 故终结事件是 turn_done(workflow_done 在其前一条);直测 runWorkflow 的 runner.test.ts 仍以 workflow_done 收尾
21
- * - 文件真的落盘到正确路径,内容正确
22
- * - 缺必填 input 时不写任何文件
23
- * - assert 失败时整个 workflow halt
24
- *
25
- * 不 mock chat / runQuery —— fixture 不依赖 LLM。
26
- * 只 mock workingDir.ts,因为其它测试文件留下的全局 mock 会污染。
27
- * ============================================================
28
- */
29
-
30
- import {
31
- afterEach,
32
- beforeEach,
33
- describe,
34
- expect,
35
- it,
36
- mock,
37
- } from 'bun:test';
38
- import {
39
- copyFileSync,
40
- existsSync,
41
- mkdirSync,
42
- mkdtempSync,
43
- readFileSync,
44
- rmSync,
45
- } from 'node:fs';
46
- import { tmpdir } from 'node:os';
47
- import { join } from 'node:path';
48
-
49
- import { _resetWorkingDir } from '../../../src/bootstrap/workingDir.js';
50
- import { _resetPluginCache } from '../../../src/plugins/commandRouter.js';
51
- import type { LoopEvent, Provider } from '../../../src/types.js';
52
- import type { PluginEvent } from '../../../src/plugins/pluginApi.js';
53
- import type { WorkflowEvent } from '../src/types.js';
54
-
55
- type WfOrLoop = LoopEvent | PluginEvent | WorkflowEvent;
56
-
57
- const FIXTURE_SRC = join(import.meta.dir, 'fixtures', 'hello-workflow.yaml');
58
-
59
- const provider: Provider = {
60
- name: 'test',
61
- baseURL: '',
62
- apiKey: '',
63
- model: 'm',
64
- contextWindow: 128000,
65
- };
66
-
67
- async function collect(
68
- gen: AsyncGenerator<WfOrLoop, void, void>,
69
- ): Promise<WfOrLoop[]> {
70
- const out: WfOrLoop[] = [];
71
- for await (const ev of gen) out.push(ev as WfOrLoop);
72
- return out;
73
- }
74
-
75
- describe('workflow E2E(/workflow → 路由 → runner → 文件落盘)', () => {
76
- let tmp: string;
77
-
78
- beforeEach(() => {
79
- tmp = mkdtempSync(join(tmpdir(), 'wf-e2e-'));
80
- mkdirSync(join(tmp, 'workflows'), { recursive: true });
81
- copyFileSync(FIXTURE_SRC, join(tmp, 'workflows', 'hello-workflow.yaml'));
82
-
83
- process.env.MINIMAL_AGENT_CWD = tmp;
84
- _resetWorkingDir();
85
- _resetPluginCache();
86
-
87
- // 抵抗其它测试文件留下的 workingDir.ts 全局 mock 污染。
88
- // 注:这一行让 getWorkingDir 跟着 tmp 走,相对路径锚点 + workflows/ 双源扫描都受益。
89
- mock.module('../../../src/bootstrap/workingDir.js', () => ({
90
- getWorkingDir: () => tmp,
91
- initWorkingDir: () => tmp,
92
- _resetWorkingDir: () => {},
93
- }));
94
- });
95
-
96
- afterEach(() => {
97
- delete process.env.MINIMAL_AGENT_CWD;
98
- _resetWorkingDir();
99
- _resetPluginCache();
100
- rmSync(tmp, { recursive: true, force: true });
101
- });
102
-
103
- async function runCmd(input: string): Promise<WfOrLoop[]> {
104
- const { runWithPlugins } = await import('../../../src/plugins/pluginRunner.js');
105
- return collect(
106
- runWithPlugins(input, { provider, history: [] }) as AsyncGenerator<WfOrLoop, void, void>,
107
- );
108
- }
109
-
110
- it('golden path:/workflow hello-workflow --input name=alice --input lang=zh 跑完且文件落盘', async () => {
111
- const events = await runCmd('/workflow hello-workflow --input name=alice --input lang=zh');
112
-
113
- // 整体形态
114
- expect(events[0]?.type).toBe('workflow_start');
115
- expect(events.some((e) => e.type === 'workflow_done')).toBe(true);
116
- // 命令路径(runWorkflowFromCommand)成功后补发通用 turn_done 作终结事件(对外协议收口),
117
- // 故 turn_done 是最后一条、workflow_done 在其前一条。直测 runWorkflow 的 runner.test.ts 仍以 workflow_done 收尾。
118
- expect(events[events.length - 1]?.type).toBe('turn_done');
119
- expect(events.some((e) => e.type === 'error')).toBe(false);
120
-
121
- // 每个 step 都跑完且 ok=true
122
- const ends = events.filter(
123
- (e): e is Extract<WorkflowEvent, { type: 'workflow_step_end' }> => e.type === 'workflow_step_end',
124
- );
125
- expect(ends.length).toBe(4);
126
- expect(ends.every((e) => e.ok)).toBe(true);
127
- expect(ends.map((e) => e.id)).toEqual([
128
- 'write_greeting',
129
- 'write_meta',
130
- 'verify_files',
131
- 'verify_capture',
132
- ]);
133
-
134
- // 文件实际写盘
135
- const helloPath = join(tmp, 'greetings', 'alice', 'hello.txt');
136
- const metaPath = join(tmp, 'greetings', 'alice', 'meta.json');
137
- expect(existsSync(helloPath)).toBe(true);
138
- expect(existsSync(metaPath)).toBe(true);
139
-
140
- // hello.txt 内容验证(${var} 插值确实工作了)
141
- expect(readFileSync(helloPath, 'utf8')).toBe('Hello, alice! (lang=zh)');
142
-
143
- // meta.json 是合法 JSON,字段对得上
144
- const meta = JSON.parse(readFileSync(metaPath, 'utf8'));
145
- expect(meta.name).toBe('alice');
146
- expect(meta.lang).toBe('zh');
147
- // length() 内置函数 + capture 链路:greeting_text="Hello, alice! (lang=zh)" → 长度 23
148
- expect(meta.greeting_length).toBe('Hello, alice! (lang=zh)'.length);
149
- });
150
-
151
- it('lang 使用默认值 en(input enum default 路径)', async () => {
152
- const events = await runCmd('/workflow hello-workflow --input name=bob');
153
- expect(events.some((e) => e.type === 'workflow_done')).toBe(true);
154
- // 命令路径(runWorkflowFromCommand)成功后补发通用 turn_done 作终结事件(对外协议收口),
155
- // 故 turn_done 是最后一条、workflow_done 在其前一条。直测 runWorkflow 的 runner.test.ts 仍以 workflow_done 收尾。
156
- expect(events[events.length - 1]?.type).toBe('turn_done');
157
- expect(readFileSync(join(tmp, 'greetings', 'bob', 'hello.txt'), 'utf8'))
158
- .toBe('Hello, bob! (lang=en)');
159
- });
160
-
161
- it('workflow_step_start 事件 index/total 单调且与 yaml 一致', async () => {
162
- const events = await runCmd('/workflow hello-workflow --input name=carol');
163
- const starts = events.filter(
164
- (e): e is Extract<WorkflowEvent, { type: 'workflow_step_start' }> => e.type === 'workflow_step_start',
165
- );
166
- expect(starts.length).toBe(4);
167
- expect(starts.map((s) => s.index)).toEqual([0, 1, 2, 3]);
168
- expect(starts.every((s) => s.total === 4)).toBe(true);
169
- expect(starts.map((s) => s.kind)).toEqual(['tool', 'tool', 'assert', 'assert']);
170
- });
171
-
172
- it('缺必填 input name → yield error,且没写任何文件', async () => {
173
- const events = await runCmd('/workflow hello-workflow');
174
- expect(events.some((e) => e.type === 'error')).toBe(true);
175
- expect(events.some((e) => e.type === 'workflow_start')).toBe(false);
176
- // tmp/greetings/ 不应被创建
177
- expect(existsSync(join(tmp, 'greetings'))).toBe(false);
178
- });
179
-
180
- it('lang 传非法值 → yield enum 校验 error,且不进入 runWorkflow', async () => {
181
- const events = await runCmd('/workflow hello-workflow --input name=dave --input lang=fr');
182
- const err = events.find(
183
- (e): e is Extract<LoopEvent, { type: 'error' }> => e.type === 'error',
184
- );
185
- expect(err).toBeDefined();
186
- expect(err!.error).toContain('lang');
187
- expect(events.some((e) => e.type === 'workflow_start')).toBe(false);
188
- });
189
-
190
- it('未知 workflow 名 → yield error,不污染文件系统', async () => {
191
- const events = await runCmd('/workflow definitely-not-exists --input name=eve');
192
- expect(events.some((e) => e.type === 'error')).toBe(true);
193
- expect(events.some((e) => e.type === 'workflow_start')).toBe(false);
194
- expect(existsSync(join(tmp, 'greetings'))).toBe(false);
195
- });
196
-
197
- it('L2:位置参数等价 --input —— /workflow hello-workflow alice 同效', async () => {
198
- const events = await runCmd('/workflow hello-workflow alice');
199
- expect(events.some((e) => e.type === 'workflow_done')).toBe(true);
200
- // 命令路径(runWorkflowFromCommand)成功后补发通用 turn_done 作终结事件(对外协议收口),
201
- // 故 turn_done 是最后一条、workflow_done 在其前一条。直测 runWorkflow 的 runner.test.ts 仍以 workflow_done 收尾。
202
- expect(events[events.length - 1]?.type).toBe('turn_done');
203
- // lang 走 default=en
204
- expect(readFileSync(join(tmp, 'greetings', 'alice', 'hello.txt'), 'utf8'))
205
- .toBe('Hello, alice! (lang=en)');
206
- });
207
-
208
- it('L2:多个位置参数按 inputs 声明顺序映射 —— alice zh → name=alice, lang=zh', async () => {
209
- const events = await runCmd('/workflow hello-workflow alice zh');
210
- expect(events.some((e) => e.type === 'workflow_done')).toBe(true);
211
- // 命令路径(runWorkflowFromCommand)成功后补发通用 turn_done 作终结事件(对外协议收口),
212
- // 故 turn_done 是最后一条、workflow_done 在其前一条。直测 runWorkflow 的 runner.test.ts 仍以 workflow_done 收尾。
213
- expect(events[events.length - 1]?.type).toBe('turn_done');
214
- expect(readFileSync(join(tmp, 'greetings', 'alice', 'hello.txt'), 'utf8'))
215
- .toBe('Hello, alice! (lang=zh)');
216
- });
217
-
218
- it('L2:.yaml / .yml 后缀自动剥离 —— hello-workflow.yaml alice 与 hello-workflow alice 等价', async () => {
219
- const events = await runCmd('/workflow hello-workflow.yaml alice');
220
- expect(events.some((e) => e.type === 'workflow_done')).toBe(true);
221
- // 命令路径(runWorkflowFromCommand)成功后补发通用 turn_done 作终结事件(对外协议收口),
222
- // 故 turn_done 是最后一条、workflow_done 在其前一条。直测 runWorkflow 的 runner.test.ts 仍以 workflow_done 收尾。
223
- expect(events[events.length - 1]?.type).toBe('turn_done');
224
- expect(existsSync(join(tmp, 'greetings', 'alice', 'hello.txt'))).toBe(true);
225
- });
226
-
227
- it('L2:--input 优先级高于位置参数 —— 同槽位的位置参数被丢弃但会 yield warning', async () => {
228
- // rawInputs={name:'bob'} (来自 --input);positional=['alice'] 对应 inputs[0]=name (已占) → 丢弃 + warn
229
- // 最终 name=bob, lang=default(en)
230
- const events = await runCmd('/workflow hello-workflow alice --input name=bob');
231
- expect(events.some((e) => e.type === 'workflow_done')).toBe(true);
232
- // 命令路径(runWorkflowFromCommand)成功后补发通用 turn_done 作终结事件(对外协议收口),
233
- // 故 turn_done 是最后一条、workflow_done 在其前一条。直测 runWorkflow 的 runner.test.ts 仍以 workflow_done 收尾。
234
- expect(events[events.length - 1]?.type).toBe('turn_done');
235
- expect(existsSync(join(tmp, 'greetings', 'bob'))).toBe(true);
236
- expect(existsSync(join(tmp, 'greetings', 'alice'))).toBe(false);
237
- expect(readFileSync(join(tmp, 'greetings', 'bob', 'hello.txt'), 'utf8'))
238
- .toBe('Hello, bob! (lang=en)');
239
-
240
- // 必须有一条 warning 提示位置参数被覆盖
241
- const warn = events.find(
242
- (e): e is { type: 'warning'; message: string } => e.type === 'warning',
243
- );
244
- expect(warn).toBeDefined();
245
- expect(warn!.message).toContain('被覆盖');
246
- expect(warn!.message).toContain('alice');
247
- expect(warn!.message).toContain('name');
248
- });
249
-
250
- it('L2:位置 + --input 混用 —— 位置填 name,--input 填 lang', async () => {
251
- // 位置 alice 填 name;--input lang=zh 填 lang(不冲突)
252
- const events = await runCmd('/workflow hello-workflow alice --input lang=zh');
253
- expect(events.some((e) => e.type === 'workflow_done')).toBe(true);
254
- // 命令路径(runWorkflowFromCommand)成功后补发通用 turn_done 作终结事件(对外协议收口),
255
- // 故 turn_done 是最后一条、workflow_done 在其前一条。直测 runWorkflow 的 runner.test.ts 仍以 workflow_done 收尾。
256
- expect(events[events.length - 1]?.type).toBe('turn_done');
257
- expect(readFileSync(join(tmp, 'greetings', 'alice', 'hello.txt'), 'utf8'))
258
- .toBe('Hello, alice! (lang=zh)');
259
- });
260
-
261
- it('L2:多余的位置参数被丢弃但会 yield warning(不影响执行)', async () => {
262
- // 第 3、4 个位置参数 extra1/extra2 没有 input 槽位 → 丢弃 + warn
263
- const events = await runCmd('/workflow hello-workflow alice zh extra1 extra2');
264
- expect(events.some((e) => e.type === 'workflow_done')).toBe(true);
265
- // 命令路径(runWorkflowFromCommand)成功后补发通用 turn_done 作终结事件(对外协议收口),
266
- // 故 turn_done 是最后一条、workflow_done 在其前一条。直测 runWorkflow 的 runner.test.ts 仍以 workflow_done 收尾。
267
- expect(events[events.length - 1]?.type).toBe('turn_done');
268
- expect(readFileSync(join(tmp, 'greetings', 'alice', 'hello.txt'), 'utf8'))
269
- .toBe('Hello, alice! (lang=zh)');
270
-
271
- // 必须有一条 warning 提示多余参数被忽略,且列出具体值
272
- const warn = events.find(
273
- (e): e is { type: 'warning'; message: string } => e.type === 'warning',
274
- );
275
- expect(warn).toBeDefined();
276
- expect(warn!.message).toContain('忽略了 2 个');
277
- expect(warn!.message).toContain('extra1');
278
- expect(warn!.message).toContain('extra2');
279
- });
280
-
281
- it('L2:位置参数刚好等于 inputs 数量 —— 无 warning', async () => {
282
- // alice zh 正好填满 name + lang,无超量、无覆盖 → 不应有 warning
283
- const events = await runCmd('/workflow hello-workflow alice zh');
284
- expect(events.some((e) => e.type === 'warning')).toBe(false);
285
- expect(events.some((e) => e.type === 'workflow_done')).toBe(true);
286
- // 命令路径(runWorkflowFromCommand)成功后补发通用 turn_done 作终结事件(对外协议收口),
287
- // 故 turn_done 是最后一条、workflow_done 在其前一条。直测 runWorkflow 的 runner.test.ts 仍以 workflow_done 收尾。
288
- expect(events[events.length - 1]?.type).toBe('turn_done');
289
- });
290
-
291
- it('/workflows 列表能看到 hello-workflow(cwd 优先双源加载)', async () => {
292
- const events = await runCmd('/workflows');
293
- const text = events
294
- .filter((e): e is Extract<LoopEvent, { type: 'text' }> => e.type === 'text')
295
- .map((e) => e.delta)
296
- .join('');
297
- expect(text).toContain('hello-workflow');
298
- });
299
- });
300
-
301
- describe('workflow E2E:assert 失败 → halt(用变体 fixture)', () => {
302
- let tmp: string;
303
-
304
- beforeEach(() => {
305
- tmp = mkdtempSync(join(tmpdir(), 'wf-e2e-fail-'));
306
- mkdirSync(join(tmp, 'workflows'), { recursive: true });
307
- // 写一个故意 assert 不通过的 yaml
308
- const failYaml = `name: assert-fail-fixture
309
- description: assert 必失败的端到端 fixture
310
- steps:
311
- - id: write_a
312
- tool: Write
313
- args:
314
- file_path: "a.txt"
315
- content: "hi"
316
- - id: bad_assert
317
- type: assert
318
- condition: '1 == 2'
319
- onFail: "故意失败"
320
- - id: should_not_run
321
- tool: Write
322
- args:
323
- file_path: "b.txt"
324
- content: "should not exist"
325
- `;
326
- require('node:fs').writeFileSync(
327
- join(tmp, 'workflows', 'assert-fail-fixture.yaml'),
328
- failYaml,
329
- 'utf8',
330
- );
331
-
332
- process.env.MINIMAL_AGENT_CWD = tmp;
333
- _resetWorkingDir();
334
- _resetPluginCache();
335
- mock.module('../../../src/bootstrap/workingDir.js', () => ({
336
- getWorkingDir: () => tmp,
337
- initWorkingDir: () => tmp,
338
- _resetWorkingDir: () => {},
339
- }));
340
- });
341
-
342
- afterEach(() => {
343
- delete process.env.MINIMAL_AGENT_CWD;
344
- _resetWorkingDir();
345
- _resetPluginCache();
346
- rmSync(tmp, { recursive: true, force: true });
347
- });
348
-
349
- it('assert 失败 → 后续 step 不执行 + yield error + 没 workflow_done', async () => {
350
- const { runWithPlugins } = await import('../../../src/plugins/pluginRunner.js');
351
- const events = await collect(
352
- runWithPlugins('/workflow assert-fail-fixture', { provider, history: [] }),
353
- );
354
-
355
- expect(events.some((e) => e.type === 'workflow_done')).toBe(false);
356
- expect(events.some((e) => e.type === 'error')).toBe(true);
357
-
358
- // a.txt 在 assert 前就写盘,应存在
359
- expect(existsSync(join(tmp, 'a.txt'))).toBe(true);
360
- // b.txt 在 assert 后,不应被写
361
- expect(existsSync(join(tmp, 'b.txt'))).toBe(false);
362
-
363
- // 错误信息含 onFail 自定义文案
364
- const errs = events
365
- .filter((e): e is Extract<LoopEvent, { type: 'error' }> => e.type === 'error')
366
- .map((e) => e.error)
367
- .join('\n');
368
- expect(errs).toContain('故意失败');
369
- });
370
- });
@@ -1,314 +0,0 @@
1
- /**
2
- * 端到端验证 Phase 3:session 化状态目录布局(<wfDir>/<sessionId>/)
3
- * 在真实 runWorkflow 下的完整行为:fresh → 同 goal completed →
4
- * 不同 goal new-task + 归档 → 旧布局兼容 → 多 session 并行隔离。
5
- *
6
- * 复用 e2e.test.ts 的 mock 模式(mock workingDir.ts + MINIMAL_AGENT_CWD),
7
- * 用 hello-workflow fixture(无 LLM 依赖,确定性强)。
8
- */
9
- import {
10
- afterEach,
11
- beforeEach,
12
- describe,
13
- expect,
14
- it,
15
- mock,
16
- } from 'bun:test';
17
- import {
18
- copyFileSync,
19
- existsSync,
20
- mkdirSync,
21
- mkdtempSync,
22
- readdirSync,
23
- readFileSync,
24
- rmSync,
25
- writeFileSync,
26
- } from 'node:fs';
27
- import { tmpdir } from 'node:os';
28
- import { join } from 'node:path';
29
-
30
- import { _resetWorkingDir } from '../../../src/bootstrap/workingDir.js';
31
- import { _resetPluginCache } from '../../../src/plugins/commandRouter.js';
32
- import type { Provider } from '../../../src/types.js';
33
- import type { PluginEvent } from '../../../src/plugins/pluginApi.js';
34
- import type { WorkflowEvent } from '../src/types.js';
35
-
36
- type Ev = PluginEvent | WorkflowEvent;
37
-
38
- const FIXTURE_SRC = join(import.meta.dir, 'fixtures', 'hello-workflow.yaml');
39
-
40
- const provider: Provider = {
41
- name: 'test',
42
- baseURL: '',
43
- apiKey: '',
44
- model: 'm',
45
- contextWindow: 128000,
46
- };
47
-
48
- async function collect(gen: AsyncGenerator<Ev, void, void>): Promise<Ev[]> {
49
- const out: Ev[] = [];
50
- for await (const ev of gen) out.push(ev);
51
- return out;
52
- }
53
-
54
- const SESSION_ALPHA = 'alpha';
55
- const SESSION_BETA = 'beta';
56
-
57
- describe('workflow E2E · session 化新布局(Phase 3)', () => {
58
- let tmp: string;
59
-
60
- beforeEach(() => {
61
- tmp = mkdtempSync(join(tmpdir(), 'wf-e2e-phase3-'));
62
- mkdirSync(join(tmp, 'workflows'), { recursive: true });
63
- // 拷贝 fixture 并:① 加 goal input(hash 身份的关键字段,区分任务)
64
- // ② 补静态路径 artifacts 声明 + 一个写它的 step(new-task 归档逻辑依赖声明产物;
65
- // 注意 artifacts 不支持 ${var} 插值,必须用固定路径)
66
- const raw = readFileSync(FIXTURE_SRC, 'utf8');
67
- const patched = raw
68
- .replace(
69
- 'version: "0.1"',
70
- 'version: "0.1"\n\nartifacts:\n - "greetings/output.txt"',
71
- )
72
- .replace(
73
- 'inputs:\n - name: name',
74
- 'inputs:\n - name: goal\n type: string\n required: true\n description: 任务身份\n - name: name',
75
- )
76
- // 在 verify_files 前插一个写 output.txt 的 step
77
- .replace(
78
- ' - id: verify_files',
79
- ` - id: write_output\n tool: Write\n args:\n file_path: "greetings/output.txt"\n content: "ok"\n\n - id: verify_files`,
80
- );
81
- writeFileSync(join(tmp, 'workflows', 'hello-workflow.yaml'), patched);
82
-
83
- process.env.MINIMAL_AGENT_CWD = tmp;
84
- _resetWorkingDir();
85
- _resetPluginCache();
86
- mock.module('../../../src/bootstrap/workingDir.js', () => ({
87
- getWorkingDir: () => tmp,
88
- initWorkingDir: () => tmp,
89
- _resetWorkingDir: () => {},
90
- }));
91
- });
92
-
93
- afterEach(() => {
94
- delete process.env.MINIMAL_AGENT_CWD;
95
- _resetWorkingDir();
96
- _resetPluginCache();
97
- rmSync(tmp, { recursive: true, force: true });
98
- });
99
-
100
- async function runCmd(
101
- input: string,
102
- opts: { sessionId?: string } = {},
103
- ): Promise<Ev[]> {
104
- const { runWithPlugins } = await import('../../../src/plugins/pluginRunner.js');
105
- const runtimeContext: Record<string, unknown> = {};
106
- if (opts.sessionId) runtimeContext.sessionId = opts.sessionId;
107
- return collect(runWithPlugins(input, {
108
- provider,
109
- history: [],
110
- runtimeContext: runtimeContext as any,
111
- }) as AsyncGenerator<Ev>);
112
- }
113
-
114
- function wfDir(): string {
115
- return join(tmp, '.minimal-agent-workflow', 'hello-workflow');
116
- }
117
-
118
- function sessionActive(session: string): boolean {
119
- return existsSync(join(wfDir(), session));
120
- }
121
- function sessionDone(session: string): boolean {
122
- return existsSync(join(wfDir(), `${session}.done`));
123
- }
124
- function sessionTrash(session: string): boolean {
125
- return existsSync(join(wfDir(), `${session}.trash`));
126
- }
127
-
128
- it('fresh → 真实 runWorkflow 跑完归档到 <wfDir>/<sessionId>.done/(成功路径)', async () => {
129
- await runCmd(
130
- '/workflow hello-workflow --input goal=任务A --input name=alice --input lang=en',
131
- { sessionId: SESSION_BETA },
132
- );
133
-
134
- // 跑完后状态被 archive,活动实例目录被改名 <sessionId>.done/
135
- expect(sessionActive(SESSION_BETA)).toBe(false);
136
- expect(sessionDone(SESSION_BETA)).toBe(true);
137
- // 产物实际落盘到 cwd(不是状态目录里)
138
- expect(existsSync(join(tmp, 'greetings/alice/hello.txt'))).toBe(true);
139
- // 状态目录保留了 current.json / inputs.json / progress.md 等(供后续回溯)
140
- const doneDir = join(wfDir(), `${SESSION_BETA}.done`);
141
- expect(existsSync(join(doneDir, 'current.json'))).toBe(true);
142
- });
143
-
144
- it('未指定 sessionId → 引擎自动生成唯一 session(非 default),多 session 互不覆盖', async () => {
145
- // 不传 sessionId:宿主未提供有意义 session(runtimeContext.sessionId 缺失),
146
- // 引擎应自动命名一个唯一 session(YYYYMMDD-HHmmss-xxxxxx),而非固定 'default'
147
- await runCmd(
148
- '/workflow hello-workflow --input goal=任务A --input name=alice --input lang=en',
149
- );
150
- let doneEntries = readdirSync(wfDir()).filter((n) => n.endsWith('.done'));
151
- expect(doneEntries.length).toBe(1);
152
- const autoSession = doneEntries[0].slice(0, -'.done'.length);
153
- expect(autoSession).not.toBe('default');
154
- expect(/^\d{8}-\d{6}-[0-9a-f]{6}$/.test(autoSession)).toBe(true);
155
- // 产物落盘
156
- expect(existsSync(join(tmp, 'greetings/alice/hello.txt'))).toBe(true);
157
-
158
- // 再跑一次(不同 goal):引擎自动生成第二个独立 session,各自归档互不覆盖
159
- await runCmd(
160
- '/workflow hello-workflow --input goal=任务X --input name=carol --input lang=en',
161
- );
162
- doneEntries = readdirSync(wfDir()).filter((n) => n.endsWith('.done'));
163
- expect(doneEntries.length).toBe(2);
164
- });
165
-
166
- it('fresh + 同 goal 再跑 → completed(命中 .done/ 归档,第二次不写产物)', async () => {
167
- await runCmd(
168
- '/workflow hello-workflow --input goal=任务A --input name=alice --input lang=en',
169
- { sessionId: SESSION_BETA },
170
- );
171
- expect(sessionDone(SESSION_BETA)).toBe(true);
172
-
173
- const events = await runCmd(
174
- '/workflow hello-workflow --input goal=任务A --input name=alice --input lang=en',
175
- { sessionId: SESSION_BETA },
176
- );
177
-
178
- // 第二次是 completed:.done 归档不变(同一任务已完成,不重新归档)
179
- expect(sessionActive(SESSION_BETA)).toBe(false);
180
- expect(sessionDone(SESSION_BETA)).toBe(true);
181
- // 产物保留(completed 不删)
182
- expect(existsSync(join(tmp, 'greetings/alice/hello.txt'))).toBe(true);
183
- // 事件序列表明已完成分支被命中
184
- expect(events.some((e) => e.type === 'workflow_done')).toBe(true);
185
- });
186
-
187
- it('goal A 完成 → 改 goal B(同 session 内 new-task):B 产物覆盖,A 产物归档到 .trash/<stamp>/', async () => {
188
- await runCmd(
189
- '/workflow hello-workflow --input goal=任务A --input name=alice --input lang=en',
190
- { sessionId: SESSION_BETA },
191
- );
192
- expect(sessionDone(SESSION_BETA)).toBe(true);
193
- expect(existsSync(join(tmp, 'greetings/output.txt'))).toBe(true);
194
-
195
- // 改 goal → hash 不同 → new-task(同 session 内,A 被归档后重跑 B)
196
- await runCmd(
197
- '/workflow hello-workflow --input goal=任务B --input name=bob --input lang=zh',
198
- { sessionId: SESSION_BETA },
199
- );
200
-
201
- // 最终仍是 .done(B 成功)
202
- expect(sessionActive(SESSION_BETA)).toBe(false);
203
- expect(sessionDone(SESSION_BETA)).toBe(true);
204
- // B 产物存在
205
- expect(existsSync(join(tmp, 'greetings/bob/hello.txt'))).toBe(true);
206
- // 声明产物(output.txt)被 goal B 重新生成(write_output step 又跑了一遍)
207
- expect(existsSync(join(tmp, 'greetings/output.txt'))).toBe(true);
208
- // A 的旧产物被归档到 .trash 里(goal A 的旧 output.txt)
209
- const trashDir = join(wfDir(), `${SESSION_BETA}.trash`);
210
- expect(sessionTrash(SESSION_BETA)).toBe(true);
211
- const outputInTrash = flattenDir(trashDir).some((f) =>
212
- f.endsWith('output.txt'),
213
- );
214
- expect(outputInTrash).toBe(true);
215
- });
216
-
217
- it('同 goal 两个 session → 各自独立完成(Phase 3 核心:多 session 并行隔离)', async () => {
218
- // session alpha 跑 goal=任务A
219
- await runCmd(
220
- '/workflow hello-workflow --input goal=任务A --input name=alice --input lang=en',
221
- { sessionId: SESSION_ALPHA },
222
- );
223
- // session beta 跑 goal=任务A(同 goal,不同 session)
224
- await runCmd(
225
- '/workflow hello-workflow --input goal=任务A --input name=alice --input lang=en',
226
- { sessionId: SESSION_BETA },
227
- );
228
-
229
- // 两个 session 都有自己的 .done 归档,互不干扰
230
- expect(sessionDone(SESSION_ALPHA)).toBe(true);
231
- expect(sessionDone(SESSION_BETA)).toBe(true);
232
- // 各自的 current.json 都在
233
- expect(existsSync(join(wfDir(), `${SESSION_ALPHA}.done`, 'current.json'))).toBe(true);
234
- expect(existsSync(join(wfDir(), `${SESSION_BETA}.done`, 'current.json'))).toBe(true);
235
- // 产物(共享 cwd 下)都存在
236
- expect(existsSync(join(tmp, 'greetings/alice/hello.txt'))).toBe(true);
237
- expect(existsSync(join(tmp, 'greetings/output.txt'))).toBe(true);
238
- });
239
-
240
- it('不同 session 的 new-task 互不影响:A session 跑 goalA,B session 跑 goalB 时 A 完好', async () => {
241
- // session alpha: goalA 完成
242
- await runCmd(
243
- '/workflow hello-workflow --input goal=任务A --input name=alice --input lang=en',
244
- { sessionId: SESSION_ALPHA },
245
- );
246
- expect(sessionDone(SESSION_ALPHA)).toBe(true);
247
- const alphaBefore = readFileSync(
248
- join(wfDir(), `${SESSION_ALPHA}.done`, 'current.json'),
249
- 'utf8',
250
- );
251
-
252
- // session beta: 跑 goalB(new-task,不应碰 alpha 的任何东西)
253
- await runCmd(
254
- '/workflow hello-workflow --input goal=任务B --input name=bob --input lang=zh',
255
- { sessionId: SESSION_BETA },
256
- );
257
-
258
- // alpha 的 .done 完好无损
259
- expect(sessionDone(SESSION_ALPHA)).toBe(true);
260
- const alphaAfter = readFileSync(
261
- join(wfDir(), `${SESSION_ALPHA}.done`, 'current.json'),
262
- 'utf8',
263
- );
264
- expect(alphaAfter).toBe(alphaBefore);
265
- // alpha 的产物归档(.trash)也没被 beta session 碰
266
- // beta 自己的 .done 也有了
267
- expect(sessionDone(SESSION_BETA)).toBe(true);
268
- });
269
-
270
- it('旧布局状态文件(wfDir/current.json)→ 新引擎正确识别 + 处理(兼容)', async () => {
271
- // 手写旧布局状态(status=running,未完成)
272
- mkdirSync(wfDir(), { recursive: true });
273
- writeFileSync(
274
- join(wfDir(), 'current.json'),
275
- JSON.stringify({
276
- name: 'hello-workflow',
277
- taskId: '1234567890abcdef',
278
- status: 'running',
279
- startedAt: '2026-01-01T00:00:00.000Z',
280
- artifacts: [],
281
- defFingerprint: 'legacy',
282
- }),
283
- );
284
-
285
- // 跑真实工作流:新引擎应当从旧布局读到状态,根据 hash 走对应分支
286
- const events = await runCmd(
287
- '/workflow hello-workflow --input goal=任务C --input name=carol --input lang=en',
288
- { sessionId: SESSION_BETA },
289
- );
290
-
291
- // 核心断言:新引擎成功处理(无 error),最终有归档或活动实例
292
- expect(events.filter((e) => e.type === 'error').length).toBe(0);
293
- expect(sessionDone(SESSION_BETA) || sessionActive(SESSION_BETA)).toBe(true);
294
- // carol 产物落盘
295
- expect(existsSync(join(tmp, 'greetings/carol/hello.txt'))).toBe(true);
296
- });
297
- });
298
-
299
- /** 递归列出目录下所有文件路径 */
300
- function flattenDir(dir: string): string[] {
301
- const out: string[] = [];
302
- const walk = (d: string) => {
303
- for (const e of readdirSync(d)) {
304
- const p = join(d, e);
305
- const isDir = existsSync(p) && (() => {
306
- try { readdirSync(p); return true; } catch { return false; }
307
- })();
308
- if (isDir) walk(p);
309
- else out.push(p);
310
- }
311
- };
312
- walk(dir);
313
- return out;
314
- }