@armadra/agent 0.7.5 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/CHANGELOG.zh-CN.md +34 -0
  3. package/dist/agent/session-classifier.d.ts +2 -0
  4. package/dist/agent/session-classifier.js +24 -3
  5. package/dist/agent/session-extensions.d.ts +1 -0
  6. package/dist/agent/session-extensions.js +3 -0
  7. package/dist/agent/session-subagent.js +9 -2
  8. package/dist/agent/subagent-background.d.ts +5 -1
  9. package/dist/agent/subagent-background.js +13 -1
  10. package/dist/agent/subagent-fork.d.ts +10 -5
  11. package/dist/agent/subagent-fork.js +22 -6
  12. package/dist/agent/subagent-registry.d.ts +1 -1
  13. package/dist/agent/subagent-registry.js +1 -1
  14. package/dist/agents/catalog.d.ts +1 -0
  15. package/dist/ai/apis/chatgpt-backend.d.ts +3 -1
  16. package/dist/ai/apis/chatgpt-backend.js +10 -1
  17. package/dist/ai/apis/max-tokens.d.ts +4 -0
  18. package/dist/ai/apis/max-tokens.js +12 -1
  19. package/dist/ai/providers/enrich.d.ts +6 -2
  20. package/dist/ai/providers/enrich.js +13 -2
  21. package/dist/ai/providers/max-tokens-cache.d.ts +22 -0
  22. package/dist/ai/providers/max-tokens-cache.js +95 -0
  23. package/dist/ai/providers/registry.js +3 -3
  24. package/dist/bundle/ama.cjs +1250 -375
  25. package/dist/checkpoints/shadow-git.d.ts +5 -1
  26. package/dist/checkpoints/shadow-git.js +11 -2
  27. package/dist/cli/compose-providers.d.ts +1 -0
  28. package/dist/cli/compose-providers.js +3 -0
  29. package/dist/cli/compose-store.d.ts +6 -2
  30. package/dist/cli/compose-store.js +8 -4
  31. package/dist/cli/compose.js +2 -2
  32. package/dist/config/json-schema.js +1 -0
  33. package/dist/config/key-docs.js +1 -0
  34. package/dist/config/schema-w5.js +2 -0
  35. package/dist/config/settings-registry.js +1 -0
  36. package/dist/config/types-w5.d.ts +5 -0
  37. package/dist/drivers/acp/driver.d.ts +22 -1
  38. package/dist/drivers/acp/driver.js +59 -5
  39. package/dist/drivers/agents.js +3 -0
  40. package/dist/drivers/catalog.d.ts +2 -0
  41. package/dist/drivers/catalog.js +94 -4
  42. package/dist/drivers/native/claude-normalize.d.ts +8 -0
  43. package/dist/drivers/native/claude-normalize.js +27 -0
  44. package/dist/drivers/native/claude-stream.js +16 -1
  45. package/dist/drivers/native/codex-app-server.js +4 -2
  46. package/dist/drivers/native/oneshot.js +12 -2
  47. package/dist/drivers/native/pi-gate.d.ts +19 -0
  48. package/dist/drivers/native/pi-gate.js +39 -0
  49. package/dist/drivers/native/pi-rpc.d.ts +29 -0
  50. package/dist/drivers/native/pi-rpc.js +483 -0
  51. package/dist/drivers/runner.js +1 -0
  52. package/dist/drivers/types.d.ts +1 -1
  53. package/dist/i18n/catalog.d.ts +5 -0
  54. package/dist/i18n/messages/auth.d.ts +2 -0
  55. package/dist/i18n/messages/auth.js +2 -0
  56. package/dist/i18n/messages/config-keys.d.ts +2 -0
  57. package/dist/i18n/messages/config-keys.js +2 -0
  58. package/dist/i18n/messages/config.d.ts +2 -0
  59. package/dist/i18n/messages/drivers.d.ts +4 -0
  60. package/dist/i18n/messages/drivers.js +4 -0
  61. package/dist/i18n/messages/interactive.d.ts +2 -0
  62. package/dist/i18n/messages/interactive.js +2 -0
  63. package/dist/i18n/messages/session.js +2 -2
  64. package/dist/modes/interactive/agent-ui.js +7 -0
  65. package/dist/session/manager.d.ts +3 -1
  66. package/dist/session/manager.js +5 -0
  67. package/dist/session/offload.d.ts +10 -2
  68. package/dist/session/offload.js +27 -4
  69. package/dist/tools/background-jobs.d.ts +4 -4
  70. package/dist/tools/background-jobs.js +4 -4
  71. package/dist/tools/bash.d.ts +2 -1
  72. package/dist/tools/bash.js +4 -3
  73. package/dist/tools/task-ctl.js +2 -1
  74. package/dist/tools/task.d.ts +9 -0
  75. package/dist/tools/task.js +27 -1
  76. package/docs/agents.md +70 -14
  77. package/docs/en/permissions.md +1 -1
  78. package/docs/en/providers.md +11 -10
  79. package/docs/en/sessions.md +2 -1
  80. package/docs/permissions.md +1 -1
  81. package/docs/providers.md +16 -11
  82. package/docs/session-format.md +2 -1
  83. package/docs/sessions.md +2 -1
  84. 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.7.5" : readPackageVersion();
44
+ AMA_VERSION = true ? "0.8.0" : readPackageVersion();
45
45
  }
46
46
  });
47
47
 
@@ -1969,7 +1969,8 @@ var init_interactive = __esm({
1969
1969
  backgroundExited: (jobId, code, command3) => `Background command ${jobId} exited (code ${code}): ${command3}`,
1970
1970
  backgroundStopped: (jobId, command3) => `Background command ${jobId} stopped: ${command3}`,
1971
1971
  compactionFailed: (error2) => `Compaction failed: ${error2}`,
1972
- compactionCancelled: "Compaction cancelled"
1972
+ compactionCancelled: "Compaction cancelled",
1973
+ imageReadBackFailed: (id) => `Session image for entry ${id} could not be read back (file changed); it stays empty`
1973
1974
  },
1974
1975
  statusLine: {
1975
1976
  usage: "Usage: /statusline [full|compact]",
@@ -2104,7 +2105,8 @@ var init_interactive = __esm({
2104
2105
  backgroundExited: (jobId, code, command3) => `后台命令 ${jobId} 已退出(码 ${code}):${command3}`,
2105
2106
  backgroundStopped: (jobId, command3) => `后台命令 ${jobId} 已停止:${command3}`,
2106
2107
  compactionFailed: (error2) => `压缩失败:${error2}`,
2107
- compactionCancelled: "压缩已取消"
2108
+ compactionCancelled: "压缩已取消",
2109
+ imageReadBackFailed: (id) => `会话文件已改变,条目 ${id} 的图片读不回,保留为空`
2108
2110
  },
2109
2111
  statusLine: {
2110
2112
  usage: "用法:/statusline [full|compact]",
@@ -3814,6 +3816,7 @@ var init_config_keys = __esm({
3814
3816
  "subagents.maxPending": "Queue limit; task fails beyond it",
3815
3817
  "subagents.retainSessions": "Finished sub-sessions kept in memory (least recently used first out); others reopen from their session file when continued",
3816
3818
  "subagents.defaultModel": "Default sub-session model provider/model[@channel]",
3819
+ "subagents.forkMaxContextRatio": "Fork sub-agents fall back to fresh when the parent's last request used more than this share of (window − compaction.reserveTokens); 0.05–0.95, default 0.5",
3817
3820
  "subagents.background": "Whether task runs in the background by default: auto = background in the TUI / RPC / ACP and foreground with -p; always / never are fixed. The call argument and the agent type's background: override it; user, project and host level",
3818
3821
  "subagents.autoBackgroundAfterMs": "Move a foreground task to the background after it has run this many milliseconds; 0 disables; user and project level",
3819
3822
  models: "Model aliases and the model picker list; user level only (effective from wave 5 W5-G)",
@@ -3942,6 +3945,7 @@ var init_config_keys = __esm({
3942
3945
  "subagents.maxPending": "排队上限,超出时 task 报错",
3943
3946
  "subagents.retainSessions": "内存中保留的已结束子会话数(最久未用的先释放),其余续聊时从会话文件重开",
3944
3947
  "subagents.defaultModel": "子会话缺省模型 provider/model[@channel]",
3948
+ "subagents.forkMaxContextRatio": "fork 子 Agent 的回落比例:父上一次请求超过(窗口 − compaction.reserveTokens)的这一比例时改为 fresh;0.05–0.95,缺省 0.5",
3945
3949
  "subagents.background": "task 缺省是否后台:auto = TUI / RPC / ACP 下后台、-p 下前台;always / never 固定。调用参数与类型定义的 background: 优先;用户、项目、宿主级都认",
3946
3950
  "subagents.autoBackgroundAfterMs": "前台任务运行超过该毫秒数自动转后台;0 关闭;用户、项目级都认",
3947
3951
  models: "模型别名与模型选择器清单;只认用户级(第五波 W5-G 起生效)",
@@ -4237,6 +4241,7 @@ var init_drivers = __esm({
4237
4241
  resumeUnsupported: (agent) => `${agent} cannot resume sessions; started a new one`,
4238
4242
  resumeNotFound: (agent, id) => `${agent} cannot find session ${id}; started a new one`,
4239
4243
  noMatchingMode: (agent, mode) => `${agent} has no "${mode}" mode; running in its own default mode (actions that need approval still come to you)`,
4244
+ noMatchingModel: (agent, model) => `${agent} does not offer model "${model}"; using its own default model`,
4240
4245
  noImages: (agent) => `${agent} does not accept images; omitted`,
4241
4246
  noImagesDriver: (agent) => `the ${agent} driver does not pass images yet; omitted`,
4242
4247
  noImagesOneshot: (agent) => `${agent} one-shot mode does not pass images; omitted`,
@@ -4247,6 +4252,7 @@ var init_drivers = __esm({
4247
4252
  error: (agent, message, retrying) => `${agent}: ${message}${retrying ? " (retrying)" : ""}`,
4248
4253
  askedQuestion: (agent, tool) => `${agent} wants to ask you a question (${tool}); ama does not answer for you and asked it to put the question in its final reply`,
4249
4254
  askedQuestionCodex: (agent) => `${agent} wants to ask you a question; ama does not answer for you — have it put the question in its final reply`,
4255
+ extensionDialog: (agent, title) => `${agent}: an extension asked for input (${title}); ama does not answer for you, cancelled`,
4250
4256
  mcpElicitation: (agent) => `${agent}'s MCP server asked for input; ama does not answer for you, cancelled`
4251
4257
  },
4252
4258
  /** Hook 配置与输出的警告(给人看;回给模型的阻止理由固定英文)。 */
@@ -4296,6 +4302,7 @@ var init_drivers = __esm({
4296
4302
  resumeUnsupported: (agent) => `${agent} 不支持续接会话,已新开`,
4297
4303
  resumeNotFound: (agent, id) => `${agent} 找不到会话 ${id},已新开`,
4298
4304
  noMatchingMode: (agent, mode) => `${agent} 没有「${mode}」模式,按它自己的缺省模式运行(需要授权的操作仍交给你)`,
4305
+ noMatchingModel: (agent, model) => `${agent} 没有模型「${model}」,按它自己的缺省模型运行`,
4299
4306
  noImages: (agent) => `${agent} 不接受图片,已省略`,
4300
4307
  noImagesDriver: (agent) => `${agent} 驱动暂不传图片,已省略`,
4301
4308
  noImagesOneshot: (agent) => `${agent} 一次性模式不传图片,已省略`,
@@ -4306,6 +4313,7 @@ var init_drivers = __esm({
4306
4313
  error: (agent, message, retrying) => `${agent}:${message}${retrying ? "(重试中)" : ""}`,
4307
4314
  askedQuestion: (agent, tool) => `${agent} 想向你提问(${tool});ama 不代答,已请它把问题写进最终回复`,
4308
4315
  askedQuestionCodex: (agent) => `${agent} 想向你提问;ama 不代答,请让它把问题写进最终回复`,
4316
+ extensionDialog: (agent, title) => `${agent}:扩展请求输入(${title});ama 不代答,已取消`,
4309
4317
  mcpElicitation: (agent) => `${agent} 的 MCP 服务器请求输入;ama 不代答,已取消`
4310
4318
  },
4311
4319
  hooks: {
@@ -4439,7 +4447,7 @@ var init_session = __esm({
4439
4447
  cwdIsHome: "the working directory is the home directory",
4440
4448
  gitNotFound: "git not found",
4441
4449
  tooManyFiles: (files, max) => `the working directory has ${plural(files, "file")} (limit ${max})`,
4442
- tooSlow: (seconds2, max) => `the snapshot took ${seconds2} s (limit ${max} s)`,
4450
+ tooSlow: (seconds2, max) => `snapshots took longer than ${max} s twice in a row (latest ${seconds2} s)`,
4443
4451
  gitFailed: (command3, code, detail) => `git ${command3} failed (${code})${detail === "" ? "" : `: ${detail}`}`,
4444
4452
  noShadowCommit: "the checkpoint has no shadow commit",
4445
4453
  shadowCommitMissing: (commit) => `shadow commit ${commit} does not exist`,
@@ -4571,7 +4579,7 @@ var init_session = __esm({
4571
4579
  cwdIsHome: "工作目录是家目录",
4572
4580
  gitNotFound: "找不到 git",
4573
4581
  tooManyFiles: (files, max) => `工作目录有 ${files} 个文件(上限 ${max})`,
4574
- tooSlow: (seconds2, max) => `快照用了 ${seconds2} 秒(上限 ${max} 秒)`,
4582
+ tooSlow: (seconds2, max) => `连续两次快照超过 ${max} 秒(最近一次 ${seconds2} 秒)`,
4575
4583
  gitFailed: (command3, code, detail) => `git ${command3} 失败(${code})${detail === "" ? "" : `:${detail}`}`,
4576
4584
  noShadowCommit: "检查点没有影子提交",
4577
4585
  shadowCommitMissing: (commit) => `影子提交 ${commit} 不存在`,
@@ -5355,6 +5363,7 @@ Then paste the full URL from the address bar (http://127.0.0.1:…/auth/callback
5355
5363
  },
5356
5364
  request: {
5357
5365
  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",
5366
+ modelUnavailable: (model) => `${model} is not available to this ChatGPT account (400 from the codex backend). The backend's model list changes over time: run ama models discover chatgpt to refresh it, then pick a listed model with /model or --model`,
5358
5367
  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}`
5359
5368
  },
5360
5369
  errors: {
@@ -5463,6 +5472,7 @@ Then paste the full URL from the address bar (http://127.0.0.1:…/auth/callback
5463
5472
  },
5464
5473
  request: {
5465
5474
  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",
5475
+ modelUnavailable: (model) => `${model} 在这个 ChatGPT 账户下不可用(codex 后端回 400)。后端的模型表会变化:运行 ama models discover chatgpt 刷新,再用 /model 或 --model 选表里的模型`,
5466
5476
  flavorMismatch: (current3, ref, pinned) => `当前以 ${current3} 方式登录,但 ${ref} 显式指定了 @${pinned} 渠道。去掉 @${pinned} 让渠道跟随登录方式,或运行 ama auth login chatgpt --flavor ${pinned}`
5467
5477
  },
5468
5478
  errors: {
@@ -6776,7 +6786,8 @@ function validateConfigW5(c, config) {
6776
6786
  "defaultModel",
6777
6787
  "background",
6778
6788
  "autoBackgroundAfterMs",
6779
- "retainSessions"
6789
+ "retainSessions",
6790
+ "forkMaxContextRatio"
6780
6791
  ],
6781
6792
  (s2, p) => {
6782
6793
  c.number(s2, "maxConcurrent", p, 1, 64);
@@ -6785,6 +6796,7 @@ function validateConfigW5(c, config) {
6785
6796
  c.oneOf(s2, "background", p, SUBAGENT_BACKGROUND_MODES);
6786
6797
  c.number(s2, "autoBackgroundAfterMs", p, 0);
6787
6798
  c.number(s2, "retainSessions", p, 0);
6799
+ c.number(s2, "forkMaxContextRatio", p, 0.05, 0.95);
6788
6800
  }
6789
6801
  );
6790
6802
  checkSection(c, config, "models", ["aliases", "enabled"], (s2, p) => {
@@ -12382,7 +12394,7 @@ function fillLimits(out, hit, sources) {
12382
12394
  sources.maxTokens = "catalog-alias";
12383
12395
  }
12384
12396
  }
12385
- function enrichEntry(entry, index2) {
12397
+ function enrichEntry(entry, index2, providerId) {
12386
12398
  const { modelsDev, channels: _channels, catalog: _catalog, ...rest } = entry;
12387
12399
  const sources = {};
12388
12400
  for (const field2 of ENRICHABLE_FIELDS) {
@@ -12390,10 +12402,14 @@ function enrichEntry(entry, index2) {
12390
12402
  }
12391
12403
  const metadata = { sources, looked: false };
12392
12404
  const out = { ...rest };
12405
+ const warnings = [];
12406
+ const ref = `${providerId ?? "?"}/${entry.id}`;
12393
12407
  const hit = catalogHit(entry);
12394
12408
  if (hit !== void 0) {
12395
12409
  metadata.catalog = hit.ref;
12396
12410
  inheritIntrinsic(out, hit, sources);
12411
+ } else if (typeof entry.catalog === "string") {
12412
+ warnings.push(`catalog "${entry.catalog}" for "${ref}" not found; ignored`);
12397
12413
  }
12398
12414
  const explicit = typeof modelsDev === "string" ? modelsDev : hit?.snapshotRef;
12399
12415
  const lookup = modelsDev !== false && (needsLookup(out) || modelsDev !== void 0);
@@ -12420,7 +12436,10 @@ function enrichEntry(entry, index2) {
12420
12436
  }
12421
12437
  }
12422
12438
  }
12439
+ if (typeof modelsDev === "string" && metadata.looked && metadata.match === void 0)
12440
+ warnings.push(`modelsDev "${modelsDev}" for "${ref}" not found`);
12423
12441
  if (hit !== void 0 && modelsDev !== false) fillLimits(out, hit, sources);
12442
+ if (warnings.length > 0) metadata.warnings = warnings;
12424
12443
  return { entry: out, metadata };
12425
12444
  }
12426
12445
  function catalogMetadata(model) {
@@ -17599,8 +17618,8 @@ var init_background_jobs = __esm({
17599
17618
  await entry.done;
17600
17619
  return entry.job;
17601
17620
  }
17602
- /** 输出文件尾部(2000 行 / 50 KB)。 */
17603
- output(id) {
17621
+ /** 输出文件尾部(缺省 2000 行 / 50 KB;调用方可传字节上限,#155)。 */
17622
+ output(id, options = {}) {
17604
17623
  const entry = this.entries.get(id);
17605
17624
  if (entry === void 0) return void 0;
17606
17625
  let text = "";
@@ -17609,7 +17628,7 @@ var init_background_jobs = __esm({
17609
17628
  text = (0, import_node_fs24.readFileSync)(entry.job.outputPath, "utf8");
17610
17629
  } catch {
17611
17630
  }
17612
- return { ...truncateTail(text), job: entry.job };
17631
+ return { ...truncateTail(text, options), job: entry.job };
17613
17632
  }
17614
17633
  /** 取走已退出、尚未通知的任务(提醒通道用;wait 已看到退出的也算已知)。 */
17615
17634
  takeExited() {
@@ -18097,7 +18116,7 @@ async function jobAction(input2, ctx, options) {
18097
18116
  }
18098
18117
  if (action === "stop") {
18099
18118
  const job2 = await jobs.stop(id);
18100
- const out2 = jobs.output(id);
18119
+ const out2 = jobs.output(id, { maxBytes: toolOutputBytes(ctx.maxResultChars) });
18101
18120
  const text = out2?.content ?? "";
18102
18121
  return {
18103
18122
  content: `${text === "" ? "(no output)" : text}
@@ -18112,7 +18131,7 @@ ${jobStatusLine(job2)}`,
18112
18131
  return fail2(`timeoutMs must be between 1 and ${MAX_BASH_TIMEOUT_MS}`);
18113
18132
  await jobs.wait(id, waitMs, ctx.signal);
18114
18133
  }
18115
- const out = jobs.output(id);
18134
+ const out = jobs.output(id, { maxBytes: toolOutputBytes(ctx.maxResultChars) });
18116
18135
  if (out === void 0) return fail2(`Unknown background job ${id}`);
18117
18136
  const job = out.job;
18118
18137
  if (job.status !== "running") jobs.markSeen(id);
@@ -18799,6 +18818,16 @@ var init_result = __esm({
18799
18818
  });
18800
18819
 
18801
18820
  // src/tools/task.ts
18821
+ function taskLine(prompt) {
18822
+ const line2 = prompt.split("\n").find((text) => text.trim() !== "")?.trim() ?? "";
18823
+ return line2.length > TASK_LINE_MAX ? `${line2.slice(0, TASK_LINE_MAX - 1)}…` : line2;
18824
+ }
18825
+ function nestedTaskRejection(ctx, tool, fallback) {
18826
+ const mark = ctx.session.lastCustom(FORK_CUSTOM_TYPE);
18827
+ if (mark === void 0 || mark === null) return fallback;
18828
+ const line2 = typeof mark.taskLine === "string" ? mark.taskLine : "";
18829
+ return `${tool} rejected: you are a sub-agent forked from the main conversation and cannot start or manage sub-agents. Do not call task or task_ctl again; complete the sub-task in your <task> block yourself with your other tools, then end with your report.` + (line2 !== "" ? ` Your task begins: "${line2}"` : "");
18830
+ }
18802
18831
  function bindTaskAgents(tool, catalog) {
18803
18832
  if (tool !== void 0) catalogs.set(tool, catalog);
18804
18833
  }
@@ -18878,7 +18907,13 @@ function createTaskTool(_options = {}) {
18878
18907
  promptGuidelines: [TASK_NOTIFICATION_RULE],
18879
18908
  async execute(input2, ctx) {
18880
18909
  if (ctx.depth >= MAX_TASK_DEPTH || ctx.spawnSubagent === void 0) {
18881
- return fail3("Sub-agents are not available here (nested tasks are not allowed).");
18910
+ return fail3(
18911
+ nestedTaskRejection(
18912
+ ctx,
18913
+ "task",
18914
+ "Sub-agents are not available here (nested tasks are not allowed)."
18915
+ )
18916
+ );
18882
18917
  }
18883
18918
  const request = buildSubagentRequest(input2, ctx);
18884
18919
  if (typeof request === "string") return fail3(request);
@@ -18907,13 +18942,15 @@ function createTaskTool(_options = {}) {
18907
18942
  };
18908
18943
  return tool;
18909
18944
  }
18910
- var MAX_TASK_DEPTH, THINKING, TASK_CONTEXT_LEAD, FOREGROUND_DESCRIPTION, BACKGROUND_DESCRIPTION, TASK_AGENTS_HEADING, catalogs, backgrounds;
18945
+ var MAX_TASK_DEPTH, TASK_LINE_MAX, FORK_CUSTOM_TYPE, THINKING, TASK_CONTEXT_LEAD, FOREGROUND_DESCRIPTION, BACKGROUND_DESCRIPTION, TASK_AGENTS_HEADING, catalogs, backgrounds;
18911
18946
  var init_task = __esm({
18912
18947
  "src/tools/task.ts"() {
18913
18948
  "use strict";
18914
18949
  init_catalog3();
18915
18950
  init_result();
18916
18951
  MAX_TASK_DEPTH = 1;
18952
+ TASK_LINE_MAX = 120;
18953
+ FORK_CUSTOM_TYPE = "ama.fork";
18917
18954
  THINKING = [
18918
18955
  "off",
18919
18956
  "minimal",
@@ -18995,7 +19032,10 @@ function createTaskCtlTool() {
18995
19032
  executionMode: "parallel",
18996
19033
  annotations: { pollable: true },
18997
19034
  async execute(input2, ctx) {
18998
- if (ctx.depth >= 1) return fail4("task_ctl is not available inside a sub-agent.");
19035
+ if (ctx.depth >= 1)
19036
+ return fail4(
19037
+ nestedTaskRejection(ctx, "task_ctl", "task_ctl is not available inside a sub-agent.")
19038
+ );
18999
19039
  const control = taskControl(ctx.sessionId);
19000
19040
  if (input2.action === "list") {
19001
19041
  const tasks = control?.list() ?? ctx.tasks?.list() ?? [];
@@ -19052,6 +19092,7 @@ var init_task_ctl = __esm({
19052
19092
  "use strict";
19053
19093
  init_result();
19054
19094
  init_task_control();
19095
+ init_task();
19055
19096
  TASK_CTL_TOOL = "task_ctl";
19056
19097
  DEFAULT_WAIT_MS = 3e4;
19057
19098
  MAX_WAIT_MS = 6e5;
@@ -20522,8 +20563,23 @@ var init_classifier = __esm({
20522
20563
  function textOf(message) {
20523
20564
  return message.content.filter((block) => block.type === "text").map((block) => block.type === "text" ? block.text : "").join("").trim();
20524
20565
  }
20566
+ function inferredSmall(core, session) {
20567
+ const hit = catalogByAlias(session.id);
20568
+ if (hit === void 0) return void 0;
20569
+ const origin = hit.ref.slice(0, hit.ref.indexOf("/"));
20570
+ const small = catalogSmall(origin);
20571
+ const target = `${origin}/${small}`;
20572
+ if (small === void 0 || hit.ref === target) return void 0;
20573
+ const listed2 = core.options.providers.get(session.provider)?.models ?? [];
20574
+ return listed2.find((m) => {
20575
+ if (m.id === small) return true;
20576
+ const entry = catalogByAlias(m.id);
20577
+ return entry?.ref === target && entry.tier === void 0;
20578
+ })?.id;
20579
+ }
20525
20580
  async function smallModel(core, session) {
20526
- const small = catalogSmall(session.provider);
20581
+ const own = catalogSmall(session.provider);
20582
+ const small = own === void 0 ? inferredSmall(core, session) : own;
20527
20583
  if (small === void 0 || small === session.id) return void 0;
20528
20584
  const lookup = core.options.providers.findModel(`${session.provider}/${small}`);
20529
20585
  if (!lookup.ok) return void 0;
@@ -25219,7 +25275,7 @@ function editTargets(file) {
25219
25275
  }
25220
25276
  return targets;
25221
25277
  }
25222
- var import_node_fs31, placeholder, ImageOffload;
25278
+ var import_node_fs31, placeholder, PENDING_WARNINGS, ImageOffload;
25223
25279
  var init_offload = __esm({
25224
25280
  "src/session/offload.ts"() {
25225
25281
  "use strict";
@@ -25228,15 +25284,26 @@ var init_offload = __esm({
25228
25284
  init_line_reader();
25229
25285
  init_projection();
25230
25286
  placeholder = (block) => ({ ...block, data: "" });
25287
+ PENDING_WARNINGS = 16;
25231
25288
  ImageOffload = class {
25232
- constructor(warn2 = () => {
25233
- }) {
25234
- this.warn = warn2;
25235
- }
25236
- warn;
25237
25289
  /** 含图 message 条目的行位置(只有已落盘的条目才有)。 */
25238
25290
  locators = /* @__PURE__ */ new Map();
25239
25291
  offloaded = /* @__PURE__ */ new Set();
25292
+ warn;
25293
+ pending = [];
25294
+ dropped = 0;
25295
+ constructor(warn2) {
25296
+ this.warn = warn2;
25297
+ }
25298
+ /** 接上(或换掉)告警通道;之前缓冲的告警按序冲出。 */
25299
+ setWarn(warn2) {
25300
+ this.warn = warn2;
25301
+ const pending = this.pending.splice(0);
25302
+ if (this.dropped > 0)
25303
+ pending.push(`and ${this.dropped} more session entries could not be read back`);
25304
+ this.dropped = 0;
25305
+ for (const message of pending) warn2(message);
25306
+ }
25240
25307
  /** 记下条目的行位置;不含图片的条目忽略。 */
25241
25308
  track(entry, locator) {
25242
25309
  if (hasImages(entry)) this.locators.set(entry.id, locator);
@@ -25326,10 +25393,15 @@ var init_offload = __esm({
25326
25393
  } catch (error2) {
25327
25394
  this.locators.delete(entry.id);
25328
25395
  this.offloaded.delete(entry.id);
25329
- this.warn(`cannot read session entry ${entry.id} back from ${file}: ${String(error2)}`);
25396
+ this.report(`cannot read session entry ${entry.id} back from ${file}: ${String(error2)}`);
25330
25397
  return void 0;
25331
25398
  }
25332
25399
  }
25400
+ report(message) {
25401
+ if (this.warn !== void 0) this.warn(message);
25402
+ else if (this.pending.length < PENDING_WARNINGS) this.pending.push(message);
25403
+ else this.dropped++;
25404
+ }
25333
25405
  };
25334
25406
  }
25335
25407
  });
@@ -25514,6 +25586,11 @@ var init_manager = __esm({
25514
25586
  if (this.storage.kind !== "file" || !this.images.isOffloaded(entry.id)) return entry;
25515
25587
  return this.images.original(this.storage.file, entry);
25516
25588
  }
25589
+ /** 接上(或换掉)告警出口(图片读不回等);`open()` 期间缓冲的告警随即按序冲出(#183)。 */
25590
+ setWarn(warn2) {
25591
+ this.warn = warn2;
25592
+ this.images.setWarn(warn2);
25593
+ }
25517
25594
  /** 已卸载图片的条目数(测试与诊断用)。 */
25518
25595
  offloadedCount() {
25519
25596
  return this.images.size;
@@ -25626,6 +25703,9 @@ var init_manager = __esm({
25626
25703
  });
25627
25704
 
25628
25705
  // src/agent/subagent-fork.ts
25706
+ function forkRatio(ratio) {
25707
+ return ratio !== void 0 && Number.isFinite(ratio) && ratio > 0 && ratio < 1 ? ratio : FORK_MAX_CONTEXT_RATIO;
25708
+ }
25629
25709
  function requestedContext(request, agent) {
25630
25710
  return request.context ?? agent.context ?? "fresh";
25631
25711
  }
@@ -25637,7 +25717,7 @@ function forkPoint(branch, parentToolCallId) {
25637
25717
  );
25638
25718
  return index2 > 0 ? branch[index2 - 1]?.id : void 0;
25639
25719
  }
25640
- function forkPlan(parent, spec2, model, thinking) {
25720
+ function forkPlan(parent, spec2, model, thinking, ratio) {
25641
25721
  const base4 = parent.childBase();
25642
25722
  if (model.provider !== base4.model.provider || model.id !== base4.model.id)
25643
25723
  return { fallback: `model ${model.provider}/${model.id} differs from the parent` };
@@ -25647,7 +25727,7 @@ function forkPlan(parent, spec2, model, thinking) {
25647
25727
  if (last === void 0) return { fallback: "the parent has not sent a request yet" };
25648
25728
  const reserve = parent.options.compaction?.reserveTokens ?? DEFAULT_COMPACTION_SETTINGS.reserveTokens;
25649
25729
  const window2 = model.contextWindow;
25650
- const limit = window2 === void 0 ? Infinity : FORK_MAX_CONTEXT_RATIO * Math.max(0, window2 - reserve);
25730
+ const limit = window2 === void 0 ? Infinity : forkRatio(ratio) * Math.max(0, window2 - reserve);
25651
25731
  if (last.promptTokens > limit)
25652
25732
  return { fallback: `parent context ${last.promptTokens} tokens exceeds ${Math.floor(limit)}` };
25653
25733
  const forkedFrom = forkPoint(parent.manager.branch(), spec2.request.parentToolCallId);
@@ -25670,12 +25750,17 @@ function forkPlan(parent, spec2, model, thinking) {
25670
25750
  }
25671
25751
  }
25672
25752
  });
25753
+ manager.append({
25754
+ type: "custom",
25755
+ customType: FORK_CUSTOM_TYPE,
25756
+ data: { taskLine: taskLine(spec2.request.prompt) }
25757
+ });
25673
25758
  return { manager, forkedFrom };
25674
25759
  }
25675
25760
  function forkBrief(input2) {
25676
25761
  const lines2 = [
25677
25762
  "<task>",
25678
- "You are a sub-agent forked from the conversation above at this point. The main agent cannot see your work, only your final reply; do not delegate further. Requests above were for the main agent: do only this task. Instructions in this block take precedence over earlier plans or reminders above."
25763
+ "You are a sub-agent forked from the conversation above at this point. The main agent cannot see your work, only your final reply; do not delegate further. Requests above were for the main agent: do only this task. Instructions in this block take precedence over earlier plans or reminders above. Do not call task or task_ctl."
25679
25764
  ];
25680
25765
  if (input2.worktree !== void 0)
25681
25766
  lines2.push(
@@ -25702,6 +25787,7 @@ var FORK_MAX_CONTEXT_RATIO, TASK_CUSTOM_TYPE2;
25702
25787
  var init_subagent_fork = __esm({
25703
25788
  "src/agent/subagent-fork.ts"() {
25704
25789
  "use strict";
25790
+ init_task();
25705
25791
  init_session_compaction();
25706
25792
  FORK_MAX_CONTEXT_RATIO = 0.5;
25707
25793
  TASK_CUSTOM_TYPE2 = "ama.task";
@@ -26613,9 +26699,15 @@ function runningResult(record3, text, outputFile) {
26613
26699
  status: "running"
26614
26700
  };
26615
26701
  if (outputFile !== void 0) result.outputFile = outputFile;
26702
+ if (record3.info.context !== void 0) result.context = record3.info.context;
26616
26703
  return result;
26617
26704
  }
26618
- function startedResult(record3, outputFile) {
26705
+ async function startedResult(record3, outputFile, settle) {
26706
+ if (settle !== void 0)
26707
+ await Promise.race([
26708
+ settle.catch(() => void 0),
26709
+ new Promise((resolve41) => setImmediate(resolve41))
26710
+ ]);
26619
26711
  return runningResult(record3, startedText(record3.info.taskId, record3.agent.name), outputFile);
26620
26712
  }
26621
26713
  function backgroundedResult(record3, reason, afterMs, outputFile) {
@@ -26997,7 +27089,7 @@ var init_subagent_registry = __esm({
26997
27089
  const file = this.outputFileFor(record3.info.taskId);
26998
27090
  if (background) {
26999
27091
  void running.then((result) => this.notifier.notify(record3, result));
27000
- return Promise.resolve(startedResult(record3, file));
27092
+ return startedResult(record3, file, running);
27001
27093
  }
27002
27094
  const { waiter, promise } = foregroundWaiter(() => {
27003
27095
  clearTimeout(timer);
@@ -27302,7 +27394,8 @@ async function startAmaChild(parent, spec2, createChild, run7) {
27302
27394
  }
27303
27395
  const thinkingLevel = spec2.request.thinkingLevel ?? spec2.agent.thinking ?? base4.thinkingLevel ?? "off";
27304
27396
  const wanted = spec2.resumeFile === void 0 && requestedContext(spec2.request, spec2.agent) === "fork";
27305
- const plan2 = wanted ? forkPlan(parent, spec2, model, thinkingLevel) : void 0;
27397
+ const ratio = subagentRegistryFor(parent).env.modelConfig?.subagents?.forkMaxContextRatio;
27398
+ const plan2 = wanted ? forkPlan(parent, spec2, model, thinkingLevel, ratio) : void 0;
27306
27399
  if (plan2 !== void 0 && "fallback" in plan2)
27307
27400
  parent.log("info", `task ${spec2.taskId}: fork falls back to fresh (${plan2.fallback})`);
27308
27401
  const forked = plan2 !== void 0 && "manager" in plan2 ? plan2.manager : void 0;
@@ -27315,6 +27408,10 @@ async function startAmaChild(parent, spec2, createChild, run7) {
27315
27408
  const unavailable = inherited.filter(
27316
27409
  (name) => !allowed.includes(name) && !PARENT_ONLY_TOOLS.includes(name)
27317
27410
  );
27411
+ const briefUnavailable = [
27412
+ ...unavailable,
27413
+ ...PARENT_ONLY_TOOLS.filter((name) => inherited.includes(name))
27414
+ ];
27318
27415
  const options = {
27319
27416
  ...parent.options,
27320
27417
  ...base4,
@@ -27403,7 +27500,7 @@ async function startAmaChild(parent, spec2, createChild, run7) {
27403
27500
  const first = forked === void 0 ? run7.prompt : forkBrief({
27404
27501
  prompt: run7.prompt,
27405
27502
  role: spec2.agent.prompt,
27406
- unavailable,
27503
+ unavailable: briefUnavailable,
27407
27504
  ...spec2.isolated ? { worktree: { cwd: spec2.cwd, parentCwd: parent.cwd } } : {}
27408
27505
  });
27409
27506
  let current3 = runOnce(first, spec2.origin);
@@ -27631,6 +27728,7 @@ var init_session_extensions = __esm({
27631
27728
  if (extension !== void 0) list5.push(extension);
27632
27729
  }
27633
27730
  this.list = list5;
27731
+ core.manager.setWarn((message) => core.log("warn", message));
27634
27732
  }
27635
27733
  get size() {
27636
27734
  return this.list.length;
@@ -30292,7 +30390,7 @@ async function readSmall2(path) {
30292
30390
  return void 0;
30293
30391
  }
30294
30392
  }
30295
- var import_node_child_process7, import_node_crypto10, import_promises16, import_node_os10, import_node_path51, SHADOW_DIR, SHADOW_MAX_FILES, SHADOW_MAX_SNAPSHOT_MS, GIT_TIMEOUT_MS, CONFIG_VERSION, IDENTITY, ATTRIBUTES, GitMissingError, MODE_ABSENT, MODE_SYMLINK, MODE_GITLINK, MODE_EXECUTABLE, queues2, ShadowRepo;
30393
+ var import_node_child_process7, import_node_crypto10, import_promises16, import_node_os10, import_node_path51, SHADOW_DIR, SHADOW_MAX_FILES, SHADOW_MAX_SNAPSHOT_MS, SHADOW_SLOW_STREAK, GIT_TIMEOUT_MS, CONFIG_VERSION, IDENTITY, ATTRIBUTES, GitMissingError, MODE_ABSENT, MODE_SYMLINK, MODE_GITLINK, MODE_EXECUTABLE, queues2, ShadowRepo;
30296
30394
  var init_shadow_git = __esm({
30297
30395
  "src/checkpoints/shadow-git.ts"() {
30298
30396
  "use strict";
@@ -30306,6 +30404,7 @@ var init_shadow_git = __esm({
30306
30404
  SHADOW_DIR = "shadow";
30307
30405
  SHADOW_MAX_FILES = 2e4;
30308
30406
  SHADOW_MAX_SNAPSHOT_MS = 3e3;
30407
+ SHADOW_SLOW_STREAK = 2;
30309
30408
  GIT_TIMEOUT_MS = 6e4;
30310
30409
  CONFIG_VERSION = "1";
30311
30410
  IDENTITY = { name: "ama", email: "ama@localhost" };
@@ -30331,6 +30430,8 @@ var init_shadow_git = __esm({
30331
30430
  indexFile;
30332
30431
  initialized;
30333
30432
  counted = false;
30433
+ /** 连续超时的快照数(首次快照不计),到 `SHADOW_SLOW_STREAK` 才降级。 */
30434
+ slowStreak = 0;
30334
30435
  constructor(dataDir, cwd, options = {}) {
30335
30436
  this.cwd = (0, import_node_path51.resolve)(cwd);
30336
30437
  this.dir = shadowRepoDir(dataDir, this.cwd);
@@ -30450,6 +30551,7 @@ var init_shadow_git = __esm({
30450
30551
  return exclusive(this.dir, async () => {
30451
30552
  await this.init();
30452
30553
  const started = this.now();
30554
+ const first = !this.counted;
30453
30555
  await this.writeExcludes();
30454
30556
  if (!this.counted) {
30455
30557
  const out = await this.run([
@@ -30475,7 +30577,9 @@ var init_shadow_git = __esm({
30475
30577
  if (parent !== void 0 && await this.hasCommitUnlocked(parent)) args.push("-p", parent);
30476
30578
  const commit = await this.text(args);
30477
30579
  const elapsed = this.now() - started;
30478
- if (elapsed > this.maxSnapshotMs) {
30580
+ if (first) return { commit };
30581
+ this.slowStreak = elapsed > this.maxSnapshotMs ? this.slowStreak + 1 : 0;
30582
+ if (this.slowStreak >= SHADOW_SLOW_STREAK) {
30479
30583
  return {
30480
30584
  commit,
30481
30585
  degrade: {
@@ -31390,7 +31494,9 @@ function openSession(request, context) {
31390
31494
  return file === void 0 ? SessionManager.create(dir, cwd, { id: request.id }) : SessionManager.open(file);
31391
31495
  }
31392
31496
  case "fork": {
31393
- const source = SessionManager.open(requireFile(root, request.id, cwd));
31497
+ const source = SessionManager.open(requireFile(root, request.id, cwd), {
31498
+ warn: (message) => context.log?.("warn", message)
31499
+ });
31394
31500
  try {
31395
31501
  const leaf = source.leafId();
31396
31502
  if (leaf === null)
@@ -31406,9 +31512,9 @@ function listSessions(context) {
31406
31512
  const dirs = context.cwd === void 0 ? cwdDirs(context.sessionDir) : [sessionDirForCwd(context.sessionDir, context.cwd)];
31407
31513
  return dirs.flatMap((dir) => SessionManager.list(dir)).filter((item) => context.includeSubagents === true || item.subagent !== true).sort((a, b) => b.modifiedAt.localeCompare(a.modifiedAt));
31408
31514
  }
31409
- function createSessionStore() {
31515
+ function createSessionStore(log) {
31410
31516
  return {
31411
- open: (request, context) => openSession(request, context),
31517
+ open: (request, context) => openSession(request, { ...context, log }),
31412
31518
  list: async (context) => listSessions(context),
31413
31519
  show: async (id, context) => {
31414
31520
  const file = requireFile(context.sessionDir, id);
@@ -33124,6 +33230,16 @@ function candidateCapabilities(c) {
33124
33230
  usage: "tokens",
33125
33231
  images: false
33126
33232
  };
33233
+ case "pi-rpc":
33234
+ return {
33235
+ resume: "resume",
33236
+ list: false,
33237
+ permissions: "interactive",
33238
+ steer: true,
33239
+ modes: ALL_MODES,
33240
+ usage: "usd",
33241
+ images: true
33242
+ };
33127
33243
  case "oneshot":
33128
33244
  return {
33129
33245
  resume: c.oneshot === "gemini" ? "none" : "resume",
@@ -33147,7 +33263,7 @@ function candidateCapabilities(c) {
33147
33263
  };
33148
33264
  }
33149
33265
  }
33150
- var ALL_MODES, DRIVER_CATALOG;
33266
+ var ALL_MODES, CLAUDE_ACP_MODES, CODEX_ACP_MODES, COPILOT_MODE, COPILOT_MODES, CURSOR_MODES, DRIVER_CATALOG;
33151
33267
  var init_catalog4 = __esm({
33152
33268
  "src/drivers/catalog.ts"() {
33153
33269
  "use strict";
@@ -33159,12 +33275,48 @@ var init_catalog4 = __esm({
33159
33275
  "auto",
33160
33276
  "full-auto"
33161
33277
  ];
33278
+ CLAUDE_ACP_MODES = {
33279
+ plan: "plan",
33280
+ default: "default",
33281
+ "auto-edit": "acceptEdits",
33282
+ auto: "auto",
33283
+ "full-auto": "auto"
33284
+ };
33285
+ CODEX_ACP_MODES = {
33286
+ plan: "read-only",
33287
+ default: "read-only",
33288
+ "auto-edit": "workspace-write",
33289
+ auto: "agent",
33290
+ "full-auto": "agent"
33291
+ };
33292
+ COPILOT_MODE = "https://agentclientprotocol.com/protocol/session-modes#";
33293
+ COPILOT_MODES = {
33294
+ plan: `${COPILOT_MODE}plan`,
33295
+ default: `${COPILOT_MODE}agent`,
33296
+ "auto-edit": `${COPILOT_MODE}agent`,
33297
+ auto: `${COPILOT_MODE}agent`,
33298
+ "full-auto": `${COPILOT_MODE}agent`
33299
+ };
33300
+ CURSOR_MODES = {
33301
+ plan: "plan",
33302
+ default: "agent",
33303
+ "auto-edit": "agent",
33304
+ auto: "agent",
33305
+ "full-auto": "agent"
33306
+ };
33162
33307
  DRIVER_CATALOG = [
33163
33308
  {
33164
33309
  agentId: "claude",
33165
33310
  label: "Claude Code",
33166
33311
  candidates: [
33167
- { kind: "acp-adapter", program: "claude-agent-acp", args: [], usage: "usd" },
33312
+ {
33313
+ kind: "acp-adapter",
33314
+ program: "claude-agent-acp",
33315
+ args: [],
33316
+ verified: ">=0.89.0 <1.0.0",
33317
+ usage: "usd",
33318
+ modes: CLAUDE_ACP_MODES
33319
+ },
33168
33320
  {
33169
33321
  kind: "claude-stream",
33170
33322
  program: "claude",
@@ -33179,7 +33331,14 @@ var init_catalog4 = __esm({
33179
33331
  agentId: "codex",
33180
33332
  label: "Codex",
33181
33333
  candidates: [
33182
- { kind: "acp-adapter", program: "codex-acp", args: [], usage: "tokens" },
33334
+ {
33335
+ kind: "acp-adapter",
33336
+ program: "codex-acp",
33337
+ args: [],
33338
+ verified: ">=2.2.0 <3.0.0",
33339
+ usage: "tokens",
33340
+ modes: CODEX_ACP_MODES
33341
+ },
33183
33342
  {
33184
33343
  kind: "codex-app-server",
33185
33344
  program: "codex",
@@ -33212,15 +33371,44 @@ var init_catalog4 = __esm({
33212
33371
  {
33213
33372
  agentId: "opencode",
33214
33373
  label: "OpenCode",
33215
- candidates: [{ kind: "acp", program: "opencode", args: ["acp"] }]
33374
+ candidates: [{ kind: "acp", program: "opencode", args: ["acp"], verified: ">=1.18.0 <2.0.0" }]
33216
33375
  },
33217
33376
  {
33218
33377
  agentId: "copilot",
33219
33378
  label: "GitHub Copilot CLI",
33220
33379
  candidates: [
33221
- { kind: "acp", program: "copilot", args: ["--acp", "--stdio"], usage: "requests" }
33380
+ {
33381
+ kind: "acp",
33382
+ program: "copilot",
33383
+ args: ["--acp", "--stdio"],
33384
+ verified: ">=1.0.95 <2.0.0",
33385
+ usage: "requests",
33386
+ modes: COPILOT_MODES,
33387
+ acpUsage: "session"
33388
+ }
33389
+ ]
33390
+ },
33391
+ {
33392
+ agentId: "pi",
33393
+ label: "Pi",
33394
+ // 社区 ACP 适配器 pi-acp 不发 request_permission(pi 没有审批通道),会让工具不经人直接执行,不收录
33395
+ candidates: [
33396
+ {
33397
+ kind: "pi-rpc",
33398
+ program: "pi",
33399
+ args: ["--mode", "rpc"],
33400
+ verified: ">=1.1.0 <2.0.0",
33401
+ usage: "usd"
33402
+ }
33222
33403
  ]
33223
33404
  },
33405
+ {
33406
+ agentId: "cursor",
33407
+ label: "Cursor CLI",
33408
+ // 未实测(本机未装):按官方文档 `cursor-agent acp`,模式 agent / plan / ask;`cursor/ask_question`
33409
+ // 等阻塞式扩展方法 ama 不实现(回 method not found,不代答)
33410
+ candidates: [{ kind: "acp", program: "cursor-agent", args: ["acp"], modes: CURSOR_MODES }]
33411
+ },
33224
33412
  {
33225
33413
  agentId: "goose",
33226
33414
  label: "Goose",
@@ -33942,6 +34130,24 @@ function pushAcpUpdate(update, turn) {
33942
34130
  return;
33943
34131
  }
33944
34132
  }
34133
+ function acpTurnUsage(usage, previous) {
34134
+ const diff = (key) => {
34135
+ const now = usage[key];
34136
+ if (now === void 0) return void 0;
34137
+ return previous === void 0 ? now : Math.max(0, now - (previous[key] ?? 0));
34138
+ };
34139
+ const input2 = diff("inputTokens");
34140
+ const output = diff("outputTokens");
34141
+ const cacheRead = diff("cachedReadTokens");
34142
+ const { totalTokens: total, inputTokens: rawIn = 0, outputTokens: rawOut = 0 } = usage;
34143
+ const cached = usage.cachedReadTokens ?? 0;
34144
+ const includesCache = total !== void 0 && cached > 0 && Math.abs(total - (rawIn + rawOut)) < Math.abs(total - (rawIn + rawOut + cached));
34145
+ return {
34146
+ ...input2 !== void 0 ? { input: includesCache ? Math.max(0, input2 - (cacheRead ?? 0)) : input2 } : {},
34147
+ ...output !== void 0 ? { output } : {},
34148
+ ...cacheRead !== void 0 ? { cacheRead } : {}
34149
+ };
34150
+ }
33945
34151
  function wantedModeIds(mode, candidate) {
33946
34152
  const wanted = [candidate.modes?.[mode] ?? mode];
33947
34153
  if (mode === "allowlist") wanted.push(candidate.modes?.plan ?? "plan");
@@ -33962,6 +34168,14 @@ function pickConfigModeValue(mode, candidate, option2) {
33962
34168
  );
33963
34169
  return wantedModeIds(mode, candidate).find((id) => values.includes(id));
33964
34170
  }
34171
+ function pickModelValue(model, options) {
34172
+ const option2 = options?.find((o) => o.category === "model" && o.type === "select");
34173
+ if (option2 === void 0) return void 0;
34174
+ const values = option2.options.flatMap((o) => "options" in o ? o.options : [o]);
34175
+ const lower = model.toLowerCase();
34176
+ const hit = values.find((v) => v.value === model) ?? values.find((v) => v.value.toLowerCase() === lower || v.name.toLowerCase() === lower) ?? values.find((v) => v.value.toLowerCase().split("/").at(-1) === lower);
34177
+ return hit === void 0 ? void 0 : { configId: option2.id, value: hit.value, current: option2.currentValue === hit.value };
34178
+ }
33965
34179
  function authMethodText(method, command3) {
33966
34180
  if (method.type !== "terminal") return method.name;
33967
34181
  const words = [...command3, ...method.args ?? []].map(
@@ -34048,6 +34262,9 @@ var init_driver = __esm({
34048
34262
  notices = [];
34049
34263
  /** 本回合已发过 cancel。 */
34050
34264
  cancelling = false;
34265
+ /** Agent 的 usage 是会话累计时,上一回合的原始值({@link acpTurnUsage})。 */
34266
+ usageTotals;
34267
+ cumulativeUsage = false;
34051
34268
  get sessionId() {
34052
34269
  return this.id;
34053
34270
  }
@@ -34062,6 +34279,7 @@ var init_driver = __esm({
34062
34279
  onProtocolError: (_line, reason) => this.deps.log?.("debug", `${this.agentId}: ${reason}`)
34063
34280
  });
34064
34281
  const signal = options.signal;
34282
+ this.cumulativeUsage = candidate.acpUsage === "session";
34065
34283
  await this.client.initialize(signal);
34066
34284
  let opened;
34067
34285
  try {
@@ -34088,6 +34306,13 @@ var init_driver = __esm({
34088
34306
  } else if (modes != null || modeOption !== void 0) {
34089
34307
  this.notices.push(msg().drivers.agent.noMatchingMode(this.agentId, options.mode));
34090
34308
  }
34309
+ if (options.model !== void 0) {
34310
+ const model = pickModelValue(options.model, opened.configOptions);
34311
+ if (model === void 0)
34312
+ this.notices.push(msg().drivers.agent.noMatchingModel(this.agentId, options.model));
34313
+ else if (!model.current)
34314
+ await this.client.setConfigOption(this.id, model.configId, model.value);
34315
+ }
34091
34316
  }
34092
34317
  /** 续聊优先 resume(不回放),其次 load(回放丢弃),都不行就新开;设好 `this.id`。 */
34093
34318
  async openSession(options) {
@@ -34148,11 +34373,10 @@ var init_driver = __esm({
34148
34373
  });
34149
34374
  const usage = result.usage;
34150
34375
  if (usage != null) {
34151
- turn.mergeUsage({
34152
- ...usage.inputTokens !== void 0 ? { input: usage.inputTokens } : {},
34153
- ...usage.outputTokens !== void 0 ? { output: usage.outputTokens } : {},
34154
- ...usage.cachedReadTokens !== void 0 ? { cacheRead: usage.cachedReadTokens } : {}
34155
- });
34376
+ turn.mergeUsage(
34377
+ acpTurnUsage(usage, this.cumulativeUsage ? this.usageTotals ?? {} : void 0)
34378
+ );
34379
+ if (this.cumulativeUsage) this.usageTotals = usage;
34156
34380
  }
34157
34381
  return turn.result(result.stopReason);
34158
34382
  } finally {
@@ -34261,6 +34485,26 @@ function claudePermissionMode(mode, manualName) {
34261
34485
  return "auto";
34262
34486
  }
34263
34487
  }
34488
+ function claudeContextTokens(usage) {
34489
+ if (typeof usage !== "object" || usage === null) return void 0;
34490
+ const u = usage;
34491
+ let total = 0;
34492
+ for (const key of [
34493
+ "input_tokens",
34494
+ "cache_read_input_tokens",
34495
+ "cache_creation_input_tokens",
34496
+ "output_tokens"
34497
+ ])
34498
+ if (typeof u[key] === "number") total += u[key];
34499
+ return total > 0 ? total : void 0;
34500
+ }
34501
+ function claudeContextWindow(result, model) {
34502
+ const entries = result.modelUsage ?? {};
34503
+ const hit = model !== void 0 ? entries[model]?.contextWindow : void 0;
34504
+ if (typeof hit === "number" && hit > 0) return hit;
34505
+ const windows = Object.values(entries).map((e) => e.contextWindow).filter((w) => typeof w === "number" && w > 0);
34506
+ return windows.length > 0 ? Math.max(...windows) : void 0;
34507
+ }
34264
34508
  function claudeStopReason(result, interrupted) {
34265
34509
  if (interrupted) return "cancelled";
34266
34510
  switch (result.subtype) {
@@ -34421,6 +34665,8 @@ var init_claude_stream = __esm({
34421
34665
  interrupted = false;
34422
34666
  sawPartialText = false;
34423
34667
  lastTotalCost = 0;
34668
+ /** 最近一条主线 assistant 消息的上下文占用与模型(result 里查窗口用)。 */
34669
+ context = {};
34424
34670
  closed = false;
34425
34671
  exited = false;
34426
34672
  get sessionId() {
@@ -34512,6 +34758,13 @@ var init_claude_stream = __esm({
34512
34758
  ...u.cache_read_input_tokens !== void 0 ? { cacheRead: u.cache_read_input_tokens } : {},
34513
34759
  ...cost2 !== void 0 ? { costUsd: cost2 } : {}
34514
34760
  });
34761
+ const window2 = claudeContextWindow(result, this.context.model);
34762
+ if (this.context.tokens !== void 0 || window2 !== void 0)
34763
+ turn.push({
34764
+ type: "usage",
34765
+ ...this.context.tokens !== void 0 ? { contextTokens: this.context.tokens } : {},
34766
+ ...window2 !== void 0 ? { contextWindow: window2 } : {}
34767
+ });
34515
34768
  if (typeof result.result === "string" && result.result !== "") turn.setFinalText(result.result);
34516
34769
  const denials = result.permission_denials?.length ?? 0;
34517
34770
  if (denials > 0)
@@ -34629,6 +34882,12 @@ var init_claude_stream = __esm({
34629
34882
  const turn = this.turn;
34630
34883
  if (turn === void 0 || !Array.isArray(message["content"])) return;
34631
34884
  const nested = typeof parent === "string" && parent !== "";
34885
+ const tokens = nested ? void 0 : claudeContextTokens(message["usage"]);
34886
+ if (tokens !== void 0)
34887
+ this.context = {
34888
+ tokens,
34889
+ ...typeof message["model"] === "string" ? { model: message["model"] } : {}
34890
+ };
34632
34891
  for (const block of message["content"]) {
34633
34892
  if (block["type"] === "text" && !nested && !this.sawPartialText && typeof block["text"] === "string")
34634
34893
  turn.push({ type: "message_delta", text: block["text"] });
@@ -35078,11 +35337,12 @@ var init_codex_app_server = __esm({
35078
35337
  const start = this.tokensAtStart;
35079
35338
  const end = this.tokensTotal;
35080
35339
  if (end !== void 0) {
35340
+ const cacheRead = end.cachedInputTokens - (start?.cachedInputTokens ?? 0);
35081
35341
  turn.push({
35082
35342
  type: "usage",
35083
- input: end.inputTokens - (start?.inputTokens ?? 0),
35343
+ input: end.inputTokens - (start?.inputTokens ?? 0) - cacheRead,
35084
35344
  output: end.outputTokens - (start?.outputTokens ?? 0),
35085
- cacheRead: end.cachedInputTokens - (start?.cachedInputTokens ?? 0),
35345
+ cacheRead,
35086
35346
  ...this.contextTokens !== void 0 ? { contextTokens: this.contextTokens } : {},
35087
35347
  ...this.contextWindow !== void 0 ? { contextWindow: this.contextWindow } : {}
35088
35348
  });
@@ -35277,7 +35537,14 @@ function oneshotArgs(dialect, options, session, prompt) {
35277
35537
  return args;
35278
35538
  }
35279
35539
  case "codex": {
35280
- const common = ["--json", "-c", 'sandbox_mode="read-only"', "-c", 'approval_policy="never"'];
35540
+ const common = [
35541
+ "--json",
35542
+ "--skip-git-repo-check",
35543
+ "-c",
35544
+ 'sandbox_mode="read-only"',
35545
+ "-c",
35546
+ 'approval_policy="never"'
35547
+ ];
35281
35548
  if (options.model !== void 0) common.push("-m", options.model);
35282
35549
  return session.resume ? ["exec", "resume", session.id, ...common, "-"] : ["exec", ...common, "-"];
35283
35550
  }
@@ -35497,9 +35764,10 @@ ${item["text"]}`
35497
35764
  }
35498
35765
  case "turn.completed": {
35499
35766
  const u = msg2["usage"] ?? {};
35767
+ const input2 = u["input_tokens"];
35500
35768
  turn.push({
35501
35769
  type: "usage",
35502
- ...u["input_tokens"] !== void 0 ? { input: u["input_tokens"] } : {},
35770
+ ...input2 !== void 0 ? { input: input2 - (u["cached_input_tokens"] ?? 0) } : {},
35503
35771
  ...u["output_tokens"] !== void 0 ? { output: u["output_tokens"] } : {},
35504
35772
  ...u["cached_input_tokens"] !== void 0 ? { cacheRead: u["cached_input_tokens"] } : {}
35505
35773
  });
@@ -35563,13 +35831,516 @@ ${item["text"]}`
35563
35831
  }
35564
35832
  });
35565
35833
 
35834
+ // src/drivers/native/pi-gate.ts
35835
+ function writePiGate() {
35836
+ const dir = (0, import_node_fs41.mkdtempSync)((0, import_node_path60.join)((0, import_node_os11.tmpdir)(), "ama-pi-"));
35837
+ const path = (0, import_node_path60.join)(dir, "ama-approval-gate.ts");
35838
+ (0, import_node_fs41.writeFileSync)(path, PI_GATE_SOURCE, { mode: 384 });
35839
+ return {
35840
+ path,
35841
+ dispose: () => (0, import_node_fs41.rmSync)(dir, { recursive: true, force: true })
35842
+ };
35843
+ }
35844
+ var import_node_fs41, import_node_os11, import_node_path60, PI_GATE_TITLE, PI_READ_ONLY_TOOLS, PI_GATE_SOURCE;
35845
+ var init_pi_gate = __esm({
35846
+ "src/drivers/native/pi-gate.ts"() {
35847
+ "use strict";
35848
+ import_node_fs41 = require("node:fs");
35849
+ import_node_os11 = require("node:os");
35850
+ import_node_path60 = require("node:path");
35851
+ PI_GATE_TITLE = "ama-approval";
35852
+ PI_READ_ONLY_TOOLS = ["read", "grep", "find", "ls"];
35853
+ PI_GATE_SOURCE = `// Generated by ama for one pi run: routes non-read-only tool calls to ama for approval.
35854
+ const READ_ONLY = new Set(${JSON.stringify(PI_READ_ONLY_TOOLS)});
35855
+ export default function (pi) {
35856
+ pi.on("tool_call", async (event, ctx) => {
35857
+ if (READ_ONLY.has(event.toolName)) return undefined;
35858
+ const ok = await ctx.ui.confirm(
35859
+ ${JSON.stringify(PI_GATE_TITLE)},
35860
+ JSON.stringify({ id: event.toolCallId, tool: event.toolName, input: event.input }),
35861
+ );
35862
+ return ok ? undefined : { block: true, reason: event.toolName + " was not approved by the user" };
35863
+ });
35864
+ }
35865
+ `;
35866
+ }
35867
+ });
35868
+
35869
+ // src/drivers/native/pi-rpc.ts
35870
+ function piArgs(options, sessionId, gatePath) {
35871
+ const args = ["--session-id", sessionId];
35872
+ if (options.model !== void 0) args.push("--model", options.model);
35873
+ args.push("-e", gatePath);
35874
+ if (isReadOnlyMode(options.mode)) args.push("--tools", PI_READ_ONLY_TOOLS.join(","));
35875
+ return args;
35876
+ }
35877
+ function piToolKind(tool) {
35878
+ switch (tool) {
35879
+ case "bash":
35880
+ case "powershell":
35881
+ return "execute";
35882
+ case "edit":
35883
+ case "write":
35884
+ return "edit";
35885
+ case "read":
35886
+ return "read";
35887
+ case "grep":
35888
+ case "find":
35889
+ case "ls":
35890
+ return "search";
35891
+ default:
35892
+ return "other";
35893
+ }
35894
+ }
35895
+ function piToolTitle(tool, input2) {
35896
+ if (typeof input2["command"] === "string") return `$ ${oneLine2(input2["command"], 100)}`;
35897
+ if (typeof input2["path"] === "string") return `${tool} ${input2["path"]}`;
35898
+ if (typeof input2["pattern"] === "string") return `${tool} ${oneLine2(input2["pattern"], 80)}`;
35899
+ return tool;
35900
+ }
35901
+ function textOf4(message) {
35902
+ const content = message["content"];
35903
+ if (typeof content === "string") return content;
35904
+ if (!Array.isArray(content)) return "";
35905
+ return content.map((b) => b["type"] === "text" && typeof b["text"] === "string" ? b["text"] : "").join("");
35906
+ }
35907
+ var import_node_crypto14, import_node_path61, DIALOG_METHODS, EDIT_TOOLS, PiRpcDriver, PiSession;
35908
+ var init_pi_rpc = __esm({
35909
+ "src/drivers/native/pi-rpc.ts"() {
35910
+ "use strict";
35911
+ import_node_crypto14 = require("node:crypto");
35912
+ import_node_path61 = require("node:path");
35913
+ init_errors();
35914
+ init_jsonl();
35915
+ init_base();
35916
+ init_process();
35917
+ init_turn();
35918
+ init_pi_gate();
35919
+ init_i18n();
35920
+ DIALOG_METHODS = /* @__PURE__ */ new Set(["select", "confirm", "input", "editor"]);
35921
+ EDIT_TOOLS = /* @__PURE__ */ new Set(["edit", "write"]);
35922
+ PiRpcDriver = class {
35923
+ constructor(agentId, candidate, deps = {}) {
35924
+ this.agentId = agentId;
35925
+ this.candidate = candidate;
35926
+ this.deps = deps;
35927
+ }
35928
+ agentId;
35929
+ candidate;
35930
+ deps;
35931
+ kind = "pi-rpc";
35932
+ probe() {
35933
+ return probeCandidate(this.candidate, this.deps);
35934
+ }
35935
+ async open(options) {
35936
+ const probed = await probeCandidate(this.candidate, this.deps);
35937
+ const sessionId = options.resume ?? (0, import_node_crypto14.randomUUID)();
35938
+ const gate = writePiGate();
35939
+ const transport = spawnOf(this.deps)({
35940
+ program: probed.path ?? this.candidate.program,
35941
+ args: [...this.candidate.args, ...piArgs(options, sessionId, gate.path)],
35942
+ cwd: options.cwd,
35943
+ env: options.env
35944
+ });
35945
+ const session = new PiSession(
35946
+ this.agentId,
35947
+ sessionId,
35948
+ transport,
35949
+ options,
35950
+ this.deps,
35951
+ () => gate.dispose()
35952
+ );
35953
+ if (probed.warning !== void 0) session.notices.push(probed.warning);
35954
+ try {
35955
+ await session.start(options.signal);
35956
+ } catch (error2) {
35957
+ await session.close();
35958
+ throw new AmaError(
35959
+ "agent_start_failed",
35960
+ `${this.agentId}: failed to start (${error2.message})${stderrHint(transport) !== "" ? `: ${stderrHint(transport)}` : ""}`,
35961
+ { cause: error2 }
35962
+ );
35963
+ }
35964
+ return session;
35965
+ }
35966
+ };
35967
+ PiSession = class {
35968
+ constructor(agentId, id, transport, options, deps, dispose) {
35969
+ this.agentId = agentId;
35970
+ this.id = id;
35971
+ this.transport = transport;
35972
+ this.options = options;
35973
+ this.deps = deps;
35974
+ this.dispose = dispose;
35975
+ createLineReader(
35976
+ transport.stdout,
35977
+ (line2) => this.onLine(line2),
35978
+ () => this.onExit()
35979
+ );
35980
+ transport.stdin.on?.("error", () => void 0);
35981
+ }
35982
+ agentId;
35983
+ id;
35984
+ transport;
35985
+ options;
35986
+ deps;
35987
+ dispose;
35988
+ notices = [];
35989
+ nextId = 1;
35990
+ pending = /* @__PURE__ */ new Map();
35991
+ permissions = /* @__PURE__ */ new Set();
35992
+ turn;
35993
+ hooks;
35994
+ settle;
35995
+ running;
35996
+ usage = { input: 0, output: 0, cacheRead: 0, costUsd: 0, seen: false };
35997
+ lastAssistant;
35998
+ interrupted = false;
35999
+ closed = false;
36000
+ exited = false;
36001
+ exitWaiters = /* @__PURE__ */ new Set();
36002
+ get sessionId() {
36003
+ return this.id;
36004
+ }
36005
+ /** 握手:`get_state` 确认进程起来了,并取 pi 实际使用的会话 id。 */
36006
+ async start(signal) {
36007
+ const aborted = new Promise((_, reject2) => {
36008
+ if (signal.aborted) reject2(new Error("aborted"));
36009
+ signal.addEventListener("abort", () => reject2(new Error("aborted")), { once: true });
36010
+ });
36011
+ void aborted.catch(() => void 0);
36012
+ const state = await Promise.race([this.request({ type: "get_state" }), aborted]);
36013
+ const data2 = state["data"] ?? {};
36014
+ if (typeof data2["sessionId"] === "string" && data2["sessionId"] !== "")
36015
+ this.id = data2["sessionId"];
36016
+ }
36017
+ async prompt(content, hooks) {
36018
+ if (this.closed || this.exited)
36019
+ throw new AmaError("agent_closed", `${this.agentId} session is closed`);
36020
+ if (this.running !== void 0)
36021
+ throw new AmaError("busy", `${this.agentId} is already running`);
36022
+ const turn = new TurnCollector((e) => hooks.onEvent(e));
36023
+ for (const text of this.notices.splice(0)) turn.push({ type: "notice", level: "warn", text });
36024
+ this.turn = turn;
36025
+ this.hooks = hooks;
36026
+ this.interrupted = false;
36027
+ this.usage = { input: 0, output: 0, cacheRead: 0, costUsd: 0, seen: false };
36028
+ this.lastAssistant = void 0;
36029
+ this.running = this.run(content, turn);
36030
+ try {
36031
+ return await this.running;
36032
+ } finally {
36033
+ this.running = void 0;
36034
+ this.turn = void 0;
36035
+ this.hooks = void 0;
36036
+ this.settle = void 0;
36037
+ this.exitWaiters.clear();
36038
+ }
36039
+ }
36040
+ async run(content, turn) {
36041
+ await Promise.resolve();
36042
+ const settled = new Promise((resolve41) => this.settle = resolve41);
36043
+ const response = await this.request({ type: "prompt", ...this.message(content) });
36044
+ if (response["success"] !== true)
36045
+ throw new AmaError(
36046
+ "agent_failed",
36047
+ `${this.agentId} rejected the prompt: ${oneLine2(String(response["error"] ?? "unknown"), 300)}`
36048
+ );
36049
+ const disposition = (response["data"] ?? {})["disposition"];
36050
+ if (disposition === "handled") return turn.result("end_turn");
36051
+ const aborted = await Promise.race([settled, this.exitPromise()]);
36052
+ await this.reportContext(turn);
36053
+ return this.complete(turn, aborted);
36054
+ }
36055
+ async steer(content) {
36056
+ if (this.closed || this.exited)
36057
+ throw new AmaError("agent_closed", `${this.agentId} session is closed`);
36058
+ await this.request({ type: "steer", ...this.message(content) });
36059
+ }
36060
+ async cancel() {
36061
+ const running = this.running;
36062
+ if (running === void 0 || this.closed) return;
36063
+ this.interrupted = true;
36064
+ for (const c of this.permissions) c.abort();
36065
+ void this.request({ type: "abort" }).catch(() => void 0);
36066
+ armCancelWatchdog(
36067
+ this.transport,
36068
+ running.catch(() => void 0),
36069
+ this.deps
36070
+ );
36071
+ }
36072
+ async close() {
36073
+ if (this.closed) return;
36074
+ this.closed = true;
36075
+ for (const c of this.permissions) c.abort();
36076
+ if (this.running !== void 0) {
36077
+ this.interrupted = true;
36078
+ this.write({ type: "abort" });
36079
+ }
36080
+ try {
36081
+ await this.transport.terminate();
36082
+ } finally {
36083
+ this.dispose();
36084
+ }
36085
+ }
36086
+ message(content) {
36087
+ const text = content.map((b) => b.type === "text" ? b.text : "").join("\n");
36088
+ const images = content.flatMap(
36089
+ (b) => b.type === "image" ? [{ type: "image", data: b.data, mimeType: b.mimeType }] : []
36090
+ );
36091
+ return { message: text, ...images.length > 0 ? { images } : {} };
36092
+ }
36093
+ complete(turn, aborted) {
36094
+ const u = this.usage;
36095
+ if (u.seen)
36096
+ turn.push({
36097
+ type: "usage",
36098
+ input: u.input,
36099
+ output: u.output,
36100
+ cacheRead: u.cacheRead,
36101
+ costUsd: u.costUsd
36102
+ });
36103
+ const last = this.lastAssistant;
36104
+ if (last !== void 0) {
36105
+ const text = textOf4(last);
36106
+ if (text !== "") turn.setFinalText(text);
36107
+ }
36108
+ if (aborted || this.interrupted) return turn.result("cancelled");
36109
+ switch (last?.["stopReason"]) {
36110
+ case "error":
36111
+ throw new AmaError(
36112
+ "agent_failed",
36113
+ `${this.agentId} failed: ${oneLine2(String(last["errorMessage"] ?? "unknown error"), 300)}`
36114
+ );
36115
+ case "aborted":
36116
+ return turn.result("cancelled");
36117
+ case "length":
36118
+ return turn.result("max_tokens");
36119
+ default:
36120
+ return turn.result("end_turn");
36121
+ }
36122
+ }
36123
+ /** `get_session_stats.contextUsage` → 上下文占用与窗口(拿不到就算了)。 */
36124
+ async reportContext(turn) {
36125
+ if (this.exited) return;
36126
+ try {
36127
+ const stats = await Promise.race([
36128
+ this.request({ type: "get_session_stats" }),
36129
+ new Promise((resolve41) => setTimeout(() => resolve41({}), 5e3).unref())
36130
+ ]);
36131
+ const usage = (stats["data"] ?? {})["contextUsage"] ?? {};
36132
+ const tokens = usage["tokens"];
36133
+ const window2 = usage["contextWindow"];
36134
+ if (typeof tokens === "number" || typeof window2 === "number")
36135
+ turn.push({
36136
+ type: "usage",
36137
+ ...typeof tokens === "number" ? { contextTokens: tokens } : {},
36138
+ ...typeof window2 === "number" ? { contextWindow: window2 } : {}
36139
+ });
36140
+ } catch {
36141
+ }
36142
+ }
36143
+ exitPromise() {
36144
+ return new Promise((_, reject2) => {
36145
+ if (this.exited) reject2(this.exitError());
36146
+ else this.exitWaiters.add(reject2);
36147
+ });
36148
+ }
36149
+ exitError() {
36150
+ const hint = stderrHint(this.transport);
36151
+ return new AmaError(
36152
+ "agent_exited",
36153
+ `${this.agentId} process exited${hint !== "" ? `: ${hint}` : ""}`
36154
+ );
36155
+ }
36156
+ request(command3) {
36157
+ if (this.exited) return Promise.reject(this.exitError());
36158
+ const id = `ama-${this.nextId++}`;
36159
+ return new Promise((resolve41, reject2) => {
36160
+ this.pending.set(id, { resolve: resolve41, reject: reject2 });
36161
+ this.write({ id, ...command3 });
36162
+ });
36163
+ }
36164
+ write(record3) {
36165
+ if (this.exited) return;
36166
+ this.transport.stdin.write(`${JSON.stringify(record3)}
36167
+ `);
36168
+ }
36169
+ onExit() {
36170
+ this.exited = true;
36171
+ const error2 = this.exitError();
36172
+ for (const p of this.pending.values()) p.reject(error2);
36173
+ this.pending.clear();
36174
+ for (const reject2 of this.exitWaiters) reject2(error2);
36175
+ this.exitWaiters.clear();
36176
+ for (const c of this.permissions) c.abort();
36177
+ }
36178
+ onLine(line2) {
36179
+ let record3;
36180
+ try {
36181
+ record3 = JSON.parse(line2);
36182
+ } catch {
36183
+ this.deps.log?.("debug", msg().drivers.agent.nonJson(this.agentId));
36184
+ return;
36185
+ }
36186
+ switch (record3["type"]) {
36187
+ case "response": {
36188
+ const id = record3["id"];
36189
+ const pending = typeof id === "string" ? this.pending.get(id) : void 0;
36190
+ if (pending === void 0 || typeof id !== "string") return;
36191
+ this.pending.delete(id);
36192
+ pending.resolve(record3);
36193
+ return;
36194
+ }
36195
+ case "agent_settled":
36196
+ this.settle?.(record3["aborted"] === true);
36197
+ return;
36198
+ case "extension_ui_request":
36199
+ void this.onDialog(record3);
36200
+ return;
36201
+ default:
36202
+ this.onEvent(record3);
36203
+ }
36204
+ }
36205
+ onEvent(record3) {
36206
+ const turn = this.turn;
36207
+ if (turn === void 0) return;
36208
+ switch (record3["type"]) {
36209
+ case "message_update": {
36210
+ const event = record3["assistantMessageEvent"] ?? {};
36211
+ const delta = event["delta"];
36212
+ if (typeof delta !== "string") return;
36213
+ if (event["type"] === "text_delta") turn.push({ type: "message_delta", text: delta });
36214
+ else if (event["type"] === "thinking_delta")
36215
+ turn.push({ type: "thought_delta", text: delta });
36216
+ return;
36217
+ }
36218
+ case "message_end": {
36219
+ const message = record3["message"] ?? {};
36220
+ if (message["role"] !== "assistant") return;
36221
+ this.lastAssistant = message;
36222
+ const usage = message["usage"] ?? {};
36223
+ const num10 = (key) => typeof usage[key] === "number" ? usage[key] : 0;
36224
+ const cost2 = (usage["cost"] ?? {})["total"];
36225
+ this.usage = {
36226
+ input: this.usage.input + num10("input"),
36227
+ output: this.usage.output + num10("output"),
36228
+ cacheRead: this.usage.cacheRead + num10("cacheRead"),
36229
+ costUsd: this.usage.costUsd + (typeof cost2 === "number" ? cost2 : 0),
36230
+ seen: true
36231
+ };
36232
+ return;
36233
+ }
36234
+ case "tool_execution_start":
36235
+ case "tool_execution_end": {
36236
+ const tool = String(record3["toolName"] ?? "tool");
36237
+ const known = turn.tool(String(record3["toolCallId"] ?? ""));
36238
+ const input2 = record3["args"] ?? {};
36239
+ const path = typeof input2["path"] === "string" ? input2["path"] : void 0;
36240
+ const locations = path !== void 0 ? [(0, import_node_path61.resolve)(this.options.cwd, path)] : known?.locations;
36241
+ turn.push({
36242
+ type: "tool_call",
36243
+ id: String(record3["toolCallId"] ?? ""),
36244
+ title: known?.title ?? piToolTitle(tool, input2),
36245
+ kind: piToolKind(tool),
36246
+ status: record3["type"] === "tool_execution_start" ? "in_progress" : record3["isError"] === true ? "failed" : "completed",
36247
+ ...locations !== void 0 && locations.length > 0 ? { locations } : {}
36248
+ });
36249
+ return;
36250
+ }
36251
+ case "auto_retry_start":
36252
+ turn.push({
36253
+ type: "notice",
36254
+ level: "warn",
36255
+ text: msg().drivers.agent.error(
36256
+ this.agentId,
36257
+ oneLine2(String(record3["errorMessage"] ?? "error"), 200),
36258
+ true
36259
+ )
36260
+ });
36261
+ return;
36262
+ default:
36263
+ return;
36264
+ }
36265
+ }
36266
+ /** 扩展对话框:ama 的审批闸按模式决定或交给人;其它扩展的对话框取消(不代答)。 */
36267
+ async onDialog(record3) {
36268
+ const id = String(record3["id"] ?? "");
36269
+ const method = String(record3["method"] ?? "");
36270
+ if (!DIALOG_METHODS.has(method)) {
36271
+ if (record3["method"] === "notify" && record3["notifyType"] !== "info")
36272
+ this.turn?.push({
36273
+ type: "notice",
36274
+ level: "warn",
36275
+ text: `${this.agentId}: ${oneLine2(String(record3["message"] ?? ""), 200)}`
36276
+ });
36277
+ return;
36278
+ }
36279
+ if (method !== "confirm" || record3["title"] !== PI_GATE_TITLE) {
36280
+ this.turn?.push({
36281
+ type: "notice",
36282
+ level: "warn",
36283
+ text: msg().drivers.agent.extensionDialog(
36284
+ this.agentId,
36285
+ oneLine2(String(record3["title"] ?? method), 80)
36286
+ )
36287
+ });
36288
+ this.write({ type: "extension_ui_response", id, cancelled: true });
36289
+ return;
36290
+ }
36291
+ const confirmed = await this.decide(record3);
36292
+ this.write({ type: "extension_ui_response", id, confirmed });
36293
+ }
36294
+ async decide(record3) {
36295
+ let call;
36296
+ try {
36297
+ call = JSON.parse(String(record3["message"] ?? "{}"));
36298
+ } catch {
36299
+ return false;
36300
+ }
36301
+ const tool = String(call["tool"] ?? "tool");
36302
+ const input2 = call["input"] ?? {};
36303
+ const mode = this.options.mode;
36304
+ if (isReadOnlyMode(mode)) return false;
36305
+ if (mode !== "default" && EDIT_TOOLS.has(tool)) return true;
36306
+ const hooks = this.hooks;
36307
+ if (hooks === void 0 || this.interrupted || this.closed) return false;
36308
+ const known = this.turn?.tool(String(call["id"] ?? ""));
36309
+ const path = typeof input2["path"] === "string" ? input2["path"] : void 0;
36310
+ const controller = new AbortController();
36311
+ this.permissions.add(controller);
36312
+ try {
36313
+ const outcome = await hooks.onPermission(
36314
+ {
36315
+ toolCall: {
36316
+ title: known?.title ?? piToolTitle(tool, input2),
36317
+ kind: piToolKind(tool),
36318
+ ...path !== void 0 ? { locations: [(0, import_node_path61.resolve)(this.options.cwd, path)] } : {},
36319
+ inputSummary: oneLine2(JSON.stringify(input2), 300)
36320
+ },
36321
+ options: [
36322
+ { optionId: "allow", kind: "allow_once" },
36323
+ { optionId: "reject", kind: "reject_once" }
36324
+ ]
36325
+ },
36326
+ controller.signal
36327
+ );
36328
+ return !controller.signal.aborted && outcome.outcome === "selected" && outcome.optionId === "allow";
36329
+ } finally {
36330
+ this.permissions.delete(controller);
36331
+ }
36332
+ }
36333
+ };
36334
+ }
36335
+ });
36336
+
35566
36337
  // src/drivers/pids.ts
35567
36338
  function pidsFile(dataDir) {
35568
- return (0, import_node_path60.join)(dataDir, "drivers", "pids.json");
36339
+ return (0, import_node_path62.join)(dataDir, "drivers", "pids.json");
35569
36340
  }
35570
36341
  function read(file) {
35571
36342
  try {
35572
- const parsed = JSON.parse((0, import_node_fs41.readFileSync)(file, "utf8"));
36343
+ const parsed = JSON.parse((0, import_node_fs42.readFileSync)(file, "utf8"));
35573
36344
  return Array.isArray(parsed.entries) ? parsed.entries : [];
35574
36345
  } catch {
35575
36346
  return [];
@@ -35577,11 +36348,11 @@ function read(file) {
35577
36348
  }
35578
36349
  function write(file, entries) {
35579
36350
  try {
35580
- (0, import_node_fs41.mkdirSync)((0, import_node_path60.dirname)(file), { recursive: true });
36351
+ (0, import_node_fs42.mkdirSync)((0, import_node_path62.dirname)(file), { recursive: true });
35581
36352
  const tmp = `${file}.${process.pid}.tmp`;
35582
- (0, import_node_fs41.writeFileSync)(tmp, `${JSON.stringify({ version: 1, entries }, null, 2)}
36353
+ (0, import_node_fs42.writeFileSync)(tmp, `${JSON.stringify({ version: 1, entries }, null, 2)}
35583
36354
  `);
35584
- (0, import_node_fs41.renameSync)(tmp, file);
36355
+ (0, import_node_fs42.renameSync)(tmp, file);
35585
36356
  } catch {
35586
36357
  }
35587
36358
  }
@@ -35597,13 +36368,13 @@ function psCommand(pid) {
35597
36368
  const out = (0, import_node_child_process11.spawnSync)("ps", ["-o", "command=", "-p", String(pid)], { encoding: "utf8" });
35598
36369
  return out.status === 0 ? out.stdout.trim() : void 0;
35599
36370
  }
35600
- var import_node_child_process11, import_node_fs41, import_node_path60, PidRegistry;
36371
+ var import_node_child_process11, import_node_fs42, import_node_path62, PidRegistry;
35601
36372
  var init_pids = __esm({
35602
36373
  "src/drivers/pids.ts"() {
35603
36374
  "use strict";
35604
36375
  import_node_child_process11 = require("node:child_process");
35605
- import_node_fs41 = require("node:fs");
35606
- import_node_path60 = require("node:path");
36376
+ import_node_fs42 = require("node:fs");
36377
+ import_node_path62 = require("node:path");
35607
36378
  init_process_tree();
35608
36379
  PidRegistry = class {
35609
36380
  constructor(file) {
@@ -35639,7 +36410,7 @@ var init_pids = __esm({
35639
36410
  }
35640
36411
  if (platform === "win32" || !groupAlive(entry.pid)) continue;
35641
36412
  const command3 = commandOf(entry.pid);
35642
- if (command3 !== void 0 && command3.includes((0, import_node_path60.basename)(entry.program))) {
36413
+ if (command3 !== void 0 && command3.includes((0, import_node_path62.basename)(entry.program))) {
35643
36414
  await kill(entry.pid);
35644
36415
  killed.push(entry.pid);
35645
36416
  }
@@ -35799,7 +36570,7 @@ async function askHuman(request, ctx) {
35799
36570
  if (ctx.signal.aborted) return CANCELLED;
35800
36571
  if (ctx.unattended) return pick(request, "reject_once") ?? CANCELLED;
35801
36572
  const approval = {
35802
- requestId: (0, import_node_crypto14.randomUUID)(),
36573
+ requestId: (0, import_node_crypto15.randomUUID)(),
35803
36574
  toolName: externalToolName(ctx.agent),
35804
36575
  input: request.toolCall,
35805
36576
  reason: "mode",
@@ -35840,11 +36611,11 @@ function supportedMode(mode, supported) {
35840
36611
  if (rank(m) <= rank(mode) && (best === void 0 || rank(m) > rank(best))) best = m;
35841
36612
  return best;
35842
36613
  }
35843
- var import_node_crypto14, CANCELLED;
36614
+ var import_node_crypto15, CANCELLED;
35844
36615
  var init_permissions2 = __esm({
35845
36616
  "src/drivers/permissions.ts"() {
35846
36617
  "use strict";
35847
- import_node_crypto14 = require("node:crypto");
36618
+ import_node_crypto15 = require("node:crypto");
35848
36619
  init_types();
35849
36620
  CANCELLED = { outcome: "cancelled" };
35850
36621
  }
@@ -35991,7 +36762,8 @@ var init_runner2 = __esm({
35991
36762
  "acp",
35992
36763
  "acp-adapter",
35993
36764
  "claude-stream",
35994
- "codex-app-server"
36765
+ "codex-app-server",
36766
+ "pi-rpc"
35995
36767
  ]);
35996
36768
  ProcessHandle = class {
35997
36769
  constructor(runner, chosen, request, deps) {
@@ -36318,15 +37090,17 @@ function createDriver(agentId, candidate, deps) {
36318
37090
  return new ClaudeStreamDriver(agentId, candidate, deps);
36319
37091
  case "codex-app-server":
36320
37092
  return new CodexAppServerDriver(agentId, candidate, deps);
37093
+ case "pi-rpc":
37094
+ return new PiRpcDriver(agentId, candidate, deps);
36321
37095
  case "oneshot":
36322
37096
  return new OneshotDriver(agentId, candidate, deps);
36323
37097
  }
36324
37098
  }
36325
- var import_node_path61, reaped, ExternalAgents;
37099
+ var import_node_path63, reaped, ExternalAgents;
36326
37100
  var init_agents2 = __esm({
36327
37101
  "src/drivers/agents.ts"() {
36328
37102
  "use strict";
36329
- import_node_path61 = require("node:path");
37103
+ import_node_path63 = require("node:path");
36330
37104
  init_errors();
36331
37105
  init_driver();
36332
37106
  init_catalog4();
@@ -36334,6 +37108,7 @@ var init_agents2 = __esm({
36334
37108
  init_claude_stream();
36335
37109
  init_codex_app_server();
36336
37110
  init_oneshot();
37111
+ init_pi_rpc();
36337
37112
  init_pids();
36338
37113
  init_pool();
36339
37114
  init_probe();
@@ -36359,7 +37134,7 @@ var init_agents2 = __esm({
36359
37134
  probe: new ProgramProbe({
36360
37135
  env: options.env,
36361
37136
  cwd: options.cwd,
36362
- ...options.dataDir !== void 0 ? { cacheFile: (0, import_node_path61.join)(options.dataDir, "drivers.json") } : {}
37137
+ ...options.dataDir !== void 0 ? { cacheFile: (0, import_node_path63.join)(options.dataDir, "drivers.json") } : {}
36363
37138
  }),
36364
37139
  spawn: (spec2) => spawnTransport(spec2, {
36365
37140
  onSpawn: (pid) => registry3?.add(pid, spec2.program),
@@ -36606,11 +37381,11 @@ function mergeAgentInfos(base4, external) {
36606
37381
  }
36607
37382
  return out;
36608
37383
  }
36609
- var import_node_crypto15, LISTED_EXTERNAL_AGENTS, NO_AGENT_PROBE_ENV, externalTesting, HOST_AMA_RUNNER, ExternalTaskHandle, infoCache, SessionExternalAgents;
37384
+ var import_node_crypto16, LISTED_EXTERNAL_AGENTS, NO_AGENT_PROBE_ENV, externalTesting, HOST_AMA_RUNNER, ExternalTaskHandle, infoCache, SessionExternalAgents;
36610
37385
  var init_external = __esm({
36611
37386
  "src/agents/external.ts"() {
36612
37387
  "use strict";
36613
- import_node_crypto15 = require("node:crypto");
37388
+ import_node_crypto16 = require("node:crypto");
36614
37389
  init_session_tools();
36615
37390
  init_types_w5();
36616
37391
  init_agents2();
@@ -36785,7 +37560,7 @@ var init_external = __esm({
36785
37560
  agentEntry(this.wiring.config, spec2)?.maxMode
36786
37561
  );
36787
37562
  const approval = {
36788
- requestId: (0, import_node_crypto15.randomUUID)(),
37563
+ requestId: (0, import_node_crypto16.randomUUID)(),
36789
37564
  toolName: "task",
36790
37565
  input: {
36791
37566
  agent: spec2,
@@ -37031,7 +37806,7 @@ function sourceText2(source, cache3, log) {
37031
37806
  if (cached !== void 0) return cached;
37032
37807
  let text = "";
37033
37808
  try {
37034
- text = (0, import_node_fs42.readFileSync)(source.path, "utf8");
37809
+ text = (0, import_node_fs43.readFileSync)(source.path, "utf8");
37035
37810
  } catch (error2) {
37036
37811
  log(
37037
37812
  "warn",
@@ -37385,11 +38160,11 @@ async function disposeSessionAlongside(target, session, fallback) {
37385
38160
  await session.dispose();
37386
38161
  record3.live.delete(session);
37387
38162
  }
37388
- var import_node_fs42, records, LOG_LEVELS;
38163
+ var import_node_fs43, records, LOG_LEVELS;
37389
38164
  var init_compose_session = __esm({
37390
38165
  "src/cli/compose-session.ts"() {
37391
38166
  "use strict";
37392
- import_node_fs42 = require("node:fs");
38167
+ import_node_fs43 = require("node:fs");
37393
38168
  init_limits();
37394
38169
  init_session2();
37395
38170
  init_session_subagent();
@@ -37437,7 +38212,7 @@ function toolTitle(name, args, nested = false) {
37437
38212
  function toolLocations(args, cwd) {
37438
38213
  const path = argOf(args, "path", "file_path", "filePath");
37439
38214
  if (path === void 0) return void 0;
37440
- return [{ path: (0, import_node_path62.isAbsolute)(path) ? path : (0, import_node_path62.resolve)(cwd, path) }];
38215
+ return [{ path: (0, import_node_path64.isAbsolute)(path) ? path : (0, import_node_path64.resolve)(cwd, path) }];
37441
38216
  }
37442
38217
  function resultText2(content) {
37443
38218
  const text = typeof content === "string" ? content : content.map((b) => b.type === "text" ? b.text : `[${b.type}]`).join("");
@@ -37464,11 +38239,11 @@ function resultContent(result) {
37464
38239
  ]
37465
38240
  };
37466
38241
  }
37467
- var import_node_path62, TOOL_OUTPUT_LIMIT, KINDS3;
38242
+ var import_node_path64, TOOL_OUTPUT_LIMIT, KINDS3;
37468
38243
  var init_acp_tool_text = __esm({
37469
38244
  "src/modes/acp/acp-tool-text.ts"() {
37470
38245
  "use strict";
37471
- import_node_path62 = require("node:path");
38246
+ import_node_path64 = require("node:path");
37472
38247
  init_turn();
37473
38248
  init_i18n();
37474
38249
  TOOL_OUTPUT_LIMIT = 4 * 1024;
@@ -38245,9 +39020,9 @@ var init_acp_sessions = __esm({
38245
39020
  // src/modes/acp/acp-server.ts
38246
39021
  function canonical(path) {
38247
39022
  try {
38248
- return import_node_fs43.realpathSync.native((0, import_node_path63.resolve)(path));
39023
+ return import_node_fs44.realpathSync.native((0, import_node_path65.resolve)(path));
38249
39024
  } catch {
38250
- return (0, import_node_path63.resolve)(path);
39025
+ return (0, import_node_path65.resolve)(path);
38251
39026
  }
38252
39027
  }
38253
39028
  function str(params, key) {
@@ -38276,12 +39051,12 @@ ${block.resource.text}
38276
39051
  function countOf(value) {
38277
39052
  return Array.isArray(value) ? value.length : 0;
38278
39053
  }
38279
- var import_node_fs43, import_node_path63, ACP_AGENT_CAPABILITIES, SESSION_ID_SHAPE, AcpServer;
39054
+ var import_node_fs44, import_node_path65, ACP_AGENT_CAPABILITIES, SESSION_ID_SHAPE, AcpServer;
38280
39055
  var init_acp_server = __esm({
38281
39056
  "src/modes/acp/acp-server.ts"() {
38282
39057
  "use strict";
38283
- import_node_fs43 = require("node:fs");
38284
- import_node_path63 = require("node:path");
39058
+ import_node_fs44 = require("node:fs");
39059
+ import_node_path65 = require("node:path");
38285
39060
  init_shared();
38286
39061
  init_compose_session();
38287
39062
  init_compose_store();
@@ -38795,7 +39570,7 @@ function terminalAuthMethods(authFile) {
38795
39570
  ];
38796
39571
  }
38797
39572
  function gateAuthFile(args, cwd) {
38798
- if (args.authFile !== void 0) return (0, import_node_path64.resolve)(cwd, args.authFile);
39573
+ if (args.authFile !== void 0) return (0, import_node_path66.resolve)(cwd, args.authFile);
38799
39574
  if (args.profile === void 0) return void 0;
38800
39575
  try {
38801
39576
  return loadProfile(args.profile, cwd).authFile;
@@ -38918,11 +39693,11 @@ async function runAcpAuthGate(args, deps, io, cause, options = {}) {
38918
39693
  await runtime?.dispose("exit").catch(() => void 0);
38919
39694
  return code;
38920
39695
  }
38921
- var import_node_path64, AUTH_RETRY_INTERVAL_MS, SESSION_METHODS;
39696
+ var import_node_path66, AUTH_RETRY_INTERVAL_MS, SESSION_METHODS;
38922
39697
  var init_acp_auth_gate = __esm({
38923
39698
  "src/modes/acp/acp-auth-gate.ts"() {
38924
39699
  "use strict";
38925
- import_node_path64 = require("node:path");
39700
+ import_node_path66 = require("node:path");
38926
39701
  init_args();
38927
39702
  init_bootstrap();
38928
39703
  init_exit_codes();
@@ -39004,7 +39779,7 @@ async function bootstrap(argsIn, deps, io) {
39004
39779
  () => deps.sessions.open(sessionRequest, { sessionDir: paths.sessionDir, cwd: paths.cwd })
39005
39780
  );
39006
39781
  let sessionCwd = sessionManager.cwd;
39007
- if (!(0, import_node_fs44.existsSync)(sessionCwd)) {
39782
+ if (!(0, import_node_fs45.existsSync)(sessionCwd)) {
39008
39783
  const replacement = interactive ? await deps.ui?.askCwd?.(sessionCwd) : void 0;
39009
39784
  if (replacement === void 0) {
39010
39785
  throw new StartupError(
@@ -39013,7 +39788,7 @@ async function bootstrap(argsIn, deps, io) {
39013
39788
  ExitCode.Session
39014
39789
  );
39015
39790
  }
39016
- sessionCwd = (0, import_node_path65.resolve)(replacement);
39791
+ sessionCwd = (0, import_node_path67.resolve)(replacement);
39017
39792
  }
39018
39793
  const runtimePaths = { ...paths, cwd: sessionCwd };
39019
39794
  const trust = await step(
@@ -39088,7 +39863,7 @@ async function bootstrap(argsIn, deps, io) {
39088
39863
  () => deps.providers.create({
39089
39864
  config,
39090
39865
  cwd: sessionCwd,
39091
- authFile: args.authFile !== void 0 ? (0, import_node_path65.resolve)(io.cwd, args.authFile) : defaultAuthFilePath(paths.configDir),
39866
+ authFile: args.authFile !== void 0 ? (0, import_node_path67.resolve)(io.cwd, args.authFile) : defaultAuthFilePath(paths.configDir),
39092
39867
  authEnv: profile?.authEnv ?? true,
39093
39868
  dataDir: paths.dataDir,
39094
39869
  ...args.apiKey !== void 0 && args.model !== void 0 ? {
@@ -39398,12 +40173,12 @@ function reportError(error2, io, fallback = ExitCode.RuntimeError) {
39398
40173
  if (isAmaError(error2) && error2.exitCode !== void 0) return error2.exitCode;
39399
40174
  return fallback;
39400
40175
  }
39401
- var import_node_fs44, import_node_path65;
40176
+ var import_node_fs45, import_node_path67;
39402
40177
  var init_bootstrap = __esm({
39403
40178
  "src/cli/bootstrap.ts"() {
39404
40179
  "use strict";
39405
- import_node_fs44 = require("node:fs");
39406
- import_node_path65 = require("node:path");
40180
+ import_node_fs45 = require("node:fs");
40181
+ import_node_path67 = require("node:path");
39407
40182
  init_auth_file();
39408
40183
  init_context_files();
39409
40184
  init_load();
@@ -39429,7 +40204,7 @@ var init_bootstrap = __esm({
39429
40204
  // src/auth/oauth/token-store.ts
39430
40205
  function readRaw(path) {
39431
40206
  try {
39432
- const value = JSON.parse(retryTransientFs(() => (0, import_node_fs45.readFileSync)(path, "utf8")));
40207
+ const value = JSON.parse(retryTransientFs(() => (0, import_node_fs46.readFileSync)(path, "utf8")));
39433
40208
  return typeof value === "object" && value !== null && typeof value.providers === "object" ? value : void 0;
39434
40209
  } catch {
39435
40210
  return void 0;
@@ -39461,12 +40236,12 @@ function isStaleLock(path, now = Date.now()) {
39461
40236
  let age;
39462
40237
  let pid;
39463
40238
  try {
39464
- age = now - (0, import_node_fs45.statSync)(path).mtimeMs;
39465
- const value = JSON.parse((0, import_node_fs45.readFileSync)(path, "utf8"));
40239
+ age = now - (0, import_node_fs46.statSync)(path).mtimeMs;
40240
+ const value = JSON.parse((0, import_node_fs46.readFileSync)(path, "utf8"));
39466
40241
  pid = typeof value.pid === "number" ? value.pid : void 0;
39467
40242
  } catch {
39468
40243
  try {
39469
- age = now - (0, import_node_fs45.statSync)(path).mtimeMs;
40244
+ age = now - (0, import_node_fs46.statSync)(path).mtimeMs;
39470
40245
  } catch {
39471
40246
  return false;
39472
40247
  }
@@ -39475,11 +40250,11 @@ function isStaleLock(path, now = Date.now()) {
39475
40250
  }
39476
40251
  function tryAcquire(path) {
39477
40252
  try {
39478
- const fd = (0, import_node_fs45.openSync)(path, "wx", 384);
40253
+ const fd = (0, import_node_fs46.openSync)(path, "wx", 384);
39479
40254
  try {
39480
- (0, import_node_fs45.writeSync)(fd, JSON.stringify({ pid: process.pid, at: (/* @__PURE__ */ new Date()).toISOString() }));
40255
+ (0, import_node_fs46.writeSync)(fd, JSON.stringify({ pid: process.pid, at: (/* @__PURE__ */ new Date()).toISOString() }));
39481
40256
  } finally {
39482
- (0, import_node_fs45.closeSync)(fd);
40257
+ (0, import_node_fs46.closeSync)(fd);
39483
40258
  }
39484
40259
  return true;
39485
40260
  } catch (error2) {
@@ -39490,13 +40265,13 @@ function tryAcquire(path) {
39490
40265
  }
39491
40266
  async function withRefreshLock(authFile, fn, options = {}) {
39492
40267
  const path = lockPath(authFile);
39493
- (0, import_node_fs45.mkdirSync)((0, import_node_path66.dirname)(path), { recursive: true, mode: 448 });
40268
+ (0, import_node_fs46.mkdirSync)((0, import_node_path68.dirname)(path), { recursive: true, mode: 448 });
39494
40269
  const deadline = Date.now() + (options.waitMs ?? LOCK_WAIT_MS);
39495
40270
  for (; ; ) {
39496
40271
  if (tryAcquire(path)) break;
39497
40272
  if (isStaleLock(path)) {
39498
40273
  try {
39499
- (0, import_node_fs45.unlinkSync)(path);
40274
+ (0, import_node_fs46.unlinkSync)(path);
39500
40275
  } catch {
39501
40276
  }
39502
40277
  continue;
@@ -39511,17 +40286,17 @@ async function withRefreshLock(authFile, fn, options = {}) {
39511
40286
  return await fn();
39512
40287
  } finally {
39513
40288
  try {
39514
- (0, import_node_fs45.unlinkSync)(path);
40289
+ (0, import_node_fs46.unlinkSync)(path);
39515
40290
  } catch {
39516
40291
  }
39517
40292
  }
39518
40293
  }
39519
- var import_node_fs45, import_node_path66, LOCK_WAIT_MS, LOCK_STALE_MS, LOCK_POLL_MS;
40294
+ var import_node_fs46, import_node_path68, LOCK_WAIT_MS, LOCK_STALE_MS, LOCK_POLL_MS;
39520
40295
  var init_token_store = __esm({
39521
40296
  "src/auth/oauth/token-store.ts"() {
39522
40297
  "use strict";
39523
- import_node_fs45 = require("node:fs");
39524
- import_node_path66 = require("node:path");
40298
+ import_node_fs46 = require("node:fs");
40299
+ import_node_path68 = require("node:path");
39525
40300
  init_auth_file();
39526
40301
  init_fs_retry();
39527
40302
  init_types2();
@@ -39535,7 +40310,7 @@ var init_token_store = __esm({
39535
40310
 
39536
40311
  // src/ai/providers/discovered-cache.ts
39537
40312
  function discoveredCachePath(dataDir, provider) {
39538
- return (0, import_node_path67.join)(dataDir, "models", "discovered", `${provider}.json`);
40313
+ return (0, import_node_path69.join)(dataDir, "models", "discovered", `${provider}.json`);
39539
40314
  }
39540
40315
  function toEntry(value) {
39541
40316
  if (typeof value !== "object" || value === null) return void 0;
@@ -39555,7 +40330,7 @@ function toEntry(value) {
39555
40330
  function readDiscoveredCache(dataDir, provider) {
39556
40331
  let parsed;
39557
40332
  try {
39558
- parsed = JSON.parse((0, import_node_fs46.readFileSync)(discoveredCachePath(dataDir, provider), "utf8"));
40333
+ parsed = JSON.parse((0, import_node_fs47.readFileSync)(discoveredCachePath(dataDir, provider), "utf8"));
39559
40334
  } catch {
39560
40335
  return void 0;
39561
40336
  }
@@ -39579,17 +40354,17 @@ function writeDiscoveredCache(dataDir, provider, input2, now = Date.now()) {
39579
40354
  ...input2.flavor !== void 0 ? { flavor: input2.flavor } : {},
39580
40355
  models: input2.models.map(toEntry).filter((m) => m !== void 0)
39581
40356
  };
39582
- (0, import_node_fs46.mkdirSync)((0, import_node_path67.dirname)(path), { recursive: true, mode: 448 });
40357
+ (0, import_node_fs47.mkdirSync)((0, import_node_path69.dirname)(path), { recursive: true, mode: 448 });
39583
40358
  const tmp = `${path}.${process.pid}.tmp`;
39584
- (0, import_node_fs46.writeFileSync)(tmp, `${JSON.stringify(file, null, 2)}
40359
+ (0, import_node_fs47.writeFileSync)(tmp, `${JSON.stringify(file, null, 2)}
39585
40360
  `);
39586
- (0, import_node_fs46.renameSync)(tmp, path);
40361
+ (0, import_node_fs47.renameSync)(tmp, path);
39587
40362
  return path;
39588
40363
  }
39589
40364
  function clearDiscoveredCache(dataDir, provider) {
39590
40365
  const path = discoveredCachePath(dataDir, provider);
39591
- if (!(0, import_node_fs46.existsSync)(path)) return false;
39592
- (0, import_node_fs46.rmSync)(path, { force: true });
40366
+ if (!(0, import_node_fs47.existsSync)(path)) return false;
40367
+ (0, import_node_fs47.rmSync)(path, { force: true });
39593
40368
  return true;
39594
40369
  }
39595
40370
  function thinkingMapOf(levels) {
@@ -39643,12 +40418,12 @@ function mergeDiscoveredModels(registry3, dataDir, modelsDev, loginFlavor = () =
39643
40418
  }
39644
40419
  return merged;
39645
40420
  }
39646
- var import_node_fs46, import_node_path67, DISCOVERED_CACHE_VERSION, EFFORT_LEVELS, SUBSCRIPTION_FALLBACK_CONTEXT_WINDOW, SUBSCRIPTION_PROVIDERS;
40421
+ var import_node_fs47, import_node_path69, DISCOVERED_CACHE_VERSION, EFFORT_LEVELS, SUBSCRIPTION_FALLBACK_CONTEXT_WINDOW, SUBSCRIPTION_PROVIDERS;
39647
40422
  var init_discovered_cache = __esm({
39648
40423
  "src/ai/providers/discovered-cache.ts"() {
39649
40424
  "use strict";
39650
- import_node_fs46 = require("node:fs");
39651
- import_node_path67 = require("node:path");
40425
+ import_node_fs47 = require("node:fs");
40426
+ import_node_path69 = require("node:path");
39652
40427
  init_catalog2();
39653
40428
  init_enrich();
39654
40429
  DISCOVERED_CACHE_VERSION = 1;
@@ -41531,7 +42306,7 @@ function parseKeybindings(value) {
41531
42306
  function loadKeybindingsFile(path) {
41532
42307
  let text;
41533
42308
  try {
41534
- text = (0, import_node_fs48.readFileSync)(path, "utf8");
42309
+ text = (0, import_node_fs49.readFileSync)(path, "utf8");
41535
42310
  } catch (error2) {
41536
42311
  if (error2.code === "ENOENT") return { overrides: {}, warnings: [] };
41537
42312
  return {
@@ -41548,12 +42323,12 @@ function loadKeybindingsFile(path) {
41548
42323
  };
41549
42324
  }
41550
42325
  }
41551
- var import_node_fs48, DEFAULT_KEYBINDINGS, Keybindings, defaultKeybindings;
42326
+ var import_node_fs49, DEFAULT_KEYBINDINGS, Keybindings, defaultKeybindings;
41552
42327
  var init_keybindings = __esm({
41553
42328
  "src/tui/keybindings.ts"() {
41554
42329
  "use strict";
41555
42330
  init_i18n();
41556
- import_node_fs48 = require("node:fs");
42331
+ import_node_fs49 = require("node:fs");
41557
42332
  init_keys();
41558
42333
  DEFAULT_KEYBINDINGS = {
41559
42334
  "tui.editor.submit": ["enter"],
@@ -42389,7 +43164,7 @@ var init_editor_buffer = __esm({
42389
43164
  function loadHistoryFile(path, limit = 500) {
42390
43165
  let text;
42391
43166
  try {
42392
- text = (0, import_node_fs49.readFileSync)(path, "utf8");
43167
+ text = (0, import_node_fs50.readFileSync)(path, "utf8");
42393
43168
  } catch {
42394
43169
  return [];
42395
43170
  }
@@ -42406,11 +43181,11 @@ function loadHistoryFile(path, limit = 500) {
42406
43181
  }
42407
43182
  function appendHistoryFile(path, entry, limit) {
42408
43183
  try {
42409
- (0, import_node_fs49.mkdirSync)((0, import_node_path69.dirname)(path), { recursive: true });
42410
- (0, import_node_fs49.appendFileSync)(path, JSON.stringify(entry) + "\n", { mode: 384 });
43184
+ (0, import_node_fs50.mkdirSync)((0, import_node_path71.dirname)(path), { recursive: true });
43185
+ (0, import_node_fs50.appendFileSync)(path, JSON.stringify(entry) + "\n", { mode: 384 });
42411
43186
  const all = loadHistoryFile(path, Number.MAX_SAFE_INTEGER);
42412
43187
  if (all.length > limit * 2) {
42413
- (0, import_node_fs49.writeFileSync)(
43188
+ (0, import_node_fs50.writeFileSync)(
42414
43189
  path,
42415
43190
  all.slice(-limit).map((e) => JSON.stringify(e) + "\n").join("")
42416
43191
  );
@@ -42418,12 +43193,12 @@ function appendHistoryFile(path, entry, limit) {
42418
43193
  } catch {
42419
43194
  }
42420
43195
  }
42421
- var import_node_fs49, import_node_path69;
43196
+ var import_node_fs50, import_node_path71;
42422
43197
  var init_editor_history = __esm({
42423
43198
  "src/tui/components/editor-history.ts"() {
42424
43199
  "use strict";
42425
- import_node_fs49 = require("node:fs");
42426
- import_node_path69 = require("node:path");
43200
+ import_node_fs50 = require("node:fs");
43201
+ import_node_path71 = require("node:path");
42427
43202
  }
42428
43203
  });
42429
43204
 
@@ -43981,7 +44756,8 @@ var init_key_docs = __esm({
43981
44756
  maxPending: 16,
43982
44757
  background: "auto",
43983
44758
  autoBackgroundAfterMs: 0,
43984
- retainSessions: 4
44759
+ retainSessions: 4,
44760
+ forkMaxContextRatio: 0.5
43985
44761
  },
43986
44762
  reminders: { todo: true, fileChanges: true, contextPressure: true, budget: true },
43987
44763
  todo: { reminder: 10 }
@@ -43996,7 +44772,7 @@ var init_key_docs = __esm({
43996
44772
 
43997
44773
  // src/ai/providers/models-dev-cache.ts
43998
44774
  function modelsDevCachePath(dataDir) {
43999
- return (0, import_node_path71.join)(dataDir, MODELS_DEV_FILE);
44775
+ return (0, import_node_path73.join)(dataDir, MODELS_DEV_FILE);
44000
44776
  }
44001
44777
  function modelsDevUrl(env = process.env) {
44002
44778
  const custom = env[MODELS_DEV_URL_ENV]?.trim();
@@ -44004,7 +44780,7 @@ function modelsDevUrl(env = process.env) {
44004
44780
  }
44005
44781
  function readModelsDevCache(dataDir) {
44006
44782
  try {
44007
- const value = JSON.parse((0, import_node_fs50.readFileSync)(modelsDevCachePath(dataDir), "utf8"));
44783
+ const value = JSON.parse((0, import_node_fs51.readFileSync)(modelsDevCachePath(dataDir), "utf8"));
44008
44784
  if (typeof value !== "object" || value === null) return void 0;
44009
44785
  const file = value;
44010
44786
  if (file.version !== 2 || typeof file.fetchedAt !== "string") return void 0;
@@ -44017,10 +44793,10 @@ function readModelsDevCache(dataDir) {
44017
44793
  }
44018
44794
  function writeModelsDevCache(dataDir, file) {
44019
44795
  const path = modelsDevCachePath(dataDir);
44020
- (0, import_node_fs50.mkdirSync)((0, import_node_path71.dirname)(path), { recursive: true, mode: 448 });
44796
+ (0, import_node_fs51.mkdirSync)((0, import_node_path73.dirname)(path), { recursive: true, mode: 448 });
44021
44797
  const tmp = `${path}.${process.pid}.tmp`;
44022
- (0, import_node_fs50.writeFileSync)(tmp, JSON.stringify(file));
44023
- (0, import_node_fs50.renameSync)(tmp, path);
44798
+ (0, import_node_fs51.writeFileSync)(tmp, JSON.stringify(file));
44799
+ (0, import_node_fs51.renameSync)(tmp, path);
44024
44800
  memo = void 0;
44025
44801
  }
44026
44802
  function overrideApplies(file) {
@@ -44030,7 +44806,7 @@ function loadModelsDevIndex(dataDir) {
44030
44806
  const path = modelsDevCachePath(dataDir);
44031
44807
  let key;
44032
44808
  try {
44033
- const stat16 = (0, import_node_fs50.statSync)(path);
44809
+ const stat16 = (0, import_node_fs51.statSync)(path);
44034
44810
  key = `${path}\0${stat16.mtimeMs}\0${stat16.size}`;
44035
44811
  } catch {
44036
44812
  return builtinSnapshotIndex();
@@ -44115,12 +44891,12 @@ function describeRefresh(result, limit = 20) {
44115
44891
  }
44116
44892
  return lines2.join("\n");
44117
44893
  }
44118
- var import_node_fs50, import_node_path71, MODELS_DEV_URL, MODELS_DEV_URL_ENV, MODELS_DEV_FILE, MODELS_DEV_TIMEOUT_MS, memo;
44894
+ var import_node_fs51, import_node_path73, MODELS_DEV_URL, MODELS_DEV_URL_ENV, MODELS_DEV_FILE, MODELS_DEV_TIMEOUT_MS, memo;
44119
44895
  var init_models_dev_cache = __esm({
44120
44896
  "src/ai/providers/models-dev-cache.ts"() {
44121
44897
  "use strict";
44122
- import_node_fs50 = require("node:fs");
44123
- import_node_path71 = require("node:path");
44898
+ import_node_fs51 = require("node:fs");
44899
+ import_node_path73 = require("node:path");
44124
44900
  init_models_dev();
44125
44901
  init_models_dev_snapshot();
44126
44902
  init_i18n();
@@ -44246,7 +45022,8 @@ function w5Sections() {
44246
45022
  defaultModel: str3(),
44247
45023
  background: oneOf(SUBAGENT_BACKGROUND_MODES),
44248
45024
  autoBackgroundAfterMs: num2(0),
44249
- retainSessions: num2(0)
45025
+ retainSessions: num2(0),
45026
+ forkMaxContextRatio: num2(0.05, 0.95)
44250
45027
  }),
44251
45028
  models: object({ aliases: object({ fast: str3(), strong: str3() }), enabled: strings2 }),
44252
45029
  fallbackModel: str3(),
@@ -44464,40 +45241,40 @@ function minimalConfig() {
44464
45241
  }
44465
45242
  function writeAtomic2(path, text, mode) {
44466
45243
  const tmp = `${path}.${process.pid}.tmp`;
44467
- (0, import_node_fs51.writeFileSync)(tmp, text, { mode });
44468
- (0, import_node_fs51.renameSync)(tmp, path);
45244
+ (0, import_node_fs52.writeFileSync)(tmp, text, { mode });
45245
+ (0, import_node_fs52.renameSync)(tmp, path);
44469
45246
  }
44470
45247
  function initConfigDir(dir, options = {}) {
44471
- const dirCreated = !(0, import_node_fs51.existsSync)(dir);
44472
- (0, import_node_fs51.mkdirSync)(dir, { recursive: true, mode: 448 });
44473
- if (dirCreated && process.platform !== "win32") (0, import_node_fs51.chmodSync)(dir, 448);
45248
+ const dirCreated = !(0, import_node_fs52.existsSync)(dir);
45249
+ (0, import_node_fs52.mkdirSync)(dir, { recursive: true, mode: 448 });
45250
+ if (dirCreated && process.platform !== "win32") (0, import_node_fs52.chmodSync)(dir, 448);
44474
45251
  const files = [];
44475
- const config = (0, import_node_path72.join)(dir, CONFIG_FILE);
45252
+ const config = (0, import_node_path74.join)(dir, CONFIG_FILE);
44476
45253
  const text = `${JSON.stringify(minimalConfig(), null, 2)}
44477
45254
  `;
44478
- if (!(0, import_node_fs51.existsSync)(config)) {
45255
+ if (!(0, import_node_fs52.existsSync)(config)) {
44479
45256
  writeAtomic2(config, text, 420);
44480
45257
  files.push({ path: config, status: "created" });
44481
45258
  } else if (options.force) {
44482
- (0, import_node_fs51.copyFileSync)(config, `${config}.bak`);
45259
+ (0, import_node_fs52.copyFileSync)(config, `${config}.bak`);
44483
45260
  writeAtomic2(config, text, 420);
44484
45261
  files.push({ path: config, status: "overwritten" });
44485
45262
  } else files.push({ path: config, status: "exists" });
44486
- const schema = (0, import_node_path72.join)(dir, CONFIG_SCHEMA_FILE);
45263
+ const schema = (0, import_node_path74.join)(dir, CONFIG_SCHEMA_FILE);
44487
45264
  const schemaText = configSchemaText();
44488
- if (!(0, import_node_fs51.existsSync)(schema)) {
45265
+ if (!(0, import_node_fs52.existsSync)(schema)) {
44489
45266
  writeAtomic2(schema, schemaText, 420);
44490
45267
  files.push({ path: schema, status: "created" });
44491
- } else if ((0, import_node_fs51.readFileSync)(schema, "utf8") !== schemaText) {
45268
+ } else if ((0, import_node_fs52.readFileSync)(schema, "utf8") !== schemaText) {
44492
45269
  writeAtomic2(schema, schemaText, 420);
44493
45270
  files.push({ path: schema, status: "updated" });
44494
45271
  } else files.push({ path: schema, status: "unchanged" });
44495
- const auth = (0, import_node_path72.join)(dir, AUTH_FILE);
44496
- if ((0, import_node_fs51.existsSync)(auth)) files.push({ path: auth, status: "exists" });
45272
+ const auth = (0, import_node_path74.join)(dir, AUTH_FILE);
45273
+ if ((0, import_node_fs52.existsSync)(auth)) files.push({ path: auth, status: "exists" });
44497
45274
  return { dir, dirCreated, files };
44498
45275
  }
44499
45276
  function autoInitConfigDir(dir, env) {
44500
- if (env[NO_INIT_ENV] === "1" || (0, import_node_fs51.existsSync)(dir)) return false;
45277
+ if (env[NO_INIT_ENV] === "1" || (0, import_node_fs52.existsSync)(dir)) return false;
44501
45278
  try {
44502
45279
  initConfigDir(dir);
44503
45280
  return true;
@@ -44515,12 +45292,12 @@ function describeInit(result) {
44515
45292
  return `${lines2.join("\n")}
44516
45293
  `;
44517
45294
  }
44518
- var import_node_fs51, import_node_path72, NO_INIT_ENV;
45295
+ var import_node_fs52, import_node_path74, NO_INIT_ENV;
44519
45296
  var init_init = __esm({
44520
45297
  "src/config/init.ts"() {
44521
45298
  "use strict";
44522
- import_node_fs51 = require("node:fs");
44523
- import_node_path72 = require("node:path");
45299
+ import_node_fs52 = require("node:fs");
45300
+ import_node_path74 = require("node:path");
44524
45301
  init_i18n();
44525
45302
  init_json_schema();
44526
45303
  init_paths();
@@ -45566,6 +46343,13 @@ function recoverChatGptError(error2, model, compat, options, apiKey, tried) {
45566
46343
  return { kind: "retry" };
45567
46344
  }
45568
46345
  }
46346
+ if (backend === "codex" && error2.status === 400 && /not supported when using codex with a chatgpt account/i.test(error2.body))
46347
+ return {
46348
+ kind: "fail",
46349
+ error: new Error(
46350
+ `model_unavailable: ${msg().auth.request.modelUnavailable(`${provider}/${model.id}`)}`
46351
+ )
46352
+ };
45569
46353
  if (backend === "codex" && error2.status === 400 && /instructions are not valid/i.test(error2.body) && !tried.has("instructions")) {
45570
46354
  tried.add("instructions");
45571
46355
  developerMode.add(sessionKeyOf(model, options));
@@ -46233,6 +47017,10 @@ var init_sse = __esm({
46233
47017
  });
46234
47018
 
46235
47019
  // src/ai/apis/max-tokens.ts
47020
+ function onMaxTokensCap(listener) {
47021
+ capListeners.add(listener);
47022
+ return () => capListeners.delete(listener);
47023
+ }
46236
47024
  function clampMaxTokens(requested, window2, estimatedInput, fixed) {
46237
47025
  if (fixed || window2 === void 0 || !Number.isFinite(window2) || window2 <= 0) return requested;
46238
47026
  const room = Math.floor(window2 - estimatedInput - OUTPUT_HEADROOM_TOKENS);
@@ -46293,14 +47081,17 @@ async function postWithMaxTokensFallback(model, url, options, field2) {
46293
47081
  const sent = body[field2];
46294
47082
  if (rejection === void 0 || !("cap" in rejection) || typeof sent !== "number") throw error2;
46295
47083
  if (rejection.cap >= sent || !budgetFits(body, rejection.cap)) throw error2;
46296
- if (!rejection.transient) maxTokensCaps.set(key, rejection.cap);
47084
+ if (!rejection.transient) {
47085
+ maxTokensCaps.set(key, rejection.cap);
47086
+ for (const listener of capListeners) listener(key, rejection.cap);
47087
+ }
46297
47088
  return postWithCacheFallback(model, url, {
46298
47089
  ...options,
46299
47090
  body: withCap(body, field2, rejection.cap)
46300
47091
  });
46301
47092
  }
46302
47093
  }
46303
- var MIN_OUTPUT_TOKENS, OUTPUT_HEADROOM_TOKENS, maxTokensCaps, NUM, toInt, RANGE, LIMIT, CONTEXT_LIMIT;
47094
+ var MIN_OUTPUT_TOKENS, OUTPUT_HEADROOM_TOKENS, maxTokensCaps, capListeners, NUM, toInt, RANGE, LIMIT, CONTEXT_LIMIT;
46304
47095
  var init_max_tokens = __esm({
46305
47096
  "src/ai/apis/max-tokens.ts"() {
46306
47097
  "use strict";
@@ -46309,6 +47100,7 @@ var init_max_tokens = __esm({
46309
47100
  MIN_OUTPUT_TOKENS = 1024;
46310
47101
  OUTPUT_HEADROOM_TOKENS = 2048;
46311
47102
  maxTokensCaps = /* @__PURE__ */ new Map();
47103
+ capListeners = /* @__PURE__ */ new Set();
46312
47104
  NUM = "`?(\\d[\\d,_]*)`?";
46313
47105
  toInt = (text) => Number((text ?? "").replace(/[,_]/g, ""));
46314
47106
  RANGE = new RegExp(
@@ -47388,14 +48180,14 @@ var init_api = __esm({
47388
48180
  // src/ai/providers/auth.ts
47389
48181
  function defaultConfigDir(env = process.env) {
47390
48182
  if (env["AMA_CONFIG_DIR"]) return env["AMA_CONFIG_DIR"];
47391
- if (process.platform === "win32" && env["APPDATA"]) return (0, import_node_path73.join)(env["APPDATA"], "ama");
47392
- if (env["XDG_CONFIG_HOME"]) return (0, import_node_path73.join)(env["XDG_CONFIG_HOME"], "ama");
47393
- return (0, import_node_path73.join)(env["HOME"] ?? (0, import_node_os11.homedir)(), ".config", "ama");
48183
+ if (process.platform === "win32" && env["APPDATA"]) return (0, import_node_path75.join)(env["APPDATA"], "ama");
48184
+ if (env["XDG_CONFIG_HOME"]) return (0, import_node_path75.join)(env["XDG_CONFIG_HOME"], "ama");
48185
+ return (0, import_node_path75.join)(env["HOME"] ?? (0, import_node_os12.homedir)(), ".config", "ama");
47394
48186
  }
47395
48187
  function readAuthFile2(path, onWarning) {
47396
48188
  let raw;
47397
48189
  try {
47398
- raw = (0, import_node_fs52.readFileSync)(path, "utf8");
48190
+ raw = (0, import_node_fs53.readFileSync)(path, "utf8");
47399
48191
  } catch (error2) {
47400
48192
  const code = error2.code;
47401
48193
  if (code !== "ENOENT") onWarning?.(`cannot read auth file ${path}`);
@@ -47403,7 +48195,7 @@ function readAuthFile2(path, onWarning) {
47403
48195
  }
47404
48196
  if (process.platform !== "win32") {
47405
48197
  try {
47406
- const mode = (0, import_node_fs52.statSync)(path).mode & 511;
48198
+ const mode = (0, import_node_fs53.statSync)(path).mode & 511;
47407
48199
  if ((mode & 63) !== 0) {
47408
48200
  onWarning?.(
47409
48201
  `auth file ${path} has permissions ${mode.toString(8).padStart(4, "0")}; expected 0600`
@@ -47437,14 +48229,14 @@ function expandEnvRefs(value, env) {
47437
48229
  );
47438
48230
  return missing || out.length === 0 ? void 0 : out;
47439
48231
  }
47440
- var import_node_child_process13, import_node_fs52, import_node_os11, import_node_path73, ApiKeyResolver;
48232
+ var import_node_child_process13, import_node_fs53, import_node_os12, import_node_path75, ApiKeyResolver;
47441
48233
  var init_auth2 = __esm({
47442
48234
  "src/ai/providers/auth.ts"() {
47443
48235
  "use strict";
47444
48236
  import_node_child_process13 = require("node:child_process");
47445
- import_node_fs52 = require("node:fs");
47446
- import_node_os11 = require("node:os");
47447
- import_node_path73 = require("node:path");
48237
+ import_node_fs53 = require("node:fs");
48238
+ import_node_os12 = require("node:os");
48239
+ import_node_path75 = require("node:path");
47448
48240
  init_live();
47449
48241
  init_refresh();
47450
48242
  init_token_store();
@@ -47464,7 +48256,7 @@ var init_auth2 = __esm({
47464
48256
  authFiles() {
47465
48257
  const files = [];
47466
48258
  if (this.options.authFile) files.push(this.options.authFile);
47467
- const user = this.options.userAuthFile === void 0 ? (0, import_node_path73.join)(defaultConfigDir(this.env), "auth.json") : this.options.userAuthFile;
48259
+ const user = this.options.userAuthFile === void 0 ? (0, import_node_path75.join)(defaultConfigDir(this.env), "auth.json") : this.options.userAuthFile;
47468
48260
  if (user && !files.includes(user)) files.push(user);
47469
48261
  return files;
47470
48262
  }
@@ -47852,9 +48644,8 @@ var init_registry2 = __esm({
47852
48644
  (name) => this.warn(`model "${id}/${modelId}" channel "${name}" not found; ignored`)
47853
48645
  );
47854
48646
  for (const entry of config.models ?? []) {
47855
- const { entry: filled, metadata } = enrichEntry(entry, this.modelsDev);
47856
- if (typeof entry.modelsDev === "string" && metadata.looked && metadata.match === void 0)
47857
- this.warn(`modelsDev "${entry.modelsDev}" for "${id}/${entry.id}" not found`);
48647
+ const { entry: filled, metadata } = enrichEntry(entry, this.modelsDev, id);
48648
+ for (const warning of metadata.warnings ?? []) this.warn(warning);
47858
48649
  const model = withCustomDefaults(filled, id, entry.api ?? provider.api);
47859
48650
  if (provider.channels !== void 0 && (entry.channels !== void 0 || !provider.builtin))
47860
48651
  model.channels = channelsOf(entry.channels, entry.id);
@@ -48207,6 +48998,7 @@ var init_settings_registry = __esm({
48207
48998
  row2("subagents.maxConcurrent", "agents", "nextSession", "deny"),
48208
48999
  row2("subagents.maxPending", "agents", "nextSession", "deny"),
48209
49000
  row2("subagents.retainSessions", "agents", "nextSession", "deny"),
49001
+ row2("subagents.forkMaxContextRatio", "agents", "nextSession", "deny"),
48210
49002
  // [W7-B2] 改 task 工具描述(缺省后台 / 前台两种文案),故 prefix
48211
49003
  row2("subagents.background", "agents", "restart", "any", { prefix: true }),
48212
49004
  row2("subagents.autoBackgroundAfterMs", "agents", "restart", "any"),
@@ -48230,26 +49022,26 @@ var init_settings_registry = __esm({
48230
49022
 
48231
49023
  // src/config/write.ts
48232
49024
  function writeConfigFile(path, config, options = {}) {
48233
- (0, import_node_fs53.mkdirSync)((0, import_node_path75.dirname)(path), { recursive: true });
49025
+ (0, import_node_fs54.mkdirSync)((0, import_node_path77.dirname)(path), { recursive: true });
48234
49026
  let mode;
48235
49027
  try {
48236
- mode = (0, import_node_fs53.statSync)(path).mode & 511;
49028
+ mode = (0, import_node_fs54.statSync)(path).mode & 511;
48237
49029
  } catch {
48238
49030
  mode = void 0;
48239
49031
  }
48240
- if (mode !== void 0 && options.backup !== false) (0, import_node_fs53.copyFileSync)(path, `${path}.bak`);
49032
+ if (mode !== void 0 && options.backup !== false) (0, import_node_fs54.copyFileSync)(path, `${path}.bak`);
48241
49033
  const tmp = `${path}.${process.pid}.tmp`;
48242
- (0, import_node_fs53.writeFileSync)(tmp, `${JSON.stringify(config, null, 2)}
49034
+ (0, import_node_fs54.writeFileSync)(tmp, `${JSON.stringify(config, null, 2)}
48243
49035
  `, { mode: mode ?? 420 });
48244
- if (mode !== void 0) (0, import_node_fs53.chmodSync)(tmp, mode);
48245
- (0, import_node_fs53.renameSync)(tmp, path);
49036
+ if (mode !== void 0) (0, import_node_fs54.chmodSync)(tmp, mode);
49037
+ (0, import_node_fs54.renameSync)(tmp, path);
48246
49038
  }
48247
- var import_node_fs53, import_node_path75;
49039
+ var import_node_fs54, import_node_path77;
48248
49040
  var init_write2 = __esm({
48249
49041
  "src/config/write.ts"() {
48250
49042
  "use strict";
48251
- import_node_fs53 = require("node:fs");
48252
- import_node_path75 = require("node:path");
49043
+ import_node_fs54 = require("node:fs");
49044
+ import_node_path77 = require("node:path");
48253
49045
  }
48254
49046
  });
48255
49047
 
@@ -48447,7 +49239,7 @@ function parseEnum(key, text, options) {
48447
49239
  function readTarget(path, scope) {
48448
49240
  let text;
48449
49241
  try {
48450
- text = (0, import_node_fs54.readFileSync)(path, "utf8");
49242
+ text = (0, import_node_fs55.readFileSync)(path, "utf8");
48451
49243
  } catch (error2) {
48452
49244
  if (error2.code === "ENOENT")
48453
49245
  return scope === "user" ? minimalConfig() : { version: CONFIG_FILE_VERSION };
@@ -48529,11 +49321,11 @@ function formatSettingValue(value) {
48529
49321
  if (typeof value === "string") return value;
48530
49322
  return JSON.stringify(value);
48531
49323
  }
48532
- var import_node_fs54, ConfigEditError, same, ABOVE, TRUE, FALSE, UNSET;
49324
+ var import_node_fs55, ConfigEditError, same, ABOVE, TRUE, FALSE, UNSET;
48533
49325
  var init_edit2 = __esm({
48534
49326
  "src/config/edit.ts"() {
48535
49327
  "use strict";
48536
- import_node_fs54 = require("node:fs");
49328
+ import_node_fs55 = require("node:fs");
48537
49329
  init_errors();
48538
49330
  init_i18n();
48539
49331
  init_init();
@@ -48609,11 +49401,11 @@ async function readClipboardImage(dataDir, deps = {}) {
48609
49401
  const platform = deps.platform ?? process.platform;
48610
49402
  const env = deps.env ?? process.env;
48611
49403
  const run7 = deps.run ?? runCommand;
48612
- const dir = (0, import_node_path78.join)(dataDir, CLIPBOARD_DIR);
49404
+ const dir = (0, import_node_path80.join)(dataDir, CLIPBOARD_DIR);
48613
49405
  await (0, import_promises22.mkdir)(dir, { recursive: true });
48614
49406
  const stamp = new Date((deps.now ?? Date.now)()).toISOString().replace(/[:.]/g, "-");
48615
- let file = (0, import_node_path78.join)(dir, `${stamp}.png`);
48616
- for (let n = 1; (0, import_node_fs60.existsSync)(file); n++) file = (0, import_node_path78.join)(dir, `${stamp}-${n}.png`);
49407
+ let file = (0, import_node_path80.join)(dir, `${stamp}.png`);
49408
+ for (let n = 1; (0, import_node_fs61.existsSync)(file); n++) file = (0, import_node_path80.join)(dir, `${stamp}-${n}.png`);
48617
49409
  let anyTool = false;
48618
49410
  for (const attempt of attempts(platform, file, env)) {
48619
49411
  const options = attempt.via === "file" && attempt.env !== void 0 ? { env: attempt.env } : {};
@@ -48632,7 +49424,7 @@ async function readClipboardImage(dataDir, deps = {}) {
48632
49424
  return { ok: false, reason: anyTool ? "no_image" : "no_tool" };
48633
49425
  }
48634
49426
  async function gcClipboardImages(dataDir, options = {}) {
48635
- const dir = (0, import_node_path78.join)(dataDir, CLIPBOARD_DIR);
49427
+ const dir = (0, import_node_path80.join)(dataDir, CLIPBOARD_DIR);
48636
49428
  let names;
48637
49429
  try {
48638
49430
  names = await (0, import_promises22.readdir)(dir);
@@ -48642,7 +49434,7 @@ async function gcClipboardImages(dataDir, options = {}) {
48642
49434
  const cutoff = (options.now ?? Date.now()) - (options.maxAgeDays ?? CLIPBOARD_MAX_AGE_DAYS) * 864e5;
48643
49435
  const removed = [];
48644
49436
  for (const name of names) {
48645
- const file = (0, import_node_path78.join)(dir, name);
49437
+ const file = (0, import_node_path80.join)(dir, name);
48646
49438
  try {
48647
49439
  const info2 = await (0, import_promises22.stat)(file);
48648
49440
  if (!info2.isFile() || info2.mtimeMs >= cutoff) continue;
@@ -48653,13 +49445,13 @@ async function gcClipboardImages(dataDir, options = {}) {
48653
49445
  }
48654
49446
  return removed;
48655
49447
  }
48656
- var import_node_fs60, import_promises22, import_node_path78, CLIPBOARD_DIR, CLIPBOARD_MAX_AGE_DAYS, OSASCRIPT, POWERSHELL;
49448
+ var import_node_fs61, import_promises22, import_node_path80, CLIPBOARD_DIR, CLIPBOARD_MAX_AGE_DAYS, OSASCRIPT, POWERSHELL;
48657
49449
  var init_clipboard_image = __esm({
48658
49450
  "src/tools/clipboard-image.ts"() {
48659
49451
  "use strict";
48660
- import_node_fs60 = require("node:fs");
49452
+ import_node_fs61 = require("node:fs");
48661
49453
  import_promises22 = require("node:fs/promises");
48662
- import_node_path78 = require("node:path");
49454
+ import_node_path80 = require("node:path");
48663
49455
  init_image_file();
48664
49456
  init_image_resize();
48665
49457
  CLIPBOARD_DIR = "clipboard";
@@ -50046,7 +50838,7 @@ function statusCost(stats) {
50046
50838
  function layoutRow(parts, width2, theme, style = {}) {
50047
50839
  const sep5 = style.sep ?? " · ";
50048
50840
  const dim = (text) => text === "" ? "" : theme.fg("dim", text);
50049
- const join66 = (list5) => {
50841
+ const join68 = (list5) => {
50050
50842
  let out = "";
50051
50843
  let size = 0;
50052
50844
  const add3 = (text, measured = visibleWidth(text)) => {
@@ -50078,7 +50870,7 @@ function layoutRow(parts, width2, theme, style = {}) {
50078
50870
  const left = zone("left");
50079
50871
  const right = zone("right");
50080
50872
  const between = left.length === 0 || right.length === 0 ? 0 : sep5.length;
50081
- return join66(left)[1] + between + join66(right)[1] <= width2;
50873
+ return join68(left)[1] + between + join68(right)[1] <= width2;
50082
50874
  };
50083
50875
  while (!fits()) {
50084
50876
  const droppable = kept.filter((p) => p.priority !== void 0);
@@ -50086,8 +50878,8 @@ function layoutRow(parts, width2, theme, style = {}) {
50086
50878
  const drop = droppable.reduce((worst, p) => p.priority > worst.priority ? p : worst);
50087
50879
  kept = kept.filter((p) => p !== drop);
50088
50880
  }
50089
- const l = join66(zone("left"))[0];
50090
- const r = join66(zone("right"))[0];
50881
+ const l = join68(zone("left"))[0];
50882
+ const r = join68(zone("right"))[0];
50091
50883
  const gap = width2 - visibleWidth(l) - visibleWidth(r);
50092
50884
  const line2 = r === "" ? l : l === "" ? " ".repeat(Math.max(0, gap)) + r : gap >= MIN_GAP ? l + " ".repeat(gap) + r : l + dim(sep5) + r;
50093
50885
  return truncateToWidth(line2, width2);
@@ -50346,9 +51138,9 @@ function flat(text, max = 120) {
50346
51138
  return one.length > max ? `${one.slice(0, max - 1)}…` : one;
50347
51139
  }
50348
51140
  function displayPath2(path, cwd) {
50349
- if (cwd === void 0 || !(0, import_node_path83.isAbsolute)(path)) return path;
50350
- const rel = (0, import_node_path83.relative)(cwd, path);
50351
- return rel === "" ? "." : rel.startsWith("..") || (0, import_node_path83.isAbsolute)(rel) ? path : rel;
51141
+ if (cwd === void 0 || !(0, import_node_path85.isAbsolute)(path)) return path;
51142
+ const rel = (0, import_node_path85.relative)(cwd, path);
51143
+ return rel === "" ? "." : rel.startsWith("..") || (0, import_node_path85.isAbsolute)(rel) ? path : rel;
50352
51144
  }
50353
51145
  function toolSummary(name, args, cwd) {
50354
51146
  if (typeof args !== "object" || args === null) return "";
@@ -50503,12 +51295,12 @@ function resultSummary(input2, theme) {
50503
51295
  return muted(count2 === 0 ? m.done : m.outputLines(count2));
50504
51296
  }
50505
51297
  }
50506
- var import_node_path83;
51298
+ var import_node_path85;
50507
51299
  var init_tool_summary = __esm({
50508
51300
  "src/modes/interactive/tool-summary.ts"() {
50509
51301
  "use strict";
50510
51302
  init_i18n();
50511
- import_node_path83 = require("node:path");
51303
+ import_node_path85 = require("node:path");
50512
51304
  init_tui2();
50513
51305
  init_status_bar();
50514
51306
  }
@@ -51325,7 +52117,7 @@ function childLoader(read2 = readTraceInput) {
51325
52117
  const load2 = ((file) => {
51326
52118
  let stamp = "";
51327
52119
  try {
51328
- const st = (0, import_node_fs63.statSync)(file);
52120
+ const st = (0, import_node_fs64.statSync)(file);
51329
52121
  stamp = `${st.mtimeMs}:${st.size}`;
51330
52122
  } catch {
51331
52123
  stamp = "missing";
@@ -51369,11 +52161,11 @@ function traceText(session, taskId) {
51369
52161
  `${msg().trace.taskTitle(node.taskId, node.agent)}${summary2}`
51370
52162
  );
51371
52163
  }
51372
- var import_node_fs63, LiveTracker, lineTraceCommand;
52164
+ var import_node_fs64, LiveTracker, lineTraceCommand;
51373
52165
  var init_session3 = __esm({
51374
52166
  "src/trace/session.ts"() {
51375
52167
  "use strict";
51376
- import_node_fs63 = require("node:fs");
52168
+ import_node_fs64 = require("node:fs");
51377
52169
  init_session2();
51378
52170
  init_i18n();
51379
52171
  init_scan();
@@ -51447,10 +52239,10 @@ var init_session3 = __esm({
51447
52239
 
51448
52240
  // src/skills/builtin.ts
51449
52241
  function builtinSkillPath(dataDir, name) {
51450
- return (0, import_node_path86.join)(dataDir, BUILTIN_SKILLS_DIR, `${name}.md`);
52242
+ return (0, import_node_path88.join)(dataDir, BUILTIN_SKILLS_DIR, `${name}.md`);
51451
52243
  }
51452
52244
  function isBuiltinSkill(skill) {
51453
- return BUILTIN_SKILLS.some((b) => b.name === skill.name) && skill.location.endsWith((0, import_node_path86.join)(BUILTIN_SKILLS_DIR, `${skill.name}.md`));
52245
+ return BUILTIN_SKILLS.some((b) => b.name === skill.name) && skill.location.endsWith((0, import_node_path88.join)(BUILTIN_SKILLS_DIR, `${skill.name}.md`));
51454
52246
  }
51455
52247
  function builtinSkillText(skill) {
51456
52248
  return `---
@@ -51465,7 +52257,7 @@ async function ensureFile(path, text) {
51465
52257
  if (await (0, import_promises23.readFile)(path, "utf8") === text) return;
51466
52258
  } catch {
51467
52259
  }
51468
- await (0, import_promises23.mkdir)((0, import_node_path86.dirname)(path), { recursive: true });
52260
+ await (0, import_promises23.mkdir)((0, import_node_path88.dirname)(path), { recursive: true });
51469
52261
  await (0, import_promises23.writeFile)(path, text, "utf8");
51470
52262
  }
51471
52263
  async function withBuiltinSkills(skills, dataDir, builtins = BUILTIN_SKILLS) {
@@ -51474,7 +52266,7 @@ async function withBuiltinSkills(skills, dataDir, builtins = BUILTIN_SKILLS) {
51474
52266
  const taken = new Set(skills.map((skill) => skill.name));
51475
52267
  for (const builtin2 of builtins) {
51476
52268
  if (taken.has(builtin2.name)) continue;
51477
- const baseDir = (0, import_node_path86.join)(dataDir, BUILTIN_SKILLS_DIR);
52269
+ const baseDir = (0, import_node_path88.join)(dataDir, BUILTIN_SKILLS_DIR);
51478
52270
  const location = builtinSkillPath(dataDir, builtin2.name);
51479
52271
  try {
51480
52272
  await ensureFile(location, builtinSkillText(builtin2));
@@ -51495,12 +52287,12 @@ async function withBuiltinSkills(skills, dataDir, builtins = BUILTIN_SKILLS) {
51495
52287
  }
51496
52288
  return { skills: out, warnings };
51497
52289
  }
51498
- var import_promises23, import_node_path86, BUILTIN_SKILLS_DIR, AMA_DOCS_BODY, BUILTIN_SKILLS;
52290
+ var import_promises23, import_node_path88, BUILTIN_SKILLS_DIR, AMA_DOCS_BODY, BUILTIN_SKILLS;
51499
52291
  var init_builtin3 = __esm({
51500
52292
  "src/skills/builtin.ts"() {
51501
52293
  "use strict";
51502
52294
  import_promises23 = require("node:fs/promises");
51503
- import_node_path86 = require("node:path");
52295
+ import_node_path88 = require("node:path");
51504
52296
  BUILTIN_SKILLS_DIR = "builtin";
51505
52297
  AMA_DOCS_BODY = `# ama quick reference
51506
52298
 
@@ -51553,33 +52345,33 @@ Skills: \`<dir>/<name>/SKILL.md\` with \`name\` and \`description\` frontmatter
51553
52345
  // src/skills/discover.ts
51554
52346
  function ancestorDirs(cwd) {
51555
52347
  const out = [];
51556
- let dir = (0, import_node_path87.resolve)(cwd);
52348
+ let dir = (0, import_node_path89.resolve)(cwd);
51557
52349
  for (; ; ) {
51558
52350
  out.push(dir);
51559
- if ((0, import_node_fs65.existsSync)((0, import_node_path87.join)(dir, ".git"))) return out;
51560
- const parent = (0, import_node_path87.dirname)(dir);
52351
+ if ((0, import_node_fs66.existsSync)((0, import_node_path89.join)(dir, ".git"))) return out;
52352
+ const parent = (0, import_node_path89.dirname)(dir);
51561
52353
  if (parent === dir) return out;
51562
52354
  dir = parent;
51563
52355
  }
51564
52356
  }
51565
52357
  function skillSources(options) {
51566
52358
  const sources = [];
51567
- const add3 = (dir, scope, requiresTrust) => sources.push({ dir: (0, import_node_path87.resolve)(options.cwd, dir), scope, requiresTrust });
52359
+ const add3 = (dir, scope, requiresTrust) => sources.push({ dir: (0, import_node_path89.resolve)(options.cwd, dir), scope, requiresTrust });
51568
52360
  for (const d of options.cliDirs ?? []) add3(d, "cli", false);
51569
52361
  for (const d of options.profileDirs ?? []) add3(d, "profile", false);
51570
52362
  for (const d of options.configDirs ?? []) add3(d, "config", false);
51571
- add3((0, import_node_path87.join)(options.configDir, "skills"), "user", false);
51572
- add3((0, import_node_path87.join)(options.cwd, ".ama", "skills"), "project", true);
51573
- for (const d of ancestorDirs(options.cwd)) add3((0, import_node_path87.join)(d, ".agents", "skills"), "ancestor", true);
52363
+ add3((0, import_node_path89.join)(options.configDir, "skills"), "user", false);
52364
+ add3((0, import_node_path89.join)(options.cwd, ".ama", "skills"), "project", true);
52365
+ for (const d of ancestorDirs(options.cwd)) add3((0, import_node_path89.join)(d, ".agents", "skills"), "ancestor", true);
51574
52366
  return sources;
51575
52367
  }
51576
52368
  function parseSkill(text, location, scope) {
51577
52369
  const warnings = [];
51578
52370
  const fm = parseFrontmatter(text);
51579
52371
  for (const e of fm.errors) warnings.push(`${location}: ${e}`);
51580
- const baseDir = (0, import_node_path87.dirname)(location);
52372
+ const baseDir = (0, import_node_path89.dirname)(location);
51581
52373
  const rawName = fm.data["name"];
51582
- const name = typeof rawName === "string" && rawName !== "" ? rawName : (0, import_node_path87.basename)(baseDir);
52374
+ const name = typeof rawName === "string" && rawName !== "" ? rawName : (0, import_node_path89.basename)(baseDir);
51583
52375
  if (name.length > MAX_SKILL_NAME || !SKILL_NAME_RE.test(name)) {
51584
52376
  warnings.push(`${location}: invalid skill name "${name}" (lowercase letters, digits, -)`);
51585
52377
  return { warnings };
@@ -51617,8 +52409,8 @@ async function isDir3(path) {
51617
52409
  }
51618
52410
  async function findSkillFiles(dir, depth = 0) {
51619
52411
  if (depth > MAX_DEPTH3) return [];
51620
- const own = (0, import_node_path87.join)(dir, SKILL_FILE);
51621
- if ((0, import_node_fs65.existsSync)(own)) return [own];
52412
+ const own = (0, import_node_path89.join)(dir, SKILL_FILE);
52413
+ if ((0, import_node_fs66.existsSync)(own)) return [own];
51622
52414
  let names;
51623
52415
  try {
51624
52416
  names = await (0, import_promises24.readdir)(dir);
@@ -51629,7 +52421,7 @@ async function findSkillFiles(dir, depth = 0) {
51629
52421
  const out = [];
51630
52422
  for (const name of names) {
51631
52423
  if (SKIP_DIRS.has(name)) continue;
51632
- const child = (0, import_node_path87.join)(dir, name);
52424
+ const child = (0, import_node_path89.join)(dir, name);
51633
52425
  if (await isDir3(child)) out.push(...await findSkillFiles(child, depth + 1));
51634
52426
  }
51635
52427
  return out;
@@ -51670,13 +52462,13 @@ async function discoverSkills(sources, options) {
51670
52462
  }
51671
52463
  return result;
51672
52464
  }
51673
- var import_node_fs65, import_promises24, import_node_path87, SKILL_FILE, SKILL_NAME_RE, MAX_SKILL_NAME, MAX_SKILL_DESCRIPTION, MAX_DEPTH3, SKIP_DIRS;
52465
+ var import_node_fs66, import_promises24, import_node_path89, SKILL_FILE, SKILL_NAME_RE, MAX_SKILL_NAME, MAX_SKILL_DESCRIPTION, MAX_DEPTH3, SKIP_DIRS;
51674
52466
  var init_discover2 = __esm({
51675
52467
  "src/skills/discover.ts"() {
51676
52468
  "use strict";
51677
- import_node_fs65 = require("node:fs");
52469
+ import_node_fs66 = require("node:fs");
51678
52470
  import_promises24 = require("node:fs/promises");
51679
- import_node_path87 = require("node:path");
52471
+ import_node_path89 = require("node:path");
51680
52472
  init_frontmatter2();
51681
52473
  SKILL_FILE = "SKILL.md";
51682
52474
  SKILL_NAME_RE = /^[a-z0-9-]+$/;
@@ -51791,14 +52583,14 @@ var init_protocol2 = __esm({
51791
52583
 
51792
52584
  // src/codemode/host-side.ts
51793
52585
  function resolveSandboxEntry(moduleUrl = __ama_import_meta_url) {
51794
- const here = (0, import_node_path88.dirname)((0, import_node_url2.fileURLToPath)(moduleUrl));
52586
+ const here = (0, import_node_path90.dirname)((0, import_node_url2.fileURLToPath)(moduleUrl));
51795
52587
  const candidates2 = [];
51796
52588
  if (true)
51797
- candidates2.push((0, import_node_path88.join)(here, "ama-sandbox.cjs"));
51798
- candidates2.push((0, import_node_path88.join)(here, "sandbox-entry.js"));
51799
- candidates2.push((0, import_node_path88.join)(here, "sandbox-entry.ts"));
52589
+ candidates2.push((0, import_node_path90.join)(here, "ama-sandbox.cjs"));
52590
+ candidates2.push((0, import_node_path90.join)(here, "sandbox-entry.js"));
52591
+ candidates2.push((0, import_node_path90.join)(here, "sandbox-entry.ts"));
51800
52592
  for (const candidate of candidates2) {
51801
- if ((0, import_node_fs66.existsSync)(candidate)) return (0, import_node_fs66.realpathSync)(candidate);
52593
+ if ((0, import_node_fs67.existsSync)(candidate)) return (0, import_node_fs67.realpathSync)(candidate);
51802
52594
  }
51803
52595
  return void 0;
51804
52596
  }
@@ -52030,13 +52822,13 @@ async function runSandbox(request) {
52030
52822
  child.stdin.end();
52031
52823
  return result;
52032
52824
  }
52033
- var import_node_child_process16, import_node_fs66, import_node_path88, import_node_url2, MAX_COLLECTED_OUTPUT_CHARS, ABORT_GRACE_MS, DEFAULT_CODEMODE_HEAP_MB, CODEMODE_OS_POLICY;
52825
+ var import_node_child_process16, import_node_fs67, import_node_path90, import_node_url2, MAX_COLLECTED_OUTPUT_CHARS, ABORT_GRACE_MS, DEFAULT_CODEMODE_HEAP_MB, CODEMODE_OS_POLICY;
52034
52826
  var init_host_side = __esm({
52035
52827
  "src/codemode/host-side.ts"() {
52036
52828
  "use strict";
52037
52829
  import_node_child_process16 = require("node:child_process");
52038
- import_node_fs66 = require("node:fs");
52039
- import_node_path88 = require("node:path");
52830
+ import_node_fs67 = require("node:fs");
52831
+ import_node_path90 = require("node:path");
52040
52832
  import_node_url2 = require("node:url");
52041
52833
  init_detect();
52042
52834
  init_wrap();
@@ -52098,7 +52890,7 @@ var init_store5 = __esm({
52098
52890
  });
52099
52891
 
52100
52892
  // src/codemode/tool.ts
52101
- function textOf4(content) {
52893
+ function textOf5(content) {
52102
52894
  if (typeof content === "string") return content;
52103
52895
  return content.map((block) => block.type === "text" ? block.text : "").join("");
52104
52896
  }
@@ -52117,8 +52909,8 @@ function toScriptValue(name, result) {
52117
52909
  if (s2.full_output_path !== void 0) value.fullOutputPath = s2.full_output_path;
52118
52910
  return value;
52119
52911
  }
52120
- if (result.isError === true) throw new Error(textOf4(result.content) || `Tool ${name} failed`);
52121
- return result.structured !== void 0 ? result.structured : textOf4(result.content);
52912
+ if (result.isError === true) throw new Error(textOf5(result.content) || `Tool ${name} failed`);
52913
+ return result.structured !== void 0 ? result.structured : textOf5(result.content);
52122
52914
  }
52123
52915
  function scriptErrorHint(error2, toolNames2) {
52124
52916
  if (/Cannot use import statement|dynamic import callback/.test(error2) || SCRIPT_ONLY_GLOBALS.test(error2)) {
@@ -52200,10 +52992,10 @@ ${output.slice(-half)}`;
52200
52992
  }
52201
52993
  function saveFullOutput(ctx, text) {
52202
52994
  try {
52203
- const dir = ctx.outputDir ?? (0, import_node_path89.join)((0, import_node_os13.tmpdir)(), "ama-codemode");
52204
- (0, import_node_fs67.mkdirSync)(dir, { recursive: true });
52205
- const file = (0, import_node_path89.join)(dir, `${ctx.toolCallId.replace(/[^A-Za-z0-9_-]/g, "_")}.txt`);
52206
- (0, import_node_fs67.writeFileSync)(file, text, "utf8");
52995
+ const dir = ctx.outputDir ?? (0, import_node_path91.join)((0, import_node_os14.tmpdir)(), "ama-codemode");
52996
+ (0, import_node_fs68.mkdirSync)(dir, { recursive: true });
52997
+ const file = (0, import_node_path91.join)(dir, `${ctx.toolCallId.replace(/[^A-Za-z0-9_-]/g, "_")}.txt`);
52998
+ (0, import_node_fs68.writeFileSync)(file, text, "utf8");
52207
52999
  return file;
52208
53000
  } catch {
52209
53001
  return void 0;
@@ -52309,7 +53101,7 @@ function createCodemodeTool(options) {
52309
53101
  return shown2;
52310
53102
  },
52311
53103
  renderResult(result, width2, expanded) {
52312
- const lines2 = textOf4(result.content).split("\n");
53104
+ const lines2 = textOf5(result.content).split("\n");
52313
53105
  const clip4 = (line2) => line2.slice(0, Math.max(10, width2));
52314
53106
  if (expanded || lines2.length <= 8) return lines2.map(clip4);
52315
53107
  return [clip4(lines2[0] ?? ""), `… ${lines2.length - 6} lines`, ...lines2.slice(-5).map(clip4)];
@@ -52355,13 +53147,13 @@ function codemodeToolFactory(overrides = {}) {
52355
53147
  return createCodemodeTool(options);
52356
53148
  };
52357
53149
  }
52358
- var import_node_fs67, import_node_os13, import_node_path89, CODEMODE_TOOL_NAME2, DEFAULT_MAX_TOOL_RESULT_CHARS2, CODEMODE_EXAMPLE, SCRIPT_ONLY_GLOBALS, TAIL_CHARS, CODEMODE_ONLY_GUIDELINE;
53150
+ var import_node_fs68, import_node_os14, import_node_path91, CODEMODE_TOOL_NAME2, DEFAULT_MAX_TOOL_RESULT_CHARS2, CODEMODE_EXAMPLE, SCRIPT_ONLY_GLOBALS, TAIL_CHARS, CODEMODE_ONLY_GUIDELINE;
52359
53151
  var init_tool = __esm({
52360
53152
  "src/codemode/tool.ts"() {
52361
53153
  "use strict";
52362
- import_node_fs67 = require("node:fs");
52363
- import_node_os13 = require("node:os");
52364
- import_node_path89 = require("node:path");
53154
+ import_node_fs68 = require("node:fs");
53155
+ import_node_os14 = require("node:os");
53156
+ import_node_path91 = require("node:path");
52365
53157
  init_presets2();
52366
53158
  init_capability();
52367
53159
  init_declarations();
@@ -52473,7 +53265,7 @@ var init_tool2 = __esm({
52473
53265
  // src/cli/codemode-notice.ts
52474
53266
  function readNotices(path) {
52475
53267
  try {
52476
- const value = JSON.parse((0, import_node_fs68.readFileSync)(path, "utf8"));
53268
+ const value = JSON.parse((0, import_node_fs69.readFileSync)(path, "utf8"));
52477
53269
  if (typeof value === "object" && value !== null && !Array.isArray(value)) {
52478
53270
  const shown2 = value[KEY];
52479
53271
  return {
@@ -52492,26 +53284,26 @@ function takeCodemodeNotice(input2) {
52492
53284
  const resolved = resolveCodemodeMode(input2.config, input2.capability.strict);
52493
53285
  if (resolved.source !== "preset" || resolved.preset !== "default" || input2.capability.strict)
52494
53286
  return void 0;
52495
- const path = (0, import_node_path90.join)(input2.dataDir, NOTICES_FILE);
53287
+ const path = (0, import_node_path92.join)(input2.dataDir, NOTICES_FILE);
52496
53288
  const notices = readNotices(path);
52497
53289
  const shown2 = notices[KEY] ?? [];
52498
53290
  if (shown2.includes(input2.configDir)) return void 0;
52499
53291
  try {
52500
- (0, import_node_fs68.mkdirSync)(input2.dataDir, { recursive: true });
53292
+ (0, import_node_fs69.mkdirSync)(input2.dataDir, { recursive: true });
52501
53293
  const tmp = `${path}.${process.pid}.tmp`;
52502
- (0, import_node_fs68.writeFileSync)(tmp, `${JSON.stringify({ ...notices, [KEY]: [...shown2, input2.configDir] })}
53294
+ (0, import_node_fs69.writeFileSync)(tmp, `${JSON.stringify({ ...notices, [KEY]: [...shown2, input2.configDir] })}
52503
53295
  `);
52504
- (0, import_node_fs68.renameSync)(tmp, path);
53296
+ (0, import_node_fs69.renameSync)(tmp, path);
52505
53297
  } catch {
52506
53298
  }
52507
53299
  return codemodeNoticeText(input2.capability);
52508
53300
  }
52509
- var import_node_fs68, import_node_path90, NOTICES_FILE, KEY;
53301
+ var import_node_fs69, import_node_path92, NOTICES_FILE, KEY;
52510
53302
  var init_codemode_notice = __esm({
52511
53303
  "src/cli/codemode-notice.ts"() {
52512
53304
  "use strict";
52513
- import_node_fs68 = require("node:fs");
52514
- import_node_path90 = require("node:path");
53305
+ import_node_fs69 = require("node:fs");
53306
+ import_node_path92 = require("node:path");
52515
53307
  init_presets2();
52516
53308
  init_i18n();
52517
53309
  NOTICES_FILE = "notices.json";
@@ -52519,6 +53311,81 @@ var init_codemode_notice = __esm({
52519
53311
  }
52520
53312
  });
52521
53313
 
53314
+ // src/ai/providers/max-tokens-cache.ts
53315
+ function maxTokensCachePath(dataDir) {
53316
+ return (0, import_node_path93.join)(dataDir, "models", "max-tokens-caps.json");
53317
+ }
53318
+ function readEntries(dataDir, now) {
53319
+ const out = /* @__PURE__ */ new Map();
53320
+ let parsed;
53321
+ try {
53322
+ parsed = JSON.parse((0, import_node_fs70.readFileSync)(maxTokensCachePath(dataDir), "utf8"));
53323
+ } catch {
53324
+ return out;
53325
+ }
53326
+ if (typeof parsed !== "object" || parsed === null) return out;
53327
+ const file = parsed;
53328
+ if (file.version !== MAX_TOKENS_CACHE_VERSION) return out;
53329
+ if (typeof file.caps !== "object" || file.caps === null) return out;
53330
+ for (const [key, value] of Object.entries(file.caps)) {
53331
+ if (typeof value !== "object" || value === null) continue;
53332
+ const { cap, learnedAt } = value;
53333
+ if (typeof cap !== "number" || !Number.isInteger(cap) || cap < 1) continue;
53334
+ if (typeof learnedAt !== "number" || !Number.isFinite(learnedAt)) continue;
53335
+ if (now - learnedAt > MAX_TOKENS_CACHE_TTL_MS) continue;
53336
+ out.set(key, { cap, learnedAt });
53337
+ }
53338
+ return out;
53339
+ }
53340
+ function loadMaxTokensCaps(dataDir, now = Date.now) {
53341
+ let loaded = 0;
53342
+ for (const [key, entry] of readEntries(dataDir, now())) {
53343
+ if (maxTokensCaps.has(key)) continue;
53344
+ maxTokensCaps.set(key, entry.cap);
53345
+ loaded++;
53346
+ }
53347
+ return loaded;
53348
+ }
53349
+ function recordMaxTokensCap(dataDir, key, cap, now = Date.now) {
53350
+ const at = now();
53351
+ const entries = readEntries(dataDir, at);
53352
+ entries.set(key, { cap, learnedAt: at });
53353
+ const path = maxTokensCachePath(dataDir);
53354
+ const tmp = `${path}.${process.pid}.tmp`;
53355
+ try {
53356
+ (0, import_node_fs70.mkdirSync)((0, import_node_path93.dirname)(path), { recursive: true, mode: 448 });
53357
+ const caps = Object.fromEntries([...entries].sort(([a], [b]) => a < b ? -1 : 1));
53358
+ (0, import_node_fs70.writeFileSync)(tmp, `${JSON.stringify({ version: MAX_TOKENS_CACHE_VERSION, caps }, null, 2)}
53359
+ `);
53360
+ (0, import_node_fs70.renameSync)(tmp, path);
53361
+ } catch {
53362
+ }
53363
+ }
53364
+ function attachMaxTokensCache(dataDir, now = Date.now) {
53365
+ const existing = attached2.get(dataDir);
53366
+ if (existing !== void 0) return existing;
53367
+ loadMaxTokensCaps(dataDir, now);
53368
+ const unsubscribe = onMaxTokensCap((key, cap) => recordMaxTokensCap(dataDir, key, cap, now));
53369
+ const detach = () => {
53370
+ unsubscribe();
53371
+ attached2.delete(dataDir);
53372
+ };
53373
+ attached2.set(dataDir, detach);
53374
+ return detach;
53375
+ }
53376
+ var import_node_fs70, import_node_path93, MAX_TOKENS_CACHE_VERSION, MAX_TOKENS_CACHE_TTL_MS, attached2;
53377
+ var init_max_tokens_cache = __esm({
53378
+ "src/ai/providers/max-tokens-cache.ts"() {
53379
+ "use strict";
53380
+ import_node_fs70 = require("node:fs");
53381
+ import_node_path93 = require("node:path");
53382
+ init_max_tokens();
53383
+ MAX_TOKENS_CACHE_VERSION = 1;
53384
+ MAX_TOKENS_CACHE_TTL_MS = 30 * 24 * 60 * 60 * 1e3;
53385
+ attached2 = /* @__PURE__ */ new Map();
53386
+ }
53387
+ });
53388
+
52522
53389
  // src/cli/compose-providers.ts
52523
53390
  function modelConfigOf(model, providerApi) {
52524
53391
  const { provider: _p, api, ...rest } = model;
@@ -52599,6 +53466,7 @@ async function buildProviderRegistry(input2, options = {}) {
52599
53466
  if (provider !== void 0) registry3 = make({ provider, apiKey: cli.apiKey });
52600
53467
  }
52601
53468
  if (dataDir !== void 0) {
53469
+ attachMaxTokensCache(dataDir);
52602
53470
  const flavor = readOAuthEntry(input2.authFile, CHATGPT_PROVIDER_ID)?.flavor;
52603
53471
  mergeDiscoveredModels(
52604
53472
  registry3,
@@ -52639,6 +53507,7 @@ var init_compose_providers = __esm({
52639
53507
  init_models_dev_cache();
52640
53508
  init_registry2();
52641
53509
  init_discovered_cache();
53510
+ init_max_tokens_cache();
52642
53511
  init_enrich();
52643
53512
  init_token_store();
52644
53513
  init_presets();
@@ -52649,8 +53518,8 @@ var init_compose_providers = __esm({
52649
53518
 
52650
53519
  // src/modes/image-input.ts
52651
53520
  function expand(path, cwd) {
52652
- const home = path === "~" || path.startsWith("~/") ? (0, import_node_os14.homedir)() + path.slice(1) : path;
52653
- return (0, import_node_path91.resolve)(cwd, home);
53521
+ const home = path === "~" || path.startsWith("~/") ? (0, import_node_os15.homedir)() + path.slice(1) : path;
53522
+ return (0, import_node_path94.resolve)(cwd, home);
52654
53523
  }
52655
53524
  function findImageRefs(text, cwd) {
52656
53525
  const out = [];
@@ -52662,7 +53531,7 @@ function findImageRefs(text, cwd) {
52662
53531
  token = token.replace(/\\ /g, " ").replace(/[,\uFF0C\u3002;\uFF1B)\uFF09]+$/, "");
52663
53532
  if (token === "" || imageMimeFromPath(token) === void 0) continue;
52664
53533
  const path = expand(token, cwd);
52665
- if (!explicit && !(0, import_node_fs69.existsSync)(path)) continue;
53534
+ if (!explicit && !(0, import_node_fs71.existsSync)(path)) continue;
52666
53535
  if (seen.has(path)) continue;
52667
53536
  seen.add(path);
52668
53537
  out.push({ path, explicit });
@@ -52721,13 +53590,13 @@ async function loadLocalized(path, options) {
52721
53590
  throw error2;
52722
53591
  }
52723
53592
  }
52724
- var import_node_fs69, import_node_os14, import_node_path91, TOKEN;
53593
+ var import_node_fs71, import_node_os15, import_node_path94, TOKEN;
52725
53594
  var init_image_input = __esm({
52726
53595
  "src/modes/image-input.ts"() {
52727
53596
  "use strict";
52728
- import_node_fs69 = require("node:fs");
52729
- import_node_os14 = require("node:os");
52730
- import_node_path91 = require("node:path");
53597
+ import_node_fs71 = require("node:fs");
53598
+ import_node_os15 = require("node:os");
53599
+ import_node_path94 = require("node:path");
52731
53600
  init_channels();
52732
53601
  init_errors();
52733
53602
  init_image_limits();
@@ -52941,7 +53810,7 @@ async function runPrintMode(runtime, context) {
52941
53810
  denied.push({
52942
53811
  toolCallId: event.toolCallId,
52943
53812
  toolName: event.toolName,
52944
- reason: textOf5(event)
53813
+ reason: textOf6(event)
52945
53814
  });
52946
53815
  const command3 = bashCommands.get(event.toolCallId);
52947
53816
  if (event.toolName === "bash" && command3 !== void 0) deniedBash.push(command3);
@@ -53077,7 +53946,7 @@ function describeLimit(event) {
53077
53946
  const m = msg().print.print;
53078
53947
  return event.kind === "turns" ? m.limitTurns(event.limit) : m.limitCost(formatUsd(event.limit), formatUsd(event.value));
53079
53948
  }
53080
- function textOf5(event) {
53949
+ function textOf6(event) {
53081
53950
  const content = event.result.content;
53082
53951
  const text = typeof content === "string" ? content : content.map((b) => b.type === "text" ? b.text : "").join("");
53083
53952
  return text.split("\n")[0]?.trim().slice(0, 200) ?? "";
@@ -53524,7 +54393,7 @@ function trustChoices() {
53524
54393
  }
53525
54394
  function isDirectory2(path) {
53526
54395
  try {
53527
- return (0, import_node_fs70.statSync)(path).isDirectory();
54396
+ return (0, import_node_fs72.statSync)(path).isDirectory();
53528
54397
  } catch {
53529
54398
  return false;
53530
54399
  }
@@ -53578,8 +54447,8 @@ function createStartupUi(options = {}) {
53578
54447
  placeholder: m.cwdPlaceholder,
53579
54448
  validate: (text) => {
53580
54449
  if (text === "") return m.cwdEmpty;
53581
- const abs = (0, import_node_path92.resolve)(text);
53582
- if (!(0, import_node_fs70.existsSync)(abs)) return m.cwdMissing(abs);
54450
+ const abs = (0, import_node_path95.resolve)(text);
54451
+ if (!(0, import_node_fs72.existsSync)(abs)) return m.cwdMissing(abs);
53583
54452
  if (!isDirectory2(abs)) return m.cwdNotDir(abs);
53584
54453
  return void 0;
53585
54454
  }
@@ -53587,13 +54456,13 @@ function createStartupUi(options = {}) {
53587
54456
  }
53588
54457
  };
53589
54458
  }
53590
- var import_node_fs70, import_node_path92;
54459
+ var import_node_fs72, import_node_path95;
53591
54460
  var init_startup_ui = __esm({
53592
54461
  "src/modes/interactive/startup-ui.ts"() {
53593
54462
  "use strict";
53594
54463
  init_i18n();
53595
- import_node_fs70 = require("node:fs");
53596
- import_node_path92 = require("node:path");
54464
+ import_node_fs72 = require("node:fs");
54465
+ import_node_path95 = require("node:path");
53597
54466
  init_tui2();
53598
54467
  init_model_items();
53599
54468
  init_model_items();
@@ -53731,7 +54600,7 @@ function oneLine7(text, max = 60) {
53731
54600
  const flat2 = text.replace(/\s+/g, " ").trim();
53732
54601
  return flat2.length > max ? `${flat2.slice(0, max - 1)}…` : flat2;
53733
54602
  }
53734
- function taskLine(task, now) {
54603
+ function taskLine2(task, now) {
53735
54604
  const m = msg().panels.tasks;
53736
54605
  const agent = task.runner !== "ama" && task.runner !== task.agent ? m.agentRunner(task.agent, task.runner) : task.agent;
53737
54606
  const parts = [agent, ...taskFacts(task, now)];
@@ -53745,7 +54614,7 @@ function describeTasks(sessionId, now) {
53745
54614
  if (tasks.length === 0) return m.none;
53746
54615
  return [
53747
54616
  m.heading(tasks.length),
53748
- ...tasks.map((task) => ` ${taskLine(task, now)}`),
54617
+ ...tasks.map((task) => ` ${taskLine2(task, now)}`),
53749
54618
  m.footer
53750
54619
  ].join("\n");
53751
54620
  }
@@ -53756,7 +54625,7 @@ function describeTaskOutput(sessionId, taskId, now) {
53756
54625
  const output = taskOutput(sessionId, taskId) ?? "";
53757
54626
  const file = task.outputFile !== void 0 ? `
53758
54627
  ${m.fullOutput(task.outputFile)}` : "";
53759
- return `${taskLine(task, now)}${file}
54628
+ return `${taskLine2(task, now)}${file}
53760
54629
  ${output.trim() === "" ? m.noOutput : output.trimEnd()}`;
53761
54630
  }
53762
54631
  function sourceText3(source) {
@@ -54010,7 +54879,7 @@ function startupInfo(runtime, home) {
54010
54879
  permissionMode: runtime.session.state.permissionMode,
54011
54880
  preset: runtime.config.tools?.preset ?? "default",
54012
54881
  codemode: effectiveCodemodeMode(runtime.config),
54013
- contextFiles: resources.contextFiles.map((f) => (0, import_node_path93.basename)(f.path)),
54882
+ contextFiles: resources.contextFiles.map((f) => (0, import_node_path96.basename)(f.path)),
54014
54883
  skills: resources.skills.filter((s2) => !isBuiltinSkill(s2)).length,
54015
54884
  prompts: resources.prompts.length,
54016
54885
  hooks: runtime.hooks.list().length,
@@ -54019,12 +54888,12 @@ function startupInfo(runtime, home) {
54019
54888
  if (runtime.host !== void 0) info2.host = runtime.host.adapter.id;
54020
54889
  return info2;
54021
54890
  }
54022
- var import_node_path93;
54891
+ var import_node_path96;
54023
54892
  var init_startup_screen = __esm({
54024
54893
  "src/cli/startup-screen.ts"() {
54025
54894
  "use strict";
54026
54895
  init_builtin3();
54027
- import_node_path93 = require("node:path");
54896
+ import_node_path96 = require("node:path");
54028
54897
  init_channels();
54029
54898
  init_presets2();
54030
54899
  init_i18n();
@@ -56767,29 +57636,29 @@ function runEditor(command3, file) {
56767
57636
  return result.status;
56768
57637
  }
56769
57638
  async function editExternally(text, name, deps) {
56770
- const dir = (0, import_node_fs71.mkdtempSync)((0, import_node_path94.join)((0, import_node_os15.tmpdir)(), "ama-edit-"));
56771
- const file = (0, import_node_path94.join)(dir, name);
56772
- (0, import_node_fs71.writeFileSync)(file, text);
57639
+ const dir = (0, import_node_fs73.mkdtempSync)((0, import_node_path97.join)((0, import_node_os16.tmpdir)(), "ama-edit-"));
57640
+ const file = (0, import_node_path97.join)(dir, name);
57641
+ (0, import_node_fs73.writeFileSync)(file, text);
56773
57642
  deps.suspend();
56774
57643
  try {
56775
57644
  const code = (deps.run ?? runEditor)(editorCommand(deps.env, deps.platform), file);
56776
57645
  if (code !== 0) return void 0;
56777
- return (0, import_node_fs71.readFileSync)(file, "utf8");
57646
+ return (0, import_node_fs73.readFileSync)(file, "utf8");
56778
57647
  } catch {
56779
57648
  return void 0;
56780
57649
  } finally {
56781
57650
  deps.resume();
56782
- (0, import_node_fs71.rmSync)(dir, { recursive: true, force: true });
57651
+ (0, import_node_fs73.rmSync)(dir, { recursive: true, force: true });
56783
57652
  }
56784
57653
  }
56785
- var import_node_child_process17, import_node_fs71, import_node_os15, import_node_path94;
57654
+ var import_node_child_process17, import_node_fs73, import_node_os16, import_node_path97;
56786
57655
  var init_external_editor = __esm({
56787
57656
  "src/modes/interactive/external-editor.ts"() {
56788
57657
  "use strict";
56789
57658
  import_node_child_process17 = require("node:child_process");
56790
- import_node_fs71 = require("node:fs");
56791
- import_node_os15 = require("node:os");
56792
- import_node_path94 = require("node:path");
57659
+ import_node_fs73 = require("node:fs");
57660
+ import_node_os16 = require("node:os");
57661
+ import_node_path97 = require("node:path");
56793
57662
  }
56794
57663
  });
56795
57664
 
@@ -59753,7 +60622,7 @@ function agentCommandHooks(get) {
59753
60622
  agentView: (taskId) => get().openView(taskId)
59754
60623
  };
59755
60624
  }
59756
- var TASK_NOTICE, AgentUi;
60625
+ var TASK_NOTICE, SESSION_NOTICE, AgentUi;
59757
60626
  var init_agent_ui = __esm({
59758
60627
  "src/modes/interactive/agent-ui.ts"() {
59759
60628
  "use strict";
@@ -59773,6 +60642,7 @@ var init_agent_ui = __esm({
59773
60642
  init_task_background();
59774
60643
  init_tasks_report();
59775
60644
  TASK_NOTICE = /^\[task (t\d+)\] ([\s\S]*)$/;
60645
+ SESSION_NOTICE = /^cannot read session entry (\S+) back from /;
59776
60646
  AgentUi = class {
59777
60647
  constructor(deps) {
59778
60648
  this.deps = deps;
@@ -59883,6 +60753,11 @@ var init_agent_ui = __esm({
59883
60753
  this.deps.notice(level === "warn" ? "warn" : "info", `[${agent} · ${taskId}] ${match[2]}`);
59884
60754
  return;
59885
60755
  }
60756
+ const image = level === "warn" ? SESSION_NOTICE.exec(message) : null;
60757
+ if (image !== null) {
60758
+ this.deps.notice("warn", msg().interactive.events.imageReadBackFailed(image[1]));
60759
+ return;
60760
+ }
59886
60761
  original?.call(holder, level, message);
59887
60762
  };
59888
60763
  holder.log = routed;
@@ -60107,7 +60982,7 @@ var init_agent_ui = __esm({
60107
60982
  const now = this.deps.now();
60108
60983
  const picked = await this.deps.pick({
60109
60984
  title: msg().interactive.agentUi.tasksTitle,
60110
- items: [...tasks].reverse().map((task2) => ({ value: task2.taskId, label: taskLine(task2, now) })),
60985
+ items: [...tasks].reverse().map((task2) => ({ value: task2.taskId, label: taskLine2(task2, now) })),
60111
60986
  footer: msg().interactive.agentUi.tasksFooter("↑↓")
60112
60987
  });
60113
60988
  if (picked === void 0) return;
@@ -60803,9 +61678,9 @@ function parseLeftRight(text) {
60803
61678
  async function hasUpstream(cwd, branch) {
60804
61679
  const gitDir = await findGitDir(cwd);
60805
61680
  if (gitDir === void 0) return false;
60806
- const common = (await (0, import_promises25.readFile)((0, import_node_path95.join)(gitDir, "commondir"), "utf8").catch(() => void 0))?.trim();
60807
- const dir = common === void 0 ? gitDir : (0, import_node_path95.isAbsolute)(common) ? common : (0, import_node_path95.resolve)(gitDir, common);
60808
- const text = await (0, import_promises25.readFile)((0, import_node_path95.join)(dir, "config"), "utf8").catch(() => "");
61681
+ const common = (await (0, import_promises25.readFile)((0, import_node_path98.join)(gitDir, "commondir"), "utf8").catch(() => void 0))?.trim();
61682
+ const dir = common === void 0 ? gitDir : (0, import_node_path98.isAbsolute)(common) ? common : (0, import_node_path98.resolve)(gitDir, common);
61683
+ const text = await (0, import_promises25.readFile)((0, import_node_path98.join)(dir, "config"), "utf8").catch(() => "");
60809
61684
  let inBranch = false;
60810
61685
  for (const raw of text.split("\n")) {
60811
61686
  const line2 = raw.trim();
@@ -60828,17 +61703,17 @@ async function readHead2(cwd) {
60828
61703
  }
60829
61704
  const gitDir = await findGitDir(cwd);
60830
61705
  if (gitDir === void 0) return void 0;
60831
- const text = await (0, import_promises25.readFile)((0, import_node_path95.join)(gitDir, "HEAD"), "utf8").catch(() => void 0);
61706
+ const text = await (0, import_promises25.readFile)((0, import_node_path98.join)(gitDir, "HEAD"), "utf8").catch(() => void 0);
60832
61707
  const match = /^ref:\s*refs\/heads\/(\S+)\s*$/.exec(text ?? "");
60833
61708
  return match?.[1] !== void 0 ? { branch: match[1] } : void 0;
60834
61709
  }
60835
- var import_node_child_process18, import_promises25, import_node_path95, GIT_NUMSTAT_INTERVAL_MS, GIT_NUMSTAT_TIMEOUT_MS, sameInfo, GitInfoWatcher;
61710
+ var import_node_child_process18, import_promises25, import_node_path98, GIT_NUMSTAT_INTERVAL_MS, GIT_NUMSTAT_TIMEOUT_MS, sameInfo, GitInfoWatcher;
60836
61711
  var init_info = __esm({
60837
61712
  "src/git/info.ts"() {
60838
61713
  "use strict";
60839
61714
  import_node_child_process18 = require("node:child_process");
60840
61715
  import_promises25 = require("node:fs/promises");
60841
- import_node_path95 = require("node:path");
61716
+ import_node_path98 = require("node:path");
60842
61717
  init_git_head();
60843
61718
  GIT_NUMSTAT_INTERVAL_MS = 1e4;
60844
61719
  GIT_NUMSTAT_TIMEOUT_MS = 2e3;
@@ -61134,12 +62009,12 @@ function statusLineText(mode) {
61134
62009
  const m = msg().interactive.statusLine;
61135
62010
  return mode === "full" ? m.full : m.compact;
61136
62011
  }
61137
- var import_node_path96, WRITE_TOOLS3, QUOTA_TICK_MS, HintLine, StatusArea;
62012
+ var import_node_path99, WRITE_TOOLS3, QUOTA_TICK_MS, HintLine, StatusArea;
61138
62013
  var init_status_area = __esm({
61139
62014
  "src/modes/interactive/status-area.ts"() {
61140
62015
  "use strict";
61141
62016
  init_i18n();
61142
- import_node_path96 = require("node:path");
62017
+ import_node_path99 = require("node:path");
61143
62018
  init_capability();
61144
62019
  init_channels();
61145
62020
  init_info();
@@ -61329,7 +62204,7 @@ var init_status_area = __esm({
61329
62204
  gitView() {
61330
62205
  const cwd = this.gitCwd;
61331
62206
  if (cwd === void 0) return void 0;
61332
- return { dir: (0, import_node_path96.basename)(cwd), info: this.git?.current() };
62207
+ return { dir: (0, import_node_path99.basename)(cwd), info: this.git?.current() };
61333
62208
  }
61334
62209
  watchGit() {
61335
62210
  const cwd = this.deps.session().state.cwd;
@@ -63656,15 +64531,15 @@ function processTerminal() {
63656
64531
  return new ProcessTerminal();
63657
64532
  }
63658
64533
  function loadKeys(runtime, warn2) {
63659
- const parsed = loadKeybindingsFile((0, import_node_path97.join)(runtime.paths.configDir, KEYBINDINGS_FILE));
64534
+ const parsed = loadKeybindingsFile((0, import_node_path100.join)(runtime.paths.configDir, KEYBINDINGS_FILE));
63660
64535
  for (const w of parsed.warnings) warn2(msg().interactive.app.keybindingsWarning(w));
63661
64536
  return new Keybindings(parsed.overrides);
63662
64537
  }
63663
- var import_node_path97;
64538
+ var import_node_path100;
63664
64539
  var init_terminal_setup = __esm({
63665
64540
  "src/modes/interactive/terminal-setup.ts"() {
63666
64541
  "use strict";
63667
- import_node_path97 = require("node:path");
64542
+ import_node_path100 = require("node:path");
63668
64543
  init_paths();
63669
64544
  init_errors();
63670
64545
  init_i18n();
@@ -63730,7 +64605,7 @@ function runInteractiveMode(runtime, context, options = {}) {
63730
64605
  ...options.statusLine !== void 0 ? { layout: options.statusLine } : {}
63731
64606
  });
63732
64607
  const { hint, bar: status } = area;
63733
- const historyFile = options.historyFile === false ? void 0 : options.historyFile ?? (0, import_node_path98.join)(runtime.paths.dataDir, "history");
64608
+ const historyFile = options.historyFile === false ? void 0 : options.historyFile ?? (0, import_node_path101.join)(runtime.paths.dataDir, "history");
63734
64609
  const completion = new InteractiveCompletion({
63735
64610
  commands: () => ALL_COMMANDS,
63736
64611
  prompts: () => runtime.resources.prompts,
@@ -64094,12 +64969,12 @@ function runInteractiveMode(runtime, context, options = {}) {
64094
64969
  }
64095
64970
  });
64096
64971
  }
64097
- var import_node_path98, HINT_MS;
64972
+ var import_node_path101, HINT_MS;
64098
64973
  var init_interactive_mode = __esm({
64099
64974
  "src/modes/interactive/interactive-mode.ts"() {
64100
64975
  "use strict";
64101
64976
  init_image_input();
64102
- import_node_path98 = require("node:path");
64977
+ import_node_path101 = require("node:path");
64103
64978
  init_session2();
64104
64979
  init_compose_session();
64105
64980
  init_startup_screen();
@@ -64175,7 +65050,7 @@ function choose(answer, values) {
64175
65050
  }
64176
65051
  function isDirectory3(path) {
64177
65052
  try {
64178
- return (0, import_node_fs72.statSync)(path).isDirectory();
65053
+ return (0, import_node_fs74.statSync)(path).isDirectory();
64179
65054
  } catch {
64180
65055
  return false;
64181
65056
  }
@@ -64219,8 +65094,8 @@ function createTextStartupUi(io) {
64219
65094
  const m = msg().report.startup;
64220
65095
  const answer = (await ask([m.cwdMissing(missing)], m.cwdAnswer))?.trim();
64221
65096
  if (answer === void 0 || answer === "") return void 0;
64222
- const abs = (0, import_node_path99.resolve)(answer);
64223
- if (!(0, import_node_fs72.existsSync)(abs) || !isDirectory3(abs)) {
65097
+ const abs = (0, import_node_path102.resolve)(answer);
65098
+ if (!(0, import_node_fs74.existsSync)(abs) || !isDirectory3(abs)) {
64224
65099
  io.write(m.notDirectory(abs));
64225
65100
  return void 0;
64226
65101
  }
@@ -64228,12 +65103,12 @@ function createTextStartupUi(io) {
64228
65103
  }
64229
65104
  };
64230
65105
  }
64231
- var import_node_fs72, import_node_path99;
65106
+ var import_node_fs74, import_node_path102;
64232
65107
  var init_startup_ui_text = __esm({
64233
65108
  "src/modes/startup-ui-text.ts"() {
64234
65109
  "use strict";
64235
- import_node_fs72 = require("node:fs");
64236
- import_node_path99 = require("node:path");
65110
+ import_node_fs74 = require("node:fs");
65111
+ import_node_path102 = require("node:path");
64237
65112
  init_i18n();
64238
65113
  }
64239
65114
  });
@@ -64258,7 +65133,7 @@ function createTools(input2, options, state) {
64258
65133
  const osStatus = configureOsSandbox(input2.config.sandbox?.enabled);
64259
65134
  const bashSandbox = options.bashSandbox ?? resolveBashSandbox(input2.config.sandbox, {
64260
65135
  status: osStatus,
64261
- ...input2.paths === void 0 ? {} : { hidden: [(0, import_node_path100.join)(input2.paths.configDir, AUTH_FILE)] }
65136
+ ...input2.paths === void 0 ? {} : { hidden: [(0, import_node_path103.join)(input2.paths.configDir, AUTH_FILE)] }
64262
65137
  });
64263
65138
  state.bashSandbox = bashSandbox;
64264
65139
  const capability = options.sandboxCapability ?? sandboxCapabilityFor(input2.config);
@@ -64379,7 +65254,7 @@ function createRuntimeDeps(options = {}) {
64379
65254
  return registry3;
64380
65255
  }
64381
65256
  },
64382
- sessions: createSessionStore(),
65257
+ sessions: createSessionStore(options.log ?? stderrLog()),
64383
65258
  tools: { create: (input2) => createTools(input2, options, state) },
64384
65259
  permissions: {
64385
65260
  create: (input2) => new PermissionPipeline({
@@ -64448,7 +65323,7 @@ function createRuntimeDeps(options = {}) {
64448
65323
  if (ui !== void 0) deps.ui = ui;
64449
65324
  return deps;
64450
65325
  }
64451
- var import_node_path100, DEFAULT_TOOL_FACTORIES, DEFAULT_MODES;
65326
+ var import_node_path103, DEFAULT_TOOL_FACTORIES, DEFAULT_MODES;
64452
65327
  var init_compose2 = __esm({
64453
65328
  "src/cli/compose.ts"() {
64454
65329
  "use strict";
@@ -64463,7 +65338,7 @@ var init_compose2 = __esm({
64463
65338
  init_tool();
64464
65339
  init_detect();
64465
65340
  init_bash();
64466
- import_node_path100 = require("node:path");
65341
+ import_node_path103 = require("node:path");
64467
65342
  init_paths();
64468
65343
  init_presets2();
64469
65344
  init_registry();
@@ -64678,8 +65553,8 @@ var init_memory3 = __esm({
64678
65553
  });
64679
65554
 
64680
65555
  // src/cli/main.ts
64681
- var import_node_fs73 = require("node:fs");
64682
- var import_node_path101 = require("node:path");
65556
+ var import_node_fs75 = require("node:fs");
65557
+ var import_node_path104 = require("node:path");
64683
65558
  var import_node_url3 = require("node:url");
64684
65559
  init_version();
64685
65560
  init_args();
@@ -64687,7 +65562,7 @@ init_bootstrap();
64687
65562
  init_exit_codes();
64688
65563
 
64689
65564
  // src/cli/subcommands/auth.ts
64690
- var import_node_path70 = require("node:path");
65565
+ var import_node_path72 = require("node:path");
64691
65566
  init_builtin();
64692
65567
 
64693
65568
  // src/auth/chatgpt/cli.ts
@@ -64967,15 +65842,15 @@ async function startCallbackServer(options) {
64967
65842
  }
64968
65843
 
64969
65844
  // src/auth/oauth/pkce.ts
64970
- var import_node_crypto16 = require("node:crypto");
65845
+ var import_node_crypto17 = require("node:crypto");
64971
65846
  function base64url(input2) {
64972
65847
  return Buffer.from(input2).toString("base64url");
64973
65848
  }
64974
65849
  function randomToken(bytes = 32) {
64975
- return base64url((0, import_node_crypto16.randomBytes)(bytes));
65850
+ return base64url((0, import_node_crypto17.randomBytes)(bytes));
64976
65851
  }
64977
65852
  function s256(verifier) {
64978
- return base64url((0, import_node_crypto16.createHash)("sha256").update(verifier, "ascii").digest());
65853
+ return base64url((0, import_node_crypto17.createHash)("sha256").update(verifier, "ascii").digest());
64979
65854
  }
64980
65855
  function generatePkce() {
64981
65856
  const verifier = randomToken(32);
@@ -65091,7 +65966,7 @@ async function loginDevice(preset, deps) {
65091
65966
  }
65092
65967
 
65093
65968
  // src/auth/oauth/jwt.ts
65094
- var import_node_crypto17 = require("node:crypto");
65969
+ var import_node_crypto18 = require("node:crypto");
65095
65970
  init_errors();
65096
65971
  function invalid2(reason) {
65097
65972
  return new AmaError("oauth_invalid_token", `invalid id_token: ${reason}`, { detail: { reason } });
@@ -65142,11 +66017,11 @@ function verifyJwtSignature(decoded, keys) {
65142
66017
  if (candidates2.length === 0) throw invalid2("no matching key");
65143
66018
  for (const jwk of candidates2) {
65144
66019
  try {
65145
- const key = (0, import_node_crypto17.createPublicKey)({ key: jwk, format: "jwk" });
65146
- const ok = (0, import_node_crypto17.verify)(
66020
+ const key = (0, import_node_crypto18.createPublicKey)({ key: jwk, format: "jwk" });
66021
+ const ok = (0, import_node_crypto18.verify)(
65147
66022
  spec2.hash,
65148
66023
  Buffer.from(decoded.signingInput),
65149
- spec2.pss ? { key, padding: import_node_crypto17.constants.RSA_PKCS1_PSS_PADDING, saltLength: 32 } : spec2.ec ? { key, dsaEncoding: "ieee-p1363" } : key,
66024
+ spec2.pss ? { key, padding: import_node_crypto18.constants.RSA_PKCS1_PSS_PADDING, saltLength: 32 } : spec2.ec ? { key, dsaEncoding: "ieee-p1363" } : key,
65150
66025
  decoded.signature
65151
66026
  );
65152
66027
  if (ok) return;
@@ -65214,24 +66089,24 @@ async function validateIdToken(fetchFn, idToken, expect) {
65214
66089
  init_token_client();
65215
66090
 
65216
66091
  // src/auth/chatgpt/host-id.ts
65217
- var import_node_crypto18 = require("node:crypto");
65218
- var import_node_fs47 = require("node:fs");
65219
- var import_node_path68 = require("node:path");
66092
+ var import_node_crypto19 = require("node:crypto");
66093
+ var import_node_fs48 = require("node:fs");
66094
+ var import_node_path70 = require("node:path");
65220
66095
  var HOST_ID_FILE = "chatgpt-host.json";
65221
66096
  function hostIdPath(dataDir) {
65222
- return (0, import_node_path68.join)(dataDir, HOST_ID_FILE);
66097
+ return (0, import_node_path70.join)(dataDir, HOST_ID_FILE);
65223
66098
  }
65224
66099
  function readOrCreateHostId(dataDir) {
65225
66100
  const path = hostIdPath(dataDir);
65226
66101
  try {
65227
- const value = JSON.parse((0, import_node_fs47.readFileSync)(path, "utf8"));
66102
+ const value = JSON.parse((0, import_node_fs48.readFileSync)(path, "utf8"));
65228
66103
  if (typeof value.hostId === "string" && /^urn:uuid:[0-9a-f-]{36}$/i.test(value.hostId))
65229
66104
  return value.hostId;
65230
66105
  } catch {
65231
66106
  }
65232
- const hostId = `urn:uuid:${(0, import_node_crypto18.randomUUID)()}`;
65233
- (0, import_node_fs47.mkdirSync)((0, import_node_path68.dirname)(path), { recursive: true, mode: 448 });
65234
- (0, import_node_fs47.writeFileSync)(path, `${JSON.stringify({ version: 1, hostId }, null, 2)}
66107
+ const hostId = `urn:uuid:${(0, import_node_crypto19.randomUUID)()}`;
66108
+ (0, import_node_fs48.mkdirSync)((0, import_node_path70.dirname)(path), { recursive: true, mode: 448 });
66109
+ (0, import_node_fs48.writeFileSync)(path, `${JSON.stringify({ version: 1, hostId }, null, 2)}
65235
66110
  `, { mode: 384 });
65236
66111
  return hostId;
65237
66112
  }
@@ -65668,7 +66543,7 @@ async function runAuth(argv, io, deps = {}) {
65668
66543
  return flags2.has("help") ? ExitCode.Ok : ExitCode.Usage;
65669
66544
  }
65670
66545
  const explicit = values.get("auth-file");
65671
- const path = explicit !== void 0 ? (0, import_node_path70.resolve)(io.cwd, explicit) : defaultAuthFilePath(resolveConfigDir({ env: io.env }));
66546
+ const path = explicit !== void 0 ? (0, import_node_path72.resolve)(io.cwd, explicit) : defaultAuthFilePath(resolveConfigDir({ env: io.env }));
65672
66547
  const loginOnly = ["flavor", "port"].filter((name) => values.has(name));
65673
66548
  const loginFlags = ["paste", "device", "no-browser", "yes"].filter((name) => flags2.has(name));
65674
66549
  if (action !== "login" && [...loginOnly, ...loginFlags].length > 0)
@@ -65744,8 +66619,8 @@ init_merge();
65744
66619
  init_key_docs();
65745
66620
  init_paths();
65746
66621
  var import_node_child_process14 = require("node:child_process");
65747
- var import_node_fs56 = require("node:fs");
65748
- var import_node_path77 = require("node:path");
66622
+ var import_node_fs57 = require("node:fs");
66623
+ var import_node_path79 = require("node:path");
65749
66624
  init_models_dev_cache();
65750
66625
  init_init();
65751
66626
  init_json_schema();
@@ -65760,7 +66635,7 @@ init_default_model();
65760
66635
  init_exit_codes();
65761
66636
 
65762
66637
  // src/cli/subcommands/context.ts
65763
- var import_node_path74 = require("node:path");
66638
+ var import_node_path76 = require("node:path");
65764
66639
  init_auth_file();
65765
66640
  init_load();
65766
66641
  init_merge();
@@ -65781,7 +66656,7 @@ function loadUserLevel(io, options = {}) {
65781
66656
  profile: profile?.config,
65782
66657
  hasProfile: profile !== void 0
65783
66658
  });
65784
- const authFile = options.authFile !== void 0 ? (0, import_node_path74.resolve)(io.cwd, options.authFile) : profile?.authFile ?? defaultAuthFilePath(configDir);
66659
+ const authFile = options.authFile !== void 0 ? (0, import_node_path76.resolve)(io.cwd, options.authFile) : profile?.authFile ?? defaultAuthFilePath(configDir);
65785
66660
  const result = { configDir, dataDir, merged, userConfigPath, authFile, warnings };
65786
66661
  if (profile !== void 0) result.profile = profile;
65787
66662
  return result;
@@ -65806,8 +66681,8 @@ init_ansi();
65806
66681
  // src/cli/subcommands/config-set.ts
65807
66682
  init_i18n();
65808
66683
  init_edit2();
65809
- var import_node_fs55 = require("node:fs");
65810
- var import_node_path76 = require("node:path");
66684
+ var import_node_fs56 = require("node:fs");
66685
+ var import_node_path78 = require("node:path");
65811
66686
  init_init();
65812
66687
  init_paths();
65813
66688
  init_profile();
@@ -65936,7 +66811,7 @@ async function runConfigEdit(action, argv, io, deps = {}) {
65936
66811
  if (key === "permission.mode" && value === "full-auto" && scope === "user") {
65937
66812
  if (!await confirmBypass(io, flags2.has("yes"), deps)) return ExitCode.Config;
65938
66813
  }
65939
- if (scope === "user" && !(0, import_node_fs55.existsSync)((0, import_node_path76.join)(input2.configDir, CONFIG_FILE)))
66814
+ if (scope === "user" && !(0, import_node_fs56.existsSync)((0, import_node_path78.join)(input2.configDir, CONFIG_FILE)))
65940
66815
  initConfigDir(input2.configDir);
65941
66816
  report(io, setConfigValue({ ...input2, scope, key, value }), value);
65942
66817
  return ExitCode.Ok;
@@ -65949,17 +66824,17 @@ function showPaths(io) {
65949
66824
  const configDir = resolveConfigDir({ env: io.env });
65950
66825
  const dataDir = resolveDataDir({ env: io.env });
65951
66826
  const m = msg().subcommands.configShow;
65952
- const mark = (path) => `${path}${(0, import_node_fs56.existsSync)(path) ? "" : m.missing}`;
66827
+ const mark = (path) => `${path}${(0, import_node_fs57.existsSync)(path) ? "" : m.missing}`;
65953
66828
  const width2 = Math.max(...[m.configDir, m.dataDir, m.projectLevel].map(visibleWidth)) + 2;
65954
66829
  const label2 = (text) => padToWidth(text, width2);
65955
66830
  const lines2 = [
65956
66831
  `${label2(m.configDir)}${mark(configDir)}`,
65957
- ` config.json ${mark((0, import_node_path77.join)(configDir, CONFIG_FILE))}`,
65958
- ` config.schema.json ${mark((0, import_node_path77.join)(configDir, CONFIG_SCHEMA_FILE))}`,
65959
- ` auth.json ${mark((0, import_node_path77.join)(configDir, AUTH_FILE))}`,
65960
- ` hooks.json ${mark((0, import_node_path77.join)(configDir, HOOKS_FILE))}`,
66832
+ ` config.json ${mark((0, import_node_path79.join)(configDir, CONFIG_FILE))}`,
66833
+ ` config.schema.json ${mark((0, import_node_path79.join)(configDir, CONFIG_SCHEMA_FILE))}`,
66834
+ ` auth.json ${mark((0, import_node_path79.join)(configDir, AUTH_FILE))}`,
66835
+ ` hooks.json ${mark((0, import_node_path79.join)(configDir, HOOKS_FILE))}`,
65961
66836
  `${label2(m.dataDir)}${mark(dataDir)}`,
65962
- ` sessions/ ${mark((0, import_node_path77.join)(dataDir, "sessions"))}`,
66837
+ ` sessions/ ${mark((0, import_node_path79.join)(dataDir, "sessions"))}`,
65963
66838
  ` models-dev.json ${mark(modelsDevCachePath(dataDir))}`,
65964
66839
  `${label2(m.projectLevel)}${mark(projectFile(io.cwd, CONFIG_FILE))}`
65965
66840
  ];
@@ -65969,8 +66844,8 @@ function showPaths(io) {
65969
66844
  }
65970
66845
  function editConfig(io) {
65971
66846
  const configDir = resolveConfigDir({ env: io.env });
65972
- const path = (0, import_node_path77.join)(configDir, CONFIG_FILE);
65973
- if (!(0, import_node_fs56.existsSync)(path)) initConfigDir(configDir);
66847
+ const path = (0, import_node_path79.join)(configDir, CONFIG_FILE);
66848
+ if (!(0, import_node_fs57.existsSync)(path)) initConfigDir(configDir);
65974
66849
  const editor = (io.env["VISUAL"] ?? io.env["EDITOR"] ?? "").trim();
65975
66850
  if (editor === "") {
65976
66851
  io.stdout(msg().subcommands.configShow.noEditor(path));
@@ -66262,7 +67137,7 @@ async function runConfig(argv, io, deps) {
66262
67137
  }
66263
67138
 
66264
67139
  // src/cli/subcommands/doctor.ts
66265
- var import_node_fs57 = require("node:fs");
67140
+ var import_node_fs58 = require("node:fs");
66266
67141
  init_blobs();
66267
67142
  init_shadow_git();
66268
67143
  init_gc();
@@ -66635,7 +67510,7 @@ async function runDoctor(argv, io, deps) {
66635
67510
  const m = msg().report.doctor;
66636
67511
  report2.section(m.dirsTitle);
66637
67512
  report2.item(m.configDir(level.configDir));
66638
- report2.item(m.dataDir(level.dataDir, (0, import_node_fs57.existsSync)(level.dataDir)));
67513
+ report2.item(m.dataDir(level.dataDir, (0, import_node_fs58.existsSync)(level.dataDir)));
66639
67514
  await fileHistoryLine(report2, level.dataDir);
66640
67515
  report2.section(m.layersTitle);
66641
67516
  report2.item(m.builtinDefaults);
@@ -66863,7 +67738,7 @@ init_discovered_cache();
66863
67738
  init_catalog2();
66864
67739
  init_models_dev_cache();
66865
67740
  init_models_dev();
66866
- var import_node_fs58 = require("node:fs");
67741
+ var import_node_fs59 = require("node:fs");
66867
67742
  init_load();
66868
67743
  init_write2();
66869
67744
  init_args();
@@ -67226,7 +68101,7 @@ function writeEntries(ctx, provider, entries, notes) {
67226
68101
  return 0;
67227
68102
  }
67228
68103
  models.push(...added);
67229
- const backup = (0, import_node_fs58.existsSync)(path);
68104
+ const backup = (0, import_node_fs59.existsSync)(path);
67230
68105
  writeConfigFile(path, config, { backup: true });
67231
68106
  io.stdout(m.written(path, provider.id, added.length, kept, backup));
67232
68107
  if (notes.noTools.size > 0) io.stdout(m.skippedNoTools([...notes.noTools].join(", ")));
@@ -67651,7 +68526,7 @@ async function runModels(argv, io, deps) {
67651
68526
  }
67652
68527
 
67653
68528
  // src/cli/subcommands/providers.ts
67654
- var import_node_fs59 = require("node:fs");
68529
+ var import_node_fs60 = require("node:fs");
67655
68530
  init_models_dev_cache();
67656
68531
  init_models_dev();
67657
68532
  init_auth_file();
@@ -68308,7 +69183,7 @@ ${renderTable2(result.plans)}`);
68308
69183
  const providers = config.providers ??= {};
68309
69184
  providers[id] = merged.config;
68310
69185
  if (defaultPick !== void 0) config.defaultModel = `${id}/${defaultPick.id}`;
68311
- const backup = (0, import_node_fs59.existsSync)(level.userConfigPath);
69186
+ const backup = (0, import_node_fs60.existsSync)(level.userConfigPath);
68312
69187
  writeConfigFile(level.userConfigPath, config, { backup: true });
68313
69188
  if (key.store !== void 0) setAuthKey(level.authFile, id, key.store);
68314
69189
  io.stdout(m.written(level.userConfigPath, backup));
@@ -68424,7 +69299,7 @@ init_init();
68424
69299
  init_paths();
68425
69300
 
68426
69301
  // src/cli/subcommands/sessions.ts
68427
- var import_node_path85 = require("node:path");
69302
+ var import_node_path87 = require("node:path");
68428
69303
  init_gc();
68429
69304
  init_paths();
68430
69305
  init_args();
@@ -68433,8 +69308,8 @@ init_reuse();
68433
69308
  init_clipboard_image();
68434
69309
 
68435
69310
  // src/cli/subcommands/sessions-export.ts
68436
- var import_node_fs61 = require("node:fs");
68437
- var import_node_path79 = require("node:path");
69311
+ var import_node_fs62 = require("node:fs");
69312
+ var import_node_path81 = require("node:path");
68438
69313
  init_paths();
68439
69314
 
68440
69315
  // src/session/export.ts
@@ -68656,7 +69531,7 @@ async function runSessionsExport(argv, io) {
68656
69531
  throw new UsageError(msg().subcommands.common.invalidChoice("--branch", BRANCHES, branch));
68657
69532
  }
68658
69533
  const dirFlag = values.get("session-dir");
68659
- const root = dirFlag !== void 0 ? (0, import_node_path79.resolve)(io.cwd, expandHome(dirFlag, { env: io.env })) : (0, import_node_path79.join)(resolveDataDir({ env: io.env }), "sessions");
69534
+ 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");
68660
69535
  const session = readSessionReadOnly(findSessionFileReadOnly(root, id, io.cwd));
68661
69536
  const text = renderExport(session, format, branch);
68662
69537
  const output = values.get("output");
@@ -68664,14 +69539,14 @@ async function runSessionsExport(argv, io) {
68664
69539
  io.stdout(text);
68665
69540
  return ExitCode.Ok;
68666
69541
  }
68667
- const target = (0, import_node_path79.resolve)(io.cwd, expandHome(output, { env: io.env }));
68668
- (0, import_node_fs61.writeFileSync)(target, text, { mode: 384 });
69542
+ const target = (0, import_node_path81.resolve)(io.cwd, expandHome(output, { env: io.env }));
69543
+ (0, import_node_fs62.writeFileSync)(target, text, { mode: 384 });
68669
69544
  io.stderr(msg().subcommands.sessionsExport.exported(target));
68670
69545
  return ExitCode.Ok;
68671
69546
  }
68672
69547
 
68673
69548
  // src/cli/subcommands/sessions-search.ts
68674
- var import_node_path82 = require("node:path");
69549
+ var import_node_path84 = require("node:path");
68675
69550
  init_paths();
68676
69551
  init_scan();
68677
69552
 
@@ -68849,7 +69724,7 @@ init_args();
68849
69724
  init_exit_codes();
68850
69725
 
68851
69726
  // src/cli/subcommands/stats.ts
68852
- var import_node_path81 = require("node:path");
69727
+ var import_node_path83 = require("node:path");
68853
69728
  init_paths();
68854
69729
  init_scan();
68855
69730
 
@@ -68997,8 +69872,8 @@ function aggregateStats(summaries, options = {}) {
68997
69872
  }
68998
69873
 
68999
69874
  // src/session/stats-index.ts
69000
- var import_node_fs62 = require("node:fs");
69001
- var import_node_path80 = require("node:path");
69875
+ var import_node_fs63 = require("node:fs");
69876
+ var import_node_path82 = require("node:path");
69002
69877
 
69003
69878
  // src/session/stats-scan.ts
69004
69879
  init_scan();
@@ -69211,7 +70086,7 @@ function collectSummaries(files, options = {}) {
69211
70086
  let index2 = { version: INDEX_VERSION, zone, files: {} };
69212
70087
  if (options.indexFile !== void 0) {
69213
70088
  try {
69214
- const loaded = JSON.parse((0, import_node_fs62.readFileSync)(options.indexFile, "utf8"));
70089
+ const loaded = JSON.parse((0, import_node_fs63.readFileSync)(options.indexFile, "utf8"));
69215
70090
  if (loaded.version === INDEX_VERSION && loaded.zone === zone && typeof loaded.files === "object")
69216
70091
  index2 = loaded;
69217
70092
  } catch {
@@ -69222,7 +70097,7 @@ function collectSummaries(files, options = {}) {
69222
70097
  for (const file of files) {
69223
70098
  let stat16;
69224
70099
  try {
69225
- stat16 = (0, import_node_fs62.statSync)(file);
70100
+ stat16 = (0, import_node_fs63.statSync)(file);
69226
70101
  } catch {
69227
70102
  result.invalid++;
69228
70103
  continue;
@@ -69252,10 +70127,10 @@ function collectSummaries(files, options = {}) {
69252
70127
  }
69253
70128
  if (dirty && options.indexFile !== void 0) {
69254
70129
  try {
69255
- (0, import_node_fs62.mkdirSync)((0, import_node_path80.dirname)(options.indexFile), { recursive: true, mode: 448 });
70130
+ (0, import_node_fs63.mkdirSync)((0, import_node_path82.dirname)(options.indexFile), { recursive: true, mode: 448 });
69256
70131
  const tmp = `${options.indexFile}.${process.pid}.tmp`;
69257
- (0, import_node_fs62.writeFileSync)(tmp, JSON.stringify(index2), { mode: 384 });
69258
- (0, import_node_fs62.renameSync)(tmp, options.indexFile);
70132
+ (0, import_node_fs63.writeFileSync)(tmp, JSON.stringify(index2), { mode: 384 });
70133
+ (0, import_node_fs63.renameSync)(tmp, options.indexFile);
69259
70134
  } catch {
69260
70135
  }
69261
70136
  }
@@ -69416,13 +70291,13 @@ async function runStats(argv, io) {
69416
70291
  }
69417
70292
  const dataDir = resolveDataDir({ env: io.env });
69418
70293
  const dirFlag = values.get("session-dir");
69419
- const root = dirFlag !== void 0 ? (0, import_node_path81.resolve)(io.cwd, expandHome(dirFlag, { env: io.env })) : (0, import_node_path81.join)(dataDir, "sessions");
70294
+ const root = dirFlag !== void 0 ? (0, import_node_path83.resolve)(io.cwd, expandHome(dirFlag, { env: io.env })) : (0, import_node_path83.join)(dataDir, "sessions");
69420
70295
  const projectFlag = values.get("project");
69421
- const project = projectFlag !== void 0 ? (0, import_node_path81.resolve)(io.cwd, expandHome(projectFlag, { env: io.env })) : flags2.has("all") || by === "project" ? void 0 : io.cwd;
70296
+ const project = projectFlag !== void 0 ? (0, import_node_path83.resolve)(io.cwd, expandHome(projectFlag, { env: io.env })) : flags2.has("all") || by === "project" ? void 0 : io.cwd;
69422
70297
  const files = sessionFilesInScope(root, project);
69423
70298
  const useCache = !flags2.has("no-cache");
69424
70299
  const collected = collectSummaries(files, {
69425
- ...useCache ? { indexFile: (0, import_node_path81.join)(dataDir, STATS_INDEX_FILE) } : {},
70300
+ ...useCache ? { indexFile: (0, import_node_path83.join)(dataDir, STATS_INDEX_FILE) } : {},
69426
70301
  prune: project === void 0
69427
70302
  });
69428
70303
  const report2 = aggregateStats(collected.summaries, {
@@ -69517,7 +70392,7 @@ async function runSessionsSearch(argv, io) {
69517
70392
  const sinceRaw = values.get("since");
69518
70393
  const sinceIso = sinceRaw === void 0 ? void 0 : (/* @__PURE__ */ new Date(`${parseDaySpec("since", sinceRaw)}T00:00:00`)).toISOString();
69519
70394
  const dirFlag = values.get("session-dir");
69520
- 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");
70395
+ const root = dirFlag !== void 0 ? (0, import_node_path84.resolve)(io.cwd, expandHome(dirFlag, { env: io.env })) : (0, import_node_path84.join)(resolveDataDir({ env: io.env }), "sessions");
69521
70396
  const files = sessionFilesInScope(root, flags2.has("all") ? void 0 : io.cwd);
69522
70397
  const { hits, truncated } = searchSessions(files, query, {
69523
70398
  limit,
@@ -69541,9 +70416,9 @@ async function runSessionsSearch(argv, io) {
69541
70416
 
69542
70417
  // src/cli/subcommands/sessions-trace.ts
69543
70418
  var import_node_child_process15 = require("node:child_process");
69544
- var import_node_fs64 = require("node:fs");
69545
- var import_node_os12 = require("node:os");
69546
- var import_node_path84 = require("node:path");
70419
+ var import_node_fs65 = require("node:fs");
70420
+ var import_node_os13 = require("node:os");
70421
+ var import_node_path86 = require("node:path");
69547
70422
  init_paths();
69548
70423
  init_i18n();
69549
70424
  init_scan();
@@ -69979,9 +70854,9 @@ function splitHtmlFlag(argv) {
69979
70854
  return { rest, html, ...file !== void 0 ? { file } : {} };
69980
70855
  }
69981
70856
  function locate(io, target, dirFlag) {
69982
- const asPath = (0, import_node_path84.resolve)(io.cwd, expandHome(target, { env: io.env }));
69983
- if (/[\\/]|\.jsonl$/.test(target) && (0, import_node_fs64.existsSync)(asPath)) return asPath;
69984
- const root = dirFlag !== void 0 ? (0, import_node_path84.resolve)(io.cwd, expandHome(dirFlag, { env: io.env })) : (0, import_node_path84.join)(resolveDataDir({ env: io.env }), "sessions");
70857
+ const asPath = (0, import_node_path86.resolve)(io.cwd, expandHome(target, { env: io.env }));
70858
+ if (/[\\/]|\.jsonl$/.test(target) && (0, import_node_fs65.existsSync)(asPath)) return asPath;
70859
+ const root = dirFlag !== void 0 ? (0, import_node_path86.resolve)(io.cwd, expandHome(dirFlag, { env: io.env })) : (0, import_node_path86.join)(resolveDataDir({ env: io.env }), "sessions");
69985
70860
  return findSessionFileReadOnly(root, target, io.cwd);
69986
70861
  }
69987
70862
  async function runSessionsTrace(argv, io, deps = {}) {
@@ -70046,14 +70921,14 @@ async function runSessionsTrace(argv, io, deps = {}) {
70046
70921
  }
70047
70922
  const outFlag = split.file ?? values.get("output");
70048
70923
  const open3 = flags2.has("open");
70049
- let outPath = outFlag === void 0 ? void 0 : (0, import_node_path84.resolve)(io.cwd, expandHome(outFlag, { env: io.env }));
70924
+ let outPath = outFlag === void 0 ? void 0 : (0, import_node_path86.resolve)(io.cwd, expandHome(outFlag, { env: io.env }));
70050
70925
  if (outPath === void 0 && open3)
70051
- outPath = (0, import_node_path84.join)((0, import_node_os12.tmpdir)(), `ama-trace-${read2.header.id}.${wantsJson ? "json" : "html"}`);
70926
+ outPath = (0, import_node_path86.join)((0, import_node_os13.tmpdir)(), `ama-trace-${read2.header.id}.${wantsJson ? "json" : "html"}`);
70052
70927
  if (outPath === void 0) {
70053
70928
  io.stdout(text);
70054
70929
  return ExitCode.Ok;
70055
70930
  }
70056
- (0, import_node_fs64.writeFileSync)(outPath, text, { mode: 384 });
70931
+ (0, import_node_fs65.writeFileSync)(outPath, text, { mode: 384 });
70057
70932
  io.stderr(m.wrote(outPath));
70058
70933
  if (open3) {
70059
70934
  try {
@@ -70094,7 +70969,7 @@ async function runSessions(argv, io, deps) {
70094
70969
  return flags2.has("help") ? ExitCode.Ok : ExitCode.Usage;
70095
70970
  }
70096
70971
  const dirFlag = values.get("session-dir");
70097
- const sessionDir = dirFlag !== void 0 ? (0, import_node_path85.resolve)(io.cwd, expandHome(dirFlag, { env: io.env })) : (0, import_node_path85.resolve)(resolveDataDir({ env: io.env }), "sessions");
70972
+ const sessionDir = dirFlag !== void 0 ? (0, import_node_path87.resolve)(io.cwd, expandHome(dirFlag, { env: io.env })) : (0, import_node_path87.resolve)(resolveDataDir({ env: io.env }), "sessions");
70098
70973
  const sessions = deps?.sessions;
70099
70974
  const scope = flags2.has("all") ? {} : { cwd: io.cwd };
70100
70975
  switch (action) {
@@ -70180,7 +71055,7 @@ async function pruneFileHistory(io, sessionDir, dryRun) {
70180
71055
  try {
70181
71056
  const result = await gcBlobs({
70182
71057
  dataDir,
70183
- sessionRoots: [sessionDir, (0, import_node_path85.join)(dataDir, "sessions")],
71058
+ sessionRoots: [sessionDir, (0, import_node_path87.join)(dataDir, "sessions")],
70184
71059
  dryRun
70185
71060
  });
70186
71061
  if (result.removed.length === 0) return;
@@ -70254,7 +71129,7 @@ function readStdinDefault() {
70254
71129
  }
70255
71130
  function stdinKindDefault() {
70256
71131
  try {
70257
- const stat16 = (0, import_node_fs73.fstatSync)(0);
71132
+ const stat16 = (0, import_node_fs75.fstatSync)(0);
70258
71133
  if (stat16.isFile()) return "file";
70259
71134
  if (stat16.isFIFO()) return "fifo";
70260
71135
  if (stat16.isSocket()) return "socket";
@@ -70314,7 +71189,7 @@ function defaultIo() {
70314
71189
  }
70315
71190
  function peekUserLanguage(env) {
70316
71191
  try {
70317
- const raw = (0, import_node_fs73.readFileSync)((0, import_node_path101.join)(resolveConfigDir({ env }), "config.json"), "utf8");
71192
+ const raw = (0, import_node_fs75.readFileSync)((0, import_node_path104.join)(resolveConfigDir({ env }), "config.json"), "utf8");
70318
71193
  const value = JSON.parse(raw).ui?.language;
70319
71194
  return value === "auto" || value === "zh" || value === "en" ? value : void 0;
70320
71195
  } catch {
@@ -70402,7 +71277,7 @@ function isDirectRun() {
70402
71277
  const entry = process.argv[1];
70403
71278
  if (entry === void 0) return false;
70404
71279
  try {
70405
- return (0, import_node_fs73.realpathSync)(entry) === (0, import_node_fs73.realpathSync)((0, import_node_url3.fileURLToPath)(__ama_import_meta_url));
71280
+ return (0, import_node_fs75.realpathSync)(entry) === (0, import_node_fs75.realpathSync)((0, import_node_url3.fileURLToPath)(__ama_import_meta_url));
70406
71281
  } catch {
70407
71282
  return false;
70408
71283
  }