context-mode 1.0.162 → 1.0.163

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 (148) hide show
  1. package/.claude-plugin/marketplace.json +2 -2
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/.codex-plugin/plugin.json +1 -1
  4. package/.openclaw-plugin/openclaw.plugin.json +1 -1
  5. package/.openclaw-plugin/package.json +1 -1
  6. package/README.md +142 -28
  7. package/bin/statusline.mjs +24 -4
  8. package/build/adapters/antigravity/index.d.ts +1 -1
  9. package/build/adapters/antigravity-cli/index.d.ts +51 -0
  10. package/build/adapters/antigravity-cli/index.js +341 -0
  11. package/build/adapters/claude-code/hooks.d.ts +1 -0
  12. package/build/adapters/claude-code/hooks.js +3 -0
  13. package/build/adapters/claude-code/index.js +24 -5
  14. package/build/adapters/client-map.js +5 -0
  15. package/build/adapters/codex/hooks.d.ts +5 -1
  16. package/build/adapters/codex/hooks.js +5 -1
  17. package/build/adapters/codex/index.d.ts +9 -1
  18. package/build/adapters/codex/index.js +87 -5
  19. package/build/adapters/copilot-cli/hooks.d.ts +33 -0
  20. package/build/adapters/copilot-cli/hooks.js +64 -0
  21. package/build/adapters/copilot-cli/index.d.ts +48 -0
  22. package/build/adapters/copilot-cli/index.js +341 -0
  23. package/build/adapters/detect.d.ts +1 -1
  24. package/build/adapters/detect.js +71 -3
  25. package/build/adapters/openclaw/mcp-tools.js +1 -1
  26. package/build/adapters/opencode/index.js +31 -17
  27. package/build/adapters/opencode/zod3tov4.js +27 -6
  28. package/build/adapters/pi/extension.d.ts +2 -12
  29. package/build/adapters/pi/extension.js +114 -96
  30. package/build/adapters/types.d.ts +5 -4
  31. package/build/adapters/types.js +4 -3
  32. package/build/cache-heal.d.ts +48 -0
  33. package/build/cache-heal.js +150 -0
  34. package/build/cli.js +37 -97
  35. package/build/executor.d.ts +25 -0
  36. package/build/executor.js +143 -22
  37. package/build/opencode-plugin.js +5 -2
  38. package/build/routing-block.d.ts +8 -0
  39. package/build/routing-block.js +86 -0
  40. package/build/runtime.d.ts +0 -36
  41. package/build/runtime.js +107 -27
  42. package/build/search/flood-guard.d.ts +57 -0
  43. package/build/search/flood-guard.js +80 -0
  44. package/build/security.d.ts +8 -3
  45. package/build/security.js +155 -29
  46. package/build/server.d.ts +14 -0
  47. package/build/server.js +368 -350
  48. package/build/session/analytics.d.ts +1 -1
  49. package/build/session/analytics.js +5 -1
  50. package/build/session/db.js +23 -3
  51. package/build/session/extract.js +8 -0
  52. package/build/store.d.ts +1 -1
  53. package/build/store.js +139 -25
  54. package/build/tool-naming.d.ts +4 -0
  55. package/build/tool-naming.js +24 -0
  56. package/build/util/jsonc.d.ts +14 -0
  57. package/build/util/jsonc.js +104 -0
  58. package/cli.bundle.mjs +254 -252
  59. package/configs/antigravity/GEMINI.md +2 -2
  60. package/configs/antigravity-cli/hooks/hooks.json +37 -0
  61. package/configs/antigravity-cli/hooks.json +37 -0
  62. package/configs/antigravity-cli/mcp_config.json +10 -0
  63. package/configs/antigravity-cli/plugin.json +14 -0
  64. package/configs/antigravity-cli/rules/context-mode.md +77 -0
  65. package/configs/antigravity-cli/skills/context-mode/SKILL.md +77 -0
  66. package/configs/claude-code/CLAUDE.md +2 -2
  67. package/configs/codex/AGENTS.md +2 -2
  68. package/configs/copilot-cli/.github/plugin/plugin.json +23 -0
  69. package/configs/copilot-cli/.mcp.json +12 -0
  70. package/configs/copilot-cli/README.md +47 -0
  71. package/configs/copilot-cli/hooks.json +41 -0
  72. package/configs/copilot-cli/skills/context-mode/SKILL.md +38 -0
  73. package/configs/gemini-cli/GEMINI.md +2 -2
  74. package/configs/jetbrains-copilot/copilot-instructions.md +2 -2
  75. package/configs/kilo/AGENTS.md +2 -2
  76. package/configs/kiro/KIRO.md +2 -2
  77. package/configs/omp/SYSTEM.md +2 -2
  78. package/configs/openclaw/AGENTS.md +2 -2
  79. package/configs/opencode/AGENTS.md +2 -2
  80. package/configs/qwen-code/QWEN.md +2 -2
  81. package/configs/vscode-copilot/copilot-instructions.md +2 -2
  82. package/configs/zed/AGENTS.md +2 -2
  83. package/hooks/antigravity-cli/payload.mjs +98 -0
  84. package/hooks/antigravity-cli/posttooluse.mjs +138 -0
  85. package/hooks/antigravity-cli/pretooluse.mjs +78 -0
  86. package/hooks/antigravity-cli/stop.mjs +58 -0
  87. package/hooks/codex/pretooluse.mjs +14 -4
  88. package/hooks/codex/stop.mjs +12 -4
  89. package/hooks/copilot-cli/posttooluse.mjs +79 -0
  90. package/hooks/copilot-cli/precompact.mjs +66 -0
  91. package/hooks/copilot-cli/pretooluse.mjs +41 -0
  92. package/hooks/copilot-cli/sessionstart.mjs +121 -0
  93. package/hooks/copilot-cli/stop.mjs +59 -0
  94. package/hooks/copilot-cli/userpromptsubmit.mjs +77 -0
  95. package/hooks/core/codex-caps.mjs +112 -0
  96. package/hooks/core/formatters.mjs +158 -7
  97. package/hooks/core/mcp-ready.mjs +37 -8
  98. package/hooks/core/routing.mjs +94 -8
  99. package/hooks/core/tool-naming.mjs +3 -0
  100. package/hooks/hooks.json +12 -1
  101. package/hooks/pretooluse.mjs +6 -2
  102. package/hooks/routing-block.mjs +2 -2
  103. package/hooks/security.bundle.mjs +2 -1
  104. package/hooks/session-db.bundle.mjs +5 -5
  105. package/hooks/session-directive.mjs +88 -20
  106. package/hooks/session-extract.bundle.mjs +1 -1
  107. package/hooks/session-helpers.mjs +21 -0
  108. package/hooks/sessionstart.mjs +37 -5
  109. package/hooks/stop.mjs +49 -0
  110. package/openclaw.plugin.json +1 -1
  111. package/package.json +4 -10
  112. package/scripts/install-antigravity-cli-plugin.mjs +141 -0
  113. package/server.bundle.mjs +208 -203
  114. package/skills/ctx-insight/SKILL.md +12 -17
  115. package/build/util/db-lock.d.ts +0 -65
  116. package/build/util/db-lock.js +0 -166
  117. package/insight/index.html +0 -13
  118. package/insight/package.json +0 -55
  119. package/insight/server.mjs +0 -1265
  120. package/insight/src/components/analytics.tsx +0 -112
  121. package/insight/src/components/ui/badge.tsx +0 -52
  122. package/insight/src/components/ui/button.tsx +0 -58
  123. package/insight/src/components/ui/card.tsx +0 -103
  124. package/insight/src/components/ui/chart.tsx +0 -371
  125. package/insight/src/components/ui/collapsible.tsx +0 -19
  126. package/insight/src/components/ui/input.tsx +0 -20
  127. package/insight/src/components/ui/progress.tsx +0 -83
  128. package/insight/src/components/ui/scroll-area.tsx +0 -55
  129. package/insight/src/components/ui/separator.tsx +0 -23
  130. package/insight/src/components/ui/table.tsx +0 -114
  131. package/insight/src/components/ui/tabs.tsx +0 -82
  132. package/insight/src/components/ui/tooltip.tsx +0 -64
  133. package/insight/src/lib/api.ts +0 -144
  134. package/insight/src/lib/utils.ts +0 -6
  135. package/insight/src/main.tsx +0 -22
  136. package/insight/src/routeTree.gen.ts +0 -189
  137. package/insight/src/router.tsx +0 -19
  138. package/insight/src/routes/__root.tsx +0 -55
  139. package/insight/src/routes/enterprise.tsx +0 -316
  140. package/insight/src/routes/index.tsx +0 -1482
  141. package/insight/src/routes/knowledge.tsx +0 -221
  142. package/insight/src/routes/knowledge_.$dbHash.$sourceId.tsx +0 -137
  143. package/insight/src/routes/search.tsx +0 -97
  144. package/insight/src/routes/sessions.tsx +0 -179
  145. package/insight/src/routes/sessions_.$dbHash.$sessionId.tsx +0 -181
  146. package/insight/src/styles.css +0 -104
  147. package/insight/tsconfig.json +0 -29
  148. package/insight/vite.config.ts +0 -19
@@ -25,7 +25,8 @@ import { existsSync, mkdirSync, rmSync, rmdirSync, readdirSync, unlinkSync, open
25
25
  * redirect action — prevents agent from getting stuck when MCP tools
26
26
  * are unavailable. Applies to deny and modify actions that mention MCP alternatives.
27
27
  */
28
- function mcpRedirect(result) {
28
+ function mcpRedirect(result, mcpToolsAvailable = true) {
29
+ if (!mcpToolsAvailable) return null;
29
30
  if (!isMCPReady()) return null;
30
31
  return result;
31
32
  }
@@ -75,6 +76,37 @@ function getExternalMcpNudgeEvery() {
75
76
  return parsed;
76
77
  }
77
78
 
79
+ // #817: size threshold so small Bash calls skip the routing nudge.
80
+ //
81
+ // PreToolUse fires BEFORE the command runs, so the actual output size is
82
+ // unknowable here. The only deterministic pre-execution signal is the command
83
+ // string itself. The Gemini CLI adapter solves the same over-interception
84
+ // problem with a matcher that only fires on large-output tools — "avoids
85
+ // unnecessary hook overhead on lightweight tools" (README). We mirror that at
86
+ // the routing layer: when CONTEXT_MODE_BASH_NUDGE_MIN_COMMAND_BYTES is set to
87
+ // N>0, an unbounded Bash command whose UTF-8 byte length is below N is treated
88
+ // as expected-lightweight and the generic routing nudge is suppressed.
89
+ //
90
+ // Default is 0 (unset) → CURRENT BEHAVIOR: every unbounded command is nudged.
91
+ // This preserves the context-saving guarantee for large outputs by default —
92
+ // the threshold is strictly opt-in. Bounds [0, 100000]; invalid/zero/negative
93
+ // values fall back to 0 (disabled). The threshold gates ONLY the generic Bash
94
+ // nudge — curl/wget, inline-HTTP, and build-tool redirects run earlier and are
95
+ // never relaxed, because those are deterministic floods regardless of command
96
+ // length.
97
+ const BASH_NUDGE_MIN_BYTES_ENV = "CONTEXT_MODE_BASH_NUDGE_MIN_COMMAND_BYTES";
98
+ const BASH_NUDGE_MIN_BYTES_MAX = 100_000;
99
+
100
+ function getBashNudgeMinCommandBytes() {
101
+ const raw = process.env[BASH_NUDGE_MIN_BYTES_ENV];
102
+ if (raw == null || raw === "") return 0;
103
+ const parsed = Number.parseInt(raw, 10);
104
+ if (!Number.isFinite(parsed) || parsed <= 0 || parsed > BASH_NUDGE_MIN_BYTES_MAX) {
105
+ return 0;
106
+ }
107
+ return parsed;
108
+ }
109
+
78
110
  function defaultGuidanceId() {
79
111
  return process.env.VITEST_WORKER_ID
80
112
  ? `${process.ppid}-w${process.env.VITEST_WORKER_ID}`
@@ -476,6 +508,14 @@ const TOOL_ALIASES = {
476
508
  "grep_search": "Grep",
477
509
  "search_file_content": "Grep",
478
510
  "web_fetch": "WebFetch",
511
+ "read_url_content": "WebFetch",
512
+ // Antigravity CLI (`agy`) native tool names. Keep in sync with the two other
513
+ // agy maps: hooks/antigravity-cli/payload.mjs (normalizeAgyToolName) and
514
+ // src/session/extract.ts (TOOL_NAME_NORMALIZE).
515
+ "run_command": "Bash",
516
+ "view_file": "Read",
517
+ "list_dir": "LS",
518
+ "search_web": "WebSearch",
479
519
  // Qwen Code additional tool names (no routing branch yet but normalized
480
520
  // so future routing logic works without per-platform fallback):
481
521
  "write_file": "Write",
@@ -580,6 +620,24 @@ function getShellCommand(toolInput) {
580
620
  if (!toolInput || typeof toolInput !== "object") return "";
581
621
  if (typeof toolInput.command === "string") return toolInput.command;
582
622
  if (typeof toolInput.cmd === "string") return toolInput.cmd;
623
+ if (typeof toolInput.CommandLine === "string") return toolInput.CommandLine;
624
+ return "";
625
+ }
626
+
627
+ function getReadFilePath(toolInput) {
628
+ if (!toolInput || typeof toolInput !== "object") return "";
629
+ if (typeof toolInput.file_path === "string") return toolInput.file_path;
630
+ if (typeof toolInput.path === "string") return toolInput.path;
631
+ if (typeof toolInput.AbsolutePath === "string") return toolInput.AbsolutePath;
632
+ if (typeof toolInput.FilePath === "string") return toolInput.FilePath;
633
+ return "";
634
+ }
635
+
636
+ function getWebFetchUrl(toolInput) {
637
+ if (!toolInput || typeof toolInput !== "object") return "";
638
+ if (typeof toolInput.url === "string") return toolInput.url;
639
+ if (typeof toolInput.URL === "string") return toolInput.URL;
640
+ if (typeof toolInput.Url === "string") return toolInput.Url;
583
641
  return "";
584
642
  }
585
643
 
@@ -604,8 +662,14 @@ function getPlatformSettingsPath(platform) {
604
662
  * @param {string} [sessionId] - Stable session identifier from hook payload. When
605
663
  * provided, the guidance throttle uses it to scope marker files across hook
606
664
  * invocations even when process.ppid shifts (Windows/Git Bash — see #298).
665
+ * @param {object} [options] - Runtime routing context from the adapter.
666
+ * @param {boolean} [options.mcpToolsAvailable=true] - False when the current
667
+ * caller context cannot invoke ctx_* MCP tools even though an MCP server is
668
+ * live on the machine (Claude Code fixed-tool subagents — #794).
607
669
  */
608
- export function routePreToolUse(toolName, toolInput, projectDir, platform, sessionId) {
670
+ export function routePreToolUse(toolName, toolInput, projectDir, platform, sessionId, options = {}) {
671
+ const mcpToolsAvailable = options.mcpToolsAvailable !== false;
672
+
609
673
  // ─── Opt-in fail-closed gate (#468 follow-up) ───
610
674
  // Default behavior on security-module load failure is fail-OPEN (a stderr
611
675
  // warning is emitted but routing continues). Security-conscious users can
@@ -715,7 +779,7 @@ export function routePreToolUse(toolName, toolInput, projectDir, platform, sessi
715
779
  bytesAvoided: 8192,
716
780
  commandSummary: command.slice(0, 200),
717
781
  },
718
- });
782
+ }, mcpToolsAvailable);
719
783
  }
720
784
  // All segments safe → allow through
721
785
  return null;
@@ -737,7 +801,7 @@ export function routePreToolUse(toolName, toolInput, projectDir, platform, sessi
737
801
  updatedInput: {
738
802
  command: `echo "context-mode: Inline HTTP redirected. Call ${t("ctx_execute")}(language, code) to fetch, derive your answer in code, and console.log() only the result — the raw response body stays in the sandbox instead of entering your conversation. Full network access. Retry the same call on a transient DNS error (EAI_AGAIN, ETIMEDOUT, ENETUNREACH)."`,
739
803
  },
740
- });
804
+ }, mcpToolsAvailable);
741
805
  }
742
806
 
743
807
  // Build tools (gradle, maven, sbt) → redirect to execute sandbox (Issue #38, #406).
@@ -750,7 +814,7 @@ export function routePreToolUse(toolName, toolInput, projectDir, platform, sessi
750
814
  updatedInput: {
751
815
  command: `echo "context-mode: Build tool redirected. Call ${t("ctx_execute")}(language: \\"shell\\", code: \\"${safeCmd} 2>&1 | tail -30\\") to run the build and print only the tail — the verbose build log stays in the sandbox instead of entering your conversation. For more targeted output, replace \\"tail -30\\" with \\"grep -E '(error|warning|FAIL|✗|×)'\\" or similar, so only the lines that matter come back."`,
752
816
  },
753
- });
817
+ }, mcpToolsAvailable);
754
818
  }
755
819
 
756
820
  // Skip the routing nudge for commands whose output is structurally
@@ -761,6 +825,17 @@ export function routePreToolUse(toolName, toolInput, projectDir, platform, sessi
761
825
  return null;
762
826
  }
763
827
 
828
+ // #817: opt-in size threshold. When the operator configures
829
+ // CONTEXT_MODE_BASH_NUDGE_MIN_COMMAND_BYTES, a short unbounded command is
830
+ // treated as expected-lightweight and passes through untouched — reserving
831
+ // the nudge for commands large/complex enough to plausibly flood context.
832
+ // Default (0) preserves current behavior, so large-output savings are not
833
+ // weakened unless the operator explicitly opts in.
834
+ const minCommandBytes = getBashNudgeMinCommandBytes();
835
+ if (minCommandBytes > 0 && Buffer.byteLength(command, "utf8") < minCommandBytes) {
836
+ return null;
837
+ }
838
+
764
839
  // allow all other Bash commands, but inject routing nudge (once per session)
765
840
  return guidanceOnce("bash", bashGuidance, sessionId);
766
841
  }
@@ -771,7 +846,7 @@ export function routePreToolUse(toolName, toolInput, projectDir, platform, sessi
771
846
  // event with the actual file size as bytes_avoided. Threshold = 50 000 bytes;
772
847
  // smaller reads stay on the existing one-shot guidance nudge.
773
848
  if (canonical === "Read") {
774
- const filePath = toolInput.file_path ?? toolInput.path ?? "";
849
+ const filePath = getReadFilePath(toolInput);
775
850
  if (filePath) {
776
851
  try {
777
852
  const st = statSync(filePath);
@@ -798,7 +873,7 @@ export function routePreToolUse(toolName, toolInput, projectDir, platform, sessi
798
873
 
799
874
  // ─── WebFetch: deny + redirect to sandbox ───
800
875
  if (canonical === "WebFetch") {
801
- const url = toolInput.url ?? "";
876
+ const url = getWebFetchUrl(toolInput);
802
877
  return mcpRedirect({
803
878
  action: "deny",
804
879
  reason: `context-mode: WebFetch redirected. Call ${t("ctx_fetch_and_index")}(url: "${url}", source: "...") to fetch + index the page, then ${t("ctx_search")}(queries: [...]) to query the indexed content — the raw page bytes stay in storage instead of entering your conversation. Or call ${t("ctx_execute")}(language, code) when you want to derive your answer in one round trip (parse, extract, count) without persisting the response. Both have full network access. Retry the same call on a transient DNS error (EAI_AGAIN, ETIMEDOUT, ENETUNREACH).`,
@@ -811,7 +886,7 @@ export function routePreToolUse(toolName, toolInput, projectDir, platform, sessi
811
886
  bytesAvoided: 16384,
812
887
  commandSummary: String(url).slice(0, 200),
813
888
  },
814
- });
889
+ }, mcpToolsAvailable);
815
890
  }
816
891
 
817
892
  // ─── Agent: inject context-mode routing into subagent prompts ───
@@ -842,6 +917,11 @@ export function routePreToolUse(toolName, toolInput, projectDir, platform, sessi
842
917
 
843
918
  // ─── MCP execute: security check for shell commands ───
844
919
  // Match bare, generic MCP, and legacy context-mode execute tool names.
920
+ const shouldPinClaudeExecutorCwd =
921
+ platform === "claude-code" &&
922
+ typeof projectDir === "string" &&
923
+ projectDir.length > 0;
924
+
845
925
  if (matchesContextModeTool(toolName, "ctx_execute", "execute")) {
846
926
  if (security && toolInput.language === "shell") {
847
927
  const code = toolInput.code ?? "";
@@ -856,6 +936,9 @@ export function routePreToolUse(toolName, toolInput, projectDir, platform, sessi
856
936
  }
857
937
  }
858
938
  }
939
+ if (toolInput.language === "shell" && shouldPinClaudeExecutorCwd && typeof toolInput.cwd !== "string") {
940
+ return { action: "modify", updatedInput: { ...toolInput, cwd: projectDir } };
941
+ }
859
942
  return null;
860
943
  }
861
944
 
@@ -907,6 +990,9 @@ export function routePreToolUse(toolName, toolInput, projectDir, platform, sessi
907
990
  }
908
991
  }
909
992
  }
993
+ if (shouldPinClaudeExecutorCwd && typeof toolInput.cwd !== "string") {
994
+ return { action: "modify", updatedInput: { ...toolInput, cwd: projectDir } };
995
+ }
910
996
  return null;
911
997
  }
912
998
 
@@ -8,6 +8,7 @@
8
8
  * | Claude Code | mcp__plugin_context-mode_context-mode__<tool> |
9
9
  * | Gemini CLI | mcp__context-mode__<tool> |
10
10
  * | Antigravity | mcp__context-mode__<tool> |
11
+ * | Antigravity CLI | context-mode/<tool> |
11
12
  * | OpenCode | context-mode_<tool> |
12
13
  * | VS Code Copilot | context-mode_<tool> |
13
14
  * | Kiro | @context-mode/<tool> |
@@ -19,10 +20,12 @@ const TOOL_PREFIXES = {
19
20
  "claude-code": (tool) => `mcp__plugin_context-mode_context-mode__${tool}`,
20
21
  "gemini-cli": (tool) => `mcp__context-mode__${tool}`,
21
22
  "antigravity": (tool) => `mcp__context-mode__${tool}`,
23
+ "antigravity-cli": (tool) => `context-mode/${tool}`,
22
24
  "opencode": (tool) => `context-mode_${tool}`,
23
25
  "kilo": (tool) => `context-mode_${tool}`,
24
26
  "vscode-copilot": (tool) => `context-mode_${tool}`,
25
27
  "jetbrains-copilot": (tool) => `context-mode_${tool}`,
28
+ "copilot-cli": (tool) => `context-mode_${tool}`,
26
29
  "kiro": (tool) => `@context-mode/${tool}`,
27
30
  "zed": (tool) => `mcp:context-mode:${tool}`,
28
31
  "cursor": (tool) => tool,
package/hooks/hooks.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "description": "Context-mode hooks — PreToolUse routing, PostToolUse session capture, PreCompact snapshot, SessionStart context injection",
2
+ "description": "Context-mode hooks — PreToolUse routing, PostToolUse session capture, UserPromptSubmit decisions, PreCompact snapshot, SessionStart context injection, Stop turn-end capture",
3
3
  "hooks": {
4
4
  "PostToolUse": [
5
5
  {
@@ -127,6 +127,17 @@
127
127
  }
128
128
  ]
129
129
  }
130
+ ],
131
+ "Stop": [
132
+ {
133
+ "matcher": "",
134
+ "hooks": [
135
+ {
136
+ "type": "command",
137
+ "command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/stop.mjs\""
138
+ }
139
+ ]
140
+ }
130
141
  ]
131
142
  }
132
143
  }
@@ -28,7 +28,7 @@ await runHook(async () => {
28
28
  const { readStdin } = await import("./core/stdin.mjs");
29
29
  const { routePreToolUse, initSecurity } = await import("./core/routing.mjs");
30
30
  const { formatDecision } = await import("./core/formatters.mjs");
31
- const { parseStdin, getSessionId, resolveConfigDir } = await import("./session-helpers.mjs");
31
+ const { parseStdin, getInputProjectDir, getSessionId, resolveConfigDir } = await import("./session-helpers.mjs");
32
32
 
33
33
  // ─── Manual recursive copy (avoids cpSync libuv crash on non-ASCII paths, Windows + Node 24) ───
34
34
  function copyDirSync(src, dest) {
@@ -163,9 +163,13 @@ await runHook(async () => {
163
163
  const input = parseStdin(raw);
164
164
  const tool = input.tool_name ?? "";
165
165
  const toolInput = input.tool_input ?? {};
166
+ const projectDir = getInputProjectDir(input);
167
+ const isSubagentContext = input.agent_id != null || input.agent_type != null;
166
168
 
167
169
  // ─── Route and format response ───
168
- const decision = routePreToolUse(tool, toolInput, process.env.CLAUDE_PROJECT_DIR, "claude-code", getSessionId(input));
170
+ const decision = routePreToolUse(tool, toolInput, projectDir, "claude-code", getSessionId(input), {
171
+ mcpToolsAvailable: !isSubagentContext,
172
+ });
169
173
  const response = formatDecision("claude-code", decision);
170
174
 
171
175
  // ─── Write latency marker for cross-hook timing (Category 27) ───
@@ -85,11 +85,11 @@ export function createReadGuidance(t) {
85
85
  }
86
86
 
87
87
  export function createGrepGuidance(t) {
88
- return '<context_guidance>\n <tip>\n Grep results may be larger than you expect. When you intend to count, filter, or aggregate matches (not just spot-check one), run the search through ' + t("ctx_execute") + '(language: "shell", code: "...") — the raw match list stays in the sandbox and only your derived answer enters your conversation.\n </tip>\n</context_guidance>';
88
+ return '<context_guidance>\n <tip>\n Grep results may be larger than you expect. When you intend to count, filter, or aggregate matches (not just spot-check one), run the search through ' + t("ctx_execute") + '(language: "javascript", code: "...") — the raw match list stays in the sandbox and only your derived answer enters your conversation. Use language: "shell" only when the code matches the host shell (PowerShell on Windows, POSIX shell on Unix).\n </tip>\n</context_guidance>';
89
89
  }
90
90
 
91
91
  export function createBashGuidance(t) {
92
- return '<context_guidance>\n <tip>\n When you intend to PROCESS the output (filter, count, parse, aggregate), use ' + t("ctx_batch_execute") + '(commands, queries) for multiple commands or ' + t("ctx_execute") + '(language: "shell", code: "...") for one — the raw output stays in the sandbox and only what you print enters your conversation. Bash stays the right surface when you intend to OBSERVE a short fixed output or when you are mutating state (git, mkdir, rm, mv, navigation).\n </tip>\n</context_guidance>';
92
+ return '<context_guidance>\n <tip>\n When you intend to PROCESS the output (filter, count, parse, aggregate), use ' + t("ctx_batch_execute") + '(commands, queries) for multiple commands or ' + t("ctx_execute") + '(language: "javascript", code: "...") for one — the raw output stays in the sandbox and only what you print enters your conversation. Shell stays the right surface when you intend to OBSERVE a short fixed output or when you are mutating state (git, mkdir, rm, mv, navigation); if you use ' + t("ctx_execute") + '(language: "shell"), write syntax for the host shell.\n </tip>\n</context_guidance>';
93
93
  }
94
94
 
95
95
  export function createExternalMcpGuidance(t) {
@@ -1 +1,2 @@
1
- var h=(n,t)=>()=>(n&&(t=n(n=0)),t);var _,I=h(()=>{"use strict";_={"claude-code":"claude-code","gemini-cli-mcp-client":"gemini-cli","antigravity-client":"antigravity","cursor-vscode":"cursor","Visual-Studio-Code":"vscode-copilot","JetBrains Client":"jetbrains-copilot","IntelliJ IDEA":"jetbrains-copilot",PyCharm:"jetbrains-copilot",Codex:"codex","codex-mcp-client":"codex","Kilo Code":"kilo","Kiro CLI":"kiro","Pi CLI":"pi","Pi Coding Agent":"pi","omp-coding-agent":"omp",Zed:"zed",zed:"zed","qwen-code":"qwen-code","qwen-cli-mcp-client":"qwen-code","kimi-code":"kimi",kimi:"kimi","Kimi Code":"kimi"}});import{existsSync as l,readFileSync as N}from"node:fs";import{resolve as a}from"node:path";import{homedir as k}from"node:os";function L(){if(f!==null)return f!=="miss"&&f.hasCM;try{let n=a(k(),".claude","plugins","installed_plugins.json"),t=N(n,"utf-8"),e=JSON.parse(t),r=[...Object.keys(e.plugins??{}),...Object.keys(e.enabledPlugins??{})].some(i=>i.includes("context-mode"));return f={hasCM:r},r}catch{return f="miss",!1}}function S(n){switch(n){case"claude-code":return[".claude"];case"gemini-cli":return[".gemini"];case"antigravity":return[".gemini"];case"openclaw":return[".openclaw"];case"codex":return[".codex"];case"cursor":return[".cursor"];case"vscode-copilot":return[".vscode"];case"kiro":return[".kiro"];case"pi":return[".pi"];case"omp":return[".omp"];case"qwen-code":return[".qwen"];case"kimi":return[".kimi-code"];case"kilo":return[".config","kilo"];case"opencode":return[".config","opencode"];case"zed":return[".config","zed"];case"jetbrains-copilot":return[".config","JetBrains"];default:return null}}function A(n){if(n?.name){let o=_[n.name];if(o)return{platform:o,confidence:"high",reason:`MCP clientInfo.name="${n.name}"`};if(n.name.startsWith("qwen-cli-mcp-client"))return{platform:"qwen-code",confidence:"high",reason:`MCP clientInfo.name="${n.name}" (qwen-cli pattern)`}}let t=process.env.CONTEXT_MODE_PLATFORM;if(t&&["claude-code","gemini-cli","kilo","opencode","codex","vscode-copilot","jetbrains-copilot","cursor","antigravity","kiro","pi","omp","zed","qwen-code","kimi"].includes(t))return{platform:t,confidence:"high",reason:`CONTEXT_MODE_PLATFORM=${t} override`};for(let[o,r]of F)if(r.some(i=>i.detect!==!1&&process.env[i.name]))return o==="vscode-copilot"&&L()?{platform:"claude-code",confidence:"high",reason:"VSCODE_PID set but ~/.claude/plugins/installed_plugins.json lists context-mode (issue #539 fallback)"}:{platform:o,confidence:"high",reason:`${r.filter(i=>i.detect!==!1).map(i=>i.name).join(" or ")} env var set`};let e=k();return l(a(e,".claude"))?{platform:"claude-code",confidence:"medium",reason:"~/.claude/ directory exists"}:l(a(e,".gemini"))?{platform:"gemini-cli",confidence:"medium",reason:"~/.gemini/ directory exists"}:l(a(e,".codex"))?{platform:"codex",confidence:"medium",reason:"~/.codex/ directory exists"}:l(a(e,".kiro"))?{platform:"kiro",confidence:"medium",reason:"~/.kiro/ directory exists"}:l(a(e,".omp"))?{platform:"omp",confidence:"medium",reason:"~/.omp/ directory exists"}:l(a(e,".pi"))?{platform:"pi",confidence:"medium",reason:"~/.pi/ directory exists"}:l(a(e,".qwen"))?{platform:"qwen-code",confidence:"medium",reason:"~/.qwen/ directory exists"}:l(a(e,".kimi-code"))?{platform:"kimi",confidence:"medium",reason:"~/.kimi-code/ directory exists"}:l(a(e,".openclaw"))?{platform:"openclaw",confidence:"medium",reason:"~/.openclaw/ directory exists"}:l(a(e,".cursor"))?{platform:"cursor",confidence:"medium",reason:"~/.cursor/ directory exists"}:l(a(e,".config","kilo"))?{platform:"kilo",confidence:"medium",reason:"~/.config/kilo/ directory exists"}:l(a(e,".config","JetBrains"))?{platform:"jetbrains-copilot",confidence:"medium",reason:"~/.config/JetBrains/ directory exists"}:l(a(e,".config","opencode"))?{platform:"opencode",confidence:"medium",reason:"~/.config/opencode/ directory exists"}:l(a(e,".config","zed"))?{platform:"zed",confidence:"medium",reason:"~/.config/zed/ directory exists"}:{platform:"claude-code",confidence:"low",reason:"No platform detected, defaulting to Claude Code"}}var f,M,F,O=h(()=>{"use strict";I();f=null;M=[["claude-code",[{name:"CLAUDE_CODE_ENTRYPOINT",role:"identification"},{name:"CLAUDE_PLUGIN_ROOT",role:"identification"},{name:"CLAUDE_PROJECT_DIR",role:"workspace"},{name:"CLAUDE_SESSION_ID",role:"identification"}]],["antigravity",[{name:"ANTIGRAVITY_CLI_ALIAS",role:"identification"}]],["cursor",[{name:"CURSOR_CWD",role:"workspace"},{name:"CURSOR_TRACE_ID",role:"identification"},{name:"CURSOR_CLI",role:"identification"}]],["kilo",[{name:"KILO",role:"identification"},{name:"KILO_PID",role:"identification"}]],["opencode",[{name:"OPENCODE_PROJECT_DIR",role:"workspace"},{name:"OPENCODE_CLIENT",role:"identification"},{name:"OPENCODE_TERMINAL",role:"identification"},{name:"OPENCODE",role:"identification"},{name:"OPENCODE_PID",role:"identification"}]],["zed",[{name:"ZED_SESSION_ID",role:"identification"},{name:"ZED_TERM",role:"identification"}]],["codex",[{name:"CODEX_THREAD_ID",role:"identification"},{name:"CODEX_CI",role:"identification"}]],["gemini-cli",[{name:"GEMINI_PROJECT_DIR",role:"workspace"},{name:"GEMINI_CLI",role:"identification"}]],["vscode-copilot",[{name:"VSCODE_CWD",role:"workspace"},{name:"VSCODE_PID",role:"identification"}]],["jetbrains-copilot",[{name:"IDEA_INITIAL_DIRECTORY",role:"workspace"}]],["qwen-code",[{name:"QWEN_PROJECT_DIR",role:"workspace"}]],["omp",[{name:"PI_CODING_AGENT_DIR",role:"workspace"}]],["pi",[{name:"PI_WORKSPACE_DIR",role:"workspace",detect:!1},{name:"PI_PROJECT_DIR",role:"workspace",detect:!1},{name:"PI_CONFIG_DIR",role:"identification"},{name:"PI_SESSION_FILE",role:"identification"},{name:"PI_COMPILED",role:"identification"}]]],F=new Map(M)});import{resolve as u}from"node:path";import{homedir as P}from"node:os";function j(n=process.env){let t=n.CLAUDE_CONFIG_DIR;return t&&t.trim()!==""?t.startsWith("~")?u(P(),t.replace(/^~[/\\]?/,"")):u(t):u(P(),".claude")}function G(n=process.env){return u(j(n),"settings.json")}function w(n=process.env){let t=[],e=A();if(e.platform!=="claude-code"){let r=S(e.platform);r&&r.length>0&&t.push(u(P(),...r,"settings.json"))}let o=G(n);return t.includes(o)||t.push(o),t}var R=h(()=>{"use strict";O()});R();import{readFileSync as D,realpathSync as $}from"node:fs";import{resolve as p}from"node:path";function b(n){let t=n.match(/^Bash\((.+)\)$/);return t?t[1]:null}function J(n){let t=n.match(/^(\w+)\((.+)\)$/);return t?{tool:t[1],glob:t[2]}:null}function q(n){return n.replace(/[.*+?^${}()|[\]\\\/\-]/g,"\\$&")}function v(n){return n.replace(/[.+?^${}()|[\]\\\/\-]/g,"\\$&").replace(/\*/g,".*")}function V(n,t=!1){let e,o=n.indexOf(":");if(o!==-1){let r=n.slice(0,o),i=n.slice(o+1),s=q(r),c=v(i);e=`^${s}(\\s${c})?$`}else e=`^${v(n)}$`;return new RegExp(e,t?"i":"")}function z(n,t=!1){let e="",o=0;for(;o<n.length;)n[o]==="*"&&n[o+1]==="*"?o+2<n.length&&n[o+2]==="/"?(e+="(.*/)?",o+=3):(e+=".*",o+=2):n[o]==="*"?(e+="[^/]*",o++):n[o]==="?"?(e+="[^/]",o++):(e+=n[o].replace(/[.+^${}()|[\]\\\/\-]/g,"\\$&"),o++);return new RegExp(`^${e}$`,t?"i":"")}function g(n,t,e=!1){for(let o of t){let r=b(o);if(r&&V(r,e).test(n))return o}return null}function T(n){let t=[],e="",o=!1,r=!1,i=!1;for(let s=0;s<n.length;s++){let c=n[s],d=s>0?n[s-1]:"";c==="'"&&!r&&!i&&d!=="\\"?(o=!o,e+=c):c==='"'&&!o&&!i&&d!=="\\"?(r=!r,e+=c):c==="`"&&!o&&!r&&d!=="\\"?(i=!i,e+=c):!o&&!r&&!i?c===";"?(t.push(e.trim()),e=""):c==="|"&&n[s+1]==="|"||c==="&"&&n[s+1]==="&"?(t.push(e.trim()),e="",s++):c==="|"?(t.push(e.trim()),e=""):e+=c:e+=c}return e.trim()&&t.push(e.trim()),t.filter(s=>s.length>0)}function C(n){let t;try{t=D(n,"utf-8")}catch{return null}let e;try{e=JSON.parse(t)}catch{return null}let o=e?.permissions;if(!o||typeof o!="object")return null;let r=i=>Array.isArray(i)?i.filter(s=>typeof s=="string"&&b(s)!==null):[];return{allow:r(o.allow),deny:r(o.deny),ask:r(o.ask)}}function ce(n,t){let e=[];if(n){let r=p(n,".claude","settings.local.json"),i=C(r);i&&e.push(i);let s=p(n,".claude","settings.json"),c=C(s);c&&e.push(c)}let o=t!==void 0?[t]:w();for(let r of o){let i=C(r);i&&e.push(i)}return e}function ae(n,t,e){let o=[],r=s=>{let c;try{c=D(s,"utf-8")}catch{return null}let d;try{d=JSON.parse(c)}catch{return null}let m=d?.permissions?.deny;if(!Array.isArray(m))return[];let x=[];for(let E of m){if(typeof E!="string")continue;let y=J(E);y&&y.tool===n&&x.push(y.glob)}return x};if(t){let s=r(p(t,".claude","settings.local.json"));s!==null&&o.push(s);let c=r(p(t,".claude","settings.json"));c!==null&&o.push(c)}let i=e!==void 0?[e]:w();for(let s of i){let c=r(s);c!==null&&o.push(c)}return o}function le(n,t,e=process.platform==="win32"){let o=T(n);for(let r of o)for(let i of t){let s=g(r,i.deny,e);if(s)return{decision:"deny",matchedPattern:s}}for(let r of t){let i=g(n,r.ask,e);if(i)return{decision:"ask",matchedPattern:i};let s=g(n,r.allow,e);if(s)return{decision:"allow",matchedPattern:s}}return{decision:"ask"}}function de(n,t,e=process.platform==="win32"){let o=T(n);for(let r of o)for(let i of t){let s=g(r,i.deny,e);if(s)return{decision:"deny",matchedPattern:s}}return{decision:"allow"}}function fe(n,t,e=process.platform==="win32",o){let r=s=>s.replace(/\\/g,"/"),i=new Set;if(i.add(r(n)),o){let s=p(o,n);i.add(r(s));try{i.add(r($(s)))}catch{}}for(let s of t)for(let c of s){let d=z(r(c),e);for(let m of i)if(d.test(m))return{denied:!0,matchedPattern:c}}return{denied:!1}}var B={python:[/os\.system\(\s*(['"])(.*?)\1\s*\)/g,/subprocess\.(?:run|call|Popen|check_output|check_call)\(\s*(['"])(.*?)\1/g],javascript:[/exec(?:Sync|File|FileSync)?\(\s*(['"`])(.*?)\1/g,/spawn(?:Sync)?\(\s*(['"`])(.*?)\1/g],typescript:[/exec(?:Sync|File|FileSync)?\(\s*(['"`])(.*?)\1/g,/spawn(?:Sync)?\(\s*(['"`])(.*?)\1/g],ruby:[/system\(\s*(['"])(.*?)\1/g,/`(.*?)`/g],go:[/exec\.Command\(\s*(['"`])(.*?)\1/g],php:[/shell_exec\(\s*(['"`])(.*?)\1/g,/(?:^|[^.])exec\(\s*(['"`])(.*?)\1/g,/(?:^|[^.])system\(\s*(['"`])(.*?)\1/g,/passthru\(\s*(['"`])(.*?)\1/g,/proc_open\(\s*(['"`])(.*?)\1/g],rust:[/Command::new\(\s*(['"`])(.*?)\1/g]};function U(n){let t=[],e=/subprocess\.(?:run|call|Popen|check_output|check_call)\(\s*\[([^\]]+)\]/g,o;for(;(o=e.exec(n))!==null;){let i=[...o[1].matchAll(/(['"])(.*?)\1/g)].map(s=>s[2]);i.length>0&&t.push(i.join(" "))}return t}function ue(n,t){let e=B[t];if(!e&&t!=="python")return[];let o=[];if(e)for(let r of e){r.lastIndex=0;let i;for(;(i=r.exec(n))!==null;){let s=i[i.length-1];s&&o.push(s)}}return t==="python"&&o.push(...U(n)),o}export{le as evaluateCommand,de as evaluateCommandDenyOnly,fe as evaluateFilePath,ue as extractShellCommands,z as fileGlobToRegex,V as globToRegex,g as matchesAnyPattern,b as parseBashPattern,J as parseToolPattern,ce as readBashPolicies,ae as readToolDenyPatterns,T as splitChainedCommands};
1
+ var P=(t,n)=>()=>(t&&(n=t(t=0)),n);var I,k=P(()=>{"use strict";I={"claude-code":"claude-code","gemini-cli-mcp-client":"gemini-cli","antigravity-client":"antigravity","antigravity-cli":"antigravity-cli",agy:"antigravity-cli","cursor-vscode":"cursor","Visual-Studio-Code":"vscode-copilot","copilot-cli":"copilot-cli","GitHub Copilot CLI":"copilot-cli","github-copilot-cli":"copilot-cli","JetBrains Client":"jetbrains-copilot","IntelliJ IDEA":"jetbrains-copilot",PyCharm:"jetbrains-copilot",Codex:"codex","codex-mcp-client":"codex","Kilo Code":"kilo","Kiro CLI":"kiro","Pi CLI":"pi","Pi Coding Agent":"pi","omp-coding-agent":"omp",Zed:"zed",zed:"zed","qwen-code":"qwen-code","qwen-cli-mcp-client":"qwen-code","kimi-code":"kimi",kimi:"kimi","Kimi Code":"kimi"}});import{existsSync as f,readFileSync as M}from"node:fs";import{resolve as d}from"node:path";import{homedir as O}from"node:os";function j(){if(g!==null)return g!=="miss"&&g.hasCM;try{let t=d(O(),".claude","plugins","installed_plugins.json"),n=M(t,"utf-8"),e=JSON.parse(n),i=[...Object.keys(e.plugins??{}),...Object.keys(e.enabledPlugins??{})].some(r=>r.includes("context-mode"));return g={hasCM:i},i}catch{return g="miss",!1}}function A(t){switch(t){case"claude-code":return[".claude"];case"gemini-cli":return[".gemini"];case"antigravity":return[".gemini"];case"antigravity-cli":return[".gemini"];case"openclaw":return[".openclaw"];case"codex":return[".codex"];case"cursor":return[".cursor"];case"vscode-copilot":return[".vscode"];case"copilot-cli":return[".copilot"];case"kiro":return[".kiro"];case"pi":return[".pi"];case"omp":return[".omp"];case"qwen-code":return[".qwen"];case"kimi":return[".kimi-code"];case"kilo":return[".config","kilo"];case"opencode":return[".config","opencode"];case"zed":return[".config","zed"];case"jetbrains-copilot":return[".config","JetBrains"];default:return null}}function v(t){if(t?.name){let r=I[t.name];if(r)return{platform:r,confidence:"high",reason:`MCP clientInfo.name="${t.name}"`};if(t.name.startsWith("qwen-cli-mcp-client"))return{platform:"qwen-code",confidence:"high",reason:`MCP clientInfo.name="${t.name}" (qwen-cli pattern)`}}let n=process.env.CONTEXT_MODE_PLATFORM;if(n&&["claude-code","gemini-cli","kilo","opencode","codex","vscode-copilot","jetbrains-copilot","copilot-cli","cursor","antigravity","antigravity-cli","kiro","pi","omp","zed","qwen-code","kimi"].includes(n))return{platform:n,confidence:"high",reason:`CONTEXT_MODE_PLATFORM=${n} override`};for(let[r,s]of $)if(s.some(c=>c.detect!==!1&&process.env[c.name]))return r==="vscode-copilot"&&j()?{platform:"claude-code",confidence:"high",reason:"VSCODE_PID set but ~/.claude/plugins/installed_plugins.json lists context-mode (issue #539 fallback)"}:{platform:r,confidence:"high",reason:`${s.filter(c=>c.detect!==!1).map(c=>c.name).join(" or ")} env var set`};let e=O(),o=(()=>{let r=process.env.COPILOT_HOME;return r&&r.trim()!==""?r.startsWith("~")?d(e,r.replace(/^~[/\\]?/,"")):d(r):d(e,".copilot")})(),i=f(d(o,"mcp-config.json"))||f(d(o,"hooks","context-mode.json"));return process.env.COPILOT_HOME?.trim()&&i?{platform:"copilot-cli",confidence:"medium",reason:"context-mode config in explicit COPILOT_HOME exists (mcp-config.json or hooks/context-mode.json)"}:f(d(e,".local","bin","agy"))||f(d(e,".gemini","antigravity-cli"))||f(d(e,".gemini","config","mcp_config.json"))?{platform:"antigravity-cli",confidence:"medium",reason:"Antigravity CLI marker exists (~/.local/bin/agy, ~/.gemini/antigravity-cli, or ~/.gemini/config/mcp_config.json)"}:i?{platform:"copilot-cli",confidence:"medium",reason:"context-mode config in Copilot CLI home exists (mcp-config.json or hooks/context-mode.json; honors COPILOT_HOME)"}:f(d(e,".claude"))?{platform:"claude-code",confidence:"medium",reason:"~/.claude/ directory exists"}:f(d(e,".gemini"))?{platform:"gemini-cli",confidence:"medium",reason:"~/.gemini/ directory exists"}:f(d(e,".codex"))?{platform:"codex",confidence:"medium",reason:"~/.codex/ directory exists"}:f(d(e,".kiro"))?{platform:"kiro",confidence:"medium",reason:"~/.kiro/ directory exists"}:f(d(e,".omp"))?{platform:"omp",confidence:"medium",reason:"~/.omp/ directory exists"}:f(d(e,".pi"))?{platform:"pi",confidence:"medium",reason:"~/.pi/ directory exists"}:f(d(e,".qwen"))?{platform:"qwen-code",confidence:"medium",reason:"~/.qwen/ directory exists"}:f(d(e,".kimi-code"))?{platform:"kimi",confidence:"medium",reason:"~/.kimi-code/ directory exists"}:f(d(e,".openclaw"))?{platform:"openclaw",confidence:"medium",reason:"~/.openclaw/ directory exists"}:f(d(e,".cursor"))?{platform:"cursor",confidence:"medium",reason:"~/.cursor/ directory exists"}:f(d(e,".config","kilo"))?{platform:"kilo",confidence:"medium",reason:"~/.config/kilo/ directory exists"}:f(d(e,".config","JetBrains"))?{platform:"jetbrains-copilot",confidence:"medium",reason:"~/.config/JetBrains/ directory exists"}:f(d(e,".config","opencode"))?{platform:"opencode",confidence:"medium",reason:"~/.config/opencode/ directory exists"}:f(d(e,".config","zed"))?{platform:"zed",confidence:"medium",reason:"~/.config/zed/ directory exists"}:{platform:"claude-code",confidence:"low",reason:"No platform detected, defaulting to Claude Code"}}var g,G,$,S=P(()=>{"use strict";k();g=null;G=[["claude-code",[{name:"CLAUDE_CODE_ENTRYPOINT",role:"identification"},{name:"CLAUDE_PLUGIN_ROOT",role:"identification"},{name:"CLAUDE_PROJECT_DIR",role:"workspace"},{name:"CLAUDE_SESSION_ID",role:"identification"}]],["antigravity",[{name:"ANTIGRAVITY_CLI_ALIAS",role:"identification"}]],["cursor",[{name:"CURSOR_CWD",role:"workspace"},{name:"CURSOR_TRACE_ID",role:"identification"},{name:"CURSOR_CLI",role:"identification"}]],["kilo",[{name:"KILO",role:"identification"},{name:"KILO_PID",role:"identification"}]],["opencode",[{name:"OPENCODE_PROJECT_DIR",role:"workspace"},{name:"OPENCODE_CLIENT",role:"identification"},{name:"OPENCODE_TERMINAL",role:"identification"},{name:"OPENCODE",role:"identification"},{name:"OPENCODE_PID",role:"identification"}]],["zed",[{name:"ZED_SESSION_ID",role:"identification"},{name:"ZED_TERM",role:"identification"}]],["codex",[{name:"CODEX_THREAD_ID",role:"identification"},{name:"CODEX_CI",role:"identification"}]],["gemini-cli",[{name:"GEMINI_PROJECT_DIR",role:"workspace"},{name:"GEMINI_CLI",role:"identification"}]],["vscode-copilot",[{name:"VSCODE_CWD",role:"workspace"},{name:"VSCODE_PID",role:"identification"}]],["jetbrains-copilot",[{name:"IDEA_INITIAL_DIRECTORY",role:"workspace"}]],["qwen-code",[{name:"QWEN_PROJECT_DIR",role:"workspace"}]],["omp",[{name:"PI_CODING_AGENT_DIR",role:"workspace"}]],["pi",[{name:"PI_WORKSPACE_DIR",role:"workspace",detect:!1},{name:"PI_PROJECT_DIR",role:"workspace",detect:!1},{name:"PI_CONFIG_DIR",role:"identification"},{name:"PI_SESSION_FILE",role:"identification"},{name:"PI_COMPILED",role:"identification"},{name:"PI_CODING_AGENT",role:"identification"}]]],$=new Map(G)});import{resolve as h}from"node:path";import{homedir as w}from"node:os";function F(t=process.env){let n=t.CLAUDE_CONFIG_DIR;return n&&n.trim()!==""?n.startsWith("~")?h(w(),n.replace(/^~[/\\]?/,"")):h(n):h(w(),".claude")}function J(t=process.env){return h(F(t),"settings.json")}function x(t=process.env){let n=[],e=v();if(e.platform!=="claude-code"){let i=A(e.platform);i&&i.length>0&&n.push(h(w(),...i,"settings.json"))}let o=J(t);return n.includes(o)||n.push(o),n}var b=P(()=>{"use strict";S()});b();import{readFileSync as R,realpathSync as q}from"node:fs";import{resolve as y}from"node:path";function T(t){let n=t.match(/^Bash\((.+)\)$/);return n?n[1]:null}function V(t){let n=t.match(/^(\w+)\((.+)\)$/);return n?{tool:n[1],glob:n[2]}:null}function z(t){return t.replace(/[.*+?^${}()|[\]\\\/\-]/g,"\\$&")}function D(t){return t.replace(/[.+?^${}()|[\]\\\/\-]/g,"\\$&").replace(/\*/g,".*")}function H(t,n=!1){let e,o=t.indexOf(":");if(o!==-1){let i=t.slice(0,o),r=t.slice(o+1),s=z(i),c=D(r);e=`^${s}(\\s${c})?$`}else e=`^${D(t)}$`;return new RegExp(e,n?"i":"")}function B(t,n=!1){let e="",o=0;for(;o<t.length;)t[o]==="*"&&t[o+1]==="*"?o+2<t.length&&t[o+2]==="/"?(e+="(.*/)?",o+=3):(e+=".*",o+=2):t[o]==="*"?(e+="[^/]*",o++):t[o]==="?"?(e+="[^/]",o++):(e+=t[o].replace(/[.+^${}()|[\]\\\/\-]/g,"\\$&"),o++);return new RegExp(`^${e}$`,n?"i":"")}function C(t,n,e=!1){for(let o of n){let i=T(o);if(i&&H(i,e).test(t))return o}return null}function N(t,n){let e=0;for(let o=n-1;o>=0&&t[o]==="\\";o--)e++;return e%2===1}function U(t){let n=[],e="",o=!1,i=!1,r=!1,s=0;for(let c=0;c<t.length;c++){let a=t[c],l=N(t,c);a==="'"&&!i&&!r&&!l?(o=!o,e+=a):a==='"'&&!o&&!r&&!l?(i=!i,e+=a):a==="`"&&!o&&!i&&!l?(r=!r,e+=a):!o&&!i&&!r?a==="$"&&t[c+1]==="("&&!l?(s++,e+=a+t[c+1],c++):s>0&&a==="("&&!l?(s++,e+=a):a===")"&&s>0&&!l?(s--,e+=a):s===0&&(a===";"||a===`
2
+ `||a==="\r")&&!l?(n.push(e.trim()),e=""):s===0&&a==="|"&&t[c+1]==="|"||s===0&&a==="&"&&t[c+1]==="&"?(n.push(e.trim()),e="",c++):s===0&&a==="&"&&!l||s===0&&a==="|"?(n.push(e.trim()),e=""):e+=a:e+=a}return e.trim()&&n.push(e.trim()),n.filter(c=>c.length>0)}function L(t){let n=[],e=!1,o=!1,i=-1,r=[],s=[],c=0;for(let a=0;a<t.length;a++){let l=t[a],p=N(t,a);if(l==="'"&&!o&&i===-1&&!p)e=!e;else if(l==='"'&&!e&&i===-1&&!p)o=!o;else if(l==="`"&&!e&&!o&&!p)if(i===-1)i=a+1;else{let u=t.slice(i,a);n.push(u),n.push(...L(u)),i=-1}else if(!e&&i===-1){if(l==="$"&&t[a+1]==="("&&!p)t[a+2]==="("?(c+=2,a+=2):(r.push(a+2),s.push(c),c++,a++);else if(l==="("&&!p)c++;else if(l===")"&&!p&&(c>0&&c--,s.length>0&&c===s[s.length-1])){s.pop();let u=r.pop(),m=t.slice(u,a);n.push(m)}}}return n}function _(t){let n=[],e=U(t);for(let o of e){n.push(o);for(let i of L(o))n.push(..._(i))}return n}function E(t){let n;try{n=R(t,"utf-8")}catch{return null}let e;try{e=JSON.parse(n)}catch{return null}let o=e?.permissions;if(!o||typeof o!="object")return null;let i=r=>Array.isArray(r)?r.filter(s=>typeof s=="string"&&T(s)!==null):[];return{allow:i(o.allow),deny:i(o.deny),ask:i(o.ask)}}function de(t,n){let e=[];if(t){let i=y(t,".claude","settings.local.json"),r=E(i);r&&e.push(r);let s=y(t,".claude","settings.json"),c=E(s);c&&e.push(c)}let o=n!==void 0?[n]:x();for(let i of o){let r=E(i);r&&e.push(r)}return e}function fe(t,n,e){let o=[],i=s=>{let c;try{c=R(s,"utf-8")}catch{return null}let a;try{a=JSON.parse(c)}catch{return null}let l=a?.permissions?.deny;if(!Array.isArray(l))return[];let p=[];for(let u of l){if(typeof u!="string")continue;let m=V(u);m&&m.tool===t&&p.push(m.glob)}return p};if(n){let s=i(y(n,".claude","settings.local.json"));s!==null&&o.push(s);let c=i(y(n,".claude","settings.json"));c!==null&&o.push(c)}let r=e!==void 0?[e]:x();for(let s of r){let c=i(s);c!==null&&o.push(c)}return o}function pe(t,n,e=process.platform==="win32"||process.platform==="darwin"){let o=_(t);for(let i of o)for(let r of n){let s=C(i,r.deny,e);if(s)return{decision:"deny",matchedPattern:s}}for(let i of n){let r=!0,s=!1,c,a;for(let l of o){let p=C(l,i.ask,e);if(p){s=!0,c=p;break}let u=C(l,i.allow,e);u?a=u:r=!1}if(s)return{decision:"ask",matchedPattern:c};if(r&&o.length>0)return{decision:"allow",matchedPattern:a}}return{decision:"ask"}}function ue(t,n,e=process.platform==="win32"||process.platform==="darwin"){let o=_(t);for(let i of o)for(let r of n){let s=C(i,r.deny,e);if(s)return{decision:"deny",matchedPattern:s}}return{decision:"allow"}}function me(t,n,e=process.platform==="win32"||process.platform==="darwin",o){let i=s=>s.replace(/\\/g,"/"),r=new Set;if(r.add(i(t)),o){let s=y(o,t);r.add(i(s));try{r.add(i(q(s)))}catch{}}for(let s of n)for(let c of s){let a=B(i(c),e);for(let l of r)if(a.test(l))return{denied:!0,matchedPattern:c}}return{denied:!1}}var W={python:[/os\.system\(\s*(['"])(.*?)\1\s*\)/g,/subprocess\.(?:run|call|Popen|check_output|check_call)\(\s*(['"])(.*?)\1/g],javascript:[/exec(?:Sync|File|FileSync)?\(\s*(['"`])(.*?)\1/g,/spawn(?:Sync)?\(\s*(['"`])(.*?)\1/g],typescript:[/exec(?:Sync|File|FileSync)?\(\s*(['"`])(.*?)\1/g,/spawn(?:Sync)?\(\s*(['"`])(.*?)\1/g],ruby:[/system\(\s*(['"])(.*?)\1/g,/`(.*?)`/g],go:[/exec\.Command\(\s*(['"`])(.*?)\1/g],php:[/shell_exec\(\s*(['"`])(.*?)\1/g,/(?:^|[^.])exec\(\s*(['"`])(.*?)\1/g,/(?:^|[^.])system\(\s*(['"`])(.*?)\1/g,/passthru\(\s*(['"`])(.*?)\1/g,/proc_open\(\s*(['"`])(.*?)\1/g],rust:[/Command::new\(\s*(['"`])(.*?)\1/g]};function K(t){let n=[],e=/subprocess\.(?:run|call|Popen|check_output|check_call)\(\s*\[([^\]]+)\]/g,o;for(;(o=e.exec(t))!==null;){let r=[...o[1].matchAll(/(['"])(.*?)\1/g)].map(s=>s[2]);r.length>0&&n.push(r.join(" "))}return n}function ge(t,n){let e=W[n];if(!e&&n!=="python")return[];let o=[];if(e)for(let i of e){i.lastIndex=0;let r;for(;(r=i.exec(t))!==null;){let s=r[r.length-1];s&&o.push(s)}}return n==="python"&&o.push(...K(t)),o}export{pe as evaluateCommand,ue as evaluateCommandDenyOnly,me as evaluateFilePath,ge as extractShellCommands,L as extractSubshellCommands,B as fileGlobToRegex,H as globToRegex,C as matchesAnyPattern,T as parseBashPattern,V as parseToolPattern,de as readBashPolicies,fe as readToolDenyPatterns,U as splitChainedCommands};
@@ -1,6 +1,6 @@
1
- import{createRequire as oe}from"node:module";import{existsSync as ie,unlinkSync as P,renameSync as ae}from"node:fs";import{tmpdir as ce}from"node:os";import{join as ue}from"node:path";var A=class{#e;constructor(e){this.#e=e}pragma(e){let r=this.#e.prepare(`PRAGMA ${e}`).all();if(!r||r.length===0)return;if(r.length>1)return r;let s=Object.values(r[0]);return s.length===1?s[0]:r[0]}exec(e){let t="",r=null;for(let a=0;a<e.length;a++){let i=e[a];if(r)t+=i,i===r&&(r=null);else if(i==="'"||i==='"')t+=i,r=i;else if(i===";"){let c=t.trim();c&&this.#e.prepare(c).run(),t=""}else t+=i}let s=t.trim();return s&&this.#e.prepare(s).run(),this}prepare(e){let t=this.#e.prepare(e);return{run:(...r)=>t.run(...r),get:(...r)=>{let s=t.get(...r);return s===null?void 0:s},all:(...r)=>t.all(...r),iterate:(...r)=>t.iterate(...r)}}transaction(e){return this.#e.transaction(e)}close(){this.#e.close()}},w=class{#e;constructor(e){this.#e=e}pragma(e){let r=this.#e.prepare(`PRAGMA ${e}`).all();if(!r||r.length===0)return;if(r.length>1)return r;let s=Object.values(r[0]);return s.length===1?s[0]:r[0]}exec(e){return this.#e.exec(e),this}prepare(e){let t=this.#e.prepare(e);return{run:(...r)=>t.run(...r),get:(...r)=>t.get(...r),all:(...r)=>t.all(...r),iterate:(...r)=>typeof t.iterate=="function"?t.iterate(...r):t.all(...r)[Symbol.iterator]()}}transaction(e){return(...t)=>{this.#e.exec("BEGIN");try{let r=e(...t);return this.#e.exec("COMMIT"),r}catch(r){throw this.#e.exec("ROLLBACK"),r}}}close(){this.#e.close()}},g=null;function de(n){let e=null;try{return e=new n(":memory:"),e.exec("CREATE VIRTUAL TABLE __fts5_probe USING fts5(x)"),!0}catch{return!1}finally{try{e?.close()}catch{}}}function le(n,e){let t=e!==void 0?e:globalThis.Bun;if(typeof t<"u"&&t!==null)return!0;let r=n??process.versions,[s,a]=(r.node??"0.0.0").split("."),i=Number(s),c=Number(a);return!Number.isFinite(i)||!Number.isFinite(c)?!1:i>22||i===22&&c>=5}function Ee(){if(!g){let n=oe(import.meta.url);if(globalThis.Bun){let e=n(["bun","sqlite"].join(":")).Database;g=function(r,s){let a=new e(r,{readonly:s?.readonly,create:!0}),i=new A(a);return s?.timeout&&i.pragma(`busy_timeout = ${s.timeout}`),i}}else if(le()){let e=null;try{({DatabaseSync:e}=n(["node","sqlite"].join(":")))}catch{e=null}e&&de(e)?g=function(r,s){let a=new e(r,{readOnly:s?.readonly??!1}),i=new w(a);return s?.timeout&&i.pragma(`busy_timeout = ${s.timeout}`),i}:g=n("better-sqlite3")}else g=n("better-sqlite3")}return g}function F(n){n.pragma("journal_mode = WAL"),n.pragma("synchronous = NORMAL");try{n.pragma("mmap_size = 268435456")}catch{}}function k(n){if(!ie(n))for(let e of["-wal","-shm"])try{P(n+e)}catch{}}function ge(n){for(let e of["","-wal","-shm"])try{P(n+e)}catch{}}function x(n){try{n.pragma("wal_checkpoint(TRUNCATE)")}catch{}try{n.close()}catch{}}function B(n="context-mode"){return ue(ce(),`${n}-${process.pid}.db`)}function me(n,e=[100,500,2e3]){let t;for(let r=0;r<=e.length;r++)try{return n()}catch(s){let a=s instanceof Error?s.message:String(s);if(!a.includes("SQLITE_BUSY")&&!a.includes("database is locked"))throw s;if(t=s instanceof Error?s:new Error(a),r<e.length){let i=e[r],c=Date.now();for(;Date.now()-c<i;);}}throw new Error(`SQLITE_BUSY: database is locked after ${e.length} retries. Original error: ${t?.message}`)}function _e(n){return n.includes("SQLITE_CORRUPT")||n.includes("SQLITE_NOTADB")||n.includes("database disk image is malformed")||n.includes("file is not a database")}function pe(n){let e=Date.now();for(let t of["","-wal","-shm"])try{ae(n+t,`${n}${t}.corrupt-${e}`)}catch{}}var y=Symbol.for("__context_mode_live_dbs_v3__"),O=(()=>{let n=globalThis;return n[y]||(n[y]=new Set,process.on("exit",()=>{for(let e of n[y])x(e);n[y].clear()})),n[y]})(),v=class{#e;#t;constructor(e){let t=Ee();this.#e=e,k(e);let r;try{r=new t(e,{timeout:3e4}),F(r)}catch(s){let a=s instanceof Error?s.message:String(s);if(_e(a)){pe(e),k(e);try{r=new t(e,{timeout:3e4}),F(r)}catch(i){throw new Error(`Failed to create fresh DB after renaming corrupt file: ${i instanceof Error?i.message:String(i)}`)}}else throw s}this.#t=r,O.add(this.#t),this.initSchema(),this.prepareStatements()}get db(){return this.#t}get dbPath(){return this.#e}close(){O.delete(this.#t),x(this.#t)}withRetry(e){return me(e)}cleanup(){O.delete(this.#t),x(this.#t),ge(this.#e)}};import{createHash as S}from"node:crypto";import{execFileSync as ye}from"node:child_process";import{accessSync as Se,constants as fe,existsSync as D,mkdirSync as he,realpathSync as Te,renameSync as I}from"node:fs";import{homedir as q}from"node:os";import{dirname as ve,isAbsolute as G,join as E,resolve as _}from"node:path";var l="CONTEXT_MODE_DIR",Y="sessions",j="content",f=class extends Error{kind;path;overrideEnvVar;ignoredEnvVar;ignoredReason;constructor(e,t,r=l,s,a,i={}){super(a??Ne(e,t,i),{cause:s}),this.name="StorageDirectoryError",this.kind=e,this.path=t,this.overrideEnvVar=r,this.ignoredEnvVar=i.ignoredEnvVar,this.ignoredReason=i.ignoredReason}},b=new Map;function qe(n){let e=n.env??process.env,t=n.legacySessionDirEnv,r=t?e[t]?.trim():void 0;return r&&t?(n.onLegacySessionDir?.(t,r),r):E(Re(n.configDir,n.configDirEnv,e),"context-mode","sessions")}function Re(n,e,t){let r=e?t[e]:void 0;return r&&r.trim()!==""?V(r.trim()):V(n,q())}function V(n,e){return n.startsWith("~")?_(q(),n.replace(/^~[/\\]?/,"")):G(n)?_(n):e?_(e,n):_(n)}function be(n,e,t){return new f(n,e,l,void 0,[`Invalid ${l} for context-mode ${n} directory: ${t}`,J()].join(`
2
- `))}function K(n){let e=process.env[l];if(e===void 0)return{kind:"unset"};let t=e.trim();if(!t)return{kind:"ignored-empty",ignoredEnvVar:l,ignoredReason:"empty"};if(!G(t))throw be(n,t,`${l} must be an absolute path.`);return{kind:"override",root:_(t)}}function De(n){return n.kind==="ignored-empty"?{ignoredEnvVar:n.ignoredEnvVar,ignoredReason:n.ignoredReason}:{}}function z(n,e){let t=K(n);return t.kind!=="override"?null:{kind:n,path:E(t.root,e),envVar:l,source:"override"}}function Le(n,e,t){return{kind:n,path:_(e()),envVar:null,source:"default",...t}}function Q(n){let e=K("session");return e.kind==="override"?{kind:"session",path:E(e.root,Y),envVar:l,source:"override"}:Le("session",n,De(e))}function Ge(n){let e=z("content",j);if(e)return e;let t=Q(n);return{kind:"content",path:E(ve(t.path),j),envVar:t.envVar,source:t.source,ignoredEnvVar:t.ignoredEnvVar,ignoredReason:t.ignoredReason}}function Ye(n){let e=z("stats",Y);if(e)return e;let t=Q(n);return{kind:"stats",path:t.path,envVar:t.envVar,source:t.source,ignoredEnvVar:t.ignoredEnvVar,ignoredReason:t.ignoredReason}}function Ke(n){return n.message}function ze(n){return n.source==="override"&&n.envVar?`via ${n.envVar}`:n.ignoredEnvVar&&n.ignoredReason==="empty"?`default; ignored empty ${n.ignoredEnvVar}`:"default"}function Qe(){b.clear()}function Je(n){let e=[n.kind,n.path,n.source,n.envVar??"",n.ignoredEnvVar??"",n.ignoredReason??""].join("\0"),t=b.get(e);if(t instanceof f)throw t;if(t===n.path)return t;try{return he(n.path,{recursive:!0}),Se(n.path,fe.W_OK),b.set(e,n.path),n.path}catch(r){let s=new f(n.kind,Oe(r)??n.path,l,r,void 0,{ignoredEnvVar:n.ignoredEnvVar,ignoredReason:n.ignoredReason});throw b.set(e,s),s}}function Ne(n,e,t={}){return[`context-mode ${n} directory is not writable: ${e}`,Ce(t),J()].filter(Boolean).join(`
3
- `)}function Ce(n){return n.ignoredEnvVar&&n.ignoredReason==="empty"?`Ignored empty ${n.ignoredEnvVar}; using adapter default.`:null}function J(){return`Set ${l} to a writable absolute path.`}function Oe(n){if(!n||typeof n!="object")return null;let e=n.path;return typeof e=="string"&&e.length>0?e:null}var m;function h(n){let e=n.replace(/\\/g,"/");return/^\/+$/.test(e)?"/":/^[A-Za-z]:\/+$/.test(e)?`${e.slice(0,2)}/`:e.replace(/\/+$/,"")}function H(n){let e=n;try{e=Te.native(n)}catch{}let t=h(e);return process.platform==="win32"||process.platform==="darwin"?t.toLowerCase():t}function Z(n,e){return ye("git",["-C",n,...e],{encoding:"utf-8",timeout:2e3,stdio:["ignore","pipe","ignore"]}).trim()}function Ae(n){let e=Z(n,["rev-parse","--show-toplevel"]);return e.length>0?h(e):null}function we(n){let e=Z(n,["worktree","list","--porcelain"]).split(/\r?\n/).find(t=>t.startsWith("worktree "))?.replace("worktree ","")?.trim();return e?h(e):null}function xe(n=process.cwd()){let e=process.env.CONTEXT_MODE_SESSION_SUFFIX;if(m&&m.projectDir===n&&m.envSuffix===e)return m.suffix;let t="";if(e!==void 0)t=e?`__${e}`:"";else try{let r=Ae(n),s=we(n);if(r&&s){let a=H(r),i=H(s);a!==i&&(t=`__${S("sha256").update(a).digest("hex").slice(0,8)}`)}}catch{}return m={projectDir:n,envSuffix:e,suffix:t},t}function Ze(){m=void 0}function ee(n){return S("sha256").update(h(n)).digest("hex").slice(0,16)}function te(n){let e=h(n),t=process.platform==="darwin"||process.platform==="win32"?e.toLowerCase():e;return S("sha256").update(t).digest("hex").slice(0,16)}function et(n){let{projectDir:e,contentDir:t}=n,r=te(e),s=E(t,`${r}.db`);if(D(s))return s;let a=ee(e);if(a===r)return s;let i=E(t,`${a}.db`);if(D(i))try{I(i,s);for(let c of["-wal","-shm"])try{I(i+c,s+c)}catch{}}catch{}return s}function tt(n){return Ie({...n,ext:".db"})}function Ie(n){let{projectDir:e,sessionsDir:t,ext:r}=n,s=n.suffix??xe(e),a=te(e),i=E(t,`${a}${s}${r}`);if(D(i))return i;let c=ee(e);if(c===a)return i;let d=E(t,`${c}${s}${r}`);if(D(d))try{I(d,i)}catch{}return i}var W=1e3,X=5;function R(n){let e=Number(n);return!Number.isFinite(e)||e<=0?0:Math.floor(e)}var o={insertEvent:"insertEvent",getEvents:"getEvents",getEventsByType:"getEventsByType",getEventsByPriority:"getEventsByPriority",getEventsByTypeAndPriority:"getEventsByTypeAndPriority",getEventCount:"getEventCount",getLatestAttributedProject:"getLatestAttributedProject",checkDuplicate:"checkDuplicate",evictLowestPriority:"evictLowestPriority",updateMetaLastEvent:"updateMetaLastEvent",ensureSession:"ensureSession",getSessionStats:"getSessionStats",getSessionRollup:"getSessionRollup",getMaxFileEdits:"getMaxFileEdits",getLatestCommitMessage:"getLatestCommitMessage",incrementCompactCount:"incrementCompactCount",upsertResume:"upsertResume",getResume:"getResume",markResumeConsumed:"markResumeConsumed",claimLatestUnconsumedResume:"claimLatestUnconsumedResume",deleteEvents:"deleteEvents",deleteMeta:"deleteMeta",deleteResume:"deleteResume",getOldSessions:"getOldSessions",searchEvents:"searchEvents",incrementToolCall:"incrementToolCall",getToolCallTotals:"getToolCallTotals",getToolCallByTool:"getToolCallByTool",getEventBytesSummary:"getEventBytesSummary"},Me=[["project_dir","TEXT NOT NULL DEFAULT ''"],["attribution_source","TEXT NOT NULL DEFAULT 'unknown'"],["attribution_confidence","REAL NOT NULL DEFAULT 0"],["bytes_avoided","INTEGER NOT NULL DEFAULT 0"],["bytes_returned","INTEGER NOT NULL DEFAULT 0"]];function ne(n){let e=n.pragma("table_xinfo(session_events)"),t=new Set(e.map(s=>s.name)),r=!1;for(let[s,a]of Me)t.has(s)||(n.exec(`ALTER TABLE session_events ADD COLUMN ${s} ${a}`),r=!0);return r&&n.exec("CREATE INDEX IF NOT EXISTS idx_session_events_project ON session_events(session_id, project_dir)"),r}function nt(n,e){let t=null;try{t=new e(n),ne(t)}catch{}finally{try{t?.close()}catch{}}}var $=class extends v{constructor(e){super(e?.dbPath??B("session"))}stmt(e){return this.stmts.get(e)}initSchema(){try{let t=this.db.pragma("table_xinfo(session_events)").find(r=>r.name==="data_hash");t&&t.hidden!==0&&this.db.exec("DROP TABLE session_events")}catch{}this.db.exec(`
1
+ import{createRequire as ie}from"node:module";import{existsSync as ae,unlinkSync as P,renameSync as ce}from"node:fs";import{tmpdir as ue}from"node:os";import{join as de}from"node:path";var A=class{#e;constructor(e){this.#e=e}pragma(e){let r=this.#e.prepare(`PRAGMA ${e}`).all();if(!r||r.length===0)return;if(r.length>1)return r;let s=Object.values(r[0]);return s.length===1?s[0]:r[0]}exec(e){let t="",r=null;for(let a=0;a<e.length;a++){let i=e[a];if(r)t+=i,i===r&&(r=null);else if(i==="'"||i==='"')t+=i,r=i;else if(i===";"){let c=t.trim();c&&this.#e.prepare(c).run(),t=""}else t+=i}let s=t.trim();return s&&this.#e.prepare(s).run(),this}prepare(e){let t=this.#e.prepare(e);return{run:(...r)=>t.run(...r),get:(...r)=>{let s=t.get(...r);return s===null?void 0:s},all:(...r)=>t.all(...r),iterate:(...r)=>t.iterate(...r)}}transaction(e){return this.#e.transaction(e)}close(){this.#e.close()}},w=class{#e;constructor(e){this.#e=e}pragma(e){let r=this.#e.prepare(`PRAGMA ${e}`).all();if(!r||r.length===0)return;if(r.length>1)return r;let s=Object.values(r[0]);return s.length===1?s[0]:r[0]}exec(e){return this.#e.exec(e),this}prepare(e){let t=this.#e.prepare(e);return{run:(...r)=>t.run(...r),get:(...r)=>t.get(...r),all:(...r)=>t.all(...r),iterate:(...r)=>typeof t.iterate=="function"?t.iterate(...r):t.all(...r)[Symbol.iterator]()}}transaction(e){return(...t)=>{this.#e.exec("BEGIN");try{let r=e(...t);return this.#e.exec("COMMIT"),r}catch(r){throw this.#e.exec("ROLLBACK"),r}}}close(){this.#e.close()}},m=null;function le(n){let e=null;try{return e=new n(":memory:"),e.exec("CREATE VIRTUAL TABLE __fts5_probe USING fts5(x)"),!0}catch{return!1}finally{try{e?.close()}catch{}}}function Ee(n,e){let t=e!==void 0?e:globalThis.Bun;if(typeof t<"u"&&t!==null)return!0;let r=n??process.versions,[s,a]=(r.node??"0.0.0").split("."),i=Number(s),c=Number(a);return!Number.isFinite(i)||!Number.isFinite(c)?!1:i>22||i===22&&c>=5}function ge(){if(!m){let n=ie(import.meta.url);if(globalThis.Bun){let e=n(["bun","sqlite"].join(":")).Database;m=function(r,s){let a=new e(r,{readonly:s?.readonly,create:!0}),i=new A(a);return s?.timeout&&i.pragma(`busy_timeout = ${s.timeout}`),i}}else if(Ee()){let e=null;try{({DatabaseSync:e}=n(["node","sqlite"].join(":")))}catch{e=null}e&&le(e)?m=function(r,s){let a=new e(r,{readOnly:s?.readonly??!1}),i=new w(a);return s?.timeout&&i.pragma(`busy_timeout = ${s.timeout}`),i}:m=n("better-sqlite3")}else m=n("better-sqlite3")}return m}function F(n){n.pragma("journal_mode = WAL"),n.pragma("synchronous = NORMAL");try{n.pragma("mmap_size = 268435456")}catch{}}function k(n){if(!ae(n))for(let e of["-wal","-shm"])try{P(n+e)}catch{}}function me(n){for(let e of["","-wal","-shm"])try{P(n+e)}catch{}}function x(n){try{n.pragma("wal_checkpoint(TRUNCATE)")}catch{}try{n.close()}catch{}}function B(n="context-mode"){return de(ue(),`${n}-${process.pid}.db`)}function _e(n,e=[100,500,2e3]){let t;for(let r=0;r<=e.length;r++)try{return n()}catch(s){let a=s instanceof Error?s.message:String(s);if(!a.includes("SQLITE_BUSY")&&!a.includes("database is locked"))throw s;if(t=s instanceof Error?s:new Error(a),r<e.length){let i=e[r],c=Date.now();for(;Date.now()-c<i;);}}throw new Error(`SQLITE_BUSY: database is locked after ${e.length} retries. Original error: ${t?.message}`)}function pe(n){return n.includes("SQLITE_CORRUPT")||n.includes("SQLITE_NOTADB")||n.includes("database disk image is malformed")||n.includes("file is not a database")}function ye(n){let e=Date.now();for(let t of["","-wal","-shm"])try{ce(n+t,`${n}${t}.corrupt-${e}`)}catch{}}var S=Symbol.for("__context_mode_live_dbs_v3__"),O=(()=>{let n=globalThis;return n[S]||(n[S]=new Set,process.on("exit",()=>{for(let e of n[S])x(e);n[S].clear()})),n[S]})(),R=class{#e;#t;constructor(e){let t=ge();this.#e=e,k(e);let r;try{r=new t(e,{timeout:3e4}),F(r)}catch(s){let a=s instanceof Error?s.message:String(s);if(pe(a)){ye(e),k(e);try{r=new t(e,{timeout:3e4}),F(r)}catch(i){throw new Error(`Failed to create fresh DB after renaming corrupt file: ${i instanceof Error?i.message:String(i)}`)}}else throw s}this.#t=r,O.add(this.#t),this.initSchema(),this.prepareStatements()}get db(){return this.#t}get dbPath(){return this.#e}close(){O.delete(this.#t),x(this.#t)}withRetry(e){return _e(e)}cleanup(){O.delete(this.#t),x(this.#t),me(this.#e)}};import{createHash as f}from"node:crypto";import{execFileSync as Se}from"node:child_process";import{accessSync as fe,constants as he,existsSync as L,mkdirSync as Te,realpathSync as ve,renameSync as I}from"node:fs";import{homedir as q}from"node:os";import{dirname as Re,isAbsolute as G,join as E,resolve as p}from"node:path";var l="CONTEXT_MODE_DIR",Y="sessions",j="content",h=class extends Error{kind;path;overrideEnvVar;ignoredEnvVar;ignoredReason;constructor(e,t,r=l,s,a,i={}){super(a??Ce(e,t,i),{cause:s}),this.name="StorageDirectoryError",this.kind=e,this.path=t,this.overrideEnvVar=r,this.ignoredEnvVar=i.ignoredEnvVar,this.ignoredReason=i.ignoredReason}},D=new Map;function Ge(n){let e=n.env??process.env,t=n.legacySessionDirEnv,r=t?e[t]?.trim():void 0;return r&&t?(n.onLegacySessionDir?.(t,r),r):E(be(n.configDir,n.configDirEnv,e),"context-mode","sessions")}function be(n,e,t){let r=e?t[e]:void 0;return r&&r.trim()!==""?V(r.trim()):V(n,q())}function V(n,e){return n.startsWith("~")?p(q(),n.replace(/^~[/\\]?/,"")):G(n)?p(n):e?p(e,n):p(n)}function De(n,e,t){return new h(n,e,l,void 0,[`Invalid ${l} for context-mode ${n} directory: ${t}`,J()].join(`
2
+ `))}function K(n){let e=process.env[l];if(e===void 0)return{kind:"unset"};let t=e.trim();if(!t)return{kind:"ignored-empty",ignoredEnvVar:l,ignoredReason:"empty"};if(!G(t))throw De(n,t,`${l} must be an absolute path.`);return{kind:"override",root:p(t)}}function Le(n){return n.kind==="ignored-empty"?{ignoredEnvVar:n.ignoredEnvVar,ignoredReason:n.ignoredReason}:{}}function z(n,e){let t=K(n);return t.kind!=="override"?null:{kind:n,path:E(t.root,e),envVar:l,source:"override"}}function Ne(n,e,t){return{kind:n,path:p(e()),envVar:null,source:"default",...t}}function Q(n){let e=K("session");return e.kind==="override"?{kind:"session",path:E(e.root,Y),envVar:l,source:"override"}:Ne("session",n,Le(e))}function Ye(n){let e=z("content",j);if(e)return e;let t=Q(n);return{kind:"content",path:E(Re(t.path),j),envVar:t.envVar,source:t.source,ignoredEnvVar:t.ignoredEnvVar,ignoredReason:t.ignoredReason}}function Ke(n){let e=z("stats",Y);if(e)return e;let t=Q(n);return{kind:"stats",path:t.path,envVar:t.envVar,source:t.source,ignoredEnvVar:t.ignoredEnvVar,ignoredReason:t.ignoredReason}}function ze(n){return n.message}function Qe(n){return n.source==="override"&&n.envVar?`via ${n.envVar}`:n.ignoredEnvVar&&n.ignoredReason==="empty"?`default; ignored empty ${n.ignoredEnvVar}`:"default"}function Je(){D.clear()}function Ze(n){let e=[n.kind,n.path,n.source,n.envVar??"",n.ignoredEnvVar??"",n.ignoredReason??""].join("\0"),t=D.get(e);if(t instanceof h)throw t;if(t===n.path)return t;try{return Te(n.path,{recursive:!0}),fe(n.path,he.W_OK),D.set(e,n.path),n.path}catch(r){let s=new h(n.kind,Ae(r)??n.path,l,r,void 0,{ignoredEnvVar:n.ignoredEnvVar,ignoredReason:n.ignoredReason});throw D.set(e,s),s}}function Ce(n,e,t={}){return[`context-mode ${n} directory is not writable: ${e}`,Oe(t),J()].filter(Boolean).join(`
3
+ `)}function Oe(n){return n.ignoredEnvVar&&n.ignoredReason==="empty"?`Ignored empty ${n.ignoredEnvVar}; using adapter default.`:null}function J(){return`Set ${l} to a writable absolute path.`}function Ae(n){if(!n||typeof n!="object")return null;let e=n.path;return typeof e=="string"&&e.length>0?e:null}var _;function g(n){let e=n.replace(/\\/g,"/");return/^\/+$/.test(e)?"/":/^[A-Za-z]:\/+$/.test(e)?`${e.slice(0,2)}/`:e.replace(/\/+$/,"")}function H(n){let e=n;try{e=ve.native(n)}catch{}let t=g(e);return process.platform==="win32"||process.platform==="darwin"?t.toLowerCase():t}function Z(n,e){return Se("git",["-C",n,...e],{encoding:"utf-8",timeout:2e3,stdio:["ignore","pipe","ignore"]}).trim()}function we(n){let e=Z(n,["rev-parse","--show-toplevel"]);return e.length>0?g(e):null}function xe(n){let e=Z(n,["worktree","list","--porcelain"]).split(/\r?\n/).find(t=>t.startsWith("worktree "))?.replace("worktree ","")?.trim();return e?g(e):null}function Ie(n=process.cwd()){let e=process.env.CONTEXT_MODE_SESSION_SUFFIX;if(_&&_.projectDir===n&&_.envSuffix===e)return _.suffix;let t="";if(e!==void 0)t=e?`__${e}`:"";else try{let r=we(n),s=xe(n);if(r&&s){let a=H(r),i=H(s);a!==i&&(t=`__${f("sha256").update(a).digest("hex").slice(0,8)}`)}}catch{}return _={projectDir:n,envSuffix:e,suffix:t},t}function et(){_=void 0}function ee(n){return f("sha256").update(g(n)).digest("hex").slice(0,16)}function te(n){let e=g(n),t=process.platform==="darwin"||process.platform==="win32"?e.toLowerCase():e;return f("sha256").update(t).digest("hex").slice(0,16)}function tt(n){let{projectDir:e,contentDir:t}=n,r=te(e),s=E(t,`${r}.db`);if(L(s))return s;let a=ee(e);if(a===r)return s;let i=E(t,`${a}.db`);if(L(i))try{I(i,s);for(let c of["-wal","-shm"])try{I(i+c,s+c)}catch{}}catch{}return s}function nt(n){return Me({...n,ext:".db"})}function Me(n){let{projectDir:e,sessionsDir:t,ext:r}=n,s=n.suffix??Ie(e),a=te(e),i=E(t,`${a}${s}${r}`);if(L(i))return i;let c=ee(e);if(c===a)return i;let d=E(t,`${c}${s}${r}`);if(L(d))try{I(d,i)}catch{}return i}var W=1e3,X=5;function b(n){let e=Number(n);return!Number.isFinite(e)||e<=0?0:Math.floor(e)}var o={insertEvent:"insertEvent",getEvents:"getEvents",getEventsByType:"getEventsByType",getEventsByPriority:"getEventsByPriority",getEventsByTypeAndPriority:"getEventsByTypeAndPriority",getEventCount:"getEventCount",getLatestAttributedProject:"getLatestAttributedProject",checkDuplicate:"checkDuplicate",evictLowestPriority:"evictLowestPriority",updateMetaLastEvent:"updateMetaLastEvent",ensureSession:"ensureSession",getSessionStats:"getSessionStats",getSessionRollup:"getSessionRollup",getMaxFileEdits:"getMaxFileEdits",getLatestCommitMessage:"getLatestCommitMessage",incrementCompactCount:"incrementCompactCount",upsertResume:"upsertResume",getResume:"getResume",markResumeConsumed:"markResumeConsumed",claimLatestUnconsumedResume:"claimLatestUnconsumedResume",deleteEvents:"deleteEvents",deleteMeta:"deleteMeta",deleteResume:"deleteResume",getOldSessions:"getOldSessions",searchEvents:"searchEvents",incrementToolCall:"incrementToolCall",getToolCallTotals:"getToolCallTotals",getToolCallByTool:"getToolCallByTool",getEventBytesSummary:"getEventBytesSummary"},Ue=[["project_dir","TEXT NOT NULL DEFAULT ''"],["attribution_source","TEXT NOT NULL DEFAULT 'unknown'"],["attribution_confidence","REAL NOT NULL DEFAULT 0"],["bytes_avoided","INTEGER NOT NULL DEFAULT 0"],["bytes_returned","INTEGER NOT NULL DEFAULT 0"]];function ne(n){let e=n.pragma("table_xinfo(session_events)"),t=new Set(e.map(s=>s.name)),r=!1;for(let[s,a]of Ue)t.has(s)||(n.exec(`ALTER TABLE session_events ADD COLUMN ${s} ${a}`),r=!0);return r&&n.exec("CREATE INDEX IF NOT EXISTS idx_session_events_project ON session_events(session_id, project_dir)"),r}function rt(n,e){let t=null;try{t=new e(n),ne(t)}catch{}finally{try{t?.close()}catch{}}}var $=class extends R{constructor(e){super(e?.dbPath??B("session"))}stmt(e){return this.stmts.get(e)}initSchema(){try{let t=this.db.pragma("table_xinfo(session_events)").find(r=>r.name==="data_hash");t&&t.hidden!==0&&this.db.exec("DROP TABLE session_events")}catch{}this.db.exec(`
4
4
  CREATE TABLE IF NOT EXISTS session_events (
5
5
  id INTEGER PRIMARY KEY AUTOINCREMENT,
6
6
  session_id TEXT NOT NULL,
@@ -139,6 +139,6 @@ import{createRequire as oe}from"node:module";import{existsSync as ie,unlinkSync
139
139
  FROM tool_calls WHERE session_id = ?`),e(o.getToolCallByTool,`SELECT tool, calls, bytes_returned
140
140
  FROM tool_calls WHERE session_id = ? ORDER BY calls DESC`),e(o.getEventBytesSummary,`SELECT COALESCE(SUM(bytes_avoided), 0) AS bytes_avoided,
141
141
  COALESCE(SUM(bytes_returned), 0) AS bytes_returned
142
- FROM session_events WHERE session_id = ?`)}insertEvent(e,t,r="PostToolUse",s,a){let i=S("sha256").update(t.data).digest("hex").slice(0,16).toUpperCase(),c=String(s?.projectDir??t.project_dir??this._getSessionProjectDir(e)).trim(),d=String(s?.source??t.attribution_source??"unknown"),u=Number(s?.confidence??t.attribution_confidence??0),T=Number.isFinite(u)?Math.max(0,Math.min(1,u)):0,p=R(a?.bytesAvoided),L=R(a?.bytesReturned),N=this.db.transaction(()=>{if(this.stmt(o.checkDuplicate).get(e,X,t.type,i))return;this.stmt(o.getEventCount).get(e).cnt>=W&&this.stmt(o.evictLowestPriority).run(e),this.stmt(o.insertEvent).run(e,t.type,t.category,t.priority,t.data,c,d,T,p,L,r,i),this.stmt(o.updateMetaLastEvent).run(e)});this.withRetry(()=>N())}bulkInsertEvents(e,t,r="PostToolUse",s,a){if(!t||t.length===0)return;if(t.length===1){this.insertEvent(e,t[0],r,s?.[0],a?.[0]);return}let i=t.map((d,u)=>{let T=S("sha256").update(d.data).digest("hex").slice(0,16).toUpperCase(),p=s?.[u],L=String(p?.projectDir??d.project_dir??this._getSessionProjectDir(e)??"").trim(),N=String(p?.source??d.attribution_source??"unknown"),C=Number(p?.confidence??d.attribution_confidence??0),M=Number.isFinite(C)?Math.max(0,Math.min(1,C)):0,U=a?.[u],re=R(U?.bytesAvoided),se=R(U?.bytesReturned);return{event:d,dataHash:T,projectDir:L,attributionSource:N,attributionConfidence:M,bytesAvoided:re,bytesReturned:se}}),c=this.db.transaction(()=>{let d=this.stmt(o.getEventCount).get(e).cnt;for(let u of i)this.stmt(o.checkDuplicate).get(e,X,u.event.type,u.dataHash)||(d>=W?this.stmt(o.evictLowestPriority).run(e):d++,this.stmt(o.insertEvent).run(e,u.event.type,u.event.category,u.event.priority,u.event.data,u.projectDir,u.attributionSource,u.attributionConfidence,u.bytesAvoided,u.bytesReturned,r,u.dataHash));this.stmt(o.updateMetaLastEvent).run(e)});this.withRetry(()=>c())}getEvents(e,t){let r=t?.limit??1e3,s=t?.type,a=t?.minPriority;return s&&a!==void 0?this.stmt(o.getEventsByTypeAndPriority).all(e,s,a,r):s?this.stmt(o.getEventsByType).all(e,s,r):a!==void 0?this.stmt(o.getEventsByPriority).all(e,a,r):this.stmt(o.getEvents).all(e,r)}getEventCount(e){return this.stmt(o.getEventCount).get(e).cnt}getEventBytesSummary(e){let t=this.stmt(o.getEventBytesSummary).get(e);return{bytesAvoided:Number(t?.bytes_avoided??0),bytesReturned:Number(t?.bytes_returned??0)}}getLatestAttributedProjectDir(e){return this.stmt(o.getLatestAttributedProject).get(e)?.project_dir||null}_getSessionProjectDir(e){try{return this.db.prepare("SELECT project_dir FROM session_meta WHERE session_id = ?").get(e)?.project_dir||""}catch{return""}}searchEvents(e,t,r,s){try{let a=e.replace(/[%_]/g,c=>"\\"+c),i=s??null;return this.stmt(o.searchEvents).all(r,a,a,i,i,t)}catch{return[]}}getSessionIdsForProject(e){try{return this.db.prepare(`SELECT DISTINCT session_id
142
+ FROM session_events WHERE session_id = ?`)}insertEvent(e,t,r="PostToolUse",s,a){let i=f("sha256").update(t.data).digest("hex").slice(0,16).toUpperCase(),c=String(s?.projectDir??t.project_dir??this._getSessionProjectDir(e)).trim(),d=String(s?.source??t.attribution_source??"unknown"),u=Number(s?.confidence??t.attribution_confidence??0),T=Number.isFinite(u)?Math.max(0,Math.min(1,u)):0,y=b(a?.bytesAvoided),v=b(a?.bytesReturned),N=this.db.transaction(()=>{if(this.stmt(o.checkDuplicate).get(e,X,t.type,i))return;this.stmt(o.getEventCount).get(e).cnt>=W&&this.stmt(o.evictLowestPriority).run(e),this.stmt(o.insertEvent).run(e,t.type,t.category,t.priority,t.data,c,d,T,y,v,r,i),this.stmt(o.updateMetaLastEvent).run(e)});this.withRetry(()=>N())}bulkInsertEvents(e,t,r="PostToolUse",s,a){if(!t||t.length===0)return;if(t.length===1){this.insertEvent(e,t[0],r,s?.[0],a?.[0]);return}let i=t.map((d,u)=>{let T=f("sha256").update(d.data).digest("hex").slice(0,16).toUpperCase(),y=s?.[u],v=String(y?.projectDir??d.project_dir??this._getSessionProjectDir(e)??"").trim(),N=v===""?"":g(v),M=String(y?.source??d.attribution_source??"unknown"),C=Number(y?.confidence??d.attribution_confidence??0),re=Number.isFinite(C)?Math.max(0,Math.min(1,C)):0,U=a?.[u],se=b(U?.bytesAvoided),oe=b(U?.bytesReturned);return{event:d,dataHash:T,projectDir:N,attributionSource:M,attributionConfidence:re,bytesAvoided:se,bytesReturned:oe}}),c=this.db.transaction(()=>{let d=this.stmt(o.getEventCount).get(e).cnt;for(let u of i)this.stmt(o.checkDuplicate).get(e,X,u.event.type,u.dataHash)||(d>=W?this.stmt(o.evictLowestPriority).run(e):d++,this.stmt(o.insertEvent).run(e,u.event.type,u.event.category,u.event.priority,u.event.data,u.projectDir,u.attributionSource,u.attributionConfidence,u.bytesAvoided,u.bytesReturned,r,u.dataHash));this.stmt(o.updateMetaLastEvent).run(e)});this.withRetry(()=>c())}getEvents(e,t){let r=t?.limit??1e3,s=t?.type,a=t?.minPriority;return s&&a!==void 0?this.stmt(o.getEventsByTypeAndPriority).all(e,s,a,r):s?this.stmt(o.getEventsByType).all(e,s,r):a!==void 0?this.stmt(o.getEventsByPriority).all(e,a,r):this.stmt(o.getEvents).all(e,r)}getEventCount(e){return this.stmt(o.getEventCount).get(e).cnt}getEventBytesSummary(e){let t=this.stmt(o.getEventBytesSummary).get(e);return{bytesAvoided:Number(t?.bytes_avoided??0),bytesReturned:Number(t?.bytes_returned??0)}}getLatestAttributedProjectDir(e){return this.stmt(o.getLatestAttributedProject).get(e)?.project_dir||null}_getSessionProjectDir(e){try{return this.db.prepare("SELECT project_dir FROM session_meta WHERE session_id = ?").get(e)?.project_dir||""}catch{return""}}searchEvents(e,t,r,s){try{let a=e.replace(/[%_]/g,c=>"\\"+c),i=s??null;return this.stmt(o.searchEvents).all(r,a,a,i,i,t)}catch{return[]}}getSessionIdsForProject(e){try{let t=g(e);return this.db.prepare(`SELECT DISTINCT session_id
143
143
  FROM session_events
144
- WHERE project_dir = ?`).all(e).map(r=>r.session_id)}catch{return[]}}ensureSession(e,t){this.stmt(o.ensureSession).run(e,t)}getSessionStats(e){return this.stmt(o.getSessionStats).get(e)??null}getSessionRollup(e){let t=this.stmt(o.getSessionRollup).get(e),r=this.stmt(o.getMaxFileEdits).get(e),s=this.stmt(o.getLatestCommitMessage).get(e),a=this.getSessionStats(e),i=(t?.tool_calls??0)>0?t?.unique_files??0:0,c=t?.errors??0,d=Math.min(i,c);return{tool_calls:t?.tool_calls??0,errors:t?.errors??0,unique_tools:t?.unique_tools??0,unique_files:t?.unique_files??0,max_file_edits:r?.max_file_edits??0,has_commit:t?.has_commit??0,commit_message:s?.data??"",edit_test_cycles:d,duration_min:t?.duration_min??0,compact_count:a?.compact_count??0,sources_indexed:t?.sources_indexed??0,total_chunks:t?.total_chunks??0,search_queries:t?.search_queries??0}}incrementCompactCount(e){this.stmt(o.incrementCompactCount).run(e)}upsertResume(e,t,r){this.stmt(o.upsertResume).run(e,t,r??0)}getResume(e){return this.stmt(o.getResume).get(e)??null}markResumeConsumed(e){this.stmt(o.markResumeConsumed).run(e)}claimLatestUnconsumedResume(e){let t=this.stmt(o.claimLatestUnconsumedResume).get(e);return t?{sessionId:t.session_id,snapshot:t.snapshot}:null}getLatestSessionId(){try{return this.db.prepare("SELECT session_id FROM session_meta ORDER BY started_at DESC LIMIT 1").get()?.session_id??null}catch{return null}}incrementToolCall(e,t,r=0){let s=Number.isFinite(r)&&r>0?Math.round(r):0;try{this.stmt(o.incrementToolCall).run(e,t,s)}catch{}}getToolCallStats(e){try{let t=this.stmt(o.getToolCallTotals).get(e),r=this.stmt(o.getToolCallByTool).all(e),s={};for(let a of r)s[a.tool]={calls:a.calls,bytesReturned:a.bytes_returned};return{totalCalls:t?.calls??0,totalBytesReturned:t?.bytes_returned??0,byTool:s}}catch{return{totalCalls:0,totalBytesReturned:0,byTool:{}}}}deleteSession(e){this.db.transaction(()=>{this.stmt(o.deleteEvents).run(e),this.stmt(o.deleteResume).run(e),this.stmt(o.deleteMeta).run(e)})()}cleanupOldSessions(e=7){let t=`-${e}`,r=this.stmt(o.getOldSessions).all(t);for(let{session_id:s}of r)this.deleteSession(s);return r.length}pruneOrphanedEvents(){let e=this.db.prepare("DELETE FROM session_events WHERE session_id NOT IN (SELECT session_id FROM session_meta)").run();return Number(e.changes??0)}};export{$ as SessionDB,f as StorageDirectoryError,Ze as _resetWorktreeSuffixCacheForTests,ne as applyMissingSessionEventsColumns,Qe as clearStorageDirectoryCheckCacheForTests,ze as describeStorageDirectorySource,nt as ensureSessionEventsSchema,Je as ensureWritableStorageDir,Ke as formatStorageDirectoryError,xe as getWorktreeSuffix,te as hashProjectDirCanonical,ee as hashProjectDirLegacy,h as normalizeWorktreePath,Ge as resolveContentStorageDir,et as resolveContentStorePath,qe as resolveDefaultSessionDir,tt as resolveSessionDbPath,Ie as resolveSessionPath,Q as resolveSessionStorageDir,Ye as resolveStatsStorageDir};
144
+ WHERE RTRIM(REPLACE(project_dir, '\\', '/'), '/') = ?`).all(t).map(s=>s.session_id)}catch{return[]}}ensureSession(e,t){this.stmt(o.ensureSession).run(e,t)}getSessionStats(e){return this.stmt(o.getSessionStats).get(e)??null}getSessionRollup(e){let t=this.stmt(o.getSessionRollup).get(e),r=this.stmt(o.getMaxFileEdits).get(e),s=this.stmt(o.getLatestCommitMessage).get(e),a=this.getSessionStats(e),i=(t?.tool_calls??0)>0?t?.unique_files??0:0,c=t?.errors??0,d=Math.min(i,c);return{tool_calls:t?.tool_calls??0,errors:t?.errors??0,unique_tools:t?.unique_tools??0,unique_files:t?.unique_files??0,max_file_edits:r?.max_file_edits??0,has_commit:t?.has_commit??0,commit_message:s?.data??"",edit_test_cycles:d,duration_min:t?.duration_min??0,compact_count:a?.compact_count??0,sources_indexed:t?.sources_indexed??0,total_chunks:t?.total_chunks??0,search_queries:t?.search_queries??0}}incrementCompactCount(e){this.stmt(o.incrementCompactCount).run(e)}upsertResume(e,t,r){this.stmt(o.upsertResume).run(e,t,r??0)}getResume(e){return this.stmt(o.getResume).get(e)??null}markResumeConsumed(e){this.stmt(o.markResumeConsumed).run(e)}claimLatestUnconsumedResume(e){let t=this.stmt(o.claimLatestUnconsumedResume).get(e);return t?{sessionId:t.session_id,snapshot:t.snapshot}:null}getLatestSessionId(){try{return this.db.prepare("SELECT session_id FROM session_meta ORDER BY started_at DESC LIMIT 1").get()?.session_id??null}catch{return null}}incrementToolCall(e,t,r=0){let s=Number.isFinite(r)&&r>0?Math.round(r):0;try{this.stmt(o.incrementToolCall).run(e,t,s)}catch{}}getToolCallStats(e){try{let t=this.stmt(o.getToolCallTotals).get(e),r=this.stmt(o.getToolCallByTool).all(e),s={};for(let a of r)s[a.tool]={calls:a.calls,bytesReturned:a.bytes_returned};return{totalCalls:t?.calls??0,totalBytesReturned:t?.bytes_returned??0,byTool:s}}catch{return{totalCalls:0,totalBytesReturned:0,byTool:{}}}}deleteSession(e){this.db.transaction(()=>{this.stmt(o.deleteEvents).run(e),this.stmt(o.deleteResume).run(e),this.stmt(o.deleteMeta).run(e)})()}cleanupOldSessions(e=7){let t=`-${e}`,r=this.stmt(o.getOldSessions).all(t);for(let{session_id:s}of r)this.deleteSession(s);return r.length}pruneOrphanedEvents(){let e=this.db.prepare("DELETE FROM session_events WHERE session_id NOT IN (SELECT session_id FROM session_meta)").run();return Number(e.changes??0)}};export{$ as SessionDB,h as StorageDirectoryError,et as _resetWorktreeSuffixCacheForTests,ne as applyMissingSessionEventsColumns,Je as clearStorageDirectoryCheckCacheForTests,Qe as describeStorageDirectorySource,rt as ensureSessionEventsSchema,Ze as ensureWritableStorageDir,ze as formatStorageDirectoryError,Ie as getWorktreeSuffix,te as hashProjectDirCanonical,ee as hashProjectDirLegacy,g as normalizeWorktreePath,Ye as resolveContentStorageDir,tt as resolveContentStorePath,Ge as resolveDefaultSessionDir,nt as resolveSessionDbPath,Me as resolveSessionPath,Q as resolveSessionStorageDir,Ke as resolveStatsStorageDir};