@codacy/verity-cli 0.23.2 → 0.24.0-experimental.6a390ac
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 +613 -187
- 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 = [
|
|
@@ -12833,6 +12898,11 @@ function getPushRangeFiles() {
|
|
|
12833
12898
|
const last = diff("HEAD~1..HEAD");
|
|
12834
12899
|
return { files: last, range: last.length > 0 ? "HEAD~1..HEAD" : null };
|
|
12835
12900
|
}
|
|
12901
|
+
function getPushRangeMessages() {
|
|
12902
|
+
const { range } = getPushRangeFiles();
|
|
12903
|
+
if (!range) return "";
|
|
12904
|
+
return execGit(`git log ${range} --format=%B%x00`).split("\0").map((s) => s.trim()).filter(Boolean).join("\n\n");
|
|
12905
|
+
}
|
|
12836
12906
|
function getWorktreeFiles() {
|
|
12837
12907
|
const result = [];
|
|
12838
12908
|
const worktreeDir = ".claude/worktrees";
|
|
@@ -13458,15 +13528,207 @@ function cleanStaleSnapshots(dir, keepSet) {
|
|
|
13458
13528
|
}
|
|
13459
13529
|
}
|
|
13460
13530
|
|
|
13461
|
-
// src/lib/
|
|
13531
|
+
// src/lib/baseline.ts
|
|
13462
13532
|
var import_node_fs13 = require("node:fs");
|
|
13533
|
+
var import_node_path11 = require("node:path");
|
|
13463
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");
|
|
13464
13726
|
function cacheRequest(body) {
|
|
13465
13727
|
try {
|
|
13466
|
-
(0,
|
|
13467
|
-
const suffix = (0,
|
|
13728
|
+
(0, import_node_fs14.mkdirSync)(CACHE_DIR, { recursive: true });
|
|
13729
|
+
const suffix = (0, import_node_crypto5.randomBytes)(4).toString("hex");
|
|
13468
13730
|
const filename = `pending-${Math.floor(Date.now() / 1e3)}-${suffix}.json`;
|
|
13469
|
-
(0,
|
|
13731
|
+
(0, import_node_fs14.writeFileSync)(`${CACHE_DIR}/${filename}`, JSON.stringify(body));
|
|
13470
13732
|
} catch {
|
|
13471
13733
|
}
|
|
13472
13734
|
}
|
|
@@ -13480,7 +13742,7 @@ function buildOfflineFallback(reason, staticResults) {
|
|
|
13480
13742
|
}
|
|
13481
13743
|
|
|
13482
13744
|
// src/lib/context-files.ts
|
|
13483
|
-
var
|
|
13745
|
+
var import_node_fs15 = require("node:fs");
|
|
13484
13746
|
var MAX_CONTEXT_FILES = 10;
|
|
13485
13747
|
var MAX_CONTEXT_FILE_BYTES = 10240;
|
|
13486
13748
|
var MAX_CONTEXT_TOTAL_BYTES = 51200;
|
|
@@ -13492,7 +13754,7 @@ function gatherContextFiles(contextPaths, deltaFiles) {
|
|
|
13492
13754
|
if (result.length >= MAX_CONTEXT_FILES) break;
|
|
13493
13755
|
if (deltaPaths.has(filePath)) continue;
|
|
13494
13756
|
try {
|
|
13495
|
-
const content = (0,
|
|
13757
|
+
const content = (0, import_node_fs15.readFileSync)(filePath, "utf8");
|
|
13496
13758
|
const bytes = Buffer.byteLength(content);
|
|
13497
13759
|
if (bytes > MAX_CONTEXT_FILE_BYTES) {
|
|
13498
13760
|
logEvent("context_file_skipped", { path: filePath, reason: "too_large", bytes });
|
|
@@ -13537,20 +13799,20 @@ function gatherContextFiles(contextPaths, deltaFiles) {
|
|
|
13537
13799
|
}
|
|
13538
13800
|
|
|
13539
13801
|
// src/lib/cache-cleanup.ts
|
|
13540
|
-
var
|
|
13541
|
-
var
|
|
13802
|
+
var import_node_fs16 = require("node:fs");
|
|
13803
|
+
var import_node_path12 = require("node:path");
|
|
13542
13804
|
var CACHE_TTL_DAYS = 7;
|
|
13543
13805
|
function pruneStaleCache() {
|
|
13544
13806
|
try {
|
|
13545
13807
|
const dir = projectPath(CACHE_DIR);
|
|
13546
13808
|
const cutoff = Date.now() - CACHE_TTL_DAYS * 24 * 3600 * 1e3;
|
|
13547
|
-
for (const entry of (0,
|
|
13809
|
+
for (const entry of (0, import_node_fs16.readdirSync)(dir)) {
|
|
13548
13810
|
if (!entry.startsWith("pending-")) continue;
|
|
13549
|
-
const path = (0,
|
|
13811
|
+
const path = (0, import_node_path12.join)(dir, entry);
|
|
13550
13812
|
try {
|
|
13551
|
-
const stat3 = (0,
|
|
13813
|
+
const stat3 = (0, import_node_fs16.statSync)(path);
|
|
13552
13814
|
if (stat3.mtimeMs < cutoff) {
|
|
13553
|
-
(0,
|
|
13815
|
+
(0, import_node_fs16.unlinkSync)(path);
|
|
13554
13816
|
logEvent("cache_entry_pruned", {
|
|
13555
13817
|
path: entry,
|
|
13556
13818
|
age_days: Math.round((Date.now() - stat3.mtimeMs) / 864e5)
|
|
@@ -13622,10 +13884,11 @@ function reconcileAnalysisMode(predictedMode, signals) {
|
|
|
13622
13884
|
signals.noFilesChanged,
|
|
13623
13885
|
signals.assistantResponse,
|
|
13624
13886
|
signals.conversationPrompts,
|
|
13625
|
-
signals.actionSummary
|
|
13887
|
+
signals.actionSummary,
|
|
13888
|
+
signals.sessionAuthoredCode
|
|
13626
13889
|
);
|
|
13627
13890
|
}
|
|
13628
|
-
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;
|
|
13629
13892
|
const agentInvestigated = didAgentInvestigate(signals.actionSummary);
|
|
13630
13893
|
switch (predictedMode) {
|
|
13631
13894
|
case "skip":
|
|
@@ -13650,8 +13913,8 @@ function didAgentInvestigate(summary) {
|
|
|
13650
13913
|
function isValidMode(mode) {
|
|
13651
13914
|
return mode === "standard" || mode === "plan" || mode === "debug" || mode === "skip";
|
|
13652
13915
|
}
|
|
13653
|
-
function detectAnalysisMode(noFilesChanged, assistantResponse, conversationPrompts, actionSummary) {
|
|
13654
|
-
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;
|
|
13655
13918
|
if (conversationPrompts.length > 0 && conversationPrompts.every(isGitOnlyPrompt)) {
|
|
13656
13919
|
if (!agentAuthoredCode) return "skip";
|
|
13657
13920
|
}
|
|
@@ -13705,7 +13968,12 @@ function isReflectionQuestion(response) {
|
|
|
13705
13968
|
/reflection\s+for\s+future\s+agents/i,
|
|
13706
13969
|
/what(?:'s|\s+is)\s+one\s+thing\s+you\s+learned/i,
|
|
13707
13970
|
/say\s+['"]?skip['"]?\s+to\s+skip/i,
|
|
13708
|
-
/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
|
|
13709
13977
|
];
|
|
13710
13978
|
return markers.some((m) => m.test(response));
|
|
13711
13979
|
}
|
|
@@ -13726,7 +13994,7 @@ function isMetaTaskLabel(label2) {
|
|
|
13726
13994
|
}
|
|
13727
13995
|
|
|
13728
13996
|
// src/lib/transcript.ts
|
|
13729
|
-
var
|
|
13997
|
+
var import_node_fs17 = require("node:fs");
|
|
13730
13998
|
var MAX_READ_BYTES = 256 * 1024;
|
|
13731
13999
|
var SMALL_FILE_BYTES = 64 * 1024;
|
|
13732
14000
|
var MAX_FILES_LIST = 20;
|
|
@@ -13748,14 +14016,14 @@ async function extractActionSummary(transcriptPath) {
|
|
|
13748
14016
|
function readTurnLines(transcriptPath) {
|
|
13749
14017
|
let size;
|
|
13750
14018
|
try {
|
|
13751
|
-
size = (0,
|
|
14019
|
+
size = (0, import_node_fs17.statSync)(transcriptPath).size;
|
|
13752
14020
|
} catch {
|
|
13753
14021
|
return null;
|
|
13754
14022
|
}
|
|
13755
14023
|
if (size === 0) return null;
|
|
13756
14024
|
let raw;
|
|
13757
14025
|
if (size <= SMALL_FILE_BYTES) {
|
|
13758
|
-
raw = (0,
|
|
14026
|
+
raw = (0, import_node_fs17.readFileSync)(transcriptPath, "utf-8");
|
|
13759
14027
|
} else {
|
|
13760
14028
|
const buf = Buffer.alloc(Math.min(MAX_READ_BYTES, size));
|
|
13761
14029
|
const fd = require("node:fs").openSync(transcriptPath, "r");
|
|
@@ -13843,6 +14111,12 @@ function buildSummary(lines) {
|
|
|
13843
14111
|
case "Edit":
|
|
13844
14112
|
addPath(filesEdited, input.file_path);
|
|
13845
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;
|
|
13846
14120
|
case "Write":
|
|
13847
14121
|
addPath(filesCreated, input.file_path);
|
|
13848
14122
|
addPath(filesEdited, input.file_path);
|
|
@@ -13926,8 +14200,8 @@ function capArray(set, max) {
|
|
|
13926
14200
|
|
|
13927
14201
|
// src/lib/seed-runner.ts
|
|
13928
14202
|
var import_promises11 = require("node:fs/promises");
|
|
13929
|
-
var
|
|
13930
|
-
var
|
|
14203
|
+
var import_node_fs18 = require("node:fs");
|
|
14204
|
+
var import_node_path13 = require("node:path");
|
|
13931
14205
|
var import_yaml2 = __toESM(require_dist());
|
|
13932
14206
|
|
|
13933
14207
|
// src/lib/seed.ts
|
|
@@ -14166,7 +14440,7 @@ function renderNodeMarkdown(candidate, nodeId, createdAt) {
|
|
|
14166
14440
|
return fm;
|
|
14167
14441
|
}
|
|
14168
14442
|
async function runSeed(opts) {
|
|
14169
|
-
if (!(0,
|
|
14443
|
+
if (!(0, import_node_fs18.existsSync)(STANDARD_FILE)) {
|
|
14170
14444
|
return { created: 0, failed: 0, skipped: "no_standard", candidates: [] };
|
|
14171
14445
|
}
|
|
14172
14446
|
let standardDoc;
|
|
@@ -14178,7 +14452,7 @@ async function runSeed(opts) {
|
|
|
14178
14452
|
}
|
|
14179
14453
|
const knowledgeSpec = standardDoc.knowledge_spec ?? {};
|
|
14180
14454
|
let readmeContent;
|
|
14181
|
-
if ((0,
|
|
14455
|
+
if ((0, import_node_fs18.existsSync)("README.md")) {
|
|
14182
14456
|
try {
|
|
14183
14457
|
readmeContent = await (0, import_promises11.readFile)("README.md", "utf-8");
|
|
14184
14458
|
} catch {
|
|
@@ -14186,7 +14460,7 @@ async function runSeed(opts) {
|
|
|
14186
14460
|
}
|
|
14187
14461
|
let claudeMdContent;
|
|
14188
14462
|
for (const p of ["CLAUDE.md", ".claude/CLAUDE.md"]) {
|
|
14189
|
-
if ((0,
|
|
14463
|
+
if ((0, import_node_fs18.existsSync)(p)) {
|
|
14190
14464
|
try {
|
|
14191
14465
|
claudeMdContent = await (0, import_promises11.readFile)(p, "utf-8");
|
|
14192
14466
|
break;
|
|
@@ -14209,8 +14483,8 @@ async function runSeed(opts) {
|
|
|
14209
14483
|
if (candidates.length === 0) {
|
|
14210
14484
|
return { created: 0, failed: 0, skipped: "no_candidates", candidates: [] };
|
|
14211
14485
|
}
|
|
14212
|
-
const overviewPath = (0,
|
|
14213
|
-
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) {
|
|
14214
14488
|
return { created: 0, failed: 0, skipped: "already_seeded", candidates };
|
|
14215
14489
|
}
|
|
14216
14490
|
if (opts.dryRun) {
|
|
@@ -14245,9 +14519,9 @@ async function runSeed(opts) {
|
|
|
14245
14519
|
}
|
|
14246
14520
|
const nodeId = res.data.node_id;
|
|
14247
14521
|
const filePathRel = res.data.file_path;
|
|
14248
|
-
const targetPath = (0,
|
|
14522
|
+
const targetPath = (0, import_node_path13.join)(MEMORY_DIR, filePathRel);
|
|
14249
14523
|
try {
|
|
14250
|
-
await (0, import_promises11.mkdir)((0,
|
|
14524
|
+
await (0, import_promises11.mkdir)((0, import_node_path13.dirname)(targetPath), { recursive: true });
|
|
14251
14525
|
await (0, import_promises11.writeFile)(targetPath, renderNodeMarkdown(c, nodeId, createdAt));
|
|
14252
14526
|
created++;
|
|
14253
14527
|
opts.onCreated?.(nodeId, filePathRel, c);
|
|
@@ -14317,6 +14591,15 @@ async function runAnalyze(opts, globals) {
|
|
|
14317
14591
|
}
|
|
14318
14592
|
const { assistantMessage: assistantResponse, stopReason, transcriptPath, sessionId } = await readStopHookStdin();
|
|
14319
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
|
+
}
|
|
14320
14603
|
const { files: allChanged, hasRecentCommitFiles } = getChangedFiles();
|
|
14321
14604
|
const analyzable = filterAnalyzable(allChanged);
|
|
14322
14605
|
const reviewable = filterReviewable(allChanged);
|
|
@@ -14326,7 +14609,7 @@ async function runAnalyze(opts, globals) {
|
|
|
14326
14609
|
passAndExit("No analyzable files changed");
|
|
14327
14610
|
}
|
|
14328
14611
|
const allForReview = Array.from(/* @__PURE__ */ new Set([...analyzable, ...reviewable]));
|
|
14329
|
-
const conversation = await readAndClearConversationBuffer();
|
|
14612
|
+
const conversation = await readAndClearConversationBuffer(sessionId ?? void 0);
|
|
14330
14613
|
const specs = discoverSpecs();
|
|
14331
14614
|
const plans = discoverPlans();
|
|
14332
14615
|
const latestPrompt = conversation?.prompts?.[conversation.prompts.length - 1]?.prompt ?? "";
|
|
@@ -14376,13 +14659,14 @@ async function runAnalyze(opts, globals) {
|
|
|
14376
14659
|
}
|
|
14377
14660
|
const conversationPrompts = (conversation?.prompts ?? []).map((p) => p.prompt);
|
|
14378
14661
|
let analysisMode;
|
|
14662
|
+
const sessionAuthoredCode = !!baseline && allForReview.some((f) => changedSinceBaseline(f, baseline));
|
|
14379
14663
|
const modeOverride = opts.mode;
|
|
14380
14664
|
if (modeOverride && ["standard", "plan", "debug", "skip"].includes(modeOverride)) {
|
|
14381
14665
|
analysisMode = modeOverride;
|
|
14382
14666
|
} else {
|
|
14383
14667
|
analysisMode = reconcileAnalysisMode(
|
|
14384
14668
|
predictedMode,
|
|
14385
|
-
{ noFilesChanged, assistantResponse, actionSummary, conversationPrompts }
|
|
14669
|
+
{ noFilesChanged, assistantResponse, actionSummary, conversationPrompts, sessionAuthoredCode }
|
|
14386
14670
|
);
|
|
14387
14671
|
}
|
|
14388
14672
|
if (analysisMode === "skip") {
|
|
@@ -14440,10 +14724,16 @@ async function runAnalyze(opts, globals) {
|
|
|
14440
14724
|
const baseForReview = agentNarrowed.length > 0 ? agentNarrowed : allForReview;
|
|
14441
14725
|
const recentForReview = narrowToRecent(baseForReview);
|
|
14442
14726
|
if (!opts.skipStatic && isCodacyAvailable()) {
|
|
14443
|
-
|
|
14444
|
-
|
|
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
|
+
}
|
|
14445
14734
|
}
|
|
14446
|
-
|
|
14735
|
+
const deltaSet = baseline ? recentForReview.filter((f) => changedSinceBaseline(f, baseline)) : recentForReview;
|
|
14736
|
+
codeDelta = collectCodeDelta(deltaSet, {
|
|
14447
14737
|
maxFiles: parseInt(opts.maxFiles, 10),
|
|
14448
14738
|
maxFileBytes: parseInt(opts.maxFileSize, 10),
|
|
14449
14739
|
maxTotalBytes: parseInt(opts.maxTotalSize, 10)
|
|
@@ -14458,7 +14748,12 @@ async function runAnalyze(opts, globals) {
|
|
|
14458
14748
|
}
|
|
14459
14749
|
}
|
|
14460
14750
|
if (analysisMode !== "plan") {
|
|
14461
|
-
|
|
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
|
+
}
|
|
14462
14757
|
currentCommit = getCurrentCommit();
|
|
14463
14758
|
const maxIterations = parseInt(opts.maxIterations, 10);
|
|
14464
14759
|
const iterResult = checkMaxIterations(currentCommit, maxIterations, contentHash ?? void 0);
|
|
@@ -14490,9 +14785,9 @@ async function runAnalyze(opts, globals) {
|
|
|
14490
14785
|
let autoSeedNotice = null;
|
|
14491
14786
|
try {
|
|
14492
14787
|
await ensureMemoryDir();
|
|
14493
|
-
const seedMarker = (0,
|
|
14494
|
-
const hasStandard = (0,
|
|
14495
|
-
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);
|
|
14496
14791
|
if (hasStandard && !alreadyTried) {
|
|
14497
14792
|
const preManifest = await buildManifest();
|
|
14498
14793
|
if (preManifest.nodes.length === 0) {
|
|
@@ -14505,7 +14800,7 @@ async function runAnalyze(opts, globals) {
|
|
|
14505
14800
|
dryRun: false
|
|
14506
14801
|
});
|
|
14507
14802
|
if (seedResult.created > 0) {
|
|
14508
|
-
(0,
|
|
14803
|
+
(0, import_node_fs19.writeFileSync)(seedMarker, `${(/* @__PURE__ */ new Date()).toISOString()} created=${seedResult.created}
|
|
14509
14804
|
`);
|
|
14510
14805
|
autoSeedNotice = `Seeded ${seedResult.created} knowledge node(s) from your existing Standard (one-time).`;
|
|
14511
14806
|
logEvent("auto_seed_ran", {
|
|
@@ -14513,7 +14808,7 @@ async function runAnalyze(opts, globals) {
|
|
|
14513
14808
|
failed: seedResult.failed
|
|
14514
14809
|
});
|
|
14515
14810
|
} else if (seedResult.skipped === "already_seeded") {
|
|
14516
|
-
(0,
|
|
14811
|
+
(0, import_node_fs19.writeFileSync)(seedMarker, `${(/* @__PURE__ */ new Date()).toISOString()} skipped=already_seeded
|
|
14517
14812
|
`);
|
|
14518
14813
|
} else {
|
|
14519
14814
|
logEvent("auto_seed_noop", {
|
|
@@ -14831,8 +15126,54 @@ async function runAnalyze(opts, globals) {
|
|
|
14831
15126
|
}
|
|
14832
15127
|
}
|
|
14833
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
|
+
|
|
14834
15175
|
// src/commands/review.ts
|
|
14835
|
-
var
|
|
15176
|
+
var import_node_fs21 = require("node:fs");
|
|
14836
15177
|
function registerReviewCommand(program2) {
|
|
14837
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) => {
|
|
14838
15179
|
const globals = program2.opts();
|
|
@@ -14851,7 +15192,7 @@ async function runReview(opts, globals) {
|
|
|
14851
15192
|
const securityFiles = filterSecurity(allFiles);
|
|
14852
15193
|
let staticResults;
|
|
14853
15194
|
if (isCodacyAvailable()) {
|
|
14854
|
-
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);
|
|
14855
15196
|
staticResults = runCodacyAnalysis(scannable);
|
|
14856
15197
|
} else {
|
|
14857
15198
|
staticResults = {
|
|
@@ -14876,10 +15217,10 @@ async function runReview(opts, globals) {
|
|
|
14876
15217
|
const specPaths = opts.specs.split(",").map((f) => f.trim()).filter(Boolean);
|
|
14877
15218
|
specs = [];
|
|
14878
15219
|
for (const p of specPaths) {
|
|
14879
|
-
if (!(0,
|
|
15220
|
+
if (!(0, import_node_fs21.existsSync)(p)) continue;
|
|
14880
15221
|
try {
|
|
14881
|
-
const { readFileSync:
|
|
14882
|
-
const content =
|
|
15222
|
+
const { readFileSync: readFileSync12 } = await import("node:fs");
|
|
15223
|
+
const content = readFileSync12(p, "utf-8");
|
|
14883
15224
|
specs.push({ path: p, content: content.slice(0, 10240) });
|
|
14884
15225
|
} catch {
|
|
14885
15226
|
}
|
|
@@ -14936,10 +15277,10 @@ async function runReview(opts, globals) {
|
|
|
14936
15277
|
}
|
|
14937
15278
|
|
|
14938
15279
|
// src/commands/guard.ts
|
|
14939
|
-
var
|
|
14940
|
-
var
|
|
15280
|
+
var import_node_fs22 = require("node:fs");
|
|
15281
|
+
var import_node_path15 = require("node:path");
|
|
14941
15282
|
var GUARD_BLOCK_CAP = 2;
|
|
14942
|
-
var GUARD_ITER_FILE = (0,
|
|
15283
|
+
var GUARD_ITER_FILE = (0, import_node_path15.join)(VERITY_DIR, ".guard-iteration");
|
|
14943
15284
|
function readPreToolUseStdin() {
|
|
14944
15285
|
const empty = { command: "", cwd: null, sessionId: null };
|
|
14945
15286
|
return new Promise((resolve) => {
|
|
@@ -15003,7 +15344,7 @@ function classifyCommand(command, on) {
|
|
|
15003
15344
|
}
|
|
15004
15345
|
function readIterMap() {
|
|
15005
15346
|
try {
|
|
15006
|
-
const raw = JSON.parse((0,
|
|
15347
|
+
const raw = JSON.parse((0, import_node_fs22.readFileSync)(GUARD_ITER_FILE, "utf-8"));
|
|
15007
15348
|
if (raw && typeof raw === "object") {
|
|
15008
15349
|
if (typeof raw.moment === "string" && typeof raw.count === "number") {
|
|
15009
15350
|
return { [raw.moment]: raw.count };
|
|
@@ -15023,10 +15364,10 @@ function readIter(moment) {
|
|
|
15023
15364
|
}
|
|
15024
15365
|
function writeIter(moment, count) {
|
|
15025
15366
|
try {
|
|
15026
|
-
(0,
|
|
15367
|
+
(0, import_node_fs22.mkdirSync)(VERITY_DIR, { recursive: true });
|
|
15027
15368
|
const map = readIterMap();
|
|
15028
15369
|
map[moment] = count;
|
|
15029
|
-
(0,
|
|
15370
|
+
(0, import_node_fs22.writeFileSync)(GUARD_ITER_FILE, JSON.stringify(map));
|
|
15030
15371
|
} catch {
|
|
15031
15372
|
}
|
|
15032
15373
|
}
|
|
@@ -15036,10 +15377,10 @@ function resetIter(moment) {
|
|
|
15036
15377
|
if (!(moment in map)) return;
|
|
15037
15378
|
delete map[moment];
|
|
15038
15379
|
if (Object.keys(map).length === 0) {
|
|
15039
|
-
if ((0,
|
|
15380
|
+
if ((0, import_node_fs22.existsSync)(GUARD_ITER_FILE)) (0, import_node_fs22.unlinkSync)(GUARD_ITER_FILE);
|
|
15040
15381
|
} else {
|
|
15041
|
-
(0,
|
|
15042
|
-
(0,
|
|
15382
|
+
(0, import_node_fs22.mkdirSync)(VERITY_DIR, { recursive: true });
|
|
15383
|
+
(0, import_node_fs22.writeFileSync)(GUARD_ITER_FILE, JSON.stringify(map));
|
|
15043
15384
|
}
|
|
15044
15385
|
} catch {
|
|
15045
15386
|
}
|
|
@@ -15057,12 +15398,53 @@ function registerGuardCommand(program2) {
|
|
|
15057
15398
|
function getMomentFiles(moment) {
|
|
15058
15399
|
return moment === "pre-commit" ? getStagedFiles() : getPushRangeFiles().files;
|
|
15059
15400
|
}
|
|
15060
|
-
function
|
|
15401
|
+
function matchFlagValue(command, flags) {
|
|
15402
|
+
const re = new RegExp(`(?<![\\w-])(?:${flags})(?:=|\\s+)('((?:[^'\\\\]|\\\\.)*)'|"((?:[^"\\\\]|\\\\.)*)"|([^\\s'"-][^\\s]*))`);
|
|
15403
|
+
const m = re.exec(command);
|
|
15404
|
+
if (!m) return null;
|
|
15405
|
+
const v = m[2] ?? m[3] ?? m[4];
|
|
15406
|
+
return v != null ? v.replace(/\\(["'])/g, "$1") : null;
|
|
15407
|
+
}
|
|
15408
|
+
function parseCommitMessage(command) {
|
|
15409
|
+
const parts = [];
|
|
15410
|
+
const re = /(?<![\w-])(?:--message|-am|-m)(?:=|\s+)('((?:[^'\\]|\\.)*)'|"((?:[^"\\]|\\.)*)"|([^\s'"-][^\s]*))/g;
|
|
15411
|
+
let m;
|
|
15412
|
+
while ((m = re.exec(command)) !== null) {
|
|
15413
|
+
const v = m[2] ?? m[3] ?? m[4];
|
|
15414
|
+
if (v != null && v.length) parts.push(v.replace(/\\(["'])/g, "$1"));
|
|
15415
|
+
}
|
|
15416
|
+
return parts.length ? parts.join("\n\n") : null;
|
|
15417
|
+
}
|
|
15418
|
+
function parsePrIntent(command) {
|
|
15419
|
+
const title = matchFlagValue(command, "--title|-t");
|
|
15420
|
+
const body = matchFlagValue(command, "--body|-b");
|
|
15421
|
+
const parts = [title, body].filter((x) => !!x);
|
|
15422
|
+
return parts.length ? parts.join("\n\n") : null;
|
|
15423
|
+
}
|
|
15424
|
+
var TRIVIAL_INTENT = /^(wip|tmp|temp|test|fix|chore|amend|\.+|fixup!.*|squash!.*|merge\b.*)$/i;
|
|
15425
|
+
var SHELL_PLUMBING = /\$\(|`|<<-?\s*['"]?[A-Za-z_]/;
|
|
15426
|
+
function isSubstantiveIntent(text) {
|
|
15427
|
+
if (!text) return false;
|
|
15428
|
+
const t = text.trim();
|
|
15429
|
+
if (t.length < 12) return false;
|
|
15430
|
+
if (TRIVIAL_INTENT.test(t)) return false;
|
|
15431
|
+
if (SHELL_PLUMBING.test(t)) return false;
|
|
15432
|
+
return true;
|
|
15433
|
+
}
|
|
15434
|
+
function extractStatedIntent(moment, command) {
|
|
15435
|
+
const text = moment === "pre-commit" ? parseCommitMessage(command) : parsePrIntent(command) ?? (getPushRangeMessages() || null);
|
|
15436
|
+
return isSubstantiveIntent(text) ? text : null;
|
|
15437
|
+
}
|
|
15438
|
+
function hasBlockingFinding(response) {
|
|
15439
|
+
const findings = response.findings ?? [];
|
|
15440
|
+
return findings.some((f) => f.scope !== "pre-existing" && ["critical", "high"].includes((f.severity ?? "").toLowerCase()));
|
|
15441
|
+
}
|
|
15442
|
+
function buildGuardRequest(moment, files, iter, sessionId, command) {
|
|
15061
15443
|
const analyzable = filterAnalyzable(files);
|
|
15062
15444
|
const securityFiles = filterSecurity(files);
|
|
15063
15445
|
let staticResults;
|
|
15064
15446
|
if (isCodacyAvailable()) {
|
|
15065
|
-
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);
|
|
15066
15448
|
staticResults = runCodacyAnalysis(scannable);
|
|
15067
15449
|
} else {
|
|
15068
15450
|
staticResults = { tool: "@codacy/analysis-cli", findings: [], summary: { total_findings: 0, by_severity: {}, tools_run: [] } };
|
|
@@ -15087,26 +15469,27 @@ function buildGuardRequest(moment, files, iter, sessionId) {
|
|
|
15087
15469
|
};
|
|
15088
15470
|
const specs = discoverSpecs();
|
|
15089
15471
|
const plans = discoverPlans();
|
|
15090
|
-
|
|
15472
|
+
const statedIntent = extractStatedIntent(moment, command);
|
|
15473
|
+
if (specs.length > 0 || plans.length > 0 || statedIntent) {
|
|
15091
15474
|
const intentContext = {};
|
|
15475
|
+
if (statedIntent) intentContext.user_prompt = statedIntent;
|
|
15092
15476
|
if (specs.length > 0) intentContext.specs = specs;
|
|
15093
15477
|
if (plans.length > 0) intentContext.plans = plans;
|
|
15094
15478
|
requestBody.intent_context = intentContext;
|
|
15095
15479
|
}
|
|
15096
15480
|
return requestBody;
|
|
15097
15481
|
}
|
|
15098
|
-
function
|
|
15099
|
-
|
|
15100
|
-
|
|
15101
|
-
|
|
15102
|
-
|
|
15103
|
-
}
|
|
15482
|
+
function emitAllowNotice(userMsg, agentMsg) {
|
|
15483
|
+
process.stdout.write(JSON.stringify({
|
|
15484
|
+
systemMessage: userMsg,
|
|
15485
|
+
hookSpecificOutput: { hookEventName: "PreToolUse", additionalContext: agentMsg }
|
|
15486
|
+
}) + "\n");
|
|
15104
15487
|
process.exit(0);
|
|
15105
15488
|
}
|
|
15106
15489
|
async function runGuard(opts, globals) {
|
|
15107
15490
|
const on = opts.on.split(",").map((s) => s.trim()).filter((s) => s === "commit" || s === "push");
|
|
15108
15491
|
const { command, cwd, sessionId } = await readPreToolUseStdin();
|
|
15109
|
-
if (cwd && (0,
|
|
15492
|
+
if (cwd && (0, import_node_fs22.existsSync)(cwd)) {
|
|
15110
15493
|
try {
|
|
15111
15494
|
process.chdir(cwd);
|
|
15112
15495
|
} catch {
|
|
@@ -15114,19 +15497,21 @@ async function runGuard(opts, globals) {
|
|
|
15114
15497
|
}
|
|
15115
15498
|
const moment = classifyCommand(command, on);
|
|
15116
15499
|
if (!moment) process.exit(0);
|
|
15500
|
+
const verb = moment === "pre-commit" ? "commit" : "push";
|
|
15117
15501
|
const iter = readIter(moment);
|
|
15118
15502
|
if (iter >= GUARD_BLOCK_CAP) {
|
|
15119
|
-
process.stderr.write(`${DIM}Verity ${moment}: ${GUARD_BLOCK_CAP} review cycles reached \u2014 allowing through.${NC}
|
|
15120
|
-
`);
|
|
15121
15503
|
resetIter(moment);
|
|
15122
|
-
|
|
15504
|
+
emitAllowNotice(
|
|
15505
|
+
`Verity ${moment}: ${GUARD_BLOCK_CAP} review cycles reached \u2014 allowing the ${verb} through`,
|
|
15506
|
+
`Verity ${moment}: review-cycle cap (${GUARD_BLOCK_CAP}) reached; the ${verb} was allowed without a further block.`
|
|
15507
|
+
);
|
|
15123
15508
|
}
|
|
15124
15509
|
const files = getMomentFiles(moment);
|
|
15125
15510
|
if (files.length === 0) process.exit(0);
|
|
15126
15511
|
const tokenResult = await resolveToken(globals.token);
|
|
15127
15512
|
const urlResult = await resolveServiceUrl(globals.serviceUrl);
|
|
15128
15513
|
if (!tokenResult.ok || !urlResult.ok) process.exit(0);
|
|
15129
|
-
const requestBody = buildGuardRequest(moment, files, iter, sessionId);
|
|
15514
|
+
const requestBody = buildGuardRequest(moment, files, iter, sessionId, command);
|
|
15130
15515
|
if (!requestBody) process.exit(0);
|
|
15131
15516
|
const result = await analyzeRequest({
|
|
15132
15517
|
serviceUrl: urlResult.data,
|
|
@@ -15137,21 +15522,39 @@ async function runGuard(opts, globals) {
|
|
|
15137
15522
|
cmd: "guard"
|
|
15138
15523
|
});
|
|
15139
15524
|
if (!result.ok) {
|
|
15140
|
-
|
|
15141
|
-
|
|
15142
|
-
|
|
15143
|
-
|
|
15144
|
-
if (opts.json) {
|
|
15145
|
-
process.stdout.write(JSON.stringify(result.data) + "\n");
|
|
15525
|
+
emitAllowNotice(
|
|
15526
|
+
`\u26A0 Verity ${moment}: service offline \u2014 ${verb}ed WITHOUT review`,
|
|
15527
|
+
`Verity ${moment}: service unavailable (${result.error}); the ${verb} was allowed WITHOUT a Verity review.`
|
|
15528
|
+
);
|
|
15146
15529
|
}
|
|
15530
|
+
if (opts.json) process.stderr.write(JSON.stringify(result.data) + "\n");
|
|
15147
15531
|
const response = result.data;
|
|
15148
15532
|
const decision = response.gate_decision ?? "PASS";
|
|
15149
|
-
|
|
15533
|
+
const viewUrl = response.view_url ?? "";
|
|
15534
|
+
const link = viewUrl ? ` \u2014 ${viewUrl}` : "";
|
|
15535
|
+
if (decision === "FAIL" && hasBlockingFinding(response)) {
|
|
15150
15536
|
writeIter(moment, iter + 1);
|
|
15151
15537
|
writeBlockMessage(moment, response);
|
|
15152
15538
|
process.exit(2);
|
|
15153
15539
|
}
|
|
15154
|
-
|
|
15540
|
+
resetIter(moment);
|
|
15541
|
+
if (decision === "FAIL") {
|
|
15542
|
+
const narrative = response.assessment?.narrative ?? "";
|
|
15543
|
+
emitAllowNotice(
|
|
15544
|
+
`\u26A0 Verity ${moment}: the ${verb} may not match its stated purpose \u2014 proceeding${link}`,
|
|
15545
|
+
`Verity ${moment}: intent-alignment WARNING (not blocked).${narrative ? " " + narrative : ""}${viewUrl ? ` Report: ${viewUrl}` : ""}`
|
|
15546
|
+
);
|
|
15547
|
+
}
|
|
15548
|
+
if (decision === "WARN") {
|
|
15549
|
+
emitAllowNotice(
|
|
15550
|
+
`\u26A0 Verity ${moment}: WARN \u2014 proceeding${link}`,
|
|
15551
|
+
`Verity ${moment} review: WARN (proceeding).${viewUrl ? ` Report: ${viewUrl}` : ""}`
|
|
15552
|
+
);
|
|
15553
|
+
}
|
|
15554
|
+
emitAllowNotice(
|
|
15555
|
+
`\u2713 Verity ${moment}: PASS${link}`,
|
|
15556
|
+
`Verity ${moment} review: PASS.${viewUrl ? ` Report: ${viewUrl}` : ""}`
|
|
15557
|
+
);
|
|
15155
15558
|
}
|
|
15156
15559
|
function writeBlockMessage(moment, response) {
|
|
15157
15560
|
const label2 = moment === "pre-commit" ? "pre-commit" : "pre-push";
|
|
@@ -15191,14 +15594,14 @@ function writeBlockMessage(moment, response) {
|
|
|
15191
15594
|
}
|
|
15192
15595
|
|
|
15193
15596
|
// src/commands/init.ts
|
|
15194
|
-
var
|
|
15597
|
+
var import_node_fs24 = require("node:fs");
|
|
15195
15598
|
var import_promises12 = require("node:fs/promises");
|
|
15196
|
-
var
|
|
15599
|
+
var import_node_path17 = require("node:path");
|
|
15197
15600
|
var import_node_child_process9 = require("node:child_process");
|
|
15198
15601
|
|
|
15199
15602
|
// src/commands/migrate.ts
|
|
15200
|
-
var
|
|
15201
|
-
var
|
|
15603
|
+
var import_node_fs23 = require("node:fs");
|
|
15604
|
+
var import_node_path16 = require("node:path");
|
|
15202
15605
|
var import_node_child_process8 = require("node:child_process");
|
|
15203
15606
|
var LEGACY_NPM_PACKAGE = "@codacy/gate-cli";
|
|
15204
15607
|
function defaultNpmRemover(pkg) {
|
|
@@ -15234,12 +15637,12 @@ async function runMigration(opts = {}) {
|
|
|
15234
15637
|
return { actions, migrated: actions.length > 0 };
|
|
15235
15638
|
}
|
|
15236
15639
|
function migrateProjectDir(root, actions) {
|
|
15237
|
-
const gateDir = (0,
|
|
15238
|
-
const verityDir = (0,
|
|
15239
|
-
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)) {
|
|
15240
15643
|
return migrateProjectDirRename(root, gateDir, verityDir, actions);
|
|
15241
15644
|
}
|
|
15242
|
-
if ((0,
|
|
15645
|
+
if ((0, import_node_fs23.existsSync)(gateDir) && (0, import_node_fs23.existsSync)(verityDir)) {
|
|
15243
15646
|
return migrateProjectDirCarry(gateDir, verityDir, actions);
|
|
15244
15647
|
}
|
|
15245
15648
|
return false;
|
|
@@ -15260,13 +15663,13 @@ function migrateProjectDirRename(root, gateDir, verityDir, actions) {
|
|
|
15260
15663
|
}
|
|
15261
15664
|
}
|
|
15262
15665
|
if (moved) {
|
|
15263
|
-
if ((0,
|
|
15666
|
+
if ((0, import_node_fs23.existsSync)(gateDir)) {
|
|
15264
15667
|
const carried = carryLegacyContents(gateDir, verityDir);
|
|
15265
15668
|
if (carried > 0) {
|
|
15266
15669
|
actions.push(`Carried ${carried} untracked legacy file(s) from .gate/ into .verity/`);
|
|
15267
15670
|
}
|
|
15268
15671
|
try {
|
|
15269
|
-
(0,
|
|
15672
|
+
(0, import_node_fs23.rmSync)(gateDir, { recursive: true, force: true });
|
|
15270
15673
|
} catch {
|
|
15271
15674
|
}
|
|
15272
15675
|
}
|
|
@@ -15282,18 +15685,18 @@ function migrateProjectDirCarry(gateDir, verityDir, actions) {
|
|
|
15282
15685
|
actions.push(`Carried ${carried} legacy file(s) from .gate/ into .verity/`);
|
|
15283
15686
|
}
|
|
15284
15687
|
try {
|
|
15285
|
-
(0,
|
|
15688
|
+
(0, import_node_fs23.rmSync)(gateDir, { recursive: true, force: true });
|
|
15286
15689
|
} catch {
|
|
15287
15690
|
}
|
|
15288
15691
|
return carried > 0;
|
|
15289
15692
|
}
|
|
15290
15693
|
function migrateGlobalCredentials(home, actions) {
|
|
15291
15694
|
if (!home) return;
|
|
15292
|
-
const gateCreds = (0,
|
|
15293
|
-
const verityCreds = (0,
|
|
15294
|
-
if (!(0,
|
|
15295
|
-
if (!(0,
|
|
15296
|
-
(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 });
|
|
15297
15700
|
moveFile(gateCreds, verityCreds);
|
|
15298
15701
|
actions.push("Moved ~/.gate/credentials \u2192 ~/.verity/credentials");
|
|
15299
15702
|
return;
|
|
@@ -15315,8 +15718,8 @@ async function migrateLegacyHooks(root, actions) {
|
|
|
15315
15718
|
}
|
|
15316
15719
|
}
|
|
15317
15720
|
async function migrateClaudeMd(root, actions) {
|
|
15318
|
-
const claudeMd = (0,
|
|
15319
|
-
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));
|
|
15320
15723
|
if (!hadLegacyBlock) return;
|
|
15321
15724
|
try {
|
|
15322
15725
|
await ensureClaudeMdPointer(root);
|
|
@@ -15326,9 +15729,9 @@ async function migrateClaudeMd(root, actions) {
|
|
|
15326
15729
|
}
|
|
15327
15730
|
}
|
|
15328
15731
|
function migrateStandardFile(root, actions) {
|
|
15329
|
-
const gateMd = (0,
|
|
15330
|
-
const verityMd = (0,
|
|
15331
|
-
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;
|
|
15332
15735
|
let moved = false;
|
|
15333
15736
|
if (isGitRepo(root) && isGitTracked(root, "GATE.md")) {
|
|
15334
15737
|
try {
|
|
@@ -15340,7 +15743,7 @@ function migrateStandardFile(root, actions) {
|
|
|
15340
15743
|
if (!moved) moveFile(gateMd, verityMd);
|
|
15341
15744
|
const content = readFileSyncSafe(verityMd);
|
|
15342
15745
|
const refreshed = content.split("GATE.md").join("VERITY.md");
|
|
15343
|
-
if (refreshed !== content) (0,
|
|
15746
|
+
if (refreshed !== content) (0, import_node_fs23.writeFileSync)(verityMd, refreshed);
|
|
15344
15747
|
actions.push("Renamed GATE.md \u2192 VERITY.md");
|
|
15345
15748
|
}
|
|
15346
15749
|
function removeLegacyPackage(movedProjectDir, npmRemover, actions) {
|
|
@@ -15374,14 +15777,14 @@ function mergeGlobalCredentials(gateCreds, verityCreds) {
|
|
|
15374
15777
|
}
|
|
15375
15778
|
if (toAppend.length > 0) {
|
|
15376
15779
|
const sep = verityContent.endsWith("\n") || verityContent === "" ? "" : "\n";
|
|
15377
|
-
(0,
|
|
15780
|
+
(0, import_node_fs23.writeFileSync)(verityCreds, verityContent + sep + toAppend.join("\n") + "\n");
|
|
15378
15781
|
}
|
|
15379
|
-
(0,
|
|
15782
|
+
(0, import_node_fs23.rmSync)(gateCreds, { force: true });
|
|
15380
15783
|
return toAppend.length;
|
|
15381
15784
|
}
|
|
15382
15785
|
function readFileSyncSafe(path) {
|
|
15383
15786
|
try {
|
|
15384
|
-
return (0,
|
|
15787
|
+
return (0, import_node_fs23.readFileSync)(path, "utf-8");
|
|
15385
15788
|
} catch {
|
|
15386
15789
|
return "";
|
|
15387
15790
|
}
|
|
@@ -15396,35 +15799,35 @@ function hasStagedChanges(root) {
|
|
|
15396
15799
|
}
|
|
15397
15800
|
function moveDir(from, to) {
|
|
15398
15801
|
try {
|
|
15399
|
-
(0,
|
|
15802
|
+
(0, import_node_fs23.renameSync)(from, to);
|
|
15400
15803
|
} catch (err) {
|
|
15401
15804
|
if (err.code !== "EXDEV") throw err;
|
|
15402
|
-
(0,
|
|
15403
|
-
(0,
|
|
15805
|
+
(0, import_node_fs23.cpSync)(from, to, { recursive: true });
|
|
15806
|
+
(0, import_node_fs23.rmSync)(from, { recursive: true, force: true });
|
|
15404
15807
|
}
|
|
15405
15808
|
}
|
|
15406
15809
|
function moveFile(from, to) {
|
|
15407
15810
|
try {
|
|
15408
|
-
(0,
|
|
15811
|
+
(0, import_node_fs23.renameSync)(from, to);
|
|
15409
15812
|
} catch (err) {
|
|
15410
15813
|
if (err.code !== "EXDEV") throw err;
|
|
15411
|
-
(0,
|
|
15412
|
-
(0,
|
|
15814
|
+
(0, import_node_fs23.cpSync)(from, to);
|
|
15815
|
+
(0, import_node_fs23.rmSync)(from, { force: true });
|
|
15413
15816
|
}
|
|
15414
15817
|
}
|
|
15415
15818
|
function carryLegacyContents(gateDir, verityDir) {
|
|
15416
15819
|
let copied = 0;
|
|
15417
15820
|
const walk = (relDir) => {
|
|
15418
|
-
const srcDir = (0,
|
|
15419
|
-
for (const entry of (0,
|
|
15420
|
-
const rel = relDir ? (0,
|
|
15421
|
-
const src = (0,
|
|
15422
|
-
const dest = (0,
|
|
15423
|
-
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()) {
|
|
15424
15827
|
walk(rel);
|
|
15425
|
-
} else if (!(0,
|
|
15426
|
-
(0,
|
|
15427
|
-
(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);
|
|
15428
15831
|
copied++;
|
|
15429
15832
|
}
|
|
15430
15833
|
}
|
|
@@ -15433,22 +15836,22 @@ function carryLegacyContents(gateDir, verityDir) {
|
|
|
15433
15836
|
return copied;
|
|
15434
15837
|
}
|
|
15435
15838
|
async function needsMigration(root = repoRoot()) {
|
|
15436
|
-
const gateDir = (0,
|
|
15437
|
-
const verityDir = (0,
|
|
15438
|
-
if ((0,
|
|
15439
|
-
if ((0,
|
|
15440
|
-
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"))) {
|
|
15441
15844
|
return true;
|
|
15442
15845
|
}
|
|
15443
|
-
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"))) {
|
|
15444
15847
|
return true;
|
|
15445
15848
|
}
|
|
15446
15849
|
}
|
|
15447
|
-
const claudeMd = (0,
|
|
15448
|
-
if ((0,
|
|
15850
|
+
const claudeMd = (0, import_node_path16.join)(root, "CLAUDE.md");
|
|
15851
|
+
if ((0, import_node_fs23.existsSync)(claudeMd) && hasLegacyMemoryBlock(readFileSyncSafe(claudeMd))) {
|
|
15449
15852
|
return true;
|
|
15450
15853
|
}
|
|
15451
|
-
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"))) {
|
|
15452
15855
|
return true;
|
|
15453
15856
|
}
|
|
15454
15857
|
if (await hasLegacyHooksAt(root)) return true;
|
|
@@ -15476,15 +15879,15 @@ function registerMigrateCommand(program2) {
|
|
|
15476
15879
|
// src/commands/init.ts
|
|
15477
15880
|
function resolveDataDir() {
|
|
15478
15881
|
const candidates = [
|
|
15479
|
-
(0,
|
|
15882
|
+
(0, import_node_path17.join)(__dirname, "..", "data"),
|
|
15480
15883
|
// installed: node_modules/@codacy/verity-cli/data
|
|
15481
|
-
(0,
|
|
15884
|
+
(0, import_node_path17.join)(__dirname, "..", "..", "data"),
|
|
15482
15885
|
// edge case: nested resolution
|
|
15483
|
-
(0,
|
|
15886
|
+
(0, import_node_path17.join)(process.cwd(), "cli", "data")
|
|
15484
15887
|
// local dev: running from repo root
|
|
15485
15888
|
];
|
|
15486
15889
|
for (const candidate of candidates) {
|
|
15487
|
-
if ((0,
|
|
15890
|
+
if ((0, import_node_fs24.existsSync)((0, import_node_path17.join)(candidate, "skills"))) {
|
|
15488
15891
|
return candidate;
|
|
15489
15892
|
}
|
|
15490
15893
|
}
|
|
@@ -15500,7 +15903,7 @@ function registerInitCommand(program2) {
|
|
|
15500
15903
|
program2.command("init").description("Initialize Verity in the current project").option("--force", "Overwrite existing skills and hooks").action(async (opts) => {
|
|
15501
15904
|
const force = opts.force ?? false;
|
|
15502
15905
|
const projectMarkers = [".git", "package.json", "pyproject.toml", "go.mod", "Cargo.toml", "Gemfile", "pom.xml", "build.gradle"];
|
|
15503
|
-
const isProject = projectMarkers.some((m) => (0,
|
|
15906
|
+
const isProject = projectMarkers.some((m) => (0, import_node_fs24.existsSync)(m));
|
|
15504
15907
|
if (!isProject) {
|
|
15505
15908
|
printError("No project detected in the current directory.");
|
|
15506
15909
|
printInfo('Run "verity init" from your project root.');
|
|
@@ -15563,21 +15966,21 @@ function registerInitCommand(program2) {
|
|
|
15563
15966
|
console.log("");
|
|
15564
15967
|
printInfo("Installing skills...");
|
|
15565
15968
|
const dataDir = resolveDataDir();
|
|
15566
|
-
const skillsSource = (0,
|
|
15969
|
+
const skillsSource = (0, import_node_path17.join)(dataDir, "skills");
|
|
15567
15970
|
const skillsDest = ".claude/skills";
|
|
15568
15971
|
const skills = ["verity-setup", "verity-analyze", "verity-status", "verity-feedback", "verity-learn", "verity-memory", "verity-insights", "verity-reflect"];
|
|
15569
15972
|
let skillsInstalled = 0;
|
|
15570
15973
|
for (const skill of skills) {
|
|
15571
|
-
const src = (0,
|
|
15572
|
-
const dest = (0,
|
|
15573
|
-
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)) {
|
|
15574
15977
|
printWarn(` Skill data not found: ${skill}`);
|
|
15575
15978
|
continue;
|
|
15576
15979
|
}
|
|
15577
|
-
if ((0,
|
|
15578
|
-
const srcSkill = (0,
|
|
15579
|
-
const destSkill = (0,
|
|
15580
|
-
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)) {
|
|
15581
15984
|
try {
|
|
15582
15985
|
const srcContent = await (0, import_promises12.readFile)(srcSkill, "utf-8");
|
|
15583
15986
|
const destContent = await (0, import_promises12.readFile)(destSkill, "utf-8");
|
|
@@ -15601,6 +16004,7 @@ function registerInitCommand(program2) {
|
|
|
15601
16004
|
await writeSettings(hookResult.data);
|
|
15602
16005
|
printInfo(" Stop hook: verity analyze \u2713");
|
|
15603
16006
|
printInfo(" Intent hook: verity intent capture \u2713");
|
|
16007
|
+
printInfo(" Baseline hook: verity baseline capture \u2713");
|
|
15604
16008
|
} else {
|
|
15605
16009
|
printWarn(` ${hookResult.error}`);
|
|
15606
16010
|
printInfo(' Run "verity hooks install --force" to overwrite.');
|
|
@@ -15613,7 +16017,7 @@ function registerInitCommand(program2) {
|
|
|
15613
16017
|
} catch (err) {
|
|
15614
16018
|
printWarn(` Could not update CLAUDE.md: ${err.message}`);
|
|
15615
16019
|
}
|
|
15616
|
-
const globalVerityDir = (0,
|
|
16020
|
+
const globalVerityDir = (0, import_node_path17.join)(process.env.HOME ?? "", ".verity");
|
|
15617
16021
|
await (0, import_promises12.mkdir)(globalVerityDir, { recursive: true });
|
|
15618
16022
|
console.log("");
|
|
15619
16023
|
printInfo("Verity initialized!");
|
|
@@ -15636,8 +16040,8 @@ function registerInitCommand(program2) {
|
|
|
15636
16040
|
}
|
|
15637
16041
|
|
|
15638
16042
|
// src/commands/uninstall.ts
|
|
15639
|
-
var
|
|
15640
|
-
var
|
|
16043
|
+
var import_node_fs25 = require("node:fs");
|
|
16044
|
+
var import_node_path18 = require("node:path");
|
|
15641
16045
|
var SKILL_NAMES = [
|
|
15642
16046
|
"verity-setup",
|
|
15643
16047
|
"verity-analyze",
|
|
@@ -15656,11 +16060,11 @@ function registerUninstallCommand(program2) {
|
|
|
15656
16060
|
const actions = [];
|
|
15657
16061
|
const skillsRoot = projectPath(".claude/skills");
|
|
15658
16062
|
for (const name of SKILL_NAMES) {
|
|
15659
|
-
const dir = (0,
|
|
15660
|
-
if ((0,
|
|
16063
|
+
const dir = (0, import_node_path18.join)(skillsRoot, name);
|
|
16064
|
+
if ((0, import_node_fs25.existsSync)(dir)) {
|
|
15661
16065
|
actions.push({
|
|
15662
16066
|
label: `Remove .claude/skills/${name}/`,
|
|
15663
|
-
apply: () => (0,
|
|
16067
|
+
apply: () => (0, import_node_fs25.rmSync)(dir, { recursive: true, force: true })
|
|
15664
16068
|
});
|
|
15665
16069
|
}
|
|
15666
16070
|
}
|
|
@@ -15674,24 +16078,24 @@ function registerUninstallCommand(program2) {
|
|
|
15674
16078
|
});
|
|
15675
16079
|
}
|
|
15676
16080
|
const verityDir = projectPath(VERITY_DIR);
|
|
15677
|
-
if ((0,
|
|
16081
|
+
if ((0, import_node_fs25.existsSync)(verityDir)) {
|
|
15678
16082
|
actions.push({
|
|
15679
16083
|
label: `Remove ${VERITY_DIR}/`,
|
|
15680
|
-
apply: () => (0,
|
|
16084
|
+
apply: () => (0, import_node_fs25.rmSync)(verityDir, { recursive: true, force: true })
|
|
15681
16085
|
});
|
|
15682
16086
|
}
|
|
15683
16087
|
if (!keepVerityMd) {
|
|
15684
16088
|
const verityMd = projectPath(VERITY_MD_FILE);
|
|
15685
|
-
if ((0,
|
|
16089
|
+
if ((0, import_node_fs25.existsSync)(verityMd)) {
|
|
15686
16090
|
actions.push({
|
|
15687
16091
|
label: `Remove ${VERITY_MD_FILE}`,
|
|
15688
|
-
apply: () => (0,
|
|
16092
|
+
apply: () => (0, import_node_fs25.rmSync)(verityMd, { force: true })
|
|
15689
16093
|
});
|
|
15690
16094
|
}
|
|
15691
16095
|
}
|
|
15692
16096
|
const cleanupEmptyDir = (path) => {
|
|
15693
|
-
if ((0,
|
|
15694
|
-
(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);
|
|
15695
16099
|
}
|
|
15696
16100
|
};
|
|
15697
16101
|
actions.push({
|
|
@@ -15702,11 +16106,11 @@ function registerUninstallCommand(program2) {
|
|
|
15702
16106
|
}
|
|
15703
16107
|
});
|
|
15704
16108
|
const home = process.env.HOME ?? "";
|
|
15705
|
-
const globalVerityDir = (0,
|
|
15706
|
-
if (purgeGlobal && (0,
|
|
16109
|
+
const globalVerityDir = (0, import_node_path18.join)(home, ".verity");
|
|
16110
|
+
if (purgeGlobal && (0, import_node_fs25.existsSync)(globalVerityDir)) {
|
|
15707
16111
|
actions.push({
|
|
15708
16112
|
label: `Remove ~/.verity/ (global credentials \u2014 reconnect requires re-registration)`,
|
|
15709
|
-
apply: () => (0,
|
|
16113
|
+
apply: () => (0, import_node_fs25.rmSync)(globalVerityDir, { recursive: true, force: true })
|
|
15710
16114
|
});
|
|
15711
16115
|
}
|
|
15712
16116
|
if (actions.length === 0) {
|
|
@@ -15900,8 +16304,8 @@ function registerTaskCommands(program2) {
|
|
|
15900
16304
|
}
|
|
15901
16305
|
|
|
15902
16306
|
// src/commands/reset.ts
|
|
15903
|
-
var
|
|
15904
|
-
var
|
|
16307
|
+
var import_node_fs26 = require("node:fs");
|
|
16308
|
+
var import_node_path19 = require("node:path");
|
|
15905
16309
|
function registerResetCommand(program2) {
|
|
15906
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) => {
|
|
15907
16311
|
const globals = program2.opts();
|
|
@@ -15938,11 +16342,11 @@ function registerResetCommand(program2) {
|
|
|
15938
16342
|
}
|
|
15939
16343
|
const cacheDir = projectPath(CACHE_DIR);
|
|
15940
16344
|
let purged = 0;
|
|
15941
|
-
if ((0,
|
|
15942
|
-
for (const entry of (0,
|
|
16345
|
+
if ((0, import_node_fs26.existsSync)(cacheDir)) {
|
|
16346
|
+
for (const entry of (0, import_node_fs26.readdirSync)(cacheDir)) {
|
|
15943
16347
|
if (entry.startsWith("pending-")) {
|
|
15944
16348
|
try {
|
|
15945
|
-
(0,
|
|
16349
|
+
(0, import_node_fs26.unlinkSync)((0, import_node_path19.join)(cacheDir, entry));
|
|
15946
16350
|
purged++;
|
|
15947
16351
|
} catch {
|
|
15948
16352
|
}
|
|
@@ -15957,19 +16361,19 @@ function registerResetCommand(program2) {
|
|
|
15957
16361
|
projectPath(`${VERITY_DIR}/.last-analysis`)
|
|
15958
16362
|
];
|
|
15959
16363
|
for (const file of filesToClear) {
|
|
15960
|
-
if ((0,
|
|
16364
|
+
if ((0, import_node_fs26.existsSync)(file)) {
|
|
15961
16365
|
try {
|
|
15962
|
-
(0,
|
|
16366
|
+
(0, import_node_fs26.writeFileSync)(file, "");
|
|
15963
16367
|
} catch {
|
|
15964
16368
|
}
|
|
15965
16369
|
}
|
|
15966
16370
|
}
|
|
15967
16371
|
if (opts.all) {
|
|
15968
16372
|
const logsDir = projectPath(`${VERITY_DIR}/.logs`);
|
|
15969
|
-
if ((0,
|
|
15970
|
-
for (const entry of (0,
|
|
16373
|
+
if ((0, import_node_fs26.existsSync)(logsDir)) {
|
|
16374
|
+
for (const entry of (0, import_node_fs26.readdirSync)(logsDir)) {
|
|
15971
16375
|
try {
|
|
15972
|
-
(0,
|
|
16376
|
+
(0, import_node_fs26.unlinkSync)((0, import_node_path19.join)(logsDir, entry));
|
|
15973
16377
|
} catch {
|
|
15974
16378
|
}
|
|
15975
16379
|
}
|
|
@@ -15980,10 +16384,29 @@ function registerResetCommand(program2) {
|
|
|
15980
16384
|
});
|
|
15981
16385
|
}
|
|
15982
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
|
+
|
|
15983
16405
|
// src/commands/reflect.ts
|
|
15984
16406
|
function registerReflectCommand(program2) {
|
|
15985
|
-
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) => {
|
|
15986
16408
|
const globals = program2.opts();
|
|
16409
|
+
const mode = resolveRunMode({ autonomousFlag: opts.autonomous });
|
|
15987
16410
|
await ensureMemoryDir();
|
|
15988
16411
|
const tokenResult = await resolveToken(globals.token);
|
|
15989
16412
|
if (!tokenResult.ok) {
|
|
@@ -16074,7 +16497,9 @@ function registerReflectCommand(program2) {
|
|
|
16074
16497
|
const nodeId = result.data.node_id;
|
|
16075
16498
|
const filePath = result.data.file_path;
|
|
16076
16499
|
printInfo(`Queued: ${nodeId} (will sync to .verity/memory/${filePath} on next analysis).`);
|
|
16077
|
-
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
|
+
);
|
|
16078
16503
|
if (taskResolution === "none") {
|
|
16079
16504
|
printInfo("(No task context \u2014 reflection lives at the project level.)");
|
|
16080
16505
|
}
|
|
@@ -16207,7 +16632,7 @@ function registerRunCommand(program2) {
|
|
|
16207
16632
|
|
|
16208
16633
|
// src/lib/telemetry.ts
|
|
16209
16634
|
var import_promises13 = require("node:fs/promises");
|
|
16210
|
-
var
|
|
16635
|
+
var import_node_path20 = require("node:path");
|
|
16211
16636
|
var SETTINGS_LOCAL_FILE2 = ".claude/settings.local.json";
|
|
16212
16637
|
var GITIGNORE_FILE = ".gitignore";
|
|
16213
16638
|
var GITIGNORE_ENTRY = ".claude/settings.local.json";
|
|
@@ -16245,7 +16670,7 @@ async function readSettingsLocal() {
|
|
|
16245
16670
|
}
|
|
16246
16671
|
async function writeSettingsLocal(settings) {
|
|
16247
16672
|
const file = projectPath(SETTINGS_LOCAL_FILE2);
|
|
16248
|
-
await (0, import_promises13.mkdir)((0,
|
|
16673
|
+
await (0, import_promises13.mkdir)((0, import_node_path20.dirname)(file), { recursive: true });
|
|
16249
16674
|
await (0, import_promises13.writeFile)(file, JSON.stringify(settings, null, 2) + "\n");
|
|
16250
16675
|
}
|
|
16251
16676
|
async function ensureGitignore() {
|
|
@@ -16341,7 +16766,7 @@ function registerTelemetryCommands(program2) {
|
|
|
16341
16766
|
}
|
|
16342
16767
|
|
|
16343
16768
|
// src/cli.ts
|
|
16344
|
-
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.6a390ac").option("--token <token>", "Override authentication token").option("--service-url <url>", "Override service URL").option("--verbose", "Log HTTP requests/responses to stderr");
|
|
16345
16770
|
registerAuthCommands(program);
|
|
16346
16771
|
registerHooksCommands(program);
|
|
16347
16772
|
registerIntentCommands(program);
|
|
@@ -16350,6 +16775,7 @@ registerConfigCommands(program);
|
|
|
16350
16775
|
registerStatusCommand(program);
|
|
16351
16776
|
registerFeedbackCommand(program);
|
|
16352
16777
|
registerAnalyzeCommand(program);
|
|
16778
|
+
registerBaselineCommands(program);
|
|
16353
16779
|
registerReviewCommand(program);
|
|
16354
16780
|
registerGuardCommand(program);
|
|
16355
16781
|
registerInitCommand(program);
|