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,189 @@
1
+ /**
2
+ * ============================================================
3
+ * src/ui/liveViewport.ts —— LiveArea 有界多行 live 区的宽度安全工具(纯函数)
4
+ * ------------------------------------------------------------
5
+ * ★ 两条硬不变量(根治 Windows 终端"思维链刷屏",缺一不可):
6
+ *
7
+ * Ink 默认 render 在主屏 scrollback 上用 log-update 维护**底部 live 区**:
8
+ * 每帧 `eraseLines(上一帧 \n 数)`(光标上移逐行清)再重写。两个坑都会让上移清除"漏擦":
9
+ *
10
+ * ┌─ INV-1 每行物理宽度 < 终端宽 ──────────────────────────────┐
11
+ * │ stock ink `log-update.js` 用 `output.split('\n').length` 记账, │
12
+ * │ **完全不补偿满宽行被终端自动折行**。若某行物理宽触到终端最后一列, │
13
+ * │ 终端自己折一行 → 实际物理行 > ink 记的 \n 数 → eraseLines 擦少 → │
14
+ * │ 它上面的行每帧 strand 进 scrollback = 刷屏。 │
15
+ * │ ∴ live 区每一行都按**我们自己的** displayWidth(CJK/全角/emoji=2, │
16
+ * │ 宁宽不窄)预钳到 ≤ cols - LIVE_RIGHT_MARGIN 再交给 ink。不依赖 │
17
+ * │ ink 的字宽测量 → 终端永不折行 → \n 记账 == 物理行 → 精确擦除。 │
18
+ * └────────────────────────────────────────────────────────┘
19
+ * ┌─ INV-2 live 区总高度 < 终端行数 ──────────────────────────┐
20
+ * │ `ink.js` onRender:一旦 outputHeight >= stdout.rows 会**全屏 │
21
+ * │ clearTerminal 重写**(含整个 static),灾难性。∴ 流式内容预览必须 │
22
+ * │ 有界(取尾部最近 N 行,N 自适应终端高度,见 LiveArea.contentMaxLines)。│
23
+ * └────────────────────────────────────────────────────────┘
24
+ *
25
+ * 完整思维链 / 完整答案 / 完整工具结果一律走 `<Static>`(write-once,永不
26
+ * 参与 log-update → 天然 strand-proof、高度不受限)。live 区只放**有界**的过程预览。
27
+ *
28
+ * ★ 中文/emoji 宽度(关键,别退化成按码点切):
29
+ * CJK / 全角 / emoji 1 码点 = 2 列。宽度必须按 charWidth 累加,不能按 length,
30
+ * 否则这些字符实际占 2× 列宽被算窄、钳不住 → 终端折行 → INV-1 失守、刷屏复发。
31
+ * ============================================================
32
+ */
33
+
34
+ /** live 行右侧安全余量(列):钳到 cols - 此值,吃掉光标在"恰好满宽"处的自动折行边界。 */
35
+ export const LIVE_RIGHT_MARGIN = 2;
36
+
37
+ /** 剥离 ANSI/CSI 控制序列(含 ESC 引导符)。流式文本理论上没有,做防御性清理。 */
38
+ const ANSI_RE = new RegExp('\\u001b\\[[0-9;?]*[ -/]*[@-~]', 'g');
39
+
40
+ /**
41
+ * 单个 Unicode 码点的终端显示宽度:CJK / 全角 / emoji = 2,其余 = 1。
42
+ *
43
+ * 设计目标是做终端实际宽度的**上界估计**(宁可算宽、不可算窄):算宽只会让行
44
+ * 提前一两列截断(无害),算窄则会让钳制失效、终端折行(= 刷屏复发,INV-1 失守)。
45
+ *
46
+ * 覆盖:
47
+ * - 常见 East Asian Ambiguous 标点(…—–·“”‘’ 等):CJK 终端按全角(2)渲染,
48
+ * 这些是中文文本里最容易把行顶宽的"隐形 2 列"字符,统一按 2 计。
49
+ * - Emoji / 符号 / dingbat(💭✶ 等):终端普遍按全角(2)渲染。注意 charWidth 是
50
+ * 逐码点求和,ZWJ/变体序列会被算成各组件之和(偏大 = 安全方向)。
51
+ * - Hangul Jamo / CJK 部首笔画符号标点 / 假名 / CJK 统一 / 谚文音节 /
52
+ * 兼容表意 / 竖排标点 / 全角 ASCII 与符号 / CJK 扩展 B+(星平面)。
53
+ */
54
+ export function charWidth(cp: number): 1 | 2 {
55
+ // 常见 ambiguous-width 标点:CJK 终端按 2 列渲染,统一上界为 2 防折行
56
+ if (
57
+ cp === 0x00b7 || // ·
58
+ cp === 0x2013 || // –
59
+ cp === 0x2014 || // —
60
+ cp === 0x2018 || // ‘
61
+ cp === 0x2019 || // ’
62
+ cp === 0x201c || // “
63
+ cp === 0x201d || // ”
64
+ cp === 0x2026 || // …
65
+ cp === 0x203b // ※
66
+ ) {
67
+ return 2;
68
+ }
69
+ // Emoji / 符号 / dingbat:终端普遍全角渲染(含 💭 与 spinner ✶✷✸✹✺)。上界=2,算宽无害。
70
+ // 0x2300/0x2500 两段是蜂群树引入的 ⎿ ├ └ │ ─(figures.ts)——ambiguous-width,
71
+ // CJK 终端可能按全角渲染,按「宁宽不窄」哲学一并按 2 计(INV-1 记账依赖此上界)。
72
+ if (
73
+ (cp >= 0x2300 && cp <= 0x23ff) || // Misc Technical(含 ⎿ U+23BF)
74
+ (cp >= 0x2500 && cp <= 0x25ff) || // Box Drawing / Block Elements / Geometric(├ └ │ ─ ▾ ▶)
75
+ (cp >= 0x2600 && cp <= 0x27bf) || // Misc Symbols + Dingbats(含 ✶✷✸✹✺)
76
+ (cp >= 0x2b00 && cp <= 0x2bff) || // Misc Symbols and Arrows
77
+ (cp >= 0xfe00 && cp <= 0xfe0f) || // Variation Selectors(VS16 强制全角)
78
+ (cp >= 0x1f000 && cp <= 0x1faff) // Emoji 主区(含 💭)
79
+ ) {
80
+ return 2;
81
+ }
82
+ if (
83
+ cp >= 0x1100 &&
84
+ (cp <= 0x115f ||
85
+ (cp >= 0x2e80 && cp <= 0x303e) ||
86
+ (cp >= 0x3041 && cp <= 0xa4cf) ||
87
+ (cp >= 0xac00 && cp <= 0xd7a3) ||
88
+ (cp >= 0xf900 && cp <= 0xfaff) ||
89
+ (cp >= 0xfe10 && cp <= 0xfe6f) ||
90
+ (cp >= 0xff00 && cp <= 0xff60) ||
91
+ (cp >= 0xffe0 && cp <= 0xffe6) ||
92
+ (cp >= 0x20000 && cp <= 0x3fffd))
93
+ ) {
94
+ return 2;
95
+ }
96
+ return 1;
97
+ }
98
+
99
+ /** 一段文本的显示宽度(按 charWidth 累加;不破坏 surrogate pair)。 */
100
+ export function displayWidth(text: string): number {
101
+ let w = 0;
102
+ for (const ch of text) {
103
+ w += charWidth(ch.codePointAt(0) ?? 0);
104
+ }
105
+ return w;
106
+ }
107
+
108
+ /**
109
+ * 标准化流式文本:CRLF/CR → LF、剥离 ANSI、收敛尾部多余空行。
110
+ */
111
+ export function normalizeLiveText(text: string): string {
112
+ return text
113
+ .replace(/\r\n?/g, '\n')
114
+ .replace(ANSI_RE, '')
115
+ .replace(/\n+$/g, '');
116
+ }
117
+
118
+ /**
119
+ * 取**前缀**:保留从头开始、显示宽度 ≤ maxWidth 的最长前缀(不破坏 surrogate pair)。
120
+ * 用于状态行的单行宽度钳制(保住最重要的行首 glyph/阶段,多余的尾部丢弃)。
121
+ */
122
+ export function clampWidthStart(text: string, maxWidth: number): string {
123
+ if (maxWidth <= 0) return '';
124
+ let w = 0;
125
+ let out = '';
126
+ for (const ch of text) {
127
+ const cw = charWidth(ch.codePointAt(0) ?? 0);
128
+ if (w + cw > maxWidth) break;
129
+ out += ch;
130
+ w += cw;
131
+ }
132
+ return out;
133
+ }
134
+
135
+ /**
136
+ * 把(可能多行的)流式文本硬换行成**显示行数组**,每行显示宽度 ≤ maxWidth(满足 INV-1)。
137
+ *
138
+ * 规则:
139
+ * - 先按原始 `\n` 切段落(保留空行 → 输出空字符串行)。
140
+ * - 段落内贪心累加:超过 maxWidth 时,优先在**最近一个空格**处断行(word-aware,
141
+ * 英文不切断单词);没有空格(如中文)则按字符硬断。
142
+ * - 全程按 charWidth(CJK/全角/emoji=2)计宽,绝不按 length。
143
+ *
144
+ * 这是"打字机多行"的核心:reasoning / 答案的长文本在这里被切成等宽窄行,
145
+ * 再由 LiveArea 取尾部最近 N 行(满足 INV-2)。
146
+ *
147
+ * 导出供单测断言。
148
+ */
149
+ export function wrapToDisplayLines(text: string, maxWidth: number): string[] {
150
+ if (maxWidth <= 0) return [];
151
+ const normalized = normalizeLiveText(text);
152
+ const out: string[] = [];
153
+
154
+ for (const para of normalized.split('\n')) {
155
+ if (para.length === 0) {
156
+ out.push('');
157
+ continue;
158
+ }
159
+ let line = '';
160
+ let lineWidth = 0;
161
+ let lastSpace = -1; // line 内最近一个空格的下标(断行机会)
162
+
163
+ for (const ch of para) {
164
+ const cw = charWidth(ch.codePointAt(0) ?? 0);
165
+ // 超宽且当前行非空 → 先断行再放入 ch
166
+ if (lineWidth + cw > maxWidth && line.length > 0) {
167
+ if (lastSpace >= 0 && lastSpace < line.length - 1) {
168
+ // 在最近空格处断:head 不含该空格,余下部分(不含空格)顺延到下一行
169
+ const head = line.slice(0, lastSpace);
170
+ const rest = line.slice(lastSpace + 1);
171
+ out.push(head);
172
+ line = rest;
173
+ lineWidth = displayWidth(rest);
174
+ } else {
175
+ out.push(line);
176
+ line = '';
177
+ lineWidth = 0;
178
+ }
179
+ lastSpace = -1;
180
+ }
181
+ line += ch;
182
+ lineWidth += cw;
183
+ if (ch === ' ') lastSpace = line.length - 1;
184
+ }
185
+ out.push(line);
186
+ }
187
+
188
+ return out;
189
+ }
@@ -0,0 +1,230 @@
1
+ /**
2
+ * ============================================================
3
+ * src/ui/markdown.ts —— assistant 最终答案的 markdown → 终端展示行
4
+ * ------------------------------------------------------------
5
+ * 借鉴 Claude Code 的管线(marked lexer 分词 + 自研 token→ANSI 格式化),
6
+ * 按 minimal-agent 减法原则收敛。核心裁决:
7
+ *
8
+ * ★ 代码块「零装饰」(复制即用的全部保障):
9
+ * `code` token 的每一行 = 原文逐字节输出——无边框、无背景、无缩进、无前缀、
10
+ * 不按宽度重排;渲染层配 wrap='end'(Ink 原样输出,不注入换行),超宽交给
11
+ * 终端软换行(现代终端复制时还原为整行)。任何"美化"都会污染复制。
12
+ *
13
+ * ★ 删除线主动禁用:模型常用 ~xxx~ 表示"约等于",渲染成删除线是灾难
14
+ * (捐赠方同款裁决),del token 原样输出 raw。
15
+ *
16
+ * ★ 只在 <Static> commit 时调用(write-once,每条消息一生解析一次,
17
+ * <1ms 无重解析压力);live 流式区不跑 markdown。
18
+ *
19
+ * 已知取舍:
20
+ * - dim 与 bold 的 SGR 关闭码同为 22,嵌套会提前关闭外层——本文件不在
21
+ * bold 内嵌 dim(捐赠方同样接受此约束)。
22
+ * - 超过终端宽度的 code 行交终端软换行显示(视觉上折行、复制仍是整行);
23
+ * TODO:后续可为超宽 code 提供 /show 式展开。
24
+ * - 表格第一期不做 flexbox 对齐,token.raw 原样透传(终端裸文本可读);
25
+ * TODO:需要时参照捐赠方 MarkdownTable 组件。
26
+ * ============================================================
27
+ */
28
+
29
+ import { lexer, type Token, type Tokens } from 'marked';
30
+ import { figures } from './figures.js';
31
+
32
+ // ---------------- ANSI 内联样式(手写 SGR,不引 chalk) ----------------
33
+ // Ink 的 Text 渲染管线(wrap-ansi / cli-truncate)是 ANSI-aware 的,
34
+ // 字符串内嵌 SGR 与 wrap='end' 兼容(捐赠方同款做法)。
35
+ const sgr = (open: number, close: number) => (s: string) => `\x1b[${open}m${s}\x1b[${close}m`;
36
+ const bold = sgr(1, 22);
37
+ const italic = sgr(3, 23);
38
+ const underline = sgr(4, 24);
39
+ const dim = sgr(2, 22);
40
+ const cyan = sgr(36, 39);
41
+
42
+ export type MdLineKind =
43
+ /** 普通文字行(可含 ANSI 内联样式;渲染层加 ⏺/缩进前缀) */
44
+ | 'prose'
45
+ /** 代码行 = 原文逐字节(渲染层零前缀零染色,复制安全断言点) */
46
+ | 'code'
47
+ /** ``` 围栏行(渲染层染 dim,与代码本体区分) */
48
+ | 'fence';
49
+
50
+ export interface MdLine {
51
+ text: string;
52
+ kind: MdLineKind;
53
+ }
54
+
55
+ /**
56
+ * 快判:文本里没有任何 markdown 语法特征 → 跳过 lexer,直接按 \n 切 prose
57
+ * (旧行为快路径;也避免纯中文叙述被 lexer 意外重排)。
58
+ */
59
+ export function looksLikeMarkdown(text: string): boolean {
60
+ return (
61
+ /(^|\n)\s{0,3}(#{1,6}\s|```|>\s|[-*+]\s|\d+\.\s|(-{3,}|\*{3,})\s*(\n|$))/.test(text) || // 块级:标题/围栏/引用/列表/hr
62
+ /`[^`\n]+`|\*\*[^*\n]+\*\*|\[[^\]\n]+\]\([^)\n]+\)/.test(text) // 行内:codespan/加粗/链接
63
+ );
64
+ }
65
+
66
+ /**
67
+ * marked tokenizer 对 codespan/escape/text 做 HTML 实体转义
68
+ * (`a && b` → 'a &amp;&amp; b')——终端不是 HTML,必须还原。
69
+ * 注意 &amp; 最后替换(否则 &amp;lt; 会被二次解码)。
70
+ */
71
+ export function unescapeEntities(text: string): string {
72
+ return text
73
+ .replace(/&lt;/g, '<')
74
+ .replace(/&gt;/g, '>')
75
+ .replace(/&quot;/g, '"')
76
+ .replace(/&#39;/g, "'")
77
+ .replace(/&amp;/g, '&');
78
+ }
79
+
80
+ /** 行内 tokens → 单条含 ANSI 的字符串。 */
81
+ export function formatInlineTokens(tokens: Token[]): string {
82
+ let out = '';
83
+ for (const token of tokens) {
84
+ switch (token.type) {
85
+ case 'strong':
86
+ out += bold(formatInlineTokens((token as Tokens.Strong).tokens));
87
+ break;
88
+ case 'em':
89
+ out += italic(formatInlineTokens((token as Tokens.Em).tokens));
90
+ break;
91
+ case 'codespan':
92
+ out += cyan(unescapeEntities((token as Tokens.Codespan).text));
93
+ break;
94
+ case 'del':
95
+ // 删除线禁用:~xxx~ 常是"约等于",原样输出
96
+ out += (token as Tokens.Del).raw;
97
+ break;
98
+ case 'link': {
99
+ const link = token as Tokens.Link;
100
+ const label = link.tokens ? formatInlineTokens(link.tokens) : link.text;
101
+ out += label === link.href ? label : `${label} ${dim(`(${link.href})`)}`;
102
+ break;
103
+ }
104
+ case 'image':
105
+ out += `[图: ${(token as Tokens.Image).text}]`;
106
+ break;
107
+ case 'br':
108
+ out += '\n';
109
+ break;
110
+ case 'escape':
111
+ out += unescapeEntities((token as Tokens.Escape).text);
112
+ break;
113
+ case 'text': {
114
+ const t = token as Tokens.Text;
115
+ out += t.tokens ? formatInlineTokens(t.tokens) : unescapeEntities(t.text);
116
+ break;
117
+ }
118
+ default:
119
+ out += 'raw' in token ? (token as { raw: string }).raw : '';
120
+ break;
121
+ }
122
+ }
123
+ return out;
124
+ }
125
+
126
+ /** 把(可能含 ANSI 的)多行字符串切成 prose 行。 */
127
+ function proseLines(text: string): MdLine[] {
128
+ return text.split('\n').map((line) => ({ text: line, kind: 'prose' as const }));
129
+ }
130
+
131
+ /** 单个块级 token → 展示行(导出供单测逐 token 断言)。 */
132
+ export function formatBlockToken(token: Token): MdLine[] {
133
+ switch (token.type) {
134
+ case 'code': {
135
+ // ★ 复制安全核心路径:代码行 = token.text 逐字节,围栏行单独标 kind
136
+ const code = token as Tokens.Code;
137
+ return [
138
+ { text: `\`\`\`${code.lang ?? ''}`, kind: 'fence' },
139
+ ...code.text.split('\n').map((line) => ({ text: line, kind: 'code' as const })),
140
+ { text: '```', kind: 'fence' },
141
+ ];
142
+ }
143
+ case 'heading': {
144
+ const heading = token as Tokens.Heading;
145
+ const inner = formatInlineTokens(heading.tokens);
146
+ return [{ text: heading.depth === 1 ? bold(underline(inner)) : bold(inner), kind: 'prose' }];
147
+ }
148
+ case 'paragraph':
149
+ return proseLines(formatInlineTokens((token as Tokens.Paragraph).tokens));
150
+ case 'list': {
151
+ const list = token as Tokens.List;
152
+ const lines: MdLine[] = [];
153
+ const start = typeof list.start === 'number' ? list.start : 1;
154
+ list.items.forEach((item, i) => {
155
+ const bullet = list.ordered ? `${start + i}. ` : '- ';
156
+ const pad = ' '.repeat(bullet.length);
157
+ let firstLineDone = false;
158
+ for (const sub of item.tokens) {
159
+ if (sub.type === 'code') {
160
+ // 列表内代码块:零装饰优先于列表对齐(不缩进,保住复制安全)
161
+ lines.push(...formatBlockToken(sub));
162
+ continue;
163
+ }
164
+ if (sub.type === 'list') {
165
+ // 嵌套列表:整体缩进对齐父 bullet(不走 firstLine 逻辑,避免双重缩进)
166
+ lines.push(
167
+ ...formatBlockToken(sub).map((l) =>
168
+ l.kind === 'prose' ? { ...l, text: `${pad}${l.text}` } : l,
169
+ ),
170
+ );
171
+ continue;
172
+ }
173
+ const subLines = proseLines(
174
+ sub.type === 'text' || sub.type === 'paragraph'
175
+ ? formatInlineTokens((sub as Tokens.Text).tokens ?? [sub])
176
+ : 'raw' in sub
177
+ ? (sub as { raw: string }).raw
178
+ : '',
179
+ );
180
+ for (const l of subLines) {
181
+ if (l.kind !== 'prose') {
182
+ lines.push(l);
183
+ } else if (!firstLineDone) {
184
+ lines.push({ text: `${bullet}${l.text}`, kind: 'prose' });
185
+ firstLineDone = true;
186
+ } else {
187
+ lines.push({ text: `${pad}${l.text}`, kind: 'prose' });
188
+ }
189
+ }
190
+ }
191
+ if (!firstLineDone) lines.push({ text: bullet.trimEnd(), kind: 'prose' });
192
+ });
193
+ return lines;
194
+ }
195
+ case 'blockquote': {
196
+ const quote = token as Tokens.Blockquote;
197
+ const inner = quote.tokens.flatMap(formatBlockToken);
198
+ // 引用竖条只加在 prose 行;引用内代码块保持零装饰
199
+ return inner.map((l) =>
200
+ l.kind === 'prose' ? { ...l, text: `${dim(`${figures.quote} `)}${l.text}` } : l,
201
+ );
202
+ }
203
+ case 'space':
204
+ return [{ text: '', kind: 'prose' }];
205
+ case 'hr':
206
+ return [{ text: dim(figures.hr.repeat(20)), kind: 'prose' }];
207
+ case 'table':
208
+ // TODO:flexbox 对齐表格(捐赠方 MarkdownTable 模式);第一期原样透传
209
+ return proseLines((token as Tokens.Table).raw.trimEnd());
210
+ default:
211
+ return 'raw' in token
212
+ ? proseLines((token as { raw: string }).raw.replace(/\n+$/, ''))
213
+ : [];
214
+ }
215
+ }
216
+
217
+ /**
218
+ * 主入口:assistant 正文 → 展示行。
219
+ * 纯文本走快路径(与旧渲染逐行一致);lexer 意外抛错时兜底回退原文
220
+ * (模型输出任意性防御——格式化是锦上添花,绝不能让渲染崩掉消息)。
221
+ */
222
+ export function renderMarkdownLines(src: string): MdLine[] {
223
+ if (src.length === 0) return [];
224
+ if (!looksLikeMarkdown(src)) return proseLines(src);
225
+ try {
226
+ return lexer(src).flatMap(formatBlockToken);
227
+ } catch {
228
+ return proseLines(src);
229
+ }
230
+ }
@@ -0,0 +1,239 @@
1
+ /**
2
+ * ============================================================
3
+ * src/ui/textBuffer.ts —— 输入框文本缓冲(纯逻辑,无 React)
4
+ * ------------------------------------------------------------
5
+ * 把"光标 + 文本"建模成一对值 { text, cursor }:
6
+ * - text 是 user-perceived 字符串(可含 \n,多行也行)
7
+ * - cursor 是 **code-point 偏移**(非 UTF-16),保证不会切坏 emoji / 中日韩
8
+ *
9
+ * 所有 op 都是纯函数:返回新的 { text, cursor },不改入参。
10
+ * 这样 React 端用 useState 包一下就行;测试也直接对纯函数断言、零依赖。
11
+ *
12
+ * 支持的操作:
13
+ * - 插入:insert / setText / clear
14
+ * - 删除:deleteBefore(Backspace)/ deleteAt(Delete)
15
+ * / killToLineStart(Ctrl+U)/ killToLineEnd(Ctrl+K)
16
+ * / deleteWordBefore(Ctrl+W)
17
+ * - 移动:moveLeft / moveRight / moveWordLeft / moveWordRight
18
+ * / moveLineStart / moveLineEnd
19
+ * / moveBufferStart / moveBufferEnd
20
+ * / moveUp / moveDown(按逻辑行,跨 \n,保持列位)
21
+ *
22
+ * 词边界定义(够用即可,不学完整 vim/emacs):
23
+ * [A-Za-z0-9_] 视为 word char;其他(空格、标点、CJK、emoji)都是 non-word。
24
+ * word-jump 的语义对齐多数 emacs:先吃当前侧的 non-word,再吃 word。
25
+ * ============================================================
26
+ */
27
+
28
+ export interface BufferState {
29
+ /** 用户可见文本(可含 \n) */
30
+ text: string;
31
+ /** 光标位置:code-point 偏移,范围 [0, codePointLength] */
32
+ cursor: number;
33
+ }
34
+
35
+ export const EMPTY_BUFFER: BufferState = { text: '', cursor: 0 };
36
+
37
+ // ---------- 工具:code-point 视角操作字符串 ----------
38
+
39
+ /** 把字符串拆成 code-point 数组(Array.from 自动处理 surrogate pair) */
40
+ function toCps(s: string): string[] {
41
+ return Array.from(s);
42
+ }
43
+
44
+ function fromCps(cps: string[]): string {
45
+ return cps.join('');
46
+ }
47
+
48
+ function isWordChar(c: string | undefined): boolean {
49
+ if (!c) return false;
50
+ return /[A-Za-z0-9_]/.test(c);
51
+ }
52
+
53
+ /** 给定 code-point 数组与一个偏移,返回所在逻辑行的起点(指向 \n 之后或 0) */
54
+ function findLineStart(cps: string[], idx: number): number {
55
+ let i = idx;
56
+ while (i > 0 && cps[i - 1] !== '\n') i--;
57
+ return i;
58
+ }
59
+
60
+ /** 给定 code-point 数组与一个偏移,返回所在逻辑行的终点(指向 \n 或末尾) */
61
+ function findLineEnd(cps: string[], idx: number): number {
62
+ let i = idx;
63
+ while (i < cps.length && cps[i] !== '\n') i++;
64
+ return i;
65
+ }
66
+
67
+ /** 把 cursor 钳制到合法范围 */
68
+ function clamp(cps: string[], idx: number): number {
69
+ return Math.max(0, Math.min(cps.length, idx));
70
+ }
71
+
72
+ // ---------- 插入 ----------
73
+
74
+ export function bufInsert(s: BufferState, content: string): BufferState {
75
+ if (content.length === 0) return s;
76
+ const cps = toCps(s.text);
77
+ const ins = toCps(content);
78
+ cps.splice(s.cursor, 0, ...ins);
79
+ return { text: fromCps(cps), cursor: s.cursor + ins.length };
80
+ }
81
+
82
+ export function bufSetText(text: string): BufferState {
83
+ return { text, cursor: toCps(text).length };
84
+ }
85
+
86
+ export function bufClear(): BufferState {
87
+ return EMPTY_BUFFER;
88
+ }
89
+
90
+ // ---------- 删除 ----------
91
+
92
+ export function bufDeleteBefore(s: BufferState): BufferState {
93
+ if (s.cursor === 0) return s;
94
+ const cps = toCps(s.text);
95
+ cps.splice(s.cursor - 1, 1);
96
+ return { text: fromCps(cps), cursor: s.cursor - 1 };
97
+ }
98
+
99
+ /**
100
+ * Ctrl+W / M-DEL:先吃光标左侧的非词字符(空格 / 标点),再吃前一个词。
101
+ * 例:光标贴在 "world" 后 → 删 'world',留 "hello "。
102
+ * 光标在 "hello " 之后 → 先吃 3 空格再吃 "hello",留空。
103
+ */
104
+ export function bufDeleteWordBefore(s: BufferState): BufferState {
105
+ if (s.cursor === 0) return s;
106
+ const cps = toCps(s.text);
107
+ let i = s.cursor;
108
+ while (i > 0 && !isWordChar(cps[i - 1])) i--;
109
+ while (i > 0 && isWordChar(cps[i - 1])) i--;
110
+ cps.splice(i, s.cursor - i);
111
+ return { text: fromCps(cps), cursor: i };
112
+ }
113
+
114
+ /** Ctrl+U:从光标删到当前逻辑行行首 */
115
+ export function bufKillToLineStart(s: BufferState): BufferState {
116
+ const cps = toCps(s.text);
117
+ const lineStart = findLineStart(cps, s.cursor);
118
+ if (lineStart === s.cursor) return s;
119
+ cps.splice(lineStart, s.cursor - lineStart);
120
+ return { text: fromCps(cps), cursor: lineStart };
121
+ }
122
+
123
+ /** Ctrl+K:从光标删到当前逻辑行行末(不删 \n 自身) */
124
+ export function bufKillToLineEnd(s: BufferState): BufferState {
125
+ const cps = toCps(s.text);
126
+ const lineEnd = findLineEnd(cps, s.cursor);
127
+ if (lineEnd === s.cursor) return s;
128
+ cps.splice(s.cursor, lineEnd - s.cursor);
129
+ return { text: fromCps(cps), cursor: s.cursor };
130
+ }
131
+
132
+ // ---------- 移动 ----------
133
+
134
+ export function bufMoveLeft(s: BufferState): BufferState {
135
+ return { text: s.text, cursor: Math.max(0, s.cursor - 1) };
136
+ }
137
+
138
+ export function bufMoveRight(s: BufferState): BufferState {
139
+ const len = toCps(s.text).length;
140
+ return { text: s.text, cursor: Math.min(len, s.cursor + 1) };
141
+ }
142
+
143
+ export function bufMoveWordLeft(s: BufferState): BufferState {
144
+ const cps = toCps(s.text);
145
+ let i = s.cursor;
146
+ while (i > 0 && !isWordChar(cps[i - 1])) i--;
147
+ while (i > 0 && isWordChar(cps[i - 1])) i--;
148
+ return { text: s.text, cursor: i };
149
+ }
150
+
151
+ export function bufMoveWordRight(s: BufferState): BufferState {
152
+ const cps = toCps(s.text);
153
+ let i = s.cursor;
154
+ while (i < cps.length && !isWordChar(cps[i])) i++;
155
+ while (i < cps.length && isWordChar(cps[i])) i++;
156
+ return { text: s.text, cursor: i };
157
+ }
158
+
159
+ export function bufMoveLineStart(s: BufferState): BufferState {
160
+ const cps = toCps(s.text);
161
+ return { text: s.text, cursor: findLineStart(cps, s.cursor) };
162
+ }
163
+
164
+ export function bufMoveLineEnd(s: BufferState): BufferState {
165
+ const cps = toCps(s.text);
166
+ return { text: s.text, cursor: findLineEnd(cps, s.cursor) };
167
+ }
168
+
169
+ export function bufMoveBufferStart(s: BufferState): BufferState {
170
+ return { text: s.text, cursor: 0 };
171
+ }
172
+
173
+ export function bufMoveBufferEnd(s: BufferState): BufferState {
174
+ return { text: s.text, cursor: toCps(s.text).length };
175
+ }
176
+
177
+ /** ↑:上移一个逻辑行,保留列位(目标行短就贴行末) */
178
+ export function bufMoveUp(s: BufferState): BufferState {
179
+ const cps = toCps(s.text);
180
+ const lineStart = findLineStart(cps, s.cursor);
181
+ if (lineStart === 0) return s; // 已在首行
182
+ const prevLineEnd = lineStart - 1; // 指向上一行末尾的 \n
183
+ const prevLineStart = findLineStart(cps, prevLineEnd);
184
+ const col = s.cursor - lineStart;
185
+ const prevLineLen = prevLineEnd - prevLineStart;
186
+ return { text: s.text, cursor: prevLineStart + Math.min(col, prevLineLen) };
187
+ }
188
+
189
+ /** ↓:下移一个逻辑行,保留列位 */
190
+ export function bufMoveDown(s: BufferState): BufferState {
191
+ const cps = toCps(s.text);
192
+ const lineStart = findLineStart(cps, s.cursor);
193
+ const lineEnd = findLineEnd(cps, s.cursor);
194
+ if (lineEnd === cps.length) return s; // 已在末行
195
+ const nextLineStart = lineEnd + 1;
196
+ const nextLineEnd = findLineEnd(cps, nextLineStart);
197
+ const col = s.cursor - lineStart;
198
+ const nextLineLen = nextLineEnd - nextLineStart;
199
+ return { text: s.text, cursor: nextLineStart + Math.min(col, nextLineLen) };
200
+ }
201
+
202
+ // ---------- 渲染辅助:把 text 切成 lines + 算光标行列 ----------
203
+
204
+ export interface BufferLayout {
205
+ /** 逻辑行(按 \n 分割),不含 \n 自身 */
206
+ lines: string[];
207
+ /** 光标所在的行号(0-based) */
208
+ cursorRow: number;
209
+ /** 光标在所在行的列号(code-point 偏移,0-based) */
210
+ cursorCol: number;
211
+ }
212
+
213
+ /**
214
+ * 给定一个 BufferState,算出它的可视布局。
215
+ * 渲染端拿到 lines + cursorRow/Col 就能把光标绘制在正确位置。
216
+ */
217
+ export function layoutBuffer(s: BufferState): BufferLayout {
218
+ const cps = toCps(s.text);
219
+ const cursor = clamp(cps, s.cursor);
220
+ const lineStart = findLineStart(cps, cursor);
221
+ // 把 cps 按 \n 分行(保持 code-point 视角,避免 surrogate pair 撕裂)
222
+ const lines: string[] = [];
223
+ let buf: string[] = [];
224
+ let cursorRow = 0;
225
+ let charCount = 0;
226
+ for (const ch of cps) {
227
+ if (ch === '\n') {
228
+ lines.push(fromCps(buf));
229
+ buf = [];
230
+ if (charCount < lineStart) cursorRow++;
231
+ } else {
232
+ buf.push(ch);
233
+ }
234
+ charCount++;
235
+ }
236
+ lines.push(fromCps(buf));
237
+ const cursorCol = cursor - lineStart;
238
+ return { lines, cursorRow, cursorCol };
239
+ }
@@ -0,0 +1,35 @@
1
+ /**
2
+ * ============================================================
3
+ * src/ui/theme.ts —— TUI 语义色板(单一出处)
4
+ * ------------------------------------------------------------
5
+ * 借鉴 Claude Code 的语义化主题键思想(utils/theme.ts),按 minimal-agent
6
+ * 减法原则收敛为 7 个键:组件里写"这段文字是什么角色"(theme.subtle),
7
+ * 不写"这段文字是什么颜色"('gray')——改配色只动这一个文件。
8
+ *
9
+ * 值是 Ink <Text color=...> 的合法取值;undefined = 终端默认前景色。
10
+ * 事实调色板(与重构前完全一致,机械替换零行为变化):
11
+ * - 层次靠三级区分:subtle+dimColor(次要:思维链/工具/进度)
12
+ * ↔ answer 默认亮色(主角:最终答案)↔ user/plugin bold(状态行)。
13
+ * ============================================================
14
+ */
15
+
16
+ export const theme = {
17
+ /** 用户输入 / banner / 状态行 spinner / 输入框边框 */
18
+ user: 'cyan',
19
+ /** 最终答案正文 —— undefined = 终端默认亮色(答案是主角,不染色) */
20
+ answer: undefined,
21
+ /** ⏺ 答案锚点(配 bold) */
22
+ anchor: 'green',
23
+ /** 次要信息:思维链 / 工具结果 / turn 横线 / live 过程区(配 dimColor) */
24
+ subtle: 'gray',
25
+ /** 暂态提示 / tool_calls 摘要 / 中断提示 */
26
+ warning: 'yellow',
27
+ /** 永久错误 */
28
+ error: 'red',
29
+ /** 健康/正常状态(StatusLine 用量比率等) */
30
+ ok: 'green',
31
+ /** compacting 状态 / 插件进度 / reverse-search */
32
+ plugin: 'magenta',
33
+ } as const;
34
+
35
+ export type ThemeColor = (typeof theme)[keyof typeof theme];