@armadra/agent 0.3.0 → 0.5.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 (527) hide show
  1. package/CHANGELOG.md +257 -0
  2. package/README.md +263 -95
  3. package/THIRD_PARTY_NOTICES.md +34 -0
  4. package/dist/acp.d.ts +18 -0
  5. package/dist/acp.js +19 -0
  6. package/dist/agent/limits.d.ts +38 -0
  7. package/dist/agent/limits.js +127 -0
  8. package/dist/agent/loop-guard.d.ts +38 -0
  9. package/dist/agent/loop-guard.js +95 -0
  10. package/dist/agent/loop.d.ts +4 -0
  11. package/dist/agent/loop.js +7 -0
  12. package/dist/agent/prompt-rules.d.ts +12 -0
  13. package/dist/agent/prompt-rules.js +18 -0
  14. package/dist/agent/reminders.d.ts +59 -0
  15. package/dist/agent/reminders.js +327 -0
  16. package/dist/agent/retry.d.ts +1 -1
  17. package/dist/agent/retry.js +2 -1
  18. package/dist/agent/session-cache.d.ts +5 -0
  19. package/dist/agent/session-cache.js +18 -2
  20. package/dist/agent/session-classifier.d.ts +18 -0
  21. package/dist/agent/session-classifier.js +105 -0
  22. package/dist/agent/session-compaction.d.ts +35 -6
  23. package/dist/agent/session-compaction.js +157 -31
  24. package/dist/agent/session-core.d.ts +40 -1
  25. package/dist/agent/session-extensions.d.ts +61 -0
  26. package/dist/agent/session-extensions.js +129 -0
  27. package/dist/agent/session-images.d.ts +23 -0
  28. package/dist/agent/session-images.js +97 -0
  29. package/dist/agent/session-plan.d.ts +21 -0
  30. package/dist/agent/session-plan.js +524 -0
  31. package/dist/agent/session-rewind.d.ts +81 -0
  32. package/dist/agent/session-rewind.js +354 -0
  33. package/dist/agent/session-run.d.ts +28 -1
  34. package/dist/agent/session-run.js +157 -6
  35. package/dist/agent/session-settings.d.ts +49 -0
  36. package/dist/agent/session-settings.js +95 -0
  37. package/dist/agent/session-subagent.d.ts +36 -24
  38. package/dist/agent/session-subagent.js +259 -129
  39. package/dist/agent/session-sync.d.ts +10 -3
  40. package/dist/agent/session-sync.js +37 -8
  41. package/dist/agent/session-telemetry.d.ts +39 -0
  42. package/dist/agent/session-telemetry.js +231 -0
  43. package/dist/agent/session-tools.js +63 -3
  44. package/dist/agent/session.d.ts +33 -29
  45. package/dist/agent/session.js +91 -126
  46. package/dist/agent/subagent-registry.d.ts +91 -0
  47. package/dist/agent/subagent-registry.js +494 -0
  48. package/dist/agent/system-prompt.d.ts +6 -3
  49. package/dist/agent/system-prompt.js +7 -2
  50. package/dist/agent/tool-runner.d.ts +8 -1
  51. package/dist/agent/tool-runner.js +72 -6
  52. package/dist/agent/types-w5.d.ts +192 -0
  53. package/dist/agent/types-w5.js +10 -0
  54. package/dist/agent/types.d.ts +55 -4
  55. package/dist/agent/types.js +2 -0
  56. package/dist/agent/worktree.d.ts +36 -0
  57. package/dist/agent/worktree.js +86 -0
  58. package/dist/agents/builtin.d.ts +14 -0
  59. package/dist/agents/builtin.js +39 -0
  60. package/dist/agents/catalog.d.ts +43 -0
  61. package/dist/agents/catalog.js +82 -0
  62. package/dist/agents/discover.d.ts +35 -0
  63. package/dist/agents/discover.js +83 -0
  64. package/dist/agents/external.d.ts +82 -0
  65. package/dist/agents/external.js +326 -0
  66. package/dist/agents/parse.d.ts +18 -0
  67. package/dist/agents/parse.js +116 -0
  68. package/dist/agents/result.d.ts +32 -0
  69. package/dist/agents/result.js +67 -0
  70. package/dist/agents/task-control.d.ts +17 -0
  71. package/dist/agents/task-control.js +17 -0
  72. package/dist/agents/task-record.d.ts +78 -0
  73. package/dist/agents/task-record.js +141 -0
  74. package/dist/agents/types.d.ts +46 -0
  75. package/dist/agents/types.js +8 -0
  76. package/dist/ai/apis/anthropic-compat.d.ts +36 -0
  77. package/dist/ai/apis/anthropic-compat.js +92 -0
  78. package/dist/ai/apis/anthropic-messages.js +3 -2
  79. package/dist/ai/apis/anthropic-request.d.ts +7 -6
  80. package/dist/ai/apis/anthropic-request.js +10 -28
  81. package/dist/ai/apis/cache-params.d.ts +11 -2
  82. package/dist/ai/apis/cache-params.js +25 -6
  83. package/dist/ai/apis/google-generative-ai.js +3 -2
  84. package/dist/ai/apis/openai-compat.d.ts +4 -1
  85. package/dist/ai/apis/openai-compat.js +8 -1
  86. package/dist/ai/apis/openai-completions.js +3 -2
  87. package/dist/ai/apis/openai-responses.js +3 -2
  88. package/dist/ai/http.d.ts +28 -6
  89. package/dist/ai/http.js +41 -8
  90. package/dist/ai/image-limits.d.ts +45 -0
  91. package/dist/ai/image-limits.js +68 -0
  92. package/dist/ai/providers/builtin.d.ts +18 -6
  93. package/dist/ai/providers/builtin.js +135 -6
  94. package/dist/ai/providers/catalog-data.js +17 -13
  95. package/dist/ai/providers/catalog.d.ts +60 -7
  96. package/dist/ai/providers/catalog.js +197 -38
  97. package/dist/ai/providers/channels.d.ts +33 -3
  98. package/dist/ai/providers/channels.js +108 -7
  99. package/dist/ai/providers/enrich.d.ts +6 -3
  100. package/dist/ai/providers/enrich.js +19 -4
  101. package/dist/ai/providers/models-dev-cache.d.ts +28 -24
  102. package/dist/ai/providers/models-dev-cache.js +92 -78
  103. package/dist/ai/providers/models-dev-data.d.ts +7 -0
  104. package/dist/ai/providers/models-dev-data.js +32 -0
  105. package/dist/ai/providers/models-dev-snapshot.d.ts +50 -0
  106. package/dist/ai/providers/models-dev-snapshot.js +137 -0
  107. package/dist/ai/providers/models-dev.d.ts +51 -10
  108. package/dist/ai/providers/models-dev.js +132 -39
  109. package/dist/ai/providers/registry.d.ts +28 -11
  110. package/dist/ai/providers/registry.js +112 -65
  111. package/dist/ai/providers/suggest.d.ts +18 -0
  112. package/dist/ai/providers/suggest.js +72 -0
  113. package/dist/ai/sse.d.ts +6 -2
  114. package/dist/ai/sse.js +22 -2
  115. package/dist/ai/types.d.ts +37 -4
  116. package/dist/ai/types.js +5 -0
  117. package/dist/bundle/ama.cjs +41979 -21147
  118. package/dist/checkpoints/backend.d.ts +61 -0
  119. package/dist/checkpoints/backend.js +135 -0
  120. package/dist/checkpoints/blobs.d.ts +60 -0
  121. package/dist/checkpoints/blobs.js +203 -0
  122. package/dist/checkpoints/gc.d.ts +47 -0
  123. package/dist/checkpoints/gc.js +144 -0
  124. package/dist/checkpoints/git-head.d.ts +15 -0
  125. package/dist/checkpoints/git-head.js +89 -0
  126. package/dist/checkpoints/index.d.ts +17 -0
  127. package/dist/checkpoints/index.js +17 -0
  128. package/dist/checkpoints/replay.d.ts +48 -0
  129. package/dist/checkpoints/replay.js +154 -0
  130. package/dist/checkpoints/restore.d.ts +86 -0
  131. package/dist/checkpoints/restore.js +263 -0
  132. package/dist/checkpoints/settings.d.ts +14 -0
  133. package/dist/checkpoints/settings.js +23 -0
  134. package/dist/checkpoints/shadow-git.d.ts +108 -0
  135. package/dist/checkpoints/shadow-git.js +491 -0
  136. package/dist/checkpoints/shadow-restore.d.ts +25 -0
  137. package/dist/checkpoints/shadow-restore.js +128 -0
  138. package/dist/checkpoints/tracker.d.ts +64 -0
  139. package/dist/checkpoints/tracker.js +192 -0
  140. package/dist/checkpoints/types.d.ts +99 -0
  141. package/dist/checkpoints/types.js +12 -0
  142. package/dist/cli/args.d.ts +26 -7
  143. package/dist/cli/args.js +75 -82
  144. package/dist/cli/bootstrap.js +40 -4
  145. package/dist/cli/codemode-notice.d.ts +21 -0
  146. package/dist/cli/codemode-notice.js +56 -0
  147. package/dist/cli/compose-agents.d.ts +27 -0
  148. package/dist/cli/compose-agents.js +111 -0
  149. package/dist/cli/compose-extensions.d.ts +29 -0
  150. package/dist/cli/compose-extensions.js +44 -0
  151. package/dist/cli/compose-session.d.ts +8 -0
  152. package/dist/cli/compose-session.js +76 -2
  153. package/dist/cli/compose-store.d.ts +1 -1
  154. package/dist/cli/compose-store.js +3 -1
  155. package/dist/cli/compose.d.ts +17 -4
  156. package/dist/cli/compose.js +60 -14
  157. package/dist/cli/default-model.d.ts +38 -1
  158. package/dist/cli/default-model.js +96 -9
  159. package/dist/cli/deps.d.ts +42 -0
  160. package/dist/cli/exit-codes.d.ts +12 -0
  161. package/dist/cli/exit-codes.js +15 -0
  162. package/dist/cli/fake-visibility.d.ts +13 -0
  163. package/dist/cli/fake-visibility.js +26 -0
  164. package/dist/cli/from-prompt.d.ts +18 -0
  165. package/dist/cli/from-prompt.js +49 -0
  166. package/dist/cli/help-text.d.ts +4 -0
  167. package/dist/cli/help-text.js +102 -0
  168. package/dist/cli/main.d.ts +9 -2
  169. package/dist/cli/main.js +77 -3
  170. package/dist/cli/proxy.d.ts +51 -0
  171. package/dist/cli/proxy.js +135 -0
  172. package/dist/cli/startup-screen.d.ts +29 -0
  173. package/dist/cli/startup-screen.js +51 -2
  174. package/dist/cli/startup-steps.d.ts +1 -1
  175. package/dist/cli/startup-steps.js +21 -13
  176. package/dist/cli/subcommands/config.d.ts +22 -3
  177. package/dist/cli/subcommands/config.js +119 -21
  178. package/dist/cli/subcommands/context.js +4 -1
  179. package/dist/cli/subcommands/doctor.js +33 -1
  180. package/dist/cli/subcommands/init.js +2 -1
  181. package/dist/cli/subcommands/models-discover.d.ts +15 -9
  182. package/dist/cli/subcommands/models-discover.js +58 -52
  183. package/dist/cli/subcommands/models.d.ts +2 -0
  184. package/dist/cli/subcommands/models.js +33 -14
  185. package/dist/cli/subcommands/probe-runner.d.ts +96 -0
  186. package/dist/cli/subcommands/probe-runner.js +264 -0
  187. package/dist/cli/subcommands/providers-probe.d.ts +34 -0
  188. package/dist/cli/subcommands/providers-probe.js +87 -0
  189. package/dist/cli/subcommands/providers.d.ts +3 -2
  190. package/dist/cli/subcommands/providers.js +53 -51
  191. package/dist/cli/subcommands/sessions-export.d.ts +10 -0
  192. package/dist/cli/subcommands/sessions-export.js +59 -0
  193. package/dist/cli/subcommands/sessions-search.d.ts +13 -0
  194. package/dist/cli/subcommands/sessions-search.js +103 -0
  195. package/dist/cli/subcommands/sessions.d.ts +6 -3
  196. package/dist/cli/subcommands/sessions.js +58 -3
  197. package/dist/cli/subcommands/stats.d.ts +17 -0
  198. package/dist/cli/subcommands/stats.js +198 -0
  199. package/dist/cli/system-prompt-arg.d.ts +11 -0
  200. package/dist/cli/system-prompt-arg.js +34 -0
  201. package/dist/codemode/capability.d.ts +24 -7
  202. package/dist/codemode/capability.js +38 -10
  203. package/dist/codemode/host-side.d.ts +14 -0
  204. package/dist/codemode/host-side.js +24 -1
  205. package/dist/codemode/modes.d.ts +4 -11
  206. package/dist/codemode/modes.js +5 -27
  207. package/dist/codemode/tool.d.ts +18 -14
  208. package/dist/codemode/tool.js +76 -31
  209. package/dist/compaction/breaker.d.ts +25 -9
  210. package/dist/compaction/breaker.js +47 -17
  211. package/dist/compaction/estimate.d.ts +11 -3
  212. package/dist/compaction/estimate.js +64 -22
  213. package/dist/compaction/image-budget.d.ts +45 -0
  214. package/dist/compaction/image-budget.js +115 -0
  215. package/dist/compaction/post-compact.d.ts +38 -0
  216. package/dist/compaction/post-compact.js +152 -0
  217. package/dist/compaction/protect.d.ts +27 -0
  218. package/dist/compaction/protect.js +56 -0
  219. package/dist/compaction/prune-tier.d.ts +58 -12
  220. package/dist/compaction/prune-tier.js +120 -54
  221. package/dist/compaction/summarize-tier.d.ts +23 -4
  222. package/dist/compaction/summarize-tier.js +100 -29
  223. package/dist/config/checker.d.ts +28 -0
  224. package/dist/config/checker.js +97 -0
  225. package/dist/config/init.d.ts +6 -2
  226. package/dist/config/init.js +12 -5
  227. package/dist/config/json-schema.d.ts +1 -0
  228. package/dist/config/json-schema.js +98 -4
  229. package/dist/config/key-docs.d.ts +22 -0
  230. package/dist/config/key-docs.js +174 -0
  231. package/dist/config/merge.d.ts +12 -9
  232. package/dist/config/merge.js +102 -13
  233. package/dist/config/profile.d.ts +2 -0
  234. package/dist/config/profile.js +2 -0
  235. package/dist/config/schema-w5.d.ts +18 -0
  236. package/dist/config/schema-w5.js +109 -0
  237. package/dist/config/schema.d.ts +5 -9
  238. package/dist/config/schema.js +91 -118
  239. package/dist/config/types-w5.d.ts +118 -0
  240. package/dist/config/types-w5.js +20 -0
  241. package/dist/config/types.d.ts +84 -7
  242. package/dist/config/types.js +29 -1
  243. package/dist/drivers/acp/client.d.ts +57 -0
  244. package/dist/drivers/acp/client.js +160 -0
  245. package/dist/drivers/acp/driver.d.ts +31 -0
  246. package/dist/drivers/acp/driver.js +274 -0
  247. package/dist/drivers/acp/testing/fake-agent-main.d.ts +5 -0
  248. package/dist/drivers/acp/testing/fake-agent-main.js +7 -0
  249. package/dist/drivers/acp/testing/fake-agent.d.ts +27 -0
  250. package/dist/drivers/acp/testing/fake-agent.js +211 -0
  251. package/dist/drivers/acp/types.d.ts +285 -0
  252. package/dist/drivers/acp/types.js +36 -0
  253. package/dist/drivers/agents.d.ts +58 -0
  254. package/dist/drivers/agents.js +142 -0
  255. package/dist/drivers/base.d.ts +35 -0
  256. package/dist/drivers/base.js +59 -0
  257. package/dist/drivers/catalog.d.ts +46 -0
  258. package/dist/drivers/catalog.js +167 -0
  259. package/dist/drivers/env.d.ts +20 -0
  260. package/dist/drivers/env.js +46 -0
  261. package/dist/drivers/host-runners.d.ts +18 -0
  262. package/dist/drivers/host-runners.js +45 -0
  263. package/dist/drivers/jsonrpc.d.ts +58 -0
  264. package/dist/drivers/jsonrpc.js +180 -0
  265. package/dist/drivers/native/claude-normalize.d.ts +46 -0
  266. package/dist/drivers/native/claude-normalize.js +106 -0
  267. package/dist/drivers/native/claude-stream.d.ts +29 -0
  268. package/dist/drivers/native/claude-stream.js +456 -0
  269. package/dist/drivers/native/codex-app-server.d.ts +26 -0
  270. package/dist/drivers/native/codex-app-server.js +407 -0
  271. package/dist/drivers/native/codex-normalize.d.ts +38 -0
  272. package/dist/drivers/native/codex-normalize.js +124 -0
  273. package/dist/drivers/native/oneshot.d.ts +28 -0
  274. package/dist/drivers/native/oneshot.js +312 -0
  275. package/dist/drivers/permissions.d.ts +40 -0
  276. package/dist/drivers/permissions.js +92 -0
  277. package/dist/drivers/pids.d.ts +32 -0
  278. package/dist/drivers/pids.js +93 -0
  279. package/dist/drivers/pool.d.ts +28 -0
  280. package/dist/drivers/pool.js +96 -0
  281. package/dist/drivers/probe.d.ts +47 -0
  282. package/dist/drivers/probe.js +172 -0
  283. package/dist/drivers/process.d.ts +48 -0
  284. package/dist/drivers/process.js +100 -0
  285. package/dist/drivers/runner.d.ts +61 -0
  286. package/dist/drivers/runner.js +388 -0
  287. package/dist/drivers/store.d.ts +49 -0
  288. package/dist/drivers/store.js +91 -0
  289. package/dist/drivers/turn.d.ts +41 -0
  290. package/dist/drivers/turn.js +99 -0
  291. package/dist/drivers/types.d.ts +122 -0
  292. package/dist/drivers/types.js +11 -0
  293. package/dist/git/info.d.ts +75 -0
  294. package/dist/git/info.js +191 -0
  295. package/dist/hooks/protocol.js +6 -1
  296. package/dist/hooks/types.d.ts +10 -1
  297. package/dist/hooks/types.js +2 -0
  298. package/dist/host/api-impl.d.ts +7 -0
  299. package/dist/host/api-impl.js +15 -0
  300. package/dist/host/types.d.ts +24 -2
  301. package/dist/host/types.js +4 -0
  302. package/dist/index.d.ts +3 -0
  303. package/dist/index.js +1 -0
  304. package/dist/modes/acp/acp-events.d.ts +46 -0
  305. package/dist/modes/acp/acp-events.js +233 -0
  306. package/dist/modes/acp/acp-mode.d.ts +17 -0
  307. package/dist/modes/acp/acp-mode.js +47 -0
  308. package/dist/modes/acp/acp-server.d.ts +79 -0
  309. package/dist/modes/acp/acp-server.js +315 -0
  310. package/dist/modes/commands-core.d.ts +7 -1
  311. package/dist/modes/commands-core.js +61 -5
  312. package/dist/modes/image-input.d.ts +12 -4
  313. package/dist/modes/image-input.js +22 -5
  314. package/dist/modes/interactive/agent-panels.d.ts +14 -0
  315. package/dist/modes/interactive/agent-panels.js +103 -0
  316. package/dist/modes/interactive/agent-ui.d.ts +73 -0
  317. package/dist/modes/interactive/agent-ui.js +234 -0
  318. package/dist/modes/interactive/approval-dialog.d.ts +40 -7
  319. package/dist/modes/interactive/approval-dialog.js +192 -35
  320. package/dist/modes/interactive/approval-merge.d.ts +41 -0
  321. package/dist/modes/interactive/approval-merge.js +89 -0
  322. package/dist/modes/interactive/clipboard-paste.d.ts +18 -0
  323. package/dist/modes/interactive/clipboard-paste.js +28 -0
  324. package/dist/modes/interactive/commands.d.ts +20 -3
  325. package/dist/modes/interactive/commands.js +75 -16
  326. package/dist/modes/interactive/double-esc.d.ts +20 -0
  327. package/dist/modes/interactive/double-esc.js +34 -0
  328. package/dist/modes/interactive/event-notices.d.ts +32 -0
  329. package/dist/modes/interactive/event-notices.js +79 -0
  330. package/dist/modes/interactive/external-editor.d.ts +16 -0
  331. package/dist/modes/interactive/external-editor.js +39 -0
  332. package/dist/modes/interactive/interactive-mode.d.ts +16 -2
  333. package/dist/modes/interactive/interactive-mode.js +184 -202
  334. package/dist/modes/interactive/key-dispatch.d.ts +18 -2
  335. package/dist/modes/interactive/key-dispatch.js +53 -6
  336. package/dist/modes/interactive/line/line-mode.d.ts +3 -1
  337. package/dist/modes/interactive/line/line-mode.js +28 -9
  338. package/dist/modes/interactive/line/line-render.d.ts +6 -1
  339. package/dist/modes/interactive/line/line-render.js +66 -8
  340. package/dist/modes/interactive/message-view.d.ts +49 -10
  341. package/dist/modes/interactive/message-view.js +262 -46
  342. package/dist/modes/interactive/panels.d.ts +35 -0
  343. package/dist/modes/interactive/panels.js +157 -0
  344. package/dist/modes/interactive/pickers.d.ts +23 -2
  345. package/dist/modes/interactive/pickers.js +48 -15
  346. package/dist/modes/interactive/plan-command.d.ts +40 -0
  347. package/dist/modes/interactive/plan-command.js +129 -0
  348. package/dist/modes/interactive/plan-dialog.d.ts +98 -0
  349. package/dist/modes/interactive/plan-dialog.js +290 -0
  350. package/dist/modes/interactive/plan-flow.d.ts +34 -0
  351. package/dist/modes/interactive/plan-flow.js +98 -0
  352. package/dist/modes/interactive/rewind-command.d.ts +31 -0
  353. package/dist/modes/interactive/rewind-command.js +106 -0
  354. package/dist/modes/interactive/rewind-flow.d.ts +37 -0
  355. package/dist/modes/interactive/rewind-flow.js +151 -0
  356. package/dist/modes/interactive/rewind-list.d.ts +36 -0
  357. package/dist/modes/interactive/rewind-list.js +123 -0
  358. package/dist/modes/interactive/rewind-panel.d.ts +77 -0
  359. package/dist/modes/interactive/rewind-panel.js +309 -0
  360. package/dist/modes/interactive/rewind-text.d.ts +40 -0
  361. package/dist/modes/interactive/rewind-text.js +139 -0
  362. package/dist/modes/interactive/run-indicator.d.ts +51 -0
  363. package/dist/modes/interactive/run-indicator.js +189 -0
  364. package/dist/modes/interactive/session-events.d.ts +24 -0
  365. package/dist/modes/interactive/session-events.js +96 -0
  366. package/dist/modes/interactive/startup-header.d.ts +40 -0
  367. package/dist/modes/interactive/startup-header.js +169 -0
  368. package/dist/modes/interactive/status-area.d.ts +73 -0
  369. package/dist/modes/interactive/status-area.js +190 -0
  370. package/dist/modes/interactive/status-bar.d.ts +107 -16
  371. package/dist/modes/interactive/status-bar.js +306 -81
  372. package/dist/modes/interactive/status-line.d.ts +33 -0
  373. package/dist/modes/interactive/status-line.js +113 -0
  374. package/dist/modes/interactive/subagent-view.d.ts +56 -0
  375. package/dist/modes/interactive/subagent-view.js +154 -0
  376. package/dist/modes/interactive/tasks-report.d.ts +27 -0
  377. package/dist/modes/interactive/tasks-report.js +114 -0
  378. package/dist/modes/interactive/tool-summary.d.ts +46 -0
  379. package/dist/modes/interactive/tool-summary.js +218 -0
  380. package/dist/modes/interactive/tool-view.d.ts +58 -15
  381. package/dist/modes/interactive/tool-view.js +233 -145
  382. package/dist/modes/print/print-mode.d.ts +40 -4
  383. package/dist/modes/print/print-mode.js +161 -8
  384. package/dist/modes/rpc/commands.d.ts +9 -0
  385. package/dist/modes/rpc/commands.js +49 -0
  386. package/dist/modes/rpc/rpc-mode.js +7 -1
  387. package/dist/modes/session-report.d.ts +11 -0
  388. package/dist/modes/session-report.js +48 -1
  389. package/dist/permissions/auto-safe.d.ts +65 -0
  390. package/dist/permissions/auto-safe.js +547 -0
  391. package/dist/permissions/classifier.d.ts +68 -0
  392. package/dist/permissions/classifier.js +186 -0
  393. package/dist/permissions/dangerous.d.ts +5 -0
  394. package/dist/permissions/dangerous.js +1 -1
  395. package/dist/permissions/modes.d.ts +30 -0
  396. package/dist/permissions/modes.js +78 -0
  397. package/dist/permissions/pipeline.d.ts +72 -6
  398. package/dist/permissions/pipeline.js +306 -11
  399. package/dist/permissions/protected.d.ts +19 -0
  400. package/dist/permissions/protected.js +74 -0
  401. package/dist/permissions/readonly-bash.d.ts +30 -0
  402. package/dist/permissions/readonly-bash.js +118 -0
  403. package/dist/permissions/rules.js +3 -0
  404. package/dist/permissions/types.d.ts +92 -3
  405. package/dist/permissions/types.js +3 -0
  406. package/dist/plan/compose.d.ts +9 -0
  407. package/dist/plan/compose.js +19 -0
  408. package/dist/plan/controller.d.ts +71 -0
  409. package/dist/plan/controller.js +27 -0
  410. package/dist/plan/done-markers.d.ts +17 -0
  411. package/dist/plan/done-markers.js +51 -0
  412. package/dist/plan/extract.d.ts +29 -0
  413. package/dist/plan/extract.js +160 -0
  414. package/dist/plan/prompts.d.ts +36 -0
  415. package/dist/plan/prompts.js +89 -0
  416. package/dist/plan/store.d.ts +37 -0
  417. package/dist/plan/store.js +90 -0
  418. package/dist/rpc.d.ts +58 -2
  419. package/dist/rpc.js +7 -0
  420. package/dist/sandbox/bash.d.ts +74 -0
  421. package/dist/sandbox/bash.js +126 -0
  422. package/dist/sandbox/detect.d.ts +48 -0
  423. package/dist/sandbox/detect.js +149 -0
  424. package/dist/sandbox/index.d.ts +5 -0
  425. package/dist/sandbox/index.js +5 -0
  426. package/dist/sandbox/profile.d.ts +33 -0
  427. package/dist/sandbox/profile.js +76 -0
  428. package/dist/sandbox/wrap.d.ts +29 -0
  429. package/dist/sandbox/wrap.js +117 -0
  430. package/dist/sdk.d.ts +42 -5
  431. package/dist/sdk.js +34 -4
  432. package/dist/session/export.d.ts +32 -0
  433. package/dist/session/export.js +187 -0
  434. package/dist/session/redact.d.ts +15 -0
  435. package/dist/session/redact.js +55 -0
  436. package/dist/session/reuse.d.ts +33 -0
  437. package/dist/session/reuse.js +86 -0
  438. package/dist/session/scan.d.ts +34 -0
  439. package/dist/session/scan.js +140 -0
  440. package/dist/session/search.d.ts +52 -0
  441. package/dist/session/search.js +211 -0
  442. package/dist/session/stats-aggregate.d.ts +63 -0
  443. package/dist/session/stats-aggregate.js +163 -0
  444. package/dist/session/stats-index.d.ts +26 -0
  445. package/dist/session/stats-index.js +91 -0
  446. package/dist/session/stats-scan.d.ts +54 -0
  447. package/dist/session/stats-scan.js +236 -0
  448. package/dist/session/types.d.ts +3 -1
  449. package/dist/session/types.js +1 -0
  450. package/dist/skills/builtin.d.ts +31 -0
  451. package/dist/skills/builtin.js +109 -0
  452. package/dist/skills/discover.d.ts +2 -1
  453. package/dist/skills/index-prompt.js +5 -8
  454. package/dist/tools/background-jobs.d.ts +71 -0
  455. package/dist/tools/background-jobs.js +198 -0
  456. package/dist/tools/bash.d.ts +53 -1
  457. package/dist/tools/bash.js +158 -7
  458. package/dist/tools/clipboard-image.d.ts +44 -0
  459. package/dist/tools/clipboard-image.js +148 -0
  460. package/dist/tools/edit.d.ts +2 -0
  461. package/dist/tools/edit.js +18 -3
  462. package/dist/tools/image-file.d.ts +38 -3
  463. package/dist/tools/image-file.js +81 -10
  464. package/dist/tools/image-resize.d.ts +58 -0
  465. package/dist/tools/image-resize.js +97 -0
  466. package/dist/tools/presets.d.ts +40 -8
  467. package/dist/tools/presets.js +65 -19
  468. package/dist/tools/read.d.ts +5 -2
  469. package/dist/tools/read.js +13 -10
  470. package/dist/tools/registry.d.ts +7 -1
  471. package/dist/tools/registry.js +27 -4
  472. package/dist/tools/task-ctl.d.ts +22 -0
  473. package/dist/tools/task-ctl.js +116 -0
  474. package/dist/tools/task.d.ts +22 -10
  475. package/dist/tools/task.js +66 -26
  476. package/dist/tools/todo.d.ts +22 -2
  477. package/dist/tools/todo.js +58 -14
  478. package/dist/tools/truncate.d.ts +15 -0
  479. package/dist/tools/truncate.js +25 -0
  480. package/dist/tools/types.d.ts +113 -0
  481. package/dist/tools/types.js +5 -0
  482. package/dist/tools/write.js +3 -0
  483. package/dist/tui/component.d.ts +8 -2
  484. package/dist/tui/component.js +3 -1
  485. package/dist/tui/components/box.d.ts +6 -1
  486. package/dist/tui/components/box.js +16 -6
  487. package/dist/tui/components/card.d.ts +23 -0
  488. package/dist/tui/components/card.js +37 -0
  489. package/dist/tui/components/editor-history.d.ts +6 -0
  490. package/dist/tui/components/editor-history.js +45 -0
  491. package/dist/tui/components/editor-paste.d.ts +1 -1
  492. package/dist/tui/components/editor-paste.js +4 -4
  493. package/dist/tui/components/editor.d.ts +11 -5
  494. package/dist/tui/components/editor.js +52 -58
  495. package/dist/tui/components/key-value.d.ts +3 -0
  496. package/dist/tui/components/key-value.js +16 -6
  497. package/dist/tui/components/loader.d.ts +37 -7
  498. package/dist/tui/components/loader.js +84 -21
  499. package/dist/tui/components/markdown.d.ts +5 -1
  500. package/dist/tui/components/markdown.js +45 -21
  501. package/dist/tui/components/meter.d.ts +3 -3
  502. package/dist/tui/components/meter.js +13 -11
  503. package/dist/tui/components/select-list.d.ts +23 -1
  504. package/dist/tui/components/select-list.js +76 -13
  505. package/dist/tui/glyphs.d.ts +72 -0
  506. package/dist/tui/glyphs.js +118 -0
  507. package/dist/tui/keybindings.d.ts +5 -0
  508. package/dist/tui/keybindings.js +5 -0
  509. package/dist/tui/theme.d.ts +30 -6
  510. package/dist/tui/theme.js +103 -17
  511. package/dist/tui.d.ts +4 -2
  512. package/dist/tui.js +3 -1
  513. package/docs/acp.md +78 -0
  514. package/docs/agents.md +250 -0
  515. package/docs/codemode.md +28 -10
  516. package/docs/hooks.md +36 -32
  517. package/docs/permissions.md +212 -0
  518. package/docs/plan.md +107 -0
  519. package/docs/providers.md +261 -62
  520. package/docs/rewind-plan.md +181 -0
  521. package/docs/rpc.md +127 -40
  522. package/docs/sandbox.md +215 -0
  523. package/docs/session-format.md +43 -22
  524. package/docs/sessions.md +174 -0
  525. package/docs/tui-design.md +751 -0
  526. package/docs/tui.md +260 -64
  527. package/package.json +15 -2
@@ -0,0 +1,148 @@
1
+ /**
2
+ * 剪贴板图片(docs/wave5-plan.md §4、D12)。[W5-I] 界面接线(`Ctrl+V`、`/paste`)归 W5-U。
3
+ *
4
+ * 零依赖读不了剪贴板位图,按平台依次调系统命令,成功写 `<dataDir>/clipboard/<时间戳>.png` 并返回
5
+ * 路径(编辑器插入 `@<路径>`,之后走 loadImageFile);没有工具或剪贴板里没有图返回 undefined:
6
+ *
7
+ * | 平台 | 依次尝试 |
8
+ * | ------- | --------------------------------------------------------------------------- |
9
+ * | macOS | `osascript`(`the clipboard as «class PNGf»` 写文件)、`pngpaste <文件>` |
10
+ * | Linux | Wayland(有 WAYLAND_DISPLAY)`wl-paste -t image/png`;`xclip -selection clipboard -t image/png -o` |
11
+ * | Windows | `powershell` 的 `Get-Clipboard -Format Image` 存 PNG(路径经环境变量传入) |
12
+ *
13
+ * 写出的文件必须以 PNG 文件头开头,否则删掉按「没有图」处理。`ama sessions prune` 清理超过 7 天的
14
+ * 剪贴板文件(`gcClipboardImages`)。
15
+ */
16
+ import { existsSync } from "node:fs";
17
+ import { mkdir, readdir, rm, stat, writeFile, readFile } from "node:fs/promises";
18
+ import { join } from "node:path";
19
+ import { sniffImageMime } from "./image-file.js";
20
+ import { runCommand } from "./image-resize.js";
21
+ export const CLIPBOARD_DIR = "clipboard";
22
+ export const CLIPBOARD_MAX_AGE_DAYS = 7;
23
+ const OSASCRIPT = [
24
+ "on run argv",
25
+ "try",
26
+ "set png to the clipboard as «class PNGf»",
27
+ "on error",
28
+ 'return "none"',
29
+ "end try",
30
+ "set f to open for access (POSIX file (item 1 of argv)) with write permission",
31
+ "set eof f to 0",
32
+ "write png to f",
33
+ "close access f",
34
+ 'return "ok"',
35
+ "end run",
36
+ ];
37
+ const POWERSHELL = "$img = Get-Clipboard -Format Image; " +
38
+ "if ($null -eq $img) { exit 3 }; " +
39
+ "$img.Save($env:AMA_CLIPBOARD_OUT, [System.Drawing.Imaging.ImageFormat]::Png)";
40
+ function attempts(platform, file, env) {
41
+ if (platform === "darwin") {
42
+ return [
43
+ {
44
+ tool: "osascript",
45
+ command: "osascript",
46
+ args: [...OSASCRIPT.flatMap((line) => ["-e", line]), file],
47
+ via: "file",
48
+ },
49
+ { tool: "pngpaste", command: "pngpaste", args: [file], via: "file" },
50
+ ];
51
+ }
52
+ if (platform === "win32") {
53
+ return [
54
+ {
55
+ tool: "powershell",
56
+ command: "powershell",
57
+ args: ["-NoProfile", "-NonInteractive", "-STA", "-Command", POWERSHELL],
58
+ via: "file",
59
+ env: { ...env, AMA_CLIPBOARD_OUT: file },
60
+ },
61
+ ];
62
+ }
63
+ const list = [];
64
+ if (env["WAYLAND_DISPLAY"]) {
65
+ list.push({ tool: "wl-paste", command: "wl-paste", args: ["-t", "image/png"], via: "stdout" });
66
+ }
67
+ list.push({
68
+ tool: "xclip",
69
+ command: "xclip",
70
+ args: ["-selection", "clipboard", "-t", "image/png", "-o"],
71
+ via: "stdout",
72
+ });
73
+ return list;
74
+ }
75
+ async function isPng(file) {
76
+ try {
77
+ return sniffImageMime(await readFile(file)) === "image/png";
78
+ }
79
+ catch {
80
+ return false;
81
+ }
82
+ }
83
+ /** 读剪贴板图片到数据目录;返回结果与原因(界面据此给一行提示)。 */
84
+ export async function readClipboardImage(dataDir, deps = {}) {
85
+ const platform = deps.platform ?? process.platform;
86
+ const env = deps.env ?? process.env;
87
+ const run = deps.run ?? runCommand;
88
+ const dir = join(dataDir, CLIPBOARD_DIR);
89
+ await mkdir(dir, { recursive: true });
90
+ const stamp = new Date((deps.now ?? Date.now)()).toISOString().replace(/[:.]/g, "-");
91
+ // 同一毫秒再贴:加序号,不能把上一张当成这次的结果
92
+ let file = join(dir, `${stamp}.png`);
93
+ for (let n = 1; existsSync(file); n++)
94
+ file = join(dir, `${stamp}-${n}.png`);
95
+ let anyTool = false;
96
+ for (const attempt of attempts(platform, file, env)) {
97
+ const options = attempt.via === "file" && attempt.env !== undefined ? { env: attempt.env } : {};
98
+ const result = await run(attempt.command, attempt.args, options);
99
+ if (result.missing === true)
100
+ continue;
101
+ anyTool = true;
102
+ if (result.code !== 0)
103
+ continue;
104
+ if (attempt.via === "stdout") {
105
+ if (sniffImageMime(result.stdout) !== "image/png")
106
+ continue;
107
+ await writeFile(file, result.stdout);
108
+ }
109
+ if (await isPng(file))
110
+ return { ok: true, path: file, tool: attempt.tool };
111
+ await rm(file, { force: true });
112
+ }
113
+ await rm(file, { force: true });
114
+ return { ok: false, reason: anyTool ? "no_image" : "no_tool" };
115
+ }
116
+ /** §10.2 的签名:成功返回 PNG 路径,没有工具或没有图返回 undefined。 */
117
+ export async function pasteClipboardImage(dataDir, deps = {}) {
118
+ const result = await readClipboardImage(dataDir, deps);
119
+ return result.ok ? result.path : undefined;
120
+ }
121
+ /** 清理 `<dataDir>/clipboard/` 里超过 `maxAgeDays`(缺省 7)天的文件;返回(将)删除的路径。 */
122
+ export async function gcClipboardImages(dataDir, options = {}) {
123
+ const dir = join(dataDir, CLIPBOARD_DIR);
124
+ let names;
125
+ try {
126
+ names = await readdir(dir);
127
+ }
128
+ catch {
129
+ return [];
130
+ }
131
+ const cutoff = (options.now ?? Date.now()) - (options.maxAgeDays ?? CLIPBOARD_MAX_AGE_DAYS) * 86_400_000;
132
+ const removed = [];
133
+ for (const name of names) {
134
+ const file = join(dir, name);
135
+ try {
136
+ const info = await stat(file);
137
+ if (!info.isFile() || info.mtimeMs >= cutoff)
138
+ continue;
139
+ if (options.dryRun !== true)
140
+ await rm(file, { force: true });
141
+ removed.push(file);
142
+ }
143
+ catch {
144
+ // 并发删除等:跳过
145
+ }
146
+ }
147
+ return removed;
148
+ }
@@ -34,5 +34,7 @@ export interface EditPlan {
34
34
  export declare function planEdits(content: string, edits: readonly EditOp[], replaceAll?: boolean): EditPlan;
35
35
  /** 统一 diff(LF 文本,3 行上下文);无差异返回空串。 */
36
36
  export declare function unifiedDiff(oldText: string, newText: string, path: string, context?: number): string;
37
+ /** 检查点:写前备份(docs/rewind-plan.md §2);钩子按约定不抛,这里再兜一层,不让编辑失败。 */
38
+ export declare function beforeWrite(ctx: ToolContext, abs: string): Promise<void>;
37
39
  export declare function executeEdit(input: EditInput, ctx: ToolContext): Promise<ToolResult>;
38
40
  export declare function createEditTool(): ToolDefinition<EditInput>;
@@ -164,6 +164,17 @@ function firstChangedLine(oldText, newText) {
164
164
  // ---------------------------------------------------------------------------
165
165
  // 工具
166
166
  // ---------------------------------------------------------------------------
167
+ /** 检查点:写前备份(docs/rewind-plan.md §2);钩子按约定不抛,这里再兜一层,不让编辑失败。 */
168
+ export async function beforeWrite(ctx, abs) {
169
+ if (ctx.checkpoint === undefined)
170
+ return;
171
+ try {
172
+ await ctx.checkpoint.beforeWrite(abs);
173
+ }
174
+ catch (error) {
175
+ ctx.log("warn", `checkpoint: ${error instanceof Error ? error.message : String(error)}`);
176
+ }
177
+ }
167
178
  export async function executeEdit(input, ctx) {
168
179
  const abs = resolvePath(input.path, ctx.cwd);
169
180
  const shown = displayPath(abs, ctx.cwd);
@@ -192,7 +203,10 @@ export async function executeEdit(input, ctx) {
192
203
  return { content: `${shown}: ${err.message}`, isError: true };
193
204
  throw err;
194
205
  }
195
- await writeFile(abs, bom + restoreLineEndings(plan.result, ending), "utf8");
206
+ const output = bom + restoreLineEndings(plan.result, ending);
207
+ await beforeWrite(ctx, abs);
208
+ await writeFile(abs, output, "utf8");
209
+ ctx.checkpoint?.afterWrite(abs, output);
196
210
  const details = {
197
211
  path: abs,
198
212
  diff: unifiedDiff(content, plan.result, shown),
@@ -209,8 +223,9 @@ export function createEditTool() {
209
223
  return {
210
224
  name: "edit",
211
225
  label: "Edit",
212
- description: "Replace text in a file (read it first). Each oldText must be unique in the original " +
213
- "(unless replaceAll); edits must not overlap.",
226
+ description: "Replace text in a file (read it first). Give all changes to a file as edits[] in one call; " +
227
+ "each oldText matches the original file and must be unique (unless replaceAll), short and " +
228
+ "non-overlapping.",
214
229
  parameters: {
215
230
  type: "object",
216
231
  properties: {
@@ -2,11 +2,15 @@
2
2
  * 图片文件(`read` 工具、`ama -p --image`、界面里的 `@图片路径` 共用):MIME 检测、尺寸、大小上限。
3
3
  *
4
4
  * - MIME 以文件头为准(PNG / JPEG / GIF / WebP),文件头认不出时退回扩展名;
5
- * - 单张上限 5 MB(各家图片上限里最小的 Anthropic);
5
+ * - [W5-I] 单张上限按 **base64 后**计算,按端点分档(ai/image-limits.ts,缺省 5 MB);任一边
6
+ * > 8000 px 拒绝;超限时按 `images.resize`(缺省 auto)用系统工具缩放(image-resize.ts),
7
+ * 没有工具则拒绝并提示;
6
8
  * - 不解码像素,只读文件头取尺寸。
7
9
  */
8
10
  import type { ImageBlock } from "../ai/types.js";
9
- export declare const MAX_IMAGE_BYTES: number;
11
+ import { type ResizeDeps } from "./image-resize.js";
12
+ /** 读进内存前的硬上限(原始字节):再大的文件缩放也不现实,直接拒绝。 */
13
+ export declare const MAX_IMAGE_FILE_BYTES: number;
10
14
  export declare const IMAGE_EXTENSIONS: Readonly<Record<string, string>>;
11
15
  /** 按扩展名(不分大小写);不是图片返回 undefined。 */
12
16
  export declare function imageMimeFromPath(path: string): string | undefined;
@@ -22,10 +26,41 @@ export interface LoadedImage {
22
26
  block: ImageBlock;
23
27
  path: string;
24
28
  mimeType: string;
29
+ /** 实际附上的字节数(缩放后为缩放结果的大小)。 */
25
30
  bytes: number;
26
31
  size?: ImageSize;
27
32
  }
33
+ export interface ImageFitOptions {
34
+ /** 单张 base64 后的上限(字节);缺省 5 MB(未知端点 / 中转)。 */
35
+ maxBase64Bytes?: number;
36
+ /** 超限时缩放:`auto`(缺省)找 sips / magick,`off` 从不缩放。 */
37
+ resize?: "auto" | "off";
38
+ /** 测试注入(平台、命令执行器)。 */
39
+ resizeDeps?: ResizeDeps;
40
+ }
41
+ export type ImageFit = {
42
+ ok: true;
43
+ buf: Buffer;
44
+ mimeType: string;
45
+ size?: ImageSize;
46
+ /** 缩放过:用的工具与原尺寸。 */
47
+ resized?: {
48
+ tool: string;
49
+ from?: ImageSize;
50
+ };
51
+ } | {
52
+ ok: false;
53
+ mimeType: string;
54
+ size?: ImageSize;
55
+ reason: "too_large" | "too_wide";
56
+ /** 给模型 / 日志的英文说明(read 工具原样放进结果)。 */
57
+ note: string;
58
+ };
59
+ /**
60
+ * 检查一张图是否在上限内(base64 后大小、边长);超限且给了 `path`、`resize` 不是 off 时先缩放再查。
61
+ */
62
+ export declare function fitImage(buf: Buffer, mimeType: string, options?: ImageFitOptions, path?: string): Promise<ImageFit>;
28
63
  /**
29
64
  * 读一张图片作为附件。文件不存在、不是图片、超过上限 → AmaError(`invalid_arguments`),文案给用户看。
30
65
  */
31
- export declare function loadImageFile(path: string): Promise<LoadedImage>;
66
+ export declare function loadImageFile(path: string, options?: ImageFitOptions): Promise<LoadedImage>;
@@ -2,13 +2,18 @@
2
2
  * 图片文件(`read` 工具、`ama -p --image`、界面里的 `@图片路径` 共用):MIME 检测、尺寸、大小上限。
3
3
  *
4
4
  * - MIME 以文件头为准(PNG / JPEG / GIF / WebP),文件头认不出时退回扩展名;
5
- * - 单张上限 5 MB(各家图片上限里最小的 Anthropic);
5
+ * - [W5-I] 单张上限按 **base64 后**计算,按端点分档(ai/image-limits.ts,缺省 5 MB);任一边
6
+ * > 8000 px 拒绝;超限时按 `images.resize`(缺省 auto)用系统工具缩放(image-resize.ts),
7
+ * 没有工具则拒绝并提示;
6
8
  * - 不解码像素,只读文件头取尺寸。
7
9
  */
8
10
  import { readFile, stat } from "node:fs/promises";
9
11
  import { extname } from "node:path";
10
12
  import { AmaError } from "../errors.js";
11
- export const MAX_IMAGE_BYTES = 5 * 1024 * 1024;
13
+ import { DEFAULT_IMAGE_BASE64_LIMIT, MAX_IMAGE_EDGE, base64Size, formatMb, } from "../ai/image-limits.js";
14
+ import { resizeImage } from "./image-resize.js";
15
+ /** 读进内存前的硬上限(原始字节):再大的文件缩放也不现实,直接拒绝。 */
16
+ export const MAX_IMAGE_FILE_BYTES = 64 * 1024 * 1024;
12
17
  export const IMAGE_EXTENSIONS = {
13
18
  ".png": "image/png",
14
19
  ".jpg": "image/jpeg",
@@ -84,10 +89,73 @@ function webpSize(buf) {
84
89
  }
85
90
  return undefined;
86
91
  }
92
+ function longEdge(size) {
93
+ return size === undefined ? 0 : Math.max(size.width, size.height);
94
+ }
95
+ function checkFit(buf, mimeType, limit) {
96
+ const size = imageSize(buf, mimeType);
97
+ const sized = size !== undefined ? { size } : {};
98
+ if (longEdge(size) > MAX_IMAGE_EDGE) {
99
+ return {
100
+ ok: false,
101
+ mimeType,
102
+ ...sized,
103
+ reason: "too_wide",
104
+ note: `Image is larger than ${MAX_IMAGE_EDGE}px on a side; not attached.`,
105
+ };
106
+ }
107
+ if (base64Size(buf.length) > limit) {
108
+ return {
109
+ ok: false,
110
+ mimeType,
111
+ ...sized,
112
+ reason: "too_large",
113
+ note: `Image exceeds the ${formatMb(limit)} attachment limit (base64); not attached.`,
114
+ };
115
+ }
116
+ return { ok: true, buf, mimeType, ...sized };
117
+ }
118
+ /**
119
+ * 检查一张图是否在上限内(base64 后大小、边长);超限且给了 `path`、`resize` 不是 off 时先缩放再查。
120
+ */
121
+ export async function fitImage(buf, mimeType, options = {}, path) {
122
+ const limit = options.maxBase64Bytes ?? DEFAULT_IMAGE_BASE64_LIMIT;
123
+ const fit = checkFit(buf, mimeType, limit);
124
+ if (fit.ok || path === undefined || options.resize === "off")
125
+ return fit;
126
+ const resized = await resizeImage(path, { maxEdge: MAX_IMAGE_EDGE, maxBase64Bytes: limit, mimeType, size: fit.size }, options.resizeDeps);
127
+ if (!resized.ok) {
128
+ const hint = resized.reason === "no_tool"
129
+ ? " (no resize tool found: install ImageMagick, or sips on macOS)"
130
+ : " (resizing did not bring it under the limit)";
131
+ return { ...fit, note: fit.note.replace(/; not attached\.$/, `${hint}; not attached.`) };
132
+ }
133
+ const again = checkFit(resized.buf, resized.mimeType, limit);
134
+ if (!again.ok)
135
+ return fit;
136
+ return {
137
+ ...again,
138
+ resized: { tool: resized.tool, ...(fit.size !== undefined ? { from: fit.size } : {}) },
139
+ };
140
+ }
141
+ function fitError(path, fit, limit, bytes, resizeOff) {
142
+ const hint = resizeOff
143
+ ? "(images.resize 为 off)"
144
+ : fit.note.includes("no resize tool")
145
+ ? "(没找到缩放工具:装 ImageMagick,macOS 自带 sips)"
146
+ : fit.note.includes("resizing did not")
147
+ ? "(缩放后仍超限)"
148
+ : "";
149
+ if (fit.reason === "too_wide") {
150
+ const dims = fit.size !== undefined ? `(${fit.size.width}×${fit.size.height})` : "";
151
+ return new AmaError("invalid_arguments", `图片任一边超过 ${MAX_IMAGE_EDGE} px:${path}${dims}${hint}`);
152
+ }
153
+ return new AmaError("invalid_arguments", `图片超过 ${formatMb(limit)} 上限(按 base64 后计算):${path}(${formatMb(base64Size(bytes))})${hint}`);
154
+ }
87
155
  /**
88
156
  * 读一张图片作为附件。文件不存在、不是图片、超过上限 → AmaError(`invalid_arguments`),文案给用户看。
89
157
  */
90
- export async function loadImageFile(path) {
158
+ export async function loadImageFile(path, options = {}) {
91
159
  let info;
92
160
  try {
93
161
  info = await stat(path);
@@ -97,18 +165,21 @@ export async function loadImageFile(path) {
97
165
  }
98
166
  if (!info.isFile())
99
167
  throw new AmaError("invalid_arguments", `不是文件:${path}`);
100
- if (info.size > MAX_IMAGE_BYTES)
101
- throw new AmaError("invalid_arguments", `图片超过 ${MAX_IMAGE_BYTES / 1024 / 1024} MB 上限:${path}(${(info.size / 1024 / 1024).toFixed(1)} MB)`);
168
+ const limit = options.maxBase64Bytes ?? DEFAULT_IMAGE_BASE64_LIMIT;
169
+ if (info.size > MAX_IMAGE_FILE_BYTES)
170
+ throw new AmaError("invalid_arguments", `图片超过 ${formatMb(limit)} 上限(按 base64 后计算):${path}(${formatMb(base64Size(info.size))})`);
102
171
  const buf = await readFile(path);
103
172
  const mimeType = sniffImageMime(buf) ?? imageMimeFromPath(path);
104
173
  if (mimeType === undefined)
105
174
  throw new AmaError("invalid_arguments", `不是支持的图片(PNG / JPEG / GIF / WebP):${path}`);
106
- const size = imageSize(buf, mimeType);
175
+ const fit = await fitImage(buf, mimeType, options, path);
176
+ if (!fit.ok)
177
+ throw fitError(path, fit, limit, buf.length, options.resize === "off");
107
178
  return {
108
- block: { type: "image", data: buf.toString("base64"), mimeType },
179
+ block: { type: "image", data: fit.buf.toString("base64"), mimeType: fit.mimeType },
109
180
  path,
110
- mimeType,
111
- bytes: buf.length,
112
- ...(size ? { size } : {}),
181
+ mimeType: fit.mimeType,
182
+ bytes: fit.buf.length,
183
+ ...(fit.size ? { size: fit.size } : {}),
113
184
  };
114
185
  }
@@ -0,0 +1,58 @@
1
+ /**
2
+ * 可选的图片缩放(docs/wave5-plan.md §4、D12)。[W5-I]
3
+ *
4
+ * 零依赖不能解码像素,只能调系统工具:macOS 依次试 `sips`、`magick`、`convert`;Linux 试
5
+ * `magick`、`convert`;Windows 只试 `magick`(`convert.exe` 是系统的磁盘转换工具)。都没有就返回
6
+ * `no_tool`,调用方按原规则拒绝并提示。只在超限时调用(`images.resize: "auto"`,缺省)。
7
+ *
8
+ * 输出写临时目录,读回后删掉;JPEG 保持 JPEG,其余格式输出 PNG(GIF 取第一帧)。边长先取
9
+ * min(目标边长, 原长边),体积仍超限就按 0.7 逐次缩小,最多 5 次。
10
+ */
11
+ import { type ImageSize } from "./image-file.js";
12
+ export interface CommandResult {
13
+ /** 进程退出码;命令不存在 / 无法启动为 null。 */
14
+ code: number | null;
15
+ stdout: Buffer;
16
+ stderr: string;
17
+ /** 命令不存在(ENOENT)。 */
18
+ missing?: boolean;
19
+ }
20
+ export type RunCommand = (command: string, args: readonly string[], options?: {
21
+ env?: NodeJS.ProcessEnv;
22
+ timeoutMs?: number;
23
+ }) => Promise<CommandResult>;
24
+ /** 缺省的命令执行器:execFile,stdout 按 Buffer 收,30 s 超时。 */
25
+ export declare const runCommand: RunCommand;
26
+ export interface ResizeTarget {
27
+ /** 长边上限(像素)。 */
28
+ maxEdge: number;
29
+ /** base64 后的体积上限(字节)。 */
30
+ maxBase64Bytes: number;
31
+ mimeType: string;
32
+ /** 原图尺寸(已知时用来定起始边长)。 */
33
+ size?: ImageSize | undefined;
34
+ }
35
+ export interface ResizeDeps {
36
+ platform?: NodeJS.Platform;
37
+ run?: RunCommand;
38
+ /** 临时目录的父目录;缺省 os.tmpdir()。 */
39
+ tmpDir?: string;
40
+ }
41
+ export interface ResizedImage {
42
+ ok: true;
43
+ buf: Buffer;
44
+ mimeType: string;
45
+ size?: ImageSize;
46
+ /** 用到的工具(`sips` / `magick` / `convert`)。 */
47
+ tool: string;
48
+ }
49
+ export interface ResizeFailure {
50
+ ok: false;
51
+ reason: "no_tool" | "failed";
52
+ }
53
+ /** 按平台的候选工具,靠前的先试。 */
54
+ export declare function resizeTools(platform: NodeJS.Platform): string[];
55
+ /**
56
+ * 把 `input` 缩到目标以内。`no_tool`:一个可用工具都没有;`failed`:工具能用但缩不到目标。
57
+ */
58
+ export declare function resizeImage(input: string, target: ResizeTarget, deps?: ResizeDeps): Promise<ResizedImage | ResizeFailure>;
@@ -0,0 +1,97 @@
1
+ /**
2
+ * 可选的图片缩放(docs/wave5-plan.md §4、D12)。[W5-I]
3
+ *
4
+ * 零依赖不能解码像素,只能调系统工具:macOS 依次试 `sips`、`magick`、`convert`;Linux 试
5
+ * `magick`、`convert`;Windows 只试 `magick`(`convert.exe` 是系统的磁盘转换工具)。都没有就返回
6
+ * `no_tool`,调用方按原规则拒绝并提示。只在超限时调用(`images.resize: "auto"`,缺省)。
7
+ *
8
+ * 输出写临时目录,读回后删掉;JPEG 保持 JPEG,其余格式输出 PNG(GIF 取第一帧)。边长先取
9
+ * min(目标边长, 原长边),体积仍超限就按 0.7 逐次缩小,最多 5 次。
10
+ */
11
+ import { execFile } from "node:child_process";
12
+ import { mkdtemp, readFile, rm } from "node:fs/promises";
13
+ import { tmpdir } from "node:os";
14
+ import { join } from "node:path";
15
+ import { base64Size } from "../ai/image-limits.js";
16
+ import { imageSize } from "./image-file.js";
17
+ /** 缺省的命令执行器:execFile,stdout 按 Buffer 收,30 s 超时。 */
18
+ export const runCommand = (command, args, options = {}) => new Promise((resolvePromise) => {
19
+ execFile(command, [...args], {
20
+ encoding: "buffer",
21
+ maxBuffer: 128 * 1024 * 1024,
22
+ timeout: options.timeoutMs ?? 30_000,
23
+ windowsHide: true,
24
+ ...(options.env !== undefined ? { env: options.env } : {}),
25
+ }, (error, stdout, stderr) => {
26
+ const err = error;
27
+ const missing = err !== null && err.code === "ENOENT";
28
+ const code = err === null ? 0 : typeof err.code === "number" ? err.code : missing ? null : 1;
29
+ resolvePromise({
30
+ code,
31
+ stdout: Buffer.isBuffer(stdout) ? stdout : Buffer.alloc(0),
32
+ stderr: Buffer.isBuffer(stderr) ? stderr.toString("utf8") : String(stderr ?? ""),
33
+ ...(missing ? { missing: true } : {}),
34
+ });
35
+ });
36
+ });
37
+ const MAX_ATTEMPTS = 5;
38
+ const SHRINK = 0.7;
39
+ const MIN_EDGE = 64;
40
+ /** 按平台的候选工具,靠前的先试。 */
41
+ export function resizeTools(platform) {
42
+ if (platform === "darwin")
43
+ return ["sips", "magick", "convert"];
44
+ if (platform === "win32")
45
+ return ["magick"];
46
+ return ["magick", "convert"];
47
+ }
48
+ function resizeArgs(tool, input, output, edge, format) {
49
+ if (tool === "sips")
50
+ return ["-Z", String(edge), "-s", "format", format, input, "--out", output];
51
+ // ImageMagick:`[0]` 取第一帧,`>` 只缩小不放大
52
+ return [`${input}[0]`, "-resize", `${edge}x${edge}>`, output];
53
+ }
54
+ /**
55
+ * 把 `input` 缩到目标以内。`no_tool`:一个可用工具都没有;`failed`:工具能用但缩不到目标。
56
+ */
57
+ export async function resizeImage(input, target, deps = {}) {
58
+ const run = deps.run ?? runCommand;
59
+ const format = target.mimeType === "image/jpeg" ? "jpeg" : "png";
60
+ const mimeType = format === "jpeg" ? "image/jpeg" : "image/png";
61
+ const long = target.size !== undefined ? Math.max(target.size.width, target.size.height) : 0;
62
+ const start = long > 0 ? Math.min(target.maxEdge, long) : target.maxEdge;
63
+ const dir = await mkdtemp(join(deps.tmpDir ?? tmpdir(), "ama-resize-"));
64
+ try {
65
+ for (const tool of resizeTools(deps.platform ?? process.platform)) {
66
+ let edge = start;
67
+ let worked = false;
68
+ for (let attempt = 0; attempt < MAX_ATTEMPTS && edge >= MIN_EDGE; attempt++) {
69
+ const output = join(dir, `out-${attempt}.${format === "jpeg" ? "jpg" : "png"}`);
70
+ const result = await run(tool, resizeArgs(tool, input, output, edge, format));
71
+ if (result.missing === true || result.code !== 0)
72
+ break;
73
+ let buf;
74
+ try {
75
+ buf = await readFile(output);
76
+ }
77
+ catch {
78
+ break;
79
+ }
80
+ worked = true;
81
+ const size = imageSize(buf, mimeType);
82
+ const longOut = size !== undefined ? Math.max(size.width, size.height) : 0;
83
+ if (base64Size(buf.length) <= target.maxBase64Bytes && longOut <= target.maxEdge) {
84
+ return { ok: true, buf, mimeType, tool, ...(size !== undefined ? { size } : {}) };
85
+ }
86
+ edge = Math.round(Math.min(edge, longOut > 0 ? longOut : edge) * SHRINK);
87
+ }
88
+ // 工具能用但缩不到目标:换工具也不会更好
89
+ if (worked)
90
+ return { ok: false, reason: "failed" };
91
+ }
92
+ return { ok: false, reason: "no_tool" };
93
+ }
94
+ finally {
95
+ await rm(dir, { recursive: true, force: true }).catch(() => undefined);
96
+ }
97
+ }
@@ -5,27 +5,57 @@
5
5
  * | ------------- | ----------------------------------------- |
6
6
  * | `default` | read、edit、write、bash、grep、glob |
7
7
  * | `minimal` | read、edit、write、bash |
8
- * | `codemode` | 只有 codemode(其余工具在脚本里调用) |
8
+ * | `codemode-only` | 只有 codemode(其余工具在脚本里调用) |
9
9
  * | `coordinator` | read + 宿主注册的工具 |
10
10
  *
11
11
  * - 预设只管**内置**工具;宿主 / SDK 注册的工具(`canvas_*` 等)总在活动集里,除非用户
12
12
  * `--tools a,b,c` 整组替换(之后只用列出的名字)。
13
13
  * - `tools.default`:`+name` / `-name` 在预设上增减;不带前缀的名字整组替换预设的内置工具,
14
14
  * 之后再应用带前缀的项。未注册的名字记 warning 并忽略。
15
- * - codemode 开关跟随预设:`codemode` 预设 → `only`,其余 → `off`;`codemode.mode` 显式配置覆盖。
16
- * - codemode 工具由 B10 经组装根的 `toolFactories` 注册(`codemode.mode` 为 off 时不注册);不可用
17
- * (例如 `codemode.requireStrict` 而运行时 Node 不隔离网络)时 codemode 预设**回退到 default 并
18
- * warning**(不报错:零配置用户不应因此起不来),`on` 同样忽略。
15
+ * - (D20)`todo` 不在 `default` 里:W5-C0 曾把它加进来,以 `bench-presets` 复测为门(费用增幅 ≤ 5% 且
16
+ * 成功率不降);W5-Z 用多步长任务复测(docs/benchmarks/presets-todo-2026-10-03.md)成功数下降 1、估价
17
+ * +4.6%、保守计价 +11.3%,按门撤回。计划批准后的进度改用 `[DONE:n]` 文本标记(plan/done-markers.ts);
18
+ * 要 todo 就 `tools.default: ["+todo"]`。
19
+ * - (W5-C0)`task_ctl` 与 `task` 同进退:`+task` 一起暴露、`-task` 一起去掉(`pairCompanions`)。
20
+ * - `codemode` 是 `codemode-only` 的旧名(0.3.0),配置合并与命令行解析时折成规范名。
21
+ * - codemode 开关跟随预设(`presetCodemodeMode`):`default` → `on`(只在沙箱 strict,即 Node ≥ 25 隔离
22
+ * 网络时;Node 22 / 24 → `off`),`codemode-only` → `only`,`minimal` / `coordinator` → `off`。
23
+ * `codemode.mode` 显式配置覆盖(缺省配置不写这个键,以后调整映射能惠及老用户)。
24
+ * - `coordinator` 预设即使显式 `on`,脚本里能调用的工具也只限活动集(read + 宿主工具),见
25
+ * `codemodeCallableFilter`:协调者「不写文件、不跑 bash」的约定不能经 codemode 绕过。
26
+ * - codemode 工具由 B10 经组装根的 `toolFactories` 注册(生效模式为 off 时不注册);不可用
27
+ * (例如 `codemode.requireStrict` 而运行时 Node 不隔离网络)时 codemode-only 预设**回退到 default 并
28
+ * warning**(不报错:零配置用户不应因此起不来),显式 `on` 同样忽略;跟随预设得到的 `on` 静默回退。
19
29
  * - `only` 模式活动集独占:宿主 / SDK 工具也不直接暴露,只能在脚本里调用(`exclusive`)。
20
30
  */
21
- import type { AmaConfig, CodemodeMode, ToolsPreset } from "../config/types.js";
31
+ import { type AmaConfig, type CodemodeMode, type ToolsPreset } from "../config/types.js";
22
32
  import { ToolRegistry } from "./registry.js";
23
33
  import type { ToolDefinition, ToolSource } from "./types.js";
24
34
  export declare const CODEMODE_TOOL = "codemode";
25
- /** 各预设下模型直接看到的内置工具(codemode 预设见 `resolvePreset`)。 */
35
+ /** 各预设下模型直接看到的内置工具(codemode-only 预设见 `resolvePreset`)。 */
26
36
  export declare const PRESET_TOOLS: Readonly<Record<ToolsPreset, readonly string[]>>;
37
+ /**
38
+ * 预设对应的 codemode 模式(没有显式 `codemode.mode` 时)。`default` 只在沙箱 strict(Node ≥ 25,
39
+ * 权限模型同时隔离网络)时开 `on`:Node 22 / 24 下 codemode 属 execute 类,每次都要审批,`-p` 下
40
+ * 直接被拒,所以缺省关闭(启动时提示一次,见 cli/codemode-notice.ts)。
41
+ */
42
+ export declare function presetCodemodeMode(preset: ToolsPreset, strict: boolean): CodemodeMode;
43
+ export interface CodemodeModeResolution {
44
+ mode: CodemodeMode;
45
+ /** `config`:显式 `codemode.mode`;`preset`:跟随预设。 */
46
+ source: "config" | "preset";
47
+ preset: ToolsPreset;
48
+ strict: boolean;
49
+ }
50
+ /** 生效的 codemode 模式及其来源;`strict` 缺省按运行时探测(测试与组装根可注入)。 */
51
+ export declare function resolveCodemodeMode(config: Pick<AmaConfig, "tools" | "codemode" | "sandbox">, strict?: boolean): CodemodeModeResolution;
27
52
  /** 生效的 codemode 模式:显式配置优先,否则跟随预设。 */
28
- export declare function effectiveCodemodeMode(config: Pick<AmaConfig, "tools" | "codemode">): CodemodeMode;
53
+ export declare function effectiveCodemodeMode(config: Pick<AmaConfig, "tools" | "codemode" | "sandbox">, strict?: boolean): CodemodeMode;
54
+ /**
55
+ * codemode 脚本里可调用工具的范围:`coordinator` 预设只能调活动集里的工具(`"active"`),其它预设
56
+ * 不限(`undefined`;`on` 模式下脚本还能调没直接暴露的 ls / task / todo 等)。
57
+ */
58
+ export declare function codemodeCallableFilter(config: Pick<AmaConfig, "tools">): "active" | undefined;
29
59
  /**
30
60
  * `tools.default` 微调:不带前缀的名字整组替换 `base`,再依次应用 `+name` / `-name`。
31
61
  * 返回去重后的名字(保持首次出现顺序)。
@@ -43,6 +73,8 @@ export declare function resolvePreset(input: {
43
73
  config: Pick<AmaConfig, "tools" | "codemode">;
44
74
  /** 该名字是否已注册(且未禁用)。 */
45
75
  available(name: string): boolean;
76
+ /** 沙箱是否 strict;缺省按运行时探测。 */
77
+ strict?: boolean;
46
78
  }): PresetResolution;
47
79
  type RegisterListener = (tool: ToolDefinition, source: ToolSource) => void;
48
80
  /**