@codacy/verity-cli 0.29.4-experimental.f2e812c → 0.30.0-experimental.452ead4
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/CHANGELOG.md +133 -0
- package/bin/verity.js +1262 -565
- package/data/skills/verity-setup/SKILL.md +21 -8
- package/package.json +1 -1
package/bin/verity.js
CHANGED
|
@@ -6974,10 +6974,10 @@ var require_resolve_block_map = __commonJS({
|
|
|
6974
6974
|
let offset = bm.offset;
|
|
6975
6975
|
let commentEnd = null;
|
|
6976
6976
|
for (const collItem of bm.items) {
|
|
6977
|
-
const { start, key, sep, value } = collItem;
|
|
6977
|
+
const { start, key, sep: sep2, value } = collItem;
|
|
6978
6978
|
const keyProps = resolveProps.resolveProps(start, {
|
|
6979
6979
|
indicator: "explicit-key-ind",
|
|
6980
|
-
next: key ??
|
|
6980
|
+
next: key ?? sep2?.[0],
|
|
6981
6981
|
offset,
|
|
6982
6982
|
onError,
|
|
6983
6983
|
parentIndent: bm.indent,
|
|
@@ -6991,7 +6991,7 @@ var require_resolve_block_map = __commonJS({
|
|
|
6991
6991
|
else if ("indent" in key && key.indent !== bm.indent)
|
|
6992
6992
|
onError(offset, "BAD_INDENT", startColMsg);
|
|
6993
6993
|
}
|
|
6994
|
-
if (!keyProps.anchor && !keyProps.tag && !
|
|
6994
|
+
if (!keyProps.anchor && !keyProps.tag && !sep2) {
|
|
6995
6995
|
commentEnd = keyProps.end;
|
|
6996
6996
|
if (keyProps.comment) {
|
|
6997
6997
|
if (map.comment)
|
|
@@ -7015,7 +7015,7 @@ var require_resolve_block_map = __commonJS({
|
|
|
7015
7015
|
ctx.atKey = false;
|
|
7016
7016
|
if (utilMapIncludes.mapIncludes(ctx, map.items, keyNode))
|
|
7017
7017
|
onError(keyStart, "DUPLICATE_KEY", "Map keys must be unique");
|
|
7018
|
-
const valueProps = resolveProps.resolveProps(
|
|
7018
|
+
const valueProps = resolveProps.resolveProps(sep2 ?? [], {
|
|
7019
7019
|
indicator: "map-value-ind",
|
|
7020
7020
|
next: value,
|
|
7021
7021
|
offset: keyNode.range[2],
|
|
@@ -7031,7 +7031,7 @@ var require_resolve_block_map = __commonJS({
|
|
|
7031
7031
|
if (ctx.options.strict && keyProps.start < valueProps.found.offset - 1024)
|
|
7032
7032
|
onError(keyNode.range, "KEY_OVER_1024_CHARS", "The : indicator must be at most 1024 chars after the start of an implicit block mapping key");
|
|
7033
7033
|
}
|
|
7034
|
-
const valueNode = value ? composeNode(ctx, value, valueProps, onError) : composeEmptyNode(ctx, offset,
|
|
7034
|
+
const valueNode = value ? composeNode(ctx, value, valueProps, onError) : composeEmptyNode(ctx, offset, sep2, null, valueProps, onError);
|
|
7035
7035
|
if (ctx.schema.compat)
|
|
7036
7036
|
utilFlowIndentCheck.flowIndentCheck(bm.indent, value, onError);
|
|
7037
7037
|
offset = valueNode.range[2];
|
|
@@ -7122,7 +7122,7 @@ var require_resolve_end = __commonJS({
|
|
|
7122
7122
|
let comment = "";
|
|
7123
7123
|
if (end) {
|
|
7124
7124
|
let hasSpace = false;
|
|
7125
|
-
let
|
|
7125
|
+
let sep2 = "";
|
|
7126
7126
|
for (const token of end) {
|
|
7127
7127
|
const { source, type } = token;
|
|
7128
7128
|
switch (type) {
|
|
@@ -7136,13 +7136,13 @@ var require_resolve_end = __commonJS({
|
|
|
7136
7136
|
if (!comment)
|
|
7137
7137
|
comment = cb;
|
|
7138
7138
|
else
|
|
7139
|
-
comment +=
|
|
7140
|
-
|
|
7139
|
+
comment += sep2 + cb;
|
|
7140
|
+
sep2 = "";
|
|
7141
7141
|
break;
|
|
7142
7142
|
}
|
|
7143
7143
|
case "newline":
|
|
7144
7144
|
if (comment)
|
|
7145
|
-
|
|
7145
|
+
sep2 += source;
|
|
7146
7146
|
hasSpace = true;
|
|
7147
7147
|
break;
|
|
7148
7148
|
default:
|
|
@@ -7185,18 +7185,18 @@ var require_resolve_flow_collection = __commonJS({
|
|
|
7185
7185
|
let offset = fc.offset + fc.start.source.length;
|
|
7186
7186
|
for (let i = 0; i < fc.items.length; ++i) {
|
|
7187
7187
|
const collItem = fc.items[i];
|
|
7188
|
-
const { start, key, sep, value } = collItem;
|
|
7188
|
+
const { start, key, sep: sep2, value } = collItem;
|
|
7189
7189
|
const props = resolveProps.resolveProps(start, {
|
|
7190
7190
|
flow: fcName,
|
|
7191
7191
|
indicator: "explicit-key-ind",
|
|
7192
|
-
next: key ??
|
|
7192
|
+
next: key ?? sep2?.[0],
|
|
7193
7193
|
offset,
|
|
7194
7194
|
onError,
|
|
7195
7195
|
parentIndent: fc.indent,
|
|
7196
7196
|
startOnNewline: false
|
|
7197
7197
|
});
|
|
7198
7198
|
if (!props.found) {
|
|
7199
|
-
if (!props.anchor && !props.tag && !
|
|
7199
|
+
if (!props.anchor && !props.tag && !sep2 && !value) {
|
|
7200
7200
|
if (i === 0 && props.comma)
|
|
7201
7201
|
onError(props.comma, "UNEXPECTED_TOKEN", `Unexpected , in ${fcName}`);
|
|
7202
7202
|
else if (i < fc.items.length - 1)
|
|
@@ -7250,8 +7250,8 @@ var require_resolve_flow_collection = __commonJS({
|
|
|
7250
7250
|
}
|
|
7251
7251
|
}
|
|
7252
7252
|
}
|
|
7253
|
-
if (!isMap && !
|
|
7254
|
-
const valueNode = value ? composeNode(ctx, value, props, onError) : composeEmptyNode(ctx, props.end,
|
|
7253
|
+
if (!isMap && !sep2 && !props.found) {
|
|
7254
|
+
const valueNode = value ? composeNode(ctx, value, props, onError) : composeEmptyNode(ctx, props.end, sep2, null, props, onError);
|
|
7255
7255
|
coll.items.push(valueNode);
|
|
7256
7256
|
offset = valueNode.range[2];
|
|
7257
7257
|
if (isBlock(value))
|
|
@@ -7263,7 +7263,7 @@ var require_resolve_flow_collection = __commonJS({
|
|
|
7263
7263
|
if (isBlock(key))
|
|
7264
7264
|
onError(keyNode.range, "BLOCK_IN_FLOW", blockMsg);
|
|
7265
7265
|
ctx.atKey = false;
|
|
7266
|
-
const valueProps = resolveProps.resolveProps(
|
|
7266
|
+
const valueProps = resolveProps.resolveProps(sep2 ?? [], {
|
|
7267
7267
|
flow: fcName,
|
|
7268
7268
|
indicator: "map-value-ind",
|
|
7269
7269
|
next: value,
|
|
@@ -7274,8 +7274,8 @@ var require_resolve_flow_collection = __commonJS({
|
|
|
7274
7274
|
});
|
|
7275
7275
|
if (valueProps.found) {
|
|
7276
7276
|
if (!isMap && !props.found && ctx.options.strict) {
|
|
7277
|
-
if (
|
|
7278
|
-
for (const st of
|
|
7277
|
+
if (sep2)
|
|
7278
|
+
for (const st of sep2) {
|
|
7279
7279
|
if (st === valueProps.found)
|
|
7280
7280
|
break;
|
|
7281
7281
|
if (st.type === "newline") {
|
|
@@ -7292,7 +7292,7 @@ var require_resolve_flow_collection = __commonJS({
|
|
|
7292
7292
|
else
|
|
7293
7293
|
onError(valueProps.start, "MISSING_CHAR", `Missing , or : between ${fcName} items`);
|
|
7294
7294
|
}
|
|
7295
|
-
const valueNode = value ? composeNode(ctx, value, valueProps, onError) : valueProps.found ? composeEmptyNode(ctx, valueProps.end,
|
|
7295
|
+
const valueNode = value ? composeNode(ctx, value, valueProps, onError) : valueProps.found ? composeEmptyNode(ctx, valueProps.end, sep2, null, valueProps, onError) : null;
|
|
7296
7296
|
if (valueNode) {
|
|
7297
7297
|
if (isBlock(value))
|
|
7298
7298
|
onError(valueNode.range, "BLOCK_IN_FLOW", blockMsg);
|
|
@@ -7472,7 +7472,7 @@ var require_resolve_block_scalar = __commonJS({
|
|
|
7472
7472
|
chompStart = i + 1;
|
|
7473
7473
|
}
|
|
7474
7474
|
let value = "";
|
|
7475
|
-
let
|
|
7475
|
+
let sep2 = "";
|
|
7476
7476
|
let prevMoreIndented = false;
|
|
7477
7477
|
for (let i = 0; i < contentStart; ++i)
|
|
7478
7478
|
value += lines[i][0].slice(trimIndent) + "\n";
|
|
@@ -7489,24 +7489,24 @@ var require_resolve_block_scalar = __commonJS({
|
|
|
7489
7489
|
indent = "";
|
|
7490
7490
|
}
|
|
7491
7491
|
if (type === Scalar.Scalar.BLOCK_LITERAL) {
|
|
7492
|
-
value +=
|
|
7493
|
-
|
|
7492
|
+
value += sep2 + indent.slice(trimIndent) + content;
|
|
7493
|
+
sep2 = "\n";
|
|
7494
7494
|
} else if (indent.length > trimIndent || content[0] === " ") {
|
|
7495
|
-
if (
|
|
7496
|
-
|
|
7497
|
-
else if (!prevMoreIndented &&
|
|
7498
|
-
|
|
7499
|
-
value +=
|
|
7500
|
-
|
|
7495
|
+
if (sep2 === " ")
|
|
7496
|
+
sep2 = "\n";
|
|
7497
|
+
else if (!prevMoreIndented && sep2 === "\n")
|
|
7498
|
+
sep2 = "\n\n";
|
|
7499
|
+
value += sep2 + indent.slice(trimIndent) + content;
|
|
7500
|
+
sep2 = "\n";
|
|
7501
7501
|
prevMoreIndented = true;
|
|
7502
7502
|
} else if (content === "") {
|
|
7503
|
-
if (
|
|
7503
|
+
if (sep2 === "\n")
|
|
7504
7504
|
value += "\n";
|
|
7505
7505
|
else
|
|
7506
|
-
|
|
7506
|
+
sep2 = "\n";
|
|
7507
7507
|
} else {
|
|
7508
|
-
value +=
|
|
7509
|
-
|
|
7508
|
+
value += sep2 + content;
|
|
7509
|
+
sep2 = " ";
|
|
7510
7510
|
prevMoreIndented = false;
|
|
7511
7511
|
}
|
|
7512
7512
|
}
|
|
@@ -7684,25 +7684,25 @@ var require_resolve_flow_scalar = __commonJS({
|
|
|
7684
7684
|
if (!match)
|
|
7685
7685
|
return source;
|
|
7686
7686
|
let res = match[1];
|
|
7687
|
-
let
|
|
7687
|
+
let sep2 = " ";
|
|
7688
7688
|
let pos = first.lastIndex;
|
|
7689
7689
|
line.lastIndex = pos;
|
|
7690
7690
|
while (match = line.exec(source)) {
|
|
7691
7691
|
if (match[1] === "") {
|
|
7692
|
-
if (
|
|
7693
|
-
res +=
|
|
7692
|
+
if (sep2 === "\n")
|
|
7693
|
+
res += sep2;
|
|
7694
7694
|
else
|
|
7695
|
-
|
|
7695
|
+
sep2 = "\n";
|
|
7696
7696
|
} else {
|
|
7697
|
-
res +=
|
|
7698
|
-
|
|
7697
|
+
res += sep2 + match[1];
|
|
7698
|
+
sep2 = " ";
|
|
7699
7699
|
}
|
|
7700
7700
|
pos = line.lastIndex;
|
|
7701
7701
|
}
|
|
7702
7702
|
const last = /[ \t]*(.*)/sy;
|
|
7703
7703
|
last.lastIndex = pos;
|
|
7704
7704
|
match = last.exec(source);
|
|
7705
|
-
return res +
|
|
7705
|
+
return res + sep2 + (match?.[1] ?? "");
|
|
7706
7706
|
}
|
|
7707
7707
|
function doubleQuotedValue(source, onError) {
|
|
7708
7708
|
let res = "";
|
|
@@ -8509,14 +8509,14 @@ var require_cst_stringify = __commonJS({
|
|
|
8509
8509
|
}
|
|
8510
8510
|
}
|
|
8511
8511
|
}
|
|
8512
|
-
function stringifyItem({ start, key, sep, value }) {
|
|
8512
|
+
function stringifyItem({ start, key, sep: sep2, value }) {
|
|
8513
8513
|
let res = "";
|
|
8514
8514
|
for (const st of start)
|
|
8515
8515
|
res += st.source;
|
|
8516
8516
|
if (key)
|
|
8517
8517
|
res += stringifyToken(key);
|
|
8518
|
-
if (
|
|
8519
|
-
for (const st of
|
|
8518
|
+
if (sep2)
|
|
8519
|
+
for (const st of sep2)
|
|
8520
8520
|
res += st.source;
|
|
8521
8521
|
if (value)
|
|
8522
8522
|
res += stringifyToken(value);
|
|
@@ -9659,18 +9659,18 @@ var require_parser = __commonJS({
|
|
|
9659
9659
|
if (this.type === "map-value-ind") {
|
|
9660
9660
|
const prev = getPrevProps(this.peek(2));
|
|
9661
9661
|
const start = getFirstKeyStartProps(prev);
|
|
9662
|
-
let
|
|
9662
|
+
let sep2;
|
|
9663
9663
|
if (scalar.end) {
|
|
9664
|
-
|
|
9665
|
-
|
|
9664
|
+
sep2 = scalar.end;
|
|
9665
|
+
sep2.push(this.sourceToken);
|
|
9666
9666
|
delete scalar.end;
|
|
9667
9667
|
} else
|
|
9668
|
-
|
|
9668
|
+
sep2 = [this.sourceToken];
|
|
9669
9669
|
const map = {
|
|
9670
9670
|
type: "block-map",
|
|
9671
9671
|
offset: scalar.offset,
|
|
9672
9672
|
indent: scalar.indent,
|
|
9673
|
-
items: [{ start, key: scalar, sep }]
|
|
9673
|
+
items: [{ start, key: scalar, sep: sep2 }]
|
|
9674
9674
|
};
|
|
9675
9675
|
this.onKeyLine = true;
|
|
9676
9676
|
this.stack[this.stack.length - 1] = map;
|
|
@@ -9822,15 +9822,15 @@ var require_parser = __commonJS({
|
|
|
9822
9822
|
} else if (isFlowToken(it.key) && !includesToken(it.sep, "newline")) {
|
|
9823
9823
|
const start2 = getFirstKeyStartProps(it.start);
|
|
9824
9824
|
const key = it.key;
|
|
9825
|
-
const
|
|
9826
|
-
|
|
9825
|
+
const sep2 = it.sep;
|
|
9826
|
+
sep2.push(this.sourceToken);
|
|
9827
9827
|
delete it.key;
|
|
9828
9828
|
delete it.sep;
|
|
9829
9829
|
this.stack.push({
|
|
9830
9830
|
type: "block-map",
|
|
9831
9831
|
offset: this.offset,
|
|
9832
9832
|
indent: this.indent,
|
|
9833
|
-
items: [{ start: start2, key, sep }]
|
|
9833
|
+
items: [{ start: start2, key, sep: sep2 }]
|
|
9834
9834
|
});
|
|
9835
9835
|
} else if (start.length > 0) {
|
|
9836
9836
|
it.sep = it.sep.concat(start, this.sourceToken);
|
|
@@ -10024,13 +10024,13 @@ var require_parser = __commonJS({
|
|
|
10024
10024
|
const prev = getPrevProps(parent);
|
|
10025
10025
|
const start = getFirstKeyStartProps(prev);
|
|
10026
10026
|
fixFlowSeqItems(fc);
|
|
10027
|
-
const
|
|
10028
|
-
|
|
10027
|
+
const sep2 = fc.end.splice(1, fc.end.length);
|
|
10028
|
+
sep2.push(this.sourceToken);
|
|
10029
10029
|
const map = {
|
|
10030
10030
|
type: "block-map",
|
|
10031
10031
|
offset: fc.offset,
|
|
10032
10032
|
indent: fc.indent,
|
|
10033
|
-
items: [{ start, key: fc, sep }]
|
|
10033
|
+
items: [{ start, key: fc, sep: sep2 }]
|
|
10034
10034
|
};
|
|
10035
10035
|
this.onKeyLine = true;
|
|
10036
10036
|
this.stack[this.stack.length - 1] = map;
|
|
@@ -10502,6 +10502,7 @@ var GITHUB_APP_INSTALL_URL = `https://github.com/apps/${GITHUB_APP_SLUG}/install
|
|
|
10502
10502
|
function githubAppInstallUrl(accountId) {
|
|
10503
10503
|
return accountId != null ? `https://github.com/apps/${GITHUB_APP_SLUG}/installations/new/permissions?target_id=${accountId}` : GITHUB_APP_INSTALL_URL;
|
|
10504
10504
|
}
|
|
10505
|
+
var ADVISORY_EPISODE_FILE = `${VERITY_DIR}/.advisory-episode`;
|
|
10505
10506
|
|
|
10506
10507
|
// src/lib/output.ts
|
|
10507
10508
|
var RED = "\x1B[0;31m";
|
|
@@ -10775,7 +10776,7 @@ async function foldLegacyLocalCredential(remoteArg) {
|
|
|
10775
10776
|
const existing = await readGlobalCredential(remote);
|
|
10776
10777
|
const merged = {
|
|
10777
10778
|
token: existing?.token ?? local.token,
|
|
10778
|
-
serviceUrl: existing?.serviceUrl
|
|
10779
|
+
serviceUrl: existing?.serviceUrl,
|
|
10779
10780
|
userId: existing?.userId ?? local.userId,
|
|
10780
10781
|
email: existing?.email ?? local.email
|
|
10781
10782
|
};
|
|
@@ -10803,6 +10804,13 @@ function execGit(cmd) {
|
|
|
10803
10804
|
return "";
|
|
10804
10805
|
}
|
|
10805
10806
|
}
|
|
10807
|
+
function execGitArgs(args) {
|
|
10808
|
+
try {
|
|
10809
|
+
return (0, import_node_child_process3.execFileSync)("git", args, { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
|
|
10810
|
+
} catch {
|
|
10811
|
+
return "";
|
|
10812
|
+
}
|
|
10813
|
+
}
|
|
10806
10814
|
function splitLines(s) {
|
|
10807
10815
|
return s.split("\n").filter((l) => l.length > 0);
|
|
10808
10816
|
}
|
|
@@ -10893,17 +10901,17 @@ function showContentAtRef(ref, repoRelPath) {
|
|
|
10893
10901
|
}
|
|
10894
10902
|
}
|
|
10895
10903
|
function getPushRangeFiles() {
|
|
10896
|
-
const diff = (range) => splitLines(
|
|
10904
|
+
const diff = (range) => splitLines(execGitArgs(["diff", "--name-only", range])).filter((f) => !f.startsWith(".verity/") && !f.startsWith(".verity\\"));
|
|
10897
10905
|
const resolvers = [
|
|
10898
|
-
() =>
|
|
10899
|
-
() =>
|
|
10906
|
+
() => execGitArgs(["rev-parse", "--abbrev-ref", "--symbolic-full-name", "@{push}"]) ? "@{push}..HEAD" : null,
|
|
10907
|
+
() => execGitArgs(["rev-parse", "--abbrev-ref", "--symbolic-full-name", "@{upstream}"]) ? "@{upstream}..HEAD" : null,
|
|
10900
10908
|
() => {
|
|
10901
|
-
const branch =
|
|
10902
|
-
return branch && branch !== "HEAD" &&
|
|
10909
|
+
const branch = execGitArgs(["rev-parse", "--abbrev-ref", "HEAD"]);
|
|
10910
|
+
return branch && branch !== "HEAD" && execGitArgs(["rev-parse", "--verify", "-q", `origin/${branch}`]) ? `origin/${branch}..HEAD` : null;
|
|
10903
10911
|
}
|
|
10904
10912
|
];
|
|
10905
|
-
for (const
|
|
10906
|
-
const range =
|
|
10913
|
+
for (const resolve4 of resolvers) {
|
|
10914
|
+
const range = resolve4();
|
|
10907
10915
|
if (range) return { files: diff(range), range };
|
|
10908
10916
|
}
|
|
10909
10917
|
const baseline = readBaselineSha();
|
|
@@ -10917,7 +10925,7 @@ function getPushRangeFiles() {
|
|
|
10917
10925
|
function getPushRangeMessages() {
|
|
10918
10926
|
const { range } = getPushRangeFiles();
|
|
10919
10927
|
if (!range) return "";
|
|
10920
|
-
return
|
|
10928
|
+
return execGitArgs(["log", range, "--format=%B%x00"]).split("\0").map((s) => s.trim()).filter(Boolean).join("\n\n");
|
|
10921
10929
|
}
|
|
10922
10930
|
function filterAnalyzable(files) {
|
|
10923
10931
|
return files.filter((f) => {
|
|
@@ -10951,7 +10959,7 @@ function getCurrentBranch() {
|
|
|
10951
10959
|
function commitResolves(sha) {
|
|
10952
10960
|
if (!sha) return false;
|
|
10953
10961
|
try {
|
|
10954
|
-
(0, import_node_child_process3.
|
|
10962
|
+
(0, import_node_child_process3.execFileSync)("git", ["merge-base", "--is-ancestor", sha, "HEAD"], {
|
|
10955
10963
|
stdio: ["pipe", "pipe", "pipe"]
|
|
10956
10964
|
});
|
|
10957
10965
|
return true;
|
|
@@ -10962,8 +10970,9 @@ function commitResolves(sha) {
|
|
|
10962
10970
|
function commitsSincePaths(sha, paths) {
|
|
10963
10971
|
if (!sha) return null;
|
|
10964
10972
|
try {
|
|
10965
|
-
const
|
|
10966
|
-
|
|
10973
|
+
const args = ["rev-list", "--count", `${sha}..HEAD`];
|
|
10974
|
+
if (paths.length > 0) args.push("--", ...paths.slice(0, 50));
|
|
10975
|
+
const out = (0, import_node_child_process3.execFileSync)("git", args, {
|
|
10967
10976
|
encoding: "utf-8",
|
|
10968
10977
|
stdio: ["pipe", "pipe", "pipe"]
|
|
10969
10978
|
}).trim();
|
|
@@ -11245,7 +11254,8 @@ async function serviceUrlFromVerityMd() {
|
|
|
11245
11254
|
}
|
|
11246
11255
|
return null;
|
|
11247
11256
|
}
|
|
11248
|
-
async function resolveServiceUrlDetailed(flagUrl) {
|
|
11257
|
+
async function resolveServiceUrlDetailed(flagUrl, opts = {}) {
|
|
11258
|
+
const allowVerityMd = opts.allowVerityMd ?? true;
|
|
11249
11259
|
if (flagUrl) {
|
|
11250
11260
|
return { ok: true, data: { url: flagUrl, source: "flag" } };
|
|
11251
11261
|
}
|
|
@@ -11257,9 +11267,11 @@ async function resolveServiceUrlDetailed(flagUrl) {
|
|
|
11257
11267
|
if (credsUrl) {
|
|
11258
11268
|
return { ok: true, data: { url: credsUrl, source: "credentials" } };
|
|
11259
11269
|
}
|
|
11260
|
-
|
|
11261
|
-
|
|
11262
|
-
|
|
11270
|
+
if (allowVerityMd) {
|
|
11271
|
+
const mdUrl = await serviceUrlFromVerityMd();
|
|
11272
|
+
if (mdUrl) {
|
|
11273
|
+
return { ok: true, data: { url: mdUrl, source: "verity_md" } };
|
|
11274
|
+
}
|
|
11263
11275
|
}
|
|
11264
11276
|
return {
|
|
11265
11277
|
ok: false,
|
|
@@ -11267,7 +11279,7 @@ async function resolveServiceUrlDetailed(flagUrl) {
|
|
|
11267
11279
|
};
|
|
11268
11280
|
}
|
|
11269
11281
|
async function resolveServiceUrlForAuth(flagUrl) {
|
|
11270
|
-
const strict = await resolveServiceUrlDetailed(flagUrl);
|
|
11282
|
+
const strict = await resolveServiceUrlDetailed(flagUrl, { allowVerityMd: false });
|
|
11271
11283
|
if (strict.ok) return strict.data;
|
|
11272
11284
|
return { url: DEFAULT_SERVICE_URL, source: "default" };
|
|
11273
11285
|
}
|
|
@@ -11405,7 +11417,7 @@ var readline = __toESM(require("node:readline/promises"));
|
|
|
11405
11417
|
var import_node_os = require("node:os");
|
|
11406
11418
|
|
|
11407
11419
|
// src/lib/provider-auth.ts
|
|
11408
|
-
var sleep = (ms) => new Promise((
|
|
11420
|
+
var sleep = (ms) => new Promise((resolve4) => setTimeout(resolve4, ms));
|
|
11409
11421
|
var form = (fields) => new URLSearchParams(fields).toString();
|
|
11410
11422
|
async function githubAccountId(owner) {
|
|
11411
11423
|
try {
|
|
@@ -13161,9 +13173,38 @@ async function retrieveForInjection(promptText, taskFiles = [], budgetTokens = D
|
|
|
13161
13173
|
|
|
13162
13174
|
// src/lib/memory-sync.ts
|
|
13163
13175
|
var import_promises8 = require("node:fs/promises");
|
|
13176
|
+
var import_node_fs9 = require("node:fs");
|
|
13177
|
+
var import_node_path10 = require("node:path");
|
|
13178
|
+
var import_node_crypto3 = require("node:crypto");
|
|
13179
|
+
|
|
13180
|
+
// src/lib/safe-path.ts
|
|
13164
13181
|
var import_node_fs8 = require("node:fs");
|
|
13165
13182
|
var import_node_path9 = require("node:path");
|
|
13166
|
-
|
|
13183
|
+
function resolveInside(baseDir, candidate) {
|
|
13184
|
+
if (typeof candidate !== "string" || candidate.length === 0) return null;
|
|
13185
|
+
if ((0, import_node_path9.isAbsolute)(candidate)) return null;
|
|
13186
|
+
const baseAbs = (0, import_node_path9.resolve)(baseDir);
|
|
13187
|
+
const full = (0, import_node_path9.resolve)(baseAbs, candidate);
|
|
13188
|
+
const baseSep = baseAbs.endsWith(import_node_path9.sep) ? baseAbs : baseAbs + import_node_path9.sep;
|
|
13189
|
+
if (full !== baseAbs && !full.startsWith(baseSep)) return null;
|
|
13190
|
+
try {
|
|
13191
|
+
if ((0, import_node_fs8.existsSync)(baseAbs)) {
|
|
13192
|
+
const realBase = (0, import_node_fs8.realpathSync)(baseAbs);
|
|
13193
|
+
const realBaseSep = realBase.endsWith(import_node_path9.sep) ? realBase : realBase + import_node_path9.sep;
|
|
13194
|
+
let probe = full;
|
|
13195
|
+
while (!(0, import_node_fs8.existsSync)(probe)) {
|
|
13196
|
+
const parent = (0, import_node_path9.dirname)(probe);
|
|
13197
|
+
if (parent === probe) break;
|
|
13198
|
+
probe = parent;
|
|
13199
|
+
}
|
|
13200
|
+
const realProbe = (0, import_node_fs8.realpathSync)(probe);
|
|
13201
|
+
if (realProbe !== realBase && !realProbe.startsWith(realBaseSep)) return null;
|
|
13202
|
+
}
|
|
13203
|
+
} catch {
|
|
13204
|
+
return null;
|
|
13205
|
+
}
|
|
13206
|
+
return full;
|
|
13207
|
+
}
|
|
13167
13208
|
|
|
13168
13209
|
// src/lib/glob-match.ts
|
|
13169
13210
|
function globToRegex(glob) {
|
|
@@ -13233,32 +13274,32 @@ var syncStateFile = () => projectPath(`${VERITY_DIR}/.memory-sync-state.json`);
|
|
|
13233
13274
|
async function ensureMemoryDir() {
|
|
13234
13275
|
await (0, import_promises8.mkdir)(memoryDir2(), { recursive: true });
|
|
13235
13276
|
for (const domain of DOMAINS2) {
|
|
13236
|
-
await (0, import_promises8.mkdir)((0,
|
|
13277
|
+
await (0, import_promises8.mkdir)((0, import_node_path10.join)(memoryDir2(), domain), { recursive: true });
|
|
13237
13278
|
}
|
|
13238
|
-
if (!(0,
|
|
13239
|
-
await (0, import_promises8.writeFile)((0,
|
|
13279
|
+
if (!(0, import_node_fs9.existsSync)((0, import_node_path10.join)(memoryDir2(), "SCHEMA.md"))) {
|
|
13280
|
+
await (0, import_promises8.writeFile)((0, import_node_path10.join)(memoryDir2(), "SCHEMA.md"), SCHEMA_TEMPLATE);
|
|
13240
13281
|
}
|
|
13241
|
-
if (!(0,
|
|
13242
|
-
await (0, import_promises8.writeFile)((0,
|
|
13282
|
+
if (!(0, import_node_fs9.existsSync)((0, import_node_path10.join)(memoryDir2(), "index.md"))) {
|
|
13283
|
+
await (0, import_promises8.writeFile)((0, import_node_path10.join)(memoryDir2(), "index.md"), "# Project Memory Index\n\nNo nodes yet. Run an analysis to start building the knowledge graph.\n");
|
|
13243
13284
|
}
|
|
13244
|
-
if (!(0,
|
|
13245
|
-
await (0, import_promises8.writeFile)((0,
|
|
13285
|
+
if (!(0, import_node_fs9.existsSync)((0, import_node_path10.join)(memoryDir2(), "log.md"))) {
|
|
13286
|
+
await (0, import_promises8.writeFile)((0, import_node_path10.join)(memoryDir2(), "log.md"), "# Memory Log\n\n");
|
|
13246
13287
|
}
|
|
13247
13288
|
}
|
|
13248
13289
|
async function buildManifest() {
|
|
13249
|
-
if (!(0,
|
|
13290
|
+
if (!(0, import_node_fs9.existsSync)(memoryDir2())) {
|
|
13250
13291
|
return { schema_version: 1, nodes: [], index_hash: null, log_length: 0 };
|
|
13251
13292
|
}
|
|
13252
13293
|
const nodes = [];
|
|
13253
13294
|
for (const domain of DOMAINS2) {
|
|
13254
|
-
const domainDir = (0,
|
|
13255
|
-
if (!(0,
|
|
13295
|
+
const domainDir = (0, import_node_path10.join)(memoryDir2(), domain);
|
|
13296
|
+
if (!(0, import_node_fs9.existsSync)(domainDir)) continue;
|
|
13256
13297
|
try {
|
|
13257
13298
|
const files = await (0, import_promises8.readdir)(domainDir);
|
|
13258
13299
|
for (const file of files) {
|
|
13259
13300
|
if (!file.endsWith(".md")) continue;
|
|
13260
13301
|
const filePath = `${domain}/${file}`;
|
|
13261
|
-
const fullPath = (0,
|
|
13302
|
+
const fullPath = (0, import_node_path10.join)(memoryDir2(), filePath);
|
|
13262
13303
|
try {
|
|
13263
13304
|
const content = await (0, import_promises8.readFile)(fullPath, "utf-8");
|
|
13264
13305
|
const hash = (0, import_node_crypto3.createHash)("sha256").update(content).digest("hex").slice(0, 16);
|
|
@@ -13271,13 +13312,13 @@ async function buildManifest() {
|
|
|
13271
13312
|
}
|
|
13272
13313
|
let indexHash = null;
|
|
13273
13314
|
try {
|
|
13274
|
-
const indexContent = await (0, import_promises8.readFile)((0,
|
|
13315
|
+
const indexContent = await (0, import_promises8.readFile)((0, import_node_path10.join)(memoryDir2(), "index.md"), "utf-8");
|
|
13275
13316
|
indexHash = `sha256:${(0, import_node_crypto3.createHash)("sha256").update(indexContent).digest("hex").slice(0, 16)}`;
|
|
13276
13317
|
} catch {
|
|
13277
13318
|
}
|
|
13278
13319
|
let logLength = 0;
|
|
13279
13320
|
try {
|
|
13280
|
-
const logContent = await (0, import_promises8.readFile)((0,
|
|
13321
|
+
const logContent = await (0, import_promises8.readFile)((0, import_node_path10.join)(memoryDir2(), "log.md"), "utf-8");
|
|
13281
13322
|
logLength = logContent.split("\n").length;
|
|
13282
13323
|
} catch {
|
|
13283
13324
|
}
|
|
@@ -13288,15 +13329,15 @@ function hashContent(content) {
|
|
|
13288
13329
|
}
|
|
13289
13330
|
async function readOnDiskNodes() {
|
|
13290
13331
|
const out = /* @__PURE__ */ new Map();
|
|
13291
|
-
if (!(0,
|
|
13332
|
+
if (!(0, import_node_fs9.existsSync)(memoryDir2())) return out;
|
|
13292
13333
|
for (const domain of DOMAINS2) {
|
|
13293
|
-
const domainDir = (0,
|
|
13294
|
-
if (!(0,
|
|
13334
|
+
const domainDir = (0, import_node_path10.join)(memoryDir2(), domain);
|
|
13335
|
+
if (!(0, import_node_fs9.existsSync)(domainDir)) continue;
|
|
13295
13336
|
try {
|
|
13296
13337
|
for (const file of await (0, import_promises8.readdir)(domainDir)) {
|
|
13297
13338
|
if (!file.endsWith(".md")) continue;
|
|
13298
13339
|
try {
|
|
13299
|
-
out.set(`${domain}/${file}`, hashContent(await (0, import_promises8.readFile)((0,
|
|
13340
|
+
out.set(`${domain}/${file}`, hashContent(await (0, import_promises8.readFile)((0, import_node_path10.join)(domainDir, file), "utf-8")));
|
|
13300
13341
|
} catch {
|
|
13301
13342
|
}
|
|
13302
13343
|
}
|
|
@@ -13342,8 +13383,8 @@ async function computeEditedNodeUploads() {
|
|
|
13342
13383
|
const uploads = [];
|
|
13343
13384
|
for (const [path, prevHash] of prev) {
|
|
13344
13385
|
if (prevHash == null) continue;
|
|
13345
|
-
const full = (0,
|
|
13346
|
-
if (!(0,
|
|
13386
|
+
const full = (0, import_node_path10.join)(memoryDir2(), path);
|
|
13387
|
+
if (!(0, import_node_fs9.existsSync)(full)) continue;
|
|
13347
13388
|
let content;
|
|
13348
13389
|
try {
|
|
13349
13390
|
content = await (0, import_promises8.readFile)(full, "utf-8");
|
|
@@ -13379,16 +13420,19 @@ async function applyMemoryWrites(writes, opts = {}) {
|
|
|
13379
13420
|
const logLines = [`- ${(/* @__PURE__ */ new Date()).toISOString().slice(0, 16)} \u2014 Applied ${count} write(s) from server`];
|
|
13380
13421
|
for (const n of notes) logLines.push(` - ${n}`);
|
|
13381
13422
|
try {
|
|
13382
|
-
const existing = (0,
|
|
13383
|
-
await (0, import_promises8.writeFile)((0,
|
|
13423
|
+
const existing = (0, import_node_fs9.existsSync)((0, import_node_path10.join)(memoryDir2(), "log.md")) ? await (0, import_promises8.readFile)((0, import_node_path10.join)(memoryDir2(), "log.md"), "utf-8") : "# Memory Log\n\n";
|
|
13424
|
+
await (0, import_promises8.writeFile)((0, import_node_path10.join)(memoryDir2(), "log.md"), existing + logLines.join("\n") + "\n");
|
|
13384
13425
|
} catch {
|
|
13385
13426
|
}
|
|
13386
13427
|
await recordSyncedNodePaths();
|
|
13387
13428
|
return count;
|
|
13388
13429
|
}
|
|
13389
13430
|
async function applyOneWrite(write, treePaths) {
|
|
13390
|
-
const fullPath = (
|
|
13431
|
+
const fullPath = resolveInside(memoryDir2(), write.path);
|
|
13391
13432
|
const notes = [];
|
|
13433
|
+
if (!fullPath) {
|
|
13434
|
+
return { written: false, notes: [`${String(write.path)}: rejected \u2014 path escapes the memory directory`] };
|
|
13435
|
+
}
|
|
13392
13436
|
let content = write.content;
|
|
13393
13437
|
if (treePaths && treePaths.length > 0) {
|
|
13394
13438
|
const grounded = groundFileGlobs(content, treePaths);
|
|
@@ -13397,7 +13441,7 @@ async function applyOneWrite(write, treePaths) {
|
|
|
13397
13441
|
notes.push(`${write.path}: dropped unmatched file_globs [${grounded.dropped.join(", ")}]`);
|
|
13398
13442
|
}
|
|
13399
13443
|
}
|
|
13400
|
-
if ((0,
|
|
13444
|
+
if ((0, import_node_fs9.existsSync)(fullPath)) {
|
|
13401
13445
|
let existing = "";
|
|
13402
13446
|
try {
|
|
13403
13447
|
existing = await (0, import_promises8.readFile)(fullPath, "utf-8");
|
|
@@ -13409,7 +13453,7 @@ async function applyOneWrite(write, treePaths) {
|
|
|
13409
13453
|
return { written: false, notes };
|
|
13410
13454
|
}
|
|
13411
13455
|
}
|
|
13412
|
-
await (0, import_promises8.mkdir)((0,
|
|
13456
|
+
await (0, import_promises8.mkdir)((0, import_node_path10.dirname)(fullPath), { recursive: true });
|
|
13413
13457
|
await (0, import_promises8.writeFile)(fullPath, content);
|
|
13414
13458
|
return { written: true, notes };
|
|
13415
13459
|
}
|
|
@@ -13450,8 +13494,8 @@ async function regenerateIndex() {
|
|
|
13450
13494
|
];
|
|
13451
13495
|
let totalNodes = 0;
|
|
13452
13496
|
for (const domain of DOMAINS2.filter((d) => d !== "_archive")) {
|
|
13453
|
-
const domainDir = (0,
|
|
13454
|
-
if (!(0,
|
|
13497
|
+
const domainDir = (0, import_node_path10.join)(memoryDir2(), domain);
|
|
13498
|
+
if (!(0, import_node_fs9.existsSync)(domainDir)) continue;
|
|
13455
13499
|
try {
|
|
13456
13500
|
const files = await (0, import_promises8.readdir)(domainDir);
|
|
13457
13501
|
const mdFiles = files.filter((f) => f.endsWith(".md"));
|
|
@@ -13461,7 +13505,7 @@ async function regenerateIndex() {
|
|
|
13461
13505
|
for (const file of mdFiles.sort()) {
|
|
13462
13506
|
const slug = file.replace(/\.md$/, "");
|
|
13463
13507
|
try {
|
|
13464
|
-
const content = await (0, import_promises8.readFile)((0,
|
|
13508
|
+
const content = await (0, import_promises8.readFile)((0, import_node_path10.join)(domainDir, file), "utf-8");
|
|
13465
13509
|
const title = pickFrontmatter(content, "title") ?? slug;
|
|
13466
13510
|
const kind = pickFrontmatter(content, "kind") ?? "-";
|
|
13467
13511
|
const confidence = pickFrontmatter(content, "confidence");
|
|
@@ -13485,7 +13529,7 @@ async function regenerateIndex() {
|
|
|
13485
13529
|
lines.push("No nodes yet. Run an analysis to start building the knowledge graph.");
|
|
13486
13530
|
}
|
|
13487
13531
|
const next = lines.join("\n") + "\n";
|
|
13488
|
-
const indexPath = (0,
|
|
13532
|
+
const indexPath = (0, import_node_path10.join)(memoryDir2(), "index.md");
|
|
13489
13533
|
let existing = null;
|
|
13490
13534
|
try {
|
|
13491
13535
|
existing = await (0, import_promises8.readFile)(indexPath, "utf-8");
|
|
@@ -13567,9 +13611,9 @@ function hasLegacyMemoryBlock(text) {
|
|
|
13567
13611
|
return findMarker(text, LEGACY_MD_START) !== -1;
|
|
13568
13612
|
}
|
|
13569
13613
|
async function ensureClaudeMdPointer(cwd = repoRoot()) {
|
|
13570
|
-
const claudeMdPath = (0,
|
|
13614
|
+
const claudeMdPath = (0, import_node_path10.join)(cwd, "CLAUDE.md");
|
|
13571
13615
|
let existing = "";
|
|
13572
|
-
if ((0,
|
|
13616
|
+
if ((0, import_node_fs9.existsSync)(claudeMdPath)) {
|
|
13573
13617
|
existing = await (0, import_promises8.readFile)(claudeMdPath, "utf-8");
|
|
13574
13618
|
}
|
|
13575
13619
|
let startTag = CLAUDE_MD_START;
|
|
@@ -13699,9 +13743,9 @@ Body content (\u22648KB). Use [[node-id]] wikilinks for cross-references.
|
|
|
13699
13743
|
`;
|
|
13700
13744
|
|
|
13701
13745
|
// src/lib/dossier-session.ts
|
|
13702
|
-
var
|
|
13746
|
+
var import_node_fs14 = require("node:fs");
|
|
13703
13747
|
var import_node_crypto7 = require("node:crypto");
|
|
13704
|
-
var
|
|
13748
|
+
var import_node_path13 = require("node:path");
|
|
13705
13749
|
|
|
13706
13750
|
// src/lib/skip-detection.ts
|
|
13707
13751
|
function isBareAckPrompt(prompt) {
|
|
@@ -13865,8 +13909,8 @@ var DEFAULT_MEMORY_BUDGET_BYTES = 4096;
|
|
|
13865
13909
|
|
|
13866
13910
|
// src/lib/dossier/log.ts
|
|
13867
13911
|
var import_node_crypto4 = require("node:crypto");
|
|
13868
|
-
var
|
|
13869
|
-
var
|
|
13912
|
+
var import_node_fs10 = require("node:fs");
|
|
13913
|
+
var import_node_path11 = require("node:path");
|
|
13870
13914
|
var CRC_TABLE = (() => {
|
|
13871
13915
|
const t = new Int32Array(256);
|
|
13872
13916
|
for (let i = 0; i < 256; i++) {
|
|
@@ -13885,13 +13929,13 @@ function crc32(s) {
|
|
|
13885
13929
|
function openDossier(identity) {
|
|
13886
13930
|
try {
|
|
13887
13931
|
const dir = dossierDir(identity);
|
|
13888
|
-
(0,
|
|
13932
|
+
(0, import_node_fs10.mkdirSync)(dir, { recursive: true, mode: 448 });
|
|
13889
13933
|
return {
|
|
13890
13934
|
dir,
|
|
13891
13935
|
identity,
|
|
13892
|
-
eventsPath: (0,
|
|
13893
|
-
foldPath: (0,
|
|
13894
|
-
rotatedDir: (0,
|
|
13936
|
+
eventsPath: (0, import_node_path11.join)(dir, "events.jsonl"),
|
|
13937
|
+
foldPath: (0, import_node_path11.join)(dir, "fold.json"),
|
|
13938
|
+
rotatedDir: (0, import_node_path11.join)(dir, "rotated")
|
|
13895
13939
|
};
|
|
13896
13940
|
} catch {
|
|
13897
13941
|
return null;
|
|
@@ -13953,7 +13997,7 @@ function appendEvent(d, ev) {
|
|
|
13953
13997
|
at: ev.at ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
13954
13998
|
...ev
|
|
13955
13999
|
});
|
|
13956
|
-
(0,
|
|
14000
|
+
(0, import_node_fs10.appendFileSync)(d.eventsPath, line, { mode: 384 });
|
|
13957
14001
|
return true;
|
|
13958
14002
|
} catch {
|
|
13959
14003
|
return false;
|
|
@@ -13961,14 +14005,14 @@ function appendEvent(d, ev) {
|
|
|
13961
14005
|
}
|
|
13962
14006
|
function rotateIfNeeded2(d) {
|
|
13963
14007
|
try {
|
|
13964
|
-
if (!(0,
|
|
13965
|
-
if ((0,
|
|
13966
|
-
(0,
|
|
13967
|
-
(0,
|
|
13968
|
-
const kept = (0,
|
|
14008
|
+
if (!(0, import_node_fs10.existsSync)(d.eventsPath)) return;
|
|
14009
|
+
if ((0, import_node_fs10.statSync)(d.eventsPath).size < ROTATE_BYTES) return;
|
|
14010
|
+
(0, import_node_fs10.mkdirSync)(d.rotatedDir, { recursive: true, mode: 448 });
|
|
14011
|
+
(0, import_node_fs10.renameSync)(d.eventsPath, (0, import_node_path11.join)(d.rotatedDir, `events.${Date.now()}.jsonl`));
|
|
14012
|
+
const kept = (0, import_node_fs10.readdirSync)(d.rotatedDir).filter((f) => f.endsWith(".jsonl")).sort();
|
|
13969
14013
|
for (const stale of kept.slice(0, Math.max(0, kept.length - ROTATE_KEEP))) {
|
|
13970
14014
|
try {
|
|
13971
|
-
(0,
|
|
14015
|
+
(0, import_node_fs10.renameSync)((0, import_node_path11.join)(d.rotatedDir, stale), (0, import_node_path11.join)(d.rotatedDir, `${stale}.pruned`));
|
|
13972
14016
|
} catch {
|
|
13973
14017
|
}
|
|
13974
14018
|
}
|
|
@@ -13978,8 +14022,8 @@ function rotateIfNeeded2(d) {
|
|
|
13978
14022
|
|
|
13979
14023
|
// src/lib/dossier/fold-dossier.ts
|
|
13980
14024
|
var import_node_crypto5 = require("node:crypto");
|
|
13981
|
-
var
|
|
13982
|
-
var
|
|
14025
|
+
var import_node_fs11 = require("node:fs");
|
|
14026
|
+
var import_node_path12 = require("node:path");
|
|
13983
14027
|
var EMPTY_CAPABILITIES = () => ({
|
|
13984
14028
|
human_reachable: { value: "unknown", tier: "unknown" },
|
|
13985
14029
|
authorship_observability: { value: "unknown", tier: "unknown" },
|
|
@@ -14030,12 +14074,12 @@ function foldDossier(d, opts = {}) {
|
|
|
14030
14074
|
}
|
|
14031
14075
|
};
|
|
14032
14076
|
try {
|
|
14033
|
-
if ((0,
|
|
14034
|
-
const files = (0,
|
|
14077
|
+
if ((0, import_node_fs11.existsSync)(d.rotatedDir)) {
|
|
14078
|
+
const files = (0, import_node_fs11.readdirSync)(d.rotatedDir).filter((f) => f.endsWith(".jsonl")).sort();
|
|
14035
14079
|
state.meta.rotations = files.length;
|
|
14036
14080
|
for (const f of files) {
|
|
14037
14081
|
try {
|
|
14038
|
-
ingest((0,
|
|
14082
|
+
ingest((0, import_node_fs11.readFileSync)((0, import_node_path12.join)(d.rotatedDir, f), "utf8"));
|
|
14039
14083
|
} catch {
|
|
14040
14084
|
state.meta.dropped_lines++;
|
|
14041
14085
|
}
|
|
@@ -14044,9 +14088,9 @@ function foldDossier(d, opts = {}) {
|
|
|
14044
14088
|
} catch {
|
|
14045
14089
|
}
|
|
14046
14090
|
try {
|
|
14047
|
-
if ((0,
|
|
14048
|
-
state.meta.upto_offset = (0,
|
|
14049
|
-
ingest((0,
|
|
14091
|
+
if ((0, import_node_fs11.existsSync)(d.eventsPath)) {
|
|
14092
|
+
state.meta.upto_offset = (0, import_node_fs11.statSync)(d.eventsPath).size;
|
|
14093
|
+
ingest((0, import_node_fs11.readFileSync)(d.eventsPath, "utf8"));
|
|
14050
14094
|
}
|
|
14051
14095
|
} catch {
|
|
14052
14096
|
}
|
|
@@ -14316,7 +14360,7 @@ function applyBounds(state, input) {
|
|
|
14316
14360
|
}
|
|
14317
14361
|
|
|
14318
14362
|
// src/lib/dossier/cache.ts
|
|
14319
|
-
var
|
|
14363
|
+
var import_node_fs12 = require("node:fs");
|
|
14320
14364
|
function compactState(s) {
|
|
14321
14365
|
const ms = (iso) => Date.parse(iso) || 0;
|
|
14322
14366
|
return {
|
|
@@ -14445,20 +14489,20 @@ function encodeState(s) {
|
|
|
14445
14489
|
function writeFoldCache(d, state) {
|
|
14446
14490
|
try {
|
|
14447
14491
|
const tmp = `${d.foldPath}.${process.pid}.tmp`;
|
|
14448
|
-
(0,
|
|
14449
|
-
(0,
|
|
14492
|
+
(0, import_node_fs12.writeFileSync)(tmp, encodeState(state), { mode: 384 });
|
|
14493
|
+
(0, import_node_fs12.renameSync)(tmp, d.foldPath);
|
|
14450
14494
|
} catch {
|
|
14451
14495
|
}
|
|
14452
14496
|
}
|
|
14453
14497
|
function readFoldCache(d) {
|
|
14454
14498
|
try {
|
|
14455
|
-
if (!(0,
|
|
14456
|
-
const raw = JSON.parse((0,
|
|
14499
|
+
if (!(0, import_node_fs12.existsSync)(d.foldPath)) return null;
|
|
14500
|
+
const raw = JSON.parse((0, import_node_fs12.readFileSync)(d.foldPath, "utf8"));
|
|
14457
14501
|
if (raw?.v !== 1) return null;
|
|
14458
14502
|
const cached2 = expandState(raw);
|
|
14459
14503
|
if (!cached2?.meta) return null;
|
|
14460
|
-
const size = (0,
|
|
14461
|
-
const rotations = (0,
|
|
14504
|
+
const size = (0, import_node_fs12.existsSync)(d.eventsPath) ? (0, import_node_fs12.statSync)(d.eventsPath).size : 0;
|
|
14505
|
+
const rotations = (0, import_node_fs12.existsSync)(d.rotatedDir) ? (0, import_node_fs12.readdirSync)(d.rotatedDir).filter((f) => f.endsWith(".jsonl")).length : 0;
|
|
14462
14506
|
if (cached2.meta.upto_offset !== size || cached2.meta.rotations !== rotations) return null;
|
|
14463
14507
|
return cached2;
|
|
14464
14508
|
} catch {
|
|
@@ -14509,13 +14553,13 @@ function assessContinuity(i) {
|
|
|
14509
14553
|
|
|
14510
14554
|
// src/lib/dossier/reanchor.ts
|
|
14511
14555
|
var import_node_crypto6 = require("node:crypto");
|
|
14512
|
-
var
|
|
14556
|
+
var import_node_fs13 = require("node:fs");
|
|
14513
14557
|
function lineSha(text) {
|
|
14514
14558
|
return (0, import_node_crypto6.createHash)("sha256").update(text.trim()).digest("hex").slice(0, HASH_WIDTH);
|
|
14515
14559
|
}
|
|
14516
14560
|
function fileHash(path) {
|
|
14517
14561
|
try {
|
|
14518
|
-
return (0, import_node_crypto6.createHash)("sha256").update((0,
|
|
14562
|
+
return (0, import_node_crypto6.createHash)("sha256").update((0, import_node_fs13.readFileSync)(path)).digest("hex").slice(0, HASH_WIDTH);
|
|
14519
14563
|
} catch {
|
|
14520
14564
|
return null;
|
|
14521
14565
|
}
|
|
@@ -14887,20 +14931,20 @@ function foreignAuthoredPaths(identity, opts = {}) {
|
|
|
14887
14931
|
let sessions = 0;
|
|
14888
14932
|
try {
|
|
14889
14933
|
const dir = treeDir(identity);
|
|
14890
|
-
if (!(0,
|
|
14891
|
-
for (const entry of (0,
|
|
14934
|
+
if (!(0, import_node_fs14.existsSync)(dir)) return { paths: [], sessions: 0 };
|
|
14935
|
+
for (const entry of (0, import_node_fs14.readdirSync)(dir, { withFileTypes: true })) {
|
|
14892
14936
|
if (!entry.isDirectory()) continue;
|
|
14893
14937
|
if (entry.name === identity.sessionKey) continue;
|
|
14894
|
-
const log = (0,
|
|
14938
|
+
const log = (0, import_node_path13.join)(dir, entry.name, "events.jsonl");
|
|
14895
14939
|
try {
|
|
14896
|
-
if (!(0,
|
|
14897
|
-
if (now - (0,
|
|
14940
|
+
if (!(0, import_node_fs14.existsSync)(log)) continue;
|
|
14941
|
+
if (now - (0, import_node_fs14.statSync)(log).mtimeMs > windowMs) continue;
|
|
14898
14942
|
const sib = {
|
|
14899
|
-
dir: (0,
|
|
14943
|
+
dir: (0, import_node_path13.join)(dir, entry.name),
|
|
14900
14944
|
identity,
|
|
14901
14945
|
eventsPath: log,
|
|
14902
|
-
foldPath: (0,
|
|
14903
|
-
rotatedDir: (0,
|
|
14946
|
+
foldPath: (0, import_node_path13.join)(dir, entry.name, "fold.json"),
|
|
14947
|
+
rotatedDir: (0, import_node_path13.join)(dir, entry.name, "rotated")
|
|
14904
14948
|
};
|
|
14905
14949
|
const state = readFoldCache(sib) ?? foldDossier(sib);
|
|
14906
14950
|
sessions++;
|
|
@@ -14928,25 +14972,25 @@ function pruneOldDossiers(identity, maxAgeMs = 7 * 24 * 60 * 60 * 1e3) {
|
|
|
14928
14972
|
let removed = 0;
|
|
14929
14973
|
try {
|
|
14930
14974
|
const mine = dossierDir(identity);
|
|
14931
|
-
const userDir = (0,
|
|
14932
|
-
if (!(0,
|
|
14975
|
+
const userDir = (0, import_node_path13.dirname)((0, import_node_path13.dirname)(mine));
|
|
14976
|
+
if (!(0, import_node_fs14.existsSync)(userDir)) return 0;
|
|
14933
14977
|
const cutoff = Date.now() - maxAgeMs;
|
|
14934
|
-
for (const tree of (0,
|
|
14978
|
+
for (const tree of (0, import_node_fs14.readdirSync)(userDir, { withFileTypes: true })) {
|
|
14935
14979
|
if (!tree.isDirectory()) continue;
|
|
14936
|
-
const treePath = (0,
|
|
14980
|
+
const treePath = (0, import_node_path13.join)(userDir, tree.name);
|
|
14937
14981
|
let live = 0;
|
|
14938
|
-
for (const entry of (0,
|
|
14982
|
+
for (const entry of (0, import_node_fs14.readdirSync)(treePath, { withFileTypes: true })) {
|
|
14939
14983
|
if (!entry.isDirectory()) continue;
|
|
14940
|
-
const dir = (0,
|
|
14984
|
+
const dir = (0, import_node_path13.join)(treePath, entry.name);
|
|
14941
14985
|
if (dir === mine) {
|
|
14942
14986
|
live++;
|
|
14943
14987
|
continue;
|
|
14944
14988
|
}
|
|
14945
14989
|
try {
|
|
14946
|
-
const log = (0,
|
|
14947
|
-
const at = (0,
|
|
14990
|
+
const log = (0, import_node_path13.join)(dir, "events.jsonl");
|
|
14991
|
+
const at = (0, import_node_fs14.existsSync)(log) ? (0, import_node_fs14.statSync)(log).mtimeMs : (0, import_node_fs14.statSync)(dir).mtimeMs;
|
|
14948
14992
|
if (at < cutoff) {
|
|
14949
|
-
(0,
|
|
14993
|
+
(0, import_node_fs14.rmSync)(dir, { recursive: true, force: true });
|
|
14950
14994
|
removed++;
|
|
14951
14995
|
} else {
|
|
14952
14996
|
live++;
|
|
@@ -14956,7 +15000,7 @@ function pruneOldDossiers(identity, maxAgeMs = 7 * 24 * 60 * 60 * 1e3) {
|
|
|
14956
15000
|
}
|
|
14957
15001
|
if (live === 0) {
|
|
14958
15002
|
try {
|
|
14959
|
-
(0,
|
|
15003
|
+
(0, import_node_fs14.rmSync)(treePath, { recursive: false, force: false });
|
|
14960
15004
|
} catch {
|
|
14961
15005
|
}
|
|
14962
15006
|
}
|
|
@@ -14973,8 +15017,8 @@ function sessionDossier(token, sessionId) {
|
|
|
14973
15017
|
}
|
|
14974
15018
|
function hasActiveGoal(d) {
|
|
14975
15019
|
try {
|
|
14976
|
-
if (!(0,
|
|
14977
|
-
return (0,
|
|
15020
|
+
if (!(0, import_node_fs14.existsSync)(d.eventsPath)) return false;
|
|
15021
|
+
return (0, import_node_fs14.readFileSync)(d.eventsPath, "utf8").includes('"k":"goal"');
|
|
14978
15022
|
} catch {
|
|
14979
15023
|
return false;
|
|
14980
15024
|
}
|
|
@@ -14998,7 +15042,7 @@ function recordTurn(d, t) {
|
|
|
14998
15042
|
for (const a of t.authored) {
|
|
14999
15043
|
const origin = a.owner === "subagent" ? "subagent" : "edit_tool";
|
|
15000
15044
|
const prior = t.known?.authored?.get(a.p);
|
|
15001
|
-
const hash = fileHash((0,
|
|
15045
|
+
const hash = fileHash((0, import_node_path13.join)(root, a.p));
|
|
15002
15046
|
const hunks = Math.max(0, a.h - (prior?.hunks ?? 0));
|
|
15003
15047
|
const adds = Math.max(0, a.a - (prior?.adds ?? 0));
|
|
15004
15048
|
const dels = Math.max(0, a.d - (prior?.dels ?? 0));
|
|
@@ -15031,7 +15075,7 @@ function recordTurn(d, t) {
|
|
|
15031
15075
|
}
|
|
15032
15076
|
const seenDivergence = t.known?.divergence ?? /* @__PURE__ */ new Set();
|
|
15033
15077
|
for (const u of t.unobserved) {
|
|
15034
|
-
const hash = fileHash((0,
|
|
15078
|
+
const hash = fileHash((0, import_node_path13.join)(root, u.p));
|
|
15035
15079
|
if (seenDivergence.has(divergenceKey(u.p, hash))) continue;
|
|
15036
15080
|
appendEvent(d, { k: "divergence", kind: "external_mutation", path: u.p, hash });
|
|
15037
15081
|
}
|
|
@@ -15060,12 +15104,14 @@ function recordVerdict(d, v) {
|
|
|
15060
15104
|
if (summary) appendEvent(d, { k: "goal_delivered", summary });
|
|
15061
15105
|
}
|
|
15062
15106
|
const lines = /* @__PURE__ */ new Map();
|
|
15107
|
+
const sent = new Set(v.sentPaths);
|
|
15063
15108
|
for (const f of v.findings) {
|
|
15064
15109
|
if (!f.file || typeof f.line !== "number" || !f.pattern_id) continue;
|
|
15110
|
+
if (!sent.has(f.file)) continue;
|
|
15065
15111
|
if (!lines.has(f.file)) {
|
|
15066
15112
|
try {
|
|
15067
|
-
const abs = (0,
|
|
15068
|
-
lines.set(f.file, (0,
|
|
15113
|
+
const abs = (0, import_node_path13.join)(root, f.file);
|
|
15114
|
+
lines.set(f.file, (0, import_node_fs14.existsSync)(abs) ? (0, import_node_fs14.readFileSync)(abs, "utf8").split("\n") : null);
|
|
15069
15115
|
} catch {
|
|
15070
15116
|
lines.set(f.file, null);
|
|
15071
15117
|
}
|
|
@@ -15165,8 +15211,8 @@ function recallMemory(d, identity, opts) {
|
|
|
15165
15211
|
budgetBytes: opts.budgetBytes,
|
|
15166
15212
|
readFileLines: (file) => {
|
|
15167
15213
|
try {
|
|
15168
|
-
const abs = (0,
|
|
15169
|
-
return (0,
|
|
15214
|
+
const abs = (0, import_node_path13.join)(root, file);
|
|
15215
|
+
return (0, import_node_fs14.existsSync)(abs) ? (0, import_node_fs14.readFileSync)(abs, "utf8").split("\n") : null;
|
|
15170
15216
|
} catch {
|
|
15171
15217
|
return null;
|
|
15172
15218
|
}
|
|
@@ -15304,22 +15350,22 @@ async function fireClassify(prompt, sessionId, globals) {
|
|
|
15304
15350
|
}
|
|
15305
15351
|
|
|
15306
15352
|
// src/commands/lifecycle.ts
|
|
15307
|
-
var
|
|
15308
|
-
var
|
|
15353
|
+
var import_node_fs18 = require("node:fs");
|
|
15354
|
+
var import_node_path17 = require("node:path");
|
|
15309
15355
|
|
|
15310
15356
|
// src/lib/baseline.ts
|
|
15311
|
-
var
|
|
15312
|
-
var
|
|
15357
|
+
var import_node_fs17 = require("node:fs");
|
|
15358
|
+
var import_node_path16 = require("node:path");
|
|
15313
15359
|
var import_node_crypto9 = require("node:crypto");
|
|
15314
15360
|
|
|
15315
15361
|
// src/lib/snapshot.ts
|
|
15316
|
-
var
|
|
15317
|
-
var
|
|
15362
|
+
var import_node_fs16 = require("node:fs");
|
|
15363
|
+
var import_node_path15 = require("node:path");
|
|
15318
15364
|
var import_node_child_process6 = require("node:child_process");
|
|
15319
15365
|
|
|
15320
15366
|
// src/lib/files.ts
|
|
15321
|
-
var
|
|
15322
|
-
var
|
|
15367
|
+
var import_node_fs15 = require("node:fs");
|
|
15368
|
+
var import_node_path14 = require("node:path");
|
|
15323
15369
|
var LANG_MAP = {
|
|
15324
15370
|
// Analyzable (static analysis + Gemini)
|
|
15325
15371
|
ts: "typescript",
|
|
@@ -15387,7 +15433,7 @@ var LANG_MAP = {
|
|
|
15387
15433
|
mk: "make"
|
|
15388
15434
|
};
|
|
15389
15435
|
function detectLanguage(filepath) {
|
|
15390
|
-
const ext = (0,
|
|
15436
|
+
const ext = (0, import_node_path14.extname)(filepath).slice(1);
|
|
15391
15437
|
return LANG_MAP[ext] ?? ext;
|
|
15392
15438
|
}
|
|
15393
15439
|
function sortByMtime(files) {
|
|
@@ -15395,7 +15441,7 @@ function sortByMtime(files) {
|
|
|
15395
15441
|
const resolved = resolveFile(f);
|
|
15396
15442
|
if (!resolved) return null;
|
|
15397
15443
|
try {
|
|
15398
|
-
const stat3 = (0,
|
|
15444
|
+
const stat3 = (0, import_node_fs15.statSync)(resolved);
|
|
15399
15445
|
return { path: f, resolved, mtime: stat3.mtimeMs };
|
|
15400
15446
|
} catch {
|
|
15401
15447
|
return null;
|
|
@@ -15428,7 +15474,7 @@ function collectCodeDelta(files, opts) {
|
|
|
15428
15474
|
}
|
|
15429
15475
|
let size;
|
|
15430
15476
|
try {
|
|
15431
|
-
size = (0,
|
|
15477
|
+
size = (0, import_node_fs15.statSync)(resolved).size;
|
|
15432
15478
|
} catch {
|
|
15433
15479
|
exclude(filepath, "not-stattable");
|
|
15434
15480
|
continue;
|
|
@@ -15445,7 +15491,7 @@ function collectCodeDelta(files, opts) {
|
|
|
15445
15491
|
}
|
|
15446
15492
|
let content;
|
|
15447
15493
|
try {
|
|
15448
|
-
content = (0,
|
|
15494
|
+
content = (0, import_node_fs15.readFileSync)(resolved, "utf-8");
|
|
15449
15495
|
} catch {
|
|
15450
15496
|
exclude(filepath, "not-readable");
|
|
15451
15497
|
continue;
|
|
@@ -15484,15 +15530,16 @@ function collectCodeDelta(files, opts) {
|
|
|
15484
15530
|
|
|
15485
15531
|
// src/lib/snapshot.ts
|
|
15486
15532
|
function generateSnapshotDiffs(files) {
|
|
15487
|
-
if (!(0,
|
|
15533
|
+
if (!(0, import_node_fs16.existsSync)(SNAPSHOT_DIR)) {
|
|
15488
15534
|
return { diffs: [], has_snapshots: false };
|
|
15489
15535
|
}
|
|
15490
15536
|
const diffs = [];
|
|
15491
15537
|
for (const file of files) {
|
|
15492
|
-
|
|
15538
|
+
if (!resolveInside(SNAPSHOT_DIR, file.path)) continue;
|
|
15539
|
+
const snapshotPath = (0, import_node_path15.join)(SNAPSHOT_DIR, file.path);
|
|
15493
15540
|
const language = file.language ?? detectLanguage(file.path);
|
|
15494
|
-
if ((0,
|
|
15495
|
-
const oldContent = (0,
|
|
15541
|
+
if ((0, import_node_fs16.existsSync)(snapshotPath)) {
|
|
15542
|
+
const oldContent = (0, import_node_fs16.readFileSync)(snapshotPath, "utf-8");
|
|
15496
15543
|
if (oldContent === file.content) continue;
|
|
15497
15544
|
const diff = computeDiff(oldContent, file.content, file.path);
|
|
15498
15545
|
if (diff) {
|
|
@@ -15513,23 +15560,51 @@ ${addedLines}`,
|
|
|
15513
15560
|
}
|
|
15514
15561
|
return { diffs, has_snapshots: true };
|
|
15515
15562
|
}
|
|
15563
|
+
function ensureSnapshotGitignored() {
|
|
15564
|
+
let content = "";
|
|
15565
|
+
try {
|
|
15566
|
+
content = (0, import_node_fs16.readFileSync)(".gitignore", "utf-8");
|
|
15567
|
+
} catch {
|
|
15568
|
+
}
|
|
15569
|
+
let ignored = null;
|
|
15570
|
+
try {
|
|
15571
|
+
(0, import_node_child_process6.execSync)("git check-ignore -q -- .verity/.snapshot/__probe__", { stdio: "pipe" });
|
|
15572
|
+
ignored = true;
|
|
15573
|
+
} catch (err) {
|
|
15574
|
+
ignored = err.status === 1 ? false : null;
|
|
15575
|
+
}
|
|
15576
|
+
if (ignored === true) return "covered";
|
|
15577
|
+
if (ignored === null) {
|
|
15578
|
+
const lines = content.split("\n").map((l) => l.trim());
|
|
15579
|
+
const covering = [".verity/.snapshot/", ".verity/.snapshot", ".verity/", ".verity", ".verity/*"];
|
|
15580
|
+
if (lines.some((l) => covering.includes(l))) return "covered";
|
|
15581
|
+
}
|
|
15582
|
+
try {
|
|
15583
|
+
const block = "# Verity \u2014 snapshots of analyzed files (machine state, never commit)\n.verity/.snapshot/\n";
|
|
15584
|
+
(0, import_node_fs16.writeFileSync)(".gitignore", content ? content + (content.endsWith("\n") ? "" : "\n") + "\n" + block : block);
|
|
15585
|
+
return "added";
|
|
15586
|
+
} catch {
|
|
15587
|
+
return "failed";
|
|
15588
|
+
}
|
|
15589
|
+
}
|
|
15516
15590
|
function saveSnapshots(files) {
|
|
15517
15591
|
const snapshotPaths = /* @__PURE__ */ new Set();
|
|
15518
15592
|
for (const file of files) {
|
|
15519
|
-
|
|
15593
|
+
if (!resolveInside(SNAPSHOT_DIR, file.path)) continue;
|
|
15594
|
+
const snapshotPath = (0, import_node_path15.join)(SNAPSHOT_DIR, file.path);
|
|
15520
15595
|
snapshotPaths.add(snapshotPath);
|
|
15521
|
-
(0,
|
|
15522
|
-
(0,
|
|
15596
|
+
(0, import_node_fs16.mkdirSync)((0, import_node_path15.dirname)(snapshotPath), { recursive: true });
|
|
15597
|
+
(0, import_node_fs16.writeFileSync)(snapshotPath, file.content);
|
|
15523
15598
|
}
|
|
15524
15599
|
cleanStaleSnapshots(SNAPSHOT_DIR, snapshotPaths);
|
|
15525
15600
|
}
|
|
15526
15601
|
function computeDiff(oldContent, newContent, filePath) {
|
|
15527
|
-
const tmpOld = (0,
|
|
15528
|
-
const tmpNew = (0,
|
|
15602
|
+
const tmpOld = (0, import_node_path15.join)(SNAPSHOT_DIR, ".diff-old.tmp");
|
|
15603
|
+
const tmpNew = (0, import_node_path15.join)(SNAPSHOT_DIR, ".diff-new.tmp");
|
|
15529
15604
|
try {
|
|
15530
|
-
(0,
|
|
15531
|
-
(0,
|
|
15532
|
-
(0,
|
|
15605
|
+
(0, import_node_fs16.mkdirSync)(SNAPSHOT_DIR, { recursive: true });
|
|
15606
|
+
(0, import_node_fs16.writeFileSync)(tmpOld, oldContent);
|
|
15607
|
+
(0, import_node_fs16.writeFileSync)(tmpNew, newContent);
|
|
15533
15608
|
const result = (0, import_node_child_process6.execSync)(
|
|
15534
15609
|
`git diff --no-index --unified=10 -- "${tmpOld}" "${tmpNew}"`,
|
|
15535
15610
|
{ encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
|
|
@@ -15543,32 +15618,32 @@ function computeDiff(oldContent, newContent, filePath) {
|
|
|
15543
15618
|
return null;
|
|
15544
15619
|
} finally {
|
|
15545
15620
|
try {
|
|
15546
|
-
(0,
|
|
15621
|
+
(0, import_node_fs16.unlinkSync)(tmpOld);
|
|
15547
15622
|
} catch {
|
|
15548
15623
|
}
|
|
15549
15624
|
try {
|
|
15550
|
-
(0,
|
|
15625
|
+
(0, import_node_fs16.unlinkSync)(tmpNew);
|
|
15551
15626
|
} catch {
|
|
15552
15627
|
}
|
|
15553
15628
|
}
|
|
15554
15629
|
}
|
|
15555
15630
|
function cleanStaleSnapshots(dir, keepSet) {
|
|
15556
|
-
if (!(0,
|
|
15631
|
+
if (!(0, import_node_fs16.existsSync)(dir)) return;
|
|
15557
15632
|
try {
|
|
15558
|
-
const entries = (0,
|
|
15633
|
+
const entries = (0, import_node_fs16.readdirSync)(dir, { withFileTypes: true });
|
|
15559
15634
|
for (const entry of entries) {
|
|
15560
|
-
if (entry.name.
|
|
15561
|
-
const fullPath = (0,
|
|
15635
|
+
if (dir === SNAPSHOT_DIR && (entry.name === ".diff-old.tmp" || entry.name === ".diff-new.tmp")) continue;
|
|
15636
|
+
const fullPath = (0, import_node_path15.join)(dir, entry.name);
|
|
15562
15637
|
if (entry.isDirectory()) {
|
|
15563
15638
|
cleanStaleSnapshots(fullPath, keepSet);
|
|
15564
15639
|
try {
|
|
15565
|
-
const remaining = (0,
|
|
15566
|
-
if (remaining.length === 0) (0,
|
|
15640
|
+
const remaining = (0, import_node_fs16.readdirSync)(fullPath);
|
|
15641
|
+
if (remaining.length === 0) (0, import_node_fs16.rmdirSync)(fullPath);
|
|
15567
15642
|
} catch {
|
|
15568
15643
|
}
|
|
15569
15644
|
} else if (!keepSet.has(fullPath)) {
|
|
15570
15645
|
try {
|
|
15571
|
-
(0,
|
|
15646
|
+
(0, import_node_fs16.unlinkSync)(fullPath);
|
|
15572
15647
|
} catch {
|
|
15573
15648
|
}
|
|
15574
15649
|
}
|
|
@@ -15587,20 +15662,20 @@ function sessionKey(sessionId) {
|
|
|
15587
15662
|
return (0, import_node_crypto9.createHash)("sha256").update(sessionId).digest("hex").slice(0, 16);
|
|
15588
15663
|
}
|
|
15589
15664
|
function sessionDir(key) {
|
|
15590
|
-
return (0,
|
|
15665
|
+
return (0, import_node_path16.join)(projectPath(BASELINE_DIR), key);
|
|
15591
15666
|
}
|
|
15592
15667
|
function manifestPath(dir) {
|
|
15593
|
-
return (0,
|
|
15668
|
+
return (0, import_node_path16.join)(dir, "manifest.json");
|
|
15594
15669
|
}
|
|
15595
15670
|
function mirrorPath(dir, repoRelPath) {
|
|
15596
|
-
return (0,
|
|
15671
|
+
return (0, import_node_path16.join)(dir, "files", repoRelPath);
|
|
15597
15672
|
}
|
|
15598
15673
|
var CARRY_FILE = `${BASELINE_DIR}/.carry`;
|
|
15599
15674
|
var CARRY_WINDOW_MS = 12e4;
|
|
15600
15675
|
function writeCarry(sessionId, headSha) {
|
|
15601
15676
|
try {
|
|
15602
|
-
(0,
|
|
15603
|
-
(0,
|
|
15677
|
+
(0, import_node_fs17.mkdirSync)(projectPath(BASELINE_DIR), { recursive: true });
|
|
15678
|
+
(0, import_node_fs17.writeFileSync)(
|
|
15604
15679
|
projectPath(CARRY_FILE),
|
|
15605
15680
|
JSON.stringify({ from_key: sessionKey(sessionId), head_sha: headSha, ts: Date.now() })
|
|
15606
15681
|
);
|
|
@@ -15610,10 +15685,10 @@ function writeCarry(sessionId, headSha) {
|
|
|
15610
15685
|
function claimCarry(newKey) {
|
|
15611
15686
|
const carryPath = projectPath(CARRY_FILE);
|
|
15612
15687
|
try {
|
|
15613
|
-
if (!(0,
|
|
15614
|
-
const carry = JSON.parse((0,
|
|
15688
|
+
if (!(0, import_node_fs17.existsSync)(carryPath)) return null;
|
|
15689
|
+
const carry = JSON.parse((0, import_node_fs17.readFileSync)(carryPath, "utf-8"));
|
|
15615
15690
|
try {
|
|
15616
|
-
(0,
|
|
15691
|
+
(0, import_node_fs17.rmSync)(carryPath, { force: true });
|
|
15617
15692
|
} catch {
|
|
15618
15693
|
}
|
|
15619
15694
|
if (!carry?.from_key || typeof carry.ts !== "number") return null;
|
|
@@ -15624,11 +15699,11 @@ function claimCarry(newKey) {
|
|
|
15624
15699
|
if (!prior) return null;
|
|
15625
15700
|
const toDir = sessionDir(newKey);
|
|
15626
15701
|
try {
|
|
15627
|
-
(0,
|
|
15702
|
+
(0, import_node_fs17.rmSync)(toDir, { recursive: true, force: true });
|
|
15628
15703
|
} catch {
|
|
15629
15704
|
}
|
|
15630
|
-
(0,
|
|
15631
|
-
(0,
|
|
15705
|
+
(0, import_node_fs17.renameSync)(fromDir, toDir);
|
|
15706
|
+
(0, import_node_fs17.writeFileSync)(manifestPath(toDir), JSON.stringify({ ...prior, session_id: newKey }) + "\n");
|
|
15632
15707
|
return readManifest(toDir);
|
|
15633
15708
|
} catch {
|
|
15634
15709
|
return null;
|
|
@@ -15652,21 +15727,21 @@ function captureBaseline(opts = {}) {
|
|
|
15652
15727
|
const head_sha = getCurrentCommit();
|
|
15653
15728
|
const dirty = getDirtyFiles();
|
|
15654
15729
|
try {
|
|
15655
|
-
(0,
|
|
15730
|
+
(0, import_node_fs17.rmSync)(dir, { recursive: true, force: true });
|
|
15656
15731
|
} catch {
|
|
15657
15732
|
}
|
|
15658
|
-
const filesDir = (0,
|
|
15733
|
+
const filesDir = (0, import_node_path16.join)(dir, "files");
|
|
15659
15734
|
const mirrored = [];
|
|
15660
15735
|
try {
|
|
15661
|
-
(0,
|
|
15736
|
+
(0, import_node_fs17.mkdirSync)(filesDir, { recursive: true });
|
|
15662
15737
|
for (const p of dirty) {
|
|
15663
15738
|
if (p.includes("..")) continue;
|
|
15664
15739
|
const content = safeReadForMirror(projectPath(p));
|
|
15665
15740
|
if (content === null) continue;
|
|
15666
15741
|
const dest = mirrorPath(dir, p);
|
|
15667
15742
|
try {
|
|
15668
|
-
(0,
|
|
15669
|
-
(0,
|
|
15743
|
+
(0, import_node_fs17.mkdirSync)((0, import_node_path16.dirname)(dest), { recursive: true });
|
|
15744
|
+
(0, import_node_fs17.writeFileSync)(dest, content);
|
|
15670
15745
|
mirrored.push(p);
|
|
15671
15746
|
} catch {
|
|
15672
15747
|
}
|
|
@@ -15681,8 +15756,8 @@ function captureBaseline(opts = {}) {
|
|
|
15681
15756
|
version: BASELINE_VERSION
|
|
15682
15757
|
};
|
|
15683
15758
|
try {
|
|
15684
|
-
(0,
|
|
15685
|
-
(0,
|
|
15759
|
+
(0, import_node_fs17.mkdirSync)(dir, { recursive: true });
|
|
15760
|
+
(0, import_node_fs17.writeFileSync)(manifestPath(dir), JSON.stringify(baseline));
|
|
15686
15761
|
} catch {
|
|
15687
15762
|
}
|
|
15688
15763
|
pruneOldBaselines();
|
|
@@ -15693,9 +15768,9 @@ function readBaseline(sessionId) {
|
|
|
15693
15768
|
}
|
|
15694
15769
|
function readManifest(dir) {
|
|
15695
15770
|
const mp = manifestPath(dir);
|
|
15696
|
-
if (!(0,
|
|
15771
|
+
if (!(0, import_node_fs17.existsSync)(mp)) return null;
|
|
15697
15772
|
try {
|
|
15698
|
-
const parsed = JSON.parse((0,
|
|
15773
|
+
const parsed = JSON.parse((0, import_node_fs17.readFileSync)(mp, "utf-8"));
|
|
15699
15774
|
if (typeof parsed.head_sha !== "string" || typeof parsed.captured_at !== "number" || !Array.isArray(parsed.dirty_paths) || parsed.version !== BASELINE_VERSION) {
|
|
15700
15775
|
return null;
|
|
15701
15776
|
}
|
|
@@ -15726,9 +15801,9 @@ function preImage(repoRelPath, baseline) {
|
|
|
15726
15801
|
function resolvePreImage(repoRelPath, baseline) {
|
|
15727
15802
|
if (baseline.dirty_paths.includes(repoRelPath)) {
|
|
15728
15803
|
const mp = mirrorPath(sessionDir(sessionKey(baseline.session_id)), repoRelPath);
|
|
15729
|
-
if ((0,
|
|
15804
|
+
if ((0, import_node_fs17.existsSync)(mp)) {
|
|
15730
15805
|
try {
|
|
15731
|
-
return { content: (0,
|
|
15806
|
+
return { content: (0, import_node_fs17.readFileSync)(mp, "utf-8"), existed: true };
|
|
15732
15807
|
} catch {
|
|
15733
15808
|
}
|
|
15734
15809
|
}
|
|
@@ -15773,8 +15848,8 @@ function absorbIntoBaseline(paths, sessionId) {
|
|
|
15773
15848
|
const content = safeReadForMirror(projectPath(p));
|
|
15774
15849
|
if (content === null) continue;
|
|
15775
15850
|
const dest = mirrorPath(dir, p);
|
|
15776
|
-
(0,
|
|
15777
|
-
(0,
|
|
15851
|
+
(0, import_node_fs17.mkdirSync)((0, import_node_path16.dirname)(dest), { recursive: true });
|
|
15852
|
+
(0, import_node_fs17.writeFileSync)(dest, content);
|
|
15778
15853
|
dirty.add(p);
|
|
15779
15854
|
adopted++;
|
|
15780
15855
|
} catch {
|
|
@@ -15783,7 +15858,7 @@ function absorbIntoBaseline(paths, sessionId) {
|
|
|
15783
15858
|
if (adopted === 0) return 0;
|
|
15784
15859
|
try {
|
|
15785
15860
|
const updated = { ...baseline, dirty_paths: [...dirty] };
|
|
15786
|
-
(0,
|
|
15861
|
+
(0, import_node_fs17.writeFileSync)(manifestPath(dir), JSON.stringify(updated));
|
|
15787
15862
|
preImageCache.delete(baseline);
|
|
15788
15863
|
} catch {
|
|
15789
15864
|
return 0;
|
|
@@ -15794,7 +15869,7 @@ function changedSinceBaseline(repoRelPath, baseline) {
|
|
|
15794
15869
|
const pre = preImage(repoRelPath, baseline);
|
|
15795
15870
|
let current;
|
|
15796
15871
|
try {
|
|
15797
|
-
current = (0,
|
|
15872
|
+
current = (0, import_node_fs17.readFileSync)(projectPath(repoRelPath), "utf-8");
|
|
15798
15873
|
} catch {
|
|
15799
15874
|
return pre.existed;
|
|
15800
15875
|
}
|
|
@@ -15803,8 +15878,8 @@ function changedSinceBaseline(repoRelPath, baseline) {
|
|
|
15803
15878
|
}
|
|
15804
15879
|
function safeReadForMirror(absPath) {
|
|
15805
15880
|
try {
|
|
15806
|
-
if ((0,
|
|
15807
|
-
const buf = (0,
|
|
15881
|
+
if ((0, import_node_fs17.statSync)(absPath).size > MIRROR_MAX_BYTES) return null;
|
|
15882
|
+
const buf = (0, import_node_fs17.readFileSync)(absPath);
|
|
15808
15883
|
if (buf.includes(0)) return null;
|
|
15809
15884
|
return buf.toString("utf-8");
|
|
15810
15885
|
} catch {
|
|
@@ -15815,18 +15890,18 @@ function pruneOldBaselines() {
|
|
|
15815
15890
|
const root = projectPath(BASELINE_DIR);
|
|
15816
15891
|
let entries;
|
|
15817
15892
|
try {
|
|
15818
|
-
entries = (0,
|
|
15893
|
+
entries = (0, import_node_fs17.readdirSync)(root);
|
|
15819
15894
|
} catch {
|
|
15820
15895
|
return;
|
|
15821
15896
|
}
|
|
15822
15897
|
const now = Date.now();
|
|
15823
15898
|
for (const name of entries) {
|
|
15824
|
-
const dir = (0,
|
|
15899
|
+
const dir = (0, import_node_path16.join)(root, name);
|
|
15825
15900
|
const manifest = readManifest(dir);
|
|
15826
15901
|
if (!manifest) {
|
|
15827
15902
|
try {
|
|
15828
|
-
if (now - (0,
|
|
15829
|
-
(0,
|
|
15903
|
+
if (now - (0, import_node_fs17.statSync)(dir).mtimeMs > BASELINE_TTL_MS) {
|
|
15904
|
+
(0, import_node_fs17.rmSync)(dir, { recursive: true, force: true });
|
|
15830
15905
|
}
|
|
15831
15906
|
} catch {
|
|
15832
15907
|
}
|
|
@@ -15834,7 +15909,7 @@ function pruneOldBaselines() {
|
|
|
15834
15909
|
}
|
|
15835
15910
|
if (now - manifest.captured_at <= BASELINE_TTL_MS) continue;
|
|
15836
15911
|
try {
|
|
15837
|
-
(0,
|
|
15912
|
+
(0, import_node_fs17.rmSync)(dir, { recursive: true, force: true });
|
|
15838
15913
|
} catch {
|
|
15839
15914
|
}
|
|
15840
15915
|
}
|
|
@@ -16007,8 +16082,8 @@ function buildCompactionContext(session) {
|
|
|
16007
16082
|
commitsSince: commitsSincePaths(watermark, (state.authored ?? []).map((a) => a.path)),
|
|
16008
16083
|
readFileLines: (file) => {
|
|
16009
16084
|
try {
|
|
16010
|
-
const abs = (0,
|
|
16011
|
-
return (0,
|
|
16085
|
+
const abs = (0, import_node_path17.join)(root, file);
|
|
16086
|
+
return (0, import_node_fs18.existsSync)(abs) ? (0, import_node_fs18.readFileSync)(abs, "utf8").split("\n") : null;
|
|
16012
16087
|
} catch {
|
|
16013
16088
|
return null;
|
|
16014
16089
|
}
|
|
@@ -16044,17 +16119,17 @@ async function readHookStdin() {
|
|
|
16044
16119
|
try {
|
|
16045
16120
|
if (process.stdin.isTTY) return {};
|
|
16046
16121
|
const chunks = [];
|
|
16047
|
-
const timeout = new Promise((
|
|
16048
|
-
const read = new Promise((
|
|
16122
|
+
const timeout = new Promise((resolve4) => setTimeout(() => resolve4({}), 500));
|
|
16123
|
+
const read = new Promise((resolve4) => {
|
|
16049
16124
|
process.stdin.on("data", (c) => chunks.push(c));
|
|
16050
16125
|
process.stdin.on("end", () => {
|
|
16051
16126
|
try {
|
|
16052
|
-
|
|
16127
|
+
resolve4(JSON.parse(Buffer.concat(chunks).toString("utf-8").trim() || "{}"));
|
|
16053
16128
|
} catch {
|
|
16054
|
-
|
|
16129
|
+
resolve4({});
|
|
16055
16130
|
}
|
|
16056
16131
|
});
|
|
16057
|
-
process.stdin.on("error", () =>
|
|
16132
|
+
process.stdin.on("error", () => resolve4({}));
|
|
16058
16133
|
process.stdin.resume();
|
|
16059
16134
|
});
|
|
16060
16135
|
return await Promise.race([read, timeout]);
|
|
@@ -16572,6 +16647,7 @@ function createRun(opts, globals) {
|
|
|
16572
16647
|
phaseReached: "",
|
|
16573
16648
|
phasesCompleted: [],
|
|
16574
16649
|
skipReason: null,
|
|
16650
|
+
treeFrame: null,
|
|
16575
16651
|
turnId: "",
|
|
16576
16652
|
// The value `resolveReachability` itself returns when every rung declines.
|
|
16577
16653
|
reachability: { human_reachable: "unknown", human_reachable_source: "inferred", rung: "none" },
|
|
@@ -16640,7 +16716,7 @@ function createRun(opts, globals) {
|
|
|
16640
16716
|
}
|
|
16641
16717
|
|
|
16642
16718
|
// src/lib/stderr-log.ts
|
|
16643
|
-
var
|
|
16719
|
+
var import_node_fs19 = require("node:fs");
|
|
16644
16720
|
var TOKEN_RE2 = /verity_[0-9a-f]{16,}/g;
|
|
16645
16721
|
var ANSI_RE = /\u001b\[[0-?]*[ -/]*[@-~]/g;
|
|
16646
16722
|
function scrub(s) {
|
|
@@ -16653,9 +16729,9 @@ function append(text) {
|
|
|
16653
16729
|
try {
|
|
16654
16730
|
const dir = projectPath(DEBUG_LOG_DIR);
|
|
16655
16731
|
const file = projectPath(STDERR_LOG_FILE);
|
|
16656
|
-
(0,
|
|
16732
|
+
(0, import_node_fs19.mkdirSync)(dir, { recursive: true });
|
|
16657
16733
|
rotateIfNeeded(file);
|
|
16658
|
-
(0,
|
|
16734
|
+
(0, import_node_fs19.appendFileSync)(file, text);
|
|
16659
16735
|
} catch {
|
|
16660
16736
|
}
|
|
16661
16737
|
}
|
|
@@ -16711,13 +16787,17 @@ function formatRunEvidence(run, startedAt) {
|
|
|
16711
16787
|
`;
|
|
16712
16788
|
out += row("turn", `${run.turnId || "(unminted)"}${run.sessionId ? ` \xB7 session ${run.sessionId}` : ""}`);
|
|
16713
16789
|
out += row("reached", `${run.phaseReached || "(none)"}${run.skipReason ? ` \xB7 SKIPPED: ${run.skipReason}` : ""} \xB7 ${ms}ms`);
|
|
16790
|
+
if (run.treeFrame) {
|
|
16791
|
+
const f = run.treeFrame;
|
|
16792
|
+
out += row("tree", f.worktreeRoot ? `${f.worktreeRoot}${f.isLinkedWorktree ? " \xB7 linked worktree" : ""}${f.branch ? ` \xB7 branch ${f.branch}` : " \xB7 detached"}` : `(unresolved: ${f.refusal ?? "unknown"})`);
|
|
16793
|
+
}
|
|
16714
16794
|
out += row("changed", `${run.changedUniverse.length} from git \xB7 analyzable ${run.analyzable.length} \xB7 reviewable ${run.reviewable.length} \xB7 security ${run.securityFiles.length} \xB7 forReview ${run.allForReview.length}`);
|
|
16715
16795
|
const done = (phase) => run.phasesCompleted.includes(phase);
|
|
16716
16796
|
const ifDone = (phase, value) => done(phase) ? value : "?";
|
|
16717
16797
|
const md = run.modeDecision;
|
|
16718
16798
|
if (md) {
|
|
16719
16799
|
const how = md.forced ? "forced by --mode" : `predicted=${md.predicted ?? "none"} \u2192 ${md.resolved}`;
|
|
16720
|
-
out += row("mode", `${md.resolved} \xB7 ${how} \xB7 authored=${md.authored ? "yes" : "no"} \xB7 investigated=${md.investigated ? "yes" : "no"}`);
|
|
16800
|
+
out += row("mode", `${md.resolved} \xB7 ${how}` + (md.flip ? ` (flipped to plan: no delta at ${md.flip})` : "") + ` \xB7 authored=${md.authored ? "yes" : "no"} \xB7 investigated=${md.investigated ? "yes" : "no"}`);
|
|
16721
16801
|
} else {
|
|
16722
16802
|
out += row("mode", `? (this run stopped in ${run.phaseReached || "no phase"}, before the mode was decided)`);
|
|
16723
16803
|
}
|
|
@@ -16807,6 +16887,285 @@ function installRunEvidence(run) {
|
|
|
16807
16887
|
});
|
|
16808
16888
|
}
|
|
16809
16889
|
|
|
16890
|
+
// src/lib/git-frame.ts
|
|
16891
|
+
var import_node_child_process7 = require("node:child_process");
|
|
16892
|
+
var import_node_fs20 = require("node:fs");
|
|
16893
|
+
var import_node_os3 = require("node:os");
|
|
16894
|
+
var import_node_path18 = require("node:path");
|
|
16895
|
+
var import_node_path19 = require("node:path");
|
|
16896
|
+
var VALUE_TOKEN = `(?:'[^']*'|"[^"]*"|\\S+)`;
|
|
16897
|
+
var GIT_GLOBAL_OPTS = `(?:\\s+(?:-[Cc]\\s+${VALUE_TOKEN}|--?[\\w-]+(?:=\\S+)?))*`;
|
|
16898
|
+
var COMMIT_HEAD = `git${GIT_GLOBAL_OPTS}\\s+commit(?![\\w-])`;
|
|
16899
|
+
var PUSH_HEAD = `git${GIT_GLOBAL_OPTS}\\s+push\\b`;
|
|
16900
|
+
var GH_PR_HEAD = `gh${GIT_GLOBAL_OPTS}\\s+pr\\s+create\\b`;
|
|
16901
|
+
var COMMIT_RE = new RegExp(`(?:^|[\\s;&|(])${COMMIT_HEAD}|(?:^|[;&|(])\\s*[^\\s;&|()'"]*\\/${COMMIT_HEAD}`);
|
|
16902
|
+
var PUSH_RE = new RegExp(`(?:^|[\\s;&|(])${PUSH_HEAD}|(?:^|[;&|(])\\s*[^\\s;&|()'"]*\\/${PUSH_HEAD}`);
|
|
16903
|
+
var GH_PR_RE = new RegExp(`(?:^|[\\s;&|(])${GH_PR_HEAD}|(?:^|[;&|(])\\s*[^\\s;&|()'"]*\\/${GH_PR_HEAD}`);
|
|
16904
|
+
function splitSegments(command) {
|
|
16905
|
+
return (command ?? "").split(/&&|\|\||;|\n/);
|
|
16906
|
+
}
|
|
16907
|
+
function findMomentSegment(command, on) {
|
|
16908
|
+
const segments = splitSegments(command);
|
|
16909
|
+
let commitIdx = -1;
|
|
16910
|
+
let pushIdx = -1;
|
|
16911
|
+
for (let i = 0; i < segments.length; i++) {
|
|
16912
|
+
const seg = segments[i];
|
|
16913
|
+
if (/--dry-run\b/.test(seg)) continue;
|
|
16914
|
+
if (commitIdx === -1 && COMMIT_RE.test(seg)) commitIdx = i;
|
|
16915
|
+
if (pushIdx === -1 && (PUSH_RE.test(seg) || GH_PR_RE.test(seg))) pushIdx = i;
|
|
16916
|
+
}
|
|
16917
|
+
if (commitIdx !== -1 && on.includes("commit")) return { moment: "pre-commit", segmentIndex: commitIdx };
|
|
16918
|
+
if (pushIdx !== -1 && on.includes("push")) return { moment: "pre-push", segmentIndex: pushIdx };
|
|
16919
|
+
return null;
|
|
16920
|
+
}
|
|
16921
|
+
function classifyCommand(command, on) {
|
|
16922
|
+
return findMomentSegment(command, on)?.moment ?? null;
|
|
16923
|
+
}
|
|
16924
|
+
function unquote(token) {
|
|
16925
|
+
if (token.length >= 2) {
|
|
16926
|
+
const first = token[0];
|
|
16927
|
+
if ((first === "'" || first === '"') && token.endsWith(first)) return token.slice(1, -1);
|
|
16928
|
+
}
|
|
16929
|
+
return token;
|
|
16930
|
+
}
|
|
16931
|
+
var SHELL_DYNAMIC = /[$`\\]/;
|
|
16932
|
+
function extractCommandTarget(command, segmentIndex, baseDir) {
|
|
16933
|
+
const segments = splitSegments(command);
|
|
16934
|
+
let dir = baseDir;
|
|
16935
|
+
let named = false;
|
|
16936
|
+
for (let i = 0; i < segmentIndex; i++) {
|
|
16937
|
+
const m = segments[i].match(new RegExp(`^\\s*cd(?:\\s+(${VALUE_TOKEN}))?\\s*$`));
|
|
16938
|
+
if (!m) continue;
|
|
16939
|
+
named = true;
|
|
16940
|
+
if (m[1] === void 0) {
|
|
16941
|
+
dir = (0, import_node_os3.homedir)();
|
|
16942
|
+
continue;
|
|
16943
|
+
}
|
|
16944
|
+
const raw = unquote(m[1]);
|
|
16945
|
+
if (SHELL_DYNAMIC.test(raw) || raw === "-") {
|
|
16946
|
+
return { dir: null, named: true, unresolvable: `cd target not statically resolvable: ${raw}` };
|
|
16947
|
+
}
|
|
16948
|
+
const expanded = raw === "~" ? (0, import_node_os3.homedir)() : raw.startsWith("~/") ? (0, import_node_path19.join)((0, import_node_os3.homedir)(), raw.slice(2)) : raw;
|
|
16949
|
+
dir = (0, import_node_path18.isAbsolute)(expanded) ? expanded : (0, import_node_path18.resolve)(dir, expanded);
|
|
16950
|
+
}
|
|
16951
|
+
const seg = segments[segmentIndex];
|
|
16952
|
+
const gitMatch = seg.match(new RegExp(`(?:^|[\\s;&|(])(?:[^\\s;&|()'"]*\\/)?git(${GIT_GLOBAL_OPTS})\\s`));
|
|
16953
|
+
if (gitMatch) {
|
|
16954
|
+
const optsRegion = gitMatch[1] ?? "";
|
|
16955
|
+
const cRe = new RegExp(`-C\\s+(${VALUE_TOKEN})`, "g");
|
|
16956
|
+
let cm;
|
|
16957
|
+
while ((cm = cRe.exec(optsRegion)) !== null) {
|
|
16958
|
+
named = true;
|
|
16959
|
+
const raw = unquote(cm[1]);
|
|
16960
|
+
if (SHELL_DYNAMIC.test(raw)) {
|
|
16961
|
+
return { dir: null, named: true, unresolvable: `-C target not statically resolvable: ${raw}` };
|
|
16962
|
+
}
|
|
16963
|
+
const expanded = raw === "~" ? (0, import_node_os3.homedir)() : raw.startsWith("~/") ? (0, import_node_path19.join)((0, import_node_os3.homedir)(), raw.slice(2)) : raw;
|
|
16964
|
+
dir = (0, import_node_path18.isAbsolute)(expanded) ? expanded : (0, import_node_path18.resolve)(dir, expanded);
|
|
16965
|
+
}
|
|
16966
|
+
}
|
|
16967
|
+
return { dir, named, unresolvable: null };
|
|
16968
|
+
}
|
|
16969
|
+
var PUSH_VALUE_FLAGS = /* @__PURE__ */ new Set(["-o", "--push-option", "--receive-pack", "--exec"]);
|
|
16970
|
+
function parsePushTarget(segment) {
|
|
16971
|
+
const none = { remote: null, srcRef: null, dstRef: null, isDelete: false };
|
|
16972
|
+
const m = PUSH_RE.exec(segment);
|
|
16973
|
+
if (!m) return none;
|
|
16974
|
+
const rest = segment.slice(m.index + m[0].length);
|
|
16975
|
+
const tokens = (rest.match(new RegExp(`'[^']*'|"[^"]*"|\\S+`, "g")) ?? []).map(unquote);
|
|
16976
|
+
let remote = null;
|
|
16977
|
+
let refspec = null;
|
|
16978
|
+
let isDelete = false;
|
|
16979
|
+
for (let i = 0; i < tokens.length; i++) {
|
|
16980
|
+
const t = tokens[i];
|
|
16981
|
+
if (t === "-d" || t === "--delete") {
|
|
16982
|
+
isDelete = true;
|
|
16983
|
+
continue;
|
|
16984
|
+
}
|
|
16985
|
+
if (t.startsWith("--repo=")) {
|
|
16986
|
+
remote = t.slice("--repo=".length);
|
|
16987
|
+
continue;
|
|
16988
|
+
}
|
|
16989
|
+
if (t === "--repo") {
|
|
16990
|
+
remote = tokens[++i] ?? null;
|
|
16991
|
+
continue;
|
|
16992
|
+
}
|
|
16993
|
+
if (PUSH_VALUE_FLAGS.has(t)) {
|
|
16994
|
+
i++;
|
|
16995
|
+
continue;
|
|
16996
|
+
}
|
|
16997
|
+
if (t.startsWith("-")) continue;
|
|
16998
|
+
if (SHELL_DYNAMIC.test(t)) return none;
|
|
16999
|
+
if (remote === null) {
|
|
17000
|
+
remote = t;
|
|
17001
|
+
continue;
|
|
17002
|
+
}
|
|
17003
|
+
if (refspec === null) {
|
|
17004
|
+
refspec = t;
|
|
17005
|
+
continue;
|
|
17006
|
+
}
|
|
17007
|
+
break;
|
|
17008
|
+
}
|
|
17009
|
+
if (refspec === null) return { remote, srcRef: null, dstRef: null, isDelete };
|
|
17010
|
+
const spec = refspec.startsWith("+") ? refspec.slice(1) : refspec;
|
|
17011
|
+
const colon = spec.indexOf(":");
|
|
17012
|
+
if (colon === -1) return { remote, srcRef: spec, dstRef: null, isDelete };
|
|
17013
|
+
const src = spec.slice(0, colon);
|
|
17014
|
+
const dst = spec.slice(colon + 1);
|
|
17015
|
+
if (src === "") return { remote, srcRef: null, dstRef: dst || null, isDelete: true };
|
|
17016
|
+
return { remote, srcRef: src, dstRef: dst || null, isDelete };
|
|
17017
|
+
}
|
|
17018
|
+
function gitAt(dir, args) {
|
|
17019
|
+
try {
|
|
17020
|
+
return (0, import_node_child_process7.execFileSync)("git", args, { cwd: dir, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
|
|
17021
|
+
} catch {
|
|
17022
|
+
return "";
|
|
17023
|
+
}
|
|
17024
|
+
}
|
|
17025
|
+
function realpathOr(p) {
|
|
17026
|
+
try {
|
|
17027
|
+
return import_node_fs20.realpathSync.native(p);
|
|
17028
|
+
} catch {
|
|
17029
|
+
return (0, import_node_path18.resolve)(p);
|
|
17030
|
+
}
|
|
17031
|
+
}
|
|
17032
|
+
function resolveFrame(input) {
|
|
17033
|
+
const found = findMomentSegment(input.command, input.on);
|
|
17034
|
+
const hookDirUsable = !!input.hookCwd && (0, import_node_fs20.existsSync)(input.hookCwd);
|
|
17035
|
+
const baseDir = hookDirUsable ? input.hookCwd : process.cwd();
|
|
17036
|
+
let anchor = hookDirUsable ? "hook-cwd" : "process-cwd";
|
|
17037
|
+
const refuse = (refusal) => ({
|
|
17038
|
+
moment: found?.moment ?? null,
|
|
17039
|
+
frame: { worktreeRoot: null, gitDir: null, commonDir: null, isLinkedWorktree: false, branch: null, anchor, refusal }
|
|
17040
|
+
});
|
|
17041
|
+
let dir = baseDir;
|
|
17042
|
+
if (found) {
|
|
17043
|
+
const target = extractCommandTarget(input.command, found.segmentIndex, baseDir);
|
|
17044
|
+
if (target.named) anchor = "command-target";
|
|
17045
|
+
if (target.unresolvable) return refuse(`target:${target.unresolvable}`);
|
|
17046
|
+
if (target.dir !== null && target.dir !== baseDir) {
|
|
17047
|
+
if (!(0, import_node_fs20.existsSync)(target.dir)) return refuse(`target:directory does not exist: ${target.dir}`);
|
|
17048
|
+
dir = target.dir;
|
|
17049
|
+
} else if (target.named) {
|
|
17050
|
+
dir = target.dir ?? baseDir;
|
|
17051
|
+
}
|
|
17052
|
+
}
|
|
17053
|
+
const toplevel = gitAt(dir, ["rev-parse", "--show-toplevel"]);
|
|
17054
|
+
if (!toplevel) {
|
|
17055
|
+
return refuse(anchor === "command-target" ? `target:not a git repository: ${dir}` : `anchor:not a git repository: ${dir}`);
|
|
17056
|
+
}
|
|
17057
|
+
const gitDirRaw = gitAt(dir, ["rev-parse", "--absolute-git-dir"]);
|
|
17058
|
+
const commonRaw = gitAt(dir, ["rev-parse", "--git-common-dir"]);
|
|
17059
|
+
const gitDir = gitDirRaw ? realpathOr(gitDirRaw) : null;
|
|
17060
|
+
const commonDir = commonRaw ? realpathOr((0, import_node_path18.isAbsolute)(commonRaw) ? commonRaw : (0, import_node_path18.resolve)(dir, commonRaw)) : null;
|
|
17061
|
+
const branchRaw = gitAt(dir, ["rev-parse", "--abbrev-ref", "HEAD"]);
|
|
17062
|
+
return {
|
|
17063
|
+
moment: found?.moment ?? null,
|
|
17064
|
+
frame: {
|
|
17065
|
+
worktreeRoot: realpathOr(toplevel),
|
|
17066
|
+
gitDir,
|
|
17067
|
+
commonDir,
|
|
17068
|
+
// The one honest definition: a linked worktree's own git dir differs from
|
|
17069
|
+
// the shared one. No path convention involved — see the header.
|
|
17070
|
+
isLinkedWorktree: !!gitDir && !!commonDir && gitDir !== commonDir,
|
|
17071
|
+
branch: !branchRaw || branchRaw === "HEAD" ? null : branchRaw,
|
|
17072
|
+
anchor,
|
|
17073
|
+
refusal: null
|
|
17074
|
+
}
|
|
17075
|
+
};
|
|
17076
|
+
}
|
|
17077
|
+
function frameGit(frame, args) {
|
|
17078
|
+
if (!frame.worktreeRoot) return "";
|
|
17079
|
+
return gitAt(frame.worktreeRoot, args);
|
|
17080
|
+
}
|
|
17081
|
+
function refResolves(frame, ref) {
|
|
17082
|
+
return frameGit(frame, ["rev-parse", "--verify", "-q", `${ref}^{commit}`]) !== "";
|
|
17083
|
+
}
|
|
17084
|
+
var SHA_RE2 = /^[0-9a-f]{40}$/;
|
|
17085
|
+
function baselineShaAt(frame) {
|
|
17086
|
+
if (!frame.worktreeRoot) return null;
|
|
17087
|
+
try {
|
|
17088
|
+
const sha = (0, import_node_fs20.readFileSync)((0, import_node_path19.join)(frame.worktreeRoot, BASELINE_SHA_FILE), "utf-8").trim();
|
|
17089
|
+
if (!SHA_RE2.test(sha)) return null;
|
|
17090
|
+
return refResolves(frame, sha) ? sha : null;
|
|
17091
|
+
} catch {
|
|
17092
|
+
return null;
|
|
17093
|
+
}
|
|
17094
|
+
}
|
|
17095
|
+
function stagedRange() {
|
|
17096
|
+
return { kind: "staged", base: "HEAD", head: "INDEX", via: "index" };
|
|
17097
|
+
}
|
|
17098
|
+
function resolvePushRange(frame, command, on) {
|
|
17099
|
+
const nothing = (via) => ({ kind: "nothing", base: null, head: "HEAD", via });
|
|
17100
|
+
if (!frame.worktreeRoot) return nothing("refused");
|
|
17101
|
+
const found = findMomentSegment(command, on);
|
|
17102
|
+
const segment = found ? splitSegments(command)[found.segmentIndex] : "";
|
|
17103
|
+
const target = parsePushTarget(segment);
|
|
17104
|
+
if (target.isDelete) return nothing("deletion");
|
|
17105
|
+
const head = target.srcRef ?? "HEAD";
|
|
17106
|
+
if (!refResolves(frame, head)) return nothing(`src-unresolvable:${head}`);
|
|
17107
|
+
const srcName = target.srcRef;
|
|
17108
|
+
const branchForRemote = srcName ?? frame.branch;
|
|
17109
|
+
const candidates = [];
|
|
17110
|
+
if (target.remote && (target.dstRef ?? srcName)) {
|
|
17111
|
+
const dstName = (target.dstRef ?? srcName).replace(/^refs\/heads\//, "");
|
|
17112
|
+
candidates.push({ ref: `refs/remotes/${target.remote}/${dstName}`, via: `refspec:${target.remote}/${dstName}` });
|
|
17113
|
+
}
|
|
17114
|
+
if (target.remote && !srcName && !target.dstRef && frame.branch) {
|
|
17115
|
+
candidates.push({ ref: `refs/remotes/${target.remote}/${frame.branch}`, via: `remote:${target.remote}/${frame.branch}` });
|
|
17116
|
+
}
|
|
17117
|
+
candidates.push({ ref: srcName ? `${srcName}@{push}` : "@{push}", via: "@{push}" });
|
|
17118
|
+
candidates.push({ ref: srcName ? `${srcName}@{upstream}` : "@{upstream}", via: "@{upstream}" });
|
|
17119
|
+
if (branchForRemote) {
|
|
17120
|
+
candidates.push({
|
|
17121
|
+
ref: `refs/remotes/origin/${branchForRemote.replace(/^refs\/heads\//, "")}`,
|
|
17122
|
+
via: `origin/${branchForRemote.replace(/^refs\/heads\//, "")}`
|
|
17123
|
+
});
|
|
17124
|
+
}
|
|
17125
|
+
for (const c of candidates) {
|
|
17126
|
+
if (!refResolves(frame, c.ref)) continue;
|
|
17127
|
+
const mergeBase = frameGit(frame, ["merge-base", c.ref, head]);
|
|
17128
|
+
if (SHA_RE2.test(mergeBase)) return { kind: "push", base: mergeBase, head, via: c.via };
|
|
17129
|
+
}
|
|
17130
|
+
const baseline = baselineShaAt(frame);
|
|
17131
|
+
if (baseline) return { kind: "baseline", base: baseline, head, via: "review-baseline" };
|
|
17132
|
+
if (refResolves(frame, `${head}~1`)) return { kind: "last-commit", base: `${head}~1`, head, via: `${head}~1` };
|
|
17133
|
+
return nothing("no-parent");
|
|
17134
|
+
}
|
|
17135
|
+
function rangeFiles(frame, range) {
|
|
17136
|
+
let out;
|
|
17137
|
+
switch (range.kind) {
|
|
17138
|
+
case "staged":
|
|
17139
|
+
out = frameGit(frame, ["diff", "--cached", "--name-only"]);
|
|
17140
|
+
break;
|
|
17141
|
+
case "push":
|
|
17142
|
+
case "baseline":
|
|
17143
|
+
case "last-commit":
|
|
17144
|
+
out = frameGit(frame, ["diff", "--name-only", range.base, range.head === "INDEX" ? "HEAD" : range.head]);
|
|
17145
|
+
break;
|
|
17146
|
+
case "nothing":
|
|
17147
|
+
return [];
|
|
17148
|
+
}
|
|
17149
|
+
return out.split("\n").filter((l) => l.length > 0).filter((f) => !isVerityOwnedPath(f));
|
|
17150
|
+
}
|
|
17151
|
+
function frameTelemetry(frame, range, divergence) {
|
|
17152
|
+
const t = {
|
|
17153
|
+
anchor: frame.anchor,
|
|
17154
|
+
linked_worktree: frame.isLinkedWorktree,
|
|
17155
|
+
range_via: range?.via ?? null,
|
|
17156
|
+
refusal: frame.refusal
|
|
17157
|
+
};
|
|
17158
|
+
if (divergence) {
|
|
17159
|
+
t.root_differs = !!frame.worktreeRoot && !!divergence.actualRoot && realpathOr(frame.worktreeRoot) !== realpathOr(divergence.actualRoot);
|
|
17160
|
+
const a = [...divergence.actualFiles].sort().join("\n");
|
|
17161
|
+
const b = [...divergence.frameFiles].sort().join("\n");
|
|
17162
|
+
t.files_differ = a !== b;
|
|
17163
|
+
t.frame_file_count = divergence.frameFiles.length;
|
|
17164
|
+
t.actual_file_count = divergence.actualFiles.length;
|
|
17165
|
+
}
|
|
17166
|
+
return t;
|
|
17167
|
+
}
|
|
17168
|
+
|
|
16810
17169
|
// src/lib/reachability.ts
|
|
16811
17170
|
function resolveReachability(input = {}) {
|
|
16812
17171
|
const env = input.env ?? {};
|
|
@@ -16835,7 +17194,7 @@ function truthy(v) {
|
|
|
16835
17194
|
}
|
|
16836
17195
|
|
|
16837
17196
|
// src/lib/transcript.ts
|
|
16838
|
-
var
|
|
17197
|
+
var import_node_fs21 = require("node:fs");
|
|
16839
17198
|
var MAX_READ_BYTES = 256 * 1024;
|
|
16840
17199
|
var SMALL_FILE_BYTES = 64 * 1024;
|
|
16841
17200
|
var MAX_FILES_LIST = 20;
|
|
@@ -16859,7 +17218,7 @@ async function extractActionSummary(transcriptPath) {
|
|
|
16859
17218
|
function readTurnLines(transcriptPath) {
|
|
16860
17219
|
let size;
|
|
16861
17220
|
try {
|
|
16862
|
-
size = (0,
|
|
17221
|
+
size = (0, import_node_fs21.statSync)(transcriptPath).size;
|
|
16863
17222
|
} catch {
|
|
16864
17223
|
return null;
|
|
16865
17224
|
}
|
|
@@ -16867,7 +17226,7 @@ function readTurnLines(transcriptPath) {
|
|
|
16867
17226
|
let raw;
|
|
16868
17227
|
let windowed = false;
|
|
16869
17228
|
if (size <= SMALL_FILE_BYTES) {
|
|
16870
|
-
raw = (0,
|
|
17229
|
+
raw = (0, import_node_fs21.readFileSync)(transcriptPath, "utf-8");
|
|
16871
17230
|
} else {
|
|
16872
17231
|
windowed = true;
|
|
16873
17232
|
const buf = Buffer.alloc(Math.min(MAX_READ_BYTES, size));
|
|
@@ -17047,11 +17406,11 @@ function sanitizeCommand(rawCmd) {
|
|
|
17047
17406
|
let cmd = rawCmd.split("\n")[0];
|
|
17048
17407
|
let cut = -1;
|
|
17049
17408
|
let marker = "";
|
|
17050
|
-
for (const
|
|
17051
|
-
const idx = cmd.indexOf(
|
|
17409
|
+
for (const sep2 of [" | ", " > ", " >> ", " 2>", " && ", " ; "]) {
|
|
17410
|
+
const idx = cmd.indexOf(sep2);
|
|
17052
17411
|
if (idx > 0 && (cut === -1 || idx < cut)) {
|
|
17053
17412
|
cut = idx;
|
|
17054
|
-
marker =
|
|
17413
|
+
marker = sep2.trim();
|
|
17055
17414
|
}
|
|
17056
17415
|
}
|
|
17057
17416
|
if (cut > -1) cmd = cmd.slice(0, cut);
|
|
@@ -17075,28 +17434,28 @@ async function readStopHookStdin() {
|
|
|
17075
17434
|
try {
|
|
17076
17435
|
if (process.stdin.isTTY) return empty;
|
|
17077
17436
|
const chunks = [];
|
|
17078
|
-
const timeout = new Promise((
|
|
17079
|
-
const read = new Promise((
|
|
17437
|
+
const timeout = new Promise((resolve4) => setTimeout(() => resolve4(empty), 500));
|
|
17438
|
+
const read = new Promise((resolve4) => {
|
|
17080
17439
|
process.stdin.on("data", (chunk) => chunks.push(chunk));
|
|
17081
17440
|
process.stdin.on("end", () => {
|
|
17082
17441
|
const raw = Buffer.concat(chunks).toString("utf-8").trim();
|
|
17083
17442
|
if (!raw) {
|
|
17084
|
-
|
|
17443
|
+
resolve4(empty);
|
|
17085
17444
|
return;
|
|
17086
17445
|
}
|
|
17087
17446
|
try {
|
|
17088
17447
|
const data = JSON.parse(raw);
|
|
17089
|
-
|
|
17448
|
+
resolve4({
|
|
17090
17449
|
assistantMessage: typeof data.last_assistant_message === "string" ? data.last_assistant_message : null,
|
|
17091
17450
|
stopReason: typeof data.stop_reason === "string" ? data.stop_reason : null,
|
|
17092
17451
|
transcriptPath: typeof data.transcript_path === "string" ? data.transcript_path : null,
|
|
17093
17452
|
sessionId: typeof data.session_id === "string" ? data.session_id : null
|
|
17094
17453
|
});
|
|
17095
17454
|
} catch {
|
|
17096
|
-
|
|
17455
|
+
resolve4(empty);
|
|
17097
17456
|
}
|
|
17098
17457
|
});
|
|
17099
|
-
process.stdin.on("error", () =>
|
|
17458
|
+
process.stdin.on("error", () => resolve4(empty));
|
|
17100
17459
|
process.stdin.resume();
|
|
17101
17460
|
});
|
|
17102
17461
|
return await Promise.race([read, timeout]);
|
|
@@ -17110,6 +17469,7 @@ async function bootstrap(run) {
|
|
|
17110
17469
|
process.chdir(repoRoot());
|
|
17111
17470
|
} catch {
|
|
17112
17471
|
}
|
|
17472
|
+
run.treeFrame = resolveFrame({ command: "", on: [], hookCwd: null }).frame;
|
|
17113
17473
|
const turnId = `t-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
|
|
17114
17474
|
let reachability = resolveReachability({
|
|
17115
17475
|
autonomousFlag: process.env.VERITY_AUTONOMOUS === "1" || opts.mode === "autonomous",
|
|
@@ -17146,6 +17506,39 @@ async function bootstrap(run) {
|
|
|
17146
17506
|
Object.assign(run, { actionSummary, assistantResponse, baseline, baselineSessionId, reachability, sessionId, stopReason, tokenResult, transcriptPath, turnId });
|
|
17147
17507
|
}
|
|
17148
17508
|
|
|
17509
|
+
// src/lib/self-scope.ts
|
|
17510
|
+
var LEGACY_GATE_SKILLS = /* @__PURE__ */ new Set([
|
|
17511
|
+
"gate-setup",
|
|
17512
|
+
"gate-analyze",
|
|
17513
|
+
"gate-review",
|
|
17514
|
+
"gate-status",
|
|
17515
|
+
"gate-feedback",
|
|
17516
|
+
"gate-insights",
|
|
17517
|
+
"gate-learn",
|
|
17518
|
+
"gate-memory",
|
|
17519
|
+
"gate-reflect"
|
|
17520
|
+
]);
|
|
17521
|
+
function isVerityOwned(path) {
|
|
17522
|
+
const segments = path.replace(/\\/g, "/").split("/");
|
|
17523
|
+
for (let i = 0; i < segments.length; i++) {
|
|
17524
|
+
const seg = segments[i];
|
|
17525
|
+
if (seg === ".verity" || seg === ".codacy") return true;
|
|
17526
|
+
if (i === segments.length - 1 && (seg === "VERITY.md" || seg === "GATE.md")) return true;
|
|
17527
|
+
if (seg === ".claude" && segments[i + 1] === "skills" && typeof segments[i + 2] === "string") {
|
|
17528
|
+
const skill = segments[i + 2];
|
|
17529
|
+
if (skill.startsWith("verity-") || LEGACY_GATE_SKILLS.has(skill)) return true;
|
|
17530
|
+
}
|
|
17531
|
+
if (seg === ".claude" && segments[i + 1] === "settings.json") return true;
|
|
17532
|
+
}
|
|
17533
|
+
return false;
|
|
17534
|
+
}
|
|
17535
|
+
function partitionVerityOwned(paths) {
|
|
17536
|
+
const kept = [];
|
|
17537
|
+
const owned = [];
|
|
17538
|
+
for (const p of paths) (isVerityOwned(p) ? owned : kept).push(p);
|
|
17539
|
+
return { kept, owned };
|
|
17540
|
+
}
|
|
17541
|
+
|
|
17149
17542
|
// src/lib/channel.ts
|
|
17150
17543
|
var MAX_AGENT_CONTEXT_CHARS = 1500;
|
|
17151
17544
|
var MAX_AGENT_ITEMS = 5;
|
|
@@ -17155,6 +17548,29 @@ function renderItem(label2, text, patternId, file, line) {
|
|
|
17155
17548
|
const id = patternId ? ` [${patternId}]` : "";
|
|
17156
17549
|
return `- ${label2}${text}${where}${id}`;
|
|
17157
17550
|
}
|
|
17551
|
+
function channelInputFrom(response, intentRepeat = 0, priorPendingFingerprints = []) {
|
|
17552
|
+
const metadata = response.metadata ?? {};
|
|
17553
|
+
const intent = response.intent_alignment ?? {};
|
|
17554
|
+
return {
|
|
17555
|
+
intentRepeat,
|
|
17556
|
+
priorPendingFingerprints,
|
|
17557
|
+
gateDecision: String(response.gate_decision ?? ""),
|
|
17558
|
+
findings: response.findings ?? [],
|
|
17559
|
+
pendingItems: response.pending_items ?? [],
|
|
17560
|
+
reviewStatus: metadata.review_status,
|
|
17561
|
+
coverage: metadata.coverage,
|
|
17562
|
+
intentVerdict: intent.verdict,
|
|
17563
|
+
intentGaps: intent.gaps
|
|
17564
|
+
};
|
|
17565
|
+
}
|
|
17566
|
+
function classifyChannelContent(input) {
|
|
17567
|
+
const refusal = input.reviewStatus === "not_reviewed" || input.reviewStatus === "no_authorship_evidence";
|
|
17568
|
+
const intentFlag = input.intentVerdict === "misaligned" || input.intentVerdict === "partial";
|
|
17569
|
+
const advisory = (input.findings ?? []).some((f) => f.scope !== "pre-existing") || (input.pendingItems ?? []).some(
|
|
17570
|
+
(p) => p.pattern_id !== "intent-misalignment" && !!(p.description ?? p.title ?? p.reason)
|
|
17571
|
+
);
|
|
17572
|
+
return { refusal, intentFlag, advisory };
|
|
17573
|
+
}
|
|
17158
17574
|
function buildAgentContext(input) {
|
|
17159
17575
|
const lines = [];
|
|
17160
17576
|
if (input.reviewStatus === "not_reviewed") {
|
|
@@ -17240,7 +17656,7 @@ function channelSilence(input) {
|
|
|
17240
17656
|
// src/lib/cli-version.ts
|
|
17241
17657
|
function cliVersion() {
|
|
17242
17658
|
try {
|
|
17243
|
-
return true ? "0.
|
|
17659
|
+
return true ? "0.30.0-experimental.452ead4" : "dev";
|
|
17244
17660
|
} catch {
|
|
17245
17661
|
return "dev";
|
|
17246
17662
|
}
|
|
@@ -17280,8 +17696,8 @@ async function sendSkipBeacon(ctx, reason) {
|
|
|
17280
17696
|
}
|
|
17281
17697
|
|
|
17282
17698
|
// src/lib/static-analysis.ts
|
|
17283
|
-
var
|
|
17284
|
-
var
|
|
17699
|
+
var import_node_child_process8 = require("node:child_process");
|
|
17700
|
+
var import_node_fs22 = require("node:fs");
|
|
17285
17701
|
var SEVERITY_ORDER = {
|
|
17286
17702
|
Error: 0,
|
|
17287
17703
|
Critical: 0,
|
|
@@ -17293,7 +17709,7 @@ var SEVERITY_ORDER = {
|
|
|
17293
17709
|
};
|
|
17294
17710
|
function isCodacyAvailable() {
|
|
17295
17711
|
try {
|
|
17296
|
-
(0,
|
|
17712
|
+
(0, import_node_child_process8.execSync)("which codacy-analysis", { stdio: "pipe" });
|
|
17297
17713
|
return true;
|
|
17298
17714
|
} catch {
|
|
17299
17715
|
return false;
|
|
@@ -17329,13 +17745,13 @@ function runCodacyAnalysis(files) {
|
|
|
17329
17745
|
if (files.length === 0) return empty;
|
|
17330
17746
|
const existingFiles = files.filter((f) => {
|
|
17331
17747
|
try {
|
|
17332
|
-
return (0,
|
|
17748
|
+
return (0, import_node_fs22.existsSync)(f);
|
|
17333
17749
|
} catch {
|
|
17334
17750
|
return false;
|
|
17335
17751
|
}
|
|
17336
17752
|
});
|
|
17337
17753
|
if (existingFiles.length === 0) return empty;
|
|
17338
|
-
const proc = (0,
|
|
17754
|
+
const proc = (0, import_node_child_process8.spawnSync)("codacy-analysis", buildAnalyzerArgv(existingFiles), {
|
|
17339
17755
|
encoding: "utf-8",
|
|
17340
17756
|
maxBuffer: 10 * 1024 * 1024
|
|
17341
17757
|
});
|
|
@@ -17562,9 +17978,10 @@ async function scope(run) {
|
|
|
17562
17978
|
const { assistantResponse } = run;
|
|
17563
17979
|
const { files: allChanged, hasRecentCommitFiles } = getChangedFiles();
|
|
17564
17980
|
run.changedUniverse = allChanged;
|
|
17565
|
-
const
|
|
17566
|
-
const
|
|
17567
|
-
const
|
|
17981
|
+
const { kept: external } = partitionVerityOwned(allChanged);
|
|
17982
|
+
const analyzable = filterAnalyzable(external);
|
|
17983
|
+
const reviewable = filterReviewable(external);
|
|
17984
|
+
const securityFiles = filterSecurity(external);
|
|
17568
17985
|
const noFilesChanged = analyzable.length === 0 && reviewable.length === 0 && securityFiles.length === 0;
|
|
17569
17986
|
if (noFilesChanged && !assistantResponse) {
|
|
17570
17987
|
await passAndExit(run, "No analyzable files changed", "no-analyzable-files");
|
|
@@ -17574,8 +17991,8 @@ async function scope(run) {
|
|
|
17574
17991
|
}
|
|
17575
17992
|
|
|
17576
17993
|
// src/lib/specs.ts
|
|
17577
|
-
var
|
|
17578
|
-
var
|
|
17994
|
+
var import_node_fs23 = require("node:fs");
|
|
17995
|
+
var import_node_path20 = require("node:path");
|
|
17579
17996
|
var SPEC_CANDIDATES = [
|
|
17580
17997
|
"CLAUDE.md",
|
|
17581
17998
|
"AGENTS.md",
|
|
@@ -17606,16 +18023,16 @@ function discoverSpecs(consulted = []) {
|
|
|
17606
18023
|
const totalCap = relevant ? MAX_TOTAL_SPEC_BYTES : UNCONSULTED_TOTAL_BYTES;
|
|
17607
18024
|
if (totalBytes >= totalCap) return false;
|
|
17608
18025
|
if (seen.has(specPath)) return true;
|
|
17609
|
-
if (!(0,
|
|
18026
|
+
if (!(0, import_node_fs23.existsSync)(specPath)) return true;
|
|
17610
18027
|
seen.add(specPath);
|
|
17611
18028
|
const remaining = totalCap - totalBytes;
|
|
17612
18029
|
const fileCap = relevant ? MAX_SPEC_FILE_BYTES : UNCONSULTED_FILE_BYTES;
|
|
17613
18030
|
const readBytes = Math.min(fileCap, remaining);
|
|
17614
18031
|
try {
|
|
17615
18032
|
const buf = Buffer.alloc(readBytes);
|
|
17616
|
-
const fd = (0,
|
|
17617
|
-
const bytesRead = (0,
|
|
17618
|
-
(0,
|
|
18033
|
+
const fd = (0, import_node_fs23.openSync)(specPath, "r");
|
|
18034
|
+
const bytesRead = (0, import_node_fs23.readSync)(fd, buf, 0, readBytes, 0);
|
|
18035
|
+
(0, import_node_fs23.closeSync)(fd);
|
|
17619
18036
|
const content = buf.slice(0, bytesRead).toString("utf-8");
|
|
17620
18037
|
if (!content) return true;
|
|
17621
18038
|
result.push({ path: specPath, content });
|
|
@@ -17631,7 +18048,7 @@ function discoverSpecs(consulted = []) {
|
|
|
17631
18048
|
if (!addSpec(candidate)) break;
|
|
17632
18049
|
}
|
|
17633
18050
|
for (const dir of ["spec", "docs"]) {
|
|
17634
|
-
if (!(0,
|
|
18051
|
+
if (!(0, import_node_fs23.existsSync)(dir)) continue;
|
|
17635
18052
|
try {
|
|
17636
18053
|
const mdFiles = findMdFiles(dir, 2).sort();
|
|
17637
18054
|
for (const mdFile of mdFiles) {
|
|
@@ -17646,9 +18063,9 @@ function findMdFiles(dir, maxDepth, depth = 0) {
|
|
|
17646
18063
|
if (depth >= maxDepth) return [];
|
|
17647
18064
|
const result = [];
|
|
17648
18065
|
try {
|
|
17649
|
-
const entries = (0,
|
|
18066
|
+
const entries = (0, import_node_fs23.readdirSync)(dir, { withFileTypes: true });
|
|
17650
18067
|
for (const entry of entries) {
|
|
17651
|
-
const fullPath = (0,
|
|
18068
|
+
const fullPath = (0, import_node_path20.join)(dir, entry.name);
|
|
17652
18069
|
if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
17653
18070
|
result.push(fullPath);
|
|
17654
18071
|
} else if (entry.isDirectory() && depth < maxDepth - 1) {
|
|
@@ -17660,19 +18077,19 @@ function findMdFiles(dir, maxDepth, depth = 0) {
|
|
|
17660
18077
|
return result;
|
|
17661
18078
|
}
|
|
17662
18079
|
function discoverPlans() {
|
|
17663
|
-
const homePlansDir = (0,
|
|
18080
|
+
const homePlansDir = (0, import_node_path20.join)(process.env.HOME ?? "", ".claude", "plans");
|
|
17664
18081
|
const localPlansDir = ".claude/plans";
|
|
17665
18082
|
const candidates = [];
|
|
17666
18083
|
const seen = /* @__PURE__ */ new Set();
|
|
17667
18084
|
for (const plansDir of [localPlansDir, homePlansDir]) {
|
|
17668
|
-
if (!(0,
|
|
18085
|
+
if (!(0, import_node_fs23.existsSync)(plansDir)) continue;
|
|
17669
18086
|
try {
|
|
17670
|
-
for (const f of (0,
|
|
18087
|
+
for (const f of (0, import_node_fs23.readdirSync)(plansDir)) {
|
|
17671
18088
|
if (!f.endsWith(".md") || seen.has(f)) continue;
|
|
17672
18089
|
seen.add(f);
|
|
17673
|
-
const fullPath = (0,
|
|
18090
|
+
const fullPath = (0, import_node_path20.join)(plansDir, f);
|
|
17674
18091
|
try {
|
|
17675
|
-
const stat3 = (0,
|
|
18092
|
+
const stat3 = (0, import_node_fs23.statSync)(fullPath);
|
|
17676
18093
|
candidates.push({ name: f, path: fullPath, mtime: stat3.mtimeMs, size: stat3.size });
|
|
17677
18094
|
} catch {
|
|
17678
18095
|
}
|
|
@@ -17685,7 +18102,7 @@ function discoverPlans() {
|
|
|
17685
18102
|
for (const entry of candidates.slice(0, MAX_PLAN_FILES)) {
|
|
17686
18103
|
if (entry.size > MAX_PLAN_FILE_BYTES) continue;
|
|
17687
18104
|
try {
|
|
17688
|
-
const content = (0,
|
|
18105
|
+
const content = (0, import_node_fs23.readFileSync)(entry.path, "utf-8");
|
|
17689
18106
|
result.push({ name: entry.name, content });
|
|
17690
18107
|
} catch {
|
|
17691
18108
|
}
|
|
@@ -17960,7 +18377,7 @@ async function mode(run) {
|
|
|
17960
18377
|
}
|
|
17961
18378
|
|
|
17962
18379
|
// src/lib/debounce.ts
|
|
17963
|
-
var
|
|
18380
|
+
var import_node_fs24 = require("node:fs");
|
|
17964
18381
|
var import_node_crypto10 = require("node:crypto");
|
|
17965
18382
|
function scopedFile(base, sessionId) {
|
|
17966
18383
|
if (!sessionId) return base;
|
|
@@ -17968,9 +18385,9 @@ function scopedFile(base, sessionId) {
|
|
|
17968
18385
|
}
|
|
17969
18386
|
function checkDebounce(debounceSeconds = DEBOUNCE_SECONDS, sessionId) {
|
|
17970
18387
|
const file = scopedFile(DEBOUNCE_FILE, sessionId);
|
|
17971
|
-
if (!(0,
|
|
18388
|
+
if (!(0, import_node_fs24.existsSync)(file)) return null;
|
|
17972
18389
|
try {
|
|
17973
|
-
const lastTs = parseInt((0,
|
|
18390
|
+
const lastTs = parseInt((0, import_node_fs24.readFileSync)(file, "utf-8").trim(), 10);
|
|
17974
18391
|
const nowTs = Math.floor(Date.now() / 1e3);
|
|
17975
18392
|
const elapsed = nowTs - lastTs;
|
|
17976
18393
|
if (elapsed < debounceSeconds) {
|
|
@@ -17983,10 +18400,10 @@ function checkDebounce(debounceSeconds = DEBOUNCE_SECONDS, sessionId) {
|
|
|
17983
18400
|
function checkMtime(files, bypassForRecentCommits, sessionId) {
|
|
17984
18401
|
if (bypassForRecentCommits) return null;
|
|
17985
18402
|
const file = scopedFile(DEBOUNCE_FILE, sessionId);
|
|
17986
|
-
if (!(0,
|
|
18403
|
+
if (!(0, import_node_fs24.existsSync)(file)) return null;
|
|
17987
18404
|
let debounceTime;
|
|
17988
18405
|
try {
|
|
17989
|
-
debounceTime = (0,
|
|
18406
|
+
debounceTime = (0, import_node_fs24.statSync)(file).mtimeMs;
|
|
17990
18407
|
} catch {
|
|
17991
18408
|
return null;
|
|
17992
18409
|
}
|
|
@@ -17994,7 +18411,7 @@ function checkMtime(files, bypassForRecentCommits, sessionId) {
|
|
|
17994
18411
|
const resolved = resolveFile(f);
|
|
17995
18412
|
if (!resolved) continue;
|
|
17996
18413
|
try {
|
|
17997
|
-
const stat3 = (0,
|
|
18414
|
+
const stat3 = (0, import_node_fs24.statSync)(resolved);
|
|
17998
18415
|
if (stat3.mtimeMs > debounceTime) {
|
|
17999
18416
|
return null;
|
|
18000
18417
|
}
|
|
@@ -18010,8 +18427,8 @@ function computeContentHash(files) {
|
|
|
18010
18427
|
for (const f of sorted) {
|
|
18011
18428
|
const resolved = resolveFile(f) ?? f;
|
|
18012
18429
|
try {
|
|
18013
|
-
if ((0,
|
|
18014
|
-
hash.update((0,
|
|
18430
|
+
if ((0, import_node_fs24.existsSync)(resolved)) {
|
|
18431
|
+
hash.update((0, import_node_fs24.readFileSync)(resolved));
|
|
18015
18432
|
}
|
|
18016
18433
|
} catch {
|
|
18017
18434
|
}
|
|
@@ -18021,9 +18438,9 @@ function computeContentHash(files) {
|
|
|
18021
18438
|
function checkContentHash(files, sessionId) {
|
|
18022
18439
|
const hash = computeContentHash(files);
|
|
18023
18440
|
const file = scopedFile(HASH_FILE, sessionId);
|
|
18024
|
-
if ((0,
|
|
18441
|
+
if ((0, import_node_fs24.existsSync)(file)) {
|
|
18025
18442
|
try {
|
|
18026
|
-
const storedHash = (0,
|
|
18443
|
+
const storedHash = (0, import_node_fs24.readFileSync)(file, "utf-8").trim();
|
|
18027
18444
|
if (hash === storedHash) {
|
|
18028
18445
|
return { skip: "No source changes since last analysis", hash };
|
|
18029
18446
|
}
|
|
@@ -18033,50 +18450,74 @@ function checkContentHash(files, sessionId) {
|
|
|
18033
18450
|
return { skip: null, hash };
|
|
18034
18451
|
}
|
|
18035
18452
|
function recordAnalysisStart(sessionId) {
|
|
18036
|
-
(0,
|
|
18037
|
-
(0,
|
|
18453
|
+
(0, import_node_fs24.mkdirSync)(VERITY_DIR, { recursive: true });
|
|
18454
|
+
(0, import_node_fs24.writeFileSync)(scopedFile(DEBOUNCE_FILE, sessionId), String(Math.floor(Date.now() / 1e3)));
|
|
18038
18455
|
}
|
|
18039
18456
|
function recordPassHash(hash, sessionId) {
|
|
18040
|
-
(0,
|
|
18457
|
+
(0, import_node_fs24.writeFileSync)(scopedFile(HASH_FILE, sessionId), hash);
|
|
18041
18458
|
}
|
|
18042
18459
|
function narrowToRecent(files, sessionId) {
|
|
18043
18460
|
const file = scopedFile(DEBOUNCE_FILE, sessionId);
|
|
18044
|
-
if (!(0,
|
|
18461
|
+
if (!(0, import_node_fs24.existsSync)(file)) return files;
|
|
18045
18462
|
let debounceTime;
|
|
18046
18463
|
try {
|
|
18047
|
-
debounceTime = (0,
|
|
18464
|
+
debounceTime = (0, import_node_fs24.statSync)(file).mtimeMs;
|
|
18048
18465
|
} catch {
|
|
18049
18466
|
return files;
|
|
18050
18467
|
}
|
|
18051
18468
|
const recent = files.filter((f) => {
|
|
18052
18469
|
try {
|
|
18053
|
-
return (0,
|
|
18470
|
+
return (0, import_node_fs24.existsSync)(f) && (0, import_node_fs24.statSync)(f).mtimeMs > debounceTime;
|
|
18054
18471
|
} catch {
|
|
18055
18472
|
return false;
|
|
18056
18473
|
}
|
|
18057
18474
|
});
|
|
18058
18475
|
return recent.length > 0 ? recent : files;
|
|
18059
18476
|
}
|
|
18060
|
-
function
|
|
18061
|
-
|
|
18477
|
+
function readIteration(currentCommit, _contentHash) {
|
|
18478
|
+
return Math.max(1, readBlockState(currentCommit).attempts);
|
|
18479
|
+
}
|
|
18480
|
+
var NO_BLOCKS = { attempts: 0, blocks: 0, fingerprint: null };
|
|
18481
|
+
function readBlockState(currentCommit, opts) {
|
|
18482
|
+
if (opts?.newUserPrompt) return NO_BLOCKS;
|
|
18483
|
+
if (!(0, import_node_fs24.existsSync)(ITERATION_FILE)) return NO_BLOCKS;
|
|
18062
18484
|
try {
|
|
18063
|
-
const stored = (0,
|
|
18064
|
-
const
|
|
18065
|
-
|
|
18066
|
-
|
|
18067
|
-
|
|
18068
|
-
|
|
18069
|
-
if (isNaN(iter)) return { iteration: 1, fingerprint: null };
|
|
18070
|
-
if (storedCommit !== currentCommit) return { iteration: 1, fingerprint: null };
|
|
18071
|
-
if (storedTimestamp > 0) {
|
|
18072
|
-
const elapsed = Math.floor(Date.now() / 1e3) - storedTimestamp;
|
|
18073
|
-
if (elapsed > 600) return { iteration: 1, fingerprint: null };
|
|
18074
|
-
}
|
|
18075
|
-
return { iteration: iter, fingerprint };
|
|
18485
|
+
const stored = (0, import_node_fs24.readFileSync)(ITERATION_FILE, "utf-8").trim();
|
|
18486
|
+
const parsed = stored.startsWith("{") ? parseJsonState(stored) : parseLegacyState(stored);
|
|
18487
|
+
if (!parsed) return NO_BLOCKS;
|
|
18488
|
+
if (parsed.commit !== currentCommit) return NO_BLOCKS;
|
|
18489
|
+
if (parsed.ts > 0 && Math.floor(Date.now() / 1e3) - parsed.ts > 600) return NO_BLOCKS;
|
|
18490
|
+
return { attempts: parsed.attempts, blocks: parsed.blocks, fingerprint: parsed.fingerprint };
|
|
18076
18491
|
} catch {
|
|
18077
|
-
return
|
|
18492
|
+
return NO_BLOCKS;
|
|
18078
18493
|
}
|
|
18079
18494
|
}
|
|
18495
|
+
function parseJsonState(raw) {
|
|
18496
|
+
const o = JSON.parse(raw);
|
|
18497
|
+
const attempts = typeof o.attempts === "number" ? o.attempts : NaN;
|
|
18498
|
+
if (isNaN(attempts)) return null;
|
|
18499
|
+
return {
|
|
18500
|
+
attempts,
|
|
18501
|
+
blocks: typeof o.blocks === "number" ? o.blocks : attempts,
|
|
18502
|
+
fingerprint: typeof o.fingerprint === "string" && o.fingerprint ? o.fingerprint : null,
|
|
18503
|
+
commit: typeof o.commit === "string" ? o.commit : "",
|
|
18504
|
+
ts: typeof o.ts === "number" ? o.ts : 0
|
|
18505
|
+
};
|
|
18506
|
+
}
|
|
18507
|
+
function parseLegacyState(raw) {
|
|
18508
|
+
const parts = raw.split(":");
|
|
18509
|
+
const n = parseInt(parts[0], 10);
|
|
18510
|
+
if (isNaN(n)) return null;
|
|
18511
|
+
return {
|
|
18512
|
+
attempts: n,
|
|
18513
|
+
// The old file has no separate block count; the old counter is the closest
|
|
18514
|
+
// honest answer, and it errs toward releasing sooner rather than later.
|
|
18515
|
+
blocks: n,
|
|
18516
|
+
fingerprint: parts.slice(3).join(":") || null,
|
|
18517
|
+
commit: parts[1] ?? "",
|
|
18518
|
+
ts: parseInt(parts[2] ?? "0", 10)
|
|
18519
|
+
};
|
|
18520
|
+
}
|
|
18080
18521
|
function findingsFingerprint(findings) {
|
|
18081
18522
|
const keys = findings.map((f) => `${String(f.pattern_id ?? "?")}|${String(f.file ?? "?")}`).filter((k) => k !== "?|?");
|
|
18082
18523
|
return [...new Set(keys)].sort().join(",");
|
|
@@ -18086,16 +18527,27 @@ function isSameProblem(previous, current) {
|
|
|
18086
18527
|
const prev = new Set(previous.split(","));
|
|
18087
18528
|
return current.split(",").some((k) => prev.has(k));
|
|
18088
18529
|
}
|
|
18089
|
-
function
|
|
18090
|
-
(0,
|
|
18091
|
-
|
|
18092
|
-
|
|
18093
|
-
|
|
18530
|
+
function writeBlockState(commit, state) {
|
|
18531
|
+
(0, import_node_fs24.mkdirSync)(VERITY_DIR, { recursive: true });
|
|
18532
|
+
(0, import_node_fs24.writeFileSync)(
|
|
18533
|
+
ITERATION_FILE,
|
|
18534
|
+
JSON.stringify({
|
|
18535
|
+
v: 2,
|
|
18536
|
+
attempts: state.attempts,
|
|
18537
|
+
blocks: state.blocks,
|
|
18538
|
+
commit,
|
|
18539
|
+
ts: Math.floor(Date.now() / 1e3),
|
|
18540
|
+
fingerprint: state.fingerprint ?? void 0
|
|
18541
|
+
})
|
|
18542
|
+
);
|
|
18543
|
+
}
|
|
18544
|
+
function resetBlockState(commit) {
|
|
18545
|
+
writeBlockState(commit, { attempts: 0, blocks: 0, fingerprint: null });
|
|
18094
18546
|
}
|
|
18095
18547
|
|
|
18096
18548
|
// src/lib/fold.ts
|
|
18097
|
-
var
|
|
18098
|
-
var
|
|
18549
|
+
var import_node_fs25 = require("node:fs");
|
|
18550
|
+
var import_node_path21 = require("node:path");
|
|
18099
18551
|
var KNOWN_RECORD_TYPES = /* @__PURE__ */ new Set([
|
|
18100
18552
|
"user",
|
|
18101
18553
|
"assistant",
|
|
@@ -18133,7 +18585,7 @@ var COMMAND_CLASSES = [
|
|
|
18133
18585
|
[/\btsc\b|\bmypy\b|\btypecheck\b/, "typecheck"],
|
|
18134
18586
|
[/^git\s/, "git"]
|
|
18135
18587
|
];
|
|
18136
|
-
function
|
|
18588
|
+
function classifyCommand2(cmd) {
|
|
18137
18589
|
for (const [re, cls] of COMMAND_CLASSES) if (re.test(cmd)) return cls;
|
|
18138
18590
|
return "other";
|
|
18139
18591
|
}
|
|
@@ -18232,7 +18684,7 @@ function candidateRoots(repoRoot2) {
|
|
|
18232
18684
|
const norm = repoRoot2.replace(/\\/g, "/").replace(/\/+$/, "");
|
|
18233
18685
|
const out = [norm];
|
|
18234
18686
|
try {
|
|
18235
|
-
const real =
|
|
18687
|
+
const real = import_node_fs25.realpathSync.native(norm).replace(/\\/g, "/").replace(/\/+$/, "");
|
|
18236
18688
|
if (real !== norm) out.push(real);
|
|
18237
18689
|
} catch {
|
|
18238
18690
|
}
|
|
@@ -18282,8 +18734,10 @@ function fold(transcriptPath, opts = {}) {
|
|
|
18282
18734
|
subagentSkipped: 0,
|
|
18283
18735
|
compactions: 0,
|
|
18284
18736
|
complete: false
|
|
18285
|
-
}
|
|
18737
|
+
},
|
|
18738
|
+
planApproval: { approvals: 0, activeSinceLastPrompt: false }
|
|
18286
18739
|
};
|
|
18740
|
+
const flow = { seq: 0, lastPrompt: -1, lastApproval: -1, approvals: 0 };
|
|
18287
18741
|
const byPath = /* @__PURE__ */ new Map();
|
|
18288
18742
|
const commandStats = /* @__PURE__ */ new Map();
|
|
18289
18743
|
const pendingByToolUse = /* @__PURE__ */ new Map();
|
|
@@ -18309,36 +18763,40 @@ function fold(transcriptPath, opts = {}) {
|
|
|
18309
18763
|
if (type === "system" && record.subtype === "compact_boundary") {
|
|
18310
18764
|
result.coverage.compactions++;
|
|
18311
18765
|
}
|
|
18312
|
-
if (type === "user" && hasUserText(record))
|
|
18313
|
-
|
|
18766
|
+
if (type === "user" && hasUserText(record)) {
|
|
18767
|
+
result.coverage.userMessages++;
|
|
18768
|
+
if (owner === "agent") flow.lastPrompt = flow.seq;
|
|
18769
|
+
}
|
|
18770
|
+
if (owner === "agent") flow.seq++;
|
|
18771
|
+
collectFromRecord(record, owner, byPath, commandStats, pendingByToolUse, toolStats, pendingToolName, taskById, pendingTaskName, opts.repoRoot, result.coverage, flow);
|
|
18314
18772
|
}
|
|
18315
18773
|
};
|
|
18316
18774
|
try {
|
|
18317
|
-
if (!(0,
|
|
18318
|
-
ingest((0,
|
|
18775
|
+
if (!(0, import_node_fs25.existsSync)(transcriptPath)) return result;
|
|
18776
|
+
ingest((0, import_node_fs25.readFileSync)(transcriptPath, "utf8"), "agent");
|
|
18319
18777
|
result.coverage.complete = true;
|
|
18320
18778
|
} catch {
|
|
18321
18779
|
return result;
|
|
18322
18780
|
}
|
|
18323
18781
|
try {
|
|
18324
|
-
const sidecarDir = (0,
|
|
18325
|
-
(0,
|
|
18326
|
-
(0,
|
|
18782
|
+
const sidecarDir = (0, import_node_path21.join)(
|
|
18783
|
+
(0, import_node_path21.dirname)(transcriptPath),
|
|
18784
|
+
(0, import_node_path21.basename)(transcriptPath).replace(/\.jsonl$/, ""),
|
|
18327
18785
|
"subagents"
|
|
18328
18786
|
);
|
|
18329
|
-
if ((0,
|
|
18787
|
+
if ((0, import_node_fs25.existsSync)(sidecarDir)) {
|
|
18330
18788
|
const maxFiles = opts.maxSidecars ?? 200;
|
|
18331
18789
|
const maxBytes = opts.maxSidecarBytes ?? 16 * 1024 * 1024;
|
|
18332
18790
|
const found = [];
|
|
18333
18791
|
const walk = (d, depth) => {
|
|
18334
18792
|
if (depth > 4) return;
|
|
18335
|
-
for (const e of (0,
|
|
18336
|
-
const p = (0,
|
|
18793
|
+
for (const e of (0, import_node_fs25.readdirSync)(d, { withFileTypes: true })) {
|
|
18794
|
+
const p = (0, import_node_path21.join)(d, e.name);
|
|
18337
18795
|
if (e.isDirectory()) {
|
|
18338
18796
|
walk(p, depth + 1);
|
|
18339
18797
|
} else if (e.name.startsWith("agent-") && e.name.endsWith(".jsonl")) {
|
|
18340
18798
|
try {
|
|
18341
|
-
const st = (0,
|
|
18799
|
+
const st = (0, import_node_fs25.statSync)(p);
|
|
18342
18800
|
found.push({ path: p, size: st.size, mtimeMs: st.mtimeMs });
|
|
18343
18801
|
} catch {
|
|
18344
18802
|
result.coverage.malformed++;
|
|
@@ -18355,7 +18813,7 @@ function fold(transcriptPath, opts = {}) {
|
|
|
18355
18813
|
continue;
|
|
18356
18814
|
}
|
|
18357
18815
|
try {
|
|
18358
|
-
ingest((0,
|
|
18816
|
+
ingest((0, import_node_fs25.readFileSync)(f.path, "utf8"), "subagent");
|
|
18359
18817
|
bytes += f.size;
|
|
18360
18818
|
result.coverage.subagentFiles++;
|
|
18361
18819
|
} catch {
|
|
@@ -18382,11 +18840,15 @@ function fold(transcriptPath, opts = {}) {
|
|
|
18382
18840
|
if (!p || authoredPaths.has(p)) continue;
|
|
18383
18841
|
result.unobserved.push({ p, cause: classifyUnobserved(raw) });
|
|
18384
18842
|
}
|
|
18843
|
+
result.planApproval = {
|
|
18844
|
+
approvals: flow.approvals,
|
|
18845
|
+
activeSinceLastPrompt: flow.lastApproval >= 0 && flow.lastApproval > flow.lastPrompt
|
|
18846
|
+
};
|
|
18385
18847
|
return result;
|
|
18386
18848
|
}
|
|
18387
18849
|
function classifyUnobserved(path) {
|
|
18388
18850
|
try {
|
|
18389
|
-
const st = (0,
|
|
18851
|
+
const st = (0, import_node_fs25.statSync)(path);
|
|
18390
18852
|
if (!st.isFile()) return "unreadable";
|
|
18391
18853
|
} catch {
|
|
18392
18854
|
return "unreadable";
|
|
@@ -18394,7 +18856,7 @@ function classifyUnobserved(path) {
|
|
|
18394
18856
|
if (/\.(png|jpg|jpeg|gif|pdf|zip|woff2?|ico|mp4)$/i.test(path)) return "binary";
|
|
18395
18857
|
return "no_edit_record";
|
|
18396
18858
|
}
|
|
18397
|
-
function collectFromRecord(record, owner, byPath, commandStats, pendingByToolUse, toolStats, pendingToolName, taskById, pendingTaskName, repoRoot2, tally) {
|
|
18859
|
+
function collectFromRecord(record, owner, byPath, commandStats, pendingByToolUse, toolStats, pendingToolName, taskById, pendingTaskName, repoRoot2, tally, flow) {
|
|
18398
18860
|
const message = record.message;
|
|
18399
18861
|
const content = message?.content ?? record.content;
|
|
18400
18862
|
const blocks = Array.isArray(content) ? content : content && typeof content === "object" ? [content] : [];
|
|
@@ -18452,7 +18914,7 @@ function collectFromRecord(record, owner, byPath, commandStats, pendingByToolUse
|
|
|
18452
18914
|
if (name === "Bash") {
|
|
18453
18915
|
const cmd = typeof input.command === "string" ? input.command : "";
|
|
18454
18916
|
if (cmd) {
|
|
18455
|
-
const cls =
|
|
18917
|
+
const cls = classifyCommand2(cmd);
|
|
18456
18918
|
const prev = commandStats.get(cls) ?? { last_status: null, runs: 0, head: "" };
|
|
18457
18919
|
commandStats.set(cls, {
|
|
18458
18920
|
// UNKNOWN until this command's OWN result arrives. Inheriting the
|
|
@@ -18478,6 +18940,13 @@ function collectFromRecord(record, owner, byPath, commandStats, pendingByToolUse
|
|
|
18478
18940
|
}
|
|
18479
18941
|
}
|
|
18480
18942
|
const toolName = id ? pendingToolName.get(id) : void 0;
|
|
18943
|
+
if (toolName === "ExitPlanMode" && flow && block.is_error !== true) {
|
|
18944
|
+
const body = typeof block.content === "string" ? block.content : Array.isArray(block.content) ? block.content.map((c) => typeof c.text === "string" ? c.text : "").join(" ") : "";
|
|
18945
|
+
if (/approved your plan/i.test(body)) {
|
|
18946
|
+
flow.lastApproval = flow.seq;
|
|
18947
|
+
flow.approvals += 1;
|
|
18948
|
+
}
|
|
18949
|
+
}
|
|
18481
18950
|
if (toolName) {
|
|
18482
18951
|
pendingToolName.delete(id);
|
|
18483
18952
|
const prevTool = toolStats.get(toolName);
|
|
@@ -18535,8 +19004,13 @@ function checkConservation(changedFiles, result, repoRoot2) {
|
|
|
18535
19004
|
// src/commands/analyze/phases/06-evidence.ts
|
|
18536
19005
|
async function evidence(run) {
|
|
18537
19006
|
const { opts } = run;
|
|
18538
|
-
const { actionSummary, allForReview, analyzable, assistantResponse, authorshipIsObservable, baseline, baselineSessionId, hasRecentCommitFiles, reviewable, securityFiles, sessionAuthoredCode, transcriptPath } = run;
|
|
19007
|
+
const { actionSummary, allForReview, analyzable, assistantResponse, authorshipIsObservable, baseline, baselineSessionId, hasRecentCommitFiles, reviewable, securityFiles, sessionAuthoredCode, transcriptPath, turnAuthoredCode } = run;
|
|
18539
19008
|
let { analysisMode, earlyFold } = run;
|
|
19009
|
+
const recordFlip = (stage) => {
|
|
19010
|
+
if (run.modeDecision) run.modeDecision = { ...run.modeDecision, resolved: "plan", flip: stage };
|
|
19011
|
+
logEvent("mode_flipped", { stage, to: "plan" });
|
|
19012
|
+
};
|
|
19013
|
+
const planWorthy = !!assistantResponse && !turnAuthoredCode;
|
|
18540
19014
|
let staticResults = {
|
|
18541
19015
|
tool: "@codacy/analysis-cli",
|
|
18542
19016
|
findings: [],
|
|
@@ -18556,8 +19030,9 @@ async function evidence(run) {
|
|
|
18556
19030
|
const debounceSeconds = parseInt(opts.debounce, 10);
|
|
18557
19031
|
const debounceSkip = checkDebounce(debounceSeconds, baselineSessionId);
|
|
18558
19032
|
if (debounceSkip) {
|
|
18559
|
-
if (
|
|
19033
|
+
if (planWorthy) {
|
|
18560
19034
|
analysisMode = "plan";
|
|
19035
|
+
recordFlip("debounce");
|
|
18561
19036
|
} else {
|
|
18562
19037
|
await passAndExit(run, debounceSkip, "debounce");
|
|
18563
19038
|
}
|
|
@@ -18566,8 +19041,9 @@ async function evidence(run) {
|
|
|
18566
19041
|
const allCheckable = Array.from(/* @__PURE__ */ new Set([...analyzable, ...reviewable, ...securityFiles]));
|
|
18567
19042
|
const mtimeSkip = checkMtime(allCheckable, hasRecentCommitFiles, baselineSessionId);
|
|
18568
19043
|
if (mtimeSkip) {
|
|
18569
|
-
if (
|
|
19044
|
+
if (planWorthy) {
|
|
18570
19045
|
analysisMode = "plan";
|
|
19046
|
+
recordFlip("mtime");
|
|
18571
19047
|
} else {
|
|
18572
19048
|
await passAndExit(run, mtimeSkip, "no-delta-since-last-review");
|
|
18573
19049
|
}
|
|
@@ -18578,8 +19054,9 @@ async function evidence(run) {
|
|
|
18578
19054
|
const allCheckable = Array.from(/* @__PURE__ */ new Set([...analyzable, ...reviewable, ...securityFiles]));
|
|
18579
19055
|
const hashResult = checkContentHash(allCheckable, baselineSessionId);
|
|
18580
19056
|
if (hashResult.skip) {
|
|
18581
|
-
if (
|
|
19057
|
+
if (planWorthy) {
|
|
18582
19058
|
analysisMode = "plan";
|
|
19059
|
+
recordFlip("content-hash");
|
|
18583
19060
|
} else {
|
|
18584
19061
|
await passAndExit(run, hashResult.skip, "no-delta-since-last-review");
|
|
18585
19062
|
}
|
|
@@ -18641,8 +19118,9 @@ async function evidence(run) {
|
|
|
18641
19118
|
maxTotalBytes: parseInt(opts.maxTotalSize, 10)
|
|
18642
19119
|
});
|
|
18643
19120
|
if (codeDelta.files.length === 0 && staticResults.findings.length === 0) {
|
|
18644
|
-
if (
|
|
19121
|
+
if (planWorthy) {
|
|
18645
19122
|
analysisMode = "plan";
|
|
19123
|
+
recordFlip("empty-after-scoping");
|
|
18646
19124
|
} else {
|
|
18647
19125
|
await passAndExit(
|
|
18648
19126
|
run,
|
|
@@ -18662,32 +19140,32 @@ async function evidence(run) {
|
|
|
18662
19140
|
snapshotResult = generateSnapshotDiffs(codeDelta.files);
|
|
18663
19141
|
}
|
|
18664
19142
|
currentCommit = getCurrentCommit();
|
|
18665
|
-
iteration =
|
|
19143
|
+
iteration = readIteration(currentCommit);
|
|
18666
19144
|
}
|
|
18667
19145
|
}
|
|
18668
19146
|
if (analysisMode === "plan") {
|
|
18669
19147
|
recordAnalysisStart();
|
|
18670
19148
|
currentCommit = getCurrentCommit();
|
|
18671
|
-
iteration =
|
|
19149
|
+
iteration = readIteration(currentCommit);
|
|
18672
19150
|
}
|
|
18673
19151
|
Object.assign(run, { analysisMode, codeDelta, contentHash, currentCommit, earlyFold, iteration, snapshotResult, staticResults });
|
|
18674
19152
|
}
|
|
18675
19153
|
|
|
18676
19154
|
// src/lib/cache-cleanup.ts
|
|
18677
|
-
var
|
|
18678
|
-
var
|
|
19155
|
+
var import_node_fs26 = require("node:fs");
|
|
19156
|
+
var import_node_path22 = require("node:path");
|
|
18679
19157
|
var CACHE_TTL_DAYS = 7;
|
|
18680
19158
|
function pruneStaleCache() {
|
|
18681
19159
|
try {
|
|
18682
19160
|
const dir = projectPath(CACHE_DIR);
|
|
18683
19161
|
const cutoff = Date.now() - CACHE_TTL_DAYS * 24 * 3600 * 1e3;
|
|
18684
|
-
for (const entry of (0,
|
|
19162
|
+
for (const entry of (0, import_node_fs26.readdirSync)(dir)) {
|
|
18685
19163
|
if (!entry.startsWith("pending-")) continue;
|
|
18686
|
-
const path = (0,
|
|
19164
|
+
const path = (0, import_node_path22.join)(dir, entry);
|
|
18687
19165
|
try {
|
|
18688
|
-
const stat3 = (0,
|
|
19166
|
+
const stat3 = (0, import_node_fs26.statSync)(path);
|
|
18689
19167
|
if (stat3.mtimeMs < cutoff) {
|
|
18690
|
-
(0,
|
|
19168
|
+
(0, import_node_fs26.unlinkSync)(path);
|
|
18691
19169
|
logEvent("cache_entry_pruned", {
|
|
18692
19170
|
path: entry,
|
|
18693
19171
|
age_days: Math.round((Date.now() - stat3.mtimeMs) / 864e5)
|
|
@@ -18701,7 +19179,7 @@ function pruneStaleCache() {
|
|
|
18701
19179
|
}
|
|
18702
19180
|
|
|
18703
19181
|
// src/lib/context-files.ts
|
|
18704
|
-
var
|
|
19182
|
+
var import_node_fs27 = require("node:fs");
|
|
18705
19183
|
var MAX_CONTEXT_FILES = 10;
|
|
18706
19184
|
var MAX_CONTEXT_FILE_BYTES = 10240;
|
|
18707
19185
|
var MAX_CONTEXT_TOTAL_BYTES = 51200;
|
|
@@ -18716,8 +19194,13 @@ function gatherContextFiles(contextPaths, deltaFiles) {
|
|
|
18716
19194
|
logEvent("context_file_skipped", { path: filePath, reason: "verity_owned" });
|
|
18717
19195
|
continue;
|
|
18718
19196
|
}
|
|
19197
|
+
const safePath = resolveInside(process.cwd(), filePath);
|
|
19198
|
+
if (!safePath) {
|
|
19199
|
+
logEvent("context_file_skipped", { path: filePath, reason: "outside_repo" });
|
|
19200
|
+
continue;
|
|
19201
|
+
}
|
|
18719
19202
|
try {
|
|
18720
|
-
const content = (0,
|
|
19203
|
+
const content = (0, import_node_fs27.readFileSync)(safePath, "utf8");
|
|
18721
19204
|
const bytes = Buffer.byteLength(content);
|
|
18722
19205
|
if (bytes > MAX_CONTEXT_FILE_BYTES) {
|
|
18723
19206
|
logEvent("context_file_skipped", { path: filePath, reason: "too_large", bytes });
|
|
@@ -18764,7 +19247,8 @@ function gatherContextFiles(contextPaths, deltaFiles) {
|
|
|
18764
19247
|
// src/commands/analyze/phases/07-context-files.ts
|
|
18765
19248
|
async function contextFiles(run) {
|
|
18766
19249
|
const { codeDelta, contextFilePaths } = run;
|
|
18767
|
-
const
|
|
19250
|
+
const { kept: externalContext } = partitionVerityOwned(contextFilePaths ?? []);
|
|
19251
|
+
const contextFiles2 = gatherContextFiles(externalContext, codeDelta.files);
|
|
18768
19252
|
for (const f of codeDelta.files) {
|
|
18769
19253
|
f.role = "delta";
|
|
18770
19254
|
}
|
|
@@ -18778,8 +19262,8 @@ async function contextFiles(run) {
|
|
|
18778
19262
|
|
|
18779
19263
|
// src/lib/seed-runner.ts
|
|
18780
19264
|
var import_promises11 = require("node:fs/promises");
|
|
18781
|
-
var
|
|
18782
|
-
var
|
|
19265
|
+
var import_node_fs28 = require("node:fs");
|
|
19266
|
+
var import_node_path23 = require("node:path");
|
|
18783
19267
|
var import_yaml2 = __toESM(require_dist());
|
|
18784
19268
|
|
|
18785
19269
|
// src/lib/seed.ts
|
|
@@ -19018,7 +19502,7 @@ function renderNodeMarkdown(candidate, nodeId, createdAt) {
|
|
|
19018
19502
|
return fm;
|
|
19019
19503
|
}
|
|
19020
19504
|
async function runSeed(opts) {
|
|
19021
|
-
if (!(0,
|
|
19505
|
+
if (!(0, import_node_fs28.existsSync)(STANDARD_FILE)) {
|
|
19022
19506
|
return { created: 0, failed: 0, skipped: "no_standard", candidates: [] };
|
|
19023
19507
|
}
|
|
19024
19508
|
let standardDoc;
|
|
@@ -19030,7 +19514,7 @@ async function runSeed(opts) {
|
|
|
19030
19514
|
}
|
|
19031
19515
|
const knowledgeSpec = standardDoc.knowledge_spec ?? {};
|
|
19032
19516
|
let readmeContent;
|
|
19033
|
-
if ((0,
|
|
19517
|
+
if ((0, import_node_fs28.existsSync)("README.md")) {
|
|
19034
19518
|
try {
|
|
19035
19519
|
readmeContent = await (0, import_promises11.readFile)("README.md", "utf-8");
|
|
19036
19520
|
} catch {
|
|
@@ -19038,7 +19522,7 @@ async function runSeed(opts) {
|
|
|
19038
19522
|
}
|
|
19039
19523
|
let claudeMdContent;
|
|
19040
19524
|
for (const p of ["CLAUDE.md", ".claude/CLAUDE.md"]) {
|
|
19041
|
-
if ((0,
|
|
19525
|
+
if ((0, import_node_fs28.existsSync)(p)) {
|
|
19042
19526
|
try {
|
|
19043
19527
|
claudeMdContent = await (0, import_promises11.readFile)(p, "utf-8");
|
|
19044
19528
|
break;
|
|
@@ -19061,8 +19545,8 @@ async function runSeed(opts) {
|
|
|
19061
19545
|
if (candidates.length === 0) {
|
|
19062
19546
|
return { created: 0, failed: 0, skipped: "no_candidates", candidates: [] };
|
|
19063
19547
|
}
|
|
19064
|
-
const overviewPath = (0,
|
|
19065
|
-
if ((0,
|
|
19548
|
+
const overviewPath = (0, import_node_path23.join)(MEMORY_DIR, "domain", "project-overview.md");
|
|
19549
|
+
if ((0, import_node_fs28.existsSync)(overviewPath) && !opts.force) {
|
|
19066
19550
|
return { created: 0, failed: 0, skipped: "already_seeded", candidates };
|
|
19067
19551
|
}
|
|
19068
19552
|
if (opts.dryRun) {
|
|
@@ -19097,9 +19581,14 @@ async function runSeed(opts) {
|
|
|
19097
19581
|
}
|
|
19098
19582
|
const nodeId = res.data.node_id;
|
|
19099
19583
|
const filePathRel = res.data.file_path;
|
|
19100
|
-
const targetPath = (
|
|
19584
|
+
const targetPath = resolveInside(MEMORY_DIR, filePathRel);
|
|
19585
|
+
if (!targetPath) {
|
|
19586
|
+
opts.onFailed?.(c, `Server returned an out-of-bounds file_path (${String(filePathRel)}); refusing to write outside the memory directory.`);
|
|
19587
|
+
failed++;
|
|
19588
|
+
continue;
|
|
19589
|
+
}
|
|
19101
19590
|
try {
|
|
19102
|
-
await (0, import_promises11.mkdir)((0,
|
|
19591
|
+
await (0, import_promises11.mkdir)((0, import_node_path23.dirname)(targetPath), { recursive: true });
|
|
19103
19592
|
await (0, import_promises11.writeFile)(targetPath, renderNodeMarkdown(c, nodeId, createdAt));
|
|
19104
19593
|
created++;
|
|
19105
19594
|
opts.onCreated?.(nodeId, filePathRel, c);
|
|
@@ -19112,8 +19601,8 @@ async function runSeed(opts) {
|
|
|
19112
19601
|
}
|
|
19113
19602
|
|
|
19114
19603
|
// src/commands/analyze/phases/08-memory-manifest.ts
|
|
19115
|
-
var
|
|
19116
|
-
var
|
|
19604
|
+
var import_node_fs29 = require("node:fs");
|
|
19605
|
+
var import_node_path24 = require("node:path");
|
|
19117
19606
|
async function memoryManifest(run) {
|
|
19118
19607
|
const { globals } = run;
|
|
19119
19608
|
const { serviceUrl, token } = run;
|
|
@@ -19123,9 +19612,9 @@ async function memoryManifest(run) {
|
|
|
19123
19612
|
let autoSeedNotice = null;
|
|
19124
19613
|
try {
|
|
19125
19614
|
await ensureMemoryDir();
|
|
19126
|
-
const seedMarker = (0,
|
|
19127
|
-
const hasStandard = (0,
|
|
19128
|
-
const alreadyTried = (0,
|
|
19615
|
+
const seedMarker = (0, import_node_path24.join)(VERITY_DIR, ".seeded");
|
|
19616
|
+
const hasStandard = (0, import_node_fs29.existsSync)(STANDARD_FILE);
|
|
19617
|
+
const alreadyTried = (0, import_node_fs29.existsSync)(seedMarker);
|
|
19129
19618
|
if (hasStandard && !alreadyTried) {
|
|
19130
19619
|
const preManifest = await buildManifest();
|
|
19131
19620
|
if (preManifest.nodes.length === 0) {
|
|
@@ -19138,7 +19627,7 @@ async function memoryManifest(run) {
|
|
|
19138
19627
|
dryRun: false
|
|
19139
19628
|
});
|
|
19140
19629
|
if (seedResult.created > 0) {
|
|
19141
|
-
(0,
|
|
19630
|
+
(0, import_node_fs29.writeFileSync)(seedMarker, `${(/* @__PURE__ */ new Date()).toISOString()} created=${seedResult.created}
|
|
19142
19631
|
`);
|
|
19143
19632
|
autoSeedNotice = `Seeded ${seedResult.created} knowledge node(s) from your existing Standard (one-time).`;
|
|
19144
19633
|
logEvent("auto_seed_ran", {
|
|
@@ -19146,7 +19635,7 @@ async function memoryManifest(run) {
|
|
|
19146
19635
|
failed: seedResult.failed
|
|
19147
19636
|
});
|
|
19148
19637
|
} else if (seedResult.skipped === "already_seeded") {
|
|
19149
|
-
(0,
|
|
19638
|
+
(0, import_node_fs29.writeFileSync)(seedMarker, `${(/* @__PURE__ */ new Date()).toISOString()} skipped=already_seeded
|
|
19150
19639
|
`);
|
|
19151
19640
|
} else {
|
|
19152
19641
|
logEvent("auto_seed_noop", {
|
|
@@ -19241,7 +19730,7 @@ function computeIncrement(reviewedPaths, hashOf, priorAuthored) {
|
|
|
19241
19730
|
}
|
|
19242
19731
|
|
|
19243
19732
|
// src/commands/analyze/phases/10-working-memory.ts
|
|
19244
|
-
var
|
|
19733
|
+
var import_node_path25 = require("node:path");
|
|
19245
19734
|
async function workingMemory(run) {
|
|
19246
19735
|
const { opts } = run;
|
|
19247
19736
|
const { allForReview, baseline, conversation, foldResult, sessionId, token, transcriptPath } = run;
|
|
@@ -19253,7 +19742,7 @@ async function workingMemory(run) {
|
|
|
19253
19742
|
const priorState = foldForMarks(memorySession.d);
|
|
19254
19743
|
incrementReport = computeIncrement(
|
|
19255
19744
|
allForReview,
|
|
19256
|
-
(p) => fileHash((0,
|
|
19745
|
+
(p) => fileHash((0, import_node_path25.join)(repoRoot(), p)),
|
|
19257
19746
|
priorState.authored_all.map((a) => ({
|
|
19258
19747
|
path: a.path,
|
|
19259
19748
|
hash_at_last_verdict: a.hash_at_last_verdict
|
|
@@ -19334,6 +19823,54 @@ async function workingMemory(run) {
|
|
|
19334
19823
|
Object.assign(run, { incrementReport, memory, memorySession, reachability });
|
|
19335
19824
|
}
|
|
19336
19825
|
|
|
19826
|
+
// src/lib/note-budget.ts
|
|
19827
|
+
var import_node_fs30 = require("node:fs");
|
|
19828
|
+
var ADVISORY_BUDGET = { PASS: 1, WARN: 2 };
|
|
19829
|
+
var EPISODE_STALE_SECONDS = 30 * 60;
|
|
19830
|
+
var FRESH = { delivered: 0, tasksCompleted: 0, ts: 0 };
|
|
19831
|
+
function resolveEpisode(prev, signals) {
|
|
19832
|
+
if (!prev) return { ...FRESH, tasksCompleted: signals.tasksCompleted, ts: signals.now };
|
|
19833
|
+
if (signals.humanSpoke) return { ...FRESH, tasksCompleted: signals.tasksCompleted, ts: signals.now };
|
|
19834
|
+
if (signals.rawFail) return { ...FRESH, tasksCompleted: signals.tasksCompleted, ts: signals.now };
|
|
19835
|
+
if (prev.tasksCompleted !== signals.tasksCompleted) {
|
|
19836
|
+
return { ...FRESH, tasksCompleted: signals.tasksCompleted, ts: signals.now };
|
|
19837
|
+
}
|
|
19838
|
+
if (prev.ts > 0 && signals.now - prev.ts > EPISODE_STALE_SECONDS) {
|
|
19839
|
+
return { ...FRESH, tasksCompleted: signals.tasksCompleted, ts: signals.now };
|
|
19840
|
+
}
|
|
19841
|
+
return prev;
|
|
19842
|
+
}
|
|
19843
|
+
function advisoryBudgetSpent(episode, rawDecision) {
|
|
19844
|
+
const budget = ADVISORY_BUDGET[rawDecision] ?? ADVISORY_BUDGET.WARN;
|
|
19845
|
+
return episode.delivered >= budget;
|
|
19846
|
+
}
|
|
19847
|
+
function readAdvisoryEpisode(sessionId) {
|
|
19848
|
+
const file = scopedFile(ADVISORY_EPISODE_FILE, sessionId);
|
|
19849
|
+
if (!(0, import_node_fs30.existsSync)(file)) return null;
|
|
19850
|
+
try {
|
|
19851
|
+
const o = JSON.parse((0, import_node_fs30.readFileSync)(file, "utf-8")) ?? {};
|
|
19852
|
+
const delivered = typeof o.delivered === "number" ? o.delivered : NaN;
|
|
19853
|
+
if (isNaN(delivered)) return null;
|
|
19854
|
+
return {
|
|
19855
|
+
delivered,
|
|
19856
|
+
tasksCompleted: typeof o.tasksCompleted === "number" ? o.tasksCompleted : 0,
|
|
19857
|
+
ts: typeof o.ts === "number" ? o.ts : 0
|
|
19858
|
+
};
|
|
19859
|
+
} catch {
|
|
19860
|
+
return null;
|
|
19861
|
+
}
|
|
19862
|
+
}
|
|
19863
|
+
function writeAdvisoryEpisode(episode, sessionId) {
|
|
19864
|
+
try {
|
|
19865
|
+
(0, import_node_fs30.mkdirSync)(VERITY_DIR, { recursive: true });
|
|
19866
|
+
(0, import_node_fs30.writeFileSync)(
|
|
19867
|
+
scopedFile(ADVISORY_EPISODE_FILE, sessionId),
|
|
19868
|
+
JSON.stringify({ v: 1, ...episode })
|
|
19869
|
+
);
|
|
19870
|
+
} catch {
|
|
19871
|
+
}
|
|
19872
|
+
}
|
|
19873
|
+
|
|
19337
19874
|
// src/lib/run-mode.ts
|
|
19338
19875
|
function parseAutonomousEnv(raw) {
|
|
19339
19876
|
if (raw === void 0) return void 0;
|
|
@@ -19356,7 +19893,7 @@ function isExplicitlyAutonomous(env = process.env) {
|
|
|
19356
19893
|
}
|
|
19357
19894
|
|
|
19358
19895
|
// src/lib/task-context.ts
|
|
19359
|
-
var
|
|
19896
|
+
var import_node_child_process9 = require("node:child_process");
|
|
19360
19897
|
var CLOSING_RE = /\b(close[sd]?|fix(?:e[sd])?|resolve[sd]?)\b[\s:]*#(\d+)/i;
|
|
19361
19898
|
var BRANCH_RE = /(?:^|[/_-])(?:issue|gh|fix)[-_/]?(\d+)\b/i;
|
|
19362
19899
|
function parseLinkedIssue(sources) {
|
|
@@ -19372,7 +19909,7 @@ function parseLinkedIssue(sources) {
|
|
|
19372
19909
|
}
|
|
19373
19910
|
function safeExec(cmd, timeout) {
|
|
19374
19911
|
try {
|
|
19375
|
-
return (0,
|
|
19912
|
+
return (0, import_node_child_process9.execSync)(cmd, { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"], timeout }).trim();
|
|
19376
19913
|
} catch {
|
|
19377
19914
|
return "";
|
|
19378
19915
|
}
|
|
@@ -19427,7 +19964,13 @@ async function buildRequest(run) {
|
|
|
19427
19964
|
excluded_by_reason: excludedByReason,
|
|
19428
19965
|
// was the transcript itself truncated? The 256 KB window means "this turn"
|
|
19429
19966
|
// can quietly mean "the last 256 KB of it".
|
|
19430
|
-
transcript_windowed: actionSummary?.transcript_windowed ?? null
|
|
19967
|
+
transcript_windowed: actionSummary?.transcript_windowed ?? null,
|
|
19968
|
+
// The advisory budget's fleet counter-metric (note-budget.ts): deliveries in
|
|
19969
|
+
// the episode as of the PREVIOUS turn — this runs before phase 13 updates
|
|
19970
|
+
// the state, so the number is one turn lagged by construction. The
|
|
19971
|
+
// degenerate win for the budget is a dead channel that looks like clean
|
|
19972
|
+
// code; this is what makes "did delivery rate collapse" a query.
|
|
19973
|
+
advisory_delivered_prior: readAdvisoryEpisode(run.baselineSessionId)?.delivered ?? 0
|
|
19431
19974
|
};
|
|
19432
19975
|
const requestBody = {
|
|
19433
19976
|
coverage_telemetry: coverageTelemetry,
|
|
@@ -19566,7 +20109,8 @@ async function buildRequest(run) {
|
|
|
19566
20109
|
}
|
|
19567
20110
|
const noHumanPrompt = (conversation?.prompts?.length ?? 0) === 0;
|
|
19568
20111
|
const w4Task = noHumanPrompt && isExplicitlyAutonomous() ? resolveTaskContext() : null;
|
|
19569
|
-
const
|
|
20112
|
+
const planApprovalActive = foldResult?.planApproval?.activeSinceLastPrompt === true;
|
|
20113
|
+
const hasIntent = (conversation?.prompts?.length ?? 0) > 0 || specs.length > 0 || plans.length > 0 || !!assistantResponse || !!w4Task || planApprovalActive;
|
|
19570
20114
|
if (hasIntent) {
|
|
19571
20115
|
const intentContext = {};
|
|
19572
20116
|
if (conversation && conversation.prompts.length > 0) {
|
|
@@ -19598,6 +20142,10 @@ async function buildRequest(run) {
|
|
|
19598
20142
|
intentContext.user_prompt = w4Task.goal;
|
|
19599
20143
|
logEvent("w4_issue_anchor", { issue: w4Task.number, via: w4Task.via });
|
|
19600
20144
|
}
|
|
20145
|
+
if (planApprovalActive) {
|
|
20146
|
+
intentContext.plan_approved = true;
|
|
20147
|
+
logEvent("plan_approval_carried", { approvals: foldResult.planApproval.approvals });
|
|
20148
|
+
}
|
|
19601
20149
|
if (assistantResponse) {
|
|
19602
20150
|
const cap = analysisMode === "plan" ? MAX_ASSISTANT_RESPONSE_CHARS_PLAN : MAX_ASSISTANT_RESPONSE_CHARS_DEFAULT;
|
|
19603
20151
|
intentContext.assistant_response = assistantResponse.length > cap ? assistantResponse.slice(0, cap) : assistantResponse;
|
|
@@ -19617,14 +20165,14 @@ async function buildRequest(run) {
|
|
|
19617
20165
|
}
|
|
19618
20166
|
|
|
19619
20167
|
// src/lib/offline.ts
|
|
19620
|
-
var
|
|
20168
|
+
var import_node_fs31 = require("node:fs");
|
|
19621
20169
|
var import_node_crypto11 = require("node:crypto");
|
|
19622
20170
|
function cacheRequest(body) {
|
|
19623
20171
|
try {
|
|
19624
|
-
(0,
|
|
20172
|
+
(0, import_node_fs31.mkdirSync)(CACHE_DIR, { recursive: true });
|
|
19625
20173
|
const suffix = (0, import_node_crypto11.randomBytes)(4).toString("hex");
|
|
19626
20174
|
const filename = `pending-${Math.floor(Date.now() / 1e3)}-${suffix}.json`;
|
|
19627
|
-
(0,
|
|
20175
|
+
(0, import_node_fs31.writeFileSync)(`${CACHE_DIR}/${filename}`, JSON.stringify(redactRequest(body)));
|
|
19628
20176
|
} catch {
|
|
19629
20177
|
}
|
|
19630
20178
|
}
|
|
@@ -19743,10 +20291,10 @@ async function transmit(run) {
|
|
|
19743
20291
|
}
|
|
19744
20292
|
|
|
19745
20293
|
// src/commands/analyze/phases/13-reconcile.ts
|
|
19746
|
-
var
|
|
19747
|
-
var
|
|
20294
|
+
var import_node_fs32 = require("node:fs");
|
|
20295
|
+
var import_node_path26 = require("node:path");
|
|
19748
20296
|
async function reconcile(run) {
|
|
19749
|
-
const { actionSummary, allChanged, analyzable, baseline, codeDelta, contentHash, conversation, decision, memory, memorySession, response, reviewable, securityFiles, turnId } = run;
|
|
20297
|
+
const { actionSummary, allChanged, analyzable, baseline, baselineSessionId, codeDelta, contentHash, conversation, decision, foldResult, memory, memorySession, response, reviewable, securityFiles, turnId } = run;
|
|
19750
20298
|
const sentPaths = codeDelta.files.map((f) => f.path);
|
|
19751
20299
|
let openElsewhere = [];
|
|
19752
20300
|
if (memorySession) {
|
|
@@ -19754,7 +20302,7 @@ async function reconcile(run) {
|
|
|
19754
20302
|
const st = foldDossier(memorySession.d);
|
|
19755
20303
|
openElsewhere = openBlockingElsewhere(st.statements, sentPaths, (file, line) => {
|
|
19756
20304
|
try {
|
|
19757
|
-
const src = (0,
|
|
20305
|
+
const src = (0, import_node_fs32.readFileSync)((0, import_node_path26.join)(repoRoot(), file), "utf8").split("\n");
|
|
19758
20306
|
const at = src[line - 1];
|
|
19759
20307
|
return at === void 0 ? null : lineSha(at);
|
|
19760
20308
|
} catch {
|
|
@@ -19764,6 +20312,7 @@ async function reconcile(run) {
|
|
|
19764
20312
|
} catch {
|
|
19765
20313
|
}
|
|
19766
20314
|
}
|
|
20315
|
+
const { kept: externalChanged, owned: verityOwned } = partitionVerityOwned(allChanged);
|
|
19767
20316
|
const reviewCoverage = {
|
|
19768
20317
|
reviewed: sentPaths,
|
|
19769
20318
|
// Declared drops from the stages that DO report themselves today. The other
|
|
@@ -19805,11 +20354,20 @@ async function reconcile(run) {
|
|
|
19805
20354
|
stage: "baseline-scoping",
|
|
19806
20355
|
kind: "policy"
|
|
19807
20356
|
})),
|
|
20357
|
+
// ⚠ VERITY'S OWN FILES, named as such — not laundered into the
|
|
20358
|
+
// extension bucket below, where "we do not review our own installer's
|
|
20359
|
+
// dirt" would read as "a changed README". See self-scope.ts.
|
|
20360
|
+
...verityOwned.map((path) => ({
|
|
20361
|
+
path,
|
|
20362
|
+
reason: "verity-owned",
|
|
20363
|
+
stage: "self-scope",
|
|
20364
|
+
kind: "policy"
|
|
20365
|
+
})),
|
|
19808
20366
|
// The extension allowlist. POLICY: a changed README was never going to be
|
|
19809
20367
|
// reviewed, and calling that a coverage gap would downgrade nearly every
|
|
19810
20368
|
// PASS to WARN until WARN meant nothing. Recorded so the ledger balances and
|
|
19811
20369
|
// so "what did Verity ignore entirely" is answerable.
|
|
19812
|
-
...
|
|
20370
|
+
...externalChanged.filter((p) => !analyzable.includes(p) && !reviewable.includes(p) && !securityFiles.includes(p)).map((path) => ({
|
|
19813
20371
|
path,
|
|
19814
20372
|
reason: "not-a-reviewed-file-type",
|
|
19815
20373
|
stage: "extension-allowlist",
|
|
@@ -19846,6 +20404,29 @@ async function reconcile(run) {
|
|
|
19846
20404
|
decision
|
|
19847
20405
|
});
|
|
19848
20406
|
}
|
|
20407
|
+
const episodeSignals = {
|
|
20408
|
+
humanSpoke: (conversation?.prompts?.length ?? 0) > 0,
|
|
20409
|
+
rawFail: decision === "FAIL",
|
|
20410
|
+
tasksCompleted: (foldResult?.tasks ?? []).filter((t) => t.status === "completed").length,
|
|
20411
|
+
now: Math.floor(Date.now() / 1e3)
|
|
20412
|
+
};
|
|
20413
|
+
let episode = resolveEpisode(readAdvisoryEpisode(baselineSessionId), episodeSignals);
|
|
20414
|
+
const contentClass = classifyChannelContent(channelInputFrom(response));
|
|
20415
|
+
const wouldCarryAdvisory = contentClass.advisory || openElsewhere.length > 0;
|
|
20416
|
+
if (decision !== "FAIL" && !silenced && wouldCarryAdvisory && !contentClass.refusal && !contentClass.intentFlag && advisoryBudgetSpent(episode, decision)) {
|
|
20417
|
+
silenced = "note-budget";
|
|
20418
|
+
logEvent("channel_silenced", {
|
|
20419
|
+
reason: silenced,
|
|
20420
|
+
run_id: response.run_id ?? turnId,
|
|
20421
|
+
decision,
|
|
20422
|
+
episode_delivered: episode.delivered
|
|
20423
|
+
});
|
|
20424
|
+
}
|
|
20425
|
+
const deliveringAdvisory = decision !== "FAIL" && !silenced && wouldCarryAdvisory;
|
|
20426
|
+
writeAdvisoryEpisode(
|
|
20427
|
+
{ ...episode, delivered: episode.delivered + (deliveringAdvisory ? 1 : 0), ts: episodeSignals.now },
|
|
20428
|
+
baselineSessionId
|
|
20429
|
+
);
|
|
19849
20430
|
let intentRepeatCount = 0;
|
|
19850
20431
|
const priorPendingFingerprints = memorySession ? (() => {
|
|
19851
20432
|
try {
|
|
@@ -19861,6 +20442,11 @@ async function reconcile(run) {
|
|
|
19861
20442
|
decision,
|
|
19862
20443
|
branch: getCurrentBranch(),
|
|
19863
20444
|
watermarkSha: watermarkIsPartial ? null : watermarkHash,
|
|
20445
|
+
// The byte witness — the same "only honest definition of reviewed" the
|
|
20446
|
+
// coverage column uses. A finding on a path outside this set records no
|
|
20447
|
+
// statement (plan-mode prose anchored to unsent files must not become
|
|
20448
|
+
// "STILL OPEN … the tree is not clean").
|
|
20449
|
+
sentPaths,
|
|
19864
20450
|
findings: response.findings?.map((f) => ({
|
|
19865
20451
|
file: f.file,
|
|
19866
20452
|
line: f.line,
|
|
@@ -19927,6 +20513,39 @@ ${YELLOW2}${note}${NC2}
|
|
|
19927
20513
|
return exit(0);
|
|
19928
20514
|
}
|
|
19929
20515
|
|
|
20516
|
+
// src/lib/may-block.ts
|
|
20517
|
+
var HARD_BLOCK_CEILING = 5;
|
|
20518
|
+
function mayBlock(input) {
|
|
20519
|
+
const ceiling = input.ceiling ?? HARD_BLOCK_CEILING;
|
|
20520
|
+
if (input.reviewedFileCount === 0 && input.staticFindingCount === 0) {
|
|
20521
|
+
return { block: false, release: "no-code-reviewed" };
|
|
20522
|
+
}
|
|
20523
|
+
if (input.cycleCutFired) {
|
|
20524
|
+
return { block: false, release: "nothing-moved" };
|
|
20525
|
+
}
|
|
20526
|
+
if (input.attempts > input.maxIterations) {
|
|
20527
|
+
return { block: false, release: "same-problem-cap" };
|
|
20528
|
+
}
|
|
20529
|
+
if (input.blocks > ceiling) {
|
|
20530
|
+
return { block: false, release: "block-ceiling" };
|
|
20531
|
+
}
|
|
20532
|
+
return { block: true, release: null };
|
|
20533
|
+
}
|
|
20534
|
+
function describeRelease(release, input) {
|
|
20535
|
+
const ceiling = input.ceiling ?? HARD_BLOCK_CEILING;
|
|
20536
|
+
const open = input.findingCount > 0 ? `${input.findingCount} finding(s) remain OPEN and were NOT fixed. Human review required before deploying.` : "Human review required before deploying.";
|
|
20537
|
+
switch (release) {
|
|
20538
|
+
case "no-code-reviewed":
|
|
20539
|
+
return `Verity: WARN \u2014 NOT BLOCKING: no code was reviewed on this turn, so there is nothing here to fix. Reported as advice instead. ${open}`;
|
|
20540
|
+
case "nothing-moved":
|
|
20541
|
+
return `Verity: WARN \u2014 NOT BLOCKING: nothing has changed since the last verdict, so re-raising it cannot move anything forward. ${open}`;
|
|
20542
|
+
case "same-problem-cap":
|
|
20543
|
+
return `Verity: WARN \u2014 self-healing limit (${input.maxIterations}) reached on the same finding. NO LONGER BLOCKING, but ${open}`;
|
|
20544
|
+
case "block-ceiling":
|
|
20545
|
+
return `Verity: WARN \u2014 ${ceiling} consecutive blocking verdicts reached; releasing the block so this cannot loop. ${open}`;
|
|
20546
|
+
}
|
|
20547
|
+
}
|
|
20548
|
+
|
|
19930
20549
|
// src/lib/remediation-guard.ts
|
|
19931
20550
|
var TOOL_CONFIG_PATTERNS = [
|
|
19932
20551
|
/(^|\/)\.codacy\//,
|
|
@@ -19969,19 +20588,7 @@ function screenRemediation(fix, findingFile) {
|
|
|
19969
20588
|
|
|
19970
20589
|
// src/commands/analyze/phases/14-render.ts
|
|
19971
20590
|
function agentContextFor(response, intentRepeat = 0, priorPendingFingerprints = []) {
|
|
19972
|
-
|
|
19973
|
-
const intent = response.intent_alignment ?? {};
|
|
19974
|
-
return buildAgentContext({
|
|
19975
|
-
intentRepeat,
|
|
19976
|
-
priorPendingFingerprints,
|
|
19977
|
-
gateDecision: String(response.gate_decision ?? ""),
|
|
19978
|
-
findings: response.findings ?? [],
|
|
19979
|
-
pendingItems: response.pending_items ?? [],
|
|
19980
|
-
reviewStatus: metadata.review_status,
|
|
19981
|
-
coverage: metadata.coverage,
|
|
19982
|
-
intentVerdict: intent.verdict,
|
|
19983
|
-
intentGaps: intent.gaps
|
|
19984
|
-
});
|
|
20591
|
+
return buildAgentContext(channelInputFrom(response, intentRepeat, priorPendingFingerprints));
|
|
19985
20592
|
}
|
|
19986
20593
|
async function render(run) {
|
|
19987
20594
|
const { opts, globals } = run;
|
|
@@ -20075,38 +20682,63 @@ async function render(run) {
|
|
|
20075
20682
|
reverify_by: response.reverify_by
|
|
20076
20683
|
});
|
|
20077
20684
|
const grantNudge = grantWarning ? ` \u26A0\uFE0F ${grantWarning}` : "";
|
|
20078
|
-
let
|
|
20685
|
+
let release = null;
|
|
20079
20686
|
let effectiveDecision = decision;
|
|
20080
20687
|
if (decision === "FAIL") {
|
|
20081
|
-
const
|
|
20688
|
+
const findings = response.findings ?? [];
|
|
20689
|
+
const blocking = findings.filter((f) => {
|
|
20082
20690
|
const sev = String(f.severity ?? "").toLowerCase();
|
|
20083
20691
|
return sev === "critical" || sev === "high";
|
|
20084
20692
|
});
|
|
20085
20693
|
const fingerprint = findingsFingerprint(blocking);
|
|
20086
|
-
const prior =
|
|
20694
|
+
const prior = readBlockState(currentCommit, {
|
|
20695
|
+
newUserPrompt: (conversation?.prompts?.length ?? 0) > 0
|
|
20696
|
+
});
|
|
20087
20697
|
const sameProblem = isSameProblem(prior.fingerprint, fingerprint);
|
|
20088
|
-
const nextIteration = sameProblem ? prior.iteration + 1 : 1;
|
|
20089
20698
|
const maxIterations = parseInt(opts.maxIterations, 10);
|
|
20090
|
-
|
|
20091
|
-
|
|
20092
|
-
|
|
20093
|
-
|
|
20699
|
+
const attempts = sameProblem ? prior.attempts + 1 : 1;
|
|
20700
|
+
const blocks = prior.blocks + 1;
|
|
20701
|
+
const decisionNow = mayBlock({
|
|
20702
|
+
reviewedFileCount: codeDelta.files.length,
|
|
20703
|
+
staticFindingCount: run.staticResults?.findings?.length ?? 0,
|
|
20704
|
+
cycleCutFired: silenced !== null,
|
|
20705
|
+
attempts,
|
|
20706
|
+
blocks,
|
|
20707
|
+
maxIterations
|
|
20708
|
+
});
|
|
20709
|
+
if (decisionNow.block) {
|
|
20710
|
+
writeBlockState(currentCommit, { attempts, blocks, fingerprint });
|
|
20711
|
+
iteration = attempts;
|
|
20712
|
+
} else {
|
|
20713
|
+
release = decisionNow.release;
|
|
20094
20714
|
effectiveDecision = "WARN";
|
|
20095
|
-
logEvent("
|
|
20715
|
+
logEvent("block_released", {
|
|
20716
|
+
reason: release,
|
|
20717
|
+
attempts,
|
|
20718
|
+
blocks,
|
|
20719
|
+
reviewed_files: codeDelta.files.length,
|
|
20720
|
+
cycle_cut: silenced,
|
|
20721
|
+
fingerprint
|
|
20722
|
+
});
|
|
20096
20723
|
}
|
|
20097
20724
|
}
|
|
20098
|
-
if (
|
|
20725
|
+
if (release) {
|
|
20099
20726
|
const findings = response.findings ?? [];
|
|
20100
20727
|
const lines = findings.slice(0, 5).map((f) => ` [${String(f.severity ?? "?").toUpperCase()}] ${String(f.title ?? f.message ?? "")} (${String(f.file ?? "?")}:${String(f.line ?? "?")})`);
|
|
20728
|
+
const summary = describeRelease(release, {
|
|
20729
|
+
findingCount: findings.length,
|
|
20730
|
+
maxIterations: parseInt(opts.maxIterations, 10)
|
|
20731
|
+
});
|
|
20101
20732
|
emitVerdict({
|
|
20102
20733
|
proposed: "WARN",
|
|
20103
20734
|
changed: run.changedUniverse,
|
|
20104
20735
|
coverage: reviewCoverage,
|
|
20105
|
-
userSummary:
|
|
20106
|
-
${lines.join("\n")}
|
|
20736
|
+
userSummary: lines.length > 0 ? `${summary}
|
|
20737
|
+
${lines.join("\n")}` : summary,
|
|
20107
20738
|
agentContext: null,
|
|
20108
20739
|
silenced: true
|
|
20109
20740
|
});
|
|
20741
|
+
return;
|
|
20110
20742
|
}
|
|
20111
20743
|
switch (effectiveDecision) {
|
|
20112
20744
|
case "FAIL": {
|
|
@@ -20205,7 +20837,7 @@ ${YELLOW}${grantNudge.trim()}${NC}
|
|
|
20205
20837
|
break;
|
|
20206
20838
|
}
|
|
20207
20839
|
case "PASS": {
|
|
20208
|
-
|
|
20840
|
+
resetBlockState(currentCommit);
|
|
20209
20841
|
if (watermarkHash) recordPassHash(watermarkHash, baselineSessionId);
|
|
20210
20842
|
if (!watermarkIsPartial && currentCommit && currentCommit !== "no-git") writeBaselineSha(currentCommit);
|
|
20211
20843
|
let userSummary = response.user_summary ?? "Verity: PASS";
|
|
@@ -20226,6 +20858,7 @@ ${YELLOW}${grantNudge.trim()}${NC}
|
|
|
20226
20858
|
break;
|
|
20227
20859
|
}
|
|
20228
20860
|
case "WARN": {
|
|
20861
|
+
if (decision !== "FAIL") resetBlockState(currentCommit);
|
|
20229
20862
|
if (watermarkHash) recordPassHash(watermarkHash, baselineSessionId);
|
|
20230
20863
|
if (!watermarkIsPartial && currentCommit && currentCommit !== "no-git") writeBaselineSha(currentCommit);
|
|
20231
20864
|
let userSummary = response.user_summary ?? "Verity: WARN";
|
|
@@ -20324,7 +20957,7 @@ async function runAnalyze(opts, globals) {
|
|
|
20324
20957
|
}
|
|
20325
20958
|
|
|
20326
20959
|
// src/commands/baseline.ts
|
|
20327
|
-
var
|
|
20960
|
+
var import_node_fs33 = require("node:fs");
|
|
20328
20961
|
function registerBaselineCommands(program2) {
|
|
20329
20962
|
const baseline = program2.command("baseline").description("Manage the task-start working-tree baseline");
|
|
20330
20963
|
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) => {
|
|
@@ -20333,7 +20966,7 @@ function registerBaselineCommands(program2) {
|
|
|
20333
20966
|
process.chdir(repoRoot());
|
|
20334
20967
|
} catch {
|
|
20335
20968
|
}
|
|
20336
|
-
if (!(0,
|
|
20969
|
+
if (!(0, import_node_fs33.existsSync)(VERITY_DIR)) {
|
|
20337
20970
|
process.exit(0);
|
|
20338
20971
|
}
|
|
20339
20972
|
let sessionId = opts.sessionId;
|
|
@@ -20373,7 +21006,7 @@ async function readStdin() {
|
|
|
20373
21006
|
}
|
|
20374
21007
|
|
|
20375
21008
|
// src/commands/review.ts
|
|
20376
|
-
var
|
|
21009
|
+
var import_node_fs34 = require("node:fs");
|
|
20377
21010
|
function registerReviewCommand(program2) {
|
|
20378
21011
|
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) => {
|
|
20379
21012
|
const globals = program2.opts();
|
|
@@ -20392,7 +21025,7 @@ async function runReview(opts, globals) {
|
|
|
20392
21025
|
const securityFiles = filterSecurity(allFiles);
|
|
20393
21026
|
let staticResults;
|
|
20394
21027
|
if (isCodacyAvailable()) {
|
|
20395
|
-
const scannable = Array.from(/* @__PURE__ */ new Set([...analyzable, ...securityFiles])).filter((f) => (0,
|
|
21028
|
+
const scannable = Array.from(/* @__PURE__ */ new Set([...analyzable, ...securityFiles])).filter((f) => (0, import_node_fs34.existsSync)(f) || resolveFile(f) !== null);
|
|
20396
21029
|
staticResults = runCodacyAnalysis(scannable);
|
|
20397
21030
|
} else {
|
|
20398
21031
|
staticResults = {
|
|
@@ -20418,10 +21051,10 @@ async function runReview(opts, globals) {
|
|
|
20418
21051
|
const specPaths = opts.specs.split(",").map((f) => f.trim()).filter(Boolean);
|
|
20419
21052
|
specs = [];
|
|
20420
21053
|
for (const p of specPaths) {
|
|
20421
|
-
if (!(0,
|
|
21054
|
+
if (!(0, import_node_fs34.existsSync)(p)) continue;
|
|
20422
21055
|
try {
|
|
20423
|
-
const { readFileSync:
|
|
20424
|
-
const content =
|
|
21056
|
+
const { readFileSync: readFileSync20 } = await import("node:fs");
|
|
21057
|
+
const content = readFileSync20(p, "utf-8");
|
|
20425
21058
|
specs.push({ path: p, content: content.slice(0, 10240) });
|
|
20426
21059
|
} catch {
|
|
20427
21060
|
}
|
|
@@ -20478,15 +21111,15 @@ async function runReview(opts, globals) {
|
|
|
20478
21111
|
}
|
|
20479
21112
|
|
|
20480
21113
|
// src/commands/guard.ts
|
|
20481
|
-
var
|
|
20482
|
-
var
|
|
21114
|
+
var import_node_fs35 = require("node:fs");
|
|
21115
|
+
var import_node_path27 = require("node:path");
|
|
20483
21116
|
var GUARD_BLOCK_CAP = 2;
|
|
20484
|
-
var GUARD_ITER_FILE = (0,
|
|
21117
|
+
var GUARD_ITER_FILE = (0, import_node_path27.join)(VERITY_DIR, ".guard-iteration");
|
|
20485
21118
|
function readPreToolUseStdin() {
|
|
20486
21119
|
const empty = { command: "", cwd: null, sessionId: null };
|
|
20487
|
-
return new Promise((
|
|
21120
|
+
return new Promise((resolve4) => {
|
|
20488
21121
|
try {
|
|
20489
|
-
if (process.stdin.isTTY) return
|
|
21122
|
+
if (process.stdin.isTTY) return resolve4(empty);
|
|
20490
21123
|
const chunks = [];
|
|
20491
21124
|
let timer;
|
|
20492
21125
|
let settled = false;
|
|
@@ -20499,7 +21132,7 @@ function readPreToolUseStdin() {
|
|
|
20499
21132
|
process.stdin.removeListener("end", onEnd);
|
|
20500
21133
|
process.stdin.removeListener("error", onError);
|
|
20501
21134
|
process.stdin.pause();
|
|
20502
|
-
|
|
21135
|
+
resolve4(value);
|
|
20503
21136
|
};
|
|
20504
21137
|
const onEnd = () => {
|
|
20505
21138
|
try {
|
|
@@ -20520,32 +21153,13 @@ function readPreToolUseStdin() {
|
|
|
20520
21153
|
process.stdin.on("error", onError);
|
|
20521
21154
|
process.stdin.resume();
|
|
20522
21155
|
} catch {
|
|
20523
|
-
|
|
21156
|
+
resolve4(empty);
|
|
20524
21157
|
}
|
|
20525
21158
|
});
|
|
20526
21159
|
}
|
|
20527
|
-
function buildCommandRe(head) {
|
|
20528
|
-
return new RegExp(`(?:^|[\\s;&|(])${head}|(?:^|[;&|(])\\s*[^\\s;&|()'"]*\\/${head}`);
|
|
20529
|
-
}
|
|
20530
|
-
var GIT_GLOBAL_OPTS = "(?:\\s+(?:-[Cc]\\s+\\S+|--?[\\w-]+(?:=\\S+)?))*";
|
|
20531
|
-
var COMMIT_RE = buildCommandRe(`git${GIT_GLOBAL_OPTS}\\s+commit(?![\\w-])`);
|
|
20532
|
-
var PUSH_RE = buildCommandRe(`git${GIT_GLOBAL_OPTS}\\s+push\\b`);
|
|
20533
|
-
var GH_PR_RE = buildCommandRe(`gh${GIT_GLOBAL_OPTS}\\s+pr\\s+create\\b`);
|
|
20534
|
-
function classifyCommand2(command, on) {
|
|
20535
|
-
let commit = false;
|
|
20536
|
-
let push = false;
|
|
20537
|
-
for (const seg of (command ?? "").split(/&&|\|\||;|\n/)) {
|
|
20538
|
-
if (/--dry-run\b/.test(seg)) continue;
|
|
20539
|
-
if (COMMIT_RE.test(seg)) commit = true;
|
|
20540
|
-
if (PUSH_RE.test(seg) || GH_PR_RE.test(seg)) push = true;
|
|
20541
|
-
}
|
|
20542
|
-
if (commit && on.includes("commit")) return "pre-commit";
|
|
20543
|
-
if (push && on.includes("push")) return "pre-push";
|
|
20544
|
-
return null;
|
|
20545
|
-
}
|
|
20546
21160
|
function readIterMap() {
|
|
20547
21161
|
try {
|
|
20548
|
-
const raw = JSON.parse((0,
|
|
21162
|
+
const raw = JSON.parse((0, import_node_fs35.readFileSync)(GUARD_ITER_FILE, "utf-8"));
|
|
20549
21163
|
if (raw && typeof raw === "object") {
|
|
20550
21164
|
if (typeof raw.moment === "string" && typeof raw.count === "number") {
|
|
20551
21165
|
return { [raw.moment]: raw.count };
|
|
@@ -20565,10 +21179,10 @@ function readIter(moment) {
|
|
|
20565
21179
|
}
|
|
20566
21180
|
function writeIter(moment, count) {
|
|
20567
21181
|
try {
|
|
20568
|
-
(0,
|
|
21182
|
+
(0, import_node_fs35.mkdirSync)(VERITY_DIR, { recursive: true });
|
|
20569
21183
|
const map = readIterMap();
|
|
20570
21184
|
map[moment] = count;
|
|
20571
|
-
(0,
|
|
21185
|
+
(0, import_node_fs35.writeFileSync)(GUARD_ITER_FILE, JSON.stringify(map));
|
|
20572
21186
|
} catch {
|
|
20573
21187
|
}
|
|
20574
21188
|
}
|
|
@@ -20578,10 +21192,10 @@ function resetIter(moment) {
|
|
|
20578
21192
|
if (!(moment in map)) return;
|
|
20579
21193
|
delete map[moment];
|
|
20580
21194
|
if (Object.keys(map).length === 0) {
|
|
20581
|
-
if ((0,
|
|
21195
|
+
if ((0, import_node_fs35.existsSync)(GUARD_ITER_FILE)) (0, import_node_fs35.unlinkSync)(GUARD_ITER_FILE);
|
|
20582
21196
|
} else {
|
|
20583
|
-
(0,
|
|
20584
|
-
(0,
|
|
21197
|
+
(0, import_node_fs35.mkdirSync)(VERITY_DIR, { recursive: true });
|
|
21198
|
+
(0, import_node_fs35.writeFileSync)(GUARD_ITER_FILE, JSON.stringify(map));
|
|
20585
21199
|
}
|
|
20586
21200
|
} catch {
|
|
20587
21201
|
}
|
|
@@ -20596,8 +21210,9 @@ function registerGuardCommand(program2) {
|
|
|
20596
21210
|
}
|
|
20597
21211
|
});
|
|
20598
21212
|
}
|
|
20599
|
-
function
|
|
20600
|
-
|
|
21213
|
+
function getMomentScope(moment) {
|
|
21214
|
+
if (moment === "pre-commit") return { files: getStagedFiles(), range: "staged" };
|
|
21215
|
+
return getPushRangeFiles();
|
|
20601
21216
|
}
|
|
20602
21217
|
function matchFlagValue(command, flags) {
|
|
20603
21218
|
const re = new RegExp(`(?<![\\w-])(?:${flags})(?:=|\\s+)('((?:[^'\\\\]|\\\\.)*)'|"((?:[^"\\\\]|\\\\.)*)"|([^\\s'"-][^\\s]*))`);
|
|
@@ -20640,18 +21255,16 @@ function hasBlockingFinding(response) {
|
|
|
20640
21255
|
const findings = response.findings ?? [];
|
|
20641
21256
|
return findings.some((f) => f.scope !== "pre-existing" && ["critical", "high"].includes((f.severity ?? "").toLowerCase()));
|
|
20642
21257
|
}
|
|
20643
|
-
function buildGuardRequest(moment, files, iter, sessionId, command) {
|
|
21258
|
+
function buildGuardRequest(moment, files, codeDelta, iter, sessionId, command, coverageTelemetry) {
|
|
20644
21259
|
const analyzable = filterAnalyzable(files);
|
|
20645
21260
|
const securityFiles = filterSecurity(files);
|
|
20646
21261
|
let staticResults;
|
|
20647
21262
|
if (isCodacyAvailable()) {
|
|
20648
|
-
const scannable = Array.from(/* @__PURE__ */ new Set([...analyzable, ...securityFiles])).map((f) => (0,
|
|
21263
|
+
const scannable = Array.from(/* @__PURE__ */ new Set([...analyzable, ...securityFiles])).map((f) => (0, import_node_fs35.existsSync)(f) ? f : resolveFile(f)).filter((f) => f !== null);
|
|
20649
21264
|
staticResults = runCodacyAnalysis(scannable);
|
|
20650
21265
|
} else {
|
|
20651
21266
|
staticResults = { tool: "@codacy/analysis-cli", findings: [], summary: { total_findings: 0, by_severity: {}, tools_run: [] } };
|
|
20652
21267
|
}
|
|
20653
|
-
const codeDelta = collectCodeDelta(files);
|
|
20654
|
-
if (codeDelta.total_files === 0) return null;
|
|
20655
21268
|
const trigger = moment === "pre-commit" ? "hook:pre-commit" : "hook:pre-push";
|
|
20656
21269
|
const requestBody = {
|
|
20657
21270
|
static_results: staticResults,
|
|
@@ -20668,6 +21281,7 @@ function buildGuardRequest(moment, files, iter, sessionId, command) {
|
|
|
20668
21281
|
iteration: iter + 1
|
|
20669
21282
|
}
|
|
20670
21283
|
};
|
|
21284
|
+
if (coverageTelemetry) requestBody.coverage_telemetry = coverageTelemetry;
|
|
20671
21285
|
const specs = discoverSpecs();
|
|
20672
21286
|
const plans = discoverPlans();
|
|
20673
21287
|
const statedIntent = extractStatedIntent(moment, command);
|
|
@@ -20680,6 +21294,43 @@ function buildGuardRequest(moment, files, iter, sessionId, command) {
|
|
|
20680
21294
|
}
|
|
20681
21295
|
return requestBody;
|
|
20682
21296
|
}
|
|
21297
|
+
function buildGuardCoverage(files, codeDelta, frame, frameRange, frameFiles, actualRoot) {
|
|
21298
|
+
const byReason = {};
|
|
21299
|
+
for (const e of codeDelta.excluded) byReason[e.reason] = (byReason[e.reason] ?? 0) + 1;
|
|
21300
|
+
return {
|
|
21301
|
+
changed_all: files.length,
|
|
21302
|
+
analyzable: filterAnalyzable(files).length,
|
|
21303
|
+
reviewable: filterReviewable(files).length,
|
|
21304
|
+
security: filterSecurity(files).length,
|
|
21305
|
+
for_review: files.length,
|
|
21306
|
+
sent: codeDelta.total_files,
|
|
21307
|
+
capped_out: codeDelta.truncated?.dropped ?? 0,
|
|
21308
|
+
excluded: codeDelta.excluded.length,
|
|
21309
|
+
excluded_by_reason: byReason,
|
|
21310
|
+
transcript_windowed: null,
|
|
21311
|
+
guard_frame: frameTelemetry(frame, frameRange, {
|
|
21312
|
+
actualRoot,
|
|
21313
|
+
actualFiles: files,
|
|
21314
|
+
frameFiles
|
|
21315
|
+
})
|
|
21316
|
+
};
|
|
21317
|
+
}
|
|
21318
|
+
function coverageSummary(c) {
|
|
21319
|
+
const range = c.range ? ` @ ${c.range}` : "";
|
|
21320
|
+
return `reviewed ${c.sent.length} file(s)${range}`;
|
|
21321
|
+
}
|
|
21322
|
+
function coverageBlock(c) {
|
|
21323
|
+
const lines = [];
|
|
21324
|
+
const tree = c.root ? `${c.root}${c.linked ? " (linked worktree)" : ""}${c.branch ? ` \xB7 branch ${c.branch}` : ""}` : "(no tree resolved)";
|
|
21325
|
+
lines.push(`Reviewed (${c.moment}): ${c.sent.length} file(s)${c.range ? ` @ ${c.range}` : ""}`);
|
|
21326
|
+
lines.push(` Tree: ${tree}`);
|
|
21327
|
+
for (const f of c.sent) lines.push(` - ${f}`);
|
|
21328
|
+
if (c.excluded.length > 0) {
|
|
21329
|
+
lines.push(` Excluded (${c.excluded.length}):`);
|
|
21330
|
+
for (const e of c.excluded) lines.push(` - ${e.path} (${e.reason})`);
|
|
21331
|
+
}
|
|
21332
|
+
return lines.join("\n");
|
|
21333
|
+
}
|
|
20683
21334
|
function emitAllowNotice(userMsg, agentMsg) {
|
|
20684
21335
|
process.stdout.write(JSON.stringify({
|
|
20685
21336
|
systemMessage: userMsg,
|
|
@@ -20690,13 +21341,13 @@ function emitAllowNotice(userMsg, agentMsg) {
|
|
|
20690
21341
|
async function runGuard(opts, globals) {
|
|
20691
21342
|
const on = opts.on.split(",").map((s) => s.trim()).filter((s) => s === "commit" || s === "push");
|
|
20692
21343
|
const { command, cwd, sessionId } = await readPreToolUseStdin();
|
|
20693
|
-
if (cwd && (0,
|
|
21344
|
+
if (cwd && (0, import_node_fs35.existsSync)(cwd)) {
|
|
20694
21345
|
try {
|
|
20695
21346
|
process.chdir(cwd);
|
|
20696
21347
|
} catch {
|
|
20697
21348
|
}
|
|
20698
21349
|
}
|
|
20699
|
-
const moment =
|
|
21350
|
+
const moment = classifyCommand(command, on);
|
|
20700
21351
|
if (!moment) process.exit(0);
|
|
20701
21352
|
const verb = moment === "pre-commit" ? "commit" : "push";
|
|
20702
21353
|
const iter = readIter(moment);
|
|
@@ -20707,13 +21358,40 @@ async function runGuard(opts, globals) {
|
|
|
20707
21358
|
`Verity ${moment}: review-cycle cap (${GUARD_BLOCK_CAP}) reached; the ${verb} was allowed without a further block.`
|
|
20708
21359
|
);
|
|
20709
21360
|
}
|
|
20710
|
-
const files =
|
|
21361
|
+
const { files, range: actualRange } = getMomentScope(moment);
|
|
20711
21362
|
if (files.length === 0) process.exit(0);
|
|
20712
21363
|
const tokenResult = await resolveToken(globals.token);
|
|
20713
21364
|
const urlResult = await resolveServiceUrl(globals.serviceUrl);
|
|
20714
21365
|
if (!tokenResult.ok || !urlResult.ok) process.exit(0);
|
|
20715
|
-
const
|
|
20716
|
-
|
|
21366
|
+
const { frame } = resolveFrame({ command, on, hookCwd: cwd });
|
|
21367
|
+
const frameRange = moment === "pre-push" ? resolvePushRange(frame, command, on) : stagedRange();
|
|
21368
|
+
const frameFiles = frame.refusal ? [] : rangeFiles(frame, frameRange);
|
|
21369
|
+
const actualRoot = repoRoot();
|
|
21370
|
+
logEvent("guard_frame", {
|
|
21371
|
+
moment,
|
|
21372
|
+
...frameTelemetry(frame, frameRange, { actualRoot, actualFiles: files, frameFiles })
|
|
21373
|
+
});
|
|
21374
|
+
const codeDelta = collectCodeDelta(files);
|
|
21375
|
+
if (codeDelta.total_files === 0) process.exit(0);
|
|
21376
|
+
const requestBody = buildGuardRequest(
|
|
21377
|
+
moment,
|
|
21378
|
+
files,
|
|
21379
|
+
codeDelta,
|
|
21380
|
+
iter,
|
|
21381
|
+
sessionId,
|
|
21382
|
+
command,
|
|
21383
|
+
buildGuardCoverage(files, codeDelta, frame, frameRange, frameFiles, actualRoot)
|
|
21384
|
+
);
|
|
21385
|
+
const coverage = {
|
|
21386
|
+
moment,
|
|
21387
|
+
root: actualRoot,
|
|
21388
|
+
branch: frame.refusal ? null : frame.branch,
|
|
21389
|
+
linked: frame.isLinkedWorktree,
|
|
21390
|
+
range: actualRange,
|
|
21391
|
+
sent: codeDelta.files.map((f) => f.path),
|
|
21392
|
+
excluded: codeDelta.excluded.map((e) => ({ path: e.path, reason: e.reason }))
|
|
21393
|
+
};
|
|
21394
|
+
logToFileOnly(coverageBlock(coverage));
|
|
20717
21395
|
const result = await analyzeRequest({
|
|
20718
21396
|
serviceUrl: urlResult.data,
|
|
20719
21397
|
token: tokenResult.data.token,
|
|
@@ -20734,31 +21412,39 @@ async function runGuard(opts, globals) {
|
|
|
20734
21412
|
const decision = response.gate_decision ?? "(unrecognised)";
|
|
20735
21413
|
const viewUrl = response.view_url ?? "";
|
|
20736
21414
|
const link = viewUrl ? ` \u2014 ${viewUrl}` : "";
|
|
21415
|
+
const covLine = coverageSummary(coverage);
|
|
21416
|
+
const covDetail = coverageBlock(coverage);
|
|
20737
21417
|
if (decision === "FAIL" && hasBlockingFinding(response)) {
|
|
20738
21418
|
writeIter(moment, iter + 1);
|
|
20739
|
-
writeBlockMessage(moment, response);
|
|
21419
|
+
writeBlockMessage(moment, response, covDetail);
|
|
20740
21420
|
process.exit(2);
|
|
20741
21421
|
}
|
|
20742
21422
|
resetIter(moment);
|
|
20743
21423
|
if (decision === "FAIL") {
|
|
20744
21424
|
const narrative = response.assessment?.narrative ?? "";
|
|
20745
21425
|
emitAllowNotice(
|
|
20746
|
-
`\u26A0 Verity ${moment}: the ${verb} may not match its stated purpose \u2014 proceeding${link}`,
|
|
20747
|
-
`Verity ${moment}: intent-alignment WARNING (not blocked).${narrative ? " " + narrative : ""}
|
|
21426
|
+
`\u26A0 Verity ${moment}: the ${verb} may not match its stated purpose \u2014 proceeding (${covLine})${link}`,
|
|
21427
|
+
`Verity ${moment}: intent-alignment WARNING (not blocked).${narrative ? " " + narrative : ""}
|
|
21428
|
+
${covDetail}${viewUrl ? `
|
|
21429
|
+
Report: ${viewUrl}` : ""}`
|
|
20748
21430
|
);
|
|
20749
21431
|
}
|
|
20750
21432
|
if (decision === "WARN") {
|
|
20751
21433
|
emitAllowNotice(
|
|
20752
|
-
`\u26A0 Verity ${moment}: WARN \u2014 proceeding${link}`,
|
|
20753
|
-
`Verity ${moment} review: WARN (proceeding)
|
|
21434
|
+
`\u26A0 Verity ${moment}: WARN \u2014 proceeding (${covLine})${link}`,
|
|
21435
|
+
`Verity ${moment} review: WARN (proceeding).
|
|
21436
|
+
${covDetail}${viewUrl ? `
|
|
21437
|
+
Report: ${viewUrl}` : ""}`
|
|
20754
21438
|
);
|
|
20755
21439
|
}
|
|
20756
21440
|
emitAllowNotice(
|
|
20757
|
-
`\u2713 Verity ${moment}: PASS${link}`,
|
|
20758
|
-
`Verity ${moment} review: PASS
|
|
21441
|
+
`\u2713 Verity ${moment}: PASS (${covLine})${link}`,
|
|
21442
|
+
`Verity ${moment} review: PASS.
|
|
21443
|
+
${covDetail}${viewUrl ? `
|
|
21444
|
+
Report: ${viewUrl}` : ""}`
|
|
20759
21445
|
);
|
|
20760
21446
|
}
|
|
20761
|
-
function writeBlockMessage(moment, response) {
|
|
21447
|
+
function writeBlockMessage(moment, response, covDetail) {
|
|
20762
21448
|
const label2 = moment === "pre-commit" ? "pre-commit" : "pre-push";
|
|
20763
21449
|
const verb = moment === "pre-commit" ? "commit" : "push";
|
|
20764
21450
|
const assessment = response.assessment;
|
|
@@ -20788,6 +21474,9 @@ function writeBlockMessage(moment, response) {
|
|
|
20788
21474
|
`);
|
|
20789
21475
|
}
|
|
20790
21476
|
}
|
|
21477
|
+
process.stderr.write(`${DIM}${covDetail}${NC}
|
|
21478
|
+
|
|
21479
|
+
`);
|
|
20791
21480
|
if (viewUrl) process.stderr.write(`${CYAN}Full report: ${viewUrl}${NC}
|
|
20792
21481
|
|
|
20793
21482
|
`);
|
|
@@ -20796,16 +21485,16 @@ function writeBlockMessage(moment, response) {
|
|
|
20796
21485
|
}
|
|
20797
21486
|
|
|
20798
21487
|
// src/commands/init.ts
|
|
20799
|
-
var
|
|
21488
|
+
var import_node_fs37 = require("node:fs");
|
|
20800
21489
|
var import_promises13 = require("node:fs/promises");
|
|
20801
|
-
var
|
|
20802
|
-
var
|
|
21490
|
+
var import_node_path29 = require("node:path");
|
|
21491
|
+
var import_node_child_process11 = require("node:child_process");
|
|
20803
21492
|
var readline2 = __toESM(require("node:readline/promises"));
|
|
20804
21493
|
|
|
20805
21494
|
// src/commands/migrate.ts
|
|
20806
|
-
var
|
|
20807
|
-
var
|
|
20808
|
-
var
|
|
21495
|
+
var import_node_fs36 = require("node:fs");
|
|
21496
|
+
var import_node_path28 = require("node:path");
|
|
21497
|
+
var import_node_child_process10 = require("node:child_process");
|
|
20809
21498
|
|
|
20810
21499
|
// src/lib/telemetry.ts
|
|
20811
21500
|
var import_promises12 = require("node:fs/promises");
|
|
@@ -20900,11 +21589,11 @@ async function uninstallTelemetry() {
|
|
|
20900
21589
|
// src/commands/migrate.ts
|
|
20901
21590
|
var LEGACY_NPM_PACKAGE = "@codacy/gate-cli";
|
|
20902
21591
|
function defaultNpmRemover(pkg) {
|
|
20903
|
-
(0,
|
|
21592
|
+
(0, import_node_child_process10.execSync)(`npm rm -g ${pkg}`, { stdio: "pipe", timeout: 12e4 });
|
|
20904
21593
|
}
|
|
20905
21594
|
function isGitTracked(cwd, relPath) {
|
|
20906
21595
|
try {
|
|
20907
|
-
(0,
|
|
21596
|
+
(0, import_node_child_process10.execSync)(`git ls-files --error-unmatch ${relPath}`, { cwd, stdio: "pipe" });
|
|
20908
21597
|
return true;
|
|
20909
21598
|
} catch {
|
|
20910
21599
|
return false;
|
|
@@ -20912,7 +21601,7 @@ function isGitTracked(cwd, relPath) {
|
|
|
20912
21601
|
}
|
|
20913
21602
|
function isGitRepo(cwd) {
|
|
20914
21603
|
try {
|
|
20915
|
-
(0,
|
|
21604
|
+
(0, import_node_child_process10.execSync)("git rev-parse --is-inside-work-tree", { cwd, stdio: "pipe" });
|
|
20916
21605
|
return true;
|
|
20917
21606
|
} catch {
|
|
20918
21607
|
return false;
|
|
@@ -20933,12 +21622,12 @@ async function runMigration(opts = {}) {
|
|
|
20933
21622
|
return { actions, migrated: actions.length > 0 };
|
|
20934
21623
|
}
|
|
20935
21624
|
function migrateProjectDir(root, actions) {
|
|
20936
|
-
const gateDir = (0,
|
|
20937
|
-
const verityDir = (0,
|
|
20938
|
-
if ((0,
|
|
21625
|
+
const gateDir = (0, import_node_path28.join)(root, ".gate");
|
|
21626
|
+
const verityDir = (0, import_node_path28.join)(root, ".verity");
|
|
21627
|
+
if ((0, import_node_fs36.existsSync)(gateDir) && !(0, import_node_fs36.existsSync)(verityDir)) {
|
|
20939
21628
|
return migrateProjectDirRename(root, gateDir, verityDir, actions);
|
|
20940
21629
|
}
|
|
20941
|
-
if ((0,
|
|
21630
|
+
if ((0, import_node_fs36.existsSync)(gateDir) && (0, import_node_fs36.existsSync)(verityDir)) {
|
|
20942
21631
|
return migrateProjectDirCarry(gateDir, verityDir, actions);
|
|
20943
21632
|
}
|
|
20944
21633
|
return false;
|
|
@@ -20952,20 +21641,20 @@ function migrateProjectDirRename(root, gateDir, verityDir, actions) {
|
|
|
20952
21641
|
);
|
|
20953
21642
|
}
|
|
20954
21643
|
try {
|
|
20955
|
-
(0,
|
|
21644
|
+
(0, import_node_child_process10.execSync)("git mv .gate .verity", { cwd: root, stdio: "pipe" });
|
|
20956
21645
|
actions.push("Moved .gate/ \u2192 .verity/ (git mv, staged)");
|
|
20957
21646
|
moved = true;
|
|
20958
21647
|
} catch {
|
|
20959
21648
|
}
|
|
20960
21649
|
}
|
|
20961
21650
|
if (moved) {
|
|
20962
|
-
if ((0,
|
|
21651
|
+
if ((0, import_node_fs36.existsSync)(gateDir)) {
|
|
20963
21652
|
const carried = carryLegacyContents(gateDir, verityDir);
|
|
20964
21653
|
if (carried > 0) {
|
|
20965
21654
|
actions.push(`Carried ${carried} untracked legacy file(s) from .gate/ into .verity/`);
|
|
20966
21655
|
}
|
|
20967
21656
|
try {
|
|
20968
|
-
(0,
|
|
21657
|
+
(0, import_node_fs36.rmSync)(gateDir, { recursive: true, force: true });
|
|
20969
21658
|
} catch {
|
|
20970
21659
|
}
|
|
20971
21660
|
}
|
|
@@ -20981,18 +21670,18 @@ function migrateProjectDirCarry(gateDir, verityDir, actions) {
|
|
|
20981
21670
|
actions.push(`Carried ${carried} legacy file(s) from .gate/ into .verity/`);
|
|
20982
21671
|
}
|
|
20983
21672
|
try {
|
|
20984
|
-
(0,
|
|
21673
|
+
(0, import_node_fs36.rmSync)(gateDir, { recursive: true, force: true });
|
|
20985
21674
|
} catch {
|
|
20986
21675
|
}
|
|
20987
21676
|
return carried > 0;
|
|
20988
21677
|
}
|
|
20989
21678
|
function migrateGlobalCredentials(home, actions) {
|
|
20990
21679
|
if (!home) return;
|
|
20991
|
-
const gateCreds = (0,
|
|
20992
|
-
const verityCreds = (0,
|
|
20993
|
-
if (!(0,
|
|
20994
|
-
if (!(0,
|
|
20995
|
-
(0,
|
|
21680
|
+
const gateCreds = (0, import_node_path28.join)(home, ".gate", "credentials");
|
|
21681
|
+
const verityCreds = (0, import_node_path28.join)(home, ".verity", "credentials");
|
|
21682
|
+
if (!(0, import_node_fs36.existsSync)(gateCreds)) return;
|
|
21683
|
+
if (!(0, import_node_fs36.existsSync)(verityCreds)) {
|
|
21684
|
+
(0, import_node_fs36.mkdirSync)((0, import_node_path28.join)(home, ".verity"), { recursive: true });
|
|
20996
21685
|
moveFile(gateCreds, verityCreds);
|
|
20997
21686
|
actions.push("Moved ~/.gate/credentials \u2192 ~/.verity/credentials");
|
|
20998
21687
|
return;
|
|
@@ -21014,8 +21703,8 @@ async function migrateLegacyHooks(root, actions) {
|
|
|
21014
21703
|
}
|
|
21015
21704
|
}
|
|
21016
21705
|
async function migrateClaudeMd(root, actions) {
|
|
21017
|
-
const claudeMd = (0,
|
|
21018
|
-
const hadLegacyBlock = (0,
|
|
21706
|
+
const claudeMd = (0, import_node_path28.join)(root, "CLAUDE.md");
|
|
21707
|
+
const hadLegacyBlock = (0, import_node_fs36.existsSync)(claudeMd) && hasLegacyMemoryBlock(readFileSyncSafe(claudeMd));
|
|
21019
21708
|
if (!hadLegacyBlock) return;
|
|
21020
21709
|
try {
|
|
21021
21710
|
await ensureClaudeMdPointer(root);
|
|
@@ -21025,13 +21714,13 @@ async function migrateClaudeMd(root, actions) {
|
|
|
21025
21714
|
}
|
|
21026
21715
|
}
|
|
21027
21716
|
function migrateStandardFile(root, actions) {
|
|
21028
|
-
const gateMd = (0,
|
|
21029
|
-
const verityMd = (0,
|
|
21030
|
-
if (!(0,
|
|
21717
|
+
const gateMd = (0, import_node_path28.join)(root, "GATE.md");
|
|
21718
|
+
const verityMd = (0, import_node_path28.join)(root, "VERITY.md");
|
|
21719
|
+
if (!(0, import_node_fs36.existsSync)(gateMd) || (0, import_node_fs36.existsSync)(verityMd)) return;
|
|
21031
21720
|
let moved = false;
|
|
21032
21721
|
if (isGitRepo(root) && isGitTracked(root, "GATE.md")) {
|
|
21033
21722
|
try {
|
|
21034
|
-
(0,
|
|
21723
|
+
(0, import_node_child_process10.execSync)("git mv GATE.md VERITY.md", { cwd: root, stdio: "pipe" });
|
|
21035
21724
|
moved = true;
|
|
21036
21725
|
} catch {
|
|
21037
21726
|
}
|
|
@@ -21039,12 +21728,12 @@ function migrateStandardFile(root, actions) {
|
|
|
21039
21728
|
if (!moved) moveFile(gateMd, verityMd);
|
|
21040
21729
|
const content = readFileSyncSafe(verityMd);
|
|
21041
21730
|
const refreshed = content.split("GATE.md").join("VERITY.md");
|
|
21042
|
-
if (refreshed !== content) (0,
|
|
21731
|
+
if (refreshed !== content) (0, import_node_fs36.writeFileSync)(verityMd, refreshed);
|
|
21043
21732
|
actions.push("Renamed GATE.md \u2192 VERITY.md");
|
|
21044
21733
|
}
|
|
21045
21734
|
async function migrateTelemetryHeaders(root, actions) {
|
|
21046
|
-
const file = (0,
|
|
21047
|
-
if (!(0,
|
|
21735
|
+
const file = (0, import_node_path28.join)(root, ".claude", "settings.local.json");
|
|
21736
|
+
if (!(0, import_node_fs36.existsSync)(file)) return;
|
|
21048
21737
|
let settings;
|
|
21049
21738
|
try {
|
|
21050
21739
|
settings = JSON.parse(readFileSyncSafe(file) || "{}");
|
|
@@ -21091,22 +21780,22 @@ function mergeGlobalCredentials(gateCreds, verityCreds) {
|
|
|
21091
21780
|
toAppend.push(line.replace(/\r$/, ""));
|
|
21092
21781
|
}
|
|
21093
21782
|
if (toAppend.length > 0) {
|
|
21094
|
-
const
|
|
21095
|
-
(0,
|
|
21783
|
+
const sep2 = verityContent.endsWith("\n") || verityContent === "" ? "" : "\n";
|
|
21784
|
+
(0, import_node_fs36.writeFileSync)(verityCreds, verityContent + sep2 + toAppend.join("\n") + "\n");
|
|
21096
21785
|
}
|
|
21097
|
-
(0,
|
|
21786
|
+
(0, import_node_fs36.rmSync)(gateCreds, { force: true });
|
|
21098
21787
|
return toAppend.length;
|
|
21099
21788
|
}
|
|
21100
21789
|
function readFileSyncSafe(path) {
|
|
21101
21790
|
try {
|
|
21102
|
-
return (0,
|
|
21791
|
+
return (0, import_node_fs36.readFileSync)(path, "utf-8");
|
|
21103
21792
|
} catch {
|
|
21104
21793
|
return "";
|
|
21105
21794
|
}
|
|
21106
21795
|
}
|
|
21107
21796
|
function hasStagedChanges(root) {
|
|
21108
21797
|
try {
|
|
21109
|
-
(0,
|
|
21798
|
+
(0, import_node_child_process10.execSync)("git diff --cached --quiet", { cwd: root, stdio: "pipe" });
|
|
21110
21799
|
return false;
|
|
21111
21800
|
} catch {
|
|
21112
21801
|
return true;
|
|
@@ -21114,35 +21803,35 @@ function hasStagedChanges(root) {
|
|
|
21114
21803
|
}
|
|
21115
21804
|
function moveDir(from, to) {
|
|
21116
21805
|
try {
|
|
21117
|
-
(0,
|
|
21806
|
+
(0, import_node_fs36.renameSync)(from, to);
|
|
21118
21807
|
} catch (err) {
|
|
21119
21808
|
if (err.code !== "EXDEV") throw err;
|
|
21120
|
-
(0,
|
|
21121
|
-
(0,
|
|
21809
|
+
(0, import_node_fs36.cpSync)(from, to, { recursive: true });
|
|
21810
|
+
(0, import_node_fs36.rmSync)(from, { recursive: true, force: true });
|
|
21122
21811
|
}
|
|
21123
21812
|
}
|
|
21124
21813
|
function moveFile(from, to) {
|
|
21125
21814
|
try {
|
|
21126
|
-
(0,
|
|
21815
|
+
(0, import_node_fs36.renameSync)(from, to);
|
|
21127
21816
|
} catch (err) {
|
|
21128
21817
|
if (err.code !== "EXDEV") throw err;
|
|
21129
|
-
(0,
|
|
21130
|
-
(0,
|
|
21818
|
+
(0, import_node_fs36.cpSync)(from, to);
|
|
21819
|
+
(0, import_node_fs36.rmSync)(from, { force: true });
|
|
21131
21820
|
}
|
|
21132
21821
|
}
|
|
21133
21822
|
function carryLegacyContents(gateDir, verityDir) {
|
|
21134
21823
|
let copied = 0;
|
|
21135
21824
|
const walk = (relDir) => {
|
|
21136
|
-
const srcDir = (0,
|
|
21137
|
-
for (const entry of (0,
|
|
21138
|
-
const rel = relDir ? (0,
|
|
21139
|
-
const src = (0,
|
|
21140
|
-
const dest = (0,
|
|
21141
|
-
if ((0,
|
|
21825
|
+
const srcDir = (0, import_node_path28.join)(gateDir, relDir);
|
|
21826
|
+
for (const entry of (0, import_node_fs36.readdirSync)(srcDir)) {
|
|
21827
|
+
const rel = relDir ? (0, import_node_path28.join)(relDir, entry) : entry;
|
|
21828
|
+
const src = (0, import_node_path28.join)(gateDir, rel);
|
|
21829
|
+
const dest = (0, import_node_path28.join)(verityDir, rel);
|
|
21830
|
+
if ((0, import_node_fs36.statSync)(src).isDirectory()) {
|
|
21142
21831
|
walk(rel);
|
|
21143
|
-
} else if (!(0,
|
|
21144
|
-
(0,
|
|
21145
|
-
(0,
|
|
21832
|
+
} else if (!(0, import_node_fs36.existsSync)(dest)) {
|
|
21833
|
+
(0, import_node_fs36.mkdirSync)((0, import_node_path28.dirname)(dest), { recursive: true });
|
|
21834
|
+
(0, import_node_fs36.cpSync)(src, dest);
|
|
21146
21835
|
copied++;
|
|
21147
21836
|
}
|
|
21148
21837
|
}
|
|
@@ -21151,22 +21840,22 @@ function carryLegacyContents(gateDir, verityDir) {
|
|
|
21151
21840
|
return copied;
|
|
21152
21841
|
}
|
|
21153
21842
|
async function needsMigration(root = repoRoot()) {
|
|
21154
|
-
const gateDir = (0,
|
|
21155
|
-
const verityDir = (0,
|
|
21156
|
-
if ((0,
|
|
21157
|
-
if ((0,
|
|
21158
|
-
if ((0,
|
|
21843
|
+
const gateDir = (0, import_node_path28.join)(root, ".gate");
|
|
21844
|
+
const verityDir = (0, import_node_path28.join)(root, ".verity");
|
|
21845
|
+
if ((0, import_node_fs36.existsSync)(gateDir) && !(0, import_node_fs36.existsSync)(verityDir)) return true;
|
|
21846
|
+
if ((0, import_node_fs36.existsSync)(gateDir) && (0, import_node_fs36.existsSync)(verityDir)) {
|
|
21847
|
+
if ((0, import_node_fs36.existsSync)((0, import_node_path28.join)(gateDir, "credentials")) && !(0, import_node_fs36.existsSync)((0, import_node_path28.join)(verityDir, "credentials"))) {
|
|
21159
21848
|
return true;
|
|
21160
21849
|
}
|
|
21161
|
-
if ((0,
|
|
21850
|
+
if ((0, import_node_fs36.existsSync)((0, import_node_path28.join)(gateDir, "memory")) && !(0, import_node_fs36.existsSync)((0, import_node_path28.join)(verityDir, "memory"))) {
|
|
21162
21851
|
return true;
|
|
21163
21852
|
}
|
|
21164
21853
|
}
|
|
21165
|
-
const claudeMd = (0,
|
|
21166
|
-
if ((0,
|
|
21854
|
+
const claudeMd = (0, import_node_path28.join)(root, "CLAUDE.md");
|
|
21855
|
+
if ((0, import_node_fs36.existsSync)(claudeMd) && hasLegacyMemoryBlock(readFileSyncSafe(claudeMd))) {
|
|
21167
21856
|
return true;
|
|
21168
21857
|
}
|
|
21169
|
-
if ((0,
|
|
21858
|
+
if ((0, import_node_fs36.existsSync)((0, import_node_path28.join)(root, "GATE.md")) && !(0, import_node_fs36.existsSync)((0, import_node_path28.join)(root, "VERITY.md"))) {
|
|
21170
21859
|
return true;
|
|
21171
21860
|
}
|
|
21172
21861
|
if (await hasLegacyHooksAt(root)) return true;
|
|
@@ -21248,6 +21937,8 @@ async function confirmExistingLogin(serviceUrl, remote, opts) {
|
|
|
21248
21937
|
async function runOptionalAuth(resolution, opts = {}) {
|
|
21249
21938
|
if (resolution.source === "default") {
|
|
21250
21939
|
printInfo(`No Verity service configured on this machine \u2014 using the default: ${resolution.url}`);
|
|
21940
|
+
} else {
|
|
21941
|
+
printInfo(`Authenticating against ${resolution.url} (source: ${resolution.source}).`);
|
|
21251
21942
|
}
|
|
21252
21943
|
const heal = await maybeHealServiceUrl(resolution, opts.verbose);
|
|
21253
21944
|
const serviceUrl = heal.serviceUrl;
|
|
@@ -21257,7 +21948,7 @@ async function runOptionalAuth(resolution, opts = {}) {
|
|
|
21257
21948
|
}
|
|
21258
21949
|
let remote = "";
|
|
21259
21950
|
try {
|
|
21260
|
-
remote = (0,
|
|
21951
|
+
remote = (0, import_node_child_process11.execSync)("git remote get-url origin", { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
|
|
21261
21952
|
} catch {
|
|
21262
21953
|
}
|
|
21263
21954
|
if (!healed) {
|
|
@@ -21300,15 +21991,15 @@ async function runOptionalAuth(resolution, opts = {}) {
|
|
|
21300
21991
|
}
|
|
21301
21992
|
function resolveDataDir() {
|
|
21302
21993
|
const candidates = [
|
|
21303
|
-
(0,
|
|
21994
|
+
(0, import_node_path29.join)(__dirname, "..", "data"),
|
|
21304
21995
|
// installed: node_modules/@codacy/verity-cli/data
|
|
21305
|
-
(0,
|
|
21996
|
+
(0, import_node_path29.join)(__dirname, "..", "..", "data"),
|
|
21306
21997
|
// edge case: nested resolution
|
|
21307
|
-
(0,
|
|
21998
|
+
(0, import_node_path29.join)(process.cwd(), "cli", "data")
|
|
21308
21999
|
// local dev: running from repo root
|
|
21309
22000
|
];
|
|
21310
22001
|
for (const candidate of candidates) {
|
|
21311
|
-
if ((0,
|
|
22002
|
+
if ((0, import_node_fs37.existsSync)((0, import_node_path29.join)(candidate, "skills"))) {
|
|
21312
22003
|
return candidate;
|
|
21313
22004
|
}
|
|
21314
22005
|
}
|
|
@@ -21324,7 +22015,7 @@ function registerInitCommand(program2) {
|
|
|
21324
22015
|
program2.command("init").description("Initialize Verity in the current project").option("--force", "Overwrite existing skills and hooks").action(async (opts) => {
|
|
21325
22016
|
const force = opts.force ?? false;
|
|
21326
22017
|
const projectMarkers = [".git", "package.json", "pyproject.toml", "go.mod", "Cargo.toml", "Gemfile", "pom.xml", "build.gradle"];
|
|
21327
|
-
const isProject = projectMarkers.some((m) => (0,
|
|
22018
|
+
const isProject = projectMarkers.some((m) => (0, import_node_fs37.existsSync)(m));
|
|
21328
22019
|
if (!isProject) {
|
|
21329
22020
|
printError("No project detected in the current directory.");
|
|
21330
22021
|
printInfo('Run "verity init" from your project root.');
|
|
@@ -21352,30 +22043,30 @@ function registerInitCommand(program2) {
|
|
|
21352
22043
|
}
|
|
21353
22044
|
printInfo(` Node.js ${nodeVersion} \u2713`);
|
|
21354
22045
|
try {
|
|
21355
|
-
const gitVersion = (0,
|
|
22046
|
+
const gitVersion = (0, import_node_child_process11.execSync)("git --version", { encoding: "utf-8" }).trim();
|
|
21356
22047
|
printInfo(` ${gitVersion} \u2713`);
|
|
21357
22048
|
} catch {
|
|
21358
22049
|
printError("git is required but not installed. Install from https://git-scm.com");
|
|
21359
22050
|
process.exit(1);
|
|
21360
22051
|
}
|
|
21361
22052
|
try {
|
|
21362
|
-
(0,
|
|
22053
|
+
(0, import_node_child_process11.execSync)("which claude", { encoding: "utf-8" });
|
|
21363
22054
|
printInfo(" Claude Code \u2713");
|
|
21364
22055
|
} catch {
|
|
21365
22056
|
printWarn(" Claude Code not found \u2014 hooks will be configured but need Claude Code to run.");
|
|
21366
22057
|
}
|
|
21367
22058
|
try {
|
|
21368
|
-
(0,
|
|
22059
|
+
(0, import_node_child_process11.execSync)("which codacy-analysis", { encoding: "utf-8", stdio: "pipe" });
|
|
21369
22060
|
printInfo(" @codacy/analysis-cli \u2713");
|
|
21370
22061
|
} catch {
|
|
21371
22062
|
printInfo(" Installing @codacy/analysis-cli...");
|
|
21372
22063
|
try {
|
|
21373
|
-
(0,
|
|
22064
|
+
(0, import_node_child_process11.execSync)("npm install -g @codacy/analysis-cli", { encoding: "utf-8", stdio: "pipe", timeout: 12e4 });
|
|
21374
22065
|
printInfo(" @codacy/analysis-cli installed \u2713");
|
|
21375
22066
|
} catch {
|
|
21376
22067
|
try {
|
|
21377
22068
|
printWarn(" Retrying with sudo...");
|
|
21378
|
-
(0,
|
|
22069
|
+
(0, import_node_child_process11.execSync)("sudo npm install -g @codacy/analysis-cli", { encoding: "utf-8", stdio: "inherit", timeout: 12e4 });
|
|
21379
22070
|
printInfo(" @codacy/analysis-cli installed \u2713");
|
|
21380
22071
|
} catch {
|
|
21381
22072
|
printWarn(" Could not install @codacy/analysis-cli automatically.");
|
|
@@ -21387,21 +22078,21 @@ function registerInitCommand(program2) {
|
|
|
21387
22078
|
console.log("");
|
|
21388
22079
|
printInfo("Installing skills...");
|
|
21389
22080
|
const dataDir = resolveDataDir();
|
|
21390
|
-
const skillsSource = (0,
|
|
22081
|
+
const skillsSource = (0, import_node_path29.join)(dataDir, "skills");
|
|
21391
22082
|
const skillsDest = ".claude/skills";
|
|
21392
22083
|
const skills = ["verity-setup", "verity-analyze", "verity-status", "verity-feedback", "verity-learn", "verity-memory", "verity-insights", "verity-reflect"];
|
|
21393
22084
|
let skillsInstalled = 0;
|
|
21394
22085
|
for (const skill of skills) {
|
|
21395
|
-
const src = (0,
|
|
21396
|
-
const dest = (0,
|
|
21397
|
-
if (!(0,
|
|
22086
|
+
const src = (0, import_node_path29.join)(skillsSource, skill);
|
|
22087
|
+
const dest = (0, import_node_path29.join)(skillsDest, skill);
|
|
22088
|
+
if (!(0, import_node_fs37.existsSync)(src)) {
|
|
21398
22089
|
printWarn(` Skill data not found: ${skill}`);
|
|
21399
22090
|
continue;
|
|
21400
22091
|
}
|
|
21401
|
-
if ((0,
|
|
21402
|
-
const srcSkill = (0,
|
|
21403
|
-
const destSkill = (0,
|
|
21404
|
-
if ((0,
|
|
22092
|
+
if ((0, import_node_fs37.existsSync)(dest) && !force) {
|
|
22093
|
+
const srcSkill = (0, import_node_path29.join)(src, "SKILL.md");
|
|
22094
|
+
const destSkill = (0, import_node_path29.join)(dest, "SKILL.md");
|
|
22095
|
+
if ((0, import_node_fs37.existsSync)(destSkill)) {
|
|
21405
22096
|
try {
|
|
21406
22097
|
const srcContent = await (0, import_promises13.readFile)(srcSkill, "utf-8");
|
|
21407
22098
|
const destContent = await (0, import_promises13.readFile)(destSkill, "utf-8");
|
|
@@ -21432,13 +22123,19 @@ function registerInitCommand(program2) {
|
|
|
21432
22123
|
}
|
|
21433
22124
|
await (0, import_promises13.mkdir)(VERITY_DIR, { recursive: true });
|
|
21434
22125
|
await ensureMemoryDir();
|
|
22126
|
+
const ignoreResult = ensureSnapshotGitignored();
|
|
22127
|
+
if (ignoreResult === "failed") {
|
|
22128
|
+
printWarn(" .gitignore: could not add .verity/.snapshot/ \u2014 add it manually (it holds copies of analyzed files)");
|
|
22129
|
+
} else {
|
|
22130
|
+
printInfo(` .gitignore: .verity/.snapshot/ ${ignoreResult === "added" ? "added" : "already covered"} \u2713`);
|
|
22131
|
+
}
|
|
21435
22132
|
try {
|
|
21436
22133
|
await ensureClaudeMdPointer();
|
|
21437
22134
|
printInfo(" CLAUDE.md memory pointer \u2713");
|
|
21438
22135
|
} catch (err) {
|
|
21439
22136
|
printWarn(` Could not update CLAUDE.md: ${err.message}`);
|
|
21440
22137
|
}
|
|
21441
|
-
const globalVerityDir = (0,
|
|
22138
|
+
const globalVerityDir = (0, import_node_path29.join)(process.env.HOME ?? "", ".verity");
|
|
21442
22139
|
await (0, import_promises13.mkdir)(globalVerityDir, { recursive: true });
|
|
21443
22140
|
console.log("");
|
|
21444
22141
|
try {
|
|
@@ -21473,8 +22170,8 @@ function registerInitCommand(program2) {
|
|
|
21473
22170
|
}
|
|
21474
22171
|
|
|
21475
22172
|
// src/commands/uninstall.ts
|
|
21476
|
-
var
|
|
21477
|
-
var
|
|
22173
|
+
var import_node_fs38 = require("node:fs");
|
|
22174
|
+
var import_node_path30 = require("node:path");
|
|
21478
22175
|
var SKILL_NAMES = [
|
|
21479
22176
|
"verity-setup",
|
|
21480
22177
|
"verity-analyze",
|
|
@@ -21493,11 +22190,11 @@ function registerUninstallCommand(program2) {
|
|
|
21493
22190
|
const actions = [];
|
|
21494
22191
|
const skillsRoot = projectPath(".claude/skills");
|
|
21495
22192
|
for (const name of SKILL_NAMES) {
|
|
21496
|
-
const dir = (0,
|
|
21497
|
-
if ((0,
|
|
22193
|
+
const dir = (0, import_node_path30.join)(skillsRoot, name);
|
|
22194
|
+
if ((0, import_node_fs38.existsSync)(dir)) {
|
|
21498
22195
|
actions.push({
|
|
21499
22196
|
label: `Remove .claude/skills/${name}/`,
|
|
21500
|
-
apply: () => (0,
|
|
22197
|
+
apply: () => (0, import_node_fs38.rmSync)(dir, { recursive: true, force: true })
|
|
21501
22198
|
});
|
|
21502
22199
|
}
|
|
21503
22200
|
}
|
|
@@ -21511,24 +22208,24 @@ function registerUninstallCommand(program2) {
|
|
|
21511
22208
|
});
|
|
21512
22209
|
}
|
|
21513
22210
|
const verityDir = projectPath(VERITY_DIR);
|
|
21514
|
-
if ((0,
|
|
22211
|
+
if ((0, import_node_fs38.existsSync)(verityDir)) {
|
|
21515
22212
|
actions.push({
|
|
21516
22213
|
label: `Remove ${VERITY_DIR}/`,
|
|
21517
|
-
apply: () => (0,
|
|
22214
|
+
apply: () => (0, import_node_fs38.rmSync)(verityDir, { recursive: true, force: true })
|
|
21518
22215
|
});
|
|
21519
22216
|
}
|
|
21520
22217
|
if (!keepVerityMd) {
|
|
21521
22218
|
const verityMd = projectPath(VERITY_MD_FILE);
|
|
21522
|
-
if ((0,
|
|
22219
|
+
if ((0, import_node_fs38.existsSync)(verityMd)) {
|
|
21523
22220
|
actions.push({
|
|
21524
22221
|
label: `Remove ${VERITY_MD_FILE}`,
|
|
21525
|
-
apply: () => (0,
|
|
22222
|
+
apply: () => (0, import_node_fs38.rmSync)(verityMd, { force: true })
|
|
21526
22223
|
});
|
|
21527
22224
|
}
|
|
21528
22225
|
}
|
|
21529
22226
|
const cleanupEmptyDir = (path) => {
|
|
21530
|
-
if ((0,
|
|
21531
|
-
(0,
|
|
22227
|
+
if ((0, import_node_fs38.existsSync)(path) && (0, import_node_fs38.statSync)(path).isDirectory() && (0, import_node_fs38.readdirSync)(path).length === 0) {
|
|
22228
|
+
(0, import_node_fs38.rmdirSync)(path);
|
|
21532
22229
|
}
|
|
21533
22230
|
};
|
|
21534
22231
|
actions.push({
|
|
@@ -21539,11 +22236,11 @@ function registerUninstallCommand(program2) {
|
|
|
21539
22236
|
}
|
|
21540
22237
|
});
|
|
21541
22238
|
const home = process.env.HOME ?? "";
|
|
21542
|
-
const globalVerityDir = (0,
|
|
21543
|
-
if (purgeGlobal && (0,
|
|
22239
|
+
const globalVerityDir = (0, import_node_path30.join)(home, ".verity");
|
|
22240
|
+
if (purgeGlobal && (0, import_node_fs38.existsSync)(globalVerityDir)) {
|
|
21544
22241
|
actions.push({
|
|
21545
22242
|
label: `Remove ~/.verity/ (global credentials \u2014 reconnect requires re-registration)`,
|
|
21546
|
-
apply: () => (0,
|
|
22243
|
+
apply: () => (0, import_node_fs38.rmSync)(globalVerityDir, { recursive: true, force: true })
|
|
21547
22244
|
});
|
|
21548
22245
|
}
|
|
21549
22246
|
if (actions.length === 0) {
|
|
@@ -21737,8 +22434,8 @@ function registerTaskCommands(program2) {
|
|
|
21737
22434
|
}
|
|
21738
22435
|
|
|
21739
22436
|
// src/commands/reset.ts
|
|
21740
|
-
var
|
|
21741
|
-
var
|
|
22437
|
+
var import_node_fs39 = require("node:fs");
|
|
22438
|
+
var import_node_path31 = require("node:path");
|
|
21742
22439
|
function registerResetCommand(program2) {
|
|
21743
22440
|
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) => {
|
|
21744
22441
|
const globals = program2.opts();
|
|
@@ -21775,11 +22472,11 @@ function registerResetCommand(program2) {
|
|
|
21775
22472
|
}
|
|
21776
22473
|
const cacheDir = projectPath(CACHE_DIR);
|
|
21777
22474
|
let purged = 0;
|
|
21778
|
-
if ((0,
|
|
21779
|
-
for (const entry of (0,
|
|
22475
|
+
if ((0, import_node_fs39.existsSync)(cacheDir)) {
|
|
22476
|
+
for (const entry of (0, import_node_fs39.readdirSync)(cacheDir)) {
|
|
21780
22477
|
if (entry.startsWith("pending-")) {
|
|
21781
22478
|
try {
|
|
21782
|
-
(0,
|
|
22479
|
+
(0, import_node_fs39.unlinkSync)((0, import_node_path31.join)(cacheDir, entry));
|
|
21783
22480
|
purged++;
|
|
21784
22481
|
} catch {
|
|
21785
22482
|
}
|
|
@@ -21794,19 +22491,19 @@ function registerResetCommand(program2) {
|
|
|
21794
22491
|
projectPath(`${VERITY_DIR}/.last-analysis`)
|
|
21795
22492
|
];
|
|
21796
22493
|
for (const file of filesToClear) {
|
|
21797
|
-
if ((0,
|
|
22494
|
+
if ((0, import_node_fs39.existsSync)(file)) {
|
|
21798
22495
|
try {
|
|
21799
|
-
(0,
|
|
22496
|
+
(0, import_node_fs39.writeFileSync)(file, "");
|
|
21800
22497
|
} catch {
|
|
21801
22498
|
}
|
|
21802
22499
|
}
|
|
21803
22500
|
}
|
|
21804
22501
|
if (opts.all) {
|
|
21805
22502
|
const logsDir = projectPath(`${VERITY_DIR}/.logs`);
|
|
21806
|
-
if ((0,
|
|
21807
|
-
for (const entry of (0,
|
|
22503
|
+
if ((0, import_node_fs39.existsSync)(logsDir)) {
|
|
22504
|
+
for (const entry of (0, import_node_fs39.readdirSync)(logsDir)) {
|
|
21808
22505
|
try {
|
|
21809
|
-
(0,
|
|
22506
|
+
(0, import_node_fs39.unlinkSync)((0, import_node_path31.join)(logsDir, entry));
|
|
21810
22507
|
} catch {
|
|
21811
22508
|
}
|
|
21812
22509
|
}
|
|
@@ -22114,8 +22811,8 @@ function registerTelemetryCommands(program2) {
|
|
|
22114
22811
|
}
|
|
22115
22812
|
|
|
22116
22813
|
// src/cli.ts
|
|
22117
|
-
program.name("verity").description("CLI for Verity quality gate service").version("0.
|
|
22118
|
-
installStderrLog(actionCommand.name(), process.argv.slice(2), "0.
|
|
22814
|
+
program.name("verity").description("CLI for Verity quality gate service").version("0.30.0-experimental.452ead4").option("--token <token>", "Override authentication token").option("--service-url <url>", "Override service URL").option("--verbose", "Log HTTP requests/responses to stderr").hook("preAction", async (_thisCommand, actionCommand) => {
|
|
22815
|
+
installStderrLog(actionCommand.name(), process.argv.slice(2), "0.30.0-experimental.452ead4");
|
|
22119
22816
|
setUserNamedServiceUrl(program.opts().serviceUrl);
|
|
22120
22817
|
try {
|
|
22121
22818
|
await foldLegacyLocalCredential();
|