@codacy/verity-cli 0.32.0 → 0.32.1-experimental.f2cf829
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 +232 -52
- package/bin/verity.js +782 -359
- 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,16 +12871,99 @@ 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));
|
|
12882
|
+
} catch {
|
|
12883
|
+
}
|
|
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 registrySays(pluginRoot) {
|
|
12931
|
+
const plugins = readJsonFile((0, import_node_path7.join)(claudeConfigDir(), "plugins", "installed_plugins.json"))?.plugins;
|
|
12932
|
+
if (!plugins || typeof plugins !== "object") return "unverified";
|
|
12933
|
+
const want = (0, import_node_path7.resolve)(pluginRoot);
|
|
12934
|
+
const markets = marketplaceLocations();
|
|
12935
|
+
for (const [key, value] of Object.entries(plugins)) {
|
|
12936
|
+
const at = key.lastIndexOf("@");
|
|
12937
|
+
const source = at > 0 ? markets.get(key.slice(at + 1)) : void 0;
|
|
12938
|
+
const claims = (Array.isArray(value) ? value : []).some((entry) => {
|
|
12939
|
+
const installPath = entry?.installPath;
|
|
12940
|
+
return typeof installPath === "string" && (0, import_node_path7.resolve)(installPath) === want;
|
|
12941
|
+
}) || source !== void 0 && isWithin(want, source);
|
|
12942
|
+
if (claims) {
|
|
12943
|
+
if (enabledPluginSetting(key) === false) return "gone";
|
|
12944
|
+
return (0, import_node_fs6.existsSync)(pluginRoot) ? "live" : "gone";
|
|
12945
|
+
}
|
|
12946
|
+
}
|
|
12947
|
+
const managed = (0, import_node_path7.resolve)((0, import_node_path7.join)(claudeConfigDir(), "plugins", "cache"));
|
|
12948
|
+
return want === managed || want.startsWith(managed + import_node_path7.sep) ? "gone" : "unverified";
|
|
12949
|
+
}
|
|
12950
|
+
var _live = /* @__PURE__ */ new Map();
|
|
12951
|
+
function pluginLiveness(pluginRoot) {
|
|
12952
|
+
const cached2 = _live.get(pluginRoot);
|
|
12953
|
+
if (cached2 !== void 0) return cached2;
|
|
12954
|
+
const said = registrySays(pluginRoot);
|
|
12955
|
+
_live.set(pluginRoot, said);
|
|
12956
|
+
return said;
|
|
12957
|
+
}
|
|
12958
|
+
function clearStalePluginMarker() {
|
|
12959
|
+
const marker = readMarker();
|
|
12960
|
+
if (!marker || pluginLiveness(marker.plugin_root) !== "gone") return null;
|
|
12961
|
+
try {
|
|
12962
|
+
(0, import_node_fs6.rmSync)(markerPath(), { force: true });
|
|
12856
12963
|
} catch {
|
|
12964
|
+
return null;
|
|
12857
12965
|
}
|
|
12966
|
+
return { pluginRoot: marker.plugin_root, version: marker.version };
|
|
12858
12967
|
}
|
|
12859
12968
|
function shouldDeferToPlugin(sessionId) {
|
|
12860
12969
|
if (isPluginInvocation()) {
|
|
@@ -12863,13 +12972,48 @@ function shouldDeferToPlugin(sessionId) {
|
|
|
12863
12972
|
}
|
|
12864
12973
|
const marker = readMarker();
|
|
12865
12974
|
if (!marker) return false;
|
|
12866
|
-
|
|
12975
|
+
const liveness = pluginLiveness(marker.plugin_root);
|
|
12976
|
+
if (liveness === "gone") return false;
|
|
12867
12977
|
if (sessionId && marker.session_id) return sessionId === marker.session_id;
|
|
12868
|
-
|
|
12978
|
+
logToFileOnly(
|
|
12979
|
+
// JSON-encoded: `plugin_root` is repository-controlled, and raw it could
|
|
12980
|
+
// write forged lines into the one place someone looks to understand why
|
|
12981
|
+
// the gate did what it did. (`readMarker` also refuses control characters.)
|
|
12982
|
+
`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.`
|
|
12983
|
+
);
|
|
12984
|
+
return false;
|
|
12869
12985
|
}
|
|
12870
12986
|
function pluginActiveHere() {
|
|
12987
|
+
return activePluginInstall() !== null;
|
|
12988
|
+
}
|
|
12989
|
+
function registeredVerityPlugin() {
|
|
12990
|
+
const plugins = readJsonFile((0, import_node_path7.join)(claudeConfigDir(), "plugins", "installed_plugins.json"))?.plugins;
|
|
12991
|
+
if (!plugins || typeof plugins !== "object") return null;
|
|
12992
|
+
const here = realpathOr(repoRoot());
|
|
12993
|
+
for (const [key, value] of Object.entries(plugins)) {
|
|
12994
|
+
const at = key.lastIndexOf("@");
|
|
12995
|
+
if ((at > 0 ? key.slice(0, at) : key) !== "verity") continue;
|
|
12996
|
+
if (enabledPluginSetting(key) === false) continue;
|
|
12997
|
+
for (const entry of Array.isArray(value) ? value : []) {
|
|
12998
|
+
const e = entry;
|
|
12999
|
+
const installPath = typeof e.installPath === "string" ? e.installPath : "";
|
|
13000
|
+
if (!installPath || !(0, import_node_fs6.existsSync)(installPath)) continue;
|
|
13001
|
+
const scope2 = typeof e.scope === "string" ? e.scope : "user";
|
|
13002
|
+
if (scope2 !== "user") {
|
|
13003
|
+
const forProject = typeof e.projectPath === "string" ? realpathOr(e.projectPath) : "";
|
|
13004
|
+
if (forProject !== here) continue;
|
|
13005
|
+
}
|
|
13006
|
+
return { pluginRoot: installPath, version: typeof e.version === "string" ? e.version : null };
|
|
13007
|
+
}
|
|
13008
|
+
}
|
|
13009
|
+
return null;
|
|
13010
|
+
}
|
|
13011
|
+
function activePluginInstall() {
|
|
12871
13012
|
const marker = readMarker();
|
|
12872
|
-
|
|
13013
|
+
if (marker && pluginLiveness(marker.plugin_root) === "live") {
|
|
13014
|
+
return { pluginRoot: marker.plugin_root, version: marker.version };
|
|
13015
|
+
}
|
|
13016
|
+
return registeredVerityPlugin();
|
|
12873
13017
|
}
|
|
12874
13018
|
function deferredToPlugin(command, sessionId) {
|
|
12875
13019
|
if (!shouldDeferToPlugin(sessionId)) return false;
|
|
@@ -12879,21 +13023,63 @@ function deferredToPlugin(command, sessionId) {
|
|
|
12879
13023
|
return true;
|
|
12880
13024
|
}
|
|
12881
13025
|
|
|
13026
|
+
// src/lib/hook-wiring.ts
|
|
13027
|
+
function carriesAnyVerityHook(s) {
|
|
13028
|
+
return s.stop || s.intent || s.baseline || s.compact || s.sessionEnd || s.guard;
|
|
13029
|
+
}
|
|
13030
|
+
async function resolveHookWiring() {
|
|
13031
|
+
const settings = await checkAllVerityHooks();
|
|
13032
|
+
const config = readProjectConfig();
|
|
13033
|
+
const gitMoments = { source: config.source, path: config.path };
|
|
13034
|
+
if (!pluginActiveHere()) {
|
|
13035
|
+
return { source: "settings", status: settings, settings, duplicateSettingsHooks: false, gitMoments };
|
|
13036
|
+
}
|
|
13037
|
+
const status = {
|
|
13038
|
+
stop: true,
|
|
13039
|
+
intent: true,
|
|
13040
|
+
baseline: true,
|
|
13041
|
+
compact: true,
|
|
13042
|
+
sessionEnd: true,
|
|
13043
|
+
guard: true,
|
|
13044
|
+
guardOn: config.git_moments
|
|
13045
|
+
};
|
|
13046
|
+
return {
|
|
13047
|
+
source: "plugin",
|
|
13048
|
+
status,
|
|
13049
|
+
settings,
|
|
13050
|
+
duplicateSettingsHooks: carriesAnyVerityHook(settings),
|
|
13051
|
+
gitMoments
|
|
13052
|
+
};
|
|
13053
|
+
}
|
|
13054
|
+
|
|
12882
13055
|
// src/commands/hooks.ts
|
|
12883
13056
|
var ALL_MOMENTS = ["stop", "pre-commit", "pre-push"];
|
|
12884
|
-
function
|
|
12885
|
-
const
|
|
12886
|
-
|
|
12887
|
-
|
|
13057
|
+
function parseMomentSelection(raw) {
|
|
13058
|
+
const parts = raw.split(",").map((s) => s.trim()).filter(Boolean);
|
|
13059
|
+
if (parts.length === 1 && parts[0].toLowerCase() === "none") return { moments: [] };
|
|
13060
|
+
if (parts.length === 0) {
|
|
13061
|
+
return { error: `--moments was empty. Pass one or more of ${ALL_MOMENTS.join(", ")} \u2014 or "none" to gate nothing.` };
|
|
13062
|
+
}
|
|
13063
|
+
const unknown = parts.filter((p) => !ALL_MOMENTS.includes(p));
|
|
13064
|
+
if (unknown.length > 0) {
|
|
13065
|
+
return {
|
|
13066
|
+
error: `--moments: unrecognised ${unknown.length === 1 ? "moment" : "moments"} ${unknown.map((u) => `"${u}"`).join(", ")}. Valid: ${ALL_MOMENTS.join(", ")} \u2014 or "none" to gate nothing.`
|
|
13067
|
+
};
|
|
12888
13068
|
}
|
|
12889
|
-
|
|
13069
|
+
const seen = new Set(parts);
|
|
13070
|
+
return { moments: ALL_MOMENTS.filter((m) => seen.has(m)) };
|
|
12890
13071
|
}
|
|
12891
13072
|
function registerHooksCommands(program2) {
|
|
12892
13073
|
const hooks = program2.command("hooks").description("Manage Claude Code hook wiring");
|
|
12893
13074
|
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
13075
|
const force = opts.force ?? false;
|
|
12895
13076
|
if (opts.moments != null) {
|
|
12896
|
-
const
|
|
13077
|
+
const parsed = parseMomentSelection(opts.moments);
|
|
13078
|
+
if ("error" in parsed) {
|
|
13079
|
+
printError(parsed.error);
|
|
13080
|
+
process.exit(1);
|
|
13081
|
+
}
|
|
13082
|
+
const moments = parsed.moments;
|
|
12897
13083
|
const gitMoments = [
|
|
12898
13084
|
...moments.includes("pre-commit") ? ["commit"] : [],
|
|
12899
13085
|
...moments.includes("pre-push") ? ["push"] : []
|
|
@@ -12954,20 +13140,22 @@ function registerHooksCommands(program2) {
|
|
|
12954
13140
|
printInfo(" SessionStart hook: verity baseline capture");
|
|
12955
13141
|
});
|
|
12956
13142
|
hooks.command("check").description("Check if Verity hooks are installed").action(async () => {
|
|
12957
|
-
const
|
|
12958
|
-
|
|
12959
|
-
|
|
13143
|
+
const wiring = await resolveHookWiring();
|
|
13144
|
+
const status = wiring.status;
|
|
13145
|
+
if (wiring.source === "plugin") {
|
|
13146
|
+
const moments = status.guardOn;
|
|
13147
|
+
const inherited = wiring.gitMoments.source === "main-worktree" && wiring.gitMoments.path ? ` (inherited from the main worktree: ${wiring.gitMoments.path})` : "";
|
|
12960
13148
|
printInfo("Wired by the Verity Claude Code plugin (not .claude/settings.json):");
|
|
12961
13149
|
printInfo(" Stop hook (verity analyze): installed");
|
|
12962
13150
|
printInfo(" Intent hook (verity intent capture): installed");
|
|
12963
13151
|
printInfo(" Baseline hook (verity baseline capture): installed");
|
|
12964
13152
|
printInfo(
|
|
12965
|
-
` Git-moment gate (verity guard): ${moments.length ? `installed [${moments.join(", ")}]` : "wired but gating nothing"}`
|
|
13153
|
+
` Git-moment gate (verity guard): ${moments.length ? `installed [${moments.join(", ")}]${inherited}` : "wired but gating nothing"}`
|
|
12966
13154
|
);
|
|
12967
13155
|
if (!moments.length) {
|
|
12968
13156
|
printInfo(' Enable it with "verity config git-moments commit,push".');
|
|
12969
13157
|
}
|
|
12970
|
-
if (
|
|
13158
|
+
if (wiring.duplicateSettingsHooks) {
|
|
12971
13159
|
printWarn(" Duplicate hooks also exist in .claude/settings.json. They stand down at run time,");
|
|
12972
13160
|
printWarn(' but remove them with "verity init --plugin-mode" so the wiring says what it does.');
|
|
12973
13161
|
}
|
|
@@ -13352,8 +13540,8 @@ function isCommandOnlyTurn(input) {
|
|
|
13352
13540
|
// src/lib/context-identity.ts
|
|
13353
13541
|
var import_node_crypto2 = require("node:crypto");
|
|
13354
13542
|
var import_node_fs8 = require("node:fs");
|
|
13355
|
-
var
|
|
13356
|
-
var
|
|
13543
|
+
var import_node_os3 = require("node:os");
|
|
13544
|
+
var import_node_path8 = require("node:path");
|
|
13357
13545
|
var SHARED_SENTINELS = /* @__PURE__ */ new Set([
|
|
13358
13546
|
"",
|
|
13359
13547
|
"-",
|
|
@@ -13407,13 +13595,13 @@ function contextIdentity(input) {
|
|
|
13407
13595
|
}
|
|
13408
13596
|
function verityHome() {
|
|
13409
13597
|
const override = process.env.VERITY_HOME;
|
|
13410
|
-
return override && override.trim() ? (0,
|
|
13598
|
+
return override && override.trim() ? (0, import_node_path8.resolve)(override) : (0, import_node_path8.join)((0, import_node_os3.homedir)(), ".verity");
|
|
13411
13599
|
}
|
|
13412
13600
|
function dossierDir(identity) {
|
|
13413
|
-
return (0,
|
|
13601
|
+
return (0, import_node_path8.join)(verityHome(), "sessions", identity.userKey, identity.treeKey, identity.sessionKey);
|
|
13414
13602
|
}
|
|
13415
13603
|
function treeDir(identity) {
|
|
13416
|
-
return (0,
|
|
13604
|
+
return (0, import_node_path8.join)(verityHome(), "sessions", identity.userKey, identity.treeKey);
|
|
13417
13605
|
}
|
|
13418
13606
|
function scopeIdentity(token, sessionId) {
|
|
13419
13607
|
const t = (token ?? "").trim();
|
|
@@ -13429,7 +13617,7 @@ function sessionScopeKey(token, sessionId) {
|
|
|
13429
13617
|
// src/lib/task-context-buffer.ts
|
|
13430
13618
|
var import_promises6 = require("node:fs/promises");
|
|
13431
13619
|
var import_node_fs9 = require("node:fs");
|
|
13432
|
-
var
|
|
13620
|
+
var import_node_path9 = require("node:path");
|
|
13433
13621
|
var TASK_CONTEXT_DIR = `${VERITY_DIR}/.task-context`;
|
|
13434
13622
|
var MAX_BUFFER_BYTES = 500 * 1024;
|
|
13435
13623
|
var MAX_PROMPT_CHARS = 2e3;
|
|
@@ -13507,7 +13695,7 @@ async function cleanupTaskContextBuffers() {
|
|
|
13507
13695
|
const cutoffMs = Date.now() - RETENTION_DAYS * 24 * 60 * 60 * 1e3;
|
|
13508
13696
|
for (const file of files) {
|
|
13509
13697
|
if (!file.endsWith(".jsonl")) continue;
|
|
13510
|
-
const filePath = (0,
|
|
13698
|
+
const filePath = (0, import_node_path9.join)(TASK_CONTEXT_DIR, file);
|
|
13511
13699
|
try {
|
|
13512
13700
|
const stats = await (0, import_promises6.stat)(filePath);
|
|
13513
13701
|
if (stats.mtimeMs < cutoffMs) {
|
|
@@ -13521,7 +13709,7 @@ async function cleanupTaskContextBuffers() {
|
|
|
13521
13709
|
}
|
|
13522
13710
|
function bufferPath(taskId) {
|
|
13523
13711
|
const safe = taskId.replace(/[^a-zA-Z0-9_-]/g, "");
|
|
13524
|
-
return (0,
|
|
13712
|
+
return (0, import_node_path9.join)(TASK_CONTEXT_DIR, `${safe}.jsonl`);
|
|
13525
13713
|
}
|
|
13526
13714
|
async function appendEntry(taskId, entry) {
|
|
13527
13715
|
try {
|
|
@@ -13547,7 +13735,7 @@ async function appendEntry(taskId, entry) {
|
|
|
13547
13735
|
// src/lib/memory-retrieval.ts
|
|
13548
13736
|
var import_promises7 = require("node:fs/promises");
|
|
13549
13737
|
var import_node_fs10 = require("node:fs");
|
|
13550
|
-
var
|
|
13738
|
+
var import_node_path10 = require("node:path");
|
|
13551
13739
|
var memoryDir = () => projectPath(`${VERITY_DIR}/memory`);
|
|
13552
13740
|
var DOMAINS = ["decisions", "quality", "security", "intent", "gotchas", "patterns", "domain", "integrations"];
|
|
13553
13741
|
var DEFAULT_BUDGET_TOKENS = 2e3;
|
|
@@ -13645,14 +13833,14 @@ async function retrieveForInjection(promptText, taskFiles = [], budgetTokens = D
|
|
|
13645
13833
|
const promptTokens = tokenize(promptText);
|
|
13646
13834
|
const nodes = [];
|
|
13647
13835
|
for (const domain of DOMAINS) {
|
|
13648
|
-
const domainDir = (0,
|
|
13836
|
+
const domainDir = (0, import_node_path10.join)(memoryDir(), domain);
|
|
13649
13837
|
if (!(0, import_node_fs10.existsSync)(domainDir)) continue;
|
|
13650
13838
|
try {
|
|
13651
13839
|
const files = await (0, import_promises7.readdir)(domainDir);
|
|
13652
13840
|
for (const file of files) {
|
|
13653
13841
|
if (!file.endsWith(".md")) continue;
|
|
13654
13842
|
try {
|
|
13655
|
-
const content = await (0, import_promises7.readFile)((0,
|
|
13843
|
+
const content = await (0, import_promises7.readFile)((0, import_node_path10.join)(domainDir, file), "utf-8");
|
|
13656
13844
|
const { fm, body } = parseFrontmatter(content);
|
|
13657
13845
|
if (fm.status && fm.status !== "active") continue;
|
|
13658
13846
|
nodes.push({
|
|
@@ -13712,26 +13900,26 @@ async function retrieveForInjection(promptText, taskFiles = [], budgetTokens = D
|
|
|
13712
13900
|
// src/lib/memory-sync.ts
|
|
13713
13901
|
var import_promises8 = require("node:fs/promises");
|
|
13714
13902
|
var import_node_fs12 = require("node:fs");
|
|
13715
|
-
var
|
|
13903
|
+
var import_node_path12 = require("node:path");
|
|
13716
13904
|
var import_node_crypto3 = require("node:crypto");
|
|
13717
13905
|
|
|
13718
13906
|
// src/lib/safe-path.ts
|
|
13719
13907
|
var import_node_fs11 = require("node:fs");
|
|
13720
|
-
var
|
|
13908
|
+
var import_node_path11 = require("node:path");
|
|
13721
13909
|
function resolveInside(baseDir, candidate) {
|
|
13722
13910
|
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(
|
|
13911
|
+
if ((0, import_node_path11.isAbsolute)(candidate)) return null;
|
|
13912
|
+
const baseAbs = (0, import_node_path11.resolve)(baseDir);
|
|
13913
|
+
const full = (0, import_node_path11.resolve)(baseAbs, candidate);
|
|
13914
|
+
const baseSep = baseAbs.endsWith(import_node_path11.sep) ? baseAbs : baseAbs + import_node_path11.sep;
|
|
13727
13915
|
if (full !== baseAbs && !full.startsWith(baseSep)) return null;
|
|
13728
13916
|
try {
|
|
13729
13917
|
if ((0, import_node_fs11.existsSync)(baseAbs)) {
|
|
13730
13918
|
const realBase = (0, import_node_fs11.realpathSync)(baseAbs);
|
|
13731
|
-
const realBaseSep = realBase.endsWith(
|
|
13919
|
+
const realBaseSep = realBase.endsWith(import_node_path11.sep) ? realBase : realBase + import_node_path11.sep;
|
|
13732
13920
|
let probe = full;
|
|
13733
13921
|
while (!(0, import_node_fs11.existsSync)(probe)) {
|
|
13734
|
-
const parent = (0,
|
|
13922
|
+
const parent = (0, import_node_path11.dirname)(probe);
|
|
13735
13923
|
if (parent === probe) break;
|
|
13736
13924
|
probe = parent;
|
|
13737
13925
|
}
|
|
@@ -13812,16 +14000,16 @@ var syncStateFile = () => projectPath(`${VERITY_DIR}/.memory-sync-state.json`);
|
|
|
13812
14000
|
async function ensureMemoryDir() {
|
|
13813
14001
|
await (0, import_promises8.mkdir)(memoryDir2(), { recursive: true });
|
|
13814
14002
|
for (const domain of DOMAINS2) {
|
|
13815
|
-
await (0, import_promises8.mkdir)((0,
|
|
14003
|
+
await (0, import_promises8.mkdir)((0, import_node_path12.join)(memoryDir2(), domain), { recursive: true });
|
|
13816
14004
|
}
|
|
13817
|
-
if (!(0, import_node_fs12.existsSync)((0,
|
|
13818
|
-
await (0, import_promises8.writeFile)((0,
|
|
14005
|
+
if (!(0, import_node_fs12.existsSync)((0, import_node_path12.join)(memoryDir2(), "SCHEMA.md"))) {
|
|
14006
|
+
await (0, import_promises8.writeFile)((0, import_node_path12.join)(memoryDir2(), "SCHEMA.md"), SCHEMA_TEMPLATE);
|
|
13819
14007
|
}
|
|
13820
|
-
if (!(0, import_node_fs12.existsSync)((0,
|
|
13821
|
-
await (0, import_promises8.writeFile)((0,
|
|
14008
|
+
if (!(0, import_node_fs12.existsSync)((0, import_node_path12.join)(memoryDir2(), "index.md"))) {
|
|
14009
|
+
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
14010
|
}
|
|
13823
|
-
if (!(0, import_node_fs12.existsSync)((0,
|
|
13824
|
-
await (0, import_promises8.writeFile)((0,
|
|
14011
|
+
if (!(0, import_node_fs12.existsSync)((0, import_node_path12.join)(memoryDir2(), "log.md"))) {
|
|
14012
|
+
await (0, import_promises8.writeFile)((0, import_node_path12.join)(memoryDir2(), "log.md"), "# Memory Log\n\n");
|
|
13825
14013
|
}
|
|
13826
14014
|
}
|
|
13827
14015
|
async function buildManifest() {
|
|
@@ -13830,14 +14018,14 @@ async function buildManifest() {
|
|
|
13830
14018
|
}
|
|
13831
14019
|
const nodes = [];
|
|
13832
14020
|
for (const domain of DOMAINS2) {
|
|
13833
|
-
const domainDir = (0,
|
|
14021
|
+
const domainDir = (0, import_node_path12.join)(memoryDir2(), domain);
|
|
13834
14022
|
if (!(0, import_node_fs12.existsSync)(domainDir)) continue;
|
|
13835
14023
|
try {
|
|
13836
14024
|
const files = await (0, import_promises8.readdir)(domainDir);
|
|
13837
14025
|
for (const file of files) {
|
|
13838
14026
|
if (!file.endsWith(".md")) continue;
|
|
13839
14027
|
const filePath = `${domain}/${file}`;
|
|
13840
|
-
const fullPath = (0,
|
|
14028
|
+
const fullPath = (0, import_node_path12.join)(memoryDir2(), filePath);
|
|
13841
14029
|
try {
|
|
13842
14030
|
const content = await (0, import_promises8.readFile)(fullPath, "utf-8");
|
|
13843
14031
|
const hash = (0, import_node_crypto3.createHash)("sha256").update(content).digest("hex").slice(0, 16);
|
|
@@ -13850,13 +14038,13 @@ async function buildManifest() {
|
|
|
13850
14038
|
}
|
|
13851
14039
|
let indexHash = null;
|
|
13852
14040
|
try {
|
|
13853
|
-
const indexContent = await (0, import_promises8.readFile)((0,
|
|
14041
|
+
const indexContent = await (0, import_promises8.readFile)((0, import_node_path12.join)(memoryDir2(), "index.md"), "utf-8");
|
|
13854
14042
|
indexHash = `sha256:${(0, import_node_crypto3.createHash)("sha256").update(indexContent).digest("hex").slice(0, 16)}`;
|
|
13855
14043
|
} catch {
|
|
13856
14044
|
}
|
|
13857
14045
|
let logLength = 0;
|
|
13858
14046
|
try {
|
|
13859
|
-
const logContent = await (0, import_promises8.readFile)((0,
|
|
14047
|
+
const logContent = await (0, import_promises8.readFile)((0, import_node_path12.join)(memoryDir2(), "log.md"), "utf-8");
|
|
13860
14048
|
logLength = logContent.split("\n").length;
|
|
13861
14049
|
} catch {
|
|
13862
14050
|
}
|
|
@@ -13869,13 +14057,13 @@ async function readOnDiskNodes() {
|
|
|
13869
14057
|
const out = /* @__PURE__ */ new Map();
|
|
13870
14058
|
if (!(0, import_node_fs12.existsSync)(memoryDir2())) return out;
|
|
13871
14059
|
for (const domain of DOMAINS2) {
|
|
13872
|
-
const domainDir = (0,
|
|
14060
|
+
const domainDir = (0, import_node_path12.join)(memoryDir2(), domain);
|
|
13873
14061
|
if (!(0, import_node_fs12.existsSync)(domainDir)) continue;
|
|
13874
14062
|
try {
|
|
13875
14063
|
for (const file of await (0, import_promises8.readdir)(domainDir)) {
|
|
13876
14064
|
if (!file.endsWith(".md")) continue;
|
|
13877
14065
|
try {
|
|
13878
|
-
out.set(`${domain}/${file}`, hashContent(await (0, import_promises8.readFile)((0,
|
|
14066
|
+
out.set(`${domain}/${file}`, hashContent(await (0, import_promises8.readFile)((0, import_node_path12.join)(domainDir, file), "utf-8")));
|
|
13879
14067
|
} catch {
|
|
13880
14068
|
}
|
|
13881
14069
|
}
|
|
@@ -13921,7 +14109,7 @@ async function computeEditedNodeUploads() {
|
|
|
13921
14109
|
const uploads = [];
|
|
13922
14110
|
for (const [path, prevHash] of prev) {
|
|
13923
14111
|
if (prevHash == null) continue;
|
|
13924
|
-
const full = (0,
|
|
14112
|
+
const full = (0, import_node_path12.join)(memoryDir2(), path);
|
|
13925
14113
|
if (!(0, import_node_fs12.existsSync)(full)) continue;
|
|
13926
14114
|
let content;
|
|
13927
14115
|
try {
|
|
@@ -13958,8 +14146,8 @@ async function applyMemoryWrites(writes, opts = {}) {
|
|
|
13958
14146
|
const logLines = [`- ${(/* @__PURE__ */ new Date()).toISOString().slice(0, 16)} \u2014 Applied ${count} write(s) from server`];
|
|
13959
14147
|
for (const n of notes) logLines.push(` - ${n}`);
|
|
13960
14148
|
try {
|
|
13961
|
-
const existing = (0, import_node_fs12.existsSync)((0,
|
|
13962
|
-
await (0, import_promises8.writeFile)((0,
|
|
14149
|
+
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";
|
|
14150
|
+
await (0, import_promises8.writeFile)((0, import_node_path12.join)(memoryDir2(), "log.md"), existing + logLines.join("\n") + "\n");
|
|
13963
14151
|
} catch {
|
|
13964
14152
|
}
|
|
13965
14153
|
await recordSyncedNodePaths();
|
|
@@ -13991,7 +14179,7 @@ async function applyOneWrite(write, treePaths) {
|
|
|
13991
14179
|
return { written: false, notes };
|
|
13992
14180
|
}
|
|
13993
14181
|
}
|
|
13994
|
-
await (0, import_promises8.mkdir)((0,
|
|
14182
|
+
await (0, import_promises8.mkdir)((0, import_node_path12.dirname)(fullPath), { recursive: true });
|
|
13995
14183
|
await (0, import_promises8.writeFile)(fullPath, content);
|
|
13996
14184
|
return { written: true, notes };
|
|
13997
14185
|
}
|
|
@@ -14032,7 +14220,7 @@ async function regenerateIndex() {
|
|
|
14032
14220
|
];
|
|
14033
14221
|
let totalNodes = 0;
|
|
14034
14222
|
for (const domain of DOMAINS2.filter((d) => d !== "_archive")) {
|
|
14035
|
-
const domainDir = (0,
|
|
14223
|
+
const domainDir = (0, import_node_path12.join)(memoryDir2(), domain);
|
|
14036
14224
|
if (!(0, import_node_fs12.existsSync)(domainDir)) continue;
|
|
14037
14225
|
try {
|
|
14038
14226
|
const files = await (0, import_promises8.readdir)(domainDir);
|
|
@@ -14043,7 +14231,7 @@ async function regenerateIndex() {
|
|
|
14043
14231
|
for (const file of mdFiles.sort()) {
|
|
14044
14232
|
const slug = file.replace(/\.md$/, "");
|
|
14045
14233
|
try {
|
|
14046
|
-
const content = await (0, import_promises8.readFile)((0,
|
|
14234
|
+
const content = await (0, import_promises8.readFile)((0, import_node_path12.join)(domainDir, file), "utf-8");
|
|
14047
14235
|
const title = pickFrontmatter(content, "title") ?? slug;
|
|
14048
14236
|
const kind = pickFrontmatter(content, "kind") ?? "-";
|
|
14049
14237
|
const confidence = pickFrontmatter(content, "confidence");
|
|
@@ -14067,7 +14255,7 @@ async function regenerateIndex() {
|
|
|
14067
14255
|
lines.push("No nodes yet. Run an analysis to start building the knowledge graph.");
|
|
14068
14256
|
}
|
|
14069
14257
|
const next = lines.join("\n") + "\n";
|
|
14070
|
-
const indexPath = (0,
|
|
14258
|
+
const indexPath = (0, import_node_path12.join)(memoryDir2(), "index.md");
|
|
14071
14259
|
let existing = null;
|
|
14072
14260
|
try {
|
|
14073
14261
|
existing = await (0, import_promises8.readFile)(indexPath, "utf-8");
|
|
@@ -14301,7 +14489,7 @@ function hasLegacyMemoryBlock(text) {
|
|
|
14301
14489
|
return findMarker(text, LEGACY_MD_START) !== -1;
|
|
14302
14490
|
}
|
|
14303
14491
|
async function ensureClaudeMdPointer(cwd = repoRoot()) {
|
|
14304
|
-
const claudeMdPath = (0,
|
|
14492
|
+
const claudeMdPath = (0, import_node_path12.join)(cwd, "CLAUDE.md");
|
|
14305
14493
|
let existing = "";
|
|
14306
14494
|
if ((0, import_node_fs12.existsSync)(claudeMdPath)) {
|
|
14307
14495
|
existing = await (0, import_promises8.readFile)(claudeMdPath, "utf-8");
|
|
@@ -14441,7 +14629,7 @@ Body content (\u22648KB). Use [[node-id]] wikilinks for cross-references.
|
|
|
14441
14629
|
// src/lib/dossier-session.ts
|
|
14442
14630
|
var import_node_fs17 = require("node:fs");
|
|
14443
14631
|
var import_node_crypto7 = require("node:crypto");
|
|
14444
|
-
var
|
|
14632
|
+
var import_node_path15 = require("node:path");
|
|
14445
14633
|
|
|
14446
14634
|
// src/lib/pending-repeat.ts
|
|
14447
14635
|
var STOP = /* @__PURE__ */ new Set([
|
|
@@ -14547,7 +14735,7 @@ function statementAnchorKey(file, patternId) {
|
|
|
14547
14735
|
// src/lib/dossier/log.ts
|
|
14548
14736
|
var import_node_crypto4 = require("node:crypto");
|
|
14549
14737
|
var import_node_fs13 = require("node:fs");
|
|
14550
|
-
var
|
|
14738
|
+
var import_node_path13 = require("node:path");
|
|
14551
14739
|
var CRC_TABLE = (() => {
|
|
14552
14740
|
const t = new Int32Array(256);
|
|
14553
14741
|
for (let i = 0; i < 256; i++) {
|
|
@@ -14570,9 +14758,9 @@ function openDossier(identity) {
|
|
|
14570
14758
|
return {
|
|
14571
14759
|
dir,
|
|
14572
14760
|
identity,
|
|
14573
|
-
eventsPath: (0,
|
|
14574
|
-
foldPath: (0,
|
|
14575
|
-
rotatedDir: (0,
|
|
14761
|
+
eventsPath: (0, import_node_path13.join)(dir, "events.jsonl"),
|
|
14762
|
+
foldPath: (0, import_node_path13.join)(dir, "fold.json"),
|
|
14763
|
+
rotatedDir: (0, import_node_path13.join)(dir, "rotated")
|
|
14576
14764
|
};
|
|
14577
14765
|
} catch {
|
|
14578
14766
|
return null;
|
|
@@ -14645,11 +14833,11 @@ function rotateIfNeeded2(d) {
|
|
|
14645
14833
|
if (!(0, import_node_fs13.existsSync)(d.eventsPath)) return;
|
|
14646
14834
|
if ((0, import_node_fs13.statSync)(d.eventsPath).size < ROTATE_BYTES) return;
|
|
14647
14835
|
(0, import_node_fs13.mkdirSync)(d.rotatedDir, { recursive: true, mode: 448 });
|
|
14648
|
-
(0, import_node_fs13.renameSync)(d.eventsPath, (0,
|
|
14836
|
+
(0, import_node_fs13.renameSync)(d.eventsPath, (0, import_node_path13.join)(d.rotatedDir, `events.${Date.now()}.jsonl`));
|
|
14649
14837
|
const kept = (0, import_node_fs13.readdirSync)(d.rotatedDir).filter((f) => f.endsWith(".jsonl")).sort();
|
|
14650
14838
|
for (const stale of kept.slice(0, Math.max(0, kept.length - ROTATE_KEEP))) {
|
|
14651
14839
|
try {
|
|
14652
|
-
(0, import_node_fs13.renameSync)((0,
|
|
14840
|
+
(0, import_node_fs13.renameSync)((0, import_node_path13.join)(d.rotatedDir, stale), (0, import_node_path13.join)(d.rotatedDir, `${stale}.pruned`));
|
|
14653
14841
|
} catch {
|
|
14654
14842
|
}
|
|
14655
14843
|
}
|
|
@@ -14660,7 +14848,7 @@ function rotateIfNeeded2(d) {
|
|
|
14660
14848
|
// src/lib/dossier/fold-dossier.ts
|
|
14661
14849
|
var import_node_crypto5 = require("node:crypto");
|
|
14662
14850
|
var import_node_fs14 = require("node:fs");
|
|
14663
|
-
var
|
|
14851
|
+
var import_node_path14 = require("node:path");
|
|
14664
14852
|
var EMPTY_CAPABILITIES = () => ({
|
|
14665
14853
|
human_reachable: { value: "unknown", tier: "unknown" },
|
|
14666
14854
|
authorship_observability: { value: "unknown", tier: "unknown" },
|
|
@@ -14716,7 +14904,7 @@ function foldDossier(d, opts = {}) {
|
|
|
14716
14904
|
state.meta.rotations = files.length;
|
|
14717
14905
|
for (const f of files) {
|
|
14718
14906
|
try {
|
|
14719
|
-
ingest((0, import_node_fs14.readFileSync)((0,
|
|
14907
|
+
ingest((0, import_node_fs14.readFileSync)((0, import_node_path14.join)(d.rotatedDir, f), "utf8"));
|
|
14720
14908
|
} catch {
|
|
14721
14909
|
state.meta.dropped_lines++;
|
|
14722
14910
|
}
|
|
@@ -15573,16 +15761,16 @@ function foreignAuthoredPaths(identity, opts = {}) {
|
|
|
15573
15761
|
for (const entry of (0, import_node_fs17.readdirSync)(dir, { withFileTypes: true })) {
|
|
15574
15762
|
if (!entry.isDirectory()) continue;
|
|
15575
15763
|
if (entry.name === identity.sessionKey) continue;
|
|
15576
|
-
const log = (0,
|
|
15764
|
+
const log = (0, import_node_path15.join)(dir, entry.name, "events.jsonl");
|
|
15577
15765
|
try {
|
|
15578
15766
|
if (!(0, import_node_fs17.existsSync)(log)) continue;
|
|
15579
15767
|
if (now - (0, import_node_fs17.statSync)(log).mtimeMs > windowMs) continue;
|
|
15580
15768
|
const sib = {
|
|
15581
|
-
dir: (0,
|
|
15769
|
+
dir: (0, import_node_path15.join)(dir, entry.name),
|
|
15582
15770
|
identity,
|
|
15583
15771
|
eventsPath: log,
|
|
15584
|
-
foldPath: (0,
|
|
15585
|
-
rotatedDir: (0,
|
|
15772
|
+
foldPath: (0, import_node_path15.join)(dir, entry.name, "fold.json"),
|
|
15773
|
+
rotatedDir: (0, import_node_path15.join)(dir, entry.name, "rotated")
|
|
15586
15774
|
};
|
|
15587
15775
|
const state = readFoldCache(sib) ?? foldDossier(sib);
|
|
15588
15776
|
sessions++;
|
|
@@ -15610,22 +15798,22 @@ function pruneOldDossiers(identity, maxAgeMs = 7 * 24 * 60 * 60 * 1e3) {
|
|
|
15610
15798
|
let removed = 0;
|
|
15611
15799
|
try {
|
|
15612
15800
|
const mine = dossierDir(identity);
|
|
15613
|
-
const userDir = (0,
|
|
15801
|
+
const userDir = (0, import_node_path15.dirname)((0, import_node_path15.dirname)(mine));
|
|
15614
15802
|
if (!(0, import_node_fs17.existsSync)(userDir)) return 0;
|
|
15615
15803
|
const cutoff = Date.now() - maxAgeMs;
|
|
15616
15804
|
for (const tree of (0, import_node_fs17.readdirSync)(userDir, { withFileTypes: true })) {
|
|
15617
15805
|
if (!tree.isDirectory()) continue;
|
|
15618
|
-
const treePath = (0,
|
|
15806
|
+
const treePath = (0, import_node_path15.join)(userDir, tree.name);
|
|
15619
15807
|
let live = 0;
|
|
15620
15808
|
for (const entry of (0, import_node_fs17.readdirSync)(treePath, { withFileTypes: true })) {
|
|
15621
15809
|
if (!entry.isDirectory()) continue;
|
|
15622
|
-
const dir = (0,
|
|
15810
|
+
const dir = (0, import_node_path15.join)(treePath, entry.name);
|
|
15623
15811
|
if (dir === mine) {
|
|
15624
15812
|
live++;
|
|
15625
15813
|
continue;
|
|
15626
15814
|
}
|
|
15627
15815
|
try {
|
|
15628
|
-
const log = (0,
|
|
15816
|
+
const log = (0, import_node_path15.join)(dir, "events.jsonl");
|
|
15629
15817
|
const at = (0, import_node_fs17.existsSync)(log) ? (0, import_node_fs17.statSync)(log).mtimeMs : (0, import_node_fs17.statSync)(dir).mtimeMs;
|
|
15630
15818
|
if (at < cutoff) {
|
|
15631
15819
|
(0, import_node_fs17.rmSync)(dir, { recursive: true, force: true });
|
|
@@ -15680,7 +15868,7 @@ function recordTurn(d, t) {
|
|
|
15680
15868
|
for (const a of t.authored) {
|
|
15681
15869
|
const origin = a.owner === "subagent" ? "subagent" : "edit_tool";
|
|
15682
15870
|
const prior = t.known?.authored?.get(a.p);
|
|
15683
|
-
const hash = fileHash((0,
|
|
15871
|
+
const hash = fileHash((0, import_node_path15.join)(root, a.p));
|
|
15684
15872
|
const hunks = Math.max(0, a.h - (prior?.hunks ?? 0));
|
|
15685
15873
|
const adds = Math.max(0, a.a - (prior?.adds ?? 0));
|
|
15686
15874
|
const dels = Math.max(0, a.d - (prior?.dels ?? 0));
|
|
@@ -15713,7 +15901,7 @@ function recordTurn(d, t) {
|
|
|
15713
15901
|
}
|
|
15714
15902
|
const seenDivergence = t.known?.divergence ?? /* @__PURE__ */ new Set();
|
|
15715
15903
|
for (const u of t.unobserved) {
|
|
15716
|
-
const hash = fileHash((0,
|
|
15904
|
+
const hash = fileHash((0, import_node_path15.join)(root, u.p));
|
|
15717
15905
|
if (seenDivergence.has(divergenceKey(u.p, hash))) continue;
|
|
15718
15906
|
appendEvent(d, { k: "divergence", kind: "external_mutation", path: u.p, hash });
|
|
15719
15907
|
}
|
|
@@ -15748,7 +15936,7 @@ function recordVerdict(d, v) {
|
|
|
15748
15936
|
if (!sent.has(f.file)) continue;
|
|
15749
15937
|
if (!lines.has(f.file)) {
|
|
15750
15938
|
try {
|
|
15751
|
-
const abs = (0,
|
|
15939
|
+
const abs = (0, import_node_path15.join)(root, f.file);
|
|
15752
15940
|
lines.set(f.file, (0, import_node_fs17.existsSync)(abs) ? (0, import_node_fs17.readFileSync)(abs, "utf8").split("\n") : null);
|
|
15753
15941
|
} catch {
|
|
15754
15942
|
lines.set(f.file, null);
|
|
@@ -15849,7 +16037,7 @@ function recallMemory(d, identity, opts) {
|
|
|
15849
16037
|
budgetBytes: opts.budgetBytes,
|
|
15850
16038
|
readFileLines: (file) => {
|
|
15851
16039
|
try {
|
|
15852
|
-
const abs = (0,
|
|
16040
|
+
const abs = (0, import_node_path15.join)(root, file);
|
|
15853
16041
|
return (0, import_node_fs17.existsSync)(abs) ? (0, import_node_fs17.readFileSync)(abs, "utf8").split("\n") : null;
|
|
15854
16042
|
} catch {
|
|
15855
16043
|
return null;
|
|
@@ -15995,21 +16183,21 @@ async function fireClassify(prompt, sessionId, globals) {
|
|
|
15995
16183
|
|
|
15996
16184
|
// src/commands/lifecycle.ts
|
|
15997
16185
|
var import_node_fs21 = require("node:fs");
|
|
15998
|
-
var
|
|
16186
|
+
var import_node_path19 = require("node:path");
|
|
15999
16187
|
|
|
16000
16188
|
// src/lib/baseline.ts
|
|
16001
16189
|
var import_node_fs20 = require("node:fs");
|
|
16002
|
-
var
|
|
16190
|
+
var import_node_path18 = require("node:path");
|
|
16003
16191
|
var import_node_crypto9 = require("node:crypto");
|
|
16004
16192
|
|
|
16005
16193
|
// src/lib/snapshot.ts
|
|
16006
16194
|
var import_node_fs19 = require("node:fs");
|
|
16007
|
-
var
|
|
16195
|
+
var import_node_path17 = require("node:path");
|
|
16008
16196
|
var import_node_child_process6 = require("node:child_process");
|
|
16009
16197
|
|
|
16010
16198
|
// src/lib/files.ts
|
|
16011
16199
|
var import_node_fs18 = require("node:fs");
|
|
16012
|
-
var
|
|
16200
|
+
var import_node_path16 = require("node:path");
|
|
16013
16201
|
var LANG_MAP = {
|
|
16014
16202
|
// Analyzable (static analysis + Gemini)
|
|
16015
16203
|
ts: "typescript",
|
|
@@ -16077,7 +16265,7 @@ var LANG_MAP = {
|
|
|
16077
16265
|
mk: "make"
|
|
16078
16266
|
};
|
|
16079
16267
|
function detectLanguage(filepath) {
|
|
16080
|
-
const ext = (0,
|
|
16268
|
+
const ext = (0, import_node_path16.extname)(filepath).slice(1);
|
|
16081
16269
|
return LANG_MAP[ext] ?? ext;
|
|
16082
16270
|
}
|
|
16083
16271
|
function sortByMtime(files) {
|
|
@@ -16180,7 +16368,7 @@ function generateSnapshotDiffs(files) {
|
|
|
16180
16368
|
const diffs = [];
|
|
16181
16369
|
for (const file of files) {
|
|
16182
16370
|
if (!resolveInside(SNAPSHOT_DIR, file.path)) continue;
|
|
16183
|
-
const snapshotPath = (0,
|
|
16371
|
+
const snapshotPath = (0, import_node_path17.join)(SNAPSHOT_DIR, file.path);
|
|
16184
16372
|
const language = file.language ?? detectLanguage(file.path);
|
|
16185
16373
|
if ((0, import_node_fs19.existsSync)(snapshotPath)) {
|
|
16186
16374
|
const oldContent = (0, import_node_fs19.readFileSync)(snapshotPath, "utf-8");
|
|
@@ -16208,16 +16396,16 @@ function saveSnapshots(files) {
|
|
|
16208
16396
|
const snapshotPaths = /* @__PURE__ */ new Set();
|
|
16209
16397
|
for (const file of files) {
|
|
16210
16398
|
if (!resolveInside(SNAPSHOT_DIR, file.path)) continue;
|
|
16211
|
-
const snapshotPath = (0,
|
|
16399
|
+
const snapshotPath = (0, import_node_path17.join)(SNAPSHOT_DIR, file.path);
|
|
16212
16400
|
snapshotPaths.add(snapshotPath);
|
|
16213
|
-
(0, import_node_fs19.mkdirSync)((0,
|
|
16401
|
+
(0, import_node_fs19.mkdirSync)((0, import_node_path17.dirname)(snapshotPath), { recursive: true });
|
|
16214
16402
|
(0, import_node_fs19.writeFileSync)(snapshotPath, file.content);
|
|
16215
16403
|
}
|
|
16216
16404
|
cleanStaleSnapshots(SNAPSHOT_DIR, snapshotPaths);
|
|
16217
16405
|
}
|
|
16218
16406
|
function computeDiff(oldContent, newContent, filePath) {
|
|
16219
|
-
const tmpOld = (0,
|
|
16220
|
-
const tmpNew = (0,
|
|
16407
|
+
const tmpOld = (0, import_node_path17.join)(SNAPSHOT_DIR, ".diff-old.tmp");
|
|
16408
|
+
const tmpNew = (0, import_node_path17.join)(SNAPSHOT_DIR, ".diff-new.tmp");
|
|
16221
16409
|
try {
|
|
16222
16410
|
(0, import_node_fs19.mkdirSync)(SNAPSHOT_DIR, { recursive: true });
|
|
16223
16411
|
(0, import_node_fs19.writeFileSync)(tmpOld, oldContent);
|
|
@@ -16250,7 +16438,7 @@ function cleanStaleSnapshots(dir, keepSet) {
|
|
|
16250
16438
|
const entries = (0, import_node_fs19.readdirSync)(dir, { withFileTypes: true });
|
|
16251
16439
|
for (const entry of entries) {
|
|
16252
16440
|
if (dir === SNAPSHOT_DIR && (entry.name === ".diff-old.tmp" || entry.name === ".diff-new.tmp")) continue;
|
|
16253
|
-
const fullPath = (0,
|
|
16441
|
+
const fullPath = (0, import_node_path17.join)(dir, entry.name);
|
|
16254
16442
|
if (entry.isDirectory()) {
|
|
16255
16443
|
cleanStaleSnapshots(fullPath, keepSet);
|
|
16256
16444
|
try {
|
|
@@ -16279,13 +16467,13 @@ function sessionKey(sessionId) {
|
|
|
16279
16467
|
return (0, import_node_crypto9.createHash)("sha256").update(sessionId).digest("hex").slice(0, 16);
|
|
16280
16468
|
}
|
|
16281
16469
|
function sessionDir(key) {
|
|
16282
|
-
return (0,
|
|
16470
|
+
return (0, import_node_path18.join)(projectPath(BASELINE_DIR), key);
|
|
16283
16471
|
}
|
|
16284
16472
|
function manifestPath(dir) {
|
|
16285
|
-
return (0,
|
|
16473
|
+
return (0, import_node_path18.join)(dir, "manifest.json");
|
|
16286
16474
|
}
|
|
16287
16475
|
function mirrorPath(dir, repoRelPath) {
|
|
16288
|
-
return (0,
|
|
16476
|
+
return (0, import_node_path18.join)(dir, "files", repoRelPath);
|
|
16289
16477
|
}
|
|
16290
16478
|
var CARRY_FILE = `${BASELINE_DIR}/.carry`;
|
|
16291
16479
|
var CARRY_WINDOW_MS = 12e4;
|
|
@@ -16347,7 +16535,7 @@ function captureBaseline(opts = {}) {
|
|
|
16347
16535
|
(0, import_node_fs20.rmSync)(dir, { recursive: true, force: true });
|
|
16348
16536
|
} catch {
|
|
16349
16537
|
}
|
|
16350
|
-
const filesDir = (0,
|
|
16538
|
+
const filesDir = (0, import_node_path18.join)(dir, "files");
|
|
16351
16539
|
const mirrored = [];
|
|
16352
16540
|
try {
|
|
16353
16541
|
(0, import_node_fs20.mkdirSync)(filesDir, { recursive: true });
|
|
@@ -16357,7 +16545,7 @@ function captureBaseline(opts = {}) {
|
|
|
16357
16545
|
if (content === null) continue;
|
|
16358
16546
|
const dest = mirrorPath(dir, p);
|
|
16359
16547
|
try {
|
|
16360
|
-
(0, import_node_fs20.mkdirSync)((0,
|
|
16548
|
+
(0, import_node_fs20.mkdirSync)((0, import_node_path18.dirname)(dest), { recursive: true });
|
|
16361
16549
|
(0, import_node_fs20.writeFileSync)(dest, content);
|
|
16362
16550
|
mirrored.push(p);
|
|
16363
16551
|
} catch {
|
|
@@ -16465,7 +16653,7 @@ function absorbIntoBaseline(paths, sessionId) {
|
|
|
16465
16653
|
const content = safeReadForMirror(projectPath(p));
|
|
16466
16654
|
if (content === null) continue;
|
|
16467
16655
|
const dest = mirrorPath(dir, p);
|
|
16468
|
-
(0, import_node_fs20.mkdirSync)((0,
|
|
16656
|
+
(0, import_node_fs20.mkdirSync)((0, import_node_path18.dirname)(dest), { recursive: true });
|
|
16469
16657
|
(0, import_node_fs20.writeFileSync)(dest, content);
|
|
16470
16658
|
dirty.add(p);
|
|
16471
16659
|
adopted++;
|
|
@@ -16513,7 +16701,7 @@ function pruneOldBaselines() {
|
|
|
16513
16701
|
}
|
|
16514
16702
|
const now = Date.now();
|
|
16515
16703
|
for (const name of entries) {
|
|
16516
|
-
const dir = (0,
|
|
16704
|
+
const dir = (0, import_node_path18.join)(root, name);
|
|
16517
16705
|
const manifest = readManifest(dir);
|
|
16518
16706
|
if (!manifest) {
|
|
16519
16707
|
try {
|
|
@@ -16701,7 +16889,7 @@ function buildCompactionContext(session) {
|
|
|
16701
16889
|
commitsSince: commitsSincePaths(watermark, (state.authored ?? []).map((a) => a.path)),
|
|
16702
16890
|
readFileLines: (file) => {
|
|
16703
16891
|
try {
|
|
16704
|
-
const abs = (0,
|
|
16892
|
+
const abs = (0, import_node_path19.join)(root, file);
|
|
16705
16893
|
return (0, import_node_fs21.existsSync)(abs) ? (0, import_node_fs21.readFileSync)(abs, "utf8").split("\n") : null;
|
|
16706
16894
|
} catch {
|
|
16707
16895
|
return null;
|
|
@@ -16738,17 +16926,17 @@ async function readHookStdin() {
|
|
|
16738
16926
|
try {
|
|
16739
16927
|
if (process.stdin.isTTY) return {};
|
|
16740
16928
|
const chunks = [];
|
|
16741
|
-
const timeout = new Promise((
|
|
16742
|
-
const read = new Promise((
|
|
16929
|
+
const timeout = new Promise((resolve5) => setTimeout(() => resolve5({}), 500));
|
|
16930
|
+
const read = new Promise((resolve5) => {
|
|
16743
16931
|
process.stdin.on("data", (c) => chunks.push(c));
|
|
16744
16932
|
process.stdin.on("end", () => {
|
|
16745
16933
|
try {
|
|
16746
|
-
|
|
16934
|
+
resolve5(JSON.parse(Buffer.concat(chunks).toString("utf-8").trim() || "{}"));
|
|
16747
16935
|
} catch {
|
|
16748
|
-
|
|
16936
|
+
resolve5({});
|
|
16749
16937
|
}
|
|
16750
16938
|
});
|
|
16751
|
-
process.stdin.on("error", () =>
|
|
16939
|
+
process.stdin.on("error", () => resolve5({}));
|
|
16752
16940
|
process.stdin.resume();
|
|
16753
16941
|
});
|
|
16754
16942
|
return await Promise.race([read, timeout]);
|
|
@@ -16766,17 +16954,17 @@ var import_yaml3 = __toESM(require_dist());
|
|
|
16766
16954
|
var import_node_child_process8 = require("node:child_process");
|
|
16767
16955
|
var import_node_fs24 = require("node:fs");
|
|
16768
16956
|
var import_promises9 = require("node:fs/promises");
|
|
16769
|
-
var
|
|
16957
|
+
var import_node_path22 = require("node:path");
|
|
16770
16958
|
var import_yaml = __toESM(require_dist());
|
|
16771
16959
|
|
|
16772
16960
|
// src/lib/data-dir.ts
|
|
16773
16961
|
var import_node_fs22 = require("node:fs");
|
|
16774
|
-
var
|
|
16962
|
+
var import_node_path20 = require("node:path");
|
|
16775
16963
|
function resolveDataDir() {
|
|
16776
|
-
const
|
|
16777
|
-
(0,
|
|
16964
|
+
const candidates2 = [
|
|
16965
|
+
(0, import_node_path20.join)(__dirname, "..", "data"),
|
|
16778
16966
|
// installed: node_modules/@codacy/verity-cli/data
|
|
16779
|
-
(0,
|
|
16967
|
+
(0, import_node_path20.join)(__dirname, "..", "..", "data"),
|
|
16780
16968
|
// edge case: nested resolution
|
|
16781
16969
|
// THE COMMITTED SOURCE, for a source checkout that has not been built.
|
|
16782
16970
|
// cli/data/skills/ is a BUILD ARTIFACT (scripts/build.js copies client/skills
|
|
@@ -16785,14 +16973,14 @@ function resolveDataDir() {
|
|
|
16785
16973
|
// without this the synthesizer throws "Could not find Verity skill data"
|
|
16786
16974
|
// for every test and every `verity` run from source. Resolved from this
|
|
16787
16975
|
// module's own location, never the cwd: see the warning below.
|
|
16788
|
-
(0,
|
|
16976
|
+
(0, import_node_path20.join)(__dirname, "..", "..", "client"),
|
|
16789
16977
|
// bundled: cli/bin/ → ../../client
|
|
16790
|
-
(0,
|
|
16978
|
+
(0, import_node_path20.join)(__dirname, "..", "..", "..", "client"),
|
|
16791
16979
|
// tsx: cli/src/lib/ → ../../../client
|
|
16792
16980
|
...process.env.VERITY_DEV_DATA_DIR ? [process.env.VERITY_DEV_DATA_DIR] : []
|
|
16793
16981
|
];
|
|
16794
|
-
for (const candidate of
|
|
16795
|
-
if ((0, import_node_fs22.existsSync)((0,
|
|
16982
|
+
for (const candidate of candidates2) {
|
|
16983
|
+
if ((0, import_node_fs22.existsSync)((0, import_node_path20.join)(candidate, "skills"))) {
|
|
16796
16984
|
return candidate;
|
|
16797
16985
|
}
|
|
16798
16986
|
}
|
|
@@ -16801,13 +16989,13 @@ function resolveDataDir() {
|
|
|
16801
16989
|
);
|
|
16802
16990
|
}
|
|
16803
16991
|
function setupDataPath(file) {
|
|
16804
|
-
return (0,
|
|
16992
|
+
return (0, import_node_path20.join)(resolveDataDir(), "skills", "verity-setup", file);
|
|
16805
16993
|
}
|
|
16806
16994
|
|
|
16807
16995
|
// src/lib/detect.ts
|
|
16808
16996
|
var import_node_child_process7 = require("node:child_process");
|
|
16809
16997
|
var import_node_fs23 = require("node:fs");
|
|
16810
|
-
var
|
|
16998
|
+
var import_node_path21 = require("node:path");
|
|
16811
16999
|
var TOOLED_LANGUAGES = /* @__PURE__ */ new Set([
|
|
16812
17000
|
"typescript",
|
|
16813
17001
|
"javascript",
|
|
@@ -16870,18 +17058,18 @@ function walk(root) {
|
|
|
16870
17058
|
for (const entry of entries) {
|
|
16871
17059
|
if (found.length >= WALK_MAX_FILES) return;
|
|
16872
17060
|
if (IGNORED_SEGMENTS.includes(entry.name)) continue;
|
|
16873
|
-
const full = (0,
|
|
17061
|
+
const full = (0, import_node_path21.join)(dir, entry.name);
|
|
16874
17062
|
if (entry.isDirectory()) visit(full, depth + 1);
|
|
16875
|
-
else if (entry.isFile()) found.push((0,
|
|
17063
|
+
else if (entry.isFile()) found.push((0, import_node_path21.relative)(root, full));
|
|
16876
17064
|
}
|
|
16877
17065
|
};
|
|
16878
17066
|
visit(root, 0);
|
|
16879
17067
|
return found;
|
|
16880
17068
|
}
|
|
16881
17069
|
function languageOf(path) {
|
|
16882
|
-
const name = (0,
|
|
17070
|
+
const name = (0, import_node_path21.basename)(path);
|
|
16883
17071
|
if (/^Dockerfile(\..+)?$/i.test(name)) return "dockerfile";
|
|
16884
|
-
if (!(0,
|
|
17072
|
+
if (!(0, import_node_path21.extname)(name)) return null;
|
|
16885
17073
|
const lang = detectLanguage(path);
|
|
16886
17074
|
return lang || null;
|
|
16887
17075
|
}
|
|
@@ -16963,12 +17151,12 @@ function declaredDependencies(root, files) {
|
|
|
16963
17151
|
if (deps && typeof deps === "object") names2.push(...Object.keys(deps));
|
|
16964
17152
|
}
|
|
16965
17153
|
};
|
|
16966
|
-
readPackageJson((0,
|
|
16967
|
-
const nested = files.filter((f) => f.includes("/") && (0,
|
|
16968
|
-
for (const rel of nested) readPackageJson((0,
|
|
17154
|
+
readPackageJson((0, import_node_path21.join)(root, "package.json"));
|
|
17155
|
+
const nested = files.filter((f) => f.includes("/") && (0, import_node_path21.basename)(f) === "package.json").slice(0, NESTED_MANIFEST_LIMIT);
|
|
17156
|
+
for (const rel of nested) readPackageJson((0, import_node_path21.join)(root, rel));
|
|
16969
17157
|
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,
|
|
17158
|
+
...["pyproject.toml", "requirements.txt", "Pipfile", "setup.py"].map((f) => (0, import_node_path21.join)(root, f)),
|
|
17159
|
+
...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
17160
|
];
|
|
16973
17161
|
for (const path of pythonManifests) {
|
|
16974
17162
|
if (!(0, import_node_fs23.existsSync)(path)) continue;
|
|
@@ -16983,8 +17171,8 @@ function declaredDependencies(root, files) {
|
|
|
16983
17171
|
}
|
|
16984
17172
|
}
|
|
16985
17173
|
const goMods = [
|
|
16986
|
-
(0,
|
|
16987
|
-
...files.filter((f) => f.includes("/") && (0,
|
|
17174
|
+
(0, import_node_path21.join)(root, "go.mod"),
|
|
17175
|
+
...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
17176
|
];
|
|
16989
17177
|
for (const path of goMods) {
|
|
16990
17178
|
if (!(0, import_node_fs23.existsSync)(path)) continue;
|
|
@@ -16997,7 +17185,7 @@ function declaredDependencies(root, files) {
|
|
|
16997
17185
|
}
|
|
16998
17186
|
}
|
|
16999
17187
|
for (const file of ["pom.xml", "build.gradle", "build.gradle.kts", "Gemfile", "Cargo.toml"]) {
|
|
17000
|
-
const path = (0,
|
|
17188
|
+
const path = (0, import_node_path21.join)(root, file);
|
|
17001
17189
|
if (!(0, import_node_fs23.existsSync)(path)) continue;
|
|
17002
17190
|
try {
|
|
17003
17191
|
const text = (0, import_node_fs23.readFileSync)(path, "utf-8");
|
|
@@ -17008,7 +17196,7 @@ function declaredDependencies(root, files) {
|
|
|
17008
17196
|
return names2;
|
|
17009
17197
|
}
|
|
17010
17198
|
function detectBuildSystem(root, files) {
|
|
17011
|
-
const has = (f) => (0, import_node_fs23.existsSync)((0,
|
|
17199
|
+
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
17200
|
if (has("pnpm-lock.yaml")) return "pnpm";
|
|
17013
17201
|
if (has("yarn.lock")) return "yarn";
|
|
17014
17202
|
if (has("bun.lock") || has("bun.lockb")) return "bun";
|
|
@@ -17025,8 +17213,8 @@ function detectBuildSystem(root, files) {
|
|
|
17025
17213
|
}
|
|
17026
17214
|
function detectArchitecture(root, files) {
|
|
17027
17215
|
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,
|
|
17216
|
+
if (workspaceMarkers.some((m) => (0, import_node_fs23.existsSync)((0, import_node_path21.join)(root, m)))) return "monorepo";
|
|
17217
|
+
const pkg = readJson((0, import_node_path21.join)(root, "package.json"));
|
|
17030
17218
|
if (pkg && "workspaces" in pkg) return "monorepo";
|
|
17031
17219
|
const manifests = files.filter((f) => /(^|\/)(package\.json|go\.mod|pyproject\.toml|Cargo\.toml|pom\.xml)$/.test(f));
|
|
17032
17220
|
const nested = manifests.filter((f) => f.includes("/"));
|
|
@@ -17039,16 +17227,16 @@ function detectArchitecture(root, files) {
|
|
|
17039
17227
|
var SAMPLE_LIMIT = 300;
|
|
17040
17228
|
function measureAvgFileLength(root, files, languages) {
|
|
17041
17229
|
const primary = new Set(languages.slice(0, 2));
|
|
17042
|
-
const
|
|
17230
|
+
const candidates2 = files.filter((f) => {
|
|
17043
17231
|
const lang = languageOf(f);
|
|
17044
17232
|
return lang !== null && primary.has(lang);
|
|
17045
17233
|
});
|
|
17046
|
-
if (
|
|
17047
|
-
const stride = Math.max(1, Math.floor(
|
|
17234
|
+
if (candidates2.length === 0) return null;
|
|
17235
|
+
const stride = Math.max(1, Math.floor(candidates2.length / SAMPLE_LIMIT));
|
|
17048
17236
|
let total = 0;
|
|
17049
17237
|
let counted = 0;
|
|
17050
|
-
for (let i = 0; i <
|
|
17051
|
-
const path = (0,
|
|
17238
|
+
for (let i = 0; i < candidates2.length; i += stride) {
|
|
17239
|
+
const path = (0, import_node_path21.join)(root, candidates2[i]);
|
|
17052
17240
|
try {
|
|
17053
17241
|
if ((0, import_node_fs23.statSync)(path).size > 2 * 1024 * 1024) continue;
|
|
17054
17242
|
total += (0, import_node_fs23.readFileSync)(path, "utf-8").split("\n").length;
|
|
@@ -17076,14 +17264,14 @@ function detectProject(root = repoRoot()) {
|
|
|
17076
17264
|
const existingToolConfigs = [];
|
|
17077
17265
|
for (const [tool, markers] of TOOL_CONFIG_MARKERS) {
|
|
17078
17266
|
for (const marker of markers) {
|
|
17079
|
-
if ((0, import_node_fs23.existsSync)((0,
|
|
17267
|
+
if ((0, import_node_fs23.existsSync)((0, import_node_path21.join)(root, marker))) {
|
|
17080
17268
|
existingToolConfigs.push({ tool, path: `./${marker}` });
|
|
17081
17269
|
break;
|
|
17082
17270
|
}
|
|
17083
17271
|
}
|
|
17084
17272
|
}
|
|
17085
17273
|
return {
|
|
17086
|
-
projectName: (0,
|
|
17274
|
+
projectName: (0, import_node_path21.basename)(root),
|
|
17087
17275
|
languages,
|
|
17088
17276
|
languageCounts,
|
|
17089
17277
|
frameworks: matchAll(dependencies, FRAMEWORK_BY_DEPENDENCY),
|
|
@@ -17529,7 +17717,7 @@ async function correctVerityMdVersion(opts) {
|
|
|
17529
17717
|
}
|
|
17530
17718
|
async function writeFileTo(relative2, body) {
|
|
17531
17719
|
const target = projectPath(relative2);
|
|
17532
|
-
await (0, import_promises9.mkdir)((0,
|
|
17720
|
+
await (0, import_promises9.mkdir)((0, import_node_path22.dirname)(target), { recursive: true });
|
|
17533
17721
|
await (0, import_promises9.writeFile)(target, body);
|
|
17534
17722
|
}
|
|
17535
17723
|
async function deriveConfigForStandard(standard) {
|
|
@@ -18004,7 +18192,11 @@ function registerConfigCommands(program2) {
|
|
|
18004
18192
|
});
|
|
18005
18193
|
config.command("git-moments [moments]").description('Get or set the git moments the guard reviews: commit,push \u2014 or "none"').action((moments) => {
|
|
18006
18194
|
if (moments === void 0) {
|
|
18007
|
-
const
|
|
18195
|
+
const config2 = readProjectConfig();
|
|
18196
|
+
const current = config2.git_moments;
|
|
18197
|
+
if (config2.source === "main-worktree" && config2.path) {
|
|
18198
|
+
printInfo(`Inherited from the main worktree: ${config2.path}`);
|
|
18199
|
+
}
|
|
18008
18200
|
process.stdout.write((current.length ? current.join(",") : "none") + "\n");
|
|
18009
18201
|
return;
|
|
18010
18202
|
}
|
|
@@ -18013,7 +18205,7 @@ function registerConfigCommands(program2) {
|
|
|
18013
18205
|
printError(`Unrecognised moments: ${moments}. Use "commit", "push", "commit,push", or "none".`);
|
|
18014
18206
|
process.exit(1);
|
|
18015
18207
|
}
|
|
18016
|
-
writeProjectConfig({ git_moments: next });
|
|
18208
|
+
writeProjectConfig({ git_moments: next, git_moments_source: "user" });
|
|
18017
18209
|
printInfo(
|
|
18018
18210
|
next.length ? `Git-moment review enabled for: ${next.join(", ")}` : "Git-moment review disabled \u2014 commits and pushes are no longer gated."
|
|
18019
18211
|
);
|
|
@@ -18474,8 +18666,14 @@ function timeAgo(isoDate) {
|
|
|
18474
18666
|
return `${days}d ago`;
|
|
18475
18667
|
}
|
|
18476
18668
|
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) => {
|
|
18669
|
+
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
18670
|
const globals = program2.opts();
|
|
18671
|
+
const rawLimit = String(opts.limit).trim();
|
|
18672
|
+
const limit = /^\d{1,3}$/.test(rawLimit) ? Number(rawLimit) : Number.NaN;
|
|
18673
|
+
if (!Number.isInteger(limit) || limit < 1 || limit > 100) {
|
|
18674
|
+
printError(`--limit must be a whole number between 1 and 100 (got "${opts.limit}").`);
|
|
18675
|
+
process.exit(1);
|
|
18676
|
+
}
|
|
18479
18677
|
const tokenResult = await resolveToken(globals.token);
|
|
18480
18678
|
if (!tokenResult.ok) {
|
|
18481
18679
|
printError(tokenResult.error);
|
|
@@ -18513,7 +18711,7 @@ function registerStatusCommand(program2) {
|
|
|
18513
18711
|
if (opts.history && !denial) {
|
|
18514
18712
|
const runsResult = await apiRequest({
|
|
18515
18713
|
method: "GET",
|
|
18516
|
-
path: `/runs?limit=${
|
|
18714
|
+
path: `/runs?limit=${limit}`,
|
|
18517
18715
|
serviceUrl,
|
|
18518
18716
|
token,
|
|
18519
18717
|
verbose: globals.verbose
|
|
@@ -18553,12 +18751,14 @@ function registerStatusCommand(program2) {
|
|
|
18553
18751
|
printInfo(`Standard: v${s.version} (${s.quality_dimensions} quality, ${s.security_patterns} security, ${s.custom_patterns} custom)`);
|
|
18554
18752
|
printInfo(`Languages: ${s.languages.join(", ")}`);
|
|
18555
18753
|
}
|
|
18556
|
-
const
|
|
18754
|
+
const wiring = await resolveHookWiring();
|
|
18755
|
+
const hookStatus = wiring.status;
|
|
18557
18756
|
const moments = [];
|
|
18558
18757
|
if (hookStatus.stop) moments.push("stop");
|
|
18559
18758
|
if (hookStatus.guardOn.includes("commit")) moments.push("pre-commit");
|
|
18560
18759
|
if (hookStatus.guardOn.includes("push")) moments.push("pre-push/PR");
|
|
18561
|
-
|
|
18760
|
+
const via = wiring.source === "plugin" ? " (wired by the Verity plugin)" : "";
|
|
18761
|
+
printInfo(`Moments: ${moments.length > 0 ? `${moments.join(", ")}${via}` : 'none (run "verity init")'}`);
|
|
18562
18762
|
if (!mem) return;
|
|
18563
18763
|
if (mem.recent_runs) {
|
|
18564
18764
|
const r = mem.recent_runs;
|
|
@@ -18635,7 +18835,7 @@ function registerStatusCommand(program2) {
|
|
|
18635
18835
|
if (opts.history) {
|
|
18636
18836
|
const runsResult = await apiRequest({
|
|
18637
18837
|
method: "GET",
|
|
18638
|
-
path: `/runs?limit=${
|
|
18838
|
+
path: `/runs?limit=${limit}`,
|
|
18639
18839
|
serviceUrl,
|
|
18640
18840
|
token,
|
|
18641
18841
|
verbose: globals.verbose
|
|
@@ -18826,11 +19026,11 @@ var import_node_fs43 = require("node:fs");
|
|
|
18826
19026
|
|
|
18827
19027
|
// src/lib/repo-context.ts
|
|
18828
19028
|
var import_node_child_process9 = require("node:child_process");
|
|
18829
|
-
var
|
|
19029
|
+
var import_node_os4 = require("node:os");
|
|
18830
19030
|
function rgInvocations(env = process.env) {
|
|
18831
19031
|
const out = [{ cmd: "rg" }];
|
|
18832
19032
|
if (env.CLAUDE_CODE_EXECPATH) out.push({ cmd: env.CLAUDE_CODE_EXECPATH, argv0: "rg" });
|
|
18833
|
-
out.push({ cmd: `${(0,
|
|
19033
|
+
out.push({ cmd: `${(0, import_node_os4.homedir)()}/.local/bin/claude`, argv0: "rg" });
|
|
18834
19034
|
return out;
|
|
18835
19035
|
}
|
|
18836
19036
|
var MAX_SYMBOLS = 12;
|
|
@@ -19644,9 +19844,9 @@ function installRunEvidence(run2) {
|
|
|
19644
19844
|
// src/lib/git-frame.ts
|
|
19645
19845
|
var import_node_child_process10 = require("node:child_process");
|
|
19646
19846
|
var import_node_fs31 = require("node:fs");
|
|
19647
|
-
var
|
|
19648
|
-
var
|
|
19649
|
-
var
|
|
19847
|
+
var import_node_os5 = require("node:os");
|
|
19848
|
+
var import_node_path23 = require("node:path");
|
|
19849
|
+
var import_node_path24 = require("node:path");
|
|
19650
19850
|
var VALUE_TOKEN = `(?:'[^']*'|"[^"]*"|\\S+)`;
|
|
19651
19851
|
var GIT_GLOBAL_OPTS = `(?:\\s+(?:-[Cc]\\s+${VALUE_TOKEN}|--?[\\w-]+(?:=\\S+)?))*`;
|
|
19652
19852
|
var COMMIT_HEAD = `git${GIT_GLOBAL_OPTS}\\s+commit(?![\\w-])`;
|
|
@@ -19692,15 +19892,15 @@ function extractCommandTarget(command, segmentIndex, baseDir) {
|
|
|
19692
19892
|
if (!m) continue;
|
|
19693
19893
|
named = true;
|
|
19694
19894
|
if (m[1] === void 0) {
|
|
19695
|
-
dir = (0,
|
|
19895
|
+
dir = (0, import_node_os5.homedir)();
|
|
19696
19896
|
continue;
|
|
19697
19897
|
}
|
|
19698
19898
|
const raw = unquote(m[1]);
|
|
19699
19899
|
if (SHELL_DYNAMIC.test(raw) || raw === "-") {
|
|
19700
19900
|
return { dir: null, named: true, unresolvable: `cd target not statically resolvable: ${raw}` };
|
|
19701
19901
|
}
|
|
19702
|
-
const expanded = raw === "~" ? (0,
|
|
19703
|
-
dir = (0,
|
|
19902
|
+
const expanded = raw === "~" ? (0, import_node_os5.homedir)() : raw.startsWith("~/") ? (0, import_node_path24.join)((0, import_node_os5.homedir)(), raw.slice(2)) : raw;
|
|
19903
|
+
dir = (0, import_node_path23.isAbsolute)(expanded) ? expanded : (0, import_node_path23.resolve)(dir, expanded);
|
|
19704
19904
|
}
|
|
19705
19905
|
const seg = segments[segmentIndex];
|
|
19706
19906
|
const overrideMatch = /--(?:git-dir|work-tree)(?:=|\s)|\bGIT_(?:DIR|WORK_TREE|INDEX_FILE)=/.exec(seg);
|
|
@@ -19718,8 +19918,8 @@ function extractCommandTarget(command, segmentIndex, baseDir) {
|
|
|
19718
19918
|
if (SHELL_DYNAMIC.test(raw)) {
|
|
19719
19919
|
return { dir: null, named: true, unresolvable: `-C target not statically resolvable: ${raw}` };
|
|
19720
19920
|
}
|
|
19721
|
-
const expanded = raw === "~" ? (0,
|
|
19722
|
-
dir = (0,
|
|
19921
|
+
const expanded = raw === "~" ? (0, import_node_os5.homedir)() : raw.startsWith("~/") ? (0, import_node_path24.join)((0, import_node_os5.homedir)(), raw.slice(2)) : raw;
|
|
19922
|
+
dir = (0, import_node_path23.isAbsolute)(expanded) ? expanded : (0, import_node_path23.resolve)(dir, expanded);
|
|
19723
19923
|
}
|
|
19724
19924
|
}
|
|
19725
19925
|
return { dir, named, unresolvable: null };
|
|
@@ -19780,11 +19980,11 @@ function gitAt(dir, args) {
|
|
|
19780
19980
|
return "";
|
|
19781
19981
|
}
|
|
19782
19982
|
}
|
|
19783
|
-
function
|
|
19983
|
+
function realpathOr2(p) {
|
|
19784
19984
|
try {
|
|
19785
19985
|
return import_node_fs31.realpathSync.native(p);
|
|
19786
19986
|
} catch {
|
|
19787
|
-
return (0,
|
|
19987
|
+
return (0, import_node_path23.resolve)(p);
|
|
19788
19988
|
}
|
|
19789
19989
|
}
|
|
19790
19990
|
function resolveFrame(input) {
|
|
@@ -19822,13 +20022,13 @@ function resolveFrame(input) {
|
|
|
19822
20022
|
}
|
|
19823
20023
|
const gitDirRaw = gitAt(dir, ["rev-parse", "--absolute-git-dir"]);
|
|
19824
20024
|
const commonRaw = gitAt(dir, ["rev-parse", "--git-common-dir"]);
|
|
19825
|
-
const gitDir = gitDirRaw ?
|
|
19826
|
-
const commonDir = commonRaw ?
|
|
20025
|
+
const gitDir = gitDirRaw ? realpathOr2(gitDirRaw) : null;
|
|
20026
|
+
const commonDir = commonRaw ? realpathOr2((0, import_node_path23.isAbsolute)(commonRaw) ? commonRaw : (0, import_node_path23.resolve)(dir, commonRaw)) : null;
|
|
19827
20027
|
const branchRaw = gitAt(dir, ["rev-parse", "--abbrev-ref", "HEAD"]);
|
|
19828
20028
|
return {
|
|
19829
20029
|
moment: found?.moment ?? null,
|
|
19830
20030
|
frame: {
|
|
19831
|
-
worktreeRoot:
|
|
20031
|
+
worktreeRoot: realpathOr2(toplevel),
|
|
19832
20032
|
gitDir,
|
|
19833
20033
|
commonDir,
|
|
19834
20034
|
// The one honest definition: a linked worktree's own git dir differs from
|
|
@@ -19848,14 +20048,172 @@ function refResolves(frame, ref) {
|
|
|
19848
20048
|
return frameGit(frame, ["rev-parse", "--verify", "-q", `${ref}^{commit}`]) !== "";
|
|
19849
20049
|
}
|
|
19850
20050
|
var SHA_RE2 = /^[0-9a-f]{40}$/;
|
|
19851
|
-
function
|
|
20051
|
+
function shellWords(segment) {
|
|
20052
|
+
return segment.match(/'[^']*'|"[^"]*"|\S+/g) ?? [];
|
|
20053
|
+
}
|
|
20054
|
+
var ADD_FLAGS_REPLAYABLE = /* @__PURE__ */ new Set([
|
|
20055
|
+
"-A",
|
|
20056
|
+
"--all",
|
|
20057
|
+
"--no-ignore-removal",
|
|
20058
|
+
"-u",
|
|
20059
|
+
"--update",
|
|
20060
|
+
"--no-all",
|
|
20061
|
+
"--ignore-removal",
|
|
20062
|
+
"-f",
|
|
20063
|
+
"--force",
|
|
20064
|
+
"-v",
|
|
20065
|
+
"--verbose",
|
|
20066
|
+
"-N",
|
|
20067
|
+
"--intent-to-add",
|
|
20068
|
+
"--renormalize",
|
|
20069
|
+
"--sparse",
|
|
20070
|
+
"--ignore-errors",
|
|
20071
|
+
"--refresh"
|
|
20072
|
+
]);
|
|
20073
|
+
var ADD_FLAGS_INTERACTIVE = /* @__PURE__ */ new Set(["-i", "--interactive", "-p", "--patch", "-e", "--edit"]);
|
|
20074
|
+
var PATHSPEC_UNRESOLVABLE = /[$`\\*?[\]{}~]/;
|
|
20075
|
+
var COMMIT_VALUE_OPTS = /* @__PURE__ */ new Set([
|
|
20076
|
+
"-m",
|
|
20077
|
+
"--message",
|
|
20078
|
+
"-F",
|
|
20079
|
+
"--file",
|
|
20080
|
+
"-C",
|
|
20081
|
+
"--reuse-message",
|
|
20082
|
+
"-c",
|
|
20083
|
+
"--reedit-message",
|
|
20084
|
+
"--author",
|
|
20085
|
+
"--date",
|
|
20086
|
+
"-t",
|
|
20087
|
+
"--template",
|
|
20088
|
+
"--fixup",
|
|
20089
|
+
"--squash",
|
|
20090
|
+
"--trailer",
|
|
20091
|
+
"--cleanup"
|
|
20092
|
+
]);
|
|
20093
|
+
var ADD_HEAD = `git${GIT_GLOBAL_OPTS}\\s+add(?![\\w-])`;
|
|
20094
|
+
var ADD_RE = new RegExp(`(?:^|[\\s;&|(])${ADD_HEAD}|(?:^|[;&|(])\\s*[^\\s;&|()'"]*\\/${ADD_HEAD}`);
|
|
20095
|
+
function pathspecOf(word) {
|
|
20096
|
+
const raw = unquote(word);
|
|
20097
|
+
if (!raw) return { reason: "an empty pathspec" };
|
|
20098
|
+
if (PATHSPEC_UNRESOLVABLE.test(raw)) {
|
|
20099
|
+
return { reason: `the shell rewrites the pathspec "${raw}" before git sees it` };
|
|
20100
|
+
}
|
|
20101
|
+
return { path: raw };
|
|
20102
|
+
}
|
|
20103
|
+
function parseAddSegment(segment) {
|
|
20104
|
+
const words = shellWords(segment);
|
|
20105
|
+
const at = words.indexOf("add");
|
|
20106
|
+
if (at === -1) return { reason: 'the "git add" arguments could not be read' };
|
|
20107
|
+
const flags = [];
|
|
20108
|
+
const paths = [];
|
|
20109
|
+
let literal = false;
|
|
20110
|
+
for (const word of words.slice(at + 1)) {
|
|
20111
|
+
if (literal || !word.startsWith("-") || word === "-") {
|
|
20112
|
+
if (word === "--" && !literal) {
|
|
20113
|
+
literal = true;
|
|
20114
|
+
continue;
|
|
20115
|
+
}
|
|
20116
|
+
const p = pathspecOf(word);
|
|
20117
|
+
if ("reason" in p) return p;
|
|
20118
|
+
paths.push(p.path);
|
|
20119
|
+
continue;
|
|
20120
|
+
}
|
|
20121
|
+
if (word === "--") {
|
|
20122
|
+
literal = true;
|
|
20123
|
+
continue;
|
|
20124
|
+
}
|
|
20125
|
+
const parts = /^-[A-Za-z]{2,}$/.test(word) ? [...word.slice(1)].map((c) => `-${c}`) : [word];
|
|
20126
|
+
for (const flag of parts) {
|
|
20127
|
+
if (ADD_FLAGS_INTERACTIVE.has(flag)) {
|
|
20128
|
+
return { reason: `"git add ${flag}" stages what a human picks at a prompt` };
|
|
20129
|
+
}
|
|
20130
|
+
if (!ADD_FLAGS_REPLAYABLE.has(flag.split("=")[0])) {
|
|
20131
|
+
return { reason: `unmodelled "git add" option ${flag}` };
|
|
20132
|
+
}
|
|
20133
|
+
flags.push(flag);
|
|
20134
|
+
}
|
|
20135
|
+
}
|
|
20136
|
+
return { flags, paths };
|
|
20137
|
+
}
|
|
20138
|
+
function commitStagesTrackedChanges(segment) {
|
|
20139
|
+
const words = shellWords(segment);
|
|
20140
|
+
const at = words.indexOf("commit");
|
|
20141
|
+
if (at === -1) return false;
|
|
20142
|
+
let skipValue = false;
|
|
20143
|
+
for (const word of words.slice(at + 1)) {
|
|
20144
|
+
if (skipValue) {
|
|
20145
|
+
skipValue = false;
|
|
20146
|
+
continue;
|
|
20147
|
+
}
|
|
20148
|
+
if (word === "--") break;
|
|
20149
|
+
if (!word.startsWith("-") || word === "-") continue;
|
|
20150
|
+
if (word.startsWith("--")) {
|
|
20151
|
+
const name = word.split("=")[0];
|
|
20152
|
+
if (name === "--all") return true;
|
|
20153
|
+
if (COMMIT_VALUE_OPTS.has(name) && !word.includes("=")) skipValue = true;
|
|
20154
|
+
continue;
|
|
20155
|
+
}
|
|
20156
|
+
for (let i = 1; i < word.length; i++) {
|
|
20157
|
+
const flag = `-${word[i]}`;
|
|
20158
|
+
if (flag === "-a") return true;
|
|
20159
|
+
if (COMMIT_VALUE_OPTS.has(flag)) {
|
|
20160
|
+
if (i === word.length - 1) skipValue = true;
|
|
20161
|
+
break;
|
|
20162
|
+
}
|
|
20163
|
+
}
|
|
20164
|
+
}
|
|
20165
|
+
return false;
|
|
20166
|
+
}
|
|
20167
|
+
function planInCommandStaging(frame, command) {
|
|
20168
|
+
const found = findMomentSegment(command, ["commit"]);
|
|
20169
|
+
if (!found) return { kind: "none" };
|
|
20170
|
+
const segments = splitSegments(command);
|
|
20171
|
+
if (commitStagesTrackedChanges(segments[found.segmentIndex])) {
|
|
20172
|
+
return {
|
|
20173
|
+
kind: "files",
|
|
20174
|
+
via: "index+commit-a",
|
|
20175
|
+
files: frameGit(frame, ["diff", "--name-only", "HEAD"]).split("\n").filter(Boolean)
|
|
20176
|
+
};
|
|
20177
|
+
}
|
|
20178
|
+
const addSegments = segments.slice(0, found.segmentIndex).filter((s) => ADD_RE.test(s));
|
|
20179
|
+
if (addSegments.length === 0) return { kind: "none" };
|
|
20180
|
+
const staged = new Set(
|
|
20181
|
+
frameGit(frame, ["diff", "--cached", "--name-only"]).split("\n").filter(Boolean)
|
|
20182
|
+
);
|
|
20183
|
+
for (const segment of addSegments) {
|
|
20184
|
+
const parsed = parseAddSegment(segment);
|
|
20185
|
+
if ("reason" in parsed) return { kind: "unpredictable", reason: parsed.reason };
|
|
20186
|
+
const args = ["add", "--dry-run", "--ignore-missing", ...parsed.flags];
|
|
20187
|
+
if (parsed.paths.length > 0) args.push("--", ...parsed.paths);
|
|
20188
|
+
for (const line of frameGit(frame, args).split("\n")) {
|
|
20189
|
+
const m = line.match(/^(?:add|remove) '(.*)'$/);
|
|
20190
|
+
if (m) staged.add(m[1]);
|
|
20191
|
+
}
|
|
20192
|
+
}
|
|
20193
|
+
return { kind: "files", via: "index+staged-in-command", files: [...staged] };
|
|
20194
|
+
}
|
|
20195
|
+
function stagedRange(frame, command) {
|
|
19852
20196
|
if (!frame.worktreeRoot) return { kind: "nothing", base: null, head: "INDEX", via: "refused" };
|
|
19853
|
-
const
|
|
20197
|
+
const plan = command ? planInCommandStaging(frame, command) : { kind: "none" };
|
|
20198
|
+
if (plan.kind === "unpredictable") {
|
|
20199
|
+
return { kind: "staged", base: "HEAD", head: "INDEX", via: "staged-in-command", refusal: plan.reason };
|
|
20200
|
+
}
|
|
20201
|
+
const mergeHead = frame.gitDir ? (0, import_node_path24.join)(frame.gitDir, "MERGE_HEAD") : null;
|
|
19854
20202
|
if (mergeHead && (0, import_node_fs31.existsSync)(mergeHead)) {
|
|
19855
20203
|
const vsHead = new Set(frameGit(frame, ["diff", "--cached", "--name-only", "HEAD"]).split("\n").filter(Boolean));
|
|
19856
20204
|
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
|
-
|
|
20205
|
+
const resolutions = new Set([...vsHead].filter((f) => vsMerge.has(f) && !isVerityOwnedPath(f)));
|
|
20206
|
+
if (plan.kind === "files") {
|
|
20207
|
+
const wtVsHead = new Set(frameGit(frame, ["diff", "--name-only", "HEAD"]).split("\n").filter(Boolean));
|
|
20208
|
+
const wtVsMerge = new Set(frameGit(frame, ["diff", "--name-only", "MERGE_HEAD"]).split("\n").filter(Boolean));
|
|
20209
|
+
for (const f of plan.files) {
|
|
20210
|
+
if (wtVsHead.has(f) && wtVsMerge.has(f) && !isVerityOwnedPath(f)) resolutions.add(f);
|
|
20211
|
+
}
|
|
20212
|
+
}
|
|
20213
|
+
return { kind: "merge", base: "HEAD", head: "INDEX", via: "merge-resolutions", files: [...resolutions] };
|
|
20214
|
+
}
|
|
20215
|
+
if (plan.kind === "files") {
|
|
20216
|
+
return { kind: "staged", base: "HEAD", head: "INDEX", via: plan.via, files: plan.files };
|
|
19859
20217
|
}
|
|
19860
20218
|
return { kind: "staged", base: "HEAD", head: "INDEX", via: "index" };
|
|
19861
20219
|
}
|
|
@@ -19937,7 +20295,7 @@ function frameTelemetry(frame, range, divergence) {
|
|
|
19937
20295
|
refusal: frame.refusal
|
|
19938
20296
|
};
|
|
19939
20297
|
if (divergence) {
|
|
19940
|
-
t.root_differs = !!frame.worktreeRoot && !!divergence.actualRoot &&
|
|
20298
|
+
t.root_differs = !!frame.worktreeRoot && !!divergence.actualRoot && realpathOr2(frame.worktreeRoot) !== realpathOr2(divergence.actualRoot);
|
|
19941
20299
|
const a = [...divergence.actualFiles].sort().join("\n");
|
|
19942
20300
|
const b = [...divergence.frameFiles].sort().join("\n");
|
|
19943
20301
|
t.files_differ = a !== b;
|
|
@@ -20247,7 +20605,7 @@ function sanitizeCommandWithLoss(rawCmd) {
|
|
|
20247
20605
|
const lost = lines.slice(1).some((l) => l.trim().length > 0);
|
|
20248
20606
|
const first = lines[0];
|
|
20249
20607
|
const cmd = sanitizeCommand(first);
|
|
20250
|
-
const hadSeparator = SEPARATORS.some((
|
|
20608
|
+
const hadSeparator = SEPARATORS.some((sep3) => first.indexOf(sep3) > 0);
|
|
20251
20609
|
return { cmd, lost: lost || !hadSeparator && first.length > MAX_COMMAND_CHARS };
|
|
20252
20610
|
}
|
|
20253
20611
|
var SEPARATORS = [" | ", " > ", " >> ", " 2>", " && ", " ; "];
|
|
@@ -20256,11 +20614,11 @@ function sanitizeCommand(rawCmd) {
|
|
|
20256
20614
|
let cmd = rawCmd.split("\n")[0];
|
|
20257
20615
|
let cut = -1;
|
|
20258
20616
|
let marker = "";
|
|
20259
|
-
for (const
|
|
20260
|
-
const idx = cmd.indexOf(
|
|
20617
|
+
for (const sep3 of SEPARATORS) {
|
|
20618
|
+
const idx = cmd.indexOf(sep3);
|
|
20261
20619
|
if (idx > 0 && (cut === -1 || idx < cut)) {
|
|
20262
20620
|
cut = idx;
|
|
20263
|
-
marker =
|
|
20621
|
+
marker = sep3.trim();
|
|
20264
20622
|
}
|
|
20265
20623
|
}
|
|
20266
20624
|
if (cut > -1) cmd = cmd.slice(0, cut);
|
|
@@ -20284,28 +20642,28 @@ async function readStopHookStdin() {
|
|
|
20284
20642
|
try {
|
|
20285
20643
|
if (process.stdin.isTTY) return empty;
|
|
20286
20644
|
const chunks = [];
|
|
20287
|
-
const timeout = new Promise((
|
|
20288
|
-
const read = new Promise((
|
|
20645
|
+
const timeout = new Promise((resolve5) => setTimeout(() => resolve5(empty), 500));
|
|
20646
|
+
const read = new Promise((resolve5) => {
|
|
20289
20647
|
process.stdin.on("data", (chunk) => chunks.push(chunk));
|
|
20290
20648
|
process.stdin.on("end", () => {
|
|
20291
20649
|
const raw = Buffer.concat(chunks).toString("utf-8").trim();
|
|
20292
20650
|
if (!raw) {
|
|
20293
|
-
|
|
20651
|
+
resolve5(empty);
|
|
20294
20652
|
return;
|
|
20295
20653
|
}
|
|
20296
20654
|
try {
|
|
20297
20655
|
const data = JSON.parse(raw);
|
|
20298
|
-
|
|
20656
|
+
resolve5({
|
|
20299
20657
|
assistantMessage: typeof data.last_assistant_message === "string" ? data.last_assistant_message : null,
|
|
20300
20658
|
stopReason: typeof data.stop_reason === "string" ? data.stop_reason : null,
|
|
20301
20659
|
transcriptPath: typeof data.transcript_path === "string" ? data.transcript_path : null,
|
|
20302
20660
|
sessionId: typeof data.session_id === "string" ? data.session_id : null
|
|
20303
20661
|
});
|
|
20304
20662
|
} catch {
|
|
20305
|
-
|
|
20663
|
+
resolve5(empty);
|
|
20306
20664
|
}
|
|
20307
20665
|
});
|
|
20308
|
-
process.stdin.on("error", () =>
|
|
20666
|
+
process.stdin.on("error", () => resolve5(empty));
|
|
20309
20667
|
process.stdin.resume();
|
|
20310
20668
|
});
|
|
20311
20669
|
return await Promise.race([read, timeout]);
|
|
@@ -20509,7 +20867,7 @@ function channelSilence(input) {
|
|
|
20509
20867
|
// src/lib/cli-version.ts
|
|
20510
20868
|
function cliVersion() {
|
|
20511
20869
|
try {
|
|
20512
|
-
return true ? "0.32.
|
|
20870
|
+
return true ? "0.32.1-experimental.f2cf829" : "dev";
|
|
20513
20871
|
} catch {
|
|
20514
20872
|
return "dev";
|
|
20515
20873
|
}
|
|
@@ -20868,7 +21226,7 @@ async function scope(run2) {
|
|
|
20868
21226
|
|
|
20869
21227
|
// src/lib/specs.ts
|
|
20870
21228
|
var import_node_fs34 = require("node:fs");
|
|
20871
|
-
var
|
|
21229
|
+
var import_node_path25 = require("node:path");
|
|
20872
21230
|
var SPEC_CANDIDATES = [
|
|
20873
21231
|
"CLAUDE.md",
|
|
20874
21232
|
"AGENTS.md",
|
|
@@ -20941,7 +21299,7 @@ function findMdFiles(dir, maxDepth, depth = 0) {
|
|
|
20941
21299
|
try {
|
|
20942
21300
|
const entries = (0, import_node_fs34.readdirSync)(dir, { withFileTypes: true });
|
|
20943
21301
|
for (const entry of entries) {
|
|
20944
|
-
const fullPath = (0,
|
|
21302
|
+
const fullPath = (0, import_node_path25.join)(dir, entry.name);
|
|
20945
21303
|
if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
20946
21304
|
result.push(fullPath);
|
|
20947
21305
|
} else if (entry.isDirectory() && depth < maxDepth - 1) {
|
|
@@ -20953,9 +21311,9 @@ function findMdFiles(dir, maxDepth, depth = 0) {
|
|
|
20953
21311
|
return result;
|
|
20954
21312
|
}
|
|
20955
21313
|
function discoverPlans() {
|
|
20956
|
-
const homePlansDir = (0,
|
|
21314
|
+
const homePlansDir = (0, import_node_path25.join)(process.env.HOME ?? "", ".claude", "plans");
|
|
20957
21315
|
const localPlansDir = ".claude/plans";
|
|
20958
|
-
const
|
|
21316
|
+
const candidates2 = [];
|
|
20959
21317
|
const seen = /* @__PURE__ */ new Set();
|
|
20960
21318
|
for (const plansDir of [localPlansDir, homePlansDir]) {
|
|
20961
21319
|
if (!(0, import_node_fs34.existsSync)(plansDir)) continue;
|
|
@@ -20963,19 +21321,19 @@ function discoverPlans() {
|
|
|
20963
21321
|
for (const f of (0, import_node_fs34.readdirSync)(plansDir)) {
|
|
20964
21322
|
if (!f.endsWith(".md") || seen.has(f)) continue;
|
|
20965
21323
|
seen.add(f);
|
|
20966
|
-
const fullPath = (0,
|
|
21324
|
+
const fullPath = (0, import_node_path25.join)(plansDir, f);
|
|
20967
21325
|
try {
|
|
20968
21326
|
const stat3 = (0, import_node_fs34.statSync)(fullPath);
|
|
20969
|
-
|
|
21327
|
+
candidates2.push({ name: f, path: fullPath, mtime: stat3.mtimeMs, size: stat3.size });
|
|
20970
21328
|
} catch {
|
|
20971
21329
|
}
|
|
20972
21330
|
}
|
|
20973
21331
|
} catch {
|
|
20974
21332
|
}
|
|
20975
21333
|
}
|
|
20976
|
-
|
|
21334
|
+
candidates2.sort((a, b) => b.mtime - a.mtime);
|
|
20977
21335
|
const result = [];
|
|
20978
|
-
for (const entry of
|
|
21336
|
+
for (const entry of candidates2.slice(0, MAX_PLAN_FILES)) {
|
|
20979
21337
|
if (entry.size > MAX_PLAN_FILE_BYTES) continue;
|
|
20980
21338
|
try {
|
|
20981
21339
|
const content = (0, import_node_fs34.readFileSync)(entry.path, "utf-8");
|
|
@@ -21175,7 +21533,7 @@ async function mode(run2) {
|
|
|
21175
21533
|
|
|
21176
21534
|
// src/lib/fold.ts
|
|
21177
21535
|
var import_node_fs35 = require("node:fs");
|
|
21178
|
-
var
|
|
21536
|
+
var import_node_path26 = require("node:path");
|
|
21179
21537
|
var KNOWN_RECORD_TYPES = /* @__PURE__ */ new Set([
|
|
21180
21538
|
"user",
|
|
21181
21539
|
"assistant",
|
|
@@ -21407,9 +21765,9 @@ function fold(transcriptPath, opts = {}) {
|
|
|
21407
21765
|
return result;
|
|
21408
21766
|
}
|
|
21409
21767
|
try {
|
|
21410
|
-
const sidecarDir = (0,
|
|
21411
|
-
(0,
|
|
21412
|
-
(0,
|
|
21768
|
+
const sidecarDir = (0, import_node_path26.join)(
|
|
21769
|
+
(0, import_node_path26.dirname)(transcriptPath),
|
|
21770
|
+
(0, import_node_path26.basename)(transcriptPath).replace(/\.jsonl$/, ""),
|
|
21413
21771
|
"subagents"
|
|
21414
21772
|
);
|
|
21415
21773
|
if ((0, import_node_fs35.existsSync)(sidecarDir)) {
|
|
@@ -21419,7 +21777,7 @@ function fold(transcriptPath, opts = {}) {
|
|
|
21419
21777
|
const walk2 = (d, depth) => {
|
|
21420
21778
|
if (depth > 4) return;
|
|
21421
21779
|
for (const e of (0, import_node_fs35.readdirSync)(d, { withFileTypes: true })) {
|
|
21422
|
-
const p = (0,
|
|
21780
|
+
const p = (0, import_node_path26.join)(d, e.name);
|
|
21423
21781
|
if (e.isDirectory()) {
|
|
21424
21782
|
walk2(p, depth + 1);
|
|
21425
21783
|
} else if (e.name.startsWith("agent-") && e.name.endsWith(".jsonl")) {
|
|
@@ -21794,7 +22152,7 @@ async function evidence(run2) {
|
|
|
21794
22152
|
|
|
21795
22153
|
// src/lib/cache-cleanup.ts
|
|
21796
22154
|
var import_node_fs36 = require("node:fs");
|
|
21797
|
-
var
|
|
22155
|
+
var import_node_path27 = require("node:path");
|
|
21798
22156
|
var CACHE_TTL_DAYS = 7;
|
|
21799
22157
|
function pruneStaleCache() {
|
|
21800
22158
|
try {
|
|
@@ -21802,7 +22160,7 @@ function pruneStaleCache() {
|
|
|
21802
22160
|
const cutoff = Date.now() - CACHE_TTL_DAYS * 24 * 3600 * 1e3;
|
|
21803
22161
|
for (const entry of (0, import_node_fs36.readdirSync)(dir)) {
|
|
21804
22162
|
if (!entry.startsWith("pending-")) continue;
|
|
21805
|
-
const path = (0,
|
|
22163
|
+
const path = (0, import_node_path27.join)(dir, entry);
|
|
21806
22164
|
try {
|
|
21807
22165
|
const stat3 = (0, import_node_fs36.statSync)(path);
|
|
21808
22166
|
if (stat3.mtimeMs < cutoff) {
|
|
@@ -21821,7 +22179,7 @@ function pruneStaleCache() {
|
|
|
21821
22179
|
|
|
21822
22180
|
// src/lib/context-files.ts
|
|
21823
22181
|
var import_node_fs37 = require("node:fs");
|
|
21824
|
-
var
|
|
22182
|
+
var import_node_os6 = require("node:os");
|
|
21825
22183
|
var MAX_CONTEXT_FILES = 10;
|
|
21826
22184
|
var MAX_CONTEXT_FILE_BYTES = 10240;
|
|
21827
22185
|
var MAX_CONTEXT_TOTAL_BYTES = 24576;
|
|
@@ -21829,7 +22187,7 @@ function readSetContextPaths(summary, deltaFiles) {
|
|
|
21829
22187
|
const reads = summary?.files_read ?? [];
|
|
21830
22188
|
if (reads.length === 0) return [];
|
|
21831
22189
|
const root = process.cwd().replace(/\/+$/, "");
|
|
21832
|
-
const home = (0,
|
|
22190
|
+
const home = (0, import_node_os6.homedir)();
|
|
21833
22191
|
const toRepoRelative2 = (p) => {
|
|
21834
22192
|
if (!p) return null;
|
|
21835
22193
|
let abs;
|
|
@@ -21970,7 +22328,7 @@ async function repoContext(run2) {
|
|
|
21970
22328
|
// src/lib/seed-runner.ts
|
|
21971
22329
|
var import_promises14 = require("node:fs/promises");
|
|
21972
22330
|
var import_node_fs38 = require("node:fs");
|
|
21973
|
-
var
|
|
22331
|
+
var import_node_path28 = require("node:path");
|
|
21974
22332
|
var import_yaml4 = __toESM(require_dist());
|
|
21975
22333
|
|
|
21976
22334
|
// src/lib/seed.ts
|
|
@@ -22237,7 +22595,7 @@ async function runSeed(opts) {
|
|
|
22237
22595
|
}
|
|
22238
22596
|
}
|
|
22239
22597
|
}
|
|
22240
|
-
const
|
|
22598
|
+
const candidates2 = deriveSeedNodes({
|
|
22241
22599
|
knowledgeSpec: {
|
|
22242
22600
|
project_name: knowledgeSpec.project_name,
|
|
22243
22601
|
languages: knowledgeSpec.languages,
|
|
@@ -22249,20 +22607,20 @@ async function runSeed(opts) {
|
|
|
22249
22607
|
readmeContent,
|
|
22250
22608
|
claudeMdContent
|
|
22251
22609
|
});
|
|
22252
|
-
if (
|
|
22610
|
+
if (candidates2.length === 0) {
|
|
22253
22611
|
return { created: 0, failed: 0, skipped: "no_candidates", candidates: [] };
|
|
22254
22612
|
}
|
|
22255
|
-
const overviewPath = (0,
|
|
22613
|
+
const overviewPath = (0, import_node_path28.join)(MEMORY_DIR, "domain", "project-overview.md");
|
|
22256
22614
|
if ((0, import_node_fs38.existsSync)(overviewPath) && !opts.force) {
|
|
22257
|
-
return { created: 0, failed: 0, skipped: "already_seeded", candidates };
|
|
22615
|
+
return { created: 0, failed: 0, skipped: "already_seeded", candidates: candidates2 };
|
|
22258
22616
|
}
|
|
22259
22617
|
if (opts.dryRun) {
|
|
22260
|
-
return { created: 0, failed: 0, skipped: null, candidates };
|
|
22618
|
+
return { created: 0, failed: 0, skipped: null, candidates: candidates2 };
|
|
22261
22619
|
}
|
|
22262
22620
|
const createdAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
22263
22621
|
let created = 0;
|
|
22264
22622
|
let failed = 0;
|
|
22265
|
-
for (const c of
|
|
22623
|
+
for (const c of candidates2) {
|
|
22266
22624
|
const res = await apiRequest({
|
|
22267
22625
|
method: "POST",
|
|
22268
22626
|
path: "/compound/memory/nodes",
|
|
@@ -22295,7 +22653,7 @@ async function runSeed(opts) {
|
|
|
22295
22653
|
continue;
|
|
22296
22654
|
}
|
|
22297
22655
|
try {
|
|
22298
|
-
await (0, import_promises14.mkdir)((0,
|
|
22656
|
+
await (0, import_promises14.mkdir)((0, import_node_path28.dirname)(targetPath), { recursive: true });
|
|
22299
22657
|
await (0, import_promises14.writeFile)(targetPath, renderNodeMarkdown(c, nodeId, createdAt));
|
|
22300
22658
|
created++;
|
|
22301
22659
|
opts.onCreated?.(nodeId, filePathRel, c);
|
|
@@ -22304,12 +22662,12 @@ async function runSeed(opts) {
|
|
|
22304
22662
|
failed++;
|
|
22305
22663
|
}
|
|
22306
22664
|
}
|
|
22307
|
-
return { created, failed, skipped: null, candidates };
|
|
22665
|
+
return { created, failed, skipped: null, candidates: candidates2 };
|
|
22308
22666
|
}
|
|
22309
22667
|
|
|
22310
22668
|
// src/commands/analyze/phases/08-memory-manifest.ts
|
|
22311
22669
|
var import_node_fs39 = require("node:fs");
|
|
22312
|
-
var
|
|
22670
|
+
var import_node_path29 = require("node:path");
|
|
22313
22671
|
async function memoryManifest(run2) {
|
|
22314
22672
|
const { globals } = run2;
|
|
22315
22673
|
const { serviceUrl, token } = run2;
|
|
@@ -22319,7 +22677,7 @@ async function memoryManifest(run2) {
|
|
|
22319
22677
|
let autoSeedNotice = null;
|
|
22320
22678
|
try {
|
|
22321
22679
|
await ensureMemoryDir();
|
|
22322
|
-
const seedMarker = (0,
|
|
22680
|
+
const seedMarker = (0, import_node_path29.join)(VERITY_DIR, ".seeded");
|
|
22323
22681
|
const hasStandard = (0, import_node_fs39.existsSync)(STANDARD_FILE);
|
|
22324
22682
|
const alreadyTried = (0, import_node_fs39.existsSync)(seedMarker);
|
|
22325
22683
|
if (hasStandard && !alreadyTried) {
|
|
@@ -22437,7 +22795,7 @@ function computeIncrement(reviewedPaths, hashOf, priorAuthored) {
|
|
|
22437
22795
|
}
|
|
22438
22796
|
|
|
22439
22797
|
// src/commands/analyze/phases/10-working-memory.ts
|
|
22440
|
-
var
|
|
22798
|
+
var import_node_path30 = require("node:path");
|
|
22441
22799
|
async function workingMemory(run2) {
|
|
22442
22800
|
const { opts } = run2;
|
|
22443
22801
|
const { allForReview, baseline, conversation, foldResult, sessionId, token, transcriptPath } = run2;
|
|
@@ -22449,7 +22807,7 @@ async function workingMemory(run2) {
|
|
|
22449
22807
|
const priorState = foldForMarks(memorySession.d);
|
|
22450
22808
|
incrementReport = computeIncrement(
|
|
22451
22809
|
allForReview,
|
|
22452
|
-
(p) => fileHash((0,
|
|
22810
|
+
(p) => fileHash((0, import_node_path30.join)(repoRoot(), p)),
|
|
22453
22811
|
priorState.authored_all.map((a) => ({
|
|
22454
22812
|
path: a.path,
|
|
22455
22813
|
hash_at_last_verdict: a.hash_at_last_verdict
|
|
@@ -23014,7 +23372,7 @@ async function transmit(run2) {
|
|
|
23014
23372
|
|
|
23015
23373
|
// src/commands/analyze/phases/13-reconcile.ts
|
|
23016
23374
|
var import_node_fs42 = require("node:fs");
|
|
23017
|
-
var
|
|
23375
|
+
var import_node_path31 = require("node:path");
|
|
23018
23376
|
async function reconcile(run2) {
|
|
23019
23377
|
const { actionSummary, allChanged, analyzable, baseline, baselineSessionId, codeDelta, contentHash, conversation, decision, foldResult, memory, memorySession, response, reviewable, securityFiles, turnId } = run2;
|
|
23020
23378
|
const sentPaths = codeDelta.files.map((f) => f.path);
|
|
@@ -23043,7 +23401,7 @@ async function reconcile(run2) {
|
|
|
23043
23401
|
const st = foldDossier(memorySession.d);
|
|
23044
23402
|
openElsewhere = openBlockingElsewhere(st.statements, sentPaths, (file, line) => {
|
|
23045
23403
|
try {
|
|
23046
|
-
const src = (0, import_node_fs42.readFileSync)((0,
|
|
23404
|
+
const src = (0, import_node_fs42.readFileSync)((0, import_node_path31.join)(repoRoot(), file), "utf8").split("\n");
|
|
23047
23405
|
const at = src[line - 1];
|
|
23048
23406
|
return at === void 0 ? null : lineSha(at);
|
|
23049
23407
|
} catch {
|
|
@@ -23895,14 +24253,14 @@ async function runReview(opts, globals) {
|
|
|
23895
24253
|
|
|
23896
24254
|
// src/commands/guard.ts
|
|
23897
24255
|
var import_node_fs45 = require("node:fs");
|
|
23898
|
-
var
|
|
24256
|
+
var import_node_path32 = require("node:path");
|
|
23899
24257
|
var GUARD_BLOCK_CAP = 2;
|
|
23900
|
-
var GUARD_ITER_FILE = (0,
|
|
24258
|
+
var GUARD_ITER_FILE = (0, import_node_path32.join)(VERITY_DIR, ".guard-iteration");
|
|
23901
24259
|
function readPreToolUseStdin() {
|
|
23902
24260
|
const empty = { command: "", cwd: null, sessionId: null };
|
|
23903
|
-
return new Promise((
|
|
24261
|
+
return new Promise((resolve5) => {
|
|
23904
24262
|
try {
|
|
23905
|
-
if (process.stdin.isTTY) return
|
|
24263
|
+
if (process.stdin.isTTY) return resolve5(empty);
|
|
23906
24264
|
const chunks = [];
|
|
23907
24265
|
let timer;
|
|
23908
24266
|
let settled = false;
|
|
@@ -23915,7 +24273,7 @@ function readPreToolUseStdin() {
|
|
|
23915
24273
|
process.stdin.removeListener("end", onEnd);
|
|
23916
24274
|
process.stdin.removeListener("error", onError);
|
|
23917
24275
|
process.stdin.pause();
|
|
23918
|
-
|
|
24276
|
+
resolve5(value);
|
|
23919
24277
|
};
|
|
23920
24278
|
const onEnd = () => {
|
|
23921
24279
|
try {
|
|
@@ -23936,7 +24294,7 @@ function readPreToolUseStdin() {
|
|
|
23936
24294
|
process.stdin.on("error", onError);
|
|
23937
24295
|
process.stdin.resume();
|
|
23938
24296
|
} catch {
|
|
23939
|
-
|
|
24297
|
+
resolve5(empty);
|
|
23940
24298
|
}
|
|
23941
24299
|
});
|
|
23942
24300
|
}
|
|
@@ -23994,7 +24352,7 @@ function registerGuardCommand(program2) {
|
|
|
23994
24352
|
});
|
|
23995
24353
|
}
|
|
23996
24354
|
function resolveMomentRange(moment, frame, command, on) {
|
|
23997
|
-
return moment === "pre-commit" ? stagedRange(frame) : resolvePushRange(frame, command, on);
|
|
24355
|
+
return moment === "pre-commit" ? stagedRange(frame, command) : resolvePushRange(frame, command, on);
|
|
23998
24356
|
}
|
|
23999
24357
|
function describeRange(range) {
|
|
24000
24358
|
if (range.kind === "staged") return "staged";
|
|
@@ -24154,6 +24512,13 @@ async function runGuard(opts, globals) {
|
|
|
24154
24512
|
);
|
|
24155
24513
|
}
|
|
24156
24514
|
const range = resolveMomentRange(moment, frame, command, on);
|
|
24515
|
+
if (range.refusal) {
|
|
24516
|
+
logEvent("guard_frame", { moment, ...frameTelemetry(frame, range) });
|
|
24517
|
+
emitAllowNotice(
|
|
24518
|
+
`\u26A0 Verity ${moment}: could not tell what this ${verb} will include \u2014 ${verb === "commit" ? "committed" : "pushed"} WITHOUT review`,
|
|
24519
|
+
`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.`
|
|
24520
|
+
);
|
|
24521
|
+
}
|
|
24157
24522
|
const files = rangeFiles(frame, range);
|
|
24158
24523
|
if (files.length === 0) process.exit(0);
|
|
24159
24524
|
const tokenResult = await resolveToken(globals.token);
|
|
@@ -24189,7 +24554,7 @@ async function runGuard(opts, globals) {
|
|
|
24189
24554
|
upgradeToExcerpts(repoContext2, {
|
|
24190
24555
|
readFile: (rel) => {
|
|
24191
24556
|
try {
|
|
24192
|
-
return (0, import_node_fs45.readFileSync)((0,
|
|
24557
|
+
return (0, import_node_fs45.readFileSync)((0, import_node_path32.join)(frame.worktreeRoot ?? process.cwd(), rel), "utf8");
|
|
24193
24558
|
} catch {
|
|
24194
24559
|
return null;
|
|
24195
24560
|
}
|
|
@@ -24258,21 +24623,28 @@ async function runGuard(opts, globals) {
|
|
|
24258
24623
|
${covDetail}${viewUrl ? `
|
|
24259
24624
|
Report: ${viewUrl}` : ""}`
|
|
24260
24625
|
);
|
|
24261
|
-
}
|
|
24262
|
-
if (decision === "WARN") {
|
|
24626
|
+
} else if (decision === "WARN") {
|
|
24263
24627
|
emitAllowNotice(
|
|
24264
24628
|
`\u26A0 Verity ${moment}: WARN \u2014 proceeding (${covLine})${link}`,
|
|
24265
24629
|
`Verity ${moment} review: WARN (proceeding).
|
|
24266
24630
|
${covDetail}${viewUrl ? `
|
|
24267
24631
|
Report: ${viewUrl}` : ""}`
|
|
24268
24632
|
);
|
|
24269
|
-
}
|
|
24270
|
-
|
|
24271
|
-
|
|
24272
|
-
|
|
24633
|
+
} else if (decision === "PASS") {
|
|
24634
|
+
emitAllowNotice(
|
|
24635
|
+
`\u2713 Verity ${moment}: PASS (${covLine})${link}`,
|
|
24636
|
+
`Verity ${moment} review: PASS.
|
|
24273
24637
|
${covDetail}${viewUrl ? `
|
|
24274
24638
|
Report: ${viewUrl}` : ""}`
|
|
24275
|
-
|
|
24639
|
+
);
|
|
24640
|
+
} else {
|
|
24641
|
+
emitAllowNotice(
|
|
24642
|
+
`\u26A0 Verity ${moment}: no verdict came back \u2014 ${verb === "commit" ? "committed" : "pushed"} WITHOUT a usable review (${covLine})${link}`,
|
|
24643
|
+
`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.
|
|
24644
|
+
${covDetail}${viewUrl ? `
|
|
24645
|
+
Report: ${viewUrl}` : ""}`
|
|
24646
|
+
);
|
|
24647
|
+
}
|
|
24276
24648
|
}
|
|
24277
24649
|
function writeBlockMessage(moment, response, covDetail) {
|
|
24278
24650
|
const label2 = moment === "pre-commit" ? "pre-commit" : "pre-push";
|
|
@@ -24467,7 +24839,7 @@ function registerWaiveCommand(program2) {
|
|
|
24467
24839
|
var import_node_fs51 = require("node:fs");
|
|
24468
24840
|
var import_promises17 = require("node:fs/promises");
|
|
24469
24841
|
var import_yaml6 = __toESM(require_dist());
|
|
24470
|
-
var
|
|
24842
|
+
var import_node_path35 = require("node:path");
|
|
24471
24843
|
var import_node_child_process16 = require("node:child_process");
|
|
24472
24844
|
|
|
24473
24845
|
// src/lib/banner.ts
|
|
@@ -24504,8 +24876,8 @@ function printBanner(opts) {
|
|
|
24504
24876
|
const dim = (text) => color ? `${DIM3}${text}${RESET2}` : text;
|
|
24505
24877
|
process.stderr.write("\n");
|
|
24506
24878
|
if (!art) {
|
|
24507
|
-
const
|
|
24508
|
-
const text =
|
|
24879
|
+
const candidates2 = [`Verity ${version}`, "Verity"];
|
|
24880
|
+
const text = candidates2.find((c) => c.length + INDENT.length <= columns);
|
|
24509
24881
|
if (text) process.stderr.write(`${INDENT}${dim(text)}
|
|
24510
24882
|
`);
|
|
24511
24883
|
process.stderr.write("\n");
|
|
@@ -24612,13 +24984,13 @@ function checkAnalysisCli() {
|
|
|
24612
24984
|
}
|
|
24613
24985
|
var INSTALL_TIMEOUT_MS = 12e4;
|
|
24614
24986
|
function run(command, args, opts = {}) {
|
|
24615
|
-
return new Promise((
|
|
24987
|
+
return new Promise((resolve5) => {
|
|
24616
24988
|
const child = (0, import_node_child_process13.spawn)(command, args, {
|
|
24617
24989
|
stdio: opts.inherit ? "inherit" : "pipe",
|
|
24618
24990
|
timeout: INSTALL_TIMEOUT_MS
|
|
24619
24991
|
});
|
|
24620
|
-
child.on("error", () =>
|
|
24621
|
-
child.on("close", (code) =>
|
|
24992
|
+
child.on("error", () => resolve5(false));
|
|
24993
|
+
child.on("close", (code) => resolve5(code === 0));
|
|
24622
24994
|
});
|
|
24623
24995
|
}
|
|
24624
24996
|
async function installAnalysisCli() {
|
|
@@ -24717,8 +25089,8 @@ function ensureVerityGitignore() {
|
|
|
24717
25089
|
next = lines.map((l) => BREAKING_ENTRIES.has(l.trim()) ? ".verity/*" : l).join("\n");
|
|
24718
25090
|
}
|
|
24719
25091
|
if (!hasMarker) {
|
|
24720
|
-
const
|
|
24721
|
-
next = next +
|
|
25092
|
+
const sep3 = next === "" ? "" : next.endsWith("\n") ? "\n" : "\n\n";
|
|
25093
|
+
next = next + sep3 + VERITY_GITIGNORE_BLOCK;
|
|
24722
25094
|
}
|
|
24723
25095
|
(0, import_node_fs47.writeFileSync)(".gitignore", next);
|
|
24724
25096
|
return verified(needsRepair ? "repaired" : "added");
|
|
@@ -24845,7 +25217,8 @@ async function uninstallTelemetry() {
|
|
|
24845
25217
|
async function buildReport() {
|
|
24846
25218
|
const prereqs = await checkPrereqs({ install: false });
|
|
24847
25219
|
const state = await readSetupState();
|
|
24848
|
-
const
|
|
25220
|
+
const wiring = await resolveHookWiring();
|
|
25221
|
+
const hooks = wiring.status;
|
|
24849
25222
|
const telemetry = await checkTelemetry();
|
|
24850
25223
|
const hasConfig = (0, import_node_fs48.existsSync)(projectPath(CODACY_CONFIG_FILE));
|
|
24851
25224
|
const artifacts = {
|
|
@@ -24884,6 +25257,11 @@ async function buildReport() {
|
|
|
24884
25257
|
'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
25258
|
);
|
|
24886
25259
|
}
|
|
25260
|
+
if (wiring.duplicateSettingsHooks) {
|
|
25261
|
+
next.push(
|
|
25262
|
+
'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.'
|
|
25263
|
+
);
|
|
25264
|
+
}
|
|
24887
25265
|
if (state?.telemetry === "deferred") {
|
|
24888
25266
|
next.push('Telemetry was requested but needs a token \u2014 run "verity login", then "verity telemetry install".');
|
|
24889
25267
|
}
|
|
@@ -24899,7 +25277,12 @@ async function buildReport() {
|
|
|
24899
25277
|
moments: state?.moments ?? null,
|
|
24900
25278
|
telemetry: state?.telemetry ?? null
|
|
24901
25279
|
},
|
|
24902
|
-
hooks: {
|
|
25280
|
+
hooks: {
|
|
25281
|
+
source: wiring.source,
|
|
25282
|
+
...hooks,
|
|
25283
|
+
duplicateSettingsHooks: wiring.duplicateSettingsHooks,
|
|
25284
|
+
noAnalysisMoment
|
|
25285
|
+
},
|
|
24903
25286
|
telemetry: { enabled: telemetry.enabled, endpoint: telemetry.endpoint },
|
|
24904
25287
|
artifacts,
|
|
24905
25288
|
next
|
|
@@ -24922,8 +25305,9 @@ function registerDoctorCommand(program2) {
|
|
|
24922
25305
|
printInfo(` verity init: ${report.phases.init.done ? `done ${report.phases.init.completed_at ?? ""}`.trim() : "NOT run here"}`);
|
|
24923
25306
|
printInfo(` /verity-setup: ${report.phases.setup.done ? "done" : "not completed"}`);
|
|
24924
25307
|
printInfo(` intensity: ${report.answers.intensity ?? "\u2014"} moments: ${report.answers.moments?.join(", ") ?? "\u2014"}`);
|
|
24925
|
-
|
|
24926
|
-
printInfo(
|
|
25308
|
+
const plugin = report.hooks.source === "plugin";
|
|
25309
|
+
printInfo(plugin ? "Hooks: wired by the Verity Claude Code plugin (not .claude/settings.json)" : "Hooks:");
|
|
25310
|
+
printInfo(` Stop (verity analyze): ${report.hooks.stop ? plugin ? "on (plugin)" : "on" : "off"}`);
|
|
24927
25311
|
printInfo(` Git-moment gate: ${report.hooks.guardOn.length ? report.hooks.guardOn.join(", ") : "off"}`);
|
|
24928
25312
|
printInfo(` Infra (intent/baseline/compact/session-end): ${[report.hooks.intent, report.hooks.baseline, report.hooks.compact, report.hooks.sessionEnd].filter(Boolean).length}/4`);
|
|
24929
25313
|
printInfo(`Telemetry: ${report.telemetry.enabled ? `enabled \u2192 ${report.telemetry.endpoint}` : "disabled"}`);
|
|
@@ -24946,7 +25330,7 @@ function registerDoctorCommand(program2) {
|
|
|
24946
25330
|
|
|
24947
25331
|
// src/commands/migrate.ts
|
|
24948
25332
|
var import_node_fs49 = require("node:fs");
|
|
24949
|
-
var
|
|
25333
|
+
var import_node_path33 = require("node:path");
|
|
24950
25334
|
var import_node_child_process15 = require("node:child_process");
|
|
24951
25335
|
var LEGACY_NPM_PACKAGE = "@codacy/gate-cli";
|
|
24952
25336
|
function defaultNpmRemover(pkg) {
|
|
@@ -24983,8 +25367,8 @@ async function runMigration(opts = {}) {
|
|
|
24983
25367
|
return { actions, migrated: actions.length > 0 };
|
|
24984
25368
|
}
|
|
24985
25369
|
function migrateProjectDir(root, actions) {
|
|
24986
|
-
const gateDir = (0,
|
|
24987
|
-
const verityDir = (0,
|
|
25370
|
+
const gateDir = (0, import_node_path33.join)(root, ".gate");
|
|
25371
|
+
const verityDir = (0, import_node_path33.join)(root, ".verity");
|
|
24988
25372
|
if ((0, import_node_fs49.existsSync)(gateDir) && !(0, import_node_fs49.existsSync)(verityDir)) {
|
|
24989
25373
|
return migrateProjectDirRename(root, gateDir, verityDir, actions);
|
|
24990
25374
|
}
|
|
@@ -25038,11 +25422,11 @@ function migrateProjectDirCarry(gateDir, verityDir, actions) {
|
|
|
25038
25422
|
}
|
|
25039
25423
|
function migrateGlobalCredentials(home, actions) {
|
|
25040
25424
|
if (!home) return;
|
|
25041
|
-
const gateCreds = (0,
|
|
25042
|
-
const verityCreds = (0,
|
|
25425
|
+
const gateCreds = (0, import_node_path33.join)(home, ".gate", "credentials");
|
|
25426
|
+
const verityCreds = (0, import_node_path33.join)(home, ".verity", "credentials");
|
|
25043
25427
|
if (!(0, import_node_fs49.existsSync)(gateCreds)) return;
|
|
25044
25428
|
if (!(0, import_node_fs49.existsSync)(verityCreds)) {
|
|
25045
|
-
(0, import_node_fs49.mkdirSync)((0,
|
|
25429
|
+
(0, import_node_fs49.mkdirSync)((0, import_node_path33.join)(home, ".verity"), { recursive: true });
|
|
25046
25430
|
moveFile(gateCreds, verityCreds);
|
|
25047
25431
|
actions.push("Moved ~/.gate/credentials \u2192 ~/.verity/credentials");
|
|
25048
25432
|
return;
|
|
@@ -25064,7 +25448,7 @@ async function migrateLegacyHooks(root, actions) {
|
|
|
25064
25448
|
}
|
|
25065
25449
|
}
|
|
25066
25450
|
async function migrateClaudeMd(root, actions) {
|
|
25067
|
-
const claudeMd = (0,
|
|
25451
|
+
const claudeMd = (0, import_node_path33.join)(root, "CLAUDE.md");
|
|
25068
25452
|
const hadLegacyBlock = (0, import_node_fs49.existsSync)(claudeMd) && hasLegacyMemoryBlock(readFileSyncSafe(claudeMd));
|
|
25069
25453
|
if (!hadLegacyBlock) return;
|
|
25070
25454
|
try {
|
|
@@ -25075,8 +25459,8 @@ async function migrateClaudeMd(root, actions) {
|
|
|
25075
25459
|
}
|
|
25076
25460
|
}
|
|
25077
25461
|
function migrateStandardFile(root, actions) {
|
|
25078
|
-
const gateMd = (0,
|
|
25079
|
-
const verityMd = (0,
|
|
25462
|
+
const gateMd = (0, import_node_path33.join)(root, "GATE.md");
|
|
25463
|
+
const verityMd = (0, import_node_path33.join)(root, "VERITY.md");
|
|
25080
25464
|
if (!(0, import_node_fs49.existsSync)(gateMd) || (0, import_node_fs49.existsSync)(verityMd)) return;
|
|
25081
25465
|
let moved = false;
|
|
25082
25466
|
if (isGitRepo(root) && isGitTracked(root, "GATE.md")) {
|
|
@@ -25093,7 +25477,7 @@ function migrateStandardFile(root, actions) {
|
|
|
25093
25477
|
actions.push("Renamed GATE.md \u2192 VERITY.md");
|
|
25094
25478
|
}
|
|
25095
25479
|
async function migrateTelemetryHeaders(root, actions) {
|
|
25096
|
-
const file = (0,
|
|
25480
|
+
const file = (0, import_node_path33.join)(root, ".claude", "settings.local.json");
|
|
25097
25481
|
if (!(0, import_node_fs49.existsSync)(file)) return;
|
|
25098
25482
|
let settings;
|
|
25099
25483
|
try {
|
|
@@ -25141,8 +25525,8 @@ function mergeGlobalCredentials(gateCreds, verityCreds) {
|
|
|
25141
25525
|
toAppend.push(line.replace(/\r$/, ""));
|
|
25142
25526
|
}
|
|
25143
25527
|
if (toAppend.length > 0) {
|
|
25144
|
-
const
|
|
25145
|
-
(0, import_node_fs49.writeFileSync)(verityCreds, verityContent +
|
|
25528
|
+
const sep3 = verityContent.endsWith("\n") || verityContent === "" ? "" : "\n";
|
|
25529
|
+
(0, import_node_fs49.writeFileSync)(verityCreds, verityContent + sep3 + toAppend.join("\n") + "\n");
|
|
25146
25530
|
}
|
|
25147
25531
|
(0, import_node_fs49.rmSync)(gateCreds, { force: true });
|
|
25148
25532
|
return toAppend.length;
|
|
@@ -25183,15 +25567,15 @@ function moveFile(from, to) {
|
|
|
25183
25567
|
function carryLegacyContents(gateDir, verityDir) {
|
|
25184
25568
|
let copied = 0;
|
|
25185
25569
|
const walk2 = (relDir) => {
|
|
25186
|
-
const srcDir = (0,
|
|
25570
|
+
const srcDir = (0, import_node_path33.join)(gateDir, relDir);
|
|
25187
25571
|
for (const entry of (0, import_node_fs49.readdirSync)(srcDir)) {
|
|
25188
|
-
const rel = relDir ? (0,
|
|
25189
|
-
const src = (0,
|
|
25190
|
-
const dest = (0,
|
|
25572
|
+
const rel = relDir ? (0, import_node_path33.join)(relDir, entry) : entry;
|
|
25573
|
+
const src = (0, import_node_path33.join)(gateDir, rel);
|
|
25574
|
+
const dest = (0, import_node_path33.join)(verityDir, rel);
|
|
25191
25575
|
if ((0, import_node_fs49.statSync)(src).isDirectory()) {
|
|
25192
25576
|
walk2(rel);
|
|
25193
25577
|
} else if (!(0, import_node_fs49.existsSync)(dest)) {
|
|
25194
|
-
(0, import_node_fs49.mkdirSync)((0,
|
|
25578
|
+
(0, import_node_fs49.mkdirSync)((0, import_node_path33.dirname)(dest), { recursive: true });
|
|
25195
25579
|
(0, import_node_fs49.cpSync)(src, dest);
|
|
25196
25580
|
copied++;
|
|
25197
25581
|
}
|
|
@@ -25201,22 +25585,22 @@ function carryLegacyContents(gateDir, verityDir) {
|
|
|
25201
25585
|
return copied;
|
|
25202
25586
|
}
|
|
25203
25587
|
async function needsMigration(root = repoRoot()) {
|
|
25204
|
-
const gateDir = (0,
|
|
25205
|
-
const verityDir = (0,
|
|
25588
|
+
const gateDir = (0, import_node_path33.join)(root, ".gate");
|
|
25589
|
+
const verityDir = (0, import_node_path33.join)(root, ".verity");
|
|
25206
25590
|
if ((0, import_node_fs49.existsSync)(gateDir) && !(0, import_node_fs49.existsSync)(verityDir)) return true;
|
|
25207
25591
|
if ((0, import_node_fs49.existsSync)(gateDir) && (0, import_node_fs49.existsSync)(verityDir)) {
|
|
25208
|
-
if ((0, import_node_fs49.existsSync)((0,
|
|
25592
|
+
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
25593
|
return true;
|
|
25210
25594
|
}
|
|
25211
|
-
if ((0, import_node_fs49.existsSync)((0,
|
|
25595
|
+
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
25596
|
return true;
|
|
25213
25597
|
}
|
|
25214
25598
|
}
|
|
25215
|
-
const claudeMd = (0,
|
|
25599
|
+
const claudeMd = (0, import_node_path33.join)(root, "CLAUDE.md");
|
|
25216
25600
|
if ((0, import_node_fs49.existsSync)(claudeMd) && hasLegacyMemoryBlock(readFileSyncSafe(claudeMd))) {
|
|
25217
25601
|
return true;
|
|
25218
25602
|
}
|
|
25219
|
-
if ((0, import_node_fs49.existsSync)((0,
|
|
25603
|
+
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
25604
|
return true;
|
|
25221
25605
|
}
|
|
25222
25606
|
if (await hasLegacyHooksAt(root)) return true;
|
|
@@ -25280,7 +25664,13 @@ function applyKey(state, action, count, mode2) {
|
|
|
25280
25664
|
}
|
|
25281
25665
|
case "jump": {
|
|
25282
25666
|
if (action.index >= count) return { status: "open", state };
|
|
25283
|
-
|
|
25667
|
+
if (mode2 === "single") {
|
|
25668
|
+
return { status: "open", state: { cursor: action.index, chosen: state.chosen } };
|
|
25669
|
+
}
|
|
25670
|
+
const chosen = new Set(state.chosen);
|
|
25671
|
+
if (chosen.has(action.index)) chosen.delete(action.index);
|
|
25672
|
+
else chosen.add(action.index);
|
|
25673
|
+
return { status: "open", state: { cursor: action.index, chosen } };
|
|
25284
25674
|
}
|
|
25285
25675
|
case "toggle": {
|
|
25286
25676
|
if (mode2 === "single") {
|
|
@@ -25325,7 +25715,7 @@ function renderSelect(question, choices, state, mode2, color = colorEnabled()) {
|
|
|
25325
25715
|
const hint = choice.hint ? `${pad} ${paint(choice.hint, DIM4)}` : "";
|
|
25326
25716
|
lines.push(` ${cursor} ${marker} ${here ? paint(label2, BOLD2) : label2}${hint}`);
|
|
25327
25717
|
});
|
|
25328
|
-
const keys = mode2 === "multi" ? "\u2191\u2193 move \xB7 space toggle \xB7 enter confirm" : "\u2191\u2193 move \xB7 enter confirm";
|
|
25718
|
+
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
25719
|
lines.push(` ${paint(state.hint ?? keys, state.hint ? GREEN3 : DIM4)}`);
|
|
25330
25720
|
return lines;
|
|
25331
25721
|
}
|
|
@@ -25339,7 +25729,7 @@ function runSelect(opts) {
|
|
|
25339
25729
|
cursor: initialIdx[0] ?? 0,
|
|
25340
25730
|
chosen: new Set(mode2 === "single" ? [initialIdx[0] ?? 0] : initialIdx)
|
|
25341
25731
|
};
|
|
25342
|
-
return new Promise((
|
|
25732
|
+
return new Promise((resolve5) => {
|
|
25343
25733
|
let painted = 0;
|
|
25344
25734
|
let settled = false;
|
|
25345
25735
|
const draw = () => {
|
|
@@ -25387,7 +25777,7 @@ function runSelect(opts) {
|
|
|
25387
25777
|
if (settled) return;
|
|
25388
25778
|
settled = true;
|
|
25389
25779
|
restore();
|
|
25390
|
-
|
|
25780
|
+
resolve5(value);
|
|
25391
25781
|
};
|
|
25392
25782
|
readline2.emitKeypressEvents(input);
|
|
25393
25783
|
input.setRawMode(true);
|
|
@@ -25408,9 +25798,9 @@ async function askLine(question, io = {}) {
|
|
|
25408
25798
|
output: io.output ?? process.stdout
|
|
25409
25799
|
});
|
|
25410
25800
|
try {
|
|
25411
|
-
return await new Promise((
|
|
25412
|
-
rl.question(question).then((a) =>
|
|
25413
|
-
rl.once("close", () => setImmediate(() =>
|
|
25801
|
+
return await new Promise((resolve5) => {
|
|
25802
|
+
rl.question(question).then((a) => resolve5(a.trim())).catch(() => resolve5(null));
|
|
25803
|
+
rl.once("close", () => setImmediate(() => resolve5(null)));
|
|
25414
25804
|
});
|
|
25415
25805
|
} finally {
|
|
25416
25806
|
rl.close();
|
|
@@ -25493,7 +25883,7 @@ async function promptMultiSelect(question, choices, fallback) {
|
|
|
25493
25883
|
// src/lib/remote-config.ts
|
|
25494
25884
|
var import_node_fs50 = require("node:fs");
|
|
25495
25885
|
var import_promises16 = require("node:fs/promises");
|
|
25496
|
-
var
|
|
25886
|
+
var import_node_path34 = require("node:path");
|
|
25497
25887
|
var import_yaml5 = __toESM(require_dist());
|
|
25498
25888
|
var IGNORE_RIDER = "verityignore";
|
|
25499
25889
|
async function fetchRemoteSetup(opts) {
|
|
@@ -25571,7 +25961,7 @@ async function adoptRemoteSetup(found, opts) {
|
|
|
25571
25961
|
}
|
|
25572
25962
|
async function writeOut(relative2, body) {
|
|
25573
25963
|
const target = projectPath(relative2);
|
|
25574
|
-
await (0, import_promises16.mkdir)((0,
|
|
25964
|
+
await (0, import_promises16.mkdir)((0, import_node_path34.dirname)(target), { recursive: true });
|
|
25575
25965
|
await (0, import_promises16.writeFile)(target, body);
|
|
25576
25966
|
}
|
|
25577
25967
|
function describeRemote(found) {
|
|
@@ -25687,16 +26077,16 @@ async function runOptionalAuth(resolution, opts = {}) {
|
|
|
25687
26077
|
}
|
|
25688
26078
|
}
|
|
25689
26079
|
function resolveDataDir2() {
|
|
25690
|
-
const
|
|
25691
|
-
(0,
|
|
26080
|
+
const candidates2 = [
|
|
26081
|
+
(0, import_node_path35.join)(__dirname, "..", "data"),
|
|
25692
26082
|
// installed: node_modules/@codacy/verity-cli/data
|
|
25693
|
-
(0,
|
|
26083
|
+
(0, import_node_path35.join)(__dirname, "..", "..", "data"),
|
|
25694
26084
|
// edge case: nested resolution
|
|
25695
|
-
(0,
|
|
26085
|
+
(0, import_node_path35.join)(process.cwd(), "cli", "data")
|
|
25696
26086
|
// local dev: running from repo root
|
|
25697
26087
|
];
|
|
25698
|
-
for (const candidate of
|
|
25699
|
-
if ((0, import_node_fs51.existsSync)((0,
|
|
26088
|
+
for (const candidate of candidates2) {
|
|
26089
|
+
if ((0, import_node_fs51.existsSync)((0, import_node_path35.join)(candidate, "skills"))) {
|
|
25700
26090
|
return candidate;
|
|
25701
26091
|
}
|
|
25702
26092
|
}
|
|
@@ -25714,7 +26104,7 @@ async function skillIsCurrent(src, dest) {
|
|
|
25714
26104
|
const walk2 = (d, prefix) => {
|
|
25715
26105
|
for (const e of (0, import_node_fs51.readdirSync)(d, { withFileTypes: true })) {
|
|
25716
26106
|
const rel = prefix ? `${prefix}/${e.name}` : e.name;
|
|
25717
|
-
if (e.isDirectory()) walk2((0,
|
|
26107
|
+
if (e.isDirectory()) walk2((0, import_node_path35.join)(d, e.name), rel);
|
|
25718
26108
|
else if (e.isFile()) out.push(rel);
|
|
25719
26109
|
}
|
|
25720
26110
|
};
|
|
@@ -25725,8 +26115,8 @@ async function skillIsCurrent(src, dest) {
|
|
|
25725
26115
|
const shipped = list2(src);
|
|
25726
26116
|
if (JSON.stringify(shipped) !== JSON.stringify(list2(dest))) return false;
|
|
25727
26117
|
for (const rel of shipped) {
|
|
25728
|
-
const a = await (0, import_promises17.readFile)((0,
|
|
25729
|
-
const b = await (0, import_promises17.readFile)((0,
|
|
26118
|
+
const a = await (0, import_promises17.readFile)((0, import_node_path35.join)(src, rel), "utf-8");
|
|
26119
|
+
const b = await (0, import_promises17.readFile)((0, import_node_path35.join)(dest, rel), "utf-8");
|
|
25730
26120
|
if (a !== b) return false;
|
|
25731
26121
|
}
|
|
25732
26122
|
return true;
|
|
@@ -26001,12 +26391,12 @@ async function handoffToSetup(enabled, claudeInstalled) {
|
|
|
26001
26391
|
async function installSkills(force, step) {
|
|
26002
26392
|
step("Installing skills");
|
|
26003
26393
|
const dataDir = resolveDataDir2();
|
|
26004
|
-
const skillsSource = (0,
|
|
26394
|
+
const skillsSource = (0, import_node_path35.join)(dataDir, "skills");
|
|
26005
26395
|
const skillsDest = ".claude/skills";
|
|
26006
26396
|
let skillsInstalled = 0;
|
|
26007
26397
|
for (const skill of SKILLS) {
|
|
26008
|
-
const src = (0,
|
|
26009
|
-
const dest = (0,
|
|
26398
|
+
const src = (0, import_node_path35.join)(skillsSource, skill);
|
|
26399
|
+
const dest = (0, import_node_path35.join)(skillsDest, skill);
|
|
26010
26400
|
if (!(0, import_node_fs51.existsSync)(src)) {
|
|
26011
26401
|
printWarn(` Skill data not found: ${skill}`);
|
|
26012
26402
|
continue;
|
|
@@ -26109,12 +26499,16 @@ function registerInitCommand(program2) {
|
|
|
26109
26499
|
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
26500
|
"--plugin-mode",
|
|
26111
26501
|
"The Claude Code plugin owns the skills and hooks: install neither, and remove any this project already has"
|
|
26502
|
+
).option(
|
|
26503
|
+
"--no-plugin",
|
|
26504
|
+
"Ignore any Claude Code plugin here and wire this project's own skills and hooks"
|
|
26112
26505
|
).option("--no-adopt", "Don't offer this repository's existing Standard from the service; synthesize a new one").action(async (opts) => {
|
|
26113
26506
|
const force = opts.force ?? false;
|
|
26114
26507
|
const wantsHandoff = opts.setup !== false;
|
|
26115
26508
|
const wantsAdopt = opts.adopt !== false;
|
|
26116
26509
|
const defaultsOnly = (opts.yes ?? false) || !interactive();
|
|
26117
|
-
const
|
|
26510
|
+
const staleMarker = clearStalePluginMarker();
|
|
26511
|
+
const pluginMode = opts.plugin === false ? false : opts.pluginMode ?? pluginActiveHere();
|
|
26118
26512
|
const projectMarkers = [".git", "package.json", "pyproject.toml", "go.mod", "Cargo.toml", "Gemfile", "pom.xml", "build.gradle"];
|
|
26119
26513
|
const isProject = projectMarkers.some((m) => (0, import_node_fs51.existsSync)(m));
|
|
26120
26514
|
if (!isProject) {
|
|
@@ -26131,6 +26525,26 @@ function registerInitCommand(program2) {
|
|
|
26131
26525
|
} else {
|
|
26132
26526
|
printPhase(1, 2, "this machine", "prerequisites \xB7 skills \xB7 hooks \xB7 sign-in");
|
|
26133
26527
|
}
|
|
26528
|
+
if (staleMarker) {
|
|
26529
|
+
printInfo(`Cleared a stale plugin marker \u2014 ${staleMarker.pluginRoot} is no longer installed.`);
|
|
26530
|
+
}
|
|
26531
|
+
const install = pluginMode ? activePluginInstall() : null;
|
|
26532
|
+
if (pluginMode) {
|
|
26533
|
+
const where = install ? ` \u2014 ${install.pluginRoot}${install.version ? ` (v${install.version})` : ""}` : "";
|
|
26534
|
+
printInfo(`Hooks here: the Verity Claude Code plugin${where}.`);
|
|
26535
|
+
printInfo(" Skills and hooks come from the plugin, so this run installs neither \u2014 and removes");
|
|
26536
|
+
printInfo(" any this project still carries from an earlier npm install.");
|
|
26537
|
+
printInfo(" It still does the half the plugin cannot: your Standard and analysis config, the");
|
|
26538
|
+
printInfo(" knowledge base, CLAUDE.md, .gitignore, the review moments, and sign-in.");
|
|
26539
|
+
printInfo(" Want this project to own its own copy instead? Uninstall the plugin, or use --no-plugin.");
|
|
26540
|
+
} else if (opts.plugin === false && pluginActiveHere()) {
|
|
26541
|
+
printWarn("Hooks here: this project's .claude/settings.json (--no-plugin).");
|
|
26542
|
+
printWarn(" The Verity plugin is active on this machine and would otherwise own them. Both sets");
|
|
26543
|
+
printWarn(" will fire; the settings.json copy stands down at run time so each turn is gated once.");
|
|
26544
|
+
} else {
|
|
26545
|
+
printInfo("Hooks here: this project's .claude/settings.json (no Verity Claude Code plugin is active).");
|
|
26546
|
+
}
|
|
26547
|
+
console.log("");
|
|
26134
26548
|
const TOTAL_STEPS = 9;
|
|
26135
26549
|
let stepNo = 0;
|
|
26136
26550
|
const step = (label2) => {
|
|
@@ -26162,7 +26576,7 @@ function registerInitCommand(program2) {
|
|
|
26162
26576
|
printInfo(` intensity: ${intensity} \xB7 moments: ${moments.join(", ") || "none"} (no questions asked)`);
|
|
26163
26577
|
}
|
|
26164
26578
|
await scaffoldProject(step, defaultsOnly);
|
|
26165
|
-
const globalVerityDir = (0,
|
|
26579
|
+
const globalVerityDir = (0, import_node_path35.join)(process.env.HOME ?? "", ".verity");
|
|
26166
26580
|
await (0, import_promises17.mkdir)(globalVerityDir, { recursive: true });
|
|
26167
26581
|
console.log("");
|
|
26168
26582
|
step("Wiring Claude Code hooks");
|
|
@@ -26170,9 +26584,18 @@ function registerInitCommand(program2) {
|
|
|
26170
26584
|
...moments.includes("pre-commit") ? ["commit"] : [],
|
|
26171
26585
|
...moments.includes("pre-push") ? ["push"] : []
|
|
26172
26586
|
];
|
|
26173
|
-
|
|
26587
|
+
const existingMoments = readProjectConfig();
|
|
26588
|
+
const keepExisting = defaultsOnly && existingMoments.git_moments_source === "user";
|
|
26589
|
+
if (keepExisting) {
|
|
26590
|
+
printInfo(
|
|
26591
|
+
` Keeping the git moments you set: ${existingMoments.git_moments.join(", ") || "none"} (this run asked no questions, so it does not overrule them).`
|
|
26592
|
+
);
|
|
26593
|
+
} else {
|
|
26594
|
+
writeProjectConfig({ git_moments: gitMoments, git_moments_source: "init" });
|
|
26595
|
+
}
|
|
26596
|
+
const effectiveMoments = keepExisting ? existingMoments.git_moments : gitMoments;
|
|
26174
26597
|
if (pluginMode) {
|
|
26175
|
-
await adoptPluginWiring(
|
|
26598
|
+
await adoptPluginWiring(effectiveMoments, moments);
|
|
26176
26599
|
} else {
|
|
26177
26600
|
await reconcileOwnWiring(moments);
|
|
26178
26601
|
}
|
|
@@ -26244,7 +26667,7 @@ function registerInitCommand(program2) {
|
|
|
26244
26667
|
...telemetryChoice ? { telemetry: telemetryChoice } : {},
|
|
26245
26668
|
init: {
|
|
26246
26669
|
completed_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
26247
|
-
cli_version: true ? "0.32.
|
|
26670
|
+
cli_version: true ? "0.32.1-experimental.f2cf829" : "dev"
|
|
26248
26671
|
}
|
|
26249
26672
|
});
|
|
26250
26673
|
} catch (err) {
|
|
@@ -26284,7 +26707,7 @@ function registerInitCommand(program2) {
|
|
|
26284
26707
|
|
|
26285
26708
|
// src/commands/uninstall.ts
|
|
26286
26709
|
var import_node_fs52 = require("node:fs");
|
|
26287
|
-
var
|
|
26710
|
+
var import_node_path36 = require("node:path");
|
|
26288
26711
|
var SKILL_NAMES = [
|
|
26289
26712
|
"verity-setup",
|
|
26290
26713
|
"verity-analyze",
|
|
@@ -26303,7 +26726,7 @@ function registerUninstallCommand(program2) {
|
|
|
26303
26726
|
const actions = [];
|
|
26304
26727
|
const skillsRoot = projectPath(".claude/skills");
|
|
26305
26728
|
for (const name of SKILL_NAMES) {
|
|
26306
|
-
const dir = (0,
|
|
26729
|
+
const dir = (0, import_node_path36.join)(skillsRoot, name);
|
|
26307
26730
|
if ((0, import_node_fs52.existsSync)(dir)) {
|
|
26308
26731
|
actions.push({
|
|
26309
26732
|
label: `Remove .claude/skills/${name}/`,
|
|
@@ -26349,7 +26772,7 @@ function registerUninstallCommand(program2) {
|
|
|
26349
26772
|
}
|
|
26350
26773
|
});
|
|
26351
26774
|
const home = process.env.HOME ?? "";
|
|
26352
|
-
const globalVerityDir = (0,
|
|
26775
|
+
const globalVerityDir = (0, import_node_path36.join)(home, ".verity");
|
|
26353
26776
|
if (purgeGlobal && (0, import_node_fs52.existsSync)(globalVerityDir)) {
|
|
26354
26777
|
actions.push({
|
|
26355
26778
|
label: `Remove ~/.verity/ (global credentials \u2014 reconnect requires re-registration)`,
|
|
@@ -26548,7 +26971,7 @@ function registerTaskCommands(program2) {
|
|
|
26548
26971
|
|
|
26549
26972
|
// src/commands/reset.ts
|
|
26550
26973
|
var import_node_fs53 = require("node:fs");
|
|
26551
|
-
var
|
|
26974
|
+
var import_node_path37 = require("node:path");
|
|
26552
26975
|
function registerResetCommand(program2) {
|
|
26553
26976
|
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
26977
|
const globals = program2.opts();
|
|
@@ -26589,7 +27012,7 @@ function registerResetCommand(program2) {
|
|
|
26589
27012
|
for (const entry of (0, import_node_fs53.readdirSync)(cacheDir)) {
|
|
26590
27013
|
if (entry.startsWith("pending-")) {
|
|
26591
27014
|
try {
|
|
26592
|
-
(0, import_node_fs53.unlinkSync)((0,
|
|
27015
|
+
(0, import_node_fs53.unlinkSync)((0, import_node_path37.join)(cacheDir, entry));
|
|
26593
27016
|
purged++;
|
|
26594
27017
|
} catch {
|
|
26595
27018
|
}
|
|
@@ -26616,7 +27039,7 @@ function registerResetCommand(program2) {
|
|
|
26616
27039
|
if ((0, import_node_fs53.existsSync)(logsDir)) {
|
|
26617
27040
|
for (const entry of (0, import_node_fs53.readdirSync)(logsDir)) {
|
|
26618
27041
|
try {
|
|
26619
|
-
(0, import_node_fs53.unlinkSync)((0,
|
|
27042
|
+
(0, import_node_fs53.unlinkSync)((0, import_node_path37.join)(logsDir, entry));
|
|
26620
27043
|
} catch {
|
|
26621
27044
|
}
|
|
26622
27045
|
}
|
|
@@ -26924,8 +27347,8 @@ function registerTelemetryCommands(program2) {
|
|
|
26924
27347
|
}
|
|
26925
27348
|
|
|
26926
27349
|
// 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.
|
|
27350
|
+
program.name("verity").description("CLI for Verity quality gate service").version("0.32.1-experimental.f2cf829").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) => {
|
|
27351
|
+
installStderrLog(actionCommand.name(), process.argv.slice(2), "0.32.1-experimental.f2cf829");
|
|
26929
27352
|
setUserNamedServiceUrl(program.opts().serviceUrl);
|
|
26930
27353
|
try {
|
|
26931
27354
|
await foldLegacyLocalCredential();
|