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,420 @@
1
+ /**
2
+ * ============================================================
3
+ * src/utils/clipboardImage.ts —— 三 OS 剪贴板取图(Ctrl+V / Alt+V 的后端)
4
+ * ------------------------------------------------------------
5
+ * **为什么必须有这个模块**:终端不会把剪贴板里的图片字节送进 stdin——拖拽进来的是
6
+ * 「文件路径文本」(那条路已由 multimodal.ts 的行内路径识别覆盖),而 Ctrl+V 粘贴图片
7
+ * 在终端里根本不产生任何输入事件。想拿到图,只能**进程主动去问操作系统要**。
8
+ *
9
+ * 返回的是「磁盘上的一个图片路径」而不是 base64:这样下游完全复用既有的
10
+ * `@"path"` → buildUserContent 通路,不新增任何数据形状、不改 loop / useChat。
11
+ *
12
+ * **取图顺序:先要文件列表,再要位图字节**。资源管理器 / Finder 复制的是**文件**,
13
+ * 截图工具 / 浏览器复制的是**位图数据**;先问文件列表就能直接拿到原文件——不落临时
14
+ * 文件、不重编码、保留原格式。
15
+ *
16
+ * 三个平台各自的坑(都踩过实账,改之前先读):
17
+ * - Windows 必须用 `powershell.exe`(5.1)而**不是** `pwsh`:PowerShell 7 删掉了
18
+ * `Get-Clipboard -Format`,且默认不带 System.Drawing。5.1 在每台 Win10/11 上都有。
19
+ * - PowerShell 输出必须显式 `[Console]::OutputEncoding = UTF8`,否则中文文件名回来是乱码
20
+ * (与 bash.ts 头注记的 GBK 事故同源)。
21
+ * - Windows 剪贴板位图原生是 BMP,而本项目 `isSupportedImageSource('.bmp') === false`
22
+ * (OpenAI 兼容接口不吃 BMP)。让 PowerShell 直接 `.Save(..., ImageFormat::Png)`,
23
+ * 就不必像 Claude Code 那样为了转码去拉 sharp。
24
+ * - Linux 的 wl-clipboard / xclip 是**可选外部依赖**,缺失时报错必须点名要装什么。
25
+ *
26
+ * 依赖全部经参数注入(platform / env / run / tmpDir),命令拼装可纯函数断言,
27
+ * 测试不用真读剪贴板、也不用 mock.module。
28
+ * ============================================================
29
+ */
30
+
31
+ import { spawn } from 'node:child_process';
32
+ import { randomUUID } from 'node:crypto';
33
+ import { chmod, mkdir, readdir, stat, unlink, writeFile } from 'node:fs/promises';
34
+ import { tmpdir } from 'node:os';
35
+ import { basename, dirname, extname, join, resolve } from 'node:path';
36
+ import { fileURLToPath } from 'node:url';
37
+
38
+ const TEMP_PREFIX = 'minimal-agent-clip-';
39
+ const TEMP_MAX_AGE_MS = 24 * 60 * 60 * 1000;
40
+ const MAX_CLIPBOARD_IMAGE_BYTES = 10 * 1024 * 1024;
41
+ const MAX_CLIPBOARD_TEXT_BYTES = 1024 * 1024;
42
+ const COMMAND_TIMEOUT_MS = 8_000;
43
+ /** 与 multimodal.ts 的 IMAGE_MIME_BY_EXT 支持集一致(.bmp 有意不在内)。 */
44
+ const SUPPORTED_EXT = new Set(['.png', '.jpg', '.jpeg', '.gif', '.webp']);
45
+
46
+ export interface ClipboardCommand {
47
+ cmd: string;
48
+ args: string[];
49
+ /**
50
+ * true = 命令自己把图写到目标文件(Windows/macOS 用脚本落盘);
51
+ * false = 图片字节从 stdout 出来,由本模块负责写盘(Linux)。
52
+ */
53
+ writesOutputFile: boolean;
54
+ }
55
+
56
+ export type ClipboardImageResult =
57
+ | { ok: true; path: string; fromFile: boolean }
58
+ | { ok: false; reason: string };
59
+
60
+ export type RunCommand = (
61
+ cmd: string,
62
+ args: string[],
63
+ options: {
64
+ env?: NodeJS.ProcessEnv;
65
+ input?: Buffer | string;
66
+ maxBytes?: number;
67
+ timeoutMs?: number;
68
+ },
69
+ ) => Promise<{ stdout: Buffer }>;
70
+
71
+ export interface ClipboardDeps {
72
+ platform?: NodeJS.Platform;
73
+ env?: NodeJS.ProcessEnv;
74
+ run?: RunCommand;
75
+ tmpDir?: string;
76
+ }
77
+
78
+ export function isManagedClipboardTemp(path: string): boolean {
79
+ return dirname(resolve(path)) === resolve(join(tmpdir(), 'minimal-agent-clipboard'))
80
+ && basename(path).startsWith(TEMP_PREFIX);
81
+ }
82
+
83
+ export async function removeManagedClipboardTemp(path: string): Promise<void> {
84
+ if (isManagedClipboardTemp(path)) await unlink(path).catch(() => undefined);
85
+ }
86
+
87
+ /**
88
+ * Spawn-based runner with an explicit byte cap. `execFile` buffers stdout with
89
+ * a small default maxBuffer, which makes ordinary Linux screenshots fail.
90
+ *
91
+ * 两处刻意的选择(都踩过账):
92
+ * - **stderr 用 `'ignore'` 而不是 `'pipe'`**:我们从不读它,而没人读的管道写满
93
+ * (约 64KB)会把子进程**堵死**,最后只能等超时——`xclip` 在没有 X 显示时正好会
94
+ * 往 stderr 狂写。丢弃它才是对的,报错信息由 exit code 表达。
95
+ * - 子进程退出不代表 stdout 已完整结束:继承管道的孙进程仍可能写数据。成功必须同时
96
+ * 等到 exit code 0 与 stdout end;若退出后管道迟迟不关,明确失败,绝不返回截断图片。
97
+ */
98
+ const EXIT_STDOUT_TIMEOUT_MS = 750;
99
+
100
+ export const spawnClipboardCommand: RunCommand = (cmd, args, options) => new Promise((resolveRun, rejectRun) => {
101
+ const child = spawn(cmd, args, {
102
+ env: options.env,
103
+ stdio: ['pipe', 'pipe', 'ignore'],
104
+ windowsHide: true,
105
+ });
106
+ const chunks: Buffer[] = [];
107
+ let total = 0;
108
+ let settled = false;
109
+ let exited: number | null = null;
110
+ let stdoutEnded = false;
111
+ const maxBytes = options.maxBytes ?? MAX_CLIPBOARD_IMAGE_BYTES;
112
+ const finish = (error?: Error) => {
113
+ if (settled) return;
114
+ settled = true;
115
+ clearTimeout(timer);
116
+ clearTimeout(drainTimer);
117
+ if (error) rejectRun(error);
118
+ else resolveRun({ stdout: Buffer.concat(chunks, total) });
119
+ };
120
+ let drainTimer: ReturnType<typeof setTimeout> | undefined;
121
+ const timer = setTimeout(() => {
122
+ child.kill();
123
+ finish(new Error('clipboard command timed out'));
124
+ }, options.timeoutMs ?? COMMAND_TIMEOUT_MS);
125
+ child.once('error', (error) => finish(error));
126
+ child.stdout.on('data', (chunk: Buffer) => {
127
+ total += chunk.length;
128
+ if (total > maxBytes) {
129
+ child.kill();
130
+ finish(new Error(`clipboard payload exceeds ${maxBytes} bytes`));
131
+ return;
132
+ }
133
+ chunks.push(chunk);
134
+ });
135
+ // stdout 自然结束时立即结算:正常情况下这比宽限窗口先到,不必白等 50ms。
136
+ child.stdout.once('error', (error) => finish(error));
137
+ child.stdout.once('end', () => {
138
+ stdoutEnded = true;
139
+ if (exited === 0) finish();
140
+ });
141
+ child.once('exit', (code) => {
142
+ exited = code;
143
+ if (code !== 0) {
144
+ finish(Object.assign(new Error(`clipboard command exited with ${code}`), { code }));
145
+ return;
146
+ }
147
+ if (stdoutEnded || child.stdout.readableEnded) finish();
148
+ else {
149
+ drainTimer = setTimeout(
150
+ () => finish(new Error('clipboard command stdout did not close after process exit')),
151
+ EXIT_STDOUT_TIMEOUT_MS,
152
+ );
153
+ }
154
+ });
155
+ if (options.input !== undefined) child.stdin.end(options.input);
156
+ else child.stdin.end();
157
+ });
158
+
159
+ /** PowerShell 单引号字符串转义(内部单引号翻倍)。 */
160
+ function psQuote(value: string): string {
161
+ return `'${value.replace(/'/g, "''")}'`;
162
+ }
163
+
164
+ /** 所有 PowerShell 脚本的第一句:强制 UTF-8 输出,否则中文路径回来是乱码。 */
165
+ const PS_UTF8 = '[Console]::OutputEncoding = [System.Text.Encoding]::UTF8';
166
+ const PS_ARGS = ['-NoProfile', '-NonInteractive', '-Command'];
167
+
168
+ /**
169
+ * 「剪贴板里是不是复制了图片**文件**」——命中就能拿到原文件路径,最理想的情况。
170
+ * 导出供测试断言命令拼装。
171
+ */
172
+ export function clipboardFileListCommands(
173
+ platform: NodeJS.Platform,
174
+ env: NodeJS.ProcessEnv,
175
+ ): ClipboardCommand[] {
176
+ if (platform === 'win32') {
177
+ const script = [
178
+ PS_UTF8,
179
+ '$files = Get-Clipboard -Format FileDropList',
180
+ 'if (-not $files) { exit 1 }',
181
+ '$files | ForEach-Object { $_.FullName }',
182
+ ].join('; ');
183
+ return [{ cmd: 'powershell.exe', args: [...PS_ARGS, script], writesOutputFile: false }];
184
+ }
185
+ if (platform === 'darwin') {
186
+ return [
187
+ {
188
+ cmd: 'osascript',
189
+ args: ['-e', 'get POSIX path of (the clipboard as «class furl»)'],
190
+ writesOutputFile: false,
191
+ },
192
+ ];
193
+ }
194
+ return linuxOrder(env, [
195
+ { cmd: 'wl-paste', args: ['--type', 'text/uri-list'], writesOutputFile: false },
196
+ { cmd: 'xclip', args: ['-selection', 'clipboard', '-t', 'text/uri-list', '-o'], writesOutputFile: false },
197
+ ]);
198
+ }
199
+
200
+ /**
201
+ * 「剪贴板里是不是位图数据」——截图工具 / 浏览器复制走这条。
202
+ * 导出供测试断言命令拼装。
203
+ */
204
+ export function clipboardImageCommands(
205
+ platform: NodeJS.Platform,
206
+ env: NodeJS.ProcessEnv,
207
+ outPath: string,
208
+ ): ClipboardCommand[] {
209
+ if (platform === 'win32') {
210
+ const script = [
211
+ PS_UTF8,
212
+ 'Add-Type -AssemblyName System.Drawing',
213
+ '$img = Get-Clipboard -Format Image',
214
+ 'if (-not $img) { exit 1 }',
215
+ // 存 PNG 而不是倒原始字节:剪贴板位图原生是 BMP,本项目不支持 BMP。
216
+ `$img.Save(${psQuote(outPath)}, [System.Drawing.Imaging.ImageFormat]::Png)`,
217
+ ].join('; ');
218
+ return [{ cmd: 'powershell.exe', args: [...PS_ARGS, script], writesOutputFile: true }];
219
+ }
220
+ if (platform === 'darwin') {
221
+ return [
222
+ {
223
+ cmd: 'osascript',
224
+ args: [
225
+ '-e',
226
+ 'set png_data to (the clipboard as «class PNGf»)',
227
+ '-e',
228
+ `set fp to open for access POSIX file "${outPath}" with write permission`,
229
+ '-e',
230
+ 'write png_data to fp',
231
+ '-e',
232
+ 'close access fp',
233
+ ],
234
+ writesOutputFile: true,
235
+ },
236
+ ];
237
+ }
238
+ return linuxOrder(env, [
239
+ { cmd: 'wl-paste', args: ['--type', 'image/png'], writesOutputFile: false },
240
+ { cmd: 'xclip', args: ['-selection', 'clipboard', '-t', 'image/png', '-o'], writesOutputFile: false },
241
+ ]);
242
+ }
243
+
244
+ /** Wayland 会话优先试 wl-paste,否则 xclip 优先;两个都会试,缺哪个都只是 ENOENT。 */
245
+ function linuxOrder(env: NodeJS.ProcessEnv, [wayland, x11]: ClipboardCommand[]): ClipboardCommand[] {
246
+ return env.WAYLAND_DISPLAY ? [wayland!, x11!] : [x11!, wayland!];
247
+ }
248
+
249
+ type Attempt =
250
+ | { status: 'ok'; stdout: Buffer }
251
+ /** 可执行文件不存在(该后端没装) */
252
+ | { status: 'missing' }
253
+ /** 跑起来了但没拿到东西(剪贴板里没这类内容) */
254
+ | { status: 'empty' };
255
+
256
+ async function attempt(command: ClipboardCommand, run: RunCommand, env: NodeJS.ProcessEnv): Promise<Attempt> {
257
+ try {
258
+ const { stdout } = await run(command.cmd, command.args, {
259
+ env,
260
+ maxBytes: MAX_CLIPBOARD_IMAGE_BYTES,
261
+ timeoutMs: COMMAND_TIMEOUT_MS,
262
+ });
263
+ return { status: 'ok', stdout: Buffer.isBuffer(stdout) ? stdout : Buffer.from(String(stdout)) };
264
+ } catch (e) {
265
+ const code = (e as NodeJS.ErrnoException).code;
266
+ return code === 'ENOENT' ? { status: 'missing' } : { status: 'empty' };
267
+ }
268
+ }
269
+
270
+ /** 把剪贴板文件列表的一行(可能是 file:// URI)转成本地路径;不是受支持的图片则返回 null。 */
271
+ function toImagePath(line: string): string | null {
272
+ const clean = line.trim().replace(/^"|"$/g, '');
273
+ if (!clean || clean.startsWith('#')) return null;
274
+ let path = clean;
275
+ if (clean.startsWith('file://')) {
276
+ try {
277
+ path = fileURLToPath(clean);
278
+ } catch {
279
+ return null;
280
+ }
281
+ }
282
+ return SUPPORTED_EXT.has(extname(path).toLowerCase()) ? path : null;
283
+ }
284
+
285
+ /** 清掉 24h 前的同前缀临时图。不能即时删——文件要活到用户提交那一刻。 */
286
+ async function pruneOldTempImages(dir: string): Promise<void> {
287
+ try {
288
+ const names = await readdir(dir);
289
+ const deadline = Date.now() - TEMP_MAX_AGE_MS;
290
+ await Promise.all(
291
+ names
292
+ .filter((name) => name.startsWith(TEMP_PREFIX))
293
+ .map(async (name) => {
294
+ const full = join(dir, name);
295
+ const info = await stat(full).catch(() => null);
296
+ if (info && info.mtimeMs < deadline) await unlink(full).catch(() => undefined);
297
+ }),
298
+ );
299
+ } catch {
300
+ // 清理是尽力而为,失败不影响取图。
301
+ }
302
+ }
303
+
304
+ export async function readClipboardImage(deps: ClipboardDeps = {}): Promise<ClipboardImageResult> {
305
+ const platform = deps.platform ?? process.platform;
306
+ const env = deps.env ?? process.env;
307
+ const run = deps.run ?? spawnClipboardCommand;
308
+ const dir = deps.tmpDir ?? join(tmpdir(), 'minimal-agent-clipboard');
309
+ await mkdir(dir, { recursive: true, mode: 0o700 });
310
+ await chmod(dir, 0o700).catch(() => undefined);
311
+
312
+ void pruneOldTempImages(dir);
313
+
314
+ let anyBackendMissing = false;
315
+ let anyBackendRan = false;
316
+
317
+ // ① 先问文件列表:命中就直接用原文件,不落临时拷贝、不重编码。
318
+ for (const command of clipboardFileListCommands(platform, env)) {
319
+ const result = await attempt(command, run, env);
320
+ if (result.status === 'missing') {
321
+ anyBackendMissing = true;
322
+ continue;
323
+ }
324
+ anyBackendRan = true;
325
+ if (result.status !== 'ok') continue;
326
+ for (const line of result.stdout.toString('utf8').split(/\r?\n/)) {
327
+ const path = toImagePath(line);
328
+ // 剪贴板里可能是任意文件(.txt/.zip),只认得出图片才算命中。
329
+ if (path && (await stat(path).then((s) => s.isFile()).catch(() => false))) {
330
+ return { ok: true, path, fromFile: true };
331
+ }
332
+ }
333
+ }
334
+
335
+ // ② 再问位图字节:截图工具 / 浏览器复制走这条,落一个临时 PNG。
336
+ const outPath = join(dir, `${TEMP_PREFIX}${Date.now()}-${randomUUID()}.png`);
337
+ for (const command of clipboardImageCommands(platform, env, outPath)) {
338
+ const result = await attempt(command, run, env);
339
+ if (result.status === 'missing') {
340
+ anyBackendMissing = true;
341
+ continue;
342
+ }
343
+ anyBackendRan = true;
344
+ if (result.status !== 'ok') continue;
345
+
346
+ if (command.writesOutputFile) {
347
+ const size = await stat(outPath).then((s) => s.size).catch(() => 0);
348
+ if (size > MAX_CLIPBOARD_IMAGE_BYTES) {
349
+ await unlink(outPath).catch(() => undefined);
350
+ return { ok: false, reason: '剪贴板图片超过 10MB 上限。' };
351
+ }
352
+ if (size > 0) {
353
+ await chmod(outPath, 0o600).catch(() => undefined);
354
+ return { ok: true, path: outPath, fromFile: false };
355
+ }
356
+ continue;
357
+ }
358
+ // stdout 就是图片字节(Linux)。空输出 = 剪贴板里没有这个类型。
359
+ if (result.stdout.length === 0) continue;
360
+ if (result.stdout.length > MAX_CLIPBOARD_IMAGE_BYTES) {
361
+ return { ok: false, reason: '剪贴板图片超过 10MB 上限。' };
362
+ }
363
+ await writeFile(outPath, result.stdout, { mode: 0o600 });
364
+ return { ok: true, path: outPath, fromFile: false };
365
+ }
366
+
367
+ if (anyBackendMissing && !anyBackendRan) {
368
+ return {
369
+ ok: false,
370
+ reason:
371
+ platform === 'linux'
372
+ ? '读不到剪贴板:请先安装 wl-clipboard(Wayland)或 xclip(X11)。'
373
+ : '读不到剪贴板:系统剪贴板工具不可用。',
374
+ };
375
+ }
376
+ return { ok: false, reason: '剪贴板里没有图片。' };
377
+ }
378
+
379
+ /** Copy exact text without terminal decoration or ANSI escape sequences. */
380
+ export async function writeClipboardText(
381
+ text: string,
382
+ deps: Pick<ClipboardDeps, 'platform' | 'env' | 'run'> = {},
383
+ ): Promise<void> {
384
+ const bytes = Buffer.from(text, 'utf8');
385
+ if (bytes.length > MAX_CLIPBOARD_TEXT_BYTES) {
386
+ throw new Error('要复制的内容超过 1MB 上限。');
387
+ }
388
+ const platform = deps.platform ?? process.platform;
389
+ const env = deps.env ?? process.env;
390
+ const run = deps.run ?? spawnClipboardCommand;
391
+ const commands = platform === 'darwin'
392
+ ? [{ cmd: 'pbcopy', args: [] }]
393
+ : platform === 'win32'
394
+ ? [{
395
+ cmd: 'powershell.exe',
396
+ args: [...PS_ARGS, `${PS_UTF8}; $input | Set-Clipboard`],
397
+ }]
398
+ : env.WAYLAND_DISPLAY
399
+ ? [{ cmd: 'wl-copy', args: [] }, { cmd: 'xclip', args: ['-selection', 'clipboard'] }]
400
+ : [{ cmd: 'xclip', args: ['-selection', 'clipboard'] }, { cmd: 'wl-copy', args: [] }];
401
+ let lastError: unknown;
402
+ for (const command of commands) {
403
+ try {
404
+ await run(command.cmd, command.args, {
405
+ env,
406
+ input: bytes,
407
+ maxBytes: 64 * 1024,
408
+ timeoutMs: COMMAND_TIMEOUT_MS,
409
+ });
410
+ return;
411
+ } catch (error) {
412
+ lastError = error;
413
+ }
414
+ }
415
+ throw new Error(
416
+ platform === 'linux'
417
+ ? '写入剪贴板失败:请安装 wl-clipboard(Wayland)或 xclip(X11)。'
418
+ : `写入剪贴板失败:${lastError instanceof Error ? lastError.message : String(lastError)}`,
419
+ );
420
+ }
@@ -0,0 +1,50 @@
1
+ /**
2
+ * ============================================================
3
+ * src/utils/debugLog.ts —— 文件调试日志(环境变量开关,默认全程 no-op)
4
+ * ------------------------------------------------------------
5
+ * 为什么需要:TUI(Ink)独占 stdout/stderr,console.log 在 TUI 里看不见、还会搅乱画面;
6
+ * 而"卡死/不响应"这类问题恰恰无法靠正常退出来事后检查。把关键生命周期点**同步追加**到
7
+ * 一个磁盘文件,进程即便随后挂死,日志也已落盘——文件的最后一行就指向卡住的位置。
8
+ *
9
+ * 用法:
10
+ * MINIMAL_AGENT_DEBUG_LOG=D:\tmp\ma-debug.log bun run start
11
+ * 然后复现问题,把该文件最后几十行发来即可定位。
12
+ *
13
+ * 设计:
14
+ * - 未设环境变量 → dlog() 直接 return,零开销、零行为改变(不影响 npm/dev/绿色版任何路径)。
15
+ * - 用 appendFileSync(同步):宁可慢一点也要保证"挂死前那一行确实写进了磁盘"。
16
+ * - 任何写日志的异常都吞掉,绝不让"记日志"反过来影响主流程。
17
+ * ============================================================
18
+ */
19
+
20
+ import { appendFileSync } from 'node:fs';
21
+
22
+ const LOG_PATH = process.env.MINIMAL_AGENT_DEBUG_LOG;
23
+
24
+ /**
25
+ * 追加一行调试日志:`<ISO 时间> [tag] msg {data}`。
26
+ * 未开启(无 MINIMAL_AGENT_DEBUG_LOG)时立即返回。
27
+ */
28
+ export function dlog(tag: string, msg: string, data?: unknown): void {
29
+ if (!LOG_PATH) return;
30
+ try {
31
+ const ts = new Date().toISOString();
32
+ const line =
33
+ data !== undefined
34
+ ? `${ts} [${tag}] ${msg} ${safeJson(data)}\n`
35
+ : `${ts} [${tag}] ${msg}\n`;
36
+ appendFileSync(LOG_PATH, line);
37
+ } catch {
38
+ // 记日志失败绝不影响主流程
39
+ }
40
+ }
41
+
42
+ /** 安全 JSON:循环引用 / 超长都不抛、不撑爆日志。 */
43
+ function safeJson(v: unknown): string {
44
+ try {
45
+ const s = JSON.stringify(v);
46
+ return s.length > 600 ? `${s.slice(0, 600)}…` : s;
47
+ } catch {
48
+ return String(v);
49
+ }
50
+ }
@@ -0,0 +1,35 @@
1
+ /**
2
+ * ============================================================
3
+ * src/utils/greenRoot.ts —— 绿色版(bun --compile 单文件)资源探测锚点
4
+ * ------------------------------------------------------------
5
+ * 问题:`bun build --compile` 把运行时 + 全部 JS 焊进单个可执行文件,
6
+ * 此时 `import.meta.url` 指向嵌入式虚拟路径(`/$bunfs/...`),磁盘上
7
+ * 既没有 package.json 也没有源码树 —— `findPackageRoot` 会抛错,靠它
8
+ * 定位的 `vendor/ripgrep/`、`skills/`、`plugins/`、`workflows/` 全失效。
9
+ *
10
+ * 方案:绿色版把这些外部资产与可执行文件**放在同一目录**,运行时用
11
+ * `dirname(process.execPath)` 找回来(exe 同级)。
12
+ *
13
+ * 为什么 dev / npm 模式零影响:
14
+ * - dev(`bun run src/main.tsx`):execPath = bun 二进制,其同级目录
15
+ * (如 `~/.bun/bin/`)没有 vendor/skills/plugins。
16
+ * - npm 全局安装(`node dist/main.js`):execPath = node 二进制,其
17
+ * 同级目录同样没有这些资源目录。
18
+ * - 故调用方一律对返回值做 `existsSync` 过滤:dev/npm 下命不中 → 被
19
+ * 丢弃 → 行为与现状逐字节一致。只有真·绿色版(资产摆在 exe 旁边)
20
+ * 才会命中。因此这里**无条件返回** execPath 目录即可,无需判别
21
+ * "是否 compiled"。
22
+ * ============================================================
23
+ */
24
+
25
+ import { dirname } from 'node:path';
26
+
27
+ /**
28
+ * 返回可执行文件所在目录(绿色版资产的同级锚点)。
29
+ *
30
+ * 调用方必须用 existsSync 过滤返回路径下的目标子目录 —— dev/npm 模式
31
+ * execPath 指向 node/bun 二进制,其同级没有资源目录,过滤后无副作用。
32
+ */
33
+ export function execSiblingDir(): string {
34
+ return dirname(process.execPath);
35
+ }
@@ -0,0 +1,40 @@
1
+ /**
2
+ * ============================================================
3
+ * src/utils/packageRoot.ts —— 定位 minimal-agent 包根目录
4
+ * ------------------------------------------------------------
5
+ * 问题:bundle 后 import.meta.url 指向 dist/main.js,
6
+ * 源码模式则指向 src/<deep>/*.ts,两者深度不同。
7
+ * 固定 `join(__dirname, '..', '..')` 在某一种模式下必然错。
8
+ *
9
+ * 方案:从调用方文件起向上找最近的 package.json,把那一层
10
+ * 当作包根。源码模式(src/prompts、src/tools/grep)、bundle
11
+ * 模式(dist/main.js)、全局安装(node_modules/minimal-agent/dist)
12
+ * 全都自动适配。
13
+ * ============================================================
14
+ */
15
+
16
+ import { existsSync } from 'node:fs';
17
+ import { dirname, resolve } from 'node:path';
18
+ import { fileURLToPath } from 'node:url';
19
+
20
+ const cache = new Map<string, string>();
21
+
22
+ /** 向上最多翻 8 级;超过仍找不到视为环境异常。 */
23
+ const MAX_DEPTH = 8;
24
+
25
+ export function findPackageRoot(metaUrl: string): string {
26
+ const cached = cache.get(metaUrl);
27
+ if (cached !== undefined) return cached;
28
+
29
+ let dir = dirname(fileURLToPath(metaUrl));
30
+ for (let i = 0; i < MAX_DEPTH; i++) {
31
+ if (existsSync(resolve(dir, 'package.json'))) {
32
+ cache.set(metaUrl, dir);
33
+ return dir;
34
+ }
35
+ const parent = dirname(dir);
36
+ if (parent === dir) break;
37
+ dir = parent;
38
+ }
39
+ throw new Error(`packageRoot: 找不到 package.json(起点 ${metaUrl})`);
40
+ }
@@ -0,0 +1,28 @@
1
+ /**
2
+ * ============================================================
3
+ * src/utils/pathContains.ts —— 「这个路径在不在那个目录里」的唯一实现
4
+ * ------------------------------------------------------------
5
+ * 这是一条**安全判据**:上传范围、产物落盘范围、截图附件范围、插件资源范围都靠它
6
+ * 决定放行还是拒绝。它此前在全仓被手写了四遍(webbrowser / browser / attachImage /
7
+ * computeruse),四份各自独立演化——判据写四遍的问题不是重复,是**其中一份写错了
8
+ * 没人会发现**,而它错的方向是放行。
9
+ *
10
+ * 实现刻意用 `path.relative` 而不是字符串前缀比较:`/tmp/data` 与 `/tmp/data-evil`
11
+ * 的前缀关系成立,但包含关系不成立,`startsWith` 写法会放行后者。
12
+ * ============================================================
13
+ */
14
+ import { isAbsolute, relative } from 'node:path';
15
+ /**
16
+ * `child` 是否落在 `root` 之内(含 `root` 自身)。
17
+ *
18
+ * 两边都应当是**已解析过的绝对路径**(调用方负责 realpath / resolve):这个函数不碰
19
+ * 文件系统,符号链接的解析必须发生在调用方,否则一条软链就能绕过判据。
20
+ */
21
+ export function pathContains(root, child) {
22
+ const rel = relative(root, child);
23
+ return rel === '' || (!rel.startsWith('..') && !isAbsolute(rel));
24
+ }
25
+ /** `child` 是否落在任意一个 root 之内。空 roots 一律不放行。 */
26
+ export function pathContainedByAny(roots, child) {
27
+ return roots.some((root) => pathContains(root, child));
28
+ }
@@ -0,0 +1,31 @@
1
+ /**
2
+ * ============================================================
3
+ * src/utils/pathContains.ts —— 「这个路径在不在那个目录里」的唯一实现
4
+ * ------------------------------------------------------------
5
+ * 这是一条**安全判据**:上传范围、产物落盘范围、截图附件范围、插件资源范围都靠它
6
+ * 决定放行还是拒绝。它此前在全仓被手写了四遍(webbrowser / browser / attachImage /
7
+ * computeruse),四份各自独立演化——判据写四遍的问题不是重复,是**其中一份写错了
8
+ * 没人会发现**,而它错的方向是放行。
9
+ *
10
+ * 实现刻意用 `path.relative` 而不是字符串前缀比较:`/tmp/data` 与 `/tmp/data-evil`
11
+ * 的前缀关系成立,但包含关系不成立,`startsWith` 写法会放行后者。
12
+ * ============================================================
13
+ */
14
+
15
+ import { isAbsolute, relative } from 'node:path';
16
+
17
+ /**
18
+ * `child` 是否落在 `root` 之内(含 `root` 自身)。
19
+ *
20
+ * 两边都应当是**已解析过的绝对路径**(调用方负责 realpath / resolve):这个函数不碰
21
+ * 文件系统,符号链接的解析必须发生在调用方,否则一条软链就能绕过判据。
22
+ */
23
+ export function pathContains(root: string, child: string): boolean {
24
+ const rel = relative(root, child);
25
+ return rel === '' || (!rel.startsWith('..') && !isAbsolute(rel));
26
+ }
27
+
28
+ /** `child` 是否落在任意一个 root 之内。空 roots 一律不放行。 */
29
+ export function pathContainedByAny(roots: readonly string[], child: string): boolean {
30
+ return roots.some((root) => pathContains(root, child));
31
+ }
@@ -0,0 +1,71 @@
1
+ /**
2
+ * ============================================================
3
+ * src/utils/resourcePaths.ts —— 资源目录双源解析
4
+ * ------------------------------------------------------------
5
+ * 问题:skills/ 和 plugins/ 这类"资源目录"需要在两种场景下都能找到:
6
+ * - 用户在 minimal-agent 源码仓库里跑(dev):cwd === packageRoot
7
+ * - 用户全局 npm install 后在自己项目里跑:cwd ≠ packageRoot
8
+ * 此时既要看 npm 包自带的资源,也要看用户在自己项目里新加的资源。
9
+ *
10
+ * 方案:返回 [cwd/<name>, packageRoot/<name>],cwd 优先。
11
+ * - 用 existsSync 过滤不存在的目录(保留静默降级)
12
+ * - cwd 与 packageRoot 重合时去重(dev 场景)
13
+ *
14
+ * 消费者(commandRouter / skillList / 各插件 loader)按顺序扫描,先扫到的
15
+ * 同名条目胜出 —— 让用户能在自己项目里覆盖或扩展全局自带资源。
16
+ *
17
+ * ResourceName 故意是开放 string:插件可以自由声明自己的资源名(如
18
+ * workflow-runner 的 'workflows'),框架不预设资源名清单。
19
+ * ============================================================
20
+ */
21
+
22
+ import { existsSync } from 'node:fs';
23
+ import { join, resolve } from 'node:path';
24
+
25
+ import { getWorkingDir } from '../bootstrap/workingDir.js';
26
+ import { execSiblingDir } from './greenRoot.js';
27
+ import { findPackageRoot } from './packageRoot.js';
28
+
29
+ /** 资源目录名(也作为子目录名)。开放字符串,框架不锁定取值。 */
30
+ export type ResourceName = string;
31
+
32
+ /**
33
+ * 返回资源目录的搜索顺序数组(cwd 优先 + packageRoot fallback)。
34
+ *
35
+ * @param name 资源类别名(也作为子目录名)
36
+ * @param metaUrl 调用方 import.meta.url(用于定位 packageRoot)
37
+ * @returns 存在的搜索路径数组;都不存在则返回空数组
38
+ */
39
+ export function getResourceSearchPaths(
40
+ name: ResourceName,
41
+ metaUrl: string,
42
+ workingDir = getWorkingDir(),
43
+ ): string[] {
44
+ const paths: string[] = [];
45
+
46
+ const cwdPath = resolve(join(workingDir, name));
47
+ if (existsSync(cwdPath)) {
48
+ paths.push(cwdPath);
49
+ }
50
+
51
+ // 绿色版(bun --compile 单文件):exe 同级 <name>/ —— compile 后 findPackageRoot
52
+ // 失效,资源目录摆在可执行文件旁边从这里命中。dev/npm 下 exe 同级(node/bun
53
+ // 二进制所在目录)没有资源目录 → existsSync 过滤 → 数组与现状一致。
54
+ const sibPath = resolve(join(execSiblingDir(), name));
55
+ if (!paths.includes(sibPath) && existsSync(sibPath)) {
56
+ paths.push(sibPath);
57
+ }
58
+
59
+ let pkgPath: string;
60
+ try {
61
+ pkgPath = resolve(join(findPackageRoot(metaUrl), name));
62
+ } catch {
63
+ return paths;
64
+ }
65
+
66
+ if (!paths.includes(pkgPath) && existsSync(pkgPath)) {
67
+ paths.push(pkgPath);
68
+ }
69
+
70
+ return paths;
71
+ }