@epoch-agent/core 2.2.0 → 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (4) hide show
  1. package/README.md +1 -1
  2. package/dist/index.d.ts +12363 -12342
  3. package/dist/index.js +254 -147
  4. package/package.json +3 -3
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { REASONING_EFFORTS, MODEL_ENTRY_PROTOCOLS, PROVIDER_TYPES, isModelEntryId, parseModelRef, OPERATION_TYPES as OPERATION_TYPES$1, COMPLIANCE_CATEGORIES, COMPLIANCE_ACTIONS, SEARCH_PROVIDER_TYPES, CURRENCIES, LANGS, isSettingsPaneId, SETTINGS_PANE_IDS, BRAND_WHEN_SIDEBAR_COLLAPSED, PERMISSION_LEVELS, SHELL_KINDS, cronTimes, SCHEDULE_MAX_TIMES_PER_DAY, SCHEDULE_INTERVAL_MIN_MINUTES, SCHEDULE_INTERVAL_MAX_MINUTES, ToolExposure, MIN_OPTIONS, MAX_OPTIONS, MAX_HEADER_CHARS, MAX_QUESTIONS, isPermissionLevel, SCHEDULE_DRAFT_TOOL, isValidAgentRoleName, DEFAULT_AGENT_ROLE, isValidCommandName, RESERVED_COMMAND_NAMES, isWirePluginArchiveName, systemNote, formatMoney, totalUsageTokens, NOOP_TELEMETRY, METRIC, contentToText, GEN_AI, isPromptOversize, promptTokens, entrySecretName, isEntrySecretName, entryRef, KEY_ACTIONS, tableOf, perAction, isKeyAction, parseSequence, RESERVED_CHORDS, chordId, sequenceId, ACTION_CONTEXTS, SEQUENCE_CONTEXTS, assertNeverPart, normalizeAppearanceTranslucent, MAX_ATTACH_FILES, MAX_ATTACH_TOTAL_BYTES, MAX_SESSION_REFS, utf8ByteLength, truncateToBudget, attachSessionSurface, isContextNearlyFull, isOperationType, normalizeApproval, imagePartOmittedSummary, ENTRY_REF_PREFIX, MAX_ATTACH_BYTES, SIMULTANEOUS_CONTEXTS, SESSION_REFERENCE_ERROR_CODES, filePartSummary, sessionPartSummary } from '@epoch-agent/protocol';
1
+ import { REASONING_EFFORTS, MODEL_ENTRY_PROTOCOLS, PROVIDER_TYPES, isModelEntryId, parseModelRef, OPERATION_TYPES as OPERATION_TYPES$1, COMPLIANCE_CATEGORIES, COMPLIANCE_ACTIONS, SEARCH_PROVIDER_TYPES, CURRENCIES, LANGS, isSettingsPaneId, SETTINGS_PANE_IDS, BRAND_WHEN_SIDEBAR_COLLAPSED, PERMISSION_LEVELS, SHELL_KINDS, cronTimes, SCHEDULE_MAX_TIMES_PER_DAY, SCHEDULE_INTERVAL_MIN_MINUTES, SCHEDULE_INTERVAL_MAX_MINUTES, ToolExposure, MIN_OPTIONS, MAX_OPTIONS, MAX_HEADER_CHARS, MAX_QUESTIONS, isPermissionLevel, SCHEDULE_DRAFT_TOOL, isValidAgentRoleName, DEFAULT_AGENT_ROLE, isValidCommandName, RESERVED_COMMAND_NAMES, isWirePluginArchiveName, systemNote, formatMoney, totalUsageTokens, NOOP_TELEMETRY, METRIC, contentToText, GEN_AI, isPromptOversize, promptTokens, entrySecretName, isEntrySecretName, entryRef, KEY_ACTIONS, tableOf, perAction, isKeyAction, parseSequence, RESERVED_CHORDS, chordId, sequenceId, ACTION_CONTEXTS, SEQUENCE_CONTEXTS, assertNeverPart, normalizeAppearanceTranslucent, MAX_ATTACH_FILES, MAX_ATTACH_TOTAL_BYTES, MAX_SESSION_REFS, utf8ByteLength, truncateToBudget, attachSessionSurface, isContextNearlyFull, isOperationType, normalizeApproval, SCHEDULE_DRAFT_SAVED_MARK, imagePartOmittedSummary, ENTRY_REF_PREFIX, MAX_ATTACH_BYTES, SIMULTANEOUS_CONTEXTS, SESSION_REFERENCE_ERROR_CODES, filePartSummary, sessionPartSummary } from '@epoch-agent/protocol';
2
2
  export { API_KEY_ENV_VARS, COMPLIANCE_ACTIONS, COMPLIANCE_CATEGORIES, MAX_ATTACH_BYTES, MAX_ATTACH_FILES, MAX_ATTACH_TOTAL_BYTES, MAX_SESSION_ATTACH_BYTES, MAX_SESSION_REFS, OPERATION_TYPES, PERMISSION_LEVELS, PLAN_OUTCOMES, PROVIDER_INFOS, PROVIDER_TYPES, ToolExposure, apiKeyEnvVar, extractAllMentions, extractMentions, extractSessionMentions, getProviderInfo, isOperationType, isPermissionLevel, isPlanOutcome, isProviderType, normalizeApproval } from '@epoch-agent/protocol';
3
3
  import { existsSync, statSync, readdirSync, readFileSync, mkdirSync, writeFileSync, rmSync, renameSync, realpathSync, symlinkSync, cpSync, lstatSync, unlinkSync, rmdirSync, mkdtempSync, copyFileSync, openSync, writeSync, closeSync, readSync } from 'fs';
4
4
  import { homedir, platform, tmpdir, hostname } from 'os';
@@ -2707,13 +2707,48 @@ function createExitTool(deps) {
2707
2707
  function createPlanModeTools(deps) {
2708
2708
  return [createEnterTool(deps), createExitTool(deps)];
2709
2709
  }
2710
+ var SCHEDULE_ISSUE_CODES = [
2711
+ "name-empty",
2712
+ "prompt-empty",
2713
+ "permission-unknown",
2714
+ "work-dir-missing",
2715
+ "budget-missing",
2716
+ "max-turns-invalid",
2717
+ "timeout-invalid",
2718
+ "trigger-time-invalid",
2719
+ "trigger-times-too-many",
2720
+ "trigger-weekdays-empty",
2721
+ "trigger-days-invalid",
2722
+ "trigger-interval-invalid",
2723
+ "trigger-once-date-invalid",
2724
+ "trigger-once-past",
2725
+ "date-range-invalid",
2726
+ "date-range-on-once",
2727
+ "rule-invalid",
2728
+ "bypass-needs-workdir",
2729
+ "bypass-workdir-too-broad",
2730
+ "bypass-needs-limits",
2731
+ "bypass-not-confirmed"
2732
+ ];
2733
+ var SCHEDULE_DEFAULTS = {
2734
+ maxTurns: DEFAULT_MAX_TURNS,
2735
+ timeoutMs: 60 * 60 * 1e3
2736
+ };
2737
+ var SCHEDULE_FORM_BUDGET_USD = 200;
2738
+ var SCHEDULE_DEFAULT_ALLOWLIST = {
2739
+ allowTools: [],
2740
+ allowOperations: ["file_read"],
2741
+ allowRules: []
2742
+ };
2743
+ // src/schedule/draft.ts
2710
2744
  var bad = (message) => ({ ok: false, message });
2711
2745
  var good = (value) => ({ ok: true, value });
2712
2746
  var PERMISSION_ORDER = [
2713
2747
  "plan",
2714
2748
  "default",
2715
2749
  "acceptEdits",
2716
- "auto"
2750
+ "auto",
2751
+ "bypass"
2717
2752
  ];
2718
2753
  var OPERATION_TYPES = [
2719
2754
  "file_read",
@@ -2755,16 +2790,18 @@ function operationList(v) {
2755
2790
  function permission(v) {
2756
2791
  const s = str(v);
2757
2792
  if (s === void 0) return bad("permission \u662F\u7A7A\u7684");
2758
- if (s === "bypass") {
2759
- return bad(
2760
- "\u8349\u7A3F\u4E0D\u8BB8\u7528 bypass\uFF08\u8DF3\u8FC7\u5168\u90E8\u68C0\u67E5\uFF09\u3002\u65E0\u4EBA\u503C\u5B88\u4E0B\u90A3\u4E00\u6863\u8981\u4EBA\u4EB2\u624B\u52FE\u4E00\u6B21\u786E\u8BA4\uFF0C\u8BA9\u8349\u7A3F\u63D0\u8BAE\u5B83\u7B49\u4E8E\u628A\u90A3\u6B21\u786E\u8BA4\u53D8\u6210\u4F8B\u884C\u624B\u7EED\u3002\u8981\u653E\u5F00\u67D0\u51E0\u4EF6\u4E8B\uFF0C\u7528 permission: default \u52A0\u4E00\u4EFD\u7CBE\u786E\u7684 allowRules"
2761
- );
2762
- }
2763
2793
  if (!PERMISSION_ORDER.includes(s)) {
2764
2794
  return bad(`permission \u53EA\u80FD\u662F ${PERMISSION_ORDER.join(" / ")} \u4E4B\u4E00\uFF0C\u6536\u5230\u7684\u662F ${s}`);
2765
2795
  }
2766
2796
  return good(s);
2767
2797
  }
2798
+ function budget(v) {
2799
+ if (v === void 0) return good(void 0);
2800
+ if (typeof v !== "number" || !Number.isFinite(v) || v <= 0) {
2801
+ return bad("maxBudgetUsd \u8981\u662F\u5927\u4E8E 0 \u7684\u6570\uFF08\u5355\u4F4D\u7F8E\u5143\uFF09\u3002\u4E0D\u7ED9\u5C31\u6309\u65B0\u5EFA\u8868\u5355\u90A3\u4E2A\u7F3A\u7701\uFF08200\uFF09");
2802
+ }
2803
+ return good(v);
2804
+ }
2768
2805
  function clock(v) {
2769
2806
  const s = str(v);
2770
2807
  if (s === void 0 || !/^\d{1,2}:\d{2}$/.test(s))
@@ -2881,6 +2918,8 @@ function parseCreate(raw, note) {
2881
2918
  const allow = parseAllowlist(raw);
2882
2919
  if (!allow.ok) return allow;
2883
2920
  const workDir = str(raw["workDir"]);
2921
+ const usd = budget(raw["maxBudgetUsd"]);
2922
+ if (!usd.ok) return usd;
2884
2923
  return good({
2885
2924
  action: "create",
2886
2925
  name,
@@ -2889,6 +2928,7 @@ function parseCreate(raw, note) {
2889
2928
  permission: level.value,
2890
2929
  note,
2891
2930
  ...workDir === void 0 ? {} : { workDir },
2931
+ ...usd.value === void 0 ? {} : { maxBudgetUsd: usd.value },
2892
2932
  ...allow.value
2893
2933
  });
2894
2934
  }
@@ -2923,6 +2963,9 @@ function parseUpdate(raw, note) {
2923
2963
  const timeout = posInt(raw["timeoutMs"], "timeoutMs");
2924
2964
  if (!timeout.ok) return timeout;
2925
2965
  if (timeout.value !== void 0) patch.timeoutMs = timeout.value;
2966
+ const usd = budget(raw["maxBudgetUsd"]);
2967
+ if (!usd.ok) return usd;
2968
+ if (usd.value !== void 0) patch.maxBudgetUsd = usd.value;
2926
2969
  if (Object.keys(patch).length === 0) {
2927
2970
  return bad(
2928
2971
  "update \u4E00\u683C\u90FD\u6CA1\u6539\u3002\u4E00\u4EFD\u4EC0\u4E48\u90FD\u4E0D\u6539\u7684\u63D0\u6848\u4F1A\u767D\u5360\u7528\u6237\u4E00\u6B21\u70B9\u51FB \u2014\u2014 \u8981\u4E48\u7ED9\u51FA\u5177\u4F53\u6539\u54EA\u51E0\u683C\uFF0C\u8981\u4E48\u522B\u63D0"
@@ -2948,7 +2991,7 @@ function parseScheduleDraft(raw) {
2948
2991
  }
2949
2992
  function draftWidening(draft, current) {
2950
2993
  const out = [];
2951
- const base2 = draft.action === "update" && current ? current.permission === "bypass" ? "auto" : current.permission : "default";
2994
+ const base2 = draft.action === "update" && current ? current.permission : "default";
2952
2995
  const level = draft.permission;
2953
2996
  if (level !== void 0 && PERMISSION_ORDER.indexOf(level) > PERMISSION_ORDER.indexOf(base2)) {
2954
2997
  out.push("permission");
@@ -3002,42 +3045,9 @@ function draftCommandLine(draft) {
3002
3045
  for (const tool of draft.allowTools ?? []) argv.push("--allow-tool", shellArg(tool));
3003
3046
  for (const op2 of draft.allowOperations ?? []) argv.push("--allow-operation", op2);
3004
3047
  for (const rule of draft.allowRules ?? []) argv.push("--allow-rule", shellArg(rule));
3005
- argv.push("--budget", shellArg("<\u4F60\u5B9A\u4E00\u4E2A\u4E0A\u9650\uFF0C\u5355\u4F4D\u7F8E\u5143>"));
3048
+ argv.push("--budget", String(draft.maxBudgetUsd ?? SCHEDULE_FORM_BUDGET_USD));
3006
3049
  return argv.join(" ");
3007
3050
  }
3008
- var SCHEDULE_ISSUE_CODES = [
3009
- "name-empty",
3010
- "prompt-empty",
3011
- "permission-unknown",
3012
- "work-dir-missing",
3013
- "budget-missing",
3014
- "max-turns-invalid",
3015
- "timeout-invalid",
3016
- "trigger-time-invalid",
3017
- "trigger-times-too-many",
3018
- "trigger-weekdays-empty",
3019
- "trigger-days-invalid",
3020
- "trigger-interval-invalid",
3021
- "trigger-once-date-invalid",
3022
- "trigger-once-past",
3023
- "date-range-invalid",
3024
- "date-range-on-once",
3025
- "rule-invalid",
3026
- "bypass-needs-workdir",
3027
- "bypass-workdir-too-broad",
3028
- "bypass-needs-limits",
3029
- "bypass-not-confirmed"
3030
- ];
3031
- var SCHEDULE_DEFAULTS = {
3032
- maxTurns: DEFAULT_MAX_TURNS,
3033
- timeoutMs: 60 * 60 * 1e3
3034
- };
3035
- var SCHEDULE_FORM_BUDGET_USD = 200;
3036
- var SCHEDULE_DEFAULT_ALLOWLIST = {
3037
- allowTools: [],
3038
- allowOperations: ["file_read"],
3039
- allowRules: []
3040
- };
3041
3051
  // src/schedule/unattended-lint.ts
3042
3052
  var ANCHORS = [
3043
3053
  { kind: "asks-human", zh: /问(?:一下|下)?我/, en: /\bask\s+(?:me|us)\b/i },
@@ -3473,7 +3483,7 @@ function validateSchedule(input) {
3473
3483
  if (input.workDir && !isExistingDir(input.workDir)) {
3474
3484
  issues.push({ code: "work-dir-missing", detail: input.workDir });
3475
3485
  }
3476
- if (!input.budgetPending && (!Number.isFinite(input.maxBudgetUsd) || input.maxBudgetUsd <= 0)) {
3486
+ if (!Number.isFinite(input.maxBudgetUsd) || input.maxBudgetUsd <= 0) {
3477
3487
  issues.push({ code: "budget-missing", detail: String(input.maxBudgetUsd) });
3478
3488
  }
3479
3489
  if (!Number.isInteger(input.maxTurns) || input.maxTurns < 0) {
@@ -3535,29 +3545,34 @@ var WIDENING_TEXT = {
3535
3545
  allowlist: "\u6E05\u5355\u591A\u4E86\u6761\u76EE\uFF08= \u591A\u4E86\u51E0\u4EF6\u4E0D\u7ECF\u786E\u8BA4\u5C31\u4F1A\u505A\u7684\u4E8B\uFF09",
3536
3546
  enabled: "\u628A\u4E00\u6761\u505C\u7528\u7684\u4EFB\u52A1\u6539\u6210\u542F\u7528"
3537
3547
  };
3548
+ function budgetOf(draft, current) {
3549
+ return draft.maxBudgetUsd ?? current?.maxBudgetUsd ?? SCHEDULE_FORM_BUDGET_USD;
3550
+ }
3538
3551
  function validateDraft(draft, homeDir, current) {
3552
+ const permission2 = draft.permission ?? current?.permission ?? "default";
3539
3553
  const merged = draft.action === "create" ? {
3540
3554
  name: draft.name,
3541
3555
  prompt: draft.prompt,
3542
- permission: draft.permission,
3556
+ permission: permission2,
3543
3557
  workDir: draft.workDir ?? "",
3544
3558
  maxTurns: SCHEDULE_DEFAULTS.maxTurns,
3545
- maxBudgetUsd: 0,
3559
+ maxBudgetUsd: budgetOf(draft),
3546
3560
  timeoutMs: SCHEDULE_DEFAULTS.timeoutMs,
3547
3561
  trigger: draft.trigger,
3548
3562
  allowRules: draft.allowRules ?? [],
3549
- budgetPending: true,
3563
+ bypassAcknowledged: permission2 === "bypass",
3550
3564
  homeDir
3551
3565
  } : {
3552
3566
  name: draft.name ?? current?.name ?? "",
3553
3567
  prompt: draft.prompt ?? current?.prompt ?? "",
3554
- permission: draft.permission ?? current?.permission ?? "default",
3568
+ permission: permission2,
3555
3569
  workDir: draft.workDir ?? current?.workDir ?? "",
3556
3570
  maxTurns: draft.maxTurns ?? current?.maxTurns ?? SCHEDULE_DEFAULTS.maxTurns,
3557
- maxBudgetUsd: current?.maxBudgetUsd ?? 0,
3571
+ maxBudgetUsd: budgetOf(draft, current),
3558
3572
  timeoutMs: draft.timeoutMs ?? current?.timeoutMs ?? SCHEDULE_DEFAULTS.timeoutMs,
3559
3573
  trigger: draft.trigger ?? current?.trigger ?? { kind: "cron", cycle: "daily", at: "09:00" },
3560
3574
  allowRules: draft.allowRules ?? current?.allowRules ?? [],
3575
+ bypassAcknowledged: permission2 === "bypass",
3561
3576
  homeDir
3562
3577
  };
3563
3578
  return validateSchedule(merged).issues.map(
@@ -3590,13 +3605,27 @@ function structuralNotes(draft, current) {
3590
3605
  }
3591
3606
  return out;
3592
3607
  }
3593
- function summarize(draft, current) {
3608
+ function registrationLine(outcome) {
3609
+ if (outcome === void 0) return void 0;
3610
+ if (outcome.ok) {
3611
+ return "\u5DF2\u7ECF\u6CE8\u518C\u8FDB\u64CD\u4F5C\u7CFB\u7EDF\uFF0C\u5230\u70B9\u4F1A\u81EA\u5DF1\u8DD1\uFF08\u5173\u6389\u8FD9\u4E2A\u5E94\u7528\u4E5F\u8DD1\uFF09\u3002";
3612
+ }
3613
+ switch (outcome.reason) {
3614
+ case "unsupported-platform":
3615
+ return "\u26A0\uFE0F \u8FD9\u53F0\u673A\u5668\uFF08Linux\uFF09\u6682\u4E0D\u652F\u6301\u81EA\u52A8\u89E6\u53D1 \u2014\u2014 \u4EFB\u52A1\u5B58\u4E0B\u6765\u4E86\uFF0C\u4F46\u5230\u70B9\u4E0D\u4F1A\u81EA\u5DF1\u8DD1\u3002";
3616
+ case "refused":
3617
+ return outcome.refusal === "npx" ? "\u26A0\uFE0F \u6CA1\u6CE8\u518C\u8FDB\u64CD\u4F5C\u7CFB\u7EDF\uFF1A\u8FD9\u4E00\u4EFD\u662F npx \u4E34\u65F6\u8DD1\u8D77\u6765\u7684\uFF0C\u7F13\u5B58\u76EE\u5F55\u4E00\u6E05\u90A3\u6761\u4EFB\u52A1\u5C31\u5E9F\u3002\u88C5\u6210\u5168\u5C40\uFF08`npm i -g`\uFF09\u4E4B\u540E\u91CD\u5EFA\u4E00\u6B21\u624D\u6CE8\u518C\u5F97\u4E0A\u3002\u4EFB\u52A1\u672C\u8EAB\u5B58\u4E0B\u6765\u4E86\u3002" : "\u26A0\uFE0F \u6CA1\u6CE8\u518C\u8FDB\u64CD\u4F5C\u7CFB\u7EDF\uFF1A\u8FD9\u4E2A\u5BBF\u4E3B\u6CA1\u7ED9\u300C\u5230\u70B9\u4E86\u600E\u4E48\u8D77\u4E00\u6B21\u300D\u7684\u5165\u53E3\u3002\u4EFB\u52A1\u5B58\u4E0B\u6765\u4E86\uFF0C\u4F46\u5E94\u7528\u5173\u7740\u7684\u65F6\u5019\u5B83\u4E0D\u4F1A\u8DD1\u3002";
3618
+ case "backend-error":
3619
+ return `\u26A0\uFE0F \u6CE8\u518C\u8FDB\u64CD\u4F5C\u7CFB\u7EDF\u5931\u8D25\u4E86\uFF1A${outcome.detail}\u3002\u4EFB\u52A1\u5B58\u4E0B\u6765\u4E86\uFF0C\u4F46\u5230\u70B9\u4E0D\u4F1A\u81EA\u5DF1\u8DD1\u3002`;
3620
+ }
3621
+ }
3622
+ function summarizeProposal(draft, current, readOnly) {
3594
3623
  const lines = [];
3595
3624
  lines.push(
3596
3625
  draft.action === "create" ? `\u8349\u7A3F\u5DF2\u7ECF\u6446\u5230\u7528\u6237\u773C\u524D\u4E86\uFF08\u4E00\u5F20\u5361\u7247\uFF0C\u6807\u9898\u300C${draft.name}\u300D\uFF09\u3002` : `\u6539\u52A8\u63D0\u6848\u5DF2\u7ECF\u6446\u5230\u7528\u6237\u773C\u524D\u4E86\uFF08\u9488\u5BF9\u300C${current?.name ?? draft.id}\u300D\uFF09\u3002`
3597
3626
  );
3598
3627
  lines.push(
3599
- "\u5B83**\u8FD8\u6CA1\u6709\u751F\u6548\uFF0C\u4E5F\u6CA1\u6709\u843D\u5E93** \u2014\u2014 \u8981\u7528\u6237\u5728\u5361\u7247\u4E0A\u70B9\u300C\u5BA1\u9605\u5E76\u4FDD\u5B58\u300D\u3001\u5728\u8868\u5355\u91CC\u81EA\u5DF1\u586B\u4E00\u4E2A\u9884\u7B97\u4E0A\u9650\uFF0C\u90A3\u4E00\u4E0B\u624D\u662F\u771F\u7684\u5EFA\u7ACB\u3002"
3628
+ readOnly ? "\u5B83**\u8FD8\u6CA1\u6709\u751F\u6548\uFF0C\u4E5F\u6CA1\u6709\u843D\u5E93** \u2014\u2014 \u4F60\u5728\u53EA\u8BFB\u8C03\u7814\u6A21\u5F0F\uFF08plan\uFF09\u4E0B\uFF0C\u8FD9\u4E00\u6863\u4E0D\u5199\u76D8\u3002\u8981\u7528\u6237\u81EA\u5DF1\u5BA1\u4E00\u904D\u3001\u70B9\u300C\u5BA1\u9605\u5E76\u4FDD\u5B58\u300D\u624D\u662F\u771F\u7684\u5EFA\u7ACB\u3002" : "\u5B83**\u8FD8\u6CA1\u6709\u843D\u5E93** \u2014\u2014 \u8FD9\u4E2A\u5BBF\u4E3B\u6CA1\u6709\u63A5\u5199\u5165\u8DEF\uFF0C\u8981\u7528\u6237\u81EA\u5DF1\u5BA1\u4E00\u904D\u3001\u70B9\u300C\u5BA1\u9605\u5E76\u4FDD\u5B58\u300D\u624D\u662F\u771F\u7684\u5EFA\u7ACB\u3002"
3600
3629
  );
3601
3630
  const widening = draftWidening(draft, current);
3602
3631
  if (widening.length > 0) {
@@ -3607,16 +3636,77 @@ function summarize(draft, current) {
3607
3636
  for (const note of structuralNotes(draft, current)) lines.push(`\u26A0\uFE0F ${note}`);
3608
3637
  const cli = draftCommandLine(draft);
3609
3638
  lines.push(
3610
- cli === void 0 ? "\uFF08\u6CA1\u6709\u754C\u9762\u7684\u5BBF\u4E3B\u4E0A\uFF1A\u6539\u4E00\u6761\u5DF2\u6709\u4EFB\u52A1\u4ECA\u5929\u53EA\u6709\u754C\u9762\u90A3\u6761\u8DEF \u2014\u2014 `epoch schedule` \u5E95\u4E0B\u6CA1\u6709\u6539\u5B57\u6BB5\u7684\u5B50\u547D\u4EE4\uFF0C\u53EA\u6709 enable / disable / rm\u3002\u522B\u7F16\u4E00\u6761 update \u51FA\u6765\u3002\uFF09" : `\u6CA1\u6709\u754C\u9762\u7684\u5BBF\u4E3B\u4E0A\uFF0C\u7B49\u4EF7\u7684\u547D\u4EE4\u884C\u662F\uFF08\u9884\u7B97\u90A3\u4E00\u683C\u8981\u7528\u6237\u81EA\u5DF1\u586B\uFF09\uFF1A
3639
+ cli === void 0 ? "\uFF08\u6CA1\u6709\u754C\u9762\u7684\u5BBF\u4E3B\u4E0A\uFF1A\u6539\u4E00\u6761\u5DF2\u6709\u4EFB\u52A1\u4ECA\u5929\u53EA\u6709\u754C\u9762\u90A3\u6761\u8DEF \u2014\u2014 `epoch schedule` \u5E95\u4E0B\u6CA1\u6709\u6539\u5B57\u6BB5\u7684\u5B50\u547D\u4EE4\uFF0C\u53EA\u6709 enable / disable / rm\u3002\u522B\u7F16\u4E00\u6761 update \u51FA\u6765\u3002\uFF09" : `\u6CA1\u6709\u754C\u9762\u7684\u5BBF\u4E3B\u4E0A\uFF0C\u7B49\u4EF7\u7684\u547D\u4EE4\u884C\u662F\uFF1A
3611
3640
  ${cli}`
3612
3641
  );
3613
- lines.push("\u522B\u91CD\u590D\u63D0\u4EA4\u540C\u4E00\u4EFD\u8349\u7A3F\u7B49\u5B83\u300C\u751F\u6548\u300D\u2014\u2014 \u7528\u6237\u4EC0\u4E48\u65F6\u5019\u5BA1\u662F\u4ED6\u7684\u4E8B\uFF0C\u4F60\u8FD9\u4E00\u8F6E\u5230\u6B64\u4E3A\u6B62\u3002");
3614
3642
  return lines.join("\n");
3615
3643
  }
3644
+ function summarizeSaved(draft, def, registration, current) {
3645
+ const lines = [];
3646
+ lines.push(
3647
+ `${SCHEDULE_DRAFT_SAVED_MARK}${def.id}`,
3648
+ draft.action === "create" ? `\u5DF2\u7ECF\u5EFA\u7ACB\u5E76\u751F\u6548\uFF1A\u300C${def.name}\u300D\u3002` : `\u5DF2\u7ECF\u6539\u597D\u4E86\uFF1A\u300C${current?.name ?? def.name}\u300D\u3002`
3649
+ );
3650
+ const when = draft.action === "create" ? draft.trigger : draft.trigger ?? current?.trigger;
3651
+ if (when !== void 0) lines.push(`\u5230\u70B9\uFF1A${JSON.stringify(when)}`);
3652
+ const permission2 = draft.permission ?? current?.permission;
3653
+ if (permission2 !== void 0) lines.push(`\u6743\u9650\u6863\uFF1A${permission2}`);
3654
+ const registered = registrationLine(registration);
3655
+ if (registered !== void 0) lines.push(registered);
3656
+ const widening = draftWidening(draft, current);
3657
+ if (widening.length > 0) {
3658
+ lines.push(
3659
+ `\u26A0\uFE0F \u8FD9\u6B21\u6539\u52A8\u653E\u5BBD\u4E86\u6388\u6743\u9762\uFF1A${widening.map((k) => WIDENING_TEXT[k]).join("\uFF1B")}\u3002\u5728\u4F60\u7684\u56DE\u590D\u91CC**\u4E3B\u52A8**\u628A\u8FD9\u4E00\u70B9\u8BF4\u7ED9\u7528\u6237\u542C \u2014\u2014 \u5B83\u5DF2\u7ECF\u751F\u6548\u4E86\uFF0C\u90A3\u4E2A\u4EBA\u53EA\u6709\u9760\u4F60\u8FD9\u53E5\u8BDD\u624D\u77E5\u9053\u521A\u624D\u591A\u653E\u884C\u4E86\u4EC0\u4E48\u3002`
3660
+ );
3661
+ }
3662
+ for (const note of structuralNotes(draft, current)) lines.push(`\u26A0\uFE0F ${note}`);
3663
+ lines.push(
3664
+ "\u5728\u4F60\u7684\u56DE\u590D\u91CC\u7528\u4E00\u53E5\u8BDD\u4EA4\u4EE3\u300C\u5EFA\u4E86\u4EC0\u4E48\u3001\u4EC0\u4E48\u65F6\u5019\u8DD1\u300D\u5C31\u591F\u4E86\u3002**\u522B\u518D\u8BF4\u300C\u8981\u4E0D\u8981\u6211\u5EFA\u4E00\u6761\u300D** \u2014\u2014 \u5B83\u5DF2\u7ECF\u5728\u4E86\uFF1B\u7528\u6237\u60F3\u64A4\u6389\uFF0C\u5361\u7247\u4E0A\u6709\u64A4\u9500\u952E\uFF0C\u4E5F\u53EF\u4EE5\u53BB\u81EA\u52A8\u5316\u9762\u677F\u5220\u3002"
3665
+ );
3666
+ return lines.join("\n");
3667
+ }
3668
+ async function persist(save, draft, current) {
3669
+ const permission2 = draft.permission ?? current?.permission ?? "default";
3670
+ const acknowledged = { bypassAcknowledged: permission2 === "bypass" };
3671
+ if (draft.action === "create") {
3672
+ return save.create(
3673
+ {
3674
+ name: draft.name,
3675
+ prompt: draft.prompt,
3676
+ permission: draft.permission,
3677
+ maxBudgetUsd: budgetOf(draft),
3678
+ trigger: draft.trigger,
3679
+ ...draft.workDir === void 0 ? {} : { workDir: draft.workDir },
3680
+ ...draft.allowTools === void 0 ? {} : { allowTools: draft.allowTools },
3681
+ ...draft.allowOperations === void 0 ? {} : { allowOperations: draft.allowOperations },
3682
+ ...draft.allowRules === void 0 ? {} : { allowRules: draft.allowRules }
3683
+ },
3684
+ acknowledged
3685
+ );
3686
+ }
3687
+ return save.update(
3688
+ draft.id,
3689
+ {
3690
+ ...draft.name === void 0 ? {} : { name: draft.name },
3691
+ ...draft.prompt === void 0 ? {} : { prompt: draft.prompt },
3692
+ ...draft.permission === void 0 ? {} : { permission: draft.permission },
3693
+ ...draft.trigger === void 0 ? {} : { trigger: draft.trigger },
3694
+ ...draft.workDir === void 0 ? {} : { workDir: draft.workDir },
3695
+ ...draft.enabled === void 0 ? {} : { enabled: draft.enabled },
3696
+ ...draft.maxTurns === void 0 ? {} : { maxTurns: draft.maxTurns },
3697
+ ...draft.timeoutMs === void 0 ? {} : { timeoutMs: draft.timeoutMs },
3698
+ ...draft.maxBudgetUsd === void 0 ? {} : { maxBudgetUsd: draft.maxBudgetUsd },
3699
+ ...draft.allowTools === void 0 ? {} : { allowTools: draft.allowTools },
3700
+ ...draft.allowOperations === void 0 ? {} : { allowOperations: draft.allowOperations },
3701
+ ...draft.allowRules === void 0 ? {} : { allowRules: draft.allowRules }
3702
+ },
3703
+ acknowledged
3704
+ );
3705
+ }
3616
3706
  function createScheduleDraftTool(deps) {
3617
3707
  return {
3618
3708
  name: SCHEDULE_DRAFT_TOOL,
3619
- description: "\u8D77\u8349\u4E00\u6761\u5B9A\u65F6\u4EFB\u52A1\uFF0C\u4EA4\u7ED9\u7528\u6237\u5BA1\u3002\u5B9A\u65F6\u4EFB\u52A1\u662F\u300C\u5230\u70B9\u4E86\u81EA\u5DF1\u8DD1\u4E00\u6B21\u300D\u2014\u2014\u7528\u6237\u8BF4\u300C\u4EE5\u540E\u6BCF\u5929/\u6BCF\u5468\u5E2E\u6211\u505A\u67D0\u4EF6\u4E8B\u300D\u300C\u5B9A\u671F\u68C0\u67E5\u67D0\u67D0\u300D\uFF0C\u6216\u8005\u4F60\u53D1\u73B0\u67D0\u4EF6\u4E8B\u4ED6\u6BCF\u6B21\u90FD\u8981\u624B\u52A8\u505A\u4E00\u904D\u65F6\uFF0C\u7528\u5B83\u3002action=list \u770B\u73B0\u6709\u4EFB\u52A1\uFF08\u8981\u6539\u67D0\u6761\u5FC5\u987B\u5148 list \u62FF\u5230 id\uFF09\uFF1Baction=create \u8D77\u8349\u65B0\u7684\uFF1Baction=update \u63D0\u8BAE\u6539\u4E00\u6761\u5DF2\u6709\u7684\u3002\u26A0\uFE0F \u4F60\u4EA4\u7684\u662F\u8349\u7A3F\uFF0C\u4E0D\u662F\u4EFB\u52A1\uFF1A\u5B83\u4E0D\u4F1A\u751F\u6548\uFF0C\u8981\u7528\u6237\u81EA\u5DF1\u5BA1\u4E00\u904D\u3001\u586B\u4E00\u4E2A\u9884\u7B97\u4E0A\u9650\u624D\u5EFA\u7ACB\u3002\u4EA4\u5B8C\u8FD9\u4E00\u8F6E\u5C31\u7ED3\u675F\uFF0C\u522B\u53CD\u590D\u63D0\u4EA4\u7B49\u5B83\u751F\u6548\u3002\u6743\u9650\u6863\u53EA\u6709 plan/default/acceptEdits/auto \u2014\u2014 bypass \u4E0D\u8BB8\u63D0\u8BAE\u3002\u8981\u653E\u5F00\u67D0\u51E0\u4EF6\u4E8B\u5C31\u7528 default \u52A0\u7CBE\u786E\u7684 allowRules\uFF08\u6BD4\u5982 terminal(git status)\uFF09\uFF0C\u522B\u6574\u4F53\u8C03\u677E\u3002",
3709
+ description: "\u5EFA\u4E00\u6761\u5B9A\u65F6\u4EFB\u52A1\uFF0C\u6216\u8005\u6539\u4E00\u6761\u5DF2\u6709\u7684\u3002\u5B9A\u65F6\u4EFB\u52A1\u662F\u300C\u5230\u70B9\u4E86\u81EA\u5DF1\u8DD1\u4E00\u6B21\u300D\u2014\u2014\u7528\u6237\u8BF4\u300C\u4EE5\u540E\u6BCF\u5929/\u6BCF\u5468\u5E2E\u6211\u505A\u67D0\u4EF6\u4E8B\u300D\u300C\u5B9A\u671F\u68C0\u67E5\u67D0\u67D0\u300D\uFF0C\u6216\u8005\u4F60\u53D1\u73B0\u67D0\u4EF6\u4E8B\u4ED6\u6BCF\u6B21\u90FD\u8981\u624B\u52A8\u505A\u4E00\u904D\u65F6\uFF0C\u7528\u5B83\u3002action=list \u770B\u73B0\u6709\u4EFB\u52A1\uFF08\u8981\u6539\u67D0\u6761\u5FC5\u987B\u5148 list \u62FF\u5230 id\uFF09\uFF1Baction=create \u76F4\u63A5\u5EFA\u4E00\u6761\uFF1Baction=update \u76F4\u63A5\u6539\u4E00\u6761\u3002\u26A0\uFE0F **\u5B83\u4EA4\u4E0A\u53BB\u5C31\u751F\u6548**\uFF08plan \u53EA\u8BFB\u6863\u4E0B\u9664\u5916\uFF0C\u90A3\u4E00\u6863\u53EA\u4EA4\u63D0\u6848\uFF09\u2014\u2014 \u5EFA\u5B8C\u5728\u4F60\u7684\u56DE\u590D\u91CC\u4EA4\u4EE3\u4E00\u53E5\u5C31\u884C\uFF0C\u522B\u95EE\u300C\u8981\u4E0D\u8981\u6211\u5EFA\u300D\u3002\u9884\u7B97\u4E0D\u7ED9\u5C31\u662F 200 \u7F8E\u5143\uFF1B\u8FD9\u6D3B\u660E\u663E\u66F4\u8F7B\u6216\u66F4\u91CD\u65F6\u81EA\u5DF1\u7ED9 maxBudgetUsd\u3002\u6743\u9650\u6863 plan/default/acceptEdits/auto/bypass \u90FD\u80FD\u63D0 \u2014\u2014 \u4F46**\u9ED8\u8BA4\u7528 plan**\uFF1A\u53EA\u8BFB\u6863\u5929\u7136\u96F6\u6388\u6743\u9762\uFF0C\u9700\u8981\u5199\u4E1C\u897F\u518D\u7528 default \u52A0\u4E00\u4EFD\u7CBE\u786E\u7684 allowRules\uFF08\u6BD4\u5982 terminal(git status)\uFF09\uFF0C\u522B\u4E00\u4E0A\u6765\u5C31 bypass\u3002",
3620
3710
  parameters: {
3621
3711
  type: "object",
3622
3712
  properties: {
@@ -3627,7 +3717,7 @@ function createScheduleDraftTool(deps) {
3627
3717
  },
3628
3718
  note: {
3629
3719
  type: "string",
3630
- description: "\u4E3A\u4EC0\u4E48\u5EFA\u8BAE\u8FD9\u6761\uFF0C\u4E00\u53E5\u8BDD\u3002create / update \u5FC5\u586B\uFF0C\u4F1A\u5370\u5728\u7528\u6237\u770B\u5230\u7684\u5361\u7247\u4E0A\uFF1B\u8BF4\u4E0D\u51FA\u771F\u5B9E\u7406\u7531\u5C31\u522B\u63D0\u8FD9\u4E2A\u5EFA\u8BAE"
3720
+ description: "\u4E3A\u4EC0\u4E48\u5EFA\u8FD9\u6761\uFF0C\u4E00\u53E5\u8BDD\u3002create / update \u5FC5\u586B\uFF0C\u4F1A\u5370\u5728\u7528\u6237\u770B\u5230\u7684\u5361\u7247\u4E0A\uFF1B\u8BF4\u4E0D\u51FA\u771F\u5B9E\u7406\u7531\u5C31\u522B\u63D0\u8FD9\u4E2A\u5EFA\u8BAE"
3631
3721
  },
3632
3722
  id: { type: "string", description: "\u6539\u54EA\u4E00\u6761\u3002update \u5FC5\u586B\uFF0C\u4ECE action=list \u91CC\u62FF" },
3633
3723
  name: { type: "string", description: "\u4EFB\u52A1\u540D\uFF0C\u7528\u6237\u5728\u5217\u8868\u91CC\u770B\u5230\u7684\u5C31\u662F\u5B83" },
@@ -3660,8 +3750,12 @@ function createScheduleDraftTool(deps) {
3660
3750
  },
3661
3751
  permission: {
3662
3752
  type: "string",
3663
- description: "\u6743\u9650\u6863\u3002plan=\u53EA\u8BFB\uFF08\u8BFB\u4E00\u904D\u5199\u4EFD\u62A5\u544A\u7684\u4EFB\u52A1\u5C31\u8BE5\u7528\u5B83\uFF0C\u5929\u7136\u96F6\u6388\u6743\u9762\uFF09\uFF1Bdefault=\u6309\u9700\u786E\u8BA4\uFF1BacceptEdits=\u81EA\u52A8\u63A5\u53D7\u6539\u52A8\uFF1Bauto=\u4E0D\u518D\u786E\u8BA4",
3664
- enum: ["plan", "default", "acceptEdits", "auto"]
3753
+ description: "\u6743\u9650\u6863\u3002plan=\u53EA\u8BFB\uFF08\u8BFB\u4E00\u904D\u5199\u4EFD\u62A5\u544A\u7684\u4EFB\u52A1\u5C31\u8BE5\u7528\u5B83\uFF0C\u5929\u7136\u96F6\u6388\u6743\u9762\uFF09\uFF1Bdefault=\u6309\u9700\u786E\u8BA4\uFF1BacceptEdits=\u81EA\u52A8\u63A5\u53D7\u6539\u52A8\uFF1Bauto=\u4E0D\u518D\u786E\u8BA4\uFF1Bbypass=\u8DF3\u8FC7\u5168\u90E8\u68C0\u67E5\uFF08**\u6700\u540E\u624B\u6BB5**\uFF1A\u5230\u70B9\u4E86\u5B83\u60F3\u8DD1\u4EC0\u4E48\u5C31\u8DD1\u4EC0\u4E48\uFF09",
3754
+ enum: ["plan", "default", "acceptEdits", "auto", "bypass"]
3755
+ },
3756
+ maxBudgetUsd: {
3757
+ type: "number",
3758
+ description: "\u6BCF\u6B21\u6700\u591A\u82B1\u591A\u5C11\u94B1\uFF08\u7F8E\u5143\uFF0C\u8981\u5927\u4E8E 0\uFF09\u3002\u4E0D\u7ED9\u5C31\u662F 200\u3002\u8FD9\u6D3B\u660E\u663E\u66F4\u8F7B\uFF08\u8BFB\u4E00\u4E2A\u6587\u4EF6\u3001\u53D1\u4E00\u6761\u6D88\u606F\uFF09\u5C31\u7ED9\u5C0F\u4E00\u70B9\uFF0C\u660E\u663E\u66F4\u91CD\uFF08\u626B\u5927\u4ED3\u3001\u591A\u8F6E\u8C03\u7814\uFF09\u5C31\u653E\u5927 \u2014\u2014 \u82B1\u8D85\u4E86\u90A3\u4E00\u8F6E\u4F1A\u505C\u4F4F"
3665
3759
  },
3666
3760
  allowTools: {
3667
3761
  type: "array",
@@ -3687,58 +3781,71 @@ function createScheduleDraftTool(deps) {
3687
3781
  exposure: ToolExposure.Direct,
3688
3782
  supportsParallel: false,
3689
3783
  annotations: {
3690
- readOnlyHint: true,
3691
- destructiveHint: false,
3692
- idempotentHint: true,
3784
+ readOnlyHint: false,
3785
+ destructiveHint: true,
3786
+ idempotentHint: false,
3693
3787
  openWorldHint: false
3694
3788
  },
3695
3789
  operation: "file_read",
3696
3790
  describeTarget: (args) => `schedule_draft:${String(args["action"] ?? "list")}`,
3697
- execute(rawArgs, _ctx) {
3791
+ async execute(rawArgs, ctx) {
3698
3792
  const startedAt = Date.now();
3699
3793
  const action = rawArgs["action"];
3700
3794
  if (action === "list") {
3701
3795
  const rows = deps.list();
3702
- return Promise.resolve(
3703
- say4(
3704
- rows.length === 0 ? "\u4E00\u6761\u5B9A\u65F6\u4EFB\u52A1\u90FD\u8FD8\u6CA1\u6709\u3002\u8981\u65B0\u5EFA\u5C31\u7528 action=create\u3002" : `\u73B0\u6709 ${rows.length} \u6761\uFF1A
3796
+ return say4(
3797
+ rows.length === 0 ? "\u4E00\u6761\u5B9A\u65F6\u4EFB\u52A1\u90FD\u8FD8\u6CA1\u6709\u3002\u8981\u65B0\u5EFA\u5C31\u7528 action=create\u3002" : `\u73B0\u6709 ${rows.length} \u6761\uFF1A
3705
3798
  ${rows.map(describeRow).join("\n")}`,
3706
- true,
3707
- startedAt
3708
- )
3799
+ true,
3800
+ startedAt
3709
3801
  );
3710
3802
  }
3711
3803
  const parsed = parseScheduleDraft(rawArgs);
3712
- if (!parsed.ok) return Promise.resolve(say4(parsed.message, false, startedAt));
3804
+ if (!parsed.ok) return say4(parsed.message, false, startedAt);
3713
3805
  const draft = parsed.value;
3714
3806
  const current = draft.action === "update" ? deps.get(draft.id) : void 0;
3715
3807
  if (draft.action === "update" && current === void 0) {
3716
- return Promise.resolve(
3717
- say4(`\u6CA1\u6709 id \u4E3A ${draft.id} \u7684\u4EFB\u52A1\u3002\u5148\u7528 action=list \u770B\u4E00\u773C\u73B0\u6709\u7684\u3002`, false, startedAt)
3808
+ return say4(
3809
+ `\u6CA1\u6709 id \u4E3A ${draft.id} \u7684\u4EFB\u52A1\u3002\u5148\u7528 action=list \u770B\u4E00\u773C\u73B0\u6709\u7684\u3002`,
3810
+ false,
3811
+ startedAt
3718
3812
  );
3719
3813
  }
3720
3814
  const issues = validateDraft(draft, deps.homeDir, current);
3721
3815
  if (issues.length > 0) {
3722
- return Promise.resolve(
3723
- say4(
3724
- `\u8FD9\u4EFD\u8349\u7A3F\u4FDD\u5B58\u4E0D\u4E86\uFF0C\u5148\u6539\u8FD9\u51E0\u5904\u518D\u4EA4\uFF1A${issues.join("\u3001")}\u3002\uFF08\u8FD9\u4E9B\u662F\u6821\u9A8C\u7801\uFF0C\u542B\u4E49\u770B\u5B57\u9762\uFF1Bdetail \u62EC\u5728\u540E\u9762\uFF09`,
3725
- false,
3726
- startedAt
3727
- )
3816
+ return say4(
3817
+ `\u8FD9\u4EFD\u63D0\u6848\u5B58\u4E0D\u4E0B\u6765\uFF0C\u5148\u6539\u8FD9\u51E0\u5904\u518D\u8BF4\uFF1A${issues.join("\u3001")}\u3002\uFF08\u8FD9\u4E9B\u662F\u6821\u9A8C\u7801\uFF0C\u542B\u4E49\u770B\u5B57\u9762\uFF1Bdetail \u62EC\u5728\u540E\u9762\uFF09`,
3818
+ false,
3819
+ startedAt
3728
3820
  );
3729
3821
  }
3730
3822
  const unattended = unattendedIssues(draft);
3731
3823
  if (unattended.length > 0) {
3732
- return Promise.resolve(
3733
- say4(
3734
- `\u8FD9\u4EFD\u8349\u7A3F\u4FDD\u5B58\u5F97\u4E86\uFF0C\u4F46\u5B83\u5230\u70B9\u4E86**\u8DD1\u4E0D\u51FA\u7ED3\u679C** \u2014\u2014 \u5B9A\u65F6\u4EFB\u52A1\u662F\u65E0\u4EBA\u503C\u5B88\u7684\uFF0C\u6CA1\u4EBA\u5728\u65C1\u8FB9\u56DE\u8BDD\u3002\u6539\u5B8C\u518D\u4EA4\uFF1A
3824
+ return say4(
3825
+ `\u8FD9\u4EFD\u63D0\u6848\u5B58\u5F97\u4E0B\u6765\uFF0C\u4F46\u5B83\u5230\u70B9\u4E86**\u8DD1\u4E0D\u51FA\u7ED3\u679C** \u2014\u2014 \u5B9A\u65F6\u4EFB\u52A1\u662F\u65E0\u4EBA\u503C\u5B88\u7684\uFF0C\u6CA1\u4EBA\u5728\u65C1\u8FB9\u56DE\u8BDD\u3002\u6539\u5B8C\u518D\u4EA4\uFF1A
3735
3826
  ${unattended.map((x) => `\xB7 ${x}`).join("\n")}`,
3736
- false,
3737
- startedAt
3738
- )
3827
+ false,
3828
+ startedAt
3829
+ );
3830
+ }
3831
+ const readOnly = ctx.permissionLevel === "plan";
3832
+ if (readOnly || deps.save === void 0) {
3833
+ return say4(summarizeProposal(draft, current, readOnly), true, startedAt);
3834
+ }
3835
+ const saved = await persist(deps.save, draft, current);
3836
+ if (saved.issues.length > 0) {
3837
+ const codes = saved.issues.map((x) => x.detail ? `${x.code}\uFF08${x.detail}\uFF09` : x.code);
3838
+ return say4(`\u5F15\u64CE\u62D2\u7EDD\u4E86\u8FD9\u4EFD\u63D0\u6848\uFF0C\u4E00\u4E2A\u5B57\u90FD\u6CA1\u5199\uFF1A${codes.join("\u3001")}\u3002`, false, startedAt);
3839
+ }
3840
+ const def = saved.schedule;
3841
+ if (def === void 0) {
3842
+ return say4(
3843
+ "\u5F15\u64CE\u8BF4\u5B58\u4E0B\u6765\u4E86\uFF0C\u4F46\u6CA1\u56DE\u90A3\u6761\u4EFB\u52A1 \u2014\u2014 \u53BB\u81EA\u52A8\u5316\u9762\u677F\u770B\u4E00\u773C\u5B83\u5230\u5E95\u5728\u4E0D\u5728\u3002",
3844
+ false,
3845
+ startedAt
3739
3846
  );
3740
3847
  }
3741
- return Promise.resolve(say4(summarize(draft, current), true, startedAt));
3848
+ return say4(summarizeSaved(draft, def, saved.registration, current), true, startedAt);
3742
3849
  }
3743
3850
  };
3744
3851
  }
@@ -4229,41 +4336,41 @@ function clampWindow(raw, fallback2, max) {
4229
4336
  function stamp2(ms) {
4230
4337
  return new Date(ms).toISOString().slice(0, 16).replace("T", " ");
4231
4338
  }
4232
- function budgetOf(total) {
4339
+ function budgetOf2(total) {
4233
4340
  const shares = ANCHOR_SHARE + Math.max(0, total - 1);
4234
4341
  const unit = Math.max(MIN_BODY, Math.floor(BODY_BUDGET / shares));
4235
4342
  return { anchor: unit * ANCHOR_SHARE, other: unit };
4236
4343
  }
4237
- function body(text, budget) {
4344
+ function body(text, budget2) {
4238
4345
  const flat = text.replace(/\r\n/g, "\n").trimEnd();
4239
- if (flat.length <= budget) return flat;
4240
- const rest = flat.length - budget;
4241
- return `${flat.slice(0, budget)}
4346
+ if (flat.length <= budget2) return flat;
4347
+ const rest = flat.length - budget2;
4348
+ return `${flat.slice(0, budget2)}
4242
4349
  \u2026[cut ${rest} more chars \u2014 lower before/after to spend the budget on fewer messages]`;
4243
4350
  }
4244
4351
  function surfaceOf(record, isCurrent) {
4245
4352
  if (!isCurrent) return record.surface === "active" ? "active there" : "compacted there";
4246
4353
  return record.surface === "active" ? "still in your context" : "compacted out of your context";
4247
4354
  }
4248
- function renderRecord(record, mark, budget, isCurrent) {
4355
+ function renderRecord(record, mark, budget2, isCurrent) {
4249
4356
  const tool = record.toolName ? ` \xB7 ${record.toolName}` : "";
4250
4357
  return [
4251
4358
  `${mark} #${record.messageId} [${record.role}${tool} \xB7 ${stamp2(record.timestamp)} \xB7 ${surfaceOf(record, isCurrent)}]`,
4252
- ` ${body(record.content, budget).split("\n").join("\n ")}`
4359
+ ` ${body(record.content, budget2).split("\n").join("\n ")}`
4253
4360
  ].join("\n");
4254
4361
  }
4255
4362
  function renderWindow(out, sessionId, isCurrent) {
4256
4363
  const anchor = out.anchor;
4257
4364
  if (!anchor) return "";
4258
4365
  const count = out.before.length + out.after.length + 1;
4259
- const budget = budgetOf(count);
4366
+ const budget2 = budgetOf2(count);
4260
4367
  return [
4261
4368
  `Session ${sessionId}${isCurrent ? " (this session)" : ""} \u2014 ${out.title || "(untitled)"}`,
4262
4369
  `${count} of ${out.total} message(s), around #${anchor.messageId}:`,
4263
4370
  "",
4264
- ...out.before.map((r) => renderRecord(r, " ", budget.other, isCurrent)),
4265
- renderRecord(anchor, "\xBB", budget.anchor, isCurrent),
4266
- ...out.after.map((r) => renderRecord(r, " ", budget.other, isCurrent))
4371
+ ...out.before.map((r) => renderRecord(r, " ", budget2.other, isCurrent)),
4372
+ renderRecord(anchor, "\xBB", budget2.anchor, isCurrent),
4373
+ ...out.after.map((r) => renderRecord(r, " ", budget2.other, isCurrent))
4267
4374
  ].join("\n");
4268
4375
  }
4269
4376
  function createSessionMessagesReadTool(deps) {
@@ -6156,7 +6263,7 @@ function loadCommandDefinitions(opts) {
6156
6263
  }
6157
6264
  diags?.ok(
6158
6265
  SLASH_COMMANDS_DIAG_MODULE,
6159
- summarize2(commands.length, plugin.commands.length, user, project)
6266
+ summarize(commands.length, plugin.commands.length, user, project)
6160
6267
  );
6161
6268
  return {
6162
6269
  commands,
@@ -6167,7 +6274,7 @@ function loadCommandDefinitions(opts) {
6167
6274
  issues: [...plugin.issues, ...user.issues, ...project.issues]
6168
6275
  };
6169
6276
  }
6170
- function summarize2(total, pluginCount, user, project) {
6277
+ function summarize(total, pluginCount, user, project) {
6171
6278
  if (total === 0) return t("custom_command.none");
6172
6279
  const parts = [
6173
6280
  t("custom_command.count_user", { count: user.commands.length }),
@@ -8924,7 +9031,7 @@ async function snapshotFiles(paths) {
8924
9031
  }
8925
9032
  async function collectDiffs(before, workDir) {
8926
9033
  const out = [];
8927
- let budget = MAX_CALL_BYTES;
9034
+ let budget2 = MAX_CALL_BYTES;
8928
9035
  for (const [path, old] of before) {
8929
9036
  if (old.kind === "opaque") continue;
8930
9037
  const now = await readSnapshot(path);
@@ -8932,8 +9039,8 @@ async function collectDiffs(before, workDir) {
8932
9039
  if (old.kind === "absent" && now.kind === "absent") continue;
8933
9040
  if (old.kind === "text" && now.kind === "text" && old.text === now.text) continue;
8934
9041
  const bytes = (old.kind === "text" ? old.bytes : 0) + (now.kind === "text" ? now.bytes : 0);
8935
- if (bytes > budget) continue;
8936
- budget -= bytes;
9042
+ if (bytes > budget2) continue;
9043
+ budget2 -= bytes;
8937
9044
  out.push({
8938
9045
  filePath: workspaceDisplayPath(path, workDir),
8939
9046
  ...old.kind === "text" ? { oldContent: old.text } : {},
@@ -9521,10 +9628,10 @@ function renderSettings(s) {
9521
9628
  bits.push(`\u4E0A\u4E0B\u6587\u7A97\u53E3 ${s.contextLength}`);
9522
9629
  bits.push(`\u81EA\u52A8\u538B\u7F29 ${s.compression.enabled ? `\u5F00\uFF08${s.compression.threshold}\uFF09` : "\u5173"}`);
9523
9630
  bits.push(`\u7EC8\u7AEF\u6C99\u7BB1 ${s.sandboxTerminal ? "\u5F00" : "\u5173"}`);
9524
- const budget = [];
9525
- if (s.budget?.maxCostUsd !== void 0) budget.push(`$${s.budget.maxCostUsd}`);
9526
- if (s.budget?.maxTokens !== void 0) budget.push(`${s.budget.maxTokens} tokens`);
9527
- bits.push(`\u9884\u7B97\u4E0A\u9650 ${budget.length > 0 ? budget.join(" / ") : "\u672A\u8BBE"}`);
9631
+ const budget2 = [];
9632
+ if (s.budget?.maxCostUsd !== void 0) budget2.push(`$${s.budget.maxCostUsd}`);
9633
+ if (s.budget?.maxTokens !== void 0) budget2.push(`${s.budget.maxTokens} tokens`);
9634
+ bits.push(`\u9884\u7B97\u4E0A\u9650 ${budget2.length > 0 ? budget2.join(" / ") : "\u672A\u8BBE"}`);
9528
9635
  return [
9529
9636
  "<settings>",
9530
9637
  bits.join(" \xB7 "),
@@ -9641,7 +9748,7 @@ function extensionFor(mediaType) {
9641
9748
  if (sub === "jpeg") return ".jpg";
9642
9749
  return /^[a-z0-9]{1,8}$/.test(sub) ? `.${sub}` : ".bin";
9643
9750
  }
9644
- function persist(bytes, mediaType, dir, hint) {
9751
+ function persist2(bytes, mediaType, dir, hint) {
9645
9752
  const digest2 = createHash("sha256").update(bytes).digest("hex").slice(0, 16);
9646
9753
  const safeHint = (hint ?? "").replace(/[^A-Za-z0-9_-]/g, "").slice(0, 40);
9647
9754
  const stem = safeHint ? `${safeHint}-${digest2}` : digest2;
@@ -9682,7 +9789,7 @@ function admitArtifact(raw, policy) {
9682
9789
  const bytes = Buffer.from(raw.base64, "base64");
9683
9790
  const byteLen = bytes.length;
9684
9791
  const size = raw.kind === "image" ? readImageSize(bytes) : void 0;
9685
- const path = policy.artifactsDir ? persist(bytes, raw.mediaType, policy.artifactsDir, raw.filename) : void 0;
9792
+ const path = policy.artifactsDir ? persist2(bytes, raw.mediaType, policy.artifactsDir, raw.filename) : void 0;
9686
9793
  const dims = size ? ` ${size.width}\xD7${size.height}` : "";
9687
9794
  const head = raw.note ? `${raw.note} ` : "";
9688
9795
  const reason9 = rejectionReason(raw, policy, byteLen, size);
@@ -11768,7 +11875,7 @@ function toAbsolute2(path, workDir) {
11768
11875
  }
11769
11876
  var MAX_TOOL_OUTPUT = 3e4;
11770
11877
  var MAX_SUB_CALL_OUTPUT = CODE_MODE_LIMITS.maxValueChars;
11771
- function budgetOf2(tool, depth, path = "success") {
11878
+ function budgetOf3(tool, depth, path = "success") {
11772
11879
  if (tool.governsOwnOutput && path === "success") return Number.POSITIVE_INFINITY;
11773
11880
  return depth > 0 ? MAX_SUB_CALL_OUTPUT : MAX_TOOL_OUTPUT;
11774
11881
  }
@@ -12019,7 +12126,7 @@ var ToolExecutor = class {
12019
12126
  permissionLevel: this.deps.permissionManager?.getLevel() || "auto",
12020
12127
  ...signal ? { signal } : {},
12021
12128
  ...onOutput ? { onOutput } : {},
12022
- outputBudget: budgetOf2(et, depth),
12129
+ outputBudget: budgetOf3(et, depth),
12023
12130
  ...depth < MAX_SUB_CALL_DEPTH ? { callTool: this.subCallChannel(sessionId, signal, span, depth) } : {}
12024
12131
  });
12025
12132
  if (snapshotted.length > 0) {
@@ -12051,7 +12158,7 @@ var ToolExecutor = class {
12051
12158
  success: true,
12052
12159
  output: this.renderOutput(
12053
12160
  et,
12054
- appendArtifactSummaries(text, artifacts, budgetOf2(et, depth), shapeOf(r.output))
12161
+ appendArtifactSummaries(text, artifacts, budgetOf3(et, depth), shapeOf(r.output))
12055
12162
  ),
12056
12163
  ...artifacts.length > 0 ? { artifacts } : {},
12057
12164
  ...diffs.length > 0 ? { diffs } : {}
@@ -12062,7 +12169,7 @@ var ToolExecutor = class {
12062
12169
  success: false,
12063
12170
  output: this.renderOutput(
12064
12171
  et,
12065
- truncateForModel(failureText(r), budgetOf2(et, depth, "failure"), "text")
12172
+ truncateForModel(failureText(r), budgetOf3(et, depth, "failure"), "text")
12066
12173
  )
12067
12174
  });
12068
12175
  } catch (err) {
@@ -12239,13 +12346,13 @@ function stripHistoryImages(history) {
12239
12346
  });
12240
12347
  return { messages, stripped };
12241
12348
  }
12242
- function budgetStop(budget, messages) {
12243
- const breach = budget.breachReason();
12244
- if (breach) return { message: budget.describeBreach(breach), breach };
12349
+ function budgetStop(budget2, messages) {
12350
+ const breach = budget2.breachReason();
12351
+ if (breach) return { message: budget2.describeBreach(breach), breach };
12245
12352
  const imageTokens = pendingImageTokens(messages);
12246
- const projected = budget.projectedBreach(imageTokens);
12353
+ const projected = budget2.projectedBreach(imageTokens);
12247
12354
  if (!projected) return void 0;
12248
- return { message: budget.describeProjectedBreach(projected, imageTokens), breach: projected };
12355
+ return { message: budget2.describeProjectedBreach(projected, imageTokens), breach: projected };
12249
12356
  }
12250
12357
  var AgentLoop = class {
12251
12358
  config;
@@ -12481,7 +12588,7 @@ var AgentLoop = class {
12481
12588
  const addRun = (u) => {
12482
12589
  runUsage = runUsage ? addUsage(runUsage, u) : u;
12483
12590
  };
12484
- const budget = new BudgetGuard({
12591
+ const budget2 = new BudgetGuard({
12485
12592
  ...this.config.budget ? { budget: this.config.budget } : {},
12486
12593
  ...this.config.modelPricing ? { pricing: this.config.modelPricing } : {},
12487
12594
  ...input.maxCallCostUsd !== void 0 ? { maxCallCostUsd: input.maxCallCostUsd } : {},
@@ -12493,7 +12600,7 @@ var AgentLoop = class {
12493
12600
  const finish = (reason9, breach) => ({
12494
12601
  type: "finish",
12495
12602
  reason: reason9,
12496
- usage: budget.snapshot(),
12603
+ usage: budget2.snapshot(),
12497
12604
  ...runUsage ? { runUsage } : {},
12498
12605
  ...lastModel ? { model: lastModel } : {},
12499
12606
  ...lastRequestedModel ? { requestedModel: lastRequestedModel } : {},
@@ -12545,8 +12652,8 @@ var AgentLoop = class {
12545
12652
  await this.prompt.syncMemory(userText, lastText);
12546
12653
  return;
12547
12654
  }
12548
- budget.syncFromStore();
12549
- const stop = budgetStop(budget, messages);
12655
+ budget2.syncFromStore();
12656
+ const stop = budgetStop(budget2, messages);
12550
12657
  if (stop) {
12551
12658
  yield { type: "text-delta", text: stop.message };
12552
12659
  await this.prompt.syncMemory(userText, lastText || stop.message);
@@ -12598,8 +12705,8 @@ var AgentLoop = class {
12598
12705
  }
12599
12706
  if (rescued.usage) {
12600
12707
  addRun(rescued.usage);
12601
- yield* budget.toEvents(
12602
- budget.add(rescued.usage, this.rateOf(rescued.model)),
12708
+ yield* budget2.toEvents(
12709
+ budget2.add(rescued.usage, this.rateOf(rescued.model)),
12603
12710
  runUsage
12604
12711
  );
12605
12712
  }
@@ -12675,7 +12782,7 @@ var AgentLoop = class {
12675
12782
  });
12676
12783
  if (rescued.usage) {
12677
12784
  addRun(rescued.usage);
12678
- yield* budget.toEvents(budget.add(rescued.usage, this.rateOf(rescued.model)), runUsage);
12785
+ yield* budget2.toEvents(budget2.add(rescued.usage, this.rateOf(rescued.model)), runUsage);
12679
12786
  }
12680
12787
  if (!shrank(messages, rescued.messages)) throw err;
12681
12788
  messages = rescued.messages;
@@ -12732,14 +12839,14 @@ var AgentLoop = class {
12732
12839
  "epoch.token_type": "cache_write"
12733
12840
  });
12734
12841
  }
12735
- const status = budget.add(usage, this.rateOf(result.model));
12842
+ const status = budget2.add(usage, this.rateOf(result.model));
12736
12843
  input.onTurnUsage?.(
12737
12844
  status.turnCostUsd === void 0 ? usage : { ...usage, costUsd: status.turnCostUsd }
12738
12845
  );
12739
12846
  addRun(usage);
12740
12847
  lastModel = result.model;
12741
12848
  lastRequestedModel = result.requestedModel;
12742
- yield* budget.toEvents(status, runUsage);
12849
+ yield* budget2.toEvents(status, runUsage);
12743
12850
  }
12744
12851
  const verdict = mergeVerdicts(guard?.verdict(), reasoningGuard?.verdict());
12745
12852
  if (verdict) this.reportCompliance(verdict, "output");
@@ -12976,8 +13083,8 @@ ${finalText}` };
12976
13083
  messages = compacted.messages;
12977
13084
  if (compacted.usage) {
12978
13085
  addRun(compacted.usage);
12979
- yield* budget.toEvents(
12980
- budget.add(compacted.usage, this.rateOf(compacted.model)),
13086
+ yield* budget2.toEvents(
13087
+ budget2.add(compacted.usage, this.rateOf(compacted.model)),
12981
13088
  runUsage
12982
13089
  );
12983
13090
  }
@@ -16916,8 +17023,8 @@ var MemoryManager = class {
16916
17023
  async add(target, content) {
16917
17024
  const label = injectionLabelOf(content);
16918
17025
  if (label !== void 0) return this.refuseInjection(label);
16919
- const budget = this.getBudget()[target];
16920
- if (budget.current + content.length > budget.limit) {
17026
+ const budget2 = this.getBudget()[target];
17027
+ if (budget2.current + content.length > budget2.limit) {
16921
17028
  this.consolidationFailures++;
16922
17029
  if (this.consolidationFailures > MAX_CONSOLIDATION_FAILURES_PER_TURN) {
16923
17030
  return {
@@ -16964,9 +17071,9 @@ var MemoryManager = class {
16964
17071
  }
16965
17072
  const label = injectionLabelOf(content);
16966
17073
  if (label !== void 0) return this.refuseInjection(label);
16967
- const budget = this.getBudget()[target];
17074
+ const budget2 = this.getBudget()[target];
16968
17075
  const delta = content.length - existing.charLength;
16969
- if (budget.current + delta > budget.limit) {
17076
+ if (budget2.current + delta > budget2.limit) {
16970
17077
  this.consolidationFailures++;
16971
17078
  if (this.consolidationFailures > MAX_CONSOLIDATION_FAILURES_PER_TURN) {
16972
17079
  return { success: false, done: true, error: "Consolidation limit reached" };
@@ -17171,11 +17278,11 @@ var MemoryManager = class {
17171
17278
  for (const target of ["memory", "user"]) {
17172
17279
  const rows = kept.filter((e) => e.target === target);
17173
17280
  if (rows.length === 0) continue;
17174
- const budget = this.getBudget()[target];
17281
+ const budget2 = this.getBudget()[target];
17175
17282
  const label = target === "user" ? "USER PROFILE (who the user is)" : "MEMORY (your personal notes)";
17176
17283
  sections.push(
17177
17284
  [
17178
- `${label} [${rows.length} entries \xB7 ${budget.current.toLocaleString()}/${budget.limit.toLocaleString()} chars]`,
17285
+ `${label} [${rows.length} entries \xB7 ${budget2.current.toLocaleString()}/${budget2.limit.toLocaleString()} chars]`,
17179
17286
  ...rows.map((e) => this.indexLine(e))
17180
17287
  ].join("\n")
17181
17288
  );
@@ -17206,7 +17313,7 @@ var MemoryManager = class {
17206
17313
  return `${e.id} ${e.summary} (${e.charLength} chars)`;
17207
17314
  }
17208
17315
  buildConsolidateHint(target) {
17209
- const budget = this.getBudget()[target];
17316
+ const budget2 = this.getBudget()[target];
17210
17317
  const heat = /* @__PURE__ */ new Map();
17211
17318
  for (const row of this.db.getAll(target)) {
17212
17319
  const id = this.idByContent.get(contentKey(row.target, row.content));
@@ -17214,7 +17321,7 @@ var MemoryManager = class {
17214
17321
  }
17215
17322
  const candidates2 = this.indexEntries(target).sort((a, b) => (heat.get(a.id) ?? 0) - (heat.get(b.id) ?? 0) || b.charLength - a.charLength).slice(0, 5);
17216
17323
  return [
17217
- `Memory at ${budget.current.toLocaleString()}/${budget.limit.toLocaleString()} chars (${budget.percent}%) for ${target}. Cannot add new entry.`,
17324
+ `Memory at ${budget2.current.toLocaleString()}/${budget2.limit.toLocaleString()} chars (${budget2.percent}%) for ${target}. Cannot add new entry.`,
17218
17325
  "",
17219
17326
  "To make room, work by id \u2014 NOT by old_text. The MEMORY INDEX only shows a truncated",
17220
17327
  "first line, so text copied from it will never match an entry exactly.",
@@ -19087,7 +19194,7 @@ var SessionManager = class {
19087
19194
  search(input) {
19088
19195
  return this.db.search(input);
19089
19196
  }
19090
- async compact(sessionId, summarize3) {
19197
+ async compact(sessionId, summarize2) {
19091
19198
  const messages = this.db.getMessages(sessionId);
19092
19199
  const beforeCount = messages.length;
19093
19200
  const IMPORTANT_ROUNDS = 5;
@@ -19098,17 +19205,17 @@ var SessionManager = class {
19098
19205
  0,
19099
19206
  Math.max(0, keyMessages.length - IMPORTANT_ROUNDS * 2)
19100
19207
  );
19101
- const summary = toSummarize.length === 0 ? "" : await this.buildSummary(toSummarize, summarize3) ?? outlineOf(toSummarize);
19208
+ const summary = toSummarize.length === 0 ? "" : await this.buildSummary(toSummarize, summarize2) ?? outlineOf(toSummarize);
19102
19209
  return this.db.compact(sessionId, summary, beforeCount, IMPORTANT_ROUNDS * 2);
19103
19210
  }
19104
19211
  archiveAndCompact(sessionId, input) {
19105
19212
  return this.db.archiveAndCompact(sessionId, input);
19106
19213
  }
19107
- async buildSummary(msgs, summarize3) {
19108
- if (!summarize3) return null;
19214
+ async buildSummary(msgs, summarize2) {
19215
+ if (!summarize2) return null;
19109
19216
  const transcript = msgs.map((m) => `[${m.role}] ${m.content}`).join("\n\n");
19110
19217
  try {
19111
- const result = await summarize3(transcript);
19218
+ const result = await summarize2(transcript);
19112
19219
  return result?.trim() ? result.trim() : null;
19113
19220
  } catch {
19114
19221
  return null;
@@ -19296,8 +19403,8 @@ var GoalService = class {
19296
19403
  const text = objective.trim();
19297
19404
  if (!text) return { ok: false, reason: "empty-objective" };
19298
19405
  if (text.length > MAX_OBJECTIVE_CHARS) return { ok: false, reason: "objective-too-long" };
19299
- const budget = maxRounds ?? DEFAULT_GOAL_MAX_ROUNDS;
19300
- if (!Number.isInteger(budget) || budget < 1 || budget > MAX_GOAL_MAX_ROUNDS) {
19406
+ const budget2 = maxRounds ?? DEFAULT_GOAL_MAX_ROUNDS;
19407
+ if (!Number.isInteger(budget2) || budget2 < 1 || budget2 > MAX_GOAL_MAX_ROUNDS) {
19301
19408
  return { ok: false, reason: "bad-budget" };
19302
19409
  }
19303
19410
  const existing = this.current(sessionId);
@@ -19309,7 +19416,7 @@ var GoalService = class {
19309
19416
  objective: text,
19310
19417
  phase: "active",
19311
19418
  block: void 0,
19312
- maxRounds: budget,
19419
+ maxRounds: budget2,
19313
19420
  roundsUsed: 0,
19314
19421
  completeEvidence: void 0,
19315
19422
  createdAt: at,
@@ -23437,7 +23544,7 @@ function stageSkillDir(source, staging, category, name, skills, issues, lang) {
23437
23544
  const dir = join(staging, category, name);
23438
23545
  mkdirSync(dir, { recursive: true });
23439
23546
  copyFileSync(join(source, SKILL_FILE), join(dir, SKILL_FILE));
23440
- let budget = MAX_FILES_PER_SKILL - 1;
23547
+ let budget2 = MAX_FILES_PER_SKILL - 1;
23441
23548
  for (const entry of readEntries2(source, label, issues, lang)) {
23442
23549
  if (entry.name === SKILL_FILE) continue;
23443
23550
  if (!entry.isDir || !SKILL_ASSET_DIRS.includes(entry.name)) {
@@ -23447,7 +23554,7 @@ function stageSkillDir(source, staging, category, name, skills, issues, lang) {
23447
23554
  });
23448
23555
  continue;
23449
23556
  }
23450
- budget = copyTree(join(source, entry.name), join(dir, entry.name), label, budget, issues, lang);
23557
+ budget2 = copyTree(join(source, entry.name), join(dir, entry.name), label, budget2, issues, lang);
23451
23558
  }
23452
23559
  skills.push({ name, category, dir });
23453
23560
  }
@@ -23506,8 +23613,8 @@ function placeOf(root, parts, lang) {
23506
23613
  const category = parts.at(-2) ?? "general";
23507
23614
  return { name, category: skillSegmentIssue(category, lang) === void 0 ? category : "general" };
23508
23615
  }
23509
- function copyTree(from, to, label, budget, issues, lang) {
23510
- let left = budget;
23616
+ function copyTree(from, to, label, budget2, issues, lang) {
23617
+ let left = budget2;
23511
23618
  mkdirSync(to, { recursive: true });
23512
23619
  for (const entry of readEntries2(from, label, issues, lang)) {
23513
23620
  if (left <= 0) {
@@ -24571,11 +24678,11 @@ function readOne(path, opts, usedBytes) {
24571
24678
  }
24572
24679
  const remaining = MAX_ATTACH_TOTAL_BYTES - usedBytes;
24573
24680
  if (remaining <= 0) return { part: { type: "file", path, omitted: "over-limit", bytes: size } };
24574
- const budget = Math.min(MAX_ATTACH_BYTES, remaining);
24575
- if (raw.length <= budget) {
24681
+ const budget2 = Math.min(MAX_ATTACH_BYTES, remaining);
24682
+ if (raw.length <= budget2) {
24576
24683
  return { part: { type: "file", path, text: raw.toString("utf8"), bytes: size } };
24577
24684
  }
24578
- const { text, truncatedTo } = truncateToBudget(raw, budget);
24685
+ const { text, truncatedTo } = truncateToBudget(raw, budget2);
24579
24686
  return {
24580
24687
  part: { type: "file", path, text, truncatedTo, bytes: size },
24581
24688
  notice: t("mentions.truncated", {