context-mode 1.0.110 → 1.0.112
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +2 -2
- package/.claude-plugin/plugin.json +1 -1
- package/.openclaw-plugin/index.ts +3 -2
- package/.openclaw-plugin/openclaw.plugin.json +1 -1
- package/.openclaw-plugin/package.json +1 -1
- package/README.md +152 -34
- package/bin/statusline.mjs +144 -127
- package/build/adapters/base.d.ts +8 -5
- package/build/adapters/base.js +8 -18
- package/build/adapters/claude-code/index.d.ts +24 -3
- package/build/adapters/claude-code/index.js +44 -11
- package/build/adapters/codex/hooks.d.ts +10 -5
- package/build/adapters/codex/hooks.js +10 -5
- package/build/adapters/codex/index.d.ts +17 -5
- package/build/adapters/codex/index.js +337 -37
- package/build/adapters/codex/paths.d.ts +1 -0
- package/build/adapters/codex/paths.js +12 -0
- package/build/adapters/cursor/index.d.ts +6 -0
- package/build/adapters/cursor/index.js +83 -2
- package/build/adapters/detect.d.ts +1 -1
- package/build/adapters/detect.js +29 -6
- package/build/adapters/omp/index.d.ts +65 -0
- package/build/adapters/omp/index.js +182 -0
- package/build/adapters/omp/plugin.d.ts +75 -0
- package/build/adapters/omp/plugin.js +220 -0
- package/build/adapters/openclaw/mcp-tools.d.ts +54 -0
- package/build/adapters/openclaw/mcp-tools.js +198 -0
- package/build/adapters/openclaw/plugin.d.ts +130 -0
- package/build/adapters/openclaw/plugin.js +629 -0
- package/build/adapters/openclaw/workspace-router.d.ts +29 -0
- package/build/adapters/openclaw/workspace-router.js +64 -0
- package/build/adapters/opencode/plugin.d.ts +145 -0
- package/build/adapters/opencode/plugin.js +457 -0
- package/build/adapters/pi/extension.d.ts +26 -0
- package/build/adapters/pi/extension.js +552 -0
- package/build/adapters/pi/index.d.ts +57 -0
- package/build/adapters/pi/index.js +173 -0
- package/build/adapters/pi/mcp-bridge.d.ts +113 -0
- package/build/adapters/pi/mcp-bridge.js +251 -0
- package/build/adapters/types.d.ts +11 -6
- package/build/cli.js +186 -170
- package/build/db-base.d.ts +15 -2
- package/build/db-base.js +50 -5
- package/build/executor.d.ts +2 -0
- package/build/executor.js +15 -2
- package/build/opencode-plugin.js +1 -1
- package/build/runPool.d.ts +36 -0
- package/build/runPool.js +51 -0
- package/build/runtime.js +64 -5
- package/build/search/auto-memory.js +6 -4
- package/build/security.js +30 -10
- package/build/server.d.ts +23 -1
- package/build/server.js +652 -174
- package/build/session/analytics.d.ts +404 -1
- package/build/session/analytics.js +1347 -42
- package/build/session/db.d.ts +114 -5
- package/build/session/db.js +275 -27
- package/build/session/event-emit.d.ts +48 -0
- package/build/session/event-emit.js +101 -0
- package/build/session/extract.d.ts +1 -0
- package/build/session/extract.js +79 -12
- package/build/session/purge.d.ts +111 -0
- package/build/session/purge.js +138 -0
- package/build/store.d.ts +7 -0
- package/build/store.js +69 -6
- package/build/util/claude-config.d.ts +26 -0
- package/build/util/claude-config.js +91 -0
- package/build/util/hook-config.d.ts +4 -0
- package/build/util/hook-config.js +39 -0
- package/cli.bundle.mjs +411 -208
- package/configs/antigravity/GEMINI.md +0 -3
- package/configs/claude-code/CLAUDE.md +1 -4
- package/configs/codex/AGENTS.md +1 -4
- package/configs/codex/config.toml +3 -0
- package/configs/codex/hooks.json +8 -0
- package/configs/cursor/context-mode.mdc +0 -3
- package/configs/gemini-cli/GEMINI.md +0 -3
- package/configs/jetbrains-copilot/copilot-instructions.md +0 -3
- package/configs/kilo/AGENTS.md +0 -3
- package/configs/kiro/KIRO.md +0 -3
- package/configs/omp/SYSTEM.md +85 -0
- package/configs/omp/mcp.json +7 -0
- package/configs/openclaw/AGENTS.md +0 -3
- package/configs/opencode/AGENTS.md +0 -3
- package/configs/pi/AGENTS.md +0 -3
- package/configs/qwen-code/QWEN.md +1 -4
- package/configs/vscode-copilot/copilot-instructions.md +0 -3
- package/configs/zed/AGENTS.md +0 -3
- package/hooks/codex/posttooluse.mjs +9 -2
- package/hooks/codex/precompact.mjs +69 -0
- package/hooks/codex/sessionstart.mjs +13 -9
- package/hooks/codex/stop.mjs +1 -2
- package/hooks/codex/userpromptsubmit.mjs +1 -2
- package/hooks/core/routing.mjs +237 -18
- package/hooks/cursor/afteragentresponse.mjs +1 -1
- package/hooks/cursor/hooks.json +31 -0
- package/hooks/cursor/posttooluse.mjs +1 -1
- package/hooks/cursor/sessionstart.mjs +5 -5
- package/hooks/cursor/stop.mjs +1 -1
- package/hooks/ensure-deps.mjs +12 -13
- package/hooks/gemini-cli/aftertool.mjs +1 -1
- package/hooks/gemini-cli/beforeagent.mjs +1 -1
- package/hooks/gemini-cli/precompress.mjs +3 -2
- package/hooks/gemini-cli/sessionstart.mjs +9 -9
- package/hooks/jetbrains-copilot/posttooluse.mjs +1 -1
- package/hooks/jetbrains-copilot/precompact.mjs +3 -2
- package/hooks/jetbrains-copilot/sessionstart.mjs +9 -9
- package/hooks/kiro/agentspawn.mjs +5 -5
- package/hooks/kiro/posttooluse.mjs +2 -2
- package/hooks/kiro/userpromptsubmit.mjs +1 -1
- package/hooks/posttooluse.mjs +45 -0
- package/hooks/precompact.mjs +17 -0
- package/hooks/pretooluse.mjs +23 -0
- package/hooks/routing-block.mjs +0 -12
- package/hooks/run-hook.mjs +16 -3
- package/hooks/session-db.bundle.mjs +27 -18
- package/hooks/session-extract.bundle.mjs +2 -2
- package/hooks/session-helpers.mjs +101 -64
- package/hooks/sessionstart.mjs +51 -2
- package/hooks/vscode-copilot/posttooluse.mjs +1 -1
- package/hooks/vscode-copilot/precompact.mjs +3 -2
- package/hooks/vscode-copilot/sessionstart.mjs +9 -9
- package/openclaw.plugin.json +1 -1
- package/package.json +14 -8
- package/server.bundle.mjs +349 -147
- package/skills/UPSTREAM-CREDITS.md +0 -51
- package/skills/context-mode-ops/SKILL.md +0 -299
- package/skills/context-mode-ops/agent-teams.md +0 -198
- package/skills/context-mode-ops/communication.md +0 -224
- package/skills/context-mode-ops/marketing.md +0 -124
- package/skills/context-mode-ops/release.md +0 -214
- package/skills/context-mode-ops/review-pr.md +0 -269
- package/skills/context-mode-ops/tdd.md +0 -329
- package/skills/context-mode-ops/triage-issue.md +0 -266
- package/skills/context-mode-ops/validation.md +0 -307
- package/skills/diagnose/SKILL.md +0 -122
- package/skills/diagnose/scripts/hitl-loop.template.sh +0 -41
- package/skills/grill-me/SKILL.md +0 -15
- package/skills/grill-with-docs/ADR-FORMAT.md +0 -47
- package/skills/grill-with-docs/CONTEXT-FORMAT.md +0 -77
- package/skills/grill-with-docs/SKILL.md +0 -93
- package/skills/improve-codebase-architecture/DEEPENING.md +0 -37
- package/skills/improve-codebase-architecture/INTERFACE-DESIGN.md +0 -44
- package/skills/improve-codebase-architecture/LANGUAGE.md +0 -53
- package/skills/improve-codebase-architecture/SKILL.md +0 -76
- package/skills/tdd/SKILL.md +0 -114
- package/skills/tdd/deep-modules.md +0 -33
- package/skills/tdd/interface-design.md +0 -31
- package/skills/tdd/mocking.md +0 -59
- package/skills/tdd/refactoring.md +0 -10
- package/skills/tdd/tests.md +0 -61
|
@@ -20,7 +20,7 @@ const ROUTING_BLOCK = createRoutingBlock(toolNamer);
|
|
|
20
20
|
import { writeSessionEventsFile, buildSessionDirective, getSessionEvents } from "../session-directive.mjs";
|
|
21
21
|
import {
|
|
22
22
|
readStdin, parseStdin, getSessionId, getSessionDBPath, getSessionEventsPath, getCleanupFlagPath,
|
|
23
|
-
|
|
23
|
+
getInputProjectDir, JETBRAINS_OPTS,
|
|
24
24
|
} from "../session-helpers.mjs";
|
|
25
25
|
import { join } from "node:path";
|
|
26
26
|
import { readFileSync, unlinkSync } from "node:fs";
|
|
@@ -37,10 +37,11 @@ try {
|
|
|
37
37
|
const raw = await readStdin();
|
|
38
38
|
const input = parseStdin(raw);
|
|
39
39
|
const source = input.source ?? "startup";
|
|
40
|
+
const projectDir = getInputProjectDir(input, OPTS);
|
|
40
41
|
|
|
41
42
|
if (source === "compact") {
|
|
42
43
|
const { SessionDB } = await loadSessionDB();
|
|
43
|
-
const dbPath = getSessionDBPath(OPTS);
|
|
44
|
+
const dbPath = getSessionDBPath(OPTS, projectDir);
|
|
44
45
|
const db = new SessionDB({ dbPath });
|
|
45
46
|
const sessionId = getSessionId(input, OPTS);
|
|
46
47
|
const resume = db.getResume(sessionId);
|
|
@@ -51,16 +52,16 @@ try {
|
|
|
51
52
|
|
|
52
53
|
const events = getSessionEvents(db, sessionId);
|
|
53
54
|
if (events.length > 0) {
|
|
54
|
-
const eventMeta = writeSessionEventsFile(events, getSessionEventsPath(OPTS));
|
|
55
|
+
const eventMeta = writeSessionEventsFile(events, getSessionEventsPath(OPTS, projectDir));
|
|
55
56
|
additionalContext += buildSessionDirective("compact", eventMeta, toolNamer);
|
|
56
57
|
}
|
|
57
58
|
|
|
58
59
|
db.close();
|
|
59
60
|
} else if (source === "resume") {
|
|
60
|
-
try { unlinkSync(getCleanupFlagPath(OPTS)); } catch { /* no flag */ }
|
|
61
|
+
try { unlinkSync(getCleanupFlagPath(OPTS, projectDir)); } catch { /* no flag */ }
|
|
61
62
|
|
|
62
63
|
const { SessionDB } = await loadSessionDB();
|
|
63
|
-
const dbPath = getSessionDBPath(OPTS);
|
|
64
|
+
const dbPath = getSessionDBPath(OPTS, projectDir);
|
|
64
65
|
const db = new SessionDB({ dbPath });
|
|
65
66
|
|
|
66
67
|
// Filter events to the session being resumed. Falling back to
|
|
@@ -70,22 +71,21 @@ try {
|
|
|
70
71
|
const sessionId = getSessionId(input, OPTS);
|
|
71
72
|
const events = sessionId ? getSessionEvents(db, sessionId) : [];
|
|
72
73
|
if (events.length > 0) {
|
|
73
|
-
const eventMeta = writeSessionEventsFile(events, getSessionEventsPath(OPTS));
|
|
74
|
+
const eventMeta = writeSessionEventsFile(events, getSessionEventsPath(OPTS, projectDir));
|
|
74
75
|
additionalContext += buildSessionDirective("resume", eventMeta, toolNamer);
|
|
75
76
|
}
|
|
76
77
|
|
|
77
78
|
db.close();
|
|
78
79
|
} else if (source === "startup") {
|
|
79
80
|
const { SessionDB } = await loadSessionDB();
|
|
80
|
-
const dbPath = getSessionDBPath(OPTS);
|
|
81
|
+
const dbPath = getSessionDBPath(OPTS, projectDir);
|
|
81
82
|
const db = new SessionDB({ dbPath });
|
|
82
|
-
try { unlinkSync(getSessionEventsPath(OPTS)); } catch { /* no stale file */ }
|
|
83
|
+
try { unlinkSync(getSessionEventsPath(OPTS, projectDir)); } catch { /* no stale file */ }
|
|
83
84
|
|
|
84
85
|
db.cleanupOldSessions(7);
|
|
85
86
|
db.db.exec(`DELETE FROM session_events WHERE session_id NOT IN (SELECT session_id FROM session_meta)`);
|
|
86
87
|
|
|
87
88
|
const sessionId = getSessionId(input, OPTS);
|
|
88
|
-
const projectDir = getProjectDir(OPTS);
|
|
89
89
|
db.ensureSession(sessionId, projectDir);
|
|
90
90
|
|
|
91
91
|
const ruleFilePaths = [
|
|
@@ -51,7 +51,7 @@ try {
|
|
|
51
51
|
|
|
52
52
|
if (source === "compact" || source === "resume") {
|
|
53
53
|
const { SessionDB } = await loadSessionDB();
|
|
54
|
-
const dbPath = getSessionDBPath(OPTS);
|
|
54
|
+
const dbPath = getSessionDBPath(OPTS, projectDir);
|
|
55
55
|
const db = new SessionDB({ dbPath });
|
|
56
56
|
|
|
57
57
|
if (source === "compact") {
|
|
@@ -61,22 +61,22 @@ try {
|
|
|
61
61
|
db.markResumeConsumed(sessionId);
|
|
62
62
|
}
|
|
63
63
|
} else {
|
|
64
|
-
try { unlinkSync(getCleanupFlagPath(OPTS)); } catch { /* no flag */ }
|
|
64
|
+
try { unlinkSync(getCleanupFlagPath(OPTS, projectDir)); } catch { /* no flag */ }
|
|
65
65
|
}
|
|
66
66
|
|
|
67
67
|
const sessionId = getSessionId(input, OPTS);
|
|
68
68
|
const events = sessionId ? getSessionEvents(db, sessionId) : [];
|
|
69
69
|
if (events.length > 0) {
|
|
70
|
-
const eventMeta = writeSessionEventsFile(events, getSessionEventsPath(OPTS));
|
|
70
|
+
const eventMeta = writeSessionEventsFile(events, getSessionEventsPath(OPTS, projectDir));
|
|
71
71
|
additionalContext += buildSessionDirective(source, eventMeta, toolNamer);
|
|
72
72
|
}
|
|
73
73
|
|
|
74
74
|
db.close();
|
|
75
75
|
} else if (source === "startup") {
|
|
76
76
|
const { SessionDB } = await loadSessionDB();
|
|
77
|
-
const dbPath = getSessionDBPath(OPTS);
|
|
77
|
+
const dbPath = getSessionDBPath(OPTS, projectDir);
|
|
78
78
|
const db = new SessionDB({ dbPath });
|
|
79
|
-
try { unlinkSync(getSessionEventsPath(OPTS)); } catch { /* no stale file */ }
|
|
79
|
+
try { unlinkSync(getSessionEventsPath(OPTS, projectDir)); } catch { /* no stale file */ }
|
|
80
80
|
|
|
81
81
|
db.cleanupOldSessions(7);
|
|
82
82
|
db.db.exec(`DELETE FROM session_events WHERE session_id NOT IN (SELECT session_id FROM session_meta)`);
|
|
@@ -25,10 +25,10 @@ try {
|
|
|
25
25
|
const { resolveProjectAttributions } = await loadProjectAttribution();
|
|
26
26
|
const { SessionDB } = await loadSessionDB();
|
|
27
27
|
|
|
28
|
-
const dbPath = getSessionDBPath(OPTS);
|
|
29
|
-
const db = new SessionDB({ dbPath });
|
|
30
28
|
const sessionId = getSessionId(input, OPTS);
|
|
31
29
|
const projectDir = getInputProjectDir(input, OPTS);
|
|
30
|
+
const dbPath = getSessionDBPath(OPTS, projectDir);
|
|
31
|
+
const db = new SessionDB({ dbPath });
|
|
32
32
|
|
|
33
33
|
db.ensureSession(sessionId, projectDir);
|
|
34
34
|
|
|
@@ -43,7 +43,7 @@ try {
|
|
|
43
43
|
const { SessionDB } = await loadSessionDB();
|
|
44
44
|
const { extractUserEvents } = await loadExtract();
|
|
45
45
|
const { resolveProjectAttributions } = await loadProjectAttribution();
|
|
46
|
-
const dbPath = getSessionDBPath(OPTS);
|
|
46
|
+
const dbPath = getSessionDBPath(OPTS, projectDir);
|
|
47
47
|
const db = new SessionDB({ dbPath });
|
|
48
48
|
const sessionId = getSessionId(input, OPTS);
|
|
49
49
|
|
package/hooks/posttooluse.mjs
CHANGED
|
@@ -80,6 +80,51 @@ await runHook(async () => {
|
|
|
80
80
|
}
|
|
81
81
|
} catch { /* best-effort */ }
|
|
82
82
|
|
|
83
|
+
// ─── D2 PRD Phase 3/4: redirect marker — emit byte-accounting event ───
|
|
84
|
+
// PreToolUse wrote `context-mode-redirect-${sessionId}.txt` for tools whose
|
|
85
|
+
// output we kept out of the model's context window (curl/wget, WebFetch,
|
|
86
|
+
// large Read). Format: `tool:type:bytesAvoided:commandSummary` (Override C).
|
|
87
|
+
try {
|
|
88
|
+
const redirectPath = resolve(tmpdir(), `context-mode-redirect-${sessionId}.txt`);
|
|
89
|
+
let redirectData;
|
|
90
|
+
try {
|
|
91
|
+
redirectData = readFileSync(redirectPath, "utf-8").trim();
|
|
92
|
+
// Slice 3.3: unlink so the next PostToolUse for an unrelated tool call
|
|
93
|
+
// does NOT re-emit the same event (no double-accounting).
|
|
94
|
+
unlinkSync(redirectPath);
|
|
95
|
+
} catch { /* no marker — Slice 3.4: phantom-event guard */ }
|
|
96
|
+
|
|
97
|
+
if (redirectData) {
|
|
98
|
+
// Parse first 3 colons; the rest (commandSummary) may itself contain
|
|
99
|
+
// colons (URLs do — `https://`). Avoid `split(":", 4)` which would
|
|
100
|
+
// truncate the summary at any embedded colon.
|
|
101
|
+
const i1 = redirectData.indexOf(":");
|
|
102
|
+
const i2 = i1 >= 0 ? redirectData.indexOf(":", i1 + 1) : -1;
|
|
103
|
+
const i3 = i2 >= 0 ? redirectData.indexOf(":", i2 + 1) : -1;
|
|
104
|
+
if (i1 > 0 && i2 > i1 && i3 > i2) {
|
|
105
|
+
const tool = redirectData.slice(0, i1);
|
|
106
|
+
const type = redirectData.slice(i1 + 1, i2);
|
|
107
|
+
const bytesRaw = redirectData.slice(i2 + 1, i3);
|
|
108
|
+
const summary = redirectData.slice(i3 + 1);
|
|
109
|
+
const bytesAvoided = Number.parseInt(bytesRaw, 10);
|
|
110
|
+
if (Number.isFinite(bytesAvoided) && bytesAvoided > 0) {
|
|
111
|
+
db.insertEvent(
|
|
112
|
+
sessionId,
|
|
113
|
+
{
|
|
114
|
+
type,
|
|
115
|
+
category: "redirect",
|
|
116
|
+
data: `${tool}: ${summary}`,
|
|
117
|
+
priority: 2,
|
|
118
|
+
},
|
|
119
|
+
"PreToolUse",
|
|
120
|
+
undefined,
|
|
121
|
+
{ bytesAvoided, bytesReturned: 0 },
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
} catch { /* best-effort — never block hook */ }
|
|
127
|
+
|
|
83
128
|
// ─── Category 27: Latency — read cross-hook marker and emit event if slow ───
|
|
84
129
|
try {
|
|
85
130
|
const toolName = input.tool_name ?? "";
|
package/hooks/precompact.mjs
CHANGED
|
@@ -60,6 +60,23 @@ await runHook(async () => {
|
|
|
60
60
|
data: `Session compacted. ${events.length} events, ${fileEvents.length} files touched.`,
|
|
61
61
|
priority: 1,
|
|
62
62
|
}, "PreCompact");
|
|
63
|
+
|
|
64
|
+
// D2 PRD Phase 6.1: emit snapshot-built event with bytes_avoided=snapshot.length
|
|
65
|
+
// Snapshot bytes are bytes the model would have re-read on resume but didn't.
|
|
66
|
+
try {
|
|
67
|
+
db.insertEvent(
|
|
68
|
+
sessionId,
|
|
69
|
+
{
|
|
70
|
+
type: "snapshot-built",
|
|
71
|
+
category: "compaction",
|
|
72
|
+
data: `Snapshot built. ${snapshot.length} bytes for ${events.length} events.`,
|
|
73
|
+
priority: 1,
|
|
74
|
+
},
|
|
75
|
+
"PreCompact",
|
|
76
|
+
undefined,
|
|
77
|
+
{ bytesAvoided: snapshot.length, bytesReturned: 0 },
|
|
78
|
+
);
|
|
79
|
+
} catch { /* best-effort */ }
|
|
63
80
|
}
|
|
64
81
|
|
|
65
82
|
db.close();
|
package/hooks/pretooluse.mjs
CHANGED
|
@@ -185,6 +185,29 @@ await runHook(async () => {
|
|
|
185
185
|
} catch { /* best-effort — never block hook */ }
|
|
186
186
|
}
|
|
187
187
|
|
|
188
|
+
// ─── D2 PRD Phase 3/4: redirect marker for byte-accounting events ───
|
|
189
|
+
// routing.mjs attaches `redirectMeta` to decisions for tools whose output we
|
|
190
|
+
// kept out of the model's context window (curl/wget, WebFetch, large Read).
|
|
191
|
+
// PostToolUse reads this marker to emit a `category=redirect` event with the
|
|
192
|
+
// estimated `bytes_avoided`. PreToolUse cannot load SessionDB safely (native
|
|
193
|
+
// module load breaks hook stdout), hence the marker indirection.
|
|
194
|
+
if (decision && decision.redirectMeta) {
|
|
195
|
+
try {
|
|
196
|
+
const sessionId = getSessionId(input);
|
|
197
|
+
const meta = decision.redirectMeta;
|
|
198
|
+
const summary = String(meta.commandSummary ?? "").slice(0, 200);
|
|
199
|
+
const markerPath = resolve(tmpdir(), `context-mode-redirect-${sessionId}.txt`);
|
|
200
|
+
// Format: tool:type:bytesAvoided:commandSummary (matches Override C).
|
|
201
|
+
// commandSummary may legitimately contain `:` (URLs) — don't quote it,
|
|
202
|
+
// PostToolUse parses only the first 3 colons and treats the rest as data.
|
|
203
|
+
writeFileSync(
|
|
204
|
+
markerPath,
|
|
205
|
+
`${meta.tool}:${meta.type}:${meta.bytesAvoided}:${summary}`,
|
|
206
|
+
"utf-8",
|
|
207
|
+
);
|
|
208
|
+
} catch { /* best-effort — never block hook */ }
|
|
209
|
+
}
|
|
210
|
+
|
|
188
211
|
// ─── stdout write is the LAST action — process exits immediately after ───
|
|
189
212
|
if (response !== null) {
|
|
190
213
|
process.stdout.write(JSON.stringify(response) + "\n");
|
package/hooks/routing-block.mjs
CHANGED
|
@@ -50,22 +50,10 @@ export function createRoutingBlock(t, options = {}) {
|
|
|
50
50
|
</file_writing_policy>
|
|
51
51
|
|
|
52
52
|
<output_constraints>
|
|
53
|
-
<communication_style>
|
|
54
|
-
Terse like caveman. Technical substance exact. Only fluff die.
|
|
55
|
-
Use fragments when clear. Short synonyms (fix not "implement a solution for").
|
|
56
|
-
Technical terms exact. Code blocks unchanged.
|
|
57
|
-
Auto-expand for: security warnings, irreversible actions, user confusion.
|
|
58
|
-
</communication_style>
|
|
59
53
|
<artifact_policy>
|
|
60
54
|
Write artifacts (code, configs, PRDs) to FILES. NEVER inline.
|
|
61
55
|
Return only: file path + 1-line description.
|
|
62
56
|
</artifact_policy>
|
|
63
|
-
<response_format>
|
|
64
|
-
Concise summary:
|
|
65
|
-
- Actions taken (2-3 bullets)
|
|
66
|
-
- File paths created/modified
|
|
67
|
-
- Key findings
|
|
68
|
-
</response_format>
|
|
69
57
|
</output_constraints>
|
|
70
58
|
<session_continuity>
|
|
71
59
|
Skills, roles, and decisions set during this session remain active until the user revokes them.
|
package/hooks/run-hook.mjs
CHANGED
|
@@ -13,7 +13,9 @@
|
|
|
13
13
|
* wrapper, where the handler is guaranteed to be live.
|
|
14
14
|
*
|
|
15
15
|
* Contract:
|
|
16
|
-
* - logs every failure to
|
|
16
|
+
* - logs every failure to <configDir>/context-mode/hook-errors.log,
|
|
17
|
+
* where configDir honors $CLAUDE_CONFIG_DIR (incl. leading ~) and
|
|
18
|
+
* falls back to ~/.claude — same contract as session-helpers.mjs (#453)
|
|
17
19
|
* - never propagates a non-zero exit (Claude Code surfaces non-zero as a
|
|
18
20
|
* "non-blocking hook error" on every tool call, which spams the user)
|
|
19
21
|
* - one-liner adoption for new hooks:
|
|
@@ -22,12 +24,23 @@
|
|
|
22
24
|
*/
|
|
23
25
|
|
|
24
26
|
import { homedir } from "node:os";
|
|
25
|
-
import { resolve } from "node:path";
|
|
27
|
+
import { resolve, join } from "node:path";
|
|
26
28
|
import { existsSync, mkdirSync, appendFileSync } from "node:fs";
|
|
27
29
|
|
|
30
|
+
// Inlined to keep this wrapper dependency-free (parse-time imports must be
|
|
31
|
+
// failure-proof). Mirrors session-helpers.mjs::resolveConfigDir for #453.
|
|
32
|
+
function resolveClaudeConfigDir() {
|
|
33
|
+
const envVal = process.env.CLAUDE_CONFIG_DIR;
|
|
34
|
+
if (envVal) {
|
|
35
|
+
if (envVal.startsWith("~")) return join(homedir(), envVal.replace(/^~[/\\]?/, ""));
|
|
36
|
+
return envVal;
|
|
37
|
+
}
|
|
38
|
+
return resolve(homedir(), ".claude");
|
|
39
|
+
}
|
|
40
|
+
|
|
28
41
|
function logError(err) {
|
|
29
42
|
try {
|
|
30
|
-
const dir = resolve(
|
|
43
|
+
const dir = resolve(resolveClaudeConfigDir(), "context-mode");
|
|
31
44
|
if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
|
|
32
45
|
const line = `[${new Date().toISOString()}] pid=${process.pid} ${err?.stack || err?.message || String(err)}\n`;
|
|
33
46
|
appendFileSync(resolve(dir, "hook-errors.log"), line);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{createRequire as
|
|
1
|
+
import{createRequire as Y}from"node:module";import{existsSync as G,unlinkSync as x,renameSync as q}from"node:fs";import{tmpdir as z}from"node:os";import{join as K}from"node:path";var N=class{#t;constructor(t){this.#t=t}pragma(t){let s=this.#t.prepare(`PRAGMA ${t}`).all();if(!s||s.length===0)return;if(s.length>1)return s;let r=Object.values(s[0]);return r.length===1?r[0]:s[0]}exec(t){let e="",s=null;for(let o=0;o<t.length;o++){let a=t[o];if(s)e+=a,a===s&&(s=null);else if(a==="'"||a==='"')e+=a,s=a;else if(a===";"){let u=e.trim();u&&this.#t.prepare(u).run(),e=""}else e+=a}let r=e.trim();return r&&this.#t.prepare(r).run(),this}prepare(t){let e=this.#t.prepare(t);return{run:(...s)=>e.run(...s),get:(...s)=>{let r=e.get(...s);return r===null?void 0:r},all:(...s)=>e.all(...s),iterate:(...s)=>e.iterate(...s)}}transaction(t){return this.#t.transaction(t)}close(){this.#t.close()}},A=class{#t;constructor(t){this.#t=t}pragma(t){let s=this.#t.prepare(`PRAGMA ${t}`).all();if(!s||s.length===0)return;if(s.length>1)return s;let r=Object.values(s[0]);return r.length===1?r[0]:s[0]}exec(t){return this.#t.exec(t),this}prepare(t){let e=this.#t.prepare(t);return{run:(...s)=>e.run(...s),get:(...s)=>e.get(...s),all:(...s)=>e.all(...s),iterate:(...s)=>typeof e.iterate=="function"?e.iterate(...s):e.all(...s)[Symbol.iterator]()}}transaction(t){return(...e)=>{this.#t.exec("BEGIN");try{let s=t(...e);return this.#t.exec("COMMIT"),s}catch(s){throw this.#t.exec("ROLLBACK"),s}}}close(){this.#t.close()}},l=null;function V(n){let t=null;try{return t=new n(":memory:"),t.exec("CREATE VIRTUAL TABLE __fts5_probe USING fts5(x)"),!0}catch{return!1}finally{try{t?.close()}catch{}}}function Q(){if(!l){let n=Y(import.meta.url);if(globalThis.Bun){let t=n(["bun","sqlite"].join(":")).Database;l=function(s,r){let o=new t(s,{readonly:r?.readonly,create:!0}),a=new N(o);return r?.timeout&&a.pragma(`busy_timeout = ${r.timeout}`),a}}else if(process.platform==="linux"){let t=null;try{({DatabaseSync:t}=n(["node","sqlite"].join(":")))}catch{t=null}t&&V(t)?l=function(s,r){let o=new t(s,{readOnly:r?.readonly??!1});return new A(o)}:l=n("better-sqlite3")}else l=n("better-sqlite3")}return l}function I(n){n.pragma("journal_mode = WAL"),n.pragma("synchronous = NORMAL");try{n.pragma("mmap_size = 268435456")}catch{}}function U(n){if(!G(n))for(let t of["-wal","-shm"])try{x(n+t)}catch{}}function Z(n){for(let t of["","-wal","-shm"])try{x(n+t)}catch{}}function D(n){try{n.pragma("wal_checkpoint(TRUNCATE)")}catch{}try{n.close()}catch{}}function M(n="context-mode"){return K(z(),`${n}-${process.pid}.db`)}function J(n,t=[100,500,2e3]){let e;for(let s=0;s<=t.length;s++)try{return n()}catch(r){let o=r instanceof Error?r.message:String(r);if(!o.includes("SQLITE_BUSY")&&!o.includes("database is locked"))throw r;if(e=r instanceof Error?r:new Error(o),s<t.length){let a=t[s],u=Date.now();for(;Date.now()-u<a;);}}throw new Error(`SQLITE_BUSY: database is locked after ${t.length} retries. Original error: ${e?.message}`)}function tt(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 et(n){let t=Date.now();for(let e of["","-wal","-shm"])try{q(n+e,`${n}${e}.corrupt-${t}`)}catch{}}var _=Symbol.for("__context_mode_live_dbs__"),v=(()=>{let n=globalThis;return n[_]||(n[_]=new Set,process.on("exit",()=>{for(let t of n[_])D(t);n[_].clear()})),n[_]})(),y=class{#t;#e;constructor(t){let e=Q();this.#t=t,U(t);let s;try{s=new e(t,{timeout:3e4}),I(s)}catch(r){let o=r instanceof Error?r.message:String(r);if(tt(o)){et(t),U(t);try{s=new e(t,{timeout:3e4}),I(s)}catch(a){throw new Error(`Failed to create fresh DB after renaming corrupt file: ${a instanceof Error?a.message:String(a)}`)}}else throw r}this.#e=s,v.add(this.#e),this.initSchema(),this.prepareStatements()}get db(){return this.#e}get dbPath(){return this.#t}close(){v.delete(this.#e),D(this.#e)}withRetry(t){return J(t)}cleanup(){v.delete(this.#e),D(this.#e),Z(this.#t)}};import{createHash as p}from"node:crypto";import{execFileSync as st}from"node:child_process";import{existsSync as f,realpathSync as nt,renameSync as C}from"node:fs";import{join as b}from"node:path";var E;function g(n){let t=n.replace(/\\/g,"/");return/^\/+$/.test(t)?"/":/^[A-Za-z]:\/+$/.test(t)?`${t.slice(0,2)}/`:t.replace(/\/+$/,"")}function F(n){let t=n;try{t=nt.native(n)}catch{}let e=g(t);return process.platform==="win32"||process.platform==="darwin"?e.toLowerCase():e}function j(n,t){return st("git",["-C",n,...t],{encoding:"utf-8",timeout:2e3,stdio:["ignore","pipe","ignore"]}).trim()}function rt(n){let t=j(n,["rev-parse","--show-toplevel"]);return t.length>0?g(t):null}function it(n){let t=j(n,["worktree","list","--porcelain"]).split(/\r?\n/).find(e=>e.startsWith("worktree "))?.replace("worktree ","")?.trim();return t?g(t):null}function ot(n=process.cwd()){let t=process.env.CONTEXT_MODE_SESSION_SUFFIX;if(E&&E.projectDir===n&&E.envSuffix===t)return E.suffix;let e="";if(t!==void 0)e=t?`__${t}`:"";else try{let s=rt(n),r=it(n);if(s&&r){let o=F(s),a=F(r);o!==a&&(e=`__${p("sha256").update(o).digest("hex").slice(0,8)}`)}}catch{}return E={projectDir:n,envSuffix:t,suffix:e},e}function yt(){E=void 0}function X(n){return p("sha256").update(g(n)).digest("hex").slice(0,16)}function W(n){let t=g(n),e=process.platform==="darwin"||process.platform==="win32"?t.toLowerCase():t;return p("sha256").update(e).digest("hex").slice(0,16)}function ht(n){let{projectDir:t,contentDir:e}=n,s=W(t),r=b(e,`${s}.db`);if(f(r))return r;let o=X(t);if(o===s)return r;let a=b(e,`${o}.db`);if(f(a))try{C(a,r);for(let u of["-wal","-shm"])try{C(a+u,r+u)}catch{}}catch{}return r}function ft(n){return at({...n,ext:".db"})}function at(n){let{projectDir:t,sessionsDir:e,ext:s}=n,r=n.suffix??ot(t),o=W(t),a=b(e,`${o}${r}${s}`);if(f(a))return a;let u=X(t);if(u===o)return a;let d=b(e,`${u}${r}${s}`);if(f(d))try{C(d,a)}catch{}return a}var B=1e3,P=5;function h(n){let t=Number(n);return!Number.isFinite(t)||t<=0?0:Math.floor(t)}var i={insertEvent:"insertEvent",getEvents:"getEvents",getEventsByType:"getEventsByType",getEventsByPriority:"getEventsByPriority",getEventsByTypeAndPriority:"getEventsByTypeAndPriority",getEventCount:"getEventCount",getLatestAttributedProject:"getLatestAttributedProject",checkDuplicate:"checkDuplicate",evictLowestPriority:"evictLowestPriority",updateMetaLastEvent:"updateMetaLastEvent",ensureSession:"ensureSession",getSessionStats:"getSessionStats",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"},k=class extends y{constructor(t){super(t?.dbPath??M("session"))}stmt(t){return this.stmts.get(t)}initSchema(){try{let e=this.db.pragma("table_xinfo(session_events)").find(s=>s.name==="data_hash");e&&e.hidden!==0&&this.db.exec("DROP TABLE session_events")}catch{}this.db.exec(`
|
|
2
2
|
CREATE TABLE IF NOT EXISTS session_events (
|
|
3
3
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
4
4
|
session_id TEXT NOT NULL,
|
|
@@ -9,6 +9,8 @@ import{createRequire as I}from"node:module";import{existsSync as U,unlinkSync as
|
|
|
9
9
|
project_dir TEXT NOT NULL DEFAULT '',
|
|
10
10
|
attribution_source TEXT NOT NULL DEFAULT 'unknown',
|
|
11
11
|
attribution_confidence REAL NOT NULL DEFAULT 0,
|
|
12
|
+
bytes_avoided INTEGER NOT NULL DEFAULT 0,
|
|
13
|
+
bytes_returned INTEGER NOT NULL DEFAULT 0,
|
|
12
14
|
source_hook TEXT NOT NULL,
|
|
13
15
|
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
14
16
|
data_hash TEXT NOT NULL DEFAULT ''
|
|
@@ -46,45 +48,50 @@ import{createRequire as I}from"node:module";import{existsSync as U,unlinkSync as
|
|
|
46
48
|
);
|
|
47
49
|
|
|
48
50
|
CREATE INDEX IF NOT EXISTS idx_tool_calls_session ON tool_calls(session_id);
|
|
49
|
-
`);try{let t=this.db.pragma("table_xinfo(session_events)"),e=new Set(t.map(s=>s.name));e.has("project_dir")||this.db.exec("ALTER TABLE session_events ADD COLUMN project_dir TEXT NOT NULL DEFAULT ''"),e.has("attribution_source")||this.db.exec("ALTER TABLE session_events ADD COLUMN attribution_source TEXT NOT NULL DEFAULT 'unknown'"),e.has("attribution_confidence")||this.db.exec("ALTER TABLE session_events ADD COLUMN attribution_confidence REAL NOT NULL DEFAULT 0"),this.db.exec("CREATE INDEX IF NOT EXISTS idx_session_events_project ON session_events(session_id, project_dir)")}catch{}}prepareStatements(){this.stmts=new Map;let t=(e,s)=>{this.stmts.set(e,this.db.prepare(s))};t(
|
|
51
|
+
`);try{let t=this.db.pragma("table_xinfo(session_events)"),e=new Set(t.map(s=>s.name));e.has("project_dir")||this.db.exec("ALTER TABLE session_events ADD COLUMN project_dir TEXT NOT NULL DEFAULT ''"),e.has("attribution_source")||this.db.exec("ALTER TABLE session_events ADD COLUMN attribution_source TEXT NOT NULL DEFAULT 'unknown'"),e.has("attribution_confidence")||this.db.exec("ALTER TABLE session_events ADD COLUMN attribution_confidence REAL NOT NULL DEFAULT 0"),e.has("bytes_avoided")||this.db.exec("ALTER TABLE session_events ADD COLUMN bytes_avoided INTEGER NOT NULL DEFAULT 0"),e.has("bytes_returned")||this.db.exec("ALTER TABLE session_events ADD COLUMN bytes_returned INTEGER NOT NULL DEFAULT 0"),this.db.exec("CREATE INDEX IF NOT EXISTS idx_session_events_project ON session_events(session_id, project_dir)")}catch{}}prepareStatements(){this.stmts=new Map;let t=(e,s)=>{this.stmts.set(e,this.db.prepare(s))};t(i.insertEvent,`INSERT INTO session_events (
|
|
50
52
|
session_id, type, category, priority, data,
|
|
51
53
|
project_dir, attribution_source, attribution_confidence,
|
|
54
|
+
bytes_avoided, bytes_returned,
|
|
52
55
|
source_hook, data_hash
|
|
53
56
|
)
|
|
54
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`),t(
|
|
57
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`),t(i.getEvents,`SELECT id, session_id, type, category, priority, data,
|
|
55
58
|
project_dir, attribution_source, attribution_confidence,
|
|
59
|
+
bytes_avoided, bytes_returned,
|
|
56
60
|
source_hook, created_at, data_hash
|
|
57
|
-
FROM session_events WHERE session_id = ? ORDER BY id ASC LIMIT ?`),t(
|
|
61
|
+
FROM session_events WHERE session_id = ? ORDER BY id ASC LIMIT ?`),t(i.getEventsByType,`SELECT id, session_id, type, category, priority, data,
|
|
58
62
|
project_dir, attribution_source, attribution_confidence,
|
|
63
|
+
bytes_avoided, bytes_returned,
|
|
59
64
|
source_hook, created_at, data_hash
|
|
60
|
-
FROM session_events WHERE session_id = ? AND type = ? ORDER BY id ASC LIMIT ?`),t(
|
|
65
|
+
FROM session_events WHERE session_id = ? AND type = ? ORDER BY id ASC LIMIT ?`),t(i.getEventsByPriority,`SELECT id, session_id, type, category, priority, data,
|
|
61
66
|
project_dir, attribution_source, attribution_confidence,
|
|
67
|
+
bytes_avoided, bytes_returned,
|
|
62
68
|
source_hook, created_at, data_hash
|
|
63
|
-
FROM session_events WHERE session_id = ? AND priority >= ? ORDER BY id ASC LIMIT ?`),t(
|
|
69
|
+
FROM session_events WHERE session_id = ? AND priority >= ? ORDER BY id ASC LIMIT ?`),t(i.getEventsByTypeAndPriority,`SELECT id, session_id, type, category, priority, data,
|
|
64
70
|
project_dir, attribution_source, attribution_confidence,
|
|
71
|
+
bytes_avoided, bytes_returned,
|
|
65
72
|
source_hook, created_at, data_hash
|
|
66
|
-
FROM session_events WHERE session_id = ? AND type = ? AND priority >= ? ORDER BY id ASC LIMIT ?`),t(
|
|
73
|
+
FROM session_events WHERE session_id = ? AND type = ? AND priority >= ? ORDER BY id ASC LIMIT ?`),t(i.getEventCount,"SELECT COUNT(*) AS cnt FROM session_events WHERE session_id = ?"),t(i.getLatestAttributedProject,`SELECT project_dir
|
|
67
74
|
FROM session_events
|
|
68
75
|
WHERE session_id = ? AND project_dir != ''
|
|
69
76
|
ORDER BY id DESC
|
|
70
|
-
LIMIT 1`),t(
|
|
77
|
+
LIMIT 1`),t(i.checkDuplicate,`SELECT 1 FROM (
|
|
71
78
|
SELECT type, data_hash FROM session_events
|
|
72
79
|
WHERE session_id = ? ORDER BY id DESC LIMIT ?
|
|
73
80
|
) AS recent
|
|
74
81
|
WHERE recent.type = ? AND recent.data_hash = ?
|
|
75
|
-
LIMIT 1`),t(
|
|
82
|
+
LIMIT 1`),t(i.evictLowestPriority,`DELETE FROM session_events WHERE id = (
|
|
76
83
|
SELECT id FROM session_events WHERE session_id = ?
|
|
77
84
|
ORDER BY priority ASC, id ASC LIMIT 1
|
|
78
|
-
)`),t(
|
|
85
|
+
)`),t(i.updateMetaLastEvent,`UPDATE session_meta
|
|
79
86
|
SET last_event_at = datetime('now'), event_count = event_count + 1
|
|
80
|
-
WHERE session_id = ?`),t(
|
|
81
|
-
FROM session_meta WHERE session_id = ?`),t(
|
|
87
|
+
WHERE session_id = ?`),t(i.ensureSession,"INSERT OR IGNORE INTO session_meta (session_id, project_dir) VALUES (?, ?)"),t(i.getSessionStats,`SELECT session_id, project_dir, started_at, last_event_at, event_count, compact_count
|
|
88
|
+
FROM session_meta WHERE session_id = ?`),t(i.incrementCompactCount,"UPDATE session_meta SET compact_count = compact_count + 1 WHERE session_id = ?"),t(i.upsertResume,`INSERT INTO session_resume (session_id, snapshot, event_count)
|
|
82
89
|
VALUES (?, ?, ?)
|
|
83
90
|
ON CONFLICT(session_id) DO UPDATE SET
|
|
84
91
|
snapshot = excluded.snapshot,
|
|
85
92
|
event_count = excluded.event_count,
|
|
86
93
|
created_at = datetime('now'),
|
|
87
|
-
consumed = 0`),t(
|
|
94
|
+
consumed = 0`),t(i.getResume,"SELECT snapshot, event_count, consumed FROM session_resume WHERE session_id = ?"),t(i.markResumeConsumed,"UPDATE session_resume SET consumed = 1 WHERE session_id = ?"),t(i.claimLatestUnconsumedResume,`UPDATE session_resume
|
|
88
95
|
SET consumed = 1
|
|
89
96
|
WHERE id = (
|
|
90
97
|
SELECT id FROM session_resume
|
|
@@ -93,18 +100,20 @@ import{createRequire as I}from"node:module";import{existsSync as U,unlinkSync as
|
|
|
93
100
|
ORDER BY created_at DESC, id DESC
|
|
94
101
|
LIMIT 1
|
|
95
102
|
)
|
|
96
|
-
RETURNING session_id, snapshot`),t(
|
|
103
|
+
RETURNING session_id, snapshot`),t(i.deleteEvents,"DELETE FROM session_events WHERE session_id = ?"),t(i.deleteMeta,"DELETE FROM session_meta WHERE session_id = ?"),t(i.deleteResume,"DELETE FROM session_resume WHERE session_id = ?"),t(i.searchEvents,`SELECT id, session_id, category, type, data, created_at
|
|
97
104
|
FROM session_events
|
|
98
105
|
WHERE project_dir = ?
|
|
99
106
|
AND (data LIKE '%' || ? || '%' ESCAPE '\\' OR category LIKE '%' || ? || '%' ESCAPE '\\')
|
|
100
107
|
AND (? IS NULL OR category = ?)
|
|
101
108
|
ORDER BY id ASC
|
|
102
|
-
LIMIT ?`),t(
|
|
109
|
+
LIMIT ?`),t(i.getOldSessions,"SELECT session_id FROM session_meta WHERE started_at < datetime('now', ? || ' days')"),t(i.incrementToolCall,`INSERT INTO tool_calls (session_id, tool, calls, bytes_returned)
|
|
103
110
|
VALUES (?, ?, 1, ?)
|
|
104
111
|
ON CONFLICT(session_id, tool) DO UPDATE SET
|
|
105
112
|
calls = calls + 1,
|
|
106
113
|
bytes_returned = bytes_returned + excluded.bytes_returned,
|
|
107
|
-
updated_at = datetime('now')`),t(
|
|
114
|
+
updated_at = datetime('now')`),t(i.getToolCallTotals,`SELECT COALESCE(SUM(calls), 0) AS calls,
|
|
115
|
+
COALESCE(SUM(bytes_returned), 0) AS bytes_returned
|
|
116
|
+
FROM tool_calls WHERE session_id = ?`),t(i.getToolCallByTool,`SELECT tool, calls, bytes_returned
|
|
117
|
+
FROM tool_calls WHERE session_id = ? ORDER BY calls DESC`),t(i.getEventBytesSummary,`SELECT COALESCE(SUM(bytes_avoided), 0) AS bytes_avoided,
|
|
108
118
|
COALESCE(SUM(bytes_returned), 0) AS bytes_returned
|
|
109
|
-
FROM
|
|
110
|
-
FROM tool_calls WHERE session_id = ? ORDER BY calls DESC`)}insertEvent(t,e,s="PostToolUse",r){let o=f("sha256").update(e.data).digest("hex").slice(0,16).toUpperCase(),a=String(r?.projectDir??e.project_dir??"").trim(),c=String(r?.source??e.attribution_source??"unknown"),u=Number(r?.confidence??e.attribution_confidence??0),_=Number.isFinite(u)?Math.max(0,Math.min(1,u)):0,E=this.db.transaction(()=>{if(this.stmt(n.checkDuplicate).get(t,D,e.type,o))return;this.stmt(n.getEventCount).get(t).cnt>=O&&this.stmt(n.evictLowestPriority).run(t),this.stmt(n.insertEvent).run(t,e.type,e.category,e.priority,e.data,a,c,_,s,o),this.stmt(n.updateMetaLastEvent).run(t)});this.withRetry(()=>E())}bulkInsertEvents(t,e,s="PostToolUse",r){if(!e||e.length===0)return;if(e.length===1){this.insertEvent(t,e[0],s,r?.[0]);return}let o=e.map((c,u)=>{let _=f("sha256").update(c.data).digest("hex").slice(0,16).toUpperCase(),E=r?.[u],S=String(E?.projectDir??c.project_dir??"").trim(),L=String(E?.source??c.attribution_source??"unknown"),R=Number(E?.confidence??c.attribution_confidence??0),w=Number.isFinite(R)?Math.max(0,Math.min(1,R)):0;return{event:c,dataHash:_,projectDir:S,attributionSource:L,attributionConfidence:w}}),a=this.db.transaction(()=>{let c=this.stmt(n.getEventCount).get(t).cnt;for(let u of o)this.stmt(n.checkDuplicate).get(t,D,u.event.type,u.dataHash)||(c>=O?this.stmt(n.evictLowestPriority).run(t):c++,this.stmt(n.insertEvent).run(t,u.event.type,u.event.category,u.event.priority,u.event.data,u.projectDir,u.attributionSource,u.attributionConfidence,s,u.dataHash));this.stmt(n.updateMetaLastEvent).run(t)});this.withRetry(()=>a())}getEvents(t,e){let s=e?.limit??1e3,r=e?.type,o=e?.minPriority;return r&&o!==void 0?this.stmt(n.getEventsByTypeAndPriority).all(t,r,o,s):r?this.stmt(n.getEventsByType).all(t,r,s):o!==void 0?this.stmt(n.getEventsByPriority).all(t,o,s):this.stmt(n.getEvents).all(t,s)}getEventCount(t){return this.stmt(n.getEventCount).get(t).cnt}getLatestAttributedProjectDir(t){return this.stmt(n.getLatestAttributedProject).get(t)?.project_dir||null}searchEvents(t,e,s,r){try{let o=t.replace(/[%_]/g,c=>"\\"+c),a=r??null;return this.stmt(n.searchEvents).all(s,o,o,a,a,e)}catch{return[]}}ensureSession(t,e){this.stmt(n.ensureSession).run(t,e)}getSessionStats(t){return this.stmt(n.getSessionStats).get(t)??null}incrementCompactCount(t){this.stmt(n.incrementCompactCount).run(t)}upsertResume(t,e,s){this.stmt(n.upsertResume).run(t,e,s??0)}getResume(t){return this.stmt(n.getResume).get(t)??null}markResumeConsumed(t){this.stmt(n.markResumeConsumed).run(t)}claimLatestUnconsumedResume(t){let e=this.stmt(n.claimLatestUnconsumedResume).get(t);return e?{sessionId:e.session_id,snapshot:e.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(t,e,s=0){let r=Number.isFinite(s)&&s>0?Math.round(s):0;try{this.stmt(n.incrementToolCall).run(t,e,r)}catch{}}getToolCallStats(t){try{let e=this.stmt(n.getToolCallTotals).get(t),s=this.stmt(n.getToolCallByTool).all(t),r={};for(let o of s)r[o.tool]={calls:o.calls,bytesReturned:o.bytes_returned};return{totalCalls:e?.calls??0,totalBytesReturned:e?.bytes_returned??0,byTool:r}}catch{return{totalCalls:0,totalBytesReturned:0,byTool:{}}}}deleteSession(t){this.db.transaction(()=>{this.stmt(n.deleteEvents).run(t),this.stmt(n.deleteResume).run(t),this.stmt(n.deleteMeta).run(t)})()}cleanupOldSessions(t=7){let e=`-${t}`,s=this.stmt(n.getOldSessions).all(e);for(let{session_id:r}of s)this.deleteSession(r);return s.length}};export{A as SessionDB,J as _resetWorktreeSuffixCacheForTests,z as getWorktreeSuffix};
|
|
119
|
+
FROM session_events WHERE session_id = ?`)}insertEvent(t,e,s="PostToolUse",r,o){let a=p("sha256").update(e.data).digest("hex").slice(0,16).toUpperCase(),u=String(r?.projectDir??e.project_dir??"").trim(),d=String(r?.source??e.attribution_source??"unknown"),c=Number(r?.confidence??e.attribution_confidence??0),T=Number.isFinite(c)?Math.max(0,Math.min(1,c)):0,m=h(o?.bytesAvoided),L=h(o?.bytesReturned),R=this.db.transaction(()=>{if(this.stmt(i.checkDuplicate).get(t,P,e.type,a))return;this.stmt(i.getEventCount).get(t).cnt>=B&&this.stmt(i.evictLowestPriority).run(t),this.stmt(i.insertEvent).run(t,e.type,e.category,e.priority,e.data,u,d,T,m,L,s,a),this.stmt(i.updateMetaLastEvent).run(t)});this.withRetry(()=>R())}bulkInsertEvents(t,e,s="PostToolUse",r,o){if(!e||e.length===0)return;if(e.length===1){this.insertEvent(t,e[0],s,r?.[0],o?.[0]);return}let a=e.map((d,c)=>{let T=p("sha256").update(d.data).digest("hex").slice(0,16).toUpperCase(),m=r?.[c],L=String(m?.projectDir??d.project_dir??"").trim(),R=String(m?.source??d.attribution_source??"unknown"),S=Number(m?.confidence??d.attribution_confidence??0),O=Number.isFinite(S)?Math.max(0,Math.min(1,S)):0,w=o?.[c],H=h(w?.bytesAvoided),$=h(w?.bytesReturned);return{event:d,dataHash:T,projectDir:L,attributionSource:R,attributionConfidence:O,bytesAvoided:H,bytesReturned:$}}),u=this.db.transaction(()=>{let d=this.stmt(i.getEventCount).get(t).cnt;for(let c of a)this.stmt(i.checkDuplicate).get(t,P,c.event.type,c.dataHash)||(d>=B?this.stmt(i.evictLowestPriority).run(t):d++,this.stmt(i.insertEvent).run(t,c.event.type,c.event.category,c.event.priority,c.event.data,c.projectDir,c.attributionSource,c.attributionConfidence,c.bytesAvoided,c.bytesReturned,s,c.dataHash));this.stmt(i.updateMetaLastEvent).run(t)});this.withRetry(()=>u())}getEvents(t,e){let s=e?.limit??1e3,r=e?.type,o=e?.minPriority;return r&&o!==void 0?this.stmt(i.getEventsByTypeAndPriority).all(t,r,o,s):r?this.stmt(i.getEventsByType).all(t,r,s):o!==void 0?this.stmt(i.getEventsByPriority).all(t,o,s):this.stmt(i.getEvents).all(t,s)}getEventCount(t){return this.stmt(i.getEventCount).get(t).cnt}getEventBytesSummary(t){let e=this.stmt(i.getEventBytesSummary).get(t);return{bytesAvoided:Number(e?.bytes_avoided??0),bytesReturned:Number(e?.bytes_returned??0)}}getLatestAttributedProjectDir(t){return this.stmt(i.getLatestAttributedProject).get(t)?.project_dir||null}searchEvents(t,e,s,r){try{let o=t.replace(/[%_]/g,u=>"\\"+u),a=r??null;return this.stmt(i.searchEvents).all(s,o,o,a,a,e)}catch{return[]}}ensureSession(t,e){this.stmt(i.ensureSession).run(t,e)}getSessionStats(t){return this.stmt(i.getSessionStats).get(t)??null}incrementCompactCount(t){this.stmt(i.incrementCompactCount).run(t)}upsertResume(t,e,s){this.stmt(i.upsertResume).run(t,e,s??0)}getResume(t){return this.stmt(i.getResume).get(t)??null}markResumeConsumed(t){this.stmt(i.markResumeConsumed).run(t)}claimLatestUnconsumedResume(t){let e=this.stmt(i.claimLatestUnconsumedResume).get(t);return e?{sessionId:e.session_id,snapshot:e.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(t,e,s=0){let r=Number.isFinite(s)&&s>0?Math.round(s):0;try{this.stmt(i.incrementToolCall).run(t,e,r)}catch{}}getToolCallStats(t){try{let e=this.stmt(i.getToolCallTotals).get(t),s=this.stmt(i.getToolCallByTool).all(t),r={};for(let o of s)r[o.tool]={calls:o.calls,bytesReturned:o.bytes_returned};return{totalCalls:e?.calls??0,totalBytesReturned:e?.bytes_returned??0,byTool:r}}catch{return{totalCalls:0,totalBytesReturned:0,byTool:{}}}}deleteSession(t){this.db.transaction(()=>{this.stmt(i.deleteEvents).run(t),this.stmt(i.deleteResume).run(t),this.stmt(i.deleteMeta).run(t)})()}cleanupOldSessions(t=7){let e=`-${t}`,s=this.stmt(i.getOldSessions).all(e);for(let{session_id:r}of s)this.deleteSession(r);return s.length}};export{k as SessionDB,yt as _resetWorktreeSuffixCacheForTests,ot as getWorktreeSuffix,W as hashProjectDirCanonical,X as hashProjectDirLegacy,g as normalizeWorktreePath,ht as resolveContentStorePath,ft as resolveSessionDbPath,at as resolveSessionPath};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
function s(t){return t==null?"":String(t)}function
|
|
2
|
-
response: ${s(
|
|
1
|
+
function s(t){return t==null?"":String(t)}function g(t){return t==null?"":typeof t=="string"?t:JSON.stringify(t)}function u(t){let e=String(t.tool_response??""),o=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)||o}function h(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 o=new Set;return e.filter(r=>{if(!r.path)return!1;let n=`${r.type}:${r.path}`;return o.has(n)?!1:(o.add(n),!0)})}function f(t){return/(?:^|[/\\])\.claude[/\\]plans[/\\]/.test(t)}function _(t){let{tool_name:e,tool_input:o,tool_response:r}=t,n=[];if(e==="Read"){let i=String(o.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))&&(n.push({type:"rule",category:"rule",data:s(i),priority:1}),r&&r.length>0&&n.push({type:"rule_content",category:"rule",data:s(r),priority:1})),n.push({type:"file_read",category:"file",data:s(i),priority:1}),n}if(e==="Edit"){let i=String(o.file_path??"");return n.push({type:"file_edit",category:"file",data:s(i),priority:1}),n}if(e==="NotebookEdit"){let i=String(o.notebook_path??"");return n.push({type:"file_edit",category:"file",data:s(i),priority:1}),n}if(e==="Write"){let i=String(o.file_path??"");return n.push({type:"file_write",category:"file",data:s(i),priority:1}),n}if(e==="apply_patch"){if(u(t))return[];let i=h(String(o.command??o.patch??""));for(let a of i)n.push({type:a.type,category:"file",data:s(a.path),priority:1});return n}if(e==="Glob"){let i=String(o.pattern??"");return n.push({type:"file_glob",category:"file",data:s(i),priority:3}),n}if(e==="Grep"){let i=String(o.pattern??""),a=String(o.path??"");return n.push({type:"file_search",category:"file",data:s(`${i} in ${a}`),priority:3}),n}return n}function m(t){if(t.tool_name!=="Bash")return[];let o=String(t.tool_input.command??"").match(/\bcd\s+("([^"]+)"|'([^']+)'|(\S+))/);if(!o)return[];let r=o[2]??o[3]??o[4]??"";return[{type:"cwd",category:"cwd",data:s(r),priority:2}]}function S(t){let{tool_response:e}=t,o=String(e??"");return u(t)?[{type:"error_tool",category:"error",data:s(o),priority:2}]:[]}var k=[{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 E(t){if(t.tool_name!=="Bash")return[];let e=String(t.tool_input.command??""),o=k.find(r=>r.pattern.test(e));return o?[{type:"git",category:"git",data:s(o.operation),priority:2}]:[]}function v(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=[],o=t.tool_input.allowedPrompts,r=Array.isArray(o)&&o.length>0?`exited plan mode (allowed: ${g(o.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(r),priority:2});let n=String(t.tool_response??"").toLowerCase();return n.includes("approved")||n.includes("approve")?e.push({type:"plan_approved",category:"plan",data:"plan approved by user",priority:1}):(n.includes("rejected")||n.includes("decline")||n.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(f(e))return[{type:"plan_file_write",category:"plan",data:s(`plan file: ${e.split(/[/\\]/).pop()??e}`),priority:2}]}return t.tool_name==="apply_patch"?u(t)?[]:h(String(t.tool_input.command??t.tool_input.patch??"")).filter(o=>f(o.path)).map(o=>({type:"plan_file_write",category:"plan",data:s(`plan file: ${o.path.split(/[/\\]/).pop()??o.path}`),priority:2})):[]}var w=[/\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 R(t){if(t.tool_name!=="Bash")return[];let e=String(t.tool_input.command??"");if(!w.some(n=>n.test(e)))return[];let r=e.replace(/\bexport\s+(\w+)=\S*/g,"export $1=***");return[{type:"env",category:"env",data:s(r),priority:2}]}function T(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 A(t){if(!t.tool_response?.includes("Error")&&!t.tool_output?.isError)return[];let e=String(t.tool_response||""),o=[/not supported/i,/cannot/i,/does not support/i,/FAIL/i,/refused/i,/permission denied/i,/incompatible/i];for(let r of o){let n=e.match(r);if(n){let i=e.toLowerCase().indexOf(n[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 I(t){if(t.tool_name!=="Agent")return[];let e=s(String(t.tool_input.prompt??t.tool_input.description??"")),o=t.tool_response?s(String(t.tool_response)):"",r=o.length>0;return[{type:r?"subagent_completed":"subagent_launched",category:"subagent",data:s(r?`[completed] ${e} \u2192 ${o}`:`[launched] ${e}`),priority:r?2:3}]}function $(t){let{tool_name:e,tool_input:o,tool_response:r}=t;if(!e.startsWith("mcp__"))return[];let n=e.split("__"),i=n[n.length-1]||e,a=Object.values(o).find(b=>typeof b=="string"),p=a?`: ${s(String(a))}`:"",y=r&&r.length>0?`
|
|
2
|
+
response: ${s(r)}`:"";return[{type:"mcp",category:"mcp",data:s(`${i}${p}${y}`),priority:3}]}var H=2048;function P(t,e){if(Buffer.byteLength(t,"utf8")<=e)return{value:t,truncated:!1};let o=Buffer.from(t,"utf8"),r=e;for(;r>0&&(o[r]&192)===128;)r--;return{value:o.subarray(0,r).toString("utf8"),truncated:!0}}var N=/(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,O="[REDACTED]";function d(t,e=new WeakSet){if(t==null||typeof t!="object")return t;if(e.has(t))return"[CIRCULAR]";e.add(t);let o;if(Array.isArray(t))o=t.map(r=>d(r,e));else{let r={};for(let[n,i]of Object.entries(t))N.test(n)?r[n]=O:r[n]=d(i,e);o=r}return e.delete(t),o}function B(t){let{tool_name:e,tool_input:o}=t;if(!e.startsWith("mcp__"))return[];let r=d(o??{}),n;try{n=JSON.stringify(r)}catch{n="{}"}let{value:i,truncated:a}=P(n,H),p=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(p),priority:4}]}function C(t){if(t.tool_name!=="AskUserQuestion")return[];let e=t.tool_input.questions,o=Array.isArray(e)&&e.length>0?String(e[0].question??""):"",r=s(String(t.tool_response??"")),n=o?`Q: ${s(o)} \u2192 A: ${r}`:`answer: ${r}`;return[{type:"decision_question",category:"decision",data:s(n),priority:2}]}function L(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 W(t){let e=[g(t.tool_input),s(t.tool_response)].join(" ");if(e.length===0)return[];let o=new Set,r=e.match(/https?:\/\/[^\s)]+/g);if(r)for(let i of r)i=i.replace(/["'})\],;.]+$/,""),/localhost|127\.0\.0\.1/i.test(i)||o.add(i);let n=e.match(/(?<!\w)#(\d+)/g);if(n)for(let i of n)o.add(i);return o.size===0?[]:[{type:"external_ref",category:"external-ref",data:s(Array.from(o).join(", ")),priority:3}]}function M(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 j=[/\b(don'?t|do not|never|always|instead|rather|prefer)\b/i,/\b(use|switch to|go with|pick|choose)\s+\w+\s+(instead|over|not)\b/i,/\b(no,?\s+(use|do|try|make))\b/i,/\b(hayır|hayir|evet|böyle|boyle|degil|değil|yerine|kullan)\b/i];function D(t){return j.some(o=>o.test(t))?[{type:"decision",category:"decision",data:s(t),priority:2}]:[]}var F=[/\b(act as|you are|behave like|pretend|role of|persona)\b/i,/\b(senior|staff|principal|lead)\s+(engineer|developer|architect)\b/i,/\b(gibi davran|rolünde|olarak çalış)\b/i];function G(t){return F.some(o=>o.test(t))?[{type:"role",category:"role",data:s(t),priority:3}]:[]}var U=[{mode:"investigate",pattern:/\b(why|how does|explain|understand|what is|analyze|debug|look into)\b/i},{mode:"implement",pattern:/\b(create|add|build|implement|write|make|develop|fix)\b/i},{mode:"discuss",pattern:/\b(think about|consider|should we|what if|pros and cons|opinion)\b/i},{mode:"review",pattern:/\b(review|check|audit|verify|test|validate)\b/i}];function J(t){let e=U.find(({pattern:o})=>o.test(t));return e?[{type:"intent",category:"intent",data:s(e.mode),priority:4}]:[]}var q=[/\bblocked on\b/i,/\bwaiting for\b/i,/\bneed\s+\S+\s+before\b/i,/\bcan'?t proceed until\b/i,/\bdepends on\b/i,/\bblocked\b/i,/\bbekliyor\b/i,/\bbekliyorum\b/i],z=[/\bunblocked\b/i,/\bresolved\b/i,/\bgot the\s+\S+/i,/\bis ready now\b/i,/\bcan proceed\b/i];function K(t){let e=[];return z.some(n=>n.test(t))?(e.push({type:"blocker_resolved",category:"blocked-on",data:s(t),priority:2}),e):(q.some(n=>n.test(t))&&e.push({type:"blocker",category:"blocked-on",data:s(t),priority:2}),e)}function Q(t){return t.length<=1024?[]:[{type:"data",category:"data",data:s(t),priority:4}]}var c=null;function V(t){let{tool_name:e,tool_response:o}=t,r=String(o??"");if(u(t))return c={tool:e,error:r.slice(0,200),callsSince:0},[];if(!c)return[];if(c.callsSince++,c.callsSince>10)return c=null,[];if(!!u(t))return[];let i=e===c.tool,a=c.tool==="Read"&&(e==="Edit"||e==="Write"||e==="apply_patch");if(i||a){let p={type:"error_resolved",category:"error-resolution",data:s(`Error in ${c.tool}: ${c.error} \u2192 Fixed`),priority:2};return c=null,[p]}return[]}function et(){c=null}var l=[];function Y(t){return`${t.length}:${t.slice(0,20)}`}function Z(t){let{tool_name:e,tool_input:o}=t,r=Y(JSON.stringify(o).slice(0,200));if(l.push({tool:e,inputHash:r}),l.length>50&&l.splice(0,l.length-50),l.length<3)return[];let n=0;for(let i=l.length-1;i>=0&&(l[i].tool===e&&l[i].inputHash===r);i--)n++;return n>=3?(l.splice(l.length-n),[{type:"retry_detected",category:"iteration-loop",data:s(`${e} called ${n} times with similar input`),priority:2}]):[]}function ot(){l.length=0}var X={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 tt(t){let e=X[t.tool_name];return!e||e===t.tool_name?t:{...t,tool_name:e}}function rt(t){try{let e=tt(t),o=[];return o.push(..._(e)),o.push(...m(e)),o.push(...S(e)),o.push(...E(e)),o.push(...R(e)),o.push(...v(e)),o.push(...x(e)),o.push(...T(e)),o.push(...I(e)),o.push(...$(e)),o.push(...B(e)),o.push(...C(e)),o.push(...A(e)),o.push(...M(e)),o.push(...L(e)),o.push(...W(e)),o.push(...V(e)),o.push(...Z(e)),o}catch{return[]}}function nt(t){try{let e=[];return e.push(...D(t)),e.push(...G(t)),e.push(...J(t)),e.push(...K(t)),e.push(...Q(t)),e}catch{return[]}}export{rt as extractEvents,nt as extractUserEvents,et as resetErrorResolutionState,ot as resetIterationLoopState};
|