vibe-code-explainer 0.3.4 → 0.3.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunk-GEAH6PTG.js +37 -0
- package/dist/chunk-GEAH6PTG.js.map +1 -0
- package/dist/{chunk-2PUO5G3C.js → chunk-KK76JK7S.js} +32 -92
- package/dist/chunk-KK76JK7S.js.map +1 -0
- package/dist/chunk-LWASVVBV.js +140 -0
- package/dist/chunk-LWASVVBV.js.map +1 -0
- package/dist/{chunk-ABPTVWQ3.js → chunk-R5H62KGX.js} +86 -85
- package/dist/chunk-R5H62KGX.js.map +1 -0
- package/dist/{chunk-XW3S5GNV.js → chunk-VJN7Y4SI.js} +114 -33
- package/dist/chunk-VJN7Y4SI.js.map +1 -0
- package/dist/cli/index.js +37 -9
- package/dist/cli/index.js.map +1 -1
- package/dist/{config-AHHWBME7.js → config-4DNTCZ6X.js} +127 -8
- package/dist/config-4DNTCZ6X.js.map +1 -0
- package/dist/hooks/post-tool.js +143 -162
- package/dist/hooks/post-tool.js.map +1 -1
- package/dist/{init-XXK6SGF2.js → init-YHRKOKSY.js} +12 -16
- package/dist/init-YHRKOKSY.js.map +1 -0
- package/dist/ollama-43BPUEEC.js +12 -0
- package/dist/{schema-YEJIXFMK.js → schema-MYOWRNBW.js} +8 -4
- package/dist/{tracker-Z5EEYUUZ.js → tracker-Y2G5DW6Y.js} +2 -2
- package/dist/{uninstall-AIH4HVPZ.js → uninstall-YADL7OUB.js} +3 -3
- package/package.json +3 -2
- package/dist/chunk-2PUO5G3C.js.map +0 -1
- package/dist/chunk-ABPTVWQ3.js.map +0 -1
- package/dist/chunk-RK7ZFN4W.js +0 -97
- package/dist/chunk-RK7ZFN4W.js.map +0 -1
- package/dist/chunk-XW3S5GNV.js.map +0 -1
- package/dist/config-AHHWBME7.js.map +0 -1
- package/dist/init-XXK6SGF2.js.map +0 -1
- package/dist/ollama-2WHLTTDD.js +0 -14
- /package/dist/{ollama-2WHLTTDD.js.map → ollama-43BPUEEC.js.map} +0 -0
- /package/dist/{schema-YEJIXFMK.js.map → schema-MYOWRNBW.js.map} +0 -0
- /package/dist/{tracker-Z5EEYUUZ.js.map → tracker-Y2G5DW6Y.js.map} +0 -0
- /package/dist/{uninstall-AIH4HVPZ.js.map → uninstall-YADL7OUB.js.map} +0 -0
package/dist/hooks/post-tool.js
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
buildClaudePrompt,
|
|
4
|
-
callOllama
|
|
5
|
-
|
|
4
|
+
callOllama,
|
|
5
|
+
parseResponse,
|
|
6
|
+
truncateText
|
|
7
|
+
} from "../chunk-R5H62KGX.js";
|
|
6
8
|
import {
|
|
7
9
|
DEFAULT_CONFIG,
|
|
8
10
|
loadConfig
|
|
9
|
-
} from "../chunk-
|
|
11
|
+
} from "../chunk-LWASVVBV.js";
|
|
10
12
|
import {
|
|
11
13
|
cleanStaleSessionFiles,
|
|
12
14
|
formatDriftAlert,
|
|
@@ -15,10 +17,11 @@ import {
|
|
|
15
17
|
formatSkipNotice,
|
|
16
18
|
getCached,
|
|
17
19
|
getRecentSummaries,
|
|
20
|
+
isSafeSessionId,
|
|
18
21
|
readSession,
|
|
19
22
|
recordEntry,
|
|
20
23
|
setCached
|
|
21
|
-
} from "../chunk-
|
|
24
|
+
} from "../chunk-VJN7Y4SI.js";
|
|
22
25
|
import "../chunk-7OCVIDC7.js";
|
|
23
26
|
|
|
24
27
|
// src/hooks/post-tool.ts
|
|
@@ -26,91 +29,6 @@ import { join } from "path";
|
|
|
26
29
|
|
|
27
30
|
// src/engines/claude.ts
|
|
28
31
|
import { execFile } from "child_process";
|
|
29
|
-
function extractBalancedObject(text, startIdx) {
|
|
30
|
-
let depth = 0;
|
|
31
|
-
let inString = false;
|
|
32
|
-
let escape = false;
|
|
33
|
-
for (let i = startIdx; i < text.length; i++) {
|
|
34
|
-
const ch = text[i];
|
|
35
|
-
if (escape) {
|
|
36
|
-
escape = false;
|
|
37
|
-
continue;
|
|
38
|
-
}
|
|
39
|
-
if (ch === "\\") {
|
|
40
|
-
escape = true;
|
|
41
|
-
continue;
|
|
42
|
-
}
|
|
43
|
-
if (ch === '"') {
|
|
44
|
-
inString = !inString;
|
|
45
|
-
continue;
|
|
46
|
-
}
|
|
47
|
-
if (inString) continue;
|
|
48
|
-
if (ch === "{") depth++;
|
|
49
|
-
else if (ch === "}") {
|
|
50
|
-
depth--;
|
|
51
|
-
if (depth === 0) return text.slice(startIdx, i + 1);
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
return null;
|
|
55
|
-
}
|
|
56
|
-
function extractJson(text) {
|
|
57
|
-
const trimmed = text.trim();
|
|
58
|
-
if (trimmed.startsWith("{") && trimmed.endsWith("}")) return trimmed;
|
|
59
|
-
const fenceOpen = trimmed.match(/```(?:json)?\s*\n?/);
|
|
60
|
-
if (fenceOpen) {
|
|
61
|
-
const afterOpen = trimmed.slice(fenceOpen.index + fenceOpen[0].length);
|
|
62
|
-
const closingIdx = afterOpen.indexOf("```");
|
|
63
|
-
const inner = closingIdx !== -1 ? afterOpen.slice(0, closingIdx) : afterOpen;
|
|
64
|
-
const innerTrimmed = inner.trim();
|
|
65
|
-
if (innerTrimmed.startsWith("{")) {
|
|
66
|
-
const lastBrace = innerTrimmed.lastIndexOf("}");
|
|
67
|
-
if (lastBrace !== -1) return innerTrimmed.slice(0, lastBrace + 1);
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
const firstOpen = trimmed.indexOf("{");
|
|
71
|
-
if (firstOpen !== -1) {
|
|
72
|
-
const balanced = extractBalancedObject(trimmed, firstOpen);
|
|
73
|
-
if (balanced) return balanced;
|
|
74
|
-
const lastClose = trimmed.lastIndexOf("}");
|
|
75
|
-
if (lastClose > firstOpen) return trimmed.slice(firstOpen, lastClose + 1);
|
|
76
|
-
}
|
|
77
|
-
return null;
|
|
78
|
-
}
|
|
79
|
-
function coerceString(v) {
|
|
80
|
-
return typeof v === "string" ? v : "";
|
|
81
|
-
}
|
|
82
|
-
function coerceDeepDive(v) {
|
|
83
|
-
if (!Array.isArray(v)) return [];
|
|
84
|
-
return v.filter((it) => typeof it === "object" && it !== null).map((it) => ({
|
|
85
|
-
term: coerceString(it.term),
|
|
86
|
-
explanation: coerceString(it.explanation)
|
|
87
|
-
})).filter((it) => it.term.length > 0);
|
|
88
|
-
}
|
|
89
|
-
function parseResponse(rawText) {
|
|
90
|
-
const json = extractJson(rawText);
|
|
91
|
-
if (!json) return null;
|
|
92
|
-
try {
|
|
93
|
-
const parsed = JSON.parse(json);
|
|
94
|
-
const risk = coerceString(parsed.risk);
|
|
95
|
-
if (!["none", "low", "medium", "high"].includes(risk)) return null;
|
|
96
|
-
return {
|
|
97
|
-
impact: coerceString(parsed.impact),
|
|
98
|
-
howItWorks: coerceString(parsed.howItWorks),
|
|
99
|
-
why: coerceString(parsed.why),
|
|
100
|
-
deepDive: coerceDeepDive(parsed.deepDive),
|
|
101
|
-
isSamePattern: parsed.isSamePattern === true,
|
|
102
|
-
samePatternNote: coerceString(parsed.samePatternNote),
|
|
103
|
-
risk,
|
|
104
|
-
riskReason: coerceString(parsed.riskReason)
|
|
105
|
-
};
|
|
106
|
-
} catch {
|
|
107
|
-
return null;
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
function truncateText(text, max) {
|
|
111
|
-
if (text.length <= max) return text;
|
|
112
|
-
return text.slice(0, max) + "...";
|
|
113
|
-
}
|
|
114
32
|
function runClaude(prompt, timeoutMs) {
|
|
115
33
|
return new Promise((resolve, reject) => {
|
|
116
34
|
const child = execFile(
|
|
@@ -145,14 +63,23 @@ function runClaude(prompt, timeoutMs) {
|
|
|
145
63
|
});
|
|
146
64
|
}
|
|
147
65
|
async function callClaude(inputs) {
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
66
|
+
let prompt;
|
|
67
|
+
try {
|
|
68
|
+
prompt = buildClaudePrompt(inputs.config.detailLevel, {
|
|
69
|
+
filePath: inputs.filePath,
|
|
70
|
+
diff: inputs.diff,
|
|
71
|
+
language: inputs.config.language,
|
|
72
|
+
learnerLevel: inputs.config.learnerLevel,
|
|
73
|
+
recentSummaries: inputs.recentSummaries
|
|
74
|
+
});
|
|
75
|
+
} catch (err) {
|
|
76
|
+
return {
|
|
77
|
+
kind: "error",
|
|
78
|
+
problem: "Failed to build Claude prompt",
|
|
79
|
+
cause: err.message || String(err),
|
|
80
|
+
fix: "Check detailLevel/learnerLevel/language values via 'npx vibe-code-explainer config'"
|
|
81
|
+
};
|
|
82
|
+
}
|
|
156
83
|
try {
|
|
157
84
|
const result = await runClaude(prompt, inputs.config.skipIfSlowMs);
|
|
158
85
|
if (result.code !== 0) {
|
|
@@ -321,6 +248,20 @@ function extractNewFileDiff(filePath, cwd) {
|
|
|
321
248
|
}
|
|
322
249
|
return { kind: "empty" };
|
|
323
250
|
}
|
|
251
|
+
function looksBinary(buf) {
|
|
252
|
+
const sample = buf.length > 8192 ? buf.subarray(0, 8192) : buf;
|
|
253
|
+
if (sample.length === 0) return false;
|
|
254
|
+
if (sample.indexOf(0) !== -1) return true;
|
|
255
|
+
let nonPrint = 0;
|
|
256
|
+
for (let i = 0; i < sample.length; i++) {
|
|
257
|
+
const b = sample[i];
|
|
258
|
+
if (b === 9 || b === 10 || b === 13 || b >= 32 && b <= 126 || b >= 128) {
|
|
259
|
+
continue;
|
|
260
|
+
}
|
|
261
|
+
nonPrint++;
|
|
262
|
+
}
|
|
263
|
+
return nonPrint / sample.length > 0.3;
|
|
264
|
+
}
|
|
324
265
|
function readFileAsNewDiff(filePath) {
|
|
325
266
|
if (!existsSync(filePath)) {
|
|
326
267
|
return { kind: "skip", reason: `file not found: ${filePath}` };
|
|
@@ -330,13 +271,17 @@ function readFileAsNewDiff(filePath) {
|
|
|
330
271
|
if (stat.size > 2 * 1024 * 1024) {
|
|
331
272
|
return { kind: "skip", reason: `file too large (${Math.round(stat.size / 1024)}KB)` };
|
|
332
273
|
}
|
|
333
|
-
const
|
|
334
|
-
if (
|
|
274
|
+
const buf = readFileSync(filePath);
|
|
275
|
+
if (buf.length === 0) {
|
|
335
276
|
return { kind: "empty" };
|
|
336
277
|
}
|
|
337
|
-
if (
|
|
278
|
+
if (looksBinary(buf)) {
|
|
338
279
|
return { kind: "binary", message: `Binary file created: ${filePath}` };
|
|
339
280
|
}
|
|
281
|
+
const raw = buf.toString("utf-8");
|
|
282
|
+
if (!raw.trim()) {
|
|
283
|
+
return { kind: "empty" };
|
|
284
|
+
}
|
|
340
285
|
const withMarkers = raw.split("\n").map((l) => `+ ${l}`).join("\n");
|
|
341
286
|
const diff = `--- /dev/null
|
|
342
287
|
+++ b/${filePath}
|
|
@@ -393,7 +338,32 @@ var MUTATING_COMMANDS = /* @__PURE__ */ new Set([
|
|
|
393
338
|
"chown",
|
|
394
339
|
"ln",
|
|
395
340
|
"touch",
|
|
396
|
-
"dd"
|
|
341
|
+
"dd",
|
|
342
|
+
"tee",
|
|
343
|
+
"install",
|
|
344
|
+
"truncate",
|
|
345
|
+
"shred",
|
|
346
|
+
"rsync",
|
|
347
|
+
"scp",
|
|
348
|
+
"sftp",
|
|
349
|
+
"mount",
|
|
350
|
+
"umount",
|
|
351
|
+
"kill",
|
|
352
|
+
"killall",
|
|
353
|
+
"pkill",
|
|
354
|
+
"crontab",
|
|
355
|
+
"useradd",
|
|
356
|
+
"userdel",
|
|
357
|
+
"usermod",
|
|
358
|
+
"groupadd",
|
|
359
|
+
"groupdel",
|
|
360
|
+
"passwd",
|
|
361
|
+
"chpasswd",
|
|
362
|
+
"visudo",
|
|
363
|
+
"systemctl",
|
|
364
|
+
"service",
|
|
365
|
+
"launchctl"
|
|
366
|
+
// Note: brew is in CONTEXTUAL_COMMANDS (finer-grained control); do not add here.
|
|
397
367
|
]);
|
|
398
368
|
var CONTEXTUAL_COMMANDS = {
|
|
399
369
|
npm: /\b(install|add|remove|uninstall|update|ci|link|unlink|init|publish)\b/,
|
|
@@ -480,9 +450,12 @@ function subCommandShouldCapture(subCmd) {
|
|
|
480
450
|
const rest = tokens.slice(idx + 1).join(" ");
|
|
481
451
|
return contextPattern.test(rest);
|
|
482
452
|
}
|
|
483
|
-
return
|
|
453
|
+
return true;
|
|
484
454
|
}
|
|
485
|
-
function shouldCaptureBash(command) {
|
|
455
|
+
function shouldCaptureBash(command, capturePatterns = []) {
|
|
456
|
+
if (capturePatterns.length > 0 && capturePatterns.some((p) => command.includes(p))) {
|
|
457
|
+
return true;
|
|
458
|
+
}
|
|
486
459
|
const parts = splitCommandChain(command);
|
|
487
460
|
return parts.some((p) => subCommandShouldCapture(p));
|
|
488
461
|
}
|
|
@@ -536,12 +509,11 @@ function shouldAlertDrift(entries) {
|
|
|
536
509
|
const unrelatedFiles = Array.from(
|
|
537
510
|
new Set(entries.filter((e) => e.unrelated).map((e) => e.file))
|
|
538
511
|
);
|
|
539
|
-
const shouldAlert = unrelatedFiles.length > 0 && unrelatedFiles.length % DRIFT_ALERT_THRESHOLD === 0 && entries.filter((e) => e.unrelated).length === entries.filter((e) => e.unrelated).length;
|
|
540
512
|
const lastEntry = entries[entries.length - 1];
|
|
541
513
|
const lastWasUnrelated = lastEntry?.unrelated ?? false;
|
|
542
|
-
const
|
|
514
|
+
const shouldAlert = lastWasUnrelated && unrelatedFiles.length === DRIFT_ALERT_THRESHOLD;
|
|
543
515
|
return {
|
|
544
|
-
shouldAlert
|
|
516
|
+
shouldAlert,
|
|
545
517
|
totalFiles: uniqueFiles.length,
|
|
546
518
|
unrelatedFiles
|
|
547
519
|
};
|
|
@@ -553,11 +525,14 @@ function addOutput(text) {
|
|
|
553
525
|
output.push(text);
|
|
554
526
|
}
|
|
555
527
|
function safeExit() {
|
|
556
|
-
if (output.length
|
|
557
|
-
|
|
558
|
-
process.stdout.write(JSON.stringify({ systemMessage }) + "\n");
|
|
528
|
+
if (output.length === 0) {
|
|
529
|
+
process.exit(0);
|
|
559
530
|
}
|
|
560
|
-
|
|
531
|
+
const systemMessage = "\n" + output.join("\n");
|
|
532
|
+
const payload = JSON.stringify({ systemMessage }) + "\n";
|
|
533
|
+
process.stdout.write(payload, () => process.exit(0));
|
|
534
|
+
setTimeout(() => process.exit(0), 500);
|
|
535
|
+
throw new Error("unreachable");
|
|
561
536
|
}
|
|
562
537
|
async function readStdin() {
|
|
563
538
|
return new Promise((resolve) => {
|
|
@@ -574,10 +549,11 @@ async function readStdin() {
|
|
|
574
549
|
function parsePayload(raw) {
|
|
575
550
|
try {
|
|
576
551
|
const parsed = JSON.parse(raw);
|
|
577
|
-
if (typeof parsed
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
return null;
|
|
552
|
+
if (typeof parsed !== "object" || parsed === null) return null;
|
|
553
|
+
if (!isSafeSessionId(parsed.session_id)) return null;
|
|
554
|
+
if (typeof parsed.tool_name !== "string") return null;
|
|
555
|
+
if (typeof parsed.tool_input !== "object" || parsed.tool_input === null) return null;
|
|
556
|
+
return parsed;
|
|
581
557
|
} catch {
|
|
582
558
|
return null;
|
|
583
559
|
}
|
|
@@ -596,14 +572,48 @@ function isHookEnabled(toolName, config) {
|
|
|
596
572
|
if (lower === "bash") return config.hooks.bash;
|
|
597
573
|
return false;
|
|
598
574
|
}
|
|
599
|
-
async function runEngine(filePath, diff, config,
|
|
575
|
+
async function runEngine(filePath, diff, config, recentSummaries, signal) {
|
|
600
576
|
if (signal.aborted) {
|
|
601
577
|
return { kind: "skip", reason: "interrupted by user" };
|
|
602
578
|
}
|
|
603
579
|
if (config.engine === "ollama") {
|
|
604
580
|
return callOllama({ filePath, diff, config, recentSummaries });
|
|
605
581
|
}
|
|
606
|
-
return callClaude({ filePath, diff, config,
|
|
582
|
+
return callClaude({ filePath, diff, config, recentSummaries });
|
|
583
|
+
}
|
|
584
|
+
function buildEditWriteDiff(payload, config, cwd) {
|
|
585
|
+
const lowerTool = payload.tool_name.toLowerCase();
|
|
586
|
+
const input = payload.tool_input;
|
|
587
|
+
const target = input.file_path ?? input.filePath;
|
|
588
|
+
if (!target) {
|
|
589
|
+
safeExit();
|
|
590
|
+
}
|
|
591
|
+
const filePath = target;
|
|
592
|
+
if (isExcluded(filePath, config.exclude)) {
|
|
593
|
+
safeExit();
|
|
594
|
+
}
|
|
595
|
+
let result;
|
|
596
|
+
if (lowerTool === "edit") {
|
|
597
|
+
const oldStr = input.old_string ?? input.oldString ?? "";
|
|
598
|
+
const newStr = input.new_string ?? input.newString ?? "";
|
|
599
|
+
result = oldStr || newStr ? buildDiffFromEdit(filePath, oldStr, newStr) : extractEditDiff(filePath, cwd);
|
|
600
|
+
} else if (lowerTool === "multiedit") {
|
|
601
|
+
result = input.edits && input.edits.length > 0 ? buildDiffFromMultiEdit(filePath, input.edits) : extractEditDiff(filePath, cwd);
|
|
602
|
+
} else {
|
|
603
|
+
result = extractNewFileDiff(filePath, cwd);
|
|
604
|
+
}
|
|
605
|
+
if (result.kind === "empty") {
|
|
606
|
+
safeExit();
|
|
607
|
+
}
|
|
608
|
+
if (result.kind === "skip") {
|
|
609
|
+
addOutput(formatSkipNotice(result.reason));
|
|
610
|
+
safeExit();
|
|
611
|
+
}
|
|
612
|
+
if (result.kind === "binary") {
|
|
613
|
+
addOutput(formatSkipNotice(result.message));
|
|
614
|
+
safeExit();
|
|
615
|
+
}
|
|
616
|
+
return { filePath, diff: result.content };
|
|
607
617
|
}
|
|
608
618
|
async function main() {
|
|
609
619
|
const controller = new AbortController();
|
|
@@ -625,48 +635,20 @@ async function main() {
|
|
|
625
635
|
let diff;
|
|
626
636
|
const lowerTool = payload.tool_name.toLowerCase();
|
|
627
637
|
if (lowerTool === "edit" || lowerTool === "multiedit" || lowerTool === "write") {
|
|
628
|
-
const
|
|
629
|
-
const target = input.file_path ?? input.filePath;
|
|
638
|
+
const target = buildEditWriteDiff(payload, config, cwd);
|
|
630
639
|
if (!target) safeExit();
|
|
631
|
-
filePath = target;
|
|
632
|
-
if (isExcluded(filePath, config.exclude)) safeExit();
|
|
633
|
-
let result2;
|
|
634
|
-
if (lowerTool === "edit") {
|
|
635
|
-
const oldStr = input.old_string ?? input.oldString ?? "";
|
|
636
|
-
const newStr = input.new_string ?? input.newString ?? "";
|
|
637
|
-
if (oldStr || newStr) {
|
|
638
|
-
result2 = buildDiffFromEdit(filePath, oldStr, newStr);
|
|
639
|
-
} else {
|
|
640
|
-
result2 = extractEditDiff(filePath, cwd);
|
|
641
|
-
}
|
|
642
|
-
} else if (lowerTool === "multiedit") {
|
|
643
|
-
if (input.edits && input.edits.length > 0) {
|
|
644
|
-
result2 = buildDiffFromMultiEdit(filePath, input.edits);
|
|
645
|
-
} else {
|
|
646
|
-
result2 = extractEditDiff(filePath, cwd);
|
|
647
|
-
}
|
|
648
|
-
} else {
|
|
649
|
-
result2 = extractNewFileDiff(filePath, cwd);
|
|
650
|
-
}
|
|
651
|
-
if (result2.kind === "empty") safeExit();
|
|
652
|
-
if (result2.kind === "skip") {
|
|
653
|
-
addOutput(formatSkipNotice(result2.reason));
|
|
654
|
-
safeExit();
|
|
655
|
-
}
|
|
656
|
-
if (result2.kind === "binary") {
|
|
657
|
-
addOutput(formatSkipNotice(result2.message));
|
|
658
|
-
safeExit();
|
|
659
|
-
}
|
|
660
|
-
diff = result2.content;
|
|
640
|
+
({ filePath, diff } = target);
|
|
661
641
|
} else if (lowerTool === "bash") {
|
|
662
642
|
const input = payload.tool_input;
|
|
663
643
|
const command = input.command ?? "";
|
|
664
|
-
if (!command || !shouldCaptureBash(command)) safeExit();
|
|
644
|
+
if (!command || !shouldCaptureBash(command, config.bashFilter.capturePatterns)) safeExit();
|
|
665
645
|
filePath = "<bash command>";
|
|
666
646
|
diff = command;
|
|
667
647
|
} else {
|
|
668
648
|
safeExit();
|
|
669
649
|
}
|
|
650
|
+
const isBash = filePath === "<bash command>";
|
|
651
|
+
const priorEntries = isBash ? [] : readSession(payload.session_id);
|
|
670
652
|
const cacheKey = `${filePath}
|
|
671
653
|
${diff}`;
|
|
672
654
|
const cached = getCached(payload.session_id, cacheKey);
|
|
@@ -674,15 +656,8 @@ ${diff}`;
|
|
|
674
656
|
if (cached) {
|
|
675
657
|
result = cached;
|
|
676
658
|
} else {
|
|
677
|
-
const recentSummaries = getRecentSummaries(payload.session_id, 3);
|
|
678
|
-
const outcome = await runEngine(
|
|
679
|
-
filePath,
|
|
680
|
-
diff,
|
|
681
|
-
config,
|
|
682
|
-
void 0,
|
|
683
|
-
recentSummaries,
|
|
684
|
-
controller.signal
|
|
685
|
-
);
|
|
659
|
+
const recentSummaries = getRecentSummaries(payload.session_id, 3, priorEntries);
|
|
660
|
+
const outcome = await runEngine(filePath, diff, config, recentSummaries, controller.signal);
|
|
686
661
|
if (outcome.kind === "skip") {
|
|
687
662
|
addOutput(formatSkipNotice(outcome.reason));
|
|
688
663
|
safeExit();
|
|
@@ -695,8 +670,7 @@ ${diff}`;
|
|
|
695
670
|
setCached(payload.session_id, cacheKey, result);
|
|
696
671
|
}
|
|
697
672
|
let driftReason;
|
|
698
|
-
if (
|
|
699
|
-
const priorEntries = readSession(payload.session_id);
|
|
673
|
+
if (!isBash) {
|
|
700
674
|
const analysis = analyzeDrift(filePath, priorEntries);
|
|
701
675
|
if (analysis.isUnrelated) {
|
|
702
676
|
driftReason = analysis.reason;
|
|
@@ -718,8 +692,15 @@ ${diff}`;
|
|
|
718
692
|
summary: summaryForTracking,
|
|
719
693
|
unrelated: !!driftReason
|
|
720
694
|
});
|
|
721
|
-
const
|
|
722
|
-
|
|
695
|
+
const entryJustRecorded = {
|
|
696
|
+
file: filePath,
|
|
697
|
+
timestamp: Date.now(),
|
|
698
|
+
risk: result.risk,
|
|
699
|
+
summary: summaryForTracking,
|
|
700
|
+
unrelated: !!driftReason
|
|
701
|
+
};
|
|
702
|
+
const updatedEntries = [...priorEntries, entryJustRecorded];
|
|
703
|
+
const driftCheck = shouldAlertDrift(updatedEntries);
|
|
723
704
|
if (driftCheck.shouldAlert) {
|
|
724
705
|
addOutput(formatDriftAlert(driftCheck.totalFiles, driftCheck.unrelatedFiles, void 0, config.language));
|
|
725
706
|
}
|