minimal-agent 0.10.0 → 0.12.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 (573) hide show
  1. package/README.md +11 -3
  2. package/package.json +52 -5
  3. package/plugins/computer_use/.claude-plugin/plugin.json +6 -0
  4. package/plugins/computer_use/README.md +94 -0
  5. package/plugins/computer_use/app/_template.md +142 -0
  6. package/plugins/computer_use/app/chrome.md +165 -0
  7. package/plugins/computer_use/app/finder.md +76 -0
  8. package/plugins/computer_use/app/macos-system-settings.md +81 -0
  9. package/plugins/computer_use/app/microsoft-excel.md +80 -0
  10. package/plugins/computer_use/app/microsoft-powerpoint.md +80 -0
  11. package/plugins/computer_use/app/microsoft-word.md +79 -0
  12. package/plugins/computer_use/app/wechat.md +413 -0
  13. package/plugins/computer_use/app/weread.md +319 -0
  14. package/plugins/computer_use/commands/computeruse.md +25 -0
  15. package/plugins/computer_use/commands/cu.md +9 -0
  16. package/plugins/computer_use/plugin.js +26 -0
  17. package/plugins/computer_use/plugin.ts +30 -0
  18. package/plugins/computer_use/src/capture.js +90 -0
  19. package/plugins/computer_use/src/capture.ts +104 -0
  20. package/plugins/computer_use/src/commands.js +91 -0
  21. package/plugins/computer_use/src/commands.ts +103 -0
  22. package/plugins/computer_use/src/daemon.js +134 -0
  23. package/plugins/computer_use/src/daemon.ts +161 -0
  24. package/plugins/computer_use/src/manuals.js +135 -0
  25. package/plugins/computer_use/src/manuals.ts +159 -0
  26. package/plugins/computer_use/src/verify.js +168 -0
  27. package/plugins/computer_use/src/verify.ts +219 -0
  28. package/plugins/computer_use/test/commands.test.ts +73 -0
  29. package/plugins/cron-runner/plugin.ts +38 -0
  30. package/plugins/cron-runner/src/commands.ts +373 -0
  31. package/plugins/cron-runner/src/cronTime.ts +155 -0
  32. package/plugins/cron-runner/src/lock.ts +79 -0
  33. package/plugins/cron-runner/src/runs.ts +99 -0
  34. package/plugins/cron-runner/src/scheduleEngine.ts +76 -0
  35. package/plugins/cron-runner/src/scheduler.ts +376 -0
  36. package/plugins/cron-runner/src/schema.ts +139 -0
  37. package/plugins/cron-runner/src/service.ts +193 -0
  38. package/plugins/cron-runner/src/store.ts +333 -0
  39. package/plugins/cron-runner/src/types.ts +141 -0
  40. package/plugins/cron-runner/test/cronTime.test.ts +41 -0
  41. package/plugins/cron-runner/test/plugin-integration.test.ts +47 -0
  42. package/plugins/cron-runner/test/scheduleEngine.test.ts +41 -0
  43. package/plugins/cron-runner/test/service.test.ts +76 -0
  44. package/plugins/cron-runner/test/store-and-scheduler.test.ts +501 -0
  45. package/plugins/workflow-runner/plugin.js +56 -2
  46. package/plugins/workflow-runner/plugin.ts +113 -0
  47. package/plugins/workflow-runner/src/agentCommon.js +43 -4
  48. package/plugins/workflow-runner/src/agentCommon.ts +435 -0
  49. package/plugins/workflow-runner/src/controlFlow/branch.js +40 -0
  50. package/plugins/workflow-runner/src/controlFlow/branch.ts +46 -0
  51. package/plugins/workflow-runner/src/controlFlow/loop.js +211 -0
  52. package/plugins/workflow-runner/src/controlFlow/loop.ts +248 -0
  53. package/plugins/workflow-runner/src/controlFlow/pause.js +129 -0
  54. package/plugins/workflow-runner/src/controlFlow/pause.ts +141 -0
  55. package/plugins/workflow-runner/src/controlFlow/signal.js +21 -0
  56. package/plugins/workflow-runner/src/controlFlow/signal.ts +29 -0
  57. package/plugins/workflow-runner/src/controlFlow/types.js +18 -0
  58. package/plugins/workflow-runner/src/controlFlow/types.ts +63 -0
  59. package/plugins/workflow-runner/src/dslManifest.ts +127 -0
  60. package/plugins/workflow-runner/src/expressions.ts +622 -0
  61. package/plugins/workflow-runner/src/index.js +13 -4
  62. package/plugins/workflow-runner/src/index.ts +338 -0
  63. package/plugins/workflow-runner/src/jsonPayload.ts +84 -0
  64. package/plugins/workflow-runner/src/loader.js +23 -0
  65. package/plugins/workflow-runner/src/loader.ts +721 -0
  66. package/plugins/workflow-runner/src/multimodal.js +2 -1
  67. package/plugins/workflow-runner/src/multimodal.ts +64 -0
  68. package/plugins/workflow-runner/src/recovery.ts +149 -0
  69. package/plugins/workflow-runner/src/runner.js +75 -659
  70. package/plugins/workflow-runner/src/runner.ts +604 -0
  71. package/plugins/workflow-runner/src/stepExecutors/agent.ts +234 -0
  72. package/plugins/workflow-runner/src/stepExecutors/assert.ts +50 -0
  73. package/plugins/workflow-runner/src/stepExecutors/echo.js +31 -0
  74. package/plugins/workflow-runner/src/stepExecutors/echo.ts +38 -0
  75. package/plugins/workflow-runner/src/stepExecutors/llm.ts +133 -0
  76. package/plugins/workflow-runner/src/stepExecutors/set.js +49 -0
  77. package/plugins/workflow-runner/src/stepExecutors/set.ts +56 -0
  78. package/plugins/workflow-runner/src/stepExecutors/skill.js +5 -6
  79. package/plugins/workflow-runner/src/stepExecutors/skill.ts +140 -0
  80. package/plugins/workflow-runner/src/stepExecutors/tool.js +80 -8
  81. package/plugins/workflow-runner/src/stepExecutors/tool.ts +256 -0
  82. package/plugins/workflow-runner/src/stepExecutors/verify.ts +68 -0
  83. package/plugins/workflow-runner/src/stepPipeline.js +277 -0
  84. package/plugins/workflow-runner/src/stepPipeline.ts +366 -0
  85. package/plugins/workflow-runner/src/taskIdentity.ts +405 -0
  86. package/plugins/workflow-runner/src/toolRuntime.js +48 -0
  87. package/plugins/workflow-runner/src/toolRuntime.ts +64 -0
  88. package/plugins/workflow-runner/src/types.js +37 -1
  89. package/plugins/workflow-runner/src/types.ts +602 -0
  90. package/plugins/workflow-runner/src/workflowState.ts +733 -0
  91. package/plugins/workflow-runner/test/agent.test.ts +587 -0
  92. package/plugins/workflow-runner/test/agentLlmError.test.ts +373 -0
  93. package/plugins/workflow-runner/test/bashBlacklist.sweep.test.ts +65 -0
  94. package/plugins/workflow-runner/test/captureMisbind.test.ts +99 -0
  95. package/plugins/workflow-runner/test/cli.e2e.test.ts +147 -0
  96. package/plugins/workflow-runner/test/context-files.test.ts +320 -0
  97. package/plugins/workflow-runner/test/e2e.test.ts +370 -0
  98. package/plugins/workflow-runner/test/engineRobustness.test.ts +226 -0
  99. package/plugins/workflow-runner/test/expressions.test.ts +397 -0
  100. package/plugins/workflow-runner/test/foundation.test.ts +126 -0
  101. package/plugins/workflow-runner/test/graceful.test.ts +139 -0
  102. package/plugins/workflow-runner/test/greedyInputs.load.test.ts +47 -0
  103. package/plugins/workflow-runner/test/hostCapability.test.ts +108 -0
  104. package/plugins/workflow-runner/test/illustrate.load.test.ts +183 -0
  105. package/plugins/workflow-runner/test/jsonPayload.test.ts +83 -0
  106. package/plugins/workflow-runner/test/loader.test.ts +617 -0
  107. package/plugins/workflow-runner/test/maxTurnsRetryDelay.test.ts +33 -0
  108. package/plugins/workflow-runner/test/multimodal.test.ts +342 -0
  109. package/plugins/workflow-runner/test/output-schema.test.ts +213 -0
  110. package/plugins/workflow-runner/test/parseWorkflowArgs.test.ts +87 -0
  111. package/plugins/workflow-runner/test/pluginRunner.isolation.test.ts +269 -0
  112. package/plugins/workflow-runner/test/ppt.load.test.ts +1220 -0
  113. package/plugins/workflow-runner/test/ralphLoop.e2e.test.ts +220 -0
  114. package/plugins/workflow-runner/test/recovery.test.ts +265 -0
  115. package/plugins/workflow-runner/test/runner.test.ts +911 -0
  116. package/plugins/workflow-runner/test/runnerPreflight.test.ts +379 -0
  117. package/plugins/workflow-runner/test/skillTurnDone.test.ts +71 -0
  118. package/plugins/workflow-runner/test/stateLifecycle.test.ts +150 -0
  119. package/plugins/workflow-runner/test/stepPipeline.test.ts +114 -0
  120. package/plugins/workflow-runner/test/taskArbitration.test.ts +338 -0
  121. package/plugins/workflow-runner/test/taskIdentity.test.ts +237 -0
  122. package/plugins/workflow-runner/test/taskLifecycle.test.ts +270 -0
  123. package/plugins/workflow-runner/test/toolArtifactOverwrite.test.ts +221 -0
  124. package/plugins/workflow-runner/test/toolCapabilityBoundary.test.ts +29 -0
  125. package/plugins/workflow-runner/test/toolRuntimeIntegration.test.ts +168 -0
  126. package/plugins/workflow-runner/test/webppt.load.test.ts +250 -0
  127. package/plugins/workflow-runner/test/word.load.test.ts +208 -0
  128. package/plugins/workflow-runner/test/workflows.smoke.test.ts +76 -0
  129. package/plugins/workflow-runner/test/yamlGuardConditions.test.ts +207 -0
  130. package/skills/browser-automation/SKILL.md +9 -19
  131. package/skills/web-crawler/SKILL.md +9 -11
  132. package/src/askBridge.ts +249 -0
  133. package/src/bootstrap/cwdArg.js +10 -3
  134. package/src/bootstrap/cwdArg.ts +31 -0
  135. package/src/bootstrap/workingDir.ts +48 -0
  136. package/src/cli/args.js +70 -7
  137. package/src/cli/args.ts +146 -0
  138. package/src/cli/computerUse.js +185 -0
  139. package/src/cli/computerUse.ts +221 -0
  140. package/src/cli/configMenu.js +274 -202
  141. package/src/cli/configMenu.tsx +521 -0
  142. package/src/cli/memoryAccess.js +45 -0
  143. package/src/cli/memoryAccess.ts +53 -0
  144. package/src/cli/print.js +119 -5
  145. package/src/cli/print.ts +597 -0
  146. package/src/cli/quickModelSetup.js +60 -0
  147. package/src/cli/quickModelSetup.tsx +96 -0
  148. package/src/cli/streamJson.js +80 -4
  149. package/src/cli/streamJson.ts +433 -0
  150. package/src/cli/wizards/advisorWizard.js +1 -0
  151. package/src/cli/wizards/advisorWizard.tsx +195 -0
  152. package/src/cli/wizards/agentRuntimeWizard.js +84 -0
  153. package/src/cli/wizards/agentRuntimeWizard.tsx +134 -0
  154. package/src/cli/wizards/browserWizard.js +55 -0
  155. package/src/cli/wizards/browserWizard.tsx +77 -0
  156. package/src/cli/wizards/contextAdvisorWizard.js +84 -0
  157. package/src/cli/wizards/contextAdvisorWizard.tsx +124 -0
  158. package/src/cli/wizards/fieldForm.js +7 -4
  159. package/src/cli/wizards/fieldForm.tsx +250 -0
  160. package/src/cli/wizards/imageWizard.js +4 -5
  161. package/src/cli/wizards/imageWizard.tsx +96 -0
  162. package/src/cli/wizards/openRouterWizard.tsx +48 -0
  163. package/src/cli/wizards/providerPresets.js +1 -8
  164. package/src/cli/wizards/providerPresets.ts +106 -0
  165. package/src/cli/wizards/providerWizard.js +152 -205
  166. package/src/cli/wizards/providerWizard.tsx +266 -0
  167. package/src/cli/wizards/searchWizard.tsx +47 -0
  168. package/src/cli/wizards/ttsWizard.js +4 -3
  169. package/src/cli/wizards/ttsWizard.tsx +61 -0
  170. package/src/config/configDefaults.js +25 -0
  171. package/src/config/configDefaults.ts +33 -0
  172. package/src/config/configDiagnostics.js +117 -0
  173. package/src/config/configDiagnostics.ts +166 -0
  174. package/src/config/configFile.js +52 -32
  175. package/src/config/configFile.ts +633 -0
  176. package/src/config/configManagement.js +126 -0
  177. package/src/config/configManagement.ts +159 -0
  178. package/src/config/configService.js +66 -11
  179. package/src/config/configService.ts +554 -0
  180. package/src/config/numericLimits.js +61 -0
  181. package/src/config/numericLimits.ts +80 -0
  182. package/src/config.ts +109 -0
  183. package/src/context/agentHome.ts +11 -0
  184. package/src/context/archive.ts +144 -0
  185. package/src/context/budgetPlan.js +54 -0
  186. package/src/context/budgetPlan.ts +88 -0
  187. package/src/context/compact.js +179 -106
  188. package/src/context/compact.ts +584 -0
  189. package/src/context/contextBundle.js +119 -0
  190. package/src/context/contextBundle.ts +176 -0
  191. package/src/context/contextLock.ts +84 -0
  192. package/src/context/microCompactLite.ts +218 -0
  193. package/src/context/persistContext.ts +177 -0
  194. package/src/context/reactiveCompact.js +19 -4
  195. package/src/context/reactiveCompact.ts +240 -0
  196. package/src/context/recentDirs.ts +42 -0
  197. package/src/context/sessionPath.ts +206 -0
  198. package/src/context/sessionRegistry.js +8 -2
  199. package/src/context/sessionRegistry.ts +414 -0
  200. package/src/context/snipCompact.ts +163 -0
  201. package/src/context/tokenCounter.ts +106 -0
  202. package/src/context/workspaceIndex.js +2 -2
  203. package/src/context/workspaceIndex.ts +751 -0
  204. package/src/entry.compiled.tsx +20 -0
  205. package/src/harness/claimValidation.js +9 -0
  206. package/src/harness/claimValidation.ts +22 -0
  207. package/src/harness/evidenceLedger.js +92 -0
  208. package/src/harness/evidenceLedger.ts +96 -0
  209. package/src/harness/stallGuard.js +60 -0
  210. package/src/harness/stallGuard.ts +81 -0
  211. package/src/humanIntervention.js +129 -0
  212. package/src/humanIntervention.ts +216 -0
  213. package/src/infra/verification.ts +295 -0
  214. package/src/irreversible/rules.js +216 -0
  215. package/src/irreversible/rules.ts +261 -0
  216. package/src/llm/client.js +40 -3
  217. package/src/llm/client.ts +621 -0
  218. package/src/llm/promptCache.js +27 -0
  219. package/src/llm/promptCache.ts +41 -0
  220. package/src/llm/providers/anthropicFormat.js +41 -5
  221. package/src/llm/providers/anthropicFormat.ts +290 -0
  222. package/src/llm/providers/openaiFormat.js +186 -8
  223. package/src/llm/providers/openaiFormat.ts +428 -0
  224. package/src/loop.js +614 -63
  225. package/src/loop.ts +1454 -0
  226. package/src/main.js +67 -10
  227. package/src/main.tsx +344 -0
  228. package/src/memory/codec.js +204 -0
  229. package/src/memory/codec.ts +249 -0
  230. package/src/memory/constants.js +34 -0
  231. package/src/memory/constants.ts +50 -0
  232. package/src/memory/episodicMemory.js +684 -0
  233. package/src/memory/episodicMemory.ts +815 -0
  234. package/src/memory/fileStore.js +148 -0
  235. package/src/memory/fileStore.ts +184 -0
  236. package/src/memory/memoryService.js +570 -0
  237. package/src/memory/memoryService.ts +859 -0
  238. package/src/memory/migration.js +128 -0
  239. package/src/memory/migration.ts +160 -0
  240. package/src/memory/repository.js +789 -0
  241. package/src/memory/repository.ts +893 -0
  242. package/src/memory/retrieval.js +108 -0
  243. package/src/memory/retrieval.ts +145 -0
  244. package/src/memory/searchIndex.js +107 -0
  245. package/src/memory/searchIndex.ts +153 -0
  246. package/src/memory/topicView.js +82 -0
  247. package/src/memory/topicView.ts +95 -0
  248. package/src/memory/turnJournal.js +95 -0
  249. package/src/memory/turnJournal.ts +120 -0
  250. package/src/memory/types.js +2 -0
  251. package/src/memory/types.ts +186 -0
  252. package/src/messageQueue.ts +123 -0
  253. package/src/multimodal.js +128 -46
  254. package/src/multimodal.ts +349 -0
  255. package/src/plugin-sdk.js +21 -1
  256. package/src/plugin-sdk.ts +134 -0
  257. package/src/plugins/builtinPluginIds.js +47 -0
  258. package/src/plugins/builtinPluginIds.ts +51 -0
  259. package/src/plugins/builtinRegistry.ts +43 -0
  260. package/src/plugins/commandRouter.js +40 -26
  261. package/src/plugins/commandRouter.ts +261 -0
  262. package/src/plugins/hookEngine.ts +341 -0
  263. package/src/plugins/pluginApi.ts +133 -0
  264. package/src/plugins/pluginLifecycle.ts +34 -0
  265. package/src/plugins/pluginLoader.ts +147 -0
  266. package/src/plugins/pluginManifest.js +127 -0
  267. package/src/plugins/pluginManifest.ts +152 -0
  268. package/src/plugins/pluginRunner.js +47 -2
  269. package/src/plugins/pluginRunner.ts +207 -0
  270. package/src/plugins/transcript.ts +208 -0
  271. package/src/prompts/lint.js +169 -0
  272. package/src/prompts/lint.ts +220 -0
  273. package/src/prompts/pluginList.js +32 -16
  274. package/src/prompts/pluginList.ts +86 -0
  275. package/src/prompts/policyRegistry.js +318 -0
  276. package/src/prompts/policyRegistry.ts +358 -0
  277. package/src/prompts/projectInstructions.js +24 -0
  278. package/src/prompts/projectInstructions.ts +81 -0
  279. package/src/prompts/promptAssembly.js +311 -202
  280. package/src/prompts/promptAssembly.ts +510 -0
  281. package/src/prompts/skillList.js +106 -45
  282. package/src/prompts/skillList.ts +198 -0
  283. package/src/prompts/system.js +31 -6
  284. package/src/prompts/system.ts +81 -0
  285. package/src/runtime/agentRuntimeContext.js +53 -0
  286. package/src/runtime/agentRuntimeContext.ts +112 -0
  287. package/src/session/runAgentTurn.js +71 -12
  288. package/src/session/runAgentTurn.ts +181 -0
  289. package/src/session/runTurn.js +29 -0
  290. package/src/session/runTurn.ts +160 -0
  291. package/src/session/runtimeStore.js +149 -0
  292. package/src/session/runtimeStore.ts +197 -0
  293. package/src/session/sessionState.js +79 -3
  294. package/src/session/sessionState.ts +134 -0
  295. package/src/toolGate.ts +50 -0
  296. package/src/tools/advisor/advisor.js +76 -15
  297. package/src/tools/advisor/advisor.ts +512 -0
  298. package/src/tools/agent/agent.js +245 -29
  299. package/src/tools/agent/agent.ts +837 -0
  300. package/src/tools/agent/agentTaskService.js +60 -0
  301. package/src/tools/agent/agentTaskService.ts +113 -0
  302. package/src/tools/agent/agentTypes.js +20 -8
  303. package/src/tools/agent/agentTypes.ts +94 -0
  304. package/src/tools/agent/coordinator.ts +111 -0
  305. package/src/tools/agent/worktree.ts +296 -0
  306. package/src/tools/ask/ask.js +17 -0
  307. package/src/tools/ask/ask.ts +122 -0
  308. package/src/tools/bash/attachImage.js +223 -0
  309. package/src/tools/bash/attachImage.ts +281 -0
  310. package/src/tools/bash/bash.js +132 -14
  311. package/src/tools/bash/bash.ts +642 -0
  312. package/src/tools/bash/semantics.ts +103 -0
  313. package/src/tools/bash/warnings.js +17 -11
  314. package/src/tools/bash/warnings.ts +117 -0
  315. package/src/tools/capabilities.js +42 -0
  316. package/src/tools/capabilities.ts +69 -0
  317. package/src/tools/computeruse/accessibilityPermission.js +261 -0
  318. package/src/tools/computeruse/accessibilityPermission.ts +294 -0
  319. package/src/tools/computeruse/axSearch.js +96 -0
  320. package/src/tools/computeruse/axSearch.ts +120 -0
  321. package/src/tools/computeruse/axSnap.js +272 -0
  322. package/src/tools/computeruse/axSnap.ts +349 -0
  323. package/src/tools/computeruse/capabilityLabels.js +95 -0
  324. package/src/tools/computeruse/capabilityLabels.ts +115 -0
  325. package/src/tools/computeruse/computerUseService.js +2235 -0
  326. package/src/tools/computeruse/computerUseService.ts +2686 -0
  327. package/src/tools/computeruse/computeruse.js +2742 -0
  328. package/src/tools/computeruse/computeruse.ts +3265 -0
  329. package/src/tools/computeruse/diagnosticTrace.js +154 -0
  330. package/src/tools/computeruse/diagnosticTrace.ts +195 -0
  331. package/src/tools/computeruse/diagnostics.js +369 -0
  332. package/src/tools/computeruse/diagnostics.ts +453 -0
  333. package/src/tools/computeruse/grants.js +53 -0
  334. package/src/tools/computeruse/grants.ts +70 -0
  335. package/src/tools/computeruse/humanBoundary.js +159 -0
  336. package/src/tools/computeruse/humanBoundary.ts +199 -0
  337. package/src/tools/computeruse/intervention.js +77 -0
  338. package/src/tools/computeruse/intervention.ts +110 -0
  339. package/src/tools/computeruse/manualSchema.js +709 -0
  340. package/src/tools/computeruse/manualSchema.ts +916 -0
  341. package/src/tools/computeruse/observationImages.js +705 -0
  342. package/src/tools/computeruse/observationImages.ts +889 -0
  343. package/src/tools/computeruse/protocol.js +60 -0
  344. package/src/tools/computeruse/protocol.ts +515 -0
  345. package/src/tools/computeruse/telemetryLog.js +57 -0
  346. package/src/tools/computeruse/telemetryLog.ts +67 -0
  347. package/src/tools/computeruse/vision/appGuide.js +325 -0
  348. package/src/tools/computeruse/vision/appGuide.ts +482 -0
  349. package/src/tools/computeruse/vision/focus.js +291 -0
  350. package/src/tools/computeruse/vision/focus.ts +382 -0
  351. package/src/tools/computeruse/vision/frames.js +248 -0
  352. package/src/tools/computeruse/vision/frames.ts +329 -0
  353. package/src/tools/computeruse/vision/geometry.js +131 -0
  354. package/src/tools/computeruse/vision/geometry.ts +163 -0
  355. package/src/tools/computeruse/vision/imaging.js +201 -0
  356. package/src/tools/computeruse/vision/imaging.ts +281 -0
  357. package/src/tools/computeruse/vision/png.js +274 -0
  358. package/src/tools/computeruse/vision/png.ts +317 -0
  359. package/src/tools/computeruse/vision/raster.js +320 -0
  360. package/src/tools/computeruse/vision/raster.ts +408 -0
  361. package/src/tools/computeruse/vision/settle.js +131 -0
  362. package/src/tools/computeruse/vision/settle.ts +220 -0
  363. package/src/tools/computeruse/vision/telemetry.js +196 -0
  364. package/src/tools/computeruse/vision/telemetry.ts +241 -0
  365. package/src/tools/computeruse/visionOcr.js +115 -0
  366. package/src/tools/computeruse/visionOcr.ts +128 -0
  367. package/src/tools/computeruse/waitFor.js +237 -0
  368. package/src/tools/computeruse/waitFor.ts +291 -0
  369. package/src/tools/download/download.js +10 -6
  370. package/src/tools/download/download.ts +187 -0
  371. package/src/tools/edit/edit.js +30 -18
  372. package/src/tools/edit/edit.ts +349 -0
  373. package/src/tools/edit/multi-edit.js +25 -14
  374. package/src/tools/edit/multi-edit.ts +223 -0
  375. package/src/tools/effectiveToolSet.js +73 -0
  376. package/src/tools/effectiveToolSet.ts +91 -0
  377. package/src/tools/genimage/genimage.ts +257 -0
  378. package/src/tools/genspeech/genspeech.ts +83 -0
  379. package/src/tools/glob/glob.js +176 -29
  380. package/src/tools/glob/glob.ts +283 -0
  381. package/src/tools/grep/grep.js +61 -19
  382. package/src/tools/grep/grep.ts +239 -0
  383. package/src/tools/grep/rgPath.ts +206 -0
  384. package/src/tools/index.js +99 -5
  385. package/src/tools/index.ts +293 -0
  386. package/src/tools/lsp/config.js +113 -0
  387. package/src/tools/lsp/config.ts +113 -0
  388. package/src/tools/lsp/lsp.js +256 -0
  389. package/src/tools/lsp/lsp.ts +274 -0
  390. package/src/tools/lsp/service.js +303 -0
  391. package/src/tools/lsp/service.ts +296 -0
  392. package/src/tools/memory/memory.js +520 -0
  393. package/src/tools/memory/memory.ts +625 -0
  394. package/src/tools/memory/policy.js +53 -0
  395. package/src/tools/memory/policy.ts +72 -0
  396. package/src/tools/notebook/notebookEdit.js +114 -0
  397. package/src/tools/notebook/notebookEdit.ts +126 -0
  398. package/src/tools/powershell/powershell.js +210 -0
  399. package/src/tools/powershell/powershell.ts +239 -0
  400. package/src/tools/presentresult/presentresult.js +145 -0
  401. package/src/tools/presentresult/presentresult.ts +156 -0
  402. package/src/tools/read/read.js +371 -163
  403. package/src/tools/read/read.ts +558 -0
  404. package/src/tools/shared/diffSummary.js +44 -0
  405. package/src/tools/shared/diffSummary.ts +63 -0
  406. package/src/tools/shared/fileActivity.js +51 -0
  407. package/src/tools/shared/fileActivity.ts +66 -0
  408. package/src/tools/shared/fileMutationBus.js +13 -0
  409. package/src/tools/shared/fileMutationBus.ts +14 -0
  410. package/src/tools/shared/fileState.js +73 -65
  411. package/src/tools/shared/fileState.ts +145 -0
  412. package/src/tools/shared/fileUtils.js +81 -4
  413. package/src/tools/shared/fileUtils.ts +504 -0
  414. package/src/tools/shared/killTree.ts +50 -0
  415. package/src/tools/shared/permanentDeleteGuard.js +26 -0
  416. package/src/tools/shared/permanentDeleteGuard.ts +34 -0
  417. package/src/tools/shared/schemas.ts +20 -0
  418. package/src/tools/shared/toolOutputStore.js +97 -0
  419. package/src/tools/shared/toolOutputStore.ts +110 -0
  420. package/src/tools/skill/skill.js +86 -0
  421. package/src/tools/skill/skill.ts +94 -0
  422. package/src/tools/snip/snip.js +67 -0
  423. package/src/tools/snip/snip.ts +80 -0
  424. package/src/tools/tasks/backgroundTaskService.js +275 -0
  425. package/src/tools/tasks/backgroundTaskService.ts +369 -0
  426. package/src/tools/tasks/processEvidence.js +24 -0
  427. package/src/tools/tasks/processEvidence.ts +34 -0
  428. package/src/tools/tasks/taskManagement.js +163 -0
  429. package/src/tools/tasks/taskManagement.ts +180 -0
  430. package/src/tools/tasks/taskOutput.js +113 -0
  431. package/src/tools/tasks/taskOutput.ts +145 -0
  432. package/src/tools/tasks/taskStop.js +74 -0
  433. package/src/tools/tasks/taskStop.ts +99 -0
  434. package/src/tools/tasks/taskStore.js +46 -0
  435. package/src/tools/tasks/taskStore.ts +77 -0
  436. package/src/tools/terminal/terminalCapture.js +167 -0
  437. package/src/tools/terminal/terminalCapture.ts +179 -0
  438. package/src/tools/trash/trash.js +233 -0
  439. package/src/tools/trash/trash.ts +283 -0
  440. package/src/tools/types.js +1 -1
  441. package/src/tools/types.ts +24 -0
  442. package/src/tools/webbrowser/agentBrowserPath.ts +286 -0
  443. package/src/tools/webbrowser/browser.js +214 -11
  444. package/src/tools/webbrowser/browser.ts +293 -0
  445. package/src/tools/webbrowser/browserControl.js +153 -48
  446. package/src/tools/webbrowser/browserControl.ts +262 -0
  447. package/src/tools/webbrowser/browserDaemon.js +147 -39
  448. package/src/tools/webbrowser/browserDaemon.ts +270 -0
  449. package/src/tools/webbrowser/browserOutcome.js +273 -0
  450. package/src/tools/webbrowser/browserOutcome.ts +306 -0
  451. package/src/tools/webbrowser/browserRunRegistry.js +150 -0
  452. package/src/tools/webbrowser/browserRunRegistry.ts +179 -0
  453. package/src/tools/webbrowser/browserService.js +20 -6
  454. package/src/tools/webbrowser/browserService.ts +56 -0
  455. package/src/tools/webbrowser/browserStream.js +30 -1
  456. package/src/tools/webbrowser/browserStream.ts +216 -0
  457. package/src/tools/webbrowser/browserTabs.js +143 -0
  458. package/src/tools/webbrowser/browserTabs.ts +210 -0
  459. package/src/tools/webbrowser/webbrowser.js +831 -150
  460. package/src/tools/webbrowser/webbrowser.ts +1537 -0
  461. package/src/tools/webfetch/preapproved.ts +274 -0
  462. package/src/tools/webfetch/webfetch.js +24 -23
  463. package/src/tools/webfetch/webfetch.ts +383 -0
  464. package/src/tools/websearch/websearch.js +12 -11
  465. package/src/tools/websearch/websearch.ts +292 -0
  466. package/src/tools/worktree/sessionWorktree.js +128 -0
  467. package/src/tools/worktree/sessionWorktree.ts +158 -0
  468. package/src/tools/write/write.js +27 -44
  469. package/src/tools/write/write.ts +136 -0
  470. package/src/types.ts +960 -0
  471. package/src/ui/App.js +216 -12
  472. package/src/ui/App.tsx +879 -0
  473. package/src/ui/AskQuestion.tsx +300 -0
  474. package/src/ui/InputBox.js +77 -1
  475. package/src/ui/InputBox.tsx +567 -0
  476. package/src/ui/LiveArea.tsx +344 -0
  477. package/src/ui/MessageList.js +27 -6
  478. package/src/ui/MessageList.tsx +559 -0
  479. package/src/ui/ModelPicker.tsx +107 -0
  480. package/src/ui/QueuedMessagesBanner.tsx +51 -0
  481. package/src/ui/Root.js +6 -8
  482. package/src/ui/Root.tsx +100 -0
  483. package/src/ui/SessionPicker.tsx +169 -0
  484. package/src/ui/StatusLine.js +22 -1
  485. package/src/ui/StatusLine.tsx +145 -0
  486. package/src/ui/WorkspacePicker.tsx +84 -0
  487. package/src/ui/advisorCommand.js +54 -0
  488. package/src/ui/advisorCommand.ts +63 -0
  489. package/src/ui/computerCommand.js +19 -0
  490. package/src/ui/computerCommand.ts +35 -0
  491. package/src/ui/figures.ts +45 -0
  492. package/src/ui/hooks/askSlot.ts +112 -0
  493. package/src/ui/hooks/useChat.js +271 -7
  494. package/src/ui/hooks/useChat.ts +1578 -0
  495. package/src/ui/hooks/useInputHistory.ts +235 -0
  496. package/src/ui/hooks/usePasteHandler.ts +220 -0
  497. package/src/ui/hooks/useTerminalSize.ts +41 -0
  498. package/src/ui/hooks/useTextBuffer.ts +108 -0
  499. package/src/ui/hooks/useTokenUsage.ts +44 -0
  500. package/src/ui/liveViewport.ts +189 -0
  501. package/src/ui/markdown.ts +230 -0
  502. package/src/ui/textBuffer.ts +239 -0
  503. package/src/ui/theme.ts +35 -0
  504. package/src/utils/clipboardImage.js +358 -0
  505. package/src/utils/clipboardImage.ts +420 -0
  506. package/src/utils/debugLog.ts +50 -0
  507. package/src/utils/greenRoot.ts +35 -0
  508. package/src/utils/packageRoot.ts +40 -0
  509. package/src/utils/pathContains.js +28 -0
  510. package/src/utils/pathContains.ts +31 -0
  511. package/src/utils/resourcePaths.ts +71 -0
  512. package/src/utils/stripThink.ts +49 -0
  513. package/src/utils/zodToJson.ts +73 -0
  514. package/src/web/browserBridge.js +365 -66
  515. package/src/web/browserBridge.ts +672 -0
  516. package/src/web/protocol.ts +1804 -0
  517. package/vendor/computer-use/arm64-darwin/cu-helperd +0 -0
  518. package/workflows/ppt.yaml +13 -2
  519. package/workflows/wechat-reading-shots.yaml +315 -0
  520. package/workflows/word.yaml +11 -1
  521. package/skills/docx/scripts/office/helpers/__pycache__/__init__.cpython-314.pyc +0 -0
  522. package/skills/docx/scripts/office/helpers/__pycache__/merge_runs.cpython-314.pyc +0 -0
  523. package/skills/docx/scripts/office/helpers/__pycache__/simplify_redlines.cpython-314.pyc +0 -0
  524. package/skills/docx/scripts/office/validators/__pycache__/__init__.cpython-314.pyc +0 -0
  525. package/skills/docx/scripts/office/validators/__pycache__/base.cpython-314.pyc +0 -0
  526. package/skills/docx/scripts/office/validators/__pycache__/docx.cpython-314.pyc +0 -0
  527. package/skills/docx/scripts/office/validators/__pycache__/pptx.cpython-314.pyc +0 -0
  528. package/skills/docx/scripts/office/validators/__pycache__/redlining.cpython-314.pyc +0 -0
  529. package/skills/image-stats/scripts/__pycache__/image_stats.cpython-314.pyc +0 -0
  530. package/skills/image-stats/scripts/__pycache__/image_stats_test.cpython-314.pyc +0 -0
  531. package/skills/ui-design/scripts/__pycache__/assemble_material.cpython-314.pyc +0 -0
  532. package/skills/ui-design/scripts/__pycache__/assemble_material_test.cpython-314.pyc +0 -0
  533. package/skills/ui-design/scripts/__pycache__/chart_sanity_check.cpython-314.pyc +0 -0
  534. package/skills/ui-design/scripts/__pycache__/check_language_policy.cpython-314.pyc +0 -0
  535. package/skills/ui-design/scripts/__pycache__/check_ui_artifact.cpython-314.pyc +0 -0
  536. package/skills/ui-design/scripts/__pycache__/check_ui_artifact_pptx_test.cpython-314.pyc +0 -0
  537. package/skills/ui-design/scripts/__pycache__/deck_pages_check.cpython-314.pyc +0 -0
  538. package/skills/ui-design/scripts/__pycache__/deck_pages_check_test.cpython-314.pyc +0 -0
  539. package/skills/ui-design/scripts/__pycache__/deck_visual_style_check.cpython-314.pyc +0 -0
  540. package/skills/ui-design/scripts/__pycache__/deck_visual_style_check_test.cpython-314.pyc +0 -0
  541. package/skills/ui-design/scripts/__pycache__/design_budget_check.cpython-314.pyc +0 -0
  542. package/skills/ui-design/scripts/__pycache__/design_budget_check_test.cpython-314.pyc +0 -0
  543. package/skills/ui-design/scripts/__pycache__/design_repair_hints.cpython-314.pyc +0 -0
  544. package/skills/ui-design/scripts/__pycache__/design_repair_hints_test.cpython-314.pyc +0 -0
  545. package/skills/ui-design/scripts/__pycache__/design_style_check.cpython-314.pyc +0 -0
  546. package/skills/ui-design/scripts/__pycache__/design_style_check_test.cpython-314.pyc +0 -0
  547. package/skills/ui-design/scripts/__pycache__/draft_coverage_check.cpython-314.pyc +0 -0
  548. package/skills/ui-design/scripts/__pycache__/extract_source_assets.cpython-314.pyc +0 -0
  549. package/skills/ui-design/scripts/__pycache__/extract_source_assets_test.cpython-314.pyc +0 -0
  550. package/skills/ui-design/scripts/__pycache__/generated_image_review_collect.cpython-314.pyc +0 -0
  551. package/skills/ui-design/scripts/__pycache__/generated_image_review_collect_test.cpython-314.pyc +0 -0
  552. package/skills/ui-design/scripts/__pycache__/image_plan_lint.cpython-314.pyc +0 -0
  553. package/skills/ui-design/scripts/__pycache__/image_plan_lint_test.cpython-314.pyc +0 -0
  554. package/skills/ui-design/scripts/__pycache__/image_prompt_rewrite.cpython-314.pyc +0 -0
  555. package/skills/ui-design/scripts/__pycache__/image_prompt_rewrite_test.cpython-314.pyc +0 -0
  556. package/skills/ui-design/scripts/__pycache__/layout_balance.cpython-314.pyc +0 -0
  557. package/skills/ui-design/scripts/__pycache__/layout_balance_test.cpython-314.pyc +0 -0
  558. package/skills/ui-design/scripts/__pycache__/normalize_design_json.cpython-314.pyc +0 -0
  559. package/skills/ui-design/scripts/__pycache__/normalize_design_json_test.cpython-314.pyc +0 -0
  560. package/skills/ui-design/scripts/__pycache__/plan_source_layout.cpython-314.pyc +0 -0
  561. package/skills/ui-design/scripts/__pycache__/plan_source_layout_test.cpython-314.pyc +0 -0
  562. package/skills/ui-design/scripts/__pycache__/resolve_source_hint.cpython-314.pyc +0 -0
  563. package/skills/ui-design/scripts/__pycache__/resolve_source_hint_test.cpython-314.pyc +0 -0
  564. package/skills/ui-design/scripts/__pycache__/resolve_source_input.cpython-314.pyc +0 -0
  565. package/skills/ui-design/scripts/__pycache__/resolve_source_input_test.cpython-314.pyc +0 -0
  566. package/skills/ui-design/scripts/__pycache__/scaffold_ui_artifact.cpython-314.pyc +0 -0
  567. package/skills/ui-design/scripts/__pycache__/source_usage_check.cpython-314.pyc +0 -0
  568. package/skills/ui-design/scripts/__pycache__/source_usage_check_test.cpython-314.pyc +0 -0
  569. package/skills/ui-design/scripts/__pycache__/text_readability_pixel.cpython-314.pyc +0 -0
  570. package/skills/ui-design/scripts/__pycache__/visual_quality_gate.cpython-314.pyc +0 -0
  571. package/skills/ui-design/scripts/__pycache__/visual_quality_gate_test.cpython-314.pyc +0 -0
  572. /package/skills/ai-image/scripts/{generate_test.mjs → generate.selftest.mjs} +0 -0
  573. /package/skills/ai-image/scripts/{generate_from_plan_test.mjs → generate_from_plan.selftest.mjs} +0 -0
@@ -2,16 +2,12 @@ import { randomUUID } from 'node:crypto';
2
2
  import { rm } from 'node:fs/promises';
3
3
  import { configService } from '../config/configService.js';
4
4
  import { resolveAgentBrowserPath } from '../tools/webbrowser/agentBrowserPath.js';
5
- import { browserProfilePath, sessionArgs, spawnRunner } from '../tools/webbrowser/browser.js';
5
+ import { browserProfilePath, normalizeUrl, sessionArgs, spawnRunner } from '../tools/webbrowser/browser.js';
6
6
  import { ensureDaemon, stopDaemon } from '../tools/webbrowser/browserDaemon.js';
7
7
  import { browserService } from '../tools/webbrowser/browserService.js';
8
+ import { browserRunRegistry } from '../tools/webbrowser/browserRunRegistry.js';
9
+ import { createConversationTab, ensureConversationTab, listBrowserTabs, } from '../tools/webbrowser/browserTabs.js';
8
10
  import { getBrowserStream, } from '../tools/webbrowser/browserStream.js';
9
- function normalizeUrl(value) {
10
- const input = value.trim();
11
- if (/^[a-z][a-z0-9+.-]*:/i.test(input))
12
- return input;
13
- return `https://${input}`;
14
- }
15
11
  function requireAllowedDeveloperOrigin(url, allowedOrigins) {
16
12
  let origin;
17
13
  try {
@@ -89,6 +85,24 @@ function mapStreamEvent(event) {
89
85
  return { id: String(item.tabId ?? item.id ?? ''), url: String(item.url ?? ''), title: typeof item.title === 'string' ? item.title : undefined, active: Boolean(item.active), favicon: typeof item.favicon === 'string' ? item.favicon : undefined };
90
86
  }) };
91
87
  }
88
+ case 'agent_candidates': {
89
+ const list = Array.isArray(event.candidates) ? event.candidates : [];
90
+ return {
91
+ t: 'browser/agent/candidates',
92
+ candidates: list.map((item) => {
93
+ const c = item;
94
+ return { ref: String(c.ref ?? ''), line: String(c.line ?? '') };
95
+ }),
96
+ ...(typeof event.selector === 'string' ? { selector: event.selector } : {}),
97
+ };
98
+ }
99
+ case 'agent_outcome': return {
100
+ t: 'browser/agent/outcome',
101
+ action: String(event.action ?? ''),
102
+ effect: event.effect === 'unknown' ? 'unknown' : 'unchanged',
103
+ ...(typeof event.selector === 'string' ? { selector: event.selector } : {}),
104
+ ...(typeof event.maskedLines === 'number' ? { maskedLines: event.maskedLines } : {}),
105
+ };
92
106
  case 'url': return { t: 'browser/url', url: String(event.url ?? ''), tabId: typeof event.tabId === 'string' ? event.tabId : undefined };
93
107
  case 'title': return { t: 'browser/title', title: String(event.title ?? ''), tabId: typeof event.tabId === 'string' ? event.tabId : undefined };
94
108
  case 'navigation': return { t: 'browser/navigation', url: String(event.url ?? ''), state: (event.state === 'start' || event.state === 'commit' || event.state === 'domcontentloaded') ? event.state : 'load' };
@@ -99,37 +113,151 @@ function mapStreamEvent(event) {
99
113
  case 'mode': return { t: 'browser/mode', mode: event.mode };
100
114
  case 'marked_elements': return { t: 'browser/marked/elements', elements: (event.elements ?? []) };
101
115
  case 'agent_acting': return { t: 'browser/agent/acting', acting: Boolean(event.acting), action: typeof event.action === 'string' ? event.action : undefined, target: typeof event.target === 'string' ? event.target : undefined };
116
+ case 'agent_pointer': return { t: 'browser/agent/pointer', x: Number(event.x ?? 0), y: Number(event.y ?? 0), visible: Boolean(event.visible), action: (typeof event.action === 'string' ? event.action : undefined), elementRef: typeof event.elementRef === 'string' ? event.elementRef : undefined };
102
117
  case 'control_state': return { t: 'browser/control/changed', state: event.state };
103
118
  default: return null;
104
119
  }
105
120
  }
121
+ function mapHumanInterventionEvent(event) {
122
+ if (event.type === 'started') {
123
+ return {
124
+ t: 'human-intervention/started',
125
+ intervention: event.intervention,
126
+ };
127
+ }
128
+ return {
129
+ t: 'human-intervention/resolved',
130
+ resolution: event.resolution,
131
+ };
132
+ }
133
+ export function createPointerRouteState() {
134
+ return { dragging: false, dragButton: 'left', pendingPress: null, lastDragMoveAt: 0 };
135
+ }
136
+ /**
137
+ * 纯函数:按持久路由状态决定一个用户鼠标帧怎么走。就地更新 state,返回待下发的快通路帧
138
+ * 与待入队的命令通路 argv。抽成纯函数便于单测拖拽判定/单击缓冲/节流,不碰真实 spawn。
139
+ */
140
+ export function routeUserMouse(state, frame, now, dragMoveThrottleMs = 40) {
141
+ const plan = { stream: [], commands: [] };
142
+ const eventType = String(frame.eventType ?? '');
143
+ const x = Math.round(Number(frame.x ?? 0));
144
+ const y = Math.round(Number(frame.y ?? 0));
145
+ const fast = (f = frame) => plan.stream.push({ type: 'input_mouse', ...f, t: undefined });
146
+ if (eventType === 'mousePressed') {
147
+ // 缓冲按下:还不知道是单击还是拖拽——先不派发,等下一帧揭晓。
148
+ state.pendingPress = frame;
149
+ state.dragging = false;
150
+ return plan;
151
+ }
152
+ if (eventType === 'mouseMoved') {
153
+ if (state.pendingPress && !state.dragging) {
154
+ // 按下后首次移动 = 拖拽:在命令通路上建立「按住」状态(mouse down 令 daemon 记住 buttons)。
155
+ const px = Math.round(Number(state.pendingPress.x ?? x));
156
+ const py = Math.round(Number(state.pendingPress.y ?? y));
157
+ state.dragButton = String(state.pendingPress.button ?? 'left') || 'left';
158
+ state.dragging = true;
159
+ state.pendingPress = null;
160
+ state.lastDragMoveAt = now;
161
+ plan.commands.push(['move', String(px), String(py)], ['down', state.dragButton], ['move', String(x), String(y)]);
162
+ return plan;
163
+ }
164
+ if (state.dragging) {
165
+ // 拖拽中间帧:节流下发命令通路(spawn 昂贵),不再走 input_mouse 避免双通路重复派发。
166
+ if (now - state.lastDragMoveAt >= dragMoveThrottleMs) {
167
+ state.lastDragMoveAt = now;
168
+ plan.commands.push(['move', String(x), String(y)]);
169
+ }
170
+ return plan;
171
+ }
172
+ fast(); // 普通悬停 → 快通路
173
+ return plan;
174
+ }
175
+ if (eventType === 'mouseReleased') {
176
+ if (state.dragging) {
177
+ // 收尾:先补末帧到真实抬起坐标(节流可能丢了它),再抬起清 buttons。
178
+ plan.commands.push(['move', String(x), String(y)], ['up', state.dragButton]);
179
+ state.dragging = false;
180
+ return plan;
181
+ }
182
+ if (state.pendingPress) {
183
+ // 纯单击(按下后无移动):快通路补发缓冲的按下 + 本次抬起,语义仍是一次点击。
184
+ fast(state.pendingPress);
185
+ fast();
186
+ state.pendingPress = null;
187
+ return plan;
188
+ }
189
+ fast();
190
+ return plan;
191
+ }
192
+ // mouseWheel / 其它鼠标事件 → 快通路(不涉及按住拖拽)。
193
+ fast();
194
+ return plan;
195
+ }
106
196
  export function createBrowserBridge(send, sessionName = 'minimal-agent') {
107
197
  let disposed = false;
108
198
  let activeTabId = '';
109
199
  let pageRevision = randomUUID();
200
+ let runContext = null;
110
201
  const stream = getBrowserStream(sessionName);
111
202
  const unsubscribe = stream.subscribe((event) => {
112
203
  if (disposed)
113
204
  return;
205
+ if (event.type === 'control_state') {
206
+ const control = event.state;
207
+ if (control && control.status !== 'idle' && control.conversationKey) {
208
+ runContext = browserRunRegistry.find(control.conversationKey, control.runId)
209
+ ?? browserRunRegistry.ensure({
210
+ conversationKey: control.conversationKey,
211
+ runId: control.runId,
212
+ profileId: 'default',
213
+ grants: ['observe', 'interact'],
214
+ });
215
+ }
216
+ }
217
+ if (event.type === 'human_intervention_started' || event.type === 'human_intervention_resolved') {
218
+ const interventionEvent = event.event;
219
+ if (interventionEvent)
220
+ send(mapHumanInterventionEvent(interventionEvent));
221
+ }
114
222
  if (event.type === 'url' || event.type === 'navigation')
115
223
  pageRevision = randomUUID();
116
224
  if (event.type === 'tabs' && Array.isArray(event.tabs)) {
117
225
  const active = event.tabs.find((tab) => Boolean(tab.active));
118
226
  activeTabId = String(active?.tabId ?? active?.id ?? activeTabId);
119
227
  }
120
- const mapped = mapStreamEvent(event);
228
+ let mapped = mapStreamEvent(event);
229
+ const activeOwner = activeTabId ? browserRunRegistry.ownerOf(activeTabId) : undefined;
230
+ if (runContext && activeTabId && activeOwner !== runContext.conversationKey
231
+ && mapped && ['browser/frame', 'browser/url', 'browser/title', 'browser/navigation'].includes(mapped.t)) {
232
+ return;
233
+ }
234
+ if (runContext && mapped?.t === 'browser/tabs') {
235
+ const claimed = new Set(browserRunRegistry.claimedTabs(runContext.conversationKey).map(String));
236
+ mapped = { ...mapped, tabs: mapped.tabs.filter((tab) => claimed.has(tab.id)) };
237
+ }
121
238
  if (mapped?.t === 'browser/frame')
122
- send({ ...mapped, tabId: activeTabId || mapped.tabId, pageRevision });
239
+ send({
240
+ ...mapped,
241
+ tabId: activeTabId || mapped.tabId,
242
+ pageRevision,
243
+ ...(runContext ? { conversationKey: runContext.conversationKey, runId: runContext.runId } : {}),
244
+ });
123
245
  else if (mapped)
124
246
  send(mapped);
125
247
  if (event.type === 'control_state') {
126
248
  const state = event.state;
249
+ // 控制权移交给用户(手动接管或验证挑战)时淡出 AI 指针,避免“谁在操作”的混淆。
250
+ if (state?.owner === 'user')
251
+ stream.setAgentPointer({ x: 0, y: 0, visible: false });
127
252
  if (state?.status === 'waiting_human' && state.reason !== 'manual') {
128
253
  const summary = state.reason === 'captcha' ? '页面需要人工完成安全验证'
129
254
  : state.reason === 'otp' ? '页面需要人工输入一次性验证码'
130
- : state.reason === 'login' ? '页面需要人工登录'
131
- : state.reason === 'permission' ? '页面需要人工确认权限'
132
- : '网站已暂停或拦截当前访问';
255
+ : state.reason === 'password' ? '页面需要人工输入密码'
256
+ : state.reason === 'qr_login' ? '页面需要人工扫码登录'
257
+ : state.reason === 'login' ? '页面需要人工登录'
258
+ : state.reason === 'permission' ? '页面需要人工确认权限'
259
+ : state.reason === 'security_warning' ? '页面需要人工处理安全警告'
260
+ : '网站已暂停或拦截当前访问';
133
261
  send({
134
262
  t: 'browser/challenge/detected',
135
263
  reason: state.reason,
@@ -151,6 +279,63 @@ export function createBrowserBridge(send, sessionName = 'minimal-agent') {
151
279
  throw new Error((result.stderr || result.stdout || `exit ${result.code}`).trim());
152
280
  return result.stdout.trim();
153
281
  };
282
+ const requireContext = () => {
283
+ if (!runContext)
284
+ throw new Error('浏览器尚未绑定当前会话,请重新打开工作台');
285
+ return runContext;
286
+ };
287
+ const claimContextTab = async () => {
288
+ const context = requireContext();
289
+ const bin = await resolveAgentBrowserPath();
290
+ if (!bin)
291
+ throw new Error('未找到内置 agent-browser');
292
+ await ensureDaemon(sessionName);
293
+ const tabId = await ensureConversationTab({
294
+ context,
295
+ sessionName,
296
+ bin,
297
+ globals: sessionArgs(sessionName),
298
+ runner: spawnRunner,
299
+ });
300
+ activeTabId = tabId;
301
+ return tabId;
302
+ };
303
+ const createContextTab = async (url = 'about:blank') => {
304
+ const context = requireContext();
305
+ const bin = await resolveAgentBrowserPath();
306
+ if (!bin)
307
+ throw new Error('未找到内置 agent-browser');
308
+ await ensureDaemon(sessionName);
309
+ const tabId = await createConversationTab({
310
+ context,
311
+ sessionName,
312
+ bin,
313
+ globals: sessionArgs(sessionName),
314
+ runner: spawnRunner,
315
+ }, url);
316
+ activeTabId = tabId;
317
+ return tabId;
318
+ };
319
+ const runOnContextTab = async (args) => {
320
+ const tabId = await claimContextTab();
321
+ const bin = await resolveAgentBrowserPath();
322
+ if (!bin)
323
+ throw new Error('未找到内置 agent-browser');
324
+ const output = await browserService.exclusive({
325
+ sessionName,
326
+ bin,
327
+ runner: spawnRunner,
328
+ }, async (execute) => {
329
+ const switched = await execute([...sessionArgs(sessionName), 'tab', tabId]);
330
+ if (switched.code !== 0)
331
+ return switched;
332
+ return execute([...sessionArgs(sessionName), ...args]);
333
+ });
334
+ if (output.code !== 0) {
335
+ throw new Error((output.stderr || output.stdout || `exit ${output.code}`).trim());
336
+ }
337
+ return output.stdout.trim();
338
+ };
154
339
  const ensureStarted = async () => {
155
340
  const config = await configService.browser();
156
341
  if (!config.enabled)
@@ -159,29 +344,41 @@ export function createBrowserBridge(send, sessionName = 'minimal-agent') {
159
344
  await stream.connect();
160
345
  return info;
161
346
  };
347
+ // 改视口后重连查看者,让下一帧按新尺寸编码(screencast 尺寸绑定在查看者连接时刻)。
348
+ // 注意:标签切换/新建/关闭/导航不需要在这里重连——agent-browser daemon 在这些命令后会自己
349
+ // set_cdp_session_id + notify、让 screencast 重定向到新活动标签(见 actions.rs / stream/cdp_loop.rs)。
350
+ // 真正的坑是「链接点击开的新标签」不在 daemon 的同步清单里,那条路由前端「活动标签变化 → 补发 tab/switch」兜住(useBrowser.ts)。
351
+ const reconnectViewer = async () => {
352
+ if (stream.isConnected()) {
353
+ stream.disconnect();
354
+ await stream.connect();
355
+ }
356
+ };
162
357
  const applyViewport = async (widthValue, heightValue) => {
163
358
  const width = Math.max(320, Math.round(Number(widthValue)));
164
359
  const height = Math.max(240, Math.round(Number(heightValue)));
165
360
  if (!Number.isFinite(width) || !Number.isFinite(height))
166
361
  throw new Error('无效的浏览器视口尺寸');
167
- await run(['set', 'viewport', String(width), String(height)]);
168
- // agent-browser starts its CDP screencast with the dimensions that were
169
- // active when the viewer connected. Reconnect only the viewer so the next
170
- // frame is encoded at the new viewport without touching tabs or profile.
171
- if (stream.isConnected()) {
172
- stream.disconnect();
173
- await stream.connect();
174
- }
362
+ await runOnContextTab(['set', 'viewport', String(width), String(height)]);
363
+ await reconnectViewer();
175
364
  };
176
365
  const pick = async (x, y) => {
177
- const value = parseJsonOutput(await run(['eval', pickScript(x, y)]));
366
+ const value = parseJsonOutput(await runOnContextTab(['eval', pickScript(x, y)]));
178
367
  if (!value || typeof value !== 'object')
179
368
  return null;
180
369
  return value;
181
370
  };
182
371
  stream.setPicker(pick);
372
+ // 用户指针输入的双通路路由状态 + 命令通路串行队列(见 routeUserMouse 头注)。
373
+ const pointerRoute = createPointerRouteState();
374
+ let mouseCmdChain = Promise.resolve();
375
+ const enqueueMouseCmd = (args) => {
376
+ // 串行保序:逐条 await 上一条再跑下一条;失败吞掉(拖拽单帧丢失不该中断整段手势)。
377
+ mouseCmdChain = mouseCmdChain.then(() => runOnContextTab(['mouse', ...args])).catch(() => { });
378
+ };
183
379
  const result = (frame, ok, data, error) => send({
184
380
  t: 'browser/result', requestId: frame.requestId, action: frame.t, ok,
381
+ ...(runContext ? { conversationKey: runContext.conversationKey, runId: runContext.runId, tabId: activeTabId || undefined } : {}),
185
382
  ...(typeof data === 'string' ? { content: data } : data === undefined ? {} : { data }),
186
383
  ...(error ? { error } : {}),
187
384
  });
@@ -191,12 +388,42 @@ export function createBrowserBridge(send, sessionName = 'minimal-agent') {
191
388
  return;
192
389
  try {
193
390
  switch (frame.t) {
391
+ case 'browser/context/set': {
392
+ const conversationKey = String(frame.conversationKey ?? '').trim();
393
+ if (!conversationKey)
394
+ throw new Error('缺少浏览器会话标识');
395
+ runContext = browserRunRegistry.ensure({
396
+ conversationKey,
397
+ runId: typeof frame.runId === 'string' ? frame.runId : 'workbench',
398
+ profileId: 'default',
399
+ grants: ['observe', 'interact'],
400
+ });
401
+ const tabId = await claimContextTab();
402
+ send({
403
+ t: 'browser/context/changed',
404
+ requestId: frame.requestId,
405
+ conversationKey: runContext.conversationKey,
406
+ runId: runContext.runId,
407
+ tabId,
408
+ });
409
+ return;
410
+ }
194
411
  case 'browser/start': {
412
+ requireContext();
195
413
  const info = await ensureStarted();
414
+ await claimContextTab();
196
415
  const viewport = frame.viewport;
197
416
  if (viewport?.width && viewport?.height)
198
417
  await applyViewport(viewport.width, viewport.height);
199
- send({ t: 'browser/started', requestId: frame.requestId, streamPort: info.streamPort, pid: info.pid, sessionId: sessionName });
418
+ send({
419
+ t: 'browser/started',
420
+ requestId: frame.requestId,
421
+ streamPort: info.streamPort,
422
+ pid: info.pid,
423
+ sessionId: sessionName,
424
+ conversationKey: runContext?.conversationKey,
425
+ runId: runContext?.runId,
426
+ });
200
427
  result(frame, true, info);
201
428
  return;
202
429
  }
@@ -217,10 +444,15 @@ export function createBrowserBridge(send, sessionName = 'minimal-agent') {
217
444
  result(frame, true);
218
445
  return;
219
446
  case 'browser/control/get':
447
+ requireContext();
220
448
  send({ t: 'browser/control/changed', state: stream.getControlState() });
221
449
  return;
222
450
  case 'browser/control/takeover':
223
- stream.requestHuman('manual');
451
+ stream.requestHuman('manual', {
452
+ runId: runContext?.runId,
453
+ conversationKey: runContext?.conversationKey,
454
+ ownerId: 'local-owner',
455
+ });
224
456
  result(frame, true, stream.getControlState());
225
457
  return;
226
458
  case 'browser/control/resume': {
@@ -228,53 +460,119 @@ export function createBrowserBridge(send, sessionName = 'minimal-agent') {
228
460
  result(frame, ok, stream.getControlState(), ok ? undefined : '浏览器接管请求已失效');
229
461
  return;
230
462
  }
231
- case 'browser/control/stop':
232
- stream.stopControl(typeof frame.resumeToken === 'string' ? frame.resumeToken : undefined);
233
- result(frame, true, stream.getControlState());
463
+ case 'browser/control/stop': {
464
+ const ok = stream.stopControl(typeof frame.resumeToken === 'string' ? frame.resumeToken : undefined);
465
+ result(frame, ok, stream.getControlState(), ok ? undefined : '浏览器接管请求已失效');
466
+ return;
467
+ }
468
+ case 'human-intervention/resume': {
469
+ const ok = stream.resumeIntervention({
470
+ id: String(frame.interventionId ?? ''),
471
+ resumeToken: String(frame.resumeToken ?? ''),
472
+ ownerId: String(frame.ownerId ?? ''),
473
+ conversationKey: String(frame.conversationKey ?? ''),
474
+ runId: String(frame.runId ?? ''),
475
+ });
476
+ result(frame, ok, stream.getControlState(), ok ? undefined : '浏览器人工介入请求已失效');
234
477
  return;
478
+ }
479
+ case 'human-intervention/cancel': {
480
+ const ok = stream.cancelIntervention({
481
+ id: String(frame.interventionId ?? ''),
482
+ resumeToken: String(frame.resumeToken ?? ''),
483
+ ownerId: String(frame.ownerId ?? ''),
484
+ conversationKey: String(frame.conversationKey ?? ''),
485
+ runId: String(frame.runId ?? ''),
486
+ });
487
+ result(frame, ok, stream.getControlState(), ok ? undefined : '浏览器人工介入请求已失效');
488
+ return;
489
+ }
235
490
  case 'browser/user/input': {
491
+ requireContext();
492
+ await claimContextTab();
236
493
  const type = String(frame.eventType ?? '');
237
- if (type.startsWith('mouse'))
238
- stream.send({ type: 'input_mouse', ...frame, t: undefined });
239
- else
494
+ if (!type.startsWith('mouse')) {
240
495
  stream.send({ type: 'input_keyboard', ...frame, t: undefined });
496
+ return;
497
+ }
498
+ // 鼠标:hover/单击/滚轮走快通路 input_mouse;拖拽手势改走 daemon 带 buttons 的命令通路。
499
+ const plan = routeUserMouse(pointerRoute, frame, Date.now());
500
+ for (const f of plan.stream)
501
+ stream.send(f);
502
+ for (const args of plan.commands)
503
+ enqueueMouseCmd(args);
241
504
  return;
242
505
  }
243
506
  case 'browser/navigate': {
507
+ requireContext();
244
508
  await ensureStarted();
245
509
  const url = normalizeUrl(String(frame.url ?? ''));
246
- await run(frame.newTab ? ['tab', 'new', url] : ['open', url]);
510
+ if (frame.newTab)
511
+ await createContextTab(url);
512
+ else {
513
+ await claimContextTab();
514
+ await run(['open', url]);
515
+ }
247
516
  stream.setCurrentUrl(url);
248
517
  result(frame, true);
249
518
  return;
250
519
  }
251
520
  case 'browser/back':
252
- await run(['back']);
521
+ await runOnContextTab(['back']);
253
522
  result(frame, true);
254
523
  return;
255
524
  case 'browser/forward':
256
- await run(['forward']);
525
+ await runOnContextTab(['forward']);
257
526
  result(frame, true);
258
527
  return;
259
528
  case 'browser/reload':
260
- await run(['reload']);
529
+ await runOnContextTab(['reload']);
261
530
  result(frame, true);
262
531
  return;
263
- case 'browser/tab/new':
264
- await run(frame.url ? ['tab', 'new', normalizeUrl(String(frame.url))] : ['tab', 'new']);
265
- result(frame, true);
532
+ case 'browser/tab/new': {
533
+ const tabId = await createContextTab(frame.url ? normalizeUrl(String(frame.url)) : 'about:blank');
534
+ result(frame, true, { tabId });
266
535
  return;
267
- case 'browser/tab/close':
268
- await run(frame.tabId ? ['tab', 'close', String(frame.tabId)] : ['tab', 'close']);
536
+ }
537
+ case 'browser/tab/close': {
538
+ const context = requireContext();
539
+ const tabId = String(frame.tabId ?? context.activeTabId ?? '');
540
+ if (!tabId)
541
+ throw new Error('无效的标签标识');
542
+ browserRunRegistry.assertTab(context, tabId);
543
+ await run(['tab', 'close', tabId]);
544
+ browserRunRegistry.releaseTab(context.conversationKey, tabId);
545
+ activeTabId = context.activeTabId ?? '';
269
546
  result(frame, true);
270
547
  return;
271
- case 'browser/tab/switch':
272
- await run(['tab', 'switch', String(frame.tabId)]);
548
+ }
549
+ case 'browser/tab/switch': {
550
+ const context = requireContext();
551
+ const tabId = String(frame.tabId ?? '');
552
+ if (!tabId)
553
+ throw new Error('无效的标签标识');
554
+ browserRunRegistry.assertTab(context, tabId);
555
+ await run(['tab', tabId]);
556
+ context.activeTabId = tabId;
557
+ activeTabId = tabId;
273
558
  result(frame, true);
274
559
  return;
275
- case 'browser/tabs':
276
- result(frame, true, parseJsonOutput(await run(['tab', 'list'])));
560
+ }
561
+ case 'browser/tabs': {
562
+ const context = requireContext();
563
+ const bin = await resolveAgentBrowserPath();
564
+ if (!bin)
565
+ throw new Error('未找到内置 agent-browser');
566
+ const tabs = await listBrowserTabs({
567
+ sessionName,
568
+ bin,
569
+ globals: sessionArgs(sessionName),
570
+ runner: spawnRunner,
571
+ });
572
+ const claimed = new Set(browserRunRegistry.claimedTabs(context.conversationKey));
573
+ result(frame, true, tabs.filter((tab) => claimed.has(tab.id)));
277
574
  return;
575
+ }
278
576
  case 'browser/pick': {
279
577
  const element = await pick(Number(frame.x), Number(frame.y));
280
578
  if (!element) {
@@ -291,7 +589,7 @@ export function createBrowserBridge(send, sessionName = 'minimal-agent') {
291
589
  return;
292
590
  }
293
591
  case 'browser/mark/element': {
294
- const raw = parseJsonOutput(await run(['eval', `(() => { const el=document.querySelector(${JSON.stringify(String(frame.selector))}); if(!el)return null; const r=el.getBoundingClientRect(); return {ref:${JSON.stringify(String(frame.selector))},tag:el.tagName.toLowerCase(),text:String(el.innerText||el.textContent||'').trim().slice(0,1000),boundingBox:{x:r.x,y:r.y,width:r.width,height:r.height}} })()`]));
592
+ const raw = parseJsonOutput(await runOnContextTab(['eval', `(() => { const el=document.querySelector(${JSON.stringify(String(frame.selector))}); if(!el)return null; const r=el.getBoundingClientRect(); return {ref:${JSON.stringify(String(frame.selector))},tag:el.tagName.toLowerCase(),text:String(el.innerText||el.textContent||'').trim().slice(0,1000),boundingBox:{x:r.x,y:r.y,width:r.width,height:r.height}} })()`]));
295
593
  if (!raw || typeof raw !== 'object')
296
594
  throw new Error('未找到该元素');
297
595
  stream.markElement({ ...raw, label: typeof frame.label === 'string' ? frame.label : undefined, color: typeof frame.color === 'string' ? frame.color : undefined });
@@ -308,100 +606,100 @@ export function createBrowserBridge(send, sessionName = 'minimal-agent') {
308
606
  result(frame, true);
309
607
  return;
310
608
  case 'browser/dialog/accept':
311
- await run(frame.text ? ['dialog', 'accept', '--text', String(frame.text)] : ['dialog', 'accept']);
609
+ await runOnContextTab(frame.text ? ['dialog', 'accept', '--text', String(frame.text)] : ['dialog', 'accept']);
312
610
  result(frame, true);
313
611
  return;
314
612
  case 'browser/dialog/dismiss':
315
- await run(['dialog', 'dismiss']);
613
+ await runOnContextTab(['dialog', 'dismiss']);
316
614
  result(frame, true);
317
615
  return;
318
616
  case 'browser/snapshot': {
319
- const tree = await run(['snapshot']);
617
+ const tree = await runOnContextTab(['snapshot']);
320
618
  send({ t: 'browser/snapshot', requestId: frame.requestId, tree });
321
619
  return;
322
620
  }
323
621
  case 'browser/getContent': {
324
- const text = await run(['get', 'text', String(frame.selector ?? 'body')]);
622
+ const text = await runOnContextTab(['get', 'text', String(frame.selector ?? 'body')]);
325
623
  send({ t: 'browser/content', requestId: frame.requestId, text });
326
624
  return;
327
625
  }
328
626
  case 'browser/click':
329
- await run(['click', String(frame.selector)]);
627
+ await runOnContextTab(['click', String(frame.selector)]);
330
628
  result(frame, true);
331
629
  return;
332
630
  case 'browser/fill':
333
- await run(['fill', String(frame.selector), String(frame.value ?? '')]);
631
+ await runOnContextTab(['fill', String(frame.selector), String(frame.value ?? '')]);
334
632
  result(frame, true);
335
633
  return;
336
634
  case 'browser/type':
337
- await run(['type', String(frame.selector), String(frame.value ?? '')]);
635
+ await runOnContextTab(['type', String(frame.selector), String(frame.value ?? '')]);
338
636
  result(frame, true);
339
637
  return;
340
638
  case 'browser/hover':
341
- await run(['hover', String(frame.selector)]);
639
+ await runOnContextTab(['hover', String(frame.selector)]);
342
640
  result(frame, true);
343
641
  return;
344
642
  case 'browser/scroll': {
345
643
  const args = frame.selector ? ['scrollintoview', String(frame.selector)] : ['scroll', String(frame.direction ?? 'down'), String(Math.abs(Number(frame.y ?? 600)))];
346
- await run(args);
644
+ await runOnContextTab(args);
347
645
  result(frame, true);
348
646
  return;
349
647
  }
350
648
  case 'browser/select':
351
- await run(['select', String(frame.selector), ...(Array.isArray(frame.value) ? frame.value.map(String) : [String(frame.value ?? '')])]);
649
+ await runOnContextTab(['select', String(frame.selector), ...(Array.isArray(frame.value) ? frame.value.map(String) : [String(frame.value ?? '')])]);
352
650
  result(frame, true);
353
651
  return;
354
652
  case 'browser/press':
355
- await run(['press', String(frame.key)]);
653
+ await runOnContextTab(['press', String(frame.key)]);
356
654
  result(frame, true);
357
655
  return;
358
656
  case 'browser/wait':
359
- await run(frame.selector ? ['wait', String(frame.selector)] : frame.text ? ['wait', '--text', String(frame.text)] : ['wait', String(frame.ms ?? 500)]);
657
+ await runOnContextTab(frame.selector ? ['wait', String(frame.selector)] : frame.text ? ['wait', '--text', String(frame.text)] : ['wait', String(frame.ms ?? 500)]);
360
658
  result(frame, true);
361
659
  return;
362
660
  case 'browser/eval':
363
- result(frame, true, parseJsonOutput(await run(['eval', String(frame.js ?? '')])));
661
+ result(frame, true, parseJsonOutput(await runOnContextTab(['eval', String(frame.js ?? '')])));
364
662
  return;
365
663
  case 'browser/upload':
366
- await run(['upload', String(frame.selector), ...(Array.isArray(frame.files) ? frame.files.map(String) : [])]);
664
+ await runOnContextTab(['upload', String(frame.selector), ...(Array.isArray(frame.files) ? frame.files.map(String) : [])]);
367
665
  result(frame, true);
368
666
  return;
369
667
  case 'browser/drag':
370
- await run(['drag', String(frame.fromSelector), String(frame.toSelector)]);
668
+ await runOnContextTab(['drag', String(frame.fromSelector), String(frame.toSelector)]);
371
669
  result(frame, true);
372
670
  return;
373
671
  case 'browser/screenshot': {
374
672
  const args = ['screenshot', ...(frame.path ? [String(frame.path)] : []), ...(frame.annotate ? ['--annotate'] : []), ...(frame.fullPage ? ['--full'] : [])];
375
- const output = await run(args);
673
+ const output = await runOnContextTab(args);
376
674
  send({ t: 'browser/screenshot', requestId: frame.requestId, path: typeof frame.path === 'string' ? frame.path : undefined, data: output });
377
675
  return;
378
676
  }
379
677
  case 'browser/pdf': {
380
- const output = await run(['pdf', String(frame.path ?? '')]);
678
+ const output = await runOnContextTab(['pdf', String(frame.path ?? '')]);
381
679
  result(frame, true, output);
382
680
  return;
383
681
  }
384
682
  case 'browser/cookies/get':
385
- send({ t: 'browser/cookies', requestId: frame.requestId, cookies: parseJsonOutput(await run(['cookies', 'get'])) ?? [] });
683
+ send({ t: 'browser/cookies', requestId: frame.requestId, cookies: parseJsonOutput(await runOnContextTab(['cookies', 'get'])) ?? [] });
386
684
  return;
387
685
  case 'browser/cookies/clear':
388
- await run(['cookies', 'clear']);
686
+ await runOnContextTab(['cookies', 'clear']);
389
687
  result(frame, true);
390
688
  return;
391
689
  case 'browser/device':
392
- await run(frame.preset ? ['set', 'device', String(frame.preset)] : ['set', 'viewport', String(frame.width), String(frame.height)]);
690
+ await runOnContextTab(frame.preset ? ['set', 'device', String(frame.preset)] : ['set', 'viewport', String(frame.width), String(frame.height)]);
393
691
  result(frame, true);
394
692
  return;
395
693
  case 'browser/media':
396
- await run(['set', 'media', String(frame.scheme ?? 'no-preference')]);
694
+ await runOnContextTab(['set', 'media', String(frame.scheme ?? 'no-preference')]);
397
695
  result(frame, true);
398
696
  return;
399
697
  case 'browser/record/start':
400
- await run(['record', 'start', String(frame.path ?? '')]);
698
+ await runOnContextTab(['record', 'start', String(frame.path ?? '')]);
401
699
  result(frame, true);
402
700
  return;
403
701
  case 'browser/record/stop':
404
- result(frame, true, await run(['record', 'stop']));
702
+ result(frame, true, await runOnContextTab(['record', 'stop']));
405
703
  return;
406
704
  case 'browser/debug/console':
407
705
  case 'browser/debug/errors':
@@ -410,6 +708,7 @@ export function createBrowserBridge(send, sessionName = 'minimal-agent') {
410
708
  case 'browser/debug/vitals':
411
709
  case 'browser/debug/trace/start':
412
710
  case 'browser/debug/trace/stop': {
711
+ await claimContextTab();
413
712
  const browserConfig = await configService.browser();
414
713
  if (!browserConfig.developerMode)
415
714
  throw new Error('请先在“设置 → 浏览器”开启完整 CDP Developer Mode');