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
@@ -0,0 +1,162 @@
1
+ /**
2
+ * ============================================================
3
+ * plugins/workflow-runner/src/jsonSchema.ts —— JSON Schema 子集校验
4
+ * ------------------------------------------------------------
5
+ * 为什么手写而不是引 ajv:
6
+ * ① 工作流的结构化输出契约采用可序列化的 JSON Schema 子集,便于参与 journal
7
+ * 指纹并跨 provider 使用。
8
+ * ② 校验结果要**回喂给模型做修复**,所以错误消息比规范覆盖度重要得多 ——
9
+ * 「`branches[2].score` 应为 number,实际是 string」比一句
10
+ * `must be number` 有用,而通用库的默认文案偏向后者。
11
+ * ③ 项目一贯取向:能用基本类型说清就不引第三方(见 CLAUDE.md 设计原则)。
12
+ *
13
+ * 支持的关键字:type(含数组联合)/ properties / required / items /
14
+ * enum / additionalProperties:false / minItems / maxItems / minimum / maximum /
15
+ * nullable。**不支持**的关键字一律**忽略**(宽松),不报错 —— 校验器的职责是
16
+ * 挡住畸形输出,不是当规范警察;误伤一个合法产出的代价比放过一个边角约束大。
17
+ * ============================================================
18
+ */
19
+
20
+ export interface JsonSchema {
21
+ type?: string | string[];
22
+ properties?: Record<string, JsonSchema>;
23
+ required?: string[];
24
+ items?: JsonSchema;
25
+ enum?: unknown[];
26
+ additionalProperties?: boolean | JsonSchema;
27
+ minItems?: number;
28
+ maxItems?: number;
29
+ minimum?: number;
30
+ maximum?: number;
31
+ nullable?: boolean;
32
+ [k: string]: unknown;
33
+ }
34
+
35
+ /** 校验失败的具体位置与原因(要拿去喂模型,所以必须是人话 + 路径)。 */
36
+ export interface SchemaViolation {
37
+ path: string;
38
+ message: string;
39
+ }
40
+
41
+ function typeOf(v: unknown): string {
42
+ if (v === null) return 'null';
43
+ if (Array.isArray(v)) return 'array';
44
+ if (Number.isInteger(v)) return 'integer';
45
+ return typeof v;
46
+ }
47
+
48
+ /** `integer` 也满足 `number`;其余按 typeof 对齐。 */
49
+ function typeMatches(want: string, v: unknown): boolean {
50
+ const actual = typeOf(v);
51
+ if (want === actual) return true;
52
+ if (want === 'number') return actual === 'integer' || actual === 'number';
53
+ if (want === 'integer') return actual === 'integer';
54
+ return false;
55
+ }
56
+
57
+ function describe(v: unknown): string {
58
+ const t = typeOf(v);
59
+ if (t === 'string') return `string(${JSON.stringify(String(v)).slice(0, 40)})`;
60
+ if (t === 'array') return `array(长度 ${(v as unknown[]).length})`;
61
+ if (t === 'object') return `object(键 ${Object.keys(v as object).join('/')})`;
62
+ return `${t}(${String(v)})`;
63
+ }
64
+
65
+ function walk(
66
+ value: unknown,
67
+ schema: JsonSchema,
68
+ path: string,
69
+ out: SchemaViolation[],
70
+ ): void {
71
+ if (!schema || typeof schema !== 'object') return;
72
+
73
+ if (value === null && schema.nullable === true) return;
74
+
75
+ if (schema.enum && Array.isArray(schema.enum)) {
76
+ if (!schema.enum.some((e) => e === value)) {
77
+ out.push({
78
+ path,
79
+ message: `应为 [${schema.enum.map((e) => JSON.stringify(e)).join(', ')}] 之一,实际是 ${describe(value)}`,
80
+ });
81
+ return;
82
+ }
83
+ }
84
+
85
+ if (schema.type !== undefined) {
86
+ const wants = Array.isArray(schema.type) ? schema.type : [schema.type];
87
+ if (!wants.some((w) => typeMatches(w, value))) {
88
+ out.push({
89
+ path,
90
+ message: `应为 ${wants.join(' 或 ')},实际是 ${describe(value)}`,
91
+ });
92
+ return; // 类型都不对,再查下去只会刷屏
93
+ }
94
+ }
95
+
96
+ const t = typeOf(value);
97
+
98
+ if (t === 'object') {
99
+ const obj = value as Record<string, unknown>;
100
+ for (const key of schema.required ?? []) {
101
+ if (!(key in obj)) {
102
+ out.push({ path: path ? `${path}.${key}` : key, message: '缺少必填字段' });
103
+ }
104
+ }
105
+ if (schema.properties) {
106
+ for (const [key, sub] of Object.entries(schema.properties)) {
107
+ if (key in obj) walk(obj[key], sub, path ? `${path}.${key}` : key, out);
108
+ }
109
+ if (schema.additionalProperties === false) {
110
+ for (const key of Object.keys(obj)) {
111
+ if (!(key in schema.properties)) {
112
+ out.push({
113
+ path: path ? `${path}.${key}` : key,
114
+ message: '不允许的额外字段',
115
+ });
116
+ }
117
+ }
118
+ }
119
+ }
120
+ }
121
+
122
+ if (t === 'array') {
123
+ const arr = value as unknown[];
124
+ if (typeof schema.minItems === 'number' && arr.length < schema.minItems) {
125
+ out.push({ path, message: `至少要 ${schema.minItems} 项,实际 ${arr.length} 项` });
126
+ }
127
+ if (typeof schema.maxItems === 'number' && arr.length > schema.maxItems) {
128
+ out.push({ path, message: `最多 ${schema.maxItems} 项,实际 ${arr.length} 项` });
129
+ }
130
+ if (schema.items) {
131
+ arr.forEach((el, i) => walk(el, schema.items!, `${path}[${i}]`, out));
132
+ }
133
+ }
134
+
135
+ if (t === 'number' || t === 'integer') {
136
+ const n = value as number;
137
+ if (typeof schema.minimum === 'number' && n < schema.minimum) {
138
+ out.push({ path, message: `不得小于 ${schema.minimum},实际 ${n}` });
139
+ }
140
+ if (typeof schema.maximum === 'number' && n > schema.maximum) {
141
+ out.push({ path, message: `不得大于 ${schema.maximum},实际 ${n}` });
142
+ }
143
+ }
144
+ }
145
+
146
+ /** 校验一个值。返回空数组 = 通过。 */
147
+ export function validateAgainstSchema(
148
+ value: unknown,
149
+ schema: JsonSchema,
150
+ ): SchemaViolation[] {
151
+ const out: SchemaViolation[] = [];
152
+ walk(value, schema, '', out);
153
+ return out;
154
+ }
155
+
156
+ /** 把违规列表渲染成给**模型**看的修复指令(不是给人看的报错)。 */
157
+ export function renderViolations(violations: SchemaViolation[]): string {
158
+ return violations
159
+ .slice(0, 20)
160
+ .map((v) => ` · ${v.path || '(根)'}:${v.message}`)
161
+ .join('\n');
162
+ }
@@ -0,0 +1,64 @@
1
+ /**
2
+ * ============================================================
3
+ * plugins/workflow-runner/src/moduleResolution.ts —— ESM 依赖图解析的唯一实现
4
+ * ------------------------------------------------------------
5
+ * `workflowFingerprint.ts`(指纹计算)与 `sandbox.ts`(实际执行)此前各自独立
6
+ * 实现了同一组"扫 import/解析相对模块/取裸包名"逻辑,且已经漂移出行为分歧
7
+ * (符号链接策略、`.json` 候选扩展名)。指纹计算总是先于执行
8
+ * (见 `workflowDependencies.ts::resolveWorkflowBundle`),所以漂移目前只表现
9
+ * 成"先炸在指纹这一步"而不是安全漏洞,但仍是两份本该一致的判断各自演化。
10
+ * 这里统一成一份,两处都改成从这里导入。
11
+ *
12
+ * `scriptGuard.mjs` 不从这里导入——它必须保持零依赖纯 `.mjs`(同时被 TS 侧
13
+ * `import` 和 `skills/workflow-creator/scripts/validate.mjs` 裸 `node` spawn),
14
+ * 多一个必须原样发布的 `.mjs` 文件会重演 CLAUDE.md 里
15
+ * "package.json::files 是逐后缀白名单"那类漏发布事故的风险面。它自己那份小小的
16
+ * `STATIC_IMPORT`/`packageName` 保留原样,人工与本文件保持同步。
17
+ * ============================================================
18
+ */
19
+ import { lstat } from 'node:fs/promises';
20
+ import { dirname, extname, join, resolve } from 'node:path';
21
+ /**
22
+ * 匹配静态 `import`/`export ... from '...'` 的说明符。三个捕获组
23
+ * (前缀/说明符/后缀)让 `sandbox.ts` 能就地 `.replace()` 改写裸包名为 file URL;
24
+ * `moduleImports()` 只取第二组即可。
25
+ */
26
+ export const STATIC_IMPORT = /((?:^|[;\n])\s*(?:import|export)\s+(?:[^'";]*?\s+from\s+)?['"])([^'"]+)(['"])/gm;
27
+ /** 从源码里抽出全部静态 import/export 说明符。 */
28
+ export function moduleImports(source) {
29
+ return [...source.matchAll(STATIC_IMPORT)].map((match) => match[2]);
30
+ }
31
+ /** 裸导入说明符 → 包名(`@scope/pkg/sub` → `@scope/pkg`,`pkg/sub` → `pkg`)。 */
32
+ export function packageName(specifier) {
33
+ return specifier.startsWith('@')
34
+ ? specifier.split('/').slice(0, 2).join('/')
35
+ : specifier.split('/')[0];
36
+ }
37
+ /**
38
+ * 把一个相对 import 说明符解析成真实文件路径。
39
+ *
40
+ * **拒绝符号链接**(用 `lstat` 而不是 `stat`)——采纳 `workflowFingerprint.ts`
41
+ * 对随包资源文件本来就有的安全立场;`sandbox.ts` 此前用 `stat`(跟随符号链接)
42
+ * 是漂移,不是有意选择,收紧它是严格向下兼容。
43
+ *
44
+ * **候选扩展名不含 `.json`**——不带扩展名的相对导入解析到 `.json` 在 Node 原生
45
+ * ESM 下本来就不合法(没有 import assertion 语法写不出这种导入),全部 15 个
46
+ * 真实工作流也确认没有依赖这个候选项,去掉是安全的。显式写 `./x.json` 走
47
+ * `sandbox.ts::copyModule` 里单独的 `extname === '.json'` 分支,与这里正交。
48
+ */
49
+ export async function resolveRelativeModule(from, specifier) {
50
+ const base = resolve(dirname(from), specifier);
51
+ const candidates = extname(base)
52
+ ? [base]
53
+ : [base, `${base}.mjs`, `${base}.js`, join(base, 'index.mjs'), join(base, 'index.js')];
54
+ for (const candidate of candidates) {
55
+ try {
56
+ if ((await lstat(candidate)).isFile())
57
+ return candidate;
58
+ }
59
+ catch {
60
+ // 试下一个候选
61
+ }
62
+ }
63
+ throw new Error(`无法解析工作流相对模块:${specifier}(来自 ${from})`);
64
+ }
@@ -0,0 +1,71 @@
1
+ /**
2
+ * ============================================================
3
+ * plugins/workflow-runner/src/moduleResolution.ts —— ESM 依赖图解析的唯一实现
4
+ * ------------------------------------------------------------
5
+ * `workflowFingerprint.ts`(指纹计算)与 `sandbox.ts`(实际执行)此前各自独立
6
+ * 实现了同一组"扫 import/解析相对模块/取裸包名"逻辑,且已经漂移出行为分歧
7
+ * (符号链接策略、`.json` 候选扩展名)。指纹计算总是先于执行
8
+ * (见 `workflowDependencies.ts::resolveWorkflowBundle`),所以漂移目前只表现
9
+ * 成"先炸在指纹这一步"而不是安全漏洞,但仍是两份本该一致的判断各自演化。
10
+ * 这里统一成一份,两处都改成从这里导入。
11
+ *
12
+ * `scriptGuard.mjs` 不从这里导入——它必须保持零依赖纯 `.mjs`(同时被 TS 侧
13
+ * `import` 和 `skills/workflow-creator/scripts/validate.mjs` 裸 `node` spawn),
14
+ * 多一个必须原样发布的 `.mjs` 文件会重演 CLAUDE.md 里
15
+ * "package.json::files 是逐后缀白名单"那类漏发布事故的风险面。它自己那份小小的
16
+ * `STATIC_IMPORT`/`packageName` 保留原样,人工与本文件保持同步。
17
+ * ============================================================
18
+ */
19
+
20
+ import { lstat } from 'node:fs/promises';
21
+ import { dirname, extname, join, resolve } from 'node:path';
22
+
23
+ /**
24
+ * 匹配静态 `import`/`export ... from '...'` 的说明符。三个捕获组
25
+ * (前缀/说明符/后缀)让 `sandbox.ts` 能就地 `.replace()` 改写裸包名为 file URL;
26
+ * `moduleImports()` 只取第二组即可。
27
+ */
28
+ export const STATIC_IMPORT =
29
+ /((?:^|[;\n])\s*(?:import|export)\s+(?:[^'";]*?\s+from\s+)?['"])([^'"]+)(['"])/gm;
30
+
31
+ /** 从源码里抽出全部静态 import/export 说明符。 */
32
+ export function moduleImports(source: string): string[] {
33
+ return [...source.matchAll(STATIC_IMPORT)].map((match) => match[2]!);
34
+ }
35
+
36
+ /** 裸导入说明符 → 包名(`@scope/pkg/sub` → `@scope/pkg`,`pkg/sub` → `pkg`)。 */
37
+ export function packageName(specifier: string): string {
38
+ return specifier.startsWith('@')
39
+ ? specifier.split('/').slice(0, 2).join('/')
40
+ : specifier.split('/')[0]!;
41
+ }
42
+
43
+ /**
44
+ * 把一个相对 import 说明符解析成真实文件路径。
45
+ *
46
+ * **拒绝符号链接**(用 `lstat` 而不是 `stat`)——采纳 `workflowFingerprint.ts`
47
+ * 对随包资源文件本来就有的安全立场;`sandbox.ts` 此前用 `stat`(跟随符号链接)
48
+ * 是漂移,不是有意选择,收紧它是严格向下兼容。
49
+ *
50
+ * **候选扩展名不含 `.json`**——不带扩展名的相对导入解析到 `.json` 在 Node 原生
51
+ * ESM 下本来就不合法(没有 import assertion 语法写不出这种导入),全部 15 个
52
+ * 真实工作流也确认没有依赖这个候选项,去掉是安全的。显式写 `./x.json` 走
53
+ * `sandbox.ts::copyModule` 里单独的 `extname === '.json'` 分支,与这里正交。
54
+ */
55
+ export async function resolveRelativeModule(
56
+ from: string,
57
+ specifier: string,
58
+ ): Promise<string> {
59
+ const base = resolve(dirname(from), specifier);
60
+ const candidates = extname(base)
61
+ ? [base]
62
+ : [base, `${base}.mjs`, `${base}.js`, join(base, 'index.mjs'), join(base, 'index.js')];
63
+ for (const candidate of candidates) {
64
+ try {
65
+ if ((await lstat(candidate)).isFile()) return candidate;
66
+ } catch {
67
+ // 试下一个候选
68
+ }
69
+ }
70
+ throw new Error(`无法解析工作流相对模块:${specifier}(来自 ${from})`);
71
+ }
@@ -0,0 +1,220 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { createReadStream } from 'node:fs';
3
+ import { chmod, copyFile, mkdir, readdir, readlink, stat, } from 'node:fs/promises';
4
+ import { homedir } from 'node:os';
5
+ import { basename, join, resolve } from 'node:path';
6
+ import { agentStateDir } from '../../../src/context/agentHome.js';
7
+ const MIME_BY_EXT = {
8
+ '.jpg': 'image/jpeg',
9
+ '.jpeg': 'image/jpeg',
10
+ '.png': 'image/png',
11
+ '.webp': 'image/webp',
12
+ '.heic': 'image/heic',
13
+ '.heif': 'image/heif',
14
+ '.gif': 'image/gif',
15
+ '.bmp': 'image/bmp',
16
+ '.svg': 'image/svg+xml',
17
+ '.pdf': 'application/pdf',
18
+ '.doc': 'application/msword',
19
+ '.docx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
20
+ '.xls': 'application/vnd.ms-excel',
21
+ '.xlsx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
22
+ '.ppt': 'application/vnd.ms-powerpoint',
23
+ '.pptx': 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
24
+ '.zip': 'application/zip',
25
+ '.txt': 'text/plain',
26
+ '.md': 'text/markdown',
27
+ '.csv': 'text/csv',
28
+ '.json': 'application/json',
29
+ '.mp3': 'audio/mpeg',
30
+ '.wav': 'audio/wav',
31
+ '.m4a': 'audio/mp4',
32
+ '.mp4': 'video/mp4',
33
+ '.mov': 'video/quicktime',
34
+ '.mkv': 'video/x-matroska',
35
+ };
36
+ function mimeForPath(path) {
37
+ const match = /\.[^.]+$/.exec(path.toLowerCase());
38
+ return (match && MIME_BY_EXT[match[0]]) || 'application/octet-stream';
39
+ }
40
+ function mimeMatches(mime, accepted) {
41
+ const a = accepted.toLowerCase();
42
+ return a.endsWith('/*')
43
+ ? mime.toLowerCase().startsWith(a.slice(0, -1))
44
+ : mime.toLowerCase() === a;
45
+ }
46
+ function compatible(resource, def) {
47
+ if (resource.kind === 'directory' && def.allowDirectory === false)
48
+ return false;
49
+ if (resource.kind === 'file' && def.allowFile === false)
50
+ return false;
51
+ if (def.accepts?.length &&
52
+ resource.kind === 'file' &&
53
+ !def.accepts.some((a) => {
54
+ const accepted = a.toLowerCase();
55
+ const ext = resource.name.toLowerCase().match(/\.[^.]+$/)?.[0];
56
+ return mimeMatches(resource.mime, accepted) || accepted === ext;
57
+ }))
58
+ return false;
59
+ return true;
60
+ }
61
+ function resourceId(path) {
62
+ return `path-${createHash('sha256').update(resolve(path)).digest('hex').slice(0, 24)}`;
63
+ }
64
+ async function contentHash(path) {
65
+ const hash = createHash('sha256');
66
+ for await (const chunk of createReadStream(path))
67
+ hash.update(chunk);
68
+ return hash.digest('hex');
69
+ }
70
+ async function directoryContentHash(root) {
71
+ const hash = createHash('sha256');
72
+ const visit = async (dir, prefix) => {
73
+ const entries = await readdir(dir, { withFileTypes: true });
74
+ entries.sort((a, b) => (a.name < b.name ? -1 : a.name > b.name ? 1 : 0));
75
+ for (const entry of entries) {
76
+ const relative = prefix ? `${prefix}/${entry.name}` : entry.name;
77
+ const fullPath = join(dir, entry.name);
78
+ if (entry.isDirectory()) {
79
+ hash.update(`d\0${relative}\0`);
80
+ await visit(fullPath, relative);
81
+ }
82
+ else if (entry.isFile()) {
83
+ hash.update(`f\0${relative}\0${await contentHash(fullPath)}\0`);
84
+ }
85
+ else if (entry.isSymbolicLink()) {
86
+ hash.update(`l\0${relative}\0${await readlink(fullPath)}\0`);
87
+ }
88
+ else {
89
+ // Keep uncommon filesystem entries deterministic without opening them.
90
+ const info = await stat(fullPath);
91
+ hash.update(`o\0${relative}\0${info.mode}\0${info.size}\0`);
92
+ }
93
+ }
94
+ };
95
+ await visit(root, '');
96
+ return hash.digest('hex');
97
+ }
98
+ function safeSegment(value) {
99
+ return value.replace(/[^a-zA-Z0-9._-]/g, '_').slice(0, 120) || 'default';
100
+ }
101
+ function safeFileName(value, fallback) {
102
+ return ([...basename(value)]
103
+ .map((ch) => ch.codePointAt(0) < 32 || '<>:"|?*/\\'.includes(ch) ? '_' : ch)
104
+ .join('')
105
+ .slice(0, 180) || fallback);
106
+ }
107
+ function stagedFilePath(dir, resource, index) {
108
+ const safe = safeFileName(resource.name, `input-${index + 1}`);
109
+ return join(dir, `${String(index + 1).padStart(3, '0')}-${safe}`);
110
+ }
111
+ function resolveInputPath(value, cwd) {
112
+ if (value === '~')
113
+ return homedir();
114
+ if (value.startsWith('~/') || value.startsWith('~\\')) {
115
+ return resolve(homedir(), value.slice(2));
116
+ }
117
+ return resolve(cwd, value);
118
+ }
119
+ async function resourceFromPath(value, cwd) {
120
+ const localPath = resolveInputPath(value, cwd);
121
+ const info = await stat(localPath);
122
+ const kind = info.isDirectory() ? 'directory' : 'file';
123
+ const sha256 = kind === 'file'
124
+ ? await contentHash(localPath)
125
+ : await directoryContentHash(localPath);
126
+ return {
127
+ id: resourceId(localPath),
128
+ origin: 'path',
129
+ name: basename(localPath),
130
+ mime: kind === 'directory' ? 'inode/directory' : mimeForPath(localPath),
131
+ size: kind === 'file' ? info.size : undefined,
132
+ sha256,
133
+ localPath,
134
+ kind,
135
+ };
136
+ }
137
+ /** Stage attachment files in a deterministic, private directory for legacy path APIs. */
138
+ export async function materializeResources(workflowName, sessionId, inputName, resources) {
139
+ const fingerprint = createHash('sha256')
140
+ .update(resources
141
+ .map((r) => `${r.sha256 ?? r.id}:${r.name}:${r.size ?? ''}`)
142
+ .join('|'))
143
+ .digest('hex')
144
+ .slice(0, 24);
145
+ const dir = join(agentStateDir(), 'workflow-inputs', safeSegment(workflowName), safeSegment(sessionId), safeSegment(inputName), fingerprint);
146
+ await mkdir(dir, { recursive: true, mode: 0o700 });
147
+ for (let i = 0; i < resources.length; i++) {
148
+ const source = resources[i];
149
+ if (source.kind !== 'file')
150
+ continue;
151
+ const target = stagedFilePath(dir, source, i);
152
+ try {
153
+ await stat(target);
154
+ continue;
155
+ }
156
+ catch {
157
+ // First materialization for this content fingerprint.
158
+ }
159
+ await copyFile(source.localPath, target);
160
+ await chmod(target, 0o400);
161
+ }
162
+ return dir;
163
+ }
164
+ /** Bind explicit paths first, then compatible current-turn attachments. */
165
+ export async function bindResourceInputs(opts) {
166
+ const inputs = { ...opts.rawInputs };
167
+ const resourceMap = {};
168
+ const resourceIdentity = [];
169
+ const warnings = [];
170
+ for (const def of opts.defs ?? []) {
171
+ if (def.type !== 'resource')
172
+ continue;
173
+ const explicit = opts.rawInputs[def.name];
174
+ if (explicit?.trim()) {
175
+ const resource = await resourceFromPath(explicit, opts.cwd ?? process.cwd());
176
+ const stageAsDirectory = def.materialize === 'directory' && resource.kind === 'file';
177
+ const accepted = stageAsDirectory
178
+ ? compatible(resource, { ...def, allowFile: true })
179
+ : compatible(resource, def);
180
+ if (!accepted)
181
+ throw new Error(`input ${def.name} 的路径类型不受支持:${explicit}`);
182
+ resourceMap[def.name] = [resource];
183
+ inputs[def.name] = stageAsDirectory
184
+ ? await materializeResources(opts.workflowName, opts.sessionId, def.name, [resource])
185
+ : resource.localPath;
186
+ resourceIdentity.push(def.identity === 'reference'
187
+ ? `${def.name}:${resource.id}`
188
+ : `${def.name}:${resource.sha256 ?? resource.id}`);
189
+ continue;
190
+ }
191
+ if (!def.attachmentFallback)
192
+ continue;
193
+ const matches = (opts.attachments ?? []).filter((resource) => def.materialize === 'directory' && resource.kind === 'file'
194
+ ? compatible(resource, { ...def, allowFile: true })
195
+ : compatible(resource, def));
196
+ if (!matches.length)
197
+ continue;
198
+ if (def.maxItems !== undefined && matches.length > def.maxItems) {
199
+ throw new Error(`input ${def.name} 最多允许 ${def.maxItems} 个附件,但本轮有 ${matches.length} 个兼容附件;请减少附件或调整 maxItems`);
200
+ }
201
+ if (def.multiple !== true && matches.length > 1) {
202
+ throw new Error(`input ${def.name} 只允许一个附件,但本轮有 ${matches.length} 个兼容附件;请使用 --input ${def.name}=路径 或声明 multiple: true`);
203
+ }
204
+ resourceMap[def.name] = matches;
205
+ for (const resource of matches) {
206
+ resourceIdentity.push(def.identity === 'reference'
207
+ ? `${def.name}:${resource.id}`
208
+ : `${def.name}:${resource.sha256 ?? resource.id}`);
209
+ }
210
+ const staged = await materializeResources(opts.workflowName, opts.sessionId, def.name, matches);
211
+ // Host attachment paths can be temporary (notably team deliveries), so
212
+ // even a single file must use the stable Runner copy for journal resume.
213
+ inputs[def.name] =
214
+ matches.length === 1 && def.materialize !== 'directory'
215
+ ? stagedFilePath(staged, matches[0], 0)
216
+ : staged;
217
+ warnings.push(`已将本轮 ${matches.length} 个附件绑定到 input ${def.name}`);
218
+ }
219
+ return { inputs, resourceMap, resourceIdentity, warnings };
220
+ }