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,96 @@
1
+ import { Box, Text, useInput } from 'ink';
2
+ import React, { useEffect, useState } from 'react';
3
+
4
+ import type { ModelConfig } from '../config/configFile.js';
5
+ import { configService } from '../config/configService.js';
6
+ import type { Provider } from '../types.js';
7
+ import { ProviderWizard } from './wizards/providerWizard.js';
8
+
9
+ interface Props {
10
+ onDone: (provider: Provider) => void;
11
+ }
12
+
13
+ export function QuickModelSetup({ onDone }: Props): JSX.Element {
14
+ const [models, setModels] = useState<ModelConfig[] | null>(null);
15
+ const [index, setIndex] = useState(0);
16
+ const [adding, setAdding] = useState(false);
17
+ const [readOnly, setReadOnly] = useState(false);
18
+ const [message, setMessage] = useState<string | null>(null);
19
+ useEffect(() => {
20
+ void configService.reload().then((snapshot) => {
21
+ setReadOnly(snapshot.readOnly);
22
+ setModels(snapshot.config?.models ?? []);
23
+ });
24
+ }, []);
25
+ useInput((input, key) => {
26
+ if (adding || !models) return;
27
+ const usable = models.filter((model) => model.enabled && model.apiKey);
28
+ const length = usable.length + 1;
29
+ if (key.upArrow) setIndex((value) => (value - 1 + length) % length);
30
+ else if (key.downArrow) setIndex((value) => (value + 1) % length);
31
+ else if (key.return) {
32
+ if (index === usable.length) setAdding(true);
33
+ else {
34
+ const selected = usable[index];
35
+ if (!selected) return;
36
+ void configService
37
+ .savePatch({ baseModelId: selected.id })
38
+ .then(() => configService.provider())
39
+ .then((provider) => {
40
+ if (provider) onDone(provider);
41
+ else setMessage('该模型当前不可用,请编辑或添加模型');
42
+ })
43
+ .catch((error: Error) => setMessage(error.message));
44
+ }
45
+ }
46
+ });
47
+ if (!models) return <Text color="gray">正在读取配置...</Text>;
48
+ if (readOnly)
49
+ return (
50
+ <Box flexDirection="column" paddingX={1}>
51
+ <Text color="yellow" bold>
52
+ 当前为环境变量只读配置,但没有可用基座模型
53
+ </Text>
54
+ <Text>
55
+ 请检查 MINIMAL_AGENT_BASE_URL、MINIMAL_AGENT_API_KEY 和
56
+ MINIMAL_AGENT_MODEL,然后重新启动。
57
+ </Text>
58
+ </Box>
59
+ );
60
+ if (adding)
61
+ return (
62
+ <ProviderWizard
63
+ quick
64
+ setAsBase
65
+ onDone={() => {
66
+ void configService.provider().then((provider) => {
67
+ if (provider) onDone(provider);
68
+ });
69
+ }}
70
+ onCancel={() => setAdding(false)}
71
+ />
72
+ );
73
+ const usable = models.filter((model) => model.enabled && model.apiKey);
74
+ return (
75
+ <Box flexDirection="column" paddingX={1}>
76
+ <Text color="cyan" bold>
77
+ 欢迎使用 minimal-agent
78
+ </Text>
79
+ <Text>请选择一个已有基座模型,或快速添加模型。</Text>
80
+ <Text color="gray">配置完成后可随时输入 /config 调整高级设置。</Text>
81
+ <Box flexDirection="column" marginTop={1}>
82
+ {usable.map((model, i) => (
83
+ <Text key={model.id} color={index === i ? 'cyan' : undefined}>
84
+ {index === i ? '> ' : ' '}
85
+ {model.displayName ?? model.model}{' '}
86
+ <Text color="gray">({model.model})</Text>
87
+ </Text>
88
+ ))}
89
+ <Text color={index === usable.length ? 'cyan' : undefined}>
90
+ {index === usable.length ? '> ' : ' '}+ 添加模型
91
+ </Text>
92
+ </Box>
93
+ {message && <Text color="red">{message}</Text>}
94
+ </Box>
95
+ );
96
+ }
@@ -23,11 +23,19 @@ import { getWorkingDir } from '../bootstrap/workingDir.js';
23
23
  import { forceCompact } from '../context/compact.js';
24
24
  import { recordRecentDir } from '../context/recentDirs.js';
25
25
  import { updateSessionMetadata } from '../context/sessionRegistry.js';
26
+ import { workspaceIndexService } from '../context/workspaceIndex.js';
26
27
  import { saveContext } from '../context/persistContext.js';
27
28
  import { setAskHandler } from '../askBridge.js';
28
29
  import { normalizeImageDetail } from '../multimodal.js';
29
30
  import { runWithPlugins } from '../plugins/pluginRunner.js';
31
+ import { buildBaseSystemPrompt, buildTransientPromptBundle } from '../prompts/system.js';
32
+ import { getOrCreateSessionState, sessionStateKey } from '../session/sessionState.js';
33
+ import { hydrateSessionWorktree } from '../tools/worktree/sessionWorktree.js';
34
+ import { ALL_TOOLS } from '../tools/index.js';
35
+ import { createPromptCacheContext } from '../llm/promptCache.js';
36
+ import { createAgentRuntimeContext, filterToolsForRuntime, memoryContextFromRuntime, } from '../runtime/agentRuntimeContext.js';
30
37
  import { extractImageOptions, extractPromptArgs } from './print.js';
38
+ import { createCliComputerRun } from './computerUse.js';
31
39
  /** 一行一个 JSON 事件写 stdout。EPIPE 时静默。 */
32
40
  function emitLine(ev) {
33
41
  try {
@@ -185,14 +193,24 @@ export async function runStreamJsonMode(provider, args, initialHistory, options)
185
193
  if (options.compact) {
186
194
  try {
187
195
  emitLine({ type: 'compact_start' });
188
- const r = await forceCompact(history, provider);
196
+ const r = await forceCompact(history, provider, undefined, undefined, createPromptCacheContext(`workspace:${options.workspace?.cwd ?? getWorkingDir()}:session:${options.workspace?.sessionId ?? 'default'}`));
189
197
  history.length = 0;
190
198
  history.push(...r.messages);
191
- emitLine({ type: 'compact_done', before: r.before, after: r.after });
199
+ emitLine({
200
+ type: 'compact_done',
201
+ before: r.before,
202
+ after: r.after,
203
+ trigger: 'manual',
204
+ mode: r.mode,
205
+ degraded: r.degraded,
206
+ ...(r.fallbackReason ? { fallbackReason: r.fallbackReason } : {}),
207
+ ...(r.messagesRemoved !== undefined ? { messagesRemoved: r.messagesRemoved } : {}),
208
+ ...(r.tokensFreed !== undefined ? { tokensFreed: r.tokensFreed } : {}),
209
+ });
192
210
  emitLine({ type: 'turn_done' });
193
211
  }
194
- catch (e) {
195
- emitLine({ type: 'error', error: `压缩失败:${e.message}`, code: 'compact_failed' });
212
+ catch {
213
+ emitLine({ type: 'error', error: '手动压缩失败。', code: 'compact_failed' });
196
214
  }
197
215
  await finalize();
198
216
  return;
@@ -251,6 +269,57 @@ export async function runStreamJsonMode(provider, args, initialHistory, options)
251
269
  void finalize().finally(() => process.exit(130));
252
270
  });
253
271
  try {
272
+ const workspaceRoot = options.workspace?.cwd ?? getWorkingDir();
273
+ const workspace = await workspaceIndexService.findByPath(workspaceRoot).catch(() => null);
274
+ const sessionId = options.workspace?.sessionId ?? 'default';
275
+ const sessionState = getOrCreateSessionState(sessionStateKey({
276
+ surface: 'headless', workspaceId: workspace?.id,
277
+ cwd: workspace?.id ? undefined : workspaceRoot, sessionId,
278
+ }));
279
+ await hydrateSessionWorktree({ sessionState, workspaceId: workspace?.id, sessionId, cwd: workspaceRoot });
280
+ const cwd = sessionState.activeWorktree?.path ?? workspaceRoot;
281
+ const conversationKey = `workspace:${workspace?.id ?? workspaceRoot}:session:${sessionId}`;
282
+ const computerRun = options.computerUseMode && options.computerUseMode !== 'disabled'
283
+ ? createCliComputerRun({
284
+ mode: options.computerUseMode,
285
+ surface: 'cli',
286
+ conversationKey,
287
+ userInput: prompt,
288
+ allowedFileRoots: [cwd],
289
+ supervised: true,
290
+ diagnosticTraceDir: options.computerUseTraceDir,
291
+ })
292
+ : undefined;
293
+ const runtimeContext = createAgentRuntimeContext({
294
+ surface: 'headless',
295
+ profile: 'main',
296
+ cwd,
297
+ workspaceId: workspace?.id,
298
+ sessionId,
299
+ owner: options.memoryAccess === 'denied' ? 'untrusted' : 'local-owner',
300
+ memoryAccess: options.memoryAccess ?? 'read-only',
301
+ interactiveAsk: control,
302
+ computer: computerRun,
303
+ });
304
+ const turnTools = filterToolsForRuntime(ALL_TOOLS, runtimeContext);
305
+ const stablePrompt = await buildBaseSystemPrompt(cwd, turnTools);
306
+ if (history[0]?.role === 'system')
307
+ history[0] = { ...history[0], content: stablePrompt };
308
+ else
309
+ history.unshift({ role: 'system', content: stablePrompt });
310
+ const transientBundle = await buildTransientPromptBundle({
311
+ cwd,
312
+ tools: turnTools,
313
+ runtime: {
314
+ surface: 'headless',
315
+ cwd,
316
+ workspaceId: workspace?.id,
317
+ sessionId,
318
+ interactiveAsk: control,
319
+ memoryAccess: runtimeContext.memoryAccess,
320
+ currentUserInput: prompt,
321
+ },
322
+ }).catch(() => undefined);
254
323
  for await (const event of runWithPlugins(prompt, {
255
324
  provider,
256
325
  history,
@@ -260,6 +329,13 @@ export async function runStreamJsonMode(provider, args, initialHistory, options)
260
329
  parseInlineImages: true,
261
330
  imageDetail: cliImageOptions.imageDetail,
262
331
  imageMaxLongSidePixel: cliImageOptions.imageMaxLongSidePixel,
332
+ runtimeContext,
333
+ sessionState,
334
+ allowedTools: turnTools.map((tool) => tool.name),
335
+ ...(transientBundle ? { transientBundle } : {}),
336
+ promptCache: createPromptCacheContext(`workspace:${workspace?.id ?? cwd}:session:${sessionId}`),
337
+ memoryContext: memoryContextFromRuntime(runtimeContext),
338
+ ...(computerRun ? { computerRun } : {}),
263
339
  })) {
264
340
  // event 是 LoopEvent | PluginEvent,原样逐行 emit;前端不识别的插件私有事件会静默忽略
265
341
  emitLine(event);
@@ -0,0 +1,433 @@
1
+ /**
2
+ * ============================================================
3
+ * src/cli/streamJson.ts —— `-p --output-format stream-json` 流式事件模式
4
+ * ------------------------------------------------------------
5
+ * 与 print.ts 的 text/json 一次性契约**并列、互不影响**(print.ts 一行未动):
6
+ * - text : 纯文本答案(向后兼容)
7
+ * - json : 退出时一行结局契约
8
+ * - stream-json(本文件): 把 runQuery 的**每个 LoopEvent 作为一行 JSON**
9
+ * 实时写 stdout(jsonl)。给 webchat 本地服务 broker 用 —— 它 spawn 本模式、
10
+ * 逐行转发成 WebSocket event 帧。也是给网关预留的"流式子进程"契约。
11
+ *
12
+ * 约定:
13
+ * - stdout 只允许 jsonl 事件流(一行一个 JSON.stringify(LoopEvent)),含「问答 over wire」
14
+ * 的出站事件 `{type:'ask',requestId,questions}`(AskUserQuestion 在远程通道弹问题)。
15
+ * - stdin 是**逐行 JSON 控制通道**(见 attachStdinChannel):首行 `{type:'prompt',text}` 为本轮输入,
16
+ * 后续 `{type:'ask_answer',requestId,answers}` 回灌用户选择。兼容:首行非控制消息 → 整段当裸 prompt。
17
+ * argv 也可给 prompt(此时 stdin 全部行按 ask_answer 解析)。--compact 走压缩动作(无需 prompt)。
18
+ * - 跑完 / 中断 / 出错都先 saveContext 再退出(finalize 还会 unref stdin,让本轮结束后进程能退出)。
19
+ * ============================================================
20
+ */
21
+
22
+ import crypto from 'node:crypto';
23
+ import { getWorkingDir } from '../bootstrap/workingDir.js';
24
+ import { forceCompact } from '../context/compact.js';
25
+ import { recordRecentDir } from '../context/recentDirs.js';
26
+ import { updateSessionMetadata } from '../context/sessionRegistry.js';
27
+ import { workspaceIndexService } from '../context/workspaceIndex.js';
28
+ import { saveContext } from '../context/persistContext.js';
29
+ import { setAskHandler, type AskAnswer } from '../askBridge.js';
30
+ // attachStdinChannel 的公开签名引用 AskAnswer → 从本模块一并 re-export,
31
+ // 供消费者(含 test/streamJson.askChannel.test.ts)从同一入口导入。
32
+ export type { AskAnswer } from '../askBridge.js';
33
+ import { normalizeImageDetail } from '../multimodal.js';
34
+ import type { ImageInputSpec, Message, Provider } from '../types.js';
35
+ import { runWithPlugins } from '../plugins/pluginRunner.js';
36
+ import { buildBaseSystemPrompt, buildTransientPromptBundle } from '../prompts/system.js';
37
+ import { getOrCreateSessionState, sessionStateKey } from '../session/sessionState.js';
38
+ import { hydrateSessionWorktree } from '../tools/worktree/sessionWorktree.js';
39
+ import { ALL_TOOLS } from '../tools/index.js';
40
+ import { createPromptCacheContext } from '../llm/promptCache.js';
41
+ import {
42
+ createAgentRuntimeContext,
43
+ filterToolsForRuntime,
44
+ memoryContextFromRuntime,
45
+ } from '../runtime/agentRuntimeContext.js';
46
+ import { extractImageOptions, extractPromptArgs } from './print.js';
47
+ import type { ComputerUseCliMode } from './computerUse.js';
48
+ import { createCliComputerRun } from './computerUse.js';
49
+
50
+ interface StreamJsonOptions {
51
+ maxTurns?: number;
52
+ /** true 时执行一次压缩(对应 Web 的 /compact),忽略 prompt。 */
53
+ compact?: boolean;
54
+ /**
55
+ * `--session <id>` 解析出的会话文件路径(main.tsx 算好传入)。缺省退回
56
+ * saveContext 的默认路径(= default session)。必须和 initialHistory 的
57
+ * 加载路径一致,否则出现"读 session A、存回 default"的读写分裂。
58
+ */
59
+ sessionFile?: string;
60
+ workspace?: { cwd: string; sessionId: string };
61
+ /** 本机长期记忆权限,由 main.tsx 判定后传入;stream-json 默认 denied(见 resolveMemoryAccess)。 */
62
+ memoryAccess?: import('../runtime/agentRuntimeContext.js').MemoryAccessInput;
63
+ /** 非交互 Computer Use 必须显式启用;缺省 disabled。 */
64
+ computerUseMode?: ComputerUseCliMode;
65
+ /** Explicit opt-in directory for chronological Computer Use diagnostics. */
66
+ computerUseTraceDir?: string;
67
+ }
68
+
69
+ /** 一行一个 JSON 事件写 stdout。EPIPE 时静默。 */
70
+ function emitLine(ev: unknown): void {
71
+ try {
72
+ process.stdout.write(`${JSON.stringify(ev)}\n`);
73
+ } catch {
74
+ /* ignore */
75
+ }
76
+ }
77
+
78
+ function firstUserTitle(history: Message[]): string | undefined {
79
+ const u = history.find((m) => m.role === 'user');
80
+ if (!u) return undefined;
81
+ if (typeof u.content === 'string') return u.content;
82
+ return u.content.find((p) => p.type === 'text')?.text;
83
+ }
84
+
85
+ type PromptImageWire =
86
+ | string
87
+ | {
88
+ source?: unknown;
89
+ url?: unknown;
90
+ detail?: unknown;
91
+ maxLongSidePixel?: unknown;
92
+ max_long_side_pixel?: unknown;
93
+ };
94
+
95
+ function parseWireImages(raw: unknown): ImageInputSpec[] {
96
+ if (!Array.isArray(raw)) return [];
97
+ const out: ImageInputSpec[] = [];
98
+ for (const item of raw as PromptImageWire[]) {
99
+ if (typeof item === 'string') {
100
+ out.push({ source: item });
101
+ continue;
102
+ }
103
+ if (!item || typeof item !== 'object') continue;
104
+ const source =
105
+ typeof item.source === 'string'
106
+ ? item.source
107
+ : typeof item.url === 'string'
108
+ ? item.url
109
+ : undefined;
110
+ if (!source) continue;
111
+ const detail =
112
+ typeof item.detail === 'string'
113
+ ? normalizeImageDetail(item.detail)
114
+ : undefined;
115
+ const rawMax = item.maxLongSidePixel ?? item.max_long_side_pixel;
116
+ const maxLongSidePixel =
117
+ typeof rawMax === 'number' && Number.isFinite(rawMax)
118
+ ? Math.floor(rawMax)
119
+ : undefined;
120
+ out.push({ source, detail, maxLongSidePixel });
121
+ }
122
+ return out;
123
+ }
124
+
125
+ /**
126
+ * stdin 控制通道:把 stdin 从「一次性裸 prompt」升级为**逐行 JSON 控制通道**,
127
+ * 支撑「问答 over wire」的入站半边。两种控制消息:
128
+ * - `{ type:'prompt', text }` —— 首行,本轮的用户输入(替代裸 prompt)
129
+ * - `{ type:'ask_answer', requestId, answers }` —— AskUserQuestion 的回答,按 requestId 关联
130
+ *
131
+ * 向后兼容:首个非空行**不是** `{type:'prompt'}` 控制消息时,判定为 legacy 模式 ——
132
+ * 整段 stdin 当裸 prompt 读到 EOF(保 `echo "x" | minimal-agent -p --output-format stream-json` 仍可用,
133
+ * legacy 下天然无交互、一次性)。argv 已给 prompt 时,stdin 全部行都按 ask_answer 解析。
134
+ *
135
+ * 返回 `{ prompt, control }`:`control=true` **仅**当 prompt 来自 `{type:'prompt'}` 控制行
136
+ * (= broker 在管理本子进程、会回灌 ask_answer);argv / 裸管道 / TTY / EOF 兜底均为 `false`
137
+ * (无人回灌 → 调用方据此**不注册** wire ask handler,让 askBridge 内置「自动选推荐项」兜底,
138
+ * 避免模型提问后永等挂死)。同时把 ask_answer 路由给 onAskAnswer。stdin 全程保持打开,
139
+ * 直到子进程结束(broker 在 turn 末 end stdin)。
140
+ */
141
+ export function attachStdinChannel(opts: {
142
+ argvPrompt?: string;
143
+ onAskAnswer: (requestId: string, answers: AskAnswer[]) => void;
144
+ /** 输入流;默认 process.stdin(测试可注入 PassThrough 驱动)。 */
145
+ input?: NodeJS.ReadableStream & { isTTY?: boolean };
146
+ }): Promise<{ prompt: string; control: boolean; imageInputs?: ImageInputSpec[] }> {
147
+ const input = opts.input ?? process.stdin;
148
+ return new Promise<{ prompt: string; control: boolean; imageInputs?: ImageInputSpec[] }>((resolvePrompt) => {
149
+ let promptResolved = false;
150
+ const resolveOnce = (
151
+ text: string,
152
+ control: boolean,
153
+ imageInputs?: ImageInputSpec[],
154
+ ): void => {
155
+ if (promptResolved) return;
156
+ promptResolved = true;
157
+ resolvePrompt(
158
+ imageInputs && imageInputs.length > 0
159
+ ? { prompt: text, control, imageInputs }
160
+ : { prompt: text, control },
161
+ );
162
+ };
163
+ // argv 给的 prompt:直连 CLI、无控制通道(broker 走 stdin 的 {type:'prompt'},不用 argv)。
164
+ if (opts.argvPrompt !== undefined) resolveOnce(opts.argvPrompt, false);
165
+
166
+ // 无 stdin 管道(TTY):argv 没给 prompt 也只能返回空(调用方据空报错)。
167
+ if (input.isTTY) {
168
+ resolveOnce('', false);
169
+ return;
170
+ }
171
+
172
+ let buf = '';
173
+ let legacy = false;
174
+ input.setEncoding('utf8');
175
+ input.on('data', (chunk: string) => {
176
+ buf += chunk;
177
+ if (legacy) return; // legacy:整段累积到 EOF
178
+ let nl: number;
179
+ while ((nl = buf.indexOf('\n')) >= 0) {
180
+ const line = buf.slice(0, nl);
181
+ buf = buf.slice(nl + 1);
182
+ if (!line.trim()) continue;
183
+ let msg:
184
+ | {
185
+ type?: string;
186
+ text?: unknown;
187
+ images?: unknown;
188
+ requestId?: unknown;
189
+ answers?: unknown;
190
+ }
191
+ | null = null;
192
+ try {
193
+ msg = JSON.parse(line);
194
+ } catch {
195
+ msg = null;
196
+ }
197
+ if (!promptResolved) {
198
+ if (msg && msg.type === 'prompt' && typeof msg.text === 'string') {
199
+ resolveOnce(msg.text, true, parseWireImages(msg.images)); // 控制行 → 存在控制通道
200
+ } else {
201
+ // 首行不是 prompt 控制消息 → legacy:把它放回去,整段当裸 prompt 读到 EOF
202
+ legacy = true;
203
+ buf = buf.length ? `${line}\n${buf}` : line;
204
+ return;
205
+ }
206
+ } else if (msg && msg.type === 'ask_answer' && typeof msg.requestId === 'string') {
207
+ opts.onAskAnswer(msg.requestId, Array.isArray(msg.answers) ? (msg.answers as AskAnswer[]) : []);
208
+ }
209
+ }
210
+ });
211
+ input.on('end', () => {
212
+ // legacy 一次性:EOF 时整段 stdin = 裸 prompt,无控制通道
213
+ if (!promptResolved) resolveOnce(buf.trim(), false);
214
+ });
215
+ });
216
+ }
217
+
218
+ export async function runStreamJsonMode(
219
+ provider: Provider,
220
+ args: string[],
221
+ initialHistory: Message[],
222
+ options: StreamJsonOptions,
223
+ ): Promise<void> {
224
+ process.stdout.on('error', (err: NodeJS.ErrnoException) => {
225
+ if (err.code === 'EPIPE') process.stdout.destroy();
226
+ });
227
+
228
+ const history = initialHistory;
229
+ // 收尾守卫用「缓存 promise」而非「布尔 once」(与 print.ts finalizeOnce 同构):
230
+ // SIGINT handler 与 for-await 的 AbortError catch 是两条并发退出路径,布尔 once
231
+ // 会让后到的路径立即返回、抢在 saveContext 落盘完成前 process.exit → 会话丢失。
232
+ // 缓存 promise 让所有路径 await 同一次真实收尾。
233
+ let finalizePromise: Promise<void> | null = null;
234
+ const finalize = (): Promise<void> => {
235
+ finalizePromise ??= (async () => {
236
+ // 释放 stdin:attachStdinChannel 的 'data' 监听会让进程在本轮结束后**仍存活**
237
+ // (等下一行输入)→ broker 永远收不到子进程 close、web 端 conn.running 卡死。
238
+ // turn 已结束(无挂起提问),unref 让 stdout 排空后进程自然退出;中途挂起期间
239
+ // 不会走到这里,故等答案时进程仍被 stdin 监听保活。
240
+ try {
241
+ process.stdin.unref();
242
+ } catch {
243
+ /* 某些 stdin 类型无 unref,忽略 */
244
+ }
245
+ setAskHandler(null); // 注销 handler,避免全局污染(测试复用 / 同进程多次调用)
246
+ await saveContext(history, options.sessionFile);
247
+ })();
248
+ return finalizePromise;
249
+ };
250
+
251
+ // --- 压缩动作(/compact):不需要 prompt ---
252
+ if (options.compact) {
253
+ try {
254
+ emitLine({ type: 'compact_start' });
255
+ const r = await forceCompact(
256
+ history,
257
+ provider,
258
+ undefined,
259
+ undefined,
260
+ createPromptCacheContext(
261
+ `workspace:${options.workspace?.cwd ?? getWorkingDir()}:session:${options.workspace?.sessionId ?? 'default'}`,
262
+ ),
263
+ );
264
+ history.length = 0;
265
+ history.push(...r.messages);
266
+ emitLine({
267
+ type: 'compact_done',
268
+ before: r.before,
269
+ after: r.after,
270
+ trigger: 'manual',
271
+ mode: r.mode,
272
+ degraded: r.degraded,
273
+ ...(r.fallbackReason ? { fallbackReason: r.fallbackReason } : {}),
274
+ ...(r.messagesRemoved !== undefined ? { messagesRemoved: r.messagesRemoved } : {}),
275
+ ...(r.tokensFreed !== undefined ? { tokensFreed: r.tokensFreed } : {}),
276
+ });
277
+ emitLine({ type: 'turn_done' });
278
+ } catch {
279
+ emitLine({ type: 'error', error: '手动压缩失败。', code: 'compact_failed' });
280
+ }
281
+ await finalize();
282
+ return;
283
+ }
284
+
285
+ // --- 普通一轮 ---
286
+ // 「问答 over wire」入站半边:pendingAsks 持本轮未决提问(requestId → resolver)。
287
+ const pendingAsks = new Map<
288
+ string,
289
+ { resolve: (a: AskAnswer[]) => void; reject: (e: Error) => void }
290
+ >();
291
+ const rejectAllAsks = (reason: string): void => {
292
+ for (const p of pendingAsks.values()) p.reject(new Error(reason));
293
+ pendingAsks.clear();
294
+ };
295
+
296
+ const promptArgs = extractPromptArgs(args);
297
+ const cliImageOptions = extractImageOptions(args);
298
+ const { prompt, control, imageInputs: stdinImageInputs } = await attachStdinChannel({
299
+ argvPrompt: promptArgs.length > 0 ? promptArgs.join(' ') : undefined,
300
+ onAskAnswer: (requestId, answers) => {
301
+ const p = pendingAsks.get(requestId);
302
+ if (p) {
303
+ pendingAsks.delete(requestId);
304
+ p.resolve(answers);
305
+ }
306
+ },
307
+ });
308
+
309
+ // 仅当存在控制通道(broker 经 `{type:'prompt'}` 启动、会回灌 ask_answer)才注册 wire handler:
310
+ // 工具调 requestUserChoice → emit `ask` 到 stdout、挂起等 stdin 回灌。无控制通道(argv / 裸管道 /
311
+ // TTY)时**不注册** → 落 askBridge 内置「自动选推荐项」兜底,避免模型提问后永等挂死。
312
+ // loop 在 prompt resolve 后才启动 → 此处注册时机安全(注册前不会有 ask 触发)。
313
+ if (control) {
314
+ setAskHandler(
315
+ (questions) =>
316
+ new Promise<AskAnswer[]>((resolve, reject) => {
317
+ const requestId = crypto.randomUUID();
318
+ pendingAsks.set(requestId, { resolve, reject });
319
+ emitLine({ type: 'ask', requestId, questions });
320
+ }),
321
+ );
322
+ }
323
+
324
+ if (!prompt.trim()) {
325
+ emitLine({ type: 'error', error: '未提供 prompt(argv / stdin 都为空)', code: 'llm_error' });
326
+ process.exit(1);
327
+ }
328
+
329
+ // 记录最近目录(侧栏用);title 优先用历史里第一条用户消息(稳定),否则用当前 prompt
330
+ await recordRecentDir(getWorkingDir(), firstUserTitle(history) ?? prompt);
331
+ if (options.workspace) {
332
+ await updateSessionMetadata(options.workspace.cwd, options.workspace.sessionId, {
333
+ lastMessagePreview: prompt,
334
+ }).catch(() => {});
335
+ }
336
+
337
+ const abortController = new AbortController();
338
+ let interrupted = false;
339
+ process.on('SIGINT', () => {
340
+ if (interrupted) process.exit(130);
341
+ interrupted = true;
342
+ abortController.abort();
343
+ rejectAllAsks('已中断'); // 挂起的提问立即落败,工具回 ok:false → loop 收口 interrupted
344
+ emitLine({ type: 'interrupted' });
345
+ void finalize().finally(() => process.exit(130));
346
+ });
347
+
348
+ try {
349
+ const workspaceRoot = options.workspace?.cwd ?? getWorkingDir();
350
+ const workspace = await workspaceIndexService.findByPath(workspaceRoot).catch(() => null);
351
+ const sessionId = options.workspace?.sessionId ?? 'default';
352
+ const sessionState = getOrCreateSessionState(sessionStateKey({
353
+ surface: 'headless', workspaceId: workspace?.id,
354
+ cwd: workspace?.id ? undefined : workspaceRoot, sessionId,
355
+ }));
356
+ await hydrateSessionWorktree({ sessionState, workspaceId: workspace?.id, sessionId, cwd: workspaceRoot });
357
+ const cwd = sessionState.activeWorktree?.path ?? workspaceRoot;
358
+ const conversationKey = `workspace:${workspace?.id ?? workspaceRoot}:session:${sessionId}`;
359
+ const computerRun = options.computerUseMode && options.computerUseMode !== 'disabled'
360
+ ? createCliComputerRun({
361
+ mode: options.computerUseMode,
362
+ surface: 'cli',
363
+ conversationKey,
364
+ userInput: prompt,
365
+ allowedFileRoots: [cwd],
366
+ supervised: true,
367
+ diagnosticTraceDir: options.computerUseTraceDir,
368
+ })
369
+ : undefined;
370
+ const runtimeContext = createAgentRuntimeContext({
371
+ surface: 'headless',
372
+ profile: 'main',
373
+ cwd,
374
+ workspaceId: workspace?.id,
375
+ sessionId,
376
+ owner: options.memoryAccess === 'denied' ? 'untrusted' : 'local-owner',
377
+ memoryAccess: options.memoryAccess ?? 'read-only',
378
+ interactiveAsk: control,
379
+ computer: computerRun,
380
+ });
381
+ const turnTools = filterToolsForRuntime(ALL_TOOLS, runtimeContext);
382
+ const stablePrompt = await buildBaseSystemPrompt(cwd, turnTools);
383
+ if (history[0]?.role === 'system') history[0] = { ...history[0], content: stablePrompt };
384
+ else history.unshift({ role: 'system', content: stablePrompt });
385
+ const transientBundle = await buildTransientPromptBundle({
386
+ cwd,
387
+ tools: turnTools,
388
+ runtime: {
389
+ surface: 'headless',
390
+ cwd,
391
+ workspaceId: workspace?.id,
392
+ sessionId,
393
+ interactiveAsk: control,
394
+ memoryAccess: runtimeContext.memoryAccess,
395
+ currentUserInput: prompt,
396
+ },
397
+ }).catch(() => undefined);
398
+ for await (const event of runWithPlugins(prompt, {
399
+ provider,
400
+ history,
401
+ signal: abortController.signal,
402
+ maxTurns: options.maxTurns,
403
+ imageInputs: [...cliImageOptions.imageInputs, ...(stdinImageInputs ?? [])],
404
+ parseInlineImages: true,
405
+ imageDetail: cliImageOptions.imageDetail,
406
+ imageMaxLongSidePixel: cliImageOptions.imageMaxLongSidePixel,
407
+ runtimeContext,
408
+ sessionState,
409
+ allowedTools: turnTools.map((tool) => tool.name),
410
+ ...(transientBundle ? { transientBundle } : {}),
411
+ promptCache: createPromptCacheContext(
412
+ `workspace:${workspace?.id ?? cwd}:session:${sessionId}`,
413
+ ),
414
+ memoryContext: memoryContextFromRuntime(runtimeContext),
415
+ ...(computerRun ? { computerRun } : {}),
416
+ })) {
417
+ // event 是 LoopEvent | PluginEvent,原样逐行 emit;前端不识别的插件私有事件会静默忽略
418
+ emitLine(event);
419
+ }
420
+ } catch (e) {
421
+ if ((e as Error).name === 'AbortError') {
422
+ // SIGINT 路径已 emit 过 interrupted → 不重发(stdout jsonl 语义:一次中断一行)
423
+ if (!interrupted) emitLine({ type: 'interrupted' });
424
+ await finalize();
425
+ process.exit(130);
426
+ }
427
+ emitLine({ type: 'error', error: (e as Error).message, code: 'llm_error' });
428
+ await finalize();
429
+ process.exit(1);
430
+ }
431
+
432
+ await finalize();
433
+ }
@@ -121,6 +121,7 @@ export function AdvisorWizard({ existing, models, onDone, onCancel }) {
121
121
  model: newModelDraft.model,
122
122
  contextWindow: newModelDraft.contextWindow,
123
123
  supportsVision: newModelDraft.supportsVision,
124
+ promptCache: { mode: 'auto' },
124
125
  enabled: true,
125
126
  },
126
127
  }],