@epoch-agent/core 0.14.0 → 0.15.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
@@ -2,7 +2,7 @@ import { existsSync, statSync, readdirSync, readFileSync, mkdirSync, writeFileSy
2
2
  import { homedir, platform, tmpdir, hostname } from 'os';
3
3
  import { join, dirname, resolve, relative, isAbsolute, sep, extname, basename } from 'path';
4
4
  import { execFile, execSync, execFileSync, spawn } from 'child_process';
5
- import { createLogger, dbPath, resolveHomeDir, DEFAULT_MAX_TURNS, PROJECT_DIR_NAME, guardSpawn, t, suggestKey, misspelledKeyIssues, openDatabase, migrate, releaseDatabase, parseLenient, issueDetails, splitWords, unknownKeyIssues, checkpointsDir, pluginsDir, projectHooksPath, projectClaudeSettingsPath, projectClaudeLocalSettingsPath, projectSettingsPath, projectLocalSettingsPath, projectPoliciesDir, trustedImportsPath, budgetStatePath, artifactsDir, UNLIMITED_TURNS, turnLimitOf, configPath, managedSettingsPath, getSecretValues, listStoredSecretNames, maskApiKey, setSectionField, countCodePoints, headCodePoints, isInWorkspace, workspacesPath, samePath, lastSessionsPath, automationLogsDir, projectComplianceDir, projectSkillsDir, attachmentsDir, trustPath, projectCommandsDir, detectBackend, EXEC_PATH_AS_NODE_ENV, isolate, createStreamDecoder, parseShellCommand, writeArtifact, envPath, checkDangerousCommand, checkObfuscation, keepHeadAndTail, normalizeForMatch, isReadOnlyCommand, CODE_EXEC_ROOTS, tailCodePoints } from '@epoch-agent/infra';
5
+ import { createLogger, dbPath, resolveHomeDir, DEFAULT_MAX_TURNS, PROJECT_DIR_NAME, guardSpawn, t, suggestKey, misspelledKeyIssues, openDatabase, migrate, releaseDatabase, parseLenient, issueDetails, splitWords, unknownKeyIssues, checkpointsDir, pluginsDir, projectHooksPath, projectClaudeSettingsPath, projectClaudeLocalSettingsPath, projectSettingsPath, projectLocalSettingsPath, projectPoliciesDir, trustedImportsPath, canProbeGit, budgetStatePath, artifactsDir, UNLIMITED_TURNS, turnLimitOf, configPath, managedSettingsPath, getSecretValues, listStoredSecretNames, maskApiKey, setSectionField, countCodePoints, headCodePoints, attachmentsDir, isInWorkspace, workspacesPath, samePath, lastSessionsPath, automationLogsDir, projectComplianceDir, projectSkillsDir, trustPath, projectCommandsDir, detectBackend, EXEC_PATH_AS_NODE_ENV, isolate, createStreamDecoder, parseShellCommand, writeArtifact, envPath, checkDangerousCommand, checkObfuscation, keepHeadAndTail, normalizeForMatch, isReadOnlyCommand, CODE_EXEC_ROOTS, tailCodePoints } from '@epoch-agent/infra';
6
6
  export { IS_WINDOWS, WINDOWS_HIDE_FLAGS, buildBwrapArgs, buildProfile, checkDangerousCommand, checkObfuscation, createLogger, detectBackend, getDefaultShell, getPythonCommand, isInWorkspace, isReadOnlyCommand, isolate, maskApiKey, probeBubblewrap, probeSeatbelt, complianceDir as resolveComplianceDir, policiesDir as resolvePoliciesDir, setLogLevel } from '@epoch-agent/infra';
7
7
  import { PROVIDER_TYPES, OPERATION_TYPES as OPERATION_TYPES$1, COMPLIANCE_CATEGORIES, COMPLIANCE_ACTIONS, SEARCH_PROVIDER_TYPES, CURRENCIES, LANGS, PERMISSION_LEVELS, SHELL_KINDS, ToolExposure, MAX_OPTIONS, MIN_OPTIONS, MAX_HEADER_CHARS, MAX_QUESTIONS, SCHEDULE_INTERVAL_MINUTES, isPermissionLevel, SCHEDULE_DRAFT_TOOL, isValidAgentRoleName, DEFAULT_AGENT_ROLE, isValidCommandName, RESERVED_COMMAND_NAMES, parseModelRef, isWirePluginArchiveName, systemNote, formatMoney, totalUsageTokens, NOOP_TELEMETRY, METRIC, contentToText, GEN_AI, isPromptOversize, promptTokens, apiKeyEnvVar, PROVIDER_INFOS, isProviderType, API_KEY_ENV_VARS, KEY_ACTIONS, tableOf, perAction, isKeyAction, parseSequence, RESERVED_CHORDS, chordId, sequenceId, ACTION_CONTEXTS, SEQUENCE_CONTEXTS, assertNeverPart, MAX_ATTACH_FILES, MAX_ATTACH_TOTAL_BYTES, MAX_SESSION_REFS, utf8ByteLength, truncateToBudget, attachSessionSurface, isContextNearlyFull, isOperationType, normalizeApproval, imagePartOmittedSummary, MAX_ATTACH_BYTES, SIMULTANEOUS_CONTEXTS, SESSION_REFERENCE_ERROR_CODES, filePartSummary, sessionPartSummary } from '@epoch-agent/protocol';
8
8
  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';
@@ -542,6 +542,7 @@ var INTERNAL_TOOLS = /* @__PURE__ */ new Set([
542
542
  "session_messages_search",
543
543
  "session_messages_read",
544
544
  "session_trace",
545
+ "session_list",
545
546
  "goal",
546
547
  "skill_view",
547
548
  "tool_search",
@@ -1117,6 +1118,7 @@ var BLOCKED_TOOLS = Object.freeze([
1117
1118
  "session_messages_search",
1118
1119
  "session_messages_read",
1119
1120
  "session_trace",
1121
+ "session_list",
1120
1122
  "goal"
1121
1123
  ]);
1122
1124
  var DelegateManager = class {
@@ -3438,11 +3440,13 @@ var SESSION_SEARCH_TOOL = "session_search";
3438
3440
  var SESSION_MESSAGES_SEARCH_TOOL = "session_messages_search";
3439
3441
  var SESSION_MESSAGES_READ_TOOL = "session_messages_read";
3440
3442
  var SESSION_TRACE_TOOL = "session_trace";
3443
+ var SESSION_LIST_TOOL = "session_list";
3441
3444
  var SESSION_QUERY_TOOLS = Object.freeze([
3442
3445
  SESSION_SEARCH_TOOL,
3443
3446
  SESSION_MESSAGES_SEARCH_TOOL,
3444
3447
  SESSION_MESSAGES_READ_TOOL,
3445
- SESSION_TRACE_TOOL
3448
+ SESSION_TRACE_TOOL,
3449
+ SESSION_LIST_TOOL
3446
3450
  ]);
3447
3451
  var MAX_SNIPPET = 160;
3448
3452
  var CANDIDATE_FACTOR = 4;
@@ -3536,6 +3540,36 @@ var SessionQueries = class {
3536
3540
  trace(input) {
3537
3541
  return traceSession(this.db, input);
3538
3542
  }
3543
+ listSessions(input) {
3544
+ const vis = resolveSessionVisibility({ ...input, db: this.db });
3545
+ const archivedClause = input.archived === "all" ? "" : input.archived === "only" ? "AND s.archived = 1" : "AND s.archived = 0";
3546
+ const where = `${vis.clause} ${archivedClause}`;
3547
+ const total = this.db.prepare(`SELECT count(*) AS n FROM sessions s WHERE ${where}`).get(vis.params).n;
3548
+ const rows = this.db.prepare(
3549
+ `SELECT s.id,
3550
+ COALESCE(NULLIF(s.display_name, ''), s.title) AS title,
3551
+ s.cwd,
3552
+ COALESCE(s.updated_at, s.started_at) AS updated_at,
3553
+ s.message_count,
3554
+ s.archived
3555
+ FROM sessions s
3556
+ WHERE ${where}
3557
+ ORDER BY COALESCE(s.updated_at, s.started_at) DESC
3558
+ LIMIT @limit`
3559
+ ).all({ ...vis.params, limit: input.limit });
3560
+ return {
3561
+ total,
3562
+ sessions: rows.map((row) => ({
3563
+ sessionId: row.id,
3564
+ title: row.title,
3565
+ cwd: row.cwd ?? void 0,
3566
+ updatedAt: row.updated_at,
3567
+ messageCount: row.message_count,
3568
+ archived: row.archived === 1,
3569
+ isCurrent: row.id === input.currentSessionId
3570
+ }))
3571
+ };
3572
+ }
3539
3573
  contentRows(safe, limit, visClause, visParams) {
3540
3574
  const sql = (table) => `
3541
3575
  SELECT m.id, m.session_id, m.role, m.content, m.timestamp, m.active,
@@ -3601,7 +3635,123 @@ var SessionQueries = class {
3601
3635
  return this.db.prepare(sql("messages_fts_trigram")).all({ query: buildTrigramMatchQuery(safe), sid: sessionId, limit });
3602
3636
  }
3603
3637
  };
3604
- // src/tools/builtin/session-read.ts
3638
+ // src/tools/builtin/session-list.ts
3639
+ var DEFAULT_LIMIT = 10;
3640
+ var MAX_LIMIT = 30;
3641
+ var MAX_TITLE = 80;
3642
+ function fail3(message, start, code, suggestion) {
3643
+ return {
3644
+ success: false,
3645
+ output: "",
3646
+ error: { code, message, ...{} },
3647
+ duration: Date.now() - start
3648
+ };
3649
+ }
3650
+ function clampLimit(raw) {
3651
+ const n = Number(raw);
3652
+ if (!Number.isFinite(n) || n <= 0) return DEFAULT_LIMIT;
3653
+ return Math.min(Math.floor(n), MAX_LIMIT);
3654
+ }
3655
+ function stamp(ms) {
3656
+ return new Date(ms).toISOString().slice(0, 16).replace("T", " ");
3657
+ }
3658
+ function archivedScopeOf(raw) {
3659
+ return raw === "only" || raw === "all" ? raw : "exclude";
3660
+ }
3661
+ function scopeNote(allWorkspaces, archived) {
3662
+ const where = allWorkspaces ? "all workspaces" : "current workspace + this session lineage";
3663
+ const which = archived === "only" ? "archived only" : archived === "all" ? "archived included" : "archived excluded";
3664
+ return `${where}, ${which}`;
3665
+ }
3666
+ function renderEntry(entry, index) {
3667
+ const self = entry.isCurrent ? " (this session)" : "";
3668
+ const title = entry.title.length > MAX_TITLE ? `${entry.title.slice(0, MAX_TITLE)}\u2026` : entry.title;
3669
+ const where = entry.cwd ? ` \xB7 ${entry.cwd}` : "";
3670
+ const archived = entry.archived ? " \xB7 archived" : "";
3671
+ return [
3672
+ `${index + 1}. ${entry.sessionId}${self} \u2014 ${title || "(untitled)"}`,
3673
+ ` ${stamp(entry.updatedAt)} \xB7 ${entry.messageCount} messages${where}${archived}`
3674
+ ].join("\n");
3675
+ }
3676
+ function render(out, note) {
3677
+ const shown = out.sessions.length;
3678
+ const head = shown < out.total ? `${out.total} session(s) (${note}), showing the ${shown} most recently active:` : `${out.total} session(s) (${note}):`;
3679
+ return [
3680
+ head,
3681
+ "",
3682
+ ...out.sessions.map(renderEntry),
3683
+ "",
3684
+ "Next: session_messages_search({ sessionId, query }) to look inside one, or session_messages_read({ sessionId, messageId }) once you have a hit."
3685
+ ].join("\n");
3686
+ }
3687
+ function createSessionListTool(deps) {
3688
+ return {
3689
+ name: SESSION_LIST_TOOL,
3690
+ description: "\u5217\u51FA\u4F60\u80FD\u8BFB\u5230\u7684\u5386\u53F2\u4F1A\u8BDD \u2014\u2014 \u68C0\u7D22\u90A3\u51E0\u4E2A\u90FD\u8981\u5148\u60F3\u51FA\u4E00\u4E2A\u8BCD\uFF0C\u8FD9\u4E2A\u4E0D\u8981\u3002\n\u7528\u5B83\u56DE\u7B54\u300C\u6211\u90FD\u6709\u54EA\u4E9B\u4F1A\u8BDD\u300D\u300C\u4E0A\u6B21\u90A3\u6BB5\u804A\u7684\u662F\u4EC0\u4E48\u300D\uFF0C\u4EE5\u53CA\u7528\u6237\u63D0\u8D77\u67D0\u6BB5\u8FC7\u53BB\u7684\u4F1A\u8BDD\u5374\u6CA1\u7ED9 id \u7684\u65F6\u5019\u3002\n\u6309\u6700\u540E\u6D3B\u52A8\u5012\u5E8F\uFF0C\u6BCF\u6BB5\u7ED9 sessionId + \u6807\u9898 + \u65F6\u95F4 + \u6D88\u606F\u6570\uFF1B\u62FF\u5230 id \u518D\u7528 session_messages_search \u8FDB\u53BB\u770B\u3002\n\u9ED8\u8BA4\u4E0D\u5217\u5F52\u6863\u7684\u4F1A\u8BDD\uFF08\u5F52\u6863\u662F\u300C\u7528\u6237\u628A\u5B83\u6536\u8D77\u6765\u4E86\u300D\uFF09\u2014\u2014 \u8981\u627E\u5F52\u6863\u7684\u5C31\u4F20 archived\u3002\n\u9ED8\u8BA4\u53EA\u5217\u5F53\u524D\u5DE5\u4F5C\u533A\u7684\u4F1A\u8BDD\uFF0C\u5916\u52A0\u672C\u4F1A\u8BDD fork \u51FA\u6765\u7684\u90A3\u6761\u8840\u7F18\u94FE\u3002",
3691
+ get parameters() {
3692
+ return {
3693
+ type: "object",
3694
+ properties: {
3695
+ limit: {
3696
+ type: "number",
3697
+ description: `\u56DE\u51E0\u6BB5\uFF0C\u9ED8\u8BA4 ${DEFAULT_LIMIT}\uFF0C\u4E0A\u9650 ${MAX_LIMIT}\uFF08\u4F20\u5927\u4E86\u81EA\u52A8\u5939\u7D27\uFF0C\u4E0D\u62A5\u9519\uFF09`
3698
+ },
3699
+ archived: {
3700
+ type: "string",
3701
+ enum: ["exclude", "only", "all"],
3702
+ description: "exclude \u4E0D\u5217\u5F52\u6863\u7684\uFF08\u9ED8\u8BA4\uFF09\uFF1Bonly \u53EA\u5217\u5F52\u6863\u7684\uFF1Ball \u4E24\u8FB9\u90FD\u5217\u3002\u7528\u6237\u63D0\u8D77\u4E00\u6BB5\u300C\u4EE5\u524D\u5F52\u6863\u6389\u7684\u4F1A\u8BDD\u300D\u65F6\u7528 only"
3703
+ },
3704
+ ...deps.allowAllWorkspaces ? {
3705
+ allWorkspaces: {
3706
+ type: "boolean",
3707
+ description: "\u5217\u5168\u90E8\u5DE5\u4F5C\u533A\u7684\u4F1A\u8BDD\uFF08\u9ED8\u8BA4 false\uFF0C\u53EA\u5217\u5F53\u524D\u5DE5\u4F5C\u533A\uFF09"
3708
+ }
3709
+ } : {}
3710
+ },
3711
+ required: []
3712
+ };
3713
+ },
3714
+ exposure: ToolExposure.Direct,
3715
+ supportsParallel: true,
3716
+ annotations: {
3717
+ readOnlyHint: true,
3718
+ destructiveHint: false,
3719
+ idempotentHint: true,
3720
+ openWorldHint: true
3721
+ },
3722
+ operation: "file_read",
3723
+ describeTarget: (args) => `${SESSION_LIST_TOOL}:${archivedScopeOf(args["archived"])}`,
3724
+ execute(args, ctx) {
3725
+ const start = Date.now();
3726
+ const allWorkspaces = deps.allowAllWorkspaces === true && args["allWorkspaces"] === true;
3727
+ const archived = archivedScopeOf(args["archived"]);
3728
+ try {
3729
+ const out = deps.queries.listSessions({
3730
+ limit: clampLimit(args["limit"]),
3731
+ archived,
3732
+ currentSessionId: ctx.sessionId,
3733
+ workspaceCwd: deps.workspaceCwd,
3734
+ allWorkspaces
3735
+ });
3736
+ if (out.sessions.length === 0) {
3737
+ const hint = archived === "exclude" ? ' If the user is asking about a session they archived, retry with archived: "only".' : "";
3738
+ return Promise.resolve({
3739
+ success: true,
3740
+ output: `No session in readable scope (${scopeNote(allWorkspaces, archived)}).${hint}`,
3741
+ duration: Date.now() - start
3742
+ });
3743
+ }
3744
+ return Promise.resolve({
3745
+ success: true,
3746
+ output: render(out, scopeNote(allWorkspaces, archived)),
3747
+ duration: Date.now() - start
3748
+ });
3749
+ } catch (err) {
3750
+ return Promise.resolve(fail3(err instanceof Error ? err.message : String(err), start, 8014));
3751
+ }
3752
+ }
3753
+ };
3754
+ }
3605
3755
  var DEFAULT_WINDOW = 2;
3606
3756
  var MAX_WINDOW = 10;
3607
3757
  var DEFAULT_TRACE_LIMIT = 20;
@@ -3609,7 +3759,7 @@ var MAX_TRACE_LIMIT = 50;
3609
3759
  var BODY_BUDGET = 1500;
3610
3760
  var MIN_BODY = 60;
3611
3761
  var ANCHOR_SHARE = 4;
3612
- function fail3(message, start, code, suggestion) {
3762
+ function fail4(message, start, code, suggestion) {
3613
3763
  return {
3614
3764
  success: false,
3615
3765
  output: "",
@@ -3623,7 +3773,7 @@ function clampWindow(raw, fallback2, max) {
3623
3773
  if (!Number.isFinite(n) || n < 0) return fallback2;
3624
3774
  return Math.min(Math.floor(n), max);
3625
3775
  }
3626
- function stamp(ms) {
3776
+ function stamp2(ms) {
3627
3777
  return new Date(ms).toISOString().slice(0, 16).replace("T", " ");
3628
3778
  }
3629
3779
  function budgetOf(total) {
@@ -3645,7 +3795,7 @@ function surfaceOf(record, isCurrent) {
3645
3795
  function renderRecord(record, mark, budget, isCurrent) {
3646
3796
  const tool = record.toolName ? ` \xB7 ${record.toolName}` : "";
3647
3797
  return [
3648
- `${mark} #${record.messageId} [${record.role}${tool} \xB7 ${stamp(record.timestamp)} \xB7 ${surfaceOf(record, isCurrent)}]`,
3798
+ `${mark} #${record.messageId} [${record.role}${tool} \xB7 ${stamp2(record.timestamp)} \xB7 ${surfaceOf(record, isCurrent)}]`,
3649
3799
  ` ${body(record.content, budget).split("\n").join("\n ")}`
3650
3800
  ].join("\n");
3651
3801
  }
@@ -3711,11 +3861,11 @@ before / after \u5404\u9ED8\u8BA4 ${DEFAULT_WINDOW}\u3001\u4E0A\u9650 ${MAX_WIND
3711
3861
  execute(args, ctx) {
3712
3862
  const start = Date.now();
3713
3863
  const sessionId = String(args["sessionId"] ?? "").trim();
3714
- if (!sessionId) return Promise.resolve(fail3("sessionId must not be empty", start, 8007));
3864
+ if (!sessionId) return Promise.resolve(fail4("sessionId must not be empty", start, 8007));
3715
3865
  const messageId = Number(args["messageId"]);
3716
3866
  if (!Number.isInteger(messageId) || messageId <= 0) {
3717
3867
  return Promise.resolve(
3718
- fail3(
3868
+ fail4(
3719
3869
  "messageId must be a positive integer",
3720
3870
  start,
3721
3871
  8008,
@@ -3736,7 +3886,7 @@ before / after \u5404\u9ED8\u8BA4 ${DEFAULT_WINDOW}\u3001\u4E0A\u9650 ${MAX_WIND
3736
3886
  });
3737
3887
  if (!out.authorized) {
3738
3888
  return Promise.resolve(
3739
- fail3(
3889
+ fail4(
3740
3890
  `session ${sessionId} is out of readable scope`,
3741
3891
  start,
3742
3892
  8009,
@@ -3746,7 +3896,7 @@ before / after \u5404\u9ED8\u8BA4 ${DEFAULT_WINDOW}\u3001\u4E0A\u9650 ${MAX_WIND
3746
3896
  }
3747
3897
  if (!out.anchor) {
3748
3898
  return Promise.resolve(
3749
- fail3(
3899
+ fail4(
3750
3900
  `session ${sessionId} has no message #${messageId} (it has ${out.total})`,
3751
3901
  start,
3752
3902
  8010,
@@ -3760,7 +3910,7 @@ before / after \u5404\u9ED8\u8BA4 ${DEFAULT_WINDOW}\u3001\u4E0A\u9650 ${MAX_WIND
3760
3910
  duration: Date.now() - start
3761
3911
  });
3762
3912
  } catch (err) {
3763
- return Promise.resolve(fail3(err instanceof Error ? err.message : String(err), start, 8011));
3913
+ return Promise.resolve(fail4(err instanceof Error ? err.message : String(err), start, 8011));
3764
3914
  }
3765
3915
  }
3766
3916
  };
@@ -3774,7 +3924,7 @@ function renderNode(node, isCurrent) {
3774
3924
  const where = node.cwd ? ` \xB7 ${node.cwd}` : "";
3775
3925
  const archived = node.archived ? " \xB7 archived" : "";
3776
3926
  return `${indent}${node.sessionId}${self} \u2014 ${node.title || "(untitled)"}
3777
- ${indent} ${stamp(node.startedAt ?? 0)} \xB7 ${node.messageCount ?? 0} messages${where}${archived}`;
3927
+ ${indent} ${stamp2(node.startedAt ?? 0)} \xB7 ${node.messageCount ?? 0} messages${where}${archived}`;
3778
3928
  }
3779
3929
  function renderTrace(trace, currentSessionId) {
3780
3930
  const anchor = trace.anchor;
@@ -3853,7 +4003,7 @@ function createSessionTraceTool(deps) {
3853
4003
  });
3854
4004
  if (!trace.authorized) {
3855
4005
  return Promise.resolve(
3856
- fail3(
4006
+ fail4(
3857
4007
  `session ${sessionId} is out of readable scope`,
3858
4008
  start,
3859
4009
  8012,
@@ -3867,14 +4017,14 @@ function createSessionTraceTool(deps) {
3867
4017
  duration: Date.now() - start
3868
4018
  });
3869
4019
  } catch (err) {
3870
- return Promise.resolve(fail3(err instanceof Error ? err.message : String(err), start, 8013));
4020
+ return Promise.resolve(fail4(err instanceof Error ? err.message : String(err), start, 8013));
3871
4021
  }
3872
4022
  }
3873
4023
  };
3874
4024
  }
3875
- var DEFAULT_LIMIT = 5;
3876
- var MAX_LIMIT = 20;
3877
- function fail4(message, start, code, suggestion) {
4025
+ var DEFAULT_LIMIT2 = 5;
4026
+ var MAX_LIMIT2 = 20;
4027
+ function fail5(message, start, code, suggestion) {
3878
4028
  return {
3879
4029
  success: false,
3880
4030
  output: "",
@@ -3885,12 +4035,12 @@ function fail4(message, start, code, suggestion) {
3885
4035
  function emptyHint(query) {
3886
4036
  return belowTrigramFloor(sanitizeFtsQuery(query)) ? ` Note: every word here is shorter than ${TRIGRAM_MIN_CHARS} characters, which the substring index cannot match at all \u2014 this is "cannot search", not "not found". Retry with a longer phrase.` : " Try fewer or different words.";
3887
4037
  }
3888
- function clampLimit(raw) {
4038
+ function clampLimit2(raw) {
3889
4039
  const n = Number(raw);
3890
- if (!Number.isFinite(n) || n <= 0) return DEFAULT_LIMIT;
3891
- return Math.min(Math.floor(n), MAX_LIMIT);
4040
+ if (!Number.isFinite(n) || n <= 0) return DEFAULT_LIMIT2;
4041
+ return Math.min(Math.floor(n), MAX_LIMIT2);
3892
4042
  }
3893
- function stamp2(ms) {
4043
+ function stamp3(ms) {
3894
4044
  return new Date(ms).toISOString().slice(0, 16).replace("T", " ");
3895
4045
  }
3896
4046
  function surfaceNote(hit, isCurrent) {
@@ -3904,14 +4054,14 @@ function renderSessionHit(hit, index) {
3904
4054
  const self = hit.isCurrent ? " (this session)" : "";
3905
4055
  return [
3906
4056
  `${index + 1}. ${hit.sessionId}${self} \u2014 ${hit.title || "(untitled)"}`,
3907
- ` ${stamp2(hit.startedAt)} \xB7 ${hit.messageCount} messages${where}`,
4057
+ ` ${stamp3(hit.startedAt)} \xB7 ${hit.messageCount} messages${where}`,
3908
4058
  ` best match [${hit.best.role} #${hit.best.messageId}, ${surfaceNote(hit.best, hit.isCurrent)}]:`,
3909
4059
  ` ${hit.best.snippet}`
3910
4060
  ].join("\n");
3911
4061
  }
3912
4062
  function renderMessageHit(hit, isCurrent) {
3913
4063
  return [
3914
- `#${hit.messageId} [${hit.role} \xB7 ${stamp2(hit.timestamp)} \xB7 ${surfaceNote(hit, isCurrent)}]`,
4064
+ `#${hit.messageId} [${hit.role} \xB7 ${stamp3(hit.timestamp)} \xB7 ${surfaceNote(hit, isCurrent)}]`,
3915
4065
  ` ${hit.snippet}`
3916
4066
  ].join("\n");
3917
4067
  }
@@ -3929,7 +4079,7 @@ function createSessionSearchTool(deps) {
3929
4079
  },
3930
4080
  limit: {
3931
4081
  type: "number",
3932
- description: `\u8FD4\u56DE\u51E0\u6BB5\u4F1A\u8BDD\uFF0C\u9ED8\u8BA4 ${DEFAULT_LIMIT}\uFF0C\u4E0A\u9650 ${MAX_LIMIT}`
4082
+ description: `\u8FD4\u56DE\u51E0\u6BB5\u4F1A\u8BDD\uFF0C\u9ED8\u8BA4 ${DEFAULT_LIMIT2}\uFF0C\u4E0A\u9650 ${MAX_LIMIT2}`
3933
4083
  },
3934
4084
  scope: {
3935
4085
  type: "string",
@@ -3959,13 +4109,13 @@ function createSessionSearchTool(deps) {
3959
4109
  execute(args, ctx) {
3960
4110
  const start = Date.now();
3961
4111
  const query = String(args["query"] ?? "").trim();
3962
- if (!query) return Promise.resolve(fail4("query must not be empty", start, 8001));
4112
+ if (!query) return Promise.resolve(fail5("query must not be empty", start, 8001));
3963
4113
  const allWorkspaces = deps.allowAllWorkspaces === true && args["allWorkspaces"] === true;
3964
4114
  const scope = args["scope"] === "title" ? "title" : "all";
3965
4115
  try {
3966
4116
  const hits = deps.queries.searchSessions({
3967
4117
  query,
3968
- limit: clampLimit(args["limit"]),
4118
+ limit: clampLimit2(args["limit"]),
3969
4119
  scope,
3970
4120
  currentSessionId: ctx.sessionId,
3971
4121
  workspaceCwd: deps.workspaceCwd,
@@ -3992,7 +4142,7 @@ function createSessionSearchTool(deps) {
3992
4142
  });
3993
4143
  } catch (err) {
3994
4144
  return Promise.resolve(
3995
- fail4(
4145
+ fail5(
3996
4146
  err instanceof Error ? err.message : String(err),
3997
4147
  start,
3998
4148
  8002,
@@ -4021,7 +4171,7 @@ function createSessionMessagesSearchTool(deps) {
4021
4171
  },
4022
4172
  limit: {
4023
4173
  type: "number",
4024
- description: `\u8FD4\u56DE\u51E0\u6761\uFF0C\u9ED8\u8BA4 ${DEFAULT_LIMIT}\uFF0C\u4E0A\u9650 ${MAX_LIMIT}`
4174
+ description: `\u8FD4\u56DE\u51E0\u6761\uFF0C\u9ED8\u8BA4 ${DEFAULT_LIMIT2}\uFF0C\u4E0A\u9650 ${MAX_LIMIT2}`
4025
4175
  },
4026
4176
  ...deps.allowAllWorkspaces ? {
4027
4177
  allWorkspaces: {
@@ -4047,21 +4197,21 @@ function createSessionMessagesSearchTool(deps) {
4047
4197
  const start = Date.now();
4048
4198
  const sessionId = String(args["sessionId"] ?? "").trim();
4049
4199
  const query = String(args["query"] ?? "").trim();
4050
- if (!sessionId) return Promise.resolve(fail4("sessionId must not be empty", start, 8003));
4051
- if (!query) return Promise.resolve(fail4("query must not be empty", start, 8004));
4200
+ if (!sessionId) return Promise.resolve(fail5("sessionId must not be empty", start, 8003));
4201
+ if (!query) return Promise.resolve(fail5("query must not be empty", start, 8004));
4052
4202
  const allWorkspaces = deps.allowAllWorkspaces === true && args["allWorkspaces"] === true;
4053
4203
  try {
4054
4204
  const out = deps.queries.searchMessages({
4055
4205
  sessionId,
4056
4206
  query,
4057
- limit: clampLimit(args["limit"]),
4207
+ limit: clampLimit2(args["limit"]),
4058
4208
  currentSessionId: ctx.sessionId,
4059
4209
  workspaceCwd: deps.workspaceCwd,
4060
4210
  allWorkspaces
4061
4211
  });
4062
4212
  if (!out.authorized) {
4063
4213
  return Promise.resolve(
4064
- fail4(
4214
+ fail5(
4065
4215
  `session ${sessionId} is out of searchable scope`,
4066
4216
  start,
4067
4217
  8005,
@@ -4088,7 +4238,7 @@ function createSessionMessagesSearchTool(deps) {
4088
4238
  });
4089
4239
  } catch (err) {
4090
4240
  return Promise.resolve(
4091
- fail4(
4241
+ fail5(
4092
4242
  err instanceof Error ? err.message : String(err),
4093
4243
  start,
4094
4244
  8006,
@@ -4104,12 +4254,13 @@ function createSessionSearchTools(deps) {
4104
4254
  createSessionSearchTool(deps),
4105
4255
  createSessionMessagesSearchTool(deps),
4106
4256
  createSessionMessagesReadTool(deps),
4107
- createSessionTraceTool(deps)
4257
+ createSessionTraceTool(deps),
4258
+ createSessionListTool(deps)
4108
4259
  ];
4109
4260
  }
4110
4261
  var SKILL_VIEW_TOOL = "skill_view";
4111
4262
  var MAX_SUGGESTED = 20;
4112
- function fail5(message, start, code, suggestion) {
4263
+ function fail6(message, start, code, suggestion) {
4113
4264
  return {
4114
4265
  success: false,
4115
4266
  output: "",
@@ -4154,18 +4305,18 @@ function createSkillViewTool(deps) {
4154
4305
  const name = String(args["name"] ?? "").trim();
4155
4306
  if (!name) {
4156
4307
  return Promise.resolve(
4157
- fail5("name must not be empty", start, 3001, describeAvailableSkills(deps.skills))
4308
+ fail6("name must not be empty", start, 3001, describeAvailableSkills(deps.skills))
4158
4309
  );
4159
4310
  }
4160
4311
  const body2 = deps.skills.view(name);
4161
4312
  if (body2 === null) {
4162
4313
  return Promise.resolve(
4163
- fail5(`skill "${name}" not found`, start, 3002, describeAvailableSkills(deps.skills))
4314
+ fail6(`skill "${name}" not found`, start, 3002, describeAvailableSkills(deps.skills))
4164
4315
  );
4165
4316
  }
4166
4317
  if (body2.trim() === "") {
4167
4318
  return Promise.resolve(
4168
- fail5(
4319
+ fail6(
4169
4320
  `skill "${name}" has an empty body \u2014 its SKILL.md is missing or empty`,
4170
4321
  start,
4171
4322
  3003,
@@ -4292,7 +4443,7 @@ var SKILL_EDIT_TOOL = "skill_edit";
4292
4443
  var SKILL_PATCH_TOOL = "skill_patch";
4293
4444
  var SKILL_WRITE_FILE_TOOL = "skill_write_file";
4294
4445
  var WRITABLE_SKILL_NAME = /^[A-Za-z0-9][A-Za-z0-9_-]{0,63}$/;
4295
- function fail6(message, start, code, suggestion) {
4446
+ function fail7(message, start, code, suggestion) {
4296
4447
  return {
4297
4448
  success: false,
4298
4449
  output: "",
@@ -4304,7 +4455,7 @@ function done(output, start) {
4304
4455
  return { success: true, output, duration: Date.now() - start };
4305
4456
  }
4306
4457
  function fromThrow(err, start, suggestion) {
4307
- return fail6(err instanceof Error ? err.message : String(err), start, 3102, suggestion);
4458
+ return fail7(err instanceof Error ? err.message : String(err), start, 3102, suggestion);
4308
4459
  }
4309
4460
  function str2(args, key) {
4310
4461
  const raw = args[key];
@@ -4360,13 +4511,13 @@ function createTool(deps) {
4360
4511
  const content = str2(args, "content");
4361
4512
  const category = str2(args, "category").trim() || "general";
4362
4513
  if (!WRITABLE_SKILL_NAME.test(name)) {
4363
- return fail6(`invalid skill name: ${JSON.stringify(name)}`, start, 3101, WRITABLE_HINT);
4514
+ return fail7(`invalid skill name: ${JSON.stringify(name)}`, start, 3101, WRITABLE_HINT);
4364
4515
  }
4365
4516
  if (!WRITABLE_SKILL_NAME.test(category)) {
4366
- return fail6(`invalid category: ${JSON.stringify(category)}`, start, 3101, WRITABLE_HINT);
4517
+ return fail7(`invalid category: ${JSON.stringify(category)}`, start, 3101, WRITABLE_HINT);
4367
4518
  }
4368
4519
  const bad2 = checkFrontmatter(name, content);
4369
- if (bad2 !== null) return fail6(bad2, start, 3103);
4520
+ if (bad2 !== null) return fail7(bad2, start, 3103);
4370
4521
  try {
4371
4522
  const path = await deps.skills.create(name, content, category);
4372
4523
  return done(`created skill "${name}" at ${path}`, start);
@@ -4398,10 +4549,10 @@ function editTool(deps) {
4398
4549
  const name = str2(args, "name").trim();
4399
4550
  const content = str2(args, "content");
4400
4551
  if (!name) {
4401
- return fail6("name must not be empty", start, 3101, describeAvailableSkills(deps.skills));
4552
+ return fail7("name must not be empty", start, 3101, describeAvailableSkills(deps.skills));
4402
4553
  }
4403
4554
  const bad2 = checkFrontmatter(name, content);
4404
- if (bad2 !== null) return fail6(bad2, start, 3103);
4555
+ if (bad2 !== null) return fail7(bad2, start, 3103);
4405
4556
  try {
4406
4557
  await deps.skills.edit(name, content);
4407
4558
  return done(`rewrote SKILL.md of skill "${name}"`, start);
@@ -4439,10 +4590,10 @@ function patchTool(deps) {
4439
4590
  const oldString = str2(args, "old_string");
4440
4591
  const filePath = str2(args, "file_path").trim();
4441
4592
  if (!name) {
4442
- return fail6("name must not be empty", start, 3101, describeAvailableSkills(deps.skills));
4593
+ return fail7("name must not be empty", start, 3101, describeAvailableSkills(deps.skills));
4443
4594
  }
4444
4595
  if (oldString === "") {
4445
- return fail6("old_string must not be empty", start, 3101);
4596
+ return fail7("old_string must not be empty", start, 3101);
4446
4597
  }
4447
4598
  try {
4448
4599
  await deps.skills.patch(
@@ -4484,9 +4635,9 @@ function writeFileTool(deps) {
4484
4635
  const name = str2(args, "name").trim();
4485
4636
  const filePath = str2(args, "file_path").trim();
4486
4637
  if (!name) {
4487
- return fail6("name must not be empty", start, 3101, describeAvailableSkills(deps.skills));
4638
+ return fail7("name must not be empty", start, 3101, describeAvailableSkills(deps.skills));
4488
4639
  }
4489
- if (!filePath) return fail6("file_path must not be empty", start, 3101);
4640
+ if (!filePath) return fail7("file_path must not be empty", start, 3101);
4490
4641
  try {
4491
4642
  await deps.skills.writeFile(name, filePath, str2(args, "content"));
4492
4643
  return done(`wrote ${filePath} into skill "${name}"`, start);
@@ -4502,7 +4653,7 @@ function createSkillWriteTools(deps) {
4502
4653
  var TOOL_SEARCH_TOOL = "tool_search";
4503
4654
  var MAX_LISTED = 40;
4504
4655
  var MAX_REVEAL_PER_CALL = 10;
4505
- function fail7(message, start, code, suggestion) {
4656
+ function fail8(message, start, code, suggestion) {
4506
4657
  return {
4507
4658
  success: false,
4508
4659
  output: "",
@@ -4552,12 +4703,12 @@ function createToolSearchTool(deps) {
4552
4703
  const pool = deps.deferred();
4553
4704
  const raw = String(args["query"] ?? "").trim();
4554
4705
  if (!raw) {
4555
- return Promise.resolve(fail7("query must not be empty", start, 3101, available(pool)));
4706
+ return Promise.resolve(fail8("query must not be empty", start, 3101, available(pool)));
4556
4707
  }
4557
4708
  const terms = raw.toLowerCase().split(/\s+/).filter(Boolean);
4558
4709
  const hits = pool.filter((tool) => matches(tool, terms));
4559
4710
  if (hits.length === 0) {
4560
- return Promise.resolve(fail7(`No tool matches "${raw}"`, start, 3102, available(pool)));
4711
+ return Promise.resolve(fail8(`No tool matches "${raw}"`, start, 3102, available(pool)));
4561
4712
  }
4562
4713
  const picked = hits.slice(0, MAX_REVEAL_PER_CALL);
4563
4714
  for (const tool of picked) deps.reveal.reveal(tool.name);
@@ -5113,7 +5264,7 @@ function createRoleFile(input, opts) {
5113
5264
  const detail = checked.error.issues.map((i) => `${i.path.join(".") || "(root)"}: ${i.message}`).join("; ");
5114
5265
  return { ok: false, reason: "invalid-field", detail };
5115
5266
  }
5116
- const text = render(fm, input.prompt ?? "");
5267
+ const text = render2(fm, input.prompt ?? "");
5117
5268
  const file = `${name}.md`;
5118
5269
  const back = parseRoleDefinition(text, file, opts.source ?? "user");
5119
5270
  if (!back.role) {
@@ -5145,7 +5296,7 @@ function frontmatterOf(name, input) {
5145
5296
  ...input.maxTurns === void 0 ? {} : { maxTurns: input.maxTurns }
5146
5297
  };
5147
5298
  }
5148
- function render(fm, prompt) {
5299
+ function render2(fm, prompt) {
5149
5300
  const head = dump(fm, { lineWidth: -1, noRefs: true });
5150
5301
  const body2 = prompt.trim();
5151
5302
  return `---
@@ -7017,11 +7168,29 @@ var MARKETPLACE_DISPLAY_FIELDS = [
7017
7168
  var DisplaySchema = z.object({
7018
7169
  fields: z.array(z.string().min(1)).optional()
7019
7170
  });
7171
+ var CategoryNodeSchema = z.lazy(
7172
+ () => z.object({
7173
+ id: z.string().min(1),
7174
+ label: z.string().min(1).optional(),
7175
+ children: z.array(CategoryNodeSchema).optional()
7176
+ })
7177
+ );
7178
+ var CategoriesSchema = z.array(CategoryNodeSchema).refine(hasUniqueCategoryIds, { message: "category ids must be unique across the whole tree" }).optional().catch(void 0);
7179
+ function hasUniqueCategoryIds(nodes) {
7180
+ const seen = /* @__PURE__ */ new Set();
7181
+ const walk3 = (list) => list.every((node) => {
7182
+ if (seen.has(node.id)) return false;
7183
+ seen.add(node.id);
7184
+ return node.children === void 0 || walk3(node.children);
7185
+ });
7186
+ return walk3(nodes);
7187
+ }
7020
7188
  var CatalogSchema = z.object({
7021
7189
  name: z.string().regex(NAME_PATTERN),
7022
7190
  description: z.string().min(1).optional(),
7023
7191
  owner: z.object({ name: z.string().min(1), url: z.string().min(1).optional() }).optional(),
7024
7192
  display: DisplaySchema.optional(),
7193
+ categories: CategoriesSchema,
7025
7194
  plugins: z.array(EntrySchema)
7026
7195
  });
7027
7196
  var RecordSchema2 = z.object({
@@ -7037,13 +7206,17 @@ var StateSchema2 = z.object({
7037
7206
  function projectEntryForDisplay(entry, display) {
7038
7207
  const allowed = display?.fields;
7039
7208
  if (allowed === void 0) return entry;
7040
- const keep = new Set(allowed);
7041
7209
  const out = { ...entry };
7042
7210
  for (const field of MARKETPLACE_DISPLAY_FIELDS) {
7043
- if (!keep.has(field)) delete out[field];
7211
+ if (!displayAllows(display, field)) delete out[field];
7044
7212
  }
7045
7213
  return out;
7046
7214
  }
7215
+ function displayAllows(display, field) {
7216
+ const allowed = display?.fields;
7217
+ if (allowed === void 0) return true;
7218
+ return allowed.includes(field);
7219
+ }
7047
7220
  function readMarketplaces(statePath) {
7048
7221
  if (!existsSync(statePath)) return { records: [], issues: [] };
7049
7222
  let raw;
@@ -9264,7 +9437,18 @@ function gitProbeEnv() {
9264
9437
  delete env.GIT_WORK_TREE;
9265
9438
  return env;
9266
9439
  }
9440
+ function insideGitRepo(rootDir) {
9441
+ let dir = rootDir;
9442
+ for (; ; ) {
9443
+ if (existsSync(join(dir, ".git"))) return true;
9444
+ const parent = dirname(dir);
9445
+ if (parent === dir) return false;
9446
+ dir = parent;
9447
+ }
9448
+ }
9267
9449
  function getGitStatus(rootDir) {
9450
+ if (!insideGitRepo(rootDir)) return void 0;
9451
+ if (!canProbeGit()) return void 0;
9268
9452
  const quiet = ["ignore", "pipe", "ignore"];
9269
9453
  const env = gitProbeEnv();
9270
9454
  try {
@@ -14280,6 +14464,7 @@ var SETTING_WRITE_KEYS = [
14280
14464
  "sessions.vacuumAfterPrune",
14281
14465
  "automation.keepRuns",
14282
14466
  "automation.maxRecordingMb",
14467
+ "sessionSearch.allWorkspaces",
14283
14468
  "permission"
14284
14469
  ];
14285
14470
  function isWritableSettingKey(value) {
@@ -14349,6 +14534,7 @@ var VALUE_SCHEMA = {
14349
14534
  "sessions.vacuumAfterPrune": EpochConfigSchema.shape.sessions.unwrap().shape.vacuumAfterPrune.unwrap(),
14350
14535
  "automation.keepRuns": EpochConfigSchema.shape.automation.unwrap().shape.keepRuns.unwrap(),
14351
14536
  "automation.maxRecordingMb": EpochConfigSchema.shape.automation.unwrap().shape.maxRecordingMb.unwrap(),
14537
+ "sessionSearch.allWorkspaces": EpochConfigSchema.shape.sessionSearch.unwrap().shape.allWorkspaces.unwrap(),
14352
14538
  permission: EpochConfigSchema.shape.permission.unwrap()
14353
14539
  };
14354
14540
  function settingValueKind(key) {
@@ -15527,6 +15713,17 @@ function textSimilarity(a, b) {
15527
15713
  const union = /* @__PURE__ */ new Set([...wordsA, ...wordsB]);
15528
15714
  return intersection / union.size;
15529
15715
  }
15716
+ var ATTACHMENT_RETENTION_DEFAULTS = {
15717
+ maxAgeDays: 7,
15718
+ maxTotalBytes: ATTACHMENT_MAX_TOTAL_BYTES
15719
+ };
15720
+ function pruneAttachments(root, keepSession, retention = ATTACHMENT_RETENTION_DEFAULTS, now = Date.now()) {
15721
+ const shared = retention;
15722
+ return pruneArtifacts(root, keepSession, shared, now);
15723
+ }
15724
+ async function removeSessionAttachments(sessionId, homeDir) {
15725
+ await rm(attachmentsDir(sessionId, homeDir), { recursive: true, force: true });
15726
+ }
15530
15727
  // src/goal/store.ts
15531
15728
  function toGoal(row) {
15532
15729
  const phase = isGoalPhase(row.phase) ? row.phase : "blocked";
@@ -15680,6 +15877,52 @@ function restoreParts(parts, opts) {
15680
15877
  }
15681
15878
  });
15682
15879
  }
15880
+ function importParts(parts) {
15881
+ const out = [];
15882
+ for (const part of parts) {
15883
+ if (part.type === "text") {
15884
+ out.push({ type: "text", text: part.text });
15885
+ continue;
15886
+ }
15887
+ if (part.type === "file") {
15888
+ out.push({
15889
+ type: "file",
15890
+ path: part.path,
15891
+ ...part.omitted ? { omitted: part.omitted } : {},
15892
+ ...part.bytes === void 0 ? {} : { bytes: part.bytes }
15893
+ });
15894
+ continue;
15895
+ }
15896
+ if (part.type === "session") {
15897
+ out.push({
15898
+ type: "session",
15899
+ ref: part.ref,
15900
+ ...part.sessionId ? { sessionId: part.sessionId } : {},
15901
+ ...part.title ? { title: part.title } : {},
15902
+ ...part.omitted ? { omitted: part.omitted } : {},
15903
+ ...part.messageCount === void 0 ? {} : { messageCount: part.messageCount },
15904
+ ...part.totalMessages === void 0 ? {} : { totalMessages: part.totalMessages }
15905
+ });
15906
+ continue;
15907
+ }
15908
+ if (part.type !== "image") {
15909
+ assertNeverPart(part);
15910
+ continue;
15911
+ }
15912
+ const { image, mediaType } = part;
15913
+ const media = mediaType ? { mediaType } : {};
15914
+ if (/^https?:/i.test(image)) {
15915
+ out.push({ type: "image", url: image, ...media });
15916
+ continue;
15917
+ }
15918
+ if (isAbsolute(image)) {
15919
+ out.push({ type: "image", path: image, ...media });
15920
+ continue;
15921
+ }
15922
+ return { ok: false, detail: DATA_URL.test(image) ? "image:data-url" : "image:base64" };
15923
+ }
15924
+ return { ok: true, parts: out };
15925
+ }
15683
15926
  function stripArtifactData(artifacts) {
15684
15927
  return artifacts.map(({ data: _data, ...rest }) => rest);
15685
15928
  }
@@ -16178,13 +16421,11 @@ var FTS_EXTERNAL_MIGRATIONS = [
16178
16421
  var SessionDB = class {
16179
16422
  db;
16180
16423
  path;
16181
- msgId = 0;
16182
16424
  constructor(dbPath$1) {
16183
16425
  this.path = dbPath$1 ?? dbPath();
16184
16426
  this.db = openDatabase(this.path);
16185
16427
  migrate(this.db, NS3, SESSION_MIGRATIONS);
16186
16428
  this.migrateFtsIndex();
16187
- this.refreshMsgId();
16188
16429
  }
16189
16430
  migrateFtsIndex() {
16190
16431
  try {
@@ -16196,9 +16437,8 @@ var SessionDB = class {
16196
16437
  );
16197
16438
  }
16198
16439
  }
16199
- refreshMsgId() {
16200
- const row = this.db.prepare("SELECT MAX(id) as maxId FROM messages").get();
16201
- this.msgId = row?.maxId ?? 0;
16440
+ transaction(fn) {
16441
+ return this.db.transaction(fn)();
16202
16442
  }
16203
16443
  insertSession(meta) {
16204
16444
  this.db.prepare(
@@ -16252,7 +16492,7 @@ var SessionDB = class {
16252
16492
  const dir = input.direction ?? "desc";
16253
16493
  let where = "1=1";
16254
16494
  const params = {};
16255
- if (input.archived !== void 0) {
16495
+ if (input.archived === "any") ; else if (input.archived !== void 0) {
16256
16496
  where += " AND archived = @archived";
16257
16497
  params["archived"] = input.archived ? 1 : 0;
16258
16498
  } else {
@@ -16265,6 +16505,10 @@ var SessionDB = class {
16265
16505
  where += " AND cwd = @cwd";
16266
16506
  params["cwd"] = input.cwd;
16267
16507
  }
16508
+ if (input.updatedSince !== void 0) {
16509
+ where += " AND COALESCE(updated_at, started_at) > @updatedSince";
16510
+ params["updatedSince"] = input.updatedSince;
16511
+ }
16268
16512
  if (input.cursor) {
16269
16513
  where += ` AND ${cursorCol} < @cursor`;
16270
16514
  params["cursor"] = Number(input.cursor);
@@ -16308,11 +16552,20 @@ var SessionDB = class {
16308
16552
  unarchiveSession(id) {
16309
16553
  this.db.prepare("UPDATE sessions SET archived = 0 WHERE id = ?").run(id);
16310
16554
  }
16555
+ importSession(meta, messages) {
16556
+ const run = this.db.transaction(
16557
+ (m, list) => {
16558
+ this.insertSession(m);
16559
+ return list.map((msg) => this.insertMessage({ ...msg, sessionId: m.id }));
16560
+ }
16561
+ );
16562
+ return run(meta, messages);
16563
+ }
16311
16564
  insertMessage(msg) {
16312
- this.db.prepare(
16565
+ const info = this.db.prepare(
16313
16566
  `
16314
- INSERT INTO messages (id, session_id, role, content, tool_call_id, tool_calls, tool_results, parts, tool_name, timestamp, token_count, finish_reason, reasoning, turn_facts, active, compacted, observed)
16315
- VALUES (@id, @sessionId, @role, @content, @toolCallId, @toolCalls, @toolResults, @parts, @toolName, @timestamp, @tokenCount, @finishReason, @reasoning, @turnFacts, 1, 0, 0)
16567
+ INSERT INTO messages (session_id, role, content, tool_call_id, tool_calls, tool_results, parts, tool_name, timestamp, token_count, finish_reason, reasoning, turn_facts, active, compacted, observed)
16568
+ VALUES (@sessionId, @role, @content, @toolCallId, @toolCalls, @toolResults, @parts, @toolName, @timestamp, @tokenCount, @finishReason, @reasoning, @turnFacts, 1, 0, 0)
16316
16569
  `
16317
16570
  ).run({
16318
16571
  ...msg,
@@ -16330,7 +16583,7 @@ var SessionDB = class {
16330
16583
  this.db.prepare(
16331
16584
  `UPDATE sessions SET message_count = message_count + 1, tool_call_count = tool_call_count + @toolCalls, updated_at = MAX(COALESCE(updated_at, 0), @timestamp) WHERE id = @id`
16332
16585
  ).run({ id: msg.sessionId, toolCalls, timestamp: msg.timestamp });
16333
- if (msg.id > this.msgId) this.msgId = msg.id;
16586
+ return Number(info.lastInsertRowid);
16334
16587
  }
16335
16588
  recordUsage(sessionId, usage) {
16336
16589
  const priced = usage.costUsd !== void 0;
@@ -16392,9 +16645,6 @@ var SessionDB = class {
16392
16645
  }
16393
16646
  return info.changes;
16394
16647
  }
16395
- nextMessageId() {
16396
- return ++this.msgId;
16397
- }
16398
16648
  search(input) {
16399
16649
  const limit = input.limit ?? 5;
16400
16650
  const scope = input.scope ?? "all";
@@ -16559,10 +16809,8 @@ var SessionDB = class {
16559
16809
  if (middle.length === 0) return null;
16560
16810
  const mark = this.db.prepare("UPDATE messages SET active = 0, compacted = 1 WHERE id = ?");
16561
16811
  for (const row of middle) mark.run(row.id);
16562
- const summaryId = this.nextMessageId();
16563
- this.insertMessage({
16812
+ const summaryId = this.insertMessage({
16564
16813
  sessionId,
16565
- id: summaryId,
16566
16814
  role: "user",
16567
16815
  content: input.summary,
16568
16816
  timestamp: middle[0].timestamp
@@ -16918,6 +17166,61 @@ var SessionReferences = class {
16918
17166
  };
16919
17167
  // src/session/manager.ts
16920
17168
  var AUTO_VACUUM_MIN_FREELIST_RATIO = 0.25;
17169
+ var IMPORT_ROLES = /* @__PURE__ */ new Set(["system", "user", "assistant", "tool"]);
17170
+ function validateImport(input) {
17171
+ const { meta, messages } = input;
17172
+ if (typeof meta.id !== "string" || meta.id.length === 0) return "meta.id";
17173
+ if (!Number.isFinite(meta.startedAt)) return "meta.startedAt";
17174
+ if (!Number.isFinite(meta.updatedAt)) return "meta.updatedAt";
17175
+ if (meta.endedAt !== void 0 && !Number.isFinite(meta.endedAt)) return "meta.endedAt";
17176
+ const seen = /* @__PURE__ */ new Set();
17177
+ for (const [i, msg] of messages.entries()) {
17178
+ if (!IMPORT_ROLES.has(msg.role)) return `messages[${i}].role`;
17179
+ if (typeof msg.content !== "string") return `messages[${i}].content`;
17180
+ if (!Number.isFinite(msg.timestamp)) return `messages[${i}].timestamp`;
17181
+ if (!Number.isFinite(msg.id) || seen.has(msg.id)) return `messages[${i}].id`;
17182
+ seen.add(msg.id);
17183
+ }
17184
+ return void 0;
17185
+ }
17186
+ function buildImportedMeta(meta, keepParent) {
17187
+ return {
17188
+ id: meta.id,
17189
+ title: meta.title,
17190
+ displayName: meta.displayName,
17191
+ source: meta.source ?? "import",
17192
+ cwd: meta.cwd,
17193
+ workspaceState: meta.workspaceState,
17194
+ workspaceRoot: meta.workspaceRoot,
17195
+ gitBranch: meta.gitBranch,
17196
+ gitRepoRoot: meta.gitRepoRoot,
17197
+ model: meta.model,
17198
+ tags: [],
17199
+ preview: "",
17200
+ pinned: meta.pinned ?? false,
17201
+ archived: meta.archived ?? false,
17202
+ rewindCount: 0,
17203
+ parentId: keepParent ? meta.parentId : void 0,
17204
+ messageCount: 0,
17205
+ toolCallCount: 0,
17206
+ apiCallCount: 0,
17207
+ inputTokens: 0,
17208
+ outputTokens: 0,
17209
+ cacheReadTokens: 0,
17210
+ cacheWriteTokens: 0,
17211
+ reasoningTokens: 0,
17212
+ estimatedCostUsd: void 0,
17213
+ actualCostUsd: void 0,
17214
+ compressionIneffectiveCount: 0,
17215
+ expiryFinalized: 0,
17216
+ summary: null,
17217
+ plan: null,
17218
+ startedAt: new Date(meta.startedAt),
17219
+ updatedAt: new Date(meta.updatedAt),
17220
+ endedAt: meta.endedAt === void 0 ? void 0 : new Date(meta.endedAt),
17221
+ endReason: meta.endReason
17222
+ };
17223
+ }
16921
17224
  var SessionManager = class {
16922
17225
  db;
16923
17226
  touched = /* @__PURE__ */ new Set();
@@ -17008,6 +17311,56 @@ var SessionManager = class {
17008
17311
  list(input) {
17009
17312
  return this.db.listSessions(input ?? {});
17010
17313
  }
17314
+ importSession(input) {
17315
+ const { meta, messages } = input;
17316
+ const id = meta.id;
17317
+ const bad2 = validateImport(input);
17318
+ if (bad2) return { ok: false, id, reason: "invalid", detail: bad2 };
17319
+ if (this.db.hasSession(id)) return { ok: false, id, reason: "exists" };
17320
+ const converted = [];
17321
+ for (const [i, msg] of messages.entries()) {
17322
+ const { id: _sourceId, parts, ...rest } = msg;
17323
+ if (!parts) {
17324
+ converted.push(rest);
17325
+ continue;
17326
+ }
17327
+ const result = importParts(parts);
17328
+ if (!result.ok) {
17329
+ return {
17330
+ ok: false,
17331
+ id,
17332
+ reason: "invalid",
17333
+ detail: `messages[${i}].parts.${result.detail}`
17334
+ };
17335
+ }
17336
+ converted.push({ ...rest, parts: result.parts });
17337
+ }
17338
+ const droppedParentId = meta.parentId !== void 0 && !this.db.hasSession(meta.parentId) ? meta.parentId : void 0;
17339
+ try {
17340
+ const newIds = this.db.importSession(
17341
+ buildImportedMeta(meta, droppedParentId === void 0),
17342
+ converted
17343
+ );
17344
+ const idMap = {};
17345
+ messages.forEach((msg, i) => {
17346
+ idMap[msg.id] = newIds[i];
17347
+ });
17348
+ return {
17349
+ ok: true,
17350
+ id,
17351
+ messageCount: newIds.length,
17352
+ idMap,
17353
+ ...droppedParentId === void 0 ? {} : { droppedParentId }
17354
+ };
17355
+ } catch (err) {
17356
+ return {
17357
+ ok: false,
17358
+ id,
17359
+ reason: "failed",
17360
+ ...err instanceof Error ? { detail: err.name } : {}
17361
+ };
17362
+ }
17363
+ }
17011
17364
  updateMeta(id, patch) {
17012
17365
  this.db.updateSessionMeta(id, patch);
17013
17366
  }
@@ -17062,6 +17415,16 @@ var SessionManager = class {
17062
17415
  return { ...result, error: cause instanceof Error ? cause.message : String(cause) };
17063
17416
  }
17064
17417
  }
17418
+ maybePruneAttachments(root, keepSession, opts = {}) {
17419
+ const now = opts.now?.() ?? Date.now();
17420
+ const minInterval = opts.minIntervalMs ?? 24 * 60 * 60 * 1e3;
17421
+ try {
17422
+ if (!this.db.claimMaintenanceSlot("last_attachment_prune", minInterval, now)) return 0;
17423
+ return pruneAttachments(root, keepSession, ATTACHMENT_RETENTION_DEFAULTS, now);
17424
+ } catch {
17425
+ return 0;
17426
+ }
17427
+ }
17065
17428
  delete(id) {
17066
17429
  return this.db.deleteSession(id);
17067
17430
  }
@@ -17081,15 +17444,16 @@ var SessionManager = class {
17081
17444
  }
17082
17445
  appendMessage(sessionId, msg) {
17083
17446
  this.touched.add(sessionId);
17084
- const id = this.db.nextMessageId();
17085
- this.db.insertMessage({ ...msg, sessionId, id, timestamp: Date.now() });
17086
- const meta = this.db.getSessionMeta(sessionId);
17087
- if (!meta) return id;
17088
- if (!meta.title && msg.role === "user") {
17089
- const title = msg.content.slice(0, 50).replace(/\n/g, " ");
17090
- this.db.updateSessionMeta(sessionId, { title });
17091
- }
17092
- return id;
17447
+ return this.db.transaction(() => {
17448
+ const id = this.db.insertMessage({ ...msg, sessionId, timestamp: Date.now() });
17449
+ const meta = this.db.getSessionMeta(sessionId);
17450
+ if (!meta) return id;
17451
+ if (!meta.title && msg.role === "user") {
17452
+ const title = msg.content.slice(0, 50).replace(/\n/g, " ");
17453
+ this.db.updateSessionMeta(sessionId, { title });
17454
+ }
17455
+ return id;
17456
+ });
17093
17457
  }
17094
17458
  attachTurnFacts(sessionId, messageId, input) {
17095
17459
  this.db.attachTurnFacts(sessionId, messageId, input);
@@ -17268,6 +17632,30 @@ function firstSentence(text, maxLen) {
17268
17632
  const lastSpace = cut.lastIndexOf(" ");
17269
17633
  return (lastSpace > maxLen * 0.6 ? cut.slice(0, lastSpace) : cut) + "\u2026";
17270
17634
  }
17635
+ // src/session/persist-failure.ts
17636
+ function codeOf(cause) {
17637
+ if (typeof cause !== "object" || cause === null) return "";
17638
+ const code = cause.code;
17639
+ return typeof code === "string" ? code : "";
17640
+ }
17641
+ function classifyPersistFailure(cause) {
17642
+ const code = codeOf(cause);
17643
+ if (!code) return "unknown";
17644
+ if (code.startsWith("SQLITE_FULL") || code === "ENOSPC") return "disk-full";
17645
+ if (code.startsWith("SQLITE_BUSY") || code.startsWith("SQLITE_LOCKED")) return "locked";
17646
+ if (code.startsWith("SQLITE_READONLY") || code.startsWith("SQLITE_PERM") || code.startsWith("SQLITE_CANTOPEN") || code === "EACCES" || code === "EPERM" || code === "EROFS") {
17647
+ return "read-only";
17648
+ }
17649
+ if (code.startsWith("SQLITE_CORRUPT") || code === "SQLITE_NOTADB") return "corrupt";
17650
+ if (code.startsWith("SQLITE_IOERR") || code === "EIO") return "io-error";
17651
+ return "unknown";
17652
+ }
17653
+ function isTransientPersistFailure(kind) {
17654
+ return kind === "locked";
17655
+ }
17656
+ function persistFailureCode(cause) {
17657
+ return codeOf(cause);
17658
+ }
17271
17659
  function isSettled(phase) {
17272
17660
  return phase === "complete";
17273
17661
  }
@@ -20083,9 +20471,9 @@ function buildAutomaton(patterns) {
20083
20471
  while (queue.length > 0) {
20084
20472
  const cur = queue.shift();
20085
20473
  for (const [ch, child] of nodes[cur].next) {
20086
- let fail8 = nodes[cur].fail;
20087
- while (fail8 !== 0 && !nodes[fail8].next.has(ch)) fail8 = nodes[fail8].fail;
20088
- const target = nodes[fail8].next.get(ch);
20474
+ let fail9 = nodes[cur].fail;
20475
+ while (fail9 !== 0 && !nodes[fail9].next.has(ch)) fail9 = nodes[fail9].fail;
20476
+ const target = nodes[fail9].next.get(ch);
20089
20477
  nodes[child].fail = target !== void 0 && target !== child ? target : 0;
20090
20478
  nodes[child].out.push(...nodes[nodes[child].fail].out);
20091
20479
  queue.push(child);
@@ -22150,6 +22538,7 @@ function listWorkspaceFiles(root) {
22150
22538
  }
22151
22539
  function listFromGit(root) {
22152
22540
  if (!existsSync(join(root, ".git"))) return null;
22541
+ if (!canProbeGit()) return null;
22153
22542
  try {
22154
22543
  const out = execFileSync("git", ["ls-files", "-co", "--exclude-standard", "-z"], {
22155
22544
  cwd: root,
@@ -22358,17 +22747,6 @@ function readSession(ref, opts, usedBytes) {
22358
22747
  })
22359
22748
  };
22360
22749
  }
22361
- var ATTACHMENT_RETENTION_DEFAULTS = {
22362
- maxAgeDays: 7,
22363
- maxTotalBytes: ATTACHMENT_MAX_TOTAL_BYTES
22364
- };
22365
- function pruneAttachments(root, keepSession, retention = ATTACHMENT_RETENTION_DEFAULTS, now = Date.now()) {
22366
- const shared = retention;
22367
- return pruneArtifacts(root, keepSession, shared, now);
22368
- }
22369
- async function removeSessionAttachments(sessionId, homeDir) {
22370
- await rm(attachmentsDir(sessionId, homeDir), { recursive: true, force: true });
22371
- }
22372
22750
  var OPENABLE_EXTENSIONS = /* @__PURE__ */ new Set([".png", ".jpg", ".jpeg", ".gif", ".webp"]);
22373
22751
  function artifactOpenRefusal(path, homeDir) {
22374
22752
  const root = homeDir === void 0 ? artifactsDir() : artifactsDir(void 0, homeDir);
@@ -22403,12 +22781,12 @@ async function openArtifact(path, homeDir) {
22403
22781
  if (refusal2) throw new Error(describeArtifactRefusal(refusal2));
22404
22782
  const launch = artifactLaunchArgv(path, process.platform, homeDir);
22405
22783
  if (!launch) throw new Error(describeArtifactRefusal("launch-failed"));
22406
- await new Promise((done2, fail8) => {
22784
+ await new Promise((done2, fail9) => {
22407
22785
  try {
22408
22786
  const child = spawn(launch.command, launch.args, { stdio: "ignore", detached: true });
22409
22787
  child.on(
22410
22788
  "error",
22411
- (err) => fail8(
22789
+ (err) => fail9(
22412
22790
  new Error(
22413
22791
  t("artifact.open_launch_failed_detail", {
22414
22792
  reason: describeArtifactRefusal("launch-failed"),
@@ -22422,7 +22800,7 @@ async function openArtifact(path, homeDir) {
22422
22800
  done2();
22423
22801
  });
22424
22802
  } catch (err) {
22425
- fail8(
22803
+ fail9(
22426
22804
  new Error(
22427
22805
  t("artifact.open_launch_failed_detail", {
22428
22806
  reason: describeArtifactRefusal("launch-failed"),
@@ -23279,4 +23657,4 @@ function trunc(stdout, stderr) {
23279
23657
  * `--tree` 的命令帮助里,让用户自己知道 `--tree` 意味着什么。
23280
23658
  */
23281
23659
 
23282
- 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_FORM_BUDGET_USD, 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 };
23660
+ 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_FORM_BUDGET_USD, 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, classifyPersistFailure, 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, displayAllows, 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, importParts, importSkills, installPlugin, instructionDirs, instructionNotices, intervalSlots, inventoryProjectExtensions, inventoryTotal, isBlockCode, isCodeModeDeferred, isEmptyRules, isGoalPhase, isNonInteractive, isReadOnlySubCall, isSettingWriteLayer, isTransientPersistFailure, 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, persistFailureCode, 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 };