@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/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([39, 136, 108, 146, 85, 233, 119, 252, 223, 226, 123, 155, 234, 168, 200, 150, 36, 249, 174, 6, 130, 146, 125, 196, 136, 224, 202, 150, 53, 228, 114, 15]);
16545
- LICENSE_PUBKEY_FINGERPRINT_HEX = "18a63d64fdec9e5a368fc45feaa49bed6ced815967e582bc7b8af534f22a9475";
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 === "true";
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 existsSync34, writeFileSync as writeFileSync11, mkdirSync as mkdirSync15 } from "fs";
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 { ...ZERO };
21682
+ if (!res.ok) return failSync(db, `http_${res.status}`);
21501
21683
  envelope = await res.json();
21502
- } catch {
21503
- return { ...ZERO };
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 (existsSync34(candidatePath) || alreadyApplied(db, promptHash)) {
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 (!existsSync34(dir)) mkdirSync15(dir, { recursive: true });
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 existsSync35, mkdirSync as mkdirSync16, writeFileSync as writeFileSync12 } from "fs";
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 (existsSync35(candidatePath)) continue;
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 existsSync36, readFileSync as readFileSync28 } from "fs";
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 (!existsSync36(file)) {
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(readFileSync28(file, "utf-8"));
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 existsSync37, readFileSync as readFileSync29, rmSync as rmSync8 } from "fs";
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 (!existsSync37(configPath)) {
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 = readFileSync29(configPath, "utf-8");
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 (existsSync37(placeholderPath)) {
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 existsSync38, statSync as statSync14 } from "fs";
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 (!existsSync38(p19)) continue;
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 (existsSync38(resolve20(projectRoot, ".git", s))) return true;
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 existsSync39, fsyncSync as fsyncSync4, mkdirSync as mkdirSync17, openSync as openSync4, readFileSync as readFileSync30, renameSync as renameSync5, rmSync as rmSync9, writeFileSync as writeFileSync13, writeSync as writeSync3 } from "fs";
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 (!existsSync39(path)) return { ...DEFAULT_STATE };
23547
- const content = readFileSync30(path, "utf-8");
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 && existsSync39(tmp)) {
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 existsSync40, mkdirSync as mkdirSync18, readFileSync as readFileSync31 } from "fs";
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 && existsSync40(fixed)) return 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 (!existsSync40(path)) {
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 (!existsSync40(path)) return [];
24415
+ if (!existsSync41(path)) return [];
24146
24416
  const warn = opts.warn ?? ((s) => {
24147
24417
  process.stderr.write(s);
24148
24418
  });
24149
- const lines = readFileSync31(path, "utf-8").split("\n").filter(Boolean);
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 existsSync41,
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 (!existsSync41(parentDir)) {
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 (existsSync41(tmpPath)) {
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 existsSync42, readFileSync as readFileSync32, statSync as statSync16 } from "node:fs";
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 (!existsSync42(paths.cachePath)) {
24889
+ if (!existsSync43(paths.cachePath)) {
24620
24890
  return { kind: "absent" };
24621
24891
  }
24622
24892
  let raw;
24623
24893
  try {
24624
- const content = readFileSync32(paths.cachePath, "utf-8");
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 existsSync43, readFileSync as readFileSync33, lstatSync as lstatSync5 } from "node:fs";
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(readFileSync33(abs)).digest("hex");
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 (!existsSync43(path)) return null;
25112
+ if (!existsSync44(path)) return null;
24843
25113
  let raw;
24844
25114
  try {
24845
- raw = JSON.parse(readFileSync33(path, "utf-8"));
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 readFileSync34, readdirSync as readdirSync16, lstatSync as lstatSync6, existsSync as existsSync44 } from "node:fs";
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 (existsSync44(`${packageDir}/${hidden}`)) {
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(readFileSync34(f2.absPath)).digest("hex");
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 (!existsSync44(path)) return {};
25242
+ if (!existsSync45(path)) return {};
24973
25243
  let raw;
24974
25244
  try {
24975
- raw = JSON.parse(readFileSync34(path, "utf-8"));
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 existsSync45, readdirSync as readdirSync17, readFileSync as readFileSync35, lstatSync as lstatSync7 } from "node:fs";
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 (!existsSync45(nodeModulesDir)) {
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 (!existsSync45(pkgJsonPath)) return null;
25392
+ if (!existsSync46(pkgJsonPath)) return null;
25123
25393
  let raw;
25124
25394
  try {
25125
- raw = JSON.parse(readFileSync35(pkgJsonPath, "utf-8"));
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 (!existsSync45(absPath)) {
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 existsSync46, readFileSync as readFileSync36 } from "node:fs";
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 (!existsSync46(yamlPath)) {
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 = readFileSync36(yamlPath, "utf-8");
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 (!existsSync46(packageDir)) {
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 (!existsSync46(pkgJsonPath)) {
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(readFileSync36(pkgJsonPath, "utf-8"));
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 (!existsSync46(packageDir)) {
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 existsSync47 } from "fs";
26203
+ import { existsSync as existsSync48 } from "fs";
25934
26204
  function assertCodegraphUsable(dbPath) {
25935
26205
  const path = dbPath ?? getResolvedPaths().codegraphDbPath;
25936
- if (!existsSync47(path)) {
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 existsSync48, mkdirSync as mkdirSync20, readdirSync as readdirSync18, statSync as statSync17 } from "fs";
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 (!existsSync48(dir)) {
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 readFileSync37, existsSync as existsSync49, statSync as statSync18 } from "fs";
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 (existsSync49(basePath) && !isDirectory(basePath)) {
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 (existsSync49(withExt)) {
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 (existsSync49(indexPath)) {
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 (!existsSync49(absPath)) continue;
26794
+ if (!existsSync50(absPath)) continue;
26525
26795
  let source;
26526
26796
  try {
26527
- source = readFileSync37(absPath, "utf-8");
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 readFileSync38, existsSync as existsSync50, readdirSync as readdirSync19 } from "fs";
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 (!existsSync50(rootPath)) {
26839
+ if (!existsSync51(rootPath)) {
26570
26840
  throw new Error(`Root router not found at ${rootPath}`);
26571
26841
  }
26572
- const source = readFileSync38(rootPath, "utf-8");
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 (existsSync50(candidate)) {
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 (existsSync50(indexCandidate)) {
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 (!existsSync50(absPath)) return [];
26610
- const source = readFileSync38(absPath, "utf-8");
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 (!existsSync50(dir)) continue;
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 = readFileSync38(fullPath, "utf-8");
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 readFileSync39, existsSync as existsSync51 } from "fs";
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 (!existsSync51(absPath)) continue;
27027
+ if (!existsSync52(absPath)) continue;
26758
27028
  try {
26759
- const source = readFileSync39(absPath, "utf-8");
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 (!existsSync51(absPath)) continue;
27048
+ if (!existsSync52(absPath)) continue;
26779
27049
  try {
26780
- const source = readFileSync39(absPath, "utf-8");
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 readFileSync40, existsSync as existsSync52, readdirSync as readdirSync20 } from "fs";
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 (!existsSync52(schemaPath)) {
27326
+ if (!existsSync53(schemaPath)) {
27057
27327
  throw new Error(`Prisma schema not found at ${schemaPath}`);
27058
27328
  }
27059
- const source = readFileSync40(schemaPath, "utf-8");
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 (!existsSync52(routersDir)) return usage2;
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 = readFileSync40(absPath, "utf-8");
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 (!existsSync52(dir)) return result;
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 = readFileSync40(fullPath, "utf-8");
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 readFileSync41, existsSync as existsSync53, readdirSync as readdirSync21 } from "fs";
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 (existsSync53(basePath + ".py")) {
27623
+ if (existsSync54(basePath + ".py")) {
27354
27624
  return relative8(projectRoot, basePath + ".py");
27355
27625
  }
27356
- if (existsSync53(join29(basePath, "__init__.py"))) {
27626
+ if (existsSync54(join29(basePath, "__init__.py"))) {
27357
27627
  return relative8(projectRoot, join29(basePath, "__init__.py"));
27358
27628
  }
27359
- if (basePath.endsWith(".py") && existsSync53(basePath)) {
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 = readFileSync41(absFile, "utf-8");
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 readFileSync42, readdirSync as readdirSync22 } from "fs";
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 = readFileSync42(absFile, "utf-8");
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 readFileSync43, readdirSync as readdirSync23 } from "fs";
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 = readFileSync43(absFile, "utf-8");
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 readFileSync44, readdirSync as readdirSync24 } from "fs";
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 = readFileSync44(absFile, "utf-8");
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 readFileSync45, readdirSync as readdirSync25 } from "fs";
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 = readFileSync45(absFile, "utf-8");
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 readFileSync46, existsSync as existsSync54 } from "fs";
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 (!existsSync54(mapPath)) {
29038
+ if (!existsSync55(mapPath)) {
28769
29039
  throw new Error(`docs-map.json not found at ${mapPath}`);
28770
29040
  }
28771
- return JSON.parse(readFileSync46(mapPath, "utf-8"));
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 (!existsSync54(absPath)) {
29112
+ if (!existsSync55(absPath)) {
28843
29113
  const altPath = ensureWithinRoot(resolve34(getResolvedPaths().srcDir, "../server/api/routers", basename9(routerPath)), root);
28844
- if (!existsSync54(altPath)) return [];
28845
- return extractProcedureNamesFromContent(readFileSync46(altPath, "utf-8"));
29114
+ if (!existsSync55(altPath)) return [];
29115
+ return extractProcedureNamesFromContent(readFileSync47(altPath, "utf-8"));
28846
29116
  }
28847
- return extractProcedureNamesFromContent(readFileSync46(absPath, "utf-8"));
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 (!existsSync54(helpPagePath)) {
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 = readFileSync46(helpPagePath, "utf-8");
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 (existsSync54(guidePath)) {
28942
- const guideContent = readFileSync46(guidePath, "utf-8");
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 = existsSync54(helpPagePath);
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 = readFileSync46(helpPagePath, "utf-8");
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 existsSync55 } from "fs";
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 (!existsSync55(absPath)) {
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 (!existsSync55(routerPath)) {
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("/") && !existsSync55(absPath)) {
29844
+ if (page.page_route.startsWith("/") && !existsSync56(absPath)) {
29575
29845
  const altPath = resolve35(PROJECT_ROOT, `src/app${page.page_route}/page.tsx`);
29576
- if (!existsSync55(altPath)) {
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 readFileSync47, existsSync as existsSync56, readdirSync as readdirSync26, statSync as statSync19 } from "fs";
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 (existsSync56(basePath)) {
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 (!existsSync56(absDir)) continue;
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 = readFileSync47(file, "utf-8");
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 existsSync57, readFileSync as readFileSync48 } from "fs";
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 (!existsSync57(absPath)) {
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 = readFileSync48(absPath, "utf-8");
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 existsSync58, readFileSync as readFileSync49 } from "fs";
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 (!existsSync58(absPath)) {
31806
+ if (!existsSync59(absPath)) {
31537
31807
  return { riskScore: 0, findings: [] };
31538
31808
  }
31539
31809
  let source;
31540
31810
  try {
31541
- source = readFileSync49(absPath, "utf-8");
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 existsSync59, readFileSync as readFileSync50 } from "fs";
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 (!existsSync59(pkgPath)) return /* @__PURE__ */ new Map();
32135
+ if (!existsSync60(pkgPath)) return /* @__PURE__ */ new Map();
31866
32136
  try {
31867
- const pkg = JSON.parse(readFileSync50(pkgPath, "utf-8"));
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 readFileSync51, readdirSync as readdirSync27, statSync as statSync20, existsSync as existsSync60 } from "fs";
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 (existsSync60(paths.plansDir)) {
33051
+ if (existsSync61(paths.plansDir)) {
32782
33052
  const planFiles = discoverMarkdownFiles(paths.plansDir);
32783
33053
  files.push(...planFiles);
32784
33054
  }
32785
- if (existsSync60(paths.docsDir)) {
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 (!existsSync60(filePath)) continue;
32829
- const content = readFileSync51(filePath, "utf-8");
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 (existsSync60(paths.plansDir)) {
33234
+ if (existsSync61(paths.plansDir)) {
32965
33235
  files.push(...discoverMarkdownFiles(paths.plansDir));
32966
33236
  }
32967
- if (existsSync60(paths.docsDir)) {
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 readFileSync52, writeFileSync as writeFileSync14, appendFileSync as appendFileSync4, readdirSync as readdirSync28 } from "fs";
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 = readFileSync52(correctionsPath, "utf-8");
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 readFileSync53, existsSync as existsSync62 } from "fs";
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 (existsSync62(absFilePath)) {
35126
- const fileContent = readFileSync53(absFilePath, "utf-8").slice(0, 3e3);
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 (!existsSync62(absPath)) {
35834
+ if (!existsSync63(absPath)) {
35565
35835
  return text17(`File not found: ${file}`);
35566
35836
  }
35567
- const source = readFileSync53(absPath, "utf-8");
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 readFileSync54 } from "fs";
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(readFileSync54(resolve41(__dirname5, "..", "package.json"), "utf-8"));
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 existsSync63, readFileSync as readFileSync55, writeFileSync as writeFileSync15, copyFileSync as copyFileSync3, unlinkSync as unlinkSync6 } from "fs";
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 (!existsSync63(bakPath)) {
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 (!existsSync63(configPath)) {
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 = readFileSync55(configPath, "utf-8");
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 = readFileSync55(configPath, "utf-8");
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 existsSync64, readFileSync as readFileSync56 } from "fs";
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 (!existsSync64(configPath)) {
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 = readFileSync56(configPath, "utf-8");
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 readFileSync57 } from "fs";
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(readFileSync57(resolve44(__dirname6, "../package.json"), "utf-8"));
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");