context-mode 1.0.134 → 1.0.136

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 (50) hide show
  1. package/.claude-plugin/marketplace.json +2 -2
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/.codex-plugin/hooks.json +65 -0
  4. package/.codex-plugin/mcp.json +9 -0
  5. package/.codex-plugin/plugin.json +31 -0
  6. package/.openclaw-plugin/openclaw.plugin.json +1 -1
  7. package/.openclaw-plugin/package.json +1 -1
  8. package/README.md +60 -12
  9. package/build/adapters/detect.d.ts +3 -1
  10. package/build/adapters/detect.js +7 -2
  11. package/build/adapters/pi/mcp-bridge.d.ts +44 -0
  12. package/build/adapters/pi/mcp-bridge.js +149 -3
  13. package/build/cli.js +17 -0
  14. package/build/lifecycle.d.ts +13 -13
  15. package/build/lifecycle.js +14 -14
  16. package/build/runtime.js +8 -5
  17. package/build/session/analytics.d.ts +0 -13
  18. package/build/session/analytics.js +50 -1
  19. package/build/session/extract.js +39 -1
  20. package/build/util/claude-config.d.ts +12 -6
  21. package/build/util/claude-config.js +16 -23
  22. package/cli.bundle.mjs +135 -133
  23. package/configs/kilo/kilo.json +9 -2
  24. package/configs/opencode/opencode.json +9 -2
  25. package/hooks/codex/platform.mjs +1 -0
  26. package/hooks/codex/posttooluse.mjs +1 -0
  27. package/hooks/codex/precompact.mjs +1 -0
  28. package/hooks/codex/pretooluse.mjs +1 -0
  29. package/hooks/codex/sessionstart.mjs +24 -1
  30. package/hooks/codex/stop.mjs +1 -0
  31. package/hooks/codex/userpromptsubmit.mjs +1 -0
  32. package/hooks/core/platform-detect.mjs +1 -1
  33. package/hooks/core/routing.mjs +112 -10
  34. package/hooks/ensure-deps.mjs +14 -3
  35. package/hooks/normalize-hooks.mjs +5 -2
  36. package/hooks/security.bundle.mjs +1 -1
  37. package/hooks/session-extract.bundle.mjs +2 -2
  38. package/openclaw.plugin.json +1 -1
  39. package/package.json +2 -1
  40. package/scripts/heal-installed-plugins.mjs +67 -0
  41. package/server.bundle.mjs +99 -99
  42. package/start.mjs +73 -11
  43. package/build/openclaw-plugin.d.ts +0 -130
  44. package/build/openclaw-plugin.js +0 -626
  45. package/build/opencode-plugin.d.ts +0 -122
  46. package/build/opencode-plugin.js +0 -372
  47. package/build/pi-extension.d.ts +0 -14
  48. package/build/pi-extension.js +0 -451
  49. package/build/util/db-lock.d.ts +0 -65
  50. package/build/util/db-lock.js +0 -166
@@ -3,8 +3,15 @@
3
3
  "mcp": {
4
4
  "context-mode": {
5
5
  "type": "local",
6
- "command": ["context-mode"]
6
+ "command": [
7
+ "context-mode"
8
+ ],
9
+ "environment": {
10
+ "CONTEXT_MODE_IDLE_TIMEOUT_MS": "900000"
11
+ }
7
12
  }
8
13
  },
9
- "plugin": ["context-mode"]
14
+ "plugin": [
15
+ "context-mode"
16
+ ]
10
17
  }
@@ -3,8 +3,15 @@
3
3
  "mcp": {
4
4
  "context-mode": {
5
5
  "type": "local",
6
- "command": ["context-mode"]
6
+ "command": [
7
+ "context-mode"
8
+ ],
9
+ "environment": {
10
+ "CONTEXT_MODE_IDLE_TIMEOUT_MS": "900000"
11
+ }
7
12
  }
8
13
  },
9
- "plugin": ["context-mode"]
14
+ "plugin": [
15
+ "context-mode"
16
+ ]
10
17
  }
@@ -0,0 +1 @@
1
+ process.env.CONTEXT_MODE_PLATFORM = "codex";
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env node
2
+ import "./platform.mjs";
2
3
  import "../suppress-stderr.mjs";
3
4
  import "../ensure-deps.mjs";
4
5
  /**
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env node
2
+ import "./platform.mjs";
2
3
  import "../suppress-stderr.mjs";
3
4
  import "../ensure-deps.mjs";
4
5
  /**
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env node
2
+ import "./platform.mjs";
2
3
  import "../suppress-stderr.mjs";
3
4
  /**
4
5
  * Codex CLI preToolUse hook for context-mode.
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env node
2
+ import "./platform.mjs";
2
3
  import "../suppress-stderr.mjs";
3
4
  import "../ensure-deps.mjs";
4
5
  /**
@@ -23,10 +24,12 @@ import {
23
24
  getSessionEventsPath,
24
25
  getCleanupFlagPath,
25
26
  getInputProjectDir,
27
+ resolveConfigDir,
26
28
  CODEX_OPTS,
27
29
  } from "../session-helpers.mjs";
28
30
  import { createSessionLoaders } from "../session-loaders.mjs";
29
- import { unlinkSync } from "node:fs";
31
+ import { existsSync, readFileSync, unlinkSync } from "node:fs";
32
+ import { join } from "node:path";
30
33
  import { fileURLToPath } from "node:url";
31
34
 
32
35
  const HOOK_DIR = fileURLToPath(new URL(".", import.meta.url));
@@ -35,6 +38,25 @@ const OPTS = CODEX_OPTS;
35
38
 
36
39
  let additionalContext = ROUTING_BLOCK;
37
40
 
41
+ function captureCodexInstructionRules(db, sessionId, projectDir) {
42
+ const paths = [];
43
+ for (const baseDir of [resolveConfigDir(OPTS), projectDir]) {
44
+ paths.push(join(baseDir, "AGENTS.md"));
45
+ paths.push(join(baseDir, "AGENTS.override.md"));
46
+ }
47
+
48
+ for (const p of [...new Set(paths)]) {
49
+ try {
50
+ if (!existsSync(p)) continue;
51
+ const content = readFileSync(p, "utf8");
52
+ db.insertEvent(sessionId, { type: "rule", category: "rule", data: p, priority: 1 });
53
+ db.insertEvent(sessionId, { type: "rule_content", category: "rule", data: content, priority: 1 });
54
+ } catch {
55
+ // Missing or unreadable rule files should never break SessionStart.
56
+ }
57
+ }
58
+ }
59
+
38
60
  try {
39
61
  const raw = await readStdin();
40
62
  const input = parseStdin(raw);
@@ -84,6 +106,7 @@ try {
84
106
 
85
107
  const sessionId = getSessionId(input, OPTS);
86
108
  db.ensureSession(sessionId, projectDir);
109
+ captureCodexInstructionRules(db, sessionId, projectDir);
87
110
 
88
111
  db.close();
89
112
  }
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env node
2
+ import "./platform.mjs";
2
3
  import "../suppress-stderr.mjs";
3
4
  import "../ensure-deps.mjs";
4
5
  /**
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env node
2
+ import "./platform.mjs";
2
3
  import "../suppress-stderr.mjs";
3
4
  import "../ensure-deps.mjs";
4
5
  /**
@@ -26,7 +26,7 @@ const PLATFORM_ENV_VARS_MIRROR = [
26
26
  ["antigravity", ["ANTIGRAVITY_CLI_ALIAS"]],
27
27
  ["cursor", ["CURSOR_TRACE_ID", "CURSOR_CLI"]],
28
28
  ["kilo", ["KILO_PID"]],
29
- ["opencode", ["OPENCODE", "OPENCODE_PID"]],
29
+ ["opencode", ["OPENCODE_CLIENT", "OPENCODE_TERMINAL", "OPENCODE", "OPENCODE_PID"]],
30
30
  ["zed", ["ZED_SESSION_ID", "ZED_TERM"]],
31
31
  ["codex", ["CODEX_THREAD_ID", "CODEX_CI"]],
32
32
  ["gemini-cli", ["GEMINI_PROJECT_DIR", "GEMINI_CLI"]],
@@ -17,7 +17,7 @@ import {
17
17
  } from "../routing-block.mjs";
18
18
  import { createToolNamer } from "./tool-naming.mjs";
19
19
  import { isMCPReady } from "./mcp-ready.mjs";
20
- import { existsSync, mkdirSync, rmSync, rmdirSync, readdirSync, unlinkSync, openSync, closeSync, statSync, constants as fsConstants } from "node:fs";
20
+ import { existsSync, mkdirSync, rmSync, rmdirSync, readdirSync, unlinkSync, openSync, closeSync, readFileSync, writeFileSync, statSync, constants as fsConstants } from "node:fs";
21
21
 
22
22
  /**
23
23
  * Guard for actions that redirect to MCP tools (#230).
@@ -29,7 +29,7 @@ function mcpRedirect(result) {
29
29
  if (!isMCPReady()) return null;
30
30
  return result;
31
31
  }
32
- import { tmpdir } from "node:os";
32
+ import { homedir, tmpdir } from "node:os";
33
33
  import { resolve } from "node:path";
34
34
 
35
35
  // Guidance throttle: show each advisory type at most once per session.
@@ -49,6 +49,32 @@ import { resolve } from "node:path";
49
49
  // invocations of the same logical session.
50
50
  const _guidanceShown = new Set();
51
51
 
52
+ // Periodic-guidance counters: how many times each (sessionId, type) pair has
53
+ // fired the periodic branch. Keyed by `${sessionId-or-ppid}::${type}`.
54
+ // File-backed for cross-process so hook invocations from the same logical
55
+ // session keep the counter coherent.
56
+ const _guidanceCounters = new Map();
57
+
58
+ // External-MCP nudge cadence — fire every N matching tool calls.
59
+ // Default 10: keeps the guidance fresh in long MCP-heavy sessions (e.g. a
60
+ // Jira/Slack/Notion run with 50+ tool calls — see #567 follow-up) without
61
+ // flooding context with repeat nudges. Bounds [1, 100]; invalid env values
62
+ // fall back to default. period=1 means "fire every call" (opt-in only).
63
+ const EXTERNAL_MCP_NUDGE_DEFAULT = 10;
64
+ const EXTERNAL_MCP_NUDGE_MIN = 1;
65
+ const EXTERNAL_MCP_NUDGE_MAX = 100;
66
+ const EXTERNAL_MCP_NUDGE_ENV = "CONTEXT_MODE_EXTERNAL_MCP_NUDGE_EVERY";
67
+
68
+ function getExternalMcpNudgeEvery() {
69
+ const raw = process.env[EXTERNAL_MCP_NUDGE_ENV];
70
+ if (raw == null || raw === "") return EXTERNAL_MCP_NUDGE_DEFAULT;
71
+ const parsed = Number.parseInt(raw, 10);
72
+ if (!Number.isFinite(parsed) || parsed < EXTERNAL_MCP_NUDGE_MIN || parsed > EXTERNAL_MCP_NUDGE_MAX) {
73
+ return EXTERNAL_MCP_NUDGE_DEFAULT;
74
+ }
75
+ return parsed;
76
+ }
77
+
52
78
  function defaultGuidanceId() {
53
79
  return process.env.VITEST_WORKER_ID
54
80
  ? `${process.ppid}-w${process.env.VITEST_WORKER_ID}`
@@ -85,6 +111,56 @@ function guidanceOnce(type, content, sessionId) {
85
111
  return { action: "context", additionalContext: content };
86
112
  }
87
113
 
114
+ /**
115
+ * Like guidanceOnce, but fires on a periodic cadence (calls 1, period+1,
116
+ * 2·period+1, …) rather than once per session.
117
+ *
118
+ * Motivation: external-MCP tool runs can span 50+ calls (e.g. a Jira/Slack
119
+ * search loop — see #567 follow-up). A single one-shot nudge gets lost
120
+ * after the model's context compaction kicks in, and subsequent large MCP
121
+ * payloads flood context unchecked. Re-firing the nudge every N calls
122
+ * keeps the guidance in the model's recent window without saturating it.
123
+ *
124
+ * Counter state is process-aware: in-memory Map for same-process callers,
125
+ * file-backed `<guidanceDir>/<type>.count` for cross-process hook
126
+ * invocations. On any IO/parse failure we fall back to firing — losing a
127
+ * counter is preferable to silently dropping the advisory.
128
+ */
129
+ function guidancePeriodic(type, content, sessionId, period) {
130
+ const safePeriod = Math.max(1, period | 0);
131
+ const id = sessionId ? `s-${sessionId}` : defaultGuidanceId();
132
+ const key = `${id}::${type}`;
133
+
134
+ // Read counter from memory first; fall through to disk on miss.
135
+ let count = _guidanceCounters.get(key);
136
+ const dir = guidanceDirFor(sessionId);
137
+ const counterPath = resolve(dir, `${type}.count`);
138
+
139
+ if (count == null) {
140
+ try {
141
+ const parsed = Number.parseInt(readFileSync(counterPath, "utf8"), 10);
142
+ count = Number.isFinite(parsed) && parsed >= 0 ? parsed : 0;
143
+ } catch {
144
+ count = 0;
145
+ }
146
+ }
147
+
148
+ const next = count + 1;
149
+ _guidanceCounters.set(key, next);
150
+
151
+ try {
152
+ mkdirSync(dir, { recursive: true });
153
+ writeFileSync(counterPath, String(next), "utf8");
154
+ } catch {
155
+ // Best-effort: cross-process counter may drift on FS failure, but we
156
+ // still return a decision based on the in-memory tick.
157
+ }
158
+
159
+ // Fire on the 1st, (period+1)th, (2·period+1)th… call.
160
+ if ((next - 1) % safePeriod !== 0) return null;
161
+ return { action: "context", additionalContext: content };
162
+ }
163
+
88
164
  /**
89
165
  * Robust recursive delete. On Windows, `fs.rmSync` on directories under a
90
166
  * tmpdir whose path contains non-ASCII characters (e.g. a Chinese / Japanese /
@@ -105,6 +181,7 @@ function rmSyncRobust(dir) {
105
181
 
106
182
  export function resetGuidanceThrottle(sessionId) {
107
183
  _guidanceShown.clear();
184
+ _guidanceCounters.clear();
108
185
  // Clear ppid-based dir (legacy / fallback callers) and the sessionId dir if given
109
186
  rmSyncRobust(guidanceDirFor());
110
187
  if (sessionId) {
@@ -499,6 +576,24 @@ function isExternalMcpTool(toolName) {
499
576
  return false;
500
577
  }
501
578
 
579
+ function getShellCommand(toolInput) {
580
+ if (!toolInput || typeof toolInput !== "object") return "";
581
+ if (typeof toolInput.command === "string") return toolInput.command;
582
+ if (typeof toolInput.cmd === "string") return toolInput.cmd;
583
+ return "";
584
+ }
585
+
586
+ function getCodexConfigDir(env = process.env) {
587
+ const codexHome = env.CODEX_HOME;
588
+ if (codexHome && codexHome.trim() !== "") return resolve(codexHome);
589
+ return resolve(homedir(), ".codex");
590
+ }
591
+
592
+ function getPlatformSettingsPath(platform) {
593
+ if (platform === "codex") return resolve(getCodexConfigDir(), "settings.json");
594
+ return undefined;
595
+ }
596
+
502
597
  /**
503
598
  * Route a PreToolUse event. Returns normalized decision object or null for passthrough.
504
599
  *
@@ -539,17 +634,18 @@ export function routePreToolUse(toolName, toolInput, projectDir, platform, sessi
539
634
 
540
635
  // Normalize platform-specific tool name to canonical
541
636
  const canonical = TOOL_ALIASES[toolName] ?? toolName;
637
+ const platformSettingsPath = getPlatformSettingsPath(platform);
542
638
 
543
639
  // ─── Bash: Stage 1 security check, then Stage 2 routing ───
544
640
  if (canonical === "Bash") {
545
- const command = toolInput.command ?? "";
641
+ const command = getShellCommand(toolInput);
546
642
 
547
643
  // Stage 1: Security check against user's deny/allow patterns.
548
644
  // Only act when an explicit pattern matched. When no pattern matches,
549
645
  // evaluateCommand returns { decision: "ask" } with no matchedPattern —
550
646
  // in that case fall through so other hooks and the platform's native engine can decide.
551
647
  if (security) {
552
- const policies = security.readBashPolicies(projectDir);
648
+ const policies = security.readBashPolicies(projectDir, platformSettingsPath);
553
649
  if (policies.length > 0) {
554
650
  const result = security.evaluateCommand(command, policies);
555
651
  if (result.decision === "deny") {
@@ -741,7 +837,7 @@ export function routePreToolUse(toolName, toolInput, projectDir, platform, sessi
741
837
  if (matchesContextModeTool(toolName, "ctx_execute", "execute")) {
742
838
  if (security && toolInput.language === "shell") {
743
839
  const code = toolInput.code ?? "";
744
- const policies = security.readBashPolicies(projectDir);
840
+ const policies = security.readBashPolicies(projectDir, platformSettingsPath);
745
841
  if (policies.length > 0) {
746
842
  const result = security.evaluateCommand(code, policies);
747
843
  if (result.decision === "deny") {
@@ -760,7 +856,7 @@ export function routePreToolUse(toolName, toolInput, projectDir, platform, sessi
760
856
  if (security) {
761
857
  // Check file path against Read deny patterns
762
858
  const filePath = toolInput.path ?? "";
763
- const denyGlobs = security.readToolDenyPatterns("Read", projectDir);
859
+ const denyGlobs = security.readToolDenyPatterns("Read", projectDir, platformSettingsPath);
764
860
  const evalResult = security.evaluateFilePath(filePath, denyGlobs);
765
861
  if (evalResult.denied) {
766
862
  return { action: "deny", reason: `Blocked by security policy: file path matches Read deny pattern ${evalResult.matchedPattern}` };
@@ -770,7 +866,7 @@ export function routePreToolUse(toolName, toolInput, projectDir, platform, sessi
770
866
  const lang = toolInput.language ?? "";
771
867
  const code = toolInput.code ?? "";
772
868
  if (lang === "shell") {
773
- const policies = security.readBashPolicies(projectDir);
869
+ const policies = security.readBashPolicies(projectDir, platformSettingsPath);
774
870
  if (policies.length > 0) {
775
871
  const result = security.evaluateCommand(code, policies);
776
872
  if (result.decision === "deny") {
@@ -789,7 +885,7 @@ export function routePreToolUse(toolName, toolInput, projectDir, platform, sessi
789
885
  if (matchesContextModeTool(toolName, "ctx_batch_execute", "batch_execute")) {
790
886
  if (security) {
791
887
  const commands = toolInput.commands ?? [];
792
- const policies = security.readBashPolicies(projectDir);
888
+ const policies = security.readBashPolicies(projectDir, platformSettingsPath);
793
889
  if (policies.length > 0) {
794
890
  for (const entry of commands) {
795
891
  const cmd = entry.command ?? "";
@@ -806,14 +902,20 @@ export function routePreToolUse(toolName, toolInput, projectDir, platform, sessi
806
902
  return null;
807
903
  }
808
904
 
809
- // ─── External MCP tools: one-shot guidance about routing large payloads ─── (#529)
905
+ // ─── External MCP tools: periodic guidance about routing large payloads ─── (#529, #567 follow-up)
810
906
  // hooks/hooks.json registers a `mcp__(?!plugin_context-mode_)` matcher so this
811
907
  // branch fires for slack/telegram/gdrive/notion-style MCPs whose results would
812
908
  // otherwise spill into context. We don't deny or modify — the agent still needs
813
909
  // the tool's output; we just nudge it to pipe large results through ctx_execute.
910
+ //
911
+ // Cadence: every N calls (default 10, tunable via CONTEXT_MODE_EXTERNAL_MCP_NUDGE_EVERY).
912
+ // The original one-shot nudge (#529) was lost after context compaction in
913
+ // MCP-heavy sessions (e.g. 50+ Jira calls in #567 follow-up), letting later
914
+ // payloads flood context unchecked. Re-firing periodically keeps the guidance
915
+ // in the model's recent window without saturating it.
814
916
  if (isExternalMcpTool(toolName)) {
815
917
  const externalMcpGuidance = platform ? createExternalMcpGuidance(t) : EXTERNAL_MCP_GUIDANCE;
816
- return guidanceOnce("external-mcp", externalMcpGuidance, sessionId);
918
+ return guidancePeriodic("external-mcp", externalMcpGuidance, sessionId, getExternalMcpNudgeEvery());
817
919
  }
818
920
 
819
921
  // Unknown tool — pass through
@@ -19,7 +19,7 @@
19
19
  * @see https://github.com/mksglu/context-mode/issues/203
20
20
  */
21
21
 
22
- import { existsSync, copyFileSync } from "node:fs";
22
+ import { existsSync, copyFileSync, renameSync, unlinkSync } from "node:fs";
23
23
  import { execSync } from "node:child_process";
24
24
  import { resolve, dirname } from "node:path";
25
25
  import { fileURLToPath, pathToFileURL } from "node:url";
@@ -127,6 +127,18 @@ function probeNativeInProcess(pluginRoot) {
127
127
  }
128
128
  }
129
129
 
130
+ function replaceActiveNativeBinaryFromCache(abiCachePath, binaryPath) {
131
+ const tmpPath = `${binaryPath}.staging-${process.pid}-${Date.now()}`;
132
+ try {
133
+ copyFileSync(abiCachePath, tmpPath);
134
+ codesignBinary(tmpPath);
135
+ renameSync(tmpPath, binaryPath);
136
+ } catch (err) {
137
+ try { unlinkSync(tmpPath); } catch { /* best effort cleanup */ }
138
+ throw err;
139
+ }
140
+ }
141
+
130
142
  export function ensureNativeCompat(pluginRoot) {
131
143
  // Pre-compute paths regardless of runtime — the Bun branch below uses
132
144
  // them to seed the ABI cache (#543) so the next /ctx-upgrade boot (under
@@ -161,8 +173,7 @@ export function ensureNativeCompat(pluginRoot) {
161
173
 
162
174
  // Fast path: cached binary for this ABI already exists — swap in
163
175
  if (existsSync(abiCachePath)) {
164
- copyFileSync(abiCachePath, binaryPath);
165
- codesignBinary(binaryPath);
176
+ replaceActiveNativeBinaryFromCache(abiCachePath, binaryPath);
166
177
  if (skipProbe) return; // Trust the cached binary — skip SIGSEGV-prone probe
167
178
  // Validate via child process — dlopen cache is per-process, so in-process
168
179
  // require() can't detect a swapped binary on disk (#148)
@@ -142,12 +142,15 @@ export function normalizePluginJson(content, nodePath, pluginRoot) {
142
142
  * Options:
143
143
  * - pluginRoot: absolute path to plugin install dir (e.g. __dirname of start.mjs)
144
144
  * - nodePath: process.execPath
145
- * - platform: process.platform (only "win32" triggers a write)
145
+ * - platform: process.platform ("win32" and "linux" trigger a write)
146
146
  *
147
147
  * Best-effort — never throws.
148
148
  */
149
149
  export function normalizeHooksOnStartup({ pluginRoot, nodePath, platform }) {
150
- if (platform !== "win32") return;
150
+ // Normalize on Windows (MSYS path mangling, #369/#372/#378) and Linux
151
+ // (bare `node` not in PATH when invoked via /bin/sh, e.g. nvm users).
152
+ // macOS ships a system node so bare `node` resolves reliably there.
153
+ if (platform !== "win32" && platform !== "linux") return;
151
154
  if (!pluginRoot || !nodePath) return;
152
155
 
153
156
  // hooks/hooks.json
@@ -1 +1 @@
1
- import{readFileSync as S,realpathSync as R}from"node:fs";import{resolve as u}from"node:path";import{resolve as a}from"node:path";import{homedir as d}from"node:os";import{createRequire as C}from"node:module";function v(e=process.env){let s=e.CLAUDE_CONFIG_DIR;return s&&s.trim()!==""?s.startsWith("~")?a(d(),s.replace(/^~[/\\]?/,"")):a(s):a(d(),".claude")}function E(e=process.env){return a(v(e),"settings.json")}function h(e=process.env){let s=[],t=null,n=null;try{let r=C(import.meta.url)("../adapters/detect.js");t=r.detectPlatform(),n=r.getSessionDirSegments}catch{}if(t&&n&&t.platform!=="claude-code"){let o=n(t.platform);o&&o.length>0&&s.push(a(d(),...o,"settings.json"))}let i=E(e);return s.includes(i)||s.push(i),s}function w(e){let s=e.match(/^Bash\((.+)\)$/);return s?s[1]:null}function k(e){let s=e.match(/^(\w+)\((.+)\)$/);return s?{tool:s[1],glob:s[2]}:null}function $(e){return e.replace(/[.*+?^${}()|[\]\\\/\-]/g,"\\$&")}function P(e){return e.replace(/[.+?^${}()|[\]\\\/\-]/g,"\\$&").replace(/\*/g,".*")}function A(e,s=!1){let t,n=e.indexOf(":");if(n!==-1){let i=e.slice(0,n),o=e.slice(n+1),r=$(i),l=P(o);t=`^${r}(\\s${l})?$`}else t=`^${P(e)}$`;return new RegExp(t,s?"i":"")}function G(e,s=!1){let t="",n=0;for(;n<e.length;)e[n]==="*"&&e[n+1]==="*"?n+2<e.length&&e[n+2]==="/"?(t+="(.*/)?",n+=3):(t+=".*",n+=2):e[n]==="*"?(t+="[^/]*",n++):e[n]==="?"?(t+="[^/]",n++):(t+=e[n].replace(/[.+^${}()|[\]\\\/\-]/g,"\\$&"),n++);return new RegExp(`^${t}$`,s?"i":"")}function f(e,s,t=!1){for(let n of s){let i=w(n);if(i&&A(i,t).test(e))return n}return null}function b(e){let s=[],t="",n=!1,i=!1,o=!1;for(let r=0;r<e.length;r++){let l=e[r],c=r>0?e[r-1]:"";l==="'"&&!i&&!o&&c!=="\\"?(n=!n,t+=l):l==='"'&&!n&&!o&&c!=="\\"?(i=!i,t+=l):l==="`"&&!n&&!i&&c!=="\\"?(o=!o,t+=l):!n&&!i&&!o?l===";"?(s.push(t.trim()),t=""):l==="|"&&e[r+1]==="|"||l==="&"&&e[r+1]==="&"?(s.push(t.trim()),t="",r++):l==="|"?(s.push(t.trim()),t=""):t+=l:t+=l}return t.trim()&&s.push(t.trim()),s.filter(r=>r.length>0)}function m(e){let s;try{s=S(e,"utf-8")}catch{return null}let t;try{t=JSON.parse(s)}catch{return null}let n=t?.permissions;if(!n||typeof n!="object")return null;let i=o=>Array.isArray(o)?o.filter(r=>typeof r=="string"&&w(r)!==null):[];return{allow:i(n.allow),deny:i(n.deny),ask:i(n.ask)}}function L(e,s){let t=[];if(e){let i=u(e,".claude","settings.local.json"),o=m(i);o&&t.push(o);let r=u(e,".claude","settings.json"),l=m(r);l&&t.push(l)}let n=s!==void 0?[s]:h();for(let i of n){let o=m(i);o&&t.push(o)}return t}function M(e,s,t){let n=[],i=r=>{let l;try{l=S(r,"utf-8")}catch{return null}let c;try{c=JSON.parse(l)}catch{return null}let g=c?.permissions?.deny;if(!Array.isArray(g))return[];let y=[];for(let x of g){if(typeof x!="string")continue;let p=k(x);p&&p.tool===e&&y.push(p.glob)}return y};if(s){let r=i(u(s,".claude","settings.local.json"));r!==null&&n.push(r);let l=i(u(s,".claude","settings.json"));l!==null&&n.push(l)}let o=t!==void 0?[t]:h();for(let r of o){let l=i(r);l!==null&&n.push(l)}return n}function q(e,s,t=process.platform==="win32"){let n=b(e);for(let i of n)for(let o of s){let r=f(i,o.deny,t);if(r)return{decision:"deny",matchedPattern:r}}for(let i of s){let o=f(e,i.ask,t);if(o)return{decision:"ask",matchedPattern:o};let r=f(e,i.allow,t);if(r)return{decision:"allow",matchedPattern:r}}return{decision:"ask"}}function z(e,s,t=process.platform==="win32"){let n=b(e);for(let i of n)for(let o of s){let r=f(i,o.deny,t);if(r)return{decision:"deny",matchedPattern:r}}return{decision:"allow"}}function I(e,s,t=process.platform==="win32",n){let i=r=>r.replace(/\\/g,"/"),o=new Set;if(o.add(i(e)),n){let r=u(n,e);o.add(i(r));try{o.add(i(R(r)))}catch{}}for(let r of s)for(let l of r){let c=G(i(l),t);for(let g of o)if(c.test(g))return{denied:!0,matchedPattern:l}}return{denied:!1}}var _={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 F(e){let s=[],t=/subprocess\.(?:run|call|Popen|check_output|check_call)\(\s*\[([^\]]+)\]/g,n;for(;(n=t.exec(e))!==null;){let o=[...n[1].matchAll(/(['"])(.*?)\1/g)].map(r=>r[2]);o.length>0&&s.push(o.join(" "))}return s}function H(e,s){let t=_[s];if(!t&&s!=="python")return[];let n=[];if(t)for(let i of t){i.lastIndex=0;let o;for(;(o=i.exec(e))!==null;){let r=o[o.length-1];r&&n.push(r)}}return s==="python"&&n.push(...F(e)),n}export{q as evaluateCommand,z as evaluateCommandDenyOnly,I as evaluateFilePath,H as extractShellCommands,G as fileGlobToRegex,A as globToRegex,f as matchesAnyPattern,w as parseBashPattern,k as parseToolPattern,L as readBashPolicies,M as readToolDenyPatterns,b as splitChainedCommands};
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"}});import{existsSync as l,readFileSync as N}from"node:fs";import{resolve as a}from"node:path";import{homedir as S}from"node:os";function L(){if(f!==null)return f!=="miss"&&f.hasCM;try{let n=a(S(),".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 A(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"kilo":return[".config","kilo"];case"opencode":return[".config","opencode"];case"zed":return[".config","zed"];case"jetbrains-copilot":return[".config","JetBrains"];default:return null}}function O(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"].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=S();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,".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,R=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 p}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("~")?p(P(),t.replace(/^~[/\\]?/,"")):p(t):p(P(),".claude")}function G(n=process.env){return p(j(n),"settings.json")}function w(n=process.env){let t=[],e=O();if(e.platform!=="claude-code"){let r=A(e.platform);r&&r.length>0&&t.push(p(P(),...r,"settings.json"))}let o=G(n);return t.includes(o)||t.push(o),t}var v=h(()=>{"use strict";R()});v();import{readFileSync as D,realpathSync as $}from"node:fs";import{resolve as u}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 k(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=k(i);e=`^${s}(\\s${c})?$`}else e=`^${k(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=u(n,".claude","settings.local.json"),i=C(r);i&&e.push(i);let s=u(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(u(t,".claude","settings.local.json"));s!==null&&o.push(s);let c=r(u(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=u(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 pe(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,pe 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,2 +1,2 @@
1
- function s(t){return t==null?"":String(t)}function y(t){return t==null?"":typeof t=="string"?t:JSON.stringify(t)}function d(t){let e=String(t.tool_response??""),n=t.tool_output?.isError===!0||t.tool_output?.is_error===!0;return t.tool_name==="Bash"&&/exit code [1-9]|error:|Error:|FAIL|failed/i.test(e)||n}function b(t){if(!t)return[];let e=[];for(let o of t.split(/\r?\n/)){if(o.startsWith("*** Add File: ")){e.push({path:o.slice(14).trim(),type:"file_write"});continue}if(o.startsWith("*** Update File: ")){e.push({path:o.slice(17).trim(),type:"file_edit"});continue}if(o.startsWith("*** Delete File: ")){e.push({path:o.slice(17).trim(),type:"file_edit"});continue}o.startsWith("*** Move to: ")&&e.push({path:o.slice(13).trim(),type:"file_edit"})}let n=new Set;return e.filter(o=>{if(!o.path)return!1;let r=`${o.type}:${o.path}`;return n.has(r)?!1:(n.add(r),!0)})}function h(t){return/(?:^|[/\\])\.claude[/\\]plans[/\\]/.test(t)}function E(t){let{tool_name:e,tool_input:n,tool_response:o}=t,r=[];if(e==="Read"){let i=String(n.file_path??"");return(/(?:CLAUDE|AGENTS(?:\.override)?|GEMINI|QWEN|KIRO)\.md$/i.test(i)||/\/copilot-instructions\.md$/i.test(i)||/\/context-mode\.mdc$/i.test(i)||/\.claude[\\/]/i.test(i)||/[\\/]memor(?:y|ies)[\\/][^\\/]+\.md$/i.test(i))&&(r.push({type:"rule",category:"rule",data:s(i),priority:1}),o&&o.length>0&&r.push({type:"rule_content",category:"rule",data:s(o),priority:1})),r.push({type:"file_read",category:"file",data:s(i),priority:1}),r}if(e==="Edit"){let i=String(n.file_path??"");return r.push({type:"file_edit",category:"file",data:s(i),priority:1}),r}if(e==="NotebookEdit"){let i=String(n.notebook_path??"");return r.push({type:"file_edit",category:"file",data:s(i),priority:1}),r}if(e==="Write"){let i=String(n.file_path??"");return r.push({type:"file_write",category:"file",data:s(i),priority:1}),r}if(e==="apply_patch"){if(d(t))return[];let i=b(String(n.command??n.patch??""));for(let a of i)r.push({type:a.type,category:"file",data:s(a.path),priority:1});return r}if(e==="Glob"){let i=String(n.pattern??"");return r.push({type:"file_glob",category:"file",data:s(i),priority:3}),r}if(e==="Grep"){let i=String(n.pattern??""),a=String(n.path??"");return r.push({type:"file_search",category:"file",data:s(`${i} in ${a}`),priority:3}),r}return r}function k(t){if(t.tool_name!=="Bash")return[];let n=String(t.tool_input.command??"").match(/\bcd\s+("([^"]+)"|'([^']+)'|(\S+))/);if(!n)return[];let o=n[2]??n[3]??n[4]??"";return[{type:"cwd",category:"cwd",data:s(o),priority:2}]}function v(t){let{tool_response:e}=t,n=String(e??"");return d(t)?[{type:"error_tool",category:"error",data:s(n),priority:2}]:[]}var A=[{pattern:/\bgit\s+checkout\b/,operation:"branch"},{pattern:/\bgit\s+commit\b/,operation:"commit"},{pattern:/\bgit\s+merge\s+\S+/,operation:"merge"},{pattern:/\bgit\s+rebase\b/,operation:"rebase"},{pattern:/\bgit\s+stash\b/,operation:"stash"},{pattern:/\bgit\s+push\b/,operation:"push"},{pattern:/\bgit\s+pull\b/,operation:"pull"},{pattern:/\bgit\s+log\b/,operation:"log"},{pattern:/\bgit\s+diff\b/,operation:"diff"},{pattern:/\bgit\s+status\b/,operation:"status"},{pattern:/\bgit\s+branch\b/,operation:"branch"},{pattern:/\bgit\s+reset\b/,operation:"reset"},{pattern:/\bgit\s+add\b/,operation:"add"},{pattern:/\bgit\s+cherry-pick\b/,operation:"cherry-pick"},{pattern:/\bgit\s+tag\b/,operation:"tag"},{pattern:/\bgit\s+fetch\b/,operation:"fetch"},{pattern:/\bgit\s+clone\b/,operation:"clone"},{pattern:/\bgit\s+worktree\b/,operation:"worktree"}];function R(t){if(t.tool_name!=="Bash")return[];let e=String(t.tool_input.command??""),n=A.find(o=>o.pattern.test(e));return n?[{type:"git",category:"git",data:s(n.operation),priority:2}]:[]}function T(t){return new Set(["TodoWrite","TaskCreate","TaskUpdate"]).has(t.tool_name)?[{type:t.tool_name==="TaskUpdate"?"task_update":t.tool_name==="TaskCreate"?"task_create":"task",category:"task",data:s(JSON.stringify(t.tool_input)),priority:1}]:[]}function x(t){if(t.tool_name==="EnterPlanMode")return[{type:"plan_enter",category:"plan",data:"entered plan mode",priority:2}];if(t.tool_name==="ExitPlanMode"){let e=[],n=t.tool_input.allowedPrompts,o=Array.isArray(n)&&n.length>0?`exited plan mode (allowed: ${y(n.map(i=>typeof i=="object"&&i!==null&&"prompt"in i?String(i.prompt):String(i)).join(", "))})`:"exited plan mode";e.push({type:"plan_exit",category:"plan",data:s(o),priority:2});let r=String(t.tool_response??"").toLowerCase();return r.includes("approved")||r.includes("approve")?e.push({type:"plan_approved",category:"plan",data:"plan approved by user",priority:1}):(r.includes("rejected")||r.includes("decline")||r.includes("denied"))&&e.push({type:"plan_rejected",category:"plan",data:s(`plan rejected: ${t.tool_response??""}`),priority:2}),e}if(t.tool_name==="Write"||t.tool_name==="Edit"){let e=String(t.tool_input.file_path??"");if(h(e))return[{type:"plan_file_write",category:"plan",data:s(`plan file: ${e.split(/[/\\]/).pop()??e}`),priority:2}]}return t.tool_name==="apply_patch"?d(t)?[]:b(String(t.tool_input.command??t.tool_input.patch??"")).filter(n=>h(n.path)).map(n=>({type:"plan_file_write",category:"plan",data:s(`plan file: ${n.path.split(/[/\\]/).pop()??n.path}`),priority:2})):[]}var I=[/\bsource\s+\S*activate\b/,/\bexport\s+\w+=/,/\bnvm\s+use\b/,/\bpyenv\s+(shell|local|global)\b/,/\bconda\s+activate\b/,/\brbenv\s+(shell|local|global)\b/,/\bnpm\s+install\b/,/\bnpm\s+ci\b/,/\bpip\s+install\b/,/\bbun\s+install\b/,/\byarn\s+(add|install)\b/,/\bpnpm\s+(add|install)\b/,/\bcargo\s+(install|add)\b/,/\bgo\s+(install|get)\b/,/\brustup\b/,/\basdf\b/,/\bvolta\b/,/\bdeno\s+install\b/];function w(t){if(t.tool_name!=="Bash")return[];let e=String(t.tool_input.command??"");if(!I.some(r=>r.test(e)))return[];let o=e.replace(/\bexport\s+(\w+)=\S*/g,"export $1=***");return[{type:"env",category:"env",data:s(o),priority:2}]}function N(t){if(t.tool_name!=="Skill")return[];let e=String(t.tool_input.skill??"");return[{type:"skill",category:"skill",data:s(e),priority:2}]}function C(t){if(!t.tool_response?.includes("Error")&&!t.tool_output?.isError)return[];let e=String(t.tool_response||""),n=[/not supported/i,/cannot/i,/does not support/i,/FAIL/i,/refused/i,/permission denied/i,/incompatible/i];for(let o of n){let r=e.match(o);if(r){let i=e.toLowerCase().indexOf(r[0].toLowerCase()),a=e.slice(Math.max(0,i-50),Math.min(e.length,i+200)).trim();return[{type:"constraint_discovered",category:"constraint",data:s(a),priority:2}]}}return[]}function H(t){if(t.tool_name!=="Agent")return[];let e=s(String(t.tool_input.prompt??t.tool_input.description??"")),n=t.tool_response?s(String(t.tool_response)):"",o=n.length>0;return[{type:o?"subagent_completed":"subagent_launched",category:"subagent",data:s(o?`[completed] ${e} \u2192 ${n}`:`[launched] ${e}`),priority:o?2:3}]}function L(t){let{tool_name:e,tool_input:n,tool_response:o}=t;if(!e.startsWith("mcp__"))return[];let r=e.split("__"),i=r[r.length-1]||e,a=Object.values(n).find(S=>typeof S=="string"),u=a?`: ${s(String(a))}`:"",c=o&&o.length>0?`
2
- response: ${s(o)}`:"";return[{type:"mcp",category:"mcp",data:s(`${i}${u}${c}`),priority:3}]}var $=2048;function P(t,e){if(Buffer.byteLength(t,"utf8")<=e)return{value:t,truncated:!1};let n=Buffer.from(t,"utf8"),o=e;for(;o>0&&(n[o]&192)===128;)o--;return{value:n.subarray(0,o).toString("utf8"),truncated:!0}}var O=/(authorization|auth_token|access_token|refresh_token|bearer|token|secret|password|passwd|pwd|api[-_]?key|apikey|cookie|set-cookie|signature|private[-_]?key|client[-_]?secret|x[-_]?api[-_]?key)/i,M="[REDACTED]";function g(t,e=new WeakSet){if(t==null||typeof t!="object")return t;if(e.has(t))return"[CIRCULAR]";e.add(t);let n;if(Array.isArray(t))n=t.map(o=>g(o,e));else{let o={};for(let[r,i]of Object.entries(t))O.test(r)?o[r]=M:o[r]=g(i,e);n=o}return e.delete(t),n}function B(t){let{tool_name:e,tool_input:n}=t;if(!e.startsWith("mcp__"))return[];let o=g(n??{}),r;try{r=JSON.stringify(o)}catch{r="{}"}let{value:i,truncated:a}=P(r,$),u=a?`{"tool_name":${JSON.stringify(e)},"params_raw":${JSON.stringify(i)},"truncated":true}`:`{"tool_name":${JSON.stringify(e)},"params":${i}}`;return[{type:"mcp_tool_call",category:"mcp_tool_call",data:s(u),priority:4}]}function W(t){if(t.tool_name!=="AskUserQuestion")return[];let e=t.tool_input.questions,n=Array.isArray(e)&&e.length>0?String(e[0].question??""):"",o=s(String(t.tool_response??"")),r=n?`Q: ${s(n)} \u2192 A: ${o}`:`answer: ${o}`;return[{type:"decision_question",category:"decision",data:s(r),priority:2}]}function F(t){if(t.tool_name!=="Agent")return[];if(!t.tool_response||t.tool_response.length===0)return[];let e=t.tool_response.length>500?t.tool_response.slice(0,500):t.tool_response;return[{type:"agent_finding",category:"agent-finding",data:s(e),priority:2}]}function j(t){let e=[y(t.tool_input),s(t.tool_response)].join(" ");if(e.length===0)return[];let n=new Set,o=e.match(/https?:\/\/[^\s)]+/g);if(o)for(let c of o)c=c.replace(/["'})\],;.]+$/,""),/localhost|127\.0\.0\.1/i.test(c)||n.add(c);let r=e.match(/(?<!\w)#(\d+)/g);if(r)for(let c of r)n.add(c);if(n.size===0)return[];let i,a=s(t.tool_response).match(/Fetched and indexed[^\(]*\(([\d.]+)\s*KB\)/i);if(a){let c=Number(a[1]);Number.isFinite(c)&&c>0&&(i=Math.round(c*1024))}let u={type:"external_ref",category:"external-ref",data:s(Array.from(n).join(", ")),priority:3};return i!==void 0&&(u.bytes_avoided=i),[u]}function D(t){if(t.tool_name!=="EnterWorktree")return[];let e=String(t.tool_input.name??"unnamed");return[{type:"worktree",category:"env",data:s(`entered worktree: ${e}`),priority:2}]}var m=/[,;,;、،]/u,U=15,K=500;function G(t){if(f.test(t)||!_.test(t)||!m.test(t))return!1;let e=[...t].length;return e>=U&&e<=K}function J(t){let e=t.trim();return G(e)?[{type:"decision",category:"decision",data:s(t),priority:2}]:[]}var q=8,z=120,Q=new RegExp("\\p{L}+\\s+\\p{L}+","u"),V=new RegExp("\\p{L}{6,}","u");function X(t){let e=t.split(/[.!\n。!]/u)[0].trim();if(f.test(e)||m.test(e)||!_.test(e))return!1;let n=[...e].length;return n<q||n>z?!1:Q.test(e)||V.test(e)}function Y(t){let e=t.trim();return X(e)?[{type:"role",category:"role",data:s(t),priority:3}]:[]}var f=/[??؟¿]/u,_=new RegExp("\\p{L}","u"),Z=60;function tt(t){if(f.test(t)||!_.test(t))return!1;let e=[...t].length;return e>0&&e<Z}function et(t){let e=t.trim();if(!e)return[];let n;return f.test(e)?n="investigate":tt(e)&&(n="implement"),n?[{type:"intent",category:"intent",data:s(n),priority:4}]:[]}var nt=/(?:\bError\s*:|\bException\s*:|\bTraceback\b|\bat\s+\S+\s*\([^)]*:\d+:\d+\))/u,ot=/[✓✔✅☑🎉]/u,rt=/^\s*(?:fixed|resolved)\s*:/iu;function it(t){let e=[];return ot.test(t)||rt.test(t)?(e.push({type:"blocker_resolved",category:"blocked-on",data:s(t),priority:2}),e):(nt.test(t)&&e.push({type:"blocker",category:"blocked-on",data:s(t),priority:2}),e)}function st(t){return t.length<=1024?[]:[{type:"data",category:"data",data:s(t),priority:4}]}var l=null;function at(t){let{tool_name:e,tool_response:n}=t,o=String(n??"");if(d(t))return l={tool:e,error:o.slice(0,200),callsSince:0},[];if(!l)return[];if(l.callsSince++,l.callsSince>10)return l=null,[];if(!!d(t))return[];let i=e===l.tool,a=l.tool==="Read"&&(e==="Edit"||e==="Write"||e==="apply_patch");if(i||a){let u={type:"error_resolved",category:"error-resolution",data:s(`Error in ${l.tool}: ${l.error} \u2192 Fixed`),priority:2};return l=null,[u]}return[]}function dt(){l=null}var p=[];function ct(t){return`${t.length}:${t.slice(0,20)}`}function lt(t){let{tool_name:e,tool_input:n}=t,o=ct(JSON.stringify(n).slice(0,200));if(p.push({tool:e,inputHash:o}),p.length>50&&p.splice(0,p.length-50),p.length<3)return[];let r=0;for(let i=p.length-1;i>=0&&(p[i].tool===e&&p[i].inputHash===o);i--)r++;return r>=3?(p.splice(p.length-r),[{type:"retry_detected",category:"iteration-loop",data:s(`${e} called ${r} times with similar input`),priority:2}]):[]}function ft(){p.length=0}var pt={run_shell_command:"Bash",read_file:"Read",read_many_files:"Read",grep_search:"Grep",search_file_content:"Grep",web_fetch:"WebFetch",write_file:"Write",edit:"Edit",glob:"Glob",todo_write:"TodoWrite",ask_user_question:"AskUserQuestion",list_directory:"LS",save_memory:"Memory",skill:"Skill",exit_plan_mode:"ExitPlanMode",agent:"Agent",bash:"Bash",view:"Read",grep:"Grep",fetch:"WebFetch",shell:"Bash",shell_command:"Bash",exec_command:"Bash","container.exec":"Bash",local_shell:"Bash",grep_files:"Grep"};function ut(t){let e=pt[t.tool_name];return!e||e===t.tool_name?t:{...t,tool_name:e}}function gt(t){try{let e=ut(t),n=[];return n.push(...E(e)),n.push(...k(e)),n.push(...v(e)),n.push(...R(e)),n.push(...w(e)),n.push(...T(e)),n.push(...x(e)),n.push(...N(e)),n.push(...H(e)),n.push(...L(e)),n.push(...B(e)),n.push(...W(e)),n.push(...C(e)),n.push(...D(e)),n.push(...F(e)),n.push(...j(e)),n.push(...at(e)),n.push(...lt(e)),n}catch{return[]}}function _t(t){try{let e=[];return e.push(...J(t)),e.push(...Y(t)),e.push(...et(t)),e.push(...it(t)),e.push(...st(t)),e}catch{return[]}}export{gt as extractEvents,_t as extractUserEvents,dt as resetErrorResolutionState,ft as resetIterationLoopState};
1
+ function i(t){return t==null?"":String(t)}function E(t){return t==null?"":typeof t=="string"?t:JSON.stringify(t)}function d(t){let e=String(t.tool_response??""),n=t.tool_output?.isError===!0||t.tool_output?.is_error===!0;return t.tool_name==="Bash"&&/exit code [1-9]|error:|Error:|FAIL|failed/i.test(e)||n}function k(t){if(!t)return[];let e=[];for(let r of t.split(/\r?\n/)){if(r.startsWith("*** Add File: ")){e.push({path:r.slice(14).trim(),type:"file_write"});continue}if(r.startsWith("*** Update File: ")){e.push({path:r.slice(17).trim(),type:"file_edit"});continue}if(r.startsWith("*** Delete File: ")){e.push({path:r.slice(17).trim(),type:"file_edit"});continue}r.startsWith("*** Move to: ")&&e.push({path:r.slice(13).trim(),type:"file_edit"})}let n=new Set;return e.filter(r=>{if(!r.path)return!1;let o=`${r.type}:${r.path}`;return n.has(o)?!1:(n.add(o),!0)})}function S(t){return/(?:^|[/\\])\.claude[/\\]plans[/\\]/.test(t)}function A(t){let{tool_name:e,tool_input:n,tool_response:r}=t,o=[];if(e==="Read"){let s=String(n.file_path??"");return(/(?:CLAUDE|AGENTS(?:\.override)?|GEMINI|QWEN|KIRO)\.md$/i.test(s)||/\/copilot-instructions\.md$/i.test(s)||/\/context-mode\.mdc$/i.test(s)||/\.claude[\\/]/i.test(s)||/[\\/]memor(?:y|ies)[\\/][^\\/]+\.md$/i.test(s))&&(o.push({type:"rule",category:"rule",data:i(s),priority:1}),r&&r.length>0&&o.push({type:"rule_content",category:"rule",data:i(r),priority:1})),o.push({type:"file_read",category:"file",data:i(s),priority:1}),o}if(e==="Edit"){let s=String(n.file_path??"");return o.push({type:"file_edit",category:"file",data:i(s),priority:1}),o}if(e==="NotebookEdit"){let s=String(n.notebook_path??"");return o.push({type:"file_edit",category:"file",data:i(s),priority:1}),o}if(e==="Write"){let s=String(n.file_path??"");return o.push({type:"file_write",category:"file",data:i(s),priority:1}),o}if(e==="apply_patch"){if(d(t))return[];let s=k(String(n.command??n.patch??""));for(let a of s)o.push({type:a.type,category:"file",data:i(a.path),priority:1});return o}if(e==="Glob"){let s=String(n.pattern??"");return o.push({type:"file_glob",category:"file",data:i(s),priority:3}),o}if(e==="Grep"){let s=String(n.pattern??""),a=String(n.path??"");return o.push({type:"file_search",category:"file",data:i(`${s} in ${a}`),priority:3}),o}return o}function R(t){if(t.tool_name!=="Bash")return[];let n=String(t.tool_input.command??"").match(/\bcd\s+("([^"]+)"|'([^']+)'|(\S+))/);if(!n)return[];let r=n[2]??n[3]??n[4]??"";return[{type:"cwd",category:"cwd",data:i(r),priority:2}]}function T(t){let{tool_response:e}=t,n=String(e??"");return d(t)?[{type:"error_tool",category:"error",data:i(n),priority:2}]:[]}var x=[{pattern:/\bgit\s+checkout\b/,operation:"branch"},{pattern:/\bgit\s+commit\b/,operation:"commit"},{pattern:/\bgit\s+merge\s+\S+/,operation:"merge"},{pattern:/\bgit\s+rebase\b/,operation:"rebase"},{pattern:/\bgit\s+stash\b/,operation:"stash"},{pattern:/\bgit\s+push\b/,operation:"push"},{pattern:/\bgit\s+pull\b/,operation:"pull"},{pattern:/\bgit\s+log\b/,operation:"log"},{pattern:/\bgit\s+diff\b/,operation:"diff"},{pattern:/\bgit\s+status\b/,operation:"status"},{pattern:/\bgit\s+branch\b/,operation:"branch"},{pattern:/\bgit\s+reset\b/,operation:"reset"},{pattern:/\bgit\s+add\b/,operation:"add"},{pattern:/\bgit\s+cherry-pick\b/,operation:"cherry-pick"},{pattern:/\bgit\s+tag\b/,operation:"tag"},{pattern:/\bgit\s+fetch\b/,operation:"fetch"},{pattern:/\bgit\s+clone\b/,operation:"clone"},{pattern:/\bgit\s+worktree\b/,operation:"worktree"}];function w(t){if(t.tool_name!=="Bash")return[];let e=String(t.tool_input.command??""),n=x.find(r=>r.pattern.test(e));return n?[{type:"git",category:"git",data:i(n.operation),priority:2}]:[]}function I(t){return new Set(["TodoWrite","TaskCreate","TaskUpdate"]).has(t.tool_name)?[{type:t.tool_name==="TaskUpdate"?"task_update":t.tool_name==="TaskCreate"?"task_create":"task",category:"task",data:i(JSON.stringify(t.tool_input)),priority:1}]:[]}function N(t){if(t.tool_name==="EnterPlanMode")return[{type:"plan_enter",category:"plan",data:"entered plan mode",priority:2}];if(t.tool_name==="ExitPlanMode"){let e=[],n=t.tool_input.allowedPrompts,r=Array.isArray(n)&&n.length>0?`exited plan mode (allowed: ${E(n.map(s=>typeof s=="object"&&s!==null&&"prompt"in s?String(s.prompt):String(s)).join(", "))})`:"exited plan mode";e.push({type:"plan_exit",category:"plan",data:i(r),priority:2});let o=String(t.tool_response??"").toLowerCase();return o.includes("approved")||o.includes("approve")?e.push({type:"plan_approved",category:"plan",data:"plan approved by user",priority:1}):(o.includes("rejected")||o.includes("decline")||o.includes("denied"))&&e.push({type:"plan_rejected",category:"plan",data:i(`plan rejected: ${t.tool_response??""}`),priority:2}),e}if(t.tool_name==="Write"||t.tool_name==="Edit"){let e=String(t.tool_input.file_path??"");if(S(e))return[{type:"plan_file_write",category:"plan",data:i(`plan file: ${e.split(/[/\\]/).pop()??e}`),priority:2}]}return t.tool_name==="apply_patch"?d(t)?[]:k(String(t.tool_input.command??t.tool_input.patch??"")).filter(n=>S(n.path)).map(n=>({type:"plan_file_write",category:"plan",data:i(`plan file: ${n.path.split(/[/\\]/).pop()??n.path}`),priority:2})):[]}var C=[/\bsource\s+\S*activate\b/,/\bexport\s+\w+=/,/\bnvm\s+use\b/,/\bpyenv\s+(shell|local|global)\b/,/\bconda\s+activate\b/,/\brbenv\s+(shell|local|global)\b/,/\bnpm\s+install\b/,/\bnpm\s+ci\b/,/\bpip\s+install\b/,/\bbun\s+install\b/,/\byarn\s+(add|install)\b/,/\bpnpm\s+(add|install)\b/,/\bcargo\s+(install|add)\b/,/\bgo\s+(install|get)\b/,/\brustup\b/,/\basdf\b/,/\bvolta\b/,/\bdeno\s+install\b/];function H(t){if(t.tool_name!=="Bash")return[];let e=String(t.tool_input.command??"");if(!C.some(o=>o.test(e)))return[];let r=e.replace(/\bexport\s+(\w+)=\S*/g,"export $1=***");return[{type:"env",category:"env",data:i(r),priority:2}]}function L(t){if(t.tool_name!=="Skill")return[];let e=String(t.tool_input.skill??"");return[{type:"skill",category:"skill",data:i(e),priority:2}]}function $(t){if(!t.tool_response?.includes("Error")&&!t.tool_output?.isError)return[];let e=String(t.tool_response||""),n=[/not supported/i,/cannot/i,/does not support/i,/FAIL/i,/refused/i,/permission denied/i,/incompatible/i];for(let r of n){let o=e.match(r);if(o){let s=e.toLowerCase().indexOf(o[0].toLowerCase()),a=e.slice(Math.max(0,s-50),Math.min(e.length,s+200)).trim();return[{type:"constraint_discovered",category:"constraint",data:i(a),priority:2}]}}return[]}function O(t){if(t.tool_name!=="Agent")return[];let e=i(String(t.tool_input.prompt??t.tool_input.description??"")),n=t.tool_response?i(String(t.tool_response)):"",r=n.length>0;return[{type:r?"subagent_completed":"subagent_launched",category:"subagent",data:i(r?`[completed] ${e} \u2192 ${n}`:`[launched] ${e}`),priority:r?2:3}]}function P(t){let{tool_name:e,tool_input:n,tool_response:r}=t;if(!e.startsWith("mcp__"))return[];let o=e.split("__"),s=o[o.length-1]||e,a=Object.values(n).find(g=>typeof g=="string"),u=a?`: ${i(String(a))}`:"",c=r&&r.length>0?`
2
+ response: ${i(r)}`:"";return[{type:"mcp",category:"mcp",data:i(`${s}${u}${c}`),priority:3}]}var M=2048;function B(t,e){if(Buffer.byteLength(t,"utf8")<=e)return{value:t,truncated:!1};let n=Buffer.from(t,"utf8"),r=e;for(;r>0&&(n[r]&192)===128;)r--;return{value:n.subarray(0,r).toString("utf8"),truncated:!0}}var W=/(authorization|auth_token|access_token|refresh_token|bearer|token|secret|password|passwd|pwd|api[-_]?key|apikey|cookie|set-cookie|signature|private[-_]?key|client[-_]?secret|x[-_]?api[-_]?key)/i,j="[REDACTED]";function y(t,e=new WeakSet){if(t==null||typeof t!="object")return t;if(e.has(t))return"[CIRCULAR]";e.add(t);let n;if(Array.isArray(t))n=t.map(r=>y(r,e));else{let r={};for(let[o,s]of Object.entries(t))W.test(o)?r[o]=j:r[o]=y(s,e);n=r}return e.delete(t),n}function F(t){let{tool_name:e,tool_input:n}=t;if(!e.startsWith("mcp__"))return[];let r=y(n??{}),o;try{o=JSON.stringify(r)}catch{o="{}"}let{value:s,truncated:a}=B(o,M),u=a?`{"tool_name":${JSON.stringify(e)},"params_raw":${JSON.stringify(s)},"truncated":true}`:`{"tool_name":${JSON.stringify(e)},"params":${s}}`;return[{type:"mcp_tool_call",category:"mcp_tool_call",data:i(u),priority:4}]}function D(t){if(t.tool_name!=="AskUserQuestion")return[];let e=t.tool_input.questions,n=Array.isArray(e)&&e.length>0?String(e[0].question??""):"",r=String(t.tool_response??""),o="";try{let c=JSON.parse(r)?.answers;if(c&&typeof c=="object"){let g=f=>typeof f=="string"?f:Array.isArray(f)?f.filter(h=>typeof h=="string").join(" | "):"",m=n?g(c[n]):"";m?o=m:o=Object.values(c).map(g).filter(h=>h.length>0).join(" | ")}}catch{}let s=i(o),a=n?`Q: ${i(n)} \u2192 A: ${s}`:`answer: ${s}`;return[{type:"decision_question",category:"decision",data:i(a),priority:2}]}function U(t){if(t.tool_name!=="Agent")return[];if(!t.tool_response||t.tool_response.length===0)return[];let e=t.tool_response.length>500?t.tool_response.slice(0,500):t.tool_response;return[{type:"agent_finding",category:"agent-finding",data:i(e),priority:2}]}function K(t){let e=[E(t.tool_input),i(t.tool_response)].join(" ");if(e.length===0)return[];let n=new Set,r=e.match(/https?:\/\/[^\s)]+/g);if(r)for(let c of r)c=c.replace(/["'})\],;.]+$/,""),/localhost|127\.0\.0\.1/i.test(c)||n.add(c);let o=e.match(/(?<!\w)#(\d+)/g);if(o)for(let c of o)n.add(c);if(n.size===0)return[];let s,a=i(t.tool_response).match(/Fetched and indexed[^\(]*\(([\d.]+)\s*KB\)/i);if(a){let c=Number(a[1]);Number.isFinite(c)&&c>0&&(s=Math.round(c*1024))}let u={type:"external_ref",category:"external-ref",data:i(Array.from(n).join(", ")),priority:3};return s!==void 0&&(u.bytes_avoided=s),[u]}function G(t){if(t.tool_name!=="EnterWorktree")return[];let e=String(t.tool_input.name??"unnamed");return[{type:"worktree",category:"env",data:i(`entered worktree: ${e}`),priority:2}]}var v=/[,;,;、،]/u,J=15,q=500;function z(t){if(_.test(t)||!b.test(t)||!v.test(t))return!1;let e=[...t].length;return e>=J&&e<=q}function Q(t){let e=t.trim();return z(e)?[{type:"decision",category:"decision",data:i(t),priority:2}]:[]}var V=8,X=120,Y=new RegExp("\\p{L}+\\s+\\p{L}+","u"),Z=new RegExp("\\p{L}{6,}","u");function tt(t){let e=t.split(/[.!\n。!]/u)[0].trim();if(_.test(e)||v.test(e)||!b.test(e))return!1;let n=[...e].length;return n<V||n>X?!1:Y.test(e)||Z.test(e)}function et(t){let e=t.trim();return tt(e)?[{type:"role",category:"role",data:i(t),priority:3}]:[]}var _=/[??؟¿]/u,b=new RegExp("\\p{L}","u"),nt=60;function rt(t){if(_.test(t)||!b.test(t))return!1;let e=[...t].length;return e>0&&e<nt}function ot(t){let e=t.trim();if(!e)return[];let n;return _.test(e)?n="investigate":rt(e)&&(n="implement"),n?[{type:"intent",category:"intent",data:i(n),priority:4}]:[]}var st=/(?:\bError\s*:|\bException\s*:|\bTraceback\b|\bat\s+\S+\s*\([^)]*:\d+:\d+\))/u,it=/[✓✔✅☑🎉]/u,at=/^\s*(?:fixed|resolved)\s*:/iu;function ct(t){let e=[];return it.test(t)||at.test(t)?(e.push({type:"blocker_resolved",category:"blocked-on",data:i(t),priority:2}),e):(st.test(t)&&e.push({type:"blocker",category:"blocked-on",data:i(t),priority:2}),e)}function lt(t){return t.length<=1024?[]:[{type:"data",category:"data",data:i(t),priority:4}]}var l=null;function pt(t){let{tool_name:e,tool_response:n}=t,r=String(n??"");if(d(t))return l={tool:e,error:r.slice(0,200),callsSince:0},[];if(!l)return[];if(l.callsSince++,l.callsSince>10)return l=null,[];if(!!d(t))return[];let s=e===l.tool,a=l.tool==="Read"&&(e==="Edit"||e==="Write"||e==="apply_patch");if(s||a){let u={type:"error_resolved",category:"error-resolution",data:i(`Error in ${l.tool}: ${l.error} \u2192 Fixed`),priority:2};return l=null,[u]}return[]}function _t(){l=null}var p=[];function ut(t){return`${t.length}:${t.slice(0,20)}`}function ft(t){let{tool_name:e,tool_input:n}=t,r=ut(JSON.stringify(n).slice(0,200));if(p.push({tool:e,inputHash:r}),p.length>50&&p.splice(0,p.length-50),p.length<3)return[];let o=0;for(let s=p.length-1;s>=0&&(p[s].tool===e&&p[s].inputHash===r);s--)o++;return o>=3?(p.splice(p.length-o),[{type:"retry_detected",category:"iteration-loop",data:i(`${e} called ${o} times with similar input`),priority:2}]):[]}function ht(){p.length=0}var dt={run_shell_command:"Bash",read_file:"Read",read_many_files:"Read",grep_search:"Grep",search_file_content:"Grep",web_fetch:"WebFetch",write_file:"Write",edit:"Edit",glob:"Glob",todo_write:"TodoWrite",ask_user_question:"AskUserQuestion",list_directory:"LS",save_memory:"Memory",skill:"Skill",exit_plan_mode:"ExitPlanMode",agent:"Agent",bash:"Bash",view:"Read",grep:"Grep",fetch:"WebFetch",shell:"Bash",shell_command:"Bash",exec_command:"Bash","container.exec":"Bash",local_shell:"Bash",grep_files:"Grep"};function gt(t){let e=dt[t.tool_name];return!e||e===t.tool_name?t:{...t,tool_name:e}}function yt(t){try{let e=gt(t),n=[];return n.push(...A(e)),n.push(...R(e)),n.push(...T(e)),n.push(...w(e)),n.push(...H(e)),n.push(...I(e)),n.push(...N(e)),n.push(...L(e)),n.push(...O(e)),n.push(...P(e)),n.push(...F(e)),n.push(...D(e)),n.push(...$(e)),n.push(...G(e)),n.push(...U(e)),n.push(...K(e)),n.push(...pt(e)),n.push(...ft(e)),n}catch{return[]}}function bt(t){try{let e=[];return e.push(...Q(t)),e.push(...et(t)),e.push(...ot(t)),e.push(...ct(t)),e.push(...lt(t)),e}catch{return[]}}export{yt as extractEvents,bt as extractUserEvents,_t as resetErrorResolutionState,ht as resetIterationLoopState};
@@ -3,7 +3,7 @@
3
3
  "name": "Context Mode",
4
4
  "kind": "tool",
5
5
  "description": "OpenClaw plugin that saves 98% of your context window. Sandboxed code execution in 11 languages, FTS5 knowledge base with BM25 ranking, and intent-driven search.",
6
- "version": "1.0.134",
6
+ "version": "1.0.136",
7
7
  "sandbox": {
8
8
  "mode": "permissive",
9
9
  "filesystem_access": "full",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "context-mode",
3
- "version": "1.0.134",
3
+ "version": "1.0.136",
4
4
  "type": "module",
5
5
  "description": "MCP plugin that saves 98% of your context window. Works with Claude Code, Gemini CLI, VS Code Copilot, OpenCode, and Codex CLI. Sandboxed code execution, FTS5 knowledge base, and intent-driven search.",
6
6
  "author": "Mert Koseoğlu",
@@ -73,6 +73,7 @@
73
73
  "bin",
74
74
  "skills",
75
75
  ".claude-plugin",
76
+ ".codex-plugin",
76
77
  ".openclaw-plugin",
77
78
  "openclaw.plugin.json",
78
79
  "start.mjs",