minimal-agent 0.13.0 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (470) hide show
  1. package/README.md +6 -5
  2. package/package.json +60 -4
  3. package/plugins/computer_use/.claude-plugin/plugin.json +1 -1
  4. package/plugins/cron-runner/src/commands.js +4 -4
  5. package/plugins/cron-runner/src/commands.ts +4 -4
  6. package/plugins/workflow-runner/.claude-plugin/plugin.json +2 -2
  7. package/plugins/workflow-runner/commands/workflow.md +57 -90
  8. package/plugins/workflow-runner/commands/workflows.md +4 -4
  9. package/plugins/workflow-runner/plugin.js +24 -13
  10. package/plugins/workflow-runner/plugin.ts +28 -13
  11. package/plugins/workflow-runner/src/discovery.js +160 -0
  12. package/plugins/workflow-runner/src/discovery.ts +194 -0
  13. package/plugins/workflow-runner/src/goalAnchor.js +53 -0
  14. package/plugins/workflow-runner/src/goalAnchor.ts +59 -0
  15. package/plugins/workflow-runner/src/index.js +197 -206
  16. package/plugins/workflow-runner/src/index.ts +248 -249
  17. package/plugins/workflow-runner/src/inputCoercion.js +40 -0
  18. package/plugins/workflow-runner/src/inputCoercion.ts +43 -0
  19. package/plugins/workflow-runner/src/journal.js +224 -0
  20. package/plugins/workflow-runner/src/journal.ts +274 -0
  21. package/plugins/workflow-runner/src/jsonSchema.js +132 -0
  22. package/plugins/workflow-runner/src/jsonSchema.ts +162 -0
  23. package/plugins/workflow-runner/src/moduleResolution.js +64 -0
  24. package/plugins/workflow-runner/src/moduleResolution.ts +71 -0
  25. package/plugins/workflow-runner/src/resourceInputs.js +220 -0
  26. package/plugins/workflow-runner/src/resourceInputs.ts +300 -0
  27. package/plugins/workflow-runner/src/runner.js +400 -489
  28. package/plugins/workflow-runner/src/runner.ts +488 -560
  29. package/plugins/workflow-runner/src/runtime/config.js +46 -0
  30. package/plugins/workflow-runner/src/runtime/config.ts +69 -0
  31. package/plugins/workflow-runner/src/runtime/context.js +1304 -0
  32. package/plugins/workflow-runner/src/runtime/context.ts +1786 -0
  33. package/plugins/workflow-runner/src/runtime/exec.js +34 -0
  34. package/plugins/workflow-runner/src/runtime/exec.ts +53 -0
  35. package/plugins/workflow-runner/src/runtime/flow.js +8 -0
  36. package/plugins/workflow-runner/src/runtime/flow.ts +12 -0
  37. package/plugins/workflow-runner/src/runtime/fs.js +27 -0
  38. package/plugins/workflow-runner/src/runtime/fs.ts +41 -0
  39. package/plugins/workflow-runner/src/runtime/model.js +6 -0
  40. package/plugins/workflow-runner/src/runtime/model.ts +8 -0
  41. package/plugins/workflow-runner/src/runtime/output.js +7 -0
  42. package/plugins/workflow-runner/src/runtime/output.ts +21 -0
  43. package/plugins/workflow-runner/src/runtime/scheduler.js +141 -0
  44. package/plugins/workflow-runner/src/runtime/scheduler.ts +166 -0
  45. package/plugins/workflow-runner/src/runtime/state.js +16 -0
  46. package/plugins/workflow-runner/src/runtime/state.ts +19 -0
  47. package/plugins/workflow-runner/src/runtime/tools.js +3 -0
  48. package/plugins/workflow-runner/src/runtime/tools.ts +6 -0
  49. package/plugins/workflow-runner/src/sandbox.js +141 -0
  50. package/plugins/workflow-runner/src/sandbox.ts +182 -0
  51. package/plugins/workflow-runner/src/scriptGuard.d.mts +38 -0
  52. package/plugins/workflow-runner/src/scriptGuard.mjs +449 -0
  53. package/plugins/workflow-runner/src/taskIdentity.js +151 -307
  54. package/plugins/workflow-runner/src/taskIdentity.ts +207 -355
  55. package/plugins/workflow-runner/src/toolRuntime.js +29 -8
  56. package/plugins/workflow-runner/src/toolRuntime.ts +36 -11
  57. package/plugins/workflow-runner/src/types.js +7 -211
  58. package/plugins/workflow-runner/src/types.ts +154 -623
  59. package/plugins/workflow-runner/src/util.js +47 -0
  60. package/plugins/workflow-runner/src/util.ts +51 -0
  61. package/plugins/workflow-runner/src/workflowContext.js +20 -0
  62. package/plugins/workflow-runner/src/workflowContext.ts +58 -0
  63. package/plugins/workflow-runner/src/workflowDependencies.js +36 -0
  64. package/plugins/workflow-runner/src/workflowDependencies.ts +59 -0
  65. package/plugins/workflow-runner/src/workflowFingerprint.js +118 -0
  66. package/plugins/workflow-runner/src/workflowFingerprint.ts +122 -0
  67. package/plugins/workflow-runner/src/workflowState.js +474 -802
  68. package/plugins/workflow-runner/src/workflowState.ts +575 -970
  69. package/plugins/workflow-runner/test/api.test.ts +223 -0
  70. package/plugins/workflow-runner/test/apiCapabilities.test.ts +614 -0
  71. package/plugins/workflow-runner/test/apiConcurrencyGate.test.ts +104 -0
  72. package/plugins/workflow-runner/test/apiEcho.test.ts +210 -0
  73. package/plugins/workflow-runner/test/apiReadText.test.ts +178 -0
  74. package/plugins/workflow-runner/test/apiResourceLedger.test.ts +184 -0
  75. package/plugins/workflow-runner/test/childWorkflow.test.ts +304 -0
  76. package/plugins/workflow-runner/test/discovery.test.ts +234 -0
  77. package/plugins/workflow-runner/test/goalAnchor.test.ts +106 -0
  78. package/plugins/workflow-runner/test/goalController.test.ts +317 -0
  79. package/plugins/workflow-runner/test/journalLanes.test.ts +198 -0
  80. package/plugins/workflow-runner/test/listResources.test.ts +106 -0
  81. package/plugins/workflow-runner/test/resourceInputs.test.ts +294 -0
  82. package/plugins/workflow-runner/test/sandbox.test.ts +126 -0
  83. package/plugins/workflow-runner/test/scheduler.test.ts +70 -0
  84. package/plugins/workflow-runner/test/scriptGuard.test.ts +276 -0
  85. package/plugins/workflow-runner/test/skillDocSync.test.ts +78 -0
  86. package/plugins/workflow-runner/test/taskIdentity.test.ts +288 -179
  87. package/plugins/workflow-runner/test/workflowFingerprint.test.ts +106 -0
  88. package/plugins/workflow-runner/test/workflowState.test.ts +429 -0
  89. package/skills/pptx/examples/assets/cover-bg.svg +23 -0
  90. package/skills/pptx/examples/assets/icon-spark.svg +5 -0
  91. package/skills/ui-design/SKILL.md +5 -2
  92. package/skills/ui-design/references/layout-composition.md +1 -1
  93. package/skills/workflow-creator/SKILL.md +344 -0
  94. package/skills/workflow-creator/assets/template/workflow.mjs +48 -0
  95. package/skills/workflow-creator/references/api.md +216 -0
  96. package/skills/workflow-creator/references/migration.md +103 -0
  97. package/skills/workflow-creator/references/patterns.md +779 -0
  98. package/skills/workflow-creator/scripts/list-resources.mjs +205 -0
  99. package/skills/workflow-creator/scripts/scaffold.mjs +148 -0
  100. package/skills/workflow-creator/scripts/validate.mjs +275 -0
  101. package/skills/workflow-creator/scripts/workflow-creator.test.mjs +82 -0
  102. package/src/advisor/advisorCoordinator.js +503 -0
  103. package/src/advisor/advisorCoordinator.ts +657 -0
  104. package/src/cli/configMenu.tsx +0 -1
  105. package/src/cli/print.js +27 -6
  106. package/src/cli/print.ts +48 -4
  107. package/src/cli/streamJson.js +5 -6
  108. package/src/cli/streamJson.ts +8 -4
  109. package/src/cli/wizards/advisorWizard.js +4 -2
  110. package/src/cli/wizards/advisorWizard.tsx +8 -2
  111. package/src/cli/wizards/contextAdvisorWizard.js +5 -4
  112. package/src/cli/wizards/contextAdvisorWizard.tsx +7 -6
  113. package/src/collaboration/taskFlow.js +115 -0
  114. package/src/collaboration/taskFlow.ts +169 -0
  115. package/src/config/configDefaults.js +41 -1
  116. package/src/config/configDefaults.ts +43 -1
  117. package/src/config/configDiagnostics.ts +2 -2
  118. package/src/config/configFile.js +40 -9
  119. package/src/config/configFile.ts +60 -11
  120. package/src/config/configService.js +419 -74
  121. package/src/config/configService.ts +703 -145
  122. package/src/config/numericLimits.js +22 -0
  123. package/src/config/numericLimits.ts +24 -0
  124. package/src/config.js +1 -0
  125. package/src/config.ts +3 -2
  126. package/src/context/budgetPlan.js +1 -1
  127. package/src/context/budgetPlan.ts +1 -1
  128. package/src/context/compact.js +7 -2
  129. package/src/context/compact.ts +9 -2
  130. package/src/context/microCompactLite.js +212 -13
  131. package/src/context/microCompactLite.ts +261 -12
  132. package/src/context/sessionRegistry.js +8 -1
  133. package/src/context/sessionRegistry.ts +18 -5
  134. package/src/context/toolResultArchive.js +72 -0
  135. package/src/context/toolResultArchive.ts +95 -0
  136. package/src/goal/errors.js +8 -0
  137. package/src/goal/errors.ts +18 -0
  138. package/src/goal/goalRuntime.js +344 -0
  139. package/src/goal/goalRuntime.ts +466 -0
  140. package/src/goal/goalStore.js +200 -0
  141. package/src/goal/goalStore.ts +219 -0
  142. package/src/goal/index.js +4 -0
  143. package/src/goal/index.ts +4 -0
  144. package/src/goal/statusMapping.js +71 -0
  145. package/src/goal/statusMapping.ts +95 -0
  146. package/src/goal/types.js +7 -0
  147. package/src/goal/types.ts +179 -0
  148. package/src/goal/workflowController.js +306 -0
  149. package/src/goal/workflowController.ts +360 -0
  150. package/src/harness/evidenceLedger.js +2 -0
  151. package/src/harness/evidenceLedger.ts +1 -0
  152. package/src/harness/stallGuard.js +9 -3
  153. package/src/harness/stallGuard.ts +7 -3
  154. package/src/images/imageResolver.js +161 -0
  155. package/src/images/imageResolver.ts +189 -0
  156. package/src/infra/verification.js +34 -5
  157. package/src/infra/verification.ts +39 -4
  158. package/src/llm/client.js +79 -21
  159. package/src/llm/client.ts +182 -35
  160. package/src/llm/gatewayClient.js +201 -0
  161. package/src/llm/gatewayClient.ts +299 -0
  162. package/src/llm/messageProvenance.js +46 -0
  163. package/src/llm/messageProvenance.ts +58 -0
  164. package/src/llm/modelProvider.js +1 -0
  165. package/src/llm/modelProvider.ts +22 -0
  166. package/src/llm/providers/anthropicFormat.js +108 -1
  167. package/src/llm/providers/anthropicFormat.ts +115 -4
  168. package/src/llm/providers/openaiFormat.js +9 -0
  169. package/src/llm/providers/openaiFormat.ts +12 -3
  170. package/src/loop.js +319 -54
  171. package/src/loop.ts +373 -57
  172. package/src/main.js +4 -1
  173. package/src/main.tsx +4 -1
  174. package/src/managedExecution/index.js +2 -0
  175. package/src/managedExecution/index.ts +2 -0
  176. package/src/managedExecution/registry.js +15 -0
  177. package/src/managedExecution/registry.ts +20 -0
  178. package/src/managedExecution/types.js +1 -0
  179. package/src/managedExecution/types.ts +86 -0
  180. package/src/modelRef.js +9 -0
  181. package/src/modelRef.ts +31 -0
  182. package/src/multimodal.js +14 -28
  183. package/src/multimodal.ts +17 -33
  184. package/src/net/lanDiscovery.js +65 -0
  185. package/src/net/lanDiscovery.ts +82 -0
  186. package/src/plugin-sdk.js +28 -3
  187. package/src/plugin-sdk.ts +39 -6
  188. package/src/plugins/pluginApi.ts +16 -1
  189. package/src/plugins/pluginLoader.js +4 -0
  190. package/src/plugins/pluginLoader.ts +6 -0
  191. package/src/plugins/pluginRunner.js +139 -7
  192. package/src/plugins/pluginRunner.ts +173 -9
  193. package/src/plugins/slashFallback.js +113 -0
  194. package/src/plugins/slashFallback.ts +137 -0
  195. package/src/prompts/policyRegistry.js +12 -32
  196. package/src/prompts/policyRegistry.ts +15 -32
  197. package/src/prompts/promptAssembly.js +103 -12
  198. package/src/prompts/promptAssembly.ts +114 -12
  199. package/src/prompts/skillList.js +21 -3
  200. package/src/prompts/skillList.ts +27 -2
  201. package/src/prompts/stableSystemPrompt.js +18 -0
  202. package/src/prompts/stableSystemPrompt.ts +33 -0
  203. package/src/runtime/agentRuntimeContext.js +8 -2
  204. package/src/runtime/agentRuntimeContext.ts +17 -4
  205. package/src/session/runAgentTurn.js +78 -12
  206. package/src/session/runAgentTurn.ts +105 -23
  207. package/src/session/runTurn.js +10 -9
  208. package/src/session/runTurn.ts +17 -8
  209. package/src/session/sessionState.ts +2 -0
  210. package/src/team/auth.js +186 -0
  211. package/src/team/auth.ts +298 -0
  212. package/src/team/cli.js +105 -0
  213. package/src/team/cli.ts +122 -0
  214. package/src/team/onlineToolContract.js +64 -0
  215. package/src/team/onlineToolContract.ts +109 -0
  216. package/src/team/toolPolicy.js +36 -0
  217. package/src/team/toolPolicy.ts +75 -0
  218. package/src/tools/advisor/advisor.js +90 -46
  219. package/src/tools/advisor/advisor.ts +100 -47
  220. package/src/tools/advisor/advisorDecision.js +71 -0
  221. package/src/tools/advisor/advisorDecision.ts +85 -0
  222. package/src/tools/agent/agent.js +18 -5
  223. package/src/tools/agent/agent.ts +21 -7
  224. package/src/tools/agent/agentControl.js +246 -0
  225. package/src/tools/agent/agentControl.ts +284 -0
  226. package/src/tools/agent/agentTaskService.js +40 -1
  227. package/src/tools/agent/agentTaskService.ts +44 -1
  228. package/src/tools/agent/agentTypes.js +14 -2
  229. package/src/tools/agent/agentTypes.ts +15 -2
  230. package/src/tools/applypatch/applyPatch.js +362 -0
  231. package/src/tools/applypatch/applyPatch.ts +428 -0
  232. package/src/tools/bash/bash.js +22 -15
  233. package/src/tools/bash/bash.ts +23 -17
  234. package/src/tools/capabilities.js +10 -5
  235. package/src/tools/capabilities.ts +10 -5
  236. package/src/tools/computeruse/computerIntent.js +32 -0
  237. package/src/tools/computeruse/computerIntent.ts +46 -0
  238. package/src/tools/computeruse/telemetryLog.js +12 -0
  239. package/src/tools/computeruse/telemetryLog.ts +16 -0
  240. package/src/tools/computeruse/vision/telemetry.js +1 -0
  241. package/src/tools/computeruse/vision/telemetry.ts +1 -0
  242. package/src/tools/effectiveToolSet.js +4 -0
  243. package/src/tools/effectiveToolSet.ts +4 -0
  244. package/src/tools/index.js +21 -2
  245. package/src/tools/index.ts +33 -2
  246. package/src/tools/presentresult/presentresult.js +6 -15
  247. package/src/tools/presentresult/presentresult.ts +6 -15
  248. package/src/tools/read/read.js +62 -9
  249. package/src/tools/read/read.ts +63 -9
  250. package/src/tools/shared/fileUtils.js +1 -2
  251. package/src/tools/shared/fileUtils.ts +1 -2
  252. package/src/tools/shared/toolOutputStore.js +23 -1
  253. package/src/tools/shared/toolOutputStore.ts +22 -1
  254. package/src/tools/skill/skill.js +9 -3
  255. package/src/tools/skill/skill.ts +8 -4
  256. package/src/tools/toolPromptGuides.js +117 -0
  257. package/src/tools/toolPromptGuides.ts +137 -0
  258. package/src/tools/webbrowser/agentBrowserPath.js +19 -9
  259. package/src/tools/webbrowser/agentBrowserPath.ts +70 -28
  260. package/src/tools/webbrowser/browser.js +27 -11
  261. package/src/tools/webbrowser/browser.ts +68 -24
  262. package/src/tools/webbrowser/browserAutomation.js +329 -0
  263. package/src/tools/webbrowser/browserAutomation.ts +467 -0
  264. package/src/tools/webbrowser/browserAxState.js +97 -0
  265. package/src/tools/webbrowser/browserAxState.ts +142 -0
  266. package/src/tools/webbrowser/browserBatch.js +1578 -0
  267. package/src/tools/webbrowser/browserBatch.ts +2382 -0
  268. package/src/tools/webbrowser/browserCdp.js +208 -0
  269. package/src/tools/webbrowser/browserCdp.ts +255 -0
  270. package/src/tools/webbrowser/browserConditions.js +24 -0
  271. package/src/tools/webbrowser/browserConditions.ts +45 -0
  272. package/src/tools/webbrowser/browserContent.js +281 -0
  273. package/src/tools/webbrowser/browserContent.ts +438 -0
  274. package/src/tools/webbrowser/browserControl.js +131 -34
  275. package/src/tools/webbrowser/browserControl.ts +210 -56
  276. package/src/tools/webbrowser/browserDaemon.js +22 -14
  277. package/src/tools/webbrowser/browserDaemon.ts +54 -21
  278. package/src/tools/webbrowser/browserFrames.js +47 -0
  279. package/src/tools/webbrowser/browserFrames.ts +54 -0
  280. package/src/tools/webbrowser/browserInteractionResolver.js +17 -0
  281. package/src/tools/webbrowser/browserInteractionResolver.ts +40 -0
  282. package/src/tools/webbrowser/browserLocator.js +140 -0
  283. package/src/tools/webbrowser/browserLocator.ts +194 -0
  284. package/src/tools/webbrowser/browserOutcome.js +10 -17
  285. package/src/tools/webbrowser/browserOutcome.ts +48 -31
  286. package/src/tools/webbrowser/browserRecovery.js +58 -0
  287. package/src/tools/webbrowser/browserRecovery.ts +83 -0
  288. package/src/tools/webbrowser/browserRunRegistry.js +35 -3
  289. package/src/tools/webbrowser/browserRunRegistry.ts +91 -15
  290. package/src/tools/webbrowser/browserService.js +28 -2
  291. package/src/tools/webbrowser/browserService.ts +49 -9
  292. package/src/tools/webbrowser/browserStream.js +132 -33
  293. package/src/tools/webbrowser/browserStream.ts +224 -50
  294. package/src/tools/webbrowser/browserTabs.js +48 -15
  295. package/src/tools/webbrowser/browserTabs.ts +178 -96
  296. package/src/tools/webbrowser/webbrowser.js +679 -144
  297. package/src/tools/webbrowser/webbrowser.ts +975 -236
  298. package/src/tools/webfetch/preapproved.js +0 -2
  299. package/src/tools/webfetch/preapproved.ts +0 -2
  300. package/src/tools/websearch/websearch.js +129 -8
  301. package/src/tools/websearch/websearch.ts +138 -6
  302. package/src/types.ts +440 -38
  303. package/src/ui/App.js +377 -58
  304. package/src/ui/App.tsx +576 -111
  305. package/src/ui/LiveArea.js +14 -8
  306. package/src/ui/LiveArea.tsx +14 -10
  307. package/src/ui/MessageList.js +63 -20
  308. package/src/ui/MessageList.tsx +101 -16
  309. package/src/ui/ModelPicker.js +7 -4
  310. package/src/ui/ModelPicker.tsx +55 -8
  311. package/src/ui/hooks/useChat.js +152 -163
  312. package/src/ui/hooks/useChat.ts +396 -334
  313. package/src/ui/loginCommand.js +56 -0
  314. package/src/ui/loginCommand.ts +63 -0
  315. package/src/ui/toolProgress.js +41 -0
  316. package/src/ui/toolProgress.ts +44 -0
  317. package/src/web/browserBridge.js +20 -2
  318. package/src/web/browserBridge.ts +20 -2
  319. package/src/web/protocol.ts +1897 -194
  320. package/workflows/adaptive-research/workflow.mjs +86 -0
  321. package/workflows/e2e-capabilities/workflow.mjs +102 -0
  322. package/workflows/e2e-llm/workflow.mjs +52 -0
  323. package/workflows/e2e-smoke/workflow.mjs +59 -0
  324. package/workflows/e2e-vision-schema/README.md +48 -0
  325. package/workflows/e2e-vision-schema/workflow.mjs +149 -0
  326. package/workflows/e2e-write-greet/workflow.mjs +37 -0
  327. package/workflows/file-census/README.md +14 -0
  328. package/workflows/file-census/scripts/.gitkeep +2 -0
  329. package/workflows/file-census/workflow.mjs +110 -0
  330. package/workflows/goal/README.md +166 -0
  331. package/workflows/goal/prompts/audit.md +57 -0
  332. package/workflows/goal/prompts/contract.md +56 -0
  333. package/workflows/goal/prompts/iterate.md +37 -0
  334. package/workflows/goal/workflow.mjs +501 -0
  335. package/workflows/illustrate/README.md +90 -0
  336. package/workflows/illustrate/assets/engines.json +20 -0
  337. package/workflows/illustrate/assets/extract-baidu.js +21 -0
  338. package/workflows/illustrate/assets/extract-bing.js +33 -0
  339. package/workflows/illustrate/assets/extract-google.js +31 -0
  340. package/workflows/illustrate/workflow.mjs +301 -0
  341. package/workflows/plan/workflow.mjs +389 -0
  342. package/workflows/question-crops/README.md +35 -0
  343. package/workflows/question-crops/prompts/inventory.md +23 -0
  344. package/workflows/question-crops/scripts/image-ops.mjs +305 -0
  345. package/workflows/question-crops/scripts/image-ops.test.mjs +95 -0
  346. package/workflows/question-crops/workflow.mjs +172 -0
  347. package/workflows/ralph-loop/workflow.mjs +162 -0
  348. package/workflows/research/README.md +74 -0
  349. package/workflows/research/prompts/s0-goal.md +43 -0
  350. package/workflows/research/prompts/s1-early-exit.md +22 -0
  351. package/workflows/research/prompts/s1-map.md +58 -0
  352. package/workflows/research/prompts/s2-options.md +53 -0
  353. package/workflows/research/prompts/s3-deep-dive.md +56 -0
  354. package/workflows/research/prompts/s4-verify.md +74 -0
  355. package/workflows/research/prompts/s5-synthesis.md +81 -0
  356. package/workflows/research/prompts/s5b-fill-gaps.md +32 -0
  357. package/workflows/research/prompts/s6-package.md +32 -0
  358. package/workflows/research/scripts/build-report.mjs +98 -0
  359. package/workflows/research/workflow.mjs +288 -0
  360. package/workflows/wechat-reading-shots/prompts/collect-params.md +16 -0
  361. package/workflows/wechat-reading-shots/prompts/evaluate.md +20 -0
  362. package/workflows/wechat-reading-shots/prompts/open-book.md +28 -0
  363. package/workflows/wechat-reading-shots/prompts/read-page.md +13 -0
  364. package/workflows/wechat-reading-shots/prompts/turn-batch.md +24 -0
  365. package/workflows/wechat-reading-shots/test/control-flow.test.ts +329 -0
  366. package/workflows/wechat-reading-shots/workflow.mjs +266 -0
  367. package/workflows/wrong-question-docx/README.md +55 -0
  368. package/workflows/wrong-question-docx/prompts/figure-qa.md +8 -0
  369. package/workflows/wrong-question-docx/prompts/transcribe.md +25 -0
  370. package/workflows/wrong-question-docx/scripts/workbook.mjs +857 -0
  371. package/workflows/wrong-question-docx/test/control-flow.test.ts +165 -0
  372. package/workflows/wrong-question-docx/test/workbook.test.mjs +303 -0
  373. package/workflows/wrong-question-docx/workflow.mjs +485 -0
  374. package/plugins/workflow-runner/src/agentCommon.js +0 -354
  375. package/plugins/workflow-runner/src/agentCommon.ts +0 -435
  376. package/plugins/workflow-runner/src/controlFlow/branch.js +0 -40
  377. package/plugins/workflow-runner/src/controlFlow/branch.ts +0 -46
  378. package/plugins/workflow-runner/src/controlFlow/loop.js +0 -211
  379. package/plugins/workflow-runner/src/controlFlow/loop.ts +0 -248
  380. package/plugins/workflow-runner/src/controlFlow/pause.js +0 -129
  381. package/plugins/workflow-runner/src/controlFlow/pause.ts +0 -141
  382. package/plugins/workflow-runner/src/controlFlow/signal.js +0 -21
  383. package/plugins/workflow-runner/src/controlFlow/signal.ts +0 -29
  384. package/plugins/workflow-runner/src/controlFlow/types.js +0 -18
  385. package/plugins/workflow-runner/src/controlFlow/types.ts +0 -63
  386. package/plugins/workflow-runner/src/dslManifest.js +0 -72
  387. package/plugins/workflow-runner/src/dslManifest.ts +0 -127
  388. package/plugins/workflow-runner/src/expressions.js +0 -639
  389. package/plugins/workflow-runner/src/expressions.ts +0 -640
  390. package/plugins/workflow-runner/src/loader.js +0 -573
  391. package/plugins/workflow-runner/src/loader.ts +0 -721
  392. package/plugins/workflow-runner/src/multimodal.js +0 -38
  393. package/plugins/workflow-runner/src/multimodal.ts +0 -64
  394. package/plugins/workflow-runner/src/recovery.js +0 -126
  395. package/plugins/workflow-runner/src/recovery.ts +0 -156
  396. package/plugins/workflow-runner/src/stepExecutors/agent.js +0 -173
  397. package/plugins/workflow-runner/src/stepExecutors/agent.ts +0 -234
  398. package/plugins/workflow-runner/src/stepExecutors/assert.js +0 -42
  399. package/plugins/workflow-runner/src/stepExecutors/assert.ts +0 -52
  400. package/plugins/workflow-runner/src/stepExecutors/echo.js +0 -31
  401. package/plugins/workflow-runner/src/stepExecutors/echo.ts +0 -38
  402. package/plugins/workflow-runner/src/stepExecutors/llm.js +0 -99
  403. package/plugins/workflow-runner/src/stepExecutors/llm.ts +0 -133
  404. package/plugins/workflow-runner/src/stepExecutors/set.js +0 -49
  405. package/plugins/workflow-runner/src/stepExecutors/set.ts +0 -56
  406. package/plugins/workflow-runner/src/stepExecutors/skill.js +0 -111
  407. package/plugins/workflow-runner/src/stepExecutors/skill.ts +0 -140
  408. package/plugins/workflow-runner/src/stepExecutors/tool.js +0 -227
  409. package/plugins/workflow-runner/src/stepExecutors/tool.ts +0 -274
  410. package/plugins/workflow-runner/src/stepExecutors/verify.js +0 -61
  411. package/plugins/workflow-runner/src/stepExecutors/verify.ts +0 -72
  412. package/plugins/workflow-runner/src/stepPipeline.js +0 -277
  413. package/plugins/workflow-runner/src/stepPipeline.ts +0 -366
  414. package/plugins/workflow-runner/test/agent.test.ts +0 -587
  415. package/plugins/workflow-runner/test/agentLlmError.test.ts +0 -373
  416. package/plugins/workflow-runner/test/bashBlacklist.sweep.test.ts +0 -65
  417. package/plugins/workflow-runner/test/captureMisbind.test.ts +0 -99
  418. package/plugins/workflow-runner/test/cli.e2e.test.ts +0 -167
  419. package/plugins/workflow-runner/test/context-files.test.ts +0 -320
  420. package/plugins/workflow-runner/test/e2e.test.ts +0 -370
  421. package/plugins/workflow-runner/test/e2eNewLayout.test.ts +0 -314
  422. package/plugins/workflow-runner/test/engineRobustness.test.ts +0 -234
  423. package/plugins/workflow-runner/test/expressions.test.ts +0 -439
  424. package/plugins/workflow-runner/test/foundation.test.ts +0 -126
  425. package/plugins/workflow-runner/test/graceful.test.ts +0 -139
  426. package/plugins/workflow-runner/test/greedyInputs.load.test.ts +0 -47
  427. package/plugins/workflow-runner/test/hostCapability.test.ts +0 -108
  428. package/plugins/workflow-runner/test/illustrate.load.test.ts +0 -183
  429. package/plugins/workflow-runner/test/jsonPayload.test.ts +0 -83
  430. package/plugins/workflow-runner/test/loader.test.ts +0 -617
  431. package/plugins/workflow-runner/test/maxTurnsRetryDelay.test.ts +0 -33
  432. package/plugins/workflow-runner/test/multimodal.test.ts +0 -342
  433. package/plugins/workflow-runner/test/output-schema.test.ts +0 -213
  434. package/plugins/workflow-runner/test/parseWorkflowArgs.test.ts +0 -106
  435. package/plugins/workflow-runner/test/pluginRunner.isolation.test.ts +0 -269
  436. package/plugins/workflow-runner/test/ppt.load.test.ts +0 -1220
  437. package/plugins/workflow-runner/test/ralphLoop.e2e.test.ts +0 -221
  438. package/plugins/workflow-runner/test/recovery.test.ts +0 -265
  439. package/plugins/workflow-runner/test/research.load.test.ts +0 -328
  440. package/plugins/workflow-runner/test/runner.test.ts +0 -911
  441. package/plugins/workflow-runner/test/runnerPreflight.test.ts +0 -436
  442. package/plugins/workflow-runner/test/skillTurnDone.test.ts +0 -71
  443. package/plugins/workflow-runner/test/stateLifecycle.test.ts +0 -198
  444. package/plugins/workflow-runner/test/stepPipeline.test.ts +0 -114
  445. package/plugins/workflow-runner/test/taskArbitration.test.ts +0 -354
  446. package/plugins/workflow-runner/test/taskLifecycle.test.ts +0 -324
  447. package/plugins/workflow-runner/test/toolArtifactOverwrite.test.ts +0 -221
  448. package/plugins/workflow-runner/test/toolCapabilityBoundary.test.ts +0 -29
  449. package/plugins/workflow-runner/test/toolRuntimeIntegration.test.ts +0 -168
  450. package/plugins/workflow-runner/test/webppt.load.test.ts +0 -250
  451. package/plugins/workflow-runner/test/word.load.test.ts +0 -208
  452. package/plugins/workflow-runner/test/workflows.smoke.test.ts +0 -76
  453. package/plugins/workflow-runner/test/yamlGuardConditions.test.ts +0 -207
  454. package/src/advisorState.js +0 -22
  455. package/src/cli/configWizard.js +0 -293
  456. package/src/tools/toolProgressBridge.js +0 -48
  457. package/workflows/adaptive-research.yaml +0 -50
  458. package/workflows/book-review-short.yaml +0 -125
  459. package/workflows/e2e-write-greet.yaml +0 -31
  460. package/workflows/illustrate.yaml +0 -227
  461. package/workflows/plan.yaml +0 -470
  462. package/workflows/ppt.yaml +0 -1670
  463. package/workflows/ralph-loop.yaml +0 -201
  464. package/workflows/research.yaml +0 -873
  465. package/workflows/schema.json +0 -176
  466. package/workflows/webppt.yaml +0 -496
  467. package/workflows/wechat-reading-shots.yaml +0 -315
  468. package/workflows/word.yaml +0 -720
  469. package/workflows/youtube-shorts.yaml +0 -202
  470. /package/workflows/{research.md → research/DESIGN.md} +0 -0
@@ -0,0 +1,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
+ }