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
@@ -0,0 +1,262 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import {
3
+ HumanInterventionCoordinator,
4
+ type HumanInterventionCredential,
5
+ type HumanInterventionEvent,
6
+ type HumanInterventionIdentity,
7
+ type HumanInterventionReason,
8
+ type PendingHumanIntervention,
9
+ } from '../../humanIntervention.js';
10
+
11
+ export type BrowserHumanReason = HumanInterventionReason;
12
+
13
+ /**
14
+ * 控制权状态的**定义已搬进 `src/web/protocol.ts`**(线路协议自持形状),
15
+ * 这里只 re-export,工具侧既有 import 路径一律不变。
16
+ *
17
+ * 为什么搬:desktop 与 server 都从 `minimal-agent/protocol` 取线路类型,
18
+ * 若协议反过来 import 这个工具模块,本工具的任何重构都会顺着协议波及两个
19
+ * 外部消费方。方向必须是工具依赖协议。`test/kernelPurity.test.ts` 守这条线
20
+ * ——它正是靠这条规则把本处揪出来的。
21
+ */
22
+ // 注意是 import + 再 export 两步:单写 `export type { X } from '...'` 只做
23
+ // **再导出**,不会把名字带进本文件的作用域,而下面有五处内部引用要用到它。
24
+ import type { BrowserControlState } from '../../web/protocol.js';
25
+ export type { BrowserControlState };
26
+
27
+ export interface BrowserChallenge {
28
+ reason: Exclude<BrowserHumanReason, 'manual'>;
29
+ summary: string;
30
+ }
31
+
32
+ const CAPTCHA_PATTERNS = [
33
+ /captcha/i,
34
+ /验证码|安全验证|人机验证|完成.{0,8}验证|拖动.{0,12}(滑块|拼图)|滑动.{0,12}(滑块|拼图)/i,
35
+ /verify\s+(?:you are|that you are)\s+(?:a\s+)?human/i,
36
+ // Additional patterns: reCAPTCHA / hCaptcha / Turnstile / Cloudflare / etc.
37
+ /i\s*'?m\s+not\s+a\s+robot/i,
38
+ /checking\s+your\s+browser/i,
39
+ /press\s+&?\s*hold|click\s+to\s+verify|verifying\s+you/i,
40
+ /点击验证|按住滑块|图片验证|行为验证/i,
41
+ ];
42
+ const OTP_PATTERNS = [/一次性密码|短信验证码|邮件验证码|动态口令|\botp\b|one[- ]time (?:password|code)/i];
43
+ const PASSWORD_PATTERNS = [
44
+ /请输入.{0,12}(?:密码|口令)|(?:密码|口令).{0,12}(?:必填|不能为空)/i,
45
+ /(?:enter|type).{0,20}(?:password|passcode)|(?:password|passcode).{0,20}(?:required|cannot be empty)/i,
46
+ ];
47
+ const QR_LOGIN_PATTERNS = [/扫码登录|二维码登录|scan (?:the )?qr|qr code.{0,20}(?:login|sign in)/i];
48
+ const LOGIN_PATTERNS = [/请先登录|登录后继续|扫码登录|sign in to continue|log in to continue/i,
49
+ /please\s+(?:log|sign)\s+in/i,
50
+ ];
51
+ const BLOCK_PATTERNS = [/操作存在异常|访问请求.{0,8}(暂停|拦截)|请求过于频繁|访问受限|access denied|unusual traffic|temporarily blocked/i,
52
+ // 403/429 必须落在 HTTP/错误语境里再判风控,避免把「售价 $429」「forbidden fruit」这类正常正文误判成拦截。
53
+ /rate\s+limit(?:ed)?|too\s+many\s+requests|\b403\s+forbidden\b|http[^\n]{0,10}\b(?:403|429)\b|\b(?:error|status)\s*(?:code)?\s*[::]?\s*(?:403|429)\b/i,
54
+ /被封禁|风控拦截|系统异常/i,
55
+ ];
56
+ const PERMISSION_PATTERNS = [/需要授权|请求权限|permission required|allow access/i];
57
+ const SECURITY_WARNING_PATTERNS = [/安全警告|风险提示|security warning|untrusted (?:application|site|publisher)/i];
58
+
59
+ /** Classifies only explicit page signals. It never attempts to solve or bypass a challenge. */
60
+ export function detectBrowserChallenge(text: string): BrowserChallenge | null {
61
+ const normalized = text.replace(/\s+/g, ' ').slice(0, 200_000);
62
+ if (OTP_PATTERNS.some((pattern) => pattern.test(normalized))) return { reason: 'otp', summary: '页面需要人工输入一次性验证码' };
63
+ if (CAPTCHA_PATTERNS.some((pattern) => pattern.test(normalized))) return { reason: 'captcha', summary: '页面需要人工完成安全验证' };
64
+ if (QR_LOGIN_PATTERNS.some((pattern) => pattern.test(normalized))) return { reason: 'qr_login', summary: '页面需要人工扫码登录' };
65
+ if (PASSWORD_PATTERNS.some((pattern) => pattern.test(normalized))) return { reason: 'password', summary: '页面需要人工输入密码' };
66
+ if (LOGIN_PATTERNS.some((pattern) => pattern.test(normalized))) return { reason: 'login', summary: '页面需要人工登录' };
67
+ if (BLOCK_PATTERNS.some((pattern) => pattern.test(normalized))) return { reason: 'blocked', summary: '网站已暂停或拦截当前访问' };
68
+ if (SECURITY_WARNING_PATTERNS.some((pattern) => pattern.test(normalized))) return { reason: 'security_warning', summary: '页面需要人工处理安全警告' };
69
+ if (PERMISSION_PATTERNS.some((pattern) => pattern.test(normalized))) return { reason: 'permission', summary: '页面需要人工确认权限' };
70
+ return null;
71
+ }
72
+
73
+ type HumanWaiter = {
74
+ interventionId: string;
75
+ };
76
+
77
+ export class BrowserControlCoordinator {
78
+ private state: BrowserControlState = { owner: 'none', status: 'idle' };
79
+ private listeners = new Set<(state: BrowserControlState) => void>();
80
+ private activeIdentity: HumanInterventionIdentity | null = null;
81
+ private activeIntervention: PendingHumanIntervention | null = null;
82
+ private readonly interventions = new HumanInterventionCoordinator();
83
+ private readonly defaultOwnerId: string;
84
+ private readonly defaultConversationKey: string;
85
+
86
+ constructor(input: { ownerId?: string; conversationKey?: string } = {}) {
87
+ this.defaultOwnerId = input.ownerId ?? 'local-owner';
88
+ this.defaultConversationKey = input.conversationKey ?? 'browser:default';
89
+ }
90
+
91
+ getState(): BrowserControlState { return this.state; }
92
+
93
+ subscribe(listener: (state: BrowserControlState) => void): () => void {
94
+ this.listeners.add(listener);
95
+ listener(this.state);
96
+ return () => this.listeners.delete(listener);
97
+ }
98
+
99
+ subscribeInterventions(listener: (event: HumanInterventionEvent) => void): () => void {
100
+ return this.interventions.subscribe(listener);
101
+ }
102
+
103
+ beginAgent(input: { runId: string; conversationKey?: string; action?: string }): void {
104
+ if (this.state.status === 'waiting_human') {
105
+ if (this.state.runId === input.runId) return;
106
+ throw new Error('浏览器正在等待另一个任务的人工处理');
107
+ }
108
+ if (this.state.status === 'running' && this.state.runId !== input.runId) {
109
+ throw new Error('浏览器正在执行另一个会话的原子操作');
110
+ }
111
+ this.activeIdentity = {
112
+ ownerId: this.defaultOwnerId,
113
+ conversationKey: input.conversationKey ?? this.defaultConversationKey,
114
+ runId: input.runId,
115
+ };
116
+ this.setState({ owner: 'agent', status: 'running', ...input });
117
+ }
118
+
119
+ finishAgent(runId: string): void {
120
+ if (this.state.status === 'running' && this.state.runId === runId) {
121
+ this.activeIdentity = null;
122
+ this.setState({ owner: 'none', status: 'idle' });
123
+ }
124
+ }
125
+
126
+ requestHuman(
127
+ reason: BrowserHumanReason,
128
+ input?: { runId?: string; conversationKey?: string; ownerId?: string; summary?: string },
129
+ ): string {
130
+ if (this.state.status === 'waiting_human') {
131
+ if (!input?.runId || this.state.runId === input.runId) return this.state.resumeToken;
132
+ throw new Error('另一个浏览器任务正在等待人工处理');
133
+ }
134
+ const running = this.state.status === 'running' ? this.state : null;
135
+ const identity: HumanInterventionIdentity = {
136
+ ownerId: input?.ownerId ?? this.activeIdentity?.ownerId ?? this.defaultOwnerId,
137
+ conversationKey: input?.conversationKey
138
+ ?? this.activeIdentity?.conversationKey
139
+ ?? running?.conversationKey
140
+ ?? this.defaultConversationKey,
141
+ runId: input?.runId ?? this.activeIdentity?.runId ?? running?.runId ?? randomUUID(),
142
+ };
143
+ const intervention = this.interventions.request({
144
+ ...identity,
145
+ surface: 'browser',
146
+ reason,
147
+ sanitizedSummary: input?.summary ?? summaryForReason(reason),
148
+ });
149
+ this.activeIdentity = identity;
150
+ this.activeIntervention = intervention;
151
+ this.setState({
152
+ owner: 'user',
153
+ status: 'waiting_human',
154
+ runId: identity.runId,
155
+ conversationKey: identity.conversationKey,
156
+ reason,
157
+ interventionId: intervention.id,
158
+ resumeToken: intervention.resumeToken,
159
+ ownerId: identity.ownerId,
160
+ });
161
+ return intervention.resumeToken;
162
+ }
163
+
164
+ takeInteractive(input?: { runId?: string; conversationKey?: string }): void {
165
+ if (this.activeIntervention && this.activeIdentity) {
166
+ this.interventions.cancel(this.credential(this.activeIntervention, this.activeIdentity));
167
+ }
168
+ this.activeIntervention = null;
169
+ this.activeIdentity = null;
170
+ this.setState({ owner: 'user', status: 'interactive', runId: input?.runId, conversationKey: input?.conversationKey });
171
+ }
172
+
173
+ resume(token?: string): boolean {
174
+ if (this.state.status !== 'waiting_human' || !token || !this.activeIntervention || !this.activeIdentity) return false;
175
+ const previous = this.state;
176
+ const ok = this.interventions.resume(this.credential(this.activeIntervention, this.activeIdentity, token));
177
+ if (!ok) return false;
178
+ this.activeIntervention = null;
179
+ this.setState({ owner: 'agent', status: 'running', runId: previous.runId, conversationKey: previous.conversationKey, action: '正在检查人工操作结果' });
180
+ return true;
181
+ }
182
+
183
+ resumeIntervention(credential: HumanInterventionCredential): boolean {
184
+ if (this.state.status !== 'waiting_human' || !this.activeIntervention || !this.activeIdentity) return false;
185
+ const previous = this.state;
186
+ if (!this.interventions.resume(credential)) return false;
187
+ this.activeIntervention = null;
188
+ this.activeIdentity = null;
189
+ this.setState({
190
+ owner: 'agent',
191
+ status: 'running',
192
+ runId: previous.runId,
193
+ conversationKey: previous.conversationKey,
194
+ action: '正在检查人工操作结果',
195
+ });
196
+ return true;
197
+ }
198
+
199
+ stop(token?: string): boolean {
200
+ if (this.state.status === 'waiting_human') {
201
+ if (!token || !this.activeIntervention || !this.activeIdentity) return false;
202
+ const ok = this.interventions.cancel(this.credential(this.activeIntervention, this.activeIdentity, token));
203
+ if (!ok) return false;
204
+ }
205
+ this.activeIntervention = null;
206
+ this.activeIdentity = null;
207
+ this.setState({ owner: 'user', status: 'interactive' });
208
+ return true;
209
+ }
210
+
211
+ cancelIntervention(credential: HumanInterventionCredential): boolean {
212
+ if (this.state.status !== 'waiting_human' || !this.activeIntervention || !this.activeIdentity) return false;
213
+ if (!this.interventions.cancel(credential)) return false;
214
+ this.activeIntervention = null;
215
+ this.activeIdentity = null;
216
+ this.setState({ owner: 'user', status: 'interactive' });
217
+ return true;
218
+ }
219
+
220
+ waitForHuman(signal?: AbortSignal): Promise<'resumed' | 'stopped'> {
221
+ if (this.state.status !== 'waiting_human') return Promise.resolve('resumed');
222
+ const intervention = this.activeIntervention;
223
+ if (!intervention) return Promise.resolve('stopped');
224
+ const waiter: HumanWaiter = { interventionId: intervention.id };
225
+ return this.interventions.wait(waiter.interventionId, signal).then((resolution) => (
226
+ resolution.status === 'resumed' ? 'resumed' : 'stopped'
227
+ ));
228
+ }
229
+
230
+ private setState(state: BrowserControlState): void {
231
+ this.state = state;
232
+ for (const listener of this.listeners) listener(state);
233
+ }
234
+
235
+ private credential(
236
+ intervention: PendingHumanIntervention,
237
+ identity: HumanInterventionIdentity,
238
+ resumeToken = intervention.resumeToken,
239
+ ): HumanInterventionCredential {
240
+ return {
241
+ id: intervention.id,
242
+ resumeToken,
243
+ ownerId: identity.ownerId,
244
+ conversationKey: identity.conversationKey,
245
+ runId: identity.runId,
246
+ };
247
+ }
248
+ }
249
+
250
+ function summaryForReason(reason: BrowserHumanReason): string {
251
+ switch (reason) {
252
+ case 'captcha': return '页面需要人工完成安全验证';
253
+ case 'otp': return '页面需要人工输入一次性验证码';
254
+ case 'password': return '页面需要人工输入密码';
255
+ case 'qr_login': return '页面需要人工扫码登录';
256
+ case 'login': return '页面需要人工登录';
257
+ case 'permission': return '页面需要人工确认权限';
258
+ case 'security_warning': return '页面需要人工处理安全警告';
259
+ case 'blocked': return '网站已暂停或拦截当前访问';
260
+ case 'manual': return '用户已接管浏览器';
261
+ }
262
+ }
@@ -1,7 +1,74 @@
1
+ import { spawn } from 'node:child_process';
2
+ import { dirname, isAbsolute } from 'node:path';
1
3
  import { resolveAgentBrowserPath, resolveBundledChromium, resolveSystemBrowser } from './agentBrowserPath.js';
2
- import { browserGlobalArgs, sessionArgs, spawnRunner } from './browser.js';
4
+ import { browserGlobalArgs, runBounded, sessionArgs, spawnRunner, } from './browser.js';
5
+ /** Daemon 启动(拉起 Chrome + CDP 就绪)总预算:超时即掐断并抛可操作错误,绝不无限挂。 */
6
+ export const DAEMON_BRINGUP_TIMEOUT_MS = 45_000;
7
+ /** 单次 `stream status` 探测预算:daemon socket 卡死时不拖累调用方。 */
8
+ export const STATUS_TIMEOUT_MS = 8_000;
3
9
  const ports = new Map();
4
10
  const starts = new Map();
11
+ const realDaemonDeps = {
12
+ resolveBin: resolveAgentBrowserPath,
13
+ runner: spawnRunner,
14
+ };
15
+ const realReclaimExec = (file, args) => new Promise((resolve) => {
16
+ try {
17
+ const child = spawn(file, args, { stdio: 'ignore', windowsHide: true });
18
+ child.on('close', () => resolve());
19
+ child.on('error', () => resolve());
20
+ }
21
+ catch {
22
+ resolve();
23
+ }
24
+ });
25
+ /**
26
+ * 回收「本仓库/本 App 的」残留 agent-browser daemon + 其 Chrome 子树(Windows `taskkill /F /T`)。
27
+ *
28
+ * 根因:agent-browser 的 daemon 是「黏」的后台进程,`--profile`/`--executable-path` 等 launch-only
29
+ * flag 首次启动即固化、之后忽略(见 readStatus 头注)。一次无 profile 的启动就毒化整个 session,
30
+ * 之后复用继承临时 profile、重启 App 也不解,且孤儿 Chrome 堆积。宿主(Desktop runtime)在启动时
31
+ * 调用一次本函数,把上一轮残留清干净,下次 bring-up 便以我们的持久 `--profile` 干净重启。
32
+ *
33
+ * 安全:**仅**按「已解析二进制所在目录前缀」作用域匹配 agent-browser.exe,绝不误伤安装版桌面 App
34
+ * 或系统上别处的 agent-browser 用法(对标 scripts/dev-browser.ts::reclaimStalePort)。无法作用域限定
35
+ * (PATH 上裸二进制 / 没装)时保守放弃,不做全局杀。幂等、best-effort(失败静默)。
36
+ */
37
+ export async function reclaimStaleDaemons(deps = {}) {
38
+ const platform = deps.platform ?? process.platform;
39
+ const exec = deps.exec ?? realReclaimExec;
40
+ const resolveDir = deps.binDir ??
41
+ (async () => {
42
+ const bin = await resolveAgentBrowserPath();
43
+ return bin && isAbsolute(bin) ? dirname(bin) : null;
44
+ });
45
+ const dir = await resolveDir();
46
+ if (!dir)
47
+ return;
48
+ ports.clear();
49
+ if (platform === 'win32') {
50
+ const root = dir.toLowerCase().replace(/'/g, "''");
51
+ const ps =
52
+ // (a) 本 App 路径下的 agent-browser daemon + 其 Chrome 子树。
53
+ `Get-CimInstance Win32_Process -Filter "Name='agent-browser.exe'" | ` +
54
+ `Where-Object { $_.ExecutablePath -and $_.ExecutablePath.ToLower().StartsWith('${root}') } | ` +
55
+ `ForEach-Object { taskkill /F /T /PID $_.ProcessId 2>$null | Out-Null }; ` +
56
+ // (b) 真孤儿 agent-browser Chrome(父进程已死)。daemon 崩溃后残留、上面的 agent-browser 树
57
+ // 够不着,堆积起来会把新 daemon 的 Chrome 拉起拖到几十秒(实测 18 棵孤儿 → 卡 43s;
58
+ // 清空后同一启动仅 1s)。**只杀父进程已不在的孤儿**,绝不误伤有活父进程的正常浏览器
59
+ // (安装版 App 的活浏览器父 agent-browser 健在 → 不匹配,天然豁免)。
60
+ `$alive=@{}; Get-CimInstance Win32_Process | ForEach-Object { $alive[[int]$_.ProcessId]=$true }; ` +
61
+ `Get-CimInstance Win32_Process -Filter "Name='chrome.exe'" | ` +
62
+ `Where-Object { ($_.CommandLine -match 'agent-browser-chrome' -or $_.CommandLine -match '\\.minimal-agent.{0,40}profiles') -and -not $alive.ContainsKey([int]$_.ParentProcessId) } | ` +
63
+ `ForEach-Object { taskkill /F /T /PID $_.ProcessId 2>$null | Out-Null }`;
64
+ await exec('powershell', ['-NoProfile', '-NonInteractive', '-Command', ps]);
65
+ }
66
+ else {
67
+ // unix:按可执行路径前缀 pkill agent-browser(其 Chrome 子进程随之收尾)。unix 孤儿会被
68
+ // reparent 到 init,无「父已死」信号,故此处不做等价的孤儿 Chrome 清扫(Windows 才是主战场)。
69
+ await exec('pkill', ['-f', `${dir}/agent-browser`]);
70
+ }
71
+ }
5
72
  function parsePort(text) {
6
73
  const match = text.match(/ws:\/\/(?:127\.0\.0\.1|localhost):([0-9]+)/i);
7
74
  if (!match)
@@ -13,82 +80,123 @@ function browserRuntimeMissing(text) {
13
80
  return /browser\s+(?:not found|was not found)|chrom(?:e|ium).*(?:not found|missing)|executable.*(?:not found|does not exist)|run ['\"]?agent-browser install/i.test(text);
14
81
  }
15
82
  export { browserRuntimeMissing as _browserRuntimeMissing };
16
- async function readStatus(bin, sessionName) {
83
+ async function readStatus(bin, sessionName, opts = {}, deps = realDaemonDeps) {
17
84
  // Profile/executable flags are launch-only. Repeating them against a running
18
85
  // daemon makes agent-browser ignore the profile and emit misleading warnings.
19
- const result = await spawnRunner(bin, [...sessionArgs(sessionName), 'stream', 'status']);
86
+ // 有界:daemon socket 卡死时不把 status 探测拖成无限挂(getStreamPort/ensureDaemon 都靠它)。
87
+ const result = await runBounded(bin, [...sessionArgs(sessionName), 'stream', 'status'], { signal: opts.signal, timeoutMs: opts.timeoutMs ?? STATUS_TIMEOUT_MS }, deps.runner);
20
88
  if (result.code !== 0)
21
89
  return { port: null, connected: false };
22
90
  const text = `${result.stdout}\n${result.stderr}`;
23
91
  return { port: parsePort(text), connected: /Connected:\s*true/i.test(text) };
24
92
  }
25
- export async function ensureDaemon(sessionName = 'minimal-agent') {
26
- const bin = await resolveAgentBrowserPath();
93
+ export async function ensureDaemon(sessionName = 'minimal-agent', opts = {}, deps = realDaemonDeps) {
94
+ const bin = await deps.resolveBin();
27
95
  if (!bin)
28
96
  throw new Error('未找到 agent-browser 可执行文件');
29
- const status = await readStatus(bin, sessionName);
97
+ const status = await readStatus(bin, sessionName, { signal: opts.signal }, deps);
30
98
  if (status.port && status.connected) {
31
99
  ports.set(sessionName, status.port);
32
100
  return { sessionName, streamPort: status.port, alreadyRunning: true };
33
101
  }
102
+ // 半死 daemon(socket 端口在、但 Chrome 已亡 connected:false):对谁都没用,先回收再重启,
103
+ // 否则新 open 可能连到无 Chrome 的僵尸 daemon 上卡死。回收对健康的共享 daemon 无影响(那会
104
+ // 走上面的 connected 分支直接复用)。
105
+ if (status.port && !status.connected) {
106
+ await reclaimStaleDaemons(opts.reclaim);
107
+ }
34
108
  const pending = starts.get(sessionName);
35
109
  if (pending)
36
110
  return pending;
111
+ const budget = opts.timeoutMs ?? DAEMON_BRINGUP_TIMEOUT_MS;
37
112
  const start = (async () => {
38
- const globals = await browserGlobalArgs(sessionName);
39
- // Prefer a stable system browser executable, but always use KakadeAI's
40
- // isolated profile. Bundled Chromium remains an offline fallback.
41
- const systemBrowser = resolveSystemBrowser();
42
- let opened = await spawnRunner(bin, [
43
- ...globals,
44
- ...(systemBrowser ? ['--executable-path', systemBrowser] : []),
45
- 'open',
46
- 'about:blank',
47
- ]);
48
- if (opened.code !== 0 && browserRuntimeMissing(`${opened.stderr}\n${opened.stdout}`)) {
49
- const chromium = resolveBundledChromium();
50
- if (chromium) {
51
- opened = await spawnRunner(bin, [...globals, '--executable-path', chromium, 'open', 'about:blank']);
113
+ // Bring-up 边界:父级 signal abort 或超预算即掐断所有内部子进程。旧缺陷是 ensureDaemon
114
+ // 全程无 timeout、不接 signal —— Chrome/CDP 起不来时无限挂、用户 stop/ESC 也掐不断
115
+ // (「访问网站卡 5m53s」的根因)。这里统一一个控制器兜住整段启动。
116
+ const ac = new AbortController();
117
+ let timedOut = false;
118
+ const onParent = () => ac.abort(opts.signal?.reason);
119
+ const timer = setTimeout(() => {
120
+ timedOut = true;
121
+ ac.abort();
122
+ }, budget);
123
+ if (opts.signal) {
124
+ if (opts.signal.aborted)
125
+ ac.abort(opts.signal.reason);
126
+ else
127
+ opts.signal.addEventListener('abort', onParent, { once: true });
128
+ }
129
+ const bringUpError = () => new Error(timedOut
130
+ ? `内置浏览器启动超时:Chrome 未在 ${Math.round(budget / 1000)}s 内就绪(可能被残留浏览器进程占用)。可稍后重试,或改用 WebFetch 读取网页。`
131
+ : '内置浏览器启动已被中断。');
132
+ const run = (args) => deps.runner(bin, args, ac.signal);
133
+ try {
134
+ const globals = await browserGlobalArgs(sessionName);
135
+ // Prefer a stable system browser executable, but always use KakadeAI's
136
+ // isolated profile. Bundled Chromium remains an offline fallback.
137
+ const systemBrowser = resolveSystemBrowser();
138
+ let opened = await run([
139
+ ...globals,
140
+ ...(systemBrowser ? ['--executable-path', systemBrowser] : []),
141
+ 'open',
142
+ 'about:blank',
143
+ ]);
144
+ if (ac.signal.aborted)
145
+ throw bringUpError();
146
+ if (opened.code !== 0 && browserRuntimeMissing(`${opened.stderr}\n${opened.stdout}`)) {
147
+ const chromium = resolveBundledChromium();
148
+ if (chromium) {
149
+ opened = await run([...globals, '--executable-path', chromium, 'open', 'about:blank']);
150
+ }
151
+ else {
152
+ const installed = await run(['install']);
153
+ if (installed.code === 0)
154
+ opened = await run([...globals, 'open', 'about:blank']);
155
+ }
156
+ if (ac.signal.aborted)
157
+ throw bringUpError();
52
158
  }
53
- else {
54
- const installed = await spawnRunner(bin, ['install']);
55
- if (installed.code === 0)
56
- opened = await spawnRunner(bin, [...globals, 'open', 'about:blank']);
159
+ if (opened.code !== 0) {
160
+ throw new Error((opened.stderr || opened.stdout || '浏览器启动失败').trim());
57
161
  }
162
+ const streamPort = await waitForStreamPort(sessionName, 10_000, deps);
163
+ ports.set(sessionName, streamPort);
164
+ return { sessionName, streamPort, alreadyRunning: false };
58
165
  }
59
- if (opened.code !== 0) {
60
- throw new Error((opened.stderr || opened.stdout || '浏览器启动失败').trim());
166
+ finally {
167
+ clearTimeout(timer);
168
+ opts.signal?.removeEventListener('abort', onParent);
61
169
  }
62
- const streamPort = await waitForStreamPort(sessionName, 10_000);
63
- ports.set(sessionName, streamPort);
64
- return { sessionName, streamPort, alreadyRunning: false };
65
170
  })().finally(() => starts.delete(sessionName));
66
171
  starts.set(sessionName, start);
67
172
  return start;
68
173
  }
69
- export async function stopDaemon(sessionName = 'minimal-agent') {
70
- const bin = await resolveAgentBrowserPath();
174
+ export async function stopDaemon(sessionName = 'minimal-agent', deps = realDaemonDeps, reclaim) {
175
+ const bin = await deps.resolveBin();
71
176
  ports.delete(sessionName);
72
- if (!bin)
73
- return;
74
- await spawnRunner(bin, [...sessionArgs(sessionName), 'close']);
177
+ if (bin) {
178
+ await runBounded(bin, [...sessionArgs(sessionName), 'close'], { timeoutMs: STATUS_TIMEOUT_MS }, deps.runner);
179
+ }
180
+ // 优雅 close 之外再 tree-kill 一遍本 App 路径下的残留:崩溃/close 不彻底时仍杜绝临时 profile
181
+ // 孤儿 Chrome 堆积(实测同时存活 ≥2 棵孤儿 Chrome 树的根因)。
182
+ await reclaimStaleDaemons(reclaim);
75
183
  }
76
- export async function getStreamPort(sessionName = 'minimal-agent') {
184
+ export async function getStreamPort(sessionName = 'minimal-agent', deps = realDaemonDeps) {
77
185
  const cached = ports.get(sessionName);
78
186
  if (cached)
79
187
  return cached;
80
- const bin = await resolveAgentBrowserPath();
188
+ const bin = await deps.resolveBin();
81
189
  if (!bin)
82
190
  return null;
83
- const port = (await readStatus(bin, sessionName)).port;
191
+ const port = (await readStatus(bin, sessionName, {}, deps)).port;
84
192
  if (port)
85
193
  ports.set(sessionName, port);
86
194
  return port;
87
195
  }
88
- export async function waitForStreamPort(sessionName = 'minimal-agent', timeoutMs = 10_000) {
196
+ export async function waitForStreamPort(sessionName = 'minimal-agent', timeoutMs = 10_000, deps = realDaemonDeps) {
89
197
  const deadline = Date.now() + timeoutMs;
90
198
  while (Date.now() < deadline) {
91
- const port = await getStreamPort(sessionName);
199
+ const port = await getStreamPort(sessionName, deps);
92
200
  if (port)
93
201
  return port;
94
202
  await new Promise((resolve) => setTimeout(resolve, 120));