@armadra/agent 0.4.0 → 0.5.1

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 (432) hide show
  1. package/CHANGELOG.md +184 -1
  2. package/README.md +202 -83
  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/session-cache.d.ts +5 -0
  17. package/dist/agent/session-cache.js +17 -1
  18. package/dist/agent/session-classifier.d.ts +1 -1
  19. package/dist/agent/session-classifier.js +3 -1
  20. package/dist/agent/session-compaction.d.ts +35 -6
  21. package/dist/agent/session-compaction.js +157 -31
  22. package/dist/agent/session-core.d.ts +27 -1
  23. package/dist/agent/session-extensions.d.ts +61 -0
  24. package/dist/agent/session-extensions.js +129 -0
  25. package/dist/agent/session-images.d.ts +23 -0
  26. package/dist/agent/session-images.js +97 -0
  27. package/dist/agent/session-plan.d.ts +21 -0
  28. package/dist/agent/session-plan.js +524 -0
  29. package/dist/agent/session-rewind.d.ts +81 -0
  30. package/dist/agent/session-rewind.js +354 -0
  31. package/dist/agent/session-run.d.ts +28 -1
  32. package/dist/agent/session-run.js +157 -6
  33. package/dist/agent/session-settings.d.ts +49 -0
  34. package/dist/agent/session-settings.js +95 -0
  35. package/dist/agent/session-subagent.d.ts +36 -24
  36. package/dist/agent/session-subagent.js +259 -129
  37. package/dist/agent/session-sync.d.ts +10 -3
  38. package/dist/agent/session-sync.js +37 -8
  39. package/dist/agent/session-telemetry.d.ts +39 -0
  40. package/dist/agent/session-telemetry.js +231 -0
  41. package/dist/agent/session-tools.js +40 -1
  42. package/dist/agent/session.d.ts +30 -29
  43. package/dist/agent/session.js +79 -123
  44. package/dist/agent/subagent-registry.d.ts +91 -0
  45. package/dist/agent/subagent-registry.js +494 -0
  46. package/dist/agent/system-prompt.d.ts +6 -3
  47. package/dist/agent/system-prompt.js +7 -2
  48. package/dist/agent/tool-runner.d.ts +8 -1
  49. package/dist/agent/tool-runner.js +57 -4
  50. package/dist/agent/types-w5.d.ts +192 -0
  51. package/dist/agent/types-w5.js +10 -0
  52. package/dist/agent/types.d.ts +47 -4
  53. package/dist/agent/types.js +2 -0
  54. package/dist/agent/worktree.d.ts +36 -0
  55. package/dist/agent/worktree.js +86 -0
  56. package/dist/agents/builtin.d.ts +14 -0
  57. package/dist/agents/builtin.js +39 -0
  58. package/dist/agents/catalog.d.ts +43 -0
  59. package/dist/agents/catalog.js +82 -0
  60. package/dist/agents/discover.d.ts +35 -0
  61. package/dist/agents/discover.js +83 -0
  62. package/dist/agents/external.d.ts +82 -0
  63. package/dist/agents/external.js +326 -0
  64. package/dist/agents/parse.d.ts +18 -0
  65. package/dist/agents/parse.js +116 -0
  66. package/dist/agents/result.d.ts +32 -0
  67. package/dist/agents/result.js +67 -0
  68. package/dist/agents/task-control.d.ts +17 -0
  69. package/dist/agents/task-control.js +17 -0
  70. package/dist/agents/task-record.d.ts +78 -0
  71. package/dist/agents/task-record.js +141 -0
  72. package/dist/agents/types.d.ts +46 -0
  73. package/dist/agents/types.js +8 -0
  74. package/dist/ai/apis/anthropic-compat.d.ts +36 -0
  75. package/dist/ai/apis/anthropic-compat.js +92 -0
  76. package/dist/ai/apis/anthropic-request.d.ts +7 -6
  77. package/dist/ai/apis/anthropic-request.js +10 -28
  78. package/dist/ai/apis/cache-params.d.ts +11 -2
  79. package/dist/ai/apis/cache-params.js +25 -6
  80. package/dist/ai/apis/openai-compat.d.ts +4 -1
  81. package/dist/ai/apis/openai-compat.js +8 -1
  82. package/dist/ai/image-limits.d.ts +45 -0
  83. package/dist/ai/image-limits.js +68 -0
  84. package/dist/ai/providers/builtin.d.ts +18 -6
  85. package/dist/ai/providers/builtin.js +135 -6
  86. package/dist/ai/providers/catalog-data.js +17 -13
  87. package/dist/ai/providers/catalog.d.ts +60 -7
  88. package/dist/ai/providers/catalog.js +197 -38
  89. package/dist/ai/providers/channels.d.ts +33 -3
  90. package/dist/ai/providers/channels.js +108 -7
  91. package/dist/ai/providers/enrich.d.ts +6 -3
  92. package/dist/ai/providers/enrich.js +19 -4
  93. package/dist/ai/providers/models-dev-cache.d.ts +28 -24
  94. package/dist/ai/providers/models-dev-cache.js +92 -78
  95. package/dist/ai/providers/models-dev-data.d.ts +7 -0
  96. package/dist/ai/providers/models-dev-data.js +32 -0
  97. package/dist/ai/providers/models-dev-snapshot.d.ts +50 -0
  98. package/dist/ai/providers/models-dev-snapshot.js +137 -0
  99. package/dist/ai/providers/models-dev.d.ts +51 -10
  100. package/dist/ai/providers/models-dev.js +132 -39
  101. package/dist/ai/providers/registry.d.ts +20 -10
  102. package/dist/ai/providers/registry.js +82 -43
  103. package/dist/ai/types.d.ts +28 -2
  104. package/dist/ai/types.js +5 -0
  105. package/dist/bundle/ama.cjs +37605 -21619
  106. package/dist/checkpoints/backend.d.ts +61 -0
  107. package/dist/checkpoints/backend.js +135 -0
  108. package/dist/checkpoints/blobs.d.ts +60 -0
  109. package/dist/checkpoints/blobs.js +203 -0
  110. package/dist/checkpoints/gc.d.ts +47 -0
  111. package/dist/checkpoints/gc.js +144 -0
  112. package/dist/checkpoints/git-head.d.ts +15 -0
  113. package/dist/checkpoints/git-head.js +89 -0
  114. package/dist/checkpoints/index.d.ts +17 -0
  115. package/dist/checkpoints/index.js +17 -0
  116. package/dist/checkpoints/replay.d.ts +48 -0
  117. package/dist/checkpoints/replay.js +154 -0
  118. package/dist/checkpoints/restore.d.ts +86 -0
  119. package/dist/checkpoints/restore.js +263 -0
  120. package/dist/checkpoints/settings.d.ts +14 -0
  121. package/dist/checkpoints/settings.js +23 -0
  122. package/dist/checkpoints/shadow-git.d.ts +108 -0
  123. package/dist/checkpoints/shadow-git.js +491 -0
  124. package/dist/checkpoints/shadow-restore.d.ts +25 -0
  125. package/dist/checkpoints/shadow-restore.js +128 -0
  126. package/dist/checkpoints/tracker.d.ts +64 -0
  127. package/dist/checkpoints/tracker.js +192 -0
  128. package/dist/checkpoints/types.d.ts +99 -0
  129. package/dist/checkpoints/types.js +12 -0
  130. package/dist/cli/args.d.ts +8 -4
  131. package/dist/cli/args.js +17 -97
  132. package/dist/cli/bootstrap.js +13 -1
  133. package/dist/cli/choice-prompt.d.ts +58 -0
  134. package/dist/cli/choice-prompt.js +140 -0
  135. package/dist/cli/codemode-notice.d.ts +3 -2
  136. package/dist/cli/codemode-notice.js +3 -2
  137. package/dist/cli/compose-agents.d.ts +27 -0
  138. package/dist/cli/compose-agents.js +111 -0
  139. package/dist/cli/compose-extensions.d.ts +29 -0
  140. package/dist/cli/compose-extensions.js +44 -0
  141. package/dist/cli/compose-session.d.ts +3 -0
  142. package/dist/cli/compose-session.js +47 -4
  143. package/dist/cli/compose.d.ts +3 -0
  144. package/dist/cli/compose.js +33 -6
  145. package/dist/cli/deps.d.ts +6 -0
  146. package/dist/cli/exit-codes.d.ts +10 -0
  147. package/dist/cli/exit-codes.js +12 -0
  148. package/dist/cli/help-text.d.ts +4 -0
  149. package/dist/cli/help-text.js +102 -0
  150. package/dist/cli/startup-screen.js +5 -3
  151. package/dist/cli/startup-steps.js +7 -1
  152. package/dist/cli/subcommands/config.d.ts +4 -1
  153. package/dist/cli/subcommands/config.js +17 -6
  154. package/dist/cli/subcommands/doctor.js +21 -0
  155. package/dist/cli/subcommands/models-cache-probe.d.ts +1 -1
  156. package/dist/cli/subcommands/models-cache-probe.js +3 -12
  157. package/dist/cli/subcommands/models-discover.js +5 -6
  158. package/dist/cli/subcommands/models.d.ts +2 -0
  159. package/dist/cli/subcommands/models.js +33 -14
  160. package/dist/cli/subcommands/providers.d.ts +1 -1
  161. package/dist/cli/subcommands/providers.js +8 -15
  162. package/dist/cli/subcommands/sessions.d.ts +3 -1
  163. package/dist/cli/subcommands/sessions.js +36 -2
  164. package/dist/codemode/capability.d.ts +24 -7
  165. package/dist/codemode/capability.js +38 -10
  166. package/dist/codemode/host-side.d.ts +14 -0
  167. package/dist/codemode/host-side.js +24 -1
  168. package/dist/codemode/tool.d.ts +1 -1
  169. package/dist/codemode/tool.js +6 -4
  170. package/dist/compaction/breaker.d.ts +25 -9
  171. package/dist/compaction/breaker.js +47 -17
  172. package/dist/compaction/estimate.d.ts +11 -3
  173. package/dist/compaction/estimate.js +64 -22
  174. package/dist/compaction/image-budget.d.ts +45 -0
  175. package/dist/compaction/image-budget.js +115 -0
  176. package/dist/compaction/post-compact.d.ts +38 -0
  177. package/dist/compaction/post-compact.js +152 -0
  178. package/dist/compaction/protect.d.ts +27 -0
  179. package/dist/compaction/protect.js +56 -0
  180. package/dist/compaction/prune-tier.d.ts +58 -12
  181. package/dist/compaction/prune-tier.js +120 -54
  182. package/dist/compaction/summarize-tier.d.ts +23 -4
  183. package/dist/compaction/summarize-tier.js +100 -29
  184. package/dist/config/checker.d.ts +28 -0
  185. package/dist/config/checker.js +97 -0
  186. package/dist/config/json-schema.js +63 -2
  187. package/dist/config/key-docs.js +72 -3
  188. package/dist/config/merge.d.ts +5 -3
  189. package/dist/config/merge.js +81 -7
  190. package/dist/config/profile.d.ts +2 -0
  191. package/dist/config/profile.js +2 -0
  192. package/dist/config/schema-w5.d.ts +18 -0
  193. package/dist/config/schema-w5.js +109 -0
  194. package/dist/config/schema.d.ts +5 -9
  195. package/dist/config/schema.js +68 -114
  196. package/dist/config/types-w5.d.ts +118 -0
  197. package/dist/config/types-w5.js +20 -0
  198. package/dist/config/types.d.ts +50 -1
  199. package/dist/config/types.js +12 -0
  200. package/dist/drivers/acp/client.d.ts +57 -0
  201. package/dist/drivers/acp/client.js +160 -0
  202. package/dist/drivers/acp/driver.d.ts +31 -0
  203. package/dist/drivers/acp/driver.js +274 -0
  204. package/dist/drivers/acp/testing/fake-agent-main.d.ts +5 -0
  205. package/dist/drivers/acp/testing/fake-agent-main.js +7 -0
  206. package/dist/drivers/acp/testing/fake-agent.d.ts +27 -0
  207. package/dist/drivers/acp/testing/fake-agent.js +211 -0
  208. package/dist/drivers/acp/types.d.ts +285 -0
  209. package/dist/drivers/acp/types.js +36 -0
  210. package/dist/drivers/agents.d.ts +58 -0
  211. package/dist/drivers/agents.js +142 -0
  212. package/dist/drivers/base.d.ts +35 -0
  213. package/dist/drivers/base.js +59 -0
  214. package/dist/drivers/catalog.d.ts +46 -0
  215. package/dist/drivers/catalog.js +167 -0
  216. package/dist/drivers/env.d.ts +20 -0
  217. package/dist/drivers/env.js +46 -0
  218. package/dist/drivers/host-runners.d.ts +18 -0
  219. package/dist/drivers/host-runners.js +45 -0
  220. package/dist/drivers/jsonrpc.d.ts +58 -0
  221. package/dist/drivers/jsonrpc.js +180 -0
  222. package/dist/drivers/native/claude-normalize.d.ts +46 -0
  223. package/dist/drivers/native/claude-normalize.js +106 -0
  224. package/dist/drivers/native/claude-stream.d.ts +29 -0
  225. package/dist/drivers/native/claude-stream.js +456 -0
  226. package/dist/drivers/native/codex-app-server.d.ts +26 -0
  227. package/dist/drivers/native/codex-app-server.js +407 -0
  228. package/dist/drivers/native/codex-normalize.d.ts +38 -0
  229. package/dist/drivers/native/codex-normalize.js +124 -0
  230. package/dist/drivers/native/oneshot.d.ts +28 -0
  231. package/dist/drivers/native/oneshot.js +312 -0
  232. package/dist/drivers/permissions.d.ts +40 -0
  233. package/dist/drivers/permissions.js +92 -0
  234. package/dist/drivers/pids.d.ts +32 -0
  235. package/dist/drivers/pids.js +93 -0
  236. package/dist/drivers/pool.d.ts +28 -0
  237. package/dist/drivers/pool.js +96 -0
  238. package/dist/drivers/probe.d.ts +47 -0
  239. package/dist/drivers/probe.js +172 -0
  240. package/dist/drivers/process.d.ts +48 -0
  241. package/dist/drivers/process.js +100 -0
  242. package/dist/drivers/runner.d.ts +61 -0
  243. package/dist/drivers/runner.js +388 -0
  244. package/dist/drivers/store.d.ts +49 -0
  245. package/dist/drivers/store.js +91 -0
  246. package/dist/drivers/turn.d.ts +41 -0
  247. package/dist/drivers/turn.js +99 -0
  248. package/dist/drivers/types.d.ts +122 -0
  249. package/dist/drivers/types.js +11 -0
  250. package/dist/git/info.d.ts +75 -0
  251. package/dist/git/info.js +191 -0
  252. package/dist/hooks/protocol.js +6 -1
  253. package/dist/hooks/types.d.ts +10 -1
  254. package/dist/hooks/types.js +2 -0
  255. package/dist/host/api-impl.d.ts +7 -0
  256. package/dist/host/api-impl.js +15 -0
  257. package/dist/host/types.d.ts +24 -2
  258. package/dist/host/types.js +4 -0
  259. package/dist/index.d.ts +3 -0
  260. package/dist/index.js +1 -0
  261. package/dist/modes/acp/acp-events.d.ts +46 -0
  262. package/dist/modes/acp/acp-events.js +233 -0
  263. package/dist/modes/acp/acp-mode.d.ts +17 -0
  264. package/dist/modes/acp/acp-mode.js +47 -0
  265. package/dist/modes/acp/acp-server.d.ts +79 -0
  266. package/dist/modes/acp/acp-server.js +315 -0
  267. package/dist/modes/commands-core.d.ts +13 -1
  268. package/dist/modes/commands-core.js +64 -0
  269. package/dist/modes/image-input.d.ts +12 -4
  270. package/dist/modes/image-input.js +22 -5
  271. package/dist/modes/interactive/agent-panels.d.ts +14 -0
  272. package/dist/modes/interactive/agent-panels.js +103 -0
  273. package/dist/modes/interactive/agent-ui.d.ts +73 -0
  274. package/dist/modes/interactive/agent-ui.js +234 -0
  275. package/dist/modes/interactive/approval-dialog.d.ts +21 -4
  276. package/dist/modes/interactive/approval-dialog.js +98 -20
  277. package/dist/modes/interactive/approval-merge.d.ts +41 -0
  278. package/dist/modes/interactive/approval-merge.js +89 -0
  279. package/dist/modes/interactive/clipboard-paste.d.ts +18 -0
  280. package/dist/modes/interactive/clipboard-paste.js +28 -0
  281. package/dist/modes/interactive/commands.d.ts +12 -1
  282. package/dist/modes/interactive/commands.js +31 -1
  283. package/dist/modes/interactive/confirm-dialog.d.ts +49 -0
  284. package/dist/modes/interactive/confirm-dialog.js +121 -0
  285. package/dist/modes/interactive/double-esc.d.ts +20 -0
  286. package/dist/modes/interactive/double-esc.js +34 -0
  287. package/dist/modes/interactive/event-notices.d.ts +32 -0
  288. package/dist/modes/interactive/event-notices.js +79 -0
  289. package/dist/modes/interactive/external-editor.d.ts +16 -0
  290. package/dist/modes/interactive/external-editor.js +39 -0
  291. package/dist/modes/interactive/interactive-mode.d.ts +14 -1
  292. package/dist/modes/interactive/interactive-mode.js +140 -136
  293. package/dist/modes/interactive/key-dispatch.d.ts +22 -2
  294. package/dist/modes/interactive/key-dispatch.js +66 -7
  295. package/dist/modes/interactive/line/line-mode.d.ts +4 -1
  296. package/dist/modes/interactive/line/line-mode.js +31 -5
  297. package/dist/modes/interactive/line/line-render.d.ts +2 -1
  298. package/dist/modes/interactive/line/line-render.js +40 -4
  299. package/dist/modes/interactive/message-view.d.ts +1 -1
  300. package/dist/modes/interactive/message-view.js +24 -2
  301. package/dist/modes/interactive/panels.d.ts +18 -1
  302. package/dist/modes/interactive/panels.js +19 -5
  303. package/dist/modes/interactive/plan-command.d.ts +40 -0
  304. package/dist/modes/interactive/plan-command.js +129 -0
  305. package/dist/modes/interactive/plan-dialog.d.ts +98 -0
  306. package/dist/modes/interactive/plan-dialog.js +290 -0
  307. package/dist/modes/interactive/plan-flow.d.ts +34 -0
  308. package/dist/modes/interactive/plan-flow.js +98 -0
  309. package/dist/modes/interactive/rewind-command.d.ts +31 -0
  310. package/dist/modes/interactive/rewind-command.js +106 -0
  311. package/dist/modes/interactive/rewind-flow.d.ts +37 -0
  312. package/dist/modes/interactive/rewind-flow.js +151 -0
  313. package/dist/modes/interactive/rewind-list.d.ts +36 -0
  314. package/dist/modes/interactive/rewind-list.js +123 -0
  315. package/dist/modes/interactive/rewind-panel.d.ts +77 -0
  316. package/dist/modes/interactive/rewind-panel.js +309 -0
  317. package/dist/modes/interactive/rewind-text.d.ts +40 -0
  318. package/dist/modes/interactive/rewind-text.js +139 -0
  319. package/dist/modes/interactive/session-events.d.ts +24 -0
  320. package/dist/modes/interactive/session-events.js +96 -0
  321. package/dist/modes/interactive/startup-ui.js +5 -1
  322. package/dist/modes/interactive/status-area.d.ts +73 -0
  323. package/dist/modes/interactive/status-area.js +190 -0
  324. package/dist/modes/interactive/status-bar.d.ts +99 -11
  325. package/dist/modes/interactive/status-bar.js +273 -90
  326. package/dist/modes/interactive/status-line.d.ts +33 -0
  327. package/dist/modes/interactive/status-line.js +113 -0
  328. package/dist/modes/interactive/subagent-view.d.ts +56 -0
  329. package/dist/modes/interactive/subagent-view.js +154 -0
  330. package/dist/modes/interactive/tasks-report.d.ts +27 -0
  331. package/dist/modes/interactive/tasks-report.js +114 -0
  332. package/dist/modes/interactive/tool-view.d.ts +12 -2
  333. package/dist/modes/interactive/tool-view.js +34 -4
  334. package/dist/modes/print/print-mode.d.ts +13 -4
  335. package/dist/modes/print/print-mode.js +56 -12
  336. package/dist/modes/rpc/commands.d.ts +9 -0
  337. package/dist/modes/rpc/commands.js +44 -0
  338. package/dist/modes/rpc/rpc-mode.js +7 -1
  339. package/dist/modes/session-report.d.ts +11 -0
  340. package/dist/modes/session-report.js +48 -1
  341. package/dist/permissions/auto-safe.d.ts +5 -0
  342. package/dist/permissions/auto-safe.js +18 -0
  343. package/dist/permissions/bypass.d.ts +32 -0
  344. package/dist/permissions/bypass.js +36 -0
  345. package/dist/permissions/classifier.d.ts +4 -0
  346. package/dist/permissions/classifier.js +2 -0
  347. package/dist/permissions/modes.js +1 -1
  348. package/dist/permissions/pipeline.d.ts +43 -4
  349. package/dist/permissions/pipeline.js +114 -9
  350. package/dist/permissions/readonly-bash.d.ts +30 -0
  351. package/dist/permissions/readonly-bash.js +118 -0
  352. package/dist/permissions/types.d.ts +42 -0
  353. package/dist/plan/compose.d.ts +9 -0
  354. package/dist/plan/compose.js +19 -0
  355. package/dist/plan/controller.d.ts +71 -0
  356. package/dist/plan/controller.js +27 -0
  357. package/dist/plan/done-markers.d.ts +17 -0
  358. package/dist/plan/done-markers.js +51 -0
  359. package/dist/plan/extract.d.ts +29 -0
  360. package/dist/plan/extract.js +160 -0
  361. package/dist/plan/prompts.d.ts +36 -0
  362. package/dist/plan/prompts.js +89 -0
  363. package/dist/plan/store.d.ts +37 -0
  364. package/dist/plan/store.js +90 -0
  365. package/dist/rpc.d.ts +58 -2
  366. package/dist/rpc.js +7 -0
  367. package/dist/sandbox/bash.d.ts +74 -0
  368. package/dist/sandbox/bash.js +126 -0
  369. package/dist/sandbox/detect.d.ts +48 -0
  370. package/dist/sandbox/detect.js +149 -0
  371. package/dist/sandbox/index.d.ts +5 -0
  372. package/dist/sandbox/index.js +5 -0
  373. package/dist/sandbox/profile.d.ts +33 -0
  374. package/dist/sandbox/profile.js +76 -0
  375. package/dist/sandbox/wrap.d.ts +29 -0
  376. package/dist/sandbox/wrap.js +117 -0
  377. package/dist/sdk.d.ts +33 -2
  378. package/dist/sdk.js +24 -2
  379. package/dist/session/types.d.ts +3 -1
  380. package/dist/session/types.js +1 -0
  381. package/dist/skills/builtin.d.ts +31 -0
  382. package/dist/skills/builtin.js +109 -0
  383. package/dist/skills/discover.d.ts +2 -1
  384. package/dist/skills/index-prompt.js +5 -8
  385. package/dist/tools/background-jobs.d.ts +71 -0
  386. package/dist/tools/background-jobs.js +198 -0
  387. package/dist/tools/bash.d.ts +53 -1
  388. package/dist/tools/bash.js +158 -7
  389. package/dist/tools/clipboard-image.d.ts +44 -0
  390. package/dist/tools/clipboard-image.js +148 -0
  391. package/dist/tools/edit.d.ts +2 -0
  392. package/dist/tools/edit.js +18 -3
  393. package/dist/tools/image-file.d.ts +38 -3
  394. package/dist/tools/image-file.js +81 -10
  395. package/dist/tools/image-resize.d.ts +58 -0
  396. package/dist/tools/image-resize.js +97 -0
  397. package/dist/tools/presets.d.ts +7 -2
  398. package/dist/tools/presets.js +11 -4
  399. package/dist/tools/read.d.ts +5 -2
  400. package/dist/tools/read.js +13 -10
  401. package/dist/tools/registry.d.ts +7 -1
  402. package/dist/tools/registry.js +27 -4
  403. package/dist/tools/task-ctl.d.ts +22 -0
  404. package/dist/tools/task-ctl.js +116 -0
  405. package/dist/tools/task.d.ts +22 -10
  406. package/dist/tools/task.js +66 -26
  407. package/dist/tools/todo.d.ts +22 -2
  408. package/dist/tools/todo.js +58 -14
  409. package/dist/tools/truncate.d.ts +15 -0
  410. package/dist/tools/truncate.js +25 -0
  411. package/dist/tools/types.d.ts +113 -0
  412. package/dist/tools/types.js +5 -0
  413. package/dist/tools/write.js +3 -0
  414. package/dist/tui/glyphs.d.ts +4 -0
  415. package/dist/tui/glyphs.js +4 -0
  416. package/dist/tui/keybindings.d.ts +6 -1
  417. package/dist/tui/keybindings.js +6 -1
  418. package/docs/acp.md +78 -0
  419. package/docs/agents.md +250 -0
  420. package/docs/codemode.md +12 -8
  421. package/docs/hooks.md +26 -22
  422. package/docs/permissions.md +78 -13
  423. package/docs/plan.md +107 -0
  424. package/docs/providers.md +228 -52
  425. package/docs/rewind-plan.md +181 -0
  426. package/docs/rpc.md +92 -5
  427. package/docs/sandbox.md +215 -0
  428. package/docs/session-format.md +41 -21
  429. package/docs/sessions.md +41 -1
  430. package/docs/tui-design.md +751 -0
  431. package/docs/tui.md +179 -21
  432. package/package.json +13 -2
@@ -0,0 +1,89 @@
1
+ /**
2
+ * plan 模式注入给模型的文本(docs/wave5-plan.md §6.2、D18)。[W5-F]
3
+ *
4
+ * 全部以 `custom_message`(`display:false`)追加在尾部,投影成 user 消息,不碰 system 节与工具表
5
+ * (design §9.1)。文本是给模型看的,用英文;界面文案不在这里。
6
+ */
7
+ export const PLAN_MODE_TYPE = "ama.plan_mode";
8
+ export const PLAN_MODE_EXIT_TYPE = "ama.plan_mode_exit";
9
+ export const PLAN_APPROVED_TYPE = "ama.plan_approved";
10
+ /** 完整版(约 400 token):进入 plan 后首个提示、每第 5 次提醒、压缩之后。 */
11
+ export const PLAN_MODE_FULL = `Plan mode is active. You may read and search, run read-only shell commands (ls, cat, grep, rg, find, git status/log/show/diff, …) and start read-only subagents with task. Do not modify files, run builds or tests, or change any state; write/execute tools are refused in this mode.
12
+
13
+ How to work:
14
+ 1. Explore first. Answer questions from the repository yourself instead of asking the user; ask only about decisions that the code cannot settle.
15
+ 2. When you are ready, write the plan as one block, with the tags on their own lines:
16
+
17
+ <proposed_plan>
18
+ # <title>
19
+
20
+ ## Background
21
+ 1–3 sentences: the goal and the key facts you found.
22
+
23
+ ## Steps
24
+ - [ ] S1 <action> (files: path/a.ts)
25
+ - [ ] S2 <action> [depends: S1] [agent: <name>]
26
+
27
+ ## Verification
28
+ - <command or check>
29
+
30
+ ## Assumptions and risks
31
+ - <defaults you chose for open questions>
32
+ </proposed_plan>
33
+
34
+ Rules for the plan:
35
+ - Make it specific enough that someone else could carry it out without making further decisions. List the key files; describe a repeated change once.
36
+ - Always include a Verification section.
37
+ - At most one <proposed_plan> block per reply; to revise, rewrite the whole block.
38
+ - Do not ask "is this OK?" in prose: the plan block itself is shown to the user for approval.
39
+ - If the user asks you to make changes while plan mode is active, treat it as a request to plan how to make them.
40
+ - Do not use the todo tool to record the plan; the task list is created from the steps when the plan is approved.`;
41
+ /** 简版:两次完整版之间每 5 个提示一次。 */
42
+ export const PLAN_MODE_BRIEF = "Plan mode is still active: read-only exploration only. Finish with a <proposed_plan> block (Background, Steps as - [ ] S1 …, Verification, Assumptions and risks).";
43
+ /** 手动退出 plan(没有获批的计划)。 */
44
+ export const PLAN_MODE_EXIT = "Plan mode has ended. The read-only restrictions no longer apply; the current permission mode decides what you may do.";
45
+ /** 获批交接时开启新回合的用户消息(之后紧跟 `ama.plan_approved`)。 */
46
+ export const PLAN_APPROVED_PROMPT = "The plan is approved. Go ahead.";
47
+ /**
48
+ * 提醒节奏:plan 模式下第 n 个提示(从 1 起)。每 5 个提示提醒一次(第 1、6、11 … 个),
49
+ * 第 1、6、11 … 次提醒里每第 5 次用完整版(即第 1、26、51 … 个提示)。
50
+ */
51
+ export function reminderKind(promptIndex) {
52
+ if (promptIndex < 1 || (promptIndex - 1) % 5 !== 0)
53
+ return undefined;
54
+ const reminder = (promptIndex - 1) / 5;
55
+ return reminder % 5 === 0 ? "full" : "brief";
56
+ }
57
+ const DONE_MARKER_HINT = "When you finish a step, write `[DONE:<step id>]` (for example `[DONE:S1]`) on its own line in your reply so progress can be tracked.";
58
+ /** 交接消息:计划已批准 + plan 模式结束 + 计划全文 + 文件路径 + 进度记法。 */
59
+ export function planApprovedText(plan, options = { todoTool: true }) {
60
+ const lines = [
61
+ "The user approved the plan below. Plan mode has ended: you may now edit files and run commands as the current permission mode allows.",
62
+ ];
63
+ if (plan.steps.length > 0) {
64
+ lines.push(options.todoTool
65
+ ? "The todo list has been created from the plan steps (the first step is in progress). Work through it in order and mark each step with todo update as soon as it is done."
66
+ : `Work through the plan steps in order. ${DONE_MARKER_HINT}`);
67
+ }
68
+ if (plan.filePath !== undefined)
69
+ lines.push(`Plan file: ${plan.filePath}`);
70
+ lines.push("", "<approved_plan>", plan.markdown, "</approved_plan>");
71
+ return lines.join("\n");
72
+ }
73
+ /** 「批准,在新上下文执行」:新会话的首条用户消息。 */
74
+ export function freshContextPrompt(plan, options = { todoTool: true }) {
75
+ const lines = [
76
+ "Carry out the approved plan below. It was written in an earlier session that you cannot see; the plan is self-contained.",
77
+ ];
78
+ if (plan.steps.length > 0)
79
+ lines.push(options.todoTool
80
+ ? "Track progress with the todo tool: mark each step with todo update when done."
81
+ : DONE_MARKER_HINT);
82
+ if (plan.filePath !== undefined)
83
+ lines.push(`Plan file: ${plan.filePath}`);
84
+ lines.push("", "<approved_plan>", plan.markdown, "</approved_plan>");
85
+ return lines.join("\n");
86
+ }
87
+ export function planMessage(customType, content) {
88
+ return { role: "custom", customType, content, display: false, timestamp: Date.now() };
89
+ }
@@ -0,0 +1,37 @@
1
+ /**
2
+ * 计划的持久化:会话条目的读取与计划文件导出(docs/wave5-plan.md §6.3)。[W5-F]
3
+ *
4
+ * - 权威数据在会话 JSONL:`custom{ama.plan}`(只追加:状态变化再记一条,同 id 取分支上最后一条)、
5
+ * `custom{ama.plan_state}`(进入 / 退出 plan)。
6
+ * - 文件只作导出:缺省 `<dataDir>/plans/<sessionId>-v<N>.md`;`plan.directory` 可指到项目内
7
+ * (相对路径按项目根解析,必须在项目根之内,否则 warning 回落缺省)。由 ama 进程写,不经工具调用。
8
+ */
9
+ import type { PlanData, PlanStateData, TodoItemView } from "../agent/types.js";
10
+ import type { PermissionMode } from "../permissions/types.js";
11
+ import type { SessionEntry } from "../session/types.js";
12
+ export declare const PLAN_CUSTOM_TYPE = "ama.plan";
13
+ export declare const PLAN_STATE_CUSTOM_TYPE = "ama.plan_state";
14
+ /**
15
+ * `ama.plan_state` 的落盘形状:契约 `PlanStateData` 加两项可选的本地字段,记下进入 plan 时切走的
16
+ * 执行模型(`plan.model` 配置时),resume 后批准仍能切回。读到旧条目时缺省。
17
+ */
18
+ export interface PlanStateRecord extends PlanStateData {
19
+ executionModel?: string;
20
+ executionThinking?: string;
21
+ }
22
+ /** 分支上最后一条 `ama.plan`(任意状态);`planId` 给定时取该计划的最后一条。 */
23
+ export declare function latestPlan(branch: readonly SessionEntry[], planId?: string): PlanData | undefined;
24
+ /** 分支上已用过的最大版本号(文件名 `-v<N>` 在会话内单调)。 */
25
+ export declare function maxPlanVersion(branch: readonly SessionEntry[]): number;
26
+ export declare function latestPlanState(branch: readonly SessionEntry[]): PlanStateRecord | undefined;
27
+ /** 分支上的当前 todo 清单(RPC `get_todos`、`todo_updated` 事件)。 */
28
+ export declare function currentTodos(branch: readonly SessionEntry[]): TodoItemView[];
29
+ /** 批准时的执行模式:显式指定 > 进入 plan 前的模式;进入前就是 plan 时用 default。 */
30
+ export declare function executionMode(requested: PermissionMode | undefined, prePlanMode: PermissionMode | undefined): PermissionMode;
31
+ /** 计划文件目录:`plan.directory` 在项目根之内才用,否则 warning 回落 `<dataDir>/plans`。 */
32
+ export declare function resolvePlanDirectory(configured: string | undefined, projectRoot: string, dataDir: string): {
33
+ dir: string;
34
+ warning?: string;
35
+ };
36
+ /** 写 `<dir>/<sessionId>-v<N>.md`,返回绝对路径。 */
37
+ export declare function writePlanFile(dir: string, sessionId: string, version: number, markdown: string): string;
@@ -0,0 +1,90 @@
1
+ /**
2
+ * 计划的持久化:会话条目的读取与计划文件导出(docs/wave5-plan.md §6.3)。[W5-F]
3
+ *
4
+ * - 权威数据在会话 JSONL:`custom{ama.plan}`(只追加:状态变化再记一条,同 id 取分支上最后一条)、
5
+ * `custom{ama.plan_state}`(进入 / 退出 plan)。
6
+ * - 文件只作导出:缺省 `<dataDir>/plans/<sessionId>-v<N>.md`;`plan.directory` 可指到项目内
7
+ * (相对路径按项目根解析,必须在项目根之内,否则 warning 回落缺省)。由 ama 进程写,不经工具调用。
8
+ */
9
+ import { mkdirSync, writeFileSync } from "node:fs";
10
+ import { isAbsolute, join, relative, resolve } from "node:path";
11
+ import { TODO_CUSTOM_TYPE, parseTodoState } from "../tools/todo.js";
12
+ export const PLAN_CUSTOM_TYPE = "ama.plan";
13
+ export const PLAN_STATE_CUSTOM_TYPE = "ama.plan_state";
14
+ function customData(entry, customType) {
15
+ return entry.type === "custom" && entry.customType === customType ? entry.data : undefined;
16
+ }
17
+ function isPlanData(value) {
18
+ if (typeof value !== "object" || value === null)
19
+ return false;
20
+ const v = value;
21
+ return (typeof v.id === "string" &&
22
+ typeof v.version === "number" &&
23
+ typeof v.markdown === "string" &&
24
+ Array.isArray(v.steps));
25
+ }
26
+ /** 分支上最后一条 `ama.plan`(任意状态);`planId` 给定时取该计划的最后一条。 */
27
+ export function latestPlan(branch, planId) {
28
+ for (let i = branch.length - 1; i >= 0; i--) {
29
+ const data = customData(branch[i], PLAN_CUSTOM_TYPE);
30
+ if (isPlanData(data) && (planId === undefined || data.id === planId))
31
+ return data;
32
+ }
33
+ return undefined;
34
+ }
35
+ /** 分支上已用过的最大版本号(文件名 `-v<N>` 在会话内单调)。 */
36
+ export function maxPlanVersion(branch) {
37
+ let max = 0;
38
+ for (const entry of branch) {
39
+ const data = customData(entry, PLAN_CUSTOM_TYPE);
40
+ if (isPlanData(data))
41
+ max = Math.max(max, data.version);
42
+ }
43
+ return max;
44
+ }
45
+ export function latestPlanState(branch) {
46
+ for (let i = branch.length - 1; i >= 0; i--) {
47
+ const data = customData(branch[i], PLAN_STATE_CUSTOM_TYPE);
48
+ if (typeof data === "object" &&
49
+ data !== null &&
50
+ typeof data.active === "boolean")
51
+ return data;
52
+ }
53
+ return undefined;
54
+ }
55
+ /** 分支上的当前 todo 清单(RPC `get_todos`、`todo_updated` 事件)。 */
56
+ export function currentTodos(branch) {
57
+ for (let i = branch.length - 1; i >= 0; i--) {
58
+ const entry = branch[i];
59
+ if (entry.type === "custom" && entry.customType === TODO_CUSTOM_TYPE)
60
+ return parseTodoState(entry.data).items;
61
+ }
62
+ return [];
63
+ }
64
+ /** 批准时的执行模式:显式指定 > 进入 plan 前的模式;进入前就是 plan 时用 default。 */
65
+ export function executionMode(requested, prePlanMode) {
66
+ const mode = requested ?? prePlanMode ?? "default";
67
+ return mode === "plan" ? "default" : mode;
68
+ }
69
+ /** 计划文件目录:`plan.directory` 在项目根之内才用,否则 warning 回落 `<dataDir>/plans`。 */
70
+ export function resolvePlanDirectory(configured, projectRoot, dataDir) {
71
+ const fallback = join(dataDir, "plans");
72
+ if (configured === undefined || configured.trim() === "")
73
+ return { dir: fallback };
74
+ const dir = resolve(projectRoot, configured);
75
+ const rel = relative(resolve(projectRoot), dir);
76
+ if (rel.startsWith("..") || isAbsolute(rel)) {
77
+ return {
78
+ dir: fallback,
79
+ warning: `plan.directory ${configured} 不在项目根 ${projectRoot} 之内,计划文件改写到 ${fallback}`,
80
+ };
81
+ }
82
+ return { dir };
83
+ }
84
+ /** 写 `<dir>/<sessionId>-v<N>.md`,返回绝对路径。 */
85
+ export function writePlanFile(dir, sessionId, version, markdown) {
86
+ mkdirSync(dir, { recursive: true });
87
+ const file = join(dir, `${sessionId}-v${version}.md`);
88
+ writeFileSync(file, markdown.endsWith("\n") ? markdown : `${markdown}\n`, "utf8");
89
+ return file;
90
+ }
package/dist/rpc.d.ts CHANGED
@@ -6,16 +6,27 @@
6
6
  * - 设计只列了命令名;参数形状按 v1 §8.4 补全,新增命令(get_available_thinking_levels、
7
7
  * set_auto_retry、abort_retry、get_fork_messages、set_permission_mode、get_commands、
8
8
  * get_skills)按名字含义补全。
9
+ * - [RW-B] 回滚:get_rewind_points → `{ points }`、rewind → `RewindResult`(形状见
10
+ * checkpoints/types.ts)、summarize_from → `{ leafId, draft, summary? }`、summarize_up_to →
11
+ * `CompactionResult`;成功回滚发 `session_rewound` 事件。
9
12
  * - 线上事件 = 进程内 `SessionEvent`,但 `message_update` 换成纯增量(去掉 partial / 累计消息,
10
13
  * 附最新 usage);stream-json 输出同一形状。
11
14
  * - 类型定义直接放在本文件(B6 实现 import 它),避免子路径入口依赖实现文件。
15
+ * - [W5-C0] 第五波(docs/wave5-plan.md §6.5、§7.5):命令 `plan_response / get_plan / get_todos /
16
+ * get_tasks / get_agents`(返回形状见 `RpcW5Results`),客户端能力 `plans`(声明后计划审批交客户端);
17
+ * 新事件由 `SessionEvent` 派生自动包含。命令实现归 W5-F(C0 时返回 `not_implemented`),
18
+ * `RPC_PROTOCOL_VERSION` 不变。
12
19
  */
13
20
  import type { AssistantEvent, ImageBlock, ModelThinkingLevel, Usage } from "./ai/types.js";
14
- import type { QueueMode, SessionEvent } from "./agent/types.js";
21
+ import type { PlanData, PlanDecisionKind, QueueMode, SessionEvent, TodoItemView } from "./agent/types.js";
22
+ import type { AgentInfo } from "./agents/types.js";
23
+ import type { TaskInfo } from "./tools/types.js";
24
+ import type { RewindRequest } from "./checkpoints/types.js";
15
25
  import type { ApprovalDecision, PermissionMode } from "./permissions/types.js";
16
26
  export type { SessionEvent } from "./agent/types.js";
17
27
  export declare const RPC_PROTOCOL_VERSION: 1;
18
- export type RpcCapability = "approvals" | "images" | "hooks";
28
+ /** `plans`(W5-C0):客户端声明后计划审批交给客户端(`plan_proposed` → `plan_response`)。 */
29
+ export type RpcCapability = "approvals" | "images" | "hooks" | "plans";
19
30
  export interface RpcHello {
20
31
  type: "hello";
21
32
  protocolVersion: typeof RPC_PROTOCOL_VERSION;
@@ -89,6 +100,16 @@ export interface RpcCommandMap {
89
100
  name: string;
90
101
  };
91
102
  get_fork_messages: NoParams;
103
+ get_rewind_points: NoParams;
104
+ rewind: RewindRequest;
105
+ summarize_from: {
106
+ entryId: string;
107
+ instructions?: string;
108
+ };
109
+ summarize_up_to: {
110
+ entryId: string;
111
+ instructions?: string;
112
+ };
92
113
  set_client_capabilities: {
93
114
  capabilities: RpcCapability[];
94
115
  };
@@ -105,6 +126,41 @@ export interface RpcCommandMap {
105
126
  };
106
127
  get_commands: NoParams;
107
128
  get_skills: NoParams;
129
+ plan_response: RpcPlanResponse;
130
+ get_plan: {
131
+ planId?: string;
132
+ };
133
+ get_todos: NoParams;
134
+ get_tasks: NoParams;
135
+ get_agents: NoParams;
136
+ }
137
+ /** [W5-C0] 计划审批的回答(与 `permission_response` 同构)。 */
138
+ export interface RpcPlanResponse {
139
+ planId: string;
140
+ decision: PlanDecisionKind;
141
+ /** `approve` 时指定执行模式(缺省回到进入 plan 前的模式)。 */
142
+ mode?: PermissionMode;
143
+ /** `revise`:修改意见(作为普通 user 消息,留在 plan)。 */
144
+ feedback?: string;
145
+ /** 客户端改过的计划全文(version + 1)。 */
146
+ editedMarkdown?: string;
147
+ }
148
+ /** [W5-C0] 第五波命令成功时的 `data` 形状。 */
149
+ export interface RpcW5Results {
150
+ plan_response: {
151
+ planId: string;
152
+ decision: PlanDecisionKind;
153
+ };
154
+ get_plan: PlanData | null;
155
+ get_todos: {
156
+ items: TodoItemView[];
157
+ };
158
+ get_tasks: {
159
+ tasks: TaskInfo[];
160
+ };
161
+ get_agents: {
162
+ agents: AgentInfo[];
163
+ };
108
164
  }
109
165
  export type RpcCommandType = keyof RpcCommandMap;
110
166
  /** `{ id?, type, ...参数 }`。 */
package/dist/rpc.js CHANGED
@@ -6,8 +6,15 @@
6
6
  * - 设计只列了命令名;参数形状按 v1 §8.4 补全,新增命令(get_available_thinking_levels、
7
7
  * set_auto_retry、abort_retry、get_fork_messages、set_permission_mode、get_commands、
8
8
  * get_skills)按名字含义补全。
9
+ * - [RW-B] 回滚:get_rewind_points → `{ points }`、rewind → `RewindResult`(形状见
10
+ * checkpoints/types.ts)、summarize_from → `{ leafId, draft, summary? }`、summarize_up_to →
11
+ * `CompactionResult`;成功回滚发 `session_rewound` 事件。
9
12
  * - 线上事件 = 进程内 `SessionEvent`,但 `message_update` 换成纯增量(去掉 partial / 累计消息,
10
13
  * 附最新 usage);stream-json 输出同一形状。
11
14
  * - 类型定义直接放在本文件(B6 实现 import 它),避免子路径入口依赖实现文件。
15
+ * - [W5-C0] 第五波(docs/wave5-plan.md §6.5、§7.5):命令 `plan_response / get_plan / get_todos /
16
+ * get_tasks / get_agents`(返回形状见 `RpcW5Results`),客户端能力 `plans`(声明后计划审批交客户端);
17
+ * 新事件由 `SessionEvent` 派生自动包含。命令实现归 W5-F(C0 时返回 `not_implemented`),
18
+ * `RPC_PROTOCOL_VERSION` 不变。
12
19
  */
13
20
  export const RPC_PROTOCOL_VERSION = 1;
@@ -0,0 +1,74 @@
1
+ /**
2
+ * bash 的 OS 沙箱(docs/sandbox.md「第二阶段」):配置 → 会话内固定的沙箱设定,以及每次调用的策略。
3
+ *
4
+ * - 生效条件:`sandbox.bash: auto` 且探测到能限制写入的沙箱(sandbox-exec / bwrap;`unshare` 只隔离网络,
5
+ * 不算)。不生效时 bash 原样运行、权限照旧;
6
+ * - 每次调用的策略:可写 = 会话工作区 + 系统临时目录(POSIX 另加 `/tmp`)+ ama 的输出目录 +
7
+ * `sandbox.writable`;工作区里 `.ama/`、`.git/hooks`、`.git/config` 仍只读(防止借 Hook / 配置 / git
8
+ * 钩子在沙箱外执行);凭据目录与 ama 的 `auth.json` 不可读;网络按 `sandbox.network`;
9
+ * - 设定在组装时算一次(探测结果进程内缓存),同一会话内不变:工具描述与 schema 逐字节稳定(设计 §9.1)。
10
+ *
11
+ * 只依赖 `node:` 内置模块与本目录。
12
+ */
13
+ import type { OsSandboxStatus } from "./detect.js";
14
+ import type { OsSandboxPolicy } from "./profile.js";
15
+ import { type WrappedCommand } from "./wrap.js";
16
+ export type BashSandboxMode = "auto" | "off";
17
+ export type SandboxNetwork = "deny" | "allow";
18
+ export declare const DEFAULT_BASH_SANDBOX_MODE: BashSandboxMode;
19
+ export declare const DEFAULT_SANDBOX_NETWORK: SandboxNetwork;
20
+ /** 配置 `sandbox` 段里与 bash 有关的键(结构与 config/types.ts 的 SandboxConfig 相容)。 */
21
+ export interface BashSandboxConfig {
22
+ bash?: BashSandboxMode;
23
+ network?: SandboxNetwork;
24
+ writable?: readonly string[];
25
+ }
26
+ export interface BashSandbox {
27
+ /** 命令将经 OS 沙箱运行(不传 `sandbox: false` 时)。 */
28
+ active: boolean;
29
+ status: OsSandboxStatus;
30
+ network: SandboxNetwork;
31
+ /** `sandbox.writable` 展开 `~` 后的绝对路径。 */
32
+ writable: string[];
33
+ /** 不可读的路径(凭据目录 / 文件)。 */
34
+ hidden: string[];
35
+ /** 人读说明(doctor / config show)。 */
36
+ detail: string;
37
+ }
38
+ export declare const NO_BASH_SANDBOX: BashSandbox;
39
+ /** 用户主目录下的凭据路径(与 permissions/protected.ts 的机密路径同一批)。 */
40
+ export declare const HIDDEN_HOME_PATHS: readonly [".ssh", ".gnupg", ".aws", ".kube", ".docker/config.json", ".config/gcloud", ".netrc", ".pgpass", ".git-credentials"];
41
+ /** 工作区里沙箱内仍只读的路径。 */
42
+ export declare const WORKSPACE_READ_ONLY: readonly [".ama", ".git/hooks", ".git/config"];
43
+ /** `~` / `~/x` 展开;其余相对路径不认(返回 undefined)。 */
44
+ export declare function expandHome(path: string, home: string): string | undefined;
45
+ export interface ResolveBashSandboxDeps {
46
+ status: OsSandboxStatus;
47
+ home?: string;
48
+ /** 额外不可读的文件(ama 的 auth.json)。 */
49
+ hidden?: readonly string[];
50
+ }
51
+ export declare function resolveBashSandbox(config: BashSandboxConfig | undefined, deps: ResolveBashSandboxDeps): BashSandbox;
52
+ export interface BashCallPlace {
53
+ /** 会话工作区(会话 cwd)。 */
54
+ workspace: string;
55
+ /** ama 的输出目录(截断全文、后台输出)。 */
56
+ outputDir?: string;
57
+ /** 测试注入:系统临时目录。 */
58
+ tmpdir?: string;
59
+ platform?: NodeJS.Platform;
60
+ }
61
+ /** 一次 bash 调用的沙箱策略(路径未 realpath,wrapCommand 再解析)。 */
62
+ export declare function bashSandboxPolicy(sandbox: BashSandbox, place: BashCallPlace): OsSandboxPolicy;
63
+ /** 调用参数里显式要求不经沙箱(`sandbox: false`)。 */
64
+ export declare function wantsUnsandboxed(input: unknown): boolean;
65
+ /** 这次调用会不会经沙箱运行(权限管线与 bash 工具共用,保证两边结论一致)。 */
66
+ export declare function runsSandboxed(sandbox: BashSandbox | undefined, input: unknown): boolean;
67
+ /**
68
+ * 包装 shell 命令行;设定生效但没能包上(不应发生)时抛错——权限管线已按「在沙箱内」放行,不能悄悄裸跑。
69
+ */
70
+ export declare function wrapBashCommand(sandbox: BashSandbox, shell: string, args: readonly string[], place: BashCallPlace): WrappedCommand;
71
+ /** 失败输出看起来像被沙箱拒绝(写入被拒;网络拒绝时另看联网失败)。 */
72
+ export declare function looksLikeSandboxDenial(output: string, networkDenied: boolean): boolean;
73
+ /** 沙箱拒绝时追加给模型的一行说明。 */
74
+ export declare function sandboxDenialHint(networkDenied: boolean): string;
@@ -0,0 +1,126 @@
1
+ /**
2
+ * bash 的 OS 沙箱(docs/sandbox.md「第二阶段」):配置 → 会话内固定的沙箱设定,以及每次调用的策略。
3
+ *
4
+ * - 生效条件:`sandbox.bash: auto` 且探测到能限制写入的沙箱(sandbox-exec / bwrap;`unshare` 只隔离网络,
5
+ * 不算)。不生效时 bash 原样运行、权限照旧;
6
+ * - 每次调用的策略:可写 = 会话工作区 + 系统临时目录(POSIX 另加 `/tmp`)+ ama 的输出目录 +
7
+ * `sandbox.writable`;工作区里 `.ama/`、`.git/hooks`、`.git/config` 仍只读(防止借 Hook / 配置 / git
8
+ * 钩子在沙箱外执行);凭据目录与 ama 的 `auth.json` 不可读;网络按 `sandbox.network`;
9
+ * - 设定在组装时算一次(探测结果进程内缓存),同一会话内不变:工具描述与 schema 逐字节稳定(设计 §9.1)。
10
+ *
11
+ * 只依赖 `node:` 内置模块与本目录。
12
+ */
13
+ import { homedir, tmpdir } from "node:os";
14
+ import { isAbsolute, join, resolve } from "node:path";
15
+ import { wrapCommand } from "./wrap.js";
16
+ export const DEFAULT_BASH_SANDBOX_MODE = "off";
17
+ export const DEFAULT_SANDBOX_NETWORK = "deny";
18
+ export const NO_BASH_SANDBOX = Object.freeze({
19
+ active: false,
20
+ status: Object.freeze({
21
+ kind: "none",
22
+ isolatesNetwork: false,
23
+ restrictsWrites: false,
24
+ detail: "未配置",
25
+ }),
26
+ network: DEFAULT_SANDBOX_NETWORK,
27
+ writable: [],
28
+ hidden: [],
29
+ detail: "未配置",
30
+ });
31
+ /** 用户主目录下的凭据路径(与 permissions/protected.ts 的机密路径同一批)。 */
32
+ export const HIDDEN_HOME_PATHS = [
33
+ ".ssh",
34
+ ".gnupg",
35
+ ".aws",
36
+ ".kube",
37
+ ".docker/config.json",
38
+ ".config/gcloud",
39
+ ".netrc",
40
+ ".pgpass",
41
+ ".git-credentials",
42
+ ];
43
+ /** 工作区里沙箱内仍只读的路径。 */
44
+ export const WORKSPACE_READ_ONLY = [".ama", ".git/hooks", ".git/config"];
45
+ /** `~` / `~/x` 展开;其余相对路径不认(返回 undefined)。 */
46
+ export function expandHome(path, home) {
47
+ if (path === "~")
48
+ return home;
49
+ if (path.startsWith("~/"))
50
+ return join(home, path.slice(2));
51
+ return isAbsolute(path) ? resolve(path) : undefined;
52
+ }
53
+ export function resolveBashSandbox(config, deps) {
54
+ const home = deps.home ?? homedir();
55
+ const mode = config?.bash ?? DEFAULT_BASH_SANDBOX_MODE;
56
+ const network = config?.network ?? DEFAULT_SANDBOX_NETWORK;
57
+ const writable = [];
58
+ for (const raw of config?.writable ?? []) {
59
+ const path = expandHome(raw, home);
60
+ if (path !== undefined && !writable.includes(path))
61
+ writable.push(path);
62
+ }
63
+ const hidden = [...HIDDEN_HOME_PATHS.map((p) => join(home, p)), ...(deps.hidden ?? [])];
64
+ const status = deps.status;
65
+ const usable = status.kind === "sandbox-exec" || status.kind === "bwrap";
66
+ const active = mode === "auto" && usable && status.restrictsWrites;
67
+ let detail;
68
+ if (mode === "off")
69
+ detail = "关闭(sandbox.bash: off)";
70
+ else if (!active)
71
+ detail =
72
+ status.kind === "unshare"
73
+ ? "不可用:unshare 只隔离网络、不能限制写入"
74
+ : `不可用:${status.detail}`;
75
+ else
76
+ detail =
77
+ `${status.kind},网络 ${network},可写:工作区、临时目录、输出目录` +
78
+ (writable.length > 0 ? `、${writable.join("、")}` : "");
79
+ return { active, status, network, writable, hidden, detail };
80
+ }
81
+ /** 一次 bash 调用的沙箱策略(路径未 realpath,wrapCommand 再解析)。 */
82
+ export function bashSandboxPolicy(sandbox, place) {
83
+ const writable = [place.workspace, place.tmpdir ?? tmpdir()];
84
+ if ((place.platform ?? process.platform) !== "win32")
85
+ writable.push("/tmp");
86
+ if (place.outputDir !== undefined)
87
+ writable.push(place.outputDir);
88
+ writable.push(...sandbox.writable);
89
+ return {
90
+ network: sandbox.network,
91
+ writable,
92
+ readOnly: WORKSPACE_READ_ONLY.map((p) => join(place.workspace, p)),
93
+ hiddenDirs: [...sandbox.hidden],
94
+ };
95
+ }
96
+ /** 调用参数里显式要求不经沙箱(`sandbox: false`)。 */
97
+ export function wantsUnsandboxed(input) {
98
+ return (typeof input === "object" &&
99
+ input !== null &&
100
+ input["sandbox"] === false);
101
+ }
102
+ /** 这次调用会不会经沙箱运行(权限管线与 bash 工具共用,保证两边结论一致)。 */
103
+ export function runsSandboxed(sandbox, input) {
104
+ return sandbox?.active === true && !wantsUnsandboxed(input);
105
+ }
106
+ /**
107
+ * 包装 shell 命令行;设定生效但没能包上(不应发生)时抛错——权限管线已按「在沙箱内」放行,不能悄悄裸跑。
108
+ */
109
+ export function wrapBashCommand(sandbox, shell, args, place) {
110
+ const wrapped = wrapCommand(sandbox.status, shell, args, bashSandboxPolicy(sandbox, place));
111
+ if (!wrapped.sandboxed || !wrapped.writesRestricted)
112
+ throw new Error(`sandbox: could not wrap the command with ${sandbox.status.kind}`);
113
+ return wrapped;
114
+ }
115
+ const WRITE_DENIAL = /Operation not permitted|Read-only file system|\bEPERM\b|\bEROFS\b|Permission denied|\bEACCES\b/i;
116
+ const NETWORK_DENIAL = /Could not resolve host|\bENOTFOUND\b|\bEAI_AGAIN\b|getaddrinfo|nodename nor servname|Temporary failure in name resolution|Name or service not known|Network is unreachable|\bENETUNREACH\b|Couldn't connect to server|Failed to connect|\bECONNREFUSED\b|Could not resolve hostname/i;
117
+ /** 失败输出看起来像被沙箱拒绝(写入被拒;网络拒绝时另看联网失败)。 */
118
+ export function looksLikeSandboxDenial(output, networkDenied) {
119
+ return WRITE_DENIAL.test(output) || (networkDenied && NETWORK_DENIAL.test(output));
120
+ }
121
+ /** 沙箱拒绝时追加给模型的一行说明。 */
122
+ export function sandboxDenialHint(networkDenied) {
123
+ return ("[sandbox: this command ran in ama's OS sandbox (writes only in the workspace and temp dirs" +
124
+ (networkDenied ? ", no network" : "") +
125
+ "). If it failed because of that, rerun it with sandbox:false, which needs the user's approval.]");
126
+ }
@@ -0,0 +1,48 @@
1
+ /**
2
+ * 操作系统沙箱能力探测(docs/sandbox.md「探测与降级」)。
3
+ *
4
+ * - 「存在」不等于「可用」(嵌套在别的沙箱里、容器里没有用户命名空间):用目标配置跑一次最小探针,退出码 0
5
+ * 才算可用;
6
+ * - macOS:`/usr/bin/sandbox-exec`;Linux:PATH 里的 `bwrap`,失败再试 `unshare -r -n`(只隔离网络);
7
+ * 其它平台:none;
8
+ * - 开关:`sandbox.enabled: off` 或环境变量 `AMA_SANDBOX=off`;
9
+ * - 结果在进程内缓存(按开关分两份);`configureOsSandbox` 记下组装根读到的配置,供拿不到配置的只读调用方
10
+ * (状态栏)得到一致的结论。
11
+ */
12
+ import { type OsSandboxKind } from "./profile.js";
13
+ export type SandboxEnabled = "auto" | "off";
14
+ export interface OsSandboxStatus {
15
+ kind: OsSandboxKind | "none";
16
+ /** 沙箱程序的绝对路径(kind 不是 none 时)。 */
17
+ path?: string;
18
+ /** 能拒绝网络。 */
19
+ isolatesNetwork: boolean;
20
+ /** 能把写入限制在指定目录(unshare 不能)。 */
21
+ restrictsWrites: boolean;
22
+ /** 人读说明(中文,给 doctor / config show)。 */
23
+ detail: string;
24
+ }
25
+ export declare const NO_OS_SANDBOX: OsSandboxStatus;
26
+ export declare const SANDBOX_EXEC_PATH = "/usr/bin/sandbox-exec";
27
+ export declare const PROBE_TIMEOUT_MS = 5000;
28
+ export interface ProbeDeps {
29
+ platform: NodeJS.Platform;
30
+ env: NodeJS.ProcessEnv;
31
+ /** 可执行文件存在且可执行。 */
32
+ isExecutable(path: string): boolean;
33
+ /** 同步运行,返回退出码(启动失败 / 超时 / 被信号杀 → null)。 */
34
+ run(command: string, args: readonly string[]): number | null;
35
+ }
36
+ export declare const REAL_PROBE_DEPS: ProbeDeps;
37
+ /** 在 PATH 里找可执行文件(按目标平台的路径规则)。 */
38
+ export declare function findExecutable(name: string, env: NodeJS.ProcessEnv, check: (path: string) => boolean, platform?: NodeJS.Platform): string | undefined;
39
+ /** 生效的开关:环境变量 `AMA_SANDBOX=off` 优先于配置。 */
40
+ export declare function resolveSandboxEnabled(configured: SandboxEnabled | undefined, env?: NodeJS.ProcessEnv): SandboxEnabled;
41
+ /** 不缓存的探测(测试注入 deps)。 */
42
+ export declare function probeOsSandbox(enabled: SandboxEnabled, deps?: ProbeDeps): OsSandboxStatus;
43
+ /** 组装根读到配置后记下(拿不到配置的只读调用方据此得到一致结论);返回生效的状态。 */
44
+ export declare function configureOsSandbox(enabled: SandboxEnabled | undefined): OsSandboxStatus;
45
+ /** 进程内缓存的探测结果;不传开关时用 `configureOsSandbox` 记下的配置(缺省 auto)。 */
46
+ export declare function osSandboxStatus(enabled?: SandboxEnabled | undefined): OsSandboxStatus;
47
+ /** 测试用:清空缓存与记下的配置。 */
48
+ export declare function resetOsSandboxForTests(): void;