minimal-agent 0.12.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 (472) hide show
  1. package/README.md +6 -5
  2. package/package.json +62 -5
  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 +204 -185
  16. package/plugins/workflow-runner/src/index.ts +249 -224
  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 +404 -467
  28. package/plugins/workflow-runner/src/runner.ts +491 -535
  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 +172 -152
  54. package/plugins/workflow-runner/src/taskIdentity.ts +233 -200
  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 -105
  58. package/plugins/workflow-runner/src/types.ts +155 -520
  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 +542 -469
  68. package/plugins/workflow-runner/src/workflowState.ts +639 -589
  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/skill-creator/scripts/run_eval.py +3 -2
  92. package/skills/ui-design/SKILL.md +5 -2
  93. package/skills/ui-design/references/layout-composition.md +1 -1
  94. package/skills/workflow-creator/SKILL.md +344 -0
  95. package/skills/workflow-creator/assets/template/workflow.mjs +48 -0
  96. package/skills/workflow-creator/references/api.md +216 -0
  97. package/skills/workflow-creator/references/migration.md +103 -0
  98. package/skills/workflow-creator/references/patterns.md +779 -0
  99. package/skills/workflow-creator/scripts/list-resources.mjs +205 -0
  100. package/skills/workflow-creator/scripts/scaffold.mjs +148 -0
  101. package/skills/workflow-creator/scripts/validate.mjs +275 -0
  102. package/skills/workflow-creator/scripts/workflow-creator.test.mjs +82 -0
  103. package/src/advisor/advisorCoordinator.js +503 -0
  104. package/src/advisor/advisorCoordinator.ts +657 -0
  105. package/src/cli/configMenu.tsx +0 -1
  106. package/src/cli/print.js +44 -6
  107. package/src/cli/print.ts +73 -4
  108. package/src/cli/streamJson.js +5 -6
  109. package/src/cli/streamJson.ts +8 -4
  110. package/src/cli/wizards/advisorWizard.js +4 -2
  111. package/src/cli/wizards/advisorWizard.tsx +8 -2
  112. package/src/cli/wizards/contextAdvisorWizard.js +5 -4
  113. package/src/cli/wizards/contextAdvisorWizard.tsx +7 -6
  114. package/src/collaboration/taskFlow.js +115 -0
  115. package/src/collaboration/taskFlow.ts +169 -0
  116. package/src/config/configDefaults.js +41 -1
  117. package/src/config/configDefaults.ts +43 -1
  118. package/src/config/configDiagnostics.ts +2 -2
  119. package/src/config/configFile.js +40 -9
  120. package/src/config/configFile.ts +60 -11
  121. package/src/config/configService.js +443 -74
  122. package/src/config/configService.ts +723 -142
  123. package/src/config/numericLimits.js +22 -0
  124. package/src/config/numericLimits.ts +24 -0
  125. package/src/config.js +1 -0
  126. package/src/config.ts +3 -2
  127. package/src/context/budgetPlan.js +1 -1
  128. package/src/context/budgetPlan.ts +1 -1
  129. package/src/context/compact.js +7 -2
  130. package/src/context/compact.ts +9 -2
  131. package/src/context/microCompactLite.js +212 -13
  132. package/src/context/microCompactLite.ts +261 -12
  133. package/src/context/sessionRegistry.js +8 -1
  134. package/src/context/sessionRegistry.ts +18 -5
  135. package/src/context/toolResultArchive.js +72 -0
  136. package/src/context/toolResultArchive.ts +95 -0
  137. package/src/goal/errors.js +8 -0
  138. package/src/goal/errors.ts +18 -0
  139. package/src/goal/goalRuntime.js +344 -0
  140. package/src/goal/goalRuntime.ts +466 -0
  141. package/src/goal/goalStore.js +200 -0
  142. package/src/goal/goalStore.ts +219 -0
  143. package/src/goal/index.js +4 -0
  144. package/src/goal/index.ts +4 -0
  145. package/src/goal/statusMapping.js +71 -0
  146. package/src/goal/statusMapping.ts +95 -0
  147. package/src/goal/types.js +7 -0
  148. package/src/goal/types.ts +179 -0
  149. package/src/goal/workflowController.js +306 -0
  150. package/src/goal/workflowController.ts +360 -0
  151. package/src/harness/evidenceLedger.js +2 -0
  152. package/src/harness/evidenceLedger.ts +1 -0
  153. package/src/harness/stallGuard.js +9 -3
  154. package/src/harness/stallGuard.ts +7 -3
  155. package/src/images/imageResolver.js +161 -0
  156. package/src/images/imageResolver.ts +189 -0
  157. package/src/infra/verification.js +56 -20
  158. package/src/infra/verification.ts +87 -20
  159. package/src/llm/client.js +79 -21
  160. package/src/llm/client.ts +182 -35
  161. package/src/llm/gatewayClient.js +201 -0
  162. package/src/llm/gatewayClient.ts +299 -0
  163. package/src/llm/messageProvenance.js +46 -0
  164. package/src/llm/messageProvenance.ts +58 -0
  165. package/src/llm/modelProvider.js +1 -0
  166. package/src/llm/modelProvider.ts +22 -0
  167. package/src/llm/providers/anthropicFormat.js +108 -1
  168. package/src/llm/providers/anthropicFormat.ts +115 -4
  169. package/src/llm/providers/openaiFormat.js +9 -0
  170. package/src/llm/providers/openaiFormat.ts +12 -3
  171. package/src/loop.js +319 -54
  172. package/src/loop.ts +373 -57
  173. package/src/main.js +4 -1
  174. package/src/main.tsx +4 -1
  175. package/src/managedExecution/index.js +2 -0
  176. package/src/managedExecution/index.ts +2 -0
  177. package/src/managedExecution/registry.js +15 -0
  178. package/src/managedExecution/registry.ts +20 -0
  179. package/src/managedExecution/types.js +1 -0
  180. package/src/managedExecution/types.ts +86 -0
  181. package/src/modelRef.js +9 -0
  182. package/src/modelRef.ts +31 -0
  183. package/src/multimodal.js +14 -28
  184. package/src/multimodal.ts +17 -33
  185. package/src/net/lanDiscovery.js +65 -0
  186. package/src/net/lanDiscovery.ts +82 -0
  187. package/src/plugin-sdk.js +28 -3
  188. package/src/plugin-sdk.ts +39 -6
  189. package/src/plugins/pluginApi.ts +16 -1
  190. package/src/plugins/pluginLoader.js +4 -0
  191. package/src/plugins/pluginLoader.ts +6 -0
  192. package/src/plugins/pluginRunner.js +152 -9
  193. package/src/plugins/pluginRunner.ts +186 -8
  194. package/src/plugins/slashFallback.js +113 -0
  195. package/src/plugins/slashFallback.ts +137 -0
  196. package/src/prompts/policyRegistry.js +15 -8
  197. package/src/prompts/policyRegistry.ts +18 -8
  198. package/src/prompts/promptAssembly.js +103 -12
  199. package/src/prompts/promptAssembly.ts +114 -12
  200. package/src/prompts/skillList.js +21 -3
  201. package/src/prompts/skillList.ts +27 -2
  202. package/src/prompts/stableSystemPrompt.js +18 -0
  203. package/src/prompts/stableSystemPrompt.ts +33 -0
  204. package/src/runtime/agentRuntimeContext.js +8 -2
  205. package/src/runtime/agentRuntimeContext.ts +17 -4
  206. package/src/session/runAgentTurn.js +78 -12
  207. package/src/session/runAgentTurn.ts +105 -23
  208. package/src/session/runTurn.js +10 -9
  209. package/src/session/runTurn.ts +17 -8
  210. package/src/session/sessionState.ts +2 -0
  211. package/src/team/auth.js +186 -0
  212. package/src/team/auth.ts +298 -0
  213. package/src/team/cli.js +105 -0
  214. package/src/team/cli.ts +122 -0
  215. package/src/team/onlineToolContract.js +64 -0
  216. package/src/team/onlineToolContract.ts +109 -0
  217. package/src/team/toolPolicy.js +36 -0
  218. package/src/team/toolPolicy.ts +75 -0
  219. package/src/tools/advisor/advisor.js +148 -37
  220. package/src/tools/advisor/advisor.ts +161 -38
  221. package/src/tools/advisor/advisorDecision.js +71 -0
  222. package/src/tools/advisor/advisorDecision.ts +85 -0
  223. package/src/tools/agent/agent.js +18 -5
  224. package/src/tools/agent/agent.ts +21 -7
  225. package/src/tools/agent/agentControl.js +246 -0
  226. package/src/tools/agent/agentControl.ts +284 -0
  227. package/src/tools/agent/agentTaskService.js +40 -1
  228. package/src/tools/agent/agentTaskService.ts +44 -1
  229. package/src/tools/agent/agentTypes.js +14 -2
  230. package/src/tools/agent/agentTypes.ts +15 -2
  231. package/src/tools/applypatch/applyPatch.js +362 -0
  232. package/src/tools/applypatch/applyPatch.ts +428 -0
  233. package/src/tools/bash/bash.js +70 -18
  234. package/src/tools/bash/bash.ts +75 -20
  235. package/src/tools/capabilities.js +10 -5
  236. package/src/tools/capabilities.ts +10 -5
  237. package/src/tools/computeruse/computerIntent.js +32 -0
  238. package/src/tools/computeruse/computerIntent.ts +46 -0
  239. package/src/tools/computeruse/telemetryLog.js +12 -0
  240. package/src/tools/computeruse/telemetryLog.ts +16 -0
  241. package/src/tools/computeruse/vision/telemetry.js +1 -0
  242. package/src/tools/computeruse/vision/telemetry.ts +1 -0
  243. package/src/tools/effectiveToolSet.js +4 -0
  244. package/src/tools/effectiveToolSet.ts +4 -0
  245. package/src/tools/index.js +21 -2
  246. package/src/tools/index.ts +33 -2
  247. package/src/tools/powershell/powershell.js +18 -1
  248. package/src/tools/powershell/powershell.ts +18 -2
  249. package/src/tools/presentresult/presentresult.js +6 -15
  250. package/src/tools/presentresult/presentresult.ts +6 -15
  251. package/src/tools/read/read.js +69 -11
  252. package/src/tools/read/read.ts +70 -11
  253. package/src/tools/shared/fileUtils.js +1 -2
  254. package/src/tools/shared/fileUtils.ts +1 -2
  255. package/src/tools/shared/permanentDeleteGuard.js +34 -3
  256. package/src/tools/shared/permanentDeleteGuard.ts +43 -6
  257. package/src/tools/shared/toolOutputStore.js +23 -1
  258. package/src/tools/shared/toolOutputStore.ts +22 -1
  259. package/src/tools/skill/skill.js +9 -3
  260. package/src/tools/skill/skill.ts +8 -4
  261. package/src/tools/toolPromptGuides.js +117 -0
  262. package/src/tools/toolPromptGuides.ts +137 -0
  263. package/src/tools/webbrowser/agentBrowserPath.js +19 -9
  264. package/src/tools/webbrowser/agentBrowserPath.ts +70 -28
  265. package/src/tools/webbrowser/browser.js +27 -11
  266. package/src/tools/webbrowser/browser.ts +68 -24
  267. package/src/tools/webbrowser/browserAutomation.js +329 -0
  268. package/src/tools/webbrowser/browserAutomation.ts +467 -0
  269. package/src/tools/webbrowser/browserAxState.js +97 -0
  270. package/src/tools/webbrowser/browserAxState.ts +142 -0
  271. package/src/tools/webbrowser/browserBatch.js +1578 -0
  272. package/src/tools/webbrowser/browserBatch.ts +2382 -0
  273. package/src/tools/webbrowser/browserCdp.js +208 -0
  274. package/src/tools/webbrowser/browserCdp.ts +255 -0
  275. package/src/tools/webbrowser/browserConditions.js +24 -0
  276. package/src/tools/webbrowser/browserConditions.ts +45 -0
  277. package/src/tools/webbrowser/browserContent.js +281 -0
  278. package/src/tools/webbrowser/browserContent.ts +438 -0
  279. package/src/tools/webbrowser/browserControl.js +131 -30
  280. package/src/tools/webbrowser/browserControl.ts +210 -50
  281. package/src/tools/webbrowser/browserDaemon.js +22 -14
  282. package/src/tools/webbrowser/browserDaemon.ts +54 -21
  283. package/src/tools/webbrowser/browserFrames.js +47 -0
  284. package/src/tools/webbrowser/browserFrames.ts +54 -0
  285. package/src/tools/webbrowser/browserInteractionResolver.js +17 -0
  286. package/src/tools/webbrowser/browserInteractionResolver.ts +40 -0
  287. package/src/tools/webbrowser/browserLocator.js +140 -0
  288. package/src/tools/webbrowser/browserLocator.ts +194 -0
  289. package/src/tools/webbrowser/browserOutcome.js +10 -17
  290. package/src/tools/webbrowser/browserOutcome.ts +48 -31
  291. package/src/tools/webbrowser/browserRecovery.js +58 -0
  292. package/src/tools/webbrowser/browserRecovery.ts +83 -0
  293. package/src/tools/webbrowser/browserRunRegistry.js +35 -3
  294. package/src/tools/webbrowser/browserRunRegistry.ts +91 -15
  295. package/src/tools/webbrowser/browserService.js +28 -2
  296. package/src/tools/webbrowser/browserService.ts +49 -9
  297. package/src/tools/webbrowser/browserStream.js +132 -33
  298. package/src/tools/webbrowser/browserStream.ts +224 -50
  299. package/src/tools/webbrowser/browserTabs.js +48 -15
  300. package/src/tools/webbrowser/browserTabs.ts +178 -96
  301. package/src/tools/webbrowser/webbrowser.js +683 -144
  302. package/src/tools/webbrowser/webbrowser.ts +979 -236
  303. package/src/tools/webfetch/preapproved.js +0 -2
  304. package/src/tools/webfetch/preapproved.ts +0 -2
  305. package/src/tools/websearch/websearch.js +129 -8
  306. package/src/tools/websearch/websearch.ts +138 -6
  307. package/src/types.ts +450 -42
  308. package/src/ui/App.js +377 -58
  309. package/src/ui/App.tsx +576 -111
  310. package/src/ui/LiveArea.js +14 -8
  311. package/src/ui/LiveArea.tsx +14 -10
  312. package/src/ui/MessageList.js +63 -20
  313. package/src/ui/MessageList.tsx +101 -16
  314. package/src/ui/ModelPicker.js +7 -4
  315. package/src/ui/ModelPicker.tsx +55 -8
  316. package/src/ui/hooks/useChat.js +152 -163
  317. package/src/ui/hooks/useChat.ts +396 -334
  318. package/src/ui/loginCommand.js +56 -0
  319. package/src/ui/loginCommand.ts +63 -0
  320. package/src/ui/toolProgress.js +41 -0
  321. package/src/ui/toolProgress.ts +44 -0
  322. package/src/web/browserBridge.js +20 -2
  323. package/src/web/browserBridge.ts +20 -2
  324. package/src/web/protocol.ts +1897 -194
  325. package/workflows/adaptive-research/workflow.mjs +86 -0
  326. package/workflows/e2e-capabilities/workflow.mjs +102 -0
  327. package/workflows/e2e-llm/workflow.mjs +52 -0
  328. package/workflows/e2e-smoke/workflow.mjs +59 -0
  329. package/workflows/e2e-vision-schema/README.md +48 -0
  330. package/workflows/e2e-vision-schema/workflow.mjs +149 -0
  331. package/workflows/e2e-write-greet/workflow.mjs +37 -0
  332. package/workflows/file-census/README.md +14 -0
  333. package/workflows/file-census/scripts/.gitkeep +2 -0
  334. package/workflows/file-census/workflow.mjs +110 -0
  335. package/workflows/goal/README.md +166 -0
  336. package/workflows/goal/prompts/audit.md +57 -0
  337. package/workflows/goal/prompts/contract.md +56 -0
  338. package/workflows/goal/prompts/iterate.md +37 -0
  339. package/workflows/goal/workflow.mjs +501 -0
  340. package/workflows/illustrate/README.md +90 -0
  341. package/workflows/illustrate/assets/engines.json +20 -0
  342. package/workflows/illustrate/assets/extract-baidu.js +21 -0
  343. package/workflows/illustrate/assets/extract-bing.js +33 -0
  344. package/workflows/illustrate/assets/extract-google.js +31 -0
  345. package/workflows/illustrate/workflow.mjs +301 -0
  346. package/workflows/plan/workflow.mjs +389 -0
  347. package/workflows/question-crops/README.md +35 -0
  348. package/workflows/question-crops/prompts/inventory.md +23 -0
  349. package/workflows/question-crops/scripts/image-ops.mjs +305 -0
  350. package/workflows/question-crops/scripts/image-ops.test.mjs +95 -0
  351. package/workflows/question-crops/workflow.mjs +172 -0
  352. package/workflows/ralph-loop/workflow.mjs +162 -0
  353. package/workflows/research/DESIGN.md +449 -0
  354. package/workflows/research/README.md +74 -0
  355. package/workflows/research/prompts/s0-goal.md +43 -0
  356. package/workflows/research/prompts/s1-early-exit.md +22 -0
  357. package/workflows/research/prompts/s1-map.md +58 -0
  358. package/workflows/research/prompts/s2-options.md +53 -0
  359. package/workflows/research/prompts/s3-deep-dive.md +56 -0
  360. package/workflows/research/prompts/s4-verify.md +74 -0
  361. package/workflows/research/prompts/s5-synthesis.md +81 -0
  362. package/workflows/research/prompts/s5b-fill-gaps.md +32 -0
  363. package/workflows/research/prompts/s6-package.md +32 -0
  364. package/workflows/research/scripts/build-report.mjs +98 -0
  365. package/workflows/research/workflow.mjs +288 -0
  366. package/workflows/wechat-reading-shots/prompts/collect-params.md +16 -0
  367. package/workflows/wechat-reading-shots/prompts/evaluate.md +20 -0
  368. package/workflows/wechat-reading-shots/prompts/open-book.md +28 -0
  369. package/workflows/wechat-reading-shots/prompts/read-page.md +13 -0
  370. package/workflows/wechat-reading-shots/prompts/turn-batch.md +24 -0
  371. package/workflows/wechat-reading-shots/test/control-flow.test.ts +329 -0
  372. package/workflows/wechat-reading-shots/workflow.mjs +266 -0
  373. package/workflows/wrong-question-docx/README.md +55 -0
  374. package/workflows/wrong-question-docx/prompts/figure-qa.md +8 -0
  375. package/workflows/wrong-question-docx/prompts/transcribe.md +25 -0
  376. package/workflows/wrong-question-docx/scripts/workbook.mjs +857 -0
  377. package/workflows/wrong-question-docx/test/control-flow.test.ts +165 -0
  378. package/workflows/wrong-question-docx/test/workbook.test.mjs +303 -0
  379. package/workflows/wrong-question-docx/workflow.mjs +485 -0
  380. package/plugins/workflow-runner/src/agentCommon.js +0 -354
  381. package/plugins/workflow-runner/src/agentCommon.ts +0 -435
  382. package/plugins/workflow-runner/src/controlFlow/branch.js +0 -40
  383. package/plugins/workflow-runner/src/controlFlow/branch.ts +0 -46
  384. package/plugins/workflow-runner/src/controlFlow/loop.js +0 -211
  385. package/plugins/workflow-runner/src/controlFlow/loop.ts +0 -248
  386. package/plugins/workflow-runner/src/controlFlow/pause.js +0 -129
  387. package/plugins/workflow-runner/src/controlFlow/pause.ts +0 -141
  388. package/plugins/workflow-runner/src/controlFlow/signal.js +0 -21
  389. package/plugins/workflow-runner/src/controlFlow/signal.ts +0 -29
  390. package/plugins/workflow-runner/src/controlFlow/types.js +0 -18
  391. package/plugins/workflow-runner/src/controlFlow/types.ts +0 -63
  392. package/plugins/workflow-runner/src/dslManifest.js +0 -72
  393. package/plugins/workflow-runner/src/dslManifest.ts +0 -127
  394. package/plugins/workflow-runner/src/expressions.js +0 -618
  395. package/plugins/workflow-runner/src/expressions.ts +0 -622
  396. package/plugins/workflow-runner/src/loader.js +0 -573
  397. package/plugins/workflow-runner/src/loader.ts +0 -721
  398. package/plugins/workflow-runner/src/multimodal.js +0 -38
  399. package/plugins/workflow-runner/src/multimodal.ts +0 -64
  400. package/plugins/workflow-runner/src/recovery.js +0 -119
  401. package/plugins/workflow-runner/src/recovery.ts +0 -149
  402. package/plugins/workflow-runner/src/stepExecutors/agent.js +0 -173
  403. package/plugins/workflow-runner/src/stepExecutors/agent.ts +0 -234
  404. package/plugins/workflow-runner/src/stepExecutors/assert.js +0 -41
  405. package/plugins/workflow-runner/src/stepExecutors/assert.ts +0 -50
  406. package/plugins/workflow-runner/src/stepExecutors/echo.js +0 -31
  407. package/plugins/workflow-runner/src/stepExecutors/echo.ts +0 -38
  408. package/plugins/workflow-runner/src/stepExecutors/llm.js +0 -99
  409. package/plugins/workflow-runner/src/stepExecutors/llm.ts +0 -133
  410. package/plugins/workflow-runner/src/stepExecutors/set.js +0 -49
  411. package/plugins/workflow-runner/src/stepExecutors/set.ts +0 -56
  412. package/plugins/workflow-runner/src/stepExecutors/skill.js +0 -111
  413. package/plugins/workflow-runner/src/stepExecutors/skill.ts +0 -140
  414. package/plugins/workflow-runner/src/stepExecutors/tool.js +0 -208
  415. package/plugins/workflow-runner/src/stepExecutors/tool.ts +0 -256
  416. package/plugins/workflow-runner/src/stepExecutors/verify.js +0 -58
  417. package/plugins/workflow-runner/src/stepExecutors/verify.ts +0 -68
  418. package/plugins/workflow-runner/src/stepPipeline.js +0 -277
  419. package/plugins/workflow-runner/src/stepPipeline.ts +0 -366
  420. package/plugins/workflow-runner/test/agent.test.ts +0 -587
  421. package/plugins/workflow-runner/test/agentLlmError.test.ts +0 -373
  422. package/plugins/workflow-runner/test/bashBlacklist.sweep.test.ts +0 -65
  423. package/plugins/workflow-runner/test/captureMisbind.test.ts +0 -99
  424. package/plugins/workflow-runner/test/cli.e2e.test.ts +0 -147
  425. package/plugins/workflow-runner/test/context-files.test.ts +0 -320
  426. package/plugins/workflow-runner/test/e2e.test.ts +0 -370
  427. package/plugins/workflow-runner/test/engineRobustness.test.ts +0 -226
  428. package/plugins/workflow-runner/test/expressions.test.ts +0 -397
  429. package/plugins/workflow-runner/test/foundation.test.ts +0 -126
  430. package/plugins/workflow-runner/test/graceful.test.ts +0 -139
  431. package/plugins/workflow-runner/test/greedyInputs.load.test.ts +0 -47
  432. package/plugins/workflow-runner/test/hostCapability.test.ts +0 -108
  433. package/plugins/workflow-runner/test/illustrate.load.test.ts +0 -183
  434. package/plugins/workflow-runner/test/jsonPayload.test.ts +0 -83
  435. package/plugins/workflow-runner/test/loader.test.ts +0 -617
  436. package/plugins/workflow-runner/test/maxTurnsRetryDelay.test.ts +0 -33
  437. package/plugins/workflow-runner/test/multimodal.test.ts +0 -342
  438. package/plugins/workflow-runner/test/output-schema.test.ts +0 -213
  439. package/plugins/workflow-runner/test/parseWorkflowArgs.test.ts +0 -87
  440. package/plugins/workflow-runner/test/pluginRunner.isolation.test.ts +0 -269
  441. package/plugins/workflow-runner/test/ppt.load.test.ts +0 -1220
  442. package/plugins/workflow-runner/test/ralphLoop.e2e.test.ts +0 -220
  443. package/plugins/workflow-runner/test/recovery.test.ts +0 -265
  444. package/plugins/workflow-runner/test/runner.test.ts +0 -911
  445. package/plugins/workflow-runner/test/runnerPreflight.test.ts +0 -379
  446. package/plugins/workflow-runner/test/skillTurnDone.test.ts +0 -71
  447. package/plugins/workflow-runner/test/stateLifecycle.test.ts +0 -150
  448. package/plugins/workflow-runner/test/stepPipeline.test.ts +0 -114
  449. package/plugins/workflow-runner/test/taskArbitration.test.ts +0 -338
  450. package/plugins/workflow-runner/test/taskLifecycle.test.ts +0 -270
  451. package/plugins/workflow-runner/test/toolArtifactOverwrite.test.ts +0 -221
  452. package/plugins/workflow-runner/test/toolCapabilityBoundary.test.ts +0 -29
  453. package/plugins/workflow-runner/test/toolRuntimeIntegration.test.ts +0 -168
  454. package/plugins/workflow-runner/test/webppt.load.test.ts +0 -250
  455. package/plugins/workflow-runner/test/word.load.test.ts +0 -208
  456. package/plugins/workflow-runner/test/workflows.smoke.test.ts +0 -76
  457. package/plugins/workflow-runner/test/yamlGuardConditions.test.ts +0 -207
  458. package/src/advisorState.js +0 -22
  459. package/src/cli/configWizard.js +0 -293
  460. package/src/tools/toolProgressBridge.js +0 -48
  461. package/workflows/adaptive-research.yaml +0 -50
  462. package/workflows/book-review-short.yaml +0 -125
  463. package/workflows/e2e-write-greet.yaml +0 -31
  464. package/workflows/illustrate.yaml +0 -227
  465. package/workflows/plan.yaml +0 -470
  466. package/workflows/ppt.yaml +0 -1670
  467. package/workflows/ralph-loop.yaml +0 -199
  468. package/workflows/schema.json +0 -176
  469. package/workflows/webppt.yaml +0 -496
  470. package/workflows/wechat-reading-shots.yaml +0 -315
  471. package/workflows/word.yaml +0 -720
  472. package/workflows/youtube-shorts.yaml +0 -202
@@ -15,7 +15,7 @@ import { chmod, mkdir, readdir, realpath, rm, stat } from 'node:fs/promises';
15
15
  import os from 'node:os';
16
16
  import path from 'node:path';
17
17
  import { sanitizeCredentialEnv } from '../../config/configService.js';
18
- import { pathContains, pathContainedByAny } from '../../utils/pathContains.js';
18
+ import { pathContainedByAny, pathContains } from '../../utils/pathContains.js';
19
19
  /**
20
20
  * minimal-agent 进程级固定 session 名:隔离机器上其它 agent-browser 用法,
21
21
  * 同时让本进程多次调用复用同一浏览器(与原 playwright「一 session 一 page」语义一致)。
@@ -38,7 +38,11 @@ export async function ensureBrowserProfile(profileId = 'default') {
38
38
  return profile;
39
39
  }
40
40
  export async function browserGlobalArgs(sessionName = BROWSER_SESSION, profileId = 'default') {
41
- return [...sessionArgs(sessionName), '--profile', await ensureBrowserProfile(profileId)];
41
+ return [
42
+ ...sessionArgs(sessionName),
43
+ '--profile',
44
+ await ensureBrowserProfile(profileId),
45
+ ];
42
46
  }
43
47
  /**
44
48
  * 默认 spawn 运行器:收集 stdout/stderr 后结算;spawn 抛错也 resolve 成失败。
@@ -83,13 +87,21 @@ export const spawnRunner = (bin, args, signal) => new Promise((resolveP) => {
83
87
  });
84
88
  }
85
89
  catch (e) {
86
- resolveP({ code: -1, stdout: '', stderr: e instanceof Error ? e.message : String(e) });
90
+ resolveP({
91
+ code: -1,
92
+ stdout: '',
93
+ stderr: e instanceof Error ? e.message : String(e),
94
+ });
87
95
  return;
88
96
  }
89
97
  child.stdout?.setEncoding('utf8');
90
- child.stdout?.on('data', (c) => (stdout += c));
98
+ child.stdout?.on('data', (c) => {
99
+ stdout += c;
100
+ });
91
101
  child.stderr?.setEncoding('utf8');
92
- child.stderr?.on('data', (c) => (stderr += c));
102
+ child.stderr?.on('data', (c) => {
103
+ stderr += c;
104
+ });
93
105
  child.on('error', (e) => finish(-1, e instanceof Error ? e.message : String(e)));
94
106
  // 正常路径:'close' 紧随 'exit'(pipe 关闭)→ 以完整输出立即结算,并清掉宽限计时器。
95
107
  child.on('close', (code) => finish(code));
@@ -169,10 +181,14 @@ async function pruneStaleArtifacts(dir) {
169
181
  if (info.mtimeMs < cutoff)
170
182
  await rm(target, { force: true, recursive: true });
171
183
  }
172
- catch { /* 单个文件清不掉不影响其它 */ }
184
+ catch {
185
+ /* 单个文件清不掉不影响其它 */
186
+ }
173
187
  }));
174
188
  }
175
- catch { /* 目录不存在或不可读:没什么可清的 */ }
189
+ catch {
190
+ /* 目录不存在或不可读:没什么可清的 */
191
+ }
176
192
  }
177
193
  /**
178
194
  * 生成一个托管的产物输出路径,并确保目录存在、旧产物已清理。
@@ -216,7 +232,9 @@ const ALLOWED_URL_SCHEMES = new Set(['http', 'https', 'about', 'file']);
216
232
  * 而不是替调用方创建——凭一个路径参数就造目录树同样是越权。
217
233
  */
218
234
  export async function validateArtifactOutputPath(candidate, allowedRoots) {
219
- const absolute = path.isAbsolute(candidate) ? candidate : path.resolve(candidate);
235
+ const absolute = path.isAbsolute(candidate)
236
+ ? candidate
237
+ : path.resolve(candidate);
220
238
  const parent = path.dirname(absolute);
221
239
  let realParent;
222
240
  try {
@@ -236,9 +254,7 @@ export async function validateArtifactOutputPath(candidate, allowedRoots) {
236
254
  if (!pathContainedByAny(roots, realParent)) {
237
255
  return {
238
256
  ok: false,
239
- error: `输出路径超出允许范围:${absolute}\n`
240
- + `允许写入:${roots.join('、')}\n`
241
- + '省略 path 参数即可写到托管的临时目录。',
257
+ error: `输出路径超出允许范围:${absolute}\n允许写入:${roots.join('、')}\n省略 path 参数即可写到托管的临时目录。`,
242
258
  };
243
259
  }
244
260
  const managed = await realpath(browserArtifactDir()).catch(() => browserArtifactDir());
@@ -17,7 +17,7 @@ import os from 'node:os';
17
17
  import path from 'node:path';
18
18
 
19
19
  import { sanitizeCredentialEnv } from '../../config/configService.js';
20
- import { pathContains, pathContainedByAny } from '../../utils/pathContains.js';
20
+ import { pathContainedByAny, pathContains } from '../../utils/pathContains.js';
21
21
 
22
22
  export interface AgentBrowserRun {
23
23
  code: number;
@@ -46,18 +46,34 @@ export function sessionArgs(sessionName = BROWSER_SESSION): string[] {
46
46
  /** KakadeAI-owned persistent browser profile. It is never the user's system Chrome profile. */
47
47
  export function browserProfilePath(profileId = 'default'): string {
48
48
  const safe = /^[a-zA-Z0-9._-]+$/.test(profileId) ? profileId : 'default';
49
- return path.join(process.env.MINIMAL_AGENT_HOME ?? os.homedir(), '.minimal-agent', 'browser', 'profiles', safe);
49
+ return path.join(
50
+ process.env.MINIMAL_AGENT_HOME ?? os.homedir(),
51
+ '.minimal-agent',
52
+ 'browser',
53
+ 'profiles',
54
+ safe,
55
+ );
50
56
  }
51
57
 
52
- export async function ensureBrowserProfile(profileId = 'default'): Promise<string> {
58
+ export async function ensureBrowserProfile(
59
+ profileId = 'default',
60
+ ): Promise<string> {
53
61
  const profile = browserProfilePath(profileId);
54
62
  await mkdir(profile, { recursive: true, mode: 0o700 });
55
- if (process.platform !== 'win32') await chmod(profile, 0o700).catch(() => undefined);
63
+ if (process.platform !== 'win32')
64
+ await chmod(profile, 0o700).catch(() => undefined);
56
65
  return profile;
57
66
  }
58
67
 
59
- export async function browserGlobalArgs(sessionName = BROWSER_SESSION, profileId = 'default'): Promise<string[]> {
60
- return [...sessionArgs(sessionName), '--profile', await ensureBrowserProfile(profileId)];
68
+ export async function browserGlobalArgs(
69
+ sessionName = BROWSER_SESSION,
70
+ profileId = 'default',
71
+ ): Promise<string[]> {
72
+ return [
73
+ ...sessionArgs(sessionName),
74
+ '--profile',
75
+ await ensureBrowserProfile(profileId),
76
+ ];
61
77
  }
62
78
 
63
79
  /**
@@ -83,8 +99,12 @@ export const spawnRunner: AgentBrowserRunner = (bin, args, signal) =>
83
99
  settled = true;
84
100
  if (graceTimer) clearTimeout(graceTimer);
85
101
  // 主动释放父侧 pipe 读端(daemon 攥着写端、我们已拿到结果,不再依赖它关闭)。
86
- try { child?.stdout?.destroy(); } catch {}
87
- try { child?.stderr?.destroy(); } catch {}
102
+ try {
103
+ child?.stdout?.destroy();
104
+ } catch {}
105
+ try {
106
+ child?.stderr?.destroy();
107
+ } catch {}
88
108
  resolveP({ code: code ?? -1, stdout, stderr: stderr || errMsg || '' });
89
109
  };
90
110
  try {
@@ -95,14 +115,24 @@ export const spawnRunner: AgentBrowserRunner = (bin, args, signal) =>
95
115
  signal,
96
116
  });
97
117
  } catch (e) {
98
- resolveP({ code: -1, stdout: '', stderr: e instanceof Error ? e.message : String(e) });
118
+ resolveP({
119
+ code: -1,
120
+ stdout: '',
121
+ stderr: e instanceof Error ? e.message : String(e),
122
+ });
99
123
  return;
100
124
  }
101
125
  child.stdout?.setEncoding('utf8');
102
- child.stdout?.on('data', (c) => (stdout += c));
126
+ child.stdout?.on('data', (c) => {
127
+ stdout += c;
128
+ });
103
129
  child.stderr?.setEncoding('utf8');
104
- child.stderr?.on('data', (c) => (stderr += c));
105
- child.on('error', (e) => finish(-1, e instanceof Error ? e.message : String(e)));
130
+ child.stderr?.on('data', (c) => {
131
+ stderr += c;
132
+ });
133
+ child.on('error', (e) =>
134
+ finish(-1, e instanceof Error ? e.message : String(e)),
135
+ );
106
136
  // 正常路径:'close' 紧随 'exit'(pipe 关闭)→ 以完整输出立即结算,并清掉宽限计时器。
107
137
  child.on('close', (code) => finish(code));
108
138
  // 拉 daemon 的命令:daemon 继承 pipe → 'close' 永不来。以 'exit' 为准,给一小段宽限等 'close'
@@ -184,11 +214,16 @@ async function pruneStaleArtifacts(dir: string): Promise<void> {
184
214
  const target = path.join(dir, name);
185
215
  try {
186
216
  const info = await stat(target);
187
- if (info.mtimeMs < cutoff) await rm(target, { force: true, recursive: true });
188
- } catch { /* 单个文件清不掉不影响其它 */ }
217
+ if (info.mtimeMs < cutoff)
218
+ await rm(target, { force: true, recursive: true });
219
+ } catch {
220
+ /* 单个文件清不掉不影响其它 */
221
+ }
189
222
  }),
190
223
  );
191
- } catch { /* 目录不存在或不可读:没什么可清的 */ }
224
+ } catch {
225
+ /* 目录不存在或不可读:没什么可清的 */
226
+ }
192
227
  }
193
228
 
194
229
  /**
@@ -197,10 +232,14 @@ async function pruneStaleArtifacts(dir: string): Promise<void> {
197
232
  * 文件名带 pid + 随机数:`Date.now()` 单独用会在同一毫秒内两次调用时撞名
198
233
  * (两个并发截图互相覆盖,症状是「截出来的图不是那一刻的画面」)。
199
234
  */
200
- export async function createArtifactPath(prefix = 'browser', ext = 'png'): Promise<string> {
235
+ export async function createArtifactPath(
236
+ prefix = 'browser',
237
+ ext = 'png',
238
+ ): Promise<string> {
201
239
  const dir = browserArtifactDir();
202
240
  await mkdir(dir, { recursive: true, mode: 0o700 });
203
- if (process.platform !== 'win32') await chmod(dir, 0o700).catch(() => undefined);
241
+ if (process.platform !== 'win32')
242
+ await chmod(dir, 0o700).catch(() => undefined);
204
243
  await pruneStaleArtifacts(dir);
205
244
  const unique = `${Date.now()}-${process.pid}-${randomUUID().slice(0, 8)}`;
206
245
  return path.join(dir, `${prefix}-${unique}.${ext}`);
@@ -237,7 +276,9 @@ export async function validateArtifactOutputPath(
237
276
  candidate: string,
238
277
  allowedRoots: string[],
239
278
  ): Promise<{ ok: true; path: string } | { ok: false; error: string }> {
240
- const absolute = path.isAbsolute(candidate) ? candidate : path.resolve(candidate);
279
+ const absolute = path.isAbsolute(candidate)
280
+ ? candidate
281
+ : path.resolve(candidate);
241
282
  const parent = path.dirname(absolute);
242
283
  let realParent: string;
243
284
  try {
@@ -247,19 +288,22 @@ export async function validateArtifactOutputPath(
247
288
  }
248
289
  const roots = await Promise.all(
249
290
  allowedRoots.map(async (root) => {
250
- try { return await realpath(root); } catch { return path.resolve(root); }
291
+ try {
292
+ return await realpath(root);
293
+ } catch {
294
+ return path.resolve(root);
295
+ }
251
296
  }),
252
297
  );
253
298
  if (!pathContainedByAny(roots, realParent)) {
254
299
  return {
255
300
  ok: false,
256
- error:
257
- `输出路径超出允许范围:${absolute}\n`
258
- + `允许写入:${roots.join('、')}\n`
259
- + '省略 path 参数即可写到托管的临时目录。',
301
+ error: `输出路径超出允许范围:${absolute}\n允许写入:${roots.join('、')}\n省略 path 参数即可写到托管的临时目录。`,
260
302
  };
261
303
  }
262
- const managed = await realpath(browserArtifactDir()).catch(() => browserArtifactDir());
304
+ const managed = await realpath(browserArtifactDir()).catch(() =>
305
+ browserArtifactDir(),
306
+ );
263
307
  if (!pathContains(managed, realParent)) {
264
308
  const exists = await stat(path.join(realParent, path.basename(absolute)))
265
309
  .then(() => true)
@@ -0,0 +1,329 @@
1
+ /**
2
+ * Persistent CDP transport used by BrowserBatch and BrowserCDP.
3
+ *
4
+ * The browser daemon is deliberately still owned by agent-browser; this module
5
+ * only replaces the short lived command clients used for each automation step.
6
+ */
7
+ import { mkdir, stat } from 'node:fs/promises';
8
+ import os from 'node:os';
9
+ import path from 'node:path';
10
+ import { sessionArgs } from './browser.js';
11
+ import { ensureDaemon } from './browserDaemon.js';
12
+ export const BROWSER_TAB_MARKER_KEY = '__minimalAgentTabMarker';
13
+ class CdpConnection {
14
+ url;
15
+ socket = null;
16
+ opening = null;
17
+ pageTargetId;
18
+ pageSessionId;
19
+ id = 0;
20
+ pending = new Map();
21
+ events = [];
22
+ sequence = 0;
23
+ listeners = new Set();
24
+ constructor(url) {
25
+ this.url = url;
26
+ }
27
+ /**
28
+ * A connection is page-scoped. It must not be put back in a process-wide
29
+ * pool and rebound by another conversation while this caller still holds it.
30
+ */
31
+ close() {
32
+ const socket = this.socket;
33
+ this.socket = null;
34
+ this.pageTargetId = undefined;
35
+ this.pageSessionId = undefined;
36
+ socket?.close();
37
+ }
38
+ get attachedPageSessionId() {
39
+ return this.pageSessionId;
40
+ }
41
+ get attachedPageTargetId() {
42
+ return this.pageTargetId;
43
+ }
44
+ async evaluateInFrame(frameId, expression, signal) {
45
+ const isolated = (await this.send('Page.createIsolatedWorld', {
46
+ frameId,
47
+ worldName: 'minimal-agent-browser',
48
+ grantUniveralAccess: false,
49
+ }, undefined, 30_000, signal));
50
+ if (typeof isolated.executionContextId !== 'number')
51
+ throw new Error(`无法创建 frame execution context:${frameId}`);
52
+ return this.send('Runtime.evaluate', {
53
+ expression,
54
+ contextId: isolated.executionContextId,
55
+ returnByValue: true,
56
+ awaitPromise: true,
57
+ }, undefined, 30_000, signal);
58
+ }
59
+ async frameOwnerOffset(frameId, signal) {
60
+ // CDP returns the owner quad in top-level viewport coordinates, including
61
+ // nested cross-origin frames. Do not add ancestor offsets a second time.
62
+ const owner = (await this.send('DOM.getFrameOwner', { frameId }, undefined, 30_000, signal));
63
+ if (typeof owner.backendNodeId !== 'number')
64
+ throw new Error(`无法取得 frame owner:${frameId}`);
65
+ const box = (await this.send('DOM.getBoxModel', { backendNodeId: owner.backendNodeId }, undefined, 30_000, signal));
66
+ const border = box.model?.border;
67
+ if (!Array.isArray(border) || border.length < 2)
68
+ throw new Error(`无法取得 frame owner 坐标:${frameId}`);
69
+ const numbers = border.filter((value) => typeof value === 'number');
70
+ if (numbers.length < 2)
71
+ throw new Error(`frame owner 坐标无效:${frameId}`);
72
+ return { x: numbers[0], y: numbers[1] };
73
+ }
74
+ async open() {
75
+ if (this.socket?.readyState === WebSocket.OPEN)
76
+ return;
77
+ if (this.opening)
78
+ return this.opening;
79
+ this.opening = new Promise((resolve, reject) => {
80
+ const socket = new WebSocket(this.url);
81
+ const timer = setTimeout(() => {
82
+ socket.close();
83
+ reject(new Error('CDP connection timed out'));
84
+ }, 10_000);
85
+ socket.onopen = () => {
86
+ clearTimeout(timer);
87
+ this.socket = socket;
88
+ resolve();
89
+ };
90
+ socket.onerror = () => {
91
+ clearTimeout(timer);
92
+ reject(new Error('Unable to connect to browser CDP'));
93
+ };
94
+ socket.onclose = () => {
95
+ if (this.socket === socket)
96
+ this.socket = null;
97
+ this.pageTargetId = undefined;
98
+ this.pageSessionId = undefined;
99
+ for (const [id, request] of this.pending) {
100
+ clearTimeout(request.timer);
101
+ if (request.signal && request.onAbort)
102
+ request.signal.removeEventListener('abort', request.onAbort);
103
+ request.reject(new Error('CDP connection closed'));
104
+ this.pending.delete(id);
105
+ }
106
+ };
107
+ socket.onmessage = (message) => this.onMessage(String(message.data));
108
+ }).finally(() => {
109
+ this.opening = null;
110
+ });
111
+ return this.opening;
112
+ }
113
+ onMessage(raw) {
114
+ let data;
115
+ try {
116
+ data = JSON.parse(raw);
117
+ }
118
+ catch {
119
+ return;
120
+ }
121
+ if (typeof data.id === 'number') {
122
+ const request = this.pending.get(data.id);
123
+ if (!request)
124
+ return;
125
+ this.pending.delete(data.id);
126
+ clearTimeout(request.timer);
127
+ if (request.signal && request.onAbort)
128
+ request.signal.removeEventListener('abort', request.onAbort);
129
+ if (data.error)
130
+ request.reject(new Error(JSON.stringify(data.error)));
131
+ else
132
+ request.resolve(data.result ?? {});
133
+ return;
134
+ }
135
+ if (typeof data.method !== 'string')
136
+ return;
137
+ const event = {
138
+ sequence: ++this.sequence,
139
+ method: data.method,
140
+ params: (data.params ?? {}),
141
+ sessionId: typeof data.sessionId === 'string' ? data.sessionId : undefined,
142
+ at: Date.now(),
143
+ };
144
+ if (event.method === 'Target.detachedFromTarget' &&
145
+ String(event.params.sessionId ?? '') === this.pageSessionId) {
146
+ this.pageTargetId = undefined;
147
+ this.pageSessionId = undefined;
148
+ }
149
+ if ((event.method === 'Target.targetDestroyed' ||
150
+ event.method === 'Target.targetCrashed') &&
151
+ String(event.params.targetId ?? '') === this.pageTargetId) {
152
+ this.pageTargetId = undefined;
153
+ this.pageSessionId = undefined;
154
+ }
155
+ this.events.push(event);
156
+ if (this.events.length > 500)
157
+ this.events.splice(0, this.events.length - 500);
158
+ for (const listener of this.listeners) {
159
+ try {
160
+ listener(event);
161
+ }
162
+ catch {
163
+ // One observer must not break delivery to the remaining CDP consumers.
164
+ }
165
+ }
166
+ }
167
+ async send(method, params = {}, target, timeoutMs = 30_000, signal) {
168
+ await this.open();
169
+ const socket = this.socket;
170
+ if (!socket || socket.readyState !== WebSocket.OPEN)
171
+ throw new Error('CDP connection is unavailable');
172
+ const id = ++this.id;
173
+ const pageDomain = /^(Accessibility|DOM|Input|Log|Network|Page|Performance|Runtime|Security)\./.test(method);
174
+ const effectiveTarget = target ?? (pageDomain ? this.pageSessionId : undefined);
175
+ return new Promise((resolve, reject) => {
176
+ const abortError = () => signal?.reason instanceof Error
177
+ ? signal.reason
178
+ : new Error(`CDP ${method} aborted`);
179
+ const cleanup = () => {
180
+ const request = this.pending.get(id);
181
+ if (!request)
182
+ return false;
183
+ this.pending.delete(id);
184
+ clearTimeout(request.timer);
185
+ if (request.signal && request.onAbort)
186
+ request.signal.removeEventListener('abort', request.onAbort);
187
+ return true;
188
+ };
189
+ const onAbort = () => {
190
+ if (cleanup())
191
+ reject(abortError());
192
+ };
193
+ const timer = setTimeout(() => {
194
+ if (cleanup())
195
+ reject(new Error(`CDP ${method} timed out`));
196
+ }, timeoutMs);
197
+ this.pending.set(id, { resolve, reject, timer, onAbort, signal });
198
+ if (signal?.aborted) {
199
+ onAbort();
200
+ return;
201
+ }
202
+ signal?.addEventListener('abort', onAbort, { once: true });
203
+ try {
204
+ socket.send(JSON.stringify({
205
+ id,
206
+ method,
207
+ params,
208
+ ...(effectiveTarget ? { sessionId: effectiveTarget } : {}),
209
+ }));
210
+ }
211
+ catch (error) {
212
+ if (cleanup())
213
+ reject(error instanceof Error ? error : new Error(String(error)));
214
+ }
215
+ });
216
+ }
217
+ async attachToPage(preferredUrl, force = false, preferredMarker) {
218
+ if (this.pageSessionId && !force)
219
+ return;
220
+ if (force && this.pageSessionId) {
221
+ const previousSession = this.pageSessionId;
222
+ this.pageSessionId = undefined;
223
+ this.pageTargetId = undefined;
224
+ await this.send('Target.detachFromTarget', {
225
+ sessionId: previousSession,
226
+ }).catch(() => undefined);
227
+ }
228
+ const targets = (await this.send('Target.getTargets'));
229
+ const pages = (targets.targetInfos ?? []).filter((target) => target.type === 'page' && typeof target.targetId === 'string');
230
+ if (!pages.length)
231
+ throw new Error('浏览器没有可绑定的页面标签');
232
+ let selected = preferredMarker
233
+ ? undefined
234
+ : preferredUrl
235
+ ? pages.find((target) => target.url === preferredUrl)
236
+ : undefined;
237
+ if (preferredMarker) {
238
+ const marker = JSON.stringify(preferredMarker);
239
+ for (const candidate of pages) {
240
+ const attached = (await this.send('Target.attachToTarget', {
241
+ targetId: candidate.targetId,
242
+ flatten: true,
243
+ }));
244
+ const sessionId = attached.sessionId;
245
+ if (typeof sessionId !== 'string')
246
+ continue;
247
+ const probe = await this.send('Runtime.evaluate', {
248
+ expression: `globalThis[${JSON.stringify(BROWSER_TAB_MARKER_KEY)}] === ${marker}`,
249
+ returnByValue: true,
250
+ }, sessionId).catch(() => undefined);
251
+ if (probe?.result
252
+ ?.value === true) {
253
+ selected = candidate;
254
+ this.pageTargetId = String(candidate.targetId);
255
+ this.pageSessionId = sessionId;
256
+ break;
257
+ }
258
+ await this.send('Target.detachFromTarget', { sessionId }).catch(() => undefined);
259
+ }
260
+ }
261
+ if (preferredMarker) {
262
+ if (!selected)
263
+ throw new Error('无法通过会话标记绑定到当前浏览器标签');
264
+ return;
265
+ }
266
+ selected ??= pages[pages.length - 1];
267
+ const attached = (await this.send('Target.attachToTarget', {
268
+ targetId: selected.targetId,
269
+ flatten: true,
270
+ }));
271
+ if (typeof attached.sessionId !== 'string')
272
+ throw new Error('浏览器未返回页面 target session');
273
+ this.pageTargetId = selected.targetId;
274
+ this.pageSessionId = attached.sessionId;
275
+ }
276
+ read(after = 0, methods, limit = 100) {
277
+ return this.events
278
+ .filter((event) => event.sequence > after &&
279
+ (!methods?.length || methods.includes(event.method)))
280
+ .slice(-Math.max(1, Math.min(limit, 500)));
281
+ }
282
+ subscribe(listener) {
283
+ this.listeners.add(listener);
284
+ return () => this.listeners.delete(listener);
285
+ }
286
+ }
287
+ async function cdpUrl(sessionName, bin, run, signal) {
288
+ await ensureDaemon(sessionName, { signal });
289
+ const output = await run(bin, [...sessionArgs(sessionName), 'get', 'cdp-url'], signal);
290
+ const url = `${output.stdout}\n${output.stderr}`.match(/ws:\/\/[^\s"']+/)?.[0];
291
+ if (output.code !== 0 || !url)
292
+ throw new Error('无法取得浏览器 CDP 地址');
293
+ return url;
294
+ }
295
+ export async function getBrowserAutomation(sessionName, bin, run, signal, preferredUrl, preferredMarker) {
296
+ const url = await cdpUrl(sessionName, bin, run, signal);
297
+ // The browser endpoint is shared, but the attached page is not. Returning
298
+ // a fresh connection prevents a later conversation from changing the
299
+ // mutable page session underneath an in-flight batch.
300
+ const conn = new CdpConnection(url);
301
+ await conn.open();
302
+ await conn.attachToPage(preferredUrl, true, preferredMarker);
303
+ return conn;
304
+ }
305
+ export function browserDownloadDir(conversationKey = 'local', runId = 'default') {
306
+ const safe = (value) => value.replace(/[^a-zA-Z0-9._-]/g, '_').slice(0, 100) || 'default';
307
+ const root = process.env.MINIMAL_AGENT_HOME ?? path.join(os.homedir(), '.minimal-agent');
308
+ return path.join(root, 'browser', 'downloads', safe(conversationKey), safe(runId));
309
+ }
310
+ export async function configureDownloads(cdp, conversationKey, runId) {
311
+ const dir = browserDownloadDir(conversationKey, runId);
312
+ await mkdir(dir, { recursive: true, mode: 0o700 });
313
+ // Browser domain is current Chrome; Page fallback keeps older Chromium usable.
314
+ await cdp
315
+ .send('Browser.setDownloadBehavior', {
316
+ behavior: 'allow',
317
+ downloadPath: dir,
318
+ eventsEnabled: true,
319
+ })
320
+ .catch(() => cdp.send('Page.setDownloadBehavior', {
321
+ behavior: 'allow',
322
+ downloadPath: dir,
323
+ }));
324
+ return dir;
325
+ }
326
+ export async function finalDownload(pathname) {
327
+ const info = await stat(pathname);
328
+ return { path: pathname, receivedBytes: info.size };
329
+ }