@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,13 @@
1
+ /**
2
+ * `ama sessions search <关键词|/正则/>`:跨会话全文检索(只读)。[W4-D]
3
+ *
4
+ * - 范围:缺省当前目录的会话,`--all` 全部;`--role user|assistant|tool`(可逗号分隔多个);
5
+ * `--since 7d|today|YYYY-MM-DD`;`--limit N`(缺省 20);`--json` 每条命中一行 JSON。
6
+ * - 输出一行一条:会话 id 前 8 位、条目时间、项目、角色与编号(user 是 `#n`,可直接给 `--from <id>#n`;
7
+ * 其它角色是条目序号 `@k`)、命中片段。stdout 是 TTY 且没设 NO_COLOR 时用 ANSI 高亮,否则纯文本。
8
+ */
9
+ import { type SearchHit } from "../../session/search.js";
10
+ import type { CliIo } from "../deps.js";
11
+ export declare const SESSIONS_SEARCH_USAGE = "\u7528\u6CD5\uFF1Aama sessions search <\u5173\u952E\u8BCD|/\u6B63\u5219/\u6807\u5FD7> [--all] [--role user|assistant|tool]\n [--since 7d|today|YYYY-MM-DD] [--limit N] [--json] [--session-dir <\u76EE\u5F55>]\n";
12
+ export declare function renderHit(hit: SearchHit, color: boolean): string;
13
+ export declare function runSessionsSearch(argv: readonly string[], io: CliIo): Promise<number>;
@@ -0,0 +1,103 @@
1
+ /**
2
+ * `ama sessions search <关键词|/正则/>`:跨会话全文检索(只读)。[W4-D]
3
+ *
4
+ * - 范围:缺省当前目录的会话,`--all` 全部;`--role user|assistant|tool`(可逗号分隔多个);
5
+ * `--since 7d|today|YYYY-MM-DD`;`--limit N`(缺省 20);`--json` 每条命中一行 JSON。
6
+ * - 输出一行一条:会话 id 前 8 位、条目时间、项目、角色与编号(user 是 `#n`,可直接给 `--from <id>#n`;
7
+ * 其它角色是条目序号 `@k`)、命中片段。stdout 是 TTY 且没设 NO_COLOR 时用 ANSI 高亮,否则纯文本。
8
+ */
9
+ import { join, resolve } from "node:path";
10
+ import { expandHome, resolveDataDir } from "../../config/paths.js";
11
+ import { sessionFilesInScope } from "../../session/scan.js";
12
+ import { compileQuery, searchSessions, } from "../../session/search.js";
13
+ import { parseSubArgs, UsageError } from "../args.js";
14
+ import { ExitCode } from "../exit-codes.js";
15
+ import { parseDaySpec } from "./stats.js";
16
+ export const SESSIONS_SEARCH_USAGE = `用法:ama sessions search <关键词|/正则/标志> [--all] [--role user|assistant|tool]
17
+ [--since 7d|today|YYYY-MM-DD] [--limit N] [--json] [--session-dir <目录>]
18
+ `;
19
+ const ROLES = ["user", "assistant", "tool"];
20
+ function highlight(text, ranges, color) {
21
+ if (!color || ranges.length === 0)
22
+ return text;
23
+ let out = "";
24
+ let at = 0;
25
+ for (const [a, b] of ranges) {
26
+ if (a < at)
27
+ continue;
28
+ out += text.slice(at, a) + `\x1b[1;33m${text.slice(a, b)}\x1b[0m`;
29
+ at = b;
30
+ }
31
+ return out + text.slice(at);
32
+ }
33
+ function shortTime(iso) {
34
+ return iso
35
+ .replace("T", " ")
36
+ .replace(/\.\d+Z$|Z$/, "")
37
+ .slice(0, 16);
38
+ }
39
+ export function renderHit(hit, color) {
40
+ const ref = hit.userN !== undefined ? `#${hit.userN}` : `@${hit.entryIndex}`;
41
+ const dim = (s) => (color ? `\x1b[2m${s}\x1b[0m` : s);
42
+ return `${hit.sessionId.slice(0, 8)}${ref.padEnd(4)} ${dim(shortTime(hit.timestamp))} ${dim(hit.cwd)} ${hit.role.padEnd(9)} ${highlight(hit.snippet, hit.ranges, color)}\n`;
43
+ }
44
+ export async function runSessionsSearch(argv, io) {
45
+ const { positionals, values, flags } = parseSubArgs(argv, ["role", "since", "limit", "session-dir"], ["all", "json"]);
46
+ if (flags.has("help")) {
47
+ io.stdout(SESSIONS_SEARCH_USAGE);
48
+ return ExitCode.Ok;
49
+ }
50
+ const pattern = positionals.join(" ");
51
+ if (pattern.trim() === "")
52
+ throw new UsageError("ama sessions search 需要关键词或 /正则/");
53
+ let query;
54
+ try {
55
+ query = compileQuery(pattern);
56
+ }
57
+ catch (error) {
58
+ throw new UsageError(`正则无效:${error.message}`);
59
+ }
60
+ let roles;
61
+ const roleRaw = values.get("role");
62
+ if (roleRaw !== undefined) {
63
+ roles = new Set();
64
+ for (const role of roleRaw.split(",").map((r) => r.trim())) {
65
+ if (!ROLES.includes(role)) {
66
+ throw new UsageError(`--role 的取值应为 ${ROLES.join(" | ")}(收到 ${role})`);
67
+ }
68
+ roles.add(role);
69
+ }
70
+ }
71
+ const limit = Number(values.get("limit") ?? "20");
72
+ if (!Number.isInteger(limit) || limit < 1)
73
+ throw new UsageError("--limit 应为正整数");
74
+ const sinceRaw = values.get("since");
75
+ const sinceIso = sinceRaw === undefined
76
+ ? undefined
77
+ : new Date(`${parseDaySpec("since", sinceRaw)}T00:00:00`).toISOString();
78
+ const dirFlag = values.get("session-dir");
79
+ const root = dirFlag !== undefined
80
+ ? resolve(io.cwd, expandHome(dirFlag, { env: io.env }))
81
+ : join(resolveDataDir({ env: io.env }), "sessions");
82
+ const files = sessionFilesInScope(root, flags.has("all") ? undefined : io.cwd);
83
+ const { hits, truncated } = searchSessions(files, query, {
84
+ limit,
85
+ ...(roles !== undefined ? { roles } : {}),
86
+ ...(sinceIso !== undefined ? { sinceIso } : {}),
87
+ });
88
+ if (flags.has("json")) {
89
+ for (const hit of hits)
90
+ io.stdout(`${JSON.stringify(hit)}\n`);
91
+ return ExitCode.Ok;
92
+ }
93
+ if (hits.length === 0) {
94
+ io.stdout(flags.has("all") ? "没有命中\n" : "没有命中(只搜了当前目录的会话,--all 搜全部)\n");
95
+ return ExitCode.Ok;
96
+ }
97
+ const color = io.stdoutIsTTY && (io.env["NO_COLOR"] ?? "") === "";
98
+ for (const hit of hits)
99
+ io.stdout(renderHit(hit, color));
100
+ if (truncated)
101
+ io.stdout(`(已到 --limit ${limit},可能还有更多)\n`);
102
+ return ExitCode.Ok;
103
+ }
@@ -3,9 +3,12 @@
3
3
  *
4
4
  * 会话存储是 B2 的实现,经 RuntimeDeps.sessions 注入;这里只做参数、目录解析与输出格式。
5
5
  * - list [--all]:缺省只列当前目录的会话;`--all` 列全部。
6
- * - show <id>:头信息 + 条目类型统计 + 首条提示。
7
- * - prune [--older-than <天>] [--dry-run]:缺省 30 天,移到 trash(不删除)。
6
+ * - show <id>:头信息 + 条目类型统计 + 首条提示 + 用户消息编号(`--from <id>#<编号>` 复用)。
7
+ * - search / export:见 sessions-search.ts、sessions-export.ts(只读扫描,不经会话存储)。
8
+ * - prune [--older-than <天>] [--dry-run]:缺省 30 天,移到 trash(不删除);之后清理检查点备份
9
+ * (未被任何会话引用且超过 1 天的 blob,docs/rewind-plan.md §1.4)与超过 7 天的剪贴板图片
10
+ * (`<数据目录>/clipboard/`,W5-I),`--dry-run` 时只报告。
8
11
  */
9
12
  import type { CliIo, RuntimeDeps } from "../deps.js";
10
- export declare const SESSIONS_USAGE = "\u7528\u6CD5\uFF1Aama sessions list [--all] [--session-dir <\u76EE\u5F55>]\n ama sessions show <id> [--session-dir <\u76EE\u5F55>]\n ama sessions prune [--older-than <\u5929>] [--dry-run] [--all] [--session-dir <\u76EE\u5F55>]\n";
13
+ export declare const SESSIONS_USAGE = "\u7528\u6CD5\uFF1Aama sessions list [--all] [--session-dir <\u76EE\u5F55>]\n ama sessions show <id> [--session-dir <\u76EE\u5F55>]\n ama sessions prune [--older-than <\u5929>] [--dry-run] [--all] [--session-dir <\u76EE\u5F55>]\n ama sessions search <\u5173\u952E\u8BCD|/\u6B63\u5219/> [--all] [--role user|assistant|tool] [--since 7d] [--limit N]\n ama sessions export <id> [--format md|json|jsonl] [--output <\u6587\u4EF6>] [--branch leaf|all]\n";
11
14
  export declare function runSessions(argv: readonly string[], io: CliIo, deps: Pick<RuntimeDeps, "sessions"> | undefined): Promise<number>;
@@ -3,16 +3,26 @@
3
3
  *
4
4
  * 会话存储是 B2 的实现,经 RuntimeDeps.sessions 注入;这里只做参数、目录解析与输出格式。
5
5
  * - list [--all]:缺省只列当前目录的会话;`--all` 列全部。
6
- * - show <id>:头信息 + 条目类型统计 + 首条提示。
7
- * - prune [--older-than <天>] [--dry-run]:缺省 30 天,移到 trash(不删除)。
6
+ * - show <id>:头信息 + 条目类型统计 + 首条提示 + 用户消息编号(`--from <id>#<编号>` 复用)。
7
+ * - search / export:见 sessions-search.ts、sessions-export.ts(只读扫描,不经会话存储)。
8
+ * - prune [--older-than <天>] [--dry-run]:缺省 30 天,移到 trash(不删除);之后清理检查点备份
9
+ * (未被任何会话引用且超过 1 天的 blob,docs/rewind-plan.md §1.4)与超过 7 天的剪贴板图片
10
+ * (`<数据目录>/clipboard/`,W5-I),`--dry-run` 时只报告。
8
11
  */
9
- import { resolve } from "node:path";
12
+ import { join, resolve } from "node:path";
13
+ import { formatBytes, gcBlobs } from "../../checkpoints/gc.js";
10
14
  import { expandHome, resolveDataDir } from "../../config/paths.js";
11
15
  import { parseSubArgs, UsageError } from "../args.js";
12
16
  import { ExitCode } from "../exit-codes.js";
17
+ import { numberUserMessages } from "../../session/reuse.js";
18
+ import { gcClipboardImages } from "../../tools/clipboard-image.js";
19
+ import { runSessionsExport } from "./sessions-export.js";
20
+ import { runSessionsSearch } from "./sessions-search.js";
13
21
  export const SESSIONS_USAGE = `用法:ama sessions list [--all] [--session-dir <目录>]
14
22
  ama sessions show <id> [--session-dir <目录>]
15
23
  ama sessions prune [--older-than <天>] [--dry-run] [--all] [--session-dir <目录>]
24
+ ama sessions search <关键词|/正则/> [--all] [--role user|assistant|tool] [--since 7d] [--limit N]
25
+ ama sessions export <id> [--format md|json|jsonl] [--output <文件>] [--branch leaf|all]
16
26
  `;
17
27
  function shortTime(iso) {
18
28
  return iso.replace("T", " ").replace(/\.\d+Z$|Z$/, "");
@@ -24,6 +34,10 @@ function oneLine(text, max = 60) {
24
34
  return flat.length > max ? `${flat.slice(0, max - 1)}…` : flat;
25
35
  }
26
36
  export async function runSessions(argv, io, deps) {
37
+ if (argv[0] === "search")
38
+ return runSessionsSearch(argv.slice(1), io);
39
+ if (argv[0] === "export")
40
+ return runSessionsExport(argv.slice(1), io);
27
41
  const { positionals, values, flags } = parseSubArgs(argv, ["session-dir", "older-than"], ["all", "dry-run"]);
28
42
  const action = positionals[0];
29
43
  if (flags.has("help") || action === undefined) {
@@ -73,6 +87,17 @@ export async function runSessions(argv, io, deps) {
73
87
  ? [`首条提示:${oneLine(item.firstPrompt, 200)}`]
74
88
  : []),
75
89
  ].join("\n") + "\n");
90
+ const users = numberUserMessages(entries);
91
+ if (users.length > 0) {
92
+ io.stdout(`用户消息(ama --from ${item.id.slice(0, 8)}#<编号> 复用):\n`);
93
+ for (const user of users) {
94
+ const tags = [
95
+ ...(user.origin !== undefined ? [`[${user.origin}]`] : []),
96
+ ...(user.images.length > 0 ? [`[图片 ${user.images.length}]`] : []),
97
+ ];
98
+ io.stdout(` #${String(user.n).padEnd(3)} ${shortTime(user.timestamp)} ${[...tags, oneLine(user.text, 100)].join(" ")}\n`);
99
+ }
100
+ }
76
101
  return ExitCode.Ok;
77
102
  }
78
103
  case "prune": {
@@ -88,12 +113,42 @@ export async function runSessions(argv, io, deps) {
88
113
  for (const file of moved)
89
114
  io.stdout(`${dryRun ? "将移到 trash" : "已移到 trash"}:${file}\n`);
90
115
  io.stdout(`${moved.length} 个会话${dryRun ? "(演练,未改动)" : ""}\n`);
116
+ await pruneFileHistory(io, sessionDir, dryRun);
117
+ await pruneClipboard(io, dryRun);
91
118
  return ExitCode.Ok;
92
119
  }
93
120
  default:
94
121
  throw new UsageError(`未知的 sessions 子命令:${action}`);
95
122
  }
96
123
  }
124
+ /** 检查点备份 GC:扫描本次的会话目录、缺省会话目录与登记过的目录。失败只提示,不影响 prune。 */
125
+ async function pruneFileHistory(io, sessionDir, dryRun) {
126
+ const dataDir = resolveDataDir({ env: io.env });
127
+ try {
128
+ const result = await gcBlobs({
129
+ dataDir,
130
+ sessionRoots: [sessionDir, join(dataDir, "sessions")],
131
+ dryRun,
132
+ });
133
+ if (result.removed.length === 0)
134
+ return;
135
+ io.stdout(`file-history:${dryRun ? "将清除" : "已清除"} ${result.removed.length} 个未引用的备份(${formatBytes(result.removedBytes)})\n`);
136
+ }
137
+ catch (error) {
138
+ io.stderr(`ama: file-history 清理跳过(${error instanceof Error ? error.message : String(error)})\n`);
139
+ }
140
+ }
141
+ /** [W5-I] `<数据目录>/clipboard/` 超过 7 天的剪贴板图片。失败只提示。 */
142
+ async function pruneClipboard(io, dryRun) {
143
+ try {
144
+ const removed = await gcClipboardImages(resolveDataDir({ env: io.env }), { dryRun });
145
+ if (removed.length > 0)
146
+ io.stdout(`clipboard:${dryRun ? "将清除" : "已清除"} ${removed.length} 个超过 7 天的剪贴板图片\n`);
147
+ }
148
+ catch (error) {
149
+ io.stderr(`ama: clipboard 清理跳过(${error instanceof Error ? error.message : String(error)})\n`);
150
+ }
151
+ }
97
152
  function notWired(io, what) {
98
153
  io.stderr(`ama: ${what} 尚未装配(会话存储由集成批次注入)\n`);
99
154
  return ExitCode.RuntimeError;
@@ -0,0 +1,17 @@
1
+ /**
2
+ * `ama stats`:跨会话的用量统计(只读扫描会话 JSONL)。[W4-D]
3
+ *
4
+ * - 范围:缺省当前目录的会话;`--project <目录>` 指定项目;`--all` 全部(`--by project` 未指定范围时也看全部)。
5
+ * - 时间:`--since` / `--until` 接受 `7d`(含今天的最近 7 天)、`today`、`YYYY-MM-DD`(本地日期,含当天)。
6
+ * - 分组:`--by day|week|month|provider|channel|model|project`。
7
+ * - 缓存:`<数据目录>/stats-index.json`,按文件 mtime / size 失效;`--no-cache` 不读也不写。
8
+ * - 口径见 session/stats-aggregate.ts 与 docs/sessions.md「统计」。
9
+ */
10
+ import { type StatsReport } from "../../session/stats-aggregate.js";
11
+ import type { CliIo } from "../deps.js";
12
+ export declare const STATS_USAGE = "\u7528\u6CD5\uFF1Aama stats [--since 7d|30d|today|YYYY-MM-DD] [--until \u2026]\n [--by day|week|month|provider|channel|model|project]\n [--project <\u76EE\u5F55> | --all] [--top N] [--json] [--no-cache] [--session-dir <\u76EE\u5F55>]\n";
13
+ /** `7d` / `today` / `YYYY-MM-DD` → 本地日期。 */
14
+ export declare function parseDaySpec(option: string, raw: string, now?: Date): string;
15
+ export declare function formatTokens(count: number): string;
16
+ export declare function renderStats(report: StatsReport, scope: string): string;
17
+ export declare function runStats(argv: readonly string[], io: CliIo): Promise<number>;
@@ -0,0 +1,198 @@
1
+ /**
2
+ * `ama stats`:跨会话的用量统计(只读扫描会话 JSONL)。[W4-D]
3
+ *
4
+ * - 范围:缺省当前目录的会话;`--project <目录>` 指定项目;`--all` 全部(`--by project` 未指定范围时也看全部)。
5
+ * - 时间:`--since` / `--until` 接受 `7d`(含今天的最近 7 天)、`today`、`YYYY-MM-DD`(本地日期,含当天)。
6
+ * - 分组:`--by day|week|month|provider|channel|model|project`。
7
+ * - 缓存:`<数据目录>/stats-index.json`,按文件 mtime / size 失效;`--no-cache` 不读也不写。
8
+ * - 口径见 session/stats-aggregate.ts 与 docs/sessions.md「统计」。
9
+ */
10
+ import { join, resolve } from "node:path";
11
+ import { expandHome, resolveDataDir } from "../../config/paths.js";
12
+ import { sessionFilesInScope } from "../../session/scan.js";
13
+ import { STATS_GROUPS, aggregateStats, } from "../../session/stats-aggregate.js";
14
+ import { STATS_INDEX_FILE, collectSummaries } from "../../session/stats-index.js";
15
+ import { localDay } from "../../session/stats-scan.js";
16
+ import { parseSubArgs, UsageError } from "../args.js";
17
+ import { ExitCode } from "../exit-codes.js";
18
+ export const STATS_USAGE = `用法:ama stats [--since 7d|30d|today|YYYY-MM-DD] [--until …]
19
+ [--by day|week|month|provider|channel|model|project]
20
+ [--project <目录> | --all] [--top N] [--json] [--no-cache] [--session-dir <目录>]
21
+ `;
22
+ /** `7d` / `today` / `YYYY-MM-DD` → 本地日期。 */
23
+ export function parseDaySpec(option, raw, now = new Date()) {
24
+ if (raw === "today")
25
+ return localDay(now.toISOString()) ?? "";
26
+ const rel = /^(\d+)d$/.exec(raw);
27
+ if (rel !== null) {
28
+ const days = Number(rel[1]);
29
+ if (days < 1)
30
+ throw new UsageError(`--${option} 的天数至少为 1(收到 ${raw})`);
31
+ const d = new Date(now);
32
+ d.setDate(d.getDate() - (days - 1));
33
+ return localDay(d.toISOString()) ?? "";
34
+ }
35
+ if (/^\d{4}-\d{2}-\d{2}$/.test(raw) && Number.isFinite(Date.parse(`${raw}T00:00:00`)))
36
+ return raw;
37
+ throw new UsageError(`--${option} 应为 7d、today 或 YYYY-MM-DD(收到 ${raw})`);
38
+ }
39
+ export function formatTokens(count) {
40
+ const trim = (text) => text.replace(/\.?0+$/, "");
41
+ if (count < 1000)
42
+ return String(Math.round(count));
43
+ if (count < 100_000)
44
+ return `${trim((count / 1000).toFixed(1))}k`;
45
+ if (count < 1_000_000)
46
+ return `${Math.round(count / 1000)}k`;
47
+ return `${trim((count / 1_000_000).toFixed(2))}M`;
48
+ }
49
+ const percent = (rate) => rate === undefined ? "—" : `${(rate * 100).toFixed(1)}%`;
50
+ const usd = (t) => {
51
+ if (t.cost === undefined)
52
+ return "—";
53
+ return t.cost >= 1 || t.cost === 0 ? `$${t.cost.toFixed(2)}` : `$${t.cost.toFixed(4)}`;
54
+ };
55
+ function seconds(ms) {
56
+ if (ms === undefined)
57
+ return "—";
58
+ return ms < 60_000 ? `${(ms / 1000).toFixed(1)}s` : `${(ms / 60_000).toFixed(1)}m`;
59
+ }
60
+ function width(text) {
61
+ let w = 0;
62
+ for (const ch of text)
63
+ w += (ch.codePointAt(0) ?? 0) > 0x2e7f ? 2 : 1;
64
+ return w;
65
+ }
66
+ function table(rows, rightAlign) {
67
+ const widths = [];
68
+ for (const row of rows)
69
+ row.forEach((cell, i) => (widths[i] = Math.max(widths[i] ?? 0, width(cell))));
70
+ return rows
71
+ .map((row) => row
72
+ .map((cell, i) => {
73
+ const padding = " ".repeat((widths[i] ?? 0) - width(cell));
74
+ return rightAlign(i) ? padding + cell : cell + padding;
75
+ })
76
+ .join(" ")
77
+ .trimEnd())
78
+ .join("\n");
79
+ }
80
+ export function renderStats(report, scope) {
81
+ const t = report.totals;
82
+ const range = report.since === undefined && report.until === undefined
83
+ ? "全部时间"
84
+ : `${report.since ?? "最早"} – ${report.until ?? "今天"}`;
85
+ const lines = [`${range} · ${scope} · ${report.sessions} 个会话`];
86
+ if (t.requests === 0) {
87
+ lines.push("没有模型请求");
88
+ return lines.join("\n") + "\n";
89
+ }
90
+ const kinds = Object.entries(report.byKind)
91
+ .sort((a, b) => b[1] - a[1])
92
+ .map(([kind, n]) => `${kind === "turn" ? "对话" : kind} ${n}`)
93
+ .join(" · ");
94
+ const costLine = t.cost === undefined
95
+ ? "— (所有请求的模型都无价格,见 token)"
96
+ : t.unpriced > 0
97
+ ? `${usd(t)}(另有 ${t.unpriced} 次请求无价,未计入)`
98
+ : usd(t);
99
+ const rows = [
100
+ ["请求", `${t.requests}(${kinds})`],
101
+ ["回合", `${t.turns} · 平均耗时 ${seconds(t.avgTurnMs)}`],
102
+ [
103
+ "Token",
104
+ `输入 ${formatTokens(t.input)} · 输出 ${formatTokens(t.output)} · 缓存读 ${formatTokens(t.cacheRead)} · 缓存写 ${formatTokens(t.cacheWrite)}`,
105
+ ],
106
+ [
107
+ "缓存命中率",
108
+ `${percent(t.hitRate)}(报告缓存的端点 ${report.endpoints.reported}/${report.endpoints.total},其余不进分母)`,
109
+ ],
110
+ ["费用", costLine],
111
+ ["错误 / 重试", `${t.errors} / ${t.retries}`],
112
+ ];
113
+ lines.push(table(rows, () => false));
114
+ if (report.groups !== undefined && report.groups.length > 0) {
115
+ const head = ["", "会话", "请求", "回合", "输入", "输出", "缓存读", "缓存写", "命中率", "费用"];
116
+ const body = report.groups.map((g) => [
117
+ g.key,
118
+ String(g.sessions),
119
+ String(g.requests),
120
+ String(g.turns),
121
+ formatTokens(g.input),
122
+ formatTokens(g.output),
123
+ formatTokens(g.cacheRead),
124
+ formatTokens(g.cacheWrite),
125
+ percent(g.hitRate),
126
+ usd(g) + (g.cost !== undefined && g.unpriced > 0 ? "+" : ""),
127
+ ]);
128
+ lines.push("", table([head, ...body], (i) => i > 0));
129
+ }
130
+ if (report.tools.length > 0) {
131
+ lines.push("", `工具调用 Top ${report.tools.length}`);
132
+ lines.push(table(report.tools.map((tool) => [` ${tool.name}`, String(tool.count)]), (i) => i > 0));
133
+ }
134
+ return lines.join("\n") + "\n";
135
+ }
136
+ export async function runStats(argv, io) {
137
+ const { positionals, values, flags } = parseSubArgs(argv, ["since", "until", "by", "project", "session-dir", "top"], ["all", "json", "no-cache"]);
138
+ if (flags.has("help")) {
139
+ io.stdout(STATS_USAGE);
140
+ return ExitCode.Ok;
141
+ }
142
+ if (positionals.length > 0)
143
+ throw new UsageError(`ama stats 不接受位置参数:${positionals[0]}`);
144
+ const now = new Date();
145
+ const since = values.has("since") ? parseDaySpec("since", values.get("since"), now) : undefined;
146
+ const until = values.has("until") ? parseDaySpec("until", values.get("until"), now) : undefined;
147
+ const byRaw = values.get("by");
148
+ if (byRaw !== undefined && !STATS_GROUPS.includes(byRaw)) {
149
+ throw new UsageError(`--by 的取值应为 ${STATS_GROUPS.join(" | ")}(收到 ${byRaw})`);
150
+ }
151
+ const by = byRaw;
152
+ const top = Number(values.get("top") ?? "10");
153
+ if (!Number.isInteger(top) || top < 0)
154
+ throw new UsageError("--top 应为非负整数");
155
+ if (flags.has("all") && values.has("project")) {
156
+ throw new UsageError("--project 与 --all 不能同时使用");
157
+ }
158
+ const dataDir = resolveDataDir({ env: io.env });
159
+ const dirFlag = values.get("session-dir");
160
+ const root = dirFlag !== undefined
161
+ ? resolve(io.cwd, expandHome(dirFlag, { env: io.env }))
162
+ : join(dataDir, "sessions");
163
+ const projectFlag = values.get("project");
164
+ const project = projectFlag !== undefined
165
+ ? resolve(io.cwd, expandHome(projectFlag, { env: io.env }))
166
+ : flags.has("all") || by === "project"
167
+ ? undefined
168
+ : io.cwd;
169
+ const files = sessionFilesInScope(root, project);
170
+ const useCache = !flags.has("no-cache");
171
+ const collected = collectSummaries(files, {
172
+ ...(useCache ? { indexFile: join(dataDir, STATS_INDEX_FILE) } : {}),
173
+ prune: project === undefined,
174
+ });
175
+ const report = aggregateStats(collected.summaries, {
176
+ ...(since !== undefined ? { since } : {}),
177
+ ...(until !== undefined ? { until } : {}),
178
+ ...(by !== undefined ? { by } : {}),
179
+ topTools: top,
180
+ });
181
+ if (flags.has("json")) {
182
+ io.stdout(JSON.stringify({
183
+ scope: project === undefined ? { all: true } : { project },
184
+ ...report,
185
+ files: {
186
+ total: files.length,
187
+ scanned: collected.scanned,
188
+ cached: collected.cached,
189
+ invalid: collected.invalid,
190
+ },
191
+ }, null, 2) + "\n");
192
+ return ExitCode.Ok;
193
+ }
194
+ io.stdout(renderStats(report, project === undefined ? "全部项目" : `项目 ${project}`));
195
+ if (collected.invalid > 0)
196
+ io.stderr(`ama: 跳过 ${collected.invalid} 个无法读取的会话文件\n`);
197
+ return ExitCode.Ok;
198
+ }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * `--system-prompt <文本|@文件>` 与 `--system-prompt-mode append|replace`(W4-C)。
3
+ *
4
+ * - `append`(缺省):作为最后一条规则追加进系统提示的 rules 节——preamble 与工具表在它前面,
5
+ * 缓存前缀里最长的那段不受影响;同一段文本每次都逐字节相同。
6
+ * - `replace`:替换开头的 preamble(「You are ama…」那一段);工具表、规则、AGENTS.md、Skill 索引、
7
+ * cwd 等节照常保留,工具仍然可用。
8
+ * - `@文件`:相对当前目录读取(UTF-8);文件不存在或为空 → 配置错误(退出码 3,同 `--instructions`)。
9
+ */
10
+ import type { SystemPromptOverride } from "./deps.js";
11
+ export declare function resolveSystemPromptArg(value: string | undefined, mode: "append" | "replace" | undefined, cwd: string): SystemPromptOverride | undefined;
@@ -0,0 +1,34 @@
1
+ /**
2
+ * `--system-prompt <文本|@文件>` 与 `--system-prompt-mode append|replace`(W4-C)。
3
+ *
4
+ * - `append`(缺省):作为最后一条规则追加进系统提示的 rules 节——preamble 与工具表在它前面,
5
+ * 缓存前缀里最长的那段不受影响;同一段文本每次都逐字节相同。
6
+ * - `replace`:替换开头的 preamble(「You are ama…」那一段);工具表、规则、AGENTS.md、Skill 索引、
7
+ * cwd 等节照常保留,工具仍然可用。
8
+ * - `@文件`:相对当前目录读取(UTF-8);文件不存在或为空 → 配置错误(退出码 3,同 `--instructions`)。
9
+ */
10
+ import { readFileSync, statSync } from "node:fs";
11
+ import { isAbsolute, resolve } from "node:path";
12
+ import { StartupError } from "../errors.js";
13
+ import { ExitCode } from "./exit-codes.js";
14
+ export function resolveSystemPromptArg(value, mode, cwd) {
15
+ if (value === undefined)
16
+ return undefined;
17
+ let text = value;
18
+ if (value.startsWith("@")) {
19
+ const raw = value.slice(1);
20
+ const path = isAbsolute(raw) ? raw : resolve(cwd, raw);
21
+ try {
22
+ if (!statSync(path).isFile())
23
+ throw new Error("not a file");
24
+ text = readFileSync(path, "utf8");
25
+ }
26
+ catch {
27
+ throw new StartupError("config_invalid", `--system-prompt 文件不存在:${path}`, ExitCode.Config);
28
+ }
29
+ }
30
+ text = text.trim();
31
+ if (text === "")
32
+ throw new StartupError("config_invalid", "--system-prompt 的内容为空", ExitCode.Config);
33
+ return { text, mode: mode ?? "append" };
34
+ }
@@ -1,14 +1,19 @@
1
1
  /**
2
- * 沙箱能力探测(设计 §5.5 沙箱第 4 条)。[B10]
2
+ * 沙箱能力探测(设计 §5.5 沙箱第 4 条;docs/sandbox.md「探测与降级」)。[B10][S2]
3
3
  *
4
4
  * Node 的权限模型(`--permission`)在 Node ≥ 25 同时拒绝网络;Node 22 / 24 只管文件、子进程、
5
- * worker 与 addon,不管网络——脚本若逃出 `vm` 就能联网。所以:
6
- * - Node ≥ 25 → `strict`;
7
- * - Node 22 / 24 → 仍可用,但工具描述与状态栏标注「网络未隔离」;`codemode.requireStrict: true`
8
- * 时直接禁用 codemode 工具并 warning(`codemodeAvailability`)。
5
+ * worker 与 addon,不管网络——脚本若逃出 `vm` 就能联网。子进程另外经操作系统沙箱(macOS
6
+ * sandbox-exec、Linux bwrap / unshare,src/sandbox)启动时,网络由内核拒绝。所以:
7
+ * - Node ≥ 25 → `strict`(OS 沙箱可用时叠加,纵深防御);
8
+ * - Node 22 / 24 + 可用的 OS 沙箱 → `strict`(子进程必须经 OS 沙箱启动);
9
+ * - Node 22 / 24 且没有 OS 沙箱 → 仍可用,但工具描述与状态栏标注「网络未隔离」;
10
+ * `codemode.requireStrict: true` 时直接禁用 codemode 工具并 warning(`codemodeAvailability`)。
9
11
  *
10
- * 状态栏由 B7 直接调用 `detectSandboxCapability()` 判断(不经宿主 status)。
12
+ * 能力在进程内只探测一次(OS 沙箱探针有缓存),同一环境下描述与权限类字节稳定。状态栏直接调用
13
+ * `detectSandboxCapability()`(不经宿主 status);组装根先用 `configureOsSandbox` 记下 `sandbox.enabled`。
11
14
  */
15
+ import type { SandboxConfig } from "../config/types.js";
16
+ import { type OsSandboxStatus } from "../sandbox/detect.js";
12
17
  export interface SandboxCapability {
13
18
  /** 权限模型同时隔离文件、子进程与网络。 */
14
19
  strict: boolean;
@@ -18,12 +23,24 @@ export interface SandboxCapability {
18
23
  reason: string;
19
24
  /** 运行时支持的权限开关:Node ≥ 22.13 / 23.5 为 `--permission`,更早为 `--experimental-permission`。 */
20
25
  permissionFlag: "--permission" | "--experimental-permission";
26
+ /** 操作系统沙箱(`kind: none` 表示没有);codemode 子进程经它启动。 */
27
+ os: OsSandboxStatus;
21
28
  }
22
29
  export declare const NETWORK_NOT_ISOLATED = "network not isolated";
23
30
  export declare function parseNodeMajor(version: string): number;
24
31
  /** `--permission` 在 Node 22.13 / 23.5 之后才是稳定名字;之前只有 `--experimental-permission`。 */
25
32
  export declare function permissionFlagFor(allowedFlags?: ReadonlySet<string>): SandboxCapability["permissionFlag"];
26
- export declare function detectSandboxCapability(nodeVersion?: string, allowedFlags?: ReadonlySet<string>): SandboxCapability;
33
+ /**
34
+ * 运行时的沙箱能力。`os` 缺省:不传 `nodeVersion` 时用进程内缓存的探测结果(`osSandboxStatus()`);
35
+ * 传了假设的 Node 版本(测试、展示)时不探测,按没有 OS 沙箱算,需要时显式传入。
36
+ */
37
+ export declare function detectSandboxCapability(nodeVersion?: string, allowedFlags?: ReadonlySet<string>, os?: OsSandboxStatus): SandboxCapability;
38
+ /** 按配置的 `sandbox.enabled`(缺省 auto)得到运行时能力。 */
39
+ export declare function sandboxCapabilityFor(config: {
40
+ sandbox?: SandboxConfig;
41
+ }): SandboxCapability;
42
+ /** strict 是否依赖 OS 沙箱(Node 22 / 24):此时子进程必须经 OS 沙箱启动,包装不了就报错。 */
43
+ export declare function strictNeedsOsSandbox(capability: Pick<SandboxCapability, "strict" | "nodeMajor">): boolean;
27
44
  export type CodemodeAvailability = {
28
45
  available: true;
29
46
  capability: SandboxCapability;
@@ -1,14 +1,18 @@
1
1
  /**
2
- * 沙箱能力探测(设计 §5.5 沙箱第 4 条)。[B10]
2
+ * 沙箱能力探测(设计 §5.5 沙箱第 4 条;docs/sandbox.md「探测与降级」)。[B10][S2]
3
3
  *
4
4
  * Node 的权限模型(`--permission`)在 Node ≥ 25 同时拒绝网络;Node 22 / 24 只管文件、子进程、
5
- * worker 与 addon,不管网络——脚本若逃出 `vm` 就能联网。所以:
6
- * - Node ≥ 25 → `strict`;
7
- * - Node 22 / 24 → 仍可用,但工具描述与状态栏标注「网络未隔离」;`codemode.requireStrict: true`
8
- * 时直接禁用 codemode 工具并 warning(`codemodeAvailability`)。
5
+ * worker 与 addon,不管网络——脚本若逃出 `vm` 就能联网。子进程另外经操作系统沙箱(macOS
6
+ * sandbox-exec、Linux bwrap / unshare,src/sandbox)启动时,网络由内核拒绝。所以:
7
+ * - Node ≥ 25 → `strict`(OS 沙箱可用时叠加,纵深防御);
8
+ * - Node 22 / 24 + 可用的 OS 沙箱 → `strict`(子进程必须经 OS 沙箱启动);
9
+ * - Node 22 / 24 且没有 OS 沙箱 → 仍可用,但工具描述与状态栏标注「网络未隔离」;
10
+ * `codemode.requireStrict: true` 时直接禁用 codemode 工具并 warning(`codemodeAvailability`)。
9
11
  *
10
- * 状态栏由 B7 直接调用 `detectSandboxCapability()` 判断(不经宿主 status)。
12
+ * 能力在进程内只探测一次(OS 沙箱探针有缓存),同一环境下描述与权限类字节稳定。状态栏直接调用
13
+ * `detectSandboxCapability()`(不经宿主 status);组装根先用 `configureOsSandbox` 记下 `sandbox.enabled`。
11
14
  */
15
+ import { NO_OS_SANDBOX, osSandboxStatus } from "../sandbox/detect.js";
12
16
  export const NETWORK_NOT_ISOLATED = "network not isolated";
13
17
  export function parseNodeMajor(version) {
14
18
  const major = Number.parseInt(version.replace(/^v/, "").split(".")[0] ?? "", 10);
@@ -18,8 +22,13 @@ export function parseNodeMajor(version) {
18
22
  export function permissionFlagFor(allowedFlags = process.allowedNodeEnvironmentFlags) {
19
23
  return allowedFlags.has("--permission") ? "--permission" : "--experimental-permission";
20
24
  }
21
- export function detectSandboxCapability(nodeVersion = process.versions.node, allowedFlags) {
22
- const nodeMajor = parseNodeMajor(nodeVersion);
25
+ /**
26
+ * 运行时的沙箱能力。`os` 缺省:不传 `nodeVersion` 时用进程内缓存的探测结果(`osSandboxStatus()`);
27
+ * 传了假设的 Node 版本(测试、展示)时不探测,按没有 OS 沙箱算,需要时显式传入。
28
+ */
29
+ export function detectSandboxCapability(nodeVersion, allowedFlags, os) {
30
+ const osStatus = os ?? (nodeVersion === undefined ? osSandboxStatus() : NO_OS_SANDBOX);
31
+ const nodeMajor = parseNodeMajor(nodeVersion ?? process.versions.node);
23
32
  const permissionFlag = permissionFlagFor(allowedFlags);
24
33
  if (nodeMajor >= 25) {
25
34
  return {
@@ -27,6 +36,16 @@ export function detectSandboxCapability(nodeVersion = process.versions.node, all
27
36
  nodeMajor,
28
37
  reason: `Node ${nodeMajor}: the permission model blocks file access, child processes and network`,
29
38
  permissionFlag,
39
+ os: osStatus,
40
+ };
41
+ }
42
+ if (osStatus.isolatesNetwork) {
43
+ return {
44
+ strict: true,
45
+ nodeMajor,
46
+ reason: `Node ${nodeMajor}: the OS sandbox (${osStatus.kind}) blocks network; the permission model blocks file access and child processes`,
47
+ permissionFlag,
48
+ os: osStatus,
30
49
  };
31
50
  }
32
51
  return {
@@ -34,8 +53,17 @@ export function detectSandboxCapability(nodeVersion = process.versions.node, all
34
53
  nodeMajor,
35
54
  reason: `Node ${nodeMajor}: ${NETWORK_NOT_ISOLATED} (the permission model blocks file access and child processes only)`,
36
55
  permissionFlag,
56
+ os: osStatus,
37
57
  };
38
58
  }
59
+ /** 按配置的 `sandbox.enabled`(缺省 auto)得到运行时能力。 */
60
+ export function sandboxCapabilityFor(config) {
61
+ return detectSandboxCapability(undefined, undefined, osSandboxStatus(config.sandbox?.enabled ?? "auto"));
62
+ }
63
+ /** strict 是否依赖 OS 沙箱(Node 22 / 24):此时子进程必须经 OS 沙箱启动,包装不了就报错。 */
64
+ export function strictNeedsOsSandbox(capability) {
65
+ return capability.strict && capability.nodeMajor < 25;
66
+ }
39
67
  /** `requireStrict` 且运行时不是 strict → 禁用并给出 warning;非 strict 但允许 → 可用并提示。 */
40
68
  export function codemodeAvailability(requireStrict, capability = detectSandboxCapability()) {
41
69
  if (capability.strict)
@@ -44,12 +72,12 @@ export function codemodeAvailability(requireStrict, capability = detectSandboxCa
44
72
  return {
45
73
  available: false,
46
74
  capability,
47
- warning: `codemode 已禁用:Node ${capability.nodeMajor} 的权限模型不隔离网络(codemode.requireStrict 为 true;Node ≥ 25 才隔离)`,
75
+ warning: `codemode 已禁用:Node ${capability.nodeMajor} 的权限模型不隔离网络,也没有可用的操作系统沙箱(${capability.os.detail};codemode.requireStrict 为 true;Node ≥ 25 或 macOS sandbox-exec / Linux bwrap 可隔离)`,
48
76
  };
49
77
  }
50
78
  return {
51
79
  available: true,
52
80
  capability,
53
- warning: `codemode:Node ${capability.nodeMajor} 下网络未隔离(Node ≥ 25 才隔离;要求隔离可设 codemode.requireStrict)`,
81
+ warning: `codemode:Node ${capability.nodeMajor} 下网络未隔离(没有可用的操作系统沙箱:${capability.os.detail};要求隔离可设 codemode.requireStrict)`,
54
82
  };
55
83
  }