@armadra/agent 0.5.1 → 0.6.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 (486) hide show
  1. package/CHANGELOG.md +203 -304
  2. package/CHANGELOG.zh-CN.md +462 -0
  3. package/README.md +408 -364
  4. package/README.zh-CN.md +705 -0
  5. package/dist/agent/session-plan.js +2 -2
  6. package/dist/agent/session-state.d.ts +3 -0
  7. package/dist/agent/session-state.js +20 -0
  8. package/dist/agent/session-subagent.d.ts +15 -1
  9. package/dist/agent/session-subagent.js +26 -3
  10. package/dist/agent/session-telemetry.d.ts +16 -2
  11. package/dist/agent/session-telemetry.js +29 -7
  12. package/dist/agent/session-tools.js +5 -2
  13. package/dist/agent/session-trace-writer.d.ts +27 -0
  14. package/dist/agent/session-trace-writer.js +253 -0
  15. package/dist/agent/session.d.ts +2 -0
  16. package/dist/agent/session.js +12 -0
  17. package/dist/agent/subagent-direct.d.ts +20 -0
  18. package/dist/agent/subagent-direct.js +76 -0
  19. package/dist/agent/subagent-registry.d.ts +8 -1
  20. package/dist/agent/subagent-registry.js +28 -1
  21. package/dist/agent/system-prompt.d.ts +3 -1
  22. package/dist/agent/system-prompt.js +3 -0
  23. package/dist/agent/tool-runner.d.ts +2 -1
  24. package/dist/agent/tool-runner.js +5 -4
  25. package/dist/agent/types-w6.d.ts +39 -0
  26. package/dist/agent/types-w6.js +4 -0
  27. package/dist/agent/types.d.ts +5 -2
  28. package/dist/agents/external.js +1 -1
  29. package/dist/agents/task-record.d.ts +74 -1
  30. package/dist/agents/task-record.js +100 -0
  31. package/dist/ai/apis/cache-params.js +2 -1
  32. package/dist/ai/apis/chatgpt-backend.d.ts +52 -0
  33. package/dist/ai/apis/chatgpt-backend.js +224 -0
  34. package/dist/ai/apis/chatgpt-rate-limits.d.ts +26 -0
  35. package/dist/ai/apis/chatgpt-rate-limits.js +91 -0
  36. package/dist/ai/apis/openai-responses-request.d.ts +2 -1
  37. package/dist/ai/apis/openai-responses-request.js +8 -2
  38. package/dist/ai/apis/openai-responses.d.ts +2 -0
  39. package/dist/ai/apis/openai-responses.js +51 -16
  40. package/dist/ai/overflow.d.ts +1 -1
  41. package/dist/ai/overflow.js +10 -7
  42. package/dist/ai/providers/auth.d.ts +15 -2
  43. package/dist/ai/providers/auth.js +69 -2
  44. package/dist/ai/providers/builtin.js +27 -0
  45. package/dist/ai/providers/catalog-data.js +1 -0
  46. package/dist/ai/providers/discovered-cache.d.ts +48 -0
  47. package/dist/ai/providers/discovered-cache.js +102 -0
  48. package/dist/ai/providers/enrich.js +2 -7
  49. package/dist/ai/providers/model-visibility.d.ts +33 -0
  50. package/dist/ai/providers/model-visibility.js +70 -0
  51. package/dist/ai/providers/models-dev-cache.js +15 -19
  52. package/dist/ai/providers/models-dev-snapshot.js +8 -7
  53. package/dist/ai/providers/models-dev.js +5 -15
  54. package/dist/ai/providers/registry.d.ts +2 -0
  55. package/dist/ai/providers/registry.js +6 -1
  56. package/dist/ai/providers/suggest.js +2 -16
  57. package/dist/ai/types.d.ts +27 -1
  58. package/dist/auth/chatgpt/backend-client.d.ts +26 -0
  59. package/dist/auth/chatgpt/backend-client.js +74 -0
  60. package/dist/auth/chatgpt/claims.d.ts +17 -0
  61. package/dist/auth/chatgpt/claims.js +46 -0
  62. package/dist/auth/chatgpt/cli.d.ts +35 -0
  63. package/dist/auth/chatgpt/cli.js +279 -0
  64. package/dist/auth/chatgpt/doctor.d.ts +17 -0
  65. package/dist/auth/chatgpt/doctor.js +36 -0
  66. package/dist/auth/chatgpt/host-id.d.ts +7 -0
  67. package/dist/auth/chatgpt/host-id.js +26 -0
  68. package/dist/auth/chatgpt/login.d.ts +30 -0
  69. package/dist/auth/chatgpt/login.js +130 -0
  70. package/dist/auth/chatgpt/presets.d.ts +66 -0
  71. package/dist/auth/chatgpt/presets.js +120 -0
  72. package/dist/auth/chatgpt/quota-text.d.ts +13 -0
  73. package/dist/auth/chatgpt/quota-text.js +36 -0
  74. package/dist/auth/oauth/browser.d.ts +12 -0
  75. package/dist/auth/oauth/browser.js +27 -0
  76. package/dist/auth/oauth/callback-server.d.ts +47 -0
  77. package/dist/auth/oauth/callback-server.js +147 -0
  78. package/dist/auth/oauth/flows.d.ts +62 -0
  79. package/dist/auth/oauth/flows.js +113 -0
  80. package/dist/auth/oauth/jwt.d.ts +24 -0
  81. package/dist/auth/oauth/jwt.js +81 -0
  82. package/dist/auth/oauth/live.d.ts +21 -0
  83. package/dist/auth/oauth/live.js +25 -0
  84. package/dist/auth/oauth/oidc.d.ts +26 -0
  85. package/dist/auth/oauth/oidc.js +72 -0
  86. package/dist/auth/oauth/pkce.d.ts +15 -0
  87. package/dist/auth/oauth/pkce.js +20 -0
  88. package/dist/auth/oauth/refresh.d.ts +35 -0
  89. package/dist/auth/oauth/refresh.js +129 -0
  90. package/dist/auth/oauth/token-client.d.ts +33 -0
  91. package/dist/auth/oauth/token-client.js +121 -0
  92. package/dist/auth/oauth/token-store.d.ts +23 -0
  93. package/dist/auth/oauth/token-store.js +125 -0
  94. package/dist/auth/testing/fake-oauth.d.ts +73 -0
  95. package/dist/auth/testing/fake-oauth.js +271 -0
  96. package/dist/auth/testing/refresh-child.d.ts +5 -0
  97. package/dist/auth/testing/refresh-child.js +16 -0
  98. package/dist/bundle/ama.cjs +26532 -11045
  99. package/dist/checkpoints/backend.js +6 -5
  100. package/dist/checkpoints/restore.js +3 -2
  101. package/dist/checkpoints/settings.js +2 -1
  102. package/dist/checkpoints/shadow-git.js +7 -6
  103. package/dist/checkpoints/shadow-restore.js +3 -2
  104. package/dist/checkpoints/tracker.js +4 -3
  105. package/dist/cli/args.d.ts +9 -2
  106. package/dist/cli/args.js +74 -27
  107. package/dist/cli/bootstrap.js +53 -31
  108. package/dist/cli/choice-prompt.js +8 -6
  109. package/dist/cli/codemode-notice.js +2 -2
  110. package/dist/cli/compose-agents.js +2 -1
  111. package/dist/cli/compose-extensions.js +2 -0
  112. package/dist/cli/compose-memory.d.ts +53 -0
  113. package/dist/cli/compose-memory.js +127 -0
  114. package/dist/cli/compose-providers.d.ts +6 -0
  115. package/dist/cli/compose-providers.js +38 -2
  116. package/dist/cli/compose-session.d.ts +5 -0
  117. package/dist/cli/compose-session.js +27 -13
  118. package/dist/cli/compose-store.d.ts +2 -0
  119. package/dist/cli/compose-store.js +9 -5
  120. package/dist/cli/compose.d.ts +2 -0
  121. package/dist/cli/compose.js +13 -5
  122. package/dist/cli/default-model.d.ts +0 -2
  123. package/dist/cli/default-model.js +5 -8
  124. package/dist/cli/deps.d.ts +5 -1
  125. package/dist/cli/exit-codes.d.ts +1 -1
  126. package/dist/cli/exit-codes.js +7 -16
  127. package/dist/cli/from-prompt.js +3 -2
  128. package/dist/cli/help-text.d.ts +2 -1
  129. package/dist/cli/help-text.js +5 -99
  130. package/dist/cli/main.d.ts +5 -0
  131. package/dist/cli/main.js +21 -2
  132. package/dist/cli/proxy.js +14 -9
  133. package/dist/cli/runtime.d.ts +5 -0
  134. package/dist/cli/startup-screen.js +20 -27
  135. package/dist/cli/startup-steps.js +6 -8
  136. package/dist/cli/subcommands/auth.d.ts +6 -3
  137. package/dist/cli/subcommands/auth.js +52 -22
  138. package/dist/cli/subcommands/config-set.d.ts +21 -0
  139. package/dist/cli/subcommands/config-set.js +145 -0
  140. package/dist/cli/subcommands/config.d.ts +2 -1
  141. package/dist/cli/subcommands/config.js +51 -37
  142. package/dist/cli/subcommands/doctor.d.ts +2 -1
  143. package/dist/cli/subcommands/doctor.js +97 -58
  144. package/dist/cli/subcommands/init.d.ts +1 -1
  145. package/dist/cli/subcommands/init.js +8 -7
  146. package/dist/cli/subcommands/memory.d.ts +18 -0
  147. package/dist/cli/subcommands/memory.js +189 -0
  148. package/dist/cli/subcommands/model-meta.js +11 -9
  149. package/dist/cli/subcommands/models-cache-probe.js +23 -20
  150. package/dist/cli/subcommands/models-discover.d.ts +4 -0
  151. package/dist/cli/subcommands/models-discover.js +60 -21
  152. package/dist/cli/subcommands/models-enable.d.ts +13 -0
  153. package/dist/cli/subcommands/models-enable.js +145 -0
  154. package/dist/cli/subcommands/models.d.ts +3 -1
  155. package/dist/cli/subcommands/models.js +39 -24
  156. package/dist/cli/subcommands/probe-runner.js +8 -7
  157. package/dist/cli/subcommands/providers-list.js +32 -21
  158. package/dist/cli/subcommands/providers-plan.js +24 -25
  159. package/dist/cli/subcommands/providers-probe.js +5 -6
  160. package/dist/cli/subcommands/providers.d.ts +1 -1
  161. package/dist/cli/subcommands/providers.js +45 -50
  162. package/dist/cli/subcommands/sessions-export.d.ts +1 -1
  163. package/dist/cli/subcommands/sessions-export.js +10 -9
  164. package/dist/cli/subcommands/sessions-search.d.ts +1 -1
  165. package/dist/cli/subcommands/sessions-search.js +11 -10
  166. package/dist/cli/subcommands/sessions-trace.d.ts +30 -0
  167. package/dist/cli/subcommands/sessions-trace.js +156 -0
  168. package/dist/cli/subcommands/sessions.d.ts +4 -3
  169. package/dist/cli/subcommands/sessions.js +40 -37
  170. package/dist/cli/subcommands/stats.d.ts +1 -1
  171. package/dist/cli/subcommands/stats.js +49 -30
  172. package/dist/cli/system-prompt-arg.js +3 -2
  173. package/dist/codemode/capability.js +3 -2
  174. package/dist/compaction/post-compact.d.ts +1 -0
  175. package/dist/compaction/post-compact.js +15 -1
  176. package/dist/compaction/prune-tier.d.ts +1 -1
  177. package/dist/compaction/prune-tier.js +3 -3
  178. package/dist/compaction/serialize.js +2 -1
  179. package/dist/config/auth-file.d.ts +12 -2
  180. package/dist/config/auth-file.js +32 -10
  181. package/dist/config/checker.js +12 -11
  182. package/dist/config/context-files.js +3 -2
  183. package/dist/config/edit.d.ts +106 -0
  184. package/dist/config/edit.js +350 -0
  185. package/dist/config/init.d.ts +4 -3
  186. package/dist/config/init.js +10 -18
  187. package/dist/config/json-schema.d.ts +2 -1
  188. package/dist/config/json-schema.js +102 -69
  189. package/dist/config/key-docs.d.ts +18 -7
  190. package/dist/config/key-docs.js +43 -128
  191. package/dist/config/load.js +7 -6
  192. package/dist/config/merge.d.ts +4 -1
  193. package/dist/config/merge.js +42 -22
  194. package/dist/config/paths.js +6 -5
  195. package/dist/config/profile.d.ts +5 -1
  196. package/dist/config/profile.js +7 -2
  197. package/dist/config/schema-w5.js +12 -4
  198. package/dist/config/schema-w6.d.ts +19 -0
  199. package/dist/config/schema-w6.js +115 -0
  200. package/dist/config/schema.js +34 -20
  201. package/dist/config/settings-registry.d.ts +81 -0
  202. package/dist/config/settings-registry.js +185 -0
  203. package/dist/config/types-w5.d.ts +7 -0
  204. package/dist/config/types-w5.js +2 -0
  205. package/dist/config/types-w6.d.ts +109 -0
  206. package/dist/config/types-w6.js +19 -0
  207. package/dist/config/types.d.ts +11 -8
  208. package/dist/config/types.js +1 -0
  209. package/dist/drivers/acp/client.js +1 -1
  210. package/dist/drivers/acp/driver.js +13 -8
  211. package/dist/drivers/agents.js +4 -3
  212. package/dist/drivers/base.js +3 -2
  213. package/dist/drivers/host-runners.js +2 -1
  214. package/dist/drivers/native/claude-stream.js +12 -11
  215. package/dist/drivers/native/codex-app-server.js +17 -12
  216. package/dist/drivers/native/oneshot.js +8 -7
  217. package/dist/drivers/pool.js +1 -1
  218. package/dist/drivers/runner.d.ts +3 -1
  219. package/dist/drivers/runner.js +68 -20
  220. package/dist/drivers/turn.js +1 -1
  221. package/dist/hooks/config.js +3 -2
  222. package/dist/hooks/protocol.js +18 -12
  223. package/dist/host/api-impl.js +11 -10
  224. package/dist/host/loader.js +9 -8
  225. package/dist/host/types.d.ts +3 -0
  226. package/dist/i18n/catalog.d.ts +2209 -0
  227. package/dist/i18n/catalog.js +72 -0
  228. package/dist/i18n/format.d.ts +21 -0
  229. package/dist/i18n/format.js +58 -0
  230. package/dist/i18n/index.d.ts +58 -0
  231. package/dist/i18n/index.js +72 -0
  232. package/dist/i18n/messages/agents.d.ts +84 -0
  233. package/dist/i18n/messages/agents.js +85 -0
  234. package/dist/i18n/messages/approval.d.ts +99 -0
  235. package/dist/i18n/messages/approval.js +100 -0
  236. package/dist/i18n/messages/auth.d.ts +189 -0
  237. package/dist/i18n/messages/auth.js +201 -0
  238. package/dist/i18n/messages/cli-args.d.ts +46 -0
  239. package/dist/i18n/messages/cli-args.js +46 -0
  240. package/dist/i18n/messages/cli-help.d.ts +12 -0
  241. package/dist/i18n/messages/cli-help.js +248 -0
  242. package/dist/i18n/messages/cli.d.ts +336 -0
  243. package/dist/i18n/messages/cli.js +311 -0
  244. package/dist/i18n/messages/config-keys.d.ts +293 -0
  245. package/dist/i18n/messages/config-keys.js +296 -0
  246. package/dist/i18n/messages/config.d.ts +508 -0
  247. package/dist/i18n/messages/config.js +241 -0
  248. package/dist/i18n/messages/drivers.d.ts +123 -0
  249. package/dist/i18n/messages/drivers.js +124 -0
  250. package/dist/i18n/messages/errors.d.ts +83 -0
  251. package/dist/i18n/messages/errors.js +171 -0
  252. package/dist/i18n/messages/interactive-line.d.ts +61 -0
  253. package/dist/i18n/messages/interactive-line.js +69 -0
  254. package/dist/i18n/messages/interactive-startup.d.ts +99 -0
  255. package/dist/i18n/messages/interactive-startup.js +100 -0
  256. package/dist/i18n/messages/interactive-view.d.ts +140 -0
  257. package/dist/i18n/messages/interactive-view.js +141 -0
  258. package/dist/i18n/messages/interactive.d.ts +489 -0
  259. package/dist/i18n/messages/interactive.js +248 -0
  260. package/dist/i18n/messages/memory.d.ts +123 -0
  261. package/dist/i18n/messages/memory.js +128 -0
  262. package/dist/i18n/messages/panels.d.ts +233 -0
  263. package/dist/i18n/messages/panels.js +232 -0
  264. package/dist/i18n/messages/permissions.d.ts +126 -0
  265. package/dist/i18n/messages/permissions.js +151 -0
  266. package/dist/i18n/messages/plan.d.ts +123 -0
  267. package/dist/i18n/messages/plan.js +124 -0
  268. package/dist/i18n/messages/print.d.ts +86 -0
  269. package/dist/i18n/messages/print.js +91 -0
  270. package/dist/i18n/messages/report.d.ts +391 -0
  271. package/dist/i18n/messages/report.js +490 -0
  272. package/dist/i18n/messages/rewind.d.ts +198 -0
  273. package/dist/i18n/messages/rewind.js +217 -0
  274. package/dist/i18n/messages/session.d.ts +230 -0
  275. package/dist/i18n/messages/session.js +258 -0
  276. package/dist/i18n/messages/settings.d.ts +355 -0
  277. package/dist/i18n/messages/settings.js +343 -0
  278. package/dist/i18n/messages/subcommands-config.d.ts +113 -0
  279. package/dist/i18n/messages/subcommands-config.js +129 -0
  280. package/dist/i18n/messages/subcommands-models.d.ts +34 -0
  281. package/dist/i18n/messages/subcommands-models.js +34 -0
  282. package/dist/i18n/messages/subcommands.d.ts +576 -0
  283. package/dist/i18n/messages/subcommands.js +477 -0
  284. package/dist/i18n/messages/trace.d.ts +243 -0
  285. package/dist/i18n/messages/trace.js +238 -0
  286. package/dist/i18n/types.d.ts +15 -0
  287. package/dist/i18n/types.js +7 -0
  288. package/dist/index.d.ts +6 -0
  289. package/dist/index.js +2 -0
  290. package/dist/memory/edit.d.ts +24 -0
  291. package/dist/memory/edit.js +63 -0
  292. package/dist/memory/frontmatter.d.ts +37 -0
  293. package/dist/memory/frontmatter.js +79 -0
  294. package/dist/memory/index.d.ts +28 -0
  295. package/dist/memory/index.js +126 -0
  296. package/dist/memory/lock.d.ts +17 -0
  297. package/dist/memory/lock.js +62 -0
  298. package/dist/memory/paths.d.ts +57 -0
  299. package/dist/memory/paths.js +175 -0
  300. package/dist/memory/report.d.ts +36 -0
  301. package/dist/memory/report.js +86 -0
  302. package/dist/memory/runtime.d.ts +42 -0
  303. package/dist/memory/runtime.js +36 -0
  304. package/dist/memory/secrets.d.ts +8 -0
  305. package/dist/memory/secrets.js +27 -0
  306. package/dist/memory/section.d.ts +28 -0
  307. package/dist/memory/section.js +59 -0
  308. package/dist/memory/store.d.ts +70 -0
  309. package/dist/memory/store.js +284 -0
  310. package/dist/memory/tool.d.ts +31 -0
  311. package/dist/memory/tool.js +94 -0
  312. package/dist/modes/acp/acp-events.js +2 -1
  313. package/dist/modes/acp/acp-server.js +13 -12
  314. package/dist/modes/commands-core.d.ts +11 -0
  315. package/dist/modes/commands-core.js +93 -62
  316. package/dist/modes/image-input.js +20 -6
  317. package/dist/modes/interactive/agent-bar.d.ts +95 -0
  318. package/dist/modes/interactive/agent-bar.js +248 -0
  319. package/dist/modes/interactive/agent-panels.js +27 -26
  320. package/dist/modes/interactive/agent-transcript.d.ts +47 -0
  321. package/dist/modes/interactive/agent-transcript.js +191 -0
  322. package/dist/modes/interactive/agent-ui.d.ts +36 -1
  323. package/dist/modes/interactive/agent-ui.js +180 -14
  324. package/dist/modes/interactive/agent-view.d.ts +72 -0
  325. package/dist/modes/interactive/agent-view.js +281 -0
  326. package/dist/modes/interactive/approval-dialog.js +46 -34
  327. package/dist/modes/interactive/clipboard-paste.d.ts +2 -2
  328. package/dist/modes/interactive/clipboard-paste.js +9 -4
  329. package/dist/modes/interactive/commands.d.ts +22 -1
  330. package/dist/modes/interactive/commands.js +100 -49
  331. package/dist/modes/interactive/completion.js +2 -1
  332. package/dist/modes/interactive/config-panel.d.ts +70 -0
  333. package/dist/modes/interactive/config-panel.js +319 -0
  334. package/dist/modes/interactive/config-ui.d.ts +96 -0
  335. package/dist/modes/interactive/config-ui.js +397 -0
  336. package/dist/modes/interactive/confirm-dialog.js +6 -7
  337. package/dist/modes/interactive/event-notices.js +11 -9
  338. package/dist/modes/interactive/interactive-mode.d.ts +1 -1
  339. package/dist/modes/interactive/interactive-mode.js +21 -22
  340. package/dist/modes/interactive/key-dispatch.d.ts +12 -0
  341. package/dist/modes/interactive/key-dispatch.js +24 -9
  342. package/dist/modes/interactive/line/line-editor.js +2 -1
  343. package/dist/modes/interactive/line/line-mode.js +18 -7
  344. package/dist/modes/interactive/line/line-render.js +25 -24
  345. package/dist/modes/interactive/memory-panel.d.ts +64 -0
  346. package/dist/modes/interactive/memory-panel.js +221 -0
  347. package/dist/modes/interactive/message-view.d.ts +4 -2
  348. package/dist/modes/interactive/message-view.js +42 -33
  349. package/dist/modes/interactive/model-items.d.ts +45 -0
  350. package/dist/modes/interactive/model-items.js +134 -0
  351. package/dist/modes/interactive/model-picker.d.ts +57 -0
  352. package/dist/modes/interactive/model-picker.js +191 -0
  353. package/dist/modes/interactive/panels.js +39 -31
  354. package/dist/modes/interactive/pickers.d.ts +2 -1
  355. package/dist/modes/interactive/pickers.js +10 -6
  356. package/dist/modes/interactive/plan-command.d.ts +1 -1
  357. package/dist/modes/interactive/plan-command.js +24 -27
  358. package/dist/modes/interactive/plan-dialog.js +18 -17
  359. package/dist/modes/interactive/plan-flow.js +6 -5
  360. package/dist/modes/interactive/rewind-command.d.ts +1 -1
  361. package/dist/modes/interactive/rewind-command.js +18 -16
  362. package/dist/modes/interactive/rewind-flow.d.ts +0 -1
  363. package/dist/modes/interactive/rewind-flow.js +13 -14
  364. package/dist/modes/interactive/rewind-list.js +7 -6
  365. package/dist/modes/interactive/rewind-panel.js +40 -40
  366. package/dist/modes/interactive/rewind-text.d.ts +5 -3
  367. package/dist/modes/interactive/rewind-text.js +48 -38
  368. package/dist/modes/interactive/run-indicator.js +15 -12
  369. package/dist/modes/interactive/session-events.js +3 -2
  370. package/dist/modes/interactive/startup-header.js +22 -23
  371. package/dist/modes/interactive/startup-ui.d.ts +3 -9
  372. package/dist/modes/interactive/startup-ui.js +44 -88
  373. package/dist/modes/interactive/status-area.d.ts +2 -0
  374. package/dist/modes/interactive/status-area.js +8 -2
  375. package/dist/modes/interactive/status-bar.js +4 -3
  376. package/dist/modes/interactive/subagent-view.js +9 -7
  377. package/dist/modes/interactive/tasks-report.d.ts +6 -0
  378. package/dist/modes/interactive/tasks-report.js +28 -31
  379. package/dist/modes/interactive/terminal-setup.d.ts +9 -0
  380. package/dist/modes/interactive/terminal-setup.js +23 -0
  381. package/dist/modes/interactive/tool-summary.js +19 -17
  382. package/dist/modes/interactive/tool-view.js +7 -4
  383. package/dist/modes/interactive/trace-view.d.ts +89 -0
  384. package/dist/modes/interactive/trace-view.js +332 -0
  385. package/dist/modes/print/print-mode.js +14 -15
  386. package/dist/modes/rpc/commands.js +7 -3
  387. package/dist/modes/rpc/rpc-mode.js +9 -3
  388. package/dist/modes/session-report.d.ts +2 -0
  389. package/dist/modes/session-report.js +101 -105
  390. package/dist/modes/startup-ui-text.js +11 -6
  391. package/dist/permissions/bypass.d.ts +8 -10
  392. package/dist/permissions/bypass.js +19 -10
  393. package/dist/permissions/memory-class.d.ts +23 -0
  394. package/dist/permissions/memory-class.js +54 -0
  395. package/dist/permissions/modes.d.ts +3 -3
  396. package/dist/permissions/modes.js +21 -16
  397. package/dist/permissions/pipeline.d.ts +1 -1
  398. package/dist/permissions/pipeline.js +9 -2
  399. package/dist/permissions/preview.js +49 -42
  400. package/dist/permissions/rules.js +5 -2
  401. package/dist/permissions/types.d.ts +4 -0
  402. package/dist/plan/store.js +2 -1
  403. package/dist/rpc.d.ts +39 -1
  404. package/dist/rpc.js +3 -0
  405. package/dist/sandbox/bash.js +11 -8
  406. package/dist/sandbox/detect.js +14 -11
  407. package/dist/sdk.d.ts +17 -1
  408. package/dist/sdk.js +29 -7
  409. package/dist/session/export.js +31 -30
  410. package/dist/session/manager.d.ts +1 -1
  411. package/dist/session/manager.js +5 -3
  412. package/dist/session/reuse.js +5 -4
  413. package/dist/session/scan.js +3 -2
  414. package/dist/session/stats-aggregate.d.ts +3 -1
  415. package/dist/session/stats-aggregate.js +5 -1
  416. package/dist/session/stats-index.js +2 -1
  417. package/dist/session/stats-scan.d.ts +4 -1
  418. package/dist/session/stats-scan.js +6 -2
  419. package/dist/session/store.d.ts +11 -0
  420. package/dist/session/store.js +48 -1
  421. package/dist/session/types.d.ts +2 -0
  422. package/dist/skills/builtin.js +2 -1
  423. package/dist/tools/image-file.d.ts +26 -1
  424. package/dist/tools/image-file.js +55 -13
  425. package/dist/tools/presets.d.ts +14 -1
  426. package/dist/tools/presets.js +3 -3
  427. package/dist/tools/registry.js +1 -1
  428. package/dist/tools/truncate.d.ts +1 -1
  429. package/dist/tools/truncate.js +2 -2
  430. package/dist/tools/types.d.ts +17 -1
  431. package/dist/trace/build-index.d.ts +91 -0
  432. package/dist/trace/build-index.js +127 -0
  433. package/dist/trace/build-nodes.d.ts +24 -0
  434. package/dist/trace/build-nodes.js +279 -0
  435. package/dist/trace/build-util.d.ts +43 -0
  436. package/dist/trace/build-util.js +120 -0
  437. package/dist/trace/build.d.ts +82 -0
  438. package/dist/trace/build.js +382 -0
  439. package/dist/trace/detail.d.ts +35 -0
  440. package/dist/trace/detail.js +205 -0
  441. package/dist/trace/flatten.d.ts +69 -0
  442. package/dist/trace/flatten.js +173 -0
  443. package/dist/trace/format.d.ts +47 -0
  444. package/dist/trace/format.js +329 -0
  445. package/dist/trace/html-template.d.ts +19 -0
  446. package/dist/trace/html-template.js +150 -0
  447. package/dist/trace/html.d.ts +104 -0
  448. package/dist/trace/html.js +292 -0
  449. package/dist/trace/preview.d.ts +29 -0
  450. package/dist/trace/preview.js +59 -0
  451. package/dist/trace/query-session.d.ts +14 -0
  452. package/dist/trace/query-session.js +38 -0
  453. package/dist/trace/query.d.ts +55 -0
  454. package/dist/trace/query.js +188 -0
  455. package/dist/trace/session.d.ts +40 -0
  456. package/dist/trace/session.js +168 -0
  457. package/dist/trace/types.d.ts +243 -0
  458. package/dist/trace/types.js +13 -0
  459. package/dist/tui/components/editor-paste.d.ts +2 -0
  460. package/dist/tui/components/editor-paste.js +6 -3
  461. package/dist/tui/components/editor.js +2 -2
  462. package/dist/tui/components/loader.d.ts +3 -0
  463. package/dist/tui/components/loader.js +14 -0
  464. package/dist/tui/components/select-list.d.ts +2 -0
  465. package/dist/tui/components/select-list.js +7 -0
  466. package/dist/tui/components/settings-list.d.ts +61 -0
  467. package/dist/tui/components/settings-list.js +135 -0
  468. package/dist/tui/keybindings.d.ts +5 -0
  469. package/dist/tui/keybindings.js +17 -5
  470. package/dist/tui.d.ts +1 -0
  471. package/dist/tui.js +2 -0
  472. package/docs/en/host-api.md +167 -0
  473. package/docs/en/permissions.md +214 -0
  474. package/docs/en/providers.md +627 -0
  475. package/docs/en/rpc.md +361 -0
  476. package/docs/en/sessions.md +219 -0
  477. package/docs/en/tui.md +534 -0
  478. package/docs/host-api.md +18 -17
  479. package/docs/memory.md +172 -0
  480. package/docs/permissions.md +2 -2
  481. package/docs/providers.md +73 -1
  482. package/docs/rpc.md +31 -3
  483. package/docs/session-format.md +8 -2
  484. package/docs/sessions.md +29 -1
  485. package/docs/tui.md +140 -4
  486. package/package.json +8 -3
@@ -10,11 +10,20 @@
10
10
  * auth.json 的 `apiKey` 以 `!` 开头 = 执行命令取值(stdout 去首尾空白;超时 10 s;空输出或
11
11
  * 非零退出视为未配置,继续找下一来源);同一命令进程内只执行一次。
12
12
  * 密钥只出现在 `resolve()` 的返回值里:warning 文案不含密钥与命令输出。
13
+ *
14
+ * [W6-O] auth.json 的 OAuth 条目(`type: "oauth"`,ChatGPT 登录)在 ②③ 的位置解析:每次从磁盘重读(绕过
15
+ * `fileCache`),临近过期经 `auth/oauth/refresh.ts` 刷新(跨进程锁),返回 `{ source: "oauth" }`,并把 token 的
16
+ * 上下文登记进 `auth/oauth/live.ts` 供协议层取账户 id、401 时强制刷新。永久失效(needsLogin)时仍返回旧 token
17
+ * 并在登记里标 needsLogin,协议层据此直接报 `auth_expired`(不发请求)。
13
18
  */
14
19
  import { exec } from "node:child_process";
15
20
  import { readFileSync, statSync } from "node:fs";
16
21
  import { homedir } from "node:os";
17
22
  import { join } from "node:path";
23
+ import { registerLiveToken } from "../../auth/oauth/live.js";
24
+ import { authExpiredError, freshOAuthEntry } from "../../auth/oauth/refresh.js";
25
+ import { readOAuthEntry } from "../../auth/oauth/token-store.js";
26
+ import { apiKeyEntry, isOAuthEntry } from "../../config/types-w6.js";
18
27
  /** 用户级配置目录:AMA_CONFIG_DIR > %APPDATA%\ama > $XDG_CONFIG_HOME/ama > ~/.config/ama。 */
19
28
  export function defaultConfigDir(env = process.env) {
20
29
  if (env["AMA_CONFIG_DIR"])
@@ -110,12 +119,61 @@ export class ApiKeyResolver {
110
119
  /** auth.json 里该供应商的条目(按 ② ③ 顺序第一个)。 */
111
120
  authEntry(providerId) {
112
121
  for (const path of this.authFiles()) {
113
- const entry = this.loadFile(path)?.providers[providerId];
122
+ const entry = apiKeyEntry(this.loadFile(path)?.providers[providerId]);
114
123
  if (entry && typeof entry.apiKey === "string")
115
124
  return { entry, path };
116
125
  }
117
126
  return undefined;
118
127
  }
128
+ /** [W6-O] 第一个给该供应商写了条目的 auth.json 若是 OAuth 条目,返回其路径。 */
129
+ oauthPath(providerId) {
130
+ for (const path of this.authFiles()) {
131
+ const raw = this.loadFile(path)?.providers[providerId];
132
+ if (raw === undefined)
133
+ continue;
134
+ return isOAuthEntry(raw) ? path : undefined;
135
+ }
136
+ return undefined;
137
+ }
138
+ register(path, providerId, entry) {
139
+ const deps = this.options.oauth ?? {};
140
+ registerLiveToken(entry.accessToken, {
141
+ provider: providerId,
142
+ flavor: entry.flavor,
143
+ accountId: entry.accountId,
144
+ planType: entry.planType,
145
+ ...(entry.needsLogin === true ? { needsLogin: true } : {}),
146
+ refresh: async () => {
147
+ const next = await freshOAuthEntry(path, providerId, deps, {
148
+ force: true,
149
+ staleToken: entry.accessToken,
150
+ });
151
+ if (next === undefined)
152
+ throw authExpiredError(providerId);
153
+ this.register(path, providerId, next);
154
+ return next.accessToken;
155
+ },
156
+ });
157
+ }
158
+ async fromOAuth(providerId, path) {
159
+ let entry;
160
+ try {
161
+ entry = await freshOAuthEntry(path, providerId, this.options.oauth ?? {});
162
+ }
163
+ catch (error) {
164
+ // 失效:用旧 token 登记 needsLogin,协议层报 auth_expired;暂时失败:先用现有 token
165
+ entry = readOAuthEntry(path, providerId);
166
+ const code = error.code;
167
+ if (entry !== undefined && code === "auth_expired")
168
+ entry = { ...entry, needsLogin: true };
169
+ else
170
+ this.warn(`${providerId}: OAuth token refresh failed (${String(code ?? "error")})`);
171
+ }
172
+ if (entry === undefined)
173
+ return undefined;
174
+ this.register(path, providerId, entry);
175
+ return { apiKey: entry.accessToken, source: "oauth", origin: path };
176
+ }
119
177
  runCommand(command, extraEnv) {
120
178
  const key = `${command}\0${JSON.stringify(extraEnv ?? {})}`;
121
179
  let pending = this.commandCache.get(key);
@@ -138,7 +196,14 @@ export class ApiKeyResolver {
138
196
  }
139
197
  async fromAuthFiles(providerId) {
140
198
  for (const path of this.authFiles()) {
141
- const entry = this.loadFile(path)?.providers[providerId];
199
+ const raw = this.loadFile(path)?.providers[providerId];
200
+ if (isOAuthEntry(raw)) {
201
+ const resolved = await this.fromOAuth(providerId, path);
202
+ if (resolved)
203
+ return resolved;
204
+ continue;
205
+ }
206
+ const entry = apiKeyEntry(raw);
142
207
  if (!entry || typeof entry.apiKey !== "string" || entry.apiKey.length === 0)
143
208
  continue;
144
209
  const value = entry.apiKey.startsWith("!")
@@ -194,6 +259,8 @@ export class ApiKeyResolver {
194
259
  return true;
195
260
  if (this.authEntry(provider.id)?.entry.apiKey)
196
261
  return true;
262
+ if (this.oauthPath(provider.id) !== undefined)
263
+ return true;
197
264
  const raw = this.options.configKeys?.[provider.id];
198
265
  if (raw && (raw.startsWith("!") || expandEnvRefs(raw, this.env) !== undefined))
199
266
  return true;
@@ -227,6 +227,33 @@ export const BUILTIN_PROVIDERS = [
227
227
  envKeys: ["TOKENHUB_API_KEY", "HUNYUAN_API_KEY", "AMA_API_KEY_TENCENT"],
228
228
  requiresApiKey: true,
229
229
  },
230
+ {
231
+ // [W6-O] ChatGPT 订阅(docs/wave6-plan.md §4、D14):`ama auth login chatgpt` 写 auth.json 的 OAuth 条目;
232
+ // 缺省渠道在组装时按条目的 flavor 定(compose-providers.ts)。模型表为空:`chatgpt/<slug>` 任意接受,
233
+ // `ama models discover chatgpt` 列出账户可用的 slug。缓存只有 prompt_cache_key(无 24h / 30m 显式缓存)。
234
+ id: "chatgpt",
235
+ name: "ChatGPT (subscription)",
236
+ api: RESPONSES,
237
+ baseUrl: "https://api.openai.com/v1",
238
+ channels: [
239
+ ch("siwc", RESPONSES, "https://api.openai.com/v1", { compat: { chatgptBackend: "siwc" } }),
240
+ ch("codex", RESPONSES, "https://chatgpt.com/backend-api/codex", {
241
+ headers: { originator: "codex_cli_rs" },
242
+ compat: { chatgptBackend: "codex" },
243
+ }),
244
+ ],
245
+ defaultChannel: "siwc",
246
+ envKeys: [],
247
+ requiresApiKey: true,
248
+ compat: {
249
+ supportsStore: true,
250
+ supportsReasoningSummary: true,
251
+ sendPromptCacheKey: true,
252
+ sendSessionAffinityHeaders: false,
253
+ supportsLongCacheRetention: false,
254
+ supportsExplicitPromptCacheMode: false,
255
+ },
256
+ },
230
257
  {
231
258
  id: "ollama",
232
259
  name: "Ollama (local)",
@@ -4,6 +4,7 @@
4
4
  */
5
5
  export const CATALOG_SOURCES = {
6
6
  anthropic: '{"version":1,"provider":"anthropic","modelsDev":"anthropic","models":[{"id":"claude-fable-5-1","thinkingLevelMap":{"off":null,"xhigh":"xhigh"},"promptCache":{"short":300,"long":3600,"minTokens":512},"compat":{"adaptiveThinking":true}},{"id":"claude-fable-5","thinkingLevelMap":{"off":null,"xhigh":"xhigh"},"promptCache":{"short":300,"long":3600,"minTokens":512},"compat":{"adaptiveThinking":true}},{"id":"claude-opus-5-5","thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":"xhigh"},"promptCache":{"short":300,"long":3600,"minTokens":512},"compat":{"adaptiveThinking":true}},{"id":"claude-opus-5","thinkingLevelMap":{"off":null,"xhigh":"xhigh"},"promptCache":{"short":300,"long":3600,"minTokens":512},"compat":{"adaptiveThinking":true}},{"id":"claude-opus-4-8","thinkingLevelMap":{"xhigh":"xhigh"},"promptCache":{"short":300,"long":3600,"minTokens":1024},"compat":{"adaptiveThinking":true}},{"id":"claude-opus-4-7","thinkingLevelMap":{"xhigh":"xhigh"},"promptCache":{"short":300,"long":3600,"minTokens":2048},"compat":{"adaptiveThinking":true}},{"id":"claude-opus-4-6","promptCache":{"short":300,"long":3600,"minTokens":4096},"compat":{"adaptiveThinking":true}},{"id":"claude-sonnet-5-5","thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":"xhigh"},"promptCache":{"short":300,"long":3600,"minTokens":512},"compat":{"adaptiveThinking":true}},{"id":"claude-sonnet-5","thinkingLevelMap":{"xhigh":"xhigh"},"promptCache":{"short":300,"long":3600,"minTokens":1024},"compat":{"adaptiveThinking":true}},{"id":"claude-sonnet-4-6","promptCache":{"short":300,"long":3600,"minTokens":1024},"compat":{"adaptiveThinking":true}},{"id":"claude-sonnet-4-5","promptCache":{"short":300,"long":3600,"minTokens":1024}},{"id":"claude-haiku-4-5","promptCache":{"short":300,"long":3600,"minTokens":4096}},{"id":"claude-opus-4-5","promptCache":{"short":300,"long":3600,"minTokens":4096}}]}',
7
+ chatgpt: '{"version":1,"provider":"chatgpt","modelsDev":false,"models":[]}',
7
8
  dashscope: '{"version":1,"provider":"dashscope","modelsDev":"alibaba-cn","models":[{"id":"qwen3.8-max","thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":null,"xhigh":"xhigh"},"compat":{"supportsReasoningEffort":true}},{"id":"qwen3.8-flash","thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":null,"xhigh":"xhigh"},"compat":{"supportsReasoningEffort":true}},{"id":"qwen3.7-max","maxTokens":131072,"compat":{"supportsReasoningEffort":false}},{"id":"qwen3.7-plus","maxTokens":65536,"compat":{"supportsReasoningEffort":false}},{"id":"qwen3.6-plus","compat":{"supportsReasoningEffort":false}},{"id":"qwen3.6-flash","compat":{"supportsReasoningEffort":false}}]}',
8
9
  deepseek: '{"version":1,"provider":"deepseek","modelsDev":"deepseek","models":[{"id":"deepseek-v4-pro","maxTokens":384000,"cost":{"input":1.32,"output":3.96,"cacheRead":0.044},"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high"},"_reason":"按官方价格页的高峰价(UTC 工作日 01–04、06–10 时)计,作上界;平峰为半价。快照价是平峰价或旧价"},{"id":"deepseek-flash","maxTokens":384000,"cost":{"input":0.3,"output":1.2,"cacheRead":0.006},"thinkingLevelMap":{"minimal":null,"low":"low","medium":null,"high":"high"},"_reason":"按官方价格页的高峰价(UTC 工作日 01–04、06–10 时)计,作上界;平峰为半价。快照价是平峰价或旧价"}]}',
9
10
  google: '{"version":1,"provider":"google","modelsDev":"google","models":[{"id":"gemini-3.8-flash","thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":null}},{"id":"gemini-3.7-flash","thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":null}},{"id":"gemini-3.5-flash","thinkingLevelMap":{"off":null,"minimal":"minimal","low":"low","medium":"medium","high":"high","xhigh":null}},{"id":"gemini-3.5-flash-lite","thinkingLevelMap":{"off":null,"minimal":"minimal","low":"low","medium":"medium","high":"high","xhigh":null}},{"id":"gemini-3.1-pro-preview","thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":null}},{"id":"gemini-3-flash-preview","thinkingLevelMap":{"off":null,"minimal":"minimal","low":"low","medium":"medium","high":"high","xhigh":null}},{"id":"gemini-2.5-pro","thinkingLevelMap":{"off":null,"minimal":128,"low":2048,"medium":8192,"high":32768}},{"id":"gemini-2.5-flash","thinkingLevelMap":{"minimal":128,"low":2048,"medium":8192,"high":24576}},{"id":"gemini-2.5-flash-lite","thinkingLevelMap":{"minimal":512,"low":2048,"medium":8192,"high":24576}}]}',
@@ -0,0 +1,48 @@
1
+ /**
2
+ * 发现得到的模型列表缓存:`<dataDir>/models/discovered/<provider>.json`。
3
+ *
4
+ * 模型表为空、接受任意 slug 的供应商(`chatgpt` 的订阅后端)在选择器里原本一个模型都看不到。
5
+ * `ama auth login chatgpt` 成功后与 `ama models discover chatgpt` 把账户可用的 slug 写进这里;组装注册表时
6
+ * (`mergeDiscoveredModels`)并入**模型表仍为空**的供应商,元数据用 models.dev(快照 ⊕ 用户刷新)补全。
7
+ * `ama auth logout chatgpt` 删掉它。只存 slug、显示名、flavor 与时间戳——没有 token、账户 id。
8
+ */
9
+ import type { Model, ProviderData } from "../types.js";
10
+ import type { ModelsDevIndex } from "./models-dev.js";
11
+ export declare const DISCOVERED_CACHE_VERSION = 1;
12
+ export interface DiscoveredCacheFile {
13
+ version: number;
14
+ provider: string;
15
+ /** ISO 时间。 */
16
+ fetchedAt: string;
17
+ /** ChatGPT 登录的 flavor(siwc / codex);其它供应商不写。 */
18
+ flavor?: string;
19
+ models: {
20
+ id: string;
21
+ name?: string;
22
+ }[];
23
+ }
24
+ /** 缓存文件位置。 */
25
+ export declare function discoveredCachePath(dataDir: string, provider: string): string;
26
+ /** 读缓存;不存在、损坏或形状不对返回 undefined(不报错,选择器给提示行)。 */
27
+ export declare function readDiscoveredCache(dataDir: string, provider: string): DiscoveredCacheFile | undefined;
28
+ /** 写缓存(先写临时文件再改名);返回路径。 */
29
+ export declare function writeDiscoveredCache(dataDir: string, provider: string, input: {
30
+ models: readonly {
31
+ id: string;
32
+ name?: string | undefined;
33
+ }[];
34
+ flavor?: string | undefined;
35
+ }, now?: number): string;
36
+ /** 删缓存;删了返回 true。 */
37
+ export declare function clearDiscoveredCache(dataDir: string, provider: string): boolean;
38
+ /** 缓存里的模型 → 注册表模型(models.dev 补元数据,补不到用自定义缺省)。 */
39
+ export declare function discoveredModels(file: DiscoveredCacheFile, provider: ProviderData, modelsDev: () => ModelsDevIndex | undefined): Model[];
40
+ /** 注册表里能追加模型的最小接口(`ProviderRegistry.addModels`)。 */
41
+ export interface DiscoveredTarget {
42
+ list(): readonly ProviderData[];
43
+ addModels(providerId: string, models: readonly Model[], source?: "discovered"): void;
44
+ }
45
+ /**
46
+ * 把缓存并入模型表为空的供应商(本地服务除外:它们每次启动现场探测)。返回并入了的供应商 id。
47
+ */
48
+ export declare function mergeDiscoveredModels(registry: DiscoveredTarget, dataDir: string, modelsDev: () => ModelsDevIndex | undefined): string[];
@@ -0,0 +1,102 @@
1
+ /**
2
+ * 发现得到的模型列表缓存:`<dataDir>/models/discovered/<provider>.json`。
3
+ *
4
+ * 模型表为空、接受任意 slug 的供应商(`chatgpt` 的订阅后端)在选择器里原本一个模型都看不到。
5
+ * `ama auth login chatgpt` 成功后与 `ama models discover chatgpt` 把账户可用的 slug 写进这里;组装注册表时
6
+ * (`mergeDiscoveredModels`)并入**模型表仍为空**的供应商,元数据用 models.dev(快照 ⊕ 用户刷新)补全。
7
+ * `ama auth logout chatgpt` 删掉它。只存 slug、显示名、flavor 与时间戳——没有 token、账户 id。
8
+ */
9
+ import { existsSync, mkdirSync, readFileSync, renameSync, rmSync, writeFileSync } from "node:fs";
10
+ import { dirname, join } from "node:path";
11
+ import { withCustomDefaults } from "./catalog.js";
12
+ import { enrichEntry } from "./enrich.js";
13
+ export const DISCOVERED_CACHE_VERSION = 1;
14
+ /** 缓存文件位置。 */
15
+ export function discoveredCachePath(dataDir, provider) {
16
+ return join(dataDir, "models", "discovered", `${provider}.json`);
17
+ }
18
+ function isEntry(value) {
19
+ if (typeof value !== "object" || value === null)
20
+ return false;
21
+ const { id, name } = value;
22
+ return typeof id === "string" && id !== "" && (name === undefined || typeof name === "string");
23
+ }
24
+ /** 读缓存;不存在、损坏或形状不对返回 undefined(不报错,选择器给提示行)。 */
25
+ export function readDiscoveredCache(dataDir, provider) {
26
+ let parsed;
27
+ try {
28
+ parsed = JSON.parse(readFileSync(discoveredCachePath(dataDir, provider), "utf8"));
29
+ }
30
+ catch {
31
+ return undefined;
32
+ }
33
+ if (typeof parsed !== "object" || parsed === null)
34
+ return undefined;
35
+ const file = parsed;
36
+ if (file.provider !== provider || !Array.isArray(file.models))
37
+ return undefined;
38
+ return {
39
+ version: typeof file.version === "number" ? file.version : DISCOVERED_CACHE_VERSION,
40
+ provider,
41
+ fetchedAt: typeof file.fetchedAt === "string" ? file.fetchedAt : "",
42
+ ...(typeof file.flavor === "string" ? { flavor: file.flavor } : {}),
43
+ models: file.models
44
+ .filter(isEntry)
45
+ .map((m) => (m.name ? { id: m.id, name: m.name } : { id: m.id })),
46
+ };
47
+ }
48
+ /** 写缓存(先写临时文件再改名);返回路径。 */
49
+ export function writeDiscoveredCache(dataDir, provider, input, now = Date.now()) {
50
+ const path = discoveredCachePath(dataDir, provider);
51
+ const file = {
52
+ version: DISCOVERED_CACHE_VERSION,
53
+ provider,
54
+ fetchedAt: new Date(now).toISOString(),
55
+ ...(input.flavor !== undefined ? { flavor: input.flavor } : {}),
56
+ models: input.models.map((m) => (m.name ? { id: m.id, name: m.name } : { id: m.id })),
57
+ };
58
+ mkdirSync(dirname(path), { recursive: true, mode: 0o700 });
59
+ const tmp = `${path}.${process.pid}.tmp`;
60
+ writeFileSync(tmp, `${JSON.stringify(file, null, 2)}\n`);
61
+ renameSync(tmp, path);
62
+ return path;
63
+ }
64
+ /** 删缓存;删了返回 true。 */
65
+ export function clearDiscoveredCache(dataDir, provider) {
66
+ const path = discoveredCachePath(dataDir, provider);
67
+ if (!existsSync(path))
68
+ return false;
69
+ rmSync(path, { force: true });
70
+ return true;
71
+ }
72
+ /** 缓存里的模型 → 注册表模型(models.dev 补元数据,补不到用自定义缺省)。 */
73
+ export function discoveredModels(file, provider, modelsDev) {
74
+ return file.models.map((m) => {
75
+ const { entry } = enrichEntry(m.name ? { id: m.id, name: m.name } : { id: m.id }, modelsDev);
76
+ const model = withCustomDefaults(entry, provider.id, provider.api);
77
+ // 只挂发现时登录的 flavor 对应的渠道(订阅后端的另一条渠道用不了,不在说明与 `@` 行里出现);
78
+ // 缓存没写 flavor 或渠道不存在时用供应商的缺省渠道
79
+ const names = (provider.channels ?? []).map((c) => c.name);
80
+ if (names.length > 0) {
81
+ const own = file.flavor !== undefined && names.includes(file.flavor) ? file.flavor : undefined;
82
+ model.channels = [own ?? provider.defaultChannel ?? names[0]];
83
+ }
84
+ return model;
85
+ });
86
+ }
87
+ /**
88
+ * 把缓存并入模型表为空的供应商(本地服务除外:它们每次启动现场探测)。返回并入了的供应商 id。
89
+ */
90
+ export function mergeDiscoveredModels(registry, dataDir, modelsDev) {
91
+ const merged = [];
92
+ for (const provider of registry.list()) {
93
+ if (provider.models.length > 0 || !provider.requiresApiKey)
94
+ continue;
95
+ const file = readDiscoveredCache(dataDir, provider.id);
96
+ if (file === undefined || file.models.length === 0)
97
+ continue;
98
+ registry.addModels(provider.id, discoveredModels(file, provider, modelsDev), "discovered");
99
+ merged.push(provider.id);
100
+ }
101
+ return merged;
102
+ }
@@ -7,6 +7,7 @@
7
7
  */
8
8
  import { catalogInherited } from "./catalog.js";
9
9
  import { ENRICHABLE_FIELDS, modelsDevFields, } from "./models-dev.js";
10
+ import { msg } from "../../i18n/index.js";
10
11
  /** 惰性取索引:只有真的要补字段时才读缓存(启动时没有自定义模型就不读约 2 MB 的缓存)。 */
11
12
  export function lazyIndex(source) {
12
13
  if (typeof source !== "function")
@@ -90,12 +91,6 @@ export function catalogMetadata(model) {
90
91
  }
91
92
  return { sources, looked: false };
92
93
  }
93
- const SOURCE_TEXT = {
94
- config: "config",
95
- catalog: "目录",
96
- "models.dev": "models.dev",
97
- default: "缺省",
98
- };
99
94
  export function sourceText(source) {
100
- return SOURCE_TEXT[source];
95
+ return msg().errors.models.source(source);
101
96
  }
@@ -0,0 +1,33 @@
1
+ /**
2
+ * 模型选择器的可见性规则(`/model`、启动选择器、`/config` 的模型项、`ama models list --enabled` 共用)。
3
+ *
4
+ * - 供应商的可用状态:本地(`requiresApiKey: false`)、有 key、OAuth 已登录、OAuth 需重新登录、没配置;
5
+ * 前三种算「已配置」,缺省只显示它们的模型。
6
+ * - `models.enabled`(用户级):`provider/model[@channel]` 或 `provider/*`;设置后只显示清单内的模型。
7
+ * 清单为空等同不设(写回时删掉这个键)。
8
+ */
9
+ import type { ProviderData, ProviderRegistryApi } from "../types.js";
10
+ export type ProviderAccess = "local" | "key" | "oauth" | "needsLogin" | "none";
11
+ /** 解析 key 判断供应商的可用状态(OAuth 条目会按需刷新,与发请求前相同)。 */
12
+ export declare function providerAccess(registry: ProviderRegistryApi, provider: ProviderData): Promise<ProviderAccess>;
13
+ export declare function accessReady(access: ProviderAccess): boolean;
14
+ /** `provider/model@channel` → 三段(模型 id 里可以有 `/`)。 */
15
+ export declare function splitEnabledRef(ref: string): {
16
+ provider: string;
17
+ model: string;
18
+ channel?: string;
19
+ } | undefined;
20
+ /**
21
+ * 清单是否包含该行:`exact` 是逐字列出(`provider/model`,渠道行要 `provider/model@channel`),
22
+ * `wildcard` 只经 `provider/*` 匹配上。
23
+ */
24
+ export declare function enabledMatch(list: readonly string[], ref: string): {
25
+ kind: "exact" | "wildcard";
26
+ pattern: string;
27
+ } | undefined;
28
+ /** 追加(去重、保持顺序)。 */
29
+ export declare function addEnabled(list: readonly string[] | undefined, refs: readonly string[]): string[];
30
+ /** 移出;移空返回 undefined(删掉键,恢复「显示全部已配置」)。 */
31
+ export declare function removeEnabled(list: readonly string[] | undefined, refs: readonly string[]): string[] | undefined;
32
+ /** 配置里的清单:非数组或空数组视为未设置。 */
33
+ export declare function enabledList(value: unknown): readonly string[] | undefined;
@@ -0,0 +1,70 @@
1
+ /**
2
+ * 模型选择器的可见性规则(`/model`、启动选择器、`/config` 的模型项、`ama models list --enabled` 共用)。
3
+ *
4
+ * - 供应商的可用状态:本地(`requiresApiKey: false`)、有 key、OAuth 已登录、OAuth 需重新登录、没配置;
5
+ * 前三种算「已配置」,缺省只显示它们的模型。
6
+ * - `models.enabled`(用户级):`provider/model[@channel]` 或 `provider/*`;设置后只显示清单内的模型。
7
+ * 清单为空等同不设(写回时删掉这个键)。
8
+ */
9
+ import { liveToken } from "../../auth/oauth/live.js";
10
+ /** 解析 key 判断供应商的可用状态(OAuth 条目会按需刷新,与发请求前相同)。 */
11
+ export async function providerAccess(registry, provider) {
12
+ if (!provider.requiresApiKey)
13
+ return "local";
14
+ const key = await registry
15
+ .resolveApiKey(provider.id)
16
+ .catch(() => ({ apiKey: undefined, source: "none" }));
17
+ if (key.apiKey === undefined)
18
+ return "none";
19
+ if (key.source !== "oauth")
20
+ return "key";
21
+ return liveToken(key.apiKey)?.needsLogin === true ? "needsLogin" : "oauth";
22
+ }
23
+ export function accessReady(access) {
24
+ return access === "local" || access === "key" || access === "oauth";
25
+ }
26
+ /** `provider/model@channel` → 三段(模型 id 里可以有 `/`)。 */
27
+ export function splitEnabledRef(ref) {
28
+ const slash = ref.indexOf("/");
29
+ if (slash <= 0 || slash === ref.length - 1)
30
+ return undefined;
31
+ const provider = ref.slice(0, slash);
32
+ const rest = ref.slice(slash + 1);
33
+ const at = rest.lastIndexOf("@");
34
+ if (at > 0)
35
+ return { provider, model: rest.slice(0, at), channel: rest.slice(at + 1) };
36
+ return { provider, model: rest };
37
+ }
38
+ /**
39
+ * 清单是否包含该行:`exact` 是逐字列出(`provider/model`,渠道行要 `provider/model@channel`),
40
+ * `wildcard` 只经 `provider/*` 匹配上。
41
+ */
42
+ export function enabledMatch(list, ref) {
43
+ if (list.includes(ref))
44
+ return { kind: "exact", pattern: ref };
45
+ const parts = splitEnabledRef(ref);
46
+ if (parts === undefined)
47
+ return undefined;
48
+ const wildcard = `${parts.provider}/*`;
49
+ return list.includes(wildcard) ? { kind: "wildcard", pattern: wildcard } : undefined;
50
+ }
51
+ /** 追加(去重、保持顺序)。 */
52
+ export function addEnabled(list, refs) {
53
+ const out = [...(list ?? [])];
54
+ for (const ref of refs)
55
+ if (!out.includes(ref))
56
+ out.push(ref);
57
+ return out;
58
+ }
59
+ /** 移出;移空返回 undefined(删掉键,恢复「显示全部已配置」)。 */
60
+ export function removeEnabled(list, refs) {
61
+ const out = (list ?? []).filter((ref) => !refs.includes(ref));
62
+ return out.length > 0 ? out : undefined;
63
+ }
64
+ /** 配置里的清单:非数组或空数组视为未设置。 */
65
+ export function enabledList(value) {
66
+ if (!Array.isArray(value))
67
+ return undefined;
68
+ const list = value.filter((x) => typeof x === "string");
69
+ return list.length > 0 ? list : undefined;
70
+ }
@@ -12,6 +12,7 @@ import { mkdirSync, readFileSync, renameSync, statSync, writeFileSync } from "no
12
12
  import { dirname, join } from "node:path";
13
13
  import { ModelsDevIndex as Index } from "./models-dev.js";
14
14
  import { buildSnapshot, builtinSnapshot, builtinSnapshotIndex, diffSnapshots, mergeSnapshot, snapshotList, snapshotMeta, } from "./models-dev-snapshot.js";
15
+ import { msg } from "../../i18n/index.js";
15
16
  export const MODELS_DEV_URL = "https://models.dev/api.json";
16
17
  export const MODELS_DEV_URL_ENV = "AMA_MODELS_DEV_URL";
17
18
  export const MODELS_DEV_FILE = "models-dev.json";
@@ -79,11 +80,11 @@ export function loadModelsDevIndex(dataDir) {
79
80
  export function describeModelsDev(dataDir) {
80
81
  const index = loadModelsDevIndex(dataDir);
81
82
  const file = readModelsDevCache(dataDir);
82
- const size = `${index.providerCount} 家供应商、${index.modelCount} 个模型`;
83
+ const m = msg().errors.models;
83
84
  const via = file !== undefined && overrideApplies(file)
84
- ? `快照 ${snapshotMeta().fetchedAt} ⊕ 刷新 ${file.fetchedAt}`
85
- : `快照 ${snapshotMeta().fetchedAt}`;
86
- return `models.dev:${via}(${size})`;
85
+ ? m.viaRefresh(snapshotMeta().fetchedAt, file.fetchedAt)
86
+ : m.viaSnapshot(snapshotMeta().fetchedAt);
87
+ return m.describe(via, index.providerCount, index.modelCount);
87
88
  }
88
89
  /** 显式联网刷新(只被 `ama models refresh` 调用):拉 api.json、按清单裁剪、写用户级覆盖。 */
89
90
  export async function refreshModelsDev(options) {
@@ -94,12 +95,12 @@ export async function refreshModelsDev(options) {
94
95
  status: "failed",
95
96
  url,
96
97
  index: before,
97
- warning: `models.dev 刷新失败(${reason}),沿用现有数据`,
98
+ warning: msg().errors.models.refreshFailed(reason),
98
99
  });
99
100
  const list = snapshotList();
100
101
  const unknown = (options.providers ?? []).filter((p) => !list.providers.includes(p));
101
102
  if (unknown.length > 0)
102
- return fail(`不在收录清单里:${unknown.join(", ")};可选 ${list.providers.join(", ")}`);
103
+ return fail(msg().errors.models.notListed(unknown.join(", "), list.providers.join(", ")));
103
104
  let fresh;
104
105
  try {
105
106
  const response = await (options.fetch ?? fetch)(url, {
@@ -134,28 +135,23 @@ export async function refreshModelsDev(options) {
134
135
  }
135
136
  /** 刷新结果的说明(命令输出用):一行状态 + 新增 / 删除 / 变化清单。 */
136
137
  export function describeRefresh(result, limit = 20) {
137
- const size = `${result.index.providerCount} 家供应商、${result.index.modelCount} 个模型`;
138
- const text = {
139
- updated: "已刷新",
140
- unchanged: "已刷新,无变化",
141
- failed: "刷新失败",
142
- };
138
+ const m = msg().errors.models;
143
139
  const lines = [
144
- `models.dev:${text[result.status]}(${size}${result.fetchedAt ? `,${result.fetchedAt}` : ""})`,
140
+ m.refreshStatus(result.status, result.index.providerCount, result.index.modelCount, result.fetchedAt),
145
141
  ];
146
- const section = (title, items) => {
142
+ const section = (kind, items) => {
147
143
  if (items.length === 0)
148
144
  return;
149
- lines.push(`${title}(${items.length}):`);
145
+ lines.push(m.section(kind, items.length));
150
146
  for (const item of items.slice(0, limit))
151
147
  lines.push(` ${item}`);
152
148
  if (items.length > limit)
153
- lines.push(` …另 ${items.length - limit} 条`);
149
+ lines.push(m.more(items.length - limit));
154
150
  };
155
151
  if (result.diff !== undefined) {
156
- section("新增", result.diff.added);
157
- section("上游删除(快照里的条目保留)", result.diff.removed);
158
- section("变化", result.diff.changed);
152
+ section("added", result.diff.added);
153
+ section("removed", result.diff.removed);
154
+ section("changed", result.diff.changed);
159
155
  }
160
156
  return lines.join("\n");
161
157
  }
@@ -7,10 +7,11 @@
7
7
  */
8
8
  import { MODELS_DEV_SOURCES } from "./models-dev-data.js";
9
9
  import { ModelsDevIndex, keepForSnapshot, trimProvider, } from "./models-dev.js";
10
+ import { msg } from "../../i18n/index.js";
10
11
  function parse(id) {
11
12
  const text = MODELS_DEV_SOURCES[id];
12
13
  if (text === undefined)
13
- throw new Error(`models.dev 快照缺少 ${id}`);
14
+ throw new Error(msg().errors.models.snapshotMissing(id));
14
15
  return JSON.parse(text);
15
16
  }
16
17
  let meta;
@@ -69,17 +70,17 @@ function isRecord(value) {
69
70
  */
70
71
  export function buildSnapshot(raw, snapshot = snapshotList(), only) {
71
72
  if (!isRecord(raw))
72
- throw new Error("api.json 顶层不是对象");
73
+ throw new Error(msg().errors.models.apiNotObject);
73
74
  const out = {};
74
75
  for (const id of only ?? snapshot.providers) {
75
76
  const provider = raw[id];
76
77
  if (!isRecord(provider))
77
- throw new Error(`api.json 缺少供应商 ${id}`);
78
+ throw new Error(msg().errors.models.apiMissingProvider(id));
78
79
  const prefixes = snapshot.prefixes?.[id];
79
80
  const trimmed = trimProvider(id, provider, (modelId, model) => keepForSnapshot(model) &&
80
81
  (prefixes === undefined || prefixes.some((p) => modelId.startsWith(`${p}/`))));
81
82
  if (Object.keys(trimmed.models).length === 0)
82
- throw new Error(`${id} 过滤后没有模型`);
83
+ throw new Error(msg().errors.models.noModelsAfterFilter(id));
83
84
  for (const model of Object.values(trimmed.models))
84
85
  delete model.tool_call;
85
86
  out[id] = trimmed;
@@ -89,7 +90,7 @@ export function buildSnapshot(raw, snapshot = snapshotList(), only) {
89
90
  function priceText(model) {
90
91
  const c = model.cost;
91
92
  return c === undefined
92
- ? "无"
93
+ ? msg().errors.models.none
93
94
  : `${c.input}/${c.output}/${c.cache_read ?? "-"}/${c.cache_write ?? "-"}`;
94
95
  }
95
96
  /** 新旧对比(与脚本摘要同一口径);只比较 `after` 里出现的供应商。 */
@@ -109,12 +110,12 @@ export function diffSnapshots(before, after) {
109
110
  const parts = [];
110
111
  for (const key of ["context", "output"]) {
111
112
  if (prev.limit?.[key] !== next.limit?.[key])
112
- parts.push(`${key} ${prev.limit?.[key] ?? "无"} → ${next.limit?.[key] ?? "无"}`);
113
+ parts.push(`${key} ${prev.limit?.[key] ?? msg().errors.models.none} → ${next.limit?.[key] ?? msg().errors.models.none}`);
113
114
  }
114
115
  if (priceText(prev) !== priceText(next))
115
116
  parts.push(`cost ${priceText(prev)} → ${priceText(next)}`);
116
117
  if (parts.length > 0)
117
- out.changed.push(`${providerId}/${id}:${parts.join(";")}`);
118
+ out.changed.push(msg().errors.models.changed(`${providerId}/${id}`, parts));
118
119
  }
119
120
  }
120
121
  out.added.sort();
@@ -8,6 +8,7 @@
8
8
  *
9
9
  * 本模块只做纯计算(不读文件、不联网);缓存与拉取在 models-dev-cache.ts。
10
10
  */
11
+ import { msg } from "../../i18n/index.js";
11
12
  /**
12
13
  * 原厂供应商(models.dev 的供应商 id,顺序即优先级)。通义在 `alibaba`、Meta 在 `meta`(Llama API
13
14
  * 在 `llama`)、智谱国际站在 `zai`、豆包在 `volcengine`、混元在 `tencent-tokenhub`;models.dev 没有
@@ -168,7 +169,7 @@ export function trimProvider(providerId, provider, keep) {
168
169
  /** 校验并裁剪 api.json:只留用到的字段;形状不对的供应商 / 模型跳过。整体不是对象抛错。 */
169
170
  export function trimModelsDev(raw) {
170
171
  if (!isRecord(raw))
171
- throw new Error("models.dev 数据不是对象");
172
+ throw new Error(msg().errors.models.notObject);
172
173
  const out = {};
173
174
  for (const [providerId, provider] of Object.entries(raw)) {
174
175
  if (!isRecord(provider) || !isRecord(provider["models"]))
@@ -322,9 +323,7 @@ export class ModelsDevIndex {
322
323
  candidates,
323
324
  };
324
325
  if (groups.size > 1) {
325
- match.warning =
326
- `${key}:models.dev 有 ${pool.length} 个条目、${groups.size} 种取值,` +
327
- `取多数(${best.length} 条:${signature(chosen.model)})`;
326
+ match.warning = msg().errors.models.consensus(key, pool.length, groups.size, best.length, signature(chosen.model));
328
327
  }
329
328
  return match;
330
329
  }
@@ -394,15 +393,6 @@ export const ENRICHABLE_FIELDS = [
394
393
  /** 匹配方式的中文说明(表格与 `models list`)。 */
395
394
  export function matchLabel(match) {
396
395
  if (match === undefined)
397
- return "未匹配";
398
- const kind = {
399
- explicit: "显式",
400
- prefix: "前缀",
401
- canonical: "原厂",
402
- vendor: "原厂",
403
- consensus: "多数",
404
- single: "唯一",
405
- };
406
- const via = match.normalized !== undefined ? `,按 ${match.normalized}` : "";
407
- return `${kind[match.kind]} ${match.ref}${via}`;
396
+ return msg().errors.models.unmatched;
397
+ return msg().errors.models.match(match.kind, match.ref, match.normalized);
408
398
  }
@@ -63,6 +63,8 @@ export declare class ProviderRegistry implements ProviderRegistryApi {
63
63
  private readonly envBaseUrls;
64
64
  /** baseUrl 指向非官方主机的内置供应商:接受目录外的 model id。 */
65
65
  private readonly relayed;
66
+ /** 模型表只来自发现缓存的供应商:表外的 id 照样合成(与空表相同)。 */
67
+ private readonly openTables;
66
68
  /** config 里写了自己 `channels` 的供应商(内置渠道不因改 baseUrl 作废)。 */
67
69
  private readonly userChannels;
68
70
  /** config 里写了供应商级 `api` 的供应商(单渠道回落时目录模型跟它走)。 */