@massu/core 1.16.0 → 1.16.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +58 -0
- package/dist/cli.js +468 -160
- package/dist/hooks/session-end.js +17 -7
- package/dist/hooks/session-start.js +17 -7
- package/dist/hooks/user-prompt.js +5 -4
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1212,6 +1212,20 @@ function setCandidateStatus(db, promptHash, status, destination) {
|
|
|
1212
1212
|
WHERE prompt_hash = ?
|
|
1213
1213
|
`).run(status, destination ?? null, promptHash);
|
|
1214
1214
|
}
|
|
1215
|
+
function getCandidate(db, promptHash) {
|
|
1216
|
+
ensureRuleCandidatesTable(db);
|
|
1217
|
+
const r2 = db.prepare("SELECT * FROM rule_candidates WHERE prompt_hash = ?").get(promptHash);
|
|
1218
|
+
if (!r2) return null;
|
|
1219
|
+
return { ...r2, payload: safeParse(r2.payload_json) };
|
|
1220
|
+
}
|
|
1221
|
+
function safeParse(raw) {
|
|
1222
|
+
try {
|
|
1223
|
+
const v3 = JSON.parse(raw);
|
|
1224
|
+
return typeof v3 === "object" && v3 !== null ? v3 : {};
|
|
1225
|
+
} catch {
|
|
1226
|
+
return {};
|
|
1227
|
+
}
|
|
1228
|
+
}
|
|
1215
1229
|
var init_rule_candidate_store = __esm({
|
|
1216
1230
|
"src/rule-candidate-store.ts"() {
|
|
1217
1231
|
"use strict";
|
|
@@ -16541,10 +16555,11 @@ var LICENSE_PUBKEY_ED25519, LICENSE_PUBKEY_FINGERPRINT_HEX, KNOWN_LICENSE_PUBKEY
|
|
|
16541
16555
|
var init_license_pubkey_generated = __esm({
|
|
16542
16556
|
"src/security/license-pubkey.generated.ts"() {
|
|
16543
16557
|
"use strict";
|
|
16544
|
-
LICENSE_PUBKEY_ED25519 = new Uint8Array([
|
|
16545
|
-
LICENSE_PUBKEY_FINGERPRINT_HEX = "
|
|
16558
|
+
LICENSE_PUBKEY_ED25519 = new Uint8Array([254, 188, 221, 150, 111, 252, 154, 100, 253, 247, 113, 192, 144, 224, 127, 160, 202, 111, 75, 40, 35, 169, 108, 89, 252, 250, 255, 233, 250, 120, 47, 160]);
|
|
16559
|
+
LICENSE_PUBKEY_FINGERPRINT_HEX = "18c0456789a70eeee28012719f04725f43f59e693f735227ff73f0475f2290e3";
|
|
16546
16560
|
KNOWN_LICENSE_PUBKEY_FINGERPRINTS = /* @__PURE__ */ new Set([
|
|
16547
|
-
"18a63d64fdec9e5a368fc45feaa49bed6ced815967e582bc7b8af534f22a9475"
|
|
16561
|
+
"18a63d64fdec9e5a368fc45feaa49bed6ced815967e582bc7b8af534f22a9475",
|
|
16562
|
+
"18c0456789a70eeee28012719f04725f43f59e693f735227ff73f0475f2290e3"
|
|
16548
16563
|
]);
|
|
16549
16564
|
}
|
|
16550
16565
|
});
|
|
@@ -16562,7 +16577,7 @@ function verifyLicenseResponse(payload) {
|
|
|
16562
16577
|
);
|
|
16563
16578
|
}
|
|
16564
16579
|
function isLicenseSignatureRequired() {
|
|
16565
|
-
return process.env.MASSU_REQUIRE_SIGNED_LICENSE
|
|
16580
|
+
return process.env.MASSU_REQUIRE_SIGNED_LICENSE !== "false";
|
|
16566
16581
|
}
|
|
16567
16582
|
var init_license_response_verifier = __esm({
|
|
16568
16583
|
"src/security/license-response-verifier.ts"() {
|
|
@@ -21363,6 +21378,173 @@ var init_rule_candidate_preview = __esm({
|
|
|
21363
21378
|
}
|
|
21364
21379
|
});
|
|
21365
21380
|
|
|
21381
|
+
// src/rule-candidate-renderer.ts
|
|
21382
|
+
function renderSignalLine(s) {
|
|
21383
|
+
const sign = s.applied >= 0 ? "+" : "";
|
|
21384
|
+
const evidence = s.evidence ? `: ${s.evidence}` : "";
|
|
21385
|
+
return `- ${s.name} (${sign}${s.applied})${evidence}`;
|
|
21386
|
+
}
|
|
21387
|
+
function fenced(language, body) {
|
|
21388
|
+
return ["```" + language, body, "```"].join("\n");
|
|
21389
|
+
}
|
|
21390
|
+
function renderCandidatePreview(candidate) {
|
|
21391
|
+
const lines = [];
|
|
21392
|
+
lines.push(`## Candidate ${candidate.prompt_hash}`);
|
|
21393
|
+
lines.push("");
|
|
21394
|
+
lines.push(`Timestamp: ${candidate.timestamp}`);
|
|
21395
|
+
lines.push("");
|
|
21396
|
+
lines.push("### 1. Detected correction");
|
|
21397
|
+
lines.push(`> ${candidate.prompt.replace(/\n+/g, " ").trim()}`);
|
|
21398
|
+
lines.push("");
|
|
21399
|
+
lines.push(`Score: ${candidate.score}/100 (threshold ${THRESHOLD})`);
|
|
21400
|
+
lines.push("Signals fired:");
|
|
21401
|
+
if (candidate.signals.length === 0) {
|
|
21402
|
+
lines.push("- (none)");
|
|
21403
|
+
} else {
|
|
21404
|
+
for (const s of candidate.signals) lines.push(renderSignalLine(s));
|
|
21405
|
+
}
|
|
21406
|
+
lines.push("");
|
|
21407
|
+
lines.push("### 2. Reacting to");
|
|
21408
|
+
if (candidate.prior_turn_files.length === 0) {
|
|
21409
|
+
lines.push("No prior Edit/Write detected in the previous assistant turn (the correction may target a free-text answer).");
|
|
21410
|
+
} else {
|
|
21411
|
+
lines.push("Prior assistant turn touched:");
|
|
21412
|
+
for (const f2 of candidate.prior_turn_files) lines.push(`- ${f2}`);
|
|
21413
|
+
}
|
|
21414
|
+
if (candidate.prior_turn_diff_snippet) {
|
|
21415
|
+
lines.push("");
|
|
21416
|
+
lines.push(fenced("diff", candidate.prior_turn_diff_snippet.trim()));
|
|
21417
|
+
}
|
|
21418
|
+
lines.push("");
|
|
21419
|
+
lines.push("### 3. Origin & status");
|
|
21420
|
+
lines.push(`- origin: ${candidate.origin ?? "local"}`);
|
|
21421
|
+
lines.push(`- status: ${candidate.status ?? "proposed"}`);
|
|
21422
|
+
lines.push(`- destination: ${candidate.destination ?? "(not yet chosen \u2014 decided at approve time)"}`);
|
|
21423
|
+
if (candidate.draft_text) {
|
|
21424
|
+
lines.push("- authoritative draft (team/pack):");
|
|
21425
|
+
lines.push(fenced("", candidate.draft_text));
|
|
21426
|
+
}
|
|
21427
|
+
lines.push("");
|
|
21428
|
+
lines.push("### 4. Next steps");
|
|
21429
|
+
lines.push("Review the exact text that would be applied, then approve or dismiss:");
|
|
21430
|
+
lines.push(
|
|
21431
|
+
fenced(
|
|
21432
|
+
"bash",
|
|
21433
|
+
`massu rule review ${candidate.prompt_hash} --destination <dest> --draft '<text>'
|
|
21434
|
+
massu rule approve ${candidate.prompt_hash} --destination <dest> --draft '<text>'
|
|
21435
|
+
massu rule dismiss ${candidate.prompt_hash} --reason '<why>'`
|
|
21436
|
+
)
|
|
21437
|
+
);
|
|
21438
|
+
lines.push("");
|
|
21439
|
+
return lines.join("\n");
|
|
21440
|
+
}
|
|
21441
|
+
var THRESHOLD;
|
|
21442
|
+
var init_rule_candidate_renderer = __esm({
|
|
21443
|
+
"src/rule-candidate-renderer.ts"() {
|
|
21444
|
+
"use strict";
|
|
21445
|
+
THRESHOLD = 60;
|
|
21446
|
+
}
|
|
21447
|
+
});
|
|
21448
|
+
|
|
21449
|
+
// src/rule-promotion-effectiveness.ts
|
|
21450
|
+
import { readFileSync as readFileSync28, existsSync as existsSync34 } from "fs";
|
|
21451
|
+
function evaluateCr53Effectiveness(inputs) {
|
|
21452
|
+
const { db, failureLogPath, knownLimitations } = inputs;
|
|
21453
|
+
const allowlist = new Set(knownLimitations.map((k3) => k3.promptHash));
|
|
21454
|
+
const auditRows = db.prepare(`
|
|
21455
|
+
SELECT id, file_path, metadata, timestamp
|
|
21456
|
+
FROM audit_log
|
|
21457
|
+
WHERE event_type = 'rule_promoted'
|
|
21458
|
+
AND timestamp < datetime('now', '-7 days')
|
|
21459
|
+
AND json_extract(metadata, '$.recurrence_count') > 0
|
|
21460
|
+
LIMIT 10000
|
|
21461
|
+
`).all();
|
|
21462
|
+
const auditViolations = [];
|
|
21463
|
+
for (const row of auditRows) {
|
|
21464
|
+
let meta = {};
|
|
21465
|
+
try {
|
|
21466
|
+
meta = JSON.parse(row.metadata);
|
|
21467
|
+
} catch {
|
|
21468
|
+
}
|
|
21469
|
+
const promptHash = String(meta.prompt_hash ?? "");
|
|
21470
|
+
if (allowlist.has(promptHash)) continue;
|
|
21471
|
+
const recurrenceCount = Number(meta.recurrence_count ?? 0);
|
|
21472
|
+
auditViolations.push({
|
|
21473
|
+
auditLogId: row.id,
|
|
21474
|
+
promptHash,
|
|
21475
|
+
filePath: row.file_path,
|
|
21476
|
+
recurrenceCount,
|
|
21477
|
+
timestamp: row.timestamp
|
|
21478
|
+
});
|
|
21479
|
+
}
|
|
21480
|
+
const failureLogViolations = [];
|
|
21481
|
+
if (existsSync34(failureLogPath)) {
|
|
21482
|
+
try {
|
|
21483
|
+
const raw = readFileSync28(failureLogPath, "utf-8");
|
|
21484
|
+
const cutoff = Date.now() - SEVEN_DAYS_MS;
|
|
21485
|
+
for (const line of raw.split("\n")) {
|
|
21486
|
+
const trimmed = line.trim();
|
|
21487
|
+
if (!trimmed) continue;
|
|
21488
|
+
let entry;
|
|
21489
|
+
try {
|
|
21490
|
+
entry = JSON.parse(trimmed);
|
|
21491
|
+
} catch {
|
|
21492
|
+
failureLogViolations.push({ rawLine: trimmed, error: "malformed JSON" });
|
|
21493
|
+
continue;
|
|
21494
|
+
}
|
|
21495
|
+
const ts = String(entry.timestamp ?? "");
|
|
21496
|
+
if (!ts) {
|
|
21497
|
+
failureLogViolations.push({ rawLine: trimmed, error: "missing timestamp" });
|
|
21498
|
+
continue;
|
|
21499
|
+
}
|
|
21500
|
+
const parsed = Date.parse(ts);
|
|
21501
|
+
if (Number.isNaN(parsed)) {
|
|
21502
|
+
failureLogViolations.push({ rawLine: trimmed, error: `invalid timestamp ${ts}` });
|
|
21503
|
+
continue;
|
|
21504
|
+
}
|
|
21505
|
+
if (parsed >= cutoff) {
|
|
21506
|
+
failureLogViolations.push({
|
|
21507
|
+
rawLine: trimmed,
|
|
21508
|
+
timestamp: ts,
|
|
21509
|
+
error: entry.error ? String(entry.error) : void 0
|
|
21510
|
+
});
|
|
21511
|
+
}
|
|
21512
|
+
}
|
|
21513
|
+
} catch {
|
|
21514
|
+
}
|
|
21515
|
+
}
|
|
21516
|
+
return {
|
|
21517
|
+
ok: auditViolations.length === 0 && failureLogViolations.length === 0,
|
|
21518
|
+
auditViolations,
|
|
21519
|
+
failureLogViolations
|
|
21520
|
+
};
|
|
21521
|
+
}
|
|
21522
|
+
function parseKnownLimitations(envVar) {
|
|
21523
|
+
if (!envVar) return [];
|
|
21524
|
+
try {
|
|
21525
|
+
const parsed = JSON.parse(envVar);
|
|
21526
|
+
if (!Array.isArray(parsed)) return [];
|
|
21527
|
+
const out = [];
|
|
21528
|
+
for (const item of parsed) {
|
|
21529
|
+
if (item && typeof item === "object" && "promptHash" in item && "reason" in item) {
|
|
21530
|
+
const promptHash = String(item.promptHash);
|
|
21531
|
+
const reason = String(item.reason);
|
|
21532
|
+
if (promptHash) out.push({ promptHash, reason });
|
|
21533
|
+
}
|
|
21534
|
+
}
|
|
21535
|
+
return out;
|
|
21536
|
+
} catch {
|
|
21537
|
+
return [];
|
|
21538
|
+
}
|
|
21539
|
+
}
|
|
21540
|
+
var SEVEN_DAYS_MS;
|
|
21541
|
+
var init_rule_promotion_effectiveness = __esm({
|
|
21542
|
+
"src/rule-promotion-effectiveness.ts"() {
|
|
21543
|
+
"use strict";
|
|
21544
|
+
SEVEN_DAYS_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
21545
|
+
}
|
|
21546
|
+
});
|
|
21547
|
+
|
|
21366
21548
|
// src/security/promotion-pubkey.generated.ts
|
|
21367
21549
|
var PROMOTION_PUBKEY_ED25519, PROMOTION_PUBKEY_FINGERPRINT_HEX, KNOWN_PROMOTION_PUBKEY_FINGERPRINTS;
|
|
21368
21550
|
var init_promotion_pubkey_generated = __esm({
|
|
@@ -21475,7 +21657,7 @@ var init_rule_pack_schema = __esm({
|
|
|
21475
21657
|
});
|
|
21476
21658
|
|
|
21477
21659
|
// src/rule-pack-sync.ts
|
|
21478
|
-
import { existsSync as
|
|
21660
|
+
import { existsSync as existsSync35, writeFileSync as writeFileSync11, mkdirSync as mkdirSync15 } from "fs";
|
|
21479
21661
|
import { join as join21, dirname as dirname18 } from "path";
|
|
21480
21662
|
async function pullInstalledPackRules(db, opts = {}) {
|
|
21481
21663
|
const config = getConfig();
|
|
@@ -21497,10 +21679,11 @@ async function pullInstalledPackRules(db, opts = {}) {
|
|
|
21497
21679
|
headers: { Authorization: `Bearer ${apiKey}` },
|
|
21498
21680
|
signal: AbortSignal.timeout(timeoutMs)
|
|
21499
21681
|
});
|
|
21500
|
-
if (!res.ok) return {
|
|
21682
|
+
if (!res.ok) return failSync(db, `http_${res.status}`);
|
|
21501
21683
|
envelope = await res.json();
|
|
21502
|
-
} catch {
|
|
21503
|
-
|
|
21684
|
+
} catch (err) {
|
|
21685
|
+
const reason = err instanceof Error && err.name === "TimeoutError" ? "timeout" : "network";
|
|
21686
|
+
return failSync(db, reason);
|
|
21504
21687
|
}
|
|
21505
21688
|
const verdict = verifyPromotionEnvelope(envelope);
|
|
21506
21689
|
if (verdict.kind !== "valid") {
|
|
@@ -21538,7 +21721,7 @@ async function pullInstalledPackRules(db, opts = {}) {
|
|
|
21538
21721
|
result.pulled += 1;
|
|
21539
21722
|
const promptHash = packRulePromptHash(pack.slug, rule);
|
|
21540
21723
|
const candidatePath = sidecarPath(projectRoot, promptHash);
|
|
21541
|
-
if (
|
|
21724
|
+
if (existsSync35(candidatePath) || alreadyApplied(db, promptHash)) {
|
|
21542
21725
|
result.skipped += 1;
|
|
21543
21726
|
continue;
|
|
21544
21727
|
}
|
|
@@ -21626,7 +21809,7 @@ function materializeCandidate(projectRoot, candidatePath, promptHash, rule, pack
|
|
|
21626
21809
|
draft_text: draftText
|
|
21627
21810
|
};
|
|
21628
21811
|
const dir = dirname18(candidatePath);
|
|
21629
|
-
if (!
|
|
21812
|
+
if (!existsSync35(dir)) mkdirSync15(dir, { recursive: true });
|
|
21630
21813
|
writeFileSync11(candidatePath, JSON.stringify(sidecar, null, 2), "utf-8");
|
|
21631
21814
|
}
|
|
21632
21815
|
function emitDropTelemetry(db, eventType, data) {
|
|
@@ -21636,6 +21819,14 @@ function emitDropTelemetry(db, eventType, data) {
|
|
|
21636
21819
|
`
|
|
21637
21820
|
);
|
|
21638
21821
|
}
|
|
21822
|
+
function failSync(db, reason) {
|
|
21823
|
+
recordTelemetry(db, "installed_pack_rules_sync_failed", { reason });
|
|
21824
|
+
process.stderr.write(
|
|
21825
|
+
`[massu] installed-pack rules pull FAILED (${reason}). This is NOT "nothing to sync" \u2014 the cloud was unreachable or rejected the request; installed-pack rules were NOT refreshed this run.
|
|
21826
|
+
`
|
|
21827
|
+
);
|
|
21828
|
+
return { ...ZERO, sync_error: reason };
|
|
21829
|
+
}
|
|
21639
21830
|
var DEFAULT_TIMEOUT_MS, ZERO;
|
|
21640
21831
|
var init_rule_pack_sync = __esm({
|
|
21641
21832
|
"src/rule-pack-sync.ts"() {
|
|
@@ -21715,6 +21906,82 @@ async function handleRuleSubcommand(args2) {
|
|
|
21715
21906
|
}
|
|
21716
21907
|
return { exitCode: 0 };
|
|
21717
21908
|
}
|
|
21909
|
+
case "effectiveness": {
|
|
21910
|
+
const db = getMemoryDb();
|
|
21911
|
+
try {
|
|
21912
|
+
const failureLogPath = join22(
|
|
21913
|
+
getProjectRoot(),
|
|
21914
|
+
".massu",
|
|
21915
|
+
"rule-candidates",
|
|
21916
|
+
".cr53-increment-failures.jsonl"
|
|
21917
|
+
);
|
|
21918
|
+
const knownLimitations = parseKnownLimitations(process.env.MASSU_KNOWN_RULE_LIMITATIONS);
|
|
21919
|
+
const result = evaluateCr53Effectiveness({ db, failureLogPath, knownLimitations });
|
|
21920
|
+
if (result.ok) {
|
|
21921
|
+
process.stdout.write(
|
|
21922
|
+
"CR-53 effectiveness: OK \u2014 every rule promoted more than 7 days ago has prevented its bug class (0 recurrences), and no unresolved increment failures.\n"
|
|
21923
|
+
);
|
|
21924
|
+
return { exitCode: 0 };
|
|
21925
|
+
}
|
|
21926
|
+
process.stdout.write(
|
|
21927
|
+
`CR-53 effectiveness: PROBLEM \u2014 ${result.auditViolations.length} recurring promoted rule(s) and ${result.failureLogViolations.length} unresolved increment failure(s) in the last 7 days.
|
|
21928
|
+
A recurrence means an auto-learned rule did NOT prevent the bug class it was promoted to enforce.
|
|
21929
|
+
`
|
|
21930
|
+
);
|
|
21931
|
+
for (const v3 of result.auditViolations) {
|
|
21932
|
+
process.stdout.write(
|
|
21933
|
+
` - rule ${v3.promptHash} recurred ${v3.recurrenceCount}x (audit_log #${v3.auditLogId}, promoted ${v3.timestamp})` + (v3.filePath ? ` \u2014 ${v3.filePath}` : "") + "\n"
|
|
21934
|
+
);
|
|
21935
|
+
}
|
|
21936
|
+
for (const v3 of result.failureLogViolations) {
|
|
21937
|
+
process.stdout.write(
|
|
21938
|
+
` - increment failure: ${v3.error ?? "recent entry"} ${v3.timestamp ?? ""}
|
|
21939
|
+
`
|
|
21940
|
+
);
|
|
21941
|
+
}
|
|
21942
|
+
process.stdout.write(
|
|
21943
|
+
" If a recurrence is a genuine documented limitation, allowlist it via the MASSU_KNOWN_RULE_LIMITATIONS env var.\n"
|
|
21944
|
+
);
|
|
21945
|
+
return { exitCode: 1 };
|
|
21946
|
+
} finally {
|
|
21947
|
+
db.close();
|
|
21948
|
+
}
|
|
21949
|
+
}
|
|
21950
|
+
case "show": {
|
|
21951
|
+
const candidateId = args2[1];
|
|
21952
|
+
if (!candidateId) {
|
|
21953
|
+
process.stderr.write("Usage: massu rule show <candidate_id>\n");
|
|
21954
|
+
return { exitCode: 2 };
|
|
21955
|
+
}
|
|
21956
|
+
let payload;
|
|
21957
|
+
try {
|
|
21958
|
+
payload = readCandidate(candidateId);
|
|
21959
|
+
} catch (err) {
|
|
21960
|
+
process.stderr.write(`massu: ${err instanceof Error ? err.message : String(err)}
|
|
21961
|
+
`);
|
|
21962
|
+
return { exitCode: 1 };
|
|
21963
|
+
}
|
|
21964
|
+
const db = getMemoryDb();
|
|
21965
|
+
try {
|
|
21966
|
+
const row = getCandidate(db, candidateId);
|
|
21967
|
+
const preview = renderCandidatePreview({
|
|
21968
|
+
prompt_hash: payload.prompt_hash,
|
|
21969
|
+
prompt: payload.prompt,
|
|
21970
|
+
score: payload.score,
|
|
21971
|
+
signals: payload.signals,
|
|
21972
|
+
prior_turn_files: payload.prior_turn_files,
|
|
21973
|
+
timestamp: payload.timestamp,
|
|
21974
|
+
origin: row?.origin ?? "local",
|
|
21975
|
+
status: row?.status ?? "proposed",
|
|
21976
|
+
destination: payload.destination ?? row?.destination ?? null,
|
|
21977
|
+
...payload.draft_text ? { draft_text: payload.draft_text } : {}
|
|
21978
|
+
});
|
|
21979
|
+
process.stdout.write(preview + "\n");
|
|
21980
|
+
return { exitCode: 0 };
|
|
21981
|
+
} finally {
|
|
21982
|
+
db.close();
|
|
21983
|
+
}
|
|
21984
|
+
}
|
|
21718
21985
|
case "review": {
|
|
21719
21986
|
const candidateId = args2[1];
|
|
21720
21987
|
if (!candidateId) {
|
|
@@ -21887,7 +22154,7 @@ Cloud sync has given up ${giveups.n} time(s) (most recent: ${giveups.last}).
|
|
|
21887
22154
|
case "-h":
|
|
21888
22155
|
case void 0: {
|
|
21889
22156
|
process.stdout.write(
|
|
21890
|
-
"massu rule <subcommand>\n\nSubcommands:\n approve <id> --destination <d> --draft <text>\n Promote a candidate to a rule (Pro+). Shares to your team at Team+.\n dismiss <id> [--reason ...] Dismiss a candidate and downweight its signals.\n review <id> --destination <d> --draft <text>\n Preview a HARDENED (executable) promotion + its risk findings;\n add --attest-operator/--attest-note to record a 2nd-operator review.\n record-shown <prompt_hash> Record a `shown` promotion-funnel event (Team-gated, best-effort).\n packs Pull installed rule-pack rules as reviewable candidates (Team-gated).\n delivery-status Show which learned rules have not yet reached your team, and why.\n"
|
|
22157
|
+
"massu rule <subcommand>\n\nSubcommands:\n show <id> Show a detected candidate (the correction, score, signals,\n what it reacted to) before deciding to review/approve/dismiss.\n approve <id> --destination <d> --draft <text>\n Promote a candidate to a rule (Pro+). Shares to your team at Team+.\n dismiss <id> [--reason ...] Dismiss a candidate and downweight its signals.\n review <id> --destination <d> --draft <text>\n Preview a HARDENED (executable) promotion + its risk findings;\n add --attest-operator/--attest-note to record a 2nd-operator review.\n record-shown <prompt_hash> Record a `shown` promotion-funnel event (Team-gated, best-effort).\n packs Pull installed rule-pack rules as reviewable candidates (Team-gated).\n delivery-status Show which learned rules have not yet reached your team, and why.\n effectiveness Check CR-53 over the live audit_log: has any promoted rule\n (older than 7 days) failed to prevent its bug class? Exits non-zero if so.\n"
|
|
21891
22158
|
);
|
|
21892
22159
|
return { exitCode: 0 };
|
|
21893
22160
|
}
|
|
@@ -21907,6 +22174,9 @@ var init_rule = __esm({
|
|
|
21907
22174
|
init_rule_delivery();
|
|
21908
22175
|
init_rule_candidate_applier();
|
|
21909
22176
|
init_rule_candidate_preview();
|
|
22177
|
+
init_rule_candidate_store();
|
|
22178
|
+
init_rule_candidate_renderer();
|
|
22179
|
+
init_rule_promotion_effectiveness();
|
|
21910
22180
|
init_license();
|
|
21911
22181
|
init_auto_learning_entitlement();
|
|
21912
22182
|
init_rule_pack_sync();
|
|
@@ -22410,7 +22680,7 @@ var init_memory_supersede = __esm({
|
|
|
22410
22680
|
|
|
22411
22681
|
// src/memory-consolidate.ts
|
|
22412
22682
|
import { createHash as createHash10 } from "crypto";
|
|
22413
|
-
import { existsSync as
|
|
22683
|
+
import { existsSync as existsSync36, mkdirSync as mkdirSync16, writeFileSync as writeFileSync12 } from "fs";
|
|
22414
22684
|
import { join as join23 } from "path";
|
|
22415
22685
|
function emptyResult() {
|
|
22416
22686
|
return {
|
|
@@ -22587,7 +22857,7 @@ ${representative.detail}` : ""}`;
|
|
|
22587
22857
|
const clusterKey = cluster.map((c2) => c2.title.toLowerCase().replace(/\s+/g, " ").trim()).sort().join("|");
|
|
22588
22858
|
const promptHash = createHash10("sha256").update(clusterKey).digest("hex").slice(0, 16);
|
|
22589
22859
|
const candidatePath = join23(candidateDir, `${promptHash}.json`);
|
|
22590
|
-
if (
|
|
22860
|
+
if (existsSync36(candidatePath)) continue;
|
|
22591
22861
|
if (dryRun) {
|
|
22592
22862
|
promoted++;
|
|
22593
22863
|
continue;
|
|
@@ -22863,7 +23133,7 @@ var show_template_exports = {};
|
|
|
22863
23133
|
__export(show_template_exports, {
|
|
22864
23134
|
runShowTemplate: () => runShowTemplate
|
|
22865
23135
|
});
|
|
22866
|
-
import { existsSync as
|
|
23136
|
+
import { existsSync as existsSync37, readFileSync as readFileSync29 } from "fs";
|
|
22867
23137
|
import { resolve as resolve17 } from "path";
|
|
22868
23138
|
function normalizeBaseName(input) {
|
|
22869
23139
|
return input.endsWith(".md") ? input.slice(0, -".md".length) : input;
|
|
@@ -22893,13 +23163,13 @@ async function runShowTemplate(args2) {
|
|
|
22893
23163
|
}
|
|
22894
23164
|
const suffix = choice.kind === "hit" ? choice.suffix : "";
|
|
22895
23165
|
const file = suffix === "" ? resolve17(sourceDir, `${baseName}.md`) : resolve17(sourceDir, `${baseName}${suffix}.md`);
|
|
22896
|
-
if (!
|
|
23166
|
+
if (!existsSync37(file)) {
|
|
22897
23167
|
process.stderr.write(`massu: resolved template "${file}" no longer exists
|
|
22898
23168
|
`);
|
|
22899
23169
|
process.exit(1);
|
|
22900
23170
|
return;
|
|
22901
23171
|
}
|
|
22902
|
-
process.stdout.write(
|
|
23172
|
+
process.stdout.write(readFileSync29(file, "utf-8"));
|
|
22903
23173
|
}
|
|
22904
23174
|
var init_show_template = __esm({
|
|
22905
23175
|
"src/commands/show-template.ts"() {
|
|
@@ -22994,7 +23264,7 @@ __export(config_refresh_exports, {
|
|
|
22994
23264
|
mergeRefresh: () => mergeRefresh,
|
|
22995
23265
|
runConfigRefresh: () => runConfigRefresh
|
|
22996
23266
|
});
|
|
22997
|
-
import { existsSync as
|
|
23267
|
+
import { existsSync as existsSync38, readFileSync as readFileSync30, rmSync as rmSync8 } from "fs";
|
|
22998
23268
|
import { resolve as resolve19 } from "path";
|
|
22999
23269
|
import { parse as parseYaml5 } from "yaml";
|
|
23000
23270
|
function flatten(obj, prefix3 = "") {
|
|
@@ -23126,14 +23396,14 @@ async function runConfigRefresh(opts = {}) {
|
|
|
23126
23396
|
const configPath = resolve19(cwd, "massu.config.yaml");
|
|
23127
23397
|
const log = opts.silent ? () => {
|
|
23128
23398
|
} : (s) => process.stdout.write(s);
|
|
23129
|
-
if (!
|
|
23399
|
+
if (!existsSync38(configPath)) {
|
|
23130
23400
|
const message = "massu.config.yaml not found. Run: npx massu init";
|
|
23131
23401
|
if (!opts.silent) process.stderr.write(message + "\n");
|
|
23132
23402
|
return { exitCode: 1, applied: false, dryRun: !!opts.dryRun, diff: [], message };
|
|
23133
23403
|
}
|
|
23134
23404
|
let existing;
|
|
23135
23405
|
try {
|
|
23136
|
-
const content =
|
|
23406
|
+
const content = readFileSync30(configPath, "utf-8");
|
|
23137
23407
|
const parsed = parseYaml5(content);
|
|
23138
23408
|
if (!parsed || typeof parsed !== "object") {
|
|
23139
23409
|
throw new Error("config is not a YAML object");
|
|
@@ -23207,7 +23477,7 @@ async function runConfigRefresh(opts = {}) {
|
|
|
23207
23477
|
const stackResolved = installResult.totalInstalled > 0 || installResult.totalUpdated > 0;
|
|
23208
23478
|
if (stackResolved) {
|
|
23209
23479
|
const placeholderPath = resolve19(installResult.claudeDir, "commands", "_massu-needs-stack.md");
|
|
23210
|
-
if (
|
|
23480
|
+
if (existsSync38(placeholderPath)) {
|
|
23211
23481
|
try {
|
|
23212
23482
|
rmSync8(placeholderPath, { force: true });
|
|
23213
23483
|
log("Removed _massu-needs-stack.md (stack now declared).\n");
|
|
@@ -23316,12 +23586,12 @@ var init_gitToplevel = __esm({
|
|
|
23316
23586
|
});
|
|
23317
23587
|
|
|
23318
23588
|
// src/watch/lockfile-detector.ts
|
|
23319
|
-
import { existsSync as
|
|
23589
|
+
import { existsSync as existsSync39, statSync as statSync14 } from "fs";
|
|
23320
23590
|
import { resolve as resolve20 } from "path";
|
|
23321
23591
|
function lockfileMidWrite(projectRoot, now = Date.now(), windowMs = LOCKFILE_WINDOW_MS) {
|
|
23322
23592
|
for (const lf of KNOWN_LOCKFILES) {
|
|
23323
23593
|
const p19 = resolve20(projectRoot, lf);
|
|
23324
|
-
if (!
|
|
23594
|
+
if (!existsSync39(p19)) continue;
|
|
23325
23595
|
try {
|
|
23326
23596
|
const stat = statSync14(p19);
|
|
23327
23597
|
const delta = now - stat.mtimeMs;
|
|
@@ -23334,7 +23604,7 @@ function lockfileMidWrite(projectRoot, now = Date.now(), windowMs = LOCKFILE_WIN
|
|
|
23334
23604
|
function gitMidOperation(projectRoot) {
|
|
23335
23605
|
const sentinels = ["MERGE_HEAD", "REBASE_HEAD", "CHERRY_PICK_HEAD", "rebase-apply", "rebase-merge"];
|
|
23336
23606
|
for (const s of sentinels) {
|
|
23337
|
-
if (
|
|
23607
|
+
if (existsSync39(resolve20(projectRoot, ".git", s))) return true;
|
|
23338
23608
|
}
|
|
23339
23609
|
return false;
|
|
23340
23610
|
}
|
|
@@ -23533,7 +23803,7 @@ var init_paths = __esm({
|
|
|
23533
23803
|
});
|
|
23534
23804
|
|
|
23535
23805
|
// src/watch/state.ts
|
|
23536
|
-
import { closeSync as closeSync4, existsSync as
|
|
23806
|
+
import { closeSync as closeSync4, existsSync as existsSync40, fsyncSync as fsyncSync4, mkdirSync as mkdirSync17, openSync as openSync4, readFileSync as readFileSync31, renameSync as renameSync5, rmSync as rmSync9, writeFileSync as writeFileSync13, writeSync as writeSync3 } from "fs";
|
|
23537
23807
|
import { dirname as dirname19, resolve as resolve21 } from "path";
|
|
23538
23808
|
function watchStatePath(projectRoot) {
|
|
23539
23809
|
return resolve21(projectRoot, ".massu", "watch-state.json");
|
|
@@ -23543,8 +23813,8 @@ function backupStatePath(projectRoot) {
|
|
|
23543
23813
|
}
|
|
23544
23814
|
function readState(projectRoot) {
|
|
23545
23815
|
const path = watchStatePath(projectRoot);
|
|
23546
|
-
if (!
|
|
23547
|
-
const content =
|
|
23816
|
+
if (!existsSync40(path)) return { ...DEFAULT_STATE };
|
|
23817
|
+
const content = readFileSync31(path, "utf-8");
|
|
23548
23818
|
let raw;
|
|
23549
23819
|
try {
|
|
23550
23820
|
raw = JSON.parse(content);
|
|
@@ -23607,7 +23877,7 @@ function writeStateAtomic(projectRoot, state) {
|
|
|
23607
23877
|
renameSync5(tmp, path);
|
|
23608
23878
|
renamed = true;
|
|
23609
23879
|
} finally {
|
|
23610
|
-
if (!renamed &&
|
|
23880
|
+
if (!renamed && existsSync40(tmp)) {
|
|
23611
23881
|
try {
|
|
23612
23882
|
rmSync9(tmp, { force: true });
|
|
23613
23883
|
} catch {
|
|
@@ -23890,7 +24160,7 @@ __export(watch_exports, {
|
|
|
23890
24160
|
});
|
|
23891
24161
|
import { spawnSync as spawnSync3 } from "child_process";
|
|
23892
24162
|
import { basename as basename8, dirname as dirname20, resolve as resolve22 } from "path";
|
|
23893
|
-
import { appendFileSync as appendFileSync3, existsSync as
|
|
24163
|
+
import { appendFileSync as appendFileSync3, existsSync as existsSync41, mkdirSync as mkdirSync18, readFileSync as readFileSync32 } from "fs";
|
|
23894
24164
|
function parseFlags(args2) {
|
|
23895
24165
|
const out = {
|
|
23896
24166
|
foreground: false,
|
|
@@ -23916,7 +24186,7 @@ function parseFlags(args2) {
|
|
|
23916
24186
|
function findClaudeBg() {
|
|
23917
24187
|
const home = process.env.HOME ?? "";
|
|
23918
24188
|
const fixed = home ? resolve22(home, ".claude", "bin", "claude-bg") : null;
|
|
23919
|
-
if (fixed &&
|
|
24189
|
+
if (fixed && existsSync41(fixed)) return fixed;
|
|
23920
24190
|
const which = spawnSync3("which", ["claude-bg"], { encoding: "utf-8" });
|
|
23921
24191
|
if (which.status === 0 && which.stdout) {
|
|
23922
24192
|
const p19 = which.stdout.trim();
|
|
@@ -23977,7 +24247,7 @@ async function runWatch(args2) {
|
|
|
23977
24247
|
}
|
|
23978
24248
|
function runStatus(root) {
|
|
23979
24249
|
const path = watchStatePath(root);
|
|
23980
|
-
if (!
|
|
24250
|
+
if (!existsSync41(path)) {
|
|
23981
24251
|
process.stdout.write("massu watch: not running (no state file)\n");
|
|
23982
24252
|
return { exitCode: 0 };
|
|
23983
24253
|
}
|
|
@@ -24142,11 +24412,11 @@ function appendRefreshLog(projectRoot, event) {
|
|
|
24142
24412
|
}
|
|
24143
24413
|
function readRefreshLog(projectRoot, limit = 10, opts = {}) {
|
|
24144
24414
|
const path = refreshLogPath(projectRoot);
|
|
24145
|
-
if (!
|
|
24415
|
+
if (!existsSync41(path)) return [];
|
|
24146
24416
|
const warn = opts.warn ?? ((s) => {
|
|
24147
24417
|
process.stderr.write(s);
|
|
24148
24418
|
});
|
|
24149
|
-
const lines =
|
|
24419
|
+
const lines = readFileSync32(path, "utf-8").split("\n").filter(Boolean);
|
|
24150
24420
|
const tail = lines.slice(-limit);
|
|
24151
24421
|
const out = [];
|
|
24152
24422
|
let corrupt = 0;
|
|
@@ -24219,7 +24489,7 @@ var init_refresh_log = __esm({
|
|
|
24219
24489
|
import {
|
|
24220
24490
|
chmodSync as chmodSync6,
|
|
24221
24491
|
closeSync as closeSync5,
|
|
24222
|
-
existsSync as
|
|
24492
|
+
existsSync as existsSync42,
|
|
24223
24493
|
fsyncSync as fsyncSync5,
|
|
24224
24494
|
mkdirSync as mkdirSync19,
|
|
24225
24495
|
openSync as openSync5,
|
|
@@ -24233,7 +24503,7 @@ function atomicWrite(path, content, opts = {}) {
|
|
|
24233
24503
|
const tmpPath = `${path}.tmp`;
|
|
24234
24504
|
const parentDir = dirname21(path);
|
|
24235
24505
|
try {
|
|
24236
|
-
if (!
|
|
24506
|
+
if (!existsSync42(parentDir)) {
|
|
24237
24507
|
const mkdirOpts = { recursive: true };
|
|
24238
24508
|
if (opts.ensureParentDirMode !== void 0) {
|
|
24239
24509
|
mkdirOpts.mode = opts.ensureParentDirMode;
|
|
@@ -24255,7 +24525,7 @@ function atomicWrite(path, content, opts = {}) {
|
|
|
24255
24525
|
renameSync6(tmpPath, path);
|
|
24256
24526
|
return { written: true };
|
|
24257
24527
|
} catch (err) {
|
|
24258
|
-
if (
|
|
24528
|
+
if (existsSync42(tmpPath)) {
|
|
24259
24529
|
try {
|
|
24260
24530
|
rmSync10(tmpPath, { force: true });
|
|
24261
24531
|
} catch {
|
|
@@ -24604,7 +24874,7 @@ var init_fetcher = __esm({
|
|
|
24604
24874
|
});
|
|
24605
24875
|
|
|
24606
24876
|
// src/security/manifest-cache.ts
|
|
24607
|
-
import { existsSync as
|
|
24877
|
+
import { existsSync as existsSync43, readFileSync as readFileSync33, statSync as statSync16 } from "node:fs";
|
|
24608
24878
|
import { homedir as homedir13 } from "node:os";
|
|
24609
24879
|
import { resolve as resolve23 } from "node:path";
|
|
24610
24880
|
import { z as z5 } from "zod";
|
|
@@ -24616,12 +24886,12 @@ function defaultCachePaths() {
|
|
|
24616
24886
|
};
|
|
24617
24887
|
}
|
|
24618
24888
|
function loadCachedManifest(paths = defaultCachePaths()) {
|
|
24619
|
-
if (!
|
|
24889
|
+
if (!existsSync43(paths.cachePath)) {
|
|
24620
24890
|
return { kind: "absent" };
|
|
24621
24891
|
}
|
|
24622
24892
|
let raw;
|
|
24623
24893
|
try {
|
|
24624
|
-
const content =
|
|
24894
|
+
const content = readFileSync33(paths.cachePath, "utf-8");
|
|
24625
24895
|
raw = JSON.parse(content);
|
|
24626
24896
|
} catch (err) {
|
|
24627
24897
|
return {
|
|
@@ -24810,7 +25080,7 @@ var init_adapter_origin = __esm({
|
|
|
24810
25080
|
});
|
|
24811
25081
|
|
|
24812
25082
|
// src/security/local-fingerprint.ts
|
|
24813
|
-
import { existsSync as
|
|
25083
|
+
import { existsSync as existsSync44, readFileSync as readFileSync34, lstatSync as lstatSync5 } from "node:fs";
|
|
24814
25084
|
import { homedir as homedir14 } from "node:os";
|
|
24815
25085
|
import { resolve as resolve24, isAbsolute as isAbsolute3 } from "node:path";
|
|
24816
25086
|
import { createHash as createHash12 } from "node:crypto";
|
|
@@ -24827,7 +25097,7 @@ function computeLocalFingerprint(localPaths, projectRoot) {
|
|
|
24827
25097
|
} else if (!lst.isFile()) {
|
|
24828
25098
|
contentTag = "<not-a-file>";
|
|
24829
25099
|
} else {
|
|
24830
|
-
contentTag = createHash12("sha256").update(
|
|
25100
|
+
contentTag = createHash12("sha256").update(readFileSync34(abs)).digest("hex");
|
|
24831
25101
|
}
|
|
24832
25102
|
} catch {
|
|
24833
25103
|
contentTag = "<missing>";
|
|
@@ -24839,10 +25109,10 @@ function computeLocalFingerprint(localPaths, projectRoot) {
|
|
|
24839
25109
|
return createHash12("sha256").update(canonical).digest("hex");
|
|
24840
25110
|
}
|
|
24841
25111
|
function readFingerprintSentinel(path = FINGERPRINT_PATH) {
|
|
24842
|
-
if (!
|
|
25112
|
+
if (!existsSync44(path)) return null;
|
|
24843
25113
|
let raw;
|
|
24844
25114
|
try {
|
|
24845
|
-
raw = JSON.parse(
|
|
25115
|
+
raw = JSON.parse(readFileSync34(path, "utf-8"));
|
|
24846
25116
|
} catch {
|
|
24847
25117
|
return null;
|
|
24848
25118
|
}
|
|
@@ -24906,7 +25176,7 @@ var init_local_fingerprint = __esm({
|
|
|
24906
25176
|
});
|
|
24907
25177
|
|
|
24908
25178
|
// src/security/install-tracking.ts
|
|
24909
|
-
import { readFileSync as
|
|
25179
|
+
import { readFileSync as readFileSync35, readdirSync as readdirSync16, lstatSync as lstatSync6, existsSync as existsSync45 } from "node:fs";
|
|
24910
25180
|
import { join as join24, relative as relative7, sep as sep2 } from "node:path";
|
|
24911
25181
|
import { homedir as homedir15 } from "node:os";
|
|
24912
25182
|
import { resolve as resolve25 } from "node:path";
|
|
@@ -24914,7 +25184,7 @@ import { createHash as createHash13 } from "node:crypto";
|
|
|
24914
25184
|
import { z as z7 } from "zod";
|
|
24915
25185
|
function containsHiddenDirs(packageDir) {
|
|
24916
25186
|
for (const hidden of EXCLUDED_DIR_NAMES) {
|
|
24917
|
-
if (
|
|
25187
|
+
if (existsSync45(`${packageDir}/${hidden}`)) {
|
|
24918
25188
|
return hidden;
|
|
24919
25189
|
}
|
|
24920
25190
|
}
|
|
@@ -24960,7 +25230,7 @@ function sha256OfDir(dir, opts = {}) {
|
|
|
24960
25230
|
files.sort((a2, b2) => a2.relativePath < b2.relativePath ? -1 : a2.relativePath > b2.relativePath ? 1 : 0);
|
|
24961
25231
|
const top = createHash13("sha256");
|
|
24962
25232
|
for (const f2 of files) {
|
|
24963
|
-
const fileHash = createHash13("sha256").update(
|
|
25233
|
+
const fileHash = createHash13("sha256").update(readFileSync35(f2.absPath)).digest("hex");
|
|
24964
25234
|
top.update(f2.relativePath, "utf-8");
|
|
24965
25235
|
top.update("\0", "utf-8");
|
|
24966
25236
|
top.update(fileHash, "utf-8");
|
|
@@ -24969,10 +25239,10 @@ function sha256OfDir(dir, opts = {}) {
|
|
|
24969
25239
|
return top.digest("hex");
|
|
24970
25240
|
}
|
|
24971
25241
|
function readInstalledManifest(path = INSTALLED_MANIFEST_PATH) {
|
|
24972
|
-
if (!
|
|
25242
|
+
if (!existsSync45(path)) return {};
|
|
24973
25243
|
let raw;
|
|
24974
25244
|
try {
|
|
24975
|
-
raw = JSON.parse(
|
|
25245
|
+
raw = JSON.parse(readFileSync35(path, "utf-8"));
|
|
24976
25246
|
} catch {
|
|
24977
25247
|
return {};
|
|
24978
25248
|
}
|
|
@@ -25059,12 +25329,12 @@ var init_install_tracking = __esm({
|
|
|
25059
25329
|
});
|
|
25060
25330
|
|
|
25061
25331
|
// src/detect/adapters/discover.ts
|
|
25062
|
-
import { existsSync as
|
|
25332
|
+
import { existsSync as existsSync46, readdirSync as readdirSync17, readFileSync as readFileSync36, lstatSync as lstatSync7 } from "node:fs";
|
|
25063
25333
|
import { resolve as resolve26, isAbsolute as isAbsolute4 } from "node:path";
|
|
25064
25334
|
import { z as z8 } from "zod";
|
|
25065
25335
|
function walkNodeModules(projectRoot, warnings) {
|
|
25066
25336
|
const nodeModulesDir = resolve26(projectRoot, "node_modules");
|
|
25067
|
-
if (!
|
|
25337
|
+
if (!existsSync46(nodeModulesDir)) {
|
|
25068
25338
|
return [];
|
|
25069
25339
|
}
|
|
25070
25340
|
const candidates = [];
|
|
@@ -25119,10 +25389,10 @@ function walkNodeModules(projectRoot, warnings) {
|
|
|
25119
25389
|
}
|
|
25120
25390
|
function tryReadAdapterPackage(packageDir, warnings) {
|
|
25121
25391
|
const pkgJsonPath = resolve26(packageDir, "package.json");
|
|
25122
|
-
if (!
|
|
25392
|
+
if (!existsSync46(pkgJsonPath)) return null;
|
|
25123
25393
|
let raw;
|
|
25124
25394
|
try {
|
|
25125
|
-
raw = JSON.parse(
|
|
25395
|
+
raw = JSON.parse(readFileSync36(pkgJsonPath, "utf-8"));
|
|
25126
25396
|
} catch (err) {
|
|
25127
25397
|
warnings.push(
|
|
25128
25398
|
`skipping ${packageDir}: package.json parse failed (${err instanceof Error ? err.message : String(err)})`
|
|
@@ -25257,7 +25527,7 @@ function discoverAdapters(opts) {
|
|
|
25257
25527
|
for (const localPath of opts.configLocalPaths) {
|
|
25258
25528
|
if (seenIds.has(localPath)) continue;
|
|
25259
25529
|
const absPath = isAbsolute4(localPath) ? localPath : resolve26(opts.projectRoot, localPath);
|
|
25260
|
-
if (!
|
|
25530
|
+
if (!existsSync46(absPath)) {
|
|
25261
25531
|
warnings.push(
|
|
25262
25532
|
`local adapter file not found: ${localPath} (resolved to ${absPath}). Remove via: massu adapters remove-local ${localPath}`
|
|
25263
25533
|
);
|
|
@@ -25339,7 +25609,7 @@ __export(adapters_exports, {
|
|
|
25339
25609
|
runAdaptersResyncLocalFingerprint: () => runAdaptersResyncLocalFingerprint,
|
|
25340
25610
|
runAdaptersSearch: () => runAdaptersSearch
|
|
25341
25611
|
});
|
|
25342
|
-
import { existsSync as
|
|
25612
|
+
import { existsSync as existsSync47, readFileSync as readFileSync37 } from "node:fs";
|
|
25343
25613
|
import { resolve as resolve27 } from "node:path";
|
|
25344
25614
|
import { parseDocument } from "yaml";
|
|
25345
25615
|
async function handleAdaptersSubcommand(args2) {
|
|
@@ -25608,7 +25878,7 @@ function mutateLocalArray(mutator, command) {
|
|
|
25608
25878
|
return { exitCode: 2 };
|
|
25609
25879
|
}
|
|
25610
25880
|
const yamlPath = resolve27(projectRoot, "massu.config.yaml");
|
|
25611
|
-
if (!
|
|
25881
|
+
if (!existsSync47(yamlPath)) {
|
|
25612
25882
|
process.stderr.write(
|
|
25613
25883
|
`${command}: massu.config.yaml not found at ${yamlPath}. Run \`massu init\` first.
|
|
25614
25884
|
`
|
|
@@ -25617,7 +25887,7 @@ function mutateLocalArray(mutator, command) {
|
|
|
25617
25887
|
}
|
|
25618
25888
|
let yamlText;
|
|
25619
25889
|
try {
|
|
25620
|
-
yamlText =
|
|
25890
|
+
yamlText = readFileSync37(yamlPath, "utf-8");
|
|
25621
25891
|
} catch (err) {
|
|
25622
25892
|
process.stderr.write(`${command}: failed to read ${yamlPath}: ${err instanceof Error ? err.message : String(err)}
|
|
25623
25893
|
`);
|
|
@@ -25708,7 +25978,7 @@ async function runAdaptersInstall(args2) {
|
|
|
25708
25978
|
return { exitCode: 1 };
|
|
25709
25979
|
}
|
|
25710
25980
|
const packageDir = resolve27(projectRoot, "node_modules", ...packageName.split("/"));
|
|
25711
|
-
if (!
|
|
25981
|
+
if (!existsSync47(packageDir)) {
|
|
25712
25982
|
process.stderr.write(
|
|
25713
25983
|
`install: ${packageName} is not installed in node_modules. Run \`npm install ${packageName}\` first.
|
|
25714
25984
|
`
|
|
@@ -25716,14 +25986,14 @@ async function runAdaptersInstall(args2) {
|
|
|
25716
25986
|
return { exitCode: 1 };
|
|
25717
25987
|
}
|
|
25718
25988
|
const pkgJsonPath = resolve27(packageDir, "package.json");
|
|
25719
|
-
if (!
|
|
25989
|
+
if (!existsSync47(pkgJsonPath)) {
|
|
25720
25990
|
process.stderr.write(`install: ${packageName} has no package.json at ${pkgJsonPath}
|
|
25721
25991
|
`);
|
|
25722
25992
|
return { exitCode: 1 };
|
|
25723
25993
|
}
|
|
25724
25994
|
let pkgJson;
|
|
25725
25995
|
try {
|
|
25726
|
-
pkgJson = JSON.parse(
|
|
25996
|
+
pkgJson = JSON.parse(readFileSync37(pkgJsonPath, "utf-8"));
|
|
25727
25997
|
} catch (err) {
|
|
25728
25998
|
process.stderr.write(`install: ${packageName} has malformed package.json: ${err instanceof Error ? err.message : String(err)}
|
|
25729
25999
|
`);
|
|
@@ -25843,7 +26113,7 @@ async function runAdaptersResign(_args) {
|
|
|
25843
26113
|
continue;
|
|
25844
26114
|
}
|
|
25845
26115
|
const packageDir = resolve27(projectRoot, "node_modules", ...name.split("/"));
|
|
25846
|
-
if (!
|
|
26116
|
+
if (!existsSync47(packageDir)) {
|
|
25847
26117
|
removed++;
|
|
25848
26118
|
warnings.push(`${name}@${entry.version}: not present in node_modules \u2014 REMOVED from sidecar`);
|
|
25849
26119
|
removeInstalledManifestEntry(name);
|
|
@@ -25930,10 +26200,10 @@ var init_adapters2 = __esm({
|
|
|
25930
26200
|
|
|
25931
26201
|
// src/preflight.ts
|
|
25932
26202
|
import Database4 from "better-sqlite3";
|
|
25933
|
-
import { existsSync as
|
|
26203
|
+
import { existsSync as existsSync48 } from "fs";
|
|
25934
26204
|
function assertCodegraphUsable(dbPath) {
|
|
25935
26205
|
const path = dbPath ?? getResolvedPaths().codegraphDbPath;
|
|
25936
|
-
if (!
|
|
26206
|
+
if (!existsSync48(path)) {
|
|
25937
26207
|
throw new CodegraphDbUnusableError(path, "missing");
|
|
25938
26208
|
}
|
|
25939
26209
|
let db = null;
|
|
@@ -26023,7 +26293,7 @@ var init_sql_table_names = __esm({
|
|
|
26023
26293
|
// src/db.ts
|
|
26024
26294
|
import Database5 from "better-sqlite3";
|
|
26025
26295
|
import { dirname as dirname22, join as join25 } from "path";
|
|
26026
|
-
import { existsSync as
|
|
26296
|
+
import { existsSync as existsSync49, mkdirSync as mkdirSync20, readdirSync as readdirSync18, statSync as statSync17 } from "fs";
|
|
26027
26297
|
function getCodeGraphDb() {
|
|
26028
26298
|
const dbPath = getResolvedPaths().codegraphDbPath;
|
|
26029
26299
|
assertCodegraphUsable(dbPath);
|
|
@@ -26034,7 +26304,7 @@ function getCodeGraphDb() {
|
|
|
26034
26304
|
function getDataDb() {
|
|
26035
26305
|
const dbPath = getResolvedPaths().dataDbPath;
|
|
26036
26306
|
const dir = dirname22(dbPath);
|
|
26037
|
-
if (!
|
|
26307
|
+
if (!existsSync49(dir)) {
|
|
26038
26308
|
mkdirSync20(dir, { recursive: true });
|
|
26039
26309
|
}
|
|
26040
26310
|
const db = new Database5(dbPath);
|
|
@@ -26411,7 +26681,7 @@ var init_rules = __esm({
|
|
|
26411
26681
|
});
|
|
26412
26682
|
|
|
26413
26683
|
// src/import-resolver.ts
|
|
26414
|
-
import { readFileSync as
|
|
26684
|
+
import { readFileSync as readFileSync38, existsSync as existsSync50, statSync as statSync18 } from "fs";
|
|
26415
26685
|
import { resolve as resolve29, dirname as dirname23, join as join26 } from "path";
|
|
26416
26686
|
function parseImports(source) {
|
|
26417
26687
|
const imports = [];
|
|
@@ -26472,19 +26742,19 @@ function resolveImportPath(specifier, fromFile) {
|
|
|
26472
26742
|
} else {
|
|
26473
26743
|
basePath = resolve29(dirname23(fromFile), specifier);
|
|
26474
26744
|
}
|
|
26475
|
-
if (
|
|
26745
|
+
if (existsSync50(basePath) && !isDirectory(basePath)) {
|
|
26476
26746
|
return toRelative(basePath);
|
|
26477
26747
|
}
|
|
26478
26748
|
const resolvedPaths = getResolvedPaths();
|
|
26479
26749
|
for (const ext of resolvedPaths.extensions) {
|
|
26480
26750
|
const withExt = basePath + ext;
|
|
26481
|
-
if (
|
|
26751
|
+
if (existsSync50(withExt)) {
|
|
26482
26752
|
return toRelative(withExt);
|
|
26483
26753
|
}
|
|
26484
26754
|
}
|
|
26485
26755
|
for (const indexFile of resolvedPaths.indexFiles) {
|
|
26486
26756
|
const indexPath = join26(basePath, indexFile);
|
|
26487
|
-
if (
|
|
26757
|
+
if (existsSync50(indexPath)) {
|
|
26488
26758
|
return toRelative(indexPath);
|
|
26489
26759
|
}
|
|
26490
26760
|
}
|
|
@@ -26521,10 +26791,10 @@ function buildImportIndex(dataDb, codegraphDb) {
|
|
|
26521
26791
|
let batch = [];
|
|
26522
26792
|
for (const file of files) {
|
|
26523
26793
|
const absPath = ensureWithinRoot(resolve29(projectRoot, file.path), projectRoot);
|
|
26524
|
-
if (!
|
|
26794
|
+
if (!existsSync50(absPath)) continue;
|
|
26525
26795
|
let source;
|
|
26526
26796
|
try {
|
|
26527
|
-
source =
|
|
26797
|
+
source = readFileSync38(absPath, "utf-8");
|
|
26528
26798
|
} catch {
|
|
26529
26799
|
continue;
|
|
26530
26800
|
}
|
|
@@ -26561,15 +26831,15 @@ var init_import_resolver = __esm({
|
|
|
26561
26831
|
});
|
|
26562
26832
|
|
|
26563
26833
|
// src/trpc-index.ts
|
|
26564
|
-
import { readFileSync as
|
|
26834
|
+
import { readFileSync as readFileSync39, existsSync as existsSync51, readdirSync as readdirSync19 } from "fs";
|
|
26565
26835
|
import { resolve as resolve30, join as join27 } from "path";
|
|
26566
26836
|
function parseRootRouter() {
|
|
26567
26837
|
const paths = getResolvedPaths();
|
|
26568
26838
|
const rootPath = paths.rootRouterPath;
|
|
26569
|
-
if (!
|
|
26839
|
+
if (!existsSync51(rootPath)) {
|
|
26570
26840
|
throw new Error(`Root router not found at ${rootPath}`);
|
|
26571
26841
|
}
|
|
26572
|
-
const source =
|
|
26842
|
+
const source = readFileSync39(rootPath, "utf-8");
|
|
26573
26843
|
const mappings = [];
|
|
26574
26844
|
const importMap = /* @__PURE__ */ new Map();
|
|
26575
26845
|
const importRegex = /import\s+\{[^}]*?(\w+Router)[^}]*\}\s+from\s+['"]\.\/routers\/([^'"]+)['"]/g;
|
|
@@ -26581,12 +26851,12 @@ function parseRootRouter() {
|
|
|
26581
26851
|
for (const ext of [".ts", ".tsx", ""]) {
|
|
26582
26852
|
const candidate = fullPath + ext;
|
|
26583
26853
|
const routersRelPath = getConfig().paths.routers ?? "src/server/api/routers";
|
|
26584
|
-
if (
|
|
26854
|
+
if (existsSync51(candidate)) {
|
|
26585
26855
|
filePath = routersRelPath + "/" + filePath + ext;
|
|
26586
26856
|
break;
|
|
26587
26857
|
}
|
|
26588
26858
|
const indexCandidate = join27(fullPath, "index.ts");
|
|
26589
|
-
if (
|
|
26859
|
+
if (existsSync51(indexCandidate)) {
|
|
26590
26860
|
filePath = routersRelPath + "/" + filePath + "/index.ts";
|
|
26591
26861
|
break;
|
|
26592
26862
|
}
|
|
@@ -26606,8 +26876,8 @@ function parseRootRouter() {
|
|
|
26606
26876
|
}
|
|
26607
26877
|
function extractProcedures(routerFilePath) {
|
|
26608
26878
|
const absPath = resolve30(getProjectRoot(), routerFilePath);
|
|
26609
|
-
if (!
|
|
26610
|
-
const source =
|
|
26879
|
+
if (!existsSync51(absPath)) return [];
|
|
26880
|
+
const source = readFileSync39(absPath, "utf-8");
|
|
26611
26881
|
const procedures = [];
|
|
26612
26882
|
const seen = /* @__PURE__ */ new Set();
|
|
26613
26883
|
const procRegex = /(\w+)\s*:\s*(protected|public)Procedure/g;
|
|
@@ -26636,7 +26906,7 @@ function findUICallSites(routerKey, procedureName) {
|
|
|
26636
26906
|
];
|
|
26637
26907
|
const searchPattern = `api.${routerKey}.${procedureName}`;
|
|
26638
26908
|
for (const dir of searchDirs) {
|
|
26639
|
-
if (!
|
|
26909
|
+
if (!existsSync51(dir)) continue;
|
|
26640
26910
|
searchDirectory(dir, searchPattern, callSites);
|
|
26641
26911
|
}
|
|
26642
26912
|
return callSites;
|
|
@@ -26650,7 +26920,7 @@ function searchDirectory(dir, pattern, results) {
|
|
|
26650
26920
|
searchDirectory(fullPath, pattern, results);
|
|
26651
26921
|
} else if (entry.name.endsWith(".ts") || entry.name.endsWith(".tsx")) {
|
|
26652
26922
|
try {
|
|
26653
|
-
const source =
|
|
26923
|
+
const source = readFileSync39(fullPath, "utf-8");
|
|
26654
26924
|
const lines = source.split("\n");
|
|
26655
26925
|
for (let i = 0; i < lines.length; i++) {
|
|
26656
26926
|
if (lines[i].includes(pattern)) {
|
|
@@ -26714,7 +26984,7 @@ var init_trpc_index = __esm({
|
|
|
26714
26984
|
});
|
|
26715
26985
|
|
|
26716
26986
|
// src/page-deps.ts
|
|
26717
|
-
import { readFileSync as
|
|
26987
|
+
import { readFileSync as readFileSync40, existsSync as existsSync52 } from "fs";
|
|
26718
26988
|
import { resolve as resolve31 } from "path";
|
|
26719
26989
|
function deriveRoute(pageFile) {
|
|
26720
26990
|
let route = pageFile.replace(/^src\/app/, "").replace(/\/page\.tsx?$/, "").replace(/\/page\.jsx?$/, "");
|
|
@@ -26754,9 +27024,9 @@ function findRouterCalls(files) {
|
|
|
26754
27024
|
const projectRoot = getProjectRoot();
|
|
26755
27025
|
for (const file of files) {
|
|
26756
27026
|
const absPath = ensureWithinRoot(resolve31(projectRoot, file), projectRoot);
|
|
26757
|
-
if (!
|
|
27027
|
+
if (!existsSync52(absPath)) continue;
|
|
26758
27028
|
try {
|
|
26759
|
-
const source =
|
|
27029
|
+
const source = readFileSync40(absPath, "utf-8");
|
|
26760
27030
|
const apiCallRegex = /api\.(\w+)\.\w+/g;
|
|
26761
27031
|
let match;
|
|
26762
27032
|
while ((match = apiCallRegex.exec(source)) !== null) {
|
|
@@ -26775,9 +27045,9 @@ function findTablesFromRouters(routerNames, dataDb) {
|
|
|
26775
27045
|
).all(routerName);
|
|
26776
27046
|
for (const proc of procs) {
|
|
26777
27047
|
const absPath = ensureWithinRoot(resolve31(getProjectRoot(), proc.router_file), getProjectRoot());
|
|
26778
|
-
if (!
|
|
27048
|
+
if (!existsSync52(absPath)) continue;
|
|
26779
27049
|
try {
|
|
26780
|
-
const source =
|
|
27050
|
+
const source = readFileSync40(absPath, "utf-8");
|
|
26781
27051
|
const dbPattern = getConfig().dbAccessPattern ?? "ctx.db.{table}";
|
|
26782
27052
|
const regexStr = dbPattern.replace(/[.*+?^${}()|[\]\\]/g, "\\$&").replace("\\{table\\}", "(\\w+)");
|
|
26783
27053
|
const tableRegex = new RegExp(regexStr + "\\.", "g");
|
|
@@ -27049,14 +27319,14 @@ var init_domains = __esm({
|
|
|
27049
27319
|
});
|
|
27050
27320
|
|
|
27051
27321
|
// src/schema-mapper.ts
|
|
27052
|
-
import { readFileSync as
|
|
27322
|
+
import { readFileSync as readFileSync41, existsSync as existsSync53, readdirSync as readdirSync20 } from "fs";
|
|
27053
27323
|
import { join as join28 } from "path";
|
|
27054
27324
|
function parsePrismaSchema() {
|
|
27055
27325
|
const schemaPath = getResolvedPaths().prismaSchemaPath;
|
|
27056
|
-
if (!
|
|
27326
|
+
if (!existsSync53(schemaPath)) {
|
|
27057
27327
|
throw new Error(`Prisma schema not found at ${schemaPath}`);
|
|
27058
27328
|
}
|
|
27059
|
-
const source =
|
|
27329
|
+
const source = readFileSync41(schemaPath, "utf-8");
|
|
27060
27330
|
const models = [];
|
|
27061
27331
|
const sourceLines = source.split("\n");
|
|
27062
27332
|
let i = 0;
|
|
@@ -27114,7 +27384,7 @@ function toSnakeCase(str) {
|
|
|
27114
27384
|
function findColumnUsageInRouters(tableName) {
|
|
27115
27385
|
const usage2 = /* @__PURE__ */ new Map();
|
|
27116
27386
|
const routersDir = getResolvedPaths().routersDir;
|
|
27117
|
-
if (!
|
|
27387
|
+
if (!existsSync53(routersDir)) return usage2;
|
|
27118
27388
|
scanDirectory(routersDir, tableName, usage2);
|
|
27119
27389
|
return usage2;
|
|
27120
27390
|
}
|
|
@@ -27131,7 +27401,7 @@ function scanDirectory(dir, tableName, usage2) {
|
|
|
27131
27401
|
}
|
|
27132
27402
|
function scanFile(absPath, tableName, usage2) {
|
|
27133
27403
|
try {
|
|
27134
|
-
const source =
|
|
27404
|
+
const source = readFileSync41(absPath, "utf-8");
|
|
27135
27405
|
if (!source.includes(tableName)) return;
|
|
27136
27406
|
const relPath = absPath.slice(getProjectRoot().length + 1);
|
|
27137
27407
|
const lines = source.split("\n");
|
|
@@ -27176,7 +27446,7 @@ function detectMismatches(models) {
|
|
|
27176
27446
|
}
|
|
27177
27447
|
function findFilesUsingColumn(dir, column, tableName) {
|
|
27178
27448
|
const result = [];
|
|
27179
|
-
if (!
|
|
27449
|
+
if (!existsSync53(dir)) return result;
|
|
27180
27450
|
const entries = readdirSync20(dir, { withFileTypes: true });
|
|
27181
27451
|
for (const entry of entries) {
|
|
27182
27452
|
const fullPath = join28(dir, entry.name);
|
|
@@ -27184,7 +27454,7 @@ function findFilesUsingColumn(dir, column, tableName) {
|
|
|
27184
27454
|
result.push(...findFilesUsingColumn(fullPath, column, tableName));
|
|
27185
27455
|
} else if (entry.name.endsWith(".ts")) {
|
|
27186
27456
|
try {
|
|
27187
|
-
const source =
|
|
27457
|
+
const source = readFileSync41(fullPath, "utf-8");
|
|
27188
27458
|
if (source.includes(tableName) && source.includes(column)) {
|
|
27189
27459
|
result.push(fullPath.slice(getProjectRoot().length + 1));
|
|
27190
27460
|
}
|
|
@@ -27329,7 +27599,7 @@ var init_import_parser = __esm({
|
|
|
27329
27599
|
});
|
|
27330
27600
|
|
|
27331
27601
|
// src/python/import-resolver.ts
|
|
27332
|
-
import { readFileSync as
|
|
27602
|
+
import { readFileSync as readFileSync42, existsSync as existsSync54, readdirSync as readdirSync21 } from "fs";
|
|
27333
27603
|
import { resolve as resolve33, join as join29, relative as relative8, dirname as dirname24 } from "path";
|
|
27334
27604
|
function resolvePythonModulePath(module, fromFile, pythonRoot, level) {
|
|
27335
27605
|
const projectRoot = getProjectRoot();
|
|
@@ -27350,13 +27620,13 @@ function resolvePythonModulePath(module, fromFile, pythonRoot, level) {
|
|
|
27350
27620
|
return tryResolvePythonPath(candidate, projectRoot);
|
|
27351
27621
|
}
|
|
27352
27622
|
function tryResolvePythonPath(basePath, projectRoot) {
|
|
27353
|
-
if (
|
|
27623
|
+
if (existsSync54(basePath + ".py")) {
|
|
27354
27624
|
return relative8(projectRoot, basePath + ".py");
|
|
27355
27625
|
}
|
|
27356
|
-
if (
|
|
27626
|
+
if (existsSync54(join29(basePath, "__init__.py"))) {
|
|
27357
27627
|
return relative8(projectRoot, join29(basePath, "__init__.py"));
|
|
27358
27628
|
}
|
|
27359
|
-
if (basePath.endsWith(".py") &&
|
|
27629
|
+
if (basePath.endsWith(".py") && existsSync54(basePath)) {
|
|
27360
27630
|
return relative8(projectRoot, basePath);
|
|
27361
27631
|
}
|
|
27362
27632
|
return null;
|
|
@@ -27396,7 +27666,7 @@ function buildPythonImportIndex(dataDb, pythonRoot, excludeDirs = ["__pycache__"
|
|
|
27396
27666
|
const relFile = relative8(projectRoot, absFile);
|
|
27397
27667
|
let source;
|
|
27398
27668
|
try {
|
|
27399
|
-
source =
|
|
27669
|
+
source = readFileSync42(absFile, "utf-8");
|
|
27400
27670
|
} catch {
|
|
27401
27671
|
continue;
|
|
27402
27672
|
}
|
|
@@ -27663,7 +27933,7 @@ var init_route_parser = __esm({
|
|
|
27663
27933
|
});
|
|
27664
27934
|
|
|
27665
27935
|
// src/python/route-indexer.ts
|
|
27666
|
-
import { readFileSync as
|
|
27936
|
+
import { readFileSync as readFileSync43, readdirSync as readdirSync22 } from "fs";
|
|
27667
27937
|
import { join as join30, relative as relative9 } from "path";
|
|
27668
27938
|
function walkPyFiles(dir, excludeDirs) {
|
|
27669
27939
|
const files = [];
|
|
@@ -27696,7 +27966,7 @@ function buildPythonRouteIndex(dataDb, pythonRoot, excludeDirs = ["__pycache__",
|
|
|
27696
27966
|
const relFile = relative9(projectRoot, absFile);
|
|
27697
27967
|
let source;
|
|
27698
27968
|
try {
|
|
27699
|
-
source =
|
|
27969
|
+
source = readFileSync43(absFile, "utf-8");
|
|
27700
27970
|
} catch {
|
|
27701
27971
|
continue;
|
|
27702
27972
|
}
|
|
@@ -27908,7 +28178,7 @@ var init_model_parser = __esm({
|
|
|
27908
28178
|
});
|
|
27909
28179
|
|
|
27910
28180
|
// src/python/model-indexer.ts
|
|
27911
|
-
import { readFileSync as
|
|
28181
|
+
import { readFileSync as readFileSync44, readdirSync as readdirSync23 } from "fs";
|
|
27912
28182
|
import { join as join31, relative as relative10 } from "path";
|
|
27913
28183
|
function walkPyFiles2(dir, excludeDirs) {
|
|
27914
28184
|
const files = [];
|
|
@@ -27944,7 +28214,7 @@ function buildPythonModelIndex(dataDb, pythonRoot, excludeDirs = ["__pycache__",
|
|
|
27944
28214
|
const relFile = relative10(projectRoot, absFile);
|
|
27945
28215
|
let source;
|
|
27946
28216
|
try {
|
|
27947
|
-
source =
|
|
28217
|
+
source = readFileSync44(absFile, "utf-8");
|
|
27948
28218
|
} catch {
|
|
27949
28219
|
continue;
|
|
27950
28220
|
}
|
|
@@ -28205,7 +28475,7 @@ var init_migration_parser = __esm({
|
|
|
28205
28475
|
});
|
|
28206
28476
|
|
|
28207
28477
|
// src/python/migration-indexer.ts
|
|
28208
|
-
import { readFileSync as
|
|
28478
|
+
import { readFileSync as readFileSync45, readdirSync as readdirSync24 } from "fs";
|
|
28209
28479
|
import { join as join32, relative as relative11 } from "path";
|
|
28210
28480
|
function buildPythonMigrationIndex(dataDb, alembicDir) {
|
|
28211
28481
|
const projectRoot = getProjectRoot();
|
|
@@ -28231,7 +28501,7 @@ function buildPythonMigrationIndex(dataDb, alembicDir) {
|
|
|
28231
28501
|
for (const absFile of files) {
|
|
28232
28502
|
let source;
|
|
28233
28503
|
try {
|
|
28234
|
-
source =
|
|
28504
|
+
source = readFileSync45(absFile, "utf-8");
|
|
28235
28505
|
} catch {
|
|
28236
28506
|
continue;
|
|
28237
28507
|
}
|
|
@@ -28266,7 +28536,7 @@ var init_migration_indexer = __esm({
|
|
|
28266
28536
|
});
|
|
28267
28537
|
|
|
28268
28538
|
// src/python/coupling-detector.ts
|
|
28269
|
-
import { readFileSync as
|
|
28539
|
+
import { readFileSync as readFileSync46, readdirSync as readdirSync25 } from "fs";
|
|
28270
28540
|
import { join as join33, relative as relative12 } from "path";
|
|
28271
28541
|
function buildPythonCouplingIndex(dataDb) {
|
|
28272
28542
|
const projectRoot = getProjectRoot();
|
|
@@ -28303,7 +28573,7 @@ function buildPythonCouplingIndex(dataDb) {
|
|
|
28303
28573
|
const relFile = relative12(projectRoot, absFile);
|
|
28304
28574
|
let source;
|
|
28305
28575
|
try {
|
|
28306
|
-
source =
|
|
28576
|
+
source = readFileSync46(absFile, "utf-8");
|
|
28307
28577
|
} catch {
|
|
28308
28578
|
continue;
|
|
28309
28579
|
}
|
|
@@ -28709,7 +28979,7 @@ var init_memory_tools = __esm({
|
|
|
28709
28979
|
});
|
|
28710
28980
|
|
|
28711
28981
|
// src/docs-tools.ts
|
|
28712
|
-
import { readFileSync as
|
|
28982
|
+
import { readFileSync as readFileSync47, existsSync as existsSync55 } from "fs";
|
|
28713
28983
|
import { resolve as resolve34, basename as basename9 } from "path";
|
|
28714
28984
|
function p4(baseName) {
|
|
28715
28985
|
return `${getConfig().toolPrefix}_${baseName}`;
|
|
@@ -28765,10 +29035,10 @@ function handleDocsToolCall(name, args2) {
|
|
|
28765
29035
|
}
|
|
28766
29036
|
function loadDocsMap() {
|
|
28767
29037
|
const mapPath = getResolvedPaths().docsMapPath;
|
|
28768
|
-
if (!
|
|
29038
|
+
if (!existsSync55(mapPath)) {
|
|
28769
29039
|
throw new Error(`docs-map.json not found at ${mapPath}`);
|
|
28770
29040
|
}
|
|
28771
|
-
return JSON.parse(
|
|
29041
|
+
return JSON.parse(readFileSync47(mapPath, "utf-8"));
|
|
28772
29042
|
}
|
|
28773
29043
|
function matchesPattern(filePath, pattern) {
|
|
28774
29044
|
const regexStr = pattern.replace(/\./g, "\\.").replace(/\*\*/g, "{{GLOBSTAR}}").replace(/\*/g, "[^/]*").replace(/\{\{GLOBSTAR\}\}/g, ".*");
|
|
@@ -28839,12 +29109,12 @@ function extractFrontmatter(content) {
|
|
|
28839
29109
|
function extractProcedureNames(routerPath) {
|
|
28840
29110
|
const root = getProjectRoot();
|
|
28841
29111
|
const absPath = ensureWithinRoot(resolve34(getResolvedPaths().srcDir, "..", routerPath), root);
|
|
28842
|
-
if (!
|
|
29112
|
+
if (!existsSync55(absPath)) {
|
|
28843
29113
|
const altPath = ensureWithinRoot(resolve34(getResolvedPaths().srcDir, "../server/api/routers", basename9(routerPath)), root);
|
|
28844
|
-
if (!
|
|
28845
|
-
return extractProcedureNamesFromContent(
|
|
29114
|
+
if (!existsSync55(altPath)) return [];
|
|
29115
|
+
return extractProcedureNamesFromContent(readFileSync47(altPath, "utf-8"));
|
|
28846
29116
|
}
|
|
28847
|
-
return extractProcedureNamesFromContent(
|
|
29117
|
+
return extractProcedureNamesFromContent(readFileSync47(absPath, "utf-8"));
|
|
28848
29118
|
}
|
|
28849
29119
|
function extractProcedureNamesFromContent(content) {
|
|
28850
29120
|
const procRegex = /\.(?:query|mutation)\s*\(/g;
|
|
@@ -28885,7 +29155,7 @@ function handleDocsAudit(args2) {
|
|
|
28885
29155
|
const mapping = docsMap.mappings.find((m3) => m3.id === mappingId);
|
|
28886
29156
|
if (!mapping) continue;
|
|
28887
29157
|
const helpPagePath = ensureWithinRoot(resolve34(getResolvedPaths().helpSitePath, mapping.helpPage), getProjectRoot());
|
|
28888
|
-
if (!
|
|
29158
|
+
if (!existsSync55(helpPagePath)) {
|
|
28889
29159
|
results.push({
|
|
28890
29160
|
helpPage: mapping.helpPage,
|
|
28891
29161
|
mappingId,
|
|
@@ -28897,7 +29167,7 @@ function handleDocsAudit(args2) {
|
|
|
28897
29167
|
});
|
|
28898
29168
|
continue;
|
|
28899
29169
|
}
|
|
28900
|
-
const content =
|
|
29170
|
+
const content = readFileSync47(helpPagePath, "utf-8");
|
|
28901
29171
|
const sections = extractSections(content);
|
|
28902
29172
|
const frontmatter = extractFrontmatter(content);
|
|
28903
29173
|
const staleReasons = [];
|
|
@@ -28938,8 +29208,8 @@ function handleDocsAudit(args2) {
|
|
|
28938
29208
|
for (const [guideName, parentId] of Object.entries(docsMap.userGuideInheritance.examples)) {
|
|
28939
29209
|
if (parentId === mappingId) {
|
|
28940
29210
|
const guidePath = ensureWithinRoot(resolve34(getResolvedPaths().helpSitePath, `pages/user-guides/${guideName}/index.mdx`), getProjectRoot());
|
|
28941
|
-
if (
|
|
28942
|
-
const guideContent =
|
|
29211
|
+
if (existsSync55(guidePath)) {
|
|
29212
|
+
const guideContent = readFileSync47(guidePath, "utf-8");
|
|
28943
29213
|
const guideFrontmatter = extractFrontmatter(guideContent);
|
|
28944
29214
|
if (!guideFrontmatter?.lastVerified || status === "STALE") {
|
|
28945
29215
|
results.push({
|
|
@@ -28973,13 +29243,13 @@ function handleDocsCoverage(args2) {
|
|
|
28973
29243
|
const mappings = filterDomain ? docsMap.mappings.filter((m3) => m3.id === filterDomain) : docsMap.mappings;
|
|
28974
29244
|
for (const mapping of mappings) {
|
|
28975
29245
|
const helpPagePath = ensureWithinRoot(resolve34(getResolvedPaths().helpSitePath, mapping.helpPage), getProjectRoot());
|
|
28976
|
-
const exists =
|
|
29246
|
+
const exists = existsSync55(helpPagePath);
|
|
28977
29247
|
let hasContent = false;
|
|
28978
29248
|
let lineCount = 0;
|
|
28979
29249
|
let lastVerified = null;
|
|
28980
29250
|
let status = null;
|
|
28981
29251
|
if (exists) {
|
|
28982
|
-
const content =
|
|
29252
|
+
const content = readFileSync47(helpPagePath, "utf-8");
|
|
28983
29253
|
lineCount = content.split("\n").length;
|
|
28984
29254
|
hasContent = lineCount > 10;
|
|
28985
29255
|
const frontmatter = extractFrontmatter(content);
|
|
@@ -29320,7 +29590,7 @@ var init_observability_tools = __esm({
|
|
|
29320
29590
|
});
|
|
29321
29591
|
|
|
29322
29592
|
// src/sentinel-db.ts
|
|
29323
|
-
import { existsSync as
|
|
29593
|
+
import { existsSync as existsSync56 } from "fs";
|
|
29324
29594
|
import { resolve as resolve35 } from "path";
|
|
29325
29595
|
function parsePortalScope(raw) {
|
|
29326
29596
|
if (!raw) return [];
|
|
@@ -29558,22 +29828,22 @@ function validateFeatures(db, domainFilter) {
|
|
|
29558
29828
|
const missingPages = [];
|
|
29559
29829
|
for (const comp of components) {
|
|
29560
29830
|
const absPath = resolve35(PROJECT_ROOT, comp.component_file);
|
|
29561
|
-
if (!
|
|
29831
|
+
if (!existsSync56(absPath)) {
|
|
29562
29832
|
missingComponents.push(comp.component_file);
|
|
29563
29833
|
}
|
|
29564
29834
|
}
|
|
29565
29835
|
for (const proc of procedures) {
|
|
29566
29836
|
const routerPath = resolve35(PROJECT_ROOT, `src/server/api/routers/${proc.router_name}.ts`);
|
|
29567
|
-
if (!
|
|
29837
|
+
if (!existsSync56(routerPath)) {
|
|
29568
29838
|
missingProcedures.push({ router: proc.router_name, procedure: proc.procedure_name });
|
|
29569
29839
|
}
|
|
29570
29840
|
}
|
|
29571
29841
|
for (const page of pages) {
|
|
29572
29842
|
const routeToPath = page.page_route.replace(/^\/(portal-[^/]+\/)?/, "src/app/").replace(/\/$/, "") + "/page.tsx";
|
|
29573
29843
|
const absPath = resolve35(PROJECT_ROOT, routeToPath);
|
|
29574
|
-
if (page.page_route.startsWith("/") && !
|
|
29844
|
+
if (page.page_route.startsWith("/") && !existsSync56(absPath)) {
|
|
29575
29845
|
const altPath = resolve35(PROJECT_ROOT, `src/app${page.page_route}/page.tsx`);
|
|
29576
|
-
if (!
|
|
29846
|
+
if (!existsSync56(altPath)) {
|
|
29577
29847
|
missingPages.push(page.page_route);
|
|
29578
29848
|
}
|
|
29579
29849
|
}
|
|
@@ -30099,7 +30369,7 @@ var init_sentinel_tools = __esm({
|
|
|
30099
30369
|
});
|
|
30100
30370
|
|
|
30101
30371
|
// src/sentinel-scanner.ts
|
|
30102
|
-
import { readFileSync as
|
|
30372
|
+
import { readFileSync as readFileSync48, existsSync as existsSync57, readdirSync as readdirSync26, statSync as statSync19 } from "fs";
|
|
30103
30373
|
import { resolve as resolve36, join as join34, basename as basename10, dirname as dirname25, relative as relative13 } from "path";
|
|
30104
30374
|
function inferDomain(filePath) {
|
|
30105
30375
|
const domains = getConfig().domains;
|
|
@@ -30232,7 +30502,7 @@ function scanComponentExports(dataDb) {
|
|
|
30232
30502
|
const componentsBase = config.paths.components ?? config.paths.source + "/components";
|
|
30233
30503
|
const componentDirs = [];
|
|
30234
30504
|
const basePath = resolve36(projectRoot, componentsBase);
|
|
30235
|
-
if (
|
|
30505
|
+
if (existsSync57(basePath)) {
|
|
30236
30506
|
try {
|
|
30237
30507
|
const entries = readdirSync26(basePath, { withFileTypes: true });
|
|
30238
30508
|
for (const entry of entries) {
|
|
@@ -30245,11 +30515,11 @@ function scanComponentExports(dataDb) {
|
|
|
30245
30515
|
}
|
|
30246
30516
|
for (const dir of componentDirs) {
|
|
30247
30517
|
const absDir = resolve36(projectRoot, dir);
|
|
30248
|
-
if (!
|
|
30518
|
+
if (!existsSync57(absDir)) continue;
|
|
30249
30519
|
const files = walkDir2(absDir).filter((f2) => f2.endsWith(".tsx") || f2.endsWith(".ts"));
|
|
30250
30520
|
for (const file of files) {
|
|
30251
30521
|
const relPath = relative13(projectRoot, file);
|
|
30252
|
-
const source =
|
|
30522
|
+
const source = readFileSync48(file, "utf-8");
|
|
30253
30523
|
const annotations = parseFeatureAnnotations(source);
|
|
30254
30524
|
if (annotations.length > 0) {
|
|
30255
30525
|
for (const ann of annotations) {
|
|
@@ -31010,7 +31280,7 @@ var init_prompt_analyzer = __esm({
|
|
|
31010
31280
|
});
|
|
31011
31281
|
|
|
31012
31282
|
// src/validation-engine.ts
|
|
31013
|
-
import { existsSync as
|
|
31283
|
+
import { existsSync as existsSync58, readFileSync as readFileSync49 } from "fs";
|
|
31014
31284
|
function p10(baseName) {
|
|
31015
31285
|
return `${getConfig().toolPrefix}_${baseName}`;
|
|
31016
31286
|
}
|
|
@@ -31041,7 +31311,7 @@ function validateFile(filePath, projectRoot) {
|
|
|
31041
31311
|
});
|
|
31042
31312
|
return checks;
|
|
31043
31313
|
}
|
|
31044
|
-
if (!
|
|
31314
|
+
if (!existsSync58(absPath)) {
|
|
31045
31315
|
checks.push({
|
|
31046
31316
|
name: "file_exists",
|
|
31047
31317
|
severity: "error",
|
|
@@ -31050,7 +31320,7 @@ function validateFile(filePath, projectRoot) {
|
|
|
31050
31320
|
});
|
|
31051
31321
|
return checks;
|
|
31052
31322
|
}
|
|
31053
|
-
const source =
|
|
31323
|
+
const source = readFileSync49(absPath, "utf-8");
|
|
31054
31324
|
const lines = source.split("\n");
|
|
31055
31325
|
if (activeChecks.rule_compliance !== false) {
|
|
31056
31326
|
for (const ruleSet of config.rules) {
|
|
@@ -31509,7 +31779,7 @@ var init_adr_generator = __esm({
|
|
|
31509
31779
|
});
|
|
31510
31780
|
|
|
31511
31781
|
// src/security-scorer.ts
|
|
31512
|
-
import { existsSync as
|
|
31782
|
+
import { existsSync as existsSync59, readFileSync as readFileSync50 } from "fs";
|
|
31513
31783
|
function p12(baseName) {
|
|
31514
31784
|
return `${getConfig().toolPrefix}_${baseName}`;
|
|
31515
31785
|
}
|
|
@@ -31533,12 +31803,12 @@ function scoreFileSecurity(filePath, projectRoot) {
|
|
|
31533
31803
|
}]
|
|
31534
31804
|
};
|
|
31535
31805
|
}
|
|
31536
|
-
if (!
|
|
31806
|
+
if (!existsSync59(absPath)) {
|
|
31537
31807
|
return { riskScore: 0, findings: [] };
|
|
31538
31808
|
}
|
|
31539
31809
|
let source;
|
|
31540
31810
|
try {
|
|
31541
|
-
source =
|
|
31811
|
+
source = readFileSync50(absPath, "utf-8");
|
|
31542
31812
|
} catch {
|
|
31543
31813
|
return { riskScore: 0, findings: [] };
|
|
31544
31814
|
}
|
|
@@ -31828,7 +32098,7 @@ var init_security_scorer = __esm({
|
|
|
31828
32098
|
});
|
|
31829
32099
|
|
|
31830
32100
|
// src/dependency-scorer.ts
|
|
31831
|
-
import { existsSync as
|
|
32101
|
+
import { existsSync as existsSync60, readFileSync as readFileSync51 } from "fs";
|
|
31832
32102
|
import { resolve as resolve37 } from "path";
|
|
31833
32103
|
function p13(baseName) {
|
|
31834
32104
|
return `${getConfig().toolPrefix}_${baseName}`;
|
|
@@ -31862,9 +32132,9 @@ function calculateDepRisk(factors) {
|
|
|
31862
32132
|
}
|
|
31863
32133
|
function getInstalledPackages(projectRoot) {
|
|
31864
32134
|
const pkgPath = resolve37(projectRoot, "package.json");
|
|
31865
|
-
if (!
|
|
32135
|
+
if (!existsSync60(pkgPath)) return /* @__PURE__ */ new Map();
|
|
31866
32136
|
try {
|
|
31867
|
-
const pkg = JSON.parse(
|
|
32137
|
+
const pkg = JSON.parse(readFileSync51(pkgPath, "utf-8"));
|
|
31868
32138
|
const packages = /* @__PURE__ */ new Map();
|
|
31869
32139
|
for (const [name, version] of Object.entries(pkg.dependencies ?? {})) {
|
|
31870
32140
|
packages.set(name, version);
|
|
@@ -32470,7 +32740,7 @@ var init_regression_detector = __esm({
|
|
|
32470
32740
|
|
|
32471
32741
|
// src/knowledge-indexer.ts
|
|
32472
32742
|
import { createHash as createHash14 } from "crypto";
|
|
32473
|
-
import { readFileSync as
|
|
32743
|
+
import { readFileSync as readFileSync52, readdirSync as readdirSync27, statSync as statSync20, existsSync as existsSync61 } from "fs";
|
|
32474
32744
|
import { resolve as resolve38, relative as relative14, basename as basename11, extname as extname2 } from "path";
|
|
32475
32745
|
function getKnowledgePaths() {
|
|
32476
32746
|
const resolved = getResolvedPaths();
|
|
@@ -32778,11 +33048,11 @@ function indexAllKnowledge(db) {
|
|
|
32778
33048
|
files.push(...memFiles);
|
|
32779
33049
|
} catch {
|
|
32780
33050
|
}
|
|
32781
|
-
if (
|
|
33051
|
+
if (existsSync61(paths.plansDir)) {
|
|
32782
33052
|
const planFiles = discoverMarkdownFiles(paths.plansDir);
|
|
32783
33053
|
files.push(...planFiles);
|
|
32784
33054
|
}
|
|
32785
|
-
if (
|
|
33055
|
+
if (existsSync61(paths.docsDir)) {
|
|
32786
33056
|
const excludePatterns = getConfig().conventions?.excludePatterns ?? ["/ARCHIVE/", "/SESSION-HISTORY/"];
|
|
32787
33057
|
const docsFiles = discoverMarkdownFiles(paths.docsDir).filter((f2) => !f2.includes("/plans/") && !excludePatterns.some((p19) => f2.includes(p19)));
|
|
32788
33058
|
files.push(...docsFiles);
|
|
@@ -32825,8 +33095,8 @@ function indexAllKnowledge(db) {
|
|
|
32825
33095
|
} catch {
|
|
32826
33096
|
}
|
|
32827
33097
|
for (const filePath of files) {
|
|
32828
|
-
if (!
|
|
32829
|
-
const content =
|
|
33098
|
+
if (!existsSync61(filePath)) continue;
|
|
33099
|
+
const content = readFileSync52(filePath, "utf-8");
|
|
32830
33100
|
const hash = hashContent2(content);
|
|
32831
33101
|
const relPath = filePath.startsWith(paths.claudeDir) ? relative14(paths.claudeDir, filePath) : filePath.startsWith(paths.plansDir) ? "plans/" + relative14(paths.plansDir, filePath) : filePath.startsWith(paths.docsDir) ? "docs/" + relative14(paths.docsDir, filePath) : filePath.startsWith(paths.memoryDir) ? `memory/${relative14(paths.memoryDir, filePath)}` : basename11(filePath);
|
|
32832
33102
|
const category = categorizeFile(filePath);
|
|
@@ -32961,10 +33231,10 @@ function isKnowledgeStale(db) {
|
|
|
32961
33231
|
files.push(...discoverMarkdownFiles(paths.memoryDir));
|
|
32962
33232
|
} catch {
|
|
32963
33233
|
}
|
|
32964
|
-
if (
|
|
33234
|
+
if (existsSync61(paths.plansDir)) {
|
|
32965
33235
|
files.push(...discoverMarkdownFiles(paths.plansDir));
|
|
32966
33236
|
}
|
|
32967
|
-
if (
|
|
33237
|
+
if (existsSync61(paths.docsDir)) {
|
|
32968
33238
|
const excludePatterns = getConfig().conventions?.excludePatterns ?? ["/ARCHIVE/", "/SESSION-HISTORY/"];
|
|
32969
33239
|
const docsFiles = discoverMarkdownFiles(paths.docsDir).filter((f2) => !f2.includes("/plans/") && !excludePatterns.some((p19) => f2.includes(p19)));
|
|
32970
33240
|
files.push(...docsFiles);
|
|
@@ -32993,7 +33263,7 @@ var init_knowledge_indexer = __esm({
|
|
|
32993
33263
|
});
|
|
32994
33264
|
|
|
32995
33265
|
// src/knowledge-tools.ts
|
|
32996
|
-
import { readFileSync as
|
|
33266
|
+
import { readFileSync as readFileSync53, writeFileSync as writeFileSync14, appendFileSync as appendFileSync4, readdirSync as readdirSync28 } from "fs";
|
|
32997
33267
|
import { resolve as resolve39, basename as basename12 } from "path";
|
|
32998
33268
|
function p16(baseName) {
|
|
32999
33269
|
return `${getConfig().toolPrefix}_${baseName}`;
|
|
@@ -33746,7 +34016,7 @@ function handleCorrect(db, args2) {
|
|
|
33746
34016
|
});
|
|
33747
34017
|
let existing = "";
|
|
33748
34018
|
try {
|
|
33749
|
-
existing =
|
|
34019
|
+
existing = readFileSync53(correctionsPath, "utf-8");
|
|
33750
34020
|
} catch {
|
|
33751
34021
|
}
|
|
33752
34022
|
const archiveIdx = existing.indexOf("## Archived");
|
|
@@ -34702,7 +34972,7 @@ var init_framework_supports = __esm({
|
|
|
34702
34972
|
});
|
|
34703
34973
|
|
|
34704
34974
|
// src/tools.ts
|
|
34705
|
-
import { readFileSync as
|
|
34975
|
+
import { readFileSync as readFileSync54, existsSync as existsSync63 } from "fs";
|
|
34706
34976
|
import { resolve as resolve40, basename as basename13 } from "path";
|
|
34707
34977
|
function prefix2() {
|
|
34708
34978
|
return getConfig().toolPrefix;
|
|
@@ -35122,8 +35392,8 @@ function handleContext(file, dataDb, codegraphDb) {
|
|
|
35122
35392
|
const resolvedPaths = getResolvedPaths();
|
|
35123
35393
|
const root = getProjectRoot();
|
|
35124
35394
|
const absFilePath = ensureWithinRoot(resolve40(resolvedPaths.srcDir, "..", file), root);
|
|
35125
|
-
if (
|
|
35126
|
-
const fileContent =
|
|
35395
|
+
if (existsSync63(absFilePath)) {
|
|
35396
|
+
const fileContent = readFileSync54(absFilePath, "utf-8").slice(0, 3e3);
|
|
35127
35397
|
const keywords = [];
|
|
35128
35398
|
if (fileContent.includes("ctx.db")) keywords.push("database", "schema");
|
|
35129
35399
|
if (fileContent.includes("BigInt") || fileContent.includes("Decimal")) keywords.push("BigInt", "serialization");
|
|
@@ -35561,10 +35831,10 @@ function handleSchema(args2) {
|
|
|
35561
35831
|
lines.push("");
|
|
35562
35832
|
const projectRoot = getProjectRoot();
|
|
35563
35833
|
const absPath = ensureWithinRoot(resolve40(projectRoot, file), projectRoot);
|
|
35564
|
-
if (!
|
|
35834
|
+
if (!existsSync63(absPath)) {
|
|
35565
35835
|
return text17(`File not found: ${file}`);
|
|
35566
35836
|
}
|
|
35567
|
-
const source =
|
|
35837
|
+
const source = readFileSync54(absPath, "utf-8");
|
|
35568
35838
|
const config = getConfig();
|
|
35569
35839
|
const dbPattern = config.dbAccessPattern ?? "ctx.db.{table}";
|
|
35570
35840
|
const regexStr = dbPattern.replace(/[.*+?^${}()|[\]\\]/g, "\\$&").replace("\\{table\\}", "(\\w+)");
|
|
@@ -35967,9 +36237,36 @@ var init_server_dispatch = __esm({
|
|
|
35967
36237
|
}
|
|
35968
36238
|
});
|
|
35969
36239
|
|
|
36240
|
+
// src/startup-health.ts
|
|
36241
|
+
function assertMemoryEngineHealthy(open) {
|
|
36242
|
+
let db;
|
|
36243
|
+
try {
|
|
36244
|
+
db = open();
|
|
36245
|
+
} catch (error) {
|
|
36246
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
36247
|
+
throw new FatalStartupError(
|
|
36248
|
+
`the memory database engine could not be opened: ${msg}
|
|
36249
|
+
This usually means the native SQLite binding was built for a different Node.js ABI (e.g. after a Node major upgrade). Remedy: rebuild the native binding for this Node version \u2014 'npm rebuild better-sqlite3' inside the @massu/core install, or reinstall @massu/core. Refusing to start in a "connected but broken" state where every database tool would fail silently.`
|
|
36250
|
+
);
|
|
36251
|
+
}
|
|
36252
|
+
db.close();
|
|
36253
|
+
}
|
|
36254
|
+
var FatalStartupError;
|
|
36255
|
+
var init_startup_health = __esm({
|
|
36256
|
+
"src/startup-health.ts"() {
|
|
36257
|
+
"use strict";
|
|
36258
|
+
FatalStartupError = class extends Error {
|
|
36259
|
+
constructor(message) {
|
|
36260
|
+
super(message);
|
|
36261
|
+
this.name = "FatalStartupError";
|
|
36262
|
+
}
|
|
36263
|
+
};
|
|
36264
|
+
}
|
|
36265
|
+
});
|
|
36266
|
+
|
|
35970
36267
|
// src/server.ts
|
|
35971
36268
|
var server_exports = {};
|
|
35972
|
-
import { readFileSync as
|
|
36269
|
+
import { readFileSync as readFileSync55 } from "fs";
|
|
35973
36270
|
import { resolve as resolve41, dirname as dirname26 } from "path";
|
|
35974
36271
|
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
35975
36272
|
function pruneMemoryOnStartup() {
|
|
@@ -36012,16 +36309,27 @@ var init_server = __esm({
|
|
|
36012
36309
|
init_consolidation_config();
|
|
36013
36310
|
init_license();
|
|
36014
36311
|
init_server_dispatch();
|
|
36312
|
+
init_startup_health();
|
|
36015
36313
|
__dirname5 = dirname26(fileURLToPath6(import.meta.url));
|
|
36016
36314
|
PKG_VERSION = (() => {
|
|
36017
36315
|
try {
|
|
36018
|
-
const pkg = JSON.parse(
|
|
36316
|
+
const pkg = JSON.parse(readFileSync55(resolve41(__dirname5, "..", "package.json"), "utf-8"));
|
|
36019
36317
|
return pkg.version ?? "0.0.0";
|
|
36020
36318
|
} catch {
|
|
36021
36319
|
return "0.0.0";
|
|
36022
36320
|
}
|
|
36023
36321
|
})();
|
|
36024
36322
|
dispatcher = createDispatcher({ serverInfoVersion: PKG_VERSION });
|
|
36323
|
+
try {
|
|
36324
|
+
assertMemoryEngineHealthy(getMemoryDb);
|
|
36325
|
+
} catch (error) {
|
|
36326
|
+
if (error instanceof FatalStartupError) {
|
|
36327
|
+
process.stderr.write(`massu: FATAL \u2014 ${error.message}
|
|
36328
|
+
`);
|
|
36329
|
+
process.exit(1);
|
|
36330
|
+
}
|
|
36331
|
+
throw error;
|
|
36332
|
+
}
|
|
36025
36333
|
pruneMemoryOnStartup();
|
|
36026
36334
|
getCurrentTier().then((tier) => {
|
|
36027
36335
|
process.stderr.write(`massu: License tier: ${tier}
|
|
@@ -36301,7 +36609,7 @@ var config_upgrade_exports = {};
|
|
|
36301
36609
|
__export(config_upgrade_exports, {
|
|
36302
36610
|
runConfigUpgrade: () => runConfigUpgrade
|
|
36303
36611
|
});
|
|
36304
|
-
import { existsSync as
|
|
36612
|
+
import { existsSync as existsSync64, readFileSync as readFileSync56, writeFileSync as writeFileSync15, copyFileSync as copyFileSync3, unlinkSync as unlinkSync6 } from "fs";
|
|
36305
36613
|
import { resolve as resolve42 } from "path";
|
|
36306
36614
|
import { parse as parseYaml6 } from "yaml";
|
|
36307
36615
|
async function runConfigUpgrade(opts = {}) {
|
|
@@ -36313,7 +36621,7 @@ async function runConfigUpgrade(opts = {}) {
|
|
|
36313
36621
|
const err = opts.silent ? () => {
|
|
36314
36622
|
} : (s) => process.stderr.write(s);
|
|
36315
36623
|
if (opts.rollback) {
|
|
36316
|
-
if (!
|
|
36624
|
+
if (!existsSync64(bakPath)) {
|
|
36317
36625
|
const message = `No backup found at ${bakPath}`;
|
|
36318
36626
|
err(message + "\n");
|
|
36319
36627
|
return { exitCode: 1, action: "none", message };
|
|
@@ -36329,14 +36637,14 @@ async function runConfigUpgrade(opts = {}) {
|
|
|
36329
36637
|
return { exitCode: 2, action: "none", message };
|
|
36330
36638
|
}
|
|
36331
36639
|
}
|
|
36332
|
-
if (!
|
|
36640
|
+
if (!existsSync64(configPath)) {
|
|
36333
36641
|
const message = "massu.config.yaml not found. Run: npx massu init";
|
|
36334
36642
|
err(message + "\n");
|
|
36335
36643
|
return { exitCode: 1, action: "none", message };
|
|
36336
36644
|
}
|
|
36337
36645
|
let existing;
|
|
36338
36646
|
try {
|
|
36339
|
-
const content =
|
|
36647
|
+
const content = readFileSync56(configPath, "utf-8");
|
|
36340
36648
|
const parsed = parseYaml6(content);
|
|
36341
36649
|
if (!parsed || typeof parsed !== "object") {
|
|
36342
36650
|
throw new Error("config is not a YAML object");
|
|
@@ -36359,7 +36667,7 @@ async function runConfigUpgrade(opts = {}) {
|
|
|
36359
36667
|
fingerprint: computeFingerprint(detection)
|
|
36360
36668
|
};
|
|
36361
36669
|
try {
|
|
36362
|
-
const original =
|
|
36670
|
+
const original = readFileSync56(configPath, "utf-8");
|
|
36363
36671
|
writeFileSync15(bakPath, original, "utf-8");
|
|
36364
36672
|
} catch (e2) {
|
|
36365
36673
|
const message = `Failed to write backup: ${e2 instanceof Error ? e2.message : String(e2)}`;
|
|
@@ -36393,7 +36701,7 @@ var config_check_drift_exports = {};
|
|
|
36393
36701
|
__export(config_check_drift_exports, {
|
|
36394
36702
|
runConfigCheckDrift: () => runConfigCheckDrift
|
|
36395
36703
|
});
|
|
36396
|
-
import { existsSync as
|
|
36704
|
+
import { existsSync as existsSync65, readFileSync as readFileSync57 } from "fs";
|
|
36397
36705
|
import { resolve as resolve43 } from "path";
|
|
36398
36706
|
import { parse as parseYaml7 } from "yaml";
|
|
36399
36707
|
function renderChanges(changes) {
|
|
@@ -36407,7 +36715,7 @@ async function runConfigCheckDrift(opts = {}) {
|
|
|
36407
36715
|
} : (s) => process.stdout.write(s);
|
|
36408
36716
|
const err = opts.silent ? () => {
|
|
36409
36717
|
} : (s) => process.stderr.write(s);
|
|
36410
|
-
if (!
|
|
36718
|
+
if (!existsSync65(configPath)) {
|
|
36411
36719
|
const message = "massu.config.yaml not found. Run: npx massu init";
|
|
36412
36720
|
err(message + "\n");
|
|
36413
36721
|
return {
|
|
@@ -36421,7 +36729,7 @@ async function runConfigCheckDrift(opts = {}) {
|
|
|
36421
36729
|
}
|
|
36422
36730
|
let config;
|
|
36423
36731
|
try {
|
|
36424
|
-
const content =
|
|
36732
|
+
const content = readFileSync57(configPath, "utf-8");
|
|
36425
36733
|
const parsed = parseYaml7(content);
|
|
36426
36734
|
if (!parsed || typeof parsed !== "object") {
|
|
36427
36735
|
throw new Error("config is not a YAML object");
|
|
@@ -36488,7 +36796,7 @@ var init_config_check_drift = __esm({
|
|
|
36488
36796
|
});
|
|
36489
36797
|
|
|
36490
36798
|
// src/cli.ts
|
|
36491
|
-
import { readFileSync as
|
|
36799
|
+
import { readFileSync as readFileSync58 } from "fs";
|
|
36492
36800
|
import { resolve as resolve44, dirname as dirname27 } from "path";
|
|
36493
36801
|
import { fileURLToPath as fileURLToPath7 } from "url";
|
|
36494
36802
|
var __filename5 = fileURLToPath7(import.meta.url);
|
|
@@ -36770,7 +37078,7 @@ Examples:
|
|
|
36770
37078
|
}
|
|
36771
37079
|
function printVersion() {
|
|
36772
37080
|
try {
|
|
36773
|
-
const pkg = JSON.parse(
|
|
37081
|
+
const pkg = JSON.parse(readFileSync58(resolve44(__dirname6, "../package.json"), "utf-8"));
|
|
36774
37082
|
console.log(`massu v${pkg.version}`);
|
|
36775
37083
|
} catch {
|
|
36776
37084
|
console.log("massu v0.1.0");
|