@massu/core 2.0.0 → 2.2.0
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 +64 -0
- package/dist/cli.js +1183 -867
- package/dist/hooks/auto-learning-pipeline.js +1 -0
- package/dist/hooks/classify-failure.js +1 -0
- package/dist/hooks/cost-tracker.js +1 -0
- package/dist/hooks/fix-detector.js +1 -0
- package/dist/hooks/incident-pipeline.js +1 -0
- package/dist/hooks/intent-suggester.js +1 -0
- package/dist/hooks/memory-recall.js +1 -0
- package/dist/hooks/post-edit-context.js +1 -0
- package/dist/hooks/post-tool-use.js +1 -0
- package/dist/hooks/pre-compact.js +1 -0
- package/dist/hooks/pre-delete-check.js +1 -0
- package/dist/hooks/pre-tool-use-gate.js +1 -0
- package/dist/hooks/quality-event.js +1 -0
- package/dist/hooks/rule-enforcement-pipeline.js +1 -0
- package/dist/hooks/security-gate.js +1 -0
- package/dist/hooks/session-end.js +1 -0
- package/dist/hooks/session-start.js +1 -0
- package/dist/hooks/user-prompt.js +1 -0
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -49,27 +49,52 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
49
49
|
));
|
|
50
50
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
51
51
|
|
|
52
|
+
// src/lib/node-floor.ts
|
|
53
|
+
function checkNodeVersion(version = process.version) {
|
|
54
|
+
const [major, minor] = version.replace(/^v/, "").split(".").map((n) => Number.parseInt(n, 10));
|
|
55
|
+
if (!Number.isFinite(major)) {
|
|
56
|
+
return { ok: false, major: 0, message: `could not parse Node version "${version}"` };
|
|
57
|
+
}
|
|
58
|
+
const meets = major > MIN_NODE_MAJOR || major === MIN_NODE_MAJOR && (minor ?? 0) >= MIN_NODE_MINOR;
|
|
59
|
+
if (!meets) {
|
|
60
|
+
return {
|
|
61
|
+
ok: false,
|
|
62
|
+
major,
|
|
63
|
+
message: `Massu requires Node >= ${MIN_NODE_MAJOR}.${MIN_NODE_MINOR}.0 (its built-in node:sqlite engine). You are on ${version}.`
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
return { ok: true, major };
|
|
67
|
+
}
|
|
68
|
+
var MIN_NODE_MAJOR, MIN_NODE_MINOR;
|
|
69
|
+
var init_node_floor = __esm({
|
|
70
|
+
"src/lib/node-floor.ts"() {
|
|
71
|
+
"use strict";
|
|
72
|
+
MIN_NODE_MAJOR = 22;
|
|
73
|
+
MIN_NODE_MINOR = 13;
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
|
|
52
77
|
// src/credentials.ts
|
|
53
|
-
import { homedir } from "os";
|
|
54
|
-
import { resolve } from "path";
|
|
78
|
+
import { homedir as homedir2 } from "os";
|
|
79
|
+
import { resolve as resolve2 } from "path";
|
|
55
80
|
import {
|
|
56
|
-
existsSync,
|
|
81
|
+
existsSync as existsSync2,
|
|
57
82
|
readFileSync,
|
|
58
83
|
writeFileSync,
|
|
59
84
|
mkdirSync,
|
|
60
85
|
rmSync,
|
|
61
86
|
chmodSync
|
|
62
87
|
} from "fs";
|
|
63
|
-
function credentialsDir(home =
|
|
64
|
-
return
|
|
88
|
+
function credentialsDir(home = homedir2()) {
|
|
89
|
+
return resolve2(home, ".massu");
|
|
65
90
|
}
|
|
66
|
-
function credentialsPath(home =
|
|
67
|
-
return
|
|
91
|
+
function credentialsPath(home = homedir2()) {
|
|
92
|
+
return resolve2(credentialsDir(home), "credentials");
|
|
68
93
|
}
|
|
69
|
-
function readUserCredentials(home =
|
|
94
|
+
function readUserCredentials(home = homedir2()) {
|
|
70
95
|
try {
|
|
71
96
|
const p19 = credentialsPath(home);
|
|
72
|
-
if (!
|
|
97
|
+
if (!existsSync2(p19)) return void 0;
|
|
73
98
|
const parsed = JSON.parse(readFileSync(p19, "utf-8"));
|
|
74
99
|
const key = typeof parsed?.apiKey === "string" ? parsed.apiKey.trim() : "";
|
|
75
100
|
return key.length > 0 ? key : void 0;
|
|
@@ -77,7 +102,7 @@ function readUserCredentials(home = homedir()) {
|
|
|
77
102
|
return void 0;
|
|
78
103
|
}
|
|
79
104
|
}
|
|
80
|
-
function writeUserCredentials(apiKey, home =
|
|
105
|
+
function writeUserCredentials(apiKey, home = homedir2()) {
|
|
81
106
|
const dir = credentialsDir(home);
|
|
82
107
|
mkdirSync(dir, { recursive: true, mode: 448 });
|
|
83
108
|
try {
|
|
@@ -94,9 +119,9 @@ function writeUserCredentials(apiKey, home = homedir()) {
|
|
|
94
119
|
}
|
|
95
120
|
return p19;
|
|
96
121
|
}
|
|
97
|
-
function removeUserCredentials(home =
|
|
122
|
+
function removeUserCredentials(home = homedir2()) {
|
|
98
123
|
const p19 = credentialsPath(home);
|
|
99
|
-
if (!
|
|
124
|
+
if (!existsSync2(p19)) return false;
|
|
100
125
|
try {
|
|
101
126
|
rmSync(p19);
|
|
102
127
|
return true;
|
|
@@ -109,7 +134,7 @@ function isUnresolvedLiteral(v3) {
|
|
|
109
134
|
}
|
|
110
135
|
function resolveApiKey(opts = {}) {
|
|
111
136
|
const env = opts.env ?? process.env;
|
|
112
|
-
const home = opts.home ??
|
|
137
|
+
const home = opts.home ?? homedir2();
|
|
113
138
|
const cfg = typeof opts.configApiKey === "string" ? opts.configApiKey.trim() : "";
|
|
114
139
|
if (cfg.length > 0 && !isUnresolvedLiteral(cfg)) {
|
|
115
140
|
return { apiKey: cfg, source: "config" };
|
|
@@ -256,8 +281,8 @@ var init_fileLock = __esm({
|
|
|
256
281
|
|
|
257
282
|
// src/lib/sqlite-loader.ts
|
|
258
283
|
import { createRequire } from "module";
|
|
259
|
-
import { spawnSync } from "child_process";
|
|
260
|
-
import { accessSync, appendFileSync, chmodSync as chmodSync2, constants as fsConstants, existsSync as
|
|
284
|
+
import { spawnSync as spawnSync2 } from "child_process";
|
|
285
|
+
import { accessSync, appendFileSync, chmodSync as chmodSync2, constants as fsConstants, existsSync as existsSync3, mkdirSync as mkdirSync3 } from "fs";
|
|
261
286
|
import { dirname as dirname2, join } from "path";
|
|
262
287
|
function isNativeAbiError(err) {
|
|
263
288
|
const code = err?.code;
|
|
@@ -329,7 +354,7 @@ function probeMemoryDbUsable(opts = {}) {
|
|
|
329
354
|
};
|
|
330
355
|
}
|
|
331
356
|
const dbPath = opts.dbPath;
|
|
332
|
-
if (dbPath && dbPath !== ":memory:" &&
|
|
357
|
+
if (dbPath && dbPath !== ":memory:" && existsSync3(dbPath)) {
|
|
333
358
|
try {
|
|
334
359
|
const rdb = openDatabase(dbPath, { readonly: true, selfHeal: false });
|
|
335
360
|
try {
|
|
@@ -396,7 +421,7 @@ function runRebuild(pkgDir, abiFrom, abiTo, start) {
|
|
|
396
421
|
}
|
|
397
422
|
const prebuildBin = resolveLocalBin(pkgDir, "prebuild-install");
|
|
398
423
|
if (prebuildBin) {
|
|
399
|
-
const r2 =
|
|
424
|
+
const r2 = spawnSync2(process.execPath, [prebuildBin], {
|
|
400
425
|
cwd: pkgDir,
|
|
401
426
|
encoding: "utf-8",
|
|
402
427
|
timeout: 12e4
|
|
@@ -409,7 +434,7 @@ function runRebuild(pkgDir, abiFrom, abiTo, start) {
|
|
|
409
434
|
}
|
|
410
435
|
const gypBin = resolveNodeGypBin();
|
|
411
436
|
if (gypBin && hasCompiler()) {
|
|
412
|
-
const r2 =
|
|
437
|
+
const r2 = spawnSync2(process.execPath, [gypBin, "rebuild", "--release"], {
|
|
413
438
|
cwd: pkgDir,
|
|
414
439
|
encoding: "utf-8",
|
|
415
440
|
timeout: 3e5
|
|
@@ -479,7 +504,7 @@ function resolveLocalBin(pkgDir, name) {
|
|
|
479
504
|
// workspace hoist
|
|
480
505
|
];
|
|
481
506
|
for (const c2 of candidates) {
|
|
482
|
-
if (
|
|
507
|
+
if (existsSync3(c2)) return c2;
|
|
483
508
|
}
|
|
484
509
|
return void 0;
|
|
485
510
|
}
|
|
@@ -493,7 +518,7 @@ function resolveNodeGypBin() {
|
|
|
493
518
|
function hasCompiler() {
|
|
494
519
|
for (const cc of ["cc", "clang", "gcc"]) {
|
|
495
520
|
try {
|
|
496
|
-
const r2 =
|
|
521
|
+
const r2 = spawnSync2(cc, ["--version"], { encoding: "utf-8", timeout: 5e3 });
|
|
497
522
|
if (r2.status === 0) return true;
|
|
498
523
|
} catch {
|
|
499
524
|
}
|
|
@@ -529,7 +554,7 @@ var init_sqlite_loader = __esm({
|
|
|
529
554
|
|
|
530
555
|
// src/db-driver.ts
|
|
531
556
|
import { createRequire as createRequire2 } from "module";
|
|
532
|
-
import { closeSync, existsSync as
|
|
557
|
+
import { closeSync, existsSync as existsSync4, mkdtempSync, openSync, readFileSync as readFileSync3, rmSync as rmSync3, fsyncSync } from "fs";
|
|
533
558
|
import { tmpdir } from "os";
|
|
534
559
|
import { join as join2 } from "path";
|
|
535
560
|
function resolveDbEngine() {
|
|
@@ -664,7 +689,7 @@ function probeMemoryDbUsable2(opts = {}) {
|
|
|
664
689
|
};
|
|
665
690
|
}
|
|
666
691
|
const dbPath = opts.dbPath;
|
|
667
|
-
if (dbPath && dbPath !== ":memory:" &&
|
|
692
|
+
if (dbPath && dbPath !== ":memory:" && existsSync4(dbPath)) {
|
|
668
693
|
try {
|
|
669
694
|
const rdb = openDatabase2(dbPath, { readonly: true });
|
|
670
695
|
try {
|
|
@@ -882,16 +907,16 @@ __export(config_exports, {
|
|
|
882
907
|
getResolvedPaths: () => getResolvedPaths,
|
|
883
908
|
resetConfig: () => resetConfig
|
|
884
909
|
});
|
|
885
|
-
import { resolve as
|
|
886
|
-
import { existsSync as
|
|
887
|
-
import { homedir as
|
|
910
|
+
import { resolve as resolve3, dirname as dirname3 } from "path";
|
|
911
|
+
import { existsSync as existsSync5, readFileSync as readFileSync4 } from "fs";
|
|
912
|
+
import { homedir as homedir3 } from "os";
|
|
888
913
|
import { parse as parseYaml } from "yaml";
|
|
889
914
|
import { z as z2 } from "zod";
|
|
890
915
|
function findProjectRoot() {
|
|
891
916
|
const cwd = process.cwd();
|
|
892
917
|
let dir = cwd;
|
|
893
918
|
while (true) {
|
|
894
|
-
if (
|
|
919
|
+
if (existsSync5(resolve3(dir, "massu.config.yaml"))) {
|
|
895
920
|
return dir;
|
|
896
921
|
}
|
|
897
922
|
const parent = dirname3(dir);
|
|
@@ -900,10 +925,10 @@ function findProjectRoot() {
|
|
|
900
925
|
}
|
|
901
926
|
dir = cwd;
|
|
902
927
|
while (true) {
|
|
903
|
-
if (
|
|
928
|
+
if (existsSync5(resolve3(dir, "package.json"))) {
|
|
904
929
|
return dir;
|
|
905
930
|
}
|
|
906
|
-
if (
|
|
931
|
+
if (existsSync5(resolve3(dir, ".git"))) {
|
|
907
932
|
return dir;
|
|
908
933
|
}
|
|
909
934
|
const parent = dirname3(dir);
|
|
@@ -921,9 +946,9 @@ function getProjectRoot() {
|
|
|
921
946
|
function getConfig() {
|
|
922
947
|
if (_config) return _config;
|
|
923
948
|
const root = getProjectRoot();
|
|
924
|
-
const configPath =
|
|
949
|
+
const configPath = resolve3(root, "massu.config.yaml");
|
|
925
950
|
let rawYaml = {};
|
|
926
|
-
if (
|
|
951
|
+
if (existsSync5(configPath)) {
|
|
927
952
|
const content = readFileSync4(configPath, "utf-8");
|
|
928
953
|
rawYaml = parseYaml(content) ?? {};
|
|
929
954
|
}
|
|
@@ -941,7 +966,7 @@ Hint: run \`massu config refresh\` to regenerate a valid config or fix the liste
|
|
|
941
966
|
);
|
|
942
967
|
}
|
|
943
968
|
const parsed = result.data;
|
|
944
|
-
const projectRoot = parsed.project.root === "auto" || !parsed.project.root ? root :
|
|
969
|
+
const projectRoot = parsed.project.root === "auto" || !parsed.project.root ? root : resolve3(root, parsed.project.root);
|
|
945
970
|
const fw = parsed.framework;
|
|
946
971
|
let router = fw.router;
|
|
947
972
|
let orm = fw.orm;
|
|
@@ -1029,34 +1054,35 @@ function getResolvedPaths() {
|
|
|
1029
1054
|
const root = getProjectRoot();
|
|
1030
1055
|
const claudeDirName = config.conventions?.claudeDirName ?? ".claude";
|
|
1031
1056
|
return {
|
|
1032
|
-
codegraphDbPath:
|
|
1033
|
-
dataDbPath:
|
|
1034
|
-
prismaSchemaPath:
|
|
1035
|
-
rootRouterPath:
|
|
1036
|
-
routersDir:
|
|
1037
|
-
srcDir:
|
|
1057
|
+
codegraphDbPath: resolve3(root, ".codegraph/codegraph.db"),
|
|
1058
|
+
dataDbPath: resolve3(root, ".massu/data.db"),
|
|
1059
|
+
prismaSchemaPath: resolve3(root, config.paths.schema ?? "prisma/schema.prisma"),
|
|
1060
|
+
rootRouterPath: resolve3(root, config.paths.routerRoot ?? "src/server/api/root.ts"),
|
|
1061
|
+
routersDir: resolve3(root, config.paths.routers ?? "src/server/api/routers"),
|
|
1062
|
+
srcDir: resolve3(root, config.paths.source),
|
|
1038
1063
|
pathAlias: Object.fromEntries(
|
|
1039
1064
|
Object.entries(config.paths.aliases).map(([alias, target]) => [
|
|
1040
1065
|
alias,
|
|
1041
|
-
|
|
1066
|
+
resolve3(root, target)
|
|
1042
1067
|
])
|
|
1043
1068
|
),
|
|
1044
1069
|
extensions: [".ts", ".tsx", ".js", ".jsx"],
|
|
1045
1070
|
indexFiles: ["index.ts", "index.tsx", "index.js", "index.jsx"],
|
|
1046
|
-
patternsDir:
|
|
1047
|
-
claudeMdPath:
|
|
1048
|
-
docsMapPath:
|
|
1049
|
-
helpSitePath:
|
|
1050
|
-
memoryDbPath:
|
|
1051
|
-
knowledgeDbPath:
|
|
1052
|
-
plansDir:
|
|
1053
|
-
docsDir:
|
|
1054
|
-
claudeDir:
|
|
1055
|
-
memoryDir:
|
|
1056
|
-
sessionStatePath:
|
|
1057
|
-
sessionArchivePath:
|
|
1058
|
-
mcpJsonPath:
|
|
1059
|
-
|
|
1071
|
+
patternsDir: resolve3(root, claudeDirName, "patterns"),
|
|
1072
|
+
claudeMdPath: resolve3(root, claudeDirName, "CLAUDE.md"),
|
|
1073
|
+
docsMapPath: resolve3(root, ".massu/docs-map.json"),
|
|
1074
|
+
helpSitePath: resolve3(root, "../" + config.project.name + "-help"),
|
|
1075
|
+
memoryDbPath: resolve3(root, ".massu/memory.db"),
|
|
1076
|
+
knowledgeDbPath: resolve3(root, ".massu/knowledge.db"),
|
|
1077
|
+
plansDir: resolve3(root, "docs/plans"),
|
|
1078
|
+
docsDir: resolve3(root, "docs"),
|
|
1079
|
+
claudeDir: resolve3(root, claudeDirName),
|
|
1080
|
+
memoryDir: resolve3(homedir3(), claudeDirName, "projects", encodeMemoryDirName(root), "memory"),
|
|
1081
|
+
sessionStatePath: resolve3(root, config.conventions?.sessionStatePath ?? `${claudeDirName}/session-state/CURRENT.md`),
|
|
1082
|
+
sessionArchivePath: resolve3(root, config.conventions?.sessionArchivePath ?? `${claudeDirName}/session-state/archive`),
|
|
1083
|
+
mcpJsonPath: resolve3(root, ".mcp.json"),
|
|
1084
|
+
settingsPath: resolve3(root, claudeDirName, "settings.json"),
|
|
1085
|
+
settingsLocalPath: resolve3(root, claudeDirName, "settings.local.json")
|
|
1060
1086
|
};
|
|
1061
1087
|
}
|
|
1062
1088
|
function resetConfig() {
|
|
@@ -1512,39 +1538,39 @@ var init_memory_vector = __esm({
|
|
|
1512
1538
|
});
|
|
1513
1539
|
|
|
1514
1540
|
// src/db-backup.ts
|
|
1515
|
-
import { existsSync as
|
|
1516
|
-
import { resolve as
|
|
1517
|
-
import { homedir as
|
|
1518
|
-
function dbBackupsRoot(home =
|
|
1519
|
-
return
|
|
1541
|
+
import { existsSync as existsSync6, mkdirSync as mkdirSync4, readdirSync as readdirSync2, statSync as statSync2, unlinkSync, copyFileSync, rmSync as rmSync4 } from "fs";
|
|
1542
|
+
import { resolve as resolve4, join as join3, basename, dirname as dirname4 } from "path";
|
|
1543
|
+
import { homedir as homedir4 } from "os";
|
|
1544
|
+
function dbBackupsRoot(home = homedir4()) {
|
|
1545
|
+
return resolve4(home, ".massu", "db-backups");
|
|
1520
1546
|
}
|
|
1521
|
-
function projectBackupDir(projectRoot, home =
|
|
1547
|
+
function projectBackupDir(projectRoot, home = homedir4()) {
|
|
1522
1548
|
const slug = basename(projectRoot).replace(/[^A-Za-z0-9._-]/g, "_") || "project";
|
|
1523
1549
|
return join3(dbBackupsRoot(home), slug);
|
|
1524
1550
|
}
|
|
1525
1551
|
function backupStamp(nowMs) {
|
|
1526
1552
|
return new Date(nowMs).toISOString().replace(/[:.]/g, "-");
|
|
1527
1553
|
}
|
|
1528
|
-
function listDbBackups(projectRoot, home =
|
|
1554
|
+
function listDbBackups(projectRoot, home = homedir4()) {
|
|
1529
1555
|
const dir = projectBackupDir(projectRoot, home);
|
|
1530
|
-
if (!
|
|
1556
|
+
if (!existsSync6(dir)) return [];
|
|
1531
1557
|
const out = [];
|
|
1532
|
-
for (const f2 of
|
|
1558
|
+
for (const f2 of readdirSync2(dir)) {
|
|
1533
1559
|
if (!f2.endsWith(".db")) continue;
|
|
1534
1560
|
const p19 = join3(dir, f2);
|
|
1535
|
-
const st =
|
|
1561
|
+
const st = statSync2(p19);
|
|
1536
1562
|
const db = f2.replace(/-\d{4}-\d{2}-\d{2}T.*$/, "");
|
|
1537
1563
|
out.push({ db, path: p19, bytes: st.size, mtimeMs: st.mtimeMs });
|
|
1538
1564
|
}
|
|
1539
1565
|
return out.sort((a2, b2) => b2.mtimeMs - a2.mtimeMs);
|
|
1540
1566
|
}
|
|
1541
|
-
function hasFreshDbBackup(projectRoot, dbPath, nowMs = Date.now(), home =
|
|
1567
|
+
function hasFreshDbBackup(projectRoot, dbPath, nowMs = Date.now(), home = homedir4()) {
|
|
1542
1568
|
const name = basename(dbPath, ".db");
|
|
1543
1569
|
const backups = listDbBackups(projectRoot, home).filter((b2) => b2.db === name);
|
|
1544
1570
|
if (backups.length === 0) return false;
|
|
1545
1571
|
const newest = backups[0];
|
|
1546
1572
|
if (nowMs - newest.mtimeMs > FRESH_WINDOW_MS) return false;
|
|
1547
|
-
if (
|
|
1573
|
+
if (existsSync6(dbPath) && statSync2(dbPath).mtimeMs > newest.mtimeMs) return false;
|
|
1548
1574
|
return true;
|
|
1549
1575
|
}
|
|
1550
1576
|
function integrityOk(dbPath) {
|
|
@@ -1562,8 +1588,8 @@ function integrityOk(dbPath) {
|
|
|
1562
1588
|
}
|
|
1563
1589
|
}
|
|
1564
1590
|
}
|
|
1565
|
-
function backupDb(projectRoot, dbPath, nowMs = Date.now(), home =
|
|
1566
|
-
if (!
|
|
1591
|
+
function backupDb(projectRoot, dbPath, nowMs = Date.now(), home = homedir4()) {
|
|
1592
|
+
if (!existsSync6(dbPath)) {
|
|
1567
1593
|
throw new DbBackupError(`cannot back up a database that does not exist: ${dbPath}`);
|
|
1568
1594
|
}
|
|
1569
1595
|
const dir = projectBackupDir(projectRoot, home);
|
|
@@ -1594,10 +1620,10 @@ function backupDb(projectRoot, dbPath, nowMs = Date.now(), home = homedir3()) {
|
|
|
1594
1620
|
);
|
|
1595
1621
|
}
|
|
1596
1622
|
pruneDbBackups(projectRoot, name, DEFAULT_RETENTION, home);
|
|
1597
|
-
const st =
|
|
1623
|
+
const st = statSync2(dest);
|
|
1598
1624
|
return { db: name, path: dest, bytes: st.size, mtimeMs: st.mtimeMs };
|
|
1599
1625
|
}
|
|
1600
|
-
function pruneDbBackups(projectRoot, dbName, keep = DEFAULT_RETENTION, home =
|
|
1626
|
+
function pruneDbBackups(projectRoot, dbName, keep = DEFAULT_RETENTION, home = homedir4()) {
|
|
1601
1627
|
const mine = listDbBackups(projectRoot, home).filter((b2) => b2.db === dbName);
|
|
1602
1628
|
let removed = 0;
|
|
1603
1629
|
for (const old of mine.slice(keep)) {
|
|
@@ -1609,8 +1635,8 @@ function pruneDbBackups(projectRoot, dbName, keep = DEFAULT_RETENTION, home = ho
|
|
|
1609
1635
|
}
|
|
1610
1636
|
return removed;
|
|
1611
1637
|
}
|
|
1612
|
-
function restoreDb(backupPath, dbPath, nowMs = Date.now(), home =
|
|
1613
|
-
if (!
|
|
1638
|
+
function restoreDb(backupPath, dbPath, nowMs = Date.now(), home = homedir4()) {
|
|
1639
|
+
if (!existsSync6(backupPath)) {
|
|
1614
1640
|
throw new DbBackupError(`backup not found: ${backupPath}`);
|
|
1615
1641
|
}
|
|
1616
1642
|
if (!integrityOk(backupPath)) {
|
|
@@ -1619,7 +1645,7 @@ function restoreDb(backupPath, dbPath, nowMs = Date.now(), home = homedir3()) {
|
|
|
1619
1645
|
);
|
|
1620
1646
|
}
|
|
1621
1647
|
let preserved = null;
|
|
1622
|
-
if (
|
|
1648
|
+
if (existsSync6(dbPath)) {
|
|
1623
1649
|
const dir = dirname4(backupPath) || projectBackupDir(process.cwd(), home);
|
|
1624
1650
|
mkdirSync4(dir, { recursive: true });
|
|
1625
1651
|
preserved = join3(dir, `${basename(dbPath, ".db")}.corrupt-${backupStamp(nowMs)}.db`);
|
|
@@ -1627,7 +1653,7 @@ function restoreDb(backupPath, dbPath, nowMs = Date.now(), home = homedir3()) {
|
|
|
1627
1653
|
}
|
|
1628
1654
|
for (const suffix of ["", "-wal", "-shm"]) {
|
|
1629
1655
|
const p19 = `${dbPath}${suffix}`;
|
|
1630
|
-
if (
|
|
1656
|
+
if (existsSync6(p19)) rmSync4(p19, { force: true });
|
|
1631
1657
|
}
|
|
1632
1658
|
copyFileSync(backupPath, dbPath);
|
|
1633
1659
|
if (!integrityOk(dbPath)) {
|
|
@@ -1637,9 +1663,9 @@ function restoreDb(backupPath, dbPath, nowMs = Date.now(), home = homedir3()) {
|
|
|
1637
1663
|
}
|
|
1638
1664
|
return { restoredFrom: backupPath, preservedOriginal: preserved };
|
|
1639
1665
|
}
|
|
1640
|
-
function backupBeforeSchemaChange(projectRoot, dbPath, onError, nowMs = Date.now(), home =
|
|
1666
|
+
function backupBeforeSchemaChange(projectRoot, dbPath, onError, nowMs = Date.now(), home = homedir4()) {
|
|
1641
1667
|
try {
|
|
1642
|
-
if (!
|
|
1668
|
+
if (!existsSync6(dbPath)) return null;
|
|
1643
1669
|
if (hasFreshDbBackup(projectRoot, dbPath, nowMs, home)) return null;
|
|
1644
1670
|
return backupDb(projectRoot, dbPath, nowMs, home);
|
|
1645
1671
|
} catch (err) {
|
|
@@ -1814,14 +1840,14 @@ var init_rule_candidate_store = __esm({
|
|
|
1814
1840
|
});
|
|
1815
1841
|
|
|
1816
1842
|
// src/hooks/lib/hook-failure-signal.ts
|
|
1817
|
-
import { appendFileSync as appendFileSync2, mkdirSync as mkdirSync5, existsSync as
|
|
1843
|
+
import { appendFileSync as appendFileSync2, mkdirSync as mkdirSync5, existsSync as existsSync7 } from "fs";
|
|
1818
1844
|
import { join as join4, dirname as dirname5 } from "path";
|
|
1819
1845
|
function resolveFailureLogPath() {
|
|
1820
1846
|
const explicit = process.env.MASSU_HOOK_FAILURE_LOG;
|
|
1821
1847
|
if (explicit) return explicit;
|
|
1822
1848
|
let dir = process.cwd();
|
|
1823
1849
|
for (let i = 0; i < 12; i++) {
|
|
1824
|
-
if (
|
|
1850
|
+
if (existsSync7(join4(dir, ".massu")) || existsSync7(join4(dir, "massu.config.yaml"))) {
|
|
1825
1851
|
return join4(dir, ".massu", "hook-failures.jsonl");
|
|
1826
1852
|
}
|
|
1827
1853
|
const parent = dirname5(dir);
|
|
@@ -2008,7 +2034,7 @@ var init_memory_embedder_tokenizer = __esm({
|
|
|
2008
2034
|
// src/memory-embedder.ts
|
|
2009
2035
|
import { fileURLToPath } from "url";
|
|
2010
2036
|
import { dirname as dirname6, join as join5 } from "path";
|
|
2011
|
-
import { existsSync as
|
|
2037
|
+
import { existsSync as existsSync8 } from "fs";
|
|
2012
2038
|
import { createRequire as createRequire3 } from "module";
|
|
2013
2039
|
function getActiveEmbedModel() {
|
|
2014
2040
|
return _activeModel;
|
|
@@ -2033,7 +2059,7 @@ function resolveModelDir() {
|
|
|
2033
2059
|
let dir = dirname6(fileURLToPath(import.meta.url));
|
|
2034
2060
|
let root = null;
|
|
2035
2061
|
for (let i = 0; i < 8; i++) {
|
|
2036
|
-
if (
|
|
2062
|
+
if (existsSync8(join5(dir, "package.json"))) {
|
|
2037
2063
|
root = dir;
|
|
2038
2064
|
break;
|
|
2039
2065
|
}
|
|
@@ -2044,7 +2070,7 @@ function resolveModelDir() {
|
|
|
2044
2070
|
if (!root) return null;
|
|
2045
2071
|
for (const rel of ["dist/embedder", "assets/embedder"]) {
|
|
2046
2072
|
const candidate = join5(root, rel);
|
|
2047
|
-
if (
|
|
2073
|
+
if (existsSync8(join5(candidate, "model_quantized.onnx"))) return candidate;
|
|
2048
2074
|
}
|
|
2049
2075
|
return null;
|
|
2050
2076
|
} catch {
|
|
@@ -2430,7 +2456,7 @@ __export(memory_db_exports, {
|
|
|
2430
2456
|
usageWarmupElapsed: () => usageWarmupElapsed
|
|
2431
2457
|
});
|
|
2432
2458
|
import { dirname as dirname7, basename as basename2 } from "path";
|
|
2433
|
-
import { existsSync as
|
|
2459
|
+
import { existsSync as existsSync9, mkdirSync as mkdirSync6 } from "fs";
|
|
2434
2460
|
function sanitizeFts5Query(raw) {
|
|
2435
2461
|
const trimmed = raw.trim();
|
|
2436
2462
|
if (!trimmed) return '""';
|
|
@@ -2447,10 +2473,10 @@ function sanitizeFts5QueryOr(raw) {
|
|
|
2447
2473
|
function getMemoryDb() {
|
|
2448
2474
|
const dbPath = getResolvedPaths().memoryDbPath;
|
|
2449
2475
|
const dir = dirname7(dbPath);
|
|
2450
|
-
if (!
|
|
2476
|
+
if (!existsSync9(dir)) {
|
|
2451
2477
|
mkdirSync6(dir, { recursive: true });
|
|
2452
2478
|
}
|
|
2453
|
-
const preExisting =
|
|
2479
|
+
const preExisting = existsSync9(dbPath);
|
|
2454
2480
|
const db = openDatabase2(dbPath);
|
|
2455
2481
|
db.pragma("journal_mode = WAL");
|
|
2456
2482
|
db.pragma("foreign_keys = ON");
|
|
@@ -4238,7 +4264,7 @@ var init_memory_db = __esm({
|
|
|
4238
4264
|
});
|
|
4239
4265
|
|
|
4240
4266
|
// src/memory-file-ingest.ts
|
|
4241
|
-
import { readFileSync as readFileSync6, existsSync as
|
|
4267
|
+
import { readFileSync as readFileSync6, existsSync as existsSync10, readdirSync as readdirSync3 } from "fs";
|
|
4242
4268
|
import { join as join6 } from "path";
|
|
4243
4269
|
import { parse as parseYaml2 } from "yaml";
|
|
4244
4270
|
import { basename as pathBasename } from "path";
|
|
@@ -4345,7 +4371,7 @@ function upsertMemoryFileMirror(db, f2) {
|
|
|
4345
4371
|
return "inserted";
|
|
4346
4372
|
}
|
|
4347
4373
|
function ingestMemoryFile(db, sessionId, filePath) {
|
|
4348
|
-
if (!
|
|
4374
|
+
if (!existsSync10(filePath)) return "skipped";
|
|
4349
4375
|
const content = readFileSync6(filePath, "utf-8");
|
|
4350
4376
|
if (Buffer.byteLength(content, "utf-8") > MAX_MEMORY_FILE_BYTES) {
|
|
4351
4377
|
process.stderr.write(
|
|
@@ -4416,8 +4442,8 @@ ${body}` : body;
|
|
|
4416
4442
|
}
|
|
4417
4443
|
function backfillMemoryFiles(db, memoryDir, sessionId) {
|
|
4418
4444
|
const stats = { inserted: 0, updated: 0, skipped: 0, total: 0 };
|
|
4419
|
-
if (!
|
|
4420
|
-
const files =
|
|
4445
|
+
if (!existsSync10(memoryDir)) return stats;
|
|
4446
|
+
const files = readdirSync3(memoryDir).filter(
|
|
4421
4447
|
(f2) => f2.endsWith(".md") && f2 !== "MEMORY.md"
|
|
4422
4448
|
);
|
|
4423
4449
|
stats.total = files.length;
|
|
@@ -4632,7 +4658,7 @@ var init_template_engine = __esm({
|
|
|
4632
4658
|
// src/lib/settings-local.ts
|
|
4633
4659
|
import {
|
|
4634
4660
|
closeSync as closeSync2,
|
|
4635
|
-
existsSync as
|
|
4661
|
+
existsSync as existsSync11,
|
|
4636
4662
|
fsyncSync as fsyncSync2,
|
|
4637
4663
|
mkdirSync as mkdirSync7,
|
|
4638
4664
|
openSync as openSync2,
|
|
@@ -4641,7 +4667,7 @@ import {
|
|
|
4641
4667
|
rmSync as rmSync5,
|
|
4642
4668
|
writeSync
|
|
4643
4669
|
} from "fs";
|
|
4644
|
-
import { dirname as dirname8, resolve as
|
|
4670
|
+
import { dirname as dirname8, resolve as resolve6 } from "path";
|
|
4645
4671
|
function atomicWriteFile(targetPath, content, mode = 420) {
|
|
4646
4672
|
const tmpPath = `${targetPath}.${process.pid}.tmp`;
|
|
4647
4673
|
try {
|
|
@@ -4655,7 +4681,7 @@ function atomicWriteFile(targetPath, content, mode = 420) {
|
|
|
4655
4681
|
}
|
|
4656
4682
|
renameSync(tmpPath, targetPath);
|
|
4657
4683
|
} catch (err) {
|
|
4658
|
-
if (
|
|
4684
|
+
if (existsSync11(tmpPath)) {
|
|
4659
4685
|
try {
|
|
4660
4686
|
rmSync5(tmpPath, { force: true });
|
|
4661
4687
|
} catch {
|
|
@@ -4665,7 +4691,7 @@ function atomicWriteFile(targetPath, content, mode = 420) {
|
|
|
4665
4691
|
}
|
|
4666
4692
|
}
|
|
4667
4693
|
function readSettingsAtPath(absolutePath) {
|
|
4668
|
-
if (!
|
|
4694
|
+
if (!existsSync11(absolutePath)) {
|
|
4669
4695
|
return {};
|
|
4670
4696
|
}
|
|
4671
4697
|
try {
|
|
@@ -4680,12 +4706,12 @@ function readSettingsAtPath(absolutePath) {
|
|
|
4680
4706
|
}
|
|
4681
4707
|
}
|
|
4682
4708
|
function readSettingsLocal(claudeDir) {
|
|
4683
|
-
return readSettingsAtPath(
|
|
4709
|
+
return readSettingsAtPath(resolve6(claudeDir, "settings.local.json"));
|
|
4684
4710
|
}
|
|
4685
4711
|
function writeSettingsLocalAtomic(claudeDir, settings) {
|
|
4686
|
-
const targetPath =
|
|
4712
|
+
const targetPath = resolve6(claudeDir, "settings.local.json");
|
|
4687
4713
|
const dir = dirname8(targetPath);
|
|
4688
|
-
if (!
|
|
4714
|
+
if (!existsSync11(dir)) {
|
|
4689
4715
|
mkdirSync7(dir, { recursive: true });
|
|
4690
4716
|
}
|
|
4691
4717
|
const content = JSON.stringify(settings, null, 2) + "\n";
|
|
@@ -4699,7 +4725,7 @@ var init_settings_local = __esm({
|
|
|
4699
4725
|
|
|
4700
4726
|
// src/permissions.ts
|
|
4701
4727
|
import { createHash as createHash2 } from "crypto";
|
|
4702
|
-
import { homedir as
|
|
4728
|
+
import { homedir as homedir5 } from "os";
|
|
4703
4729
|
import { join as join7 } from "path";
|
|
4704
4730
|
function canonicalJson(value) {
|
|
4705
4731
|
if (value === null || typeof value !== "object") {
|
|
@@ -4739,7 +4765,7 @@ function detectInvalidDefaultMode(settings) {
|
|
|
4739
4765
|
return { invalid: false };
|
|
4740
4766
|
}
|
|
4741
4767
|
function readGlobalSettings() {
|
|
4742
|
-
return readSettingsAtPath(join7(
|
|
4768
|
+
return readSettingsAtPath(join7(homedir5(), ".claude", "settings.json"));
|
|
4743
4769
|
}
|
|
4744
4770
|
function mergedPermissionState(global2, local, canonical2) {
|
|
4745
4771
|
const globalPerm = global2.permissions ?? {};
|
|
@@ -4927,20 +4953,20 @@ __export(install_commands_exports, {
|
|
|
4927
4953
|
syncDirectory: () => syncDirectory
|
|
4928
4954
|
});
|
|
4929
4955
|
import {
|
|
4930
|
-
existsSync as
|
|
4956
|
+
existsSync as existsSync12,
|
|
4931
4957
|
readFileSync as readFileSync8,
|
|
4932
4958
|
mkdirSync as mkdirSync8,
|
|
4933
|
-
readdirSync as
|
|
4934
|
-
statSync as
|
|
4959
|
+
readdirSync as readdirSync4,
|
|
4960
|
+
statSync as statSync3
|
|
4935
4961
|
} from "fs";
|
|
4936
|
-
import { resolve as
|
|
4962
|
+
import { resolve as resolve7, dirname as dirname9, join as join8 } from "path";
|
|
4937
4963
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
4938
4964
|
import { createHash as createHash3 } from "crypto";
|
|
4939
4965
|
function dirHoldsAssets(dir) {
|
|
4940
|
-
if (!
|
|
4966
|
+
if (!existsSync12(dir)) return false;
|
|
4941
4967
|
try {
|
|
4942
|
-
return
|
|
4943
|
-
(e2) => e2.endsWith(".md") ||
|
|
4968
|
+
return readdirSync4(dir).some(
|
|
4969
|
+
(e2) => e2.endsWith(".md") || statSync3(resolve7(dir, e2)).isDirectory()
|
|
4944
4970
|
);
|
|
4945
4971
|
} catch {
|
|
4946
4972
|
return false;
|
|
@@ -4950,11 +4976,11 @@ function resolveAssetDir(assetName) {
|
|
|
4950
4976
|
const cwd = process.cwd();
|
|
4951
4977
|
const candidates = [
|
|
4952
4978
|
// 1. npm-installed: node_modules/@massu/core/{assetName}
|
|
4953
|
-
|
|
4979
|
+
resolve7(cwd, "node_modules/@massu/core", assetName),
|
|
4954
4980
|
// 2. Relative to compiled dist/cli.js → ../{assetName}
|
|
4955
|
-
|
|
4981
|
+
resolve7(__dirname, "..", assetName),
|
|
4956
4982
|
// 3. Relative to source src/commands/ → ../../{assetName}
|
|
4957
|
-
|
|
4983
|
+
resolve7(__dirname, "../..", assetName)
|
|
4958
4984
|
];
|
|
4959
4985
|
for (const c2 of candidates) {
|
|
4960
4986
|
if (dirHoldsAssets(c2)) return c2;
|
|
@@ -4972,7 +4998,7 @@ function canonicalizeOwned(content) {
|
|
|
4972
4998
|
}
|
|
4973
4999
|
function massuOwnedSourceIsValid(resolvedSourcePath, content) {
|
|
4974
5000
|
const sidecar = `${resolvedSourcePath}.sha256`;
|
|
4975
|
-
if (!
|
|
5001
|
+
if (!existsSync12(sidecar)) return false;
|
|
4976
5002
|
let expected;
|
|
4977
5003
|
try {
|
|
4978
5004
|
expected = readFileSync8(sidecar, "utf-8").trim();
|
|
@@ -4985,8 +5011,8 @@ function hashContent(content) {
|
|
|
4985
5011
|
return createHash3("sha256").update(content, "utf-8").digest("hex");
|
|
4986
5012
|
}
|
|
4987
5013
|
function loadManifest(claudeDir) {
|
|
4988
|
-
const path =
|
|
4989
|
-
if (!
|
|
5014
|
+
const path = resolve7(claudeDir, MANIFEST_RELPATH);
|
|
5015
|
+
if (!existsSync12(path)) {
|
|
4990
5016
|
return emptyManifest();
|
|
4991
5017
|
}
|
|
4992
5018
|
try {
|
|
@@ -5001,11 +5027,11 @@ function loadManifest(claudeDir) {
|
|
|
5001
5027
|
}
|
|
5002
5028
|
}
|
|
5003
5029
|
function saveManifest(claudeDir, manifest) {
|
|
5004
|
-
const dir =
|
|
5005
|
-
if (!
|
|
5030
|
+
const dir = resolve7(claudeDir, ".massu");
|
|
5031
|
+
if (!existsSync12(dir)) {
|
|
5006
5032
|
mkdirSync8(dir, { recursive: true });
|
|
5007
5033
|
}
|
|
5008
|
-
const finalPath =
|
|
5034
|
+
const finalPath = resolve7(dir, "install-manifest.json");
|
|
5009
5035
|
manifest.generatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
5010
5036
|
atomicWriteFile(finalPath, JSON.stringify(manifest, null, 2));
|
|
5011
5037
|
}
|
|
@@ -5067,18 +5093,18 @@ function pickVariant(baseName, sourceDir, framework) {
|
|
|
5067
5093
|
}
|
|
5068
5094
|
for (const cand of candidates) {
|
|
5069
5095
|
if (cand.subFramework) {
|
|
5070
|
-
const subPath =
|
|
5071
|
-
if (
|
|
5096
|
+
const subPath = resolve7(sourceDir, `${baseName}.${cand.lang}-${cand.subFramework}.md`);
|
|
5097
|
+
if (existsSync12(subPath)) {
|
|
5072
5098
|
return { kind: "hit", suffix: `.${cand.lang}-${cand.subFramework}` };
|
|
5073
5099
|
}
|
|
5074
5100
|
}
|
|
5075
|
-
const langPath =
|
|
5076
|
-
if (
|
|
5101
|
+
const langPath = resolve7(sourceDir, `${baseName}.${cand.lang}.md`);
|
|
5102
|
+
if (existsSync12(langPath)) {
|
|
5077
5103
|
return { kind: "hit", suffix: `.${cand.lang}` };
|
|
5078
5104
|
}
|
|
5079
5105
|
}
|
|
5080
|
-
const defaultPath =
|
|
5081
|
-
if (
|
|
5106
|
+
const defaultPath = resolve7(sourceDir, `${baseName}.md`);
|
|
5107
|
+
if (existsSync12(defaultPath)) {
|
|
5082
5108
|
return { kind: "hit", suffix: "" };
|
|
5083
5109
|
}
|
|
5084
5110
|
if (framework.type === "multi" && !framework.primary) {
|
|
@@ -5094,15 +5120,15 @@ function isVariantFilename(entry) {
|
|
|
5094
5120
|
}
|
|
5095
5121
|
function syncDirectory(sourceDir, targetDir, framework, manifest, manifestKeyPrefix, topLevel = true, templateVars = {}) {
|
|
5096
5122
|
const stats = { installed: 0, updated: 0, skipped: 0, kept: 0 };
|
|
5097
|
-
if (!
|
|
5123
|
+
if (!existsSync12(targetDir)) {
|
|
5098
5124
|
mkdirSync8(targetDir, { recursive: true });
|
|
5099
5125
|
}
|
|
5100
|
-
const entries =
|
|
5126
|
+
const entries = readdirSync4(sourceDir);
|
|
5101
5127
|
for (const entry of entries) {
|
|
5102
|
-
const sourcePath =
|
|
5103
|
-
const entryStat =
|
|
5128
|
+
const sourcePath = resolve7(sourceDir, entry);
|
|
5129
|
+
const entryStat = statSync3(sourcePath);
|
|
5104
5130
|
if (entryStat.isDirectory()) {
|
|
5105
|
-
const subTargetDir =
|
|
5131
|
+
const subTargetDir = resolve7(targetDir, entry);
|
|
5106
5132
|
const subPrefix = manifestKeyPrefix === "" ? entry : `${manifestKeyPrefix}/${entry}`;
|
|
5107
5133
|
const subStats = syncDirectory(
|
|
5108
5134
|
sourcePath,
|
|
@@ -5131,12 +5157,12 @@ function syncDirectory(sourceDir, targetDir, framework, manifest, manifestKeyPre
|
|
|
5131
5157
|
const suffix = choice.kind === "hit" ? choice.suffix : "";
|
|
5132
5158
|
sourceFilename = suffix === "" ? `${baseName}.md` : `${baseName}${suffix}.md`;
|
|
5133
5159
|
}
|
|
5134
|
-
const resolvedSourcePath =
|
|
5135
|
-
if (!
|
|
5160
|
+
const resolvedSourcePath = resolve7(sourceDir, sourceFilename);
|
|
5161
|
+
if (!existsSync12(resolvedSourcePath)) {
|
|
5136
5162
|
continue;
|
|
5137
5163
|
}
|
|
5138
5164
|
const targetFilename = topLevel ? `${baseName}.md` : entry;
|
|
5139
|
-
const targetPath =
|
|
5165
|
+
const targetPath = resolve7(targetDir, targetFilename);
|
|
5140
5166
|
const rawContent = readFileSync8(resolvedSourcePath, "utf-8");
|
|
5141
5167
|
let sourceContent;
|
|
5142
5168
|
try {
|
|
@@ -5155,10 +5181,10 @@ function syncDirectory(sourceDir, targetDir, framework, manifest, manifestKeyPre
|
|
|
5155
5181
|
const sourceHash = hashContent(sourceContent);
|
|
5156
5182
|
const manifestKey = manifestKeyPrefix === "" ? targetFilename : `${manifestKeyPrefix}/${targetFilename}`;
|
|
5157
5183
|
const lastInstalledHash = manifest.entries[manifestKey];
|
|
5158
|
-
if (
|
|
5184
|
+
if (existsSync12(targetPath)) {
|
|
5159
5185
|
let existingContent;
|
|
5160
5186
|
try {
|
|
5161
|
-
if (!
|
|
5187
|
+
if (!statSync3(targetPath).isFile()) throw new Error("not a regular file");
|
|
5162
5188
|
existingContent = readFileSync8(targetPath, "utf-8");
|
|
5163
5189
|
} catch (err) {
|
|
5164
5190
|
process.stderr.write(
|
|
@@ -5240,9 +5266,9 @@ function buildTemplateVars() {
|
|
|
5240
5266
|
}
|
|
5241
5267
|
function installCommands(projectRoot, opts = {}) {
|
|
5242
5268
|
const claudeDirName = getConfig().conventions?.claudeDirName ?? ".claude";
|
|
5243
|
-
const claudeDir =
|
|
5244
|
-
const targetDir =
|
|
5245
|
-
if (!
|
|
5269
|
+
const claudeDir = resolve7(projectRoot, claudeDirName);
|
|
5270
|
+
const targetDir = resolve7(claudeDir, "commands");
|
|
5271
|
+
if (!existsSync12(targetDir)) {
|
|
5246
5272
|
mkdirSync8(targetDir, { recursive: true });
|
|
5247
5273
|
}
|
|
5248
5274
|
const sourceDir = resolveAssetDir("commands");
|
|
@@ -5272,7 +5298,7 @@ function installCommands(projectRoot, opts = {}) {
|
|
|
5272
5298
|
}
|
|
5273
5299
|
function installAll(projectRoot, opts = {}) {
|
|
5274
5300
|
const claudeDirName = getConfig().conventions?.claudeDirName ?? ".claude";
|
|
5275
|
-
const claudeDir =
|
|
5301
|
+
const claudeDir = resolve7(projectRoot, claudeDirName);
|
|
5276
5302
|
const assets = {};
|
|
5277
5303
|
let totalInstalled = 0;
|
|
5278
5304
|
let totalUpdated = 0;
|
|
@@ -5285,7 +5311,7 @@ function installAll(projectRoot, opts = {}) {
|
|
|
5285
5311
|
for (const assetType of ASSET_TYPES) {
|
|
5286
5312
|
const sourceDir = resolveAssetDir(assetType.name);
|
|
5287
5313
|
if (!sourceDir) continue;
|
|
5288
|
-
const targetDir =
|
|
5314
|
+
const targetDir = resolve7(claudeDir, assetType.targetSubdir);
|
|
5289
5315
|
const stats = syncDirectory(
|
|
5290
5316
|
sourceDir,
|
|
5291
5317
|
targetDir,
|
|
@@ -5594,15 +5620,15 @@ var init_manifest_registry = __esm({
|
|
|
5594
5620
|
});
|
|
5595
5621
|
|
|
5596
5622
|
// src/detect/package-detector.ts
|
|
5597
|
-
import { readFileSync as readFileSync9, existsSync as
|
|
5623
|
+
import { readFileSync as readFileSync9, existsSync as existsSync13, statSync as statSync4, lstatSync, readdirSync as readdirSync5 } from "fs";
|
|
5598
5624
|
import { join as join9, relative as relative2 } from "path";
|
|
5599
5625
|
import { parse as parseToml } from "smol-toml";
|
|
5600
5626
|
function safeRead(path) {
|
|
5601
5627
|
try {
|
|
5602
|
-
if (!
|
|
5628
|
+
if (!existsSync13(path)) return null;
|
|
5603
5629
|
const ls = lstatSync(path);
|
|
5604
5630
|
if (ls.isSymbolicLink()) return null;
|
|
5605
|
-
const st =
|
|
5631
|
+
const st = statSync4(path);
|
|
5606
5632
|
if (!st.isFile()) return null;
|
|
5607
5633
|
return readFileSync9(path, "utf-8");
|
|
5608
5634
|
} catch {
|
|
@@ -5635,7 +5661,7 @@ function parsePackageJson(path, directory, root, warnings) {
|
|
|
5635
5661
|
const peer = Object.keys(
|
|
5636
5662
|
pkg.peerDependencies ?? {}
|
|
5637
5663
|
);
|
|
5638
|
-
const hasTs = deps.includes("typescript") || devDeps.includes("typescript") ||
|
|
5664
|
+
const hasTs = deps.includes("typescript") || devDeps.includes("typescript") || existsSync13(join9(directory, "tsconfig.json"));
|
|
5639
5665
|
const language = hasTs ? "typescript" : "javascript";
|
|
5640
5666
|
const scripts = Object.keys(
|
|
5641
5667
|
pkg.scripts ?? {}
|
|
@@ -6062,13 +6088,13 @@ function detectManifestsInDir(dir, root, warnings) {
|
|
|
6062
6088
|
for (const entry of getManifestRegistry2()) {
|
|
6063
6089
|
if (!entry.pattern.startsWith("*")) {
|
|
6064
6090
|
const path = join9(dir, entry.pattern);
|
|
6065
|
-
if (!
|
|
6091
|
+
if (!existsSync13(path)) continue;
|
|
6066
6092
|
const m3 = entry.parse(path, dir, root, warnings);
|
|
6067
6093
|
if (m3 !== null) out.push(m3);
|
|
6068
6094
|
} else {
|
|
6069
6095
|
if (dirEntries === null) {
|
|
6070
6096
|
try {
|
|
6071
|
-
dirEntries =
|
|
6097
|
+
dirEntries = readdirSync5(dir);
|
|
6072
6098
|
} catch {
|
|
6073
6099
|
dirEntries = [];
|
|
6074
6100
|
}
|
|
@@ -6076,7 +6102,7 @@ function detectManifestsInDir(dir, root, warnings) {
|
|
|
6076
6102
|
for (const fname of dirEntries) {
|
|
6077
6103
|
if (!matchManifestPattern2(fname, entry.pattern)) continue;
|
|
6078
6104
|
const path = join9(dir, fname);
|
|
6079
|
-
if (!
|
|
6105
|
+
if (!existsSync13(path)) continue;
|
|
6080
6106
|
const m3 = entry.parse(path, dir, root, warnings);
|
|
6081
6107
|
if (m3 !== null) out.push(m3);
|
|
6082
6108
|
}
|
|
@@ -6086,7 +6112,7 @@ function detectManifestsInDir(dir, root, warnings) {
|
|
|
6086
6112
|
}
|
|
6087
6113
|
function listSubdirs(dir) {
|
|
6088
6114
|
try {
|
|
6089
|
-
return
|
|
6115
|
+
return readdirSync5(dir, { withFileTypes: true }).filter((e2) => e2.isDirectory() && !IGNORED_DIRS.has(e2.name)).map((e2) => join9(dir, e2.name));
|
|
6090
6116
|
} catch {
|
|
6091
6117
|
return [];
|
|
6092
6118
|
}
|
|
@@ -6097,7 +6123,7 @@ function detectPackageManifests(projectRoot) {
|
|
|
6097
6123
|
manifests.push(...detectManifestsInDir(projectRoot, projectRoot, warnings));
|
|
6098
6124
|
for (const ws of WORKSPACE_DIRS) {
|
|
6099
6125
|
const wsRoot = join9(projectRoot, ws);
|
|
6100
|
-
if (!
|
|
6126
|
+
if (!existsSync13(wsRoot)) continue;
|
|
6101
6127
|
for (const sub of listSubdirs(wsRoot)) {
|
|
6102
6128
|
manifests.push(...detectManifestsInDir(sub, projectRoot, warnings));
|
|
6103
6129
|
for (const sub2 of listSubdirs(sub)) {
|
|
@@ -6349,22 +6375,22 @@ import {
|
|
|
6349
6375
|
openSync as openSync3,
|
|
6350
6376
|
fsyncSync as fsyncSync3,
|
|
6351
6377
|
closeSync as closeSync3,
|
|
6352
|
-
existsSync as
|
|
6353
|
-
realpathSync,
|
|
6378
|
+
existsSync as existsSync14,
|
|
6379
|
+
realpathSync as realpathSync2,
|
|
6354
6380
|
unlinkSync as unlinkSync2,
|
|
6355
6381
|
accessSync as accessSync2,
|
|
6356
|
-
statSync as
|
|
6382
|
+
statSync as statSync5,
|
|
6357
6383
|
chmodSync as chmodSync3,
|
|
6358
6384
|
constants
|
|
6359
6385
|
} from "fs";
|
|
6360
|
-
import { dirname as dirname10, resolve as
|
|
6386
|
+
import { dirname as dirname10, resolve as resolve8, relative as relative3, isAbsolute as isAbsolute2, basename as basename3, sep } from "path";
|
|
6361
6387
|
import { createHash as createHash4 } from "crypto";
|
|
6362
6388
|
function assertContainedIn(rootDir, candidate, opts = {}) {
|
|
6363
6389
|
if (candidate.includes("\0")) {
|
|
6364
6390
|
throw new PathEscapeError("path contains a NUL byte");
|
|
6365
6391
|
}
|
|
6366
|
-
const root =
|
|
6367
|
-
const abs =
|
|
6392
|
+
const root = resolve8(rootDir);
|
|
6393
|
+
const abs = resolve8(root, candidate);
|
|
6368
6394
|
if (!opts.allowNested) {
|
|
6369
6395
|
const rel = relative3(root, abs);
|
|
6370
6396
|
if (rel.includes(sep)) {
|
|
@@ -6383,13 +6409,13 @@ function assertContainedIn(rootDir, candidate, opts = {}) {
|
|
|
6383
6409
|
}
|
|
6384
6410
|
function isContainedIn(rootDir, candidate, opts = {}) {
|
|
6385
6411
|
if (candidate.includes("\0")) return false;
|
|
6386
|
-
const root =
|
|
6387
|
-
const abs =
|
|
6412
|
+
const root = resolve8(rootDir);
|
|
6413
|
+
const abs = resolve8(root, candidate);
|
|
6388
6414
|
const rel = relative3(root, abs);
|
|
6389
6415
|
if (rel === "" && !opts.allowRoot) return false;
|
|
6390
|
-
if (rel.startsWith("..") ||
|
|
6416
|
+
if (rel.startsWith("..") || isAbsolute2(rel)) return false;
|
|
6391
6417
|
let probe = abs;
|
|
6392
|
-
while (!
|
|
6418
|
+
while (!existsSync14(probe) && probe.length > 1) {
|
|
6393
6419
|
const parent = dirname10(probe);
|
|
6394
6420
|
if (parent === probe) break;
|
|
6395
6421
|
probe = parent;
|
|
@@ -6397,22 +6423,22 @@ function isContainedIn(rootDir, candidate, opts = {}) {
|
|
|
6397
6423
|
let realRoot;
|
|
6398
6424
|
let realProbe;
|
|
6399
6425
|
try {
|
|
6400
|
-
realRoot =
|
|
6401
|
-
realProbe =
|
|
6426
|
+
realRoot = realpathSync2(root);
|
|
6427
|
+
realProbe = realpathSync2(probe);
|
|
6402
6428
|
} catch {
|
|
6403
6429
|
return true;
|
|
6404
6430
|
}
|
|
6405
6431
|
const realRel = relative3(realRoot, realProbe);
|
|
6406
6432
|
if (realRel === "") return true;
|
|
6407
|
-
return !realRel.startsWith("..") && !
|
|
6433
|
+
return !realRel.startsWith("..") && !isAbsolute2(realRel);
|
|
6408
6434
|
}
|
|
6409
6435
|
function atomicWriteFileSync(destPath, contents) {
|
|
6410
6436
|
const dir = dirname10(destPath);
|
|
6411
|
-
const tmp =
|
|
6437
|
+
const tmp = resolve8(dir, `.${basename3(destPath)}.massu-tmp-${process.pid}`);
|
|
6412
6438
|
let destMode;
|
|
6413
|
-
if (
|
|
6439
|
+
if (existsSync14(destPath)) {
|
|
6414
6440
|
accessSync2(destPath, constants.W_OK);
|
|
6415
|
-
destMode =
|
|
6441
|
+
destMode = statSync5(destPath).mode & 511;
|
|
6416
6442
|
}
|
|
6417
6443
|
let fd;
|
|
6418
6444
|
try {
|
|
@@ -6431,7 +6457,7 @@ function atomicWriteFileSync(destPath, contents) {
|
|
|
6431
6457
|
}
|
|
6432
6458
|
}
|
|
6433
6459
|
try {
|
|
6434
|
-
if (
|
|
6460
|
+
if (existsSync14(tmp)) unlinkSync2(tmp);
|
|
6435
6461
|
} catch {
|
|
6436
6462
|
}
|
|
6437
6463
|
throw err;
|
|
@@ -9938,7 +9964,7 @@ var require_pattern = __commonJS({
|
|
|
9938
9964
|
const absolute = [];
|
|
9939
9965
|
const relative15 = [];
|
|
9940
9966
|
for (const pattern of patterns) {
|
|
9941
|
-
if (
|
|
9967
|
+
if (isAbsolute6(pattern)) {
|
|
9942
9968
|
absolute.push(pattern);
|
|
9943
9969
|
} else {
|
|
9944
9970
|
relative15.push(pattern);
|
|
@@ -9947,10 +9973,10 @@ var require_pattern = __commonJS({
|
|
|
9947
9973
|
return [absolute, relative15];
|
|
9948
9974
|
}
|
|
9949
9975
|
exports.partitionAbsoluteAndRelative = partitionAbsoluteAndRelative;
|
|
9950
|
-
function
|
|
9976
|
+
function isAbsolute6(pattern) {
|
|
9951
9977
|
return path.isAbsolute(pattern);
|
|
9952
9978
|
}
|
|
9953
|
-
exports.isAbsolute =
|
|
9979
|
+
exports.isAbsolute = isAbsolute6;
|
|
9954
9980
|
}
|
|
9955
9981
|
});
|
|
9956
9982
|
|
|
@@ -10365,11 +10391,11 @@ var require_out = __commonJS({
|
|
|
10365
10391
|
async.read(path, getSettings(optionsOrSettingsOrCallback), callback);
|
|
10366
10392
|
}
|
|
10367
10393
|
exports.stat = stat;
|
|
10368
|
-
function
|
|
10394
|
+
function statSync22(path, optionsOrSettings) {
|
|
10369
10395
|
const settings = getSettings(optionsOrSettings);
|
|
10370
10396
|
return sync.read(path, settings);
|
|
10371
10397
|
}
|
|
10372
|
-
exports.statSync =
|
|
10398
|
+
exports.statSync = statSync22;
|
|
10373
10399
|
function getSettings(settingsOrOptions = {}) {
|
|
10374
10400
|
if (settingsOrOptions instanceof settings_1.default) {
|
|
10375
10401
|
return settingsOrOptions;
|
|
@@ -11034,41 +11060,41 @@ var require_queue = __commonJS({
|
|
|
11034
11060
|
queue.drained = drained;
|
|
11035
11061
|
return queue;
|
|
11036
11062
|
function push(value) {
|
|
11037
|
-
var p19 = new Promise(function(
|
|
11063
|
+
var p19 = new Promise(function(resolve46, reject) {
|
|
11038
11064
|
pushCb(value, function(err, result) {
|
|
11039
11065
|
if (err) {
|
|
11040
11066
|
reject(err);
|
|
11041
11067
|
return;
|
|
11042
11068
|
}
|
|
11043
|
-
|
|
11069
|
+
resolve46(result);
|
|
11044
11070
|
});
|
|
11045
11071
|
});
|
|
11046
11072
|
p19.catch(noop);
|
|
11047
11073
|
return p19;
|
|
11048
11074
|
}
|
|
11049
11075
|
function unshift(value) {
|
|
11050
|
-
var p19 = new Promise(function(
|
|
11076
|
+
var p19 = new Promise(function(resolve46, reject) {
|
|
11051
11077
|
unshiftCb(value, function(err, result) {
|
|
11052
11078
|
if (err) {
|
|
11053
11079
|
reject(err);
|
|
11054
11080
|
return;
|
|
11055
11081
|
}
|
|
11056
|
-
|
|
11082
|
+
resolve46(result);
|
|
11057
11083
|
});
|
|
11058
11084
|
});
|
|
11059
11085
|
p19.catch(noop);
|
|
11060
11086
|
return p19;
|
|
11061
11087
|
}
|
|
11062
11088
|
function drained() {
|
|
11063
|
-
var p19 = new Promise(function(
|
|
11089
|
+
var p19 = new Promise(function(resolve46) {
|
|
11064
11090
|
process.nextTick(function() {
|
|
11065
11091
|
if (queue.idle()) {
|
|
11066
|
-
|
|
11092
|
+
resolve46();
|
|
11067
11093
|
} else {
|
|
11068
11094
|
var previousDrain = queue.drain;
|
|
11069
11095
|
queue.drain = function() {
|
|
11070
11096
|
if (typeof previousDrain === "function") previousDrain();
|
|
11071
|
-
|
|
11097
|
+
resolve46();
|
|
11072
11098
|
queue.drain = previousDrain;
|
|
11073
11099
|
};
|
|
11074
11100
|
}
|
|
@@ -11554,9 +11580,9 @@ var require_stream3 = __commonJS({
|
|
|
11554
11580
|
});
|
|
11555
11581
|
}
|
|
11556
11582
|
_getStat(filepath) {
|
|
11557
|
-
return new Promise((
|
|
11583
|
+
return new Promise((resolve46, reject) => {
|
|
11558
11584
|
this._stat(filepath, this._fsStatSettings, (error, stats) => {
|
|
11559
|
-
return error === null ?
|
|
11585
|
+
return error === null ? resolve46(stats) : reject(error);
|
|
11560
11586
|
});
|
|
11561
11587
|
});
|
|
11562
11588
|
}
|
|
@@ -11580,10 +11606,10 @@ var require_async5 = __commonJS({
|
|
|
11580
11606
|
this._readerStream = new stream_1.default(this._settings);
|
|
11581
11607
|
}
|
|
11582
11608
|
dynamic(root, options) {
|
|
11583
|
-
return new Promise((
|
|
11609
|
+
return new Promise((resolve46, reject) => {
|
|
11584
11610
|
this._walkAsync(root, options, (error, entries) => {
|
|
11585
11611
|
if (error === null) {
|
|
11586
|
-
|
|
11612
|
+
resolve46(entries);
|
|
11587
11613
|
} else {
|
|
11588
11614
|
reject(error);
|
|
11589
11615
|
}
|
|
@@ -11593,10 +11619,10 @@ var require_async5 = __commonJS({
|
|
|
11593
11619
|
async static(patterns, options) {
|
|
11594
11620
|
const entries = [];
|
|
11595
11621
|
const stream = this._readerStream.static(patterns, options);
|
|
11596
|
-
return new Promise((
|
|
11622
|
+
return new Promise((resolve46, reject) => {
|
|
11597
11623
|
stream.once("error", reject);
|
|
11598
11624
|
stream.on("data", (entry) => entries.push(entry));
|
|
11599
|
-
stream.once("end", () =>
|
|
11625
|
+
stream.once("end", () => resolve46(entries));
|
|
11600
11626
|
});
|
|
11601
11627
|
}
|
|
11602
11628
|
};
|
|
@@ -12442,16 +12468,16 @@ var init_source_dir_detector = __esm({
|
|
|
12442
12468
|
});
|
|
12443
12469
|
|
|
12444
12470
|
// src/detect/monorepo-detector.ts
|
|
12445
|
-
import { readFileSync as readFileSync10, existsSync as
|
|
12471
|
+
import { readFileSync as readFileSync10, existsSync as existsSync15, statSync as statSync6, lstatSync as lstatSync2, readdirSync as readdirSync6 } from "fs";
|
|
12446
12472
|
import { join as join10, relative as relative4 } from "path";
|
|
12447
12473
|
import { parse as parseYaml3 } from "yaml";
|
|
12448
12474
|
import { parse as parseToml2 } from "smol-toml";
|
|
12449
12475
|
function safeReadText(path) {
|
|
12450
12476
|
try {
|
|
12451
|
-
if (!
|
|
12477
|
+
if (!existsSync15(path)) return null;
|
|
12452
12478
|
const ls = lstatSync2(path);
|
|
12453
12479
|
if (ls.isSymbolicLink()) return null;
|
|
12454
|
-
const st =
|
|
12480
|
+
const st = statSync6(path);
|
|
12455
12481
|
if (!st.isFile()) return null;
|
|
12456
12482
|
return readFileSync10(path, "utf-8");
|
|
12457
12483
|
} catch {
|
|
@@ -12460,7 +12486,7 @@ function safeReadText(path) {
|
|
|
12460
12486
|
}
|
|
12461
12487
|
function firstManifestIn(dir) {
|
|
12462
12488
|
for (const m3 of MANIFEST_PRIORITY) {
|
|
12463
|
-
if (
|
|
12489
|
+
if (existsSync15(join10(dir, m3))) return m3;
|
|
12464
12490
|
}
|
|
12465
12491
|
return null;
|
|
12466
12492
|
}
|
|
@@ -12516,7 +12542,7 @@ function pkgFromDir(root, dir) {
|
|
|
12516
12542
|
}
|
|
12517
12543
|
function listSubdirs2(dir) {
|
|
12518
12544
|
try {
|
|
12519
|
-
return
|
|
12545
|
+
return readdirSync6(dir, { withFileTypes: true }).filter((e2) => e2.isDirectory() && !IGNORED_DIRS2.has(e2.name)).map((e2) => join10(dir, e2.name));
|
|
12520
12546
|
} catch {
|
|
12521
12547
|
return [];
|
|
12522
12548
|
}
|
|
@@ -12525,7 +12551,7 @@ function genericWorkspaces(root) {
|
|
|
12525
12551
|
const out = [];
|
|
12526
12552
|
for (const parent of CONVENTIONAL_WORKSPACE_PARENTS) {
|
|
12527
12553
|
const p19 = join10(root, parent);
|
|
12528
|
-
if (!
|
|
12554
|
+
if (!existsSync15(p19)) continue;
|
|
12529
12555
|
for (const sub of listSubdirs2(p19)) {
|
|
12530
12556
|
const pkg = pkgFromDir(root, sub);
|
|
12531
12557
|
if (pkg) out.push(pkg);
|
|
@@ -12566,7 +12592,7 @@ function expandWorkspaceGlobs(root, globs) {
|
|
|
12566
12592
|
const parts = pattern.split("/");
|
|
12567
12593
|
if (parts.length === 2 && (parts[1] === "*" || parts[1] === "**")) {
|
|
12568
12594
|
const parent = join10(root, parts[0]);
|
|
12569
|
-
if (!
|
|
12595
|
+
if (!existsSync15(parent)) continue;
|
|
12570
12596
|
for (const sub of listSubdirs2(parent)) {
|
|
12571
12597
|
const pkg = pkgFromDir(root, sub);
|
|
12572
12598
|
if (pkg && !seen.has(pkg.path)) {
|
|
@@ -12577,7 +12603,7 @@ function expandWorkspaceGlobs(root, globs) {
|
|
|
12577
12603
|
continue;
|
|
12578
12604
|
}
|
|
12579
12605
|
const direct = join10(root, pattern);
|
|
12580
|
-
if (
|
|
12606
|
+
if (existsSync15(direct)) {
|
|
12581
12607
|
const pkg = pkgFromDir(root, direct);
|
|
12582
12608
|
if (pkg && !seen.has(pkg.path)) {
|
|
12583
12609
|
seen.add(pkg.path);
|
|
@@ -12588,16 +12614,16 @@ function expandWorkspaceGlobs(root, globs) {
|
|
|
12588
12614
|
return out;
|
|
12589
12615
|
}
|
|
12590
12616
|
function hasTurbo(root) {
|
|
12591
|
-
return
|
|
12617
|
+
return existsSync15(join10(root, "turbo.json"));
|
|
12592
12618
|
}
|
|
12593
12619
|
function hasNx(root) {
|
|
12594
|
-
return
|
|
12620
|
+
return existsSync15(join10(root, "nx.json"));
|
|
12595
12621
|
}
|
|
12596
12622
|
function hasLerna(root) {
|
|
12597
|
-
return
|
|
12623
|
+
return existsSync15(join10(root, "lerna.json"));
|
|
12598
12624
|
}
|
|
12599
12625
|
function hasBazel(root) {
|
|
12600
|
-
return
|
|
12626
|
+
return existsSync15(join10(root, "WORKSPACE")) || existsSync15(join10(root, "WORKSPACE.bazel")) || existsSync15(join10(root, "MODULE.bazel"));
|
|
12601
12627
|
}
|
|
12602
12628
|
function detectMonorepo(projectRoot) {
|
|
12603
12629
|
const nested = [];
|
|
@@ -12788,7 +12814,7 @@ var init_vr_command_map = __esm({
|
|
|
12788
12814
|
});
|
|
12789
12815
|
|
|
12790
12816
|
// src/detect/domain-inferrer.ts
|
|
12791
|
-
import { existsSync as
|
|
12817
|
+
import { existsSync as existsSync16, readdirSync as readdirSync7 } from "fs";
|
|
12792
12818
|
import { join as join11 } from "path";
|
|
12793
12819
|
function titleCase(s) {
|
|
12794
12820
|
if (!s) return s;
|
|
@@ -12810,9 +12836,9 @@ function topLevelSrcSubdirs(root, sourceDirs) {
|
|
|
12810
12836
|
const seen = /* @__PURE__ */ new Set();
|
|
12811
12837
|
for (const rel of effective) {
|
|
12812
12838
|
const abs = join11(root, rel);
|
|
12813
|
-
if (!
|
|
12839
|
+
if (!existsSync16(abs)) continue;
|
|
12814
12840
|
try {
|
|
12815
|
-
for (const e2 of
|
|
12841
|
+
for (const e2 of readdirSync7(abs, { withFileTypes: true })) {
|
|
12816
12842
|
if (!e2.isDirectory()) continue;
|
|
12817
12843
|
if (IGNORED_SUBDIRS.has(e2.name)) continue;
|
|
12818
12844
|
seen.add(e2.name);
|
|
@@ -12897,8 +12923,8 @@ var init_domain_inferrer = __esm({
|
|
|
12897
12923
|
});
|
|
12898
12924
|
|
|
12899
12925
|
// src/detect/regex-fallback.ts
|
|
12900
|
-
import { existsSync as
|
|
12901
|
-
import { resolve as
|
|
12926
|
+
import { existsSync as existsSync17, readdirSync as readdirSync8, readFileSync as readFileSync11, statSync as statSync7 } from "fs";
|
|
12927
|
+
import { resolve as resolve9, join as join12, basename as basename4 } from "path";
|
|
12902
12928
|
function introspectPython(detection, projectRoot) {
|
|
12903
12929
|
const sourceDir = resolveSourceDir(detection, "python", projectRoot);
|
|
12904
12930
|
if (!sourceDir) return null;
|
|
@@ -13064,10 +13090,10 @@ function resolveSourceDir(detection, lang, projectRoot) {
|
|
|
13064
13090
|
const list = info?.source_dirs ?? [];
|
|
13065
13091
|
if (list.length > 0) {
|
|
13066
13092
|
const first = list[0];
|
|
13067
|
-
const abs =
|
|
13068
|
-
return
|
|
13093
|
+
const abs = resolve9(projectRoot, first);
|
|
13094
|
+
return existsSync17(abs) ? abs : null;
|
|
13069
13095
|
}
|
|
13070
|
-
return
|
|
13096
|
+
return existsSync17(projectRoot) ? projectRoot : null;
|
|
13071
13097
|
}
|
|
13072
13098
|
function sampleFiles(dir, nameRegex, pathFilter) {
|
|
13073
13099
|
const out = [];
|
|
@@ -13077,7 +13103,7 @@ function sampleFiles(dir, nameRegex, pathFilter) {
|
|
|
13077
13103
|
if (depth > MAX_DIR_DEPTH) continue;
|
|
13078
13104
|
let entries;
|
|
13079
13105
|
try {
|
|
13080
|
-
entries =
|
|
13106
|
+
entries = readdirSync8(path);
|
|
13081
13107
|
} catch {
|
|
13082
13108
|
continue;
|
|
13083
13109
|
}
|
|
@@ -13090,7 +13116,7 @@ function sampleFiles(dir, nameRegex, pathFilter) {
|
|
|
13090
13116
|
const child = join12(path, entry);
|
|
13091
13117
|
let st;
|
|
13092
13118
|
try {
|
|
13093
|
-
st =
|
|
13119
|
+
st = statSync7(child);
|
|
13094
13120
|
} catch {
|
|
13095
13121
|
continue;
|
|
13096
13122
|
}
|
|
@@ -13110,7 +13136,7 @@ function sampleFiles(dir, nameRegex, pathFilter) {
|
|
|
13110
13136
|
}
|
|
13111
13137
|
function readSafe(path) {
|
|
13112
13138
|
try {
|
|
13113
|
-
const st =
|
|
13139
|
+
const st = statSync7(path);
|
|
13114
13140
|
if (st.size > MAX_FILE_BYTES) return null;
|
|
13115
13141
|
return readFileSync11(path, "utf-8");
|
|
13116
13142
|
} catch {
|
|
@@ -13193,7 +13219,7 @@ var init_parse_guard = __esm({
|
|
|
13193
13219
|
|
|
13194
13220
|
// src/detect/adapters/runner.ts
|
|
13195
13221
|
import { basename as basename5, relative as relative5 } from "path";
|
|
13196
|
-
import { existsSync as
|
|
13222
|
+
import { existsSync as existsSync18, readdirSync as readdirSync9, readFileSync as readFileSync12, statSync as statSync8 } from "fs";
|
|
13197
13223
|
import { join as join13 } from "path";
|
|
13198
13224
|
async function runAdapters(adapters, rootDir, signals, options = {}) {
|
|
13199
13225
|
const out = {
|
|
@@ -13288,10 +13314,10 @@ function buildDetectionSignals(rootDir) {
|
|
|
13288
13314
|
const presentDirs = /* @__PURE__ */ new Set();
|
|
13289
13315
|
const presentFiles = /* @__PURE__ */ new Set();
|
|
13290
13316
|
try {
|
|
13291
|
-
for (const entry of
|
|
13317
|
+
for (const entry of readdirSync9(rootDir)) {
|
|
13292
13318
|
if (entry.startsWith(".")) continue;
|
|
13293
13319
|
try {
|
|
13294
|
-
const st =
|
|
13320
|
+
const st = statSync8(join13(rootDir, entry));
|
|
13295
13321
|
if (st.isDirectory()) presentDirs.add(entry);
|
|
13296
13322
|
else if (st.isFile()) presentFiles.add(entry);
|
|
13297
13323
|
} catch {
|
|
@@ -13328,7 +13354,7 @@ function tryReadGradleBuild(rootDir, presentFiles) {
|
|
|
13328
13354
|
return void 0;
|
|
13329
13355
|
}
|
|
13330
13356
|
function tryReadString(path) {
|
|
13331
|
-
if (!
|
|
13357
|
+
if (!existsSync18(path)) return void 0;
|
|
13332
13358
|
try {
|
|
13333
13359
|
return readFileSync12(path, "utf-8");
|
|
13334
13360
|
} catch {
|
|
@@ -13448,7 +13474,7 @@ ${querySource}`
|
|
|
13448
13474
|
import { createHash as createHash5 } from "crypto";
|
|
13449
13475
|
import {
|
|
13450
13476
|
mkdirSync as mkdirSync9,
|
|
13451
|
-
readdirSync as
|
|
13477
|
+
readdirSync as readdirSync10,
|
|
13452
13478
|
readFileSync as readFileSync13,
|
|
13453
13479
|
writeFileSync as writeFileSync4,
|
|
13454
13480
|
renameSync as renameSync3,
|
|
@@ -13457,11 +13483,11 @@ import {
|
|
|
13457
13483
|
chmodSync as chmodSync4,
|
|
13458
13484
|
utimesSync
|
|
13459
13485
|
} from "fs";
|
|
13460
|
-
import { homedir as
|
|
13486
|
+
import { homedir as homedir6 } from "os";
|
|
13461
13487
|
import { dirname as dirname11, join as join14 } from "path";
|
|
13462
13488
|
import { Language, Parser } from "web-tree-sitter";
|
|
13463
13489
|
function getCacheDir() {
|
|
13464
|
-
return process.env.MASSU_WASM_CACHE_DIR ?? join14(
|
|
13490
|
+
return process.env.MASSU_WASM_CACHE_DIR ?? join14(homedir6(), ".massu", "wasm-cache");
|
|
13465
13491
|
}
|
|
13466
13492
|
function getCachedPath(language, sha) {
|
|
13467
13493
|
return join14(getCacheDir(), `${language}-${sha}.wasm`);
|
|
@@ -13485,7 +13511,7 @@ function evictBeyondRetainCount(retain = getCacheRetainCount()) {
|
|
|
13485
13511
|
const dir = getCacheDir();
|
|
13486
13512
|
let entries;
|
|
13487
13513
|
try {
|
|
13488
|
-
entries =
|
|
13514
|
+
entries = readdirSync10(dir);
|
|
13489
13515
|
} catch {
|
|
13490
13516
|
return;
|
|
13491
13517
|
}
|
|
@@ -14467,7 +14493,7 @@ __export(file_sampler_exports, {
|
|
|
14467
14493
|
SAMPLE_TEST_FILE_PATTERNS: () => SAMPLE_TEST_FILE_PATTERNS,
|
|
14468
14494
|
sampleFilesForAdapter: () => sampleFilesForAdapter
|
|
14469
14495
|
});
|
|
14470
|
-
import { readdirSync as
|
|
14496
|
+
import { readdirSync as readdirSync11, readFileSync as readFileSync14, lstatSync as lstatSync4 } from "node:fs";
|
|
14471
14497
|
import { join as join15, extname } from "node:path";
|
|
14472
14498
|
function sampleFilesForAdapter(adapter, projectRoot, detection, options = {}) {
|
|
14473
14499
|
const maxDepth = options.maxDepth ?? DEFAULT_MAX_DEPTH;
|
|
@@ -14499,7 +14525,7 @@ function walkDir(dir, exts, testPatterns, lang, maxDepth, curDepth, out, seen, m
|
|
|
14499
14525
|
if (out.length >= maxFiles) return;
|
|
14500
14526
|
let entries;
|
|
14501
14527
|
try {
|
|
14502
|
-
entries =
|
|
14528
|
+
entries = readdirSync11(dir);
|
|
14503
14529
|
} catch {
|
|
14504
14530
|
return;
|
|
14505
14531
|
}
|
|
@@ -15952,10 +15978,10 @@ __export(init_exports, {
|
|
|
15952
15978
|
validateWrittenConfig: () => validateWrittenConfig,
|
|
15953
15979
|
writeConfigAtomic: () => writeConfigAtomic
|
|
15954
15980
|
});
|
|
15955
|
-
import { closeSync as closeSync4, existsSync as
|
|
15956
|
-
import { resolve as
|
|
15981
|
+
import { closeSync as closeSync4, existsSync as existsSync19, fsyncSync as fsyncSync4, openSync as openSync4, readFileSync as readFileSync15, writeFileSync as writeFileSync5, writeSync as writeSync2, mkdirSync as mkdirSync10, readdirSync as readdirSync12, renameSync as renameSync4, rmSync as rmSync6, statSync as statSync10, chmodSync as chmodSync5 } from "fs";
|
|
15982
|
+
import { resolve as resolve10, basename as basename6, dirname as dirname12 } from "path";
|
|
15957
15983
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
15958
|
-
import { homedir as
|
|
15984
|
+
import { homedir as homedir7 } from "os";
|
|
15959
15985
|
import { stringify as yamlStringify, parse as yamlParse } from "yaml";
|
|
15960
15986
|
function detectFramework(projectRoot) {
|
|
15961
15987
|
const result = {
|
|
@@ -15964,8 +15990,8 @@ function detectFramework(projectRoot) {
|
|
|
15964
15990
|
orm: "none",
|
|
15965
15991
|
ui: "none"
|
|
15966
15992
|
};
|
|
15967
|
-
const pkgPath =
|
|
15968
|
-
if (!
|
|
15993
|
+
const pkgPath = resolve10(projectRoot, "package.json");
|
|
15994
|
+
if (!existsSync19(pkgPath)) return result;
|
|
15969
15995
|
try {
|
|
15970
15996
|
const pkg = JSON.parse(readFileSync15(pkgPath, "utf-8"));
|
|
15971
15997
|
const allDeps = {
|
|
@@ -16001,7 +16027,7 @@ function detectPython(projectRoot) {
|
|
|
16001
16027
|
alembicDir: null
|
|
16002
16028
|
};
|
|
16003
16029
|
const markers = ["pyproject.toml", "setup.py", "requirements.txt", "Pipfile"];
|
|
16004
|
-
const hasMarker = markers.some((m3) =>
|
|
16030
|
+
const hasMarker = markers.some((m3) => existsSync19(resolve10(projectRoot, m3)));
|
|
16005
16031
|
if (!hasMarker) return result;
|
|
16006
16032
|
result.detected = true;
|
|
16007
16033
|
const depFiles = [
|
|
@@ -16011,8 +16037,8 @@ function detectPython(projectRoot) {
|
|
|
16011
16037
|
{ file: "Pipfile" }
|
|
16012
16038
|
];
|
|
16013
16039
|
for (const { file } of depFiles) {
|
|
16014
|
-
const filePath =
|
|
16015
|
-
if (
|
|
16040
|
+
const filePath = resolve10(projectRoot, file);
|
|
16041
|
+
if (existsSync19(filePath)) {
|
|
16016
16042
|
try {
|
|
16017
16043
|
const content = readFileSync15(filePath, "utf-8").toLowerCase();
|
|
16018
16044
|
if (content.includes("fastapi")) result.hasFastapi = true;
|
|
@@ -16021,25 +16047,25 @@ function detectPython(projectRoot) {
|
|
|
16021
16047
|
}
|
|
16022
16048
|
}
|
|
16023
16049
|
}
|
|
16024
|
-
if (
|
|
16050
|
+
if (existsSync19(resolve10(projectRoot, "alembic.ini"))) {
|
|
16025
16051
|
result.hasAlembic = true;
|
|
16026
|
-
if (
|
|
16052
|
+
if (existsSync19(resolve10(projectRoot, "alembic"))) {
|
|
16027
16053
|
result.alembicDir = "alembic";
|
|
16028
16054
|
}
|
|
16029
|
-
} else if (
|
|
16055
|
+
} else if (existsSync19(resolve10(projectRoot, "alembic"))) {
|
|
16030
16056
|
result.hasAlembic = true;
|
|
16031
16057
|
result.alembicDir = "alembic";
|
|
16032
16058
|
}
|
|
16033
16059
|
const candidateRoots = ["app", "src", "backend", "api"];
|
|
16034
16060
|
for (const candidate of candidateRoots) {
|
|
16035
|
-
const candidatePath =
|
|
16036
|
-
if (
|
|
16061
|
+
const candidatePath = resolve10(projectRoot, candidate);
|
|
16062
|
+
if (existsSync19(candidatePath) && existsSync19(resolve10(candidatePath, "__init__.py"))) {
|
|
16037
16063
|
result.root = candidate;
|
|
16038
16064
|
break;
|
|
16039
16065
|
}
|
|
16040
|
-
if (
|
|
16066
|
+
if (existsSync19(candidatePath)) {
|
|
16041
16067
|
try {
|
|
16042
|
-
const files =
|
|
16068
|
+
const files = readdirSync12(candidatePath);
|
|
16043
16069
|
if (files.some((f2) => f2.endsWith(".py"))) {
|
|
16044
16070
|
result.root = candidate;
|
|
16045
16071
|
break;
|
|
@@ -16057,8 +16083,8 @@ function generateConfig(projectRoot, framework) {
|
|
|
16057
16083
|
console.warn(
|
|
16058
16084
|
"[@massu/core] generateConfig() is deprecated since 1.2.1 \u2014 use buildConfigFromDetection instead. It cannot produce valid configs for monorepos."
|
|
16059
16085
|
);
|
|
16060
|
-
const configPath =
|
|
16061
|
-
if (
|
|
16086
|
+
const configPath = resolve10(projectRoot, "massu.config.yaml");
|
|
16087
|
+
if (existsSync19(configPath)) {
|
|
16062
16088
|
return false;
|
|
16063
16089
|
}
|
|
16064
16090
|
const projectName = basename6(projectRoot);
|
|
@@ -16169,10 +16195,10 @@ function buildConfigFromDetection(opts) {
|
|
|
16169
16195
|
pathsSource = monorepoCommonRoot(detection.monorepo.packages);
|
|
16170
16196
|
}
|
|
16171
16197
|
}
|
|
16172
|
-
if (pathsSource === "src" && !
|
|
16198
|
+
if (pathsSource === "src" && !existsSync19(resolve10(projectRoot, "src"))) {
|
|
16173
16199
|
const fallbacks = ["app", "pages", "."];
|
|
16174
16200
|
for (const fallback of fallbacks) {
|
|
16175
|
-
if (fallback === "." ||
|
|
16201
|
+
if (fallback === "." || existsSync19(resolve10(projectRoot, fallback))) {
|
|
16176
16202
|
pathsSource = fallback;
|
|
16177
16203
|
break;
|
|
16178
16204
|
}
|
|
@@ -16256,7 +16282,7 @@ function buildConfigFromDetection(opts) {
|
|
|
16256
16282
|
};
|
|
16257
16283
|
if (pyFw?.framework) pythonBlock.framework = pyFw.framework;
|
|
16258
16284
|
if (pyFw?.orm) pythonBlock.orm = pyFw.orm;
|
|
16259
|
-
if (
|
|
16285
|
+
if (existsSync19(resolve10(projectRoot, "alembic.ini")) || existsSync19(resolve10(projectRoot, "alembic"))) {
|
|
16260
16286
|
pythonBlock.alembic_dir = "alembic";
|
|
16261
16287
|
}
|
|
16262
16288
|
config.python = pythonBlock;
|
|
@@ -16280,8 +16306,8 @@ function applyVariantTemplate(config, templatesDir) {
|
|
|
16280
16306
|
}
|
|
16281
16307
|
}
|
|
16282
16308
|
if (templateId === null) return config;
|
|
16283
|
-
const templatePath =
|
|
16284
|
-
if (!
|
|
16309
|
+
const templatePath = resolve10(templatesDir, templateId, "massu.config.yaml");
|
|
16310
|
+
if (!existsSync19(templatePath)) return config;
|
|
16285
16311
|
let template;
|
|
16286
16312
|
try {
|
|
16287
16313
|
template = yamlParse(readFileSync15(templatePath, "utf-8"));
|
|
@@ -16343,9 +16369,9 @@ ${yamlStringify(config)}`;
|
|
|
16343
16369
|
function writeConfigAtomic(configPath, content) {
|
|
16344
16370
|
const tmpPath = `${configPath}.tmp`;
|
|
16345
16371
|
let existingMode;
|
|
16346
|
-
if (
|
|
16372
|
+
if (existsSync19(configPath)) {
|
|
16347
16373
|
try {
|
|
16348
|
-
existingMode =
|
|
16374
|
+
existingMode = statSync10(configPath).mode;
|
|
16349
16375
|
} catch {
|
|
16350
16376
|
existingMode = void 0;
|
|
16351
16377
|
}
|
|
@@ -16373,7 +16399,7 @@ function writeConfigAtomic(configPath, content) {
|
|
|
16373
16399
|
}
|
|
16374
16400
|
return { validated: true };
|
|
16375
16401
|
} catch (err) {
|
|
16376
|
-
if (
|
|
16402
|
+
if (existsSync19(tmpPath)) {
|
|
16377
16403
|
try {
|
|
16378
16404
|
rmSync6(tmpPath, { force: true });
|
|
16379
16405
|
} catch {
|
|
@@ -16384,7 +16410,7 @@ function writeConfigAtomic(configPath, content) {
|
|
|
16384
16410
|
}
|
|
16385
16411
|
function validateWrittenConfig(configPath, projectRoot, checkPaths = true) {
|
|
16386
16412
|
try {
|
|
16387
|
-
if (!
|
|
16413
|
+
if (!existsSync19(configPath)) return "Config file does not exist after write";
|
|
16388
16414
|
const content = readFileSync15(configPath, "utf-8");
|
|
16389
16415
|
const parsed = yamlParse(content);
|
|
16390
16416
|
if (parsed === null || typeof parsed !== "object") {
|
|
@@ -16405,8 +16431,8 @@ function validateWrittenConfig(configPath, projectRoot, checkPaths = true) {
|
|
|
16405
16431
|
if (checkPaths) {
|
|
16406
16432
|
const src = cfg.paths.source;
|
|
16407
16433
|
if (src && src !== ".") {
|
|
16408
|
-
const srcAbs =
|
|
16409
|
-
if (!
|
|
16434
|
+
const srcAbs = resolve10(projectRoot, src);
|
|
16435
|
+
if (!existsSync19(srcAbs)) {
|
|
16410
16436
|
return `paths.source '${src}' does not exist on disk`;
|
|
16411
16437
|
}
|
|
16412
16438
|
}
|
|
@@ -16416,8 +16442,8 @@ function validateWrittenConfig(configPath, projectRoot, checkPaths = true) {
|
|
|
16416
16442
|
if (!Array.isArray(rawDirs)) continue;
|
|
16417
16443
|
for (const d2 of rawDirs) {
|
|
16418
16444
|
if (typeof d2 !== "string" || d2 === ".") continue;
|
|
16419
|
-
const abs =
|
|
16420
|
-
if (!
|
|
16445
|
+
const abs = resolve10(projectRoot, d2);
|
|
16446
|
+
if (!existsSync19(abs)) {
|
|
16421
16447
|
return `framework.languages.${lang}.source_dirs '${d2}' does not exist on disk`;
|
|
16422
16448
|
}
|
|
16423
16449
|
}
|
|
@@ -16426,7 +16452,7 @@ function validateWrittenConfig(configPath, projectRoot, checkPaths = true) {
|
|
|
16426
16452
|
if (Array.isArray(mRoots)) {
|
|
16427
16453
|
for (const r2 of mRoots) {
|
|
16428
16454
|
if (typeof r2 !== "string" || r2 === ".") continue;
|
|
16429
|
-
if (!
|
|
16455
|
+
if (!existsSync19(resolve10(projectRoot, r2))) {
|
|
16430
16456
|
return `paths.monorepo_roots '${r2}' does not exist on disk`;
|
|
16431
16457
|
}
|
|
16432
16458
|
}
|
|
@@ -16458,21 +16484,21 @@ function resolveTemplatesDir() {
|
|
|
16458
16484
|
const cwd = process.cwd();
|
|
16459
16485
|
const candidates = [
|
|
16460
16486
|
// Project-local install: `<project>/node_modules/@massu/core/templates`.
|
|
16461
|
-
|
|
16487
|
+
resolve10(cwd, "node_modules/@massu/core/templates"),
|
|
16462
16488
|
// Bundled cli.js layout: cli.js sits at `<package>/dist/cli.js`, so
|
|
16463
16489
|
// templates live one level up at `<package>/templates`. (Plan 1.5.1
|
|
16464
16490
|
// bug discovery: pre-existing layout assumed `dist/commands/init.js`
|
|
16465
16491
|
// depth which never matched the bundled cli, so resolveTemplatesDir
|
|
16466
16492
|
// returned null in production for both `--template` mode AND the
|
|
16467
16493
|
// applyVariantTemplate path.)
|
|
16468
|
-
|
|
16494
|
+
resolve10(__dirname2, "../templates"),
|
|
16469
16495
|
// Legacy nested layouts retained as fallbacks (in case a future
|
|
16470
16496
|
// build moves cli.js back into a subdirectory).
|
|
16471
|
-
|
|
16472
|
-
|
|
16497
|
+
resolve10(__dirname2, "../../templates"),
|
|
16498
|
+
resolve10(__dirname2, "../../../templates")
|
|
16473
16499
|
];
|
|
16474
16500
|
for (const c2 of candidates) {
|
|
16475
|
-
if (
|
|
16501
|
+
if (existsSync19(c2)) return c2;
|
|
16476
16502
|
}
|
|
16477
16503
|
return null;
|
|
16478
16504
|
}
|
|
@@ -16481,8 +16507,8 @@ function copyTemplateConfig(templateName, targetPath, projectName) {
|
|
|
16481
16507
|
if (!templatesDir) {
|
|
16482
16508
|
return { success: false, error: `Templates directory not found (looked in node_modules and dist/src)` };
|
|
16483
16509
|
}
|
|
16484
|
-
const srcPath =
|
|
16485
|
-
if (!
|
|
16510
|
+
const srcPath = resolve10(templatesDir, templateName, "massu.config.yaml");
|
|
16511
|
+
if (!existsSync19(srcPath)) {
|
|
16486
16512
|
return { success: false, error: `Template '${templateName}' not found at ${srcPath}` };
|
|
16487
16513
|
}
|
|
16488
16514
|
try {
|
|
@@ -16496,11 +16522,11 @@ function copyTemplateConfig(templateName, targetPath, projectName) {
|
|
|
16496
16522
|
}
|
|
16497
16523
|
function getInstallerVersion() {
|
|
16498
16524
|
const candidates = [
|
|
16499
|
-
|
|
16500
|
-
|
|
16525
|
+
resolve10(__dirname2, "../package.json"),
|
|
16526
|
+
resolve10(__dirname2, "../../package.json")
|
|
16501
16527
|
];
|
|
16502
16528
|
for (const candidate of candidates) {
|
|
16503
|
-
if (
|
|
16529
|
+
if (existsSync19(candidate)) {
|
|
16504
16530
|
try {
|
|
16505
16531
|
const pkg = JSON.parse(readFileSync15(candidate, "utf-8"));
|
|
16506
16532
|
if (typeof pkg.version === "string" && pkg.version.length > 0 && pkg.name === "@massu/core") {
|
|
@@ -16515,9 +16541,9 @@ function getInstallerVersion() {
|
|
|
16515
16541
|
);
|
|
16516
16542
|
}
|
|
16517
16543
|
function registerMcpServer(projectRoot) {
|
|
16518
|
-
const mcpPath =
|
|
16544
|
+
const mcpPath = resolve10(projectRoot, ".mcp.json");
|
|
16519
16545
|
let existing = {};
|
|
16520
|
-
if (
|
|
16546
|
+
if (existsSync19(mcpPath)) {
|
|
16521
16547
|
try {
|
|
16522
16548
|
existing = JSON.parse(readFileSync15(mcpPath, "utf-8"));
|
|
16523
16549
|
} catch {
|
|
@@ -16540,12 +16566,12 @@ function registerMcpServer(projectRoot) {
|
|
|
16540
16566
|
}
|
|
16541
16567
|
function resolveHooksDir() {
|
|
16542
16568
|
const cwd = process.cwd();
|
|
16543
|
-
const nodeModulesPath =
|
|
16544
|
-
if (
|
|
16569
|
+
const nodeModulesPath = resolve10(cwd, "node_modules/@massu/core/dist/hooks");
|
|
16570
|
+
if (existsSync19(nodeModulesPath)) {
|
|
16545
16571
|
return "node_modules/@massu/core/dist/hooks";
|
|
16546
16572
|
}
|
|
16547
|
-
const localPath =
|
|
16548
|
-
if (
|
|
16573
|
+
const localPath = resolve10(__dirname2, "../dist/hooks");
|
|
16574
|
+
if (existsSync19(localPath)) {
|
|
16549
16575
|
return localPath;
|
|
16550
16576
|
}
|
|
16551
16577
|
return "node_modules/@massu/core/dist/hooks";
|
|
@@ -16694,8 +16720,8 @@ function installHooks(projectRoot) {
|
|
|
16694
16720
|
} catch {
|
|
16695
16721
|
claudeDirName = ".claude";
|
|
16696
16722
|
}
|
|
16697
|
-
const claudeDir =
|
|
16698
|
-
if (!
|
|
16723
|
+
const claudeDir = resolve10(projectRoot, claudeDirName);
|
|
16724
|
+
if (!existsSync19(claudeDir)) {
|
|
16699
16725
|
mkdirSync10(claudeDir, { recursive: true });
|
|
16700
16726
|
}
|
|
16701
16727
|
const settings = readSettingsLocal(claudeDir);
|
|
@@ -16714,16 +16740,16 @@ function installHooks(projectRoot) {
|
|
|
16714
16740
|
}
|
|
16715
16741
|
function initMemoryDir(projectRoot) {
|
|
16716
16742
|
const encodedRoot = encodeMemoryDirName(projectRoot);
|
|
16717
|
-
const memoryDir =
|
|
16743
|
+
const memoryDir = resolve10(homedir7(), `.claude/projects/${encodedRoot}/memory`);
|
|
16718
16744
|
let migratedFromLegacy = false;
|
|
16719
|
-
const legacyDir =
|
|
16720
|
-
if (
|
|
16745
|
+
const legacyDir = resolve10(homedir7(), `.claude/projects/-${encodedRoot}/memory`);
|
|
16746
|
+
if (existsSync19(legacyDir) && !existsSync19(memoryDir)) {
|
|
16721
16747
|
try {
|
|
16722
|
-
mkdirSync10(
|
|
16748
|
+
mkdirSync10(resolve10(memoryDir, ".."), { recursive: true });
|
|
16723
16749
|
renameSync4(legacyDir, memoryDir);
|
|
16724
16750
|
try {
|
|
16725
|
-
const legacyParent =
|
|
16726
|
-
if (
|
|
16751
|
+
const legacyParent = resolve10(legacyDir, "..");
|
|
16752
|
+
if (existsSync19(legacyParent) && readdirSync12(legacyParent).length === 0) {
|
|
16727
16753
|
rmSync6(legacyParent, { recursive: false });
|
|
16728
16754
|
}
|
|
16729
16755
|
} catch {
|
|
@@ -16733,13 +16759,13 @@ function initMemoryDir(projectRoot) {
|
|
|
16733
16759
|
}
|
|
16734
16760
|
}
|
|
16735
16761
|
let created = false;
|
|
16736
|
-
if (!
|
|
16762
|
+
if (!existsSync19(memoryDir)) {
|
|
16737
16763
|
mkdirSync10(memoryDir, { recursive: true });
|
|
16738
16764
|
created = true;
|
|
16739
16765
|
}
|
|
16740
|
-
const memoryMdPath =
|
|
16766
|
+
const memoryMdPath = resolve10(memoryDir, "MEMORY.md");
|
|
16741
16767
|
let memoryMdCreated = false;
|
|
16742
|
-
if (!
|
|
16768
|
+
if (!existsSync19(memoryMdPath)) {
|
|
16743
16769
|
const projectName = basename6(projectRoot);
|
|
16744
16770
|
const memoryContent = `# ${projectName} - Massu Memory
|
|
16745
16771
|
|
|
@@ -16853,8 +16879,8 @@ async function runInit(argv, overrides) {
|
|
|
16853
16879
|
log("Massu AI - Project Setup");
|
|
16854
16880
|
log("========================");
|
|
16855
16881
|
log("");
|
|
16856
|
-
const configPath =
|
|
16857
|
-
if (
|
|
16882
|
+
const configPath = resolve10(projectRoot, "massu.config.yaml");
|
|
16883
|
+
if (existsSync19(configPath)) {
|
|
16858
16884
|
if (opts.ci && !opts.force) {
|
|
16859
16885
|
errLog(`error: massu.config.yaml already exists at ${configPath}`);
|
|
16860
16886
|
errLog(" rerun with --force to overwrite, or remove the file first");
|
|
@@ -16993,8 +17019,8 @@ function installSideEffects(projectRoot, log, skipCommands = false, emptyStack =
|
|
|
16993
17019
|
const commandStats = cmdResult.assets.commands;
|
|
16994
17020
|
const stackResolved = !emptyStack && commandStats && (commandStats.installed > 0 || commandStats.updated > 0 || commandStats.kept > 0);
|
|
16995
17021
|
if (!stackResolved) {
|
|
16996
|
-
const placeholderPath =
|
|
16997
|
-
if (!
|
|
17022
|
+
const placeholderPath = resolve10(cmdResult.claudeDir, "commands", "_massu-needs-stack.md");
|
|
17023
|
+
if (!existsSync19(placeholderPath)) {
|
|
16998
17024
|
const placeholderBody = [
|
|
16999
17025
|
"# Massu \u2014 stack not yet detected",
|
|
17000
17026
|
"",
|
|
@@ -17015,7 +17041,7 @@ function installSideEffects(projectRoot, log, skipCommands = false, emptyStack =
|
|
|
17015
17041
|
"\u2014 Massu"
|
|
17016
17042
|
].join("\n");
|
|
17017
17043
|
try {
|
|
17018
|
-
mkdirSync10(
|
|
17044
|
+
mkdirSync10(resolve10(cmdResult.claudeDir, "commands"), { recursive: true });
|
|
17019
17045
|
writeFileSync5(placeholderPath, placeholderBody, "utf-8");
|
|
17020
17046
|
log(" Wrote _massu-needs-stack.md placeholder (no stack detected yet)");
|
|
17021
17047
|
} catch {
|
|
@@ -17038,8 +17064,8 @@ function installSideEffects(projectRoot, log, skipCommands = false, emptyStack =
|
|
|
17038
17064
|
(async () => {
|
|
17039
17065
|
try {
|
|
17040
17066
|
const encodedRoot = encodeMemoryDirName(projectRoot);
|
|
17041
|
-
const memoryDir =
|
|
17042
|
-
const memFiles =
|
|
17067
|
+
const memoryDir = resolve10(homedir7(), ".claude", "projects", encodedRoot, "memory");
|
|
17068
|
+
const memFiles = existsSync19(memoryDir) ? readdirSync12(memoryDir).filter((f2) => f2.endsWith(".md") && f2 !== "MEMORY.md") : [];
|
|
17043
17069
|
if (memFiles.length > 0) {
|
|
17044
17070
|
const { getMemoryDb: getMemoryDb2 } = await Promise.resolve().then(() => (init_memory_db(), memory_db_exports));
|
|
17045
17071
|
const db = getMemoryDb2();
|
|
@@ -17720,21 +17746,195 @@ var init_hook_registry = __esm({
|
|
|
17720
17746
|
}
|
|
17721
17747
|
});
|
|
17722
17748
|
|
|
17749
|
+
// src/preflight.ts
|
|
17750
|
+
import { existsSync as existsSync20 } from "fs";
|
|
17751
|
+
function assertCodegraphUsable(dbPath) {
|
|
17752
|
+
const path = dbPath ?? getResolvedPaths().codegraphDbPath;
|
|
17753
|
+
if (!existsSync20(path)) {
|
|
17754
|
+
throw new CodegraphDbUnusableError(path, "missing");
|
|
17755
|
+
}
|
|
17756
|
+
let db = null;
|
|
17757
|
+
try {
|
|
17758
|
+
db = openDatabase2(path, { readonly: true });
|
|
17759
|
+
const row = db.prepare("SELECT COUNT(*) AS c FROM files").get();
|
|
17760
|
+
const files = row?.c ?? 0;
|
|
17761
|
+
if (files === 0) {
|
|
17762
|
+
throw new CodegraphDbUnusableError(path, "empty");
|
|
17763
|
+
}
|
|
17764
|
+
} catch (err) {
|
|
17765
|
+
if (err instanceof CodegraphDbUnusableError) throw err;
|
|
17766
|
+
throw new CodegraphDbUnusableError(
|
|
17767
|
+
path,
|
|
17768
|
+
"unreadable",
|
|
17769
|
+
err instanceof Error ? err.message : String(err)
|
|
17770
|
+
);
|
|
17771
|
+
} finally {
|
|
17772
|
+
try {
|
|
17773
|
+
db?.close();
|
|
17774
|
+
} catch {
|
|
17775
|
+
}
|
|
17776
|
+
}
|
|
17777
|
+
}
|
|
17778
|
+
var CodegraphDbNotInitializedError, CodegraphDbUnusableError;
|
|
17779
|
+
var init_preflight = __esm({
|
|
17780
|
+
"src/preflight.ts"() {
|
|
17781
|
+
"use strict";
|
|
17782
|
+
init_db_driver();
|
|
17783
|
+
init_config();
|
|
17784
|
+
init_node_floor();
|
|
17785
|
+
CodegraphDbNotInitializedError = class extends Error {
|
|
17786
|
+
dbPath;
|
|
17787
|
+
constructor(dbPath) {
|
|
17788
|
+
super(`CodeGraph database not found at ${dbPath}`);
|
|
17789
|
+
this.name = "CodegraphDbNotInitializedError";
|
|
17790
|
+
this.dbPath = dbPath;
|
|
17791
|
+
}
|
|
17792
|
+
};
|
|
17793
|
+
CodegraphDbUnusableError = class extends CodegraphDbNotInitializedError {
|
|
17794
|
+
reason;
|
|
17795
|
+
constructor(dbPath, reason, detail) {
|
|
17796
|
+
super(dbPath);
|
|
17797
|
+
this.message = reason === "missing" ? `CodeGraph database not found at ${dbPath}` : reason === "empty" ? `CodeGraph database at ${dbPath} exists but is EMPTY (0 files indexed)` : `CodeGraph database at ${dbPath} could not be read: ${detail ?? "unknown"}`;
|
|
17798
|
+
this.name = "CodegraphDbUnusableError";
|
|
17799
|
+
this.reason = reason;
|
|
17800
|
+
}
|
|
17801
|
+
/**
|
|
17802
|
+
* The remedy, per reason. VERIFIED BY EXECUTION — `init` is a no-op on an
|
|
17803
|
+
* already-initialized repo and will NOT populate the graph. `index` is the command
|
|
17804
|
+
* that does. Getting this wrong sends the customer in a circle.
|
|
17805
|
+
*/
|
|
17806
|
+
get remedy() {
|
|
17807
|
+
switch (this.reason) {
|
|
17808
|
+
case "missing":
|
|
17809
|
+
return "npx @colbymchenry/codegraph init && npx @colbymchenry/codegraph index";
|
|
17810
|
+
case "empty":
|
|
17811
|
+
return "npx @colbymchenry/codegraph index";
|
|
17812
|
+
case "unreadable":
|
|
17813
|
+
return "npx @colbymchenry/codegraph index (the database may be corrupt \u2014 re-indexing rebuilds it)";
|
|
17814
|
+
}
|
|
17815
|
+
}
|
|
17816
|
+
/** Plain-English explanation for a human. */
|
|
17817
|
+
get humanExplanation() {
|
|
17818
|
+
switch (this.reason) {
|
|
17819
|
+
case "missing":
|
|
17820
|
+
return "Massu needs a map of your code to answer questions about it. That map has not been built yet.";
|
|
17821
|
+
case "empty":
|
|
17822
|
+
return 'The code map exists but is EMPTY \u2014 nothing was ever indexed into it. Massu would answer "no impact" to every question, which is indistinguishable from a real answer. It is refusing rather than misleading you.';
|
|
17823
|
+
case "unreadable":
|
|
17824
|
+
return "The code map exists but cannot be read. It may be corrupt.";
|
|
17825
|
+
}
|
|
17826
|
+
}
|
|
17827
|
+
};
|
|
17828
|
+
}
|
|
17829
|
+
});
|
|
17830
|
+
|
|
17831
|
+
// src/commands/hook-runner.ts
|
|
17832
|
+
var hook_runner_exports = {};
|
|
17833
|
+
__export(hook_runner_exports, {
|
|
17834
|
+
HOOK_NAME_TO_FILE: () => HOOK_NAME_TO_FILE,
|
|
17835
|
+
resolveHookFile: () => resolveHookFile,
|
|
17836
|
+
runHookRunner: () => runHookRunner
|
|
17837
|
+
});
|
|
17838
|
+
import { existsSync as existsSync21 } from "fs";
|
|
17839
|
+
import { resolve as resolve11, dirname as dirname13 } from "path";
|
|
17840
|
+
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
17841
|
+
import { spawn } from "child_process";
|
|
17842
|
+
function resolveHookFile(hookName) {
|
|
17843
|
+
const file = HOOK_NAME_TO_FILE[hookName];
|
|
17844
|
+
if (!file) {
|
|
17845
|
+
throw new Error(
|
|
17846
|
+
`Unknown hook: "${hookName}". Recognized: ${Object.keys(HOOK_NAME_TO_FILE).join(", ")}`
|
|
17847
|
+
);
|
|
17848
|
+
}
|
|
17849
|
+
const candidates = [
|
|
17850
|
+
// Bundled compiled layout: dist/cli.js → ./hooks/<file>.js
|
|
17851
|
+
resolve11(__dirname3, "hooks", file),
|
|
17852
|
+
// TS-source dev / sibling layout: src/commands/ → ../hooks/<file>
|
|
17853
|
+
resolve11(__dirname3, "../hooks", file),
|
|
17854
|
+
// TS-source dev fallback: src/commands/ → ../../dist/hooks/<file>
|
|
17855
|
+
resolve11(__dirname3, "../../dist/hooks", file)
|
|
17856
|
+
];
|
|
17857
|
+
for (const candidate of candidates) {
|
|
17858
|
+
if (existsSync21(candidate)) {
|
|
17859
|
+
return candidate;
|
|
17860
|
+
}
|
|
17861
|
+
}
|
|
17862
|
+
throw new Error(
|
|
17863
|
+
`Hook file not found for "${hookName}". Searched: ${candidates.join(", ")}. This indicates a broken @massu/core install. Re-run \`npx -y @massu/core init\`.`
|
|
17864
|
+
);
|
|
17865
|
+
}
|
|
17866
|
+
async function runHookRunner(args2) {
|
|
17867
|
+
const hookName = args2[0];
|
|
17868
|
+
if (!hookName) {
|
|
17869
|
+
process.stderr.write(
|
|
17870
|
+
`massu hook-runner: missing hook name.
|
|
17871
|
+
Usage: massu hook-runner <hook-name>
|
|
17872
|
+
Recognized: ${Object.keys(HOOK_NAME_TO_FILE).join(", ")}
|
|
17873
|
+
`
|
|
17874
|
+
);
|
|
17875
|
+
return { exitCode: 2 };
|
|
17876
|
+
}
|
|
17877
|
+
let hookFile;
|
|
17878
|
+
try {
|
|
17879
|
+
hookFile = resolveHookFile(hookName);
|
|
17880
|
+
} catch (err) {
|
|
17881
|
+
process.stderr.write(`massu hook-runner: ${err instanceof Error ? err.message : String(err)}
|
|
17882
|
+
`);
|
|
17883
|
+
return { exitCode: 2 };
|
|
17884
|
+
}
|
|
17885
|
+
return new Promise((resolvePromise) => {
|
|
17886
|
+
const child = spawn(process.execPath, [hookFile], {
|
|
17887
|
+
stdio: ["inherit", "inherit", "inherit"],
|
|
17888
|
+
// MASSU_HOOK_RUNTIME marks the hook process so the SSOT SQLite loader NEVER
|
|
17889
|
+
// self-heals here (5s budget / CR-12, CR-65 P0-003) — even for indirect opens
|
|
17890
|
+
// via getMemoryDb(). The next server/CLI touch performs the rebuild.
|
|
17891
|
+
env: { ...process.env, MASSU_HOOK_RUNTIME: "1" }
|
|
17892
|
+
});
|
|
17893
|
+
child.on("exit", (code, signal) => {
|
|
17894
|
+
if (signal) {
|
|
17895
|
+
resolvePromise({ exitCode: 128 });
|
|
17896
|
+
return;
|
|
17897
|
+
}
|
|
17898
|
+
resolvePromise({ exitCode: code ?? 0 });
|
|
17899
|
+
});
|
|
17900
|
+
child.on("error", (err) => {
|
|
17901
|
+
process.stderr.write(`massu hook-runner: failed to spawn hook "${hookName}": ${err.message}
|
|
17902
|
+
`);
|
|
17903
|
+
resolvePromise({ exitCode: 2 });
|
|
17904
|
+
});
|
|
17905
|
+
});
|
|
17906
|
+
}
|
|
17907
|
+
var __filename3, __dirname3, HOOK_NAME_TO_FILE;
|
|
17908
|
+
var init_hook_runner = __esm({
|
|
17909
|
+
"src/commands/hook-runner.ts"() {
|
|
17910
|
+
"use strict";
|
|
17911
|
+
init_hook_registry();
|
|
17912
|
+
__filename3 = fileURLToPath4(import.meta.url);
|
|
17913
|
+
__dirname3 = dirname13(__filename3);
|
|
17914
|
+
HOOK_NAME_TO_FILE = Object.freeze(
|
|
17915
|
+
Object.fromEntries(REGISTERED_HOOKS.map((name) => [name, `${name}.js`]))
|
|
17916
|
+
);
|
|
17917
|
+
}
|
|
17918
|
+
});
|
|
17919
|
+
|
|
17723
17920
|
// src/commands/doctor.ts
|
|
17724
17921
|
var doctor_exports = {};
|
|
17725
17922
|
__export(doctor_exports, {
|
|
17923
|
+
checkHookExecution: () => checkHookExecution,
|
|
17924
|
+
checkHooksConfig: () => checkHooksConfig,
|
|
17726
17925
|
checkNativeModules: () => checkNativeModules,
|
|
17926
|
+
checkShellHooksWired: () => checkShellHooksWired,
|
|
17727
17927
|
formatLicenseCheck: () => formatLicenseCheck,
|
|
17728
17928
|
runDoctor: () => runDoctor,
|
|
17729
17929
|
runValidateConfig: () => runValidateConfig
|
|
17730
17930
|
});
|
|
17731
|
-
import { existsSync as
|
|
17732
|
-
import { resolve as
|
|
17733
|
-
import { fileURLToPath as
|
|
17931
|
+
import { existsSync as existsSync22, readFileSync as readFileSync16, readdirSync as readdirSync13 } from "fs";
|
|
17932
|
+
import { resolve as resolve12, dirname as dirname14 } from "path";
|
|
17933
|
+
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
17734
17934
|
import { parse as parseYaml4 } from "yaml";
|
|
17735
17935
|
function checkConfig(projectRoot) {
|
|
17736
|
-
const configPath =
|
|
17737
|
-
if (!
|
|
17936
|
+
const configPath = resolve12(projectRoot, "massu.config.yaml");
|
|
17937
|
+
if (!existsSync22(configPath)) {
|
|
17738
17938
|
return { name: "Configuration", status: "fail", detail: "massu.config.yaml not found. Run: npx massu init" };
|
|
17739
17939
|
}
|
|
17740
17940
|
try {
|
|
@@ -17750,7 +17950,7 @@ function checkConfig(projectRoot) {
|
|
|
17750
17950
|
}
|
|
17751
17951
|
function checkMcpServer(projectRoot) {
|
|
17752
17952
|
const mcpPath = getResolvedPaths().mcpJsonPath;
|
|
17753
|
-
if (!
|
|
17953
|
+
if (!existsSync22(mcpPath)) {
|
|
17754
17954
|
return { name: "MCP Server", status: "fail", detail: ".mcp.json not found. Run: npx massu init" };
|
|
17755
17955
|
}
|
|
17756
17956
|
try {
|
|
@@ -17764,41 +17964,54 @@ function checkMcpServer(projectRoot) {
|
|
|
17764
17964
|
return { name: "MCP Server", status: "fail", detail: `.mcp.json parse error: ${err instanceof Error ? err.message : String(err)}` };
|
|
17765
17965
|
}
|
|
17766
17966
|
}
|
|
17767
|
-
function
|
|
17768
|
-
const settingsPath = getResolvedPaths()
|
|
17769
|
-
|
|
17770
|
-
|
|
17967
|
+
function readHookSources() {
|
|
17968
|
+
const { settingsPath, settingsLocalPath } = getResolvedPaths();
|
|
17969
|
+
const out = [];
|
|
17970
|
+
for (const [label, p19] of [["settings.json", settingsPath], ["settings.local.json", settingsLocalPath]]) {
|
|
17971
|
+
if (!existsSync22(p19)) continue;
|
|
17972
|
+
const content = readSettingsAtPath(p19);
|
|
17973
|
+
out.push({ label, hooks: content.hooks });
|
|
17974
|
+
}
|
|
17975
|
+
return out;
|
|
17976
|
+
}
|
|
17977
|
+
function checkHooksConfig(_projectRoot2) {
|
|
17978
|
+
const sources = readHookSources();
|
|
17979
|
+
if (sources.length === 0) {
|
|
17980
|
+
return { name: "Hooks Config", status: "fail", detail: ".claude/settings.json or settings.local.json not found. Run: npx massu init" };
|
|
17771
17981
|
}
|
|
17772
17982
|
try {
|
|
17773
|
-
const content = readSettingsAtPath(settingsPath);
|
|
17774
|
-
if (!content.hooks) {
|
|
17775
|
-
return { name: "Hooks Config", status: "fail", detail: "No hooks configured. Run: npx massu install-hooks" };
|
|
17776
|
-
}
|
|
17777
17983
|
let hookCount = 0;
|
|
17778
|
-
|
|
17779
|
-
|
|
17780
|
-
|
|
17781
|
-
|
|
17782
|
-
|
|
17783
|
-
|
|
17984
|
+
const from = [];
|
|
17985
|
+
for (const { label, hooks } of sources) {
|
|
17986
|
+
if (!hooks) continue;
|
|
17987
|
+
let n = 0;
|
|
17988
|
+
for (const groups of Object.values(hooks)) {
|
|
17989
|
+
if (Array.isArray(groups)) {
|
|
17990
|
+
for (const group of groups) {
|
|
17991
|
+
const g2 = group;
|
|
17992
|
+
if (Array.isArray(g2.hooks)) n += g2.hooks.length;
|
|
17784
17993
|
}
|
|
17785
17994
|
}
|
|
17786
17995
|
}
|
|
17996
|
+
if (n > 0) {
|
|
17997
|
+
hookCount += n;
|
|
17998
|
+
from.push(label);
|
|
17999
|
+
}
|
|
17787
18000
|
}
|
|
17788
18001
|
if (hookCount === 0) {
|
|
17789
|
-
return { name: "Hooks Config", status: "fail", detail: "
|
|
18002
|
+
return { name: "Hooks Config", status: "fail", detail: "No hooks configured. Run: npx massu install-hooks" };
|
|
17790
18003
|
}
|
|
17791
|
-
return { name: "Hooks Config", status: "pass", detail: `${hookCount} hooks configured` };
|
|
18004
|
+
return { name: "Hooks Config", status: "pass", detail: `${hookCount} hooks configured (${from.join(" + ")})` };
|
|
17792
18005
|
} catch (err) {
|
|
17793
|
-
return { name: "Hooks Config", status: "fail", detail: `settings
|
|
18006
|
+
return { name: "Hooks Config", status: "fail", detail: `settings parse error: ${err instanceof Error ? err.message : String(err)}` };
|
|
17794
18007
|
}
|
|
17795
18008
|
}
|
|
17796
18009
|
function checkHookFiles(projectRoot) {
|
|
17797
|
-
const nodeModulesHooksDir =
|
|
18010
|
+
const nodeModulesHooksDir = resolve12(projectRoot, "node_modules/@massu/core/dist/hooks");
|
|
17798
18011
|
let hooksDir = nodeModulesHooksDir;
|
|
17799
|
-
if (!
|
|
17800
|
-
const devHooksDir =
|
|
17801
|
-
if (
|
|
18012
|
+
if (!existsSync22(nodeModulesHooksDir)) {
|
|
18013
|
+
const devHooksDir = resolve12(__dirname4, "../../dist/hooks");
|
|
18014
|
+
if (existsSync22(devHooksDir)) {
|
|
17802
18015
|
hooksDir = devHooksDir;
|
|
17803
18016
|
} else {
|
|
17804
18017
|
return { name: "Hook Files", status: "fail", detail: "Compiled hooks not found. Run: npm install @massu/core" };
|
|
@@ -17806,7 +18019,7 @@ function checkHookFiles(projectRoot) {
|
|
|
17806
18019
|
}
|
|
17807
18020
|
const missing = [];
|
|
17808
18021
|
for (const hookFile of EXPECTED_HOOKS) {
|
|
17809
|
-
if (!
|
|
18022
|
+
if (!existsSync22(resolve12(hooksDir, hookFile))) {
|
|
17810
18023
|
missing.push(hookFile);
|
|
17811
18024
|
}
|
|
17812
18025
|
}
|
|
@@ -17815,6 +18028,67 @@ function checkHookFiles(projectRoot) {
|
|
|
17815
18028
|
}
|
|
17816
18029
|
return { name: "Hook Files", status: "pass", detail: `${EXPECTED_HOOKS.length}/${EXPECTED_HOOKS.length} compiled hooks present` };
|
|
17817
18030
|
}
|
|
18031
|
+
async function checkHookExecution(projectRoot, opts = {}) {
|
|
18032
|
+
const { spawnSync: spawnSync6 } = await import("child_process");
|
|
18033
|
+
const { mkdtempSync: mkdtempSync2, copyFileSync: copyFileSync4, rmSync: rmSync12 } = await import("fs");
|
|
18034
|
+
const { tmpdir: tmpdir2 } = await import("os");
|
|
18035
|
+
const node = opts.node ?? process.execPath;
|
|
18036
|
+
const timeoutMs = opts.timeoutMs ?? 1e4;
|
|
18037
|
+
const event = opts.event ?? JSON.stringify({ hook_event_name: "SessionStart", source: "massu-doctor-canary" });
|
|
18038
|
+
let hookFile;
|
|
18039
|
+
try {
|
|
18040
|
+
hookFile = opts.hookFile ?? resolveHookFile("session-start");
|
|
18041
|
+
} catch (err) {
|
|
18042
|
+
return {
|
|
18043
|
+
name: "Hook Runtime",
|
|
18044
|
+
status: "fail",
|
|
18045
|
+
detail: `Canary hook file unresolved: ${err instanceof Error ? err.message : String(err)}. Re-run: npx -y @massu/core init`
|
|
18046
|
+
};
|
|
18047
|
+
}
|
|
18048
|
+
const tmpCwd = mkdtempSync2(resolve12(tmpdir2(), "massu-hook-canary-"));
|
|
18049
|
+
try {
|
|
18050
|
+
const realConfig = resolve12(projectRoot, "massu.config.yaml");
|
|
18051
|
+
if (existsSync22(realConfig)) {
|
|
18052
|
+
try {
|
|
18053
|
+
copyFileSync4(realConfig, resolve12(tmpCwd, "massu.config.yaml"));
|
|
18054
|
+
} catch {
|
|
18055
|
+
}
|
|
18056
|
+
}
|
|
18057
|
+
const res = spawnSync6(node, [hookFile], {
|
|
18058
|
+
input: event,
|
|
18059
|
+
cwd: tmpCwd,
|
|
18060
|
+
timeout: timeoutMs,
|
|
18061
|
+
encoding: "utf-8",
|
|
18062
|
+
env: { ...process.env, MASSU_HOOK_RUNTIME: "1" }
|
|
18063
|
+
});
|
|
18064
|
+
if (res.error) {
|
|
18065
|
+
const killed = res.error.code === "ETIMEDOUT" ? " (timed out)" : "";
|
|
18066
|
+
return {
|
|
18067
|
+
name: "Hook Runtime",
|
|
18068
|
+
status: "fail",
|
|
18069
|
+
detail: `Canary hook did not run under Node ${process.version}${killed}: ${res.error.message}. Hooks would crash at runtime \u2014 upgrade Node to >= ${MIN_NODE_MAJOR}.${MIN_NODE_MINOR}.0.`
|
|
18070
|
+
};
|
|
18071
|
+
}
|
|
18072
|
+
if (res.status !== 0) {
|
|
18073
|
+
const tail = (res.stderr || "").trim().split("\n").slice(-2).join(" ");
|
|
18074
|
+
return {
|
|
18075
|
+
name: "Hook Runtime",
|
|
18076
|
+
status: "fail",
|
|
18077
|
+
detail: `Canary hook exited ${res.status ?? "null"} under Node ${process.version} \u2014 a configured hook FAILS at runtime.${tail ? ` ${tail}` : ""}`
|
|
18078
|
+
};
|
|
18079
|
+
}
|
|
18080
|
+
return {
|
|
18081
|
+
name: "Hook Runtime",
|
|
18082
|
+
status: "pass",
|
|
18083
|
+
detail: `Canary hook executes (exit 0) under Node ${process.version}`
|
|
18084
|
+
};
|
|
18085
|
+
} finally {
|
|
18086
|
+
try {
|
|
18087
|
+
rmSync12(tmpCwd, { recursive: true, force: true });
|
|
18088
|
+
} catch {
|
|
18089
|
+
}
|
|
18090
|
+
}
|
|
18091
|
+
}
|
|
17818
18092
|
async function checkNativeModules() {
|
|
17819
18093
|
const engine = resolveDbEngine();
|
|
17820
18094
|
const engineLabel = engine === "better-sqlite3" ? "better-sqlite3 (native fallback)" : "node:sqlite (native-free, Node built-in)";
|
|
@@ -17830,23 +18104,22 @@ async function checkNativeModules() {
|
|
|
17830
18104
|
detail: `${engineLabel} unusable \u2014 ${verdict.reason}${because}. ${verdict.remedy ?? NATIVE_DB_REMEDY}`
|
|
17831
18105
|
};
|
|
17832
18106
|
}
|
|
17833
|
-
function
|
|
18107
|
+
function checkNodeVersion2() {
|
|
17834
18108
|
const version = process.versions.node;
|
|
17835
|
-
const
|
|
17836
|
-
|
|
17837
|
-
|
|
17838
|
-
return { name: "Node.js", status: "pass", detail: `v${version} (>= 22.13.0 required for node:sqlite)` };
|
|
18109
|
+
const floor = `${MIN_NODE_MAJOR}.${MIN_NODE_MINOR}.0`;
|
|
18110
|
+
if (checkNodeVersion().ok) {
|
|
18111
|
+
return { name: "Node.js", status: "pass", detail: `v${version} (>= ${floor} required for node:sqlite)` };
|
|
17839
18112
|
}
|
|
17840
|
-
return { name: "Node.js", status: "fail", detail: `v${version} \u2014 Node.js >=
|
|
18113
|
+
return { name: "Node.js", status: "fail", detail: `v${version} \u2014 Node.js >= ${floor} is required (node:sqlite engine)` };
|
|
17841
18114
|
}
|
|
17842
18115
|
async function checkGitRepo(projectRoot) {
|
|
17843
|
-
const gitDir =
|
|
17844
|
-
if (!
|
|
18116
|
+
const gitDir = resolve12(projectRoot, ".git");
|
|
18117
|
+
if (!existsSync22(gitDir)) {
|
|
17845
18118
|
return { name: "Git Repository", status: "warn", detail: "Not a git repository (optional but recommended)" };
|
|
17846
18119
|
}
|
|
17847
18120
|
try {
|
|
17848
|
-
const { spawnSync:
|
|
17849
|
-
const result =
|
|
18121
|
+
const { spawnSync: spawnSync6 } = await import("child_process");
|
|
18122
|
+
const result = spawnSync6("git", ["rev-parse", "--abbrev-ref", "HEAD"], {
|
|
17850
18123
|
encoding: "utf-8",
|
|
17851
18124
|
timeout: 5e3,
|
|
17852
18125
|
cwd: projectRoot
|
|
@@ -17859,7 +18132,7 @@ async function checkGitRepo(projectRoot) {
|
|
|
17859
18132
|
}
|
|
17860
18133
|
function checkKnowledgeDb(projectRoot) {
|
|
17861
18134
|
const knowledgeDbPath = getResolvedPaths().memoryDbPath;
|
|
17862
|
-
if (!
|
|
18135
|
+
if (!existsSync22(knowledgeDbPath)) {
|
|
17863
18136
|
return {
|
|
17864
18137
|
name: "Knowledge DB",
|
|
17865
18138
|
status: "warn",
|
|
@@ -17870,7 +18143,7 @@ function checkKnowledgeDb(projectRoot) {
|
|
|
17870
18143
|
}
|
|
17871
18144
|
function checkMemoryDir(_projectRoot2) {
|
|
17872
18145
|
const memoryDir = getResolvedPaths().memoryDir;
|
|
17873
|
-
if (!
|
|
18146
|
+
if (!existsSync22(memoryDir)) {
|
|
17874
18147
|
return {
|
|
17875
18148
|
name: "Memory Directory",
|
|
17876
18149
|
status: "warn",
|
|
@@ -17880,19 +18153,22 @@ function checkMemoryDir(_projectRoot2) {
|
|
|
17880
18153
|
return { name: "Memory Directory", status: "pass", detail: `Memory directory exists` };
|
|
17881
18154
|
}
|
|
17882
18155
|
function checkShellHooksWired(_projectRoot2) {
|
|
17883
|
-
const
|
|
17884
|
-
if (
|
|
18156
|
+
const sources = readHookSources();
|
|
18157
|
+
if (sources.length === 0) {
|
|
17885
18158
|
return {
|
|
17886
18159
|
name: "Shell Hooks",
|
|
17887
18160
|
status: "fail",
|
|
17888
|
-
detail: "settings.local.json not found. Run: npx massu install-hooks"
|
|
18161
|
+
detail: "settings.json / settings.local.json not found. Run: npx massu install-hooks"
|
|
17889
18162
|
};
|
|
17890
18163
|
}
|
|
17891
18164
|
try {
|
|
17892
|
-
|
|
17893
|
-
|
|
17894
|
-
const
|
|
17895
|
-
|
|
18165
|
+
let hasSessionStart = false;
|
|
18166
|
+
let hasPreToolUse = false;
|
|
18167
|
+
for (const { hooks } of sources) {
|
|
18168
|
+
const h2 = hooks ?? {};
|
|
18169
|
+
if (Array.isArray(h2.SessionStart) && h2.SessionStart.length > 0) hasSessionStart = true;
|
|
18170
|
+
if (Array.isArray(h2.PreToolUse) && h2.PreToolUse.length > 0) hasPreToolUse = true;
|
|
18171
|
+
}
|
|
17896
18172
|
if (!hasSessionStart && !hasPreToolUse) {
|
|
17897
18173
|
return {
|
|
17898
18174
|
name: "Shell Hooks",
|
|
@@ -17900,12 +18176,12 @@ function checkShellHooksWired(_projectRoot2) {
|
|
|
17900
18176
|
detail: "No lifecycle hooks wired. Run: npx massu install-hooks"
|
|
17901
18177
|
};
|
|
17902
18178
|
}
|
|
17903
|
-
return { name: "Shell Hooks", status: "pass", detail: "Lifecycle hooks wired
|
|
18179
|
+
return { name: "Shell Hooks", status: "pass", detail: "Lifecycle hooks wired (settings.json / settings.local.json)" };
|
|
17904
18180
|
} catch (err) {
|
|
17905
18181
|
return {
|
|
17906
18182
|
name: "Shell Hooks",
|
|
17907
18183
|
status: "fail",
|
|
17908
|
-
detail: `settings
|
|
18184
|
+
detail: `settings parse error: ${err instanceof Error ? err.message : String(err)}`
|
|
17909
18185
|
};
|
|
17910
18186
|
}
|
|
17911
18187
|
}
|
|
@@ -17957,8 +18233,8 @@ async function checkLicenseStatus() {
|
|
|
17957
18233
|
async function checkApiKeyHygiene(projectRoot) {
|
|
17958
18234
|
if (getResolvedApiKeySource() !== "config") return null;
|
|
17959
18235
|
try {
|
|
17960
|
-
const { spawnSync:
|
|
17961
|
-
const res =
|
|
18236
|
+
const { spawnSync: spawnSync6 } = await import("child_process");
|
|
18237
|
+
const res = spawnSync6("git", ["ls-files", "--error-unmatch", "massu.config.yaml"], {
|
|
17962
18238
|
cwd: projectRoot,
|
|
17963
18239
|
timeout: 5e3,
|
|
17964
18240
|
encoding: "utf-8"
|
|
@@ -17977,8 +18253,8 @@ async function checkApiKeyHygiene(projectRoot) {
|
|
|
17977
18253
|
function checkPythonHealth(projectRoot) {
|
|
17978
18254
|
const config = getConfig();
|
|
17979
18255
|
if (!config.python?.root) return null;
|
|
17980
|
-
const pythonRoot =
|
|
17981
|
-
if (!
|
|
18256
|
+
const pythonRoot = resolve12(projectRoot, config.python.root);
|
|
18257
|
+
if (!existsSync22(pythonRoot)) {
|
|
17982
18258
|
return {
|
|
17983
18259
|
name: "Python",
|
|
17984
18260
|
status: "fail",
|
|
@@ -17992,15 +18268,15 @@ function checkPythonHealth(projectRoot) {
|
|
|
17992
18268
|
function scanDir(dir, depth) {
|
|
17993
18269
|
if (depth > 5) return;
|
|
17994
18270
|
try {
|
|
17995
|
-
const entries =
|
|
18271
|
+
const entries = readdirSync13(dir, { withFileTypes: true });
|
|
17996
18272
|
for (const entry of entries) {
|
|
17997
18273
|
if (entry.isDirectory()) {
|
|
17998
18274
|
const excludeDirs = config.python?.exclude_dirs || ["__pycache__", ".venv", "venv", ".mypy_cache", ".pytest_cache"];
|
|
17999
18275
|
if (!excludeDirs.includes(entry.name)) {
|
|
18000
|
-
const subdir =
|
|
18001
|
-
if (depth <= 2 && !
|
|
18276
|
+
const subdir = resolve12(dir, entry.name);
|
|
18277
|
+
if (depth <= 2 && !existsSync22(resolve12(subdir, "__init__.py"))) {
|
|
18002
18278
|
try {
|
|
18003
|
-
const subEntries =
|
|
18279
|
+
const subEntries = readdirSync13(subdir);
|
|
18004
18280
|
if (subEntries.some((f2) => f2.endsWith(".py") && f2 !== "__init__.py")) {
|
|
18005
18281
|
initPyMissing.push(entry.name);
|
|
18006
18282
|
}
|
|
@@ -18058,11 +18334,12 @@ async function runDoctor() {
|
|
|
18058
18334
|
checkMcpServer(projectRoot),
|
|
18059
18335
|
checkHooksConfig(projectRoot),
|
|
18060
18336
|
checkHookFiles(projectRoot),
|
|
18337
|
+
await checkHookExecution(projectRoot),
|
|
18061
18338
|
checkKnowledgeDb(projectRoot),
|
|
18062
18339
|
checkMemoryDir(projectRoot),
|
|
18063
18340
|
checkShellHooksWired(projectRoot),
|
|
18064
18341
|
await checkNativeModules(),
|
|
18065
|
-
|
|
18342
|
+
checkNodeVersion2(),
|
|
18066
18343
|
await checkGitRepo(projectRoot),
|
|
18067
18344
|
await checkLicenseStatus()
|
|
18068
18345
|
];
|
|
@@ -18095,8 +18372,8 @@ async function runDoctor() {
|
|
|
18095
18372
|
}
|
|
18096
18373
|
async function runValidateConfig() {
|
|
18097
18374
|
const projectRoot = process.cwd();
|
|
18098
|
-
const configPath =
|
|
18099
|
-
if (!
|
|
18375
|
+
const configPath = resolve12(projectRoot, "massu.config.yaml");
|
|
18376
|
+
if (!existsSync22(configPath)) {
|
|
18100
18377
|
console.error("Error: massu.config.yaml not found in current directory");
|
|
18101
18378
|
console.error("Run: npx massu init");
|
|
18102
18379
|
process.exit(1);
|
|
@@ -18135,7 +18412,7 @@ async function runValidateConfig() {
|
|
|
18135
18412
|
process.exit(1);
|
|
18136
18413
|
}
|
|
18137
18414
|
}
|
|
18138
|
-
var
|
|
18415
|
+
var __filename4, __dirname4, EXPECTED_HOOKS;
|
|
18139
18416
|
var init_doctor = __esm({
|
|
18140
18417
|
"src/commands/doctor.ts"() {
|
|
18141
18418
|
"use strict";
|
|
@@ -18145,8 +18422,10 @@ var init_doctor = __esm({
|
|
|
18145
18422
|
init_settings_local();
|
|
18146
18423
|
init_hook_registry();
|
|
18147
18424
|
init_db_driver();
|
|
18148
|
-
|
|
18149
|
-
|
|
18425
|
+
init_preflight();
|
|
18426
|
+
init_hook_runner();
|
|
18427
|
+
__filename4 = fileURLToPath5(import.meta.url);
|
|
18428
|
+
__dirname4 = dirname14(__filename4);
|
|
18150
18429
|
EXPECTED_HOOKS = getExpectedHookFiles();
|
|
18151
18430
|
}
|
|
18152
18431
|
});
|
|
@@ -18435,102 +18714,13 @@ var init_install_hooks = __esm({
|
|
|
18435
18714
|
}
|
|
18436
18715
|
});
|
|
18437
18716
|
|
|
18438
|
-
// src/commands/hook-runner.ts
|
|
18439
|
-
var hook_runner_exports = {};
|
|
18440
|
-
__export(hook_runner_exports, {
|
|
18441
|
-
HOOK_NAME_TO_FILE: () => HOOK_NAME_TO_FILE,
|
|
18442
|
-
resolveHookFile: () => resolveHookFile,
|
|
18443
|
-
runHookRunner: () => runHookRunner
|
|
18444
|
-
});
|
|
18445
|
-
import { existsSync as existsSync20 } from "fs";
|
|
18446
|
-
import { resolve as resolve11, dirname as dirname14 } from "path";
|
|
18447
|
-
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
18448
|
-
import { spawn } from "child_process";
|
|
18449
|
-
function resolveHookFile(hookName) {
|
|
18450
|
-
const file = HOOK_NAME_TO_FILE[hookName];
|
|
18451
|
-
if (!file) {
|
|
18452
|
-
throw new Error(
|
|
18453
|
-
`Unknown hook: "${hookName}". Recognized: ${Object.keys(HOOK_NAME_TO_FILE).join(", ")}`
|
|
18454
|
-
);
|
|
18455
|
-
}
|
|
18456
|
-
const candidates = [
|
|
18457
|
-
// Bundled compiled layout: dist/cli.js → ./hooks/<file>.js
|
|
18458
|
-
resolve11(__dirname4, "hooks", file),
|
|
18459
|
-
// TS-source dev / sibling layout: src/commands/ → ../hooks/<file>
|
|
18460
|
-
resolve11(__dirname4, "../hooks", file),
|
|
18461
|
-
// TS-source dev fallback: src/commands/ → ../../dist/hooks/<file>
|
|
18462
|
-
resolve11(__dirname4, "../../dist/hooks", file)
|
|
18463
|
-
];
|
|
18464
|
-
for (const candidate of candidates) {
|
|
18465
|
-
if (existsSync20(candidate)) {
|
|
18466
|
-
return candidate;
|
|
18467
|
-
}
|
|
18468
|
-
}
|
|
18469
|
-
throw new Error(
|
|
18470
|
-
`Hook file not found for "${hookName}". Searched: ${candidates.join(", ")}. This indicates a broken @massu/core install. Re-run \`npx -y @massu/core init\`.`
|
|
18471
|
-
);
|
|
18472
|
-
}
|
|
18473
|
-
async function runHookRunner(args2) {
|
|
18474
|
-
const hookName = args2[0];
|
|
18475
|
-
if (!hookName) {
|
|
18476
|
-
process.stderr.write(
|
|
18477
|
-
`massu hook-runner: missing hook name.
|
|
18478
|
-
Usage: massu hook-runner <hook-name>
|
|
18479
|
-
Recognized: ${Object.keys(HOOK_NAME_TO_FILE).join(", ")}
|
|
18480
|
-
`
|
|
18481
|
-
);
|
|
18482
|
-
return { exitCode: 2 };
|
|
18483
|
-
}
|
|
18484
|
-
let hookFile;
|
|
18485
|
-
try {
|
|
18486
|
-
hookFile = resolveHookFile(hookName);
|
|
18487
|
-
} catch (err) {
|
|
18488
|
-
process.stderr.write(`massu hook-runner: ${err instanceof Error ? err.message : String(err)}
|
|
18489
|
-
`);
|
|
18490
|
-
return { exitCode: 2 };
|
|
18491
|
-
}
|
|
18492
|
-
return new Promise((resolvePromise) => {
|
|
18493
|
-
const child = spawn(process.execPath, [hookFile], {
|
|
18494
|
-
stdio: ["inherit", "inherit", "inherit"],
|
|
18495
|
-
// MASSU_HOOK_RUNTIME marks the hook process so the SSOT SQLite loader NEVER
|
|
18496
|
-
// self-heals here (5s budget / CR-12, CR-65 P0-003) — even for indirect opens
|
|
18497
|
-
// via getMemoryDb(). The next server/CLI touch performs the rebuild.
|
|
18498
|
-
env: { ...process.env, MASSU_HOOK_RUNTIME: "1" }
|
|
18499
|
-
});
|
|
18500
|
-
child.on("exit", (code, signal) => {
|
|
18501
|
-
if (signal) {
|
|
18502
|
-
resolvePromise({ exitCode: 128 });
|
|
18503
|
-
return;
|
|
18504
|
-
}
|
|
18505
|
-
resolvePromise({ exitCode: code ?? 0 });
|
|
18506
|
-
});
|
|
18507
|
-
child.on("error", (err) => {
|
|
18508
|
-
process.stderr.write(`massu hook-runner: failed to spawn hook "${hookName}": ${err.message}
|
|
18509
|
-
`);
|
|
18510
|
-
resolvePromise({ exitCode: 2 });
|
|
18511
|
-
});
|
|
18512
|
-
});
|
|
18513
|
-
}
|
|
18514
|
-
var __filename4, __dirname4, HOOK_NAME_TO_FILE;
|
|
18515
|
-
var init_hook_runner = __esm({
|
|
18516
|
-
"src/commands/hook-runner.ts"() {
|
|
18517
|
-
"use strict";
|
|
18518
|
-
init_hook_registry();
|
|
18519
|
-
__filename4 = fileURLToPath5(import.meta.url);
|
|
18520
|
-
__dirname4 = dirname14(__filename4);
|
|
18521
|
-
HOOK_NAME_TO_FILE = Object.freeze(
|
|
18522
|
-
Object.fromEntries(REGISTERED_HOOKS.map((name) => [name, `${name}.js`]))
|
|
18523
|
-
);
|
|
18524
|
-
}
|
|
18525
|
-
});
|
|
18526
|
-
|
|
18527
18717
|
// src/commands/permissions.ts
|
|
18528
18718
|
var permissions_exports = {};
|
|
18529
18719
|
__export(permissions_exports, {
|
|
18530
18720
|
handlePermissionsSubcommand: () => handlePermissionsSubcommand,
|
|
18531
18721
|
printPermissionsHelp: () => printPermissionsHelp
|
|
18532
18722
|
});
|
|
18533
|
-
import { resolve as
|
|
18723
|
+
import { resolve as resolve13 } from "path";
|
|
18534
18724
|
function resolveClaudeDir2() {
|
|
18535
18725
|
let claudeDirName = ".claude";
|
|
18536
18726
|
try {
|
|
@@ -18538,7 +18728,7 @@ function resolveClaudeDir2() {
|
|
|
18538
18728
|
} catch {
|
|
18539
18729
|
claudeDirName = ".claude";
|
|
18540
18730
|
}
|
|
18541
|
-
return
|
|
18731
|
+
return resolve13(process.cwd(), claudeDirName);
|
|
18542
18732
|
}
|
|
18543
18733
|
async function handlePermissionsSubcommand(args2) {
|
|
18544
18734
|
const sub = args2[0];
|
|
@@ -18656,7 +18846,7 @@ var db_exports = {};
|
|
|
18656
18846
|
__export(db_exports, {
|
|
18657
18847
|
handleDbSubcommand: () => handleDbSubcommand
|
|
18658
18848
|
});
|
|
18659
|
-
import { existsSync as
|
|
18849
|
+
import { existsSync as existsSync23, statSync as statSync11 } from "fs";
|
|
18660
18850
|
import { basename as basename7 } from "path";
|
|
18661
18851
|
function human(bytes) {
|
|
18662
18852
|
if (bytes < 1024) return `${bytes} B`;
|
|
@@ -18701,7 +18891,7 @@ async function handleDbSubcommand(args2) {
|
|
|
18701
18891
|
|
|
18702
18892
|
`);
|
|
18703
18893
|
for (const store of allStores()) {
|
|
18704
|
-
if (!
|
|
18894
|
+
if (!existsSync23(store.path)) {
|
|
18705
18895
|
process.stdout.write(` ${"\u2014"} ${store.name.padEnd(10)} not present, skipped
|
|
18706
18896
|
`);
|
|
18707
18897
|
continue;
|
|
@@ -18799,12 +18989,12 @@ Restore with: massu db restore --latest memory
|
|
|
18799
18989
|
target = found.path;
|
|
18800
18990
|
}
|
|
18801
18991
|
try {
|
|
18802
|
-
const before =
|
|
18992
|
+
const before = existsSync23(target) ? statSync11(target).size : 0;
|
|
18803
18993
|
const res = restoreDb(backupPath, target);
|
|
18804
18994
|
process.stdout.write(
|
|
18805
18995
|
`Restored ${basename7(target)}
|
|
18806
18996
|
from : ${res.restoredFrom}
|
|
18807
|
-
size : ${human(before)} -> ${human(
|
|
18997
|
+
size : ${human(before)} -> ${human(statSync11(target).size)}
|
|
18808
18998
|
` + (res.preservedOriginal ? ` the previous file was NOT destroyed \u2014 kept at:
|
|
18809
18999
|
${res.preservedOriginal}
|
|
18810
19000
|
` : "") + ` integrity_check: ok (verified before AND after the restore)
|
|
@@ -18965,8 +19155,8 @@ var init_license2 = __esm({
|
|
|
18965
19155
|
});
|
|
18966
19156
|
|
|
18967
19157
|
// src/changelog-generator.ts
|
|
18968
|
-
import { existsSync as
|
|
18969
|
-
import { resolve as
|
|
19158
|
+
import { existsSync as existsSync24, readFileSync as readFileSync17, readdirSync as readdirSync14 } from "fs";
|
|
19159
|
+
import { resolve as resolve14 } from "path";
|
|
18970
19160
|
function parseCommitsForPlanTokens(subjects) {
|
|
18971
19161
|
const tokens = /* @__PURE__ */ new Set();
|
|
18972
19162
|
const maintenance = [];
|
|
@@ -18983,15 +19173,15 @@ function parseCommitsForPlanTokens(subjects) {
|
|
|
18983
19173
|
function loadPlanSummaries(tokens, planDir) {
|
|
18984
19174
|
const result = /* @__PURE__ */ new Map();
|
|
18985
19175
|
if (tokens.size === 0) return result;
|
|
18986
|
-
if (!
|
|
19176
|
+
if (!existsSync24(planDir)) {
|
|
18987
19177
|
throw new Error(`Plan directory does not exist: ${planDir}`);
|
|
18988
19178
|
}
|
|
18989
|
-
const files =
|
|
19179
|
+
const files = readdirSync14(planDir).filter((f2) => f2.endsWith(".md"));
|
|
18990
19180
|
for (const token of tokens) {
|
|
18991
19181
|
let matchedFile = null;
|
|
18992
19182
|
let content = "";
|
|
18993
19183
|
for (const file of files) {
|
|
18994
|
-
const path =
|
|
19184
|
+
const path = resolve14(planDir, file);
|
|
18995
19185
|
const text18 = readFileSync17(path, "utf-8");
|
|
18996
19186
|
const tokenRe = new RegExp(
|
|
18997
19187
|
`^\\*\\*Plan Token\\*\\*:\\s*\`?${token.replace(/[.*+?^${}()|[\\]\\\\]/g, "\\$&")}\`?(\\s|$)`,
|
|
@@ -19073,8 +19263,8 @@ __export(changelog_exports, {
|
|
|
19073
19263
|
printChangelogHelp: () => printChangelogHelp
|
|
19074
19264
|
});
|
|
19075
19265
|
import { execSync } from "child_process";
|
|
19076
|
-
import { existsSync as
|
|
19077
|
-
import { resolve as
|
|
19266
|
+
import { existsSync as existsSync25, readFileSync as readFileSync18 } from "fs";
|
|
19267
|
+
import { resolve as resolve15 } from "path";
|
|
19078
19268
|
function resolveRepoRoot() {
|
|
19079
19269
|
try {
|
|
19080
19270
|
return execSync("git rev-parse --show-toplevel", { encoding: "utf-8" }).trim();
|
|
@@ -19098,8 +19288,8 @@ function getCommitSubjects(range) {
|
|
|
19098
19288
|
}
|
|
19099
19289
|
}
|
|
19100
19290
|
function getCurrentVersion(repoRoot) {
|
|
19101
|
-
const pkgPath =
|
|
19102
|
-
if (!
|
|
19291
|
+
const pkgPath = resolve15(repoRoot, "packages/core/package.json");
|
|
19292
|
+
if (!existsSync25(pkgPath)) return "0.0.0";
|
|
19103
19293
|
const pkg = JSON.parse(readFileSync18(pkgPath, "utf-8"));
|
|
19104
19294
|
return pkg.version || "0.0.0";
|
|
19105
19295
|
}
|
|
@@ -19107,8 +19297,8 @@ function todayDate() {
|
|
|
19107
19297
|
return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
19108
19298
|
}
|
|
19109
19299
|
function getLatestChangelogEntryBody(repoRoot) {
|
|
19110
|
-
const path =
|
|
19111
|
-
if (!
|
|
19300
|
+
const path = resolve15(repoRoot, "CHANGELOG.md");
|
|
19301
|
+
if (!existsSync25(path)) return "";
|
|
19112
19302
|
const content = readFileSync18(path, "utf-8");
|
|
19113
19303
|
const m3 = content.match(/^## \[[\d.]+\][^\n]*\n([\s\S]*?)(?=\n## \[|$)/m);
|
|
19114
19304
|
return m3 ? m3[1] : "";
|
|
@@ -19116,7 +19306,7 @@ function getLatestChangelogEntryBody(repoRoot) {
|
|
|
19116
19306
|
async function handleChangelogSubcommand(args2) {
|
|
19117
19307
|
const sub = args2[0];
|
|
19118
19308
|
const repoRoot = resolveRepoRoot();
|
|
19119
|
-
const planDir =
|
|
19309
|
+
const planDir = resolve15(repoRoot, "docs/plans");
|
|
19120
19310
|
switch (sub) {
|
|
19121
19311
|
case "generate": {
|
|
19122
19312
|
const lastTag = getLastTag();
|
|
@@ -19205,11 +19395,11 @@ var init_changelog = __esm({
|
|
|
19205
19395
|
|
|
19206
19396
|
// src/knowledge-db.ts
|
|
19207
19397
|
import { dirname as dirname15 } from "path";
|
|
19208
|
-
import { existsSync as
|
|
19398
|
+
import { existsSync as existsSync26, mkdirSync as mkdirSync11 } from "fs";
|
|
19209
19399
|
function getKnowledgeDb() {
|
|
19210
19400
|
const dbPath = getResolvedPaths().knowledgeDbPath;
|
|
19211
19401
|
const dir = dirname15(dbPath);
|
|
19212
|
-
if (!
|
|
19402
|
+
if (!existsSync26(dir)) {
|
|
19213
19403
|
mkdirSync11(dir, { recursive: true });
|
|
19214
19404
|
}
|
|
19215
19405
|
const db = openDatabase2(dbPath);
|
|
@@ -19436,7 +19626,7 @@ var memory_embed_backfill_exports = {};
|
|
|
19436
19626
|
__export(memory_embed_backfill_exports, {
|
|
19437
19627
|
runMemoryEmbedBackfill: () => runMemoryEmbedBackfill
|
|
19438
19628
|
});
|
|
19439
|
-
import { existsSync as
|
|
19629
|
+
import { existsSync as existsSync27 } from "fs";
|
|
19440
19630
|
async function runMemoryEmbedBackfill(_args = []) {
|
|
19441
19631
|
await embed("massu memory embed backfill probe");
|
|
19442
19632
|
const active = getActiveEmbedModel();
|
|
@@ -19463,7 +19653,7 @@ async function runMemoryEmbedBackfill(_args = []) {
|
|
|
19463
19653
|
);
|
|
19464
19654
|
let chunks = { embedded: 0, scanned: 0 };
|
|
19465
19655
|
const knowledgeDbPath = getResolvedPaths().knowledgeDbPath;
|
|
19466
|
-
if (
|
|
19656
|
+
if (existsSync27(knowledgeDbPath)) {
|
|
19467
19657
|
const knowledgeDb = getKnowledgeDb();
|
|
19468
19658
|
try {
|
|
19469
19659
|
chunks = await embedMissingChunks(knowledgeDb);
|
|
@@ -19496,16 +19686,16 @@ var init_memory_embed_backfill = __esm({
|
|
|
19496
19686
|
|
|
19497
19687
|
// src/memory-authorship.ts
|
|
19498
19688
|
import { createHmac, randomBytes, timingSafeEqual } from "crypto";
|
|
19499
|
-
import { readFileSync as readFileSync19, writeFileSync as writeFileSync6, existsSync as
|
|
19500
|
-
import { homedir as
|
|
19501
|
-
import { resolve as
|
|
19502
|
-
function renderKeyPath(home =
|
|
19503
|
-
return
|
|
19689
|
+
import { readFileSync as readFileSync19, writeFileSync as writeFileSync6, existsSync as existsSync28, mkdirSync as mkdirSync12, chmodSync as chmodSync6, statSync as statSync12 } from "fs";
|
|
19690
|
+
import { homedir as homedir8 } from "os";
|
|
19691
|
+
import { resolve as resolve16 } from "path";
|
|
19692
|
+
function renderKeyPath(home = homedir8()) {
|
|
19693
|
+
return resolve16(home, ".massu", "render-key");
|
|
19504
19694
|
}
|
|
19505
|
-
function readRenderKey(home =
|
|
19695
|
+
function readRenderKey(home = homedir8()) {
|
|
19506
19696
|
const p19 = renderKeyPath(home);
|
|
19507
19697
|
try {
|
|
19508
|
-
if (!
|
|
19698
|
+
if (!existsSync28(p19)) return void 0;
|
|
19509
19699
|
const raw = readFileSync19(p19);
|
|
19510
19700
|
if (raw.length !== 32) return void 0;
|
|
19511
19701
|
return raw;
|
|
@@ -19513,12 +19703,12 @@ function readRenderKey(home = homedir7()) {
|
|
|
19513
19703
|
return void 0;
|
|
19514
19704
|
}
|
|
19515
19705
|
}
|
|
19516
|
-
function ensureRenderKey(home =
|
|
19706
|
+
function ensureRenderKey(home = homedir8()) {
|
|
19517
19707
|
const existing = readRenderKey(home);
|
|
19518
19708
|
if (existing) return existing;
|
|
19519
19709
|
const p19 = renderKeyPath(home);
|
|
19520
19710
|
try {
|
|
19521
|
-
const dir =
|
|
19711
|
+
const dir = resolve16(home, ".massu");
|
|
19522
19712
|
mkdirSync12(dir, { recursive: true, mode: 448 });
|
|
19523
19713
|
try {
|
|
19524
19714
|
chmodSync6(dir, 448);
|
|
@@ -19535,7 +19725,7 @@ function ensureRenderKey(home = homedir7()) {
|
|
|
19535
19725
|
return void 0;
|
|
19536
19726
|
}
|
|
19537
19727
|
}
|
|
19538
|
-
function mintAuthorship(body, home =
|
|
19728
|
+
function mintAuthorship(body, home = homedir8()) {
|
|
19539
19729
|
try {
|
|
19540
19730
|
const key = ensureRenderKey(home);
|
|
19541
19731
|
if (!key) return null;
|
|
@@ -19544,7 +19734,7 @@ function mintAuthorship(body, home = homedir7()) {
|
|
|
19544
19734
|
return null;
|
|
19545
19735
|
}
|
|
19546
19736
|
}
|
|
19547
|
-
function verifyAuthorship(body, frontmatter, storeRow, home =
|
|
19737
|
+
function verifyAuthorship(body, frontmatter, storeRow, home = homedir8()) {
|
|
19548
19738
|
try {
|
|
19549
19739
|
if (storeRow?.adopted_human_at_epoch != null) return false;
|
|
19550
19740
|
const key = readRenderKey(home);
|
|
@@ -19564,7 +19754,7 @@ function extractRenderMac(frontmatter) {
|
|
|
19564
19754
|
const v3 = frontmatter?.[RENDER_MAC_KEY];
|
|
19565
19755
|
return typeof v3 === "string" && v3.length > 0 ? v3 : null;
|
|
19566
19756
|
}
|
|
19567
|
-
function renderKeyExists(home =
|
|
19757
|
+
function renderKeyExists(home = homedir8()) {
|
|
19568
19758
|
return readRenderKey(home) !== void 0;
|
|
19569
19759
|
}
|
|
19570
19760
|
var RENDER_MAC_KEY;
|
|
@@ -19576,11 +19766,11 @@ var init_memory_authorship = __esm({
|
|
|
19576
19766
|
});
|
|
19577
19767
|
|
|
19578
19768
|
// src/rule-candidate-snapshot.ts
|
|
19579
|
-
import { existsSync as
|
|
19769
|
+
import { existsSync as existsSync29, readFileSync as readFileSync20, writeFileSync as writeFileSync7, unlinkSync as unlinkSync4 } from "fs";
|
|
19580
19770
|
function takeSnapshots(paths) {
|
|
19581
19771
|
const out = /* @__PURE__ */ new Map();
|
|
19582
19772
|
for (const p19 of paths) {
|
|
19583
|
-
if (
|
|
19773
|
+
if (existsSync29(p19)) out.set(p19, readFileSync20(p19, "utf-8"));
|
|
19584
19774
|
else out.set(p19, null);
|
|
19585
19775
|
}
|
|
19586
19776
|
return out;
|
|
@@ -19590,7 +19780,7 @@ function restoreSnapshots(snapshot) {
|
|
|
19590
19780
|
for (const [path, content] of snapshot) {
|
|
19591
19781
|
try {
|
|
19592
19782
|
if (content === null) {
|
|
19593
|
-
if (
|
|
19783
|
+
if (existsSync29(path)) unlinkSync4(path);
|
|
19594
19784
|
} else {
|
|
19595
19785
|
writeFileSync7(path, content, "utf-8");
|
|
19596
19786
|
}
|
|
@@ -19670,7 +19860,7 @@ var init_memory_render_path = __esm({
|
|
|
19670
19860
|
});
|
|
19671
19861
|
|
|
19672
19862
|
// src/memory-tombstones.ts
|
|
19673
|
-
import { readFileSync as readFileSync21, appendFileSync as appendFileSync3, existsSync as
|
|
19863
|
+
import { readFileSync as readFileSync21, appendFileSync as appendFileSync3, existsSync as existsSync30 } from "fs";
|
|
19674
19864
|
import { join as join16 } from "path";
|
|
19675
19865
|
function tombstoneLedgerPath(memoryDir) {
|
|
19676
19866
|
return join16(memoryDir, TOMBSTONE_LEDGER);
|
|
@@ -19678,7 +19868,7 @@ function tombstoneLedgerPath(memoryDir) {
|
|
|
19678
19868
|
function readTombstones(memoryDir) {
|
|
19679
19869
|
const out = /* @__PURE__ */ new Map();
|
|
19680
19870
|
const p19 = tombstoneLedgerPath(memoryDir);
|
|
19681
|
-
if (!
|
|
19871
|
+
if (!existsSync30(p19)) return out;
|
|
19682
19872
|
let raw;
|
|
19683
19873
|
try {
|
|
19684
19874
|
raw = readFileSync21(p19, "utf8");
|
|
@@ -19920,29 +20110,29 @@ var init_memory_llm = __esm({
|
|
|
19920
20110
|
|
|
19921
20111
|
// src/memory-backup.ts
|
|
19922
20112
|
import {
|
|
19923
|
-
readdirSync as
|
|
20113
|
+
readdirSync as readdirSync15,
|
|
19924
20114
|
mkdirSync as mkdirSync13,
|
|
19925
20115
|
copyFileSync as copyFileSync2,
|
|
19926
|
-
statSync as
|
|
19927
|
-
existsSync as
|
|
20116
|
+
statSync as statSync13,
|
|
20117
|
+
existsSync as existsSync31,
|
|
19928
20118
|
rmSync as rmSync7,
|
|
19929
20119
|
readFileSync as readFileSync22
|
|
19930
20120
|
} from "fs";
|
|
19931
|
-
import { homedir as
|
|
19932
|
-
import { join as join17, resolve as
|
|
19933
|
-
function backupsRoot(home =
|
|
19934
|
-
return
|
|
20121
|
+
import { homedir as homedir9 } from "os";
|
|
20122
|
+
import { join as join17, resolve as resolve17 } from "path";
|
|
20123
|
+
function backupsRoot(home = homedir9()) {
|
|
20124
|
+
return resolve17(home, ".massu", "memory-backups");
|
|
19935
20125
|
}
|
|
19936
20126
|
function backupStamp2(nowMs) {
|
|
19937
20127
|
return new Date(nowMs).toISOString().replace(/:/g, "-");
|
|
19938
20128
|
}
|
|
19939
20129
|
function newestMtimeMs(dir) {
|
|
19940
|
-
if (!
|
|
20130
|
+
if (!existsSync31(dir)) return 0;
|
|
19941
20131
|
let newest = 0;
|
|
19942
|
-
for (const entry of
|
|
20132
|
+
for (const entry of readdirSync15(dir)) {
|
|
19943
20133
|
const p19 = join17(dir, entry);
|
|
19944
20134
|
try {
|
|
19945
|
-
const st =
|
|
20135
|
+
const st = statSync13(p19);
|
|
19946
20136
|
if (st.isFile() && st.mtimeMs > newest) newest = st.mtimeMs;
|
|
19947
20137
|
} catch {
|
|
19948
20138
|
continue;
|
|
@@ -19950,14 +20140,14 @@ function newestMtimeMs(dir) {
|
|
|
19950
20140
|
}
|
|
19951
20141
|
return newest;
|
|
19952
20142
|
}
|
|
19953
|
-
function listBackups(home =
|
|
20143
|
+
function listBackups(home = homedir9()) {
|
|
19954
20144
|
const root = backupsRoot(home);
|
|
19955
|
-
if (!
|
|
20145
|
+
if (!existsSync31(root)) return [];
|
|
19956
20146
|
const out = [];
|
|
19957
|
-
for (const stamp of
|
|
20147
|
+
for (const stamp of readdirSync15(root)) {
|
|
19958
20148
|
const dir = join17(root, stamp);
|
|
19959
20149
|
try {
|
|
19960
|
-
const st =
|
|
20150
|
+
const st = statSync13(dir);
|
|
19961
20151
|
if (!st.isDirectory()) continue;
|
|
19962
20152
|
out.push({ stamp, dir, createdMs: st.mtimeMs });
|
|
19963
20153
|
} catch {
|
|
@@ -19966,24 +20156,24 @@ function listBackups(home = homedir8()) {
|
|
|
19966
20156
|
}
|
|
19967
20157
|
return out.sort((a2, b2) => b2.createdMs - a2.createdMs);
|
|
19968
20158
|
}
|
|
19969
|
-
function hasFreshBackup(memoryDir, home =
|
|
20159
|
+
function hasFreshBackup(memoryDir, home = homedir9()) {
|
|
19970
20160
|
const backups = listBackups(home);
|
|
19971
20161
|
if (backups.length === 0) return false;
|
|
19972
20162
|
const newestChange = newestMtimeMs(memoryDir);
|
|
19973
20163
|
return backups[0].createdMs >= newestChange;
|
|
19974
20164
|
}
|
|
19975
|
-
function takeBackup(memoryDir, nowMs, home =
|
|
19976
|
-
if (!
|
|
20165
|
+
function takeBackup(memoryDir, nowMs, home = homedir9(), retention = DEFAULT_RETENTION2) {
|
|
20166
|
+
if (!existsSync31(memoryDir)) {
|
|
19977
20167
|
throw new BackupError(`memory directory does not exist: ${memoryDir}`);
|
|
19978
20168
|
}
|
|
19979
20169
|
const stamp = backupStamp2(nowMs);
|
|
19980
20170
|
const dir = join17(backupsRoot(home), stamp);
|
|
19981
20171
|
try {
|
|
19982
20172
|
mkdirSync13(dir, { recursive: true, mode: 448 });
|
|
19983
|
-
for (const entry of
|
|
20173
|
+
for (const entry of readdirSync15(memoryDir)) {
|
|
19984
20174
|
const srcPath = join17(memoryDir, entry);
|
|
19985
20175
|
try {
|
|
19986
|
-
if (!
|
|
20176
|
+
if (!statSync13(srcPath).isFile()) continue;
|
|
19987
20177
|
} catch {
|
|
19988
20178
|
continue;
|
|
19989
20179
|
}
|
|
@@ -19995,7 +20185,7 @@ function takeBackup(memoryDir, nowMs, home = homedir8(), retention = DEFAULT_RET
|
|
|
19995
20185
|
pruneBackups(home, retention);
|
|
19996
20186
|
return { stamp, dir, createdMs: nowMs };
|
|
19997
20187
|
}
|
|
19998
|
-
function pruneBackups(home =
|
|
20188
|
+
function pruneBackups(home = homedir9(), retention = DEFAULT_RETENTION2) {
|
|
19999
20189
|
const backups = listBackups(home);
|
|
20000
20190
|
for (const stale of backups.slice(Math.max(retention, 1))) {
|
|
20001
20191
|
try {
|
|
@@ -20005,22 +20195,22 @@ function pruneBackups(home = homedir8(), retention = DEFAULT_RETENTION2) {
|
|
|
20005
20195
|
}
|
|
20006
20196
|
}
|
|
20007
20197
|
function restoreBackup(memoryDir, opts = {}) {
|
|
20008
|
-
const home = opts.home ??
|
|
20198
|
+
const home = opts.home ?? homedir9();
|
|
20009
20199
|
const backups = listBackups(home);
|
|
20010
20200
|
if (backups.length === 0) throw new BackupError("no backups exist");
|
|
20011
20201
|
const chosen = opts.from ? backups.find((b2) => b2.stamp === opts.from) : backups[0];
|
|
20012
20202
|
if (!chosen) throw new BackupError(`no backup with stamp: ${opts.from}`);
|
|
20013
20203
|
const wouldRestore = [];
|
|
20014
|
-
for (const entry of
|
|
20204
|
+
for (const entry of readdirSync15(chosen.dir)) {
|
|
20015
20205
|
try {
|
|
20016
|
-
if (
|
|
20206
|
+
if (statSync13(join17(chosen.dir, entry)).isFile()) wouldRestore.push(entry);
|
|
20017
20207
|
} catch {
|
|
20018
20208
|
continue;
|
|
20019
20209
|
}
|
|
20020
20210
|
}
|
|
20021
|
-
const currentFiles =
|
|
20211
|
+
const currentFiles = existsSync31(memoryDir) ? readdirSync15(memoryDir).filter((e2) => {
|
|
20022
20212
|
try {
|
|
20023
|
-
return
|
|
20213
|
+
return statSync13(join17(memoryDir, e2)).isFile();
|
|
20024
20214
|
} catch {
|
|
20025
20215
|
return false;
|
|
20026
20216
|
}
|
|
@@ -20064,7 +20254,7 @@ var init_memory_backup = __esm({
|
|
|
20064
20254
|
});
|
|
20065
20255
|
|
|
20066
20256
|
// src/memory-index-region.ts
|
|
20067
|
-
import { readFileSync as readFileSync23, existsSync as
|
|
20257
|
+
import { readFileSync as readFileSync23, existsSync as existsSync32 } from "fs";
|
|
20068
20258
|
import { dirname as dirname16, join as join18 } from "path";
|
|
20069
20259
|
function parseRegion(content) {
|
|
20070
20260
|
const begins = countOccurrences(content, BEGIN_SENTINEL);
|
|
@@ -20169,7 +20359,7 @@ function withMemoryIndexLock(memoryDir, fn) {
|
|
|
20169
20359
|
});
|
|
20170
20360
|
}
|
|
20171
20361
|
function readMemoryIndex(indexPath) {
|
|
20172
|
-
if (!
|
|
20362
|
+
if (!existsSync32(indexPath)) return void 0;
|
|
20173
20363
|
try {
|
|
20174
20364
|
return readFileSync23(indexPath, "utf8");
|
|
20175
20365
|
} catch {
|
|
@@ -20242,9 +20432,9 @@ var init_memory_files_config = __esm({
|
|
|
20242
20432
|
});
|
|
20243
20433
|
|
|
20244
20434
|
// src/memory-renderer.ts
|
|
20245
|
-
import { existsSync as
|
|
20435
|
+
import { existsSync as existsSync33, readFileSync as readFileSync24 } from "fs";
|
|
20246
20436
|
import { join as join19 } from "path";
|
|
20247
|
-
import { homedir as
|
|
20437
|
+
import { homedir as homedir10 } from "os";
|
|
20248
20438
|
import { createHash as createHash8 } from "crypto";
|
|
20249
20439
|
function renderMemoryFiles(db, candidates, opts) {
|
|
20250
20440
|
const config = opts.config ?? resolveMemoryFilesConfig();
|
|
@@ -20253,11 +20443,11 @@ function renderMemoryFiles(db, candidates, opts) {
|
|
|
20253
20443
|
}
|
|
20254
20444
|
const dryRun = opts.dryRun === true;
|
|
20255
20445
|
const now = opts.now ?? Date.now();
|
|
20256
|
-
const home = opts.home ??
|
|
20446
|
+
const home = opts.home ?? homedir10();
|
|
20257
20447
|
const audit = opts.audit ?? (() => {
|
|
20258
20448
|
});
|
|
20259
20449
|
const { memoryDir } = opts;
|
|
20260
|
-
if (!
|
|
20450
|
+
if (!existsSync33(memoryDir)) {
|
|
20261
20451
|
return EMPTY("no_memory_dir");
|
|
20262
20452
|
}
|
|
20263
20453
|
try {
|
|
@@ -20325,7 +20515,7 @@ function renderLocked(db, candidates, o) {
|
|
|
20325
20515
|
refusals.push({ name: c2.name, reason: "tombstoned" });
|
|
20326
20516
|
continue;
|
|
20327
20517
|
}
|
|
20328
|
-
if (
|
|
20518
|
+
if (existsSync33(absPath)) {
|
|
20329
20519
|
const existing = readFileSync24(absPath, "utf8");
|
|
20330
20520
|
const fm = readMemoryFileFrontmatter(existing);
|
|
20331
20521
|
const storeRow = db.prepare(
|
|
@@ -20548,22 +20738,22 @@ var init_memory_renderer = __esm({
|
|
|
20548
20738
|
});
|
|
20549
20739
|
|
|
20550
20740
|
// src/commands/memory-render-cli.ts
|
|
20551
|
-
import { readdirSync as
|
|
20741
|
+
import { readdirSync as readdirSync16, readFileSync as readFileSync25, existsSync as existsSync34, rmSync as rmSync8, statSync as statSync14 } from "fs";
|
|
20552
20742
|
import { join as join20 } from "path";
|
|
20553
|
-
import { homedir as
|
|
20743
|
+
import { homedir as homedir11 } from "os";
|
|
20554
20744
|
function memoryFiles(memoryDir) {
|
|
20555
|
-
if (!
|
|
20556
|
-
return
|
|
20745
|
+
if (!existsSync34(memoryDir)) return [];
|
|
20746
|
+
return readdirSync16(memoryDir).filter((f2) => {
|
|
20557
20747
|
if (!f2.endsWith(".md")) return false;
|
|
20558
20748
|
if (f2 === "MEMORY.md") return false;
|
|
20559
20749
|
try {
|
|
20560
|
-
return
|
|
20750
|
+
return statSync14(join20(memoryDir, f2)).isFile();
|
|
20561
20751
|
} catch {
|
|
20562
20752
|
return false;
|
|
20563
20753
|
}
|
|
20564
20754
|
});
|
|
20565
20755
|
}
|
|
20566
|
-
function massuAuthoredFiles(db, memoryDir, home =
|
|
20756
|
+
function massuAuthoredFiles(db, memoryDir, home = homedir11()) {
|
|
20567
20757
|
const out = [];
|
|
20568
20758
|
for (const f2 of memoryFiles(memoryDir)) {
|
|
20569
20759
|
let content;
|
|
@@ -20583,7 +20773,7 @@ function massuAuthoredFiles(db, memoryDir, home = homedir10()) {
|
|
|
20583
20773
|
return out;
|
|
20584
20774
|
}
|
|
20585
20775
|
function memoryAdopt(db, memoryDir, opts = {}) {
|
|
20586
|
-
const home = opts.home ??
|
|
20776
|
+
const home = opts.home ?? homedir11();
|
|
20587
20777
|
const now = opts.now ?? Math.floor(Date.now() / 1e3);
|
|
20588
20778
|
const lines = [];
|
|
20589
20779
|
if (!renderKeyExists(home)) {
|
|
@@ -20649,7 +20839,7 @@ function memoryAdopt(db, memoryDir, opts = {}) {
|
|
|
20649
20839
|
return { exitCode: 0, output: lines.join("\n") };
|
|
20650
20840
|
}
|
|
20651
20841
|
function memoryUnrender(db, memoryDir, opts = {}) {
|
|
20652
|
-
const home = opts.home ??
|
|
20842
|
+
const home = opts.home ?? homedir11();
|
|
20653
20843
|
const now = opts.now ?? Math.floor(Date.now() / 1e3);
|
|
20654
20844
|
const lines = [];
|
|
20655
20845
|
const ours = massuAuthoredFiles(db, memoryDir, home);
|
|
@@ -20697,7 +20887,7 @@ function memoryUnrender(db, memoryDir, opts = {}) {
|
|
|
20697
20887
|
return { exitCode: 0, output: lines.join("\n") };
|
|
20698
20888
|
}
|
|
20699
20889
|
function memoryRestore(memoryDir, opts = {}) {
|
|
20700
|
-
const home = opts.home ??
|
|
20890
|
+
const home = opts.home ?? homedir11();
|
|
20701
20891
|
const backups = listBackups(home);
|
|
20702
20892
|
if (backups.length === 0) {
|
|
20703
20893
|
return { exitCode: 1, output: "No backups exist yet. Nothing to restore." };
|
|
@@ -20766,16 +20956,16 @@ var init_memory_render_candidates = __esm({
|
|
|
20766
20956
|
});
|
|
20767
20957
|
|
|
20768
20958
|
// src/capability-advisor.ts
|
|
20769
|
-
import { existsSync as
|
|
20770
|
-
import { homedir as
|
|
20959
|
+
import { existsSync as existsSync35, mkdirSync as mkdirSync14, readFileSync as readFileSync26, writeFileSync as writeFileSync8 } from "fs";
|
|
20960
|
+
import { homedir as homedir12 } from "os";
|
|
20771
20961
|
import { dirname as dirname17, join as join21 } from "path";
|
|
20772
|
-
function advisorStatePath(home =
|
|
20962
|
+
function advisorStatePath(home = homedir12()) {
|
|
20773
20963
|
return join21(home, ".massu", "advisor-state.json");
|
|
20774
20964
|
}
|
|
20775
20965
|
function readAdvisorState(home) {
|
|
20776
20966
|
try {
|
|
20777
20967
|
const p19 = advisorStatePath(home);
|
|
20778
|
-
if (!
|
|
20968
|
+
if (!existsSync35(p19)) return {};
|
|
20779
20969
|
return JSON.parse(readFileSync26(p19, "utf-8"));
|
|
20780
20970
|
} catch {
|
|
20781
20971
|
return {};
|
|
@@ -21011,22 +21201,22 @@ var init_memory_repo_identity = __esm({
|
|
|
21011
21201
|
// src/memory-repos-registry.ts
|
|
21012
21202
|
import {
|
|
21013
21203
|
chmodSync as chmodSync7,
|
|
21014
|
-
existsSync as
|
|
21204
|
+
existsSync as existsSync36,
|
|
21015
21205
|
mkdirSync as mkdirSync15,
|
|
21016
21206
|
readFileSync as readFileSync27,
|
|
21017
21207
|
writeFileSync as writeFileSync9
|
|
21018
21208
|
} from "fs";
|
|
21019
|
-
import { homedir as
|
|
21209
|
+
import { homedir as homedir13 } from "os";
|
|
21020
21210
|
import { dirname as dirname18, join as join22 } from "path";
|
|
21021
|
-
function reposRegistryPath(home =
|
|
21211
|
+
function reposRegistryPath(home = homedir13()) {
|
|
21022
21212
|
return join22(home, ".massu", "repos.json");
|
|
21023
21213
|
}
|
|
21024
21214
|
function emptyRegistry() {
|
|
21025
21215
|
return { version: REPOS_REGISTRY_VERSION, repos: [] };
|
|
21026
21216
|
}
|
|
21027
|
-
function readReposRegistry(home =
|
|
21217
|
+
function readReposRegistry(home = homedir13()) {
|
|
21028
21218
|
const p19 = reposRegistryPath(home);
|
|
21029
|
-
if (!
|
|
21219
|
+
if (!existsSync36(p19)) return emptyRegistry();
|
|
21030
21220
|
try {
|
|
21031
21221
|
const parsed = JSON.parse(readFileSync27(p19, "utf-8"));
|
|
21032
21222
|
if (!parsed || typeof parsed !== "object") return emptyRegistry();
|
|
@@ -21076,12 +21266,12 @@ var init_shared_memory_envelope = __esm({
|
|
|
21076
21266
|
// src/security/local-share-signer.ts
|
|
21077
21267
|
import {
|
|
21078
21268
|
chmodSync as chmodSync8,
|
|
21079
|
-
existsSync as
|
|
21269
|
+
existsSync as existsSync37,
|
|
21080
21270
|
mkdirSync as mkdirSync16,
|
|
21081
21271
|
readFileSync as readFileSync28,
|
|
21082
21272
|
writeFileSync as writeFileSync10
|
|
21083
21273
|
} from "fs";
|
|
21084
|
-
import { homedir as
|
|
21274
|
+
import { homedir as homedir14 } from "os";
|
|
21085
21275
|
import { join as join23 } from "path";
|
|
21086
21276
|
import {
|
|
21087
21277
|
createHash as createHash10,
|
|
@@ -21090,18 +21280,18 @@ import {
|
|
|
21090
21280
|
generateKeyPairSync,
|
|
21091
21281
|
sign as cryptoSign
|
|
21092
21282
|
} from "crypto";
|
|
21093
|
-
function localShareKeyDir(home =
|
|
21283
|
+
function localShareKeyDir(home = homedir14()) {
|
|
21094
21284
|
return join23(home, ".massu", "keys");
|
|
21095
21285
|
}
|
|
21096
|
-
function localSharePubKeyPath(home =
|
|
21286
|
+
function localSharePubKeyPath(home = homedir14()) {
|
|
21097
21287
|
return join23(localShareKeyDir(home), "local-share.pub");
|
|
21098
21288
|
}
|
|
21099
|
-
function readLocalSharePublicKeyRaw(home =
|
|
21289
|
+
function readLocalSharePublicKeyRaw(home = homedir14()) {
|
|
21100
21290
|
const pubPem = readFileSync28(localSharePubKeyPath(home), "utf-8");
|
|
21101
21291
|
const der = createPublicKey2(pubPem).export({ format: "der", type: "spki" });
|
|
21102
21292
|
return Uint8Array.from(der.subarray(SPKI_ED25519_PREFIX_LEN));
|
|
21103
21293
|
}
|
|
21104
|
-
function localSharePubkeyFingerprint(home =
|
|
21294
|
+
function localSharePubkeyFingerprint(home = homedir14()) {
|
|
21105
21295
|
return createHash10("sha256").update(Buffer.from(readLocalSharePublicKeyRaw(home))).digest("hex");
|
|
21106
21296
|
}
|
|
21107
21297
|
var SPKI_ED25519_PREFIX_LEN;
|
|
@@ -21114,8 +21304,8 @@ var init_local_share_signer = __esm({
|
|
|
21114
21304
|
});
|
|
21115
21305
|
|
|
21116
21306
|
// src/security/local-share-verifier.ts
|
|
21117
|
-
import { homedir as
|
|
21118
|
-
function verifyLocalShareEnvelope(envelope, pinnedFingerprint, home =
|
|
21307
|
+
import { homedir as homedir15 } from "os";
|
|
21308
|
+
function verifyLocalShareEnvelope(envelope, pinnedFingerprint, home = homedir15()) {
|
|
21119
21309
|
let key;
|
|
21120
21310
|
try {
|
|
21121
21311
|
const pubkeyBytes = readLocalSharePublicKeyRaw(home);
|
|
@@ -21189,9 +21379,9 @@ var init_shared_memory_audit = __esm({
|
|
|
21189
21379
|
});
|
|
21190
21380
|
|
|
21191
21381
|
// src/shared-memory-sync.ts
|
|
21192
|
-
import { homedir as
|
|
21382
|
+
import { homedir as homedir16 } from "os";
|
|
21193
21383
|
function acceptSharedMemory(db, recordHash, opts = {}) {
|
|
21194
|
-
const home = opts.home ??
|
|
21384
|
+
const home = opts.home ?? homedir16();
|
|
21195
21385
|
const nowEpoch = opts.nowEpoch ?? Math.floor(Date.now() / 1e3);
|
|
21196
21386
|
const row = loadPending(db, recordHash);
|
|
21197
21387
|
if (!row) return refuse(db, recordHash, "not_found");
|
|
@@ -21296,7 +21486,7 @@ function refuseSharedMemory(db, recordHash, opts = {}) {
|
|
|
21296
21486
|
return { ok: true };
|
|
21297
21487
|
}
|
|
21298
21488
|
function listPendingSharedMemories(db, opts = {}) {
|
|
21299
|
-
const home = opts.home ??
|
|
21489
|
+
const home = opts.home ?? homedir16();
|
|
21300
21490
|
const rows = db.prepare(
|
|
21301
21491
|
`SELECT record_hash, origin_repo_id, origin_repo_label, envelope_raw, record_json, received_at_epoch
|
|
21302
21492
|
FROM shared_memory_pending
|
|
@@ -21401,9 +21591,9 @@ var memory_share_cli_exports = {};
|
|
|
21401
21591
|
__export(memory_share_cli_exports, {
|
|
21402
21592
|
runMemoryShareCli: () => runMemoryShareCli
|
|
21403
21593
|
});
|
|
21404
|
-
import { homedir as
|
|
21594
|
+
import { homedir as homedir17 } from "os";
|
|
21405
21595
|
async function runMemoryShareCli(sub, args2, opts = {}) {
|
|
21406
|
-
const home = opts.home ??
|
|
21596
|
+
const home = opts.home ?? homedir17();
|
|
21407
21597
|
const ownDb = !opts.db;
|
|
21408
21598
|
const db = opts.db ?? getMemoryDb();
|
|
21409
21599
|
try {
|
|
@@ -21996,14 +22186,14 @@ var init_rule_candidate_hardened = __esm({
|
|
|
21996
22186
|
|
|
21997
22187
|
// src/security/promotion-apply-mac.ts
|
|
21998
22188
|
import { createHmac as createHmac2, timingSafeEqual as timingSafeEqual2 } from "crypto";
|
|
21999
|
-
import { homedir as
|
|
22189
|
+
import { homedir as homedir18 } from "os";
|
|
22000
22190
|
function canonical(f2) {
|
|
22001
22191
|
return [DOMAIN, f2.origin, f2.org_id, f2.prompt_hash, f2.destination, f2.draft_text].join("\n");
|
|
22002
22192
|
}
|
|
22003
22193
|
function deriveApplyKey(renderKey) {
|
|
22004
22194
|
return createHmac2("sha256", renderKey).update(DOMAIN, "utf8").digest();
|
|
22005
22195
|
}
|
|
22006
|
-
function computePromotionApplyMac(fields, home =
|
|
22196
|
+
function computePromotionApplyMac(fields, home = homedir18()) {
|
|
22007
22197
|
try {
|
|
22008
22198
|
const key = ensureRenderKey(home);
|
|
22009
22199
|
if (!key) return null;
|
|
@@ -22012,7 +22202,7 @@ function computePromotionApplyMac(fields, home = homedir17()) {
|
|
|
22012
22202
|
return null;
|
|
22013
22203
|
}
|
|
22014
22204
|
}
|
|
22015
|
-
function verifyPromotionApplyMac(claimed, fields, home =
|
|
22205
|
+
function verifyPromotionApplyMac(claimed, fields, home = homedir18()) {
|
|
22016
22206
|
try {
|
|
22017
22207
|
if (typeof claimed !== "string" || claimed.length === 0) return false;
|
|
22018
22208
|
const key = readRenderKey(home);
|
|
@@ -22036,9 +22226,9 @@ var init_promotion_apply_mac = __esm({
|
|
|
22036
22226
|
});
|
|
22037
22227
|
|
|
22038
22228
|
// src/rule-candidate-applier.ts
|
|
22039
|
-
import { readFileSync as readFileSync29, writeFileSync as writeFileSync11, existsSync as
|
|
22040
|
-
import { join as join24, dirname as dirname19, isAbsolute as
|
|
22041
|
-
import { homedir as
|
|
22229
|
+
import { readFileSync as readFileSync29, writeFileSync as writeFileSync11, existsSync as existsSync38, unlinkSync as unlinkSync5, mkdirSync as mkdirSync17 } from "fs";
|
|
22230
|
+
import { join as join24, dirname as dirname19, isAbsolute as isAbsolute3 } from "path";
|
|
22231
|
+
import { homedir as homedir19 } from "os";
|
|
22042
22232
|
import { createHash as createHash11 } from "crypto";
|
|
22043
22233
|
function isRuleDestination(value) {
|
|
22044
22234
|
return typeof value === "string" && ALL_RULE_DESTINATIONS.includes(value);
|
|
@@ -22046,10 +22236,10 @@ function isRuleDestination(value) {
|
|
|
22046
22236
|
function isTeamShareableDestination(destination) {
|
|
22047
22237
|
return TEAM_SHAREABLE_DESTINATIONS.includes(destination);
|
|
22048
22238
|
}
|
|
22049
|
-
function resolveMemoryDir(projectRoot = getProjectRoot(), home =
|
|
22239
|
+
function resolveMemoryDir(projectRoot = getProjectRoot(), home = homedir19()) {
|
|
22050
22240
|
return join24(home, ".claude", "projects", encodeMemoryDirName(projectRoot), "memory");
|
|
22051
22241
|
}
|
|
22052
|
-
function resolveMemoryIndexPath(projectRoot = getProjectRoot(), home =
|
|
22242
|
+
function resolveMemoryIndexPath(projectRoot = getProjectRoot(), home = homedir19()) {
|
|
22053
22243
|
return join24(resolveMemoryDir(projectRoot, home), "MEMORY.md");
|
|
22054
22244
|
}
|
|
22055
22245
|
function deriveSlug2(prompt) {
|
|
@@ -22079,7 +22269,7 @@ function readCandidate(candidateId, projectRoot = getProjectRoot()) {
|
|
|
22079
22269
|
throw new InvalidCandidateIdError(candidateId);
|
|
22080
22270
|
}
|
|
22081
22271
|
const path = join24(projectRoot, ".massu", "rule-candidates", `${candidateId}.json`);
|
|
22082
|
-
if (!
|
|
22272
|
+
if (!existsSync38(path)) throw new CandidateNotFoundError(path);
|
|
22083
22273
|
const raw = readFileSync29(path, "utf-8");
|
|
22084
22274
|
let parsed;
|
|
22085
22275
|
try {
|
|
@@ -22172,7 +22362,7 @@ async function applyRuleCandidate(db, opts) {
|
|
|
22172
22362
|
throw new InvalidCandidateIdError(opts.candidateId);
|
|
22173
22363
|
}
|
|
22174
22364
|
const projectRoot = opts.projectRoot ?? getProjectRoot();
|
|
22175
|
-
const home = opts.home ??
|
|
22365
|
+
const home = opts.home ?? homedir19();
|
|
22176
22366
|
const candidate = readCandidate(opts.candidateId, projectRoot);
|
|
22177
22367
|
if (candidate.provenance !== void 0) {
|
|
22178
22368
|
const provOrigin = candidate.provenance.origin;
|
|
@@ -22223,7 +22413,7 @@ async function applyRuleCandidate(db, opts) {
|
|
|
22223
22413
|
throw new InvalidSlugError(slug);
|
|
22224
22414
|
}
|
|
22225
22415
|
const memoryIndex = resolveMemoryIndexPath(projectRoot, home);
|
|
22226
|
-
if (!
|
|
22416
|
+
if (!existsSync38(memoryIndex)) {
|
|
22227
22417
|
throw new MemoryIndexMissingError(memoryIndex);
|
|
22228
22418
|
}
|
|
22229
22419
|
let destTargets;
|
|
@@ -22279,7 +22469,7 @@ async function applyRuleCandidate(db, opts) {
|
|
|
22279
22469
|
throw err;
|
|
22280
22470
|
}
|
|
22281
22471
|
}
|
|
22282
|
-
if (
|
|
22472
|
+
if (existsSync38(candidatePath)) unlinkSync5(candidatePath);
|
|
22283
22473
|
let teamShared = false;
|
|
22284
22474
|
const localOrigin = candidate.provenance === void 0;
|
|
22285
22475
|
const entitledTeam = entitledForTeamSharedPromotion(ent.currentTier);
|
|
@@ -22340,7 +22530,7 @@ function computeDestinationTargets(opts, candidate, slug, projectRoot, home) {
|
|
|
22340
22530
|
throw new DestinationConfigError("custom-destination requires customDestination config entry");
|
|
22341
22531
|
}
|
|
22342
22532
|
const raw = opts.customDestination.path;
|
|
22343
|
-
const absolute =
|
|
22533
|
+
const absolute = isAbsolute3(raw) ? raw : join24(projectRoot, raw);
|
|
22344
22534
|
try {
|
|
22345
22535
|
assertContainedIn(projectRoot, absolute, { allowNested: true });
|
|
22346
22536
|
} catch (err) {
|
|
@@ -22380,8 +22570,8 @@ function writeCorrectionsMd(opts, candidate, slug, targets, auditRowId) {
|
|
|
22380
22570
|
audit_log_id: auditRowId
|
|
22381
22571
|
}
|
|
22382
22572
|
});
|
|
22383
|
-
if (!
|
|
22384
|
-
const correctionsPre =
|
|
22573
|
+
if (!existsSync38(dirname19(correctionsMd))) mkdirSync17(dirname19(correctionsMd), { recursive: true });
|
|
22574
|
+
const correctionsPre = existsSync38(correctionsMd) ? readFileSync29(correctionsMd, "utf-8") : "# Corrections\n";
|
|
22385
22575
|
writeFileSync11(correctionsMd, correctionsPre + correctionsEntry, "utf-8");
|
|
22386
22576
|
const body = `${opts.draftText}
|
|
22387
22577
|
`;
|
|
@@ -22407,7 +22597,7 @@ function writeCorrectionsMd(opts, candidate, slug, targets, auditRowId) {
|
|
|
22407
22597
|
function writePatternScanner(opts, candidate, slug, targets) {
|
|
22408
22598
|
const [scannerPath, driftGuardPath] = targets.paths;
|
|
22409
22599
|
const checkNumber = opts.patternScannerCheckNumber;
|
|
22410
|
-
const scannerPre =
|
|
22600
|
+
const scannerPre = existsSync38(scannerPath) ? readFileSync29(scannerPath, "utf-8") : "";
|
|
22411
22601
|
if (scannerPre.includes(`${SCANNER_AUTOGEN_MARKER_PREFIX} ${candidate.prompt_hash}`)) {
|
|
22412
22602
|
throw new DestinationConfigError(
|
|
22413
22603
|
`scanner already contains a check auto-generated for prompt_hash ${candidate.prompt_hash}`
|
|
@@ -22443,13 +22633,13 @@ function writePatternScanner(opts, candidate, slug, targets) {
|
|
|
22443
22633
|
`});`,
|
|
22444
22634
|
""
|
|
22445
22635
|
].join("\n");
|
|
22446
|
-
if (!
|
|
22636
|
+
if (!existsSync38(dirname19(driftGuardPath))) mkdirSync17(dirname19(driftGuardPath), { recursive: true });
|
|
22447
22637
|
writeFileSync11(driftGuardPath, driftGuard, "utf-8");
|
|
22448
22638
|
}
|
|
22449
22639
|
function writeClaudeMdCr(opts, candidate, slug, targets) {
|
|
22450
22640
|
const [claudePath] = targets.paths;
|
|
22451
22641
|
const crNumber = opts.claudeMdCrNumber;
|
|
22452
|
-
const pre =
|
|
22642
|
+
const pre = existsSync38(claudePath) ? readFileSync29(claudePath, "utf-8") : "";
|
|
22453
22643
|
if (new RegExp(`\\bCR-${crNumber}\\b`).test(pre)) {
|
|
22454
22644
|
throw new DestinationConfigError(`CLAUDE.md already contains a CR-${crNumber} entry`);
|
|
22455
22645
|
}
|
|
@@ -22491,8 +22681,8 @@ function writeCustomDestination(opts, candidate, slug, targets) {
|
|
|
22491
22681
|
destination_name: entry.name
|
|
22492
22682
|
};
|
|
22493
22683
|
const rendered = renderTemplate2(entry.template, vars);
|
|
22494
|
-
if (!
|
|
22495
|
-
const pre =
|
|
22684
|
+
if (!existsSync38(dirname19(destPath))) mkdirSync17(dirname19(destPath), { recursive: true });
|
|
22685
|
+
const pre = existsSync38(destPath) ? readFileSync29(destPath, "utf-8") : "";
|
|
22496
22686
|
const sep3 = pre && !pre.endsWith("\n") ? "\n" : "";
|
|
22497
22687
|
writeFileSync11(destPath, pre + sep3 + rendered + (rendered.endsWith("\n") ? "" : "\n"), "utf-8");
|
|
22498
22688
|
}
|
|
@@ -22545,8 +22735,8 @@ function dismissRuleCandidate(db, opts) {
|
|
|
22545
22735
|
}
|
|
22546
22736
|
try {
|
|
22547
22737
|
const dismissedLog = join24(projectRoot, ".massu", "rule-candidates", ".dismissed.jsonl");
|
|
22548
|
-
if (!
|
|
22549
|
-
const pre =
|
|
22738
|
+
if (!existsSync38(dirname19(dismissedLog))) mkdirSync17(dirname19(dismissedLog), { recursive: true });
|
|
22739
|
+
const pre = existsSync38(dismissedLog) ? readFileSync29(dismissedLog, "utf-8") : "";
|
|
22550
22740
|
const sep3 = pre && !pre.endsWith("\n") ? "\n" : "";
|
|
22551
22741
|
writeFileSync11(dismissedLog, pre + sep3 + JSON.stringify({
|
|
22552
22742
|
id: opts.candidateId,
|
|
@@ -22557,7 +22747,7 @@ function dismissRuleCandidate(db, opts) {
|
|
|
22557
22747
|
audit_log_id: auditRowId,
|
|
22558
22748
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
22559
22749
|
}) + "\n", "utf-8");
|
|
22560
|
-
if (
|
|
22750
|
+
if (existsSync38(candidatePath)) unlinkSync5(candidatePath);
|
|
22561
22751
|
} catch (err) {
|
|
22562
22752
|
appendFailureLog(projectRoot, {
|
|
22563
22753
|
candidate_id: opts.candidateId,
|
|
@@ -22576,9 +22766,9 @@ function dismissRuleCandidate(db, opts) {
|
|
|
22576
22766
|
function appendFailureLog(projectRoot, entry) {
|
|
22577
22767
|
try {
|
|
22578
22768
|
const dir = join24(projectRoot, ".massu", "rule-candidates");
|
|
22579
|
-
if (!
|
|
22769
|
+
if (!existsSync38(dir)) mkdirSync17(dir, { recursive: true });
|
|
22580
22770
|
const logPath = join24(dir, ".failures.jsonl");
|
|
22581
|
-
const pre =
|
|
22771
|
+
const pre = existsSync38(logPath) ? readFileSync29(logPath, "utf-8") : "";
|
|
22582
22772
|
const sep3 = pre && !pre.endsWith("\n") ? "\n" : "";
|
|
22583
22773
|
writeFileSync11(logPath, pre + sep3 + JSON.stringify(entry) + "\n", "utf-8");
|
|
22584
22774
|
} catch {
|
|
@@ -22663,7 +22853,7 @@ var init_rule_candidate_applier = __esm({
|
|
|
22663
22853
|
});
|
|
22664
22854
|
|
|
22665
22855
|
// src/rule-candidate-preview.ts
|
|
22666
|
-
import { readFileSync as readFileSync30, writeFileSync as writeFileSync12, existsSync as
|
|
22856
|
+
import { readFileSync as readFileSync30, writeFileSync as writeFileSync12, existsSync as existsSync39 } from "node:fs";
|
|
22667
22857
|
function renderHardenedPreview(destination, body) {
|
|
22668
22858
|
const rendered = String(body ?? "");
|
|
22669
22859
|
const riskFindings = RISK_PATTERNS.filter((p19) => p19.re.test(rendered)).map((p19) => p19.label);
|
|
@@ -22691,7 +22881,7 @@ function validateReviewAttestation(att) {
|
|
|
22691
22881
|
};
|
|
22692
22882
|
}
|
|
22693
22883
|
function recordHardenedReviewAttestation(sidecarPath2, attestation) {
|
|
22694
|
-
if (!
|
|
22884
|
+
if (!existsSync39(sidecarPath2)) {
|
|
22695
22885
|
throw new Error(`candidate sidecar not found: ${sidecarPath2}`);
|
|
22696
22886
|
}
|
|
22697
22887
|
const validated = validateReviewAttestation(attestation);
|
|
@@ -22803,7 +22993,7 @@ var init_rule_candidate_renderer = __esm({
|
|
|
22803
22993
|
});
|
|
22804
22994
|
|
|
22805
22995
|
// src/rule-promotion-effectiveness.ts
|
|
22806
|
-
import { readFileSync as readFileSync31, existsSync as
|
|
22996
|
+
import { readFileSync as readFileSync31, existsSync as existsSync40 } from "fs";
|
|
22807
22997
|
function evaluateCr53Effectiveness(inputs) {
|
|
22808
22998
|
const { db, failureLogPath, knownLimitations } = inputs;
|
|
22809
22999
|
const allowlist = new Set(knownLimitations.map((k3) => k3.promptHash));
|
|
@@ -22834,7 +23024,7 @@ function evaluateCr53Effectiveness(inputs) {
|
|
|
22834
23024
|
});
|
|
22835
23025
|
}
|
|
22836
23026
|
const failureLogViolations = [];
|
|
22837
|
-
if (
|
|
23027
|
+
if (existsSync40(failureLogPath)) {
|
|
22838
23028
|
try {
|
|
22839
23029
|
const raw = readFileSync31(failureLogPath, "utf-8");
|
|
22840
23030
|
const cutoff = Date.now() - SEVEN_DAYS_MS;
|
|
@@ -23013,8 +23203,8 @@ var init_rule_pack_schema = __esm({
|
|
|
23013
23203
|
});
|
|
23014
23204
|
|
|
23015
23205
|
// src/rule-pack-sync.ts
|
|
23016
|
-
import { existsSync as
|
|
23017
|
-
import { homedir as
|
|
23206
|
+
import { existsSync as existsSync41, writeFileSync as writeFileSync13, mkdirSync as mkdirSync18 } from "fs";
|
|
23207
|
+
import { homedir as homedir20 } from "os";
|
|
23018
23208
|
import { join as join25, dirname as dirname20 } from "path";
|
|
23019
23209
|
async function pullInstalledPackRules(db, opts = {}) {
|
|
23020
23210
|
const config = getConfig();
|
|
@@ -23078,11 +23268,11 @@ async function pullInstalledPackRules(db, opts = {}) {
|
|
|
23078
23268
|
result.pulled += 1;
|
|
23079
23269
|
const promptHash = packRulePromptHash(pack.slug, rule);
|
|
23080
23270
|
const candidatePath = sidecarPath(projectRoot, promptHash);
|
|
23081
|
-
if (
|
|
23271
|
+
if (existsSync41(candidatePath) || alreadyApplied(db, promptHash)) {
|
|
23082
23272
|
result.skipped += 1;
|
|
23083
23273
|
continue;
|
|
23084
23274
|
}
|
|
23085
|
-
materializeCandidate(projectRoot, candidatePath, promptHash, rule, pack, signedOrgId, nowIso, opts.home ??
|
|
23275
|
+
materializeCandidate(projectRoot, candidatePath, promptHash, rule, pack, signedOrgId, nowIso, opts.home ?? homedir20());
|
|
23086
23276
|
result.materialized += 1;
|
|
23087
23277
|
}
|
|
23088
23278
|
}
|
|
@@ -23171,7 +23361,7 @@ function materializeCandidate(projectRoot, candidatePath, promptHash, rule, pack
|
|
|
23171
23361
|
draft_text: draftText
|
|
23172
23362
|
};
|
|
23173
23363
|
const dir = dirname20(candidatePath);
|
|
23174
|
-
if (!
|
|
23364
|
+
if (!existsSync41(dir)) mkdirSync18(dir, { recursive: true });
|
|
23175
23365
|
writeFileSync13(candidatePath, JSON.stringify(sidecar, null, 2), "utf-8");
|
|
23176
23366
|
}
|
|
23177
23367
|
function emitDropTelemetry(db, eventType, data) {
|
|
@@ -24043,7 +24233,7 @@ var init_memory_supersede = __esm({
|
|
|
24043
24233
|
|
|
24044
24234
|
// src/memory-consolidate.ts
|
|
24045
24235
|
import { createHash as createHash12 } from "crypto";
|
|
24046
|
-
import { existsSync as
|
|
24236
|
+
import { existsSync as existsSync42, mkdirSync as mkdirSync19, writeFileSync as writeFileSync14 } from "fs";
|
|
24047
24237
|
import { join as join27 } from "path";
|
|
24048
24238
|
function emptyResult() {
|
|
24049
24239
|
return {
|
|
@@ -24220,7 +24410,7 @@ ${representative.detail}` : ""}`;
|
|
|
24220
24410
|
const clusterKey = cluster.map((c2) => c2.title.toLowerCase().replace(/\s+/g, " ").trim()).sort().join("|");
|
|
24221
24411
|
const promptHash = createHash12("sha256").update(clusterKey).digest("hex").slice(0, 16);
|
|
24222
24412
|
const candidatePath = join27(candidateDir, `${promptHash}.json`);
|
|
24223
|
-
if (
|
|
24413
|
+
if (existsSync42(candidatePath)) continue;
|
|
24224
24414
|
if (dryRun) {
|
|
24225
24415
|
promoted++;
|
|
24226
24416
|
continue;
|
|
@@ -24513,8 +24703,8 @@ var show_template_exports = {};
|
|
|
24513
24703
|
__export(show_template_exports, {
|
|
24514
24704
|
runShowTemplate: () => runShowTemplate
|
|
24515
24705
|
});
|
|
24516
|
-
import { existsSync as
|
|
24517
|
-
import { resolve as
|
|
24706
|
+
import { existsSync as existsSync43, readFileSync as readFileSync32 } from "fs";
|
|
24707
|
+
import { resolve as resolve18 } from "path";
|
|
24518
24708
|
function normalizeBaseName(input) {
|
|
24519
24709
|
return input.endsWith(".md") ? input.slice(0, -".md".length) : input;
|
|
24520
24710
|
}
|
|
@@ -24542,8 +24732,8 @@ async function runShowTemplate(args2) {
|
|
|
24542
24732
|
return;
|
|
24543
24733
|
}
|
|
24544
24734
|
const suffix = choice.kind === "hit" ? choice.suffix : "";
|
|
24545
|
-
const file = suffix === "" ?
|
|
24546
|
-
if (!
|
|
24735
|
+
const file = suffix === "" ? resolve18(sourceDir, `${baseName}.md`) : resolve18(sourceDir, `${baseName}${suffix}.md`);
|
|
24736
|
+
if (!existsSync43(file)) {
|
|
24547
24737
|
process.stderr.write(`massu: resolved template "${file}" no longer exists
|
|
24548
24738
|
`);
|
|
24549
24739
|
process.exit(1);
|
|
@@ -24602,9 +24792,9 @@ var init_passthrough = __esm({
|
|
|
24602
24792
|
});
|
|
24603
24793
|
|
|
24604
24794
|
// src/lib/installLock.ts
|
|
24605
|
-
import { resolve as
|
|
24795
|
+
import { resolve as resolve19 } from "path";
|
|
24606
24796
|
function withInstallLock(projectRoot, fn, opts = {}) {
|
|
24607
|
-
const lockPath =
|
|
24797
|
+
const lockPath = resolve19(projectRoot, ".massu", "installAll.lock");
|
|
24608
24798
|
return withFileLockSync(
|
|
24609
24799
|
lockPath,
|
|
24610
24800
|
fn,
|
|
@@ -24644,8 +24834,8 @@ __export(config_refresh_exports, {
|
|
|
24644
24834
|
mergeRefresh: () => mergeRefresh,
|
|
24645
24835
|
runConfigRefresh: () => runConfigRefresh
|
|
24646
24836
|
});
|
|
24647
|
-
import { existsSync as
|
|
24648
|
-
import { resolve as
|
|
24837
|
+
import { existsSync as existsSync44, readFileSync as readFileSync33, rmSync as rmSync9 } from "fs";
|
|
24838
|
+
import { resolve as resolve20 } from "path";
|
|
24649
24839
|
import { parse as parseYaml5 } from "yaml";
|
|
24650
24840
|
function flatten(obj, prefix3 = "") {
|
|
24651
24841
|
const out = {};
|
|
@@ -24773,10 +24963,10 @@ function renderDiff(diff) {
|
|
|
24773
24963
|
}
|
|
24774
24964
|
async function runConfigRefresh(opts = {}) {
|
|
24775
24965
|
const cwd = opts.cwd ?? process.cwd();
|
|
24776
|
-
const configPath =
|
|
24966
|
+
const configPath = resolve20(cwd, "massu.config.yaml");
|
|
24777
24967
|
const log = opts.silent ? () => {
|
|
24778
24968
|
} : (s) => process.stdout.write(s);
|
|
24779
|
-
if (!
|
|
24969
|
+
if (!existsSync44(configPath)) {
|
|
24780
24970
|
const message = "massu.config.yaml not found. Run: npx massu init";
|
|
24781
24971
|
if (!opts.silent) process.stderr.write(message + "\n");
|
|
24782
24972
|
return { exitCode: 1, applied: false, dryRun: !!opts.dryRun, diff: [], message };
|
|
@@ -24856,8 +25046,8 @@ async function runConfigRefresh(opts = {}) {
|
|
|
24856
25046
|
`);
|
|
24857
25047
|
const stackResolved = installResult.totalInstalled > 0 || installResult.totalUpdated > 0;
|
|
24858
25048
|
if (stackResolved) {
|
|
24859
|
-
const placeholderPath =
|
|
24860
|
-
if (
|
|
25049
|
+
const placeholderPath = resolve20(installResult.claudeDir, "commands", "_massu-needs-stack.md");
|
|
25050
|
+
if (existsSync44(placeholderPath)) {
|
|
24861
25051
|
try {
|
|
24862
25052
|
rmSync9(placeholderPath, { force: true });
|
|
24863
25053
|
log("Removed _massu-needs-stack.md (stack now declared).\n");
|
|
@@ -24907,7 +25097,7 @@ var init_config_refresh = __esm({
|
|
|
24907
25097
|
});
|
|
24908
25098
|
|
|
24909
25099
|
// src/lib/pidLiveness.ts
|
|
24910
|
-
import { spawnSync as
|
|
25100
|
+
import { spawnSync as spawnSync3 } from "child_process";
|
|
24911
25101
|
function isPidAlive(pid, opts = {}) {
|
|
24912
25102
|
if (!Number.isFinite(pid) || pid <= 0) return false;
|
|
24913
25103
|
const platform = opts.platformOverride ?? process.platform;
|
|
@@ -24932,7 +25122,7 @@ function checkPosix(pid, killOverride) {
|
|
|
24932
25122
|
}
|
|
24933
25123
|
function checkWindows(pid) {
|
|
24934
25124
|
try {
|
|
24935
|
-
const res =
|
|
25125
|
+
const res = spawnSync3("tasklist", ["/FI", `PID eq ${pid}`, "/NH"], {
|
|
24936
25126
|
encoding: "utf-8",
|
|
24937
25127
|
windowsHide: true
|
|
24938
25128
|
});
|
|
@@ -24950,9 +25140,9 @@ var init_pidLiveness = __esm({
|
|
|
24950
25140
|
});
|
|
24951
25141
|
|
|
24952
25142
|
// src/lib/gitToplevel.ts
|
|
24953
|
-
import { spawnSync as
|
|
25143
|
+
import { spawnSync as spawnSync4 } from "child_process";
|
|
24954
25144
|
function gitToplevel(cwd) {
|
|
24955
|
-
const res =
|
|
25145
|
+
const res = spawnSync4("git", ["rev-parse", "--show-toplevel"], {
|
|
24956
25146
|
cwd,
|
|
24957
25147
|
encoding: "utf-8"
|
|
24958
25148
|
});
|
|
@@ -24966,14 +25156,14 @@ var init_gitToplevel = __esm({
|
|
|
24966
25156
|
});
|
|
24967
25157
|
|
|
24968
25158
|
// src/watch/lockfile-detector.ts
|
|
24969
|
-
import { existsSync as
|
|
24970
|
-
import { resolve as
|
|
25159
|
+
import { existsSync as existsSync45, statSync as statSync15 } from "fs";
|
|
25160
|
+
import { resolve as resolve21 } from "path";
|
|
24971
25161
|
function lockfileMidWrite(projectRoot, now = Date.now(), windowMs = LOCKFILE_WINDOW_MS) {
|
|
24972
25162
|
for (const lf of KNOWN_LOCKFILES) {
|
|
24973
|
-
const p19 =
|
|
24974
|
-
if (!
|
|
25163
|
+
const p19 = resolve21(projectRoot, lf);
|
|
25164
|
+
if (!existsSync45(p19)) continue;
|
|
24975
25165
|
try {
|
|
24976
|
-
const stat =
|
|
25166
|
+
const stat = statSync15(p19);
|
|
24977
25167
|
const delta = now - stat.mtimeMs;
|
|
24978
25168
|
if (delta >= 0 && delta < windowMs) return true;
|
|
24979
25169
|
} catch {
|
|
@@ -24984,7 +25174,7 @@ function lockfileMidWrite(projectRoot, now = Date.now(), windowMs = LOCKFILE_WIN
|
|
|
24984
25174
|
function gitMidOperation(projectRoot) {
|
|
24985
25175
|
const sentinels = ["MERGE_HEAD", "REBASE_HEAD", "CHERRY_PICK_HEAD", "rebase-apply", "rebase-merge"];
|
|
24986
25176
|
for (const s of sentinels) {
|
|
24987
|
-
if (
|
|
25177
|
+
if (existsSync45(resolve21(projectRoot, ".git", s))) return true;
|
|
24988
25178
|
}
|
|
24989
25179
|
return false;
|
|
24990
25180
|
}
|
|
@@ -25183,17 +25373,17 @@ var init_paths = __esm({
|
|
|
25183
25373
|
});
|
|
25184
25374
|
|
|
25185
25375
|
// src/watch/state.ts
|
|
25186
|
-
import { closeSync as closeSync5, existsSync as
|
|
25187
|
-
import { dirname as dirname21, resolve as
|
|
25376
|
+
import { closeSync as closeSync5, existsSync as existsSync46, fsyncSync as fsyncSync5, mkdirSync as mkdirSync20, openSync as openSync5, readFileSync as readFileSync34, renameSync as renameSync5, rmSync as rmSync10, writeFileSync as writeFileSync15, writeSync as writeSync3 } from "fs";
|
|
25377
|
+
import { dirname as dirname21, resolve as resolve22 } from "path";
|
|
25188
25378
|
function watchStatePath(projectRoot) {
|
|
25189
|
-
return
|
|
25379
|
+
return resolve22(projectRoot, ".massu", "watch-state.json");
|
|
25190
25380
|
}
|
|
25191
25381
|
function backupStatePath(projectRoot) {
|
|
25192
|
-
return
|
|
25382
|
+
return resolve22(projectRoot, ".massu", "watch-state.v0.bak.json");
|
|
25193
25383
|
}
|
|
25194
25384
|
function readState(projectRoot) {
|
|
25195
25385
|
const path = watchStatePath(projectRoot);
|
|
25196
|
-
if (!
|
|
25386
|
+
if (!existsSync46(path)) return { ...DEFAULT_STATE };
|
|
25197
25387
|
const content = readFileSync34(path, "utf-8");
|
|
25198
25388
|
let raw;
|
|
25199
25389
|
try {
|
|
@@ -25257,7 +25447,7 @@ function writeStateAtomic(projectRoot, state) {
|
|
|
25257
25447
|
renameSync5(tmp, path);
|
|
25258
25448
|
renamed = true;
|
|
25259
25449
|
} finally {
|
|
25260
|
-
if (!renamed &&
|
|
25450
|
+
if (!renamed && existsSync46(tmp)) {
|
|
25261
25451
|
try {
|
|
25262
25452
|
rmSync10(tmp, { force: true });
|
|
25263
25453
|
} catch {
|
|
@@ -25538,9 +25728,9 @@ __export(watch_exports, {
|
|
|
25538
25728
|
runOnQuiescent: () => runOnQuiescent,
|
|
25539
25729
|
runWatch: () => runWatch
|
|
25540
25730
|
});
|
|
25541
|
-
import { spawnSync as
|
|
25542
|
-
import { basename as basename8, dirname as dirname22, resolve as
|
|
25543
|
-
import { appendFileSync as appendFileSync4, existsSync as
|
|
25731
|
+
import { spawnSync as spawnSync5 } from "child_process";
|
|
25732
|
+
import { basename as basename8, dirname as dirname22, resolve as resolve23 } from "path";
|
|
25733
|
+
import { appendFileSync as appendFileSync4, existsSync as existsSync47, mkdirSync as mkdirSync21, readFileSync as readFileSync35 } from "fs";
|
|
25544
25734
|
function parseFlags(args2) {
|
|
25545
25735
|
const out = {
|
|
25546
25736
|
foreground: false,
|
|
@@ -25565,9 +25755,9 @@ function parseFlags(args2) {
|
|
|
25565
25755
|
}
|
|
25566
25756
|
function findClaudeBg() {
|
|
25567
25757
|
const home = process.env.HOME ?? "";
|
|
25568
|
-
const fixed = home ?
|
|
25569
|
-
if (fixed &&
|
|
25570
|
-
const which =
|
|
25758
|
+
const fixed = home ? resolve23(home, ".claude", "bin", "claude-bg") : null;
|
|
25759
|
+
if (fixed && existsSync47(fixed)) return fixed;
|
|
25760
|
+
const which = spawnSync5("which", ["claude-bg"], { encoding: "utf-8" });
|
|
25571
25761
|
if (which.status === 0 && which.stdout) {
|
|
25572
25762
|
const p19 = which.stdout.trim();
|
|
25573
25763
|
if (p19) return p19;
|
|
@@ -25609,7 +25799,7 @@ async function runWatch(args2) {
|
|
|
25609
25799
|
return { exitCode: 1, message: msg };
|
|
25610
25800
|
}
|
|
25611
25801
|
const name = watchName(root);
|
|
25612
|
-
const res =
|
|
25802
|
+
const res = spawnSync5(claudeBg, [
|
|
25613
25803
|
"start",
|
|
25614
25804
|
"--name",
|
|
25615
25805
|
name,
|
|
@@ -25627,7 +25817,7 @@ async function runWatch(args2) {
|
|
|
25627
25817
|
}
|
|
25628
25818
|
function runStatus(root) {
|
|
25629
25819
|
const path = watchStatePath(root);
|
|
25630
|
-
if (!
|
|
25820
|
+
if (!existsSync47(path)) {
|
|
25631
25821
|
process.stdout.write("massu watch: not running (no state file)\n");
|
|
25632
25822
|
return { exitCode: 0 };
|
|
25633
25823
|
}
|
|
@@ -25665,7 +25855,7 @@ function runStop(root) {
|
|
|
25665
25855
|
process.stderr.write("massu watch --stop: claude-bg not found; cannot kill registered daemon\n");
|
|
25666
25856
|
return { exitCode: 1 };
|
|
25667
25857
|
}
|
|
25668
|
-
const res =
|
|
25858
|
+
const res = spawnSync5(claudeBg, ["kill", watchName(root)], { stdio: "inherit" });
|
|
25669
25859
|
return { exitCode: (res.status ?? 1) === 0 ? 0 : 1 };
|
|
25670
25860
|
}
|
|
25671
25861
|
async function runApplyNow(root) {
|
|
@@ -25709,7 +25899,7 @@ async function runForeground(root) {
|
|
|
25709
25899
|
}
|
|
25710
25900
|
throw err;
|
|
25711
25901
|
}
|
|
25712
|
-
return new Promise((
|
|
25902
|
+
return new Promise((resolve46) => {
|
|
25713
25903
|
const shutdown = async () => {
|
|
25714
25904
|
if (stopped) return;
|
|
25715
25905
|
stopped = true;
|
|
@@ -25719,7 +25909,7 @@ async function runForeground(root) {
|
|
|
25719
25909
|
process.chdir(priorCwd);
|
|
25720
25910
|
} catch {
|
|
25721
25911
|
}
|
|
25722
|
-
|
|
25912
|
+
resolve46({ exitCode: 0 });
|
|
25723
25913
|
};
|
|
25724
25914
|
process.on("SIGINT", () => {
|
|
25725
25915
|
void shutdown();
|
|
@@ -25780,7 +25970,7 @@ async function runOnQuiescent(projectRoot) {
|
|
|
25780
25970
|
);
|
|
25781
25971
|
}
|
|
25782
25972
|
function refreshLogPath(projectRoot) {
|
|
25783
|
-
return
|
|
25973
|
+
return resolve23(projectRoot, ".massu", "refresh-log.jsonl");
|
|
25784
25974
|
}
|
|
25785
25975
|
function appendRefreshLog(projectRoot, event) {
|
|
25786
25976
|
const path = refreshLogPath(projectRoot);
|
|
@@ -25792,7 +25982,7 @@ function appendRefreshLog(projectRoot, event) {
|
|
|
25792
25982
|
}
|
|
25793
25983
|
function readRefreshLog(projectRoot, limit = 10, opts = {}) {
|
|
25794
25984
|
const path = refreshLogPath(projectRoot);
|
|
25795
|
-
if (!
|
|
25985
|
+
if (!existsSync47(path)) return [];
|
|
25796
25986
|
const warn = opts.warn ?? ((s) => {
|
|
25797
25987
|
process.stderr.write(s);
|
|
25798
25988
|
});
|
|
@@ -25869,13 +26059,13 @@ var init_refresh_log = __esm({
|
|
|
25869
26059
|
import {
|
|
25870
26060
|
chmodSync as chmodSync9,
|
|
25871
26061
|
closeSync as closeSync6,
|
|
25872
|
-
existsSync as
|
|
26062
|
+
existsSync as existsSync48,
|
|
25873
26063
|
fsyncSync as fsyncSync6,
|
|
25874
26064
|
mkdirSync as mkdirSync22,
|
|
25875
26065
|
openSync as openSync6,
|
|
25876
26066
|
renameSync as renameSync6,
|
|
25877
26067
|
rmSync as rmSync11,
|
|
25878
|
-
statSync as
|
|
26068
|
+
statSync as statSync16,
|
|
25879
26069
|
writeSync as writeSync4
|
|
25880
26070
|
} from "node:fs";
|
|
25881
26071
|
import { dirname as dirname23 } from "node:path";
|
|
@@ -25883,7 +26073,7 @@ function atomicWrite(path, content, opts = {}) {
|
|
|
25883
26073
|
const tmpPath = `${path}.tmp`;
|
|
25884
26074
|
const parentDir = dirname23(path);
|
|
25885
26075
|
try {
|
|
25886
|
-
if (!
|
|
26076
|
+
if (!existsSync48(parentDir)) {
|
|
25887
26077
|
const mkdirOpts = { recursive: true };
|
|
25888
26078
|
if (opts.ensureParentDirMode !== void 0) {
|
|
25889
26079
|
mkdirOpts.mode = opts.ensureParentDirMode;
|
|
@@ -25905,7 +26095,7 @@ function atomicWrite(path, content, opts = {}) {
|
|
|
25905
26095
|
renameSync6(tmpPath, path);
|
|
25906
26096
|
return { written: true };
|
|
25907
26097
|
} catch (err) {
|
|
25908
|
-
if (
|
|
26098
|
+
if (existsSync48(tmpPath)) {
|
|
25909
26099
|
try {
|
|
25910
26100
|
rmSync11(tmpPath, { force: true });
|
|
25911
26101
|
} catch {
|
|
@@ -26254,19 +26444,19 @@ var init_fetcher = __esm({
|
|
|
26254
26444
|
});
|
|
26255
26445
|
|
|
26256
26446
|
// src/security/manifest-cache.ts
|
|
26257
|
-
import { existsSync as
|
|
26258
|
-
import { homedir as
|
|
26259
|
-
import { resolve as
|
|
26447
|
+
import { existsSync as existsSync49, readFileSync as readFileSync36, statSync as statSync17 } from "node:fs";
|
|
26448
|
+
import { homedir as homedir21 } from "node:os";
|
|
26449
|
+
import { resolve as resolve24 } from "node:path";
|
|
26260
26450
|
import { z as z5 } from "zod";
|
|
26261
26451
|
function defaultCachePaths() {
|
|
26262
|
-
const dir =
|
|
26452
|
+
const dir = resolve24(homedir21(), ".massu");
|
|
26263
26453
|
return {
|
|
26264
|
-
cachePath:
|
|
26265
|
-
lockPath:
|
|
26454
|
+
cachePath: resolve24(dir, "adapter-manifest.json"),
|
|
26455
|
+
lockPath: resolve24(dir, ".adapter-manifest.lock")
|
|
26266
26456
|
};
|
|
26267
26457
|
}
|
|
26268
26458
|
function loadCachedManifest(paths = defaultCachePaths()) {
|
|
26269
|
-
if (!
|
|
26459
|
+
if (!existsSync49(paths.cachePath)) {
|
|
26270
26460
|
return { kind: "absent" };
|
|
26271
26461
|
}
|
|
26272
26462
|
let raw;
|
|
@@ -26460,15 +26650,15 @@ var init_adapter_origin = __esm({
|
|
|
26460
26650
|
});
|
|
26461
26651
|
|
|
26462
26652
|
// src/security/local-fingerprint.ts
|
|
26463
|
-
import { existsSync as
|
|
26464
|
-
import { homedir as
|
|
26465
|
-
import { resolve as
|
|
26653
|
+
import { existsSync as existsSync50, readFileSync as readFileSync37, lstatSync as lstatSync5 } from "node:fs";
|
|
26654
|
+
import { homedir as homedir22 } from "node:os";
|
|
26655
|
+
import { resolve as resolve25, isAbsolute as isAbsolute4 } from "node:path";
|
|
26466
26656
|
import { createHash as createHash14 } from "node:crypto";
|
|
26467
26657
|
import { z as z6 } from "zod";
|
|
26468
26658
|
function computeLocalFingerprint(localPaths, projectRoot) {
|
|
26469
26659
|
const tuples = [];
|
|
26470
26660
|
for (const p19 of localPaths) {
|
|
26471
|
-
const abs =
|
|
26661
|
+
const abs = isAbsolute4(p19) ? p19 : resolve25(projectRoot, p19);
|
|
26472
26662
|
let contentTag;
|
|
26473
26663
|
try {
|
|
26474
26664
|
const lst = lstatSync5(abs);
|
|
@@ -26489,7 +26679,7 @@ function computeLocalFingerprint(localPaths, projectRoot) {
|
|
|
26489
26679
|
return createHash14("sha256").update(canonical2).digest("hex");
|
|
26490
26680
|
}
|
|
26491
26681
|
function readFingerprintSentinel(path = FINGERPRINT_PATH) {
|
|
26492
|
-
if (!
|
|
26682
|
+
if (!existsSync50(path)) return null;
|
|
26493
26683
|
let raw;
|
|
26494
26684
|
try {
|
|
26495
26685
|
raw = JSON.parse(readFileSync37(path, "utf-8"));
|
|
@@ -26540,7 +26730,7 @@ var init_local_fingerprint = __esm({
|
|
|
26540
26730
|
"use strict";
|
|
26541
26731
|
init_atomic_write();
|
|
26542
26732
|
init_manifest_schema();
|
|
26543
|
-
FINGERPRINT_PATH =
|
|
26733
|
+
FINGERPRINT_PATH = resolve25(homedir22(), ".massu", "adapters-local-fingerprint.json");
|
|
26544
26734
|
FingerprintSentinelSchema = z6.object({
|
|
26545
26735
|
fingerprint: z6.string().regex(/^[0-9a-f]{64}$/),
|
|
26546
26736
|
source: z6.enum(["cli", "cli-resync"]),
|
|
@@ -26556,15 +26746,15 @@ var init_local_fingerprint = __esm({
|
|
|
26556
26746
|
});
|
|
26557
26747
|
|
|
26558
26748
|
// src/security/install-tracking.ts
|
|
26559
|
-
import { readFileSync as readFileSync38, readdirSync as
|
|
26749
|
+
import { readFileSync as readFileSync38, readdirSync as readdirSync17, lstatSync as lstatSync6, existsSync as existsSync51 } from "node:fs";
|
|
26560
26750
|
import { join as join28, relative as relative7, sep as sep2 } from "node:path";
|
|
26561
|
-
import { homedir as
|
|
26562
|
-
import { resolve as
|
|
26751
|
+
import { homedir as homedir23 } from "node:os";
|
|
26752
|
+
import { resolve as resolve26 } from "node:path";
|
|
26563
26753
|
import { createHash as createHash15 } from "node:crypto";
|
|
26564
26754
|
import { z as z7 } from "zod";
|
|
26565
26755
|
function containsHiddenDirs(packageDir) {
|
|
26566
26756
|
for (const hidden of EXCLUDED_DIR_NAMES) {
|
|
26567
|
-
if (
|
|
26757
|
+
if (existsSync51(`${packageDir}/${hidden}`)) {
|
|
26568
26758
|
return hidden;
|
|
26569
26759
|
}
|
|
26570
26760
|
}
|
|
@@ -26576,7 +26766,7 @@ function sha256OfDir(dir, opts = {}) {
|
|
|
26576
26766
|
function walk(currentDir) {
|
|
26577
26767
|
let entries;
|
|
26578
26768
|
try {
|
|
26579
|
-
entries =
|
|
26769
|
+
entries = readdirSync17(currentDir);
|
|
26580
26770
|
} catch {
|
|
26581
26771
|
return;
|
|
26582
26772
|
}
|
|
@@ -26619,7 +26809,7 @@ function sha256OfDir(dir, opts = {}) {
|
|
|
26619
26809
|
return top.digest("hex");
|
|
26620
26810
|
}
|
|
26621
26811
|
function readInstalledManifest(path = INSTALLED_MANIFEST_PATH) {
|
|
26622
|
-
if (!
|
|
26812
|
+
if (!existsSync51(path)) return {};
|
|
26623
26813
|
let raw;
|
|
26624
26814
|
try {
|
|
26625
26815
|
raw = JSON.parse(readFileSync38(path, "utf-8"));
|
|
@@ -26686,7 +26876,7 @@ var init_install_tracking = __esm({
|
|
|
26686
26876
|
"src/security/install-tracking.ts"() {
|
|
26687
26877
|
"use strict";
|
|
26688
26878
|
init_atomic_write();
|
|
26689
|
-
INSTALLED_MANIFEST_PATH =
|
|
26879
|
+
INSTALLED_MANIFEST_PATH = resolve26(homedir23(), ".massu", "adapter-manifest-installed.json");
|
|
26690
26880
|
DEFAULT_MAX_FILE_BYTES = 64 * 1024 * 1024;
|
|
26691
26881
|
EXCLUDED_DIR_NAMES = /* @__PURE__ */ new Set([".git", "node_modules", ".cache", ".tmp"]);
|
|
26692
26882
|
InstallEntrySchema = z7.object({
|
|
@@ -26709,25 +26899,25 @@ var init_install_tracking = __esm({
|
|
|
26709
26899
|
});
|
|
26710
26900
|
|
|
26711
26901
|
// src/detect/adapters/discover.ts
|
|
26712
|
-
import { existsSync as
|
|
26713
|
-
import { resolve as
|
|
26902
|
+
import { existsSync as existsSync52, readdirSync as readdirSync18, readFileSync as readFileSync39, lstatSync as lstatSync7 } from "node:fs";
|
|
26903
|
+
import { resolve as resolve27, isAbsolute as isAbsolute5 } from "node:path";
|
|
26714
26904
|
import { z as z8 } from "zod";
|
|
26715
26905
|
function walkNodeModules(projectRoot, warnings) {
|
|
26716
|
-
const nodeModulesDir =
|
|
26717
|
-
if (!
|
|
26906
|
+
const nodeModulesDir = resolve27(projectRoot, "node_modules");
|
|
26907
|
+
if (!existsSync52(nodeModulesDir)) {
|
|
26718
26908
|
return [];
|
|
26719
26909
|
}
|
|
26720
26910
|
const candidates = [];
|
|
26721
26911
|
let topLevelEntries;
|
|
26722
26912
|
try {
|
|
26723
|
-
topLevelEntries =
|
|
26913
|
+
topLevelEntries = readdirSync18(nodeModulesDir);
|
|
26724
26914
|
} catch (err) {
|
|
26725
26915
|
warnings.push(`failed to read node_modules: ${err instanceof Error ? err.message : String(err)}`);
|
|
26726
26916
|
return [];
|
|
26727
26917
|
}
|
|
26728
26918
|
for (const entry of topLevelEntries) {
|
|
26729
26919
|
if (entry.startsWith(".")) continue;
|
|
26730
|
-
const entryPath =
|
|
26920
|
+
const entryPath = resolve27(nodeModulesDir, entry);
|
|
26731
26921
|
let entryStat;
|
|
26732
26922
|
try {
|
|
26733
26923
|
entryStat = lstatSync7(entryPath);
|
|
@@ -26744,12 +26934,12 @@ function walkNodeModules(projectRoot, warnings) {
|
|
|
26744
26934
|
if (entry.startsWith("@")) {
|
|
26745
26935
|
let scopedEntries;
|
|
26746
26936
|
try {
|
|
26747
|
-
scopedEntries =
|
|
26937
|
+
scopedEntries = readdirSync18(entryPath);
|
|
26748
26938
|
} catch {
|
|
26749
26939
|
continue;
|
|
26750
26940
|
}
|
|
26751
26941
|
for (const sub of scopedEntries) {
|
|
26752
|
-
const subPath =
|
|
26942
|
+
const subPath = resolve27(entryPath, sub);
|
|
26753
26943
|
let subStat;
|
|
26754
26944
|
try {
|
|
26755
26945
|
subStat = lstatSync7(subPath);
|
|
@@ -26768,8 +26958,8 @@ function walkNodeModules(projectRoot, warnings) {
|
|
|
26768
26958
|
return candidates;
|
|
26769
26959
|
}
|
|
26770
26960
|
function tryReadAdapterPackage(packageDir, warnings) {
|
|
26771
|
-
const pkgJsonPath =
|
|
26772
|
-
if (!
|
|
26961
|
+
const pkgJsonPath = resolve27(packageDir, "package.json");
|
|
26962
|
+
if (!existsSync52(pkgJsonPath)) return null;
|
|
26773
26963
|
let raw;
|
|
26774
26964
|
try {
|
|
26775
26965
|
raw = JSON.parse(readFileSync39(pkgJsonPath, "utf-8"));
|
|
@@ -26906,8 +27096,8 @@ function discoverAdapters(opts) {
|
|
|
26906
27096
|
const localSet = new Set(opts.configLocalPaths);
|
|
26907
27097
|
for (const localPath of opts.configLocalPaths) {
|
|
26908
27098
|
if (seenIds.has(localPath)) continue;
|
|
26909
|
-
const absPath =
|
|
26910
|
-
if (!
|
|
27099
|
+
const absPath = isAbsolute5(localPath) ? localPath : resolve27(opts.projectRoot, localPath);
|
|
27100
|
+
if (!existsSync52(absPath)) {
|
|
26911
27101
|
warnings.push(
|
|
26912
27102
|
`local adapter file not found: ${localPath} (resolved to ${absPath}). Remove via: massu adapters remove-local ${localPath}`
|
|
26913
27103
|
);
|
|
@@ -26989,8 +27179,8 @@ __export(adapters_exports, {
|
|
|
26989
27179
|
runAdaptersResyncLocalFingerprint: () => runAdaptersResyncLocalFingerprint,
|
|
26990
27180
|
runAdaptersSearch: () => runAdaptersSearch
|
|
26991
27181
|
});
|
|
26992
|
-
import { existsSync as
|
|
26993
|
-
import { resolve as
|
|
27182
|
+
import { existsSync as existsSync53, readFileSync as readFileSync40 } from "node:fs";
|
|
27183
|
+
import { resolve as resolve28 } from "node:path";
|
|
26994
27184
|
import { parseDocument } from "yaml";
|
|
26995
27185
|
async function handleAdaptersSubcommand(args2) {
|
|
26996
27186
|
const sub = args2[0];
|
|
@@ -27257,8 +27447,8 @@ function mutateLocalArray(mutator, command) {
|
|
|
27257
27447
|
);
|
|
27258
27448
|
return { exitCode: 2 };
|
|
27259
27449
|
}
|
|
27260
|
-
const yamlPath =
|
|
27261
|
-
if (!
|
|
27450
|
+
const yamlPath = resolve28(projectRoot, "massu.config.yaml");
|
|
27451
|
+
if (!existsSync53(yamlPath)) {
|
|
27262
27452
|
process.stderr.write(
|
|
27263
27453
|
`${command}: massu.config.yaml not found at ${yamlPath}. Run \`massu init\` first.
|
|
27264
27454
|
`
|
|
@@ -27288,7 +27478,7 @@ function mutateLocalArray(mutator, command) {
|
|
|
27288
27478
|
if (next === null) {
|
|
27289
27479
|
return { exitCode: 0 };
|
|
27290
27480
|
}
|
|
27291
|
-
const lockPath =
|
|
27481
|
+
const lockPath = resolve28(projectRoot, ".massu", "adapters-local-mutate.lock");
|
|
27292
27482
|
return withFileLockSync(lockPath, () => {
|
|
27293
27483
|
doc.setIn(["adapters", "local"], next);
|
|
27294
27484
|
const newYaml = doc.toString();
|
|
@@ -27357,16 +27547,16 @@ async function runAdaptersInstall(args2) {
|
|
|
27357
27547
|
`);
|
|
27358
27548
|
return { exitCode: 1 };
|
|
27359
27549
|
}
|
|
27360
|
-
const packageDir =
|
|
27361
|
-
if (!
|
|
27550
|
+
const packageDir = resolve28(projectRoot, "node_modules", ...packageName.split("/"));
|
|
27551
|
+
if (!existsSync53(packageDir)) {
|
|
27362
27552
|
process.stderr.write(
|
|
27363
27553
|
`install: ${packageName} is not installed in node_modules. Run \`npm install ${packageName}\` first.
|
|
27364
27554
|
`
|
|
27365
27555
|
);
|
|
27366
27556
|
return { exitCode: 1 };
|
|
27367
27557
|
}
|
|
27368
|
-
const pkgJsonPath =
|
|
27369
|
-
if (!
|
|
27558
|
+
const pkgJsonPath = resolve28(packageDir, "package.json");
|
|
27559
|
+
if (!existsSync53(pkgJsonPath)) {
|
|
27370
27560
|
process.stderr.write(`install: ${packageName} has no package.json at ${pkgJsonPath}
|
|
27371
27561
|
`);
|
|
27372
27562
|
return { exitCode: 1 };
|
|
@@ -27492,8 +27682,8 @@ async function runAdaptersResign(_args) {
|
|
|
27492
27682
|
removeInstalledManifestEntry(name);
|
|
27493
27683
|
continue;
|
|
27494
27684
|
}
|
|
27495
|
-
const packageDir =
|
|
27496
|
-
if (!
|
|
27685
|
+
const packageDir = resolve28(projectRoot, "node_modules", ...name.split("/"));
|
|
27686
|
+
if (!existsSync53(packageDir)) {
|
|
27497
27687
|
removed++;
|
|
27498
27688
|
warnings.push(`${name}@${entry.version}: not present in node_modules \u2014 REMOVED from sidecar`);
|
|
27499
27689
|
removeInstalledManifestEntry(name);
|
|
@@ -27578,87 +27768,6 @@ var init_adapters2 = __esm({
|
|
|
27578
27768
|
}
|
|
27579
27769
|
});
|
|
27580
27770
|
|
|
27581
|
-
// src/preflight.ts
|
|
27582
|
-
import { existsSync as existsSync52 } from "fs";
|
|
27583
|
-
function assertCodegraphUsable(dbPath) {
|
|
27584
|
-
const path = dbPath ?? getResolvedPaths().codegraphDbPath;
|
|
27585
|
-
if (!existsSync52(path)) {
|
|
27586
|
-
throw new CodegraphDbUnusableError(path, "missing");
|
|
27587
|
-
}
|
|
27588
|
-
let db = null;
|
|
27589
|
-
try {
|
|
27590
|
-
db = openDatabase2(path, { readonly: true });
|
|
27591
|
-
const row = db.prepare("SELECT COUNT(*) AS c FROM files").get();
|
|
27592
|
-
const files = row?.c ?? 0;
|
|
27593
|
-
if (files === 0) {
|
|
27594
|
-
throw new CodegraphDbUnusableError(path, "empty");
|
|
27595
|
-
}
|
|
27596
|
-
} catch (err) {
|
|
27597
|
-
if (err instanceof CodegraphDbUnusableError) throw err;
|
|
27598
|
-
throw new CodegraphDbUnusableError(
|
|
27599
|
-
path,
|
|
27600
|
-
"unreadable",
|
|
27601
|
-
err instanceof Error ? err.message : String(err)
|
|
27602
|
-
);
|
|
27603
|
-
} finally {
|
|
27604
|
-
try {
|
|
27605
|
-
db?.close();
|
|
27606
|
-
} catch {
|
|
27607
|
-
}
|
|
27608
|
-
}
|
|
27609
|
-
}
|
|
27610
|
-
var CodegraphDbNotInitializedError, CodegraphDbUnusableError;
|
|
27611
|
-
var init_preflight = __esm({
|
|
27612
|
-
"src/preflight.ts"() {
|
|
27613
|
-
"use strict";
|
|
27614
|
-
init_db_driver();
|
|
27615
|
-
init_config();
|
|
27616
|
-
CodegraphDbNotInitializedError = class extends Error {
|
|
27617
|
-
dbPath;
|
|
27618
|
-
constructor(dbPath) {
|
|
27619
|
-
super(`CodeGraph database not found at ${dbPath}`);
|
|
27620
|
-
this.name = "CodegraphDbNotInitializedError";
|
|
27621
|
-
this.dbPath = dbPath;
|
|
27622
|
-
}
|
|
27623
|
-
};
|
|
27624
|
-
CodegraphDbUnusableError = class extends CodegraphDbNotInitializedError {
|
|
27625
|
-
reason;
|
|
27626
|
-
constructor(dbPath, reason, detail) {
|
|
27627
|
-
super(dbPath);
|
|
27628
|
-
this.message = reason === "missing" ? `CodeGraph database not found at ${dbPath}` : reason === "empty" ? `CodeGraph database at ${dbPath} exists but is EMPTY (0 files indexed)` : `CodeGraph database at ${dbPath} could not be read: ${detail ?? "unknown"}`;
|
|
27629
|
-
this.name = "CodegraphDbUnusableError";
|
|
27630
|
-
this.reason = reason;
|
|
27631
|
-
}
|
|
27632
|
-
/**
|
|
27633
|
-
* The remedy, per reason. VERIFIED BY EXECUTION — `init` is a no-op on an
|
|
27634
|
-
* already-initialized repo and will NOT populate the graph. `index` is the command
|
|
27635
|
-
* that does. Getting this wrong sends the customer in a circle.
|
|
27636
|
-
*/
|
|
27637
|
-
get remedy() {
|
|
27638
|
-
switch (this.reason) {
|
|
27639
|
-
case "missing":
|
|
27640
|
-
return "npx @colbymchenry/codegraph init && npx @colbymchenry/codegraph index";
|
|
27641
|
-
case "empty":
|
|
27642
|
-
return "npx @colbymchenry/codegraph index";
|
|
27643
|
-
case "unreadable":
|
|
27644
|
-
return "npx @colbymchenry/codegraph index (the database may be corrupt \u2014 re-indexing rebuilds it)";
|
|
27645
|
-
}
|
|
27646
|
-
}
|
|
27647
|
-
/** Plain-English explanation for a human. */
|
|
27648
|
-
get humanExplanation() {
|
|
27649
|
-
switch (this.reason) {
|
|
27650
|
-
case "missing":
|
|
27651
|
-
return "Massu needs a map of your code to answer questions about it. That map has not been built yet.";
|
|
27652
|
-
case "empty":
|
|
27653
|
-
return 'The code map exists but is EMPTY \u2014 nothing was ever indexed into it. Massu would answer "no impact" to every question, which is indistinguishable from a real answer. It is refusing rather than misleading you.';
|
|
27654
|
-
case "unreadable":
|
|
27655
|
-
return "The code map exists but cannot be read. It may be corrupt.";
|
|
27656
|
-
}
|
|
27657
|
-
}
|
|
27658
|
-
};
|
|
27659
|
-
}
|
|
27660
|
-
});
|
|
27661
|
-
|
|
27662
27771
|
// src/lib/sql-table-names.ts
|
|
27663
27772
|
function t(suffix) {
|
|
27664
27773
|
return `${getConfig().toolPrefix}_${suffix}`;
|
|
@@ -27672,7 +27781,7 @@ var init_sql_table_names = __esm({
|
|
|
27672
27781
|
|
|
27673
27782
|
// src/db.ts
|
|
27674
27783
|
import { dirname as dirname24, join as join29 } from "path";
|
|
27675
|
-
import { existsSync as
|
|
27784
|
+
import { existsSync as existsSync54, mkdirSync as mkdirSync23, readdirSync as readdirSync19, statSync as statSync18 } from "fs";
|
|
27676
27785
|
function getCodeGraphDb() {
|
|
27677
27786
|
const dbPath = getResolvedPaths().codegraphDbPath;
|
|
27678
27787
|
assertCodegraphUsable(dbPath);
|
|
@@ -27683,7 +27792,7 @@ function getCodeGraphDb() {
|
|
|
27683
27792
|
function getDataDb() {
|
|
27684
27793
|
const dbPath = getResolvedPaths().dataDbPath;
|
|
27685
27794
|
const dir = dirname24(dbPath);
|
|
27686
|
-
if (!
|
|
27795
|
+
if (!existsSync54(dir)) {
|
|
27687
27796
|
mkdirSync23(dir, { recursive: true });
|
|
27688
27797
|
}
|
|
27689
27798
|
const db = openDatabase2(dbPath);
|
|
@@ -27954,14 +28063,14 @@ function isPythonDataStale(dataDb, pythonRoot) {
|
|
|
27954
28063
|
const lastBuildTime = new Date(lastBuild.value).getTime();
|
|
27955
28064
|
function checkDir(dir) {
|
|
27956
28065
|
try {
|
|
27957
|
-
const entries =
|
|
28066
|
+
const entries = readdirSync19(dir, { withFileTypes: true });
|
|
27958
28067
|
for (const entry of entries) {
|
|
27959
28068
|
const fullPath = join29(dir, entry.name);
|
|
27960
28069
|
if (entry.isDirectory()) {
|
|
27961
28070
|
if (["__pycache__", ".venv", "venv", "node_modules", ".mypy_cache", ".pytest_cache"].includes(entry.name)) continue;
|
|
27962
28071
|
if (checkDir(fullPath)) return true;
|
|
27963
28072
|
} else if (entry.name.endsWith(".py")) {
|
|
27964
|
-
if (
|
|
28073
|
+
if (statSync18(fullPath).mtimeMs > lastBuildTime) return true;
|
|
27965
28074
|
}
|
|
27966
28075
|
}
|
|
27967
28076
|
} catch {
|
|
@@ -27985,10 +28094,10 @@ var init_db2 = __esm({
|
|
|
27985
28094
|
});
|
|
27986
28095
|
|
|
27987
28096
|
// src/security-utils.ts
|
|
27988
|
-
import { resolve as
|
|
28097
|
+
import { resolve as resolve29, normalize } from "path";
|
|
27989
28098
|
function ensureWithinRoot(filePath, projectRoot) {
|
|
27990
|
-
const resolvedRoot =
|
|
27991
|
-
const resolvedPath =
|
|
28099
|
+
const resolvedRoot = resolve29(projectRoot);
|
|
28100
|
+
const resolvedPath = resolve29(resolvedRoot, filePath);
|
|
27992
28101
|
const normalizedPath = normalize(resolvedPath);
|
|
27993
28102
|
const normalizedRoot = normalize(resolvedRoot);
|
|
27994
28103
|
if (!normalizedPath.startsWith(normalizedRoot + "/") && normalizedPath !== normalizedRoot) {
|
|
@@ -28061,8 +28170,8 @@ var init_rules = __esm({
|
|
|
28061
28170
|
});
|
|
28062
28171
|
|
|
28063
28172
|
// src/import-resolver.ts
|
|
28064
|
-
import { readFileSync as readFileSync41, existsSync as
|
|
28065
|
-
import { resolve as
|
|
28173
|
+
import { readFileSync as readFileSync41, existsSync as existsSync55, statSync as statSync19 } from "fs";
|
|
28174
|
+
import { resolve as resolve30, dirname as dirname25, join as join30 } from "path";
|
|
28066
28175
|
function parseImports(source) {
|
|
28067
28176
|
const imports = [];
|
|
28068
28177
|
const lines = source.split("\n");
|
|
@@ -28118,23 +28227,23 @@ function resolveImportPath(specifier, fromFile) {
|
|
|
28118
28227
|
let basePath;
|
|
28119
28228
|
if (specifier.startsWith("@/")) {
|
|
28120
28229
|
const paths = getResolvedPaths();
|
|
28121
|
-
basePath =
|
|
28230
|
+
basePath = resolve30(paths.pathAlias["@"] ?? paths.srcDir, specifier.slice(2));
|
|
28122
28231
|
} else {
|
|
28123
|
-
basePath =
|
|
28232
|
+
basePath = resolve30(dirname25(fromFile), specifier);
|
|
28124
28233
|
}
|
|
28125
|
-
if (
|
|
28234
|
+
if (existsSync55(basePath) && !isDirectory(basePath)) {
|
|
28126
28235
|
return toRelative(basePath);
|
|
28127
28236
|
}
|
|
28128
28237
|
const resolvedPaths = getResolvedPaths();
|
|
28129
28238
|
for (const ext of resolvedPaths.extensions) {
|
|
28130
28239
|
const withExt = basePath + ext;
|
|
28131
|
-
if (
|
|
28240
|
+
if (existsSync55(withExt)) {
|
|
28132
28241
|
return toRelative(withExt);
|
|
28133
28242
|
}
|
|
28134
28243
|
}
|
|
28135
28244
|
for (const indexFile of resolvedPaths.indexFiles) {
|
|
28136
28245
|
const indexPath = join30(basePath, indexFile);
|
|
28137
|
-
if (
|
|
28246
|
+
if (existsSync55(indexPath)) {
|
|
28138
28247
|
return toRelative(indexPath);
|
|
28139
28248
|
}
|
|
28140
28249
|
}
|
|
@@ -28142,7 +28251,7 @@ function resolveImportPath(specifier, fromFile) {
|
|
|
28142
28251
|
}
|
|
28143
28252
|
function isDirectory(path) {
|
|
28144
28253
|
try {
|
|
28145
|
-
return
|
|
28254
|
+
return statSync19(path).isDirectory();
|
|
28146
28255
|
} catch {
|
|
28147
28256
|
return false;
|
|
28148
28257
|
}
|
|
@@ -28170,8 +28279,8 @@ function buildImportIndex(dataDb, codegraphDb) {
|
|
|
28170
28279
|
const batchSize = 500;
|
|
28171
28280
|
let batch = [];
|
|
28172
28281
|
for (const file of files) {
|
|
28173
|
-
const absPath = ensureWithinRoot(
|
|
28174
|
-
if (!
|
|
28282
|
+
const absPath = ensureWithinRoot(resolve30(projectRoot, file.path), projectRoot);
|
|
28283
|
+
if (!existsSync55(absPath)) continue;
|
|
28175
28284
|
let source;
|
|
28176
28285
|
try {
|
|
28177
28286
|
source = readFileSync41(absPath, "utf-8");
|
|
@@ -28211,12 +28320,12 @@ var init_import_resolver = __esm({
|
|
|
28211
28320
|
});
|
|
28212
28321
|
|
|
28213
28322
|
// src/trpc-index.ts
|
|
28214
|
-
import { readFileSync as readFileSync42, existsSync as
|
|
28215
|
-
import { resolve as
|
|
28323
|
+
import { readFileSync as readFileSync42, existsSync as existsSync56, readdirSync as readdirSync20 } from "fs";
|
|
28324
|
+
import { resolve as resolve31, join as join31 } from "path";
|
|
28216
28325
|
function parseRootRouter() {
|
|
28217
28326
|
const paths = getResolvedPaths();
|
|
28218
28327
|
const rootPath = paths.rootRouterPath;
|
|
28219
|
-
if (!
|
|
28328
|
+
if (!existsSync56(rootPath)) {
|
|
28220
28329
|
throw new Error(`Root router not found at ${rootPath}`);
|
|
28221
28330
|
}
|
|
28222
28331
|
const source = readFileSync42(rootPath, "utf-8");
|
|
@@ -28227,16 +28336,16 @@ function parseRootRouter() {
|
|
|
28227
28336
|
while ((match = importRegex.exec(source)) !== null) {
|
|
28228
28337
|
const variable = match[1];
|
|
28229
28338
|
let filePath = match[2];
|
|
28230
|
-
const fullPath =
|
|
28339
|
+
const fullPath = resolve31(paths.routersDir, filePath);
|
|
28231
28340
|
for (const ext of [".ts", ".tsx", ""]) {
|
|
28232
28341
|
const candidate = fullPath + ext;
|
|
28233
28342
|
const routersRelPath = getConfig().paths.routers ?? "src/server/api/routers";
|
|
28234
|
-
if (
|
|
28343
|
+
if (existsSync56(candidate)) {
|
|
28235
28344
|
filePath = routersRelPath + "/" + filePath + ext;
|
|
28236
28345
|
break;
|
|
28237
28346
|
}
|
|
28238
28347
|
const indexCandidate = join31(fullPath, "index.ts");
|
|
28239
|
-
if (
|
|
28348
|
+
if (existsSync56(indexCandidate)) {
|
|
28240
28349
|
filePath = routersRelPath + "/" + filePath + "/index.ts";
|
|
28241
28350
|
break;
|
|
28242
28351
|
}
|
|
@@ -28255,8 +28364,8 @@ function parseRootRouter() {
|
|
|
28255
28364
|
return mappings;
|
|
28256
28365
|
}
|
|
28257
28366
|
function extractProcedures(routerFilePath) {
|
|
28258
|
-
const absPath =
|
|
28259
|
-
if (!
|
|
28367
|
+
const absPath = resolve31(getProjectRoot(), routerFilePath);
|
|
28368
|
+
if (!existsSync56(absPath)) return [];
|
|
28260
28369
|
const source = readFileSync42(absPath, "utf-8");
|
|
28261
28370
|
const procedures = [];
|
|
28262
28371
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -28280,19 +28389,19 @@ function findUICallSites(routerKey, procedureName) {
|
|
|
28280
28389
|
const root = getProjectRoot();
|
|
28281
28390
|
const src = config.paths.source;
|
|
28282
28391
|
const searchDirs = [
|
|
28283
|
-
|
|
28284
|
-
|
|
28285
|
-
|
|
28392
|
+
resolve31(root, config.paths.pages ?? src + "/app"),
|
|
28393
|
+
resolve31(root, config.paths.components ?? src + "/components"),
|
|
28394
|
+
resolve31(root, config.paths.hooks ?? src + "/hooks")
|
|
28286
28395
|
];
|
|
28287
28396
|
const searchPattern = `api.${routerKey}.${procedureName}`;
|
|
28288
28397
|
for (const dir of searchDirs) {
|
|
28289
|
-
if (!
|
|
28398
|
+
if (!existsSync56(dir)) continue;
|
|
28290
28399
|
searchDirectory(dir, searchPattern, callSites);
|
|
28291
28400
|
}
|
|
28292
28401
|
return callSites;
|
|
28293
28402
|
}
|
|
28294
28403
|
function searchDirectory(dir, pattern, results) {
|
|
28295
|
-
const entries =
|
|
28404
|
+
const entries = readdirSync20(dir, { withFileTypes: true });
|
|
28296
28405
|
for (const entry of entries) {
|
|
28297
28406
|
const fullPath = join31(dir, entry.name);
|
|
28298
28407
|
if (entry.isDirectory()) {
|
|
@@ -28364,8 +28473,8 @@ var init_trpc_index = __esm({
|
|
|
28364
28473
|
});
|
|
28365
28474
|
|
|
28366
28475
|
// src/page-deps.ts
|
|
28367
|
-
import { readFileSync as readFileSync43, existsSync as
|
|
28368
|
-
import { resolve as
|
|
28476
|
+
import { readFileSync as readFileSync43, existsSync as existsSync57 } from "fs";
|
|
28477
|
+
import { resolve as resolve32 } from "path";
|
|
28369
28478
|
function deriveRoute(pageFile) {
|
|
28370
28479
|
let route = pageFile.replace(/^src\/app/, "").replace(/\/page\.tsx?$/, "").replace(/\/page\.jsx?$/, "");
|
|
28371
28480
|
return route || "/";
|
|
@@ -28403,8 +28512,8 @@ function findRouterCalls(files) {
|
|
|
28403
28512
|
const routers = /* @__PURE__ */ new Set();
|
|
28404
28513
|
const projectRoot = getProjectRoot();
|
|
28405
28514
|
for (const file of files) {
|
|
28406
|
-
const absPath = ensureWithinRoot(
|
|
28407
|
-
if (!
|
|
28515
|
+
const absPath = ensureWithinRoot(resolve32(projectRoot, file), projectRoot);
|
|
28516
|
+
if (!existsSync57(absPath)) continue;
|
|
28408
28517
|
try {
|
|
28409
28518
|
const source = readFileSync43(absPath, "utf-8");
|
|
28410
28519
|
const apiCallRegex = /api\.(\w+)\.\w+/g;
|
|
@@ -28424,8 +28533,8 @@ function findTablesFromRouters(routerNames, dataDb) {
|
|
|
28424
28533
|
`SELECT DISTINCT router_file FROM ${t("trpc_procedures")} WHERE router_name = ? LIMIT 10000`
|
|
28425
28534
|
).all(routerName);
|
|
28426
28535
|
for (const proc of procs) {
|
|
28427
|
-
const absPath = ensureWithinRoot(
|
|
28428
|
-
if (!
|
|
28536
|
+
const absPath = ensureWithinRoot(resolve32(getProjectRoot(), proc.router_file), getProjectRoot());
|
|
28537
|
+
if (!existsSync57(absPath)) continue;
|
|
28429
28538
|
try {
|
|
28430
28539
|
const source = readFileSync43(absPath, "utf-8");
|
|
28431
28540
|
const dbPattern = getConfig().dbAccessPattern ?? "ctx.db.{table}";
|
|
@@ -28699,11 +28808,11 @@ var init_domains = __esm({
|
|
|
28699
28808
|
});
|
|
28700
28809
|
|
|
28701
28810
|
// src/schema-mapper.ts
|
|
28702
|
-
import { readFileSync as readFileSync44, existsSync as
|
|
28811
|
+
import { readFileSync as readFileSync44, existsSync as existsSync58, readdirSync as readdirSync21 } from "fs";
|
|
28703
28812
|
import { join as join32 } from "path";
|
|
28704
28813
|
function parsePrismaSchema() {
|
|
28705
28814
|
const schemaPath = getResolvedPaths().prismaSchemaPath;
|
|
28706
|
-
if (!
|
|
28815
|
+
if (!existsSync58(schemaPath)) {
|
|
28707
28816
|
throw new Error(`Prisma schema not found at ${schemaPath}`);
|
|
28708
28817
|
}
|
|
28709
28818
|
const source = readFileSync44(schemaPath, "utf-8");
|
|
@@ -28764,12 +28873,12 @@ function toSnakeCase(str) {
|
|
|
28764
28873
|
function findColumnUsageInRouters(tableName) {
|
|
28765
28874
|
const usage2 = /* @__PURE__ */ new Map();
|
|
28766
28875
|
const routersDir = getResolvedPaths().routersDir;
|
|
28767
|
-
if (!
|
|
28876
|
+
if (!existsSync58(routersDir)) return usage2;
|
|
28768
28877
|
scanDirectory(routersDir, tableName, usage2);
|
|
28769
28878
|
return usage2;
|
|
28770
28879
|
}
|
|
28771
28880
|
function scanDirectory(dir, tableName, usage2) {
|
|
28772
|
-
const entries =
|
|
28881
|
+
const entries = readdirSync21(dir, { withFileTypes: true });
|
|
28773
28882
|
for (const entry of entries) {
|
|
28774
28883
|
const fullPath = join32(dir, entry.name);
|
|
28775
28884
|
if (entry.isDirectory()) {
|
|
@@ -28826,8 +28935,8 @@ function detectMismatches(models) {
|
|
|
28826
28935
|
}
|
|
28827
28936
|
function findFilesUsingColumn(dir, column, tableName) {
|
|
28828
28937
|
const result = [];
|
|
28829
|
-
if (!
|
|
28830
|
-
const entries =
|
|
28938
|
+
if (!existsSync58(dir)) return result;
|
|
28939
|
+
const entries = readdirSync21(dir, { withFileTypes: true });
|
|
28831
28940
|
for (const entry of entries) {
|
|
28832
28941
|
const fullPath = join32(dir, entry.name);
|
|
28833
28942
|
if (entry.isDirectory()) {
|
|
@@ -28979,12 +29088,12 @@ var init_import_parser = __esm({
|
|
|
28979
29088
|
});
|
|
28980
29089
|
|
|
28981
29090
|
// src/python/import-resolver.ts
|
|
28982
|
-
import { readFileSync as readFileSync45, existsSync as
|
|
28983
|
-
import { resolve as
|
|
29091
|
+
import { readFileSync as readFileSync45, existsSync as existsSync59, readdirSync as readdirSync22 } from "fs";
|
|
29092
|
+
import { resolve as resolve34, join as join33, relative as relative8, dirname as dirname26 } from "path";
|
|
28984
29093
|
function resolvePythonModulePath(module, fromFile, pythonRoot, level) {
|
|
28985
29094
|
const projectRoot = getProjectRoot();
|
|
28986
29095
|
if (level > 0) {
|
|
28987
|
-
let baseDir = dirname26(
|
|
29096
|
+
let baseDir = dirname26(resolve34(projectRoot, fromFile));
|
|
28988
29097
|
for (let i = 1; i < level; i++) {
|
|
28989
29098
|
baseDir = dirname26(baseDir);
|
|
28990
29099
|
}
|
|
@@ -28996,17 +29105,17 @@ function resolvePythonModulePath(module, fromFile, pythonRoot, level) {
|
|
|
28996
29105
|
return tryResolvePythonPath(baseDir, projectRoot);
|
|
28997
29106
|
}
|
|
28998
29107
|
const parts = module.split(".");
|
|
28999
|
-
const candidate = join33(
|
|
29108
|
+
const candidate = join33(resolve34(projectRoot, pythonRoot), ...parts);
|
|
29000
29109
|
return tryResolvePythonPath(candidate, projectRoot);
|
|
29001
29110
|
}
|
|
29002
29111
|
function tryResolvePythonPath(basePath, projectRoot) {
|
|
29003
|
-
if (
|
|
29112
|
+
if (existsSync59(basePath + ".py")) {
|
|
29004
29113
|
return relative8(projectRoot, basePath + ".py");
|
|
29005
29114
|
}
|
|
29006
|
-
if (
|
|
29115
|
+
if (existsSync59(join33(basePath, "__init__.py"))) {
|
|
29007
29116
|
return relative8(projectRoot, join33(basePath, "__init__.py"));
|
|
29008
29117
|
}
|
|
29009
|
-
if (basePath.endsWith(".py") &&
|
|
29118
|
+
if (basePath.endsWith(".py") && existsSync59(basePath)) {
|
|
29010
29119
|
return relative8(projectRoot, basePath);
|
|
29011
29120
|
}
|
|
29012
29121
|
return null;
|
|
@@ -29014,7 +29123,7 @@ function tryResolvePythonPath(basePath, projectRoot) {
|
|
|
29014
29123
|
function walkPythonFiles(dir, excludeDirs) {
|
|
29015
29124
|
const files = [];
|
|
29016
29125
|
try {
|
|
29017
|
-
const entries =
|
|
29126
|
+
const entries = readdirSync22(dir, { withFileTypes: true });
|
|
29018
29127
|
for (const entry of entries) {
|
|
29019
29128
|
if (entry.isDirectory()) {
|
|
29020
29129
|
if (excludeDirs.includes(entry.name)) continue;
|
|
@@ -29029,7 +29138,7 @@ function walkPythonFiles(dir, excludeDirs) {
|
|
|
29029
29138
|
}
|
|
29030
29139
|
function buildPythonImportIndex(dataDb, pythonRoot, excludeDirs = ["__pycache__", ".venv", "venv", ".mypy_cache", ".pytest_cache"]) {
|
|
29031
29140
|
const projectRoot = getProjectRoot();
|
|
29032
|
-
const absRoot =
|
|
29141
|
+
const absRoot = resolve34(projectRoot, pythonRoot);
|
|
29033
29142
|
dataDb.exec(`DELETE FROM ${t("py_imports")}`);
|
|
29034
29143
|
const insertStmt = dataDb.prepare(
|
|
29035
29144
|
`INSERT INTO ${t("py_imports")} (source_file, target_file, import_type, imported_names, line) VALUES (?, ?, ?, ?, ?)`
|
|
@@ -29313,12 +29422,12 @@ var init_route_parser = __esm({
|
|
|
29313
29422
|
});
|
|
29314
29423
|
|
|
29315
29424
|
// src/python/route-indexer.ts
|
|
29316
|
-
import { readFileSync as readFileSync46, readdirSync as
|
|
29425
|
+
import { readFileSync as readFileSync46, readdirSync as readdirSync23 } from "fs";
|
|
29317
29426
|
import { join as join34, relative as relative9 } from "path";
|
|
29318
29427
|
function walkPyFiles(dir, excludeDirs) {
|
|
29319
29428
|
const files = [];
|
|
29320
29429
|
try {
|
|
29321
|
-
const entries =
|
|
29430
|
+
const entries = readdirSync23(dir, { withFileTypes: true });
|
|
29322
29431
|
for (const entry of entries) {
|
|
29323
29432
|
if (entry.isDirectory()) {
|
|
29324
29433
|
if (excludeDirs.includes(entry.name)) continue;
|
|
@@ -29558,12 +29667,12 @@ var init_model_parser = __esm({
|
|
|
29558
29667
|
});
|
|
29559
29668
|
|
|
29560
29669
|
// src/python/model-indexer.ts
|
|
29561
|
-
import { readFileSync as readFileSync47, readdirSync as
|
|
29670
|
+
import { readFileSync as readFileSync47, readdirSync as readdirSync24 } from "fs";
|
|
29562
29671
|
import { join as join35, relative as relative10 } from "path";
|
|
29563
29672
|
function walkPyFiles2(dir, excludeDirs) {
|
|
29564
29673
|
const files = [];
|
|
29565
29674
|
try {
|
|
29566
|
-
const entries =
|
|
29675
|
+
const entries = readdirSync24(dir, { withFileTypes: true });
|
|
29567
29676
|
for (const entry of entries) {
|
|
29568
29677
|
if (entry.isDirectory()) {
|
|
29569
29678
|
if (excludeDirs.includes(entry.name)) continue;
|
|
@@ -29855,7 +29964,7 @@ var init_migration_parser = __esm({
|
|
|
29855
29964
|
});
|
|
29856
29965
|
|
|
29857
29966
|
// src/python/migration-indexer.ts
|
|
29858
|
-
import { readFileSync as readFileSync48, readdirSync as
|
|
29967
|
+
import { readFileSync as readFileSync48, readdirSync as readdirSync25 } from "fs";
|
|
29859
29968
|
import { join as join36, relative as relative11 } from "path";
|
|
29860
29969
|
function buildPythonMigrationIndex(dataDb, alembicDir) {
|
|
29861
29970
|
const projectRoot = getProjectRoot();
|
|
@@ -29864,10 +29973,10 @@ function buildPythonMigrationIndex(dataDb, alembicDir) {
|
|
|
29864
29973
|
const versionsDir = join36(absDir, "versions");
|
|
29865
29974
|
let files = [];
|
|
29866
29975
|
try {
|
|
29867
|
-
files =
|
|
29976
|
+
files = readdirSync25(versionsDir).filter((f2) => f2.endsWith(".py")).map((f2) => join36(versionsDir, f2));
|
|
29868
29977
|
} catch {
|
|
29869
29978
|
try {
|
|
29870
|
-
files =
|
|
29979
|
+
files = readdirSync25(absDir).filter((f2) => f2.endsWith(".py") && f2 !== "env.py").map((f2) => join36(absDir, f2));
|
|
29871
29980
|
} catch {
|
|
29872
29981
|
}
|
|
29873
29982
|
}
|
|
@@ -29916,7 +30025,7 @@ var init_migration_indexer = __esm({
|
|
|
29916
30025
|
});
|
|
29917
30026
|
|
|
29918
30027
|
// src/python/coupling-detector.ts
|
|
29919
|
-
import { readFileSync as readFileSync49, readdirSync as
|
|
30028
|
+
import { readFileSync as readFileSync49, readdirSync as readdirSync26 } from "fs";
|
|
29920
30029
|
import { join as join37, relative as relative12 } from "path";
|
|
29921
30030
|
function buildPythonCouplingIndex(dataDb) {
|
|
29922
30031
|
const projectRoot = getProjectRoot();
|
|
@@ -29981,7 +30090,7 @@ function walkFrontendFiles(dir) {
|
|
|
29981
30090
|
const files = [];
|
|
29982
30091
|
const exclude = ["node_modules", ".next", "dist", ".git", "__pycache__", ".venv", "venv"];
|
|
29983
30092
|
try {
|
|
29984
|
-
const entries =
|
|
30093
|
+
const entries = readdirSync26(dir, { withFileTypes: true });
|
|
29985
30094
|
for (const entry of entries) {
|
|
29986
30095
|
if (entry.isDirectory()) {
|
|
29987
30096
|
if (exclude.includes(entry.name)) continue;
|
|
@@ -30359,8 +30468,8 @@ var init_memory_tools = __esm({
|
|
|
30359
30468
|
});
|
|
30360
30469
|
|
|
30361
30470
|
// src/docs-tools.ts
|
|
30362
|
-
import { readFileSync as readFileSync50, existsSync as
|
|
30363
|
-
import { resolve as
|
|
30471
|
+
import { readFileSync as readFileSync50, existsSync as existsSync60 } from "fs";
|
|
30472
|
+
import { resolve as resolve35, basename as basename9 } from "path";
|
|
30364
30473
|
function p4(baseName) {
|
|
30365
30474
|
return `${getConfig().toolPrefix}_${baseName}`;
|
|
30366
30475
|
}
|
|
@@ -30415,7 +30524,7 @@ function handleDocsToolCall(name, args2) {
|
|
|
30415
30524
|
}
|
|
30416
30525
|
function loadDocsMap() {
|
|
30417
30526
|
const mapPath = getResolvedPaths().docsMapPath;
|
|
30418
|
-
if (!
|
|
30527
|
+
if (!existsSync60(mapPath)) {
|
|
30419
30528
|
throw new Error(`docs-map.json not found at ${mapPath}`);
|
|
30420
30529
|
}
|
|
30421
30530
|
return JSON.parse(readFileSync50(mapPath, "utf-8"));
|
|
@@ -30488,10 +30597,10 @@ function extractFrontmatter(content) {
|
|
|
30488
30597
|
}
|
|
30489
30598
|
function extractProcedureNames(routerPath) {
|
|
30490
30599
|
const root = getProjectRoot();
|
|
30491
|
-
const absPath = ensureWithinRoot(
|
|
30492
|
-
if (!
|
|
30493
|
-
const altPath = ensureWithinRoot(
|
|
30494
|
-
if (!
|
|
30600
|
+
const absPath = ensureWithinRoot(resolve35(getResolvedPaths().srcDir, "..", routerPath), root);
|
|
30601
|
+
if (!existsSync60(absPath)) {
|
|
30602
|
+
const altPath = ensureWithinRoot(resolve35(getResolvedPaths().srcDir, "../server/api/routers", basename9(routerPath)), root);
|
|
30603
|
+
if (!existsSync60(altPath)) return [];
|
|
30495
30604
|
return extractProcedureNamesFromContent(readFileSync50(altPath, "utf-8"));
|
|
30496
30605
|
}
|
|
30497
30606
|
return extractProcedureNamesFromContent(readFileSync50(absPath, "utf-8"));
|
|
@@ -30534,8 +30643,8 @@ function handleDocsAudit(args2) {
|
|
|
30534
30643
|
for (const [mappingId, triggeringFiles] of affectedMappings) {
|
|
30535
30644
|
const mapping = docsMap.mappings.find((m3) => m3.id === mappingId);
|
|
30536
30645
|
if (!mapping) continue;
|
|
30537
|
-
const helpPagePath = ensureWithinRoot(
|
|
30538
|
-
if (!
|
|
30646
|
+
const helpPagePath = ensureWithinRoot(resolve35(getResolvedPaths().helpSitePath, mapping.helpPage), getProjectRoot());
|
|
30647
|
+
if (!existsSync60(helpPagePath)) {
|
|
30539
30648
|
results.push({
|
|
30540
30649
|
helpPage: mapping.helpPage,
|
|
30541
30650
|
mappingId,
|
|
@@ -30587,8 +30696,8 @@ function handleDocsAudit(args2) {
|
|
|
30587
30696
|
});
|
|
30588
30697
|
for (const [guideName, parentId] of Object.entries(docsMap.userGuideInheritance.examples)) {
|
|
30589
30698
|
if (parentId === mappingId) {
|
|
30590
|
-
const guidePath = ensureWithinRoot(
|
|
30591
|
-
if (
|
|
30699
|
+
const guidePath = ensureWithinRoot(resolve35(getResolvedPaths().helpSitePath, `pages/user-guides/${guideName}/index.mdx`), getProjectRoot());
|
|
30700
|
+
if (existsSync60(guidePath)) {
|
|
30592
30701
|
const guideContent = readFileSync50(guidePath, "utf-8");
|
|
30593
30702
|
const guideFrontmatter = extractFrontmatter(guideContent);
|
|
30594
30703
|
if (!guideFrontmatter?.lastVerified || status === "STALE") {
|
|
@@ -30622,8 +30731,8 @@ function handleDocsCoverage(args2) {
|
|
|
30622
30731
|
const gaps = [];
|
|
30623
30732
|
const mappings = filterDomain ? docsMap.mappings.filter((m3) => m3.id === filterDomain) : docsMap.mappings;
|
|
30624
30733
|
for (const mapping of mappings) {
|
|
30625
|
-
const helpPagePath = ensureWithinRoot(
|
|
30626
|
-
const exists =
|
|
30734
|
+
const helpPagePath = ensureWithinRoot(resolve35(getResolvedPaths().helpSitePath, mapping.helpPage), getProjectRoot());
|
|
30735
|
+
const exists = existsSync60(helpPagePath);
|
|
30627
30736
|
let hasContent = false;
|
|
30628
30737
|
let lineCount = 0;
|
|
30629
30738
|
let lastVerified = null;
|
|
@@ -30970,8 +31079,8 @@ var init_observability_tools = __esm({
|
|
|
30970
31079
|
});
|
|
30971
31080
|
|
|
30972
31081
|
// src/sentinel-db.ts
|
|
30973
|
-
import { existsSync as
|
|
30974
|
-
import { resolve as
|
|
31082
|
+
import { existsSync as existsSync61 } from "fs";
|
|
31083
|
+
import { resolve as resolve36 } from "path";
|
|
30975
31084
|
function parsePortalScope(raw) {
|
|
30976
31085
|
if (!raw) return [];
|
|
30977
31086
|
try {
|
|
@@ -31207,23 +31316,23 @@ function validateFeatures(db, domainFilter) {
|
|
|
31207
31316
|
const missingProcedures = [];
|
|
31208
31317
|
const missingPages = [];
|
|
31209
31318
|
for (const comp of components) {
|
|
31210
|
-
const absPath =
|
|
31211
|
-
if (!
|
|
31319
|
+
const absPath = resolve36(PROJECT_ROOT, comp.component_file);
|
|
31320
|
+
if (!existsSync61(absPath)) {
|
|
31212
31321
|
missingComponents.push(comp.component_file);
|
|
31213
31322
|
}
|
|
31214
31323
|
}
|
|
31215
31324
|
for (const proc of procedures) {
|
|
31216
|
-
const routerPath =
|
|
31217
|
-
if (!
|
|
31325
|
+
const routerPath = resolve36(PROJECT_ROOT, `src/server/api/routers/${proc.router_name}.ts`);
|
|
31326
|
+
if (!existsSync61(routerPath)) {
|
|
31218
31327
|
missingProcedures.push({ router: proc.router_name, procedure: proc.procedure_name });
|
|
31219
31328
|
}
|
|
31220
31329
|
}
|
|
31221
31330
|
for (const page of pages) {
|
|
31222
31331
|
const routeToPath = page.page_route.replace(/^\/(portal-[^/]+\/)?/, "src/app/").replace(/\/$/, "") + "/page.tsx";
|
|
31223
|
-
const absPath =
|
|
31224
|
-
if (page.page_route.startsWith("/") && !
|
|
31225
|
-
const altPath =
|
|
31226
|
-
if (!
|
|
31332
|
+
const absPath = resolve36(PROJECT_ROOT, routeToPath);
|
|
31333
|
+
if (page.page_route.startsWith("/") && !existsSync61(absPath)) {
|
|
31334
|
+
const altPath = resolve36(PROJECT_ROOT, `src/app${page.page_route}/page.tsx`);
|
|
31335
|
+
if (!existsSync61(altPath)) {
|
|
31227
31336
|
missingPages.push(page.page_route);
|
|
31228
31337
|
}
|
|
31229
31338
|
}
|
|
@@ -31749,8 +31858,8 @@ var init_sentinel_tools = __esm({
|
|
|
31749
31858
|
});
|
|
31750
31859
|
|
|
31751
31860
|
// src/sentinel-scanner.ts
|
|
31752
|
-
import { readFileSync as readFileSync51, existsSync as
|
|
31753
|
-
import { resolve as
|
|
31861
|
+
import { readFileSync as readFileSync51, existsSync as existsSync62, readdirSync as readdirSync27, statSync as statSync20 } from "fs";
|
|
31862
|
+
import { resolve as resolve37, join as join38, basename as basename10, dirname as dirname27, relative as relative13 } from "path";
|
|
31754
31863
|
function inferDomain(filePath) {
|
|
31755
31864
|
const domains = getConfig().domains;
|
|
31756
31865
|
const path = filePath.toLowerCase();
|
|
@@ -31881,10 +31990,10 @@ function scanComponentExports(dataDb) {
|
|
|
31881
31990
|
const projectRoot = getProjectRoot();
|
|
31882
31991
|
const componentsBase = config.paths.components ?? config.paths.source + "/components";
|
|
31883
31992
|
const componentDirs = [];
|
|
31884
|
-
const basePath =
|
|
31885
|
-
if (
|
|
31993
|
+
const basePath = resolve37(projectRoot, componentsBase);
|
|
31994
|
+
if (existsSync62(basePath)) {
|
|
31886
31995
|
try {
|
|
31887
|
-
const entries =
|
|
31996
|
+
const entries = readdirSync27(basePath, { withFileTypes: true });
|
|
31888
31997
|
for (const entry of entries) {
|
|
31889
31998
|
if (entry.isDirectory()) {
|
|
31890
31999
|
componentDirs.push(componentsBase + "/" + entry.name);
|
|
@@ -31894,8 +32003,8 @@ function scanComponentExports(dataDb) {
|
|
|
31894
32003
|
}
|
|
31895
32004
|
}
|
|
31896
32005
|
for (const dir of componentDirs) {
|
|
31897
|
-
const absDir =
|
|
31898
|
-
if (!
|
|
32006
|
+
const absDir = resolve37(projectRoot, dir);
|
|
32007
|
+
if (!existsSync62(absDir)) continue;
|
|
31899
32008
|
const files = walkDir2(absDir).filter((f2) => f2.endsWith(".tsx") || f2.endsWith(".ts"));
|
|
31900
32009
|
for (const file of files) {
|
|
31901
32010
|
const relPath = relative13(projectRoot, file);
|
|
@@ -31948,11 +32057,11 @@ function scanComponentExports(dataDb) {
|
|
|
31948
32057
|
function walkDir2(dir) {
|
|
31949
32058
|
const results = [];
|
|
31950
32059
|
try {
|
|
31951
|
-
const entries =
|
|
32060
|
+
const entries = readdirSync27(dir);
|
|
31952
32061
|
for (const entry of entries) {
|
|
31953
32062
|
const fullPath = join38(dir, entry);
|
|
31954
32063
|
try {
|
|
31955
|
-
const stat =
|
|
32064
|
+
const stat = statSync20(fullPath);
|
|
31956
32065
|
if (stat.isDirectory()) {
|
|
31957
32066
|
results.push(...walkDir2(fullPath));
|
|
31958
32067
|
} else {
|
|
@@ -32660,7 +32769,7 @@ var init_prompt_analyzer = __esm({
|
|
|
32660
32769
|
});
|
|
32661
32770
|
|
|
32662
32771
|
// src/validation-engine.ts
|
|
32663
|
-
import { existsSync as
|
|
32772
|
+
import { existsSync as existsSync63, readFileSync as readFileSync52 } from "fs";
|
|
32664
32773
|
function p10(baseName) {
|
|
32665
32774
|
return `${getConfig().toolPrefix}_${baseName}`;
|
|
32666
32775
|
}
|
|
@@ -32691,7 +32800,7 @@ function validateFile(filePath, projectRoot) {
|
|
|
32691
32800
|
});
|
|
32692
32801
|
return checks;
|
|
32693
32802
|
}
|
|
32694
|
-
if (!
|
|
32803
|
+
if (!existsSync63(absPath)) {
|
|
32695
32804
|
checks.push({
|
|
32696
32805
|
name: "file_exists",
|
|
32697
32806
|
severity: "error",
|
|
@@ -33159,7 +33268,7 @@ var init_adr_generator = __esm({
|
|
|
33159
33268
|
});
|
|
33160
33269
|
|
|
33161
33270
|
// src/security-scorer.ts
|
|
33162
|
-
import { existsSync as
|
|
33271
|
+
import { existsSync as existsSync64, readFileSync as readFileSync53 } from "fs";
|
|
33163
33272
|
function p12(baseName) {
|
|
33164
33273
|
return `${getConfig().toolPrefix}_${baseName}`;
|
|
33165
33274
|
}
|
|
@@ -33183,7 +33292,7 @@ function scoreFileSecurity(filePath, projectRoot) {
|
|
|
33183
33292
|
}]
|
|
33184
33293
|
};
|
|
33185
33294
|
}
|
|
33186
|
-
if (!
|
|
33295
|
+
if (!existsSync64(absPath)) {
|
|
33187
33296
|
return { riskScore: 0, findings: [] };
|
|
33188
33297
|
}
|
|
33189
33298
|
let source;
|
|
@@ -33478,8 +33587,8 @@ var init_security_scorer = __esm({
|
|
|
33478
33587
|
});
|
|
33479
33588
|
|
|
33480
33589
|
// src/dependency-scorer.ts
|
|
33481
|
-
import { existsSync as
|
|
33482
|
-
import { resolve as
|
|
33590
|
+
import { existsSync as existsSync65, readFileSync as readFileSync54 } from "fs";
|
|
33591
|
+
import { resolve as resolve38 } from "path";
|
|
33483
33592
|
function p13(baseName) {
|
|
33484
33593
|
return `${getConfig().toolPrefix}_${baseName}`;
|
|
33485
33594
|
}
|
|
@@ -33511,8 +33620,8 @@ function calculateDepRisk(factors) {
|
|
|
33511
33620
|
return Math.min(100, risk);
|
|
33512
33621
|
}
|
|
33513
33622
|
function getInstalledPackages(projectRoot) {
|
|
33514
|
-
const pkgPath =
|
|
33515
|
-
if (!
|
|
33623
|
+
const pkgPath = resolve38(projectRoot, "package.json");
|
|
33624
|
+
if (!existsSync65(pkgPath)) return /* @__PURE__ */ new Map();
|
|
33516
33625
|
try {
|
|
33517
33626
|
const pkg = JSON.parse(readFileSync54(pkgPath, "utf-8"));
|
|
33518
33627
|
const packages = /* @__PURE__ */ new Map();
|
|
@@ -34120,8 +34229,8 @@ var init_regression_detector = __esm({
|
|
|
34120
34229
|
|
|
34121
34230
|
// src/knowledge-indexer.ts
|
|
34122
34231
|
import { createHash as createHash16 } from "crypto";
|
|
34123
|
-
import { readFileSync as readFileSync55, readdirSync as
|
|
34124
|
-
import { resolve as
|
|
34232
|
+
import { readFileSync as readFileSync55, readdirSync as readdirSync28, statSync as statSync21, existsSync as existsSync66 } from "fs";
|
|
34233
|
+
import { resolve as resolve39, relative as relative14, basename as basename11, extname as extname2 } from "path";
|
|
34125
34234
|
function getKnowledgePaths() {
|
|
34126
34235
|
const resolved = getResolvedPaths();
|
|
34127
34236
|
const config = getConfig();
|
|
@@ -34147,9 +34256,9 @@ function discoverMarkdownFiles(baseDir) {
|
|
|
34147
34256
|
const files = [];
|
|
34148
34257
|
function walk(dir) {
|
|
34149
34258
|
try {
|
|
34150
|
-
const entries =
|
|
34259
|
+
const entries = readdirSync28(dir, { withFileTypes: true });
|
|
34151
34260
|
for (const entry of entries) {
|
|
34152
|
-
const fullPath =
|
|
34261
|
+
const fullPath = resolve39(dir, entry.name);
|
|
34153
34262
|
if (entry.isDirectory()) {
|
|
34154
34263
|
if (entry.name === "archive" && dir.includes("session-state")) continue;
|
|
34155
34264
|
if (entry.name === "archive" && dir.includes("status")) continue;
|
|
@@ -34428,11 +34537,11 @@ function indexAllKnowledge(db) {
|
|
|
34428
34537
|
files.push(...memFiles);
|
|
34429
34538
|
} catch {
|
|
34430
34539
|
}
|
|
34431
|
-
if (
|
|
34540
|
+
if (existsSync66(paths.plansDir)) {
|
|
34432
34541
|
const planFiles = discoverMarkdownFiles(paths.plansDir);
|
|
34433
34542
|
files.push(...planFiles);
|
|
34434
34543
|
}
|
|
34435
|
-
if (
|
|
34544
|
+
if (existsSync66(paths.docsDir)) {
|
|
34436
34545
|
const excludePatterns = getConfig().conventions?.excludePatterns ?? ["/ARCHIVE/", "/SESSION-HISTORY/"];
|
|
34437
34546
|
const docsFiles = discoverMarkdownFiles(paths.docsDir).filter((f2) => !f2.includes("/plans/") && !excludePatterns.some((p19) => f2.includes(p19)));
|
|
34438
34547
|
files.push(...docsFiles);
|
|
@@ -34475,7 +34584,7 @@ function indexAllKnowledge(db) {
|
|
|
34475
34584
|
} catch {
|
|
34476
34585
|
}
|
|
34477
34586
|
for (const filePath of files) {
|
|
34478
|
-
if (!
|
|
34587
|
+
if (!existsSync66(filePath)) continue;
|
|
34479
34588
|
const content = readFileSync55(filePath, "utf-8");
|
|
34480
34589
|
const hash = hashContent2(content);
|
|
34481
34590
|
const relPath = filePath.startsWith(paths.claudeDir) ? relative14(paths.claudeDir, filePath) : filePath.startsWith(paths.plansDir) ? "plans/" + relative14(paths.plansDir, filePath) : filePath.startsWith(paths.docsDir) ? "docs/" + relative14(paths.docsDir, filePath) : filePath.startsWith(paths.memoryDir) ? `memory/${relative14(paths.memoryDir, filePath)}` : basename11(filePath);
|
|
@@ -34611,17 +34720,17 @@ function isKnowledgeStale(db) {
|
|
|
34611
34720
|
files.push(...discoverMarkdownFiles(paths.memoryDir));
|
|
34612
34721
|
} catch {
|
|
34613
34722
|
}
|
|
34614
|
-
if (
|
|
34723
|
+
if (existsSync66(paths.plansDir)) {
|
|
34615
34724
|
files.push(...discoverMarkdownFiles(paths.plansDir));
|
|
34616
34725
|
}
|
|
34617
|
-
if (
|
|
34726
|
+
if (existsSync66(paths.docsDir)) {
|
|
34618
34727
|
const excludePatterns = getConfig().conventions?.excludePatterns ?? ["/ARCHIVE/", "/SESSION-HISTORY/"];
|
|
34619
34728
|
const docsFiles = discoverMarkdownFiles(paths.docsDir).filter((f2) => !f2.includes("/plans/") && !excludePatterns.some((p19) => f2.includes(p19)));
|
|
34620
34729
|
files.push(...docsFiles);
|
|
34621
34730
|
}
|
|
34622
34731
|
for (const filePath of files) {
|
|
34623
34732
|
try {
|
|
34624
|
-
const stat =
|
|
34733
|
+
const stat = statSync21(filePath);
|
|
34625
34734
|
if (stat.mtimeMs > lastIndexTime) return true;
|
|
34626
34735
|
} catch {
|
|
34627
34736
|
continue;
|
|
@@ -34643,8 +34752,8 @@ var init_knowledge_indexer = __esm({
|
|
|
34643
34752
|
});
|
|
34644
34753
|
|
|
34645
34754
|
// src/knowledge-tools.ts
|
|
34646
|
-
import { readFileSync as readFileSync56, writeFileSync as writeFileSync16, appendFileSync as appendFileSync5, readdirSync as
|
|
34647
|
-
import { resolve as
|
|
34755
|
+
import { readFileSync as readFileSync56, writeFileSync as writeFileSync16, appendFileSync as appendFileSync5, readdirSync as readdirSync29 } from "fs";
|
|
34756
|
+
import { resolve as resolve40, basename as basename12 } from "path";
|
|
34648
34757
|
function p16(baseName) {
|
|
34649
34758
|
return `${getConfig().toolPrefix}_${baseName}`;
|
|
34650
34759
|
}
|
|
@@ -35383,7 +35492,7 @@ function handleCorrect(db, args2) {
|
|
|
35383
35492
|
if (!wrong || !correction || !rule) {
|
|
35384
35493
|
return text15("Error: wrong, correction, and rule are all required.");
|
|
35385
35494
|
}
|
|
35386
|
-
const correctionsPath =
|
|
35495
|
+
const correctionsPath = resolve40(getResolvedPaths().memoryDir, "corrections.md");
|
|
35387
35496
|
const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
35388
35497
|
const title = rule.slice(0, 60);
|
|
35389
35498
|
const entry = formatCorrectionEntry({
|
|
@@ -35578,7 +35687,7 @@ function handleGaps(db, args2) {
|
|
|
35578
35687
|
} else if (checkType === "routers") {
|
|
35579
35688
|
try {
|
|
35580
35689
|
const routersDir = getResolvedPaths().routersDir;
|
|
35581
|
-
const routerFiles =
|
|
35690
|
+
const routerFiles = readdirSync29(routersDir).filter((f2) => f2.endsWith(".ts") && !f2.startsWith("_"));
|
|
35582
35691
|
lines.push(`| Router | Knowledge Hits | Status |`);
|
|
35583
35692
|
lines.push(`|--------|----------------|--------|`);
|
|
35584
35693
|
for (const file of routerFiles) {
|
|
@@ -36352,8 +36461,8 @@ var init_framework_supports = __esm({
|
|
|
36352
36461
|
});
|
|
36353
36462
|
|
|
36354
36463
|
// src/tools.ts
|
|
36355
|
-
import { readFileSync as readFileSync57, existsSync as
|
|
36356
|
-
import { resolve as
|
|
36464
|
+
import { readFileSync as readFileSync57, existsSync as existsSync68 } from "fs";
|
|
36465
|
+
import { resolve as resolve41, basename as basename13 } from "path";
|
|
36357
36466
|
function prefix2() {
|
|
36358
36467
|
return getConfig().toolPrefix;
|
|
36359
36468
|
}
|
|
@@ -36388,7 +36497,7 @@ function ensureIndexes(dataDb, codegraphDb, force = false) {
|
|
|
36388
36497
|
if (config.python?.root) {
|
|
36389
36498
|
const pythonRoot = config.python.root;
|
|
36390
36499
|
const excludeDirs = config.python.exclude_dirs || ["__pycache__", ".venv", "venv", ".mypy_cache", ".pytest_cache"];
|
|
36391
|
-
if (force || isPythonDataStale(dataDb,
|
|
36500
|
+
if (force || isPythonDataStale(dataDb, resolve41(getProjectRoot(), pythonRoot))) {
|
|
36392
36501
|
const pyImports = buildPythonImportIndex(dataDb, pythonRoot, excludeDirs);
|
|
36393
36502
|
results.push(`Python imports: ${pyImports}`);
|
|
36394
36503
|
const pyRoutes = buildPythonRouteIndex(dataDb, pythonRoot, excludeDirs);
|
|
@@ -36771,8 +36880,8 @@ function handleContext(file, dataDb, codegraphDb) {
|
|
|
36771
36880
|
try {
|
|
36772
36881
|
const resolvedPaths = getResolvedPaths();
|
|
36773
36882
|
const root = getProjectRoot();
|
|
36774
|
-
const absFilePath = ensureWithinRoot(
|
|
36775
|
-
if (
|
|
36883
|
+
const absFilePath = ensureWithinRoot(resolve41(resolvedPaths.srcDir, "..", file), root);
|
|
36884
|
+
if (existsSync68(absFilePath)) {
|
|
36776
36885
|
const fileContent = readFileSync57(absFilePath, "utf-8").slice(0, 3e3);
|
|
36777
36886
|
const keywords = [];
|
|
36778
36887
|
if (fileContent.includes("ctx.db")) keywords.push("database", "schema");
|
|
@@ -37210,8 +37319,8 @@ function handleSchema(args2) {
|
|
|
37210
37319
|
lines.push("Checking all column references against Prisma schema...");
|
|
37211
37320
|
lines.push("");
|
|
37212
37321
|
const projectRoot = getProjectRoot();
|
|
37213
|
-
const absPath = ensureWithinRoot(
|
|
37214
|
-
if (!
|
|
37322
|
+
const absPath = ensureWithinRoot(resolve41(projectRoot, file), projectRoot);
|
|
37323
|
+
if (!existsSync68(absPath)) {
|
|
37215
37324
|
return text17(`File not found: ${file}`);
|
|
37216
37325
|
}
|
|
37217
37326
|
const source = readFileSync57(absPath, "utf-8");
|
|
@@ -37647,7 +37756,7 @@ var init_startup_health = __esm({
|
|
|
37647
37756
|
// src/server.ts
|
|
37648
37757
|
var server_exports = {};
|
|
37649
37758
|
import { readFileSync as readFileSync58 } from "fs";
|
|
37650
|
-
import { resolve as
|
|
37759
|
+
import { resolve as resolve42, dirname as dirname28 } from "path";
|
|
37651
37760
|
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
37652
37761
|
function pruneMemoryOnStartup() {
|
|
37653
37762
|
try {
|
|
@@ -37695,7 +37804,7 @@ var init_server = __esm({
|
|
|
37695
37804
|
__dirname5 = dirname28(fileURLToPath6(import.meta.url));
|
|
37696
37805
|
PKG_VERSION = (() => {
|
|
37697
37806
|
try {
|
|
37698
|
-
const pkg = JSON.parse(readFileSync58(
|
|
37807
|
+
const pkg = JSON.parse(readFileSync58(resolve42(__dirname5, "..", "package.json"), "utf-8"));
|
|
37699
37808
|
return pkg.version ?? "0.0.0";
|
|
37700
37809
|
} catch {
|
|
37701
37810
|
return "0.0.0";
|
|
@@ -37998,19 +38107,19 @@ var config_upgrade_exports = {};
|
|
|
37998
38107
|
__export(config_upgrade_exports, {
|
|
37999
38108
|
runConfigUpgrade: () => runConfigUpgrade
|
|
38000
38109
|
});
|
|
38001
|
-
import { existsSync as
|
|
38002
|
-
import { resolve as
|
|
38110
|
+
import { existsSync as existsSync69, readFileSync as readFileSync59, writeFileSync as writeFileSync17, copyFileSync as copyFileSync3, unlinkSync as unlinkSync6 } from "fs";
|
|
38111
|
+
import { resolve as resolve43 } from "path";
|
|
38003
38112
|
import { parse as parseYaml6 } from "yaml";
|
|
38004
38113
|
async function runConfigUpgrade(opts = {}) {
|
|
38005
38114
|
const cwd = opts.cwd ?? process.cwd();
|
|
38006
|
-
const configPath =
|
|
38115
|
+
const configPath = resolve43(cwd, "massu.config.yaml");
|
|
38007
38116
|
const bakPath = `${configPath}.bak`;
|
|
38008
38117
|
const log = opts.silent ? () => {
|
|
38009
38118
|
} : (s) => process.stdout.write(s);
|
|
38010
38119
|
const err = opts.silent ? () => {
|
|
38011
38120
|
} : (s) => process.stderr.write(s);
|
|
38012
38121
|
if (opts.rollback) {
|
|
38013
|
-
if (!
|
|
38122
|
+
if (!existsSync69(bakPath)) {
|
|
38014
38123
|
const message = `No backup found at ${bakPath}`;
|
|
38015
38124
|
err(message + "\n");
|
|
38016
38125
|
return { exitCode: 1, action: "none", message };
|
|
@@ -38026,7 +38135,7 @@ async function runConfigUpgrade(opts = {}) {
|
|
|
38026
38135
|
return { exitCode: 2, action: "none", message };
|
|
38027
38136
|
}
|
|
38028
38137
|
}
|
|
38029
|
-
if (!
|
|
38138
|
+
if (!existsSync69(configPath)) {
|
|
38030
38139
|
const message = "massu.config.yaml not found. Run: npx massu init";
|
|
38031
38140
|
err(message + "\n");
|
|
38032
38141
|
return { exitCode: 1, action: "none", message };
|
|
@@ -38090,8 +38199,8 @@ var config_check_drift_exports = {};
|
|
|
38090
38199
|
__export(config_check_drift_exports, {
|
|
38091
38200
|
runConfigCheckDrift: () => runConfigCheckDrift
|
|
38092
38201
|
});
|
|
38093
|
-
import { existsSync as
|
|
38094
|
-
import { resolve as
|
|
38202
|
+
import { existsSync as existsSync70, readFileSync as readFileSync60 } from "fs";
|
|
38203
|
+
import { resolve as resolve44 } from "path";
|
|
38095
38204
|
import { parse as parseYaml7 } from "yaml";
|
|
38096
38205
|
function renderChanges(changes) {
|
|
38097
38206
|
if (changes.length === 0) return "(none)\n";
|
|
@@ -38099,12 +38208,12 @@ function renderChanges(changes) {
|
|
|
38099
38208
|
}
|
|
38100
38209
|
async function runConfigCheckDrift(opts = {}) {
|
|
38101
38210
|
const cwd = opts.cwd ?? process.cwd();
|
|
38102
|
-
const configPath =
|
|
38211
|
+
const configPath = resolve44(cwd, "massu.config.yaml");
|
|
38103
38212
|
const log = opts.silent ? () => {
|
|
38104
38213
|
} : (s) => process.stdout.write(s);
|
|
38105
38214
|
const err = opts.silent ? () => {
|
|
38106
38215
|
} : (s) => process.stderr.write(s);
|
|
38107
|
-
if (!
|
|
38216
|
+
if (!existsSync70(configPath)) {
|
|
38108
38217
|
const message = "massu.config.yaml not found. Run: npx massu init";
|
|
38109
38218
|
err(message + "\n");
|
|
38110
38219
|
return {
|
|
@@ -38186,13 +38295,220 @@ var init_config_check_drift = __esm({
|
|
|
38186
38295
|
|
|
38187
38296
|
// src/cli.ts
|
|
38188
38297
|
import { readFileSync as readFileSync61 } from "fs";
|
|
38189
|
-
import { resolve as
|
|
38298
|
+
import { resolve as resolve45, dirname as dirname29 } from "path";
|
|
38190
38299
|
import { fileURLToPath as fileURLToPath7 } from "url";
|
|
38300
|
+
|
|
38301
|
+
// src/lib/node-bootstrap.ts
|
|
38302
|
+
init_node_floor();
|
|
38303
|
+
import { existsSync, readdirSync, statSync, realpathSync } from "fs";
|
|
38304
|
+
import { spawnSync, execFileSync } from "child_process";
|
|
38305
|
+
import { homedir } from "os";
|
|
38306
|
+
import { isAbsolute, resolve, win32 as pathWin32 } from "path";
|
|
38307
|
+
var REEXEC_SENTINEL_ENV = "MASSU_BOOTSTRAP_REEXEC";
|
|
38308
|
+
var OPT_OUT_ENV = "MASSU_NO_NODE_BOOTSTRAP";
|
|
38309
|
+
function allowlistPatterns(env, platform = process.platform) {
|
|
38310
|
+
if (platform === "win32") return windowsAllowlistPatterns(env);
|
|
38311
|
+
const patterns = [];
|
|
38312
|
+
const rawHome = env.HOME || homedir();
|
|
38313
|
+
const home = rawHome && isAbsolute(rawHome) ? rawHome : null;
|
|
38314
|
+
const addAbs = (dir, suffix) => {
|
|
38315
|
+
if (dir && isAbsolute(dir)) patterns.push(resolve(dir, suffix));
|
|
38316
|
+
};
|
|
38317
|
+
addAbs(env.NVM_DIR ?? (home && resolve(home, ".nvm")), "versions/node/*/bin/node");
|
|
38318
|
+
addAbs(env.FNM_DIR ?? (home && resolve(home, ".local/share/fnm")), "node-versions/*/installation/bin/node");
|
|
38319
|
+
addAbs(env.VOLTA_HOME ?? (home && resolve(home, ".volta")), "tools/image/node/*/bin/node");
|
|
38320
|
+
addAbs(env.ASDF_DATA_DIR ?? (home && resolve(home, ".asdf")), "installs/nodejs/*/bin/node");
|
|
38321
|
+
addAbs(env.N_PREFIX ?? (home && resolve(home, "n")), "bin/node");
|
|
38322
|
+
patterns.push(
|
|
38323
|
+
"/opt/homebrew/opt/node@*/bin/node",
|
|
38324
|
+
"/usr/local/opt/node@*/bin/node",
|
|
38325
|
+
"/opt/homebrew/bin/node",
|
|
38326
|
+
"/usr/local/bin/node"
|
|
38327
|
+
);
|
|
38328
|
+
return patterns;
|
|
38329
|
+
}
|
|
38330
|
+
function winManagerDirs(env) {
|
|
38331
|
+
const abs = (d2) => d2 && pathWin32.isAbsolute(d2) ? d2 : null;
|
|
38332
|
+
const appdata = abs(env.APPDATA);
|
|
38333
|
+
const localappdata = abs(env.LOCALAPPDATA);
|
|
38334
|
+
return {
|
|
38335
|
+
userprofile: abs(env.USERPROFILE),
|
|
38336
|
+
nvmHome: abs(env.NVM_HOME),
|
|
38337
|
+
nvmSymlink: abs(env.NVM_SYMLINK),
|
|
38338
|
+
fnmDir: abs(env.FNM_DIR) ?? (appdata ? `${appdata}\\fnm` : null),
|
|
38339
|
+
voltaHome: abs(env.VOLTA_HOME) ?? (localappdata ? `${localappdata}\\Volta` : null),
|
|
38340
|
+
localappdata
|
|
38341
|
+
};
|
|
38342
|
+
}
|
|
38343
|
+
function windowsAllowlistRoots(env) {
|
|
38344
|
+
const d2 = winManagerDirs(env);
|
|
38345
|
+
const roots = [];
|
|
38346
|
+
for (const r2 of [d2.userprofile, d2.nvmHome, d2.nvmSymlink, d2.fnmDir, d2.voltaHome, d2.localappdata]) {
|
|
38347
|
+
if (r2) roots.push(r2);
|
|
38348
|
+
}
|
|
38349
|
+
roots.push("C:\\Program Files\\nodejs", "C:\\Program Files (x86)\\nodejs");
|
|
38350
|
+
return roots;
|
|
38351
|
+
}
|
|
38352
|
+
function windowsAllowlistPatterns(env) {
|
|
38353
|
+
const d2 = winManagerDirs(env);
|
|
38354
|
+
const patterns = [];
|
|
38355
|
+
const add = (dir, suffix) => {
|
|
38356
|
+
if (dir) patterns.push(`${dir}\\${suffix}`);
|
|
38357
|
+
};
|
|
38358
|
+
add(d2.nvmHome, "v*\\node.exe");
|
|
38359
|
+
add(d2.nvmSymlink, "node.exe");
|
|
38360
|
+
add(d2.fnmDir, "node-versions\\v*\\installation\\node.exe");
|
|
38361
|
+
add(d2.voltaHome, "tools\\image\\node\\*\\node.exe");
|
|
38362
|
+
add(d2.userprofile, "scoop\\apps\\nodejs\\current\\node.exe");
|
|
38363
|
+
add(d2.userprofile, "scoop\\apps\\nodejs-lts\\current\\node.exe");
|
|
38364
|
+
add(d2.localappdata, "Programs\\nodejs\\node.exe");
|
|
38365
|
+
patterns.push("C:\\Program Files\\nodejs\\node.exe", "C:\\Program Files (x86)\\nodejs\\node.exe");
|
|
38366
|
+
return patterns;
|
|
38367
|
+
}
|
|
38368
|
+
function isOwnershipTrusted(candidate) {
|
|
38369
|
+
const getuid = process.getuid;
|
|
38370
|
+
if (typeof getuid !== "function") return true;
|
|
38371
|
+
try {
|
|
38372
|
+
const uid = statSync(candidate).uid;
|
|
38373
|
+
return uid === 0 || uid === getuid.call(process);
|
|
38374
|
+
} catch {
|
|
38375
|
+
return false;
|
|
38376
|
+
}
|
|
38377
|
+
}
|
|
38378
|
+
function isWindowsTrusted(candidate, env) {
|
|
38379
|
+
let resolved;
|
|
38380
|
+
try {
|
|
38381
|
+
resolved = pathWin32.resolve(realpathSync(candidate));
|
|
38382
|
+
} catch {
|
|
38383
|
+
resolved = pathWin32.resolve(candidate);
|
|
38384
|
+
}
|
|
38385
|
+
const target = resolved.toLowerCase();
|
|
38386
|
+
for (const root of windowsAllowlistRoots(env)) {
|
|
38387
|
+
const base = pathWin32.resolve(root).toLowerCase();
|
|
38388
|
+
if (target === base || target.startsWith(base + pathWin32.sep)) return true;
|
|
38389
|
+
}
|
|
38390
|
+
return false;
|
|
38391
|
+
}
|
|
38392
|
+
function expandSingleStarGlob(pattern) {
|
|
38393
|
+
const parts = pattern.split(/[\\/]/);
|
|
38394
|
+
const starIdx = parts.findIndex((p19) => p19.includes("*"));
|
|
38395
|
+
if (starIdx === -1) {
|
|
38396
|
+
return existsSync(pattern) ? [pattern] : [];
|
|
38397
|
+
}
|
|
38398
|
+
const parentDir = parts.slice(0, starIdx).join("/") || "/";
|
|
38399
|
+
const seg = parts[starIdx];
|
|
38400
|
+
const rest = parts.slice(starIdx + 1).join("/");
|
|
38401
|
+
const [pre, post] = seg.split("*");
|
|
38402
|
+
let entries;
|
|
38403
|
+
try {
|
|
38404
|
+
entries = readdirSync(parentDir);
|
|
38405
|
+
} catch {
|
|
38406
|
+
return [];
|
|
38407
|
+
}
|
|
38408
|
+
const out = [];
|
|
38409
|
+
for (const e2 of entries) {
|
|
38410
|
+
if (!e2.startsWith(pre) || !e2.endsWith(post ?? "")) continue;
|
|
38411
|
+
out.push(rest ? `${parentDir}/${e2}/${rest}` : `${parentDir}/${e2}`);
|
|
38412
|
+
}
|
|
38413
|
+
return out;
|
|
38414
|
+
}
|
|
38415
|
+
function probeNodeVersion(candidate) {
|
|
38416
|
+
try {
|
|
38417
|
+
const out = execFileSync(candidate, ["-p", "process.versions.node"], {
|
|
38418
|
+
encoding: "utf8",
|
|
38419
|
+
timeout: 5e3
|
|
38420
|
+
});
|
|
38421
|
+
const v3 = out.trim();
|
|
38422
|
+
return /^\d+\.\d+\.\d+/.test(v3) ? v3 : null;
|
|
38423
|
+
} catch {
|
|
38424
|
+
return null;
|
|
38425
|
+
}
|
|
38426
|
+
}
|
|
38427
|
+
function isAcceptedCandidatePath(candidate, platform = process.platform) {
|
|
38428
|
+
if (platform === "win32") {
|
|
38429
|
+
return pathWin32.isAbsolute(candidate) && (/^[A-Za-z]:[\\/]/.test(candidate) || candidate.startsWith("\\\\"));
|
|
38430
|
+
}
|
|
38431
|
+
return candidate.startsWith("/");
|
|
38432
|
+
}
|
|
38433
|
+
function discoverCompatibleNode(env = process.env, platform = process.platform) {
|
|
38434
|
+
const seen = /* @__PURE__ */ new Set();
|
|
38435
|
+
let best = null;
|
|
38436
|
+
for (const pattern of allowlistPatterns(env, platform)) {
|
|
38437
|
+
for (const candidate of expandSingleStarGlob(pattern)) {
|
|
38438
|
+
if (!isAcceptedCandidatePath(candidate, platform)) continue;
|
|
38439
|
+
if (seen.has(candidate)) continue;
|
|
38440
|
+
seen.add(candidate);
|
|
38441
|
+
if (!existsSync(candidate)) continue;
|
|
38442
|
+
const trusted = platform === "win32" ? isWindowsTrusted(candidate, env) : isOwnershipTrusted(candidate);
|
|
38443
|
+
if (!trusted) continue;
|
|
38444
|
+
const v3 = probeNodeVersion(candidate);
|
|
38445
|
+
if (!v3) continue;
|
|
38446
|
+
if (!checkNodeVersion(`v${v3}`).ok) continue;
|
|
38447
|
+
const [major, minor, patch] = v3.split(".").map((n) => Number.parseInt(n, 10));
|
|
38448
|
+
const lower = best === null || major < best.major || major === best.major && minor < best.minor || major === best.major && minor === best.minor && patch < best.patch;
|
|
38449
|
+
if (lower) best = { path: candidate, major, minor, patch };
|
|
38450
|
+
}
|
|
38451
|
+
}
|
|
38452
|
+
return best?.path ?? null;
|
|
38453
|
+
}
|
|
38454
|
+
function reexecUnder(nodePath, selfEntry, argv, env) {
|
|
38455
|
+
const result = spawnSync(nodePath, [selfEntry, ...argv], {
|
|
38456
|
+
stdio: "inherit",
|
|
38457
|
+
env: { ...env, [REEXEC_SENTINEL_ENV]: "1" }
|
|
38458
|
+
});
|
|
38459
|
+
return result.status ?? 1;
|
|
38460
|
+
}
|
|
38461
|
+
function writeLoudRemedy(floorMessage, stderr) {
|
|
38462
|
+
const floor = `${MIN_NODE_MAJOR}.${MIN_NODE_MINOR}.0`;
|
|
38463
|
+
const installLine = process.platform === "win32" ? ` winget install OpenJS.NodeJS # or download Node >= ${floor} from https://nodejs.org` : ` nvm install ${MIN_NODE_MAJOR} # or: brew install node@${MIN_NODE_MAJOR}`;
|
|
38464
|
+
stderr(
|
|
38465
|
+
`
|
|
38466
|
+
massu: ${floorMessage}
|
|
38467
|
+
No compatible Node was found on this machine, so massu will not launch under a Node it cannot run on (that would crash your hooks silently).
|
|
38468
|
+
Fix it once: install Node >= ${floor}, e.g.
|
|
38469
|
+
${installLine}
|
|
38470
|
+
then re-run. (Set ${OPT_OUT_ENV}=1 to skip auto-discovery if you pin your own Node.)
|
|
38471
|
+
|
|
38472
|
+
`
|
|
38473
|
+
);
|
|
38474
|
+
}
|
|
38475
|
+
function bootstrapNodeOrExit(argv, env = process.env, deps = {}) {
|
|
38476
|
+
const nodeVersion = deps.nodeVersion ?? process.version;
|
|
38477
|
+
const stderr = deps.stderr ?? ((m3) => void process.stderr.write(m3));
|
|
38478
|
+
const exit = deps.exit ?? ((c2) => process.exit(c2));
|
|
38479
|
+
const check = checkNodeVersion(nodeVersion);
|
|
38480
|
+
if (env[REEXEC_SENTINEL_ENV] === "1") {
|
|
38481
|
+
if (check.ok) return;
|
|
38482
|
+
writeLoudRemedy(check.message ?? "", stderr);
|
|
38483
|
+
exit(1);
|
|
38484
|
+
return;
|
|
38485
|
+
}
|
|
38486
|
+
if (check.ok) return;
|
|
38487
|
+
if (env[OPT_OUT_ENV] === "1") {
|
|
38488
|
+
writeLoudRemedy(check.message ?? "", stderr);
|
|
38489
|
+
exit(1);
|
|
38490
|
+
return;
|
|
38491
|
+
}
|
|
38492
|
+
const discover = deps.discover ?? discoverCompatibleNode;
|
|
38493
|
+
const nodePath = discover(env);
|
|
38494
|
+
if (!nodePath) {
|
|
38495
|
+
writeLoudRemedy(check.message ?? "", stderr);
|
|
38496
|
+
exit(1);
|
|
38497
|
+
return;
|
|
38498
|
+
}
|
|
38499
|
+
const selfEntry = deps.selfEntry ?? process.argv[1];
|
|
38500
|
+
const reexec = deps.reexec ?? reexecUnder;
|
|
38501
|
+
const status = reexec(nodePath, selfEntry, argv, env);
|
|
38502
|
+
exit(status);
|
|
38503
|
+
}
|
|
38504
|
+
|
|
38505
|
+
// src/cli.ts
|
|
38191
38506
|
var __filename5 = fileURLToPath7(import.meta.url);
|
|
38192
38507
|
var __dirname6 = dirname29(__filename5);
|
|
38193
38508
|
var args = process.argv.slice(2);
|
|
38194
38509
|
var subcommand = args[0];
|
|
38195
38510
|
async function main() {
|
|
38511
|
+
bootstrapNodeOrExit(process.argv.slice(2));
|
|
38196
38512
|
switch (subcommand) {
|
|
38197
38513
|
case "init": {
|
|
38198
38514
|
const { runInit: runInit2 } = await Promise.resolve().then(() => (init_init(), init_exports));
|
|
@@ -38481,7 +38797,7 @@ Examples:
|
|
|
38481
38797
|
}
|
|
38482
38798
|
function printVersion() {
|
|
38483
38799
|
try {
|
|
38484
|
-
const pkg = JSON.parse(readFileSync61(
|
|
38800
|
+
const pkg = JSON.parse(readFileSync61(resolve45(__dirname6, "../package.json"), "utf-8"));
|
|
38485
38801
|
console.log(`massu v${pkg.version}`);
|
|
38486
38802
|
} catch {
|
|
38487
38803
|
console.log("massu v0.1.0");
|