@armadra/agent 0.6.0 → 0.6.2

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 (83) hide show
  1. package/CHANGELOG.md +43 -0
  2. package/CHANGELOG.zh-CN.md +32 -0
  3. package/dist/agent/session-settings.d.ts +4 -1
  4. package/dist/agent/session-settings.js +7 -2
  5. package/dist/ai/apis/chatgpt-backend.d.ts +7 -2
  6. package/dist/ai/apis/chatgpt-backend.js +12 -4
  7. package/dist/ai/providers/discovered-cache.d.ts +59 -0
  8. package/dist/ai/providers/discovered-cache.js +146 -0
  9. package/dist/ai/providers/model-visibility.d.ts +33 -0
  10. package/dist/ai/providers/model-visibility.js +70 -0
  11. package/dist/ai/providers/registry.d.ts +2 -0
  12. package/dist/ai/providers/registry.js +13 -7
  13. package/dist/ai/types.d.ts +5 -0
  14. package/dist/auth/chatgpt/backend-client.d.ts +11 -2
  15. package/dist/auth/chatgpt/backend-client.js +38 -6
  16. package/dist/auth/chatgpt/cli.d.ts +4 -1
  17. package/dist/auth/chatgpt/cli.js +40 -6
  18. package/dist/auth/chatgpt/follow.d.ts +16 -0
  19. package/dist/auth/chatgpt/follow.js +51 -0
  20. package/dist/auth/chatgpt/presets.d.ts +8 -0
  21. package/dist/auth/chatgpt/presets.js +12 -0
  22. package/dist/auth/testing/fake-oauth.d.ts +4 -1
  23. package/dist/auth/testing/fake-oauth.js +24 -1
  24. package/dist/bundle/ama.cjs +1663 -799
  25. package/dist/cli/compose-providers.d.ts +2 -0
  26. package/dist/cli/compose-providers.js +9 -0
  27. package/dist/cli/startup-steps.js +4 -1
  28. package/dist/cli/subcommands/config-set.js +19 -11
  29. package/dist/cli/subcommands/models-discover.d.ts +4 -1
  30. package/dist/cli/subcommands/models-discover.js +51 -3
  31. package/dist/cli/subcommands/models-enable.d.ts +13 -0
  32. package/dist/cli/subcommands/models-enable.js +145 -0
  33. package/dist/cli/subcommands/models.d.ts +2 -0
  34. package/dist/cli/subcommands/models.js +10 -2
  35. package/dist/config/json-schema.js +2 -1
  36. package/dist/config/key-docs.js +7 -1
  37. package/dist/config/schema-w5.js +9 -2
  38. package/dist/config/schema-w6.d.ts +1 -1
  39. package/dist/config/schema-w6.js +2 -1
  40. package/dist/config/settings-registry.d.ts +3 -0
  41. package/dist/config/settings-registry.js +1 -0
  42. package/dist/config/types-w5.d.ts +7 -0
  43. package/dist/config/types-w5.js +2 -0
  44. package/dist/config/types-w6.d.ts +5 -0
  45. package/dist/i18n/catalog.d.ts +50 -3
  46. package/dist/i18n/messages/auth.d.ts +16 -2
  47. package/dist/i18n/messages/auth.js +34 -2
  48. package/dist/i18n/messages/cli-help.js +4 -0
  49. package/dist/i18n/messages/config-keys.d.ts +6 -0
  50. package/dist/i18n/messages/config-keys.js +8 -2
  51. package/dist/i18n/messages/config.d.ts +8 -0
  52. package/dist/i18n/messages/config.js +2 -0
  53. package/dist/i18n/messages/errors.d.ts +1 -1
  54. package/dist/i18n/messages/interactive-startup.d.ts +0 -4
  55. package/dist/i18n/messages/interactive-startup.js +0 -4
  56. package/dist/i18n/messages/interactive.d.ts +0 -4
  57. package/dist/i18n/messages/panels.d.ts +43 -0
  58. package/dist/i18n/messages/panels.js +43 -0
  59. package/dist/i18n/messages/settings.d.ts +7 -0
  60. package/dist/i18n/messages/settings.js +7 -0
  61. package/dist/i18n/messages/subcommands-config.d.ts +2 -0
  62. package/dist/i18n/messages/subcommands-config.js +2 -0
  63. package/dist/i18n/messages/subcommands-models.d.ts +34 -0
  64. package/dist/i18n/messages/subcommands-models.js +34 -0
  65. package/dist/i18n/messages/subcommands.d.ts +28 -0
  66. package/dist/i18n/messages/subcommands.js +3 -0
  67. package/dist/modes/interactive/commands.d.ts +3 -0
  68. package/dist/modes/interactive/commands.js +18 -11
  69. package/dist/modes/interactive/config-ui.js +1 -1
  70. package/dist/modes/interactive/interactive-mode.js +2 -0
  71. package/dist/modes/interactive/model-items.d.ts +45 -0
  72. package/dist/modes/interactive/model-items.js +134 -0
  73. package/dist/modes/interactive/model-picker.d.ts +57 -0
  74. package/dist/modes/interactive/model-picker.js +191 -0
  75. package/dist/modes/interactive/startup-ui.d.ts +3 -9
  76. package/dist/modes/interactive/startup-ui.js +8 -60
  77. package/dist/tui/components/select-list.d.ts +2 -0
  78. package/dist/tui/components/select-list.js +7 -0
  79. package/docs/en/providers.md +9 -3
  80. package/docs/en/tui.md +8 -1
  81. package/docs/providers.md +27 -6
  82. package/docs/tui.md +8 -1
  83. package/package.json +1 -1
@@ -41,7 +41,7 @@ var AMA_VERSION;
41
41
  var init_version = __esm({
42
42
  "src/version.ts"() {
43
43
  "use strict";
44
- AMA_VERSION = true ? "0.6.0" : readPackageVersion();
44
+ AMA_VERSION = true ? "0.6.2" : readPackageVersion();
45
45
  }
46
46
  });
47
47
 
@@ -117,7 +117,7 @@ function agentEntry(agents, agentId) {
117
117
  const entry = agents[agentId];
118
118
  return typeof entry === "object" && !Array.isArray(entry) ? entry : void 0;
119
119
  }
120
- var STATUS_LINE_MODES, IMAGE_RESIZE_MODES, PLAN_BASH_MODES_STRICT_FIRST, PLAN_UNATTENDED_MODES, AGENTS_RESERVED_KEYS;
120
+ var STATUS_LINE_MODES, IMAGE_RESIZE_MODES, PLAN_BASH_MODES_STRICT_FIRST, PLAN_UNATTENDED_MODES, AGENTS_RESERVED_KEYS, MODELS_ENABLED_REF;
121
121
  var init_types_w5 = __esm({
122
122
  "src/config/types-w5.ts"() {
123
123
  "use strict";
@@ -126,6 +126,7 @@ var init_types_w5 = __esm({
126
126
  PLAN_BASH_MODES_STRICT_FIRST = ["deny", "readonly", "ask"];
127
127
  PLAN_UNATTENDED_MODES = ["stop", "approve"];
128
128
  AGENTS_RESERVED_KEYS = ["maxConcurrent", "sessionBudgetUsd", "dirs"];
129
+ MODELS_ENABLED_REF = /^[^/\s]+\/\S+$/;
129
130
  }
130
131
  });
131
132
 
@@ -267,6 +268,8 @@ Subcommands
267
268
  Timeline of turns, requests, tools and subagents (text / HTML / JSON)
268
269
  ama models list [--provider <id>] List models (with source and key status)
269
270
  ama models check <provider/id> Send one minimal request to check availability
271
+ ama models enable|disable <provider/model|provider/*>…
272
+ Edit the /model list (models.enabled); list --enabled shows it
270
273
  ama models discover <provider> [--probe] [--write] [--limit N]
271
274
  List models from a relay's /v1/models, probe protocols, write the config
272
275
  ama models refresh [--provider <id>] Refresh models.dev metadata into the data directory (startup stays
@@ -382,6 +385,8 @@ Exit codes: 0 ok · 1 runtime error · 2 usage error · 3 config error · 4 no u
382
385
  回合、请求、工具与子 Agent 的时间线(文本 / HTML / JSON)
383
386
  ama models list [--provider <id>] 列出模型(含来源与 key 状态)
384
387
  ama models check <provider/id> 发一次最小请求检查可用性
388
+ ama models enable|disable <provider/model|provider/*>…
389
+ 编辑 /model 的模型清单(models.enabled);list --enabled 查看
385
390
  ama models discover <provider> [--probe] [--write] [--limit N]
386
391
  从中转 /v1/models 列出模型,探测协议并写入配置
387
392
  ama models refresh [--provider <id>] 联网刷新 models.dev 元数据到数据目录(启动不联网;
@@ -902,6 +907,8 @@ Probing protocols: ${plural(count2, "model")} (${order}), at most ${plural(reque
902
907
  `,
903
908
  unavailable: "unavailable (all three protocols failed)",
904
909
  probeStopped: (reason) => `ama: probing stopped early (${reason})
910
+ `,
911
+ cached: (path) => `Model list cached at ${path}; /model shows these models
905
912
  `
906
913
  }
907
914
  };
@@ -973,21 +980,79 @@ Probing protocols: ${plural(count2, "model")} (${order}), at most ${plural(reque
973
980
  `,
974
981
  unavailable: "不可用(三种协议均失败)",
975
982
  probeStopped: (reason) => `ama: 探测提前停止(${reason})
983
+ `,
984
+ cached: (path) => `模型列表已缓存到 ${path},/model 里会列出这些模型
976
985
  `
977
986
  }
978
987
  };
979
988
  }
980
989
  });
981
990
 
982
- // src/i18n/messages/subcommands.ts
991
+ // src/i18n/messages/subcommands-models.ts
983
992
  var en5, zh5;
993
+ var init_subcommands_models = __esm({
994
+ "src/i18n/messages/subcommands-models.ts"() {
995
+ "use strict";
996
+ en5 = {
997
+ modelsEnabled: {
998
+ badRef: (ref) => `ama: ${ref} is not provider/model[@channel] or provider/*
999
+ `,
1000
+ unknownModel: (ref) => `ama: warning: ${ref} is not in the model table; written anyway (relays accept any id)
1001
+ `,
1002
+ added: (refs, path) => `Added to models.enabled: ${refs} → ${path}
1003
+ `,
1004
+ alreadyListed: (refs) => `Already in models.enabled: ${refs}
1005
+ `,
1006
+ removed: (refs, path) => `Removed from models.enabled: ${refs} → ${path}
1007
+ `,
1008
+ notListed: (refs) => `Not in models.enabled: ${refs}
1009
+ `,
1010
+ cleared: (path) => `models.enabled is empty and was removed; /model shows every configured model again → ${path}
1011
+ `,
1012
+ listHeader: (path) => `models.enabled (${path}):
1013
+ `,
1014
+ listUnset: "models.enabled is not set; /model shows the models of configured providers:\n",
1015
+ notInTable: "not in the model table",
1016
+ nothing: " (none)\n"
1017
+ }
1018
+ };
1019
+ zh5 = {
1020
+ modelsEnabled: {
1021
+ badRef: (ref) => `ama: ${ref} 不是 provider/model[@channel] 或 provider/*
1022
+ `,
1023
+ unknownModel: (ref) => `ama: 警告:${ref} 不在模型表里,照样写入(中转站接受任意 id)
1024
+ `,
1025
+ added: (refs, path) => `已加入 models.enabled:${refs} → ${path}
1026
+ `,
1027
+ alreadyListed: (refs) => `已在 models.enabled 里:${refs}
1028
+ `,
1029
+ removed: (refs, path) => `已移出 models.enabled:${refs} → ${path}
1030
+ `,
1031
+ notListed: (refs) => `不在 models.enabled 里:${refs}
1032
+ `,
1033
+ cleared: (path) => `models.enabled 已清空并删除,/model 恢复显示全部已配置的模型 → ${path}
1034
+ `,
1035
+ listHeader: (path) => `models.enabled(${path}):
1036
+ `,
1037
+ listUnset: "未设置 models.enabled;/model 显示已配置供应商的模型:\n",
1038
+ notInTable: "不在模型表里",
1039
+ nothing: " (无)\n"
1040
+ }
1041
+ };
1042
+ }
1043
+ });
1044
+
1045
+ // src/i18n/messages/subcommands.ts
1046
+ var en6, zh6;
984
1047
  var init_subcommands = __esm({
985
1048
  "src/i18n/messages/subcommands.ts"() {
986
1049
  "use strict";
987
1050
  init_format();
988
1051
  init_subcommands_config();
989
- en5 = {
1052
+ init_subcommands_models();
1053
+ en6 = {
990
1054
  ...en4,
1055
+ ...en5,
991
1056
  /** 多个子命令共用。 */
992
1057
  common: {
993
1058
  warning: (text) => `ama: warning: ${text}
@@ -1238,8 +1303,9 @@ Estimated cost: ${estimate} (2 × ${tokens} tokens × catalog price)
1238
1303
  `
1239
1304
  }
1240
1305
  };
1241
- zh5 = {
1306
+ zh6 = {
1242
1307
  ...zh4,
1308
+ ...zh5,
1243
1309
  common: {
1244
1310
  warning: (text) => `ama: 警告:${text}
1245
1311
  `,
@@ -1505,12 +1571,12 @@ function zhWhy(why) {
1505
1571
  if (why.kind === "hook") return `(${why.reason})`;
1506
1572
  return `(Auto ${why.layer}:${why.reason})`;
1507
1573
  }
1508
- var en6, zh6;
1574
+ var en7, zh7;
1509
1575
  var init_interactive_line = __esm({
1510
1576
  "src/i18n/messages/interactive-line.ts"() {
1511
1577
  "use strict";
1512
1578
  init_format();
1513
- en6 = {
1579
+ en7 = {
1514
1580
  approvalOrigin: (task, title, where) => `${task}Allow ${title}${where !== void 0 ? ` ${where}` : ""}? [y allow / a allow all this session / N deny] `,
1515
1581
  approvalFirstRun: (task, note) => `${task}${note} Allow? [y allow / N deny] `,
1516
1582
  approvalTool: (task, tool, summary2, why) => `${task}Allow ${tool}${summary2 !== "" ? ` ${summary2}` : ""}${enWhy(why)}? [y allow / a allow all this session / N deny] `,
@@ -1532,7 +1598,7 @@ var init_interactive_line = __esm({
1532
1598
  steer: (text) => `↳ steer: ${text}`,
1533
1599
  pasteMarker: (id, lines2) => `[paste #${id} +${plural(lines2, "line")}]`
1534
1600
  };
1535
- zh6 = {
1601
+ zh7 = {
1536
1602
  approvalOrigin: (task, title, where) => `${task}允许 ${title}${where !== void 0 ? ` ${where}` : ""}?[y 允许 / a 本会话都允许 / N 拒绝] `,
1537
1603
  approvalFirstRun: (task, note) => `${task}${note} 允许?[y 允许 / N 拒绝] `,
1538
1604
  approvalTool: (task, tool, summary2, why) => `${task}允许 ${tool}${summary2 !== "" ? ` ${summary2}` : ""}${zhWhy(why)}?[y 允许 / a 本会话都允许 / N 拒绝] `,
@@ -1558,12 +1624,12 @@ var init_interactive_line = __esm({
1558
1624
  });
1559
1625
 
1560
1626
  // src/i18n/messages/interactive-startup.ts
1561
- var en7, zh7;
1627
+ var en8, zh8;
1562
1628
  var init_interactive_startup = __esm({
1563
1629
  "src/i18n/messages/interactive-startup.ts"() {
1564
1630
  "use strict";
1565
1631
  init_format();
1566
- en7 = {
1632
+ en8 = {
1567
1633
  header: {
1568
1634
  trusted: "trusted",
1569
1635
  untrusted: "untrusted",
@@ -1588,8 +1654,6 @@ var init_interactive_startup = __esm({
1588
1654
  hintFilter: (arrows) => `type to filter · ${arrows} select · Enter confirm · Esc cancel`,
1589
1655
  hintNumbers: (arrows, n) => `${arrows} select · Enter confirm · 1-${n} pick · Esc cancel`,
1590
1656
  hint: (arrows) => `${arrows} select · Enter confirm · Esc cancel`,
1591
- local: "local",
1592
- noKey: "no key",
1593
1657
  justNow: "just now",
1594
1658
  minutesAgo: (n) => `${n}m ago`,
1595
1659
  hoursAgo: (n) => `${n}h ago`,
@@ -1611,7 +1675,7 @@ var init_interactive_startup = __esm({
1611
1675
  cwdNotDir: (path) => `Not a directory: ${path}`
1612
1676
  }
1613
1677
  };
1614
- zh7 = {
1678
+ zh8 = {
1615
1679
  header: {
1616
1680
  trusted: "已信任",
1617
1681
  untrusted: "未信任",
@@ -1636,8 +1700,6 @@ var init_interactive_startup = __esm({
1636
1700
  hintFilter: (arrows) => `输入过滤 · ${arrows} 选择 · Enter 确认 · Esc 取消`,
1637
1701
  hintNumbers: (arrows, n) => `${arrows} 选择 · Enter 确认 · 1-${n} 直接选 · Esc 取消`,
1638
1702
  hint: (arrows) => `${arrows} 选择 · Enter 确认 · Esc 取消`,
1639
- local: "本地",
1640
- noKey: "无 key",
1641
1703
  justNow: "刚刚",
1642
1704
  minutesAgo: (n) => `${n} 分钟前`,
1643
1705
  hoursAgo: (n) => `${n} 小时前`,
@@ -1663,12 +1725,12 @@ var init_interactive_startup = __esm({
1663
1725
  });
1664
1726
 
1665
1727
  // src/i18n/messages/interactive-view.ts
1666
- var en8, zh8;
1728
+ var en9, zh9;
1667
1729
  var init_interactive_view = __esm({
1668
1730
  "src/i18n/messages/interactive-view.ts"() {
1669
1731
  "use strict";
1670
1732
  init_format();
1671
- en8 = {
1733
+ en9 = {
1672
1734
  message: {
1673
1735
  /** 退出摘要的时长:不足 1 分钟按秒,否则按分钟。 */
1674
1736
  duration: (seconds2) => seconds2 < 60 ? `${seconds2}s` : `${Math.round(seconds2 / 60)} min`,
@@ -1735,7 +1797,7 @@ var init_interactive_view = __esm({
1735
1797
  earlierCalls: (ellipsis, n) => `${ellipsis} ${plural(n, "earlier call")}`
1736
1798
  }
1737
1799
  };
1738
- zh8 = {
1800
+ zh9 = {
1739
1801
  message: {
1740
1802
  duration: (seconds2) => seconds2 < 60 ? `${seconds2} 秒` : `${Math.round(seconds2 / 60)} 分钟`,
1741
1803
  sessionPrefix: (rule) => `${rule} 会话 `,
@@ -1805,7 +1867,7 @@ var init_interactive_view = __esm({
1805
1867
  });
1806
1868
 
1807
1869
  // src/i18n/messages/interactive.ts
1808
- var en9, zh9;
1870
+ var en10, zh10;
1809
1871
  var init_interactive = __esm({
1810
1872
  "src/i18n/messages/interactive.ts"() {
1811
1873
  "use strict";
@@ -1813,7 +1875,7 @@ var init_interactive = __esm({
1813
1875
  init_interactive_line();
1814
1876
  init_interactive_startup();
1815
1877
  init_interactive_view();
1816
- en9 = {
1878
+ en10 = {
1817
1879
  commands: {
1818
1880
  /** [W6-C0] 第六波命令登记了但本构建还没有实现。 */
1819
1881
  unavailable: (name) => `/${name} is not available in this build yet`,
@@ -1929,11 +1991,11 @@ var init_interactive = __esm({
1929
1991
  editor: {
1930
1992
  completionFooter: "Tab accept · Esc close"
1931
1993
  },
1932
- view: en8,
1933
- startup: en7,
1934
- line: en6
1994
+ view: en9,
1995
+ startup: en8,
1996
+ line: en7
1935
1997
  };
1936
- zh9 = {
1998
+ zh10 = {
1937
1999
  commands: {
1938
2000
  unavailable: (name) => `/${name} 当前版本尚未提供`,
1939
2001
  treeDescription: "浏览会话树,回到某条消息之前重写",
@@ -2044,20 +2106,20 @@ var init_interactive = __esm({
2044
2106
  editor: {
2045
2107
  completionFooter: "Tab 接受 · Esc 关闭"
2046
2108
  },
2047
- view: zh8,
2048
- startup: zh7,
2049
- line: zh6
2109
+ view: zh9,
2110
+ startup: zh8,
2111
+ line: zh7
2050
2112
  };
2051
2113
  }
2052
2114
  });
2053
2115
 
2054
2116
  // src/i18n/messages/approval.ts
2055
- var en10, zh10;
2117
+ var en11, zh11;
2056
2118
  var init_approval = __esm({
2057
2119
  "src/i18n/messages/approval.ts"() {
2058
2120
  "use strict";
2059
2121
  init_format();
2060
- en10 = {
2122
+ en11 = {
2061
2123
  /** 外部 Agent 来源标注:`[claude · session abc12345]`。 */
2062
2124
  originLabel: (agent, sessionId) => `[${agent} · session ${sessionId}]`,
2063
2125
  /** 标题里的原因。 */
@@ -2105,7 +2167,7 @@ var init_approval = __esm({
2105
2167
  /** 通用确认框的按键行。 */
2106
2168
  choiceHint: (arrows, n) => `${arrows} select · Enter confirm · 1-${n} pick · Esc cancel`
2107
2169
  };
2108
- zh10 = {
2170
+ zh11 = {
2109
2171
  originLabel: (agent, sessionId) => `[${agent} · 会话 ${sessionId}]`,
2110
2172
  title: {
2111
2173
  firstRun: "首次运行外部 Agent",
@@ -2152,12 +2214,12 @@ var init_approval = __esm({
2152
2214
  });
2153
2215
 
2154
2216
  // src/i18n/messages/plan.ts
2155
- var en11, zh11;
2217
+ var en12, zh12;
2156
2218
  var init_plan = __esm({
2157
2219
  "src/i18n/messages/plan.ts"() {
2158
2220
  "use strict";
2159
2221
  init_format();
2160
- en11 = {
2222
+ en12 = {
2161
2223
  usage: "Usage: /plan [goal] | /plan approve [mode|fresh] | /plan reject",
2162
2224
  status: {
2163
2225
  proposed: "awaiting approval",
@@ -2214,7 +2276,7 @@ var init_plan = __esm({
2214
2276
  rejectedStay: (version) => `Rejected plan v${version} (still in Plan mode; /plan to view)`
2215
2277
  }
2216
2278
  };
2217
- zh11 = {
2279
+ zh12 = {
2218
2280
  usage: "用法:/plan [目标] | /plan approve [模式|fresh] | /plan reject",
2219
2281
  status: {
2220
2282
  proposed: "待审批",
@@ -2275,7 +2337,7 @@ var init_plan = __esm({
2275
2337
  });
2276
2338
 
2277
2339
  // src/i18n/messages/rewind.ts
2278
- var EN_SKIP, ZH_SKIP, en12, zh12;
2340
+ var EN_SKIP, ZH_SKIP, en13, zh13;
2279
2341
  var init_rewind = __esm({
2280
2342
  "src/i18n/messages/rewind.ts"() {
2281
2343
  "use strict";
@@ -2300,7 +2362,7 @@ var init_rewind = __esm({
2300
2362
  conflict: "冲突",
2301
2363
  failed: "失败"
2302
2364
  };
2303
- en12 = {
2365
+ en13 = {
2304
2366
  skip: {
2305
2367
  reason: (code) => EN_SKIP[code],
2306
2368
  failed: (message) => `failed: ${message}`,
@@ -2395,7 +2457,7 @@ var init_rewind = __esm({
2395
2457
  fileReason: (reason) => `: ${reason}`
2396
2458
  }
2397
2459
  };
2398
- zh12 = {
2460
+ zh13 = {
2399
2461
  skip: {
2400
2462
  reason: (code) => ZH_SKIP[code],
2401
2463
  failed: (message) => `失败:${message}`,
@@ -2492,12 +2554,12 @@ var init_rewind = __esm({
2492
2554
  });
2493
2555
 
2494
2556
  // src/i18n/messages/panels.ts
2495
- var en13, zh13;
2557
+ var en14, zh14;
2496
2558
  var init_panels = __esm({
2497
2559
  "src/i18n/messages/panels.ts"() {
2498
2560
  "use strict";
2499
2561
  init_format();
2500
- en13 = {
2562
+ en14 = {
2501
2563
  session: {
2502
2564
  title: (id) => `Session ${id}`,
2503
2565
  notSaved: "not saved",
@@ -2539,6 +2601,28 @@ var init_panels = __esm({
2539
2601
  thinkingUnsupported: "The current model does not support thinking",
2540
2602
  emptyText: "(empty)"
2541
2603
  },
2604
+ /** 模型选择器(`/model`、启动选择器、`/config` 的模型项)。 */
2605
+ model: {
2606
+ local: "local",
2607
+ key: "key ✓",
2608
+ oauth: "signed in ✓",
2609
+ needsLogin: "sign in again",
2610
+ noKey: "no key configured",
2611
+ current: "current",
2612
+ listed: "listed",
2613
+ otherChannels: (names) => `also ${names}`,
2614
+ discoverHint: (provider) => `Run ama models discover ${provider} to list its models`,
2615
+ loginHint: (provider) => `Run ama auth login ${provider} to sign in`,
2616
+ footerConfigured: "Tab all · Space list · @ channels · Enter switch · Esc cancel",
2617
+ footerAll: "Tab configured · Space list · @ channels · Enter switch · Esc cancel",
2618
+ emptyConfigured: "(no configured models; Tab shows all)",
2619
+ added: (ref) => `Added ${ref} to models.enabled`,
2620
+ addedFirst: (ref) => `Added ${ref} to models.enabled; /model now shows only listed models (Tab shows all)`,
2621
+ removed: (ref) => `Removed ${ref} from models.enabled`,
2622
+ wildcard: (ref, pattern) => `${ref} is listed through ${pattern}; remove it with ama models disable ${pattern}`,
2623
+ noKeyHint: (provider) => `${provider} has no key: run ama auth set ${provider} (custom providers: ama providers add)`,
2624
+ needsLoginHint: (provider) => `${provider} needs a new sign-in: run ama auth login ${provider}`
2625
+ },
2542
2626
  plan: {
2543
2627
  title: "Plan",
2544
2628
  titleVersion: (version) => `Plan v${version}`,
@@ -2586,7 +2670,7 @@ var init_panels = __esm({
2586
2670
  title: (id) => `Task ${id}`
2587
2671
  }
2588
2672
  };
2589
- zh13 = {
2673
+ zh14 = {
2590
2674
  session: {
2591
2675
  title: (id) => `会话 ${id}`,
2592
2676
  notSaved: "未落盘",
@@ -2628,6 +2712,27 @@ var init_panels = __esm({
2628
2712
  thinkingUnsupported: "当前模型不支持思考",
2629
2713
  emptyText: "(空)"
2630
2714
  },
2715
+ model: {
2716
+ local: "本地",
2717
+ key: "key ✓",
2718
+ oauth: "已登录 ✓",
2719
+ needsLogin: "需重新登录",
2720
+ noKey: "未配置 key",
2721
+ current: "当前",
2722
+ listed: "清单内",
2723
+ otherChannels: (names) => `另有 ${names}`,
2724
+ discoverHint: (provider) => `运行 ama models discover ${provider} 获取模型`,
2725
+ loginHint: (provider) => `运行 ama auth login ${provider} 登录`,
2726
+ footerConfigured: "Tab 全部 · Space 清单 · @ 渠道 · Enter 切换 · Esc 取消",
2727
+ footerAll: "Tab 已配置 · Space 清单 · @ 渠道 · Enter 切换 · Esc 取消",
2728
+ emptyConfigured: "(没有已配置的模型,Tab 看全部)",
2729
+ added: (ref) => `已把 ${ref} 加入 models.enabled`,
2730
+ addedFirst: (ref) => `已把 ${ref} 加入 models.enabled;/model 之后只显示清单内的模型(Tab 看全部)`,
2731
+ removed: (ref) => `已把 ${ref} 移出 models.enabled`,
2732
+ wildcard: (ref, pattern) => `${ref} 经 ${pattern} 列入清单;用 ama models disable ${pattern} 移除`,
2733
+ noKeyHint: (provider) => `${provider} 未配置 key:运行 ama auth set ${provider}(自定义供应商用 ama providers add)`,
2734
+ needsLoginHint: (provider) => `${provider} 需要重新登录:运行 ama auth login ${provider}`
2735
+ },
2631
2736
  plan: {
2632
2737
  title: "计划",
2633
2738
  titleVersion: (version) => `计划 v${version}`,
@@ -2679,7 +2784,7 @@ var init_panels = __esm({
2679
2784
  });
2680
2785
 
2681
2786
  // src/i18n/messages/permissions.ts
2682
- var EN_VERB, ZH_VERB, EN_NOTE, ZH_NOTE, en14, zh14;
2787
+ var EN_VERB, ZH_VERB, EN_NOTE, ZH_NOTE, en15, zh15;
2683
2788
  var init_permissions = __esm({
2684
2789
  "src/i18n/messages/permissions.ts"() {
2685
2790
  "use strict";
@@ -2712,7 +2817,7 @@ var init_permissions = __esm({
2712
2817
  overwritten: "(已存在,将被覆盖)",
2713
2818
  gitCleanTracked: "(计数含已跟踪文件,实际只删未跟踪的)"
2714
2819
  };
2715
- en14 = {
2820
+ en15 = {
2716
2821
  /** 六种权限模式的一行说明(`permissions/modes.ts`)。 */
2717
2822
  modeDescription: {
2718
2823
  default: "Ask before writing files or running commands",
@@ -2770,7 +2875,7 @@ var init_permissions = __esm({
2770
2875
  moreLines: (n) => `… ${plural(n, "more line")}`
2771
2876
  }
2772
2877
  };
2773
- zh14 = {
2878
+ zh15 = {
2774
2879
  modeDescription: {
2775
2880
  default: "写文件、执行命令前询问",
2776
2881
  autoEdit: "自动接受文件编辑,执行命令仍询问",
@@ -2830,12 +2935,12 @@ var init_permissions = __esm({
2830
2935
  });
2831
2936
 
2832
2937
  // src/i18n/messages/report.ts
2833
- var en15, zh15;
2938
+ var en16, zh16;
2834
2939
  var init_report = __esm({
2835
2940
  "src/i18n/messages/report.ts"() {
2836
2941
  "use strict";
2837
2942
  init_format();
2838
- en15 = {
2943
+ en16 = {
2839
2944
  /** 内置斜杠命令:`args` 只写需要翻译的占位,说明整句。 */
2840
2945
  commands: {
2841
2946
  help: "List commands",
@@ -3075,7 +3180,7 @@ Available: ${inactive.join(", ")}` : ""}`,
3075
3180
  userHooks: (path) => `User hooks.json: ${path}`
3076
3181
  }
3077
3182
  };
3078
- zh15 = {
3183
+ zh16 = {
3079
3184
  commands: {
3080
3185
  help: "列出命令",
3081
3186
  new: "新建会话",
@@ -3310,12 +3415,12 @@ Available: ${inactive.join(", ")}` : ""}`,
3310
3415
  });
3311
3416
 
3312
3417
  // src/i18n/messages/print.ts
3313
- var en16, zh16;
3418
+ var en17, zh17;
3314
3419
  var init_print = __esm({
3315
3420
  "src/i18n/messages/print.ts"() {
3316
3421
  "use strict";
3317
3422
  init_format();
3318
- en16 = {
3423
+ en17 = {
3319
3424
  /** `ama -p` 的 stderr。 */
3320
3425
  print: {
3321
3426
  stdinIgnored: (wait) => `ama: no piped input within ${wait}, ignored; to wait for it, end the arguments with -
@@ -3358,7 +3463,7 @@ var init_print = __esm({
3358
3463
  truncated: (length) => `…(truncated, ${plural(length, "character")} in total)`
3359
3464
  }
3360
3465
  };
3361
- zh16 = {
3466
+ zh17 = {
3362
3467
  print: {
3363
3468
  stdinIgnored: (wait) => `ama: 未在 ${wait}内收到管道输入,已忽略;需要等待请在末尾加 -
3364
3469
  `,
@@ -3402,7 +3507,7 @@ var init_print = __esm({
3402
3507
  });
3403
3508
 
3404
3509
  // src/i18n/messages/config-keys.ts
3405
- var dynamicDefaultsEn, dynamicDefaultsZh, keysEn, keysZh, en17, zh17;
3510
+ var dynamicDefaultsEn, dynamicDefaultsZh, keysEn, keysZh, en18, zh18;
3406
3511
  var init_config_keys = __esm({
3407
3512
  "src/i18n/messages/config-keys.ts"() {
3408
3513
  "use strict";
@@ -3420,6 +3525,7 @@ var init_config_keys = __esm({
3420
3525
  "subagents.defaultModel": "unset: inherit the parent session model",
3421
3526
  "models.aliases.fast": "unset: fast is treated as inherit",
3422
3527
  "models.aliases.strong": "unset: strong is treated as inherit",
3528
+ "models.enabled": "unset: /model shows every model of configured providers",
3423
3529
  fallbackModel: "unset: no fallback",
3424
3530
  "limits.maxTurns": "unset: unlimited",
3425
3531
  "limits.maxCostUsd": "unset: unlimited",
@@ -3442,6 +3548,7 @@ var init_config_keys = __esm({
3442
3548
  "subagents.defaultModel": "不设:继承父会话模型",
3443
3549
  "models.aliases.fast": "不设:fast 按 inherit 处理",
3444
3550
  "models.aliases.strong": "不设:strong 按 inherit 处理",
3551
+ "models.enabled": "不设:/model 显示已配置供应商的全部模型",
3445
3552
  fallbackModel: "不设:不回退",
3446
3553
  "limits.maxTurns": "不设:不限",
3447
3554
  "limits.maxCostUsd": "不设:不限",
@@ -3515,6 +3622,7 @@ var init_config_keys = __esm({
3515
3622
  "auth.chatgpt.clientId": "OAuth client id",
3516
3623
  "auth.chatgpt.issuer": "Authorization server (override with AMA_CHATGPT_ISSUER for tests)",
3517
3624
  "auth.chatgpt.originator": "originator request header for the codex flavor",
3625
+ "auth.chatgpt.codexClientVersion": "Codex CLI version sent as client_version when listing codex-flavor models (the backend hides models newer than it); AMA_CHATGPT_CODEX_CLIENT_VERSION overrides",
3518
3626
  "auth.chatgpt.redirectPorts": "Local callback ports, tried in order; 0 = any free port",
3519
3627
  skills: "Skills",
3520
3628
  "skills.dirs": "Extra skill directories; accumulated across levels",
@@ -3551,10 +3659,11 @@ var init_config_keys = __esm({
3551
3659
  "subagents.maxConcurrent": "Sub-sessions running at the same time",
3552
3660
  "subagents.maxPending": "Queue limit; task fails beyond it",
3553
3661
  "subagents.defaultModel": "Default sub-session model provider/model[@channel]",
3554
- models: "Model aliases; user level only (effective from wave 5 W5-G)",
3662
+ models: "Model aliases and the model picker list; user level only (effective from wave 5 W5-G)",
3555
3663
  "models.aliases": "Models that model: fast / strong in sub-agent definitions point to",
3556
3664
  "models.aliases.fast": "Model for the fast alias provider/model[@channel]",
3557
3665
  "models.aliases.strong": "Model for the strong alias provider/model[@channel]",
3666
+ "models.enabled": "Models shown by /model (provider/model[@channel], provider/* for a whole provider); unset: every model of providers with a key, a sign-in or a local server",
3558
3667
  fallbackModel: "Fallback model provider/model[@channel]: switch and retry once when retryable errors are exhausted or the model is overloaded; the next turn returns to the main model; user level only (effective from wave 5 W5-H2)",
3559
3668
  limits: "Session budget; the run ends when reached (-p exit code 8); --max-turns / --max-cost override; user level only (effective from wave 5 W5-H2)",
3560
3669
  "limits.maxTurns": "Maximum turns per run",
@@ -3632,6 +3741,7 @@ var init_config_keys = __esm({
3632
3741
  "auth.chatgpt.clientId": "OAuth 客户端 id",
3633
3742
  "auth.chatgpt.issuer": "授权服务器(测试用 AMA_CHATGPT_ISSUER 覆盖)",
3634
3743
  "auth.chatgpt.originator": "codex flavor 的 originator 请求头",
3744
+ "auth.chatgpt.codexClientVersion": "codex flavor 列模型时作为 client_version 发送的 Codex CLI 版本号(后端不给比它新的模型);AMA_CHATGPT_CODEX_CLIENT_VERSION 优先",
3635
3745
  "auth.chatgpt.redirectPorts": "本地回调端口,依次尝试;0 = 任意空闲端口",
3636
3746
  skills: "Skill",
3637
3747
  "skills.dirs": "追加的 Skill 目录;各层累加",
@@ -3668,10 +3778,11 @@ var init_config_keys = __esm({
3668
3778
  "subagents.maxConcurrent": "同时运行的子会话数",
3669
3779
  "subagents.maxPending": "排队上限,超出时 task 报错",
3670
3780
  "subagents.defaultModel": "子会话缺省模型 provider/model[@channel]",
3671
- models: "模型别名;只认用户级(第五波 W5-G 起生效)",
3781
+ models: "模型别名与模型选择器清单;只认用户级(第五波 W5-G 起生效)",
3672
3782
  "models.aliases": "子 Agent 定义里 model: fast / strong 指向的模型",
3673
3783
  "models.aliases.fast": "fast 别名的模型 provider/model[@channel]",
3674
3784
  "models.aliases.strong": "strong 别名的模型 provider/model[@channel]",
3785
+ "models.enabled": "/model 显示的模型(provider/model[@channel],provider/* 表示整个供应商);不设:已配置 key、已登录或本地可达的供应商的全部模型",
3675
3786
  fallbackModel: "回退模型 provider/model[@channel]:可重试错误用尽或过载时切换重试一次,下一回合回主模型;只认用户级(第五波 W5-H2 起生效)",
3676
3787
  limits: "会话预算,到限结束本次运行(-p 退出码 8);--max-turns / --max-cost 覆盖;只认用户级(第五波 W5-H2 起生效)",
3677
3788
  "limits.maxTurns": "一次运行最多回合数",
@@ -3684,8 +3795,8 @@ var init_config_keys = __esm({
3684
3795
  todo: "todo 工具;只认用户级(第五波 W5-F / W5-H2 起生效)",
3685
3796
  "todo.reminder": "连续 N 回合未更新且有未完成项时提醒复述;0 关闭"
3686
3797
  };
3687
- en17 = { keys: keysEn, dynamicDefaults: dynamicDefaultsEn };
3688
- zh17 = {
3798
+ en18 = { keys: keysEn, dynamicDefaults: dynamicDefaultsEn };
3799
+ zh18 = {
3689
3800
  keys: keysZh,
3690
3801
  dynamicDefaults: dynamicDefaultsZh
3691
3802
  };
@@ -3693,12 +3804,12 @@ var init_config_keys = __esm({
3693
3804
  });
3694
3805
 
3695
3806
  // src/i18n/messages/config.ts
3696
- var en18, zh18;
3807
+ var en19, zh19;
3697
3808
  var init_config = __esm({
3698
3809
  "src/i18n/messages/config.ts"() {
3699
3810
  "use strict";
3700
3811
  init_config_keys();
3701
- en18 = {
3812
+ en19 = {
3702
3813
  /** 配置校验诊断(checker.ts、schema.ts、schema-w5.ts、schema-w6.ts)。 */
3703
3814
  schema: {
3704
3815
  enumArray: (choices) => `should be an array of ${choices.join(" | ")}`,
@@ -3717,6 +3828,7 @@ var init_config = __esm({
3717
3828
  stringArray: "should be an array of strings",
3718
3829
  array: "should be an array",
3719
3830
  modelsDev: `should be "provider/model" or false`,
3831
+ modelsEnabled: `should be "provider/model[@channel]" or "provider/*"`,
3720
3832
  noChannels: "the provider has no channels",
3721
3833
  unknownChannelOf: (name, available) => `channel "${name}" does not exist (available: ${available.join(", ")})`,
3722
3834
  modelInput: `should be ("text" | "image")[]`,
@@ -3818,9 +3930,9 @@ var init_config = __esm({
3818
3930
  models: "Custom models (an entry with the same id replaces the whole model)",
3819
3931
  modelOverrides: "Only changes metadata of existing models"
3820
3932
  },
3821
- ...en17
3933
+ ...en18
3822
3934
  };
3823
- zh18 = {
3935
+ zh19 = {
3824
3936
  schema: {
3825
3937
  enumArray: (choices) => `应为 ${choices.join(" | ")} 组成的数组`,
3826
3938
  ports: "应为端口号数组(0–65535;0 = 任意空闲端口)",
@@ -3838,6 +3950,7 @@ var init_config = __esm({
3838
3950
  stringArray: "应为字符串数组",
3839
3951
  array: "应为数组",
3840
3952
  modelsDev: `应为 "provider/model" 或 false`,
3953
+ modelsEnabled: `应为 "provider/model[@channel]" 或 "provider/*"`,
3841
3954
  noChannels: "供应商没有 channels",
3842
3955
  unknownChannelOf: (name, available) => `渠道 "${name}" 不存在(可用:${available.join(", ")})`,
3843
3956
  modelInput: `应为 ("text" | "image")[]`,
@@ -3931,18 +4044,18 @@ var init_config = __esm({
3931
4044
  models: "自定义模型(同 id 整条替换)",
3932
4045
  modelOverrides: "只改已有模型的元数据"
3933
4046
  },
3934
- ...zh17
4047
+ ...zh18
3935
4048
  };
3936
4049
  }
3937
4050
  });
3938
4051
 
3939
4052
  // src/i18n/messages/drivers.ts
3940
- var en19, zh19;
4053
+ var en20, zh20;
3941
4054
  var init_drivers = __esm({
3942
4055
  "src/i18n/messages/drivers.ts"() {
3943
4056
  "use strict";
3944
4057
  init_format();
3945
- en19 = {
4058
+ en20 = {
3946
4059
  /** 外部 Agent 的 notice 与日志。 */
3947
4060
  agent: {
3948
4061
  reapedOrphans: (pids) => `cleaned up external agent processes left over from last time: ${pids}`,
@@ -4002,7 +4115,7 @@ var init_drivers = __esm({
4002
4115
  noId: (label2) => `${label2}: the adapter returned by create() has no id`
4003
4116
  }
4004
4117
  };
4005
- zh19 = {
4118
+ zh20 = {
4006
4119
  agent: {
4007
4120
  reapedOrphans: (pids) => `清理了上次遗留的外部 Agent 进程:${pids}`,
4008
4121
  unverifiedVersion: (program, version, verified) => `${program} ${version} 不在已验证区间 ${verified},协议可能有变化`,
@@ -4063,12 +4176,12 @@ var init_drivers = __esm({
4063
4176
  });
4064
4177
 
4065
4178
  // src/i18n/messages/session.ts
4066
- var en20, zh20;
4179
+ var en21, zh21;
4067
4180
  var init_session = __esm({
4068
4181
  "src/i18n/messages/session.ts"() {
4069
4182
  "use strict";
4070
4183
  init_format();
4071
- en20 = {
4184
+ en21 = {
4072
4185
  /** `ama sessions list / show / prune`(search / export / trace 各有自己的文案)。 */
4073
4186
  cli: {
4074
4187
  usage: `Usage: ama sessions list [--all] [--session-dir <dir>]
@@ -4204,7 +4317,7 @@ var init_session = __esm({
4204
4317
  }
4205
4318
  }
4206
4319
  };
4207
- zh20 = {
4320
+ zh21 = {
4208
4321
  cli: {
4209
4322
  usage: `用法:ama sessions list [--all] [--session-dir <目录>]
4210
4323
  ama sessions show <id> [--session-dir <目录>]
@@ -4337,7 +4450,7 @@ var init_session = __esm({
4337
4450
  });
4338
4451
 
4339
4452
  // src/i18n/messages/errors.ts
4340
- var EN_HINT, ZH_HINT, en21, zh21;
4453
+ var EN_HINT, ZH_HINT, en22, zh22;
4341
4454
  var init_errors2 = __esm({
4342
4455
  "src/i18n/messages/errors.ts"() {
4343
4456
  "use strict";
@@ -4352,7 +4465,7 @@ var init_errors2 = __esm({
4352
4465
  no_tool: "(没找到缩放工具:装 ImageMagick,macOS 自带 sips)",
4353
4466
  still_too_large: "(缩放后仍超限)"
4354
4467
  };
4355
- en21 = {
4468
+ en22 = {
4356
4469
  /** [W6-I3] 图片附件:当前模型不收图片(`--image` / `@路径`)。 */
4357
4470
  imageUnsupported: (model) => `${model ?? "The current model"} does not accept image input (the model's input has no image); switch to a model that supports images (marked "image" in ama models list, or give the model "input": ["text", "image"] in the config)`,
4358
4471
  /** [W6-I3] SDK(`createRuntime` / `createAgentSession`)。 */
@@ -4424,7 +4537,7 @@ var init_errors2 = __esm({
4424
4537
  }
4425
4538
  }
4426
4539
  };
4427
- zh21 = {
4540
+ zh22 = {
4428
4541
  imageUnsupported: (model) => `${model ?? "当前模型"} 不接受图片输入(模型 input 没有 image);换一个支持图像的模型再试(ama models list 里标「图片」的,或在配置里给该模型写 "input": ["text", "image"])`,
4429
4542
  cacheParamsStripped: (key, field2, suggestion) => `${key}:该端点不支持 ${field2},已自动去掉缓存参数重发;可在 config 里设 ${suggestion ?? "相应的 compat 开关"}`,
4430
4543
  sdk: {
@@ -4495,12 +4608,12 @@ var init_errors2 = __esm({
4495
4608
  });
4496
4609
 
4497
4610
  // src/i18n/messages/agents.ts
4498
- var en22, zh22;
4611
+ var en23, zh23;
4499
4612
  var init_agents = __esm({
4500
4613
  "src/i18n/messages/agents.ts"() {
4501
4614
  "use strict";
4502
4615
  init_format();
4503
- en22 = {
4616
+ en23 = {
4504
4617
  status: {
4505
4618
  queued: "queued",
4506
4619
  running: "running",
@@ -4538,7 +4651,7 @@ var init_agents = __esm({
4538
4651
  externalNoSession: (runner) => `Live output is kept only in memory; ${runner} did not report a session to resume.`
4539
4652
  }
4540
4653
  };
4541
- zh22 = {
4654
+ zh23 = {
4542
4655
  status: {
4543
4656
  queued: "排队",
4544
4657
  running: "运行中",
@@ -4580,12 +4693,12 @@ var init_agents = __esm({
4580
4693
  });
4581
4694
 
4582
4695
  // src/i18n/messages/trace.ts
4583
- var en23, zh23;
4696
+ var en24, zh24;
4584
4697
  var init_trace = __esm({
4585
4698
  "src/i18n/messages/trace.ts"() {
4586
4699
  "use strict";
4587
4700
  init_format();
4588
- en23 = {
4701
+ en24 = {
4589
4702
  title: "Trace",
4590
4703
  /** 顶部汇总行。 */
4591
4704
  summary: (turns, requests, tools) => `${plural(turns, "turn")} · ${plural(requests, "request")} · ${plural(tools, "tool call")}`,
@@ -4704,7 +4817,7 @@ var init_trace = __esm({
4704
4817
  badNow: (raw) => `--now expects epoch milliseconds (got ${raw})`
4705
4818
  }
4706
4819
  };
4707
- zh23 = {
4820
+ zh24 = {
4708
4821
  title: "轨迹",
4709
4822
  summary: (turns, requests, tools) => `${turns} 回合 · ${requests} 请求 · ${tools} 次工具`,
4710
4823
  cache: (percent2) => `缓存 ${percent2}`,
@@ -4823,12 +4936,12 @@ var init_trace = __esm({
4823
4936
  });
4824
4937
 
4825
4938
  // src/i18n/messages/memory.ts
4826
- var en24, zh24;
4939
+ var en25, zh25;
4827
4940
  var init_memory = __esm({
4828
4941
  "src/i18n/messages/memory.ts"() {
4829
4942
  "use strict";
4830
4943
  init_format();
4831
- en24 = {
4944
+ en25 = {
4832
4945
  scope: { user: "user", project: "project", workspace: "workspace" },
4833
4946
  panel: {
4834
4947
  title: "Memory",
@@ -4888,7 +5001,7 @@ var init_memory = __esm({
4888
5001
  untrusted: (cwd) => `Project scope skipped: ${cwd} is not trusted (run ama --trust there once).`
4889
5002
  }
4890
5003
  };
4891
- zh24 = {
5004
+ zh25 = {
4892
5005
  scope: { user: "用户", project: "项目", workspace: "工作空间" },
4893
5006
  panel: {
4894
5007
  title: "记忆",
@@ -4952,11 +5065,11 @@ var init_memory = __esm({
4952
5065
  });
4953
5066
 
4954
5067
  // src/i18n/messages/auth.ts
4955
- var en25, zh25;
5068
+ var en26, zh26;
4956
5069
  var init_auth = __esm({
4957
5070
  "src/i18n/messages/auth.ts"() {
4958
5071
  "use strict";
4959
- en25 = {
5072
+ en26 = {
4960
5073
  usage: `Usage: ama auth set <provider> [--auth-file <file>] read the key from stdin
4961
5074
  ama auth list [--auth-file <file>]
4962
5075
  ama auth remove <provider> [--auth-file <file>]
@@ -5002,12 +5115,22 @@ Then paste the full URL from the address bar (http://127.0.0.1:…/auth/callback
5002
5115
  loggedIn: (flavor, plan2, email, path) => `Signed in to ChatGPT (${flavor}${plan2 !== void 0 ? ` · ${plan2}` : ""}${email !== void 0 ? ` · ${email}` : ""}) → ${path} (0600)`,
5003
5116
  siwcLimitHint: "Tip: set a weekly limit for ama in ChatGPT → Settings → Usage → App limits. For personal use only; never share one sign-in between several people.",
5004
5117
  freePlanHint: (plan2) => `Note: the "${plan2}" plan may not include subscription usage for ama.`,
5005
- modelHint: "Use it with --model chatgpt/<model>; list the models your account can use with ama models discover chatgpt."
5118
+ modelHint: "Use it with --model chatgpt/<model>; list the models your account can use with ama models discover chatgpt.",
5119
+ modelsCached: (count2) => `Your account can use ${count2} model(s); pick one with /model or --model chatgpt/<model>.`,
5120
+ siwcEligibilityHint: "Whether this account can share its plan usage with ama is only confirmed on the first request.",
5121
+ codexNoModels: (version) => `The codex backend returned no models. codexClientVersion (${version}) may be too old: set a newer Codex CLI version with ama config set auth.chatgpt.codexClientVersion <version>, then run ama models discover chatgpt.`
5122
+ },
5123
+ request: {
5124
+ notEligible: "this ChatGPT account cannot share plan usage with ama (403 subscription_sharing_user_not_eligible). Possible causes:\n 1. Plan: plan usage is shared with Plus / Pro only\n 2. Workspace account: Team / Enterprise / Edu workspaces may not offer it\n 3. Region restriction, or not yet rolled out during the preview (most likely when a Pro account still gets this error)\nYou can sign in the other way instead: ama auth login chatgpt --flavor codex",
5125
+ flavorMismatch: (current3, ref, pinned) => `signed in with ${current3}, but ${ref} pins the @${pinned} channel. Drop @${pinned} so the channel follows the sign-in, or run ama auth login chatgpt --flavor ${pinned}`
5006
5126
  },
5007
5127
  errors: {
5008
5128
  portsBusy: (ports, codex) => `callback port ${ports} is in use: finish the other sign-in first, or use --paste${codex ? " / --device" : ""}`,
5009
5129
  timeout: "sign-in timed out; run the command again",
5010
- denied: (error2) => `sign-in was not authorized (${error2})`,
5130
+ denied: (error2, codexFallback) => `sign-in was not authorized (${error2}). Possible causes:
5131
+ 1. The authorization page was cancelled, or using your ChatGPT plan was not checked: run ama auth login chatgpt again and keep that option checked
5132
+ 2. The account or plan is not eligible: plan usage is shared with Plus / Pro only; Team / Enterprise workspaces may not offer it; the browser may be signed in to another account
5133
+ 3. Your region is not supported` + (codexFallback ? "\nYou can also try the fallback: ama auth login chatgpt --flavor codex" : ""),
5011
5134
  stateMismatch: "the pasted URL does not belong to this sign-in (state mismatch); start again",
5012
5135
  noCode: "the pasted URL has no code; copy the whole address after the browser redirects",
5013
5136
  invalidToken: (reason) => `id_token failed verification (${reason}); sign-in rejected`,
@@ -5053,7 +5176,7 @@ Then paste the full URL from the address bar (http://127.0.0.1:…/auth/callback
5053
5176
  relogin: (provider) => `${provider}: sign-in expired, run ama auth login ${provider}`
5054
5177
  }
5055
5178
  };
5056
- zh25 = {
5179
+ zh26 = {
5057
5180
  usage: `用法:ama auth set <provider> [--auth-file <文件>] 从 stdin 读取 key
5058
5181
  ama auth list [--auth-file <文件>]
5059
5182
  ama auth remove <provider> [--auth-file <文件>]
@@ -5099,12 +5222,22 @@ Then paste the full URL from the address bar (http://127.0.0.1:…/auth/callback
5099
5222
  loggedIn: (flavor, plan2, email, path) => `已登录 ChatGPT(${flavor}${plan2 !== void 0 ? ` · ${plan2}` : ""}${email !== void 0 ? ` · ${email}` : ""})→ ${path}(0600)`,
5100
5223
  siwcLimitHint: "提示:可在 ChatGPT → 设置 → Usage → App limits 给 ama 设周上限。仅限本人使用,不要让多人共用一个登录。",
5101
5224
  freePlanHint: (plan2) => `注意:「${plan2}」计划可能不含给 ama 用的订阅额度。`,
5102
- modelHint: "用 --model chatgpt/<模型> 使用;账户可用的模型用 ama models discover chatgpt 查看。"
5225
+ modelHint: "用 --model chatgpt/<模型> 使用;账户可用的模型用 ama models discover chatgpt 查看。",
5226
+ modelsCached: (count2) => `账户可用 ${count2} 个模型,用 /model 或 --model chatgpt/<模型> 选择。`,
5227
+ siwcEligibilityHint: "这个账户能否把套餐额度共享给 ama,要到首次请求时才能确认。",
5228
+ codexNoModels: (version) => `codex 后端没有返回模型,可能是 codexClientVersion(${version})过旧:用 ama config set auth.chatgpt.codexClientVersion <版本> 设为较新的 Codex CLI 版本,再运行 ama models discover chatgpt。`
5229
+ },
5230
+ request: {
5231
+ notEligible: "这个 ChatGPT 账户不能把套餐额度共享给 ama(403 subscription_sharing_user_not_eligible)。可能的原因:\n 1. 账户套餐:额度共享只对 Plus / Pro 开放\n 2. 工作空间账户:Team / Enterprise / Edu 工作空间可能未开放\n 3. 地区受限,或预览期尚未开放(Pro 账户仍报此错时最可能是这一条)\n可以改用另一种登录方式:ama auth login chatgpt --flavor codex",
5232
+ flavorMismatch: (current3, ref, pinned) => `当前以 ${current3} 方式登录,但 ${ref} 显式指定了 @${pinned} 渠道。去掉 @${pinned} 让渠道跟随登录方式,或运行 ama auth login chatgpt --flavor ${pinned}`
5103
5233
  },
5104
5234
  errors: {
5105
5235
  portsBusy: (ports, codex) => `回调端口 ${ports} 被占用:请先结束其它登录,或用 --paste${codex ? " / --device" : ""}`,
5106
5236
  timeout: "登录超时,请重新运行命令",
5107
- denied: (error2) => `授权未通过(${error2})`,
5237
+ denied: (error2, codexFallback) => `授权未通过(${error2})。可能的原因:
5238
+ 1. 在授权页取消了,或没有勾选使用 ChatGPT 套餐额度:重新运行 ama auth login chatgpt 并确认勾选
5239
+ 2. 账户或套餐不符合:额度共享只对 Plus / Pro 开放;Team / Enterprise 工作空间可能未开放;浏览器可能登录了别的账户
5240
+ 3. 所在地区受限` + (codexFallback ? "\n也可以改用备用方式:ama auth login chatgpt --flavor codex" : ""),
5108
5241
  stateMismatch: "粘贴的 URL 不属于这次登录(state 不符),请重新开始",
5109
5242
  noCode: "粘贴的 URL 里没有 code;请在浏览器跳转后复制完整地址",
5110
5243
  invalidToken: (reason) => `id_token 校验失败(${reason}),已拒绝这次登录`,
@@ -5154,11 +5287,11 @@ Then paste the full URL from the address bar (http://127.0.0.1:…/auth/callback
5154
5287
  });
5155
5288
 
5156
5289
  // src/i18n/messages/settings.ts
5157
- var en26, zh26;
5290
+ var en27, zh27;
5158
5291
  var init_settings = __esm({
5159
5292
  "src/i18n/messages/settings.ts"() {
5160
5293
  "use strict";
5161
- en26 = {
5294
+ en27 = {
5162
5295
  groups: {
5163
5296
  ui: "Interface",
5164
5297
  model: "Model",
@@ -5278,6 +5411,9 @@ var init_settings = __esm({
5278
5411
  setDone: (key, value, scope) => `${key} = ${value} (${scope})`,
5279
5412
  unsetDone: (key, value, scope) => `${key} reset (${scope}); now ${value}`,
5280
5413
  stillOverridden: (key, source) => `${key} is still overridden by ${source}; the saved value applies once that is removed`,
5414
+ /** `ama config set` when a higher layer hides the write: first line = what was written. */
5415
+ writtenTo: (key, value, scope) => `${key} = ${value} (written to ${scope})`,
5416
+ overriddenNow: (source, effective) => `Still overridden by ${source} (${effective}); the effective value is ${effective}`,
5281
5417
  slashUsage: "Usage: /config [key=value | key value]",
5282
5418
  errors: {
5283
5419
  unknownKey: (key) => `${key} isn't a /config setting. Run /config to see what's available.`,
@@ -5305,7 +5441,8 @@ var init_settings = __esm({
5305
5441
  sandboxWritable: "ama config set sandbox.writable --json-value",
5306
5442
  agents: "agents.<id>: ama config edit",
5307
5443
  hooks: "hooks.json · /hooks",
5308
- auth: "ama auth"
5444
+ auth: "ama auth",
5445
+ modelsEnabled: "/model (Space) · ama models enable / disable"
5309
5446
  },
5310
5447
  cli: {
5311
5448
  usage: `Usage: ama config get <key> [--json]
@@ -5323,7 +5460,7 @@ var init_settings = __esm({
5323
5460
  missingValue: "missing <value>"
5324
5461
  }
5325
5462
  };
5326
- zh26 = {
5463
+ zh27 = {
5327
5464
  groups: {
5328
5465
  ui: "界面",
5329
5466
  model: "模型",
@@ -5442,6 +5579,8 @@ var init_settings = __esm({
5442
5579
  setDone: (key, value, scope) => `${key} = ${value}(${scope})`,
5443
5580
  unsetDone: (key, value, scope) => `已恢复 ${key}(${scope}),现为 ${value}`,
5444
5581
  stillOverridden: (key, source) => `${key} 仍被 ${source} 覆盖,撤掉后写入的值才生效`,
5582
+ writtenTo: (key, value, scope) => `${key} = ${value}(已写入${scope})`,
5583
+ overriddenNow: (source, effective) => `当前仍被 ${source}(${effective})覆盖,生效值为 ${effective}`,
5445
5584
  slashUsage: "用法:/config [key=value | key value]",
5446
5585
  errors: {
5447
5586
  unknownKey: (key) => `${key} 不是可设置项,用 /config 查看`,
@@ -5469,7 +5608,8 @@ var init_settings = __esm({
5469
5608
  sandboxWritable: "ama config set sandbox.writable --json-value",
5470
5609
  agents: "agents.<id>:ama config edit",
5471
5610
  hooks: "hooks.json · /hooks",
5472
- auth: "ama auth"
5611
+ auth: "ama auth",
5612
+ modelsEnabled: "/model(Space)· ama models enable / disable"
5473
5613
  },
5474
5614
  cli: {
5475
5615
  usage: `用法:ama config get <key> [--json]
@@ -5491,7 +5631,7 @@ var init_settings = __esm({
5491
5631
  });
5492
5632
 
5493
5633
  // src/i18n/catalog.ts
5494
- var en27, zh27, CATALOGS, MESSAGE_DOMAINS;
5634
+ var en28, zh28, CATALOGS, MESSAGE_DOMAINS;
5495
5635
  var init_catalog = __esm({
5496
5636
  "src/i18n/catalog.ts"() {
5497
5637
  "use strict";
@@ -5514,50 +5654,50 @@ var init_catalog = __esm({
5514
5654
  init_memory();
5515
5655
  init_auth();
5516
5656
  init_settings();
5517
- en27 = {
5657
+ en28 = {
5518
5658
  cli: en3,
5519
- subcommands: en5,
5520
- interactive: en9,
5521
- approval: en10,
5522
- plan: en11,
5523
- rewind: en12,
5524
- panels: en13,
5525
- permissions: en14,
5526
- report: en15,
5527
- print: en16,
5528
- config: en18,
5529
- drivers: en19,
5530
- session: en20,
5531
- errors: en21,
5532
- agents: en22,
5533
- trace: en23,
5534
- memory: en24,
5535
- auth: en25,
5536
- settings: en26
5537
- };
5538
- zh27 = {
5659
+ subcommands: en6,
5660
+ interactive: en10,
5661
+ approval: en11,
5662
+ plan: en12,
5663
+ rewind: en13,
5664
+ panels: en14,
5665
+ permissions: en15,
5666
+ report: en16,
5667
+ print: en17,
5668
+ config: en19,
5669
+ drivers: en20,
5670
+ session: en21,
5671
+ errors: en22,
5672
+ agents: en23,
5673
+ trace: en24,
5674
+ memory: en25,
5675
+ auth: en26,
5676
+ settings: en27
5677
+ };
5678
+ zh28 = {
5539
5679
  cli: zh3,
5540
- subcommands: zh5,
5541
- interactive: zh9,
5542
- approval: zh10,
5543
- plan: zh11,
5544
- rewind: zh12,
5545
- panels: zh13,
5546
- permissions: zh14,
5547
- report: zh15,
5548
- print: zh16,
5549
- config: zh18,
5550
- drivers: zh19,
5551
- session: zh20,
5552
- errors: zh21,
5553
- agents: zh22,
5554
- trace: zh23,
5555
- memory: zh24,
5556
- auth: zh25,
5557
- settings: zh26
5558
- };
5559
- CATALOGS = { en: en27, zh: zh27 };
5560
- MESSAGE_DOMAINS = Object.keys(en27);
5680
+ subcommands: zh6,
5681
+ interactive: zh10,
5682
+ approval: zh11,
5683
+ plan: zh12,
5684
+ rewind: zh13,
5685
+ panels: zh14,
5686
+ permissions: zh15,
5687
+ report: zh16,
5688
+ print: zh17,
5689
+ config: zh19,
5690
+ drivers: zh20,
5691
+ session: zh21,
5692
+ errors: zh22,
5693
+ agents: zh23,
5694
+ trace: zh24,
5695
+ memory: zh25,
5696
+ auth: zh26,
5697
+ settings: zh27
5698
+ };
5699
+ CATALOGS = { en: en28, zh: zh28 };
5700
+ MESSAGE_DOMAINS = Object.keys(en28);
5561
5701
  }
5562
5702
  });
5563
5703
 
@@ -6192,7 +6332,14 @@ function validateConfigW5(c, config) {
6192
6332
  c.number(s2, "maxPending", p, 0, 1024);
6193
6333
  c.string(s2, "defaultModel", p);
6194
6334
  });
6195
- checkSection(c, config, "models", ["aliases"], (s2, p) => {
6335
+ checkSection(c, config, "models", ["aliases", "enabled"], (s2, p) => {
6336
+ c.stringArray(s2, "enabled", p);
6337
+ const enabled = s2["enabled"];
6338
+ if (Array.isArray(enabled))
6339
+ enabled.forEach((ref, i) => {
6340
+ if (typeof ref === "string" && !MODELS_ENABLED_REF.test(ref))
6341
+ c.error(join(join(p, "enabled"), i), msg().config.schema.modelsEnabled);
6342
+ });
6196
6343
  const aliases = s2["aliases"];
6197
6344
  const ap = join(p, "aliases");
6198
6345
  if (aliases === void 0 || !c.object(aliases, ap)) return;
@@ -6277,7 +6424,8 @@ function validateConfigW6(c, config) {
6277
6424
  if (chatgpt === void 0 || !c.object(chatgpt, cp)) return;
6278
6425
  c.keys(chatgpt, cp, CHATGPT_AUTH_KEYS);
6279
6426
  c.oneOf(chatgpt, "flavor", cp, CHATGPT_FLAVORS);
6280
- for (const key of ["clientId", "issuer", "originator"]) c.string(chatgpt, key, cp);
6427
+ for (const key of ["clientId", "issuer", "originator", "codexClientVersion"])
6428
+ c.string(chatgpt, key, cp);
6281
6429
  checkPorts(c, chatgpt, "redirectPorts", cp);
6282
6430
  });
6283
6431
  }
@@ -6344,6 +6492,7 @@ var init_schema_w6 = __esm({
6344
6492
  "clientId",
6345
6493
  "issuer",
6346
6494
  "originator",
6495
+ "codexClientVersion",
6347
6496
  "redirectPorts"
6348
6497
  ];
6349
6498
  }
@@ -9185,12 +9334,12 @@ function editDistance(a, b) {
9185
9334
  if (b.length === 0) return a.length;
9186
9335
  let prev = Array.from({ length: b.length + 1 }, (_, i) => i);
9187
9336
  for (let i = 1; i <= a.length; i++) {
9188
- const row2 = [i];
9337
+ const row3 = [i];
9189
9338
  for (let j = 1; j <= b.length; j++) {
9190
9339
  const cost2 = a[i - 1] === b[j - 1] ? 0 : 1;
9191
- row2[j] = Math.min((prev[j] ?? 0) + 1, (row2[j - 1] ?? 0) + 1, (prev[j - 1] ?? 0) + cost2);
9340
+ row3[j] = Math.min((prev[j] ?? 0) + 1, (row3[j - 1] ?? 0) + 1, (prev[j - 1] ?? 0) + cost2);
9192
9341
  }
9193
- prev = row2;
9342
+ prev = row3;
9194
9343
  }
9195
9344
  return prev[b.length] ?? 0;
9196
9345
  }
@@ -9562,6 +9711,113 @@ var init_channels = __esm({
9562
9711
  }
9563
9712
  });
9564
9713
 
9714
+ // src/auth/chatgpt/presets.ts
9715
+ function nonEmpty2(value) {
9716
+ const trimmed = value?.trim();
9717
+ return trimmed === void 0 || trimmed === "" ? void 0 : trimmed;
9718
+ }
9719
+ function chatgptBaseUrl(flavor, env = process.env) {
9720
+ return nonEmpty2(env["AMA_CHATGPT_BASE_URL"]) ?? CHATGPT_BASE_URLS[flavor];
9721
+ }
9722
+ function codexClientVersion(config, env = process.env) {
9723
+ return nonEmpty2(env["AMA_CHATGPT_CODEX_CLIENT_VERSION"]) ?? nonEmpty2(config?.codexClientVersion) ?? DEFAULT_CODEX_CLIENT_VERSION;
9724
+ }
9725
+ function resolveChatGptPreset(flavor, overrides = {}) {
9726
+ const env = overrides.env ?? process.env;
9727
+ const config = overrides.config;
9728
+ const issuer = (nonEmpty2(env["AMA_CHATGPT_ISSUER"]) ?? nonEmpty2(config?.issuer) ?? DEFAULT_ISSUER).replace(/\/+$/, "");
9729
+ const sameFlavor = overrides.entry?.flavor === flavor ? overrides.entry : void 0;
9730
+ const explicitClient = nonEmpty2(env["AMA_CHATGPT_CLIENT_ID"]) ?? nonEmpty2(config?.clientId);
9731
+ const ports = overrides.port !== void 0 ? [overrides.port] : config?.redirectPorts !== void 0 && config.redirectPorts.length > 0 ? [...config.redirectPorts] : void 0;
9732
+ if (flavor === "siwc") {
9733
+ const issued = sameFlavor?.clientId !== SIWC_REGISTRATION_CLIENT_ID ? sameFlavor?.clientId : void 0;
9734
+ const clientId = explicitClient ?? issued ?? SIWC_REGISTRATION_CLIENT_ID;
9735
+ return {
9736
+ flavor,
9737
+ issuer,
9738
+ clientId,
9739
+ registering: clientId === SIWC_REGISTRATION_CLIENT_ID,
9740
+ authorizeUrl: `${issuer}/api/accounts/authorize`,
9741
+ tokenUrl: `${issuer}/api/accounts/oauth/token`,
9742
+ scopes: [
9743
+ "openid",
9744
+ "profile",
9745
+ "email",
9746
+ "offline_access",
9747
+ "resource.invoke",
9748
+ SIWC_REQUIRED_SCOPE
9749
+ ],
9750
+ // 端口可变(scheme / host / path 不变):1455 被占用就用任意空闲端口
9751
+ redirectPorts: ports ?? [1455, 0],
9752
+ resource: SIWC_RESOURCE,
9753
+ refreshEncoding: "form",
9754
+ baseUrl: chatgptBaseUrl(flavor, env),
9755
+ verifyIdToken: true,
9756
+ requiredScope: SIWC_REQUIRED_SCOPE,
9757
+ device: false,
9758
+ revoke: true
9759
+ };
9760
+ }
9761
+ return {
9762
+ flavor,
9763
+ issuer,
9764
+ clientId: explicitClient ?? CODEX_CLIENT_ID,
9765
+ registering: false,
9766
+ authorizeUrl: `${issuer}/oauth/authorize`,
9767
+ tokenUrl: `${issuer}/oauth/token`,
9768
+ scopes: ["openid", "profile", "email", "offline_access"],
9769
+ // 公开客户端只登记了这两个端口;被占用不抢占
9770
+ redirectPorts: ports ?? [1455, 1457],
9771
+ refreshEncoding: "json",
9772
+ baseUrl: chatgptBaseUrl(flavor, env),
9773
+ verifyIdToken: false,
9774
+ device: true,
9775
+ revoke: false,
9776
+ originator: nonEmpty2(config?.originator) ?? DEFAULT_ORIGINATOR
9777
+ };
9778
+ }
9779
+ function authorizeUrl(preset, input2) {
9780
+ const params = new URLSearchParams({
9781
+ response_type: "code",
9782
+ client_id: preset.clientId,
9783
+ redirect_uri: input2.redirectUri,
9784
+ scope: preset.scopes.join(" "),
9785
+ code_challenge: input2.challenge,
9786
+ code_challenge_method: "S256",
9787
+ state: input2.state
9788
+ });
9789
+ if (preset.flavor === "siwc") {
9790
+ params.set("nonce", input2.nonce);
9791
+ if (preset.resource !== void 0) params.set("resource", preset.resource);
9792
+ if (input2.hostId !== void 0) params.set("ext_agent_host_id", input2.hostId);
9793
+ if (preset.registering) params.set("agent_name_hint", AGENT_NAME_HINT);
9794
+ } else {
9795
+ params.set("id_token_add_organizations", "true");
9796
+ params.set("codex_cli_simplified_flow", "true");
9797
+ if (preset.originator !== void 0) params.set("originator", preset.originator);
9798
+ }
9799
+ return `${preset.authorizeUrl}?${params.toString()}`;
9800
+ }
9801
+ var CHATGPT_PROVIDER_ID, DEFAULT_ISSUER, SIWC_REGISTRATION_CLIENT_ID, CODEX_CLIENT_ID, SIWC_RESOURCE, SIWC_REQUIRED_SCOPE, AGENT_NAME_HINT, DEFAULT_ORIGINATOR, DEFAULT_CODEX_CLIENT_VERSION, CHATGPT_BASE_URLS;
9802
+ var init_presets = __esm({
9803
+ "src/auth/chatgpt/presets.ts"() {
9804
+ "use strict";
9805
+ CHATGPT_PROVIDER_ID = "chatgpt";
9806
+ DEFAULT_ISSUER = "https://auth.openai.com";
9807
+ SIWC_REGISTRATION_CLIENT_ID = "dynamic_agent_client";
9808
+ CODEX_CLIENT_ID = "app_EMoamEEZ73f0CkXaXp7hrann";
9809
+ SIWC_RESOURCE = "https://api.openai.com/v1";
9810
+ SIWC_REQUIRED_SCOPE = "chatgpt.tokens.use.direct";
9811
+ AGENT_NAME_HINT = "ama";
9812
+ DEFAULT_ORIGINATOR = "codex_cli_rs";
9813
+ DEFAULT_CODEX_CLIENT_VERSION = "0.160.0";
9814
+ CHATGPT_BASE_URLS = {
9815
+ siwc: "https://api.openai.com/v1",
9816
+ codex: "https://chatgpt.com/backend-api/codex"
9817
+ };
9818
+ }
9819
+ });
9820
+
9565
9821
  // src/ai/providers/catalog-data.ts
9566
9822
  var CATALOG_SOURCES;
9567
9823
  var init_catalog_data = __esm({
@@ -11669,11 +11925,12 @@ async function resolveModel(args, registry2, manager, defaultModel, deps, intera
11669
11925
  } else {
11670
11926
  const change = lastEntry(manager, (e) => e.type === "model_change");
11671
11927
  if (change?.type === "model_change") {
11928
+ const channel = change.provider === CHATGPT_PROVIDER_ID ? void 0 : change.channel;
11672
11929
  const found = registry2.findModel(
11673
11930
  formatModelRef({
11674
11931
  provider: change.provider,
11675
11932
  id: change.modelId,
11676
- ...change.channel !== void 0 ? { channel: change.channel } : {}
11933
+ ...channel !== void 0 ? { channel } : {}
11677
11934
  })
11678
11935
  );
11679
11936
  if (found.ok) choice3 = { model: found.model, provider: found.provider };
@@ -11750,6 +12007,7 @@ var init_startup_steps = __esm({
11750
12007
  "use strict";
11751
12008
  init_suggest();
11752
12009
  init_channels();
12010
+ init_presets();
11753
12011
  import_node_fs14 = require("node:fs");
11754
12012
  import_node_path16 = require("node:path");
11755
12013
  init_errors();
@@ -16446,7 +16704,7 @@ function resolvePreset(input2) {
16446
16704
  return { preset, codemode, builtin: names.sort(), warnings };
16447
16705
  }
16448
16706
  var CODEMODE_TOOL, PRESET_TOOLS, PresetToolRegistry;
16449
- var init_presets = __esm({
16707
+ var init_presets2 = __esm({
16450
16708
  "src/tools/presets.ts"() {
16451
16709
  "use strict";
16452
16710
  init_capability();
@@ -16806,7 +17064,7 @@ var init_tool_runner = __esm({
16806
17064
  import_node_path35 = require("node:path");
16807
17065
  init_loop_guard();
16808
17066
  init_schema2();
16809
- init_presets();
17067
+ init_presets2();
16810
17068
  init_registry();
16811
17069
  init_truncate();
16812
17070
  ABORTED_TOOL_TEXT = "aborted by user";
@@ -20550,11 +20808,11 @@ function addSubscription(stats, provider, usage) {
20550
20808
  if (usage.billing !== "subscription") return;
20551
20809
  const sub = stats.subscription ??= { requests: 0, byProvider: {} };
20552
20810
  sub.requests++;
20553
- const row2 = sub.byProvider[provider] ??= { requests: 0, input: 0, output: 0, cacheRead: 0 };
20554
- row2.requests++;
20555
- row2.input += usage.input;
20556
- row2.output += usage.output;
20557
- row2.cacheRead += usage.cacheRead;
20811
+ const row3 = sub.byProvider[provider] ??= { requests: 0, input: 0, output: 0, cacheRead: 0 };
20812
+ row3.requests++;
20813
+ row3.input += usage.input;
20814
+ row3.output += usage.output;
20815
+ row3.cacheRead += usage.cacheRead;
20558
20816
  }
20559
20817
  function computeStats(input2) {
20560
20818
  const tokens = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 };
@@ -23994,9 +24252,72 @@ var init_session_extensions = __esm({
23994
24252
  }
23995
24253
  });
23996
24254
 
24255
+ // src/auth/oauth/live.ts
24256
+ function registerLiveToken(token, context) {
24257
+ live.delete(token);
24258
+ live.set(token, context);
24259
+ while (live.size > MAX_LIVE) {
24260
+ const oldest = live.keys().next().value;
24261
+ if (oldest === void 0) break;
24262
+ live.delete(oldest);
24263
+ }
24264
+ }
24265
+ function liveToken(token) {
24266
+ return token === void 0 ? void 0 : live.get(token);
24267
+ }
24268
+ var MAX_LIVE, live;
24269
+ var init_live = __esm({
24270
+ "src/auth/oauth/live.ts"() {
24271
+ "use strict";
24272
+ MAX_LIVE = 32;
24273
+ live = /* @__PURE__ */ new Map();
24274
+ }
24275
+ });
24276
+
24277
+ // src/auth/chatgpt/follow.ts
24278
+ function backendOf(compat) {
24279
+ if (typeof compat !== "object" || compat === null) return void 0;
24280
+ const value = compat.chatgptBackend;
24281
+ return value === "siwc" || value === "codex" ? value : void 0;
24282
+ }
24283
+ function followChatGptLogin(model, provider, apiKey) {
24284
+ const current3 = backendOf(model.compat);
24285
+ if (current3 === void 0 || model.channelPinned === true) return model;
24286
+ const flavor = liveToken(apiKey)?.flavor;
24287
+ if (flavor === void 0 || flavor === current3) return model;
24288
+ const channels = provider?.channels ?? [];
24289
+ const target = channels.find((c) => backendOf(c.compat) === flavor) ?? channels.find((c) => c.name === flavor);
24290
+ if (target === void 0) return model;
24291
+ const previous = channels.find((c) => c.name === model.channel);
24292
+ const headers2 = { ...model.headers };
24293
+ for (const name of Object.keys(previous?.headers ?? {})) delete headers2[name];
24294
+ Object.assign(headers2, target.headers);
24295
+ const next = {
24296
+ ...model,
24297
+ api: target.api,
24298
+ baseUrl: target.baseUrl,
24299
+ channel: target.name,
24300
+ compat: { ...model.compat, ...target.compat, chatgptBackend: flavor }
24301
+ };
24302
+ if (Object.keys(headers2).length > 0) next.headers = headers2;
24303
+ else delete next.headers;
24304
+ return next;
24305
+ }
24306
+ var init_follow = __esm({
24307
+ "src/auth/chatgpt/follow.ts"() {
24308
+ "use strict";
24309
+ init_live();
24310
+ }
24311
+ });
24312
+
23997
24313
  // src/agent/session-settings.ts
23998
24314
  function providerStream(providers) {
23999
- return (model, context, streamOptions) => {
24315
+ return (requested, context, streamOptions) => {
24316
+ const model = followChatGptLogin(
24317
+ requested,
24318
+ providers.get(requested.provider),
24319
+ streamOptions.apiKey
24320
+ );
24000
24321
  const api = providers.getApi(model.api);
24001
24322
  if (api === void 0) {
24002
24323
  throw new AmaError("provider_not_found", `no implementation registered for api ${model.api}`);
@@ -24008,6 +24329,7 @@ var SessionSettings;
24008
24329
  var init_session_settings = __esm({
24009
24330
  "src/agent/session-settings.ts"() {
24010
24331
  "use strict";
24332
+ init_follow();
24011
24333
  init_errors();
24012
24334
  init_session_sync();
24013
24335
  SessionSettings = class {
@@ -32643,14 +32965,14 @@ function aggregateExternal(entries) {
32643
32965
  const byAgent = {};
32644
32966
  for (const u of usage) {
32645
32967
  if (typeof u.agent !== "string" || typeof u.amount !== "number") continue;
32646
- const row2 = byAgent[u.agent] ??= { runs: 0, unit: u.unit, amount: 0 };
32647
- row2.runs += 1;
32648
- if (row2.unit !== u.unit) {
32649
- row2.unit = u.unit;
32650
- row2.amount = 0;
32968
+ const row3 = byAgent[u.agent] ??= { runs: 0, unit: u.unit, amount: 0 };
32969
+ row3.runs += 1;
32970
+ if (row3.unit !== u.unit) {
32971
+ row3.unit = u.unit;
32972
+ row3.amount = 0;
32651
32973
  }
32652
- row2.amount += u.amount;
32653
- if (typeof u.tokens === "number") row2.tokens = (row2.tokens ?? 0) + u.tokens;
32974
+ row3.amount += u.amount;
32975
+ if (typeof u.tokens === "number") row3.tokens = (row3.tokens ?? 0) + u.tokens;
32654
32976
  }
32655
32977
  return { byAgent };
32656
32978
  }
@@ -33492,7 +33814,7 @@ var init_compose_session = __esm({
33492
33814
  init_expand();
33493
33815
  init_index_prompt();
33494
33816
  init_templates();
33495
- init_presets();
33817
+ init_presets2();
33496
33818
  init_compose_store();
33497
33819
  init_compose_extensions();
33498
33820
  init_compose_memory();
@@ -34162,6 +34484,125 @@ var init_token_store = __esm({
34162
34484
  }
34163
34485
  });
34164
34486
 
34487
+ // src/ai/providers/discovered-cache.ts
34488
+ function discoveredCachePath(dataDir, provider) {
34489
+ return (0, import_node_path66.join)(dataDir, "models", "discovered", `${provider}.json`);
34490
+ }
34491
+ function toEntry(value) {
34492
+ if (typeof value !== "object" || value === null) return void 0;
34493
+ const raw = value;
34494
+ const { id, name, contextWindow, input: input2, reasoningLevels } = raw;
34495
+ if (typeof id !== "string" || id === "") return void 0;
34496
+ const out = { id };
34497
+ if (typeof name === "string" && name !== "") out.name = name;
34498
+ if (typeof contextWindow === "number" && Number.isInteger(contextWindow) && contextWindow > 0)
34499
+ out.contextWindow = contextWindow;
34500
+ if (Array.isArray(input2) && input2.includes("text"))
34501
+ out.input = ["text", "image"].filter((x) => input2.includes(x));
34502
+ if (Array.isArray(reasoningLevels) && reasoningLevels.every((x) => typeof x === "string"))
34503
+ out.reasoningLevels = reasoningLevels;
34504
+ return out;
34505
+ }
34506
+ function readDiscoveredCache(dataDir, provider) {
34507
+ let parsed;
34508
+ try {
34509
+ parsed = JSON.parse((0, import_node_fs44.readFileSync)(discoveredCachePath(dataDir, provider), "utf8"));
34510
+ } catch {
34511
+ return void 0;
34512
+ }
34513
+ if (typeof parsed !== "object" || parsed === null) return void 0;
34514
+ const file = parsed;
34515
+ if (file.provider !== provider || !Array.isArray(file.models)) return void 0;
34516
+ return {
34517
+ version: typeof file.version === "number" ? file.version : DISCOVERED_CACHE_VERSION,
34518
+ provider,
34519
+ fetchedAt: typeof file.fetchedAt === "string" ? file.fetchedAt : "",
34520
+ ...typeof file.flavor === "string" ? { flavor: file.flavor } : {},
34521
+ models: file.models.map(toEntry).filter((m) => m !== void 0)
34522
+ };
34523
+ }
34524
+ function writeDiscoveredCache(dataDir, provider, input2, now = Date.now()) {
34525
+ const path = discoveredCachePath(dataDir, provider);
34526
+ const file = {
34527
+ version: DISCOVERED_CACHE_VERSION,
34528
+ provider,
34529
+ fetchedAt: new Date(now).toISOString(),
34530
+ ...input2.flavor !== void 0 ? { flavor: input2.flavor } : {},
34531
+ models: input2.models.map(toEntry).filter((m) => m !== void 0)
34532
+ };
34533
+ (0, import_node_fs44.mkdirSync)((0, import_node_path66.dirname)(path), { recursive: true, mode: 448 });
34534
+ const tmp = `${path}.${process.pid}.tmp`;
34535
+ (0, import_node_fs44.writeFileSync)(tmp, `${JSON.stringify(file, null, 2)}
34536
+ `);
34537
+ (0, import_node_fs44.renameSync)(tmp, path);
34538
+ return path;
34539
+ }
34540
+ function clearDiscoveredCache(dataDir, provider) {
34541
+ const path = discoveredCachePath(dataDir, provider);
34542
+ if (!(0, import_node_fs44.existsSync)(path)) return false;
34543
+ (0, import_node_fs44.rmSync)(path, { force: true });
34544
+ return true;
34545
+ }
34546
+ function thinkingMapOf(levels) {
34547
+ const map = {
34548
+ off: levels.includes("none") ? "none" : null
34549
+ };
34550
+ for (const level of EFFORT_LEVELS) map[level] = levels.includes(level) ? level : null;
34551
+ return map;
34552
+ }
34553
+ function withBackendMetadata(model, cached, matched) {
34554
+ if (model.contextWindow === void 0 && cached.contextWindow !== void 0)
34555
+ model.contextWindow = cached.contextWindow;
34556
+ if (matched) return;
34557
+ if (cached.input !== void 0) model.input = [...cached.input];
34558
+ const efforts = (cached.reasoningLevels ?? []).filter((x) => x !== "none");
34559
+ if (efforts.length > 0) {
34560
+ model.reasoning = true;
34561
+ model.thinkingLevelMap = thinkingMapOf(cached.reasoningLevels ?? []);
34562
+ }
34563
+ }
34564
+ function discoveredModels(file, provider, modelsDev) {
34565
+ return file.models.map((m) => {
34566
+ const { entry, metadata } = enrichEntry(
34567
+ m.name ? { id: m.id, name: m.name } : { id: m.id },
34568
+ modelsDev
34569
+ );
34570
+ const model = withCustomDefaults(entry, provider.id, provider.api);
34571
+ withBackendMetadata(model, m, metadata.match !== void 0);
34572
+ const names = (provider.channels ?? []).map((c) => c.name);
34573
+ if (names.length > 0) {
34574
+ const own = file.flavor !== void 0 && names.includes(file.flavor) ? file.flavor : void 0;
34575
+ model.channels = [own ?? provider.defaultChannel ?? names[0]];
34576
+ }
34577
+ return model;
34578
+ });
34579
+ }
34580
+ function mergeDiscoveredModels(registry2, dataDir, modelsDev, loginFlavor = () => void 0) {
34581
+ const merged = [];
34582
+ for (const provider of registry2.list()) {
34583
+ if (provider.models.length > 0 || !provider.requiresApiKey) continue;
34584
+ const file = readDiscoveredCache(dataDir, provider.id);
34585
+ if (file === void 0 || file.models.length === 0) continue;
34586
+ const flavor = loginFlavor(provider.id);
34587
+ if (flavor !== void 0 && file.flavor !== void 0 && file.flavor !== flavor) continue;
34588
+ registry2.addModels(provider.id, discoveredModels(file, provider, modelsDev), "discovered");
34589
+ merged.push(provider.id);
34590
+ }
34591
+ return merged;
34592
+ }
34593
+ var import_node_fs44, import_node_path66, DISCOVERED_CACHE_VERSION, EFFORT_LEVELS;
34594
+ var init_discovered_cache = __esm({
34595
+ "src/ai/providers/discovered-cache.ts"() {
34596
+ "use strict";
34597
+ import_node_fs44 = require("node:fs");
34598
+ import_node_path66 = require("node:path");
34599
+ init_catalog2();
34600
+ init_enrich();
34601
+ DISCOVERED_CACHE_VERSION = 1;
34602
+ EFFORT_LEVELS = ["minimal", "low", "medium", "high", "xhigh"];
34603
+ }
34604
+ });
34605
+
34165
34606
  // src/ai/apis/chatgpt-rate-limits.ts
34166
34607
  function num(value) {
34167
34608
  const n = typeof value === "string" && value.trim() !== "" ? Number(value) : value;
@@ -34247,109 +34688,6 @@ var init_chatgpt_rate_limits = __esm({
34247
34688
  }
34248
34689
  });
34249
34690
 
34250
- // src/auth/chatgpt/presets.ts
34251
- function nonEmpty2(value) {
34252
- const trimmed = value?.trim();
34253
- return trimmed === void 0 || trimmed === "" ? void 0 : trimmed;
34254
- }
34255
- function chatgptBaseUrl(flavor, env = process.env) {
34256
- return nonEmpty2(env["AMA_CHATGPT_BASE_URL"]) ?? CHATGPT_BASE_URLS[flavor];
34257
- }
34258
- function resolveChatGptPreset(flavor, overrides = {}) {
34259
- const env = overrides.env ?? process.env;
34260
- const config = overrides.config;
34261
- const issuer = (nonEmpty2(env["AMA_CHATGPT_ISSUER"]) ?? nonEmpty2(config?.issuer) ?? DEFAULT_ISSUER).replace(/\/+$/, "");
34262
- const sameFlavor = overrides.entry?.flavor === flavor ? overrides.entry : void 0;
34263
- const explicitClient = nonEmpty2(env["AMA_CHATGPT_CLIENT_ID"]) ?? nonEmpty2(config?.clientId);
34264
- const ports = overrides.port !== void 0 ? [overrides.port] : config?.redirectPorts !== void 0 && config.redirectPorts.length > 0 ? [...config.redirectPorts] : void 0;
34265
- if (flavor === "siwc") {
34266
- const issued = sameFlavor?.clientId !== SIWC_REGISTRATION_CLIENT_ID ? sameFlavor?.clientId : void 0;
34267
- const clientId = explicitClient ?? issued ?? SIWC_REGISTRATION_CLIENT_ID;
34268
- return {
34269
- flavor,
34270
- issuer,
34271
- clientId,
34272
- registering: clientId === SIWC_REGISTRATION_CLIENT_ID,
34273
- authorizeUrl: `${issuer}/api/accounts/authorize`,
34274
- tokenUrl: `${issuer}/api/accounts/oauth/token`,
34275
- scopes: [
34276
- "openid",
34277
- "profile",
34278
- "email",
34279
- "offline_access",
34280
- "resource.invoke",
34281
- SIWC_REQUIRED_SCOPE
34282
- ],
34283
- // 端口可变(scheme / host / path 不变):1455 被占用就用任意空闲端口
34284
- redirectPorts: ports ?? [1455, 0],
34285
- resource: SIWC_RESOURCE,
34286
- refreshEncoding: "form",
34287
- baseUrl: chatgptBaseUrl(flavor, env),
34288
- verifyIdToken: true,
34289
- requiredScope: SIWC_REQUIRED_SCOPE,
34290
- device: false,
34291
- revoke: true
34292
- };
34293
- }
34294
- return {
34295
- flavor,
34296
- issuer,
34297
- clientId: explicitClient ?? CODEX_CLIENT_ID,
34298
- registering: false,
34299
- authorizeUrl: `${issuer}/oauth/authorize`,
34300
- tokenUrl: `${issuer}/oauth/token`,
34301
- scopes: ["openid", "profile", "email", "offline_access"],
34302
- // 公开客户端只登记了这两个端口;被占用不抢占
34303
- redirectPorts: ports ?? [1455, 1457],
34304
- refreshEncoding: "json",
34305
- baseUrl: chatgptBaseUrl(flavor, env),
34306
- verifyIdToken: false,
34307
- device: true,
34308
- revoke: false,
34309
- originator: nonEmpty2(config?.originator) ?? DEFAULT_ORIGINATOR
34310
- };
34311
- }
34312
- function authorizeUrl(preset, input2) {
34313
- const params = new URLSearchParams({
34314
- response_type: "code",
34315
- client_id: preset.clientId,
34316
- redirect_uri: input2.redirectUri,
34317
- scope: preset.scopes.join(" "),
34318
- code_challenge: input2.challenge,
34319
- code_challenge_method: "S256",
34320
- state: input2.state
34321
- });
34322
- if (preset.flavor === "siwc") {
34323
- params.set("nonce", input2.nonce);
34324
- if (preset.resource !== void 0) params.set("resource", preset.resource);
34325
- if (input2.hostId !== void 0) params.set("ext_agent_host_id", input2.hostId);
34326
- if (preset.registering) params.set("agent_name_hint", AGENT_NAME_HINT);
34327
- } else {
34328
- params.set("id_token_add_organizations", "true");
34329
- params.set("codex_cli_simplified_flow", "true");
34330
- if (preset.originator !== void 0) params.set("originator", preset.originator);
34331
- }
34332
- return `${preset.authorizeUrl}?${params.toString()}`;
34333
- }
34334
- var CHATGPT_PROVIDER_ID, DEFAULT_ISSUER, SIWC_REGISTRATION_CLIENT_ID, CODEX_CLIENT_ID, SIWC_RESOURCE, SIWC_REQUIRED_SCOPE, AGENT_NAME_HINT, DEFAULT_ORIGINATOR, CHATGPT_BASE_URLS;
34335
- var init_presets2 = __esm({
34336
- "src/auth/chatgpt/presets.ts"() {
34337
- "use strict";
34338
- CHATGPT_PROVIDER_ID = "chatgpt";
34339
- DEFAULT_ISSUER = "https://auth.openai.com";
34340
- SIWC_REGISTRATION_CLIENT_ID = "dynamic_agent_client";
34341
- CODEX_CLIENT_ID = "app_EMoamEEZ73f0CkXaXp7hrann";
34342
- SIWC_RESOURCE = "https://api.openai.com/v1";
34343
- SIWC_REQUIRED_SCOPE = "chatgpt.tokens.use.direct";
34344
- AGENT_NAME_HINT = "ama";
34345
- DEFAULT_ORIGINATOR = "codex_cli_rs";
34346
- CHATGPT_BASE_URLS = {
34347
- siwc: "https://api.openai.com/v1",
34348
- codex: "https://chatgpt.com/backend-api/codex"
34349
- };
34350
- }
34351
- });
34352
-
34353
34691
  // src/auth/oauth/token-client.ts
34354
34692
  function oauthErrorCode(body) {
34355
34693
  try {
@@ -34615,6 +34953,7 @@ var init_key_docs = __esm({
34615
34953
  "src/config/key-docs.ts"() {
34616
34954
  "use strict";
34617
34955
  init_http();
34956
+ init_presets();
34618
34957
  init_i18n();
34619
34958
  init_declarations();
34620
34959
  init_merge();
@@ -34637,7 +34976,12 @@ var init_key_docs = __esm({
34637
34976
  subagents: "read"
34638
34977
  },
34639
34978
  auth: {
34640
- chatgpt: { flavor: "siwc", issuer: "https://auth.openai.com", originator: "codex_cli_rs" }
34979
+ chatgpt: {
34980
+ flavor: "siwc",
34981
+ issuer: "https://auth.openai.com",
34982
+ originator: "codex_cli_rs",
34983
+ codexClientVersion: DEFAULT_CODEX_CLIENT_VERSION
34984
+ }
34641
34985
  },
34642
34986
  checkpoints: { ...DEFAULT_CHECKPOINTS_CONFIG },
34643
34987
  sandbox: { enabled: "auto", bash: "off", network: "deny", writable: [] },
@@ -34660,7 +35004,7 @@ var init_key_docs = __esm({
34660
35004
 
34661
35005
  // src/ai/providers/models-dev-cache.ts
34662
35006
  function modelsDevCachePath(dataDir) {
34663
- return (0, import_node_path68.join)(dataDir, MODELS_DEV_FILE);
35007
+ return (0, import_node_path69.join)(dataDir, MODELS_DEV_FILE);
34664
35008
  }
34665
35009
  function modelsDevUrl(env = process.env) {
34666
35010
  const custom = env[MODELS_DEV_URL_ENV]?.trim();
@@ -34668,7 +35012,7 @@ function modelsDevUrl(env = process.env) {
34668
35012
  }
34669
35013
  function readModelsDevCache(dataDir) {
34670
35014
  try {
34671
- const value = JSON.parse((0, import_node_fs45.readFileSync)(modelsDevCachePath(dataDir), "utf8"));
35015
+ const value = JSON.parse((0, import_node_fs46.readFileSync)(modelsDevCachePath(dataDir), "utf8"));
34672
35016
  if (typeof value !== "object" || value === null) return void 0;
34673
35017
  const file = value;
34674
35018
  if (file.version !== 2 || typeof file.fetchedAt !== "string") return void 0;
@@ -34681,10 +35025,10 @@ function readModelsDevCache(dataDir) {
34681
35025
  }
34682
35026
  function writeModelsDevCache(dataDir, file) {
34683
35027
  const path = modelsDevCachePath(dataDir);
34684
- (0, import_node_fs45.mkdirSync)((0, import_node_path68.dirname)(path), { recursive: true, mode: 448 });
35028
+ (0, import_node_fs46.mkdirSync)((0, import_node_path69.dirname)(path), { recursive: true, mode: 448 });
34685
35029
  const tmp = `${path}.${process.pid}.tmp`;
34686
- (0, import_node_fs45.writeFileSync)(tmp, JSON.stringify(file));
34687
- (0, import_node_fs45.renameSync)(tmp, path);
35030
+ (0, import_node_fs46.writeFileSync)(tmp, JSON.stringify(file));
35031
+ (0, import_node_fs46.renameSync)(tmp, path);
34688
35032
  memo = void 0;
34689
35033
  }
34690
35034
  function overrideApplies(file) {
@@ -34694,7 +35038,7 @@ function loadModelsDevIndex(dataDir) {
34694
35038
  const path = modelsDevCachePath(dataDir);
34695
35039
  let key;
34696
35040
  try {
34697
- const stat16 = (0, import_node_fs45.statSync)(path);
35041
+ const stat16 = (0, import_node_fs46.statSync)(path);
34698
35042
  key = `${path}\0${stat16.mtimeMs}\0${stat16.size}`;
34699
35043
  } catch {
34700
35044
  return builtinSnapshotIndex();
@@ -34779,12 +35123,12 @@ function describeRefresh(result, limit = 20) {
34779
35123
  }
34780
35124
  return lines2.join("\n");
34781
35125
  }
34782
- var import_node_fs45, import_node_path68, MODELS_DEV_URL, MODELS_DEV_URL_ENV, MODELS_DEV_FILE, MODELS_DEV_TIMEOUT_MS, memo;
35126
+ var import_node_fs46, import_node_path69, MODELS_DEV_URL, MODELS_DEV_URL_ENV, MODELS_DEV_FILE, MODELS_DEV_TIMEOUT_MS, memo;
34783
35127
  var init_models_dev_cache = __esm({
34784
35128
  "src/ai/providers/models-dev-cache.ts"() {
34785
35129
  "use strict";
34786
- import_node_fs45 = require("node:fs");
34787
- import_node_path68 = require("node:path");
35130
+ import_node_fs46 = require("node:fs");
35131
+ import_node_path69 = require("node:path");
34788
35132
  init_models_dev();
34789
35133
  init_models_dev_snapshot();
34790
35134
  init_i18n();
@@ -34901,7 +35245,7 @@ function w5Sections() {
34901
35245
  }
34902
35246
  ),
34903
35247
  subagents: object({ maxConcurrent: num2(1, 64), maxPending: num2(0, 1024), defaultModel: str3() }),
34904
- models: object({ aliases: object({ fast: str3(), strong: str3() }) }),
35248
+ models: object({ aliases: object({ fast: str3(), strong: str3() }), enabled: strings2 }),
34905
35249
  fallbackModel: str3(),
34906
35250
  limits: object({ maxTurns: num2(1), maxCostUsd: num2(0) }),
34907
35251
  reminders: object({
@@ -34929,6 +35273,7 @@ function w6Sections() {
34929
35273
  clientId: str3(),
34930
35274
  issuer: str3(),
34931
35275
  originator: str3(),
35276
+ codexClientVersion: str3(),
34932
35277
  redirectPorts: {
34933
35278
  type: "array",
34934
35279
  items: { type: "integer", minimum: 0, maximum: 65535 }
@@ -35111,40 +35456,40 @@ function minimalConfig() {
35111
35456
  }
35112
35457
  function writeAtomic2(path, text, mode) {
35113
35458
  const tmp = `${path}.${process.pid}.tmp`;
35114
- (0, import_node_fs46.writeFileSync)(tmp, text, { mode });
35115
- (0, import_node_fs46.renameSync)(tmp, path);
35459
+ (0, import_node_fs47.writeFileSync)(tmp, text, { mode });
35460
+ (0, import_node_fs47.renameSync)(tmp, path);
35116
35461
  }
35117
35462
  function initConfigDir(dir, options = {}) {
35118
- const dirCreated = !(0, import_node_fs46.existsSync)(dir);
35119
- (0, import_node_fs46.mkdirSync)(dir, { recursive: true, mode: 448 });
35120
- if (dirCreated && process.platform !== "win32") (0, import_node_fs46.chmodSync)(dir, 448);
35463
+ const dirCreated = !(0, import_node_fs47.existsSync)(dir);
35464
+ (0, import_node_fs47.mkdirSync)(dir, { recursive: true, mode: 448 });
35465
+ if (dirCreated && process.platform !== "win32") (0, import_node_fs47.chmodSync)(dir, 448);
35121
35466
  const files = [];
35122
- const config = (0, import_node_path69.join)(dir, CONFIG_FILE);
35467
+ const config = (0, import_node_path70.join)(dir, CONFIG_FILE);
35123
35468
  const text = `${JSON.stringify(minimalConfig(), null, 2)}
35124
35469
  `;
35125
- if (!(0, import_node_fs46.existsSync)(config)) {
35470
+ if (!(0, import_node_fs47.existsSync)(config)) {
35126
35471
  writeAtomic2(config, text, 420);
35127
35472
  files.push({ path: config, status: "created" });
35128
35473
  } else if (options.force) {
35129
- (0, import_node_fs46.copyFileSync)(config, `${config}.bak`);
35474
+ (0, import_node_fs47.copyFileSync)(config, `${config}.bak`);
35130
35475
  writeAtomic2(config, text, 420);
35131
35476
  files.push({ path: config, status: "overwritten" });
35132
35477
  } else files.push({ path: config, status: "exists" });
35133
- const schema = (0, import_node_path69.join)(dir, CONFIG_SCHEMA_FILE);
35478
+ const schema = (0, import_node_path70.join)(dir, CONFIG_SCHEMA_FILE);
35134
35479
  const schemaText = configSchemaText();
35135
- if (!(0, import_node_fs46.existsSync)(schema)) {
35480
+ if (!(0, import_node_fs47.existsSync)(schema)) {
35136
35481
  writeAtomic2(schema, schemaText, 420);
35137
35482
  files.push({ path: schema, status: "created" });
35138
- } else if ((0, import_node_fs46.readFileSync)(schema, "utf8") !== schemaText) {
35483
+ } else if ((0, import_node_fs47.readFileSync)(schema, "utf8") !== schemaText) {
35139
35484
  writeAtomic2(schema, schemaText, 420);
35140
35485
  files.push({ path: schema, status: "updated" });
35141
35486
  } else files.push({ path: schema, status: "unchanged" });
35142
- const auth = (0, import_node_path69.join)(dir, AUTH_FILE);
35143
- if ((0, import_node_fs46.existsSync)(auth)) files.push({ path: auth, status: "exists" });
35487
+ const auth = (0, import_node_path70.join)(dir, AUTH_FILE);
35488
+ if ((0, import_node_fs47.existsSync)(auth)) files.push({ path: auth, status: "exists" });
35144
35489
  return { dir, dirCreated, files };
35145
35490
  }
35146
35491
  function autoInitConfigDir(dir, env) {
35147
- if (env[NO_INIT_ENV] === "1" || (0, import_node_fs46.existsSync)(dir)) return false;
35492
+ if (env[NO_INIT_ENV] === "1" || (0, import_node_fs47.existsSync)(dir)) return false;
35148
35493
  try {
35149
35494
  initConfigDir(dir);
35150
35495
  return true;
@@ -35162,12 +35507,12 @@ function describeInit(result) {
35162
35507
  return `${lines2.join("\n")}
35163
35508
  `;
35164
35509
  }
35165
- var import_node_fs46, import_node_path69, NO_INIT_ENV;
35510
+ var import_node_fs47, import_node_path70, NO_INIT_ENV;
35166
35511
  var init_init = __esm({
35167
35512
  "src/config/init.ts"() {
35168
35513
  "use strict";
35169
- import_node_fs46 = require("node:fs");
35170
- import_node_path69 = require("node:path");
35514
+ import_node_fs47 = require("node:fs");
35515
+ import_node_path70 = require("node:path");
35171
35516
  init_i18n();
35172
35517
  init_json_schema();
35173
35518
  init_paths();
@@ -35951,28 +36296,6 @@ var init_openai_compat = __esm({
35951
36296
  }
35952
36297
  });
35953
36298
 
35954
- // src/auth/oauth/live.ts
35955
- function registerLiveToken(token, context) {
35956
- live.delete(token);
35957
- live.set(token, context);
35958
- while (live.size > MAX_LIVE) {
35959
- const oldest = live.keys().next().value;
35960
- if (oldest === void 0) break;
35961
- live.delete(oldest);
35962
- }
35963
- }
35964
- function liveToken(token) {
35965
- return token === void 0 ? void 0 : live.get(token);
35966
- }
35967
- var MAX_LIVE, live;
35968
- var init_live = __esm({
35969
- "src/auth/oauth/live.ts"() {
35970
- "use strict";
35971
- MAX_LIVE = 32;
35972
- live = /* @__PURE__ */ new Map();
35973
- }
35974
- });
35975
-
35976
36299
  // src/auth/oauth/refresh.ts
35977
36300
  function authExpiredError(provider) {
35978
36301
  return new AmaError(
@@ -36071,7 +36394,7 @@ var init_refresh = __esm({
36071
36394
  "src/auth/oauth/refresh.ts"() {
36072
36395
  "use strict";
36073
36396
  init_errors();
36074
- init_presets2();
36397
+ init_presets();
36075
36398
  init_token_client();
36076
36399
  init_token_store();
36077
36400
  REFRESH_MARGIN_MS = 5 * 6e4;
@@ -36125,8 +36448,10 @@ function chatgptPrecheck(model, compat, apiKey) {
36125
36448
  if (live2 === void 0) return;
36126
36449
  if (live2.needsLogin === true) throw authExpiredError(live2.provider);
36127
36450
  if (live2.flavor !== compat.chatgptBackend) {
36451
+ const pinned = String(compat.chatgptBackend);
36452
+ const ref = `${model.provider}/${model.id}@${pinned}`;
36128
36453
  throw new Error(
36129
- `chatgpt_flavor_mismatch: logged in with ${live2.flavor} but ${model.provider}/${model.id} uses the ${String(compat.chatgptBackend)} channel; run \`ama auth login ${live2.provider} --flavor ${String(compat.chatgptBackend)}\` or switch channel`
36454
+ `chatgpt_flavor_mismatch: ${msg().auth.request.flavorMismatch(live2.flavor, ref, pinned)}`
36130
36455
  );
36131
36456
  }
36132
36457
  }
@@ -36210,9 +36535,7 @@ function recoverChatGptError(error2, model, compat, options, apiKey, tried) {
36210
36535
  if (backend === "siwc" && error2.status === 403 && code === "subscription_sharing_user_not_eligible")
36211
36536
  return {
36212
36537
  kind: "fail",
36213
- error: new Error(
36214
- "not_eligible: this ChatGPT account cannot share plan usage with ama (403 subscription_sharing_user_not_eligible)"
36215
- )
36538
+ error: new Error(`not_eligible: ${msg().auth.request.notEligible}`)
36216
36539
  };
36217
36540
  if (backend === "siwc" && error2.status === 400 && code === "subscription_sharing_unsupported_capability" && !tried.has("strip")) {
36218
36541
  const param = typeof body["param"] === "string" ? body["param"].split(/[.[]/)[0] : void 0;
@@ -36238,6 +36561,7 @@ var init_chatgpt_backend = __esm({
36238
36561
  "use strict";
36239
36562
  init_live();
36240
36563
  init_refresh();
36564
+ init_i18n();
36241
36565
  init_chatgpt_rate_limits();
36242
36566
  SIWC_FORBIDDEN_FIELDS = [
36243
36567
  "background",
@@ -37937,14 +38261,14 @@ var init_api = __esm({
37937
38261
  // src/ai/providers/auth.ts
37938
38262
  function defaultConfigDir(env = process.env) {
37939
38263
  if (env["AMA_CONFIG_DIR"]) return env["AMA_CONFIG_DIR"];
37940
- if (process.platform === "win32" && env["APPDATA"]) return (0, import_node_path70.join)(env["APPDATA"], "ama");
37941
- if (env["XDG_CONFIG_HOME"]) return (0, import_node_path70.join)(env["XDG_CONFIG_HOME"], "ama");
37942
- return (0, import_node_path70.join)(env["HOME"] ?? (0, import_node_os11.homedir)(), ".config", "ama");
38264
+ if (process.platform === "win32" && env["APPDATA"]) return (0, import_node_path71.join)(env["APPDATA"], "ama");
38265
+ if (env["XDG_CONFIG_HOME"]) return (0, import_node_path71.join)(env["XDG_CONFIG_HOME"], "ama");
38266
+ return (0, import_node_path71.join)(env["HOME"] ?? (0, import_node_os11.homedir)(), ".config", "ama");
37943
38267
  }
37944
38268
  function readAuthFile2(path, onWarning) {
37945
38269
  let raw;
37946
38270
  try {
37947
- raw = (0, import_node_fs47.readFileSync)(path, "utf8");
38271
+ raw = (0, import_node_fs48.readFileSync)(path, "utf8");
37948
38272
  } catch (error2) {
37949
38273
  const code = error2.code;
37950
38274
  if (code !== "ENOENT") onWarning?.(`cannot read auth file ${path}`);
@@ -37952,7 +38276,7 @@ function readAuthFile2(path, onWarning) {
37952
38276
  }
37953
38277
  if (process.platform !== "win32") {
37954
38278
  try {
37955
- const mode = (0, import_node_fs47.statSync)(path).mode & 511;
38279
+ const mode = (0, import_node_fs48.statSync)(path).mode & 511;
37956
38280
  if ((mode & 63) !== 0) {
37957
38281
  onWarning?.(
37958
38282
  `auth file ${path} has permissions ${mode.toString(8).padStart(4, "0")}; expected 0600`
@@ -37986,14 +38310,14 @@ function expandEnvRefs(value, env) {
37986
38310
  );
37987
38311
  return missing || out.length === 0 ? void 0 : out;
37988
38312
  }
37989
- var import_node_child_process13, import_node_fs47, import_node_os11, import_node_path70, ApiKeyResolver;
38313
+ var import_node_child_process13, import_node_fs48, import_node_os11, import_node_path71, ApiKeyResolver;
37990
38314
  var init_auth2 = __esm({
37991
38315
  "src/ai/providers/auth.ts"() {
37992
38316
  "use strict";
37993
38317
  import_node_child_process13 = require("node:child_process");
37994
- import_node_fs47 = require("node:fs");
38318
+ import_node_fs48 = require("node:fs");
37995
38319
  import_node_os11 = require("node:os");
37996
- import_node_path70 = require("node:path");
38320
+ import_node_path71 = require("node:path");
37997
38321
  init_live();
37998
38322
  init_refresh();
37999
38323
  init_token_store();
@@ -38013,7 +38337,7 @@ var init_auth2 = __esm({
38013
38337
  authFiles() {
38014
38338
  const files = [];
38015
38339
  if (this.options.authFile) files.push(this.options.authFile);
38016
- const user = this.options.userAuthFile === void 0 ? (0, import_node_path70.join)(defaultConfigDir(this.env), "auth.json") : this.options.userAuthFile;
38340
+ const user = this.options.userAuthFile === void 0 ? (0, import_node_path71.join)(defaultConfigDir(this.env), "auth.json") : this.options.userAuthFile;
38017
38341
  if (user && !files.includes(user)) files.push(user);
38018
38342
  return files;
38019
38343
  }
@@ -38214,6 +38538,8 @@ var init_registry2 = __esm({
38214
38538
  envBaseUrls = /* @__PURE__ */ new Map();
38215
38539
  /** baseUrl 指向非官方主机的内置供应商:接受目录外的 model id。 */
38216
38540
  relayed = /* @__PURE__ */ new Set();
38541
+ /** 模型表只来自发现缓存的供应商:表外的 id 照样合成(与空表相同)。 */
38542
+ openTables = /* @__PURE__ */ new Set();
38217
38543
  /** config 里写了自己 `channels` 的供应商(内置渠道不因改 baseUrl 作废)。 */
38218
38544
  userChannels = /* @__PURE__ */ new Set();
38219
38545
  /** config 里写了供应商级 `api` 的供应商(单渠道回落时目录模型跟它走)。 */
@@ -38484,6 +38810,8 @@ var init_registry2 = __esm({
38484
38810
  addModels(providerId, models, source = "discovered") {
38485
38811
  const provider = this.providers.get(providerId);
38486
38812
  if (!provider) return;
38813
+ if (source === "discovered" && provider.models.length === 0 && provider.requiresApiKey)
38814
+ this.openTables.add(providerId);
38487
38815
  for (const raw of models) {
38488
38816
  this.raw.delete(`${providerId}/${raw.id}`);
38489
38817
  const model = this.materialize(provider, { ...raw, provider: providerId });
@@ -38512,8 +38840,8 @@ var init_registry2 = __esm({
38512
38840
  candidates: available.filter(Boolean).map((c) => `${provider.id}/${model.id}@${c}`)
38513
38841
  };
38514
38842
  }
38515
- if (channel === model.channel) return { ok: true, model, provider };
38516
- return { ok: true, model: this.materialize(provider, model, channel), provider };
38843
+ const picked = channel === model.channel ? model : this.materialize(provider, model, channel);
38844
+ return { ok: true, model: { ...picked, channelPinned: true }, provider };
38517
38845
  }
38518
38846
  /**
38519
38847
  * `provider/model`、`provider/model@渠道` 或裸模型 id。`@` 先按渠道解析(id 里本来就带 `@` 且已登记的
@@ -38539,11 +38867,12 @@ var init_registry2 = __esm({
38539
38867
  const id = trimmed.slice(slash + 1);
38540
38868
  const model = provider.models.find((m) => m.id === id);
38541
38869
  if (model) return { ok: true, model, provider };
38542
- const relayed = provider.models.length === 0 || this.relayed.has(provider.id);
38870
+ const open2 = this.relayed.has(provider.id) || this.openTables.has(provider.id);
38871
+ const relayed = provider.models.length === 0 || open2;
38543
38872
  if (synthesize && relayed && id.length > 0) {
38544
- const synthesized = this.synthesize(provider, id);
38545
- if (channel !== void 0 && provider.channels?.some((c) => c.name === channel))
38546
- synthesized.channels = [.../* @__PURE__ */ new Set([...synthesized.channels ?? [], channel])];
38873
+ const known = provider.channels?.some((c) => c.name === channel) ? channel : void 0;
38874
+ const synthesized = this.synthesize(provider, id, known);
38875
+ if (known) synthesized.channels = [.../* @__PURE__ */ new Set([...synthesized.channels ?? [], known])];
38547
38876
  return { ok: true, model: synthesized, provider };
38548
38877
  }
38549
38878
  return { ok: false, reason: "not_found", candidates: this.similar(id, provider.id) };
@@ -39115,33 +39444,34 @@ var init_settings_registry = __esm({
39115
39444
  { key: "sandbox.writable", hint: "sandboxWritable" },
39116
39445
  { key: "agents.<id>", hint: "agents" },
39117
39446
  { key: "hooks", hint: "hooks" },
39118
- { key: "auth.chatgpt", hint: "auth" }
39447
+ { key: "auth.chatgpt", hint: "auth" },
39448
+ { key: "models.enabled", hint: "modelsEnabled" }
39119
39449
  ];
39120
39450
  }
39121
39451
  });
39122
39452
 
39123
39453
  // src/config/write.ts
39124
39454
  function writeConfigFile(path, config, options = {}) {
39125
- (0, import_node_fs48.mkdirSync)((0, import_node_path72.dirname)(path), { recursive: true });
39455
+ (0, import_node_fs49.mkdirSync)((0, import_node_path73.dirname)(path), { recursive: true });
39126
39456
  let mode;
39127
39457
  try {
39128
- mode = (0, import_node_fs48.statSync)(path).mode & 511;
39458
+ mode = (0, import_node_fs49.statSync)(path).mode & 511;
39129
39459
  } catch {
39130
39460
  mode = void 0;
39131
39461
  }
39132
- if (mode !== void 0 && options.backup !== false) (0, import_node_fs48.copyFileSync)(path, `${path}.bak`);
39462
+ if (mode !== void 0 && options.backup !== false) (0, import_node_fs49.copyFileSync)(path, `${path}.bak`);
39133
39463
  const tmp = `${path}.${process.pid}.tmp`;
39134
- (0, import_node_fs48.writeFileSync)(tmp, `${JSON.stringify(config, null, 2)}
39464
+ (0, import_node_fs49.writeFileSync)(tmp, `${JSON.stringify(config, null, 2)}
39135
39465
  `, { mode: mode ?? 420 });
39136
- if (mode !== void 0) (0, import_node_fs48.chmodSync)(tmp, mode);
39137
- (0, import_node_fs48.renameSync)(tmp, path);
39466
+ if (mode !== void 0) (0, import_node_fs49.chmodSync)(tmp, mode);
39467
+ (0, import_node_fs49.renameSync)(tmp, path);
39138
39468
  }
39139
- var import_node_fs48, import_node_path72;
39469
+ var import_node_fs49, import_node_path73;
39140
39470
  var init_write2 = __esm({
39141
39471
  "src/config/write.ts"() {
39142
39472
  "use strict";
39143
- import_node_fs48 = require("node:fs");
39144
- import_node_path72 = require("node:path");
39473
+ import_node_fs49 = require("node:fs");
39474
+ import_node_path73 = require("node:path");
39145
39475
  }
39146
39476
  });
39147
39477
 
@@ -39339,7 +39669,7 @@ function parseEnum(key, text, options) {
39339
39669
  function readTarget(path, scope) {
39340
39670
  let text;
39341
39671
  try {
39342
- text = (0, import_node_fs49.readFileSync)(path, "utf8");
39672
+ text = (0, import_node_fs50.readFileSync)(path, "utf8");
39343
39673
  } catch (error2) {
39344
39674
  if (error2.code === "ENOENT")
39345
39675
  return scope === "user" ? minimalConfig() : { version: CONFIG_FILE_VERSION };
@@ -39421,11 +39751,11 @@ function formatSettingValue(value) {
39421
39751
  if (typeof value === "string") return value;
39422
39752
  return JSON.stringify(value);
39423
39753
  }
39424
- var import_node_fs49, ConfigEditError, same, ABOVE, TRUE, FALSE, UNSET;
39754
+ var import_node_fs50, ConfigEditError, same, ABOVE, TRUE, FALSE, UNSET;
39425
39755
  var init_edit2 = __esm({
39426
39756
  "src/config/edit.ts"() {
39427
39757
  "use strict";
39428
- import_node_fs49 = require("node:fs");
39758
+ import_node_fs50 = require("node:fs");
39429
39759
  init_errors();
39430
39760
  init_i18n();
39431
39761
  init_init();
@@ -39538,8 +39868,8 @@ function compositeOne(lines2, layer, width2, height) {
39538
39868
  const startRow = anchor === "bottom" ? result.length - oh : viewportTop + Math.max(0, Math.floor((visible - oh) / 2));
39539
39869
  const col = anchor === "bottom" && ow === width2 ? 0 : Math.floor((width2 - ow) / 2);
39540
39870
  for (let i = 0; i < oh; i++) {
39541
- const row2 = startRow + i;
39542
- result[row2] = spliceLine(result[row2] ?? "", body[i] ?? "", col, ow, width2);
39871
+ const row3 = startRow + i;
39872
+ result[row3] = spliceLine(result[row3] ?? "", body[i] ?? "", col, ow, width2);
39543
39873
  }
39544
39874
  return result;
39545
39875
  }
@@ -40245,21 +40575,21 @@ var init_tui = __esm({
40245
40575
  return Math.max(this.topLimit, this.bufferRows - height);
40246
40576
  }
40247
40577
  /** 从 hwRow 移到内容行 row 的行首;越过已有行时用换行(会滚屏)。 */
40248
- moveTo(row2) {
40578
+ moveTo(row3) {
40249
40579
  let seq = "";
40250
- if (row2 < this.hwRow) {
40251
- seq += `\x1B[${this.hwRow - row2}A`;
40252
- } else if (row2 > this.hwRow) {
40580
+ if (row3 < this.hwRow) {
40581
+ seq += `\x1B[${this.hwRow - row3}A`;
40582
+ } else if (row3 > this.hwRow) {
40253
40583
  const lastExisting = Math.max(this.hwRow, this.bufferRows - 1);
40254
- const down = Math.min(row2, lastExisting) - this.hwRow;
40584
+ const down = Math.min(row3, lastExisting) - this.hwRow;
40255
40585
  if (down > 0) seq += `\x1B[${down}B`;
40256
- const extra = row2 - lastExisting;
40586
+ const extra = row3 - lastExisting;
40257
40587
  if (extra > 0) {
40258
40588
  seq += "\r\n".repeat(extra);
40259
- this.bufferRows = row2 + 1;
40589
+ this.bufferRows = row3 + 1;
40260
40590
  }
40261
40591
  }
40262
- this.hwRow = row2;
40592
+ this.hwRow = row3;
40263
40593
  return seq + "\r";
40264
40594
  }
40265
40595
  doRender() {
@@ -40740,7 +41070,7 @@ function parseKeybindings(value) {
40740
41070
  function loadKeybindingsFile(path) {
40741
41071
  let text;
40742
41072
  try {
40743
- text = (0, import_node_fs50.readFileSync)(path, "utf8");
41073
+ text = (0, import_node_fs51.readFileSync)(path, "utf8");
40744
41074
  } catch (error2) {
40745
41075
  if (error2.code === "ENOENT") return { overrides: {}, warnings: [] };
40746
41076
  return {
@@ -40757,12 +41087,12 @@ function loadKeybindingsFile(path) {
40757
41087
  };
40758
41088
  }
40759
41089
  }
40760
- var import_node_fs50, DEFAULT_KEYBINDINGS, Keybindings, defaultKeybindings;
41090
+ var import_node_fs51, DEFAULT_KEYBINDINGS, Keybindings, defaultKeybindings;
40761
41091
  var init_keybindings = __esm({
40762
41092
  "src/tui/keybindings.ts"() {
40763
41093
  "use strict";
40764
41094
  init_i18n();
40765
- import_node_fs50 = require("node:fs");
41095
+ import_node_fs51 = require("node:fs");
40766
41096
  init_keys();
40767
41097
  DEFAULT_KEYBINDINGS = {
40768
41098
  "tui.editor.submit": ["enter"],
@@ -40945,9 +41275,9 @@ function parseBlock(lines2, i, blocks) {
40945
41275
  if (TABLE_RE.test(line2)) {
40946
41276
  const rows = [];
40947
41277
  while (i < lines2.length && TABLE_RE.test(lines2[i])) {
40948
- const row2 = lines2[i++];
40949
- if (TABLE_SEP_RE.test(row2)) continue;
40950
- rows.push(splitTableRow(row2));
41278
+ const row3 = lines2[i++];
41279
+ if (TABLE_SEP_RE.test(row3)) continue;
41280
+ rows.push(splitTableRow(row3));
40951
41281
  }
40952
41282
  blocks.push({ kind: "table", rows, source: lines2.slice(start, i).join("\n") });
40953
41283
  return i;
@@ -41016,8 +41346,8 @@ function joinSoftBreaks(lines2) {
41016
41346
  });
41017
41347
  return out.trimEnd();
41018
41348
  }
41019
- function splitTableRow(row2) {
41020
- const trimmed = row2.trim().replace(/^\|/, "").replace(/\|$/, "");
41349
+ function splitTableRow(row3) {
41350
+ const trimmed = row3.trim().replace(/^\|/, "").replace(/\|$/, "");
41021
41351
  return trimmed.split(/(?<!\\)\|/).map((cell) => cell.trim().replace(/\\\|/g, "|"));
41022
41352
  }
41023
41353
  function renderInline(text, theme) {
@@ -41184,13 +41514,13 @@ function wrapCode(line2, width2) {
41184
41514
  function renderTable(rows, width2, theme) {
41185
41515
  const cols = Math.max(0, ...rows.map((r) => r.length));
41186
41516
  const widths = new Array(cols).fill(0);
41187
- const rendered = rows.map((row2) => row2.map((cell) => renderInline(cell, theme)));
41188
- for (const row2 of rendered) {
41189
- row2.forEach((cell, c) => widths[c] = Math.max(widths[c], visibleWidth(cell)));
41517
+ const rendered = rows.map((row3) => row3.map((cell) => renderInline(cell, theme)));
41518
+ for (const row3 of rendered) {
41519
+ row3.forEach((cell, c) => widths[c] = Math.max(widths[c], visibleWidth(cell)));
41190
41520
  }
41191
41521
  const lines2 = [];
41192
- rendered.forEach((row2, r) => {
41193
- const cells = widths.map((w, c) => padToWidth(row2[c] ?? "", w));
41522
+ rendered.forEach((row3, r) => {
41523
+ const cells = widths.map((w, c) => padToWidth(row3[c] ?? "", w));
41194
41524
  const line2 = cells.join(" ").replace(/\s+$/, "");
41195
41525
  const header = r === 0 && rows.length > 1;
41196
41526
  lines2.push(truncateToWidth(header ? theme.bold(line2) : line2, width2));
@@ -41586,7 +41916,7 @@ var init_editor_buffer = __esm({
41586
41916
  function loadHistoryFile(path, limit = 500) {
41587
41917
  let text;
41588
41918
  try {
41589
- text = (0, import_node_fs51.readFileSync)(path, "utf8");
41919
+ text = (0, import_node_fs52.readFileSync)(path, "utf8");
41590
41920
  } catch {
41591
41921
  return [];
41592
41922
  }
@@ -41603,11 +41933,11 @@ function loadHistoryFile(path, limit = 500) {
41603
41933
  }
41604
41934
  function appendHistoryFile(path, entry, limit) {
41605
41935
  try {
41606
- (0, import_node_fs51.mkdirSync)((0, import_node_path73.dirname)(path), { recursive: true });
41607
- (0, import_node_fs51.appendFileSync)(path, JSON.stringify(entry) + "\n", { mode: 384 });
41936
+ (0, import_node_fs52.mkdirSync)((0, import_node_path74.dirname)(path), { recursive: true });
41937
+ (0, import_node_fs52.appendFileSync)(path, JSON.stringify(entry) + "\n", { mode: 384 });
41608
41938
  const all = loadHistoryFile(path, Number.MAX_SAFE_INTEGER);
41609
41939
  if (all.length > limit * 2) {
41610
- (0, import_node_fs51.writeFileSync)(
41940
+ (0, import_node_fs52.writeFileSync)(
41611
41941
  path,
41612
41942
  all.slice(-limit).map((e) => JSON.stringify(e) + "\n").join("")
41613
41943
  );
@@ -41615,12 +41945,12 @@ function appendHistoryFile(path, entry, limit) {
41615
41945
  } catch {
41616
41946
  }
41617
41947
  }
41618
- var import_node_fs51, import_node_path73;
41948
+ var import_node_fs52, import_node_path74;
41619
41949
  var init_editor_history = __esm({
41620
41950
  "src/tui/components/editor-history.ts"() {
41621
41951
  "use strict";
41622
- import_node_fs51 = require("node:fs");
41623
- import_node_path73 = require("node:path");
41952
+ import_node_fs52 = require("node:fs");
41953
+ import_node_path74 = require("node:path");
41624
41954
  }
41625
41955
  });
41626
41956
 
@@ -41727,6 +42057,11 @@ var init_select_list = __esm({
41727
42057
  getItems() {
41728
42058
  return this.filtered;
41729
42059
  }
42060
+ /** 换列表下的按键提示(选择器切视图时)。 */
42061
+ setFooter(footer) {
42062
+ if (footer === void 0) delete this.options.footer;
42063
+ else this.options.footer = footer;
42064
+ }
41730
42065
  getFilter() {
41731
42066
  return this.filter;
41732
42067
  }
@@ -42110,9 +42445,9 @@ var init_editor = __esm({
42110
42445
  else this.buffer.moveLineEnd();
42111
42446
  return;
42112
42447
  }
42113
- const row2 = rows[at];
42114
- const line2 = this.buffer.getLines()[row2.line];
42115
- const col = this.preferredCol ?? visibleWidth(line2.slice(row2.start, this.buffer.cursor.col));
42448
+ const row3 = rows[at];
42449
+ const line2 = this.buffer.getLines()[row3.line];
42450
+ const col = this.preferredCol ?? visibleWidth(line2.slice(row3.start, this.buffer.cursor.col));
42116
42451
  this.preferredCol = col;
42117
42452
  const target = rows[at + direction];
42118
42453
  this.buffer.setCursor({ line: target.line, col: this.colAtWidth(target, col) });
@@ -42135,17 +42470,17 @@ var init_editor = __esm({
42135
42470
  this.preferredCol = null;
42136
42471
  this.options.onChange?.(this.buffer.getText());
42137
42472
  }
42138
- colAtWidth(row2, targetWidth) {
42139
- const line2 = this.buffer.getLines()[row2.line];
42140
- let col = row2.start;
42473
+ colAtWidth(row3, targetWidth) {
42474
+ const line2 = this.buffer.getLines()[row3.line];
42475
+ let col = row3.start;
42141
42476
  let width2 = 0;
42142
- for (const { segment, index: index2 } of segmenter4.segment(line2.slice(row2.start, row2.end))) {
42477
+ for (const { segment, index: index2 } of segmenter4.segment(line2.slice(row3.start, row3.end))) {
42143
42478
  const w = visibleWidth(segment);
42144
42479
  if (width2 + w > targetWidth) break;
42145
42480
  width2 += w;
42146
- col = row2.start + index2 + segment.length;
42481
+ col = row3.start + index2 + segment.length;
42147
42482
  }
42148
- if (!row2.last && col >= row2.end) col = this.prevGrapheme(line2, row2.end);
42483
+ if (!row3.last && col >= row3.end) col = this.prevGrapheme(line2, row3.end);
42149
42484
  return col;
42150
42485
  }
42151
42486
  prevGrapheme(line2, col) {
@@ -42277,28 +42612,28 @@ var init_editor = __esm({
42277
42612
  }
42278
42613
  return rows.length - 1;
42279
42614
  }
42280
- renderRow(row2, withCursor) {
42281
- const text = this.buffer.getLines()[row2.line];
42615
+ renderRow(row3, withCursor) {
42616
+ const text = this.buffer.getLines()[row3.line];
42282
42617
  const atomic = this.pastes.ranges(text);
42283
42618
  const cursorCol = withCursor ? this.buffer.cursor.col : -1;
42284
42619
  let out = "";
42285
- let pos = row2.start;
42286
- while (pos < row2.end || pos === cursorCol) {
42620
+ let pos = row3.start;
42621
+ while (pos < row3.end || pos === cursorCol) {
42287
42622
  if (pos === cursorCol) {
42288
- const g = pos < row2.end ? nextGrapheme(text, pos) : " ";
42623
+ const g = pos < row3.end ? nextGrapheme(text, pos) : " ";
42289
42624
  out += CURSOR_MARKER + `\x1B[7m${g}\x1B[27m`;
42290
- if (pos >= row2.end) break;
42625
+ if (pos >= row3.end) break;
42291
42626
  pos += g.length;
42292
42627
  continue;
42293
42628
  }
42294
42629
  const range = atomic.find(([s2, e]) => pos >= s2 && pos < e);
42295
42630
  if (range) {
42296
- const end2 = Math.min(range[1], row2.end, cursorCol > pos ? cursorCol : Infinity);
42631
+ const end2 = Math.min(range[1], row3.end, cursorCol > pos ? cursorCol : Infinity);
42297
42632
  out += this.theme.fg("accent", text.slice(pos, end2));
42298
42633
  pos = end2;
42299
42634
  continue;
42300
42635
  }
42301
- let end = row2.end;
42636
+ let end = row3.end;
42302
42637
  if (cursorCol > pos && cursorCol < end) end = cursorCol;
42303
42638
  const nextAtomic = atomic.find(([s2]) => s2 > pos && s2 < end);
42304
42639
  if (nextAtomic) end = nextAtomic[0];
@@ -42398,7 +42733,7 @@ var init_box = __esm({
42398
42733
  for (let i = 0; i < padY; i++) rows.push(emptyRow);
42399
42734
  if (!border) return rows;
42400
42735
  const lines2 = [this.topBorder(width2, color)];
42401
- for (const row2 of rows) lines2.push(color(g.vertical) + row2 + color(g.vertical));
42736
+ for (const row3 of rows) lines2.push(color(g.vertical) + row3 + color(g.vertical));
42402
42737
  lines2.push(color(g.bottomLeft + g.horizontal.repeat(width2 - 2) + g.bottomRight));
42403
42738
  return lines2;
42404
42739
  }
@@ -42755,7 +43090,7 @@ var init_settings_list = __esm({
42755
43090
  return this.shown;
42756
43091
  }
42757
43092
  selectId(id) {
42758
- const index2 = this.shown.findIndex((row2) => row2.id === id);
43093
+ const index2 = this.shown.findIndex((row3) => row3.id === id);
42759
43094
  if (index2 === -1) return false;
42760
43095
  this.selected = index2;
42761
43096
  return true;
@@ -42769,7 +43104,7 @@ var init_settings_list = __esm({
42769
43104
  refilter() {
42770
43105
  const q = this.filter.trim().toLowerCase();
42771
43106
  this.shown = q === "" ? [...this.rows] : this.rows.filter(
42772
- (row2) => [row2.id, row2.label, row2.value, row2.search ?? ""].some(
43107
+ (row3) => [row3.id, row3.label, row3.value, row3.search ?? ""].some(
42773
43108
  (t) => t.toLowerCase().includes(q)
42774
43109
  )
42775
43110
  );
@@ -42778,12 +43113,12 @@ var init_settings_list = __esm({
42778
43113
  lines() {
42779
43114
  const out = [];
42780
43115
  let group;
42781
- this.shown.forEach((row2, index2) => {
42782
- if (row2.group !== group) {
42783
- group = row2.group;
42784
- out.push({ kind: "group", text: row2.group });
43116
+ this.shown.forEach((row3, index2) => {
43117
+ if (row3.group !== group) {
43118
+ group = row3.group;
43119
+ out.push({ kind: "group", text: row3.group });
42785
43120
  }
42786
- out.push({ kind: "row", row: row2, index: index2 });
43121
+ out.push({ kind: "row", row: row3, index: index2 });
42787
43122
  });
42788
43123
  return out;
42789
43124
  }
@@ -42809,18 +43144,18 @@ var init_settings_list = __esm({
42809
43144
  (line2) => line2.kind === "group" ? truncateToWidth(theme.fg("muted", theme.bold(line2.text)), width2) : this.rowLine(line2.row, line2.index === this.selected, width2, labelW, valueW, tagW)
42810
43145
  );
42811
43146
  }
42812
- rowLine(row2, selected, width2, labelW, valueW, tagW) {
43147
+ rowLine(row3, selected, width2, labelW, valueW, tagW) {
42813
43148
  const { theme } = this.options;
42814
43149
  const pointer = selected ? theme.glyphs.prompt : " ";
42815
- const label2 = padToWidth(truncateToWidth(row2.label, labelW), labelW);
42816
- const valueText = padToWidth(truncateToWidth(row2.value, valueW), valueW);
42817
- const value = row2.valueColor !== void 0 ? theme.fg(row2.valueColor, valueText) : valueText;
43150
+ const label2 = padToWidth(truncateToWidth(row3.label, labelW), labelW);
43151
+ const valueText = padToWidth(truncateToWidth(row3.value, valueW), valueW);
43152
+ const value = row3.valueColor !== void 0 ? theme.fg(row3.valueColor, valueText) : valueText;
42818
43153
  let line2 = `${pointer} ${selected ? theme.fg("accent", theme.bold(label2)) : label2} ${value}`;
42819
- if (width2 >= 48 && tagW > 0) line2 += ` ${theme.fg("dim", padToWidth(row2.tag ?? "", tagW))}`;
42820
- if (width2 >= 60 && row2.note !== void 0 && row2.note !== "")
42821
- line2 += ` ${theme.fg(row2.noteColor ?? "dim", row2.note)}`;
43154
+ if (width2 >= 48 && tagW > 0) line2 += ` ${theme.fg("dim", padToWidth(row3.tag ?? "", tagW))}`;
43155
+ if (width2 >= 60 && row3.note !== void 0 && row3.note !== "")
43156
+ line2 += ` ${theme.fg(row3.noteColor ?? "dim", row3.note)}`;
42822
43157
  let out = truncateToWidth(line2, width2);
42823
- if (row2.dim === true && !selected) out = theme.dim(out);
43158
+ if (row3.dim === true && !selected) out = theme.dim(out);
42824
43159
  return selected ? theme.bg("selection", padToWidth(out, width2)) : out;
42825
43160
  }
42826
43161
  invalidate() {
@@ -42979,6 +43314,54 @@ var init_choice_prompt = __esm({
42979
43314
  }
42980
43315
  });
42981
43316
 
43317
+ // src/ai/providers/model-visibility.ts
43318
+ async function providerAccess(registry2, provider) {
43319
+ if (!provider.requiresApiKey) return "local";
43320
+ const key = await registry2.resolveApiKey(provider.id).catch(() => ({ apiKey: void 0, source: "none" }));
43321
+ if (key.apiKey === void 0) return "none";
43322
+ if (key.source !== "oauth") return "key";
43323
+ return liveToken(key.apiKey)?.needsLogin === true ? "needsLogin" : "oauth";
43324
+ }
43325
+ function accessReady(access) {
43326
+ return access === "local" || access === "key" || access === "oauth";
43327
+ }
43328
+ function splitEnabledRef(ref) {
43329
+ const slash = ref.indexOf("/");
43330
+ if (slash <= 0 || slash === ref.length - 1) return void 0;
43331
+ const provider = ref.slice(0, slash);
43332
+ const rest = ref.slice(slash + 1);
43333
+ const at = rest.lastIndexOf("@");
43334
+ if (at > 0) return { provider, model: rest.slice(0, at), channel: rest.slice(at + 1) };
43335
+ return { provider, model: rest };
43336
+ }
43337
+ function enabledMatch(list5, ref) {
43338
+ if (list5.includes(ref)) return { kind: "exact", pattern: ref };
43339
+ const parts = splitEnabledRef(ref);
43340
+ if (parts === void 0) return void 0;
43341
+ const wildcard = `${parts.provider}/*`;
43342
+ return list5.includes(wildcard) ? { kind: "wildcard", pattern: wildcard } : void 0;
43343
+ }
43344
+ function addEnabled(list5, refs) {
43345
+ const out = [...list5 ?? []];
43346
+ for (const ref of refs) if (!out.includes(ref)) out.push(ref);
43347
+ return out;
43348
+ }
43349
+ function removeEnabled(list5, refs) {
43350
+ const out = (list5 ?? []).filter((ref) => !refs.includes(ref));
43351
+ return out.length > 0 ? out : void 0;
43352
+ }
43353
+ function enabledList(value) {
43354
+ if (!Array.isArray(value)) return void 0;
43355
+ const list5 = value.filter((x) => typeof x === "string");
43356
+ return list5.length > 0 ? list5 : void 0;
43357
+ }
43358
+ var init_model_visibility = __esm({
43359
+ "src/ai/providers/model-visibility.ts"() {
43360
+ "use strict";
43361
+ init_live();
43362
+ }
43363
+ });
43364
+
42982
43365
  // src/tools/clipboard-image.ts
42983
43366
  function attempts(platform, file, env) {
42984
43367
  if (platform === "darwin") {
@@ -43026,11 +43409,11 @@ async function readClipboardImage(dataDir, deps = {}) {
43026
43409
  const platform = deps.platform ?? process.platform;
43027
43410
  const env = deps.env ?? process.env;
43028
43411
  const run7 = deps.run ?? runCommand;
43029
- const dir = (0, import_node_path76.join)(dataDir, CLIPBOARD_DIR);
43412
+ const dir = (0, import_node_path77.join)(dataDir, CLIPBOARD_DIR);
43030
43413
  await (0, import_promises21.mkdir)(dir, { recursive: true });
43031
43414
  const stamp = new Date((deps.now ?? Date.now)()).toISOString().replace(/[:.]/g, "-");
43032
- let file = (0, import_node_path76.join)(dir, `${stamp}.png`);
43033
- for (let n = 1; (0, import_node_fs57.existsSync)(file); n++) file = (0, import_node_path76.join)(dir, `${stamp}-${n}.png`);
43415
+ let file = (0, import_node_path77.join)(dir, `${stamp}.png`);
43416
+ for (let n = 1; (0, import_node_fs58.existsSync)(file); n++) file = (0, import_node_path77.join)(dir, `${stamp}-${n}.png`);
43034
43417
  let anyTool = false;
43035
43418
  for (const attempt of attempts(platform, file, env)) {
43036
43419
  const options = attempt.via === "file" && attempt.env !== void 0 ? { env: attempt.env } : {};
@@ -43049,7 +43432,7 @@ async function readClipboardImage(dataDir, deps = {}) {
43049
43432
  return { ok: false, reason: anyTool ? "no_image" : "no_tool" };
43050
43433
  }
43051
43434
  async function gcClipboardImages(dataDir, options = {}) {
43052
- const dir = (0, import_node_path76.join)(dataDir, CLIPBOARD_DIR);
43435
+ const dir = (0, import_node_path77.join)(dataDir, CLIPBOARD_DIR);
43053
43436
  let names;
43054
43437
  try {
43055
43438
  names = await (0, import_promises21.readdir)(dir);
@@ -43059,7 +43442,7 @@ async function gcClipboardImages(dataDir, options = {}) {
43059
43442
  const cutoff = (options.now ?? Date.now()) - (options.maxAgeDays ?? CLIPBOARD_MAX_AGE_DAYS) * 864e5;
43060
43443
  const removed = [];
43061
43444
  for (const name of names) {
43062
- const file = (0, import_node_path76.join)(dir, name);
43445
+ const file = (0, import_node_path77.join)(dir, name);
43063
43446
  try {
43064
43447
  const info2 = await (0, import_promises21.stat)(file);
43065
43448
  if (!info2.isFile() || info2.mtimeMs >= cutoff) continue;
@@ -43070,13 +43453,13 @@ async function gcClipboardImages(dataDir, options = {}) {
43070
43453
  }
43071
43454
  return removed;
43072
43455
  }
43073
- var import_node_fs57, import_promises21, import_node_path76, CLIPBOARD_DIR, CLIPBOARD_MAX_AGE_DAYS, OSASCRIPT, POWERSHELL;
43456
+ var import_node_fs58, import_promises21, import_node_path77, CLIPBOARD_DIR, CLIPBOARD_MAX_AGE_DAYS, OSASCRIPT, POWERSHELL;
43074
43457
  var init_clipboard_image = __esm({
43075
43458
  "src/tools/clipboard-image.ts"() {
43076
43459
  "use strict";
43077
- import_node_fs57 = require("node:fs");
43460
+ import_node_fs58 = require("node:fs");
43078
43461
  import_promises21 = require("node:fs/promises");
43079
- import_node_path76 = require("node:path");
43462
+ import_node_path77 = require("node:path");
43080
43463
  init_image_file();
43081
43464
  init_image_resize();
43082
43465
  CLIPBOARD_DIR = "clipboard";
@@ -44192,7 +44575,7 @@ function statusCost(stats) {
44192
44575
  function layoutRow(parts, width2, theme, style = {}) {
44193
44576
  const sep5 = style.sep ?? " · ";
44194
44577
  const dim = (text) => text === "" ? "" : theme.fg("dim", text);
44195
- const join65 = (list5) => {
44578
+ const join66 = (list5) => {
44196
44579
  let out = "";
44197
44580
  let size = 0;
44198
44581
  const add3 = (text, measured = visibleWidth(text)) => {
@@ -44221,9 +44604,9 @@ function layoutRow(parts, width2, theme, style = {}) {
44221
44604
  let kept = [...parts];
44222
44605
  const zone = (z) => kept.filter((p) => p.zone === z);
44223
44606
  const fits = () => {
44224
- const l2 = join65(zone("left"))[1];
44607
+ const l2 = join66(zone("left"))[1];
44225
44608
  const right = zone("right");
44226
- return l2 + (right.length === 0 ? 0 : sep5.length + join65(right)[1]) <= width2;
44609
+ return l2 + (right.length === 0 ? 0 : sep5.length + join66(right)[1]) <= width2;
44227
44610
  };
44228
44611
  while (!fits()) {
44229
44612
  const droppable = kept.filter((p) => p.priority !== void 0);
@@ -44231,8 +44614,8 @@ function layoutRow(parts, width2, theme, style = {}) {
44231
44614
  const drop = droppable.reduce((worst, p) => p.priority > worst.priority ? p : worst);
44232
44615
  kept = kept.filter((p) => p !== drop);
44233
44616
  }
44234
- const l = join65(zone("left"))[0];
44235
- const r = join65(zone("right"))[0];
44617
+ const l = join66(zone("left"))[0];
44618
+ const r = join66(zone("right"))[0];
44236
44619
  const gap = width2 - visibleWidth(l) - visibleWidth(r);
44237
44620
  const line2 = r === "" ? l : gap >= MIN_GAP ? l + " ".repeat(gap) + r : l + dim(sep5) + r;
44238
44621
  return truncateToWidth(line2, width2);
@@ -44449,9 +44832,9 @@ function flat(text, max = 120) {
44449
44832
  return one.length > max ? `${one.slice(0, max - 1)}…` : one;
44450
44833
  }
44451
44834
  function displayPath2(path, cwd) {
44452
- if (cwd === void 0 || !(0, import_node_path81.isAbsolute)(path)) return path;
44453
- const rel = (0, import_node_path81.relative)(cwd, path);
44454
- return rel === "" ? "." : rel.startsWith("..") || (0, import_node_path81.isAbsolute)(rel) ? path : rel;
44835
+ if (cwd === void 0 || !(0, import_node_path82.isAbsolute)(path)) return path;
44836
+ const rel = (0, import_node_path82.relative)(cwd, path);
44837
+ return rel === "" ? "." : rel.startsWith("..") || (0, import_node_path82.isAbsolute)(rel) ? path : rel;
44455
44838
  }
44456
44839
  function toolSummary(name, args, cwd) {
44457
44840
  if (typeof args !== "object" || args === null) return "";
@@ -44605,12 +44988,12 @@ function resultSummary(input2, theme) {
44605
44988
  return muted(count2 === 0 ? m.done : m.outputLines(count2));
44606
44989
  }
44607
44990
  }
44608
- var import_node_path81;
44991
+ var import_node_path82;
44609
44992
  var init_tool_summary = __esm({
44610
44993
  "src/modes/interactive/tool-summary.ts"() {
44611
44994
  "use strict";
44612
44995
  init_i18n();
44613
- import_node_path81 = require("node:path");
44996
+ import_node_path82 = require("node:path");
44614
44997
  init_tui2();
44615
44998
  init_status_bar();
44616
44999
  }
@@ -44675,9 +45058,9 @@ function walk3(w, node, prefix, depth, turn, span) {
44675
45058
  const key = rowKey(prefix, node);
44676
45059
  const expandable = isExpandable(node);
44677
45060
  const expanded = expandable && (w.expanded.get(key) ?? defaultExpanded(node));
44678
- const row2 = { key, depth, node, turn, expandable, expanded };
44679
- if (span !== void 0) row2.span = span;
44680
- w.rows.push(row2);
45061
+ const row3 = { key, depth, node, turn, expandable, expanded };
45062
+ if (span !== void 0) row3.span = span;
45063
+ w.rows.push(row3);
44681
45064
  if (!expanded) return;
44682
45065
  const childPrefix = `${key}/`;
44683
45066
  if (node.kind === "subagent") {
@@ -44723,7 +45106,7 @@ function flattenNode(node, opts = {}) {
44723
45106
  return w.rows;
44724
45107
  }
44725
45108
  function rowIndex(rows, key) {
44726
- return rows.findIndex((row2) => row2.key === key);
45109
+ return rows.findIndex((row3) => row3.key === key);
44727
45110
  }
44728
45111
  var KEY_CODE;
44729
45112
  var init_flatten = __esm({
@@ -44804,9 +45187,9 @@ function auxLabel(purpose) {
44804
45187
  const aux = msg().trace.row.aux;
44805
45188
  return purpose === "cache_warm" ? aux.cache_warm : purpose === "permission_classify" ? aux.permission_classify : purpose === "compaction" ? msg().trace.row.compactionPlain : purpose;
44806
45189
  }
44807
- function rowLabel(row2, ctx) {
45190
+ function rowLabel(row3, ctx) {
44808
45191
  const m = msg().trace.row;
44809
- const node = row2.node;
45192
+ const node = row3.node;
44810
45193
  const described = ctx.describe?.(node);
44811
45194
  switch (node.kind) {
44812
45195
  case "more":
@@ -44816,7 +45199,7 @@ function rowLabel(row2, ctx) {
44816
45199
  case "turn": {
44817
45200
  const text = described ?? "";
44818
45201
  const origin = node.origin;
44819
- return origin === void 0 || origin === "followUp" ? m.turn(row2.turn, text).trimEnd() : m.turnOrigin(row2.turn, origin, text).trimEnd();
45202
+ return origin === void 0 || origin === "followUp" ? m.turn(row3.turn, text).trimEnd() : m.turnOrigin(row3.turn, origin, text).trimEnd();
44820
45203
  }
44821
45204
  case "step": {
44822
45205
  const base4 = node.attempt > 1 ? m.stepAttempt(node.model, node.attempt) : m.step(node.model);
@@ -44880,12 +45263,12 @@ function pushSegments(node, out, deep) {
44880
45263
  }
44881
45264
  }
44882
45265
  }
44883
- function barText(row2, width2, theme) {
45266
+ function barText(row3, width2, theme) {
44884
45267
  const plain = plainBars(theme);
44885
45268
  const cells = Math.max(1, width2 - 2);
44886
45269
  const ranks = new Array(cells).fill(0);
44887
- const span = row2.span;
44888
- const node = row2.node;
45270
+ const span = row3.span;
45271
+ const node = row3.node;
44889
45272
  if (span !== void 0 && node.kind !== "more" && node.kind !== "aux_group") {
44890
45273
  const segs = [];
44891
45274
  pushSegments(node, segs, true);
@@ -44908,31 +45291,31 @@ function barText(row2, width2, theme) {
44908
45291
  const [open2, close] = plain ? ["[", "]"] : ["▕", "▏"];
44909
45292
  return theme.fg("border", open2) + body + theme.fg("border", close);
44910
45293
  }
44911
- function labelPart(row2, ctx) {
45294
+ function labelPart(row3, ctx) {
44912
45295
  const g = ctx.theme.glyphs;
44913
- const indent2 = " ".repeat(Math.min(row2.depth * 2, MAX_INDENT));
44914
- const fold = row2.expandable ? row2.expanded ? g.collapse : g.expand : " ";
44915
- const mark = statusMark(row2.node, ctx.theme);
44916
- const label2 = rowLabel(row2, ctx);
44917
- const styled = row2.node.kind === "turn" ? ctx.theme.bold(label2) : row2.node.kind === "more" || row2.node.kind === "aux_group" ? ctx.theme.dim(label2) : label2;
45296
+ const indent2 = " ".repeat(Math.min(row3.depth * 2, MAX_INDENT));
45297
+ const fold = row3.expandable ? row3.expanded ? g.collapse : g.expand : " ";
45298
+ const mark = statusMark(row3.node, ctx.theme);
45299
+ const label2 = rowLabel(row3, ctx);
45300
+ const styled = row3.node.kind === "turn" ? ctx.theme.bold(label2) : row3.node.kind === "more" || row3.node.kind === "aux_group" ? ctx.theme.dim(label2) : label2;
44918
45301
  return `${indent2}${ctx.theme.fg("dim", fold)} ${mark === "" ? "" : `${mark} `}${styled}`;
44919
45302
  }
44920
- function formatRow(row2, width2, ctx, selected = false) {
45303
+ function formatRow(row3, width2, ctx, selected = false) {
44921
45304
  const theme = ctx.theme;
44922
45305
  const cursor = selected ? theme.fg("accent", theme.glyphs.prompt) : " ";
44923
45306
  const inner = Math.max(1, width2 - 1);
44924
- const duration = durationText(row2.node, theme).padStart(DURATION_WIDTH);
45307
+ const duration = durationText(row3.node, theme).padStart(DURATION_WIDTH);
44925
45308
  let right;
44926
45309
  if (width2 < NARROW_WIDTH) right = ` ${duration}`;
44927
45310
  else {
44928
- const bar = barText(row2, barWidth(width2), theme);
44929
- const tokens = padToWidth(tokensText(row2.node, theme), TOKENS_WIDTH);
44930
- const cache3 = cacheText2(row2.node).padStart(CACHE_WIDTH);
45311
+ const bar = barText(row3, barWidth(width2), theme);
45312
+ const tokens = padToWidth(tokensText(row3.node, theme), TOKENS_WIDTH);
45313
+ const cache3 = cacheText2(row3.node).padStart(CACHE_WIDTH);
44931
45314
  right = ` ${duration} ${bar} ${tokens} ${cache3}`;
44932
45315
  }
44933
45316
  const labelWidth = Math.max(1, inner - visibleWidth(right));
44934
45317
  const label2 = padToWidth(
44935
- truncateToWidth(labelPart(row2, ctx), labelWidth, theme.glyphs.ellipsis),
45318
+ truncateToWidth(labelPart(row3, ctx), labelWidth, theme.glyphs.ellipsis),
44936
45319
  labelWidth
44937
45320
  );
44938
45321
  const line2 = `${cursor}${label2}${theme.fg("muted", right)}`;
@@ -44961,9 +45344,9 @@ function expandAll(rows) {
44961
45344
  const expanded = /* @__PURE__ */ new Map();
44962
45345
  for (let guard2 = 0; guard2 < 8; guard2++) {
44963
45346
  let changed = false;
44964
- for (const row2 of rows(expanded))
44965
- if (row2.expandable && !row2.expanded && row2.node.kind !== "more") {
44966
- expanded.set(row2.key, true);
45347
+ for (const row3 of rows(expanded))
45348
+ if (row3.expandable && !row3.expanded && row3.node.kind !== "more") {
45349
+ expanded.set(row3.key, true);
44967
45350
  changed = true;
44968
45351
  }
44969
45352
  if (!changed) break;
@@ -44974,11 +45357,11 @@ function formatTraceText(trace, ctx, rows = expandAll((expanded) => flattenTrace
44974
45357
  const theme = ctx.theme;
44975
45358
  const lines2 = [title];
44976
45359
  if (rows.length === 0) lines2.push(msg().trace.empty);
44977
- for (const row2 of rows) {
44978
- const indent2 = " ".repeat(row2.depth);
44979
- const mark = statusMark(row2.node, theme);
44980
- const cols = [durationText(row2.node, theme), tokensText(row2.node, theme), cacheText2(row2.node)].filter((c) => c !== "").join(" ");
44981
- const label2 = `${indent2}${mark === "" ? "" : `${mark} `}${rowLabel(row2, ctx)}`;
45360
+ for (const row3 of rows) {
45361
+ const indent2 = " ".repeat(row3.depth);
45362
+ const mark = statusMark(row3.node, theme);
45363
+ const cols = [durationText(row3.node, theme), tokensText(row3.node, theme), cacheText2(row3.node)].filter((c) => c !== "").join(" ");
45364
+ const label2 = `${indent2}${mark === "" ? "" : `${mark} `}${rowLabel(row3, ctx)}`;
44982
45365
  lines2.push(cols === "" ? label2 : `${label2} ${cols}`);
44983
45366
  }
44984
45367
  return `${lines2.join("\n")}
@@ -45427,7 +45810,7 @@ function childLoader(read2 = readTraceInput) {
45427
45810
  const load2 = ((file) => {
45428
45811
  let stamp = "";
45429
45812
  try {
45430
- const st = (0, import_node_fs60.statSync)(file);
45813
+ const st = (0, import_node_fs61.statSync)(file);
45431
45814
  stamp = `${st.mtimeMs}:${st.size}`;
45432
45815
  } catch {
45433
45816
  stamp = "missing";
@@ -45471,11 +45854,11 @@ function traceText(session, taskId) {
45471
45854
  `${msg().trace.taskTitle(node.taskId, node.agent)}${summary2}`
45472
45855
  );
45473
45856
  }
45474
- var import_node_fs60, LiveTracker, lineTraceCommand;
45857
+ var import_node_fs61, LiveTracker, lineTraceCommand;
45475
45858
  var init_session3 = __esm({
45476
45859
  "src/trace/session.ts"() {
45477
45860
  "use strict";
45478
- import_node_fs60 = require("node:fs");
45861
+ import_node_fs61 = require("node:fs");
45479
45862
  init_session2();
45480
45863
  init_i18n();
45481
45864
  init_scan();
@@ -45549,10 +45932,10 @@ var init_session3 = __esm({
45549
45932
 
45550
45933
  // src/skills/builtin.ts
45551
45934
  function builtinSkillPath(dataDir, name) {
45552
- return (0, import_node_path84.join)(dataDir, BUILTIN_SKILLS_DIR, `${name}.md`);
45935
+ return (0, import_node_path85.join)(dataDir, BUILTIN_SKILLS_DIR, `${name}.md`);
45553
45936
  }
45554
45937
  function isBuiltinSkill(skill) {
45555
- return BUILTIN_SKILLS.some((b) => b.name === skill.name) && skill.location.endsWith((0, import_node_path84.join)(BUILTIN_SKILLS_DIR, `${skill.name}.md`));
45938
+ return BUILTIN_SKILLS.some((b) => b.name === skill.name) && skill.location.endsWith((0, import_node_path85.join)(BUILTIN_SKILLS_DIR, `${skill.name}.md`));
45556
45939
  }
45557
45940
  function builtinSkillText(skill) {
45558
45941
  return `---
@@ -45567,7 +45950,7 @@ async function ensureFile(path, text) {
45567
45950
  if (await (0, import_promises22.readFile)(path, "utf8") === text) return;
45568
45951
  } catch {
45569
45952
  }
45570
- await (0, import_promises22.mkdir)((0, import_node_path84.dirname)(path), { recursive: true });
45953
+ await (0, import_promises22.mkdir)((0, import_node_path85.dirname)(path), { recursive: true });
45571
45954
  await (0, import_promises22.writeFile)(path, text, "utf8");
45572
45955
  }
45573
45956
  async function withBuiltinSkills(skills, dataDir, builtins = BUILTIN_SKILLS) {
@@ -45576,7 +45959,7 @@ async function withBuiltinSkills(skills, dataDir, builtins = BUILTIN_SKILLS) {
45576
45959
  const taken = new Set(skills.map((skill) => skill.name));
45577
45960
  for (const builtin2 of builtins) {
45578
45961
  if (taken.has(builtin2.name)) continue;
45579
- const baseDir = (0, import_node_path84.join)(dataDir, BUILTIN_SKILLS_DIR);
45962
+ const baseDir = (0, import_node_path85.join)(dataDir, BUILTIN_SKILLS_DIR);
45580
45963
  const location = builtinSkillPath(dataDir, builtin2.name);
45581
45964
  try {
45582
45965
  await ensureFile(location, builtinSkillText(builtin2));
@@ -45597,12 +45980,12 @@ async function withBuiltinSkills(skills, dataDir, builtins = BUILTIN_SKILLS) {
45597
45980
  }
45598
45981
  return { skills: out, warnings };
45599
45982
  }
45600
- var import_promises22, import_node_path84, BUILTIN_SKILLS_DIR, AMA_DOCS_BODY, BUILTIN_SKILLS;
45983
+ var import_promises22, import_node_path85, BUILTIN_SKILLS_DIR, AMA_DOCS_BODY, BUILTIN_SKILLS;
45601
45984
  var init_builtin3 = __esm({
45602
45985
  "src/skills/builtin.ts"() {
45603
45986
  "use strict";
45604
45987
  import_promises22 = require("node:fs/promises");
45605
- import_node_path84 = require("node:path");
45988
+ import_node_path85 = require("node:path");
45606
45989
  BUILTIN_SKILLS_DIR = "builtin";
45607
45990
  AMA_DOCS_BODY = `# ama quick reference
45608
45991
 
@@ -45655,33 +46038,33 @@ Skills: \`<dir>/<name>/SKILL.md\` with \`name\` and \`description\` frontmatter
45655
46038
  // src/skills/discover.ts
45656
46039
  function ancestorDirs(cwd) {
45657
46040
  const out = [];
45658
- let dir = (0, import_node_path85.resolve)(cwd);
46041
+ let dir = (0, import_node_path86.resolve)(cwd);
45659
46042
  for (; ; ) {
45660
46043
  out.push(dir);
45661
- if ((0, import_node_fs62.existsSync)((0, import_node_path85.join)(dir, ".git"))) return out;
45662
- const parent = (0, import_node_path85.dirname)(dir);
46044
+ if ((0, import_node_fs63.existsSync)((0, import_node_path86.join)(dir, ".git"))) return out;
46045
+ const parent = (0, import_node_path86.dirname)(dir);
45663
46046
  if (parent === dir) return out;
45664
46047
  dir = parent;
45665
46048
  }
45666
46049
  }
45667
46050
  function skillSources(options) {
45668
46051
  const sources = [];
45669
- const add3 = (dir, scope, requiresTrust) => sources.push({ dir: (0, import_node_path85.resolve)(options.cwd, dir), scope, requiresTrust });
46052
+ const add3 = (dir, scope, requiresTrust) => sources.push({ dir: (0, import_node_path86.resolve)(options.cwd, dir), scope, requiresTrust });
45670
46053
  for (const d of options.cliDirs ?? []) add3(d, "cli", false);
45671
46054
  for (const d of options.profileDirs ?? []) add3(d, "profile", false);
45672
46055
  for (const d of options.configDirs ?? []) add3(d, "config", false);
45673
- add3((0, import_node_path85.join)(options.configDir, "skills"), "user", false);
45674
- add3((0, import_node_path85.join)(options.cwd, ".ama", "skills"), "project", true);
45675
- for (const d of ancestorDirs(options.cwd)) add3((0, import_node_path85.join)(d, ".agents", "skills"), "ancestor", true);
46056
+ add3((0, import_node_path86.join)(options.configDir, "skills"), "user", false);
46057
+ add3((0, import_node_path86.join)(options.cwd, ".ama", "skills"), "project", true);
46058
+ for (const d of ancestorDirs(options.cwd)) add3((0, import_node_path86.join)(d, ".agents", "skills"), "ancestor", true);
45676
46059
  return sources;
45677
46060
  }
45678
46061
  function parseSkill(text, location, scope) {
45679
46062
  const warnings = [];
45680
46063
  const fm = parseFrontmatter(text);
45681
46064
  for (const e of fm.errors) warnings.push(`${location}: ${e}`);
45682
- const baseDir = (0, import_node_path85.dirname)(location);
46065
+ const baseDir = (0, import_node_path86.dirname)(location);
45683
46066
  const rawName = fm.data["name"];
45684
- const name = typeof rawName === "string" && rawName !== "" ? rawName : (0, import_node_path85.basename)(baseDir);
46067
+ const name = typeof rawName === "string" && rawName !== "" ? rawName : (0, import_node_path86.basename)(baseDir);
45685
46068
  if (name.length > MAX_SKILL_NAME || !SKILL_NAME_RE.test(name)) {
45686
46069
  warnings.push(`${location}: invalid skill name "${name}" (lowercase letters, digits, -)`);
45687
46070
  return { warnings };
@@ -45719,8 +46102,8 @@ async function isDir3(path) {
45719
46102
  }
45720
46103
  async function findSkillFiles(dir, depth = 0) {
45721
46104
  if (depth > MAX_DEPTH2) return [];
45722
- const own = (0, import_node_path85.join)(dir, SKILL_FILE);
45723
- if ((0, import_node_fs62.existsSync)(own)) return [own];
46105
+ const own = (0, import_node_path86.join)(dir, SKILL_FILE);
46106
+ if ((0, import_node_fs63.existsSync)(own)) return [own];
45724
46107
  let names;
45725
46108
  try {
45726
46109
  names = await (0, import_promises23.readdir)(dir);
@@ -45731,7 +46114,7 @@ async function findSkillFiles(dir, depth = 0) {
45731
46114
  const out = [];
45732
46115
  for (const name of names) {
45733
46116
  if (SKIP_DIRS.has(name)) continue;
45734
- const child = (0, import_node_path85.join)(dir, name);
46117
+ const child = (0, import_node_path86.join)(dir, name);
45735
46118
  if (await isDir3(child)) out.push(...await findSkillFiles(child, depth + 1));
45736
46119
  }
45737
46120
  return out;
@@ -45772,13 +46155,13 @@ async function discoverSkills(sources, options) {
45772
46155
  }
45773
46156
  return result;
45774
46157
  }
45775
- var import_node_fs62, import_promises23, import_node_path85, SKILL_FILE, SKILL_NAME_RE, MAX_SKILL_NAME, MAX_SKILL_DESCRIPTION, MAX_DEPTH2, SKIP_DIRS;
46158
+ var import_node_fs63, import_promises23, import_node_path86, SKILL_FILE, SKILL_NAME_RE, MAX_SKILL_NAME, MAX_SKILL_DESCRIPTION, MAX_DEPTH2, SKIP_DIRS;
45776
46159
  var init_discover2 = __esm({
45777
46160
  "src/skills/discover.ts"() {
45778
46161
  "use strict";
45779
- import_node_fs62 = require("node:fs");
46162
+ import_node_fs63 = require("node:fs");
45780
46163
  import_promises23 = require("node:fs/promises");
45781
- import_node_path85 = require("node:path");
46164
+ import_node_path86 = require("node:path");
45782
46165
  init_frontmatter2();
45783
46166
  SKILL_FILE = "SKILL.md";
45784
46167
  SKILL_NAME_RE = /^[a-z0-9-]+$/;
@@ -45893,14 +46276,14 @@ var init_protocol = __esm({
45893
46276
 
45894
46277
  // src/codemode/host-side.ts
45895
46278
  function resolveSandboxEntry(moduleUrl = __ama_import_meta_url) {
45896
- const here = (0, import_node_path86.dirname)((0, import_node_url2.fileURLToPath)(moduleUrl));
46279
+ const here = (0, import_node_path87.dirname)((0, import_node_url2.fileURLToPath)(moduleUrl));
45897
46280
  const candidates2 = [];
45898
46281
  if (true)
45899
- candidates2.push((0, import_node_path86.join)(here, "ama-sandbox.cjs"));
45900
- candidates2.push((0, import_node_path86.join)(here, "sandbox-entry.js"));
45901
- candidates2.push((0, import_node_path86.join)(here, "sandbox-entry.ts"));
46282
+ candidates2.push((0, import_node_path87.join)(here, "ama-sandbox.cjs"));
46283
+ candidates2.push((0, import_node_path87.join)(here, "sandbox-entry.js"));
46284
+ candidates2.push((0, import_node_path87.join)(here, "sandbox-entry.ts"));
45902
46285
  for (const candidate of candidates2) {
45903
- if ((0, import_node_fs63.existsSync)(candidate)) return (0, import_node_fs63.realpathSync)(candidate);
46286
+ if ((0, import_node_fs64.existsSync)(candidate)) return (0, import_node_fs64.realpathSync)(candidate);
45904
46287
  }
45905
46288
  return void 0;
45906
46289
  }
@@ -46119,13 +46502,13 @@ async function runSandbox(request) {
46119
46502
  child.stdin.end();
46120
46503
  return result;
46121
46504
  }
46122
- var import_node_child_process16, import_node_fs63, import_node_path86, import_node_url2, MAX_COLLECTED_OUTPUT_CHARS, ABORT_GRACE_MS, CODEMODE_OS_POLICY;
46505
+ var import_node_child_process16, import_node_fs64, import_node_path87, import_node_url2, MAX_COLLECTED_OUTPUT_CHARS, ABORT_GRACE_MS, CODEMODE_OS_POLICY;
46123
46506
  var init_host_side = __esm({
46124
46507
  "src/codemode/host-side.ts"() {
46125
46508
  "use strict";
46126
46509
  import_node_child_process16 = require("node:child_process");
46127
- import_node_fs63 = require("node:fs");
46128
- import_node_path86 = require("node:path");
46510
+ import_node_fs64 = require("node:fs");
46511
+ import_node_path87 = require("node:path");
46129
46512
  import_node_url2 = require("node:url");
46130
46513
  init_detect();
46131
46514
  init_wrap();
@@ -46288,10 +46671,10 @@ ${output.slice(-half)}`;
46288
46671
  }
46289
46672
  function saveFullOutput(ctx, text) {
46290
46673
  try {
46291
- const dir = ctx.outputDir ?? (0, import_node_path87.join)((0, import_node_os13.tmpdir)(), "ama-codemode");
46292
- (0, import_node_fs64.mkdirSync)(dir, { recursive: true });
46293
- const file = (0, import_node_path87.join)(dir, `${ctx.toolCallId.replace(/[^A-Za-z0-9_-]/g, "_")}.txt`);
46294
- (0, import_node_fs64.writeFileSync)(file, text, "utf8");
46674
+ const dir = ctx.outputDir ?? (0, import_node_path88.join)((0, import_node_os13.tmpdir)(), "ama-codemode");
46675
+ (0, import_node_fs65.mkdirSync)(dir, { recursive: true });
46676
+ const file = (0, import_node_path88.join)(dir, `${ctx.toolCallId.replace(/[^A-Za-z0-9_-]/g, "_")}.txt`);
46677
+ (0, import_node_fs65.writeFileSync)(file, text, "utf8");
46295
46678
  return file;
46296
46679
  } catch {
46297
46680
  return void 0;
@@ -46440,14 +46823,14 @@ function codemodeToolFactory(overrides = {}) {
46440
46823
  return createCodemodeTool(options);
46441
46824
  };
46442
46825
  }
46443
- var import_node_fs64, import_node_os13, import_node_path87, CODEMODE_TOOL_NAME2, DEFAULT_MAX_TOOL_RESULT_CHARS2, CODEMODE_EXAMPLE, SCRIPT_ONLY_GLOBALS, TAIL_CHARS, CODEMODE_ONLY_GUIDELINE;
46826
+ var import_node_fs65, import_node_os13, import_node_path88, CODEMODE_TOOL_NAME2, DEFAULT_MAX_TOOL_RESULT_CHARS2, CODEMODE_EXAMPLE, SCRIPT_ONLY_GLOBALS, TAIL_CHARS, CODEMODE_ONLY_GUIDELINE;
46444
46827
  var init_tool = __esm({
46445
46828
  "src/codemode/tool.ts"() {
46446
46829
  "use strict";
46447
- import_node_fs64 = require("node:fs");
46830
+ import_node_fs65 = require("node:fs");
46448
46831
  import_node_os13 = require("node:os");
46449
- import_node_path87 = require("node:path");
46450
- init_presets();
46832
+ import_node_path88 = require("node:path");
46833
+ init_presets2();
46451
46834
  init_capability();
46452
46835
  init_declarations();
46453
46836
  init_host_side();
@@ -46558,7 +46941,7 @@ var init_tool2 = __esm({
46558
46941
  // src/cli/codemode-notice.ts
46559
46942
  function readNotices(path) {
46560
46943
  try {
46561
- const value = JSON.parse((0, import_node_fs65.readFileSync)(path, "utf8"));
46944
+ const value = JSON.parse((0, import_node_fs66.readFileSync)(path, "utf8"));
46562
46945
  if (typeof value === "object" && value !== null && !Array.isArray(value)) {
46563
46946
  const shown2 = value[KEY];
46564
46947
  return {
@@ -46577,27 +46960,27 @@ function takeCodemodeNotice(input2) {
46577
46960
  const resolved = resolveCodemodeMode(input2.config, input2.capability.strict);
46578
46961
  if (resolved.source !== "preset" || resolved.preset !== "default" || input2.capability.strict)
46579
46962
  return void 0;
46580
- const path = (0, import_node_path88.join)(input2.dataDir, NOTICES_FILE);
46963
+ const path = (0, import_node_path89.join)(input2.dataDir, NOTICES_FILE);
46581
46964
  const notices = readNotices(path);
46582
46965
  const shown2 = notices[KEY] ?? [];
46583
46966
  if (shown2.includes(input2.configDir)) return void 0;
46584
46967
  try {
46585
- (0, import_node_fs65.mkdirSync)(input2.dataDir, { recursive: true });
46968
+ (0, import_node_fs66.mkdirSync)(input2.dataDir, { recursive: true });
46586
46969
  const tmp = `${path}.${process.pid}.tmp`;
46587
- (0, import_node_fs65.writeFileSync)(tmp, `${JSON.stringify({ ...notices, [KEY]: [...shown2, input2.configDir] })}
46970
+ (0, import_node_fs66.writeFileSync)(tmp, `${JSON.stringify({ ...notices, [KEY]: [...shown2, input2.configDir] })}
46588
46971
  `);
46589
- (0, import_node_fs65.renameSync)(tmp, path);
46972
+ (0, import_node_fs66.renameSync)(tmp, path);
46590
46973
  } catch {
46591
46974
  }
46592
46975
  return codemodeNoticeText(input2.capability);
46593
46976
  }
46594
- var import_node_fs65, import_node_path88, NOTICES_FILE, KEY;
46977
+ var import_node_fs66, import_node_path89, NOTICES_FILE, KEY;
46595
46978
  var init_codemode_notice = __esm({
46596
46979
  "src/cli/codemode-notice.ts"() {
46597
46980
  "use strict";
46598
- import_node_fs65 = require("node:fs");
46599
- import_node_path88 = require("node:path");
46600
- init_presets();
46981
+ import_node_fs66 = require("node:fs");
46982
+ import_node_path89 = require("node:path");
46983
+ init_presets2();
46601
46984
  init_i18n();
46602
46985
  NOTICES_FILE = "notices.json";
46603
46986
  KEY = "codemodeNonStrictDefault";
@@ -46683,6 +47066,15 @@ async function buildProviderRegistry(input2, options = {}) {
46683
47066
  }
46684
47067
  if (provider !== void 0) registry2 = make({ provider, apiKey: cli.apiKey });
46685
47068
  }
47069
+ if (dataDir !== void 0) {
47070
+ const flavor = readOAuthEntry(input2.authFile, CHATGPT_PROVIDER_ID)?.flavor;
47071
+ mergeDiscoveredModels(
47072
+ registry2,
47073
+ dataDir,
47074
+ lazyIndex(() => loadModelsDevIndex(dataDir)),
47075
+ (id) => id === CHATGPT_PROVIDER_ID ? flavor : void 0
47076
+ );
47077
+ }
46686
47078
  const probe = options.probeLocal ?? env[NO_LOCAL_PROBE_ENV] !== "1";
46687
47079
  if (probe && config.defaultModel === void 0 && !anyKeyConfigured(registry2)) {
46688
47080
  await probeLocalProviders(registry2, options.probeTimeoutMs ?? LOCAL_PROBE_TIMEOUT_MS);
@@ -46714,8 +47106,10 @@ var init_compose_providers = __esm({
46714
47106
  "use strict";
46715
47107
  init_models_dev_cache();
46716
47108
  init_registry2();
47109
+ init_discovered_cache();
47110
+ init_enrich();
46717
47111
  init_token_store();
46718
- init_presets2();
47112
+ init_presets();
46719
47113
  LOCAL_PROBE_TIMEOUT_MS = 300;
46720
47114
  NO_LOCAL_PROBE_ENV = "AMA_NO_LOCAL_PROBE";
46721
47115
  }
@@ -46724,7 +47118,7 @@ var init_compose_providers = __esm({
46724
47118
  // src/modes/image-input.ts
46725
47119
  function expand(path, cwd) {
46726
47120
  const home = path === "~" || path.startsWith("~/") ? (0, import_node_os14.homedir)() + path.slice(1) : path;
46727
- return (0, import_node_path89.resolve)(cwd, home);
47121
+ return (0, import_node_path90.resolve)(cwd, home);
46728
47122
  }
46729
47123
  function findImageRefs(text, cwd) {
46730
47124
  const out = [];
@@ -46736,7 +47130,7 @@ function findImageRefs(text, cwd) {
46736
47130
  token = token.replace(/\\ /g, " ").replace(/[,\uFF0C\u3002;\uFF1B)\uFF09]+$/, "");
46737
47131
  if (token === "" || imageMimeFromPath(token) === void 0) continue;
46738
47132
  const path = expand(token, cwd);
46739
- if (!explicit && !(0, import_node_fs66.existsSync)(path)) continue;
47133
+ if (!explicit && !(0, import_node_fs67.existsSync)(path)) continue;
46740
47134
  if (seen.has(path)) continue;
46741
47135
  seen.add(path);
46742
47136
  out.push({ path, explicit });
@@ -46795,13 +47189,13 @@ async function loadLocalized(path, options) {
46795
47189
  throw error2;
46796
47190
  }
46797
47191
  }
46798
- var import_node_fs66, import_node_os14, import_node_path89, TOKEN;
47192
+ var import_node_fs67, import_node_os14, import_node_path90, TOKEN;
46799
47193
  var init_image_input = __esm({
46800
47194
  "src/modes/image-input.ts"() {
46801
47195
  "use strict";
46802
- import_node_fs66 = require("node:fs");
47196
+ import_node_fs67 = require("node:fs");
46803
47197
  import_node_os14 = require("node:os");
46804
- import_node_path89 = require("node:path");
47198
+ import_node_path90 = require("node:path");
46805
47199
  init_channels();
46806
47200
  init_errors();
46807
47201
  init_image_limits();
@@ -47353,6 +47747,116 @@ var init_rewind_text = __esm({
47353
47747
  }
47354
47748
  });
47355
47749
 
47750
+ // src/modes/interactive/model-items.ts
47751
+ function isHintValue(value) {
47752
+ return value.startsWith(HINT_PREFIX);
47753
+ }
47754
+ function modelDescription(model) {
47755
+ const ctx = model.contextWindow;
47756
+ const parts = [
47757
+ model.name !== "" && model.name !== model.id ? model.name : void 0,
47758
+ ctx === void 0 ? void 0 : ctx >= 1e6 ? `${Math.round(ctx / 1e5) / 10}M` : `${Math.round(ctx / 1e3)}k`,
47759
+ model.input.includes("image") ? "img" : void 0
47760
+ ].filter((x) => x !== void 0);
47761
+ return parts.length > 0 ? parts.join(" · ") : void 0;
47762
+ }
47763
+ async function loadModelCatalog(registry2) {
47764
+ const providers = [];
47765
+ for (const provider of registry2.list())
47766
+ providers.push({ provider, access: await providerAccess(registry2, provider) });
47767
+ return { providers };
47768
+ }
47769
+ function accessLabel(access) {
47770
+ const m = msg().panels.model;
47771
+ return access === "none" ? m.noKey : m[access];
47772
+ }
47773
+ function otherChannels(model) {
47774
+ return (model.channels ?? []).filter((c) => c !== "" && c !== model.channel);
47775
+ }
47776
+ function row2(model, group, channel) {
47777
+ const suffix = channel === void 0 ? "" : `@${channel}`;
47778
+ const item = {
47779
+ value: `${model.provider}/${model.id}${suffix}`,
47780
+ label: `${model.id}${suffix}`,
47781
+ group
47782
+ };
47783
+ const others = channel === void 0 ? otherChannels(model) : [];
47784
+ const parts = [
47785
+ modelDescription(model),
47786
+ others.length > 0 ? msg().panels.model.otherChannels(others.map((c) => `@${c}`).join(" ")) : void 0
47787
+ ].filter((x) => x !== void 0);
47788
+ if (parts.length > 0) item.description = parts.join(" · ");
47789
+ return item;
47790
+ }
47791
+ function hintRow(entry, group) {
47792
+ const { provider, access } = entry;
47793
+ if (provider.models.length > 0 || !provider.requiresApiKey) return void 0;
47794
+ const m = msg().panels.model;
47795
+ if (access === "key" || access === "oauth")
47796
+ return { value: `${HINT_PREFIX}${provider.id}`, label: m.discoverHint(provider.id), group };
47797
+ if (provider.id === CHATGPT_PROVIDER_ID)
47798
+ return { value: `${HINT_PREFIX}${provider.id}`, label: m.loginHint(provider.id), group };
47799
+ return void 0;
47800
+ }
47801
+ function catalogItems(catalog, options = {}) {
47802
+ const all = options.view === "all";
47803
+ const list5 = options.enabled !== void 0 && options.enabled.length > 0 ? options.enabled : void 0;
47804
+ const ready = [];
47805
+ const rest = [];
47806
+ for (const entry of catalog.providers) {
47807
+ const { provider, access } = entry;
47808
+ const isReady = accessReady(access);
47809
+ const group = `${provider.id} · ${accessLabel(access)}`;
47810
+ const items = [];
47811
+ const listedProvider = list5?.includes(`${provider.id}/*`) === true;
47812
+ for (const model of provider.models) {
47813
+ const main2 = row2(model, group);
47814
+ const listed2 = list5 !== void 0 && enabledMatch(list5, main2.value) !== void 0;
47815
+ const shown2 = all || (list5 !== void 0 ? listed2 : isReady);
47816
+ if (shown2) {
47817
+ if (all && listed2) main2.badge = msg().panels.model.listed;
47818
+ if (all && listed2) main2.badgeColor = "dim";
47819
+ items.push(main2);
47820
+ }
47821
+ for (const channel of otherChannels(model)) {
47822
+ const extra = row2(model, group, channel);
47823
+ const exact = list5?.includes(extra.value) === true;
47824
+ if (exact || shown2 && options.channels === true) items.push(extra);
47825
+ }
47826
+ }
47827
+ const hint = options.hints === false ? void 0 : hintRow(entry, group);
47828
+ if (hint !== void 0 && (all || (list5 !== void 0 ? listedProvider : isReady)))
47829
+ items.push(hint);
47830
+ (isReady ? ready : rest).push(...items);
47831
+ }
47832
+ return pinCurrent(catalog, [...ready, ...rest], options.current);
47833
+ }
47834
+ function pinCurrent(catalog, items, current3) {
47835
+ if (current3 === void 0 || current3 === "" || items.some((i) => i.value === current3))
47836
+ return items;
47837
+ const slash = current3.indexOf("/");
47838
+ const at = current3.lastIndexOf("@");
47839
+ const base4 = at > slash ? current3.slice(0, at) : current3;
47840
+ const model = catalog.providers.find((p) => p.provider.id === current3.slice(0, slash))?.provider.models.find((m) => `${m.provider}/${m.id}` === base4);
47841
+ const item = { value: current3, label: current3, group: msg().panels.model.current };
47842
+ const description = model === void 0 ? void 0 : modelDescription(model);
47843
+ if (description !== void 0) item.description = description;
47844
+ return [item, ...items];
47845
+ }
47846
+ async function modelItems(registry2, options = {}) {
47847
+ return catalogItems(await loadModelCatalog(registry2), options);
47848
+ }
47849
+ var HINT_PREFIX;
47850
+ var init_model_items = __esm({
47851
+ "src/modes/interactive/model-items.ts"() {
47852
+ "use strict";
47853
+ init_model_visibility();
47854
+ init_presets();
47855
+ init_i18n();
47856
+ HINT_PREFIX = "ama:hint:";
47857
+ }
47858
+ });
47859
+
47356
47860
  // src/modes/interactive/startup-ui.ts
47357
47861
  var startup_ui_exports = {};
47358
47862
  __export(startup_ui_exports, {
@@ -47456,54 +47960,6 @@ function askText(r, prompt) {
47456
47960
  tui.setFocus(editor);
47457
47961
  });
47458
47962
  }
47459
- function modelDescription(model) {
47460
- const ctx = model.contextWindow;
47461
- const parts = [
47462
- model.name !== "" && model.name !== model.id ? model.name : void 0,
47463
- ctx === void 0 ? void 0 : ctx >= 1e6 ? `${Math.round(ctx / 1e5) / 10}M` : `${Math.round(ctx / 1e3)}k`,
47464
- model.input.includes("image") ? "img" : void 0
47465
- ].filter((x) => x !== void 0);
47466
- return parts.length > 0 ? parts.join(" · ") : void 0;
47467
- }
47468
- async function modelItems(providers) {
47469
- const groups = [];
47470
- for (const provider of providers.list()) {
47471
- if (provider.models.length === 0) continue;
47472
- let status;
47473
- let ready = true;
47474
- if (!provider.requiresApiKey) status = msg().interactive.startup.ui.local;
47475
- else {
47476
- const key = await providers.resolveApiKey(provider.id).catch(() => ({ apiKey: void 0 }));
47477
- ready = key.apiKey !== void 0;
47478
- status = ready ? "key ✓" : msg().interactive.startup.ui.noKey;
47479
- }
47480
- const item = (model, group, channel) => {
47481
- const suffix = channel !== void 0 && channel !== model.channel ? `@${channel}` : "";
47482
- const out = {
47483
- value: `${provider.id}/${model.id}${suffix}`,
47484
- label: `${model.id}${suffix}`,
47485
- group
47486
- };
47487
- const description = modelDescription(model);
47488
- if (description !== void 0) out.description = description;
47489
- return out;
47490
- };
47491
- if (provider.channels === void 0) {
47492
- const group = `${provider.id} · ${status}`;
47493
- groups.push({ ready, items: provider.models.map((model) => item(model, group)) });
47494
- continue;
47495
- }
47496
- for (const channel of provider.channels) {
47497
- const group = `${provider.id} · ${channel.name} · ${status}`;
47498
- const models = provider.models.filter((m) => m.channels?.includes(channel.name));
47499
- if (models.length > 0)
47500
- groups.push({ ready, items: models.map((model) => item(model, group, channel.name)) });
47501
- }
47502
- }
47503
- return [...groups.filter((g) => g.ready), ...groups.filter((g) => !g.ready)].flatMap(
47504
- (g) => g.items
47505
- );
47506
- }
47507
47963
  function relativeTime(iso, now) {
47508
47964
  const at = Date.parse(iso);
47509
47965
  if (!Number.isFinite(at)) return "";
@@ -47539,7 +47995,7 @@ function trustChoices() {
47539
47995
  }
47540
47996
  function isDirectory2(path) {
47541
47997
  try {
47542
- return (0, import_node_fs67.statSync)(path).isDirectory();
47998
+ return (0, import_node_fs68.statSync)(path).isDirectory();
47543
47999
  } catch {
47544
48000
  return false;
47545
48001
  }
@@ -47573,7 +48029,9 @@ function createStartupUi(options = {}) {
47573
48029
  return picked?.value;
47574
48030
  },
47575
48031
  async pickModel(providers, reason) {
47576
- const items = await modelItems(providers);
48032
+ const catalog = await loadModelCatalog(providers);
48033
+ let items = catalogItems(catalog, { hints: false });
48034
+ if (items.length === 0) items = catalogItems(catalog, { view: "all", hints: false });
47577
48035
  if (items.length === 0) return void 0;
47578
48036
  const picked = await askSelect(r, {
47579
48037
  title: msg().interactive.startup.ui.modelTitle,
@@ -47591,8 +48049,8 @@ function createStartupUi(options = {}) {
47591
48049
  placeholder: m.cwdPlaceholder,
47592
48050
  validate: (text) => {
47593
48051
  if (text === "") return m.cwdEmpty;
47594
- const abs = (0, import_node_path90.resolve)(text);
47595
- if (!(0, import_node_fs67.existsSync)(abs)) return m.cwdMissing(abs);
48052
+ const abs = (0, import_node_path91.resolve)(text);
48053
+ if (!(0, import_node_fs68.existsSync)(abs)) return m.cwdMissing(abs);
47596
48054
  if (!isDirectory2(abs)) return m.cwdNotDir(abs);
47597
48055
  return void 0;
47598
48056
  }
@@ -47600,14 +48058,16 @@ function createStartupUi(options = {}) {
47600
48058
  }
47601
48059
  };
47602
48060
  }
47603
- var import_node_fs67, import_node_path90;
48061
+ var import_node_fs68, import_node_path91;
47604
48062
  var init_startup_ui = __esm({
47605
48063
  "src/modes/interactive/startup-ui.ts"() {
47606
48064
  "use strict";
47607
48065
  init_i18n();
47608
- import_node_fs67 = require("node:fs");
47609
- import_node_path90 = require("node:path");
48066
+ import_node_fs68 = require("node:fs");
48067
+ import_node_path91 = require("node:path");
47610
48068
  init_tui2();
48069
+ init_model_items();
48070
+ init_model_items();
47611
48071
  }
47612
48072
  });
47613
48073
 
@@ -48585,7 +49045,7 @@ function startupInfo(runtime, home) {
48585
49045
  permissionMode: runtime.session.state.permissionMode,
48586
49046
  preset: runtime.config.tools?.preset ?? "default",
48587
49047
  codemode: effectiveCodemodeMode(runtime.config),
48588
- contextFiles: resources.contextFiles.map((f) => (0, import_node_path91.basename)(f.path)),
49048
+ contextFiles: resources.contextFiles.map((f) => (0, import_node_path92.basename)(f.path)),
48589
49049
  skills: resources.skills.filter((s2) => !isBuiltinSkill(s2)).length,
48590
49050
  prompts: resources.prompts.length,
48591
49051
  hooks: runtime.hooks.list().length,
@@ -48594,14 +49054,14 @@ function startupInfo(runtime, home) {
48594
49054
  if (runtime.host !== void 0) info2.host = runtime.host.adapter.id;
48595
49055
  return info2;
48596
49056
  }
48597
- var import_node_path91;
49057
+ var import_node_path92;
48598
49058
  var init_startup_screen = __esm({
48599
49059
  "src/cli/startup-screen.ts"() {
48600
49060
  "use strict";
48601
49061
  init_builtin3();
48602
- import_node_path91 = require("node:path");
49062
+ import_node_path92 = require("node:path");
48603
49063
  init_channels();
48604
- init_presets();
49064
+ init_presets2();
48605
49065
  init_i18n();
48606
49066
  init_version();
48607
49067
  }
@@ -48644,7 +49104,7 @@ function settingRows(snapshot2, scope, theme) {
48644
49104
  noteColor = "warning";
48645
49105
  } else if (scope === "project" && spec2.project !== "any") note = s2.projectNote[spec2.project];
48646
49106
  else if (value.source !== "default") note = s2.source(value.source);
48647
- const row2 = {
49107
+ const row3 = {
48648
49108
  id: spec2.key,
48649
49109
  group: s2.groups[spec2.group],
48650
49110
  label: labels[spec2.key] ?? spec2.key,
@@ -48652,11 +49112,11 @@ function settingRows(snapshot2, scope, theme) {
48652
49112
  tag,
48653
49113
  search: [...spec2.options ?? [], settingDoc(spec2.key) ?? ""].join(" ")
48654
49114
  };
48655
- if (value.value === void 0) row2.valueColor = "dim";
48656
- if (note !== void 0) row2.note = note;
48657
- if (noteColor !== void 0) row2.noteColor = noteColor;
48658
- if (scope === "project" && spec2.project === "deny") row2.dim = true;
48659
- return row2;
49115
+ if (value.value === void 0) row3.valueColor = "dim";
49116
+ if (note !== void 0) row3.note = note;
49117
+ if (noteColor !== void 0) row3.noteColor = noteColor;
49118
+ if (scope === "project" && spec2.project === "deny") row3.dim = true;
49119
+ return row3;
48660
49120
  });
48661
49121
  for (const hint of SETTING_HINTS) {
48662
49122
  rows.push({
@@ -48738,7 +49198,7 @@ var init_config_panel = __esm({
48738
49198
  if (this.busy) return;
48739
49199
  const keys = this.deps.keybindings ?? defaultKeybindings;
48740
49200
  if (this.edit !== void 0) return this.editInput(data2);
48741
- const row2 = this.list.selectedRow;
49201
+ const row3 = this.list.selectedRow;
48742
49202
  const unsetKey = matchesKey(data2, "backspace") || matchesKey(data2, "delete");
48743
49203
  if (!unsetKey || this.searching) this.pendingUnset = void 0;
48744
49204
  if (keys.matches(data2, "tui.select.up")) return this.move(-1);
@@ -48758,8 +49218,8 @@ var init_config_panel = __esm({
48758
49218
  return;
48759
49219
  }
48760
49220
  if (this.searching) {
48761
- if (matchesKey(data2, "enter") && row2 !== void 0)
48762
- return this.run(this.deps.activate(row2.id, this.scope));
49221
+ if (matchesKey(data2, "enter") && row3 !== void 0)
49222
+ return this.run(this.deps.activate(row3.id, this.scope));
48763
49223
  if (matchesKey(data2, "backspace"))
48764
49224
  return this.list.setQuery([...this.list.query].slice(0, -1).join(""));
48765
49225
  const text = isPasteData(data2) ? unwrapPaste(data2) : isPrintableText(data2) ? data2 : "";
@@ -48770,20 +49230,20 @@ var init_config_panel = __esm({
48770
49230
  this.searching = true;
48771
49231
  return;
48772
49232
  }
48773
- if (row2 === void 0) return;
49233
+ if (row3 === void 0) return;
48774
49234
  if (matchesKey(data2, "enter") || matchesKey(data2, "space")) {
48775
49235
  this.notice = void 0;
48776
- const hint = hintOf(row2.id);
49236
+ const hint = hintOf(row3.id);
48777
49237
  if (hint !== void 0) return this.setNotice(hint);
48778
- return this.run(this.deps.activate(row2.id, this.scope));
49238
+ return this.run(this.deps.activate(row3.id, this.scope));
48779
49239
  }
48780
- if (unsetKey && hintOf(row2.id) === void 0) {
48781
- if (this.pendingUnset === row2.id) {
49240
+ if (unsetKey && hintOf(row3.id) === void 0) {
49241
+ if (this.pendingUnset === row3.id) {
48782
49242
  this.pendingUnset = void 0;
48783
- return this.run(this.deps.unset(row2.id, this.scope));
49243
+ return this.run(this.deps.unset(row3.id, this.scope));
48784
49244
  }
48785
- this.pendingUnset = row2.id;
48786
- this.setNotice(msg().settings.confirmUnset(row2.id), "warning");
49245
+ this.pendingUnset = row3.id;
49246
+ this.setNotice(msg().settings.confirmUnset(row3.id), "warning");
48787
49247
  }
48788
49248
  }
48789
49249
  move(delta) {
@@ -48862,13 +49322,13 @@ var init_config_panel = __esm({
48862
49322
  }
48863
49323
  description(width2) {
48864
49324
  const { theme } = this.deps;
48865
- const row2 = this.list.selectedRow;
48866
- if (row2 === void 0 || hintOf(row2.id) !== void 0) return [];
48867
- const doc = settingDoc(row2.id) ?? "";
48868
- const value = getConfigValue(this.snapshot, row2.id);
48869
- const dynamic = value.value === void 0 ? settingDynamicDefault(row2.id) : void 0;
49325
+ const row3 = this.list.selectedRow;
49326
+ if (row3 === void 0 || hintOf(row3.id) !== void 0) return [];
49327
+ const doc = settingDoc(row3.id) ?? "";
49328
+ const value = getConfigValue(this.snapshot, row3.id);
49329
+ const dynamic = value.value === void 0 ? settingDynamicDefault(row3.id) : void 0;
48870
49330
  const text = dynamic === void 0 ? doc : `${doc} · ${dynamic}`;
48871
- const spec2 = settingsRegistry().find((x) => x.key === row2.id);
49331
+ const spec2 = settingsRegistry().find((x) => x.key === row3.id);
48872
49332
  const blocked = spec2 === void 0 ? void 0 : blockedReason(spec2, value, this.scope);
48873
49333
  const lines2 = blocked === void 0 ? [] : [theme.fg("warning", truncateToWidth(blocked, width2))];
48874
49334
  if (text !== "") lines2.push(...wrapTextWithAnsi(theme.fg("dim", text), width2));
@@ -49944,7 +50404,8 @@ var init_config_ui = __esm({
49944
50404
  else if (spec2.kind === "model")
49945
50405
  items = [
49946
50406
  ...await modelItems(
49947
- hideFakeProvider(this.deps.runtime.providers, this.deps.context.io.env)
50407
+ hideFakeProvider(this.deps.runtime.providers, this.deps.context.io.env),
50408
+ { current: current3, enabled: this.deps.runtime.config.models?.enabled, hints: false }
49948
50409
  ),
49949
50410
  { value: "", label: s2.defaultChoice }
49950
50411
  ];
@@ -50197,29 +50658,29 @@ function runEditor(command3, file) {
50197
50658
  return result.status;
50198
50659
  }
50199
50660
  async function editExternally(text, name, deps) {
50200
- const dir = (0, import_node_fs68.mkdtempSync)((0, import_node_path92.join)((0, import_node_os15.tmpdir)(), "ama-edit-"));
50201
- const file = (0, import_node_path92.join)(dir, name);
50202
- (0, import_node_fs68.writeFileSync)(file, text);
50661
+ const dir = (0, import_node_fs69.mkdtempSync)((0, import_node_path93.join)((0, import_node_os15.tmpdir)(), "ama-edit-"));
50662
+ const file = (0, import_node_path93.join)(dir, name);
50663
+ (0, import_node_fs69.writeFileSync)(file, text);
50203
50664
  deps.suspend();
50204
50665
  try {
50205
50666
  const code = (deps.run ?? runEditor)(editorCommand(deps.env, deps.platform), file);
50206
50667
  if (code !== 0) return void 0;
50207
- return (0, import_node_fs68.readFileSync)(file, "utf8");
50668
+ return (0, import_node_fs69.readFileSync)(file, "utf8");
50208
50669
  } catch {
50209
50670
  return void 0;
50210
50671
  } finally {
50211
50672
  deps.resume();
50212
- (0, import_node_fs68.rmSync)(dir, { recursive: true, force: true });
50673
+ (0, import_node_fs69.rmSync)(dir, { recursive: true, force: true });
50213
50674
  }
50214
50675
  }
50215
- var import_node_child_process17, import_node_fs68, import_node_os15, import_node_path92;
50676
+ var import_node_child_process17, import_node_fs69, import_node_os15, import_node_path93;
50216
50677
  var init_external_editor = __esm({
50217
50678
  "src/modes/interactive/external-editor.ts"() {
50218
50679
  "use strict";
50219
50680
  import_node_child_process17 = require("node:child_process");
50220
- import_node_fs68 = require("node:fs");
50681
+ import_node_fs69 = require("node:fs");
50221
50682
  import_node_os15 = require("node:os");
50222
- import_node_path92 = require("node:path");
50683
+ import_node_path93 = require("node:path");
50223
50684
  }
50224
50685
  });
50225
50686
 
@@ -51016,10 +51477,10 @@ var init_tool_view = __esm({
51016
51477
  del: "error",
51017
51478
  ctx: "muted"
51018
51479
  };
51019
- const styled = shown2.map((row2) => {
51020
- if (!numbers || row2.kind === "hunk") return theme.fg(color[row2.kind], row2.text);
51021
- const no = theme.fg("dim", String(row2.num ?? "").padStart(numWidth));
51022
- return `${no} ${theme.fg(color[row2.kind], row2.text)}`;
51480
+ const styled = shown2.map((row3) => {
51481
+ if (!numbers || row3.kind === "hunk") return theme.fg(color[row3.kind], row3.text);
51482
+ const no = theme.fg("dim", String(row3.num ?? "").padStart(numWidth));
51483
+ return `${no} ${theme.fg(color[row3.kind], row3.text)}`;
51023
51484
  });
51024
51485
  const out = this.indent(styled, width2);
51025
51486
  if (rows.length > shown2.length) out.push(this.more(rows.length - shown2.length));
@@ -51939,7 +52400,7 @@ function taskNumber(taskId) {
51939
52400
  return n === null ? Number.MAX_SAFE_INTEGER : Number(n[1]);
51940
52401
  }
51941
52402
  function compareRows(a, b) {
51942
- const group = (row2) => ACTIVE.has(row2.status) ? 0 : 1;
52403
+ const group = (row3) => ACTIVE.has(row3.status) ? 0 : 1;
51943
52404
  return group(a) - group(b) || taskNumber(a.taskId) - taskNumber(b.taskId);
51944
52405
  }
51945
52406
  function statusLabel(status) {
@@ -51966,7 +52427,7 @@ function taskRow(info2, ctx) {
51966
52427
  else if (ctx.approvals.has(info2.taskId)) status = "approval";
51967
52428
  else if (ctx.queued) status = "queued";
51968
52429
  else status = "running";
51969
- const row2 = {
52430
+ const row3 = {
51970
52431
  taskId: info2.taskId,
51971
52432
  agent: info2.agent,
51972
52433
  runner: info2.runner,
@@ -51975,21 +52436,21 @@ function taskRow(info2, ctx) {
51975
52436
  turns: Math.max(state?.turns ?? 0, info2.turns ?? 0)
51976
52437
  };
51977
52438
  const tool = state?.tools.at(-1);
51978
- if (tool !== void 0 && status !== "queued") row2.tool = tool;
52439
+ if (tool !== void 0 && status !== "queued") row3.tool = tool;
51979
52440
  if (status !== "queued") {
51980
- if (state !== void 0) row2.elapsedMs = (state.endedAt ?? ctx.now) - state.startedAt;
51981
- else if (info2.endedAt !== void 0) row2.elapsedMs = info2.endedAt - info2.startedAt;
52441
+ if (state !== void 0) row3.elapsedMs = (state.endedAt ?? ctx.now) - state.startedAt;
52442
+ else if (info2.endedAt !== void 0) row3.elapsedMs = info2.endedAt - info2.startedAt;
51982
52443
  }
51983
- return row2;
52444
+ return row3;
51984
52445
  }
51985
- function agentLabel(row2) {
51986
- return row2.runner !== "ama" && row2.runner !== row2.agent ? `${row2.agent}(${row2.runner})` : row2.agent;
52446
+ function agentLabel(row3) {
52447
+ return row3.runner !== "ama" && row3.runner !== row3.agent ? `${row3.agent}(${row3.runner})` : row3.agent;
51987
52448
  }
51988
- function rowFacts(row2, withTool = true) {
51989
- const facts = [statusLabel(row2.status)];
51990
- if (row2.elapsedMs !== void 0) facts[0] += ` ${formatElapsed(row2.elapsedMs)}`;
51991
- if (row2.turns > 0) facts.push(msg().agents.turns(row2.turns));
51992
- if (withTool && row2.tool !== void 0 && row2.status === "running") facts.push(row2.tool);
52449
+ function rowFacts(row3, withTool = true) {
52450
+ const facts = [statusLabel(row3.status)];
52451
+ if (row3.elapsedMs !== void 0) facts[0] += ` ${formatElapsed(row3.elapsedMs)}`;
52452
+ if (row3.turns > 0) facts.push(msg().agents.turns(row3.turns));
52453
+ if (withTool && row3.tool !== void 0 && row3.status === "running") facts.push(row3.tool);
51993
52454
  return facts.join(" · ");
51994
52455
  }
51995
52456
  var BAR_ROWS, BAR_RETAIN_MS, ACTIVE, AgentBar;
@@ -52028,11 +52489,11 @@ var init_agent_bar = __esm({
52028
52489
  visibleRows() {
52029
52490
  if (!this.deps.enabled()) return [];
52030
52491
  const now = this.deps.now();
52031
- return this.all().filter((row2) => {
52032
- if (ACTIVE.has(row2.status)) return true;
52033
- if (this.deps.tracker.get(row2.taskId) === void 0 || this.viewed.has(row2.taskId))
52492
+ return this.all().filter((row3) => {
52493
+ if (ACTIVE.has(row3.status)) return true;
52494
+ if (this.deps.tracker.get(row3.taskId) === void 0 || this.viewed.has(row3.taskId))
52034
52495
  return false;
52035
- const seen = this.endedSeen.get(row2.taskId);
52496
+ const seen = this.endedSeen.get(row3.taskId);
52036
52497
  return seen !== void 0 && now - seen < BAR_RETAIN_MS;
52037
52498
  });
52038
52499
  }
@@ -52067,7 +52528,7 @@ var init_agent_bar = __esm({
52067
52528
  /** 聚焦时选中某任务。 */
52068
52529
  select(taskId) {
52069
52530
  if (this.index === void 0) return;
52070
- const at = this.all().findIndex((row2) => row2.taskId === taskId);
52531
+ const at = this.all().findIndex((row3) => row3.taskId === taskId);
52071
52532
  if (at >= 0) this.index = at;
52072
52533
  }
52073
52534
  /** 查看过(视图里看到了结束后的状态):不再留在栏里。 */
@@ -52081,17 +52542,17 @@ var init_agent_bar = __esm({
52081
52542
  this.viewed.clear();
52082
52543
  }
52083
52544
  row(info2, approvals, now) {
52084
- const row2 = taskRow(info2, {
52545
+ const row3 = taskRow(info2, {
52085
52546
  tracker: this.deps.tracker,
52086
52547
  approvals,
52087
52548
  queued: this.deps.registry()?.live(info2.taskId)?.queued === true,
52088
52549
  now
52089
52550
  });
52090
- if (ACTIVE.has(row2.status)) {
52551
+ if (ACTIVE.has(row3.status)) {
52091
52552
  this.endedSeen.delete(info2.taskId);
52092
52553
  this.viewed.delete(info2.taskId);
52093
52554
  } else if (!this.endedSeen.has(info2.taskId)) this.endedSeen.set(info2.taskId, now);
52094
- return row2;
52555
+ return row3;
52095
52556
  }
52096
52557
  render(width2) {
52097
52558
  const focused = this.index !== void 0;
@@ -52108,7 +52569,7 @@ var init_agent_bar = __esm({
52108
52569
  start = this.top;
52109
52570
  }
52110
52571
  const shown2 = rows.slice(start, start + BAR_ROWS);
52111
- const out = shown2.map((row2, i) => this.line(row2, width2, focused, start + i === this.index));
52572
+ const out = shown2.map((row3, i) => this.line(row3, width2, focused, start + i === this.index));
52112
52573
  const hidden = rows.length - shown2.length;
52113
52574
  const tail = [];
52114
52575
  if (hidden > 0) tail.push(m.bar.more(hidden));
@@ -52117,15 +52578,15 @@ var init_agent_bar = __esm({
52117
52578
  out.push(truncateToWidth(t.fg("dim", tail.join(" · ")), width2, t.glyphs.ellipsis));
52118
52579
  return out;
52119
52580
  }
52120
- line(row2, width2, focused, selected) {
52581
+ line(row3, width2, focused, selected) {
52121
52582
  const t = this.deps.theme;
52122
52583
  const g = t.glyphs;
52123
- const agent = agentLabel(row2);
52584
+ const agent = agentLabel(row3);
52124
52585
  const lead = focused ? (selected ? t.fg("accent", g.prompt) : " ") + " " : "";
52125
- const marker = t.fg(statusColor(row2.status), g.tool);
52126
- const id = selected ? t.bold(row2.taskId) : row2.taskId;
52127
- const description = row2.description.replace(/\s+/g, " ").trim();
52128
- const text = `${lead}${marker} ${id} ${t.fg("tool", agent)}` + t.fg("dim", " · ") + t.fg(row2.status === "approval" ? "warning" : "muted", rowFacts(row2)) + (description === "" ? "" : ` ${t.fg("dim", description)}`);
52586
+ const marker = t.fg(statusColor(row3.status), g.tool);
52587
+ const id = selected ? t.bold(row3.taskId) : row3.taskId;
52588
+ const description = row3.description.replace(/\s+/g, " ").trim();
52589
+ const text = `${lead}${marker} ${id} ${t.fg("tool", agent)}` + t.fg("dim", " · ") + t.fg(row3.status === "approval" ? "warning" : "muted", rowFacts(row3)) + (description === "" ? "" : ` ${t.fg("dim", description)}`);
52129
52590
  return truncateToWidth(text, width2, g.ellipsis);
52130
52591
  }
52131
52592
  invalidate() {
@@ -52500,7 +52961,7 @@ var init_agent_view = __esm({
52500
52961
  const registry2 = this.deps.registry();
52501
52962
  const info2 = registry2?.get(this.taskId);
52502
52963
  if (info2 === void 0) return truncateToWidth(t.bold(this.taskId), width2);
52503
- const row2 = taskRow(info2, {
52964
+ const row3 = taskRow(info2, {
52504
52965
  tracker: this.deps.tracker,
52505
52966
  approvals: this.deps.approvals(),
52506
52967
  queued: registry2?.live(this.taskId)?.queued === true,
@@ -52511,9 +52972,9 @@ var init_agent_view = __esm({
52511
52972
  const tokens = usage !== void 0 && usage.input + usage.output + usage.cacheRead > 0 ? `${g.arrowUp}${formatTokenCount(usage.input + usage.cacheRead + usage.cacheWrite)} ${g.arrowDown}${formatTokenCount(usage.output)}` : void 0;
52512
52973
  const stop = info2.status === "running" ? m.stopHint(this.taskId) : void 0;
52513
52974
  const compose = (withTokens, withStop) => {
52514
- const facts = [rowFacts(row2, false), ...withTokens && tokens ? [tokens] : []];
52975
+ const facts = [rowFacts(row3, false), ...withTokens && tokens ? [tokens] : []];
52515
52976
  const hints = [m.back, ...withStop && stop ? [stop] : []];
52516
- return t.bold(`${this.taskId} ${agentLabel(row2)}`) + t.fg("dim", " · ") + t.fg(statusColor(row2.status), facts.join(" · ")) + t.fg("dim", ` · ${hints.join(" · ")}`);
52977
+ return t.bold(`${this.taskId} ${agentLabel(row3)}`) + t.fg("dim", " · ") + t.fg(statusColor(row3.status), facts.join(" · ")) + t.fg("dim", ` · ${hints.join(" · ")}`);
52517
52978
  };
52518
52979
  for (const [withTokens, withStop] of [
52519
52980
  [true, true],
@@ -53532,7 +53993,7 @@ var init_agent_ui = __esm({
53532
53993
  now: () => this.deps.now(),
53533
53994
  rows: () => this.deps.tui.terminal.rows,
53534
53995
  render: () => this.deps.render(),
53535
- siblings: () => this.bar.all().map((row2) => row2.taskId),
53996
+ siblings: () => this.bar.all().map((row3) => row3.taskId),
53536
53997
  close: () => this.closeView(),
53537
53998
  stop: (id) => stopTask(this.deps.session().state.sessionId, id),
53538
53999
  messages: {
@@ -53706,18 +54167,21 @@ async function handlePick(what, ui) {
53706
54167
  case "model": {
53707
54168
  const current3 = session.state.model;
53708
54169
  const ref = current3 === void 0 ? void 0 : `${current3.provider}/${current3.id}`;
53709
- const picked = await ui.pick({
54170
+ const providers = ui.env === void 0 ? ui.runtime.providers : hideFakeProvider(ui.runtime.providers, ui.env);
54171
+ const picked = ui.pickModel !== void 0 ? await ui.pickModel(providers, ref) : (await ui.pick({
53710
54172
  title: m.modelTitle,
53711
- items: await modelItems(
53712
- ui.env === void 0 ? ui.runtime.providers : hideFakeProvider(ui.runtime.providers, ui.env)
53713
- ),
54173
+ items: await modelItems(providers, {
54174
+ current: ref,
54175
+ enabled: ui.runtime.config.models?.enabled,
54176
+ hints: false
54177
+ }),
53714
54178
  filterable: true,
53715
54179
  showCount: true,
53716
54180
  ...ref !== void 0 ? { selected: ref, currentValue: ref } : {}
53717
- });
54181
+ }))?.value;
53718
54182
  if (picked === void 0) return;
53719
- await session.setModel(picked.value);
53720
- ui.notice("info", m.modelSet(picked.value));
54183
+ await session.setModel(picked);
54184
+ ui.notice("info", m.modelSet(picked));
53721
54185
  return;
53722
54186
  }
53723
54187
  case "session": {
@@ -54098,17 +54562,17 @@ async function readHead2(cwd) {
54098
54562
  }
54099
54563
  const gitDir = await findGitDir(cwd);
54100
54564
  if (gitDir === void 0) return void 0;
54101
- const text = await (0, import_promises24.readFile)((0, import_node_path93.join)(gitDir, "HEAD"), "utf8").catch(() => void 0);
54565
+ const text = await (0, import_promises24.readFile)((0, import_node_path94.join)(gitDir, "HEAD"), "utf8").catch(() => void 0);
54102
54566
  const match = /^ref:\s*refs\/heads\/(\S+)\s*$/.exec(text ?? "");
54103
54567
  return match?.[1] !== void 0 ? { branch: match[1] } : void 0;
54104
54568
  }
54105
- var import_node_child_process18, import_promises24, import_node_path93, GIT_NUMSTAT_INTERVAL_MS, GIT_NUMSTAT_TIMEOUT_MS, sameInfo, GitInfoWatcher;
54569
+ var import_node_child_process18, import_promises24, import_node_path94, GIT_NUMSTAT_INTERVAL_MS, GIT_NUMSTAT_TIMEOUT_MS, sameInfo, GitInfoWatcher;
54106
54570
  var init_info = __esm({
54107
54571
  "src/git/info.ts"() {
54108
54572
  "use strict";
54109
54573
  import_node_child_process18 = require("node:child_process");
54110
54574
  import_promises24 = require("node:fs/promises");
54111
- import_node_path93 = require("node:path");
54575
+ import_node_path94 = require("node:path");
54112
54576
  init_git_head();
54113
54577
  GIT_NUMSTAT_INTERVAL_MS = 1e4;
54114
54578
  GIT_NUMSTAT_TIMEOUT_MS = 2e3;
@@ -54358,18 +54822,18 @@ function statusLineText(mode) {
54358
54822
  const m = msg().interactive.statusLine;
54359
54823
  return mode === "full" ? m.full : m.compact;
54360
54824
  }
54361
- var import_node_path94, WRITE_TOOLS3, HintLine, StatusArea;
54825
+ var import_node_path95, WRITE_TOOLS3, HintLine, StatusArea;
54362
54826
  var init_status_area = __esm({
54363
54827
  "src/modes/interactive/status-area.ts"() {
54364
54828
  "use strict";
54365
54829
  init_i18n();
54366
- import_node_path94 = require("node:path");
54830
+ import_node_path95 = require("node:path");
54367
54831
  init_capability();
54368
54832
  init_channels();
54369
54833
  init_info();
54370
54834
  init_bash();
54371
54835
  init_detect();
54372
- init_presets();
54836
+ init_presets2();
54373
54837
  init_tui2();
54374
54838
  init_status_bar();
54375
54839
  init_status_line();
@@ -54497,7 +54961,7 @@ var init_status_area = __esm({
54497
54961
  gitView() {
54498
54962
  const cwd = this.gitCwd;
54499
54963
  if (cwd === void 0) return void 0;
54500
- return { dir: (0, import_node_path94.basename)(cwd), info: this.git?.current() };
54964
+ return { dir: (0, import_node_path95.basename)(cwd), info: this.git?.current() };
54501
54965
  }
54502
54966
  watchGit() {
54503
54967
  const cwd = this.deps.session().state.cwd;
@@ -54669,6 +55133,184 @@ var init_key_dispatch = __esm({
54669
55133
  }
54670
55134
  });
54671
55135
 
55136
+ // src/modes/interactive/model-picker.ts
55137
+ async function openModelPicker(host, options) {
55138
+ const catalog = await loadModelCatalog(options.providers);
55139
+ return new Promise((resolve38) => {
55140
+ let handle;
55141
+ const view = new ModelPickerView(host, catalog, options, (ref) => {
55142
+ handle?.hide();
55143
+ resolve38(ref);
55144
+ });
55145
+ const width2 = Math.max(20, Math.min(host.columns() - 2, 72));
55146
+ handle = host.showOverlay(new Box(view, { title: options.title, theme: host.theme }), {
55147
+ anchor: "center",
55148
+ width: width2
55149
+ });
55150
+ });
55151
+ }
55152
+ function modelPickerFor(host, runtime, context) {
55153
+ return (providers, current3) => openModelPicker(host, {
55154
+ title: msg().interactive.commands.modelTitle,
55155
+ providers,
55156
+ current: current3,
55157
+ enabled: runtime.config.models?.enabled,
55158
+ saveEnabled: (next) => {
55159
+ const result = setConfigValue({
55160
+ ...layerInputFor(runtime, context),
55161
+ scope: "user",
55162
+ key: "models.enabled",
55163
+ value: next
55164
+ });
55165
+ runtime.replaceConfig?.(result.snapshot.config);
55166
+ }
55167
+ });
55168
+ }
55169
+ var ModelPickerView;
55170
+ var init_model_picker = __esm({
55171
+ "src/modes/interactive/model-picker.ts"() {
55172
+ "use strict";
55173
+ init_model_visibility();
55174
+ init_edit2();
55175
+ init_i18n();
55176
+ init_tui2();
55177
+ init_config_ui();
55178
+ init_model_items();
55179
+ ModelPickerView = class {
55180
+ constructor(host, catalog, options, done) {
55181
+ this.host = host;
55182
+ this.catalog = catalog;
55183
+ this.options = options;
55184
+ this.done = done;
55185
+ this.enabled = enabledList(options.enabled);
55186
+ this.list = new SelectList([], {
55187
+ theme: host.theme,
55188
+ maxVisible: 12,
55189
+ filterable: true,
55190
+ showCount: true,
55191
+ ...host.keybindings !== void 0 ? { keybindings: host.keybindings } : {},
55192
+ ...options.current !== void 0 ? { currentValue: options.current } : {},
55193
+ emptyText: msg().panels.model.emptyConfigured,
55194
+ onSelect: (item) => this.select(item),
55195
+ onCancel: () => this.done(void 0)
55196
+ });
55197
+ this.rebuild();
55198
+ if (options.current !== void 0) this.list.selectValue(options.current);
55199
+ }
55200
+ host;
55201
+ catalog;
55202
+ options;
55203
+ done;
55204
+ view = "configured";
55205
+ enabled;
55206
+ notice;
55207
+ channels = false;
55208
+ list;
55209
+ get focused() {
55210
+ return this.list.focused;
55211
+ }
55212
+ set focused(value) {
55213
+ this.list.focused = value;
55214
+ }
55215
+ get currentView() {
55216
+ return this.view;
55217
+ }
55218
+ rebuild() {
55219
+ const m = msg().panels.model;
55220
+ this.list.setFooter(this.view === "all" ? m.footerAll : m.footerConfigured);
55221
+ this.list.setItems(
55222
+ catalogItems(this.catalog, {
55223
+ view: this.view,
55224
+ enabled: this.enabled,
55225
+ current: this.options.current,
55226
+ channels: this.channels
55227
+ })
55228
+ );
55229
+ }
55230
+ handleInput(data2) {
55231
+ if (matchesKey(data2, "tab")) {
55232
+ this.view = this.view === "all" ? "configured" : "all";
55233
+ this.notice = void 0;
55234
+ this.rebuild();
55235
+ return;
55236
+ }
55237
+ if (data2 === " ") {
55238
+ this.toggle();
55239
+ return;
55240
+ }
55241
+ this.list.handleInput(data2);
55242
+ const channels = this.list.getFilter().includes("@");
55243
+ if (channels !== this.channels) {
55244
+ this.channels = channels;
55245
+ this.rebuild();
55246
+ }
55247
+ }
55248
+ providerOf(value) {
55249
+ const id = value.slice(0, value.indexOf("/"));
55250
+ return this.catalog.providers.find((p) => p.provider.id === id);
55251
+ }
55252
+ save(next) {
55253
+ try {
55254
+ this.options.saveEnabled(next);
55255
+ this.enabled = next;
55256
+ return true;
55257
+ } catch (error2) {
55258
+ this.notice = {
55259
+ text: error2 instanceof Error ? error2.message : String(error2),
55260
+ level: "error"
55261
+ };
55262
+ return false;
55263
+ }
55264
+ }
55265
+ toggle() {
55266
+ const item = this.list.getSelected();
55267
+ if (item === void 0 || isHintValue(item.value)) return;
55268
+ const m = msg().panels.model;
55269
+ const ref = item.value;
55270
+ const match = this.enabled === void 0 ? void 0 : enabledMatch(this.enabled, ref);
55271
+ if (match?.kind === "wildcard") {
55272
+ this.notice = { text: m.wildcard(ref, match.pattern), level: "warning" };
55273
+ } else if (match !== void 0) {
55274
+ if (this.save(removeEnabled(this.enabled, [ref])))
55275
+ this.notice = { text: m.removed(ref), level: "info" };
55276
+ } else {
55277
+ const first = this.enabled === void 0;
55278
+ if (this.save(addEnabled(this.enabled, [ref])))
55279
+ this.notice = { text: first ? m.addedFirst(ref) : m.added(ref), level: "info" };
55280
+ }
55281
+ this.rebuild();
55282
+ }
55283
+ select(item) {
55284
+ const m = msg().panels.model;
55285
+ const id = item.value.slice(0, item.value.indexOf("/"));
55286
+ if (isHintValue(item.value)) {
55287
+ this.notice = { text: item.label, level: "info" };
55288
+ return;
55289
+ }
55290
+ const entry = this.providerOf(item.value);
55291
+ if (item.value !== this.options.current && entry !== void 0 && !accessReady(entry.access)) {
55292
+ const text = entry.access === "needsLogin" ? m.needsLoginHint(id) : m.noKeyHint(id);
55293
+ this.notice = { text, level: "warning" };
55294
+ return;
55295
+ }
55296
+ if (this.enabled !== void 0 && item.value !== this.options.current && enabledMatch(this.enabled, item.value) === void 0 && !this.save(addEnabled(this.enabled, [item.value])))
55297
+ return;
55298
+ this.done(item.value);
55299
+ }
55300
+ render(width2) {
55301
+ const lines2 = this.list.render(width2);
55302
+ if (this.notice === void 0) return lines2;
55303
+ const theme = this.host.theme;
55304
+ const color = this.notice.level === "info" ? "dim" : this.notice.level;
55305
+ return [...lines2, ...wrapTextWithAnsi(theme.fg(color, this.notice.text), width2)];
55306
+ }
55307
+ invalidate() {
55308
+ this.list.invalidate();
55309
+ }
55310
+ };
55311
+ }
55312
+ });
55313
+
54672
55314
  // src/modes/interactive/rewind-list.ts
54673
55315
  function rewindListItems(points, cache3, highlighted, now, ascii = false) {
54674
55316
  return points.map((point) => {
@@ -55384,33 +56026,33 @@ var init_trace_view = __esm({
55384
56026
  this.cursor = Math.max(0, at - 1);
55385
56027
  }
55386
56028
  expand() {
55387
- const row2 = this.selected;
55388
- if (row2 === void 0) return;
55389
- if (!row2.expandable) return;
55390
- if (!row2.expanded) {
55391
- if (needsChild(row2.node)) {
55392
- this.loaded.add(row2.node.taskId);
55393
- loadSubagentTrace(row2.node, this.loadChild);
56029
+ const row3 = this.selected;
56030
+ if (row3 === void 0) return;
56031
+ if (!row3.expandable) return;
56032
+ if (!row3.expanded) {
56033
+ if (needsChild(row3.node)) {
56034
+ this.loaded.add(row3.node.taskId);
56035
+ loadSubagentTrace(row3.node, this.loadChild);
55394
56036
  this.rebuild();
55395
56037
  }
55396
- this.expanded.set(row2.key, true);
56038
+ this.expanded.set(row3.key, true);
55397
56039
  this.reflow();
55398
56040
  return;
55399
56041
  }
55400
- if (this.rows[this.cursor + 1]?.depth === row2.depth + 1) this.cursor++;
56042
+ if (this.rows[this.cursor + 1]?.depth === row3.depth + 1) this.cursor++;
55401
56043
  }
55402
56044
  collapse() {
55403
- const row2 = this.selected;
55404
- if (row2 === void 0) return;
56045
+ const row3 = this.selected;
56046
+ if (row3 === void 0) return;
55405
56047
  this.follow = false;
55406
- if (row2.expanded) {
55407
- this.expanded.set(row2.key, false);
56048
+ if (row3.expanded) {
56049
+ this.expanded.set(row3.key, false);
55408
56050
  this.reflow();
55409
56051
  return;
55410
56052
  }
55411
- const slash = row2.key.lastIndexOf("/");
56053
+ const slash = row3.key.lastIndexOf("/");
55412
56054
  if (slash < 0) return;
55413
- const parent = rowIndex(this.rows, row2.key.slice(0, slash));
56055
+ const parent = rowIndex(this.rows, row3.key.slice(0, slash));
55414
56056
  if (parent >= 0) this.cursor = parent;
55415
56057
  }
55416
56058
  handleInput(data2) {
@@ -55430,9 +56072,9 @@ var init_trace_view = __esm({
55430
56072
  } else if (matchesKey(data2, "right")) this.expand();
55431
56073
  else if (matchesKey(data2, "left")) this.collapse();
55432
56074
  else if (matchesKey(data2, "enter")) {
55433
- const row2 = this.selected;
55434
- if (row2?.node.kind === "more") this.loadEarlier();
55435
- else if (row2 !== void 0 && row2.node.kind !== "aux_group") this.detail = { row: row2, scroll: 0 };
56075
+ const row3 = this.selected;
56076
+ if (row3?.node.kind === "more") this.loadEarlier();
56077
+ else if (row3 !== void 0 && row3.node.kind !== "aux_group") this.detail = { row: row3, scroll: 0 };
55436
56078
  } else if (data2 === "f") {
55437
56079
  this.follow = !this.follow;
55438
56080
  if (this.follow) this.cursor = Math.max(0, this.rows.length - 1);
@@ -55476,10 +56118,10 @@ var init_trace_view = __esm({
55476
56118
  const height = this.bodyHeight();
55477
56119
  const lines2 = [this.headerLine(width2)];
55478
56120
  if (this.detail !== void 0) {
55479
- const { row: row2 } = this.detail;
56121
+ const { row: row3 } = this.detail;
55480
56122
  const body = [
55481
- theme.bold(rowLabel(row2, this.ctx())),
55482
- ...detailLines(row2.node, this.lookup, Math.max(8, width2 - 2), theme, this.trace.startedAt)
56123
+ theme.bold(rowLabel(row3, this.ctx())),
56124
+ ...detailLines(row3.node, this.lookup, Math.max(8, width2 - 2), theme, this.trace.startedAt)
55483
56125
  ].map((l) => ` ${l}`);
55484
56126
  const max = Math.max(0, body.length - height);
55485
56127
  this.detail.scroll = Math.min(this.detail.scroll, max);
@@ -55641,7 +56283,7 @@ var init_startup_header = __esm({
55641
56283
  if (info2.warnings > 0) {
55642
56284
  rows.push({ key: m.keyWarnings, value: t.fg("warning", m.warningsValue(info2.warnings)) });
55643
56285
  }
55644
- const padded = rows.map((row2) => ({ ...row2, key: padToWidth(row2.key, keyWidth) }));
56286
+ const padded = rows.map((row3) => ({ ...row3, key: padToWidth(row3.key, keyWidth) }));
55645
56287
  const kv = new KeyValue(padded, { theme: t, gap: 1, maxKeyRatio: 1 });
55646
56288
  const body = {
55647
56289
  render: (inner) => [this.title(), "", ...kv.render(inner), "", t.fg("dim", m.hint)],
@@ -55811,10 +56453,10 @@ var init_run_indicator = __esm({
55811
56453
  theme;
55812
56454
  setQueue(steering, followUp) {
55813
56455
  const t = this.theme;
55814
- const row2 = (origin, text) => ` ${t.fg("dim", `${t.glyphs.queued} ${originLabel(origin)}`)} ${t.fg("muted", oneLine8(text))}`;
56456
+ const row3 = (origin, text) => ` ${t.fg("dim", `${t.glyphs.queued} ${originLabel(origin)}`)} ${t.fg("muted", oneLine8(text))}`;
55815
56457
  const rows = [
55816
- ...steering.map((text) => row2("steer", text)),
55817
- ...followUp.map((text) => row2("followUp", text))
56458
+ ...steering.map((text) => row3("steer", text)),
56459
+ ...followUp.map((text) => row3("followUp", text))
55818
56460
  ];
55819
56461
  const shown2 = rows.slice(-QUEUE_PREVIEW);
55820
56462
  if (rows.length > shown2.length) {
@@ -55938,15 +56580,15 @@ function processTerminal() {
55938
56580
  return new ProcessTerminal();
55939
56581
  }
55940
56582
  function loadKeys(runtime, warn2) {
55941
- const parsed = loadKeybindingsFile((0, import_node_path95.join)(runtime.paths.configDir, KEYBINDINGS_FILE));
56583
+ const parsed = loadKeybindingsFile((0, import_node_path96.join)(runtime.paths.configDir, KEYBINDINGS_FILE));
55942
56584
  for (const w of parsed.warnings) warn2(msg().interactive.app.keybindingsWarning(w));
55943
56585
  return new Keybindings(parsed.overrides);
55944
56586
  }
55945
- var import_node_path95;
56587
+ var import_node_path96;
55946
56588
  var init_terminal_setup = __esm({
55947
56589
  "src/modes/interactive/terminal-setup.ts"() {
55948
56590
  "use strict";
55949
- import_node_path95 = require("node:path");
56591
+ import_node_path96 = require("node:path");
55950
56592
  init_paths();
55951
56593
  init_errors();
55952
56594
  init_i18n();
@@ -56009,7 +56651,7 @@ function runInteractiveMode(runtime, context, options = {}) {
56009
56651
  ...options.statusLine !== void 0 ? { layout: options.statusLine } : {}
56010
56652
  });
56011
56653
  const { hint, bar: status } = area;
56012
- const historyFile = options.historyFile === false ? void 0 : options.historyFile ?? (0, import_node_path96.join)(runtime.paths.dataDir, "history");
56654
+ const historyFile = options.historyFile === false ? void 0 : options.historyFile ?? (0, import_node_path97.join)(runtime.paths.dataDir, "history");
56013
56655
  const completion = new InteractiveCompletion({
56014
56656
  commands: () => ALL_COMMANDS,
56015
56657
  prompts: () => runtime.resources.prompts,
@@ -56186,6 +56828,7 @@ function runInteractiveMode(runtime, context, options = {}) {
56186
56828
  return next;
56187
56829
  },
56188
56830
  pick: (spec2) => openPicker(pickerHost, spec2),
56831
+ pickModel: modelPickerFor(pickerHost, runtime, context),
56189
56832
  confirmMode,
56190
56833
  rewind: () => rewind.open(),
56191
56834
  setDraft,
@@ -56374,12 +57017,12 @@ function runInteractiveMode(runtime, context, options = {}) {
56374
57017
  }
56375
57018
  });
56376
57019
  }
56377
- var import_node_path96, HINT_MS;
57020
+ var import_node_path97, HINT_MS;
56378
57021
  var init_interactive_mode = __esm({
56379
57022
  "src/modes/interactive/interactive-mode.ts"() {
56380
57023
  "use strict";
56381
57024
  init_image_input();
56382
- import_node_path96 = require("node:path");
57025
+ import_node_path97 = require("node:path");
56383
57026
  init_session2();
56384
57027
  init_subagent_registry();
56385
57028
  init_compose_session();
@@ -56400,6 +57043,7 @@ var init_interactive_mode = __esm({
56400
57043
  init_key_dispatch();
56401
57044
  init_message_view();
56402
57045
  init_pickers();
57046
+ init_model_picker();
56403
57047
  init_rewind_flow();
56404
57048
  init_trace_view();
56405
57049
  init_startup_header();
@@ -56452,7 +57096,7 @@ function choose(answer, values) {
56452
57096
  }
56453
57097
  function isDirectory3(path) {
56454
57098
  try {
56455
- return (0, import_node_fs69.statSync)(path).isDirectory();
57099
+ return (0, import_node_fs70.statSync)(path).isDirectory();
56456
57100
  } catch {
56457
57101
  return false;
56458
57102
  }
@@ -56496,8 +57140,8 @@ function createTextStartupUi(io) {
56496
57140
  const m = msg().report.startup;
56497
57141
  const answer = (await ask([m.cwdMissing(missing)], m.cwdAnswer))?.trim();
56498
57142
  if (answer === void 0 || answer === "") return void 0;
56499
- const abs = (0, import_node_path97.resolve)(answer);
56500
- if (!(0, import_node_fs69.existsSync)(abs) || !isDirectory3(abs)) {
57143
+ const abs = (0, import_node_path98.resolve)(answer);
57144
+ if (!(0, import_node_fs70.existsSync)(abs) || !isDirectory3(abs)) {
56501
57145
  io.write(m.notDirectory(abs));
56502
57146
  return void 0;
56503
57147
  }
@@ -56505,12 +57149,12 @@ function createTextStartupUi(io) {
56505
57149
  }
56506
57150
  };
56507
57151
  }
56508
- var import_node_fs69, import_node_path97;
57152
+ var import_node_fs70, import_node_path98;
56509
57153
  var init_startup_ui_text = __esm({
56510
57154
  "src/modes/startup-ui-text.ts"() {
56511
57155
  "use strict";
56512
- import_node_fs69 = require("node:fs");
56513
- import_node_path97 = require("node:path");
57156
+ import_node_fs70 = require("node:fs");
57157
+ import_node_path98 = require("node:path");
56514
57158
  init_i18n();
56515
57159
  }
56516
57160
  });
@@ -56535,7 +57179,7 @@ function createTools(input2, options, state) {
56535
57179
  const osStatus = configureOsSandbox(input2.config.sandbox?.enabled);
56536
57180
  const bashSandbox = options.bashSandbox ?? resolveBashSandbox(input2.config.sandbox, {
56537
57181
  status: osStatus,
56538
- ...input2.paths === void 0 ? {} : { hidden: [(0, import_node_path98.join)(input2.paths.configDir, AUTH_FILE)] }
57182
+ ...input2.paths === void 0 ? {} : { hidden: [(0, import_node_path99.join)(input2.paths.configDir, AUTH_FILE)] }
56539
57183
  });
56540
57184
  state.bashSandbox = bashSandbox;
56541
57185
  const capability = options.sandboxCapability ?? sandboxCapabilityFor(input2.config);
@@ -56720,7 +57364,7 @@ function createRuntimeDeps(options = {}) {
56720
57364
  if (ui !== void 0) deps.ui = ui;
56721
57365
  return deps;
56722
57366
  }
56723
- var import_node_path98, DEFAULT_TOOL_FACTORIES, DEFAULT_MODES;
57367
+ var import_node_path99, DEFAULT_TOOL_FACTORIES, DEFAULT_MODES;
56724
57368
  var init_compose2 = __esm({
56725
57369
  "src/cli/compose.ts"() {
56726
57370
  "use strict";
@@ -56735,9 +57379,9 @@ var init_compose2 = __esm({
56735
57379
  init_tool();
56736
57380
  init_detect();
56737
57381
  init_bash();
56738
- import_node_path98 = require("node:path");
57382
+ import_node_path99 = require("node:path");
56739
57383
  init_paths();
56740
- init_presets();
57384
+ init_presets2();
56741
57385
  init_registry();
56742
57386
  init_tool2();
56743
57387
  init_codemode_notice();
@@ -56950,8 +57594,8 @@ var init_memory3 = __esm({
56950
57594
  });
56951
57595
 
56952
57596
  // src/cli/main.ts
56953
- var import_node_fs70 = require("node:fs");
56954
- var import_node_path99 = require("node:path");
57597
+ var import_node_fs71 = require("node:fs");
57598
+ var import_node_path100 = require("node:path");
56955
57599
  var import_node_url3 = require("node:url");
56956
57600
  init_version();
56957
57601
  init_args();
@@ -58239,7 +58883,7 @@ function reportError(error2, io, fallback = ExitCode.RuntimeError) {
58239
58883
  init_exit_codes();
58240
58884
 
58241
58885
  // src/cli/subcommands/auth.ts
58242
- var import_node_path67 = require("node:path");
58886
+ var import_node_path68 = require("node:path");
58243
58887
 
58244
58888
  // src/auth/chatgpt/cli.ts
58245
58889
  init_errors();
@@ -58273,11 +58917,11 @@ var openBrowser = (url) => new Promise((resolve38) => {
58273
58917
 
58274
58918
  // src/auth/chatgpt/cli.ts
58275
58919
  init_token_store();
58920
+ init_discovered_cache();
58276
58921
 
58277
58922
  // src/auth/chatgpt/backend-client.ts
58278
58923
  init_chatgpt_rate_limits();
58279
- init_version();
58280
- init_presets2();
58924
+ init_presets();
58281
58925
  var BACKEND_TIMEOUT_MS = 15e3;
58282
58926
  function headers(auth) {
58283
58927
  const out = {
@@ -58294,9 +58938,29 @@ function listed(item) {
58294
58938
  const visibility = item["visibility"];
58295
58939
  return visibility === void 0 || visibility === "list";
58296
58940
  }
58941
+ function codexMetadata(item) {
58942
+ const out = {};
58943
+ const window2 = item["context_window"];
58944
+ if (typeof window2 === "number" && Number.isInteger(window2) && window2 > 0)
58945
+ out.contextWindow = window2;
58946
+ const modalities = item["input_modalities"];
58947
+ if (Array.isArray(modalities)) {
58948
+ const input2 = ["text", "image"].filter((x) => modalities.includes(x));
58949
+ if (input2.includes("text")) out.input = input2;
58950
+ }
58951
+ const levels = item["supported_reasoning_levels"];
58952
+ if (Array.isArray(levels)) {
58953
+ const efforts = levels.map(
58954
+ (level) => typeof level === "string" ? level : typeof level === "object" && level !== null ? level["effort"] : void 0
58955
+ ).filter((x) => typeof x === "string" && x !== "");
58956
+ if (efforts.length > 0) out.reasoningLevels = [...new Set(efforts)];
58957
+ }
58958
+ return out;
58959
+ }
58297
58960
  async function listChatGptModels(fetchFn, baseUrl, auth) {
58298
58961
  const base4 = baseUrl.replace(/\/+$/, "");
58299
- const url = auth.flavor === "codex" ? `${base4}/models?client_version=${encodeURIComponent(AMA_VERSION)}` : `${base4}/models`;
58962
+ const version = auth.clientVersion ?? DEFAULT_CODEX_CLIENT_VERSION;
58963
+ const url = auth.flavor === "codex" ? `${base4}/models?client_version=${encodeURIComponent(version)}` : `${base4}/models`;
58300
58964
  const response = await fetchFn(url, {
58301
58965
  headers: headers(auth),
58302
58966
  signal: AbortSignal.timeout(BACKEND_TIMEOUT_MS)
@@ -58311,7 +58975,11 @@ async function listChatGptModels(fetchFn, baseUrl, auth) {
58311
58975
  if (typeof id !== "string" || id === "" || seen.has(id)) continue;
58312
58976
  seen.add(id);
58313
58977
  const name = item["display_name"];
58314
- out.push(typeof name === "string" && name !== "" ? { id, name } : { id });
58978
+ out.push({
58979
+ id,
58980
+ ...typeof name === "string" && name !== "" ? { name } : {},
58981
+ ...auth.flavor === "codex" ? codexMetadata(item) : {}
58982
+ });
58315
58983
  }
58316
58984
  return out;
58317
58985
  }
@@ -58742,29 +59410,29 @@ init_token_client();
58742
59410
 
58743
59411
  // src/auth/chatgpt/host-id.ts
58744
59412
  var import_node_crypto17 = require("node:crypto");
58745
- var import_node_fs44 = require("node:fs");
58746
- var import_node_path66 = require("node:path");
59413
+ var import_node_fs45 = require("node:fs");
59414
+ var import_node_path67 = require("node:path");
58747
59415
  var HOST_ID_FILE = "chatgpt-host.json";
58748
59416
  function hostIdPath(dataDir) {
58749
- return (0, import_node_path66.join)(dataDir, HOST_ID_FILE);
59417
+ return (0, import_node_path67.join)(dataDir, HOST_ID_FILE);
58750
59418
  }
58751
59419
  function readOrCreateHostId(dataDir) {
58752
59420
  const path = hostIdPath(dataDir);
58753
59421
  try {
58754
- const value = JSON.parse((0, import_node_fs44.readFileSync)(path, "utf8"));
59422
+ const value = JSON.parse((0, import_node_fs45.readFileSync)(path, "utf8"));
58755
59423
  if (typeof value.hostId === "string" && /^urn:uuid:[0-9a-f-]{36}$/i.test(value.hostId))
58756
59424
  return value.hostId;
58757
59425
  } catch {
58758
59426
  }
58759
59427
  const hostId = `urn:uuid:${(0, import_node_crypto17.randomUUID)()}`;
58760
- (0, import_node_fs44.mkdirSync)((0, import_node_path66.dirname)(path), { recursive: true, mode: 448 });
58761
- (0, import_node_fs44.writeFileSync)(path, `${JSON.stringify({ version: 1, hostId }, null, 2)}
59428
+ (0, import_node_fs45.mkdirSync)((0, import_node_path67.dirname)(path), { recursive: true, mode: 448 });
59429
+ (0, import_node_fs45.writeFileSync)(path, `${JSON.stringify({ version: 1, hostId }, null, 2)}
58762
59430
  `, { mode: 384 });
58763
59431
  return hostId;
58764
59432
  }
58765
59433
 
58766
59434
  // src/auth/chatgpt/login.ts
58767
- init_presets2();
59435
+ init_presets();
58768
59436
  var DEFAULT_ACCESS_TTL_S = 3600;
58769
59437
  function flowPreset(preset, hostId) {
58770
59438
  return {
@@ -58877,7 +59545,7 @@ async function revokeChatGpt(fetchFn, entry, overrides = {}) {
58877
59545
  }
58878
59546
 
58879
59547
  // src/auth/chatgpt/cli.ts
58880
- init_presets2();
59548
+ init_presets();
58881
59549
  init_quota_text();
58882
59550
  function userAuthConfig(io) {
58883
59551
  try {
@@ -58906,7 +59574,7 @@ function loginErrorText(error2, flavor) {
58906
59574
  case "oauth_timeout":
58907
59575
  return m.timeout;
58908
59576
  case "oauth_denied":
58909
- return m.denied(detail.error ?? "error");
59577
+ return m.denied(detail.error ?? "error", flavor === "siwc");
58910
59578
  case "oauth_state_mismatch":
58911
59579
  return m.stateMismatch;
58912
59580
  case "oauth_no_code":
@@ -59029,11 +59697,35 @@ async function runLogin(args, io, deps = {}) {
59029
59697
  if (entry.planType === "free") io.stdout(`${m.freePlanHint(entry.planType)}
59030
59698
  `);
59031
59699
  if (flavor === "siwc") io.stdout(`${m.siwcLimitHint}
59700
+ ${m.siwcEligibilityHint}
59032
59701
  `);
59033
- io.stdout(`${m.modelHint}
59702
+ const count2 = await cacheModels(io, entry, config, deps);
59703
+ const done = count2 === 0 && flavor === "codex" ? m.codexNoModels(codexClientVersion(config, io.env)) : count2 === void 0 || count2 === 0 ? m.modelHint : m.modelsCached(count2);
59704
+ io.stdout(`${done}
59034
59705
  `);
59035
59706
  return ExitCode.Ok;
59036
59707
  }
59708
+ async function cacheModels(io, entry, config, deps) {
59709
+ const dataDir = resolveDataDir({ env: io.env });
59710
+ try {
59711
+ clearDiscoveredCache(dataDir, CHATGPT_PROVIDER_ID);
59712
+ const models = await listChatGptModels(
59713
+ deps.fetch ?? fetch,
59714
+ chatgptBaseUrl(entry.flavor, io.env),
59715
+ {
59716
+ flavor: entry.flavor,
59717
+ accessToken: entry.accessToken,
59718
+ accountId: entry.accountId,
59719
+ originator: config?.originator,
59720
+ clientVersion: codexClientVersion(config, io.env)
59721
+ }
59722
+ );
59723
+ writeDiscoveredCache(dataDir, CHATGPT_PROVIDER_ID, { models, flavor: entry.flavor });
59724
+ return models.length;
59725
+ } catch {
59726
+ return void 0;
59727
+ }
59728
+ }
59037
59729
  async function runLogout(args, io, deps = {}) {
59038
59730
  const m = msg().auth.logout;
59039
59731
  const provider = providerOf(args, "logout");
@@ -59051,6 +59743,7 @@ async function runLogout(args, io, deps = {}) {
59051
59743
  `);
59052
59744
  return ExitCode.RuntimeError;
59053
59745
  }
59746
+ clearDiscoveredCache(resolveDataDir({ env: io.env }), provider);
59054
59747
  const text = revoked === void 0 ? m.local(provider, args.path) : revoked ? m.revoked(provider, args.path) : m.notRevoked(provider, args.path);
59055
59748
  io.stdout(`${text}
59056
59749
  `);
@@ -59152,7 +59845,7 @@ async function runAuth(argv, io, deps = {}) {
59152
59845
  return flags2.has("help") ? ExitCode.Ok : ExitCode.Usage;
59153
59846
  }
59154
59847
  const explicit = values.get("auth-file");
59155
- const path = explicit !== void 0 ? (0, import_node_path67.resolve)(io.cwd, explicit) : defaultAuthFilePath(resolveConfigDir({ env: io.env }));
59848
+ const path = explicit !== void 0 ? (0, import_node_path68.resolve)(io.cwd, explicit) : defaultAuthFilePath(resolveConfigDir({ env: io.env }));
59156
59849
  const loginOnly = ["flavor", "port"].filter((name) => values.has(name));
59157
59850
  const loginFlags = ["paste", "device", "no-browser", "yes"].filter((name) => flags2.has(name));
59158
59851
  if (action !== "login" && [...loginOnly, ...loginFlags].length > 0)
@@ -59224,8 +59917,8 @@ init_merge();
59224
59917
  init_key_docs();
59225
59918
  init_paths();
59226
59919
  var import_node_child_process14 = require("node:child_process");
59227
- var import_node_fs53 = require("node:fs");
59228
- var import_node_path75 = require("node:path");
59920
+ var import_node_fs54 = require("node:fs");
59921
+ var import_node_path76 = require("node:path");
59229
59922
  init_models_dev_cache();
59230
59923
  init_init();
59231
59924
  init_json_schema();
@@ -59233,14 +59926,14 @@ init_types2();
59233
59926
  init_capability();
59234
59927
  init_registry2();
59235
59928
  init_auth_file();
59236
- init_presets();
59929
+ init_presets2();
59237
59930
  init_registry();
59238
59931
  init_args();
59239
59932
  init_default_model();
59240
59933
  init_exit_codes();
59241
59934
 
59242
59935
  // src/cli/subcommands/context.ts
59243
- var import_node_path71 = require("node:path");
59936
+ var import_node_path72 = require("node:path");
59244
59937
  init_auth_file();
59245
59938
  init_load();
59246
59939
  init_merge();
@@ -59261,7 +59954,7 @@ function loadUserLevel(io, options = {}) {
59261
59954
  profile: profile?.config,
59262
59955
  hasProfile: profile !== void 0
59263
59956
  });
59264
- const authFile = options.authFile !== void 0 ? (0, import_node_path71.resolve)(io.cwd, options.authFile) : profile?.authFile ?? defaultAuthFilePath(configDir);
59957
+ const authFile = options.authFile !== void 0 ? (0, import_node_path72.resolve)(io.cwd, options.authFile) : profile?.authFile ?? defaultAuthFilePath(configDir);
59265
59958
  const result = { configDir, dataDir, merged, userConfigPath, authFile, warnings };
59266
59959
  if (profile !== void 0) result.profile = profile;
59267
59960
  return result;
@@ -59286,8 +59979,8 @@ init_ansi();
59286
59979
  // src/cli/subcommands/config-set.ts
59287
59980
  init_i18n();
59288
59981
  init_edit2();
59289
- var import_node_fs52 = require("node:fs");
59290
- var import_node_path74 = require("node:path");
59982
+ var import_node_fs53 = require("node:fs");
59983
+ var import_node_path75 = require("node:path");
59291
59984
  init_init();
59292
59985
  init_paths();
59293
59986
  init_profile();
@@ -59339,18 +60032,22 @@ function textRow(value) {
59339
60032
  function scopeLabel(scope) {
59340
60033
  return msg().settings.scope[scope];
59341
60034
  }
59342
- function report(io, result, unset) {
60035
+ function report(io, result, written) {
59343
60036
  const s2 = msg().settings;
59344
- const value = formatSettingValue(result.after.value);
60037
+ const effective = formatSettingValue(result.after.value);
60038
+ const scope = scopeLabel(result.scope);
60039
+ const by = result.after.envName ?? result.overriddenBy;
60040
+ if (written === void 0) io.stdout(`${s2.unsetDone(result.key, effective, scope)}
60041
+ `);
60042
+ else if (by === void 0) io.stdout(`${s2.setDone(result.key, effective, scope)}
60043
+ `);
60044
+ else io.stdout(`${s2.writtenTo(result.key, formatSettingValue(written), scope)}
60045
+ `);
60046
+ if (by === void 0) return;
59345
60047
  io.stdout(
59346
- `${unset ? s2.unsetDone(result.key, value, scopeLabel(result.scope)) : s2.setDone(result.key, value, scopeLabel(result.scope))}
60048
+ `${written === void 0 ? s2.stillOverridden(result.key, by) : s2.overriddenNow(by, effective)}
59347
60049
  `
59348
60050
  );
59349
- if (result.overriddenBy !== void 0) {
59350
- const by = result.after.envName ?? result.overriddenBy;
59351
- io.stdout(`${s2.stillOverridden(result.key, by)}
59352
- `);
59353
- }
59354
60051
  }
59355
60052
  async function confirmBypass(io, yes, deps) {
59356
60053
  const s2 = msg().settings.cli;
@@ -59403,7 +60100,7 @@ async function runConfigEdit(action, argv, io, deps = {}) {
59403
60100
  return ExitCode.Ok;
59404
60101
  }
59405
60102
  if (action === "unset") {
59406
- report(io, setConfigValue({ ...input2, scope, key, value: void 0 }), true);
60103
+ report(io, setConfigValue({ ...input2, scope, key, value: void 0 }), void 0);
59407
60104
  return ExitCode.Ok;
59408
60105
  }
59409
60106
  const raw = positionals.slice(1).join(" ");
@@ -59412,9 +60109,9 @@ async function runConfigEdit(action, argv, io, deps = {}) {
59412
60109
  if (key === "permission.mode" && value === "full-auto" && scope === "user") {
59413
60110
  if (!await confirmBypass(io, flags2.has("yes"), deps)) return ExitCode.Config;
59414
60111
  }
59415
- if (scope === "user" && !(0, import_node_fs52.existsSync)((0, import_node_path74.join)(input2.configDir, CONFIG_FILE)))
60112
+ if (scope === "user" && !(0, import_node_fs53.existsSync)((0, import_node_path75.join)(input2.configDir, CONFIG_FILE)))
59416
60113
  initConfigDir(input2.configDir);
59417
- report(io, setConfigValue({ ...input2, scope, key, value }), value === void 0);
60114
+ report(io, setConfigValue({ ...input2, scope, key, value }), value);
59418
60115
  return ExitCode.Ok;
59419
60116
  }
59420
60117
 
@@ -59425,17 +60122,17 @@ function showPaths(io) {
59425
60122
  const configDir = resolveConfigDir({ env: io.env });
59426
60123
  const dataDir = resolveDataDir({ env: io.env });
59427
60124
  const m = msg().subcommands.configShow;
59428
- const mark = (path) => `${path}${(0, import_node_fs53.existsSync)(path) ? "" : m.missing}`;
60125
+ const mark = (path) => `${path}${(0, import_node_fs54.existsSync)(path) ? "" : m.missing}`;
59429
60126
  const width2 = Math.max(...[m.configDir, m.dataDir, m.projectLevel].map(visibleWidth)) + 2;
59430
60127
  const label2 = (text) => padToWidth(text, width2);
59431
60128
  const lines2 = [
59432
60129
  `${label2(m.configDir)}${mark(configDir)}`,
59433
- ` config.json ${mark((0, import_node_path75.join)(configDir, CONFIG_FILE))}`,
59434
- ` config.schema.json ${mark((0, import_node_path75.join)(configDir, CONFIG_SCHEMA_FILE))}`,
59435
- ` auth.json ${mark((0, import_node_path75.join)(configDir, AUTH_FILE))}`,
59436
- ` hooks.json ${mark((0, import_node_path75.join)(configDir, HOOKS_FILE))}`,
60130
+ ` config.json ${mark((0, import_node_path76.join)(configDir, CONFIG_FILE))}`,
60131
+ ` config.schema.json ${mark((0, import_node_path76.join)(configDir, CONFIG_SCHEMA_FILE))}`,
60132
+ ` auth.json ${mark((0, import_node_path76.join)(configDir, AUTH_FILE))}`,
60133
+ ` hooks.json ${mark((0, import_node_path76.join)(configDir, HOOKS_FILE))}`,
59437
60134
  `${label2(m.dataDir)}${mark(dataDir)}`,
59438
- ` sessions/ ${mark((0, import_node_path75.join)(dataDir, "sessions"))}`,
60135
+ ` sessions/ ${mark((0, import_node_path76.join)(dataDir, "sessions"))}`,
59439
60136
  ` models-dev.json ${mark(modelsDevCachePath(dataDir))}`,
59440
60137
  `${label2(m.projectLevel)}${mark(projectFile(io.cwd, CONFIG_FILE))}`
59441
60138
  ];
@@ -59445,8 +60142,8 @@ function showPaths(io) {
59445
60142
  }
59446
60143
  function editConfig(io) {
59447
60144
  const configDir = resolveConfigDir({ env: io.env });
59448
- const path = (0, import_node_path75.join)(configDir, CONFIG_FILE);
59449
- if (!(0, import_node_fs53.existsSync)(path)) initConfigDir(configDir);
60145
+ const path = (0, import_node_path76.join)(configDir, CONFIG_FILE);
60146
+ if (!(0, import_node_fs54.existsSync)(path)) initConfigDir(configDir);
59450
60147
  const editor = (io.env["VISUAL"] ?? io.env["EDITOR"] ?? "").trim();
59451
60148
  if (editor === "") {
59452
60149
  io.stdout(msg().subcommands.configShow.noEditor(path));
@@ -59719,7 +60416,7 @@ async function runConfig(argv, io, deps) {
59719
60416
  const lines2 = [m.heading];
59720
60417
  for (const layer of layers.slice(1)) lines2.push(m.layerLine(layer.name, layer.label));
59721
60418
  lines2.push("");
59722
- const texts2 = rows.map((row2) => [`${row2.path} = ${display(row2.path, row2.value)}`, row2.source]);
60419
+ const texts2 = rows.map((row3) => [`${row3.path} = ${display(row3.path, row3.value)}`, row3.source]);
59723
60420
  const width2 = Math.min(60, Math.max(...texts2.map(([text]) => (text ?? "").length)));
59724
60421
  for (const [text, source] of texts2) lines2.push(` ${(text ?? "").padEnd(width2)} ${source}`);
59725
60422
  lines2.push(...providerLines(providers));
@@ -59738,7 +60435,7 @@ async function runConfig(argv, io, deps) {
59738
60435
  }
59739
60436
 
59740
60437
  // src/cli/subcommands/doctor.ts
59741
- var import_node_fs54 = require("node:fs");
60438
+ var import_node_fs55 = require("node:fs");
59742
60439
  init_blobs();
59743
60440
  init_shadow_git();
59744
60441
  init_gc();
@@ -59863,7 +60560,7 @@ init_types_w6();
59863
60560
 
59864
60561
  // src/auth/chatgpt/doctor.ts
59865
60562
  init_i18n();
59866
- init_presets2();
60563
+ init_presets();
59867
60564
  init_quota_text();
59868
60565
  async function oauthDoctorLines(provider, entry, options = {}) {
59869
60566
  const m = msg().auth;
@@ -60109,7 +60806,7 @@ async function runDoctor(argv, io, deps) {
60109
60806
  const m = msg().report.doctor;
60110
60807
  report2.section(m.dirsTitle);
60111
60808
  report2.item(m.configDir(level.configDir));
60112
- report2.item(m.dataDir(level.dataDir, (0, import_node_fs54.existsSync)(level.dataDir)));
60809
+ report2.item(m.dataDir(level.dataDir, (0, import_node_fs55.existsSync)(level.dataDir)));
60113
60810
  await fileHistoryLine(report2, level.dataDir);
60114
60811
  report2.section(m.layersTitle);
60115
60812
  report2.item(m.builtinDefaults);
@@ -60330,13 +61027,14 @@ var CACHE_PROBE_ACTION = {
60330
61027
 
60331
61028
  // src/cli/subcommands/models-discover.ts
60332
61029
  init_http();
60333
- init_presets2();
61030
+ init_presets();
60334
61031
  init_live();
60335
61032
  init_registry2();
61033
+ init_discovered_cache();
60336
61034
  init_catalog2();
60337
61035
  init_models_dev_cache();
60338
61036
  init_models_dev();
60339
- var import_node_fs55 = require("node:fs");
61037
+ var import_node_fs56 = require("node:fs");
60340
61038
  init_load();
60341
61039
  init_write2();
60342
61040
  init_args();
@@ -60598,11 +61296,18 @@ async function discoverModels(provider, apiKey, options = {}) {
60598
61296
  flavor,
60599
61297
  accessToken: apiKey,
60600
61298
  accountId: live2?.accountId,
60601
- originator: channel?.headers?.["originator"]
61299
+ originator: channel?.headers?.["originator"],
61300
+ clientVersion: options.codexClientVersion
60602
61301
  });
60603
61302
  return models.map((m) => {
60604
61303
  const model = withCustomDefaults({ id: m.id }, provider.id, provider.api);
60605
61304
  if (m.name !== void 0) model.name = m.name;
61305
+ if (m.contextWindow !== void 0) model.contextWindow = m.contextWindow;
61306
+ if (m.input !== void 0) model.input = m.input;
61307
+ if (m.reasoningLevels?.some((x) => x !== "none") === true) {
61308
+ model.reasoning = true;
61309
+ model.thinkingLevelMap = thinkingMapOf(m.reasoningLevels);
61310
+ }
60606
61311
  return model;
60607
61312
  });
60608
61313
  }
@@ -60692,7 +61397,7 @@ function writeEntries(ctx, provider, entries, notes) {
60692
61397
  return 0;
60693
61398
  }
60694
61399
  models.push(...added);
60695
- const backup = (0, import_node_fs55.existsSync)(path);
61400
+ const backup = (0, import_node_fs56.existsSync)(path);
60696
61401
  writeConfigFile(path, config, { backup: true });
60697
61402
  io.stdout(m.written(path, provider.id, added.length, kept, backup));
60698
61403
  if (notes.noTools.size > 0) io.stdout(m.skippedNoTools([...notes.noTools].join(", ")));
@@ -60717,13 +61422,16 @@ async function run6(ctx) {
60717
61422
  }
60718
61423
  let found;
60719
61424
  try {
60720
- found = await discoverModels(provider, key.apiKey);
61425
+ found = await discoverModels(provider, key.apiKey, {
61426
+ codexClientVersion: codexClientVersion(ctx.level.merged.config.auth?.chatgpt, io.env)
61427
+ });
60721
61428
  } catch (error2) {
60722
61429
  io.stderr(m.listFailed(provider.id, error2.message));
60723
61430
  return ExitCode.RuntimeError;
60724
61431
  }
60725
61432
  const configured2 = new Map(provider.models.map((m2) => [m2.id, m2]));
60726
61433
  io.stdout(m.found(provider.id, found.length, modelsUrl(provider)));
61434
+ if (provider.id === CHATGPT_PROVIDER_ID) cacheChatGpt(ctx, found, key.apiKey);
60727
61435
  const mdIndex = loadModelsDevIndex(ctx.level.dataDir);
60728
61436
  io.stdout(`${describeModelsDev(ctx.level.dataDir)}
60729
61437
  `);
@@ -60782,6 +61490,33 @@ async function run6(ctx) {
60782
61490
  }
60783
61491
  return ExitCode.Ok;
60784
61492
  }
61493
+ function cacheEntry(m) {
61494
+ const entry = { id: m.id };
61495
+ if (m.name !== m.id) entry.name = m.name;
61496
+ if (m.contextWindow !== void 0) entry.contextWindow = m.contextWindow;
61497
+ if (m.input.length !== 1 || m.input[0] !== "text") entry.input = [...m.input];
61498
+ if (m.reasoning && m.thinkingLevelMap !== void 0)
61499
+ entry.reasoningLevels = Object.entries(m.thinkingLevelMap).flatMap(
61500
+ ([level, value]) => typeof value !== "string" ? [] : level === "off" ? ["none"] : [level]
61501
+ );
61502
+ return entry;
61503
+ }
61504
+ function cacheChatGpt(ctx, found, apiKey) {
61505
+ const flavor = liveToken(apiKey)?.flavor;
61506
+ try {
61507
+ const models = found.map(cacheEntry);
61508
+ const path = writeDiscoveredCache(ctx.level.dataDir, CHATGPT_PROVIDER_ID, { models, flavor });
61509
+ ctx.io.stdout(msg().subcommands.discover.cached(path));
61510
+ } catch (error2) {
61511
+ ctx.io.stderr(`ama: ${error2.message}
61512
+ `);
61513
+ }
61514
+ if (found.length === 0 && flavor === "codex") {
61515
+ const version = codexClientVersion(ctx.level.merged.config.auth?.chatgpt, ctx.io.env);
61516
+ ctx.io.stderr(`${msg().auth.login.codexNoModels(version)}
61517
+ `);
61518
+ }
61519
+ }
60785
61520
  var DISCOVER_ACTION = {
60786
61521
  usage: "ama models discover <provider> [--probe] [--write] [--limit <n>] [--concurrency <n>] [--probe-timeout <ms>]",
60787
61522
  required: "<provider>",
@@ -60790,6 +61525,132 @@ var DISCOVER_ACTION = {
60790
61525
  run: run6
60791
61526
  };
60792
61527
 
61528
+ // src/cli/subcommands/models-enable.ts
61529
+ init_model_visibility();
61530
+ init_edit2();
61531
+ init_types_w5();
61532
+ init_i18n();
61533
+ init_args();
61534
+ init_exit_codes();
61535
+ function layerInput2(ctx) {
61536
+ const input2 = {
61537
+ configDir: ctx.level.configDir,
61538
+ cwd: ctx.io.cwd,
61539
+ env: ctx.io.env
61540
+ };
61541
+ if (ctx.level.profile !== void 0) {
61542
+ input2.profile = { config: ctx.level.profile.config };
61543
+ input2.hasProfile = true;
61544
+ }
61545
+ return input2;
61546
+ }
61547
+ function checkRefs(ctx, refs) {
61548
+ const m = msg().subcommands.modelsEnabled;
61549
+ for (const ref of refs) {
61550
+ const parts = splitEnabledRef(ref);
61551
+ if (!MODELS_ENABLED_REF.test(ref) || parts === void 0) throw new UsageError(m.badRef(ref));
61552
+ const provider = ctx.registry.get(parts.provider);
61553
+ if (provider === void 0) {
61554
+ ctx.io.stderr(msg().subcommands.common.providerNotFound(parts.provider));
61555
+ return ExitCode.NoModel;
61556
+ }
61557
+ if (parts.model !== "*" && provider.models.length > 0 && !provider.models.some((model) => model.id === parts.model))
61558
+ ctx.io.stderr(m.unknownModel(ref));
61559
+ }
61560
+ return void 0;
61561
+ }
61562
+ function userList(input2) {
61563
+ return enabledList(readSnapshot(input2).user?.models?.enabled);
61564
+ }
61565
+ async function enable(ctx) {
61566
+ const m = msg().subcommands.modelsEnabled;
61567
+ const refs = [...new Set(ctx.args)];
61568
+ const bad = checkRefs(ctx, refs);
61569
+ if (bad !== void 0) return bad;
61570
+ const input2 = layerInput2(ctx);
61571
+ const current3 = userList(input2);
61572
+ const fresh = refs.filter((ref) => !(current3 ?? []).includes(ref));
61573
+ if (fresh.length === 0) {
61574
+ ctx.io.stdout(m.alreadyListed(refs.join(", ")));
61575
+ return ExitCode.Ok;
61576
+ }
61577
+ const result = setConfigValue({
61578
+ ...input2,
61579
+ scope: "user",
61580
+ key: "models.enabled",
61581
+ value: addEnabled(current3, fresh)
61582
+ });
61583
+ ctx.io.stdout(m.added(fresh.join(", "), result.path));
61584
+ return ExitCode.Ok;
61585
+ }
61586
+ async function disable(ctx) {
61587
+ const m = msg().subcommands.modelsEnabled;
61588
+ const refs = [...new Set(ctx.args)];
61589
+ for (const ref of refs) if (!MODELS_ENABLED_REF.test(ref)) throw new UsageError(m.badRef(ref));
61590
+ const input2 = layerInput2(ctx);
61591
+ const current3 = userList(input2) ?? [];
61592
+ const listed2 = refs.filter((ref) => current3.includes(ref));
61593
+ const missing = refs.filter((ref) => !current3.includes(ref));
61594
+ if (missing.length > 0) ctx.io.stderr(m.notListed(missing.join(", ")));
61595
+ if (listed2.length === 0) return missing.length > 0 ? ExitCode.RuntimeError : ExitCode.Ok;
61596
+ const next = removeEnabled(current3, listed2);
61597
+ const result = setConfigValue({ ...input2, scope: "user", key: "models.enabled", value: next });
61598
+ ctx.io.stdout(
61599
+ next === void 0 ? m.cleared(result.path) : m.removed(listed2.join(", "), result.path)
61600
+ );
61601
+ return ExitCode.Ok;
61602
+ }
61603
+ async function listEnabled(ctx) {
61604
+ const m = msg().subcommands.modelsEnabled;
61605
+ const labels = msg().panels.model;
61606
+ const list5 = enabledList(ctx.level.merged.config.models?.enabled);
61607
+ const status = async (providerId) => {
61608
+ const provider = ctx.registry.get(providerId);
61609
+ if (provider === void 0) return "?";
61610
+ const access = await providerAccess(ctx.registry, provider);
61611
+ return access === "none" ? labels.noKey : labels[access];
61612
+ };
61613
+ if (list5 !== void 0) {
61614
+ ctx.io.stdout(m.listHeader(ctx.level.userConfigPath));
61615
+ for (const ref of list5) {
61616
+ const parts = splitEnabledRef(ref);
61617
+ const provider = parts === void 0 ? void 0 : ctx.registry.get(parts.provider);
61618
+ const known = parts === void 0 || parts.model === "*" || provider === void 0 || provider.models.length === 0 || provider.models.some((model) => model.id === parts.model);
61619
+ const notes = [
61620
+ parts === void 0 ? "?" : await status(parts.provider),
61621
+ ...known ? [] : [m.notInTable]
61622
+ ];
61623
+ ctx.io.stdout(` ${ref} ${notes.join(" · ")}
61624
+ `);
61625
+ }
61626
+ return ExitCode.Ok;
61627
+ }
61628
+ ctx.io.stdout(m.listUnset);
61629
+ let shown2 = 0;
61630
+ for (const provider of ctx.registry.list()) {
61631
+ const access = await providerAccess(ctx.registry, provider);
61632
+ if (!accessReady(access)) continue;
61633
+ const label2 = access === "none" ? labels.noKey : labels[access];
61634
+ for (const model of provider.models) {
61635
+ ctx.io.stdout(` ${provider.id}/${model.id} ${label2}
61636
+ `);
61637
+ shown2++;
61638
+ }
61639
+ }
61640
+ if (shown2 === 0) ctx.io.stdout(m.nothing);
61641
+ return ExitCode.Ok;
61642
+ }
61643
+ var ENABLE_ACTION = {
61644
+ usage: "ama models enable <provider/model[@channel]|provider/*>…",
61645
+ required: "<provider/model>",
61646
+ run: enable
61647
+ };
61648
+ var DISABLE_ACTION = {
61649
+ usage: "ama models disable <provider/model[@channel]|provider/*>…",
61650
+ required: "<provider/model>",
61651
+ run: disable
61652
+ };
61653
+
60793
61654
  // src/cli/subcommands/models.ts
60794
61655
  init_model_meta();
60795
61656
  init_i18n();
@@ -60887,9 +61748,10 @@ var REFRESH_ACTION = {
60887
61748
  };
60888
61749
  var MODELS_ACTIONS = Object.freeze({
60889
61750
  list: {
60890
- usage: "ama models list [--provider <id>]",
61751
+ usage: "ama models list [--provider <id>] [--enabled]",
60891
61752
  valueOptions: ["provider"],
60892
- run: (ctx) => list3(ctx.io, ctx.registry, ctx.values.get("provider"))
61753
+ flagOptions: ["enabled"],
61754
+ run: (ctx) => ctx.flags.has("enabled") ? listEnabled(ctx) : list3(ctx.io, ctx.registry, ctx.values.get("provider"))
60893
61755
  },
60894
61756
  check: {
60895
61757
  usage: "ama models check <provider/id>",
@@ -60905,7 +61767,9 @@ var MODELS_ACTIONS = Object.freeze({
60905
61767
  get usage() {
60906
61768
  return msg().subcommands.models.refreshCatalogUsage;
60907
61769
  }
60908
- }
61770
+ },
61771
+ enable: ENABLE_ACTION,
61772
+ disable: DISABLE_ACTION
60909
61773
  });
60910
61774
  function modelsUsage() {
60911
61775
  return msg().subcommands.models.usage(Object.values(MODELS_ACTIONS).map((a) => a.usage));
@@ -60953,7 +61817,7 @@ async function runModels(argv, io, deps) {
60953
61817
  }
60954
61818
 
60955
61819
  // src/cli/subcommands/providers.ts
60956
- var import_node_fs56 = require("node:fs");
61820
+ var import_node_fs57 = require("node:fs");
60957
61821
  init_models_dev_cache();
60958
61822
  init_models_dev();
60959
61823
  init_auth_file();
@@ -61610,7 +62474,7 @@ ${renderTable2(result.plans)}`);
61610
62474
  const providers = config.providers ??= {};
61611
62475
  providers[id] = merged.config;
61612
62476
  if (defaultPick !== void 0) config.defaultModel = `${id}/${defaultPick.id}`;
61613
- const backup = (0, import_node_fs56.existsSync)(level.userConfigPath);
62477
+ const backup = (0, import_node_fs57.existsSync)(level.userConfigPath);
61614
62478
  writeConfigFile(level.userConfigPath, config, { backup: true });
61615
62479
  if (key.store !== void 0) setAuthKey(level.authFile, id, key.store);
61616
62480
  io.stdout(m.written(level.userConfigPath, backup));
@@ -61726,7 +62590,7 @@ init_init();
61726
62590
  init_paths();
61727
62591
 
61728
62592
  // src/cli/subcommands/sessions.ts
61729
- var import_node_path83 = require("node:path");
62593
+ var import_node_path84 = require("node:path");
61730
62594
  init_gc();
61731
62595
  init_paths();
61732
62596
  init_args();
@@ -61735,8 +62599,8 @@ init_reuse();
61735
62599
  init_clipboard_image();
61736
62600
 
61737
62601
  // src/cli/subcommands/sessions-export.ts
61738
- var import_node_fs58 = require("node:fs");
61739
- var import_node_path77 = require("node:path");
62602
+ var import_node_fs59 = require("node:fs");
62603
+ var import_node_path78 = require("node:path");
61740
62604
  init_paths();
61741
62605
 
61742
62606
  // src/session/export.ts
@@ -61958,7 +62822,7 @@ async function runSessionsExport(argv, io) {
61958
62822
  throw new UsageError(msg().subcommands.common.invalidChoice("--branch", BRANCHES, branch));
61959
62823
  }
61960
62824
  const dirFlag = values.get("session-dir");
61961
- const root = dirFlag !== void 0 ? (0, import_node_path77.resolve)(io.cwd, expandHome(dirFlag, { env: io.env })) : (0, import_node_path77.join)(resolveDataDir({ env: io.env }), "sessions");
62825
+ const root = dirFlag !== void 0 ? (0, import_node_path78.resolve)(io.cwd, expandHome(dirFlag, { env: io.env })) : (0, import_node_path78.join)(resolveDataDir({ env: io.env }), "sessions");
61962
62826
  const session = readSessionReadOnly(findSessionFileReadOnly(root, id, io.cwd));
61963
62827
  const text = renderExport(session, format, branch);
61964
62828
  const output = values.get("output");
@@ -61966,14 +62830,14 @@ async function runSessionsExport(argv, io) {
61966
62830
  io.stdout(text);
61967
62831
  return ExitCode.Ok;
61968
62832
  }
61969
- const target = (0, import_node_path77.resolve)(io.cwd, expandHome(output, { env: io.env }));
61970
- (0, import_node_fs58.writeFileSync)(target, text, { mode: 384 });
62833
+ const target = (0, import_node_path78.resolve)(io.cwd, expandHome(output, { env: io.env }));
62834
+ (0, import_node_fs59.writeFileSync)(target, text, { mode: 384 });
61971
62835
  io.stderr(msg().subcommands.sessionsExport.exported(target));
61972
62836
  return ExitCode.Ok;
61973
62837
  }
61974
62838
 
61975
62839
  // src/cli/subcommands/sessions-search.ts
61976
- var import_node_path80 = require("node:path");
62840
+ var import_node_path81 = require("node:path");
61977
62841
  init_paths();
61978
62842
  init_scan();
61979
62843
 
@@ -62151,7 +63015,7 @@ init_args();
62151
63015
  init_exit_codes();
62152
63016
 
62153
63017
  // src/cli/subcommands/stats.ts
62154
- var import_node_path79 = require("node:path");
63018
+ var import_node_path80 = require("node:path");
62155
63019
  init_paths();
62156
63020
  init_scan();
62157
63021
 
@@ -62299,8 +63163,8 @@ function aggregateStats(summaries, options = {}) {
62299
63163
  }
62300
63164
 
62301
63165
  // src/session/stats-index.ts
62302
- var import_node_fs59 = require("node:fs");
62303
- var import_node_path78 = require("node:path");
63166
+ var import_node_fs60 = require("node:fs");
63167
+ var import_node_path79 = require("node:path");
62304
63168
 
62305
63169
  // src/session/stats-scan.ts
62306
63170
  init_scan();
@@ -62513,7 +63377,7 @@ function collectSummaries(files, options = {}) {
62513
63377
  let index2 = { version: INDEX_VERSION, zone, files: {} };
62514
63378
  if (options.indexFile !== void 0) {
62515
63379
  try {
62516
- const loaded = JSON.parse((0, import_node_fs59.readFileSync)(options.indexFile, "utf8"));
63380
+ const loaded = JSON.parse((0, import_node_fs60.readFileSync)(options.indexFile, "utf8"));
62517
63381
  if (loaded.version === INDEX_VERSION && loaded.zone === zone && typeof loaded.files === "object")
62518
63382
  index2 = loaded;
62519
63383
  } catch {
@@ -62524,7 +63388,7 @@ function collectSummaries(files, options = {}) {
62524
63388
  for (const file of files) {
62525
63389
  let stat16;
62526
63390
  try {
62527
- stat16 = (0, import_node_fs59.statSync)(file);
63391
+ stat16 = (0, import_node_fs60.statSync)(file);
62528
63392
  } catch {
62529
63393
  result.invalid++;
62530
63394
  continue;
@@ -62554,10 +63418,10 @@ function collectSummaries(files, options = {}) {
62554
63418
  }
62555
63419
  if (dirty && options.indexFile !== void 0) {
62556
63420
  try {
62557
- (0, import_node_fs59.mkdirSync)((0, import_node_path78.dirname)(options.indexFile), { recursive: true, mode: 448 });
63421
+ (0, import_node_fs60.mkdirSync)((0, import_node_path79.dirname)(options.indexFile), { recursive: true, mode: 448 });
62558
63422
  const tmp = `${options.indexFile}.${process.pid}.tmp`;
62559
- (0, import_node_fs59.writeFileSync)(tmp, JSON.stringify(index2), { mode: 384 });
62560
- (0, import_node_fs59.renameSync)(tmp, options.indexFile);
63423
+ (0, import_node_fs60.writeFileSync)(tmp, JSON.stringify(index2), { mode: 384 });
63424
+ (0, import_node_fs60.renameSync)(tmp, options.indexFile);
62561
63425
  } catch {
62562
63426
  }
62563
63427
  }
@@ -62607,10 +63471,10 @@ function width(text) {
62607
63471
  }
62608
63472
  function table(rows, rightAlign) {
62609
63473
  const widths = [];
62610
- for (const row2 of rows)
62611
- row2.forEach((cell, i) => widths[i] = Math.max(widths[i] ?? 0, width(cell)));
63474
+ for (const row3 of rows)
63475
+ row3.forEach((cell, i) => widths[i] = Math.max(widths[i] ?? 0, width(cell)));
62612
63476
  return rows.map(
62613
- (row2) => row2.map((cell, i) => {
63477
+ (row3) => row3.map((cell, i) => {
62614
63478
  const padding = " ".repeat((widths[i] ?? 0) - width(cell));
62615
63479
  return rightAlign(i) ? padding + cell : cell + padding;
62616
63480
  }).join(" ").trimEnd()
@@ -62718,13 +63582,13 @@ async function runStats(argv, io) {
62718
63582
  }
62719
63583
  const dataDir = resolveDataDir({ env: io.env });
62720
63584
  const dirFlag = values.get("session-dir");
62721
- const root = dirFlag !== void 0 ? (0, import_node_path79.resolve)(io.cwd, expandHome(dirFlag, { env: io.env })) : (0, import_node_path79.join)(dataDir, "sessions");
63585
+ const root = dirFlag !== void 0 ? (0, import_node_path80.resolve)(io.cwd, expandHome(dirFlag, { env: io.env })) : (0, import_node_path80.join)(dataDir, "sessions");
62722
63586
  const projectFlag = values.get("project");
62723
- const project = projectFlag !== void 0 ? (0, import_node_path79.resolve)(io.cwd, expandHome(projectFlag, { env: io.env })) : flags2.has("all") || by === "project" ? void 0 : io.cwd;
63587
+ const project = projectFlag !== void 0 ? (0, import_node_path80.resolve)(io.cwd, expandHome(projectFlag, { env: io.env })) : flags2.has("all") || by === "project" ? void 0 : io.cwd;
62724
63588
  const files = sessionFilesInScope(root, project);
62725
63589
  const useCache = !flags2.has("no-cache");
62726
63590
  const collected = collectSummaries(files, {
62727
- ...useCache ? { indexFile: (0, import_node_path79.join)(dataDir, STATS_INDEX_FILE) } : {},
63591
+ ...useCache ? { indexFile: (0, import_node_path80.join)(dataDir, STATS_INDEX_FILE) } : {},
62728
63592
  prune: project === void 0
62729
63593
  });
62730
63594
  const report2 = aggregateStats(collected.summaries, {
@@ -62819,7 +63683,7 @@ async function runSessionsSearch(argv, io) {
62819
63683
  const sinceRaw = values.get("since");
62820
63684
  const sinceIso = sinceRaw === void 0 ? void 0 : (/* @__PURE__ */ new Date(`${parseDaySpec("since", sinceRaw)}T00:00:00`)).toISOString();
62821
63685
  const dirFlag = values.get("session-dir");
62822
- const root = dirFlag !== void 0 ? (0, import_node_path80.resolve)(io.cwd, expandHome(dirFlag, { env: io.env })) : (0, import_node_path80.join)(resolveDataDir({ env: io.env }), "sessions");
63686
+ const root = dirFlag !== void 0 ? (0, import_node_path81.resolve)(io.cwd, expandHome(dirFlag, { env: io.env })) : (0, import_node_path81.join)(resolveDataDir({ env: io.env }), "sessions");
62823
63687
  const files = sessionFilesInScope(root, flags2.has("all") ? void 0 : io.cwd);
62824
63688
  const { hits, truncated } = searchSessions(files, query, {
62825
63689
  limit,
@@ -62843,9 +63707,9 @@ async function runSessionsSearch(argv, io) {
62843
63707
 
62844
63708
  // src/cli/subcommands/sessions-trace.ts
62845
63709
  var import_node_child_process15 = require("node:child_process");
62846
- var import_node_fs61 = require("node:fs");
63710
+ var import_node_fs62 = require("node:fs");
62847
63711
  var import_node_os12 = require("node:os");
62848
- var import_node_path82 = require("node:path");
63712
+ var import_node_path83 = require("node:path");
62849
63713
  init_paths();
62850
63714
  init_i18n();
62851
63715
  init_scan();
@@ -63061,8 +63925,8 @@ function mapTime(points, raw) {
63061
63925
  }
63062
63926
  return prev[1] + (raw - prev[0]);
63063
63927
  }
63064
- function segments2(row2, at) {
63065
- const node = row2.node;
63928
+ function segments2(row3, at) {
63929
+ const node = row3.node;
63066
63930
  if (node.kind === "more" || node.kind === "aux_group") return [];
63067
63931
  const out = [];
63068
63932
  const running = node.status === "running" && node.endedAt === void 0;
@@ -63131,20 +63995,20 @@ function traceHtmlData(source, opts) {
63131
63995
  const parents = [];
63132
63996
  const under = [];
63133
63997
  let span = axis.at(-1)?.[1] ?? 0;
63134
- flat2.forEach((row2, i) => {
63135
- parents.length = row2.depth;
63136
- const node = row2.node;
63998
+ flat2.forEach((row3, i) => {
63999
+ parents.length = row3.depth;
64000
+ const node = row3.node;
63137
64001
  const out = {
63138
- d: row2.depth,
63139
- p: row2.depth === 0 ? -1 : parents[row2.depth - 1] ?? -1,
64002
+ d: row3.depth,
64003
+ p: row3.depth === 0 ? -1 : parents[row3.depth - 1] ?? -1,
63140
64004
  k: node.kind,
63141
- l: redactSecrets(rowLabel(row2, describe4 === void 0 ? {} : { describe: describe4 })),
64005
+ l: redactSecrets(rowLabel(row3, describe4 === void 0 ? {} : { describe: describe4 })),
63142
64006
  kv: []
63143
64007
  };
63144
64008
  const parent = out.p < 0 ? void 0 : rows[out.p];
63145
- const inChild = row2.depth > 0 && ((under[row2.depth - 1] ?? false) || parent?.k === "subagent");
63146
- under[row2.depth] = inChild;
63147
- parents[row2.depth] = i;
64009
+ const inChild = row3.depth > 0 && ((under[row3.depth - 1] ?? false) || parent?.k === "subagent");
64010
+ under[row3.depth] = inChild;
64011
+ parents[row3.depth] = i;
63148
64012
  if (node.kind !== "more" && node.kind !== "aux_group") {
63149
64013
  if (node.status !== "ok") {
63150
64014
  out.s = m.status[node.status];
@@ -63157,7 +64021,7 @@ function traceHtmlData(source, opts) {
63157
64021
  const ca = cacheText2(node);
63158
64022
  if (ca !== "") out.ca = ca;
63159
64023
  out.kv = summaryRows(node, theme, t0).filter(([label2]) => opts.content || !dropKeys.has(label2)).map(([label2, value]) => [label2, redactSecrets(value)]);
63160
- const g = segments2(row2, at);
64024
+ const g = segments2(row3, at);
63161
64025
  if (g.length > 0) {
63162
64026
  out.g = g;
63163
64027
  for (const seg of g) span = Math.max(span, seg[1]);
@@ -63170,20 +64034,20 @@ function traceHtmlData(source, opts) {
63170
64034
  }
63171
64035
  }
63172
64036
  }
63173
- if (row2.expandable && defaultExpanded(node)) out.e = 1;
63174
- if (node.kind === "turn" && row2.depth === 0) out.t = row2.turn;
64037
+ if (row3.expandable && defaultExpanded(node)) out.e = 1;
64038
+ if (node.kind === "turn" && row3.depth === 0) out.t = row3.turn;
63175
64039
  rows.push(out);
63176
64040
  });
63177
64041
  let budget = opts.previewBudget ?? PREVIEW_BUDGET;
63178
64042
  for (let i = rows.length - 1; i >= 0; i--) {
63179
- const row2 = rows[i];
63180
- if (row2.pv === void 0) continue;
63181
- const size = row2.pv.reduce((n, [, text]) => n + text.length, 0);
64043
+ const row3 = rows[i];
64044
+ if (row3.pv === void 0) continue;
64045
+ const size = row3.pv.reduce((n, [, text]) => n + text.length, 0);
63182
64046
  if (size <= budget) budget -= size;
63183
64047
  else {
63184
64048
  budget = 0;
63185
- delete row2.pv;
63186
- row2.pd = 1;
64049
+ delete row3.pv;
64050
+ row3.pd = 1;
63187
64051
  }
63188
64052
  }
63189
64053
  const h = m.html;
@@ -63281,9 +64145,9 @@ function splitHtmlFlag(argv) {
63281
64145
  return { rest, html, ...file !== void 0 ? { file } : {} };
63282
64146
  }
63283
64147
  function locate(io, target, dirFlag) {
63284
- const asPath = (0, import_node_path82.resolve)(io.cwd, expandHome(target, { env: io.env }));
63285
- if (/[\\/]|\.jsonl$/.test(target) && (0, import_node_fs61.existsSync)(asPath)) return asPath;
63286
- const root = dirFlag !== void 0 ? (0, import_node_path82.resolve)(io.cwd, expandHome(dirFlag, { env: io.env })) : (0, import_node_path82.join)(resolveDataDir({ env: io.env }), "sessions");
64148
+ const asPath = (0, import_node_path83.resolve)(io.cwd, expandHome(target, { env: io.env }));
64149
+ if (/[\\/]|\.jsonl$/.test(target) && (0, import_node_fs62.existsSync)(asPath)) return asPath;
64150
+ const root = dirFlag !== void 0 ? (0, import_node_path83.resolve)(io.cwd, expandHome(dirFlag, { env: io.env })) : (0, import_node_path83.join)(resolveDataDir({ env: io.env }), "sessions");
63287
64151
  return findSessionFileReadOnly(root, target, io.cwd);
63288
64152
  }
63289
64153
  async function runSessionsTrace(argv, io, deps = {}) {
@@ -63348,14 +64212,14 @@ async function runSessionsTrace(argv, io, deps = {}) {
63348
64212
  }
63349
64213
  const outFlag = split.file ?? values.get("output");
63350
64214
  const open2 = flags2.has("open");
63351
- let outPath = outFlag === void 0 ? void 0 : (0, import_node_path82.resolve)(io.cwd, expandHome(outFlag, { env: io.env }));
64215
+ let outPath = outFlag === void 0 ? void 0 : (0, import_node_path83.resolve)(io.cwd, expandHome(outFlag, { env: io.env }));
63352
64216
  if (outPath === void 0 && open2)
63353
- outPath = (0, import_node_path82.join)((0, import_node_os12.tmpdir)(), `ama-trace-${read2.header.id}.${wantsJson ? "json" : "html"}`);
64217
+ outPath = (0, import_node_path83.join)((0, import_node_os12.tmpdir)(), `ama-trace-${read2.header.id}.${wantsJson ? "json" : "html"}`);
63354
64218
  if (outPath === void 0) {
63355
64219
  io.stdout(text);
63356
64220
  return ExitCode.Ok;
63357
64221
  }
63358
- (0, import_node_fs61.writeFileSync)(outPath, text, { mode: 384 });
64222
+ (0, import_node_fs62.writeFileSync)(outPath, text, { mode: 384 });
63359
64223
  io.stderr(m.wrote(outPath));
63360
64224
  if (open2) {
63361
64225
  try {
@@ -63396,7 +64260,7 @@ async function runSessions(argv, io, deps) {
63396
64260
  return flags2.has("help") ? ExitCode.Ok : ExitCode.Usage;
63397
64261
  }
63398
64262
  const dirFlag = values.get("session-dir");
63399
- const sessionDir = dirFlag !== void 0 ? (0, import_node_path83.resolve)(io.cwd, expandHome(dirFlag, { env: io.env })) : (0, import_node_path83.resolve)(resolveDataDir({ env: io.env }), "sessions");
64263
+ const sessionDir = dirFlag !== void 0 ? (0, import_node_path84.resolve)(io.cwd, expandHome(dirFlag, { env: io.env })) : (0, import_node_path84.resolve)(resolveDataDir({ env: io.env }), "sessions");
63400
64264
  const sessions = deps?.sessions;
63401
64265
  const scope = flags2.has("all") ? {} : { cwd: io.cwd };
63402
64266
  switch (action) {
@@ -63482,7 +64346,7 @@ async function pruneFileHistory(io, sessionDir, dryRun) {
63482
64346
  try {
63483
64347
  const result = await gcBlobs({
63484
64348
  dataDir,
63485
- sessionRoots: [sessionDir, (0, import_node_path83.join)(dataDir, "sessions")],
64349
+ sessionRoots: [sessionDir, (0, import_node_path84.join)(dataDir, "sessions")],
63486
64350
  dryRun
63487
64351
  });
63488
64352
  if (result.removed.length === 0) return;
@@ -63556,7 +64420,7 @@ function readStdinDefault() {
63556
64420
  }
63557
64421
  function stdinKindDefault() {
63558
64422
  try {
63559
- const stat16 = (0, import_node_fs70.fstatSync)(0);
64423
+ const stat16 = (0, import_node_fs71.fstatSync)(0);
63560
64424
  if (stat16.isFile()) return "file";
63561
64425
  if (stat16.isFIFO()) return "fifo";
63562
64426
  if (stat16.isSocket()) return "socket";
@@ -63616,7 +64480,7 @@ function defaultIo() {
63616
64480
  }
63617
64481
  function peekUserLanguage(env) {
63618
64482
  try {
63619
- const raw = (0, import_node_fs70.readFileSync)((0, import_node_path99.join)(resolveConfigDir({ env }), "config.json"), "utf8");
64483
+ const raw = (0, import_node_fs71.readFileSync)((0, import_node_path100.join)(resolveConfigDir({ env }), "config.json"), "utf8");
63620
64484
  const value = JSON.parse(raw).ui?.language;
63621
64485
  return value === "auto" || value === "zh" || value === "en" ? value : void 0;
63622
64486
  } catch {
@@ -63704,7 +64568,7 @@ function isDirectRun() {
63704
64568
  const entry = process.argv[1];
63705
64569
  if (entry === void 0) return false;
63706
64570
  try {
63707
- return (0, import_node_fs70.realpathSync)(entry) === (0, import_node_fs70.realpathSync)((0, import_node_url3.fileURLToPath)(__ama_import_meta_url));
64571
+ return (0, import_node_fs71.realpathSync)(entry) === (0, import_node_fs71.realpathSync)((0, import_node_url3.fileURLToPath)(__ama_import_meta_url));
63708
64572
  } catch {
63709
64573
  return false;
63710
64574
  }