@massu/core 1.9.2 → 1.9.5
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/dist/cli.js +473 -261
- package/dist/hooks/classify-failure.js +8 -1
- package/dist/hooks/cost-tracker.js +8 -1
- package/dist/hooks/fix-detector.js +3 -3
- package/dist/hooks/incident-pipeline.js +8 -1
- package/dist/hooks/post-edit-context.js +8 -1
- package/dist/hooks/post-tool-use.js +8 -1
- package/dist/hooks/pre-compact.js +8 -1
- package/dist/hooks/pre-delete-check.js +8 -1
- package/dist/hooks/quality-event.js +8 -1
- package/dist/hooks/session-end.js +8 -1
- package/dist/hooks/session-start.js +8 -1
- package/dist/hooks/user-prompt.js +8 -1
- package/package.json +2 -2
- package/src/backfill-sessions.ts +3 -2
- package/src/cli.ts +10 -0
- package/src/commands/hook-runner.ts +145 -0
- package/src/commands/init.ts +223 -29
- package/src/config.ts +2 -1
- package/src/hooks/fix-detector.ts +3 -3
- package/src/lib/memory-path.ts +49 -0
- package/src/license.ts +5 -2
- package/src/security/registry-pubkey.generated.ts +1 -1
- package/src/tools.ts +1 -1
package/dist/cli.js
CHANGED
|
@@ -39,6 +39,16 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
39
39
|
mod
|
|
40
40
|
));
|
|
41
41
|
|
|
42
|
+
// src/lib/memory-path.ts
|
|
43
|
+
function encodeMemoryDirName(projectRoot) {
|
|
44
|
+
return projectRoot.replace(/\//g, "-");
|
|
45
|
+
}
|
|
46
|
+
var init_memory_path = __esm({
|
|
47
|
+
"src/lib/memory-path.ts"() {
|
|
48
|
+
"use strict";
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
|
|
42
52
|
// src/config.ts
|
|
43
53
|
import { resolve, dirname } from "path";
|
|
44
54
|
import { existsSync, readFileSync } from "fs";
|
|
@@ -193,7 +203,7 @@ function getResolvedPaths() {
|
|
|
193
203
|
plansDir: resolve(root, "docs/plans"),
|
|
194
204
|
docsDir: resolve(root, "docs"),
|
|
195
205
|
claudeDir: resolve(root, claudeDirName),
|
|
196
|
-
memoryDir: resolve(homedir(), claudeDirName, "projects", root
|
|
206
|
+
memoryDir: resolve(homedir(), claudeDirName, "projects", encodeMemoryDirName(root), "memory"),
|
|
197
207
|
sessionStatePath: resolve(root, config.conventions?.sessionStatePath ?? `${claudeDirName}/session-state/CURRENT.md`),
|
|
198
208
|
sessionArchivePath: resolve(root, config.conventions?.sessionArchivePath ?? `${claudeDirName}/session-state/archive`),
|
|
199
209
|
mcpJsonPath: resolve(root, ".mcp.json"),
|
|
@@ -208,6 +218,7 @@ var DomainConfigSchema, PatternRuleConfigSchema, CostModelSchema, AnalyticsConfi
|
|
|
208
218
|
var init_config = __esm({
|
|
209
219
|
"src/config.ts"() {
|
|
210
220
|
"use strict";
|
|
221
|
+
init_memory_path();
|
|
211
222
|
DomainConfigSchema = z.object({
|
|
212
223
|
name: z.string().default("Unknown"),
|
|
213
224
|
routers: z.array(z.string()).default([]),
|
|
@@ -8045,41 +8056,41 @@ var require_queue = __commonJS({
|
|
|
8045
8056
|
queue.drained = drained;
|
|
8046
8057
|
return queue;
|
|
8047
8058
|
function push(value) {
|
|
8048
|
-
var p19 = new Promise(function(
|
|
8059
|
+
var p19 = new Promise(function(resolve41, reject) {
|
|
8049
8060
|
pushCb(value, function(err, result) {
|
|
8050
8061
|
if (err) {
|
|
8051
8062
|
reject(err);
|
|
8052
8063
|
return;
|
|
8053
8064
|
}
|
|
8054
|
-
|
|
8065
|
+
resolve41(result);
|
|
8055
8066
|
});
|
|
8056
8067
|
});
|
|
8057
8068
|
p19.catch(noop);
|
|
8058
8069
|
return p19;
|
|
8059
8070
|
}
|
|
8060
8071
|
function unshift(value) {
|
|
8061
|
-
var p19 = new Promise(function(
|
|
8072
|
+
var p19 = new Promise(function(resolve41, reject) {
|
|
8062
8073
|
unshiftCb(value, function(err, result) {
|
|
8063
8074
|
if (err) {
|
|
8064
8075
|
reject(err);
|
|
8065
8076
|
return;
|
|
8066
8077
|
}
|
|
8067
|
-
|
|
8078
|
+
resolve41(result);
|
|
8068
8079
|
});
|
|
8069
8080
|
});
|
|
8070
8081
|
p19.catch(noop);
|
|
8071
8082
|
return p19;
|
|
8072
8083
|
}
|
|
8073
8084
|
function drained() {
|
|
8074
|
-
var p19 = new Promise(function(
|
|
8085
|
+
var p19 = new Promise(function(resolve41) {
|
|
8075
8086
|
process.nextTick(function() {
|
|
8076
8087
|
if (queue.idle()) {
|
|
8077
|
-
|
|
8088
|
+
resolve41();
|
|
8078
8089
|
} else {
|
|
8079
8090
|
var previousDrain = queue.drain;
|
|
8080
8091
|
queue.drain = function() {
|
|
8081
8092
|
if (typeof previousDrain === "function") previousDrain();
|
|
8082
|
-
|
|
8093
|
+
resolve41();
|
|
8083
8094
|
queue.drain = previousDrain;
|
|
8084
8095
|
};
|
|
8085
8096
|
}
|
|
@@ -8565,9 +8576,9 @@ var require_stream3 = __commonJS({
|
|
|
8565
8576
|
});
|
|
8566
8577
|
}
|
|
8567
8578
|
_getStat(filepath) {
|
|
8568
|
-
return new Promise((
|
|
8579
|
+
return new Promise((resolve41, reject) => {
|
|
8569
8580
|
this._stat(filepath, this._fsStatSettings, (error, stats) => {
|
|
8570
|
-
return error === null ?
|
|
8581
|
+
return error === null ? resolve41(stats) : reject(error);
|
|
8571
8582
|
});
|
|
8572
8583
|
});
|
|
8573
8584
|
}
|
|
@@ -8591,10 +8602,10 @@ var require_async5 = __commonJS({
|
|
|
8591
8602
|
this._readerStream = new stream_1.default(this._settings);
|
|
8592
8603
|
}
|
|
8593
8604
|
dynamic(root, options) {
|
|
8594
|
-
return new Promise((
|
|
8605
|
+
return new Promise((resolve41, reject) => {
|
|
8595
8606
|
this._walkAsync(root, options, (error, entries) => {
|
|
8596
8607
|
if (error === null) {
|
|
8597
|
-
|
|
8608
|
+
resolve41(entries);
|
|
8598
8609
|
} else {
|
|
8599
8610
|
reject(error);
|
|
8600
8611
|
}
|
|
@@ -8604,10 +8615,10 @@ var require_async5 = __commonJS({
|
|
|
8604
8615
|
async static(patterns, options) {
|
|
8605
8616
|
const entries = [];
|
|
8606
8617
|
const stream = this._readerStream.static(patterns, options);
|
|
8607
|
-
return new Promise((
|
|
8618
|
+
return new Promise((resolve41, reject) => {
|
|
8608
8619
|
stream.once("error", reject);
|
|
8609
8620
|
stream.on("data", (entry) => entries.push(entry));
|
|
8610
|
-
stream.once("end", () =>
|
|
8621
|
+
stream.once("end", () => resolve41(entries));
|
|
8611
8622
|
});
|
|
8612
8623
|
}
|
|
8613
8624
|
};
|
|
@@ -12982,10 +12993,12 @@ __export(init_exports, {
|
|
|
12982
12993
|
detectFramework: () => detectFramework,
|
|
12983
12994
|
detectPython: () => detectPython,
|
|
12984
12995
|
generateConfig: () => generateConfig,
|
|
12996
|
+
getInstallerVersion: () => getInstallerVersion,
|
|
12985
12997
|
initMemoryDir: () => initMemoryDir,
|
|
12986
12998
|
installHooks: () => installHooks,
|
|
12987
12999
|
isTemplateName: () => isTemplateName,
|
|
12988
13000
|
listTemplates: () => listTemplates,
|
|
13001
|
+
mergeHooksConfig: () => mergeHooksConfig,
|
|
12989
13002
|
parseInitArgs: () => parseInitArgs,
|
|
12990
13003
|
printInitHelp: () => printInitHelp,
|
|
12991
13004
|
registerMcpServer: () => registerMcpServer,
|
|
@@ -13529,6 +13542,26 @@ function copyTemplateConfig(templateName, targetPath, projectName) {
|
|
|
13529
13542
|
return { success: false, error: err instanceof Error ? err.message : String(err) };
|
|
13530
13543
|
}
|
|
13531
13544
|
}
|
|
13545
|
+
function getInstallerVersion() {
|
|
13546
|
+
const candidates = [
|
|
13547
|
+
resolve7(__dirname2, "../package.json"),
|
|
13548
|
+
resolve7(__dirname2, "../../package.json")
|
|
13549
|
+
];
|
|
13550
|
+
for (const candidate of candidates) {
|
|
13551
|
+
if (existsSync11(candidate)) {
|
|
13552
|
+
try {
|
|
13553
|
+
const pkg = JSON.parse(readFileSync11(candidate, "utf-8"));
|
|
13554
|
+
if (typeof pkg.version === "string" && pkg.version.length > 0 && pkg.name === "@massu/core") {
|
|
13555
|
+
return pkg.version;
|
|
13556
|
+
}
|
|
13557
|
+
} catch {
|
|
13558
|
+
}
|
|
13559
|
+
}
|
|
13560
|
+
}
|
|
13561
|
+
throw new Error(
|
|
13562
|
+
"getInstallerVersion: could not resolve @massu/core package.json. This indicates a corrupt install. Re-install via `npx -y @massu/core init`."
|
|
13563
|
+
);
|
|
13564
|
+
}
|
|
13532
13565
|
function registerMcpServer(projectRoot) {
|
|
13533
13566
|
const mcpPath = resolve7(projectRoot, ".mcp.json");
|
|
13534
13567
|
let existing = {};
|
|
@@ -13543,10 +13576,11 @@ function registerMcpServer(projectRoot) {
|
|
|
13543
13576
|
if (servers.massu) {
|
|
13544
13577
|
return false;
|
|
13545
13578
|
}
|
|
13579
|
+
const version = getInstallerVersion();
|
|
13546
13580
|
servers.massu = {
|
|
13547
13581
|
type: "stdio",
|
|
13548
13582
|
command: "npx",
|
|
13549
|
-
args: ["-y",
|
|
13583
|
+
args: ["-y", `@massu/core@${version}`]
|
|
13550
13584
|
};
|
|
13551
13585
|
existing.mcpServers = servers;
|
|
13552
13586
|
writeFileSync2(mcpPath, JSON.stringify(existing, null, 2) + "\n", "utf-8");
|
|
@@ -13564,15 +13598,16 @@ function resolveHooksDir() {
|
|
|
13564
13598
|
}
|
|
13565
13599
|
return "node_modules/@massu/core/dist/hooks";
|
|
13566
13600
|
}
|
|
13567
|
-
function hookCmd(
|
|
13568
|
-
return `
|
|
13601
|
+
function hookCmd(version, hookName) {
|
|
13602
|
+
return `npx -y @massu/core@${version} hook-runner ${hookName}`;
|
|
13569
13603
|
}
|
|
13570
|
-
function buildHooksConfig(
|
|
13604
|
+
function buildHooksConfig(_hooksDir) {
|
|
13605
|
+
const version = getInstallerVersion();
|
|
13571
13606
|
return {
|
|
13572
13607
|
SessionStart: [
|
|
13573
13608
|
{
|
|
13574
13609
|
hooks: [
|
|
13575
|
-
{ type: "command", command: hookCmd(
|
|
13610
|
+
{ type: "command", command: hookCmd(version, "session-start"), timeout: 10 }
|
|
13576
13611
|
]
|
|
13577
13612
|
}
|
|
13578
13613
|
],
|
|
@@ -13580,32 +13615,32 @@ function buildHooksConfig(hooksDir) {
|
|
|
13580
13615
|
{
|
|
13581
13616
|
matcher: "Bash",
|
|
13582
13617
|
hooks: [
|
|
13583
|
-
{ type: "command", command: hookCmd(
|
|
13618
|
+
{ type: "command", command: hookCmd(version, "security-gate"), timeout: 5 }
|
|
13584
13619
|
]
|
|
13585
13620
|
},
|
|
13586
13621
|
{
|
|
13587
13622
|
matcher: "Bash|Write",
|
|
13588
13623
|
hooks: [
|
|
13589
|
-
{ type: "command", command: hookCmd(
|
|
13624
|
+
{ type: "command", command: hookCmd(version, "pre-delete-check"), timeout: 5 }
|
|
13590
13625
|
]
|
|
13591
13626
|
}
|
|
13592
13627
|
],
|
|
13593
13628
|
PostToolUse: [
|
|
13594
13629
|
{
|
|
13595
13630
|
hooks: [
|
|
13596
|
-
{ type: "command", command: hookCmd(
|
|
13597
|
-
{ type: "command", command: hookCmd(
|
|
13598
|
-
{ type: "command", command: hookCmd(
|
|
13631
|
+
{ type: "command", command: hookCmd(version, "post-tool-use"), timeout: 10 },
|
|
13632
|
+
{ type: "command", command: hookCmd(version, "quality-event"), timeout: 5 },
|
|
13633
|
+
{ type: "command", command: hookCmd(version, "cost-tracker"), timeout: 5 }
|
|
13599
13634
|
]
|
|
13600
13635
|
},
|
|
13601
13636
|
{
|
|
13602
13637
|
matcher: "Edit|Write",
|
|
13603
13638
|
hooks: [
|
|
13604
|
-
{ type: "command", command: hookCmd(
|
|
13639
|
+
{ type: "command", command: hookCmd(version, "post-edit-context"), timeout: 5 },
|
|
13605
13640
|
// Auto-learning pipeline — classifies failures and detects fixes on
|
|
13606
13641
|
// file changes. See Phase 5-6 of the autodetect plan.
|
|
13607
|
-
{ type: "command", command: hookCmd(
|
|
13608
|
-
{ type: "command", command: hookCmd(
|
|
13642
|
+
{ type: "command", command: hookCmd(version, "fix-detector"), timeout: 5 },
|
|
13643
|
+
{ type: "command", command: hookCmd(version, "classify-failure"), timeout: 5 }
|
|
13609
13644
|
]
|
|
13610
13645
|
},
|
|
13611
13646
|
{
|
|
@@ -13613,37 +13648,86 @@ function buildHooksConfig(hooksDir) {
|
|
|
13613
13648
|
hooks: [
|
|
13614
13649
|
// Incident + rule enforcement pipelines fire on Write-only (incidents
|
|
13615
13650
|
// are authored as .md files; rules are enforced after new-file drops).
|
|
13616
|
-
{ type: "command", command: hookCmd(
|
|
13617
|
-
{ type: "command", command: hookCmd(
|
|
13651
|
+
{ type: "command", command: hookCmd(version, "incident-pipeline"), timeout: 5 },
|
|
13652
|
+
{ type: "command", command: hookCmd(version, "rule-enforcement-pipeline"), timeout: 5 }
|
|
13618
13653
|
]
|
|
13619
13654
|
}
|
|
13620
13655
|
],
|
|
13621
13656
|
Stop: [
|
|
13622
13657
|
{
|
|
13623
13658
|
hooks: [
|
|
13624
|
-
{ type: "command", command: hookCmd(
|
|
13659
|
+
{ type: "command", command: hookCmd(version, "session-end"), timeout: 15 },
|
|
13625
13660
|
// Session-end auto-learning aggregation (failure-class roll-up).
|
|
13626
|
-
{ type: "command", command: hookCmd(
|
|
13661
|
+
{ type: "command", command: hookCmd(version, "auto-learning-pipeline"), timeout: 10 }
|
|
13627
13662
|
]
|
|
13628
13663
|
}
|
|
13629
13664
|
],
|
|
13630
13665
|
PreCompact: [
|
|
13631
13666
|
{
|
|
13632
13667
|
hooks: [
|
|
13633
|
-
{ type: "command", command: hookCmd(
|
|
13668
|
+
{ type: "command", command: hookCmd(version, "pre-compact"), timeout: 10 }
|
|
13634
13669
|
]
|
|
13635
13670
|
}
|
|
13636
13671
|
],
|
|
13637
13672
|
UserPromptSubmit: [
|
|
13638
13673
|
{
|
|
13639
13674
|
hooks: [
|
|
13640
|
-
{ type: "command", command: hookCmd(
|
|
13641
|
-
{ type: "command", command: hookCmd(
|
|
13675
|
+
{ type: "command", command: hookCmd(version, "user-prompt"), timeout: 5 },
|
|
13676
|
+
{ type: "command", command: hookCmd(version, "intent-suggester"), timeout: 5 }
|
|
13642
13677
|
]
|
|
13643
13678
|
}
|
|
13644
13679
|
]
|
|
13645
13680
|
};
|
|
13646
13681
|
}
|
|
13682
|
+
function mergeHooksConfig(existing, additions) {
|
|
13683
|
+
const eventNames = /* @__PURE__ */ new Set([
|
|
13684
|
+
...Object.keys(existing ?? {}),
|
|
13685
|
+
...Object.keys(additions ?? {})
|
|
13686
|
+
]);
|
|
13687
|
+
const merged = {};
|
|
13688
|
+
for (const event of eventNames) {
|
|
13689
|
+
const existingGroups = existing?.[event] ?? [];
|
|
13690
|
+
const additionGroups = additions?.[event] ?? [];
|
|
13691
|
+
const byMatcher = /* @__PURE__ */ new Map();
|
|
13692
|
+
for (const group of existingGroups) {
|
|
13693
|
+
const key = group.matcher ?? "";
|
|
13694
|
+
const existingGroup = byMatcher.get(key);
|
|
13695
|
+
if (existingGroup) {
|
|
13696
|
+
existingGroup.hooks = mergeHookEntries(existingGroup.hooks, group.hooks);
|
|
13697
|
+
} else {
|
|
13698
|
+
byMatcher.set(key, { ...group, hooks: [...group.hooks ?? []] });
|
|
13699
|
+
}
|
|
13700
|
+
}
|
|
13701
|
+
for (const group of additionGroups) {
|
|
13702
|
+
const key = group.matcher ?? "";
|
|
13703
|
+
const existingGroup = byMatcher.get(key);
|
|
13704
|
+
if (existingGroup) {
|
|
13705
|
+
existingGroup.hooks = mergeHookEntries(existingGroup.hooks, group.hooks);
|
|
13706
|
+
} else {
|
|
13707
|
+
byMatcher.set(key, { ...group, hooks: [...group.hooks ?? []] });
|
|
13708
|
+
}
|
|
13709
|
+
}
|
|
13710
|
+
merged[event] = Array.from(byMatcher.values());
|
|
13711
|
+
}
|
|
13712
|
+
return merged;
|
|
13713
|
+
}
|
|
13714
|
+
function mergeHookEntries(existing, additions) {
|
|
13715
|
+
const seen = /* @__PURE__ */ new Set();
|
|
13716
|
+
const result = [];
|
|
13717
|
+
for (const entry of additions ?? []) {
|
|
13718
|
+
if (!entry || typeof entry.command !== "string") continue;
|
|
13719
|
+
if (seen.has(entry.command)) continue;
|
|
13720
|
+
seen.add(entry.command);
|
|
13721
|
+
result.push(entry);
|
|
13722
|
+
}
|
|
13723
|
+
for (const entry of existing ?? []) {
|
|
13724
|
+
if (!entry || typeof entry.command !== "string") continue;
|
|
13725
|
+
if (seen.has(entry.command)) continue;
|
|
13726
|
+
seen.add(entry.command);
|
|
13727
|
+
result.push(entry);
|
|
13728
|
+
}
|
|
13729
|
+
return result;
|
|
13730
|
+
}
|
|
13647
13731
|
function installHooks(projectRoot) {
|
|
13648
13732
|
let claudeDirName = ".claude";
|
|
13649
13733
|
try {
|
|
@@ -13656,21 +13740,39 @@ function installHooks(projectRoot) {
|
|
|
13656
13740
|
mkdirSync5(claudeDir, { recursive: true });
|
|
13657
13741
|
}
|
|
13658
13742
|
const settings = readSettingsLocal(claudeDir);
|
|
13659
|
-
const
|
|
13660
|
-
const
|
|
13743
|
+
const hooksConfig = buildHooksConfig(resolveHooksDir());
|
|
13744
|
+
const existingHooks = settings.hooks ?? {};
|
|
13745
|
+
const mergedHooks = mergeHooksConfig(existingHooks, hooksConfig);
|
|
13661
13746
|
let hookCount = 0;
|
|
13662
|
-
for (const groups of Object.values(
|
|
13747
|
+
for (const groups of Object.values(mergedHooks)) {
|
|
13663
13748
|
for (const group of groups) {
|
|
13664
13749
|
hookCount += group.hooks.length;
|
|
13665
13750
|
}
|
|
13666
13751
|
}
|
|
13667
|
-
settings.hooks =
|
|
13752
|
+
settings.hooks = mergedHooks;
|
|
13668
13753
|
writeSettingsLocalAtomic(claudeDir, settings);
|
|
13669
13754
|
return { installed: true, count: hookCount };
|
|
13670
13755
|
}
|
|
13671
13756
|
function initMemoryDir(projectRoot) {
|
|
13672
|
-
const encodedRoot =
|
|
13757
|
+
const encodedRoot = encodeMemoryDirName(projectRoot);
|
|
13673
13758
|
const memoryDir = resolve7(homedir4(), `.claude/projects/${encodedRoot}/memory`);
|
|
13759
|
+
let migratedFromLegacy = false;
|
|
13760
|
+
const legacyDir = resolve7(homedir4(), `.claude/projects/-${encodedRoot}/memory`);
|
|
13761
|
+
if (existsSync11(legacyDir) && !existsSync11(memoryDir)) {
|
|
13762
|
+
try {
|
|
13763
|
+
mkdirSync5(resolve7(memoryDir, ".."), { recursive: true });
|
|
13764
|
+
renameSync3(legacyDir, memoryDir);
|
|
13765
|
+
try {
|
|
13766
|
+
const legacyParent = resolve7(legacyDir, "..");
|
|
13767
|
+
if (existsSync11(legacyParent) && readdirSync10(legacyParent).length === 0) {
|
|
13768
|
+
rmSync2(legacyParent, { recursive: false });
|
|
13769
|
+
}
|
|
13770
|
+
} catch {
|
|
13771
|
+
}
|
|
13772
|
+
migratedFromLegacy = true;
|
|
13773
|
+
} catch {
|
|
13774
|
+
}
|
|
13775
|
+
}
|
|
13674
13776
|
let created = false;
|
|
13675
13777
|
if (!existsSync11(memoryDir)) {
|
|
13676
13778
|
mkdirSync5(memoryDir, { recursive: true });
|
|
@@ -13697,7 +13799,7 @@ function initMemoryDir(projectRoot) {
|
|
|
13697
13799
|
writeFileSync2(memoryMdPath, memoryContent, "utf-8");
|
|
13698
13800
|
memoryMdCreated = true;
|
|
13699
13801
|
}
|
|
13700
|
-
return { created, memoryMdCreated };
|
|
13802
|
+
return { created, memoryMdCreated, migratedFromLegacy };
|
|
13701
13803
|
}
|
|
13702
13804
|
function parseInitArgs(argv) {
|
|
13703
13805
|
const opts = {};
|
|
@@ -13956,16 +14058,19 @@ function installSideEffects(projectRoot, log, skipCommands = false, emptyStack =
|
|
|
13956
14058
|
} catch {
|
|
13957
14059
|
}
|
|
13958
14060
|
}
|
|
13959
|
-
const { created: memDirCreated, memoryMdCreated } = initMemoryDir(projectRoot);
|
|
14061
|
+
const { created: memDirCreated, memoryMdCreated, migratedFromLegacy } = initMemoryDir(projectRoot);
|
|
13960
14062
|
if (memDirCreated) {
|
|
13961
14063
|
log(" Created memory directory");
|
|
13962
14064
|
}
|
|
13963
14065
|
if (memoryMdCreated) {
|
|
13964
14066
|
log(" Created initial MEMORY.md");
|
|
13965
14067
|
}
|
|
14068
|
+
if (migratedFromLegacy) {
|
|
14069
|
+
log(" Migrated memory directory from legacy double-dash path (pre-1.9.4)");
|
|
14070
|
+
}
|
|
13966
14071
|
(async () => {
|
|
13967
14072
|
try {
|
|
13968
|
-
const encodedRoot = projectRoot
|
|
14073
|
+
const encodedRoot = encodeMemoryDirName(projectRoot);
|
|
13969
14074
|
const memoryDir = resolve7(homedir4(), ".claude", "projects", encodedRoot, "memory");
|
|
13970
14075
|
const memFiles = existsSync11(memoryDir) ? readdirSync10(memoryDir).filter((f2) => f2.endsWith(".md") && f2 !== "MEMORY.md") : [];
|
|
13971
14076
|
if (memFiles.length > 0) {
|
|
@@ -14025,6 +14130,7 @@ var init_init = __esm({
|
|
|
14025
14130
|
init_config();
|
|
14026
14131
|
init_install_commands();
|
|
14027
14132
|
init_settings_local();
|
|
14133
|
+
init_memory_path();
|
|
14028
14134
|
init_detect();
|
|
14029
14135
|
init_drift();
|
|
14030
14136
|
__filename2 = fileURLToPath2(import.meta.url);
|
|
@@ -14069,7 +14175,7 @@ function annotateToolDefinitions(defs) {
|
|
|
14069
14175
|
const label = TIER_LABELS[tier];
|
|
14070
14176
|
return {
|
|
14071
14177
|
...def,
|
|
14072
|
-
tier,
|
|
14178
|
+
annotations: { ...def.annotations ?? {}, tier },
|
|
14073
14179
|
description: label ? `${label}${def.description}` : def.description
|
|
14074
14180
|
};
|
|
14075
14181
|
});
|
|
@@ -14756,13 +14862,113 @@ var init_install_hooks = __esm({
|
|
|
14756
14862
|
}
|
|
14757
14863
|
});
|
|
14758
14864
|
|
|
14865
|
+
// src/commands/hook-runner.ts
|
|
14866
|
+
var hook_runner_exports = {};
|
|
14867
|
+
__export(hook_runner_exports, {
|
|
14868
|
+
HOOK_NAME_TO_FILE: () => HOOK_NAME_TO_FILE,
|
|
14869
|
+
resolveHookFile: () => resolveHookFile,
|
|
14870
|
+
runHookRunner: () => runHookRunner
|
|
14871
|
+
});
|
|
14872
|
+
import { existsSync as existsSync13 } from "fs";
|
|
14873
|
+
import { resolve as resolve9, dirname as dirname8 } from "path";
|
|
14874
|
+
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
14875
|
+
import { spawn } from "child_process";
|
|
14876
|
+
function resolveHookFile(hookName) {
|
|
14877
|
+
const file = HOOK_NAME_TO_FILE[hookName];
|
|
14878
|
+
if (!file) {
|
|
14879
|
+
throw new Error(
|
|
14880
|
+
`Unknown hook: "${hookName}". Recognized: ${Object.keys(HOOK_NAME_TO_FILE).join(", ")}`
|
|
14881
|
+
);
|
|
14882
|
+
}
|
|
14883
|
+
const candidates = [
|
|
14884
|
+
// Bundled compiled layout: dist/cli.js → ./hooks/<file>.js
|
|
14885
|
+
resolve9(__dirname4, "hooks", file),
|
|
14886
|
+
// TS-source dev / sibling layout: src/commands/ → ../hooks/<file>
|
|
14887
|
+
resolve9(__dirname4, "../hooks", file),
|
|
14888
|
+
// TS-source dev fallback: src/commands/ → ../../dist/hooks/<file>
|
|
14889
|
+
resolve9(__dirname4, "../../dist/hooks", file)
|
|
14890
|
+
];
|
|
14891
|
+
for (const candidate of candidates) {
|
|
14892
|
+
if (existsSync13(candidate)) {
|
|
14893
|
+
return candidate;
|
|
14894
|
+
}
|
|
14895
|
+
}
|
|
14896
|
+
throw new Error(
|
|
14897
|
+
`Hook file not found for "${hookName}". Searched: ${candidates.join(", ")}. This indicates a broken @massu/core install. Re-run \`npx -y @massu/core init\`.`
|
|
14898
|
+
);
|
|
14899
|
+
}
|
|
14900
|
+
async function runHookRunner(args2) {
|
|
14901
|
+
const hookName = args2[0];
|
|
14902
|
+
if (!hookName) {
|
|
14903
|
+
process.stderr.write(
|
|
14904
|
+
`massu hook-runner: missing hook name.
|
|
14905
|
+
Usage: massu hook-runner <hook-name>
|
|
14906
|
+
Recognized: ${Object.keys(HOOK_NAME_TO_FILE).join(", ")}
|
|
14907
|
+
`
|
|
14908
|
+
);
|
|
14909
|
+
return { exitCode: 2 };
|
|
14910
|
+
}
|
|
14911
|
+
let hookFile;
|
|
14912
|
+
try {
|
|
14913
|
+
hookFile = resolveHookFile(hookName);
|
|
14914
|
+
} catch (err) {
|
|
14915
|
+
process.stderr.write(`massu hook-runner: ${err instanceof Error ? err.message : String(err)}
|
|
14916
|
+
`);
|
|
14917
|
+
return { exitCode: 2 };
|
|
14918
|
+
}
|
|
14919
|
+
return new Promise((resolvePromise) => {
|
|
14920
|
+
const child = spawn(process.execPath, [hookFile], {
|
|
14921
|
+
stdio: ["inherit", "inherit", "inherit"],
|
|
14922
|
+
env: process.env
|
|
14923
|
+
});
|
|
14924
|
+
child.on("exit", (code, signal) => {
|
|
14925
|
+
if (signal) {
|
|
14926
|
+
resolvePromise({ exitCode: 128 });
|
|
14927
|
+
return;
|
|
14928
|
+
}
|
|
14929
|
+
resolvePromise({ exitCode: code ?? 0 });
|
|
14930
|
+
});
|
|
14931
|
+
child.on("error", (err) => {
|
|
14932
|
+
process.stderr.write(`massu hook-runner: failed to spawn hook "${hookName}": ${err.message}
|
|
14933
|
+
`);
|
|
14934
|
+
resolvePromise({ exitCode: 2 });
|
|
14935
|
+
});
|
|
14936
|
+
});
|
|
14937
|
+
}
|
|
14938
|
+
var __filename4, __dirname4, HOOK_NAME_TO_FILE;
|
|
14939
|
+
var init_hook_runner = __esm({
|
|
14940
|
+
"src/commands/hook-runner.ts"() {
|
|
14941
|
+
"use strict";
|
|
14942
|
+
__filename4 = fileURLToPath4(import.meta.url);
|
|
14943
|
+
__dirname4 = dirname8(__filename4);
|
|
14944
|
+
HOOK_NAME_TO_FILE = {
|
|
14945
|
+
"session-start": "session-start.js",
|
|
14946
|
+
"session-end": "session-end.js",
|
|
14947
|
+
"security-gate": "security-gate.js",
|
|
14948
|
+
"pre-delete-check": "pre-delete-check.js",
|
|
14949
|
+
"post-tool-use": "post-tool-use.js",
|
|
14950
|
+
"post-edit-context": "post-edit-context.js",
|
|
14951
|
+
"quality-event": "quality-event.js",
|
|
14952
|
+
"cost-tracker": "cost-tracker.js",
|
|
14953
|
+
"fix-detector": "fix-detector.js",
|
|
14954
|
+
"classify-failure": "classify-failure.js",
|
|
14955
|
+
"incident-pipeline": "incident-pipeline.js",
|
|
14956
|
+
"rule-enforcement-pipeline": "rule-enforcement-pipeline.js",
|
|
14957
|
+
"auto-learning-pipeline": "auto-learning-pipeline.js",
|
|
14958
|
+
"pre-compact": "pre-compact.js",
|
|
14959
|
+
"user-prompt": "user-prompt.js",
|
|
14960
|
+
"intent-suggester": "intent-suggester.js"
|
|
14961
|
+
};
|
|
14962
|
+
}
|
|
14963
|
+
});
|
|
14964
|
+
|
|
14759
14965
|
// src/commands/permissions.ts
|
|
14760
14966
|
var permissions_exports = {};
|
|
14761
14967
|
__export(permissions_exports, {
|
|
14762
14968
|
handlePermissionsSubcommand: () => handlePermissionsSubcommand,
|
|
14763
14969
|
printPermissionsHelp: () => printPermissionsHelp
|
|
14764
14970
|
});
|
|
14765
|
-
import { resolve as
|
|
14971
|
+
import { resolve as resolve10 } from "path";
|
|
14766
14972
|
function resolveClaudeDir2() {
|
|
14767
14973
|
let claudeDirName = ".claude";
|
|
14768
14974
|
try {
|
|
@@ -14770,7 +14976,7 @@ function resolveClaudeDir2() {
|
|
|
14770
14976
|
} catch {
|
|
14771
14977
|
claudeDirName = ".claude";
|
|
14772
14978
|
}
|
|
14773
|
-
return
|
|
14979
|
+
return resolve10(process.cwd(), claudeDirName);
|
|
14774
14980
|
}
|
|
14775
14981
|
async function handlePermissionsSubcommand(args2) {
|
|
14776
14982
|
const sub = args2[0];
|
|
@@ -14884,8 +15090,8 @@ var init_permissions2 = __esm({
|
|
|
14884
15090
|
});
|
|
14885
15091
|
|
|
14886
15092
|
// src/changelog-generator.ts
|
|
14887
|
-
import { existsSync as
|
|
14888
|
-
import { resolve as
|
|
15093
|
+
import { existsSync as existsSync14, readFileSync as readFileSync13, readdirSync as readdirSync12 } from "fs";
|
|
15094
|
+
import { resolve as resolve11 } from "path";
|
|
14889
15095
|
function parseCommitsForPlanTokens(subjects) {
|
|
14890
15096
|
const tokens = /* @__PURE__ */ new Set();
|
|
14891
15097
|
const maintenance = [];
|
|
@@ -14902,7 +15108,7 @@ function parseCommitsForPlanTokens(subjects) {
|
|
|
14902
15108
|
function loadPlanSummaries(tokens, planDir) {
|
|
14903
15109
|
const result = /* @__PURE__ */ new Map();
|
|
14904
15110
|
if (tokens.size === 0) return result;
|
|
14905
|
-
if (!
|
|
15111
|
+
if (!existsSync14(planDir)) {
|
|
14906
15112
|
throw new Error(`Plan directory does not exist: ${planDir}`);
|
|
14907
15113
|
}
|
|
14908
15114
|
const files = readdirSync12(planDir).filter((f2) => f2.endsWith(".md"));
|
|
@@ -14910,7 +15116,7 @@ function loadPlanSummaries(tokens, planDir) {
|
|
|
14910
15116
|
let matchedFile = null;
|
|
14911
15117
|
let content = "";
|
|
14912
15118
|
for (const file of files) {
|
|
14913
|
-
const path =
|
|
15119
|
+
const path = resolve11(planDir, file);
|
|
14914
15120
|
const text18 = readFileSync13(path, "utf-8");
|
|
14915
15121
|
const tokenRe = new RegExp(
|
|
14916
15122
|
`^\\*\\*Plan Token\\*\\*:\\s*\`?${token.replace(/[.*+?^${}()|[\\]\\\\]/g, "\\$&")}\`?(\\s|$)`,
|
|
@@ -14992,8 +15198,8 @@ __export(changelog_exports, {
|
|
|
14992
15198
|
printChangelogHelp: () => printChangelogHelp
|
|
14993
15199
|
});
|
|
14994
15200
|
import { execSync } from "child_process";
|
|
14995
|
-
import { existsSync as
|
|
14996
|
-
import { resolve as
|
|
15201
|
+
import { existsSync as existsSync15, readFileSync as readFileSync14 } from "fs";
|
|
15202
|
+
import { resolve as resolve12 } from "path";
|
|
14997
15203
|
function resolveRepoRoot() {
|
|
14998
15204
|
try {
|
|
14999
15205
|
return execSync("git rev-parse --show-toplevel", { encoding: "utf-8" }).trim();
|
|
@@ -15017,8 +15223,8 @@ function getCommitSubjects(range) {
|
|
|
15017
15223
|
}
|
|
15018
15224
|
}
|
|
15019
15225
|
function getCurrentVersion(repoRoot) {
|
|
15020
|
-
const pkgPath =
|
|
15021
|
-
if (!
|
|
15226
|
+
const pkgPath = resolve12(repoRoot, "packages/core/package.json");
|
|
15227
|
+
if (!existsSync15(pkgPath)) return "0.0.0";
|
|
15022
15228
|
const pkg = JSON.parse(readFileSync14(pkgPath, "utf-8"));
|
|
15023
15229
|
return pkg.version || "0.0.0";
|
|
15024
15230
|
}
|
|
@@ -15026,8 +15232,8 @@ function todayDate() {
|
|
|
15026
15232
|
return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
15027
15233
|
}
|
|
15028
15234
|
function getLatestChangelogEntryBody(repoRoot) {
|
|
15029
|
-
const path =
|
|
15030
|
-
if (!
|
|
15235
|
+
const path = resolve12(repoRoot, "CHANGELOG.md");
|
|
15236
|
+
if (!existsSync15(path)) return "";
|
|
15031
15237
|
const content = readFileSync14(path, "utf-8");
|
|
15032
15238
|
const m3 = content.match(/^## \[[\d.]+\][^\n]*\n([\s\S]*?)(?=\n## \[|$)/m);
|
|
15033
15239
|
return m3 ? m3[1] : "";
|
|
@@ -15035,7 +15241,7 @@ function getLatestChangelogEntryBody(repoRoot) {
|
|
|
15035
15241
|
async function handleChangelogSubcommand(args2) {
|
|
15036
15242
|
const sub = args2[0];
|
|
15037
15243
|
const repoRoot = resolveRepoRoot();
|
|
15038
|
-
const planDir =
|
|
15244
|
+
const planDir = resolve12(repoRoot, "docs/plans");
|
|
15039
15245
|
switch (sub) {
|
|
15040
15246
|
case "generate": {
|
|
15041
15247
|
const lastTag = getLastTag();
|
|
@@ -15127,8 +15333,8 @@ var show_template_exports = {};
|
|
|
15127
15333
|
__export(show_template_exports, {
|
|
15128
15334
|
runShowTemplate: () => runShowTemplate
|
|
15129
15335
|
});
|
|
15130
|
-
import { existsSync as
|
|
15131
|
-
import { resolve as
|
|
15336
|
+
import { existsSync as existsSync16, readFileSync as readFileSync15 } from "fs";
|
|
15337
|
+
import { resolve as resolve13 } from "path";
|
|
15132
15338
|
function normalizeBaseName(input) {
|
|
15133
15339
|
return input.endsWith(".md") ? input.slice(0, -".md".length) : input;
|
|
15134
15340
|
}
|
|
@@ -15156,8 +15362,8 @@ async function runShowTemplate(args2) {
|
|
|
15156
15362
|
return;
|
|
15157
15363
|
}
|
|
15158
15364
|
const suffix = choice.kind === "hit" ? choice.suffix : "";
|
|
15159
|
-
const file = suffix === "" ?
|
|
15160
|
-
if (!
|
|
15365
|
+
const file = suffix === "" ? resolve13(sourceDir, `${baseName}.md`) : resolve13(sourceDir, `${baseName}${suffix}.md`);
|
|
15366
|
+
if (!existsSync16(file)) {
|
|
15161
15367
|
process.stderr.write(`massu: resolved template "${file}" no longer exists
|
|
15162
15368
|
`);
|
|
15163
15369
|
process.exit(1);
|
|
@@ -15217,7 +15423,7 @@ var init_passthrough = __esm({
|
|
|
15217
15423
|
|
|
15218
15424
|
// src/lib/fileLock.ts
|
|
15219
15425
|
import { mkdirSync as mkdirSync6, readFileSync as readFileSync16, rmSync as rmSync3, writeFileSync as writeFileSync3 } from "fs";
|
|
15220
|
-
import { dirname as
|
|
15426
|
+
import { dirname as dirname9 } from "path";
|
|
15221
15427
|
import * as lockfile from "proper-lockfile";
|
|
15222
15428
|
function readLockHolderPid(lockPath) {
|
|
15223
15429
|
try {
|
|
@@ -15240,7 +15446,7 @@ function busyWaitSync(ms) {
|
|
|
15240
15446
|
Atomics.wait(view, 0, 0, ms);
|
|
15241
15447
|
}
|
|
15242
15448
|
function withFileLockSync(lockPath, fn, opts = {}) {
|
|
15243
|
-
mkdirSync6(
|
|
15449
|
+
mkdirSync6(dirname9(lockPath), { recursive: true });
|
|
15244
15450
|
const staleMs = opts.staleMs ?? 3e4;
|
|
15245
15451
|
const blockMs = opts.retries === 0 ? 0 : opts.blockMs ?? 3e4;
|
|
15246
15452
|
const pollIntervalMs = opts.pollIntervalMs ?? 100;
|
|
@@ -15308,9 +15514,9 @@ var init_fileLock = __esm({
|
|
|
15308
15514
|
});
|
|
15309
15515
|
|
|
15310
15516
|
// src/lib/installLock.ts
|
|
15311
|
-
import { resolve as
|
|
15517
|
+
import { resolve as resolve14 } from "path";
|
|
15312
15518
|
function withInstallLock(projectRoot, fn, opts = {}) {
|
|
15313
|
-
const lockPath =
|
|
15519
|
+
const lockPath = resolve14(projectRoot, ".massu", "installAll.lock");
|
|
15314
15520
|
return withFileLockSync(
|
|
15315
15521
|
lockPath,
|
|
15316
15522
|
fn,
|
|
@@ -15346,8 +15552,8 @@ __export(config_refresh_exports, {
|
|
|
15346
15552
|
mergeRefresh: () => mergeRefresh,
|
|
15347
15553
|
runConfigRefresh: () => runConfigRefresh
|
|
15348
15554
|
});
|
|
15349
|
-
import { existsSync as
|
|
15350
|
-
import { resolve as
|
|
15555
|
+
import { existsSync as existsSync17, readFileSync as readFileSync17, rmSync as rmSync4 } from "fs";
|
|
15556
|
+
import { resolve as resolve15 } from "path";
|
|
15351
15557
|
import { parse as parseYaml5 } from "yaml";
|
|
15352
15558
|
function flatten(obj, prefix3 = "") {
|
|
15353
15559
|
const out = {};
|
|
@@ -15475,10 +15681,10 @@ function renderDiff(diff) {
|
|
|
15475
15681
|
}
|
|
15476
15682
|
async function runConfigRefresh(opts = {}) {
|
|
15477
15683
|
const cwd = opts.cwd ?? process.cwd();
|
|
15478
|
-
const configPath =
|
|
15684
|
+
const configPath = resolve15(cwd, "massu.config.yaml");
|
|
15479
15685
|
const log = opts.silent ? () => {
|
|
15480
15686
|
} : (s) => process.stdout.write(s);
|
|
15481
|
-
if (!
|
|
15687
|
+
if (!existsSync17(configPath)) {
|
|
15482
15688
|
const message = "massu.config.yaml not found. Run: npx massu init";
|
|
15483
15689
|
if (!opts.silent) process.stderr.write(message + "\n");
|
|
15484
15690
|
return { exitCode: 1, applied: false, dryRun: !!opts.dryRun, diff: [], message };
|
|
@@ -15558,8 +15764,8 @@ async function runConfigRefresh(opts = {}) {
|
|
|
15558
15764
|
`);
|
|
15559
15765
|
const stackResolved = installResult.totalInstalled > 0 || installResult.totalUpdated > 0;
|
|
15560
15766
|
if (stackResolved) {
|
|
15561
|
-
const placeholderPath =
|
|
15562
|
-
if (
|
|
15767
|
+
const placeholderPath = resolve15(installResult.claudeDir, "commands", "_massu-needs-stack.md");
|
|
15768
|
+
if (existsSync17(placeholderPath)) {
|
|
15563
15769
|
try {
|
|
15564
15770
|
rmSync4(placeholderPath, { force: true });
|
|
15565
15771
|
log("Removed _massu-needs-stack.md (stack now declared).\n");
|
|
@@ -15668,12 +15874,12 @@ var init_gitToplevel = __esm({
|
|
|
15668
15874
|
});
|
|
15669
15875
|
|
|
15670
15876
|
// src/watch/lockfile-detector.ts
|
|
15671
|
-
import { existsSync as
|
|
15672
|
-
import { resolve as
|
|
15877
|
+
import { existsSync as existsSync18, statSync as statSync8 } from "fs";
|
|
15878
|
+
import { resolve as resolve16 } from "path";
|
|
15673
15879
|
function lockfileMidWrite(projectRoot, now = Date.now(), windowMs = LOCKFILE_WINDOW_MS) {
|
|
15674
15880
|
for (const lf of KNOWN_LOCKFILES) {
|
|
15675
|
-
const p19 =
|
|
15676
|
-
if (!
|
|
15881
|
+
const p19 = resolve16(projectRoot, lf);
|
|
15882
|
+
if (!existsSync18(p19)) continue;
|
|
15677
15883
|
try {
|
|
15678
15884
|
const stat = statSync8(p19);
|
|
15679
15885
|
const delta = now - stat.mtimeMs;
|
|
@@ -15686,7 +15892,7 @@ function lockfileMidWrite(projectRoot, now = Date.now(), windowMs = LOCKFILE_WIN
|
|
|
15686
15892
|
function gitMidOperation(projectRoot) {
|
|
15687
15893
|
const sentinels = ["MERGE_HEAD", "REBASE_HEAD", "CHERRY_PICK_HEAD", "rebase-apply", "rebase-merge"];
|
|
15688
15894
|
for (const s of sentinels) {
|
|
15689
|
-
if (
|
|
15895
|
+
if (existsSync18(resolve16(projectRoot, ".git", s))) return true;
|
|
15690
15896
|
}
|
|
15691
15897
|
return false;
|
|
15692
15898
|
}
|
|
@@ -15883,17 +16089,17 @@ var init_paths = __esm({
|
|
|
15883
16089
|
});
|
|
15884
16090
|
|
|
15885
16091
|
// src/watch/state.ts
|
|
15886
|
-
import { closeSync as closeSync3, existsSync as
|
|
15887
|
-
import { dirname as
|
|
16092
|
+
import { closeSync as closeSync3, existsSync as existsSync19, fsyncSync as fsyncSync3, mkdirSync as mkdirSync7, openSync as openSync3, readFileSync as readFileSync18, renameSync as renameSync4, rmSync as rmSync5, writeFileSync as writeFileSync4, writeSync as writeSync3 } from "fs";
|
|
16093
|
+
import { dirname as dirname10, resolve as resolve17 } from "path";
|
|
15888
16094
|
function watchStatePath(projectRoot) {
|
|
15889
|
-
return
|
|
16095
|
+
return resolve17(projectRoot, ".massu", "watch-state.json");
|
|
15890
16096
|
}
|
|
15891
16097
|
function backupStatePath(projectRoot) {
|
|
15892
|
-
return
|
|
16098
|
+
return resolve17(projectRoot, ".massu", "watch-state.v0.bak.json");
|
|
15893
16099
|
}
|
|
15894
16100
|
function readState(projectRoot) {
|
|
15895
16101
|
const path = watchStatePath(projectRoot);
|
|
15896
|
-
if (!
|
|
16102
|
+
if (!existsSync19(path)) return { ...DEFAULT_STATE };
|
|
15897
16103
|
const content = readFileSync18(path, "utf-8");
|
|
15898
16104
|
let raw;
|
|
15899
16105
|
try {
|
|
@@ -15936,14 +16142,14 @@ function readState(projectRoot) {
|
|
|
15936
16142
|
}
|
|
15937
16143
|
function archiveCorrupt(projectRoot, content) {
|
|
15938
16144
|
const bak = backupStatePath(projectRoot);
|
|
15939
|
-
mkdirSync7(
|
|
16145
|
+
mkdirSync7(dirname10(bak), { recursive: true });
|
|
15940
16146
|
writeFileSync4(bak, content, "utf-8");
|
|
15941
16147
|
}
|
|
15942
16148
|
function writeStateAtomic(projectRoot, state) {
|
|
15943
16149
|
const path = watchStatePath(projectRoot);
|
|
15944
16150
|
writeStateAtomicCounter = writeStateAtomicCounter + 1 >>> 0;
|
|
15945
16151
|
const tmp = `${path}.${process.pid}.${writeStateAtomicCounter}.tmp`;
|
|
15946
|
-
mkdirSync7(
|
|
16152
|
+
mkdirSync7(dirname10(path), { recursive: true });
|
|
15947
16153
|
let renamed = false;
|
|
15948
16154
|
try {
|
|
15949
16155
|
const fd = openSync3(tmp, "w");
|
|
@@ -15957,7 +16163,7 @@ function writeStateAtomic(projectRoot, state) {
|
|
|
15957
16163
|
renameSync4(tmp, path);
|
|
15958
16164
|
renamed = true;
|
|
15959
16165
|
} finally {
|
|
15960
|
-
if (!renamed &&
|
|
16166
|
+
if (!renamed && existsSync19(tmp)) {
|
|
15961
16167
|
try {
|
|
15962
16168
|
rmSync5(tmp, { force: true });
|
|
15963
16169
|
} catch {
|
|
@@ -16237,8 +16443,8 @@ __export(watch_exports, {
|
|
|
16237
16443
|
runWatch: () => runWatch
|
|
16238
16444
|
});
|
|
16239
16445
|
import { spawnSync as spawnSync3 } from "child_process";
|
|
16240
|
-
import { basename as basename5, dirname as
|
|
16241
|
-
import { appendFileSync, existsSync as
|
|
16446
|
+
import { basename as basename5, dirname as dirname11, resolve as resolve18 } from "path";
|
|
16447
|
+
import { appendFileSync, existsSync as existsSync20, mkdirSync as mkdirSync8, readFileSync as readFileSync19 } from "fs";
|
|
16242
16448
|
function parseFlags(args2) {
|
|
16243
16449
|
const out = {
|
|
16244
16450
|
foreground: false,
|
|
@@ -16263,8 +16469,8 @@ function parseFlags(args2) {
|
|
|
16263
16469
|
}
|
|
16264
16470
|
function findClaudeBg() {
|
|
16265
16471
|
const home = process.env.HOME ?? "";
|
|
16266
|
-
const fixed = home ?
|
|
16267
|
-
if (fixed &&
|
|
16472
|
+
const fixed = home ? resolve18(home, ".claude", "bin", "claude-bg") : null;
|
|
16473
|
+
if (fixed && existsSync20(fixed)) return fixed;
|
|
16268
16474
|
const which = spawnSync3("which", ["claude-bg"], { encoding: "utf-8" });
|
|
16269
16475
|
if (which.status === 0 && which.stdout) {
|
|
16270
16476
|
const p19 = which.stdout.trim();
|
|
@@ -16325,7 +16531,7 @@ async function runWatch(args2) {
|
|
|
16325
16531
|
}
|
|
16326
16532
|
function runStatus(root) {
|
|
16327
16533
|
const path = watchStatePath(root);
|
|
16328
|
-
if (!
|
|
16534
|
+
if (!existsSync20(path)) {
|
|
16329
16535
|
process.stdout.write("massu watch: not running (no state file)\n");
|
|
16330
16536
|
return { exitCode: 0 };
|
|
16331
16537
|
}
|
|
@@ -16407,7 +16613,7 @@ async function runForeground(root) {
|
|
|
16407
16613
|
}
|
|
16408
16614
|
throw err;
|
|
16409
16615
|
}
|
|
16410
|
-
return new Promise((
|
|
16616
|
+
return new Promise((resolve41) => {
|
|
16411
16617
|
const shutdown = async () => {
|
|
16412
16618
|
if (stopped) return;
|
|
16413
16619
|
stopped = true;
|
|
@@ -16417,7 +16623,7 @@ async function runForeground(root) {
|
|
|
16417
16623
|
process.chdir(priorCwd);
|
|
16418
16624
|
} catch {
|
|
16419
16625
|
}
|
|
16420
|
-
|
|
16626
|
+
resolve41({ exitCode: 0 });
|
|
16421
16627
|
};
|
|
16422
16628
|
process.on("SIGINT", () => {
|
|
16423
16629
|
void shutdown();
|
|
@@ -16478,19 +16684,19 @@ async function runOnQuiescent(projectRoot) {
|
|
|
16478
16684
|
);
|
|
16479
16685
|
}
|
|
16480
16686
|
function refreshLogPath(projectRoot) {
|
|
16481
|
-
return
|
|
16687
|
+
return resolve18(projectRoot, ".massu", "refresh-log.jsonl");
|
|
16482
16688
|
}
|
|
16483
16689
|
function appendRefreshLog(projectRoot, event) {
|
|
16484
16690
|
const path = refreshLogPath(projectRoot);
|
|
16485
16691
|
try {
|
|
16486
|
-
mkdirSync8(
|
|
16692
|
+
mkdirSync8(dirname11(path), { recursive: true });
|
|
16487
16693
|
appendFileSync(path, JSON.stringify(event) + "\n", "utf-8");
|
|
16488
16694
|
} catch {
|
|
16489
16695
|
}
|
|
16490
16696
|
}
|
|
16491
16697
|
function readRefreshLog(projectRoot, limit = 10, opts = {}) {
|
|
16492
16698
|
const path = refreshLogPath(projectRoot);
|
|
16493
|
-
if (!
|
|
16699
|
+
if (!existsSync20(path)) return [];
|
|
16494
16700
|
const warn = opts.warn ?? ((s) => {
|
|
16495
16701
|
process.stderr.write(s);
|
|
16496
16702
|
});
|
|
@@ -16567,7 +16773,7 @@ var init_refresh_log = __esm({
|
|
|
16567
16773
|
import {
|
|
16568
16774
|
chmodSync as chmodSync3,
|
|
16569
16775
|
closeSync as closeSync4,
|
|
16570
|
-
existsSync as
|
|
16776
|
+
existsSync as existsSync21,
|
|
16571
16777
|
fsyncSync as fsyncSync4,
|
|
16572
16778
|
mkdirSync as mkdirSync9,
|
|
16573
16779
|
openSync as openSync4,
|
|
@@ -16576,12 +16782,12 @@ import {
|
|
|
16576
16782
|
statSync as statSync9,
|
|
16577
16783
|
writeSync as writeSync4
|
|
16578
16784
|
} from "node:fs";
|
|
16579
|
-
import { dirname as
|
|
16785
|
+
import { dirname as dirname12 } from "node:path";
|
|
16580
16786
|
function atomicWrite(path, content, opts = {}) {
|
|
16581
16787
|
const tmpPath = `${path}.tmp`;
|
|
16582
|
-
const parentDir =
|
|
16788
|
+
const parentDir = dirname12(path);
|
|
16583
16789
|
try {
|
|
16584
|
-
if (!
|
|
16790
|
+
if (!existsSync21(parentDir)) {
|
|
16585
16791
|
const mkdirOpts = { recursive: true };
|
|
16586
16792
|
if (opts.ensureParentDirMode !== void 0) {
|
|
16587
16793
|
mkdirOpts.mode = opts.ensureParentDirMode;
|
|
@@ -16603,7 +16809,7 @@ function atomicWrite(path, content, opts = {}) {
|
|
|
16603
16809
|
renameSync5(tmpPath, path);
|
|
16604
16810
|
return { written: true };
|
|
16605
16811
|
} catch (err) {
|
|
16606
|
-
if (
|
|
16812
|
+
if (existsSync21(tmpPath)) {
|
|
16607
16813
|
try {
|
|
16608
16814
|
rmSync6(tmpPath, { force: true });
|
|
16609
16815
|
} catch {
|
|
@@ -16946,19 +17152,19 @@ var init_fetcher = __esm({
|
|
|
16946
17152
|
});
|
|
16947
17153
|
|
|
16948
17154
|
// src/security/manifest-cache.ts
|
|
16949
|
-
import { existsSync as
|
|
17155
|
+
import { existsSync as existsSync22, readFileSync as readFileSync20, statSync as statSync10 } from "node:fs";
|
|
16950
17156
|
import { homedir as homedir5 } from "node:os";
|
|
16951
|
-
import { resolve as
|
|
17157
|
+
import { resolve as resolve19 } from "node:path";
|
|
16952
17158
|
import { z as z4 } from "zod";
|
|
16953
17159
|
function defaultCachePaths() {
|
|
16954
|
-
const dir =
|
|
17160
|
+
const dir = resolve19(homedir5(), ".massu");
|
|
16955
17161
|
return {
|
|
16956
|
-
cachePath:
|
|
16957
|
-
lockPath:
|
|
17162
|
+
cachePath: resolve19(dir, "adapter-manifest.json"),
|
|
17163
|
+
lockPath: resolve19(dir, ".adapter-manifest.lock")
|
|
16958
17164
|
};
|
|
16959
17165
|
}
|
|
16960
17166
|
function loadCachedManifest(paths = defaultCachePaths()) {
|
|
16961
|
-
if (!
|
|
17167
|
+
if (!existsSync22(paths.cachePath)) {
|
|
16962
17168
|
return { kind: "absent" };
|
|
16963
17169
|
}
|
|
16964
17170
|
let raw;
|
|
@@ -17152,15 +17358,15 @@ var init_adapter_origin = __esm({
|
|
|
17152
17358
|
});
|
|
17153
17359
|
|
|
17154
17360
|
// src/security/local-fingerprint.ts
|
|
17155
|
-
import { existsSync as
|
|
17361
|
+
import { existsSync as existsSync23, readFileSync as readFileSync21, lstatSync as lstatSync5 } from "node:fs";
|
|
17156
17362
|
import { homedir as homedir6 } from "node:os";
|
|
17157
|
-
import { resolve as
|
|
17363
|
+
import { resolve as resolve20, isAbsolute } from "node:path";
|
|
17158
17364
|
import { createHash as createHash7 } from "node:crypto";
|
|
17159
17365
|
import { z as z5 } from "zod";
|
|
17160
17366
|
function computeLocalFingerprint(localPaths, projectRoot) {
|
|
17161
17367
|
const tuples = [];
|
|
17162
17368
|
for (const p19 of localPaths) {
|
|
17163
|
-
const abs = isAbsolute(p19) ? p19 :
|
|
17369
|
+
const abs = isAbsolute(p19) ? p19 : resolve20(projectRoot, p19);
|
|
17164
17370
|
let contentTag;
|
|
17165
17371
|
try {
|
|
17166
17372
|
const lst = lstatSync5(abs);
|
|
@@ -17181,7 +17387,7 @@ function computeLocalFingerprint(localPaths, projectRoot) {
|
|
|
17181
17387
|
return createHash7("sha256").update(canonical).digest("hex");
|
|
17182
17388
|
}
|
|
17183
17389
|
function readFingerprintSentinel(path = FINGERPRINT_PATH) {
|
|
17184
|
-
if (!
|
|
17390
|
+
if (!existsSync23(path)) return null;
|
|
17185
17391
|
let raw;
|
|
17186
17392
|
try {
|
|
17187
17393
|
raw = JSON.parse(readFileSync21(path, "utf-8"));
|
|
@@ -17232,7 +17438,7 @@ var init_local_fingerprint = __esm({
|
|
|
17232
17438
|
"use strict";
|
|
17233
17439
|
init_atomic_write();
|
|
17234
17440
|
init_manifest_schema();
|
|
17235
|
-
FINGERPRINT_PATH =
|
|
17441
|
+
FINGERPRINT_PATH = resolve20(homedir6(), ".massu", "adapters-local-fingerprint.json");
|
|
17236
17442
|
FingerprintSentinelSchema = z5.object({
|
|
17237
17443
|
fingerprint: z5.string().regex(/^[0-9a-f]{64}$/),
|
|
17238
17444
|
source: z5.enum(["cli", "cli-resync"]),
|
|
@@ -17248,15 +17454,15 @@ var init_local_fingerprint = __esm({
|
|
|
17248
17454
|
});
|
|
17249
17455
|
|
|
17250
17456
|
// src/security/install-tracking.ts
|
|
17251
|
-
import { readFileSync as readFileSync22, readdirSync as readdirSync13, lstatSync as lstatSync6, existsSync as
|
|
17457
|
+
import { readFileSync as readFileSync22, readdirSync as readdirSync13, lstatSync as lstatSync6, existsSync as existsSync24 } from "node:fs";
|
|
17252
17458
|
import { join as join11, relative as relative5, sep } from "node:path";
|
|
17253
17459
|
import { homedir as homedir7 } from "node:os";
|
|
17254
|
-
import { resolve as
|
|
17460
|
+
import { resolve as resolve21 } from "node:path";
|
|
17255
17461
|
import { createHash as createHash8 } from "node:crypto";
|
|
17256
17462
|
import { z as z6 } from "zod";
|
|
17257
17463
|
function containsHiddenDirs(packageDir) {
|
|
17258
17464
|
for (const hidden of EXCLUDED_DIR_NAMES) {
|
|
17259
|
-
if (
|
|
17465
|
+
if (existsSync24(`${packageDir}/${hidden}`)) {
|
|
17260
17466
|
return hidden;
|
|
17261
17467
|
}
|
|
17262
17468
|
}
|
|
@@ -17311,7 +17517,7 @@ function sha256OfDir(dir, opts = {}) {
|
|
|
17311
17517
|
return top.digest("hex");
|
|
17312
17518
|
}
|
|
17313
17519
|
function readInstalledManifest(path = INSTALLED_MANIFEST_PATH) {
|
|
17314
|
-
if (!
|
|
17520
|
+
if (!existsSync24(path)) return {};
|
|
17315
17521
|
let raw;
|
|
17316
17522
|
try {
|
|
17317
17523
|
raw = JSON.parse(readFileSync22(path, "utf-8"));
|
|
@@ -17378,7 +17584,7 @@ var init_install_tracking = __esm({
|
|
|
17378
17584
|
"src/security/install-tracking.ts"() {
|
|
17379
17585
|
"use strict";
|
|
17380
17586
|
init_atomic_write();
|
|
17381
|
-
INSTALLED_MANIFEST_PATH =
|
|
17587
|
+
INSTALLED_MANIFEST_PATH = resolve21(homedir7(), ".massu", "adapter-manifest-installed.json");
|
|
17382
17588
|
DEFAULT_MAX_FILE_BYTES = 64 * 1024 * 1024;
|
|
17383
17589
|
EXCLUDED_DIR_NAMES = /* @__PURE__ */ new Set([".git", "node_modules", ".cache", ".tmp"]);
|
|
17384
17590
|
InstallEntrySchema = z6.object({
|
|
@@ -17401,12 +17607,12 @@ var init_install_tracking = __esm({
|
|
|
17401
17607
|
});
|
|
17402
17608
|
|
|
17403
17609
|
// src/detect/adapters/discover.ts
|
|
17404
|
-
import { existsSync as
|
|
17405
|
-
import { resolve as
|
|
17610
|
+
import { existsSync as existsSync25, readdirSync as readdirSync14, readFileSync as readFileSync23, lstatSync as lstatSync7 } from "node:fs";
|
|
17611
|
+
import { resolve as resolve22, isAbsolute as isAbsolute2 } from "node:path";
|
|
17406
17612
|
import { z as z7 } from "zod";
|
|
17407
17613
|
function walkNodeModules(projectRoot, warnings) {
|
|
17408
|
-
const nodeModulesDir =
|
|
17409
|
-
if (!
|
|
17614
|
+
const nodeModulesDir = resolve22(projectRoot, "node_modules");
|
|
17615
|
+
if (!existsSync25(nodeModulesDir)) {
|
|
17410
17616
|
return [];
|
|
17411
17617
|
}
|
|
17412
17618
|
const candidates = [];
|
|
@@ -17419,7 +17625,7 @@ function walkNodeModules(projectRoot, warnings) {
|
|
|
17419
17625
|
}
|
|
17420
17626
|
for (const entry of topLevelEntries) {
|
|
17421
17627
|
if (entry.startsWith(".")) continue;
|
|
17422
|
-
const entryPath =
|
|
17628
|
+
const entryPath = resolve22(nodeModulesDir, entry);
|
|
17423
17629
|
let entryStat;
|
|
17424
17630
|
try {
|
|
17425
17631
|
entryStat = lstatSync7(entryPath);
|
|
@@ -17441,7 +17647,7 @@ function walkNodeModules(projectRoot, warnings) {
|
|
|
17441
17647
|
continue;
|
|
17442
17648
|
}
|
|
17443
17649
|
for (const sub of scopedEntries) {
|
|
17444
|
-
const subPath =
|
|
17650
|
+
const subPath = resolve22(entryPath, sub);
|
|
17445
17651
|
let subStat;
|
|
17446
17652
|
try {
|
|
17447
17653
|
subStat = lstatSync7(subPath);
|
|
@@ -17460,8 +17666,8 @@ function walkNodeModules(projectRoot, warnings) {
|
|
|
17460
17666
|
return candidates;
|
|
17461
17667
|
}
|
|
17462
17668
|
function tryReadAdapterPackage(packageDir, warnings) {
|
|
17463
|
-
const pkgJsonPath =
|
|
17464
|
-
if (!
|
|
17669
|
+
const pkgJsonPath = resolve22(packageDir, "package.json");
|
|
17670
|
+
if (!existsSync25(pkgJsonPath)) return null;
|
|
17465
17671
|
let raw;
|
|
17466
17672
|
try {
|
|
17467
17673
|
raw = JSON.parse(readFileSync23(pkgJsonPath, "utf-8"));
|
|
@@ -17598,8 +17804,8 @@ function discoverAdapters(opts) {
|
|
|
17598
17804
|
const localSet = new Set(opts.configLocalPaths);
|
|
17599
17805
|
for (const localPath of opts.configLocalPaths) {
|
|
17600
17806
|
if (seenIds.has(localPath)) continue;
|
|
17601
|
-
const absPath = isAbsolute2(localPath) ? localPath :
|
|
17602
|
-
if (!
|
|
17807
|
+
const absPath = isAbsolute2(localPath) ? localPath : resolve22(opts.projectRoot, localPath);
|
|
17808
|
+
if (!existsSync25(absPath)) {
|
|
17603
17809
|
warnings.push(
|
|
17604
17810
|
`local adapter file not found: ${localPath} (resolved to ${absPath}). Remove via: massu adapters remove-local ${localPath}`
|
|
17605
17811
|
);
|
|
@@ -17680,8 +17886,8 @@ __export(adapters_exports, {
|
|
|
17680
17886
|
runAdaptersResyncLocalFingerprint: () => runAdaptersResyncLocalFingerprint,
|
|
17681
17887
|
runAdaptersSearch: () => runAdaptersSearch
|
|
17682
17888
|
});
|
|
17683
|
-
import { existsSync as
|
|
17684
|
-
import { resolve as
|
|
17889
|
+
import { existsSync as existsSync26, readFileSync as readFileSync24 } from "node:fs";
|
|
17890
|
+
import { resolve as resolve23 } from "node:path";
|
|
17685
17891
|
import { parseDocument } from "yaml";
|
|
17686
17892
|
async function handleAdaptersSubcommand(args2) {
|
|
17687
17893
|
const sub = args2[0];
|
|
@@ -17948,8 +18154,8 @@ function mutateLocalArray(mutator, command) {
|
|
|
17948
18154
|
);
|
|
17949
18155
|
return { exitCode: 2 };
|
|
17950
18156
|
}
|
|
17951
|
-
const yamlPath =
|
|
17952
|
-
if (!
|
|
18157
|
+
const yamlPath = resolve23(projectRoot, "massu.config.yaml");
|
|
18158
|
+
if (!existsSync26(yamlPath)) {
|
|
17953
18159
|
process.stderr.write(
|
|
17954
18160
|
`${command}: massu.config.yaml not found at ${yamlPath}. Run \`massu init\` first.
|
|
17955
18161
|
`
|
|
@@ -17979,7 +18185,7 @@ function mutateLocalArray(mutator, command) {
|
|
|
17979
18185
|
if (next === null) {
|
|
17980
18186
|
return { exitCode: 0 };
|
|
17981
18187
|
}
|
|
17982
|
-
const lockPath =
|
|
18188
|
+
const lockPath = resolve23(projectRoot, ".massu", "adapters-local-mutate.lock");
|
|
17983
18189
|
return withFileLockSync(lockPath, () => {
|
|
17984
18190
|
doc.setIn(["adapters", "local"], next);
|
|
17985
18191
|
const newYaml = doc.toString();
|
|
@@ -18048,16 +18254,16 @@ async function runAdaptersInstall(args2) {
|
|
|
18048
18254
|
`);
|
|
18049
18255
|
return { exitCode: 1 };
|
|
18050
18256
|
}
|
|
18051
|
-
const packageDir =
|
|
18052
|
-
if (!
|
|
18257
|
+
const packageDir = resolve23(projectRoot, "node_modules", ...packageName.split("/"));
|
|
18258
|
+
if (!existsSync26(packageDir)) {
|
|
18053
18259
|
process.stderr.write(
|
|
18054
18260
|
`install: ${packageName} is not installed in node_modules. Run \`npm install ${packageName}\` first.
|
|
18055
18261
|
`
|
|
18056
18262
|
);
|
|
18057
18263
|
return { exitCode: 1 };
|
|
18058
18264
|
}
|
|
18059
|
-
const pkgJsonPath =
|
|
18060
|
-
if (!
|
|
18265
|
+
const pkgJsonPath = resolve23(packageDir, "package.json");
|
|
18266
|
+
if (!existsSync26(pkgJsonPath)) {
|
|
18061
18267
|
process.stderr.write(`install: ${packageName} has no package.json at ${pkgJsonPath}
|
|
18062
18268
|
`);
|
|
18063
18269
|
return { exitCode: 1 };
|
|
@@ -18183,8 +18389,8 @@ async function runAdaptersResign(_args) {
|
|
|
18183
18389
|
removeInstalledManifestEntry(name);
|
|
18184
18390
|
continue;
|
|
18185
18391
|
}
|
|
18186
|
-
const packageDir =
|
|
18187
|
-
if (!
|
|
18392
|
+
const packageDir = resolve23(projectRoot, "node_modules", ...name.split("/"));
|
|
18393
|
+
if (!existsSync26(packageDir)) {
|
|
18188
18394
|
removed++;
|
|
18189
18395
|
warnings.push(`${name}@${entry.version}: not present in node_modules \u2014 REMOVED from sidecar`);
|
|
18190
18396
|
removeInstalledManifestEntry(name);
|
|
@@ -18271,11 +18477,11 @@ var init_adapters2 = __esm({
|
|
|
18271
18477
|
|
|
18272
18478
|
// src/db.ts
|
|
18273
18479
|
import Database2 from "better-sqlite3";
|
|
18274
|
-
import { dirname as
|
|
18275
|
-
import { existsSync as
|
|
18480
|
+
import { dirname as dirname13, join as join12 } from "path";
|
|
18481
|
+
import { existsSync as existsSync27, mkdirSync as mkdirSync10, readdirSync as readdirSync15, statSync as statSync11 } from "fs";
|
|
18276
18482
|
function getCodeGraphDb() {
|
|
18277
18483
|
const dbPath = getResolvedPaths().codegraphDbPath;
|
|
18278
|
-
if (!
|
|
18484
|
+
if (!existsSync27(dbPath)) {
|
|
18279
18485
|
throw new CodegraphDbNotInitializedError(dbPath);
|
|
18280
18486
|
}
|
|
18281
18487
|
const db = new Database2(dbPath, { readonly: true });
|
|
@@ -18284,8 +18490,8 @@ function getCodeGraphDb() {
|
|
|
18284
18490
|
}
|
|
18285
18491
|
function getDataDb() {
|
|
18286
18492
|
const dbPath = getResolvedPaths().dataDbPath;
|
|
18287
|
-
const dir =
|
|
18288
|
-
if (!
|
|
18493
|
+
const dir = dirname13(dbPath);
|
|
18494
|
+
if (!existsSync27(dir)) {
|
|
18289
18495
|
mkdirSync10(dir, { recursive: true });
|
|
18290
18496
|
}
|
|
18291
18497
|
const db = new Database2(dbPath);
|
|
@@ -18592,10 +18798,10 @@ var init_db = __esm({
|
|
|
18592
18798
|
});
|
|
18593
18799
|
|
|
18594
18800
|
// src/security-utils.ts
|
|
18595
|
-
import { resolve as
|
|
18801
|
+
import { resolve as resolve24, normalize } from "path";
|
|
18596
18802
|
function ensureWithinRoot(filePath, projectRoot) {
|
|
18597
|
-
const resolvedRoot =
|
|
18598
|
-
const resolvedPath =
|
|
18803
|
+
const resolvedRoot = resolve24(projectRoot);
|
|
18804
|
+
const resolvedPath = resolve24(resolvedRoot, filePath);
|
|
18599
18805
|
const normalizedPath = normalize(resolvedPath);
|
|
18600
18806
|
const normalizedRoot = normalize(resolvedRoot);
|
|
18601
18807
|
if (!normalizedPath.startsWith(normalizedRoot + "/") && normalizedPath !== normalizedRoot) {
|
|
@@ -18668,8 +18874,8 @@ var init_rules = __esm({
|
|
|
18668
18874
|
});
|
|
18669
18875
|
|
|
18670
18876
|
// src/import-resolver.ts
|
|
18671
|
-
import { readFileSync as readFileSync25, existsSync as
|
|
18672
|
-
import { resolve as
|
|
18877
|
+
import { readFileSync as readFileSync25, existsSync as existsSync28, statSync as statSync12 } from "fs";
|
|
18878
|
+
import { resolve as resolve25, dirname as dirname14, join as join13 } from "path";
|
|
18673
18879
|
function parseImports(source) {
|
|
18674
18880
|
const imports = [];
|
|
18675
18881
|
const lines = source.split("\n");
|
|
@@ -18725,23 +18931,23 @@ function resolveImportPath(specifier, fromFile) {
|
|
|
18725
18931
|
let basePath;
|
|
18726
18932
|
if (specifier.startsWith("@/")) {
|
|
18727
18933
|
const paths = getResolvedPaths();
|
|
18728
|
-
basePath =
|
|
18934
|
+
basePath = resolve25(paths.pathAlias["@"] ?? paths.srcDir, specifier.slice(2));
|
|
18729
18935
|
} else {
|
|
18730
|
-
basePath =
|
|
18936
|
+
basePath = resolve25(dirname14(fromFile), specifier);
|
|
18731
18937
|
}
|
|
18732
|
-
if (
|
|
18938
|
+
if (existsSync28(basePath) && !isDirectory(basePath)) {
|
|
18733
18939
|
return toRelative(basePath);
|
|
18734
18940
|
}
|
|
18735
18941
|
const resolvedPaths = getResolvedPaths();
|
|
18736
18942
|
for (const ext of resolvedPaths.extensions) {
|
|
18737
18943
|
const withExt = basePath + ext;
|
|
18738
|
-
if (
|
|
18944
|
+
if (existsSync28(withExt)) {
|
|
18739
18945
|
return toRelative(withExt);
|
|
18740
18946
|
}
|
|
18741
18947
|
}
|
|
18742
18948
|
for (const indexFile of resolvedPaths.indexFiles) {
|
|
18743
18949
|
const indexPath = join13(basePath, indexFile);
|
|
18744
|
-
if (
|
|
18950
|
+
if (existsSync28(indexPath)) {
|
|
18745
18951
|
return toRelative(indexPath);
|
|
18746
18952
|
}
|
|
18747
18953
|
}
|
|
@@ -18777,8 +18983,8 @@ function buildImportIndex(dataDb, codegraphDb) {
|
|
|
18777
18983
|
const batchSize = 500;
|
|
18778
18984
|
let batch = [];
|
|
18779
18985
|
for (const file of files) {
|
|
18780
|
-
const absPath = ensureWithinRoot(
|
|
18781
|
-
if (!
|
|
18986
|
+
const absPath = ensureWithinRoot(resolve25(projectRoot, file.path), projectRoot);
|
|
18987
|
+
if (!existsSync28(absPath)) continue;
|
|
18782
18988
|
let source;
|
|
18783
18989
|
try {
|
|
18784
18990
|
source = readFileSync25(absPath, "utf-8");
|
|
@@ -18817,12 +19023,12 @@ var init_import_resolver = __esm({
|
|
|
18817
19023
|
});
|
|
18818
19024
|
|
|
18819
19025
|
// src/trpc-index.ts
|
|
18820
|
-
import { readFileSync as readFileSync26, existsSync as
|
|
18821
|
-
import { resolve as
|
|
19026
|
+
import { readFileSync as readFileSync26, existsSync as existsSync29, readdirSync as readdirSync16 } from "fs";
|
|
19027
|
+
import { resolve as resolve26, join as join14 } from "path";
|
|
18822
19028
|
function parseRootRouter() {
|
|
18823
19029
|
const paths = getResolvedPaths();
|
|
18824
19030
|
const rootPath = paths.rootRouterPath;
|
|
18825
|
-
if (!
|
|
19031
|
+
if (!existsSync29(rootPath)) {
|
|
18826
19032
|
throw new Error(`Root router not found at ${rootPath}`);
|
|
18827
19033
|
}
|
|
18828
19034
|
const source = readFileSync26(rootPath, "utf-8");
|
|
@@ -18833,16 +19039,16 @@ function parseRootRouter() {
|
|
|
18833
19039
|
while ((match = importRegex.exec(source)) !== null) {
|
|
18834
19040
|
const variable = match[1];
|
|
18835
19041
|
let filePath = match[2];
|
|
18836
|
-
const fullPath =
|
|
19042
|
+
const fullPath = resolve26(paths.routersDir, filePath);
|
|
18837
19043
|
for (const ext of [".ts", ".tsx", ""]) {
|
|
18838
19044
|
const candidate = fullPath + ext;
|
|
18839
19045
|
const routersRelPath = getConfig().paths.routers ?? "src/server/api/routers";
|
|
18840
|
-
if (
|
|
19046
|
+
if (existsSync29(candidate)) {
|
|
18841
19047
|
filePath = routersRelPath + "/" + filePath + ext;
|
|
18842
19048
|
break;
|
|
18843
19049
|
}
|
|
18844
19050
|
const indexCandidate = join14(fullPath, "index.ts");
|
|
18845
|
-
if (
|
|
19051
|
+
if (existsSync29(indexCandidate)) {
|
|
18846
19052
|
filePath = routersRelPath + "/" + filePath + "/index.ts";
|
|
18847
19053
|
break;
|
|
18848
19054
|
}
|
|
@@ -18861,8 +19067,8 @@ function parseRootRouter() {
|
|
|
18861
19067
|
return mappings;
|
|
18862
19068
|
}
|
|
18863
19069
|
function extractProcedures(routerFilePath) {
|
|
18864
|
-
const absPath =
|
|
18865
|
-
if (!
|
|
19070
|
+
const absPath = resolve26(getProjectRoot(), routerFilePath);
|
|
19071
|
+
if (!existsSync29(absPath)) return [];
|
|
18866
19072
|
const source = readFileSync26(absPath, "utf-8");
|
|
18867
19073
|
const procedures = [];
|
|
18868
19074
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -18886,13 +19092,13 @@ function findUICallSites(routerKey, procedureName) {
|
|
|
18886
19092
|
const root = getProjectRoot();
|
|
18887
19093
|
const src = config.paths.source;
|
|
18888
19094
|
const searchDirs = [
|
|
18889
|
-
|
|
18890
|
-
|
|
18891
|
-
|
|
19095
|
+
resolve26(root, config.paths.pages ?? src + "/app"),
|
|
19096
|
+
resolve26(root, config.paths.components ?? src + "/components"),
|
|
19097
|
+
resolve26(root, config.paths.hooks ?? src + "/hooks")
|
|
18892
19098
|
];
|
|
18893
19099
|
const searchPattern = `api.${routerKey}.${procedureName}`;
|
|
18894
19100
|
for (const dir of searchDirs) {
|
|
18895
|
-
if (!
|
|
19101
|
+
if (!existsSync29(dir)) continue;
|
|
18896
19102
|
searchDirectory(dir, searchPattern, callSites);
|
|
18897
19103
|
}
|
|
18898
19104
|
return callSites;
|
|
@@ -18969,8 +19175,8 @@ var init_trpc_index = __esm({
|
|
|
18969
19175
|
});
|
|
18970
19176
|
|
|
18971
19177
|
// src/page-deps.ts
|
|
18972
|
-
import { readFileSync as readFileSync27, existsSync as
|
|
18973
|
-
import { resolve as
|
|
19178
|
+
import { readFileSync as readFileSync27, existsSync as existsSync30 } from "fs";
|
|
19179
|
+
import { resolve as resolve27 } from "path";
|
|
18974
19180
|
function deriveRoute(pageFile) {
|
|
18975
19181
|
let route = pageFile.replace(/^src\/app/, "").replace(/\/page\.tsx?$/, "").replace(/\/page\.jsx?$/, "");
|
|
18976
19182
|
return route || "/";
|
|
@@ -19008,8 +19214,8 @@ function findRouterCalls(files) {
|
|
|
19008
19214
|
const routers = /* @__PURE__ */ new Set();
|
|
19009
19215
|
const projectRoot = getProjectRoot();
|
|
19010
19216
|
for (const file of files) {
|
|
19011
|
-
const absPath = ensureWithinRoot(
|
|
19012
|
-
if (!
|
|
19217
|
+
const absPath = ensureWithinRoot(resolve27(projectRoot, file), projectRoot);
|
|
19218
|
+
if (!existsSync30(absPath)) continue;
|
|
19013
19219
|
try {
|
|
19014
19220
|
const source = readFileSync27(absPath, "utf-8");
|
|
19015
19221
|
const apiCallRegex = /api\.(\w+)\.\w+/g;
|
|
@@ -19029,8 +19235,8 @@ function findTablesFromRouters(routerNames, dataDb) {
|
|
|
19029
19235
|
"SELECT DISTINCT router_file FROM massu_trpc_procedures WHERE router_name = ?"
|
|
19030
19236
|
).all(routerName);
|
|
19031
19237
|
for (const proc of procs) {
|
|
19032
|
-
const absPath = ensureWithinRoot(
|
|
19033
|
-
if (!
|
|
19238
|
+
const absPath = ensureWithinRoot(resolve27(getProjectRoot(), proc.router_file), getProjectRoot());
|
|
19239
|
+
if (!existsSync30(absPath)) continue;
|
|
19034
19240
|
try {
|
|
19035
19241
|
const source = readFileSync27(absPath, "utf-8");
|
|
19036
19242
|
const dbPattern = getConfig().dbAccessPattern ?? "ctx.db.{table}";
|
|
@@ -19301,11 +19507,11 @@ var init_domains = __esm({
|
|
|
19301
19507
|
});
|
|
19302
19508
|
|
|
19303
19509
|
// src/schema-mapper.ts
|
|
19304
|
-
import { readFileSync as readFileSync28, existsSync as
|
|
19510
|
+
import { readFileSync as readFileSync28, existsSync as existsSync31, readdirSync as readdirSync17 } from "fs";
|
|
19305
19511
|
import { join as join15 } from "path";
|
|
19306
19512
|
function parsePrismaSchema() {
|
|
19307
19513
|
const schemaPath = getResolvedPaths().prismaSchemaPath;
|
|
19308
|
-
if (!
|
|
19514
|
+
if (!existsSync31(schemaPath)) {
|
|
19309
19515
|
throw new Error(`Prisma schema not found at ${schemaPath}`);
|
|
19310
19516
|
}
|
|
19311
19517
|
const source = readFileSync28(schemaPath, "utf-8");
|
|
@@ -19366,7 +19572,7 @@ function toSnakeCase(str) {
|
|
|
19366
19572
|
function findColumnUsageInRouters(tableName) {
|
|
19367
19573
|
const usage = /* @__PURE__ */ new Map();
|
|
19368
19574
|
const routersDir = getResolvedPaths().routersDir;
|
|
19369
|
-
if (!
|
|
19575
|
+
if (!existsSync31(routersDir)) return usage;
|
|
19370
19576
|
scanDirectory(routersDir, tableName, usage);
|
|
19371
19577
|
return usage;
|
|
19372
19578
|
}
|
|
@@ -19428,7 +19634,7 @@ function detectMismatches(models) {
|
|
|
19428
19634
|
}
|
|
19429
19635
|
function findFilesUsingColumn(dir, column, tableName) {
|
|
19430
19636
|
const result = [];
|
|
19431
|
-
if (!
|
|
19637
|
+
if (!existsSync31(dir)) return result;
|
|
19432
19638
|
const entries = readdirSync17(dir, { withFileTypes: true });
|
|
19433
19639
|
for (const entry of entries) {
|
|
19434
19640
|
const fullPath = join15(dir, entry.name);
|
|
@@ -19581,14 +19787,14 @@ var init_import_parser = __esm({
|
|
|
19581
19787
|
});
|
|
19582
19788
|
|
|
19583
19789
|
// src/python/import-resolver.ts
|
|
19584
|
-
import { readFileSync as readFileSync29, existsSync as
|
|
19585
|
-
import { resolve as
|
|
19790
|
+
import { readFileSync as readFileSync29, existsSync as existsSync32, readdirSync as readdirSync18 } from "fs";
|
|
19791
|
+
import { resolve as resolve29, join as join16, relative as relative6, dirname as dirname15 } from "path";
|
|
19586
19792
|
function resolvePythonModulePath(module, fromFile, pythonRoot, level) {
|
|
19587
19793
|
const projectRoot = getProjectRoot();
|
|
19588
19794
|
if (level > 0) {
|
|
19589
|
-
let baseDir =
|
|
19795
|
+
let baseDir = dirname15(resolve29(projectRoot, fromFile));
|
|
19590
19796
|
for (let i = 1; i < level; i++) {
|
|
19591
|
-
baseDir =
|
|
19797
|
+
baseDir = dirname15(baseDir);
|
|
19592
19798
|
}
|
|
19593
19799
|
const modulePart = module.replace(/^\.+/, "");
|
|
19594
19800
|
if (modulePart) {
|
|
@@ -19598,17 +19804,17 @@ function resolvePythonModulePath(module, fromFile, pythonRoot, level) {
|
|
|
19598
19804
|
return tryResolvePythonPath(baseDir, projectRoot);
|
|
19599
19805
|
}
|
|
19600
19806
|
const parts = module.split(".");
|
|
19601
|
-
const candidate = join16(
|
|
19807
|
+
const candidate = join16(resolve29(projectRoot, pythonRoot), ...parts);
|
|
19602
19808
|
return tryResolvePythonPath(candidate, projectRoot);
|
|
19603
19809
|
}
|
|
19604
19810
|
function tryResolvePythonPath(basePath, projectRoot) {
|
|
19605
|
-
if (
|
|
19811
|
+
if (existsSync32(basePath + ".py")) {
|
|
19606
19812
|
return relative6(projectRoot, basePath + ".py");
|
|
19607
19813
|
}
|
|
19608
|
-
if (
|
|
19814
|
+
if (existsSync32(join16(basePath, "__init__.py"))) {
|
|
19609
19815
|
return relative6(projectRoot, join16(basePath, "__init__.py"));
|
|
19610
19816
|
}
|
|
19611
|
-
if (basePath.endsWith(".py") &&
|
|
19817
|
+
if (basePath.endsWith(".py") && existsSync32(basePath)) {
|
|
19612
19818
|
return relative6(projectRoot, basePath);
|
|
19613
19819
|
}
|
|
19614
19820
|
return null;
|
|
@@ -19631,7 +19837,7 @@ function walkPythonFiles(dir, excludeDirs) {
|
|
|
19631
19837
|
}
|
|
19632
19838
|
function buildPythonImportIndex(dataDb, pythonRoot, excludeDirs = ["__pycache__", ".venv", "venv", ".mypy_cache", ".pytest_cache"]) {
|
|
19633
19839
|
const projectRoot = getProjectRoot();
|
|
19634
|
-
const absRoot =
|
|
19840
|
+
const absRoot = resolve29(projectRoot, pythonRoot);
|
|
19635
19841
|
dataDb.exec("DELETE FROM massu_py_imports");
|
|
19636
19842
|
const insertStmt = dataDb.prepare(
|
|
19637
19843
|
"INSERT INTO massu_py_imports (source_file, target_file, import_type, imported_names, line) VALUES (?, ?, ?, ?, ?)"
|
|
@@ -20956,8 +21162,8 @@ var init_memory_tools = __esm({
|
|
|
20956
21162
|
});
|
|
20957
21163
|
|
|
20958
21164
|
// src/docs-tools.ts
|
|
20959
|
-
import { readFileSync as readFileSync34, existsSync as
|
|
20960
|
-
import { resolve as
|
|
21165
|
+
import { readFileSync as readFileSync34, existsSync as existsSync33 } from "fs";
|
|
21166
|
+
import { resolve as resolve30, basename as basename6 } from "path";
|
|
20961
21167
|
function p3(baseName) {
|
|
20962
21168
|
return `${getConfig().toolPrefix}_${baseName}`;
|
|
20963
21169
|
}
|
|
@@ -21012,7 +21218,7 @@ function handleDocsToolCall(name, args2) {
|
|
|
21012
21218
|
}
|
|
21013
21219
|
function loadDocsMap() {
|
|
21014
21220
|
const mapPath = getResolvedPaths().docsMapPath;
|
|
21015
|
-
if (!
|
|
21221
|
+
if (!existsSync33(mapPath)) {
|
|
21016
21222
|
throw new Error(`docs-map.json not found at ${mapPath}`);
|
|
21017
21223
|
}
|
|
21018
21224
|
return JSON.parse(readFileSync34(mapPath, "utf-8"));
|
|
@@ -21085,10 +21291,10 @@ function extractFrontmatter(content) {
|
|
|
21085
21291
|
}
|
|
21086
21292
|
function extractProcedureNames(routerPath) {
|
|
21087
21293
|
const root = getProjectRoot();
|
|
21088
|
-
const absPath = ensureWithinRoot(
|
|
21089
|
-
if (!
|
|
21090
|
-
const altPath = ensureWithinRoot(
|
|
21091
|
-
if (!
|
|
21294
|
+
const absPath = ensureWithinRoot(resolve30(getResolvedPaths().srcDir, "..", routerPath), root);
|
|
21295
|
+
if (!existsSync33(absPath)) {
|
|
21296
|
+
const altPath = ensureWithinRoot(resolve30(getResolvedPaths().srcDir, "../server/api/routers", basename6(routerPath)), root);
|
|
21297
|
+
if (!existsSync33(altPath)) return [];
|
|
21092
21298
|
return extractProcedureNamesFromContent(readFileSync34(altPath, "utf-8"));
|
|
21093
21299
|
}
|
|
21094
21300
|
return extractProcedureNamesFromContent(readFileSync34(absPath, "utf-8"));
|
|
@@ -21131,8 +21337,8 @@ function handleDocsAudit(args2) {
|
|
|
21131
21337
|
for (const [mappingId, triggeringFiles] of affectedMappings) {
|
|
21132
21338
|
const mapping = docsMap.mappings.find((m3) => m3.id === mappingId);
|
|
21133
21339
|
if (!mapping) continue;
|
|
21134
|
-
const helpPagePath = ensureWithinRoot(
|
|
21135
|
-
if (!
|
|
21340
|
+
const helpPagePath = ensureWithinRoot(resolve30(getResolvedPaths().helpSitePath, mapping.helpPage), getProjectRoot());
|
|
21341
|
+
if (!existsSync33(helpPagePath)) {
|
|
21136
21342
|
results.push({
|
|
21137
21343
|
helpPage: mapping.helpPage,
|
|
21138
21344
|
mappingId,
|
|
@@ -21184,8 +21390,8 @@ function handleDocsAudit(args2) {
|
|
|
21184
21390
|
});
|
|
21185
21391
|
for (const [guideName, parentId] of Object.entries(docsMap.userGuideInheritance.examples)) {
|
|
21186
21392
|
if (parentId === mappingId) {
|
|
21187
|
-
const guidePath = ensureWithinRoot(
|
|
21188
|
-
if (
|
|
21393
|
+
const guidePath = ensureWithinRoot(resolve30(getResolvedPaths().helpSitePath, `pages/user-guides/${guideName}/index.mdx`), getProjectRoot());
|
|
21394
|
+
if (existsSync33(guidePath)) {
|
|
21189
21395
|
const guideContent = readFileSync34(guidePath, "utf-8");
|
|
21190
21396
|
const guideFrontmatter = extractFrontmatter(guideContent);
|
|
21191
21397
|
if (!guideFrontmatter?.lastVerified || status === "STALE") {
|
|
@@ -21219,8 +21425,8 @@ function handleDocsCoverage(args2) {
|
|
|
21219
21425
|
const gaps = [];
|
|
21220
21426
|
const mappings = filterDomain ? docsMap.mappings.filter((m3) => m3.id === filterDomain) : docsMap.mappings;
|
|
21221
21427
|
for (const mapping of mappings) {
|
|
21222
|
-
const helpPagePath = ensureWithinRoot(
|
|
21223
|
-
const exists =
|
|
21428
|
+
const helpPagePath = ensureWithinRoot(resolve30(getResolvedPaths().helpSitePath, mapping.helpPage), getProjectRoot());
|
|
21429
|
+
const exists = existsSync33(helpPagePath);
|
|
21224
21430
|
let hasContent = false;
|
|
21225
21431
|
let lineCount = 0;
|
|
21226
21432
|
let lastVerified = null;
|
|
@@ -21567,8 +21773,8 @@ var init_observability_tools = __esm({
|
|
|
21567
21773
|
});
|
|
21568
21774
|
|
|
21569
21775
|
// src/sentinel-db.ts
|
|
21570
|
-
import { existsSync as
|
|
21571
|
-
import { resolve as
|
|
21776
|
+
import { existsSync as existsSync34 } from "fs";
|
|
21777
|
+
import { resolve as resolve31 } from "path";
|
|
21572
21778
|
function parsePortalScope(raw) {
|
|
21573
21779
|
if (!raw) return [];
|
|
21574
21780
|
try {
|
|
@@ -21804,23 +22010,23 @@ function validateFeatures(db, domainFilter) {
|
|
|
21804
22010
|
const missingProcedures = [];
|
|
21805
22011
|
const missingPages = [];
|
|
21806
22012
|
for (const comp of components) {
|
|
21807
|
-
const absPath =
|
|
21808
|
-
if (!
|
|
22013
|
+
const absPath = resolve31(PROJECT_ROOT, comp.component_file);
|
|
22014
|
+
if (!existsSync34(absPath)) {
|
|
21809
22015
|
missingComponents.push(comp.component_file);
|
|
21810
22016
|
}
|
|
21811
22017
|
}
|
|
21812
22018
|
for (const proc of procedures) {
|
|
21813
|
-
const routerPath =
|
|
21814
|
-
if (!
|
|
22019
|
+
const routerPath = resolve31(PROJECT_ROOT, `src/server/api/routers/${proc.router_name}.ts`);
|
|
22020
|
+
if (!existsSync34(routerPath)) {
|
|
21815
22021
|
missingProcedures.push({ router: proc.router_name, procedure: proc.procedure_name });
|
|
21816
22022
|
}
|
|
21817
22023
|
}
|
|
21818
22024
|
for (const page of pages) {
|
|
21819
22025
|
const routeToPath = page.page_route.replace(/^\/(portal-[^/]+\/)?/, "src/app/").replace(/\/$/, "") + "/page.tsx";
|
|
21820
|
-
const absPath =
|
|
21821
|
-
if (page.page_route.startsWith("/") && !
|
|
21822
|
-
const altPath =
|
|
21823
|
-
if (!
|
|
22026
|
+
const absPath = resolve31(PROJECT_ROOT, routeToPath);
|
|
22027
|
+
if (page.page_route.startsWith("/") && !existsSync34(absPath)) {
|
|
22028
|
+
const altPath = resolve31(PROJECT_ROOT, `src/app${page.page_route}/page.tsx`);
|
|
22029
|
+
if (!existsSync34(altPath)) {
|
|
21824
22030
|
missingPages.push(page.page_route);
|
|
21825
22031
|
}
|
|
21826
22032
|
}
|
|
@@ -22344,8 +22550,8 @@ var init_sentinel_tools = __esm({
|
|
|
22344
22550
|
});
|
|
22345
22551
|
|
|
22346
22552
|
// src/sentinel-scanner.ts
|
|
22347
|
-
import { readFileSync as readFileSync35, existsSync as
|
|
22348
|
-
import { resolve as
|
|
22553
|
+
import { readFileSync as readFileSync35, existsSync as existsSync35, readdirSync as readdirSync23, statSync as statSync13 } from "fs";
|
|
22554
|
+
import { resolve as resolve32, join as join21, basename as basename7, dirname as dirname16, relative as relative11 } from "path";
|
|
22349
22555
|
function inferDomain(filePath) {
|
|
22350
22556
|
const domains = getConfig().domains;
|
|
22351
22557
|
const path = filePath.toLowerCase();
|
|
@@ -22474,8 +22680,8 @@ function scanComponentExports(dataDb) {
|
|
|
22474
22680
|
const projectRoot = getProjectRoot();
|
|
22475
22681
|
const componentsBase = config.paths.components ?? config.paths.source + "/components";
|
|
22476
22682
|
const componentDirs = [];
|
|
22477
|
-
const basePath =
|
|
22478
|
-
if (
|
|
22683
|
+
const basePath = resolve32(projectRoot, componentsBase);
|
|
22684
|
+
if (existsSync35(basePath)) {
|
|
22479
22685
|
try {
|
|
22480
22686
|
const entries = readdirSync23(basePath, { withFileTypes: true });
|
|
22481
22687
|
for (const entry of entries) {
|
|
@@ -22487,8 +22693,8 @@ function scanComponentExports(dataDb) {
|
|
|
22487
22693
|
}
|
|
22488
22694
|
}
|
|
22489
22695
|
for (const dir of componentDirs) {
|
|
22490
|
-
const absDir =
|
|
22491
|
-
if (!
|
|
22696
|
+
const absDir = resolve32(projectRoot, dir);
|
|
22697
|
+
if (!existsSync35(absDir)) continue;
|
|
22492
22698
|
const files = walkDir2(absDir).filter((f2) => f2.endsWith(".tsx") || f2.endsWith(".ts"));
|
|
22493
22699
|
for (const file of files) {
|
|
22494
22700
|
const relPath = relative11(projectRoot, file);
|
|
@@ -22518,7 +22724,7 @@ function scanComponentExports(dataDb) {
|
|
|
22518
22724
|
if (hasHandlers && exportMatch) {
|
|
22519
22725
|
const componentName = exportMatch[1];
|
|
22520
22726
|
const domain = inferDomain(relPath);
|
|
22521
|
-
const subdomain = basename7(
|
|
22727
|
+
const subdomain = basename7(dirname16(relPath));
|
|
22522
22728
|
const featureKey = `component.${subdomain}.${componentName.replace(/([A-Z])/g, "-$1").toLowerCase().replace(/^-/, "")}`;
|
|
22523
22729
|
if (!annotations.some((a2) => a2.featureKey === featureKey)) {
|
|
22524
22730
|
features.push({
|
|
@@ -23531,7 +23737,7 @@ var init_audit_trail = __esm({
|
|
|
23531
23737
|
});
|
|
23532
23738
|
|
|
23533
23739
|
// src/validation-engine.ts
|
|
23534
|
-
import { existsSync as
|
|
23740
|
+
import { existsSync as existsSync36, readFileSync as readFileSync36 } from "fs";
|
|
23535
23741
|
function p10(baseName) {
|
|
23536
23742
|
return `${getConfig().toolPrefix}_${baseName}`;
|
|
23537
23743
|
}
|
|
@@ -23562,7 +23768,7 @@ function validateFile(filePath, projectRoot) {
|
|
|
23562
23768
|
});
|
|
23563
23769
|
return checks;
|
|
23564
23770
|
}
|
|
23565
|
-
if (!
|
|
23771
|
+
if (!existsSync36(absPath)) {
|
|
23566
23772
|
checks.push({
|
|
23567
23773
|
name: "file_exists",
|
|
23568
23774
|
severity: "error",
|
|
@@ -24016,7 +24222,7 @@ var init_adr_generator = __esm({
|
|
|
24016
24222
|
});
|
|
24017
24223
|
|
|
24018
24224
|
// src/security-scorer.ts
|
|
24019
|
-
import { existsSync as
|
|
24225
|
+
import { existsSync as existsSync37, readFileSync as readFileSync37 } from "fs";
|
|
24020
24226
|
function p12(baseName) {
|
|
24021
24227
|
return `${getConfig().toolPrefix}_${baseName}`;
|
|
24022
24228
|
}
|
|
@@ -24040,7 +24246,7 @@ function scoreFileSecurity(filePath, projectRoot) {
|
|
|
24040
24246
|
}]
|
|
24041
24247
|
};
|
|
24042
24248
|
}
|
|
24043
|
-
if (!
|
|
24249
|
+
if (!existsSync37(absPath)) {
|
|
24044
24250
|
return { riskScore: 0, findings: [] };
|
|
24045
24251
|
}
|
|
24046
24252
|
let source;
|
|
@@ -24334,8 +24540,8 @@ var init_security_scorer = __esm({
|
|
|
24334
24540
|
});
|
|
24335
24541
|
|
|
24336
24542
|
// src/dependency-scorer.ts
|
|
24337
|
-
import { existsSync as
|
|
24338
|
-
import { resolve as
|
|
24543
|
+
import { existsSync as existsSync38, readFileSync as readFileSync38 } from "fs";
|
|
24544
|
+
import { resolve as resolve33 } from "path";
|
|
24339
24545
|
function p13(baseName) {
|
|
24340
24546
|
return `${getConfig().toolPrefix}_${baseName}`;
|
|
24341
24547
|
}
|
|
@@ -24367,8 +24573,8 @@ function calculateDepRisk(factors) {
|
|
|
24367
24573
|
return Math.min(100, risk);
|
|
24368
24574
|
}
|
|
24369
24575
|
function getInstalledPackages(projectRoot) {
|
|
24370
|
-
const pkgPath =
|
|
24371
|
-
if (!
|
|
24576
|
+
const pkgPath = resolve33(projectRoot, "package.json");
|
|
24577
|
+
if (!existsSync38(pkgPath)) return /* @__PURE__ */ new Map();
|
|
24372
24578
|
try {
|
|
24373
24579
|
const pkg = JSON.parse(readFileSync38(pkgPath, "utf-8"));
|
|
24374
24580
|
const packages = /* @__PURE__ */ new Map();
|
|
@@ -24973,8 +25179,8 @@ var init_regression_detector = __esm({
|
|
|
24973
25179
|
|
|
24974
25180
|
// src/knowledge-indexer.ts
|
|
24975
25181
|
import { createHash as createHash9 } from "crypto";
|
|
24976
|
-
import { readFileSync as readFileSync39, readdirSync as readdirSync24, statSync as statSync14, existsSync as
|
|
24977
|
-
import { resolve as
|
|
25182
|
+
import { readFileSync as readFileSync39, readdirSync as readdirSync24, statSync as statSync14, existsSync as existsSync39 } from "fs";
|
|
25183
|
+
import { resolve as resolve34, relative as relative12, basename as basename8, extname as extname2 } from "path";
|
|
24978
25184
|
function getKnowledgePaths() {
|
|
24979
25185
|
const resolved = getResolvedPaths();
|
|
24980
25186
|
const config = getConfig();
|
|
@@ -25002,7 +25208,7 @@ function discoverMarkdownFiles(baseDir) {
|
|
|
25002
25208
|
try {
|
|
25003
25209
|
const entries = readdirSync24(dir, { withFileTypes: true });
|
|
25004
25210
|
for (const entry of entries) {
|
|
25005
|
-
const fullPath =
|
|
25211
|
+
const fullPath = resolve34(dir, entry.name);
|
|
25006
25212
|
if (entry.isDirectory()) {
|
|
25007
25213
|
if (entry.name === "archive" && dir.includes("session-state")) continue;
|
|
25008
25214
|
if (entry.name === "archive" && dir.includes("status")) continue;
|
|
@@ -25280,11 +25486,11 @@ function indexAllKnowledge(db) {
|
|
|
25280
25486
|
files.push(...memFiles);
|
|
25281
25487
|
} catch {
|
|
25282
25488
|
}
|
|
25283
|
-
if (
|
|
25489
|
+
if (existsSync39(paths.plansDir)) {
|
|
25284
25490
|
const planFiles = discoverMarkdownFiles(paths.plansDir);
|
|
25285
25491
|
files.push(...planFiles);
|
|
25286
25492
|
}
|
|
25287
|
-
if (
|
|
25493
|
+
if (existsSync39(paths.docsDir)) {
|
|
25288
25494
|
const excludePatterns = getConfig().conventions?.excludePatterns ?? ["/ARCHIVE/", "/SESSION-HISTORY/"];
|
|
25289
25495
|
const docsFiles = discoverMarkdownFiles(paths.docsDir).filter((f2) => !f2.includes("/plans/") && !excludePatterns.some((p19) => f2.includes(p19)));
|
|
25290
25496
|
files.push(...docsFiles);
|
|
@@ -25327,7 +25533,7 @@ function indexAllKnowledge(db) {
|
|
|
25327
25533
|
} catch {
|
|
25328
25534
|
}
|
|
25329
25535
|
for (const filePath of files) {
|
|
25330
|
-
if (!
|
|
25536
|
+
if (!existsSync39(filePath)) continue;
|
|
25331
25537
|
const content = readFileSync39(filePath, "utf-8");
|
|
25332
25538
|
const hash = hashContent2(content);
|
|
25333
25539
|
const relPath = filePath.startsWith(paths.claudeDir) ? relative12(paths.claudeDir, filePath) : filePath.startsWith(paths.plansDir) ? "plans/" + relative12(paths.plansDir, filePath) : filePath.startsWith(paths.docsDir) ? "docs/" + relative12(paths.docsDir, filePath) : filePath.startsWith(paths.memoryDir) ? `memory/${relative12(paths.memoryDir, filePath)}` : basename8(filePath);
|
|
@@ -25448,10 +25654,10 @@ function isKnowledgeStale(db) {
|
|
|
25448
25654
|
files.push(...discoverMarkdownFiles(paths.memoryDir));
|
|
25449
25655
|
} catch {
|
|
25450
25656
|
}
|
|
25451
|
-
if (
|
|
25657
|
+
if (existsSync39(paths.plansDir)) {
|
|
25452
25658
|
files.push(...discoverMarkdownFiles(paths.plansDir));
|
|
25453
25659
|
}
|
|
25454
|
-
if (
|
|
25660
|
+
if (existsSync39(paths.docsDir)) {
|
|
25455
25661
|
const excludePatterns = getConfig().conventions?.excludePatterns ?? ["/ARCHIVE/", "/SESSION-HISTORY/"];
|
|
25456
25662
|
const docsFiles = discoverMarkdownFiles(paths.docsDir).filter((f2) => !f2.includes("/plans/") && !excludePatterns.some((p19) => f2.includes(p19)));
|
|
25457
25663
|
files.push(...docsFiles);
|
|
@@ -25481,7 +25687,7 @@ var init_knowledge_indexer = __esm({
|
|
|
25481
25687
|
|
|
25482
25688
|
// src/knowledge-tools.ts
|
|
25483
25689
|
import { readFileSync as readFileSync40, writeFileSync as writeFileSync5, appendFileSync as appendFileSync2, readdirSync as readdirSync25 } from "fs";
|
|
25484
|
-
import { resolve as
|
|
25690
|
+
import { resolve as resolve35, basename as basename9 } from "path";
|
|
25485
25691
|
function p16(baseName) {
|
|
25486
25692
|
return `${getConfig().toolPrefix}_${baseName}`;
|
|
25487
25693
|
}
|
|
@@ -26218,7 +26424,7 @@ function handleCorrect(db, args2) {
|
|
|
26218
26424
|
if (!wrong || !correction || !rule) {
|
|
26219
26425
|
return text15("Error: wrong, correction, and rule are all required.");
|
|
26220
26426
|
}
|
|
26221
|
-
const correctionsPath =
|
|
26427
|
+
const correctionsPath = resolve35(getResolvedPaths().memoryDir, "corrections.md");
|
|
26222
26428
|
const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
26223
26429
|
const title = rule.slice(0, 60);
|
|
26224
26430
|
const entry = `
|
|
@@ -26569,12 +26775,12 @@ var init_knowledge_tools = __esm({
|
|
|
26569
26775
|
|
|
26570
26776
|
// src/knowledge-db.ts
|
|
26571
26777
|
import Database3 from "better-sqlite3";
|
|
26572
|
-
import { dirname as
|
|
26573
|
-
import { existsSync as
|
|
26778
|
+
import { dirname as dirname17 } from "path";
|
|
26779
|
+
import { existsSync as existsSync41, mkdirSync as mkdirSync11 } from "fs";
|
|
26574
26780
|
function getKnowledgeDb() {
|
|
26575
26781
|
const dbPath = getResolvedPaths().knowledgeDbPath;
|
|
26576
|
-
const dir =
|
|
26577
|
-
if (!
|
|
26782
|
+
const dir = dirname17(dbPath);
|
|
26783
|
+
if (!existsSync41(dir)) {
|
|
26578
26784
|
mkdirSync11(dir, { recursive: true });
|
|
26579
26785
|
}
|
|
26580
26786
|
const db = new Database3(dbPath);
|
|
@@ -27308,8 +27514,8 @@ var init_python_tools = __esm({
|
|
|
27308
27514
|
});
|
|
27309
27515
|
|
|
27310
27516
|
// src/tools.ts
|
|
27311
|
-
import { readFileSync as readFileSync41, existsSync as
|
|
27312
|
-
import { resolve as
|
|
27517
|
+
import { readFileSync as readFileSync41, existsSync as existsSync42 } from "fs";
|
|
27518
|
+
import { resolve as resolve36, basename as basename10 } from "path";
|
|
27313
27519
|
function prefix2() {
|
|
27314
27520
|
return getConfig().toolPrefix;
|
|
27315
27521
|
}
|
|
@@ -27344,7 +27550,7 @@ function ensureIndexes(dataDb, codegraphDb, force = false) {
|
|
|
27344
27550
|
if (config.python?.root) {
|
|
27345
27551
|
const pythonRoot = config.python.root;
|
|
27346
27552
|
const excludeDirs = config.python.exclude_dirs || ["__pycache__", ".venv", "venv", ".mypy_cache", ".pytest_cache"];
|
|
27347
|
-
if (force || isPythonDataStale(dataDb,
|
|
27553
|
+
if (force || isPythonDataStale(dataDb, resolve36(getProjectRoot(), pythonRoot))) {
|
|
27348
27554
|
const pyImports = buildPythonImportIndex(dataDb, pythonRoot, excludeDirs);
|
|
27349
27555
|
results.push(`Python imports: ${pyImports}`);
|
|
27350
27556
|
const pyRoutes = buildPythonRouteIndex(dataDb, pythonRoot, excludeDirs);
|
|
@@ -27779,8 +27985,8 @@ function handleContext(file, dataDb, codegraphDb) {
|
|
|
27779
27985
|
try {
|
|
27780
27986
|
const resolvedPaths = getResolvedPaths();
|
|
27781
27987
|
const root = getProjectRoot();
|
|
27782
|
-
const absFilePath = ensureWithinRoot(
|
|
27783
|
-
if (
|
|
27988
|
+
const absFilePath = ensureWithinRoot(resolve36(resolvedPaths.srcDir, "..", file), root);
|
|
27989
|
+
if (existsSync42(absFilePath)) {
|
|
27784
27990
|
const fileContent = readFileSync41(absFilePath, "utf-8").slice(0, 3e3);
|
|
27785
27991
|
const keywords = [];
|
|
27786
27992
|
if (fileContent.includes("ctx.db")) keywords.push("database", "schema");
|
|
@@ -28205,8 +28411,8 @@ function handleSchema(args2) {
|
|
|
28205
28411
|
lines.push("Checking all column references against Prisma schema...");
|
|
28206
28412
|
lines.push("");
|
|
28207
28413
|
const projectRoot = getProjectRoot();
|
|
28208
|
-
const absPath = ensureWithinRoot(
|
|
28209
|
-
if (!
|
|
28414
|
+
const absPath = ensureWithinRoot(resolve36(projectRoot, file), projectRoot);
|
|
28415
|
+
if (!existsSync42(absPath)) {
|
|
28210
28416
|
return text17(`File not found: ${file}`);
|
|
28211
28417
|
}
|
|
28212
28418
|
const source = readFileSync41(absPath, "utf-8");
|
|
@@ -28579,8 +28785,8 @@ var init_server_dispatch = __esm({
|
|
|
28579
28785
|
// src/server.ts
|
|
28580
28786
|
var server_exports = {};
|
|
28581
28787
|
import { readFileSync as readFileSync42 } from "fs";
|
|
28582
|
-
import { resolve as
|
|
28583
|
-
import { fileURLToPath as
|
|
28788
|
+
import { resolve as resolve37, dirname as dirname18 } from "path";
|
|
28789
|
+
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
28584
28790
|
function pruneMemoryOnStartup() {
|
|
28585
28791
|
try {
|
|
28586
28792
|
const memDb = getMemoryDb();
|
|
@@ -28604,17 +28810,17 @@ function pruneMemoryOnStartup() {
|
|
|
28604
28810
|
);
|
|
28605
28811
|
}
|
|
28606
28812
|
}
|
|
28607
|
-
var
|
|
28813
|
+
var __dirname5, PKG_VERSION, dispatcher, buffer;
|
|
28608
28814
|
var init_server = __esm({
|
|
28609
28815
|
"src/server.ts"() {
|
|
28610
28816
|
"use strict";
|
|
28611
28817
|
init_memory_db();
|
|
28612
28818
|
init_license();
|
|
28613
28819
|
init_server_dispatch();
|
|
28614
|
-
|
|
28820
|
+
__dirname5 = dirname18(fileURLToPath5(import.meta.url));
|
|
28615
28821
|
PKG_VERSION = (() => {
|
|
28616
28822
|
try {
|
|
28617
|
-
const pkg = JSON.parse(readFileSync42(
|
|
28823
|
+
const pkg = JSON.parse(readFileSync42(resolve37(__dirname5, "..", "package.json"), "utf-8"));
|
|
28618
28824
|
return pkg.version ?? "0.0.0";
|
|
28619
28825
|
} catch {
|
|
28620
28826
|
return "0.0.0";
|
|
@@ -28900,19 +29106,19 @@ var config_upgrade_exports = {};
|
|
|
28900
29106
|
__export(config_upgrade_exports, {
|
|
28901
29107
|
runConfigUpgrade: () => runConfigUpgrade
|
|
28902
29108
|
});
|
|
28903
|
-
import { existsSync as
|
|
28904
|
-
import { resolve as
|
|
29109
|
+
import { existsSync as existsSync43, readFileSync as readFileSync43, writeFileSync as writeFileSync6, copyFileSync, unlinkSync as unlinkSync2 } from "fs";
|
|
29110
|
+
import { resolve as resolve38 } from "path";
|
|
28905
29111
|
import { parse as parseYaml6 } from "yaml";
|
|
28906
29112
|
async function runConfigUpgrade(opts = {}) {
|
|
28907
29113
|
const cwd = opts.cwd ?? process.cwd();
|
|
28908
|
-
const configPath =
|
|
29114
|
+
const configPath = resolve38(cwd, "massu.config.yaml");
|
|
28909
29115
|
const bakPath = `${configPath}.bak`;
|
|
28910
29116
|
const log = opts.silent ? () => {
|
|
28911
29117
|
} : (s) => process.stdout.write(s);
|
|
28912
29118
|
const err = opts.silent ? () => {
|
|
28913
29119
|
} : (s) => process.stderr.write(s);
|
|
28914
29120
|
if (opts.rollback) {
|
|
28915
|
-
if (!
|
|
29121
|
+
if (!existsSync43(bakPath)) {
|
|
28916
29122
|
const message = `No backup found at ${bakPath}`;
|
|
28917
29123
|
err(message + "\n");
|
|
28918
29124
|
return { exitCode: 1, action: "none", message };
|
|
@@ -28928,7 +29134,7 @@ async function runConfigUpgrade(opts = {}) {
|
|
|
28928
29134
|
return { exitCode: 2, action: "none", message };
|
|
28929
29135
|
}
|
|
28930
29136
|
}
|
|
28931
|
-
if (!
|
|
29137
|
+
if (!existsSync43(configPath)) {
|
|
28932
29138
|
const message = "massu.config.yaml not found. Run: npx massu init";
|
|
28933
29139
|
err(message + "\n");
|
|
28934
29140
|
return { exitCode: 1, action: "none", message };
|
|
@@ -28992,8 +29198,8 @@ var config_check_drift_exports = {};
|
|
|
28992
29198
|
__export(config_check_drift_exports, {
|
|
28993
29199
|
runConfigCheckDrift: () => runConfigCheckDrift
|
|
28994
29200
|
});
|
|
28995
|
-
import { existsSync as
|
|
28996
|
-
import { resolve as
|
|
29201
|
+
import { existsSync as existsSync44, readFileSync as readFileSync44 } from "fs";
|
|
29202
|
+
import { resolve as resolve39 } from "path";
|
|
28997
29203
|
import { parse as parseYaml7 } from "yaml";
|
|
28998
29204
|
function renderChanges(changes) {
|
|
28999
29205
|
if (changes.length === 0) return "(none)\n";
|
|
@@ -29001,12 +29207,12 @@ function renderChanges(changes) {
|
|
|
29001
29207
|
}
|
|
29002
29208
|
async function runConfigCheckDrift(opts = {}) {
|
|
29003
29209
|
const cwd = opts.cwd ?? process.cwd();
|
|
29004
|
-
const configPath =
|
|
29210
|
+
const configPath = resolve39(cwd, "massu.config.yaml");
|
|
29005
29211
|
const log = opts.silent ? () => {
|
|
29006
29212
|
} : (s) => process.stdout.write(s);
|
|
29007
29213
|
const err = opts.silent ? () => {
|
|
29008
29214
|
} : (s) => process.stderr.write(s);
|
|
29009
|
-
if (!
|
|
29215
|
+
if (!existsSync44(configPath)) {
|
|
29010
29216
|
const message = "massu.config.yaml not found. Run: npx massu init";
|
|
29011
29217
|
err(message + "\n");
|
|
29012
29218
|
return {
|
|
@@ -29088,10 +29294,10 @@ var init_config_check_drift = __esm({
|
|
|
29088
29294
|
|
|
29089
29295
|
// src/cli.ts
|
|
29090
29296
|
import { readFileSync as readFileSync45 } from "fs";
|
|
29091
|
-
import { resolve as
|
|
29092
|
-
import { fileURLToPath as
|
|
29093
|
-
var
|
|
29094
|
-
var
|
|
29297
|
+
import { resolve as resolve40, dirname as dirname19 } from "path";
|
|
29298
|
+
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
29299
|
+
var __filename5 = fileURLToPath6(import.meta.url);
|
|
29300
|
+
var __dirname6 = dirname19(__filename5);
|
|
29095
29301
|
var args = process.argv.slice(2);
|
|
29096
29302
|
var subcommand = args[0];
|
|
29097
29303
|
async function main() {
|
|
@@ -29111,6 +29317,12 @@ async function main() {
|
|
|
29111
29317
|
await runInstallHooks2();
|
|
29112
29318
|
break;
|
|
29113
29319
|
}
|
|
29320
|
+
case "hook-runner": {
|
|
29321
|
+
const { runHookRunner: runHookRunner2 } = await Promise.resolve().then(() => (init_hook_runner(), hook_runner_exports));
|
|
29322
|
+
const result = await runHookRunner2(args.slice(1));
|
|
29323
|
+
process.exit(result.exitCode);
|
|
29324
|
+
return;
|
|
29325
|
+
}
|
|
29114
29326
|
case "install-commands": {
|
|
29115
29327
|
const { runInstallCommands: runInstallCommands2 } = await Promise.resolve().then(() => (init_install_commands(), install_commands_exports));
|
|
29116
29328
|
await runInstallCommands2();
|
|
@@ -29287,7 +29499,7 @@ Examples:
|
|
|
29287
29499
|
}
|
|
29288
29500
|
function printVersion() {
|
|
29289
29501
|
try {
|
|
29290
|
-
const pkg = JSON.parse(readFileSync45(
|
|
29502
|
+
const pkg = JSON.parse(readFileSync45(resolve40(__dirname6, "../package.json"), "utf-8"));
|
|
29291
29503
|
console.log(`massu v${pkg.version}`);
|
|
29292
29504
|
} catch {
|
|
29293
29505
|
console.log("massu v0.1.0");
|