@codacy/verity-cli 0.32.0 → 0.32.1-experimental.c640abd
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 +235 -52
- package/bin/verity.js +813 -371
- package/package.json +1 -1
package/bin/verity.js
CHANGED
|
@@ -911,18 +911,18 @@ var require_suggestSimilar = __commonJS({
|
|
|
911
911
|
}
|
|
912
912
|
return d[a.length][b.length];
|
|
913
913
|
}
|
|
914
|
-
function suggestSimilar(word,
|
|
915
|
-
if (!
|
|
916
|
-
|
|
914
|
+
function suggestSimilar(word, candidates2) {
|
|
915
|
+
if (!candidates2 || candidates2.length === 0) return "";
|
|
916
|
+
candidates2 = Array.from(new Set(candidates2));
|
|
917
917
|
const searchingOptions = word.startsWith("--");
|
|
918
918
|
if (searchingOptions) {
|
|
919
919
|
word = word.slice(2);
|
|
920
|
-
|
|
920
|
+
candidates2 = candidates2.map((candidate) => candidate.slice(2));
|
|
921
921
|
}
|
|
922
922
|
let similar = [];
|
|
923
923
|
let bestDistance = maxDistance;
|
|
924
924
|
const minSimilarity = 0.4;
|
|
925
|
-
|
|
925
|
+
candidates2.forEach((candidate) => {
|
|
926
926
|
if (candidate.length <= 1) return;
|
|
927
927
|
const distance = editDistance(word, candidate);
|
|
928
928
|
const length = Math.max(word.length, candidate.length);
|
|
@@ -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:
|
|
6977
|
+
const { start, key, sep: sep3, value } = collItem;
|
|
6978
6978
|
const keyProps = resolveProps.resolveProps(start, {
|
|
6979
6979
|
indicator: "explicit-key-ind",
|
|
6980
|
-
next: key ??
|
|
6980
|
+
next: key ?? sep3?.[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 && !sep3) {
|
|
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(sep3 ?? [], {
|
|
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, sep3, 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 sep3 = "";
|
|
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 += sep3 + cb;
|
|
7140
|
+
sep3 = "";
|
|
7141
7141
|
break;
|
|
7142
7142
|
}
|
|
7143
7143
|
case "newline":
|
|
7144
7144
|
if (comment)
|
|
7145
|
-
|
|
7145
|
+
sep3 += 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:
|
|
7188
|
+
const { start, key, sep: sep3, 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 ?? sep3?.[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 && !sep3 && !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 && !sep3 && !props.found) {
|
|
7254
|
+
const valueNode = value ? composeNode(ctx, value, props, onError) : composeEmptyNode(ctx, props.end, sep3, 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(sep3 ?? [], {
|
|
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 (sep3)
|
|
7278
|
+
for (const st of sep3) {
|
|
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, sep3, 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 sep3 = "";
|
|
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 += sep3 + indent.slice(trimIndent) + content;
|
|
7493
|
+
sep3 = "\n";
|
|
7494
7494
|
} else if (indent.length > trimIndent || content[0] === " ") {
|
|
7495
|
-
if (
|
|
7496
|
-
|
|
7497
|
-
else if (!prevMoreIndented &&
|
|
7498
|
-
|
|
7499
|
-
value +=
|
|
7500
|
-
|
|
7495
|
+
if (sep3 === " ")
|
|
7496
|
+
sep3 = "\n";
|
|
7497
|
+
else if (!prevMoreIndented && sep3 === "\n")
|
|
7498
|
+
sep3 = "\n\n";
|
|
7499
|
+
value += sep3 + indent.slice(trimIndent) + content;
|
|
7500
|
+
sep3 = "\n";
|
|
7501
7501
|
prevMoreIndented = true;
|
|
7502
7502
|
} else if (content === "") {
|
|
7503
|
-
if (
|
|
7503
|
+
if (sep3 === "\n")
|
|
7504
7504
|
value += "\n";
|
|
7505
7505
|
else
|
|
7506
|
-
|
|
7506
|
+
sep3 = "\n";
|
|
7507
7507
|
} else {
|
|
7508
|
-
value +=
|
|
7509
|
-
|
|
7508
|
+
value += sep3 + content;
|
|
7509
|
+
sep3 = " ";
|
|
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 sep3 = " ";
|
|
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 (sep3 === "\n")
|
|
7693
|
+
res += sep3;
|
|
7694
7694
|
else
|
|
7695
|
-
|
|
7695
|
+
sep3 = "\n";
|
|
7696
7696
|
} else {
|
|
7697
|
-
res +=
|
|
7698
|
-
|
|
7697
|
+
res += sep3 + match[1];
|
|
7698
|
+
sep3 = " ";
|
|
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 + sep3 + (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:
|
|
8512
|
+
function stringifyItem({ start, key, sep: sep3, 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 (sep3)
|
|
8519
|
+
for (const st of sep3)
|
|
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 sep3;
|
|
9663
9663
|
if (scalar.end) {
|
|
9664
|
-
|
|
9665
|
-
|
|
9664
|
+
sep3 = scalar.end;
|
|
9665
|
+
sep3.push(this.sourceToken);
|
|
9666
9666
|
delete scalar.end;
|
|
9667
9667
|
} else
|
|
9668
|
-
|
|
9668
|
+
sep3 = [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: sep3 }]
|
|
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 sep3 = it.sep;
|
|
9826
|
+
sep3.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: sep3 }]
|
|
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 sep3 = fc.end.splice(1, fc.end.length);
|
|
10028
|
+
sep3.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: sep3 }]
|
|
10034
10034
|
};
|
|
10035
10035
|
this.onKeyLine = true;
|
|
10036
10036
|
this.stack[this.stack.length - 1] = map;
|
|
@@ -10509,7 +10509,7 @@ var SECURITY_PATTERNS = [
|
|
|
10509
10509
|
/Dockerfile/
|
|
10510
10510
|
];
|
|
10511
10511
|
var PROD_SERVICE_URL = "https://ofcamwrjwrkazqvdchko.supabase.co/functions/v1";
|
|
10512
|
-
var DEFAULT_SERVICE_URL = "".length > 0 ? "" : PROD_SERVICE_URL;
|
|
10512
|
+
var DEFAULT_SERVICE_URL = "https://wukeddyzpijoegyajtnc.supabase.co/functions/v1".length > 0 ? "https://wukeddyzpijoegyajtnc.supabase.co/functions/v1" : PROD_SERVICE_URL;
|
|
10513
10513
|
var GITHUB_CLIENT_ID = "Iv23li88HxAi3ZrbYzWh";
|
|
10514
10514
|
var GITHUB_DEVICE_CODE_URL = "https://github.com/login/device/code";
|
|
10515
10515
|
var GITHUB_ACCESS_TOKEN_URL = "https://github.com/login/oauth/access_token";
|
|
@@ -11519,7 +11519,7 @@ function startSpinner(label2, opts = {}) {
|
|
|
11519
11519
|
}
|
|
11520
11520
|
|
|
11521
11521
|
// src/lib/provider-auth.ts
|
|
11522
|
-
var sleep = (ms) => new Promise((
|
|
11522
|
+
var sleep = (ms) => new Promise((resolve5) => setTimeout(resolve5, ms));
|
|
11523
11523
|
var form = (fields) => new URLSearchParams(fields).toString();
|
|
11524
11524
|
async function githubAccountId(owner) {
|
|
11525
11525
|
try {
|
|
@@ -12735,6 +12735,7 @@ async function applyMomentSelection(moments) {
|
|
|
12735
12735
|
|
|
12736
12736
|
// src/lib/project-config.ts
|
|
12737
12737
|
var import_node_fs4 = require("node:fs");
|
|
12738
|
+
var import_node_path6 = require("node:path");
|
|
12738
12739
|
var DEFAULTS = { git_moments: [] };
|
|
12739
12740
|
function isMoment(value) {
|
|
12740
12741
|
return value === "commit" || value === "push";
|
|
@@ -12742,20 +12743,40 @@ function isMoment(value) {
|
|
|
12742
12743
|
function parseMoments(raw) {
|
|
12743
12744
|
return [...new Set(raw.split(",").map((s) => s.trim()).filter(isMoment))];
|
|
12744
12745
|
}
|
|
12745
|
-
function
|
|
12746
|
+
function readConfigFile(path) {
|
|
12746
12747
|
try {
|
|
12747
|
-
if (!(0, import_node_fs4.existsSync)(
|
|
12748
|
-
const raw = JSON.parse((0, import_node_fs4.readFileSync)(
|
|
12748
|
+
if (!(0, import_node_fs4.existsSync)(path)) return null;
|
|
12749
|
+
const raw = JSON.parse((0, import_node_fs4.readFileSync)(path, "utf-8"));
|
|
12749
12750
|
const moments = Array.isArray(raw.git_moments) ? raw.git_moments.filter(isMoment) : [];
|
|
12750
|
-
|
|
12751
|
+
const source = raw.git_moments_source === "user" || raw.git_moments_source === "init" ? raw.git_moments_source : void 0;
|
|
12752
|
+
return { git_moments: [...new Set(moments)], ...source ? { git_moments_source: source } : {} };
|
|
12751
12753
|
} catch {
|
|
12752
12754
|
return DEFAULTS;
|
|
12753
12755
|
}
|
|
12754
12756
|
}
|
|
12757
|
+
function candidates() {
|
|
12758
|
+
const local = projectPath(PROJECT_CONFIG_FILE);
|
|
12759
|
+
const out = [{ path: local, source: "local" }];
|
|
12760
|
+
const main = mainWorktreeRoot();
|
|
12761
|
+
if (main) {
|
|
12762
|
+
const inherited = (0, import_node_path6.join)(main, PROJECT_CONFIG_FILE);
|
|
12763
|
+
if (inherited !== local) out.push({ path: inherited, source: "main-worktree" });
|
|
12764
|
+
}
|
|
12765
|
+
return out;
|
|
12766
|
+
}
|
|
12767
|
+
function readProjectConfig() {
|
|
12768
|
+
for (const { path, source } of candidates()) {
|
|
12769
|
+
const cfg = readConfigFile(path);
|
|
12770
|
+
if (cfg) return { ...cfg, source, path };
|
|
12771
|
+
}
|
|
12772
|
+
return { ...DEFAULTS, source: "default" };
|
|
12773
|
+
}
|
|
12755
12774
|
function writeProjectConfig(patch) {
|
|
12756
|
-
const
|
|
12757
|
-
|
|
12758
|
-
|
|
12775
|
+
const { git_moments, git_moments_source } = readProjectConfig();
|
|
12776
|
+
const next = { git_moments, ...git_moments_source ? { git_moments_source } : {}, ...patch };
|
|
12777
|
+
const target = projectPath(PROJECT_CONFIG_FILE);
|
|
12778
|
+
(0, import_node_fs4.mkdirSync)((0, import_node_path6.dirname)(target), { recursive: true });
|
|
12779
|
+
(0, import_node_fs4.writeFileSync)(target, JSON.stringify(next, null, 2) + "\n");
|
|
12759
12780
|
return next;
|
|
12760
12781
|
}
|
|
12761
12782
|
function resolveGuardMoments(explicit) {
|
|
@@ -12765,6 +12786,8 @@ function resolveGuardMoments(explicit) {
|
|
|
12765
12786
|
|
|
12766
12787
|
// src/lib/plugin-ownership.ts
|
|
12767
12788
|
var import_node_fs6 = require("node:fs");
|
|
12789
|
+
var import_node_os2 = require("node:os");
|
|
12790
|
+
var import_node_path7 = require("node:path");
|
|
12768
12791
|
|
|
12769
12792
|
// src/lib/stderr-log.ts
|
|
12770
12793
|
var import_node_fs5 = require("node:fs");
|
|
@@ -12821,16 +12844,19 @@ function logToFileOnly(text) {
|
|
|
12821
12844
|
}
|
|
12822
12845
|
|
|
12823
12846
|
// src/lib/plugin-ownership.ts
|
|
12824
|
-
var
|
|
12847
|
+
var CONTROL_CHARS = /[\u0000-\u001f\u007f]/;
|
|
12825
12848
|
function isPluginInvocation() {
|
|
12826
12849
|
return !!process.env.VERITY_PLUGIN_ROOT;
|
|
12827
12850
|
}
|
|
12851
|
+
function markerPath() {
|
|
12852
|
+
return projectPath(PLUGIN_MARKER_FILE);
|
|
12853
|
+
}
|
|
12828
12854
|
function readMarker() {
|
|
12829
12855
|
try {
|
|
12830
|
-
if (!(0, import_node_fs6.existsSync)(
|
|
12831
|
-
const raw = JSON.parse((0, import_node_fs6.readFileSync)(
|
|
12856
|
+
if (!(0, import_node_fs6.existsSync)(markerPath())) return null;
|
|
12857
|
+
const raw = JSON.parse((0, import_node_fs6.readFileSync)(markerPath(), "utf-8"));
|
|
12832
12858
|
const pluginRoot = typeof raw.plugin_root === "string" ? raw.plugin_root : "";
|
|
12833
|
-
if (!pluginRoot) return null;
|
|
12859
|
+
if (!pluginRoot || CONTROL_CHARS.test(pluginRoot)) return null;
|
|
12834
12860
|
return {
|
|
12835
12861
|
session_id: typeof raw.session_id === "string" ? raw.session_id : null,
|
|
12836
12862
|
plugin_root: pluginRoot,
|
|
@@ -12845,17 +12871,109 @@ function recordPluginOwnership(sessionId) {
|
|
|
12845
12871
|
const pluginRoot = process.env.VERITY_PLUGIN_ROOT;
|
|
12846
12872
|
if (!pluginRoot) return;
|
|
12847
12873
|
try {
|
|
12848
|
-
(0, import_node_fs6.mkdirSync)(VERITY_DIR, { recursive: true });
|
|
12874
|
+
(0, import_node_fs6.mkdirSync)(projectPath(VERITY_DIR), { recursive: true });
|
|
12849
12875
|
const marker = {
|
|
12850
12876
|
session_id: sessionId,
|
|
12851
12877
|
plugin_root: pluginRoot,
|
|
12852
12878
|
version: process.env.VERITY_PLUGIN_VERSION || null,
|
|
12853
12879
|
ts: Math.floor(Date.now() / 1e3)
|
|
12854
12880
|
};
|
|
12855
|
-
(0, import_node_fs6.writeFileSync)(
|
|
12881
|
+
(0, import_node_fs6.writeFileSync)(markerPath(), JSON.stringify(marker));
|
|
12856
12882
|
} catch {
|
|
12857
12883
|
}
|
|
12858
12884
|
}
|
|
12885
|
+
function claudeConfigDir() {
|
|
12886
|
+
return process.env.CLAUDE_CONFIG_DIR || (0, import_node_path7.join)((0, import_node_os2.homedir)(), ".claude");
|
|
12887
|
+
}
|
|
12888
|
+
function readJsonFile(path) {
|
|
12889
|
+
try {
|
|
12890
|
+
const parsed = JSON.parse((0, import_node_fs6.readFileSync)(path, "utf-8"));
|
|
12891
|
+
return parsed && typeof parsed === "object" ? parsed : null;
|
|
12892
|
+
} catch {
|
|
12893
|
+
return null;
|
|
12894
|
+
}
|
|
12895
|
+
}
|
|
12896
|
+
function enabledPluginSetting(key) {
|
|
12897
|
+
const files = [
|
|
12898
|
+
projectPath((0, import_node_path7.join)(".claude", "settings.local.json")),
|
|
12899
|
+
projectPath((0, import_node_path7.join)(".claude", "settings.json")),
|
|
12900
|
+
(0, import_node_path7.join)(claudeConfigDir(), "settings.json")
|
|
12901
|
+
];
|
|
12902
|
+
for (const file of files) {
|
|
12903
|
+
const map = readJsonFile(file)?.enabledPlugins;
|
|
12904
|
+
if (map && typeof map === "object" && key in map) {
|
|
12905
|
+
return map[key] !== false;
|
|
12906
|
+
}
|
|
12907
|
+
}
|
|
12908
|
+
return void 0;
|
|
12909
|
+
}
|
|
12910
|
+
function marketplaceLocations() {
|
|
12911
|
+
const out = /* @__PURE__ */ new Map();
|
|
12912
|
+
const known = readJsonFile((0, import_node_path7.join)(claudeConfigDir(), "plugins", "known_marketplaces.json"));
|
|
12913
|
+
if (!known) return out;
|
|
12914
|
+
for (const [name, entry] of Object.entries(known)) {
|
|
12915
|
+
const loc2 = entry?.installLocation;
|
|
12916
|
+
if (typeof loc2 === "string" && loc2) out.set(name, (0, import_node_path7.resolve)(loc2));
|
|
12917
|
+
}
|
|
12918
|
+
return out;
|
|
12919
|
+
}
|
|
12920
|
+
function realpathOr(p) {
|
|
12921
|
+
try {
|
|
12922
|
+
return import_node_fs6.realpathSync.native(p);
|
|
12923
|
+
} catch {
|
|
12924
|
+
return (0, import_node_path7.resolve)(p);
|
|
12925
|
+
}
|
|
12926
|
+
}
|
|
12927
|
+
function isWithin(want, dir) {
|
|
12928
|
+
return want === dir || want.startsWith(dir + import_node_path7.sep);
|
|
12929
|
+
}
|
|
12930
|
+
function entryAppliesHere(entry, here) {
|
|
12931
|
+
const e = entry;
|
|
12932
|
+
const scope2 = typeof e?.scope === "string" ? e.scope : "user";
|
|
12933
|
+
if (scope2 === "user") return true;
|
|
12934
|
+
const forProject = typeof e?.projectPath === "string" ? realpathOr(e.projectPath) : "";
|
|
12935
|
+
return forProject === here;
|
|
12936
|
+
}
|
|
12937
|
+
function registrySays(pluginRoot) {
|
|
12938
|
+
const plugins = readJsonFile((0, import_node_path7.join)(claudeConfigDir(), "plugins", "installed_plugins.json"))?.plugins;
|
|
12939
|
+
if (!plugins || typeof plugins !== "object") return "unverified";
|
|
12940
|
+
const want = (0, import_node_path7.resolve)(pluginRoot);
|
|
12941
|
+
const here = realpathOr(repoRoot());
|
|
12942
|
+
const markets = marketplaceLocations();
|
|
12943
|
+
for (const [key, value] of Object.entries(plugins)) {
|
|
12944
|
+
const at = key.lastIndexOf("@");
|
|
12945
|
+
const source = at > 0 ? markets.get(key.slice(at + 1)) : void 0;
|
|
12946
|
+
const applicable = (Array.isArray(value) ? value : []).filter((entry) => entryAppliesHere(entry, here));
|
|
12947
|
+
const claims = applicable.some((entry) => {
|
|
12948
|
+
const installPath = entry?.installPath;
|
|
12949
|
+
return typeof installPath === "string" && (0, import_node_path7.resolve)(installPath) === want;
|
|
12950
|
+
}) || source !== void 0 && applicable.length > 0 && isWithin(want, source);
|
|
12951
|
+
if (claims) {
|
|
12952
|
+
if (enabledPluginSetting(key) === false) return "gone";
|
|
12953
|
+
return (0, import_node_fs6.existsSync)(pluginRoot) ? "live" : "gone";
|
|
12954
|
+
}
|
|
12955
|
+
}
|
|
12956
|
+
const managed = (0, import_node_path7.resolve)((0, import_node_path7.join)(claudeConfigDir(), "plugins", "cache"));
|
|
12957
|
+
return want === managed || want.startsWith(managed + import_node_path7.sep) ? "gone" : "unverified";
|
|
12958
|
+
}
|
|
12959
|
+
var _live = /* @__PURE__ */ new Map();
|
|
12960
|
+
function pluginLiveness(pluginRoot) {
|
|
12961
|
+
const cached2 = _live.get(pluginRoot);
|
|
12962
|
+
if (cached2 !== void 0) return cached2;
|
|
12963
|
+
const said = registrySays(pluginRoot);
|
|
12964
|
+
_live.set(pluginRoot, said);
|
|
12965
|
+
return said;
|
|
12966
|
+
}
|
|
12967
|
+
function clearStalePluginMarker() {
|
|
12968
|
+
const marker = readMarker();
|
|
12969
|
+
if (!marker || pluginLiveness(marker.plugin_root) !== "gone") return null;
|
|
12970
|
+
try {
|
|
12971
|
+
(0, import_node_fs6.rmSync)(markerPath(), { force: true });
|
|
12972
|
+
} catch {
|
|
12973
|
+
return null;
|
|
12974
|
+
}
|
|
12975
|
+
return { pluginRoot: marker.plugin_root, version: marker.version };
|
|
12976
|
+
}
|
|
12859
12977
|
function shouldDeferToPlugin(sessionId) {
|
|
12860
12978
|
if (isPluginInvocation()) {
|
|
12861
12979
|
recordPluginOwnership(sessionId);
|
|
@@ -12863,13 +12981,44 @@ function shouldDeferToPlugin(sessionId) {
|
|
|
12863
12981
|
}
|
|
12864
12982
|
const marker = readMarker();
|
|
12865
12983
|
if (!marker) return false;
|
|
12866
|
-
|
|
12984
|
+
const liveness = pluginLiveness(marker.plugin_root);
|
|
12985
|
+
if (liveness === "gone") return false;
|
|
12867
12986
|
if (sessionId && marker.session_id) return sessionId === marker.session_id;
|
|
12868
|
-
|
|
12987
|
+
logToFileOnly(
|
|
12988
|
+
// JSON-encoded: `plugin_root` is repository-controlled, and raw it could
|
|
12989
|
+
// write forged lines into the one place someone looks to understand why
|
|
12990
|
+
// the gate did what it did. (`readMarker` also refuses control characters.)
|
|
12991
|
+
`plugin ownership: no session id to match against the marker for ${JSON.stringify(marker.plugin_root)} \u2014 running rather than standing down, because only an exact session match is evidence a repository cannot write.`
|
|
12992
|
+
);
|
|
12993
|
+
return false;
|
|
12869
12994
|
}
|
|
12870
12995
|
function pluginActiveHere() {
|
|
12996
|
+
return activePluginInstall() !== null;
|
|
12997
|
+
}
|
|
12998
|
+
function registeredVerityPlugin() {
|
|
12999
|
+
const plugins = readJsonFile((0, import_node_path7.join)(claudeConfigDir(), "plugins", "installed_plugins.json"))?.plugins;
|
|
13000
|
+
if (!plugins || typeof plugins !== "object") return null;
|
|
13001
|
+
const here = realpathOr(repoRoot());
|
|
13002
|
+
for (const [key, value] of Object.entries(plugins)) {
|
|
13003
|
+
const at = key.lastIndexOf("@");
|
|
13004
|
+
if ((at > 0 ? key.slice(0, at) : key) !== "verity") continue;
|
|
13005
|
+
if (enabledPluginSetting(key) === false) continue;
|
|
13006
|
+
for (const entry of Array.isArray(value) ? value : []) {
|
|
13007
|
+
const e = entry;
|
|
13008
|
+
const installPath = typeof e.installPath === "string" ? e.installPath : "";
|
|
13009
|
+
if (!installPath || !(0, import_node_fs6.existsSync)(installPath)) continue;
|
|
13010
|
+
if (!entryAppliesHere(entry, here)) continue;
|
|
13011
|
+
return { pluginRoot: installPath, version: typeof e.version === "string" ? e.version : null };
|
|
13012
|
+
}
|
|
13013
|
+
}
|
|
13014
|
+
return null;
|
|
13015
|
+
}
|
|
13016
|
+
function activePluginInstall() {
|
|
12871
13017
|
const marker = readMarker();
|
|
12872
|
-
|
|
13018
|
+
if (marker && pluginLiveness(marker.plugin_root) === "live") {
|
|
13019
|
+
return { pluginRoot: marker.plugin_root, version: marker.version };
|
|
13020
|
+
}
|
|
13021
|
+
return registeredVerityPlugin();
|
|
12873
13022
|
}
|
|
12874
13023
|
function deferredToPlugin(command, sessionId) {
|
|
12875
13024
|
if (!shouldDeferToPlugin(sessionId)) return false;
|
|
@@ -12879,21 +13028,63 @@ function deferredToPlugin(command, sessionId) {
|
|
|
12879
13028
|
return true;
|
|
12880
13029
|
}
|
|
12881
13030
|
|
|
13031
|
+
// src/lib/hook-wiring.ts
|
|
13032
|
+
function carriesAnyVerityHook(s) {
|
|
13033
|
+
return s.stop || s.intent || s.baseline || s.compact || s.sessionEnd || s.guard;
|
|
13034
|
+
}
|
|
13035
|
+
async function resolveHookWiring() {
|
|
13036
|
+
const settings = await checkAllVerityHooks();
|
|
13037
|
+
const config = readProjectConfig();
|
|
13038
|
+
const gitMoments = { source: config.source, path: config.path };
|
|
13039
|
+
if (!pluginActiveHere()) {
|
|
13040
|
+
return { source: "settings", status: settings, settings, duplicateSettingsHooks: false, gitMoments };
|
|
13041
|
+
}
|
|
13042
|
+
const status = {
|
|
13043
|
+
stop: true,
|
|
13044
|
+
intent: true,
|
|
13045
|
+
baseline: true,
|
|
13046
|
+
compact: true,
|
|
13047
|
+
sessionEnd: true,
|
|
13048
|
+
guard: true,
|
|
13049
|
+
guardOn: config.git_moments
|
|
13050
|
+
};
|
|
13051
|
+
return {
|
|
13052
|
+
source: "plugin",
|
|
13053
|
+
status,
|
|
13054
|
+
settings,
|
|
13055
|
+
duplicateSettingsHooks: carriesAnyVerityHook(settings),
|
|
13056
|
+
gitMoments
|
|
13057
|
+
};
|
|
13058
|
+
}
|
|
13059
|
+
|
|
12882
13060
|
// src/commands/hooks.ts
|
|
12883
13061
|
var ALL_MOMENTS = ["stop", "pre-commit", "pre-push"];
|
|
12884
|
-
function
|
|
12885
|
-
const
|
|
12886
|
-
|
|
12887
|
-
|
|
13062
|
+
function parseMomentSelection(raw) {
|
|
13063
|
+
const parts = raw.split(",").map((s) => s.trim()).filter(Boolean);
|
|
13064
|
+
if (parts.length === 1 && parts[0].toLowerCase() === "none") return { moments: [] };
|
|
13065
|
+
if (parts.length === 0) {
|
|
13066
|
+
return { error: `--moments was empty. Pass one or more of ${ALL_MOMENTS.join(", ")} \u2014 or "none" to gate nothing.` };
|
|
13067
|
+
}
|
|
13068
|
+
const unknown = parts.filter((p) => !ALL_MOMENTS.includes(p));
|
|
13069
|
+
if (unknown.length > 0) {
|
|
13070
|
+
return {
|
|
13071
|
+
error: `--moments: unrecognised ${unknown.length === 1 ? "moment" : "moments"} ${unknown.map((u) => `"${u}"`).join(", ")}. Valid: ${ALL_MOMENTS.join(", ")} \u2014 or "none" to gate nothing.`
|
|
13072
|
+
};
|
|
12888
13073
|
}
|
|
12889
|
-
|
|
13074
|
+
const seen = new Set(parts);
|
|
13075
|
+
return { moments: ALL_MOMENTS.filter((m) => seen.has(m)) };
|
|
12890
13076
|
}
|
|
12891
13077
|
function registerHooksCommands(program2) {
|
|
12892
13078
|
const hooks = program2.command("hooks").description("Manage Claude Code hook wiring");
|
|
12893
13079
|
hooks.command("install").description("Install Verity hooks into Claude Code settings").option("--force", "Overwrite existing Verity hooks").option("--moments <list>", "Reconcile to exactly these moments: stop,pre-commit,pre-push").action(async (opts) => {
|
|
12894
13080
|
const force = opts.force ?? false;
|
|
12895
13081
|
if (opts.moments != null) {
|
|
12896
|
-
const
|
|
13082
|
+
const parsed = parseMomentSelection(opts.moments);
|
|
13083
|
+
if ("error" in parsed) {
|
|
13084
|
+
printError(parsed.error);
|
|
13085
|
+
process.exit(1);
|
|
13086
|
+
}
|
|
13087
|
+
const moments = parsed.moments;
|
|
12897
13088
|
const gitMoments = [
|
|
12898
13089
|
...moments.includes("pre-commit") ? ["commit"] : [],
|
|
12899
13090
|
...moments.includes("pre-push") ? ["push"] : []
|
|
@@ -12954,20 +13145,22 @@ function registerHooksCommands(program2) {
|
|
|
12954
13145
|
printInfo(" SessionStart hook: verity baseline capture");
|
|
12955
13146
|
});
|
|
12956
13147
|
hooks.command("check").description("Check if Verity hooks are installed").action(async () => {
|
|
12957
|
-
const
|
|
12958
|
-
|
|
12959
|
-
|
|
13148
|
+
const wiring = await resolveHookWiring();
|
|
13149
|
+
const status = wiring.status;
|
|
13150
|
+
if (wiring.source === "plugin") {
|
|
13151
|
+
const moments = status.guardOn;
|
|
13152
|
+
const inherited = wiring.gitMoments.source === "main-worktree" && wiring.gitMoments.path ? ` (inherited from the main worktree: ${wiring.gitMoments.path})` : "";
|
|
12960
13153
|
printInfo("Wired by the Verity Claude Code plugin (not .claude/settings.json):");
|
|
12961
13154
|
printInfo(" Stop hook (verity analyze): installed");
|
|
12962
13155
|
printInfo(" Intent hook (verity intent capture): installed");
|
|
12963
13156
|
printInfo(" Baseline hook (verity baseline capture): installed");
|
|
12964
13157
|
printInfo(
|
|
12965
|
-
` Git-moment gate (verity guard): ${moments.length ? `installed [${moments.join(", ")}]` : "wired but gating nothing"}`
|
|
13158
|
+
` Git-moment gate (verity guard): ${moments.length ? `installed [${moments.join(", ")}]${inherited}` : "wired but gating nothing"}`
|
|
12966
13159
|
);
|
|
12967
13160
|
if (!moments.length) {
|
|
12968
13161
|
printInfo(' Enable it with "verity config git-moments commit,push".');
|
|
12969
13162
|
}
|
|
12970
|
-
if (
|
|
13163
|
+
if (wiring.duplicateSettingsHooks) {
|
|
12971
13164
|
printWarn(" Duplicate hooks also exist in .claude/settings.json. They stand down at run time,");
|
|
12972
13165
|
printWarn(' but remove them with "verity init --plugin-mode" so the wiring says what it does.');
|
|
12973
13166
|
}
|
|
@@ -13352,8 +13545,8 @@ function isCommandOnlyTurn(input) {
|
|
|
13352
13545
|
// src/lib/context-identity.ts
|
|
13353
13546
|
var import_node_crypto2 = require("node:crypto");
|
|
13354
13547
|
var import_node_fs8 = require("node:fs");
|
|
13355
|
-
var
|
|
13356
|
-
var
|
|
13548
|
+
var import_node_os3 = require("node:os");
|
|
13549
|
+
var import_node_path8 = require("node:path");
|
|
13357
13550
|
var SHARED_SENTINELS = /* @__PURE__ */ new Set([
|
|
13358
13551
|
"",
|
|
13359
13552
|
"-",
|
|
@@ -13407,13 +13600,13 @@ function contextIdentity(input) {
|
|
|
13407
13600
|
}
|
|
13408
13601
|
function verityHome() {
|
|
13409
13602
|
const override = process.env.VERITY_HOME;
|
|
13410
|
-
return override && override.trim() ? (0,
|
|
13603
|
+
return override && override.trim() ? (0, import_node_path8.resolve)(override) : (0, import_node_path8.join)((0, import_node_os3.homedir)(), ".verity");
|
|
13411
13604
|
}
|
|
13412
13605
|
function dossierDir(identity) {
|
|
13413
|
-
return (0,
|
|
13606
|
+
return (0, import_node_path8.join)(verityHome(), "sessions", identity.userKey, identity.treeKey, identity.sessionKey);
|
|
13414
13607
|
}
|
|
13415
13608
|
function treeDir(identity) {
|
|
13416
|
-
return (0,
|
|
13609
|
+
return (0, import_node_path8.join)(verityHome(), "sessions", identity.userKey, identity.treeKey);
|
|
13417
13610
|
}
|
|
13418
13611
|
function scopeIdentity(token, sessionId) {
|
|
13419
13612
|
const t = (token ?? "").trim();
|
|
@@ -13429,7 +13622,7 @@ function sessionScopeKey(token, sessionId) {
|
|
|
13429
13622
|
// src/lib/task-context-buffer.ts
|
|
13430
13623
|
var import_promises6 = require("node:fs/promises");
|
|
13431
13624
|
var import_node_fs9 = require("node:fs");
|
|
13432
|
-
var
|
|
13625
|
+
var import_node_path9 = require("node:path");
|
|
13433
13626
|
var TASK_CONTEXT_DIR = `${VERITY_DIR}/.task-context`;
|
|
13434
13627
|
var MAX_BUFFER_BYTES = 500 * 1024;
|
|
13435
13628
|
var MAX_PROMPT_CHARS = 2e3;
|
|
@@ -13507,7 +13700,7 @@ async function cleanupTaskContextBuffers() {
|
|
|
13507
13700
|
const cutoffMs = Date.now() - RETENTION_DAYS * 24 * 60 * 60 * 1e3;
|
|
13508
13701
|
for (const file of files) {
|
|
13509
13702
|
if (!file.endsWith(".jsonl")) continue;
|
|
13510
|
-
const filePath = (0,
|
|
13703
|
+
const filePath = (0, import_node_path9.join)(TASK_CONTEXT_DIR, file);
|
|
13511
13704
|
try {
|
|
13512
13705
|
const stats = await (0, import_promises6.stat)(filePath);
|
|
13513
13706
|
if (stats.mtimeMs < cutoffMs) {
|
|
@@ -13521,7 +13714,7 @@ async function cleanupTaskContextBuffers() {
|
|
|
13521
13714
|
}
|
|
13522
13715
|
function bufferPath(taskId) {
|
|
13523
13716
|
const safe = taskId.replace(/[^a-zA-Z0-9_-]/g, "");
|
|
13524
|
-
return (0,
|
|
13717
|
+
return (0, import_node_path9.join)(TASK_CONTEXT_DIR, `${safe}.jsonl`);
|
|
13525
13718
|
}
|
|
13526
13719
|
async function appendEntry(taskId, entry) {
|
|
13527
13720
|
try {
|
|
@@ -13547,7 +13740,7 @@ async function appendEntry(taskId, entry) {
|
|
|
13547
13740
|
// src/lib/memory-retrieval.ts
|
|
13548
13741
|
var import_promises7 = require("node:fs/promises");
|
|
13549
13742
|
var import_node_fs10 = require("node:fs");
|
|
13550
|
-
var
|
|
13743
|
+
var import_node_path10 = require("node:path");
|
|
13551
13744
|
var memoryDir = () => projectPath(`${VERITY_DIR}/memory`);
|
|
13552
13745
|
var DOMAINS = ["decisions", "quality", "security", "intent", "gotchas", "patterns", "domain", "integrations"];
|
|
13553
13746
|
var DEFAULT_BUDGET_TOKENS = 2e3;
|
|
@@ -13645,14 +13838,14 @@ async function retrieveForInjection(promptText, taskFiles = [], budgetTokens = D
|
|
|
13645
13838
|
const promptTokens = tokenize(promptText);
|
|
13646
13839
|
const nodes = [];
|
|
13647
13840
|
for (const domain of DOMAINS) {
|
|
13648
|
-
const domainDir = (0,
|
|
13841
|
+
const domainDir = (0, import_node_path10.join)(memoryDir(), domain);
|
|
13649
13842
|
if (!(0, import_node_fs10.existsSync)(domainDir)) continue;
|
|
13650
13843
|
try {
|
|
13651
13844
|
const files = await (0, import_promises7.readdir)(domainDir);
|
|
13652
13845
|
for (const file of files) {
|
|
13653
13846
|
if (!file.endsWith(".md")) continue;
|
|
13654
13847
|
try {
|
|
13655
|
-
const content = await (0, import_promises7.readFile)((0,
|
|
13848
|
+
const content = await (0, import_promises7.readFile)((0, import_node_path10.join)(domainDir, file), "utf-8");
|
|
13656
13849
|
const { fm, body } = parseFrontmatter(content);
|
|
13657
13850
|
if (fm.status && fm.status !== "active") continue;
|
|
13658
13851
|
nodes.push({
|
|
@@ -13712,26 +13905,26 @@ async function retrieveForInjection(promptText, taskFiles = [], budgetTokens = D
|
|
|
13712
13905
|
// src/lib/memory-sync.ts
|
|
13713
13906
|
var import_promises8 = require("node:fs/promises");
|
|
13714
13907
|
var import_node_fs12 = require("node:fs");
|
|
13715
|
-
var
|
|
13908
|
+
var import_node_path12 = require("node:path");
|
|
13716
13909
|
var import_node_crypto3 = require("node:crypto");
|
|
13717
13910
|
|
|
13718
13911
|
// src/lib/safe-path.ts
|
|
13719
13912
|
var import_node_fs11 = require("node:fs");
|
|
13720
|
-
var
|
|
13913
|
+
var import_node_path11 = require("node:path");
|
|
13721
13914
|
function resolveInside(baseDir, candidate) {
|
|
13722
13915
|
if (typeof candidate !== "string" || candidate.length === 0) return null;
|
|
13723
|
-
if ((0,
|
|
13724
|
-
const baseAbs = (0,
|
|
13725
|
-
const full = (0,
|
|
13726
|
-
const baseSep = baseAbs.endsWith(
|
|
13916
|
+
if ((0, import_node_path11.isAbsolute)(candidate)) return null;
|
|
13917
|
+
const baseAbs = (0, import_node_path11.resolve)(baseDir);
|
|
13918
|
+
const full = (0, import_node_path11.resolve)(baseAbs, candidate);
|
|
13919
|
+
const baseSep = baseAbs.endsWith(import_node_path11.sep) ? baseAbs : baseAbs + import_node_path11.sep;
|
|
13727
13920
|
if (full !== baseAbs && !full.startsWith(baseSep)) return null;
|
|
13728
13921
|
try {
|
|
13729
13922
|
if ((0, import_node_fs11.existsSync)(baseAbs)) {
|
|
13730
13923
|
const realBase = (0, import_node_fs11.realpathSync)(baseAbs);
|
|
13731
|
-
const realBaseSep = realBase.endsWith(
|
|
13924
|
+
const realBaseSep = realBase.endsWith(import_node_path11.sep) ? realBase : realBase + import_node_path11.sep;
|
|
13732
13925
|
let probe = full;
|
|
13733
13926
|
while (!(0, import_node_fs11.existsSync)(probe)) {
|
|
13734
|
-
const parent = (0,
|
|
13927
|
+
const parent = (0, import_node_path11.dirname)(probe);
|
|
13735
13928
|
if (parent === probe) break;
|
|
13736
13929
|
probe = parent;
|
|
13737
13930
|
}
|
|
@@ -13812,16 +14005,16 @@ var syncStateFile = () => projectPath(`${VERITY_DIR}/.memory-sync-state.json`);
|
|
|
13812
14005
|
async function ensureMemoryDir() {
|
|
13813
14006
|
await (0, import_promises8.mkdir)(memoryDir2(), { recursive: true });
|
|
13814
14007
|
for (const domain of DOMAINS2) {
|
|
13815
|
-
await (0, import_promises8.mkdir)((0,
|
|
14008
|
+
await (0, import_promises8.mkdir)((0, import_node_path12.join)(memoryDir2(), domain), { recursive: true });
|
|
13816
14009
|
}
|
|
13817
|
-
if (!(0, import_node_fs12.existsSync)((0,
|
|
13818
|
-
await (0, import_promises8.writeFile)((0,
|
|
14010
|
+
if (!(0, import_node_fs12.existsSync)((0, import_node_path12.join)(memoryDir2(), "SCHEMA.md"))) {
|
|
14011
|
+
await (0, import_promises8.writeFile)((0, import_node_path12.join)(memoryDir2(), "SCHEMA.md"), SCHEMA_TEMPLATE);
|
|
13819
14012
|
}
|
|
13820
|
-
if (!(0, import_node_fs12.existsSync)((0,
|
|
13821
|
-
await (0, import_promises8.writeFile)((0,
|
|
14013
|
+
if (!(0, import_node_fs12.existsSync)((0, import_node_path12.join)(memoryDir2(), "index.md"))) {
|
|
14014
|
+
await (0, import_promises8.writeFile)((0, import_node_path12.join)(memoryDir2(), "index.md"), "# Project Memory Index\n\nNo nodes yet. Run an analysis to start building the knowledge graph.\n");
|
|
13822
14015
|
}
|
|
13823
|
-
if (!(0, import_node_fs12.existsSync)((0,
|
|
13824
|
-
await (0, import_promises8.writeFile)((0,
|
|
14016
|
+
if (!(0, import_node_fs12.existsSync)((0, import_node_path12.join)(memoryDir2(), "log.md"))) {
|
|
14017
|
+
await (0, import_promises8.writeFile)((0, import_node_path12.join)(memoryDir2(), "log.md"), "# Memory Log\n\n");
|
|
13825
14018
|
}
|
|
13826
14019
|
}
|
|
13827
14020
|
async function buildManifest() {
|
|
@@ -13830,14 +14023,14 @@ async function buildManifest() {
|
|
|
13830
14023
|
}
|
|
13831
14024
|
const nodes = [];
|
|
13832
14025
|
for (const domain of DOMAINS2) {
|
|
13833
|
-
const domainDir = (0,
|
|
14026
|
+
const domainDir = (0, import_node_path12.join)(memoryDir2(), domain);
|
|
13834
14027
|
if (!(0, import_node_fs12.existsSync)(domainDir)) continue;
|
|
13835
14028
|
try {
|
|
13836
14029
|
const files = await (0, import_promises8.readdir)(domainDir);
|
|
13837
14030
|
for (const file of files) {
|
|
13838
14031
|
if (!file.endsWith(".md")) continue;
|
|
13839
14032
|
const filePath = `${domain}/${file}`;
|
|
13840
|
-
const fullPath = (0,
|
|
14033
|
+
const fullPath = (0, import_node_path12.join)(memoryDir2(), filePath);
|
|
13841
14034
|
try {
|
|
13842
14035
|
const content = await (0, import_promises8.readFile)(fullPath, "utf-8");
|
|
13843
14036
|
const hash = (0, import_node_crypto3.createHash)("sha256").update(content).digest("hex").slice(0, 16);
|
|
@@ -13850,13 +14043,13 @@ async function buildManifest() {
|
|
|
13850
14043
|
}
|
|
13851
14044
|
let indexHash = null;
|
|
13852
14045
|
try {
|
|
13853
|
-
const indexContent = await (0, import_promises8.readFile)((0,
|
|
14046
|
+
const indexContent = await (0, import_promises8.readFile)((0, import_node_path12.join)(memoryDir2(), "index.md"), "utf-8");
|
|
13854
14047
|
indexHash = `sha256:${(0, import_node_crypto3.createHash)("sha256").update(indexContent).digest("hex").slice(0, 16)}`;
|
|
13855
14048
|
} catch {
|
|
13856
14049
|
}
|
|
13857
14050
|
let logLength = 0;
|
|
13858
14051
|
try {
|
|
13859
|
-
const logContent = await (0, import_promises8.readFile)((0,
|
|
14052
|
+
const logContent = await (0, import_promises8.readFile)((0, import_node_path12.join)(memoryDir2(), "log.md"), "utf-8");
|
|
13860
14053
|
logLength = logContent.split("\n").length;
|
|
13861
14054
|
} catch {
|
|
13862
14055
|
}
|
|
@@ -13869,13 +14062,13 @@ async function readOnDiskNodes() {
|
|
|
13869
14062
|
const out = /* @__PURE__ */ new Map();
|
|
13870
14063
|
if (!(0, import_node_fs12.existsSync)(memoryDir2())) return out;
|
|
13871
14064
|
for (const domain of DOMAINS2) {
|
|
13872
|
-
const domainDir = (0,
|
|
14065
|
+
const domainDir = (0, import_node_path12.join)(memoryDir2(), domain);
|
|
13873
14066
|
if (!(0, import_node_fs12.existsSync)(domainDir)) continue;
|
|
13874
14067
|
try {
|
|
13875
14068
|
for (const file of await (0, import_promises8.readdir)(domainDir)) {
|
|
13876
14069
|
if (!file.endsWith(".md")) continue;
|
|
13877
14070
|
try {
|
|
13878
|
-
out.set(`${domain}/${file}`, hashContent(await (0, import_promises8.readFile)((0,
|
|
14071
|
+
out.set(`${domain}/${file}`, hashContent(await (0, import_promises8.readFile)((0, import_node_path12.join)(domainDir, file), "utf-8")));
|
|
13879
14072
|
} catch {
|
|
13880
14073
|
}
|
|
13881
14074
|
}
|
|
@@ -13921,7 +14114,7 @@ async function computeEditedNodeUploads() {
|
|
|
13921
14114
|
const uploads = [];
|
|
13922
14115
|
for (const [path, prevHash] of prev) {
|
|
13923
14116
|
if (prevHash == null) continue;
|
|
13924
|
-
const full = (0,
|
|
14117
|
+
const full = (0, import_node_path12.join)(memoryDir2(), path);
|
|
13925
14118
|
if (!(0, import_node_fs12.existsSync)(full)) continue;
|
|
13926
14119
|
let content;
|
|
13927
14120
|
try {
|
|
@@ -13958,8 +14151,8 @@ async function applyMemoryWrites(writes, opts = {}) {
|
|
|
13958
14151
|
const logLines = [`- ${(/* @__PURE__ */ new Date()).toISOString().slice(0, 16)} \u2014 Applied ${count} write(s) from server`];
|
|
13959
14152
|
for (const n of notes) logLines.push(` - ${n}`);
|
|
13960
14153
|
try {
|
|
13961
|
-
const existing = (0, import_node_fs12.existsSync)((0,
|
|
13962
|
-
await (0, import_promises8.writeFile)((0,
|
|
14154
|
+
const existing = (0, import_node_fs12.existsSync)((0, import_node_path12.join)(memoryDir2(), "log.md")) ? await (0, import_promises8.readFile)((0, import_node_path12.join)(memoryDir2(), "log.md"), "utf-8") : "# Memory Log\n\n";
|
|
14155
|
+
await (0, import_promises8.writeFile)((0, import_node_path12.join)(memoryDir2(), "log.md"), existing + logLines.join("\n") + "\n");
|
|
13963
14156
|
} catch {
|
|
13964
14157
|
}
|
|
13965
14158
|
await recordSyncedNodePaths();
|
|
@@ -13991,7 +14184,7 @@ async function applyOneWrite(write, treePaths) {
|
|
|
13991
14184
|
return { written: false, notes };
|
|
13992
14185
|
}
|
|
13993
14186
|
}
|
|
13994
|
-
await (0, import_promises8.mkdir)((0,
|
|
14187
|
+
await (0, import_promises8.mkdir)((0, import_node_path12.dirname)(fullPath), { recursive: true });
|
|
13995
14188
|
await (0, import_promises8.writeFile)(fullPath, content);
|
|
13996
14189
|
return { written: true, notes };
|
|
13997
14190
|
}
|
|
@@ -14032,7 +14225,7 @@ async function regenerateIndex() {
|
|
|
14032
14225
|
];
|
|
14033
14226
|
let totalNodes = 0;
|
|
14034
14227
|
for (const domain of DOMAINS2.filter((d) => d !== "_archive")) {
|
|
14035
|
-
const domainDir = (0,
|
|
14228
|
+
const domainDir = (0, import_node_path12.join)(memoryDir2(), domain);
|
|
14036
14229
|
if (!(0, import_node_fs12.existsSync)(domainDir)) continue;
|
|
14037
14230
|
try {
|
|
14038
14231
|
const files = await (0, import_promises8.readdir)(domainDir);
|
|
@@ -14043,7 +14236,7 @@ async function regenerateIndex() {
|
|
|
14043
14236
|
for (const file of mdFiles.sort()) {
|
|
14044
14237
|
const slug = file.replace(/\.md$/, "");
|
|
14045
14238
|
try {
|
|
14046
|
-
const content = await (0, import_promises8.readFile)((0,
|
|
14239
|
+
const content = await (0, import_promises8.readFile)((0, import_node_path12.join)(domainDir, file), "utf-8");
|
|
14047
14240
|
const title = pickFrontmatter(content, "title") ?? slug;
|
|
14048
14241
|
const kind = pickFrontmatter(content, "kind") ?? "-";
|
|
14049
14242
|
const confidence = pickFrontmatter(content, "confidence");
|
|
@@ -14067,7 +14260,7 @@ async function regenerateIndex() {
|
|
|
14067
14260
|
lines.push("No nodes yet. Run an analysis to start building the knowledge graph.");
|
|
14068
14261
|
}
|
|
14069
14262
|
const next = lines.join("\n") + "\n";
|
|
14070
|
-
const indexPath = (0,
|
|
14263
|
+
const indexPath = (0, import_node_path12.join)(memoryDir2(), "index.md");
|
|
14071
14264
|
let existing = null;
|
|
14072
14265
|
try {
|
|
14073
14266
|
existing = await (0, import_promises8.readFile)(indexPath, "utf-8");
|
|
@@ -14301,7 +14494,7 @@ function hasLegacyMemoryBlock(text) {
|
|
|
14301
14494
|
return findMarker(text, LEGACY_MD_START) !== -1;
|
|
14302
14495
|
}
|
|
14303
14496
|
async function ensureClaudeMdPointer(cwd = repoRoot()) {
|
|
14304
|
-
const claudeMdPath = (0,
|
|
14497
|
+
const claudeMdPath = (0, import_node_path12.join)(cwd, "CLAUDE.md");
|
|
14305
14498
|
let existing = "";
|
|
14306
14499
|
if ((0, import_node_fs12.existsSync)(claudeMdPath)) {
|
|
14307
14500
|
existing = await (0, import_promises8.readFile)(claudeMdPath, "utf-8");
|
|
@@ -14441,7 +14634,7 @@ Body content (\u22648KB). Use [[node-id]] wikilinks for cross-references.
|
|
|
14441
14634
|
// src/lib/dossier-session.ts
|
|
14442
14635
|
var import_node_fs17 = require("node:fs");
|
|
14443
14636
|
var import_node_crypto7 = require("node:crypto");
|
|
14444
|
-
var
|
|
14637
|
+
var import_node_path15 = require("node:path");
|
|
14445
14638
|
|
|
14446
14639
|
// src/lib/pending-repeat.ts
|
|
14447
14640
|
var STOP = /* @__PURE__ */ new Set([
|
|
@@ -14547,7 +14740,7 @@ function statementAnchorKey(file, patternId) {
|
|
|
14547
14740
|
// src/lib/dossier/log.ts
|
|
14548
14741
|
var import_node_crypto4 = require("node:crypto");
|
|
14549
14742
|
var import_node_fs13 = require("node:fs");
|
|
14550
|
-
var
|
|
14743
|
+
var import_node_path13 = require("node:path");
|
|
14551
14744
|
var CRC_TABLE = (() => {
|
|
14552
14745
|
const t = new Int32Array(256);
|
|
14553
14746
|
for (let i = 0; i < 256; i++) {
|
|
@@ -14570,9 +14763,9 @@ function openDossier(identity) {
|
|
|
14570
14763
|
return {
|
|
14571
14764
|
dir,
|
|
14572
14765
|
identity,
|
|
14573
|
-
eventsPath: (0,
|
|
14574
|
-
foldPath: (0,
|
|
14575
|
-
rotatedDir: (0,
|
|
14766
|
+
eventsPath: (0, import_node_path13.join)(dir, "events.jsonl"),
|
|
14767
|
+
foldPath: (0, import_node_path13.join)(dir, "fold.json"),
|
|
14768
|
+
rotatedDir: (0, import_node_path13.join)(dir, "rotated")
|
|
14576
14769
|
};
|
|
14577
14770
|
} catch {
|
|
14578
14771
|
return null;
|
|
@@ -14645,11 +14838,11 @@ function rotateIfNeeded2(d) {
|
|
|
14645
14838
|
if (!(0, import_node_fs13.existsSync)(d.eventsPath)) return;
|
|
14646
14839
|
if ((0, import_node_fs13.statSync)(d.eventsPath).size < ROTATE_BYTES) return;
|
|
14647
14840
|
(0, import_node_fs13.mkdirSync)(d.rotatedDir, { recursive: true, mode: 448 });
|
|
14648
|
-
(0, import_node_fs13.renameSync)(d.eventsPath, (0,
|
|
14841
|
+
(0, import_node_fs13.renameSync)(d.eventsPath, (0, import_node_path13.join)(d.rotatedDir, `events.${Date.now()}.jsonl`));
|
|
14649
14842
|
const kept = (0, import_node_fs13.readdirSync)(d.rotatedDir).filter((f) => f.endsWith(".jsonl")).sort();
|
|
14650
14843
|
for (const stale of kept.slice(0, Math.max(0, kept.length - ROTATE_KEEP))) {
|
|
14651
14844
|
try {
|
|
14652
|
-
(0, import_node_fs13.renameSync)((0,
|
|
14845
|
+
(0, import_node_fs13.renameSync)((0, import_node_path13.join)(d.rotatedDir, stale), (0, import_node_path13.join)(d.rotatedDir, `${stale}.pruned`));
|
|
14653
14846
|
} catch {
|
|
14654
14847
|
}
|
|
14655
14848
|
}
|
|
@@ -14660,7 +14853,7 @@ function rotateIfNeeded2(d) {
|
|
|
14660
14853
|
// src/lib/dossier/fold-dossier.ts
|
|
14661
14854
|
var import_node_crypto5 = require("node:crypto");
|
|
14662
14855
|
var import_node_fs14 = require("node:fs");
|
|
14663
|
-
var
|
|
14856
|
+
var import_node_path14 = require("node:path");
|
|
14664
14857
|
var EMPTY_CAPABILITIES = () => ({
|
|
14665
14858
|
human_reachable: { value: "unknown", tier: "unknown" },
|
|
14666
14859
|
authorship_observability: { value: "unknown", tier: "unknown" },
|
|
@@ -14716,7 +14909,7 @@ function foldDossier(d, opts = {}) {
|
|
|
14716
14909
|
state.meta.rotations = files.length;
|
|
14717
14910
|
for (const f of files) {
|
|
14718
14911
|
try {
|
|
14719
|
-
ingest((0, import_node_fs14.readFileSync)((0,
|
|
14912
|
+
ingest((0, import_node_fs14.readFileSync)((0, import_node_path14.join)(d.rotatedDir, f), "utf8"));
|
|
14720
14913
|
} catch {
|
|
14721
14914
|
state.meta.dropped_lines++;
|
|
14722
14915
|
}
|
|
@@ -15573,16 +15766,16 @@ function foreignAuthoredPaths(identity, opts = {}) {
|
|
|
15573
15766
|
for (const entry of (0, import_node_fs17.readdirSync)(dir, { withFileTypes: true })) {
|
|
15574
15767
|
if (!entry.isDirectory()) continue;
|
|
15575
15768
|
if (entry.name === identity.sessionKey) continue;
|
|
15576
|
-
const log = (0,
|
|
15769
|
+
const log = (0, import_node_path15.join)(dir, entry.name, "events.jsonl");
|
|
15577
15770
|
try {
|
|
15578
15771
|
if (!(0, import_node_fs17.existsSync)(log)) continue;
|
|
15579
15772
|
if (now - (0, import_node_fs17.statSync)(log).mtimeMs > windowMs) continue;
|
|
15580
15773
|
const sib = {
|
|
15581
|
-
dir: (0,
|
|
15774
|
+
dir: (0, import_node_path15.join)(dir, entry.name),
|
|
15582
15775
|
identity,
|
|
15583
15776
|
eventsPath: log,
|
|
15584
|
-
foldPath: (0,
|
|
15585
|
-
rotatedDir: (0,
|
|
15777
|
+
foldPath: (0, import_node_path15.join)(dir, entry.name, "fold.json"),
|
|
15778
|
+
rotatedDir: (0, import_node_path15.join)(dir, entry.name, "rotated")
|
|
15586
15779
|
};
|
|
15587
15780
|
const state = readFoldCache(sib) ?? foldDossier(sib);
|
|
15588
15781
|
sessions++;
|
|
@@ -15610,22 +15803,22 @@ function pruneOldDossiers(identity, maxAgeMs = 7 * 24 * 60 * 60 * 1e3) {
|
|
|
15610
15803
|
let removed = 0;
|
|
15611
15804
|
try {
|
|
15612
15805
|
const mine = dossierDir(identity);
|
|
15613
|
-
const userDir = (0,
|
|
15806
|
+
const userDir = (0, import_node_path15.dirname)((0, import_node_path15.dirname)(mine));
|
|
15614
15807
|
if (!(0, import_node_fs17.existsSync)(userDir)) return 0;
|
|
15615
15808
|
const cutoff = Date.now() - maxAgeMs;
|
|
15616
15809
|
for (const tree of (0, import_node_fs17.readdirSync)(userDir, { withFileTypes: true })) {
|
|
15617
15810
|
if (!tree.isDirectory()) continue;
|
|
15618
|
-
const treePath = (0,
|
|
15811
|
+
const treePath = (0, import_node_path15.join)(userDir, tree.name);
|
|
15619
15812
|
let live = 0;
|
|
15620
15813
|
for (const entry of (0, import_node_fs17.readdirSync)(treePath, { withFileTypes: true })) {
|
|
15621
15814
|
if (!entry.isDirectory()) continue;
|
|
15622
|
-
const dir = (0,
|
|
15815
|
+
const dir = (0, import_node_path15.join)(treePath, entry.name);
|
|
15623
15816
|
if (dir === mine) {
|
|
15624
15817
|
live++;
|
|
15625
15818
|
continue;
|
|
15626
15819
|
}
|
|
15627
15820
|
try {
|
|
15628
|
-
const log = (0,
|
|
15821
|
+
const log = (0, import_node_path15.join)(dir, "events.jsonl");
|
|
15629
15822
|
const at = (0, import_node_fs17.existsSync)(log) ? (0, import_node_fs17.statSync)(log).mtimeMs : (0, import_node_fs17.statSync)(dir).mtimeMs;
|
|
15630
15823
|
if (at < cutoff) {
|
|
15631
15824
|
(0, import_node_fs17.rmSync)(dir, { recursive: true, force: true });
|
|
@@ -15680,7 +15873,7 @@ function recordTurn(d, t) {
|
|
|
15680
15873
|
for (const a of t.authored) {
|
|
15681
15874
|
const origin = a.owner === "subagent" ? "subagent" : "edit_tool";
|
|
15682
15875
|
const prior = t.known?.authored?.get(a.p);
|
|
15683
|
-
const hash = fileHash((0,
|
|
15876
|
+
const hash = fileHash((0, import_node_path15.join)(root, a.p));
|
|
15684
15877
|
const hunks = Math.max(0, a.h - (prior?.hunks ?? 0));
|
|
15685
15878
|
const adds = Math.max(0, a.a - (prior?.adds ?? 0));
|
|
15686
15879
|
const dels = Math.max(0, a.d - (prior?.dels ?? 0));
|
|
@@ -15713,7 +15906,7 @@ function recordTurn(d, t) {
|
|
|
15713
15906
|
}
|
|
15714
15907
|
const seenDivergence = t.known?.divergence ?? /* @__PURE__ */ new Set();
|
|
15715
15908
|
for (const u of t.unobserved) {
|
|
15716
|
-
const hash = fileHash((0,
|
|
15909
|
+
const hash = fileHash((0, import_node_path15.join)(root, u.p));
|
|
15717
15910
|
if (seenDivergence.has(divergenceKey(u.p, hash))) continue;
|
|
15718
15911
|
appendEvent(d, { k: "divergence", kind: "external_mutation", path: u.p, hash });
|
|
15719
15912
|
}
|
|
@@ -15748,7 +15941,7 @@ function recordVerdict(d, v) {
|
|
|
15748
15941
|
if (!sent.has(f.file)) continue;
|
|
15749
15942
|
if (!lines.has(f.file)) {
|
|
15750
15943
|
try {
|
|
15751
|
-
const abs = (0,
|
|
15944
|
+
const abs = (0, import_node_path15.join)(root, f.file);
|
|
15752
15945
|
lines.set(f.file, (0, import_node_fs17.existsSync)(abs) ? (0, import_node_fs17.readFileSync)(abs, "utf8").split("\n") : null);
|
|
15753
15946
|
} catch {
|
|
15754
15947
|
lines.set(f.file, null);
|
|
@@ -15849,7 +16042,7 @@ function recallMemory(d, identity, opts) {
|
|
|
15849
16042
|
budgetBytes: opts.budgetBytes,
|
|
15850
16043
|
readFileLines: (file) => {
|
|
15851
16044
|
try {
|
|
15852
|
-
const abs = (0,
|
|
16045
|
+
const abs = (0, import_node_path15.join)(root, file);
|
|
15853
16046
|
return (0, import_node_fs17.existsSync)(abs) ? (0, import_node_fs17.readFileSync)(abs, "utf8").split("\n") : null;
|
|
15854
16047
|
} catch {
|
|
15855
16048
|
return null;
|
|
@@ -15995,21 +16188,21 @@ async function fireClassify(prompt, sessionId, globals) {
|
|
|
15995
16188
|
|
|
15996
16189
|
// src/commands/lifecycle.ts
|
|
15997
16190
|
var import_node_fs21 = require("node:fs");
|
|
15998
|
-
var
|
|
16191
|
+
var import_node_path19 = require("node:path");
|
|
15999
16192
|
|
|
16000
16193
|
// src/lib/baseline.ts
|
|
16001
16194
|
var import_node_fs20 = require("node:fs");
|
|
16002
|
-
var
|
|
16195
|
+
var import_node_path18 = require("node:path");
|
|
16003
16196
|
var import_node_crypto9 = require("node:crypto");
|
|
16004
16197
|
|
|
16005
16198
|
// src/lib/snapshot.ts
|
|
16006
16199
|
var import_node_fs19 = require("node:fs");
|
|
16007
|
-
var
|
|
16200
|
+
var import_node_path17 = require("node:path");
|
|
16008
16201
|
var import_node_child_process6 = require("node:child_process");
|
|
16009
16202
|
|
|
16010
16203
|
// src/lib/files.ts
|
|
16011
16204
|
var import_node_fs18 = require("node:fs");
|
|
16012
|
-
var
|
|
16205
|
+
var import_node_path16 = require("node:path");
|
|
16013
16206
|
var LANG_MAP = {
|
|
16014
16207
|
// Analyzable (static analysis + Gemini)
|
|
16015
16208
|
ts: "typescript",
|
|
@@ -16077,7 +16270,7 @@ var LANG_MAP = {
|
|
|
16077
16270
|
mk: "make"
|
|
16078
16271
|
};
|
|
16079
16272
|
function detectLanguage(filepath) {
|
|
16080
|
-
const ext = (0,
|
|
16273
|
+
const ext = (0, import_node_path16.extname)(filepath).slice(1);
|
|
16081
16274
|
return LANG_MAP[ext] ?? ext;
|
|
16082
16275
|
}
|
|
16083
16276
|
function sortByMtime(files) {
|
|
@@ -16180,7 +16373,7 @@ function generateSnapshotDiffs(files) {
|
|
|
16180
16373
|
const diffs = [];
|
|
16181
16374
|
for (const file of files) {
|
|
16182
16375
|
if (!resolveInside(SNAPSHOT_DIR, file.path)) continue;
|
|
16183
|
-
const snapshotPath = (0,
|
|
16376
|
+
const snapshotPath = (0, import_node_path17.join)(SNAPSHOT_DIR, file.path);
|
|
16184
16377
|
const language = file.language ?? detectLanguage(file.path);
|
|
16185
16378
|
if ((0, import_node_fs19.existsSync)(snapshotPath)) {
|
|
16186
16379
|
const oldContent = (0, import_node_fs19.readFileSync)(snapshotPath, "utf-8");
|
|
@@ -16208,16 +16401,16 @@ function saveSnapshots(files) {
|
|
|
16208
16401
|
const snapshotPaths = /* @__PURE__ */ new Set();
|
|
16209
16402
|
for (const file of files) {
|
|
16210
16403
|
if (!resolveInside(SNAPSHOT_DIR, file.path)) continue;
|
|
16211
|
-
const snapshotPath = (0,
|
|
16404
|
+
const snapshotPath = (0, import_node_path17.join)(SNAPSHOT_DIR, file.path);
|
|
16212
16405
|
snapshotPaths.add(snapshotPath);
|
|
16213
|
-
(0, import_node_fs19.mkdirSync)((0,
|
|
16406
|
+
(0, import_node_fs19.mkdirSync)((0, import_node_path17.dirname)(snapshotPath), { recursive: true });
|
|
16214
16407
|
(0, import_node_fs19.writeFileSync)(snapshotPath, file.content);
|
|
16215
16408
|
}
|
|
16216
16409
|
cleanStaleSnapshots(SNAPSHOT_DIR, snapshotPaths);
|
|
16217
16410
|
}
|
|
16218
16411
|
function computeDiff(oldContent, newContent, filePath) {
|
|
16219
|
-
const tmpOld = (0,
|
|
16220
|
-
const tmpNew = (0,
|
|
16412
|
+
const tmpOld = (0, import_node_path17.join)(SNAPSHOT_DIR, ".diff-old.tmp");
|
|
16413
|
+
const tmpNew = (0, import_node_path17.join)(SNAPSHOT_DIR, ".diff-new.tmp");
|
|
16221
16414
|
try {
|
|
16222
16415
|
(0, import_node_fs19.mkdirSync)(SNAPSHOT_DIR, { recursive: true });
|
|
16223
16416
|
(0, import_node_fs19.writeFileSync)(tmpOld, oldContent);
|
|
@@ -16250,7 +16443,7 @@ function cleanStaleSnapshots(dir, keepSet) {
|
|
|
16250
16443
|
const entries = (0, import_node_fs19.readdirSync)(dir, { withFileTypes: true });
|
|
16251
16444
|
for (const entry of entries) {
|
|
16252
16445
|
if (dir === SNAPSHOT_DIR && (entry.name === ".diff-old.tmp" || entry.name === ".diff-new.tmp")) continue;
|
|
16253
|
-
const fullPath = (0,
|
|
16446
|
+
const fullPath = (0, import_node_path17.join)(dir, entry.name);
|
|
16254
16447
|
if (entry.isDirectory()) {
|
|
16255
16448
|
cleanStaleSnapshots(fullPath, keepSet);
|
|
16256
16449
|
try {
|
|
@@ -16279,13 +16472,13 @@ function sessionKey(sessionId) {
|
|
|
16279
16472
|
return (0, import_node_crypto9.createHash)("sha256").update(sessionId).digest("hex").slice(0, 16);
|
|
16280
16473
|
}
|
|
16281
16474
|
function sessionDir(key) {
|
|
16282
|
-
return (0,
|
|
16475
|
+
return (0, import_node_path18.join)(projectPath(BASELINE_DIR), key);
|
|
16283
16476
|
}
|
|
16284
16477
|
function manifestPath(dir) {
|
|
16285
|
-
return (0,
|
|
16478
|
+
return (0, import_node_path18.join)(dir, "manifest.json");
|
|
16286
16479
|
}
|
|
16287
16480
|
function mirrorPath(dir, repoRelPath) {
|
|
16288
|
-
return (0,
|
|
16481
|
+
return (0, import_node_path18.join)(dir, "files", repoRelPath);
|
|
16289
16482
|
}
|
|
16290
16483
|
var CARRY_FILE = `${BASELINE_DIR}/.carry`;
|
|
16291
16484
|
var CARRY_WINDOW_MS = 12e4;
|
|
@@ -16347,7 +16540,7 @@ function captureBaseline(opts = {}) {
|
|
|
16347
16540
|
(0, import_node_fs20.rmSync)(dir, { recursive: true, force: true });
|
|
16348
16541
|
} catch {
|
|
16349
16542
|
}
|
|
16350
|
-
const filesDir = (0,
|
|
16543
|
+
const filesDir = (0, import_node_path18.join)(dir, "files");
|
|
16351
16544
|
const mirrored = [];
|
|
16352
16545
|
try {
|
|
16353
16546
|
(0, import_node_fs20.mkdirSync)(filesDir, { recursive: true });
|
|
@@ -16357,7 +16550,7 @@ function captureBaseline(opts = {}) {
|
|
|
16357
16550
|
if (content === null) continue;
|
|
16358
16551
|
const dest = mirrorPath(dir, p);
|
|
16359
16552
|
try {
|
|
16360
|
-
(0, import_node_fs20.mkdirSync)((0,
|
|
16553
|
+
(0, import_node_fs20.mkdirSync)((0, import_node_path18.dirname)(dest), { recursive: true });
|
|
16361
16554
|
(0, import_node_fs20.writeFileSync)(dest, content);
|
|
16362
16555
|
mirrored.push(p);
|
|
16363
16556
|
} catch {
|
|
@@ -16465,7 +16658,7 @@ function absorbIntoBaseline(paths, sessionId) {
|
|
|
16465
16658
|
const content = safeReadForMirror(projectPath(p));
|
|
16466
16659
|
if (content === null) continue;
|
|
16467
16660
|
const dest = mirrorPath(dir, p);
|
|
16468
|
-
(0, import_node_fs20.mkdirSync)((0,
|
|
16661
|
+
(0, import_node_fs20.mkdirSync)((0, import_node_path18.dirname)(dest), { recursive: true });
|
|
16469
16662
|
(0, import_node_fs20.writeFileSync)(dest, content);
|
|
16470
16663
|
dirty.add(p);
|
|
16471
16664
|
adopted++;
|
|
@@ -16513,7 +16706,7 @@ function pruneOldBaselines() {
|
|
|
16513
16706
|
}
|
|
16514
16707
|
const now = Date.now();
|
|
16515
16708
|
for (const name of entries) {
|
|
16516
|
-
const dir = (0,
|
|
16709
|
+
const dir = (0, import_node_path18.join)(root, name);
|
|
16517
16710
|
const manifest = readManifest(dir);
|
|
16518
16711
|
if (!manifest) {
|
|
16519
16712
|
try {
|
|
@@ -16701,7 +16894,7 @@ function buildCompactionContext(session) {
|
|
|
16701
16894
|
commitsSince: commitsSincePaths(watermark, (state.authored ?? []).map((a) => a.path)),
|
|
16702
16895
|
readFileLines: (file) => {
|
|
16703
16896
|
try {
|
|
16704
|
-
const abs = (0,
|
|
16897
|
+
const abs = (0, import_node_path19.join)(root, file);
|
|
16705
16898
|
return (0, import_node_fs21.existsSync)(abs) ? (0, import_node_fs21.readFileSync)(abs, "utf8").split("\n") : null;
|
|
16706
16899
|
} catch {
|
|
16707
16900
|
return null;
|
|
@@ -16738,17 +16931,17 @@ async function readHookStdin() {
|
|
|
16738
16931
|
try {
|
|
16739
16932
|
if (process.stdin.isTTY) return {};
|
|
16740
16933
|
const chunks = [];
|
|
16741
|
-
const timeout = new Promise((
|
|
16742
|
-
const read = new Promise((
|
|
16934
|
+
const timeout = new Promise((resolve5) => setTimeout(() => resolve5({}), 500));
|
|
16935
|
+
const read = new Promise((resolve5) => {
|
|
16743
16936
|
process.stdin.on("data", (c) => chunks.push(c));
|
|
16744
16937
|
process.stdin.on("end", () => {
|
|
16745
16938
|
try {
|
|
16746
|
-
|
|
16939
|
+
resolve5(JSON.parse(Buffer.concat(chunks).toString("utf-8").trim() || "{}"));
|
|
16747
16940
|
} catch {
|
|
16748
|
-
|
|
16941
|
+
resolve5({});
|
|
16749
16942
|
}
|
|
16750
16943
|
});
|
|
16751
|
-
process.stdin.on("error", () =>
|
|
16944
|
+
process.stdin.on("error", () => resolve5({}));
|
|
16752
16945
|
process.stdin.resume();
|
|
16753
16946
|
});
|
|
16754
16947
|
return await Promise.race([read, timeout]);
|
|
@@ -16766,17 +16959,17 @@ var import_yaml3 = __toESM(require_dist());
|
|
|
16766
16959
|
var import_node_child_process8 = require("node:child_process");
|
|
16767
16960
|
var import_node_fs24 = require("node:fs");
|
|
16768
16961
|
var import_promises9 = require("node:fs/promises");
|
|
16769
|
-
var
|
|
16962
|
+
var import_node_path22 = require("node:path");
|
|
16770
16963
|
var import_yaml = __toESM(require_dist());
|
|
16771
16964
|
|
|
16772
16965
|
// src/lib/data-dir.ts
|
|
16773
16966
|
var import_node_fs22 = require("node:fs");
|
|
16774
|
-
var
|
|
16967
|
+
var import_node_path20 = require("node:path");
|
|
16775
16968
|
function resolveDataDir() {
|
|
16776
|
-
const
|
|
16777
|
-
(0,
|
|
16969
|
+
const candidates2 = [
|
|
16970
|
+
(0, import_node_path20.join)(__dirname, "..", "data"),
|
|
16778
16971
|
// installed: node_modules/@codacy/verity-cli/data
|
|
16779
|
-
(0,
|
|
16972
|
+
(0, import_node_path20.join)(__dirname, "..", "..", "data"),
|
|
16780
16973
|
// edge case: nested resolution
|
|
16781
16974
|
// THE COMMITTED SOURCE, for a source checkout that has not been built.
|
|
16782
16975
|
// cli/data/skills/ is a BUILD ARTIFACT (scripts/build.js copies client/skills
|
|
@@ -16785,14 +16978,14 @@ function resolveDataDir() {
|
|
|
16785
16978
|
// without this the synthesizer throws "Could not find Verity skill data"
|
|
16786
16979
|
// for every test and every `verity` run from source. Resolved from this
|
|
16787
16980
|
// module's own location, never the cwd: see the warning below.
|
|
16788
|
-
(0,
|
|
16981
|
+
(0, import_node_path20.join)(__dirname, "..", "..", "client"),
|
|
16789
16982
|
// bundled: cli/bin/ → ../../client
|
|
16790
|
-
(0,
|
|
16983
|
+
(0, import_node_path20.join)(__dirname, "..", "..", "..", "client"),
|
|
16791
16984
|
// tsx: cli/src/lib/ → ../../../client
|
|
16792
16985
|
...process.env.VERITY_DEV_DATA_DIR ? [process.env.VERITY_DEV_DATA_DIR] : []
|
|
16793
16986
|
];
|
|
16794
|
-
for (const candidate of
|
|
16795
|
-
if ((0, import_node_fs22.existsSync)((0,
|
|
16987
|
+
for (const candidate of candidates2) {
|
|
16988
|
+
if ((0, import_node_fs22.existsSync)((0, import_node_path20.join)(candidate, "skills"))) {
|
|
16796
16989
|
return candidate;
|
|
16797
16990
|
}
|
|
16798
16991
|
}
|
|
@@ -16801,13 +16994,13 @@ function resolveDataDir() {
|
|
|
16801
16994
|
);
|
|
16802
16995
|
}
|
|
16803
16996
|
function setupDataPath(file) {
|
|
16804
|
-
return (0,
|
|
16997
|
+
return (0, import_node_path20.join)(resolveDataDir(), "skills", "verity-setup", file);
|
|
16805
16998
|
}
|
|
16806
16999
|
|
|
16807
17000
|
// src/lib/detect.ts
|
|
16808
17001
|
var import_node_child_process7 = require("node:child_process");
|
|
16809
17002
|
var import_node_fs23 = require("node:fs");
|
|
16810
|
-
var
|
|
17003
|
+
var import_node_path21 = require("node:path");
|
|
16811
17004
|
var TOOLED_LANGUAGES = /* @__PURE__ */ new Set([
|
|
16812
17005
|
"typescript",
|
|
16813
17006
|
"javascript",
|
|
@@ -16870,18 +17063,18 @@ function walk(root) {
|
|
|
16870
17063
|
for (const entry of entries) {
|
|
16871
17064
|
if (found.length >= WALK_MAX_FILES) return;
|
|
16872
17065
|
if (IGNORED_SEGMENTS.includes(entry.name)) continue;
|
|
16873
|
-
const full = (0,
|
|
17066
|
+
const full = (0, import_node_path21.join)(dir, entry.name);
|
|
16874
17067
|
if (entry.isDirectory()) visit(full, depth + 1);
|
|
16875
|
-
else if (entry.isFile()) found.push((0,
|
|
17068
|
+
else if (entry.isFile()) found.push((0, import_node_path21.relative)(root, full));
|
|
16876
17069
|
}
|
|
16877
17070
|
};
|
|
16878
17071
|
visit(root, 0);
|
|
16879
17072
|
return found;
|
|
16880
17073
|
}
|
|
16881
17074
|
function languageOf(path) {
|
|
16882
|
-
const name = (0,
|
|
17075
|
+
const name = (0, import_node_path21.basename)(path);
|
|
16883
17076
|
if (/^Dockerfile(\..+)?$/i.test(name)) return "dockerfile";
|
|
16884
|
-
if (!(0,
|
|
17077
|
+
if (!(0, import_node_path21.extname)(name)) return null;
|
|
16885
17078
|
const lang = detectLanguage(path);
|
|
16886
17079
|
return lang || null;
|
|
16887
17080
|
}
|
|
@@ -16963,12 +17156,12 @@ function declaredDependencies(root, files) {
|
|
|
16963
17156
|
if (deps && typeof deps === "object") names2.push(...Object.keys(deps));
|
|
16964
17157
|
}
|
|
16965
17158
|
};
|
|
16966
|
-
readPackageJson((0,
|
|
16967
|
-
const nested = files.filter((f) => f.includes("/") && (0,
|
|
16968
|
-
for (const rel of nested) readPackageJson((0,
|
|
17159
|
+
readPackageJson((0, import_node_path21.join)(root, "package.json"));
|
|
17160
|
+
const nested = files.filter((f) => f.includes("/") && (0, import_node_path21.basename)(f) === "package.json").slice(0, NESTED_MANIFEST_LIMIT);
|
|
17161
|
+
for (const rel of nested) readPackageJson((0, import_node_path21.join)(root, rel));
|
|
16969
17162
|
const pythonManifests = [
|
|
16970
|
-
...["pyproject.toml", "requirements.txt", "Pipfile", "setup.py"].map((f) => (0,
|
|
16971
|
-
...files.filter((f) => f.includes("/") && /(^|\/)(pyproject\.toml|requirements\.txt)$/.test(f)).slice(0, NESTED_MANIFEST_LIMIT).map((f) => (0,
|
|
17163
|
+
...["pyproject.toml", "requirements.txt", "Pipfile", "setup.py"].map((f) => (0, import_node_path21.join)(root, f)),
|
|
17164
|
+
...files.filter((f) => f.includes("/") && /(^|\/)(pyproject\.toml|requirements\.txt)$/.test(f)).slice(0, NESTED_MANIFEST_LIMIT).map((f) => (0, import_node_path21.join)(root, f))
|
|
16972
17165
|
];
|
|
16973
17166
|
for (const path of pythonManifests) {
|
|
16974
17167
|
if (!(0, import_node_fs23.existsSync)(path)) continue;
|
|
@@ -16983,8 +17176,8 @@ function declaredDependencies(root, files) {
|
|
|
16983
17176
|
}
|
|
16984
17177
|
}
|
|
16985
17178
|
const goMods = [
|
|
16986
|
-
(0,
|
|
16987
|
-
...files.filter((f) => f.includes("/") && (0,
|
|
17179
|
+
(0, import_node_path21.join)(root, "go.mod"),
|
|
17180
|
+
...files.filter((f) => f.includes("/") && (0, import_node_path21.basename)(f) === "go.mod").slice(0, NESTED_MANIFEST_LIMIT).map((f) => (0, import_node_path21.join)(root, f))
|
|
16988
17181
|
];
|
|
16989
17182
|
for (const path of goMods) {
|
|
16990
17183
|
if (!(0, import_node_fs23.existsSync)(path)) continue;
|
|
@@ -16997,7 +17190,7 @@ function declaredDependencies(root, files) {
|
|
|
16997
17190
|
}
|
|
16998
17191
|
}
|
|
16999
17192
|
for (const file of ["pom.xml", "build.gradle", "build.gradle.kts", "Gemfile", "Cargo.toml"]) {
|
|
17000
|
-
const path = (0,
|
|
17193
|
+
const path = (0, import_node_path21.join)(root, file);
|
|
17001
17194
|
if (!(0, import_node_fs23.existsSync)(path)) continue;
|
|
17002
17195
|
try {
|
|
17003
17196
|
const text = (0, import_node_fs23.readFileSync)(path, "utf-8");
|
|
@@ -17008,7 +17201,7 @@ function declaredDependencies(root, files) {
|
|
|
17008
17201
|
return names2;
|
|
17009
17202
|
}
|
|
17010
17203
|
function detectBuildSystem(root, files) {
|
|
17011
|
-
const has = (f) => (0, import_node_fs23.existsSync)((0,
|
|
17204
|
+
const has = (f) => (0, import_node_fs23.existsSync)((0, import_node_path21.join)(root, f)) || files.some((p) => (0, import_node_path21.basename)(p) === f);
|
|
17012
17205
|
if (has("pnpm-lock.yaml")) return "pnpm";
|
|
17013
17206
|
if (has("yarn.lock")) return "yarn";
|
|
17014
17207
|
if (has("bun.lock") || has("bun.lockb")) return "bun";
|
|
@@ -17025,8 +17218,8 @@ function detectBuildSystem(root, files) {
|
|
|
17025
17218
|
}
|
|
17026
17219
|
function detectArchitecture(root, files) {
|
|
17027
17220
|
const workspaceMarkers = ["lerna.json", "pnpm-workspace.yaml", "nx.json", "turbo.json", "rush.json"];
|
|
17028
|
-
if (workspaceMarkers.some((m) => (0, import_node_fs23.existsSync)((0,
|
|
17029
|
-
const pkg = readJson((0,
|
|
17221
|
+
if (workspaceMarkers.some((m) => (0, import_node_fs23.existsSync)((0, import_node_path21.join)(root, m)))) return "monorepo";
|
|
17222
|
+
const pkg = readJson((0, import_node_path21.join)(root, "package.json"));
|
|
17030
17223
|
if (pkg && "workspaces" in pkg) return "monorepo";
|
|
17031
17224
|
const manifests = files.filter((f) => /(^|\/)(package\.json|go\.mod|pyproject\.toml|Cargo\.toml|pom\.xml)$/.test(f));
|
|
17032
17225
|
const nested = manifests.filter((f) => f.includes("/"));
|
|
@@ -17039,16 +17232,16 @@ function detectArchitecture(root, files) {
|
|
|
17039
17232
|
var SAMPLE_LIMIT = 300;
|
|
17040
17233
|
function measureAvgFileLength(root, files, languages) {
|
|
17041
17234
|
const primary = new Set(languages.slice(0, 2));
|
|
17042
|
-
const
|
|
17235
|
+
const candidates2 = files.filter((f) => {
|
|
17043
17236
|
const lang = languageOf(f);
|
|
17044
17237
|
return lang !== null && primary.has(lang);
|
|
17045
17238
|
});
|
|
17046
|
-
if (
|
|
17047
|
-
const stride = Math.max(1, Math.floor(
|
|
17239
|
+
if (candidates2.length === 0) return null;
|
|
17240
|
+
const stride = Math.max(1, Math.floor(candidates2.length / SAMPLE_LIMIT));
|
|
17048
17241
|
let total = 0;
|
|
17049
17242
|
let counted = 0;
|
|
17050
|
-
for (let i = 0; i <
|
|
17051
|
-
const path = (0,
|
|
17243
|
+
for (let i = 0; i < candidates2.length; i += stride) {
|
|
17244
|
+
const path = (0, import_node_path21.join)(root, candidates2[i]);
|
|
17052
17245
|
try {
|
|
17053
17246
|
if ((0, import_node_fs23.statSync)(path).size > 2 * 1024 * 1024) continue;
|
|
17054
17247
|
total += (0, import_node_fs23.readFileSync)(path, "utf-8").split("\n").length;
|
|
@@ -17076,14 +17269,14 @@ function detectProject(root = repoRoot()) {
|
|
|
17076
17269
|
const existingToolConfigs = [];
|
|
17077
17270
|
for (const [tool, markers] of TOOL_CONFIG_MARKERS) {
|
|
17078
17271
|
for (const marker of markers) {
|
|
17079
|
-
if ((0, import_node_fs23.existsSync)((0,
|
|
17272
|
+
if ((0, import_node_fs23.existsSync)((0, import_node_path21.join)(root, marker))) {
|
|
17080
17273
|
existingToolConfigs.push({ tool, path: `./${marker}` });
|
|
17081
17274
|
break;
|
|
17082
17275
|
}
|
|
17083
17276
|
}
|
|
17084
17277
|
}
|
|
17085
17278
|
return {
|
|
17086
|
-
projectName: (0,
|
|
17279
|
+
projectName: (0, import_node_path21.basename)(root),
|
|
17087
17280
|
languages,
|
|
17088
17281
|
languageCounts,
|
|
17089
17282
|
frameworks: matchAll(dependencies, FRAMEWORK_BY_DEPENDENCY),
|
|
@@ -17529,7 +17722,7 @@ async function correctVerityMdVersion(opts) {
|
|
|
17529
17722
|
}
|
|
17530
17723
|
async function writeFileTo(relative2, body) {
|
|
17531
17724
|
const target = projectPath(relative2);
|
|
17532
|
-
await (0, import_promises9.mkdir)((0,
|
|
17725
|
+
await (0, import_promises9.mkdir)((0, import_node_path22.dirname)(target), { recursive: true });
|
|
17533
17726
|
await (0, import_promises9.writeFile)(target, body);
|
|
17534
17727
|
}
|
|
17535
17728
|
async function deriveConfigForStandard(standard) {
|
|
@@ -18004,7 +18197,11 @@ function registerConfigCommands(program2) {
|
|
|
18004
18197
|
});
|
|
18005
18198
|
config.command("git-moments [moments]").description('Get or set the git moments the guard reviews: commit,push \u2014 or "none"').action((moments) => {
|
|
18006
18199
|
if (moments === void 0) {
|
|
18007
|
-
const
|
|
18200
|
+
const config2 = readProjectConfig();
|
|
18201
|
+
const current = config2.git_moments;
|
|
18202
|
+
if (config2.source === "main-worktree" && config2.path) {
|
|
18203
|
+
printInfo(`Inherited from the main worktree: ${config2.path}`);
|
|
18204
|
+
}
|
|
18008
18205
|
process.stdout.write((current.length ? current.join(",") : "none") + "\n");
|
|
18009
18206
|
return;
|
|
18010
18207
|
}
|
|
@@ -18013,7 +18210,7 @@ function registerConfigCommands(program2) {
|
|
|
18013
18210
|
printError(`Unrecognised moments: ${moments}. Use "commit", "push", "commit,push", or "none".`);
|
|
18014
18211
|
process.exit(1);
|
|
18015
18212
|
}
|
|
18016
|
-
writeProjectConfig({ git_moments: next });
|
|
18213
|
+
writeProjectConfig({ git_moments: next, git_moments_source: "user" });
|
|
18017
18214
|
printInfo(
|
|
18018
18215
|
next.length ? `Git-moment review enabled for: ${next.join(", ")}` : "Git-moment review disabled \u2014 commits and pushes are no longer gated."
|
|
18019
18216
|
);
|
|
@@ -18474,8 +18671,14 @@ function timeAgo(isoDate) {
|
|
|
18474
18671
|
return `${days}d ago`;
|
|
18475
18672
|
}
|
|
18476
18673
|
function registerStatusCommand(program2) {
|
|
18477
|
-
program2.command("status").description("Show project quality status").option("--history", "Include recent run history").option("--limit <n>", "Number of history entries", "5").option("--json", "Output raw JSON").action(async (opts) => {
|
|
18674
|
+
program2.command("status").description("Show project quality status").option("--history", "Include recent run history").option("--limit <n>", "Number of history entries (1-100)", "5").option("--json", "Output raw JSON").action(async (opts) => {
|
|
18478
18675
|
const globals = program2.opts();
|
|
18676
|
+
const rawLimit = String(opts.limit).trim();
|
|
18677
|
+
const limit = /^\d{1,3}$/.test(rawLimit) ? Number(rawLimit) : Number.NaN;
|
|
18678
|
+
if (!Number.isInteger(limit) || limit < 1 || limit > 100) {
|
|
18679
|
+
printError(`--limit must be a whole number between 1 and 100 (got "${opts.limit}").`);
|
|
18680
|
+
process.exit(1);
|
|
18681
|
+
}
|
|
18479
18682
|
const tokenResult = await resolveToken(globals.token);
|
|
18480
18683
|
if (!tokenResult.ok) {
|
|
18481
18684
|
printError(tokenResult.error);
|
|
@@ -18513,7 +18716,7 @@ function registerStatusCommand(program2) {
|
|
|
18513
18716
|
if (opts.history && !denial) {
|
|
18514
18717
|
const runsResult = await apiRequest({
|
|
18515
18718
|
method: "GET",
|
|
18516
|
-
path: `/runs?limit=${
|
|
18719
|
+
path: `/runs?limit=${limit}`,
|
|
18517
18720
|
serviceUrl,
|
|
18518
18721
|
token,
|
|
18519
18722
|
verbose: globals.verbose
|
|
@@ -18553,12 +18756,14 @@ function registerStatusCommand(program2) {
|
|
|
18553
18756
|
printInfo(`Standard: v${s.version} (${s.quality_dimensions} quality, ${s.security_patterns} security, ${s.custom_patterns} custom)`);
|
|
18554
18757
|
printInfo(`Languages: ${s.languages.join(", ")}`);
|
|
18555
18758
|
}
|
|
18556
|
-
const
|
|
18759
|
+
const wiring = await resolveHookWiring();
|
|
18760
|
+
const hookStatus = wiring.status;
|
|
18557
18761
|
const moments = [];
|
|
18558
18762
|
if (hookStatus.stop) moments.push("stop");
|
|
18559
18763
|
if (hookStatus.guardOn.includes("commit")) moments.push("pre-commit");
|
|
18560
18764
|
if (hookStatus.guardOn.includes("push")) moments.push("pre-push/PR");
|
|
18561
|
-
|
|
18765
|
+
const via = wiring.source === "plugin" ? " (wired by the Verity plugin)" : "";
|
|
18766
|
+
printInfo(`Moments: ${moments.length > 0 ? `${moments.join(", ")}${via}` : 'none (run "verity init")'}`);
|
|
18562
18767
|
if (!mem) return;
|
|
18563
18768
|
if (mem.recent_runs) {
|
|
18564
18769
|
const r = mem.recent_runs;
|
|
@@ -18635,7 +18840,7 @@ function registerStatusCommand(program2) {
|
|
|
18635
18840
|
if (opts.history) {
|
|
18636
18841
|
const runsResult = await apiRequest({
|
|
18637
18842
|
method: "GET",
|
|
18638
|
-
path: `/runs?limit=${
|
|
18843
|
+
path: `/runs?limit=${limit}`,
|
|
18639
18844
|
serviceUrl,
|
|
18640
18845
|
token,
|
|
18641
18846
|
verbose: globals.verbose
|
|
@@ -18826,11 +19031,11 @@ var import_node_fs43 = require("node:fs");
|
|
|
18826
19031
|
|
|
18827
19032
|
// src/lib/repo-context.ts
|
|
18828
19033
|
var import_node_child_process9 = require("node:child_process");
|
|
18829
|
-
var
|
|
19034
|
+
var import_node_os4 = require("node:os");
|
|
18830
19035
|
function rgInvocations(env = process.env) {
|
|
18831
19036
|
const out = [{ cmd: "rg" }];
|
|
18832
19037
|
if (env.CLAUDE_CODE_EXECPATH) out.push({ cmd: env.CLAUDE_CODE_EXECPATH, argv0: "rg" });
|
|
18833
|
-
out.push({ cmd: `${(0,
|
|
19038
|
+
out.push({ cmd: `${(0, import_node_os4.homedir)()}/.local/bin/claude`, argv0: "rg" });
|
|
18834
19039
|
return out;
|
|
18835
19040
|
}
|
|
18836
19041
|
var MAX_SYMBOLS = 12;
|
|
@@ -19644,9 +19849,9 @@ function installRunEvidence(run2) {
|
|
|
19644
19849
|
// src/lib/git-frame.ts
|
|
19645
19850
|
var import_node_child_process10 = require("node:child_process");
|
|
19646
19851
|
var import_node_fs31 = require("node:fs");
|
|
19647
|
-
var
|
|
19648
|
-
var
|
|
19649
|
-
var
|
|
19852
|
+
var import_node_os5 = require("node:os");
|
|
19853
|
+
var import_node_path23 = require("node:path");
|
|
19854
|
+
var import_node_path24 = require("node:path");
|
|
19650
19855
|
var VALUE_TOKEN = `(?:'[^']*'|"[^"]*"|\\S+)`;
|
|
19651
19856
|
var GIT_GLOBAL_OPTS = `(?:\\s+(?:-[Cc]\\s+${VALUE_TOKEN}|--?[\\w-]+(?:=\\S+)?))*`;
|
|
19652
19857
|
var COMMIT_HEAD = `git${GIT_GLOBAL_OPTS}\\s+commit(?![\\w-])`;
|
|
@@ -19692,15 +19897,15 @@ function extractCommandTarget(command, segmentIndex, baseDir) {
|
|
|
19692
19897
|
if (!m) continue;
|
|
19693
19898
|
named = true;
|
|
19694
19899
|
if (m[1] === void 0) {
|
|
19695
|
-
dir = (0,
|
|
19900
|
+
dir = (0, import_node_os5.homedir)();
|
|
19696
19901
|
continue;
|
|
19697
19902
|
}
|
|
19698
19903
|
const raw = unquote(m[1]);
|
|
19699
19904
|
if (SHELL_DYNAMIC.test(raw) || raw === "-") {
|
|
19700
19905
|
return { dir: null, named: true, unresolvable: `cd target not statically resolvable: ${raw}` };
|
|
19701
19906
|
}
|
|
19702
|
-
const expanded = raw === "~" ? (0,
|
|
19703
|
-
dir = (0,
|
|
19907
|
+
const expanded = raw === "~" ? (0, import_node_os5.homedir)() : raw.startsWith("~/") ? (0, import_node_path24.join)((0, import_node_os5.homedir)(), raw.slice(2)) : raw;
|
|
19908
|
+
dir = (0, import_node_path23.isAbsolute)(expanded) ? expanded : (0, import_node_path23.resolve)(dir, expanded);
|
|
19704
19909
|
}
|
|
19705
19910
|
const seg = segments[segmentIndex];
|
|
19706
19911
|
const overrideMatch = /--(?:git-dir|work-tree)(?:=|\s)|\bGIT_(?:DIR|WORK_TREE|INDEX_FILE)=/.exec(seg);
|
|
@@ -19718,8 +19923,8 @@ function extractCommandTarget(command, segmentIndex, baseDir) {
|
|
|
19718
19923
|
if (SHELL_DYNAMIC.test(raw)) {
|
|
19719
19924
|
return { dir: null, named: true, unresolvable: `-C target not statically resolvable: ${raw}` };
|
|
19720
19925
|
}
|
|
19721
|
-
const expanded = raw === "~" ? (0,
|
|
19722
|
-
dir = (0,
|
|
19926
|
+
const expanded = raw === "~" ? (0, import_node_os5.homedir)() : raw.startsWith("~/") ? (0, import_node_path24.join)((0, import_node_os5.homedir)(), raw.slice(2)) : raw;
|
|
19927
|
+
dir = (0, import_node_path23.isAbsolute)(expanded) ? expanded : (0, import_node_path23.resolve)(dir, expanded);
|
|
19723
19928
|
}
|
|
19724
19929
|
}
|
|
19725
19930
|
return { dir, named, unresolvable: null };
|
|
@@ -19780,11 +19985,11 @@ function gitAt(dir, args) {
|
|
|
19780
19985
|
return "";
|
|
19781
19986
|
}
|
|
19782
19987
|
}
|
|
19783
|
-
function
|
|
19988
|
+
function realpathOr2(p) {
|
|
19784
19989
|
try {
|
|
19785
19990
|
return import_node_fs31.realpathSync.native(p);
|
|
19786
19991
|
} catch {
|
|
19787
|
-
return (0,
|
|
19992
|
+
return (0, import_node_path23.resolve)(p);
|
|
19788
19993
|
}
|
|
19789
19994
|
}
|
|
19790
19995
|
function resolveFrame(input) {
|
|
@@ -19822,13 +20027,13 @@ function resolveFrame(input) {
|
|
|
19822
20027
|
}
|
|
19823
20028
|
const gitDirRaw = gitAt(dir, ["rev-parse", "--absolute-git-dir"]);
|
|
19824
20029
|
const commonRaw = gitAt(dir, ["rev-parse", "--git-common-dir"]);
|
|
19825
|
-
const gitDir = gitDirRaw ?
|
|
19826
|
-
const commonDir = commonRaw ?
|
|
20030
|
+
const gitDir = gitDirRaw ? realpathOr2(gitDirRaw) : null;
|
|
20031
|
+
const commonDir = commonRaw ? realpathOr2((0, import_node_path23.isAbsolute)(commonRaw) ? commonRaw : (0, import_node_path23.resolve)(dir, commonRaw)) : null;
|
|
19827
20032
|
const branchRaw = gitAt(dir, ["rev-parse", "--abbrev-ref", "HEAD"]);
|
|
19828
20033
|
return {
|
|
19829
20034
|
moment: found?.moment ?? null,
|
|
19830
20035
|
frame: {
|
|
19831
|
-
worktreeRoot:
|
|
20036
|
+
worktreeRoot: realpathOr2(toplevel),
|
|
19832
20037
|
gitDir,
|
|
19833
20038
|
commonDir,
|
|
19834
20039
|
// The one honest definition: a linked worktree's own git dir differs from
|
|
@@ -19848,14 +20053,172 @@ function refResolves(frame, ref) {
|
|
|
19848
20053
|
return frameGit(frame, ["rev-parse", "--verify", "-q", `${ref}^{commit}`]) !== "";
|
|
19849
20054
|
}
|
|
19850
20055
|
var SHA_RE2 = /^[0-9a-f]{40}$/;
|
|
19851
|
-
function
|
|
20056
|
+
function shellWords(segment) {
|
|
20057
|
+
return segment.match(/'[^']*'|"[^"]*"|\S+/g) ?? [];
|
|
20058
|
+
}
|
|
20059
|
+
var ADD_FLAGS_REPLAYABLE = /* @__PURE__ */ new Set([
|
|
20060
|
+
"-A",
|
|
20061
|
+
"--all",
|
|
20062
|
+
"--no-ignore-removal",
|
|
20063
|
+
"-u",
|
|
20064
|
+
"--update",
|
|
20065
|
+
"--no-all",
|
|
20066
|
+
"--ignore-removal",
|
|
20067
|
+
"-f",
|
|
20068
|
+
"--force",
|
|
20069
|
+
"-v",
|
|
20070
|
+
"--verbose",
|
|
20071
|
+
"-N",
|
|
20072
|
+
"--intent-to-add",
|
|
20073
|
+
"--renormalize",
|
|
20074
|
+
"--sparse",
|
|
20075
|
+
"--ignore-errors",
|
|
20076
|
+
"--refresh"
|
|
20077
|
+
]);
|
|
20078
|
+
var ADD_FLAGS_INTERACTIVE = /* @__PURE__ */ new Set(["-i", "--interactive", "-p", "--patch", "-e", "--edit"]);
|
|
20079
|
+
var PATHSPEC_UNRESOLVABLE = /[$`\\*?[\]{}~]/;
|
|
20080
|
+
var COMMIT_VALUE_OPTS = /* @__PURE__ */ new Set([
|
|
20081
|
+
"-m",
|
|
20082
|
+
"--message",
|
|
20083
|
+
"-F",
|
|
20084
|
+
"--file",
|
|
20085
|
+
"-C",
|
|
20086
|
+
"--reuse-message",
|
|
20087
|
+
"-c",
|
|
20088
|
+
"--reedit-message",
|
|
20089
|
+
"--author",
|
|
20090
|
+
"--date",
|
|
20091
|
+
"-t",
|
|
20092
|
+
"--template",
|
|
20093
|
+
"--fixup",
|
|
20094
|
+
"--squash",
|
|
20095
|
+
"--trailer",
|
|
20096
|
+
"--cleanup"
|
|
20097
|
+
]);
|
|
20098
|
+
var ADD_HEAD = `git${GIT_GLOBAL_OPTS}\\s+add(?![\\w-])`;
|
|
20099
|
+
var ADD_RE = new RegExp(`(?:^|[\\s;&|(])${ADD_HEAD}|(?:^|[;&|(])\\s*[^\\s;&|()'"]*\\/${ADD_HEAD}`);
|
|
20100
|
+
function pathspecOf(word) {
|
|
20101
|
+
const raw = unquote(word);
|
|
20102
|
+
if (!raw) return { reason: "an empty pathspec" };
|
|
20103
|
+
if (PATHSPEC_UNRESOLVABLE.test(raw)) {
|
|
20104
|
+
return { reason: `the shell rewrites the pathspec "${raw}" before git sees it` };
|
|
20105
|
+
}
|
|
20106
|
+
return { path: raw };
|
|
20107
|
+
}
|
|
20108
|
+
function parseAddSegment(segment) {
|
|
20109
|
+
const words = shellWords(segment);
|
|
20110
|
+
const at = words.indexOf("add");
|
|
20111
|
+
if (at === -1) return { reason: 'the "git add" arguments could not be read' };
|
|
20112
|
+
const flags = [];
|
|
20113
|
+
const paths = [];
|
|
20114
|
+
let literal = false;
|
|
20115
|
+
for (const word of words.slice(at + 1)) {
|
|
20116
|
+
if (literal || !word.startsWith("-") || word === "-") {
|
|
20117
|
+
if (word === "--" && !literal) {
|
|
20118
|
+
literal = true;
|
|
20119
|
+
continue;
|
|
20120
|
+
}
|
|
20121
|
+
const p = pathspecOf(word);
|
|
20122
|
+
if ("reason" in p) return p;
|
|
20123
|
+
paths.push(p.path);
|
|
20124
|
+
continue;
|
|
20125
|
+
}
|
|
20126
|
+
if (word === "--") {
|
|
20127
|
+
literal = true;
|
|
20128
|
+
continue;
|
|
20129
|
+
}
|
|
20130
|
+
const parts = /^-[A-Za-z]{2,}$/.test(word) ? [...word.slice(1)].map((c) => `-${c}`) : [word];
|
|
20131
|
+
for (const flag of parts) {
|
|
20132
|
+
if (ADD_FLAGS_INTERACTIVE.has(flag)) {
|
|
20133
|
+
return { reason: `"git add ${flag}" stages what a human picks at a prompt` };
|
|
20134
|
+
}
|
|
20135
|
+
if (!ADD_FLAGS_REPLAYABLE.has(flag.split("=")[0])) {
|
|
20136
|
+
return { reason: `unmodelled "git add" option ${flag}` };
|
|
20137
|
+
}
|
|
20138
|
+
flags.push(flag);
|
|
20139
|
+
}
|
|
20140
|
+
}
|
|
20141
|
+
return { flags, paths };
|
|
20142
|
+
}
|
|
20143
|
+
function commitStagesTrackedChanges(segment) {
|
|
20144
|
+
const words = shellWords(segment);
|
|
20145
|
+
const at = words.indexOf("commit");
|
|
20146
|
+
if (at === -1) return false;
|
|
20147
|
+
let skipValue = false;
|
|
20148
|
+
for (const word of words.slice(at + 1)) {
|
|
20149
|
+
if (skipValue) {
|
|
20150
|
+
skipValue = false;
|
|
20151
|
+
continue;
|
|
20152
|
+
}
|
|
20153
|
+
if (word === "--") break;
|
|
20154
|
+
if (!word.startsWith("-") || word === "-") continue;
|
|
20155
|
+
if (word.startsWith("--")) {
|
|
20156
|
+
const name = word.split("=")[0];
|
|
20157
|
+
if (name === "--all") return true;
|
|
20158
|
+
if (COMMIT_VALUE_OPTS.has(name) && !word.includes("=")) skipValue = true;
|
|
20159
|
+
continue;
|
|
20160
|
+
}
|
|
20161
|
+
for (let i = 1; i < word.length; i++) {
|
|
20162
|
+
const flag = `-${word[i]}`;
|
|
20163
|
+
if (flag === "-a") return true;
|
|
20164
|
+
if (COMMIT_VALUE_OPTS.has(flag)) {
|
|
20165
|
+
if (i === word.length - 1) skipValue = true;
|
|
20166
|
+
break;
|
|
20167
|
+
}
|
|
20168
|
+
}
|
|
20169
|
+
}
|
|
20170
|
+
return false;
|
|
20171
|
+
}
|
|
20172
|
+
function planInCommandStaging(frame, command) {
|
|
20173
|
+
const found = findMomentSegment(command, ["commit"]);
|
|
20174
|
+
if (!found) return { kind: "none" };
|
|
20175
|
+
const segments = splitSegments(command);
|
|
20176
|
+
if (commitStagesTrackedChanges(segments[found.segmentIndex])) {
|
|
20177
|
+
return {
|
|
20178
|
+
kind: "files",
|
|
20179
|
+
via: "index+commit-a",
|
|
20180
|
+
files: frameGit(frame, ["diff", "--name-only", "HEAD"]).split("\n").filter(Boolean)
|
|
20181
|
+
};
|
|
20182
|
+
}
|
|
20183
|
+
const addSegments = segments.slice(0, found.segmentIndex).filter((s) => ADD_RE.test(s));
|
|
20184
|
+
if (addSegments.length === 0) return { kind: "none" };
|
|
20185
|
+
const staged = new Set(
|
|
20186
|
+
frameGit(frame, ["diff", "--cached", "--name-only"]).split("\n").filter(Boolean)
|
|
20187
|
+
);
|
|
20188
|
+
for (const segment of addSegments) {
|
|
20189
|
+
const parsed = parseAddSegment(segment);
|
|
20190
|
+
if ("reason" in parsed) return { kind: "unpredictable", reason: parsed.reason };
|
|
20191
|
+
const args = ["add", "--dry-run", "--ignore-missing", ...parsed.flags];
|
|
20192
|
+
if (parsed.paths.length > 0) args.push("--", ...parsed.paths);
|
|
20193
|
+
for (const line of frameGit(frame, args).split("\n")) {
|
|
20194
|
+
const m = line.match(/^(?:add|remove) '(.*)'$/);
|
|
20195
|
+
if (m) staged.add(m[1]);
|
|
20196
|
+
}
|
|
20197
|
+
}
|
|
20198
|
+
return { kind: "files", via: "index+staged-in-command", files: [...staged] };
|
|
20199
|
+
}
|
|
20200
|
+
function stagedRange(frame, command) {
|
|
19852
20201
|
if (!frame.worktreeRoot) return { kind: "nothing", base: null, head: "INDEX", via: "refused" };
|
|
19853
|
-
const
|
|
20202
|
+
const plan = command ? planInCommandStaging(frame, command) : { kind: "none" };
|
|
20203
|
+
if (plan.kind === "unpredictable") {
|
|
20204
|
+
return { kind: "staged", base: "HEAD", head: "INDEX", via: "staged-in-command", refusal: plan.reason };
|
|
20205
|
+
}
|
|
20206
|
+
const mergeHead = frame.gitDir ? (0, import_node_path24.join)(frame.gitDir, "MERGE_HEAD") : null;
|
|
19854
20207
|
if (mergeHead && (0, import_node_fs31.existsSync)(mergeHead)) {
|
|
19855
20208
|
const vsHead = new Set(frameGit(frame, ["diff", "--cached", "--name-only", "HEAD"]).split("\n").filter(Boolean));
|
|
19856
20209
|
const vsMerge = new Set(frameGit(frame, ["diff", "--cached", "--name-only", "MERGE_HEAD"]).split("\n").filter(Boolean));
|
|
19857
|
-
const resolutions = [...vsHead].filter((f) => vsMerge.has(f) && !isVerityOwnedPath(f));
|
|
19858
|
-
|
|
20210
|
+
const resolutions = new Set([...vsHead].filter((f) => vsMerge.has(f) && !isVerityOwnedPath(f)));
|
|
20211
|
+
if (plan.kind === "files") {
|
|
20212
|
+
const wtVsHead = new Set(frameGit(frame, ["diff", "--name-only", "HEAD"]).split("\n").filter(Boolean));
|
|
20213
|
+
const wtVsMerge = new Set(frameGit(frame, ["diff", "--name-only", "MERGE_HEAD"]).split("\n").filter(Boolean));
|
|
20214
|
+
for (const f of plan.files) {
|
|
20215
|
+
if (wtVsHead.has(f) && wtVsMerge.has(f) && !isVerityOwnedPath(f)) resolutions.add(f);
|
|
20216
|
+
}
|
|
20217
|
+
}
|
|
20218
|
+
return { kind: "merge", base: "HEAD", head: "INDEX", via: "merge-resolutions", files: [...resolutions] };
|
|
20219
|
+
}
|
|
20220
|
+
if (plan.kind === "files") {
|
|
20221
|
+
return { kind: "staged", base: "HEAD", head: "INDEX", via: plan.via, files: plan.files };
|
|
19859
20222
|
}
|
|
19860
20223
|
return { kind: "staged", base: "HEAD", head: "INDEX", via: "index" };
|
|
19861
20224
|
}
|
|
@@ -19937,7 +20300,7 @@ function frameTelemetry(frame, range, divergence) {
|
|
|
19937
20300
|
refusal: frame.refusal
|
|
19938
20301
|
};
|
|
19939
20302
|
if (divergence) {
|
|
19940
|
-
t.root_differs = !!frame.worktreeRoot && !!divergence.actualRoot &&
|
|
20303
|
+
t.root_differs = !!frame.worktreeRoot && !!divergence.actualRoot && realpathOr2(frame.worktreeRoot) !== realpathOr2(divergence.actualRoot);
|
|
19941
20304
|
const a = [...divergence.actualFiles].sort().join("\n");
|
|
19942
20305
|
const b = [...divergence.frameFiles].sort().join("\n");
|
|
19943
20306
|
t.files_differ = a !== b;
|
|
@@ -20247,7 +20610,7 @@ function sanitizeCommandWithLoss(rawCmd) {
|
|
|
20247
20610
|
const lost = lines.slice(1).some((l) => l.trim().length > 0);
|
|
20248
20611
|
const first = lines[0];
|
|
20249
20612
|
const cmd = sanitizeCommand(first);
|
|
20250
|
-
const hadSeparator = SEPARATORS.some((
|
|
20613
|
+
const hadSeparator = SEPARATORS.some((sep3) => first.indexOf(sep3) > 0);
|
|
20251
20614
|
return { cmd, lost: lost || !hadSeparator && first.length > MAX_COMMAND_CHARS };
|
|
20252
20615
|
}
|
|
20253
20616
|
var SEPARATORS = [" | ", " > ", " >> ", " 2>", " && ", " ; "];
|
|
@@ -20256,11 +20619,11 @@ function sanitizeCommand(rawCmd) {
|
|
|
20256
20619
|
let cmd = rawCmd.split("\n")[0];
|
|
20257
20620
|
let cut = -1;
|
|
20258
20621
|
let marker = "";
|
|
20259
|
-
for (const
|
|
20260
|
-
const idx = cmd.indexOf(
|
|
20622
|
+
for (const sep3 of SEPARATORS) {
|
|
20623
|
+
const idx = cmd.indexOf(sep3);
|
|
20261
20624
|
if (idx > 0 && (cut === -1 || idx < cut)) {
|
|
20262
20625
|
cut = idx;
|
|
20263
|
-
marker =
|
|
20626
|
+
marker = sep3.trim();
|
|
20264
20627
|
}
|
|
20265
20628
|
}
|
|
20266
20629
|
if (cut > -1) cmd = cmd.slice(0, cut);
|
|
@@ -20284,28 +20647,28 @@ async function readStopHookStdin() {
|
|
|
20284
20647
|
try {
|
|
20285
20648
|
if (process.stdin.isTTY) return empty;
|
|
20286
20649
|
const chunks = [];
|
|
20287
|
-
const timeout = new Promise((
|
|
20288
|
-
const read = new Promise((
|
|
20650
|
+
const timeout = new Promise((resolve5) => setTimeout(() => resolve5(empty), 500));
|
|
20651
|
+
const read = new Promise((resolve5) => {
|
|
20289
20652
|
process.stdin.on("data", (chunk) => chunks.push(chunk));
|
|
20290
20653
|
process.stdin.on("end", () => {
|
|
20291
20654
|
const raw = Buffer.concat(chunks).toString("utf-8").trim();
|
|
20292
20655
|
if (!raw) {
|
|
20293
|
-
|
|
20656
|
+
resolve5(empty);
|
|
20294
20657
|
return;
|
|
20295
20658
|
}
|
|
20296
20659
|
try {
|
|
20297
20660
|
const data = JSON.parse(raw);
|
|
20298
|
-
|
|
20661
|
+
resolve5({
|
|
20299
20662
|
assistantMessage: typeof data.last_assistant_message === "string" ? data.last_assistant_message : null,
|
|
20300
20663
|
stopReason: typeof data.stop_reason === "string" ? data.stop_reason : null,
|
|
20301
20664
|
transcriptPath: typeof data.transcript_path === "string" ? data.transcript_path : null,
|
|
20302
20665
|
sessionId: typeof data.session_id === "string" ? data.session_id : null
|
|
20303
20666
|
});
|
|
20304
20667
|
} catch {
|
|
20305
|
-
|
|
20668
|
+
resolve5(empty);
|
|
20306
20669
|
}
|
|
20307
20670
|
});
|
|
20308
|
-
process.stdin.on("error", () =>
|
|
20671
|
+
process.stdin.on("error", () => resolve5(empty));
|
|
20309
20672
|
process.stdin.resume();
|
|
20310
20673
|
});
|
|
20311
20674
|
return await Promise.race([read, timeout]);
|
|
@@ -20509,7 +20872,7 @@ function channelSilence(input) {
|
|
|
20509
20872
|
// src/lib/cli-version.ts
|
|
20510
20873
|
function cliVersion() {
|
|
20511
20874
|
try {
|
|
20512
|
-
return true ? "0.32.
|
|
20875
|
+
return true ? "0.32.1-experimental.c640abd" : "dev";
|
|
20513
20876
|
} catch {
|
|
20514
20877
|
return "dev";
|
|
20515
20878
|
}
|
|
@@ -20868,7 +21231,7 @@ async function scope(run2) {
|
|
|
20868
21231
|
|
|
20869
21232
|
// src/lib/specs.ts
|
|
20870
21233
|
var import_node_fs34 = require("node:fs");
|
|
20871
|
-
var
|
|
21234
|
+
var import_node_path25 = require("node:path");
|
|
20872
21235
|
var SPEC_CANDIDATES = [
|
|
20873
21236
|
"CLAUDE.md",
|
|
20874
21237
|
"AGENTS.md",
|
|
@@ -20941,7 +21304,7 @@ function findMdFiles(dir, maxDepth, depth = 0) {
|
|
|
20941
21304
|
try {
|
|
20942
21305
|
const entries = (0, import_node_fs34.readdirSync)(dir, { withFileTypes: true });
|
|
20943
21306
|
for (const entry of entries) {
|
|
20944
|
-
const fullPath = (0,
|
|
21307
|
+
const fullPath = (0, import_node_path25.join)(dir, entry.name);
|
|
20945
21308
|
if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
20946
21309
|
result.push(fullPath);
|
|
20947
21310
|
} else if (entry.isDirectory() && depth < maxDepth - 1) {
|
|
@@ -20953,9 +21316,9 @@ function findMdFiles(dir, maxDepth, depth = 0) {
|
|
|
20953
21316
|
return result;
|
|
20954
21317
|
}
|
|
20955
21318
|
function discoverPlans() {
|
|
20956
|
-
const homePlansDir = (0,
|
|
21319
|
+
const homePlansDir = (0, import_node_path25.join)(process.env.HOME ?? "", ".claude", "plans");
|
|
20957
21320
|
const localPlansDir = ".claude/plans";
|
|
20958
|
-
const
|
|
21321
|
+
const candidates2 = [];
|
|
20959
21322
|
const seen = /* @__PURE__ */ new Set();
|
|
20960
21323
|
for (const plansDir of [localPlansDir, homePlansDir]) {
|
|
20961
21324
|
if (!(0, import_node_fs34.existsSync)(plansDir)) continue;
|
|
@@ -20963,19 +21326,19 @@ function discoverPlans() {
|
|
|
20963
21326
|
for (const f of (0, import_node_fs34.readdirSync)(plansDir)) {
|
|
20964
21327
|
if (!f.endsWith(".md") || seen.has(f)) continue;
|
|
20965
21328
|
seen.add(f);
|
|
20966
|
-
const fullPath = (0,
|
|
21329
|
+
const fullPath = (0, import_node_path25.join)(plansDir, f);
|
|
20967
21330
|
try {
|
|
20968
21331
|
const stat3 = (0, import_node_fs34.statSync)(fullPath);
|
|
20969
|
-
|
|
21332
|
+
candidates2.push({ name: f, path: fullPath, mtime: stat3.mtimeMs, size: stat3.size });
|
|
20970
21333
|
} catch {
|
|
20971
21334
|
}
|
|
20972
21335
|
}
|
|
20973
21336
|
} catch {
|
|
20974
21337
|
}
|
|
20975
21338
|
}
|
|
20976
|
-
|
|
21339
|
+
candidates2.sort((a, b) => b.mtime - a.mtime);
|
|
20977
21340
|
const result = [];
|
|
20978
|
-
for (const entry of
|
|
21341
|
+
for (const entry of candidates2.slice(0, MAX_PLAN_FILES)) {
|
|
20979
21342
|
if (entry.size > MAX_PLAN_FILE_BYTES) continue;
|
|
20980
21343
|
try {
|
|
20981
21344
|
const content = (0, import_node_fs34.readFileSync)(entry.path, "utf-8");
|
|
@@ -21175,7 +21538,7 @@ async function mode(run2) {
|
|
|
21175
21538
|
|
|
21176
21539
|
// src/lib/fold.ts
|
|
21177
21540
|
var import_node_fs35 = require("node:fs");
|
|
21178
|
-
var
|
|
21541
|
+
var import_node_path26 = require("node:path");
|
|
21179
21542
|
var KNOWN_RECORD_TYPES = /* @__PURE__ */ new Set([
|
|
21180
21543
|
"user",
|
|
21181
21544
|
"assistant",
|
|
@@ -21407,9 +21770,9 @@ function fold(transcriptPath, opts = {}) {
|
|
|
21407
21770
|
return result;
|
|
21408
21771
|
}
|
|
21409
21772
|
try {
|
|
21410
|
-
const sidecarDir = (0,
|
|
21411
|
-
(0,
|
|
21412
|
-
(0,
|
|
21773
|
+
const sidecarDir = (0, import_node_path26.join)(
|
|
21774
|
+
(0, import_node_path26.dirname)(transcriptPath),
|
|
21775
|
+
(0, import_node_path26.basename)(transcriptPath).replace(/\.jsonl$/, ""),
|
|
21413
21776
|
"subagents"
|
|
21414
21777
|
);
|
|
21415
21778
|
if ((0, import_node_fs35.existsSync)(sidecarDir)) {
|
|
@@ -21419,7 +21782,7 @@ function fold(transcriptPath, opts = {}) {
|
|
|
21419
21782
|
const walk2 = (d, depth) => {
|
|
21420
21783
|
if (depth > 4) return;
|
|
21421
21784
|
for (const e of (0, import_node_fs35.readdirSync)(d, { withFileTypes: true })) {
|
|
21422
|
-
const p = (0,
|
|
21785
|
+
const p = (0, import_node_path26.join)(d, e.name);
|
|
21423
21786
|
if (e.isDirectory()) {
|
|
21424
21787
|
walk2(p, depth + 1);
|
|
21425
21788
|
} else if (e.name.startsWith("agent-") && e.name.endsWith(".jsonl")) {
|
|
@@ -21794,7 +22157,7 @@ async function evidence(run2) {
|
|
|
21794
22157
|
|
|
21795
22158
|
// src/lib/cache-cleanup.ts
|
|
21796
22159
|
var import_node_fs36 = require("node:fs");
|
|
21797
|
-
var
|
|
22160
|
+
var import_node_path27 = require("node:path");
|
|
21798
22161
|
var CACHE_TTL_DAYS = 7;
|
|
21799
22162
|
function pruneStaleCache() {
|
|
21800
22163
|
try {
|
|
@@ -21802,7 +22165,7 @@ function pruneStaleCache() {
|
|
|
21802
22165
|
const cutoff = Date.now() - CACHE_TTL_DAYS * 24 * 3600 * 1e3;
|
|
21803
22166
|
for (const entry of (0, import_node_fs36.readdirSync)(dir)) {
|
|
21804
22167
|
if (!entry.startsWith("pending-")) continue;
|
|
21805
|
-
const path = (0,
|
|
22168
|
+
const path = (0, import_node_path27.join)(dir, entry);
|
|
21806
22169
|
try {
|
|
21807
22170
|
const stat3 = (0, import_node_fs36.statSync)(path);
|
|
21808
22171
|
if (stat3.mtimeMs < cutoff) {
|
|
@@ -21821,7 +22184,7 @@ function pruneStaleCache() {
|
|
|
21821
22184
|
|
|
21822
22185
|
// src/lib/context-files.ts
|
|
21823
22186
|
var import_node_fs37 = require("node:fs");
|
|
21824
|
-
var
|
|
22187
|
+
var import_node_os6 = require("node:os");
|
|
21825
22188
|
var MAX_CONTEXT_FILES = 10;
|
|
21826
22189
|
var MAX_CONTEXT_FILE_BYTES = 10240;
|
|
21827
22190
|
var MAX_CONTEXT_TOTAL_BYTES = 24576;
|
|
@@ -21829,7 +22192,7 @@ function readSetContextPaths(summary, deltaFiles) {
|
|
|
21829
22192
|
const reads = summary?.files_read ?? [];
|
|
21830
22193
|
if (reads.length === 0) return [];
|
|
21831
22194
|
const root = process.cwd().replace(/\/+$/, "");
|
|
21832
|
-
const home = (0,
|
|
22195
|
+
const home = (0, import_node_os6.homedir)();
|
|
21833
22196
|
const toRepoRelative2 = (p) => {
|
|
21834
22197
|
if (!p) return null;
|
|
21835
22198
|
let abs;
|
|
@@ -21970,7 +22333,7 @@ async function repoContext(run2) {
|
|
|
21970
22333
|
// src/lib/seed-runner.ts
|
|
21971
22334
|
var import_promises14 = require("node:fs/promises");
|
|
21972
22335
|
var import_node_fs38 = require("node:fs");
|
|
21973
|
-
var
|
|
22336
|
+
var import_node_path28 = require("node:path");
|
|
21974
22337
|
var import_yaml4 = __toESM(require_dist());
|
|
21975
22338
|
|
|
21976
22339
|
// src/lib/seed.ts
|
|
@@ -22237,7 +22600,7 @@ async function runSeed(opts) {
|
|
|
22237
22600
|
}
|
|
22238
22601
|
}
|
|
22239
22602
|
}
|
|
22240
|
-
const
|
|
22603
|
+
const candidates2 = deriveSeedNodes({
|
|
22241
22604
|
knowledgeSpec: {
|
|
22242
22605
|
project_name: knowledgeSpec.project_name,
|
|
22243
22606
|
languages: knowledgeSpec.languages,
|
|
@@ -22249,20 +22612,20 @@ async function runSeed(opts) {
|
|
|
22249
22612
|
readmeContent,
|
|
22250
22613
|
claudeMdContent
|
|
22251
22614
|
});
|
|
22252
|
-
if (
|
|
22615
|
+
if (candidates2.length === 0) {
|
|
22253
22616
|
return { created: 0, failed: 0, skipped: "no_candidates", candidates: [] };
|
|
22254
22617
|
}
|
|
22255
|
-
const overviewPath = (0,
|
|
22618
|
+
const overviewPath = (0, import_node_path28.join)(MEMORY_DIR, "domain", "project-overview.md");
|
|
22256
22619
|
if ((0, import_node_fs38.existsSync)(overviewPath) && !opts.force) {
|
|
22257
|
-
return { created: 0, failed: 0, skipped: "already_seeded", candidates };
|
|
22620
|
+
return { created: 0, failed: 0, skipped: "already_seeded", candidates: candidates2 };
|
|
22258
22621
|
}
|
|
22259
22622
|
if (opts.dryRun) {
|
|
22260
|
-
return { created: 0, failed: 0, skipped: null, candidates };
|
|
22623
|
+
return { created: 0, failed: 0, skipped: null, candidates: candidates2 };
|
|
22261
22624
|
}
|
|
22262
22625
|
const createdAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
22263
22626
|
let created = 0;
|
|
22264
22627
|
let failed = 0;
|
|
22265
|
-
for (const c of
|
|
22628
|
+
for (const c of candidates2) {
|
|
22266
22629
|
const res = await apiRequest({
|
|
22267
22630
|
method: "POST",
|
|
22268
22631
|
path: "/compound/memory/nodes",
|
|
@@ -22295,7 +22658,7 @@ async function runSeed(opts) {
|
|
|
22295
22658
|
continue;
|
|
22296
22659
|
}
|
|
22297
22660
|
try {
|
|
22298
|
-
await (0, import_promises14.mkdir)((0,
|
|
22661
|
+
await (0, import_promises14.mkdir)((0, import_node_path28.dirname)(targetPath), { recursive: true });
|
|
22299
22662
|
await (0, import_promises14.writeFile)(targetPath, renderNodeMarkdown(c, nodeId, createdAt));
|
|
22300
22663
|
created++;
|
|
22301
22664
|
opts.onCreated?.(nodeId, filePathRel, c);
|
|
@@ -22304,12 +22667,12 @@ async function runSeed(opts) {
|
|
|
22304
22667
|
failed++;
|
|
22305
22668
|
}
|
|
22306
22669
|
}
|
|
22307
|
-
return { created, failed, skipped: null, candidates };
|
|
22670
|
+
return { created, failed, skipped: null, candidates: candidates2 };
|
|
22308
22671
|
}
|
|
22309
22672
|
|
|
22310
22673
|
// src/commands/analyze/phases/08-memory-manifest.ts
|
|
22311
22674
|
var import_node_fs39 = require("node:fs");
|
|
22312
|
-
var
|
|
22675
|
+
var import_node_path29 = require("node:path");
|
|
22313
22676
|
async function memoryManifest(run2) {
|
|
22314
22677
|
const { globals } = run2;
|
|
22315
22678
|
const { serviceUrl, token } = run2;
|
|
@@ -22319,7 +22682,7 @@ async function memoryManifest(run2) {
|
|
|
22319
22682
|
let autoSeedNotice = null;
|
|
22320
22683
|
try {
|
|
22321
22684
|
await ensureMemoryDir();
|
|
22322
|
-
const seedMarker = (0,
|
|
22685
|
+
const seedMarker = (0, import_node_path29.join)(VERITY_DIR, ".seeded");
|
|
22323
22686
|
const hasStandard = (0, import_node_fs39.existsSync)(STANDARD_FILE);
|
|
22324
22687
|
const alreadyTried = (0, import_node_fs39.existsSync)(seedMarker);
|
|
22325
22688
|
if (hasStandard && !alreadyTried) {
|
|
@@ -22437,7 +22800,7 @@ function computeIncrement(reviewedPaths, hashOf, priorAuthored) {
|
|
|
22437
22800
|
}
|
|
22438
22801
|
|
|
22439
22802
|
// src/commands/analyze/phases/10-working-memory.ts
|
|
22440
|
-
var
|
|
22803
|
+
var import_node_path30 = require("node:path");
|
|
22441
22804
|
async function workingMemory(run2) {
|
|
22442
22805
|
const { opts } = run2;
|
|
22443
22806
|
const { allForReview, baseline, conversation, foldResult, sessionId, token, transcriptPath } = run2;
|
|
@@ -22449,7 +22812,7 @@ async function workingMemory(run2) {
|
|
|
22449
22812
|
const priorState = foldForMarks(memorySession.d);
|
|
22450
22813
|
incrementReport = computeIncrement(
|
|
22451
22814
|
allForReview,
|
|
22452
|
-
(p) => fileHash((0,
|
|
22815
|
+
(p) => fileHash((0, import_node_path30.join)(repoRoot(), p)),
|
|
22453
22816
|
priorState.authored_all.map((a) => ({
|
|
22454
22817
|
path: a.path,
|
|
22455
22818
|
hash_at_last_verdict: a.hash_at_last_verdict
|
|
@@ -23014,7 +23377,7 @@ async function transmit(run2) {
|
|
|
23014
23377
|
|
|
23015
23378
|
// src/commands/analyze/phases/13-reconcile.ts
|
|
23016
23379
|
var import_node_fs42 = require("node:fs");
|
|
23017
|
-
var
|
|
23380
|
+
var import_node_path31 = require("node:path");
|
|
23018
23381
|
async function reconcile(run2) {
|
|
23019
23382
|
const { actionSummary, allChanged, analyzable, baseline, baselineSessionId, codeDelta, contentHash, conversation, decision, foldResult, memory, memorySession, response, reviewable, securityFiles, turnId } = run2;
|
|
23020
23383
|
const sentPaths = codeDelta.files.map((f) => f.path);
|
|
@@ -23043,7 +23406,7 @@ async function reconcile(run2) {
|
|
|
23043
23406
|
const st = foldDossier(memorySession.d);
|
|
23044
23407
|
openElsewhere = openBlockingElsewhere(st.statements, sentPaths, (file, line) => {
|
|
23045
23408
|
try {
|
|
23046
|
-
const src = (0, import_node_fs42.readFileSync)((0,
|
|
23409
|
+
const src = (0, import_node_fs42.readFileSync)((0, import_node_path31.join)(repoRoot(), file), "utf8").split("\n");
|
|
23047
23410
|
const at = src[line - 1];
|
|
23048
23411
|
return at === void 0 ? null : lineSha(at);
|
|
23049
23412
|
} catch {
|
|
@@ -23895,14 +24258,14 @@ async function runReview(opts, globals) {
|
|
|
23895
24258
|
|
|
23896
24259
|
// src/commands/guard.ts
|
|
23897
24260
|
var import_node_fs45 = require("node:fs");
|
|
23898
|
-
var
|
|
24261
|
+
var import_node_path32 = require("node:path");
|
|
23899
24262
|
var GUARD_BLOCK_CAP = 2;
|
|
23900
|
-
var GUARD_ITER_FILE = (0,
|
|
24263
|
+
var GUARD_ITER_FILE = (0, import_node_path32.join)(VERITY_DIR, ".guard-iteration");
|
|
23901
24264
|
function readPreToolUseStdin() {
|
|
23902
24265
|
const empty = { command: "", cwd: null, sessionId: null };
|
|
23903
|
-
return new Promise((
|
|
24266
|
+
return new Promise((resolve5) => {
|
|
23904
24267
|
try {
|
|
23905
|
-
if (process.stdin.isTTY) return
|
|
24268
|
+
if (process.stdin.isTTY) return resolve5(empty);
|
|
23906
24269
|
const chunks = [];
|
|
23907
24270
|
let timer;
|
|
23908
24271
|
let settled = false;
|
|
@@ -23915,7 +24278,7 @@ function readPreToolUseStdin() {
|
|
|
23915
24278
|
process.stdin.removeListener("end", onEnd);
|
|
23916
24279
|
process.stdin.removeListener("error", onError);
|
|
23917
24280
|
process.stdin.pause();
|
|
23918
|
-
|
|
24281
|
+
resolve5(value);
|
|
23919
24282
|
};
|
|
23920
24283
|
const onEnd = () => {
|
|
23921
24284
|
try {
|
|
@@ -23936,7 +24299,7 @@ function readPreToolUseStdin() {
|
|
|
23936
24299
|
process.stdin.on("error", onError);
|
|
23937
24300
|
process.stdin.resume();
|
|
23938
24301
|
} catch {
|
|
23939
|
-
|
|
24302
|
+
resolve5(empty);
|
|
23940
24303
|
}
|
|
23941
24304
|
});
|
|
23942
24305
|
}
|
|
@@ -23994,7 +24357,7 @@ function registerGuardCommand(program2) {
|
|
|
23994
24357
|
});
|
|
23995
24358
|
}
|
|
23996
24359
|
function resolveMomentRange(moment, frame, command, on) {
|
|
23997
|
-
return moment === "pre-commit" ? stagedRange(frame) : resolvePushRange(frame, command, on);
|
|
24360
|
+
return moment === "pre-commit" ? stagedRange(frame, command) : resolvePushRange(frame, command, on);
|
|
23998
24361
|
}
|
|
23999
24362
|
function describeRange(range) {
|
|
24000
24363
|
if (range.kind === "staged") return "staged";
|
|
@@ -24154,6 +24517,13 @@ async function runGuard(opts, globals) {
|
|
|
24154
24517
|
);
|
|
24155
24518
|
}
|
|
24156
24519
|
const range = resolveMomentRange(moment, frame, command, on);
|
|
24520
|
+
if (range.refusal) {
|
|
24521
|
+
logEvent("guard_frame", { moment, ...frameTelemetry(frame, range) });
|
|
24522
|
+
emitAllowNotice(
|
|
24523
|
+
`\u26A0 Verity ${moment}: could not tell what this ${verb} will include \u2014 ${verb === "commit" ? "committed" : "pushed"} WITHOUT review`,
|
|
24524
|
+
`Verity ${moment}: this command stages files as it runs and the resulting set could not be resolved (${range.refusal}); the ${verb} was allowed WITHOUT a Verity review. Stage first (\`git add \u2026\`) and re-run the ${verb} to have it reviewed.`
|
|
24525
|
+
);
|
|
24526
|
+
}
|
|
24157
24527
|
const files = rangeFiles(frame, range);
|
|
24158
24528
|
if (files.length === 0) process.exit(0);
|
|
24159
24529
|
const tokenResult = await resolveToken(globals.token);
|
|
@@ -24189,7 +24559,7 @@ async function runGuard(opts, globals) {
|
|
|
24189
24559
|
upgradeToExcerpts(repoContext2, {
|
|
24190
24560
|
readFile: (rel) => {
|
|
24191
24561
|
try {
|
|
24192
|
-
return (0, import_node_fs45.readFileSync)((0,
|
|
24562
|
+
return (0, import_node_fs45.readFileSync)((0, import_node_path32.join)(frame.worktreeRoot ?? process.cwd(), rel), "utf8");
|
|
24193
24563
|
} catch {
|
|
24194
24564
|
return null;
|
|
24195
24565
|
}
|
|
@@ -24250,29 +24620,50 @@ async function runGuard(opts, globals) {
|
|
|
24250
24620
|
process.exit(2);
|
|
24251
24621
|
}
|
|
24252
24622
|
resetIter(moment);
|
|
24623
|
+
const notice = verdictNotice({
|
|
24624
|
+
decision,
|
|
24625
|
+
moment,
|
|
24626
|
+
verb,
|
|
24627
|
+
covLine,
|
|
24628
|
+
covDetail,
|
|
24629
|
+
link,
|
|
24630
|
+
viewUrl,
|
|
24631
|
+
narrative: response.assessment?.narrative ?? ""
|
|
24632
|
+
});
|
|
24633
|
+
emitAllowNotice(notice.user, notice.agent);
|
|
24634
|
+
}
|
|
24635
|
+
function verdictNotice(ctx) {
|
|
24636
|
+
const { moment, verb, covLine, covDetail, link, viewUrl } = ctx;
|
|
24637
|
+
const decision = ctx.decision ?? "(unrecognised)";
|
|
24638
|
+
const report = viewUrl ? `
|
|
24639
|
+
Report: ${viewUrl}` : "";
|
|
24253
24640
|
if (decision === "FAIL") {
|
|
24254
|
-
const narrative =
|
|
24255
|
-
|
|
24256
|
-
`\u26A0 Verity ${moment}: the ${verb} may not match its stated purpose \u2014 proceeding (${covLine})${link}`,
|
|
24257
|
-
`Verity ${moment}: intent-alignment WARNING (not blocked).${narrative ? " " + narrative : ""}
|
|
24258
|
-
${covDetail}${
|
|
24259
|
-
|
|
24260
|
-
);
|
|
24641
|
+
const narrative = ctx.narrative ?? "";
|
|
24642
|
+
return {
|
|
24643
|
+
user: `\u26A0 Verity ${moment}: the ${verb} may not match its stated purpose \u2014 proceeding (${covLine})${link}`,
|
|
24644
|
+
agent: `Verity ${moment}: intent-alignment WARNING (not blocked).${narrative ? " " + narrative : ""}
|
|
24645
|
+
${covDetail}${report}`
|
|
24646
|
+
};
|
|
24261
24647
|
}
|
|
24262
24648
|
if (decision === "WARN") {
|
|
24263
|
-
|
|
24264
|
-
`\u26A0 Verity ${moment}: WARN \u2014 proceeding (${covLine})${link}`,
|
|
24265
|
-
`Verity ${moment} review: WARN (proceeding).
|
|
24266
|
-
${covDetail}${
|
|
24267
|
-
|
|
24268
|
-
);
|
|
24649
|
+
return {
|
|
24650
|
+
user: `\u26A0 Verity ${moment}: WARN \u2014 proceeding (${covLine})${link}`,
|
|
24651
|
+
agent: `Verity ${moment} review: WARN (proceeding).
|
|
24652
|
+
${covDetail}${report}`
|
|
24653
|
+
};
|
|
24269
24654
|
}
|
|
24270
|
-
|
|
24271
|
-
|
|
24272
|
-
|
|
24273
|
-
${
|
|
24274
|
-
|
|
24275
|
-
|
|
24655
|
+
if (decision === "PASS") {
|
|
24656
|
+
return {
|
|
24657
|
+
user: `\u2713 Verity ${moment}: PASS (${covLine})${link}`,
|
|
24658
|
+
agent: `Verity ${moment} review: PASS.
|
|
24659
|
+
${covDetail}${report}`
|
|
24660
|
+
};
|
|
24661
|
+
}
|
|
24662
|
+
return {
|
|
24663
|
+
user: `\u26A0 Verity ${moment}: no verdict came back \u2014 ${verb === "commit" ? "committed" : "pushed"} WITHOUT a usable review (${covLine})${link}`,
|
|
24664
|
+
agent: `Verity ${moment}: the service answered with no recognisable gate decision (${decision}); the ${verb} was allowed, but nothing reviewed it. Treat this as unreviewed, not as a pass.
|
|
24665
|
+
${covDetail}${report}`
|
|
24666
|
+
};
|
|
24276
24667
|
}
|
|
24277
24668
|
function writeBlockMessage(moment, response, covDetail) {
|
|
24278
24669
|
const label2 = moment === "pre-commit" ? "pre-commit" : "pre-push";
|
|
@@ -24467,7 +24858,7 @@ function registerWaiveCommand(program2) {
|
|
|
24467
24858
|
var import_node_fs51 = require("node:fs");
|
|
24468
24859
|
var import_promises17 = require("node:fs/promises");
|
|
24469
24860
|
var import_yaml6 = __toESM(require_dist());
|
|
24470
|
-
var
|
|
24861
|
+
var import_node_path35 = require("node:path");
|
|
24471
24862
|
var import_node_child_process16 = require("node:child_process");
|
|
24472
24863
|
|
|
24473
24864
|
// src/lib/banner.ts
|
|
@@ -24504,8 +24895,8 @@ function printBanner(opts) {
|
|
|
24504
24895
|
const dim = (text) => color ? `${DIM3}${text}${RESET2}` : text;
|
|
24505
24896
|
process.stderr.write("\n");
|
|
24506
24897
|
if (!art) {
|
|
24507
|
-
const
|
|
24508
|
-
const text =
|
|
24898
|
+
const candidates2 = [`Verity ${version}`, "Verity"];
|
|
24899
|
+
const text = candidates2.find((c) => c.length + INDENT.length <= columns);
|
|
24509
24900
|
if (text) process.stderr.write(`${INDENT}${dim(text)}
|
|
24510
24901
|
`);
|
|
24511
24902
|
process.stderr.write("\n");
|
|
@@ -24612,13 +25003,13 @@ function checkAnalysisCli() {
|
|
|
24612
25003
|
}
|
|
24613
25004
|
var INSTALL_TIMEOUT_MS = 12e4;
|
|
24614
25005
|
function run(command, args, opts = {}) {
|
|
24615
|
-
return new Promise((
|
|
25006
|
+
return new Promise((resolve5) => {
|
|
24616
25007
|
const child = (0, import_node_child_process13.spawn)(command, args, {
|
|
24617
25008
|
stdio: opts.inherit ? "inherit" : "pipe",
|
|
24618
25009
|
timeout: INSTALL_TIMEOUT_MS
|
|
24619
25010
|
});
|
|
24620
|
-
child.on("error", () =>
|
|
24621
|
-
child.on("close", (code) =>
|
|
25011
|
+
child.on("error", () => resolve5(false));
|
|
25012
|
+
child.on("close", (code) => resolve5(code === 0));
|
|
24622
25013
|
});
|
|
24623
25014
|
}
|
|
24624
25015
|
async function installAnalysisCli() {
|
|
@@ -24717,8 +25108,8 @@ function ensureVerityGitignore() {
|
|
|
24717
25108
|
next = lines.map((l) => BREAKING_ENTRIES.has(l.trim()) ? ".verity/*" : l).join("\n");
|
|
24718
25109
|
}
|
|
24719
25110
|
if (!hasMarker) {
|
|
24720
|
-
const
|
|
24721
|
-
next = next +
|
|
25111
|
+
const sep3 = next === "" ? "" : next.endsWith("\n") ? "\n" : "\n\n";
|
|
25112
|
+
next = next + sep3 + VERITY_GITIGNORE_BLOCK;
|
|
24722
25113
|
}
|
|
24723
25114
|
(0, import_node_fs47.writeFileSync)(".gitignore", next);
|
|
24724
25115
|
return verified(needsRepair ? "repaired" : "added");
|
|
@@ -24845,7 +25236,8 @@ async function uninstallTelemetry() {
|
|
|
24845
25236
|
async function buildReport() {
|
|
24846
25237
|
const prereqs = await checkPrereqs({ install: false });
|
|
24847
25238
|
const state = await readSetupState();
|
|
24848
|
-
const
|
|
25239
|
+
const wiring = await resolveHookWiring();
|
|
25240
|
+
const hooks = wiring.status;
|
|
24849
25241
|
const telemetry = await checkTelemetry();
|
|
24850
25242
|
const hasConfig = (0, import_node_fs48.existsSync)(projectPath(CODACY_CONFIG_FILE));
|
|
24851
25243
|
const artifacts = {
|
|
@@ -24884,6 +25276,11 @@ async function buildReport() {
|
|
|
24884
25276
|
'Your analysis config names pattern ids that no longer resolve, so those tools run with nothing enabled and report zero issues. Fix: "verity standard synthesize --config-only" (or re-run "verity init").'
|
|
24885
25277
|
);
|
|
24886
25278
|
}
|
|
25279
|
+
if (wiring.duplicateSettingsHooks) {
|
|
25280
|
+
next.push(
|
|
25281
|
+
'Duplicate Verity hooks also exist in .claude/settings.json. They stand down at run time under the plugin, but remove them with "verity init --plugin-mode" so the wiring says what it does.'
|
|
25282
|
+
);
|
|
25283
|
+
}
|
|
24887
25284
|
if (state?.telemetry === "deferred") {
|
|
24888
25285
|
next.push('Telemetry was requested but needs a token \u2014 run "verity login", then "verity telemetry install".');
|
|
24889
25286
|
}
|
|
@@ -24899,7 +25296,12 @@ async function buildReport() {
|
|
|
24899
25296
|
moments: state?.moments ?? null,
|
|
24900
25297
|
telemetry: state?.telemetry ?? null
|
|
24901
25298
|
},
|
|
24902
|
-
hooks: {
|
|
25299
|
+
hooks: {
|
|
25300
|
+
source: wiring.source,
|
|
25301
|
+
...hooks,
|
|
25302
|
+
duplicateSettingsHooks: wiring.duplicateSettingsHooks,
|
|
25303
|
+
noAnalysisMoment
|
|
25304
|
+
},
|
|
24903
25305
|
telemetry: { enabled: telemetry.enabled, endpoint: telemetry.endpoint },
|
|
24904
25306
|
artifacts,
|
|
24905
25307
|
next
|
|
@@ -24922,8 +25324,9 @@ function registerDoctorCommand(program2) {
|
|
|
24922
25324
|
printInfo(` verity init: ${report.phases.init.done ? `done ${report.phases.init.completed_at ?? ""}`.trim() : "NOT run here"}`);
|
|
24923
25325
|
printInfo(` /verity-setup: ${report.phases.setup.done ? "done" : "not completed"}`);
|
|
24924
25326
|
printInfo(` intensity: ${report.answers.intensity ?? "\u2014"} moments: ${report.answers.moments?.join(", ") ?? "\u2014"}`);
|
|
24925
|
-
|
|
24926
|
-
printInfo(
|
|
25327
|
+
const plugin = report.hooks.source === "plugin";
|
|
25328
|
+
printInfo(plugin ? "Hooks: wired by the Verity Claude Code plugin (not .claude/settings.json)" : "Hooks:");
|
|
25329
|
+
printInfo(` Stop (verity analyze): ${report.hooks.stop ? plugin ? "on (plugin)" : "on" : "off"}`);
|
|
24927
25330
|
printInfo(` Git-moment gate: ${report.hooks.guardOn.length ? report.hooks.guardOn.join(", ") : "off"}`);
|
|
24928
25331
|
printInfo(` Infra (intent/baseline/compact/session-end): ${[report.hooks.intent, report.hooks.baseline, report.hooks.compact, report.hooks.sessionEnd].filter(Boolean).length}/4`);
|
|
24929
25332
|
printInfo(`Telemetry: ${report.telemetry.enabled ? `enabled \u2192 ${report.telemetry.endpoint}` : "disabled"}`);
|
|
@@ -24946,7 +25349,7 @@ function registerDoctorCommand(program2) {
|
|
|
24946
25349
|
|
|
24947
25350
|
// src/commands/migrate.ts
|
|
24948
25351
|
var import_node_fs49 = require("node:fs");
|
|
24949
|
-
var
|
|
25352
|
+
var import_node_path33 = require("node:path");
|
|
24950
25353
|
var import_node_child_process15 = require("node:child_process");
|
|
24951
25354
|
var LEGACY_NPM_PACKAGE = "@codacy/gate-cli";
|
|
24952
25355
|
function defaultNpmRemover(pkg) {
|
|
@@ -24983,8 +25386,8 @@ async function runMigration(opts = {}) {
|
|
|
24983
25386
|
return { actions, migrated: actions.length > 0 };
|
|
24984
25387
|
}
|
|
24985
25388
|
function migrateProjectDir(root, actions) {
|
|
24986
|
-
const gateDir = (0,
|
|
24987
|
-
const verityDir = (0,
|
|
25389
|
+
const gateDir = (0, import_node_path33.join)(root, ".gate");
|
|
25390
|
+
const verityDir = (0, import_node_path33.join)(root, ".verity");
|
|
24988
25391
|
if ((0, import_node_fs49.existsSync)(gateDir) && !(0, import_node_fs49.existsSync)(verityDir)) {
|
|
24989
25392
|
return migrateProjectDirRename(root, gateDir, verityDir, actions);
|
|
24990
25393
|
}
|
|
@@ -25038,11 +25441,11 @@ function migrateProjectDirCarry(gateDir, verityDir, actions) {
|
|
|
25038
25441
|
}
|
|
25039
25442
|
function migrateGlobalCredentials(home, actions) {
|
|
25040
25443
|
if (!home) return;
|
|
25041
|
-
const gateCreds = (0,
|
|
25042
|
-
const verityCreds = (0,
|
|
25444
|
+
const gateCreds = (0, import_node_path33.join)(home, ".gate", "credentials");
|
|
25445
|
+
const verityCreds = (0, import_node_path33.join)(home, ".verity", "credentials");
|
|
25043
25446
|
if (!(0, import_node_fs49.existsSync)(gateCreds)) return;
|
|
25044
25447
|
if (!(0, import_node_fs49.existsSync)(verityCreds)) {
|
|
25045
|
-
(0, import_node_fs49.mkdirSync)((0,
|
|
25448
|
+
(0, import_node_fs49.mkdirSync)((0, import_node_path33.join)(home, ".verity"), { recursive: true });
|
|
25046
25449
|
moveFile(gateCreds, verityCreds);
|
|
25047
25450
|
actions.push("Moved ~/.gate/credentials \u2192 ~/.verity/credentials");
|
|
25048
25451
|
return;
|
|
@@ -25064,7 +25467,7 @@ async function migrateLegacyHooks(root, actions) {
|
|
|
25064
25467
|
}
|
|
25065
25468
|
}
|
|
25066
25469
|
async function migrateClaudeMd(root, actions) {
|
|
25067
|
-
const claudeMd = (0,
|
|
25470
|
+
const claudeMd = (0, import_node_path33.join)(root, "CLAUDE.md");
|
|
25068
25471
|
const hadLegacyBlock = (0, import_node_fs49.existsSync)(claudeMd) && hasLegacyMemoryBlock(readFileSyncSafe(claudeMd));
|
|
25069
25472
|
if (!hadLegacyBlock) return;
|
|
25070
25473
|
try {
|
|
@@ -25075,8 +25478,8 @@ async function migrateClaudeMd(root, actions) {
|
|
|
25075
25478
|
}
|
|
25076
25479
|
}
|
|
25077
25480
|
function migrateStandardFile(root, actions) {
|
|
25078
|
-
const gateMd = (0,
|
|
25079
|
-
const verityMd = (0,
|
|
25481
|
+
const gateMd = (0, import_node_path33.join)(root, "GATE.md");
|
|
25482
|
+
const verityMd = (0, import_node_path33.join)(root, "VERITY.md");
|
|
25080
25483
|
if (!(0, import_node_fs49.existsSync)(gateMd) || (0, import_node_fs49.existsSync)(verityMd)) return;
|
|
25081
25484
|
let moved = false;
|
|
25082
25485
|
if (isGitRepo(root) && isGitTracked(root, "GATE.md")) {
|
|
@@ -25093,7 +25496,7 @@ function migrateStandardFile(root, actions) {
|
|
|
25093
25496
|
actions.push("Renamed GATE.md \u2192 VERITY.md");
|
|
25094
25497
|
}
|
|
25095
25498
|
async function migrateTelemetryHeaders(root, actions) {
|
|
25096
|
-
const file = (0,
|
|
25499
|
+
const file = (0, import_node_path33.join)(root, ".claude", "settings.local.json");
|
|
25097
25500
|
if (!(0, import_node_fs49.existsSync)(file)) return;
|
|
25098
25501
|
let settings;
|
|
25099
25502
|
try {
|
|
@@ -25141,8 +25544,8 @@ function mergeGlobalCredentials(gateCreds, verityCreds) {
|
|
|
25141
25544
|
toAppend.push(line.replace(/\r$/, ""));
|
|
25142
25545
|
}
|
|
25143
25546
|
if (toAppend.length > 0) {
|
|
25144
|
-
const
|
|
25145
|
-
(0, import_node_fs49.writeFileSync)(verityCreds, verityContent +
|
|
25547
|
+
const sep3 = verityContent.endsWith("\n") || verityContent === "" ? "" : "\n";
|
|
25548
|
+
(0, import_node_fs49.writeFileSync)(verityCreds, verityContent + sep3 + toAppend.join("\n") + "\n");
|
|
25146
25549
|
}
|
|
25147
25550
|
(0, import_node_fs49.rmSync)(gateCreds, { force: true });
|
|
25148
25551
|
return toAppend.length;
|
|
@@ -25183,15 +25586,15 @@ function moveFile(from, to) {
|
|
|
25183
25586
|
function carryLegacyContents(gateDir, verityDir) {
|
|
25184
25587
|
let copied = 0;
|
|
25185
25588
|
const walk2 = (relDir) => {
|
|
25186
|
-
const srcDir = (0,
|
|
25589
|
+
const srcDir = (0, import_node_path33.join)(gateDir, relDir);
|
|
25187
25590
|
for (const entry of (0, import_node_fs49.readdirSync)(srcDir)) {
|
|
25188
|
-
const rel = relDir ? (0,
|
|
25189
|
-
const src = (0,
|
|
25190
|
-
const dest = (0,
|
|
25591
|
+
const rel = relDir ? (0, import_node_path33.join)(relDir, entry) : entry;
|
|
25592
|
+
const src = (0, import_node_path33.join)(gateDir, rel);
|
|
25593
|
+
const dest = (0, import_node_path33.join)(verityDir, rel);
|
|
25191
25594
|
if ((0, import_node_fs49.statSync)(src).isDirectory()) {
|
|
25192
25595
|
walk2(rel);
|
|
25193
25596
|
} else if (!(0, import_node_fs49.existsSync)(dest)) {
|
|
25194
|
-
(0, import_node_fs49.mkdirSync)((0,
|
|
25597
|
+
(0, import_node_fs49.mkdirSync)((0, import_node_path33.dirname)(dest), { recursive: true });
|
|
25195
25598
|
(0, import_node_fs49.cpSync)(src, dest);
|
|
25196
25599
|
copied++;
|
|
25197
25600
|
}
|
|
@@ -25201,22 +25604,22 @@ function carryLegacyContents(gateDir, verityDir) {
|
|
|
25201
25604
|
return copied;
|
|
25202
25605
|
}
|
|
25203
25606
|
async function needsMigration(root = repoRoot()) {
|
|
25204
|
-
const gateDir = (0,
|
|
25205
|
-
const verityDir = (0,
|
|
25607
|
+
const gateDir = (0, import_node_path33.join)(root, ".gate");
|
|
25608
|
+
const verityDir = (0, import_node_path33.join)(root, ".verity");
|
|
25206
25609
|
if ((0, import_node_fs49.existsSync)(gateDir) && !(0, import_node_fs49.existsSync)(verityDir)) return true;
|
|
25207
25610
|
if ((0, import_node_fs49.existsSync)(gateDir) && (0, import_node_fs49.existsSync)(verityDir)) {
|
|
25208
|
-
if ((0, import_node_fs49.existsSync)((0,
|
|
25611
|
+
if ((0, import_node_fs49.existsSync)((0, import_node_path33.join)(gateDir, "credentials")) && !(0, import_node_fs49.existsSync)((0, import_node_path33.join)(verityDir, "credentials"))) {
|
|
25209
25612
|
return true;
|
|
25210
25613
|
}
|
|
25211
|
-
if ((0, import_node_fs49.existsSync)((0,
|
|
25614
|
+
if ((0, import_node_fs49.existsSync)((0, import_node_path33.join)(gateDir, "memory")) && !(0, import_node_fs49.existsSync)((0, import_node_path33.join)(verityDir, "memory"))) {
|
|
25212
25615
|
return true;
|
|
25213
25616
|
}
|
|
25214
25617
|
}
|
|
25215
|
-
const claudeMd = (0,
|
|
25618
|
+
const claudeMd = (0, import_node_path33.join)(root, "CLAUDE.md");
|
|
25216
25619
|
if ((0, import_node_fs49.existsSync)(claudeMd) && hasLegacyMemoryBlock(readFileSyncSafe(claudeMd))) {
|
|
25217
25620
|
return true;
|
|
25218
25621
|
}
|
|
25219
|
-
if ((0, import_node_fs49.existsSync)((0,
|
|
25622
|
+
if ((0, import_node_fs49.existsSync)((0, import_node_path33.join)(root, "GATE.md")) && !(0, import_node_fs49.existsSync)((0, import_node_path33.join)(root, "VERITY.md"))) {
|
|
25220
25623
|
return true;
|
|
25221
25624
|
}
|
|
25222
25625
|
if (await hasLegacyHooksAt(root)) return true;
|
|
@@ -25280,7 +25683,13 @@ function applyKey(state, action, count, mode2) {
|
|
|
25280
25683
|
}
|
|
25281
25684
|
case "jump": {
|
|
25282
25685
|
if (action.index >= count) return { status: "open", state };
|
|
25283
|
-
|
|
25686
|
+
if (mode2 === "single") {
|
|
25687
|
+
return { status: "open", state: { cursor: action.index, chosen: state.chosen } };
|
|
25688
|
+
}
|
|
25689
|
+
const chosen = new Set(state.chosen);
|
|
25690
|
+
if (chosen.has(action.index)) chosen.delete(action.index);
|
|
25691
|
+
else chosen.add(action.index);
|
|
25692
|
+
return { status: "open", state: { cursor: action.index, chosen } };
|
|
25284
25693
|
}
|
|
25285
25694
|
case "toggle": {
|
|
25286
25695
|
if (mode2 === "single") {
|
|
@@ -25325,7 +25734,7 @@ function renderSelect(question, choices, state, mode2, color = colorEnabled()) {
|
|
|
25325
25734
|
const hint = choice.hint ? `${pad} ${paint(choice.hint, DIM4)}` : "";
|
|
25326
25735
|
lines.push(` ${cursor} ${marker} ${here ? paint(label2, BOLD2) : label2}${hint}`);
|
|
25327
25736
|
});
|
|
25328
|
-
const keys = mode2 === "multi" ? "\u2191\u2193 move \xB7 space toggle \xB7 enter confirm" : "\u2191\u2193 move \xB7 enter confirm";
|
|
25737
|
+
const keys = mode2 === "multi" ? "\u2191\u2193 move \xB7 space or number toggle \xB7 enter confirm" : "\u2191\u2193 move \xB7 number jumps \xB7 enter confirm";
|
|
25329
25738
|
lines.push(` ${paint(state.hint ?? keys, state.hint ? GREEN3 : DIM4)}`);
|
|
25330
25739
|
return lines;
|
|
25331
25740
|
}
|
|
@@ -25339,7 +25748,7 @@ function runSelect(opts) {
|
|
|
25339
25748
|
cursor: initialIdx[0] ?? 0,
|
|
25340
25749
|
chosen: new Set(mode2 === "single" ? [initialIdx[0] ?? 0] : initialIdx)
|
|
25341
25750
|
};
|
|
25342
|
-
return new Promise((
|
|
25751
|
+
return new Promise((resolve5) => {
|
|
25343
25752
|
let painted = 0;
|
|
25344
25753
|
let settled = false;
|
|
25345
25754
|
const draw = () => {
|
|
@@ -25387,7 +25796,7 @@ function runSelect(opts) {
|
|
|
25387
25796
|
if (settled) return;
|
|
25388
25797
|
settled = true;
|
|
25389
25798
|
restore();
|
|
25390
|
-
|
|
25799
|
+
resolve5(value);
|
|
25391
25800
|
};
|
|
25392
25801
|
readline2.emitKeypressEvents(input);
|
|
25393
25802
|
input.setRawMode(true);
|
|
@@ -25408,9 +25817,9 @@ async function askLine(question, io = {}) {
|
|
|
25408
25817
|
output: io.output ?? process.stdout
|
|
25409
25818
|
});
|
|
25410
25819
|
try {
|
|
25411
|
-
return await new Promise((
|
|
25412
|
-
rl.question(question).then((a) =>
|
|
25413
|
-
rl.once("close", () => setImmediate(() =>
|
|
25820
|
+
return await new Promise((resolve5) => {
|
|
25821
|
+
rl.question(question).then((a) => resolve5(a.trim())).catch(() => resolve5(null));
|
|
25822
|
+
rl.once("close", () => setImmediate(() => resolve5(null)));
|
|
25414
25823
|
});
|
|
25415
25824
|
} finally {
|
|
25416
25825
|
rl.close();
|
|
@@ -25493,7 +25902,7 @@ async function promptMultiSelect(question, choices, fallback) {
|
|
|
25493
25902
|
// src/lib/remote-config.ts
|
|
25494
25903
|
var import_node_fs50 = require("node:fs");
|
|
25495
25904
|
var import_promises16 = require("node:fs/promises");
|
|
25496
|
-
var
|
|
25905
|
+
var import_node_path34 = require("node:path");
|
|
25497
25906
|
var import_yaml5 = __toESM(require_dist());
|
|
25498
25907
|
var IGNORE_RIDER = "verityignore";
|
|
25499
25908
|
async function fetchRemoteSetup(opts) {
|
|
@@ -25571,7 +25980,7 @@ async function adoptRemoteSetup(found, opts) {
|
|
|
25571
25980
|
}
|
|
25572
25981
|
async function writeOut(relative2, body) {
|
|
25573
25982
|
const target = projectPath(relative2);
|
|
25574
|
-
await (0, import_promises16.mkdir)((0,
|
|
25983
|
+
await (0, import_promises16.mkdir)((0, import_node_path34.dirname)(target), { recursive: true });
|
|
25575
25984
|
await (0, import_promises16.writeFile)(target, body);
|
|
25576
25985
|
}
|
|
25577
25986
|
function describeRemote(found) {
|
|
@@ -25687,16 +26096,16 @@ async function runOptionalAuth(resolution, opts = {}) {
|
|
|
25687
26096
|
}
|
|
25688
26097
|
}
|
|
25689
26098
|
function resolveDataDir2() {
|
|
25690
|
-
const
|
|
25691
|
-
(0,
|
|
26099
|
+
const candidates2 = [
|
|
26100
|
+
(0, import_node_path35.join)(__dirname, "..", "data"),
|
|
25692
26101
|
// installed: node_modules/@codacy/verity-cli/data
|
|
25693
|
-
(0,
|
|
26102
|
+
(0, import_node_path35.join)(__dirname, "..", "..", "data"),
|
|
25694
26103
|
// edge case: nested resolution
|
|
25695
|
-
(0,
|
|
26104
|
+
(0, import_node_path35.join)(process.cwd(), "cli", "data")
|
|
25696
26105
|
// local dev: running from repo root
|
|
25697
26106
|
];
|
|
25698
|
-
for (const candidate of
|
|
25699
|
-
if ((0, import_node_fs51.existsSync)((0,
|
|
26107
|
+
for (const candidate of candidates2) {
|
|
26108
|
+
if ((0, import_node_fs51.existsSync)((0, import_node_path35.join)(candidate, "skills"))) {
|
|
25700
26109
|
return candidate;
|
|
25701
26110
|
}
|
|
25702
26111
|
}
|
|
@@ -25714,7 +26123,7 @@ async function skillIsCurrent(src, dest) {
|
|
|
25714
26123
|
const walk2 = (d, prefix) => {
|
|
25715
26124
|
for (const e of (0, import_node_fs51.readdirSync)(d, { withFileTypes: true })) {
|
|
25716
26125
|
const rel = prefix ? `${prefix}/${e.name}` : e.name;
|
|
25717
|
-
if (e.isDirectory()) walk2((0,
|
|
26126
|
+
if (e.isDirectory()) walk2((0, import_node_path35.join)(d, e.name), rel);
|
|
25718
26127
|
else if (e.isFile()) out.push(rel);
|
|
25719
26128
|
}
|
|
25720
26129
|
};
|
|
@@ -25725,8 +26134,8 @@ async function skillIsCurrent(src, dest) {
|
|
|
25725
26134
|
const shipped = list2(src);
|
|
25726
26135
|
if (JSON.stringify(shipped) !== JSON.stringify(list2(dest))) return false;
|
|
25727
26136
|
for (const rel of shipped) {
|
|
25728
|
-
const a = await (0, import_promises17.readFile)((0,
|
|
25729
|
-
const b = await (0, import_promises17.readFile)((0,
|
|
26137
|
+
const a = await (0, import_promises17.readFile)((0, import_node_path35.join)(src, rel), "utf-8");
|
|
26138
|
+
const b = await (0, import_promises17.readFile)((0, import_node_path35.join)(dest, rel), "utf-8");
|
|
25730
26139
|
if (a !== b) return false;
|
|
25731
26140
|
}
|
|
25732
26141
|
return true;
|
|
@@ -26001,12 +26410,12 @@ async function handoffToSetup(enabled, claudeInstalled) {
|
|
|
26001
26410
|
async function installSkills(force, step) {
|
|
26002
26411
|
step("Installing skills");
|
|
26003
26412
|
const dataDir = resolveDataDir2();
|
|
26004
|
-
const skillsSource = (0,
|
|
26413
|
+
const skillsSource = (0, import_node_path35.join)(dataDir, "skills");
|
|
26005
26414
|
const skillsDest = ".claude/skills";
|
|
26006
26415
|
let skillsInstalled = 0;
|
|
26007
26416
|
for (const skill of SKILLS) {
|
|
26008
|
-
const src = (0,
|
|
26009
|
-
const dest = (0,
|
|
26417
|
+
const src = (0, import_node_path35.join)(skillsSource, skill);
|
|
26418
|
+
const dest = (0, import_node_path35.join)(skillsDest, skill);
|
|
26010
26419
|
if (!(0, import_node_fs51.existsSync)(src)) {
|
|
26011
26420
|
printWarn(` Skill data not found: ${skill}`);
|
|
26012
26421
|
continue;
|
|
@@ -26109,12 +26518,16 @@ function registerInitCommand(program2) {
|
|
|
26109
26518
|
program2.command("init").alias("setup").description("Set up Verity in the current project (asks the setup questions, then hands off to /verity-setup)").option("--force", "Reinstall the skills even when they are already up to date (hooks are always reconciled)").option("-y, --yes", "Take the recommended answer for every question (no prompts)").option("--no-setup", "Skip the /verity-setup handoff at the end").option(
|
|
26110
26519
|
"--plugin-mode",
|
|
26111
26520
|
"The Claude Code plugin owns the skills and hooks: install neither, and remove any this project already has"
|
|
26521
|
+
).option(
|
|
26522
|
+
"--no-plugin",
|
|
26523
|
+
"Ignore any Claude Code plugin here and wire this project's own skills and hooks"
|
|
26112
26524
|
).option("--no-adopt", "Don't offer this repository's existing Standard from the service; synthesize a new one").action(async (opts) => {
|
|
26113
26525
|
const force = opts.force ?? false;
|
|
26114
26526
|
const wantsHandoff = opts.setup !== false;
|
|
26115
26527
|
const wantsAdopt = opts.adopt !== false;
|
|
26116
26528
|
const defaultsOnly = (opts.yes ?? false) || !interactive();
|
|
26117
|
-
const
|
|
26529
|
+
const staleMarker = clearStalePluginMarker();
|
|
26530
|
+
const pluginMode = opts.plugin === false ? false : opts.pluginMode ?? pluginActiveHere();
|
|
26118
26531
|
const projectMarkers = [".git", "package.json", "pyproject.toml", "go.mod", "Cargo.toml", "Gemfile", "pom.xml", "build.gradle"];
|
|
26119
26532
|
const isProject = projectMarkers.some((m) => (0, import_node_fs51.existsSync)(m));
|
|
26120
26533
|
if (!isProject) {
|
|
@@ -26131,6 +26544,26 @@ function registerInitCommand(program2) {
|
|
|
26131
26544
|
} else {
|
|
26132
26545
|
printPhase(1, 2, "this machine", "prerequisites \xB7 skills \xB7 hooks \xB7 sign-in");
|
|
26133
26546
|
}
|
|
26547
|
+
if (staleMarker) {
|
|
26548
|
+
printInfo(`Cleared a stale plugin marker \u2014 ${staleMarker.pluginRoot} is no longer installed.`);
|
|
26549
|
+
}
|
|
26550
|
+
const install = pluginMode ? activePluginInstall() : null;
|
|
26551
|
+
if (pluginMode) {
|
|
26552
|
+
const where = install ? ` \u2014 ${install.pluginRoot}${install.version ? ` (v${install.version})` : ""}` : "";
|
|
26553
|
+
printInfo(`Hooks here: the Verity Claude Code plugin${where}.`);
|
|
26554
|
+
printInfo(" Skills and hooks come from the plugin, so this run installs neither \u2014 and removes");
|
|
26555
|
+
printInfo(" any this project still carries from an earlier npm install.");
|
|
26556
|
+
printInfo(" It still does the half the plugin cannot: your Standard and analysis config, the");
|
|
26557
|
+
printInfo(" knowledge base, CLAUDE.md, .gitignore, the review moments, and sign-in.");
|
|
26558
|
+
printInfo(" Want this project to own its own copy instead? Uninstall the plugin, or use --no-plugin.");
|
|
26559
|
+
} else if (opts.plugin === false && pluginActiveHere()) {
|
|
26560
|
+
printWarn("Hooks here: this project's .claude/settings.json (--no-plugin).");
|
|
26561
|
+
printWarn(" The Verity plugin is active on this machine and would otherwise own them. Both sets");
|
|
26562
|
+
printWarn(" will fire; the settings.json copy stands down at run time so each turn is gated once.");
|
|
26563
|
+
} else {
|
|
26564
|
+
printInfo("Hooks here: this project's .claude/settings.json (no Verity Claude Code plugin is active).");
|
|
26565
|
+
}
|
|
26566
|
+
console.log("");
|
|
26134
26567
|
const TOTAL_STEPS = 9;
|
|
26135
26568
|
let stepNo = 0;
|
|
26136
26569
|
const step = (label2) => {
|
|
@@ -26162,7 +26595,7 @@ function registerInitCommand(program2) {
|
|
|
26162
26595
|
printInfo(` intensity: ${intensity} \xB7 moments: ${moments.join(", ") || "none"} (no questions asked)`);
|
|
26163
26596
|
}
|
|
26164
26597
|
await scaffoldProject(step, defaultsOnly);
|
|
26165
|
-
const globalVerityDir = (0,
|
|
26598
|
+
const globalVerityDir = (0, import_node_path35.join)(process.env.HOME ?? "", ".verity");
|
|
26166
26599
|
await (0, import_promises17.mkdir)(globalVerityDir, { recursive: true });
|
|
26167
26600
|
console.log("");
|
|
26168
26601
|
step("Wiring Claude Code hooks");
|
|
@@ -26170,9 +26603,18 @@ function registerInitCommand(program2) {
|
|
|
26170
26603
|
...moments.includes("pre-commit") ? ["commit"] : [],
|
|
26171
26604
|
...moments.includes("pre-push") ? ["push"] : []
|
|
26172
26605
|
];
|
|
26173
|
-
|
|
26606
|
+
const existingMoments = readProjectConfig();
|
|
26607
|
+
const keepExisting = defaultsOnly && existingMoments.git_moments_source === "user";
|
|
26608
|
+
if (keepExisting) {
|
|
26609
|
+
printInfo(
|
|
26610
|
+
` Keeping the git moments you set: ${existingMoments.git_moments.join(", ") || "none"} (this run asked no questions, so it does not overrule them).`
|
|
26611
|
+
);
|
|
26612
|
+
} else {
|
|
26613
|
+
writeProjectConfig({ git_moments: gitMoments, git_moments_source: "init" });
|
|
26614
|
+
}
|
|
26615
|
+
const effectiveMoments = keepExisting ? existingMoments.git_moments : gitMoments;
|
|
26174
26616
|
if (pluginMode) {
|
|
26175
|
-
await adoptPluginWiring(
|
|
26617
|
+
await adoptPluginWiring(effectiveMoments, moments);
|
|
26176
26618
|
} else {
|
|
26177
26619
|
await reconcileOwnWiring(moments);
|
|
26178
26620
|
}
|
|
@@ -26244,7 +26686,7 @@ function registerInitCommand(program2) {
|
|
|
26244
26686
|
...telemetryChoice ? { telemetry: telemetryChoice } : {},
|
|
26245
26687
|
init: {
|
|
26246
26688
|
completed_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
26247
|
-
cli_version: true ? "0.32.
|
|
26689
|
+
cli_version: true ? "0.32.1-experimental.c640abd" : "dev"
|
|
26248
26690
|
}
|
|
26249
26691
|
});
|
|
26250
26692
|
} catch (err) {
|
|
@@ -26284,7 +26726,7 @@ function registerInitCommand(program2) {
|
|
|
26284
26726
|
|
|
26285
26727
|
// src/commands/uninstall.ts
|
|
26286
26728
|
var import_node_fs52 = require("node:fs");
|
|
26287
|
-
var
|
|
26729
|
+
var import_node_path36 = require("node:path");
|
|
26288
26730
|
var SKILL_NAMES = [
|
|
26289
26731
|
"verity-setup",
|
|
26290
26732
|
"verity-analyze",
|
|
@@ -26303,7 +26745,7 @@ function registerUninstallCommand(program2) {
|
|
|
26303
26745
|
const actions = [];
|
|
26304
26746
|
const skillsRoot = projectPath(".claude/skills");
|
|
26305
26747
|
for (const name of SKILL_NAMES) {
|
|
26306
|
-
const dir = (0,
|
|
26748
|
+
const dir = (0, import_node_path36.join)(skillsRoot, name);
|
|
26307
26749
|
if ((0, import_node_fs52.existsSync)(dir)) {
|
|
26308
26750
|
actions.push({
|
|
26309
26751
|
label: `Remove .claude/skills/${name}/`,
|
|
@@ -26349,7 +26791,7 @@ function registerUninstallCommand(program2) {
|
|
|
26349
26791
|
}
|
|
26350
26792
|
});
|
|
26351
26793
|
const home = process.env.HOME ?? "";
|
|
26352
|
-
const globalVerityDir = (0,
|
|
26794
|
+
const globalVerityDir = (0, import_node_path36.join)(home, ".verity");
|
|
26353
26795
|
if (purgeGlobal && (0, import_node_fs52.existsSync)(globalVerityDir)) {
|
|
26354
26796
|
actions.push({
|
|
26355
26797
|
label: `Remove ~/.verity/ (global credentials \u2014 reconnect requires re-registration)`,
|
|
@@ -26548,7 +26990,7 @@ function registerTaskCommands(program2) {
|
|
|
26548
26990
|
|
|
26549
26991
|
// src/commands/reset.ts
|
|
26550
26992
|
var import_node_fs53 = require("node:fs");
|
|
26551
|
-
var
|
|
26993
|
+
var import_node_path37 = require("node:path");
|
|
26552
26994
|
function registerResetCommand(program2) {
|
|
26553
26995
|
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) => {
|
|
26554
26996
|
const globals = program2.opts();
|
|
@@ -26589,7 +27031,7 @@ function registerResetCommand(program2) {
|
|
|
26589
27031
|
for (const entry of (0, import_node_fs53.readdirSync)(cacheDir)) {
|
|
26590
27032
|
if (entry.startsWith("pending-")) {
|
|
26591
27033
|
try {
|
|
26592
|
-
(0, import_node_fs53.unlinkSync)((0,
|
|
27034
|
+
(0, import_node_fs53.unlinkSync)((0, import_node_path37.join)(cacheDir, entry));
|
|
26593
27035
|
purged++;
|
|
26594
27036
|
} catch {
|
|
26595
27037
|
}
|
|
@@ -26616,7 +27058,7 @@ function registerResetCommand(program2) {
|
|
|
26616
27058
|
if ((0, import_node_fs53.existsSync)(logsDir)) {
|
|
26617
27059
|
for (const entry of (0, import_node_fs53.readdirSync)(logsDir)) {
|
|
26618
27060
|
try {
|
|
26619
|
-
(0, import_node_fs53.unlinkSync)((0,
|
|
27061
|
+
(0, import_node_fs53.unlinkSync)((0, import_node_path37.join)(logsDir, entry));
|
|
26620
27062
|
} catch {
|
|
26621
27063
|
}
|
|
26622
27064
|
}
|
|
@@ -26924,8 +27366,8 @@ function registerTelemetryCommands(program2) {
|
|
|
26924
27366
|
}
|
|
26925
27367
|
|
|
26926
27368
|
// src/cli.ts
|
|
26927
|
-
program.name("verity").description("CLI for Verity quality gate service").version("0.32.
|
|
26928
|
-
installStderrLog(actionCommand.name(), process.argv.slice(2), "0.32.
|
|
27369
|
+
program.name("verity").description("CLI for Verity quality gate service").version("0.32.1-experimental.c640abd").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) => {
|
|
27370
|
+
installStderrLog(actionCommand.name(), process.argv.slice(2), "0.32.1-experimental.c640abd");
|
|
26929
27371
|
setUserNamedServiceUrl(program.opts().serviceUrl);
|
|
26930
27372
|
try {
|
|
26931
27373
|
await foldLegacyLocalCredential();
|