mason-context 0.17.3 → 0.17.4
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 +11 -0
- package/dist/mason-audit.js +193 -156
- package/dist/mason-audit.js.map +1 -1
- package/dist/mason-auto.js +285 -244
- package/dist/mason-auto.js.map +1 -1
- package/dist/mason-drift.js +45 -18
- package/dist/mason-drift.js.map +1 -1
- package/dist/mason-hook.js +41 -13
- package/dist/mason-hook.js.map +1 -1
- package/dist/mason-mcp.js +421 -382
- package/dist/mason-mcp.js.map +1 -1
- package/dist/mason-review.js +53 -25
- package/dist/mason-review.js.map +1 -1
- package/dist/mason.js +318 -277
- package/dist/mason.js.map +1 -1
- package/package.json +1 -1
package/dist/mason-mcp.js
CHANGED
|
@@ -31,6 +31,32 @@ var init_profile = __esm({
|
|
|
31
31
|
}
|
|
32
32
|
});
|
|
33
33
|
|
|
34
|
+
// src/utils/git-read.ts
|
|
35
|
+
import { execFile } from "child_process";
|
|
36
|
+
import { promisify } from "util";
|
|
37
|
+
function execGit(args, options) {
|
|
38
|
+
const command = args.find((arg) => !arg.startsWith("-")) ?? "other";
|
|
39
|
+
return profilePhase("git." + (commands.has(command) ? command : "other"), async () => {
|
|
40
|
+
const { input, ...processOptions } = options;
|
|
41
|
+
const operation = execute("git", args, processOptions);
|
|
42
|
+
if (input !== void 0) {
|
|
43
|
+
operation.child.stdin.on("error", () => {
|
|
44
|
+
});
|
|
45
|
+
operation.child.stdin.end(input);
|
|
46
|
+
}
|
|
47
|
+
return operation;
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
var execute, commands;
|
|
51
|
+
var init_git_read = __esm({
|
|
52
|
+
"src/utils/git-read.ts"() {
|
|
53
|
+
"use strict";
|
|
54
|
+
init_profile();
|
|
55
|
+
execute = promisify(execFile);
|
|
56
|
+
commands = /* @__PURE__ */ new Set(["rev-parse", "symbolic-ref", "for-each-ref", "ls-files", "check-ignore", "status", "log", "diff", "ls-tree", "show", "merge-base"]);
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
|
|
34
60
|
// src/audit/commands.ts
|
|
35
61
|
import path from "path";
|
|
36
62
|
function splitCommands(line) {
|
|
@@ -255,14 +281,14 @@ function extractClaims(content2) {
|
|
|
255
281
|
const ignored = computeIgnoredLines(lines);
|
|
256
282
|
const paths = /* @__PURE__ */ new Map();
|
|
257
283
|
const counts = [];
|
|
258
|
-
const
|
|
284
|
+
const commands2 = /* @__PURE__ */ new Map();
|
|
259
285
|
const addPath = (claim) => {
|
|
260
286
|
const key = [claim.relativeTo ?? "scope", claim.path].join(":");
|
|
261
287
|
if (!paths.has(key)) paths.set(key, claim);
|
|
262
288
|
};
|
|
263
289
|
const addCommand = (claim) => {
|
|
264
290
|
const key = JSON.stringify([claim.scriptName, claim.directory, claim.scopeUnknown]);
|
|
265
|
-
if (!
|
|
291
|
+
if (!commands2.has(key)) commands2.set(key, claim);
|
|
266
292
|
};
|
|
267
293
|
const parsed = markdown.parse(lines.map((line, i) => ignored[i] ? "" : line).join("\n"), {});
|
|
268
294
|
for (const token of parsed) {
|
|
@@ -364,7 +390,7 @@ function extractClaims(content2) {
|
|
|
364
390
|
return {
|
|
365
391
|
paths: [...paths.values()],
|
|
366
392
|
counts,
|
|
367
|
-
commands: [...
|
|
393
|
+
commands: [...commands2.values()]
|
|
368
394
|
};
|
|
369
395
|
}
|
|
370
396
|
var ROOT_FILE_NAMES, SHELL_FENCE_INFOS, markdown, COUNT_RE, COUNT_DENYLIST_RE, IGNORE_LINE, IGNORE_START, IGNORE_END;
|
|
@@ -414,97 +440,6 @@ var init_claims = __esm({
|
|
|
414
440
|
}
|
|
415
441
|
});
|
|
416
442
|
|
|
417
|
-
// src/audit/git.ts
|
|
418
|
-
import { execFile } from "child_process";
|
|
419
|
-
import { promisify } from "util";
|
|
420
|
-
function parseCommitLine(line) {
|
|
421
|
-
const parts = line.split(" ");
|
|
422
|
-
if (parts.length < 3 || !parts[0]) return null;
|
|
423
|
-
return { hash: parts[0], date: parts[1], subject: parts.slice(2).join(" ") };
|
|
424
|
-
}
|
|
425
|
-
async function lastCommitOf(resolvedRoot, relPath) {
|
|
426
|
-
try {
|
|
427
|
-
const { stdout } = await exec(
|
|
428
|
-
"git",
|
|
429
|
-
["log", "-1", `--format=${COMMIT_FORMAT}`, "--", `:(literal)${relPath}`],
|
|
430
|
-
{ cwd: resolvedRoot }
|
|
431
|
-
);
|
|
432
|
-
const line = stdout.trim().split("\n")[0];
|
|
433
|
-
return line ? parseCommitLine(line) : null;
|
|
434
|
-
} catch {
|
|
435
|
-
return null;
|
|
436
|
-
}
|
|
437
|
-
}
|
|
438
|
-
async function deletingCommitOf(resolvedRoot, relPath) {
|
|
439
|
-
try {
|
|
440
|
-
const { stdout } = await exec(
|
|
441
|
-
"git",
|
|
442
|
-
[
|
|
443
|
-
"log",
|
|
444
|
-
"-1",
|
|
445
|
-
"--diff-filter=D",
|
|
446
|
-
`--format=${COMMIT_FORMAT}`,
|
|
447
|
-
"--",
|
|
448
|
-
`:(literal)${relPath}`
|
|
449
|
-
],
|
|
450
|
-
{ cwd: resolvedRoot }
|
|
451
|
-
);
|
|
452
|
-
const line = stdout.trim().split("\n")[0];
|
|
453
|
-
return line ? parseCommitLine(line) : null;
|
|
454
|
-
} catch {
|
|
455
|
-
return null;
|
|
456
|
-
}
|
|
457
|
-
}
|
|
458
|
-
async function firstCommitOf(resolvedRoot, relPath) {
|
|
459
|
-
try {
|
|
460
|
-
const { stdout } = await exec(
|
|
461
|
-
"git",
|
|
462
|
-
["log", "--reverse", `--format=${COMMIT_FORMAT}`, "--", `:(literal)${relPath}`],
|
|
463
|
-
{ cwd: resolvedRoot, maxBuffer: 10 * 1024 * 1024 }
|
|
464
|
-
);
|
|
465
|
-
const line = stdout.trim().split("\n")[0];
|
|
466
|
-
return line ? parseCommitLine(line) : null;
|
|
467
|
-
} catch {
|
|
468
|
-
return null;
|
|
469
|
-
}
|
|
470
|
-
}
|
|
471
|
-
async function commitsTouchingSince(resolvedRoot, fromHash, pathspecs) {
|
|
472
|
-
if (!fromHash || fromHash === "unknown") return null;
|
|
473
|
-
try {
|
|
474
|
-
const { stdout } = await exec(
|
|
475
|
-
"git",
|
|
476
|
-
[
|
|
477
|
-
"log",
|
|
478
|
-
`${fromHash}..HEAD`,
|
|
479
|
-
`--format=%x01${COMMIT_FORMAT}`,
|
|
480
|
-
"--name-only",
|
|
481
|
-
"--",
|
|
482
|
-
...pathspecs
|
|
483
|
-
],
|
|
484
|
-
{ cwd: resolvedRoot, maxBuffer: 10 * 1024 * 1024 }
|
|
485
|
-
);
|
|
486
|
-
const commits = [];
|
|
487
|
-
for (const block of stdout.split("")) {
|
|
488
|
-
if (!block.trim()) continue;
|
|
489
|
-
const lines = block.split("\n").filter((l) => l.trim().length > 0);
|
|
490
|
-
const ref = parseCommitLine(lines[0]);
|
|
491
|
-
if (!ref) continue;
|
|
492
|
-
commits.push({ ...ref, files: lines.slice(1).map((l) => l.trim()) });
|
|
493
|
-
}
|
|
494
|
-
return { commits, total: commits.length };
|
|
495
|
-
} catch {
|
|
496
|
-
return null;
|
|
497
|
-
}
|
|
498
|
-
}
|
|
499
|
-
var exec, COMMIT_FORMAT;
|
|
500
|
-
var init_git = __esm({
|
|
501
|
-
"src/audit/git.ts"() {
|
|
502
|
-
"use strict";
|
|
503
|
-
exec = promisify(execFile);
|
|
504
|
-
COMMIT_FORMAT = "%H%x09%cI%x09%s";
|
|
505
|
-
}
|
|
506
|
-
});
|
|
507
|
-
|
|
508
443
|
// src/utils/paths.ts
|
|
509
444
|
import path2 from "path";
|
|
510
445
|
function normalizeRepoPath(value) {
|
|
@@ -539,8 +474,6 @@ var init_paths = __esm({
|
|
|
539
474
|
import fs from "fs/promises";
|
|
540
475
|
import { constants } from "fs";
|
|
541
476
|
import path3 from "path";
|
|
542
|
-
import { execFile as execFile2 } from "child_process";
|
|
543
|
-
import { promisify as promisify2 } from "util";
|
|
544
477
|
import fg from "fast-glob";
|
|
545
478
|
function isSensitiveFile(file) {
|
|
546
479
|
return file.split(/[\\/]/).some(
|
|
@@ -594,12 +527,12 @@ async function createFileAccess(rootDir) {
|
|
|
594
527
|
const ignore = [...SOURCE_IGNORE, ...config.ignore ?? []];
|
|
595
528
|
let gitFiles = null;
|
|
596
529
|
try {
|
|
597
|
-
const { stdout } = await
|
|
530
|
+
const { stdout } = await execGit(["ls-files", "-z", "--cached", "--others", "--exclude-standard"], { cwd: root, maxBuffer: 50 * 1024 * 1024 });
|
|
598
531
|
gitFiles = new Set(stdout.split("\0").filter(Boolean));
|
|
599
532
|
} catch {
|
|
600
533
|
let inGit = false;
|
|
601
534
|
try {
|
|
602
|
-
await
|
|
535
|
+
await execGit(["rev-parse", "--git-dir"], { cwd: root });
|
|
603
536
|
inGit = true;
|
|
604
537
|
} catch {
|
|
605
538
|
}
|
|
@@ -642,12 +575,12 @@ async function createFileAccess(rootDir) {
|
|
|
642
575
|
}
|
|
643
576
|
return { root, config, list, read };
|
|
644
577
|
}
|
|
645
|
-
var
|
|
578
|
+
var SOURCE_EXTENSIONS, SOURCE_GLOB, SOURCE_IGNORE, MAX_SOURCE_BYTES;
|
|
646
579
|
var init_files = __esm({
|
|
647
580
|
"src/utils/files.ts"() {
|
|
648
581
|
"use strict";
|
|
582
|
+
init_git_read();
|
|
649
583
|
init_paths();
|
|
650
|
-
exec2 = promisify2(execFile2);
|
|
651
584
|
SOURCE_EXTENSIONS = ["ts", "tsx", "js", "jsx", "mts", "cts", "mjs", "cjs", "vue", "svelte", "kt", "kts", "java", "py", "go", "rs", "swift", "rb", "cs", "cpp", "c", "h", "hpp", "dart", "php"];
|
|
652
585
|
SOURCE_GLOB = `**/*.{${SOURCE_EXTENSIONS.join(",")}}`;
|
|
653
586
|
SOURCE_IGNORE = [
|
|
@@ -677,9 +610,140 @@ var init_files = __esm({
|
|
|
677
610
|
}
|
|
678
611
|
});
|
|
679
612
|
|
|
613
|
+
// src/audit/inspection.ts
|
|
614
|
+
import { AsyncLocalStorage as AsyncLocalStorage2 } from "async_hooks";
|
|
615
|
+
import path4 from "path";
|
|
616
|
+
function withRepositoryInspection(root, run) {
|
|
617
|
+
return inspections.run({ root: path4.resolve(root), reads: /* @__PURE__ */ new Map() }, run);
|
|
618
|
+
}
|
|
619
|
+
function inspectionRead(root, key, read) {
|
|
620
|
+
const inspection = inspections.getStore();
|
|
621
|
+
if (!inspection || inspection.root !== path4.resolve(root)) return read();
|
|
622
|
+
if (!inspection.reads.has(key)) {
|
|
623
|
+
const pending = read();
|
|
624
|
+
inspection.reads.set(key, pending);
|
|
625
|
+
void pending.catch(() => {
|
|
626
|
+
if (inspection.reads.get(key) === pending) inspection.reads.delete(key);
|
|
627
|
+
});
|
|
628
|
+
}
|
|
629
|
+
return inspection.reads.get(key);
|
|
630
|
+
}
|
|
631
|
+
function inspectionGit(args, options) {
|
|
632
|
+
return inspectionRead(options.cwd, "git:" + JSON.stringify([args, options]), () => execGit(args, options));
|
|
633
|
+
}
|
|
634
|
+
async function auditGitPaths(root, kind) {
|
|
635
|
+
const shared = inspections.getStore()?.root === path4.resolve(root);
|
|
636
|
+
const specs = shared ? [...docSpecs, ...sourceSpecs] : kind === "documents" ? docSpecs : sourceSpecs;
|
|
637
|
+
const limit = kind === "documents" ? 16 * 1024 * 1024 : 32 * 1024 * 1024;
|
|
638
|
+
const { stdout } = await inspectionGit(
|
|
639
|
+
["ls-files", "-z", "--cached", "--others", "--exclude-standard", "--", ...specs],
|
|
640
|
+
{ cwd: root, maxBuffer: shared ? 48 * 1024 * 1024 : limit, timeout: 1e4 }
|
|
641
|
+
);
|
|
642
|
+
const paths = [...new Set(stdout.split("\0").filter(Boolean))].filter((file) => kind === "documents" ? /^(readme|agents|claude)\.md$/i.test(path4.posix.basename(file)) : sourceSuffixes.has(file.slice(file.lastIndexOf("."))));
|
|
643
|
+
if (Buffer.byteLength(paths.join("\0")) > limit) throw new Error("Git " + kind + " inventory exceeds its bounded read limit.");
|
|
644
|
+
return paths.sort();
|
|
645
|
+
}
|
|
646
|
+
var inspections, sourceSpecs, docSpecs, sourceSuffixes;
|
|
647
|
+
var init_inspection = __esm({
|
|
648
|
+
"src/audit/inspection.ts"() {
|
|
649
|
+
"use strict";
|
|
650
|
+
init_git_read();
|
|
651
|
+
init_files();
|
|
652
|
+
inspections = new AsyncLocalStorage2();
|
|
653
|
+
sourceSpecs = SOURCE_EXTENSIONS.map((extension) => `:(glob)**/*.${extension}`);
|
|
654
|
+
docSpecs = [":(icase,glob)**/readme.md", ":(icase,glob)**/agents.md", ":(icase,glob)**/claude.md"];
|
|
655
|
+
sourceSuffixes = new Set(SOURCE_EXTENSIONS.map((extension) => "." + extension));
|
|
656
|
+
}
|
|
657
|
+
});
|
|
658
|
+
|
|
659
|
+
// src/audit/git.ts
|
|
660
|
+
function parseCommitLine(line) {
|
|
661
|
+
const parts = line.split(" ");
|
|
662
|
+
if (parts.length < 3 || !parts[0]) return null;
|
|
663
|
+
return { hash: parts[0], date: parts[1], subject: parts.slice(2).join(" ") };
|
|
664
|
+
}
|
|
665
|
+
async function lastCommitOf(resolvedRoot, relPath) {
|
|
666
|
+
try {
|
|
667
|
+
const { stdout } = await inspectionGit(
|
|
668
|
+
["log", "-1", `--format=${COMMIT_FORMAT}`, "--", `:(literal)${relPath}`],
|
|
669
|
+
{ cwd: resolvedRoot }
|
|
670
|
+
);
|
|
671
|
+
const line = stdout.trim().split("\n")[0];
|
|
672
|
+
return line ? parseCommitLine(line) : null;
|
|
673
|
+
} catch {
|
|
674
|
+
return null;
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
async function deletingCommitOf(resolvedRoot, relPath) {
|
|
678
|
+
try {
|
|
679
|
+
const { stdout } = await inspectionGit(
|
|
680
|
+
[
|
|
681
|
+
"log",
|
|
682
|
+
"-1",
|
|
683
|
+
"--diff-filter=D",
|
|
684
|
+
`--format=${COMMIT_FORMAT}`,
|
|
685
|
+
"--",
|
|
686
|
+
`:(literal)${relPath}`
|
|
687
|
+
],
|
|
688
|
+
{ cwd: resolvedRoot }
|
|
689
|
+
);
|
|
690
|
+
const line = stdout.trim().split("\n")[0];
|
|
691
|
+
return line ? parseCommitLine(line) : null;
|
|
692
|
+
} catch {
|
|
693
|
+
return null;
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
async function firstCommitOf(resolvedRoot, relPath) {
|
|
697
|
+
try {
|
|
698
|
+
const { stdout } = await inspectionGit(
|
|
699
|
+
["log", "--reverse", `--format=${COMMIT_FORMAT}`, "--", `:(literal)${relPath}`],
|
|
700
|
+
{ cwd: resolvedRoot, maxBuffer: 10 * 1024 * 1024 }
|
|
701
|
+
);
|
|
702
|
+
const line = stdout.trim().split("\n")[0];
|
|
703
|
+
return line ? parseCommitLine(line) : null;
|
|
704
|
+
} catch {
|
|
705
|
+
return null;
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
async function commitsTouchingSince(resolvedRoot, fromHash, pathspecs) {
|
|
709
|
+
if (!fromHash || fromHash === "unknown") return null;
|
|
710
|
+
try {
|
|
711
|
+
const { stdout } = await inspectionGit(
|
|
712
|
+
[
|
|
713
|
+
"log",
|
|
714
|
+
`${fromHash}..HEAD`,
|
|
715
|
+
`--format=%x01${COMMIT_FORMAT}`,
|
|
716
|
+
"--name-only",
|
|
717
|
+
"--",
|
|
718
|
+
...pathspecs
|
|
719
|
+
],
|
|
720
|
+
{ cwd: resolvedRoot, maxBuffer: 10 * 1024 * 1024 }
|
|
721
|
+
);
|
|
722
|
+
const commits = [];
|
|
723
|
+
for (const block of stdout.split("")) {
|
|
724
|
+
if (!block.trim()) continue;
|
|
725
|
+
const lines = block.split("\n").filter((l) => l.trim().length > 0);
|
|
726
|
+
const ref = parseCommitLine(lines[0]);
|
|
727
|
+
if (!ref) continue;
|
|
728
|
+
commits.push({ ...ref, files: lines.slice(1).map((l) => l.trim()) });
|
|
729
|
+
}
|
|
730
|
+
return { commits, total: commits.length };
|
|
731
|
+
} catch {
|
|
732
|
+
return null;
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
var COMMIT_FORMAT;
|
|
736
|
+
var init_git = __esm({
|
|
737
|
+
"src/audit/git.ts"() {
|
|
738
|
+
"use strict";
|
|
739
|
+
init_inspection();
|
|
740
|
+
COMMIT_FORMAT = "%H%x09%cI%x09%s";
|
|
741
|
+
}
|
|
742
|
+
});
|
|
743
|
+
|
|
680
744
|
// src/utils/storage.ts
|
|
681
745
|
import fs2 from "fs/promises";
|
|
682
|
-
import
|
|
746
|
+
import path5 from "path";
|
|
683
747
|
import { randomUUID } from "crypto";
|
|
684
748
|
async function storePath(root, relative, createParents = false) {
|
|
685
749
|
const normalized = normalizeRepoPath(relative);
|
|
@@ -687,7 +751,7 @@ async function storePath(root, relative, createParents = false) {
|
|
|
687
751
|
let current = await fs2.realpath(root);
|
|
688
752
|
const parts = normalized.split("/");
|
|
689
753
|
for (let i = 0; i < parts.length; i++) {
|
|
690
|
-
current =
|
|
754
|
+
current = path5.join(current, parts[i]);
|
|
691
755
|
let stat;
|
|
692
756
|
try {
|
|
693
757
|
stat = await fs2.lstat(current);
|
|
@@ -725,7 +789,7 @@ async function writeStoreJson(root, relative, value) {
|
|
|
725
789
|
throw new Error(`Mason store ${relative} exceeds 10 MiB`);
|
|
726
790
|
}
|
|
727
791
|
const file = await storePath(root, relative, true);
|
|
728
|
-
const temporary =
|
|
792
|
+
const temporary = path5.join(path5.dirname(file), `.${path5.basename(file)}.${randomUUID()}.tmp`);
|
|
729
793
|
try {
|
|
730
794
|
const handle = await fs2.open(temporary, "wx", 384);
|
|
731
795
|
try {
|
|
@@ -750,9 +814,7 @@ var init_storage = __esm({
|
|
|
750
814
|
// src/audit/inputs.ts
|
|
751
815
|
import fs3 from "fs/promises";
|
|
752
816
|
import * as nativeFs from "fs";
|
|
753
|
-
import
|
|
754
|
-
import { execFile as execFile3 } from "child_process";
|
|
755
|
-
import { promisify as promisify3 } from "util";
|
|
817
|
+
import path6 from "path";
|
|
756
818
|
import fg2 from "fast-glob";
|
|
757
819
|
async function auditInputPath(root, file) {
|
|
758
820
|
if (file === ".") return fs3.realpath(root);
|
|
@@ -779,7 +841,7 @@ async function auditGlob(root, patterns, options) {
|
|
|
779
841
|
if (Array.isArray(patterns) && !patterns.length) return [];
|
|
780
842
|
const directories = /* @__PURE__ */ new Set();
|
|
781
843
|
const readdir2 = ((directory, opts, callback) => {
|
|
782
|
-
const relative =
|
|
844
|
+
const relative = path6.relative(root, directory).split(path6.sep).join("/") || ".";
|
|
783
845
|
directories.add(relative);
|
|
784
846
|
if (directories.size > MAX_INPUTS) {
|
|
785
847
|
callback(new Error(`${options.label} exceeds ${MAX_INPUTS.toLocaleString("en-US")} directories while inspecting ${relative}. Narrow this check's inputs.`));
|
|
@@ -790,7 +852,7 @@ async function auditGlob(root, patterns, options) {
|
|
|
790
852
|
}, callback);
|
|
791
853
|
});
|
|
792
854
|
const lstat2 = ((file, callback) => {
|
|
793
|
-
const relative =
|
|
855
|
+
const relative = path6.relative(root, file).split(path6.sep).join("/") || ".";
|
|
794
856
|
auditInputPath(root, relative).then(() => nativeFs.lstat(file, callback), callback);
|
|
795
857
|
});
|
|
796
858
|
const stream = fg2.stream(patterns, {
|
|
@@ -827,62 +889,48 @@ async function auditGlob(root, patterns, options) {
|
|
|
827
889
|
return matches.sort();
|
|
828
890
|
}
|
|
829
891
|
async function gitSourcePaths(root) {
|
|
830
|
-
|
|
831
|
-
"git",
|
|
832
|
-
[
|
|
833
|
-
"ls-files",
|
|
834
|
-
"-z",
|
|
835
|
-
"--cached",
|
|
836
|
-
"--others",
|
|
837
|
-
"--exclude-standard",
|
|
838
|
-
"--",
|
|
839
|
-
...SOURCE_EXTENSIONS.map((extension) => `:(glob)**/*.${extension}`)
|
|
840
|
-
],
|
|
841
|
-
{ cwd: root, maxBuffer: 32 * 1024 * 1024, timeout: 1e4 }
|
|
842
|
-
);
|
|
843
|
-
return [...new Set(stdout.split("\0").filter(Boolean))].sort();
|
|
892
|
+
return auditGitPaths(root, "sources");
|
|
844
893
|
}
|
|
845
894
|
async function gitIgnoredPaths(root, files) {
|
|
846
895
|
if (!files.length) return /* @__PURE__ */ new Set();
|
|
847
|
-
const
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
896
|
+
const ignored = /* @__PURE__ */ new Set();
|
|
897
|
+
for (let offset = 0; offset < files.length; offset += 1e3) {
|
|
898
|
+
try {
|
|
899
|
+
const { stdout } = await execGit(["check-ignore", "-z", "--stdin"], {
|
|
900
|
+
cwd: root,
|
|
901
|
+
maxBuffer: 4 * 1024 * 1024,
|
|
902
|
+
timeout: 1e4,
|
|
903
|
+
input: files.slice(offset, offset + 1e3).join("\0") + "\0"
|
|
904
|
+
});
|
|
905
|
+
for (const file of stdout.split("\0").filter(Boolean)) ignored.add(file);
|
|
906
|
+
} catch (error) {
|
|
907
|
+
if (error.code !== 1) throw error;
|
|
908
|
+
}
|
|
860
909
|
}
|
|
910
|
+
return ignored;
|
|
861
911
|
}
|
|
862
|
-
var
|
|
912
|
+
var MAX_INPUTS;
|
|
863
913
|
var init_inputs = __esm({
|
|
864
914
|
"src/audit/inputs.ts"() {
|
|
865
915
|
"use strict";
|
|
866
916
|
init_files();
|
|
867
917
|
init_storage();
|
|
868
|
-
|
|
918
|
+
init_git_read();
|
|
919
|
+
init_inspection();
|
|
869
920
|
MAX_INPUTS = 1e5;
|
|
870
921
|
}
|
|
871
922
|
});
|
|
872
923
|
|
|
873
924
|
// src/audit/docs.ts
|
|
874
925
|
import fs4 from "fs/promises";
|
|
875
|
-
import
|
|
876
|
-
import { execFile as execFile4 } from "child_process";
|
|
877
|
-
import { promisify as promisify4 } from "util";
|
|
926
|
+
import path7 from "path";
|
|
878
927
|
import fg3 from "fast-glob";
|
|
879
928
|
async function dirtyDocs(resolvedRoot, files) {
|
|
880
929
|
if (!files.length) return /* @__PURE__ */ new Set();
|
|
881
930
|
try {
|
|
882
931
|
const dirty = /* @__PURE__ */ new Set();
|
|
883
932
|
for (let offset = 0; offset < files.length; offset += 256) {
|
|
884
|
-
const { stdout } = await
|
|
885
|
-
"git",
|
|
933
|
+
const { stdout } = await execGit(
|
|
886
934
|
["status", "--porcelain=v1", "-z", "--untracked-files=all", "--", ...files.slice(offset, offset + 256).map((file) => `:(literal)${file}`)],
|
|
887
935
|
{ cwd: resolvedRoot, maxBuffer: 16 * 1024 * 1024, timeout: 1e4 }
|
|
888
936
|
);
|
|
@@ -902,25 +950,10 @@ async function dirtyDocs(resolvedRoot, files) {
|
|
|
902
950
|
async function discoverDocPaths(root) {
|
|
903
951
|
let candidates = [];
|
|
904
952
|
try {
|
|
905
|
-
|
|
906
|
-
"git",
|
|
907
|
-
[
|
|
908
|
-
"ls-files",
|
|
909
|
-
"-z",
|
|
910
|
-
"--cached",
|
|
911
|
-
"--others",
|
|
912
|
-
"--exclude-standard",
|
|
913
|
-
"--",
|
|
914
|
-
":(icase,glob)**/readme.md",
|
|
915
|
-
":(icase,glob)**/agents.md",
|
|
916
|
-
":(icase,glob)**/claude.md"
|
|
917
|
-
],
|
|
918
|
-
{ cwd: root, maxBuffer: 16 * 1024 * 1024, timeout: 1e4 }
|
|
919
|
-
);
|
|
920
|
-
candidates = stdout.split("\0").filter(Boolean);
|
|
953
|
+
candidates = await auditGitPaths(root, "documents");
|
|
921
954
|
} catch (error) {
|
|
922
955
|
try {
|
|
923
|
-
await
|
|
956
|
+
await execGit(["rev-parse", "--git-dir"], { cwd: root });
|
|
924
957
|
} catch {
|
|
925
958
|
return localDocPaths(root);
|
|
926
959
|
}
|
|
@@ -967,14 +1000,14 @@ async function localDocPaths(root) {
|
|
|
967
1000
|
throw error;
|
|
968
1001
|
}
|
|
969
1002
|
for (const entry of entries) if (/^(?:agents|claude|readme)\.md$/i.test(entry.name)) {
|
|
970
|
-
paths.push(
|
|
1003
|
+
paths.push(path7.posix.join(dir, entry.name));
|
|
971
1004
|
}
|
|
972
1005
|
}
|
|
973
1006
|
return paths;
|
|
974
1007
|
}
|
|
975
1008
|
function documentScope(file) {
|
|
976
|
-
const parent =
|
|
977
|
-
return
|
|
1009
|
+
const parent = path7.posix.dirname(file);
|
|
1010
|
+
return path7.posix.basename(parent).toLowerCase() === ".claude" ? path7.posix.dirname(parent) : parent;
|
|
978
1011
|
}
|
|
979
1012
|
async function discoverDocs(resolvedRoot) {
|
|
980
1013
|
return profilePhase("audit.documents", () => readDocs(resolvedRoot));
|
|
@@ -994,7 +1027,7 @@ async function readDocs(resolvedRoot) {
|
|
|
994
1027
|
path: candidate,
|
|
995
1028
|
content: content2,
|
|
996
1029
|
scope: documentScope(candidate),
|
|
997
|
-
kind: /^readme\.md$/i.test(
|
|
1030
|
+
kind: /^readme\.md$/i.test(path7.posix.basename(candidate)) ? "readme" : "instructions",
|
|
998
1031
|
lineCount: content2.split("\n").length,
|
|
999
1032
|
lastCommit,
|
|
1000
1033
|
dirty: dirty.has(candidate),
|
|
@@ -1004,16 +1037,17 @@ async function readDocs(resolvedRoot) {
|
|
|
1004
1037
|
}
|
|
1005
1038
|
return docs;
|
|
1006
1039
|
}
|
|
1007
|
-
var
|
|
1040
|
+
var DOC_CANDIDATES;
|
|
1008
1041
|
var init_docs = __esm({
|
|
1009
1042
|
"src/audit/docs.ts"() {
|
|
1010
1043
|
"use strict";
|
|
1044
|
+
init_git_read();
|
|
1011
1045
|
init_profile();
|
|
1012
1046
|
init_claims();
|
|
1013
1047
|
init_git();
|
|
1014
1048
|
init_inputs();
|
|
1015
1049
|
init_files();
|
|
1016
|
-
|
|
1050
|
+
init_inspection();
|
|
1017
1051
|
DOC_CANDIDATES = [
|
|
1018
1052
|
"AGENTS.md",
|
|
1019
1053
|
"CLAUDE.md",
|
|
@@ -1024,14 +1058,14 @@ var init_docs = __esm({
|
|
|
1024
1058
|
|
|
1025
1059
|
// src/audit/scope.ts
|
|
1026
1060
|
import fs5 from "fs/promises";
|
|
1027
|
-
import
|
|
1061
|
+
import path8 from "path";
|
|
1028
1062
|
function scopedPath(directory, value) {
|
|
1029
|
-
if (
|
|
1030
|
-
const resolved =
|
|
1063
|
+
if (path8.posix.isAbsolute(value) || value.includes("\\") || /[\x00-\x1f]/.test(value)) return null;
|
|
1064
|
+
const resolved = path8.posix.normalize(path8.posix.join(directory, value));
|
|
1031
1065
|
return resolved === ".." || resolved.startsWith("../") ? null : resolved;
|
|
1032
1066
|
}
|
|
1033
1067
|
function pathClaimScope(doc, claim) {
|
|
1034
|
-
const directory = claim.relativeTo === "document" ?
|
|
1068
|
+
const directory = claim.relativeTo === "document" ? path8.posix.dirname(doc) : documentScope(doc);
|
|
1035
1069
|
const local = scopedPath(directory, claim.path);
|
|
1036
1070
|
if (!local) return null;
|
|
1037
1071
|
const candidates = claim.relativeTo === "document" || directory === "." ? [local] : [...new Set([local, scopedPath(".", claim.path)].filter((p) => p !== null))];
|
|
@@ -1069,9 +1103,9 @@ var test_map_exports = {};
|
|
|
1069
1103
|
__export(test_map_exports, {
|
|
1070
1104
|
buildTestMap: () => buildTestMap
|
|
1071
1105
|
});
|
|
1072
|
-
import
|
|
1106
|
+
import path9 from "path";
|
|
1073
1107
|
async function buildTestMap(dir) {
|
|
1074
|
-
const rootDir =
|
|
1108
|
+
const rootDir = path9.resolve(dir);
|
|
1075
1109
|
const access = await createFileAccess(rootDir);
|
|
1076
1110
|
const testPatterns = [
|
|
1077
1111
|
"**/*.test.*",
|
|
@@ -1092,7 +1126,7 @@ async function buildTestMap(dir) {
|
|
|
1092
1126
|
const sourceByBaseName = /* @__PURE__ */ new Map();
|
|
1093
1127
|
for (const file of sourceFiles) {
|
|
1094
1128
|
if (testFiles.includes(file)) continue;
|
|
1095
|
-
const baseName =
|
|
1129
|
+
const baseName = path9.basename(file).replace(/\.[^.]+$/, "");
|
|
1096
1130
|
const existing = sourceByBaseName.get(baseName) ?? [];
|
|
1097
1131
|
existing.push(file);
|
|
1098
1132
|
sourceByBaseName.set(baseName, existing);
|
|
@@ -1100,7 +1134,7 @@ async function buildTestMap(dir) {
|
|
|
1100
1134
|
const paired = [];
|
|
1101
1135
|
const unmatched = [];
|
|
1102
1136
|
for (const testFile of testFiles) {
|
|
1103
|
-
const testBaseName =
|
|
1137
|
+
const testBaseName = path9.basename(testFile).replace(/\.[^.]+$/, "");
|
|
1104
1138
|
const sourceName = testBaseName.replace(/Test$|Tests$|Spec$|\.test$|\.spec$/, "").replace(/^test_|_test$/, "");
|
|
1105
1139
|
if (!sourceName) {
|
|
1106
1140
|
unmatched.push(testFile);
|
|
@@ -1108,10 +1142,10 @@ async function buildTestMap(dir) {
|
|
|
1108
1142
|
}
|
|
1109
1143
|
const candidates = sourceByBaseName.get(sourceName);
|
|
1110
1144
|
if (candidates && candidates.length > 0) {
|
|
1111
|
-
const testDir =
|
|
1145
|
+
const testDir = path9.dirname(testFile);
|
|
1112
1146
|
const bestMatch = candidates.reduce((best, candidate) => {
|
|
1113
|
-
const candidateDir =
|
|
1114
|
-
const bestDir =
|
|
1147
|
+
const candidateDir = path9.dirname(candidate);
|
|
1148
|
+
const bestDir = path9.dirname(best);
|
|
1115
1149
|
const candidateOverlap = commonSegments(testDir, candidateDir);
|
|
1116
1150
|
const bestOverlap = commonSegments(testDir, bestDir);
|
|
1117
1151
|
return candidateOverlap > bestOverlap ? candidate : best;
|
|
@@ -1145,9 +1179,7 @@ var init_test_map = __esm({
|
|
|
1145
1179
|
});
|
|
1146
1180
|
|
|
1147
1181
|
// src/snapshot/snapshot.ts
|
|
1148
|
-
import
|
|
1149
|
-
import { execFile as execFile5 } from "child_process";
|
|
1150
|
-
import { promisify as promisify5 } from "util";
|
|
1182
|
+
import path10 from "path";
|
|
1151
1183
|
import { z } from "zod";
|
|
1152
1184
|
function normalizeFeatureType(value) {
|
|
1153
1185
|
return value === "infrastructure" ? "infrastructure" : "capability";
|
|
@@ -1176,7 +1208,7 @@ async function saveSnapshot(rootDir, snapshot) {
|
|
|
1176
1208
|
}
|
|
1177
1209
|
async function getCurrentGitHash(rootDir) {
|
|
1178
1210
|
try {
|
|
1179
|
-
const { stdout } = await
|
|
1211
|
+
const { stdout } = await execGit(["rev-parse", "HEAD"], {
|
|
1180
1212
|
cwd: rootDir
|
|
1181
1213
|
});
|
|
1182
1214
|
return stdout.trim();
|
|
@@ -1188,7 +1220,7 @@ async function listSourceFiles(resolvedRoot) {
|
|
|
1188
1220
|
return (await createFileAccess(resolvedRoot)).list();
|
|
1189
1221
|
}
|
|
1190
1222
|
async function prepareSnapshotBatch(rootDir, offset, batchSize = DEFAULT_BATCH_SIZE, scopeFiles) {
|
|
1191
|
-
const resolvedRoot =
|
|
1223
|
+
const resolvedRoot = path10.resolve(rootDir);
|
|
1192
1224
|
const access = await createFileAccess(resolvedRoot);
|
|
1193
1225
|
let allFiles = await access.list();
|
|
1194
1226
|
if (scopeFiles) {
|
|
@@ -1237,16 +1269,16 @@ async function prepareSnapshotBatch(rootDir, offset, batchSize = DEFAULT_BATCH_S
|
|
|
1237
1269
|
testPairs
|
|
1238
1270
|
};
|
|
1239
1271
|
}
|
|
1240
|
-
var
|
|
1272
|
+
var repoPath, verificationFields, featureSchema, flowSchema, snapshotSchema, DEFAULT_BATCH_SIZE, SKELETON_CHARS, DEEP_SAMPLE_CHARS, DEEP_SAMPLES_PER_BATCH;
|
|
1241
1273
|
var init_snapshot = __esm({
|
|
1242
1274
|
"src/snapshot/snapshot.ts"() {
|
|
1243
1275
|
"use strict";
|
|
1276
|
+
init_git_read();
|
|
1244
1277
|
init_files();
|
|
1245
1278
|
init_files();
|
|
1246
1279
|
init_storage();
|
|
1247
1280
|
init_paths();
|
|
1248
1281
|
init_test_map();
|
|
1249
|
-
exec4 = promisify5(execFile5);
|
|
1250
1282
|
repoPath = z.string().refine((value) => normalizeRepoPath(value) !== null, "Expected a relative repository path");
|
|
1251
1283
|
verificationFields = {
|
|
1252
1284
|
refreshedHash: z.string().optional(),
|
|
@@ -1280,9 +1312,7 @@ var init_snapshot = __esm({
|
|
|
1280
1312
|
|
|
1281
1313
|
// src/drift/drift.ts
|
|
1282
1314
|
import fs6 from "fs/promises";
|
|
1283
|
-
import
|
|
1284
|
-
import { execFile as execFile6 } from "child_process";
|
|
1285
|
-
import { promisify as promisify6 } from "util";
|
|
1315
|
+
import path11 from "path";
|
|
1286
1316
|
function parseChanges(output) {
|
|
1287
1317
|
const fields = output.split("\0");
|
|
1288
1318
|
const changes = [];
|
|
@@ -1303,7 +1333,7 @@ function touchedPaths(changes) {
|
|
|
1303
1333
|
async function getChangesWithStatus(resolvedRoot, fromHash, toHash = "HEAD") {
|
|
1304
1334
|
if (!fromHash || fromHash === "unknown" || fromHash.startsWith("-") || !toHash || toHash === "unknown" || toHash.startsWith("-")) return null;
|
|
1305
1335
|
try {
|
|
1306
|
-
const { stdout } = await
|
|
1336
|
+
const { stdout } = await execGit(["diff", "--name-status", "-z", "-M", fromHash, toHash, "--"], { cwd: resolvedRoot, maxBuffer: 10 * 1024 * 1024 });
|
|
1307
1337
|
return parseChanges(stdout);
|
|
1308
1338
|
} catch {
|
|
1309
1339
|
return null;
|
|
@@ -1312,8 +1342,8 @@ async function getChangesWithStatus(resolvedRoot, fromHash, toHash = "HEAD") {
|
|
|
1312
1342
|
async function getWorkingTree(resolvedRoot) {
|
|
1313
1343
|
try {
|
|
1314
1344
|
const [diff, untracked] = await Promise.all([
|
|
1315
|
-
|
|
1316
|
-
|
|
1345
|
+
execGit(["diff", "--name-status", "-z", "-M", "HEAD", "--"], { cwd: resolvedRoot, maxBuffer: 10 * 1024 * 1024 }),
|
|
1346
|
+
execGit(["ls-files", "-z", "--others", "--exclude-standard"], { cwd: resolvedRoot, maxBuffer: 10 * 1024 * 1024 })
|
|
1317
1347
|
]);
|
|
1318
1348
|
const untrackedFiles = untracked.stdout.split("\0").filter((f) => f && !f.startsWith(".mason/"));
|
|
1319
1349
|
return { available: true, changedFiles: [.../* @__PURE__ */ new Set([...touchedPaths(parseChanges(diff.stdout)), ...untrackedFiles])].sort(), untrackedFiles };
|
|
@@ -1324,8 +1354,7 @@ async function getWorkingTree(resolvedRoot) {
|
|
|
1324
1354
|
async function countCommitsBehind(resolvedRoot, fromHash) {
|
|
1325
1355
|
if (!fromHash || fromHash === "unknown" || fromHash.startsWith("-")) return null;
|
|
1326
1356
|
try {
|
|
1327
|
-
const { stdout } = await
|
|
1328
|
-
"git",
|
|
1357
|
+
const { stdout } = await execGit(
|
|
1329
1358
|
["rev-list", "--count", `${fromHash}..HEAD`],
|
|
1330
1359
|
{ cwd: resolvedRoot }
|
|
1331
1360
|
);
|
|
@@ -1350,7 +1379,7 @@ async function findGhostFiles(resolvedRoot, mappedFiles) {
|
|
|
1350
1379
|
const ghosts = [];
|
|
1351
1380
|
for (const file of mappedFiles) {
|
|
1352
1381
|
try {
|
|
1353
|
-
await fs6.access(
|
|
1382
|
+
await fs6.access(path11.join(resolvedRoot, file));
|
|
1354
1383
|
} catch {
|
|
1355
1384
|
ghosts.push(file);
|
|
1356
1385
|
}
|
|
@@ -1358,7 +1387,7 @@ async function findGhostFiles(resolvedRoot, mappedFiles) {
|
|
|
1358
1387
|
return ghosts.sort();
|
|
1359
1388
|
}
|
|
1360
1389
|
async function computeDrift(rootDir) {
|
|
1361
|
-
const root =
|
|
1390
|
+
const root = path11.resolve(rootDir);
|
|
1362
1391
|
const snapshot = await loadSnapshot(root);
|
|
1363
1392
|
if (!snapshot) return null;
|
|
1364
1393
|
const [headHash, workingTree] = await Promise.all([getCurrentGitHash(root), getWorkingTree(root)]);
|
|
@@ -1415,7 +1444,7 @@ async function computeDrift(rootDir) {
|
|
|
1415
1444
|
const sourceFiles = new Set(await listSourceFiles(root));
|
|
1416
1445
|
let committedFiles = /* @__PURE__ */ new Set();
|
|
1417
1446
|
try {
|
|
1418
|
-
const { stdout } = await
|
|
1447
|
+
const { stdout } = await execGit(["ls-tree", "-r", "--name-only", "-z", "HEAD"], { cwd: root, maxBuffer: 50 * 1024 * 1024 });
|
|
1419
1448
|
committedFiles = new Set(stdout.split("\0").filter(Boolean));
|
|
1420
1449
|
} catch {
|
|
1421
1450
|
report.historyAvailable = false;
|
|
@@ -1435,13 +1464,13 @@ async function computeDrift(rootDir) {
|
|
|
1435
1464
|
else report.recommendation = changedMapped.size >= FULL_REBUILD_MIN_CHANGED_MAPPED_FILES && changedMapped.size / Math.max(1, mappedFiles.size) > FULL_REBUILD_FRACTION ? "full-rebuild" : "incremental";
|
|
1436
1465
|
return report;
|
|
1437
1466
|
}
|
|
1438
|
-
var
|
|
1467
|
+
var FULL_REBUILD_FRACTION, FULL_REBUILD_MIN_CHANGED_MAPPED_FILES;
|
|
1439
1468
|
var init_drift = __esm({
|
|
1440
1469
|
"src/drift/drift.ts"() {
|
|
1441
1470
|
"use strict";
|
|
1471
|
+
init_git_read();
|
|
1442
1472
|
init_snapshot();
|
|
1443
1473
|
init_paths();
|
|
1444
|
-
exec5 = promisify6(execFile6);
|
|
1445
1474
|
FULL_REBUILD_FRACTION = 0.4;
|
|
1446
1475
|
FULL_REBUILD_MIN_CHANGED_MAPPED_FILES = 10;
|
|
1447
1476
|
}
|
|
@@ -1464,7 +1493,7 @@ var init_types = __esm({
|
|
|
1464
1493
|
});
|
|
1465
1494
|
|
|
1466
1495
|
// src/audit/checks/deleted-reference.ts
|
|
1467
|
-
import
|
|
1496
|
+
import path12 from "path";
|
|
1468
1497
|
async function checkDeletedReferences(ctx) {
|
|
1469
1498
|
const result = emptyResult();
|
|
1470
1499
|
for (const doc of ctx.docs) {
|
|
@@ -1493,7 +1522,7 @@ async function checkDeletedReferences(ctx) {
|
|
|
1493
1522
|
const candidates = await Promise.all(scope.candidates.map(async (file) => ({
|
|
1494
1523
|
file,
|
|
1495
1524
|
tracked: await lastCommitOf(ctx.root, file),
|
|
1496
|
-
parent: await pathExists(ctx.root,
|
|
1525
|
+
parent: await pathExists(ctx.root, path12.posix.dirname(file))
|
|
1497
1526
|
})));
|
|
1498
1527
|
const candidate = candidates.find((c) => c.tracked || renames.has(c.file)) ?? candidates.find((c) => c.parent);
|
|
1499
1528
|
if (!candidate && claim.relativeTo !== "document") continue;
|
|
@@ -1533,7 +1562,7 @@ var init_deleted_reference = __esm({
|
|
|
1533
1562
|
// src/audit/checks/new-module.ts
|
|
1534
1563
|
import fg4 from "fast-glob";
|
|
1535
1564
|
import fs7 from "fs/promises";
|
|
1536
|
-
import
|
|
1565
|
+
import path13 from "path";
|
|
1537
1566
|
function escapeRegExp(text2) {
|
|
1538
1567
|
return text2.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
1539
1568
|
}
|
|
@@ -1571,23 +1600,36 @@ async function checkNewModules(ctx) {
|
|
|
1571
1600
|
return result;
|
|
1572
1601
|
}
|
|
1573
1602
|
function moduleDocumentation(docs) {
|
|
1574
|
-
return docs.map((doc) => doc.content + "\n" + (
|
|
1603
|
+
return docs.map((doc) => doc.content + "\n" + (path13.posix.dirname(doc.path) === "." ? "" : path13.posix.dirname(doc.path) + "/")).join("\n");
|
|
1604
|
+
}
|
|
1605
|
+
function moduleCandidates(root, combinedDocs) {
|
|
1606
|
+
return inspectionRead(root, "modules:" + combinedDocs, () => collectModuleCandidates(root, combinedDocs));
|
|
1575
1607
|
}
|
|
1576
|
-
async function
|
|
1608
|
+
async function collectModuleCandidates(root, combinedDocs) {
|
|
1577
1609
|
const [config, sourcePaths] = await Promise.all([loadProjectConfig(root), gitSourcePaths(root)]);
|
|
1578
1610
|
const ignore = [...SOURCE_IGNORE, ...config.ignore ?? []];
|
|
1579
1611
|
const sources = sourcePaths.filter((file) => !file.split("/").some((part) => part.startsWith(".")));
|
|
1580
|
-
const listSubdirs = async (
|
|
1581
|
-
const
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1612
|
+
const listSubdirs = async (parents) => {
|
|
1613
|
+
const byParent = /* @__PURE__ */ new Map();
|
|
1614
|
+
for (let offset = 0; offset < parents.length; offset += 16) {
|
|
1615
|
+
await Promise.all(parents.slice(offset, offset + 16).map(async (dir) => {
|
|
1616
|
+
const entries = await fs7.readdir(await auditInputPath(root, dir), { withFileTypes: true });
|
|
1617
|
+
const dirs = entries.filter((entry) => (entry.isDirectory() || entry.isSymbolicLink() && sources.some((file) => file.startsWith(path13.posix.join(dir, entry.name) + "/"))) && !entry.name.startsWith(".") && !DIR_DENYLIST.has(entry.name)).map((entry) => path13.posix.join(dir, entry.name));
|
|
1618
|
+
byParent.set(dir, dirs);
|
|
1619
|
+
}));
|
|
1620
|
+
}
|
|
1621
|
+
const ignored = await gitIgnoredPaths(root, [...byParent.values()].flat());
|
|
1622
|
+
const result = /* @__PURE__ */ new Map();
|
|
1623
|
+
for (const dir of parents) {
|
|
1624
|
+
const visible = new Set(byParent.get(dir).filter((candidate) => !ignored.has(candidate) || sources.some((file) => file.startsWith(candidate + "/"))));
|
|
1625
|
+
result.set(dir, (await auditGlob(root, dir === "." ? "*" : `${fg4.escapePath(dir)}/*`, {
|
|
1626
|
+
ignore,
|
|
1627
|
+
onlyDirectories: true,
|
|
1628
|
+
label: "Module directory discovery",
|
|
1629
|
+
select: (file) => visible.has(file)
|
|
1630
|
+
})).map((file) => path13.posix.basename(file)));
|
|
1631
|
+
}
|
|
1632
|
+
return result;
|
|
1591
1633
|
};
|
|
1592
1634
|
const countSourceFiles = async (dir) => {
|
|
1593
1635
|
const files = sources.filter((file) => file.startsWith(dir + "/"));
|
|
@@ -1603,14 +1645,16 @@ async function moduleCandidates(root, combinedDocs) {
|
|
|
1603
1645
|
return count4;
|
|
1604
1646
|
};
|
|
1605
1647
|
const candidates = [];
|
|
1606
|
-
|
|
1648
|
+
const topDirs = (await listSubdirs(["."])).get(".");
|
|
1649
|
+
const nested = await listSubdirs(topDirs.filter((dir) => isMentioned(combinedDocs, dir)));
|
|
1650
|
+
for (const topDir of topDirs) {
|
|
1607
1651
|
const topMentioned = isMentioned(combinedDocs, topDir);
|
|
1608
1652
|
if (!topMentioned) {
|
|
1609
1653
|
const count4 = await countSourceFiles(topDir);
|
|
1610
1654
|
if (count4 >= 1) candidates.push({ dir: topDir, sourceFileCount: count4 });
|
|
1611
1655
|
continue;
|
|
1612
1656
|
}
|
|
1613
|
-
const subdirs =
|
|
1657
|
+
const subdirs = nested.get(topDir);
|
|
1614
1658
|
const mentioned = subdirs.filter((s) => isMentioned(combinedDocs, s));
|
|
1615
1659
|
if (mentioned.length < ENUMERATION_THRESHOLD) continue;
|
|
1616
1660
|
for (const sub of subdirs) {
|
|
@@ -1627,6 +1671,7 @@ var DIR_DENYLIST, SECOND_LEVEL_MIN_SOURCE_FILES, ENUMERATION_THRESHOLD;
|
|
|
1627
1671
|
var init_new_module = __esm({
|
|
1628
1672
|
"src/audit/checks/new-module.ts"() {
|
|
1629
1673
|
"use strict";
|
|
1674
|
+
init_inspection();
|
|
1630
1675
|
init_files();
|
|
1631
1676
|
init_inputs();
|
|
1632
1677
|
init_git();
|
|
@@ -1656,7 +1701,7 @@ var init_new_module = __esm({
|
|
|
1656
1701
|
});
|
|
1657
1702
|
|
|
1658
1703
|
// src/audit/checks/stale-count.ts
|
|
1659
|
-
import
|
|
1704
|
+
import path14 from "path";
|
|
1660
1705
|
async function countGradleModules(root) {
|
|
1661
1706
|
for (const name of ["settings.gradle.kts", "settings.gradle"]) {
|
|
1662
1707
|
const content2 = await readAuditInput(root, name);
|
|
@@ -1690,7 +1735,7 @@ async function countNpmWorkspaces(root) {
|
|
|
1690
1735
|
return {
|
|
1691
1736
|
actual: matched.length,
|
|
1692
1737
|
countedFrom: "package.json workspaces",
|
|
1693
|
-
members: matched.map((m) =>
|
|
1738
|
+
members: matched.map((m) => path14.dirname(m)).sort()
|
|
1694
1739
|
};
|
|
1695
1740
|
}
|
|
1696
1741
|
}
|
|
@@ -1721,7 +1766,7 @@ async function countNpmWorkspaces(root) {
|
|
|
1721
1766
|
return {
|
|
1722
1767
|
actual: matched.length,
|
|
1723
1768
|
countedFrom: "pnpm-workspace.yaml",
|
|
1724
|
-
members: matched.map((m) =>
|
|
1769
|
+
members: matched.map((m) => path14.dirname(m)).sort()
|
|
1725
1770
|
};
|
|
1726
1771
|
}
|
|
1727
1772
|
}
|
|
@@ -1743,8 +1788,8 @@ async function countCargoCrates(root) {
|
|
|
1743
1788
|
ignore: ["**/target/**"],
|
|
1744
1789
|
label: "Cargo workspace discovery"
|
|
1745
1790
|
});
|
|
1746
|
-
for (const m of matched) members.add(
|
|
1747
|
-
} else if (await readAuditInput(root,
|
|
1791
|
+
for (const m of matched) members.add(path14.dirname(m));
|
|
1792
|
+
} else if (await readAuditInput(root, path14.posix.join(entry, "Cargo.toml")) !== null) {
|
|
1748
1793
|
members.add(entry);
|
|
1749
1794
|
}
|
|
1750
1795
|
}
|
|
@@ -1764,7 +1809,7 @@ async function resolveCountSource(root, claim) {
|
|
|
1764
1809
|
}
|
|
1765
1810
|
async function resolveDocCountSource(root, doc, claim) {
|
|
1766
1811
|
const scope = documentScope(doc);
|
|
1767
|
-
const source = await resolveCountSource(
|
|
1812
|
+
const source = await resolveCountSource(path14.join(root, scope), claim);
|
|
1768
1813
|
if (!source || scope === ".") return source;
|
|
1769
1814
|
return {
|
|
1770
1815
|
...source,
|
|
@@ -1816,7 +1861,7 @@ var init_stale_count = __esm({
|
|
|
1816
1861
|
});
|
|
1817
1862
|
|
|
1818
1863
|
// src/audit/checks/dead-command.ts
|
|
1819
|
-
import
|
|
1864
|
+
import path15 from "path";
|
|
1820
1865
|
function scriptsOf(raw) {
|
|
1821
1866
|
try {
|
|
1822
1867
|
const pkg = JSON.parse(raw);
|
|
@@ -1852,7 +1897,7 @@ async function commandInputs(root, docs) {
|
|
|
1852
1897
|
}
|
|
1853
1898
|
let cursor = directory;
|
|
1854
1899
|
while (true) {
|
|
1855
|
-
const manifest =
|
|
1900
|
+
const manifest = path15.posix.join(cursor, "package.json");
|
|
1856
1901
|
scope.candidates.push(manifest);
|
|
1857
1902
|
const raw = await read(manifest);
|
|
1858
1903
|
if (raw !== null) {
|
|
@@ -1863,7 +1908,7 @@ async function commandInputs(root, docs) {
|
|
|
1863
1908
|
break;
|
|
1864
1909
|
}
|
|
1865
1910
|
if (claim.directory !== void 0 || cursor === ".") break;
|
|
1866
|
-
cursor =
|
|
1911
|
+
cursor = path15.posix.dirname(cursor);
|
|
1867
1912
|
}
|
|
1868
1913
|
if (!resolution.manifest && !resolution.problem) {
|
|
1869
1914
|
resolution.problem = `No package.json for the command's scope (${directory}).`;
|
|
@@ -1926,10 +1971,8 @@ var init_dead_command = __esm({
|
|
|
1926
1971
|
});
|
|
1927
1972
|
|
|
1928
1973
|
// src/audit/release-metadata.ts
|
|
1929
|
-
import { execFile as execFile7 } from "child_process";
|
|
1930
|
-
import { promisify as promisify7 } from "util";
|
|
1931
1974
|
async function git(root, args) {
|
|
1932
|
-
return (await
|
|
1975
|
+
return (await execGit(args, { cwd: root, timeout: 1e4, maxBuffer: 2 * 1024 * 1024 })).stdout;
|
|
1933
1976
|
}
|
|
1934
1977
|
function withoutAndroidReleaseValues(text2) {
|
|
1935
1978
|
if (/\/\*|"""|'''/.test(text2) || !/id\s*\(?\s*["']com\.android\.(application|library)["']/.test(text2)) return null;
|
|
@@ -1975,11 +2018,10 @@ async function releaseMetadataOnly(root, commit) {
|
|
|
1975
2018
|
return false;
|
|
1976
2019
|
}
|
|
1977
2020
|
}
|
|
1978
|
-
var exec6;
|
|
1979
2021
|
var init_release_metadata = __esm({
|
|
1980
2022
|
"src/audit/release-metadata.ts"() {
|
|
1981
2023
|
"use strict";
|
|
1982
|
-
|
|
2024
|
+
init_git_read();
|
|
1983
2025
|
}
|
|
1984
2026
|
});
|
|
1985
2027
|
|
|
@@ -2075,7 +2117,7 @@ var init_deps_changed = __esm({
|
|
|
2075
2117
|
});
|
|
2076
2118
|
|
|
2077
2119
|
// src/context/lexical.ts
|
|
2078
|
-
import
|
|
2120
|
+
import path16 from "path";
|
|
2079
2121
|
function tokenize(text2) {
|
|
2080
2122
|
return text2.replace(/([a-z0-9])([A-Z])/g, "$1 $2").toLowerCase().split(/[^a-z0-9]+/).filter((t) => t.length > 2 && !STOPWORDS.has(t));
|
|
2081
2123
|
}
|
|
@@ -2088,7 +2130,7 @@ function tokenSet(text2) {
|
|
|
2088
2130
|
function scoreEntry(taskTokens, entry) {
|
|
2089
2131
|
const nameTokens = tokenSet(entry.name);
|
|
2090
2132
|
const descTokens = tokenSet(entry.description);
|
|
2091
|
-
const fileTokens = tokenSet(entry.files.map((f) =>
|
|
2133
|
+
const fileTokens = tokenSet(entry.files.map((f) => path16.basename(f)).join(" "));
|
|
2092
2134
|
let score = 0;
|
|
2093
2135
|
for (const token of taskTokens) {
|
|
2094
2136
|
if (nameTokens.has(token)) score += 3;
|
|
@@ -2420,7 +2462,7 @@ __export(decisions_exports, {
|
|
|
2420
2462
|
withDecisionWrite: () => withDecisionWrite
|
|
2421
2463
|
});
|
|
2422
2464
|
import fs8 from "fs/promises";
|
|
2423
|
-
import
|
|
2465
|
+
import path17 from "path";
|
|
2424
2466
|
import { createHash } from "crypto";
|
|
2425
2467
|
import { z as z3 } from "zod";
|
|
2426
2468
|
async function loadDecisionStore(rootDir) {
|
|
@@ -2518,7 +2560,7 @@ async function upsertDecision(rootDir, input) {
|
|
|
2518
2560
|
if (input.files && files.length < input.files.length) warnings.push("some anchor paths were outside the repo or duplicated and were dropped");
|
|
2519
2561
|
for (const file of files) {
|
|
2520
2562
|
try {
|
|
2521
|
-
await fs8.access(
|
|
2563
|
+
await fs8.access(path17.join(rootDir, file));
|
|
2522
2564
|
} catch {
|
|
2523
2565
|
warnings.push(`anchor file does not exist on disk: ${file}`);
|
|
2524
2566
|
}
|
|
@@ -2643,9 +2685,9 @@ var init_decisions = __esm({
|
|
|
2643
2685
|
});
|
|
2644
2686
|
|
|
2645
2687
|
// src/decisions/drift.ts
|
|
2646
|
-
import
|
|
2688
|
+
import path18 from "path";
|
|
2647
2689
|
async function computeDecisionDrift(rootDir, decisions) {
|
|
2648
|
-
const resolvedRoot =
|
|
2690
|
+
const resolvedRoot = path18.resolve(rootDir);
|
|
2649
2691
|
const store = decisions ? { records: decisions, diagnostics: [] } : await loadDecisionStore(resolvedRoot);
|
|
2650
2692
|
const report = { historyAvailable: true, totalDecisions: store.records.length, staleDecisions: {}, freshness: {}, diagnostics: store.diagnostics };
|
|
2651
2693
|
const [head, workingTree] = await Promise.all([getCurrentGitHash(resolvedRoot), getWorkingTree(resolvedRoot)]);
|
|
@@ -2967,8 +3009,6 @@ var init_store = __esm({
|
|
|
2967
3009
|
|
|
2968
3010
|
// src/audit/advisory-review.ts
|
|
2969
3011
|
import fs10 from "fs/promises";
|
|
2970
|
-
import { execFile as execFile8 } from "child_process";
|
|
2971
|
-
import { promisify as promisify8 } from "util";
|
|
2972
3012
|
import { z as z6 } from "zod";
|
|
2973
3013
|
async function readRecord(root, id) {
|
|
2974
3014
|
const raw = await readStoreJson(root, recordPath(id));
|
|
@@ -3163,10 +3203,12 @@ async function reviewAdvisory(rootDir, input) {
|
|
|
3163
3203
|
};
|
|
3164
3204
|
});
|
|
3165
3205
|
}
|
|
3166
|
-
var
|
|
3206
|
+
var git2, hashSchema, commitSchema2, evidenceSchema2, eventSchema2, recordSchema, reviewSummarySchema, advisoryReviewRequest, recordPath;
|
|
3167
3207
|
var init_advisory_review = __esm({
|
|
3168
3208
|
"src/audit/advisory-review.ts"() {
|
|
3169
3209
|
"use strict";
|
|
3210
|
+
init_inspection();
|
|
3211
|
+
init_git_read();
|
|
3170
3212
|
init_findings();
|
|
3171
3213
|
init_deps_changed();
|
|
3172
3214
|
init_inputs();
|
|
@@ -3176,8 +3218,7 @@ var init_advisory_review = __esm({
|
|
|
3176
3218
|
init_store();
|
|
3177
3219
|
init_decisions();
|
|
3178
3220
|
init_drift2();
|
|
3179
|
-
|
|
3180
|
-
git2 = async (root, ...args) => (await execute2("git", args, { cwd: root, timeout: 1e4, maxBuffer: 8 * 1024 * 1024 })).stdout;
|
|
3221
|
+
git2 = async (root, ...args) => (await (["log", "ls-tree", "ls-files", "merge-base"].includes(args[0]) ? inspectionGit : execGit)(args, { cwd: root, timeout: 1e4, maxBuffer: 8 * 1024 * 1024 })).stdout;
|
|
3181
3222
|
hashSchema = z6.string().regex(/^[a-f0-9]{64}$/);
|
|
3182
3223
|
commitSchema2 = z6.string().regex(/^[a-f0-9]{40,64}$/);
|
|
3183
3224
|
evidenceSchema2 = z6.object({
|
|
@@ -3221,12 +3262,12 @@ var init_advisory_review = __esm({
|
|
|
3221
3262
|
|
|
3222
3263
|
// src/audit/audit.ts
|
|
3223
3264
|
import fs11 from "fs/promises";
|
|
3224
|
-
import
|
|
3265
|
+
import path19 from "path";
|
|
3225
3266
|
async function computeAudit(rootDir, options = {}) {
|
|
3226
3267
|
return profilePhase("audit.current", () => auditCurrent(rootDir, options));
|
|
3227
3268
|
}
|
|
3228
3269
|
async function auditCurrent(rootDir, options) {
|
|
3229
|
-
const resolvedRoot =
|
|
3270
|
+
const resolvedRoot = path19.resolve(rootDir);
|
|
3230
3271
|
const [docs, headHash] = await Promise.all([discoverDocs(resolvedRoot), getCurrentGitHash(resolvedRoot)]);
|
|
3231
3272
|
if (docs.length === 0) return null;
|
|
3232
3273
|
const report = {
|
|
@@ -3260,7 +3301,7 @@ async function auditCurrent(rootDir, options) {
|
|
|
3260
3301
|
}
|
|
3261
3302
|
let decisionsPresent = false;
|
|
3262
3303
|
try {
|
|
3263
|
-
await fs11.access(
|
|
3304
|
+
await fs11.access(path19.join(resolvedRoot, ".mason", "decisions"));
|
|
3264
3305
|
decisionsPresent = true;
|
|
3265
3306
|
} catch {
|
|
3266
3307
|
}
|
|
@@ -3315,7 +3356,7 @@ __export(repair_exports, {
|
|
|
3315
3356
|
withRepairSession: () => withRepairSession
|
|
3316
3357
|
});
|
|
3317
3358
|
import fs12 from "fs/promises";
|
|
3318
|
-
import
|
|
3359
|
+
import path20 from "path";
|
|
3319
3360
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
3320
3361
|
import { z as z7 } from "zod";
|
|
3321
3362
|
function recheckable(finding) {
|
|
@@ -3353,8 +3394,8 @@ async function readStableAudit(root, checks, options) {
|
|
|
3353
3394
|
async function prepareRepair(rootDir, checks = ALL_CHECKS, options = {}) {
|
|
3354
3395
|
return prepareOriginal(rootDir, checks, options);
|
|
3355
3396
|
}
|
|
3356
|
-
async function withRepairSession(root, options, run, cachedAudit) {
|
|
3357
|
-
const
|
|
3397
|
+
async function withRepairSession(root, options, run, validate, cachedAudit) {
|
|
3398
|
+
const head = await getCurrentGitHash(root);
|
|
3358
3399
|
const audits = /* @__PURE__ */ new Map();
|
|
3359
3400
|
const documents = /* @__PURE__ */ new Map();
|
|
3360
3401
|
const history = /* @__PURE__ */ new Map();
|
|
@@ -3365,9 +3406,9 @@ async function withRepairSession(root, options, run, cachedAudit) {
|
|
|
3365
3406
|
};
|
|
3366
3407
|
const session = {
|
|
3367
3408
|
audit: (checks) => memo(audits, [...checks].sort().join(","), async () => {
|
|
3368
|
-
if (cachedAudit && cachedAudit.headHash ===
|
|
3409
|
+
if (cachedAudit && cachedAudit.headHash === head && cachedAudit.root === root && digest([...checks].sort()) === digest([...cachedAudit.checksRun ?? []].sort())) {
|
|
3369
3410
|
const current = structuredClone(cachedAudit);
|
|
3370
|
-
const reviews = (await Promise.all(allFindings(current).map((f) => assessAdvisory(root, f,
|
|
3411
|
+
const reviews = (await Promise.all(allFindings(current).map((f) => assessAdvisory(root, f, head)))).filter((r) => r !== null);
|
|
3371
3412
|
delete current.advisoryReviews;
|
|
3372
3413
|
if (reviews.length) current.advisoryReviews = reviews;
|
|
3373
3414
|
return current;
|
|
@@ -3375,16 +3416,15 @@ async function withRepairSession(root, options, run, cachedAudit) {
|
|
|
3375
3416
|
return computeAudit(root, { ...options, checks });
|
|
3376
3417
|
}),
|
|
3377
3418
|
document: (file) => memo(documents, file, async () => readBoundedFile(await storePath(root, file), 10 * 1024 * 1024)),
|
|
3378
|
-
history: (
|
|
3379
|
-
assessment: (dir, finding,
|
|
3419
|
+
history: (head2) => memo(history, head2, () => getChangesWithStatus(root, head2)),
|
|
3420
|
+
assessment: (dir, finding, head2) => memo(assessments, digest([dir, finding, head2]), () => assessAdvisory(dir, finding, head2))
|
|
3380
3421
|
};
|
|
3381
3422
|
const result = await run({
|
|
3382
3423
|
prepare: () => prepareOriginal(root, ALL_CHECKS, options, session),
|
|
3383
3424
|
verify: (baseline) => profilePhase("repair.verify", () => verifyOriginal(root, baseline, options, session)),
|
|
3384
3425
|
currentAudit: () => session.audit(ALL_CHECKS)
|
|
3385
3426
|
});
|
|
3386
|
-
|
|
3387
|
-
if (digest(before) !== digest(after)) throw new Error("HEAD, context files or advisory review records changed during verification; retry against stable evidence.");
|
|
3427
|
+
await validate();
|
|
3388
3428
|
return result;
|
|
3389
3429
|
}
|
|
3390
3430
|
async function prepareOriginal(rootDir, checks, options, session) {
|
|
@@ -3406,8 +3446,8 @@ async function prepareOriginal(rootDir, checks, options, session) {
|
|
|
3406
3446
|
}
|
|
3407
3447
|
async function loadRepairBaseline(rootDir, baselinePath) {
|
|
3408
3448
|
const root = await fs12.realpath(rootDir);
|
|
3409
|
-
const declaredRoot =
|
|
3410
|
-
const relative =
|
|
3449
|
+
const declaredRoot = path20.resolve(rootDir);
|
|
3450
|
+
const relative = path20.isAbsolute(baselinePath) ? path20.relative(isWithinRoot(declaredRoot, baselinePath) ? declaredRoot : root, baselinePath) : baselinePath;
|
|
3411
3451
|
const stored = baselineSchema.parse(await readStoreJson(root, relative));
|
|
3412
3452
|
const { digest: savedDigest, ...payload } = stored;
|
|
3413
3453
|
if (digest(payload) !== savedDigest) throw new Error("Repair baseline was modified; use the original baseline.");
|
|
@@ -3582,14 +3622,12 @@ var init_repair = __esm({
|
|
|
3582
3622
|
|
|
3583
3623
|
// src/automation/evidence.ts
|
|
3584
3624
|
import fs13 from "fs/promises";
|
|
3585
|
-
import
|
|
3625
|
+
import path21 from "path";
|
|
3586
3626
|
import { createHash as createHash3 } from "crypto";
|
|
3587
|
-
import { execFile as execFile9 } from "child_process";
|
|
3588
|
-
import { promisify as promisify9 } from "util";
|
|
3589
3627
|
import fg5 from "fast-glob";
|
|
3590
3628
|
import { z as z8 } from "zod";
|
|
3591
3629
|
async function git3(root, ...args) {
|
|
3592
|
-
return profilePhase("automation.git", async () => (await
|
|
3630
|
+
return profilePhase("automation.git", async () => (await execGit(args, { cwd: root, maxBuffer: 16 * 1024 * 1024, timeout: 1e4 })).stdout);
|
|
3593
3631
|
}
|
|
3594
3632
|
async function workspace(dir) {
|
|
3595
3633
|
const root = await fs13.realpath((await git3(dir, "rev-parse", "--show-toplevel")).trim());
|
|
@@ -3613,7 +3651,7 @@ async function collectInputs(root) {
|
|
|
3613
3651
|
const head = headText.trim();
|
|
3614
3652
|
let shallow = null;
|
|
3615
3653
|
try {
|
|
3616
|
-
shallow = await fs13.readFile(
|
|
3654
|
+
shallow = await fs13.readFile(path21.resolve(root, shallowPath.trim()), "utf8");
|
|
3617
3655
|
} catch (error) {
|
|
3618
3656
|
if (error.code !== "ENOENT") throw error;
|
|
3619
3657
|
}
|
|
@@ -3637,7 +3675,7 @@ async function collectInputs(root) {
|
|
|
3637
3675
|
if (scope?.candidates.some(gitMetadataPath)) continue;
|
|
3638
3676
|
for (const candidate of scope?.candidates ?? []) {
|
|
3639
3677
|
if (optionalMasonPath(candidate)) continue;
|
|
3640
|
-
const [filePresent, parentPresent] = await Promise.all([exists(candidate), exists(
|
|
3678
|
+
const [filePresent, parentPresent] = await Promise.all([exists(candidate), exists(path21.posix.dirname(candidate))]);
|
|
3641
3679
|
claims.push([candidate, filePresent, parentPresent]);
|
|
3642
3680
|
}
|
|
3643
3681
|
}
|
|
@@ -3649,7 +3687,7 @@ async function collectInputs(root) {
|
|
|
3649
3687
|
if (error.code === "ENOENT") return "absent";
|
|
3650
3688
|
throw error;
|
|
3651
3689
|
});
|
|
3652
|
-
const [modules, counts,
|
|
3690
|
+
const [modules, counts, commands2, decisionFiles] = await Promise.all([
|
|
3653
3691
|
combinedDocs ? moduleCandidates(root, combinedDocs) : [],
|
|
3654
3692
|
Promise.all(countClaims.map(({ doc, claim }) => resolveDocCountSource(root, doc, claim))),
|
|
3655
3693
|
commandInputs(root, parsedDocs),
|
|
@@ -3668,7 +3706,7 @@ async function collectInputs(root) {
|
|
|
3668
3706
|
"deleted-reference": hash([common, claims, docStatus]),
|
|
3669
3707
|
"new-module": hash([common, modules]),
|
|
3670
3708
|
"stale-count": hash([common, counts]),
|
|
3671
|
-
"dead-command": hash([common,
|
|
3709
|
+
"dead-command": hash([common, commands2]),
|
|
3672
3710
|
"deps-changed": hash([common, docStatus]),
|
|
3673
3711
|
"decision-anchor-drift": hash([common, decisionPresence, decisions, status, index2])
|
|
3674
3712
|
};
|
|
@@ -3706,10 +3744,11 @@ function checkCache(raw, inputs) {
|
|
|
3706
3744
|
}
|
|
3707
3745
|
};
|
|
3708
3746
|
}
|
|
3709
|
-
var
|
|
3747
|
+
var engineVersion, hash, content, cacheSchema;
|
|
3710
3748
|
var init_evidence = __esm({
|
|
3711
3749
|
"src/automation/evidence.ts"() {
|
|
3712
3750
|
"use strict";
|
|
3751
|
+
init_git_read();
|
|
3713
3752
|
init_profile();
|
|
3714
3753
|
init_docs();
|
|
3715
3754
|
init_scope();
|
|
@@ -3722,8 +3761,7 @@ var init_evidence = __esm({
|
|
|
3722
3761
|
init_dead_command();
|
|
3723
3762
|
init_storage();
|
|
3724
3763
|
init_advisory_review();
|
|
3725
|
-
|
|
3726
|
-
engineVersion = true ? "0.17.3" : "development";
|
|
3764
|
+
engineVersion = true ? "0.17.4" : "development";
|
|
3727
3765
|
hash = (value) => createHash3("sha256").update(JSON.stringify(value)).digest("hex");
|
|
3728
3766
|
content = readAuditInput;
|
|
3729
3767
|
cacheSchema = z8.object({ version: z8.literal(1), entries: z8.record(z8.object({ key: z8.string(), result: checkResultSchema })), digest: z8.string() });
|
|
@@ -3783,8 +3821,8 @@ var init_model = __esm({
|
|
|
3783
3821
|
});
|
|
3784
3822
|
|
|
3785
3823
|
// src/setup/launcher.ts
|
|
3786
|
-
import { execFile as
|
|
3787
|
-
import { promisify as
|
|
3824
|
+
import { execFile as execFile2 } from "child_process";
|
|
3825
|
+
import { promisify as promisify2 } from "util";
|
|
3788
3826
|
import fs14 from "fs/promises";
|
|
3789
3827
|
function globalCommand(args, platform = process.platform) {
|
|
3790
3828
|
return platform === "win32" ? { command: "cmd.exe", args: ["/d", "/s", "/c", "mason", ...args] } : { command: "mason", args };
|
|
@@ -3792,7 +3830,7 @@ function globalCommand(args, platform = process.platform) {
|
|
|
3792
3830
|
async function installedCommand() {
|
|
3793
3831
|
const invocation = globalCommand(["internal-integration-version"]);
|
|
3794
3832
|
try {
|
|
3795
|
-
const { stdout } = await
|
|
3833
|
+
const { stdout } = await promisify2(execFile2)(
|
|
3796
3834
|
invocation.command,
|
|
3797
3835
|
invocation.args,
|
|
3798
3836
|
{ timeout: 5e3, maxBuffer: 8192, windowsHide: true }
|
|
@@ -3815,7 +3853,7 @@ var init_launcher = __esm({
|
|
|
3815
3853
|
"use strict";
|
|
3816
3854
|
init_evidence();
|
|
3817
3855
|
init_model();
|
|
3818
|
-
executingVersion = () => true ? "0.17.
|
|
3856
|
+
executingVersion = () => true ? "0.17.4" : "development";
|
|
3819
3857
|
mcpCommand = (host) => globalCommand(["--setup-host", host, "mcp"]);
|
|
3820
3858
|
hookCommand = (host) => `mason --setup-host ${host} auto`;
|
|
3821
3859
|
}
|
|
@@ -3829,7 +3867,7 @@ __export(files_exports, {
|
|
|
3829
3867
|
readText: () => readText
|
|
3830
3868
|
});
|
|
3831
3869
|
import fs17 from "fs/promises";
|
|
3832
|
-
import
|
|
3870
|
+
import path25 from "path";
|
|
3833
3871
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
3834
3872
|
async function readText(root, file) {
|
|
3835
3873
|
try {
|
|
@@ -3862,7 +3900,7 @@ async function applyEdit(root, edit) {
|
|
|
3862
3900
|
return true;
|
|
3863
3901
|
}
|
|
3864
3902
|
const file = await storePath(root, edit.path, true);
|
|
3865
|
-
const temporary =
|
|
3903
|
+
const temporary = path25.join(path25.dirname(file), ".mason-setup-" + randomUUID3() + ".tmp");
|
|
3866
3904
|
try {
|
|
3867
3905
|
const mode = await fs17.stat(file).then((s) => s.mode & 511, () => 384);
|
|
3868
3906
|
const handle = await fs17.open(temporary, "wx", mode);
|
|
@@ -4164,12 +4202,12 @@ async function matchingAnalysis(ws, state, inputs) {
|
|
|
4164
4202
|
return { analysis: a };
|
|
4165
4203
|
}
|
|
4166
4204
|
async function verifyInputs(ws, inputs) {
|
|
4167
|
-
return profilePhase("automation.revalidate", async () => {
|
|
4205
|
+
return profilePhase("automation.revalidate", () => withRepositoryInspection(ws.root, async () => {
|
|
4168
4206
|
const [after, currentWs] = await Promise.all([readInputs(ws.root), workspace(ws.root)]);
|
|
4169
4207
|
if (after.fingerprint !== inputs.fingerprint || currentWs.directory !== ws.directory) {
|
|
4170
4208
|
throw new Error("Repository inputs or branch changed during automation; no current verification was recorded. Retry on a stable checkout.");
|
|
4171
4209
|
}
|
|
4172
|
-
});
|
|
4210
|
+
}));
|
|
4173
4211
|
}
|
|
4174
4212
|
async function computeAnalysis(ws, state, inputs, event, previousAudit, cacheDiagnostic) {
|
|
4175
4213
|
const baselines = [...state.baselines];
|
|
@@ -4189,7 +4227,10 @@ async function computeAnalysis(ws, state, inputs, event, previousAudit, cacheDia
|
|
|
4189
4227
|
capture: "unknown",
|
|
4190
4228
|
scope: SCOPE
|
|
4191
4229
|
};
|
|
4192
|
-
if (!baselines.length && Object.values(inputs.docs).every((value) => value === null))
|
|
4230
|
+
if (!baselines.length && Object.values(inputs.docs).every((value) => value === null)) {
|
|
4231
|
+
await verifyInputs(ws, inputs);
|
|
4232
|
+
return { baselines, report: empty, cache: null };
|
|
4233
|
+
}
|
|
4193
4234
|
if (ws.branch === "detached" && state.latest) {
|
|
4194
4235
|
const previous = await readStoreJson(ws.root, state.latest);
|
|
4195
4236
|
if (!previous?.head || !/^[a-f0-9]{40,64}$/.test(previous.head)) throw new Error("The previous detached checkout evidence is unavailable.");
|
|
@@ -4227,7 +4268,7 @@ async function computeAnalysis(ws, state, inputs, event, previousAudit, cacheDia
|
|
|
4227
4268
|
}
|
|
4228
4269
|
currentAudit = await repairs.currentAudit();
|
|
4229
4270
|
return verifications2;
|
|
4230
|
-
}, cachedAudit);
|
|
4271
|
+
}, () => verifyInputs(ws, inputs), cachedAudit);
|
|
4231
4272
|
const merged = /* @__PURE__ */ new Map();
|
|
4232
4273
|
for (const verification of verifications) {
|
|
4233
4274
|
for (const finding of verification.findings) {
|
|
@@ -4262,7 +4303,6 @@ async function analyze(ws, inputs, event, startedAt) {
|
|
|
4262
4303
|
if (previous && previous.completedAt >= startedAt) return { analysis: previous, shared: true };
|
|
4263
4304
|
const originalDigest = await baselineDigest(ws, before);
|
|
4264
4305
|
const computed = await computeAnalysis(ws, before, inputs, event, previous?.currentAudit, diagnostic);
|
|
4265
|
-
await verifyInputs(ws, inputs);
|
|
4266
4306
|
if (originalDigest !== await baselineDigest(ws, before)) throw new Error("Repair baseline was modified during automation; original evidence must be inspected.");
|
|
4267
4307
|
const id = randomUUID5();
|
|
4268
4308
|
const analysis = analysisSchema.parse({
|
|
@@ -4291,7 +4331,7 @@ async function analyze(ws, inputs, event, startedAt) {
|
|
|
4291
4331
|
async function automate(dir, event) {
|
|
4292
4332
|
const startedAt = Date.now();
|
|
4293
4333
|
const ws = await profilePhase("automation.workspace", () => workspace(dir));
|
|
4294
|
-
return recordExecution(ws.root, ws.directory, event.event, async () => {
|
|
4334
|
+
return recordExecution(ws.root, ws.directory, event.event, () => withRepositoryInspection(ws.root, async () => {
|
|
4295
4335
|
const inputs = await readInputs(ws.root);
|
|
4296
4336
|
const result = await profilePhase("automation.analysis", () => analyze(ws, inputs, event, startedAt));
|
|
4297
4337
|
if (result.shared) {
|
|
@@ -4364,7 +4404,7 @@ async function automate(dir, event) {
|
|
|
4364
4404
|
await writeStoreJson(ws.root, ws.directory + "/state.json", state);
|
|
4365
4405
|
return { report, message: notify ? summarize(report) : null, continueOnce };
|
|
4366
4406
|
}));
|
|
4367
|
-
});
|
|
4407
|
+
}));
|
|
4368
4408
|
}
|
|
4369
4409
|
async function automationStatus(dir) {
|
|
4370
4410
|
const ws = await profilePhase("automation.workspace", () => workspace(dir));
|
|
@@ -4402,6 +4442,7 @@ var init_runtime = __esm({
|
|
|
4402
4442
|
"src/automation/runtime.ts"() {
|
|
4403
4443
|
"use strict";
|
|
4404
4444
|
init_profile();
|
|
4445
|
+
init_inspection();
|
|
4405
4446
|
init_execution();
|
|
4406
4447
|
init_repair();
|
|
4407
4448
|
init_types();
|
|
@@ -4447,7 +4488,7 @@ var init_runtime = __esm({
|
|
|
4447
4488
|
|
|
4448
4489
|
// src/automation/hook-root.ts
|
|
4449
4490
|
import fs19 from "fs/promises";
|
|
4450
|
-
import
|
|
4491
|
+
import path26 from "path";
|
|
4451
4492
|
var init_hook_root = __esm({
|
|
4452
4493
|
"src/automation/hook-root.ts"() {
|
|
4453
4494
|
"use strict";
|
|
@@ -4916,13 +4957,13 @@ If a build is interrupted, its partials remain in \`.mason/partial-snapshots/\`.
|
|
|
4916
4957
|
});
|
|
4917
4958
|
|
|
4918
4959
|
// src/review/cochange.ts
|
|
4919
|
-
import { execFile as
|
|
4920
|
-
import { promisify as
|
|
4960
|
+
import { execFile as execFile6 } from "child_process";
|
|
4961
|
+
import { promisify as promisify6 } from "util";
|
|
4921
4962
|
async function buildMatrix(resolvedRoot) {
|
|
4922
4963
|
try {
|
|
4923
|
-
const { stdout: shallow } = await
|
|
4964
|
+
const { stdout: shallow } = await exec4("git", ["rev-parse", "--is-shallow-repository"], { cwd: resolvedRoot });
|
|
4924
4965
|
if (shallow.trim() === "true") return null;
|
|
4925
|
-
const { stdout } = await
|
|
4966
|
+
const { stdout } = await exec4(
|
|
4926
4967
|
"git",
|
|
4927
4968
|
["log", `-n${HISTORY_COMMITS}`, "--format=%x01", "--name-only", "-M"],
|
|
4928
4969
|
{ cwd: resolvedRoot, maxBuffer: 100 * 1024 * 1024 }
|
|
@@ -4978,11 +5019,11 @@ async function findMissingPartners(resolvedRoot, changedFiles, existsOnDisk, all
|
|
|
4978
5019
|
findings.sort((a, b) => b.rate - a.rate || b.sharedCommits - a.sharedCommits);
|
|
4979
5020
|
return findings;
|
|
4980
5021
|
}
|
|
4981
|
-
var
|
|
5022
|
+
var exec4, HISTORY_COMMITS, MIN_FILE_COMMITS, MIN_SHARED_COMMITS, MIN_COCHANGE_RATE, MAX_COMMIT_FILES;
|
|
4982
5023
|
var init_cochange = __esm({
|
|
4983
5024
|
"src/review/cochange.ts"() {
|
|
4984
5025
|
"use strict";
|
|
4985
|
-
|
|
5026
|
+
exec4 = promisify6(execFile6);
|
|
4986
5027
|
HISTORY_COMMITS = 1500;
|
|
4987
5028
|
MIN_FILE_COMMITS = 5;
|
|
4988
5029
|
MIN_SHARED_COMMITS = 4;
|
|
@@ -5290,10 +5331,10 @@ var init_check = __esm({
|
|
|
5290
5331
|
});
|
|
5291
5332
|
|
|
5292
5333
|
// src/review/evidence.ts
|
|
5293
|
-
import
|
|
5334
|
+
import path27 from "path";
|
|
5294
5335
|
import { z as z22 } from "zod";
|
|
5295
5336
|
function relativeArtifact(root, file) {
|
|
5296
|
-
const relative =
|
|
5337
|
+
const relative = path27.isAbsolute(file) ? path27.relative(root, file) : file;
|
|
5297
5338
|
const normalized = normalizeRepoPath(relative);
|
|
5298
5339
|
if (!normalized) throw new Error(`Evidence artifact must be inside the repository: ${file}`);
|
|
5299
5340
|
return normalized;
|
|
@@ -5390,7 +5431,7 @@ async function collectReviewEvidence(root, manifests, changedFiles, decisions, d
|
|
|
5390
5431
|
const report = await readStoreJson(root, file);
|
|
5391
5432
|
if (report === null) throw new Error(`Report artifact is missing: ${file}`);
|
|
5392
5433
|
const sourceRoot = check.sourceRoot ?? root;
|
|
5393
|
-
if (!
|
|
5434
|
+
if (!path27.posix.isAbsolute(sourceRoot) && !/^[A-Za-z]:[\\/]/.test(sourceRoot)) throw new Error("sourceRoot must identify the absolute checkout root on the check runner.");
|
|
5394
5435
|
const parsed = check.report.format === "vitest-json" ? parseVitest(report, sourceRoot) : check.report.format === "mason-check-json" ? parseCheck(report, sourceRoot) : parseSarif(report, sourceRoot);
|
|
5395
5436
|
result.outcome = parsed.outcome;
|
|
5396
5437
|
result.counts = parsed.counts;
|
|
@@ -5512,12 +5553,12 @@ var init_evidence2 = __esm({
|
|
|
5512
5553
|
|
|
5513
5554
|
// src/review/review.ts
|
|
5514
5555
|
import fs20 from "fs/promises";
|
|
5515
|
-
import
|
|
5516
|
-
import { execFile as
|
|
5517
|
-
import { promisify as
|
|
5556
|
+
import path28 from "path";
|
|
5557
|
+
import { execFile as execFile7 } from "child_process";
|
|
5558
|
+
import { promisify as promisify7 } from "util";
|
|
5518
5559
|
async function resolveMergeBase(resolvedRoot, base, head) {
|
|
5519
5560
|
try {
|
|
5520
|
-
const { stdout } = await
|
|
5561
|
+
const { stdout } = await exec5("git", ["merge-base", base, head], {
|
|
5521
5562
|
cwd: resolvedRoot
|
|
5522
5563
|
});
|
|
5523
5564
|
return stdout.trim() || null;
|
|
@@ -5528,7 +5569,7 @@ async function resolveMergeBase(resolvedRoot, base, head) {
|
|
|
5528
5569
|
async function defaultBase(resolvedRoot) {
|
|
5529
5570
|
for (const ref of ["origin/HEAD", "origin/main", "origin/master", "main"]) {
|
|
5530
5571
|
try {
|
|
5531
|
-
await
|
|
5572
|
+
await exec5("git", ["rev-parse", "--verify", "--quiet", ref], {
|
|
5532
5573
|
cwd: resolvedRoot
|
|
5533
5574
|
});
|
|
5534
5575
|
return ref;
|
|
@@ -5541,7 +5582,7 @@ function anchorsTouched(record, changedFiles) {
|
|
|
5541
5582
|
return matchingPaths(record.files, changedFiles);
|
|
5542
5583
|
}
|
|
5543
5584
|
async function computeReview(rootDir, base, options = {}) {
|
|
5544
|
-
const resolvedRoot =
|
|
5585
|
+
const resolvedRoot = path28.resolve(rootDir);
|
|
5545
5586
|
const head = await getCurrentGitHash(resolvedRoot);
|
|
5546
5587
|
if (head === "unknown") return null;
|
|
5547
5588
|
const mergeBase = await resolveMergeBase(resolvedRoot, base, head);
|
|
@@ -5591,7 +5632,7 @@ async function computeReview(rootDir, base, options = {}) {
|
|
|
5591
5632
|
analyzed,
|
|
5592
5633
|
async (relPath) => {
|
|
5593
5634
|
try {
|
|
5594
|
-
await fs20.access(
|
|
5635
|
+
await fs20.access(path28.join(resolvedRoot, relPath));
|
|
5595
5636
|
return true;
|
|
5596
5637
|
} catch {
|
|
5597
5638
|
return false;
|
|
@@ -5624,7 +5665,7 @@ async function computeReview(rootDir, base, options = {}) {
|
|
|
5624
5665
|
}
|
|
5625
5666
|
return finalize();
|
|
5626
5667
|
}
|
|
5627
|
-
var
|
|
5668
|
+
var exec5, MAX_ANALYZED_FILES;
|
|
5628
5669
|
var init_review = __esm({
|
|
5629
5670
|
"src/review/review.ts"() {
|
|
5630
5671
|
"use strict";
|
|
@@ -5636,7 +5677,7 @@ var init_review = __esm({
|
|
|
5636
5677
|
init_cochange();
|
|
5637
5678
|
init_evidence2();
|
|
5638
5679
|
init_snapshot();
|
|
5639
|
-
|
|
5680
|
+
exec5 = promisify7(execFile7);
|
|
5640
5681
|
MAX_ANALYZED_FILES = 50;
|
|
5641
5682
|
}
|
|
5642
5683
|
});
|
|
@@ -5726,7 +5767,7 @@ var init_onboarding = __esm({
|
|
|
5726
5767
|
});
|
|
5727
5768
|
|
|
5728
5769
|
// src/impact/references.ts
|
|
5729
|
-
import
|
|
5770
|
+
import path29 from "path";
|
|
5730
5771
|
function templateEnd(content2, start) {
|
|
5731
5772
|
let i = start + 1, interpolation = 0;
|
|
5732
5773
|
while (i < content2.length) {
|
|
@@ -5852,10 +5893,10 @@ function jvmImports(content2) {
|
|
|
5852
5893
|
}
|
|
5853
5894
|
function resolveImport(file, specifier, available) {
|
|
5854
5895
|
if (!specifier.startsWith("./") && !specifier.startsWith("../")) return null;
|
|
5855
|
-
const relative =
|
|
5896
|
+
const relative = path29.posix.normalize(path29.posix.join(path29.posix.dirname(file), specifier));
|
|
5856
5897
|
if (relative.startsWith("../")) return null;
|
|
5857
5898
|
if (available.has(relative)) return relative;
|
|
5858
|
-
const ext =
|
|
5899
|
+
const ext = path29.posix.extname(relative);
|
|
5859
5900
|
const replacements = { ".js": [".ts", ".tsx"], ".mjs": [".mts"], ".cjs": [".cts"] };
|
|
5860
5901
|
const candidates = ext ? (replacements[ext] ?? []).map((e) => relative.slice(0, -ext.length) + e) : jsExtensions.flatMap((e) => [relative + e, relative + "/index" + e]);
|
|
5861
5902
|
const found = candidates.filter((f) => available.has(f));
|
|
@@ -5867,13 +5908,13 @@ function mentionsPath(content2, target) {
|
|
|
5867
5908
|
function createReferenceMatcher(targets, available, targetContents = /* @__PURE__ */ new Map()) {
|
|
5868
5909
|
const counts = /* @__PURE__ */ new Map();
|
|
5869
5910
|
for (const file of available) {
|
|
5870
|
-
const name =
|
|
5911
|
+
const name = path29.posix.basename(file, path29.posix.extname(file));
|
|
5871
5912
|
counts.set(name, (counts.get(name) ?? 0) + 1);
|
|
5872
5913
|
}
|
|
5873
5914
|
const jvmTargets = new Map([...targetContents].filter(([file]) => /\.(?:kt|kts|java)$/.test(file)).map(([file, content2]) => [file, declaredSymbols(content2)]));
|
|
5874
5915
|
return (source) => {
|
|
5875
5916
|
if (targets.includes(source.path)) return [];
|
|
5876
|
-
const resolved = new Set(jsExtensions.includes(
|
|
5917
|
+
const resolved = new Set(jsExtensions.includes(path29.posix.extname(source.path)) ? imports(source.content).map((s) => resolveImport(source.path, s, available)).filter(Boolean) : []);
|
|
5877
5918
|
if (/\.(?:kt|kts|java)$/.test(source.path)) {
|
|
5878
5919
|
const imported = jvmImports(source.content);
|
|
5879
5920
|
for (const [target, symbols] of jvmTargets) if (symbols.some((symbol) => imported.some((name) => name === symbol || name.startsWith(symbol + ".")))) resolved.add(target);
|
|
@@ -5889,7 +5930,7 @@ function createReferenceMatcher(targets, available, targetContents = /* @__PURE_
|
|
|
5889
5930
|
add("explicit-path", target);
|
|
5890
5931
|
continue;
|
|
5891
5932
|
}
|
|
5892
|
-
const ext =
|
|
5933
|
+
const ext = path29.posix.extname(target), name = path29.posix.basename(target, ext);
|
|
5893
5934
|
if (!/\.(?:[cm]?[jt]sx?|py|kt|java|go|rs|swift|rb|cs|cpp|c|h|hpp|dart|php)$/.test(ext) || name.startsWith(".") || name.length < 3 || genericNames.has(name.toLowerCase()) || counts.get(name) !== 1) continue;
|
|
5894
5935
|
if (word(name).test(source.content)) {
|
|
5895
5936
|
add("name-candidate", name);
|
|
@@ -5918,11 +5959,11 @@ var impact_exports = {};
|
|
|
5918
5959
|
__export(impact_exports, {
|
|
5919
5960
|
analyzeImpact: () => analyzeImpact
|
|
5920
5961
|
});
|
|
5921
|
-
import
|
|
5922
|
-
import { execFile as
|
|
5923
|
-
import { promisify as
|
|
5962
|
+
import path30 from "path";
|
|
5963
|
+
import { execFile as execFile8 } from "child_process";
|
|
5964
|
+
import { promisify as promisify8 } from "util";
|
|
5924
5965
|
async function analyzeImpact(rootDir, targetFiles) {
|
|
5925
|
-
const resolvedRoot =
|
|
5966
|
+
const resolvedRoot = path30.resolve(rootDir);
|
|
5926
5967
|
const resolvedTargets = await resolveTargetFiles(resolvedRoot, targetFiles);
|
|
5927
5968
|
const [cochange, references, tests] = await Promise.all([
|
|
5928
5969
|
getCochangeFiles(resolvedRoot, resolvedTargets),
|
|
@@ -5965,7 +6006,7 @@ async function getCochangeFiles(rootDir, targetFiles) {
|
|
|
5965
6006
|
let totalTargetCommits = 0;
|
|
5966
6007
|
for (const targetFile of targetFiles) {
|
|
5967
6008
|
try {
|
|
5968
|
-
const { stdout: commitLog } = await
|
|
6009
|
+
const { stdout: commitLog } = await exec6(
|
|
5969
6010
|
"git",
|
|
5970
6011
|
["log", "--format=%H", "-n", "500", "--", targetFile],
|
|
5971
6012
|
{ cwd: rootDir, maxBuffer: 5e6 }
|
|
@@ -5975,7 +6016,7 @@ async function getCochangeFiles(rootDir, targetFiles) {
|
|
|
5975
6016
|
if (commits.length === 0) continue;
|
|
5976
6017
|
for (const commit of commits) {
|
|
5977
6018
|
try {
|
|
5978
|
-
const { stdout: filesInCommit } = await
|
|
6019
|
+
const { stdout: filesInCommit } = await exec6(
|
|
5979
6020
|
"git",
|
|
5980
6021
|
["diff-tree", "--no-commit-id", "--name-only", "-r", commit],
|
|
5981
6022
|
{ cwd: rootDir }
|
|
@@ -6036,9 +6077,9 @@ async function getRelatedTests(rootDir, targetFiles) {
|
|
|
6036
6077
|
const testFiles = await (await createFileAccess(rootDir)).list(testPatterns);
|
|
6037
6078
|
const results = [];
|
|
6038
6079
|
for (const target of targetFiles) {
|
|
6039
|
-
const targetBaseName =
|
|
6080
|
+
const targetBaseName = path30.basename(target).replace(/\.[^.]+$/, "");
|
|
6040
6081
|
for (const testFile of testFiles) {
|
|
6041
|
-
const testBaseName =
|
|
6082
|
+
const testBaseName = path30.basename(testFile).replace(/\.[^.]+$/, "");
|
|
6042
6083
|
const sourceName = testBaseName.replace(/Test$|Tests$|Spec$|\.test$|\.spec$/, "").replace(/^test_|_test$/, "");
|
|
6043
6084
|
if (sourceName === targetBaseName) {
|
|
6044
6085
|
results.push({
|
|
@@ -6050,14 +6091,14 @@ async function getRelatedTests(rootDir, targetFiles) {
|
|
|
6050
6091
|
}
|
|
6051
6092
|
return results;
|
|
6052
6093
|
}
|
|
6053
|
-
var
|
|
6094
|
+
var exec6;
|
|
6054
6095
|
var init_impact = __esm({
|
|
6055
6096
|
"src/impact/impact.ts"() {
|
|
6056
6097
|
"use strict";
|
|
6057
6098
|
init_files();
|
|
6058
6099
|
init_paths();
|
|
6059
6100
|
init_references();
|
|
6060
|
-
|
|
6101
|
+
exec6 = promisify8(execFile8);
|
|
6061
6102
|
}
|
|
6062
6103
|
});
|
|
6063
6104
|
|
|
@@ -6066,13 +6107,13 @@ var assemble_exports = {};
|
|
|
6066
6107
|
__export(assemble_exports, {
|
|
6067
6108
|
assembleContext: () => assembleContext
|
|
6068
6109
|
});
|
|
6069
|
-
import
|
|
6110
|
+
import path31 from "path";
|
|
6070
6111
|
import fs21 from "fs/promises";
|
|
6071
6112
|
async function collectImpact(root, candidates) {
|
|
6072
6113
|
const targets = /* @__PURE__ */ new Set();
|
|
6073
6114
|
let sourceFiles;
|
|
6074
6115
|
for (const candidate of sanitizeRepoPaths(candidates)) {
|
|
6075
|
-
const stat = await fs21.stat(
|
|
6116
|
+
const stat = await fs21.stat(path31.join(root, candidate)).catch(() => null);
|
|
6076
6117
|
if (stat?.isDirectory()) {
|
|
6077
6118
|
sourceFiles ??= await (await createFileAccess(root)).list();
|
|
6078
6119
|
for (const file of sourceFiles) {
|
|
@@ -6098,7 +6139,7 @@ async function collectImpact(root, candidates) {
|
|
|
6098
6139
|
};
|
|
6099
6140
|
}
|
|
6100
6141
|
async function assembleContext(rootDir, task, files) {
|
|
6101
|
-
const resolvedRoot =
|
|
6142
|
+
const resolvedRoot = path31.resolve(rootDir);
|
|
6102
6143
|
const mapState = await inspectSnapshot(resolvedRoot);
|
|
6103
6144
|
const snapshot = mapState.snapshot;
|
|
6104
6145
|
const store = await loadDecisionStore(resolvedRoot);
|
|
@@ -6641,8 +6682,8 @@ __export(client_exports, {
|
|
|
6641
6682
|
function createConfluenceClient(config, fetchFn = fetch) {
|
|
6642
6683
|
const baseUrl = config.baseUrl.replace(/\/+$/, "");
|
|
6643
6684
|
const auth = "Basic " + Buffer.from(`${config.email}:${config.apiToken}`).toString("base64");
|
|
6644
|
-
async function call(method,
|
|
6645
|
-
const res = await fetchFn(`${baseUrl}${
|
|
6685
|
+
async function call(method, path35, body) {
|
|
6686
|
+
const res = await fetchFn(`${baseUrl}${path35}`, {
|
|
6646
6687
|
method,
|
|
6647
6688
|
headers: {
|
|
6648
6689
|
Authorization: auth,
|
|
@@ -6654,7 +6695,7 @@ function createConfluenceClient(config, fetchFn = fetch) {
|
|
|
6654
6695
|
if (!res.ok) {
|
|
6655
6696
|
const text2 = await res.text();
|
|
6656
6697
|
throw new Error(
|
|
6657
|
-
`Confluence ${method} ${
|
|
6698
|
+
`Confluence ${method} ${path35} failed: ${res.status} ${res.statusText} \u2014 ${text2}`
|
|
6658
6699
|
);
|
|
6659
6700
|
}
|
|
6660
6701
|
if (res.status === 204) return null;
|
|
@@ -6756,15 +6797,15 @@ __export(config_exports2, {
|
|
|
6756
6797
|
validateProvider: () => validateProvider
|
|
6757
6798
|
});
|
|
6758
6799
|
import fs23 from "fs/promises";
|
|
6759
|
-
import
|
|
6800
|
+
import path32 from "path";
|
|
6760
6801
|
import os3 from "os";
|
|
6761
|
-
import { execFile as
|
|
6762
|
-
import { promisify as
|
|
6802
|
+
import { execFile as execFile9 } from "child_process";
|
|
6803
|
+
import { promisify as promisify9 } from "util";
|
|
6763
6804
|
function configDir() {
|
|
6764
|
-
return
|
|
6805
|
+
return path32.join(os3.homedir(), ".mason");
|
|
6765
6806
|
}
|
|
6766
6807
|
function configFile() {
|
|
6767
|
-
return
|
|
6808
|
+
return path32.join(configDir(), "config.json");
|
|
6768
6809
|
}
|
|
6769
6810
|
async function loadConfig() {
|
|
6770
6811
|
try {
|
|
@@ -6794,7 +6835,7 @@ async function detectCLI(provider) {
|
|
|
6794
6835
|
const cliName = provider === "claude" ? "claude" : provider === "gemini" ? "gemini" : provider === "ollama" ? "ollama" : null;
|
|
6795
6836
|
if (!cliName) return { available: false };
|
|
6796
6837
|
try {
|
|
6797
|
-
const { stdout } = await
|
|
6838
|
+
const { stdout } = await exec7(cliName, ["--version"]);
|
|
6798
6839
|
return { available: true, version: stdout.trim() };
|
|
6799
6840
|
} catch {
|
|
6800
6841
|
return { available: false };
|
|
@@ -6811,11 +6852,11 @@ async function loadConfluenceConfig() {
|
|
|
6811
6852
|
const config = await loadConfig();
|
|
6812
6853
|
return config?.confluence ?? null;
|
|
6813
6854
|
}
|
|
6814
|
-
var
|
|
6855
|
+
var exec7, DEFAULT_MODELS;
|
|
6815
6856
|
var init_config2 = __esm({
|
|
6816
6857
|
"src/llm/config.ts"() {
|
|
6817
6858
|
"use strict";
|
|
6818
|
-
|
|
6859
|
+
exec7 = promisify9(execFile9);
|
|
6819
6860
|
DEFAULT_MODELS = {
|
|
6820
6861
|
claude: "claude-sonnet-4-20250514",
|
|
6821
6862
|
gemini: "gemini-2.5-flash",
|
|
@@ -6937,16 +6978,16 @@ var init_renderer = __esm({
|
|
|
6937
6978
|
|
|
6938
6979
|
// src/confluence/diff.ts
|
|
6939
6980
|
import fs24 from "fs/promises";
|
|
6940
|
-
import
|
|
6981
|
+
import path33 from "path";
|
|
6941
6982
|
import { createHash as createHash5 } from "crypto";
|
|
6942
6983
|
function hashDescription(description) {
|
|
6943
6984
|
return createHash5("sha256").update(description, "utf8").digest("hex");
|
|
6944
6985
|
}
|
|
6945
6986
|
function syncStateDir(rootDir) {
|
|
6946
|
-
return
|
|
6987
|
+
return path33.join(rootDir, ".mason");
|
|
6947
6988
|
}
|
|
6948
6989
|
function syncStatePath(rootDir) {
|
|
6949
|
-
return
|
|
6990
|
+
return path33.join(syncStateDir(rootDir), "confluence-sync.json");
|
|
6950
6991
|
}
|
|
6951
6992
|
async function loadSyncState(rootDir) {
|
|
6952
6993
|
try {
|
|
@@ -7014,8 +7055,8 @@ var init_diff = __esm({
|
|
|
7014
7055
|
});
|
|
7015
7056
|
|
|
7016
7057
|
// src/llm/providers.ts
|
|
7017
|
-
import { execFile as
|
|
7018
|
-
import { promisify as
|
|
7058
|
+
import { execFile as execFile10, spawn } from "child_process";
|
|
7059
|
+
import { promisify as promisify10 } from "util";
|
|
7019
7060
|
async function callLLM(config, userMessage, systemPrompt) {
|
|
7020
7061
|
const model = config.model ?? getDefaultModel(config.provider);
|
|
7021
7062
|
const system = systemPrompt ?? CLAUDE_MD_SYSTEM_PROMPT;
|
|
@@ -7172,12 +7213,12 @@ async function callOpenAIAPI(apiKey, model, system, userMessage) {
|
|
|
7172
7213
|
});
|
|
7173
7214
|
return response.choices[0]?.message?.content ?? "";
|
|
7174
7215
|
}
|
|
7175
|
-
var
|
|
7216
|
+
var exec8, CLAUDE_MD_SYSTEM_PROMPT;
|
|
7176
7217
|
var init_providers = __esm({
|
|
7177
7218
|
"src/llm/providers.ts"() {
|
|
7178
7219
|
"use strict";
|
|
7179
7220
|
init_config2();
|
|
7180
|
-
|
|
7221
|
+
exec8 = promisify10(execFile10);
|
|
7181
7222
|
CLAUDE_MD_SYSTEM_PROMPT = `You are Mason, a context engineering tool. You've been given a comprehensive analysis of a codebase including:
|
|
7182
7223
|
- Git history stats (commit patterns, frequently changed files, stale directories)
|
|
7183
7224
|
- Project structure (directory layout, file counts by type)
|
|
@@ -7519,20 +7560,20 @@ import { z as z24 } from "zod";
|
|
|
7519
7560
|
init_repair();
|
|
7520
7561
|
init_advisory_review();
|
|
7521
7562
|
import fs25 from "fs/promises";
|
|
7522
|
-
import
|
|
7523
|
-
import { execFile as
|
|
7524
|
-
import { promisify as
|
|
7563
|
+
import path34 from "path";
|
|
7564
|
+
import { execFile as execFile11 } from "child_process";
|
|
7565
|
+
import { promisify as promisify11 } from "util";
|
|
7525
7566
|
|
|
7526
7567
|
// src/audit/cli.ts
|
|
7527
7568
|
init_audit();
|
|
7528
7569
|
init_types();
|
|
7529
7570
|
init_repair();
|
|
7530
7571
|
init_findings();
|
|
7531
|
-
import
|
|
7572
|
+
import path23 from "path";
|
|
7532
7573
|
|
|
7533
7574
|
// src/audit/advisory-cli.ts
|
|
7534
7575
|
init_advisory_review();
|
|
7535
|
-
import
|
|
7576
|
+
import path22 from "path";
|
|
7536
7577
|
import { stripVTControlCharacters } from "util";
|
|
7537
7578
|
|
|
7538
7579
|
// src/audit/cli.ts
|
|
@@ -7625,8 +7666,8 @@ function formatFixPrompt(report, baselinePath) {
|
|
|
7625
7666
|
}
|
|
7626
7667
|
|
|
7627
7668
|
// src/analyzers/git-history.ts
|
|
7628
|
-
import { execFile as
|
|
7629
|
-
import { promisify as
|
|
7669
|
+
import { execFile as execFile3 } from "child_process";
|
|
7670
|
+
import { promisify as promisify3 } from "util";
|
|
7630
7671
|
|
|
7631
7672
|
// src/analyzers/base.ts
|
|
7632
7673
|
import fs15 from "fs/promises";
|
|
@@ -7663,7 +7704,7 @@ var BaseAnalyzer = class {
|
|
|
7663
7704
|
};
|
|
7664
7705
|
|
|
7665
7706
|
// src/analyzers/git-history.ts
|
|
7666
|
-
var
|
|
7707
|
+
var exec = promisify3(execFile3);
|
|
7667
7708
|
var GitHistoryAnalyzer = class extends BaseAnalyzer {
|
|
7668
7709
|
name = "git-history";
|
|
7669
7710
|
async analyze(context) {
|
|
@@ -7684,7 +7725,7 @@ var GitHistoryAnalyzer = class extends BaseAnalyzer {
|
|
|
7684
7725
|
}
|
|
7685
7726
|
async git(args, cwd) {
|
|
7686
7727
|
try {
|
|
7687
|
-
const { stdout } = await
|
|
7728
|
+
const { stdout } = await exec("git", args, { cwd, maxBuffer: 1e7 });
|
|
7688
7729
|
return stdout.trim();
|
|
7689
7730
|
} catch {
|
|
7690
7731
|
return "";
|
|
@@ -7833,12 +7874,10 @@ async function runAll(context) {
|
|
|
7833
7874
|
}
|
|
7834
7875
|
|
|
7835
7876
|
// src/utils/git.ts
|
|
7836
|
-
|
|
7837
|
-
import { promisify as promisify12 } from "util";
|
|
7838
|
-
var exec9 = promisify12(execFile12);
|
|
7877
|
+
init_git_read();
|
|
7839
7878
|
async function isGitRepo(dir) {
|
|
7840
7879
|
try {
|
|
7841
|
-
await
|
|
7880
|
+
await execGit(["rev-parse", "--git-dir"], { cwd: dir });
|
|
7842
7881
|
return true;
|
|
7843
7882
|
} catch {
|
|
7844
7883
|
return false;
|
|
@@ -7847,10 +7886,10 @@ async function isGitRepo(dir) {
|
|
|
7847
7886
|
|
|
7848
7887
|
// src/mcp/sampler.ts
|
|
7849
7888
|
init_files();
|
|
7850
|
-
import
|
|
7851
|
-
import { execFile as
|
|
7852
|
-
import { promisify as
|
|
7853
|
-
var
|
|
7889
|
+
import path24 from "path";
|
|
7890
|
+
import { execFile as execFile4 } from "child_process";
|
|
7891
|
+
import { promisify as promisify4 } from "util";
|
|
7892
|
+
var exec2 = promisify4(execFile4);
|
|
7854
7893
|
var CONFIG_FILES = [
|
|
7855
7894
|
// Build & project config
|
|
7856
7895
|
"package.json",
|
|
@@ -7955,8 +7994,8 @@ async function sampleFiles(rootDir, maxFiles = 25) {
|
|
|
7955
7994
|
const projectConfig = access.config;
|
|
7956
7995
|
for (const filePath of projectConfig.alwaysInclude ?? []) {
|
|
7957
7996
|
if (selected.size >= maxFiles) break;
|
|
7958
|
-
const resolvedPath =
|
|
7959
|
-
if (!resolvedPath.startsWith(
|
|
7997
|
+
const resolvedPath = path24.resolve(rootDir, filePath);
|
|
7998
|
+
if (!resolvedPath.startsWith(path24.resolve(rootDir))) continue;
|
|
7960
7999
|
selected.set(filePath, "always-include (project config)");
|
|
7961
8000
|
}
|
|
7962
8001
|
let configCount = 0;
|
|
@@ -8012,7 +8051,7 @@ async function sampleFiles(rootDir, maxFiles = 25) {
|
|
|
8012
8051
|
}
|
|
8013
8052
|
}
|
|
8014
8053
|
try {
|
|
8015
|
-
const { stdout } = await
|
|
8054
|
+
const { stdout } = await exec2(
|
|
8016
8055
|
"git",
|
|
8017
8056
|
["log", "--since=3 months ago", "--format=", "--name-only"],
|
|
8018
8057
|
{ cwd: rootDir, maxBuffer: 5e6 }
|
|
@@ -8022,7 +8061,7 @@ async function sampleFiles(rootDir, maxFiles = 25) {
|
|
|
8022
8061
|
if (!line) continue;
|
|
8023
8062
|
if (line.includes("node_modules") || line.includes("/build/") || line.includes(".gradle") || line.includes("/generated/"))
|
|
8024
8063
|
continue;
|
|
8025
|
-
const ext =
|
|
8064
|
+
const ext = path24.extname(line).slice(1);
|
|
8026
8065
|
if (!SOURCE_EXTENSIONS.includes(ext)) continue;
|
|
8027
8066
|
fileCounts.set(line, (fileCounts.get(line) ?? 0) + 1);
|
|
8028
8067
|
}
|
|
@@ -8142,10 +8181,10 @@ init_drift();
|
|
|
8142
8181
|
init_paths();
|
|
8143
8182
|
init_files();
|
|
8144
8183
|
import { createHash as createHash4 } from "crypto";
|
|
8145
|
-
import { execFile as
|
|
8146
|
-
import { promisify as
|
|
8184
|
+
import { execFile as execFile5 } from "child_process";
|
|
8185
|
+
import { promisify as promisify5 } from "util";
|
|
8147
8186
|
import { z as z10 } from "zod";
|
|
8148
|
-
var
|
|
8187
|
+
var exec3 = promisify5(execFile5);
|
|
8149
8188
|
var requestSchema = z10.object({
|
|
8150
8189
|
id: z10.string().regex(/^[a-zA-Z0-9_-]+$/),
|
|
8151
8190
|
action: z10.enum(["prepare", "accept", "reaffirm", "retire"]).default("prepare"),
|
|
@@ -8200,7 +8239,7 @@ async function previews(root, record, state) {
|
|
|
8200
8239
|
let diffUnavailable;
|
|
8201
8240
|
if (state.evidence.historyAvailable && diffPaths.length) {
|
|
8202
8241
|
try {
|
|
8203
|
-
const { stdout } = await
|
|
8242
|
+
const { stdout } = await exec3("git", ["--literal-pathspecs", "diff", "--no-ext-diff", "--no-textconv", "--no-color", "--no-renames", "-U3", record.refreshedHash, state.evidence.headHash, "--", ...diffPaths], { cwd: root, maxBuffer: 1024 * 1024 });
|
|
8204
8243
|
diff = stdout.slice(0, 16e3);
|
|
8205
8244
|
if (stdout.length > diff.length) diffUnavailable = "Diff preview was truncated; inspect the full diff before reviewing.";
|
|
8206
8245
|
} catch {
|
|
@@ -8426,7 +8465,7 @@ function batchIdFor(offset) {
|
|
|
8426
8465
|
// src/mcp/tools.ts
|
|
8427
8466
|
init_init();
|
|
8428
8467
|
init_onboarding();
|
|
8429
|
-
var
|
|
8468
|
+
var exec9 = promisify11(execFile11);
|
|
8430
8469
|
async function buildContext(dir) {
|
|
8431
8470
|
return {
|
|
8432
8471
|
rootDir: dir,
|
|
@@ -8434,7 +8473,7 @@ async function buildContext(dir) {
|
|
|
8434
8473
|
};
|
|
8435
8474
|
}
|
|
8436
8475
|
async function analyzeProject(dir) {
|
|
8437
|
-
const rootDir =
|
|
8476
|
+
const rootDir = path34.resolve(dir);
|
|
8438
8477
|
const context = await buildContext(rootDir);
|
|
8439
8478
|
const results = await runAll(context);
|
|
8440
8479
|
const projectSnapshot = await detectProjectSnapshot(rootDir);
|
|
@@ -8489,7 +8528,7 @@ async function detectProjectSnapshot(rootDir) {
|
|
|
8489
8528
|
const present = [];
|
|
8490
8529
|
for (const file of buildFiles) {
|
|
8491
8530
|
try {
|
|
8492
|
-
await fs25.access(
|
|
8531
|
+
await fs25.access(path34.join(rootDir, file));
|
|
8493
8532
|
present.push(file);
|
|
8494
8533
|
} catch {
|
|
8495
8534
|
}
|
|
@@ -8531,7 +8570,7 @@ async function detectProjectSnapshot(rootDir) {
|
|
|
8531
8570
|
const sourceFiles = await access.list();
|
|
8532
8571
|
const fileCounts = {};
|
|
8533
8572
|
for (const file of sourceFiles) {
|
|
8534
|
-
const ext =
|
|
8573
|
+
const ext = path34.extname(file).slice(1);
|
|
8535
8574
|
fileCounts[ext] = (fileCounts[ext] ?? 0) + 1;
|
|
8536
8575
|
}
|
|
8537
8576
|
return {
|
|
@@ -8542,7 +8581,7 @@ async function detectProjectSnapshot(rootDir) {
|
|
|
8542
8581
|
};
|
|
8543
8582
|
}
|
|
8544
8583
|
async function getCodeSamples(dir, count4 = 15) {
|
|
8545
|
-
const rootDir =
|
|
8584
|
+
const rootDir = path34.resolve(dir);
|
|
8546
8585
|
const samples = await sampleFiles(rootDir, count4);
|
|
8547
8586
|
const output = {
|
|
8548
8587
|
note: "These are previews (first ~60 lines). Read the file directly with your own tools to see it in full.",
|
|
@@ -8585,7 +8624,7 @@ async function unmappedContextResponse(rootDir) {
|
|
|
8585
8624
|
});
|
|
8586
8625
|
}
|
|
8587
8626
|
async function getProjectStructure(dir) {
|
|
8588
|
-
const rootDir =
|
|
8627
|
+
const rootDir = path34.resolve(dir);
|
|
8589
8628
|
const allFiles = await (await createFileAccess(rootDir)).list("**/*");
|
|
8590
8629
|
const dirInfo = /* @__PURE__ */ new Map();
|
|
8591
8630
|
for (const file of allFiles) {
|
|
@@ -8597,7 +8636,7 @@ async function getProjectStructure(dir) {
|
|
|
8597
8636
|
}
|
|
8598
8637
|
const info = dirInfo.get(dirPath);
|
|
8599
8638
|
info.fileCount++;
|
|
8600
|
-
const ext =
|
|
8639
|
+
const ext = path34.extname(file).slice(1);
|
|
8601
8640
|
if (ext) {
|
|
8602
8641
|
info.extensions.set(ext, (info.extensions.get(ext) ?? 0) + 1);
|
|
8603
8642
|
}
|
|
@@ -8642,7 +8681,7 @@ async function buildChangedFilePreviews(rootDir, changedFiles) {
|
|
|
8642
8681
|
return previews2;
|
|
8643
8682
|
}
|
|
8644
8683
|
async function getSnapshot(dir) {
|
|
8645
|
-
const rootDir =
|
|
8684
|
+
const rootDir = path34.resolve(dir);
|
|
8646
8685
|
const snapshot = await loadSnapshot(rootDir);
|
|
8647
8686
|
if (!snapshot) {
|
|
8648
8687
|
return unmappedContextResponse(rootDir);
|
|
@@ -8743,7 +8782,7 @@ function driftHint(report) {
|
|
|
8743
8782
|
return "Read the changed files under staleFeatures/staleFlows, update those entries (fold unmappedFiles into the right features), and call save_snapshot with only the affected entries \u2014 unchanged entries are preserved. Drop ghostFiles from any entries that reference them, and delete features/flows that no longer exist via save_snapshot's removeFeatures/removeFlows.";
|
|
8744
8783
|
}
|
|
8745
8784
|
async function checkDrift(dir) {
|
|
8746
|
-
const rootDir =
|
|
8785
|
+
const rootDir = path34.resolve(dir);
|
|
8747
8786
|
const report = await computeDrift(rootDir);
|
|
8748
8787
|
if (!report) {
|
|
8749
8788
|
return JSON.stringify({
|
|
@@ -8774,7 +8813,7 @@ async function checkDrift(dir) {
|
|
|
8774
8813
|
return JSON.stringify({ exists: true, ...report, verification, hint });
|
|
8775
8814
|
}
|
|
8776
8815
|
async function generateSnapshotBatch(dir, offset = 0, batchSize = DEFAULT_BATCH_SIZE, files) {
|
|
8777
|
-
const rootDir =
|
|
8816
|
+
const rootDir = path34.resolve(dir);
|
|
8778
8817
|
const scoped = files !== void 0 && files.length > 0;
|
|
8779
8818
|
const scopeFiles = scoped ? sanitizePaths(rootDir, files) : void 0;
|
|
8780
8819
|
const batch = await prepareSnapshotBatch(dir, offset, batchSize, scopeFiles);
|
|
@@ -8821,7 +8860,7 @@ async function generateSnapshotBatch(dir, offset = 0, batchSize = DEFAULT_BATCH_
|
|
|
8821
8860
|
);
|
|
8822
8861
|
}
|
|
8823
8862
|
async function saveSnapshotPartial(dir, batchId, offset, features, flows) {
|
|
8824
|
-
const rootDir =
|
|
8863
|
+
const rootDir = path34.resolve(dir);
|
|
8825
8864
|
for (const feat of Object.values(features)) {
|
|
8826
8865
|
feat.files = sanitizePaths(rootDir, feat.files);
|
|
8827
8866
|
if (feat.tests) feat.tests = sanitizePaths(rootDir, feat.tests);
|
|
@@ -8850,7 +8889,7 @@ async function saveSnapshotPartial(dir, batchId, offset, features, flows) {
|
|
|
8850
8889
|
);
|
|
8851
8890
|
}
|
|
8852
8891
|
async function reduceSnapshot(dir) {
|
|
8853
|
-
const rootDir =
|
|
8892
|
+
const rootDir = path34.resolve(dir);
|
|
8854
8893
|
const partials = await loadAllPartials(rootDir);
|
|
8855
8894
|
if (partials.length === 0) {
|
|
8856
8895
|
return JSON.stringify(
|
|
@@ -8912,7 +8951,7 @@ async function reduceSnapshot(dir) {
|
|
|
8912
8951
|
);
|
|
8913
8952
|
}
|
|
8914
8953
|
async function fullAnalysis(dir) {
|
|
8915
|
-
const rootDir =
|
|
8954
|
+
const rootDir = path34.resolve(dir);
|
|
8916
8955
|
const [analysis, structure, samples, testMap, snapshot] = await Promise.all([
|
|
8917
8956
|
analyzeProject(dir),
|
|
8918
8957
|
getProjectStructure(dir),
|
|
@@ -8941,7 +8980,7 @@ function sanitizePaths(rootDir, files) {
|
|
|
8941
8980
|
return sanitizeRepoPaths(files);
|
|
8942
8981
|
}
|
|
8943
8982
|
async function saveSnapshotData(dir, features, flows, removeFeatures = [], removeFlows = []) {
|
|
8944
|
-
const rootDir =
|
|
8983
|
+
const rootDir = path34.resolve(dir);
|
|
8945
8984
|
const gitHash = await getCurrentGitHash(rootDir);
|
|
8946
8985
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
8947
8986
|
for (const feat of Object.values(features)) {
|
|
@@ -9025,7 +9064,7 @@ async function saveSnapshotData(dir, features, flows, removeFeatures = [], remov
|
|
|
9025
9064
|
});
|
|
9026
9065
|
}
|
|
9027
9066
|
async function getImpact(dir, files) {
|
|
9028
|
-
const rootDir =
|
|
9067
|
+
const rootDir = path34.resolve(dir);
|
|
9029
9068
|
const { analyzeImpact: analyzeImpact2 } = await Promise.resolve().then(() => (init_impact(), impact_exports));
|
|
9030
9069
|
const result = await analyzeImpact2(rootDir, files);
|
|
9031
9070
|
return JSON.stringify(result, null, 2);
|
|
@@ -9034,7 +9073,7 @@ var VERIFY_DEFAULT_SAMPLE = 5;
|
|
|
9034
9073
|
var VERIFY_MAX_FILES_PER_ENTRY = 8;
|
|
9035
9074
|
var VERIFY_SKELETON_CHARS = 500;
|
|
9036
9075
|
async function verifySnapshot(dir, sample = VERIFY_DEFAULT_SAMPLE) {
|
|
9037
|
-
const rootDir =
|
|
9076
|
+
const rootDir = path34.resolve(dir);
|
|
9038
9077
|
const snapshot = await loadSnapshot(rootDir);
|
|
9039
9078
|
if (!snapshot) {
|
|
9040
9079
|
return JSON.stringify({
|
|
@@ -9099,7 +9138,7 @@ async function verifySnapshot(dir, sample = VERIFY_DEFAULT_SAMPLE) {
|
|
|
9099
9138
|
});
|
|
9100
9139
|
}
|
|
9101
9140
|
async function saveVerification(dir, verdicts) {
|
|
9102
|
-
const rootDir =
|
|
9141
|
+
const rootDir = path34.resolve(dir);
|
|
9103
9142
|
const snapshot = await loadSnapshot(rootDir);
|
|
9104
9143
|
if (!snapshot) {
|
|
9105
9144
|
return JSON.stringify({ exists: false, hint: "No concept map exists." });
|
|
@@ -9137,16 +9176,16 @@ async function saveVerification(dir, verdicts) {
|
|
|
9137
9176
|
});
|
|
9138
9177
|
}
|
|
9139
9178
|
async function saveDecision(dir, input) {
|
|
9140
|
-
const rootDir =
|
|
9179
|
+
const rootDir = path34.resolve(dir);
|
|
9141
9180
|
const { upsertDecision: upsertDecision2 } = await Promise.resolve().then(() => (init_decisions(), decisions_exports));
|
|
9142
9181
|
const result = await upsertDecision2(rootDir, input);
|
|
9143
9182
|
return JSON.stringify(result);
|
|
9144
9183
|
}
|
|
9145
9184
|
async function reviewDecision2(dir, input) {
|
|
9146
|
-
return JSON.stringify(await reviewDecision(
|
|
9185
|
+
return JSON.stringify(await reviewDecision(path34.resolve(dir), input));
|
|
9147
9186
|
}
|
|
9148
9187
|
async function getContext(dir, task, files) {
|
|
9149
|
-
const rootDir =
|
|
9188
|
+
const rootDir = path34.resolve(dir);
|
|
9150
9189
|
const { assembleContext: assembleContext2 } = await Promise.resolve().then(() => (init_assemble(), assemble_exports));
|
|
9151
9190
|
const bundle = await assembleContext2(rootDir, task, files);
|
|
9152
9191
|
return JSON.stringify(bundle);
|
|
@@ -9195,7 +9234,7 @@ async function masonInit(dir, options = {}) {
|
|
|
9195
9234
|
return JSON.stringify(await setupProject2(dir, options), null, 2);
|
|
9196
9235
|
}
|
|
9197
9236
|
if (options.host) throw new Error("host applies only to mode: setup.");
|
|
9198
|
-
const rootDir =
|
|
9237
|
+
const rootDir = path34.resolve(dir);
|
|
9199
9238
|
const marker = await loadProjectMarker(rootDir);
|
|
9200
9239
|
const { loadSetup: loadSetup2 } = await Promise.resolve().then(() => (init_model(), model_exports));
|
|
9201
9240
|
const setup = await loadSetup2(rootDir);
|
|
@@ -9215,7 +9254,7 @@ async function masonInit(dir, options = {}) {
|
|
|
9215
9254
|
);
|
|
9216
9255
|
}
|
|
9217
9256
|
async function masonCompleteInit(dir, options = {}) {
|
|
9218
|
-
const rootDir =
|
|
9257
|
+
const rootDir = path34.resolve(dir);
|
|
9219
9258
|
const existing = await loadProjectMarker(rootDir);
|
|
9220
9259
|
const features = await loadProjectFeatures(rootDir);
|
|
9221
9260
|
const marker = {
|
|
@@ -9324,7 +9363,7 @@ async function masonSetConfluence(input) {
|
|
|
9324
9363
|
);
|
|
9325
9364
|
}
|
|
9326
9365
|
async function exportToConfluenceTool(dir, overrides) {
|
|
9327
|
-
const rootDir =
|
|
9366
|
+
const rootDir = path34.resolve(dir);
|
|
9328
9367
|
const { loadConfig: loadConfig2 } = await Promise.resolve().then(() => (init_config2(), config_exports2));
|
|
9329
9368
|
const { exportToConfluence: exportToConfluence2 } = await Promise.resolve().then(() => (init_sync(), sync_exports));
|
|
9330
9369
|
const config = await loadConfig2();
|
|
@@ -9363,7 +9402,7 @@ function createMcpServer() {
|
|
|
9363
9402
|
const server = new McpServer(
|
|
9364
9403
|
{
|
|
9365
9404
|
name: "mason",
|
|
9366
|
-
version: "0.17.
|
|
9405
|
+
version: "0.17.4"
|
|
9367
9406
|
},
|
|
9368
9407
|
{
|
|
9369
9408
|
instructions: (setupNotice ? setupNotice + "\n\n" : "") + 'Mason retrieves recorded decisions, file impact, and optional feature/flow maps. Use get_context with the task and known files, and get_impact before editing. Save learned rationale and constraints with save_decision; review and commit the local records through the project workflow. These tools work without initialization or a concept map. Consult trust and diagnostics: changed or unknown freshness needs source inspection, failed verification needs correction, and proposals are suggestions and legacy records are unreviewed. Accepted decisions are recorded team constraints, still subject to freshness checks. Use review_decision to prepare code evidence and record only authorized acceptance, reaffirmation, or retirement. Never invent a reviewer or treat these recorded identities as authenticated approval. mason_init returns documentation audit and committed-diff review findings with a quickstart guide. Use mode: "map" only when a full architecture map is requested. A missing map is not a setup failure; use decisions and source evidence. get_snapshot provides architecture navigation when a map is available. The mason-audit and mason-review CLIs also work without setup.'
|