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,281 @@
1
+ /**
2
+ * ============================================================
3
+ * src/tools/bash/attachImage.ts —— Bash 的「让模型看一眼这张图」协议
4
+ * ------------------------------------------------------------
5
+ * 背景(为什么需要这个口子):
6
+ * Read 工具明确拒绝二进制/图片(read.ts 的黑名单),Bash 只能回文本,
7
+ * 全仓库唯一会产 `ToolResult.visionImages` 的是 WebBrowser。于是任何
8
+ * 「skill 脚本生成/截取了一张图,想让模型亲眼看看」的场景都物理上做不到 ——
9
+ * computer-use(截屏)、生图核验、图表渲染核验全卡在这一处。
10
+ *
11
+ * 方案:约定一个 stdout sentinel。脚本自己打一行
12
+ * <<<ATTACH_IMAGE:/abs/path.png|detail=low|maxLongSide=960>>>
13
+ * Bash 解析出来填进 visionImages,并把该行**从给模型看的 content 里剥掉**
14
+ * (协议是给宿主看的,不是给模型读的噪声)。
15
+ *
16
+ * 为什么是 Bash 的 sentinel 而不是新工具:
17
+ * 工具 schema 已占稳定系统提示词前缀的绝大头,新增一个多 action 的工具
18
+ * 等于让**所有用户的每次请求**都为它付 token。sentinel 是零新增 schema
19
+ * 字节的加性改动,而且天然通用 —— 任何脚本都能用,不绑任何具体 skill。
20
+ *
21
+ * 安全边界(重要):
22
+ * `multimodal.ts::imageToContentPart` 对路径**没有任何沙箱**,它会老实读
23
+ * 任何给它的绝对路径并 base64 进请求体。既然现在允许「命令输出决定读哪个
24
+ * 文件」,防线就必须建在这里:
25
+ * ① 路径必须落在 cwd 或系统临时目录之下(realpath 之后比较,防软链逃逸)
26
+ * ② 数量上限(图很贵,一次回 20 张能直接打爆上下文)
27
+ * ③ 单图与总字节上限
28
+ * 越界的一律拒绝,并**如实写进 content 告诉模型哪张被拒、为什么** ——
29
+ * 静默丢弃会让脚本作者以为图发出去了,debug 时无从下手。
30
+ * ============================================================
31
+ */
32
+
33
+ import { open, realpath, stat } from 'node:fs/promises';
34
+ import { tmpdir } from 'node:os';
35
+ import { basename, dirname, join, resolve } from 'node:path';
36
+
37
+ import { getWorkingDir } from '../../bootstrap/workingDir.js';
38
+ import { pathContains } from '../../utils/pathContains.js';
39
+ import { MAX_IMAGE_BYTES, sniffImageMime } from '../../multimodal.js';
40
+ import type { ImageDetail, ImageInputSpec } from '../../types.js';
41
+
42
+ /** 一次 Bash 调用最多附多少张图。图是上下文里最贵的东西,宁少勿多。 */
43
+ export const MAX_ATTACH_IMAGES = 4;
44
+
45
+ /**
46
+ * 一次 Bash 调用附图的总字节上限。取单图上限的 2 倍而非 4 倍:
47
+ * base64 会把体积撑到约 4/3,且 provider 侧有请求体上限(Claude 32MB),
48
+ * 留足余量给同一请求里的文本与历史。
49
+ */
50
+ export const MAX_ATTACH_TOTAL_BYTES = MAX_IMAGE_BYTES * 2;
51
+
52
+ /** 整行 sentinel(必须独占一行;行首尾允许空白)。 */
53
+ const SENTINEL_LINE = /^[ \t]*<<<ATTACH_IMAGE:(.*?)>>>[ \t]*$/;
54
+
55
+ /** 已知的可选段,从 payload 尾部往前剥;剩下的(可能含 `|`)才是路径。 */
56
+ const OPTION_SEGMENT = /^(detail|maxLongSide)=(.*)$/;
57
+
58
+ const VALID_DETAILS: ReadonlySet<string> = new Set<ImageDetail>(['low', 'default', 'high']);
59
+
60
+ /** 解析出来但还没经过 fs / 边界校验的一条指令。 */
61
+ export interface AttachImageDirective {
62
+ /** sentinel 里写的原始路径(可能是相对路径) */
63
+ rawPath: string;
64
+ detail?: ImageDetail;
65
+ maxLongSidePixel?: number;
66
+ }
67
+
68
+ export interface ExtractResult {
69
+ /** 剥掉全部 sentinel 行之后的 stdout */
70
+ text: string;
71
+ directives: AttachImageDirective[];
72
+ }
73
+
74
+ /**
75
+ * 纯函数:从 stdout 里摘出 sentinel 行并剥除。不碰文件系统,便于单测。
76
+ *
77
+ * 无法识别的 payload(如空路径、只有选项没有路径)当作**普通输出行保留** ——
78
+ * 宁可让模型看到一行奇怪的文本,也不要把用户真实的输出悄悄吃掉。
79
+ */
80
+ export function extractAttachImageDirectives(stdout: string): ExtractResult {
81
+ if (!stdout.includes('<<<ATTACH_IMAGE:')) {
82
+ return { text: stdout, directives: [] };
83
+ }
84
+
85
+ const directives: AttachImageDirective[] = [];
86
+ const kept: string[] = [];
87
+
88
+ for (const line of stdout.split('\n')) {
89
+ const match = SENTINEL_LINE.exec(line);
90
+ if (!match) {
91
+ kept.push(line);
92
+ continue;
93
+ }
94
+ const directive = parsePayload(match[1] ?? '');
95
+ if (!directive) {
96
+ kept.push(line); // 认不出来的形状原样保留,不静默吞
97
+ continue;
98
+ }
99
+ directives.push(directive);
100
+ }
101
+
102
+ return { text: kept.join('\n'), directives };
103
+ }
104
+
105
+ /** 从尾部剥已知选项段,剩余部分(重新用 `|` 拼回)是路径 —— 容忍路径里含 `|`。 */
106
+ function parsePayload(payload: string): AttachImageDirective | null {
107
+ const segments = payload.split('|');
108
+ let detail: ImageDetail | undefined;
109
+ let maxLongSidePixel: number | undefined;
110
+
111
+ while (segments.length > 1) {
112
+ const tail = segments[segments.length - 1]!;
113
+ const option = OPTION_SEGMENT.exec(tail.trim());
114
+ if (!option) break;
115
+
116
+ const [, key, rawValue] = option;
117
+ const value = (rawValue ?? '').trim();
118
+ if (key === 'detail') {
119
+ if (!VALID_DETAILS.has(value)) return null; // 写错了就整条不认,别猜
120
+ detail = value as ImageDetail;
121
+ } else {
122
+ const n = Number(value);
123
+ if (!Number.isFinite(n) || n <= 0) return null;
124
+ maxLongSidePixel = Math.floor(n);
125
+ }
126
+ segments.pop();
127
+ }
128
+
129
+ const rawPath = segments.join('|').trim();
130
+ if (!rawPath) return null;
131
+
132
+ return {
133
+ rawPath,
134
+ ...(detail ? { detail } : {}),
135
+ ...(maxLongSidePixel !== undefined ? { maxLongSidePixel } : {}),
136
+ };
137
+ }
138
+
139
+ export interface ResolveResult {
140
+ images: ImageInputSpec[];
141
+ /** 被拒绝的条目说明;调用方须把它拼进 content,让模型知道图没发出去。 */
142
+ rejections: string[];
143
+ }
144
+
145
+ export interface ResolveOptions {
146
+ /** 允许的根目录(默认 cwd + 系统临时目录)。测试可注入。 */
147
+ allowedRoots?: string[];
148
+ maxImages?: number;
149
+ maxTotalBytes?: number;
150
+ }
151
+
152
+ /**
153
+ * 校验并解析成 `ImageInputSpec`。逐条独立判定 —— 一张被拒不影响其它张。
154
+ */
155
+ export async function resolveAttachImages(
156
+ directives: AttachImageDirective[],
157
+ options: ResolveOptions = {},
158
+ ): Promise<ResolveResult> {
159
+ if (directives.length === 0) return { images: [], rejections: [] };
160
+
161
+ const maxImages = options.maxImages ?? MAX_ATTACH_IMAGES;
162
+ const maxTotalBytes = options.maxTotalBytes ?? MAX_ATTACH_TOTAL_BYTES;
163
+ const roots = await canonicalRoots(options.allowedRoots ?? [getWorkingDir(), tmpdir()]);
164
+
165
+ const images: ImageInputSpec[] = [];
166
+ const rejections: string[] = [];
167
+ let totalBytes = 0;
168
+
169
+ for (const directive of directives) {
170
+ if (images.length >= maxImages) {
171
+ rejections.push(`${directive.rawPath}:一次最多附 ${maxImages} 张图,已超出`);
172
+ continue;
173
+ }
174
+
175
+ const absolute = resolve(getWorkingDir(), directive.rawPath);
176
+ const canonical = await canonicalize(absolute);
177
+
178
+ if (!roots.some((root) => isInside(root, canonical))) {
179
+ rejections.push(
180
+ `${directive.rawPath}:路径不在当前工作目录或系统临时目录之下,已拒绝`,
181
+ );
182
+ continue;
183
+ }
184
+
185
+ const st = await stat(canonical).catch(() => null);
186
+ if (!st) {
187
+ rejections.push(`${directive.rawPath}:文件不存在或不可读`);
188
+ continue;
189
+ }
190
+ if (!st.isFile()) {
191
+ rejections.push(`${directive.rawPath}:不是普通文件`);
192
+ continue;
193
+ }
194
+ if (st.size > MAX_IMAGE_BYTES) {
195
+ rejections.push(
196
+ `${directive.rawPath}:单图 ${(st.size / 1024 / 1024).toFixed(1)}MB 超过 ${MAX_IMAGE_BYTES / 1024 / 1024}MB 上限`,
197
+ );
198
+ continue;
199
+ }
200
+ if (totalBytes + st.size > maxTotalBytes) {
201
+ rejections.push(
202
+ `${directive.rawPath}:累计体积超过 ${maxTotalBytes / 1024 / 1024}MB 上限,已跳过`,
203
+ );
204
+ continue;
205
+ }
206
+
207
+ const mime = await sniffFileImageMime(canonical);
208
+ if (!mime) {
209
+ rejections.push(
210
+ `${directive.rawPath}:文件内容不是受支持的 JPEG/PNG/GIF/WEBP 图片,已跳过`,
211
+ );
212
+ continue;
213
+ }
214
+
215
+ totalBytes += st.size;
216
+ images.push({
217
+ source: canonical,
218
+ ...(directive.detail ? { detail: directive.detail } : {}),
219
+ ...(directive.maxLongSidePixel !== undefined
220
+ ? { maxLongSidePixel: directive.maxLongSidePixel }
221
+ : {}),
222
+ });
223
+ }
224
+
225
+ return { images, rejections };
226
+ }
227
+
228
+ /**
229
+ * 在接受 sentinel 时验魔数,不依赖扩展名。只读取头部,避免为拒绝一张大文件
230
+ * 再做一次完整读取。逐条返回 null,由调用方记录 rejection,不抛到整个回合。
231
+ */
232
+ async function sniffFileImageMime(path: string): Promise<string | null> {
233
+ let handle;
234
+ try {
235
+ handle = await open(path, 'r');
236
+ const header = Buffer.alloc(16);
237
+ const { bytesRead } = await handle.read(header, 0, header.length, 0);
238
+ return sniffImageMime(header.subarray(0, bytesRead));
239
+ } catch {
240
+ return null;
241
+ } finally {
242
+ await handle?.close().catch(() => {});
243
+ }
244
+ }
245
+
246
+ /**
247
+ * realpath 之后再比较 —— 否则一条指向 /etc 的软链就能绕过根目录白名单。
248
+ *
249
+ * 目标不存在时不能简单退回 `resolve()`:macOS 的 `os.tmpdir()` 是
250
+ * `/var/folders/…`(软链到 `/private/var/folders/…`),根目录已归一化而目标没有,
251
+ * 于是「临时目录下一个还没生成的文件」会被判成**越界**而不是**不存在** ——
252
+ * 报错指向错误的原因,脚本作者会去查权限而不是去查文件名。
253
+ * 因此回退到「归一化最近的存在祖先,再接回剩余段」。
254
+ */
255
+ async function canonicalize(path: string): Promise<string> {
256
+ const absolute = resolve(path);
257
+ try {
258
+ return await realpath(absolute);
259
+ } catch {
260
+ const parent = dirname(absolute);
261
+ if (parent === absolute) return absolute; // 已到根,停止递归
262
+ return join(await canonicalize(parent), basename(absolute));
263
+ }
264
+ }
265
+
266
+ /**
267
+ * 根目录也必须 realpath:macOS 的 `os.tmpdir()` 返回 `/var/folders/...`,
268
+ * 而它其实是 `/private/var/folders/...` 的软链 —— 不归一化的话临时目录里的
269
+ * 图会被自己的边界检查误杀。
270
+ */
271
+ async function canonicalRoots(roots: string[]): Promise<string[]> {
272
+ const out: string[] = [];
273
+ for (const root of roots) {
274
+ const canonical = await canonicalize(resolve(root));
275
+ if (!out.includes(canonical)) out.push(canonical);
276
+ }
277
+ return out;
278
+ }
279
+
280
+ /** target 是否落在 root 之内(含 root 自身)。判据实现见 `utils/pathContains.ts`(全仓唯一一份)。 */
281
+ const isInside = pathContains;
@@ -49,8 +49,15 @@ import { sanitizeCredentialEnv } from '../../config/configService.js';
49
49
  import { DEFAULT_MAX_RESULT_SIZE_CHARS } from '../types.js';
50
50
  import { killTree } from '../shared/killTree.js';
51
51
  import { toToolParameters } from '../../utils/zodToJson.js';
52
+ import { MAX_ATTACH_IMAGES, extractAttachImageDirectives, resolveAttachImages, } from './attachImage.js';
52
53
  import { interpretCommandResult } from './semantics.js';
53
54
  import { scanDestructiveCommand } from './warnings.js';
55
+ import { requestUserChoice } from '../../askBridge.js';
56
+ import { classifyCommand } from '../../irreversible/rules.js';
57
+ import { startBackgroundTask } from '../tasks/backgroundTaskService.js';
58
+ import { processExecutionMetadata } from '../tasks/processEvidence.js';
59
+ import { permanentDeleteReason } from '../shared/permanentDeleteGuard.js';
60
+ import { ToolOutputStore } from '../shared/toolOutputStore.js';
54
61
  // ---------------- 0. 常量 ----------------
55
62
  const DEFAULT_TIMEOUT_MS = 120_000; // 2 min
56
63
  const MAX_TIMEOUT_MS = 600_000; // 10 min
@@ -250,6 +257,7 @@ const inputSchema = z.object({
250
257
  .string()
251
258
  .optional()
252
259
  .describe('用一句话主动语态描述命令做什么(5-10 词),如 "List files in current directory"'),
260
+ run_in_background: z.boolean().optional().describe('长时间构建、测试或开发服务器设为 true;用 TaskOutput 获取增量输出、TaskStop 停止'),
253
261
  });
254
262
  // ---------------- 2. JSON Schema(由 Zod 自动派生) ----------------
255
263
  const parameters = toToolParameters(inputSchema);
@@ -290,6 +298,11 @@ While the Bash tool can do similar things, it's better to use the built-in tools
290
298
  - Never skip hooks (--no-verify) or bypass signing (--no-gpg-sign, -c commit.gpgsign=false) unless the user has explicitly asked for it. If a hook fails, investigate and fix the underlying issue.
291
299
  - Avoid unnecessary \`sleep\` commands; do not retry failing commands in a sleep loop — diagnose the root cause.
292
300
 
301
+ # Viewing images
302
+ Read cannot open images. To look at one (screenshot, chart, photo), print a line by itself:
303
+ \`<<<ATTACH_IMAGE:/abs/path.png>>>\` — optionally \`|detail=low\` (cheap overview) and \`|maxLongSide=960\`.
304
+ The image is attached for you to see and the line is stripped from the output. Up to ${MAX_ATTACH_IMAGES} per call; the file must live under the working directory or the system temp directory.
305
+
293
306
  # Exit code semantics
294
307
  Some commands return non-zero exit codes for informational (non-error) reasons. Bash recognizes these and reports them as success (ok=true) — do NOT retry just because exit code is 1:
295
308
  - \`grep\` / \`rg\` exit 1 → no match found (not an error)
@@ -325,7 +338,7 @@ No bash found on this Windows machine: commands run in cmd.exe (UTF-8 enforced).
325
338
  - Use \`dir\` / \`copy\` / \`del\` / \`type\` instead of \`ls\` / \`cp\` / \`rm\` / \`cat\`
326
339
  \`&&\` and \`;\`-style chaining: \`&&\` works in cmd; \`;\` does not (use \`&\`).`}`;
327
340
  // ---------------- 4. call() —— 真正干活 ----------------
328
- async function call(input, signal) {
341
+ async function call(input, signal, context) {
329
342
  const command = input.command;
330
343
  const timeoutMs = Math.min(input.timeout ?? DEFAULT_TIMEOUT_MS, MAX_TIMEOUT_MS);
331
344
  // 4a. 安全黑名单(命中即拒)
@@ -336,15 +349,81 @@ async function call(input, signal) {
336
349
  error: `安全检查拒绝执行:${forbiddenReason}\n命令:${command}`,
337
350
  };
338
351
  }
352
+ const permanentDelete = permanentDeleteReason(command, 'bash');
353
+ if (permanentDelete)
354
+ return { ok: false, error: `永久删除检查拒绝执行:${permanentDelete}\n命令:${command}` };
355
+ // 4a-1. 不可逆动作闸门:毁掉「最后一份副本」的命令要**停下来问人**。
356
+ //
357
+ // 与上面黑名单的分工:黑名单是「灾难且无正当用途」→ 直接拒;这里是
358
+ // 「不可逆但有正当用途」(force push / 删库 / 毁 reflog)→ 问一句。
359
+ // 判据与规则表都在内核 `src/irreversible/rules.ts`,与 ComputerUse 共用。
360
+ //
361
+ // ★ 选项顺序不能改:askBridge 在**没有交互宿主**时(`-p`、cron、子 agent)
362
+ // 自动选第一项。所以第一项必须是「取消」——无人可问时 fail-closed。
363
+ const irreversible = classifyCommand(command);
364
+ if (irreversible) {
365
+ const [answer] = await requestUserChoice([
366
+ {
367
+ question: `这条命令不可逆:${irreversible.why}。\n\n命令:${command}\n\n确认执行吗?`,
368
+ header: '不可逆操作',
369
+ options: [
370
+ { label: '取消,不执行 (推荐)', description: '放弃这一步,请 AI 换个可回滚的做法' },
371
+ { label: '我已确认后果,执行', description: '我清楚这一步做完找不回来' },
372
+ ],
373
+ },
374
+ ], signal);
375
+ const approved = answer?.selected?.[0]?.includes('执行') === true
376
+ && answer.selected[0]?.includes('取消') !== true;
377
+ if (!approved) {
378
+ return {
379
+ ok: false,
380
+ // 明确要求模型**停下**而不是改写命令绕过去。没有这句,模型收到拒绝后
381
+ // 极可能把 `--force` 换成 `-f`、把 `push --force` 换成 `push origin +main`
382
+ // 再试一次 —— 那既绕过了闸门,也不是用户想要的。
383
+ error: `已被用户/策略拒绝执行(不可逆操作:${irreversible.why})。\n` +
384
+ `命令:${command}\n\n` +
385
+ `请**不要**改写命令重试(换 -f、换 +refspec、拆成多条都算绕过)。` +
386
+ `改用可回滚的做法,或直接把这一步交还给用户手动执行。`,
387
+ };
388
+ }
389
+ }
339
390
  // 4a-2. 破坏性命令告警扫描(仅警告,不阻塞)
340
391
  // 命中后把警告挂到结果输出顶部,让模型/用户看见苗头。
341
392
  const destructiveWarning = scanDestructiveCommand(command);
393
+ if (input.run_in_background) {
394
+ try {
395
+ const cwd = context?.cwd ?? getWorkingDir();
396
+ const task = await startBackgroundTask(WIN_BASH
397
+ ? { command, executable: WIN_BASH, args: ['-c', command], cwd, env: sanitizedChildEnv(), sessionId: context?.sessionId, workspaceId: context?.workspaceId, shellKind: 'bash' }
398
+ : {
399
+ command: process.platform === 'win32' ? `chcp 65001 >nul & ${command}` : command,
400
+ cwd,
401
+ env: sanitizedChildEnv(),
402
+ shell: true,
403
+ sessionId: context?.sessionId,
404
+ workspaceId: context?.workspaceId,
405
+ shellKind: 'bash',
406
+ }, context?.sessionState?.backgroundTasks);
407
+ return {
408
+ ok: true,
409
+ content: `${destructiveWarning ? `⚠️ 警告: ${destructiveWarning}\n` : ''}后台任务已启动。task_id=${task.id.replace(/^proc_/, '')}\nprocess_id=${task.id}\nlog=${task.logPath}\n使用 TaskOutput 增量读取输出,TaskStop 停止进程。`,
410
+ metadata: processExecutionMetadata({ shell: 'bash', mode: 'background', command, status: 'started', taskId: task.id }),
411
+ };
412
+ }
413
+ catch (error) {
414
+ return { ok: false, error: `后台命令启动失败:${error.message}` };
415
+ }
416
+ }
342
417
  // 4b. spawn —— 平台分派(见 0b 探测注释):
343
418
  // Unix: /bin/sh -c <command>(shell:true)
344
419
  // Windows + Git Bash: bash.exe -c <command>(POSIX 语法成立)
345
420
  // Windows 无 bash: cmd.exe,命令前缀 chcp 65001 强制 UTF-8 输出
346
421
  let stdout = '';
347
422
  let stderr = '';
423
+ const outputStore = new ToolOutputStore({
424
+ workspaceId: context?.workspaceId,
425
+ sessionId: context?.sessionId,
426
+ });
348
427
  let exitCode = null;
349
428
  let timedOut = false;
350
429
  let killedBySignal = false;
@@ -359,7 +438,7 @@ async function call(input, signal) {
359
438
  try {
360
439
  await new Promise((resolveP, rejectP) => {
361
440
  const spawnOpts = {
362
- cwd: getWorkingDir(),
441
+ cwd: context?.cwd ?? getWorkingDir(),
363
442
  env: sanitizedChildEnv(),
364
443
  windowsHide: true,
365
444
  // POSIX:detached 自成进程组,中断时 killTree 的 kill(-pid) 才能掀整组;win32 不 detached(taskkill /T 掀树)。
@@ -387,14 +466,16 @@ async function call(input, signal) {
387
466
  child.stdout?.setEncoding('utf8');
388
467
  child.stderr?.setEncoding('utf8');
389
468
  child.stdout?.on('data', (chunk) => {
390
- // G1:即时封顶,防止狂输出命令在最终截断前撑爆内存(OOM)。不强行 kill,
391
- // 让命令自己跑完或被 timeout 收走;超出上限的部分直接丢弃,最终仍按上限截断展示。
392
- if (stdout.length < MAX_STREAM_BUFFER_CHARS)
393
- stdout += chunk;
469
+ if (!outputStore.append('stdout', chunk)) {
470
+ child.stdout?.pause();
471
+ outputStore.onDrain(() => child.stdout?.resume());
472
+ }
394
473
  });
395
474
  child.stderr?.on('data', (chunk) => {
396
- if (stderr.length < MAX_STREAM_BUFFER_CHARS)
397
- stderr += chunk;
475
+ if (!outputStore.append('stderr', chunk)) {
476
+ child.stderr?.pause();
477
+ outputStore.onDrain(() => child.stderr?.resume());
478
+ }
398
479
  });
399
480
  child.on('error', (e) => {
400
481
  ac.signal.removeEventListener('abort', onKill);
@@ -413,18 +494,36 @@ async function call(input, signal) {
413
494
  return {
414
495
  ok: false,
415
496
  error: `执行命令失败:${e.message}\n命令:${command}`,
497
+ metadata: processExecutionMetadata({ shell: 'bash', mode: 'foreground', command, status: 'failed', exitCode: null }),
416
498
  };
417
499
  }
418
500
  finally {
419
501
  clearTimeout(timer);
420
502
  signal?.removeEventListener('abort', onAbort);
421
503
  }
504
+ const storedOutput = await outputStore.finish();
505
+ stdout = storedOutput.stdout;
506
+ stderr = storedOutput.stderr;
507
+ // 4b-2. ATTACH_IMAGE sentinel:脚本可以打一行 `<<<ATTACH_IMAGE:path>>>` 让模型亲眼看图。
508
+ // 协议行**从 content 剥掉**(那是给宿主看的,不是给模型读的噪声);被拒的条目
509
+ // 如实写进输出(静默丢弃会让脚本作者以为图发出去了,无从 debug)。
510
+ // `ToolResult` 的成功与失败分支都能带 visionImages,所以脚本**不必**为了
511
+ // 附图而假装成功——非零退出码照样能把图带给模型。
512
+ const attach = extractAttachImageDirectives(stdout);
513
+ stdout = attach.text;
514
+ const { images: visionImages, rejections: attachRejections } = await resolveAttachImages(attach.directives);
422
515
  // 4c. 拼输出
423
516
  const parts = [];
424
517
  if (stdout)
425
518
  parts.push(`<stdout>\n${stdout.replace(/\s+$/, '')}\n</stdout>`);
426
519
  if (stderr)
427
520
  parts.push(`<stderr>\n${stderr.replace(/\s+$/, '')}\n</stderr>`);
521
+ if (visionImages.length > 0) {
522
+ parts.push(`[已附加 ${visionImages.length} 张图片供你查看]`);
523
+ }
524
+ if (attachRejections.length > 0) {
525
+ parts.push(`[附图被拒绝]\n${attachRejections.map((r) => `- ${r}`).join('\n')}`);
526
+ }
428
527
  if (parts.length === 0)
429
528
  parts.push('<no output>');
430
529
  if (timedOut) {
@@ -434,16 +533,27 @@ async function call(input, signal) {
434
533
  parts.push(`\n[被信号中断]`);
435
534
  }
436
535
  parts.push(`\n[exit code: ${exitCode === null ? 'killed' : exitCode}]`);
536
+ const outputReference = storedOutput.path
537
+ ? `\n[完整输出: ${storedOutput.path}; bytes=${storedOutput.bytes}; sha256=${storedOutput.sha256}; complete=${storedOutput.complete}]`
538
+ : '';
437
539
  let combinedOutput = parts.join('\n');
438
540
  // 4d. 大小兜底
439
- if (combinedOutput.length > DEFAULT_MAX_RESULT_SIZE_CHARS) {
541
+ if (combinedOutput.length + outputReference.length > DEFAULT_MAX_RESULT_SIZE_CHARS) {
542
+ const suffix = `\n\n... (输出超过 ${DEFAULT_MAX_RESULT_SIZE_CHARS} 字符,预览已截断)${outputReference}`;
440
543
  combinedOutput =
441
- combinedOutput.slice(0, DEFAULT_MAX_RESULT_SIZE_CHARS) +
442
- `\n\n... (输出超过 ${DEFAULT_MAX_RESULT_SIZE_CHARS} 字符,已截断)`;
544
+ combinedOutput.slice(0, Math.max(0, DEFAULT_MAX_RESULT_SIZE_CHARS - suffix.length)) + suffix;
443
545
  }
546
+ else
547
+ combinedOutput += outputReference;
444
548
  // 4e. 中断 / 超时仍然算硬失败
549
+ // 失败也带上已解析的附图:脚本挂掉前截的那张诊断图正是最该看的。
445
550
  if (timedOut || killedBySignal) {
446
- return { ok: false, error: combinedOutput };
551
+ return {
552
+ ok: false,
553
+ error: combinedOutput,
554
+ metadata: processExecutionMetadata({ shell: 'bash', mode: 'foreground', command, status: 'failed', exitCode }),
555
+ ...(visionImages.length > 0 ? { visionImages } : {}),
556
+ };
447
557
  }
448
558
  // 4f. 语义化退出码判定
449
559
  // 交给 semantics 模块:grep/rg/find/diff/test 有"信息性退出码",
@@ -458,9 +568,16 @@ async function call(input, signal) {
458
568
  ok: false,
459
569
  error: `命令失败 (exit ${exitCode}): ${stderr || stdout || semantic.message || ''}`.trim() +
460
570
  `\n\n${finalContent}`,
571
+ metadata: processExecutionMetadata({ shell: 'bash', mode: 'foreground', command, status: 'failed', exitCode }),
572
+ ...(visionImages.length > 0 ? { visionImages } : {}),
461
573
  };
462
574
  }
463
- return { ok: true, content: finalContent };
575
+ return {
576
+ ok: true,
577
+ content: finalContent,
578
+ metadata: processExecutionMetadata({ shell: 'bash', mode: 'foreground', command, status: 'completed', exitCode }),
579
+ ...(visionImages.length > 0 ? { visionImages } : {}),
580
+ };
464
581
  }
465
582
  // ---------------- 5. 导出 ----------------
466
583
  export const bashTool = {
@@ -472,5 +589,6 @@ export const bashTool = {
472
589
  isConcurrencySafe: false, // 默认按"会改状态"算;保守不并发
473
590
  maxResultSizeChars: DEFAULT_MAX_RESULT_SIZE_CHARS,
474
591
  interruptBehavior: () => 'block',
475
- call,
592
+ call: (input, signal) => call(input, signal),
593
+ callWithContext: (input, signal, context) => call(input, signal, context),
476
594
  };