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,163 @@
1
+ /**
2
+ * ============================================================
3
+ * vision/geometry.ts —— 坐标系(纯函数)
4
+ * ------------------------------------------------------------
5
+ * 整个 computer-use 只有**一个**对外坐标约定:
6
+ *
7
+ * 0–1000 相对值。左上 (0,0),右下 (1000,1000)。
8
+ *
9
+ * 照抄 MiniMax M3 在 OSWorld computer-use 评测里的设置。它一次性绕开了
10
+ * 三类真实事故:
11
+ * - macOS Retina:物理像素是逻辑点的 2 倍(scaleFactor=2),截图坐标
12
+ * 直接当鼠标坐标用会偏一半
13
+ * - Windows 显示缩放:进程若没声明 per-monitor DPI aware,125%/150% 下
14
+ * 系统会悄悄给缩放过的坐标,落点系统性偏移(第三方普遍踩这个坑)
15
+ * - 多显示器 / 换分辨率:apps/*.md 里写的位置描述若绑死像素就全废
16
+ *
17
+ * **物理换算只发生在本文件里。** 其它模块一律只见相对坐标。
18
+ * ============================================================
19
+ */
20
+
21
+ import type { Rect } from './raster.js';
22
+
23
+ /** 相对坐标空间的边长。取 1000 而非 100 是为了保留亚百分点精度(小控件需要)。 */
24
+ export const REL_SPAN = 1000;
25
+
26
+ export interface Point {
27
+ x: number;
28
+ y: number;
29
+ }
30
+
31
+ /** 逻辑点空间里的一块屏幕。 */
32
+ export interface Screen {
33
+ x: number;
34
+ y: number;
35
+ width: number;
36
+ height: number;
37
+ }
38
+
39
+ export interface Size {
40
+ width: number;
41
+ height: number;
42
+ }
43
+
44
+ /**
45
+ * scaleFactor = 物理像素 / 逻辑点。
46
+ * **必须实测算出,不能假设 1 或 2** —— 外接显示器、缩放设置、Sidecar
47
+ * 都会给出非整数或非 2 的值。
48
+ */
49
+ export function scaleFactor(physical: Size, logical: Size): number {
50
+ if (!logical.width) return 1;
51
+ return physical.width / logical.width;
52
+ }
53
+
54
+ /** 相对点 → 逻辑点(鼠标事件用的坐标系)。越界钳住而非报错:模型偶尔给 1000 或轻微越界。 */
55
+ export function relToLogical(rel: Point, screen: Screen): Point {
56
+ return {
57
+ x: screen.x + clamp((rel.x / REL_SPAN) * screen.width, 0, screen.width - 1),
58
+ y: screen.y + clamp((rel.y / REL_SPAN) * screen.height, 0, screen.height - 1),
59
+ };
60
+ }
61
+
62
+ /** 逻辑点 → 相对点(把 OS 报来的 caret/窗口位置翻译给模型看)。 */
63
+ export function logicalToRel(point: Point, screen: Screen): Point {
64
+ if (!screen.width || !screen.height) return { x: 0, y: 0 };
65
+ return {
66
+ x: Math.round(((point.x - screen.x) / screen.width) * REL_SPAN),
67
+ y: Math.round(((point.y - screen.y) / screen.height) * REL_SPAN),
68
+ };
69
+ }
70
+
71
+ /** 相对矩形 → 某张图上的像素矩形(图可以是任意缩放尺寸,故传 imageSize 而非 screen)。 */
72
+ export function relRectToPixels(rect: Rect, imageSize: Size): Rect {
73
+ const x = (rect.x / REL_SPAN) * imageSize.width;
74
+ const y = (rect.y / REL_SPAN) * imageSize.height;
75
+ return {
76
+ x: Math.round(x),
77
+ y: Math.round(y),
78
+ width: Math.max(1, Math.round((rect.width / REL_SPAN) * imageSize.width)),
79
+ height: Math.max(1, Math.round((rect.height / REL_SPAN) * imageSize.height)),
80
+ };
81
+ }
82
+
83
+ /** 像素矩形 → 相对矩形。 */
84
+ export function pixelRectToRel(rect: Rect, imageSize: Size): Rect {
85
+ if (!imageSize.width || !imageSize.height) return { x: 0, y: 0, width: 0, height: 0 };
86
+ return {
87
+ x: Math.round((rect.x / imageSize.width) * REL_SPAN),
88
+ y: Math.round((rect.y / imageSize.height) * REL_SPAN),
89
+ width: Math.round((rect.width / imageSize.width) * REL_SPAN),
90
+ height: Math.round((rect.height / imageSize.height) * REL_SPAN),
91
+ };
92
+ }
93
+
94
+ /**
95
+ * 向外扩边。变化区检出的包围盒往往刚好卡住控件边缘,裁出来会切掉半个按钮或
96
+ * 一圈阴影 —— 按比例外扩一圈(默认 20%)再裁,模型才看得到上下文。
97
+ */
98
+ export function padRect(rect: Rect, ratio = 0.2, bounds: Size | null = null): Rect {
99
+ const dx = rect.width * ratio;
100
+ const dy = rect.height * ratio;
101
+ const padded = {
102
+ x: rect.x - dx,
103
+ y: rect.y - dy,
104
+ width: rect.width + dx * 2,
105
+ height: rect.height + dy * 2,
106
+ };
107
+ return bounds ? clampRectTo(padded, bounds) : padded;
108
+ }
109
+
110
+ /** 钳进边界(bounds 用 {width, height},原点视为 0,0)。 */
111
+ export function clampRectTo(rect: Rect, bounds: Size): Rect {
112
+ const x = clamp(rect.x, 0, bounds.width - 1);
113
+ const y = clamp(rect.y, 0, bounds.height - 1);
114
+ return {
115
+ x,
116
+ y,
117
+ width: Math.max(1, Math.min(bounds.width - x, Math.round(rect.width))),
118
+ height: Math.max(1, Math.min(bounds.height - y, Math.round(rect.height))),
119
+ };
120
+ }
121
+
122
+ /** 两个矩形的最小外接矩形。 */
123
+ export function unionRect(a: Rect | null, b: Rect | null): Rect | null {
124
+ if (!a) return b;
125
+ if (!b) return a;
126
+ const x = Math.min(a.x, b.x);
127
+ const y = Math.min(a.y, b.y);
128
+ return {
129
+ x,
130
+ y,
131
+ width: Math.max(a.x + a.width, b.x + b.width) - x,
132
+ height: Math.max(a.y + a.height, b.y + b.height) - y,
133
+ };
134
+ }
135
+
136
+ /** 是否相交(用于判断「模型要点的地方」是否落在变化区里 —— epoch 陈旧性检查的核心)。 */
137
+ export function rectsIntersect(a: Rect, b: Rect): boolean {
138
+ return (
139
+ a.x < b.x + b.width &&
140
+ b.x < a.x + a.width &&
141
+ a.y < b.y + b.height &&
142
+ b.y < a.y + a.height
143
+ );
144
+ }
145
+
146
+ /** 点是否在矩形内。 */
147
+ export function pointInRect(point: Point, rect: Rect): boolean {
148
+ return (
149
+ point.x >= rect.x &&
150
+ point.x < rect.x + rect.width &&
151
+ point.y >= rect.y &&
152
+ point.y < rect.y + rect.height
153
+ );
154
+ }
155
+
156
+ export function clamp(value: number, min: number, max: number): number {
157
+ return Math.max(min, Math.min(max, Math.round(value)));
158
+ }
159
+
160
+ /** 人话描述一个相对矩形,供文本通道使用(比塞一张图便宜 20 倍)。 */
161
+ export function describeRelRect(rect: Rect): string {
162
+ return `(${rect.x},${rect.y})-(${rect.x + rect.width},${rect.y + rect.height})`;
163
+ }
@@ -0,0 +1,201 @@
1
+ /**
2
+ * ============================================================
3
+ * vision/imaging.ts —— 观测图组装(纯函数)
4
+ * ------------------------------------------------------------
5
+ * 把「像素」翻译成「模型看得懂、且付得起」的一组图。
6
+ *
7
+ * ★ 为什么不拼接成一张大图(这个方向已被算术否掉,别再走回去):
8
+ * provider 按**像素**计费而非按张数,且 1920×1080 与 3840×2160 到达模型时
9
+ * 尺寸与计费完全相同(都会被服务端降采样到同一档)。多图是一等公民
10
+ * (Claude 单请求 600 张),所以「一次回 N 张独立图、每张拿满分辨率」
11
+ * 严格优于「拼成九宫格/4K」。
12
+ *
13
+ * ★ 「概览 + ROI 裁剪」的组装(buildObservation)曾在这里,已删除。
14
+ * 它从未被任何生产路径调用,而它要解决的「看不清小字」现在由
15
+ * `observe { rect }` 在本机从完整原始帧裁出局部区域再缩放来解决 ——
16
+ * 更清晰(局部文字不会先随整屏缩小),同时保持模型输入只有一张图。
17
+ * 按项目的两次规则删掉,需要时 git 历史里有。
18
+ * ============================================================
19
+ */
20
+ import { ANNOTATION_COLOR, cloneImage, drawRect, fadeOutside, fitLongSide, } from './raster.js';
21
+ import { clampRectTo, describeRelRect, padRect, pixelRectToRel } from './geometry.js';
22
+ import { GLOBAL_CHANGE_RATIO, clusterChanges } from './frames.js';
23
+ /** 回放帧长边 —— 它回答「发生了什么」而非「写的什么」,做小是对的。 */
24
+ export const REPLAY_LONG_SIDE = 683;
25
+ /** 单帧最多标几块变化区。超过 3 块说明变化太散,该退化成全量了。 */
26
+ export const MAX_ROIS = 3;
27
+ /** 变化区外扩比例。包围盒常卡在控件边缘,不扩一圈会切掉半个按钮。 */
28
+ export const ROI_PAD_RATIO = 0.2;
29
+ /**
30
+ * 帧序列单帧的长边 = 720p。
31
+ *
32
+ * Claude:⌈1280/28⌉×⌈720/28⌉ = 46×26 = 1196 patch/帧,远在 1568 预算内,
33
+ * 因此**不会被服务端二次降采样**。比概览档的 1400 小一档是有意的:
34
+ * 帧序列一次给多张,单帧成本必须压住。
35
+ */
36
+ export const SEQUENCE_LONG_SIDE = 1280;
37
+ /** 默认帧数。3 帧覆盖 3 秒变化窗口。 */
38
+ export const SEQUENCE_FRAMES = 3;
39
+ /** 帧间隔(毫秒)。1Hz。 */
40
+ export const SEQUENCE_INTERVAL_MS = 1000;
41
+ /**
42
+ * 未变化区域保留的原色比例 = 0.3,即「70% 透明」。
43
+ *
44
+ * 必须是**合成到确定背景色**而不是 alpha 通道 —— 见 raster.ts::fadeOutside。
45
+ */
46
+ export const SEQUENCE_FADE_ALPHA = 0.3;
47
+ /**
48
+ * 组装 720p RGB 帧序列。
49
+ *
50
+ * 契约(与 SPEC §4.2 一致):
51
+ * [帧1] 关键帧:全量、100% 亮度、无遮罩
52
+ * [帧2..N] 变化帧:变化区域(外扩 20%)原色 100% 并用红框标注,
53
+ * 其余像素合成到白色至 30% 保留度
54
+ * 时序:正序,帧1 最早、帧N 最新 = 当前状态
55
+ *
56
+ * ★ 变化是**逐帧增量**(帧 i vs 帧 i−1),不是「相对关键帧的累计差」——
57
+ * 需求是「变化**过程**」,累计差会把早期变化一直重复标到最后一帧。
58
+ */
59
+ export function buildFrameSequence(args) {
60
+ const { frames: source, longSide = SEQUENCE_LONG_SIDE, fadeAlpha = SEQUENCE_FADE_ALPHA, padRatio = ROI_PAD_RATIO, maxRegionsPerFrame = MAX_ROIS, globalChangeRatio = GLOBAL_CHANGE_RATIO, } = args;
61
+ if (source.length === 0) {
62
+ return { frames: [], note: '(本次没有可用的画面帧。)', summary: ['无帧'] };
63
+ }
64
+ const scaled = source.map((f) => ({ t: f.t, image: fitLongSide(f.image, longSide) }));
65
+ const base = scaled[0];
66
+ const out = [{
67
+ index: 1,
68
+ t: base.t,
69
+ offsetSec: 0,
70
+ image: base.image,
71
+ changes: [],
72
+ degradedToFull: false,
73
+ }];
74
+ for (let i = 1; i < scaled.length; i += 1) {
75
+ const prev = scaled[i - 1];
76
+ const cur = scaled[i];
77
+ const bounds = { width: cur.image.width, height: cur.image.height };
78
+ const diff = diffRgba(prev.image, cur.image);
79
+ const degraded = diff.ratio >= globalChangeRatio;
80
+ // clusterChanges 吃时间线,这里把单次差分包成一个采样点复用同一套聚类逻辑,
81
+ // 避免帧序列与 settle 各写一份「相邻变化怎么合并」。
82
+ const timeline = diff.bbox
83
+ ? [{ t: cur.t, ratio: diff.ratio, bbox: diff.bbox }]
84
+ : [];
85
+ const regions = degraded
86
+ ? []
87
+ : clusterChanges(timeline, { maxClusters: maxRegionsPerFrame })
88
+ .map((rect) => clampRectTo(padRect(rect, padRatio, bounds), bounds));
89
+ const image = cloneImage(cur.image);
90
+ if (regions.length > 0) {
91
+ fadeOutside(image, regions, fadeAlpha);
92
+ const thickness = Math.max(2, Math.round(image.width / 400));
93
+ for (const rect of regions)
94
+ drawRect(image, rect, ANNOTATION_COLOR, thickness);
95
+ }
96
+ out.push({
97
+ index: i + 1,
98
+ t: cur.t,
99
+ offsetSec: Math.round((cur.t - base.t) / 100) / 10,
100
+ image,
101
+ changes: regions.map((r) => pixelRectToRel(r, bounds)),
102
+ degradedToFull: degraded,
103
+ });
104
+ }
105
+ const collapse = args.collapseWhenStatic ?? true;
106
+ const changedAtAll = out.some((f) => f.changes.length > 0 || f.degradedToFull);
107
+ const frames = collapse && !changedAtAll ? out.slice(0, 1) : out;
108
+ return {
109
+ frames,
110
+ note: buildSequenceNote(frames),
111
+ summary: summarizeSequence(frames),
112
+ };
113
+ }
114
+ /** 两张同尺寸 RGBA 的变化占比与包围盒(走亮度差,与灰度帧差同一判据)。 */
115
+ function diffRgba(a, b, threshold = 8) {
116
+ if (a.width !== b.width || a.height !== b.height)
117
+ return { ratio: 1, bbox: null };
118
+ let changed = 0;
119
+ let minX = Infinity;
120
+ let minY = Infinity;
121
+ let maxX = -1;
122
+ let maxY = -1;
123
+ for (let y = 0; y < b.height; y += 1) {
124
+ for (let x = 0; x < b.width; x += 1) {
125
+ const i = (y * b.width + x) * 4;
126
+ const la = (a.data[i] * 77 + a.data[i + 1] * 150 + a.data[i + 2] * 29) >> 8;
127
+ const lb = (b.data[i] * 77 + b.data[i + 1] * 150 + b.data[i + 2] * 29) >> 8;
128
+ if (Math.abs(la - lb) < threshold)
129
+ continue;
130
+ changed += 1;
131
+ if (x < minX)
132
+ minX = x;
133
+ if (x > maxX)
134
+ maxX = x;
135
+ if (y < minY)
136
+ minY = y;
137
+ if (y > maxY)
138
+ maxY = y;
139
+ }
140
+ }
141
+ const total = Math.max(1, b.width * b.height);
142
+ return {
143
+ ratio: changed / total,
144
+ bbox: maxX >= 0 ? { x: minX, y: minY, width: maxX - minX + 1, height: maxY - minY + 1 } : null,
145
+ };
146
+ }
147
+ /**
148
+ * 随图说明。
149
+ *
150
+ * ★ 末句「淡化 ≠ 禁用」是**必须的**:真实 UI 语义里变淡就是禁用/加载中,
151
+ * 不明说模型会把遮罩区描述成「灰显不可点击」并据此行动。
152
+ */
153
+ function buildSequenceNote(frames) {
154
+ if (frames.length === 1) {
155
+ return [
156
+ '以上是当前屏幕的完整画面(原色、未做任何遮罩)。',
157
+ '这段时间内屏幕没有发生变化,因此只附了一帧。',
158
+ '坐标一律用 0–1000 相对值。',
159
+ ].join('\n');
160
+ }
161
+ const n = frames.length;
162
+ return [
163
+ `以上 ${n} 张图是同一块屏幕的连续帧,间隔 1 秒,按时间正序(第 1 张最早,第 ${n} 张 = 当前状态)。`,
164
+ '第 1 张是关键帧:完整画面、原色。',
165
+ `第 2–${n} 张是变化过程:只有发生变化的区域保持原色并用红框标注,其余区域已淡化至 30%`,
166
+ '(淡化只表示「这里没变」,**不表示该控件被禁用或不可点击**)。',
167
+ '坐标一律用 0–1000 相对值。',
168
+ ].join('\n');
169
+ }
170
+ function summarizeSequence(frames) {
171
+ const lines = [`帧序列 ${frames.length} 张 · ${frames[0].image.width}×${frames[0].image.height}`];
172
+ for (const frame of frames) {
173
+ if (frame.index === 1) {
174
+ lines.push('第 1 帧(关键帧,+0.0s):完整画面');
175
+ continue;
176
+ }
177
+ if (frame.degradedToFull) {
178
+ lines.push(`第 ${frame.index} 帧(+${frame.offsetSec}s):整屏变化,已给完整画面`);
179
+ continue;
180
+ }
181
+ if (frame.changes.length === 0) {
182
+ lines.push(`第 ${frame.index} 帧(+${frame.offsetSec}s):无变化`);
183
+ continue;
184
+ }
185
+ lines.push(`第 ${frame.index} 帧(+${frame.offsetSec}s):变化区 ${frame.changes.map(describeRelRect).join('、')}`);
186
+ }
187
+ return lines;
188
+ }
189
+ /**
190
+ * 预算估算:粗略换算一张图在 provider 侧的 token 成本,供调用方在超预算时降级。
191
+ *
192
+ * 两家的公式不同,取**较大者**保守估计:
193
+ * Claude:⌈w/28⌉ × ⌈h/28⌉(上限 1568)
194
+ * OpenAI:85 + 170 × ⌈w/512⌉⌈h/512⌉(先塞进 2048、短边压到 768)
195
+ * 这只是本地的粗算,真实值以 provider 的 usage 为准。
196
+ */
197
+ export function estimateImageTokens(image) {
198
+ const claude = Math.ceil(image.width / 28) * Math.ceil(image.height / 28);
199
+ const openai = 85 + 170 * Math.ceil(image.width / 512) * Math.ceil(image.height / 512);
200
+ return Math.max(Math.min(claude, 1568), openai);
201
+ }
@@ -0,0 +1,281 @@
1
+ /**
2
+ * ============================================================
3
+ * vision/imaging.ts —— 观测图组装(纯函数)
4
+ * ------------------------------------------------------------
5
+ * 把「像素」翻译成「模型看得懂、且付得起」的一组图。
6
+ *
7
+ * ★ 为什么不拼接成一张大图(这个方向已被算术否掉,别再走回去):
8
+ * provider 按**像素**计费而非按张数,且 1920×1080 与 3840×2160 到达模型时
9
+ * 尺寸与计费完全相同(都会被服务端降采样到同一档)。多图是一等公民
10
+ * (Claude 单请求 600 张),所以「一次回 N 张独立图、每张拿满分辨率」
11
+ * 严格优于「拼成九宫格/4K」。
12
+ *
13
+ * ★ 「概览 + ROI 裁剪」的组装(buildObservation)曾在这里,已删除。
14
+ * 它从未被任何生产路径调用,而它要解决的「看不清小字」现在由
15
+ * `observe { rect }` 在本机从完整原始帧裁出局部区域再缩放来解决 ——
16
+ * 更清晰(局部文字不会先随整屏缩小),同时保持模型输入只有一张图。
17
+ * 按项目的两次规则删掉,需要时 git 历史里有。
18
+ * ============================================================
19
+ */
20
+
21
+ import {
22
+ ANNOTATION_COLOR,
23
+ type Rect,
24
+ cloneImage,
25
+ drawRect,
26
+ fadeOutside,
27
+ fitLongSide,
28
+ } from './raster.js';
29
+ import { clampRectTo, describeRelRect, padRect, pixelRectToRel } from './geometry.js';
30
+ import { GLOBAL_CHANGE_RATIO, type TimelinePoint, clusterChanges } from './frames.js';
31
+ import type { RgbaImage } from './png.js';
32
+
33
+ /** 回放帧长边 —— 它回答「发生了什么」而非「写的什么」,做小是对的。 */
34
+ export const REPLAY_LONG_SIDE = 683;
35
+
36
+ /** 单帧最多标几块变化区。超过 3 块说明变化太散,该退化成全量了。 */
37
+ export const MAX_ROIS = 3;
38
+
39
+ /** 变化区外扩比例。包围盒常卡在控件边缘,不扩一圈会切掉半个按钮。 */
40
+ export const ROI_PAD_RATIO = 0.2;
41
+
42
+ /**
43
+ * 帧序列单帧的长边 = 720p。
44
+ *
45
+ * Claude:⌈1280/28⌉×⌈720/28⌉ = 46×26 = 1196 patch/帧,远在 1568 预算内,
46
+ * 因此**不会被服务端二次降采样**。比概览档的 1400 小一档是有意的:
47
+ * 帧序列一次给多张,单帧成本必须压住。
48
+ */
49
+ export const SEQUENCE_LONG_SIDE = 1280;
50
+
51
+ /** 默认帧数。3 帧覆盖 3 秒变化窗口。 */
52
+ export const SEQUENCE_FRAMES = 3;
53
+
54
+ /** 帧间隔(毫秒)。1Hz。 */
55
+ export const SEQUENCE_INTERVAL_MS = 1000;
56
+
57
+ /**
58
+ * 未变化区域保留的原色比例 = 0.3,即「70% 透明」。
59
+ *
60
+ * 必须是**合成到确定背景色**而不是 alpha 通道 —— 见 raster.ts::fadeOutside。
61
+ */
62
+ export const SEQUENCE_FADE_ALPHA = 0.3;
63
+
64
+ // ============================================================
65
+ // 帧序列
66
+ // ============================================================
67
+
68
+ export interface SequenceSourceFrame {
69
+ /** 采样时刻(毫秒) */
70
+ t: number;
71
+ image: RgbaImage;
72
+ }
73
+
74
+ export interface SequenceFrame {
75
+ index: number;
76
+ t: number;
77
+ /** 相对首帧的秒数,供文案使用 */
78
+ offsetSec: number;
79
+ image: RgbaImage;
80
+ /** 本帧相对前一帧的变化区(相对坐标 0–1000);关键帧为空 */
81
+ changes: Rect[];
82
+ /** 本帧变化过大而退化成全量 */
83
+ degradedToFull: boolean;
84
+ }
85
+
86
+ export interface FrameSequence {
87
+ frames: SequenceFrame[];
88
+ /** 随图发给模型的说明。帧数是变量,文案按实际帧数生成。 */
89
+ note: string;
90
+ summary: string[];
91
+ }
92
+
93
+ export interface BuildFrameSequenceArgs {
94
+ /** 按时间**正序**(最早在前)。 */
95
+ frames: SequenceSourceFrame[];
96
+ longSide?: number;
97
+ fadeAlpha?: number;
98
+ padRatio?: number;
99
+ maxRegionsPerFrame?: number;
100
+ /** 变化占比超过它,该帧退化成全量(整屏都变了,遮罩无意义) */
101
+ globalChangeRatio?: number;
102
+ /**
103
+ * 全程无变化时只保留关键帧。默认开启。
104
+ *
105
+ * 不开的话,静态屏幕会得到 N 张**一模一样**的全量图 —— 付 N 倍的 token
106
+ * 买零信息。这正是「注意力」的本意:有变化才值得多看几眼。
107
+ */
108
+ collapseWhenStatic?: boolean;
109
+ }
110
+
111
+ /**
112
+ * 组装 720p RGB 帧序列。
113
+ *
114
+ * 契约(与 SPEC §4.2 一致):
115
+ * [帧1] 关键帧:全量、100% 亮度、无遮罩
116
+ * [帧2..N] 变化帧:变化区域(外扩 20%)原色 100% 并用红框标注,
117
+ * 其余像素合成到白色至 30% 保留度
118
+ * 时序:正序,帧1 最早、帧N 最新 = 当前状态
119
+ *
120
+ * ★ 变化是**逐帧增量**(帧 i vs 帧 i−1),不是「相对关键帧的累计差」——
121
+ * 需求是「变化**过程**」,累计差会把早期变化一直重复标到最后一帧。
122
+ */
123
+ export function buildFrameSequence(args: BuildFrameSequenceArgs): FrameSequence {
124
+ const {
125
+ frames: source,
126
+ longSide = SEQUENCE_LONG_SIDE,
127
+ fadeAlpha = SEQUENCE_FADE_ALPHA,
128
+ padRatio = ROI_PAD_RATIO,
129
+ maxRegionsPerFrame = MAX_ROIS,
130
+ globalChangeRatio = GLOBAL_CHANGE_RATIO,
131
+ } = args;
132
+
133
+ if (source.length === 0) {
134
+ return { frames: [], note: '(本次没有可用的画面帧。)', summary: ['无帧'] };
135
+ }
136
+
137
+ const scaled = source.map((f) => ({ t: f.t, image: fitLongSide(f.image, longSide) }));
138
+ const base = scaled[0]!;
139
+ const out: SequenceFrame[] = [{
140
+ index: 1,
141
+ t: base.t,
142
+ offsetSec: 0,
143
+ image: base.image,
144
+ changes: [],
145
+ degradedToFull: false,
146
+ }];
147
+
148
+ for (let i = 1; i < scaled.length; i += 1) {
149
+ const prev = scaled[i - 1]!;
150
+ const cur = scaled[i]!;
151
+ const bounds = { width: cur.image.width, height: cur.image.height };
152
+ const diff = diffRgba(prev.image, cur.image);
153
+ const degraded = diff.ratio >= globalChangeRatio;
154
+
155
+ // clusterChanges 吃时间线,这里把单次差分包成一个采样点复用同一套聚类逻辑,
156
+ // 避免帧序列与 settle 各写一份「相邻变化怎么合并」。
157
+ const timeline: TimelinePoint[] = diff.bbox
158
+ ? [{ t: cur.t, ratio: diff.ratio, bbox: diff.bbox }]
159
+ : [];
160
+ const regions = degraded
161
+ ? []
162
+ : clusterChanges(timeline, { maxClusters: maxRegionsPerFrame })
163
+ .map((rect) => clampRectTo(padRect(rect, padRatio, bounds), bounds));
164
+
165
+ const image = cloneImage(cur.image);
166
+ if (regions.length > 0) {
167
+ fadeOutside(image, regions, fadeAlpha);
168
+ const thickness = Math.max(2, Math.round(image.width / 400));
169
+ for (const rect of regions) drawRect(image, rect, ANNOTATION_COLOR, thickness);
170
+ }
171
+
172
+ out.push({
173
+ index: i + 1,
174
+ t: cur.t,
175
+ offsetSec: Math.round((cur.t - base.t) / 100) / 10,
176
+ image,
177
+ changes: regions.map((r) => pixelRectToRel(r, bounds)),
178
+ degradedToFull: degraded,
179
+ });
180
+ }
181
+
182
+ const collapse = args.collapseWhenStatic ?? true;
183
+ const changedAtAll = out.some((f) => f.changes.length > 0 || f.degradedToFull);
184
+ const frames = collapse && !changedAtAll ? out.slice(0, 1) : out;
185
+
186
+ return {
187
+ frames,
188
+ note: buildSequenceNote(frames),
189
+ summary: summarizeSequence(frames),
190
+ };
191
+ }
192
+
193
+ /** 两张同尺寸 RGBA 的变化占比与包围盒(走亮度差,与灰度帧差同一判据)。 */
194
+ function diffRgba(a: RgbaImage, b: RgbaImage, threshold = 8): { ratio: number; bbox: Rect | null } {
195
+ if (a.width !== b.width || a.height !== b.height) return { ratio: 1, bbox: null };
196
+ let changed = 0;
197
+ let minX = Infinity;
198
+ let minY = Infinity;
199
+ let maxX = -1;
200
+ let maxY = -1;
201
+
202
+ for (let y = 0; y < b.height; y += 1) {
203
+ for (let x = 0; x < b.width; x += 1) {
204
+ const i = (y * b.width + x) * 4;
205
+ const la = (a.data[i]! * 77 + a.data[i + 1]! * 150 + a.data[i + 2]! * 29) >> 8;
206
+ const lb = (b.data[i]! * 77 + b.data[i + 1]! * 150 + b.data[i + 2]! * 29) >> 8;
207
+ if (Math.abs(la - lb) < threshold) continue;
208
+ changed += 1;
209
+ if (x < minX) minX = x;
210
+ if (x > maxX) maxX = x;
211
+ if (y < minY) minY = y;
212
+ if (y > maxY) maxY = y;
213
+ }
214
+ }
215
+
216
+ const total = Math.max(1, b.width * b.height);
217
+ return {
218
+ ratio: changed / total,
219
+ bbox: maxX >= 0 ? { x: minX, y: minY, width: maxX - minX + 1, height: maxY - minY + 1 } : null,
220
+ };
221
+ }
222
+
223
+ /**
224
+ * 随图说明。
225
+ *
226
+ * ★ 末句「淡化 ≠ 禁用」是**必须的**:真实 UI 语义里变淡就是禁用/加载中,
227
+ * 不明说模型会把遮罩区描述成「灰显不可点击」并据此行动。
228
+ */
229
+ function buildSequenceNote(frames: SequenceFrame[]): string {
230
+ if (frames.length === 1) {
231
+ return [
232
+ '以上是当前屏幕的完整画面(原色、未做任何遮罩)。',
233
+ '这段时间内屏幕没有发生变化,因此只附了一帧。',
234
+ '坐标一律用 0–1000 相对值。',
235
+ ].join('\n');
236
+ }
237
+ const n = frames.length;
238
+ return [
239
+ `以上 ${n} 张图是同一块屏幕的连续帧,间隔 1 秒,按时间正序(第 1 张最早,第 ${n} 张 = 当前状态)。`,
240
+ '第 1 张是关键帧:完整画面、原色。',
241
+ `第 2–${n} 张是变化过程:只有发生变化的区域保持原色并用红框标注,其余区域已淡化至 30%`,
242
+ '(淡化只表示「这里没变」,**不表示该控件被禁用或不可点击**)。',
243
+ '坐标一律用 0–1000 相对值。',
244
+ ].join('\n');
245
+ }
246
+
247
+ function summarizeSequence(frames: SequenceFrame[]): string[] {
248
+ const lines = [`帧序列 ${frames.length} 张 · ${frames[0]!.image.width}×${frames[0]!.image.height}`];
249
+ for (const frame of frames) {
250
+ if (frame.index === 1) {
251
+ lines.push('第 1 帧(关键帧,+0.0s):完整画面');
252
+ continue;
253
+ }
254
+ if (frame.degradedToFull) {
255
+ lines.push(`第 ${frame.index} 帧(+${frame.offsetSec}s):整屏变化,已给完整画面`);
256
+ continue;
257
+ }
258
+ if (frame.changes.length === 0) {
259
+ lines.push(`第 ${frame.index} 帧(+${frame.offsetSec}s):无变化`);
260
+ continue;
261
+ }
262
+ lines.push(
263
+ `第 ${frame.index} 帧(+${frame.offsetSec}s):变化区 ${frame.changes.map(describeRelRect).join('、')}`,
264
+ );
265
+ }
266
+ return lines;
267
+ }
268
+
269
+ /**
270
+ * 预算估算:粗略换算一张图在 provider 侧的 token 成本,供调用方在超预算时降级。
271
+ *
272
+ * 两家的公式不同,取**较大者**保守估计:
273
+ * Claude:⌈w/28⌉ × ⌈h/28⌉(上限 1568)
274
+ * OpenAI:85 + 170 × ⌈w/512⌉⌈h/512⌉(先塞进 2048、短边压到 768)
275
+ * 这只是本地的粗算,真实值以 provider 的 usage 为准。
276
+ */
277
+ export function estimateImageTokens(image: Pick<RgbaImage, 'width' | 'height'>): number {
278
+ const claude = Math.ceil(image.width / 28) * Math.ceil(image.height / 28);
279
+ const openai = 85 + 170 * Math.ceil(image.width / 512) * Math.ceil(image.height / 512);
280
+ return Math.max(Math.min(claude, 1568), openai);
281
+ }