@armadra/agent 0.0.0-stage → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (433) hide show
  1. package/CHANGELOG.md +37 -0
  2. package/LICENSE +21 -0
  3. package/README.md +470 -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 +514 -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 +119 -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 +111 -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 +485 -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 +304 -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 +103 -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/channels.d.ts +51 -0
  101. package/dist/ai/providers/channels.js +96 -0
  102. package/dist/ai/providers/enrich.d.ts +34 -0
  103. package/dist/ai/providers/enrich.js +86 -0
  104. package/dist/ai/providers/models-dev-cache.d.ts +53 -0
  105. package/dist/ai/providers/models-dev-cache.js +147 -0
  106. package/dist/ai/providers/models-dev.d.ts +99 -0
  107. package/dist/ai/providers/models-dev.js +315 -0
  108. package/dist/ai/providers/registry.d.ts +114 -0
  109. package/dist/ai/providers/registry.js +458 -0
  110. package/dist/ai/sse.d.ts +32 -0
  111. package/dist/ai/sse.js +140 -0
  112. package/dist/ai/thinking.d.ts +42 -0
  113. package/dist/ai/thinking.js +101 -0
  114. package/dist/ai/types.d.ts +448 -0
  115. package/dist/ai/types.js +19 -0
  116. package/dist/bundle/ama-sandbox.cjs +324 -0
  117. package/dist/bundle/ama.cjs +27837 -0
  118. package/dist/bundle.d.ts +9 -0
  119. package/dist/bundle.js +15 -0
  120. package/dist/cli/args.d.ts +85 -0
  121. package/dist/cli/args.js +408 -0
  122. package/dist/cli/bootstrap.d.ts +18 -0
  123. package/dist/cli/bootstrap.js +399 -0
  124. package/dist/cli/compose-providers.d.ts +37 -0
  125. package/dist/cli/compose-providers.js +107 -0
  126. package/dist/cli/compose-session.d.ts +72 -0
  127. package/dist/cli/compose-session.js +370 -0
  128. package/dist/cli/compose-store.d.ts +24 -0
  129. package/dist/cli/compose-store.js +125 -0
  130. package/dist/cli/compose.d.ts +108 -0
  131. package/dist/cli/compose.js +221 -0
  132. package/dist/cli/default-model.d.ts +16 -0
  133. package/dist/cli/default-model.js +24 -0
  134. package/dist/cli/deps.d.ts +207 -0
  135. package/dist/cli/deps.js +12 -0
  136. package/dist/cli/exit-codes.d.ts +29 -0
  137. package/dist/cli/exit-codes.js +40 -0
  138. package/dist/cli/main.d.ts +27 -0
  139. package/dist/cli/main.js +177 -0
  140. package/dist/cli/runtime.d.ts +90 -0
  141. package/dist/cli/runtime.js +8 -0
  142. package/dist/cli/startup-screen.d.ts +15 -0
  143. package/dist/cli/startup-screen.js +56 -0
  144. package/dist/cli/startup-steps.d.ts +35 -0
  145. package/dist/cli/startup-steps.js +202 -0
  146. package/dist/cli/subcommands/auth.d.ts +12 -0
  147. package/dist/cli/subcommands/auth.js +91 -0
  148. package/dist/cli/subcommands/config.d.ts +53 -0
  149. package/dist/cli/subcommands/config.js +277 -0
  150. package/dist/cli/subcommands/context.d.ts +21 -0
  151. package/dist/cli/subcommands/context.js +42 -0
  152. package/dist/cli/subcommands/doctor.d.ts +11 -0
  153. package/dist/cli/subcommands/doctor.js +246 -0
  154. package/dist/cli/subcommands/init.d.ts +6 -0
  155. package/dist/cli/subcommands/init.js +22 -0
  156. package/dist/cli/subcommands/model-meta.d.ts +16 -0
  157. package/dist/cli/subcommands/model-meta.js +54 -0
  158. package/dist/cli/subcommands/models-cache-probe.d.ts +34 -0
  159. package/dist/cli/subcommands/models-cache-probe.js +190 -0
  160. package/dist/cli/subcommands/models-discover.d.ts +46 -0
  161. package/dist/cli/subcommands/models-discover.js +232 -0
  162. package/dist/cli/subcommands/models.d.ts +40 -0
  163. package/dist/cli/subcommands/models.js +152 -0
  164. package/dist/cli/subcommands/providers-list.d.ts +8 -0
  165. package/dist/cli/subcommands/providers-list.js +97 -0
  166. package/dist/cli/subcommands/providers-plan.d.ts +79 -0
  167. package/dist/cli/subcommands/providers-plan.js +215 -0
  168. package/dist/cli/subcommands/providers.d.ts +27 -0
  169. package/dist/cli/subcommands/providers.js +433 -0
  170. package/dist/cli/subcommands/sessions.d.ts +11 -0
  171. package/dist/cli/subcommands/sessions.js +100 -0
  172. package/dist/codemode/capability.d.ts +37 -0
  173. package/dist/codemode/capability.js +55 -0
  174. package/dist/codemode/declarations.d.ts +44 -0
  175. package/dist/codemode/declarations.js +111 -0
  176. package/dist/codemode/host-side.d.ts +59 -0
  177. package/dist/codemode/host-side.js +253 -0
  178. package/dist/codemode/modes.d.ts +23 -0
  179. package/dist/codemode/modes.js +40 -0
  180. package/dist/codemode/protocol.d.ts +91 -0
  181. package/dist/codemode/protocol.js +114 -0
  182. package/dist/codemode/sandbox-entry.d.ts +25 -0
  183. package/dist/codemode/sandbox-entry.js +323 -0
  184. package/dist/codemode/store.d.ts +26 -0
  185. package/dist/codemode/store.js +53 -0
  186. package/dist/codemode/tool.d.ts +105 -0
  187. package/dist/codemode/tool.js +283 -0
  188. package/dist/compaction/branch-summary.d.ts +30 -0
  189. package/dist/compaction/branch-summary.js +79 -0
  190. package/dist/compaction/breaker.d.ts +32 -0
  191. package/dist/compaction/breaker.js +65 -0
  192. package/dist/compaction/cut-point.d.ts +23 -0
  193. package/dist/compaction/cut-point.js +70 -0
  194. package/dist/compaction/estimate.d.ts +30 -0
  195. package/dist/compaction/estimate.js +114 -0
  196. package/dist/compaction/prune-tier.d.ts +31 -0
  197. package/dist/compaction/prune-tier.js +83 -0
  198. package/dist/compaction/serialize.d.ts +20 -0
  199. package/dist/compaction/serialize.js +115 -0
  200. package/dist/compaction/summarize-tier.d.ts +111 -0
  201. package/dist/compaction/summarize-tier.js +305 -0
  202. package/dist/config/auth-file.d.ts +39 -0
  203. package/dist/config/auth-file.js +92 -0
  204. package/dist/config/context-files.d.ts +30 -0
  205. package/dist/config/context-files.js +77 -0
  206. package/dist/config/init.d.ts +30 -0
  207. package/dist/config/init.js +92 -0
  208. package/dist/config/json-schema.d.ts +14 -0
  209. package/dist/config/json-schema.js +182 -0
  210. package/dist/config/load.d.ts +45 -0
  211. package/dist/config/load.js +97 -0
  212. package/dist/config/merge.d.ts +73 -0
  213. package/dist/config/merge.js +248 -0
  214. package/dist/config/paths.d.ts +38 -0
  215. package/dist/config/paths.js +108 -0
  216. package/dist/config/profile.d.ts +27 -0
  217. package/dist/config/profile.js +65 -0
  218. package/dist/config/schema.d.ts +34 -0
  219. package/dist/config/schema.js +476 -0
  220. package/dist/config/trust.d.ts +42 -0
  221. package/dist/config/trust.js +122 -0
  222. package/dist/config/types.d.ts +190 -0
  223. package/dist/config/types.js +29 -0
  224. package/dist/config/write.d.ts +10 -0
  225. package/dist/config/write.js +25 -0
  226. package/dist/errors.d.ts +28 -0
  227. package/dist/errors.js +30 -0
  228. package/dist/hooks/config.d.ts +49 -0
  229. package/dist/hooks/config.js +102 -0
  230. package/dist/hooks/dispatcher.d.ts +41 -0
  231. package/dist/hooks/dispatcher.js +104 -0
  232. package/dist/hooks/matcher.d.ts +22 -0
  233. package/dist/hooks/matcher.js +108 -0
  234. package/dist/hooks/protocol.d.ts +33 -0
  235. package/dist/hooks/protocol.js +240 -0
  236. package/dist/hooks/runner.d.ts +30 -0
  237. package/dist/hooks/runner.js +143 -0
  238. package/dist/hooks/types.d.ts +147 -0
  239. package/dist/hooks/types.js +20 -0
  240. package/dist/host/api-impl.d.ts +75 -0
  241. package/dist/host/api-impl.js +173 -0
  242. package/dist/host/loader.d.ts +31 -0
  243. package/dist/host/loader.js +147 -0
  244. package/dist/host/types.d.ts +169 -0
  245. package/dist/host/types.js +14 -0
  246. package/dist/host.d.ts +5 -0
  247. package/dist/host.js +4 -0
  248. package/dist/index.d.ts +41 -0
  249. package/dist/index.js +28 -0
  250. package/dist/modes/commands-core.d.ts +44 -0
  251. package/dist/modes/commands-core.js +171 -0
  252. package/dist/modes/image-input.d.ts +27 -0
  253. package/dist/modes/image-input.js +78 -0
  254. package/dist/modes/interactive/approval-dialog.d.ts +48 -0
  255. package/dist/modes/interactive/approval-dialog.js +202 -0
  256. package/dist/modes/interactive/commands.d.ts +41 -0
  257. package/dist/modes/interactive/commands.js +201 -0
  258. package/dist/modes/interactive/completion.d.ts +53 -0
  259. package/dist/modes/interactive/completion.js +157 -0
  260. package/dist/modes/interactive/interactive-mode.d.ts +46 -0
  261. package/dist/modes/interactive/interactive-mode.js +491 -0
  262. package/dist/modes/interactive/key-dispatch.d.ts +29 -0
  263. package/dist/modes/interactive/key-dispatch.js +107 -0
  264. package/dist/modes/interactive/line/line-editor.d.ts +50 -0
  265. package/dist/modes/interactive/line/line-editor.js +232 -0
  266. package/dist/modes/interactive/line/line-mode.d.ts +20 -0
  267. package/dist/modes/interactive/line/line-mode.js +218 -0
  268. package/dist/modes/interactive/line/line-render.d.ts +35 -0
  269. package/dist/modes/interactive/line/line-render.js +171 -0
  270. package/dist/modes/interactive/line/paste-state.d.ts +26 -0
  271. package/dist/modes/interactive/line/paste-state.js +72 -0
  272. package/dist/modes/interactive/message-view.d.ts +77 -0
  273. package/dist/modes/interactive/message-view.js +269 -0
  274. package/dist/modes/interactive/pickers.d.ts +42 -0
  275. package/dist/modes/interactive/pickers.js +115 -0
  276. package/dist/modes/interactive/startup-ui.d.ts +33 -0
  277. package/dist/modes/interactive/startup-ui.js +268 -0
  278. package/dist/modes/interactive/status-bar.d.ts +48 -0
  279. package/dist/modes/interactive/status-bar.js +139 -0
  280. package/dist/modes/interactive/tool-view.d.ts +95 -0
  281. package/dist/modes/interactive/tool-view.js +344 -0
  282. package/dist/modes/print/json-event.d.ts +15 -0
  283. package/dist/modes/print/json-event.js +39 -0
  284. package/dist/modes/print/print-mode.d.ts +17 -0
  285. package/dist/modes/print/print-mode.js +107 -0
  286. package/dist/modes/rpc/commands.d.ts +40 -0
  287. package/dist/modes/rpc/commands.js +263 -0
  288. package/dist/modes/rpc/jsonl.d.ts +16 -0
  289. package/dist/modes/rpc/jsonl.js +55 -0
  290. package/dist/modes/rpc/rpc-mode.d.ts +22 -0
  291. package/dist/modes/rpc/rpc-mode.js +153 -0
  292. package/dist/modes/session-report.d.ts +55 -0
  293. package/dist/modes/session-report.js +278 -0
  294. package/dist/modes/shared.d.ts +13 -0
  295. package/dist/modes/shared.js +52 -0
  296. package/dist/modes/startup-ui-text.d.ts +16 -0
  297. package/dist/modes/startup-ui-text.js +103 -0
  298. package/dist/permissions/broker.d.ts +47 -0
  299. package/dist/permissions/broker.js +107 -0
  300. package/dist/permissions/dangerous.d.ts +47 -0
  301. package/dist/permissions/dangerous.js +370 -0
  302. package/dist/permissions/pipeline.d.ts +51 -0
  303. package/dist/permissions/pipeline.js +181 -0
  304. package/dist/permissions/preview.d.ts +43 -0
  305. package/dist/permissions/preview.js +463 -0
  306. package/dist/permissions/rules.d.ts +58 -0
  307. package/dist/permissions/rules.js +249 -0
  308. package/dist/permissions/types.d.ts +100 -0
  309. package/dist/permissions/types.js +18 -0
  310. package/dist/rpc.d.ts +173 -0
  311. package/dist/rpc.js +13 -0
  312. package/dist/sdk.d.ts +98 -0
  313. package/dist/sdk.js +195 -0
  314. package/dist/session/manager.d.ts +70 -0
  315. package/dist/session/manager.js +278 -0
  316. package/dist/session/migrate.d.ts +19 -0
  317. package/dist/session/migrate.js +53 -0
  318. package/dist/session/projection.d.ts +50 -0
  319. package/dist/session/projection.js +184 -0
  320. package/dist/session/store.d.ts +47 -0
  321. package/dist/session/store.js +210 -0
  322. package/dist/session/tree.d.ts +21 -0
  323. package/dist/session/tree.js +88 -0
  324. package/dist/session/types.d.ts +201 -0
  325. package/dist/session/types.js +18 -0
  326. package/dist/skills/discover.d.ts +60 -0
  327. package/dist/skills/discover.js +160 -0
  328. package/dist/skills/expand.d.ts +35 -0
  329. package/dist/skills/expand.js +46 -0
  330. package/dist/skills/frontmatter.d.ts +27 -0
  331. package/dist/skills/frontmatter.js +157 -0
  332. package/dist/skills/index-prompt.d.ts +13 -0
  333. package/dist/skills/index-prompt.js +42 -0
  334. package/dist/skills/templates.d.ts +52 -0
  335. package/dist/skills/templates.js +177 -0
  336. package/dist/tools/bash.d.ts +49 -0
  337. package/dist/tools/bash.js +222 -0
  338. package/dist/tools/edit-fuzzy.d.ts +36 -0
  339. package/dist/tools/edit-fuzzy.js +129 -0
  340. package/dist/tools/edit.d.ts +38 -0
  341. package/dist/tools/edit.js +241 -0
  342. package/dist/tools/file-mutex.d.ts +8 -0
  343. package/dist/tools/file-mutex.js +29 -0
  344. package/dist/tools/glob.d.ts +44 -0
  345. package/dist/tools/glob.js +217 -0
  346. package/dist/tools/grep.d.ts +39 -0
  347. package/dist/tools/grep.js +179 -0
  348. package/dist/tools/ignore.d.ts +40 -0
  349. package/dist/tools/ignore.js +174 -0
  350. package/dist/tools/image-file.d.ts +31 -0
  351. package/dist/tools/image-file.js +114 -0
  352. package/dist/tools/ls.d.ts +21 -0
  353. package/dist/tools/ls.js +96 -0
  354. package/dist/tools/output-accumulator.d.ts +48 -0
  355. package/dist/tools/output-accumulator.js +106 -0
  356. package/dist/tools/paths.d.ts +20 -0
  357. package/dist/tools/paths.js +58 -0
  358. package/dist/tools/presets.d.ts +71 -0
  359. package/dist/tools/presets.js +128 -0
  360. package/dist/tools/process-tree.d.ts +35 -0
  361. package/dist/tools/process-tree.js +125 -0
  362. package/dist/tools/read.d.ts +24 -0
  363. package/dist/tools/read.js +132 -0
  364. package/dist/tools/registry.d.ts +43 -0
  365. package/dist/tools/registry.js +106 -0
  366. package/dist/tools/shell.d.ts +38 -0
  367. package/dist/tools/shell.js +91 -0
  368. package/dist/tools/task.d.ts +29 -0
  369. package/dist/tools/task.js +107 -0
  370. package/dist/tools/todo.d.ts +28 -0
  371. package/dist/tools/todo.js +107 -0
  372. package/dist/tools/truncate.d.ts +44 -0
  373. package/dist/tools/truncate.js +175 -0
  374. package/dist/tools/types.d.ts +135 -0
  375. package/dist/tools/types.js +19 -0
  376. package/dist/tools/write.d.ts +20 -0
  377. package/dist/tools/write.js +84 -0
  378. package/dist/tui/ansi.d.ts +29 -0
  379. package/dist/tui/ansi.js +420 -0
  380. package/dist/tui/component.d.ts +38 -0
  381. package/dist/tui/component.js +13 -0
  382. package/dist/tui/components/box.d.ts +26 -0
  383. package/dist/tui/components/box.js +65 -0
  384. package/dist/tui/components/container.d.ts +14 -0
  385. package/dist/tui/components/container.js +39 -0
  386. package/dist/tui/components/editor-buffer.d.ts +67 -0
  387. package/dist/tui/components/editor-buffer.js +300 -0
  388. package/dist/tui/components/editor-paste.d.ts +29 -0
  389. package/dist/tui/components/editor-paste.js +64 -0
  390. package/dist/tui/components/editor.d.ts +114 -0
  391. package/dist/tui/components/editor.js +530 -0
  392. package/dist/tui/components/key-value.d.ts +29 -0
  393. package/dist/tui/components/key-value.js +48 -0
  394. package/dist/tui/components/loader.d.ts +35 -0
  395. package/dist/tui/components/loader.js +71 -0
  396. package/dist/tui/components/markdown.d.ts +90 -0
  397. package/dist/tui/components/markdown.js +462 -0
  398. package/dist/tui/components/meter.d.ts +29 -0
  399. package/dist/tui/components/meter.js +47 -0
  400. package/dist/tui/components/overlay.d.ts +24 -0
  401. package/dist/tui/components/overlay.js +52 -0
  402. package/dist/tui/components/select-list.d.ts +57 -0
  403. package/dist/tui/components/select-list.js +179 -0
  404. package/dist/tui/components/spacer.d.ts +11 -0
  405. package/dist/tui/components/spacer.js +16 -0
  406. package/dist/tui/components/text.d.ts +30 -0
  407. package/dist/tui/components/text.js +65 -0
  408. package/dist/tui/keybindings.d.ts +66 -0
  409. package/dist/tui/keybindings.js +120 -0
  410. package/dist/tui/keys.d.ts +38 -0
  411. package/dist/tui/keys.js +275 -0
  412. package/dist/tui/stdin-buffer.d.ts +41 -0
  413. package/dist/tui/stdin-buffer.js +206 -0
  414. package/dist/tui/terminal.d.ts +79 -0
  415. package/dist/tui/terminal.js +153 -0
  416. package/dist/tui/theme.d.ts +31 -0
  417. package/dist/tui/theme.js +199 -0
  418. package/dist/tui/tui.d.ts +103 -0
  419. package/dist/tui/tui.js +363 -0
  420. package/dist/tui/vt-screen.d.ts +46 -0
  421. package/dist/tui/vt-screen.js +251 -0
  422. package/dist/tui.d.ts +30 -0
  423. package/dist/tui.js +31 -0
  424. package/dist/version.d.ts +8 -0
  425. package/dist/version.js +24 -0
  426. package/docs/codemode.md +102 -0
  427. package/docs/hooks.md +196 -0
  428. package/docs/host-api.md +161 -0
  429. package/docs/providers.md +531 -0
  430. package/docs/rpc.md +253 -0
  431. package/docs/session-format.md +119 -0
  432. package/docs/tui.md +170 -0
  433. package/package.json +101 -4
@@ -0,0 +1,71 @@
1
+ /**
2
+ * 工具预设(设计 §5.6):模型直接看到哪些内置工具。
3
+ *
4
+ * | 预设 | 模型直接看到 |
5
+ * | ------------- | ----------------------------------------- |
6
+ * | `default` | read、edit、write、bash、grep、glob |
7
+ * | `minimal` | read、edit、write、bash |
8
+ * | `codemode` | 只有 codemode(其余工具在脚本里调用) |
9
+ * | `coordinator` | read + 宿主注册的工具 |
10
+ *
11
+ * - 预设只管**内置**工具;宿主 / SDK 注册的工具(`canvas_*` 等)总在活动集里,除非用户
12
+ * `--tools a,b,c` 整组替换(之后只用列出的名字)。
13
+ * - `tools.default`:`+name` / `-name` 在预设上增减;不带前缀的名字整组替换预设的内置工具,
14
+ * 之后再应用带前缀的项。未注册的名字记 warning 并忽略。
15
+ * - codemode 开关跟随预设:`codemode` 预设 → `only`,其余 → `off`;`codemode.mode` 显式配置覆盖。
16
+ * - codemode 工具由 B10 经组装根的 `toolFactories` 注册(`codemode.mode` 为 off 时不注册);不可用
17
+ * (例如 `codemode.requireStrict` 而运行时 Node 不隔离网络)时 codemode 预设**回退到 default 并
18
+ * warning**(不报错:零配置用户不应因此起不来),`on` 同样忽略。
19
+ * - `only` 模式活动集独占:宿主 / SDK 工具也不直接暴露,只能在脚本里调用(`exclusive`)。
20
+ */
21
+ import type { AmaConfig, CodemodeMode, ToolsPreset } from "../config/types.js";
22
+ import { ToolRegistry } from "./registry.js";
23
+ import type { ToolDefinition, ToolSource } from "./types.js";
24
+ export declare const CODEMODE_TOOL = "codemode";
25
+ /** 各预设下模型直接看到的内置工具(codemode 预设见 `resolvePreset`)。 */
26
+ export declare const PRESET_TOOLS: Readonly<Record<ToolsPreset, readonly string[]>>;
27
+ /** 生效的 codemode 模式:显式配置优先,否则跟随预设。 */
28
+ export declare function effectiveCodemodeMode(config: Pick<AmaConfig, "tools" | "codemode">): CodemodeMode;
29
+ /**
30
+ * `tools.default` 微调:不带前缀的名字整组替换 `base`,再依次应用 `+name` / `-name`。
31
+ * 返回去重后的名字(保持首次出现顺序)。
32
+ */
33
+ export declare function applyToolAdjustments(base: readonly string[], adjustments: readonly string[] | undefined): string[];
34
+ export interface PresetResolution {
35
+ /** 生效的预设(codemode 工具缺失时回退为 default)。 */
36
+ preset: ToolsPreset;
37
+ codemode: CodemodeMode;
38
+ /** 活动的内置工具名(按名排序)。 */
39
+ builtin: string[];
40
+ warnings: string[];
41
+ }
42
+ export declare function resolvePreset(input: {
43
+ config: Pick<AmaConfig, "tools" | "codemode">;
44
+ /** 该名字是否已注册(且未禁用)。 */
45
+ available(name: string): boolean;
46
+ }): PresetResolution;
47
+ type RegisterListener = (tool: ToolDefinition, source: ToolSource) => void;
48
+ /**
49
+ * 带预设的注册表:活动集 = 预设里的内置工具 + 全部非内置工具;`setActive()`(`--tools`)之后
50
+ * 退回整组替换语义。`onRegister` 让组装根把会话创建之后才注册的宿主工具追加进会话。
51
+ */
52
+ export declare class PresetToolRegistry extends ToolRegistry {
53
+ private presetNames;
54
+ private exclusive;
55
+ private explicit;
56
+ private readonly listeners;
57
+ /**
58
+ * 设预设的内置工具;undefined = 全部内置工具。`exclusive`(codemode only):活动集只有这些名字,
59
+ * 宿主 / SDK 工具也不进活动集。
60
+ */
61
+ setPresetTools(names: readonly string[] | undefined, options?: {
62
+ exclusive?: boolean;
63
+ }): void;
64
+ /** 是否被 `setActive` 整组替换过。 */
65
+ get hasExplicitActive(): boolean;
66
+ setActive(names: readonly string[]): void;
67
+ active(): readonly ToolDefinition[];
68
+ register(tool: ToolDefinition, source: ToolSource): void;
69
+ onRegister(listener: RegisterListener): () => void;
70
+ }
71
+ export {};
@@ -0,0 +1,128 @@
1
+ /**
2
+ * 工具预设(设计 §5.6):模型直接看到哪些内置工具。
3
+ *
4
+ * | 预设 | 模型直接看到 |
5
+ * | ------------- | ----------------------------------------- |
6
+ * | `default` | read、edit、write、bash、grep、glob |
7
+ * | `minimal` | read、edit、write、bash |
8
+ * | `codemode` | 只有 codemode(其余工具在脚本里调用) |
9
+ * | `coordinator` | read + 宿主注册的工具 |
10
+ *
11
+ * - 预设只管**内置**工具;宿主 / SDK 注册的工具(`canvas_*` 等)总在活动集里,除非用户
12
+ * `--tools a,b,c` 整组替换(之后只用列出的名字)。
13
+ * - `tools.default`:`+name` / `-name` 在预设上增减;不带前缀的名字整组替换预设的内置工具,
14
+ * 之后再应用带前缀的项。未注册的名字记 warning 并忽略。
15
+ * - codemode 开关跟随预设:`codemode` 预设 → `only`,其余 → `off`;`codemode.mode` 显式配置覆盖。
16
+ * - codemode 工具由 B10 经组装根的 `toolFactories` 注册(`codemode.mode` 为 off 时不注册);不可用
17
+ * (例如 `codemode.requireStrict` 而运行时 Node 不隔离网络)时 codemode 预设**回退到 default 并
18
+ * warning**(不报错:零配置用户不应因此起不来),`on` 同样忽略。
19
+ * - `only` 模式活动集独占:宿主 / SDK 工具也不直接暴露,只能在脚本里调用(`exclusive`)。
20
+ */
21
+ import { ToolRegistry } from "./registry.js";
22
+ export const CODEMODE_TOOL = "codemode";
23
+ /** 各预设下模型直接看到的内置工具(codemode 预设见 `resolvePreset`)。 */
24
+ export const PRESET_TOOLS = Object.freeze({
25
+ default: ["bash", "edit", "glob", "grep", "read", "write"],
26
+ minimal: ["bash", "edit", "read", "write"],
27
+ codemode: [CODEMODE_TOOL],
28
+ coordinator: ["read"],
29
+ });
30
+ /** 生效的 codemode 模式:显式配置优先,否则跟随预设。 */
31
+ export function effectiveCodemodeMode(config) {
32
+ const explicit = config.codemode?.mode;
33
+ if (explicit !== undefined)
34
+ return explicit;
35
+ return config.tools?.preset === "codemode" ? "only" : "off";
36
+ }
37
+ /**
38
+ * `tools.default` 微调:不带前缀的名字整组替换 `base`,再依次应用 `+name` / `-name`。
39
+ * 返回去重后的名字(保持首次出现顺序)。
40
+ */
41
+ export function applyToolAdjustments(base, adjustments) {
42
+ if (adjustments === undefined || adjustments.length === 0)
43
+ return [...base];
44
+ const plain = adjustments.filter((a) => !a.startsWith("+") && !a.startsWith("-"));
45
+ const names = new Set(plain.length > 0 ? plain.map((a) => a.trim()) : base);
46
+ for (const item of adjustments) {
47
+ const name = item.slice(1).trim();
48
+ if (item.startsWith("+"))
49
+ names.add(name);
50
+ else if (item.startsWith("-"))
51
+ names.delete(name);
52
+ }
53
+ names.delete("");
54
+ return [...names];
55
+ }
56
+ export function resolvePreset(input) {
57
+ const warnings = [];
58
+ let preset = input.config.tools?.preset ?? "default";
59
+ let codemode = effectiveCodemodeMode(input.config);
60
+ if (codemode !== "off" && !input.available(CODEMODE_TOOL)) {
61
+ warnings.push(preset === "codemode"
62
+ ? "工具预设 codemode 需要 codemode 工具(不可用),已回退到 default"
63
+ : `codemode.mode ${codemode} 需要 codemode 工具(不可用),已忽略`);
64
+ if (preset === "codemode")
65
+ preset = "default";
66
+ codemode = "off";
67
+ }
68
+ let base;
69
+ if (codemode === "only")
70
+ base = [CODEMODE_TOOL];
71
+ else {
72
+ base = [...PRESET_TOOLS[preset === "codemode" ? "default" : preset]];
73
+ if (codemode === "on")
74
+ base.push(CODEMODE_TOOL);
75
+ }
76
+ const names = [];
77
+ for (const name of applyToolAdjustments(base, input.config.tools?.default)) {
78
+ if (input.available(name))
79
+ names.push(name);
80
+ else
81
+ warnings.push(`tools.default:未知工具 ${name},已忽略`);
82
+ }
83
+ return { preset, codemode, builtin: names.sort(), warnings };
84
+ }
85
+ /**
86
+ * 带预设的注册表:活动集 = 预设里的内置工具 + 全部非内置工具;`setActive()`(`--tools`)之后
87
+ * 退回整组替换语义。`onRegister` 让组装根把会话创建之后才注册的宿主工具追加进会话。
88
+ */
89
+ export class PresetToolRegistry extends ToolRegistry {
90
+ presetNames;
91
+ exclusive = false;
92
+ explicit = false;
93
+ listeners = new Set();
94
+ /**
95
+ * 设预设的内置工具;undefined = 全部内置工具。`exclusive`(codemode only):活动集只有这些名字,
96
+ * 宿主 / SDK 工具也不进活动集。
97
+ */
98
+ setPresetTools(names, options = {}) {
99
+ this.presetNames = names === undefined ? undefined : new Set(names);
100
+ this.exclusive = names !== undefined && options.exclusive === true;
101
+ }
102
+ /** 是否被 `setActive` 整组替换过。 */
103
+ get hasExplicitActive() {
104
+ return this.explicit;
105
+ }
106
+ setActive(names) {
107
+ super.setActive(names);
108
+ this.explicit = true;
109
+ }
110
+ active() {
111
+ const preset = this.presetNames;
112
+ if (this.explicit || preset === undefined)
113
+ return super.active();
114
+ return this.list()
115
+ .filter((name) => preset.has(name) || (!this.exclusive && this.sourceOf(name) !== "builtin"))
116
+ .map((name) => this.get(name))
117
+ .filter((tool) => tool !== undefined);
118
+ }
119
+ register(tool, source) {
120
+ super.register(tool, source);
121
+ for (const listener of [...this.listeners])
122
+ listener(tool, source);
123
+ }
124
+ onRegister(listener) {
125
+ this.listeners.add(listener);
126
+ return () => this.listeners.delete(listener);
127
+ }
128
+ }
@@ -0,0 +1,35 @@
1
+ /**
2
+ * 进程组与杀树(设计 §5.2 bash、§4.2)。[B3]
3
+ *
4
+ * - POSIX:bash 以 `detached: true` 启动,自成进程组(pgid = pid);杀树 = 对 `-pid` 发 SIGTERM,
5
+ * 每 50 ms 探测组是否还在,宽限 2 s 后 SIGKILL。
6
+ * - Windows:`taskkill /PID <pid> /T /F`(没有优雅阶段)。
7
+ * - 信号退出的退出码按 shell 惯例 `128 + signo`。
8
+ * - 启动过的进程组登记在案;本进程 `exit` 时同步 SIGKILL 仍存活的组(Windows 同步 taskkill)。
9
+ */
10
+ export declare const KILL_GRACE_MS = 2000;
11
+ export interface ProcessDeps {
12
+ platform?: NodeJS.Platform;
13
+ /** 缺省 process.kill。 */
14
+ kill?(pid: number, signal: NodeJS.Signals | 0): void;
15
+ /** Windows taskkill 的执行器;缺省 spawn。 */
16
+ runTaskkill?(args: readonly string[]): Promise<void>;
17
+ graceMs?: number;
18
+ }
19
+ /** 信号名 → `128 + signo`;未知信号按 SIGTERM 处理。 */
20
+ export declare function signalExitCode(signal: NodeJS.Signals | string): number;
21
+ /** 子进程结束时的退出码:正常退出取 code,信号退出取 128+signo。 */
22
+ export declare function exitCodeOf(code: number | null, signal: NodeJS.Signals | null): number;
23
+ export declare function taskkillArgs(pid: number): string[];
24
+ /** 进程组(POSIX)是否还有成员。 */
25
+ export declare function isGroupAlive(pid: number, deps?: ProcessDeps): boolean;
26
+ /**
27
+ * 杀整棵进程树。POSIX:SIGTERM → 宽限(缺省 2 s,组提前消失则提前返回)→ SIGKILL。
28
+ * 返回实际是否升级到了 SIGKILL(Windows 恒为 false)。
29
+ */
30
+ export declare function killProcessTree(pid: number, deps?: ProcessDeps): Promise<boolean>;
31
+ export declare function trackProcessGroup(pid: number): void;
32
+ export declare function untrackProcessGroup(pid: number): void;
33
+ export declare function trackedProcessGroups(): readonly number[];
34
+ /** 同步清理(只能在 `exit` 里用同步 API)。 */
35
+ export declare function killTrackedSync(deps?: ProcessDeps): void;
@@ -0,0 +1,125 @@
1
+ /**
2
+ * 进程组与杀树(设计 §5.2 bash、§4.2)。[B3]
3
+ *
4
+ * - POSIX:bash 以 `detached: true` 启动,自成进程组(pgid = pid);杀树 = 对 `-pid` 发 SIGTERM,
5
+ * 每 50 ms 探测组是否还在,宽限 2 s 后 SIGKILL。
6
+ * - Windows:`taskkill /PID <pid> /T /F`(没有优雅阶段)。
7
+ * - 信号退出的退出码按 shell 惯例 `128 + signo`。
8
+ * - 启动过的进程组登记在案;本进程 `exit` 时同步 SIGKILL 仍存活的组(Windows 同步 taskkill)。
9
+ */
10
+ import { spawn, spawnSync } from "node:child_process";
11
+ import { constants } from "node:os";
12
+ export const KILL_GRACE_MS = 2000;
13
+ const POLL_MS = 50;
14
+ /** 信号名 → `128 + signo`;未知信号按 SIGTERM 处理。 */
15
+ export function signalExitCode(signal) {
16
+ const signo = constants.signals[signal];
17
+ return 128 + (signo ?? constants.signals.SIGTERM);
18
+ }
19
+ /** 子进程结束时的退出码:正常退出取 code,信号退出取 128+signo。 */
20
+ export function exitCodeOf(code, signal) {
21
+ if (code !== null)
22
+ return code;
23
+ if (signal !== null)
24
+ return signalExitCode(signal);
25
+ return 1;
26
+ }
27
+ export function taskkillArgs(pid) {
28
+ return ["/PID", String(pid), "/T", "/F"];
29
+ }
30
+ function defaultTaskkill(args) {
31
+ return new Promise((resolve) => {
32
+ try {
33
+ const child = spawn("taskkill", [...args], { stdio: "ignore", windowsHide: true });
34
+ child.on("error", () => resolve());
35
+ child.on("exit", () => resolve());
36
+ }
37
+ catch {
38
+ resolve();
39
+ }
40
+ });
41
+ }
42
+ /** 进程组(POSIX)是否还有成员。 */
43
+ export function isGroupAlive(pid, deps = {}) {
44
+ const kill = deps.kill ?? ((p, s) => process.kill(p, s));
45
+ try {
46
+ kill(-pid, 0);
47
+ return true;
48
+ }
49
+ catch (err) {
50
+ return err.code === "EPERM";
51
+ }
52
+ }
53
+ function sendGroup(pid, signal, deps) {
54
+ const kill = deps.kill ?? ((p, s) => process.kill(p, s));
55
+ try {
56
+ kill(-pid, signal);
57
+ }
58
+ catch {
59
+ try {
60
+ kill(pid, signal);
61
+ }
62
+ catch {
63
+ // 已退出
64
+ }
65
+ }
66
+ }
67
+ const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
68
+ /**
69
+ * 杀整棵进程树。POSIX:SIGTERM → 宽限(缺省 2 s,组提前消失则提前返回)→ SIGKILL。
70
+ * 返回实际是否升级到了 SIGKILL(Windows 恒为 false)。
71
+ */
72
+ export async function killProcessTree(pid, deps = {}) {
73
+ const platform = deps.platform ?? process.platform;
74
+ if (platform === "win32") {
75
+ await (deps.runTaskkill ?? defaultTaskkill)(taskkillArgs(pid));
76
+ return false;
77
+ }
78
+ sendGroup(pid, "SIGTERM", deps);
79
+ const deadline = Date.now() + (deps.graceMs ?? KILL_GRACE_MS);
80
+ while (Date.now() < deadline) {
81
+ if (!isGroupAlive(pid, deps))
82
+ return false;
83
+ await sleep(POLL_MS);
84
+ }
85
+ if (!isGroupAlive(pid, deps))
86
+ return false;
87
+ sendGroup(pid, "SIGKILL", deps);
88
+ return true;
89
+ }
90
+ // ---------------------------------------------------------------------------
91
+ // 登记与退出清理
92
+ // ---------------------------------------------------------------------------
93
+ const tracked = new Set();
94
+ let exitHookInstalled = false;
95
+ export function trackProcessGroup(pid) {
96
+ tracked.add(pid);
97
+ if (!exitHookInstalled) {
98
+ exitHookInstalled = true;
99
+ process.once("exit", () => killTrackedSync());
100
+ }
101
+ }
102
+ export function untrackProcessGroup(pid) {
103
+ tracked.delete(pid);
104
+ }
105
+ export function trackedProcessGroups() {
106
+ return [...tracked];
107
+ }
108
+ /** 同步清理(只能在 `exit` 里用同步 API)。 */
109
+ export function killTrackedSync(deps = {}) {
110
+ const platform = deps.platform ?? process.platform;
111
+ for (const pid of tracked) {
112
+ if (platform === "win32") {
113
+ try {
114
+ spawnSync("taskkill", taskkillArgs(pid), { stdio: "ignore", windowsHide: true });
115
+ }
116
+ catch {
117
+ // 忽略
118
+ }
119
+ }
120
+ else if (isGroupAlive(pid, deps)) {
121
+ sendGroup(pid, "SIGKILL", deps);
122
+ }
123
+ }
124
+ tracked.clear();
125
+ }
@@ -0,0 +1,24 @@
1
+ /**
2
+ * `read` 工具(设计 §5.2)。[B3]
3
+ *
4
+ * 文本按 `cat -n` 形状返回(行号右对齐 6 位 + Tab);头截断 2000 行 / 50 KB 先到者,末尾提示
5
+ * `offset` 续读;NUL 嗅探判二进制并拒绝;png / jpg / gif / webp 作为 ImageBlock 返回(MIME 按文件头,
6
+ * 与 `--image` / `@图片` 共用 image-file.ts;模型不支持图片或超过 5 MB 时只给路径与尺寸);成功后
7
+ * `ctx.markRead(abs)`。
8
+ */
9
+ import type { ToolContext, ToolDefinition, ToolResult } from "./types.js";
10
+ export { imageSize, type ImageSize } from "./image-file.js";
11
+ export interface ReadInput {
12
+ path: string;
13
+ offset?: number;
14
+ limit?: number;
15
+ }
16
+ export interface ReadToolOptions {
17
+ /** 当前模型是否接受图片输入;缺省 true。 */
18
+ supportsImages?(ctx: ToolContext): boolean;
19
+ }
20
+ export declare function isBinary(buf: Buffer): boolean;
21
+ /** `cat -n` 形状。 */
22
+ export declare function numberLines(lines: readonly string[], firstLine: number): string;
23
+ export declare function executeRead(input: ReadInput, ctx: ToolContext, options?: ReadToolOptions): Promise<ToolResult>;
24
+ export declare function createReadTool(options?: ReadToolOptions): ToolDefinition<ReadInput>;
@@ -0,0 +1,132 @@
1
+ /**
2
+ * `read` 工具(设计 §5.2)。[B3]
3
+ *
4
+ * 文本按 `cat -n` 形状返回(行号右对齐 6 位 + Tab);头截断 2000 行 / 50 KB 先到者,末尾提示
5
+ * `offset` 续读;NUL 嗅探判二进制并拒绝;png / jpg / gif / webp 作为 ImageBlock 返回(MIME 按文件头,
6
+ * 与 `--image` / `@图片` 共用 image-file.ts;模型不支持图片或超过 5 MB 时只给路径与尺寸);成功后
7
+ * `ctx.markRead(abs)`。
8
+ */
9
+ import { readFile, stat } from "node:fs/promises";
10
+ import { displayPath, resolvePath } from "./paths.js";
11
+ import { DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, formatSize, truncateHead } from "./truncate.js";
12
+ import { normalizeToLF, splitBom } from "./edit-fuzzy.js";
13
+ import { MAX_IMAGE_BYTES, imageMimeFromPath, imageSize, sniffImageMime } from "./image-file.js";
14
+ export { imageSize } from "./image-file.js";
15
+ const SNIFF_BYTES = 8000;
16
+ export function isBinary(buf) {
17
+ const end = Math.min(buf.length, SNIFF_BYTES);
18
+ for (let i = 0; i < end; i++)
19
+ if (buf[i] === 0)
20
+ return true;
21
+ return false;
22
+ }
23
+ function error(message) {
24
+ return { content: message, isError: true };
25
+ }
26
+ /** `cat -n` 形状。 */
27
+ export function numberLines(lines, firstLine) {
28
+ return lines.map((line, i) => `${String(firstLine + i).padStart(6)}\t${line}`).join("\n");
29
+ }
30
+ async function readImage(abs, shown, ctx, options) {
31
+ const buf = await readFile(abs);
32
+ const mimeType = sniffImageMime(buf) ?? imageMimeFromPath(abs) ?? "application/octet-stream";
33
+ const size = imageSize(buf, mimeType);
34
+ const dims = size ? `${size.width}x${size.height}, ` : "";
35
+ const caption = `Image: ${shown} (${dims}${mimeType}, ${formatSize(buf.length)})`;
36
+ ctx.markRead(abs);
37
+ const details = { path: abs, mimeType, bytes: buf.length, ...(size ? { size } : {}) };
38
+ if (options.supportsImages && !options.supportsImages(ctx)) {
39
+ return { content: `${caption}\n[The current model does not accept image input.]`, details };
40
+ }
41
+ if (buf.length > MAX_IMAGE_BYTES) {
42
+ return {
43
+ content: `${caption}\n[Image exceeds the ${formatSize(MAX_IMAGE_BYTES)} attachment limit; not attached.]`,
44
+ details,
45
+ };
46
+ }
47
+ const blocks = [
48
+ { type: "text", text: caption },
49
+ { type: "image", data: buf.toString("base64"), mimeType },
50
+ ];
51
+ return { content: blocks, details };
52
+ }
53
+ export async function executeRead(input, ctx, options = {}) {
54
+ const abs = resolvePath(input.path, ctx.cwd);
55
+ const shown = displayPath(abs, ctx.cwd);
56
+ let info;
57
+ try {
58
+ info = await stat(abs);
59
+ }
60
+ catch {
61
+ return error(`File not found: ${shown}`);
62
+ }
63
+ if (info.isDirectory())
64
+ return error(`${shown} is a directory; use the ls tool instead`);
65
+ if (imageMimeFromPath(abs) !== undefined)
66
+ return readImage(abs, shown, ctx, options);
67
+ const buf = await readFile(abs);
68
+ if (isBinary(buf))
69
+ return error(`${shown} appears to be a binary file; refusing to read it`);
70
+ const { text } = splitBom(buf.toString("utf8"));
71
+ const normalized = normalizeToLF(text);
72
+ const allLines = normalized === "" ? [] : normalized.replace(/\n$/, "").split("\n");
73
+ ctx.markRead(abs);
74
+ if (allLines.length === 0) {
75
+ return { content: `(${shown} is empty)`, details: { path: abs, totalLines: 0 } };
76
+ }
77
+ const offset = input.offset ?? 1;
78
+ if (!Number.isInteger(offset) || offset < 1)
79
+ return error("offset must be an integer ≥ 1");
80
+ if (offset > allLines.length) {
81
+ return error(`offset ${offset} is beyond the end of ${shown} (${allLines.length} lines)`);
82
+ }
83
+ if (input.limit !== undefined && (!Number.isInteger(input.limit) || input.limit < 1)) {
84
+ return error("limit must be an integer ≥ 1");
85
+ }
86
+ const end = input.limit === undefined ? allLines.length : offset - 1 + input.limit;
87
+ const selected = allLines.slice(offset - 1, end);
88
+ const numbered = numberLines(selected, offset);
89
+ const cut = truncateHead(numbered, { maxLines: DEFAULT_MAX_LINES, maxBytes: DEFAULT_MAX_BYTES });
90
+ const lastShown = offset - 1 + cut.outputLines;
91
+ let content = cut.content;
92
+ if (lastShown < allLines.length) {
93
+ const reason = cut.truncated
94
+ ? ` (output limit ${cut.truncatedBy === "bytes" ? formatSize(DEFAULT_MAX_BYTES) : `${DEFAULT_MAX_LINES} lines`} reached)`
95
+ : "";
96
+ content += `\n\n[Showing lines ${offset}-${lastShown} of ${allLines.length}${reason}. Use offset=${lastShown + 1} to continue.]`;
97
+ }
98
+ return {
99
+ content,
100
+ details: {
101
+ path: abs,
102
+ totalLines: allLines.length,
103
+ firstLine: offset,
104
+ lastLine: lastShown,
105
+ truncated: cut.truncated,
106
+ },
107
+ };
108
+ }
109
+ export function createReadTool(options = {}) {
110
+ return {
111
+ name: "read",
112
+ label: "Read",
113
+ description: "Read a file. Text comes with line numbers (cat -n), limited to " +
114
+ `${DEFAULT_MAX_LINES} lines or ${formatSize(DEFAULT_MAX_BYTES)}; page with offset/limit. ` +
115
+ "Images (png, jpg, gif, webp) come as attachments.",
116
+ parameters: {
117
+ type: "object",
118
+ properties: {
119
+ path: { type: "string", description: "Absolute or relative to cwd" },
120
+ offset: { type: "integer", description: "First line (1-based)" },
121
+ limit: { type: "integer", description: "Max lines" },
122
+ },
123
+ required: ["path"],
124
+ additionalProperties: false,
125
+ },
126
+ permission: "read",
127
+ executionMode: "parallel",
128
+ annotations: { readOnly: true },
129
+ promptSnippet: "read: read files (text or images)",
130
+ execute: (input, ctx) => executeRead(input, ctx, options),
131
+ };
132
+ }
@@ -0,0 +1,43 @@
1
+ /**
2
+ * ToolRegistry:内置 + 宿主 / SDK 注册、disable、活动集、按名排序(设计 §1.2、§5.1)。[B3]
3
+ *
4
+ * - 注册校验:名字 `^[a-z][a-z0-9_]{1,63}$`、`parameters` 只用 JSON Schema 子集(checkSchemaSubset)、
5
+ * 同名 → AmaError{code:"tool_exists"};
6
+ * - `disable(name)` 后不再出现在 `list()` / `active()`,也不能被 `setActive` 选中;未注册的名字也
7
+ * 记下(宿主可能先 disable 再由内置注册,例如 `disable("task")`);
8
+ * - 活动集缺省 = 全部已注册且未禁用;`setActive(names)` 之后只用这些(未知名 → tool_not_found);
9
+ * - `builtinTools()` 给出全部内置工具;Skill 正文由模型用 read 读取(设计 §5.6 删除了 skill 工具),
10
+ * `/skill:` 命令展开在 skills/expand.ts。
11
+ */
12
+ import type { ToolDefinition, ToolExecutionMode, ToolRegistryApi, ToolSource } from "./types.js";
13
+ import { type ReadToolOptions } from "./read.js";
14
+ import { type BashToolOptions } from "./bash.js";
15
+ import { type TaskToolOptions } from "./task.js";
16
+ export declare const TOOL_NAME_RE: RegExp;
17
+ /** 未声明时:read → parallel;write / execute → sequential。 */
18
+ export declare function executionModeOf(tool: Pick<ToolDefinition, "permission" | "executionMode">): ToolExecutionMode;
19
+ export declare function validateToolDefinition(tool: ToolDefinition): void;
20
+ export declare class ToolRegistry implements ToolRegistryApi {
21
+ private readonly entries;
22
+ private readonly disabled;
23
+ private activeNames;
24
+ register(tool: ToolDefinition, source: ToolSource): void;
25
+ disable(name: string): void;
26
+ isDisabled(name: string): boolean;
27
+ get(name: string): ToolDefinition | undefined;
28
+ sourceOf(name: string): ToolSource | undefined;
29
+ list(): readonly string[];
30
+ active(): readonly ToolDefinition[];
31
+ setActive(names: readonly string[]): void;
32
+ }
33
+ export interface BuiltinToolOptions {
34
+ read?: ReadToolOptions;
35
+ bash?: BashToolOptions;
36
+ task?: TaskToolOptions;
37
+ }
38
+ /** 全部内置工具(read / write / edit / bash / grep / glob / ls / todo / task)。 */
39
+ export declare function builtinTools(options?: BuiltinToolOptions): ToolDefinition[];
40
+ /** 新建注册表并登记全部内置工具;`disabled` 来自 config.tools.disabled。 */
41
+ export declare function createToolRegistry(options?: BuiltinToolOptions & {
42
+ disabled?: readonly string[];
43
+ }): ToolRegistry;
@@ -0,0 +1,106 @@
1
+ /**
2
+ * ToolRegistry:内置 + 宿主 / SDK 注册、disable、活动集、按名排序(设计 §1.2、§5.1)。[B3]
3
+ *
4
+ * - 注册校验:名字 `^[a-z][a-z0-9_]{1,63}$`、`parameters` 只用 JSON Schema 子集(checkSchemaSubset)、
5
+ * 同名 → AmaError{code:"tool_exists"};
6
+ * - `disable(name)` 后不再出现在 `list()` / `active()`,也不能被 `setActive` 选中;未注册的名字也
7
+ * 记下(宿主可能先 disable 再由内置注册,例如 `disable("task")`);
8
+ * - 活动集缺省 = 全部已注册且未禁用;`setActive(names)` 之后只用这些(未知名 → tool_not_found);
9
+ * - `builtinTools()` 给出全部内置工具;Skill 正文由模型用 read 读取(设计 §5.6 删除了 skill 工具),
10
+ * `/skill:` 命令展开在 skills/expand.ts。
11
+ */
12
+ import { AmaError } from "../errors.js";
13
+ import { checkSchemaSubset } from "../agent/schema.js";
14
+ import { createReadTool } from "./read.js";
15
+ import { createWriteTool } from "./write.js";
16
+ import { createEditTool } from "./edit.js";
17
+ import { createBashTool } from "./bash.js";
18
+ import { createGrepTool } from "./grep.js";
19
+ import { createGlobTool } from "./glob.js";
20
+ import { createLsTool } from "./ls.js";
21
+ import { createTodoTool } from "./todo.js";
22
+ import { createTaskTool } from "./task.js";
23
+ export const TOOL_NAME_RE = /^[a-z][a-z0-9_]{1,63}$/;
24
+ /** 未声明时:read → parallel;write / execute → sequential。 */
25
+ export function executionModeOf(tool) {
26
+ return tool.executionMode ?? (tool.permission === "read" ? "parallel" : "sequential");
27
+ }
28
+ export function validateToolDefinition(tool) {
29
+ if (typeof tool.name !== "string" || !TOOL_NAME_RE.test(tool.name)) {
30
+ throw new AmaError("invalid_arguments", `Invalid tool name "${String(tool.name)}"`);
31
+ }
32
+ if (!["read", "write", "execute"].includes(tool.permission)) {
33
+ throw new AmaError("invalid_arguments", `Tool ${tool.name}: invalid permission`);
34
+ }
35
+ if (typeof tool.execute !== "function") {
36
+ throw new AmaError("invalid_arguments", `Tool ${tool.name}: execute must be a function`);
37
+ }
38
+ const problems = checkSchemaSubset(tool.parameters);
39
+ if (problems.length > 0) {
40
+ throw new AmaError("invalid_arguments", `Tool ${tool.name}: parameters use unsupported schema features: ${problems.join("; ")}`);
41
+ }
42
+ }
43
+ export class ToolRegistry {
44
+ entries = new Map();
45
+ disabled = new Set();
46
+ activeNames;
47
+ register(tool, source) {
48
+ validateToolDefinition(tool);
49
+ if (this.entries.has(tool.name)) {
50
+ throw new AmaError("tool_exists", `Tool "${tool.name}" is already registered`);
51
+ }
52
+ this.entries.set(tool.name, { tool, source });
53
+ }
54
+ disable(name) {
55
+ this.disabled.add(name);
56
+ this.activeNames?.delete(name);
57
+ }
58
+ isDisabled(name) {
59
+ return this.disabled.has(name);
60
+ }
61
+ get(name) {
62
+ return this.disabled.has(name) ? undefined : this.entries.get(name)?.tool;
63
+ }
64
+ sourceOf(name) {
65
+ return this.entries.get(name)?.source;
66
+ }
67
+ list() {
68
+ return [...this.entries.keys()].filter((n) => !this.disabled.has(n)).sort();
69
+ }
70
+ active() {
71
+ const names = this.list().filter((n) => this.activeNames === undefined || this.activeNames.has(n));
72
+ return names.map((n) => this.entries.get(n).tool);
73
+ }
74
+ setActive(names) {
75
+ for (const name of names) {
76
+ if (!this.entries.has(name) || this.disabled.has(name)) {
77
+ throw new AmaError("tool_not_found", `Unknown or disabled tool "${name}"`);
78
+ }
79
+ }
80
+ this.activeNames = new Set(names);
81
+ }
82
+ }
83
+ /** 全部内置工具(read / write / edit / bash / grep / glob / ls / todo / task)。 */
84
+ export function builtinTools(options = {}) {
85
+ const tools = [
86
+ createReadTool(options.read),
87
+ createWriteTool(),
88
+ createEditTool(),
89
+ createBashTool(options.bash),
90
+ createGrepTool(),
91
+ createGlobTool(),
92
+ createLsTool(),
93
+ createTodoTool(),
94
+ createTaskTool(options.task),
95
+ ];
96
+ return tools;
97
+ }
98
+ /** 新建注册表并登记全部内置工具;`disabled` 来自 config.tools.disabled。 */
99
+ export function createToolRegistry(options = {}) {
100
+ const registry = new ToolRegistry();
101
+ for (const tool of builtinTools(options))
102
+ registry.register(tool, "builtin");
103
+ for (const name of options.disabled ?? [])
104
+ registry.disable(name);
105
+ return registry;
106
+ }