minimal-agent 0.13.0 → 0.15.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 (474) 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 +536 -0
  103. package/src/advisor/advisorCoordinator.ts +693 -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/quickModelSetup.js +12 -1
  108. package/src/cli/quickModelSetup.tsx +15 -3
  109. package/src/cli/streamJson.js +5 -6
  110. package/src/cli/streamJson.ts +8 -4
  111. package/src/cli/wizards/advisorWizard.js +4 -2
  112. package/src/cli/wizards/advisorWizard.tsx +8 -2
  113. package/src/cli/wizards/contextAdvisorWizard.js +5 -4
  114. package/src/cli/wizards/contextAdvisorWizard.tsx +7 -6
  115. package/src/cli/wizards/providerPresets.js +18 -8
  116. package/src/cli/wizards/providerPresets.ts +18 -8
  117. package/src/collaboration/taskFlow.js +115 -0
  118. package/src/collaboration/taskFlow.ts +169 -0
  119. package/src/config/configDefaults.js +41 -1
  120. package/src/config/configDefaults.ts +43 -1
  121. package/src/config/configDiagnostics.ts +2 -2
  122. package/src/config/configFile.js +40 -9
  123. package/src/config/configFile.ts +60 -11
  124. package/src/config/configService.js +419 -74
  125. package/src/config/configService.ts +703 -145
  126. package/src/config/numericLimits.js +22 -0
  127. package/src/config/numericLimits.ts +24 -0
  128. package/src/config.js +1 -0
  129. package/src/config.ts +3 -2
  130. package/src/context/budgetPlan.js +1 -1
  131. package/src/context/budgetPlan.ts +1 -1
  132. package/src/context/compact.js +7 -2
  133. package/src/context/compact.ts +9 -2
  134. package/src/context/microCompactLite.js +212 -13
  135. package/src/context/microCompactLite.ts +261 -12
  136. package/src/context/sessionRegistry.js +8 -1
  137. package/src/context/sessionRegistry.ts +18 -5
  138. package/src/context/toolResultArchive.js +72 -0
  139. package/src/context/toolResultArchive.ts +95 -0
  140. package/src/goal/errors.js +8 -0
  141. package/src/goal/errors.ts +18 -0
  142. package/src/goal/goalRuntime.js +344 -0
  143. package/src/goal/goalRuntime.ts +466 -0
  144. package/src/goal/goalStore.js +200 -0
  145. package/src/goal/goalStore.ts +219 -0
  146. package/src/goal/index.js +4 -0
  147. package/src/goal/index.ts +4 -0
  148. package/src/goal/statusMapping.js +71 -0
  149. package/src/goal/statusMapping.ts +95 -0
  150. package/src/goal/types.js +7 -0
  151. package/src/goal/types.ts +179 -0
  152. package/src/goal/workflowController.js +306 -0
  153. package/src/goal/workflowController.ts +360 -0
  154. package/src/harness/evidenceLedger.js +2 -0
  155. package/src/harness/evidenceLedger.ts +1 -0
  156. package/src/harness/stallGuard.js +9 -3
  157. package/src/harness/stallGuard.ts +7 -3
  158. package/src/images/imageResolver.js +161 -0
  159. package/src/images/imageResolver.ts +189 -0
  160. package/src/infra/verification.js +34 -5
  161. package/src/infra/verification.ts +39 -4
  162. package/src/llm/client.js +79 -21
  163. package/src/llm/client.ts +182 -35
  164. package/src/llm/gatewayClient.js +201 -0
  165. package/src/llm/gatewayClient.ts +299 -0
  166. package/src/llm/messageProvenance.js +46 -0
  167. package/src/llm/messageProvenance.ts +58 -0
  168. package/src/llm/modelProvider.js +1 -0
  169. package/src/llm/modelProvider.ts +22 -0
  170. package/src/llm/providers/anthropicFormat.js +108 -1
  171. package/src/llm/providers/anthropicFormat.ts +115 -4
  172. package/src/llm/providers/openaiFormat.js +9 -0
  173. package/src/llm/providers/openaiFormat.ts +12 -3
  174. package/src/loop.js +328 -55
  175. package/src/loop.ts +382 -58
  176. package/src/main.js +4 -1
  177. package/src/main.tsx +4 -1
  178. package/src/managedExecution/index.js +2 -0
  179. package/src/managedExecution/index.ts +2 -0
  180. package/src/managedExecution/registry.js +15 -0
  181. package/src/managedExecution/registry.ts +20 -0
  182. package/src/managedExecution/types.js +1 -0
  183. package/src/managedExecution/types.ts +86 -0
  184. package/src/modelRef.js +9 -0
  185. package/src/modelRef.ts +31 -0
  186. package/src/multimodal.js +14 -28
  187. package/src/multimodal.ts +17 -33
  188. package/src/net/lanDiscovery.js +65 -0
  189. package/src/net/lanDiscovery.ts +82 -0
  190. package/src/plugin-sdk.js +28 -3
  191. package/src/plugin-sdk.ts +39 -6
  192. package/src/plugins/pluginApi.ts +16 -1
  193. package/src/plugins/pluginLoader.js +4 -0
  194. package/src/plugins/pluginLoader.ts +6 -0
  195. package/src/plugins/pluginRunner.js +139 -7
  196. package/src/plugins/pluginRunner.ts +173 -9
  197. package/src/plugins/slashFallback.js +113 -0
  198. package/src/plugins/slashFallback.ts +137 -0
  199. package/src/prompts/policyRegistry.js +12 -32
  200. package/src/prompts/policyRegistry.ts +15 -32
  201. package/src/prompts/promptAssembly.js +103 -12
  202. package/src/prompts/promptAssembly.ts +114 -12
  203. package/src/prompts/skillList.js +21 -3
  204. package/src/prompts/skillList.ts +27 -2
  205. package/src/prompts/stableSystemPrompt.js +18 -0
  206. package/src/prompts/stableSystemPrompt.ts +33 -0
  207. package/src/runtime/agentRuntimeContext.js +8 -2
  208. package/src/runtime/agentRuntimeContext.ts +17 -4
  209. package/src/session/runAgentTurn.js +78 -12
  210. package/src/session/runAgentTurn.ts +105 -23
  211. package/src/session/runTurn.js +10 -9
  212. package/src/session/runTurn.ts +17 -8
  213. package/src/session/sessionState.ts +2 -0
  214. package/src/team/auth.js +186 -0
  215. package/src/team/auth.ts +298 -0
  216. package/src/team/cli.js +105 -0
  217. package/src/team/cli.ts +122 -0
  218. package/src/team/onlineToolContract.js +64 -0
  219. package/src/team/onlineToolContract.ts +109 -0
  220. package/src/team/toolPolicy.js +36 -0
  221. package/src/team/toolPolicy.ts +75 -0
  222. package/src/tools/advisor/advisor.js +115 -50
  223. package/src/tools/advisor/advisor.ts +124 -51
  224. package/src/tools/advisor/advisorDecision.js +71 -0
  225. package/src/tools/advisor/advisorDecision.ts +85 -0
  226. package/src/tools/agent/agent.js +18 -5
  227. package/src/tools/agent/agent.ts +21 -7
  228. package/src/tools/agent/agentControl.js +246 -0
  229. package/src/tools/agent/agentControl.ts +284 -0
  230. package/src/tools/agent/agentTaskService.js +40 -1
  231. package/src/tools/agent/agentTaskService.ts +44 -1
  232. package/src/tools/agent/agentTypes.js +14 -2
  233. package/src/tools/agent/agentTypes.ts +15 -2
  234. package/src/tools/applypatch/applyPatch.js +362 -0
  235. package/src/tools/applypatch/applyPatch.ts +428 -0
  236. package/src/tools/bash/bash.js +22 -15
  237. package/src/tools/bash/bash.ts +23 -17
  238. package/src/tools/capabilities.js +10 -5
  239. package/src/tools/capabilities.ts +10 -5
  240. package/src/tools/computeruse/computerIntent.js +32 -0
  241. package/src/tools/computeruse/computerIntent.ts +46 -0
  242. package/src/tools/computeruse/telemetryLog.js +12 -0
  243. package/src/tools/computeruse/telemetryLog.ts +16 -0
  244. package/src/tools/computeruse/vision/telemetry.js +1 -0
  245. package/src/tools/computeruse/vision/telemetry.ts +1 -0
  246. package/src/tools/effectiveToolSet.js +4 -0
  247. package/src/tools/effectiveToolSet.ts +4 -0
  248. package/src/tools/index.js +21 -2
  249. package/src/tools/index.ts +33 -2
  250. package/src/tools/presentresult/presentresult.js +6 -15
  251. package/src/tools/presentresult/presentresult.ts +6 -15
  252. package/src/tools/read/read.js +62 -9
  253. package/src/tools/read/read.ts +63 -9
  254. package/src/tools/shared/fileUtils.js +1 -2
  255. package/src/tools/shared/fileUtils.ts +1 -2
  256. package/src/tools/shared/toolOutputStore.js +23 -1
  257. package/src/tools/shared/toolOutputStore.ts +22 -1
  258. package/src/tools/skill/skill.js +9 -3
  259. package/src/tools/skill/skill.ts +8 -4
  260. package/src/tools/toolPromptGuides.js +125 -0
  261. package/src/tools/toolPromptGuides.ts +146 -0
  262. package/src/tools/webbrowser/agentBrowserPath.js +19 -9
  263. package/src/tools/webbrowser/agentBrowserPath.ts +70 -28
  264. package/src/tools/webbrowser/browser.js +27 -11
  265. package/src/tools/webbrowser/browser.ts +68 -24
  266. package/src/tools/webbrowser/browserAutomation.js +329 -0
  267. package/src/tools/webbrowser/browserAutomation.ts +467 -0
  268. package/src/tools/webbrowser/browserAxState.js +97 -0
  269. package/src/tools/webbrowser/browserAxState.ts +142 -0
  270. package/src/tools/webbrowser/browserBatch.js +1578 -0
  271. package/src/tools/webbrowser/browserBatch.ts +2382 -0
  272. package/src/tools/webbrowser/browserCdp.js +208 -0
  273. package/src/tools/webbrowser/browserCdp.ts +255 -0
  274. package/src/tools/webbrowser/browserConditions.js +24 -0
  275. package/src/tools/webbrowser/browserConditions.ts +45 -0
  276. package/src/tools/webbrowser/browserContent.js +281 -0
  277. package/src/tools/webbrowser/browserContent.ts +438 -0
  278. package/src/tools/webbrowser/browserControl.js +131 -34
  279. package/src/tools/webbrowser/browserControl.ts +210 -56
  280. package/src/tools/webbrowser/browserDaemon.js +22 -14
  281. package/src/tools/webbrowser/browserDaemon.ts +54 -21
  282. package/src/tools/webbrowser/browserFrames.js +47 -0
  283. package/src/tools/webbrowser/browserFrames.ts +54 -0
  284. package/src/tools/webbrowser/browserInteractionResolver.js +17 -0
  285. package/src/tools/webbrowser/browserInteractionResolver.ts +40 -0
  286. package/src/tools/webbrowser/browserLocator.js +140 -0
  287. package/src/tools/webbrowser/browserLocator.ts +194 -0
  288. package/src/tools/webbrowser/browserOutcome.js +10 -17
  289. package/src/tools/webbrowser/browserOutcome.ts +48 -31
  290. package/src/tools/webbrowser/browserRecovery.js +58 -0
  291. package/src/tools/webbrowser/browserRecovery.ts +83 -0
  292. package/src/tools/webbrowser/browserRunRegistry.js +35 -3
  293. package/src/tools/webbrowser/browserRunRegistry.ts +91 -15
  294. package/src/tools/webbrowser/browserService.js +28 -2
  295. package/src/tools/webbrowser/browserService.ts +49 -9
  296. package/src/tools/webbrowser/browserStream.js +132 -33
  297. package/src/tools/webbrowser/browserStream.ts +224 -50
  298. package/src/tools/webbrowser/browserTabs.js +48 -15
  299. package/src/tools/webbrowser/browserTabs.ts +178 -96
  300. package/src/tools/webbrowser/webbrowser.js +679 -144
  301. package/src/tools/webbrowser/webbrowser.ts +975 -236
  302. package/src/tools/webfetch/preapproved.js +0 -2
  303. package/src/tools/webfetch/preapproved.ts +0 -2
  304. package/src/tools/websearch/websearch.js +129 -8
  305. package/src/tools/websearch/websearch.ts +138 -6
  306. package/src/types.ts +459 -40
  307. package/src/ui/App.js +377 -58
  308. package/src/ui/App.tsx +576 -111
  309. package/src/ui/LiveArea.js +14 -8
  310. package/src/ui/LiveArea.tsx +14 -10
  311. package/src/ui/MessageList.js +63 -20
  312. package/src/ui/MessageList.tsx +101 -16
  313. package/src/ui/ModelPicker.js +7 -4
  314. package/src/ui/ModelPicker.tsx +55 -8
  315. package/src/ui/hooks/useChat.js +152 -163
  316. package/src/ui/hooks/useChat.ts +396 -334
  317. package/src/ui/loginCommand.js +56 -0
  318. package/src/ui/loginCommand.ts +63 -0
  319. package/src/ui/toolProgress.js +41 -0
  320. package/src/ui/toolProgress.ts +44 -0
  321. package/src/web/browserBridge.js +20 -2
  322. package/src/web/browserBridge.ts +20 -2
  323. package/src/web/protocol.ts +1897 -194
  324. package/workflows/adaptive-research/workflow.mjs +86 -0
  325. package/workflows/e2e-capabilities/workflow.mjs +102 -0
  326. package/workflows/e2e-llm/workflow.mjs +52 -0
  327. package/workflows/e2e-smoke/workflow.mjs +59 -0
  328. package/workflows/e2e-vision-schema/README.md +48 -0
  329. package/workflows/e2e-vision-schema/workflow.mjs +149 -0
  330. package/workflows/e2e-write-greet/workflow.mjs +37 -0
  331. package/workflows/file-census/README.md +14 -0
  332. package/workflows/file-census/scripts/.gitkeep +2 -0
  333. package/workflows/file-census/workflow.mjs +110 -0
  334. package/workflows/goal/README.md +166 -0
  335. package/workflows/goal/prompts/audit.md +57 -0
  336. package/workflows/goal/prompts/contract.md +56 -0
  337. package/workflows/goal/prompts/iterate.md +37 -0
  338. package/workflows/goal/workflow.mjs +501 -0
  339. package/workflows/illustrate/README.md +90 -0
  340. package/workflows/illustrate/assets/engines.json +20 -0
  341. package/workflows/illustrate/assets/extract-baidu.js +21 -0
  342. package/workflows/illustrate/assets/extract-bing.js +33 -0
  343. package/workflows/illustrate/assets/extract-google.js +31 -0
  344. package/workflows/illustrate/workflow.mjs +301 -0
  345. package/workflows/plan/workflow.mjs +389 -0
  346. package/workflows/question-crops/README.md +35 -0
  347. package/workflows/question-crops/prompts/inventory.md +23 -0
  348. package/workflows/question-crops/scripts/image-ops.mjs +305 -0
  349. package/workflows/question-crops/scripts/image-ops.test.mjs +95 -0
  350. package/workflows/question-crops/workflow.mjs +172 -0
  351. package/workflows/ralph-loop/workflow.mjs +162 -0
  352. package/workflows/research/README.md +74 -0
  353. package/workflows/research/prompts/s0-goal.md +43 -0
  354. package/workflows/research/prompts/s1-early-exit.md +22 -0
  355. package/workflows/research/prompts/s1-map.md +58 -0
  356. package/workflows/research/prompts/s2-options.md +53 -0
  357. package/workflows/research/prompts/s3-deep-dive.md +56 -0
  358. package/workflows/research/prompts/s4-verify.md +74 -0
  359. package/workflows/research/prompts/s5-synthesis.md +81 -0
  360. package/workflows/research/prompts/s5b-fill-gaps.md +32 -0
  361. package/workflows/research/prompts/s6-package.md +32 -0
  362. package/workflows/research/scripts/build-report.mjs +98 -0
  363. package/workflows/research/workflow.mjs +288 -0
  364. package/workflows/wechat-reading-shots/prompts/collect-params.md +16 -0
  365. package/workflows/wechat-reading-shots/prompts/evaluate.md +20 -0
  366. package/workflows/wechat-reading-shots/prompts/open-book.md +28 -0
  367. package/workflows/wechat-reading-shots/prompts/read-page.md +13 -0
  368. package/workflows/wechat-reading-shots/prompts/turn-batch.md +24 -0
  369. package/workflows/wechat-reading-shots/test/control-flow.test.ts +329 -0
  370. package/workflows/wechat-reading-shots/workflow.mjs +266 -0
  371. package/workflows/wrong-question-docx/README.md +55 -0
  372. package/workflows/wrong-question-docx/prompts/figure-qa.md +8 -0
  373. package/workflows/wrong-question-docx/prompts/transcribe.md +25 -0
  374. package/workflows/wrong-question-docx/scripts/workbook.mjs +857 -0
  375. package/workflows/wrong-question-docx/test/control-flow.test.ts +165 -0
  376. package/workflows/wrong-question-docx/test/workbook.test.mjs +303 -0
  377. package/workflows/wrong-question-docx/workflow.mjs +485 -0
  378. package/plugins/workflow-runner/src/agentCommon.js +0 -354
  379. package/plugins/workflow-runner/src/agentCommon.ts +0 -435
  380. package/plugins/workflow-runner/src/controlFlow/branch.js +0 -40
  381. package/plugins/workflow-runner/src/controlFlow/branch.ts +0 -46
  382. package/plugins/workflow-runner/src/controlFlow/loop.js +0 -211
  383. package/plugins/workflow-runner/src/controlFlow/loop.ts +0 -248
  384. package/plugins/workflow-runner/src/controlFlow/pause.js +0 -129
  385. package/plugins/workflow-runner/src/controlFlow/pause.ts +0 -141
  386. package/plugins/workflow-runner/src/controlFlow/signal.js +0 -21
  387. package/plugins/workflow-runner/src/controlFlow/signal.ts +0 -29
  388. package/plugins/workflow-runner/src/controlFlow/types.js +0 -18
  389. package/plugins/workflow-runner/src/controlFlow/types.ts +0 -63
  390. package/plugins/workflow-runner/src/dslManifest.js +0 -72
  391. package/plugins/workflow-runner/src/dslManifest.ts +0 -127
  392. package/plugins/workflow-runner/src/expressions.js +0 -639
  393. package/plugins/workflow-runner/src/expressions.ts +0 -640
  394. package/plugins/workflow-runner/src/loader.js +0 -573
  395. package/plugins/workflow-runner/src/loader.ts +0 -721
  396. package/plugins/workflow-runner/src/multimodal.js +0 -38
  397. package/plugins/workflow-runner/src/multimodal.ts +0 -64
  398. package/plugins/workflow-runner/src/recovery.js +0 -126
  399. package/plugins/workflow-runner/src/recovery.ts +0 -156
  400. package/plugins/workflow-runner/src/stepExecutors/agent.js +0 -173
  401. package/plugins/workflow-runner/src/stepExecutors/agent.ts +0 -234
  402. package/plugins/workflow-runner/src/stepExecutors/assert.js +0 -42
  403. package/plugins/workflow-runner/src/stepExecutors/assert.ts +0 -52
  404. package/plugins/workflow-runner/src/stepExecutors/echo.js +0 -31
  405. package/plugins/workflow-runner/src/stepExecutors/echo.ts +0 -38
  406. package/plugins/workflow-runner/src/stepExecutors/llm.js +0 -99
  407. package/plugins/workflow-runner/src/stepExecutors/llm.ts +0 -133
  408. package/plugins/workflow-runner/src/stepExecutors/set.js +0 -49
  409. package/plugins/workflow-runner/src/stepExecutors/set.ts +0 -56
  410. package/plugins/workflow-runner/src/stepExecutors/skill.js +0 -111
  411. package/plugins/workflow-runner/src/stepExecutors/skill.ts +0 -140
  412. package/plugins/workflow-runner/src/stepExecutors/tool.js +0 -227
  413. package/plugins/workflow-runner/src/stepExecutors/tool.ts +0 -274
  414. package/plugins/workflow-runner/src/stepExecutors/verify.js +0 -61
  415. package/plugins/workflow-runner/src/stepExecutors/verify.ts +0 -72
  416. package/plugins/workflow-runner/src/stepPipeline.js +0 -277
  417. package/plugins/workflow-runner/src/stepPipeline.ts +0 -366
  418. package/plugins/workflow-runner/test/agent.test.ts +0 -587
  419. package/plugins/workflow-runner/test/agentLlmError.test.ts +0 -373
  420. package/plugins/workflow-runner/test/bashBlacklist.sweep.test.ts +0 -65
  421. package/plugins/workflow-runner/test/captureMisbind.test.ts +0 -99
  422. package/plugins/workflow-runner/test/cli.e2e.test.ts +0 -167
  423. package/plugins/workflow-runner/test/context-files.test.ts +0 -320
  424. package/plugins/workflow-runner/test/e2e.test.ts +0 -370
  425. package/plugins/workflow-runner/test/e2eNewLayout.test.ts +0 -314
  426. package/plugins/workflow-runner/test/engineRobustness.test.ts +0 -234
  427. package/plugins/workflow-runner/test/expressions.test.ts +0 -439
  428. package/plugins/workflow-runner/test/foundation.test.ts +0 -126
  429. package/plugins/workflow-runner/test/graceful.test.ts +0 -139
  430. package/plugins/workflow-runner/test/greedyInputs.load.test.ts +0 -47
  431. package/plugins/workflow-runner/test/hostCapability.test.ts +0 -108
  432. package/plugins/workflow-runner/test/illustrate.load.test.ts +0 -183
  433. package/plugins/workflow-runner/test/jsonPayload.test.ts +0 -83
  434. package/plugins/workflow-runner/test/loader.test.ts +0 -617
  435. package/plugins/workflow-runner/test/maxTurnsRetryDelay.test.ts +0 -33
  436. package/plugins/workflow-runner/test/multimodal.test.ts +0 -342
  437. package/plugins/workflow-runner/test/output-schema.test.ts +0 -213
  438. package/plugins/workflow-runner/test/parseWorkflowArgs.test.ts +0 -106
  439. package/plugins/workflow-runner/test/pluginRunner.isolation.test.ts +0 -269
  440. package/plugins/workflow-runner/test/ppt.load.test.ts +0 -1220
  441. package/plugins/workflow-runner/test/ralphLoop.e2e.test.ts +0 -221
  442. package/plugins/workflow-runner/test/recovery.test.ts +0 -265
  443. package/plugins/workflow-runner/test/research.load.test.ts +0 -328
  444. package/plugins/workflow-runner/test/runner.test.ts +0 -911
  445. package/plugins/workflow-runner/test/runnerPreflight.test.ts +0 -436
  446. package/plugins/workflow-runner/test/skillTurnDone.test.ts +0 -71
  447. package/plugins/workflow-runner/test/stateLifecycle.test.ts +0 -198
  448. package/plugins/workflow-runner/test/stepPipeline.test.ts +0 -114
  449. package/plugins/workflow-runner/test/taskArbitration.test.ts +0 -354
  450. package/plugins/workflow-runner/test/taskLifecycle.test.ts +0 -324
  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 -201
  468. package/workflows/research.yaml +0 -873
  469. package/workflows/schema.json +0 -176
  470. package/workflows/webppt.yaml +0 -496
  471. package/workflows/wechat-reading-shots.yaml +0 -315
  472. package/workflows/word.yaml +0 -720
  473. package/workflows/youtube-shorts.yaml +0 -202
  474. /package/workflows/{research.md → research/DESIGN.md} +0 -0
@@ -0,0 +1,467 @@
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
+
11
+ import type { AgentBrowserRunner } from './browser.js';
12
+ import { sessionArgs } from './browser.js';
13
+ import { ensureDaemon } from './browserDaemon.js';
14
+
15
+ export type CdpEvent = {
16
+ sequence: number;
17
+ method: string;
18
+ params: Record<string, unknown>;
19
+ sessionId?: string;
20
+ at: number;
21
+ };
22
+ export type BrowserDownload = {
23
+ id: string;
24
+ url: string;
25
+ filename: string;
26
+ path: string;
27
+ state: 'start' | 'progress' | 'complete' | 'failed' | 'canceled';
28
+ receivedBytes?: number;
29
+ totalBytes?: number;
30
+ mime?: string;
31
+ error?: string;
32
+ };
33
+
34
+ export const BROWSER_TAB_MARKER_KEY = '__minimalAgentTabMarker';
35
+
36
+ type Pending = {
37
+ resolve: (value: unknown) => void;
38
+ reject: (reason: Error) => void;
39
+ timer: ReturnType<typeof setTimeout>;
40
+ onAbort?: () => void;
41
+ signal?: AbortSignal;
42
+ };
43
+
44
+ class CdpConnection {
45
+ private socket: WebSocket | null = null;
46
+ private opening: Promise<void> | null = null;
47
+ private pageTargetId: string | undefined;
48
+ private pageSessionId: string | undefined;
49
+ private id = 0;
50
+ private pending = new Map<number, Pending>();
51
+ private events: CdpEvent[] = [];
52
+ private sequence = 0;
53
+ private listeners = new Set<(event: CdpEvent) => void>();
54
+
55
+ constructor(private readonly url: string) {}
56
+
57
+ /**
58
+ * A connection is page-scoped. It must not be put back in a process-wide
59
+ * pool and rebound by another conversation while this caller still holds it.
60
+ */
61
+ close(): void {
62
+ const socket = this.socket;
63
+ this.socket = null;
64
+ this.pageTargetId = undefined;
65
+ this.pageSessionId = undefined;
66
+ socket?.close();
67
+ }
68
+
69
+ get attachedPageSessionId(): string | undefined {
70
+ return this.pageSessionId;
71
+ }
72
+
73
+ get attachedPageTargetId(): string | undefined {
74
+ return this.pageTargetId;
75
+ }
76
+
77
+ async evaluateInFrame(
78
+ frameId: string,
79
+ expression: string,
80
+ signal?: AbortSignal,
81
+ ): Promise<unknown> {
82
+ const isolated = (await this.send(
83
+ 'Page.createIsolatedWorld',
84
+ {
85
+ frameId,
86
+ worldName: 'minimal-agent-browser',
87
+ grantUniveralAccess: false,
88
+ },
89
+ undefined,
90
+ 30_000,
91
+ signal,
92
+ )) as { executionContextId?: unknown };
93
+ if (typeof isolated.executionContextId !== 'number')
94
+ throw new Error(`无法创建 frame execution context:${frameId}`);
95
+ return this.send(
96
+ 'Runtime.evaluate',
97
+ {
98
+ expression,
99
+ contextId: isolated.executionContextId,
100
+ returnByValue: true,
101
+ awaitPromise: true,
102
+ },
103
+ undefined,
104
+ 30_000,
105
+ signal,
106
+ );
107
+ }
108
+
109
+ async frameOwnerOffset(
110
+ frameId: string,
111
+ signal?: AbortSignal,
112
+ ): Promise<{ x: number; y: number }> {
113
+ // CDP returns the owner quad in top-level viewport coordinates, including
114
+ // nested cross-origin frames. Do not add ancestor offsets a second time.
115
+ const owner = (await this.send(
116
+ 'DOM.getFrameOwner',
117
+ { frameId },
118
+ undefined,
119
+ 30_000,
120
+ signal,
121
+ )) as { backendNodeId?: unknown };
122
+ if (typeof owner.backendNodeId !== 'number')
123
+ throw new Error(`无法取得 frame owner:${frameId}`);
124
+ const box = (await this.send(
125
+ 'DOM.getBoxModel',
126
+ { backendNodeId: owner.backendNodeId },
127
+ undefined,
128
+ 30_000,
129
+ signal,
130
+ )) as { model?: { border?: unknown } };
131
+ const border = box.model?.border;
132
+ if (!Array.isArray(border) || border.length < 2)
133
+ throw new Error(`无法取得 frame owner 坐标:${frameId}`);
134
+ const numbers = border.filter(
135
+ (value): value is number => typeof value === 'number',
136
+ );
137
+ if (numbers.length < 2) throw new Error(`frame owner 坐标无效:${frameId}`);
138
+ return { x: numbers[0]!, y: numbers[1]! };
139
+ }
140
+
141
+ async open(): Promise<void> {
142
+ if (this.socket?.readyState === WebSocket.OPEN) return;
143
+ if (this.opening) return this.opening;
144
+ this.opening = new Promise<void>((resolve, reject) => {
145
+ const socket = new WebSocket(this.url);
146
+ const timer = setTimeout(() => {
147
+ socket.close();
148
+ reject(new Error('CDP connection timed out'));
149
+ }, 10_000);
150
+ socket.onopen = () => {
151
+ clearTimeout(timer);
152
+ this.socket = socket;
153
+ resolve();
154
+ };
155
+ socket.onerror = () => {
156
+ clearTimeout(timer);
157
+ reject(new Error('Unable to connect to browser CDP'));
158
+ };
159
+ socket.onclose = () => {
160
+ if (this.socket === socket) this.socket = null;
161
+ this.pageTargetId = undefined;
162
+ this.pageSessionId = undefined;
163
+ for (const [id, request] of this.pending) {
164
+ clearTimeout(request.timer);
165
+ if (request.signal && request.onAbort)
166
+ request.signal.removeEventListener('abort', request.onAbort);
167
+ request.reject(new Error('CDP connection closed'));
168
+ this.pending.delete(id);
169
+ }
170
+ };
171
+ socket.onmessage = (message) => this.onMessage(String(message.data));
172
+ }).finally(() => {
173
+ this.opening = null;
174
+ });
175
+ return this.opening;
176
+ }
177
+
178
+ private onMessage(raw: string): void {
179
+ let data: Record<string, unknown>;
180
+ try {
181
+ data = JSON.parse(raw) as Record<string, unknown>;
182
+ } catch {
183
+ return;
184
+ }
185
+ if (typeof data.id === 'number') {
186
+ const request = this.pending.get(data.id);
187
+ if (!request) return;
188
+ this.pending.delete(data.id);
189
+ clearTimeout(request.timer);
190
+ if (request.signal && request.onAbort)
191
+ request.signal.removeEventListener('abort', request.onAbort);
192
+ if (data.error) request.reject(new Error(JSON.stringify(data.error)));
193
+ else request.resolve(data.result ?? {});
194
+ return;
195
+ }
196
+ if (typeof data.method !== 'string') return;
197
+ const event: CdpEvent = {
198
+ sequence: ++this.sequence,
199
+ method: data.method,
200
+ params: (data.params ?? {}) as Record<string, unknown>,
201
+ sessionId:
202
+ typeof data.sessionId === 'string' ? data.sessionId : undefined,
203
+ at: Date.now(),
204
+ };
205
+ if (
206
+ event.method === 'Target.detachedFromTarget' &&
207
+ String(event.params.sessionId ?? '') === this.pageSessionId
208
+ ) {
209
+ this.pageTargetId = undefined;
210
+ this.pageSessionId = undefined;
211
+ }
212
+ if (
213
+ (event.method === 'Target.targetDestroyed' ||
214
+ event.method === 'Target.targetCrashed') &&
215
+ String(event.params.targetId ?? '') === this.pageTargetId
216
+ ) {
217
+ this.pageTargetId = undefined;
218
+ this.pageSessionId = undefined;
219
+ }
220
+ this.events.push(event);
221
+ if (this.events.length > 500)
222
+ this.events.splice(0, this.events.length - 500);
223
+ for (const listener of this.listeners) {
224
+ try {
225
+ listener(event);
226
+ } catch {
227
+ // One observer must not break delivery to the remaining CDP consumers.
228
+ }
229
+ }
230
+ }
231
+
232
+ async send(
233
+ method: string,
234
+ params: Record<string, unknown> = {},
235
+ target?: string,
236
+ timeoutMs = 30_000,
237
+ signal?: AbortSignal,
238
+ ): Promise<unknown> {
239
+ await this.open();
240
+ const socket = this.socket;
241
+ if (!socket || socket.readyState !== WebSocket.OPEN)
242
+ throw new Error('CDP connection is unavailable');
243
+ const id = ++this.id;
244
+ const pageDomain =
245
+ /^(Accessibility|DOM|Input|Log|Network|Page|Performance|Runtime|Security)\./.test(
246
+ method,
247
+ );
248
+ const effectiveTarget =
249
+ target ?? (pageDomain ? this.pageSessionId : undefined);
250
+ return new Promise((resolve, reject) => {
251
+ const abortError = () =>
252
+ signal?.reason instanceof Error
253
+ ? signal.reason
254
+ : new Error(`CDP ${method} aborted`);
255
+ const cleanup = () => {
256
+ const request = this.pending.get(id);
257
+ if (!request) return false;
258
+ this.pending.delete(id);
259
+ clearTimeout(request.timer);
260
+ if (request.signal && request.onAbort)
261
+ request.signal.removeEventListener('abort', request.onAbort);
262
+ return true;
263
+ };
264
+ const onAbort = () => {
265
+ if (cleanup()) reject(abortError());
266
+ };
267
+ const timer = setTimeout(() => {
268
+ if (cleanup()) reject(new Error(`CDP ${method} timed out`));
269
+ }, timeoutMs);
270
+ this.pending.set(id, { resolve, reject, timer, onAbort, signal });
271
+ if (signal?.aborted) {
272
+ onAbort();
273
+ return;
274
+ }
275
+ signal?.addEventListener('abort', onAbort, { once: true });
276
+ try {
277
+ socket.send(
278
+ JSON.stringify({
279
+ id,
280
+ method,
281
+ params,
282
+ ...(effectiveTarget ? { sessionId: effectiveTarget } : {}),
283
+ }),
284
+ );
285
+ } catch (error) {
286
+ if (cleanup())
287
+ reject(error instanceof Error ? error : new Error(String(error)));
288
+ }
289
+ });
290
+ }
291
+
292
+ async attachToPage(
293
+ preferredUrl?: string,
294
+ force = false,
295
+ preferredMarker?: string,
296
+ ): Promise<void> {
297
+ if (this.pageSessionId && !force) return;
298
+ if (force && this.pageSessionId) {
299
+ const previousSession = this.pageSessionId;
300
+ this.pageSessionId = undefined;
301
+ this.pageTargetId = undefined;
302
+ await this.send('Target.detachFromTarget', {
303
+ sessionId: previousSession,
304
+ }).catch(() => undefined);
305
+ }
306
+ const targets = (await this.send('Target.getTargets')) as {
307
+ targetInfos?: Array<{
308
+ targetId?: unknown;
309
+ type?: unknown;
310
+ url?: unknown;
311
+ }>;
312
+ };
313
+ const pages = (targets.targetInfos ?? []).filter(
314
+ (target) => target.type === 'page' && typeof target.targetId === 'string',
315
+ );
316
+ if (!pages.length) throw new Error('浏览器没有可绑定的页面标签');
317
+ let selected = preferredMarker
318
+ ? undefined
319
+ : preferredUrl
320
+ ? pages.find((target) => target.url === preferredUrl)
321
+ : undefined;
322
+ if (preferredMarker) {
323
+ const marker = JSON.stringify(preferredMarker);
324
+ for (const candidate of pages) {
325
+ const attached = (await this.send('Target.attachToTarget', {
326
+ targetId: candidate.targetId,
327
+ flatten: true,
328
+ })) as { sessionId?: unknown };
329
+ const sessionId = attached.sessionId;
330
+ if (typeof sessionId !== 'string') continue;
331
+ const probe = await this.send(
332
+ 'Runtime.evaluate',
333
+ {
334
+ expression: `globalThis[${JSON.stringify(BROWSER_TAB_MARKER_KEY)}] === ${marker}`,
335
+ returnByValue: true,
336
+ },
337
+ sessionId,
338
+ ).catch(() => undefined);
339
+ if (
340
+ (probe as { result?: { value?: unknown } } | undefined)?.result
341
+ ?.value === true
342
+ ) {
343
+ selected = candidate;
344
+ this.pageTargetId = String(candidate.targetId);
345
+ this.pageSessionId = sessionId;
346
+ break;
347
+ }
348
+ await this.send('Target.detachFromTarget', { sessionId }).catch(
349
+ () => undefined,
350
+ );
351
+ }
352
+ }
353
+ if (preferredMarker) {
354
+ if (!selected) throw new Error('无法通过会话标记绑定到当前浏览器标签');
355
+ return;
356
+ }
357
+ selected ??= pages[pages.length - 1]!;
358
+ const attached = (await this.send('Target.attachToTarget', {
359
+ targetId: selected.targetId,
360
+ flatten: true,
361
+ })) as { sessionId?: unknown };
362
+ if (typeof attached.sessionId !== 'string')
363
+ throw new Error('浏览器未返回页面 target session');
364
+ this.pageTargetId = selected.targetId as string;
365
+ this.pageSessionId = attached.sessionId;
366
+ }
367
+
368
+ read(after = 0, methods?: string[], limit = 100): CdpEvent[] {
369
+ return this.events
370
+ .filter(
371
+ (event) =>
372
+ event.sequence > after &&
373
+ (!methods?.length || methods.includes(event.method)),
374
+ )
375
+ .slice(-Math.max(1, Math.min(limit, 500)));
376
+ }
377
+ subscribe(listener: (event: CdpEvent) => void): () => void {
378
+ this.listeners.add(listener);
379
+ return () => this.listeners.delete(listener);
380
+ }
381
+ }
382
+
383
+ async function cdpUrl(
384
+ sessionName: string,
385
+ bin: string,
386
+ run: AgentBrowserRunner,
387
+ signal?: AbortSignal,
388
+ ): Promise<string> {
389
+ await ensureDaemon(sessionName, { signal });
390
+ const output = await run(
391
+ bin,
392
+ [...sessionArgs(sessionName), 'get', 'cdp-url'],
393
+ signal,
394
+ );
395
+ const url = `${output.stdout}\n${output.stderr}`.match(
396
+ /ws:\/\/[^\s"']+/,
397
+ )?.[0];
398
+ if (output.code !== 0 || !url) throw new Error('无法取得浏览器 CDP 地址');
399
+ return url;
400
+ }
401
+
402
+ export async function getBrowserAutomation(
403
+ sessionName: string,
404
+ bin: string,
405
+ run: AgentBrowserRunner,
406
+ signal?: AbortSignal,
407
+ preferredUrl?: string,
408
+ preferredMarker?: string,
409
+ ): Promise<CdpConnection> {
410
+ const url = await cdpUrl(sessionName, bin, run, signal);
411
+ // The browser endpoint is shared, but the attached page is not. Returning
412
+ // a fresh connection prevents a later conversation from changing the
413
+ // mutable page session underneath an in-flight batch.
414
+ const conn = new CdpConnection(url);
415
+ await conn.open();
416
+ await conn.attachToPage(preferredUrl, true, preferredMarker);
417
+ return conn;
418
+ }
419
+
420
+ export function browserDownloadDir(
421
+ conversationKey = 'local',
422
+ runId = 'default',
423
+ ): string {
424
+ const safe = (value: string) =>
425
+ value.replace(/[^a-zA-Z0-9._-]/g, '_').slice(0, 100) || 'default';
426
+ const root =
427
+ process.env.MINIMAL_AGENT_HOME ?? path.join(os.homedir(), '.minimal-agent');
428
+ return path.join(
429
+ root,
430
+ 'browser',
431
+ 'downloads',
432
+ safe(conversationKey),
433
+ safe(runId),
434
+ );
435
+ }
436
+
437
+ export async function configureDownloads(
438
+ cdp: CdpConnection,
439
+ conversationKey?: string,
440
+ runId?: string,
441
+ ): Promise<string> {
442
+ const dir = browserDownloadDir(conversationKey, runId);
443
+ await mkdir(dir, { recursive: true, mode: 0o700 });
444
+ // Browser domain is current Chrome; Page fallback keeps older Chromium usable.
445
+ await cdp
446
+ .send('Browser.setDownloadBehavior', {
447
+ behavior: 'allow',
448
+ downloadPath: dir,
449
+ eventsEnabled: true,
450
+ })
451
+ .catch(() =>
452
+ cdp.send('Page.setDownloadBehavior', {
453
+ behavior: 'allow',
454
+ downloadPath: dir,
455
+ }),
456
+ );
457
+ return dir;
458
+ }
459
+
460
+ export async function finalDownload(
461
+ pathname: string,
462
+ ): Promise<Pick<BrowserDownload, 'path' | 'receivedBytes' | 'mime'>> {
463
+ const info = await stat(pathname);
464
+ return { path: pathname, receivedBytes: info.size };
465
+ }
466
+
467
+ export type { CdpConnection };
@@ -0,0 +1,97 @@
1
+ /** Compact AX state and generation-aware diffs for BrowserBatch observations. */
2
+ function axValue(input) {
3
+ if (input && typeof input === 'object' && 'value' in input)
4
+ return input.value;
5
+ return input;
6
+ }
7
+ function propertyValue(node, key) {
8
+ const value = node.properties?.find((item) => item.name === key)?.value
9
+ ?.value;
10
+ return value === undefined || value === null ? undefined : String(value);
11
+ }
12
+ export function normalizeAxTree(raw) {
13
+ const root = raw && typeof raw === 'object' ? raw : {};
14
+ const nodes = Array.isArray(raw)
15
+ ? raw
16
+ : Array.isArray(root.nodes)
17
+ ? root.nodes
18
+ : [];
19
+ return nodes
20
+ .map((value) => {
21
+ const node = value && typeof value === 'object' ? value : {};
22
+ const bounds = node?.bounds;
23
+ return {
24
+ id: String(node.nodeId ?? node.id ?? ''),
25
+ ...(node.parentId !== undefined
26
+ ? { parentId: String(node.parentId) }
27
+ : {}),
28
+ ...(axValue(node.role) || node.role
29
+ ? { role: String(axValue(node.role) ?? node.role) }
30
+ : {}),
31
+ ...(axValue(node.name) || node.name
32
+ ? { name: String(axValue(node.name) ?? node.name) }
33
+ : {}),
34
+ ...(propertyValue(node, 'value')
35
+ ? { value: propertyValue(node, 'value') }
36
+ : {}),
37
+ ...(node.ignored !== undefined
38
+ ? { ignored: Boolean(node.ignored) }
39
+ : {}),
40
+ ...(node.backendDOMNodeId !== undefined
41
+ ? { backendDOMNodeId: Number(node.backendDOMNodeId) }
42
+ : {}),
43
+ ...(bounds &&
44
+ typeof bounds.x === 'number' &&
45
+ typeof bounds.y === 'number' &&
46
+ typeof bounds.width === 'number' &&
47
+ typeof bounds.height === 'number'
48
+ ? {
49
+ bounds: {
50
+ x: bounds.x,
51
+ y: bounds.y,
52
+ width: bounds.width,
53
+ height: bounds.height,
54
+ },
55
+ }
56
+ : {}),
57
+ };
58
+ })
59
+ .filter((node) => node.id.length > 0);
60
+ }
61
+ function nodeKey(node) {
62
+ return JSON.stringify(node);
63
+ }
64
+ export function diffAxTree(previous, current, generation, pageRevision, forceFull = false) {
65
+ const next = new Map(current.map((node) => [node.id, node]));
66
+ if (!previous || forceFull) {
67
+ return {
68
+ generation,
69
+ pageRevision,
70
+ full: true,
71
+ added: current,
72
+ changed: [],
73
+ removed: [],
74
+ };
75
+ }
76
+ const added = [];
77
+ const changed = [];
78
+ for (const node of current) {
79
+ const old = previous.get(node.id);
80
+ if (!old)
81
+ added.push(node);
82
+ else if (nodeKey(old) !== nodeKey(node))
83
+ changed.push(node);
84
+ }
85
+ const removed = [...previous.keys()].filter((id) => !next.has(id));
86
+ return { generation, pageRevision, full: false, added, changed, removed };
87
+ }
88
+ export function conciseAxTree(nodes) {
89
+ return nodes
90
+ .map((node, index) => {
91
+ const details = [node.role, node.name, node.value]
92
+ .filter(Boolean)
93
+ .join(' ');
94
+ return `[ax=${node.id}]${details ? ` ${details}` : ''} index=${index}${node.ignored ? ' (ignored)' : ''}`;
95
+ })
96
+ .join('\n');
97
+ }
@@ -0,0 +1,142 @@
1
+ /** Compact AX state and generation-aware diffs for BrowserBatch observations. */
2
+
3
+ export interface BrowserAxNode {
4
+ id: string;
5
+ parentId?: string;
6
+ role?: string;
7
+ name?: string;
8
+ value?: string;
9
+ ignored?: boolean;
10
+ backendDOMNodeId?: number;
11
+ bounds?: { x: number; y: number; width: number; height: number };
12
+ }
13
+
14
+ export interface BrowserAxDiff {
15
+ generation: number;
16
+ pageRevision: number;
17
+ full: boolean;
18
+ added: BrowserAxNode[];
19
+ changed: BrowserAxNode[];
20
+ removed: string[];
21
+ }
22
+
23
+ type RawAxProperty = { name?: unknown; value?: { value?: unknown } };
24
+ type RawAxNode = {
25
+ nodeId?: unknown;
26
+ id?: unknown;
27
+ parentId?: unknown;
28
+ role?: unknown;
29
+ name?: unknown;
30
+ ignored?: unknown;
31
+ backendDOMNodeId?: unknown;
32
+ bounds?: { x?: unknown; y?: unknown; width?: unknown; height?: unknown };
33
+ properties?: RawAxProperty[];
34
+ };
35
+
36
+ function axValue(input: unknown): unknown {
37
+ if (input && typeof input === 'object' && 'value' in input)
38
+ return (input as { value?: unknown }).value;
39
+ return input;
40
+ }
41
+
42
+ function propertyValue(node: RawAxNode, key: string): string | undefined {
43
+ const value = node.properties?.find((item) => item.name === key)?.value
44
+ ?.value;
45
+ return value === undefined || value === null ? undefined : String(value);
46
+ }
47
+
48
+ export function normalizeAxTree(raw: unknown): BrowserAxNode[] {
49
+ const root =
50
+ raw && typeof raw === 'object' ? (raw as { nodes?: unknown }) : {};
51
+ const nodes = Array.isArray(raw)
52
+ ? raw
53
+ : Array.isArray(root.nodes)
54
+ ? root.nodes
55
+ : [];
56
+ return nodes
57
+ .map((value: unknown) => {
58
+ const node =
59
+ value && typeof value === 'object' ? (value as RawAxNode) : {};
60
+ const bounds = node?.bounds;
61
+ return {
62
+ id: String(node.nodeId ?? node.id ?? ''),
63
+ ...(node.parentId !== undefined
64
+ ? { parentId: String(node.parentId) }
65
+ : {}),
66
+ ...(axValue(node.role) || node.role
67
+ ? { role: String(axValue(node.role) ?? node.role) }
68
+ : {}),
69
+ ...(axValue(node.name) || node.name
70
+ ? { name: String(axValue(node.name) ?? node.name) }
71
+ : {}),
72
+ ...(propertyValue(node, 'value')
73
+ ? { value: propertyValue(node, 'value') }
74
+ : {}),
75
+ ...(node.ignored !== undefined
76
+ ? { ignored: Boolean(node.ignored) }
77
+ : {}),
78
+ ...(node.backendDOMNodeId !== undefined
79
+ ? { backendDOMNodeId: Number(node.backendDOMNodeId) }
80
+ : {}),
81
+ ...(bounds &&
82
+ typeof bounds.x === 'number' &&
83
+ typeof bounds.y === 'number' &&
84
+ typeof bounds.width === 'number' &&
85
+ typeof bounds.height === 'number'
86
+ ? {
87
+ bounds: {
88
+ x: bounds.x,
89
+ y: bounds.y,
90
+ width: bounds.width,
91
+ height: bounds.height,
92
+ },
93
+ }
94
+ : {}),
95
+ } satisfies BrowserAxNode;
96
+ })
97
+ .filter((node: BrowserAxNode) => node.id.length > 0);
98
+ }
99
+
100
+ function nodeKey(node: BrowserAxNode): string {
101
+ return JSON.stringify(node);
102
+ }
103
+
104
+ export function diffAxTree(
105
+ previous: Map<string, BrowserAxNode> | undefined,
106
+ current: BrowserAxNode[],
107
+ generation: number,
108
+ pageRevision: number,
109
+ forceFull = false,
110
+ ): BrowserAxDiff {
111
+ const next = new Map(current.map((node) => [node.id, node]));
112
+ if (!previous || forceFull) {
113
+ return {
114
+ generation,
115
+ pageRevision,
116
+ full: true,
117
+ added: current,
118
+ changed: [],
119
+ removed: [],
120
+ };
121
+ }
122
+ const added: BrowserAxNode[] = [];
123
+ const changed: BrowserAxNode[] = [];
124
+ for (const node of current) {
125
+ const old = previous.get(node.id);
126
+ if (!old) added.push(node);
127
+ else if (nodeKey(old) !== nodeKey(node)) changed.push(node);
128
+ }
129
+ const removed = [...previous.keys()].filter((id) => !next.has(id));
130
+ return { generation, pageRevision, full: false, added, changed, removed };
131
+ }
132
+
133
+ export function conciseAxTree(nodes: BrowserAxNode[]): string {
134
+ return nodes
135
+ .map((node, index) => {
136
+ const details = [node.role, node.name, node.value]
137
+ .filter(Boolean)
138
+ .join(' ');
139
+ return `[ax=${node.id}]${details ? ` ${details}` : ''} index=${index}${node.ignored ? ' (ignored)' : ''}`;
140
+ })
141
+ .join('\n');
142
+ }