@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
@@ -2,64 +2,106 @@
2
2
  * 上下文 token 估算(设计 §9「估算」)。[B2]
3
3
  *
4
4
  * `contextTokens` = 最后一条非 error / aborted 助手消息的 `totalTokens`(缺则
5
- * `input + output + cacheRead + cacheWrite`,**含 output**)+ 其后消息的估算(字符 / 4,图片 1 600)。
5
+ * `input + output + cacheRead + cacheWrite`,**含 output**)+ 其后消息的估算(图片 1 600)。
6
6
  * 若该 usage 之后活动分支上出现过 `context_edit` 或 `compaction`,usage 不再可信,按投影全量重估。
7
+ *
8
+ * [W5-H1] 文本估算按脚本区分(wave5 D28 / C10):CJK 统一表意文字(含扩展区与兼容区)、假名、
9
+ * 谚文、CJK 符号与全角形式每字 1 token,其余字符合计 / 4 向上取整。「字符 / 4」对中文低估 3–4 倍,
10
+ * 中文会话会晚触发直至溢出;所有阈值(档一、档二、保留区)都用这个口径。
7
11
  */
8
12
  export const IMAGE_TOKENS = 1600;
9
13
  const CHARS_PER_TOKEN = 4;
14
+ /** 按 1 token / 字计的码位(BMP 内)。 */
15
+ function isWideCode(code) {
16
+ return ((code >= 0x4e00 && code <= 0x9fff) || // CJK 统一表意文字
17
+ (code >= 0x3400 && code <= 0x4dbf) || // 扩展 A
18
+ (code >= 0xf900 && code <= 0xfaff) || // 兼容表意文字
19
+ (code >= 0x3040 && code <= 0x30ff) || // 平假名、片假名
20
+ (code >= 0x31f0 && code <= 0x31ff) || // 片假名音标扩展
21
+ (code >= 0xac00 && code <= 0xd7af) || // 谚文音节
22
+ (code >= 0x1100 && code <= 0x11ff) || // 谚文字母
23
+ (code >= 0x3130 && code <= 0x318f) || // 谚文兼容字母
24
+ (code >= 0x3000 && code <= 0x303f) || // CJK 符号与标点
25
+ (code >= 0xff00 && code <= 0xffef) // 半角与全角形式
26
+ );
27
+ }
28
+ /** 文本的 token 估算:CJK / 假名 / 谚文每字 1,其余字符 / 4(向上取整)。 */
29
+ export function estimateTextTokens(text) {
30
+ return tokensOf(countText(text, { wide: 0, narrow: 0 }));
31
+ }
32
+ function countText(text, into) {
33
+ let wide = 0;
34
+ let narrow = 0;
35
+ for (let i = 0; i < text.length; i++) {
36
+ const code = text.charCodeAt(i);
37
+ if (code < 0x1100)
38
+ narrow++;
39
+ else if (code >= 0xd840 && code <= 0xd87f) {
40
+ // 补充平面 CJK 扩展 B–F(U+20000–U+2FFFF)的代理对:整对算 1 个字
41
+ wide++;
42
+ i++;
43
+ }
44
+ else if (isWideCode(code))
45
+ wide++;
46
+ else
47
+ narrow++;
48
+ }
49
+ into.wide += wide;
50
+ into.narrow += narrow;
51
+ return into;
52
+ }
53
+ function tokensOf(count) {
54
+ return count.wide + Math.ceil(count.narrow / CHARS_PER_TOKEN);
55
+ }
10
56
  export function calculateContextTokens(usage) {
11
57
  return usage.totalTokens > 0
12
58
  ? usage.totalTokens
13
59
  : usage.input + usage.output + usage.cacheRead + usage.cacheWrite;
14
60
  }
15
- function contentChars(content) {
61
+ /** 内容的估算(文本按脚本,图片每张 1 600)。 */
62
+ export function estimateContentTokens(content) {
16
63
  if (typeof content === "string")
17
- return { chars: content.length, images: 0 };
18
- let chars = 0;
64
+ return estimateTextTokens(content);
65
+ const count = { wide: 0, narrow: 0 };
19
66
  let images = 0;
20
67
  for (const block of content) {
21
68
  if (block.type === "text")
22
- chars += block.text.length;
69
+ countText(block.text, count);
23
70
  else
24
71
  images++;
25
72
  }
26
- return { chars, images };
73
+ return tokensOf(count) + images * IMAGE_TOKENS;
27
74
  }
28
- /** 单条消息的估算(字符 / 4 向上取整,图片每张 1 600)。 */
75
+ /** 单条消息的估算(文本按脚本区分,图片每张 1 600)。 */
29
76
  export function estimateMessageTokens(message) {
30
- let chars = 0;
31
- let images = 0;
77
+ const count = { wide: 0, narrow: 0 };
32
78
  switch (message.role) {
33
79
  case "system":
34
80
  for (const text of Object.values(message.sections))
35
- chars += text?.length ?? 0;
81
+ countText(text ?? "", count);
36
82
  if (message.toolsAdded !== undefined)
37
- chars += JSON.stringify(message.toolsAdded).length;
83
+ countText(JSON.stringify(message.toolsAdded), count);
38
84
  break;
39
85
  case "user":
40
86
  case "toolResult":
41
- case "custom": {
42
- const counted = contentChars(message.content);
43
- chars = counted.chars;
44
- images = counted.images;
45
- break;
46
- }
87
+ case "custom":
88
+ return estimateContentTokens(message.content);
47
89
  case "assistant":
48
90
  for (const block of message.content) {
49
91
  if (block.type === "text")
50
- chars += block.text.length;
92
+ countText(block.text, count);
51
93
  else if (block.type === "thinking")
52
- chars += block.thinking.length;
94
+ countText(block.thinking, count);
53
95
  else
54
- chars += block.name.length + JSON.stringify(block.arguments).length;
96
+ countText(block.name + JSON.stringify(block.arguments), count);
55
97
  }
56
98
  break;
57
99
  case "compactionSummary":
58
100
  case "branchSummary":
59
- chars = message.summary.length;
101
+ countText(message.summary, count);
60
102
  break;
61
103
  }
62
- return Math.ceil(chars / CHARS_PER_TOKEN) + images * IMAGE_TOKENS;
104
+ return tokensOf(count);
63
105
  }
64
106
  export function estimateMessagesTokens(messages) {
65
107
  let total = 0;
@@ -0,0 +1,45 @@
1
+ /**
2
+ * 单请求图片总量预算(docs/wave5-plan.md §4、D11)。[W5-I] 纯函数,无模型调用。
3
+ *
4
+ * base64 图片在历史里每轮重发,几张截图就可能撞上 Anthropic 32 MB / Gemini 20 MB 的请求上限。
5
+ * `planImageBudget` 给出要降级的消息:调用方把每条写成 `context_edit{reason:"image_budget"}`,
6
+ * 之后前缀稳定(不是请求时临时处理),未命中归因把它当重置点。
7
+ *
8
+ * 规则(按投影顺序,最旧在前):
9
+ * 1. 单张超过 `perImageBytes`(换了更小上限的模型 / 中转)的消息必降——发出去必被拒;
10
+ * 2. 总量(含本回合新提示里的图 `reserve`)> 预算时,从最旧的开始降,直到 ≤ 预算 × 60%
11
+ * (一次多降一些,减少反复失效);
12
+ * 3. 图片数 > 20 且还有边长 > 2000 px 的图时,继续从最旧的开始降,直到不超过 20 张或没有大图;
13
+ * 规则 2、3 不降最新一条带图的消息(刚读的图要让模型看到)。降级以消息为单位:文本块原样保留,
14
+ * 每个图片块换成占位文本。
15
+ */
16
+ import type { ContentBlock, ImageBlock } from "../ai/types.js";
17
+ import type { ContextItem } from "../session/projection.js";
18
+ import { type ImageSize } from "../tools/image-file.js";
19
+ export declare const IMAGE_BUDGET_TARGET_RATIO = 0.6;
20
+ export declare const IMAGE_OMITTED_FOR_BUDGET = "[earlier image omitted to fit request size]";
21
+ export declare const IMAGE_OMITTED_TOO_LARGE = "[image omitted: larger than this endpoint's per-image limit]";
22
+ export interface ImageBudgetOptions {
23
+ /** 单张上限(base64 后);超过的必降。缺省不检查。 */
24
+ perImageBytes?: number;
25
+ /** 本回合即将发送、不能降级的图片(新提示里的附件):计入总量与张数。 */
26
+ reserve?: readonly ImageBlock[];
27
+ /** 降到预算的这个比例以下;缺省 0.6。 */
28
+ targetRatio?: number;
29
+ /** 测试注入:图片尺寸。缺省解 base64 读文件头。 */
30
+ sizeOf?(block: ImageBlock): ImageSize | undefined;
31
+ }
32
+ export interface ImageBudgetEdit {
33
+ targetId: string;
34
+ replacement: string;
35
+ /** `per_image`:单张超限;`budget`:总量;`many_images`:> 20 张时的边长。 */
36
+ cause: "per_image" | "budget" | "many_images";
37
+ /** 本条消息里被省略的图片数与 base64 字节。 */
38
+ images: number;
39
+ bytes: number;
40
+ }
41
+ /** 降级后的文本:文本块原样,图片块换成 `placeholder`,块间换行。 */
42
+ export declare function budgetReplacement(content: readonly ContentBlock[], placeholder?: string): string;
43
+ /** 解 base64 读文件头取尺寸(先解前 384 KB;JPEG 的 SOF 更靠后时再解全量);按块缓存。 */
44
+ export declare function base64ImageSize(block: ImageBlock): ImageSize | undefined;
45
+ export declare function planImageBudget(items: readonly ContextItem[], budgetBytes: number, options?: ImageBudgetOptions): ImageBudgetEdit[];
@@ -0,0 +1,115 @@
1
+ /**
2
+ * 单请求图片总量预算(docs/wave5-plan.md §4、D11)。[W5-I] 纯函数,无模型调用。
3
+ *
4
+ * base64 图片在历史里每轮重发,几张截图就可能撞上 Anthropic 32 MB / Gemini 20 MB 的请求上限。
5
+ * `planImageBudget` 给出要降级的消息:调用方把每条写成 `context_edit{reason:"image_budget"}`,
6
+ * 之后前缀稳定(不是请求时临时处理),未命中归因把它当重置点。
7
+ *
8
+ * 规则(按投影顺序,最旧在前):
9
+ * 1. 单张超过 `perImageBytes`(换了更小上限的模型 / 中转)的消息必降——发出去必被拒;
10
+ * 2. 总量(含本回合新提示里的图 `reserve`)> 预算时,从最旧的开始降,直到 ≤ 预算 × 60%
11
+ * (一次多降一些,减少反复失效);
12
+ * 3. 图片数 > 20 且还有边长 > 2000 px 的图时,继续从最旧的开始降,直到不超过 20 张或没有大图;
13
+ * 规则 2、3 不降最新一条带图的消息(刚读的图要让模型看到)。降级以消息为单位:文本块原样保留,
14
+ * 每个图片块换成占位文本。
15
+ */
16
+ import { MANY_IMAGES_COUNT, MANY_IMAGES_EDGE } from "../ai/image-limits.js";
17
+ import { imageSize } from "../tools/image-file.js";
18
+ export const IMAGE_BUDGET_TARGET_RATIO = 0.6;
19
+ export const IMAGE_OMITTED_FOR_BUDGET = "[earlier image omitted to fit request size]";
20
+ export const IMAGE_OMITTED_TOO_LARGE = "[image omitted: larger than this endpoint's per-image limit]";
21
+ function imagesOf(content) {
22
+ return content.filter((block) => block.type === "image");
23
+ }
24
+ function candidates(items) {
25
+ const out = [];
26
+ for (const { entry, message } of items) {
27
+ if (entry.type !== "message" && entry.type !== "custom_message")
28
+ continue;
29
+ if (message.role !== "user" && message.role !== "toolResult" && message.role !== "custom")
30
+ continue;
31
+ if (typeof message.content === "string")
32
+ continue;
33
+ const images = imagesOf(message.content);
34
+ if (images.length === 0)
35
+ continue;
36
+ const bytes = images.reduce((sum, image) => sum + image.data.length, 0);
37
+ out.push({ targetId: entry.id, content: message.content, images, bytes });
38
+ }
39
+ return out;
40
+ }
41
+ /** 降级后的文本:文本块原样,图片块换成 `placeholder`,块间换行。 */
42
+ export function budgetReplacement(content, placeholder = IMAGE_OMITTED_FOR_BUDGET) {
43
+ return content
44
+ .map((block) => (block.type === "text" ? block.text : placeholder))
45
+ .filter((text) => text !== "")
46
+ .join("\n");
47
+ }
48
+ const HEAD_CHARS = 512 * 1024;
49
+ const sizeCache = new WeakMap();
50
+ /** 解 base64 读文件头取尺寸(先解前 384 KB;JPEG 的 SOF 更靠后时再解全量);按块缓存。 */
51
+ export function base64ImageSize(block) {
52
+ const cached = sizeCache.get(block);
53
+ if (cached !== undefined)
54
+ return cached ?? undefined;
55
+ let size = imageSize(Buffer.from(block.data.slice(0, HEAD_CHARS), "base64"), block.mimeType);
56
+ if (size === undefined && block.data.length > HEAD_CHARS)
57
+ size = imageSize(Buffer.from(block.data, "base64"), block.mimeType);
58
+ sizeCache.set(block, size ?? null);
59
+ return size;
60
+ }
61
+ export function planImageBudget(items, budgetBytes, options = {}) {
62
+ const all = candidates(items);
63
+ const plan = [];
64
+ const drop = (c, cause) => {
65
+ const placeholder = cause === "per_image" ? IMAGE_OMITTED_TOO_LARGE : IMAGE_OMITTED_FOR_BUDGET;
66
+ plan.push({
67
+ targetId: c.targetId,
68
+ replacement: budgetReplacement(c.content, placeholder),
69
+ cause,
70
+ images: c.images.length,
71
+ bytes: c.bytes,
72
+ });
73
+ };
74
+ // 1. 单张超限
75
+ const perImage = options.perImageBytes;
76
+ const kept = [];
77
+ for (const c of all) {
78
+ if (perImage !== undefined && c.images.some((image) => image.data.length > perImage))
79
+ drop(c, "per_image");
80
+ else
81
+ kept.push(c);
82
+ }
83
+ const reserve = options.reserve ?? [];
84
+ let total = kept.reduce((sum, c) => sum + c.bytes, 0) +
85
+ reserve.reduce((sum, image) => sum + image.data.length, 0);
86
+ let count = kept.reduce((sum, c) => sum + c.images.length, 0) + reserve.length;
87
+ // 最新一条带图的消息不降
88
+ const droppable = kept.slice(0, -1);
89
+ let next = 0;
90
+ // 2. 总量
91
+ if (total > budgetBytes) {
92
+ const target = budgetBytes * (options.targetRatio ?? IMAGE_BUDGET_TARGET_RATIO);
93
+ while (total > target && next < droppable.length) {
94
+ const c = droppable[next++];
95
+ drop(c, "budget");
96
+ total -= c.bytes;
97
+ count -= c.images.length;
98
+ }
99
+ }
100
+ // 3. > 20 张时的边长
101
+ if (count > MANY_IMAGES_COUNT) {
102
+ const sizeOf = options.sizeOf ?? base64ImageSize;
103
+ const tooWide = (image) => {
104
+ const size = sizeOf(image);
105
+ return size !== undefined && Math.max(size.width, size.height) > MANY_IMAGES_EDGE;
106
+ };
107
+ const remaining = () => reserve.some(tooWide) || kept.slice(next).some((c) => c.images.some(tooWide));
108
+ while (count > MANY_IMAGES_COUNT && next < droppable.length && remaining()) {
109
+ const c = droppable[next++];
110
+ drop(c, "many_images");
111
+ count -= c.images.length;
112
+ }
113
+ }
114
+ return plan;
115
+ }
@@ -0,0 +1,38 @@
1
+ /**
2
+ * 压缩后回注(wave5 §8.2 C6,D26)。[W5-H1]
3
+ *
4
+ * 把压缩可能丢掉的关键状态以**清单与指针**放回上下文(不含文件正文):
5
+ * - todo 快照(分支上最近一条 `ama.todo`);
6
+ * - 当前计划(最近一条未被拒绝 / 取代的 `ama.plan`:编号、状态、文件路径与步骤标题);
7
+ * - 已加载的 Skill(用 `read` 读过的索引路径,或 `skill` 工具的调用);
8
+ * - 最近修改 / 读取的文件路径(按最近使用排序,各至多 20 个);
9
+ * - 完整转录与 `outputs/` 路径(模型需要细节时自己 `read`);
10
+ * - 续接说明。
11
+ *
12
+ * 放在哪:作为 `<post-compact-state>` 块接在 compaction 条目的 `summary` 末尾(与已有的
13
+ * `<read-files>` / `<modified-files>` 同一做法),模型看到的顺序就是「摘要 → 回注 → 保留区」。
14
+ * 不另写 `custom_message`:投影把 compaction 之后的条目放在保留区之后,溢出恢复时保留区以用户刚发
15
+ * 的提示结尾,追加在末尾的回注会排在那条提示后面、让模型先回应回注。压缩后本来就是新前缀,
16
+ * 回注不额外打断缓存。下一次增量摘要前先剥掉这个块(`stripPostCompact`),每次重新生成。
17
+ */
18
+ import type { SessionEntry } from "../session/types.js";
19
+ export declare const POST_COMPACT_TAG = "post-compact-state";
20
+ export declare const PLAN_CUSTOM_TYPE = "ama.plan";
21
+ export declare const MAX_RECENT_FILES = 20;
22
+ export interface PostCompactInput {
23
+ /** 活动分支(含刚追加的 compaction)。 */
24
+ branch: readonly SessionEntry[];
25
+ cwd: string;
26
+ /** Skill 索引里的文件路径(`skillLocations`)。 */
27
+ skillPaths?: readonly string[];
28
+ /** 会话转录文件;内存会话 undefined。 */
29
+ transcriptPath?: string | undefined;
30
+ /** 裁剪 / 截断全文目录。 */
31
+ outputDir?: string | undefined;
32
+ }
33
+ /** 去掉摘要里的回注块(上一份摘要作增量合并的输入前、模型照抄进新摘要时)。 */
34
+ export declare function stripPostCompact(summary: string): string;
35
+ /** 回注块(`<post-compact-state>…</post-compact-state>`);无任何可回注的状态时仍给出续接说明。 */
36
+ export declare function buildPostCompactBlock(input: PostCompactInput): string;
37
+ /** 回注正文。 */
38
+ export declare function buildPostCompactContent(input: PostCompactInput): string;
@@ -0,0 +1,152 @@
1
+ /**
2
+ * 压缩后回注(wave5 §8.2 C6,D26)。[W5-H1]
3
+ *
4
+ * 把压缩可能丢掉的关键状态以**清单与指针**放回上下文(不含文件正文):
5
+ * - todo 快照(分支上最近一条 `ama.todo`);
6
+ * - 当前计划(最近一条未被拒绝 / 取代的 `ama.plan`:编号、状态、文件路径与步骤标题);
7
+ * - 已加载的 Skill(用 `read` 读过的索引路径,或 `skill` 工具的调用);
8
+ * - 最近修改 / 读取的文件路径(按最近使用排序,各至多 20 个);
9
+ * - 完整转录与 `outputs/` 路径(模型需要细节时自己 `read`);
10
+ * - 续接说明。
11
+ *
12
+ * 放在哪:作为 `<post-compact-state>` 块接在 compaction 条目的 `summary` 末尾(与已有的
13
+ * `<read-files>` / `<modified-files>` 同一做法),模型看到的顺序就是「摘要 → 回注 → 保留区」。
14
+ * 不另写 `custom_message`:投影把 compaction 之后的条目放在保留区之后,溢出恢复时保留区以用户刚发
15
+ * 的提示结尾,追加在末尾的回注会排在那条提示后面、让模型先回应回注。压缩后本来就是新前缀,
16
+ * 回注不额外打断缓存。下一次增量摘要前先剥掉这个块(`stripPostCompact`),每次重新生成。
17
+ */
18
+ import { resolve } from "node:path";
19
+ import { TODO_CUSTOM_TYPE } from "../tools/todo.js";
20
+ export const POST_COMPACT_TAG = "post-compact-state";
21
+ export const PLAN_CUSTOM_TYPE = "ama.plan";
22
+ export const MAX_RECENT_FILES = 20;
23
+ const MAX_PLAN_STEPS = 20;
24
+ const MAX_LINE = 160;
25
+ const READ_TOOLS = new Set(["read"]);
26
+ const WRITE_TOOLS = new Set(["write", "edit"]);
27
+ function clip(text) {
28
+ const line = text.replace(/\s+/g, " ").trim();
29
+ return line.length > MAX_LINE ? `${line.slice(0, MAX_LINE - 1)}…` : line;
30
+ }
31
+ function lastCustom(branch, type, accept) {
32
+ for (let i = branch.length - 1; i >= 0; i--) {
33
+ const entry = branch[i];
34
+ if (entry?.type === "custom" && entry.customType === type) {
35
+ if (accept === undefined || accept(entry.data))
36
+ return entry.data;
37
+ }
38
+ }
39
+ return undefined;
40
+ }
41
+ const TODO_MARK = { pending: "[ ]", in_progress: "[~]", done: "[x]" };
42
+ function todoLines(branch) {
43
+ const data = lastCustom(branch, TODO_CUSTOM_TYPE);
44
+ const items = Array.isArray(data?.items) ? data.items : [];
45
+ const lines = [];
46
+ for (const item of items) {
47
+ if (typeof item?.["text"] !== "string")
48
+ continue;
49
+ const mark = TODO_MARK[String(item["status"])] ?? "[ ]";
50
+ lines.push(`${mark} ${String(item["id"] ?? "")}. ${clip(item["text"])}`);
51
+ }
52
+ return lines;
53
+ }
54
+ function planBlock(branch) {
55
+ const plan = lastCustom(branch, PLAN_CUSTOM_TYPE);
56
+ if (plan === undefined || typeof plan !== "object" || plan === null)
57
+ return undefined;
58
+ if (plan.status === "rejected" || plan.status === "superseded")
59
+ return undefined;
60
+ const attrs = [`id="${String(plan.id ?? "")}"`];
61
+ if (plan.version !== undefined)
62
+ attrs.push(`version="${String(plan.version)}"`);
63
+ if (plan.status !== undefined)
64
+ attrs.push(`status="${String(plan.status)}"`);
65
+ if (typeof plan.filePath === "string")
66
+ attrs.push(`file="${plan.filePath}"`);
67
+ const steps = Array.isArray(plan.steps) ? plan.steps : [];
68
+ const lines = steps
69
+ .slice(0, MAX_PLAN_STEPS)
70
+ .map((step) => `${String(step?.["id"] ?? "")} ${clip(String(step?.["text"] ?? ""))}`);
71
+ if (steps.length > MAX_PLAN_STEPS)
72
+ lines.push(`(+${steps.length - MAX_PLAN_STEPS} more steps)`);
73
+ return [`<plan ${attrs.join(" ")}>`, ...lines, "</plan>"].join("\n");
74
+ }
75
+ /** 按最近使用排序(最近的在前)的文件与 Skill。 */
76
+ function fileActivity(input) {
77
+ const skillSet = new Set((input.skillPaths ?? []).map((path) => resolve(input.cwd, path)));
78
+ const read = new Map();
79
+ const modified = new Map();
80
+ const skills = new Map();
81
+ let order = 0;
82
+ for (const entry of input.branch) {
83
+ if (entry.type !== "message" || entry.message.role !== "assistant")
84
+ continue;
85
+ for (const block of entry.message.content) {
86
+ if (block.type !== "toolCall")
87
+ continue;
88
+ order++;
89
+ if (block.name === "skill") {
90
+ const name = block.arguments["name"];
91
+ if (typeof name === "string")
92
+ skills.set(name, order);
93
+ continue;
94
+ }
95
+ const path = block.arguments["path"];
96
+ if (typeof path !== "string" || path === "")
97
+ continue;
98
+ const abs = resolve(input.cwd, path);
99
+ if (WRITE_TOOLS.has(block.name))
100
+ modified.set(path, order);
101
+ else if (READ_TOOLS.has(block.name)) {
102
+ if (skillSet.has(abs))
103
+ skills.set(abs, order);
104
+ else
105
+ read.set(path, order);
106
+ }
107
+ }
108
+ }
109
+ for (const path of modified.keys())
110
+ read.delete(path);
111
+ const recent = (map) => [...map.entries()].sort((a, b) => b[1] - a[1]).map(([key]) => key);
112
+ return { read: recent(read), modified: recent(modified), skills: recent(skills) };
113
+ }
114
+ function capped(paths) {
115
+ const shown = paths.slice(0, MAX_RECENT_FILES);
116
+ const more = paths.length - shown.length;
117
+ return more > 0 ? `${shown.join("\n")}\n(+${more} more)` : shown.join("\n");
118
+ }
119
+ const BLOCK_PATTERN = new RegExp(`\\s*<${POST_COMPACT_TAG}>[\\s\\S]*?</${POST_COMPACT_TAG}>`, "g");
120
+ /** 去掉摘要里的回注块(上一份摘要作增量合并的输入前、模型照抄进新摘要时)。 */
121
+ export function stripPostCompact(summary) {
122
+ return summary.replace(BLOCK_PATTERN, "").trimEnd();
123
+ }
124
+ /** 回注块(`<post-compact-state>…</post-compact-state>`);无任何可回注的状态时仍给出续接说明。 */
125
+ export function buildPostCompactBlock(input) {
126
+ return `<${POST_COMPACT_TAG}>\n${buildPostCompactContent(input)}\n</${POST_COMPACT_TAG}>`;
127
+ }
128
+ /** 回注正文。 */
129
+ export function buildPostCompactContent(input) {
130
+ const parts = [
131
+ "State to continue from after compaction (pointers only; read a file again only when you need its content):",
132
+ ];
133
+ const todo = todoLines(input.branch);
134
+ if (todo.length > 0)
135
+ parts.push(`<todo>\n${todo.join("\n")}\n</todo>`);
136
+ const plan = planBlock(input.branch);
137
+ if (plan !== undefined)
138
+ parts.push(plan);
139
+ const files = fileActivity(input);
140
+ if (files.skills.length > 0)
141
+ parts.push(`<loaded-skills>\n${capped(files.skills)}\n</loaded-skills>`);
142
+ if (files.modified.length > 0)
143
+ parts.push(`<recently-modified-files>\n${capped(files.modified)}\n</recently-modified-files>`);
144
+ if (files.read.length > 0)
145
+ parts.push(`<recently-read-files>\n${capped(files.read)}\n</recently-read-files>`);
146
+ if (input.transcriptPath !== undefined)
147
+ parts.push(`<transcript>${input.transcriptPath}</transcript> (full history before compaction, JSONL; read it only if the summary lacks a detail you need)`);
148
+ if (input.outputDir !== undefined)
149
+ parts.push(`<outputs>${input.outputDir}</outputs> (full text of pruned and truncated tool results)`);
150
+ parts.push("Continue from the summary's Next Steps and the todo list; do not redo finished work.");
151
+ return parts.join("\n\n");
152
+ }
@@ -0,0 +1,27 @@
1
+ /**
2
+ * 档一保护集(wave5 §8.2 C4)。[W5-H1]
3
+ *
4
+ * 不被档一换成占位的工具结果:
5
+ * - `todo`、`skill` 工具的结果(任务清单与 Skill 正文是长任务的骨架);
6
+ * - `read` 读入的 Skill 文件(系统提示 skills 节 `<location>` 里列出的路径)与 `AGENTS.md` / `CLAUDE.md`;
7
+ * - 声明了 `annotations.keepInContext` 的工具(宿主工具可用);
8
+ * - `compaction.pruneExclude` 列出的工具名。
9
+ */
10
+ import type { ContextItem } from "../session/projection.js";
11
+ import type { PruneCandidate } from "./prune-tier.js";
12
+ export declare const PROTECTED_TOOLS: readonly string[];
13
+ export declare const PROTECTED_FILE_NAMES: readonly string[];
14
+ export interface ProtectionInput {
15
+ cwd: string;
16
+ /** Skill 文件的绝对路径(见 `skillLocations`)。 */
17
+ skillPaths?: readonly string[];
18
+ /** `compaction.pruneExclude`。 */
19
+ exclude?: readonly string[];
20
+ /** 工具是否声明了 `annotations.keepInContext`。 */
21
+ keepInContext?(toolName: string): boolean;
22
+ }
23
+ /** 投影里最近一次给出 skills 节的 system 消息中的 `<location>`(索引里列出的 Skill 文件)。 */
24
+ export declare function skillLocations(items: readonly ContextItem[]): string[];
25
+ /** `read` 调用读的文件(绝对路径);不是 read 或缺 path 时 undefined。 */
26
+ export declare function readPathOf(candidate: Pick<PruneCandidate, "toolName" | "args">, cwd: string): string | undefined;
27
+ export declare function createProtection(input: ProtectionInput): (candidate: PruneCandidate) => boolean;
@@ -0,0 +1,56 @@
1
+ /**
2
+ * 档一保护集(wave5 §8.2 C4)。[W5-H1]
3
+ *
4
+ * 不被档一换成占位的工具结果:
5
+ * - `todo`、`skill` 工具的结果(任务清单与 Skill 正文是长任务的骨架);
6
+ * - `read` 读入的 Skill 文件(系统提示 skills 节 `<location>` 里列出的路径)与 `AGENTS.md` / `CLAUDE.md`;
7
+ * - 声明了 `annotations.keepInContext` 的工具(宿主工具可用);
8
+ * - `compaction.pruneExclude` 列出的工具名。
9
+ */
10
+ import { basename, resolve } from "node:path";
11
+ export const PROTECTED_TOOLS = ["todo", "skill"];
12
+ export const PROTECTED_FILE_NAMES = ["AGENTS.md", "CLAUDE.md"];
13
+ function unescapeXml(text) {
14
+ return text
15
+ .replace(/&lt;/g, "<")
16
+ .replace(/&gt;/g, ">")
17
+ .replace(/&quot;/g, '"')
18
+ .replace(/&apos;/g, "'")
19
+ .replace(/&amp;/g, "&");
20
+ }
21
+ /** 投影里最近一次给出 skills 节的 system 消息中的 `<location>`(索引里列出的 Skill 文件)。 */
22
+ export function skillLocations(items) {
23
+ for (let i = items.length - 1; i >= 0; i--) {
24
+ const message = items[i]?.message;
25
+ if (message?.role !== "system")
26
+ continue;
27
+ const section = message.sections["skills"];
28
+ if (section === undefined)
29
+ continue; // 补丁里没改这一节,往前找
30
+ if (section === null)
31
+ return []; // 这一节被移除
32
+ return [...section.matchAll(/<location>([^<]*)<\/location>/g)].map((m) => unescapeXml(m[1] ?? "").trim());
33
+ }
34
+ return [];
35
+ }
36
+ /** `read` 调用读的文件(绝对路径);不是 read 或缺 path 时 undefined。 */
37
+ export function readPathOf(candidate, cwd) {
38
+ if (candidate.toolName !== "read")
39
+ return undefined;
40
+ const path = candidate.args?.["path"];
41
+ return typeof path === "string" && path !== "" ? resolve(cwd, path) : undefined;
42
+ }
43
+ export function createProtection(input) {
44
+ const tools = new Set([...PROTECTED_TOOLS, ...(input.exclude ?? [])]);
45
+ const skills = new Set((input.skillPaths ?? []).map((path) => resolve(input.cwd, path)));
46
+ return (candidate) => {
47
+ if (tools.has(candidate.toolName))
48
+ return true;
49
+ if (input.keepInContext?.(candidate.toolName) === true)
50
+ return true;
51
+ const path = readPathOf(candidate, input.cwd);
52
+ if (path === undefined)
53
+ return false;
54
+ return skills.has(path) || PROTECTED_FILE_NAMES.includes(basename(path));
55
+ };
56
+ }
@@ -1,31 +1,77 @@
1
1
  /**
2
- * 档一裁剪(设计 §9「档一」):无模型调用。[B2]
2
+ * 档一裁剪(设计 §9「档一」,wave5 §8.2 C1 / C2 / C4 / C10):无模型调用。[B2][W5-H1]
3
3
  *
4
- * 触发:`contextTokens > 0.7 × (contextWindow − reserveTokens)`。
5
- * 范围:最近两个用户回合之前、内容 > 2 KiB 的 toolResult。
4
+ * 边界按**工具结果新旧**计(C1,修 G1:只有一条 user 消息的长任务以前永不触发):从最新往回数,
5
+ * 最近 `keepResults` 个结果与累计不超过 `protectTokens` 的结果不动;更早、估算 > 512 token、
6
+ * 不在保护集里的结果是候选。
7
+ * 门槛与回差(C2):候选合计可省 < `clearAtLeast` 不动;动就一次清到目标(调用方给 `need` =
8
+ * 当前 − 0.5×预算,且至少 `clearAtLeast`),从最旧的开始换,避免过线后每回合推进一点、每回合
9
+ * 打断一次缓存。缓存已冷时(C3,调用方判断)`need` 为 undefined:全部候选一次换掉。
10
+ * 保护集(C4):调用方给 `isProtected`(Skill 文件、AGENTS.md、todo、`keepInContext` 工具、
11
+ * `compaction.pruneExclude`),见 `protect.ts`。
6
12
  * 动作:返回 `context_edit{reason:"prune", replacement:"[已裁剪 …全文 path]"}` 计划;有 outputDir 时
7
13
  * 把全文写到 `<outputDir>/<toolCallId>.txt`(已存在则不覆盖),模型可用 read 取回。
8
14
  */
9
15
  import type { ContentBlock } from "../ai/types.js";
16
+ import type { PruneConfig } from "../config/types.js";
10
17
  import type { ContextItem } from "../session/projection.js";
11
- export declare const PRUNE_THRESHOLD_RATIO = 0.7;
12
- export declare const PRUNE_MIN_BYTES = 2048;
13
- export declare const PRUNE_KEEP_USER_TURNS = 2;
18
+ export declare const PRUNE_TRIGGER_RATIO = 0.7;
19
+ export declare const PRUNE_TARGET_RATIO = 0.5;
20
+ export declare const PRUNE_KEEP_RESULTS = 5;
21
+ /** 保护最近 min(40k, 0.2×预算) token 的工具输出。 */
22
+ export declare const PRUNE_PROTECT_TOKENS = 40000;
23
+ export declare const PRUNE_PROTECT_RATIO = 0.2;
24
+ /**
25
+ * `clearAtLeast: "auto"` = max(20k, 0.1×预算),但不超过 0.2×预算(= 触发线与目标之差;小窗口
26
+ * 模型上 20k 比这段差还大,档一就永远不会动)。
27
+ */
28
+ export declare const PRUNE_CLEAR_AT_LEAST = 20000;
29
+ export declare const PRUNE_CLEAR_AT_LEAST_RATIO = 0.1;
30
+ export declare const PRUNE_CLEAR_AT_LEAST_CAP_RATIO = 0.2;
31
+ /** 小于等于此估算 token 的结果不裁(占位本身也要几十 token)。 */
32
+ export declare const PRUNE_MIN_TOKENS = 512;
33
+ /** 由预算(窗口 − 预留)与配置得出的档一参数;只有 keepResults / clearAtLeast 进配置面(D27)。 */
34
+ export interface PrunePolicy {
35
+ keepResults: number;
36
+ protectTokens: number;
37
+ clearAtLeast: number;
38
+ minTokens: number;
39
+ /** 超过才按阈值裁(0.7×预算)。 */
40
+ triggerTokens: number;
41
+ /** 一次清到(0.5×预算)。 */
42
+ targetTokens: number;
43
+ }
44
+ export declare function prunePolicy(budget: number, config?: PruneConfig): PrunePolicy;
14
45
  export interface PrunePlanItem {
15
46
  targetId: string;
16
47
  replacement: string;
17
48
  toolCallId: string;
18
49
  originalBytes: number;
50
+ /** 估算可省的 token。 */
51
+ savedTokens: number;
19
52
  fullTextPath?: string;
20
53
  }
54
+ export interface PrunePlan {
55
+ items: PrunePlanItem[];
56
+ /** 本计划省下的 token(估算)。 */
57
+ savedTokens: number;
58
+ /** 全部候选合计可省(不足 clearAtLeast 时计划为空)。 */
59
+ availableTokens: number;
60
+ }
61
+ /** 保护集判断的输入:结果所属工具与调用参数(从同一投影里的助手消息找)。 */
62
+ export interface PruneCandidate {
63
+ toolName: string;
64
+ args: Record<string, unknown> | undefined;
65
+ }
21
66
  export interface PruneOptions {
22
- keepUserTurns?: number;
23
- minBytes?: number;
67
+ policy: Pick<PrunePolicy, "keepResults" | "protectTokens" | "clearAtLeast" | "minTokens">;
68
+ /** 至少要省多少才到目标;undefined = 全部候选(缓存已冷)。实际至少 clearAtLeast。 */
69
+ need?: number | undefined;
24
70
  /** 全文落盘目录;undefined 时不落盘(内存会话)。 */
25
71
  outputDir?: string | undefined;
72
+ /** 保护集(C4):返回 true 的结果不裁。 */
73
+ isProtected?(candidate: PruneCandidate): boolean;
26
74
  }
27
- export declare function pruneThreshold(contextWindow: number, reserveTokens: number): number;
28
- export declare function shouldPrune(tokens: number, contextWindow: number, reserveTokens: number): boolean;
29
75
  export declare function contentToText(content: string | readonly ContentBlock[]): string;
30
- /** 计算裁剪计划(并按需落盘全文);返回空数组表示无可裁剪项。 */
31
- export declare function planPrune(items: readonly ContextItem[], options?: PruneOptions): PrunePlanItem[];
76
+ /** 计算裁剪计划(并为选中项落盘全文);`items` 为空表示不裁。 */
77
+ export declare function planPrune(items: readonly ContextItem[], options: PruneOptions): PrunePlan;