@codacy/verity-cli 0.23.3 → 0.24.0-experimental.9a9e918
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/bin/verity.js +526 -167
- package/data/skills/verity-reflect/SKILL.md +60 -24
- package/data/skills/verity-setup/SKILL.md +19 -6
- package/package.json +1 -1
package/bin/verity.js
CHANGED
|
@@ -10379,6 +10379,7 @@ var MAX_PLAN_FILES = 3;
|
|
|
10379
10379
|
var MAX_PLAN_FILE_BYTES = 10240;
|
|
10380
10380
|
var MAX_INTENT_CHARS = 2e3;
|
|
10381
10381
|
var SNAPSHOT_DIR = `${VERITY_DIR}/.snapshot`;
|
|
10382
|
+
var BASELINE_DIR = `${VERITY_DIR}/.baseline`;
|
|
10382
10383
|
var CONVERSATION_BUFFER_FILE = `${VERITY_DIR}/.conversation-buffer`;
|
|
10383
10384
|
var CONVERSATION_MAX_ENTRIES = 10;
|
|
10384
10385
|
var CONVERSATION_WINDOW_MINUTES = 15;
|
|
@@ -10473,7 +10474,8 @@ var SECURITY_PATTERNS = [
|
|
|
10473
10474
|
/Cargo\.lock$/,
|
|
10474
10475
|
/Dockerfile/
|
|
10475
10476
|
];
|
|
10476
|
-
var
|
|
10477
|
+
var PROD_SERVICE_URL = "https://ofcamwrjwrkazqvdchko.supabase.co/functions/v1";
|
|
10478
|
+
var DEFAULT_SERVICE_URL = "https://yykkfdexzljmmkklpgyz.supabase.co/functions/v1".length > 0 ? "https://yykkfdexzljmmkklpgyz.supabase.co/functions/v1" : PROD_SERVICE_URL;
|
|
10477
10479
|
|
|
10478
10480
|
// src/lib/auth.ts
|
|
10479
10481
|
async function resolveToken(flagToken) {
|
|
@@ -10848,6 +10850,10 @@ var VERITY_INTENT_HOOK = {
|
|
|
10848
10850
|
type: "command",
|
|
10849
10851
|
command: "verity intent capture"
|
|
10850
10852
|
};
|
|
10853
|
+
var VERITY_BASELINE_HOOK = {
|
|
10854
|
+
type: "command",
|
|
10855
|
+
command: "verity baseline capture"
|
|
10856
|
+
};
|
|
10851
10857
|
var GUARD_TIMEOUT = 300;
|
|
10852
10858
|
function buildGuardHook(on) {
|
|
10853
10859
|
return {
|
|
@@ -10860,9 +10866,13 @@ function buildGuardHook(on) {
|
|
|
10860
10866
|
var VERITY_STOP_RE = /(?:^|[\/\s"'])verity\s+analyze\b/;
|
|
10861
10867
|
var VERITY_INTENT_RE = /(?:^|[\/\s"'])verity\s+intent\s+capture\b/;
|
|
10862
10868
|
var VERITY_GUARD_RE = /(?:^|[\/\s"'])verity\s+guard\b/;
|
|
10869
|
+
var VERITY_BASELINE_RE = /(?:^|[\/\s"'])verity\s+baseline\s+capture\b/;
|
|
10863
10870
|
function isVerityGuardHook(entry) {
|
|
10864
10871
|
return VERITY_GUARD_RE.test(entry.command ?? "");
|
|
10865
10872
|
}
|
|
10873
|
+
function isVerityBaselineHook(entry) {
|
|
10874
|
+
return VERITY_BASELINE_RE.test(entry.command ?? "");
|
|
10875
|
+
}
|
|
10866
10876
|
var LEGACY_STOP_RE = /(?:^|[\/\s"'])gate\s+analyze\b/;
|
|
10867
10877
|
var LEGACY_INTENT_RE = /(?:^|[\/\s"'])gate\s+intent\s+capture\b/;
|
|
10868
10878
|
function isVerityStopHook(entry) {
|
|
@@ -10874,7 +10884,7 @@ function isVerityIntentHook(entry) {
|
|
|
10874
10884
|
return VERITY_INTENT_RE.test(c) || LEGACY_INTENT_RE.test(c) || c.includes(".verity/hooks/capture-intent.sh") || c.includes(".gate/hooks/capture-intent.sh");
|
|
10875
10885
|
}
|
|
10876
10886
|
function isVerityHook(entry) {
|
|
10877
|
-
return isVerityStopHook(entry) || isVerityIntentHook(entry) || isVerityGuardHook(entry);
|
|
10887
|
+
return isVerityStopHook(entry) || isVerityIntentHook(entry) || isVerityGuardHook(entry) || isVerityBaselineHook(entry);
|
|
10878
10888
|
}
|
|
10879
10889
|
function isCurrentVerityStopHook(entry) {
|
|
10880
10890
|
const c = entry.command ?? "";
|
|
@@ -10885,7 +10895,7 @@ function isCurrentVerityIntentHook(entry) {
|
|
|
10885
10895
|
return VERITY_INTENT_RE.test(c) || c.includes(".verity/hooks/capture-intent.sh");
|
|
10886
10896
|
}
|
|
10887
10897
|
function isCurrentVerityHook(entry) {
|
|
10888
|
-
return isCurrentVerityStopHook(entry) || isCurrentVerityIntentHook(entry) || isVerityGuardHook(entry);
|
|
10898
|
+
return isCurrentVerityStopHook(entry) || isCurrentVerityIntentHook(entry) || isVerityGuardHook(entry) || isVerityBaselineHook(entry);
|
|
10889
10899
|
}
|
|
10890
10900
|
function settingsHasLegacyHook(settings) {
|
|
10891
10901
|
for (const groups of Object.values(settings.hooks ?? {})) {
|
|
@@ -10927,16 +10937,18 @@ async function readAllSettings() {
|
|
|
10927
10937
|
async function checkAllVerityHooks() {
|
|
10928
10938
|
let stop = false;
|
|
10929
10939
|
let intent = false;
|
|
10940
|
+
let baseline = false;
|
|
10930
10941
|
let guard = false;
|
|
10931
10942
|
let guardOn = [];
|
|
10932
10943
|
for (const settings of await readAllSettings()) {
|
|
10933
10944
|
const r = checkVerityHooks(settings);
|
|
10934
10945
|
stop = stop || r.stop;
|
|
10935
10946
|
intent = intent || r.intent;
|
|
10947
|
+
baseline = baseline || r.baseline;
|
|
10936
10948
|
guard = guard || r.guard;
|
|
10937
10949
|
if (r.guardOn.length > guardOn.length) guardOn = r.guardOn;
|
|
10938
10950
|
}
|
|
10939
|
-
return { stop, intent, guard, guardOn };
|
|
10951
|
+
return { stop, intent, baseline, guard, guardOn };
|
|
10940
10952
|
}
|
|
10941
10953
|
async function checkExternalVerityHooks() {
|
|
10942
10954
|
let stop = false;
|
|
@@ -10959,12 +10971,14 @@ async function checkExternalVerityHooks() {
|
|
|
10959
10971
|
async function checkAllVerityHooksDetailed() {
|
|
10960
10972
|
let stop = false;
|
|
10961
10973
|
let intent = false;
|
|
10974
|
+
let baseline = false;
|
|
10962
10975
|
let hasCurrent = false;
|
|
10963
10976
|
let hasLegacy = false;
|
|
10964
10977
|
for (const settings of await readAllSettings()) {
|
|
10965
10978
|
const r = checkVerityHooks(settings);
|
|
10966
10979
|
stop = stop || r.stop;
|
|
10967
10980
|
intent = intent || r.intent;
|
|
10981
|
+
baseline = baseline || r.baseline;
|
|
10968
10982
|
for (const groups of Object.values(settings.hooks ?? {})) {
|
|
10969
10983
|
for (const g of groups ?? []) {
|
|
10970
10984
|
for (const h of g.hooks ?? []) {
|
|
@@ -10974,7 +10988,7 @@ async function checkAllVerityHooksDetailed() {
|
|
|
10974
10988
|
}
|
|
10975
10989
|
}
|
|
10976
10990
|
}
|
|
10977
|
-
return { stop, intent, current: hasCurrent, legacyOnly: hasLegacy && !hasCurrent };
|
|
10991
|
+
return { stop, intent, baseline, current: hasCurrent, legacyOnly: hasLegacy && !hasCurrent };
|
|
10978
10992
|
}
|
|
10979
10993
|
async function writeSettings(settings) {
|
|
10980
10994
|
await (0, import_promises4.mkdir)((0, import_node_path3.dirname)(CLAUDE_SETTINGS_FILE), { recursive: true });
|
|
@@ -11017,6 +11031,10 @@ function checkVerityHooks(settings) {
|
|
|
11017
11031
|
const hasIntent = intentGroups.some(
|
|
11018
11032
|
(g) => g.hooks?.some((h) => isCurrentVerityIntentHook(h))
|
|
11019
11033
|
);
|
|
11034
|
+
const sessionStartGroups = hooks["SessionStart"] ?? [];
|
|
11035
|
+
const hasBaseline = sessionStartGroups.some(
|
|
11036
|
+
(g) => g.hooks?.some((h) => isVerityBaselineHook(h))
|
|
11037
|
+
);
|
|
11020
11038
|
let guard = false;
|
|
11021
11039
|
let guardOn = [];
|
|
11022
11040
|
for (const g of hooks["PreToolUse"] ?? []) {
|
|
@@ -11029,16 +11047,17 @@ function checkVerityHooks(settings) {
|
|
|
11029
11047
|
}
|
|
11030
11048
|
}
|
|
11031
11049
|
}
|
|
11032
|
-
return { stop: hasStop, intent: hasIntent, guard, guardOn };
|
|
11050
|
+
return { stop: hasStop, intent: hasIntent, baseline: hasBaseline, guard, guardOn };
|
|
11033
11051
|
}
|
|
11034
|
-
function installVerityHooks(settings, force, externalPresent = { stop: false, intent: false }) {
|
|
11052
|
+
function installVerityHooks(settings, force, externalPresent = { stop: false, intent: false, baseline: false }) {
|
|
11035
11053
|
const local = checkVerityHooks(settings);
|
|
11036
11054
|
const existing = {
|
|
11037
11055
|
stop: local.stop || externalPresent.stop,
|
|
11038
|
-
intent: local.intent || externalPresent.intent
|
|
11056
|
+
intent: local.intent || externalPresent.intent,
|
|
11057
|
+
baseline: local.baseline || (externalPresent.baseline ?? false)
|
|
11039
11058
|
};
|
|
11040
11059
|
const hasLocalLegacy = settingsHasLegacyHook(settings);
|
|
11041
|
-
if (existing.stop && existing.intent && !force && !hasLocalLegacy) {
|
|
11060
|
+
if (existing.stop && existing.intent && existing.baseline && !force && !hasLocalLegacy) {
|
|
11042
11061
|
return { ok: false, error: "Verity hooks already installed. Use --force to overwrite." };
|
|
11043
11062
|
}
|
|
11044
11063
|
const newSettings = { ...settings };
|
|
@@ -11046,7 +11065,7 @@ function installVerityHooks(settings, force, externalPresent = { stop: false, in
|
|
|
11046
11065
|
newSettings.hooks = {};
|
|
11047
11066
|
}
|
|
11048
11067
|
const shouldStrip = force ? isVerityHook : isLegacyHook;
|
|
11049
|
-
for (const key of ["Stop", "UserPromptSubmit"]) {
|
|
11068
|
+
for (const key of ["Stop", "UserPromptSubmit", "SessionStart"]) {
|
|
11050
11069
|
const groups = newSettings.hooks[key];
|
|
11051
11070
|
if (groups) {
|
|
11052
11071
|
newSettings.hooks[key] = groups.map((g) => ({
|
|
@@ -11073,6 +11092,15 @@ function installVerityHooks(settings, force, externalPresent = { stop: false, in
|
|
|
11073
11092
|
if (!newSettings.hooks["UserPromptSubmit"]) newSettings.hooks["UserPromptSubmit"] = [];
|
|
11074
11093
|
newSettings.hooks["UserPromptSubmit"].push({ hooks: [VERITY_INTENT_HOOK] });
|
|
11075
11094
|
}
|
|
11095
|
+
if (!existing.baseline) {
|
|
11096
|
+
if (!newSettings.hooks["SessionStart"]) {
|
|
11097
|
+
newSettings.hooks["SessionStart"] = [];
|
|
11098
|
+
}
|
|
11099
|
+
newSettings.hooks["SessionStart"].push({ hooks: [VERITY_BASELINE_HOOK] });
|
|
11100
|
+
} else if (force && local.baseline) {
|
|
11101
|
+
if (!newSettings.hooks["SessionStart"]) newSettings.hooks["SessionStart"] = [];
|
|
11102
|
+
newSettings.hooks["SessionStart"].push({ hooks: [VERITY_BASELINE_HOOK] });
|
|
11103
|
+
}
|
|
11076
11104
|
return { ok: true, data: newSettings };
|
|
11077
11105
|
}
|
|
11078
11106
|
function removeVerityHooks(settings) {
|
|
@@ -11106,6 +11134,7 @@ function reconcileMomentHooks(settings, moments, externalPresent = {
|
|
|
11106
11134
|
(s.hooks[event] ??= []).push(group);
|
|
11107
11135
|
};
|
|
11108
11136
|
if (!externalPresent.intent) push("UserPromptSubmit", { hooks: [VERITY_INTENT_HOOK] });
|
|
11137
|
+
push("SessionStart", { hooks: [VERITY_BASELINE_HOOK] });
|
|
11109
11138
|
if (moments.includes("stop") && !externalPresent.stop) {
|
|
11110
11139
|
push("Stop", { hooks: [VERITY_STOP_HOOK] });
|
|
11111
11140
|
}
|
|
@@ -11154,7 +11183,7 @@ function registerHooksCommands(program2) {
|
|
|
11154
11183
|
return;
|
|
11155
11184
|
}
|
|
11156
11185
|
const detail = await checkAllVerityHooksDetailed();
|
|
11157
|
-
const present = { stop: detail.stop, intent: detail.intent };
|
|
11186
|
+
const present = { stop: detail.stop, intent: detail.intent, baseline: detail.baseline };
|
|
11158
11187
|
if (detail.legacyOnly) {
|
|
11159
11188
|
printInfo("Found a legacy GATE.md hook \u2014 upgrading it to Verity...");
|
|
11160
11189
|
const settings2 = removeVerityHooks(await readSettings());
|
|
@@ -11167,11 +11196,12 @@ function registerHooksCommands(program2) {
|
|
|
11167
11196
|
printInfo("Verity hooks installed in .claude/settings.json (legacy hook removed)");
|
|
11168
11197
|
printInfo(" Stop hook: verity analyze");
|
|
11169
11198
|
printInfo(" UserPromptSubmit hook: verity intent capture");
|
|
11199
|
+
printInfo(" SessionStart hook: verity baseline capture");
|
|
11170
11200
|
return;
|
|
11171
11201
|
}
|
|
11172
11202
|
const settings = await readSettings();
|
|
11173
11203
|
const hasLocalLegacy = settingsHasLegacyHook(settings);
|
|
11174
|
-
if (!force && present.stop && present.intent && !hasLocalLegacy) {
|
|
11204
|
+
if (!force && present.stop && present.intent && present.baseline && !hasLocalLegacy) {
|
|
11175
11205
|
printInfo("Verity hooks already installed (found in .claude/settings.json, settings.local.json, or your global settings).");
|
|
11176
11206
|
printInfo("Use --force to rewrite the project settings.json copy.");
|
|
11177
11207
|
return;
|
|
@@ -11185,11 +11215,13 @@ function registerHooksCommands(program2) {
|
|
|
11185
11215
|
printInfo("Verity hooks installed in .claude/settings.json");
|
|
11186
11216
|
printInfo(" Stop hook: verity analyze");
|
|
11187
11217
|
printInfo(" UserPromptSubmit hook: verity intent capture");
|
|
11218
|
+
printInfo(" SessionStart hook: verity baseline capture");
|
|
11188
11219
|
});
|
|
11189
11220
|
hooks.command("check").description("Check if Verity hooks are installed").action(async () => {
|
|
11190
11221
|
const status = await checkAllVerityHooks();
|
|
11191
11222
|
printInfo(`Stop hook (verity analyze): ${status.stop ? "installed" : "not installed"}`);
|
|
11192
11223
|
printInfo(`Intent hook (verity intent capture): ${status.intent ? "installed" : "not installed"}`);
|
|
11224
|
+
printInfo(`Baseline hook (verity baseline capture): ${status.baseline ? "installed" : "not installed"}`);
|
|
11193
11225
|
const gates = status.guard ? status.guardOn.join(", ") : "none";
|
|
11194
11226
|
printInfo(`Git-moment gate (verity guard): ${status.guard ? `installed [${gates}]` : "not installed"}`);
|
|
11195
11227
|
if (!status.stop && !status.guard) {
|
|
@@ -11242,15 +11274,28 @@ async function appendToConversationBuffer(prompt, sessionId) {
|
|
|
11242
11274
|
} catch {
|
|
11243
11275
|
}
|
|
11244
11276
|
}
|
|
11245
|
-
async function readAndClearConversationBuffer() {
|
|
11277
|
+
async function readAndClearConversationBuffer(currentSessionId) {
|
|
11246
11278
|
try {
|
|
11247
11279
|
if ((0, import_node_fs2.existsSync)(CONVERSATION_BUFFER_FILE)) {
|
|
11248
11280
|
const entries = await readBufferEntries();
|
|
11249
|
-
|
|
11250
|
-
|
|
11251
|
-
if (
|
|
11281
|
+
let mine = entries;
|
|
11282
|
+
let others = [];
|
|
11283
|
+
if (currentSessionId) {
|
|
11284
|
+
mine = entries.filter((e) => e.session_id === currentSessionId || !e.session_id);
|
|
11285
|
+
others = entries.filter((e) => e.session_id && e.session_id !== currentSessionId);
|
|
11286
|
+
}
|
|
11287
|
+
if (others.length > 0) {
|
|
11288
|
+
const remaining = others.map((e) => JSON.stringify(e)).join("\n") + "\n";
|
|
11289
|
+
const tmpFile = `${CONVERSATION_BUFFER_FILE}.tmp`;
|
|
11290
|
+
await (0, import_promises5.writeFile)(tmpFile, remaining);
|
|
11291
|
+
await (0, import_promises5.rename)(tmpFile, CONVERSATION_BUFFER_FILE);
|
|
11292
|
+
} else {
|
|
11293
|
+
await (0, import_promises5.unlink)(CONVERSATION_BUFFER_FILE).catch(() => {
|
|
11294
|
+
});
|
|
11295
|
+
}
|
|
11296
|
+
if (mine.length > 0) {
|
|
11252
11297
|
return {
|
|
11253
|
-
prompts:
|
|
11298
|
+
prompts: mine,
|
|
11254
11299
|
recent_commits: getRecentCommitMessages()
|
|
11255
11300
|
};
|
|
11256
11301
|
}
|
|
@@ -12718,8 +12763,8 @@ async function sendGeneralFeedback(message, opts, globals) {
|
|
|
12718
12763
|
}
|
|
12719
12764
|
|
|
12720
12765
|
// src/commands/analyze.ts
|
|
12721
|
-
var
|
|
12722
|
-
var
|
|
12766
|
+
var import_node_fs19 = require("node:fs");
|
|
12767
|
+
var import_node_path14 = require("node:path");
|
|
12723
12768
|
|
|
12724
12769
|
// src/lib/git.ts
|
|
12725
12770
|
var import_node_child_process5 = require("node:child_process");
|
|
@@ -12811,6 +12856,26 @@ function getChangedFiles() {
|
|
|
12811
12856
|
function getStagedFiles() {
|
|
12812
12857
|
return splitLines(execGit("git diff --cached --name-only")).filter((f) => !f.startsWith(".verity/") && !f.startsWith(".verity\\"));
|
|
12813
12858
|
}
|
|
12859
|
+
function getDirtyFiles() {
|
|
12860
|
+
const set = /* @__PURE__ */ new Set();
|
|
12861
|
+
for (const f of splitLines(execGit("git diff --name-only HEAD"))) set.add(f);
|
|
12862
|
+
for (const f of splitLines(execGit("git diff --name-only --cached"))) set.add(f);
|
|
12863
|
+
for (const f of splitLines(execGit("git ls-files --others --exclude-standard"))) set.add(f);
|
|
12864
|
+
return Array.from(set).filter((f) => !f.startsWith(".verity/") && !f.startsWith(".verity\\"));
|
|
12865
|
+
}
|
|
12866
|
+
function showContentAtRef(ref, repoRelPath) {
|
|
12867
|
+
if (!ref || ref === "no-git") return null;
|
|
12868
|
+
const normalizedPath = repoRelPath.replace(/\\/g, "/");
|
|
12869
|
+
try {
|
|
12870
|
+
return (0, import_node_child_process5.execFileSync)("git", ["show", `${ref}:${normalizedPath}`], {
|
|
12871
|
+
encoding: "utf-8",
|
|
12872
|
+
maxBuffer: 64 * 1024 * 1024,
|
|
12873
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
12874
|
+
});
|
|
12875
|
+
} catch {
|
|
12876
|
+
return null;
|
|
12877
|
+
}
|
|
12878
|
+
}
|
|
12814
12879
|
function getPushRangeFiles() {
|
|
12815
12880
|
const diff = (range) => splitLines(execGit(`git diff --name-only ${range}`)).filter((f) => !f.startsWith(".verity/") && !f.startsWith(".verity\\"));
|
|
12816
12881
|
const resolvers = [
|
|
@@ -13463,15 +13528,207 @@ function cleanStaleSnapshots(dir, keepSet) {
|
|
|
13463
13528
|
}
|
|
13464
13529
|
}
|
|
13465
13530
|
|
|
13466
|
-
// src/lib/
|
|
13531
|
+
// src/lib/baseline.ts
|
|
13467
13532
|
var import_node_fs13 = require("node:fs");
|
|
13533
|
+
var import_node_path11 = require("node:path");
|
|
13468
13534
|
var import_node_crypto4 = require("node:crypto");
|
|
13535
|
+
var BASELINE_VERSION = 1;
|
|
13536
|
+
var BASELINE_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
13537
|
+
var MIRROR_MAX_BYTES = 2 * 1024 * 1024;
|
|
13538
|
+
var DEFAULT_SESSION_KEY = "_default";
|
|
13539
|
+
function sessionKey(sessionId) {
|
|
13540
|
+
if (!sessionId) return DEFAULT_SESSION_KEY;
|
|
13541
|
+
return (0, import_node_crypto4.createHash)("sha256").update(sessionId).digest("hex").slice(0, 16);
|
|
13542
|
+
}
|
|
13543
|
+
function sessionDir(key) {
|
|
13544
|
+
return (0, import_node_path11.join)(projectPath(BASELINE_DIR), key);
|
|
13545
|
+
}
|
|
13546
|
+
function manifestPath(dir) {
|
|
13547
|
+
return (0, import_node_path11.join)(dir, "manifest.json");
|
|
13548
|
+
}
|
|
13549
|
+
function mirrorPath(dir, repoRelPath) {
|
|
13550
|
+
return (0, import_node_path11.join)(dir, "files", repoRelPath);
|
|
13551
|
+
}
|
|
13552
|
+
function captureBaseline(opts = {}) {
|
|
13553
|
+
const key = sessionKey(opts.sessionId);
|
|
13554
|
+
const dir = sessionDir(key);
|
|
13555
|
+
const existing = readManifest(dir);
|
|
13556
|
+
const freshStart = opts.source === "startup" || opts.source === "clear";
|
|
13557
|
+
if (existing && !freshStart) {
|
|
13558
|
+
return { baseline: existing, created: false };
|
|
13559
|
+
}
|
|
13560
|
+
const head_sha = getCurrentCommit();
|
|
13561
|
+
const dirty = getDirtyFiles();
|
|
13562
|
+
try {
|
|
13563
|
+
(0, import_node_fs13.rmSync)(dir, { recursive: true, force: true });
|
|
13564
|
+
} catch {
|
|
13565
|
+
}
|
|
13566
|
+
const filesDir = (0, import_node_path11.join)(dir, "files");
|
|
13567
|
+
const mirrored = [];
|
|
13568
|
+
try {
|
|
13569
|
+
(0, import_node_fs13.mkdirSync)(filesDir, { recursive: true });
|
|
13570
|
+
for (const p of dirty) {
|
|
13571
|
+
if (p.includes("..")) continue;
|
|
13572
|
+
const content = safeReadForMirror(projectPath(p));
|
|
13573
|
+
if (content === null) continue;
|
|
13574
|
+
const dest = mirrorPath(dir, p);
|
|
13575
|
+
try {
|
|
13576
|
+
(0, import_node_fs13.mkdirSync)((0, import_node_path11.dirname)(dest), { recursive: true });
|
|
13577
|
+
(0, import_node_fs13.writeFileSync)(dest, content);
|
|
13578
|
+
mirrored.push(p);
|
|
13579
|
+
} catch {
|
|
13580
|
+
}
|
|
13581
|
+
}
|
|
13582
|
+
} catch {
|
|
13583
|
+
}
|
|
13584
|
+
const baseline = {
|
|
13585
|
+
session_id: opts.sessionId ?? "",
|
|
13586
|
+
head_sha,
|
|
13587
|
+
captured_at: Date.now(),
|
|
13588
|
+
dirty_paths: mirrored,
|
|
13589
|
+
version: BASELINE_VERSION
|
|
13590
|
+
};
|
|
13591
|
+
try {
|
|
13592
|
+
(0, import_node_fs13.mkdirSync)(dir, { recursive: true });
|
|
13593
|
+
(0, import_node_fs13.writeFileSync)(manifestPath(dir), JSON.stringify(baseline));
|
|
13594
|
+
} catch {
|
|
13595
|
+
}
|
|
13596
|
+
pruneOldBaselines();
|
|
13597
|
+
return { baseline, created: true };
|
|
13598
|
+
}
|
|
13599
|
+
function readBaseline(sessionId) {
|
|
13600
|
+
return readManifest(sessionDir(sessionKey(sessionId)));
|
|
13601
|
+
}
|
|
13602
|
+
function readManifest(dir) {
|
|
13603
|
+
const mp = manifestPath(dir);
|
|
13604
|
+
if (!(0, import_node_fs13.existsSync)(mp)) return null;
|
|
13605
|
+
try {
|
|
13606
|
+
const parsed = JSON.parse((0, import_node_fs13.readFileSync)(mp, "utf-8"));
|
|
13607
|
+
if (typeof parsed.head_sha !== "string" || typeof parsed.captured_at !== "number" || !Array.isArray(parsed.dirty_paths) || parsed.version !== BASELINE_VERSION) {
|
|
13608
|
+
return null;
|
|
13609
|
+
}
|
|
13610
|
+
return {
|
|
13611
|
+
session_id: typeof parsed.session_id === "string" ? parsed.session_id : "",
|
|
13612
|
+
head_sha: parsed.head_sha,
|
|
13613
|
+
captured_at: parsed.captured_at,
|
|
13614
|
+
dirty_paths: parsed.dirty_paths.filter((p) => typeof p === "string"),
|
|
13615
|
+
version: parsed.version
|
|
13616
|
+
};
|
|
13617
|
+
} catch {
|
|
13618
|
+
return null;
|
|
13619
|
+
}
|
|
13620
|
+
}
|
|
13621
|
+
var preImageCache = /* @__PURE__ */ new WeakMap();
|
|
13622
|
+
function preImage(repoRelPath, baseline) {
|
|
13623
|
+
let perBaseline = preImageCache.get(baseline);
|
|
13624
|
+
if (!perBaseline) {
|
|
13625
|
+
perBaseline = /* @__PURE__ */ new Map();
|
|
13626
|
+
preImageCache.set(baseline, perBaseline);
|
|
13627
|
+
}
|
|
13628
|
+
const cached = perBaseline.get(repoRelPath);
|
|
13629
|
+
if (cached) return cached;
|
|
13630
|
+
const resolved = resolvePreImage(repoRelPath, baseline);
|
|
13631
|
+
perBaseline.set(repoRelPath, resolved);
|
|
13632
|
+
return resolved;
|
|
13633
|
+
}
|
|
13634
|
+
function resolvePreImage(repoRelPath, baseline) {
|
|
13635
|
+
if (baseline.dirty_paths.includes(repoRelPath)) {
|
|
13636
|
+
const mp = mirrorPath(sessionDir(sessionKey(baseline.session_id)), repoRelPath);
|
|
13637
|
+
if ((0, import_node_fs13.existsSync)(mp)) {
|
|
13638
|
+
try {
|
|
13639
|
+
return { content: (0, import_node_fs13.readFileSync)(mp, "utf-8"), existed: true };
|
|
13640
|
+
} catch {
|
|
13641
|
+
}
|
|
13642
|
+
}
|
|
13643
|
+
}
|
|
13644
|
+
const atHead = showContentAtRef(baseline.head_sha, repoRelPath);
|
|
13645
|
+
if (atHead !== null) return { content: atHead, existed: true };
|
|
13646
|
+
return { content: "", existed: false };
|
|
13647
|
+
}
|
|
13648
|
+
function generateBaselineDiffs(files, baseline) {
|
|
13649
|
+
if (!baseline) return { diffs: [], has_baseline: false };
|
|
13650
|
+
const diffs = [];
|
|
13651
|
+
for (const file of files) {
|
|
13652
|
+
const language = file.language ?? detectLanguage(file.path);
|
|
13653
|
+
const pre = preImage(file.path, baseline);
|
|
13654
|
+
if (pre.existed) {
|
|
13655
|
+
if (pre.content === file.content) continue;
|
|
13656
|
+
const diff = computeDiff(pre.content, file.content, file.path);
|
|
13657
|
+
if (diff) diffs.push({ path: file.path, language, diff, status: "modified" });
|
|
13658
|
+
} else {
|
|
13659
|
+
const addedLines = file.content.split("\n").map((l) => `+${l}`).join("\n");
|
|
13660
|
+
diffs.push({
|
|
13661
|
+
path: file.path,
|
|
13662
|
+
language,
|
|
13663
|
+
diff: `--- /dev/null
|
|
13664
|
+
+++ b/${file.path}
|
|
13665
|
+
@@ -0,0 +1,${file.content.split("\n").length} @@
|
|
13666
|
+
${addedLines}`,
|
|
13667
|
+
status: "added"
|
|
13668
|
+
});
|
|
13669
|
+
}
|
|
13670
|
+
}
|
|
13671
|
+
return { diffs, has_baseline: true };
|
|
13672
|
+
}
|
|
13673
|
+
function changedSinceBaseline(repoRelPath, baseline) {
|
|
13674
|
+
const pre = preImage(repoRelPath, baseline);
|
|
13675
|
+
let current;
|
|
13676
|
+
try {
|
|
13677
|
+
current = (0, import_node_fs13.readFileSync)(projectPath(repoRelPath), "utf-8");
|
|
13678
|
+
} catch {
|
|
13679
|
+
return pre.existed;
|
|
13680
|
+
}
|
|
13681
|
+
if (!pre.existed) return true;
|
|
13682
|
+
return current !== pre.content;
|
|
13683
|
+
}
|
|
13684
|
+
function safeReadForMirror(absPath) {
|
|
13685
|
+
try {
|
|
13686
|
+
if ((0, import_node_fs13.statSync)(absPath).size > MIRROR_MAX_BYTES) return null;
|
|
13687
|
+
const buf = (0, import_node_fs13.readFileSync)(absPath);
|
|
13688
|
+
if (buf.includes(0)) return null;
|
|
13689
|
+
return buf.toString("utf-8");
|
|
13690
|
+
} catch {
|
|
13691
|
+
return null;
|
|
13692
|
+
}
|
|
13693
|
+
}
|
|
13694
|
+
function pruneOldBaselines() {
|
|
13695
|
+
const root = projectPath(BASELINE_DIR);
|
|
13696
|
+
let entries;
|
|
13697
|
+
try {
|
|
13698
|
+
entries = (0, import_node_fs13.readdirSync)(root);
|
|
13699
|
+
} catch {
|
|
13700
|
+
return;
|
|
13701
|
+
}
|
|
13702
|
+
const now = Date.now();
|
|
13703
|
+
for (const name of entries) {
|
|
13704
|
+
const dir = (0, import_node_path11.join)(root, name);
|
|
13705
|
+
const manifest = readManifest(dir);
|
|
13706
|
+
if (!manifest) {
|
|
13707
|
+
try {
|
|
13708
|
+
if (now - (0, import_node_fs13.statSync)(dir).mtimeMs > BASELINE_TTL_MS) {
|
|
13709
|
+
(0, import_node_fs13.rmSync)(dir, { recursive: true, force: true });
|
|
13710
|
+
}
|
|
13711
|
+
} catch {
|
|
13712
|
+
}
|
|
13713
|
+
continue;
|
|
13714
|
+
}
|
|
13715
|
+
if (now - manifest.captured_at <= BASELINE_TTL_MS) continue;
|
|
13716
|
+
try {
|
|
13717
|
+
(0, import_node_fs13.rmSync)(dir, { recursive: true, force: true });
|
|
13718
|
+
} catch {
|
|
13719
|
+
}
|
|
13720
|
+
}
|
|
13721
|
+
}
|
|
13722
|
+
|
|
13723
|
+
// src/lib/offline.ts
|
|
13724
|
+
var import_node_fs14 = require("node:fs");
|
|
13725
|
+
var import_node_crypto5 = require("node:crypto");
|
|
13469
13726
|
function cacheRequest(body) {
|
|
13470
13727
|
try {
|
|
13471
|
-
(0,
|
|
13472
|
-
const suffix = (0,
|
|
13728
|
+
(0, import_node_fs14.mkdirSync)(CACHE_DIR, { recursive: true });
|
|
13729
|
+
const suffix = (0, import_node_crypto5.randomBytes)(4).toString("hex");
|
|
13473
13730
|
const filename = `pending-${Math.floor(Date.now() / 1e3)}-${suffix}.json`;
|
|
13474
|
-
(0,
|
|
13731
|
+
(0, import_node_fs14.writeFileSync)(`${CACHE_DIR}/${filename}`, JSON.stringify(body));
|
|
13475
13732
|
} catch {
|
|
13476
13733
|
}
|
|
13477
13734
|
}
|
|
@@ -13485,7 +13742,7 @@ function buildOfflineFallback(reason, staticResults) {
|
|
|
13485
13742
|
}
|
|
13486
13743
|
|
|
13487
13744
|
// src/lib/context-files.ts
|
|
13488
|
-
var
|
|
13745
|
+
var import_node_fs15 = require("node:fs");
|
|
13489
13746
|
var MAX_CONTEXT_FILES = 10;
|
|
13490
13747
|
var MAX_CONTEXT_FILE_BYTES = 10240;
|
|
13491
13748
|
var MAX_CONTEXT_TOTAL_BYTES = 51200;
|
|
@@ -13497,7 +13754,7 @@ function gatherContextFiles(contextPaths, deltaFiles) {
|
|
|
13497
13754
|
if (result.length >= MAX_CONTEXT_FILES) break;
|
|
13498
13755
|
if (deltaPaths.has(filePath)) continue;
|
|
13499
13756
|
try {
|
|
13500
|
-
const content = (0,
|
|
13757
|
+
const content = (0, import_node_fs15.readFileSync)(filePath, "utf8");
|
|
13501
13758
|
const bytes = Buffer.byteLength(content);
|
|
13502
13759
|
if (bytes > MAX_CONTEXT_FILE_BYTES) {
|
|
13503
13760
|
logEvent("context_file_skipped", { path: filePath, reason: "too_large", bytes });
|
|
@@ -13542,20 +13799,20 @@ function gatherContextFiles(contextPaths, deltaFiles) {
|
|
|
13542
13799
|
}
|
|
13543
13800
|
|
|
13544
13801
|
// src/lib/cache-cleanup.ts
|
|
13545
|
-
var
|
|
13546
|
-
var
|
|
13802
|
+
var import_node_fs16 = require("node:fs");
|
|
13803
|
+
var import_node_path12 = require("node:path");
|
|
13547
13804
|
var CACHE_TTL_DAYS = 7;
|
|
13548
13805
|
function pruneStaleCache() {
|
|
13549
13806
|
try {
|
|
13550
13807
|
const dir = projectPath(CACHE_DIR);
|
|
13551
13808
|
const cutoff = Date.now() - CACHE_TTL_DAYS * 24 * 3600 * 1e3;
|
|
13552
|
-
for (const entry of (0,
|
|
13809
|
+
for (const entry of (0, import_node_fs16.readdirSync)(dir)) {
|
|
13553
13810
|
if (!entry.startsWith("pending-")) continue;
|
|
13554
|
-
const path = (0,
|
|
13811
|
+
const path = (0, import_node_path12.join)(dir, entry);
|
|
13555
13812
|
try {
|
|
13556
|
-
const stat3 = (0,
|
|
13813
|
+
const stat3 = (0, import_node_fs16.statSync)(path);
|
|
13557
13814
|
if (stat3.mtimeMs < cutoff) {
|
|
13558
|
-
(0,
|
|
13815
|
+
(0, import_node_fs16.unlinkSync)(path);
|
|
13559
13816
|
logEvent("cache_entry_pruned", {
|
|
13560
13817
|
path: entry,
|
|
13561
13818
|
age_days: Math.round((Date.now() - stat3.mtimeMs) / 864e5)
|
|
@@ -13627,10 +13884,11 @@ function reconcileAnalysisMode(predictedMode, signals) {
|
|
|
13627
13884
|
signals.noFilesChanged,
|
|
13628
13885
|
signals.assistantResponse,
|
|
13629
13886
|
signals.conversationPrompts,
|
|
13630
|
-
signals.actionSummary
|
|
13887
|
+
signals.actionSummary,
|
|
13888
|
+
signals.sessionAuthoredCode
|
|
13631
13889
|
);
|
|
13632
13890
|
}
|
|
13633
|
-
const agentAuthoredCode = !!(signals.actionSummary && (signals.actionSummary.files_edited.length > 0 || signals.actionSummary.files_created.length > 0));
|
|
13891
|
+
const agentAuthoredCode = !!(signals.actionSummary && (signals.actionSummary.files_edited.length > 0 || signals.actionSummary.files_created.length > 0)) || !!signals.sessionAuthoredCode;
|
|
13634
13892
|
const agentInvestigated = didAgentInvestigate(signals.actionSummary);
|
|
13635
13893
|
switch (predictedMode) {
|
|
13636
13894
|
case "skip":
|
|
@@ -13655,8 +13913,8 @@ function didAgentInvestigate(summary) {
|
|
|
13655
13913
|
function isValidMode(mode) {
|
|
13656
13914
|
return mode === "standard" || mode === "plan" || mode === "debug" || mode === "skip";
|
|
13657
13915
|
}
|
|
13658
|
-
function detectAnalysisMode(noFilesChanged, assistantResponse, conversationPrompts, actionSummary) {
|
|
13659
|
-
const agentAuthoredCode = !!(actionSummary && (actionSummary.files_edited.length > 0 || actionSummary.files_created.length > 0));
|
|
13916
|
+
function detectAnalysisMode(noFilesChanged, assistantResponse, conversationPrompts, actionSummary, sessionAuthoredCode) {
|
|
13917
|
+
const agentAuthoredCode = !!(actionSummary && (actionSummary.files_edited.length > 0 || actionSummary.files_created.length > 0)) || !!sessionAuthoredCode;
|
|
13660
13918
|
if (conversationPrompts.length > 0 && conversationPrompts.every(isGitOnlyPrompt)) {
|
|
13661
13919
|
if (!agentAuthoredCode) return "skip";
|
|
13662
13920
|
}
|
|
@@ -13710,7 +13968,12 @@ function isReflectionQuestion(response) {
|
|
|
13710
13968
|
/reflection\s+for\s+future\s+agents/i,
|
|
13711
13969
|
/what(?:'s|\s+is)\s+one\s+thing\s+you\s+learned/i,
|
|
13712
13970
|
/say\s+['"]?skip['"]?\s+to\s+skip/i,
|
|
13713
|
-
/quick\s+reflection\s+question/i
|
|
13971
|
+
/quick\s+reflection\s+question/i,
|
|
13972
|
+
// Post-flip (VRT-21): the agent drafts the reflection itself and, when
|
|
13973
|
+
// interactive, asks the user to confirm/correct before recording. That
|
|
13974
|
+
// turn authors no code either, so it's still a reflection turn.
|
|
13975
|
+
/reflection\s+draft/i,
|
|
13976
|
+
/confirm,?\s+correct,?\s+or\s+add/i
|
|
13714
13977
|
];
|
|
13715
13978
|
return markers.some((m) => m.test(response));
|
|
13716
13979
|
}
|
|
@@ -13731,7 +13994,7 @@ function isMetaTaskLabel(label2) {
|
|
|
13731
13994
|
}
|
|
13732
13995
|
|
|
13733
13996
|
// src/lib/transcript.ts
|
|
13734
|
-
var
|
|
13997
|
+
var import_node_fs17 = require("node:fs");
|
|
13735
13998
|
var MAX_READ_BYTES = 256 * 1024;
|
|
13736
13999
|
var SMALL_FILE_BYTES = 64 * 1024;
|
|
13737
14000
|
var MAX_FILES_LIST = 20;
|
|
@@ -13753,14 +14016,14 @@ async function extractActionSummary(transcriptPath) {
|
|
|
13753
14016
|
function readTurnLines(transcriptPath) {
|
|
13754
14017
|
let size;
|
|
13755
14018
|
try {
|
|
13756
|
-
size = (0,
|
|
14019
|
+
size = (0, import_node_fs17.statSync)(transcriptPath).size;
|
|
13757
14020
|
} catch {
|
|
13758
14021
|
return null;
|
|
13759
14022
|
}
|
|
13760
14023
|
if (size === 0) return null;
|
|
13761
14024
|
let raw;
|
|
13762
14025
|
if (size <= SMALL_FILE_BYTES) {
|
|
13763
|
-
raw = (0,
|
|
14026
|
+
raw = (0, import_node_fs17.readFileSync)(transcriptPath, "utf-8");
|
|
13764
14027
|
} else {
|
|
13765
14028
|
const buf = Buffer.alloc(Math.min(MAX_READ_BYTES, size));
|
|
13766
14029
|
const fd = require("node:fs").openSync(transcriptPath, "r");
|
|
@@ -13848,6 +14111,12 @@ function buildSummary(lines) {
|
|
|
13848
14111
|
case "Edit":
|
|
13849
14112
|
addPath(filesEdited, input.file_path);
|
|
13850
14113
|
break;
|
|
14114
|
+
case "MultiEdit":
|
|
14115
|
+
addPath(filesEdited, input.file_path);
|
|
14116
|
+
break;
|
|
14117
|
+
case "NotebookEdit":
|
|
14118
|
+
addPath(filesEdited, input.notebook_path ?? input.file_path);
|
|
14119
|
+
break;
|
|
13851
14120
|
case "Write":
|
|
13852
14121
|
addPath(filesCreated, input.file_path);
|
|
13853
14122
|
addPath(filesEdited, input.file_path);
|
|
@@ -13931,8 +14200,8 @@ function capArray(set, max) {
|
|
|
13931
14200
|
|
|
13932
14201
|
// src/lib/seed-runner.ts
|
|
13933
14202
|
var import_promises11 = require("node:fs/promises");
|
|
13934
|
-
var
|
|
13935
|
-
var
|
|
14203
|
+
var import_node_fs18 = require("node:fs");
|
|
14204
|
+
var import_node_path13 = require("node:path");
|
|
13936
14205
|
var import_yaml2 = __toESM(require_dist());
|
|
13937
14206
|
|
|
13938
14207
|
// src/lib/seed.ts
|
|
@@ -14171,7 +14440,7 @@ function renderNodeMarkdown(candidate, nodeId, createdAt) {
|
|
|
14171
14440
|
return fm;
|
|
14172
14441
|
}
|
|
14173
14442
|
async function runSeed(opts) {
|
|
14174
|
-
if (!(0,
|
|
14443
|
+
if (!(0, import_node_fs18.existsSync)(STANDARD_FILE)) {
|
|
14175
14444
|
return { created: 0, failed: 0, skipped: "no_standard", candidates: [] };
|
|
14176
14445
|
}
|
|
14177
14446
|
let standardDoc;
|
|
@@ -14183,7 +14452,7 @@ async function runSeed(opts) {
|
|
|
14183
14452
|
}
|
|
14184
14453
|
const knowledgeSpec = standardDoc.knowledge_spec ?? {};
|
|
14185
14454
|
let readmeContent;
|
|
14186
|
-
if ((0,
|
|
14455
|
+
if ((0, import_node_fs18.existsSync)("README.md")) {
|
|
14187
14456
|
try {
|
|
14188
14457
|
readmeContent = await (0, import_promises11.readFile)("README.md", "utf-8");
|
|
14189
14458
|
} catch {
|
|
@@ -14191,7 +14460,7 @@ async function runSeed(opts) {
|
|
|
14191
14460
|
}
|
|
14192
14461
|
let claudeMdContent;
|
|
14193
14462
|
for (const p of ["CLAUDE.md", ".claude/CLAUDE.md"]) {
|
|
14194
|
-
if ((0,
|
|
14463
|
+
if ((0, import_node_fs18.existsSync)(p)) {
|
|
14195
14464
|
try {
|
|
14196
14465
|
claudeMdContent = await (0, import_promises11.readFile)(p, "utf-8");
|
|
14197
14466
|
break;
|
|
@@ -14214,8 +14483,8 @@ async function runSeed(opts) {
|
|
|
14214
14483
|
if (candidates.length === 0) {
|
|
14215
14484
|
return { created: 0, failed: 0, skipped: "no_candidates", candidates: [] };
|
|
14216
14485
|
}
|
|
14217
|
-
const overviewPath = (0,
|
|
14218
|
-
if ((0,
|
|
14486
|
+
const overviewPath = (0, import_node_path13.join)(MEMORY_DIR, "domain", "project-overview.md");
|
|
14487
|
+
if ((0, import_node_fs18.existsSync)(overviewPath) && !opts.force) {
|
|
14219
14488
|
return { created: 0, failed: 0, skipped: "already_seeded", candidates };
|
|
14220
14489
|
}
|
|
14221
14490
|
if (opts.dryRun) {
|
|
@@ -14250,9 +14519,9 @@ async function runSeed(opts) {
|
|
|
14250
14519
|
}
|
|
14251
14520
|
const nodeId = res.data.node_id;
|
|
14252
14521
|
const filePathRel = res.data.file_path;
|
|
14253
|
-
const targetPath = (0,
|
|
14522
|
+
const targetPath = (0, import_node_path13.join)(MEMORY_DIR, filePathRel);
|
|
14254
14523
|
try {
|
|
14255
|
-
await (0, import_promises11.mkdir)((0,
|
|
14524
|
+
await (0, import_promises11.mkdir)((0, import_node_path13.dirname)(targetPath), { recursive: true });
|
|
14256
14525
|
await (0, import_promises11.writeFile)(targetPath, renderNodeMarkdown(c, nodeId, createdAt));
|
|
14257
14526
|
created++;
|
|
14258
14527
|
opts.onCreated?.(nodeId, filePathRel, c);
|
|
@@ -14322,6 +14591,15 @@ async function runAnalyze(opts, globals) {
|
|
|
14322
14591
|
}
|
|
14323
14592
|
const { assistantMessage: assistantResponse, stopReason, transcriptPath, sessionId } = await readStopHookStdin();
|
|
14324
14593
|
const actionSummary = transcriptPath ? await extractActionSummary(transcriptPath) : null;
|
|
14594
|
+
const baselineSessionId = sessionId || process.env.CLAUDE_SESSION_ID || void 0;
|
|
14595
|
+
const baseline = readBaseline(baselineSessionId);
|
|
14596
|
+
if (baseline) {
|
|
14597
|
+
logEvent("baseline_loaded", {
|
|
14598
|
+
head: baseline.head_sha.slice(0, 12),
|
|
14599
|
+
dirty_count: baseline.dirty_paths.length,
|
|
14600
|
+
age_ms: Date.now() - baseline.captured_at
|
|
14601
|
+
});
|
|
14602
|
+
}
|
|
14325
14603
|
const { files: allChanged, hasRecentCommitFiles } = getChangedFiles();
|
|
14326
14604
|
const analyzable = filterAnalyzable(allChanged);
|
|
14327
14605
|
const reviewable = filterReviewable(allChanged);
|
|
@@ -14331,7 +14609,7 @@ async function runAnalyze(opts, globals) {
|
|
|
14331
14609
|
passAndExit("No analyzable files changed");
|
|
14332
14610
|
}
|
|
14333
14611
|
const allForReview = Array.from(/* @__PURE__ */ new Set([...analyzable, ...reviewable]));
|
|
14334
|
-
const conversation = await readAndClearConversationBuffer();
|
|
14612
|
+
const conversation = await readAndClearConversationBuffer(sessionId ?? void 0);
|
|
14335
14613
|
const specs = discoverSpecs();
|
|
14336
14614
|
const plans = discoverPlans();
|
|
14337
14615
|
const latestPrompt = conversation?.prompts?.[conversation.prompts.length - 1]?.prompt ?? "";
|
|
@@ -14381,13 +14659,14 @@ async function runAnalyze(opts, globals) {
|
|
|
14381
14659
|
}
|
|
14382
14660
|
const conversationPrompts = (conversation?.prompts ?? []).map((p) => p.prompt);
|
|
14383
14661
|
let analysisMode;
|
|
14662
|
+
const sessionAuthoredCode = !!baseline && allForReview.some((f) => changedSinceBaseline(f, baseline));
|
|
14384
14663
|
const modeOverride = opts.mode;
|
|
14385
14664
|
if (modeOverride && ["standard", "plan", "debug", "skip"].includes(modeOverride)) {
|
|
14386
14665
|
analysisMode = modeOverride;
|
|
14387
14666
|
} else {
|
|
14388
14667
|
analysisMode = reconcileAnalysisMode(
|
|
14389
14668
|
predictedMode,
|
|
14390
|
-
{ noFilesChanged, assistantResponse, actionSummary, conversationPrompts }
|
|
14669
|
+
{ noFilesChanged, assistantResponse, actionSummary, conversationPrompts, sessionAuthoredCode }
|
|
14391
14670
|
);
|
|
14392
14671
|
}
|
|
14393
14672
|
if (analysisMode === "skip") {
|
|
@@ -14445,10 +14724,16 @@ async function runAnalyze(opts, globals) {
|
|
|
14445
14724
|
const baseForReview = agentNarrowed.length > 0 ? agentNarrowed : allForReview;
|
|
14446
14725
|
const recentForReview = narrowToRecent(baseForReview);
|
|
14447
14726
|
if (!opts.skipStatic && isCodacyAvailable()) {
|
|
14448
|
-
|
|
14449
|
-
|
|
14727
|
+
let allScannable = Array.from(/* @__PURE__ */ new Set([...analyzable, ...securityFiles]));
|
|
14728
|
+
if (baseline) {
|
|
14729
|
+
allScannable = allScannable.filter((f) => changedSinceBaseline(f, baseline));
|
|
14730
|
+
}
|
|
14731
|
+
if (allScannable.length > 0) {
|
|
14732
|
+
staticResults = runCodacyAnalysis(allScannable);
|
|
14733
|
+
}
|
|
14450
14734
|
}
|
|
14451
|
-
|
|
14735
|
+
const deltaSet = baseline ? recentForReview.filter((f) => changedSinceBaseline(f, baseline)) : recentForReview;
|
|
14736
|
+
codeDelta = collectCodeDelta(deltaSet, {
|
|
14452
14737
|
maxFiles: parseInt(opts.maxFiles, 10),
|
|
14453
14738
|
maxFileBytes: parseInt(opts.maxFileSize, 10),
|
|
14454
14739
|
maxTotalBytes: parseInt(opts.maxTotalSize, 10)
|
|
@@ -14463,7 +14748,12 @@ async function runAnalyze(opts, globals) {
|
|
|
14463
14748
|
}
|
|
14464
14749
|
}
|
|
14465
14750
|
if (analysisMode !== "plan") {
|
|
14466
|
-
|
|
14751
|
+
if (baseline) {
|
|
14752
|
+
const baselineDiffs = generateBaselineDiffs(codeDelta.files, baseline);
|
|
14753
|
+
snapshotResult = { has_snapshots: baselineDiffs.diffs.length > 0, diffs: baselineDiffs.diffs };
|
|
14754
|
+
} else {
|
|
14755
|
+
snapshotResult = generateSnapshotDiffs(codeDelta.files);
|
|
14756
|
+
}
|
|
14467
14757
|
currentCommit = getCurrentCommit();
|
|
14468
14758
|
const maxIterations = parseInt(opts.maxIterations, 10);
|
|
14469
14759
|
const iterResult = checkMaxIterations(currentCommit, maxIterations, contentHash ?? void 0);
|
|
@@ -14495,9 +14785,9 @@ async function runAnalyze(opts, globals) {
|
|
|
14495
14785
|
let autoSeedNotice = null;
|
|
14496
14786
|
try {
|
|
14497
14787
|
await ensureMemoryDir();
|
|
14498
|
-
const seedMarker = (0,
|
|
14499
|
-
const hasStandard = (0,
|
|
14500
|
-
const alreadyTried = (0,
|
|
14788
|
+
const seedMarker = (0, import_node_path14.join)(VERITY_DIR, ".seeded");
|
|
14789
|
+
const hasStandard = (0, import_node_fs19.existsSync)(STANDARD_FILE);
|
|
14790
|
+
const alreadyTried = (0, import_node_fs19.existsSync)(seedMarker);
|
|
14501
14791
|
if (hasStandard && !alreadyTried) {
|
|
14502
14792
|
const preManifest = await buildManifest();
|
|
14503
14793
|
if (preManifest.nodes.length === 0) {
|
|
@@ -14510,7 +14800,7 @@ async function runAnalyze(opts, globals) {
|
|
|
14510
14800
|
dryRun: false
|
|
14511
14801
|
});
|
|
14512
14802
|
if (seedResult.created > 0) {
|
|
14513
|
-
(0,
|
|
14803
|
+
(0, import_node_fs19.writeFileSync)(seedMarker, `${(/* @__PURE__ */ new Date()).toISOString()} created=${seedResult.created}
|
|
14514
14804
|
`);
|
|
14515
14805
|
autoSeedNotice = `Seeded ${seedResult.created} knowledge node(s) from your existing Standard (one-time).`;
|
|
14516
14806
|
logEvent("auto_seed_ran", {
|
|
@@ -14518,7 +14808,7 @@ async function runAnalyze(opts, globals) {
|
|
|
14518
14808
|
failed: seedResult.failed
|
|
14519
14809
|
});
|
|
14520
14810
|
} else if (seedResult.skipped === "already_seeded") {
|
|
14521
|
-
(0,
|
|
14811
|
+
(0, import_node_fs19.writeFileSync)(seedMarker, `${(/* @__PURE__ */ new Date()).toISOString()} skipped=already_seeded
|
|
14522
14812
|
`);
|
|
14523
14813
|
} else {
|
|
14524
14814
|
logEvent("auto_seed_noop", {
|
|
@@ -14836,8 +15126,54 @@ async function runAnalyze(opts, globals) {
|
|
|
14836
15126
|
}
|
|
14837
15127
|
}
|
|
14838
15128
|
|
|
15129
|
+
// src/commands/baseline.ts
|
|
15130
|
+
var import_node_fs20 = require("node:fs");
|
|
15131
|
+
function registerBaselineCommands(program2) {
|
|
15132
|
+
const baseline = program2.command("baseline").description("Manage the task-start working-tree baseline");
|
|
15133
|
+
baseline.command("capture").description("Snapshot the working tree at task start (used by SessionStart hook)").option("--session-id <id>", "Session id (overrides any value from stdin)").option("--source <source>", "Lifecycle hint: startup|resume|clear|compact").action(async (opts) => {
|
|
15134
|
+
try {
|
|
15135
|
+
try {
|
|
15136
|
+
process.chdir(repoRoot());
|
|
15137
|
+
} catch {
|
|
15138
|
+
}
|
|
15139
|
+
if (!(0, import_node_fs20.existsSync)(VERITY_DIR)) {
|
|
15140
|
+
process.exit(0);
|
|
15141
|
+
}
|
|
15142
|
+
let sessionId = opts.sessionId;
|
|
15143
|
+
let source = opts.source;
|
|
15144
|
+
if (!process.stdin.isTTY) {
|
|
15145
|
+
const input = (await readStdin()).trim();
|
|
15146
|
+
if (input) {
|
|
15147
|
+
try {
|
|
15148
|
+
const event = JSON.parse(input);
|
|
15149
|
+
sessionId = sessionId ?? event.session_id;
|
|
15150
|
+
source = source ?? event.source;
|
|
15151
|
+
} catch {
|
|
15152
|
+
}
|
|
15153
|
+
}
|
|
15154
|
+
}
|
|
15155
|
+
const result = captureBaseline({ sessionId, source });
|
|
15156
|
+
logEvent("baseline_capture", {
|
|
15157
|
+
created: result.created,
|
|
15158
|
+
source: source ?? null,
|
|
15159
|
+
dirty_count: result.baseline.dirty_paths.length,
|
|
15160
|
+
head: result.baseline.head_sha.slice(0, 12)
|
|
15161
|
+
});
|
|
15162
|
+
} catch {
|
|
15163
|
+
}
|
|
15164
|
+
process.exit(0);
|
|
15165
|
+
});
|
|
15166
|
+
}
|
|
15167
|
+
async function readStdin() {
|
|
15168
|
+
const chunks = [];
|
|
15169
|
+
for await (const chunk of process.stdin) {
|
|
15170
|
+
chunks.push(chunk);
|
|
15171
|
+
}
|
|
15172
|
+
return Buffer.concat(chunks).toString("utf-8");
|
|
15173
|
+
}
|
|
15174
|
+
|
|
14839
15175
|
// src/commands/review.ts
|
|
14840
|
-
var
|
|
15176
|
+
var import_node_fs21 = require("node:fs");
|
|
14841
15177
|
function registerReviewCommand(program2) {
|
|
14842
15178
|
program2.command("review").description("Run on-demand Verity analysis (advisory, never blocks)").requiredOption("--files <paths>", "Comma-separated file list").option("--changed <paths>", "Subset of --files that were modified").option("--intent <text>", "User intent description (max 2000 chars)").option("--specs <paths>", "Comma-separated spec file paths").option("--json", "Output raw JSON response").action(async (opts) => {
|
|
14843
15179
|
const globals = program2.opts();
|
|
@@ -14856,7 +15192,7 @@ async function runReview(opts, globals) {
|
|
|
14856
15192
|
const securityFiles = filterSecurity(allFiles);
|
|
14857
15193
|
let staticResults;
|
|
14858
15194
|
if (isCodacyAvailable()) {
|
|
14859
|
-
const scannable = Array.from(/* @__PURE__ */ new Set([...analyzable, ...securityFiles])).filter((f) => (0,
|
|
15195
|
+
const scannable = Array.from(/* @__PURE__ */ new Set([...analyzable, ...securityFiles])).filter((f) => (0, import_node_fs21.existsSync)(f) || resolveFile(f) !== null);
|
|
14860
15196
|
staticResults = runCodacyAnalysis(scannable);
|
|
14861
15197
|
} else {
|
|
14862
15198
|
staticResults = {
|
|
@@ -14881,10 +15217,10 @@ async function runReview(opts, globals) {
|
|
|
14881
15217
|
const specPaths = opts.specs.split(",").map((f) => f.trim()).filter(Boolean);
|
|
14882
15218
|
specs = [];
|
|
14883
15219
|
for (const p of specPaths) {
|
|
14884
|
-
if (!(0,
|
|
15220
|
+
if (!(0, import_node_fs21.existsSync)(p)) continue;
|
|
14885
15221
|
try {
|
|
14886
|
-
const { readFileSync:
|
|
14887
|
-
const content =
|
|
15222
|
+
const { readFileSync: readFileSync12 } = await import("node:fs");
|
|
15223
|
+
const content = readFileSync12(p, "utf-8");
|
|
14888
15224
|
specs.push({ path: p, content: content.slice(0, 10240) });
|
|
14889
15225
|
} catch {
|
|
14890
15226
|
}
|
|
@@ -14941,10 +15277,10 @@ async function runReview(opts, globals) {
|
|
|
14941
15277
|
}
|
|
14942
15278
|
|
|
14943
15279
|
// src/commands/guard.ts
|
|
14944
|
-
var
|
|
14945
|
-
var
|
|
15280
|
+
var import_node_fs22 = require("node:fs");
|
|
15281
|
+
var import_node_path15 = require("node:path");
|
|
14946
15282
|
var GUARD_BLOCK_CAP = 2;
|
|
14947
|
-
var GUARD_ITER_FILE = (0,
|
|
15283
|
+
var GUARD_ITER_FILE = (0, import_node_path15.join)(VERITY_DIR, ".guard-iteration");
|
|
14948
15284
|
function readPreToolUseStdin() {
|
|
14949
15285
|
const empty = { command: "", cwd: null, sessionId: null };
|
|
14950
15286
|
return new Promise((resolve) => {
|
|
@@ -15008,7 +15344,7 @@ function classifyCommand(command, on) {
|
|
|
15008
15344
|
}
|
|
15009
15345
|
function readIterMap() {
|
|
15010
15346
|
try {
|
|
15011
|
-
const raw = JSON.parse((0,
|
|
15347
|
+
const raw = JSON.parse((0, import_node_fs22.readFileSync)(GUARD_ITER_FILE, "utf-8"));
|
|
15012
15348
|
if (raw && typeof raw === "object") {
|
|
15013
15349
|
if (typeof raw.moment === "string" && typeof raw.count === "number") {
|
|
15014
15350
|
return { [raw.moment]: raw.count };
|
|
@@ -15028,10 +15364,10 @@ function readIter(moment) {
|
|
|
15028
15364
|
}
|
|
15029
15365
|
function writeIter(moment, count) {
|
|
15030
15366
|
try {
|
|
15031
|
-
(0,
|
|
15367
|
+
(0, import_node_fs22.mkdirSync)(VERITY_DIR, { recursive: true });
|
|
15032
15368
|
const map = readIterMap();
|
|
15033
15369
|
map[moment] = count;
|
|
15034
|
-
(0,
|
|
15370
|
+
(0, import_node_fs22.writeFileSync)(GUARD_ITER_FILE, JSON.stringify(map));
|
|
15035
15371
|
} catch {
|
|
15036
15372
|
}
|
|
15037
15373
|
}
|
|
@@ -15041,10 +15377,10 @@ function resetIter(moment) {
|
|
|
15041
15377
|
if (!(moment in map)) return;
|
|
15042
15378
|
delete map[moment];
|
|
15043
15379
|
if (Object.keys(map).length === 0) {
|
|
15044
|
-
if ((0,
|
|
15380
|
+
if ((0, import_node_fs22.existsSync)(GUARD_ITER_FILE)) (0, import_node_fs22.unlinkSync)(GUARD_ITER_FILE);
|
|
15045
15381
|
} else {
|
|
15046
|
-
(0,
|
|
15047
|
-
(0,
|
|
15382
|
+
(0, import_node_fs22.mkdirSync)(VERITY_DIR, { recursive: true });
|
|
15383
|
+
(0, import_node_fs22.writeFileSync)(GUARD_ITER_FILE, JSON.stringify(map));
|
|
15048
15384
|
}
|
|
15049
15385
|
} catch {
|
|
15050
15386
|
}
|
|
@@ -15108,7 +15444,7 @@ function buildGuardRequest(moment, files, iter, sessionId, command) {
|
|
|
15108
15444
|
const securityFiles = filterSecurity(files);
|
|
15109
15445
|
let staticResults;
|
|
15110
15446
|
if (isCodacyAvailable()) {
|
|
15111
|
-
const scannable = Array.from(/* @__PURE__ */ new Set([...analyzable, ...securityFiles])).map((f) => (0,
|
|
15447
|
+
const scannable = Array.from(/* @__PURE__ */ new Set([...analyzable, ...securityFiles])).map((f) => (0, import_node_fs22.existsSync)(f) ? f : resolveFile(f)).filter((f) => f !== null);
|
|
15112
15448
|
staticResults = runCodacyAnalysis(scannable);
|
|
15113
15449
|
} else {
|
|
15114
15450
|
staticResults = { tool: "@codacy/analysis-cli", findings: [], summary: { total_findings: 0, by_severity: {}, tools_run: [] } };
|
|
@@ -15153,7 +15489,7 @@ function emitAllowNotice(userMsg, agentMsg) {
|
|
|
15153
15489
|
async function runGuard(opts, globals) {
|
|
15154
15490
|
const on = opts.on.split(",").map((s) => s.trim()).filter((s) => s === "commit" || s === "push");
|
|
15155
15491
|
const { command, cwd, sessionId } = await readPreToolUseStdin();
|
|
15156
|
-
if (cwd && (0,
|
|
15492
|
+
if (cwd && (0, import_node_fs22.existsSync)(cwd)) {
|
|
15157
15493
|
try {
|
|
15158
15494
|
process.chdir(cwd);
|
|
15159
15495
|
} catch {
|
|
@@ -15258,14 +15594,14 @@ function writeBlockMessage(moment, response) {
|
|
|
15258
15594
|
}
|
|
15259
15595
|
|
|
15260
15596
|
// src/commands/init.ts
|
|
15261
|
-
var
|
|
15597
|
+
var import_node_fs24 = require("node:fs");
|
|
15262
15598
|
var import_promises12 = require("node:fs/promises");
|
|
15263
|
-
var
|
|
15599
|
+
var import_node_path17 = require("node:path");
|
|
15264
15600
|
var import_node_child_process9 = require("node:child_process");
|
|
15265
15601
|
|
|
15266
15602
|
// src/commands/migrate.ts
|
|
15267
|
-
var
|
|
15268
|
-
var
|
|
15603
|
+
var import_node_fs23 = require("node:fs");
|
|
15604
|
+
var import_node_path16 = require("node:path");
|
|
15269
15605
|
var import_node_child_process8 = require("node:child_process");
|
|
15270
15606
|
var LEGACY_NPM_PACKAGE = "@codacy/gate-cli";
|
|
15271
15607
|
function defaultNpmRemover(pkg) {
|
|
@@ -15301,12 +15637,12 @@ async function runMigration(opts = {}) {
|
|
|
15301
15637
|
return { actions, migrated: actions.length > 0 };
|
|
15302
15638
|
}
|
|
15303
15639
|
function migrateProjectDir(root, actions) {
|
|
15304
|
-
const gateDir = (0,
|
|
15305
|
-
const verityDir = (0,
|
|
15306
|
-
if ((0,
|
|
15640
|
+
const gateDir = (0, import_node_path16.join)(root, ".gate");
|
|
15641
|
+
const verityDir = (0, import_node_path16.join)(root, ".verity");
|
|
15642
|
+
if ((0, import_node_fs23.existsSync)(gateDir) && !(0, import_node_fs23.existsSync)(verityDir)) {
|
|
15307
15643
|
return migrateProjectDirRename(root, gateDir, verityDir, actions);
|
|
15308
15644
|
}
|
|
15309
|
-
if ((0,
|
|
15645
|
+
if ((0, import_node_fs23.existsSync)(gateDir) && (0, import_node_fs23.existsSync)(verityDir)) {
|
|
15310
15646
|
return migrateProjectDirCarry(gateDir, verityDir, actions);
|
|
15311
15647
|
}
|
|
15312
15648
|
return false;
|
|
@@ -15327,13 +15663,13 @@ function migrateProjectDirRename(root, gateDir, verityDir, actions) {
|
|
|
15327
15663
|
}
|
|
15328
15664
|
}
|
|
15329
15665
|
if (moved) {
|
|
15330
|
-
if ((0,
|
|
15666
|
+
if ((0, import_node_fs23.existsSync)(gateDir)) {
|
|
15331
15667
|
const carried = carryLegacyContents(gateDir, verityDir);
|
|
15332
15668
|
if (carried > 0) {
|
|
15333
15669
|
actions.push(`Carried ${carried} untracked legacy file(s) from .gate/ into .verity/`);
|
|
15334
15670
|
}
|
|
15335
15671
|
try {
|
|
15336
|
-
(0,
|
|
15672
|
+
(0, import_node_fs23.rmSync)(gateDir, { recursive: true, force: true });
|
|
15337
15673
|
} catch {
|
|
15338
15674
|
}
|
|
15339
15675
|
}
|
|
@@ -15349,18 +15685,18 @@ function migrateProjectDirCarry(gateDir, verityDir, actions) {
|
|
|
15349
15685
|
actions.push(`Carried ${carried} legacy file(s) from .gate/ into .verity/`);
|
|
15350
15686
|
}
|
|
15351
15687
|
try {
|
|
15352
|
-
(0,
|
|
15688
|
+
(0, import_node_fs23.rmSync)(gateDir, { recursive: true, force: true });
|
|
15353
15689
|
} catch {
|
|
15354
15690
|
}
|
|
15355
15691
|
return carried > 0;
|
|
15356
15692
|
}
|
|
15357
15693
|
function migrateGlobalCredentials(home, actions) {
|
|
15358
15694
|
if (!home) return;
|
|
15359
|
-
const gateCreds = (0,
|
|
15360
|
-
const verityCreds = (0,
|
|
15361
|
-
if (!(0,
|
|
15362
|
-
if (!(0,
|
|
15363
|
-
(0,
|
|
15695
|
+
const gateCreds = (0, import_node_path16.join)(home, ".gate", "credentials");
|
|
15696
|
+
const verityCreds = (0, import_node_path16.join)(home, ".verity", "credentials");
|
|
15697
|
+
if (!(0, import_node_fs23.existsSync)(gateCreds)) return;
|
|
15698
|
+
if (!(0, import_node_fs23.existsSync)(verityCreds)) {
|
|
15699
|
+
(0, import_node_fs23.mkdirSync)((0, import_node_path16.join)(home, ".verity"), { recursive: true });
|
|
15364
15700
|
moveFile(gateCreds, verityCreds);
|
|
15365
15701
|
actions.push("Moved ~/.gate/credentials \u2192 ~/.verity/credentials");
|
|
15366
15702
|
return;
|
|
@@ -15382,8 +15718,8 @@ async function migrateLegacyHooks(root, actions) {
|
|
|
15382
15718
|
}
|
|
15383
15719
|
}
|
|
15384
15720
|
async function migrateClaudeMd(root, actions) {
|
|
15385
|
-
const claudeMd = (0,
|
|
15386
|
-
const hadLegacyBlock = (0,
|
|
15721
|
+
const claudeMd = (0, import_node_path16.join)(root, "CLAUDE.md");
|
|
15722
|
+
const hadLegacyBlock = (0, import_node_fs23.existsSync)(claudeMd) && hasLegacyMemoryBlock(readFileSyncSafe(claudeMd));
|
|
15387
15723
|
if (!hadLegacyBlock) return;
|
|
15388
15724
|
try {
|
|
15389
15725
|
await ensureClaudeMdPointer(root);
|
|
@@ -15393,9 +15729,9 @@ async function migrateClaudeMd(root, actions) {
|
|
|
15393
15729
|
}
|
|
15394
15730
|
}
|
|
15395
15731
|
function migrateStandardFile(root, actions) {
|
|
15396
|
-
const gateMd = (0,
|
|
15397
|
-
const verityMd = (0,
|
|
15398
|
-
if (!(0,
|
|
15732
|
+
const gateMd = (0, import_node_path16.join)(root, "GATE.md");
|
|
15733
|
+
const verityMd = (0, import_node_path16.join)(root, "VERITY.md");
|
|
15734
|
+
if (!(0, import_node_fs23.existsSync)(gateMd) || (0, import_node_fs23.existsSync)(verityMd)) return;
|
|
15399
15735
|
let moved = false;
|
|
15400
15736
|
if (isGitRepo(root) && isGitTracked(root, "GATE.md")) {
|
|
15401
15737
|
try {
|
|
@@ -15407,7 +15743,7 @@ function migrateStandardFile(root, actions) {
|
|
|
15407
15743
|
if (!moved) moveFile(gateMd, verityMd);
|
|
15408
15744
|
const content = readFileSyncSafe(verityMd);
|
|
15409
15745
|
const refreshed = content.split("GATE.md").join("VERITY.md");
|
|
15410
|
-
if (refreshed !== content) (0,
|
|
15746
|
+
if (refreshed !== content) (0, import_node_fs23.writeFileSync)(verityMd, refreshed);
|
|
15411
15747
|
actions.push("Renamed GATE.md \u2192 VERITY.md");
|
|
15412
15748
|
}
|
|
15413
15749
|
function removeLegacyPackage(movedProjectDir, npmRemover, actions) {
|
|
@@ -15441,14 +15777,14 @@ function mergeGlobalCredentials(gateCreds, verityCreds) {
|
|
|
15441
15777
|
}
|
|
15442
15778
|
if (toAppend.length > 0) {
|
|
15443
15779
|
const sep = verityContent.endsWith("\n") || verityContent === "" ? "" : "\n";
|
|
15444
|
-
(0,
|
|
15780
|
+
(0, import_node_fs23.writeFileSync)(verityCreds, verityContent + sep + toAppend.join("\n") + "\n");
|
|
15445
15781
|
}
|
|
15446
|
-
(0,
|
|
15782
|
+
(0, import_node_fs23.rmSync)(gateCreds, { force: true });
|
|
15447
15783
|
return toAppend.length;
|
|
15448
15784
|
}
|
|
15449
15785
|
function readFileSyncSafe(path) {
|
|
15450
15786
|
try {
|
|
15451
|
-
return (0,
|
|
15787
|
+
return (0, import_node_fs23.readFileSync)(path, "utf-8");
|
|
15452
15788
|
} catch {
|
|
15453
15789
|
return "";
|
|
15454
15790
|
}
|
|
@@ -15463,35 +15799,35 @@ function hasStagedChanges(root) {
|
|
|
15463
15799
|
}
|
|
15464
15800
|
function moveDir(from, to) {
|
|
15465
15801
|
try {
|
|
15466
|
-
(0,
|
|
15802
|
+
(0, import_node_fs23.renameSync)(from, to);
|
|
15467
15803
|
} catch (err) {
|
|
15468
15804
|
if (err.code !== "EXDEV") throw err;
|
|
15469
|
-
(0,
|
|
15470
|
-
(0,
|
|
15805
|
+
(0, import_node_fs23.cpSync)(from, to, { recursive: true });
|
|
15806
|
+
(0, import_node_fs23.rmSync)(from, { recursive: true, force: true });
|
|
15471
15807
|
}
|
|
15472
15808
|
}
|
|
15473
15809
|
function moveFile(from, to) {
|
|
15474
15810
|
try {
|
|
15475
|
-
(0,
|
|
15811
|
+
(0, import_node_fs23.renameSync)(from, to);
|
|
15476
15812
|
} catch (err) {
|
|
15477
15813
|
if (err.code !== "EXDEV") throw err;
|
|
15478
|
-
(0,
|
|
15479
|
-
(0,
|
|
15814
|
+
(0, import_node_fs23.cpSync)(from, to);
|
|
15815
|
+
(0, import_node_fs23.rmSync)(from, { force: true });
|
|
15480
15816
|
}
|
|
15481
15817
|
}
|
|
15482
15818
|
function carryLegacyContents(gateDir, verityDir) {
|
|
15483
15819
|
let copied = 0;
|
|
15484
15820
|
const walk = (relDir) => {
|
|
15485
|
-
const srcDir = (0,
|
|
15486
|
-
for (const entry of (0,
|
|
15487
|
-
const rel = relDir ? (0,
|
|
15488
|
-
const src = (0,
|
|
15489
|
-
const dest = (0,
|
|
15490
|
-
if ((0,
|
|
15821
|
+
const srcDir = (0, import_node_path16.join)(gateDir, relDir);
|
|
15822
|
+
for (const entry of (0, import_node_fs23.readdirSync)(srcDir)) {
|
|
15823
|
+
const rel = relDir ? (0, import_node_path16.join)(relDir, entry) : entry;
|
|
15824
|
+
const src = (0, import_node_path16.join)(gateDir, rel);
|
|
15825
|
+
const dest = (0, import_node_path16.join)(verityDir, rel);
|
|
15826
|
+
if ((0, import_node_fs23.statSync)(src).isDirectory()) {
|
|
15491
15827
|
walk(rel);
|
|
15492
|
-
} else if (!(0,
|
|
15493
|
-
(0,
|
|
15494
|
-
(0,
|
|
15828
|
+
} else if (!(0, import_node_fs23.existsSync)(dest)) {
|
|
15829
|
+
(0, import_node_fs23.mkdirSync)((0, import_node_path16.dirname)(dest), { recursive: true });
|
|
15830
|
+
(0, import_node_fs23.cpSync)(src, dest);
|
|
15495
15831
|
copied++;
|
|
15496
15832
|
}
|
|
15497
15833
|
}
|
|
@@ -15500,22 +15836,22 @@ function carryLegacyContents(gateDir, verityDir) {
|
|
|
15500
15836
|
return copied;
|
|
15501
15837
|
}
|
|
15502
15838
|
async function needsMigration(root = repoRoot()) {
|
|
15503
|
-
const gateDir = (0,
|
|
15504
|
-
const verityDir = (0,
|
|
15505
|
-
if ((0,
|
|
15506
|
-
if ((0,
|
|
15507
|
-
if ((0,
|
|
15839
|
+
const gateDir = (0, import_node_path16.join)(root, ".gate");
|
|
15840
|
+
const verityDir = (0, import_node_path16.join)(root, ".verity");
|
|
15841
|
+
if ((0, import_node_fs23.existsSync)(gateDir) && !(0, import_node_fs23.existsSync)(verityDir)) return true;
|
|
15842
|
+
if ((0, import_node_fs23.existsSync)(gateDir) && (0, import_node_fs23.existsSync)(verityDir)) {
|
|
15843
|
+
if ((0, import_node_fs23.existsSync)((0, import_node_path16.join)(gateDir, "credentials")) && !(0, import_node_fs23.existsSync)((0, import_node_path16.join)(verityDir, "credentials"))) {
|
|
15508
15844
|
return true;
|
|
15509
15845
|
}
|
|
15510
|
-
if ((0,
|
|
15846
|
+
if ((0, import_node_fs23.existsSync)((0, import_node_path16.join)(gateDir, "memory")) && !(0, import_node_fs23.existsSync)((0, import_node_path16.join)(verityDir, "memory"))) {
|
|
15511
15847
|
return true;
|
|
15512
15848
|
}
|
|
15513
15849
|
}
|
|
15514
|
-
const claudeMd = (0,
|
|
15515
|
-
if ((0,
|
|
15850
|
+
const claudeMd = (0, import_node_path16.join)(root, "CLAUDE.md");
|
|
15851
|
+
if ((0, import_node_fs23.existsSync)(claudeMd) && hasLegacyMemoryBlock(readFileSyncSafe(claudeMd))) {
|
|
15516
15852
|
return true;
|
|
15517
15853
|
}
|
|
15518
|
-
if ((0,
|
|
15854
|
+
if ((0, import_node_fs23.existsSync)((0, import_node_path16.join)(root, "GATE.md")) && !(0, import_node_fs23.existsSync)((0, import_node_path16.join)(root, "VERITY.md"))) {
|
|
15519
15855
|
return true;
|
|
15520
15856
|
}
|
|
15521
15857
|
if (await hasLegacyHooksAt(root)) return true;
|
|
@@ -15543,15 +15879,15 @@ function registerMigrateCommand(program2) {
|
|
|
15543
15879
|
// src/commands/init.ts
|
|
15544
15880
|
function resolveDataDir() {
|
|
15545
15881
|
const candidates = [
|
|
15546
|
-
(0,
|
|
15882
|
+
(0, import_node_path17.join)(__dirname, "..", "data"),
|
|
15547
15883
|
// installed: node_modules/@codacy/verity-cli/data
|
|
15548
|
-
(0,
|
|
15884
|
+
(0, import_node_path17.join)(__dirname, "..", "..", "data"),
|
|
15549
15885
|
// edge case: nested resolution
|
|
15550
|
-
(0,
|
|
15886
|
+
(0, import_node_path17.join)(process.cwd(), "cli", "data")
|
|
15551
15887
|
// local dev: running from repo root
|
|
15552
15888
|
];
|
|
15553
15889
|
for (const candidate of candidates) {
|
|
15554
|
-
if ((0,
|
|
15890
|
+
if ((0, import_node_fs24.existsSync)((0, import_node_path17.join)(candidate, "skills"))) {
|
|
15555
15891
|
return candidate;
|
|
15556
15892
|
}
|
|
15557
15893
|
}
|
|
@@ -15567,7 +15903,7 @@ function registerInitCommand(program2) {
|
|
|
15567
15903
|
program2.command("init").description("Initialize Verity in the current project").option("--force", "Overwrite existing skills and hooks").action(async (opts) => {
|
|
15568
15904
|
const force = opts.force ?? false;
|
|
15569
15905
|
const projectMarkers = [".git", "package.json", "pyproject.toml", "go.mod", "Cargo.toml", "Gemfile", "pom.xml", "build.gradle"];
|
|
15570
|
-
const isProject = projectMarkers.some((m) => (0,
|
|
15906
|
+
const isProject = projectMarkers.some((m) => (0, import_node_fs24.existsSync)(m));
|
|
15571
15907
|
if (!isProject) {
|
|
15572
15908
|
printError("No project detected in the current directory.");
|
|
15573
15909
|
printInfo('Run "verity init" from your project root.');
|
|
@@ -15630,21 +15966,21 @@ function registerInitCommand(program2) {
|
|
|
15630
15966
|
console.log("");
|
|
15631
15967
|
printInfo("Installing skills...");
|
|
15632
15968
|
const dataDir = resolveDataDir();
|
|
15633
|
-
const skillsSource = (0,
|
|
15969
|
+
const skillsSource = (0, import_node_path17.join)(dataDir, "skills");
|
|
15634
15970
|
const skillsDest = ".claude/skills";
|
|
15635
15971
|
const skills = ["verity-setup", "verity-analyze", "verity-status", "verity-feedback", "verity-learn", "verity-memory", "verity-insights", "verity-reflect"];
|
|
15636
15972
|
let skillsInstalled = 0;
|
|
15637
15973
|
for (const skill of skills) {
|
|
15638
|
-
const src = (0,
|
|
15639
|
-
const dest = (0,
|
|
15640
|
-
if (!(0,
|
|
15974
|
+
const src = (0, import_node_path17.join)(skillsSource, skill);
|
|
15975
|
+
const dest = (0, import_node_path17.join)(skillsDest, skill);
|
|
15976
|
+
if (!(0, import_node_fs24.existsSync)(src)) {
|
|
15641
15977
|
printWarn(` Skill data not found: ${skill}`);
|
|
15642
15978
|
continue;
|
|
15643
15979
|
}
|
|
15644
|
-
if ((0,
|
|
15645
|
-
const srcSkill = (0,
|
|
15646
|
-
const destSkill = (0,
|
|
15647
|
-
if ((0,
|
|
15980
|
+
if ((0, import_node_fs24.existsSync)(dest) && !force) {
|
|
15981
|
+
const srcSkill = (0, import_node_path17.join)(src, "SKILL.md");
|
|
15982
|
+
const destSkill = (0, import_node_path17.join)(dest, "SKILL.md");
|
|
15983
|
+
if ((0, import_node_fs24.existsSync)(destSkill)) {
|
|
15648
15984
|
try {
|
|
15649
15985
|
const srcContent = await (0, import_promises12.readFile)(srcSkill, "utf-8");
|
|
15650
15986
|
const destContent = await (0, import_promises12.readFile)(destSkill, "utf-8");
|
|
@@ -15668,6 +16004,7 @@ function registerInitCommand(program2) {
|
|
|
15668
16004
|
await writeSettings(hookResult.data);
|
|
15669
16005
|
printInfo(" Stop hook: verity analyze \u2713");
|
|
15670
16006
|
printInfo(" Intent hook: verity intent capture \u2713");
|
|
16007
|
+
printInfo(" Baseline hook: verity baseline capture \u2713");
|
|
15671
16008
|
} else {
|
|
15672
16009
|
printWarn(` ${hookResult.error}`);
|
|
15673
16010
|
printInfo(' Run "verity hooks install --force" to overwrite.');
|
|
@@ -15680,7 +16017,7 @@ function registerInitCommand(program2) {
|
|
|
15680
16017
|
} catch (err) {
|
|
15681
16018
|
printWarn(` Could not update CLAUDE.md: ${err.message}`);
|
|
15682
16019
|
}
|
|
15683
|
-
const globalVerityDir = (0,
|
|
16020
|
+
const globalVerityDir = (0, import_node_path17.join)(process.env.HOME ?? "", ".verity");
|
|
15684
16021
|
await (0, import_promises12.mkdir)(globalVerityDir, { recursive: true });
|
|
15685
16022
|
console.log("");
|
|
15686
16023
|
printInfo("Verity initialized!");
|
|
@@ -15703,8 +16040,8 @@ function registerInitCommand(program2) {
|
|
|
15703
16040
|
}
|
|
15704
16041
|
|
|
15705
16042
|
// src/commands/uninstall.ts
|
|
15706
|
-
var
|
|
15707
|
-
var
|
|
16043
|
+
var import_node_fs25 = require("node:fs");
|
|
16044
|
+
var import_node_path18 = require("node:path");
|
|
15708
16045
|
var SKILL_NAMES = [
|
|
15709
16046
|
"verity-setup",
|
|
15710
16047
|
"verity-analyze",
|
|
@@ -15723,11 +16060,11 @@ function registerUninstallCommand(program2) {
|
|
|
15723
16060
|
const actions = [];
|
|
15724
16061
|
const skillsRoot = projectPath(".claude/skills");
|
|
15725
16062
|
for (const name of SKILL_NAMES) {
|
|
15726
|
-
const dir = (0,
|
|
15727
|
-
if ((0,
|
|
16063
|
+
const dir = (0, import_node_path18.join)(skillsRoot, name);
|
|
16064
|
+
if ((0, import_node_fs25.existsSync)(dir)) {
|
|
15728
16065
|
actions.push({
|
|
15729
16066
|
label: `Remove .claude/skills/${name}/`,
|
|
15730
|
-
apply: () => (0,
|
|
16067
|
+
apply: () => (0, import_node_fs25.rmSync)(dir, { recursive: true, force: true })
|
|
15731
16068
|
});
|
|
15732
16069
|
}
|
|
15733
16070
|
}
|
|
@@ -15741,24 +16078,24 @@ function registerUninstallCommand(program2) {
|
|
|
15741
16078
|
});
|
|
15742
16079
|
}
|
|
15743
16080
|
const verityDir = projectPath(VERITY_DIR);
|
|
15744
|
-
if ((0,
|
|
16081
|
+
if ((0, import_node_fs25.existsSync)(verityDir)) {
|
|
15745
16082
|
actions.push({
|
|
15746
16083
|
label: `Remove ${VERITY_DIR}/`,
|
|
15747
|
-
apply: () => (0,
|
|
16084
|
+
apply: () => (0, import_node_fs25.rmSync)(verityDir, { recursive: true, force: true })
|
|
15748
16085
|
});
|
|
15749
16086
|
}
|
|
15750
16087
|
if (!keepVerityMd) {
|
|
15751
16088
|
const verityMd = projectPath(VERITY_MD_FILE);
|
|
15752
|
-
if ((0,
|
|
16089
|
+
if ((0, import_node_fs25.existsSync)(verityMd)) {
|
|
15753
16090
|
actions.push({
|
|
15754
16091
|
label: `Remove ${VERITY_MD_FILE}`,
|
|
15755
|
-
apply: () => (0,
|
|
16092
|
+
apply: () => (0, import_node_fs25.rmSync)(verityMd, { force: true })
|
|
15756
16093
|
});
|
|
15757
16094
|
}
|
|
15758
16095
|
}
|
|
15759
16096
|
const cleanupEmptyDir = (path) => {
|
|
15760
|
-
if ((0,
|
|
15761
|
-
(0,
|
|
16097
|
+
if ((0, import_node_fs25.existsSync)(path) && (0, import_node_fs25.statSync)(path).isDirectory() && (0, import_node_fs25.readdirSync)(path).length === 0) {
|
|
16098
|
+
(0, import_node_fs25.rmdirSync)(path);
|
|
15762
16099
|
}
|
|
15763
16100
|
};
|
|
15764
16101
|
actions.push({
|
|
@@ -15769,11 +16106,11 @@ function registerUninstallCommand(program2) {
|
|
|
15769
16106
|
}
|
|
15770
16107
|
});
|
|
15771
16108
|
const home = process.env.HOME ?? "";
|
|
15772
|
-
const globalVerityDir = (0,
|
|
15773
|
-
if (purgeGlobal && (0,
|
|
16109
|
+
const globalVerityDir = (0, import_node_path18.join)(home, ".verity");
|
|
16110
|
+
if (purgeGlobal && (0, import_node_fs25.existsSync)(globalVerityDir)) {
|
|
15774
16111
|
actions.push({
|
|
15775
16112
|
label: `Remove ~/.verity/ (global credentials \u2014 reconnect requires re-registration)`,
|
|
15776
|
-
apply: () => (0,
|
|
16113
|
+
apply: () => (0, import_node_fs25.rmSync)(globalVerityDir, { recursive: true, force: true })
|
|
15777
16114
|
});
|
|
15778
16115
|
}
|
|
15779
16116
|
if (actions.length === 0) {
|
|
@@ -15967,8 +16304,8 @@ function registerTaskCommands(program2) {
|
|
|
15967
16304
|
}
|
|
15968
16305
|
|
|
15969
16306
|
// src/commands/reset.ts
|
|
15970
|
-
var
|
|
15971
|
-
var
|
|
16307
|
+
var import_node_fs26 = require("node:fs");
|
|
16308
|
+
var import_node_path19 = require("node:path");
|
|
15972
16309
|
function registerResetCommand(program2) {
|
|
15973
16310
|
program2.command("reset").description("Close the current task and clear transient state").option("--keep-task", "Only purge caches; leave the current task open").option("--all", "Also purge diagnostic logs (.verity/.logs/)").action(async (opts) => {
|
|
15974
16311
|
const globals = program2.opts();
|
|
@@ -16005,11 +16342,11 @@ function registerResetCommand(program2) {
|
|
|
16005
16342
|
}
|
|
16006
16343
|
const cacheDir = projectPath(CACHE_DIR);
|
|
16007
16344
|
let purged = 0;
|
|
16008
|
-
if ((0,
|
|
16009
|
-
for (const entry of (0,
|
|
16345
|
+
if ((0, import_node_fs26.existsSync)(cacheDir)) {
|
|
16346
|
+
for (const entry of (0, import_node_fs26.readdirSync)(cacheDir)) {
|
|
16010
16347
|
if (entry.startsWith("pending-")) {
|
|
16011
16348
|
try {
|
|
16012
|
-
(0,
|
|
16349
|
+
(0, import_node_fs26.unlinkSync)((0, import_node_path19.join)(cacheDir, entry));
|
|
16013
16350
|
purged++;
|
|
16014
16351
|
} catch {
|
|
16015
16352
|
}
|
|
@@ -16024,19 +16361,19 @@ function registerResetCommand(program2) {
|
|
|
16024
16361
|
projectPath(`${VERITY_DIR}/.last-analysis`)
|
|
16025
16362
|
];
|
|
16026
16363
|
for (const file of filesToClear) {
|
|
16027
|
-
if ((0,
|
|
16364
|
+
if ((0, import_node_fs26.existsSync)(file)) {
|
|
16028
16365
|
try {
|
|
16029
|
-
(0,
|
|
16366
|
+
(0, import_node_fs26.writeFileSync)(file, "");
|
|
16030
16367
|
} catch {
|
|
16031
16368
|
}
|
|
16032
16369
|
}
|
|
16033
16370
|
}
|
|
16034
16371
|
if (opts.all) {
|
|
16035
16372
|
const logsDir = projectPath(`${VERITY_DIR}/.logs`);
|
|
16036
|
-
if ((0,
|
|
16037
|
-
for (const entry of (0,
|
|
16373
|
+
if ((0, import_node_fs26.existsSync)(logsDir)) {
|
|
16374
|
+
for (const entry of (0, import_node_fs26.readdirSync)(logsDir)) {
|
|
16038
16375
|
try {
|
|
16039
|
-
(0,
|
|
16376
|
+
(0, import_node_fs26.unlinkSync)((0, import_node_path19.join)(logsDir, entry));
|
|
16040
16377
|
} catch {
|
|
16041
16378
|
}
|
|
16042
16379
|
}
|
|
@@ -16047,10 +16384,29 @@ function registerResetCommand(program2) {
|
|
|
16047
16384
|
});
|
|
16048
16385
|
}
|
|
16049
16386
|
|
|
16387
|
+
// src/lib/run-mode.ts
|
|
16388
|
+
function parseAutonomousEnv(raw) {
|
|
16389
|
+
if (raw === void 0) return void 0;
|
|
16390
|
+
const v = raw.trim().toLowerCase();
|
|
16391
|
+
if (v === "") return void 0;
|
|
16392
|
+
if (v === "0" || v === "false" || v === "off" || v === "no") return false;
|
|
16393
|
+
return true;
|
|
16394
|
+
}
|
|
16395
|
+
function resolveRunMode(inputs = {}) {
|
|
16396
|
+
if (inputs.autonomousFlag === true) return "autonomous";
|
|
16397
|
+
if (inputs.autonomousFlag === false) return "interactive";
|
|
16398
|
+
const env = inputs.env ?? process.env;
|
|
16399
|
+
const envDecision = parseAutonomousEnv(env.VERITY_AUTONOMOUS);
|
|
16400
|
+
if (envDecision !== void 0) return envDecision ? "autonomous" : "interactive";
|
|
16401
|
+
const isTTY = inputs.isTTY ?? Boolean(process.stdin?.isTTY);
|
|
16402
|
+
return isTTY ? "interactive" : "autonomous";
|
|
16403
|
+
}
|
|
16404
|
+
|
|
16050
16405
|
// src/commands/reflect.ts
|
|
16051
16406
|
function registerReflectCommand(program2) {
|
|
16052
|
-
program2.command("reflect").description("Capture learnings \u2014 auto-extract or submit a human reflection").option("--user-input <text>", "
|
|
16407
|
+
program2.command("reflect").description("Capture learnings \u2014 auto-extract or submit a human reflection").option("--user-input <text>", "The reflection to record (the agent-drafted or user-confirmed text)").option("--kind <kind>", "Node kind (decision, gotcha, pattern, security, quality, intent, domain, integration)", "gotcha").option("--task-id <id>", "Task to reflect on (defaults to current task)").option("--autonomous", "Record the drafted reflection without a confirm step (auto-detected from TTY / VERITY_AUTONOMOUS when omitted)").action(async (opts) => {
|
|
16053
16408
|
const globals = program2.opts();
|
|
16409
|
+
const mode = resolveRunMode({ autonomousFlag: opts.autonomous });
|
|
16054
16410
|
await ensureMemoryDir();
|
|
16055
16411
|
const tokenResult = await resolveToken(globals.token);
|
|
16056
16412
|
if (!tokenResult.ok) {
|
|
@@ -16141,7 +16497,9 @@ function registerReflectCommand(program2) {
|
|
|
16141
16497
|
const nodeId = result.data.node_id;
|
|
16142
16498
|
const filePath = result.data.file_path;
|
|
16143
16499
|
printInfo(`Queued: ${nodeId} (will sync to .verity/memory/${filePath} on next analysis).`);
|
|
16144
|
-
printInfo(
|
|
16500
|
+
printInfo(
|
|
16501
|
+
mode === "autonomous" ? "Recorded autonomously (no confirm step) into the project knowledge base." : "Recorded your confirmed reflection into the project knowledge base."
|
|
16502
|
+
);
|
|
16145
16503
|
if (taskResolution === "none") {
|
|
16146
16504
|
printInfo("(No task context \u2014 reflection lives at the project level.)");
|
|
16147
16505
|
}
|
|
@@ -16274,7 +16632,7 @@ function registerRunCommand(program2) {
|
|
|
16274
16632
|
|
|
16275
16633
|
// src/lib/telemetry.ts
|
|
16276
16634
|
var import_promises13 = require("node:fs/promises");
|
|
16277
|
-
var
|
|
16635
|
+
var import_node_path20 = require("node:path");
|
|
16278
16636
|
var SETTINGS_LOCAL_FILE2 = ".claude/settings.local.json";
|
|
16279
16637
|
var GITIGNORE_FILE = ".gitignore";
|
|
16280
16638
|
var GITIGNORE_ENTRY = ".claude/settings.local.json";
|
|
@@ -16312,7 +16670,7 @@ async function readSettingsLocal() {
|
|
|
16312
16670
|
}
|
|
16313
16671
|
async function writeSettingsLocal(settings) {
|
|
16314
16672
|
const file = projectPath(SETTINGS_LOCAL_FILE2);
|
|
16315
|
-
await (0, import_promises13.mkdir)((0,
|
|
16673
|
+
await (0, import_promises13.mkdir)((0, import_node_path20.dirname)(file), { recursive: true });
|
|
16316
16674
|
await (0, import_promises13.writeFile)(file, JSON.stringify(settings, null, 2) + "\n");
|
|
16317
16675
|
}
|
|
16318
16676
|
async function ensureGitignore() {
|
|
@@ -16408,7 +16766,7 @@ function registerTelemetryCommands(program2) {
|
|
|
16408
16766
|
}
|
|
16409
16767
|
|
|
16410
16768
|
// src/cli.ts
|
|
16411
|
-
program.name("verity").description("CLI for Verity quality gate service").version("0.
|
|
16769
|
+
program.name("verity").description("CLI for Verity quality gate service").version("0.24.0-experimental.9a9e918").option("--token <token>", "Override authentication token").option("--service-url <url>", "Override service URL").option("--verbose", "Log HTTP requests/responses to stderr");
|
|
16412
16770
|
registerAuthCommands(program);
|
|
16413
16771
|
registerHooksCommands(program);
|
|
16414
16772
|
registerIntentCommands(program);
|
|
@@ -16417,6 +16775,7 @@ registerConfigCommands(program);
|
|
|
16417
16775
|
registerStatusCommand(program);
|
|
16418
16776
|
registerFeedbackCommand(program);
|
|
16419
16777
|
registerAnalyzeCommand(program);
|
|
16778
|
+
registerBaselineCommands(program);
|
|
16420
16779
|
registerReviewCommand(program);
|
|
16421
16780
|
registerGuardCommand(program);
|
|
16422
16781
|
registerInitCommand(program);
|