@codacy/verity-cli 0.33.2-experimental.0c53bed → 0.33.3-experimental.072d5cb
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 +26 -0
- package/bin/verity.js +1314 -731
- package/package.json +1 -1
package/bin/verity.js
CHANGED
|
@@ -10970,8 +10970,8 @@ function filterReviewable(files) {
|
|
|
10970
10970
|
const ext = (0, import_node_path3.extname)(f).slice(1);
|
|
10971
10971
|
if (ANALYZABLE_EXTENSIONS.has(ext)) return false;
|
|
10972
10972
|
if (REVIEWABLE_EXTENSIONS.has(ext)) return true;
|
|
10973
|
-
const
|
|
10974
|
-
if (REVIEWABLE_FILENAMES.has(
|
|
10973
|
+
const basename6 = f.split("/").pop() ?? "";
|
|
10974
|
+
if (REVIEWABLE_FILENAMES.has(basename6)) return true;
|
|
10975
10975
|
if (REVIEWABLE_PATH_PATTERNS.some((p) => p.test(f))) return true;
|
|
10976
10976
|
return false;
|
|
10977
10977
|
});
|
|
@@ -13457,7 +13457,7 @@ function registerHooksCommands(program2) {
|
|
|
13457
13457
|
}
|
|
13458
13458
|
|
|
13459
13459
|
// src/commands/intent.ts
|
|
13460
|
-
var
|
|
13460
|
+
var import_node_crypto9 = require("node:crypto");
|
|
13461
13461
|
|
|
13462
13462
|
// src/lib/conversation-buffer.ts
|
|
13463
13463
|
var import_promises5 = require("node:fs/promises");
|
|
@@ -14009,8 +14009,8 @@ async function appendEntry(taskId, entry) {
|
|
|
14009
14009
|
|
|
14010
14010
|
// src/lib/memory-retrieval.ts
|
|
14011
14011
|
var import_promises8 = require("node:fs/promises");
|
|
14012
|
-
var
|
|
14013
|
-
var
|
|
14012
|
+
var import_node_fs14 = require("node:fs");
|
|
14013
|
+
var import_node_path14 = require("node:path");
|
|
14014
14014
|
|
|
14015
14015
|
// src/lib/org-mirror.ts
|
|
14016
14016
|
var import_node_fs12 = require("node:fs");
|
|
@@ -14201,16 +14201,216 @@ async function readOrgMirror(remote = requestRemote()) {
|
|
|
14201
14201
|
return out;
|
|
14202
14202
|
}
|
|
14203
14203
|
|
|
14204
|
-
// src/lib/
|
|
14205
|
-
var
|
|
14206
|
-
var
|
|
14207
|
-
var
|
|
14208
|
-
var
|
|
14209
|
-
var
|
|
14210
|
-
|
|
14204
|
+
// src/lib/safe-read.ts
|
|
14205
|
+
var import_node_fs13 = require("node:fs");
|
|
14206
|
+
var import_node_path13 = require("node:path");
|
|
14207
|
+
var FLAGS = import_node_fs13.constants;
|
|
14208
|
+
var NOFOLLOW = FLAGS.O_NOFOLLOW;
|
|
14209
|
+
var NONBLOCK = FLAGS.O_NONBLOCK;
|
|
14210
|
+
function closeOpened(fd) {
|
|
14211
|
+
try {
|
|
14212
|
+
(0, import_node_fs13.closeSync)(fd);
|
|
14213
|
+
} catch {
|
|
14214
|
+
}
|
|
14215
|
+
}
|
|
14216
|
+
function isInsideRoot(realRoot, realPath) {
|
|
14217
|
+
return realPath === realRoot || realPath.startsWith(realRoot.endsWith(import_node_path13.sep) ? realRoot : realRoot + import_node_path13.sep);
|
|
14218
|
+
}
|
|
14219
|
+
function sameOpenedFile(opened, current, nofollowAvailable) {
|
|
14220
|
+
if (!nofollowAvailable && (opened.ino === 0n || current.ino === 0n)) return false;
|
|
14221
|
+
return opened.ino === current.ino && opened.dev === current.dev;
|
|
14222
|
+
}
|
|
14223
|
+
function openRegularInRoot(root, path) {
|
|
14224
|
+
const full = (0, import_node_path13.isAbsolute)(path) ? path : (0, import_node_path13.join)(root, path);
|
|
14225
|
+
let fd;
|
|
14226
|
+
try {
|
|
14227
|
+
fd = (0, import_node_fs13.openSync)(full, import_node_fs13.constants.O_RDONLY | (NOFOLLOW ?? 0) | (NONBLOCK ?? 0));
|
|
14228
|
+
} catch (err) {
|
|
14229
|
+
const code = err.code;
|
|
14230
|
+
if (code === "ELOOP" || code === "EMLINK" || code === "EFTYPE") return { ok: false, reason: "symlink" };
|
|
14231
|
+
if (code === "ENOENT" || code === "ENOTDIR") return { ok: false, reason: "missing" };
|
|
14232
|
+
return { ok: false, reason: "unreadable" };
|
|
14233
|
+
}
|
|
14234
|
+
try {
|
|
14235
|
+
const opened = (0, import_node_fs13.fstatSync)(fd, { bigint: true });
|
|
14236
|
+
if (!opened.isFile()) {
|
|
14237
|
+
closeOpened(fd);
|
|
14238
|
+
return { ok: false, reason: "not-regular" };
|
|
14239
|
+
}
|
|
14240
|
+
const realRoot = import_node_fs13.realpathSync.native(root);
|
|
14241
|
+
const realPath = import_node_fs13.realpathSync.native(full);
|
|
14242
|
+
if (!isInsideRoot(realRoot, realPath)) {
|
|
14243
|
+
closeOpened(fd);
|
|
14244
|
+
return { ok: false, reason: "outside-root" };
|
|
14245
|
+
}
|
|
14246
|
+
const current = (0, import_node_fs13.statSync)(realPath, { bigint: true });
|
|
14247
|
+
if (!sameOpenedFile(opened, current, NOFOLLOW !== void 0)) {
|
|
14248
|
+
closeOpened(fd);
|
|
14249
|
+
return { ok: false, reason: NOFOLLOW === void 0 ? "unreadable" : "outside-root" };
|
|
14250
|
+
}
|
|
14251
|
+
return { ok: true, fd, size: Number(opened.size), mtimeMs: Number(opened.mtimeMs) };
|
|
14252
|
+
} catch {
|
|
14253
|
+
closeOpened(fd);
|
|
14254
|
+
return { ok: false, reason: "unreadable" };
|
|
14255
|
+
}
|
|
14256
|
+
}
|
|
14257
|
+
function statRegularInRoot(root, path) {
|
|
14258
|
+
const opened = openRegularInRoot(root, path);
|
|
14259
|
+
if (!opened.ok) return opened;
|
|
14260
|
+
closeOpened(opened.fd);
|
|
14261
|
+
return { ok: true, size: opened.size, mtimeMs: opened.mtimeMs };
|
|
14262
|
+
}
|
|
14263
|
+
function readOpened(fd, size) {
|
|
14264
|
+
try {
|
|
14265
|
+
const buffer = Buffer.alloc(size);
|
|
14266
|
+
let offset = 0;
|
|
14267
|
+
while (offset < size) {
|
|
14268
|
+
const n = (0, import_node_fs13.readSync)(fd, buffer, offset, size - offset, offset);
|
|
14269
|
+
if (n === 0) break;
|
|
14270
|
+
offset += n;
|
|
14271
|
+
}
|
|
14272
|
+
return buffer.subarray(0, offset);
|
|
14273
|
+
} finally {
|
|
14274
|
+
closeOpened(fd);
|
|
14275
|
+
}
|
|
14276
|
+
}
|
|
14277
|
+
function readOpenedUtf8(fd, size) {
|
|
14278
|
+
return readOpened(fd, size).toString("utf-8");
|
|
14279
|
+
}
|
|
14280
|
+
function readRegularFileInRoot(root, path, maxBytes) {
|
|
14281
|
+
const opened = openRegularInRoot(root, path);
|
|
14282
|
+
if (!opened.ok) return opened;
|
|
14283
|
+
if (opened.size > maxBytes) {
|
|
14284
|
+
closeOpened(opened.fd);
|
|
14285
|
+
return { ok: false, reason: "too-large", size: opened.size };
|
|
14286
|
+
}
|
|
14287
|
+
try {
|
|
14288
|
+
return { ok: true, content: readOpenedUtf8(opened.fd, opened.size), size: opened.size };
|
|
14289
|
+
} catch {
|
|
14290
|
+
return { ok: false, reason: "unreadable" };
|
|
14291
|
+
}
|
|
14292
|
+
}
|
|
14293
|
+
|
|
14294
|
+
// src/lib/knowledge-score.ts
|
|
14295
|
+
var KIND_PRIOR_MEAN = {
|
|
14296
|
+
decision: 0.78,
|
|
14297
|
+
pattern: 0.89,
|
|
14298
|
+
security: 0.8,
|
|
14299
|
+
quality: 0.71,
|
|
14300
|
+
integration: 0.71,
|
|
14301
|
+
domain: 0.71,
|
|
14302
|
+
gotcha: 0.53,
|
|
14303
|
+
intent: 0.53
|
|
14304
|
+
};
|
|
14305
|
+
var DEFAULT_PRIOR_MEAN = 0.6;
|
|
14306
|
+
var PRIOR_STRENGTH = 2;
|
|
14307
|
+
var RELEVANCE_FLOOR = 0.15;
|
|
14308
|
+
var TAG_SATURATION = 1.5;
|
|
14309
|
+
var STOPWORDS = /* @__PURE__ */ new Set([
|
|
14310
|
+
"the",
|
|
14311
|
+
"and",
|
|
14312
|
+
"for",
|
|
14313
|
+
"are",
|
|
14314
|
+
"but",
|
|
14315
|
+
"not",
|
|
14316
|
+
"you",
|
|
14317
|
+
"all",
|
|
14318
|
+
"any",
|
|
14319
|
+
"can",
|
|
14320
|
+
"had",
|
|
14321
|
+
"has",
|
|
14322
|
+
"her",
|
|
14323
|
+
"was",
|
|
14324
|
+
"one",
|
|
14325
|
+
"our",
|
|
14326
|
+
"out",
|
|
14327
|
+
"him",
|
|
14328
|
+
"his",
|
|
14329
|
+
"how",
|
|
14330
|
+
"its",
|
|
14331
|
+
"may",
|
|
14332
|
+
"who",
|
|
14333
|
+
"did",
|
|
14334
|
+
"get",
|
|
14335
|
+
"got",
|
|
14336
|
+
"let",
|
|
14337
|
+
"say",
|
|
14338
|
+
"she",
|
|
14339
|
+
"too",
|
|
14340
|
+
"use",
|
|
14341
|
+
"via",
|
|
14342
|
+
"yes",
|
|
14343
|
+
"yet",
|
|
14344
|
+
"now",
|
|
14345
|
+
"new",
|
|
14346
|
+
"also",
|
|
14347
|
+
"been",
|
|
14348
|
+
"both",
|
|
14349
|
+
"does",
|
|
14350
|
+
"each",
|
|
14351
|
+
"from",
|
|
14352
|
+
"have",
|
|
14353
|
+
"here",
|
|
14354
|
+
"into",
|
|
14355
|
+
"just",
|
|
14356
|
+
"like",
|
|
14357
|
+
"make",
|
|
14358
|
+
"more",
|
|
14359
|
+
"most",
|
|
14360
|
+
"much",
|
|
14361
|
+
"must",
|
|
14362
|
+
"need",
|
|
14363
|
+
"only",
|
|
14364
|
+
"over",
|
|
14365
|
+
"same",
|
|
14366
|
+
"some",
|
|
14367
|
+
"such",
|
|
14368
|
+
"than",
|
|
14369
|
+
"that",
|
|
14370
|
+
"them",
|
|
14371
|
+
"then",
|
|
14372
|
+
"there",
|
|
14373
|
+
"these",
|
|
14374
|
+
"they",
|
|
14375
|
+
"this",
|
|
14376
|
+
"those",
|
|
14377
|
+
"very",
|
|
14378
|
+
"want",
|
|
14379
|
+
"were",
|
|
14380
|
+
"what",
|
|
14381
|
+
"when",
|
|
14382
|
+
"where",
|
|
14383
|
+
"which",
|
|
14384
|
+
"while",
|
|
14385
|
+
"will",
|
|
14386
|
+
"with",
|
|
14387
|
+
"would",
|
|
14388
|
+
"your",
|
|
14389
|
+
"about",
|
|
14390
|
+
"after",
|
|
14391
|
+
"again",
|
|
14392
|
+
"being",
|
|
14393
|
+
"could",
|
|
14394
|
+
"other",
|
|
14395
|
+
"should",
|
|
14396
|
+
"their",
|
|
14397
|
+
"because",
|
|
14398
|
+
"before",
|
|
14399
|
+
"doing",
|
|
14400
|
+
"going",
|
|
14401
|
+
"still",
|
|
14402
|
+
"think",
|
|
14403
|
+
"thing",
|
|
14404
|
+
"things",
|
|
14405
|
+
"well",
|
|
14406
|
+
"way",
|
|
14407
|
+
"why",
|
|
14408
|
+
"within",
|
|
14409
|
+
"without"
|
|
14410
|
+
]);
|
|
14211
14411
|
function tokenize(text) {
|
|
14212
14412
|
return new Set(
|
|
14213
|
-
text.toLowerCase().replace(/[^a-z0-9\s]/g, " ").split(/\s+/).filter((w) => w.length > 2)
|
|
14413
|
+
text.toLowerCase().replace(/[^a-z0-9\s]/g, " ").split(/\s+/).filter((w) => w.length > 2 && !STOPWORDS.has(w))
|
|
14214
14414
|
);
|
|
14215
14415
|
}
|
|
14216
14416
|
function jaccardKeywords(a, b) {
|
|
@@ -14220,6 +14420,78 @@ function jaccardKeywords(a, b) {
|
|
|
14220
14420
|
const union = a.size + b.size - inter;
|
|
14221
14421
|
return union === 0 ? 0 : inter / union;
|
|
14222
14422
|
}
|
|
14423
|
+
function relevance(node, ctx) {
|
|
14424
|
+
const globHit = node.globHit === true;
|
|
14425
|
+
let tagScore = 0;
|
|
14426
|
+
const nodeTags = node.context_tags ?? [];
|
|
14427
|
+
if (nodeTags.length > 0 && ctx.changeTags && ctx.changeTags.length > 0) {
|
|
14428
|
+
const change = new Set(ctx.changeTags);
|
|
14429
|
+
let hit = 0;
|
|
14430
|
+
for (const t of nodeTags) {
|
|
14431
|
+
if (!change.has(t)) continue;
|
|
14432
|
+
hit += t.startsWith("pkg:") || t.startsWith("tbl:") ? 1 : t.startsWith("sym:") ? 0.8 : t.startsWith("dir:") ? 0.4 : 0.15;
|
|
14433
|
+
}
|
|
14434
|
+
tagScore = Math.min(1, hit / TAG_SATURATION);
|
|
14435
|
+
}
|
|
14436
|
+
let textScore = 0;
|
|
14437
|
+
if (ctx.promptTokens && ctx.promptTokens.size > 0) {
|
|
14438
|
+
textScore = jaccardKeywords(tokenize(`${node.title} ${node.body}`), ctx.promptTokens);
|
|
14439
|
+
textScore = Math.min(1, textScore * 4);
|
|
14440
|
+
}
|
|
14441
|
+
const distance = node.distance ?? 0;
|
|
14442
|
+
const hopScore = distance > 0 ? Math.min(1, node.hopWeight ?? 1) * 0.45 * Math.pow(0.6, distance - 1) : 0;
|
|
14443
|
+
const globEvidence = globHit && (node.kind !== "integration" || tagScore > 0 || textScore > 0);
|
|
14444
|
+
const evidence2 = [globEvidence ? 0.85 : 0, tagScore * 0.9, textScore * 0.7, hopScore];
|
|
14445
|
+
let miss = 1;
|
|
14446
|
+
for (const e of evidence2) miss *= 1 - Math.max(0, Math.min(1, e));
|
|
14447
|
+
let score = 1 - miss;
|
|
14448
|
+
if (distance > 0) score *= Math.pow(0.85, distance);
|
|
14449
|
+
return { score, via: { glob: globHit, tag: tagScore, text: textScore } };
|
|
14450
|
+
}
|
|
14451
|
+
var KIND_POOL_STRENGTH = 20;
|
|
14452
|
+
function priorFor(kind, pooled) {
|
|
14453
|
+
const base = KIND_PRIOR_MEAN[kind] ?? DEFAULT_PRIOR_MEAN;
|
|
14454
|
+
const a = pooled ? Math.max(0, pooled.alpha) : 0;
|
|
14455
|
+
const b = pooled ? Math.max(0, pooled.beta) : 0;
|
|
14456
|
+
const mean = pooled && kind !== "integration" ? (KIND_POOL_STRENGTH * base + a) / (KIND_POOL_STRENGTH + a + b) : base;
|
|
14457
|
+
return { alpha: mean * PRIOR_STRENGTH, beta: (1 - mean) * PRIOR_STRENGTH };
|
|
14458
|
+
}
|
|
14459
|
+
function posteriorFor(kind, own, pooled) {
|
|
14460
|
+
const p = priorFor(kind, pooled);
|
|
14461
|
+
if (!own || kind === "integration") return p;
|
|
14462
|
+
return { alpha: p.alpha + Math.max(0, own.alpha), beta: p.beta + Math.max(0, own.beta) };
|
|
14463
|
+
}
|
|
14464
|
+
function posteriorMean(p) {
|
|
14465
|
+
const n = p.alpha + p.beta;
|
|
14466
|
+
return n <= 0 ? DEFAULT_PRIOR_MEAN : p.alpha / n;
|
|
14467
|
+
}
|
|
14468
|
+
function scoreCandidates(nodes, ctx, opts = {}) {
|
|
14469
|
+
const floor = opts.relevanceFloor ?? RELEVANCE_FLOOR;
|
|
14470
|
+
const out = [];
|
|
14471
|
+
for (const n of nodes) {
|
|
14472
|
+
const rel = relevance(n, ctx);
|
|
14473
|
+
if (rel.score < floor) continue;
|
|
14474
|
+
const post = posteriorFor(n.kind, opts.posteriors?.get(n.id), opts.kindPosteriors?.get(n.kind));
|
|
14475
|
+
const usefulness = posteriorMean(post);
|
|
14476
|
+
out.push({ id: n.id, score: rel.score * usefulness, relevance: rel.score, usefulness, via: rel.via });
|
|
14477
|
+
}
|
|
14478
|
+
out.sort((a, b) => b.score - a.score || (a.id < b.id ? -1 : a.id > b.id ? 1 : 0));
|
|
14479
|
+
return out;
|
|
14480
|
+
}
|
|
14481
|
+
|
|
14482
|
+
// src/lib/memory-retrieval.ts
|
|
14483
|
+
var memoryDir = () => projectPath(`${VERITY_DIR}/memory`);
|
|
14484
|
+
var DOMAINS = ["decisions", "quality", "security", "intent", "gotchas", "patterns", "domain", "integrations"];
|
|
14485
|
+
var DEFAULT_BUDGET_TOKENS = 2e3;
|
|
14486
|
+
var MAX_BUDGET_TOKENS = 4e3;
|
|
14487
|
+
var MAX_NODE_FILE_BYTES = 64 * 1024;
|
|
14488
|
+
var MIN_SCORE = RELEVANCE_FLOOR * 0.5;
|
|
14489
|
+
var ORG_MIN_SHARED_TERMS = 2;
|
|
14490
|
+
function orgTerms(text) {
|
|
14491
|
+
return new Set(
|
|
14492
|
+
text.toLowerCase().replace(/[^a-z0-9\s]/g, " ").split(/\s+/).filter((w) => w.length > 2)
|
|
14493
|
+
);
|
|
14494
|
+
}
|
|
14223
14495
|
function sharedTerms(a, b) {
|
|
14224
14496
|
let n = 0;
|
|
14225
14497
|
for (const w of a) if (b.has(w)) n++;
|
|
@@ -14248,34 +14520,27 @@ function globMatch(glob, filePath) {
|
|
|
14248
14520
|
return false;
|
|
14249
14521
|
}
|
|
14250
14522
|
function scoreNode(node, promptTokens, taskFiles) {
|
|
14251
|
-
|
|
14252
|
-
|
|
14253
|
-
|
|
14254
|
-
|
|
14255
|
-
|
|
14256
|
-
|
|
14257
|
-
|
|
14258
|
-
|
|
14259
|
-
|
|
14260
|
-
|
|
14261
|
-
|
|
14262
|
-
|
|
14263
|
-
|
|
14264
|
-
|
|
14265
|
-
|
|
14266
|
-
|
|
14267
|
-
|
|
14268
|
-
|
|
14269
|
-
|
|
14270
|
-
|
|
14271
|
-
|
|
14272
|
-
integration: 0.3,
|
|
14273
|
-
domain: 0.2,
|
|
14274
|
-
quality: 0.1,
|
|
14275
|
-
intent: 0.1
|
|
14276
|
-
};
|
|
14277
|
-
score += kindPriors[node.kind] ?? 0;
|
|
14278
|
-
return score;
|
|
14523
|
+
const globHit = node.fileGlobs.length > 0 && taskFiles.length > 0 && node.fileGlobs.some((glob) => taskFiles.some((file) => globMatch(glob, file)));
|
|
14524
|
+
const [scored] = scoreCandidates(
|
|
14525
|
+
[{
|
|
14526
|
+
id: node.nodeId,
|
|
14527
|
+
kind: node.kind,
|
|
14528
|
+
title: node.title,
|
|
14529
|
+
body: node.body,
|
|
14530
|
+
file_globs: node.fileGlobs,
|
|
14531
|
+
// Not yet synced to the client graph; absent means "no tag evidence",
|
|
14532
|
+
// never "excluded" (KL18).
|
|
14533
|
+
context_tags: [],
|
|
14534
|
+
globHit
|
|
14535
|
+
}],
|
|
14536
|
+
{ promptTokens }
|
|
14537
|
+
// ⚠ The gate is on RELEVANCE, as on the server. This once passed
|
|
14538
|
+
// `relevanceFloor: 0` and left MIN_SCORE (on the product) as the only
|
|
14539
|
+
// filter, so a sub-floor match rode a strong kind prior past it: 30% of
|
|
14540
|
+
// replayed injections had r < RELEVANCE_FLOOR. MIN_SCORE stays as a second
|
|
14541
|
+
// guard for a very weak kind; it can no longer admit what the gate refused.
|
|
14542
|
+
);
|
|
14543
|
+
return scored?.score ?? 0;
|
|
14279
14544
|
}
|
|
14280
14545
|
function parseFrontmatter(content) {
|
|
14281
14546
|
const match = content.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
|
|
@@ -14315,20 +14580,22 @@ function parseFrontmatter(content) {
|
|
|
14315
14580
|
return { fm, body: match[2].trim() };
|
|
14316
14581
|
}
|
|
14317
14582
|
async function retrieveForInjection(promptText, taskFiles = [], budgetTokens = DEFAULT_BUDGET_TOKENS) {
|
|
14318
|
-
const hasRepoGraph = (0,
|
|
14583
|
+
const hasRepoGraph = (0, import_node_fs14.existsSync)(memoryDir());
|
|
14319
14584
|
const budget = Math.min(budgetTokens, MAX_BUDGET_TOKENS);
|
|
14320
14585
|
const promptTokens = tokenize(promptText);
|
|
14586
|
+
const orgPromptTerms = orgTerms(promptText);
|
|
14321
14587
|
const nodes = [];
|
|
14322
14588
|
for (const domain of hasRepoGraph ? DOMAINS : []) {
|
|
14323
|
-
const domainDir = (0,
|
|
14324
|
-
if (!(0,
|
|
14589
|
+
const domainDir = (0, import_node_path14.join)(memoryDir(), domain);
|
|
14590
|
+
if (!(0, import_node_fs14.existsSync)(domainDir)) continue;
|
|
14325
14591
|
try {
|
|
14326
14592
|
const files = await (0, import_promises8.readdir)(domainDir);
|
|
14327
14593
|
for (const file of files) {
|
|
14328
14594
|
if (!file.endsWith(".md")) continue;
|
|
14329
14595
|
try {
|
|
14330
|
-
const
|
|
14331
|
-
|
|
14596
|
+
const read = readRegularFileInRoot(memoryDir(), `${domain}/${file}`, MAX_NODE_FILE_BYTES);
|
|
14597
|
+
if (!read.ok) continue;
|
|
14598
|
+
const { fm, body } = parseFrontmatter(read.content);
|
|
14332
14599
|
if (fm.status && fm.status !== "active") continue;
|
|
14333
14600
|
nodes.push({
|
|
14334
14601
|
path: `${domain}/${file}`,
|
|
@@ -14350,7 +14617,7 @@ async function retrieveForInjection(promptText, taskFiles = [], budgetTokens = D
|
|
|
14350
14617
|
try {
|
|
14351
14618
|
for (const claim of await readOrgMirror()) {
|
|
14352
14619
|
const local = orgNodeToLocal(claim);
|
|
14353
|
-
if (sharedTerms(
|
|
14620
|
+
if (sharedTerms(orgTerms(`${local.title} ${local.body}`), orgPromptTerms) >= ORG_MIN_SHARED_TERMS) nodes.push(local);
|
|
14354
14621
|
}
|
|
14355
14622
|
} catch {
|
|
14356
14623
|
}
|
|
@@ -14388,19 +14655,216 @@ async function retrieveForInjection(promptText, taskFiles = [], budgetTokens = D
|
|
|
14388
14655
|
return {
|
|
14389
14656
|
nodes: selected,
|
|
14390
14657
|
contextBlock: lines.join("\n"),
|
|
14391
|
-
tokensUsed
|
|
14658
|
+
tokensUsed,
|
|
14659
|
+
eligible: filtered.length
|
|
14392
14660
|
};
|
|
14393
14661
|
}
|
|
14394
14662
|
|
|
14395
|
-
// src/lib/
|
|
14396
|
-
var import_promises9 = require("node:fs/promises");
|
|
14663
|
+
// src/lib/injection-record.ts
|
|
14397
14664
|
var import_node_fs16 = require("node:fs");
|
|
14398
|
-
var import_node_path15 = require("node:path");
|
|
14399
14665
|
var import_node_crypto3 = require("node:crypto");
|
|
14400
14666
|
|
|
14667
|
+
// src/lib/safe-write.ts
|
|
14668
|
+
var import_node_fs15 = require("node:fs");
|
|
14669
|
+
var import_node_path15 = require("node:path");
|
|
14670
|
+
var FLAGS2 = import_node_fs15.constants;
|
|
14671
|
+
var O_NOFOLLOW = FLAGS2.O_NOFOLLOW ?? 0;
|
|
14672
|
+
var NOFOLLOW_AVAILABLE = O_NOFOLLOW !== 0;
|
|
14673
|
+
function validateRoot(root) {
|
|
14674
|
+
try {
|
|
14675
|
+
const parentReal = (0, import_node_fs15.realpathSync)((0, import_node_path15.dirname)(root));
|
|
14676
|
+
const expected = (0, import_node_path15.join)(parentReal, (0, import_node_path15.basename)(root));
|
|
14677
|
+
try {
|
|
14678
|
+
(0, import_node_fs15.mkdirSync)(expected);
|
|
14679
|
+
} catch (e) {
|
|
14680
|
+
if (e.code !== "EEXIST") return null;
|
|
14681
|
+
}
|
|
14682
|
+
const st = (0, import_node_fs15.lstatSync)(expected, { bigint: true });
|
|
14683
|
+
if (st.isSymbolicLink() || !st.isDirectory()) return null;
|
|
14684
|
+
if ((0, import_node_fs15.realpathSync)(expected) !== expected) return null;
|
|
14685
|
+
return { real: expected, dev: st.dev, ino: st.ino };
|
|
14686
|
+
} catch {
|
|
14687
|
+
return null;
|
|
14688
|
+
}
|
|
14689
|
+
}
|
|
14690
|
+
function rootUnchanged(root) {
|
|
14691
|
+
try {
|
|
14692
|
+
const st = (0, import_node_fs15.lstatSync)(root.real, { bigint: true });
|
|
14693
|
+
return !st.isSymbolicLink() && st.isDirectory() && st.dev === root.dev && st.ino === root.ino;
|
|
14694
|
+
} catch {
|
|
14695
|
+
return false;
|
|
14696
|
+
}
|
|
14697
|
+
}
|
|
14698
|
+
function bareName(name) {
|
|
14699
|
+
return !!name && name === (0, import_node_path15.basename)(name) && name !== "." && name !== ".." && !name.includes("\0");
|
|
14700
|
+
}
|
|
14701
|
+
function absentOrRegular(path) {
|
|
14702
|
+
try {
|
|
14703
|
+
const st = (0, import_node_fs15.lstatSync)(path);
|
|
14704
|
+
return st.isFile() && !st.isSymbolicLink();
|
|
14705
|
+
} catch (e) {
|
|
14706
|
+
return e.code === "ENOENT";
|
|
14707
|
+
}
|
|
14708
|
+
}
|
|
14709
|
+
function verifyOpened(fd, path, root) {
|
|
14710
|
+
try {
|
|
14711
|
+
const opened = (0, import_node_fs15.fstatSync)(fd, { bigint: true });
|
|
14712
|
+
if (!opened.isFile() || opened.nlink !== 1n) return false;
|
|
14713
|
+
const real = (0, import_node_fs15.realpathSync)(path);
|
|
14714
|
+
if (!isInsideRoot(root.real, real)) return false;
|
|
14715
|
+
const current = (0, import_node_fs15.statSync)(real, { bigint: true });
|
|
14716
|
+
if (!sameOpenedFile(opened, current, NOFOLLOW_AVAILABLE)) return false;
|
|
14717
|
+
return rootUnchanged(root);
|
|
14718
|
+
} catch {
|
|
14719
|
+
return false;
|
|
14720
|
+
}
|
|
14721
|
+
}
|
|
14722
|
+
function removeIfOurs(fd, path) {
|
|
14723
|
+
try {
|
|
14724
|
+
const opened = (0, import_node_fs15.fstatSync)(fd, { bigint: true });
|
|
14725
|
+
const at = (0, import_node_fs15.lstatSync)(path, { bigint: true });
|
|
14726
|
+
if (!at.isSymbolicLink() && at.dev === opened.dev && at.ino === opened.ino) (0, import_node_fs15.unlinkSync)(path);
|
|
14727
|
+
} catch {
|
|
14728
|
+
}
|
|
14729
|
+
}
|
|
14730
|
+
function openTarget(path, append2) {
|
|
14731
|
+
const base = import_node_fs15.constants.O_WRONLY | (append2 ? import_node_fs15.constants.O_APPEND : 0) | O_NOFOLLOW;
|
|
14732
|
+
try {
|
|
14733
|
+
return { fd: (0, import_node_fs15.openSync)(path, base), created: false };
|
|
14734
|
+
} catch (e) {
|
|
14735
|
+
if (e.code !== "ENOENT") return null;
|
|
14736
|
+
}
|
|
14737
|
+
try {
|
|
14738
|
+
return { fd: (0, import_node_fs15.openSync)(path, base | import_node_fs15.constants.O_CREAT | import_node_fs15.constants.O_EXCL, 384), created: true };
|
|
14739
|
+
} catch {
|
|
14740
|
+
return null;
|
|
14741
|
+
}
|
|
14742
|
+
}
|
|
14743
|
+
function writeVerified(root, name, hooks, append2, write) {
|
|
14744
|
+
const r = validateRoot(root);
|
|
14745
|
+
if (!r || !bareName(name)) return false;
|
|
14746
|
+
const path = (0, import_node_path15.join)(r.real, name);
|
|
14747
|
+
if (!absentOrRegular(path)) return false;
|
|
14748
|
+
if (!runHook(hooks)) return false;
|
|
14749
|
+
const opened = openTarget(path, append2);
|
|
14750
|
+
if (!opened) return false;
|
|
14751
|
+
try {
|
|
14752
|
+
if (!verifyOpened(opened.fd, path, r)) {
|
|
14753
|
+
if (opened.created) removeIfOurs(opened.fd, path);
|
|
14754
|
+
return false;
|
|
14755
|
+
}
|
|
14756
|
+
write(opened.fd);
|
|
14757
|
+
return true;
|
|
14758
|
+
} catch {
|
|
14759
|
+
return false;
|
|
14760
|
+
} finally {
|
|
14761
|
+
try {
|
|
14762
|
+
(0, import_node_fs15.closeSync)(opened.fd);
|
|
14763
|
+
} catch {
|
|
14764
|
+
}
|
|
14765
|
+
}
|
|
14766
|
+
}
|
|
14767
|
+
function runHook(hooks) {
|
|
14768
|
+
try {
|
|
14769
|
+
hooks.afterRootValidated?.();
|
|
14770
|
+
return true;
|
|
14771
|
+
} catch {
|
|
14772
|
+
return false;
|
|
14773
|
+
}
|
|
14774
|
+
}
|
|
14775
|
+
function appendInRoot(root, name, text, hooks = {}) {
|
|
14776
|
+
return writeVerified(root, name, hooks, true, (fd) => {
|
|
14777
|
+
(0, import_node_fs15.writeSync)(fd, text);
|
|
14778
|
+
});
|
|
14779
|
+
}
|
|
14780
|
+
function replaceInRoot(root, name, text, hooks = {}) {
|
|
14781
|
+
return writeVerified(root, name, hooks, false, (fd) => {
|
|
14782
|
+
(0, import_node_fs15.ftruncateSync)(fd, 0);
|
|
14783
|
+
(0, import_node_fs15.writeSync)(fd, text, 0);
|
|
14784
|
+
});
|
|
14785
|
+
}
|
|
14786
|
+
|
|
14787
|
+
// src/lib/injection-record.ts
|
|
14788
|
+
var MAX_PENDING = 200;
|
|
14789
|
+
var MAX_RECORD_BYTES = 1024 * 1024;
|
|
14790
|
+
var COMPACT_AT_BYTES = 256 * 1024;
|
|
14791
|
+
var MAX_NODES = 50;
|
|
14792
|
+
var SAFE_ID = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/;
|
|
14793
|
+
var VIA = /^[A-Za-z0-9_+,:.-]{0,40}$/;
|
|
14794
|
+
var PROMPT_HASH = /^[0-9a-f]{16}$/;
|
|
14795
|
+
var nonNegInt = (v, max) => typeof v === "number" && Number.isInteger(v) && v >= 0 && v <= max;
|
|
14796
|
+
function parseInjectionEvent(raw) {
|
|
14797
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return null;
|
|
14798
|
+
const o = raw;
|
|
14799
|
+
if (typeof o.ts !== "number" || !Number.isFinite(o.ts) || o.ts <= 0 || o.ts > 1e13) return null;
|
|
14800
|
+
if (!(o.session_id === null || typeof o.session_id === "string" && SAFE_ID.test(o.session_id))) return null;
|
|
14801
|
+
if (typeof o.prompt_hash !== "string" || !PROMPT_HASH.test(o.prompt_hash)) return null;
|
|
14802
|
+
if (o.arm !== "injected" && o.arm !== "withheld") return null;
|
|
14803
|
+
if (!nonNegInt(o.eligible, 1e5) || !nonNegInt(o.tokens, 1e6)) return null;
|
|
14804
|
+
if (!Array.isArray(o.nodes) || o.nodes.length > MAX_NODES) return null;
|
|
14805
|
+
const nodes = [];
|
|
14806
|
+
for (const n of o.nodes) {
|
|
14807
|
+
if (!n || typeof n !== "object") return null;
|
|
14808
|
+
const r = n;
|
|
14809
|
+
if (typeof r.id !== "string" || !SAFE_ID.test(r.id)) return null;
|
|
14810
|
+
if (typeof r.score !== "number" || !Number.isFinite(r.score) || r.score < 0 || r.score > 10) return null;
|
|
14811
|
+
if (typeof r.via !== "string" || !VIA.test(r.via)) return null;
|
|
14812
|
+
nodes.push({ id: r.id, score: r.score, via: r.via });
|
|
14813
|
+
}
|
|
14814
|
+
return {
|
|
14815
|
+
ts: o.ts,
|
|
14816
|
+
session_id: o.session_id,
|
|
14817
|
+
prompt_hash: o.prompt_hash,
|
|
14818
|
+
arm: o.arm,
|
|
14819
|
+
nodes,
|
|
14820
|
+
eligible: o.eligible,
|
|
14821
|
+
tokens: o.tokens
|
|
14822
|
+
};
|
|
14823
|
+
}
|
|
14824
|
+
var recordPath = () => projectPath(`${VERITY_DIR}/injections.jsonl`);
|
|
14825
|
+
function hashPrompt(prompt) {
|
|
14826
|
+
return (0, import_node_crypto3.createHash)("sha256").update(prompt).digest("hex").slice(0, 16);
|
|
14827
|
+
}
|
|
14828
|
+
function recordInjection(event) {
|
|
14829
|
+
if (!appendInRoot(projectPath(VERITY_DIR), "injections.jsonl", JSON.stringify(event) + "\n")) return;
|
|
14830
|
+
try {
|
|
14831
|
+
if ((0, import_node_fs16.lstatSync)(recordPath()).size > COMPACT_AT_BYTES) writeEvents(readPendingInjections());
|
|
14832
|
+
} catch {
|
|
14833
|
+
}
|
|
14834
|
+
}
|
|
14835
|
+
function writeEvents(events) {
|
|
14836
|
+
replaceInRoot(projectPath(VERITY_DIR), "injections.jsonl", events.map((e) => JSON.stringify(e)).join("\n") + (events.length ? "\n" : ""));
|
|
14837
|
+
}
|
|
14838
|
+
function readPendingInjections() {
|
|
14839
|
+
try {
|
|
14840
|
+
const p = recordPath();
|
|
14841
|
+
if (!(0, import_node_fs16.existsSync)(p)) return [];
|
|
14842
|
+
const read = readRegularFileInRoot(projectPath(VERITY_DIR), "injections.jsonl", MAX_RECORD_BYTES);
|
|
14843
|
+
if (!read.ok) return [];
|
|
14844
|
+
const out = [];
|
|
14845
|
+
for (const line of read.content.split("\n")) {
|
|
14846
|
+
if (!line.trim()) continue;
|
|
14847
|
+
try {
|
|
14848
|
+
const e = parseInjectionEvent(JSON.parse(line));
|
|
14849
|
+
if (e) out.push(e);
|
|
14850
|
+
} catch {
|
|
14851
|
+
}
|
|
14852
|
+
}
|
|
14853
|
+
return out.slice(-MAX_PENDING);
|
|
14854
|
+
} catch {
|
|
14855
|
+
return [];
|
|
14856
|
+
}
|
|
14857
|
+
}
|
|
14858
|
+
|
|
14859
|
+
// src/lib/memory-sync.ts
|
|
14860
|
+
var import_promises9 = require("node:fs/promises");
|
|
14861
|
+
var import_node_fs19 = require("node:fs");
|
|
14862
|
+
var import_node_path17 = require("node:path");
|
|
14863
|
+
var import_node_crypto4 = require("node:crypto");
|
|
14864
|
+
|
|
14401
14865
|
// src/lib/gitignore.ts
|
|
14402
14866
|
var import_node_child_process6 = require("node:child_process");
|
|
14403
|
-
var
|
|
14867
|
+
var import_node_fs17 = require("node:fs");
|
|
14404
14868
|
var VERITY_GITIGNORE_MARKER = "# Verity \u2014 machine-local state.";
|
|
14405
14869
|
var SETTINGS_LOCAL_IGNORE_ENTRY = ".claude/settings.local.json";
|
|
14406
14870
|
var VERITY_GITIGNORE_BLOCK = [
|
|
@@ -14484,7 +14948,7 @@ function fenceMemoryLines(lines) {
|
|
|
14484
14948
|
function ensureVerityGitignore() {
|
|
14485
14949
|
let content = "";
|
|
14486
14950
|
try {
|
|
14487
|
-
content = (0,
|
|
14951
|
+
content = (0, import_node_fs17.readFileSync)(".gitignore", "utf-8");
|
|
14488
14952
|
} catch {
|
|
14489
14953
|
}
|
|
14490
14954
|
const hasMarker = content.includes(VERITY_GITIGNORE_MARKER);
|
|
@@ -14511,7 +14975,7 @@ function ensureVerityGitignore() {
|
|
|
14511
14975
|
const sep4 = text === "" ? "" : text.endsWith("\n") ? "\n" : "\n\n";
|
|
14512
14976
|
text = text + sep4 + VERITY_GITIGNORE_BLOCK;
|
|
14513
14977
|
}
|
|
14514
|
-
if (text !== content) (0,
|
|
14978
|
+
if (text !== content) (0, import_node_fs17.writeFileSync)(".gitignore", text);
|
|
14515
14979
|
return verified(
|
|
14516
14980
|
memoryIsCommitted ? "memory-tracked" : hasSupersededMemory ? "memory-fenced" : needsRepair ? "repaired" : "added"
|
|
14517
14981
|
);
|
|
@@ -14531,7 +14995,7 @@ function untrackMemory() {
|
|
|
14531
14995
|
function writeFencedBlock() {
|
|
14532
14996
|
let content = "";
|
|
14533
14997
|
try {
|
|
14534
|
-
content = (0,
|
|
14998
|
+
content = (0, import_node_fs17.readFileSync)(".gitignore", "utf-8");
|
|
14535
14999
|
} catch {
|
|
14536
15000
|
}
|
|
14537
15001
|
const hasMarker = content.includes(VERITY_GITIGNORE_MARKER);
|
|
@@ -14543,7 +15007,7 @@ function writeFencedBlock() {
|
|
|
14543
15007
|
text = text + sep4 + VERITY_GITIGNORE_BLOCK;
|
|
14544
15008
|
}
|
|
14545
15009
|
try {
|
|
14546
|
-
(0,
|
|
15010
|
+
(0, import_node_fs17.writeFileSync)(".gitignore", text);
|
|
14547
15011
|
return true;
|
|
14548
15012
|
} catch {
|
|
14549
15013
|
return false;
|
|
@@ -14552,14 +15016,14 @@ function writeFencedBlock() {
|
|
|
14552
15016
|
function fenceMemory() {
|
|
14553
15017
|
let original = null;
|
|
14554
15018
|
try {
|
|
14555
|
-
original = (0,
|
|
15019
|
+
original = (0, import_node_fs17.readFileSync)(".gitignore", "utf-8");
|
|
14556
15020
|
} catch {
|
|
14557
15021
|
original = null;
|
|
14558
15022
|
}
|
|
14559
15023
|
const restore = () => {
|
|
14560
15024
|
try {
|
|
14561
|
-
if (original === null) (0,
|
|
14562
|
-
else (0,
|
|
15025
|
+
if (original === null) (0, import_node_fs17.rmSync)(".gitignore", { force: true });
|
|
15026
|
+
else (0, import_node_fs17.writeFileSync)(".gitignore", original);
|
|
14563
15027
|
} catch {
|
|
14564
15028
|
}
|
|
14565
15029
|
};
|
|
@@ -14577,7 +15041,7 @@ function fenceMemory() {
|
|
|
14577
15041
|
}
|
|
14578
15042
|
function memoryOptOut() {
|
|
14579
15043
|
try {
|
|
14580
|
-
return (0,
|
|
15044
|
+
return (0, import_node_fs17.readFileSync)(".gitignore", "utf-8").includes(MEMORY_OPT_OUT_MARKER);
|
|
14581
15045
|
} catch {
|
|
14582
15046
|
return false;
|
|
14583
15047
|
}
|
|
@@ -14585,13 +15049,13 @@ function memoryOptOut() {
|
|
|
14585
15049
|
function keepMemoryTracked() {
|
|
14586
15050
|
let content = "";
|
|
14587
15051
|
try {
|
|
14588
|
-
content = (0,
|
|
15052
|
+
content = (0, import_node_fs17.readFileSync)(".gitignore", "utf-8");
|
|
14589
15053
|
} catch {
|
|
14590
15054
|
}
|
|
14591
15055
|
if (content.includes(MEMORY_OPT_OUT_MARKER)) return "already";
|
|
14592
15056
|
try {
|
|
14593
15057
|
const sep4 = content === "" ? "" : content.endsWith("\n") ? "\n" : "\n\n";
|
|
14594
|
-
(0,
|
|
15058
|
+
(0, import_node_fs17.writeFileSync)(".gitignore", content + sep4 + MEMORY_OPT_OUT_STANZA);
|
|
14595
15059
|
} catch {
|
|
14596
15060
|
return "failed";
|
|
14597
15061
|
}
|
|
@@ -14626,26 +15090,26 @@ function untrackVerityState() {
|
|
|
14626
15090
|
}
|
|
14627
15091
|
|
|
14628
15092
|
// src/lib/safe-path.ts
|
|
14629
|
-
var
|
|
14630
|
-
var
|
|
15093
|
+
var import_node_fs18 = require("node:fs");
|
|
15094
|
+
var import_node_path16 = require("node:path");
|
|
14631
15095
|
function resolveInside(baseDir, candidate) {
|
|
14632
15096
|
if (typeof candidate !== "string" || candidate.length === 0) return null;
|
|
14633
|
-
if ((0,
|
|
14634
|
-
const baseAbs = (0,
|
|
14635
|
-
const full = (0,
|
|
14636
|
-
const baseSep = baseAbs.endsWith(
|
|
15097
|
+
if ((0, import_node_path16.isAbsolute)(candidate)) return null;
|
|
15098
|
+
const baseAbs = (0, import_node_path16.resolve)(baseDir);
|
|
15099
|
+
const full = (0, import_node_path16.resolve)(baseAbs, candidate);
|
|
15100
|
+
const baseSep = baseAbs.endsWith(import_node_path16.sep) ? baseAbs : baseAbs + import_node_path16.sep;
|
|
14637
15101
|
if (full !== baseAbs && !full.startsWith(baseSep)) return null;
|
|
14638
15102
|
try {
|
|
14639
|
-
if ((0,
|
|
14640
|
-
const realBase = (0,
|
|
14641
|
-
const realBaseSep = realBase.endsWith(
|
|
15103
|
+
if ((0, import_node_fs18.existsSync)(baseAbs)) {
|
|
15104
|
+
const realBase = (0, import_node_fs18.realpathSync)(baseAbs);
|
|
15105
|
+
const realBaseSep = realBase.endsWith(import_node_path16.sep) ? realBase : realBase + import_node_path16.sep;
|
|
14642
15106
|
let probe = full;
|
|
14643
|
-
while (!(0,
|
|
14644
|
-
const parent = (0,
|
|
15107
|
+
while (!(0, import_node_fs18.existsSync)(probe)) {
|
|
15108
|
+
const parent = (0, import_node_path16.dirname)(probe);
|
|
14645
15109
|
if (parent === probe) break;
|
|
14646
15110
|
probe = parent;
|
|
14647
15111
|
}
|
|
14648
|
-
const realProbe = (0,
|
|
15112
|
+
const realProbe = (0, import_node_fs18.realpathSync)(probe);
|
|
14649
15113
|
if (realProbe !== realBase && !realProbe.startsWith(realBaseSep)) return null;
|
|
14650
15114
|
}
|
|
14651
15115
|
} catch {
|
|
@@ -14653,37 +15117,37 @@ function resolveInside(baseDir, candidate) {
|
|
|
14653
15117
|
}
|
|
14654
15118
|
return full;
|
|
14655
15119
|
}
|
|
14656
|
-
var
|
|
15120
|
+
var O_NOFOLLOW2 = typeof import_node_fs18.constants.O_NOFOLLOW === "number" ? import_node_fs18.constants.O_NOFOLLOW : 0;
|
|
14657
15121
|
function readFileInside(baseDir, candidate, maxBytes) {
|
|
14658
15122
|
const full = resolveInside(baseDir, candidate);
|
|
14659
15123
|
if (!full) return null;
|
|
14660
15124
|
let realParent;
|
|
14661
15125
|
let realBase;
|
|
14662
15126
|
try {
|
|
14663
|
-
realParent = (0,
|
|
14664
|
-
realBase = (0,
|
|
15127
|
+
realParent = (0, import_node_fs18.realpathSync)((0, import_node_path16.dirname)(full));
|
|
15128
|
+
realBase = (0, import_node_fs18.realpathSync)((0, import_node_path16.resolve)(baseDir));
|
|
14665
15129
|
} catch {
|
|
14666
15130
|
return null;
|
|
14667
15131
|
}
|
|
14668
|
-
const realBaseSep = realBase.endsWith(
|
|
15132
|
+
const realBaseSep = realBase.endsWith(import_node_path16.sep) ? realBase : realBase + import_node_path16.sep;
|
|
14669
15133
|
if (realParent !== realBase && !realParent.startsWith(realBaseSep)) return null;
|
|
14670
|
-
const target = (0,
|
|
15134
|
+
const target = (0, import_node_path16.join)(realParent, (0, import_node_path16.basename)(full));
|
|
14671
15135
|
let fd = null;
|
|
14672
15136
|
try {
|
|
14673
|
-
fd = (0,
|
|
14674
|
-
const st = (0,
|
|
15137
|
+
fd = (0, import_node_fs18.openSync)(target, import_node_fs18.constants.O_RDONLY | O_NOFOLLOW2);
|
|
15138
|
+
const st = (0, import_node_fs18.fstatSync)(fd);
|
|
14675
15139
|
if (!st.isFile()) return null;
|
|
14676
15140
|
const cap = Math.min(maxBytes, st.size);
|
|
14677
15141
|
if (cap <= 0) return "";
|
|
14678
15142
|
const buf = Buffer.alloc(cap);
|
|
14679
|
-
const bytesRead = (0,
|
|
15143
|
+
const bytesRead = (0, import_node_fs18.readSync)(fd, buf, 0, cap, 0);
|
|
14680
15144
|
return buf.subarray(0, bytesRead).toString("utf-8");
|
|
14681
15145
|
} catch {
|
|
14682
15146
|
return null;
|
|
14683
15147
|
} finally {
|
|
14684
15148
|
if (fd !== null) {
|
|
14685
15149
|
try {
|
|
14686
|
-
(0,
|
|
15150
|
+
(0, import_node_fs18.closeSync)(fd);
|
|
14687
15151
|
} catch {
|
|
14688
15152
|
}
|
|
14689
15153
|
}
|
|
@@ -14766,35 +15230,35 @@ var syncStateFile = () => projectPath(`${VERITY_DIR}/.memory-sync-state.json`);
|
|
|
14766
15230
|
async function ensureMemoryDir() {
|
|
14767
15231
|
await (0, import_promises9.mkdir)(memoryDir2(), { recursive: true });
|
|
14768
15232
|
for (const domain of DOMAINS2) {
|
|
14769
|
-
await (0, import_promises9.mkdir)((0,
|
|
15233
|
+
await (0, import_promises9.mkdir)((0, import_node_path17.join)(memoryDir2(), domain), { recursive: true });
|
|
14770
15234
|
}
|
|
14771
|
-
if (!(0,
|
|
14772
|
-
await (0, import_promises9.writeFile)((0,
|
|
15235
|
+
if (!(0, import_node_fs19.existsSync)((0, import_node_path17.join)(memoryDir2(), "SCHEMA.md"))) {
|
|
15236
|
+
await (0, import_promises9.writeFile)((0, import_node_path17.join)(memoryDir2(), "SCHEMA.md"), SCHEMA_TEMPLATE);
|
|
14773
15237
|
}
|
|
14774
|
-
if (!(0,
|
|
14775
|
-
await (0, import_promises9.writeFile)((0,
|
|
15238
|
+
if (!(0, import_node_fs19.existsSync)((0, import_node_path17.join)(memoryDir2(), "index.md"))) {
|
|
15239
|
+
await (0, import_promises9.writeFile)((0, import_node_path17.join)(memoryDir2(), "index.md"), "# Project Memory Index\n\nNo nodes yet. Run an analysis to start building the knowledge graph.\n");
|
|
14776
15240
|
}
|
|
14777
|
-
if (!(0,
|
|
14778
|
-
await (0, import_promises9.writeFile)((0,
|
|
15241
|
+
if (!(0, import_node_fs19.existsSync)((0, import_node_path17.join)(memoryDir2(), "log.md"))) {
|
|
15242
|
+
await (0, import_promises9.writeFile)((0, import_node_path17.join)(memoryDir2(), "log.md"), "# Memory Log\n\n");
|
|
14779
15243
|
}
|
|
14780
15244
|
}
|
|
14781
15245
|
async function buildManifest() {
|
|
14782
|
-
if (!(0,
|
|
15246
|
+
if (!(0, import_node_fs19.existsSync)(memoryDir2())) {
|
|
14783
15247
|
return { schema_version: 1, nodes: [], index_hash: null, log_length: 0 };
|
|
14784
15248
|
}
|
|
14785
15249
|
const nodes = [];
|
|
14786
15250
|
for (const domain of DOMAINS2) {
|
|
14787
|
-
const domainDir = (0,
|
|
14788
|
-
if (!(0,
|
|
15251
|
+
const domainDir = (0, import_node_path17.join)(memoryDir2(), domain);
|
|
15252
|
+
if (!(0, import_node_fs19.existsSync)(domainDir)) continue;
|
|
14789
15253
|
try {
|
|
14790
15254
|
const files = await (0, import_promises9.readdir)(domainDir);
|
|
14791
15255
|
for (const file of files) {
|
|
14792
15256
|
if (!file.endsWith(".md")) continue;
|
|
14793
15257
|
const filePath = `${domain}/${file}`;
|
|
14794
|
-
const fullPath = (0,
|
|
15258
|
+
const fullPath = (0, import_node_path17.join)(memoryDir2(), filePath);
|
|
14795
15259
|
try {
|
|
14796
15260
|
const content = await (0, import_promises9.readFile)(fullPath, "utf-8");
|
|
14797
|
-
const hash = (0,
|
|
15261
|
+
const hash = (0, import_node_crypto4.createHash)("sha256").update(content).digest("hex").slice(0, 16);
|
|
14798
15262
|
nodes.push({ path: filePath, content_hash: `sha256:${hash}` });
|
|
14799
15263
|
} catch {
|
|
14800
15264
|
}
|
|
@@ -14804,32 +15268,32 @@ async function buildManifest() {
|
|
|
14804
15268
|
}
|
|
14805
15269
|
let indexHash = null;
|
|
14806
15270
|
try {
|
|
14807
|
-
const indexContent = await (0, import_promises9.readFile)((0,
|
|
14808
|
-
indexHash = `sha256:${(0,
|
|
15271
|
+
const indexContent = await (0, import_promises9.readFile)((0, import_node_path17.join)(memoryDir2(), "index.md"), "utf-8");
|
|
15272
|
+
indexHash = `sha256:${(0, import_node_crypto4.createHash)("sha256").update(indexContent).digest("hex").slice(0, 16)}`;
|
|
14809
15273
|
} catch {
|
|
14810
15274
|
}
|
|
14811
15275
|
let logLength = 0;
|
|
14812
15276
|
try {
|
|
14813
|
-
const logContent = await (0, import_promises9.readFile)((0,
|
|
15277
|
+
const logContent = await (0, import_promises9.readFile)((0, import_node_path17.join)(memoryDir2(), "log.md"), "utf-8");
|
|
14814
15278
|
logLength = logContent.split("\n").length;
|
|
14815
15279
|
} catch {
|
|
14816
15280
|
}
|
|
14817
15281
|
return { schema_version: 1, nodes, index_hash: indexHash, log_length: logLength };
|
|
14818
15282
|
}
|
|
14819
15283
|
function hashContent(content) {
|
|
14820
|
-
return `sha256:${(0,
|
|
15284
|
+
return `sha256:${(0, import_node_crypto4.createHash)("sha256").update(content).digest("hex").slice(0, 16)}`;
|
|
14821
15285
|
}
|
|
14822
15286
|
async function readOnDiskNodes() {
|
|
14823
15287
|
const out = /* @__PURE__ */ new Map();
|
|
14824
|
-
if (!(0,
|
|
15288
|
+
if (!(0, import_node_fs19.existsSync)(memoryDir2())) return out;
|
|
14825
15289
|
for (const domain of DOMAINS2) {
|
|
14826
|
-
const domainDir = (0,
|
|
14827
|
-
if (!(0,
|
|
15290
|
+
const domainDir = (0, import_node_path17.join)(memoryDir2(), domain);
|
|
15291
|
+
if (!(0, import_node_fs19.existsSync)(domainDir)) continue;
|
|
14828
15292
|
try {
|
|
14829
15293
|
for (const file of await (0, import_promises9.readdir)(domainDir)) {
|
|
14830
15294
|
if (!file.endsWith(".md")) continue;
|
|
14831
15295
|
try {
|
|
14832
|
-
out.set(`${domain}/${file}`, hashContent(await (0, import_promises9.readFile)((0,
|
|
15296
|
+
out.set(`${domain}/${file}`, hashContent(await (0, import_promises9.readFile)((0, import_node_path17.join)(domainDir, file), "utf-8")));
|
|
14833
15297
|
} catch {
|
|
14834
15298
|
}
|
|
14835
15299
|
}
|
|
@@ -14866,7 +15330,7 @@ async function recordSyncedNodePaths() {
|
|
|
14866
15330
|
}
|
|
14867
15331
|
}
|
|
14868
15332
|
async function writeFileAtomic(path, content) {
|
|
14869
|
-
await (0, import_promises9.mkdir)((0,
|
|
15333
|
+
await (0, import_promises9.mkdir)((0, import_node_path17.dirname)(path), { recursive: true });
|
|
14870
15334
|
const tmp = `${path}.${process.pid}.${Date.now()}.tmp`;
|
|
14871
15335
|
await (0, import_promises9.writeFile)(tmp, content);
|
|
14872
15336
|
await (0, import_promises9.rename)(tmp, path);
|
|
@@ -14880,8 +15344,8 @@ async function computeEditedNodeUploads() {
|
|
|
14880
15344
|
const uploads = [];
|
|
14881
15345
|
for (const [path, prevHash] of prev) {
|
|
14882
15346
|
if (prevHash == null) continue;
|
|
14883
|
-
const full = (0,
|
|
14884
|
-
if (!(0,
|
|
15347
|
+
const full = (0, import_node_path17.join)(memoryDir2(), path);
|
|
15348
|
+
if (!(0, import_node_fs19.existsSync)(full)) continue;
|
|
14885
15349
|
let content;
|
|
14886
15350
|
try {
|
|
14887
15351
|
content = await (0, import_promises9.readFile)(full, "utf-8");
|
|
@@ -14925,8 +15389,8 @@ async function applyMemoryWrites(writes, opts = {}) {
|
|
|
14925
15389
|
const logLines = [`- ${(/* @__PURE__ */ new Date()).toISOString().slice(0, 16)} \u2014 Applied ${count} write(s) from server`];
|
|
14926
15390
|
for (const n of notes) logLines.push(` - ${n}`);
|
|
14927
15391
|
try {
|
|
14928
|
-
const existing = (0,
|
|
14929
|
-
await (0, import_promises9.writeFile)((0,
|
|
15392
|
+
const existing = (0, import_node_fs19.existsSync)((0, import_node_path17.join)(memoryDir2(), "log.md")) ? await (0, import_promises9.readFile)((0, import_node_path17.join)(memoryDir2(), "log.md"), "utf-8") : "# Memory Log\n\n";
|
|
15393
|
+
await (0, import_promises9.writeFile)((0, import_node_path17.join)(memoryDir2(), "log.md"), existing + logLines.join("\n") + "\n");
|
|
14930
15394
|
} catch {
|
|
14931
15395
|
}
|
|
14932
15396
|
if (opts.baseline === "written") await mergeSyncBaseline(synced);
|
|
@@ -14936,7 +15400,7 @@ async function applyMemoryWrites(writes, opts = {}) {
|
|
|
14936
15400
|
async function mergeSyncBaseline(entries) {
|
|
14937
15401
|
if (entries.size === 0) return;
|
|
14938
15402
|
try {
|
|
14939
|
-
if ((0,
|
|
15403
|
+
if ((0, import_node_fs19.existsSync)(syncStateFile())) {
|
|
14940
15404
|
try {
|
|
14941
15405
|
JSON.parse(await (0, import_promises9.readFile)(syncStateFile(), "utf-8"));
|
|
14942
15406
|
} catch {
|
|
@@ -14964,7 +15428,7 @@ async function applyOneWrite(write, treePaths, lastServed) {
|
|
|
14964
15428
|
notes.push(`${write.path}: dropped unmatched file_globs [${grounded.dropped.join(", ")}]`);
|
|
14965
15429
|
}
|
|
14966
15430
|
}
|
|
14967
|
-
if ((0,
|
|
15431
|
+
if ((0, import_node_fs19.existsSync)(fullPath)) {
|
|
14968
15432
|
let existing = "";
|
|
14969
15433
|
try {
|
|
14970
15434
|
existing = await (0, import_promises9.readFile)(fullPath, "utf-8");
|
|
@@ -14980,7 +15444,7 @@ async function applyOneWrite(write, treePaths, lastServed) {
|
|
|
14980
15444
|
notes.push(`${write.path}: updated from server (untouched here since the server delivered it)`);
|
|
14981
15445
|
}
|
|
14982
15446
|
}
|
|
14983
|
-
await (0, import_promises9.mkdir)((0,
|
|
15447
|
+
await (0, import_promises9.mkdir)((0, import_node_path17.dirname)(fullPath), { recursive: true });
|
|
14984
15448
|
await (0, import_promises9.writeFile)(fullPath, content);
|
|
14985
15449
|
return { written: true, syncedHash: hashContent(content), notes };
|
|
14986
15450
|
}
|
|
@@ -15021,8 +15485,8 @@ async function regenerateIndex() {
|
|
|
15021
15485
|
];
|
|
15022
15486
|
let totalNodes = 0;
|
|
15023
15487
|
for (const domain of DOMAINS2.filter((d) => d !== "_archive")) {
|
|
15024
|
-
const domainDir = (0,
|
|
15025
|
-
if (!(0,
|
|
15488
|
+
const domainDir = (0, import_node_path17.join)(memoryDir2(), domain);
|
|
15489
|
+
if (!(0, import_node_fs19.existsSync)(domainDir)) continue;
|
|
15026
15490
|
try {
|
|
15027
15491
|
const files = await (0, import_promises9.readdir)(domainDir);
|
|
15028
15492
|
const mdFiles = files.filter((f) => f.endsWith(".md"));
|
|
@@ -15032,7 +15496,7 @@ async function regenerateIndex() {
|
|
|
15032
15496
|
for (const file of mdFiles.sort()) {
|
|
15033
15497
|
const slug = file.replace(/\.md$/, "");
|
|
15034
15498
|
try {
|
|
15035
|
-
const content = await (0, import_promises9.readFile)((0,
|
|
15499
|
+
const content = await (0, import_promises9.readFile)((0, import_node_path17.join)(domainDir, file), "utf-8");
|
|
15036
15500
|
const title = pickFrontmatter(content, "title") ?? slug;
|
|
15037
15501
|
const kind = pickFrontmatter(content, "kind") ?? "-";
|
|
15038
15502
|
const confidence = pickFrontmatter(content, "confidence");
|
|
@@ -15056,7 +15520,7 @@ async function regenerateIndex() {
|
|
|
15056
15520
|
lines.push("No nodes yet. Run an analysis to start building the knowledge graph.");
|
|
15057
15521
|
}
|
|
15058
15522
|
const next = lines.join("\n") + "\n";
|
|
15059
|
-
const indexPath = (0,
|
|
15523
|
+
const indexPath = (0, import_node_path17.join)(memoryDir2(), "index.md");
|
|
15060
15524
|
let existing = null;
|
|
15061
15525
|
try {
|
|
15062
15526
|
existing = await (0, import_promises9.readFile)(indexPath, "utf-8");
|
|
@@ -15453,9 +15917,9 @@ function hasLegacyMemoryBlock(text) {
|
|
|
15453
15917
|
return findMarker(text, LEGACY_MD_START) !== -1;
|
|
15454
15918
|
}
|
|
15455
15919
|
async function ensureClaudeMdPointer(cwd = repoRoot()) {
|
|
15456
|
-
const claudeMdPath = (0,
|
|
15920
|
+
const claudeMdPath = (0, import_node_path17.join)(cwd, "CLAUDE.md");
|
|
15457
15921
|
let existing = "";
|
|
15458
|
-
if ((0,
|
|
15922
|
+
if ((0, import_node_fs19.existsSync)(claudeMdPath)) {
|
|
15459
15923
|
existing = await (0, import_promises9.readFile)(claudeMdPath, "utf-8");
|
|
15460
15924
|
}
|
|
15461
15925
|
let startTag = CLAUDE_MD_START;
|
|
@@ -15596,9 +16060,9 @@ Body content (\u22648KB). Use [[node-id]] wikilinks for cross-references.
|
|
|
15596
16060
|
`;
|
|
15597
16061
|
|
|
15598
16062
|
// src/lib/dossier-session.ts
|
|
15599
|
-
var
|
|
15600
|
-
var
|
|
15601
|
-
var
|
|
16063
|
+
var import_node_fs24 = require("node:fs");
|
|
16064
|
+
var import_node_crypto8 = require("node:crypto");
|
|
16065
|
+
var import_node_path20 = require("node:path");
|
|
15602
16066
|
|
|
15603
16067
|
// src/lib/pending-repeat.ts
|
|
15604
16068
|
var STOP = /* @__PURE__ */ new Set([
|
|
@@ -15702,9 +16166,9 @@ function statementAnchorKey(file, patternId) {
|
|
|
15702
16166
|
}
|
|
15703
16167
|
|
|
15704
16168
|
// src/lib/dossier/log.ts
|
|
15705
|
-
var
|
|
15706
|
-
var
|
|
15707
|
-
var
|
|
16169
|
+
var import_node_crypto5 = require("node:crypto");
|
|
16170
|
+
var import_node_fs20 = require("node:fs");
|
|
16171
|
+
var import_node_path18 = require("node:path");
|
|
15708
16172
|
var CRC_TABLE = (() => {
|
|
15709
16173
|
const t = new Int32Array(256);
|
|
15710
16174
|
for (let i = 0; i < 256; i++) {
|
|
@@ -15723,13 +16187,13 @@ function crc32(s) {
|
|
|
15723
16187
|
function openDossier(identity) {
|
|
15724
16188
|
try {
|
|
15725
16189
|
const dir = dossierDir(identity);
|
|
15726
|
-
(0,
|
|
16190
|
+
(0, import_node_fs20.mkdirSync)(dir, { recursive: true, mode: 448 });
|
|
15727
16191
|
return {
|
|
15728
16192
|
dir,
|
|
15729
16193
|
identity,
|
|
15730
|
-
eventsPath: (0,
|
|
15731
|
-
foldPath: (0,
|
|
15732
|
-
rotatedDir: (0,
|
|
16194
|
+
eventsPath: (0, import_node_path18.join)(dir, "events.jsonl"),
|
|
16195
|
+
foldPath: (0, import_node_path18.join)(dir, "fold.json"),
|
|
16196
|
+
rotatedDir: (0, import_node_path18.join)(dir, "rotated")
|
|
15733
16197
|
};
|
|
15734
16198
|
} catch {
|
|
15735
16199
|
return null;
|
|
@@ -15744,7 +16208,7 @@ function nextSeq() {
|
|
|
15744
16208
|
function encodeEvent(ev) {
|
|
15745
16209
|
const full = {
|
|
15746
16210
|
v: 1,
|
|
15747
|
-
id: (0,
|
|
16211
|
+
id: (0, import_node_crypto5.randomBytes)(4).toString("hex"),
|
|
15748
16212
|
...ev
|
|
15749
16213
|
};
|
|
15750
16214
|
let body = JSON.stringify(full);
|
|
@@ -15791,7 +16255,7 @@ function appendEvent(d, ev) {
|
|
|
15791
16255
|
at: ev.at ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
15792
16256
|
...ev
|
|
15793
16257
|
});
|
|
15794
|
-
(0,
|
|
16258
|
+
(0, import_node_fs20.appendFileSync)(d.eventsPath, line, { mode: 384 });
|
|
15795
16259
|
return true;
|
|
15796
16260
|
} catch {
|
|
15797
16261
|
return false;
|
|
@@ -15799,14 +16263,14 @@ function appendEvent(d, ev) {
|
|
|
15799
16263
|
}
|
|
15800
16264
|
function rotateIfNeeded2(d) {
|
|
15801
16265
|
try {
|
|
15802
|
-
if (!(0,
|
|
15803
|
-
if ((0,
|
|
15804
|
-
(0,
|
|
15805
|
-
(0,
|
|
15806
|
-
const kept = (0,
|
|
16266
|
+
if (!(0, import_node_fs20.existsSync)(d.eventsPath)) return;
|
|
16267
|
+
if ((0, import_node_fs20.statSync)(d.eventsPath).size < ROTATE_BYTES) return;
|
|
16268
|
+
(0, import_node_fs20.mkdirSync)(d.rotatedDir, { recursive: true, mode: 448 });
|
|
16269
|
+
(0, import_node_fs20.renameSync)(d.eventsPath, (0, import_node_path18.join)(d.rotatedDir, `events.${Date.now()}.jsonl`));
|
|
16270
|
+
const kept = (0, import_node_fs20.readdirSync)(d.rotatedDir).filter((f) => f.endsWith(".jsonl")).sort();
|
|
15807
16271
|
for (const stale of kept.slice(0, Math.max(0, kept.length - ROTATE_KEEP))) {
|
|
15808
16272
|
try {
|
|
15809
|
-
(0,
|
|
16273
|
+
(0, import_node_fs20.renameSync)((0, import_node_path18.join)(d.rotatedDir, stale), (0, import_node_path18.join)(d.rotatedDir, `${stale}.pruned`));
|
|
15810
16274
|
} catch {
|
|
15811
16275
|
}
|
|
15812
16276
|
}
|
|
@@ -15815,9 +16279,9 @@ function rotateIfNeeded2(d) {
|
|
|
15815
16279
|
}
|
|
15816
16280
|
|
|
15817
16281
|
// src/lib/dossier/fold-dossier.ts
|
|
15818
|
-
var
|
|
15819
|
-
var
|
|
15820
|
-
var
|
|
16282
|
+
var import_node_crypto6 = require("node:crypto");
|
|
16283
|
+
var import_node_fs21 = require("node:fs");
|
|
16284
|
+
var import_node_path19 = require("node:path");
|
|
15821
16285
|
var EMPTY_CAPABILITIES = () => ({
|
|
15822
16286
|
human_reachable: { value: "unknown", tier: "unknown" },
|
|
15823
16287
|
authorship_observability: { value: "unknown", tier: "unknown" },
|
|
@@ -15868,12 +16332,12 @@ function foldDossier(d, opts = {}) {
|
|
|
15868
16332
|
}
|
|
15869
16333
|
};
|
|
15870
16334
|
try {
|
|
15871
|
-
if ((0,
|
|
15872
|
-
const files = (0,
|
|
16335
|
+
if ((0, import_node_fs21.existsSync)(d.rotatedDir)) {
|
|
16336
|
+
const files = (0, import_node_fs21.readdirSync)(d.rotatedDir).filter((f) => f.endsWith(".jsonl")).sort();
|
|
15873
16337
|
state.meta.rotations = files.length;
|
|
15874
16338
|
for (const f of files) {
|
|
15875
16339
|
try {
|
|
15876
|
-
ingest((0,
|
|
16340
|
+
ingest((0, import_node_fs21.readFileSync)((0, import_node_path19.join)(d.rotatedDir, f), "utf8"));
|
|
15877
16341
|
} catch {
|
|
15878
16342
|
state.meta.dropped_lines++;
|
|
15879
16343
|
}
|
|
@@ -15882,9 +16346,9 @@ function foldDossier(d, opts = {}) {
|
|
|
15882
16346
|
} catch {
|
|
15883
16347
|
}
|
|
15884
16348
|
try {
|
|
15885
|
-
if ((0,
|
|
15886
|
-
state.meta.upto_offset = (0,
|
|
15887
|
-
ingest((0,
|
|
16349
|
+
if ((0, import_node_fs21.existsSync)(d.eventsPath)) {
|
|
16350
|
+
state.meta.upto_offset = (0, import_node_fs21.statSync)(d.eventsPath).size;
|
|
16351
|
+
ingest((0, import_node_fs21.readFileSync)(d.eventsPath, "utf8"));
|
|
15888
16352
|
}
|
|
15889
16353
|
} catch {
|
|
15890
16354
|
}
|
|
@@ -15907,7 +16371,7 @@ function reduce(state, events, now) {
|
|
|
15907
16371
|
state.meta.seq = Math.max(state.meta.seq, ev.seq);
|
|
15908
16372
|
switch (ev.k) {
|
|
15909
16373
|
case "goal": {
|
|
15910
|
-
const hash = (0,
|
|
16374
|
+
const hash = (0, import_node_crypto6.createHash)("sha256").update(ev.text).digest("hex").slice(0, 16);
|
|
15911
16375
|
const prev = state.goal[state.goal.length - 1];
|
|
15912
16376
|
if (prev && prev.hash === hash) {
|
|
15913
16377
|
prev.repeats = (prev.repeats ?? 0) + 1;
|
|
@@ -16155,7 +16619,7 @@ function applyBounds(state, input) {
|
|
|
16155
16619
|
}
|
|
16156
16620
|
|
|
16157
16621
|
// src/lib/dossier/cache.ts
|
|
16158
|
-
var
|
|
16622
|
+
var import_node_fs22 = require("node:fs");
|
|
16159
16623
|
function compactState(s) {
|
|
16160
16624
|
const ms = (iso) => Date.parse(iso) || 0;
|
|
16161
16625
|
return {
|
|
@@ -16284,20 +16748,20 @@ function encodeState(s) {
|
|
|
16284
16748
|
function writeFoldCache(d, state) {
|
|
16285
16749
|
try {
|
|
16286
16750
|
const tmp = `${d.foldPath}.${process.pid}.tmp`;
|
|
16287
|
-
(0,
|
|
16288
|
-
(0,
|
|
16751
|
+
(0, import_node_fs22.writeFileSync)(tmp, encodeState(state), { mode: 384 });
|
|
16752
|
+
(0, import_node_fs22.renameSync)(tmp, d.foldPath);
|
|
16289
16753
|
} catch {
|
|
16290
16754
|
}
|
|
16291
16755
|
}
|
|
16292
16756
|
function readFoldCache(d) {
|
|
16293
16757
|
try {
|
|
16294
|
-
if (!(0,
|
|
16295
|
-
const raw = JSON.parse((0,
|
|
16758
|
+
if (!(0, import_node_fs22.existsSync)(d.foldPath)) return null;
|
|
16759
|
+
const raw = JSON.parse((0, import_node_fs22.readFileSync)(d.foldPath, "utf8"));
|
|
16296
16760
|
if (raw?.v !== 1) return null;
|
|
16297
16761
|
const cached2 = expandState(raw);
|
|
16298
16762
|
if (!cached2?.meta) return null;
|
|
16299
|
-
const size = (0,
|
|
16300
|
-
const rotations = (0,
|
|
16763
|
+
const size = (0, import_node_fs22.existsSync)(d.eventsPath) ? (0, import_node_fs22.statSync)(d.eventsPath).size : 0;
|
|
16764
|
+
const rotations = (0, import_node_fs22.existsSync)(d.rotatedDir) ? (0, import_node_fs22.readdirSync)(d.rotatedDir).filter((f) => f.endsWith(".jsonl")).length : 0;
|
|
16301
16765
|
if (cached2.meta.upto_offset !== size || cached2.meta.rotations !== rotations) return null;
|
|
16302
16766
|
return cached2;
|
|
16303
16767
|
} catch {
|
|
@@ -16347,14 +16811,14 @@ function assessContinuity(i) {
|
|
|
16347
16811
|
}
|
|
16348
16812
|
|
|
16349
16813
|
// src/lib/dossier/reanchor.ts
|
|
16350
|
-
var
|
|
16351
|
-
var
|
|
16814
|
+
var import_node_crypto7 = require("node:crypto");
|
|
16815
|
+
var import_node_fs23 = require("node:fs");
|
|
16352
16816
|
function lineSha(text) {
|
|
16353
|
-
return (0,
|
|
16817
|
+
return (0, import_node_crypto7.createHash)("sha256").update(text.trim()).digest("hex").slice(0, HASH_WIDTH);
|
|
16354
16818
|
}
|
|
16355
16819
|
function fileHash(path) {
|
|
16356
16820
|
try {
|
|
16357
|
-
return (0,
|
|
16821
|
+
return (0, import_node_crypto7.createHash)("sha256").update((0, import_node_fs23.readFileSync)(path)).digest("hex").slice(0, HASH_WIDTH);
|
|
16358
16822
|
} catch {
|
|
16359
16823
|
return null;
|
|
16360
16824
|
}
|
|
@@ -16726,20 +17190,20 @@ function foreignAuthoredPaths(identity, opts = {}) {
|
|
|
16726
17190
|
let sessions = 0;
|
|
16727
17191
|
try {
|
|
16728
17192
|
const dir = treeDir(identity);
|
|
16729
|
-
if (!(0,
|
|
16730
|
-
for (const entry of (0,
|
|
17193
|
+
if (!(0, import_node_fs24.existsSync)(dir)) return { paths: [], sessions: 0 };
|
|
17194
|
+
for (const entry of (0, import_node_fs24.readdirSync)(dir, { withFileTypes: true })) {
|
|
16731
17195
|
if (!entry.isDirectory()) continue;
|
|
16732
17196
|
if (entry.name === identity.sessionKey) continue;
|
|
16733
|
-
const log = (0,
|
|
17197
|
+
const log = (0, import_node_path20.join)(dir, entry.name, "events.jsonl");
|
|
16734
17198
|
try {
|
|
16735
|
-
if (!(0,
|
|
16736
|
-
if (now - (0,
|
|
17199
|
+
if (!(0, import_node_fs24.existsSync)(log)) continue;
|
|
17200
|
+
if (now - (0, import_node_fs24.statSync)(log).mtimeMs > windowMs) continue;
|
|
16737
17201
|
const sib = {
|
|
16738
|
-
dir: (0,
|
|
17202
|
+
dir: (0, import_node_path20.join)(dir, entry.name),
|
|
16739
17203
|
identity,
|
|
16740
17204
|
eventsPath: log,
|
|
16741
|
-
foldPath: (0,
|
|
16742
|
-
rotatedDir: (0,
|
|
17205
|
+
foldPath: (0, import_node_path20.join)(dir, entry.name, "fold.json"),
|
|
17206
|
+
rotatedDir: (0, import_node_path20.join)(dir, entry.name, "rotated")
|
|
16743
17207
|
};
|
|
16744
17208
|
const state = readFoldCache(sib) ?? foldDossier(sib);
|
|
16745
17209
|
sessions++;
|
|
@@ -16767,25 +17231,25 @@ function pruneOldDossiers(identity, maxAgeMs = 7 * 24 * 60 * 60 * 1e3) {
|
|
|
16767
17231
|
let removed = 0;
|
|
16768
17232
|
try {
|
|
16769
17233
|
const mine = dossierDir(identity);
|
|
16770
|
-
const userDir = (0,
|
|
16771
|
-
if (!(0,
|
|
17234
|
+
const userDir = (0, import_node_path20.dirname)((0, import_node_path20.dirname)(mine));
|
|
17235
|
+
if (!(0, import_node_fs24.existsSync)(userDir)) return 0;
|
|
16772
17236
|
const cutoff = Date.now() - maxAgeMs;
|
|
16773
|
-
for (const tree of (0,
|
|
17237
|
+
for (const tree of (0, import_node_fs24.readdirSync)(userDir, { withFileTypes: true })) {
|
|
16774
17238
|
if (!tree.isDirectory()) continue;
|
|
16775
|
-
const treePath = (0,
|
|
17239
|
+
const treePath = (0, import_node_path20.join)(userDir, tree.name);
|
|
16776
17240
|
let live = 0;
|
|
16777
|
-
for (const entry of (0,
|
|
17241
|
+
for (const entry of (0, import_node_fs24.readdirSync)(treePath, { withFileTypes: true })) {
|
|
16778
17242
|
if (!entry.isDirectory()) continue;
|
|
16779
|
-
const dir = (0,
|
|
17243
|
+
const dir = (0, import_node_path20.join)(treePath, entry.name);
|
|
16780
17244
|
if (dir === mine) {
|
|
16781
17245
|
live++;
|
|
16782
17246
|
continue;
|
|
16783
17247
|
}
|
|
16784
17248
|
try {
|
|
16785
|
-
const log = (0,
|
|
16786
|
-
const at = (0,
|
|
17249
|
+
const log = (0, import_node_path20.join)(dir, "events.jsonl");
|
|
17250
|
+
const at = (0, import_node_fs24.existsSync)(log) ? (0, import_node_fs24.statSync)(log).mtimeMs : (0, import_node_fs24.statSync)(dir).mtimeMs;
|
|
16787
17251
|
if (at < cutoff) {
|
|
16788
|
-
(0,
|
|
17252
|
+
(0, import_node_fs24.rmSync)(dir, { recursive: true, force: true });
|
|
16789
17253
|
removed++;
|
|
16790
17254
|
} else {
|
|
16791
17255
|
live++;
|
|
@@ -16795,7 +17259,7 @@ function pruneOldDossiers(identity, maxAgeMs = 7 * 24 * 60 * 60 * 1e3) {
|
|
|
16795
17259
|
}
|
|
16796
17260
|
if (live === 0) {
|
|
16797
17261
|
try {
|
|
16798
|
-
(0,
|
|
17262
|
+
(0, import_node_fs24.rmSync)(treePath, { recursive: false, force: false });
|
|
16799
17263
|
} catch {
|
|
16800
17264
|
}
|
|
16801
17265
|
}
|
|
@@ -16812,8 +17276,8 @@ function sessionDossier(token, sessionId) {
|
|
|
16812
17276
|
}
|
|
16813
17277
|
function hasActiveGoal(d) {
|
|
16814
17278
|
try {
|
|
16815
|
-
if (!(0,
|
|
16816
|
-
return (0,
|
|
17279
|
+
if (!(0, import_node_fs24.existsSync)(d.eventsPath)) return false;
|
|
17280
|
+
return (0, import_node_fs24.readFileSync)(d.eventsPath, "utf8").includes('"k":"goal"');
|
|
16817
17281
|
} catch {
|
|
16818
17282
|
return false;
|
|
16819
17283
|
}
|
|
@@ -16837,7 +17301,7 @@ function recordTurn(d, t) {
|
|
|
16837
17301
|
for (const a of t.authored) {
|
|
16838
17302
|
const origin = a.owner === "subagent" ? "subagent" : "edit_tool";
|
|
16839
17303
|
const prior = t.known?.authored?.get(a.p);
|
|
16840
|
-
const hash = fileHash((0,
|
|
17304
|
+
const hash = fileHash((0, import_node_path20.join)(root, a.p));
|
|
16841
17305
|
const hunks = Math.max(0, a.h - (prior?.hunks ?? 0));
|
|
16842
17306
|
const adds = Math.max(0, a.a - (prior?.adds ?? 0));
|
|
16843
17307
|
const dels = Math.max(0, a.d - (prior?.dels ?? 0));
|
|
@@ -16851,7 +17315,7 @@ function recordTurn(d, t) {
|
|
|
16851
17315
|
// Identity is the COMMAND, not its category — otherwise `npm test -- a` and
|
|
16852
17316
|
// `npm test -- b` are one row and the streak counts two different commands
|
|
16853
17317
|
// as a run of one.
|
|
16854
|
-
cmd_hash: (0,
|
|
17318
|
+
cmd_hash: (0, import_node_crypto8.createHash)("sha256").update(c.head || c.class).digest("hex").slice(0, 12),
|
|
16855
17319
|
head: c.head || c.class,
|
|
16856
17320
|
status: toStatus(c.last_status)
|
|
16857
17321
|
});
|
|
@@ -16870,7 +17334,7 @@ function recordTurn(d, t) {
|
|
|
16870
17334
|
}
|
|
16871
17335
|
const seenDivergence = t.known?.divergence ?? /* @__PURE__ */ new Set();
|
|
16872
17336
|
for (const u of t.unobserved) {
|
|
16873
|
-
const hash = fileHash((0,
|
|
17337
|
+
const hash = fileHash((0, import_node_path20.join)(root, u.p));
|
|
16874
17338
|
if (seenDivergence.has(divergenceKey(u.p, hash))) continue;
|
|
16875
17339
|
appendEvent(d, { k: "divergence", kind: "external_mutation", path: u.p, hash });
|
|
16876
17340
|
}
|
|
@@ -16905,8 +17369,8 @@ function recordVerdict(d, v) {
|
|
|
16905
17369
|
if (!sent.has(f.file)) continue;
|
|
16906
17370
|
if (!lines.has(f.file)) {
|
|
16907
17371
|
try {
|
|
16908
|
-
const abs = (0,
|
|
16909
|
-
lines.set(f.file, (0,
|
|
17372
|
+
const abs = (0, import_node_path20.join)(root, f.file);
|
|
17373
|
+
lines.set(f.file, (0, import_node_fs24.existsSync)(abs) ? (0, import_node_fs24.readFileSync)(abs, "utf8").split("\n") : null);
|
|
16910
17374
|
} catch {
|
|
16911
17375
|
lines.set(f.file, null);
|
|
16912
17376
|
}
|
|
@@ -17006,8 +17470,8 @@ function recallMemory(d, identity, opts) {
|
|
|
17006
17470
|
budgetBytes: opts.budgetBytes,
|
|
17007
17471
|
readFileLines: (file) => {
|
|
17008
17472
|
try {
|
|
17009
|
-
const abs = (0,
|
|
17010
|
-
return (0,
|
|
17473
|
+
const abs = (0, import_node_path20.join)(root, file);
|
|
17474
|
+
return (0, import_node_fs24.existsSync)(abs) ? (0, import_node_fs24.readFileSync)(abs, "utf8").split("\n") : null;
|
|
17011
17475
|
} catch {
|
|
17012
17476
|
return null;
|
|
17013
17477
|
}
|
|
@@ -17026,6 +17490,9 @@ function recallMemory(d, identity, opts) {
|
|
|
17026
17490
|
}
|
|
17027
17491
|
|
|
17028
17492
|
// src/commands/intent.ts
|
|
17493
|
+
var MAX_PROMPT_EVENT_BYTES = 2 * 1024 * 1024;
|
|
17494
|
+
var MAX_PROMPT_CHARS2 = 2e5;
|
|
17495
|
+
var SESSION_ID_RE = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/;
|
|
17029
17496
|
function registerIntentCommands(program2) {
|
|
17030
17497
|
const intent = program2.command("intent").description("Manage intent capture");
|
|
17031
17498
|
intent.command("capture").description("Capture user intent from stdin (used by UserPromptSubmit hook)").action(async () => {
|
|
@@ -17039,16 +17506,24 @@ function registerIntentCommands(program2) {
|
|
|
17039
17506
|
process.exit(0);
|
|
17040
17507
|
}
|
|
17041
17508
|
const chunks = [];
|
|
17509
|
+
let size = 0;
|
|
17042
17510
|
for await (const chunk of process.stdin) {
|
|
17043
|
-
|
|
17511
|
+
size += chunk.length;
|
|
17512
|
+
if (size <= MAX_PROMPT_EVENT_BYTES) chunks.push(chunk);
|
|
17044
17513
|
}
|
|
17045
|
-
const input = Buffer.concat(chunks).toString("utf-8").trim();
|
|
17514
|
+
const input = size > MAX_PROMPT_EVENT_BYTES ? "" : Buffer.concat(chunks).toString("utf-8").trim();
|
|
17046
17515
|
if (!input) {
|
|
17047
17516
|
process.exit(0);
|
|
17048
17517
|
}
|
|
17049
|
-
let event;
|
|
17518
|
+
let event = {};
|
|
17050
17519
|
try {
|
|
17051
|
-
|
|
17520
|
+
const parsed = JSON.parse(input);
|
|
17521
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) process.exit(0);
|
|
17522
|
+
const o = parsed;
|
|
17523
|
+
event = {
|
|
17524
|
+
prompt: typeof o.prompt === "string" ? o.prompt.slice(0, MAX_PROMPT_CHARS2) : void 0,
|
|
17525
|
+
session_id: typeof o.session_id === "string" && SESSION_ID_RE.test(o.session_id) ? o.session_id : void 0
|
|
17526
|
+
};
|
|
17052
17527
|
} catch {
|
|
17053
17528
|
process.exit(0);
|
|
17054
17529
|
}
|
|
@@ -17077,6 +17552,19 @@ function registerIntentCommands(program2) {
|
|
|
17077
17552
|
const injection = await retrieveForInjection(prompt);
|
|
17078
17553
|
if (injection) {
|
|
17079
17554
|
process.stdout.write(injection.contextBlock);
|
|
17555
|
+
recordInjection({
|
|
17556
|
+
ts: Date.now(),
|
|
17557
|
+
session_id: scopeSession || null,
|
|
17558
|
+
prompt_hash: hashPrompt(prompt),
|
|
17559
|
+
arm: "injected",
|
|
17560
|
+
eligible: injection.eligible,
|
|
17561
|
+
tokens: injection.tokensUsed,
|
|
17562
|
+
nodes: injection.nodes.map((n) => ({
|
|
17563
|
+
id: n.nodeId,
|
|
17564
|
+
score: Math.round(n.score * 1e3) / 1e3,
|
|
17565
|
+
via: `${n.fileGlobs.length ? "g" : ""}${n.scope === "org" ? "o" : ""}x`
|
|
17566
|
+
}))
|
|
17567
|
+
});
|
|
17080
17568
|
}
|
|
17081
17569
|
} catch {
|
|
17082
17570
|
}
|
|
@@ -17085,179 +17573,87 @@ function registerIntentCommands(program2) {
|
|
|
17085
17573
|
error: err.message?.slice(0, 200) ?? "unknown"
|
|
17086
17574
|
});
|
|
17087
17575
|
});
|
|
17088
|
-
} catch {
|
|
17089
|
-
}
|
|
17090
|
-
process.exit(0);
|
|
17091
|
-
});
|
|
17092
|
-
intent.command("classify-body").description("Output JSON body for POST /classify-task (internal, used by hooks)").requiredOption("--session-id <id>", "Session ID").requiredOption("--prompt <text>", "User prompt").requiredOption("--prompt-hash <hash>", "SHA-256 hash of the prompt").action((opts) => {
|
|
17093
|
-
const body = JSON.stringify({
|
|
17094
|
-
session_id: opts.sessionId,
|
|
17095
|
-
user_prompt: opts.prompt.slice(0, 4e3),
|
|
17096
|
-
user_prompt_hash: opts.promptHash
|
|
17097
|
-
});
|
|
17098
|
-
process.stdout.write(body);
|
|
17099
|
-
});
|
|
17100
|
-
}
|
|
17101
|
-
async function fireClassify(prompt, sessionId, globals) {
|
|
17102
|
-
if (!sessionId) {
|
|
17103
|
-
logEvent("classify_skipped", { reason: "no_session_id" });
|
|
17104
|
-
return;
|
|
17105
|
-
}
|
|
17106
|
-
const tokenResult = await resolveToken(globals?.token);
|
|
17107
|
-
if (!tokenResult.ok) {
|
|
17108
|
-
logEvent("classify_skipped", { reason: "no_token", detail: tokenResult.error });
|
|
17109
|
-
return;
|
|
17110
|
-
}
|
|
17111
|
-
const urlResult = await resolveServiceUrl(globals?.serviceUrl);
|
|
17112
|
-
if (!urlResult.ok) {
|
|
17113
|
-
logEvent("classify_skipped", { reason: "no_service_url", detail: urlResult.error });
|
|
17114
|
-
return;
|
|
17115
|
-
}
|
|
17116
|
-
const promptHash = (0, import_node_crypto8.createHash)("sha256").update(prompt).digest("hex");
|
|
17117
|
-
const result = await apiRequest({
|
|
17118
|
-
method: "POST",
|
|
17119
|
-
path: "/classify-task",
|
|
17120
|
-
serviceUrl: urlResult.data,
|
|
17121
|
-
token: tokenResult.data.token,
|
|
17122
|
-
body: {
|
|
17123
|
-
session_id: sessionId,
|
|
17124
|
-
user_prompt: prompt.slice(0, 4e3),
|
|
17125
|
-
user_prompt_hash: promptHash
|
|
17126
|
-
},
|
|
17127
|
-
timeout: 4e3,
|
|
17128
|
-
cmd: "classify"
|
|
17129
|
-
});
|
|
17130
|
-
if (!result.ok) {
|
|
17131
|
-
logEvent("classify_failed", {
|
|
17132
|
-
category: result.category,
|
|
17133
|
-
http_status: result.http_status ?? null,
|
|
17134
|
-
error: result.error?.slice(0, 200) ?? "unknown",
|
|
17135
|
-
prompt_len: prompt.length
|
|
17136
|
-
});
|
|
17137
|
-
return;
|
|
17138
|
-
}
|
|
17139
|
-
const classificationId = result.data.classification_id;
|
|
17140
|
-
const status = result.data.status;
|
|
17141
|
-
logEvent("classify_accepted", {
|
|
17142
|
-
classification_id: classificationId ?? null,
|
|
17143
|
-
status: status ?? null,
|
|
17144
|
-
prompt_len: prompt.length
|
|
17145
|
-
});
|
|
17146
|
-
const decidedTaskId = result.data.decided_task_id;
|
|
17147
|
-
if (decidedTaskId) {
|
|
17148
|
-
appendPromptToTaskBuffer(decidedTaskId, prompt, sessionId).catch(() => {
|
|
17149
|
-
});
|
|
17150
|
-
}
|
|
17151
|
-
}
|
|
17152
|
-
|
|
17153
|
-
// src/commands/lifecycle.ts
|
|
17154
|
-
var import_node_fs25 = require("node:fs");
|
|
17155
|
-
var import_node_path23 = require("node:path");
|
|
17156
|
-
|
|
17157
|
-
// src/lib/baseline.ts
|
|
17158
|
-
var import_node_fs24 = require("node:fs");
|
|
17159
|
-
var import_node_path22 = require("node:path");
|
|
17160
|
-
var import_node_crypto9 = require("node:crypto");
|
|
17161
|
-
|
|
17162
|
-
// src/lib/snapshot.ts
|
|
17163
|
-
var import_node_fs23 = require("node:fs");
|
|
17164
|
-
var import_node_path21 = require("node:path");
|
|
17165
|
-
var import_node_child_process7 = require("node:child_process");
|
|
17166
|
-
|
|
17167
|
-
// src/lib/files.ts
|
|
17168
|
-
var import_node_path20 = require("node:path");
|
|
17169
|
-
|
|
17170
|
-
// src/lib/safe-read.ts
|
|
17171
|
-
var import_node_fs22 = require("node:fs");
|
|
17172
|
-
var import_node_path19 = require("node:path");
|
|
17173
|
-
var FLAGS = import_node_fs22.constants;
|
|
17174
|
-
var NOFOLLOW = FLAGS.O_NOFOLLOW;
|
|
17175
|
-
var NONBLOCK = FLAGS.O_NONBLOCK;
|
|
17176
|
-
function closeOpened(fd) {
|
|
17177
|
-
try {
|
|
17178
|
-
(0, import_node_fs22.closeSync)(fd);
|
|
17179
|
-
} catch {
|
|
17180
|
-
}
|
|
17181
|
-
}
|
|
17182
|
-
function isInsideRoot(realRoot, realPath) {
|
|
17183
|
-
return realPath === realRoot || realPath.startsWith(realRoot.endsWith(import_node_path19.sep) ? realRoot : realRoot + import_node_path19.sep);
|
|
17184
|
-
}
|
|
17185
|
-
function sameOpenedFile(opened, current, nofollowAvailable) {
|
|
17186
|
-
if (!nofollowAvailable && (opened.ino === 0n || current.ino === 0n)) return false;
|
|
17187
|
-
return opened.ino === current.ino && opened.dev === current.dev;
|
|
17188
|
-
}
|
|
17189
|
-
function openRegularInRoot(root, path) {
|
|
17190
|
-
const full = (0, import_node_path19.isAbsolute)(path) ? path : (0, import_node_path19.join)(root, path);
|
|
17191
|
-
let fd;
|
|
17192
|
-
try {
|
|
17193
|
-
fd = (0, import_node_fs22.openSync)(full, import_node_fs22.constants.O_RDONLY | (NOFOLLOW ?? 0) | (NONBLOCK ?? 0));
|
|
17194
|
-
} catch (err) {
|
|
17195
|
-
const code = err.code;
|
|
17196
|
-
if (code === "ELOOP" || code === "EMLINK" || code === "EFTYPE") return { ok: false, reason: "symlink" };
|
|
17197
|
-
if (code === "ENOENT" || code === "ENOTDIR") return { ok: false, reason: "missing" };
|
|
17198
|
-
return { ok: false, reason: "unreadable" };
|
|
17199
|
-
}
|
|
17200
|
-
try {
|
|
17201
|
-
const opened = (0, import_node_fs22.fstatSync)(fd, { bigint: true });
|
|
17202
|
-
if (!opened.isFile()) {
|
|
17203
|
-
closeOpened(fd);
|
|
17204
|
-
return { ok: false, reason: "not-regular" };
|
|
17205
|
-
}
|
|
17206
|
-
const realRoot = import_node_fs22.realpathSync.native(root);
|
|
17207
|
-
const realPath = import_node_fs22.realpathSync.native(full);
|
|
17208
|
-
if (!isInsideRoot(realRoot, realPath)) {
|
|
17209
|
-
closeOpened(fd);
|
|
17210
|
-
return { ok: false, reason: "outside-root" };
|
|
17211
|
-
}
|
|
17212
|
-
const current = (0, import_node_fs22.statSync)(realPath, { bigint: true });
|
|
17213
|
-
if (!sameOpenedFile(opened, current, NOFOLLOW !== void 0)) {
|
|
17214
|
-
closeOpened(fd);
|
|
17215
|
-
return { ok: false, reason: NOFOLLOW === void 0 ? "unreadable" : "outside-root" };
|
|
17216
|
-
}
|
|
17217
|
-
return { ok: true, fd, size: Number(opened.size), mtimeMs: Number(opened.mtimeMs) };
|
|
17218
|
-
} catch {
|
|
17219
|
-
closeOpened(fd);
|
|
17220
|
-
return { ok: false, reason: "unreadable" };
|
|
17221
|
-
}
|
|
17222
|
-
}
|
|
17223
|
-
function statRegularInRoot(root, path) {
|
|
17224
|
-
const opened = openRegularInRoot(root, path);
|
|
17225
|
-
if (!opened.ok) return opened;
|
|
17226
|
-
closeOpened(opened.fd);
|
|
17227
|
-
return { ok: true, size: opened.size, mtimeMs: opened.mtimeMs };
|
|
17228
|
-
}
|
|
17229
|
-
function readOpened(fd, size) {
|
|
17230
|
-
try {
|
|
17231
|
-
const buffer = Buffer.alloc(size);
|
|
17232
|
-
let offset = 0;
|
|
17233
|
-
while (offset < size) {
|
|
17234
|
-
const n = (0, import_node_fs22.readSync)(fd, buffer, offset, size - offset, offset);
|
|
17235
|
-
if (n === 0) break;
|
|
17236
|
-
offset += n;
|
|
17576
|
+
} catch {
|
|
17237
17577
|
}
|
|
17238
|
-
|
|
17239
|
-
}
|
|
17240
|
-
|
|
17241
|
-
|
|
17242
|
-
|
|
17243
|
-
|
|
17244
|
-
|
|
17578
|
+
process.exit(0);
|
|
17579
|
+
});
|
|
17580
|
+
intent.command("classify-body").description("Output JSON body for POST /classify-task (internal, used by hooks)").requiredOption("--session-id <id>", "Session ID").requiredOption("--prompt <text>", "User prompt").requiredOption("--prompt-hash <hash>", "SHA-256 hash of the prompt").action((opts) => {
|
|
17581
|
+
const body = JSON.stringify({
|
|
17582
|
+
session_id: opts.sessionId,
|
|
17583
|
+
user_prompt: opts.prompt.slice(0, 4e3),
|
|
17584
|
+
user_prompt_hash: opts.promptHash
|
|
17585
|
+
});
|
|
17586
|
+
process.stdout.write(body);
|
|
17587
|
+
});
|
|
17245
17588
|
}
|
|
17246
|
-
function
|
|
17247
|
-
|
|
17248
|
-
|
|
17249
|
-
|
|
17250
|
-
closeOpened(opened.fd);
|
|
17251
|
-
return { ok: false, reason: "too-large", size: opened.size };
|
|
17589
|
+
async function fireClassify(prompt, sessionId, globals) {
|
|
17590
|
+
if (!sessionId) {
|
|
17591
|
+
logEvent("classify_skipped", { reason: "no_session_id" });
|
|
17592
|
+
return;
|
|
17252
17593
|
}
|
|
17253
|
-
|
|
17254
|
-
|
|
17255
|
-
|
|
17256
|
-
return
|
|
17594
|
+
const tokenResult = await resolveToken(globals?.token);
|
|
17595
|
+
if (!tokenResult.ok) {
|
|
17596
|
+
logEvent("classify_skipped", { reason: "no_token", detail: tokenResult.error });
|
|
17597
|
+
return;
|
|
17598
|
+
}
|
|
17599
|
+
const urlResult = await resolveServiceUrl(globals?.serviceUrl);
|
|
17600
|
+
if (!urlResult.ok) {
|
|
17601
|
+
logEvent("classify_skipped", { reason: "no_service_url", detail: urlResult.error });
|
|
17602
|
+
return;
|
|
17603
|
+
}
|
|
17604
|
+
const promptHash = (0, import_node_crypto9.createHash)("sha256").update(prompt).digest("hex");
|
|
17605
|
+
const result = await apiRequest({
|
|
17606
|
+
method: "POST",
|
|
17607
|
+
path: "/classify-task",
|
|
17608
|
+
serviceUrl: urlResult.data,
|
|
17609
|
+
token: tokenResult.data.token,
|
|
17610
|
+
body: {
|
|
17611
|
+
session_id: sessionId,
|
|
17612
|
+
user_prompt: prompt.slice(0, 4e3),
|
|
17613
|
+
user_prompt_hash: promptHash
|
|
17614
|
+
},
|
|
17615
|
+
timeout: 4e3,
|
|
17616
|
+
cmd: "classify"
|
|
17617
|
+
});
|
|
17618
|
+
if (!result.ok) {
|
|
17619
|
+
logEvent("classify_failed", {
|
|
17620
|
+
category: result.category,
|
|
17621
|
+
http_status: result.http_status ?? null,
|
|
17622
|
+
error: result.error?.slice(0, 200) ?? "unknown",
|
|
17623
|
+
prompt_len: prompt.length
|
|
17624
|
+
});
|
|
17625
|
+
return;
|
|
17626
|
+
}
|
|
17627
|
+
const classificationId = result.data.classification_id;
|
|
17628
|
+
const status = result.data.status;
|
|
17629
|
+
logEvent("classify_accepted", {
|
|
17630
|
+
classification_id: classificationId ?? null,
|
|
17631
|
+
status: status ?? null,
|
|
17632
|
+
prompt_len: prompt.length
|
|
17633
|
+
});
|
|
17634
|
+
const decidedTaskId = result.data.decided_task_id;
|
|
17635
|
+
if (decidedTaskId) {
|
|
17636
|
+
appendPromptToTaskBuffer(decidedTaskId, prompt, sessionId).catch(() => {
|
|
17637
|
+
});
|
|
17257
17638
|
}
|
|
17258
17639
|
}
|
|
17259
17640
|
|
|
17641
|
+
// src/commands/lifecycle.ts
|
|
17642
|
+
var import_node_fs27 = require("node:fs");
|
|
17643
|
+
var import_node_path24 = require("node:path");
|
|
17644
|
+
|
|
17645
|
+
// src/lib/baseline.ts
|
|
17646
|
+
var import_node_fs26 = require("node:fs");
|
|
17647
|
+
var import_node_path23 = require("node:path");
|
|
17648
|
+
var import_node_crypto10 = require("node:crypto");
|
|
17649
|
+
|
|
17650
|
+
// src/lib/snapshot.ts
|
|
17651
|
+
var import_node_fs25 = require("node:fs");
|
|
17652
|
+
var import_node_path22 = require("node:path");
|
|
17653
|
+
var import_node_child_process7 = require("node:child_process");
|
|
17654
|
+
|
|
17260
17655
|
// src/lib/files.ts
|
|
17656
|
+
var import_node_path21 = require("node:path");
|
|
17261
17657
|
var LANG_MAP = {
|
|
17262
17658
|
// Analyzable (static analysis + Gemini)
|
|
17263
17659
|
ts: "typescript",
|
|
@@ -17325,7 +17721,7 @@ var LANG_MAP = {
|
|
|
17325
17721
|
mk: "make"
|
|
17326
17722
|
};
|
|
17327
17723
|
function detectLanguage(filepath) {
|
|
17328
|
-
const ext = (0,
|
|
17724
|
+
const ext = (0, import_node_path21.extname)(filepath).slice(1);
|
|
17329
17725
|
return LANG_MAP[ext] ?? ext;
|
|
17330
17726
|
}
|
|
17331
17727
|
function sortByMtime(files) {
|
|
@@ -17416,16 +17812,16 @@ function collectCodeDelta(files, opts) {
|
|
|
17416
17812
|
|
|
17417
17813
|
// src/lib/snapshot.ts
|
|
17418
17814
|
function generateSnapshotDiffs(files) {
|
|
17419
|
-
if (!(0,
|
|
17815
|
+
if (!(0, import_node_fs25.existsSync)(SNAPSHOT_DIR)) {
|
|
17420
17816
|
return { diffs: [], has_snapshots: false };
|
|
17421
17817
|
}
|
|
17422
17818
|
const diffs = [];
|
|
17423
17819
|
for (const file of files) {
|
|
17424
17820
|
if (!resolveInside(SNAPSHOT_DIR, file.path)) continue;
|
|
17425
|
-
const snapshotPath = (0,
|
|
17821
|
+
const snapshotPath = (0, import_node_path22.join)(SNAPSHOT_DIR, file.path);
|
|
17426
17822
|
const language = file.language ?? detectLanguage(file.path);
|
|
17427
|
-
if ((0,
|
|
17428
|
-
const oldContent = (0,
|
|
17823
|
+
if ((0, import_node_fs25.existsSync)(snapshotPath)) {
|
|
17824
|
+
const oldContent = (0, import_node_fs25.readFileSync)(snapshotPath, "utf-8");
|
|
17429
17825
|
if (oldContent === file.content) continue;
|
|
17430
17826
|
const diff = computeDiff(oldContent, file.content, file.path);
|
|
17431
17827
|
if (diff) {
|
|
@@ -17450,20 +17846,20 @@ function saveSnapshots(files) {
|
|
|
17450
17846
|
const snapshotPaths = /* @__PURE__ */ new Set();
|
|
17451
17847
|
for (const file of files) {
|
|
17452
17848
|
if (!resolveInside(SNAPSHOT_DIR, file.path)) continue;
|
|
17453
|
-
const snapshotPath = (0,
|
|
17849
|
+
const snapshotPath = (0, import_node_path22.join)(SNAPSHOT_DIR, file.path);
|
|
17454
17850
|
snapshotPaths.add(snapshotPath);
|
|
17455
|
-
(0,
|
|
17456
|
-
(0,
|
|
17851
|
+
(0, import_node_fs25.mkdirSync)((0, import_node_path22.dirname)(snapshotPath), { recursive: true });
|
|
17852
|
+
(0, import_node_fs25.writeFileSync)(snapshotPath, file.content);
|
|
17457
17853
|
}
|
|
17458
17854
|
cleanStaleSnapshots(SNAPSHOT_DIR, snapshotPaths);
|
|
17459
17855
|
}
|
|
17460
17856
|
function computeDiff(oldContent, newContent, filePath) {
|
|
17461
|
-
const tmpOld = (0,
|
|
17462
|
-
const tmpNew = (0,
|
|
17857
|
+
const tmpOld = (0, import_node_path22.join)(SNAPSHOT_DIR, ".diff-old.tmp");
|
|
17858
|
+
const tmpNew = (0, import_node_path22.join)(SNAPSHOT_DIR, ".diff-new.tmp");
|
|
17463
17859
|
try {
|
|
17464
|
-
(0,
|
|
17465
|
-
(0,
|
|
17466
|
-
(0,
|
|
17860
|
+
(0, import_node_fs25.mkdirSync)(SNAPSHOT_DIR, { recursive: true });
|
|
17861
|
+
(0, import_node_fs25.writeFileSync)(tmpOld, oldContent);
|
|
17862
|
+
(0, import_node_fs25.writeFileSync)(tmpNew, newContent);
|
|
17467
17863
|
const result = (0, import_node_child_process7.execSync)(
|
|
17468
17864
|
`git diff --no-index --unified=10 -- "${tmpOld}" "${tmpNew}"`,
|
|
17469
17865
|
{ encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
|
|
@@ -17477,32 +17873,32 @@ function computeDiff(oldContent, newContent, filePath) {
|
|
|
17477
17873
|
return null;
|
|
17478
17874
|
} finally {
|
|
17479
17875
|
try {
|
|
17480
|
-
(0,
|
|
17876
|
+
(0, import_node_fs25.unlinkSync)(tmpOld);
|
|
17481
17877
|
} catch {
|
|
17482
17878
|
}
|
|
17483
17879
|
try {
|
|
17484
|
-
(0,
|
|
17880
|
+
(0, import_node_fs25.unlinkSync)(tmpNew);
|
|
17485
17881
|
} catch {
|
|
17486
17882
|
}
|
|
17487
17883
|
}
|
|
17488
17884
|
}
|
|
17489
17885
|
function cleanStaleSnapshots(dir, keepSet) {
|
|
17490
|
-
if (!(0,
|
|
17886
|
+
if (!(0, import_node_fs25.existsSync)(dir)) return;
|
|
17491
17887
|
try {
|
|
17492
|
-
const entries = (0,
|
|
17888
|
+
const entries = (0, import_node_fs25.readdirSync)(dir, { withFileTypes: true });
|
|
17493
17889
|
for (const entry of entries) {
|
|
17494
17890
|
if (dir === SNAPSHOT_DIR && (entry.name === ".diff-old.tmp" || entry.name === ".diff-new.tmp")) continue;
|
|
17495
|
-
const fullPath = (0,
|
|
17891
|
+
const fullPath = (0, import_node_path22.join)(dir, entry.name);
|
|
17496
17892
|
if (entry.isDirectory()) {
|
|
17497
17893
|
cleanStaleSnapshots(fullPath, keepSet);
|
|
17498
17894
|
try {
|
|
17499
|
-
const remaining = (0,
|
|
17500
|
-
if (remaining.length === 0) (0,
|
|
17895
|
+
const remaining = (0, import_node_fs25.readdirSync)(fullPath);
|
|
17896
|
+
if (remaining.length === 0) (0, import_node_fs25.rmdirSync)(fullPath);
|
|
17501
17897
|
} catch {
|
|
17502
17898
|
}
|
|
17503
17899
|
} else if (!keepSet.has(fullPath)) {
|
|
17504
17900
|
try {
|
|
17505
|
-
(0,
|
|
17901
|
+
(0, import_node_fs25.unlinkSync)(fullPath);
|
|
17506
17902
|
} catch {
|
|
17507
17903
|
}
|
|
17508
17904
|
}
|
|
@@ -17518,23 +17914,23 @@ var MIRROR_MAX_BYTES = 2 * 1024 * 1024;
|
|
|
17518
17914
|
var DEFAULT_SESSION_KEY = "_default";
|
|
17519
17915
|
function sessionKey(sessionId) {
|
|
17520
17916
|
if (!sessionId) return DEFAULT_SESSION_KEY;
|
|
17521
|
-
return (0,
|
|
17917
|
+
return (0, import_node_crypto10.createHash)("sha256").update(sessionId).digest("hex").slice(0, 16);
|
|
17522
17918
|
}
|
|
17523
17919
|
function sessionDir(key) {
|
|
17524
|
-
return (0,
|
|
17920
|
+
return (0, import_node_path23.join)(projectPath(BASELINE_DIR), key);
|
|
17525
17921
|
}
|
|
17526
17922
|
function manifestPath(dir) {
|
|
17527
|
-
return (0,
|
|
17923
|
+
return (0, import_node_path23.join)(dir, "manifest.json");
|
|
17528
17924
|
}
|
|
17529
17925
|
function mirrorPath(dir, repoRelPath) {
|
|
17530
|
-
return (0,
|
|
17926
|
+
return (0, import_node_path23.join)(dir, "files", repoRelPath);
|
|
17531
17927
|
}
|
|
17532
17928
|
var CARRY_FILE = `${BASELINE_DIR}/.carry`;
|
|
17533
17929
|
var CARRY_WINDOW_MS = 12e4;
|
|
17534
17930
|
function writeCarry(sessionId, headSha) {
|
|
17535
17931
|
try {
|
|
17536
|
-
(0,
|
|
17537
|
-
(0,
|
|
17932
|
+
(0, import_node_fs26.mkdirSync)(projectPath(BASELINE_DIR), { recursive: true });
|
|
17933
|
+
(0, import_node_fs26.writeFileSync)(
|
|
17538
17934
|
projectPath(CARRY_FILE),
|
|
17539
17935
|
JSON.stringify({ from_key: sessionKey(sessionId), head_sha: headSha, ts: Date.now() })
|
|
17540
17936
|
);
|
|
@@ -17544,10 +17940,10 @@ function writeCarry(sessionId, headSha) {
|
|
|
17544
17940
|
function claimCarry(newKey) {
|
|
17545
17941
|
const carryPath = projectPath(CARRY_FILE);
|
|
17546
17942
|
try {
|
|
17547
|
-
if (!(0,
|
|
17548
|
-
const carry = JSON.parse((0,
|
|
17943
|
+
if (!(0, import_node_fs26.existsSync)(carryPath)) return null;
|
|
17944
|
+
const carry = JSON.parse((0, import_node_fs26.readFileSync)(carryPath, "utf-8"));
|
|
17549
17945
|
try {
|
|
17550
|
-
(0,
|
|
17946
|
+
(0, import_node_fs26.rmSync)(carryPath, { force: true });
|
|
17551
17947
|
} catch {
|
|
17552
17948
|
}
|
|
17553
17949
|
if (!carry?.from_key || typeof carry.ts !== "number") return null;
|
|
@@ -17558,11 +17954,11 @@ function claimCarry(newKey) {
|
|
|
17558
17954
|
if (!prior) return null;
|
|
17559
17955
|
const toDir = sessionDir(newKey);
|
|
17560
17956
|
try {
|
|
17561
|
-
(0,
|
|
17957
|
+
(0, import_node_fs26.rmSync)(toDir, { recursive: true, force: true });
|
|
17562
17958
|
} catch {
|
|
17563
17959
|
}
|
|
17564
|
-
(0,
|
|
17565
|
-
(0,
|
|
17960
|
+
(0, import_node_fs26.renameSync)(fromDir, toDir);
|
|
17961
|
+
(0, import_node_fs26.writeFileSync)(manifestPath(toDir), JSON.stringify({ ...prior, session_id: newKey }) + "\n");
|
|
17566
17962
|
return readManifest(toDir);
|
|
17567
17963
|
} catch {
|
|
17568
17964
|
return null;
|
|
@@ -17586,21 +17982,21 @@ function captureBaseline(opts = {}) {
|
|
|
17586
17982
|
const head_sha = getCurrentCommit();
|
|
17587
17983
|
const dirty = getDirtyFiles();
|
|
17588
17984
|
try {
|
|
17589
|
-
(0,
|
|
17985
|
+
(0, import_node_fs26.rmSync)(dir, { recursive: true, force: true });
|
|
17590
17986
|
} catch {
|
|
17591
17987
|
}
|
|
17592
|
-
const filesDir = (0,
|
|
17988
|
+
const filesDir = (0, import_node_path23.join)(dir, "files");
|
|
17593
17989
|
const mirrored = [];
|
|
17594
17990
|
try {
|
|
17595
|
-
(0,
|
|
17991
|
+
(0, import_node_fs26.mkdirSync)(filesDir, { recursive: true });
|
|
17596
17992
|
for (const p of dirty) {
|
|
17597
17993
|
if (p.includes("..")) continue;
|
|
17598
17994
|
const content = safeReadForMirror(projectPath(p));
|
|
17599
17995
|
if (content === null) continue;
|
|
17600
17996
|
const dest = mirrorPath(dir, p);
|
|
17601
17997
|
try {
|
|
17602
|
-
(0,
|
|
17603
|
-
(0,
|
|
17998
|
+
(0, import_node_fs26.mkdirSync)((0, import_node_path23.dirname)(dest), { recursive: true });
|
|
17999
|
+
(0, import_node_fs26.writeFileSync)(dest, content);
|
|
17604
18000
|
mirrored.push(p);
|
|
17605
18001
|
} catch {
|
|
17606
18002
|
}
|
|
@@ -17615,8 +18011,8 @@ function captureBaseline(opts = {}) {
|
|
|
17615
18011
|
version: BASELINE_VERSION
|
|
17616
18012
|
};
|
|
17617
18013
|
try {
|
|
17618
|
-
(0,
|
|
17619
|
-
(0,
|
|
18014
|
+
(0, import_node_fs26.mkdirSync)(dir, { recursive: true });
|
|
18015
|
+
(0, import_node_fs26.writeFileSync)(manifestPath(dir), JSON.stringify(baseline));
|
|
17620
18016
|
} catch {
|
|
17621
18017
|
}
|
|
17622
18018
|
pruneOldBaselines();
|
|
@@ -17627,9 +18023,9 @@ function readBaseline(sessionId) {
|
|
|
17627
18023
|
}
|
|
17628
18024
|
function readManifest(dir) {
|
|
17629
18025
|
const mp = manifestPath(dir);
|
|
17630
|
-
if (!(0,
|
|
18026
|
+
if (!(0, import_node_fs26.existsSync)(mp)) return null;
|
|
17631
18027
|
try {
|
|
17632
|
-
const parsed = JSON.parse((0,
|
|
18028
|
+
const parsed = JSON.parse((0, import_node_fs26.readFileSync)(mp, "utf-8"));
|
|
17633
18029
|
if (typeof parsed.head_sha !== "string" || typeof parsed.captured_at !== "number" || !Array.isArray(parsed.dirty_paths) || parsed.version !== BASELINE_VERSION) {
|
|
17634
18030
|
return null;
|
|
17635
18031
|
}
|
|
@@ -17660,9 +18056,9 @@ function preImage(repoRelPath, baseline) {
|
|
|
17660
18056
|
function resolvePreImage(repoRelPath, baseline) {
|
|
17661
18057
|
if (baseline.dirty_paths.includes(repoRelPath)) {
|
|
17662
18058
|
const mp = mirrorPath(sessionDir(sessionKey(baseline.session_id)), repoRelPath);
|
|
17663
|
-
if ((0,
|
|
18059
|
+
if ((0, import_node_fs26.existsSync)(mp)) {
|
|
17664
18060
|
try {
|
|
17665
|
-
return { content: (0,
|
|
18061
|
+
return { content: (0, import_node_fs26.readFileSync)(mp, "utf-8"), existed: true };
|
|
17666
18062
|
} catch {
|
|
17667
18063
|
}
|
|
17668
18064
|
}
|
|
@@ -17707,8 +18103,8 @@ function absorbIntoBaseline(paths, sessionId) {
|
|
|
17707
18103
|
const content = safeReadForMirror(projectPath(p));
|
|
17708
18104
|
if (content === null) continue;
|
|
17709
18105
|
const dest = mirrorPath(dir, p);
|
|
17710
|
-
(0,
|
|
17711
|
-
(0,
|
|
18106
|
+
(0, import_node_fs26.mkdirSync)((0, import_node_path23.dirname)(dest), { recursive: true });
|
|
18107
|
+
(0, import_node_fs26.writeFileSync)(dest, content);
|
|
17712
18108
|
dirty.add(p);
|
|
17713
18109
|
adopted++;
|
|
17714
18110
|
} catch {
|
|
@@ -17717,7 +18113,7 @@ function absorbIntoBaseline(paths, sessionId) {
|
|
|
17717
18113
|
if (adopted === 0) return 0;
|
|
17718
18114
|
try {
|
|
17719
18115
|
const updated = { ...baseline, dirty_paths: [...dirty] };
|
|
17720
|
-
(0,
|
|
18116
|
+
(0, import_node_fs26.writeFileSync)(manifestPath(dir), JSON.stringify(updated));
|
|
17721
18117
|
preImageCache.delete(baseline);
|
|
17722
18118
|
} catch {
|
|
17723
18119
|
return 0;
|
|
@@ -17728,7 +18124,7 @@ function changedSinceBaseline(repoRelPath, baseline) {
|
|
|
17728
18124
|
const pre = preImage(repoRelPath, baseline);
|
|
17729
18125
|
let current;
|
|
17730
18126
|
try {
|
|
17731
|
-
current = (0,
|
|
18127
|
+
current = (0, import_node_fs26.readFileSync)(projectPath(repoRelPath), "utf-8");
|
|
17732
18128
|
} catch {
|
|
17733
18129
|
return pre.existed;
|
|
17734
18130
|
}
|
|
@@ -17737,8 +18133,8 @@ function changedSinceBaseline(repoRelPath, baseline) {
|
|
|
17737
18133
|
}
|
|
17738
18134
|
function safeReadForMirror(absPath) {
|
|
17739
18135
|
try {
|
|
17740
|
-
if ((0,
|
|
17741
|
-
const buf = (0,
|
|
18136
|
+
if ((0, import_node_fs26.statSync)(absPath).size > MIRROR_MAX_BYTES) return null;
|
|
18137
|
+
const buf = (0, import_node_fs26.readFileSync)(absPath);
|
|
17742
18138
|
if (buf.includes(0)) return null;
|
|
17743
18139
|
return buf.toString("utf-8");
|
|
17744
18140
|
} catch {
|
|
@@ -17749,18 +18145,18 @@ function pruneOldBaselines() {
|
|
|
17749
18145
|
const root = projectPath(BASELINE_DIR);
|
|
17750
18146
|
let entries;
|
|
17751
18147
|
try {
|
|
17752
|
-
entries = (0,
|
|
18148
|
+
entries = (0, import_node_fs26.readdirSync)(root);
|
|
17753
18149
|
} catch {
|
|
17754
18150
|
return;
|
|
17755
18151
|
}
|
|
17756
18152
|
const now = Date.now();
|
|
17757
18153
|
for (const name of entries) {
|
|
17758
|
-
const dir = (0,
|
|
18154
|
+
const dir = (0, import_node_path23.join)(root, name);
|
|
17759
18155
|
const manifest = readManifest(dir);
|
|
17760
18156
|
if (!manifest) {
|
|
17761
18157
|
try {
|
|
17762
|
-
if (now - (0,
|
|
17763
|
-
(0,
|
|
18158
|
+
if (now - (0, import_node_fs26.statSync)(dir).mtimeMs > BASELINE_TTL_MS) {
|
|
18159
|
+
(0, import_node_fs26.rmSync)(dir, { recursive: true, force: true });
|
|
17764
18160
|
}
|
|
17765
18161
|
} catch {
|
|
17766
18162
|
}
|
|
@@ -17768,7 +18164,7 @@ function pruneOldBaselines() {
|
|
|
17768
18164
|
}
|
|
17769
18165
|
if (now - manifest.captured_at <= BASELINE_TTL_MS) continue;
|
|
17770
18166
|
try {
|
|
17771
|
-
(0,
|
|
18167
|
+
(0, import_node_fs26.rmSync)(dir, { recursive: true, force: true });
|
|
17772
18168
|
} catch {
|
|
17773
18169
|
}
|
|
17774
18170
|
}
|
|
@@ -17943,8 +18339,8 @@ function buildCompactionContext(session) {
|
|
|
17943
18339
|
commitsSince: commitsSincePaths(watermark, (state.authored ?? []).map((a) => a.path)),
|
|
17944
18340
|
readFileLines: (file) => {
|
|
17945
18341
|
try {
|
|
17946
|
-
const abs = (0,
|
|
17947
|
-
return (0,
|
|
18342
|
+
const abs = (0, import_node_path24.join)(root, file);
|
|
18343
|
+
return (0, import_node_fs27.existsSync)(abs) ? (0, import_node_fs27.readFileSync)(abs, "utf8").split("\n") : null;
|
|
17948
18344
|
} catch {
|
|
17949
18345
|
return null;
|
|
17950
18346
|
}
|
|
@@ -18001,24 +18397,24 @@ async function readHookStdin() {
|
|
|
18001
18397
|
|
|
18002
18398
|
// src/commands/standard.ts
|
|
18003
18399
|
var import_promises13 = require("node:fs/promises");
|
|
18004
|
-
var
|
|
18400
|
+
var import_node_fs34 = require("node:fs");
|
|
18005
18401
|
var import_yaml3 = __toESM(require_dist());
|
|
18006
18402
|
|
|
18007
18403
|
// src/lib/synthesize.ts
|
|
18008
18404
|
var import_node_child_process9 = require("node:child_process");
|
|
18009
|
-
var
|
|
18405
|
+
var import_node_fs30 = require("node:fs");
|
|
18010
18406
|
var import_promises10 = require("node:fs/promises");
|
|
18011
|
-
var
|
|
18407
|
+
var import_node_path27 = require("node:path");
|
|
18012
18408
|
var import_yaml = __toESM(require_dist());
|
|
18013
18409
|
|
|
18014
18410
|
// src/lib/data-dir.ts
|
|
18015
|
-
var
|
|
18016
|
-
var
|
|
18411
|
+
var import_node_fs28 = require("node:fs");
|
|
18412
|
+
var import_node_path25 = require("node:path");
|
|
18017
18413
|
function resolveDataDir() {
|
|
18018
18414
|
const candidates2 = [
|
|
18019
|
-
(0,
|
|
18415
|
+
(0, import_node_path25.join)(__dirname, "..", "data"),
|
|
18020
18416
|
// installed: node_modules/@codacy/verity-cli/data
|
|
18021
|
-
(0,
|
|
18417
|
+
(0, import_node_path25.join)(__dirname, "..", "..", "data"),
|
|
18022
18418
|
// edge case: nested resolution
|
|
18023
18419
|
// THE COMMITTED SOURCE, for a source checkout that has not been built.
|
|
18024
18420
|
// cli/data/skills/ is a BUILD ARTIFACT (scripts/build.js copies client/skills
|
|
@@ -18027,14 +18423,14 @@ function resolveDataDir() {
|
|
|
18027
18423
|
// without this the synthesizer throws "Could not find Verity skill data"
|
|
18028
18424
|
// for every test and every `verity` run from source. Resolved from this
|
|
18029
18425
|
// module's own location, never the cwd: see the warning below.
|
|
18030
|
-
(0,
|
|
18426
|
+
(0, import_node_path25.join)(__dirname, "..", "..", "client"),
|
|
18031
18427
|
// bundled: cli/bin/ → ../../client
|
|
18032
|
-
(0,
|
|
18428
|
+
(0, import_node_path25.join)(__dirname, "..", "..", "..", "client"),
|
|
18033
18429
|
// tsx: cli/src/lib/ → ../../../client
|
|
18034
18430
|
...process.env.VERITY_DEV_DATA_DIR ? [process.env.VERITY_DEV_DATA_DIR] : []
|
|
18035
18431
|
];
|
|
18036
18432
|
for (const candidate of candidates2) {
|
|
18037
|
-
if ((0,
|
|
18433
|
+
if ((0, import_node_fs28.existsSync)((0, import_node_path25.join)(candidate, "skills"))) {
|
|
18038
18434
|
return candidate;
|
|
18039
18435
|
}
|
|
18040
18436
|
}
|
|
@@ -18043,13 +18439,13 @@ function resolveDataDir() {
|
|
|
18043
18439
|
);
|
|
18044
18440
|
}
|
|
18045
18441
|
function setupDataPath(file) {
|
|
18046
|
-
return (0,
|
|
18442
|
+
return (0, import_node_path25.join)(resolveDataDir(), "skills", "verity-setup", file);
|
|
18047
18443
|
}
|
|
18048
18444
|
|
|
18049
18445
|
// src/lib/detect.ts
|
|
18050
18446
|
var import_node_child_process8 = require("node:child_process");
|
|
18051
|
-
var
|
|
18052
|
-
var
|
|
18447
|
+
var import_node_fs29 = require("node:fs");
|
|
18448
|
+
var import_node_path26 = require("node:path");
|
|
18053
18449
|
var TOOLED_LANGUAGES = /* @__PURE__ */ new Set([
|
|
18054
18450
|
"typescript",
|
|
18055
18451
|
"javascript",
|
|
@@ -18106,25 +18502,25 @@ function walk(root) {
|
|
|
18106
18502
|
if (depth > WALK_MAX_DEPTH || found.length >= WALK_MAX_FILES) return;
|
|
18107
18503
|
let entries;
|
|
18108
18504
|
try {
|
|
18109
|
-
entries = (0,
|
|
18505
|
+
entries = (0, import_node_fs29.readdirSync)(dir, { withFileTypes: true });
|
|
18110
18506
|
} catch {
|
|
18111
18507
|
return;
|
|
18112
18508
|
}
|
|
18113
18509
|
for (const entry of entries) {
|
|
18114
18510
|
if (found.length >= WALK_MAX_FILES) return;
|
|
18115
18511
|
if (IGNORED_SEGMENTS.includes(entry.name)) continue;
|
|
18116
|
-
const full = (0,
|
|
18512
|
+
const full = (0, import_node_path26.join)(dir, entry.name);
|
|
18117
18513
|
if (entry.isDirectory()) visit(full, depth + 1);
|
|
18118
|
-
else if (entry.isFile()) found.push((0,
|
|
18514
|
+
else if (entry.isFile()) found.push((0, import_node_path26.relative)(root, full));
|
|
18119
18515
|
}
|
|
18120
18516
|
};
|
|
18121
18517
|
visit(root, 0);
|
|
18122
18518
|
return found;
|
|
18123
18519
|
}
|
|
18124
18520
|
function languageOf(path) {
|
|
18125
|
-
const name = (0,
|
|
18521
|
+
const name = (0, import_node_path26.basename)(path);
|
|
18126
18522
|
if (/^Dockerfile(\..+)?$/i.test(name)) return "dockerfile";
|
|
18127
|
-
if (!(0,
|
|
18523
|
+
if (!(0, import_node_path26.extname)(name)) return null;
|
|
18128
18524
|
const lang = detectLanguage(path);
|
|
18129
18525
|
return lang || null;
|
|
18130
18526
|
}
|
|
@@ -18181,7 +18577,7 @@ var TOOL_CONFIG_MARKERS = [
|
|
|
18181
18577
|
];
|
|
18182
18578
|
function readJson2(path) {
|
|
18183
18579
|
try {
|
|
18184
|
-
return JSON.parse((0,
|
|
18580
|
+
return JSON.parse((0, import_node_fs29.readFileSync)(path, "utf-8"));
|
|
18185
18581
|
} catch {
|
|
18186
18582
|
return null;
|
|
18187
18583
|
}
|
|
@@ -18206,17 +18602,17 @@ function declaredDependencies(root, files) {
|
|
|
18206
18602
|
if (deps && typeof deps === "object") names2.push(...Object.keys(deps));
|
|
18207
18603
|
}
|
|
18208
18604
|
};
|
|
18209
|
-
readPackageJson((0,
|
|
18210
|
-
const nested = files.filter((f) => f.includes("/") && (0,
|
|
18211
|
-
for (const rel of nested) readPackageJson((0,
|
|
18605
|
+
readPackageJson((0, import_node_path26.join)(root, "package.json"));
|
|
18606
|
+
const nested = files.filter((f) => f.includes("/") && (0, import_node_path26.basename)(f) === "package.json").slice(0, NESTED_MANIFEST_LIMIT);
|
|
18607
|
+
for (const rel of nested) readPackageJson((0, import_node_path26.join)(root, rel));
|
|
18212
18608
|
const pythonManifests = [
|
|
18213
|
-
...["pyproject.toml", "requirements.txt", "Pipfile", "setup.py"].map((f) => (0,
|
|
18214
|
-
...files.filter((f) => f.includes("/") && /(^|\/)(pyproject\.toml|requirements\.txt)$/.test(f)).slice(0, NESTED_MANIFEST_LIMIT).map((f) => (0,
|
|
18609
|
+
...["pyproject.toml", "requirements.txt", "Pipfile", "setup.py"].map((f) => (0, import_node_path26.join)(root, f)),
|
|
18610
|
+
...files.filter((f) => f.includes("/") && /(^|\/)(pyproject\.toml|requirements\.txt)$/.test(f)).slice(0, NESTED_MANIFEST_LIMIT).map((f) => (0, import_node_path26.join)(root, f))
|
|
18215
18611
|
];
|
|
18216
18612
|
for (const path of pythonManifests) {
|
|
18217
|
-
if (!(0,
|
|
18613
|
+
if (!(0, import_node_fs29.existsSync)(path)) continue;
|
|
18218
18614
|
try {
|
|
18219
|
-
const text = (0,
|
|
18615
|
+
const text = (0, import_node_fs29.readFileSync)(path, "utf-8");
|
|
18220
18616
|
for (const m of text.matchAll(/^\s*["']?([A-Za-z][A-Za-z0-9._-]+)/gm)) names2.push(m[1]);
|
|
18221
18617
|
for (const line of text.split("\n")) {
|
|
18222
18618
|
if (!/dependencies\s*=/.test(line)) continue;
|
|
@@ -18226,13 +18622,13 @@ function declaredDependencies(root, files) {
|
|
|
18226
18622
|
}
|
|
18227
18623
|
}
|
|
18228
18624
|
const goMods = [
|
|
18229
|
-
(0,
|
|
18230
|
-
...files.filter((f) => f.includes("/") && (0,
|
|
18625
|
+
(0, import_node_path26.join)(root, "go.mod"),
|
|
18626
|
+
...files.filter((f) => f.includes("/") && (0, import_node_path26.basename)(f) === "go.mod").slice(0, NESTED_MANIFEST_LIMIT).map((f) => (0, import_node_path26.join)(root, f))
|
|
18231
18627
|
];
|
|
18232
18628
|
for (const path of goMods) {
|
|
18233
|
-
if (!(0,
|
|
18629
|
+
if (!(0, import_node_fs29.existsSync)(path)) continue;
|
|
18234
18630
|
try {
|
|
18235
|
-
const text = (0,
|
|
18631
|
+
const text = (0, import_node_fs29.readFileSync)(path, "utf-8");
|
|
18236
18632
|
for (const m of text.matchAll(/^\s+([\w.-]+\/[\w./-]+)\s+v/gm)) {
|
|
18237
18633
|
names2.push(m[1].replace(/^github\.com\//, ""));
|
|
18238
18634
|
}
|
|
@@ -18240,10 +18636,10 @@ function declaredDependencies(root, files) {
|
|
|
18240
18636
|
}
|
|
18241
18637
|
}
|
|
18242
18638
|
for (const file of ["pom.xml", "build.gradle", "build.gradle.kts", "Gemfile", "Cargo.toml"]) {
|
|
18243
|
-
const path = (0,
|
|
18244
|
-
if (!(0,
|
|
18639
|
+
const path = (0, import_node_path26.join)(root, file);
|
|
18640
|
+
if (!(0, import_node_fs29.existsSync)(path)) continue;
|
|
18245
18641
|
try {
|
|
18246
|
-
const text = (0,
|
|
18642
|
+
const text = (0, import_node_fs29.readFileSync)(path, "utf-8");
|
|
18247
18643
|
for (const m of text.matchAll(/["'<]([A-Za-z][A-Za-z0-9._-]{2,})["'>]/g)) names2.push(m[1]);
|
|
18248
18644
|
} catch {
|
|
18249
18645
|
}
|
|
@@ -18251,7 +18647,7 @@ function declaredDependencies(root, files) {
|
|
|
18251
18647
|
return names2;
|
|
18252
18648
|
}
|
|
18253
18649
|
function detectBuildSystem(root, files) {
|
|
18254
|
-
const has = (f) => (0,
|
|
18650
|
+
const has = (f) => (0, import_node_fs29.existsSync)((0, import_node_path26.join)(root, f)) || files.some((p) => (0, import_node_path26.basename)(p) === f);
|
|
18255
18651
|
if (has("pnpm-lock.yaml")) return "pnpm";
|
|
18256
18652
|
if (has("yarn.lock")) return "yarn";
|
|
18257
18653
|
if (has("bun.lock") || has("bun.lockb")) return "bun";
|
|
@@ -18268,8 +18664,8 @@ function detectBuildSystem(root, files) {
|
|
|
18268
18664
|
}
|
|
18269
18665
|
function detectArchitecture(root, files) {
|
|
18270
18666
|
const workspaceMarkers = ["lerna.json", "pnpm-workspace.yaml", "nx.json", "turbo.json", "rush.json"];
|
|
18271
|
-
if (workspaceMarkers.some((m) => (0,
|
|
18272
|
-
const pkg = readJson2((0,
|
|
18667
|
+
if (workspaceMarkers.some((m) => (0, import_node_fs29.existsSync)((0, import_node_path26.join)(root, m)))) return "monorepo";
|
|
18668
|
+
const pkg = readJson2((0, import_node_path26.join)(root, "package.json"));
|
|
18273
18669
|
if (pkg && "workspaces" in pkg) return "monorepo";
|
|
18274
18670
|
const manifests = files.filter((f) => /(^|\/)(package\.json|go\.mod|pyproject\.toml|Cargo\.toml|pom\.xml)$/.test(f));
|
|
18275
18671
|
const nested = manifests.filter((f) => f.includes("/"));
|
|
@@ -18291,10 +18687,10 @@ function measureAvgFileLength(root, files, languages) {
|
|
|
18291
18687
|
let total = 0;
|
|
18292
18688
|
let counted = 0;
|
|
18293
18689
|
for (let i = 0; i < candidates2.length; i += stride) {
|
|
18294
|
-
const path = (0,
|
|
18690
|
+
const path = (0, import_node_path26.join)(root, candidates2[i]);
|
|
18295
18691
|
try {
|
|
18296
|
-
if ((0,
|
|
18297
|
-
total += (0,
|
|
18692
|
+
if ((0, import_node_fs29.statSync)(path).size > 2 * 1024 * 1024) continue;
|
|
18693
|
+
total += (0, import_node_fs29.readFileSync)(path, "utf-8").split("\n").length;
|
|
18298
18694
|
counted++;
|
|
18299
18695
|
} catch {
|
|
18300
18696
|
}
|
|
@@ -18324,14 +18720,14 @@ function detectProject(root = repoRoot()) {
|
|
|
18324
18720
|
const existingToolConfigs = [];
|
|
18325
18721
|
for (const [tool, markers] of TOOL_CONFIG_MARKERS) {
|
|
18326
18722
|
for (const marker of markers) {
|
|
18327
|
-
if ((0,
|
|
18723
|
+
if ((0, import_node_fs29.existsSync)((0, import_node_path26.join)(root, marker))) {
|
|
18328
18724
|
existingToolConfigs.push({ tool, path: `./${marker}` });
|
|
18329
18725
|
break;
|
|
18330
18726
|
}
|
|
18331
18727
|
}
|
|
18332
18728
|
}
|
|
18333
18729
|
return {
|
|
18334
|
-
projectName: (0,
|
|
18730
|
+
projectName: (0, import_node_path26.basename)(root),
|
|
18335
18731
|
languages,
|
|
18336
18732
|
languageCounts,
|
|
18337
18733
|
frameworks: matchAll(dependencies, FRAMEWORK_BY_DEPENDENCY),
|
|
@@ -18429,8 +18825,8 @@ ${closingNote(input.origin)}
|
|
|
18429
18825
|
|
|
18430
18826
|
// src/lib/synthesize.ts
|
|
18431
18827
|
function loadCatalog() {
|
|
18432
|
-
const catalog = (0, import_yaml.parse)((0,
|
|
18433
|
-
const template = (0, import_yaml.parse)((0,
|
|
18828
|
+
const catalog = (0, import_yaml.parse)((0, import_node_fs30.readFileSync)(setupDataPath("patterns-reference.yaml"), "utf-8"));
|
|
18829
|
+
const template = (0, import_yaml.parse)((0, import_node_fs30.readFileSync)(setupDataPath("standard-template.yaml"), "utf-8"));
|
|
18434
18830
|
return { catalog, template };
|
|
18435
18831
|
}
|
|
18436
18832
|
function selectTools(languages, intensity, catalog) {
|
|
@@ -18708,7 +19104,7 @@ function validatePatternIds() {
|
|
|
18708
19104
|
}
|
|
18709
19105
|
async function runSynthesis(opts) {
|
|
18710
19106
|
const standardPath = projectPath(STANDARD_FILE);
|
|
18711
|
-
if ((0,
|
|
19107
|
+
if ((0, import_node_fs30.existsSync)(standardPath) && !opts.force) {
|
|
18712
19108
|
return { refused: `${STANDARD_FILE} already exists \u2014 pass --force to replace it.` };
|
|
18713
19109
|
}
|
|
18714
19110
|
const detected = opts.detected ?? detectProject();
|
|
@@ -18777,7 +19173,7 @@ async function correctVerityMdVersion(opts) {
|
|
|
18777
19173
|
}
|
|
18778
19174
|
async function writeFileTo(relative3, body) {
|
|
18779
19175
|
const target = projectPath(relative3);
|
|
18780
|
-
await (0, import_promises10.mkdir)((0,
|
|
19176
|
+
await (0, import_promises10.mkdir)((0, import_node_path27.dirname)(target), { recursive: true });
|
|
18781
19177
|
await (0, import_promises10.writeFile)(target, body);
|
|
18782
19178
|
}
|
|
18783
19179
|
async function deriveConfigForStandard(standard) {
|
|
@@ -18836,11 +19232,11 @@ ${validation.detail}`);
|
|
|
18836
19232
|
|
|
18837
19233
|
// src/lib/setup-state.ts
|
|
18838
19234
|
var import_promises11 = require("node:fs/promises");
|
|
18839
|
-
var
|
|
19235
|
+
var import_node_fs31 = require("node:fs");
|
|
18840
19236
|
var SETUP_STATE_FILE = `${VERITY_DIR}/setup.json`;
|
|
18841
19237
|
async function readSetupState() {
|
|
18842
19238
|
const path = projectPath(SETUP_STATE_FILE);
|
|
18843
|
-
if (!(0,
|
|
19239
|
+
if (!(0, import_node_fs31.existsSync)(path)) return null;
|
|
18844
19240
|
try {
|
|
18845
19241
|
const parsed = JSON.parse(await (0, import_promises11.readFile)(path, "utf-8"));
|
|
18846
19242
|
return parsed && typeof parsed === "object" ? parsed : null;
|
|
@@ -18856,12 +19252,12 @@ async function writeSetupState(patch) {
|
|
|
18856
19252
|
}
|
|
18857
19253
|
|
|
18858
19254
|
// src/lib/push-setup.ts
|
|
18859
|
-
var
|
|
19255
|
+
var import_node_fs33 = require("node:fs");
|
|
18860
19256
|
var import_promises12 = require("node:fs/promises");
|
|
18861
19257
|
var import_yaml2 = __toESM(require_dist());
|
|
18862
19258
|
|
|
18863
19259
|
// src/lib/verityignore.ts
|
|
18864
|
-
var
|
|
19260
|
+
var import_node_fs32 = require("node:fs");
|
|
18865
19261
|
var EMPTY = { rules: [], securityOverlap: [], problems: [] };
|
|
18866
19262
|
var SECURITY_PROBES = [
|
|
18867
19263
|
".env",
|
|
@@ -18954,9 +19350,9 @@ function isIgnored3(ig, path) {
|
|
|
18954
19350
|
}
|
|
18955
19351
|
function loadVerityIgnore() {
|
|
18956
19352
|
const file = projectPath(VERITYIGNORE_FILE);
|
|
18957
|
-
if (!(0,
|
|
19353
|
+
if (!(0, import_node_fs32.existsSync)(file)) return EMPTY;
|
|
18958
19354
|
try {
|
|
18959
|
-
return parseVerityIgnore((0,
|
|
19355
|
+
return parseVerityIgnore((0, import_node_fs32.readFileSync)(file, "utf-8"));
|
|
18960
19356
|
} catch {
|
|
18961
19357
|
return EMPTY;
|
|
18962
19358
|
}
|
|
@@ -18994,9 +19390,9 @@ function buildStandardUpload(standard, ignoreRaw) {
|
|
|
18994
19390
|
}
|
|
18995
19391
|
function readVerityIgnoreRaw() {
|
|
18996
19392
|
const file = projectPath(VERITYIGNORE_FILE);
|
|
18997
|
-
if (!(0,
|
|
19393
|
+
if (!(0, import_node_fs32.existsSync)(file)) return null;
|
|
18998
19394
|
try {
|
|
18999
|
-
return (0,
|
|
19395
|
+
return (0, import_node_fs32.readFileSync)(file, "utf-8");
|
|
19000
19396
|
} catch {
|
|
19001
19397
|
return null;
|
|
19002
19398
|
}
|
|
@@ -19024,7 +19420,7 @@ async function pushStandardAndConfig(globals, what = {}) {
|
|
|
19024
19420
|
}
|
|
19025
19421
|
let standardVersion = null;
|
|
19026
19422
|
const standardPath = projectPath(STANDARD_FILE);
|
|
19027
|
-
if (pushStandard && (0,
|
|
19423
|
+
if (pushStandard && (0, import_node_fs33.existsSync)(standardPath)) {
|
|
19028
19424
|
try {
|
|
19029
19425
|
const content = (0, import_yaml2.parse)(await (0, import_promises12.readFile)(standardPath, "utf-8"));
|
|
19030
19426
|
const upload = buildStandardUpload(content, readVerityIgnoreRaw());
|
|
@@ -19049,7 +19445,7 @@ async function pushStandardAndConfig(globals, what = {}) {
|
|
|
19049
19445
|
}
|
|
19050
19446
|
let configPushed = false;
|
|
19051
19447
|
const configPath = projectPath(CODACY_CONFIG_FILE);
|
|
19052
|
-
if (pushConfig && (0,
|
|
19448
|
+
if (pushConfig && (0, import_node_fs33.existsSync)(configPath)) {
|
|
19053
19449
|
try {
|
|
19054
19450
|
const content = JSON.parse(await (0, import_promises12.readFile)(configPath, "utf-8"));
|
|
19055
19451
|
const result = await apiRequest({
|
|
@@ -19081,7 +19477,7 @@ function registerStandardCommands(program2) {
|
|
|
19081
19477
|
const state = await readSetupState();
|
|
19082
19478
|
if (opts.configOnly) {
|
|
19083
19479
|
const standardPath = projectPath(STANDARD_FILE);
|
|
19084
|
-
if (!(0,
|
|
19480
|
+
if (!(0, import_node_fs34.existsSync)(standardPath)) {
|
|
19085
19481
|
printError(`No ${STANDARD_FILE} here \u2014 run "verity standard synthesize" to create one.`);
|
|
19086
19482
|
process.exit(1);
|
|
19087
19483
|
}
|
|
@@ -19414,20 +19810,20 @@ function formatRunDetail(run2) {
|
|
|
19414
19810
|
}
|
|
19415
19811
|
|
|
19416
19812
|
// src/lib/ignore-declaration.ts
|
|
19417
|
-
var
|
|
19813
|
+
var import_node_fs36 = require("node:fs");
|
|
19418
19814
|
|
|
19419
19815
|
// src/lib/debounce.ts
|
|
19420
|
-
var
|
|
19421
|
-
var
|
|
19816
|
+
var import_node_fs35 = require("node:fs");
|
|
19817
|
+
var import_node_crypto11 = require("node:crypto");
|
|
19422
19818
|
function scopedFile(base, sessionId) {
|
|
19423
19819
|
if (!sessionId) return base;
|
|
19424
|
-
return `${base}.${(0,
|
|
19820
|
+
return `${base}.${(0, import_node_crypto11.createHash)("sha1").update(sessionId).digest("hex").slice(0, 12)}`;
|
|
19425
19821
|
}
|
|
19426
19822
|
function checkDebounce(debounceSeconds = DEBOUNCE_SECONDS, sessionId) {
|
|
19427
19823
|
const file = scopedFile(DEBOUNCE_FILE, sessionId);
|
|
19428
|
-
if (!(0,
|
|
19824
|
+
if (!(0, import_node_fs35.existsSync)(file)) return null;
|
|
19429
19825
|
try {
|
|
19430
|
-
const lastTs = parseInt((0,
|
|
19826
|
+
const lastTs = parseInt((0, import_node_fs35.readFileSync)(file, "utf-8").trim(), 10);
|
|
19431
19827
|
const nowTs = Math.floor(Date.now() / 1e3);
|
|
19432
19828
|
const elapsed = nowTs - lastTs;
|
|
19433
19829
|
if (elapsed < debounceSeconds) {
|
|
@@ -19440,10 +19836,10 @@ function checkDebounce(debounceSeconds = DEBOUNCE_SECONDS, sessionId) {
|
|
|
19440
19836
|
function checkMtime(files, bypassForRecentCommits, sessionId) {
|
|
19441
19837
|
if (bypassForRecentCommits) return null;
|
|
19442
19838
|
const file = scopedFile(DEBOUNCE_FILE, sessionId);
|
|
19443
|
-
if (!(0,
|
|
19839
|
+
if (!(0, import_node_fs35.existsSync)(file)) return null;
|
|
19444
19840
|
let debounceTime;
|
|
19445
19841
|
try {
|
|
19446
|
-
debounceTime = (0,
|
|
19842
|
+
debounceTime = (0, import_node_fs35.statSync)(file).mtimeMs;
|
|
19447
19843
|
} catch {
|
|
19448
19844
|
return null;
|
|
19449
19845
|
}
|
|
@@ -19451,7 +19847,7 @@ function checkMtime(files, bypassForRecentCommits, sessionId) {
|
|
|
19451
19847
|
const resolved = resolveFile(f);
|
|
19452
19848
|
if (!resolved) continue;
|
|
19453
19849
|
try {
|
|
19454
|
-
const stat3 = (0,
|
|
19850
|
+
const stat3 = (0, import_node_fs35.statSync)(resolved);
|
|
19455
19851
|
if (stat3.mtimeMs > debounceTime) {
|
|
19456
19852
|
return null;
|
|
19457
19853
|
}
|
|
@@ -19462,13 +19858,13 @@ function checkMtime(files, bypassForRecentCommits, sessionId) {
|
|
|
19462
19858
|
return "No files modified since last analysis";
|
|
19463
19859
|
}
|
|
19464
19860
|
function computeContentHash(files) {
|
|
19465
|
-
const hash = (0,
|
|
19861
|
+
const hash = (0, import_node_crypto11.createHash)("sha1");
|
|
19466
19862
|
const sorted = [...files].sort();
|
|
19467
19863
|
for (const f of sorted) {
|
|
19468
19864
|
const resolved = resolveFile(f) ?? f;
|
|
19469
19865
|
try {
|
|
19470
|
-
if ((0,
|
|
19471
|
-
hash.update((0,
|
|
19866
|
+
if ((0, import_node_fs35.existsSync)(resolved)) {
|
|
19867
|
+
hash.update((0, import_node_fs35.readFileSync)(resolved));
|
|
19472
19868
|
}
|
|
19473
19869
|
} catch {
|
|
19474
19870
|
}
|
|
@@ -19478,9 +19874,9 @@ function computeContentHash(files) {
|
|
|
19478
19874
|
function checkContentHash(files, sessionId) {
|
|
19479
19875
|
const hash = computeContentHash(files);
|
|
19480
19876
|
const file = scopedFile(HASH_FILE, sessionId);
|
|
19481
|
-
if ((0,
|
|
19877
|
+
if ((0, import_node_fs35.existsSync)(file)) {
|
|
19482
19878
|
try {
|
|
19483
|
-
const storedHash = (0,
|
|
19879
|
+
const storedHash = (0, import_node_fs35.readFileSync)(file, "utf-8").trim();
|
|
19484
19880
|
if (hash === storedHash) {
|
|
19485
19881
|
return { skip: "No source changes since last analysis", hash };
|
|
19486
19882
|
}
|
|
@@ -19490,24 +19886,24 @@ function checkContentHash(files, sessionId) {
|
|
|
19490
19886
|
return { skip: null, hash };
|
|
19491
19887
|
}
|
|
19492
19888
|
function recordAnalysisStart(sessionId) {
|
|
19493
|
-
(0,
|
|
19494
|
-
(0,
|
|
19889
|
+
(0, import_node_fs35.mkdirSync)(VERITY_DIR, { recursive: true });
|
|
19890
|
+
(0, import_node_fs35.writeFileSync)(scopedFile(DEBOUNCE_FILE, sessionId), String(Math.floor(Date.now() / 1e3)));
|
|
19495
19891
|
}
|
|
19496
19892
|
function recordPassHash(hash, sessionId) {
|
|
19497
|
-
(0,
|
|
19893
|
+
(0, import_node_fs35.writeFileSync)(scopedFile(HASH_FILE, sessionId), hash);
|
|
19498
19894
|
}
|
|
19499
19895
|
function narrowToRecent(files, sessionId) {
|
|
19500
19896
|
const file = scopedFile(DEBOUNCE_FILE, sessionId);
|
|
19501
|
-
if (!(0,
|
|
19897
|
+
if (!(0, import_node_fs35.existsSync)(file)) return files;
|
|
19502
19898
|
let debounceTime;
|
|
19503
19899
|
try {
|
|
19504
|
-
debounceTime = (0,
|
|
19900
|
+
debounceTime = (0, import_node_fs35.statSync)(file).mtimeMs;
|
|
19505
19901
|
} catch {
|
|
19506
19902
|
return files;
|
|
19507
19903
|
}
|
|
19508
19904
|
const recent = files.filter((f) => {
|
|
19509
19905
|
try {
|
|
19510
|
-
return (0,
|
|
19906
|
+
return (0, import_node_fs35.existsSync)(f) && (0, import_node_fs35.statSync)(f).mtimeMs > debounceTime;
|
|
19511
19907
|
} catch {
|
|
19512
19908
|
return false;
|
|
19513
19909
|
}
|
|
@@ -19520,9 +19916,9 @@ function readIteration(currentCommit, _contentHash) {
|
|
|
19520
19916
|
var NO_BLOCKS = { attempts: 0, blocks: 0, fingerprint: null };
|
|
19521
19917
|
function readBlockState(currentCommit, opts) {
|
|
19522
19918
|
if (opts?.newUserPrompt) return NO_BLOCKS;
|
|
19523
|
-
if (!(0,
|
|
19919
|
+
if (!(0, import_node_fs35.existsSync)(ITERATION_FILE)) return NO_BLOCKS;
|
|
19524
19920
|
try {
|
|
19525
|
-
const stored = (0,
|
|
19921
|
+
const stored = (0, import_node_fs35.readFileSync)(ITERATION_FILE, "utf-8").trim();
|
|
19526
19922
|
const parsed = stored.startsWith("{") ? parseJsonState(stored) : parseLegacyState(stored);
|
|
19527
19923
|
if (!parsed) return NO_BLOCKS;
|
|
19528
19924
|
if (parsed.commit !== currentCommit) return NO_BLOCKS;
|
|
@@ -19568,8 +19964,8 @@ function isSameProblem(previous, current) {
|
|
|
19568
19964
|
return current.split(",").some((k) => prev.has(k));
|
|
19569
19965
|
}
|
|
19570
19966
|
function writeBlockState(commit, state) {
|
|
19571
|
-
(0,
|
|
19572
|
-
(0,
|
|
19967
|
+
(0, import_node_fs35.mkdirSync)(VERITY_DIR, { recursive: true });
|
|
19968
|
+
(0, import_node_fs35.writeFileSync)(
|
|
19573
19969
|
ITERATION_FILE,
|
|
19574
19970
|
JSON.stringify({
|
|
19575
19971
|
v: 2,
|
|
@@ -19674,9 +20070,9 @@ function resolveIgnoreState(keys) {
|
|
|
19674
20070
|
}
|
|
19675
20071
|
function readIgnoreState(sessionId) {
|
|
19676
20072
|
const file = stateFile(sessionId);
|
|
19677
|
-
if (!(0,
|
|
20073
|
+
if (!(0, import_node_fs36.existsSync)(file)) return null;
|
|
19678
20074
|
try {
|
|
19679
|
-
const o = JSON.parse((0,
|
|
20075
|
+
const o = JSON.parse((0, import_node_fs36.readFileSync)(file, "utf-8")) ?? {};
|
|
19680
20076
|
const spent = typeof o.spent === "number" ? o.spent : 0;
|
|
19681
20077
|
const raw = o.active;
|
|
19682
20078
|
let active = null;
|
|
@@ -19700,8 +20096,8 @@ function readIgnoreState(sessionId) {
|
|
|
19700
20096
|
}
|
|
19701
20097
|
function writeIgnoreState(state, sessionId) {
|
|
19702
20098
|
try {
|
|
19703
|
-
(0,
|
|
19704
|
-
(0,
|
|
20099
|
+
(0, import_node_fs36.mkdirSync)(projectPath(VERITY_DIR), { recursive: true });
|
|
20100
|
+
(0, import_node_fs36.writeFileSync)(stateFile(sessionId), JSON.stringify({ v: 1, active: state.active, spent: state.spent }));
|
|
19705
20101
|
} catch {
|
|
19706
20102
|
}
|
|
19707
20103
|
}
|
|
@@ -20084,7 +20480,7 @@ function createRun(opts, globals) {
|
|
|
20084
20480
|
}
|
|
20085
20481
|
|
|
20086
20482
|
// src/commands/analyze/index.ts
|
|
20087
|
-
var
|
|
20483
|
+
var import_node_fs49 = require("node:fs");
|
|
20088
20484
|
|
|
20089
20485
|
// src/lib/repo-context.ts
|
|
20090
20486
|
var import_node_child_process10 = require("node:child_process");
|
|
@@ -21020,10 +21416,10 @@ function installRunEvidence(run2) {
|
|
|
21020
21416
|
}
|
|
21021
21417
|
|
|
21022
21418
|
// src/lib/git-frame.ts
|
|
21023
|
-
var
|
|
21419
|
+
var import_node_fs37 = require("node:fs");
|
|
21024
21420
|
var import_node_os6 = require("node:os");
|
|
21025
|
-
var import_node_path27 = require("node:path");
|
|
21026
21421
|
var import_node_path28 = require("node:path");
|
|
21422
|
+
var import_node_path29 = require("node:path");
|
|
21027
21423
|
|
|
21028
21424
|
// src/lib/hardened-git.ts
|
|
21029
21425
|
var import_node_child_process11 = require("node:child_process");
|
|
@@ -21185,8 +21581,8 @@ function extractCommandTarget(command, segmentIndex, baseDir) {
|
|
|
21185
21581
|
if (SHELL_DYNAMIC.test(raw) || raw === "-") {
|
|
21186
21582
|
return { dir: null, named: true, unresolvable: `cd target not statically resolvable: ${raw}` };
|
|
21187
21583
|
}
|
|
21188
|
-
const expanded = raw === "~" ? (0, import_node_os6.homedir)() : raw.startsWith("~/") ? (0,
|
|
21189
|
-
dir = (0,
|
|
21584
|
+
const expanded = raw === "~" ? (0, import_node_os6.homedir)() : raw.startsWith("~/") ? (0, import_node_path29.join)((0, import_node_os6.homedir)(), raw.slice(2)) : raw;
|
|
21585
|
+
dir = (0, import_node_path28.isAbsolute)(expanded) ? expanded : (0, import_node_path28.resolve)(dir, expanded);
|
|
21190
21586
|
}
|
|
21191
21587
|
const seg = segments[segmentIndex];
|
|
21192
21588
|
const overrideMatch = /--(?:git-dir|work-tree)(?:=|\s)|\bGIT_(?:DIR|WORK_TREE|INDEX_FILE)=/.exec(seg);
|
|
@@ -21204,8 +21600,8 @@ function extractCommandTarget(command, segmentIndex, baseDir) {
|
|
|
21204
21600
|
if (SHELL_DYNAMIC.test(raw)) {
|
|
21205
21601
|
return { dir: null, named: true, unresolvable: `-C target not statically resolvable: ${raw}` };
|
|
21206
21602
|
}
|
|
21207
|
-
const expanded = raw === "~" ? (0, import_node_os6.homedir)() : raw.startsWith("~/") ? (0,
|
|
21208
|
-
dir = (0,
|
|
21603
|
+
const expanded = raw === "~" ? (0, import_node_os6.homedir)() : raw.startsWith("~/") ? (0, import_node_path29.join)((0, import_node_os6.homedir)(), raw.slice(2)) : raw;
|
|
21604
|
+
dir = (0, import_node_path28.isAbsolute)(expanded) ? expanded : (0, import_node_path28.resolve)(dir, expanded);
|
|
21209
21605
|
}
|
|
21210
21606
|
}
|
|
21211
21607
|
return { dir, named, unresolvable: null };
|
|
@@ -21265,14 +21661,14 @@ function gitAt(dir, args) {
|
|
|
21265
21661
|
}
|
|
21266
21662
|
function realpathOr2(p) {
|
|
21267
21663
|
try {
|
|
21268
|
-
return
|
|
21664
|
+
return import_node_fs37.realpathSync.native(p);
|
|
21269
21665
|
} catch {
|
|
21270
|
-
return (0,
|
|
21666
|
+
return (0, import_node_path28.resolve)(p);
|
|
21271
21667
|
}
|
|
21272
21668
|
}
|
|
21273
21669
|
function resolveFrame(input) {
|
|
21274
21670
|
const found = findMomentSegment(input.command, input.on);
|
|
21275
|
-
const hookDirUsable = !!input.hookCwd && (0,
|
|
21671
|
+
const hookDirUsable = !!input.hookCwd && (0, import_node_fs37.existsSync)(input.hookCwd);
|
|
21276
21672
|
const baseDir = hookDirUsable ? input.hookCwd : process.cwd();
|
|
21277
21673
|
let anchor = hookDirUsable ? "hook-cwd" : "process-cwd";
|
|
21278
21674
|
const refuse = (refusal) => ({
|
|
@@ -21295,7 +21691,7 @@ function resolveFrame(input) {
|
|
|
21295
21691
|
if (dirs.size > 1) return refuse(`target:multiple ${found.moment} targets in one command`);
|
|
21296
21692
|
const targetDir = dirs.size === 1 ? [...dirs][0] : baseDir;
|
|
21297
21693
|
if (targetDir !== baseDir) {
|
|
21298
|
-
if (!(0,
|
|
21694
|
+
if (!(0, import_node_fs37.existsSync)(targetDir)) return refuse(`target:directory does not exist: ${targetDir}`);
|
|
21299
21695
|
dir = targetDir;
|
|
21300
21696
|
}
|
|
21301
21697
|
}
|
|
@@ -21306,7 +21702,7 @@ function resolveFrame(input) {
|
|
|
21306
21702
|
const gitDirRaw = gitAt(dir, ["rev-parse", "--absolute-git-dir"]);
|
|
21307
21703
|
const commonRaw = gitAt(dir, ["rev-parse", "--git-common-dir"]);
|
|
21308
21704
|
const gitDir = gitDirRaw ? realpathOr2(gitDirRaw) : null;
|
|
21309
|
-
const commonDir = commonRaw ? realpathOr2((0,
|
|
21705
|
+
const commonDir = commonRaw ? realpathOr2((0, import_node_path28.isAbsolute)(commonRaw) ? commonRaw : (0, import_node_path28.resolve)(dir, commonRaw)) : null;
|
|
21310
21706
|
const branchRaw = gitAt(dir, ["rev-parse", "--abbrev-ref", "HEAD"]);
|
|
21311
21707
|
return {
|
|
21312
21708
|
moment: found?.moment ?? null,
|
|
@@ -21481,8 +21877,8 @@ function stagedRange(frame, command) {
|
|
|
21481
21877
|
if (plan.kind === "unpredictable") {
|
|
21482
21878
|
return { kind: "staged", base: "HEAD", head: "INDEX", via: "staged-in-command", refusal: plan.reason };
|
|
21483
21879
|
}
|
|
21484
|
-
const mergeHead = frame.gitDir ? (0,
|
|
21485
|
-
if (mergeHead && (0,
|
|
21880
|
+
const mergeHead = frame.gitDir ? (0, import_node_path29.join)(frame.gitDir, "MERGE_HEAD") : null;
|
|
21881
|
+
if (mergeHead && (0, import_node_fs37.existsSync)(mergeHead)) {
|
|
21486
21882
|
const vsHead = new Set(frameGit(frame, ["diff", "--cached", "--name-only", "HEAD"]).split("\n").filter(Boolean));
|
|
21487
21883
|
const vsMerge = new Set(frameGit(frame, ["diff", "--cached", "--name-only", "MERGE_HEAD"]).split("\n").filter(Boolean));
|
|
21488
21884
|
const resolutions = new Set([...vsHead].filter((f) => vsMerge.has(f) && !isVerityOwnedPath(f)));
|
|
@@ -21616,7 +22012,7 @@ function truthy(v) {
|
|
|
21616
22012
|
}
|
|
21617
22013
|
|
|
21618
22014
|
// src/lib/transcript.ts
|
|
21619
|
-
var
|
|
22015
|
+
var import_node_fs38 = require("node:fs");
|
|
21620
22016
|
var MAX_READ_BYTES = 256 * 1024;
|
|
21621
22017
|
var SMALL_FILE_BYTES = 64 * 1024;
|
|
21622
22018
|
var MAX_FILES_LIST = 20;
|
|
@@ -21643,7 +22039,7 @@ async function extractActionSummary(transcriptPath) {
|
|
|
21643
22039
|
function readTurnLines(transcriptPath) {
|
|
21644
22040
|
let size;
|
|
21645
22041
|
try {
|
|
21646
|
-
size = (0,
|
|
22042
|
+
size = (0, import_node_fs38.statSync)(transcriptPath).size;
|
|
21647
22043
|
} catch {
|
|
21648
22044
|
return null;
|
|
21649
22045
|
}
|
|
@@ -21651,7 +22047,7 @@ function readTurnLines(transcriptPath) {
|
|
|
21651
22047
|
let raw;
|
|
21652
22048
|
let windowed = false;
|
|
21653
22049
|
if (size <= SMALL_FILE_BYTES) {
|
|
21654
|
-
raw = (0,
|
|
22050
|
+
raw = (0, import_node_fs38.readFileSync)(transcriptPath, "utf-8");
|
|
21655
22051
|
} else {
|
|
21656
22052
|
windowed = true;
|
|
21657
22053
|
const buf = Buffer.alloc(Math.min(MAX_READ_BYTES, size));
|
|
@@ -22042,6 +22438,52 @@ function partitionVerityOwned(paths) {
|
|
|
22042
22438
|
return { kept, owned };
|
|
22043
22439
|
}
|
|
22044
22440
|
|
|
22441
|
+
// src/lib/knowledge-note-state.ts
|
|
22442
|
+
var stateDir = () => projectPath(VERITY_DIR);
|
|
22443
|
+
var STATE_FILE2 = "knowledge-note-state.json";
|
|
22444
|
+
function parseKnowledgeNote(raw) {
|
|
22445
|
+
if (!raw || typeof raw !== "object") return null;
|
|
22446
|
+
const o = raw;
|
|
22447
|
+
const node_id = typeof o.node_id === "string" ? o.node_id.trim() : "";
|
|
22448
|
+
const text = typeof o.text === "string" ? o.text.trim() : "";
|
|
22449
|
+
if (!node_id || !text) return null;
|
|
22450
|
+
if (text.length > 1e3) return null;
|
|
22451
|
+
return {
|
|
22452
|
+
node_id,
|
|
22453
|
+
text,
|
|
22454
|
+
file: typeof o.file === "string" && o.file ? o.file : null,
|
|
22455
|
+
line: typeof o.line === "number" && Number.isFinite(o.line) && o.line > 0 ? Math.floor(o.line) : null
|
|
22456
|
+
};
|
|
22457
|
+
}
|
|
22458
|
+
function recordNoteOutcome(runId, delivered) {
|
|
22459
|
+
replaceInRoot(stateDir(), STATE_FILE2, JSON.stringify({ run_id: runId, delivered }));
|
|
22460
|
+
}
|
|
22461
|
+
function peekNoteOutcome() {
|
|
22462
|
+
try {
|
|
22463
|
+
const read = readRegularFileInRoot(stateDir(), STATE_FILE2, 4096);
|
|
22464
|
+
if (!read.ok || !read.content.trim()) return null;
|
|
22465
|
+
const parsed = JSON.parse(read.content);
|
|
22466
|
+
if (!parsed || typeof parsed !== "object") return null;
|
|
22467
|
+
const o = parsed;
|
|
22468
|
+
if (typeof o.run_id !== "string" || !/^run-\d{14}-[0-9a-f]{8}$/.test(o.run_id)) return null;
|
|
22469
|
+
if (typeof o.delivered !== "boolean") return null;
|
|
22470
|
+
return { run_id: o.run_id, delivered: o.delivered };
|
|
22471
|
+
} catch {
|
|
22472
|
+
return null;
|
|
22473
|
+
}
|
|
22474
|
+
}
|
|
22475
|
+
function clearNoteOutcome() {
|
|
22476
|
+
replaceInRoot(stateDir(), STATE_FILE2, "");
|
|
22477
|
+
}
|
|
22478
|
+
function episodeForWire(e, humanSpoke) {
|
|
22479
|
+
return {
|
|
22480
|
+
delivered: e?.delivered ?? 0,
|
|
22481
|
+
tasks_completed: e?.tasksCompleted ?? 0,
|
|
22482
|
+
ts: e?.ts ?? 0,
|
|
22483
|
+
human_spoke: humanSpoke
|
|
22484
|
+
};
|
|
22485
|
+
}
|
|
22486
|
+
|
|
22045
22487
|
// src/lib/channel.ts
|
|
22046
22488
|
var MAX_AGENT_CONTEXT_CHARS = 1500;
|
|
22047
22489
|
var MAX_AGENT_ITEMS = 5;
|
|
@@ -22063,7 +22505,14 @@ function channelInputFrom(response, intentRepeat = 0, priorPendingFingerprints =
|
|
|
22063
22505
|
reviewStatus: metadata.review_status,
|
|
22064
22506
|
coverage: metadata.coverage,
|
|
22065
22507
|
intentVerdict: intent.verdict,
|
|
22066
|
-
intentGaps: intent.gaps
|
|
22508
|
+
intentGaps: intent.gaps,
|
|
22509
|
+
// Phase 5. Parsed defensively: a malformed or oversized note degrades to
|
|
22510
|
+
// silence rather than to a broken agent message, and an old server simply
|
|
22511
|
+
// sends nothing — which is indistinguishable from a server that chose to
|
|
22512
|
+
// stay quiet, as it should be.
|
|
22513
|
+
knowledgeNote: parseKnowledgeNote(
|
|
22514
|
+
response.knowledge_note ?? metadata.knowledge_note
|
|
22515
|
+
)?.text
|
|
22067
22516
|
};
|
|
22068
22517
|
}
|
|
22069
22518
|
function classifyChannelContent(input) {
|
|
@@ -22071,7 +22520,13 @@ function classifyChannelContent(input) {
|
|
|
22071
22520
|
const intentFlag = input.intentVerdict === "misaligned" || input.intentVerdict === "partial";
|
|
22072
22521
|
const advisory = (input.findings ?? []).some((f) => f.scope !== "pre-existing") || (input.pendingItems ?? []).some(
|
|
22073
22522
|
(p) => p.pattern_id !== "intent-misalignment" && !!(p.description ?? p.title ?? p.reason)
|
|
22074
|
-
)
|
|
22523
|
+
) || // ⚠ A KNOWLEDGE NOTE IS ADVISORY CONTENT, and it must be classified as such
|
|
22524
|
+
// or the invariant above breaks: `buildAgentContext` would return a message
|
|
22525
|
+
// on a run where all three classes are false, which is exactly the drift
|
|
22526
|
+
// this pair is written to prevent. It is advisory rather than refusal or
|
|
22527
|
+
// intent because it costs the agent a turn — the same cost the episode
|
|
22528
|
+
// budget exists to bound.
|
|
22529
|
+
!!input.knowledgeNote;
|
|
22075
22530
|
return { refusal, intentFlag, advisory };
|
|
22076
22531
|
}
|
|
22077
22532
|
function buildAgentContext(input) {
|
|
@@ -22098,6 +22553,9 @@ function buildAgentContext(input) {
|
|
|
22098
22553
|
);
|
|
22099
22554
|
}
|
|
22100
22555
|
}
|
|
22556
|
+
if (input.knowledgeNote && lines.length < MAX_AGENT_ITEMS) {
|
|
22557
|
+
lines.push(`- ${input.knowledgeNote}`);
|
|
22558
|
+
}
|
|
22101
22559
|
const agentFindings = (input.findings ?? []).filter((f) => f.scope !== "pre-existing");
|
|
22102
22560
|
for (const f of agentFindings) {
|
|
22103
22561
|
if (lines.length >= MAX_AGENT_ITEMS) break;
|
|
@@ -22159,7 +22617,7 @@ function channelSilence(input) {
|
|
|
22159
22617
|
// src/lib/cli-version.ts
|
|
22160
22618
|
function cliVersion() {
|
|
22161
22619
|
try {
|
|
22162
|
-
return true ? "0.33.
|
|
22620
|
+
return true ? "0.33.3-experimental.072d5cb" : "dev";
|
|
22163
22621
|
} catch {
|
|
22164
22622
|
return "dev";
|
|
22165
22623
|
}
|
|
@@ -22200,7 +22658,7 @@ async function sendSkipBeacon(ctx, reason) {
|
|
|
22200
22658
|
|
|
22201
22659
|
// src/lib/static-analysis.ts
|
|
22202
22660
|
var import_node_child_process12 = require("node:child_process");
|
|
22203
|
-
var
|
|
22661
|
+
var import_node_fs39 = require("node:fs");
|
|
22204
22662
|
var SEVERITY_ORDER = {
|
|
22205
22663
|
Error: 0,
|
|
22206
22664
|
Critical: 0,
|
|
@@ -22256,7 +22714,7 @@ function runCodacyAnalysis(files) {
|
|
|
22256
22714
|
if (files.length === 0) return empty;
|
|
22257
22715
|
const existingFiles = files.filter((f) => {
|
|
22258
22716
|
try {
|
|
22259
|
-
return (0,
|
|
22717
|
+
return (0, import_node_fs39.existsSync)(f);
|
|
22260
22718
|
} catch {
|
|
22261
22719
|
return false;
|
|
22262
22720
|
}
|
|
@@ -22525,8 +22983,8 @@ async function scope(run2) {
|
|
|
22525
22983
|
}
|
|
22526
22984
|
|
|
22527
22985
|
// src/lib/specs.ts
|
|
22528
|
-
var
|
|
22529
|
-
var
|
|
22986
|
+
var import_node_fs40 = require("node:fs");
|
|
22987
|
+
var import_node_path30 = require("node:path");
|
|
22530
22988
|
var SPEC_CANDIDATES = [
|
|
22531
22989
|
"CLAUDE.md",
|
|
22532
22990
|
"AGENTS.md",
|
|
@@ -22548,7 +23006,7 @@ var UNCONSULTED_TOTAL_BYTES = 30720;
|
|
|
22548
23006
|
function readSpecFiles(specsOpt, root) {
|
|
22549
23007
|
const out = [];
|
|
22550
23008
|
for (const raw of specsOpt.split(",").map((f) => f.trim()).filter(Boolean)) {
|
|
22551
|
-
const candidate = (0,
|
|
23009
|
+
const candidate = (0, import_node_path30.isAbsolute)(raw) ? (0, import_node_path30.relative)(root, raw) : raw;
|
|
22552
23010
|
const content = readFileInside(root, candidate, MAX_EXPLICIT_SPEC_FILE_BYTES);
|
|
22553
23011
|
if (content === null) continue;
|
|
22554
23012
|
out.push({ path: raw, content });
|
|
@@ -22567,7 +23025,7 @@ function discoverSpecs(consulted = []) {
|
|
|
22567
23025
|
const totalCap = relevant ? MAX_TOTAL_SPEC_BYTES : UNCONSULTED_TOTAL_BYTES;
|
|
22568
23026
|
if (totalBytes >= totalCap) return false;
|
|
22569
23027
|
if (seen.has(specPath)) return true;
|
|
22570
|
-
if (!(0,
|
|
23028
|
+
if (!(0, import_node_fs40.existsSync)(specPath)) return true;
|
|
22571
23029
|
seen.add(specPath);
|
|
22572
23030
|
const remaining = totalCap - totalBytes;
|
|
22573
23031
|
const fileCap = relevant ? MAX_SPEC_FILE_BYTES : UNCONSULTED_FILE_BYTES;
|
|
@@ -22590,7 +23048,7 @@ function discoverSpecs(consulted = []) {
|
|
|
22590
23048
|
if (!addSpec(candidate)) break;
|
|
22591
23049
|
}
|
|
22592
23050
|
for (const dir of ["spec", "docs"]) {
|
|
22593
|
-
if (!(0,
|
|
23051
|
+
if (!(0, import_node_fs40.existsSync)(dir)) continue;
|
|
22594
23052
|
try {
|
|
22595
23053
|
const mdFiles = findMdFiles(dir, 2).sort();
|
|
22596
23054
|
for (const mdFile of mdFiles) {
|
|
@@ -22605,9 +23063,9 @@ function findMdFiles(dir, maxDepth, depth = 0) {
|
|
|
22605
23063
|
if (depth >= maxDepth) return [];
|
|
22606
23064
|
const result = [];
|
|
22607
23065
|
try {
|
|
22608
|
-
const entries = (0,
|
|
23066
|
+
const entries = (0, import_node_fs40.readdirSync)(dir, { withFileTypes: true });
|
|
22609
23067
|
for (const entry of entries) {
|
|
22610
|
-
const fullPath = (0,
|
|
23068
|
+
const fullPath = (0, import_node_path30.join)(dir, entry.name);
|
|
22611
23069
|
if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
22612
23070
|
result.push(fullPath);
|
|
22613
23071
|
} else if (entry.isDirectory() && depth < maxDepth - 1) {
|
|
@@ -22620,25 +23078,25 @@ function findMdFiles(dir, maxDepth, depth = 0) {
|
|
|
22620
23078
|
}
|
|
22621
23079
|
function discoverPlans() {
|
|
22622
23080
|
const home = process.env.HOME ?? "";
|
|
22623
|
-
const homePlansDir = (0,
|
|
23081
|
+
const homePlansDir = (0, import_node_path30.join)(home, ".claude", "plans");
|
|
22624
23082
|
const sources = [];
|
|
22625
23083
|
if (isRealDirectoryChain(process.cwd(), [".claude", "plans"])) {
|
|
22626
|
-
sources.push({ root: process.cwd(), prefix: (0,
|
|
23084
|
+
sources.push({ root: process.cwd(), prefix: (0, import_node_path30.join)(".claude", "plans") });
|
|
22627
23085
|
}
|
|
22628
|
-
if (home && (0,
|
|
23086
|
+
if (home && (0, import_node_fs40.existsSync)(homePlansDir)) sources.push({ root: homePlansDir, prefix: "" });
|
|
22629
23087
|
const candidates2 = [];
|
|
22630
23088
|
const seen = /* @__PURE__ */ new Set();
|
|
22631
23089
|
for (const source of sources) {
|
|
22632
23090
|
let names2;
|
|
22633
23091
|
try {
|
|
22634
|
-
names2 = (0,
|
|
23092
|
+
names2 = (0, import_node_fs40.readdirSync)(source.prefix ? (0, import_node_path30.join)(source.root, source.prefix) : source.root);
|
|
22635
23093
|
} catch {
|
|
22636
23094
|
continue;
|
|
22637
23095
|
}
|
|
22638
23096
|
for (const f of names2) {
|
|
22639
23097
|
if (!f.endsWith(".md") || seen.has(f)) continue;
|
|
22640
23098
|
seen.add(f);
|
|
22641
|
-
const relPath = source.prefix ? (0,
|
|
23099
|
+
const relPath = source.prefix ? (0, import_node_path30.join)(source.prefix, f) : f;
|
|
22642
23100
|
const stat3 = statRegularInRoot(source.root, relPath);
|
|
22643
23101
|
if (!stat3.ok) continue;
|
|
22644
23102
|
candidates2.push({ name: f, root: source.root, relPath, mtime: stat3.mtimeMs, size: stat3.size });
|
|
@@ -22656,9 +23114,9 @@ function discoverPlans() {
|
|
|
22656
23114
|
function isRealDirectoryChain(root, parts) {
|
|
22657
23115
|
let current = root;
|
|
22658
23116
|
for (const part of parts) {
|
|
22659
|
-
current = (0,
|
|
23117
|
+
current = (0, import_node_path30.join)(current, part);
|
|
22660
23118
|
try {
|
|
22661
|
-
if (!(0,
|
|
23119
|
+
if (!(0, import_node_fs40.lstatSync)(current).isDirectory()) return false;
|
|
22662
23120
|
} catch {
|
|
22663
23121
|
return false;
|
|
22664
23122
|
}
|
|
@@ -22673,7 +23131,7 @@ function discoverGuardDocs(rangeFiles2) {
|
|
|
22673
23131
|
if (result.length >= MAX_SPEC_FILES) break;
|
|
22674
23132
|
if (!GUARD_DOC_EXT.test(path)) continue;
|
|
22675
23133
|
if (path.startsWith("/") || path.includes("..")) continue;
|
|
22676
|
-
if (!(0,
|
|
23134
|
+
if (!(0, import_node_fs40.existsSync)(path)) continue;
|
|
22677
23135
|
const opened = openRegularInRoot(process.cwd(), path);
|
|
22678
23136
|
if (!opened.ok) continue;
|
|
22679
23137
|
if (opened.size > MAX_PLAN_FILE_BYTES || totalBytes + opened.size > MAX_TOTAL_SPEC_BYTES) {
|
|
@@ -22859,8 +23317,8 @@ async function mode(run2) {
|
|
|
22859
23317
|
}
|
|
22860
23318
|
|
|
22861
23319
|
// src/lib/fold.ts
|
|
22862
|
-
var
|
|
22863
|
-
var
|
|
23320
|
+
var import_node_fs41 = require("node:fs");
|
|
23321
|
+
var import_node_path31 = require("node:path");
|
|
22864
23322
|
var KNOWN_RECORD_TYPES = /* @__PURE__ */ new Set([
|
|
22865
23323
|
"user",
|
|
22866
23324
|
"assistant",
|
|
@@ -22997,7 +23455,7 @@ function candidateRoots(repoRoot2) {
|
|
|
22997
23455
|
const norm = repoRoot2.replace(/\\/g, "/").replace(/\/+$/, "");
|
|
22998
23456
|
const out = [norm];
|
|
22999
23457
|
try {
|
|
23000
|
-
const real =
|
|
23458
|
+
const real = import_node_fs41.realpathSync.native(norm).replace(/\\/g, "/").replace(/\/+$/, "");
|
|
23001
23459
|
if (real !== norm) out.push(real);
|
|
23002
23460
|
} catch {
|
|
23003
23461
|
}
|
|
@@ -23085,31 +23543,31 @@ function fold(transcriptPath, opts = {}) {
|
|
|
23085
23543
|
}
|
|
23086
23544
|
};
|
|
23087
23545
|
try {
|
|
23088
|
-
if (!(0,
|
|
23089
|
-
ingest((0,
|
|
23546
|
+
if (!(0, import_node_fs41.existsSync)(transcriptPath)) return result;
|
|
23547
|
+
ingest((0, import_node_fs41.readFileSync)(transcriptPath, "utf8"), "agent");
|
|
23090
23548
|
result.coverage.complete = true;
|
|
23091
23549
|
} catch {
|
|
23092
23550
|
return result;
|
|
23093
23551
|
}
|
|
23094
23552
|
try {
|
|
23095
|
-
const sidecarDir = (0,
|
|
23096
|
-
(0,
|
|
23097
|
-
(0,
|
|
23553
|
+
const sidecarDir = (0, import_node_path31.join)(
|
|
23554
|
+
(0, import_node_path31.dirname)(transcriptPath),
|
|
23555
|
+
(0, import_node_path31.basename)(transcriptPath).replace(/\.jsonl$/, ""),
|
|
23098
23556
|
"subagents"
|
|
23099
23557
|
);
|
|
23100
|
-
if ((0,
|
|
23558
|
+
if ((0, import_node_fs41.existsSync)(sidecarDir)) {
|
|
23101
23559
|
const maxFiles = opts.maxSidecars ?? 200;
|
|
23102
23560
|
const maxBytes = opts.maxSidecarBytes ?? 16 * 1024 * 1024;
|
|
23103
23561
|
const found = [];
|
|
23104
23562
|
const walk2 = (d, depth) => {
|
|
23105
23563
|
if (depth > 4) return;
|
|
23106
|
-
for (const e of (0,
|
|
23107
|
-
const p = (0,
|
|
23564
|
+
for (const e of (0, import_node_fs41.readdirSync)(d, { withFileTypes: true })) {
|
|
23565
|
+
const p = (0, import_node_path31.join)(d, e.name);
|
|
23108
23566
|
if (e.isDirectory()) {
|
|
23109
23567
|
walk2(p, depth + 1);
|
|
23110
23568
|
} else if (e.name.startsWith("agent-") && e.name.endsWith(".jsonl")) {
|
|
23111
23569
|
try {
|
|
23112
|
-
const st = (0,
|
|
23570
|
+
const st = (0, import_node_fs41.statSync)(p);
|
|
23113
23571
|
found.push({ path: p, size: st.size, mtimeMs: st.mtimeMs });
|
|
23114
23572
|
} catch {
|
|
23115
23573
|
result.coverage.malformed++;
|
|
@@ -23126,7 +23584,7 @@ function fold(transcriptPath, opts = {}) {
|
|
|
23126
23584
|
continue;
|
|
23127
23585
|
}
|
|
23128
23586
|
try {
|
|
23129
|
-
ingest((0,
|
|
23587
|
+
ingest((0, import_node_fs41.readFileSync)(f.path, "utf8"), "subagent");
|
|
23130
23588
|
bytes += f.size;
|
|
23131
23589
|
result.coverage.subagentFiles++;
|
|
23132
23590
|
} catch {
|
|
@@ -23161,7 +23619,7 @@ function fold(transcriptPath, opts = {}) {
|
|
|
23161
23619
|
}
|
|
23162
23620
|
function classifyUnobserved(path) {
|
|
23163
23621
|
try {
|
|
23164
|
-
const st = (0,
|
|
23622
|
+
const st = (0, import_node_fs41.statSync)(path);
|
|
23165
23623
|
if (!st.isFile()) return "unreadable";
|
|
23166
23624
|
} catch {
|
|
23167
23625
|
return "unreadable";
|
|
@@ -23476,20 +23934,20 @@ async function evidence(run2) {
|
|
|
23476
23934
|
}
|
|
23477
23935
|
|
|
23478
23936
|
// src/lib/cache-cleanup.ts
|
|
23479
|
-
var
|
|
23480
|
-
var
|
|
23937
|
+
var import_node_fs42 = require("node:fs");
|
|
23938
|
+
var import_node_path32 = require("node:path");
|
|
23481
23939
|
var CACHE_TTL_DAYS = 7;
|
|
23482
23940
|
function pruneStaleCache() {
|
|
23483
23941
|
try {
|
|
23484
23942
|
const dir = projectPath(CACHE_DIR);
|
|
23485
23943
|
const cutoff = Date.now() - CACHE_TTL_DAYS * 24 * 3600 * 1e3;
|
|
23486
|
-
for (const entry of (0,
|
|
23944
|
+
for (const entry of (0, import_node_fs42.readdirSync)(dir)) {
|
|
23487
23945
|
if (!entry.startsWith("pending-")) continue;
|
|
23488
|
-
const path = (0,
|
|
23946
|
+
const path = (0, import_node_path32.join)(dir, entry);
|
|
23489
23947
|
try {
|
|
23490
|
-
const stat3 = (0,
|
|
23948
|
+
const stat3 = (0, import_node_fs42.statSync)(path);
|
|
23491
23949
|
if (stat3.mtimeMs < cutoff) {
|
|
23492
|
-
(0,
|
|
23950
|
+
(0, import_node_fs42.unlinkSync)(path);
|
|
23493
23951
|
logEvent("cache_entry_pruned", {
|
|
23494
23952
|
path: entry,
|
|
23495
23953
|
age_days: Math.round((Date.now() - stat3.mtimeMs) / 864e5)
|
|
@@ -23503,7 +23961,7 @@ function pruneStaleCache() {
|
|
|
23503
23961
|
}
|
|
23504
23962
|
|
|
23505
23963
|
// src/lib/context-files.ts
|
|
23506
|
-
var
|
|
23964
|
+
var import_node_fs43 = require("node:fs");
|
|
23507
23965
|
var import_node_os7 = require("node:os");
|
|
23508
23966
|
var MAX_CONTEXT_FILES = 10;
|
|
23509
23967
|
var MAX_CONTEXT_FILE_BYTES = 10240;
|
|
@@ -23561,7 +24019,7 @@ function gatherContextFiles(contextPaths, deltaFiles, opts) {
|
|
|
23561
24019
|
continue;
|
|
23562
24020
|
}
|
|
23563
24021
|
try {
|
|
23564
|
-
const content = (0,
|
|
24022
|
+
const content = (0, import_node_fs43.readFileSync)(safePath, "utf8");
|
|
23565
24023
|
const bytes = Buffer.byteLength(content);
|
|
23566
24024
|
if (bytes > MAX_CONTEXT_FILE_BYTES) {
|
|
23567
24025
|
logEvent("context_file_skipped", { path: filePath, reason: "too_large", bytes });
|
|
@@ -23653,8 +24111,8 @@ async function repoContext(run2) {
|
|
|
23653
24111
|
|
|
23654
24112
|
// src/lib/seed-runner.ts
|
|
23655
24113
|
var import_promises15 = require("node:fs/promises");
|
|
23656
|
-
var
|
|
23657
|
-
var
|
|
24114
|
+
var import_node_fs44 = require("node:fs");
|
|
24115
|
+
var import_node_path33 = require("node:path");
|
|
23658
24116
|
var import_yaml4 = __toESM(require_dist());
|
|
23659
24117
|
|
|
23660
24118
|
// src/lib/seed.ts
|
|
@@ -23870,6 +24328,73 @@ _Seeded from CLAUDE.md. Edit or archive if outdated._`,
|
|
|
23870
24328
|
}
|
|
23871
24329
|
|
|
23872
24330
|
// src/lib/seed-runner.ts
|
|
24331
|
+
var NODE_DIRS = ["decisions", "quality", "security", "intent", "gotchas", "patterns", "domain", "integrations"];
|
|
24332
|
+
function normalizeTitle(title) {
|
|
24333
|
+
return title.trim().replace(/\s+/g, " ").toLowerCase();
|
|
24334
|
+
}
|
|
24335
|
+
async function localSeedTitles(memoryDir3 = MEMORY_DIR) {
|
|
24336
|
+
const titles = /* @__PURE__ */ new Set();
|
|
24337
|
+
for (const dir of NODE_DIRS) {
|
|
24338
|
+
const full = (0, import_node_path33.join)(memoryDir3, dir);
|
|
24339
|
+
if (!(0, import_node_fs44.existsSync)(full)) continue;
|
|
24340
|
+
let files;
|
|
24341
|
+
try {
|
|
24342
|
+
files = await (0, import_promises15.readdir)(full);
|
|
24343
|
+
} catch {
|
|
24344
|
+
continue;
|
|
24345
|
+
}
|
|
24346
|
+
for (const file of files) {
|
|
24347
|
+
if (!file.endsWith(".md")) continue;
|
|
24348
|
+
let content;
|
|
24349
|
+
try {
|
|
24350
|
+
content = await (0, import_promises15.readFile)((0, import_node_path33.join)(full, file), "utf-8");
|
|
24351
|
+
} catch {
|
|
24352
|
+
continue;
|
|
24353
|
+
}
|
|
24354
|
+
if (!isSeedNodeMarkdown(content)) continue;
|
|
24355
|
+
const title = pickFrontmatterTitle(content);
|
|
24356
|
+
if (title) titles.add(normalizeTitle(title));
|
|
24357
|
+
}
|
|
24358
|
+
}
|
|
24359
|
+
return titles;
|
|
24360
|
+
}
|
|
24361
|
+
function frontmatterOf(content) {
|
|
24362
|
+
if (!content.startsWith("---")) return null;
|
|
24363
|
+
const end = content.indexOf("\n---", 3);
|
|
24364
|
+
return end === -1 ? content : content.slice(0, end);
|
|
24365
|
+
}
|
|
24366
|
+
function isSeedNodeMarkdown(content) {
|
|
24367
|
+
const frontmatter = frontmatterOf(content);
|
|
24368
|
+
return frontmatter !== null && /^created_by:\s*["']?seed["']?\s*$/m.test(frontmatter);
|
|
24369
|
+
}
|
|
24370
|
+
function pickFrontmatterTitle(content) {
|
|
24371
|
+
const frontmatter = frontmatterOf(content);
|
|
24372
|
+
const match = frontmatter?.match(/^title:[ \t]*(.*)$/m);
|
|
24373
|
+
if (!match) return null;
|
|
24374
|
+
const raw = match[1].trim();
|
|
24375
|
+
if (raw.startsWith('"')) {
|
|
24376
|
+
try {
|
|
24377
|
+
return String(JSON.parse(raw));
|
|
24378
|
+
} catch {
|
|
24379
|
+
return raw.slice(1, raw.endsWith('"') ? -1 : void 0).replace(/\\"/g, '"');
|
|
24380
|
+
}
|
|
24381
|
+
}
|
|
24382
|
+
return raw;
|
|
24383
|
+
}
|
|
24384
|
+
async function serverSeedTitles(opts) {
|
|
24385
|
+
const res = await apiRequest({
|
|
24386
|
+
method: "GET",
|
|
24387
|
+
path: "/compound/memory/nodes?created_by=seed&status=active&limit=100",
|
|
24388
|
+
serviceUrl: opts.serviceUrl,
|
|
24389
|
+
token: opts.token,
|
|
24390
|
+
verbose: opts.verbose,
|
|
24391
|
+
cmd: "memory_seed"
|
|
24392
|
+
});
|
|
24393
|
+
if (!res.ok || !Array.isArray(res.data.nodes)) return null;
|
|
24394
|
+
const titles = /* @__PURE__ */ new Set();
|
|
24395
|
+
for (const n of res.data.nodes) if (typeof n?.title === "string") titles.add(normalizeTitle(n.title));
|
|
24396
|
+
return titles;
|
|
24397
|
+
}
|
|
23873
24398
|
function renderNodeMarkdown(candidate, nodeId, createdAt) {
|
|
23874
24399
|
const fm = [
|
|
23875
24400
|
"---",
|
|
@@ -23893,19 +24418,19 @@ function renderNodeMarkdown(candidate, nodeId, createdAt) {
|
|
|
23893
24418
|
return fm;
|
|
23894
24419
|
}
|
|
23895
24420
|
async function runSeed(opts) {
|
|
23896
|
-
if (!(0,
|
|
23897
|
-
return { created: 0, failed: 0, skipped: "no_standard", candidates: [] };
|
|
24421
|
+
if (!(0, import_node_fs44.existsSync)(STANDARD_FILE)) {
|
|
24422
|
+
return { created: 0, existing: 0, failed: 0, skipped: "no_standard", candidates: [] };
|
|
23898
24423
|
}
|
|
23899
24424
|
let standardDoc;
|
|
23900
24425
|
try {
|
|
23901
24426
|
const raw = await (0, import_promises15.readFile)(STANDARD_FILE, "utf-8");
|
|
23902
24427
|
standardDoc = (0, import_yaml4.parse)(raw);
|
|
23903
24428
|
} catch {
|
|
23904
|
-
return { created: 0, failed: 0, skipped: "no_standard", candidates: [] };
|
|
24429
|
+
return { created: 0, existing: 0, failed: 0, skipped: "no_standard", candidates: [] };
|
|
23905
24430
|
}
|
|
23906
24431
|
const knowledgeSpec = standardDoc.knowledge_spec ?? {};
|
|
23907
24432
|
let readmeContent;
|
|
23908
|
-
if ((0,
|
|
24433
|
+
if ((0, import_node_fs44.existsSync)("README.md")) {
|
|
23909
24434
|
try {
|
|
23910
24435
|
readmeContent = await (0, import_promises15.readFile)("README.md", "utf-8");
|
|
23911
24436
|
} catch {
|
|
@@ -23913,7 +24438,7 @@ async function runSeed(opts) {
|
|
|
23913
24438
|
}
|
|
23914
24439
|
let claudeMdContent;
|
|
23915
24440
|
for (const p of ["CLAUDE.md", ".claude/CLAUDE.md"]) {
|
|
23916
|
-
if ((0,
|
|
24441
|
+
if ((0, import_node_fs44.existsSync)(p)) {
|
|
23917
24442
|
try {
|
|
23918
24443
|
claudeMdContent = await (0, import_promises15.readFile)(p, "utf-8");
|
|
23919
24444
|
break;
|
|
@@ -23934,19 +24459,33 @@ async function runSeed(opts) {
|
|
|
23934
24459
|
claudeMdContent
|
|
23935
24460
|
});
|
|
23936
24461
|
if (candidates2.length === 0) {
|
|
23937
|
-
return { created: 0, failed: 0, skipped: "no_candidates", candidates: [] };
|
|
24462
|
+
return { created: 0, existing: 0, failed: 0, skipped: "no_candidates", candidates: [] };
|
|
23938
24463
|
}
|
|
23939
|
-
|
|
23940
|
-
if (
|
|
23941
|
-
|
|
24464
|
+
let toPost = candidates2;
|
|
24465
|
+
if (!opts.force) {
|
|
24466
|
+
const local = await localSeedTitles();
|
|
24467
|
+
toPost = toPost.filter((c) => !local.has(normalizeTitle(c.title)));
|
|
24468
|
+
if (toPost.length === 0) {
|
|
24469
|
+
return { created: 0, existing: 0, failed: 0, skipped: "already_seeded", candidates: candidates2 };
|
|
24470
|
+
}
|
|
24471
|
+
if (!opts.dryRun) {
|
|
24472
|
+
const remote = await serverSeedTitles(opts);
|
|
24473
|
+
if (remote) {
|
|
24474
|
+
toPost = toPost.filter((c) => !remote.has(normalizeTitle(c.title)));
|
|
24475
|
+
if (toPost.length === 0) {
|
|
24476
|
+
return { created: 0, existing: 0, failed: 0, skipped: "already_seeded", candidates: candidates2 };
|
|
24477
|
+
}
|
|
24478
|
+
}
|
|
24479
|
+
}
|
|
23942
24480
|
}
|
|
23943
24481
|
if (opts.dryRun) {
|
|
23944
|
-
return { created: 0, failed: 0, skipped: null, candidates: candidates2 };
|
|
24482
|
+
return { created: 0, existing: 0, failed: 0, skipped: null, candidates: candidates2 };
|
|
23945
24483
|
}
|
|
23946
24484
|
const createdAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
23947
24485
|
let created = 0;
|
|
24486
|
+
let existing = 0;
|
|
23948
24487
|
let failed = 0;
|
|
23949
|
-
for (const c of
|
|
24488
|
+
for (const c of toPost) {
|
|
23950
24489
|
const res = await apiRequest({
|
|
23951
24490
|
method: "POST",
|
|
23952
24491
|
path: "/compound/memory/nodes",
|
|
@@ -23978,22 +24517,31 @@ async function runSeed(opts) {
|
|
|
23978
24517
|
failed++;
|
|
23979
24518
|
continue;
|
|
23980
24519
|
}
|
|
24520
|
+
const deduplicated = res.data.deduplicated === true;
|
|
24521
|
+
if (deduplicated && (0, import_node_fs44.existsSync)(targetPath)) {
|
|
24522
|
+
existing++;
|
|
24523
|
+
continue;
|
|
24524
|
+
}
|
|
24525
|
+
const content = typeof res.data.content === "string" && res.data.content.length > 0 ? res.data.content : renderNodeMarkdown(c, nodeId, createdAt);
|
|
23981
24526
|
try {
|
|
23982
|
-
await (0, import_promises15.mkdir)((0,
|
|
23983
|
-
await (0, import_promises15.writeFile)(targetPath,
|
|
23984
|
-
|
|
23985
|
-
|
|
24527
|
+
await (0, import_promises15.mkdir)((0, import_node_path33.dirname)(targetPath), { recursive: true });
|
|
24528
|
+
await (0, import_promises15.writeFile)(targetPath, content);
|
|
24529
|
+
if (deduplicated) existing++;
|
|
24530
|
+
else {
|
|
24531
|
+
created++;
|
|
24532
|
+
opts.onCreated?.(nodeId, filePathRel, c);
|
|
24533
|
+
}
|
|
23986
24534
|
} catch (err) {
|
|
23987
24535
|
opts.onFailed?.(c, `Server accepted "${c.title}" but couldn't write local file: ${err.message}`);
|
|
23988
24536
|
failed++;
|
|
23989
24537
|
}
|
|
23990
24538
|
}
|
|
23991
|
-
return { created, failed, skipped: null, candidates: candidates2 };
|
|
24539
|
+
return { created, existing, failed, skipped: null, candidates: candidates2 };
|
|
23992
24540
|
}
|
|
23993
24541
|
|
|
23994
24542
|
// src/commands/analyze/phases/08-memory-manifest.ts
|
|
23995
|
-
var
|
|
23996
|
-
var
|
|
24543
|
+
var import_node_fs45 = require("node:fs");
|
|
24544
|
+
var import_node_path34 = require("node:path");
|
|
23997
24545
|
async function memoryManifest(run2) {
|
|
23998
24546
|
const { globals } = run2;
|
|
23999
24547
|
const { serviceUrl, token } = run2;
|
|
@@ -24003,9 +24551,9 @@ async function memoryManifest(run2) {
|
|
|
24003
24551
|
let autoSeedNotice = null;
|
|
24004
24552
|
try {
|
|
24005
24553
|
await ensureMemoryDir();
|
|
24006
|
-
const seedMarker = (0,
|
|
24007
|
-
const hasStandard = (0,
|
|
24008
|
-
const alreadyTried = (0,
|
|
24554
|
+
const seedMarker = (0, import_node_path34.join)(VERITY_DIR, ".seeded");
|
|
24555
|
+
const hasStandard = (0, import_node_fs45.existsSync)(STANDARD_FILE);
|
|
24556
|
+
const alreadyTried = (0, import_node_fs45.existsSync)(seedMarker);
|
|
24009
24557
|
if (hasStandard && !alreadyTried) {
|
|
24010
24558
|
const preManifest = await buildManifest();
|
|
24011
24559
|
if (preManifest.nodes.length === 0) {
|
|
@@ -24017,16 +24565,19 @@ async function memoryManifest(run2) {
|
|
|
24017
24565
|
force: false,
|
|
24018
24566
|
dryRun: false
|
|
24019
24567
|
});
|
|
24020
|
-
if (seedResult.created > 0) {
|
|
24021
|
-
(0,
|
|
24568
|
+
if (seedResult.created > 0 || seedResult.existing > 0) {
|
|
24569
|
+
(0, import_node_fs45.writeFileSync)(seedMarker, `${(/* @__PURE__ */ new Date()).toISOString()} created=${seedResult.created} existing=${seedResult.existing}
|
|
24022
24570
|
`);
|
|
24023
|
-
|
|
24571
|
+
if (seedResult.created > 0) {
|
|
24572
|
+
autoSeedNotice = `Seeded ${seedResult.created} knowledge node(s) from your existing Standard (one-time).`;
|
|
24573
|
+
}
|
|
24024
24574
|
logEvent("auto_seed_ran", {
|
|
24025
24575
|
created: seedResult.created,
|
|
24576
|
+
existing: seedResult.existing,
|
|
24026
24577
|
failed: seedResult.failed
|
|
24027
24578
|
});
|
|
24028
24579
|
} else if (seedResult.skipped === "already_seeded") {
|
|
24029
|
-
(0,
|
|
24580
|
+
(0, import_node_fs45.writeFileSync)(seedMarker, `${(/* @__PURE__ */ new Date()).toISOString()} skipped=already_seeded
|
|
24030
24581
|
`);
|
|
24031
24582
|
} else {
|
|
24032
24583
|
logEvent("auto_seed_noop", {
|
|
@@ -24121,7 +24672,7 @@ function computeIncrement(reviewedPaths, hashOf, priorAuthored) {
|
|
|
24121
24672
|
}
|
|
24122
24673
|
|
|
24123
24674
|
// src/commands/analyze/phases/10-working-memory.ts
|
|
24124
|
-
var
|
|
24675
|
+
var import_node_path35 = require("node:path");
|
|
24125
24676
|
async function workingMemory(run2) {
|
|
24126
24677
|
const { opts } = run2;
|
|
24127
24678
|
const { allForReview, baseline, conversation, foldResult, sessionId, token, transcriptPath } = run2;
|
|
@@ -24133,7 +24684,7 @@ async function workingMemory(run2) {
|
|
|
24133
24684
|
const priorState = foldForMarks(memorySession.d);
|
|
24134
24685
|
incrementReport = computeIncrement(
|
|
24135
24686
|
allForReview,
|
|
24136
|
-
(p) => fileHash((0,
|
|
24687
|
+
(p) => fileHash((0, import_node_path35.join)(repoRoot(), p)),
|
|
24137
24688
|
priorState.authored_all.map((a) => ({
|
|
24138
24689
|
path: a.path,
|
|
24139
24690
|
hash_at_last_verdict: a.hash_at_last_verdict
|
|
@@ -24215,7 +24766,7 @@ async function workingMemory(run2) {
|
|
|
24215
24766
|
}
|
|
24216
24767
|
|
|
24217
24768
|
// src/lib/note-budget.ts
|
|
24218
|
-
var
|
|
24769
|
+
var import_node_fs46 = require("node:fs");
|
|
24219
24770
|
var ADVISORY_BUDGET = { PASS: 1, WARN: 2 };
|
|
24220
24771
|
var EPISODE_STALE_SECONDS = 30 * 60;
|
|
24221
24772
|
var FRESH = { delivered: 0, tasksCompleted: 0, ts: 0 };
|
|
@@ -24237,9 +24788,9 @@ function advisoryBudgetSpent(episode, rawDecision) {
|
|
|
24237
24788
|
}
|
|
24238
24789
|
function readAdvisoryEpisode(sessionId) {
|
|
24239
24790
|
const file = scopedFile(ADVISORY_EPISODE_FILE, sessionId);
|
|
24240
|
-
if (!(0,
|
|
24791
|
+
if (!(0, import_node_fs46.existsSync)(file)) return null;
|
|
24241
24792
|
try {
|
|
24242
|
-
const o = JSON.parse((0,
|
|
24793
|
+
const o = JSON.parse((0, import_node_fs46.readFileSync)(file, "utf-8")) ?? {};
|
|
24243
24794
|
const delivered = typeof o.delivered === "number" ? o.delivered : NaN;
|
|
24244
24795
|
if (isNaN(delivered)) return null;
|
|
24245
24796
|
return {
|
|
@@ -24253,8 +24804,8 @@ function readAdvisoryEpisode(sessionId) {
|
|
|
24253
24804
|
}
|
|
24254
24805
|
function writeAdvisoryEpisode(episode, sessionId) {
|
|
24255
24806
|
try {
|
|
24256
|
-
(0,
|
|
24257
|
-
(0,
|
|
24807
|
+
(0, import_node_fs46.mkdirSync)(VERITY_DIR, { recursive: true });
|
|
24808
|
+
(0, import_node_fs46.writeFileSync)(
|
|
24258
24809
|
scopedFile(ADVISORY_EPISODE_FILE, sessionId),
|
|
24259
24810
|
JSON.stringify({ v: 1, ...episode })
|
|
24260
24811
|
);
|
|
@@ -24323,6 +24874,11 @@ var MAX_ASSISTANT_RESPONSE_CHARS_PLAN = 32768;
|
|
|
24323
24874
|
var MAX_ASSISTANT_RESPONSE_CHARS_DEFAULT = 8e3;
|
|
24324
24875
|
async function buildRequest(run2) {
|
|
24325
24876
|
const { actionSummary, allChanged, allForReview, analysisMode, analyzable, assistantResponse, codeDelta, conversation, deletedNodePaths, editedUploads, foldConservation, foldResult, incrementReport, iteration, memory, memoryManifest: memoryManifest2, memorySession, plans, reachability, reviewable, securityFiles, sessionId, snapshotResult, specs, staticResults, stopReason, turnId } = run2;
|
|
24877
|
+
const advisoryEpisode = episodeForWire(
|
|
24878
|
+
readAdvisoryEpisode(run2.baselineSessionId),
|
|
24879
|
+
(conversation?.prompts?.length ?? 0) > 0
|
|
24880
|
+
);
|
|
24881
|
+
const noteConfirmation = peekNoteOutcome();
|
|
24326
24882
|
const excludedByReason = {};
|
|
24327
24883
|
for (const e of codeDelta.excluded ?? []) {
|
|
24328
24884
|
excludedByReason[e.reason] = (excludedByReason[e.reason] ?? 0) + 1;
|
|
@@ -24493,7 +25049,26 @@ async function buildRequest(run2) {
|
|
|
24493
25049
|
},
|
|
24494
25050
|
...memoryManifest2 && { memory_manifest: memoryManifest2 },
|
|
24495
25051
|
...deletedNodePaths.length > 0 && { deleted_node_paths: deletedNodePaths },
|
|
24496
|
-
...editedUploads.length > 0 && { memory_files_upload: editedUploads }
|
|
25052
|
+
...editedUploads.length > 0 && { memory_files_upload: editedUploads },
|
|
25053
|
+
// --- KNOWLEDGE-LOOP phase 5 -------------------------------------------
|
|
25054
|
+
//
|
|
25055
|
+
// The server decides whether to speak a memory node, and needs the episode
|
|
25056
|
+
// state to apply the SAME budget the client applies to its own advisory
|
|
25057
|
+
// content (`note-budget.ts`, ported and parity-tested). Sending it is not a
|
|
25058
|
+
// request for a note: it is what lets the budget be evaluated before the
|
|
25059
|
+
// ε-coin, which is what keeps the two holdout arms comparable.
|
|
25060
|
+
//
|
|
25061
|
+
// Absent on an old CLI, and the server answers `no_episode_state` rather
|
|
25062
|
+
// than guessing — silence is the safe direction when a forced turn cannot
|
|
25063
|
+
// be accounted for.
|
|
25064
|
+
advisory_episode: advisoryEpisode,
|
|
25065
|
+
// What the PREVIOUS run did with the note it was sent. The server decides,
|
|
25066
|
+
// but only the client knows whether the sentence actually reached the
|
|
25067
|
+
// agent, and an undelivered note must be voided rather than counted.
|
|
25068
|
+
...noteConfirmation && {
|
|
25069
|
+
knowledge_note_run_id: noteConfirmation.run_id,
|
|
25070
|
+
knowledge_note_delivered: noteConfirmation.delivered
|
|
25071
|
+
}
|
|
24497
25072
|
};
|
|
24498
25073
|
if (snapshotResult.has_snapshots && snapshotResult.diffs.length > 0) {
|
|
24499
25074
|
requestBody.snapshot_diffs = snapshotResult.diffs;
|
|
@@ -24562,14 +25137,14 @@ async function buildRequest(run2) {
|
|
|
24562
25137
|
}
|
|
24563
25138
|
|
|
24564
25139
|
// src/lib/offline.ts
|
|
24565
|
-
var
|
|
24566
|
-
var
|
|
25140
|
+
var import_node_fs47 = require("node:fs");
|
|
25141
|
+
var import_node_crypto12 = require("node:crypto");
|
|
24567
25142
|
function cacheRequest(body) {
|
|
24568
25143
|
try {
|
|
24569
|
-
(0,
|
|
24570
|
-
const suffix = (0,
|
|
25144
|
+
(0, import_node_fs47.mkdirSync)(CACHE_DIR, { recursive: true });
|
|
25145
|
+
const suffix = (0, import_node_crypto12.randomBytes)(4).toString("hex");
|
|
24571
25146
|
const filename = `pending-${Math.floor(Date.now() / 1e3)}-${suffix}.json`;
|
|
24572
|
-
(0,
|
|
25147
|
+
(0, import_node_fs47.writeFileSync)(`${CACHE_DIR}/${filename}`, JSON.stringify(redactRequest(body)));
|
|
24573
25148
|
} catch {
|
|
24574
25149
|
}
|
|
24575
25150
|
}
|
|
@@ -24688,8 +25263,8 @@ async function transmit(run2) {
|
|
|
24688
25263
|
}
|
|
24689
25264
|
|
|
24690
25265
|
// src/commands/analyze/phases/13-reconcile.ts
|
|
24691
|
-
var
|
|
24692
|
-
var
|
|
25266
|
+
var import_node_fs48 = require("node:fs");
|
|
25267
|
+
var import_node_path36 = require("node:path");
|
|
24693
25268
|
async function reconcile(run2) {
|
|
24694
25269
|
const { actionSummary, allChanged, analyzable, baseline, baselineSessionId, codeDelta, contentHash, conversation, decision, foldResult, memory, memorySession, response, reviewable, securityFiles, turnId } = run2;
|
|
24695
25270
|
const sentPaths = codeDelta.files.map((f) => f.path);
|
|
@@ -24718,7 +25293,7 @@ async function reconcile(run2) {
|
|
|
24718
25293
|
const st = foldDossier(memorySession.d);
|
|
24719
25294
|
openElsewhere = openBlockingElsewhere(st.statements, sentPaths, (file, line) => {
|
|
24720
25295
|
try {
|
|
24721
|
-
const src = (0,
|
|
25296
|
+
const src = (0, import_node_fs48.readFileSync)((0, import_node_path36.join)(repoRoot(), file), "utf8").split("\n");
|
|
24722
25297
|
const at = src[line - 1];
|
|
24723
25298
|
return at === void 0 ? null : lineSha(at);
|
|
24724
25299
|
} catch {
|
|
@@ -25171,7 +25746,14 @@ function screenRemediation(fix, findingFile) {
|
|
|
25171
25746
|
|
|
25172
25747
|
// src/commands/analyze/phases/14-render.ts
|
|
25173
25748
|
function agentContextFor(response, intentRepeat = 0, priorPendingFingerprints = []) {
|
|
25174
|
-
|
|
25749
|
+
const built = buildAgentContext(channelInputFrom(response, intentRepeat, priorPendingFingerprints));
|
|
25750
|
+
clearNoteOutcome();
|
|
25751
|
+
const note = parseKnowledgeNote(response.knowledge_note);
|
|
25752
|
+
if (note) {
|
|
25753
|
+
const runId = typeof response.run_id === "string" ? response.run_id : null;
|
|
25754
|
+
if (runId) recordNoteOutcome(runId, !!built && built.includes(note.text));
|
|
25755
|
+
}
|
|
25756
|
+
return built;
|
|
25175
25757
|
}
|
|
25176
25758
|
async function render(run2) {
|
|
25177
25759
|
const { opts, globals } = run2;
|
|
@@ -25533,7 +26115,7 @@ function registerAnalyzeCommand(program2) {
|
|
|
25533
26115
|
var tracing = () => process.env.VERITY_TRACE_PHASES === "1";
|
|
25534
26116
|
async function runAnalyze(opts, globals) {
|
|
25535
26117
|
if (!verityConfigured()) {
|
|
25536
|
-
(0,
|
|
26118
|
+
(0, import_node_fs49.writeSync)(2, '[verity] not set up in this project \u2014 run "verity init" first.\n');
|
|
25537
26119
|
process.exit(0);
|
|
25538
26120
|
}
|
|
25539
26121
|
const run2 = createRun(opts, globals);
|
|
@@ -25554,11 +26136,11 @@ async function runAnalyze(opts, globals) {
|
|
|
25554
26136
|
}
|
|
25555
26137
|
|
|
25556
26138
|
// src/commands/baseline.ts
|
|
25557
|
-
var
|
|
26139
|
+
var import_node_fs51 = require("node:fs");
|
|
25558
26140
|
|
|
25559
26141
|
// src/lib/project-skills.ts
|
|
25560
|
-
var
|
|
25561
|
-
var
|
|
26142
|
+
var import_node_fs50 = require("node:fs");
|
|
26143
|
+
var import_node_path37 = require("node:path");
|
|
25562
26144
|
var PROJECT_SKILL_NAMES = [
|
|
25563
26145
|
"verity-setup",
|
|
25564
26146
|
"verity-analyze",
|
|
@@ -25583,14 +26165,14 @@ var LEGACY_SKILL_NAMES = [
|
|
|
25583
26165
|
var ALL = [...PROJECT_SKILL_NAMES, ...LEGACY_SKILL_NAMES];
|
|
25584
26166
|
function staleProjectSkills() {
|
|
25585
26167
|
const root = projectPath(".claude/skills");
|
|
25586
|
-
if (!(0,
|
|
25587
|
-
return ALL.filter((name) => (0,
|
|
26168
|
+
if (!(0, import_node_fs50.existsSync)(root)) return [];
|
|
26169
|
+
return ALL.filter((name) => (0, import_node_fs50.existsSync)((0, import_node_path37.join)(root, name)));
|
|
25588
26170
|
}
|
|
25589
26171
|
function removeProjectSkills() {
|
|
25590
26172
|
const root = projectPath(".claude/skills");
|
|
25591
26173
|
const removed = [];
|
|
25592
26174
|
for (const name of staleProjectSkills()) {
|
|
25593
|
-
(0,
|
|
26175
|
+
(0, import_node_fs50.rmSync)((0, import_node_path37.join)(root, name), { recursive: true, force: true });
|
|
25594
26176
|
removed.push(name);
|
|
25595
26177
|
}
|
|
25596
26178
|
return removed;
|
|
@@ -25655,13 +26237,13 @@ function registerBaselineCommands(program2) {
|
|
|
25655
26237
|
let memoryMsg = null;
|
|
25656
26238
|
let memoryAgentLine = null;
|
|
25657
26239
|
const memoryNotice = projectPath(`${VERITY_DIR}/.memory-fence-notice`);
|
|
25658
|
-
if (realStart && !(0,
|
|
26240
|
+
if (realStart && !(0, import_node_fs51.existsSync)(memoryNotice)) {
|
|
25659
26241
|
const trackedGraph = memoryOptOut() ? 0 : committedMemoryFiles().length;
|
|
25660
26242
|
if (trackedGraph > 0) {
|
|
25661
26243
|
memoryMsg = `Verity: this project commits its knowledge base (${trackedGraph} files under .verity/memory/), so Verity's generated notes show up in every diff and pull request. Run \`verity memory untrack\` to keep them on disk but out of git, or \`verity memory track\` to keep committing them on purpose.`;
|
|
25662
26244
|
memoryAgentLine = `This project has ${trackedGraph} knowledge-graph files tracked in git under .verity/memory/. As of Verity 0.32.6 the graph is machine-local by default \u2014 it is rebuilt from the service, and committing it puts generated notes in every pull request. If the user wants that stopped, run \`verity memory untrack\` for them: it keeps every file on disk and stages their removal from the index, so they only need to commit \u2014 and their teammates' working copies will vanish on the next pull and re-sync from the service, which is expected. If they would rather keep committing it, \`verity memory track\` records that and nothing will offer again.`;
|
|
25663
26245
|
try {
|
|
25664
|
-
(0,
|
|
26246
|
+
(0, import_node_fs51.writeFileSync)(memoryNotice, (/* @__PURE__ */ new Date()).toISOString() + "\n");
|
|
25665
26247
|
} catch {
|
|
25666
26248
|
}
|
|
25667
26249
|
}
|
|
@@ -25732,7 +26314,7 @@ function registerBaselineCommands(program2) {
|
|
|
25732
26314
|
}
|
|
25733
26315
|
var MAX_HOOK_EVENT_BYTES = 64 * 1024;
|
|
25734
26316
|
var HOOK_SOURCES = /* @__PURE__ */ new Set(["startup", "resume", "clear", "compact"]);
|
|
25735
|
-
var
|
|
26317
|
+
var SESSION_ID_RE2 = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/;
|
|
25736
26318
|
async function readStdin() {
|
|
25737
26319
|
const chunks = [];
|
|
25738
26320
|
let size = 0;
|
|
@@ -25754,7 +26336,7 @@ function parseHookEvent(input) {
|
|
|
25754
26336
|
return { sessionId: validSessionId(id), source: hookSource(source) };
|
|
25755
26337
|
}
|
|
25756
26338
|
function validSessionId(value) {
|
|
25757
|
-
return typeof value === "string" &&
|
|
26339
|
+
return typeof value === "string" && SESSION_ID_RE2.test(value) ? value : void 0;
|
|
25758
26340
|
}
|
|
25759
26341
|
function hookSource(value) {
|
|
25760
26342
|
if (typeof value !== "string") return void 0;
|
|
@@ -25762,7 +26344,7 @@ function hookSource(value) {
|
|
|
25762
26344
|
}
|
|
25763
26345
|
|
|
25764
26346
|
// src/commands/review.ts
|
|
25765
|
-
var
|
|
26347
|
+
var import_node_fs52 = require("node:fs");
|
|
25766
26348
|
function registerReviewCommand(program2) {
|
|
25767
26349
|
program2.command("review").description("Run on-demand Verity analysis (advisory, never blocks)").requiredOption("--files <paths>", "Comma-separated file list").option("--changed <paths>", "Subset of --files that were modified").option("--intent <text>", "User intent description (max 2000 chars)").option("--specs <paths>", "Comma-separated spec file paths").option("--json", "Output raw JSON response").action(async (opts) => {
|
|
25768
26350
|
const globals = program2.opts();
|
|
@@ -25779,7 +26361,7 @@ async function runReview(opts, globals) {
|
|
|
25779
26361
|
const changedFiles = opts.changed ? opts.changed.split(",").map((f) => f.trim()).filter(Boolean) : allFiles;
|
|
25780
26362
|
const analyzable = filterAnalyzable(allFiles);
|
|
25781
26363
|
const securityFiles = filterSecurity(allFiles);
|
|
25782
|
-
const scannable = Array.from(/* @__PURE__ */ new Set([...analyzable, ...securityFiles])).filter((f) => (0,
|
|
26364
|
+
const scannable = Array.from(/* @__PURE__ */ new Set([...analyzable, ...securityFiles])).filter((f) => (0, import_node_fs52.existsSync)(f) || resolveFile(f) !== null);
|
|
25783
26365
|
const staticResults = runCodacyAnalysisIfAvailable(scannable);
|
|
25784
26366
|
const codeDelta = collectCodeDelta(allFiles);
|
|
25785
26367
|
const tokenResult = await resolveToken(globals.token);
|
|
@@ -25845,8 +26427,8 @@ async function runReview(opts, globals) {
|
|
|
25845
26427
|
}
|
|
25846
26428
|
|
|
25847
26429
|
// src/commands/guard.ts
|
|
25848
|
-
var
|
|
25849
|
-
var
|
|
26430
|
+
var import_node_fs53 = require("node:fs");
|
|
26431
|
+
var import_node_path38 = require("node:path");
|
|
25850
26432
|
|
|
25851
26433
|
// src/lib/terminal-text.ts
|
|
25852
26434
|
var CONTROL = /[\x00-\x08\x0b-\x1f\x7f-\x9f\u061c\u200e\u200f\u2028-\u202e\u2066-\u2069]/g;
|
|
@@ -26221,7 +26803,7 @@ async function buildAgentDiffs(ctx, paths, limits = { perFileChars: 24e3, totalC
|
|
|
26221
26803
|
// src/commands/guard.ts
|
|
26222
26804
|
var EXCERPT_SOURCE_MAX_BYTES = 2 * 1024 * 1024;
|
|
26223
26805
|
var GUARD_BLOCK_CAP = 2;
|
|
26224
|
-
var GUARD_ITER_FILE = (0,
|
|
26806
|
+
var GUARD_ITER_FILE = (0, import_node_path38.join)(VERITY_DIR, ".guard-iteration");
|
|
26225
26807
|
function readPreToolUseStdin() {
|
|
26226
26808
|
const empty = { command: "", cwd: null, sessionId: null };
|
|
26227
26809
|
return new Promise((resolve6) => {
|
|
@@ -26266,7 +26848,7 @@ function readPreToolUseStdin() {
|
|
|
26266
26848
|
}
|
|
26267
26849
|
function readIterMap() {
|
|
26268
26850
|
try {
|
|
26269
|
-
const raw = JSON.parse((0,
|
|
26851
|
+
const raw = JSON.parse((0, import_node_fs53.readFileSync)(GUARD_ITER_FILE, "utf-8"));
|
|
26270
26852
|
if (raw && typeof raw === "object") {
|
|
26271
26853
|
if (typeof raw.moment === "string" && typeof raw.count === "number") {
|
|
26272
26854
|
return { [raw.moment]: raw.count };
|
|
@@ -26286,10 +26868,10 @@ function readIter(moment) {
|
|
|
26286
26868
|
}
|
|
26287
26869
|
function writeIter(moment, count) {
|
|
26288
26870
|
try {
|
|
26289
|
-
(0,
|
|
26871
|
+
(0, import_node_fs53.mkdirSync)(VERITY_DIR, { recursive: true });
|
|
26290
26872
|
const map = readIterMap();
|
|
26291
26873
|
map[moment] = count;
|
|
26292
|
-
(0,
|
|
26874
|
+
(0, import_node_fs53.writeFileSync)(GUARD_ITER_FILE, JSON.stringify(map));
|
|
26293
26875
|
} catch {
|
|
26294
26876
|
}
|
|
26295
26877
|
}
|
|
@@ -26299,10 +26881,10 @@ function resetIter(moment) {
|
|
|
26299
26881
|
if (!(moment in map)) return;
|
|
26300
26882
|
delete map[moment];
|
|
26301
26883
|
if (Object.keys(map).length === 0) {
|
|
26302
|
-
if ((0,
|
|
26884
|
+
if ((0, import_node_fs53.existsSync)(GUARD_ITER_FILE)) (0, import_node_fs53.unlinkSync)(GUARD_ITER_FILE);
|
|
26303
26885
|
} else {
|
|
26304
|
-
(0,
|
|
26305
|
-
(0,
|
|
26886
|
+
(0, import_node_fs53.mkdirSync)(VERITY_DIR, { recursive: true });
|
|
26887
|
+
(0, import_node_fs53.writeFileSync)(GUARD_ITER_FILE, JSON.stringify(map));
|
|
26306
26888
|
}
|
|
26307
26889
|
} catch {
|
|
26308
26890
|
}
|
|
@@ -26372,7 +26954,7 @@ function hasBlockingFinding(response, sentFiles) {
|
|
|
26372
26954
|
function buildGuardRequest(moment, files, codeDelta, iter, sessionId, statedIntent, coverageTelemetry) {
|
|
26373
26955
|
const analyzable = filterAnalyzable(files);
|
|
26374
26956
|
const securityFiles = filterSecurity(files);
|
|
26375
|
-
const scannable = Array.from(/* @__PURE__ */ new Set([...analyzable, ...securityFiles])).map((f) => (0,
|
|
26957
|
+
const scannable = Array.from(/* @__PURE__ */ new Set([...analyzable, ...securityFiles])).map((f) => (0, import_node_fs53.existsSync)(f) ? f : resolveFile(f)).filter((f) => f !== null);
|
|
26376
26958
|
const staticResults = runCodacyAnalysisIfAvailable(scannable);
|
|
26377
26959
|
const trigger = moment === "pre-commit" ? "hook:pre-commit" : "hook:pre-push";
|
|
26378
26960
|
const requestBody = {
|
|
@@ -26881,8 +27463,8 @@ function registerIgnoreCommand(program2) {
|
|
|
26881
27463
|
}
|
|
26882
27464
|
|
|
26883
27465
|
// src/commands/waive.ts
|
|
26884
|
-
var
|
|
26885
|
-
var
|
|
27466
|
+
var import_node_crypto13 = require("node:crypto");
|
|
27467
|
+
var import_node_fs54 = require("node:fs");
|
|
26886
27468
|
function registerWaiveCommand(program2) {
|
|
26887
27469
|
program2.command("waive <pattern-id>").description("Record an accepted-risk disposition for an open finding (voids when the file changes)").option("--file <path>", "File the finding is anchored to, REPO-RELATIVE (recommended \u2014 narrows the waive)").requiredOption("--reason <text>", "The human disposition this records (reviewer finding, ADR, \u2026)").action(async (patternId, opts) => {
|
|
26888
27470
|
const globals = program2.opts();
|
|
@@ -26911,7 +27493,7 @@ function registerWaiveCommand(program2) {
|
|
|
26911
27493
|
if (opts.file) {
|
|
26912
27494
|
body.file = opts.file;
|
|
26913
27495
|
try {
|
|
26914
|
-
body.file_sha256 = (0,
|
|
27496
|
+
body.file_sha256 = (0, import_node_crypto13.createHash)("sha256").update((0, import_node_fs54.readFileSync)(opts.file)).digest("hex");
|
|
26915
27497
|
} catch {
|
|
26916
27498
|
printError(`Cannot read ${opts.file} \u2014 run from the repo root, or omit --file to waive by pattern.`);
|
|
26917
27499
|
process.exit(1);
|
|
@@ -26936,10 +27518,10 @@ function registerWaiveCommand(program2) {
|
|
|
26936
27518
|
}
|
|
26937
27519
|
|
|
26938
27520
|
// src/commands/init.ts
|
|
26939
|
-
var
|
|
27521
|
+
var import_node_fs58 = require("node:fs");
|
|
26940
27522
|
var import_promises19 = require("node:fs/promises");
|
|
26941
27523
|
var import_yaml6 = __toESM(require_dist());
|
|
26942
|
-
var
|
|
27524
|
+
var import_node_path41 = require("node:path");
|
|
26943
27525
|
var import_node_child_process17 = require("node:child_process");
|
|
26944
27526
|
|
|
26945
27527
|
// src/lib/banner.ts
|
|
@@ -27018,7 +27600,7 @@ function printPhase(n, of, title, subtitle) {
|
|
|
27018
27600
|
}
|
|
27019
27601
|
|
|
27020
27602
|
// src/commands/doctor.ts
|
|
27021
|
-
var
|
|
27603
|
+
var import_node_fs55 = require("node:fs");
|
|
27022
27604
|
|
|
27023
27605
|
// src/lib/prereqs.ts
|
|
27024
27606
|
var import_node_child_process15 = require("node:child_process");
|
|
@@ -27226,11 +27808,11 @@ async function buildReport() {
|
|
|
27226
27808
|
const hooks = wiring.status;
|
|
27227
27809
|
const provenance = cliProvenance();
|
|
27228
27810
|
const telemetry = await checkTelemetry();
|
|
27229
|
-
const hasConfig = (0,
|
|
27811
|
+
const hasConfig = (0, import_node_fs55.existsSync)(projectPath(CODACY_CONFIG_FILE));
|
|
27230
27812
|
const artifacts = {
|
|
27231
|
-
standard: (0,
|
|
27813
|
+
standard: (0, import_node_fs55.existsSync)(projectPath(STANDARD_FILE)),
|
|
27232
27814
|
analysisConfig: hasConfig,
|
|
27233
|
-
verityMd: (0,
|
|
27815
|
+
verityMd: (0, import_node_fs55.existsSync)(projectPath(VERITY_MD_FILE)),
|
|
27234
27816
|
analysisConfigIds: hasConfig ? validatePatternIds().status : "absent"
|
|
27235
27817
|
};
|
|
27236
27818
|
const next = [];
|
|
@@ -27371,8 +27953,8 @@ function registerDoctorCommand(program2) {
|
|
|
27371
27953
|
}
|
|
27372
27954
|
|
|
27373
27955
|
// src/commands/migrate.ts
|
|
27374
|
-
var
|
|
27375
|
-
var
|
|
27956
|
+
var import_node_fs56 = require("node:fs");
|
|
27957
|
+
var import_node_path39 = require("node:path");
|
|
27376
27958
|
var import_node_child_process16 = require("node:child_process");
|
|
27377
27959
|
var LEGACY_NPM_PACKAGE = "@codacy/gate-cli";
|
|
27378
27960
|
function defaultNpmRemover(pkg) {
|
|
@@ -27409,12 +27991,12 @@ async function runMigration(opts = {}) {
|
|
|
27409
27991
|
return { actions, migrated: actions.length > 0 };
|
|
27410
27992
|
}
|
|
27411
27993
|
function migrateProjectDir(root, actions) {
|
|
27412
|
-
const gateDir = (0,
|
|
27413
|
-
const verityDir = (0,
|
|
27414
|
-
if ((0,
|
|
27994
|
+
const gateDir = (0, import_node_path39.join)(root, ".gate");
|
|
27995
|
+
const verityDir = (0, import_node_path39.join)(root, ".verity");
|
|
27996
|
+
if ((0, import_node_fs56.existsSync)(gateDir) && !(0, import_node_fs56.existsSync)(verityDir)) {
|
|
27415
27997
|
return migrateProjectDirRename(root, gateDir, verityDir, actions);
|
|
27416
27998
|
}
|
|
27417
|
-
if ((0,
|
|
27999
|
+
if ((0, import_node_fs56.existsSync)(gateDir) && (0, import_node_fs56.existsSync)(verityDir)) {
|
|
27418
28000
|
return migrateProjectDirCarry(gateDir, verityDir, actions);
|
|
27419
28001
|
}
|
|
27420
28002
|
return false;
|
|
@@ -27435,13 +28017,13 @@ function migrateProjectDirRename(root, gateDir, verityDir, actions) {
|
|
|
27435
28017
|
}
|
|
27436
28018
|
}
|
|
27437
28019
|
if (moved) {
|
|
27438
|
-
if ((0,
|
|
28020
|
+
if ((0, import_node_fs56.existsSync)(gateDir)) {
|
|
27439
28021
|
const carried = carryLegacyContents(gateDir, verityDir);
|
|
27440
28022
|
if (carried > 0) {
|
|
27441
28023
|
actions.push(`Carried ${carried} untracked legacy file(s) from .gate/ into .verity/`);
|
|
27442
28024
|
}
|
|
27443
28025
|
try {
|
|
27444
|
-
(0,
|
|
28026
|
+
(0, import_node_fs56.rmSync)(gateDir, { recursive: true, force: true });
|
|
27445
28027
|
} catch {
|
|
27446
28028
|
}
|
|
27447
28029
|
}
|
|
@@ -27457,18 +28039,18 @@ function migrateProjectDirCarry(gateDir, verityDir, actions) {
|
|
|
27457
28039
|
actions.push(`Carried ${carried} legacy file(s) from .gate/ into .verity/`);
|
|
27458
28040
|
}
|
|
27459
28041
|
try {
|
|
27460
|
-
(0,
|
|
28042
|
+
(0, import_node_fs56.rmSync)(gateDir, { recursive: true, force: true });
|
|
27461
28043
|
} catch {
|
|
27462
28044
|
}
|
|
27463
28045
|
return carried > 0;
|
|
27464
28046
|
}
|
|
27465
28047
|
function migrateGlobalCredentials(home, actions) {
|
|
27466
28048
|
if (!home) return;
|
|
27467
|
-
const gateCreds = (0,
|
|
27468
|
-
const verityCreds = (0,
|
|
27469
|
-
if (!(0,
|
|
27470
|
-
if (!(0,
|
|
27471
|
-
(0,
|
|
28049
|
+
const gateCreds = (0, import_node_path39.join)(home, ".gate", "credentials");
|
|
28050
|
+
const verityCreds = (0, import_node_path39.join)(home, ".verity", "credentials");
|
|
28051
|
+
if (!(0, import_node_fs56.existsSync)(gateCreds)) return;
|
|
28052
|
+
if (!(0, import_node_fs56.existsSync)(verityCreds)) {
|
|
28053
|
+
(0, import_node_fs56.mkdirSync)((0, import_node_path39.join)(home, ".verity"), { recursive: true });
|
|
27472
28054
|
moveFile(gateCreds, verityCreds);
|
|
27473
28055
|
actions.push("Moved ~/.gate/credentials \u2192 ~/.verity/credentials");
|
|
27474
28056
|
return;
|
|
@@ -27490,8 +28072,8 @@ async function migrateLegacyHooks(root, actions) {
|
|
|
27490
28072
|
}
|
|
27491
28073
|
}
|
|
27492
28074
|
async function migrateClaudeMd(root, actions) {
|
|
27493
|
-
const claudeMd = (0,
|
|
27494
|
-
const hadLegacyBlock = (0,
|
|
28075
|
+
const claudeMd = (0, import_node_path39.join)(root, "CLAUDE.md");
|
|
28076
|
+
const hadLegacyBlock = (0, import_node_fs56.existsSync)(claudeMd) && hasLegacyMemoryBlock(readFileSyncSafe(claudeMd));
|
|
27495
28077
|
if (!hadLegacyBlock) return;
|
|
27496
28078
|
try {
|
|
27497
28079
|
await ensureClaudeMdPointer(root);
|
|
@@ -27501,9 +28083,9 @@ async function migrateClaudeMd(root, actions) {
|
|
|
27501
28083
|
}
|
|
27502
28084
|
}
|
|
27503
28085
|
function migrateStandardFile(root, actions) {
|
|
27504
|
-
const gateMd = (0,
|
|
27505
|
-
const verityMd = (0,
|
|
27506
|
-
if (!(0,
|
|
28086
|
+
const gateMd = (0, import_node_path39.join)(root, "GATE.md");
|
|
28087
|
+
const verityMd = (0, import_node_path39.join)(root, "VERITY.md");
|
|
28088
|
+
if (!(0, import_node_fs56.existsSync)(gateMd) || (0, import_node_fs56.existsSync)(verityMd)) return;
|
|
27507
28089
|
let moved = false;
|
|
27508
28090
|
if (isGitRepo(root) && isGitTracked(root, "GATE.md")) {
|
|
27509
28091
|
try {
|
|
@@ -27515,12 +28097,12 @@ function migrateStandardFile(root, actions) {
|
|
|
27515
28097
|
if (!moved) moveFile(gateMd, verityMd);
|
|
27516
28098
|
const content = readFileSyncSafe(verityMd);
|
|
27517
28099
|
const refreshed = content.split("GATE.md").join("VERITY.md");
|
|
27518
|
-
if (refreshed !== content) (0,
|
|
28100
|
+
if (refreshed !== content) (0, import_node_fs56.writeFileSync)(verityMd, refreshed);
|
|
27519
28101
|
actions.push("Renamed GATE.md \u2192 VERITY.md");
|
|
27520
28102
|
}
|
|
27521
28103
|
async function migrateTelemetryHeaders(root, actions) {
|
|
27522
|
-
const file = (0,
|
|
27523
|
-
if (!(0,
|
|
28104
|
+
const file = (0, import_node_path39.join)(root, ".claude", "settings.local.json");
|
|
28105
|
+
if (!(0, import_node_fs56.existsSync)(file)) return;
|
|
27524
28106
|
let settings;
|
|
27525
28107
|
try {
|
|
27526
28108
|
settings = JSON.parse(readFileSyncSafe(file) || "{}");
|
|
@@ -27568,14 +28150,14 @@ function mergeGlobalCredentials(gateCreds, verityCreds) {
|
|
|
27568
28150
|
}
|
|
27569
28151
|
if (toAppend.length > 0) {
|
|
27570
28152
|
const sep4 = verityContent.endsWith("\n") || verityContent === "" ? "" : "\n";
|
|
27571
|
-
(0,
|
|
28153
|
+
(0, import_node_fs56.writeFileSync)(verityCreds, verityContent + sep4 + toAppend.join("\n") + "\n");
|
|
27572
28154
|
}
|
|
27573
|
-
(0,
|
|
28155
|
+
(0, import_node_fs56.rmSync)(gateCreds, { force: true });
|
|
27574
28156
|
return toAppend.length;
|
|
27575
28157
|
}
|
|
27576
28158
|
function readFileSyncSafe(path) {
|
|
27577
28159
|
try {
|
|
27578
|
-
return (0,
|
|
28160
|
+
return (0, import_node_fs56.readFileSync)(path, "utf-8");
|
|
27579
28161
|
} catch {
|
|
27580
28162
|
return "";
|
|
27581
28163
|
}
|
|
@@ -27590,35 +28172,35 @@ function hasStagedChanges(root) {
|
|
|
27590
28172
|
}
|
|
27591
28173
|
function moveDir(from, to) {
|
|
27592
28174
|
try {
|
|
27593
|
-
(0,
|
|
28175
|
+
(0, import_node_fs56.renameSync)(from, to);
|
|
27594
28176
|
} catch (err) {
|
|
27595
28177
|
if (err.code !== "EXDEV") throw err;
|
|
27596
|
-
(0,
|
|
27597
|
-
(0,
|
|
28178
|
+
(0, import_node_fs56.cpSync)(from, to, { recursive: true });
|
|
28179
|
+
(0, import_node_fs56.rmSync)(from, { recursive: true, force: true });
|
|
27598
28180
|
}
|
|
27599
28181
|
}
|
|
27600
28182
|
function moveFile(from, to) {
|
|
27601
28183
|
try {
|
|
27602
|
-
(0,
|
|
28184
|
+
(0, import_node_fs56.renameSync)(from, to);
|
|
27603
28185
|
} catch (err) {
|
|
27604
28186
|
if (err.code !== "EXDEV") throw err;
|
|
27605
|
-
(0,
|
|
27606
|
-
(0,
|
|
28187
|
+
(0, import_node_fs56.cpSync)(from, to);
|
|
28188
|
+
(0, import_node_fs56.rmSync)(from, { force: true });
|
|
27607
28189
|
}
|
|
27608
28190
|
}
|
|
27609
28191
|
function carryLegacyContents(gateDir, verityDir) {
|
|
27610
28192
|
let copied = 0;
|
|
27611
28193
|
const walk2 = (relDir) => {
|
|
27612
|
-
const srcDir = (0,
|
|
27613
|
-
for (const entry of (0,
|
|
27614
|
-
const rel = relDir ? (0,
|
|
27615
|
-
const src = (0,
|
|
27616
|
-
const dest = (0,
|
|
27617
|
-
if ((0,
|
|
28194
|
+
const srcDir = (0, import_node_path39.join)(gateDir, relDir);
|
|
28195
|
+
for (const entry of (0, import_node_fs56.readdirSync)(srcDir)) {
|
|
28196
|
+
const rel = relDir ? (0, import_node_path39.join)(relDir, entry) : entry;
|
|
28197
|
+
const src = (0, import_node_path39.join)(gateDir, rel);
|
|
28198
|
+
const dest = (0, import_node_path39.join)(verityDir, rel);
|
|
28199
|
+
if ((0, import_node_fs56.statSync)(src).isDirectory()) {
|
|
27618
28200
|
walk2(rel);
|
|
27619
|
-
} else if (!(0,
|
|
27620
|
-
(0,
|
|
27621
|
-
(0,
|
|
28201
|
+
} else if (!(0, import_node_fs56.existsSync)(dest)) {
|
|
28202
|
+
(0, import_node_fs56.mkdirSync)((0, import_node_path39.dirname)(dest), { recursive: true });
|
|
28203
|
+
(0, import_node_fs56.cpSync)(src, dest);
|
|
27622
28204
|
copied++;
|
|
27623
28205
|
}
|
|
27624
28206
|
}
|
|
@@ -27627,22 +28209,22 @@ function carryLegacyContents(gateDir, verityDir) {
|
|
|
27627
28209
|
return copied;
|
|
27628
28210
|
}
|
|
27629
28211
|
async function needsMigration(root = repoRoot()) {
|
|
27630
|
-
const gateDir = (0,
|
|
27631
|
-
const verityDir = (0,
|
|
27632
|
-
if ((0,
|
|
27633
|
-
if ((0,
|
|
27634
|
-
if ((0,
|
|
28212
|
+
const gateDir = (0, import_node_path39.join)(root, ".gate");
|
|
28213
|
+
const verityDir = (0, import_node_path39.join)(root, ".verity");
|
|
28214
|
+
if ((0, import_node_fs56.existsSync)(gateDir) && !(0, import_node_fs56.existsSync)(verityDir)) return true;
|
|
28215
|
+
if ((0, import_node_fs56.existsSync)(gateDir) && (0, import_node_fs56.existsSync)(verityDir)) {
|
|
28216
|
+
if ((0, import_node_fs56.existsSync)((0, import_node_path39.join)(gateDir, "credentials")) && !(0, import_node_fs56.existsSync)((0, import_node_path39.join)(verityDir, "credentials"))) {
|
|
27635
28217
|
return true;
|
|
27636
28218
|
}
|
|
27637
|
-
if ((0,
|
|
28219
|
+
if ((0, import_node_fs56.existsSync)((0, import_node_path39.join)(gateDir, "memory")) && !(0, import_node_fs56.existsSync)((0, import_node_path39.join)(verityDir, "memory"))) {
|
|
27638
28220
|
return true;
|
|
27639
28221
|
}
|
|
27640
28222
|
}
|
|
27641
|
-
const claudeMd = (0,
|
|
27642
|
-
if ((0,
|
|
28223
|
+
const claudeMd = (0, import_node_path39.join)(root, "CLAUDE.md");
|
|
28224
|
+
if ((0, import_node_fs56.existsSync)(claudeMd) && hasLegacyMemoryBlock(readFileSyncSafe(claudeMd))) {
|
|
27643
28225
|
return true;
|
|
27644
28226
|
}
|
|
27645
|
-
if ((0,
|
|
28227
|
+
if ((0, import_node_fs56.existsSync)((0, import_node_path39.join)(root, "GATE.md")) && !(0, import_node_fs56.existsSync)((0, import_node_path39.join)(root, "VERITY.md"))) {
|
|
27646
28228
|
return true;
|
|
27647
28229
|
}
|
|
27648
28230
|
if (await hasLegacyHooksAt(root)) return true;
|
|
@@ -27923,9 +28505,9 @@ async function promptMultiSelect(question, choices, fallback) {
|
|
|
27923
28505
|
}
|
|
27924
28506
|
|
|
27925
28507
|
// src/lib/remote-config.ts
|
|
27926
|
-
var
|
|
28508
|
+
var import_node_fs57 = require("node:fs");
|
|
27927
28509
|
var import_promises18 = require("node:fs/promises");
|
|
27928
|
-
var
|
|
28510
|
+
var import_node_path40 = require("node:path");
|
|
27929
28511
|
var import_yaml5 = __toESM(require_dist());
|
|
27930
28512
|
var IGNORE_RIDER = "verityignore";
|
|
27931
28513
|
async function fetchRemoteSetup(opts) {
|
|
@@ -27970,7 +28552,7 @@ async function adoptRemoteSetup(found, opts) {
|
|
|
27970
28552
|
written.push(STANDARD_FILE);
|
|
27971
28553
|
if (rider !== null) {
|
|
27972
28554
|
const localIgnore = projectPath(VERITYIGNORE_FILE);
|
|
27973
|
-
if (!(0,
|
|
28555
|
+
if (!(0, import_node_fs57.existsSync)(localIgnore)) {
|
|
27974
28556
|
await writeOut(VERITYIGNORE_FILE, rider);
|
|
27975
28557
|
written.push(VERITYIGNORE_FILE);
|
|
27976
28558
|
} else {
|
|
@@ -28003,7 +28585,7 @@ async function adoptRemoteSetup(found, opts) {
|
|
|
28003
28585
|
}
|
|
28004
28586
|
async function writeOut(relative3, body) {
|
|
28005
28587
|
const target = projectPath(relative3);
|
|
28006
|
-
await (0, import_promises18.mkdir)((0,
|
|
28588
|
+
await (0, import_promises18.mkdir)((0, import_node_path40.dirname)(target), { recursive: true });
|
|
28007
28589
|
await (0, import_promises18.writeFile)(target, body);
|
|
28008
28590
|
}
|
|
28009
28591
|
function describeRemote(found) {
|
|
@@ -28120,15 +28702,15 @@ async function runOptionalAuth(resolution, opts = {}) {
|
|
|
28120
28702
|
}
|
|
28121
28703
|
function resolveDataDir2() {
|
|
28122
28704
|
const candidates2 = [
|
|
28123
|
-
(0,
|
|
28705
|
+
(0, import_node_path41.join)(__dirname, "..", "data"),
|
|
28124
28706
|
// installed: node_modules/@codacy/verity-cli/data
|
|
28125
|
-
(0,
|
|
28707
|
+
(0, import_node_path41.join)(__dirname, "..", "..", "data"),
|
|
28126
28708
|
// edge case: nested resolution
|
|
28127
|
-
(0,
|
|
28709
|
+
(0, import_node_path41.join)(process.cwd(), "cli", "data")
|
|
28128
28710
|
// local dev: running from repo root
|
|
28129
28711
|
];
|
|
28130
28712
|
for (const candidate of candidates2) {
|
|
28131
|
-
if ((0,
|
|
28713
|
+
if ((0, import_node_fs58.existsSync)((0, import_node_path41.join)(candidate, "skills"))) {
|
|
28132
28714
|
return candidate;
|
|
28133
28715
|
}
|
|
28134
28716
|
}
|
|
@@ -28144,9 +28726,9 @@ async function skillIsCurrent(src, dest) {
|
|
|
28144
28726
|
const list2 = (dir) => {
|
|
28145
28727
|
const out = [];
|
|
28146
28728
|
const walk2 = (d, prefix) => {
|
|
28147
|
-
for (const e of (0,
|
|
28729
|
+
for (const e of (0, import_node_fs58.readdirSync)(d, { withFileTypes: true })) {
|
|
28148
28730
|
const rel = prefix ? `${prefix}/${e.name}` : e.name;
|
|
28149
|
-
if (e.isDirectory()) walk2((0,
|
|
28731
|
+
if (e.isDirectory()) walk2((0, import_node_path41.join)(d, e.name), rel);
|
|
28150
28732
|
else if (e.isFile()) out.push(rel);
|
|
28151
28733
|
}
|
|
28152
28734
|
};
|
|
@@ -28157,8 +28739,8 @@ async function skillIsCurrent(src, dest) {
|
|
|
28157
28739
|
const shipped = list2(src);
|
|
28158
28740
|
if (JSON.stringify(shipped) !== JSON.stringify(list2(dest))) return false;
|
|
28159
28741
|
for (const rel of shipped) {
|
|
28160
|
-
const a = await (0, import_promises19.readFile)((0,
|
|
28161
|
-
const b = await (0, import_promises19.readFile)((0,
|
|
28742
|
+
const a = await (0, import_promises19.readFile)((0, import_node_path41.join)(src, rel), "utf-8");
|
|
28743
|
+
const b = await (0, import_promises19.readFile)((0, import_node_path41.join)(dest, rel), "utf-8");
|
|
28162
28744
|
if (a !== b) return false;
|
|
28163
28745
|
}
|
|
28164
28746
|
return true;
|
|
@@ -28339,7 +28921,7 @@ async function synthesizeLocally(opts) {
|
|
|
28339
28921
|
async function healStaleAnalysisConfig(globals) {
|
|
28340
28922
|
const configPath = projectPath(CODACY_CONFIG_FILE);
|
|
28341
28923
|
const standardPath = projectPath(STANDARD_FILE);
|
|
28342
|
-
if (!(0,
|
|
28924
|
+
if (!(0, import_node_fs58.existsSync)(configPath) || !(0, import_node_fs58.existsSync)(standardPath)) return;
|
|
28343
28925
|
const validation = validatePatternIds();
|
|
28344
28926
|
if (validation.status !== "invalid") return;
|
|
28345
28927
|
printWarn(" Your analysis config names pattern ids that no longer resolve \u2014 those tools were");
|
|
@@ -28436,17 +29018,17 @@ async function handoffToSetup(enabled, claudeInstalled) {
|
|
|
28436
29018
|
async function installSkills(force, step) {
|
|
28437
29019
|
step("Installing skills");
|
|
28438
29020
|
const dataDir = resolveDataDir2();
|
|
28439
|
-
const skillsSource = (0,
|
|
29021
|
+
const skillsSource = (0, import_node_path41.join)(dataDir, "skills");
|
|
28440
29022
|
const skillsDest = ".claude/skills";
|
|
28441
29023
|
let skillsInstalled = 0;
|
|
28442
29024
|
for (const skill of SKILLS) {
|
|
28443
|
-
const src = (0,
|
|
28444
|
-
const dest = (0,
|
|
28445
|
-
if (!(0,
|
|
29025
|
+
const src = (0, import_node_path41.join)(skillsSource, skill);
|
|
29026
|
+
const dest = (0, import_node_path41.join)(skillsDest, skill);
|
|
29027
|
+
if (!(0, import_node_fs58.existsSync)(src)) {
|
|
28446
29028
|
printWarn(` Skill data not found: ${skill}`);
|
|
28447
29029
|
continue;
|
|
28448
29030
|
}
|
|
28449
|
-
if ((0,
|
|
29031
|
+
if ((0, import_node_fs58.existsSync)(dest) && !force && await skillIsCurrent(src, dest)) {
|
|
28450
29032
|
skillsInstalled++;
|
|
28451
29033
|
continue;
|
|
28452
29034
|
}
|
|
@@ -28585,7 +29167,7 @@ function registerInitCommand(program2) {
|
|
|
28585
29167
|
const staleMarker = clearStalePluginMarker();
|
|
28586
29168
|
const pluginMode = opts.plugin === false ? false : opts.pluginMode ?? pluginActiveHere();
|
|
28587
29169
|
const projectMarkers = [".git", "package.json", "pyproject.toml", "go.mod", "Cargo.toml", "Gemfile", "pom.xml", "build.gradle"];
|
|
28588
|
-
const isProject = projectMarkers.some((m) => (0,
|
|
29170
|
+
const isProject = projectMarkers.some((m) => (0, import_node_fs58.existsSync)(m));
|
|
28589
29171
|
if (!isProject) {
|
|
28590
29172
|
printError("No project detected in the current directory.");
|
|
28591
29173
|
printInfo('Run "verity init" from your project root.');
|
|
@@ -28675,7 +29257,7 @@ function registerInitCommand(program2) {
|
|
|
28675
29257
|
printInfo(` intensity: ${intensity} \xB7 moments: ${moments.join(", ") || "none"} (no questions asked)`);
|
|
28676
29258
|
}
|
|
28677
29259
|
await scaffoldProject(step, defaultsOnly);
|
|
28678
|
-
const globalVerityDir = (0,
|
|
29260
|
+
const globalVerityDir = (0, import_node_path41.join)(process.env.HOME ?? "", ".verity");
|
|
28679
29261
|
await (0, import_promises19.mkdir)(globalVerityDir, { recursive: true });
|
|
28680
29262
|
console.log("");
|
|
28681
29263
|
step("Wiring Claude Code hooks");
|
|
@@ -28744,7 +29326,7 @@ function registerInitCommand(program2) {
|
|
|
28744
29326
|
}
|
|
28745
29327
|
step("Your project's Standard");
|
|
28746
29328
|
let haveStandard = false;
|
|
28747
|
-
if ((0,
|
|
29329
|
+
if ((0, import_node_fs58.existsSync)(projectPath(STANDARD_FILE))) {
|
|
28748
29330
|
printInfo(" This project already has .verity/standard.yaml \u2014 keeping it.");
|
|
28749
29331
|
haveStandard = true;
|
|
28750
29332
|
} else {
|
|
@@ -28774,7 +29356,7 @@ function registerInitCommand(program2) {
|
|
|
28774
29356
|
...telemetryChoice ? { telemetry: telemetryChoice } : {},
|
|
28775
29357
|
init: {
|
|
28776
29358
|
completed_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
28777
|
-
cli_version: true ? "0.33.
|
|
29359
|
+
cli_version: true ? "0.33.3-experimental.072d5cb" : "dev"
|
|
28778
29360
|
}
|
|
28779
29361
|
});
|
|
28780
29362
|
} catch (err) {
|
|
@@ -28824,8 +29406,8 @@ function registerInitCommand(program2) {
|
|
|
28824
29406
|
}
|
|
28825
29407
|
|
|
28826
29408
|
// src/commands/uninstall.ts
|
|
28827
|
-
var
|
|
28828
|
-
var
|
|
29409
|
+
var import_node_fs59 = require("node:fs");
|
|
29410
|
+
var import_node_path42 = require("node:path");
|
|
28829
29411
|
function registerUninstallCommand(program2) {
|
|
28830
29412
|
program2.command("uninstall").description("Remove Verity from this project (skills, hooks, .verity/, VERITY.md)").option("--dry-run", "Show what would be removed without doing it").option("--purge-global", "Also remove ~/.verity/ (deletes saved tokens \u2014 reconnect requires re-registration)").option("--keep-verity-md", "Keep the project root VERITY.md file").action(async (opts) => {
|
|
28831
29413
|
const dryRun = opts.dryRun ?? false;
|
|
@@ -28834,11 +29416,11 @@ function registerUninstallCommand(program2) {
|
|
|
28834
29416
|
const actions = [];
|
|
28835
29417
|
const skillsRoot = projectPath(".claude/skills");
|
|
28836
29418
|
for (const name of PROJECT_SKILL_NAMES) {
|
|
28837
|
-
const dir = (0,
|
|
28838
|
-
if ((0,
|
|
29419
|
+
const dir = (0, import_node_path42.join)(skillsRoot, name);
|
|
29420
|
+
if ((0, import_node_fs59.existsSync)(dir)) {
|
|
28839
29421
|
actions.push({
|
|
28840
29422
|
label: `Remove .claude/skills/${name}/`,
|
|
28841
|
-
apply: () => (0,
|
|
29423
|
+
apply: () => (0, import_node_fs59.rmSync)(dir, { recursive: true, force: true })
|
|
28842
29424
|
});
|
|
28843
29425
|
}
|
|
28844
29426
|
}
|
|
@@ -28852,24 +29434,24 @@ function registerUninstallCommand(program2) {
|
|
|
28852
29434
|
});
|
|
28853
29435
|
}
|
|
28854
29436
|
const verityDir = projectPath(VERITY_DIR);
|
|
28855
|
-
if ((0,
|
|
29437
|
+
if ((0, import_node_fs59.existsSync)(verityDir)) {
|
|
28856
29438
|
actions.push({
|
|
28857
29439
|
label: `Remove ${VERITY_DIR}/`,
|
|
28858
|
-
apply: () => (0,
|
|
29440
|
+
apply: () => (0, import_node_fs59.rmSync)(verityDir, { recursive: true, force: true })
|
|
28859
29441
|
});
|
|
28860
29442
|
}
|
|
28861
29443
|
if (!keepVerityMd) {
|
|
28862
29444
|
const verityMd = projectPath(VERITY_MD_FILE);
|
|
28863
|
-
if ((0,
|
|
29445
|
+
if ((0, import_node_fs59.existsSync)(verityMd)) {
|
|
28864
29446
|
actions.push({
|
|
28865
29447
|
label: `Remove ${VERITY_MD_FILE}`,
|
|
28866
|
-
apply: () => (0,
|
|
29448
|
+
apply: () => (0, import_node_fs59.rmSync)(verityMd, { force: true })
|
|
28867
29449
|
});
|
|
28868
29450
|
}
|
|
28869
29451
|
}
|
|
28870
29452
|
const cleanupEmptyDir = (path) => {
|
|
28871
|
-
if ((0,
|
|
28872
|
-
(0,
|
|
29453
|
+
if ((0, import_node_fs59.existsSync)(path) && (0, import_node_fs59.statSync)(path).isDirectory() && (0, import_node_fs59.readdirSync)(path).length === 0) {
|
|
29454
|
+
(0, import_node_fs59.rmdirSync)(path);
|
|
28873
29455
|
}
|
|
28874
29456
|
};
|
|
28875
29457
|
actions.push({
|
|
@@ -28880,11 +29462,11 @@ function registerUninstallCommand(program2) {
|
|
|
28880
29462
|
}
|
|
28881
29463
|
});
|
|
28882
29464
|
const home = process.env.HOME ?? "";
|
|
28883
|
-
const globalVerityDir = (0,
|
|
28884
|
-
if (purgeGlobal && (0,
|
|
29465
|
+
const globalVerityDir = (0, import_node_path42.join)(home, ".verity");
|
|
29466
|
+
if (purgeGlobal && (0, import_node_fs59.existsSync)(globalVerityDir)) {
|
|
28885
29467
|
actions.push({
|
|
28886
29468
|
label: `Remove ~/.verity/ (global credentials \u2014 reconnect requires re-registration)`,
|
|
28887
|
-
apply: () => (0,
|
|
29469
|
+
apply: () => (0, import_node_fs59.rmSync)(globalVerityDir, { recursive: true, force: true })
|
|
28888
29470
|
});
|
|
28889
29471
|
}
|
|
28890
29472
|
if (actions.length === 0) {
|
|
@@ -29078,8 +29660,8 @@ function registerTaskCommands(program2) {
|
|
|
29078
29660
|
}
|
|
29079
29661
|
|
|
29080
29662
|
// src/commands/reset.ts
|
|
29081
|
-
var
|
|
29082
|
-
var
|
|
29663
|
+
var import_node_fs60 = require("node:fs");
|
|
29664
|
+
var import_node_path43 = require("node:path");
|
|
29083
29665
|
function registerResetCommand(program2) {
|
|
29084
29666
|
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) => {
|
|
29085
29667
|
const globals = program2.opts();
|
|
@@ -29116,11 +29698,11 @@ function registerResetCommand(program2) {
|
|
|
29116
29698
|
}
|
|
29117
29699
|
const cacheDir = projectPath(CACHE_DIR);
|
|
29118
29700
|
let purged = 0;
|
|
29119
|
-
if ((0,
|
|
29120
|
-
for (const entry of (0,
|
|
29701
|
+
if ((0, import_node_fs60.existsSync)(cacheDir)) {
|
|
29702
|
+
for (const entry of (0, import_node_fs60.readdirSync)(cacheDir)) {
|
|
29121
29703
|
if (entry.startsWith("pending-")) {
|
|
29122
29704
|
try {
|
|
29123
|
-
(0,
|
|
29705
|
+
(0, import_node_fs60.unlinkSync)((0, import_node_path43.join)(cacheDir, entry));
|
|
29124
29706
|
purged++;
|
|
29125
29707
|
} catch {
|
|
29126
29708
|
}
|
|
@@ -29135,19 +29717,19 @@ function registerResetCommand(program2) {
|
|
|
29135
29717
|
projectPath(`${VERITY_DIR}/.last-analysis`)
|
|
29136
29718
|
];
|
|
29137
29719
|
for (const file of filesToClear) {
|
|
29138
|
-
if ((0,
|
|
29720
|
+
if ((0, import_node_fs60.existsSync)(file)) {
|
|
29139
29721
|
try {
|
|
29140
|
-
(0,
|
|
29722
|
+
(0, import_node_fs60.writeFileSync)(file, "");
|
|
29141
29723
|
} catch {
|
|
29142
29724
|
}
|
|
29143
29725
|
}
|
|
29144
29726
|
}
|
|
29145
29727
|
if (opts.all) {
|
|
29146
29728
|
const logsDir = projectPath(`${VERITY_DIR}/.logs`);
|
|
29147
|
-
if ((0,
|
|
29148
|
-
for (const entry of (0,
|
|
29729
|
+
if ((0, import_node_fs60.existsSync)(logsDir)) {
|
|
29730
|
+
for (const entry of (0, import_node_fs60.readdirSync)(logsDir)) {
|
|
29149
29731
|
try {
|
|
29150
|
-
(0,
|
|
29732
|
+
(0, import_node_fs60.unlinkSync)((0, import_node_path43.join)(logsDir, entry));
|
|
29151
29733
|
} catch {
|
|
29152
29734
|
}
|
|
29153
29735
|
}
|
|
@@ -29159,7 +29741,7 @@ function registerResetCommand(program2) {
|
|
|
29159
29741
|
}
|
|
29160
29742
|
|
|
29161
29743
|
// src/commands/reflect.ts
|
|
29162
|
-
var
|
|
29744
|
+
var import_node_fs61 = require("node:fs");
|
|
29163
29745
|
|
|
29164
29746
|
// src/lib/reflection-globs.ts
|
|
29165
29747
|
var MAX_GLOBS = 6;
|
|
@@ -29197,7 +29779,7 @@ async function writeNodeToDisk(args) {
|
|
|
29197
29779
|
{ treePaths: listTrackedFiles(), recordBaseline: false }
|
|
29198
29780
|
);
|
|
29199
29781
|
if (written === 0) return false;
|
|
29200
|
-
return (0,
|
|
29782
|
+
return (0, import_node_fs61.existsSync)(projectPath(`${VERITY_DIR}/memory/${args.filePath}`));
|
|
29201
29783
|
} catch {
|
|
29202
29784
|
return false;
|
|
29203
29785
|
}
|
|
@@ -29400,7 +29982,7 @@ function registerMemoryCommand(program2) {
|
|
|
29400
29982
|
process.exit(0);
|
|
29401
29983
|
}
|
|
29402
29984
|
if (result.skipped === "already_seeded") {
|
|
29403
|
-
printInfo("Memory graph already seeded
|
|
29985
|
+
printInfo("Memory graph already seeded \u2014 this project has seed nodes (locally or on the server). Use --force to re-materialize them.");
|
|
29404
29986
|
process.exit(0);
|
|
29405
29987
|
}
|
|
29406
29988
|
if (opts.dryRun) {
|
|
@@ -29411,10 +29993,11 @@ function registerMemoryCommand(program2) {
|
|
|
29411
29993
|
process.exit(0);
|
|
29412
29994
|
}
|
|
29413
29995
|
console.log("");
|
|
29996
|
+
const existingNote = result.existing > 0 ? ` ${result.existing} already existed on the server and were not duplicated.` : "";
|
|
29414
29997
|
if (result.failed === 0) {
|
|
29415
|
-
printInfo(`Seeded ${result.created} knowledge node(s) from the Standard into .verity/memory
|
|
29998
|
+
printInfo(`Seeded ${result.created} knowledge node(s) from the Standard into .verity/memory/.${existingNote}`);
|
|
29416
29999
|
} else {
|
|
29417
|
-
printWarn(`Seeded ${result.created} node(s); ${result.failed} failed
|
|
30000
|
+
printWarn(`Seeded ${result.created} node(s); ${result.failed} failed.${existingNote} See messages above.`);
|
|
29418
30001
|
}
|
|
29419
30002
|
process.exit(result.failed === 0 ? 0 : 1);
|
|
29420
30003
|
});
|
|
@@ -29696,8 +30279,8 @@ function registerTelemetryCommands(program2) {
|
|
|
29696
30279
|
}
|
|
29697
30280
|
|
|
29698
30281
|
// src/cli.ts
|
|
29699
|
-
program.name("verity").description("CLI for Verity quality gate service").version("0.33.
|
|
29700
|
-
installStderrLog(actionCommand.name(), process.argv.slice(2), "0.33.
|
|
30282
|
+
program.name("verity").description("CLI for Verity quality gate service").version("0.33.3-experimental.072d5cb").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) => {
|
|
30283
|
+
installStderrLog(actionCommand.name(), process.argv.slice(2), "0.33.3-experimental.072d5cb");
|
|
29701
30284
|
setUserNamedServiceUrl(program.opts().serviceUrl);
|
|
29702
30285
|
try {
|
|
29703
30286
|
await foldLegacyLocalCredential();
|