@massu/core 2.5.1 → 2.5.2
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 +170 -0
- package/dist/cli.js +578 -212
- package/dist/hooks/auto-learning-pipeline.js +244 -47
- package/dist/hooks/classify-failure.js +272 -18
- package/dist/hooks/cost-tracker.js +24 -1
- package/dist/hooks/fix-detector.js +40 -1
- package/dist/hooks/incident-pipeline.js +24 -1
- package/dist/hooks/intent-suggester.js +24 -1
- package/dist/hooks/memory-recall.js +24 -1
- package/dist/hooks/post-edit-context.js +72 -2
- package/dist/hooks/post-tool-use.js +25 -1
- package/dist/hooks/pre-compact.js +24 -1
- package/dist/hooks/pre-delete-check.js +72 -4
- package/dist/hooks/pre-tool-use-gate.js +78 -6
- package/dist/hooks/quality-event.js +24 -1
- package/dist/hooks/rule-enforcement-pipeline.js +24 -1
- package/dist/hooks/security-gate.js +22 -1
- package/dist/hooks/session-end.js +24 -1
- package/dist/hooks/session-start.js +24 -1
- package/dist/hooks/user-prompt.js +24 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1355,6 +1355,13 @@ var init_config = __esm({
|
|
|
1355
1355
|
});
|
|
1356
1356
|
LanguageFrameworkEntrySchema = z2.object({
|
|
1357
1357
|
framework: z2.string().optional(),
|
|
1358
|
+
// `source_dirs` is emitted by `init` (commands/init.ts:417) and existence-checked
|
|
1359
|
+
// by config validation (init.ts:868-876), but until 2026-08-14 it survived only via
|
|
1360
|
+
// `.passthrough()` — declared in the file, untyped in the schema. `lib/source-layout.ts`
|
|
1361
|
+
// derives the index builders' candidate set from it, so it is typed here rather than
|
|
1362
|
+
// read as an unknown: a consumer that has to shape-check its own SoT is one branch away
|
|
1363
|
+
// from silently contributing `undefined` to a path predicate.
|
|
1364
|
+
source_dirs: z2.array(z2.string()).optional(),
|
|
1358
1365
|
test_framework: z2.string().optional(),
|
|
1359
1366
|
test: z2.string().optional(),
|
|
1360
1367
|
runtime: z2.string().optional(),
|
|
@@ -9986,21 +9993,21 @@ var require_pattern = __commonJS({
|
|
|
9986
9993
|
exports.removeDuplicateSlashes = removeDuplicateSlashes;
|
|
9987
9994
|
function partitionAbsoluteAndRelative(patterns) {
|
|
9988
9995
|
const absolute = [];
|
|
9989
|
-
const
|
|
9996
|
+
const relative16 = [];
|
|
9990
9997
|
for (const pattern of patterns) {
|
|
9991
|
-
if (
|
|
9998
|
+
if (isAbsolute6(pattern)) {
|
|
9992
9999
|
absolute.push(pattern);
|
|
9993
10000
|
} else {
|
|
9994
|
-
|
|
10001
|
+
relative16.push(pattern);
|
|
9995
10002
|
}
|
|
9996
10003
|
}
|
|
9997
|
-
return [absolute,
|
|
10004
|
+
return [absolute, relative16];
|
|
9998
10005
|
}
|
|
9999
10006
|
exports.partitionAbsoluteAndRelative = partitionAbsoluteAndRelative;
|
|
10000
|
-
function
|
|
10007
|
+
function isAbsolute6(pattern) {
|
|
10001
10008
|
return path.isAbsolute(pattern);
|
|
10002
10009
|
}
|
|
10003
|
-
exports.isAbsolute =
|
|
10010
|
+
exports.isAbsolute = isAbsolute6;
|
|
10004
10011
|
}
|
|
10005
10012
|
});
|
|
10006
10013
|
|
|
@@ -11084,41 +11091,41 @@ var require_queue = __commonJS({
|
|
|
11084
11091
|
queue.drained = drained;
|
|
11085
11092
|
return queue;
|
|
11086
11093
|
function push(value) {
|
|
11087
|
-
var p19 = new Promise(function(
|
|
11094
|
+
var p19 = new Promise(function(resolve47, reject) {
|
|
11088
11095
|
pushCb(value, function(err, result) {
|
|
11089
11096
|
if (err) {
|
|
11090
11097
|
reject(err);
|
|
11091
11098
|
return;
|
|
11092
11099
|
}
|
|
11093
|
-
|
|
11100
|
+
resolve47(result);
|
|
11094
11101
|
});
|
|
11095
11102
|
});
|
|
11096
11103
|
p19.catch(noop);
|
|
11097
11104
|
return p19;
|
|
11098
11105
|
}
|
|
11099
11106
|
function unshift(value) {
|
|
11100
|
-
var p19 = new Promise(function(
|
|
11107
|
+
var p19 = new Promise(function(resolve47, reject) {
|
|
11101
11108
|
unshiftCb(value, function(err, result) {
|
|
11102
11109
|
if (err) {
|
|
11103
11110
|
reject(err);
|
|
11104
11111
|
return;
|
|
11105
11112
|
}
|
|
11106
|
-
|
|
11113
|
+
resolve47(result);
|
|
11107
11114
|
});
|
|
11108
11115
|
});
|
|
11109
11116
|
p19.catch(noop);
|
|
11110
11117
|
return p19;
|
|
11111
11118
|
}
|
|
11112
11119
|
function drained() {
|
|
11113
|
-
var p19 = new Promise(function(
|
|
11120
|
+
var p19 = new Promise(function(resolve47) {
|
|
11114
11121
|
process.nextTick(function() {
|
|
11115
11122
|
if (queue.idle()) {
|
|
11116
|
-
|
|
11123
|
+
resolve47();
|
|
11117
11124
|
} else {
|
|
11118
11125
|
var previousDrain = queue.drain;
|
|
11119
11126
|
queue.drain = function() {
|
|
11120
11127
|
if (typeof previousDrain === "function") previousDrain();
|
|
11121
|
-
|
|
11128
|
+
resolve47();
|
|
11122
11129
|
queue.drain = previousDrain;
|
|
11123
11130
|
};
|
|
11124
11131
|
}
|
|
@@ -11604,9 +11611,9 @@ var require_stream3 = __commonJS({
|
|
|
11604
11611
|
});
|
|
11605
11612
|
}
|
|
11606
11613
|
_getStat(filepath) {
|
|
11607
|
-
return new Promise((
|
|
11614
|
+
return new Promise((resolve47, reject) => {
|
|
11608
11615
|
this._stat(filepath, this._fsStatSettings, (error, stats) => {
|
|
11609
|
-
return error === null ?
|
|
11616
|
+
return error === null ? resolve47(stats) : reject(error);
|
|
11610
11617
|
});
|
|
11611
11618
|
});
|
|
11612
11619
|
}
|
|
@@ -11630,10 +11637,10 @@ var require_async5 = __commonJS({
|
|
|
11630
11637
|
this._readerStream = new stream_1.default(this._settings);
|
|
11631
11638
|
}
|
|
11632
11639
|
dynamic(root, options) {
|
|
11633
|
-
return new Promise((
|
|
11640
|
+
return new Promise((resolve47, reject) => {
|
|
11634
11641
|
this._walkAsync(root, options, (error, entries) => {
|
|
11635
11642
|
if (error === null) {
|
|
11636
|
-
|
|
11643
|
+
resolve47(entries);
|
|
11637
11644
|
} else {
|
|
11638
11645
|
reject(error);
|
|
11639
11646
|
}
|
|
@@ -11643,10 +11650,10 @@ var require_async5 = __commonJS({
|
|
|
11643
11650
|
async static(patterns, options) {
|
|
11644
11651
|
const entries = [];
|
|
11645
11652
|
const stream = this._readerStream.static(patterns, options);
|
|
11646
|
-
return new Promise((
|
|
11653
|
+
return new Promise((resolve47, reject) => {
|
|
11647
11654
|
stream.once("error", reject);
|
|
11648
11655
|
stream.on("data", (entry) => entries.push(entry));
|
|
11649
|
-
stream.once("end", () =>
|
|
11656
|
+
stream.once("end", () => resolve47(entries));
|
|
11650
11657
|
});
|
|
11651
11658
|
}
|
|
11652
11659
|
};
|
|
@@ -16611,15 +16618,15 @@ function resolveHooksDir() {
|
|
|
16611
16618
|
}
|
|
16612
16619
|
return "node_modules/@massu/core/dist/hooks";
|
|
16613
16620
|
}
|
|
16614
|
-
function massuRuntimeDir(version) {
|
|
16615
|
-
return resolve9(
|
|
16621
|
+
function massuRuntimeDir(version, home = homedir7()) {
|
|
16622
|
+
return resolve9(home, ".massu", "runtime", version);
|
|
16616
16623
|
}
|
|
16617
|
-
function massuRuntimeCliPath(version) {
|
|
16618
|
-
return resolve9(massuRuntimeDir(version), "node_modules", "@massu", "core", "dist", "cli.js");
|
|
16624
|
+
function massuRuntimeCliPath(version, home = homedir7()) {
|
|
16625
|
+
return resolve9(massuRuntimeDir(version, home), "node_modules", "@massu", "core", "dist", "cli.js");
|
|
16619
16626
|
}
|
|
16620
|
-
function resolveMassuRuntimeCli(version) {
|
|
16627
|
+
function resolveMassuRuntimeCli(version, home = homedir7()) {
|
|
16621
16628
|
if (process.env.MASSU_NO_NODE_DIRECT === "1") return null;
|
|
16622
|
-
const cli = massuRuntimeCliPath(version);
|
|
16629
|
+
const cli = massuRuntimeCliPath(version, home);
|
|
16623
16630
|
if (!existsSync19(cli)) return null;
|
|
16624
16631
|
try {
|
|
16625
16632
|
execFileSync2(process.execPath, [cli, "--version"], { stdio: "ignore", timeout: 2e4 });
|
|
@@ -16628,10 +16635,10 @@ function resolveMassuRuntimeCli(version) {
|
|
|
16628
16635
|
return null;
|
|
16629
16636
|
}
|
|
16630
16637
|
}
|
|
16631
|
-
function materializeMassuRuntime(version) {
|
|
16638
|
+
function materializeMassuRuntime(version, home = homedir7()) {
|
|
16632
16639
|
if (process.env.MASSU_NO_NODE_DIRECT === "1") return false;
|
|
16633
|
-
if (resolveMassuRuntimeCli(version) !== null) return true;
|
|
16634
|
-
const dir = massuRuntimeDir(version);
|
|
16640
|
+
if (resolveMassuRuntimeCli(version, home) !== null) return true;
|
|
16641
|
+
const dir = massuRuntimeDir(version, home);
|
|
16635
16642
|
try {
|
|
16636
16643
|
mkdirSync10(dir, { recursive: true });
|
|
16637
16644
|
execFileSync2(
|
|
@@ -16642,10 +16649,10 @@ function materializeMassuRuntime(version) {
|
|
|
16642
16649
|
} catch {
|
|
16643
16650
|
return false;
|
|
16644
16651
|
}
|
|
16645
|
-
return resolveMassuRuntimeCli(version) !== null;
|
|
16652
|
+
return resolveMassuRuntimeCli(version, home) !== null;
|
|
16646
16653
|
}
|
|
16647
|
-
function massuShimPath() {
|
|
16648
|
-
return resolve9(
|
|
16654
|
+
function massuShimPath(home = homedir7()) {
|
|
16655
|
+
return resolve9(home, ".massu", "bin", "massu-hook");
|
|
16649
16656
|
}
|
|
16650
16657
|
function massuShimBody() {
|
|
16651
16658
|
return `#!/bin/sh
|
|
@@ -16670,10 +16677,10 @@ fi
|
|
|
16670
16677
|
exec npx -y "@massu/core@\${MASSU_VERSION}" "$@"
|
|
16671
16678
|
`;
|
|
16672
16679
|
}
|
|
16673
|
-
function installMassuShim() {
|
|
16680
|
+
function installMassuShim(home = homedir7()) {
|
|
16674
16681
|
if (process.env.MASSU_NO_NODE_DIRECT === "1") return false;
|
|
16675
16682
|
if (process.platform === "win32") return false;
|
|
16676
|
-
const shim = massuShimPath();
|
|
16683
|
+
const shim = massuShimPath(home);
|
|
16677
16684
|
try {
|
|
16678
16685
|
mkdirSync10(dirname12(shim), { recursive: true });
|
|
16679
16686
|
writeFileSync5(shim, massuShimBody(), "utf-8");
|
|
@@ -16689,10 +16696,10 @@ function installMassuShim() {
|
|
|
16689
16696
|
return status === 2;
|
|
16690
16697
|
}
|
|
16691
16698
|
}
|
|
16692
|
-
function resolveMassuShim() {
|
|
16699
|
+
function resolveMassuShim(home = homedir7()) {
|
|
16693
16700
|
if (process.env.MASSU_NO_NODE_DIRECT === "1") return null;
|
|
16694
16701
|
if (process.platform === "win32") return null;
|
|
16695
|
-
const shim = massuShimPath();
|
|
16702
|
+
const shim = massuShimPath(home);
|
|
16696
16703
|
if (!existsSync19(shim)) return null;
|
|
16697
16704
|
try {
|
|
16698
16705
|
execFileSync2(shim, [], { stdio: "ignore", timeout: 1e4 });
|
|
@@ -16708,9 +16715,8 @@ function hookCmd(version, hookName, shim) {
|
|
|
16708
16715
|
function getHookTimeout(name) {
|
|
16709
16716
|
return HOOK_TIMEOUTS[name] ?? 5;
|
|
16710
16717
|
}
|
|
16711
|
-
function buildHooksConfig(_hooksDir) {
|
|
16718
|
+
function buildHooksConfig(_hooksDir, shim = resolveMassuShim()) {
|
|
16712
16719
|
const version = getInstallerVersion();
|
|
16713
|
-
const shim = resolveMassuShim();
|
|
16714
16720
|
return {
|
|
16715
16721
|
SessionStart: [
|
|
16716
16722
|
{
|
|
@@ -18167,7 +18173,7 @@ function checkHookFiles(projectRoot) {
|
|
|
18167
18173
|
}
|
|
18168
18174
|
async function checkHookExecution(projectRoot, opts = {}) {
|
|
18169
18175
|
const { spawnSync: spawnSync6 } = await import("child_process");
|
|
18170
|
-
const { mkdtempSync: mkdtempSync2, copyFileSync: copyFileSync4, rmSync:
|
|
18176
|
+
const { mkdtempSync: mkdtempSync2, copyFileSync: copyFileSync4, rmSync: rmSync13 } = await import("fs");
|
|
18171
18177
|
const { tmpdir: tmpdir2 } = await import("os");
|
|
18172
18178
|
const node = opts.node ?? process.execPath;
|
|
18173
18179
|
const timeoutMs = opts.timeoutMs ?? 1e4;
|
|
@@ -18221,7 +18227,7 @@ async function checkHookExecution(projectRoot, opts = {}) {
|
|
|
18221
18227
|
};
|
|
18222
18228
|
} finally {
|
|
18223
18229
|
try {
|
|
18224
|
-
|
|
18230
|
+
rmSync13(tmpCwd, { recursive: true, force: true });
|
|
18225
18231
|
} catch {
|
|
18226
18232
|
}
|
|
18227
18233
|
}
|
|
@@ -20442,8 +20448,8 @@ function renderRegion(content, lines) {
|
|
|
20442
20448
|
${lines.join("\n")}
|
|
20443
20449
|
` : "\n";
|
|
20444
20450
|
if (state.kind === "absent") {
|
|
20445
|
-
const
|
|
20446
|
-
return `${content}${
|
|
20451
|
+
const sep4 = content.endsWith("\n") ? "" : "\n";
|
|
20452
|
+
return `${content}${sep4}
|
|
20447
20453
|
${BEGIN_SENTINEL}${body}${END_SENTINEL}
|
|
20448
20454
|
`;
|
|
20449
20455
|
}
|
|
@@ -22909,8 +22915,8 @@ function writeCustomDestination(opts, candidate, slug, targets) {
|
|
|
22909
22915
|
const rendered = renderTemplate2(entry.template, vars);
|
|
22910
22916
|
if (!existsSync38(dirname19(destPath))) mkdirSync17(dirname19(destPath), { recursive: true });
|
|
22911
22917
|
const pre = existsSync38(destPath) ? readFileSync29(destPath, "utf-8") : "";
|
|
22912
|
-
const
|
|
22913
|
-
writeFileSync11(destPath, pre +
|
|
22918
|
+
const sep4 = pre && !pre.endsWith("\n") ? "\n" : "";
|
|
22919
|
+
writeFileSync11(destPath, pre + sep4 + rendered + (rendered.endsWith("\n") ? "" : "\n"), "utf-8");
|
|
22914
22920
|
}
|
|
22915
22921
|
function dismissRuleCandidate(db, opts) {
|
|
22916
22922
|
if (!CANDIDATE_ID_PATTERN.test(opts.candidateId)) {
|
|
@@ -22963,8 +22969,8 @@ function dismissRuleCandidate(db, opts) {
|
|
|
22963
22969
|
const dismissedLog = join24(projectRoot, ".massu", "rule-candidates", ".dismissed.jsonl");
|
|
22964
22970
|
if (!existsSync38(dirname19(dismissedLog))) mkdirSync17(dirname19(dismissedLog), { recursive: true });
|
|
22965
22971
|
const pre = existsSync38(dismissedLog) ? readFileSync29(dismissedLog, "utf-8") : "";
|
|
22966
|
-
const
|
|
22967
|
-
writeFileSync11(dismissedLog, pre +
|
|
22972
|
+
const sep4 = pre && !pre.endsWith("\n") ? "\n" : "";
|
|
22973
|
+
writeFileSync11(dismissedLog, pre + sep4 + JSON.stringify({
|
|
22968
22974
|
id: opts.candidateId,
|
|
22969
22975
|
prompt_hash: candidate.prompt_hash,
|
|
22970
22976
|
score: candidate.score,
|
|
@@ -22995,8 +23001,8 @@ function appendFailureLog(projectRoot, entry) {
|
|
|
22995
23001
|
if (!existsSync38(dir)) mkdirSync17(dir, { recursive: true });
|
|
22996
23002
|
const logPath = join24(dir, ".failures.jsonl");
|
|
22997
23003
|
const pre = existsSync38(logPath) ? readFileSync29(logPath, "utf-8") : "";
|
|
22998
|
-
const
|
|
22999
|
-
writeFileSync11(logPath, pre +
|
|
23004
|
+
const sep4 = pre && !pre.endsWith("\n") ? "\n" : "";
|
|
23005
|
+
writeFileSync11(logPath, pre + sep4 + JSON.stringify(entry) + "\n", "utf-8");
|
|
23000
23006
|
} catch {
|
|
23001
23007
|
}
|
|
23002
23008
|
}
|
|
@@ -25381,12 +25387,102 @@ var init_gitToplevel = __esm({
|
|
|
25381
25387
|
}
|
|
25382
25388
|
});
|
|
25383
25389
|
|
|
25390
|
+
// src/watch/canary.ts
|
|
25391
|
+
import { mkdirSync as mkdirSync20, rmSync as rmSync10, writeFileSync as writeFileSync15 } from "fs";
|
|
25392
|
+
import { isAbsolute as isAbsolute3, relative as relative7, resolve as resolve20, sep as sep2 } from "path";
|
|
25393
|
+
function toRelative(projectRoot, p19) {
|
|
25394
|
+
const raw = String(p19);
|
|
25395
|
+
const rel = isAbsolute3(raw) ? relative7(projectRoot, raw) : raw;
|
|
25396
|
+
return rel.split(sep2).join("/");
|
|
25397
|
+
}
|
|
25398
|
+
function isCanaryPath(projectRoot, p19) {
|
|
25399
|
+
const rel = toRelative(projectRoot, p19);
|
|
25400
|
+
return rel === CANARY_DIR_REL || rel.startsWith(`${CANARY_DIR_REL}/`);
|
|
25401
|
+
}
|
|
25402
|
+
function canaryAwareIgnore(ignore, projectRoot) {
|
|
25403
|
+
const withoutMassu = ignore.filter((g2) => g2 !== "**/.massu/**");
|
|
25404
|
+
const massuButNotCanary = (p19) => {
|
|
25405
|
+
if (isCanaryPath(projectRoot, p19)) return false;
|
|
25406
|
+
const rel = toRelative(projectRoot, p19);
|
|
25407
|
+
return rel === ".massu" || rel.startsWith(".massu/") || rel.includes("/.massu/");
|
|
25408
|
+
};
|
|
25409
|
+
return [...withoutMassu, massuButNotCanary];
|
|
25410
|
+
}
|
|
25411
|
+
function createWatcherCanary(opts) {
|
|
25412
|
+
const projectRoot = resolve20(opts.projectRoot);
|
|
25413
|
+
const now = opts.now ?? Date.now;
|
|
25414
|
+
const filePath = resolve20(projectRoot, CANARY_FILE_REL);
|
|
25415
|
+
let outstanding = false;
|
|
25416
|
+
let echoed = false;
|
|
25417
|
+
let consecutiveDead = 0;
|
|
25418
|
+
let armedAt = 0;
|
|
25419
|
+
return {
|
|
25420
|
+
dirRel: CANARY_DIR_REL,
|
|
25421
|
+
filePath,
|
|
25422
|
+
get consecutiveDead() {
|
|
25423
|
+
return consecutiveDead;
|
|
25424
|
+
},
|
|
25425
|
+
arm() {
|
|
25426
|
+
if (outstanding) return "armed";
|
|
25427
|
+
try {
|
|
25428
|
+
mkdirSync20(resolve20(projectRoot, CANARY_DIR_REL), { recursive: true });
|
|
25429
|
+
writeFileSync15(filePath, `${now()}
|
|
25430
|
+
`, "utf-8");
|
|
25431
|
+
} catch {
|
|
25432
|
+
outstanding = false;
|
|
25433
|
+
echoed = false;
|
|
25434
|
+
return "unwritable";
|
|
25435
|
+
}
|
|
25436
|
+
outstanding = true;
|
|
25437
|
+
echoed = false;
|
|
25438
|
+
armedAt = now();
|
|
25439
|
+
return "armed";
|
|
25440
|
+
},
|
|
25441
|
+
observe(path) {
|
|
25442
|
+
if (!isCanaryPath(projectRoot, path)) return false;
|
|
25443
|
+
if (outstanding) echoed = true;
|
|
25444
|
+
return true;
|
|
25445
|
+
},
|
|
25446
|
+
evaluate() {
|
|
25447
|
+
if (!outstanding) return "idle";
|
|
25448
|
+
if (now() - armedAt < CANARY_MIN_GRACE_MS) return "idle";
|
|
25449
|
+
outstanding = false;
|
|
25450
|
+
if (echoed) {
|
|
25451
|
+
consecutiveDead = 0;
|
|
25452
|
+
return "alive";
|
|
25453
|
+
}
|
|
25454
|
+
consecutiveDead += 1;
|
|
25455
|
+
return "dead";
|
|
25456
|
+
},
|
|
25457
|
+
cleanup() {
|
|
25458
|
+
try {
|
|
25459
|
+
rmSync10(filePath, { force: true });
|
|
25460
|
+
} catch {
|
|
25461
|
+
}
|
|
25462
|
+
}
|
|
25463
|
+
};
|
|
25464
|
+
}
|
|
25465
|
+
var CANARY_DIR_REL, CANARY_FILE_REL, CANARY_DEAD_STRIKES_BEFORE_REBUILD, CANARY_MIN_GRACE_MS, CANARY_DEAD_LOG, CANARY_REBUILD_LOG, CANARY_UNWRITABLE_LOG, CANARY_RECOVERED_LOG;
|
|
25466
|
+
var init_canary = __esm({
|
|
25467
|
+
"src/watch/canary.ts"() {
|
|
25468
|
+
"use strict";
|
|
25469
|
+
CANARY_DIR_REL = ".massu/watch-canary";
|
|
25470
|
+
CANARY_FILE_REL = `${CANARY_DIR_REL}/liveness`;
|
|
25471
|
+
CANARY_DEAD_STRIKES_BEFORE_REBUILD = 2;
|
|
25472
|
+
CANARY_MIN_GRACE_MS = 2500;
|
|
25473
|
+
CANARY_DEAD_LOG = "[massu] watcher liveness canary NOT echoed";
|
|
25474
|
+
CANARY_REBUILD_LOG = "[massu] rebuilding file watcher";
|
|
25475
|
+
CANARY_UNWRITABLE_LOG = "[massu] watcher liveness canary could not be written";
|
|
25476
|
+
CANARY_RECOVERED_LOG = "[massu] file watcher recovered";
|
|
25477
|
+
}
|
|
25478
|
+
});
|
|
25479
|
+
|
|
25384
25480
|
// src/watch/lockfile-detector.ts
|
|
25385
25481
|
import { existsSync as existsSync45, statSync as statSync15 } from "fs";
|
|
25386
|
-
import { resolve as
|
|
25482
|
+
import { resolve as resolve21 } from "path";
|
|
25387
25483
|
function lockfileMidWrite(projectRoot, now = Date.now(), windowMs = LOCKFILE_WINDOW_MS) {
|
|
25388
25484
|
for (const lf of KNOWN_LOCKFILES) {
|
|
25389
|
-
const p19 =
|
|
25485
|
+
const p19 = resolve21(projectRoot, lf);
|
|
25390
25486
|
if (!existsSync45(p19)) continue;
|
|
25391
25487
|
try {
|
|
25392
25488
|
const stat = statSync15(p19);
|
|
@@ -25400,7 +25496,7 @@ function lockfileMidWrite(projectRoot, now = Date.now(), windowMs = LOCKFILE_WIN
|
|
|
25400
25496
|
function gitMidOperation(projectRoot) {
|
|
25401
25497
|
const sentinels = ["MERGE_HEAD", "REBASE_HEAD", "CHERRY_PICK_HEAD", "rebase-apply", "rebase-merge"];
|
|
25402
25498
|
for (const s of sentinels) {
|
|
25403
|
-
if (existsSync45(
|
|
25499
|
+
if (existsSync45(resolve21(projectRoot, ".git", s))) return true;
|
|
25404
25500
|
}
|
|
25405
25501
|
return false;
|
|
25406
25502
|
}
|
|
@@ -25599,13 +25695,13 @@ var init_paths = __esm({
|
|
|
25599
25695
|
});
|
|
25600
25696
|
|
|
25601
25697
|
// src/watch/state.ts
|
|
25602
|
-
import { closeSync as closeSync5, existsSync as existsSync46, fsyncSync as fsyncSync5, mkdirSync as
|
|
25603
|
-
import { dirname as dirname21, resolve as
|
|
25698
|
+
import { closeSync as closeSync5, existsSync as existsSync46, fsyncSync as fsyncSync5, mkdirSync as mkdirSync21, openSync as openSync5, readFileSync as readFileSync34, renameSync as renameSync5, rmSync as rmSync11, writeFileSync as writeFileSync16, writeSync as writeSync3 } from "fs";
|
|
25699
|
+
import { dirname as dirname21, resolve as resolve22 } from "path";
|
|
25604
25700
|
function watchStatePath(projectRoot) {
|
|
25605
|
-
return
|
|
25701
|
+
return resolve22(projectRoot, ".massu", "watch-state.json");
|
|
25606
25702
|
}
|
|
25607
25703
|
function backupStatePath(projectRoot) {
|
|
25608
|
-
return
|
|
25704
|
+
return resolve22(projectRoot, ".massu", "watch-state.v0.bak.json");
|
|
25609
25705
|
}
|
|
25610
25706
|
function readState(projectRoot) {
|
|
25611
25707
|
const path = watchStatePath(projectRoot);
|
|
@@ -25652,14 +25748,14 @@ function readState(projectRoot) {
|
|
|
25652
25748
|
}
|
|
25653
25749
|
function archiveCorrupt(projectRoot, content) {
|
|
25654
25750
|
const bak = backupStatePath(projectRoot);
|
|
25655
|
-
|
|
25656
|
-
|
|
25751
|
+
mkdirSync21(dirname21(bak), { recursive: true });
|
|
25752
|
+
writeFileSync16(bak, content, "utf-8");
|
|
25657
25753
|
}
|
|
25658
25754
|
function writeStateAtomic(projectRoot, state) {
|
|
25659
25755
|
const path = watchStatePath(projectRoot);
|
|
25660
25756
|
writeStateAtomicCounter = writeStateAtomicCounter + 1 >>> 0;
|
|
25661
25757
|
const tmp = `${path}.${process.pid}.${writeStateAtomicCounter}.tmp`;
|
|
25662
|
-
|
|
25758
|
+
mkdirSync21(dirname21(path), { recursive: true });
|
|
25663
25759
|
let renamed = false;
|
|
25664
25760
|
try {
|
|
25665
25761
|
const fd = openSync5(tmp, "w");
|
|
@@ -25675,7 +25771,7 @@ function writeStateAtomic(projectRoot, state) {
|
|
|
25675
25771
|
} finally {
|
|
25676
25772
|
if (!renamed && existsSync46(tmp)) {
|
|
25677
25773
|
try {
|
|
25678
|
-
|
|
25774
|
+
rmSync11(tmp, { force: true });
|
|
25679
25775
|
} catch {
|
|
25680
25776
|
}
|
|
25681
25777
|
}
|
|
@@ -25718,6 +25814,8 @@ var init_state = __esm({
|
|
|
25718
25814
|
|
|
25719
25815
|
// src/watch/daemon.ts
|
|
25720
25816
|
import * as chokidar from "chokidar";
|
|
25817
|
+
import { mkdirSync as mkdirSync22 } from "fs";
|
|
25818
|
+
import { resolve as resolve23 } from "path";
|
|
25721
25819
|
function readDaemonConfig(projectRoot) {
|
|
25722
25820
|
const cfg = getConfig();
|
|
25723
25821
|
const w2 = cfg.watch ?? {};
|
|
@@ -25751,6 +25849,10 @@ async function startDaemon(projectRoot, hooks) {
|
|
|
25751
25849
|
let tickTimer = null;
|
|
25752
25850
|
let stopped = false;
|
|
25753
25851
|
let runningRefresh = false;
|
|
25852
|
+
let canary = null;
|
|
25853
|
+
let watchSpec = null;
|
|
25854
|
+
let rebuilding = false;
|
|
25855
|
+
let watcherReady = false;
|
|
25754
25856
|
function clearDebounce() {
|
|
25755
25857
|
if (ctx.debounceTimer) {
|
|
25756
25858
|
clearTimeout(ctx.debounceTimer);
|
|
@@ -25857,6 +25959,110 @@ async function startDaemon(projectRoot, hooks) {
|
|
|
25857
25959
|
await watcher.close();
|
|
25858
25960
|
watcher = null;
|
|
25859
25961
|
}
|
|
25962
|
+
if (canary) {
|
|
25963
|
+
canary.cleanup();
|
|
25964
|
+
canary = null;
|
|
25965
|
+
}
|
|
25966
|
+
}
|
|
25967
|
+
function createWatcherInstance() {
|
|
25968
|
+
const spec = watchSpec;
|
|
25969
|
+
if (!spec) throw new Error("watch spec not derived before createWatcherInstance()");
|
|
25970
|
+
const w2 = chokidar.watch(spec.watch, {
|
|
25971
|
+
cwd: cfg.projectRoot,
|
|
25972
|
+
ignored: spec.ignored,
|
|
25973
|
+
ignoreInitial: true,
|
|
25974
|
+
persistent: true,
|
|
25975
|
+
awaitWriteFinish: false
|
|
25976
|
+
});
|
|
25977
|
+
w2.on("ready", () => {
|
|
25978
|
+
watcherReady = true;
|
|
25979
|
+
});
|
|
25980
|
+
w2.on("all", (event, path) => {
|
|
25981
|
+
if (canary?.observe(path)) return;
|
|
25982
|
+
if (!STACK_RELEVANT_EVENTS.has(event)) return;
|
|
25983
|
+
pushEvent(path);
|
|
25984
|
+
});
|
|
25985
|
+
w2.on("error", (err) => {
|
|
25986
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
25987
|
+
writeStderr(`[massu] chokidar error: ${msg}
|
|
25988
|
+
`);
|
|
25989
|
+
try {
|
|
25990
|
+
updateState(cfg.projectRoot, { lastError: `chokidar: ${msg}` });
|
|
25991
|
+
} catch {
|
|
25992
|
+
}
|
|
25993
|
+
});
|
|
25994
|
+
return w2;
|
|
25995
|
+
}
|
|
25996
|
+
function armCanary() {
|
|
25997
|
+
if (!canary || stopped) return;
|
|
25998
|
+
if (canary.arm() === "unwritable") {
|
|
25999
|
+
writeStderr(
|
|
26000
|
+
`${CANARY_UNWRITABLE_LOG} (${canary.filePath}); watcher liveness is UNKNOWN for this interval
|
|
26001
|
+
`
|
|
26002
|
+
);
|
|
26003
|
+
}
|
|
26004
|
+
}
|
|
26005
|
+
function isPowerOfTwo(n) {
|
|
26006
|
+
return n > 0 && (n & n - 1) === 0;
|
|
26007
|
+
}
|
|
26008
|
+
async function rebuildWatcher() {
|
|
26009
|
+
if (rebuilding || stopped || !watchSpec) return;
|
|
26010
|
+
rebuilding = true;
|
|
26011
|
+
try {
|
|
26012
|
+
const old = watcher;
|
|
26013
|
+
watcher = null;
|
|
26014
|
+
if (old) {
|
|
26015
|
+
try {
|
|
26016
|
+
await old.close();
|
|
26017
|
+
} catch {
|
|
26018
|
+
}
|
|
26019
|
+
}
|
|
26020
|
+
if (stopped) return;
|
|
26021
|
+
watcherReady = false;
|
|
26022
|
+
watcher = createWatcherInstance();
|
|
26023
|
+
} catch (err) {
|
|
26024
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
26025
|
+
writeStderr(`[massu] watcher rebuild FAILED: ${msg}
|
|
26026
|
+
`);
|
|
26027
|
+
} finally {
|
|
26028
|
+
rebuilding = false;
|
|
26029
|
+
}
|
|
26030
|
+
}
|
|
26031
|
+
function checkWatcherLiveness() {
|
|
26032
|
+
if (!canary || !watcher || rebuilding || !watcherReady) return;
|
|
26033
|
+
const priorDead = canary.consecutiveDead;
|
|
26034
|
+
const verdict = canary.evaluate();
|
|
26035
|
+
if (verdict === "dead") {
|
|
26036
|
+
const streak = canary.consecutiveDead;
|
|
26037
|
+
if (!isPowerOfTwo(streak)) return armCanary();
|
|
26038
|
+
writeStderr(
|
|
26039
|
+
`${CANARY_DEAD_LOG} after ${streak} consecutive interval(s): the watcher reported ready and emitted no error, but did not deliver its own canary write (${canary.filePath}). Treating it as DEAD and reconciling so changes are not silently missed.
|
|
26040
|
+
`
|
|
26041
|
+
);
|
|
26042
|
+
try {
|
|
26043
|
+
updateState(cfg.projectRoot, {
|
|
26044
|
+
lastError: `watcher liveness canary not echoed for ${streak} consecutive interval(s)`
|
|
26045
|
+
});
|
|
26046
|
+
} catch {
|
|
26047
|
+
}
|
|
26048
|
+
void forceReconciliation();
|
|
26049
|
+
if (streak >= CANARY_DEAD_STRIKES_BEFORE_REBUILD) {
|
|
26050
|
+
writeStderr(`${CANARY_REBUILD_LOG} after ${streak} dead interval(s) (close + re-watch)
|
|
26051
|
+
`);
|
|
26052
|
+
void rebuildWatcher();
|
|
26053
|
+
return;
|
|
26054
|
+
}
|
|
26055
|
+
return armCanary();
|
|
26056
|
+
}
|
|
26057
|
+
if (verdict === "alive" && priorDead > 0) {
|
|
26058
|
+
writeStderr(`${CANARY_RECOVERED_LOG} after ${priorDead} dead interval(s)
|
|
26059
|
+
`);
|
|
26060
|
+
try {
|
|
26061
|
+
updateState(cfg.projectRoot, { lastError: null });
|
|
26062
|
+
} catch {
|
|
26063
|
+
}
|
|
26064
|
+
}
|
|
26065
|
+
armCanary();
|
|
25860
26066
|
}
|
|
25861
26067
|
function tick() {
|
|
25862
26068
|
if (stopped) return;
|
|
@@ -25873,6 +26079,7 @@ async function startDaemon(projectRoot, hooks) {
|
|
|
25873
26079
|
`);
|
|
25874
26080
|
void forceReconciliation();
|
|
25875
26081
|
}
|
|
26082
|
+
checkWatcherLiveness();
|
|
25876
26083
|
}
|
|
25877
26084
|
if (!hooks.noWatcher) {
|
|
25878
26085
|
const cfgYaml = getConfig();
|
|
@@ -25897,23 +26104,16 @@ async function startDaemon(projectRoot, hooks) {
|
|
|
25897
26104
|
`[massu] watch surface: ${countLabel} files (cap ${cap}, opted-in: ${optedIn}, scan ${surfaceMs}ms, scope: ${globs.effectiveScope})
|
|
25898
26105
|
`
|
|
25899
26106
|
);
|
|
25900
|
-
|
|
25901
|
-
|
|
25902
|
-
|
|
25903
|
-
|
|
25904
|
-
|
|
25905
|
-
|
|
25906
|
-
|
|
25907
|
-
|
|
25908
|
-
|
|
25909
|
-
|
|
25910
|
-
writeStderr(`[massu] chokidar error: ${msg}
|
|
25911
|
-
`);
|
|
25912
|
-
try {
|
|
25913
|
-
updateState(cfg.projectRoot, { lastError: `chokidar: ${msg}` });
|
|
25914
|
-
} catch {
|
|
25915
|
-
}
|
|
25916
|
-
});
|
|
26107
|
+
canary = createWatcherCanary({ projectRoot: cfg.projectRoot, now });
|
|
26108
|
+
try {
|
|
26109
|
+
mkdirSync22(resolve23(cfg.projectRoot, canary.dirRel), { recursive: true });
|
|
26110
|
+
} catch {
|
|
26111
|
+
}
|
|
26112
|
+
watchSpec = {
|
|
26113
|
+
watch: [...globs.watch, canary.dirRel],
|
|
26114
|
+
ignored: canaryAwareIgnore(globs.ignore, cfg.projectRoot)
|
|
26115
|
+
};
|
|
26116
|
+
watcher = createWatcherInstance();
|
|
25917
26117
|
}
|
|
25918
26118
|
resetConfig();
|
|
25919
26119
|
try {
|
|
@@ -25925,15 +26125,16 @@ async function startDaemon(projectRoot, hooks) {
|
|
|
25925
26125
|
});
|
|
25926
26126
|
} catch {
|
|
25927
26127
|
}
|
|
25928
|
-
tickTimer = setInterval(tick, TICK_INTERVAL_MS);
|
|
26128
|
+
tickTimer = setInterval(tick, hooks.tickIntervalMs ?? TICK_INTERVAL_MS);
|
|
25929
26129
|
if (typeof tickTimer.unref === "function") tickTimer.unref();
|
|
25930
26130
|
return { pushEvent, flushNow, stop, forceReconciliation };
|
|
25931
26131
|
}
|
|
25932
|
-
var STORM_WINDOW_MS, DEEP_STORM_WINDOW_MS, STORM_WAIT_MS, DEEP_STORM_WAIT_MS, TICK_INTERVAL_MS, TICK_GAP_THRESHOLD_MS;
|
|
26132
|
+
var STORM_WINDOW_MS, DEEP_STORM_WINDOW_MS, STORM_WAIT_MS, DEEP_STORM_WAIT_MS, TICK_INTERVAL_MS, TICK_GAP_THRESHOLD_MS, STACK_RELEVANT_EVENTS;
|
|
25933
26133
|
var init_daemon = __esm({
|
|
25934
26134
|
"src/watch/daemon.ts"() {
|
|
25935
26135
|
"use strict";
|
|
25936
26136
|
init_config();
|
|
26137
|
+
init_canary();
|
|
25937
26138
|
init_lockfile_detector();
|
|
25938
26139
|
init_paths();
|
|
25939
26140
|
init_state();
|
|
@@ -25943,6 +26144,7 @@ var init_daemon = __esm({
|
|
|
25943
26144
|
DEEP_STORM_WAIT_MS = 12e4;
|
|
25944
26145
|
TICK_INTERVAL_MS = 1e4;
|
|
25945
26146
|
TICK_GAP_THRESHOLD_MS = 3e4;
|
|
26147
|
+
STACK_RELEVANT_EVENTS = /* @__PURE__ */ new Set(["add", "change", "unlink"]);
|
|
25946
26148
|
}
|
|
25947
26149
|
});
|
|
25948
26150
|
|
|
@@ -25955,8 +26157,8 @@ __export(watch_exports, {
|
|
|
25955
26157
|
runWatch: () => runWatch
|
|
25956
26158
|
});
|
|
25957
26159
|
import { spawnSync as spawnSync5 } from "child_process";
|
|
25958
|
-
import { basename as basename8, dirname as dirname22, resolve as
|
|
25959
|
-
import { appendFileSync as appendFileSync4, existsSync as existsSync47, mkdirSync as
|
|
26160
|
+
import { basename as basename8, dirname as dirname22, resolve as resolve24 } from "path";
|
|
26161
|
+
import { appendFileSync as appendFileSync4, existsSync as existsSync47, mkdirSync as mkdirSync23, readFileSync as readFileSync35 } from "fs";
|
|
25960
26162
|
function parseFlags(args2) {
|
|
25961
26163
|
const out = {
|
|
25962
26164
|
foreground: false,
|
|
@@ -25981,7 +26183,7 @@ function parseFlags(args2) {
|
|
|
25981
26183
|
}
|
|
25982
26184
|
function findClaudeBg() {
|
|
25983
26185
|
const home = process.env.HOME ?? "";
|
|
25984
|
-
const fixed = home ?
|
|
26186
|
+
const fixed = home ? resolve24(home, ".claude", "bin", "claude-bg") : null;
|
|
25985
26187
|
if (fixed && existsSync47(fixed)) return fixed;
|
|
25986
26188
|
const which = spawnSync5("which", ["claude-bg"], { encoding: "utf-8" });
|
|
25987
26189
|
if (which.status === 0 && which.stdout) {
|
|
@@ -26125,7 +26327,7 @@ async function runForeground(root) {
|
|
|
26125
26327
|
}
|
|
26126
26328
|
throw err;
|
|
26127
26329
|
}
|
|
26128
|
-
return new Promise((
|
|
26330
|
+
return new Promise((resolve47) => {
|
|
26129
26331
|
const shutdown = async () => {
|
|
26130
26332
|
if (stopped) return;
|
|
26131
26333
|
stopped = true;
|
|
@@ -26135,7 +26337,7 @@ async function runForeground(root) {
|
|
|
26135
26337
|
process.chdir(priorCwd);
|
|
26136
26338
|
} catch {
|
|
26137
26339
|
}
|
|
26138
|
-
|
|
26340
|
+
resolve47({ exitCode: 0 });
|
|
26139
26341
|
};
|
|
26140
26342
|
process.on("SIGINT", () => {
|
|
26141
26343
|
void shutdown();
|
|
@@ -26196,12 +26398,12 @@ async function runOnQuiescent(projectRoot) {
|
|
|
26196
26398
|
);
|
|
26197
26399
|
}
|
|
26198
26400
|
function refreshLogPath(projectRoot) {
|
|
26199
|
-
return
|
|
26401
|
+
return resolve24(projectRoot, ".massu", "refresh-log.jsonl");
|
|
26200
26402
|
}
|
|
26201
26403
|
function appendRefreshLog(projectRoot, event) {
|
|
26202
26404
|
const path = refreshLogPath(projectRoot);
|
|
26203
26405
|
try {
|
|
26204
|
-
|
|
26406
|
+
mkdirSync23(dirname22(path), { recursive: true });
|
|
26205
26407
|
appendFileSync4(path, JSON.stringify(event) + "\n", "utf-8");
|
|
26206
26408
|
} catch {
|
|
26207
26409
|
}
|
|
@@ -26287,10 +26489,10 @@ import {
|
|
|
26287
26489
|
closeSync as closeSync6,
|
|
26288
26490
|
existsSync as existsSync48,
|
|
26289
26491
|
fsyncSync as fsyncSync6,
|
|
26290
|
-
mkdirSync as
|
|
26492
|
+
mkdirSync as mkdirSync24,
|
|
26291
26493
|
openSync as openSync6,
|
|
26292
26494
|
renameSync as renameSync6,
|
|
26293
|
-
rmSync as
|
|
26495
|
+
rmSync as rmSync12,
|
|
26294
26496
|
statSync as statSync16,
|
|
26295
26497
|
writeSync as writeSync4
|
|
26296
26498
|
} from "node:fs";
|
|
@@ -26304,7 +26506,7 @@ function atomicWrite(path, content, opts = {}) {
|
|
|
26304
26506
|
if (opts.ensureParentDirMode !== void 0) {
|
|
26305
26507
|
mkdirOpts.mode = opts.ensureParentDirMode;
|
|
26306
26508
|
}
|
|
26307
|
-
|
|
26509
|
+
mkdirSync24(parentDir, mkdirOpts);
|
|
26308
26510
|
}
|
|
26309
26511
|
const buf = typeof content === "string" ? Buffer.from(content, "utf-8") : content;
|
|
26310
26512
|
const openMode = opts.mode ?? 420;
|
|
@@ -26323,7 +26525,7 @@ function atomicWrite(path, content, opts = {}) {
|
|
|
26323
26525
|
} catch (err) {
|
|
26324
26526
|
if (existsSync48(tmpPath)) {
|
|
26325
26527
|
try {
|
|
26326
|
-
|
|
26528
|
+
rmSync12(tmpPath, { force: true });
|
|
26327
26529
|
} catch {
|
|
26328
26530
|
}
|
|
26329
26531
|
}
|
|
@@ -26672,13 +26874,13 @@ var init_fetcher = __esm({
|
|
|
26672
26874
|
// src/security/manifest-cache.ts
|
|
26673
26875
|
import { existsSync as existsSync49, readFileSync as readFileSync36, statSync as statSync17 } from "node:fs";
|
|
26674
26876
|
import { homedir as homedir21 } from "node:os";
|
|
26675
|
-
import { resolve as
|
|
26877
|
+
import { resolve as resolve25 } from "node:path";
|
|
26676
26878
|
import { z as z5 } from "zod";
|
|
26677
26879
|
function defaultCachePaths() {
|
|
26678
|
-
const dir =
|
|
26880
|
+
const dir = resolve25(homedir21(), ".massu");
|
|
26679
26881
|
return {
|
|
26680
|
-
cachePath:
|
|
26681
|
-
lockPath:
|
|
26882
|
+
cachePath: resolve25(dir, "adapter-manifest.json"),
|
|
26883
|
+
lockPath: resolve25(dir, ".adapter-manifest.lock")
|
|
26682
26884
|
};
|
|
26683
26885
|
}
|
|
26684
26886
|
function loadCachedManifest(paths = defaultCachePaths()) {
|
|
@@ -26878,13 +27080,13 @@ var init_adapter_origin = __esm({
|
|
|
26878
27080
|
// src/security/local-fingerprint.ts
|
|
26879
27081
|
import { existsSync as existsSync50, readFileSync as readFileSync37, lstatSync as lstatSync5 } from "node:fs";
|
|
26880
27082
|
import { homedir as homedir22 } from "node:os";
|
|
26881
|
-
import { resolve as
|
|
27083
|
+
import { resolve as resolve26, isAbsolute as isAbsolute4 } from "node:path";
|
|
26882
27084
|
import { createHash as createHash14 } from "node:crypto";
|
|
26883
27085
|
import { z as z6 } from "zod";
|
|
26884
27086
|
function computeLocalFingerprint(localPaths, projectRoot) {
|
|
26885
27087
|
const tuples = [];
|
|
26886
27088
|
for (const p19 of localPaths) {
|
|
26887
|
-
const abs =
|
|
27089
|
+
const abs = isAbsolute4(p19) ? p19 : resolve26(projectRoot, p19);
|
|
26888
27090
|
let contentTag;
|
|
26889
27091
|
try {
|
|
26890
27092
|
const lst = lstatSync5(abs);
|
|
@@ -26956,7 +27158,7 @@ var init_local_fingerprint = __esm({
|
|
|
26956
27158
|
"use strict";
|
|
26957
27159
|
init_atomic_write();
|
|
26958
27160
|
init_manifest_schema();
|
|
26959
|
-
FINGERPRINT_PATH =
|
|
27161
|
+
FINGERPRINT_PATH = resolve26(homedir22(), ".massu", "adapters-local-fingerprint.json");
|
|
26960
27162
|
FingerprintSentinelSchema = z6.object({
|
|
26961
27163
|
fingerprint: z6.string().regex(/^[0-9a-f]{64}$/),
|
|
26962
27164
|
source: z6.enum(["cli", "cli-resync"]),
|
|
@@ -26973,9 +27175,9 @@ var init_local_fingerprint = __esm({
|
|
|
26973
27175
|
|
|
26974
27176
|
// src/security/install-tracking.ts
|
|
26975
27177
|
import { readFileSync as readFileSync38, readdirSync as readdirSync17, lstatSync as lstatSync6, existsSync as existsSync51 } from "node:fs";
|
|
26976
|
-
import { join as join28, relative as
|
|
27178
|
+
import { join as join28, relative as relative8, sep as sep3 } from "node:path";
|
|
26977
27179
|
import { homedir as homedir23 } from "node:os";
|
|
26978
|
-
import { resolve as
|
|
27180
|
+
import { resolve as resolve27 } from "node:path";
|
|
26979
27181
|
import { createHash as createHash15 } from "node:crypto";
|
|
26980
27182
|
import { z as z7 } from "zod";
|
|
26981
27183
|
function containsHiddenDirs(packageDir) {
|
|
@@ -27018,7 +27220,7 @@ function sha256OfDir(dir, opts = {}) {
|
|
|
27018
27220
|
`sha256OfDir: file ${absPath} exceeds maxFileBytes (${lst.size} > ${maxFileBytes}); adapter packages should not ship files this large.`
|
|
27019
27221
|
);
|
|
27020
27222
|
}
|
|
27021
|
-
const rel =
|
|
27223
|
+
const rel = relative8(dir, absPath).split(sep3).join("/");
|
|
27022
27224
|
files.push({ relativePath: rel, absPath });
|
|
27023
27225
|
}
|
|
27024
27226
|
}
|
|
@@ -27102,7 +27304,7 @@ var init_install_tracking = __esm({
|
|
|
27102
27304
|
"src/security/install-tracking.ts"() {
|
|
27103
27305
|
"use strict";
|
|
27104
27306
|
init_atomic_write();
|
|
27105
|
-
INSTALLED_MANIFEST_PATH =
|
|
27307
|
+
INSTALLED_MANIFEST_PATH = resolve27(homedir23(), ".massu", "adapter-manifest-installed.json");
|
|
27106
27308
|
DEFAULT_MAX_FILE_BYTES = 64 * 1024 * 1024;
|
|
27107
27309
|
EXCLUDED_DIR_NAMES = /* @__PURE__ */ new Set([".git", "node_modules", ".cache", ".tmp"]);
|
|
27108
27310
|
InstallEntrySchema = z7.object({
|
|
@@ -27126,10 +27328,10 @@ var init_install_tracking = __esm({
|
|
|
27126
27328
|
|
|
27127
27329
|
// src/detect/adapters/discover.ts
|
|
27128
27330
|
import { existsSync as existsSync52, readdirSync as readdirSync18, readFileSync as readFileSync39, lstatSync as lstatSync7 } from "node:fs";
|
|
27129
|
-
import { resolve as
|
|
27331
|
+
import { resolve as resolve28, isAbsolute as isAbsolute5 } from "node:path";
|
|
27130
27332
|
import { z as z8 } from "zod";
|
|
27131
27333
|
function walkNodeModules(projectRoot, warnings) {
|
|
27132
|
-
const nodeModulesDir =
|
|
27334
|
+
const nodeModulesDir = resolve28(projectRoot, "node_modules");
|
|
27133
27335
|
if (!existsSync52(nodeModulesDir)) {
|
|
27134
27336
|
return [];
|
|
27135
27337
|
}
|
|
@@ -27143,7 +27345,7 @@ function walkNodeModules(projectRoot, warnings) {
|
|
|
27143
27345
|
}
|
|
27144
27346
|
for (const entry of topLevelEntries) {
|
|
27145
27347
|
if (entry.startsWith(".")) continue;
|
|
27146
|
-
const entryPath =
|
|
27348
|
+
const entryPath = resolve28(nodeModulesDir, entry);
|
|
27147
27349
|
let entryStat;
|
|
27148
27350
|
try {
|
|
27149
27351
|
entryStat = lstatSync7(entryPath);
|
|
@@ -27165,7 +27367,7 @@ function walkNodeModules(projectRoot, warnings) {
|
|
|
27165
27367
|
continue;
|
|
27166
27368
|
}
|
|
27167
27369
|
for (const sub of scopedEntries) {
|
|
27168
|
-
const subPath =
|
|
27370
|
+
const subPath = resolve28(entryPath, sub);
|
|
27169
27371
|
let subStat;
|
|
27170
27372
|
try {
|
|
27171
27373
|
subStat = lstatSync7(subPath);
|
|
@@ -27184,7 +27386,7 @@ function walkNodeModules(projectRoot, warnings) {
|
|
|
27184
27386
|
return candidates;
|
|
27185
27387
|
}
|
|
27186
27388
|
function tryReadAdapterPackage(packageDir, warnings) {
|
|
27187
|
-
const pkgJsonPath =
|
|
27389
|
+
const pkgJsonPath = resolve28(packageDir, "package.json");
|
|
27188
27390
|
if (!existsSync52(pkgJsonPath)) return null;
|
|
27189
27391
|
let raw;
|
|
27190
27392
|
try {
|
|
@@ -27322,7 +27524,7 @@ function discoverAdapters(opts) {
|
|
|
27322
27524
|
const localSet = new Set(opts.configLocalPaths);
|
|
27323
27525
|
for (const localPath of opts.configLocalPaths) {
|
|
27324
27526
|
if (seenIds.has(localPath)) continue;
|
|
27325
|
-
const absPath =
|
|
27527
|
+
const absPath = isAbsolute5(localPath) ? localPath : resolve28(opts.projectRoot, localPath);
|
|
27326
27528
|
if (!existsSync52(absPath)) {
|
|
27327
27529
|
warnings.push(
|
|
27328
27530
|
`local adapter file not found: ${localPath} (resolved to ${absPath}). Remove via: massu adapters remove-local ${localPath}`
|
|
@@ -27406,7 +27608,7 @@ __export(adapters_exports, {
|
|
|
27406
27608
|
runAdaptersSearch: () => runAdaptersSearch
|
|
27407
27609
|
});
|
|
27408
27610
|
import { existsSync as existsSync53, readFileSync as readFileSync40 } from "node:fs";
|
|
27409
|
-
import { resolve as
|
|
27611
|
+
import { resolve as resolve29 } from "node:path";
|
|
27410
27612
|
import { parseDocument } from "yaml";
|
|
27411
27613
|
async function handleAdaptersSubcommand(args2) {
|
|
27412
27614
|
const sub = args2[0];
|
|
@@ -27673,7 +27875,7 @@ function mutateLocalArray(mutator, command) {
|
|
|
27673
27875
|
);
|
|
27674
27876
|
return { exitCode: 2 };
|
|
27675
27877
|
}
|
|
27676
|
-
const yamlPath =
|
|
27878
|
+
const yamlPath = resolve29(projectRoot, "massu.config.yaml");
|
|
27677
27879
|
if (!existsSync53(yamlPath)) {
|
|
27678
27880
|
process.stderr.write(
|
|
27679
27881
|
`${command}: massu.config.yaml not found at ${yamlPath}. Run \`massu init\` first.
|
|
@@ -27704,7 +27906,7 @@ function mutateLocalArray(mutator, command) {
|
|
|
27704
27906
|
if (next === null) {
|
|
27705
27907
|
return { exitCode: 0 };
|
|
27706
27908
|
}
|
|
27707
|
-
const lockPath =
|
|
27909
|
+
const lockPath = resolve29(projectRoot, ".massu", "adapters-local-mutate.lock");
|
|
27708
27910
|
return withFileLockSync(lockPath, () => {
|
|
27709
27911
|
doc.setIn(["adapters", "local"], next);
|
|
27710
27912
|
const newYaml = doc.toString();
|
|
@@ -27773,7 +27975,7 @@ async function runAdaptersInstall(args2) {
|
|
|
27773
27975
|
`);
|
|
27774
27976
|
return { exitCode: 1 };
|
|
27775
27977
|
}
|
|
27776
|
-
const packageDir =
|
|
27978
|
+
const packageDir = resolve29(projectRoot, "node_modules", ...packageName.split("/"));
|
|
27777
27979
|
if (!existsSync53(packageDir)) {
|
|
27778
27980
|
process.stderr.write(
|
|
27779
27981
|
`install: ${packageName} is not installed in node_modules. Run \`npm install ${packageName}\` first.
|
|
@@ -27781,7 +27983,7 @@ async function runAdaptersInstall(args2) {
|
|
|
27781
27983
|
);
|
|
27782
27984
|
return { exitCode: 1 };
|
|
27783
27985
|
}
|
|
27784
|
-
const pkgJsonPath =
|
|
27986
|
+
const pkgJsonPath = resolve29(packageDir, "package.json");
|
|
27785
27987
|
if (!existsSync53(pkgJsonPath)) {
|
|
27786
27988
|
process.stderr.write(`install: ${packageName} has no package.json at ${pkgJsonPath}
|
|
27787
27989
|
`);
|
|
@@ -27908,7 +28110,7 @@ async function runAdaptersResign(_args) {
|
|
|
27908
28110
|
removeInstalledManifestEntry(name);
|
|
27909
28111
|
continue;
|
|
27910
28112
|
}
|
|
27911
|
-
const packageDir =
|
|
28113
|
+
const packageDir = resolve29(projectRoot, "node_modules", ...name.split("/"));
|
|
27912
28114
|
if (!existsSync53(packageDir)) {
|
|
27913
28115
|
removed++;
|
|
27914
28116
|
warnings.push(`${name}@${entry.version}: not present in node_modules \u2014 REMOVED from sidecar`);
|
|
@@ -28007,7 +28209,7 @@ var init_sql_table_names = __esm({
|
|
|
28007
28209
|
|
|
28008
28210
|
// src/db.ts
|
|
28009
28211
|
import { dirname as dirname24, join as join29 } from "path";
|
|
28010
|
-
import { existsSync as existsSync54, mkdirSync as
|
|
28212
|
+
import { existsSync as existsSync54, mkdirSync as mkdirSync25, readdirSync as readdirSync19, statSync as statSync18 } from "fs";
|
|
28011
28213
|
function getCodeGraphDb() {
|
|
28012
28214
|
const dbPath = getResolvedPaths().codegraphDbPath;
|
|
28013
28215
|
assertCodegraphUsable(dbPath);
|
|
@@ -28019,7 +28221,7 @@ function getDataDb() {
|
|
|
28019
28221
|
const dbPath = getResolvedPaths().dataDbPath;
|
|
28020
28222
|
const dir = dirname24(dbPath);
|
|
28021
28223
|
if (!existsSync54(dir)) {
|
|
28022
|
-
|
|
28224
|
+
mkdirSync25(dir, { recursive: true });
|
|
28023
28225
|
}
|
|
28024
28226
|
const db = openDatabase2(dbPath);
|
|
28025
28227
|
db.pragma("journal_mode = WAL");
|
|
@@ -28273,12 +28475,23 @@ function initDataSchema(db) {
|
|
|
28273
28475
|
END;
|
|
28274
28476
|
`);
|
|
28275
28477
|
}
|
|
28478
|
+
function codegraphIndexedAtToEpochMs(raw) {
|
|
28479
|
+
const ceiling = Date.now() + CODEGRAPH_TS_SKEW_MS;
|
|
28480
|
+
const asMs = raw;
|
|
28481
|
+
const asSeconds = raw * 1e3;
|
|
28482
|
+
if (asMs >= CODEGRAPH_TS_FLOOR_MS && asMs <= ceiling) return asMs;
|
|
28483
|
+
if (asSeconds >= CODEGRAPH_TS_FLOOR_MS && asSeconds <= ceiling) return asSeconds;
|
|
28484
|
+
const describe = (ms) => Number.isFinite(ms) && Math.abs(ms) <= 864e13 ? new Date(ms).toISOString() : "out of representable range";
|
|
28485
|
+
throw new Error(
|
|
28486
|
+
`CodeGraph files.indexed_at=${raw} is implausible as both milliseconds (${describe(asMs)}) and seconds (${describe(asSeconds)}). Expected a timestamp between ${new Date(CODEGRAPH_TS_FLOOR_MS).toISOString()} and now. The CodeGraph engine's timestamp format may have changed \u2014 do not guess the unit.`
|
|
28487
|
+
);
|
|
28488
|
+
}
|
|
28276
28489
|
function isDataStale(dataDb, codegraphDb) {
|
|
28277
28490
|
const lastBuild = dataDb.prepare(`SELECT value FROM ${t("meta")} WHERE key = 'last_build_time'`).get();
|
|
28278
28491
|
if (!lastBuild) return true;
|
|
28279
28492
|
const latestIndexed = codegraphDb.prepare("SELECT MAX(indexed_at) as latest FROM files").get();
|
|
28280
28493
|
if (!latestIndexed?.latest) return true;
|
|
28281
|
-
return latestIndexed.latest
|
|
28494
|
+
return codegraphIndexedAtToEpochMs(latestIndexed.latest) > new Date(lastBuild.value).getTime();
|
|
28282
28495
|
}
|
|
28283
28496
|
function updateBuildTimestamp(dataDb) {
|
|
28284
28497
|
dataDb.prepare(`INSERT OR REPLACE INTO ${t("meta")} (key, value) VALUES ('last_build_time', ?)`).run((/* @__PURE__ */ new Date()).toISOString());
|
|
@@ -28308,6 +28521,7 @@ function isPythonDataStale(dataDb, pythonRoot) {
|
|
|
28308
28521
|
function updatePythonBuildTimestamp(dataDb) {
|
|
28309
28522
|
dataDb.prepare(`INSERT OR REPLACE INTO ${t("py_meta")} (key, value) VALUES ('last_build_time', ?)`).run((/* @__PURE__ */ new Date()).toISOString());
|
|
28310
28523
|
}
|
|
28524
|
+
var CODEGRAPH_TS_FLOOR_MS, CODEGRAPH_TS_SKEW_MS;
|
|
28311
28525
|
var init_db2 = __esm({
|
|
28312
28526
|
"src/db.ts"() {
|
|
28313
28527
|
"use strict";
|
|
@@ -28316,14 +28530,16 @@ var init_db2 = __esm({
|
|
|
28316
28530
|
init_config();
|
|
28317
28531
|
init_sql_table_names();
|
|
28318
28532
|
init_preflight();
|
|
28533
|
+
CODEGRAPH_TS_FLOOR_MS = 15778368e5;
|
|
28534
|
+
CODEGRAPH_TS_SKEW_MS = 864e5;
|
|
28319
28535
|
}
|
|
28320
28536
|
});
|
|
28321
28537
|
|
|
28322
28538
|
// src/security-utils.ts
|
|
28323
|
-
import { resolve as
|
|
28539
|
+
import { resolve as resolve30, normalize } from "path";
|
|
28324
28540
|
function ensureWithinRoot(filePath, projectRoot) {
|
|
28325
|
-
const resolvedRoot =
|
|
28326
|
-
const resolvedPath =
|
|
28541
|
+
const resolvedRoot = resolve30(projectRoot);
|
|
28542
|
+
const resolvedPath = resolve30(resolvedRoot, filePath);
|
|
28327
28543
|
const normalizedPath = normalize(resolvedPath);
|
|
28328
28544
|
const normalizedRoot = normalize(resolvedRoot);
|
|
28329
28545
|
if (!normalizedPath.startsWith(normalizedRoot + "/") && normalizedPath !== normalizedRoot) {
|
|
@@ -28395,9 +28611,125 @@ var init_rules = __esm({
|
|
|
28395
28611
|
}
|
|
28396
28612
|
});
|
|
28397
28613
|
|
|
28614
|
+
// src/lib/source-layout.ts
|
|
28615
|
+
function normalizeDir(raw) {
|
|
28616
|
+
if (typeof raw !== "string") return null;
|
|
28617
|
+
const posix = raw.replace(/\\/g, "/");
|
|
28618
|
+
if (posix.startsWith("/") || /^[A-Za-z]:\//.test(posix)) return null;
|
|
28619
|
+
const parts = posix.split("/").filter((p19) => p19 !== "" && p19 !== ".");
|
|
28620
|
+
if (parts.some((p19) => p19 === "..")) return null;
|
|
28621
|
+
if (parts.length === 0) return ".";
|
|
28622
|
+
return parts.join("/");
|
|
28623
|
+
}
|
|
28624
|
+
function declaredLanguageSourceDirs() {
|
|
28625
|
+
const languages = getConfig().framework.languages;
|
|
28626
|
+
if (!languages) return [];
|
|
28627
|
+
const out = [];
|
|
28628
|
+
for (const entry of Object.values(languages)) {
|
|
28629
|
+
if (Array.isArray(entry.source_dirs)) out.push(...entry.source_dirs);
|
|
28630
|
+
}
|
|
28631
|
+
return out;
|
|
28632
|
+
}
|
|
28633
|
+
function getSourceLayout() {
|
|
28634
|
+
const config = getConfig();
|
|
28635
|
+
const paths = config.paths;
|
|
28636
|
+
const declared = [
|
|
28637
|
+
paths.source,
|
|
28638
|
+
...paths.monorepo_roots ?? [],
|
|
28639
|
+
...declaredLanguageSourceDirs()
|
|
28640
|
+
];
|
|
28641
|
+
const normalized = declared.map(normalizeDir).filter((d2) => d2 !== null);
|
|
28642
|
+
const includesRoot = normalized.includes(".");
|
|
28643
|
+
const sourceDirs = includesRoot ? [] : [...new Set(normalized)].sort();
|
|
28644
|
+
const source = normalizeDir(paths.source) ?? ".";
|
|
28645
|
+
const under = (child) => source === "." ? child : `${source}/${child}`;
|
|
28646
|
+
return {
|
|
28647
|
+
sourceDirs,
|
|
28648
|
+
includesRoot,
|
|
28649
|
+
extensions: getResolvedPaths().extensions,
|
|
28650
|
+
pagesDir: normalizeDir(paths.pages ?? under("app")) ?? under("app"),
|
|
28651
|
+
componentsDir: normalizeDir(paths.components ?? under("components")) ?? under("components")
|
|
28652
|
+
};
|
|
28653
|
+
}
|
|
28654
|
+
function escapeLike(literal) {
|
|
28655
|
+
return literal.replace(/[\\%_]/g, (m3) => `\\${m3}`);
|
|
28656
|
+
}
|
|
28657
|
+
function assertIdentifier(column) {
|
|
28658
|
+
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(column)) {
|
|
28659
|
+
throw new Error(`source-layout: refusing to interpolate '${column}' as a SQL column name`);
|
|
28660
|
+
}
|
|
28661
|
+
return column;
|
|
28662
|
+
}
|
|
28663
|
+
function likeAny(column, patterns) {
|
|
28664
|
+
if (patterns.length === 0) return { sql: "1=0", params: [] };
|
|
28665
|
+
const col = assertIdentifier(column);
|
|
28666
|
+
const sql = patterns.map(() => `${col} LIKE ? ESCAPE '\\'`).join(" OR ");
|
|
28667
|
+
return { sql: `(${sql})`, params: patterns };
|
|
28668
|
+
}
|
|
28669
|
+
function sourceDirPredicate(column = "path", layout = getSourceLayout()) {
|
|
28670
|
+
if (layout.includesRoot) return { sql: `(${assertIdentifier(column)} IS NOT NULL)`, params: [] };
|
|
28671
|
+
return likeAny(column, layout.sourceDirs.map((d2) => `${escapeLike(d2)}/%`));
|
|
28672
|
+
}
|
|
28673
|
+
function sourceFilePredicate(column = "path", layout = getSourceLayout()) {
|
|
28674
|
+
const dirs = sourceDirPredicate(column, layout);
|
|
28675
|
+
const exts = likeAny(column, layout.extensions.map((e2) => `%${escapeLike(e2)}`));
|
|
28676
|
+
return {
|
|
28677
|
+
sql: `${dirs.sql} AND ${exts.sql}`,
|
|
28678
|
+
params: [...dirs.params, ...exts.params]
|
|
28679
|
+
};
|
|
28680
|
+
}
|
|
28681
|
+
function pagesPredicate(layout = getSourceLayout()) {
|
|
28682
|
+
const dir = escapeLike(layout.pagesDir);
|
|
28683
|
+
return {
|
|
28684
|
+
sql: `(path LIKE ? ESCAPE '\\' OR path = ?)`,
|
|
28685
|
+
params: [`${dir}/%/page.tsx`, `${layout.pagesDir}/page.tsx`]
|
|
28686
|
+
};
|
|
28687
|
+
}
|
|
28688
|
+
function componentsPredicate(layout = getSourceLayout()) {
|
|
28689
|
+
return {
|
|
28690
|
+
sql: `path LIKE ? ESCAPE '\\'`,
|
|
28691
|
+
params: [`${escapeLike(layout.componentsDir)}/%`]
|
|
28692
|
+
};
|
|
28693
|
+
}
|
|
28694
|
+
function isUnderSourceDir(path, layout = getSourceLayout()) {
|
|
28695
|
+
if (normalizeDir(path) === null) return false;
|
|
28696
|
+
if (layout.includesRoot) return true;
|
|
28697
|
+
return layout.sourceDirs.some((d2) => path.startsWith(`${d2}/`));
|
|
28698
|
+
}
|
|
28699
|
+
function assertSourceCandidateSet(codegraphDb, builder, layout = getSourceLayout()) {
|
|
28700
|
+
const present = codegraphDb.prepare("SELECT COUNT(*) AS n FROM files").get().n;
|
|
28701
|
+
if (present === 0) return;
|
|
28702
|
+
const pred = sourceDirPredicate("path", layout);
|
|
28703
|
+
const matched = codegraphDb.prepare(`SELECT COUNT(*) AS n FROM files WHERE ${pred.sql}`).get(...pred.params).n;
|
|
28704
|
+
if (matched > 0) return;
|
|
28705
|
+
const prefixes = codegraphDb.prepare(
|
|
28706
|
+
`SELECT CASE WHEN instr(path, '/') > 0 THEN substr(path, 1, instr(path, '/') - 1) ELSE '<root>' END AS prefix,
|
|
28707
|
+
COUNT(*) AS n
|
|
28708
|
+
FROM files GROUP BY prefix ORDER BY n DESC LIMIT 20`
|
|
28709
|
+
).all();
|
|
28710
|
+
const declared = layout.includesRoot ? "<project root>" : layout.sourceDirs.join(", ") || "<none>";
|
|
28711
|
+
const found = prefixes.map((p19) => `${p19.prefix} (${p19.n})`).join(", ") || "<none>";
|
|
28712
|
+
throw new CandidateSetContractError(
|
|
28713
|
+
`${builder}: declared source dirs match 0 of ${present} indexed files. Declared: ${declared}. Present in CodeGraph: ${found}. Declare the real layout in massu.config.yaml (paths.source, paths.monorepo_roots, or framework.languages.<lang>.source_dirs) \u2014 an index built from an empty candidate set is indistinguishable from a project with no imports.`
|
|
28714
|
+
);
|
|
28715
|
+
}
|
|
28716
|
+
var CandidateSetContractError;
|
|
28717
|
+
var init_source_layout = __esm({
|
|
28718
|
+
"src/lib/source-layout.ts"() {
|
|
28719
|
+
"use strict";
|
|
28720
|
+
init_config();
|
|
28721
|
+
CandidateSetContractError = class extends Error {
|
|
28722
|
+
constructor(message) {
|
|
28723
|
+
super(message);
|
|
28724
|
+
this.name = "CandidateSetContractError";
|
|
28725
|
+
}
|
|
28726
|
+
};
|
|
28727
|
+
}
|
|
28728
|
+
});
|
|
28729
|
+
|
|
28398
28730
|
// src/import-resolver.ts
|
|
28399
28731
|
import { readFileSync as readFileSync41, existsSync as existsSync55, statSync as statSync19 } from "fs";
|
|
28400
|
-
import { resolve as
|
|
28732
|
+
import { resolve as resolve31, dirname as dirname25, join as join30 } from "path";
|
|
28401
28733
|
function parseImports(source) {
|
|
28402
28734
|
const imports = [];
|
|
28403
28735
|
const lines = source.split("\n");
|
|
@@ -28453,24 +28785,24 @@ function resolveImportPath(specifier, fromFile) {
|
|
|
28453
28785
|
let basePath;
|
|
28454
28786
|
if (specifier.startsWith("@/")) {
|
|
28455
28787
|
const paths = getResolvedPaths();
|
|
28456
|
-
basePath =
|
|
28788
|
+
basePath = resolve31(paths.pathAlias["@"] ?? paths.srcDir, specifier.slice(2));
|
|
28457
28789
|
} else {
|
|
28458
|
-
basePath =
|
|
28790
|
+
basePath = resolve31(dirname25(fromFile), specifier);
|
|
28459
28791
|
}
|
|
28460
28792
|
if (existsSync55(basePath) && !isDirectory(basePath)) {
|
|
28461
|
-
return
|
|
28793
|
+
return toRelative2(basePath);
|
|
28462
28794
|
}
|
|
28463
28795
|
const resolvedPaths = getResolvedPaths();
|
|
28464
28796
|
for (const ext of resolvedPaths.extensions) {
|
|
28465
28797
|
const withExt = basePath + ext;
|
|
28466
28798
|
if (existsSync55(withExt)) {
|
|
28467
|
-
return
|
|
28799
|
+
return toRelative2(withExt);
|
|
28468
28800
|
}
|
|
28469
28801
|
}
|
|
28470
28802
|
for (const indexFile of resolvedPaths.indexFiles) {
|
|
28471
28803
|
const indexPath = join30(basePath, indexFile);
|
|
28472
28804
|
if (existsSync55(indexPath)) {
|
|
28473
|
-
return
|
|
28805
|
+
return toRelative2(indexPath);
|
|
28474
28806
|
}
|
|
28475
28807
|
}
|
|
28476
28808
|
return null;
|
|
@@ -28482,7 +28814,7 @@ function isDirectory(path) {
|
|
|
28482
28814
|
return false;
|
|
28483
28815
|
}
|
|
28484
28816
|
}
|
|
28485
|
-
function
|
|
28817
|
+
function toRelative2(absPath) {
|
|
28486
28818
|
const root = getProjectRoot();
|
|
28487
28819
|
if (absPath.startsWith(root)) {
|
|
28488
28820
|
return absPath.slice(root.length + 1);
|
|
@@ -28490,7 +28822,15 @@ function toRelative(absPath) {
|
|
|
28490
28822
|
return absPath;
|
|
28491
28823
|
}
|
|
28492
28824
|
function buildImportIndex(dataDb, codegraphDb) {
|
|
28493
|
-
|
|
28825
|
+
assertSourceCandidateSet(codegraphDb, "buildImportIndex");
|
|
28826
|
+
const filesPredicate = sourceFilePredicate();
|
|
28827
|
+
const FILE_SCAN_LIMIT = 2e5;
|
|
28828
|
+
const files = codegraphDb.prepare(`SELECT path FROM files WHERE ${filesPredicate.sql} LIMIT ${FILE_SCAN_LIMIT}`).all(...filesPredicate.params);
|
|
28829
|
+
if (files.length === FILE_SCAN_LIMIT) {
|
|
28830
|
+
throw new Error(
|
|
28831
|
+
`buildImportIndex: candidate set hit the ${FILE_SCAN_LIMIT}-row scan limit, so the import index would be built from a truncated file list. Narrow the declared source dirs in massu.config.yaml, or raise FILE_SCAN_LIMIT deliberately.`
|
|
28832
|
+
);
|
|
28833
|
+
}
|
|
28494
28834
|
dataDb.exec(`DELETE FROM ${t("imports")}`);
|
|
28495
28835
|
const insertStmt = dataDb.prepare(
|
|
28496
28836
|
`INSERT INTO ${t("imports")} (source_file, target_file, import_type, imported_names, line) VALUES (?, ?, ?, ?, ?)`
|
|
@@ -28505,7 +28845,7 @@ function buildImportIndex(dataDb, codegraphDb) {
|
|
|
28505
28845
|
const batchSize = 500;
|
|
28506
28846
|
let batch = [];
|
|
28507
28847
|
for (const file of files) {
|
|
28508
|
-
const absPath = ensureWithinRoot(
|
|
28848
|
+
const absPath = ensureWithinRoot(resolve31(projectRoot, file.path), projectRoot);
|
|
28509
28849
|
if (!existsSync55(absPath)) continue;
|
|
28510
28850
|
let source;
|
|
28511
28851
|
try {
|
|
@@ -28542,12 +28882,13 @@ var init_import_resolver = __esm({
|
|
|
28542
28882
|
init_config();
|
|
28543
28883
|
init_security_utils();
|
|
28544
28884
|
init_sql_table_names();
|
|
28885
|
+
init_source_layout();
|
|
28545
28886
|
}
|
|
28546
28887
|
});
|
|
28547
28888
|
|
|
28548
28889
|
// src/trpc-index.ts
|
|
28549
28890
|
import { readFileSync as readFileSync42, existsSync as existsSync56, readdirSync as readdirSync20 } from "fs";
|
|
28550
|
-
import { resolve as
|
|
28891
|
+
import { resolve as resolve32, join as join31 } from "path";
|
|
28551
28892
|
function parseRootRouter() {
|
|
28552
28893
|
const paths = getResolvedPaths();
|
|
28553
28894
|
const rootPath = paths.rootRouterPath;
|
|
@@ -28562,7 +28903,7 @@ function parseRootRouter() {
|
|
|
28562
28903
|
while ((match = importRegex.exec(source)) !== null) {
|
|
28563
28904
|
const variable = match[1];
|
|
28564
28905
|
let filePath = match[2];
|
|
28565
|
-
const fullPath =
|
|
28906
|
+
const fullPath = resolve32(paths.routersDir, filePath);
|
|
28566
28907
|
for (const ext of [".ts", ".tsx", ""]) {
|
|
28567
28908
|
const candidate = fullPath + ext;
|
|
28568
28909
|
const routersRelPath = getConfig().paths.routers ?? "src/server/api/routers";
|
|
@@ -28590,7 +28931,7 @@ function parseRootRouter() {
|
|
|
28590
28931
|
return mappings;
|
|
28591
28932
|
}
|
|
28592
28933
|
function extractProcedures(routerFilePath) {
|
|
28593
|
-
const absPath =
|
|
28934
|
+
const absPath = resolve32(getProjectRoot(), routerFilePath);
|
|
28594
28935
|
if (!existsSync56(absPath)) return [];
|
|
28595
28936
|
const source = readFileSync42(absPath, "utf-8");
|
|
28596
28937
|
const procedures = [];
|
|
@@ -28615,9 +28956,9 @@ function findUICallSites(routerKey, procedureName) {
|
|
|
28615
28956
|
const root = getProjectRoot();
|
|
28616
28957
|
const src = config.paths.source;
|
|
28617
28958
|
const searchDirs = [
|
|
28618
|
-
|
|
28619
|
-
|
|
28620
|
-
|
|
28959
|
+
resolve32(root, config.paths.pages ?? src + "/app"),
|
|
28960
|
+
resolve32(root, config.paths.components ?? src + "/components"),
|
|
28961
|
+
resolve32(root, config.paths.hooks ?? src + "/hooks")
|
|
28621
28962
|
];
|
|
28622
28963
|
const searchPattern = `api.${routerKey}.${procedureName}`;
|
|
28623
28964
|
for (const dir of searchDirs) {
|
|
@@ -28700,9 +29041,11 @@ var init_trpc_index = __esm({
|
|
|
28700
29041
|
|
|
28701
29042
|
// src/page-deps.ts
|
|
28702
29043
|
import { readFileSync as readFileSync43, existsSync as existsSync57 } from "fs";
|
|
28703
|
-
import { resolve as
|
|
29044
|
+
import { resolve as resolve33 } from "path";
|
|
28704
29045
|
function deriveRoute(pageFile) {
|
|
28705
|
-
|
|
29046
|
+
const pagesDir = getSourceLayout().pagesDir;
|
|
29047
|
+
const prefix3 = pagesDir.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
29048
|
+
let route = pageFile.replace(new RegExp(`^${prefix3}`), "").replace(/\/page\.tsx?$/, "").replace(/\/page\.jsx?$/, "");
|
|
28706
29049
|
return route || "/";
|
|
28707
29050
|
}
|
|
28708
29051
|
function derivePortal(route) {
|
|
@@ -28729,7 +29072,7 @@ function traceImports(startFile, dataDb, visited, components, hooks, maxDepth =
|
|
|
28729
29072
|
if (target.includes("/hooks/") || target.match(/use[A-Z]/)) {
|
|
28730
29073
|
hooks.add(target);
|
|
28731
29074
|
}
|
|
28732
|
-
if (target
|
|
29075
|
+
if (isUnderSourceDir(target)) {
|
|
28733
29076
|
traceImports(target, dataDb, visited, components, hooks, maxDepth - 1);
|
|
28734
29077
|
}
|
|
28735
29078
|
}
|
|
@@ -28738,7 +29081,7 @@ function findRouterCalls(files) {
|
|
|
28738
29081
|
const routers = /* @__PURE__ */ new Set();
|
|
28739
29082
|
const projectRoot = getProjectRoot();
|
|
28740
29083
|
for (const file of files) {
|
|
28741
|
-
const absPath = ensureWithinRoot(
|
|
29084
|
+
const absPath = ensureWithinRoot(resolve33(projectRoot, file), projectRoot);
|
|
28742
29085
|
if (!existsSync57(absPath)) continue;
|
|
28743
29086
|
try {
|
|
28744
29087
|
const source = readFileSync43(absPath, "utf-8");
|
|
@@ -28759,7 +29102,7 @@ function findTablesFromRouters(routerNames, dataDb) {
|
|
|
28759
29102
|
`SELECT DISTINCT router_file FROM ${t("trpc_procedures")} WHERE router_name = ? LIMIT 10000`
|
|
28760
29103
|
).all(routerName);
|
|
28761
29104
|
for (const proc of procs) {
|
|
28762
|
-
const absPath = ensureWithinRoot(
|
|
29105
|
+
const absPath = ensureWithinRoot(resolve33(getProjectRoot(), proc.router_file), getProjectRoot());
|
|
28763
29106
|
if (!existsSync57(absPath)) continue;
|
|
28764
29107
|
try {
|
|
28765
29108
|
const source = readFileSync43(absPath, "utf-8");
|
|
@@ -28777,10 +29120,12 @@ function findTablesFromRouters(routerNames, dataDb) {
|
|
|
28777
29120
|
return [...tables];
|
|
28778
29121
|
}
|
|
28779
29122
|
function buildPageDeps(dataDb, codegraphDb) {
|
|
29123
|
+
assertSourceCandidateSet(codegraphDb, "buildPageDeps");
|
|
28780
29124
|
dataDb.exec(`DELETE FROM ${t("page_deps")}`);
|
|
29125
|
+
const pagesPred = pagesPredicate();
|
|
28781
29126
|
const pages = codegraphDb.prepare(
|
|
28782
|
-
|
|
28783
|
-
).all();
|
|
29127
|
+
`SELECT path FROM files WHERE ${pagesPred.sql} LIMIT 10000`
|
|
29128
|
+
).all(...pagesPred.params);
|
|
28784
29129
|
const insertStmt = dataDb.prepare(
|
|
28785
29130
|
`INSERT INTO ${t("page_deps")} (page_file, route, portal, components, hooks, routers, tables_touched) VALUES (?, ?, ?, ?, ?, ?, ?)`
|
|
28786
29131
|
);
|
|
@@ -28875,6 +29220,7 @@ var init_page_deps = __esm({
|
|
|
28875
29220
|
init_config();
|
|
28876
29221
|
init_security_utils();
|
|
28877
29222
|
init_sql_table_names();
|
|
29223
|
+
init_source_layout();
|
|
28878
29224
|
}
|
|
28879
29225
|
});
|
|
28880
29226
|
|
|
@@ -28893,7 +29239,7 @@ function buildMiddlewareTree(dataDb) {
|
|
|
28893
29239
|
`SELECT target_file FROM ${t("imports")} WHERE source_file = ? LIMIT 10000`
|
|
28894
29240
|
).all(current);
|
|
28895
29241
|
for (const imp of imports) {
|
|
28896
|
-
if (!visited.has(imp.target_file) && imp.target_file
|
|
29242
|
+
if (!visited.has(imp.target_file) && isUnderSourceDir(imp.target_file)) {
|
|
28897
29243
|
visited.add(imp.target_file);
|
|
28898
29244
|
queue.push(imp.target_file);
|
|
28899
29245
|
}
|
|
@@ -28917,6 +29263,7 @@ var init_middleware_tree = __esm({
|
|
|
28917
29263
|
"use strict";
|
|
28918
29264
|
init_config();
|
|
28919
29265
|
init_sql_table_names();
|
|
29266
|
+
init_source_layout();
|
|
28920
29267
|
}
|
|
28921
29268
|
});
|
|
28922
29269
|
|
|
@@ -28974,12 +29321,11 @@ function globMatchSimple(name, pattern) {
|
|
|
28974
29321
|
}
|
|
28975
29322
|
function findCrossDomainImports(dataDb) {
|
|
28976
29323
|
const domains = getDomains();
|
|
28977
|
-
const
|
|
28978
|
-
const
|
|
28979
|
-
const srcPattern = srcPrefix + "/%";
|
|
29324
|
+
const srcSource = sourceDirPredicate("source_file");
|
|
29325
|
+
const srcTarget = sourceDirPredicate("target_file");
|
|
28980
29326
|
const imports = dataDb.prepare(
|
|
28981
|
-
`SELECT source_file, target_file FROM ${t("imports")} WHERE
|
|
28982
|
-
).all(
|
|
29327
|
+
`SELECT source_file, target_file FROM ${t("imports")} WHERE ${srcSource.sql} AND ${srcTarget.sql} LIMIT 10000`
|
|
29328
|
+
).all(...srcSource.params, ...srcTarget.params);
|
|
28983
29329
|
const crossings = [];
|
|
28984
29330
|
for (const imp of imports) {
|
|
28985
29331
|
const sourceDomain = classifyFile(imp.source_file);
|
|
@@ -29004,10 +29350,9 @@ function getFilesInDomain(dataDb, codegraphDb, domainName) {
|
|
|
29004
29350
|
const config = getConfig();
|
|
29005
29351
|
const domain = domains.find((d2) => d2.name === domainName);
|
|
29006
29352
|
if (!domain) return { routers: [], pages: [], components: [] };
|
|
29007
|
-
const srcPrefix = config.paths.source;
|
|
29008
29353
|
const routersPath = config.paths.routers ?? "src/server/api/routers";
|
|
29009
|
-
const
|
|
29010
|
-
const allFiles = codegraphDb.prepare(
|
|
29354
|
+
const srcPred = sourceDirPredicate();
|
|
29355
|
+
const allFiles = codegraphDb.prepare(`SELECT path FROM files WHERE ${srcPred.sql} LIMIT 200000`).all(...srcPred.params);
|
|
29011
29356
|
const routers = [];
|
|
29012
29357
|
const pages = [];
|
|
29013
29358
|
const components = [];
|
|
@@ -29030,6 +29375,7 @@ var init_domains = __esm({
|
|
|
29030
29375
|
init_rules();
|
|
29031
29376
|
init_config();
|
|
29032
29377
|
init_sql_table_names();
|
|
29378
|
+
init_source_layout();
|
|
29033
29379
|
}
|
|
29034
29380
|
});
|
|
29035
29381
|
|
|
@@ -29315,11 +29661,11 @@ var init_import_parser = __esm({
|
|
|
29315
29661
|
|
|
29316
29662
|
// src/python/import-resolver.ts
|
|
29317
29663
|
import { readFileSync as readFileSync45, existsSync as existsSync59, readdirSync as readdirSync22 } from "fs";
|
|
29318
|
-
import { resolve as
|
|
29664
|
+
import { resolve as resolve35, join as join33, relative as relative9, dirname as dirname26 } from "path";
|
|
29319
29665
|
function resolvePythonModulePath(module, fromFile, pythonRoot, level) {
|
|
29320
29666
|
const projectRoot = getProjectRoot();
|
|
29321
29667
|
if (level > 0) {
|
|
29322
|
-
let baseDir = dirname26(
|
|
29668
|
+
let baseDir = dirname26(resolve35(projectRoot, fromFile));
|
|
29323
29669
|
for (let i = 1; i < level; i++) {
|
|
29324
29670
|
baseDir = dirname26(baseDir);
|
|
29325
29671
|
}
|
|
@@ -29331,18 +29677,18 @@ function resolvePythonModulePath(module, fromFile, pythonRoot, level) {
|
|
|
29331
29677
|
return tryResolvePythonPath(baseDir, projectRoot);
|
|
29332
29678
|
}
|
|
29333
29679
|
const parts = module.split(".");
|
|
29334
|
-
const candidate = join33(
|
|
29680
|
+
const candidate = join33(resolve35(projectRoot, pythonRoot), ...parts);
|
|
29335
29681
|
return tryResolvePythonPath(candidate, projectRoot);
|
|
29336
29682
|
}
|
|
29337
29683
|
function tryResolvePythonPath(basePath, projectRoot) {
|
|
29338
29684
|
if (existsSync59(basePath + ".py")) {
|
|
29339
|
-
return
|
|
29685
|
+
return relative9(projectRoot, basePath + ".py");
|
|
29340
29686
|
}
|
|
29341
29687
|
if (existsSync59(join33(basePath, "__init__.py"))) {
|
|
29342
|
-
return
|
|
29688
|
+
return relative9(projectRoot, join33(basePath, "__init__.py"));
|
|
29343
29689
|
}
|
|
29344
29690
|
if (basePath.endsWith(".py") && existsSync59(basePath)) {
|
|
29345
|
-
return
|
|
29691
|
+
return relative9(projectRoot, basePath);
|
|
29346
29692
|
}
|
|
29347
29693
|
return null;
|
|
29348
29694
|
}
|
|
@@ -29364,7 +29710,7 @@ function walkPythonFiles(dir, excludeDirs) {
|
|
|
29364
29710
|
}
|
|
29365
29711
|
function buildPythonImportIndex(dataDb, pythonRoot, excludeDirs = ["__pycache__", ".venv", "venv", ".mypy_cache", ".pytest_cache"]) {
|
|
29366
29712
|
const projectRoot = getProjectRoot();
|
|
29367
|
-
const absRoot =
|
|
29713
|
+
const absRoot = resolve35(projectRoot, pythonRoot);
|
|
29368
29714
|
dataDb.exec(`DELETE FROM ${t("py_imports")}`);
|
|
29369
29715
|
const insertStmt = dataDb.prepare(
|
|
29370
29716
|
`INSERT INTO ${t("py_imports")} (source_file, target_file, import_type, imported_names, line) VALUES (?, ?, ?, ?, ?)`
|
|
@@ -29378,7 +29724,7 @@ function buildPythonImportIndex(dataDb, pythonRoot, excludeDirs = ["__pycache__"
|
|
|
29378
29724
|
});
|
|
29379
29725
|
const batch = [];
|
|
29380
29726
|
for (const absFile of files) {
|
|
29381
|
-
const relFile =
|
|
29727
|
+
const relFile = relative9(projectRoot, absFile);
|
|
29382
29728
|
let source;
|
|
29383
29729
|
try {
|
|
29384
29730
|
source = readFileSync45(absFile, "utf-8");
|
|
@@ -29649,7 +29995,7 @@ var init_route_parser = __esm({
|
|
|
29649
29995
|
|
|
29650
29996
|
// src/python/route-indexer.ts
|
|
29651
29997
|
import { readFileSync as readFileSync46, readdirSync as readdirSync23 } from "fs";
|
|
29652
|
-
import { join as join34, relative as
|
|
29998
|
+
import { join as join34, relative as relative10 } from "path";
|
|
29653
29999
|
function walkPyFiles(dir, excludeDirs) {
|
|
29654
30000
|
const files = [];
|
|
29655
30001
|
try {
|
|
@@ -29678,7 +30024,7 @@ function buildPythonRouteIndex(dataDb, pythonRoot, excludeDirs = ["__pycache__",
|
|
|
29678
30024
|
let count = 0;
|
|
29679
30025
|
dataDb.transaction(() => {
|
|
29680
30026
|
for (const absFile of files) {
|
|
29681
|
-
const relFile =
|
|
30027
|
+
const relFile = relative10(projectRoot, absFile);
|
|
29682
30028
|
let source;
|
|
29683
30029
|
try {
|
|
29684
30030
|
source = readFileSync46(absFile, "utf-8");
|
|
@@ -29894,7 +30240,7 @@ var init_model_parser = __esm({
|
|
|
29894
30240
|
|
|
29895
30241
|
// src/python/model-indexer.ts
|
|
29896
30242
|
import { readFileSync as readFileSync47, readdirSync as readdirSync24 } from "fs";
|
|
29897
|
-
import { join as join35, relative as
|
|
30243
|
+
import { join as join35, relative as relative11 } from "path";
|
|
29898
30244
|
function walkPyFiles2(dir, excludeDirs) {
|
|
29899
30245
|
const files = [];
|
|
29900
30246
|
try {
|
|
@@ -29926,7 +30272,7 @@ function buildPythonModelIndex(dataDb, pythonRoot, excludeDirs = ["__pycache__",
|
|
|
29926
30272
|
let count = 0;
|
|
29927
30273
|
dataDb.transaction(() => {
|
|
29928
30274
|
for (const absFile of files) {
|
|
29929
|
-
const relFile =
|
|
30275
|
+
const relFile = relative11(projectRoot, absFile);
|
|
29930
30276
|
let source;
|
|
29931
30277
|
try {
|
|
29932
30278
|
source = readFileSync47(absFile, "utf-8");
|
|
@@ -30191,7 +30537,7 @@ var init_migration_parser = __esm({
|
|
|
30191
30537
|
|
|
30192
30538
|
// src/python/migration-indexer.ts
|
|
30193
30539
|
import { readFileSync as readFileSync48, readdirSync as readdirSync25 } from "fs";
|
|
30194
|
-
import { join as join36, relative as
|
|
30540
|
+
import { join as join36, relative as relative12 } from "path";
|
|
30195
30541
|
function buildPythonMigrationIndex(dataDb, alembicDir) {
|
|
30196
30542
|
const projectRoot = getProjectRoot();
|
|
30197
30543
|
const absDir = join36(projectRoot, alembicDir);
|
|
@@ -30227,7 +30573,7 @@ function buildPythonMigrationIndex(dataDb, alembicDir) {
|
|
|
30227
30573
|
rows.push({
|
|
30228
30574
|
revision: parsed.revision,
|
|
30229
30575
|
downRevision: parsed.downRevision,
|
|
30230
|
-
file:
|
|
30576
|
+
file: relative12(projectRoot, absFile),
|
|
30231
30577
|
description: parsed.description,
|
|
30232
30578
|
operations: JSON.stringify(parsed.operations)
|
|
30233
30579
|
});
|
|
@@ -30252,7 +30598,7 @@ var init_migration_indexer = __esm({
|
|
|
30252
30598
|
|
|
30253
30599
|
// src/python/coupling-detector.ts
|
|
30254
30600
|
import { readFileSync as readFileSync49, readdirSync as readdirSync26 } from "fs";
|
|
30255
|
-
import { join as join37, relative as
|
|
30601
|
+
import { join as join37, relative as relative13 } from "path";
|
|
30256
30602
|
function buildPythonCouplingIndex(dataDb) {
|
|
30257
30603
|
const projectRoot = getProjectRoot();
|
|
30258
30604
|
const config = getConfig();
|
|
@@ -30285,7 +30631,7 @@ function buildPythonCouplingIndex(dataDb) {
|
|
|
30285
30631
|
];
|
|
30286
30632
|
dataDb.transaction(() => {
|
|
30287
30633
|
for (const absFile of frontendFiles) {
|
|
30288
|
-
const relFile =
|
|
30634
|
+
const relFile = relative13(projectRoot, absFile);
|
|
30289
30635
|
let source;
|
|
30290
30636
|
try {
|
|
30291
30637
|
source = readFileSync49(absFile, "utf-8");
|
|
@@ -30695,7 +31041,7 @@ var init_memory_tools = __esm({
|
|
|
30695
31041
|
|
|
30696
31042
|
// src/docs-tools.ts
|
|
30697
31043
|
import { readFileSync as readFileSync50, existsSync as existsSync60 } from "fs";
|
|
30698
|
-
import { resolve as
|
|
31044
|
+
import { resolve as resolve36, basename as basename9 } from "path";
|
|
30699
31045
|
function p4(baseName) {
|
|
30700
31046
|
return `${getConfig().toolPrefix}_${baseName}`;
|
|
30701
31047
|
}
|
|
@@ -30823,9 +31169,9 @@ function extractFrontmatter(content) {
|
|
|
30823
31169
|
}
|
|
30824
31170
|
function extractProcedureNames(routerPath) {
|
|
30825
31171
|
const root = getProjectRoot();
|
|
30826
|
-
const absPath = ensureWithinRoot(
|
|
31172
|
+
const absPath = ensureWithinRoot(resolve36(getResolvedPaths().srcDir, "..", routerPath), root);
|
|
30827
31173
|
if (!existsSync60(absPath)) {
|
|
30828
|
-
const altPath = ensureWithinRoot(
|
|
31174
|
+
const altPath = ensureWithinRoot(resolve36(getResolvedPaths().srcDir, "../server/api/routers", basename9(routerPath)), root);
|
|
30829
31175
|
if (!existsSync60(altPath)) return [];
|
|
30830
31176
|
return extractProcedureNamesFromContent(readFileSync50(altPath, "utf-8"));
|
|
30831
31177
|
}
|
|
@@ -30869,7 +31215,7 @@ function handleDocsAudit(args2) {
|
|
|
30869
31215
|
for (const [mappingId, triggeringFiles] of affectedMappings) {
|
|
30870
31216
|
const mapping = docsMap.mappings.find((m3) => m3.id === mappingId);
|
|
30871
31217
|
if (!mapping) continue;
|
|
30872
|
-
const helpPagePath = ensureWithinRoot(
|
|
31218
|
+
const helpPagePath = ensureWithinRoot(resolve36(getResolvedPaths().helpSitePath, mapping.helpPage), getProjectRoot());
|
|
30873
31219
|
if (!existsSync60(helpPagePath)) {
|
|
30874
31220
|
results.push({
|
|
30875
31221
|
helpPage: mapping.helpPage,
|
|
@@ -30922,7 +31268,7 @@ function handleDocsAudit(args2) {
|
|
|
30922
31268
|
});
|
|
30923
31269
|
for (const [guideName, parentId] of Object.entries(docsMap.userGuideInheritance.examples)) {
|
|
30924
31270
|
if (parentId === mappingId) {
|
|
30925
|
-
const guidePath = ensureWithinRoot(
|
|
31271
|
+
const guidePath = ensureWithinRoot(resolve36(getResolvedPaths().helpSitePath, `pages/user-guides/${guideName}/index.mdx`), getProjectRoot());
|
|
30926
31272
|
if (existsSync60(guidePath)) {
|
|
30927
31273
|
const guideContent = readFileSync50(guidePath, "utf-8");
|
|
30928
31274
|
const guideFrontmatter = extractFrontmatter(guideContent);
|
|
@@ -30957,7 +31303,7 @@ function handleDocsCoverage(args2) {
|
|
|
30957
31303
|
const gaps = [];
|
|
30958
31304
|
const mappings = filterDomain ? docsMap.mappings.filter((m3) => m3.id === filterDomain) : docsMap.mappings;
|
|
30959
31305
|
for (const mapping of mappings) {
|
|
30960
|
-
const helpPagePath = ensureWithinRoot(
|
|
31306
|
+
const helpPagePath = ensureWithinRoot(resolve36(getResolvedPaths().helpSitePath, mapping.helpPage), getProjectRoot());
|
|
30961
31307
|
const exists = existsSync60(helpPagePath);
|
|
30962
31308
|
let hasContent = false;
|
|
30963
31309
|
let lineCount = 0;
|
|
@@ -31306,7 +31652,7 @@ var init_observability_tools = __esm({
|
|
|
31306
31652
|
|
|
31307
31653
|
// src/sentinel-db.ts
|
|
31308
31654
|
import { existsSync as existsSync61 } from "fs";
|
|
31309
|
-
import { resolve as
|
|
31655
|
+
import { resolve as resolve37 } from "path";
|
|
31310
31656
|
function parsePortalScope(raw) {
|
|
31311
31657
|
if (!raw) return [];
|
|
31312
31658
|
try {
|
|
@@ -31542,22 +31888,22 @@ function validateFeatures(db, domainFilter) {
|
|
|
31542
31888
|
const missingProcedures = [];
|
|
31543
31889
|
const missingPages = [];
|
|
31544
31890
|
for (const comp of components) {
|
|
31545
|
-
const absPath =
|
|
31891
|
+
const absPath = resolve37(PROJECT_ROOT, comp.component_file);
|
|
31546
31892
|
if (!existsSync61(absPath)) {
|
|
31547
31893
|
missingComponents.push(comp.component_file);
|
|
31548
31894
|
}
|
|
31549
31895
|
}
|
|
31550
31896
|
for (const proc of procedures) {
|
|
31551
|
-
const routerPath =
|
|
31897
|
+
const routerPath = resolve37(PROJECT_ROOT, `src/server/api/routers/${proc.router_name}.ts`);
|
|
31552
31898
|
if (!existsSync61(routerPath)) {
|
|
31553
31899
|
missingProcedures.push({ router: proc.router_name, procedure: proc.procedure_name });
|
|
31554
31900
|
}
|
|
31555
31901
|
}
|
|
31556
31902
|
for (const page of pages) {
|
|
31557
31903
|
const routeToPath = page.page_route.replace(/^\/(portal-[^/]+\/)?/, "src/app/").replace(/\/$/, "") + "/page.tsx";
|
|
31558
|
-
const absPath =
|
|
31904
|
+
const absPath = resolve37(PROJECT_ROOT, routeToPath);
|
|
31559
31905
|
if (page.page_route.startsWith("/") && !existsSync61(absPath)) {
|
|
31560
|
-
const altPath =
|
|
31906
|
+
const altPath = resolve37(PROJECT_ROOT, `src/app${page.page_route}/page.tsx`);
|
|
31561
31907
|
if (!existsSync61(altPath)) {
|
|
31562
31908
|
missingPages.push(page.page_route);
|
|
31563
31909
|
}
|
|
@@ -32085,7 +32431,7 @@ var init_sentinel_tools = __esm({
|
|
|
32085
32431
|
|
|
32086
32432
|
// src/sentinel-scanner.ts
|
|
32087
32433
|
import { readFileSync as readFileSync51, existsSync as existsSync62, readdirSync as readdirSync27, statSync as statSync20 } from "fs";
|
|
32088
|
-
import { resolve as
|
|
32434
|
+
import { resolve as resolve38, join as join38, basename as basename10, dirname as dirname27, relative as relative14 } from "path";
|
|
32089
32435
|
function inferDomain(filePath) {
|
|
32090
32436
|
const domains = getConfig().domains;
|
|
32091
32437
|
const path = filePath.toLowerCase();
|
|
@@ -32216,7 +32562,7 @@ function scanComponentExports(dataDb) {
|
|
|
32216
32562
|
const projectRoot = getProjectRoot();
|
|
32217
32563
|
const componentsBase = config.paths.components ?? config.paths.source + "/components";
|
|
32218
32564
|
const componentDirs = [];
|
|
32219
|
-
const basePath =
|
|
32565
|
+
const basePath = resolve38(projectRoot, componentsBase);
|
|
32220
32566
|
if (existsSync62(basePath)) {
|
|
32221
32567
|
try {
|
|
32222
32568
|
const entries = readdirSync27(basePath, { withFileTypes: true });
|
|
@@ -32229,11 +32575,11 @@ function scanComponentExports(dataDb) {
|
|
|
32229
32575
|
}
|
|
32230
32576
|
}
|
|
32231
32577
|
for (const dir of componentDirs) {
|
|
32232
|
-
const absDir =
|
|
32578
|
+
const absDir = resolve38(projectRoot, dir);
|
|
32233
32579
|
if (!existsSync62(absDir)) continue;
|
|
32234
32580
|
const files = walkDir2(absDir).filter((f2) => f2.endsWith(".tsx") || f2.endsWith(".ts"));
|
|
32235
32581
|
for (const file of files) {
|
|
32236
|
-
const relPath =
|
|
32582
|
+
const relPath = relative14(projectRoot, file);
|
|
32237
32583
|
const source = readFileSync51(file, "utf-8");
|
|
32238
32584
|
const annotations = parseFeatureAnnotations(source);
|
|
32239
32585
|
if (annotations.length > 0) {
|
|
@@ -33814,7 +34160,7 @@ var init_security_scorer = __esm({
|
|
|
33814
34160
|
|
|
33815
34161
|
// src/dependency-scorer.ts
|
|
33816
34162
|
import { existsSync as existsSync65, readFileSync as readFileSync54 } from "fs";
|
|
33817
|
-
import { resolve as
|
|
34163
|
+
import { resolve as resolve39 } from "path";
|
|
33818
34164
|
function p13(baseName) {
|
|
33819
34165
|
return `${getConfig().toolPrefix}_${baseName}`;
|
|
33820
34166
|
}
|
|
@@ -33846,7 +34192,7 @@ function calculateDepRisk(factors) {
|
|
|
33846
34192
|
return Math.min(100, risk);
|
|
33847
34193
|
}
|
|
33848
34194
|
function getInstalledPackages(projectRoot) {
|
|
33849
|
-
const pkgPath =
|
|
34195
|
+
const pkgPath = resolve39(projectRoot, "package.json");
|
|
33850
34196
|
if (!existsSync65(pkgPath)) return /* @__PURE__ */ new Map();
|
|
33851
34197
|
try {
|
|
33852
34198
|
const pkg = JSON.parse(readFileSync54(pkgPath, "utf-8"));
|
|
@@ -34456,7 +34802,7 @@ var init_regression_detector = __esm({
|
|
|
34456
34802
|
// src/knowledge-indexer.ts
|
|
34457
34803
|
import { createHash as createHash16 } from "crypto";
|
|
34458
34804
|
import { readFileSync as readFileSync55, readdirSync as readdirSync28, statSync as statSync21, existsSync as existsSync66 } from "fs";
|
|
34459
|
-
import { resolve as
|
|
34805
|
+
import { resolve as resolve40, relative as relative15, basename as basename11, extname as extname2 } from "path";
|
|
34460
34806
|
function getKnowledgePaths() {
|
|
34461
34807
|
const resolved = getResolvedPaths();
|
|
34462
34808
|
const config = getConfig();
|
|
@@ -34484,7 +34830,7 @@ function discoverMarkdownFiles(baseDir) {
|
|
|
34484
34830
|
try {
|
|
34485
34831
|
const entries = readdirSync28(dir, { withFileTypes: true });
|
|
34486
34832
|
for (const entry of entries) {
|
|
34487
|
-
const fullPath =
|
|
34833
|
+
const fullPath = resolve40(dir, entry.name);
|
|
34488
34834
|
if (entry.isDirectory()) {
|
|
34489
34835
|
if (entry.name === "archive" && dir.includes("session-state")) continue;
|
|
34490
34836
|
if (entry.name === "archive" && dir.includes("status")) continue;
|
|
@@ -34504,7 +34850,7 @@ function categorizeFile(filePath) {
|
|
|
34504
34850
|
const paths = getKnowledgePaths();
|
|
34505
34851
|
if (filePath.startsWith(paths.plansDir)) return "plan";
|
|
34506
34852
|
if (filePath.startsWith(paths.docsDir)) {
|
|
34507
|
-
const relFromDocs =
|
|
34853
|
+
const relFromDocs = relative15(paths.docsDir, filePath).replace(/\\/g, "/").toLowerCase();
|
|
34508
34854
|
if (relFromDocs.startsWith("plans/")) return "plan";
|
|
34509
34855
|
if (relFromDocs.includes("architecture")) return "architecture";
|
|
34510
34856
|
if (relFromDocs.includes("security")) return "security";
|
|
@@ -34520,7 +34866,7 @@ function categorizeFile(filePath) {
|
|
|
34520
34866
|
}
|
|
34521
34867
|
const claudeDirName = getConfig().conventions?.claudeDirName ?? ".claude";
|
|
34522
34868
|
if (filePath.includes(`${claudeDirName}/projects/`) && filePath.includes("/memory/")) return "memory";
|
|
34523
|
-
const rel =
|
|
34869
|
+
const rel = relative15(paths.claudeDir, filePath).replace(/\\/g, "/");
|
|
34524
34870
|
const firstDir = rel.split("/")[0];
|
|
34525
34871
|
const knownCategories = getConfig().conventions?.knowledgeCategories ?? [
|
|
34526
34872
|
"patterns",
|
|
@@ -34813,7 +35159,7 @@ function indexAllKnowledge(db) {
|
|
|
34813
35159
|
if (!existsSync66(filePath)) continue;
|
|
34814
35160
|
const content = readFileSync55(filePath, "utf-8");
|
|
34815
35161
|
const hash = hashContent2(content);
|
|
34816
|
-
const relPath = filePath.startsWith(paths.claudeDir) ?
|
|
35162
|
+
const relPath = filePath.startsWith(paths.claudeDir) ? relative15(paths.claudeDir, filePath) : filePath.startsWith(paths.plansDir) ? "plans/" + relative15(paths.plansDir, filePath) : filePath.startsWith(paths.docsDir) ? "docs/" + relative15(paths.docsDir, filePath) : filePath.startsWith(paths.memoryDir) ? `memory/${relative15(paths.memoryDir, filePath)}` : basename11(filePath);
|
|
34817
35163
|
const category = categorizeFile(filePath);
|
|
34818
35164
|
const title = extractTitle(content, filePath);
|
|
34819
35165
|
const description = extractDescription2(content);
|
|
@@ -34978,8 +35324,8 @@ var init_knowledge_indexer = __esm({
|
|
|
34978
35324
|
});
|
|
34979
35325
|
|
|
34980
35326
|
// src/knowledge-tools.ts
|
|
34981
|
-
import { readFileSync as readFileSync56, writeFileSync as
|
|
34982
|
-
import { resolve as
|
|
35327
|
+
import { readFileSync as readFileSync56, writeFileSync as writeFileSync17, appendFileSync as appendFileSync5, readdirSync as readdirSync29 } from "fs";
|
|
35328
|
+
import { resolve as resolve41, basename as basename12 } from "path";
|
|
34983
35329
|
function p16(baseName) {
|
|
34984
35330
|
return `${getConfig().toolPrefix}_${baseName}`;
|
|
34985
35331
|
}
|
|
@@ -34997,10 +35343,19 @@ function ensureKnowledgeIndexed(db) {
|
|
|
34997
35343
|
try {
|
|
34998
35344
|
indexIfStale(db);
|
|
34999
35345
|
return true;
|
|
35000
|
-
} catch {
|
|
35346
|
+
} catch (err) {
|
|
35347
|
+
recordHookFailure("knowledge-tools:ensure-indexed", err, {
|
|
35348
|
+
note: "knowledge index refresh failed; dispatch continued against the existing index"
|
|
35349
|
+
});
|
|
35001
35350
|
return false;
|
|
35002
35351
|
}
|
|
35003
35352
|
}
|
|
35353
|
+
function withStaleIndexWarning(result) {
|
|
35354
|
+
const banner = "\u26A0\uFE0F KNOWLEDGE INDEX NOT REFRESHED \u2014 the re-index for this call FAILED, so the results below come from the last successfully built index and may be out of date. The error was recorded to the hook-failure log under `knowledge-tools:ensure-indexed`.";
|
|
35355
|
+
return {
|
|
35356
|
+
content: [{ type: "text", text: banner }, ...result.content]
|
|
35357
|
+
};
|
|
35358
|
+
}
|
|
35004
35359
|
function hasData(db) {
|
|
35005
35360
|
const row = db.prepare("SELECT COUNT(*) as cnt FROM knowledge_documents").get();
|
|
35006
35361
|
return (row?.cnt ?? 0) > 0;
|
|
@@ -35181,8 +35536,15 @@ function isKnowledgeTool(name) {
|
|
|
35181
35536
|
const baseName = name.startsWith(pfx) ? name.slice(pfx.length) : name;
|
|
35182
35537
|
return KNOWLEDGE_BASE_NAMES.has(baseName);
|
|
35183
35538
|
}
|
|
35184
|
-
function handleKnowledgeToolCall(name, args2, db) {
|
|
35185
|
-
|
|
35539
|
+
function handleKnowledgeToolCall(name, args2, db, freshness) {
|
|
35540
|
+
if (freshness === "use-existing") {
|
|
35541
|
+
return dispatchKnowledgeTool(name, args2, db);
|
|
35542
|
+
}
|
|
35543
|
+
const indexed = ensureKnowledgeIndexed(db);
|
|
35544
|
+
const result = dispatchKnowledgeTool(name, args2, db);
|
|
35545
|
+
return indexed ? result : withStaleIndexWarning(result);
|
|
35546
|
+
}
|
|
35547
|
+
function dispatchKnowledgeTool(name, args2, db) {
|
|
35186
35548
|
if (!hasData(db)) {
|
|
35187
35549
|
return text15("No knowledge indexed yet. The knowledge DB will be populated automatically on next MCP server restart.");
|
|
35188
35550
|
}
|
|
@@ -35718,7 +36080,7 @@ function handleCorrect(db, args2) {
|
|
|
35718
36080
|
if (!wrong || !correction || !rule) {
|
|
35719
36081
|
return text15("Error: wrong, correction, and rule are all required.");
|
|
35720
36082
|
}
|
|
35721
|
-
const correctionsPath =
|
|
36083
|
+
const correctionsPath = resolve41(getResolvedPaths().memoryDir, "corrections.md");
|
|
35722
36084
|
const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
35723
36085
|
const title = rule.slice(0, 60);
|
|
35724
36086
|
const entry = formatCorrectionEntry({
|
|
@@ -35738,7 +36100,7 @@ function handleCorrect(db, args2) {
|
|
|
35738
36100
|
if (archiveIdx > 0) {
|
|
35739
36101
|
const before = existing.slice(0, archiveIdx);
|
|
35740
36102
|
const after = existing.slice(archiveIdx);
|
|
35741
|
-
|
|
36103
|
+
writeFileSync17(correctionsPath, before + entry + after);
|
|
35742
36104
|
} else {
|
|
35743
36105
|
appendFileSync5(correctionsPath, entry);
|
|
35744
36106
|
}
|
|
@@ -36052,6 +36414,7 @@ var init_knowledge_tools = __esm({
|
|
|
36052
36414
|
init_db2();
|
|
36053
36415
|
init_memory_db();
|
|
36054
36416
|
init_sql_table_names();
|
|
36417
|
+
init_hook_failure_signal();
|
|
36055
36418
|
KNOWLEDGE_BASE_NAMES = /* @__PURE__ */ new Set([
|
|
36056
36419
|
"knowledge_search",
|
|
36057
36420
|
"knowledge_rule",
|
|
@@ -36688,7 +37051,7 @@ var init_framework_supports = __esm({
|
|
|
36688
37051
|
|
|
36689
37052
|
// src/tools.ts
|
|
36690
37053
|
import { readFileSync as readFileSync57, existsSync as existsSync68 } from "fs";
|
|
36691
|
-
import { resolve as
|
|
37054
|
+
import { resolve as resolve42, basename as basename13 } from "path";
|
|
36692
37055
|
function prefix2() {
|
|
36693
37056
|
return getConfig().toolPrefix;
|
|
36694
37057
|
}
|
|
@@ -36723,7 +37086,7 @@ function ensureIndexes(dataDb, codegraphDb, force = false) {
|
|
|
36723
37086
|
if (config.python?.root) {
|
|
36724
37087
|
const pythonRoot = config.python.root;
|
|
36725
37088
|
const excludeDirs = config.python.exclude_dirs || ["__pycache__", ".venv", "venv", ".mypy_cache", ".pytest_cache"];
|
|
36726
|
-
if (force || isPythonDataStale(dataDb,
|
|
37089
|
+
if (force || isPythonDataStale(dataDb, resolve42(getProjectRoot(), pythonRoot))) {
|
|
36727
37090
|
const pyImports = buildPythonImportIndex(dataDb, pythonRoot, excludeDirs);
|
|
36728
37091
|
results.push(`Python imports: ${pyImports}`);
|
|
36729
37092
|
const pyRoutes = buildPythonRouteIndex(dataDb, pythonRoot, excludeDirs);
|
|
@@ -36946,7 +37309,7 @@ async function handleToolCall(name, args2, dataDb, codegraphDb, memoryDbCache, k
|
|
|
36946
37309
|
return withMemDb((memDb) => handleRegressionToolCall(name, args2, memDb));
|
|
36947
37310
|
}
|
|
36948
37311
|
if (isKnowledgeTool(name)) {
|
|
36949
|
-
return withKnowledgeDb((kdb) => handleKnowledgeToolCall(name, args2, kdb));
|
|
37312
|
+
return withKnowledgeDb((kdb) => handleKnowledgeToolCall(name, args2, kdb, "ensure-fresh"));
|
|
36950
37313
|
}
|
|
36951
37314
|
if (isPythonTool(name)) {
|
|
36952
37315
|
const pyDataDb = assertDataDb(dataDb, name);
|
|
@@ -37106,7 +37469,7 @@ function handleContext(file, dataDb, codegraphDb) {
|
|
|
37106
37469
|
try {
|
|
37107
37470
|
const resolvedPaths = getResolvedPaths();
|
|
37108
37471
|
const root = getProjectRoot();
|
|
37109
|
-
const absFilePath = ensureWithinRoot(
|
|
37472
|
+
const absFilePath = ensureWithinRoot(resolve42(resolvedPaths.srcDir, "..", file), root);
|
|
37110
37473
|
if (existsSync68(absFilePath)) {
|
|
37111
37474
|
const fileContent = readFileSync57(absFilePath, "utf-8").slice(0, 3e3);
|
|
37112
37475
|
const keywords = [];
|
|
@@ -37345,9 +37708,10 @@ function handleCouplingCheck(args2, dataDb, codegraphDb) {
|
|
|
37345
37708
|
lines.push("### Uncoupled Procedures: 0 (PASS)");
|
|
37346
37709
|
lines.push("");
|
|
37347
37710
|
}
|
|
37711
|
+
const pagesPred = pagesPredicate();
|
|
37348
37712
|
const allPages = codegraphDb.prepare(
|
|
37349
|
-
|
|
37350
|
-
).all();
|
|
37713
|
+
`SELECT path FROM files WHERE ${pagesPred.sql} LIMIT 10000`
|
|
37714
|
+
).all(...pagesPred.params);
|
|
37351
37715
|
const pageImports = /* @__PURE__ */ new Set();
|
|
37352
37716
|
for (const page of allPages) {
|
|
37353
37717
|
const imports = dataDb.prepare(
|
|
@@ -37360,9 +37724,10 @@ function handleCouplingCheck(args2, dataDb, codegraphDb) {
|
|
|
37360
37724
|
let componentFiles;
|
|
37361
37725
|
if (stagedFiles) {
|
|
37362
37726
|
const placeholders = stagedFiles.map(() => "?").join(",");
|
|
37727
|
+
const componentsPred = componentsPredicate();
|
|
37363
37728
|
componentFiles = codegraphDb.prepare(
|
|
37364
|
-
`SELECT path FROM files WHERE
|
|
37365
|
-
).all(...stagedFiles);
|
|
37729
|
+
`SELECT path FROM files WHERE ${componentsPred.sql} AND path IN (${placeholders}) LIMIT 10000`
|
|
37730
|
+
).all(...componentsPred.params, ...stagedFiles);
|
|
37366
37731
|
} else {
|
|
37367
37732
|
componentFiles = [];
|
|
37368
37733
|
}
|
|
@@ -37545,7 +37910,7 @@ function handleSchema(args2) {
|
|
|
37545
37910
|
lines.push("Checking all column references against Prisma schema...");
|
|
37546
37911
|
lines.push("");
|
|
37547
37912
|
const projectRoot = getProjectRoot();
|
|
37548
|
-
const absPath = ensureWithinRoot(
|
|
37913
|
+
const absPath = ensureWithinRoot(resolve42(projectRoot, file), projectRoot);
|
|
37549
37914
|
if (!existsSync68(absPath)) {
|
|
37550
37915
|
return text17(`File not found: ${file}`);
|
|
37551
37916
|
}
|
|
@@ -37624,6 +37989,7 @@ var init_tools = __esm({
|
|
|
37624
37989
|
init_framework_supports();
|
|
37625
37990
|
init_license();
|
|
37626
37991
|
init_sql_table_names();
|
|
37992
|
+
init_source_layout();
|
|
37627
37993
|
}
|
|
37628
37994
|
});
|
|
37629
37995
|
|
|
@@ -37982,7 +38348,7 @@ var init_startup_health = __esm({
|
|
|
37982
38348
|
// src/server.ts
|
|
37983
38349
|
var server_exports = {};
|
|
37984
38350
|
import { readFileSync as readFileSync58 } from "fs";
|
|
37985
|
-
import { resolve as
|
|
38351
|
+
import { resolve as resolve43, dirname as dirname28 } from "path";
|
|
37986
38352
|
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
37987
38353
|
function pruneMemoryOnStartup() {
|
|
37988
38354
|
try {
|
|
@@ -38030,7 +38396,7 @@ var init_server = __esm({
|
|
|
38030
38396
|
__dirname5 = dirname28(fileURLToPath6(import.meta.url));
|
|
38031
38397
|
PKG_VERSION = (() => {
|
|
38032
38398
|
try {
|
|
38033
|
-
const pkg = JSON.parse(readFileSync58(
|
|
38399
|
+
const pkg = JSON.parse(readFileSync58(resolve43(__dirname5, "..", "package.json"), "utf-8"));
|
|
38034
38400
|
return pkg.version ?? "0.0.0";
|
|
38035
38401
|
} catch {
|
|
38036
38402
|
return "0.0.0";
|
|
@@ -38333,12 +38699,12 @@ var config_upgrade_exports = {};
|
|
|
38333
38699
|
__export(config_upgrade_exports, {
|
|
38334
38700
|
runConfigUpgrade: () => runConfigUpgrade
|
|
38335
38701
|
});
|
|
38336
|
-
import { existsSync as existsSync69, readFileSync as readFileSync59, writeFileSync as
|
|
38337
|
-
import { resolve as
|
|
38702
|
+
import { existsSync as existsSync69, readFileSync as readFileSync59, writeFileSync as writeFileSync18, copyFileSync as copyFileSync3, unlinkSync as unlinkSync6 } from "fs";
|
|
38703
|
+
import { resolve as resolve44 } from "path";
|
|
38338
38704
|
import { parse as parseYaml6 } from "yaml";
|
|
38339
38705
|
async function runConfigUpgrade(opts = {}) {
|
|
38340
38706
|
const cwd = opts.cwd ?? process.cwd();
|
|
38341
|
-
const configPath =
|
|
38707
|
+
const configPath = resolve44(cwd, "massu.config.yaml");
|
|
38342
38708
|
const bakPath = `${configPath}.bak`;
|
|
38343
38709
|
const log = opts.silent ? () => {
|
|
38344
38710
|
} : (s) => process.stdout.write(s);
|
|
@@ -38392,7 +38758,7 @@ async function runConfigUpgrade(opts = {}) {
|
|
|
38392
38758
|
};
|
|
38393
38759
|
try {
|
|
38394
38760
|
const original = readFileSync59(configPath, "utf-8");
|
|
38395
|
-
|
|
38761
|
+
writeFileSync18(bakPath, original, "utf-8");
|
|
38396
38762
|
} catch (e2) {
|
|
38397
38763
|
const message = `Failed to write backup: ${e2 instanceof Error ? e2.message : String(e2)}`;
|
|
38398
38764
|
err(message + "\n");
|
|
@@ -38426,7 +38792,7 @@ __export(config_check_drift_exports, {
|
|
|
38426
38792
|
runConfigCheckDrift: () => runConfigCheckDrift
|
|
38427
38793
|
});
|
|
38428
38794
|
import { existsSync as existsSync70, readFileSync as readFileSync60 } from "fs";
|
|
38429
|
-
import { resolve as
|
|
38795
|
+
import { resolve as resolve45 } from "path";
|
|
38430
38796
|
import { parse as parseYaml7 } from "yaml";
|
|
38431
38797
|
function renderChanges(changes) {
|
|
38432
38798
|
if (changes.length === 0) return "(none)\n";
|
|
@@ -38434,7 +38800,7 @@ function renderChanges(changes) {
|
|
|
38434
38800
|
}
|
|
38435
38801
|
async function runConfigCheckDrift(opts = {}) {
|
|
38436
38802
|
const cwd = opts.cwd ?? process.cwd();
|
|
38437
|
-
const configPath =
|
|
38803
|
+
const configPath = resolve45(cwd, "massu.config.yaml");
|
|
38438
38804
|
const log = opts.silent ? () => {
|
|
38439
38805
|
} : (s) => process.stdout.write(s);
|
|
38440
38806
|
const err = opts.silent ? () => {
|
|
@@ -38521,7 +38887,7 @@ var init_config_check_drift = __esm({
|
|
|
38521
38887
|
|
|
38522
38888
|
// src/cli.ts
|
|
38523
38889
|
import { readFileSync as readFileSync61 } from "fs";
|
|
38524
|
-
import { resolve as
|
|
38890
|
+
import { resolve as resolve46, dirname as dirname29 } from "path";
|
|
38525
38891
|
import { fileURLToPath as fileURLToPath7 } from "url";
|
|
38526
38892
|
|
|
38527
38893
|
// src/lib/node-bootstrap.ts
|
|
@@ -39023,7 +39389,7 @@ Examples:
|
|
|
39023
39389
|
}
|
|
39024
39390
|
function printVersion() {
|
|
39025
39391
|
try {
|
|
39026
|
-
const pkg = JSON.parse(readFileSync61(
|
|
39392
|
+
const pkg = JSON.parse(readFileSync61(resolve46(__dirname6, "../package.json"), "utf-8"));
|
|
39027
39393
|
console.log(`massu v${pkg.version}`);
|
|
39028
39394
|
} catch {
|
|
39029
39395
|
console.log("massu v0.1.0");
|