@massu/core 1.8.0 → 1.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -0
- package/commands/massu-release.md +23 -1
- package/dist/cli.js +514 -268
- package/package.json +1 -1
- package/src/changelog-generator.ts +178 -0
- package/src/cli.ts +7 -0
- package/src/commands/changelog.ts +165 -0
- package/src/security/registry-pubkey.generated.ts +1 -1
package/dist/cli.js
CHANGED
|
@@ -8045,41 +8045,41 @@ var require_queue = __commonJS({
|
|
|
8045
8045
|
queue.drained = drained;
|
|
8046
8046
|
return queue;
|
|
8047
8047
|
function push(value) {
|
|
8048
|
-
var p19 = new Promise(function(
|
|
8048
|
+
var p19 = new Promise(function(resolve40, reject) {
|
|
8049
8049
|
pushCb(value, function(err, result) {
|
|
8050
8050
|
if (err) {
|
|
8051
8051
|
reject(err);
|
|
8052
8052
|
return;
|
|
8053
8053
|
}
|
|
8054
|
-
|
|
8054
|
+
resolve40(result);
|
|
8055
8055
|
});
|
|
8056
8056
|
});
|
|
8057
8057
|
p19.catch(noop);
|
|
8058
8058
|
return p19;
|
|
8059
8059
|
}
|
|
8060
8060
|
function unshift(value) {
|
|
8061
|
-
var p19 = new Promise(function(
|
|
8061
|
+
var p19 = new Promise(function(resolve40, reject) {
|
|
8062
8062
|
unshiftCb(value, function(err, result) {
|
|
8063
8063
|
if (err) {
|
|
8064
8064
|
reject(err);
|
|
8065
8065
|
return;
|
|
8066
8066
|
}
|
|
8067
|
-
|
|
8067
|
+
resolve40(result);
|
|
8068
8068
|
});
|
|
8069
8069
|
});
|
|
8070
8070
|
p19.catch(noop);
|
|
8071
8071
|
return p19;
|
|
8072
8072
|
}
|
|
8073
8073
|
function drained() {
|
|
8074
|
-
var p19 = new Promise(function(
|
|
8074
|
+
var p19 = new Promise(function(resolve40) {
|
|
8075
8075
|
process.nextTick(function() {
|
|
8076
8076
|
if (queue.idle()) {
|
|
8077
|
-
|
|
8077
|
+
resolve40();
|
|
8078
8078
|
} else {
|
|
8079
8079
|
var previousDrain = queue.drain;
|
|
8080
8080
|
queue.drain = function() {
|
|
8081
8081
|
if (typeof previousDrain === "function") previousDrain();
|
|
8082
|
-
|
|
8082
|
+
resolve40();
|
|
8083
8083
|
queue.drain = previousDrain;
|
|
8084
8084
|
};
|
|
8085
8085
|
}
|
|
@@ -8565,9 +8565,9 @@ var require_stream3 = __commonJS({
|
|
|
8565
8565
|
});
|
|
8566
8566
|
}
|
|
8567
8567
|
_getStat(filepath) {
|
|
8568
|
-
return new Promise((
|
|
8568
|
+
return new Promise((resolve40, reject) => {
|
|
8569
8569
|
this._stat(filepath, this._fsStatSettings, (error, stats) => {
|
|
8570
|
-
return error === null ?
|
|
8570
|
+
return error === null ? resolve40(stats) : reject(error);
|
|
8571
8571
|
});
|
|
8572
8572
|
});
|
|
8573
8573
|
}
|
|
@@ -8591,10 +8591,10 @@ var require_async5 = __commonJS({
|
|
|
8591
8591
|
this._readerStream = new stream_1.default(this._settings);
|
|
8592
8592
|
}
|
|
8593
8593
|
dynamic(root, options) {
|
|
8594
|
-
return new Promise((
|
|
8594
|
+
return new Promise((resolve40, reject) => {
|
|
8595
8595
|
this._walkAsync(root, options, (error, entries) => {
|
|
8596
8596
|
if (error === null) {
|
|
8597
|
-
|
|
8597
|
+
resolve40(entries);
|
|
8598
8598
|
} else {
|
|
8599
8599
|
reject(error);
|
|
8600
8600
|
}
|
|
@@ -8604,10 +8604,10 @@ var require_async5 = __commonJS({
|
|
|
8604
8604
|
async static(patterns, options) {
|
|
8605
8605
|
const entries = [];
|
|
8606
8606
|
const stream = this._readerStream.static(patterns, options);
|
|
8607
|
-
return new Promise((
|
|
8607
|
+
return new Promise((resolve40, reject) => {
|
|
8608
8608
|
stream.once("error", reject);
|
|
8609
8609
|
stream.on("data", (entry) => entries.push(entry));
|
|
8610
|
-
stream.once("end", () =>
|
|
8610
|
+
stream.once("end", () => resolve40(entries));
|
|
8611
8611
|
});
|
|
8612
8612
|
}
|
|
8613
8613
|
};
|
|
@@ -14883,13 +14883,252 @@ var init_permissions2 = __esm({
|
|
|
14883
14883
|
}
|
|
14884
14884
|
});
|
|
14885
14885
|
|
|
14886
|
+
// src/changelog-generator.ts
|
|
14887
|
+
import { existsSync as existsSync13, readFileSync as readFileSync13, readdirSync as readdirSync12 } from "fs";
|
|
14888
|
+
import { resolve as resolve10 } from "path";
|
|
14889
|
+
function parseCommitsForPlanTokens(subjects) {
|
|
14890
|
+
const tokens = /* @__PURE__ */ new Set();
|
|
14891
|
+
const maintenance = [];
|
|
14892
|
+
for (const subject of subjects) {
|
|
14893
|
+
const m3 = subject.match(PLAN_TOKEN_RE);
|
|
14894
|
+
if (m3 && m3[2]) {
|
|
14895
|
+
tokens.add(m3[2]);
|
|
14896
|
+
} else {
|
|
14897
|
+
maintenance.push(subject);
|
|
14898
|
+
}
|
|
14899
|
+
}
|
|
14900
|
+
return { tokens, maintenance };
|
|
14901
|
+
}
|
|
14902
|
+
function loadPlanSummaries(tokens, planDir) {
|
|
14903
|
+
const result = /* @__PURE__ */ new Map();
|
|
14904
|
+
if (tokens.size === 0) return result;
|
|
14905
|
+
if (!existsSync13(planDir)) {
|
|
14906
|
+
throw new Error(`Plan directory does not exist: ${planDir}`);
|
|
14907
|
+
}
|
|
14908
|
+
const files = readdirSync12(planDir).filter((f2) => f2.endsWith(".md"));
|
|
14909
|
+
for (const token of tokens) {
|
|
14910
|
+
let matchedFile = null;
|
|
14911
|
+
let content = "";
|
|
14912
|
+
for (const file of files) {
|
|
14913
|
+
const path = resolve10(planDir, file);
|
|
14914
|
+
const text18 = readFileSync13(path, "utf-8");
|
|
14915
|
+
const tokenRe = new RegExp(
|
|
14916
|
+
`^\\*\\*Plan Token\\*\\*:\\s*\`?${token.replace(/[.*+?^${}()|[\\]\\\\]/g, "\\$&")}\`?(\\s|$)`,
|
|
14917
|
+
"m"
|
|
14918
|
+
);
|
|
14919
|
+
if (tokenRe.test(text18)) {
|
|
14920
|
+
matchedFile = file;
|
|
14921
|
+
content = text18;
|
|
14922
|
+
break;
|
|
14923
|
+
}
|
|
14924
|
+
}
|
|
14925
|
+
if (!matchedFile) {
|
|
14926
|
+
throw new MissingPlanFileError(token);
|
|
14927
|
+
}
|
|
14928
|
+
const titleMatch = content.match(/^# (.+)$/m);
|
|
14929
|
+
const title = titleMatch ? titleMatch[1].trim() : token;
|
|
14930
|
+
const sectionRe = /^## Changelog Summary\s*\n([\s\S]*?)(?=\n## |\n---|\n# |$)/m;
|
|
14931
|
+
const sectionMatch = content.match(sectionRe);
|
|
14932
|
+
if (!sectionMatch || !sectionMatch[1].trim()) {
|
|
14933
|
+
throw new MissingChangelogSummaryError(token, matchedFile);
|
|
14934
|
+
}
|
|
14935
|
+
const summary = sectionMatch[1].trim();
|
|
14936
|
+
result.set(token, { title, summary });
|
|
14937
|
+
}
|
|
14938
|
+
return result;
|
|
14939
|
+
}
|
|
14940
|
+
function generateChangelogEntry(opts) {
|
|
14941
|
+
const parts = [];
|
|
14942
|
+
parts.push(`## [${opts.version}] - ${opts.date}
|
|
14943
|
+
`);
|
|
14944
|
+
parts.push("");
|
|
14945
|
+
for (const [, planSum] of opts.planSummaries) {
|
|
14946
|
+
parts.push(planSum.summary);
|
|
14947
|
+
parts.push("");
|
|
14948
|
+
}
|
|
14949
|
+
if (opts.maintenance.length > 0) {
|
|
14950
|
+
parts.push("### Maintenance");
|
|
14951
|
+
parts.push("");
|
|
14952
|
+
for (const subject of opts.maintenance) {
|
|
14953
|
+
parts.push(`- ${subject}`);
|
|
14954
|
+
}
|
|
14955
|
+
parts.push("");
|
|
14956
|
+
}
|
|
14957
|
+
return parts.join("\n") + "\n";
|
|
14958
|
+
}
|
|
14959
|
+
function findCoverageGaps(entryText, tokens) {
|
|
14960
|
+
const gaps = [];
|
|
14961
|
+
for (const token of tokens) {
|
|
14962
|
+
if (!entryText.includes(token)) {
|
|
14963
|
+
gaps.push(token);
|
|
14964
|
+
}
|
|
14965
|
+
}
|
|
14966
|
+
return gaps;
|
|
14967
|
+
}
|
|
14968
|
+
var PLAN_TOKEN_RE, MissingPlanFileError, MissingChangelogSummaryError;
|
|
14969
|
+
var init_changelog_generator = __esm({
|
|
14970
|
+
"src/changelog-generator.ts"() {
|
|
14971
|
+
"use strict";
|
|
14972
|
+
PLAN_TOKEN_RE = /^(feat|fix|chore|docs)\((plan-[a-z0-9._-]+)\)/;
|
|
14973
|
+
MissingPlanFileError = class extends Error {
|
|
14974
|
+
constructor(token) {
|
|
14975
|
+
super(`No plan file found in plans directory matching Plan Token: ${token}`);
|
|
14976
|
+
this.name = "MissingPlanFileError";
|
|
14977
|
+
}
|
|
14978
|
+
};
|
|
14979
|
+
MissingChangelogSummaryError = class extends Error {
|
|
14980
|
+
constructor(token, planFile) {
|
|
14981
|
+
super(`Plan file ${planFile} for token ${token} has no '## Changelog Summary' section`);
|
|
14982
|
+
this.name = "MissingChangelogSummaryError";
|
|
14983
|
+
}
|
|
14984
|
+
};
|
|
14985
|
+
}
|
|
14986
|
+
});
|
|
14987
|
+
|
|
14988
|
+
// src/commands/changelog.ts
|
|
14989
|
+
var changelog_exports = {};
|
|
14990
|
+
__export(changelog_exports, {
|
|
14991
|
+
handleChangelogSubcommand: () => handleChangelogSubcommand,
|
|
14992
|
+
printChangelogHelp: () => printChangelogHelp
|
|
14993
|
+
});
|
|
14994
|
+
import { execSync } from "child_process";
|
|
14995
|
+
import { existsSync as existsSync14, readFileSync as readFileSync14 } from "fs";
|
|
14996
|
+
import { resolve as resolve11 } from "path";
|
|
14997
|
+
function resolveRepoRoot() {
|
|
14998
|
+
try {
|
|
14999
|
+
return execSync("git rev-parse --show-toplevel", { encoding: "utf-8" }).trim();
|
|
15000
|
+
} catch {
|
|
15001
|
+
return process.cwd();
|
|
15002
|
+
}
|
|
15003
|
+
}
|
|
15004
|
+
function getLastTag() {
|
|
15005
|
+
try {
|
|
15006
|
+
return execSync("git describe --tags --abbrev=0", { encoding: "utf-8" }).trim();
|
|
15007
|
+
} catch {
|
|
15008
|
+
return null;
|
|
15009
|
+
}
|
|
15010
|
+
}
|
|
15011
|
+
function getCommitSubjects(range) {
|
|
15012
|
+
try {
|
|
15013
|
+
const out = execSync(`git log ${range} --pretty=format:%s`, { encoding: "utf-8" });
|
|
15014
|
+
return out.split("\n").filter((s) => s.length > 0);
|
|
15015
|
+
} catch {
|
|
15016
|
+
return [];
|
|
15017
|
+
}
|
|
15018
|
+
}
|
|
15019
|
+
function getCurrentVersion(repoRoot) {
|
|
15020
|
+
const pkgPath = resolve11(repoRoot, "packages/core/package.json");
|
|
15021
|
+
if (!existsSync14(pkgPath)) return "0.0.0";
|
|
15022
|
+
const pkg = JSON.parse(readFileSync14(pkgPath, "utf-8"));
|
|
15023
|
+
return pkg.version || "0.0.0";
|
|
15024
|
+
}
|
|
15025
|
+
function todayDate() {
|
|
15026
|
+
return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
15027
|
+
}
|
|
15028
|
+
function getLatestChangelogEntryBody(repoRoot) {
|
|
15029
|
+
const path = resolve11(repoRoot, "CHANGELOG.md");
|
|
15030
|
+
if (!existsSync14(path)) return "";
|
|
15031
|
+
const content = readFileSync14(path, "utf-8");
|
|
15032
|
+
const m3 = content.match(/^## \[[\d.]+\][^\n]*\n([\s\S]*?)(?=\n## \[|$)/m);
|
|
15033
|
+
return m3 ? m3[1] : "";
|
|
15034
|
+
}
|
|
15035
|
+
async function handleChangelogSubcommand(args2) {
|
|
15036
|
+
const sub = args2[0];
|
|
15037
|
+
const repoRoot = resolveRepoRoot();
|
|
15038
|
+
const planDir = resolve11(repoRoot, "docs/plans");
|
|
15039
|
+
switch (sub) {
|
|
15040
|
+
case "generate": {
|
|
15041
|
+
const lastTag = getLastTag();
|
|
15042
|
+
const range = lastTag ? `${lastTag}..HEAD` : "HEAD";
|
|
15043
|
+
const subjects = getCommitSubjects(range);
|
|
15044
|
+
const { tokens, maintenance } = parseCommitsForPlanTokens(subjects);
|
|
15045
|
+
let planSummaries;
|
|
15046
|
+
try {
|
|
15047
|
+
planSummaries = loadPlanSummaries(tokens, planDir);
|
|
15048
|
+
} catch (err) {
|
|
15049
|
+
if (err instanceof MissingPlanFileError || err instanceof MissingChangelogSummaryError) {
|
|
15050
|
+
process.stderr.write(`changelog generate: ${err.message}
|
|
15051
|
+
`);
|
|
15052
|
+
return { exitCode: 2 };
|
|
15053
|
+
}
|
|
15054
|
+
throw err;
|
|
15055
|
+
}
|
|
15056
|
+
const entry = generateChangelogEntry({
|
|
15057
|
+
version: getCurrentVersion(repoRoot),
|
|
15058
|
+
date: todayDate(),
|
|
15059
|
+
planSummaries,
|
|
15060
|
+
maintenance
|
|
15061
|
+
});
|
|
15062
|
+
process.stdout.write(entry);
|
|
15063
|
+
return { exitCode: 0 };
|
|
15064
|
+
}
|
|
15065
|
+
case "verify": {
|
|
15066
|
+
const lastTag = getLastTag();
|
|
15067
|
+
const range = lastTag ? `${lastTag}..HEAD` : "HEAD";
|
|
15068
|
+
const subjects = getCommitSubjects(range);
|
|
15069
|
+
const { tokens } = parseCommitsForPlanTokens(subjects);
|
|
15070
|
+
const entryBody = getLatestChangelogEntryBody(repoRoot);
|
|
15071
|
+
const gaps = findCoverageGaps(entryBody, tokens);
|
|
15072
|
+
if (gaps.length === 0) {
|
|
15073
|
+
process.stdout.write("All plan-tokens referenced.\n");
|
|
15074
|
+
return { exitCode: 0 };
|
|
15075
|
+
}
|
|
15076
|
+
for (const t of gaps) {
|
|
15077
|
+
process.stderr.write(`gap: ${t}
|
|
15078
|
+
`);
|
|
15079
|
+
}
|
|
15080
|
+
return { exitCode: 1 };
|
|
15081
|
+
}
|
|
15082
|
+
case "--help":
|
|
15083
|
+
case "-h":
|
|
15084
|
+
case void 0: {
|
|
15085
|
+
printChangelogHelp();
|
|
15086
|
+
return { exitCode: 0 };
|
|
15087
|
+
}
|
|
15088
|
+
default: {
|
|
15089
|
+
process.stderr.write(`massu: unknown changelog subcommand: ${sub}
|
|
15090
|
+
`);
|
|
15091
|
+
printChangelogHelp();
|
|
15092
|
+
return { exitCode: 1 };
|
|
15093
|
+
}
|
|
15094
|
+
}
|
|
15095
|
+
}
|
|
15096
|
+
function printChangelogHelp() {
|
|
15097
|
+
process.stdout.write(`
|
|
15098
|
+
massu changelog <subcommand>
|
|
15099
|
+
|
|
15100
|
+
Subcommands:
|
|
15101
|
+
generate Emit a draft CHANGELOG.md entry to stdout. Reads commit subjects
|
|
15102
|
+
since the last git tag, groups by (plan-<token>) paren-notation,
|
|
15103
|
+
looks up each plan file's ## Changelog Summary section, and emits
|
|
15104
|
+
a Keep-a-Changelog 1.1.0 entry. Operator pipes/copies into
|
|
15105
|
+
CHANGELOG.md (no forced overwrite).
|
|
15106
|
+
|
|
15107
|
+
verify Read-only check that the latest CHANGELOG.md entry references
|
|
15108
|
+
every plan-token in commits since the last tag. Exit 0 if clean,
|
|
15109
|
+
exit 1 with one 'gap: <token>' per missing.
|
|
15110
|
+
|
|
15111
|
+
Examples:
|
|
15112
|
+
npx massu changelog generate > /tmp/draft-entry.md
|
|
15113
|
+
npx massu changelog verify
|
|
15114
|
+
|
|
15115
|
+
Documentation: https://massu.ai/docs/reference/cli-reference#massu-changelog
|
|
15116
|
+
`);
|
|
15117
|
+
}
|
|
15118
|
+
var init_changelog = __esm({
|
|
15119
|
+
"src/commands/changelog.ts"() {
|
|
15120
|
+
"use strict";
|
|
15121
|
+
init_changelog_generator();
|
|
15122
|
+
}
|
|
15123
|
+
});
|
|
15124
|
+
|
|
14886
15125
|
// src/commands/show-template.ts
|
|
14887
15126
|
var show_template_exports = {};
|
|
14888
15127
|
__export(show_template_exports, {
|
|
14889
15128
|
runShowTemplate: () => runShowTemplate
|
|
14890
15129
|
});
|
|
14891
|
-
import { existsSync as
|
|
14892
|
-
import { resolve as
|
|
15130
|
+
import { existsSync as existsSync15, readFileSync as readFileSync15 } from "fs";
|
|
15131
|
+
import { resolve as resolve12 } from "path";
|
|
14893
15132
|
function normalizeBaseName(input) {
|
|
14894
15133
|
return input.endsWith(".md") ? input.slice(0, -".md".length) : input;
|
|
14895
15134
|
}
|
|
@@ -14917,14 +15156,14 @@ async function runShowTemplate(args2) {
|
|
|
14917
15156
|
return;
|
|
14918
15157
|
}
|
|
14919
15158
|
const suffix = choice.kind === "hit" ? choice.suffix : "";
|
|
14920
|
-
const file = suffix === "" ?
|
|
14921
|
-
if (!
|
|
15159
|
+
const file = suffix === "" ? resolve12(sourceDir, `${baseName}.md`) : resolve12(sourceDir, `${baseName}${suffix}.md`);
|
|
15160
|
+
if (!existsSync15(file)) {
|
|
14922
15161
|
process.stderr.write(`massu: resolved template "${file}" no longer exists
|
|
14923
15162
|
`);
|
|
14924
15163
|
process.exit(1);
|
|
14925
15164
|
return;
|
|
14926
15165
|
}
|
|
14927
|
-
process.stdout.write(
|
|
15166
|
+
process.stdout.write(readFileSync15(file, "utf-8"));
|
|
14928
15167
|
}
|
|
14929
15168
|
var init_show_template = __esm({
|
|
14930
15169
|
"src/commands/show-template.ts"() {
|
|
@@ -14977,12 +15216,12 @@ var init_passthrough = __esm({
|
|
|
14977
15216
|
});
|
|
14978
15217
|
|
|
14979
15218
|
// src/lib/fileLock.ts
|
|
14980
|
-
import { mkdirSync as mkdirSync6, readFileSync as
|
|
15219
|
+
import { mkdirSync as mkdirSync6, readFileSync as readFileSync16, rmSync as rmSync3, writeFileSync as writeFileSync3 } from "fs";
|
|
14981
15220
|
import { dirname as dirname8 } from "path";
|
|
14982
15221
|
import * as lockfile from "proper-lockfile";
|
|
14983
15222
|
function readLockHolderPid(lockPath) {
|
|
14984
15223
|
try {
|
|
14985
|
-
const raw =
|
|
15224
|
+
const raw = readFileSync16(`${lockPath}.pid`, "utf-8").trim();
|
|
14986
15225
|
const pid = Number.parseInt(raw, 10);
|
|
14987
15226
|
if (!Number.isFinite(pid) || pid <= 0) return null;
|
|
14988
15227
|
return pid;
|
|
@@ -15069,9 +15308,9 @@ var init_fileLock = __esm({
|
|
|
15069
15308
|
});
|
|
15070
15309
|
|
|
15071
15310
|
// src/lib/installLock.ts
|
|
15072
|
-
import { resolve as
|
|
15311
|
+
import { resolve as resolve13 } from "path";
|
|
15073
15312
|
function withInstallLock(projectRoot, fn, opts = {}) {
|
|
15074
|
-
const lockPath =
|
|
15313
|
+
const lockPath = resolve13(projectRoot, ".massu", "installAll.lock");
|
|
15075
15314
|
return withFileLockSync(
|
|
15076
15315
|
lockPath,
|
|
15077
15316
|
fn,
|
|
@@ -15107,8 +15346,8 @@ __export(config_refresh_exports, {
|
|
|
15107
15346
|
mergeRefresh: () => mergeRefresh,
|
|
15108
15347
|
runConfigRefresh: () => runConfigRefresh
|
|
15109
15348
|
});
|
|
15110
|
-
import { existsSync as
|
|
15111
|
-
import { resolve as
|
|
15349
|
+
import { existsSync as existsSync16, readFileSync as readFileSync17, rmSync as rmSync4 } from "fs";
|
|
15350
|
+
import { resolve as resolve14 } from "path";
|
|
15112
15351
|
import { parse as parseYaml5 } from "yaml";
|
|
15113
15352
|
function flatten(obj, prefix3 = "") {
|
|
15114
15353
|
const out = {};
|
|
@@ -15236,17 +15475,17 @@ function renderDiff(diff) {
|
|
|
15236
15475
|
}
|
|
15237
15476
|
async function runConfigRefresh(opts = {}) {
|
|
15238
15477
|
const cwd = opts.cwd ?? process.cwd();
|
|
15239
|
-
const configPath =
|
|
15478
|
+
const configPath = resolve14(cwd, "massu.config.yaml");
|
|
15240
15479
|
const log = opts.silent ? () => {
|
|
15241
15480
|
} : (s) => process.stdout.write(s);
|
|
15242
|
-
if (!
|
|
15481
|
+
if (!existsSync16(configPath)) {
|
|
15243
15482
|
const message = "massu.config.yaml not found. Run: npx massu init";
|
|
15244
15483
|
if (!opts.silent) process.stderr.write(message + "\n");
|
|
15245
15484
|
return { exitCode: 1, applied: false, dryRun: !!opts.dryRun, diff: [], message };
|
|
15246
15485
|
}
|
|
15247
15486
|
let existing;
|
|
15248
15487
|
try {
|
|
15249
|
-
const content =
|
|
15488
|
+
const content = readFileSync17(configPath, "utf-8");
|
|
15250
15489
|
const parsed = parseYaml5(content);
|
|
15251
15490
|
if (!parsed || typeof parsed !== "object") {
|
|
15252
15491
|
throw new Error("config is not a YAML object");
|
|
@@ -15319,8 +15558,8 @@ async function runConfigRefresh(opts = {}) {
|
|
|
15319
15558
|
`);
|
|
15320
15559
|
const stackResolved = installResult.totalInstalled > 0 || installResult.totalUpdated > 0;
|
|
15321
15560
|
if (stackResolved) {
|
|
15322
|
-
const placeholderPath =
|
|
15323
|
-
if (
|
|
15561
|
+
const placeholderPath = resolve14(installResult.claudeDir, "commands", "_massu-needs-stack.md");
|
|
15562
|
+
if (existsSync16(placeholderPath)) {
|
|
15324
15563
|
try {
|
|
15325
15564
|
rmSync4(placeholderPath, { force: true });
|
|
15326
15565
|
log("Removed _massu-needs-stack.md (stack now declared).\n");
|
|
@@ -15429,12 +15668,12 @@ var init_gitToplevel = __esm({
|
|
|
15429
15668
|
});
|
|
15430
15669
|
|
|
15431
15670
|
// src/watch/lockfile-detector.ts
|
|
15432
|
-
import { existsSync as
|
|
15433
|
-
import { resolve as
|
|
15671
|
+
import { existsSync as existsSync17, statSync as statSync8 } from "fs";
|
|
15672
|
+
import { resolve as resolve15 } from "path";
|
|
15434
15673
|
function lockfileMidWrite(projectRoot, now = Date.now(), windowMs = LOCKFILE_WINDOW_MS) {
|
|
15435
15674
|
for (const lf of KNOWN_LOCKFILES) {
|
|
15436
|
-
const p19 =
|
|
15437
|
-
if (!
|
|
15675
|
+
const p19 = resolve15(projectRoot, lf);
|
|
15676
|
+
if (!existsSync17(p19)) continue;
|
|
15438
15677
|
try {
|
|
15439
15678
|
const stat = statSync8(p19);
|
|
15440
15679
|
const delta = now - stat.mtimeMs;
|
|
@@ -15447,7 +15686,7 @@ function lockfileMidWrite(projectRoot, now = Date.now(), windowMs = LOCKFILE_WIN
|
|
|
15447
15686
|
function gitMidOperation(projectRoot) {
|
|
15448
15687
|
const sentinels = ["MERGE_HEAD", "REBASE_HEAD", "CHERRY_PICK_HEAD", "rebase-apply", "rebase-merge"];
|
|
15449
15688
|
for (const s of sentinels) {
|
|
15450
|
-
if (
|
|
15689
|
+
if (existsSync17(resolve15(projectRoot, ".git", s))) return true;
|
|
15451
15690
|
}
|
|
15452
15691
|
return false;
|
|
15453
15692
|
}
|
|
@@ -15644,18 +15883,18 @@ var init_paths = __esm({
|
|
|
15644
15883
|
});
|
|
15645
15884
|
|
|
15646
15885
|
// src/watch/state.ts
|
|
15647
|
-
import { closeSync as closeSync3, existsSync as
|
|
15648
|
-
import { dirname as dirname9, resolve as
|
|
15886
|
+
import { closeSync as closeSync3, existsSync as existsSync18, 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";
|
|
15887
|
+
import { dirname as dirname9, resolve as resolve16 } from "path";
|
|
15649
15888
|
function watchStatePath(projectRoot) {
|
|
15650
|
-
return
|
|
15889
|
+
return resolve16(projectRoot, ".massu", "watch-state.json");
|
|
15651
15890
|
}
|
|
15652
15891
|
function backupStatePath(projectRoot) {
|
|
15653
|
-
return
|
|
15892
|
+
return resolve16(projectRoot, ".massu", "watch-state.v0.bak.json");
|
|
15654
15893
|
}
|
|
15655
15894
|
function readState(projectRoot) {
|
|
15656
15895
|
const path = watchStatePath(projectRoot);
|
|
15657
|
-
if (!
|
|
15658
|
-
const content =
|
|
15896
|
+
if (!existsSync18(path)) return { ...DEFAULT_STATE };
|
|
15897
|
+
const content = readFileSync18(path, "utf-8");
|
|
15659
15898
|
let raw;
|
|
15660
15899
|
try {
|
|
15661
15900
|
raw = JSON.parse(content);
|
|
@@ -15718,7 +15957,7 @@ function writeStateAtomic(projectRoot, state) {
|
|
|
15718
15957
|
renameSync4(tmp, path);
|
|
15719
15958
|
renamed = true;
|
|
15720
15959
|
} finally {
|
|
15721
|
-
if (!renamed &&
|
|
15960
|
+
if (!renamed && existsSync18(tmp)) {
|
|
15722
15961
|
try {
|
|
15723
15962
|
rmSync5(tmp, { force: true });
|
|
15724
15963
|
} catch {
|
|
@@ -15998,8 +16237,8 @@ __export(watch_exports, {
|
|
|
15998
16237
|
runWatch: () => runWatch
|
|
15999
16238
|
});
|
|
16000
16239
|
import { spawnSync as spawnSync3 } from "child_process";
|
|
16001
|
-
import { basename as basename5, dirname as dirname10, resolve as
|
|
16002
|
-
import { appendFileSync, existsSync as
|
|
16240
|
+
import { basename as basename5, dirname as dirname10, resolve as resolve17 } from "path";
|
|
16241
|
+
import { appendFileSync, existsSync as existsSync19, mkdirSync as mkdirSync8, readFileSync as readFileSync19 } from "fs";
|
|
16003
16242
|
function parseFlags(args2) {
|
|
16004
16243
|
const out = {
|
|
16005
16244
|
foreground: false,
|
|
@@ -16024,8 +16263,8 @@ function parseFlags(args2) {
|
|
|
16024
16263
|
}
|
|
16025
16264
|
function findClaudeBg() {
|
|
16026
16265
|
const home = process.env.HOME ?? "";
|
|
16027
|
-
const fixed = home ?
|
|
16028
|
-
if (fixed &&
|
|
16266
|
+
const fixed = home ? resolve17(home, ".claude", "bin", "claude-bg") : null;
|
|
16267
|
+
if (fixed && existsSync19(fixed)) return fixed;
|
|
16029
16268
|
const which = spawnSync3("which", ["claude-bg"], { encoding: "utf-8" });
|
|
16030
16269
|
if (which.status === 0 && which.stdout) {
|
|
16031
16270
|
const p19 = which.stdout.trim();
|
|
@@ -16086,7 +16325,7 @@ async function runWatch(args2) {
|
|
|
16086
16325
|
}
|
|
16087
16326
|
function runStatus(root) {
|
|
16088
16327
|
const path = watchStatePath(root);
|
|
16089
|
-
if (!
|
|
16328
|
+
if (!existsSync19(path)) {
|
|
16090
16329
|
process.stdout.write("massu watch: not running (no state file)\n");
|
|
16091
16330
|
return { exitCode: 0 };
|
|
16092
16331
|
}
|
|
@@ -16168,7 +16407,7 @@ async function runForeground(root) {
|
|
|
16168
16407
|
}
|
|
16169
16408
|
throw err;
|
|
16170
16409
|
}
|
|
16171
|
-
return new Promise((
|
|
16410
|
+
return new Promise((resolve40) => {
|
|
16172
16411
|
const shutdown = async () => {
|
|
16173
16412
|
if (stopped) return;
|
|
16174
16413
|
stopped = true;
|
|
@@ -16178,7 +16417,7 @@ async function runForeground(root) {
|
|
|
16178
16417
|
process.chdir(priorCwd);
|
|
16179
16418
|
} catch {
|
|
16180
16419
|
}
|
|
16181
|
-
|
|
16420
|
+
resolve40({ exitCode: 0 });
|
|
16182
16421
|
};
|
|
16183
16422
|
process.on("SIGINT", () => {
|
|
16184
16423
|
void shutdown();
|
|
@@ -16239,7 +16478,7 @@ async function runOnQuiescent(projectRoot) {
|
|
|
16239
16478
|
);
|
|
16240
16479
|
}
|
|
16241
16480
|
function refreshLogPath(projectRoot) {
|
|
16242
|
-
return
|
|
16481
|
+
return resolve17(projectRoot, ".massu", "refresh-log.jsonl");
|
|
16243
16482
|
}
|
|
16244
16483
|
function appendRefreshLog(projectRoot, event) {
|
|
16245
16484
|
const path = refreshLogPath(projectRoot);
|
|
@@ -16251,11 +16490,11 @@ function appendRefreshLog(projectRoot, event) {
|
|
|
16251
16490
|
}
|
|
16252
16491
|
function readRefreshLog(projectRoot, limit = 10, opts = {}) {
|
|
16253
16492
|
const path = refreshLogPath(projectRoot);
|
|
16254
|
-
if (!
|
|
16493
|
+
if (!existsSync19(path)) return [];
|
|
16255
16494
|
const warn = opts.warn ?? ((s) => {
|
|
16256
16495
|
process.stderr.write(s);
|
|
16257
16496
|
});
|
|
16258
|
-
const lines =
|
|
16497
|
+
const lines = readFileSync19(path, "utf-8").split("\n").filter(Boolean);
|
|
16259
16498
|
const tail = lines.slice(-limit);
|
|
16260
16499
|
const out = [];
|
|
16261
16500
|
let corrupt = 0;
|
|
@@ -16328,7 +16567,7 @@ var init_refresh_log = __esm({
|
|
|
16328
16567
|
import {
|
|
16329
16568
|
chmodSync as chmodSync3,
|
|
16330
16569
|
closeSync as closeSync4,
|
|
16331
|
-
existsSync as
|
|
16570
|
+
existsSync as existsSync20,
|
|
16332
16571
|
fsyncSync as fsyncSync4,
|
|
16333
16572
|
mkdirSync as mkdirSync9,
|
|
16334
16573
|
openSync as openSync4,
|
|
@@ -16342,7 +16581,7 @@ function atomicWrite(path, content, opts = {}) {
|
|
|
16342
16581
|
const tmpPath = `${path}.tmp`;
|
|
16343
16582
|
const parentDir = dirname11(path);
|
|
16344
16583
|
try {
|
|
16345
|
-
if (!
|
|
16584
|
+
if (!existsSync20(parentDir)) {
|
|
16346
16585
|
const mkdirOpts = { recursive: true };
|
|
16347
16586
|
if (opts.ensureParentDirMode !== void 0) {
|
|
16348
16587
|
mkdirOpts.mode = opts.ensureParentDirMode;
|
|
@@ -16364,7 +16603,7 @@ function atomicWrite(path, content, opts = {}) {
|
|
|
16364
16603
|
renameSync5(tmpPath, path);
|
|
16365
16604
|
return { written: true };
|
|
16366
16605
|
} catch (err) {
|
|
16367
|
-
if (
|
|
16606
|
+
if (existsSync20(tmpPath)) {
|
|
16368
16607
|
try {
|
|
16369
16608
|
rmSync6(tmpPath, { force: true });
|
|
16370
16609
|
} catch {
|
|
@@ -16707,24 +16946,24 @@ var init_fetcher = __esm({
|
|
|
16707
16946
|
});
|
|
16708
16947
|
|
|
16709
16948
|
// src/security/manifest-cache.ts
|
|
16710
|
-
import { existsSync as
|
|
16949
|
+
import { existsSync as existsSync21, readFileSync as readFileSync20, statSync as statSync10 } from "node:fs";
|
|
16711
16950
|
import { homedir as homedir5 } from "node:os";
|
|
16712
|
-
import { resolve as
|
|
16951
|
+
import { resolve as resolve18 } from "node:path";
|
|
16713
16952
|
import { z as z4 } from "zod";
|
|
16714
16953
|
function defaultCachePaths() {
|
|
16715
|
-
const dir =
|
|
16954
|
+
const dir = resolve18(homedir5(), ".massu");
|
|
16716
16955
|
return {
|
|
16717
|
-
cachePath:
|
|
16718
|
-
lockPath:
|
|
16956
|
+
cachePath: resolve18(dir, "adapter-manifest.json"),
|
|
16957
|
+
lockPath: resolve18(dir, ".adapter-manifest.lock")
|
|
16719
16958
|
};
|
|
16720
16959
|
}
|
|
16721
16960
|
function loadCachedManifest(paths = defaultCachePaths()) {
|
|
16722
|
-
if (!
|
|
16961
|
+
if (!existsSync21(paths.cachePath)) {
|
|
16723
16962
|
return { kind: "absent" };
|
|
16724
16963
|
}
|
|
16725
16964
|
let raw;
|
|
16726
16965
|
try {
|
|
16727
|
-
const content =
|
|
16966
|
+
const content = readFileSync20(paths.cachePath, "utf-8");
|
|
16728
16967
|
raw = JSON.parse(content);
|
|
16729
16968
|
} catch (err) {
|
|
16730
16969
|
return {
|
|
@@ -16913,15 +17152,15 @@ var init_adapter_origin = __esm({
|
|
|
16913
17152
|
});
|
|
16914
17153
|
|
|
16915
17154
|
// src/security/local-fingerprint.ts
|
|
16916
|
-
import { existsSync as
|
|
17155
|
+
import { existsSync as existsSync22, readFileSync as readFileSync21, lstatSync as lstatSync5 } from "node:fs";
|
|
16917
17156
|
import { homedir as homedir6 } from "node:os";
|
|
16918
|
-
import { resolve as
|
|
17157
|
+
import { resolve as resolve19, isAbsolute } from "node:path";
|
|
16919
17158
|
import { createHash as createHash7 } from "node:crypto";
|
|
16920
17159
|
import { z as z5 } from "zod";
|
|
16921
17160
|
function computeLocalFingerprint(localPaths, projectRoot) {
|
|
16922
17161
|
const tuples = [];
|
|
16923
17162
|
for (const p19 of localPaths) {
|
|
16924
|
-
const abs = isAbsolute(p19) ? p19 :
|
|
17163
|
+
const abs = isAbsolute(p19) ? p19 : resolve19(projectRoot, p19);
|
|
16925
17164
|
let contentTag;
|
|
16926
17165
|
try {
|
|
16927
17166
|
const lst = lstatSync5(abs);
|
|
@@ -16930,7 +17169,7 @@ function computeLocalFingerprint(localPaths, projectRoot) {
|
|
|
16930
17169
|
} else if (!lst.isFile()) {
|
|
16931
17170
|
contentTag = "<not-a-file>";
|
|
16932
17171
|
} else {
|
|
16933
|
-
contentTag = createHash7("sha256").update(
|
|
17172
|
+
contentTag = createHash7("sha256").update(readFileSync21(abs)).digest("hex");
|
|
16934
17173
|
}
|
|
16935
17174
|
} catch {
|
|
16936
17175
|
contentTag = "<missing>";
|
|
@@ -16942,10 +17181,10 @@ function computeLocalFingerprint(localPaths, projectRoot) {
|
|
|
16942
17181
|
return createHash7("sha256").update(canonical).digest("hex");
|
|
16943
17182
|
}
|
|
16944
17183
|
function readFingerprintSentinel(path = FINGERPRINT_PATH) {
|
|
16945
|
-
if (!
|
|
17184
|
+
if (!existsSync22(path)) return null;
|
|
16946
17185
|
let raw;
|
|
16947
17186
|
try {
|
|
16948
|
-
raw = JSON.parse(
|
|
17187
|
+
raw = JSON.parse(readFileSync21(path, "utf-8"));
|
|
16949
17188
|
} catch {
|
|
16950
17189
|
return null;
|
|
16951
17190
|
}
|
|
@@ -16993,7 +17232,7 @@ var init_local_fingerprint = __esm({
|
|
|
16993
17232
|
"use strict";
|
|
16994
17233
|
init_atomic_write();
|
|
16995
17234
|
init_manifest_schema();
|
|
16996
|
-
FINGERPRINT_PATH =
|
|
17235
|
+
FINGERPRINT_PATH = resolve19(homedir6(), ".massu", "adapters-local-fingerprint.json");
|
|
16997
17236
|
FingerprintSentinelSchema = z5.object({
|
|
16998
17237
|
fingerprint: z5.string().regex(/^[0-9a-f]{64}$/),
|
|
16999
17238
|
source: z5.enum(["cli", "cli-resync"]),
|
|
@@ -17009,15 +17248,15 @@ var init_local_fingerprint = __esm({
|
|
|
17009
17248
|
});
|
|
17010
17249
|
|
|
17011
17250
|
// src/security/install-tracking.ts
|
|
17012
|
-
import { readFileSync as
|
|
17251
|
+
import { readFileSync as readFileSync22, readdirSync as readdirSync13, lstatSync as lstatSync6, existsSync as existsSync23 } from "node:fs";
|
|
17013
17252
|
import { join as join11, relative as relative5, sep } from "node:path";
|
|
17014
17253
|
import { homedir as homedir7 } from "node:os";
|
|
17015
|
-
import { resolve as
|
|
17254
|
+
import { resolve as resolve20 } from "node:path";
|
|
17016
17255
|
import { createHash as createHash8 } from "node:crypto";
|
|
17017
17256
|
import { z as z6 } from "zod";
|
|
17018
17257
|
function containsHiddenDirs(packageDir) {
|
|
17019
17258
|
for (const hidden of EXCLUDED_DIR_NAMES) {
|
|
17020
|
-
if (
|
|
17259
|
+
if (existsSync23(`${packageDir}/${hidden}`)) {
|
|
17021
17260
|
return hidden;
|
|
17022
17261
|
}
|
|
17023
17262
|
}
|
|
@@ -17029,7 +17268,7 @@ function sha256OfDir(dir, opts = {}) {
|
|
|
17029
17268
|
function walk(currentDir) {
|
|
17030
17269
|
let entries;
|
|
17031
17270
|
try {
|
|
17032
|
-
entries =
|
|
17271
|
+
entries = readdirSync13(currentDir);
|
|
17033
17272
|
} catch {
|
|
17034
17273
|
return;
|
|
17035
17274
|
}
|
|
@@ -17063,7 +17302,7 @@ function sha256OfDir(dir, opts = {}) {
|
|
|
17063
17302
|
files.sort((a2, b2) => a2.relativePath < b2.relativePath ? -1 : a2.relativePath > b2.relativePath ? 1 : 0);
|
|
17064
17303
|
const top = createHash8("sha256");
|
|
17065
17304
|
for (const f2 of files) {
|
|
17066
|
-
const fileHash = createHash8("sha256").update(
|
|
17305
|
+
const fileHash = createHash8("sha256").update(readFileSync22(f2.absPath)).digest("hex");
|
|
17067
17306
|
top.update(f2.relativePath, "utf-8");
|
|
17068
17307
|
top.update("\0", "utf-8");
|
|
17069
17308
|
top.update(fileHash, "utf-8");
|
|
@@ -17072,10 +17311,10 @@ function sha256OfDir(dir, opts = {}) {
|
|
|
17072
17311
|
return top.digest("hex");
|
|
17073
17312
|
}
|
|
17074
17313
|
function readInstalledManifest(path = INSTALLED_MANIFEST_PATH) {
|
|
17075
|
-
if (!
|
|
17314
|
+
if (!existsSync23(path)) return {};
|
|
17076
17315
|
let raw;
|
|
17077
17316
|
try {
|
|
17078
|
-
raw = JSON.parse(
|
|
17317
|
+
raw = JSON.parse(readFileSync22(path, "utf-8"));
|
|
17079
17318
|
} catch {
|
|
17080
17319
|
return {};
|
|
17081
17320
|
}
|
|
@@ -17139,7 +17378,7 @@ var init_install_tracking = __esm({
|
|
|
17139
17378
|
"src/security/install-tracking.ts"() {
|
|
17140
17379
|
"use strict";
|
|
17141
17380
|
init_atomic_write();
|
|
17142
|
-
INSTALLED_MANIFEST_PATH =
|
|
17381
|
+
INSTALLED_MANIFEST_PATH = resolve20(homedir7(), ".massu", "adapter-manifest-installed.json");
|
|
17143
17382
|
DEFAULT_MAX_FILE_BYTES = 64 * 1024 * 1024;
|
|
17144
17383
|
EXCLUDED_DIR_NAMES = /* @__PURE__ */ new Set([".git", "node_modules", ".cache", ".tmp"]);
|
|
17145
17384
|
InstallEntrySchema = z6.object({
|
|
@@ -17162,25 +17401,25 @@ var init_install_tracking = __esm({
|
|
|
17162
17401
|
});
|
|
17163
17402
|
|
|
17164
17403
|
// src/detect/adapters/discover.ts
|
|
17165
|
-
import { existsSync as
|
|
17166
|
-
import { resolve as
|
|
17404
|
+
import { existsSync as existsSync24, readdirSync as readdirSync14, readFileSync as readFileSync23, lstatSync as lstatSync7 } from "node:fs";
|
|
17405
|
+
import { resolve as resolve21, isAbsolute as isAbsolute2 } from "node:path";
|
|
17167
17406
|
import { z as z7 } from "zod";
|
|
17168
17407
|
function walkNodeModules(projectRoot, warnings) {
|
|
17169
|
-
const nodeModulesDir =
|
|
17170
|
-
if (!
|
|
17408
|
+
const nodeModulesDir = resolve21(projectRoot, "node_modules");
|
|
17409
|
+
if (!existsSync24(nodeModulesDir)) {
|
|
17171
17410
|
return [];
|
|
17172
17411
|
}
|
|
17173
17412
|
const candidates = [];
|
|
17174
17413
|
let topLevelEntries;
|
|
17175
17414
|
try {
|
|
17176
|
-
topLevelEntries =
|
|
17415
|
+
topLevelEntries = readdirSync14(nodeModulesDir);
|
|
17177
17416
|
} catch (err) {
|
|
17178
17417
|
warnings.push(`failed to read node_modules: ${err instanceof Error ? err.message : String(err)}`);
|
|
17179
17418
|
return [];
|
|
17180
17419
|
}
|
|
17181
17420
|
for (const entry of topLevelEntries) {
|
|
17182
17421
|
if (entry.startsWith(".")) continue;
|
|
17183
|
-
const entryPath =
|
|
17422
|
+
const entryPath = resolve21(nodeModulesDir, entry);
|
|
17184
17423
|
let entryStat;
|
|
17185
17424
|
try {
|
|
17186
17425
|
entryStat = lstatSync7(entryPath);
|
|
@@ -17197,12 +17436,12 @@ function walkNodeModules(projectRoot, warnings) {
|
|
|
17197
17436
|
if (entry.startsWith("@")) {
|
|
17198
17437
|
let scopedEntries;
|
|
17199
17438
|
try {
|
|
17200
|
-
scopedEntries =
|
|
17439
|
+
scopedEntries = readdirSync14(entryPath);
|
|
17201
17440
|
} catch {
|
|
17202
17441
|
continue;
|
|
17203
17442
|
}
|
|
17204
17443
|
for (const sub of scopedEntries) {
|
|
17205
|
-
const subPath =
|
|
17444
|
+
const subPath = resolve21(entryPath, sub);
|
|
17206
17445
|
let subStat;
|
|
17207
17446
|
try {
|
|
17208
17447
|
subStat = lstatSync7(subPath);
|
|
@@ -17221,11 +17460,11 @@ function walkNodeModules(projectRoot, warnings) {
|
|
|
17221
17460
|
return candidates;
|
|
17222
17461
|
}
|
|
17223
17462
|
function tryReadAdapterPackage(packageDir, warnings) {
|
|
17224
|
-
const pkgJsonPath =
|
|
17225
|
-
if (!
|
|
17463
|
+
const pkgJsonPath = resolve21(packageDir, "package.json");
|
|
17464
|
+
if (!existsSync24(pkgJsonPath)) return null;
|
|
17226
17465
|
let raw;
|
|
17227
17466
|
try {
|
|
17228
|
-
raw = JSON.parse(
|
|
17467
|
+
raw = JSON.parse(readFileSync23(pkgJsonPath, "utf-8"));
|
|
17229
17468
|
} catch (err) {
|
|
17230
17469
|
warnings.push(
|
|
17231
17470
|
`skipping ${packageDir}: package.json parse failed (${err instanceof Error ? err.message : String(err)})`
|
|
@@ -17359,8 +17598,8 @@ function discoverAdapters(opts) {
|
|
|
17359
17598
|
const localSet = new Set(opts.configLocalPaths);
|
|
17360
17599
|
for (const localPath of opts.configLocalPaths) {
|
|
17361
17600
|
if (seenIds.has(localPath)) continue;
|
|
17362
|
-
const absPath = isAbsolute2(localPath) ? localPath :
|
|
17363
|
-
if (!
|
|
17601
|
+
const absPath = isAbsolute2(localPath) ? localPath : resolve21(opts.projectRoot, localPath);
|
|
17602
|
+
if (!existsSync24(absPath)) {
|
|
17364
17603
|
warnings.push(
|
|
17365
17604
|
`local adapter file not found: ${localPath} (resolved to ${absPath}). Remove via: massu adapters remove-local ${localPath}`
|
|
17366
17605
|
);
|
|
@@ -17441,8 +17680,8 @@ __export(adapters_exports, {
|
|
|
17441
17680
|
runAdaptersResyncLocalFingerprint: () => runAdaptersResyncLocalFingerprint,
|
|
17442
17681
|
runAdaptersSearch: () => runAdaptersSearch
|
|
17443
17682
|
});
|
|
17444
|
-
import { existsSync as
|
|
17445
|
-
import { resolve as
|
|
17683
|
+
import { existsSync as existsSync25, readFileSync as readFileSync24 } from "node:fs";
|
|
17684
|
+
import { resolve as resolve22 } from "node:path";
|
|
17446
17685
|
import { parseDocument } from "yaml";
|
|
17447
17686
|
async function handleAdaptersSubcommand(args2) {
|
|
17448
17687
|
const sub = args2[0];
|
|
@@ -17709,8 +17948,8 @@ function mutateLocalArray(mutator, command) {
|
|
|
17709
17948
|
);
|
|
17710
17949
|
return { exitCode: 2 };
|
|
17711
17950
|
}
|
|
17712
|
-
const yamlPath =
|
|
17713
|
-
if (!
|
|
17951
|
+
const yamlPath = resolve22(projectRoot, "massu.config.yaml");
|
|
17952
|
+
if (!existsSync25(yamlPath)) {
|
|
17714
17953
|
process.stderr.write(
|
|
17715
17954
|
`${command}: massu.config.yaml not found at ${yamlPath}. Run \`massu init\` first.
|
|
17716
17955
|
`
|
|
@@ -17719,7 +17958,7 @@ function mutateLocalArray(mutator, command) {
|
|
|
17719
17958
|
}
|
|
17720
17959
|
let yamlText;
|
|
17721
17960
|
try {
|
|
17722
|
-
yamlText =
|
|
17961
|
+
yamlText = readFileSync24(yamlPath, "utf-8");
|
|
17723
17962
|
} catch (err) {
|
|
17724
17963
|
process.stderr.write(`${command}: failed to read ${yamlPath}: ${err instanceof Error ? err.message : String(err)}
|
|
17725
17964
|
`);
|
|
@@ -17740,7 +17979,7 @@ function mutateLocalArray(mutator, command) {
|
|
|
17740
17979
|
if (next === null) {
|
|
17741
17980
|
return { exitCode: 0 };
|
|
17742
17981
|
}
|
|
17743
|
-
const lockPath =
|
|
17982
|
+
const lockPath = resolve22(projectRoot, ".massu", "adapters-local-mutate.lock");
|
|
17744
17983
|
return withFileLockSync(lockPath, () => {
|
|
17745
17984
|
doc.setIn(["adapters", "local"], next);
|
|
17746
17985
|
const newYaml = doc.toString();
|
|
@@ -17809,23 +18048,23 @@ async function runAdaptersInstall(args2) {
|
|
|
17809
18048
|
`);
|
|
17810
18049
|
return { exitCode: 1 };
|
|
17811
18050
|
}
|
|
17812
|
-
const packageDir =
|
|
17813
|
-
if (!
|
|
18051
|
+
const packageDir = resolve22(projectRoot, "node_modules", ...packageName.split("/"));
|
|
18052
|
+
if (!existsSync25(packageDir)) {
|
|
17814
18053
|
process.stderr.write(
|
|
17815
18054
|
`install: ${packageName} is not installed in node_modules. Run \`npm install ${packageName}\` first.
|
|
17816
18055
|
`
|
|
17817
18056
|
);
|
|
17818
18057
|
return { exitCode: 1 };
|
|
17819
18058
|
}
|
|
17820
|
-
const pkgJsonPath =
|
|
17821
|
-
if (!
|
|
18059
|
+
const pkgJsonPath = resolve22(packageDir, "package.json");
|
|
18060
|
+
if (!existsSync25(pkgJsonPath)) {
|
|
17822
18061
|
process.stderr.write(`install: ${packageName} has no package.json at ${pkgJsonPath}
|
|
17823
18062
|
`);
|
|
17824
18063
|
return { exitCode: 1 };
|
|
17825
18064
|
}
|
|
17826
18065
|
let pkgJson;
|
|
17827
18066
|
try {
|
|
17828
|
-
pkgJson = JSON.parse(
|
|
18067
|
+
pkgJson = JSON.parse(readFileSync24(pkgJsonPath, "utf-8"));
|
|
17829
18068
|
} catch (err) {
|
|
17830
18069
|
process.stderr.write(`install: ${packageName} has malformed package.json: ${err instanceof Error ? err.message : String(err)}
|
|
17831
18070
|
`);
|
|
@@ -17944,8 +18183,8 @@ async function runAdaptersResign(_args) {
|
|
|
17944
18183
|
removeInstalledManifestEntry(name);
|
|
17945
18184
|
continue;
|
|
17946
18185
|
}
|
|
17947
|
-
const packageDir =
|
|
17948
|
-
if (!
|
|
18186
|
+
const packageDir = resolve22(projectRoot, "node_modules", ...name.split("/"));
|
|
18187
|
+
if (!existsSync25(packageDir)) {
|
|
17949
18188
|
removed++;
|
|
17950
18189
|
warnings.push(`${name}@${entry.version}: not present in node_modules \u2014 REMOVED from sidecar`);
|
|
17951
18190
|
removeInstalledManifestEntry(name);
|
|
@@ -18033,10 +18272,10 @@ var init_adapters2 = __esm({
|
|
|
18033
18272
|
// src/db.ts
|
|
18034
18273
|
import Database2 from "better-sqlite3";
|
|
18035
18274
|
import { dirname as dirname12, join as join12 } from "path";
|
|
18036
|
-
import { existsSync as
|
|
18275
|
+
import { existsSync as existsSync26, mkdirSync as mkdirSync10, readdirSync as readdirSync15, statSync as statSync11 } from "fs";
|
|
18037
18276
|
function getCodeGraphDb() {
|
|
18038
18277
|
const dbPath = getResolvedPaths().codegraphDbPath;
|
|
18039
|
-
if (!
|
|
18278
|
+
if (!existsSync26(dbPath)) {
|
|
18040
18279
|
throw new CodegraphDbNotInitializedError(dbPath);
|
|
18041
18280
|
}
|
|
18042
18281
|
const db = new Database2(dbPath, { readonly: true });
|
|
@@ -18046,7 +18285,7 @@ function getCodeGraphDb() {
|
|
|
18046
18285
|
function getDataDb() {
|
|
18047
18286
|
const dbPath = getResolvedPaths().dataDbPath;
|
|
18048
18287
|
const dir = dirname12(dbPath);
|
|
18049
|
-
if (!
|
|
18288
|
+
if (!existsSync26(dir)) {
|
|
18050
18289
|
mkdirSync10(dir, { recursive: true });
|
|
18051
18290
|
}
|
|
18052
18291
|
const db = new Database2(dbPath);
|
|
@@ -18317,7 +18556,7 @@ function isPythonDataStale(dataDb, pythonRoot) {
|
|
|
18317
18556
|
const lastBuildTime = new Date(lastBuild.value).getTime();
|
|
18318
18557
|
function checkDir(dir) {
|
|
18319
18558
|
try {
|
|
18320
|
-
const entries =
|
|
18559
|
+
const entries = readdirSync15(dir, { withFileTypes: true });
|
|
18321
18560
|
for (const entry of entries) {
|
|
18322
18561
|
const fullPath = join12(dir, entry.name);
|
|
18323
18562
|
if (entry.isDirectory()) {
|
|
@@ -18353,10 +18592,10 @@ var init_db = __esm({
|
|
|
18353
18592
|
});
|
|
18354
18593
|
|
|
18355
18594
|
// src/security-utils.ts
|
|
18356
|
-
import { resolve as
|
|
18595
|
+
import { resolve as resolve23, normalize } from "path";
|
|
18357
18596
|
function ensureWithinRoot(filePath, projectRoot) {
|
|
18358
|
-
const resolvedRoot =
|
|
18359
|
-
const resolvedPath =
|
|
18597
|
+
const resolvedRoot = resolve23(projectRoot);
|
|
18598
|
+
const resolvedPath = resolve23(resolvedRoot, filePath);
|
|
18360
18599
|
const normalizedPath = normalize(resolvedPath);
|
|
18361
18600
|
const normalizedRoot = normalize(resolvedRoot);
|
|
18362
18601
|
if (!normalizedPath.startsWith(normalizedRoot + "/") && normalizedPath !== normalizedRoot) {
|
|
@@ -18429,8 +18668,8 @@ var init_rules = __esm({
|
|
|
18429
18668
|
});
|
|
18430
18669
|
|
|
18431
18670
|
// src/import-resolver.ts
|
|
18432
|
-
import { readFileSync as
|
|
18433
|
-
import { resolve as
|
|
18671
|
+
import { readFileSync as readFileSync25, existsSync as existsSync27, statSync as statSync12 } from "fs";
|
|
18672
|
+
import { resolve as resolve24, dirname as dirname13, join as join13 } from "path";
|
|
18434
18673
|
function parseImports(source) {
|
|
18435
18674
|
const imports = [];
|
|
18436
18675
|
const lines = source.split("\n");
|
|
@@ -18486,23 +18725,23 @@ function resolveImportPath(specifier, fromFile) {
|
|
|
18486
18725
|
let basePath;
|
|
18487
18726
|
if (specifier.startsWith("@/")) {
|
|
18488
18727
|
const paths = getResolvedPaths();
|
|
18489
|
-
basePath =
|
|
18728
|
+
basePath = resolve24(paths.pathAlias["@"] ?? paths.srcDir, specifier.slice(2));
|
|
18490
18729
|
} else {
|
|
18491
|
-
basePath =
|
|
18730
|
+
basePath = resolve24(dirname13(fromFile), specifier);
|
|
18492
18731
|
}
|
|
18493
|
-
if (
|
|
18732
|
+
if (existsSync27(basePath) && !isDirectory(basePath)) {
|
|
18494
18733
|
return toRelative(basePath);
|
|
18495
18734
|
}
|
|
18496
18735
|
const resolvedPaths = getResolvedPaths();
|
|
18497
18736
|
for (const ext of resolvedPaths.extensions) {
|
|
18498
18737
|
const withExt = basePath + ext;
|
|
18499
|
-
if (
|
|
18738
|
+
if (existsSync27(withExt)) {
|
|
18500
18739
|
return toRelative(withExt);
|
|
18501
18740
|
}
|
|
18502
18741
|
}
|
|
18503
18742
|
for (const indexFile of resolvedPaths.indexFiles) {
|
|
18504
18743
|
const indexPath = join13(basePath, indexFile);
|
|
18505
|
-
if (
|
|
18744
|
+
if (existsSync27(indexPath)) {
|
|
18506
18745
|
return toRelative(indexPath);
|
|
18507
18746
|
}
|
|
18508
18747
|
}
|
|
@@ -18538,11 +18777,11 @@ function buildImportIndex(dataDb, codegraphDb) {
|
|
|
18538
18777
|
const batchSize = 500;
|
|
18539
18778
|
let batch = [];
|
|
18540
18779
|
for (const file of files) {
|
|
18541
|
-
const absPath = ensureWithinRoot(
|
|
18542
|
-
if (!
|
|
18780
|
+
const absPath = ensureWithinRoot(resolve24(projectRoot, file.path), projectRoot);
|
|
18781
|
+
if (!existsSync27(absPath)) continue;
|
|
18543
18782
|
let source;
|
|
18544
18783
|
try {
|
|
18545
|
-
source =
|
|
18784
|
+
source = readFileSync25(absPath, "utf-8");
|
|
18546
18785
|
} catch {
|
|
18547
18786
|
continue;
|
|
18548
18787
|
}
|
|
@@ -18578,15 +18817,15 @@ var init_import_resolver = __esm({
|
|
|
18578
18817
|
});
|
|
18579
18818
|
|
|
18580
18819
|
// src/trpc-index.ts
|
|
18581
|
-
import { readFileSync as
|
|
18582
|
-
import { resolve as
|
|
18820
|
+
import { readFileSync as readFileSync26, existsSync as existsSync28, readdirSync as readdirSync16 } from "fs";
|
|
18821
|
+
import { resolve as resolve25, join as join14 } from "path";
|
|
18583
18822
|
function parseRootRouter() {
|
|
18584
18823
|
const paths = getResolvedPaths();
|
|
18585
18824
|
const rootPath = paths.rootRouterPath;
|
|
18586
|
-
if (!
|
|
18825
|
+
if (!existsSync28(rootPath)) {
|
|
18587
18826
|
throw new Error(`Root router not found at ${rootPath}`);
|
|
18588
18827
|
}
|
|
18589
|
-
const source =
|
|
18828
|
+
const source = readFileSync26(rootPath, "utf-8");
|
|
18590
18829
|
const mappings = [];
|
|
18591
18830
|
const importMap = /* @__PURE__ */ new Map();
|
|
18592
18831
|
const importRegex = /import\s+\{[^}]*?(\w+Router)[^}]*\}\s+from\s+['"]\.\/routers\/([^'"]+)['"]/g;
|
|
@@ -18594,16 +18833,16 @@ function parseRootRouter() {
|
|
|
18594
18833
|
while ((match = importRegex.exec(source)) !== null) {
|
|
18595
18834
|
const variable = match[1];
|
|
18596
18835
|
let filePath = match[2];
|
|
18597
|
-
const fullPath =
|
|
18836
|
+
const fullPath = resolve25(paths.routersDir, filePath);
|
|
18598
18837
|
for (const ext of [".ts", ".tsx", ""]) {
|
|
18599
18838
|
const candidate = fullPath + ext;
|
|
18600
18839
|
const routersRelPath = getConfig().paths.routers ?? "src/server/api/routers";
|
|
18601
|
-
if (
|
|
18840
|
+
if (existsSync28(candidate)) {
|
|
18602
18841
|
filePath = routersRelPath + "/" + filePath + ext;
|
|
18603
18842
|
break;
|
|
18604
18843
|
}
|
|
18605
18844
|
const indexCandidate = join14(fullPath, "index.ts");
|
|
18606
|
-
if (
|
|
18845
|
+
if (existsSync28(indexCandidate)) {
|
|
18607
18846
|
filePath = routersRelPath + "/" + filePath + "/index.ts";
|
|
18608
18847
|
break;
|
|
18609
18848
|
}
|
|
@@ -18622,9 +18861,9 @@ function parseRootRouter() {
|
|
|
18622
18861
|
return mappings;
|
|
18623
18862
|
}
|
|
18624
18863
|
function extractProcedures(routerFilePath) {
|
|
18625
|
-
const absPath =
|
|
18626
|
-
if (!
|
|
18627
|
-
const source =
|
|
18864
|
+
const absPath = resolve25(getProjectRoot(), routerFilePath);
|
|
18865
|
+
if (!existsSync28(absPath)) return [];
|
|
18866
|
+
const source = readFileSync26(absPath, "utf-8");
|
|
18628
18867
|
const procedures = [];
|
|
18629
18868
|
const seen = /* @__PURE__ */ new Set();
|
|
18630
18869
|
const procRegex = /(\w+)\s*:\s*(protected|public)Procedure/g;
|
|
@@ -18647,19 +18886,19 @@ function findUICallSites(routerKey, procedureName) {
|
|
|
18647
18886
|
const root = getProjectRoot();
|
|
18648
18887
|
const src = config.paths.source;
|
|
18649
18888
|
const searchDirs = [
|
|
18650
|
-
|
|
18651
|
-
|
|
18652
|
-
|
|
18889
|
+
resolve25(root, config.paths.pages ?? src + "/app"),
|
|
18890
|
+
resolve25(root, config.paths.components ?? src + "/components"),
|
|
18891
|
+
resolve25(root, config.paths.hooks ?? src + "/hooks")
|
|
18653
18892
|
];
|
|
18654
18893
|
const searchPattern = `api.${routerKey}.${procedureName}`;
|
|
18655
18894
|
for (const dir of searchDirs) {
|
|
18656
|
-
if (!
|
|
18895
|
+
if (!existsSync28(dir)) continue;
|
|
18657
18896
|
searchDirectory(dir, searchPattern, callSites);
|
|
18658
18897
|
}
|
|
18659
18898
|
return callSites;
|
|
18660
18899
|
}
|
|
18661
18900
|
function searchDirectory(dir, pattern, results) {
|
|
18662
|
-
const entries =
|
|
18901
|
+
const entries = readdirSync16(dir, { withFileTypes: true });
|
|
18663
18902
|
for (const entry of entries) {
|
|
18664
18903
|
const fullPath = join14(dir, entry.name);
|
|
18665
18904
|
if (entry.isDirectory()) {
|
|
@@ -18667,7 +18906,7 @@ function searchDirectory(dir, pattern, results) {
|
|
|
18667
18906
|
searchDirectory(fullPath, pattern, results);
|
|
18668
18907
|
} else if (entry.name.endsWith(".ts") || entry.name.endsWith(".tsx")) {
|
|
18669
18908
|
try {
|
|
18670
|
-
const source =
|
|
18909
|
+
const source = readFileSync26(fullPath, "utf-8");
|
|
18671
18910
|
const lines = source.split("\n");
|
|
18672
18911
|
for (let i = 0; i < lines.length; i++) {
|
|
18673
18912
|
if (lines[i].includes(pattern)) {
|
|
@@ -18730,8 +18969,8 @@ var init_trpc_index = __esm({
|
|
|
18730
18969
|
});
|
|
18731
18970
|
|
|
18732
18971
|
// src/page-deps.ts
|
|
18733
|
-
import { readFileSync as
|
|
18734
|
-
import { resolve as
|
|
18972
|
+
import { readFileSync as readFileSync27, existsSync as existsSync29 } from "fs";
|
|
18973
|
+
import { resolve as resolve26 } from "path";
|
|
18735
18974
|
function deriveRoute(pageFile) {
|
|
18736
18975
|
let route = pageFile.replace(/^src\/app/, "").replace(/\/page\.tsx?$/, "").replace(/\/page\.jsx?$/, "");
|
|
18737
18976
|
return route || "/";
|
|
@@ -18769,10 +19008,10 @@ function findRouterCalls(files) {
|
|
|
18769
19008
|
const routers = /* @__PURE__ */ new Set();
|
|
18770
19009
|
const projectRoot = getProjectRoot();
|
|
18771
19010
|
for (const file of files) {
|
|
18772
|
-
const absPath = ensureWithinRoot(
|
|
18773
|
-
if (!
|
|
19011
|
+
const absPath = ensureWithinRoot(resolve26(projectRoot, file), projectRoot);
|
|
19012
|
+
if (!existsSync29(absPath)) continue;
|
|
18774
19013
|
try {
|
|
18775
|
-
const source =
|
|
19014
|
+
const source = readFileSync27(absPath, "utf-8");
|
|
18776
19015
|
const apiCallRegex = /api\.(\w+)\.\w+/g;
|
|
18777
19016
|
let match;
|
|
18778
19017
|
while ((match = apiCallRegex.exec(source)) !== null) {
|
|
@@ -18790,10 +19029,10 @@ function findTablesFromRouters(routerNames, dataDb) {
|
|
|
18790
19029
|
"SELECT DISTINCT router_file FROM massu_trpc_procedures WHERE router_name = ?"
|
|
18791
19030
|
).all(routerName);
|
|
18792
19031
|
for (const proc of procs) {
|
|
18793
|
-
const absPath = ensureWithinRoot(
|
|
18794
|
-
if (!
|
|
19032
|
+
const absPath = ensureWithinRoot(resolve26(getProjectRoot(), proc.router_file), getProjectRoot());
|
|
19033
|
+
if (!existsSync29(absPath)) continue;
|
|
18795
19034
|
try {
|
|
18796
|
-
const source =
|
|
19035
|
+
const source = readFileSync27(absPath, "utf-8");
|
|
18797
19036
|
const dbPattern = getConfig().dbAccessPattern ?? "ctx.db.{table}";
|
|
18798
19037
|
const regexStr = dbPattern.replace(/[.*+?^${}()|[\]\\]/g, "\\$&").replace("\\{table\\}", "(\\w+)");
|
|
18799
19038
|
const tableRegex = new RegExp(regexStr + "\\.", "g");
|
|
@@ -19062,14 +19301,14 @@ var init_domains = __esm({
|
|
|
19062
19301
|
});
|
|
19063
19302
|
|
|
19064
19303
|
// src/schema-mapper.ts
|
|
19065
|
-
import { readFileSync as
|
|
19304
|
+
import { readFileSync as readFileSync28, existsSync as existsSync30, readdirSync as readdirSync17 } from "fs";
|
|
19066
19305
|
import { join as join15 } from "path";
|
|
19067
19306
|
function parsePrismaSchema() {
|
|
19068
19307
|
const schemaPath = getResolvedPaths().prismaSchemaPath;
|
|
19069
|
-
if (!
|
|
19308
|
+
if (!existsSync30(schemaPath)) {
|
|
19070
19309
|
throw new Error(`Prisma schema not found at ${schemaPath}`);
|
|
19071
19310
|
}
|
|
19072
|
-
const source =
|
|
19311
|
+
const source = readFileSync28(schemaPath, "utf-8");
|
|
19073
19312
|
const models = [];
|
|
19074
19313
|
const sourceLines = source.split("\n");
|
|
19075
19314
|
let i = 0;
|
|
@@ -19127,12 +19366,12 @@ function toSnakeCase(str) {
|
|
|
19127
19366
|
function findColumnUsageInRouters(tableName) {
|
|
19128
19367
|
const usage = /* @__PURE__ */ new Map();
|
|
19129
19368
|
const routersDir = getResolvedPaths().routersDir;
|
|
19130
|
-
if (!
|
|
19369
|
+
if (!existsSync30(routersDir)) return usage;
|
|
19131
19370
|
scanDirectory(routersDir, tableName, usage);
|
|
19132
19371
|
return usage;
|
|
19133
19372
|
}
|
|
19134
19373
|
function scanDirectory(dir, tableName, usage) {
|
|
19135
|
-
const entries =
|
|
19374
|
+
const entries = readdirSync17(dir, { withFileTypes: true });
|
|
19136
19375
|
for (const entry of entries) {
|
|
19137
19376
|
const fullPath = join15(dir, entry.name);
|
|
19138
19377
|
if (entry.isDirectory()) {
|
|
@@ -19144,7 +19383,7 @@ function scanDirectory(dir, tableName, usage) {
|
|
|
19144
19383
|
}
|
|
19145
19384
|
function scanFile(absPath, tableName, usage) {
|
|
19146
19385
|
try {
|
|
19147
|
-
const source =
|
|
19386
|
+
const source = readFileSync28(absPath, "utf-8");
|
|
19148
19387
|
if (!source.includes(tableName)) return;
|
|
19149
19388
|
const relPath = absPath.slice(getProjectRoot().length + 1);
|
|
19150
19389
|
const lines = source.split("\n");
|
|
@@ -19189,15 +19428,15 @@ function detectMismatches(models) {
|
|
|
19189
19428
|
}
|
|
19190
19429
|
function findFilesUsingColumn(dir, column, tableName) {
|
|
19191
19430
|
const result = [];
|
|
19192
|
-
if (!
|
|
19193
|
-
const entries =
|
|
19431
|
+
if (!existsSync30(dir)) return result;
|
|
19432
|
+
const entries = readdirSync17(dir, { withFileTypes: true });
|
|
19194
19433
|
for (const entry of entries) {
|
|
19195
19434
|
const fullPath = join15(dir, entry.name);
|
|
19196
19435
|
if (entry.isDirectory()) {
|
|
19197
19436
|
result.push(...findFilesUsingColumn(fullPath, column, tableName));
|
|
19198
19437
|
} else if (entry.name.endsWith(".ts")) {
|
|
19199
19438
|
try {
|
|
19200
|
-
const source =
|
|
19439
|
+
const source = readFileSync28(fullPath, "utf-8");
|
|
19201
19440
|
if (source.includes(tableName) && source.includes(column)) {
|
|
19202
19441
|
result.push(fullPath.slice(getProjectRoot().length + 1));
|
|
19203
19442
|
}
|
|
@@ -19342,12 +19581,12 @@ var init_import_parser = __esm({
|
|
|
19342
19581
|
});
|
|
19343
19582
|
|
|
19344
19583
|
// src/python/import-resolver.ts
|
|
19345
|
-
import { readFileSync as
|
|
19346
|
-
import { resolve as
|
|
19584
|
+
import { readFileSync as readFileSync29, existsSync as existsSync31, readdirSync as readdirSync18 } from "fs";
|
|
19585
|
+
import { resolve as resolve28, join as join16, relative as relative6, dirname as dirname14 } from "path";
|
|
19347
19586
|
function resolvePythonModulePath(module, fromFile, pythonRoot, level) {
|
|
19348
19587
|
const projectRoot = getProjectRoot();
|
|
19349
19588
|
if (level > 0) {
|
|
19350
|
-
let baseDir = dirname14(
|
|
19589
|
+
let baseDir = dirname14(resolve28(projectRoot, fromFile));
|
|
19351
19590
|
for (let i = 1; i < level; i++) {
|
|
19352
19591
|
baseDir = dirname14(baseDir);
|
|
19353
19592
|
}
|
|
@@ -19359,17 +19598,17 @@ function resolvePythonModulePath(module, fromFile, pythonRoot, level) {
|
|
|
19359
19598
|
return tryResolvePythonPath(baseDir, projectRoot);
|
|
19360
19599
|
}
|
|
19361
19600
|
const parts = module.split(".");
|
|
19362
|
-
const candidate = join16(
|
|
19601
|
+
const candidate = join16(resolve28(projectRoot, pythonRoot), ...parts);
|
|
19363
19602
|
return tryResolvePythonPath(candidate, projectRoot);
|
|
19364
19603
|
}
|
|
19365
19604
|
function tryResolvePythonPath(basePath, projectRoot) {
|
|
19366
|
-
if (
|
|
19605
|
+
if (existsSync31(basePath + ".py")) {
|
|
19367
19606
|
return relative6(projectRoot, basePath + ".py");
|
|
19368
19607
|
}
|
|
19369
|
-
if (
|
|
19608
|
+
if (existsSync31(join16(basePath, "__init__.py"))) {
|
|
19370
19609
|
return relative6(projectRoot, join16(basePath, "__init__.py"));
|
|
19371
19610
|
}
|
|
19372
|
-
if (basePath.endsWith(".py") &&
|
|
19611
|
+
if (basePath.endsWith(".py") && existsSync31(basePath)) {
|
|
19373
19612
|
return relative6(projectRoot, basePath);
|
|
19374
19613
|
}
|
|
19375
19614
|
return null;
|
|
@@ -19377,7 +19616,7 @@ function tryResolvePythonPath(basePath, projectRoot) {
|
|
|
19377
19616
|
function walkPythonFiles(dir, excludeDirs) {
|
|
19378
19617
|
const files = [];
|
|
19379
19618
|
try {
|
|
19380
|
-
const entries =
|
|
19619
|
+
const entries = readdirSync18(dir, { withFileTypes: true });
|
|
19381
19620
|
for (const entry of entries) {
|
|
19382
19621
|
if (entry.isDirectory()) {
|
|
19383
19622
|
if (excludeDirs.includes(entry.name)) continue;
|
|
@@ -19392,7 +19631,7 @@ function walkPythonFiles(dir, excludeDirs) {
|
|
|
19392
19631
|
}
|
|
19393
19632
|
function buildPythonImportIndex(dataDb, pythonRoot, excludeDirs = ["__pycache__", ".venv", "venv", ".mypy_cache", ".pytest_cache"]) {
|
|
19394
19633
|
const projectRoot = getProjectRoot();
|
|
19395
|
-
const absRoot =
|
|
19634
|
+
const absRoot = resolve28(projectRoot, pythonRoot);
|
|
19396
19635
|
dataDb.exec("DELETE FROM massu_py_imports");
|
|
19397
19636
|
const insertStmt = dataDb.prepare(
|
|
19398
19637
|
"INSERT INTO massu_py_imports (source_file, target_file, import_type, imported_names, line) VALUES (?, ?, ?, ?, ?)"
|
|
@@ -19409,7 +19648,7 @@ function buildPythonImportIndex(dataDb, pythonRoot, excludeDirs = ["__pycache__"
|
|
|
19409
19648
|
const relFile = relative6(projectRoot, absFile);
|
|
19410
19649
|
let source;
|
|
19411
19650
|
try {
|
|
19412
|
-
source =
|
|
19651
|
+
source = readFileSync29(absFile, "utf-8");
|
|
19413
19652
|
} catch {
|
|
19414
19653
|
continue;
|
|
19415
19654
|
}
|
|
@@ -19675,12 +19914,12 @@ var init_route_parser = __esm({
|
|
|
19675
19914
|
});
|
|
19676
19915
|
|
|
19677
19916
|
// src/python/route-indexer.ts
|
|
19678
|
-
import { readFileSync as
|
|
19917
|
+
import { readFileSync as readFileSync30, readdirSync as readdirSync19 } from "fs";
|
|
19679
19918
|
import { join as join17, relative as relative7 } from "path";
|
|
19680
19919
|
function walkPyFiles(dir, excludeDirs) {
|
|
19681
19920
|
const files = [];
|
|
19682
19921
|
try {
|
|
19683
|
-
const entries =
|
|
19922
|
+
const entries = readdirSync19(dir, { withFileTypes: true });
|
|
19684
19923
|
for (const entry of entries) {
|
|
19685
19924
|
if (entry.isDirectory()) {
|
|
19686
19925
|
if (excludeDirs.includes(entry.name)) continue;
|
|
@@ -19708,7 +19947,7 @@ function buildPythonRouteIndex(dataDb, pythonRoot, excludeDirs = ["__pycache__",
|
|
|
19708
19947
|
const relFile = relative7(projectRoot, absFile);
|
|
19709
19948
|
let source;
|
|
19710
19949
|
try {
|
|
19711
|
-
source =
|
|
19950
|
+
source = readFileSync30(absFile, "utf-8");
|
|
19712
19951
|
} catch {
|
|
19713
19952
|
continue;
|
|
19714
19953
|
}
|
|
@@ -19919,12 +20158,12 @@ var init_model_parser = __esm({
|
|
|
19919
20158
|
});
|
|
19920
20159
|
|
|
19921
20160
|
// src/python/model-indexer.ts
|
|
19922
|
-
import { readFileSync as
|
|
20161
|
+
import { readFileSync as readFileSync31, readdirSync as readdirSync20 } from "fs";
|
|
19923
20162
|
import { join as join18, relative as relative8 } from "path";
|
|
19924
20163
|
function walkPyFiles2(dir, excludeDirs) {
|
|
19925
20164
|
const files = [];
|
|
19926
20165
|
try {
|
|
19927
|
-
const entries =
|
|
20166
|
+
const entries = readdirSync20(dir, { withFileTypes: true });
|
|
19928
20167
|
for (const entry of entries) {
|
|
19929
20168
|
if (entry.isDirectory()) {
|
|
19930
20169
|
if (excludeDirs.includes(entry.name)) continue;
|
|
@@ -19955,7 +20194,7 @@ function buildPythonModelIndex(dataDb, pythonRoot, excludeDirs = ["__pycache__",
|
|
|
19955
20194
|
const relFile = relative8(projectRoot, absFile);
|
|
19956
20195
|
let source;
|
|
19957
20196
|
try {
|
|
19958
|
-
source =
|
|
20197
|
+
source = readFileSync31(absFile, "utf-8");
|
|
19959
20198
|
} catch {
|
|
19960
20199
|
continue;
|
|
19961
20200
|
}
|
|
@@ -20215,7 +20454,7 @@ var init_migration_parser = __esm({
|
|
|
20215
20454
|
});
|
|
20216
20455
|
|
|
20217
20456
|
// src/python/migration-indexer.ts
|
|
20218
|
-
import { readFileSync as
|
|
20457
|
+
import { readFileSync as readFileSync32, readdirSync as readdirSync21 } from "fs";
|
|
20219
20458
|
import { join as join19, relative as relative9 } from "path";
|
|
20220
20459
|
function buildPythonMigrationIndex(dataDb, alembicDir) {
|
|
20221
20460
|
const projectRoot = getProjectRoot();
|
|
@@ -20224,10 +20463,10 @@ function buildPythonMigrationIndex(dataDb, alembicDir) {
|
|
|
20224
20463
|
const versionsDir = join19(absDir, "versions");
|
|
20225
20464
|
let files = [];
|
|
20226
20465
|
try {
|
|
20227
|
-
files =
|
|
20466
|
+
files = readdirSync21(versionsDir).filter((f2) => f2.endsWith(".py")).map((f2) => join19(versionsDir, f2));
|
|
20228
20467
|
} catch {
|
|
20229
20468
|
try {
|
|
20230
|
-
files =
|
|
20469
|
+
files = readdirSync21(absDir).filter((f2) => f2.endsWith(".py") && f2 !== "env.py").map((f2) => join19(absDir, f2));
|
|
20231
20470
|
} catch {
|
|
20232
20471
|
}
|
|
20233
20472
|
}
|
|
@@ -20241,7 +20480,7 @@ function buildPythonMigrationIndex(dataDb, alembicDir) {
|
|
|
20241
20480
|
for (const absFile of files) {
|
|
20242
20481
|
let source;
|
|
20243
20482
|
try {
|
|
20244
|
-
source =
|
|
20483
|
+
source = readFileSync32(absFile, "utf-8");
|
|
20245
20484
|
} catch {
|
|
20246
20485
|
continue;
|
|
20247
20486
|
}
|
|
@@ -20275,7 +20514,7 @@ var init_migration_indexer = __esm({
|
|
|
20275
20514
|
});
|
|
20276
20515
|
|
|
20277
20516
|
// src/python/coupling-detector.ts
|
|
20278
|
-
import { readFileSync as
|
|
20517
|
+
import { readFileSync as readFileSync33, readdirSync as readdirSync22 } from "fs";
|
|
20279
20518
|
import { join as join20, relative as relative10 } from "path";
|
|
20280
20519
|
function buildPythonCouplingIndex(dataDb) {
|
|
20281
20520
|
const projectRoot = getProjectRoot();
|
|
@@ -20312,7 +20551,7 @@ function buildPythonCouplingIndex(dataDb) {
|
|
|
20312
20551
|
const relFile = relative10(projectRoot, absFile);
|
|
20313
20552
|
let source;
|
|
20314
20553
|
try {
|
|
20315
|
-
source =
|
|
20554
|
+
source = readFileSync33(absFile, "utf-8");
|
|
20316
20555
|
} catch {
|
|
20317
20556
|
continue;
|
|
20318
20557
|
}
|
|
@@ -20340,7 +20579,7 @@ function walkFrontendFiles(dir) {
|
|
|
20340
20579
|
const files = [];
|
|
20341
20580
|
const exclude = ["node_modules", ".next", "dist", ".git", "__pycache__", ".venv", "venv"];
|
|
20342
20581
|
try {
|
|
20343
|
-
const entries =
|
|
20582
|
+
const entries = readdirSync22(dir, { withFileTypes: true });
|
|
20344
20583
|
for (const entry of entries) {
|
|
20345
20584
|
if (entry.isDirectory()) {
|
|
20346
20585
|
if (exclude.includes(entry.name)) continue;
|
|
@@ -20717,8 +20956,8 @@ var init_memory_tools = __esm({
|
|
|
20717
20956
|
});
|
|
20718
20957
|
|
|
20719
20958
|
// src/docs-tools.ts
|
|
20720
|
-
import { readFileSync as
|
|
20721
|
-
import { resolve as
|
|
20959
|
+
import { readFileSync as readFileSync34, existsSync as existsSync32 } from "fs";
|
|
20960
|
+
import { resolve as resolve29, basename as basename6 } from "path";
|
|
20722
20961
|
function p3(baseName) {
|
|
20723
20962
|
return `${getConfig().toolPrefix}_${baseName}`;
|
|
20724
20963
|
}
|
|
@@ -20773,10 +21012,10 @@ function handleDocsToolCall(name, args2) {
|
|
|
20773
21012
|
}
|
|
20774
21013
|
function loadDocsMap() {
|
|
20775
21014
|
const mapPath = getResolvedPaths().docsMapPath;
|
|
20776
|
-
if (!
|
|
21015
|
+
if (!existsSync32(mapPath)) {
|
|
20777
21016
|
throw new Error(`docs-map.json not found at ${mapPath}`);
|
|
20778
21017
|
}
|
|
20779
|
-
return JSON.parse(
|
|
21018
|
+
return JSON.parse(readFileSync34(mapPath, "utf-8"));
|
|
20780
21019
|
}
|
|
20781
21020
|
function matchesPattern(filePath, pattern) {
|
|
20782
21021
|
const regexStr = pattern.replace(/\./g, "\\.").replace(/\*\*/g, "{{GLOBSTAR}}").replace(/\*/g, "[^/]*").replace(/\{\{GLOBSTAR\}\}/g, ".*");
|
|
@@ -20846,13 +21085,13 @@ function extractFrontmatter(content) {
|
|
|
20846
21085
|
}
|
|
20847
21086
|
function extractProcedureNames(routerPath) {
|
|
20848
21087
|
const root = getProjectRoot();
|
|
20849
|
-
const absPath = ensureWithinRoot(
|
|
20850
|
-
if (!
|
|
20851
|
-
const altPath = ensureWithinRoot(
|
|
20852
|
-
if (!
|
|
20853
|
-
return extractProcedureNamesFromContent(
|
|
21088
|
+
const absPath = ensureWithinRoot(resolve29(getResolvedPaths().srcDir, "..", routerPath), root);
|
|
21089
|
+
if (!existsSync32(absPath)) {
|
|
21090
|
+
const altPath = ensureWithinRoot(resolve29(getResolvedPaths().srcDir, "../server/api/routers", basename6(routerPath)), root);
|
|
21091
|
+
if (!existsSync32(altPath)) return [];
|
|
21092
|
+
return extractProcedureNamesFromContent(readFileSync34(altPath, "utf-8"));
|
|
20854
21093
|
}
|
|
20855
|
-
return extractProcedureNamesFromContent(
|
|
21094
|
+
return extractProcedureNamesFromContent(readFileSync34(absPath, "utf-8"));
|
|
20856
21095
|
}
|
|
20857
21096
|
function extractProcedureNamesFromContent(content) {
|
|
20858
21097
|
const procRegex = /\.(?:query|mutation)\s*\(/g;
|
|
@@ -20892,8 +21131,8 @@ function handleDocsAudit(args2) {
|
|
|
20892
21131
|
for (const [mappingId, triggeringFiles] of affectedMappings) {
|
|
20893
21132
|
const mapping = docsMap.mappings.find((m3) => m3.id === mappingId);
|
|
20894
21133
|
if (!mapping) continue;
|
|
20895
|
-
const helpPagePath = ensureWithinRoot(
|
|
20896
|
-
if (!
|
|
21134
|
+
const helpPagePath = ensureWithinRoot(resolve29(getResolvedPaths().helpSitePath, mapping.helpPage), getProjectRoot());
|
|
21135
|
+
if (!existsSync32(helpPagePath)) {
|
|
20897
21136
|
results.push({
|
|
20898
21137
|
helpPage: mapping.helpPage,
|
|
20899
21138
|
mappingId,
|
|
@@ -20905,7 +21144,7 @@ function handleDocsAudit(args2) {
|
|
|
20905
21144
|
});
|
|
20906
21145
|
continue;
|
|
20907
21146
|
}
|
|
20908
|
-
const content =
|
|
21147
|
+
const content = readFileSync34(helpPagePath, "utf-8");
|
|
20909
21148
|
const sections = extractSections(content);
|
|
20910
21149
|
const frontmatter = extractFrontmatter(content);
|
|
20911
21150
|
const staleReasons = [];
|
|
@@ -20945,9 +21184,9 @@ function handleDocsAudit(args2) {
|
|
|
20945
21184
|
});
|
|
20946
21185
|
for (const [guideName, parentId] of Object.entries(docsMap.userGuideInheritance.examples)) {
|
|
20947
21186
|
if (parentId === mappingId) {
|
|
20948
|
-
const guidePath = ensureWithinRoot(
|
|
20949
|
-
if (
|
|
20950
|
-
const guideContent =
|
|
21187
|
+
const guidePath = ensureWithinRoot(resolve29(getResolvedPaths().helpSitePath, `pages/user-guides/${guideName}/index.mdx`), getProjectRoot());
|
|
21188
|
+
if (existsSync32(guidePath)) {
|
|
21189
|
+
const guideContent = readFileSync34(guidePath, "utf-8");
|
|
20951
21190
|
const guideFrontmatter = extractFrontmatter(guideContent);
|
|
20952
21191
|
if (!guideFrontmatter?.lastVerified || status === "STALE") {
|
|
20953
21192
|
results.push({
|
|
@@ -20980,14 +21219,14 @@ function handleDocsCoverage(args2) {
|
|
|
20980
21219
|
const gaps = [];
|
|
20981
21220
|
const mappings = filterDomain ? docsMap.mappings.filter((m3) => m3.id === filterDomain) : docsMap.mappings;
|
|
20982
21221
|
for (const mapping of mappings) {
|
|
20983
|
-
const helpPagePath = ensureWithinRoot(
|
|
20984
|
-
const exists =
|
|
21222
|
+
const helpPagePath = ensureWithinRoot(resolve29(getResolvedPaths().helpSitePath, mapping.helpPage), getProjectRoot());
|
|
21223
|
+
const exists = existsSync32(helpPagePath);
|
|
20985
21224
|
let hasContent = false;
|
|
20986
21225
|
let lineCount = 0;
|
|
20987
21226
|
let lastVerified = null;
|
|
20988
21227
|
let status = null;
|
|
20989
21228
|
if (exists) {
|
|
20990
|
-
const content =
|
|
21229
|
+
const content = readFileSync34(helpPagePath, "utf-8");
|
|
20991
21230
|
lineCount = content.split("\n").length;
|
|
20992
21231
|
hasContent = lineCount > 10;
|
|
20993
21232
|
const frontmatter = extractFrontmatter(content);
|
|
@@ -21328,8 +21567,8 @@ var init_observability_tools = __esm({
|
|
|
21328
21567
|
});
|
|
21329
21568
|
|
|
21330
21569
|
// src/sentinel-db.ts
|
|
21331
|
-
import { existsSync as
|
|
21332
|
-
import { resolve as
|
|
21570
|
+
import { existsSync as existsSync33 } from "fs";
|
|
21571
|
+
import { resolve as resolve30 } from "path";
|
|
21333
21572
|
function parsePortalScope(raw) {
|
|
21334
21573
|
if (!raw) return [];
|
|
21335
21574
|
try {
|
|
@@ -21565,23 +21804,23 @@ function validateFeatures(db, domainFilter) {
|
|
|
21565
21804
|
const missingProcedures = [];
|
|
21566
21805
|
const missingPages = [];
|
|
21567
21806
|
for (const comp of components) {
|
|
21568
|
-
const absPath =
|
|
21569
|
-
if (!
|
|
21807
|
+
const absPath = resolve30(PROJECT_ROOT, comp.component_file);
|
|
21808
|
+
if (!existsSync33(absPath)) {
|
|
21570
21809
|
missingComponents.push(comp.component_file);
|
|
21571
21810
|
}
|
|
21572
21811
|
}
|
|
21573
21812
|
for (const proc of procedures) {
|
|
21574
|
-
const routerPath =
|
|
21575
|
-
if (!
|
|
21813
|
+
const routerPath = resolve30(PROJECT_ROOT, `src/server/api/routers/${proc.router_name}.ts`);
|
|
21814
|
+
if (!existsSync33(routerPath)) {
|
|
21576
21815
|
missingProcedures.push({ router: proc.router_name, procedure: proc.procedure_name });
|
|
21577
21816
|
}
|
|
21578
21817
|
}
|
|
21579
21818
|
for (const page of pages) {
|
|
21580
21819
|
const routeToPath = page.page_route.replace(/^\/(portal-[^/]+\/)?/, "src/app/").replace(/\/$/, "") + "/page.tsx";
|
|
21581
|
-
const absPath =
|
|
21582
|
-
if (page.page_route.startsWith("/") && !
|
|
21583
|
-
const altPath =
|
|
21584
|
-
if (!
|
|
21820
|
+
const absPath = resolve30(PROJECT_ROOT, routeToPath);
|
|
21821
|
+
if (page.page_route.startsWith("/") && !existsSync33(absPath)) {
|
|
21822
|
+
const altPath = resolve30(PROJECT_ROOT, `src/app${page.page_route}/page.tsx`);
|
|
21823
|
+
if (!existsSync33(altPath)) {
|
|
21585
21824
|
missingPages.push(page.page_route);
|
|
21586
21825
|
}
|
|
21587
21826
|
}
|
|
@@ -22105,8 +22344,8 @@ var init_sentinel_tools = __esm({
|
|
|
22105
22344
|
});
|
|
22106
22345
|
|
|
22107
22346
|
// src/sentinel-scanner.ts
|
|
22108
|
-
import { readFileSync as
|
|
22109
|
-
import { resolve as
|
|
22347
|
+
import { readFileSync as readFileSync35, existsSync as existsSync34, readdirSync as readdirSync23, statSync as statSync13 } from "fs";
|
|
22348
|
+
import { resolve as resolve31, join as join21, basename as basename7, dirname as dirname15, relative as relative11 } from "path";
|
|
22110
22349
|
function inferDomain(filePath) {
|
|
22111
22350
|
const domains = getConfig().domains;
|
|
22112
22351
|
const path = filePath.toLowerCase();
|
|
@@ -22235,10 +22474,10 @@ function scanComponentExports(dataDb) {
|
|
|
22235
22474
|
const projectRoot = getProjectRoot();
|
|
22236
22475
|
const componentsBase = config.paths.components ?? config.paths.source + "/components";
|
|
22237
22476
|
const componentDirs = [];
|
|
22238
|
-
const basePath =
|
|
22239
|
-
if (
|
|
22477
|
+
const basePath = resolve31(projectRoot, componentsBase);
|
|
22478
|
+
if (existsSync34(basePath)) {
|
|
22240
22479
|
try {
|
|
22241
|
-
const entries =
|
|
22480
|
+
const entries = readdirSync23(basePath, { withFileTypes: true });
|
|
22242
22481
|
for (const entry of entries) {
|
|
22243
22482
|
if (entry.isDirectory()) {
|
|
22244
22483
|
componentDirs.push(componentsBase + "/" + entry.name);
|
|
@@ -22248,12 +22487,12 @@ function scanComponentExports(dataDb) {
|
|
|
22248
22487
|
}
|
|
22249
22488
|
}
|
|
22250
22489
|
for (const dir of componentDirs) {
|
|
22251
|
-
const absDir =
|
|
22252
|
-
if (!
|
|
22490
|
+
const absDir = resolve31(projectRoot, dir);
|
|
22491
|
+
if (!existsSync34(absDir)) continue;
|
|
22253
22492
|
const files = walkDir2(absDir).filter((f2) => f2.endsWith(".tsx") || f2.endsWith(".ts"));
|
|
22254
22493
|
for (const file of files) {
|
|
22255
22494
|
const relPath = relative11(projectRoot, file);
|
|
22256
|
-
const source =
|
|
22495
|
+
const source = readFileSync35(file, "utf-8");
|
|
22257
22496
|
const annotations = parseFeatureAnnotations(source);
|
|
22258
22497
|
if (annotations.length > 0) {
|
|
22259
22498
|
for (const ann of annotations) {
|
|
@@ -22302,7 +22541,7 @@ function scanComponentExports(dataDb) {
|
|
|
22302
22541
|
function walkDir2(dir) {
|
|
22303
22542
|
const results = [];
|
|
22304
22543
|
try {
|
|
22305
|
-
const entries =
|
|
22544
|
+
const entries = readdirSync23(dir);
|
|
22306
22545
|
for (const entry of entries) {
|
|
22307
22546
|
const fullPath = join21(dir, entry);
|
|
22308
22547
|
try {
|
|
@@ -23292,7 +23531,7 @@ var init_audit_trail = __esm({
|
|
|
23292
23531
|
});
|
|
23293
23532
|
|
|
23294
23533
|
// src/validation-engine.ts
|
|
23295
|
-
import { existsSync as
|
|
23534
|
+
import { existsSync as existsSync35, readFileSync as readFileSync36 } from "fs";
|
|
23296
23535
|
function p10(baseName) {
|
|
23297
23536
|
return `${getConfig().toolPrefix}_${baseName}`;
|
|
23298
23537
|
}
|
|
@@ -23323,7 +23562,7 @@ function validateFile(filePath, projectRoot) {
|
|
|
23323
23562
|
});
|
|
23324
23563
|
return checks;
|
|
23325
23564
|
}
|
|
23326
|
-
if (!
|
|
23565
|
+
if (!existsSync35(absPath)) {
|
|
23327
23566
|
checks.push({
|
|
23328
23567
|
name: "file_exists",
|
|
23329
23568
|
severity: "error",
|
|
@@ -23332,7 +23571,7 @@ function validateFile(filePath, projectRoot) {
|
|
|
23332
23571
|
});
|
|
23333
23572
|
return checks;
|
|
23334
23573
|
}
|
|
23335
|
-
const source =
|
|
23574
|
+
const source = readFileSync36(absPath, "utf-8");
|
|
23336
23575
|
const lines = source.split("\n");
|
|
23337
23576
|
if (activeChecks.rule_compliance !== false) {
|
|
23338
23577
|
for (const ruleSet of config.rules) {
|
|
@@ -23777,7 +24016,7 @@ var init_adr_generator = __esm({
|
|
|
23777
24016
|
});
|
|
23778
24017
|
|
|
23779
24018
|
// src/security-scorer.ts
|
|
23780
|
-
import { existsSync as
|
|
24019
|
+
import { existsSync as existsSync36, readFileSync as readFileSync37 } from "fs";
|
|
23781
24020
|
function p12(baseName) {
|
|
23782
24021
|
return `${getConfig().toolPrefix}_${baseName}`;
|
|
23783
24022
|
}
|
|
@@ -23801,12 +24040,12 @@ function scoreFileSecurity(filePath, projectRoot) {
|
|
|
23801
24040
|
}]
|
|
23802
24041
|
};
|
|
23803
24042
|
}
|
|
23804
|
-
if (!
|
|
24043
|
+
if (!existsSync36(absPath)) {
|
|
23805
24044
|
return { riskScore: 0, findings: [] };
|
|
23806
24045
|
}
|
|
23807
24046
|
let source;
|
|
23808
24047
|
try {
|
|
23809
|
-
source =
|
|
24048
|
+
source = readFileSync37(absPath, "utf-8");
|
|
23810
24049
|
} catch {
|
|
23811
24050
|
return { riskScore: 0, findings: [] };
|
|
23812
24051
|
}
|
|
@@ -24095,8 +24334,8 @@ var init_security_scorer = __esm({
|
|
|
24095
24334
|
});
|
|
24096
24335
|
|
|
24097
24336
|
// src/dependency-scorer.ts
|
|
24098
|
-
import { existsSync as
|
|
24099
|
-
import { resolve as
|
|
24337
|
+
import { existsSync as existsSync37, readFileSync as readFileSync38 } from "fs";
|
|
24338
|
+
import { resolve as resolve32 } from "path";
|
|
24100
24339
|
function p13(baseName) {
|
|
24101
24340
|
return `${getConfig().toolPrefix}_${baseName}`;
|
|
24102
24341
|
}
|
|
@@ -24128,10 +24367,10 @@ function calculateDepRisk(factors) {
|
|
|
24128
24367
|
return Math.min(100, risk);
|
|
24129
24368
|
}
|
|
24130
24369
|
function getInstalledPackages(projectRoot) {
|
|
24131
|
-
const pkgPath =
|
|
24132
|
-
if (!
|
|
24370
|
+
const pkgPath = resolve32(projectRoot, "package.json");
|
|
24371
|
+
if (!existsSync37(pkgPath)) return /* @__PURE__ */ new Map();
|
|
24133
24372
|
try {
|
|
24134
|
-
const pkg = JSON.parse(
|
|
24373
|
+
const pkg = JSON.parse(readFileSync38(pkgPath, "utf-8"));
|
|
24135
24374
|
const packages = /* @__PURE__ */ new Map();
|
|
24136
24375
|
for (const [name, version] of Object.entries(pkg.dependencies ?? {})) {
|
|
24137
24376
|
packages.set(name, version);
|
|
@@ -24734,8 +24973,8 @@ var init_regression_detector = __esm({
|
|
|
24734
24973
|
|
|
24735
24974
|
// src/knowledge-indexer.ts
|
|
24736
24975
|
import { createHash as createHash9 } from "crypto";
|
|
24737
|
-
import { readFileSync as
|
|
24738
|
-
import { resolve as
|
|
24976
|
+
import { readFileSync as readFileSync39, readdirSync as readdirSync24, statSync as statSync14, existsSync as existsSync38 } from "fs";
|
|
24977
|
+
import { resolve as resolve33, relative as relative12, basename as basename8, extname as extname2 } from "path";
|
|
24739
24978
|
function getKnowledgePaths() {
|
|
24740
24979
|
const resolved = getResolvedPaths();
|
|
24741
24980
|
const config = getConfig();
|
|
@@ -24761,9 +25000,9 @@ function discoverMarkdownFiles(baseDir) {
|
|
|
24761
25000
|
const files = [];
|
|
24762
25001
|
function walk(dir) {
|
|
24763
25002
|
try {
|
|
24764
|
-
const entries =
|
|
25003
|
+
const entries = readdirSync24(dir, { withFileTypes: true });
|
|
24765
25004
|
for (const entry of entries) {
|
|
24766
|
-
const fullPath =
|
|
25005
|
+
const fullPath = resolve33(dir, entry.name);
|
|
24767
25006
|
if (entry.isDirectory()) {
|
|
24768
25007
|
if (entry.name === "archive" && dir.includes("session-state")) continue;
|
|
24769
25008
|
if (entry.name === "archive" && dir.includes("status")) continue;
|
|
@@ -25041,11 +25280,11 @@ function indexAllKnowledge(db) {
|
|
|
25041
25280
|
files.push(...memFiles);
|
|
25042
25281
|
} catch {
|
|
25043
25282
|
}
|
|
25044
|
-
if (
|
|
25283
|
+
if (existsSync38(paths.plansDir)) {
|
|
25045
25284
|
const planFiles = discoverMarkdownFiles(paths.plansDir);
|
|
25046
25285
|
files.push(...planFiles);
|
|
25047
25286
|
}
|
|
25048
|
-
if (
|
|
25287
|
+
if (existsSync38(paths.docsDir)) {
|
|
25049
25288
|
const excludePatterns = getConfig().conventions?.excludePatterns ?? ["/ARCHIVE/", "/SESSION-HISTORY/"];
|
|
25050
25289
|
const docsFiles = discoverMarkdownFiles(paths.docsDir).filter((f2) => !f2.includes("/plans/") && !excludePatterns.some((p19) => f2.includes(p19)));
|
|
25051
25290
|
files.push(...docsFiles);
|
|
@@ -25088,8 +25327,8 @@ function indexAllKnowledge(db) {
|
|
|
25088
25327
|
} catch {
|
|
25089
25328
|
}
|
|
25090
25329
|
for (const filePath of files) {
|
|
25091
|
-
if (!
|
|
25092
|
-
const content =
|
|
25330
|
+
if (!existsSync38(filePath)) continue;
|
|
25331
|
+
const content = readFileSync39(filePath, "utf-8");
|
|
25093
25332
|
const hash = hashContent2(content);
|
|
25094
25333
|
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);
|
|
25095
25334
|
const category = categorizeFile(filePath);
|
|
@@ -25209,10 +25448,10 @@ function isKnowledgeStale(db) {
|
|
|
25209
25448
|
files.push(...discoverMarkdownFiles(paths.memoryDir));
|
|
25210
25449
|
} catch {
|
|
25211
25450
|
}
|
|
25212
|
-
if (
|
|
25451
|
+
if (existsSync38(paths.plansDir)) {
|
|
25213
25452
|
files.push(...discoverMarkdownFiles(paths.plansDir));
|
|
25214
25453
|
}
|
|
25215
|
-
if (
|
|
25454
|
+
if (existsSync38(paths.docsDir)) {
|
|
25216
25455
|
const excludePatterns = getConfig().conventions?.excludePatterns ?? ["/ARCHIVE/", "/SESSION-HISTORY/"];
|
|
25217
25456
|
const docsFiles = discoverMarkdownFiles(paths.docsDir).filter((f2) => !f2.includes("/plans/") && !excludePatterns.some((p19) => f2.includes(p19)));
|
|
25218
25457
|
files.push(...docsFiles);
|
|
@@ -25241,8 +25480,8 @@ var init_knowledge_indexer = __esm({
|
|
|
25241
25480
|
});
|
|
25242
25481
|
|
|
25243
25482
|
// src/knowledge-tools.ts
|
|
25244
|
-
import { readFileSync as
|
|
25245
|
-
import { resolve as
|
|
25483
|
+
import { readFileSync as readFileSync40, writeFileSync as writeFileSync5, appendFileSync as appendFileSync2, readdirSync as readdirSync25 } from "fs";
|
|
25484
|
+
import { resolve as resolve34, basename as basename9 } from "path";
|
|
25246
25485
|
function p16(baseName) {
|
|
25247
25486
|
return `${getConfig().toolPrefix}_${baseName}`;
|
|
25248
25487
|
}
|
|
@@ -25979,7 +26218,7 @@ function handleCorrect(db, args2) {
|
|
|
25979
26218
|
if (!wrong || !correction || !rule) {
|
|
25980
26219
|
return text15("Error: wrong, correction, and rule are all required.");
|
|
25981
26220
|
}
|
|
25982
|
-
const correctionsPath =
|
|
26221
|
+
const correctionsPath = resolve34(getResolvedPaths().memoryDir, "corrections.md");
|
|
25983
26222
|
const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
25984
26223
|
const title = rule.slice(0, 60);
|
|
25985
26224
|
const entry = `
|
|
@@ -25992,7 +26231,7 @@ ${crRule ? `- **CR**: ${crRule}
|
|
|
25992
26231
|
`;
|
|
25993
26232
|
let existing = "";
|
|
25994
26233
|
try {
|
|
25995
|
-
existing =
|
|
26234
|
+
existing = readFileSync40(correctionsPath, "utf-8");
|
|
25996
26235
|
} catch {
|
|
25997
26236
|
}
|
|
25998
26237
|
const archiveIdx = existing.indexOf("## Archived");
|
|
@@ -26174,7 +26413,7 @@ function handleGaps(db, args2) {
|
|
|
26174
26413
|
} else if (checkType === "routers") {
|
|
26175
26414
|
try {
|
|
26176
26415
|
const routersDir = getResolvedPaths().routersDir;
|
|
26177
|
-
const routerFiles =
|
|
26416
|
+
const routerFiles = readdirSync25(routersDir).filter((f2) => f2.endsWith(".ts") && !f2.startsWith("_"));
|
|
26178
26417
|
lines.push(`| Router | Knowledge Hits | Status |`);
|
|
26179
26418
|
lines.push(`|--------|----------------|--------|`);
|
|
26180
26419
|
for (const file of routerFiles) {
|
|
@@ -26331,11 +26570,11 @@ var init_knowledge_tools = __esm({
|
|
|
26331
26570
|
// src/knowledge-db.ts
|
|
26332
26571
|
import Database3 from "better-sqlite3";
|
|
26333
26572
|
import { dirname as dirname16 } from "path";
|
|
26334
|
-
import { existsSync as
|
|
26573
|
+
import { existsSync as existsSync40, mkdirSync as mkdirSync11 } from "fs";
|
|
26335
26574
|
function getKnowledgeDb() {
|
|
26336
26575
|
const dbPath = getResolvedPaths().knowledgeDbPath;
|
|
26337
26576
|
const dir = dirname16(dbPath);
|
|
26338
|
-
if (!
|
|
26577
|
+
if (!existsSync40(dir)) {
|
|
26339
26578
|
mkdirSync11(dir, { recursive: true });
|
|
26340
26579
|
}
|
|
26341
26580
|
const db = new Database3(dbPath);
|
|
@@ -27069,8 +27308,8 @@ var init_python_tools = __esm({
|
|
|
27069
27308
|
});
|
|
27070
27309
|
|
|
27071
27310
|
// src/tools.ts
|
|
27072
|
-
import { readFileSync as
|
|
27073
|
-
import { resolve as
|
|
27311
|
+
import { readFileSync as readFileSync41, existsSync as existsSync41 } from "fs";
|
|
27312
|
+
import { resolve as resolve35, basename as basename10 } from "path";
|
|
27074
27313
|
function prefix2() {
|
|
27075
27314
|
return getConfig().toolPrefix;
|
|
27076
27315
|
}
|
|
@@ -27105,7 +27344,7 @@ function ensureIndexes(dataDb, codegraphDb, force = false) {
|
|
|
27105
27344
|
if (config.python?.root) {
|
|
27106
27345
|
const pythonRoot = config.python.root;
|
|
27107
27346
|
const excludeDirs = config.python.exclude_dirs || ["__pycache__", ".venv", "venv", ".mypy_cache", ".pytest_cache"];
|
|
27108
|
-
if (force || isPythonDataStale(dataDb,
|
|
27347
|
+
if (force || isPythonDataStale(dataDb, resolve35(getProjectRoot(), pythonRoot))) {
|
|
27109
27348
|
const pyImports = buildPythonImportIndex(dataDb, pythonRoot, excludeDirs);
|
|
27110
27349
|
results.push(`Python imports: ${pyImports}`);
|
|
27111
27350
|
const pyRoutes = buildPythonRouteIndex(dataDb, pythonRoot, excludeDirs);
|
|
@@ -27540,9 +27779,9 @@ function handleContext(file, dataDb, codegraphDb) {
|
|
|
27540
27779
|
try {
|
|
27541
27780
|
const resolvedPaths = getResolvedPaths();
|
|
27542
27781
|
const root = getProjectRoot();
|
|
27543
|
-
const absFilePath = ensureWithinRoot(
|
|
27544
|
-
if (
|
|
27545
|
-
const fileContent =
|
|
27782
|
+
const absFilePath = ensureWithinRoot(resolve35(resolvedPaths.srcDir, "..", file), root);
|
|
27783
|
+
if (existsSync41(absFilePath)) {
|
|
27784
|
+
const fileContent = readFileSync41(absFilePath, "utf-8").slice(0, 3e3);
|
|
27546
27785
|
const keywords = [];
|
|
27547
27786
|
if (fileContent.includes("ctx.db")) keywords.push("database", "schema");
|
|
27548
27787
|
if (fileContent.includes("BigInt") || fileContent.includes("Decimal")) keywords.push("BigInt", "serialization");
|
|
@@ -27966,11 +28205,11 @@ function handleSchema(args2) {
|
|
|
27966
28205
|
lines.push("Checking all column references against Prisma schema...");
|
|
27967
28206
|
lines.push("");
|
|
27968
28207
|
const projectRoot = getProjectRoot();
|
|
27969
|
-
const absPath = ensureWithinRoot(
|
|
27970
|
-
if (!
|
|
28208
|
+
const absPath = ensureWithinRoot(resolve35(projectRoot, file), projectRoot);
|
|
28209
|
+
if (!existsSync41(absPath)) {
|
|
27971
28210
|
return text17(`File not found: ${file}`);
|
|
27972
28211
|
}
|
|
27973
|
-
const source =
|
|
28212
|
+
const source = readFileSync41(absPath, "utf-8");
|
|
27974
28213
|
const config = getConfig();
|
|
27975
28214
|
const dbPattern = config.dbAccessPattern ?? "ctx.db.{table}";
|
|
27976
28215
|
const regexStr = dbPattern.replace(/[.*+?^${}()|[\]\\]/g, "\\$&").replace("\\{table\\}", "(\\w+)");
|
|
@@ -28339,8 +28578,8 @@ var init_server_dispatch = __esm({
|
|
|
28339
28578
|
|
|
28340
28579
|
// src/server.ts
|
|
28341
28580
|
var server_exports = {};
|
|
28342
|
-
import { readFileSync as
|
|
28343
|
-
import { resolve as
|
|
28581
|
+
import { readFileSync as readFileSync42 } from "fs";
|
|
28582
|
+
import { resolve as resolve36, dirname as dirname17 } from "path";
|
|
28344
28583
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
28345
28584
|
function pruneMemoryOnStartup() {
|
|
28346
28585
|
try {
|
|
@@ -28375,7 +28614,7 @@ var init_server = __esm({
|
|
|
28375
28614
|
__dirname4 = dirname17(fileURLToPath4(import.meta.url));
|
|
28376
28615
|
PKG_VERSION = (() => {
|
|
28377
28616
|
try {
|
|
28378
|
-
const pkg = JSON.parse(
|
|
28617
|
+
const pkg = JSON.parse(readFileSync42(resolve36(__dirname4, "..", "package.json"), "utf-8"));
|
|
28379
28618
|
return pkg.version ?? "0.0.0";
|
|
28380
28619
|
} catch {
|
|
28381
28620
|
return "0.0.0";
|
|
@@ -28661,19 +28900,19 @@ var config_upgrade_exports = {};
|
|
|
28661
28900
|
__export(config_upgrade_exports, {
|
|
28662
28901
|
runConfigUpgrade: () => runConfigUpgrade
|
|
28663
28902
|
});
|
|
28664
|
-
import { existsSync as
|
|
28665
|
-
import { resolve as
|
|
28903
|
+
import { existsSync as existsSync42, readFileSync as readFileSync43, writeFileSync as writeFileSync6, copyFileSync, unlinkSync as unlinkSync2 } from "fs";
|
|
28904
|
+
import { resolve as resolve37 } from "path";
|
|
28666
28905
|
import { parse as parseYaml6 } from "yaml";
|
|
28667
28906
|
async function runConfigUpgrade(opts = {}) {
|
|
28668
28907
|
const cwd = opts.cwd ?? process.cwd();
|
|
28669
|
-
const configPath =
|
|
28908
|
+
const configPath = resolve37(cwd, "massu.config.yaml");
|
|
28670
28909
|
const bakPath = `${configPath}.bak`;
|
|
28671
28910
|
const log = opts.silent ? () => {
|
|
28672
28911
|
} : (s) => process.stdout.write(s);
|
|
28673
28912
|
const err = opts.silent ? () => {
|
|
28674
28913
|
} : (s) => process.stderr.write(s);
|
|
28675
28914
|
if (opts.rollback) {
|
|
28676
|
-
if (!
|
|
28915
|
+
if (!existsSync42(bakPath)) {
|
|
28677
28916
|
const message = `No backup found at ${bakPath}`;
|
|
28678
28917
|
err(message + "\n");
|
|
28679
28918
|
return { exitCode: 1, action: "none", message };
|
|
@@ -28689,14 +28928,14 @@ async function runConfigUpgrade(opts = {}) {
|
|
|
28689
28928
|
return { exitCode: 2, action: "none", message };
|
|
28690
28929
|
}
|
|
28691
28930
|
}
|
|
28692
|
-
if (!
|
|
28931
|
+
if (!existsSync42(configPath)) {
|
|
28693
28932
|
const message = "massu.config.yaml not found. Run: npx massu init";
|
|
28694
28933
|
err(message + "\n");
|
|
28695
28934
|
return { exitCode: 1, action: "none", message };
|
|
28696
28935
|
}
|
|
28697
28936
|
let existing;
|
|
28698
28937
|
try {
|
|
28699
|
-
const content =
|
|
28938
|
+
const content = readFileSync43(configPath, "utf-8");
|
|
28700
28939
|
const parsed = parseYaml6(content);
|
|
28701
28940
|
if (!parsed || typeof parsed !== "object") {
|
|
28702
28941
|
throw new Error("config is not a YAML object");
|
|
@@ -28719,7 +28958,7 @@ async function runConfigUpgrade(opts = {}) {
|
|
|
28719
28958
|
fingerprint: computeFingerprint(detection)
|
|
28720
28959
|
};
|
|
28721
28960
|
try {
|
|
28722
|
-
const original =
|
|
28961
|
+
const original = readFileSync43(configPath, "utf-8");
|
|
28723
28962
|
writeFileSync6(bakPath, original, "utf-8");
|
|
28724
28963
|
} catch (e2) {
|
|
28725
28964
|
const message = `Failed to write backup: ${e2 instanceof Error ? e2.message : String(e2)}`;
|
|
@@ -28753,8 +28992,8 @@ var config_check_drift_exports = {};
|
|
|
28753
28992
|
__export(config_check_drift_exports, {
|
|
28754
28993
|
runConfigCheckDrift: () => runConfigCheckDrift
|
|
28755
28994
|
});
|
|
28756
|
-
import { existsSync as
|
|
28757
|
-
import { resolve as
|
|
28995
|
+
import { existsSync as existsSync43, readFileSync as readFileSync44 } from "fs";
|
|
28996
|
+
import { resolve as resolve38 } from "path";
|
|
28758
28997
|
import { parse as parseYaml7 } from "yaml";
|
|
28759
28998
|
function renderChanges(changes) {
|
|
28760
28999
|
if (changes.length === 0) return "(none)\n";
|
|
@@ -28762,12 +29001,12 @@ function renderChanges(changes) {
|
|
|
28762
29001
|
}
|
|
28763
29002
|
async function runConfigCheckDrift(opts = {}) {
|
|
28764
29003
|
const cwd = opts.cwd ?? process.cwd();
|
|
28765
|
-
const configPath =
|
|
29004
|
+
const configPath = resolve38(cwd, "massu.config.yaml");
|
|
28766
29005
|
const log = opts.silent ? () => {
|
|
28767
29006
|
} : (s) => process.stdout.write(s);
|
|
28768
29007
|
const err = opts.silent ? () => {
|
|
28769
29008
|
} : (s) => process.stderr.write(s);
|
|
28770
|
-
if (!
|
|
29009
|
+
if (!existsSync43(configPath)) {
|
|
28771
29010
|
const message = "massu.config.yaml not found. Run: npx massu init";
|
|
28772
29011
|
err(message + "\n");
|
|
28773
29012
|
return {
|
|
@@ -28781,7 +29020,7 @@ async function runConfigCheckDrift(opts = {}) {
|
|
|
28781
29020
|
}
|
|
28782
29021
|
let config;
|
|
28783
29022
|
try {
|
|
28784
|
-
const content =
|
|
29023
|
+
const content = readFileSync44(configPath, "utf-8");
|
|
28785
29024
|
const parsed = parseYaml7(content);
|
|
28786
29025
|
if (!parsed || typeof parsed !== "object") {
|
|
28787
29026
|
throw new Error("config is not a YAML object");
|
|
@@ -28848,8 +29087,8 @@ var init_config_check_drift = __esm({
|
|
|
28848
29087
|
});
|
|
28849
29088
|
|
|
28850
29089
|
// src/cli.ts
|
|
28851
|
-
import { readFileSync as
|
|
28852
|
-
import { resolve as
|
|
29090
|
+
import { readFileSync as readFileSync45 } from "fs";
|
|
29091
|
+
import { resolve as resolve39, dirname as dirname18 } from "path";
|
|
28853
29092
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
28854
29093
|
var __filename4 = fileURLToPath5(import.meta.url);
|
|
28855
29094
|
var __dirname5 = dirname18(__filename4);
|
|
@@ -28883,6 +29122,12 @@ async function main() {
|
|
|
28883
29122
|
process.exit(result.exitCode);
|
|
28884
29123
|
return;
|
|
28885
29124
|
}
|
|
29125
|
+
case "changelog": {
|
|
29126
|
+
const { handleChangelogSubcommand: handleChangelogSubcommand2 } = await Promise.resolve().then(() => (init_changelog(), changelog_exports));
|
|
29127
|
+
const result = await handleChangelogSubcommand2(args.slice(1));
|
|
29128
|
+
process.exit(result.exitCode);
|
|
29129
|
+
return;
|
|
29130
|
+
}
|
|
28886
29131
|
case "show-template": {
|
|
28887
29132
|
const { runShowTemplate: runShowTemplate2 } = await Promise.resolve().then(() => (init_show_template(), show_template_exports));
|
|
28888
29133
|
await runShowTemplate2(args.slice(1));
|
|
@@ -29002,6 +29247,7 @@ Commands:
|
|
|
29002
29247
|
validate-config Validate massu.config.yaml (alias: config validate)
|
|
29003
29248
|
config <sub> Config lifecycle: refresh | validate | upgrade | doctor | check-drift
|
|
29004
29249
|
permissions <sub> MCP permission lifecycle: install | verify | check-drift
|
|
29250
|
+
changelog <sub> CHANGELOG generation / verification: generate | verify
|
|
29005
29251
|
adapters <sub> Third-party adapter registry: list | refresh | search | add-local | remove-local | install | resign
|
|
29006
29252
|
|
|
29007
29253
|
Options:
|
|
@@ -29041,7 +29287,7 @@ Examples:
|
|
|
29041
29287
|
}
|
|
29042
29288
|
function printVersion() {
|
|
29043
29289
|
try {
|
|
29044
|
-
const pkg = JSON.parse(
|
|
29290
|
+
const pkg = JSON.parse(readFileSync45(resolve39(__dirname5, "../package.json"), "utf-8"));
|
|
29045
29291
|
console.log(`massu v${pkg.version}`);
|
|
29046
29292
|
} catch {
|
|
29047
29293
|
console.log("massu v0.1.0");
|