@armadra/agent 0.0.0-stage → 0.2.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 (407) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/LICENSE +21 -0
  3. package/README.md +426 -2
  4. package/dist/agent/agent.d.ts +56 -0
  5. package/dist/agent/agent.js +129 -0
  6. package/dist/agent/loop.d.ts +51 -0
  7. package/dist/agent/loop.js +158 -0
  8. package/dist/agent/queue.d.ts +25 -0
  9. package/dist/agent/queue.js +55 -0
  10. package/dist/agent/retry.d.ts +22 -0
  11. package/dist/agent/retry.js +92 -0
  12. package/dist/agent/schema.d.ts +27 -0
  13. package/dist/agent/schema.js +186 -0
  14. package/dist/agent/session-cache.d.ts +100 -0
  15. package/dist/agent/session-cache.js +511 -0
  16. package/dist/agent/session-compaction.d.ts +49 -0
  17. package/dist/agent/session-compaction.js +251 -0
  18. package/dist/agent/session-core.d.ts +103 -0
  19. package/dist/agent/session-core.js +7 -0
  20. package/dist/agent/session-run.d.ts +55 -0
  21. package/dist/agent/session-run.js +246 -0
  22. package/dist/agent/session-state.d.ts +39 -0
  23. package/dist/agent/session-state.js +118 -0
  24. package/dist/agent/session-subagent.d.ts +54 -0
  25. package/dist/agent/session-subagent.js +157 -0
  26. package/dist/agent/session-sync.d.ts +20 -0
  27. package/dist/agent/session-sync.js +104 -0
  28. package/dist/agent/session-tools.d.ts +24 -0
  29. package/dist/agent/session-tools.js +277 -0
  30. package/dist/agent/session.d.ts +117 -0
  31. package/dist/agent/session.js +484 -0
  32. package/dist/agent/system-prompt.d.ts +49 -0
  33. package/dist/agent/system-prompt.js +121 -0
  34. package/dist/agent/tool-runner.d.ts +64 -0
  35. package/dist/agent/tool-runner.js +309 -0
  36. package/dist/agent/transform.d.ts +26 -0
  37. package/dist/agent/transform.js +171 -0
  38. package/dist/agent/types.d.ts +378 -0
  39. package/dist/agent/types.js +21 -0
  40. package/dist/ai/apis/anthropic-messages.d.ts +26 -0
  41. package/dist/ai/apis/anthropic-messages.js +214 -0
  42. package/dist/ai/apis/anthropic-request.d.ts +42 -0
  43. package/dist/ai/apis/anthropic-request.js +282 -0
  44. package/dist/ai/apis/api.d.ts +28 -0
  45. package/dist/ai/apis/api.js +102 -0
  46. package/dist/ai/apis/cache-params.d.ts +48 -0
  47. package/dist/ai/apis/cache-params.js +163 -0
  48. package/dist/ai/apis/google-generative-ai.d.ts +32 -0
  49. package/dist/ai/apis/google-generative-ai.js +249 -0
  50. package/dist/ai/apis/google-request.d.ts +40 -0
  51. package/dist/ai/apis/google-request.js +255 -0
  52. package/dist/ai/apis/openai-compat.d.ts +35 -0
  53. package/dist/ai/apis/openai-compat.js +142 -0
  54. package/dist/ai/apis/openai-completions.d.ts +28 -0
  55. package/dist/ai/apis/openai-completions.js +246 -0
  56. package/dist/ai/apis/openai-request.d.ts +35 -0
  57. package/dist/ai/apis/openai-request.js +303 -0
  58. package/dist/ai/apis/openai-responses-request.d.ts +52 -0
  59. package/dist/ai/apis/openai-responses-request.js +266 -0
  60. package/dist/ai/apis/openai-responses.d.ts +28 -0
  61. package/dist/ai/apis/openai-responses.js +303 -0
  62. package/dist/ai/apis/shared.d.ts +56 -0
  63. package/dist/ai/apis/shared.js +179 -0
  64. package/dist/ai/cache/economics.d.ts +24 -0
  65. package/dist/ai/cache/economics.js +69 -0
  66. package/dist/ai/cache/fingerprint.d.ts +17 -0
  67. package/dist/ai/cache/fingerprint.js +39 -0
  68. package/dist/ai/cache/miss.d.ts +49 -0
  69. package/dist/ai/cache/miss.js +96 -0
  70. package/dist/ai/cache/reporting.d.ts +39 -0
  71. package/dist/ai/cache/reporting.js +102 -0
  72. package/dist/ai/cache/types.d.ts +94 -0
  73. package/dist/ai/cache/types.js +19 -0
  74. package/dist/ai/cache/warmer.d.ts +94 -0
  75. package/dist/ai/cache/warmer.js +224 -0
  76. package/dist/ai/context.d.ts +35 -0
  77. package/dist/ai/context.js +114 -0
  78. package/dist/ai/cost.d.ts +21 -0
  79. package/dist/ai/cost.js +60 -0
  80. package/dist/ai/event-stream.d.ts +33 -0
  81. package/dist/ai/event-stream.js +101 -0
  82. package/dist/ai/fake/fake-provider.d.ts +68 -0
  83. package/dist/ai/fake/fake-provider.js +278 -0
  84. package/dist/ai/fake/fake-script.d.ts +69 -0
  85. package/dist/ai/fake/fake-script.js +142 -0
  86. package/dist/ai/http.d.ts +54 -0
  87. package/dist/ai/http.js +212 -0
  88. package/dist/ai/json-partial.d.ts +17 -0
  89. package/dist/ai/json-partial.js +243 -0
  90. package/dist/ai/overflow.d.ts +22 -0
  91. package/dist/ai/overflow.js +61 -0
  92. package/dist/ai/providers/auth.d.ts +71 -0
  93. package/dist/ai/providers/auth.js +202 -0
  94. package/dist/ai/providers/builtin.d.ts +23 -0
  95. package/dist/ai/providers/builtin.js +148 -0
  96. package/dist/ai/providers/catalog-data.d.ts +5 -0
  97. package/dist/ai/providers/catalog-data.js +19 -0
  98. package/dist/ai/providers/catalog.d.ts +28 -0
  99. package/dist/ai/providers/catalog.js +166 -0
  100. package/dist/ai/providers/registry.d.ts +83 -0
  101. package/dist/ai/providers/registry.js +305 -0
  102. package/dist/ai/sse.d.ts +32 -0
  103. package/dist/ai/sse.js +140 -0
  104. package/dist/ai/thinking.d.ts +42 -0
  105. package/dist/ai/thinking.js +101 -0
  106. package/dist/ai/types.d.ts +428 -0
  107. package/dist/ai/types.js +19 -0
  108. package/dist/bundle/ama-sandbox.cjs +324 -0
  109. package/dist/bundle/ama.cjs +25770 -0
  110. package/dist/bundle.d.ts +9 -0
  111. package/dist/bundle.js +15 -0
  112. package/dist/cli/args.d.ts +82 -0
  113. package/dist/cli/args.js +381 -0
  114. package/dist/cli/bootstrap.d.ts +18 -0
  115. package/dist/cli/bootstrap.js +398 -0
  116. package/dist/cli/compose-providers.d.ts +37 -0
  117. package/dist/cli/compose-providers.js +104 -0
  118. package/dist/cli/compose-session.d.ts +69 -0
  119. package/dist/cli/compose-session.js +370 -0
  120. package/dist/cli/compose-store.d.ts +24 -0
  121. package/dist/cli/compose-store.js +125 -0
  122. package/dist/cli/compose.d.ts +106 -0
  123. package/dist/cli/compose.js +206 -0
  124. package/dist/cli/default-model.d.ts +16 -0
  125. package/dist/cli/default-model.js +24 -0
  126. package/dist/cli/deps.d.ts +205 -0
  127. package/dist/cli/deps.js +12 -0
  128. package/dist/cli/exit-codes.d.ts +29 -0
  129. package/dist/cli/exit-codes.js +40 -0
  130. package/dist/cli/main.d.ts +26 -0
  131. package/dist/cli/main.js +165 -0
  132. package/dist/cli/runtime.d.ts +90 -0
  133. package/dist/cli/runtime.js +8 -0
  134. package/dist/cli/startup-screen.d.ts +15 -0
  135. package/dist/cli/startup-screen.js +56 -0
  136. package/dist/cli/startup-steps.d.ts +35 -0
  137. package/dist/cli/startup-steps.js +197 -0
  138. package/dist/cli/subcommands/auth.d.ts +12 -0
  139. package/dist/cli/subcommands/auth.js +91 -0
  140. package/dist/cli/subcommands/config.d.ts +44 -0
  141. package/dist/cli/subcommands/config.js +201 -0
  142. package/dist/cli/subcommands/context.d.ts +21 -0
  143. package/dist/cli/subcommands/context.js +41 -0
  144. package/dist/cli/subcommands/doctor.d.ts +11 -0
  145. package/dist/cli/subcommands/doctor.js +246 -0
  146. package/dist/cli/subcommands/models-cache-probe.d.ts +34 -0
  147. package/dist/cli/subcommands/models-cache-probe.js +190 -0
  148. package/dist/cli/subcommands/models-discover.d.ts +40 -0
  149. package/dist/cli/subcommands/models-discover.js +204 -0
  150. package/dist/cli/subcommands/models.d.ts +40 -0
  151. package/dist/cli/subcommands/models.js +144 -0
  152. package/dist/cli/subcommands/sessions.d.ts +11 -0
  153. package/dist/cli/subcommands/sessions.js +100 -0
  154. package/dist/codemode/capability.d.ts +37 -0
  155. package/dist/codemode/capability.js +55 -0
  156. package/dist/codemode/declarations.d.ts +44 -0
  157. package/dist/codemode/declarations.js +111 -0
  158. package/dist/codemode/host-side.d.ts +59 -0
  159. package/dist/codemode/host-side.js +253 -0
  160. package/dist/codemode/modes.d.ts +23 -0
  161. package/dist/codemode/modes.js +40 -0
  162. package/dist/codemode/protocol.d.ts +91 -0
  163. package/dist/codemode/protocol.js +114 -0
  164. package/dist/codemode/sandbox-entry.d.ts +25 -0
  165. package/dist/codemode/sandbox-entry.js +323 -0
  166. package/dist/codemode/store.d.ts +26 -0
  167. package/dist/codemode/store.js +53 -0
  168. package/dist/codemode/tool.d.ts +105 -0
  169. package/dist/codemode/tool.js +283 -0
  170. package/dist/compaction/branch-summary.d.ts +30 -0
  171. package/dist/compaction/branch-summary.js +79 -0
  172. package/dist/compaction/breaker.d.ts +32 -0
  173. package/dist/compaction/breaker.js +65 -0
  174. package/dist/compaction/cut-point.d.ts +23 -0
  175. package/dist/compaction/cut-point.js +70 -0
  176. package/dist/compaction/estimate.d.ts +30 -0
  177. package/dist/compaction/estimate.js +114 -0
  178. package/dist/compaction/prune-tier.d.ts +31 -0
  179. package/dist/compaction/prune-tier.js +83 -0
  180. package/dist/compaction/serialize.d.ts +20 -0
  181. package/dist/compaction/serialize.js +115 -0
  182. package/dist/compaction/summarize-tier.d.ts +111 -0
  183. package/dist/compaction/summarize-tier.js +305 -0
  184. package/dist/config/auth-file.d.ts +39 -0
  185. package/dist/config/auth-file.js +92 -0
  186. package/dist/config/context-files.d.ts +30 -0
  187. package/dist/config/context-files.js +77 -0
  188. package/dist/config/load.d.ts +45 -0
  189. package/dist/config/load.js +97 -0
  190. package/dist/config/merge.d.ts +73 -0
  191. package/dist/config/merge.js +248 -0
  192. package/dist/config/paths.d.ts +38 -0
  193. package/dist/config/paths.js +108 -0
  194. package/dist/config/profile.d.ts +27 -0
  195. package/dist/config/profile.js +65 -0
  196. package/dist/config/schema.d.ts +34 -0
  197. package/dist/config/schema.js +413 -0
  198. package/dist/config/trust.d.ts +42 -0
  199. package/dist/config/trust.js +122 -0
  200. package/dist/config/types.d.ts +172 -0
  201. package/dist/config/types.js +27 -0
  202. package/dist/config/write.d.ts +10 -0
  203. package/dist/config/write.js +25 -0
  204. package/dist/errors.d.ts +28 -0
  205. package/dist/errors.js +30 -0
  206. package/dist/hooks/config.d.ts +49 -0
  207. package/dist/hooks/config.js +102 -0
  208. package/dist/hooks/dispatcher.d.ts +41 -0
  209. package/dist/hooks/dispatcher.js +104 -0
  210. package/dist/hooks/matcher.d.ts +22 -0
  211. package/dist/hooks/matcher.js +108 -0
  212. package/dist/hooks/protocol.d.ts +33 -0
  213. package/dist/hooks/protocol.js +240 -0
  214. package/dist/hooks/runner.d.ts +30 -0
  215. package/dist/hooks/runner.js +143 -0
  216. package/dist/hooks/types.d.ts +147 -0
  217. package/dist/hooks/types.js +20 -0
  218. package/dist/host/api-impl.d.ts +75 -0
  219. package/dist/host/api-impl.js +173 -0
  220. package/dist/host/loader.d.ts +31 -0
  221. package/dist/host/loader.js +147 -0
  222. package/dist/host/types.d.ts +169 -0
  223. package/dist/host/types.js +14 -0
  224. package/dist/host.d.ts +5 -0
  225. package/dist/host.js +4 -0
  226. package/dist/index.d.ts +41 -0
  227. package/dist/index.js +28 -0
  228. package/dist/modes/commands-core.d.ts +44 -0
  229. package/dist/modes/commands-core.js +171 -0
  230. package/dist/modes/interactive/approval-dialog.d.ts +48 -0
  231. package/dist/modes/interactive/approval-dialog.js +202 -0
  232. package/dist/modes/interactive/commands.d.ts +41 -0
  233. package/dist/modes/interactive/commands.js +202 -0
  234. package/dist/modes/interactive/completion.d.ts +53 -0
  235. package/dist/modes/interactive/completion.js +157 -0
  236. package/dist/modes/interactive/interactive-mode.d.ts +46 -0
  237. package/dist/modes/interactive/interactive-mode.js +487 -0
  238. package/dist/modes/interactive/key-dispatch.d.ts +29 -0
  239. package/dist/modes/interactive/key-dispatch.js +107 -0
  240. package/dist/modes/interactive/line/line-editor.d.ts +50 -0
  241. package/dist/modes/interactive/line/line-editor.js +232 -0
  242. package/dist/modes/interactive/line/line-mode.d.ts +20 -0
  243. package/dist/modes/interactive/line/line-mode.js +216 -0
  244. package/dist/modes/interactive/line/line-render.d.ts +35 -0
  245. package/dist/modes/interactive/line/line-render.js +171 -0
  246. package/dist/modes/interactive/line/paste-state.d.ts +26 -0
  247. package/dist/modes/interactive/line/paste-state.js +72 -0
  248. package/dist/modes/interactive/message-view.d.ts +77 -0
  249. package/dist/modes/interactive/message-view.js +269 -0
  250. package/dist/modes/interactive/pickers.d.ts +42 -0
  251. package/dist/modes/interactive/pickers.js +115 -0
  252. package/dist/modes/interactive/startup-ui.d.ts +28 -0
  253. package/dist/modes/interactive/startup-ui.js +238 -0
  254. package/dist/modes/interactive/status-bar.d.ts +48 -0
  255. package/dist/modes/interactive/status-bar.js +139 -0
  256. package/dist/modes/interactive/tool-view.d.ts +95 -0
  257. package/dist/modes/interactive/tool-view.js +344 -0
  258. package/dist/modes/print/json-event.d.ts +15 -0
  259. package/dist/modes/print/json-event.js +39 -0
  260. package/dist/modes/print/print-mode.d.ts +15 -0
  261. package/dist/modes/print/print-mode.js +96 -0
  262. package/dist/modes/rpc/commands.d.ts +40 -0
  263. package/dist/modes/rpc/commands.js +258 -0
  264. package/dist/modes/rpc/jsonl.d.ts +16 -0
  265. package/dist/modes/rpc/jsonl.js +55 -0
  266. package/dist/modes/rpc/rpc-mode.d.ts +22 -0
  267. package/dist/modes/rpc/rpc-mode.js +153 -0
  268. package/dist/modes/session-report.d.ts +55 -0
  269. package/dist/modes/session-report.js +278 -0
  270. package/dist/modes/shared.d.ts +13 -0
  271. package/dist/modes/shared.js +52 -0
  272. package/dist/modes/startup-ui-text.d.ts +16 -0
  273. package/dist/modes/startup-ui-text.js +103 -0
  274. package/dist/permissions/broker.d.ts +47 -0
  275. package/dist/permissions/broker.js +107 -0
  276. package/dist/permissions/dangerous.d.ts +47 -0
  277. package/dist/permissions/dangerous.js +370 -0
  278. package/dist/permissions/pipeline.d.ts +51 -0
  279. package/dist/permissions/pipeline.js +181 -0
  280. package/dist/permissions/preview.d.ts +43 -0
  281. package/dist/permissions/preview.js +463 -0
  282. package/dist/permissions/rules.d.ts +58 -0
  283. package/dist/permissions/rules.js +249 -0
  284. package/dist/permissions/types.d.ts +100 -0
  285. package/dist/permissions/types.js +18 -0
  286. package/dist/rpc.d.ts +171 -0
  287. package/dist/rpc.js +13 -0
  288. package/dist/sdk.d.ts +98 -0
  289. package/dist/sdk.js +195 -0
  290. package/dist/session/manager.d.ts +70 -0
  291. package/dist/session/manager.js +278 -0
  292. package/dist/session/migrate.d.ts +19 -0
  293. package/dist/session/migrate.js +53 -0
  294. package/dist/session/projection.d.ts +50 -0
  295. package/dist/session/projection.js +180 -0
  296. package/dist/session/store.d.ts +47 -0
  297. package/dist/session/store.js +210 -0
  298. package/dist/session/tree.d.ts +21 -0
  299. package/dist/session/tree.js +88 -0
  300. package/dist/session/types.d.ts +199 -0
  301. package/dist/session/types.js +18 -0
  302. package/dist/skills/discover.d.ts +60 -0
  303. package/dist/skills/discover.js +160 -0
  304. package/dist/skills/expand.d.ts +35 -0
  305. package/dist/skills/expand.js +46 -0
  306. package/dist/skills/frontmatter.d.ts +27 -0
  307. package/dist/skills/frontmatter.js +157 -0
  308. package/dist/skills/index-prompt.d.ts +13 -0
  309. package/dist/skills/index-prompt.js +42 -0
  310. package/dist/skills/templates.d.ts +52 -0
  311. package/dist/skills/templates.js +177 -0
  312. package/dist/tools/bash.d.ts +49 -0
  313. package/dist/tools/bash.js +222 -0
  314. package/dist/tools/edit-fuzzy.d.ts +36 -0
  315. package/dist/tools/edit-fuzzy.js +129 -0
  316. package/dist/tools/edit.d.ts +38 -0
  317. package/dist/tools/edit.js +241 -0
  318. package/dist/tools/file-mutex.d.ts +8 -0
  319. package/dist/tools/file-mutex.js +29 -0
  320. package/dist/tools/glob.d.ts +44 -0
  321. package/dist/tools/glob.js +217 -0
  322. package/dist/tools/grep.d.ts +39 -0
  323. package/dist/tools/grep.js +179 -0
  324. package/dist/tools/ignore.d.ts +40 -0
  325. package/dist/tools/ignore.js +174 -0
  326. package/dist/tools/ls.d.ts +21 -0
  327. package/dist/tools/ls.js +96 -0
  328. package/dist/tools/output-accumulator.d.ts +48 -0
  329. package/dist/tools/output-accumulator.js +106 -0
  330. package/dist/tools/paths.d.ts +20 -0
  331. package/dist/tools/paths.js +58 -0
  332. package/dist/tools/presets.d.ts +71 -0
  333. package/dist/tools/presets.js +128 -0
  334. package/dist/tools/process-tree.d.ts +35 -0
  335. package/dist/tools/process-tree.js +125 -0
  336. package/dist/tools/read.d.ts +28 -0
  337. package/dist/tools/read.js +181 -0
  338. package/dist/tools/registry.d.ts +43 -0
  339. package/dist/tools/registry.js +106 -0
  340. package/dist/tools/shell.d.ts +38 -0
  341. package/dist/tools/shell.js +91 -0
  342. package/dist/tools/task.d.ts +29 -0
  343. package/dist/tools/task.js +107 -0
  344. package/dist/tools/todo.d.ts +28 -0
  345. package/dist/tools/todo.js +107 -0
  346. package/dist/tools/truncate.d.ts +44 -0
  347. package/dist/tools/truncate.js +175 -0
  348. package/dist/tools/types.d.ts +135 -0
  349. package/dist/tools/types.js +19 -0
  350. package/dist/tools/write.d.ts +20 -0
  351. package/dist/tools/write.js +84 -0
  352. package/dist/tui/ansi.d.ts +29 -0
  353. package/dist/tui/ansi.js +420 -0
  354. package/dist/tui/component.d.ts +38 -0
  355. package/dist/tui/component.js +13 -0
  356. package/dist/tui/components/box.d.ts +26 -0
  357. package/dist/tui/components/box.js +65 -0
  358. package/dist/tui/components/container.d.ts +14 -0
  359. package/dist/tui/components/container.js +39 -0
  360. package/dist/tui/components/editor-buffer.d.ts +67 -0
  361. package/dist/tui/components/editor-buffer.js +300 -0
  362. package/dist/tui/components/editor-paste.d.ts +29 -0
  363. package/dist/tui/components/editor-paste.js +64 -0
  364. package/dist/tui/components/editor.d.ts +114 -0
  365. package/dist/tui/components/editor.js +530 -0
  366. package/dist/tui/components/key-value.d.ts +29 -0
  367. package/dist/tui/components/key-value.js +48 -0
  368. package/dist/tui/components/loader.d.ts +35 -0
  369. package/dist/tui/components/loader.js +71 -0
  370. package/dist/tui/components/markdown.d.ts +90 -0
  371. package/dist/tui/components/markdown.js +462 -0
  372. package/dist/tui/components/meter.d.ts +29 -0
  373. package/dist/tui/components/meter.js +47 -0
  374. package/dist/tui/components/overlay.d.ts +24 -0
  375. package/dist/tui/components/overlay.js +52 -0
  376. package/dist/tui/components/select-list.d.ts +57 -0
  377. package/dist/tui/components/select-list.js +179 -0
  378. package/dist/tui/components/spacer.d.ts +11 -0
  379. package/dist/tui/components/spacer.js +16 -0
  380. package/dist/tui/components/text.d.ts +30 -0
  381. package/dist/tui/components/text.js +65 -0
  382. package/dist/tui/keybindings.d.ts +66 -0
  383. package/dist/tui/keybindings.js +120 -0
  384. package/dist/tui/keys.d.ts +38 -0
  385. package/dist/tui/keys.js +275 -0
  386. package/dist/tui/stdin-buffer.d.ts +41 -0
  387. package/dist/tui/stdin-buffer.js +206 -0
  388. package/dist/tui/terminal.d.ts +79 -0
  389. package/dist/tui/terminal.js +153 -0
  390. package/dist/tui/theme.d.ts +31 -0
  391. package/dist/tui/theme.js +199 -0
  392. package/dist/tui/tui.d.ts +103 -0
  393. package/dist/tui/tui.js +363 -0
  394. package/dist/tui/vt-screen.d.ts +46 -0
  395. package/dist/tui/vt-screen.js +251 -0
  396. package/dist/tui.d.ts +30 -0
  397. package/dist/tui.js +31 -0
  398. package/dist/version.d.ts +8 -0
  399. package/dist/version.js +24 -0
  400. package/docs/codemode.md +102 -0
  401. package/docs/hooks.md +196 -0
  402. package/docs/host-api.md +161 -0
  403. package/docs/providers.md +316 -0
  404. package/docs/rpc.md +253 -0
  405. package/docs/session-format.md +119 -0
  406. package/docs/tui.md +168 -0
  407. package/package.json +101 -4
package/dist/tui.js ADDED
@@ -0,0 +1,31 @@
1
+ /**
2
+ * `@armadra/agent/tui` 子路径:组件库再导出(设计 D1、§12.1)。[B0] 所有。
3
+ *
4
+ * B0 只导出组件模型契约;B4 完成组件库后在本文件末尾追加各组件的再导出
5
+ * (TUI、ProcessTerminal / MemoryTerminal、Container、Text、Markdown、Editor、SelectList、Box、
6
+ * Spacer、Loader、Overlay、主题与 ansi 工具)——这是 B4 唯一允许改动的 B0 文件。
7
+ */
8
+ export { CURSOR_MARKER, isFocusable } from "./tui/component.js";
9
+ // ---- B4 组件库再导出 ----
10
+ export { TUI, SYNC_BEGIN, SYNC_END, WRITE_CHUNK_SIZE, MIN_RENDER_INTERVAL_MS, } from "./tui/tui.js";
11
+ export { ProcessTerminal, MemoryTerminal, BRACKETED_PASTE_ON, BRACKETED_PASTE_OFF, SHOW_CURSOR, HIDE_CURSOR, } from "./tui/terminal.js";
12
+ export { VirtualScreen } from "./tui/vt-screen.js";
13
+ export { StdinBuffer, defaultEscTimeout } from "./tui/stdin-buffer.js";
14
+ export { parseKey, matchesKey, normalizeKeyId, isPasteData, unwrapPaste, isPrintableText, PASTE_START, PASTE_END, } from "./tui/keys.js";
15
+ export { visibleWidth, truncateToWidth, sliceByColumn, wrapTextWithAnsi, padToWidth, stripAnsi, codePointWidth, graphemeWidth, SGR_RESET, } from "./tui/ansi.js";
16
+ export { createTheme, plainTheme, detectCapabilities, detectColorDepth, colorCode, rgbTo256, rgbTo16, THEME_PALETTES, } from "./tui/theme.js";
17
+ export { Keybindings, defaultKeybindings, DEFAULT_KEYBINDINGS, parseKeybindings, loadKeybindingsFile, isActionId, } from "./tui/keybindings.js";
18
+ export { Container } from "./tui/components/container.js";
19
+ export { Text, TruncatedText } from "./tui/components/text.js";
20
+ export { Markdown, parseMarkdown, renderInline, renderBlock, } from "./tui/components/markdown.js";
21
+ export { EditorBuffer, } from "./tui/components/editor-buffer.js";
22
+ export { Editor, loadHistoryFile, } from "./tui/components/editor.js";
23
+ export { PasteStore, shouldCollapse, formatMarker, PASTE_LINE_THRESHOLD, PASTE_CHAR_THRESHOLD, } from "./tui/components/editor-paste.js";
24
+ export { SelectList, filterItems, } from "./tui/components/select-list.js";
25
+ export { Box } from "./tui/components/box.js";
26
+ export { Spacer } from "./tui/components/spacer.js";
27
+ export { Loader, LOADER_FRAMES, formatElapsed, } from "./tui/components/loader.js";
28
+ export { compositeOverlays, } from "./tui/components/overlay.js";
29
+ // ---- W3-B9a-2 组件 ----
30
+ export { KeyValue } from "./tui/components/key-value.js";
31
+ export { Meter, METER_FULL, METER_EMPTY } from "./tui/components/meter.js";
@@ -0,0 +1,8 @@
1
+ /**
2
+ * 包版本。[B0] 所有。
3
+ *
4
+ * 补全说明:§1.2 没有这个文件,但 `ama --version`、`HostApi.agent.version`、会话头
5
+ * `agent.version` 都要它。bundle 构建时 esbuild 把 `__AMA_VERSION__` 定义为字面量;
6
+ * 未打包时(dist/ 或 vitest 跑 src/)从包根的 package.json 读取——两处都在本文件的 `../`。
7
+ */
8
+ export declare const AMA_VERSION: string;
@@ -0,0 +1,24 @@
1
+ /**
2
+ * 包版本。[B0] 所有。
3
+ *
4
+ * 补全说明:§1.2 没有这个文件,但 `ama --version`、`HostApi.agent.version`、会话头
5
+ * `agent.version` 都要它。bundle 构建时 esbuild 把 `__AMA_VERSION__` 定义为字面量;
6
+ * 未打包时(dist/ 或 vitest 跑 src/)从包根的 package.json 读取——两处都在本文件的 `../`。
7
+ */
8
+ import { readFileSync } from "node:fs";
9
+ function readPackageVersion() {
10
+ try {
11
+ const raw = readFileSync(new URL("../package.json", import.meta.url), "utf8");
12
+ const pkg = JSON.parse(raw);
13
+ if (typeof pkg === "object" && pkg !== null && "version" in pkg) {
14
+ const { version } = pkg;
15
+ if (typeof version === "string")
16
+ return version;
17
+ }
18
+ }
19
+ catch {
20
+ // 落到下面的兜底值
21
+ }
22
+ return "0.0.0-unknown";
23
+ }
24
+ export const AMA_VERSION = typeof __AMA_VERSION__ === "string" ? __AMA_VERSION__ : readPackageVersion();
@@ -0,0 +1,102 @@
1
+ # codemode
2
+
3
+ 设计依据见 [design.md](design.md) §5.5、§5.6、§9.1。
4
+
5
+ `codemode` 工具让模型写一段 JavaScript,在脚本里经 `tools.*` 编排多次工具调用,只有脚本输出回到模型。长流程、工具密集的任务里,它把多次往返合成一次,减少往返次数与缓存读取;短任务收益不明显,因此是可选的调用方式。
6
+
7
+ ## 打开
8
+
9
+ | 写法 | 模型看到的工具 |
10
+ | ------------------------------------------- | ----------------------------------------------------------------------------------- |
11
+ | `--tools-preset codemode`(`only`) | 只有 `codemode`;全部内置工具与宿主工具只能在脚本里调用,声明列在 `codemode` 描述里 |
12
+ | `--codemode on` / `codemode.mode: "on"` | 预设的工具 + `codemode`;其它工具描述末尾加一行提示 |
13
+ | `--codemode off` / 缺省(非 codemode 预设) | 不注册 `codemode` |
14
+
15
+ `codemode` 本身的权限类随沙箱能力:网络隔离(Node ≥ 25,见下文沙箱)时是 `read` 类,`default` 权限模式下免审批——脚本只能经 `tools.*` 做事,每次内层调用仍逐个经过权限管线;网络未隔离(Node 22 / 24)时是 `execute` 类,`default` 模式下每次都要审批,`-p` 等无人值守场景直接拒绝,此时常用做法是在配置里放行它:
16
+
17
+ ```json
18
+ { "version": 1, "tools": { "preset": "codemode" }, "permission": { "allow": ["codemode"] } }
19
+ ```
20
+
21
+ 其它配置:`codemode.inlineBudget`(描述里内联声明的预算,估算 token,缺省 3000,超出只列名字)、`codemode.requireStrict`(见下文沙箱)。项目级配置只能把 `codemode.mode` 设为 `off`。
22
+
23
+ ## 脚本
24
+
25
+ 输入是原始 JavaScript(不是 JSON,不要代码块),作为 async 函数体执行,可用顶层 `await` 与 `return`。首行可选:
26
+
27
+ ```js
28
+ // @options: {"max_output_tokens": 2000, "timeout_ms": 60000}
29
+ ```
30
+
31
+ - `max_output_tokens`(缺省 10 000,按字符 / 4 估算):输出超出时保留首尾,全文写 `<会话目录>/outputs/<toolCallId>.txt`(内存会话写系统临时目录)。单条工具结果上限(`tools.maxToolResultChars`,缺省 30 000 字符)更小时以它为准。
32
+ - `timeout_ms`(缺省 300 000,上限 3 600 000):整个脚本的硬期限,到点杀掉子进程树。
33
+
34
+ | 全局 | 作用 |
35
+ | ------------------------------ | --------------------------------------------------------------------------------- |
36
+ | `tools.<name>(args)` | 调用会话里任一未禁用的工具(含宿主注册的 `canvas_*`),走与模型直接调用相同的门禁 |
37
+ | `text(v)` / `console.log(...)` | 追加输出;字符串原样,其它值按 JSON(`console.info / warn / error / debug` 相同) |
38
+ | `return v` | 同 `text(v)` |
39
+ | `store(key, v)` / `load(key)` | 跨次保留小块 JSON;`store(key, undefined)` 删除 |
40
+ | `ALL_TOOLS` | 可调用工具名(执行时的清单,含描述冻结之后才注册的宿主工具) |
41
+ | `describeTool(name)` | 单个工具的 TypeScript 声明 |
42
+
43
+ 没有 `require`、`import`、`process`、`fetch`、定时器;`eval` 与 `new Function` 被拒绝。工具只能写成 `tools.read({ path })`,不能直接 `read(...)`。
44
+
45
+ ### 给模型的描述
46
+
47
+ 描述首段写明规则(只有 `tools.<name>(args)`;没有 require / import / process / fetch / 定时器;不要把工具当函数直接调用),随后是一段 6 行示例脚本:`Promise.all` 并发两个 `tools.read`、过滤、`return`。实测 Kimi、MiniMax 在旧描述下会在脚本里写 `require` / `import`,或在 `only` 模式下直接调用 `read`。两类错误都给出正确写法:
48
+
49
+ - 脚本因 `require` / `import` / `process` / `fetch` / 定时器失败:`Script error` 后追加一行 `Only tools.<name>(args) is available in codemode scripts …`;脚本里直接调用工具名(`read is not defined`):追加 `Call tools as tools.read({...}), not read(...).`
50
+ - `only` 模式下系统提示的工具行写明 `codemode` 是唯一工具,规则节加一条「read / edit / bash 等不能直接调用,放进脚本里以 `tools.<name>(args)` 调用」。
51
+ - `only` 模式下模型仍绕过 `codemode` 直接调用工具时:错误结果是 `Tool read is only callable inside a codemode script: tools.read({...})`(真不存在的工具仍是 `Tool X not found`)。
52
+
53
+ ### 返回值
54
+
55
+ - `bash` 解析为 `{ output, truncated, fullOutputPath?, exitCode, wallTimeMs }`,非零退出码同样解析;`output` 是模型可见的版本(2000 行 / 50 KB 尾截断),`fullOutputPath` 存在时可再 `tools.read` 全文。
56
+ - 其它内置工具解析为文本;宿主 / SDK 工具返回 `structured` 时解析为它,否则为文本。
57
+ - 工具失败、被 Hook / 权限 / 用户拒绝、参数非法 → 以 `Error` reject,消息是工具的错误文本;用 `Promise.allSettled` 保留其余结果。
58
+ - 同一脚本内最多 8 个调用同时进行,多出的排队;脚本里不能调用 `codemode`。
59
+
60
+ ### 结果
61
+
62
+ `Script completed` / `Script failed` + 用时 + 输出;失败时保留已产生的输出,末尾附 `Script error: …`(带脚本行号)。已完成的工具调用不回滚;脚本结束时仍在跑的调用被取消,未 await 的 Promise 被丢弃。
63
+
64
+ ### store
65
+
66
+ 脚本成功结束且写过 store 时,追加一条 `custom{customType:"ama.codemode-store"}` 条目,内容是完整快照;读取取活动分支上最近一条,所以 `/resume` 后值仍在,切分支、fork 后只看本分支写过的值。单值 JSON ≤ 262 144 字符,合计 ≤ 1 048 576 字符;超限时 `store()` 抛 `RangeError`。失败的脚本不提交。
67
+
68
+ ## Hook 与事件
69
+
70
+ - `codemode` 本身作为一次工具调用经过 PreToolUse、权限与 PostToolUse。
71
+ - 脚本里的每次 `tools.*` 再各自经过完整流程,Hook 按**真实工具名**匹配(`bash`,不是 `codemode`);Hook 输入多两个字段:`viaCodemode: true` 与 `parentToolCallId`(外层 `codemode` 调用的 id)。
72
+ - 事件:`tool_execution_update` 透传脚本输出(最近 4000 字符);内层调用发 `tool_execution_start / end`,带 `parentToolCallId`,不进转录、不进模型上下文。
73
+
74
+ ## 沙箱
75
+
76
+ 每次执行起一个子进程:
77
+
78
+ ```text
79
+ <node> --permission --allow-fs-read=<ama-sandbox.cjs> --disallow-code-generation-from-strings <ama-sandbox.cjs> --ama-codemode-sandbox
80
+ ```
81
+
82
+ - 空环境启动,拿不到密钥、会话文件与环境变量(Windows 上 libuv 会从父进程补入 PATH、SYSTEMROOT、USERPROFILE 等系统变量,不含密钥);不授予文件写、子进程、worker、addon、inspector 权限;Node 22.0–22.12 用 `--experimental-permission`;嵌入 Electron 时设 `ELECTRON_RUN_AS_NODE=1`。
83
+ - 子进程里用 `node:vm` 建只含 ECMAScript 内建对象的上下文(`codeGeneration: { strings: false, wasm: false }`,沙箱对象空原型);全局函数都在上下文内定义,只经一个宿主函数交换 JSON 字符串;子进程主 realm 也禁止字符串生成代码,经构造器链逃逸拿不到 `Function("return process")`。
84
+ - `tools.*` 经 stdin / stdout 的 JSON 行协议回调父进程执行。
85
+ - 网络:Node ≥ 25 的权限模型同时拒绝网络(strict);Node 22 / 24 不管网络,脚本若逃出 `vm` 就能联网——此时工具描述标注 `network not isolated`,`codemode.requireStrict: true` 时直接不注册 `codemode` 并给出 warning(codemode 预设随之回退到 default)。
86
+
87
+ | 实测(`--permission` + 只读入口) | Node 22.19 | Node 24.21 | Node 26.10 |
88
+ | --------------------------------- | ---------- | ---------- | ---------- |
89
+ | 读其它文件 | 拒绝 | 拒绝 | 拒绝 |
90
+ | 写文件 | 拒绝 | 拒绝 | 拒绝 |
91
+ | 起子进程 / worker | 拒绝 | 拒绝 | 拒绝 |
92
+ | 联网(fetch / TCP) | **允许** | **允许** | 拒绝 |
93
+
94
+ 沙箱防的是脚本**绕过权限管线**,不是对抗性的代码执行环境;脚本能造成的副作用都来自它调用的工具,而工具调用照常受 Hook、权限与审批约束。
95
+
96
+ ## 缓存
97
+
98
+ `codemode` 的描述(含工具声明)在第一次读取时确定并冻结,同一会话内字节稳定;之后宿主注册的工具不改变描述(`only` 模式下也不进活动集),但脚本里可以调用,`ALL_TOOLS` / `describeTool` 能查到。
99
+
100
+ - 脚本里的内层调用不进转录、不进模型上下文,所以一段脚本无论调用多少次工具,前缀都只多一次 `codemode` 调用与它的结果。
101
+ - 一段脚本可能跑几分钟(长测试、批量读写),这正是缓存保温覆盖的场景:保温不区分 codemode,运行期间(`cache.warming: "streaming"`,缺省)在 TTL 到期前重放上一次请求续上缓存,脚本结束后的下一次请求仍按读价计费。保温的前提与经济性见 [providers.md](providers.md)「保温」。
102
+ - `/cache fingerprint` 打印最近一次请求的 system / 工具表哈希;开了 codemode 之后哈希在会话内应保持不变。
package/docs/hooks.md ADDED
@@ -0,0 +1,196 @@
1
+ # 命令式 Hook(hooks.json)
2
+
3
+ 命令式 Hook 是在固定时机运行的 shell 命令:ama 把事件写成 JSON 交给命令的 stdin,按退出码与 stdout JSON 决定放行、阻止或改写。它是**用户策略**层——可以改工具输入、一票否决工具调用、给提示追加上下文、让运行再跑一轮。类型定义在 `src/hooks/types.ts`(经 `@armadra/agent` 导出 `HookInput`、`HookOutput`、`HookConfig` 等)。设计依据见 [design.md](design.md) §6.1、§6.3、§7.3。
4
+
5
+ ## 配置
6
+
7
+ ```json
8
+ {
9
+ "version": 1,
10
+ "hooks": {
11
+ "PreToolUse": [
12
+ {
13
+ "matcher": "bash",
14
+ "hooks": [{ "type": "command", "command": "./scripts/guard.sh", "timeoutMs": 10000 }]
15
+ },
16
+ { "matcher": "write|edit", "hooks": [{ "type": "command", "command": "ama-fmt-check" }] }
17
+ ],
18
+ "PostToolUse": [
19
+ {
20
+ "matcher": "edit",
21
+ "hooks": [{ "type": "command", "command": "prettier --check \"$AMA_FILE\"" }]
22
+ }
23
+ ],
24
+ "UserPromptSubmit": [
25
+ { "hooks": [{ "type": "command", "command": "./scripts/inject-context.sh" }] }
26
+ ]
27
+ }
28
+ }
29
+ ```
30
+
31
+ | 位置 | 来源 | 说明 |
32
+ | -------------------------- | --------- | --------------------------------------------------------------- |
33
+ | `~/.config/ama/hooks.json` | `user` | 用户级(`AMA_CONFIG_DIR` 可改配置目录) |
34
+ | profile 的 `hooksFile` | `profile` | 宿主(如 Armadra)提供,视同用户级 |
35
+ | `<cwd>/.ama/hooks.json` | `project` | 项目级,**需要信任**;未信任时跳过,`ama doctor` 与启动画面提示 |
36
+
37
+ 三份按「用户 → profile → 项目」**拼接**各事件的数组,不覆盖。文件语法或字段错误(含非法 matcher)→ 启动失败,退出码 3。`config.json` 的 `hooks.timeoutMs` 设缺省超时(缺省 60 000 ms),单条命令的 `timeoutMs` 优先,上限 600 000 ms。`/hooks` 与 `ama doctor` 列出已加载的 Hook 及来源。SDK 的 `createAgentSession({ hooks })` 直接传 `HookConfig`,缺省不读文件系统里的 hooks.json。
38
+
39
+ ## 事件
40
+
41
+ | 事件 | 时机 | stdout JSON 可改变什么 | 退出码 2 |
42
+ | ------------------ | ---------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- | ----------------------------------- |
43
+ | `SessionStart` | 会话创建 / 恢复后、首次提示前(`source`) | `additionalContext` → 系统提示的 `hooks` 节;`decision: "block"` → 启动失败 | 启动失败,退出码 6(换会话时忽略) |
44
+ | `UserPromptSubmit` | 用户提示展开后、入转录前 | `decision: "block"` + `reason` 阻止本次提示;`updatedPrompt` 替换提示;`additionalContext` 作为 custom 消息随提示进上下文 | 阻止,reason 显示给用户 |
45
+ | `PreToolUse` | schema 校验之后、权限管线之前 | `decision: "allow" \| "deny" \| "ask"`、`reason`、`updatedInput` 替换工具输入 | deny,stderr 作为 reason 进工具结果 |
46
+ | `PostToolUse` | 工具执行后、结果入转录前 | `additionalContext` 追加到工具结果末尾;`decision: "block"` 把结果改为错误 | 结果标为错误,stderr 追加进结果 |
47
+ | `Stop` | 运行将要结束(`agent_before_settle`,没有排队的 followUp) | `decision: "block"` + `reason` → 以 reason 作为新的 user 消息**再跑一轮**(每次运行最多 3 次) | 同左 |
48
+ | `SubagentStop` | `task` 子会话将要结束 | 同 Stop,作用于子会话 | 同左 |
49
+ | `PreCompact` | 档二摘要压缩前 | `customInstructions` 追加到摘要提示;`decision: "block"` 取消本次压缩 | 取消压缩 |
50
+ | `Notification` | 需要用户注意:审批等待、运行结束、错误、重试 | 无(纯通知) | 忽略 |
51
+ | `SessionEnd` | 退出或换会话前(`reason: exit \| new \| switch`) | 无 | 忽略 |
52
+
53
+ 每个事件只接受上表的决策;`deny` 与 `block` 在两类事件间互换(`UserPromptSubmit` 返回 `deny` 视为 `block`,`PreToolUse` 返回 `block` 视为 `deny`),其它不接受的决策忽略并记 warning。
54
+
55
+ 任何事件的 stdout 都可以带 `"continue": false`:请求结束当前运行(reason 显示给用户)。`"suppressOutput": true` 被接受并合并,但当前界面本来就不显示 Hook 的 stdout,暂无可见效果。
56
+
57
+ ## 输入(stdin)
58
+
59
+ stdin 是一个 JSON 对象,写完即关闭。所有事件共有:
60
+
61
+ | 字段 | 说明 |
62
+ | ---------------- | ---------------------------------------------- |
63
+ | `hookEventName` | 事件名 |
64
+ | `sessionId` | 会话 id(子会话为子会话自己的) |
65
+ | `sessionFile` | 会话文件(落盘前缺省) |
66
+ | `cwd` | 会话 cwd |
67
+ | `model` | `{ provider, id }` |
68
+ | `permissionMode` | `plan` / `default` / `auto-edit` / `full-auto` |
69
+ | `depth` | 主会话 0,`task` 子会话 1 |
70
+ | `host` | 宿主适配器 id(激活时) |
71
+
72
+ 事件特有:
73
+
74
+ | 事件 | 字段 |
75
+ | ----------------------- | ----------------------------------------------------------------------------------------------------- |
76
+ | `SessionStart` | `source: startup \| resume \| new \| fork` |
77
+ | `SessionEnd` | `reason: exit \| new \| switch` |
78
+ | `UserPromptSubmit` | `prompt` |
79
+ | `PreToolUse` | `toolCallId`、`toolName`、`toolInput`、`viaCodemode?`、`parentToolCallId?` |
80
+ | `PostToolUse` | 同上 + `toolResult: { content, isError }`(content 为文本) |
81
+ | `Stop` / `SubagentStop` | `lastAssistantText`、`stopHookActive`(本次运行已被 Stop Hook 续跑过;处理器应避免再 block 造成循环) |
82
+ | `PreCompact` | `tokensBefore`、`trigger: auto \| manual` |
83
+ | `Notification` | `notification: { kind: approval \| settled \| error \| retry, message }` |
84
+
85
+ **codemode**:脚本里经 `tools.*` 发起的每次调用都单独经过 PreToolUse / PostToolUse,matcher 按**真实工具名**匹配(`bash`,不是 `codemode`),输入多两个字段:`viaCodemode: true` 与 `parentToolCallId`(外层 `codemode` 调用的 id)。`codemode` 调用本身也作为一次工具调用经过两个事件。模型直接发起的调用不带这两个字段。
86
+
87
+ 环境变量(便于 shell 脚本):`AMA_HOOK_EVENT`、`AMA_SESSION_ID`、`AMA_CWD`,工具事件另有 `AMA_TOOL_NAME`,`read` / `write` / `edit` 另有 `AMA_FILE`(目标路径)。
88
+
89
+ ## 输出(退出码与 stdout)
90
+
91
+ | 退出码 | 含义 |
92
+ | --------------------- | ------------------------------------------------------------------------ |
93
+ | `0` | 放行;stdout 若是 JSON 对象则解析(空或非 JSON = 无决策) |
94
+ | `2` | 阻止:按上表「退出码 2」列处理,stderr 文本作为 reason;stdout 不再解析 |
95
+ | 其它非零 / 被信号杀死 | Hook 自身错误,**不阻塞**:记 warning(附 stderr 末 3 行),按无决策继续 |
96
+ | 超时 | 同非阻塞错误;**但 PreToolUse 超时按 deny**(fail-safe) |
97
+
98
+ stdout JSON:
99
+
100
+ ```ts
101
+ interface HookOutput {
102
+ decision?: "allow" | "deny" | "ask" | "block";
103
+ reason?: string;
104
+ updatedInput?: unknown; // PreToolUse
105
+ updatedPrompt?: string; // UserPromptSubmit
106
+ additionalContext?: string; // SessionStart / UserPromptSubmit / PostToolUse
107
+ customInstructions?: string; // PreCompact
108
+ continue?: false; // 任何事件:结束当前运行
109
+ suppressOutput?: true;
110
+ }
111
+ ```
112
+
113
+ 字段类型不对的丢弃并记 warning。stdout / stderr 各最多收集 1 MiB。
114
+
115
+ ## 合并与顺序
116
+
117
+ 同一事件下所有匹配的 Hook **并行**启动,全部结束后按配置顺序合并:
118
+
119
+ - 决策取最严:`deny > block > ask > allow`;reason 取决定性那条 Hook 的。
120
+ - `updatedInput` / `updatedPrompt` 只在**恰好一个** Hook 返回时采用;多个则全部忽略并 warning。
121
+ - `additionalContext` / `customInstructions` 按配置顺序拼接。
122
+ - 任一 Hook 返回 `continue: false` 即请求结束运行。
123
+
124
+ 一次工具调用的完整顺序([design.md](design.md) §6.3):
125
+
126
+ ```text
127
+ 模型产出工具调用
128
+ 1. schema 校验(失败 → 错误结果,不再往下)
129
+ 2. PreToolUse Hook(并行,合并为 allow / ask / deny / 无;updatedInput 替换输入)
130
+ 3. 权限管线:① deny 规则或 Hook deny → deny
131
+ ② 危险命令识别(bash)→ ask(无人值守时 deny)
132
+ ③ 权限模式决定 ask / allow
133
+ ④ allow 规则或 Hook allow 把 ③ 的 ask 变 allow(不能越过 ①②);Hook ask 把 allow 变 ask
134
+ 4. 结果为 ask → 审批链:宿主 broker → 界面对话框 / RPC 客户端 → 无人作答 deny;超时 10 分钟 deny
135
+ 5. 执行工具
136
+ 6. PostToolUse Hook(追加上下文 / 改为错误)→ 结果入转录
137
+ ```
138
+
139
+ Hook 在权限管线之前,是因为它是用户策略(可以改输入、可以否决);Hook 的 allow 只能免去模式带来的审批,不能放宽 deny 规则与危险命令识别。
140
+
141
+ ## matcher
142
+
143
+ 只对 `PreToolUse` / `PostToolUse` 生效,其它事件忽略 matcher。
144
+
145
+ | 写法 | 匹配 |
146
+ | ----------------- | ----------------------------------------------------------------------------------------------------- |
147
+ | 缺省、`""`、`*` | 全部工具 |
148
+ | `bash` | 精确匹配工具名 |
149
+ | `write\|edit` | 多选(括号外的 `\|` 分隔) |
150
+ | `canvas_*` | glob:`*` 任意字符串、`?` 单个字符 |
151
+ | `bash(git push*)` | 先匹配工具名,再对参数文本做 glob:bash 是 `command`,文件类工具是 `path`,其它工具是输入的 JSON 文本 |
152
+ | `/regex/flags` | 对工具名做正则 |
153
+
154
+ ## 运行环境
155
+
156
+ - POSIX:`/bin/sh -c <command>`,独立进程组;超时或运行被中断时向整组发 SIGTERM,1 秒后 SIGKILL。
157
+ - Windows:Git Bash(`AMA_HOOK_SHELL` 指定,或常见安装位置);找不到时 `cmd /d /s /c`。
158
+ - cwd 为会话 cwd;Hook 以 ama 进程的权限运行,继承环境变量。
159
+
160
+ ## 信任
161
+
162
+ - 用户级与 profile 的 Hook 总是加载。项目级 `.ama/hooks.json`(与 `.ama/skills/`、`.ama/prompts/`、祖先 `.agents/skills/`)在目录被**信任**之前不加载。
163
+ - 信任的粒度是目录(含子目录),记在 `~/.config/ama/trust.json`。决策顺序:`--trust` / `--no-trust` → `trust.json` 里最近祖先的记录 → 交互模式询问一次(可记住)→ 非交互模式缺省不信任。宿主 profile 可设 `trustProject: true`。
164
+ - 信任一个仓库 = 允许它的 Hook 以你的身份执行命令。信任不会放开权限:项目级 `config.json` 仍只能收紧规则。
165
+
166
+ ## 事件观察
167
+
168
+ 每条 Hook 结束后发 `hook_executed{event, command, exitCode, durationMs}`(RPC 事件与宿主事件都有),超时或被信号杀死时 `exitCode` 为 null。
169
+
170
+ ## 示例
171
+
172
+ 阻止推送到 main:
173
+
174
+ ```sh
175
+ #!/bin/sh
176
+ # .ama/guard.sh;hooks.json:{"matcher":"bash(git push*)","hooks":[{"type":"command","command":"./.ama/guard.sh"}]}
177
+ input=$(cat)
178
+ case "$input" in
179
+ *'main'*) echo "不要直接推送 main,请开分支" >&2; exit 2 ;;
180
+ esac
181
+ exit 0
182
+ ```
183
+
184
+ 编辑后跑格式检查,把结果交给模型:
185
+
186
+ ```json
187
+ {
188
+ "matcher": "edit|write",
189
+ "hooks": [
190
+ {
191
+ "type": "command",
192
+ "command": "prettier --check \"$AMA_FILE\" >/dev/null 2>&1 || echo '{\"additionalContext\":\"prettier 检查失败,请修正格式\"}'"
193
+ }
194
+ ]
195
+ }
196
+ ```
@@ -0,0 +1,161 @@
1
+ # 宿主适配器 API(@armadra/agent/host)
2
+
3
+ 宿主适配器是一个本地 JS 模块,ama 启动时加载它并交给它一个 `HostApi`:它可以注册工具、追加系统提示、观察事件、回答审批、注入用户消息、在界面上显示通知与状态。Armadra 画布就是以宿主适配器的形式接入的(画布工具 `canvas_*` / `context_*` 都由适配器注册)。类型定义在 `src/host/types.ts`,从 `@armadra/agent/host` 导出,`HOST_API_VERSION = 1`。设计依据见 [design.md](design.md) §6.2、§6.3、§11.1 第 13 步。
4
+
5
+ ## 模块形状
6
+
7
+ ```js
8
+ // my-host.mjs
9
+ export const hostApi = 1;
10
+ export function create(api) {
11
+ if (!api.env.MY_HOST_ENABLED) return undefined; // 不激活:ama 退化为普通独立模式
12
+ api.tools.register({
13
+ name: "my_lookup",
14
+ description: "Look up a ticket by id.",
15
+ parameters: { type: "object", properties: { id: { type: "string" } }, required: ["id"] },
16
+ permission: "read",
17
+ async execute(input) {
18
+ return { content: `ticket ${input.id}: …` };
19
+ },
20
+ });
21
+ api.instructions.add({
22
+ kind: "text",
23
+ name: "my-host",
24
+ text: "Tickets live in the tracker; use my_lookup.",
25
+ });
26
+ api.events.on("agent_settled", () => api.ui.setStatus("my-host", "idle"));
27
+ return { id: "my-host", dispose() {} };
28
+ }
29
+ ```
30
+
31
+ - 导出 `hostApi`(必须等于 `HOST_API_VERSION`)与 `create(api)`;也可以放在默认导出(ESM `export default { hostApi, create }` 或 CJS `module.exports = { hostApi, create }`)。
32
+ - `create` 返回 `HostAdapter`(`{ id: string, dispose?() }`,`id` 非空)激活;返回 `undefined` 表示本次不激活。可以是 async。
33
+ - `dispose()` 在退出时调用(`session_shutdown` 事件之后),幂等。
34
+
35
+ ## 加载
36
+
37
+ - 来源:`--host <模块>` 或 profile 的 `host`(命令行优先);相对路径按 cwd 解析。
38
+ - `.mjs` 用动态 `import()`;`.cjs` 用 `require`;`.js` 先 `require`,遇到 ESM(`ERR_REQUIRE_ESM` 等)再 `import()`。单文件发行版 `ama.cjs` 里同样能加载 ESM 适配器。
39
+ - 时机:启动序列第 13 步——配置、资源、模型与工具注册表就绪之后,组装会话之前。`create()` 里注册的工具与指令进入首个请求的系统提示与工具表,前缀从第一个请求起就稳定。
40
+ - 失败:
41
+
42
+ | 情形 | 退出码 |
43
+ | --------------------------------------------- | ------ |
44
+ | 文件不存在、加载抛错、缺 `hostApi` / `create` | 6 |
45
+ | `hostApi` 不等于 `HOST_API_VERSION` | 78 |
46
+ | `create()` 抛错或 10 秒内未返回 | 6 |
47
+ | 返回的适配器缺 `id` | 6 |
48
+
49
+ ## HostApi
50
+
51
+ | 成员 | 说明 |
52
+ | ----------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
53
+ | `version` | `HOST_API_VERSION` |
54
+ | `agent` | `{ name: "ama", version }` |
55
+ | `env` | 启动时环境变量的冻结副本 |
56
+ | `mode` | `interactive` / `line` / `print` / `rpc` |
57
+ | `session.id()` / `file()` / `cwd()` / `model()` | 当前会话(换会话后跟随新会话);`file()` 在首次请求落盘前为 `undefined` |
58
+ | `tools.register(tool)` | 注册工具(形状见下);名字须匹配 `^[a-z][a-z0-9_]{1,63}$`,同名已存在抛 `tool_exists`。建议加前缀(`canvas_*`) |
59
+ | `tools.disable(name)` | 隐藏内置工具(如 Armadra 禁用 `task`),系统提示的工具节随之不再列它 |
60
+ | `tools.list()` | 当前全部工具名 |
61
+ | `instructions.add(source)` | 追加到系统提示最后的 `host` 节;`{ kind: "file", path }` 或 `{ kind: "text", text, name? }` |
62
+ | `events.on(name, handler)` | 观察事件(下表),返回注销函数 |
63
+ | `approvals.setBroker(broker)` | 设置审批回答者(见「审批」) |
64
+ | `messages.sendUser(text, origin?)` | 以 user 消息注入:空闲时开始一次运行(`"started"`),运行中按 steer 入队(`"queued"`);`origin` 缺省 `"host"`,落盘在消息上,界面标 `↳ host` |
65
+ | `ui.notify(message, level?)` | 交互 / line 模式进消息区;rpc 模式变成 `notification` 事件(stderr 另有一份);print 模式写 stderr |
66
+ | `ui.setStatus(key, text?)` | 状态栏的宿主项;`text` 为空或缺省则移除该键 |
67
+ | `log(level, message, detail?)` | 日志;`warn` / `error` 写 stderr |
68
+ | `cache?.onWarmingDecision(handler)` | 缓存保温的否决钩子(见「缓存保温」);可选面,旧版本运行时没有它,用前判断 `api.cache !== undefined` |
69
+
70
+ `create()` 期间会话还没组装完:`session.*` 返回启动时确定的值,`sendUser` 会以 `busy` 拒绝——要在启动时发消息,等 `session_start` 事件之后再调用。
71
+
72
+ ### 工具定义
73
+
74
+ ```ts
75
+ interface ToolDefinition<I = unknown> {
76
+ name: string;
77
+ label?: string; // TUI 标题
78
+ description: string;
79
+ parameters: JsonSchema;
80
+ permission: "read" | "write" | "execute"; // 权限管线的分类
81
+ executionMode?: "sequential" | "parallel"; // 缺省 read 并行、其余串行
82
+ annotations?: { readOnly?: boolean; destructive?: boolean; openWorld?: boolean };
83
+ promptSnippet?: string; // 系统提示 tools 节一行
84
+ promptGuidelines?: string[]; // 系统提示 rules 节
85
+ execute(input: I, ctx: ToolContext): Promise<ToolResult>;
86
+ renderCall?(input: I, width: number): string[];
87
+ renderResult?(result: ToolResult, width: number, expanded: boolean): string[];
88
+ }
89
+ interface ToolResult {
90
+ content: string | ContentBlock[];
91
+ isError?: boolean;
92
+ details?: unknown; // 落盘,不进上下文
93
+ structured?: unknown; // codemode 脚本里 tools.<name>() 的返回值
94
+ terminate?: boolean; // 整批结果都为 true 才提前结束本次运行
95
+ }
96
+ ```
97
+
98
+ `ToolContext` 提供 `toolCallId`、`cwd`、`sessionId`、`sessionFile?`、`signal`、`depth`、`model?`、`thinkingLevel?`、`outputDir?`、`onUpdate(partial)`(运行中输出)、`readFiles` / `markRead`、`tools.executeTool(name, input)`(嵌套调用,受同一管线)、`session.appendCustom` / `lastCustom`(不进上下文的 custom 条目,见 [session-format.md](session-format.md))、`spawnSubagent?`、`log`。
99
+
100
+ 宿主工具与内置工具走同一条路径:schema 校验 → 命令式 Hook PreToolUse → 权限管线(按 `permission` 分类)→ 审批 → 执行 → PostToolUse。在 codemode 脚本里也能以 `tools.<name>()` 调用。
101
+
102
+ ## 事件
103
+
104
+ `events.on` 的处理器只观察:抛错只记日志,不影响运行;处理器依次调用并等待,`session_shutdown` 被 await(退出前可以做清理)。
105
+
106
+ | 事件 | 载荷 | 来源 |
107
+ | ----------------------------------------------------------------- | ------------------------------------------------------------------------------ | ------------------------------------------- |
108
+ | `session_start` | `sessionId`、`sessionFile?`、`cwd`、`reason: startup \| resume \| new \| fork` | 启动与换会话 |
109
+ | `before_agent_start` | `prompt` | 用户提示展开后、运行开始前 |
110
+ | `agent_start` / `turn_start` / `turn_end` / `agent_before_settle` | `{}` | 运行与回合 |
111
+ | `agent_end` | `stopReason`、`willRetry` | |
112
+ | `agent_settled` | `warning?` | 运行彻底结束 |
113
+ | `tool_call` | `toolCallId`、`toolName`、`input` | 工具开始执行(已通过权限) |
114
+ | `tool_result` | `toolCallId`、`toolName`、`isError` | 工具执行结束 |
115
+ | `tool_approval_requested` | `requestId`、`toolName` | 需要审批 |
116
+ | `tool_approval_resolved` | `requestId`、`decision` | 审批结论 |
117
+ | `session_compact` | `tokensBefore` | 压缩成功 |
118
+ | `model_select` | `model: { provider, id }` | 切换模型 |
119
+ | `hook_executed` | `event`、`command`、`exitCode`、`durationMs` | 每条命令式 Hook 结束 |
120
+ | `cache_miss` | `missedTokens`、`missedCost?`、`reason`、`detail?`、`idleMs` | 一次缓存未命中(含低于界面门槛的) |
121
+ | `context_pressure` | `percent`、`threshold: 70 \| 90`、`remainingTokens?`、`estimatedTurnsLeft?` | 上下文占用跨过 70% / 90% |
122
+ | `session_shutdown` | `{}` | 退出前(之后跑 SessionEnd Hook、`dispose`) |
123
+
124
+ 需要逐 token 的流式内容或完整事件流时用 RPC 或 SDK 的 `subscribe`,宿主事件是精简过的。
125
+
126
+ ## 审批
127
+
128
+ `approvals.setBroker({ ask(request, signal) })`:工具调用需要确认时,审批链依次问**宿主 broker → UI(TUI 对话框 / RPC 客户端 / SDK 回调)→ 无人作答 deny**。
129
+
130
+ - `ask` 返回 `"allow"` / `"deny"` / `"allow_session"` 作答;返回 `undefined` 交给下一个回答者;抛错按 deny。
131
+ - `request`:`requestId`、`toolName`、`input`、`reason: "mode" | "dangerous" | "hook"`、`hookReason?`、`preview?`(执行前预览,见 [rpc.md](rpc.md)「审批」)、`context?`(`depth > 0` 表示来自 `task` 子 Agent;codemode 内层调用带 `parentToolCallId`)。
132
+ - 超时(缺省 10 分钟,`AMA_APPROVAL_TIMEOUT_MS`)或运行被中断时 `signal` abort,结论为 deny。审批串行,同一时刻只有一个请求在等。
133
+ - 时机:broker 每次审批时现取,可以在 `create()` 里设,也可以之后任何时候设或替换;最后一次 `setBroker` 生效。
134
+ - 宿主 broker 只决定「谁来回答 ask」,不能放宽 deny 规则、命令式 Hook 的 deny 与危险命令识别([design.md](design.md) §6.3)。
135
+
136
+ ## 缓存保温
137
+
138
+ `api.cache.onWarmingDecision(handler)` 在每次缓存保温请求前以内置决策调用 `handler(decision)`:
139
+
140
+ ```ts
141
+ interface WarmDecision {
142
+ action: "warm" | "stop"; // 内置决策
143
+ phase: "streaming" | "idle";
144
+ promptTokens: number; // 上一次真实请求的 input + cacheRead + cacheWrite
145
+ warmCost: number | undefined; // 一次保温的花费(美元)
146
+ missCost: number | undefined; // 不保温而失效时多付的金额
147
+ probability: number; // 失效后仍会再发请求的概率:streaming 1、idle 0.15
148
+ reason?: string; // stop 的原因
149
+ }
150
+ ```
151
+
152
+ 返回 `"warm"` / `"stop"`(可以是 Promise)。返回 `"stop"` 即不发并停止本轮保温(内置决策本是 warm 时,停止原因记为 `declined`);返回 `"warm"` 可以覆盖内置的 stop。处理器出错回落内置决策。注册多个时最后注册且未注销的那个生效;返回值是注销函数。保温机制本身见 [providers.md](providers.md)「缓存」。
153
+
154
+ ## 退出
155
+
156
+ - 进程退出:`session_shutdown` 事件(await)→ SessionEnd Hook(`reason: "exit"`)→ `adapter.dispose()` → 会话 dispose。`dispose` 抛错只记 warning。
157
+ - `/new`、`/resume`、`/fork` 与 RPC 换会话:适配器保持激活,不发 `session_shutdown`;顺序是 SessionEnd Hook(`new` / `switch`)→ 旧会话 dispose → 新会话的 `session_start` → SessionStart Hook。`api.session.*` 随之指向新会话。
158
+
159
+ ## 嵌入 Armadra
160
+
161
+ Armadra 用 profile 启动 ama:`ama --profile <path>`,profile 的 `host` 指向它的适配器(`ama-armadra.cjs`),另带 instructions、skillDirs、hooksFile、authFile、sessionDir、`trustProject`。适配器在 `ARMADRA_NODE_ID` 缺失时返回 `undefined`,同一个 profile 在画布外退化为普通 ama。契约细节见 Armadra 仓库 [docs/design/coordinator-agent.md](https://github.com/yovinchen/Armadra/blob/main/docs/design/coordinator-agent.md)。