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,159 @@
1
+ /**
2
+ * ============================================================
3
+ * plugins/computer_use/src/manuals.ts —— 应用说明书的清单与详情
4
+ * ------------------------------------------------------------
5
+ * 说明书文件住在本插件的 `app/`,但**解析与匹配**用内核的
6
+ * `vision/appGuide.ts` —— 内核工具在每次观测时也用同一份逻辑,两边必须
7
+ * 是同一套判断,否则 `/computeruse apps` 说"命中了"而模型那边没命中。
8
+ * ============================================================
9
+ */
10
+
11
+ import {
12
+ computerUseDiagnostics,
13
+ describeMatch,
14
+ EMPTY_MANUAL,
15
+ loadAllAppManuals,
16
+ matchGuide,
17
+ validateManual,
18
+ type LoadedManuals,
19
+ } from '../../../src/plugin-sdk.js';
20
+
21
+ /** 全部说明书 + 冲突报告。与内核工具用**同一个**加载器,不另写一份。 */
22
+ export async function loadAllManuals(): Promise<LoadedManuals> {
23
+ return loadAllAppManuals();
24
+ }
25
+
26
+ /** 当前前台应用身份。拿不到就返回 undefined —— 不猜。 */
27
+ async function foregroundIdentity(
28
+ signal?: AbortSignal,
29
+ ): Promise<{ id?: string; name?: string } | undefined> {
30
+ if (!computerUseDiagnostics.platformSupported()) return undefined;
31
+ const response = await computerUseDiagnostics.observe(signal).catch(() => null);
32
+ if (!response?.ok || !response.state?.activeApp) return undefined;
33
+ return { id: response.state.activeApp.id, name: response.state.activeApp.name };
34
+ }
35
+
36
+ export async function runApps(signal?: AbortSignal): Promise<string> {
37
+ const { guides, conflicts, rejected } = await loadAllManuals();
38
+ const lines = ['# 应用说明书', ''];
39
+ if (guides.length === 0 && rejected.length === 0) {
40
+ lines.push(
41
+ '(一份都没有。工作区说明书放 `app-manuals/<app>.md`;',
42
+ '插件提供的要在 plugin.json 里声明 `"appManuals": "app"`。)',
43
+ );
44
+ return lines.join('\n');
45
+ }
46
+
47
+ for (const guide of guides) {
48
+ const identifiers = [...guide.bundleIds, ...guide.processNames, ...guide.displayNames];
49
+ lines.push(
50
+ `- **${guide.name}** — 匹配标识 ${identifiers.length} 个 · 不可逆声明 ${guide.irreversible.length} 条`,
51
+ );
52
+ }
53
+
54
+ // 被隔离的说明书必须可见,而且要说得出错在哪 —— 它们的失败方式全是静默的:
55
+ // match 写错就永远匹配不上、precondition 写错就永远不生效。不报出来,用户
56
+ // 会以为自己没写过这份说明书。
57
+ if (rejected.length > 0) {
58
+ lines.push('', '## ⛔ 已隔离(写错了,不会进入模型上下文)');
59
+ for (const item of rejected) {
60
+ lines.push(`- **${item.guide.name}** — ${item.guide.path}`);
61
+ for (const message of item.errors) lines.push(` - ${message}`);
62
+ }
63
+ }
64
+
65
+ // 冲突必须可见:靠目录顺序决定「哪份知识生效」而没人知道,是最难查的那类问题。
66
+ if (conflicts.length > 0) {
67
+ lines.push('', '## ⚠️ 冲突');
68
+ for (const conflict of conflicts) {
69
+ lines.push(conflict.kind === 'same-name'
70
+ ? `- 同名说明书 \`${conflict.key}\`:生效 ${conflict.winner},被遮蔽 ${conflict.shadowed}`
71
+ : `- 标识 \`${conflict.key}\` 被两份说明书同时认领:生效 ${conflict.winner},被遮蔽 ${conflict.shadowed}`);
72
+ }
73
+ }
74
+
75
+ const identity = await foregroundIdentity(signal);
76
+ lines.push('', '## 当前前台应用');
77
+ if (!identity) {
78
+ lines.push('拿不到前台应用(平台不支持、权限未授予或守护进程不可用)。');
79
+ } else {
80
+ lines.push(`${identity.name ?? '未知'}(${identity.id ?? '无标识'})`, '');
81
+ lines.push(describeMatch(matchGuide(guides, identity), guides, identity));
82
+ }
83
+ return lines.join('\n');
84
+ }
85
+
86
+ export async function runApp(name: string): Promise<string> {
87
+ const trimmed = name.trim();
88
+ if (!trimmed) return '用法:`/computeruse app <name>`(名字见 `/computeruse apps`)';
89
+
90
+ const { guides, rejected } = await loadAllManuals();
91
+ // 被隔离的那些也要能查 —— 用户最需要看详情的恰恰是写坏的那一份。
92
+ const blocked = rejected.find((item) => item.guide.name === trimmed);
93
+ const guide = guides.find((candidate) => candidate.name === trimmed) ?? blocked?.guide;
94
+ if (!guide) {
95
+ return [
96
+ `没有名为「${trimmed}」的说明书。`,
97
+ `已有:${guides.map((g) => g.name).join('、') || '(无)'}`,
98
+ ].join('\n');
99
+ }
100
+
101
+ const checkable = guide.irreversible.filter(
102
+ (entry) => entry.startsWith('key:') || entry.startsWith('region:'),
103
+ );
104
+ const manual = guide.manual ?? EMPTY_MANUAL;
105
+ const issues = validateManual({
106
+ manual,
107
+ irreversible: guide.irreversible,
108
+ identifiers: guide.bundleIds.length + guide.processNames.length + guide.displayNames.length,
109
+ });
110
+ const unverified = [
111
+ ...manual.layout.filter((r) => !r.verified).map((r) => `分区 ${r.id}`),
112
+ ...manual.controls.filter((c) => !c.verified).map((c) => `控件 ${c.id}`),
113
+ ...manual.flows.filter((f) => !f.verified).map((f) => `流程 ${f.id}`),
114
+ ];
115
+
116
+ return [
117
+ `# 说明书 ${guide.name}`,
118
+ '',
119
+ // 隔离状态放最前面:其它信息都建立在「它到底生不生效」之上。
120
+ ...(blocked
121
+ ? ['⛔ **已隔离**:这份说明书写错了,不会进入模型上下文。修完下面的 ❌ 才会生效。', '']
122
+ : []),
123
+ `文件:${guide.path}`,
124
+ `schema v${manual.schemaVersion}`,
125
+ `bundleId:${guide.bundleIds.join('、') || '(无)'}`,
126
+ `进程名:${guide.processNames.join('、') || '(无)'}`,
127
+ `显示名:${guide.displayNames.join('、') || '(无)'}`,
128
+ '',
129
+ '## 不可逆声明',
130
+ ...(guide.irreversible.length > 0
131
+ ? guide.irreversible.map((entry) => `- ${entry}`)
132
+ : ['(无)']),
133
+ '',
134
+ checkable.length > 0
135
+ ? `其中 ${checkable.length} 条是**引擎可独立验证**的(key/region)。`
136
+ : '⚠️ 全部是 `intent:` 形式 —— 只能靠模型自报,模型漏报就拦不住。'
137
+ + '等实机验证出稳定的按键或区域,改成 key:/region: 才是真拦截。',
138
+ '',
139
+ '## 结构化内容',
140
+ `分区 ${manual.layout.length} · 控件 ${manual.controls.length} · 流程 ${manual.flows.length}`,
141
+ ...manual.flows.map((flow) => {
142
+ const guarded = flow.steps.filter((s) => s.precondition).length;
143
+ return `- ${flow.id}:${flow.steps.length} 步`
144
+ + (guarded > 0 ? `,其中 ${guarded} 步有机器可检查的前置条件` : ',无前置条件');
145
+ }),
146
+ '',
147
+ '## 校验',
148
+ ...(issues.length > 0
149
+ ? issues.map((issue) => `${issue.level === 'error' ? '❌' : '⚠️'} ${issue.message}`)
150
+ : ['✅ 无问题']),
151
+ '',
152
+ '## 未验证条目',
153
+ // 未验证不是缺陷,是**状态**。说清楚才能知道哪些还得实机跑一遍;
154
+ // 不说,就等于把猜测当事实用。
155
+ unverified.length > 0
156
+ ? `${unverified.length} 项:${unverified.join('、')}`
157
+ : '(无 —— 所有结构化条目都已标记 verified)',
158
+ ].join('\n');
159
+ }
@@ -0,0 +1,168 @@
1
+ /**
2
+ * ============================================================
3
+ * plugins/computer_use/src/verify.ts —— 半自动实机验收
4
+ * ------------------------------------------------------------
5
+ * 为什么需要它:说明书里的流程目前全部 `verified: false` —— 它们是把面向人的
6
+ * 帮助文档转写成 agent 视角,**没有一条实机跑过**。而实机验收这件事我单方面
7
+ * 做不了:它会接管用户的屏幕、需要人在场判断「这一步到底成了没有」。
8
+ *
9
+ * 于是把它做成脚手架:逐步提示 → 人拍板 → 每步自动观测并记下**实际看到的** →
10
+ * 一条流程全过才把 `verified` 翻真。用户什么时候方便就跑一个 app,
11
+ * 结论可累积、可审计。
12
+ *
13
+ * ★ 三条纪律:
14
+ * ① **人说通过才算通过。** 观测只负责记录现场,不替人判断成败 —— 引擎看不出
15
+ * 「消息真的发给了张三」这种事。
16
+ * ② **只翻全过的那条流程。** 任一步失败或跳过,整条保持 false 并记下卡在哪。
17
+ * 部分通过就翻真,等于把「大概能用」写成「已验证」。
18
+ * ③ **写工作区,不动包内文件**(见 diagnostics.ts::saveVerification)。
19
+ *
20
+ * 问用户走 `executeTool('AskUserQuestion')` —— 与 workflow-runner 的 pause 同
21
+ * 一条通道,非交互宿主会自动选推荐项(这里推荐项是「停止」,见下)。
22
+ * ============================================================
23
+ */
24
+ import { computerUseDiagnostics, executeTool, } from '../../../src/plugin-sdk.js';
25
+ export async function runVerify(raw, signal) {
26
+ const name = raw.trim().split(/\s+/)[0] ?? '';
27
+ if (!name) {
28
+ return '用法:`/computeruse verify <app>`(名字见 `/computeruse apps`)\n'
29
+ + '它会逐步提示你操作、每步记录实际观测,全部通过才把该流程标记为已验证。';
30
+ }
31
+ if (!computerUseDiagnostics.platformSupported()) {
32
+ return `⚠️ 当前平台是 ${process.platform},实机验收只能在 macOS 上做。`;
33
+ }
34
+ const source = await computerUseDiagnostics.readManualSource(name);
35
+ if (typeof source === 'string')
36
+ return `# 实机验收\n\n${source}`;
37
+ const flows = source.guide.manual?.flows ?? [];
38
+ if (flows.length === 0) {
39
+ return [
40
+ `# 实机验收:${name}`,
41
+ '',
42
+ '这份说明书没有声明任何 `flows:` —— 没有可验收的流程。',
43
+ '先用 `/computeruse capture` 采一份草稿,把流程补上,再回来验收。',
44
+ ].join('\n');
45
+ }
46
+ const records = [];
47
+ const verifiedFlows = [];
48
+ let aborted = false;
49
+ for (const flow of flows) {
50
+ if (aborted)
51
+ break;
52
+ if (flow.verified)
53
+ continue; // 已验证过的不重复折腾人
54
+ const outcome = await verifyFlow(flow, records, signal);
55
+ if (outcome === 'aborted') {
56
+ aborted = true;
57
+ break;
58
+ }
59
+ if (outcome === 'passed')
60
+ verifiedFlows.push(flow.id);
61
+ }
62
+ return renderResult({ source, flows, records, verifiedFlows, aborted, signal });
63
+ }
64
+ async function verifyFlow(flow, records, signal) {
65
+ let allPassed = flow.steps.length > 0;
66
+ for (const [index, step] of flow.steps.entries()) {
67
+ const verdict = await askStep(flow, index, step.do, signal);
68
+ const scene = await observeScene(signal);
69
+ records.push({ flowId: flow.id, index: index + 1, step: step.do, verdict, scene });
70
+ if (verdict === 'aborted')
71
+ return 'aborted';
72
+ if (verdict !== 'passed') {
73
+ allPassed = false;
74
+ // 一步没过,这条流程后面的步骤多半也无从谈起 —— 不再逐个折腾人。
75
+ break;
76
+ }
77
+ }
78
+ return allPassed ? 'passed' : 'failed';
79
+ }
80
+ async function askStep(flow, index, step, signal) {
81
+ const result = await executeTool('AskUserQuestion', JSON.stringify({
82
+ questions: [{
83
+ header: `验收 ${flow.id}`,
84
+ question: `【${flow.id} 第 ${index + 1}/${flow.steps.length} 步】${step}\n`
85
+ + (flow.goal ? `(这条流程的目标:${flow.goal})\n` : '')
86
+ + '请你在真实应用里做这一步,然后告诉我结果。',
87
+ options: [
88
+ // 首项是非交互宿主的自动兜底 —— 必须是「停止」:无人在场时不该
89
+ // 产出一份「全部通过」的验收结论。
90
+ { label: '停止验收', description: '结束本次验收,已记录的结果保留。' },
91
+ { label: '做到了', description: '这一步按说明书描述完成了。' },
92
+ { label: '跳过', description: '这一步这次不测(不算通过)。' },
93
+ { label: '失败了', description: '照说明书做不出来 —— 说明书与实际不符。' },
94
+ ],
95
+ }],
96
+ }), signal);
97
+ if (!result.ok)
98
+ return 'aborted';
99
+ const label = String(result.content ?? '');
100
+ if (label.includes('做到了'))
101
+ return 'passed';
102
+ if (label.includes('跳过'))
103
+ return 'skipped';
104
+ if (label.includes('失败'))
105
+ return 'failed';
106
+ return 'aborted';
107
+ }
108
+ /** 记下这一步执行后**实际看到的**现场。观测失败也如实写,不留空。 */
109
+ async function observeScene(signal) {
110
+ const response = await computerUseDiagnostics.observe(signal).catch(() => null);
111
+ if (!response?.ok || !response.state) {
112
+ return `观测失败(${response?.error?.code ?? 'unknown'})`;
113
+ }
114
+ const state = response.state;
115
+ const windows = state.windows.map((w) => w.title ?? '(无标题)').slice(0, 3).join(' / ');
116
+ return [
117
+ `前台 ${state.activeApp?.name ?? '未知'}(${state.activeApp?.id ?? '无标识'})`,
118
+ `窗口 ${windows || '无'}`,
119
+ `AX ${state.accessibility ? (state.accessibility.truncated ? '不完整' : '可用') : '无'}`,
120
+ ].join(' · ');
121
+ }
122
+ async function renderResult(input) {
123
+ const { source, records, verifiedFlows, aborted } = input;
124
+ const lines = [
125
+ `# 实机验收:${source.name}`,
126
+ '',
127
+ `说明书:${source.path}`,
128
+ aborted ? '⚠️ 验收被中止,下面只是已经走过的部分。' : '',
129
+ '',
130
+ '## 逐步结果',
131
+ '',
132
+ ].filter((line) => line !== '' || true);
133
+ if (records.length === 0) {
134
+ return [
135
+ `# 实机验收:${source.name}`,
136
+ '',
137
+ '没有可验收的流程 —— 声明的流程可能都已标记为已验证。',
138
+ '想重验请先把对应流程的 `verified` 改回 false。',
139
+ ].join('\n');
140
+ }
141
+ for (const record of records) {
142
+ const mark = record.verdict === 'passed' ? '✅'
143
+ : record.verdict === 'skipped' ? '⏭️'
144
+ : record.verdict === 'failed' ? '❌' : '⛔';
145
+ lines.push(`${mark} ${record.flowId} 第 ${record.index} 步:${record.step}`);
146
+ lines.push(` 实际观测:${record.scene}`);
147
+ }
148
+ lines.push('', '## 结论', '', verifiedFlows.length > 0
149
+ ? `全部通过、可标记为已验证的流程:${verifiedFlows.join('、')}`
150
+ : '没有任何流程全部通过 —— 保持未验证。');
151
+ const notes = buildNotes(records, verifiedFlows);
152
+ const written = await computerUseDiagnostics.saveVerification({ source, verifiedFlows, notes }, input.signal);
153
+ lines.push('', written.ok ? `✅ 已写入 ${written.path}` : `未写盘:${written.error}`);
154
+ if (!written.ok) {
155
+ lines.push('', '实测记录(可自己贴进说明书的 `## 实测记录` 一节):', '', ...notes);
156
+ }
157
+ return lines.join('\n');
158
+ }
159
+ /** 追加进 `## 实测记录` 的行。带日期,因为「上次能用这次不能」本身是信息。 */
160
+ function buildNotes(records, verifiedFlows) {
161
+ const day = new Date().toISOString().slice(0, 10);
162
+ const notes = [`- ${day} 实机验收:通过 ${verifiedFlows.join('、') || '(无)'}`];
163
+ for (const record of records.filter((item) => item.verdict !== 'passed')) {
164
+ notes.push(` - ${record.flowId} 第 ${record.index} 步(${record.verdict}):${record.step}`
165
+ + ` —— 当时 ${record.scene}`);
166
+ }
167
+ return notes;
168
+ }
@@ -0,0 +1,219 @@
1
+ /**
2
+ * ============================================================
3
+ * plugins/computer_use/src/verify.ts —— 半自动实机验收
4
+ * ------------------------------------------------------------
5
+ * 为什么需要它:说明书里的流程目前全部 `verified: false` —— 它们是把面向人的
6
+ * 帮助文档转写成 agent 视角,**没有一条实机跑过**。而实机验收这件事我单方面
7
+ * 做不了:它会接管用户的屏幕、需要人在场判断「这一步到底成了没有」。
8
+ *
9
+ * 于是把它做成脚手架:逐步提示 → 人拍板 → 每步自动观测并记下**实际看到的** →
10
+ * 一条流程全过才把 `verified` 翻真。用户什么时候方便就跑一个 app,
11
+ * 结论可累积、可审计。
12
+ *
13
+ * ★ 三条纪律:
14
+ * ① **人说通过才算通过。** 观测只负责记录现场,不替人判断成败 —— 引擎看不出
15
+ * 「消息真的发给了张三」这种事。
16
+ * ② **只翻全过的那条流程。** 任一步失败或跳过,整条保持 false 并记下卡在哪。
17
+ * 部分通过就翻真,等于把「大概能用」写成「已验证」。
18
+ * ③ **写工作区,不动包内文件**(见 diagnostics.ts::saveVerification)。
19
+ *
20
+ * 问用户走 `executeTool('AskUserQuestion')` —— 与 workflow-runner 的 pause 同
21
+ * 一条通道,非交互宿主会自动选推荐项(这里推荐项是「停止」,见下)。
22
+ * ============================================================
23
+ */
24
+
25
+ import {
26
+ computerUseDiagnostics,
27
+ executeTool,
28
+ type ManualFlow,
29
+ type ManualSource,
30
+ } from '../../../src/plugin-sdk.js';
31
+
32
+ /** 每步三选一。「跳过」与「失败」都不算通过 —— 只是记下来的理由不同。 */
33
+ type StepVerdict = 'passed' | 'skipped' | 'failed' | 'aborted';
34
+
35
+ interface StepRecord {
36
+ flowId: string;
37
+ index: number;
38
+ step: string;
39
+ verdict: StepVerdict;
40
+ /** 这一步执行时**实际看到的**现场。 */
41
+ scene: string;
42
+ }
43
+
44
+ export async function runVerify(raw: string, signal?: AbortSignal): Promise<string> {
45
+ const name = raw.trim().split(/\s+/)[0] ?? '';
46
+ if (!name) {
47
+ return '用法:`/computeruse verify <app>`(名字见 `/computeruse apps`)\n'
48
+ + '它会逐步提示你操作、每步记录实际观测,全部通过才把该流程标记为已验证。';
49
+ }
50
+ if (!computerUseDiagnostics.platformSupported()) {
51
+ return `⚠️ 当前平台是 ${process.platform},实机验收只能在 macOS 上做。`;
52
+ }
53
+
54
+ const source = await computerUseDiagnostics.readManualSource(name);
55
+ if (typeof source === 'string') return `# 实机验收\n\n${source}`;
56
+
57
+ const flows = source.guide.manual?.flows ?? [];
58
+ if (flows.length === 0) {
59
+ return [
60
+ `# 实机验收:${name}`,
61
+ '',
62
+ '这份说明书没有声明任何 `flows:` —— 没有可验收的流程。',
63
+ '先用 `/computeruse capture` 采一份草稿,把流程补上,再回来验收。',
64
+ ].join('\n');
65
+ }
66
+
67
+ const records: StepRecord[] = [];
68
+ const verifiedFlows: string[] = [];
69
+ let aborted = false;
70
+
71
+ for (const flow of flows) {
72
+ if (aborted) break;
73
+ if (flow.verified) continue; // 已验证过的不重复折腾人
74
+ const outcome = await verifyFlow(flow, records, signal);
75
+ if (outcome === 'aborted') { aborted = true; break; }
76
+ if (outcome === 'passed') verifiedFlows.push(flow.id);
77
+ }
78
+
79
+ return renderResult({ source, flows, records, verifiedFlows, aborted, signal });
80
+ }
81
+
82
+ async function verifyFlow(
83
+ flow: ManualFlow,
84
+ records: StepRecord[],
85
+ signal?: AbortSignal,
86
+ ): Promise<'passed' | 'failed' | 'aborted'> {
87
+ let allPassed = flow.steps.length > 0;
88
+ for (const [index, step] of flow.steps.entries()) {
89
+ const verdict = await askStep(flow, index, step.do, signal);
90
+ const scene = await observeScene(signal);
91
+ records.push({ flowId: flow.id, index: index + 1, step: step.do, verdict, scene });
92
+ if (verdict === 'aborted') return 'aborted';
93
+ if (verdict !== 'passed') {
94
+ allPassed = false;
95
+ // 一步没过,这条流程后面的步骤多半也无从谈起 —— 不再逐个折腾人。
96
+ break;
97
+ }
98
+ }
99
+ return allPassed ? 'passed' : 'failed';
100
+ }
101
+
102
+ async function askStep(
103
+ flow: ManualFlow,
104
+ index: number,
105
+ step: string,
106
+ signal?: AbortSignal,
107
+ ): Promise<StepVerdict> {
108
+ const result = await executeTool(
109
+ 'AskUserQuestion',
110
+ JSON.stringify({
111
+ questions: [{
112
+ header: `验收 ${flow.id}`,
113
+ question: `【${flow.id} 第 ${index + 1}/${flow.steps.length} 步】${step}\n`
114
+ + (flow.goal ? `(这条流程的目标:${flow.goal})\n` : '')
115
+ + '请你在真实应用里做这一步,然后告诉我结果。',
116
+ options: [
117
+ // 首项是非交互宿主的自动兜底 —— 必须是「停止」:无人在场时不该
118
+ // 产出一份「全部通过」的验收结论。
119
+ { label: '停止验收', description: '结束本次验收,已记录的结果保留。' },
120
+ { label: '做到了', description: '这一步按说明书描述完成了。' },
121
+ { label: '跳过', description: '这一步这次不测(不算通过)。' },
122
+ { label: '失败了', description: '照说明书做不出来 —— 说明书与实际不符。' },
123
+ ],
124
+ }],
125
+ }),
126
+ signal,
127
+ );
128
+ if (!result.ok) return 'aborted';
129
+ const label = String(result.content ?? '');
130
+ if (label.includes('做到了')) return 'passed';
131
+ if (label.includes('跳过')) return 'skipped';
132
+ if (label.includes('失败')) return 'failed';
133
+ return 'aborted';
134
+ }
135
+
136
+ /** 记下这一步执行后**实际看到的**现场。观测失败也如实写,不留空。 */
137
+ async function observeScene(signal?: AbortSignal): Promise<string> {
138
+ const response = await computerUseDiagnostics.observe(signal).catch(() => null);
139
+ if (!response?.ok || !response.state) {
140
+ return `观测失败(${response?.error?.code ?? 'unknown'})`;
141
+ }
142
+ const state = response.state;
143
+ const windows = state.windows.map((w) => w.title ?? '(无标题)').slice(0, 3).join(' / ');
144
+ return [
145
+ `前台 ${state.activeApp?.name ?? '未知'}(${state.activeApp?.id ?? '无标识'})`,
146
+ `窗口 ${windows || '无'}`,
147
+ `AX ${state.accessibility ? (state.accessibility.truncated ? '不完整' : '可用') : '无'}`,
148
+ ].join(' · ');
149
+ }
150
+
151
+ async function renderResult(input: {
152
+ source: ManualSource;
153
+ flows: ManualFlow[];
154
+ records: StepRecord[];
155
+ verifiedFlows: string[];
156
+ aborted: boolean;
157
+ signal?: AbortSignal;
158
+ }): Promise<string> {
159
+ const { source, records, verifiedFlows, aborted } = input;
160
+ const lines = [
161
+ `# 实机验收:${source.name}`,
162
+ '',
163
+ `说明书:${source.path}`,
164
+ aborted ? '⚠️ 验收被中止,下面只是已经走过的部分。' : '',
165
+ '',
166
+ '## 逐步结果',
167
+ '',
168
+ ].filter((line) => line !== '' || true);
169
+
170
+ if (records.length === 0) {
171
+ return [
172
+ `# 实机验收:${source.name}`,
173
+ '',
174
+ '没有可验收的流程 —— 声明的流程可能都已标记为已验证。',
175
+ '想重验请先把对应流程的 `verified` 改回 false。',
176
+ ].join('\n');
177
+ }
178
+
179
+ for (const record of records) {
180
+ const mark = record.verdict === 'passed' ? '✅'
181
+ : record.verdict === 'skipped' ? '⏭️'
182
+ : record.verdict === 'failed' ? '❌' : '⛔';
183
+ lines.push(`${mark} ${record.flowId} 第 ${record.index} 步:${record.step}`);
184
+ lines.push(` 实际观测:${record.scene}`);
185
+ }
186
+
187
+ lines.push(
188
+ '',
189
+ '## 结论',
190
+ '',
191
+ verifiedFlows.length > 0
192
+ ? `全部通过、可标记为已验证的流程:${verifiedFlows.join('、')}`
193
+ : '没有任何流程全部通过 —— 保持未验证。',
194
+ );
195
+
196
+ const notes = buildNotes(records, verifiedFlows);
197
+ const written = await computerUseDiagnostics.saveVerification(
198
+ { source, verifiedFlows, notes },
199
+ input.signal,
200
+ );
201
+ lines.push('', written.ok ? `✅ 已写入 ${written.path}` : `未写盘:${written.error}`);
202
+ if (!written.ok) {
203
+ lines.push('', '实测记录(可自己贴进说明书的 `## 实测记录` 一节):', '', ...notes);
204
+ }
205
+ return lines.join('\n');
206
+ }
207
+
208
+ /** 追加进 `## 实测记录` 的行。带日期,因为「上次能用这次不能」本身是信息。 */
209
+ function buildNotes(records: StepRecord[], verifiedFlows: string[]): string[] {
210
+ const day = new Date().toISOString().slice(0, 10);
211
+ const notes = [`- ${day} 实机验收:通过 ${verifiedFlows.join('、') || '(无)'}`];
212
+ for (const record of records.filter((item) => item.verdict !== 'passed')) {
213
+ notes.push(
214
+ ` - ${record.flowId} 第 ${record.index} 步(${record.verdict}):${record.step}`
215
+ + ` —— 当时 ${record.scene}`,
216
+ );
217
+ }
218
+ return notes;
219
+ }
@@ -0,0 +1,73 @@
1
+ /**
2
+ * plugins/computer_use/test/commands.test.ts
3
+ *
4
+ * 守两件事:
5
+ * ① `/computeruse` 与 `/cu` 都能路由到同一个 runCommand(别名不是摆设)
6
+ * ② 命令面**只读**:不平台依赖的子命令在任何机器上都给出可读输出,
7
+ * 且不会因为拿不到守护进程就抛异常
8
+ */
9
+
10
+ import { describe, expect, test } from 'bun:test';
11
+ import { readdirSync } from 'node:fs';
12
+ import { join } from 'node:path';
13
+
14
+ import { initWorkingDir } from '../../../src/bootstrap/workingDir.js';
15
+
16
+ initWorkingDir();
17
+
18
+ const { handleComputerUseCommand } = await import('../src/commands.js');
19
+
20
+ describe('computer-use 命令面', () => {
21
+ test('两个命令文件都存在 —— /cu 是声明出来的别名,不是隐式行为', () => {
22
+ const commands = readdirSync(join(import.meta.dir, '..', 'commands')).sort();
23
+ expect(commands).toEqual(['computeruse.md', 'cu.md']);
24
+ });
25
+
26
+ test('plugin.ts 对两个命令名都接管', async () => {
27
+ const api = (await import('../plugin.js')).default;
28
+ for (const name of ['computeruse', 'cu']) {
29
+ const events: unknown[] = [];
30
+ for await (const event of api.runCommand!(name, 'apps', {
31
+ provider: { baseURL: '', apiKey: '', model: '' } as never,
32
+ history: [],
33
+ })) {
34
+ events.push(event);
35
+ }
36
+ // 有实际输出,且以 turn_done 收尾(否则 UI 会一直等)
37
+ expect(events.length).toBeGreaterThan(1);
38
+ expect((events.at(-1) as { type: string }).type).toBe('turn_done');
39
+ }
40
+ });
41
+
42
+ test('未知子命令给出可用列表,而不是静默或抛错', async () => {
43
+ const out = await handleComputerUseCommand('nonsense');
44
+ expect(out).toContain('未知子命令');
45
+ expect(out).toContain('doctor');
46
+ });
47
+
48
+ test('apps 列出真实说明书,并如实报告拿不到前台应用', async () => {
49
+ const out = await handleComputerUseCommand('apps');
50
+ expect(out).toContain('wechat');
51
+ expect(out).toContain('当前前台应用');
52
+ });
53
+
54
+ test('app <name> 报告不可逆声明的可检查性 —— 不把 intent 说成拦截', async () => {
55
+ const out = await handleComputerUseCommand('app wechat');
56
+ // 显示的是**引擎实际用来匹配**的形式(loadGuides 统一小写化),
57
+ // 不是文件里的原始大小写 —— 诊断要照着引擎的眼睛看。
58
+ expect(out).toContain('com.tencent.xinwechat');
59
+ // 现状:微信的声明全是 intent 形式,必须如实说"拦不住"
60
+ expect(out).toContain('模型漏报就拦不住');
61
+ });
62
+
63
+ test('app 名字不存在时列出已有的,不静默', async () => {
64
+ const out = await handleComputerUseCommand('app 不存在的应用');
65
+ expect(out).toContain('已有:');
66
+ expect(out).toContain('finder');
67
+ });
68
+
69
+ test('report / audit 在没有任何记录时也不抛异常', async () => {
70
+ expect(typeof await handleComputerUseCommand('report')).toBe('string');
71
+ expect(await handleComputerUseCommand('audit 3')).toContain('最近 3 条');
72
+ });
73
+ });
@@ -0,0 +1,38 @@
1
+ import type { PluginApi, PluginRuntimeContext } from '../../src/plugin-sdk.js';
2
+ import { handleCronCommand } from './src/commands.js';
3
+ import { Scheduler } from './src/scheduler.js';
4
+ import { migrateCronTasks } from './src/store.js';
5
+
6
+ let scheduler: Scheduler | null = null;
7
+ let schedulerStop: Promise<void> | null = null;
8
+
9
+ export function getCronScheduler(): Scheduler | null {
10
+ return scheduler;
11
+ }
12
+
13
+ const api: PluginApi = {
14
+ async activate(ctx: PluginRuntimeContext) {
15
+ await migrateCronTasks();
16
+ await scheduler?.stop();
17
+ await schedulerStop;
18
+ const instance = new Scheduler(ctx);
19
+ scheduler = instance;
20
+ instance.start();
21
+ return () => {
22
+ if (scheduler === instance) scheduler = null;
23
+ let tracked: Promise<void>;
24
+ tracked = instance.stop().finally(() => {
25
+ if (schedulerStop === tracked) schedulerStop = null;
26
+ });
27
+ schedulerStop = tracked;
28
+ };
29
+ },
30
+
31
+ async *runCommand(commandName, args) {
32
+ const text = await handleCronCommand(commandName, args, scheduler);
33
+ yield { type: 'text', delta: text };
34
+ yield { type: 'turn_done' };
35
+ },
36
+ };
37
+
38
+ export default api;