@epoch-agent/core 0.11.0 → 0.12.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.
package/dist/index.js CHANGED
@@ -264,7 +264,7 @@ function createLaunchdBackend(opts = {}) {
264
264
  mkdirSync(input.logDir, { recursive: true });
265
265
  writeFileSync(path, renderPlist(label, input), "utf-8");
266
266
  } catch (err) {
267
- return { ok: false, detail: `plist-write-failed: ${describe7(err)}` };
267
+ return { ok: false, detail: `plist-write-failed: ${describe8(err)}` };
268
268
  }
269
269
  await run("launchctl", ["bootout", `${guiDomain()}/${label}`]);
270
270
  const toggle = await backend.setEnabled(label, input.enabled);
@@ -280,7 +280,7 @@ function createLaunchdBackend(opts = {}) {
280
280
  try {
281
281
  rmSync(plistPath(label), { force: true });
282
282
  } catch (err) {
283
- return { ok: false, detail: `plist-remove-failed: ${describe7(err)}` };
283
+ return { ok: false, detail: `plist-remove-failed: ${describe8(err)}` };
284
284
  }
285
285
  return { ok: true };
286
286
  },
@@ -435,7 +435,7 @@ function detailOf2(what, res) {
435
435
  const msg = (res.stderr || res.stdout).trim();
436
436
  return `${what} exit ${res.code}${msg ? `: ${msg}` : ""}`;
437
437
  }
438
- function describe7(err) {
438
+ function describe8(err) {
439
439
  return err instanceof Error ? err.message : String(err);
440
440
  }
441
441
  var LAUNCHD_LABEL_PREFIX;
@@ -629,7 +629,7 @@ var ToolRegistry = class {
629
629
  this.addTool(tool, source);
630
630
  }
631
631
  registerTools(tools, source = "builtin") {
632
- for (const t79 of tools) this.addTool(t79, source);
632
+ for (const t81 of tools) this.addTool(t81, source);
633
633
  }
634
634
  addTool(tool, source) {
635
635
  const existing = this.tools.get(tool.name);
@@ -678,14 +678,14 @@ var ToolRegistry = class {
678
678
  return isCodeModeDeferred(tool) ? ToolExposure.Deferred : declared;
679
679
  }
680
680
  exposed() {
681
- return this.list().filter((t79) => this.exposureOf(t79) === ToolExposure.Direct);
681
+ return this.list().filter((t81) => this.exposureOf(t81) === ToolExposure.Direct);
682
682
  }
683
683
  byExposure(exposure) {
684
- return this.list().filter((t79) => this.exposureOf(t79) === exposure);
684
+ return this.list().filter((t81) => this.exposureOf(t81) === exposure);
685
685
  }
686
686
  codeModeDeclared() {
687
687
  if (!this.codeMode) return [];
688
- return this.list().filter((t79) => isCodeModeDeferred(t79));
688
+ return this.list().filter((t81) => isCodeModeDeferred(t81));
689
689
  }
690
690
  sourceOf(name) {
691
691
  return this.tools.get(name)?.source;
@@ -734,7 +734,7 @@ var ToolRegistry = class {
734
734
  function staticToolProvider(tools) {
735
735
  return {
736
736
  list: () => tools,
737
- get: (name) => tools.find((t79) => t79.name === name)
737
+ get: (name) => tools.find((t81) => t81.name === name)
738
738
  };
739
739
  }
740
740
  var log = createLogger("tokenizer");
@@ -1146,7 +1146,7 @@ var DelegateManager = class {
1146
1146
  }
1147
1147
  normalizeTasks(args) {
1148
1148
  if (args.tasks && args.tasks.length > 0) {
1149
- return args.role ? args.tasks.map((t79) => ({ ...t79, role: t79.role ?? args.role })) : args.tasks;
1149
+ return args.role ? args.tasks.map((t81) => ({ ...t81, role: t81.role ?? args.role })) : args.tasks;
1150
1150
  }
1151
1151
  if (args.goal) return [{ goal: args.goal, ...args.role ? { role: args.role } : {} }];
1152
1152
  return [];
@@ -1156,7 +1156,7 @@ var DelegateManager = class {
1156
1156
  for (let i = 0; i < tasks.length; i += maxConcurrent) {
1157
1157
  const batch = tasks.slice(i, i + maxConcurrent);
1158
1158
  const batchResults = await Promise.allSettled(
1159
- batch.map((t79) => this.runSingleTask(t79, parentSessionId))
1159
+ batch.map((t81) => this.runSingleTask(t81, parentSessionId))
1160
1160
  );
1161
1161
  for (const r of batchResults) {
1162
1162
  if (r.status === "fulfilled") {
@@ -1297,21 +1297,21 @@ function createDelegateTool(runner, config, roles) {
1297
1297
  operation: "command",
1298
1298
  describeTarget: (args) => {
1299
1299
  const tasks = Array.isArray(args["tasks"]) ? args["tasks"] : [];
1300
- const goals = tasks.map((t79) => String(t79["goal"] ?? ""));
1300
+ const goals = tasks.map((t81) => String(t81["goal"] ?? ""));
1301
1301
  const single = typeof args["goal"] === "string" ? args["goal"] : "";
1302
1302
  return [...goals, single].filter(Boolean).join(" | ");
1303
1303
  },
1304
1304
  async execute(args, ctx) {
1305
1305
  const start = Date.now();
1306
1306
  const rawTasks = Array.isArray(args["tasks"]) ? args["tasks"] : void 0;
1307
- const tasks = rawTasks?.map((t79) => {
1308
- const o = t79;
1307
+ const tasks = rawTasks?.map((t81) => {
1308
+ const o = t81;
1309
1309
  return {
1310
1310
  goal: String(o["goal"] ?? "").trim(),
1311
1311
  context: String(o["context"] ?? ""),
1312
1312
  ...typeof o["role"] === "string" && o["role"].trim() ? { role: o["role"].trim() } : {}
1313
1313
  };
1314
- }).filter((t79) => t79.goal.length > 0);
1314
+ }).filter((t81) => t81.goal.length > 0);
1315
1315
  const goal = typeof args["goal"] === "string" ? args["goal"].trim() : "";
1316
1316
  const topRole = typeof args["role"] === "string" ? args["role"].trim() : "";
1317
1317
  if ((!tasks || tasks.length === 0) && !goal) {
@@ -1327,7 +1327,7 @@ function createDelegateTool(runner, config, roles) {
1327
1327
  };
1328
1328
  }
1329
1329
  const known = listRoles();
1330
- const requested = [...(tasks ?? []).map((t79) => t79.role), topRole].filter(
1330
+ const requested = [...(tasks ?? []).map((t81) => t81.role), topRole].filter(
1331
1331
  (r) => Boolean(r)
1332
1332
  );
1333
1333
  const unknown = [...new Set(requested)].filter((r) => !known.some((k) => k.name === r));
@@ -1500,8 +1500,8 @@ function createGoalTool(deps) {
1500
1500
  }
1501
1501
  var VALID_TARGETS = ["memory", "user"];
1502
1502
  var VALID_ACTIONS = ["add", "replace", "remove", "search", "read", "budget"];
1503
- function isValidTarget(t79) {
1504
- return typeof t79 === "string" && VALID_TARGETS.includes(t79);
1503
+ function isValidTarget(t81) {
1504
+ return typeof t81 === "string" && VALID_TARGETS.includes(t81);
1505
1505
  }
1506
1506
  function isValidAction(a) {
1507
1507
  return VALID_ACTIONS.includes(a);
@@ -4507,7 +4507,7 @@ function available(tools) {
4507
4507
  if (tools.length === 0) {
4508
4508
  return "No deferred tools in this session \u2014 every tool is already in your tool list.";
4509
4509
  }
4510
- const names = tools.map((t79) => t79.name).sort();
4510
+ const names = tools.map((t81) => t81.name).sort();
4511
4511
  const shown = names.slice(0, MAX_LISTED);
4512
4512
  const rest = names.length - shown.length;
4513
4513
  return `Searchable tools: ${shown.join(", ")}${rest > 0 ? ` (\u2026and ${rest} more)` : ""}.`;
@@ -4627,15 +4627,15 @@ var TrackerDB = class {
4627
4627
  );
4628
4628
  this.db.transaction(() => {
4629
4629
  this.db.prepare("DELETE FROM todos WHERE session_id = ?").run(sessionId);
4630
- for (const t79 of todos) {
4630
+ for (const t81 of todos) {
4631
4631
  insertStmt.run({
4632
- id: t79.id,
4632
+ id: t81.id,
4633
4633
  session_id: sessionId,
4634
- content: t79.content,
4635
- status: t79.status,
4636
- reason: t79.reason || null,
4637
- created_at: t79.created_at,
4638
- updated_at: t79.updated_at
4634
+ content: t81.content,
4635
+ status: t81.status,
4636
+ reason: t81.reason || null,
4637
+ created_at: t81.created_at,
4638
+ updated_at: t81.updated_at
4639
4639
  });
4640
4640
  }
4641
4641
  })();
@@ -4657,9 +4657,9 @@ function formatTodoList(todos, pendingCount) {
4657
4657
  cancelled: "\u5DF2\u53D6\u6D88"
4658
4658
  };
4659
4659
  lines.push(`[todo] \u72B6\u6001\u6C47\u603B: ${pendingCount} \u4E2A\u5F85\u5B8C\u6210`);
4660
- for (const t79 of todos) {
4661
- const label = statusLabel[t79.status] || t79.status;
4662
- lines.push(`- [${label}] ${t79.content}${t79.reason ? ` \u2014\u2014 ${t79.reason}` : ""}`);
4660
+ for (const t81 of todos) {
4661
+ const label = statusLabel[t81.status] || t81.status;
4662
+ lines.push(`- [${label}] ${t81.content}${t81.reason ? ` \u2014\u2014 ${t81.reason}` : ""}`);
4663
4663
  }
4664
4664
  return lines.join("\n");
4665
4665
  }
@@ -4733,14 +4733,14 @@ function createTodoTool(db) {
4733
4733
  };
4734
4734
  }
4735
4735
  const now = (/* @__PURE__ */ new Date()).toISOString();
4736
- const existing = new Map(db.listBySession(ctx.sessionId).map((t79) => [t79.id, t79]));
4737
- const todos = rawTodos.map((t79) => {
4738
- const prev = t79.id ? existing.get(t79.id) : void 0;
4739
- const status = isValidStatus(t79.status) ? t79.status : "pending";
4740
- const reason9 = normalizeReason(status, t79.reason);
4736
+ const existing = new Map(db.listBySession(ctx.sessionId).map((t81) => [t81.id, t81]));
4737
+ const todos = rawTodos.map((t81) => {
4738
+ const prev = t81.id ? existing.get(t81.id) : void 0;
4739
+ const status = isValidStatus(t81.status) ? t81.status : "pending";
4740
+ const reason9 = normalizeReason(status, t81.reason);
4741
4741
  return {
4742
- id: t79.id || generateShortId(),
4743
- content: String(t79.content || "").slice(0, 500),
4742
+ id: t81.id || generateShortId(),
4743
+ content: String(t81.content || "").slice(0, 500),
4744
4744
  status,
4745
4745
  ...reason9 ? { reason: reason9 } : {},
4746
4746
  created_at: prev?.created_at || now,
@@ -4748,7 +4748,7 @@ function createTodoTool(db) {
4748
4748
  };
4749
4749
  });
4750
4750
  db.replaceAll(ctx.sessionId, todos);
4751
- const pendingCount = todos.filter((t79) => isOpenTodo(t79.status)).length;
4751
+ const pendingCount = todos.filter((t81) => isOpenTodo(t81.status)).length;
4752
4752
  return {
4753
4753
  success: true,
4754
4754
  output: formatTodoList(todos, pendingCount),
@@ -5083,7 +5083,7 @@ function intersectNames(base, incoming) {
5083
5083
  if (!base) return incoming ? [...incoming] : void 0;
5084
5084
  if (!incoming) return [...base];
5085
5085
  const baseSet = new Set(base);
5086
- return incoming.filter((t79) => baseSet.has(t79));
5086
+ return incoming.filter((t81) => baseSet.has(t81));
5087
5087
  }
5088
5088
  function findRole(roles, name) {
5089
5089
  return roles.find((r) => r.name === name);
@@ -5160,6 +5160,64 @@ function driftOf(role, name, input) {
5160
5160
  function describe(err) {
5161
5161
  return err instanceof Error ? err.message : String(err);
5162
5162
  }
5163
+ function removeRoleFile(name, opts) {
5164
+ const wanted = name.trim();
5165
+ const hits = matchingFiles(opts.dir, wanted);
5166
+ if (hits.length > 1) {
5167
+ return {
5168
+ ok: false,
5169
+ reason: "ambiguous",
5170
+ detail: t(
5171
+ "role_write.ambiguous_files",
5172
+ {
5173
+ name: wanted,
5174
+ paths: hits.join(t("role_write.path_sep", void 0, opts.lang))
5175
+ },
5176
+ opts.lang
5177
+ )
5178
+ };
5179
+ }
5180
+ const [path] = hits;
5181
+ if (path === void 0) {
5182
+ return {
5183
+ ok: false,
5184
+ reason: "not-found",
5185
+ detail: t("role_write.no_such_file", { name: wanted }, opts.lang)
5186
+ };
5187
+ }
5188
+ try {
5189
+ rmSync(path);
5190
+ } catch (err) {
5191
+ return { ok: false, reason: "failed", detail: describe2(err, path, opts.lang) };
5192
+ }
5193
+ return { ok: true, path };
5194
+ }
5195
+ function matchingFiles(dir, name) {
5196
+ if (!existsSync(dir)) return [];
5197
+ let files;
5198
+ try {
5199
+ files = readdirSync(dir).filter((f) => f.endsWith(".md")).sort();
5200
+ } catch {
5201
+ return [];
5202
+ }
5203
+ const hits = [];
5204
+ for (const file of files) {
5205
+ const path = join(dir, file);
5206
+ let raw;
5207
+ try {
5208
+ raw = readFileSync(path, "utf-8");
5209
+ } catch {
5210
+ continue;
5211
+ }
5212
+ const parsed = parseRoleDefinition(raw, file, "user");
5213
+ if (parsed.role?.name === name) hits.push(path);
5214
+ }
5215
+ return hits;
5216
+ }
5217
+ function describe2(err, path, lang) {
5218
+ const reason9 = err instanceof Error ? err.message : String(err);
5219
+ return t("role_write.remove_failed", { path, reason: reason9 }, lang);
5220
+ }
5163
5221
  // src/agent-role/scope.ts
5164
5222
  function roleScopedProvider(base, role, blocked) {
5165
5223
  const blockedSet = new Set(blocked);
@@ -5169,7 +5227,7 @@ function roleScopedProvider(base, role, blocked) {
5169
5227
  return allow ? allow.has(name) : true;
5170
5228
  };
5171
5229
  return {
5172
- list: () => base.list().filter((t79) => permitted(t79.name)),
5230
+ list: () => base.list().filter((t81) => permitted(t81.name)),
5173
5231
  get: (name) => permitted(name) ? base.get(name) : void 0
5174
5232
  };
5175
5233
  }
@@ -5196,7 +5254,7 @@ function createRoleScope(base, sessionRole, blocked) {
5196
5254
  }
5197
5255
  function unknownRoleTools(base, role, blocked) {
5198
5256
  if (!role?.tools) return [];
5199
- const available2 = new Set(base.list().map((t79) => t79.name));
5257
+ const available2 = new Set(base.list().map((t81) => t81.name));
5200
5258
  const blockedSet = new Set(blocked);
5201
5259
  return role.tools.filter((name) => !available2.has(name) && !blockedSet.has(name));
5202
5260
  }
@@ -5532,7 +5590,7 @@ function createToolScope(base) {
5532
5590
  const permitted = (name) => allow ? allow.has(name) : true;
5533
5591
  return {
5534
5592
  provider: {
5535
- list: () => base.list().filter((t79) => permitted(t79.name)),
5593
+ list: () => base.list().filter((t81) => permitted(t81.name)),
5536
5594
  get: (name) => permitted(name) ? base.get(name) : void 0
5537
5595
  },
5538
5596
  enter: (next) => {
@@ -5702,7 +5760,7 @@ function scanHooks(dir, issues) {
5702
5760
  return [...parsed.entries].map(([type, list]) => ({
5703
5761
  type,
5704
5762
  count: list.reduce((sum, entry) => sum + entry.hooks.length, 0)
5705
- })).filter((t79) => t79.count > 0).sort((a, b) => a.type.localeCompare(b.type));
5763
+ })).filter((t81) => t81.count > 0).sort((a, b) => a.type.localeCompare(b.type));
5706
5764
  }
5707
5765
  function scanMcp(dir, plugin, issues) {
5708
5766
  const path = join(dir, PLUGIN_LAYOUT.mcp);
@@ -6322,7 +6380,7 @@ function runCommand(file, args, opts = {}) {
6322
6380
  resolvePromise({ ok: true, stdout: out, stderr: errOut });
6323
6381
  return;
6324
6382
  }
6325
- const detail = describe2(file, err, errOut);
6383
+ const detail = describe3(file, err, errOut);
6326
6384
  resolvePromise({
6327
6385
  ok: false,
6328
6386
  detail,
@@ -6341,7 +6399,7 @@ function escapeForCmd(arg) {
6341
6399
  const quoted = `"${arg.replace(/(\\*)"/g, '$1$1\\"').replace(/(\\*)$/, "$1$1")}"`;
6342
6400
  return quoted.replace(/([()%!^<>&|;,"])/g, "^$1");
6343
6401
  }
6344
- function describe2(file, err, stderr) {
6402
+ function describe3(file, err, stderr) {
6345
6403
  if (err.code === "ENOENT") return t("plugin_cmd.not_found", { file });
6346
6404
  if (err.killed) return t("plugin_cmd.timeout", { file });
6347
6405
  const tail = stderr.trim().split("\n").slice(-4).join("\n").trim();
@@ -7427,14 +7485,14 @@ var CheckpointStore = class {
7427
7485
  }
7428
7486
  async enforceTotalSize(protectSession, protectTurnIndex) {
7429
7487
  const turns = await this.collectTurns();
7430
- let total = turns.reduce((sum, t79) => sum + t79.bytes, 0);
7488
+ let total = turns.reduce((sum, t81) => sum + t81.bytes, 0);
7431
7489
  if (total <= this.maxTotalBytes) return;
7432
7490
  turns.sort((a, b) => a.createdAt - b.createdAt);
7433
- for (const t79 of turns) {
7491
+ for (const t81 of turns) {
7434
7492
  if (total <= this.maxTotalBytes) return;
7435
- if (t79.sessionId === protectSession && t79.turnIndex === protectTurnIndex) continue;
7436
- await this.removeTurn(t79.sessionId, t79.turnIndex);
7437
- total -= t79.bytes;
7493
+ if (t81.sessionId === protectSession && t81.turnIndex === protectTurnIndex) continue;
7494
+ await this.removeTurn(t81.sessionId, t81.turnIndex);
7495
+ total -= t81.bytes;
7438
7496
  }
7439
7497
  }
7440
7498
  async collectTurns() {
@@ -8619,7 +8677,7 @@ function decideTrust(dir) {
8619
8677
  return ambient ? ambient.decide(dir) : noGate();
8620
8678
  }
8621
8679
  var FILE_VERSION = 1;
8622
- function describe3(err) {
8680
+ function describe4(err) {
8623
8681
  return err instanceof Error ? err.message : String(err);
8624
8682
  }
8625
8683
  var ImportTrustStore = class {
@@ -8661,7 +8719,7 @@ var ImportTrustStore = class {
8661
8719
  raw = readFileSync(this.filePath, "utf-8");
8662
8720
  } catch (err) {
8663
8721
  this.loadErrors.push(
8664
- t("import_trust.read_failed", { path: this.filePath, reason: describe3(err) })
8722
+ t("import_trust.read_failed", { path: this.filePath, reason: describe4(err) })
8665
8723
  );
8666
8724
  return;
8667
8725
  }
@@ -8670,7 +8728,7 @@ var ImportTrustStore = class {
8670
8728
  parsed = JSON.parse(raw);
8671
8729
  } catch (err) {
8672
8730
  this.loadErrors.push(
8673
- t("import_trust.bad_json", { path: this.filePath, reason: describe3(err) })
8731
+ t("import_trust.bad_json", { path: this.filePath, reason: describe4(err) })
8674
8732
  );
8675
8733
  return;
8676
8734
  }
@@ -8728,7 +8786,7 @@ var ImportTrustStore = class {
8728
8786
  } catch (err) {
8729
8787
  rmSync(tmp, { force: true });
8730
8788
  throw new Error(
8731
- t("import_trust.write_failed", { path: this.filePath, reason: describe3(err) })
8789
+ t("import_trust.write_failed", { path: this.filePath, reason: describe4(err) })
8732
8790
  );
8733
8791
  }
8734
8792
  }
@@ -9540,7 +9598,6 @@ ${this.describeWarning(status)}
9540
9598
  });
9541
9599
  }
9542
9600
  };
9543
- // src/provider/errors.ts
9544
9601
  var ProviderError = class extends Error {
9545
9602
  constructor(message, code, recoverable, recovery = "abort") {
9546
9603
  super(message);
@@ -9568,6 +9625,40 @@ function isAbortError(err) {
9568
9625
  }
9569
9626
  return false;
9570
9627
  }
9628
+ function causeChain(err) {
9629
+ const out = [];
9630
+ for (let cur = err, depth = 0; cur && depth < 5; depth++) {
9631
+ if (typeof cur !== "object") break;
9632
+ const e = cur;
9633
+ out.push({
9634
+ message: typeof e.message === "string" ? e.message : "",
9635
+ ...typeof e.code === "string" ? { code: e.code } : {}
9636
+ });
9637
+ cur = e.cause;
9638
+ }
9639
+ return out;
9640
+ }
9641
+ var NETWORK_ERROR_CODES = /* @__PURE__ */ new Set([
9642
+ "ECONNRESET",
9643
+ "ECONNREFUSED",
9644
+ "ETIMEDOUT",
9645
+ "ENOTFOUND",
9646
+ "EPIPE",
9647
+ "EAI_AGAIN",
9648
+ "UND_ERR_SOCKET",
9649
+ "UND_ERR_CONNECT_TIMEOUT",
9650
+ "UND_ERR_HEADERS_TIMEOUT",
9651
+ "UND_ERR_BODY_TIMEOUT",
9652
+ "UND_ERR_RESPONSE_STATUS_CODE"
9653
+ ]);
9654
+ var NETWORK_MESSAGE_RE = /timeout|timed.?out|etimedout|econnreset|enotfound|socket.?hang.?up|other.?side.?closed|terminated|network.?error|fetch.?failed/i;
9655
+ function describeProviderError(err) {
9656
+ const chain = causeChain(err);
9657
+ const head = chain[0]?.message ?? (typeof err === "string" ? err : String(err));
9658
+ if (chain.length === 0) return head;
9659
+ const root = [...chain].reverse().find((link) => link.message !== "" && link.message !== head)?.message;
9660
+ return root ? t("provider_route.root_cause", { message: head, cause: root }) : head;
9661
+ }
9571
9662
  function extractStatus(err) {
9572
9663
  if (!err || typeof err !== "object") return void 0;
9573
9664
  const e = err;
@@ -9600,8 +9691,7 @@ function classifyProviderError(err) {
9600
9691
  return { code: 1040, recovery: "switch_model" };
9601
9692
  if (/overloaded|server.?error|bad.?gateway|service.?unavailable/i.test(msg))
9602
9693
  return { code: 1020, recovery: "retry" };
9603
- if (/timeout|timed.?out|etimedout|econnreset|enotfound|socket.?hang.?up/i.test(msg))
9604
- return { code: 1041, recovery: "retry" };
9694
+ if (NETWORK_MESSAGE_RE.test(msg)) return { code: 1041, recovery: "retry" };
9605
9695
  const code = status ?? extractStatusFromMessage(msg);
9606
9696
  if (code !== void 0) {
9607
9697
  if (code === 401 || code === 403) return { code: 1001, recovery: "rotate_credential" };
@@ -9611,6 +9701,10 @@ function classifyProviderError(err) {
9611
9701
  if (code >= 500) return { code: 1020, recovery: "retry" };
9612
9702
  if (code >= 400) return { code: 1050, recovery: "abort" };
9613
9703
  }
9704
+ for (const link of causeChain(err)) {
9705
+ if (link.code && NETWORK_ERROR_CODES.has(link.code)) return { code: 1041, recovery: "retry" };
9706
+ if (NETWORK_MESSAGE_RE.test(link.message)) return { code: 1041, recovery: "retry" };
9707
+ }
9614
9708
  return { code: 9999, recovery: "retry" };
9615
9709
  }
9616
9710
  function toModelMessages(messages) {
@@ -9801,6 +9895,28 @@ function droppedUserContentParts(warnings) {
9801
9895
  });
9802
9896
  }
9803
9897
  var DROPPED_PART_HINTS = ["image", "file"];
9898
+ // src/agent/blank-turn-detector.ts
9899
+ var NEAR_BLANK_MAX_CHARS = 4;
9900
+ var ACKNOWLEDGEMENTS = [
9901
+ {
9902
+ zh: /^[一-鿿]{0,2}(?:完|好|到)(?:了|啦|的)?[。..!!]?$/,
9903
+ en: /^(?:done|finished|complete[d]?)[.!]?$/i
9904
+ },
9905
+ {
9906
+ zh: /^(?:完成|搞定|收工|行|可以|嗯|是|是的|对|对的|没错)(?:了|啦)?[。..!!]?$/,
9907
+ en: /^(?:ok(?:ay)?|sure|yes|yep|yeah|right|no|nope)[.!]?$/i
9908
+ }
9909
+ ];
9910
+ function isAcknowledgement(text) {
9911
+ return ACKNOWLEDGEMENTS.some((a) => a.zh.test(text) || a.en.test(text));
9912
+ }
9913
+ function blankFinish(text, didToolWork) {
9914
+ if (!didToolWork) return false;
9915
+ const trimmed = text.trim();
9916
+ if (trimmed.length === 0) return true;
9917
+ if (trimmed.length > NEAR_BLANK_MAX_CHARS) return false;
9918
+ return !isAcknowledgement(trimmed);
9919
+ }
9804
9920
  // src/agent/hooks.ts
9805
9921
  var HookDispatcher = class {
9806
9922
  constructor(manager, workDir) {
@@ -10104,6 +10220,14 @@ function announcedButIdleNote() {
10104
10220
  "\u771F\u505A\u4E0D\u4E0B\u53BB\uFF08\u7F3A\u51ED\u636E\u3001\u8981\u82B1\u94B1\u3001\u53D6\u6570\u4E00\u76F4\u5931\u8D25\uFF09\u5C31\u8BF4\u6E05\u5361\u5728\u54EA\u4E00\u6B65\u7684\u54EA\u4E00\u73AF\u3002"
10105
10221
  ].join("\n");
10106
10222
  }
10223
+ function blankResponseNote(chars) {
10224
+ return [
10225
+ `\u4F60\u4E0A\u4E00\u8F6E\u628A\u5DE5\u5177\u8DD1\u5B8C\u4E86\uFF0C\u4F46\u4EA4\u5230\u7528\u6237\u5C4F\u5E55\u4E0A\u7684\u6B63\u6587\u53EA\u6709 ${chars} \u4E2A\u5B57 \u2014\u2014 \u5728\u7528\u6237\u90A3\u8FB9\uFF0C\u8FD9\u4E00\u8F6E\u7B49\u4E8E\u6CA1\u6709\u56DE\u590D\u3002`,
10226
+ "\u73B0\u5728\u628A\u7ED3\u8BBA\u5B8C\u6574\u5199\u51FA\u6765\uFF1A\u7528\u6237\u95EE\u7684\u90A3\u4EF6\u4E8B\uFF0C\u7B54\u6848\u662F\u4EC0\u4E48\u3002\u522B\u53EA\u56DE\u4E00\u53E5\u300C\u597D\u7684\u300D\u300C\u5B8C\u6210\u4E86\u300D\u300C\u5DF2\u5904\u7406\u300D\u3002",
10227
+ "\u5982\u679C\u4F60\u89C9\u5F97\u81EA\u5DF1\u4E0A\u4E00\u8F6E\u5176\u5B9E\u5DF2\u7ECF\u7B54\u5B8C\u4E86\uFF0C\u90A3\u5C31\u628A\u90A3\u6BB5\u7ED3\u8BBA\u5B8C\u6574\u5730\u518D\u8BF4\u4E00\u904D \u2014\u2014 \u5B83\u6CA1\u6709\u5230\u8FBE\u7528\u6237\u3002",
10228
+ "\u4E0A\u4E00\u8F6E\u7684\u5DE5\u5177\u7ED3\u679C\u90FD\u8FD8\u5728\u4E0A\u9762\u7684\u4E0A\u4E0B\u6587\u91CC\uFF0C\u76F4\u63A5\u636E\u6B64\u4F5C\u7B54\uFF0C\u522B\u628A\u90A3\u4E9B\u5DE5\u5177\u91CD\u8DD1\u4E00\u904D\u3002"
10229
+ ].join("\n");
10230
+ }
10107
10231
  var CODE_VERIFICATION_POLICY = [
10108
10232
  "<code_verification>",
10109
10233
  "\u6539\u5B8C\u4EE3\u7801\u3001\u5BA3\u5E03\u5B8C\u6210\u4E4B\u524D\uFF0C\u8C03\u4E00\u6B21 `lsp_diagnostics`\uFF0C\u628A\u672C\u8F6E\u65B0\u5EFA\u6216\u4FEE\u6539\u8FC7\u7684\u6E90\u6587\u4EF6\u5217\u8FDB\u53BB\u3002",
@@ -10147,11 +10271,11 @@ var PromptBuilder = class {
10147
10271
  memoryInitialized = false;
10148
10272
  projectBlock(tools) {
10149
10273
  const permLevel = this.deps.permissionManager?.getLevel() || "default";
10150
- const hasPlanTool = tools.some((t79) => t79.name === "enter_plan_mode");
10151
- const hasLspTool = tools.some((t79) => t79.name === "lsp_diagnostics");
10152
- const hasAskTool = tools.some((t79) => t79.name === "ask_user_question");
10153
- const hasTodoTool = tools.some((t79) => t79.name === "todo");
10154
- const hasTerminal = tools.some((t79) => t79.name === "terminal");
10274
+ const hasPlanTool = tools.some((t81) => t81.name === "enter_plan_mode");
10275
+ const hasLspTool = tools.some((t81) => t81.name === "lsp_diagnostics");
10276
+ const hasAskTool = tools.some((t81) => t81.name === "ask_user_question");
10277
+ const hasTodoTool = tools.some((t81) => t81.name === "todo");
10278
+ const hasTerminal = tools.some((t81) => t81.name === "terminal");
10155
10279
  const needsCommandApproval = hasTerminal && permLevel === "default";
10156
10280
  const plan = this.deps.approvedPlan?.()?.trim();
10157
10281
  const codeSdk = renderSdkDeclaration(this.deps.codeModeTools?.() ?? []);
@@ -11030,8 +11154,8 @@ function imageParts(content) {
11030
11154
  return typeof content === "string" ? [] : content.filter((p) => p.type === "image");
11031
11155
  }
11032
11156
  function toolSignatureOf(config, tools) {
11033
- const direct = tools.map((t79) => t79.name).join("\0");
11034
- const declared = (config.codeModeTools?.() ?? []).map((t79) => t79.name).join("\0");
11157
+ const direct = tools.map((t81) => t81.name).join("\0");
11158
+ const declared = (config.codeModeTools?.() ?? []).map((t81) => t81.name).join("\0");
11035
11159
  return declared ? `${direct}|${declared}` : direct;
11036
11160
  }
11037
11161
  function modelSignatureOf(info) {
@@ -11150,6 +11274,15 @@ var AgentLoop = class {
11150
11274
  isAborted(signal) {
11151
11275
  return this.aborted || signal?.aborted === true;
11152
11276
  }
11277
+ async *drainSteer(input, messages) {
11278
+ const items = input.steer?.take() ?? [];
11279
+ for (const item of items) {
11280
+ const text = contentToText(item);
11281
+ const parts = typeof item === "string" ? void 0 : item;
11282
+ messages.push({ role: "user", content: text, ...parts ? { parts } : {} });
11283
+ yield { type: "steer", text, ...parts ? { parts } : {} };
11284
+ }
11285
+ }
11153
11286
  contextBreakdown(opts) {
11154
11287
  const seg2 = this.prompt.segments();
11155
11288
  return buildContextBreakdown({
@@ -11334,6 +11467,8 @@ var AgentLoop = class {
11334
11467
  const taskNotice = new TaskNoticeTracker(this.config.backgroundTasks);
11335
11468
  let todoNudged = false;
11336
11469
  let idleNudged = false;
11470
+ let blankNudged = false;
11471
+ let blankAfterNudge = false;
11337
11472
  for (let turn = 1; turn <= maxTurns; turn++) {
11338
11473
  if (this.isAborted(input.signal)) {
11339
11474
  yield finish("aborted");
@@ -11356,6 +11491,7 @@ var AgentLoop = class {
11356
11491
  }
11357
11492
  const notice2 = taskNotice.notice();
11358
11493
  if (notice2) messages.push({ role: "user", content: notice2 });
11494
+ if (turn > 1) yield* this.drainSteer(input, messages);
11359
11495
  this.hooks.fire("turn:before", {
11360
11496
  sessionId: input.sessionId,
11361
11497
  userMessage: transformed,
@@ -11433,7 +11569,8 @@ var AgentLoop = class {
11433
11569
  tools,
11434
11570
  system,
11435
11571
  maxSteps: 1,
11436
- ...isAbortSignal(input.signal) ? { signal: input.signal } : {}
11572
+ ...isAbortSignal(input.signal) ? { signal: input.signal } : {},
11573
+ ...this.config.maxOutputTokens ? { maxTokens: this.config.maxOutputTokens } : {}
11437
11574
  },
11438
11575
  streaming,
11439
11576
  ...guard ? { guard } : {},
@@ -11585,6 +11722,11 @@ ${finalText}` };
11585
11722
  usage: result.usage,
11586
11723
  turn
11587
11724
  });
11725
+ if (turn < maxTurns && input.steer?.pending() === true) {
11726
+ messages.push({ role: "assistant", content: finalText || NO_OUTPUT_TEXT });
11727
+ yield* this.drainSteer(input, messages);
11728
+ continue;
11729
+ }
11588
11730
  const wantContinue = await this.hooks.wantsContinue(
11589
11731
  input.sessionId,
11590
11732
  finalText,
@@ -11602,6 +11744,23 @@ ${finalText}` };
11602
11744
  );
11603
11745
  continue;
11604
11746
  }
11747
+ const didToolWork = turns.some((r) => r.toolCalls.length > 0);
11748
+ if (!truncated && blankFinish(finalText, didToolWork)) {
11749
+ if (!blankNudged && turn < maxTurns) {
11750
+ blankNudged = true;
11751
+ yield {
11752
+ type: "notice",
11753
+ code: "blank-response",
11754
+ text: t("agent_run.blank_response")
11755
+ };
11756
+ messages.push(
11757
+ { role: "assistant", content: finalText || NO_OUTPUT_TEXT },
11758
+ { role: "user", content: systemNote(blankResponseNote(finalText.trim().length)) }
11759
+ );
11760
+ continue;
11761
+ }
11762
+ blankAfterNudge = blankNudged;
11763
+ }
11605
11764
  if (!todoNudged && turn < maxTurns) {
11606
11765
  const open = this.config.pendingTodos?.(input.sessionId);
11607
11766
  if (open !== void 0 && open > 0) {
@@ -11630,8 +11789,8 @@ ${finalText}` };
11630
11789
  totalTokens: totalInput + totalOutput,
11631
11790
  turns
11632
11791
  });
11633
- this.maybeLearn(userText, finalText);
11634
- yield finish(truncated ? "length" : "stop");
11792
+ if (!blankAfterNudge) this.maybeLearn(userText, finalText);
11793
+ yield finish(truncated ? "length" : blankAfterNudge ? "blank" : "stop");
11635
11794
  return;
11636
11795
  }
11637
11796
  messages.push({
@@ -12002,6 +12161,7 @@ var EpochConfigSchema = z.object({
12002
12161
  shell: z.enum(SHELL_KINDS).optional(),
12003
12162
  maxTurns: z.int().nonnegative().default(DEFAULT_MAX_TURNS),
12004
12163
  contextLength: z.int().positive().default(2e5),
12164
+ maxOutputTokens: z.int().positive().optional(),
12005
12165
  homeDir: z.string().min(1).default(() => resolveHomeDir()),
12006
12166
  dbPath: z.string().min(1).default(() => dbPath(resolveHomeDir())),
12007
12167
  permission: z.enum(PERMISSION_LEVELS).default("default"),
@@ -12247,12 +12407,12 @@ function finishLayer(source, read, execTrusted, issues) {
12247
12407
  status: gated ? "gated" : "loaded",
12248
12408
  lists: checked.lists,
12249
12409
  scalars: {},
12250
- detail: describe4(layer, gated, checked.lists)
12410
+ detail: describe5(layer, gated, checked.lists)
12251
12411
  },
12252
12412
  file: { ...file, permissions: checked.lists }
12253
12413
  };
12254
12414
  }
12255
- function describe4(layer, gated, lists) {
12415
+ function describe5(layer, gated, lists) {
12256
12416
  const label = layerLabel(layer);
12257
12417
  if (gated) {
12258
12418
  const deny = lists.deny?.length ?? 0;
@@ -13638,7 +13798,7 @@ var ProviderRouter = class {
13638
13798
  }
13639
13799
  async recover(err, state) {
13640
13800
  const { code, recovery } = classifyProviderError(err);
13641
- const message = err instanceof Error ? err.message : String(err);
13801
+ const message = describeProviderError(err);
13642
13802
  const stay = { kind: "continue", ct: state.ct, cm: state.cm };
13643
13803
  if (code === PROVIDER_ABORTED) return { kind: "give-up", message, code };
13644
13804
  if (recovery === "rotate_credential" && this.rotateCredential())
@@ -13829,7 +13989,7 @@ var ProviderRouter = class {
13829
13989
  } catch (err) {
13830
13990
  const cause = streamPartError ?? err;
13831
13991
  if (emitted) {
13832
- yield { type: "error", error: cause instanceof Error ? cause.message : String(cause) };
13992
+ yield { type: "error", error: describeProviderError(cause) };
13833
13993
  return;
13834
13994
  }
13835
13995
  const plan = await this.recover(cause, state);
@@ -14073,6 +14233,7 @@ var SETTING_WRITE_KEYS = [
14073
14233
  "models.utility",
14074
14234
  "fallback.model",
14075
14235
  "contextLength",
14236
+ "maxOutputTokens",
14076
14237
  "compression.enabled",
14077
14238
  "compression.threshold",
14078
14239
  "memory.memoryCharLimit",
@@ -14139,6 +14300,7 @@ var VALUE_SCHEMA = {
14139
14300
  "models.utility": EpochConfigSchema.shape.models.unwrap().shape.utility.unwrap(),
14140
14301
  "fallback.model": EpochConfigSchema.shape.fallback.unwrap().shape.model.unwrap(),
14141
14302
  contextLength: EpochConfigSchema.shape.contextLength.unwrap(),
14303
+ maxOutputTokens: EpochConfigSchema.shape.maxOutputTokens.unwrap(),
14142
14304
  "compression.enabled": EpochConfigSchema.shape.compression.unwrap().shape.enabled.unwrap(),
14143
14305
  "compression.threshold": EpochConfigSchema.shape.compression.unwrap().shape.threshold.unwrap(),
14144
14306
  "memory.memoryCharLimit": EpochConfigSchema.shape.memory.unwrap().shape.memoryCharLimit.unwrap(),
@@ -14559,11 +14721,11 @@ function buildSearchQuery(query) {
14559
14721
  }
14560
14722
  const latinPart = cleaned.replace(CJK_RUN, " ");
14561
14723
  for (const w of latinPart.split(/\s+/)) {
14562
- const t79 = w.trim();
14563
- if (t79.length >= 2) terms.add(t79);
14724
+ const t81 = w.trim();
14725
+ if (t81.length >= 2) terms.add(t81);
14564
14726
  }
14565
14727
  if (terms.size === 0) return null;
14566
- return [...terms].map((t79) => `"${t79.replace(/"/g, "")}"`).join(" OR ");
14728
+ return [...terms].map((t81) => `"${t81.replace(/"/g, "")}"`).join(" OR ");
14567
14729
  }
14568
14730
  // src/memory/db.ts
14569
14731
  var NS2 = "memory";
@@ -15905,6 +16067,14 @@ var SESSION_MIGRATIONS = [
15905
16067
  );
15906
16068
  `);
15907
16069
  }
16070
+ },
16071
+ {
16072
+ id: "sessions-open-turn-from",
16073
+ version: 13,
16074
+ description: "\u4F1A\u8BDD\u8868\u52A0 open_turn_from \u4E00\u5217\uFF08\u88AB\u4E2D\u65AD\u7684\u90A3\u4E00\u8F6E\u8BA4\u5F97\u51FA\u6765\uFF0C2026-09-16\uFF09",
16075
+ up: (db) => {
16076
+ db.exec(`ALTER TABLE sessions ADD COLUMN open_turn_from INTEGER`);
16077
+ }
15908
16078
  }
15909
16079
  ];
15910
16080
  var FTS_EXTERNAL_SCHEMA = `
@@ -15955,7 +16125,7 @@ var FTS_EXTERNAL_SCHEMA = `
15955
16125
  var FTS_EXTERNAL_MIGRATIONS = [
15956
16126
  {
15957
16127
  id: "fts-external-content",
15958
- version: 12,
16128
+ version: 14,
15959
16129
  description: "\u4E24\u5F20 FTS \u8868\u6539\u6210\u5916\u90E8\u5185\u5BB9\u8868\uFF08\u6B63\u6587\u4E0D\u518D\u5B58\u4E09\u4EFD\uFF0C2026-08-21\uFF09",
15960
16130
  up: (db) => {
15961
16131
  db.exec(FTS_EXTERNAL_SCHEMA);
@@ -16151,12 +16321,27 @@ var SessionDB = class {
16151
16321
  }
16152
16322
  getMessages(sessionId, activeOnly = true) {
16153
16323
  const where = activeOnly ? "session_id = ? AND active = 1" : "session_id = ?";
16154
- const rows = this.db.prepare(`SELECT * FROM messages WHERE ${where} ORDER BY timestamp ASC`).all(sessionId);
16324
+ const rows = this.db.prepare(`SELECT * FROM messages WHERE ${where} ORDER BY timestamp ASC, id ASC`).all(sessionId);
16155
16325
  return rows.map((r) => this.rowToMessage(r));
16156
16326
  }
16157
16327
  markObserved(sessionId, messageId) {
16158
16328
  this.db.prepare("UPDATE messages SET observed = 1 WHERE session_id = ? AND id <= ?").run(sessionId, messageId);
16159
16329
  }
16330
+ attachTurnFacts(sessionId, messageId, input) {
16331
+ const sets = [];
16332
+ if (input.turnFacts !== void 0) sets.push("turn_facts = @turnFacts");
16333
+ if (input.finishReason !== void 0) sets.push("finish_reason = @finishReason");
16334
+ if (sets.length === 0) return;
16335
+ this.db.prepare(`UPDATE messages SET ${sets.join(", ")} WHERE session_id = @sessionId AND id = @id`).run({
16336
+ sessionId,
16337
+ id: messageId,
16338
+ turnFacts: encodeTurnFacts(input.turnFacts),
16339
+ finishReason: input.finishReason ?? null
16340
+ });
16341
+ }
16342
+ setOpenTurn(sessionId, from) {
16343
+ this.db.prepare("UPDATE sessions SET open_turn_from = ? WHERE id = ?").run(from, sessionId);
16344
+ }
16160
16345
  lastMessageId(sessionId) {
16161
16346
  const row = this.db.prepare("SELECT MAX(id) AS maxId FROM messages WHERE session_id = ?").get(sessionId);
16162
16347
  return row?.maxId ?? 0;
@@ -16425,6 +16610,7 @@ var SessionDB = class {
16425
16610
  workspaceRoot: row["workspace_root"] ?? void 0,
16426
16611
  startedAt: new Date(row["started_at"]),
16427
16612
  updatedAt: new Date(row["updated_at"] ?? row["started_at"]),
16613
+ openTurnFrom: row["open_turn_from"] ?? null,
16428
16614
  endedAt: row["ended_at"] ? new Date(row["ended_at"]) : void 0,
16429
16615
  endReason: row["end_reason"]
16430
16616
  };
@@ -16537,7 +16723,7 @@ function checkFtsHealth(db) {
16537
16723
  messages,
16538
16724
  tables,
16539
16725
  missingTriggers,
16540
- healthy: missingTriggers.length === 0 && tables.every((t79) => t79.error === null && t79.drift === null && t79.rows === messages),
16726
+ healthy: missingTriggers.length === 0 && tables.every((t81) => t81.error === null && t81.drift === null && t81.rows === messages),
16541
16727
  indexBytes: indexBytesOf(db),
16542
16728
  space: spaceOf(db)
16543
16729
  };
@@ -16826,11 +17012,18 @@ var SessionManager = class {
16826
17012
  const id = this.db.nextMessageId();
16827
17013
  this.db.insertMessage({ ...msg, sessionId, id, timestamp: Date.now() });
16828
17014
  const meta = this.db.getSessionMeta(sessionId);
16829
- if (!meta) return;
17015
+ if (!meta) return id;
16830
17016
  if (!meta.title && msg.role === "user") {
16831
17017
  const title = msg.content.slice(0, 50).replace(/\n/g, " ");
16832
17018
  this.db.updateSessionMeta(sessionId, { title });
16833
17019
  }
17020
+ return id;
17021
+ }
17022
+ attachTurnFacts(sessionId, messageId, input) {
17023
+ this.db.attachTurnFacts(sessionId, messageId, input);
17024
+ }
17025
+ setOpenTurn(sessionId, from) {
17026
+ this.db.setOpenTurn(sessionId, from);
16834
17027
  }
16835
17028
  recordUsage(sessionId, usage) {
16836
17029
  this.db.recordUsage(sessionId, usage);
@@ -17278,7 +17471,7 @@ function inspect(input, resolved, root, accepted) {
17278
17471
  }
17279
17472
  var MAX_RECENT_WORKSPACES = 20;
17280
17473
  var FILE_VERSION2 = 1;
17281
- function describe5(err) {
17474
+ function describe6(err) {
17282
17475
  return err instanceof Error ? err.message : String(err);
17283
17476
  }
17284
17477
  var RecentWorkspaces = class {
@@ -17318,7 +17511,7 @@ var RecentWorkspaces = class {
17318
17511
  parsed = JSON.parse(readFileSync(this.filePath, "utf-8"));
17319
17512
  } catch (err) {
17320
17513
  this.loadErrors.push(
17321
- (lang) => t("workspace.recent_unreadable", { path: this.filePath, reason: describe5(err) }, lang)
17514
+ (lang) => t("workspace.recent_unreadable", { path: this.filePath, reason: describe6(err) }, lang)
17322
17515
  );
17323
17516
  return;
17324
17517
  }
@@ -17371,7 +17564,7 @@ var RecentWorkspaces = class {
17371
17564
  } catch (err) {
17372
17565
  rmSync(tmp, { force: true });
17373
17566
  this.writeErrors.push(
17374
- (lang) => t("workspace.recent_write_failed", { path: this.filePath, reason: describe5(err) }, lang)
17567
+ (lang) => t("workspace.recent_write_failed", { path: this.filePath, reason: describe6(err) }, lang)
17375
17568
  );
17376
17569
  }
17377
17570
  }
@@ -17383,7 +17576,7 @@ function isRecentWorkspace(value) {
17383
17576
  }
17384
17577
  var MAX_LAST_OPEN_SESSIONS = 20;
17385
17578
  var FILE_VERSION3 = 1;
17386
- function describe6(err) {
17579
+ function describe7(err) {
17387
17580
  return err instanceof Error ? err.message : String(err);
17388
17581
  }
17389
17582
  var LastOpenSessions = class {
@@ -17422,7 +17615,7 @@ var LastOpenSessions = class {
17422
17615
  parsed = JSON.parse(readFileSync(this.filePath, "utf-8"));
17423
17616
  } catch (err) {
17424
17617
  this.loadErrors.push(
17425
- (lang) => t("last_session.unreadable", { path: this.filePath, reason: describe6(err) }, lang)
17618
+ (lang) => t("last_session.unreadable", { path: this.filePath, reason: describe7(err) }, lang)
17426
17619
  );
17427
17620
  return;
17428
17621
  }
@@ -17449,7 +17642,7 @@ var LastOpenSessions = class {
17449
17642
  } catch (err) {
17450
17643
  rmSync(tmp, { force: true });
17451
17644
  this.writeErrors.push(
17452
- (lang) => t("last_session.write_failed", { path: this.filePath, reason: describe6(err) }, lang)
17645
+ (lang) => t("last_session.write_failed", { path: this.filePath, reason: describe7(err) }, lang)
17453
17646
  );
17454
17647
  }
17455
17648
  }
@@ -17459,6 +17652,9 @@ function isLastOpenSession(value) {
17459
17652
  const v = value;
17460
17653
  return typeof v["root"] === "string" && v["root"].length > 0 && typeof v["sessionId"] === "string" && v["sessionId"].length > 0 && typeof v["at"] === "number";
17461
17654
  }
17655
+ function ruleAskActive(level) {
17656
+ return level !== "bypass";
17657
+ }
17462
17658
  function checkCodeExec(isolation) {
17463
17659
  if (isolation === "os") {
17464
17660
  return { allowed: true, reason: t("permission_reason.sandbox_os"), code: "sandbox-isolation" };
@@ -17470,8 +17666,7 @@ function checkCodeExec(isolation) {
17470
17666
  code: "sandbox-isolation"
17471
17667
  };
17472
17668
  }
17473
- function checkAuto(operation, isolation) {
17474
- if (operation.type === "code_exec") return checkCodeExec(isolation);
17669
+ function checkAuto() {
17475
17670
  return { allowed: true, code: "level-default" };
17476
17671
  }
17477
17672
  function checkPlan(operation) {
@@ -17529,7 +17724,7 @@ function decideByLevel(level, operation, isolation, extraRoots = []) {
17529
17724
  case "bypass":
17530
17725
  return { allowed: true, code: "level-default" };
17531
17726
  case "auto":
17532
- return checkAuto(operation, isolation);
17727
+ return checkAuto();
17533
17728
  case "plan":
17534
17729
  return checkPlan(operation);
17535
17730
  case "acceptEdits":
@@ -17707,11 +17902,11 @@ var ApprovalCache = class {
17707
17902
  return !rel.startsWith("..") && !isAbsolute(rel);
17708
17903
  }
17709
17904
  normalizeTarget(target) {
17710
- const t79 = target.trim();
17711
- if (!t79) return "";
17712
- const unix = t79.replace(/\\/g, "/");
17905
+ const t81 = target.trim();
17906
+ if (!t81) return "";
17907
+ const unix = t81.replace(/\\/g, "/");
17713
17908
  if (unix.startsWith("/") || /^[A-Za-z]:\//.test(unix)) return resolve(unix);
17714
- return t79;
17909
+ return t81;
17715
17910
  }
17716
17911
  load() {
17717
17912
  try {
@@ -17814,9 +18009,9 @@ function createSharedPermissionState(cache) {
17814
18009
  };
17815
18010
  }
17816
18011
  function cacheKeyFor(raw) {
17817
- const t79 = raw.trim();
17818
- if (!t79) return null;
17819
- return t79.slice(0, 500);
18012
+ const t81 = raw.trim();
18013
+ if (!t81) return null;
18014
+ return t81.slice(0, 500);
17820
18015
  }
17821
18016
  // src/permission/manager.ts
17822
18017
  var log3 = createLogger("permission");
@@ -17989,16 +18184,22 @@ var PermissionManager = class _PermissionManager {
17989
18184
  }
17990
18185
  const cached = this.approvalCacheActive() ? this.cachedDecision(operation) : null;
17991
18186
  if (cached) return cached;
17992
- if (listMatch?.verdict === "ask") {
17993
- return {
17994
- allowed: false,
17995
- requireApproval: true,
17996
- reason: t("permission_reason.rule_ask", { rule: listMatch.rule }),
17997
- code: "rule-match",
17998
- ...this.rememberFlag()
17999
- };
18187
+ const asked = listMatch?.verdict === "ask" ? {
18188
+ allowed: false,
18189
+ requireApproval: true,
18190
+ reason: t("permission_reason.rule_ask", { rule: listMatch.rule }),
18191
+ code: "rule-match"
18192
+ } : ruleDecision?.requireApproval ?? false ? ruleDecision : null;
18193
+ if (asked) {
18194
+ if (!ruleAskActive(this.level)) {
18195
+ return {
18196
+ allowed: true,
18197
+ reason: t("permission_reason.bypass_rule_ask", { reason: asked.reason ?? "" }),
18198
+ code: asked.code
18199
+ };
18200
+ }
18201
+ return { ...asked, ...this.rememberFlag() };
18000
18202
  }
18001
- if (ruleDecision?.requireApproval) return { ...ruleDecision, ...this.rememberFlag() };
18002
18203
  if (listMatch?.verdict === "allow") {
18003
18204
  return {
18004
18205
  allowed: true,
@@ -18146,10 +18347,13 @@ function byRule(rules, probe) {
18146
18347
  }
18147
18348
  return hit ? { ...hit, conditional } : { verdict: null, conditional };
18148
18349
  }
18350
+ function effectiveRules(rules, level) {
18351
+ return ruleAskActive(level) ? rules : { ...rules, ask: [] };
18352
+ }
18149
18353
  function gateForTool(tool, rules, level, isolation) {
18150
18354
  const type = mapOperation(tool);
18151
18355
  const probe = { type, toolName: tool.name };
18152
- const rule = byRule(rules, probe);
18356
+ const rule = byRule(effectiveRules(rules, level), probe);
18153
18357
  if (rule.verdict) {
18154
18358
  return {
18155
18359
  type,
@@ -18741,6 +18945,12 @@ function pruneRecordings(dir, opts = {}) {
18741
18945
  }
18742
18946
  return { removed: removed.filter((p) => !existsSync(p)), remainingBytes: Math.max(0, total) };
18743
18947
  }
18948
+ function removeRecordings(dir) {
18949
+ try {
18950
+ rmSync(dir, { recursive: true, force: true });
18951
+ } catch {
18952
+ }
18953
+ }
18744
18954
  function readRecording(path) {
18745
18955
  if (!existsSync(path)) return [];
18746
18956
  const out = [];
@@ -20175,7 +20385,7 @@ var HookManager = class {
20175
20385
  return { blocked: true, reason: result.rejectReason || t("hook_load.rejected") };
20176
20386
  }
20177
20387
  } catch (err) {
20178
- this.log("warn", `[HookManager] ${type} \u7684 command hook \u6267\u884C\u5F02\u5E38: ${describe8(err)}`, {
20388
+ this.log("warn", `[HookManager] ${type} \u7684 command hook \u6267\u884C\u5F02\u5E38: ${describe9(err)}`, {
20179
20389
  hookType: type,
20180
20390
  command: config.command
20181
20391
  });
@@ -20193,7 +20403,7 @@ var HookManager = class {
20193
20403
  (_, reject2) => setTimeout(() => reject2(new Error("Hook timeout")), HOOK_TIMEOUT_MS)
20194
20404
  )
20195
20405
  ]).catch((err) => {
20196
- this.log("warn", `[HookManager] ${type} (${reg.plugin}) \u5931\u8D25: ${describe8(err)}`, {
20406
+ this.log("warn", `[HookManager] ${type} (${reg.plugin}) \u5931\u8D25: ${describe9(err)}`, {
20197
20407
  hookType: type,
20198
20408
  plugin: reg.plugin
20199
20409
  });
@@ -20205,7 +20415,7 @@ var HookManager = class {
20205
20415
  if (!matchesHook(entry.matcher, event)) continue;
20206
20416
  for (const config of entry.configs) {
20207
20417
  runCommandHook(config, event, ctx.workDir).then((result) => reportIfNeverRan(this.log, type, config, result)).catch((err) => {
20208
- this.log("warn", `[HookManager] ${type} \u7684 command hook \u5F02\u6B65\u5F02\u5E38: ${describe8(err)}`, {
20418
+ this.log("warn", `[HookManager] ${type} \u7684 command hook \u5F02\u6B65\u5F02\u5E38: ${describe9(err)}`, {
20209
20419
  hookType: type,
20210
20420
  command: config.command
20211
20421
  });
@@ -20226,7 +20436,7 @@ var HookManager = class {
20226
20436
  ]);
20227
20437
  if (result !== null && result !== void 0) return result;
20228
20438
  } catch (err) {
20229
- this.log("warn", `[HookManager] ${type} (${reg.plugin}) \u5931\u8D25: ${describe8(err)}`, {
20439
+ this.log("warn", `[HookManager] ${type} (${reg.plugin}) \u5931\u8D25: ${describe9(err)}`, {
20230
20440
  hookType: type,
20231
20441
  plugin: reg.plugin
20232
20442
  });
@@ -20247,7 +20457,7 @@ var HookManager = class {
20247
20457
  ]);
20248
20458
  if (result) results.push(result);
20249
20459
  } catch (err) {
20250
- this.log("warn", `[HookManager] ${type} (${reg.plugin}) \u5931\u8D25: ${describe8(err)}`, {
20460
+ this.log("warn", `[HookManager] ${type} (${reg.plugin}) \u5931\u8D25: ${describe9(err)}`, {
20251
20461
  hookType: type,
20252
20462
  plugin: reg.plugin
20253
20463
  });
@@ -20264,7 +20474,7 @@ var HookManager = class {
20264
20474
  const verdict = verdictOf2(result);
20265
20475
  if (verdict) results.push(verdict);
20266
20476
  } catch (err) {
20267
- this.log("warn", `[HookManager] ${type} \u7684 command hook \u6267\u884C\u5F02\u5E38: ${describe8(err)}`, {
20477
+ this.log("warn", `[HookManager] ${type} \u7684 command hook \u6267\u884C\u5F02\u5E38: ${describe9(err)}`, {
20268
20478
  hookType: type,
20269
20479
  command: config.command
20270
20480
  });
@@ -20280,7 +20490,7 @@ var HookManager = class {
20280
20490
  return [...list].sort((a, b) => a.priority - b.priority);
20281
20491
  }
20282
20492
  };
20283
- function describe8(err) {
20493
+ function describe9(err) {
20284
20494
  return err instanceof Error ? err.message : String(err);
20285
20495
  }
20286
20496
  function verdictOf2(result) {
@@ -21577,7 +21787,7 @@ async function withStaged(source, opts, fn) {
21577
21787
  shape = existsSync(join(unpacked, SKILL_FILE)) ? "skill-dir" : "tree";
21578
21788
  }
21579
21789
  const staged = stageImport(root, staging, shape, opts.lang);
21580
- const preview3 = describe9(source, form, staged.skills, staged.issues, opts.existing, opts.lang);
21790
+ const preview3 = describe10(source, form, staged.skills, staged.issues, opts.existing, opts.lang);
21581
21791
  if (preview3.skills.length === 0) {
21582
21792
  const detail = t("skill.import_empty", { path: source }, opts.lang);
21583
21793
  return { ok: false, reason: "empty", detail, issues: preview3.issues };
@@ -21588,7 +21798,7 @@ async function withStaged(source, opts, fn) {
21588
21798
  rmSync(unpacked, { recursive: true, force: true });
21589
21799
  }
21590
21800
  }
21591
- function describe9(source, form, staged, issues, existing, lang) {
21801
+ function describe10(source, form, staged, issues, existing, lang) {
21592
21802
  const byName = new Map(existing.map((s) => [s.name, s.scope]));
21593
21803
  const entries2 = [];
21594
21804
  const taken = /* @__PURE__ */ new Set();
@@ -22441,7 +22651,7 @@ ${extra}` : withGoal;
22441
22651
  var FILE_VERSION4 = 1;
22442
22652
  var LEVELS = ["trusted", "untrusted"];
22443
22653
  var SCOPES = ["directory", "directory-tree"];
22444
- function describe10(err) {
22654
+ function describe11(err) {
22445
22655
  return err instanceof Error ? err.message : String(err);
22446
22656
  }
22447
22657
  function covers(base, target, scope) {
@@ -22515,7 +22725,7 @@ var TrustManager = class {
22515
22725
  raw = readFileSync(this.filePath, "utf-8");
22516
22726
  } catch (err) {
22517
22727
  this.loadErrors.push(
22518
- t("trust_gate.record_read_failed", { path: this.filePath, reason: describe10(err) })
22728
+ t("trust_gate.record_read_failed", { path: this.filePath, reason: describe11(err) })
22519
22729
  );
22520
22730
  return;
22521
22731
  }
@@ -22524,7 +22734,7 @@ var TrustManager = class {
22524
22734
  parsed = JSON.parse(raw);
22525
22735
  } catch (err) {
22526
22736
  this.loadErrors.push(
22527
- t("trust_gate.record_bad_json", { path: this.filePath, reason: describe10(err) })
22737
+ t("trust_gate.record_bad_json", { path: this.filePath, reason: describe11(err) })
22528
22738
  );
22529
22739
  return;
22530
22740
  }
@@ -22573,7 +22783,7 @@ var TrustManager = class {
22573
22783
  } catch (err) {
22574
22784
  rmSync(tmp, { force: true });
22575
22785
  throw new Error(
22576
- t("trust_gate.record_write_failed", { path: this.filePath, reason: describe10(err) })
22786
+ t("trust_gate.record_write_failed", { path: this.filePath, reason: describe11(err) })
22577
22787
  );
22578
22788
  }
22579
22789
  }
@@ -22956,4 +23166,4 @@ function trunc(stdout, stderr) {
22956
23166
  * `--tree` 的命令帮助里,让用户自己知道 `--tree` 意味着什么。
22957
23167
  */
22958
23168
 
22959
- export { AGENT_ROLE_DIAG_MODULE, ARTIFACT_MAX_TOTAL_BYTES, ARTIFACT_RETENTION_DEFAULTS, ATTACHMENT_MAX_TOTAL_BYTES, ATTACHMENT_RETENTION_DEFAULTS, AgentLoop, ApprovalCache, BLOCKED_TOOLS, BudgetGuard, BudgetStore, CHECKPOINT_MAX_TOTAL_BYTES, CLAUDE_EVENT_NAMES, CLAUDE_TOOL_NAMES, CODE_MODE_LIMITS, CODE_MODE_SDK_TAG, CONFIG_KEYS, CURRENT_CONFIG_VERSION, CheckpointManager, CheckpointStore, CodeSandbox, ComplianceEngine, ContextCompressor, DEFAULT_COMPLIANCE_ACTIONS, DEFAULT_COMPLIANCE_SETTINGS, DEFAULT_COMPRESSION_THRESHOLD, DEFAULT_GOAL_MAX_ROUNDS, DEFAULT_MAX_HOLD_CHARS, DelegateManager, EMPTY_RULES, EPOCH_DISK_LEDGER, EpochConfigSchema, FTS_TABLES, FTS_TRIGGERS, GOAL_BLOCK_CODES, GoalService, GoalStore, HEADLESS_AUDIT_CODES, HookManager, INSTRUCTION_BUDGET_CHARS, INSTRUCTION_FILES, ImageLoadError, ImportTrustStore, LAUNCHD_LABEL_PREFIX, LOCK_HEARTBEAT_MS, LOCK_STALE_MS, LastOpenSessions, MARKETPLACE_DISPLAY_FIELDS, MARKETPLACE_FILE, MAX_AUDIT_ENTRIES, MAX_COMMAND_DEPTH, MAX_GOAL_MAX_ROUNDS, MAX_IMPORT_DEPTH, MAX_LAST_OPEN_SESSIONS, MAX_OBJECTIVE_CHARS, MAX_REASON_CHARS, MAX_RECENT_WORKSPACES, MODEL_GIVE_UP_THRESHOLD, MULTIMODAL_DEFAULTS, ManagedPolicyError, ManagedSettingsSchema, MemoryManager, MemoryReviewer, ModelFailureTracker, NOMINAL_TOTAL_BYTES, NO_REVEALED_TOOLS, PACK_EXCLUDES, PACK_MAX_BYTES, PACK_MAX_FILES, PERMISSION_AUDIT_CODES, PLUGIN_LAYOUT, PLUGIN_MANIFEST_FILE, PLUGIN_MANIFEST_KEYS, PLUGIN_NAME_PATTERN, PLUGIN_ROOT_ENV, PLUGIN_ROOT_TOKEN, PLUGIN_VISIBILITY, POLICY_DECISIONS, PROBE_VERSION, PROJECT_AGENTS_SUBDIR, PROVIDER_NO_CREDENTIAL, PermissionManager, PlanModeState, PluginAuthorSchema, PluginStore, PolicyRuleSchema, ProviderError, ProviderRouter, RECORDING_KEEP_RUNS, RECORDING_MAX_BYTES, ROLE_FRONTMATTER_SCHEMA, RUN_CODE_TOOL, RecentWorkspaces, SANDBOX_COVERS, SANDBOX_EXCLUDES, SCALAR_KEYS, SCHEDULE_DEFAULTS, SCHEDULE_DEFAULT_ALLOWLIST, SCHEDULE_ISSUE_CODES, SCHTASKS_FOLDER, SESSION_MESSAGES_READ_TOOL, SESSION_MESSAGES_SEARCH_TOOL, SESSION_QUERY_TOOLS, SESSION_SEARCH_TOOL, SESSION_TRACE_TOOL, SETTINGS_LAYER_ORDER, SETTING_WRITE_KEYS, SETTING_WRITE_LAYERS, SKILL_CREATE_TOOL, SKILL_EDIT_TOOL, SKILL_PATCH_TOOL, SKILL_VIEW_TOOL, SKILL_WRITE_FILE_TOOL, SLASH_COMMANDS_DIAG_MODULE, ScheduleRecorder, ScheduleRegistrar, ScheduleStore, SessionManager, SessionQueries, SessionReferences, SettingsFileError, SettingsFileSchema, SkillLearner, SkillSystem, TOOL_SEARCH_TOOL, TaskNoticeTracker, ToolRegistry, TrackerDB, TrustManager, Workspace, acquireScheduleLock, addMarketplace, addUsage, admitArtifact, admitArtifacts, affectedPaths, artifactLaunchArgv, artifactOpenRefusal, assertLevelAllowed, blockedRoleTools, buildContextBreakdown, buildFireArgv, buildFtsMatchQuery, buildSchemaExports, buildSystemPrompt, buildTrigramMatchQuery, builtinRoles, checkEpochVersion, checkFtsHealth, checkShadowing, classifyProviderError, clearModelCache, coalesceRecording, codeModeWorkerPath, commandNameFromRelPath, compileRuleLists, compressionOptions, computeCost, computeCostMicros, computeExecHash, countRules, createAllowAllGate, createAllowAllImportGate, createAskQuestionTool, createCodeExecTool, createDelegateTool, createDenyAllGate, createDenyAllImportGate, createGoalTool, createImportGate, createMemoryTool, createPlanModeTools, createRoleFile, createRoleScope, createRunCodeTool, createScheduleDraftTool, createSessionMessagesReadTool, createSessionMessagesSearchTool, createSessionSearchTool, createSessionSearchTools, createSessionTraceTool, createSkillViewTool, createSkillWriteTools, createTodoTool, createToolRevealState, createToolScope, createToolSearchTool, createTrustGate, currentEpochVersion, decideImport, decideTrust, defaultConfig, defaultModelOf, describeArtifactRefusal, describeBackgroundTask, describeHeadlessPolicy, describeIsolation, describeJsonError, diagnoseSchedules, discoverMarkdown, discoverModels, discoverProject, displayCurrency, draftCommandLine, draftWidening, escapeRuleContent, estimateImageTokens, estimateRunTokens, estimateTokens, evaluateSelection, expandCommand, expandImports, explainSetting, extractArchive, findInstructionFiles, findProjectInstructions, findRole, formatBytes, formatSkillIndex, formatUsd, gateForTool, getCapability, getConfigIssues, getConfigOrigins, getImportGate, getTrustGate, hasDedicatedExecContent, hasExecTierContent, hasPromptCaching, hasProviderCredentials, hasReadTierContent, imageFromBase64, imageFromPath, imagePartTokens, importSkills, installPlugin, instructionDirs, instructionNotices, intervalSlots, inventoryProjectExtensions, inventoryTotal, isBlockCode, isCodeModeDeferred, isEmptyRules, isGoalPhase, isNonInteractive, isReadOnlySubCall, isSettingWriteLayer, isValidPluginName, isWithinWindow, isWritableSettingKey, labelSlug, layerRank, listRunningSchedules, listSessionCandidates, listWorkspaceFiles, loadCommandDefinitions, loadCommandFile, loadCommands, loadConfig, loadHookSources, loadKeybindings, loadLexiconDir, loadLexiconFiles, loadPlugins, loadPolicyFiles, loadPolicyRules, loadRoleDefinitions, loadRoleDir, loadedImports, localDateString, managedSwitchNotes, mapClaudeToolName, mapEpochToolName, mapOperationType, matchPreauthorization, matchRuleLists, matchesHook, mentionsPluginRoot, mergeHeadlessPolicy, mergeRoles, mergeSchedulePatch, microsToUsd, modelListCandidates, needsAllowlist, nextFallbackModel, nextRunAt, noConfigOrigins, noManagedPolicy, noPlugins, openArtifact, originOf, packFileName, packPlugin, parseClaudeSettingsHooks, parseClock, parseDate, parseFrontmatter, parseHooksConfig, parseHooksConfigVerbose, parseImportLine, parseModelList, parseRoleDefinition, parseScheduleDraft, parseSkillFrontmatter, parseTrigger, pendingImageTokens, persistParts, persistToolResults, persistedUsage, planPack, previewSkillImport, pricingFor, projectEntryForDisplay, pruneArtifacts, pruneAttachments, pruneRecordings, pruneSchedules, readImageSize, readMarketplaces, readPluginManifest, readPluginRecords, readProviderKeyEnv, readRecording, readSessionSurface, reclaimFtsSpace, redactLine, refreshOpenRouterMetadata, removeMarketplace, removeSessionArtifacts, removeSessionAttachments, renderImportTree, renderProjectContext, renderSdkDeclaration, renderSelfIndex, repairSchedules, resolveArtifactRetention, resolveCodeModeWorker, resolveComplianceDirs, resolveEntrySource, resolveInWorkspace, resolveMarketplaceRef, resolveMentions, resolveMultimodalPolicy, resolvePolicyDirs, resolvePricingAt, resolveProjectRoot, resolveScheduleBackend, resolveSessionReference, resolveSessionVisibility, resolveSettings, resolveSkillDirs, resolveSource, resolveTar, resolveWorkspace, restoreParts, revealScopedProvider, roleScopedProvider, roleSourceLabel, ruleCovers, ruleFromString, ruleToString, runCode, runCommand2 as runCommand, sanitizeArgNames, sanitizeCommand, sanitizeFtsQuery, sanitizePath, sanitizeToolOutput, scanInstructions, scanPluginDir, scanSkillDirs, searchMarketplaces, setDisplayCurrency, setImportGate, setPluginEnabled, setTrustGate, settingValueChoices, settingValueKind, settingWriteApply, settingWriteLayers, settingWriteTargets, skillIndexDescription, skillIndexResidency, skillIndexStats, sniffMediaType, splitFrontmatter, staticToolProvider, stripArtifactData, substitutePluginRoot, suggestRuleFromApproval, systemOpenArgv, systemPromptSegments, toPosix, toolDefinitionTokens, toolMatches, toolTableTokens, totalTokens, traceSession, triggerPeriodMs, unescapeRuleContent, uninstallPlugin, unknownRoleSkills, unknownRoleTools, unloadedInstructionFiles, updateMarketplace, updatePlugin, usdToMicros, validateSchedule, validateTrigger, validateWindow, withGoalCompression, withGoalPrompt, workspaceDisplayPath, writeSettingValue };
23169
+ export { AGENT_ROLE_DIAG_MODULE, ARTIFACT_MAX_TOTAL_BYTES, ARTIFACT_RETENTION_DEFAULTS, ATTACHMENT_MAX_TOTAL_BYTES, ATTACHMENT_RETENTION_DEFAULTS, AgentLoop, ApprovalCache, BLOCKED_TOOLS, BudgetGuard, BudgetStore, CHECKPOINT_MAX_TOTAL_BYTES, CLAUDE_EVENT_NAMES, CLAUDE_TOOL_NAMES, CODE_MODE_LIMITS, CODE_MODE_SDK_TAG, CONFIG_KEYS, CURRENT_CONFIG_VERSION, CheckpointManager, CheckpointStore, CodeSandbox, ComplianceEngine, ContextCompressor, DEFAULT_COMPLIANCE_ACTIONS, DEFAULT_COMPLIANCE_SETTINGS, DEFAULT_COMPRESSION_THRESHOLD, DEFAULT_GOAL_MAX_ROUNDS, DEFAULT_MAX_HOLD_CHARS, DelegateManager, EMPTY_RULES, EPOCH_DISK_LEDGER, EpochConfigSchema, FTS_TABLES, FTS_TRIGGERS, GOAL_BLOCK_CODES, GoalService, GoalStore, HEADLESS_AUDIT_CODES, HookManager, INSTRUCTION_BUDGET_CHARS, INSTRUCTION_FILES, ImageLoadError, ImportTrustStore, LAUNCHD_LABEL_PREFIX, LOCK_HEARTBEAT_MS, LOCK_STALE_MS, LastOpenSessions, MARKETPLACE_DISPLAY_FIELDS, MARKETPLACE_FILE, MAX_AUDIT_ENTRIES, MAX_COMMAND_DEPTH, MAX_GOAL_MAX_ROUNDS, MAX_IMPORT_DEPTH, MAX_LAST_OPEN_SESSIONS, MAX_OBJECTIVE_CHARS, MAX_REASON_CHARS, MAX_RECENT_WORKSPACES, MODEL_GIVE_UP_THRESHOLD, MULTIMODAL_DEFAULTS, ManagedPolicyError, ManagedSettingsSchema, MemoryManager, MemoryReviewer, ModelFailureTracker, NOMINAL_TOTAL_BYTES, NO_REVEALED_TOOLS, PACK_EXCLUDES, PACK_MAX_BYTES, PACK_MAX_FILES, PERMISSION_AUDIT_CODES, PLUGIN_LAYOUT, PLUGIN_MANIFEST_FILE, PLUGIN_MANIFEST_KEYS, PLUGIN_NAME_PATTERN, PLUGIN_ROOT_ENV, PLUGIN_ROOT_TOKEN, PLUGIN_VISIBILITY, POLICY_DECISIONS, PROBE_VERSION, PROJECT_AGENTS_SUBDIR, PROVIDER_NO_CREDENTIAL, PermissionManager, PlanModeState, PluginAuthorSchema, PluginStore, PolicyRuleSchema, ProviderError, ProviderRouter, RECORDING_KEEP_RUNS, RECORDING_MAX_BYTES, ROLE_FRONTMATTER_SCHEMA, RUN_CODE_TOOL, RecentWorkspaces, SANDBOX_COVERS, SANDBOX_EXCLUDES, SCALAR_KEYS, SCHEDULE_DEFAULTS, SCHEDULE_DEFAULT_ALLOWLIST, SCHEDULE_ISSUE_CODES, SCHTASKS_FOLDER, SESSION_MESSAGES_READ_TOOL, SESSION_MESSAGES_SEARCH_TOOL, SESSION_QUERY_TOOLS, SESSION_SEARCH_TOOL, SESSION_TRACE_TOOL, SETTINGS_LAYER_ORDER, SETTING_WRITE_KEYS, SETTING_WRITE_LAYERS, SKILL_CREATE_TOOL, SKILL_EDIT_TOOL, SKILL_PATCH_TOOL, SKILL_VIEW_TOOL, SKILL_WRITE_FILE_TOOL, SLASH_COMMANDS_DIAG_MODULE, ScheduleRecorder, ScheduleRegistrar, ScheduleStore, SessionManager, SessionQueries, SessionReferences, SettingsFileError, SettingsFileSchema, SkillLearner, SkillSystem, TOOL_SEARCH_TOOL, TaskNoticeTracker, ToolRegistry, TrackerDB, TrustManager, Workspace, acquireScheduleLock, addMarketplace, addUsage, admitArtifact, admitArtifacts, affectedPaths, artifactLaunchArgv, artifactOpenRefusal, assertLevelAllowed, blockedRoleTools, buildContextBreakdown, buildFireArgv, buildFtsMatchQuery, buildSchemaExports, buildSystemPrompt, buildTrigramMatchQuery, builtinRoles, checkEpochVersion, checkFtsHealth, checkShadowing, classifyProviderError, clearModelCache, coalesceRecording, codeModeWorkerPath, commandNameFromRelPath, compileRuleLists, compressionOptions, computeCost, computeCostMicros, computeExecHash, countRules, createAllowAllGate, createAllowAllImportGate, createAskQuestionTool, createCodeExecTool, createDelegateTool, createDenyAllGate, createDenyAllImportGate, createGoalTool, createImportGate, createMemoryTool, createPlanModeTools, createRoleFile, createRoleScope, createRunCodeTool, createScheduleDraftTool, createSessionMessagesReadTool, createSessionMessagesSearchTool, createSessionSearchTool, createSessionSearchTools, createSessionTraceTool, createSkillViewTool, createSkillWriteTools, createTodoTool, createToolRevealState, createToolScope, createToolSearchTool, createTrustGate, currentEpochVersion, decideImport, decideTrust, defaultConfig, defaultModelOf, describeArtifactRefusal, describeBackgroundTask, describeHeadlessPolicy, describeIsolation, describeJsonError, diagnoseSchedules, discoverMarkdown, discoverModels, discoverProject, displayCurrency, draftCommandLine, draftWidening, escapeRuleContent, estimateImageTokens, estimateRunTokens, estimateTokens, evaluateSelection, expandCommand, expandImports, explainSetting, extractArchive, findInstructionFiles, findProjectInstructions, findRole, formatBytes, formatSkillIndex, formatUsd, gateForTool, getCapability, getConfigIssues, getConfigOrigins, getImportGate, getTrustGate, hasDedicatedExecContent, hasExecTierContent, hasPromptCaching, hasProviderCredentials, hasReadTierContent, imageFromBase64, imageFromPath, imagePartTokens, importSkills, installPlugin, instructionDirs, instructionNotices, intervalSlots, inventoryProjectExtensions, inventoryTotal, isBlockCode, isCodeModeDeferred, isEmptyRules, isGoalPhase, isNonInteractive, isReadOnlySubCall, isSettingWriteLayer, isValidPluginName, isWithinWindow, isWritableSettingKey, labelSlug, layerRank, listRunningSchedules, listSessionCandidates, listWorkspaceFiles, loadCommandDefinitions, loadCommandFile, loadCommands, loadConfig, loadHookSources, loadKeybindings, loadLexiconDir, loadLexiconFiles, loadPlugins, loadPolicyFiles, loadPolicyRules, loadRoleDefinitions, loadRoleDir, loadedImports, localDateString, managedSwitchNotes, mapClaudeToolName, mapEpochToolName, mapOperationType, matchPreauthorization, matchRuleLists, matchesHook, mentionsPluginRoot, mergeHeadlessPolicy, mergeRoles, mergeSchedulePatch, microsToUsd, modelListCandidates, needsAllowlist, nextFallbackModel, nextRunAt, noConfigOrigins, noManagedPolicy, noPlugins, openArtifact, originOf, packFileName, packPlugin, parseClaudeSettingsHooks, parseClock, parseDate, parseFrontmatter, parseHooksConfig, parseHooksConfigVerbose, parseImportLine, parseModelList, parseRoleDefinition, parseScheduleDraft, parseSkillFrontmatter, parseTrigger, pendingImageTokens, persistParts, persistToolResults, persistedUsage, planPack, previewSkillImport, pricingFor, projectEntryForDisplay, pruneArtifacts, pruneAttachments, pruneRecordings, pruneSchedules, readImageSize, readMarketplaces, readPluginManifest, readPluginRecords, readProviderKeyEnv, readRecording, readSessionSurface, reclaimFtsSpace, redactLine, refreshOpenRouterMetadata, removeMarketplace, removeRecordings, removeRoleFile, removeSessionArtifacts, removeSessionAttachments, renderImportTree, renderProjectContext, renderSdkDeclaration, renderSelfIndex, repairSchedules, resolveArtifactRetention, resolveCodeModeWorker, resolveComplianceDirs, resolveEntrySource, resolveInWorkspace, resolveMarketplaceRef, resolveMentions, resolveMultimodalPolicy, resolvePolicyDirs, resolvePricingAt, resolveProjectRoot, resolveScheduleBackend, resolveSessionReference, resolveSessionVisibility, resolveSettings, resolveSkillDirs, resolveSource, resolveTar, resolveWorkspace, restoreParts, revealScopedProvider, roleScopedProvider, roleSourceLabel, ruleCovers, ruleFromString, ruleToString, runCode, runCommand2 as runCommand, sanitizeArgNames, sanitizeCommand, sanitizeFtsQuery, sanitizePath, sanitizeToolOutput, scanInstructions, scanPluginDir, scanSkillDirs, searchMarketplaces, setDisplayCurrency, setImportGate, setPluginEnabled, setTrustGate, settingValueChoices, settingValueKind, settingWriteApply, settingWriteLayers, settingWriteTargets, skillIndexDescription, skillIndexResidency, skillIndexStats, sniffMediaType, splitFrontmatter, staticToolProvider, stripArtifactData, substitutePluginRoot, suggestRuleFromApproval, systemOpenArgv, systemPromptSegments, toPosix, toolDefinitionTokens, toolMatches, toolTableTokens, totalTokens, traceSession, triggerPeriodMs, unescapeRuleContent, uninstallPlugin, unknownRoleSkills, unknownRoleTools, unloadedInstructionFiles, updateMarketplace, updatePlugin, usdToMicros, validateSchedule, validateTrigger, validateWindow, withGoalCompression, withGoalPrompt, workspaceDisplayPath, writeSettingValue };