@plumpslabs/kuma 2.4.15 → 2.4.16

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.
Files changed (3) hide show
  1. package/dist/index.js +750 -500
  2. package/package.json +1 -1
  3. package/plugin.json +1 -1
package/dist/index.js CHANGED
@@ -4589,14 +4589,216 @@ var init_workspaceIntelligence = __esm({
4589
4589
  }
4590
4590
  });
4591
4591
 
4592
+ // src/engine/mapBackbone.ts
4593
+ var mapBackbone_exports = {};
4594
+ __export(mapBackbone_exports, {
4595
+ BACKBONE_MAX_FILES: () => BACKBONE_MAX_FILES,
4596
+ buildBackbone: () => buildBackbone,
4597
+ ensureBackbone: () => ensureBackbone,
4598
+ ensureMapped: () => ensureMapped,
4599
+ extractImportSources: () => extractImportSources,
4600
+ formatBackbone: () => formatBackbone,
4601
+ isMapEmpty: () => isMapEmpty,
4602
+ readMapMeta: () => readMapMeta
4603
+ });
4604
+ import fs9 from "fs";
4605
+ import path11 from "path";
4606
+ import fastGlob3 from "fast-glob";
4607
+ function extractImportSources(line) {
4608
+ const out = [];
4609
+ const t = line.trim();
4610
+ if (t.startsWith("//") || t.startsWith("#") || t.startsWith("*")) return out;
4611
+ for (const re of IMPORT_RES) {
4612
+ re.lastIndex = 0;
4613
+ let m;
4614
+ while ((m = re.exec(line)) !== null) {
4615
+ if (m[1] && m[1].startsWith(".")) out.push(m[1]);
4616
+ }
4617
+ }
4618
+ return out;
4619
+ }
4620
+ function mapMetaPath(root) {
4621
+ return path11.join(root || getProjectRoot(), MAP_META);
4622
+ }
4623
+ function readMapMeta(root) {
4624
+ try {
4625
+ const fp = mapMetaPath(root);
4626
+ if (fs9.existsSync(fp)) return JSON.parse(fs9.readFileSync(fp, "utf-8"));
4627
+ } catch {
4628
+ }
4629
+ return {};
4630
+ }
4631
+ function writeMapMeta(patch, root) {
4632
+ try {
4633
+ const fp = mapMetaPath(root);
4634
+ const prev = readMapMeta(root);
4635
+ fs9.writeFileSync(fp, JSON.stringify({ ...prev, ...patch }, null, 2), "utf-8");
4636
+ } catch {
4637
+ }
4638
+ }
4639
+ async function isMapEmpty() {
4640
+ try {
4641
+ const { getDb: getDb2 } = await Promise.resolve().then(() => (init_kumaDb(), kumaDb_exports));
4642
+ const db = await getDb2();
4643
+ const stmt = db.prepare(`SELECT COUNT(*) as cnt FROM nodes WHERE type = 'file'`);
4644
+ let n = 0;
4645
+ if (stmt.step()) n = Number(stmt.getAsObject().cnt) || 0;
4646
+ stmt.free();
4647
+ return n === 0;
4648
+ } catch {
4649
+ return true;
4650
+ }
4651
+ }
4652
+ async function buildBackbone(maxFiles = BACKBONE_MAX_FILES) {
4653
+ const started = Date.now();
4654
+ const root = getProjectRoot();
4655
+ const result = { files: 0, capped: false, nodes: 0, edges: 0, ms: 0, filesPerSec: 0 };
4656
+ let files = [];
4657
+ try {
4658
+ files = await fastGlob3([...DEFAULT_SOURCE_INCLUDES], {
4659
+ cwd: root,
4660
+ ignore: ["**/node_modules/**", "**/.git/**", "**/dist/**", "**/build/**", "**/.next/**", "**/coverage/**", "**/*.d.ts", "**/.kuma/**"],
4661
+ onlyFiles: true,
4662
+ deep: 7,
4663
+ dot: false
4664
+ });
4665
+ } catch {
4666
+ return result;
4667
+ }
4668
+ const capped = files.length > maxFiles;
4669
+ const batch = files.slice(0, maxFiles);
4670
+ result.files = batch.length;
4671
+ result.capped = capped;
4672
+ const existingEdges = /* @__PURE__ */ new Set();
4673
+ const existingFiles = /* @__PURE__ */ new Set();
4674
+ try {
4675
+ const { getDb: getDb2 } = await Promise.resolve().then(() => (init_kumaDb(), kumaDb_exports));
4676
+ const db = await getDb2();
4677
+ const stmt = db.prepare(`SELECT source_id, target_id FROM edges WHERE type = 'imports'`);
4678
+ while (stmt.step()) {
4679
+ const r = stmt.getAsObject();
4680
+ existingEdges.add(`${r.source_id}\u2192${r.target_id}`);
4681
+ }
4682
+ stmt.free();
4683
+ const fStmt = db.prepare(`SELECT id FROM nodes WHERE type = 'file'`);
4684
+ while (fStmt.step()) existingFiles.add(fStmt.getAsObject().id);
4685
+ fStmt.free();
4686
+ } catch {
4687
+ }
4688
+ for (const filePath of batch) {
4689
+ try {
4690
+ const full = path11.join(root, filePath);
4691
+ const stat = fs9.statSync(full);
4692
+ if (!stat.isFile() || stat.size > 512 * 1024) continue;
4693
+ const fileId = `file::${filePath}`;
4694
+ if (!existingFiles.has(fileId)) {
4695
+ try {
4696
+ await upsertNode({ id: fileId, type: "file", name: filePath, filePath, metadata: { backbone: true } });
4697
+ existingFiles.add(fileId);
4698
+ result.nodes++;
4699
+ } catch {
4700
+ continue;
4701
+ }
4702
+ }
4703
+ const content = fs9.readFileSync(full, "utf-8");
4704
+ const seen = /* @__PURE__ */ new Set();
4705
+ for (const line of content.split("\n")) {
4706
+ for (const src of extractImportSources(line)) {
4707
+ if (seen.has(src)) continue;
4708
+ seen.add(src);
4709
+ try {
4710
+ const resolved = resolveImportPath(filePath, src, root);
4711
+ const key = resolved ? `${fileId}\u2192file::${resolved}` : "";
4712
+ if (resolved && !existingEdges.has(key)) {
4713
+ await addEdge({ sourceId: fileId, targetId: `file::${resolved}`, type: "imports" });
4714
+ existingEdges.add(key);
4715
+ result.edges++;
4716
+ }
4717
+ } catch {
4718
+ }
4719
+ }
4720
+ }
4721
+ } catch {
4722
+ }
4723
+ }
4724
+ result.ms = Date.now() - started;
4725
+ result.filesPerSec = result.ms > 0 ? Math.round(result.files / result.ms * 1e3) : result.files;
4726
+ writeMapMeta({
4727
+ backboneAt: Date.now(),
4728
+ backboneFiles: result.files,
4729
+ backboneCapped: result.capped,
4730
+ backboneMs: result.ms,
4731
+ filesPerSec: result.filesPerSec
4732
+ });
4733
+ return result;
4734
+ }
4735
+ async function ensureBackbone() {
4736
+ try {
4737
+ if (!await isMapEmpty()) return null;
4738
+ return await buildBackbone();
4739
+ } catch {
4740
+ return null;
4741
+ }
4742
+ }
4743
+ function formatBackbone(r) {
4744
+ return `\u{1F5FA}\uFE0F Backbone: ${r.files} file(s)${r.capped ? ` (capped at ${BACKBONE_MAX_FILES})` : ""}, ${r.edges} import edge(s) in ${r.ms}ms (~${r.filesPerSec} files/s) \u2014 approximate tier, symbols fill in on demand.`;
4745
+ }
4746
+ async function ensureMapped(files) {
4747
+ const targets = [...new Set(files.map((f) => f.trim()).filter(Boolean))].slice(0, 10);
4748
+ if (targets.length === 0) return { filled: 0 };
4749
+ let missing = [];
4750
+ try {
4751
+ const { getDb: getDb2 } = await Promise.resolve().then(() => (init_kumaDb(), kumaDb_exports));
4752
+ const db = await getDb2();
4753
+ for (const f of targets) {
4754
+ const stmt = db.prepare(
4755
+ `SELECT COUNT(*) as cnt FROM nodes WHERE type IN ('function','class','method','interface') AND file_path LIKE ?`
4756
+ );
4757
+ stmt.bind([`%${path11.basename(f)}%`]);
4758
+ let n = 0;
4759
+ if (stmt.step()) n = Number(stmt.getAsObject().cnt) || 0;
4760
+ stmt.free();
4761
+ if (n === 0) missing.push(f);
4762
+ }
4763
+ } catch {
4764
+ missing = targets;
4765
+ }
4766
+ if (missing.length === 0) return { filled: 0 };
4767
+ try {
4768
+ const { scanCodebase: scanCodebase2 } = await Promise.resolve().then(() => (init_kumaCodeScanner(), kumaCodeScanner_exports));
4769
+ const res = await scanCodebase2({ include: missing, force: true, maxFiles: missing.length });
4770
+ if (res.filesScanned > 0) writeMapMeta({ precisionAt: Date.now() });
4771
+ return { filled: Math.min(missing.length, res.filesScanned) };
4772
+ } catch {
4773
+ return { filled: 0 };
4774
+ }
4775
+ }
4776
+ var BACKBONE_MAX_FILES, MAP_META, IMPORT_RES;
4777
+ var init_mapBackbone = __esm({
4778
+ "src/engine/mapBackbone.ts"() {
4779
+ "use strict";
4780
+ init_pathValidator();
4781
+ init_kumaGraph();
4782
+ init_kumaCodeScanner();
4783
+ init_languageSupport();
4784
+ BACKBONE_MAX_FILES = 2e3;
4785
+ MAP_META = ".kuma/map-meta.json";
4786
+ IMPORT_RES = [
4787
+ /(?:import)\s+(?:[\w*{},\s]+\s+from\s+|[\w$]+\s+)?['"]([^'"]+)['"]/g,
4788
+ /(?:from)\s+["']?([a-zA-Z0-9_./-]+)["']?\s+import\s+/g,
4789
+ /require\s*\(\s*['"]([^'"]+)['"]\s*\)/g
4790
+ ];
4791
+ }
4792
+ });
4793
+
4592
4794
  // src/engine/symbolReach.ts
4593
4795
  var symbolReach_exports = {};
4594
4796
  __export(symbolReach_exports, {
4595
4797
  formatReachability: () => formatReachability,
4596
4798
  symbolReachability: () => symbolReachability
4597
4799
  });
4598
- import fs9 from "fs";
4599
- import path11 from "path";
4800
+ import fs10 from "fs";
4801
+ import path12 from "path";
4600
4802
  import { execSync as execSync4 } from "child_process";
4601
4803
  async function graphReach(symbol, limit) {
4602
4804
  const rows = [];
@@ -4663,16 +4865,16 @@ function ripgrepReach(symbol, root, limit) {
4663
4865
  }
4664
4866
  for (const c of [...callers].slice(0, BERBEDA)) {
4665
4867
  const [fp] = c.split(":");
4666
- const dir = path11.dirname(fp);
4667
- const stem = path11.basename(fp, path11.extname(fp)).split(/[-_.]/)[0];
4868
+ const dir = path12.dirname(fp);
4869
+ const stem = path12.basename(fp, path12.extname(fp)).split(/[-_.]/)[0];
4668
4870
  try {
4669
- const dirFull = path11.join(root, dir);
4670
- if (!fs9.existsSync(dirFull)) continue;
4671
- for (const f of fs9.readdirSync(dirFull)) {
4871
+ const dirFull = path12.join(root, dir);
4872
+ if (!fs10.existsSync(dirFull)) continue;
4873
+ for (const f of fs10.readdirSync(dirFull)) {
4672
4874
  if (!/(\.test\.|\.spec\.|_test\.)/i.test(f)) continue;
4673
4875
  const low = f.toLowerCase();
4674
4876
  if (low.includes(stem.toLowerCase()) || low.includes(symbol.toLowerCase())) {
4675
- const rel = path11.join(dir, f);
4877
+ const rel = path12.join(dir, f);
4676
4878
  if (!rows.some((r) => r.test === rel)) {
4677
4879
  rows.push({ test: rel, via: fp, evidence: `${rel} sibling-matches caller ${fp} (called at ${c})` });
4678
4880
  }
@@ -4822,17 +5024,17 @@ __export(impactAnalysis_exports, {
4822
5024
  classifyDiffShape: () => classifyDiffShape,
4823
5025
  getIndexerStatus: () => getIndexerStatus
4824
5026
  });
4825
- import fs10 from "fs";
4826
- import path12 from "path";
5027
+ import fs11 from "fs";
5028
+ import path13 from "path";
4827
5029
  import { execSync as execSync5 } from "child_process";
4828
- import fastGlob3 from "fast-glob";
5030
+ import fastGlob4 from "fast-glob";
4829
5031
  function extOf(target) {
4830
- const base = path12.basename(target);
5032
+ const base = path13.basename(target);
4831
5033
  const dot = base.lastIndexOf(".");
4832
5034
  return dot > 0 ? base.slice(dot).toLowerCase() : "";
4833
5035
  }
4834
5036
  function isExampleOrDocName(target) {
4835
- const base = path12.basename(target).toLowerCase();
5037
+ const base = path13.basename(target).toLowerCase();
4836
5038
  return base.endsWith(".example") || base.startsWith(".env") || base.endsWith(".md") || base.endsWith(".txt") || base.endsWith(".rst") || base === "license" || base.startsWith("license.");
4837
5039
  }
4838
5040
  function classifyDiffShape(target, root) {
@@ -4865,7 +5067,7 @@ function classifyDiffShape(target, root) {
4865
5067
  return { shape: "runtime-code", detail: "runtime code change" };
4866
5068
  }
4867
5069
  async function findImportingFiles(targetFile, root) {
4868
- const normTarget = normalizeScope(path12.normalize(targetFile)) || path12.normalize(targetFile);
5070
+ const normTarget = normalizeScope(path13.normalize(targetFile)) || path13.normalize(targetFile);
4869
5071
  try {
4870
5072
  const db = await getDb();
4871
5073
  const targetFileId = `file::${normTarget}`;
@@ -4904,10 +5106,10 @@ async function findImportingFiles(targetFile, root) {
4904
5106
  }
4905
5107
  } catch {
4906
5108
  }
4907
- const baseName = path12.basename(normTarget, path12.extname(normTarget));
4908
- const relTarget = path12.isAbsolute(normTarget) ? path12.relative(root, normTarget) : normTarget;
5109
+ const baseName = path13.basename(normTarget, path13.extname(normTarget));
5110
+ const relTarget = path13.isAbsolute(normTarget) ? path13.relative(root, normTarget) : normTarget;
4909
5111
  try {
4910
- const files = await fastGlob3(
5112
+ const files = await fastGlob4(
4911
5113
  ["**/*.{ts,tsx,js,jsx,mjs,cjs,py,go,rs}"],
4912
5114
  {
4913
5115
  cwd: root,
@@ -4922,10 +5124,10 @@ async function findImportingFiles(targetFile, root) {
4922
5124
  "i"
4923
5125
  );
4924
5126
  for (const f of files) {
4925
- if (path12.normalize(f) === path12.normalize(relTarget)) continue;
4926
- const fullPath = path12.join(root, f);
5127
+ if (path13.normalize(f) === path13.normalize(relTarget)) continue;
5128
+ const fullPath = path13.join(root, f);
4927
5129
  try {
4928
- const content = fs10.readFileSync(fullPath, "utf-8");
5130
+ const content = fs11.readFileSync(fullPath, "utf-8");
4929
5131
  const lines = content.split("\n");
4930
5132
  const hitIdx = lines.findIndex((l) => importRegex.test(l));
4931
5133
  if (hitIdx >= 0) {
@@ -4941,7 +5143,7 @@ async function findImportingFiles(targetFile, root) {
4941
5143
  }
4942
5144
  }
4943
5145
  async function findRelatedTests(targetFile, root, owningPackage, additionalDependents = [], exactOnly = false) {
4944
- const normTarget = normalizeScope(path12.normalize(targetFile)) || path12.normalize(targetFile);
5146
+ const normTarget = normalizeScope(path13.normalize(targetFile)) || path13.normalize(targetFile);
4945
5147
  try {
4946
5148
  const db = await getDb();
4947
5149
  const targetFileId = `file::${normTarget}`;
@@ -4965,13 +5167,13 @@ async function findRelatedTests(targetFile, root, owningPackage, additionalDepen
4965
5167
  }
4966
5168
  } catch {
4967
5169
  }
4968
- const baseName = path12.basename(normTarget, path12.extname(normTarget));
5170
+ const baseName = path13.basename(normTarget, path13.extname(normTarget));
4969
5171
  const testFiles = [];
4970
5172
  const stems = /* @__PURE__ */ new Set();
4971
5173
  if (baseName) stems.add(baseName);
4972
5174
  if (!exactOnly) {
4973
5175
  for (const dep of additionalDependents.slice(0, 3)) {
4974
- const depBase = path12.basename(dep, path12.extname(dep));
5176
+ const depBase = path13.basename(dep, path13.extname(dep));
4975
5177
  if (depBase) stems.add(depBase);
4976
5178
  }
4977
5179
  }
@@ -4987,7 +5189,7 @@ async function findRelatedTests(targetFile, root, owningPackage, additionalDepen
4987
5189
  );
4988
5190
  }
4989
5191
  try {
4990
- const matches = await fastGlob3(testPatterns, {
5192
+ const matches = await fastGlob4(testPatterns, {
4991
5193
  cwd: root,
4992
5194
  ignore: ["**/node_modules/**", "**/dist/**", "**/.git/**", "**/.kuma/**"],
4993
5195
  onlyFiles: true
@@ -5006,13 +5208,13 @@ async function findRelatedTests(targetFile, root, owningPackage, additionalDepen
5006
5208
  `**/__tests__/**/*${stem}*.*`
5007
5209
  );
5008
5210
  }
5009
- const pkgTests = await fastGlob3(pkgPatterns, {
5010
- cwd: path12.join(root, owningPackage.path),
5211
+ const pkgTests = await fastGlob4(pkgPatterns, {
5212
+ cwd: path13.join(root, owningPackage.path),
5011
5213
  ignore: ["**/node_modules/**", "**/dist/**"],
5012
5214
  onlyFiles: true
5013
5215
  });
5014
5216
  for (const pt of pkgTests) {
5015
- const fullRel = path12.join(owningPackage.path, pt);
5217
+ const fullRel = path13.join(owningPackage.path, pt);
5016
5218
  if (!testFiles.includes(fullRel)) {
5017
5219
  testFiles.push(fullRel);
5018
5220
  }
@@ -5063,18 +5265,29 @@ function assessRisk(target, targetType, directDependents, downstreamPackages, af
5063
5265
  }
5064
5266
  async function getIndexerStatus() {
5065
5267
  let graphEdges = false;
5268
+ let backboneOnly = false;
5066
5269
  try {
5067
5270
  const db = await getDb();
5068
5271
  const stmt = db.prepare(`SELECT COUNT(*) as cnt FROM edges WHERE type IN ('imports','depends_on','calls','tests')`);
5069
5272
  if (stmt.step()) graphEdges = Number(stmt.getAsObject().cnt) > 0;
5070
5273
  stmt.free();
5274
+ const fStmt = db.prepare(`SELECT COUNT(*) as cnt FROM nodes WHERE type = 'file'`);
5275
+ let files = 0;
5276
+ if (fStmt.step()) files = Number(fStmt.getAsObject().cnt) || 0;
5277
+ fStmt.free();
5278
+ const sStmt = db.prepare(`SELECT COUNT(*) as cnt FROM nodes WHERE type IN ('function','class','method','interface')`);
5279
+ let syms = 0;
5280
+ if (sStmt.step()) syms = Number(sStmt.getAsObject().cnt) || 0;
5281
+ sStmt.free();
5282
+ backboneOnly = files > 0 && syms === 0;
5071
5283
  } catch {
5072
5284
  }
5073
5285
  return {
5074
5286
  tier: graphEdges ? 1 : 2,
5075
5287
  graphEdges,
5288
+ backboneOnly,
5076
5289
  languages: ["ts", "tsx", "js", "jsx", "mjs", "cjs", "py", "go", "rs"],
5077
- note: graphEdges ? "Tier 1: graph edges grounded the verdict (Tier 2 ripgrep fallback available)" : "Tier 2: ripgrep import-regex fallback (no graph edges; run a scan to reach Tier 1; LSP indexers are future work per #35)"
5290
+ note: backboneOnly ? "Backbone-tier coverage: import graph only (approximate) \u2014 symbols fill in on demand when impact/research touches an area" : graphEdges ? "Tier 1: graph edges grounded the verdict (Tier 2 ripgrep fallback available)" : "Tier 2: ripgrep import-regex fallback (no graph edges; run a scan to reach Tier 1; LSP indexers are future work per #35)"
5078
5291
  };
5079
5292
  }
5080
5293
  async function calculateBlastRadius(target, options = {}) {
@@ -5100,6 +5313,13 @@ async function calculateBlastRadius(target, options = {}) {
5100
5313
  const rev = getReverseDependencies(owningPackage.name, wsInfo);
5101
5314
  downstreamPackages.push(...rev.map((p) => p.name));
5102
5315
  }
5316
+ if (targetType === "file") {
5317
+ try {
5318
+ const { ensureMapped: ensureMapped2 } = await Promise.resolve().then(() => (init_mapBackbone(), mapBackbone_exports));
5319
+ await ensureMapped2([target]);
5320
+ } catch {
5321
+ }
5322
+ }
5103
5323
  let directDependents = [];
5104
5324
  let evidence = [];
5105
5325
  if (targetType === "file" || targetType === "symbol") {
@@ -6339,27 +6559,27 @@ async function codebaseSearchFallback(query, limit = 20) {
6339
6559
  if (results.length >= limit || depth > MAX_WALK_DEPTH) return;
6340
6560
  let entries = [];
6341
6561
  try {
6342
- entries = fs34.readdirSync(dir);
6562
+ entries = fs35.readdirSync(dir);
6343
6563
  } catch {
6344
6564
  return;
6345
6565
  }
6346
6566
  for (const entry of entries) {
6347
6567
  if (entry.startsWith(".") || entry === "node_modules" || entry === "dist" || entry === "build") continue;
6348
- const full = path37.join(dir, entry);
6568
+ const full = path38.join(dir, entry);
6349
6569
  try {
6350
- const stat = fs34.statSync(full);
6570
+ const stat = fs35.statSync(full);
6351
6571
  if (stat.isDirectory()) {
6352
6572
  walk2(full, depth + 1);
6353
6573
  } else if (entry.toLowerCase().includes(query.toLowerCase())) {
6354
- results.push(path37.relative(root, full));
6574
+ results.push(path38.relative(root, full));
6355
6575
  }
6356
6576
  } catch {
6357
6577
  }
6358
6578
  }
6359
6579
  };
6360
6580
  var walk = walk2;
6361
- const fs34 = await import("fs");
6362
- const path37 = await import("path");
6581
+ const fs35 = await import("fs");
6582
+ const path38 = await import("path");
6363
6583
  const root = process.cwd();
6364
6584
  const results = [];
6365
6585
  const MAX_WALK_DEPTH = 8;
@@ -6641,8 +6861,8 @@ __export(kumaShared_exports, {
6641
6861
  isTestTool: () => isTestTool
6642
6862
  });
6643
6863
  import { execSync as execSync6 } from "child_process";
6644
- import fs11 from "fs";
6645
- import path13 from "path";
6864
+ import fs12 from "fs";
6865
+ import path14 from "path";
6646
6866
  function isEditTool(toolName) {
6647
6867
  const n = (toolName || "").toLowerCase();
6648
6868
  return n.includes("edit") || n.includes("write") || n.includes("patch") || n.includes("apply") || n.includes("replace");
@@ -6748,10 +6968,10 @@ function hasVerificationEvidence(toolCalls) {
6748
6968
  }
6749
6969
  function hasVerificationInHookLog(hours = 24) {
6750
6970
  try {
6751
- const fp = path13.join(getProjectRoot(), ".kuma", "injections.jsonl");
6752
- if (!fs11.existsSync(fp)) return false;
6971
+ const fp = path14.join(getProjectRoot(), ".kuma", "injections.jsonl");
6972
+ if (!fs12.existsSync(fp)) return false;
6753
6973
  const cutoff = Date.now() - hours * 60 * 60 * 1e3;
6754
- const lines = fs11.readFileSync(fp, "utf-8").split("\n");
6974
+ const lines = fs12.readFileSync(fp, "utf-8").split("\n");
6755
6975
  for (const line of lines) {
6756
6976
  if (!line.trim()) continue;
6757
6977
  try {
@@ -6893,19 +7113,19 @@ __export(kumaMemory_exports, {
6893
7113
  scoreMemoryRelevance: () => scoreMemoryRelevance,
6894
7114
  shouldRecordDecision: () => shouldRecordDecision
6895
7115
  });
6896
- import fs12 from "fs";
6897
- import path14 from "path";
7116
+ import fs13 from "fs";
7117
+ import path15 from "path";
6898
7118
  function scoreMemoryRelevance(context, limit = 5) {
6899
7119
  const results = [];
6900
- const kumaDir = path14.join(getProjectRoot(), MEMORY_DIR);
6901
- if (!fs12.existsSync(kumaDir)) return [];
7120
+ const kumaDir = path15.join(getProjectRoot(), MEMORY_DIR);
7121
+ if (!fs13.existsSync(kumaDir)) return [];
6902
7122
  const terms = Array.from(new Set(context.toLowerCase().split(/[\s/._-]+/).filter((w) => w.length > 2)));
6903
7123
  if (terms.length === 0) return [];
6904
7124
  try {
6905
- const files = fs12.readdirSync(kumaDir).filter((f) => f.endsWith(".md"));
7125
+ const files = fs13.readdirSync(kumaDir).filter((f) => f.endsWith(".md"));
6906
7126
  for (const file of files) {
6907
7127
  try {
6908
- const content = fs12.readFileSync(path14.join(kumaDir, file), "utf-8");
7128
+ const content = fs13.readFileSync(path15.join(kumaDir, file), "utf-8");
6909
7129
  const lower = content.toLowerCase();
6910
7130
  let matchCount = 0;
6911
7131
  for (const term of terms) {
@@ -7087,8 +7307,8 @@ __export(cacheFreshness_exports, {
7087
7307
  isStale: () => isStale,
7088
7308
  markDirty: () => markDirty
7089
7309
  });
7090
- import fs13 from "fs";
7091
- import path15 from "path";
7310
+ import fs14 from "fs";
7311
+ import path16 from "path";
7092
7312
  function isStale(savedAtMs, ttlMs, nowMs = Date.now()) {
7093
7313
  if (!savedAtMs) return true;
7094
7314
  return nowMs - savedAtMs > ttlMs;
@@ -7101,13 +7321,13 @@ function formatAge(savedAtMs, nowMs = Date.now()) {
7101
7321
  return `${Math.floor(s / 86400)}d`;
7102
7322
  }
7103
7323
  function dirtyPath() {
7104
- return path15.join(getProjectRoot(), DIRTY_FILE);
7324
+ return path16.join(getProjectRoot(), DIRTY_FILE);
7105
7325
  }
7106
7326
  function loadDirty() {
7107
7327
  try {
7108
7328
  const fp = dirtyPath();
7109
- if (fs13.existsSync(fp)) {
7110
- const parsed = JSON.parse(fs13.readFileSync(fp, "utf-8"));
7329
+ if (fs14.existsSync(fp)) {
7330
+ const parsed = JSON.parse(fs14.readFileSync(fp, "utf-8"));
7111
7331
  if (parsed && typeof parsed === "object") return parsed;
7112
7332
  }
7113
7333
  } catch {
@@ -7117,14 +7337,14 @@ function loadDirty() {
7117
7337
  function markDirty(filePath) {
7118
7338
  try {
7119
7339
  const fp = dirtyPath();
7120
- const dir = path15.dirname(fp);
7121
- if (!fs13.existsSync(dir)) fs13.mkdirSync(dir, { recursive: true });
7340
+ const dir = path16.dirname(fp);
7341
+ if (!fs14.existsSync(dir)) fs14.mkdirSync(dir, { recursive: true });
7122
7342
  const dirty = loadDirty();
7123
7343
  dirty[filePath] = Date.now();
7124
7344
  const keys = Object.keys(dirty).sort((a, b) => dirty[b] - dirty[a]).slice(0, 200);
7125
7345
  const bounded = {};
7126
7346
  for (const k of keys) bounded[k] = dirty[k];
7127
- fs13.writeFileSync(fp, JSON.stringify(bounded), "utf-8");
7347
+ fs14.writeFileSync(fp, JSON.stringify(bounded), "utf-8");
7128
7348
  } catch {
7129
7349
  }
7130
7350
  }
@@ -7134,7 +7354,7 @@ function getDirtyFiles() {
7134
7354
  function clearDirty() {
7135
7355
  try {
7136
7356
  const fp = dirtyPath();
7137
- if (fs13.existsSync(fp)) fs13.rmSync(fp, { force: true });
7357
+ if (fs14.existsSync(fp)) fs14.rmSync(fp, { force: true });
7138
7358
  } catch {
7139
7359
  }
7140
7360
  }
@@ -7154,8 +7374,8 @@ var codeReuseEngine_exports = {};
7154
7374
  __export(codeReuseEngine_exports, {
7155
7375
  findReusableSymbols: () => findReusableSymbols
7156
7376
  });
7157
- import path16 from "path";
7158
- import fs14 from "fs";
7377
+ import path17 from "path";
7378
+ import fs15 from "fs";
7159
7379
  async function findReusableSymbols(query, scope) {
7160
7380
  const cleanQuery = query.trim().toLowerCase();
7161
7381
  const searchTokens = cleanQuery.replace(/[^a-zA-Z0-9_\s]/g, " ").split(/\s+/).filter((t) => t.length >= 2);
@@ -7278,7 +7498,7 @@ function detectRecommendedUtilDirectory() {
7278
7498
  "utils"
7279
7499
  ];
7280
7500
  for (const c of candidates) {
7281
- if (fs14.existsSync(path16.resolve(root, c))) {
7501
+ if (fs15.existsSync(path17.resolve(root, c))) {
7282
7502
  return c;
7283
7503
  }
7284
7504
  }
@@ -7297,7 +7517,7 @@ var domainClusterEngine_exports = {};
7297
7517
  __export(domainClusterEngine_exports, {
7298
7518
  buildSubsystemClusters: () => buildSubsystemClusters
7299
7519
  });
7300
- import path17 from "path";
7520
+ import path18 from "path";
7301
7521
  async function buildSubsystemClusters() {
7302
7522
  const db = await getDb();
7303
7523
  const fileStmt = db.prepare(`
@@ -7374,7 +7594,7 @@ async function buildSubsystemClusters() {
7374
7594
  for (const [cKey, files] of clusterFileMap.entries()) {
7375
7595
  for (const f of files) {
7376
7596
  fileToCluster.set(f, cKey);
7377
- fileToCluster.set(path17.normalize(f), cKey);
7597
+ fileToCluster.set(path18.normalize(f), cKey);
7378
7598
  }
7379
7599
  }
7380
7600
  const clusterInteractions = /* @__PURE__ */ new Map();
@@ -7382,8 +7602,8 @@ async function buildSubsystemClusters() {
7382
7602
  const srcFile = extractFilePathFromNodeId(e.source);
7383
7603
  const tgtFile = extractFilePathFromNodeId(e.target);
7384
7604
  if (!srcFile || !tgtFile) continue;
7385
- const srcCluster = fileToCluster.get(srcFile) || fileToCluster.get(path17.normalize(srcFile));
7386
- const tgtCluster = fileToCluster.get(tgtFile) || fileToCluster.get(path17.normalize(tgtFile));
7605
+ const srcCluster = fileToCluster.get(srcFile) || fileToCluster.get(path18.normalize(srcFile));
7606
+ const tgtCluster = fileToCluster.get(tgtFile) || fileToCluster.get(path18.normalize(tgtFile));
7387
7607
  if (srcCluster && tgtCluster && srcCluster !== tgtCluster) {
7388
7608
  const pairKey = `${srcCluster}->${tgtCluster}`;
7389
7609
  const stats = clusterInteractions.get(pairKey) || { calls: 0, imports: 0 };
@@ -7405,13 +7625,13 @@ async function buildSubsystemClusters() {
7405
7625
  const clusterId = nodeId("feature_domain", cKey);
7406
7626
  const name = formatClusterName(cKey);
7407
7627
  const role = inferSubsystemRole(cKey, files);
7408
- const entrypoints = files.filter((f) => /index|main|server|app|engine|root/i.test(path17.basename(f))).slice(0, 3);
7628
+ const entrypoints = files.filter((f) => /index|main|server|app|engine|root/i.test(path18.basename(f))).slice(0, 3);
7409
7629
  if (entrypoints.length === 0 && files.length > 0) {
7410
7630
  entrypoints.push(files[0]);
7411
7631
  }
7412
7632
  const allSyms = [];
7413
7633
  for (const f of files) {
7414
- const syms = fileSymbols.get(f) || fileSymbols.get(path17.normalize(f)) || [];
7634
+ const syms = fileSymbols.get(f) || fileSymbols.get(path18.normalize(f)) || [];
7415
7635
  for (const s of syms) {
7416
7636
  if (!allSyms.includes(s)) allSyms.push(s);
7417
7637
  }
@@ -7590,7 +7810,7 @@ function inferSubsystemRole(key, files) {
7590
7810
  if (k.includes("util") || k.includes("common")) {
7591
7811
  return "Shared path validation, configuration loading, and platform detection helpers.";
7592
7812
  }
7593
- return `Core subsystem handling ${files.slice(0, 3).map((f) => path17.basename(f)).join(", ")}.`;
7813
+ return `Core subsystem handling ${files.slice(0, 3).map((f) => path18.basename(f)).join(", ")}.`;
7594
7814
  }
7595
7815
  function inferTypedVerb(sourceKey, targetKey, _stats) {
7596
7816
  const src = sourceKey.toLowerCase();
@@ -7669,18 +7889,18 @@ __export(domainRules_exports, {
7669
7889
  readLayer: () => readLayer,
7670
7890
  writeLayer: () => writeLayer
7671
7891
  });
7672
- import fs15 from "fs";
7673
- import path18 from "path";
7892
+ import fs16 from "fs";
7893
+ import path19 from "path";
7674
7894
  function layerFilePath(layer) {
7675
- return path18.join(getProjectRoot(), ".kuma", LAYER_FILES[layer].filename);
7895
+ return path19.join(getProjectRoot(), ".kuma", LAYER_FILES[layer].filename);
7676
7896
  }
7677
7897
  function ensureLayerFile(layer) {
7678
7898
  const fp = layerFilePath(layer);
7679
- if (!fs15.existsSync(fp)) {
7899
+ if (!fs16.existsSync(fp)) {
7680
7900
  const template = layer === "arch_flow" ? ARCH_FLOW_TEMPLATE : GOTCHAS_TEMPLATE;
7681
- const dir = path18.dirname(fp);
7682
- if (!fs15.existsSync(dir)) fs15.mkdirSync(dir, { recursive: true });
7683
- fs15.writeFileSync(fp, template, "utf-8");
7901
+ const dir = path19.dirname(fp);
7902
+ if (!fs16.existsSync(dir)) fs16.mkdirSync(dir, { recursive: true });
7903
+ fs16.writeFileSync(fp, template, "utf-8");
7684
7904
  console.error(`[DomainRules] Auto-created ${LAYER_FILES[layer].filename}`);
7685
7905
  }
7686
7906
  return fp;
@@ -7688,7 +7908,7 @@ function ensureLayerFile(layer) {
7688
7908
  function readLayer(layer) {
7689
7909
  try {
7690
7910
  const fp = ensureLayerFile(layer);
7691
- return fs15.readFileSync(fp, "utf-8");
7911
+ return fs16.readFileSync(fp, "utf-8");
7692
7912
  } catch (err) {
7693
7913
  return `Error reading ${layer}: ${err}`;
7694
7914
  }
@@ -7696,7 +7916,7 @@ function readLayer(layer) {
7696
7916
  function writeLayer(layer, content) {
7697
7917
  try {
7698
7918
  const fp = ensureLayerFile(layer);
7699
- fs15.writeFileSync(fp, content, "utf-8");
7919
+ fs16.writeFileSync(fp, content, "utf-8");
7700
7920
  const label = LAYER_FILES[layer].label;
7701
7921
  sessionMemory.recordToolCall("kuma_memory", { action: `write_${layer}` });
7702
7922
  return `\u2705 **${label}** updated successfully.`;
@@ -7707,9 +7927,9 @@ function writeLayer(layer, content) {
7707
7927
  function appendToLayer(layer, entry) {
7708
7928
  try {
7709
7929
  const fp = ensureLayerFile(layer);
7710
- const existing = fs15.readFileSync(fp, "utf-8");
7930
+ const existing = fs16.readFileSync(fp, "utf-8");
7711
7931
  const newContent = existing.trimEnd() + "\n\n" + entry.trim() + "\n";
7712
- fs15.writeFileSync(fp, newContent, "utf-8");
7932
+ fs16.writeFileSync(fp, newContent, "utf-8");
7713
7933
  return `\u2705 Entry added to **${LAYER_FILES[layer].label}**.`;
7714
7934
  } catch (err) {
7715
7935
  return `\u274C Failed to append: ${err}`;
@@ -7719,7 +7939,7 @@ function getActiveGotchas() {
7719
7939
  const results = [];
7720
7940
  try {
7721
7941
  const fp = ensureLayerFile("gotcha");
7722
- const content = fs15.readFileSync(fp, "utf-8");
7942
+ const content = fs16.readFileSync(fp, "utf-8");
7723
7943
  const lines = content.split("\n");
7724
7944
  let currentSection = "";
7725
7945
  let currentFilePath = "";
@@ -7755,9 +7975,9 @@ function getActiveGotchas() {
7755
7975
  function checkFileGotchas(filePath) {
7756
7976
  const gotchas = getActiveGotchas();
7757
7977
  const warnings = [];
7758
- const base = path18.basename(filePath);
7978
+ const base = path19.basename(filePath);
7759
7979
  for (const g of gotchas) {
7760
- const gBase = path18.basename(g.filePath);
7980
+ const gBase = path19.basename(g.filePath);
7761
7981
  if (filePath.includes(g.filePath) || g.filePath.includes(filePath) || base && gBase && base === gBase) {
7762
7982
  const icon = g.severity === "critical" ? "\u{1F534}" : g.severity === "high" ? "\u{1F7E0}" : g.severity === "medium" ? "\u{1F7E1}" : "\u{1F7E2}";
7763
7983
  warnings.push(`${icon} **Gotcha**: ${g.description} (${g.severity})`);
@@ -7857,8 +8077,8 @@ __export(kumaInject_exports, {
7857
8077
  parseHookInput: () => parseHookInput,
7858
8078
  trackFileEditLoop: () => trackFileEditLoop
7859
8079
  });
7860
- import fs16 from "fs";
7861
- import path19 from "path";
8080
+ import fs17 from "fs";
8081
+ import path20 from "path";
7862
8082
  function hashFileContent(filePath) {
7863
8083
  return hashFile(filePath);
7864
8084
  }
@@ -7869,10 +8089,10 @@ function isGotchaFresh(storedHash, currentHash) {
7869
8089
  }
7870
8090
  async function getFreshGotchasForFile(filePath, limit = 5, includeStale = false) {
7871
8091
  const root = getProjectRoot();
7872
- const base = path19.basename(filePath);
8092
+ const base = path20.basename(filePath);
7873
8093
  try {
7874
- const dbFile = path19.join(root, ".kuma", "kuma.db");
7875
- if (fs16.existsSync(dbFile)) {
8094
+ const dbFile = path20.join(root, ".kuma", "kuma.db");
8095
+ if (fs17.existsSync(dbFile)) {
7876
8096
  const { getDb: getDb2 } = await Promise.resolve().then(() => (init_kumaDb(), kumaDb_exports));
7877
8097
  const db = await getDb2();
7878
8098
  const stmt = db.prepare(`
@@ -7913,11 +8133,11 @@ async function getFreshGotchasForFile(filePath, limit = 5, includeStale = false)
7913
8133
  } catch {
7914
8134
  }
7915
8135
  try {
7916
- if (!fs16.existsSync(path19.join(root, ".kuma"))) return [];
8136
+ if (!fs17.existsSync(path20.join(root, ".kuma"))) return [];
7917
8137
  const { getActiveGotchas: getActiveGotchas2 } = await Promise.resolve().then(() => (init_domainRules(), domainRules_exports));
7918
8138
  const allGotchas = getActiveGotchas2();
7919
8139
  const matched = allGotchas.filter(
7920
- (g) => g.filePath.includes(filePath) || filePath.includes(g.filePath) || base && path19.basename(g.filePath) === base
8140
+ (g) => g.filePath.includes(filePath) || filePath.includes(g.filePath) || base && path20.basename(g.filePath) === base
7921
8141
  );
7922
8142
  if (matched.length > 0) {
7923
8143
  return matched.slice(0, limit).map((g) => ({
@@ -7936,8 +8156,8 @@ async function getFreshGotchasForFile(filePath, limit = 5, includeStale = false)
7936
8156
  async function getFileTrace(filePath, limit = 8) {
7937
8157
  try {
7938
8158
  const root = getProjectRoot();
7939
- const dbFile = path19.join(root, ".kuma", "kuma.db");
7940
- if (!fs16.existsSync(dbFile)) return [];
8159
+ const dbFile = path20.join(root, ".kuma", "kuma.db");
8160
+ if (!fs17.existsSync(dbFile)) return [];
7941
8161
  const { getDb: getDb2 } = await Promise.resolve().then(() => (init_kumaDb(), kumaDb_exports));
7942
8162
  const db = await getDb2();
7943
8163
  const stmt = db.prepare(`
@@ -7947,7 +8167,7 @@ async function getFileTrace(filePath, limit = 8) {
7947
8167
  ORDER BY cl.created_at DESC
7948
8168
  LIMIT ?
7949
8169
  `);
7950
- stmt.bind([`%${path19.basename(filePath)}%`, limit]);
8170
+ stmt.bind([`%${path20.basename(filePath)}%`, limit]);
7951
8171
  const rows = [];
7952
8172
  while (stmt.step()) rows.push(stmt.getAsObject());
7953
8173
  stmt.free();
@@ -7965,7 +8185,7 @@ async function getFileTrace(filePath, limit = 8) {
7965
8185
  function formatFileTrace(entries, filePath) {
7966
8186
  if (entries.length === 0) return "";
7967
8187
  const lines = [
7968
- `\u{1F570}\uFE0F **Why is ${path19.basename(filePath)} written this way?** \u2014 ${entries.length} change(s) recorded:`
8188
+ `\u{1F570}\uFE0F **Why is ${path20.basename(filePath)} written this way?** \u2014 ${entries.length} change(s) recorded:`
7969
8189
  ];
7970
8190
  for (const e of entries) {
7971
8191
  const date = new Date((e.createdAt || 0) * 1e3).toLocaleDateString("en-US", {
@@ -7981,12 +8201,12 @@ function formatFileTrace(entries, filePath) {
7981
8201
  async function getDecisionsForFile(filePath, limit = 3) {
7982
8202
  const decisions = [];
7983
8203
  const root = getProjectRoot();
7984
- const base = path19.basename(filePath);
8204
+ const base = path20.basename(filePath);
7985
8205
  const baseWithoutExt = base.replace(/\.[^.]+$/, "");
7986
8206
  try {
7987
- const decisionsMdPath = path19.join(root, ".kuma", "memories", "decisions.md");
7988
- if (fs16.existsSync(decisionsMdPath)) {
7989
- const content = fs16.readFileSync(decisionsMdPath, "utf-8");
8207
+ const decisionsMdPath = path20.join(root, ".kuma", "memories", "decisions.md");
8208
+ if (fs17.existsSync(decisionsMdPath)) {
8209
+ const content = fs17.readFileSync(decisionsMdPath, "utf-8");
7990
8210
  const sections = content.split(/^##\s+/m);
7991
8211
  for (const section of sections) {
7992
8212
  if (!section.trim() || section.startsWith("# ")) continue;
@@ -8091,13 +8311,13 @@ async function getRelevantContext(filePath, goal) {
8091
8311
  if (traceStr) parts.push(traceStr);
8092
8312
  try {
8093
8313
  const root = getProjectRoot();
8094
- if (fs16.existsSync(path19.join(root, ".kuma", "kuma.db"))) {
8314
+ if (fs17.existsSync(path20.join(root, ".kuma", "kuma.db"))) {
8095
8315
  const { getDb: getDb2 } = await Promise.resolve().then(() => (init_kumaDb(), kumaDb_exports));
8096
8316
  const db = await getDb2();
8097
8317
  const stmt = db.prepare(
8098
8318
  `SELECT COUNT(*) FROM known_gotchas WHERE status = 'resolved' AND file_path LIKE ?`
8099
8319
  );
8100
- stmt.bind([`%${path19.basename(filePath)}%`]);
8320
+ stmt.bind([`%${path20.basename(filePath)}%`]);
8101
8321
  const found = stmt.step();
8102
8322
  const count = found ? Number(stmt.getAsObject()["COUNT(*)"]) : 0;
8103
8323
  stmt.free();
@@ -8108,7 +8328,7 @@ async function getRelevantContext(filePath, goal) {
8108
8328
  } catch {
8109
8329
  }
8110
8330
  if (gotchas.length > 0) {
8111
- const scopeHint = path19.basename(path19.dirname(filePath)) || "current change";
8331
+ const scopeHint = path20.basename(path20.dirname(filePath)) || "current change";
8112
8332
  parts.push(
8113
8333
  `\u2705 AFTER editing, verify: kuma_safety({ action: "verify", scope: "${scopeHint}" })`
8114
8334
  );
@@ -8124,11 +8344,11 @@ async function getRelevantContext(filePath, goal) {
8124
8344
  async function getFileSummary2(filePath) {
8125
8345
  try {
8126
8346
  const root = getProjectRoot();
8127
- const dbFile = path19.join(root, ".kuma", "kuma.db");
8128
- if (!fs16.existsSync(dbFile)) return null;
8347
+ const dbFile = path20.join(root, ".kuma", "kuma.db");
8348
+ if (!fs17.existsSync(dbFile)) return null;
8129
8349
  const { getDb: getDb2 } = await Promise.resolve().then(() => (init_kumaDb(), kumaDb_exports));
8130
8350
  const db = await getDb2();
8131
- const base = path19.basename(filePath);
8351
+ const base = path20.basename(filePath);
8132
8352
  const stmt = db.prepare(`
8133
8353
  SELECT
8134
8354
  (SELECT COUNT(*) FROM known_gotchas WHERE status = 'active' AND (file_path = ? OR file_path LIKE ?)) as active_gotchas,
@@ -8220,9 +8440,9 @@ async function getCommandContext(command) {
8220
8440
  }
8221
8441
  function loadHookState(root) {
8222
8442
  try {
8223
- const fp = path19.join(root, HOOK_STATE_FILE);
8224
- if (fs16.existsSync(fp)) {
8225
- return JSON.parse(fs16.readFileSync(fp, "utf-8"));
8443
+ const fp = path20.join(root, HOOK_STATE_FILE);
8444
+ if (fs17.existsSync(fp)) {
8445
+ return JSON.parse(fs17.readFileSync(fp, "utf-8"));
8226
8446
  }
8227
8447
  } catch {
8228
8448
  }
@@ -8230,10 +8450,10 @@ function loadHookState(root) {
8230
8450
  }
8231
8451
  function saveHookState(root, state) {
8232
8452
  try {
8233
- const fp = path19.join(root, HOOK_STATE_FILE);
8234
- const dir = path19.dirname(fp);
8235
- if (!fs16.existsSync(dir)) fs16.mkdirSync(dir, { recursive: true });
8236
- fs16.writeFileSync(fp, JSON.stringify(state), "utf-8");
8453
+ const fp = path20.join(root, HOOK_STATE_FILE);
8454
+ const dir = path20.dirname(fp);
8455
+ if (!fs17.existsSync(dir)) fs17.mkdirSync(dir, { recursive: true });
8456
+ fs17.writeFileSync(fp, JSON.stringify(state), "utf-8");
8237
8457
  } catch {
8238
8458
  }
8239
8459
  }
@@ -8267,7 +8487,7 @@ async function trackFileEditLoop(filePath) {
8267
8487
  saveHookState(root, state);
8268
8488
  if (recorded) {
8269
8489
  try {
8270
- if (!fs16.existsSync(path19.join(root, ".kuma", "kuma.db"))) return entry.count;
8490
+ if (!fs17.existsSync(path20.join(root, ".kuma", "kuma.db"))) return entry.count;
8271
8491
  const { addGotcha: addGotcha2 } = await Promise.resolve().then(() => (init_kumaGotchas(), kumaGotchas_exports));
8272
8492
  await addGotcha2({
8273
8493
  filePath,
@@ -8321,8 +8541,8 @@ __export(kumaGotchas_exports, {
8321
8541
  syncGotchasToDb: () => syncGotchasToDb,
8322
8542
  tokenizeForSimilarity: () => tokenizeForSimilarity
8323
8543
  });
8324
- import fs17 from "fs";
8325
- import path20 from "path";
8544
+ import fs18 from "fs";
8545
+ import path21 from "path";
8326
8546
  async function ensureGotchasSchema() {
8327
8547
  const db = await getDb();
8328
8548
  db.exec(`
@@ -8744,8 +8964,8 @@ async function getActiveGotchasForCommand(command) {
8744
8964
  }
8745
8965
  async function recordInjection(params) {
8746
8966
  try {
8747
- const fp = path20.join(getProjectRoot(), ".kuma", "injections.jsonl");
8748
- if (!fs17.existsSync(path20.dirname(fp))) fs17.mkdirSync(path20.dirname(fp), { recursive: true });
8967
+ const fp = path21.join(getProjectRoot(), ".kuma", "injections.jsonl");
8968
+ if (!fs18.existsSync(path21.dirname(fp))) fs18.mkdirSync(path21.dirname(fp), { recursive: true });
8749
8969
  const line = JSON.stringify({
8750
8970
  filePath: params.filePath || null,
8751
8971
  command: params.command || null,
@@ -8754,16 +8974,16 @@ async function recordInjection(params) {
8754
8974
  // conservative estimate: avoided re-research / re-discovery
8755
8975
  at: Date.now()
8756
8976
  });
8757
- fs17.appendFileSync(fp, line + "\n", "utf-8");
8977
+ fs18.appendFileSync(fp, line + "\n", "utf-8");
8758
8978
  } catch {
8759
8979
  }
8760
8980
  }
8761
8981
  function getInjectionStats(hours = 24) {
8762
8982
  try {
8763
- const fp = path20.join(getProjectRoot(), ".kuma", "injections.jsonl");
8764
- if (!fs17.existsSync(fp)) return { count: 0, savedMs: 0 };
8983
+ const fp = path21.join(getProjectRoot(), ".kuma", "injections.jsonl");
8984
+ if (!fs18.existsSync(fp)) return { count: 0, savedMs: 0 };
8765
8985
  const cutoff = Date.now() - hours * 60 * 60 * 1e3;
8766
- const lines = fs17.readFileSync(fp, "utf-8").split("\n");
8986
+ const lines = fs18.readFileSync(fp, "utf-8").split("\n");
8767
8987
  let count = 0;
8768
8988
  let savedMs = 0;
8769
8989
  for (const line of lines) {
@@ -8821,9 +9041,9 @@ async function getGotchasByStatus(status, limit = 20) {
8821
9041
  }
8822
9042
  function syncGotchaStatusToMarkdown(targetPaths, newStatus, reason) {
8823
9043
  try {
8824
- const mdPath = path20.join(getProjectRoot(), ".kuma", "KNOWN_GOTCHAS.md");
8825
- if (!fs17.existsSync(mdPath)) return false;
8826
- const content = fs17.readFileSync(mdPath, "utf-8");
9044
+ const mdPath = path21.join(getProjectRoot(), ".kuma", "KNOWN_GOTCHAS.md");
9045
+ if (!fs18.existsSync(mdPath)) return false;
9046
+ const content = fs18.readFileSync(mdPath, "utf-8");
8827
9047
  const lines = content.split("\n");
8828
9048
  const normalizedTargets = targetPaths.map((p) => p.trim().toLowerCase()).filter(Boolean);
8829
9049
  if (normalizedTargets.length === 0) return false;
@@ -8840,9 +9060,9 @@ function syncGotchaStatusToMarkdown(targetPaths, newStatus, reason) {
8840
9060
  modified = true;
8841
9061
  }
8842
9062
  const headingFile = headingMatch[1].trim().toLowerCase();
8843
- const headingBase = path20.basename(headingFile);
9063
+ const headingBase = path21.basename(headingFile);
8844
9064
  inMatchingSection = normalizedTargets.some(
8845
- (t) => headingFile.includes(t) || t.includes(headingFile) || headingBase === t || headingBase === path20.basename(t)
9065
+ (t) => headingFile.includes(t) || t.includes(headingFile) || headingBase === t || headingBase === path21.basename(t)
8846
9066
  );
8847
9067
  sectionHasStatus = false;
8848
9068
  outputLines.push(line);
@@ -8864,7 +9084,7 @@ function syncGotchaStatusToMarkdown(targetPaths, newStatus, reason) {
8864
9084
  modified = true;
8865
9085
  }
8866
9086
  if (modified) {
8867
- fs17.writeFileSync(mdPath, outputLines.join("\n"), "utf-8");
9087
+ fs18.writeFileSync(mdPath, outputLines.join("\n"), "utf-8");
8868
9088
  }
8869
9089
  return modified;
8870
9090
  } catch {
@@ -9005,24 +9225,24 @@ var kumaMaintenance_exports = {};
9005
9225
  __export(kumaMaintenance_exports, {
9006
9226
  maybeRunAutoCleanup: () => maybeRunAutoCleanup
9007
9227
  });
9008
- import fs18 from "fs";
9009
- import path21 from "path";
9228
+ import fs19 from "fs";
9229
+ import path22 from "path";
9010
9230
  async function maybeRunAutoCleanup() {
9011
9231
  try {
9012
9232
  const root = getProjectRoot();
9013
- const stateFile = path21.join(root, GC_STATE_FILE);
9233
+ const stateFile = path22.join(root, GC_STATE_FILE);
9014
9234
  const now = Date.now();
9015
9235
  let lastRun = 0;
9016
- if (fs18.existsSync(stateFile)) {
9236
+ if (fs19.existsSync(stateFile)) {
9017
9237
  try {
9018
- lastRun = JSON.parse(fs18.readFileSync(stateFile, "utf-8")).lastRun || 0;
9238
+ lastRun = JSON.parse(fs19.readFileSync(stateFile, "utf-8")).lastRun || 0;
9019
9239
  } catch {
9020
9240
  lastRun = 0;
9021
9241
  }
9022
9242
  }
9023
9243
  if (now - lastRun < GC_INTERVAL_MS) return "";
9024
- fs18.mkdirSync(path21.dirname(stateFile), { recursive: true });
9025
- fs18.writeFileSync(stateFile, JSON.stringify({ lastRun: now }), "utf-8");
9244
+ fs19.mkdirSync(path22.dirname(stateFile), { recursive: true });
9245
+ fs19.writeFileSync(stateFile, JSON.stringify({ lastRun: now }), "utf-8");
9026
9246
  const { syncGotchasToDb: syncGotchasToDb2 } = await Promise.resolve().then(() => (init_kumaGotchas(), kumaGotchas_exports));
9027
9247
  await syncGotchasToDb2();
9028
9248
  const { runGarbageCollection: runGarbageCollection2 } = await Promise.resolve().then(() => (init_kumaDb(), kumaDb_exports));
@@ -9058,22 +9278,22 @@ __export(kumaPathRules_exports, {
9058
9278
  loadPathRules: () => loadPathRules,
9059
9279
  matchRulePath: () => matchRulePath
9060
9280
  });
9061
- import fs19 from "fs";
9062
- import path22 from "path";
9281
+ import fs20 from "fs";
9282
+ import path23 from "path";
9063
9283
  function rulesDir() {
9064
- return path22.join(getProjectRoot(), RULES_DIR);
9284
+ return path23.join(getProjectRoot(), RULES_DIR);
9065
9285
  }
9066
9286
  function ensureRulesDir() {
9067
9287
  try {
9068
9288
  const dir = rulesDir();
9069
- if (!fs19.existsSync(dir)) fs19.mkdirSync(dir, { recursive: true });
9289
+ if (!fs20.existsSync(dir)) fs20.mkdirSync(dir, { recursive: true });
9070
9290
  } catch {
9071
9291
  }
9072
9292
  }
9073
9293
  function parseRuleFile(filePath) {
9074
9294
  try {
9075
- const raw = fs19.readFileSync(filePath, "utf-8");
9076
- const id = path22.basename(filePath, ".md");
9295
+ const raw = fs20.readFileSync(filePath, "utf-8");
9296
+ const id = path23.basename(filePath, ".md");
9077
9297
  const fm = raw.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/);
9078
9298
  if (!fm) {
9079
9299
  return { id, description: id, paths: ["*"], content: raw.trim(), filePath };
@@ -9098,7 +9318,7 @@ function loadPathRules() {
9098
9318
  ensureRulesDir();
9099
9319
  try {
9100
9320
  const dir = rulesDir();
9101
- return fs19.readdirSync(dir).filter((f) => f.endsWith(".md")).map((f) => parseRuleFile(path22.join(dir, f))).filter((r) => r !== null);
9321
+ return fs20.readdirSync(dir).filter((f) => f.endsWith(".md")).map((f) => parseRuleFile(path23.join(dir, f))).filter((r) => r !== null);
9102
9322
  } catch {
9103
9323
  return [];
9104
9324
  }
@@ -9186,8 +9406,8 @@ __export(kumaFlowCache_exports, {
9186
9406
  getFreshDomainFlow: () => getFreshDomainFlow,
9187
9407
  getHopsForDomain: () => getHopsForDomain
9188
9408
  });
9189
- import fs20 from "fs";
9190
- import path23 from "path";
9409
+ import fs21 from "fs";
9410
+ import path24 from "path";
9191
9411
  async function getFlowFreshness(domain) {
9192
9412
  try {
9193
9413
  const { getDb: getDb2 } = await Promise.resolve().then(() => (init_kumaDb(), kumaDb_exports));
@@ -9222,26 +9442,26 @@ async function getFlowFreshness(domain) {
9222
9442
  }
9223
9443
  function resolveImport(fromFile, spec) {
9224
9444
  const root = getProjectRoot();
9225
- const fromDir = path23.dirname(fromFile);
9445
+ const fromDir = path24.dirname(fromFile);
9226
9446
  const candidates = [];
9227
9447
  if (spec.startsWith(".")) {
9228
- const abs = path23.resolve(fromDir, spec);
9448
+ const abs = path24.resolve(fromDir, spec);
9229
9449
  candidates.push(abs);
9230
9450
  } else {
9231
- candidates.push(path23.join(root, spec));
9451
+ candidates.push(path24.join(root, spec));
9232
9452
  }
9233
9453
  for (const c of candidates) {
9234
9454
  for (const ext of SOURCE_EXTENSIONS) {
9235
9455
  const withExt = `${c}${ext}`;
9236
- if (fs20.existsSync(withExt)) return path23.relative(root, withExt);
9237
- if (fs20.existsSync(c) && fs20.statSync(c).isDirectory()) {
9238
- const idx = path23.join(c, "index") + ext;
9239
- if (fs20.existsSync(idx)) return path23.relative(root, idx);
9456
+ if (fs21.existsSync(withExt)) return path24.relative(root, withExt);
9457
+ if (fs21.existsSync(c) && fs21.statSync(c).isDirectory()) {
9458
+ const idx = path24.join(c, "index") + ext;
9459
+ if (fs21.existsSync(idx)) return path24.relative(root, idx);
9240
9460
  }
9241
9461
  }
9242
- if (fs20.existsSync(c)) {
9462
+ if (fs21.existsSync(c)) {
9243
9463
  try {
9244
- if (fs20.statSync(c).isFile()) return path23.relative(root, c);
9464
+ if (fs21.statSync(c).isFile()) return path24.relative(root, c);
9245
9465
  } catch {
9246
9466
  }
9247
9467
  }
@@ -9250,13 +9470,13 @@ function resolveImport(fromFile, spec) {
9250
9470
  }
9251
9471
  function deriveHopsFromImports(entryFile, maxHops = 6) {
9252
9472
  const root = getProjectRoot();
9253
- const absEntry = path23.isAbsolute(entryFile) ? entryFile : path23.resolve(root, entryFile);
9254
- if (!fs20.existsSync(absEntry)) return [];
9473
+ const absEntry = path24.isAbsolute(entryFile) ? entryFile : path24.resolve(root, entryFile);
9474
+ if (!fs21.existsSync(absEntry)) return [];
9255
9475
  const hops = [];
9256
9476
  const seen = /* @__PURE__ */ new Set([entryFile]);
9257
- const fromName = path23.basename(absEntry);
9477
+ const fromName = path24.basename(absEntry);
9258
9478
  try {
9259
- const lines = fs20.readFileSync(absEntry, "utf-8").split("\n");
9479
+ const lines = fs21.readFileSync(absEntry, "utf-8").split("\n");
9260
9480
  for (const line of lines) {
9261
9481
  if (hops.length >= maxHops) break;
9262
9482
  const spec = matchImportPath(line);
@@ -9266,9 +9486,9 @@ function deriveHopsFromImports(entryFile, maxHops = 6) {
9266
9486
  seen.add(resolved);
9267
9487
  hops.push({
9268
9488
  from: fromName,
9269
- to: path23.basename(resolved),
9489
+ to: path24.basename(resolved),
9270
9490
  relation: "imports",
9271
- description: `${fromName} imports ${path23.basename(resolved)}`
9491
+ description: `${fromName} imports ${path24.basename(resolved)}`
9272
9492
  });
9273
9493
  }
9274
9494
  } catch {
@@ -9331,9 +9551,9 @@ async function getHopsForDomain(domain) {
9331
9551
  }
9332
9552
  try {
9333
9553
  const root = getProjectRoot();
9334
- const archPath = path23.join(root, ".kuma", "ARCHITECTURE_FLOW.md");
9335
- if (fs20.existsSync(archPath)) {
9336
- const content = fs20.readFileSync(archPath, "utf-8");
9554
+ const archPath = path24.join(root, ".kuma", "ARCHITECTURE_FLOW.md");
9555
+ if (fs21.existsSync(archPath)) {
9556
+ const content = fs21.readFileSync(archPath, "utf-8");
9337
9557
  const lines = content.split("\n");
9338
9558
  for (const line of lines) {
9339
9559
  const domMatch = line.match(new RegExp(`domain:\\s*${escapeRegex(domain)}\\s*\\|\\s*hops:\\s*(.+)`, "i"));
@@ -9378,7 +9598,7 @@ Record one with kuma_memory({ action: 'arch_flow', content: 'domain: ${domain} |
9378
9598
  hops: derivedHops,
9379
9599
  filePaths: freshness.filePaths
9380
9600
  });
9381
- lines.push(`\u2705 Re-derived ${derivedHops.length} hop(s) from ${path23.basename(entry)} \u2014 cache refreshed.`);
9601
+ lines.push(`\u2705 Re-derived ${derivedHops.length} hop(s) from ${path24.basename(entry)} \u2014 cache refreshed.`);
9382
9602
  hops.splice(0, hops.length, ...derivedHops);
9383
9603
  } else {
9384
9604
  lines.push("\u26A0\uFE0F No imports to follow \u2014 cache left as-is (record hops manually if needed).");
@@ -9431,10 +9651,10 @@ __export(packageBriefs_exports, {
9431
9651
  readBrief: () => readBrief,
9432
9652
  refreshPackageBriefs: () => refreshPackageBriefs
9433
9653
  });
9434
- import fs21 from "fs";
9435
- import path24 from "path";
9654
+ import fs22 from "fs";
9655
+ import path25 from "path";
9436
9656
  function briefsDir(root) {
9437
- return path24.join(root || getProjectRoot(), BRIEFS_DIR);
9657
+ return path25.join(root || getProjectRoot(), BRIEFS_DIR);
9438
9658
  }
9439
9659
  function slug(name) {
9440
9660
  return name.replace(/[^a-zA-Z0-9_-]/g, "_").slice(0, 60) || "root";
@@ -9498,13 +9718,13 @@ async function refreshPackageBriefs() {
9498
9718
  const dir = briefsDir(root);
9499
9719
  try {
9500
9720
  const ws = await getWorkspaceInfo(root);
9501
- if (!fs21.existsSync(dir)) fs21.mkdirSync(dir, { recursive: true });
9721
+ if (!fs22.existsSync(dir)) fs22.mkdirSync(dir, { recursive: true });
9502
9722
  let count = 0;
9503
9723
  const pkgs = ws.isWorkspace ? ws.packages : [{ name: "root", path: ".", isRoot: true }];
9504
9724
  for (const p of pkgs.slice(0, 20)) {
9505
9725
  const pkg = p;
9506
9726
  const content = await buildPackageBrief(pkg.name, pkg.path, root);
9507
- fs21.writeFileSync(path24.join(dir, `${slug(pkg.name)}.md`), content, "utf-8");
9727
+ fs22.writeFileSync(path25.join(dir, `${slug(pkg.name)}.md`), content, "utf-8");
9508
9728
  count++;
9509
9729
  }
9510
9730
  return { count, dir };
@@ -9514,9 +9734,9 @@ async function refreshPackageBriefs() {
9514
9734
  }
9515
9735
  function briefFreshness(pkgName) {
9516
9736
  try {
9517
- const fp = path24.join(briefsDir(), `${slug(pkgName)}.md`);
9518
- if (!fs21.existsSync(fp)) return { exists: false, fresh: false, age: "missing" };
9519
- const ageMs = Date.now() - fs21.statSync(fp).mtimeMs;
9737
+ const fp = path25.join(briefsDir(), `${slug(pkgName)}.md`);
9738
+ if (!fs22.existsSync(fp)) return { exists: false, fresh: false, age: "missing" };
9739
+ const ageMs = Date.now() - fs22.statSync(fp).mtimeMs;
9520
9740
  return { exists: true, fresh: !isStale(Date.now() - ageMs, MAP_TTL_MS), age: formatAge(Date.now() - ageMs) };
9521
9741
  } catch {
9522
9742
  return { exists: false, fresh: false, age: "missing" };
@@ -9524,9 +9744,9 @@ function briefFreshness(pkgName) {
9524
9744
  }
9525
9745
  function readBrief(pkgName, maxChars = 1200) {
9526
9746
  try {
9527
- const fp = path24.join(briefsDir(), `${slug(pkgName)}.md`);
9528
- if (!fs21.existsSync(fp)) return null;
9529
- const content = fs21.readFileSync(fp, "utf-8");
9747
+ const fp = path25.join(briefsDir(), `${slug(pkgName)}.md`);
9748
+ if (!fs22.existsSync(fp)) return null;
9749
+ const content = fs22.readFileSync(fp, "utf-8");
9530
9750
  return content.length > maxChars ? content.slice(0, maxChars) + "\n\u2026(truncated)" : content;
9531
9751
  } catch {
9532
9752
  return null;
@@ -9555,8 +9775,8 @@ __export(kumaSearch_exports, {
9555
9775
  formatHybridResults: () => formatHybridResults,
9556
9776
  hybridSearch: () => hybridSearch
9557
9777
  });
9558
- import fs23 from "fs";
9559
- import path26 from "path";
9778
+ import fs24 from "fs";
9779
+ import path27 from "path";
9560
9780
  function expandQueryTerms(query) {
9561
9781
  const terms = query.toLowerCase().split(/[\s_-]+/).filter((t) => t.length > 2);
9562
9782
  const expanded = /* @__PURE__ */ new Map();
@@ -9619,13 +9839,13 @@ async function buildSearchVectors() {
9619
9839
  }
9620
9840
  try {
9621
9841
  const root = getProjectRoot();
9622
- const memDir = path26.join(root, ".kuma", "memories");
9623
- if (fs23.existsSync(memDir)) {
9624
- const files = fs23.readdirSync(memDir).filter((f) => f.endsWith(".md")).slice(0, SCALE_LIMITS.maxMemoryFiles);
9842
+ const memDir = path27.join(root, ".kuma", "memories");
9843
+ if (fs24.existsSync(memDir)) {
9844
+ const files = fs24.readdirSync(memDir).filter((f) => f.endsWith(".md")).slice(0, SCALE_LIMITS.maxMemoryFiles);
9625
9845
  for (const file of files) {
9626
9846
  try {
9627
- const fullPath = path26.join(memDir, file);
9628
- const content = fs23.readFileSync(fullPath, "utf-8");
9847
+ const fullPath = path27.join(memDir, file);
9848
+ const content = fs24.readFileSync(fullPath, "utf-8");
9629
9849
  const text = content.toLowerCase();
9630
9850
  const rawTerms = extractTerms(text);
9631
9851
  const termCounts = /* @__PURE__ */ new Map();
@@ -9636,7 +9856,7 @@ async function buildSearchVectors() {
9636
9856
  terms: termCounts,
9637
9857
  source: file.replace(/\.md$/, ""),
9638
9858
  sourceType: "memory",
9639
- recency: recencyScore(Math.floor(fs23.statSync(fullPath).mtimeMs / 1e3))
9859
+ recency: recencyScore(Math.floor(fs24.statSync(fullPath).mtimeMs / 1e3))
9640
9860
  });
9641
9861
  } catch {
9642
9862
  }
@@ -9953,14 +10173,14 @@ __export(architectureGuard_exports, {
9953
10173
  detectWorkspaceCircularDeps: () => detectWorkspaceCircularDeps,
9954
10174
  loadArchitectureRules: () => loadArchitectureRules
9955
10175
  });
9956
- import fs27 from "fs";
9957
- import path30 from "path";
9958
- import fastGlob4 from "fast-glob";
10176
+ import fs28 from "fs";
10177
+ import path31 from "path";
10178
+ import fastGlob5 from "fast-glob";
9959
10179
  function loadArchitectureRules(root) {
9960
- const rulesPath = path30.join(root, ".kuma", "architecture.json");
9961
- if (fs27.existsSync(rulesPath)) {
10180
+ const rulesPath = path31.join(root, ".kuma", "architecture.json");
10181
+ if (fs28.existsSync(rulesPath)) {
9962
10182
  try {
9963
- const data = JSON.parse(fs27.readFileSync(rulesPath, "utf-8"));
10183
+ const data = JSON.parse(fs28.readFileSync(rulesPath, "utf-8"));
9964
10184
  if (Array.isArray(data.rules)) {
9965
10185
  return data.rules;
9966
10186
  }
@@ -10013,7 +10233,7 @@ async function checkArchitectureBoundaries(filesToCheck, customRoot) {
10013
10233
  }
10014
10234
  let targetFiles = filesToCheck;
10015
10235
  if (!targetFiles || targetFiles.length === 0) {
10016
- targetFiles = await fastGlob4(["**/*.{ts,tsx,js,jsx,mjs,cjs}"], {
10236
+ targetFiles = await fastGlob5(["**/*.{ts,tsx,js,jsx,mjs,cjs}"], {
10017
10237
  cwd: root,
10018
10238
  ignore: ["**/node_modules/**", "**/dist/**", "**/build/**", "**/.git/**", "**/.kuma/**"],
10019
10239
  onlyFiles: true
@@ -10022,11 +10242,11 @@ async function checkArchitectureBoundaries(filesToCheck, customRoot) {
10022
10242
  const customRules = loadArchitectureRules(root);
10023
10243
  const importRegex = /(?:import|export\s+.*from|require\s*\()\s*['"]([^'"]+)['"]/g;
10024
10244
  for (const file of targetFiles) {
10025
- const fullPath = path30.isAbsolute(file) ? file : path30.join(root, file);
10026
- if (!fs27.existsSync(fullPath)) continue;
10245
+ const fullPath = path31.isAbsolute(file) ? file : path31.join(root, file);
10246
+ if (!fs28.existsSync(fullPath)) continue;
10027
10247
  let content = "";
10028
10248
  try {
10029
- content = fs27.readFileSync(fullPath, "utf-8");
10249
+ content = fs28.readFileSync(fullPath, "utf-8");
10030
10250
  } catch {
10031
10251
  continue;
10032
10252
  }
@@ -10036,7 +10256,7 @@ async function checkArchitectureBoundaries(filesToCheck, customRoot) {
10036
10256
  const importPath = match[1];
10037
10257
  if (wsInfo.isWorkspace && currentPkg && !currentPkg.isRoot) {
10038
10258
  if (importPath.startsWith("../") && (importPath.includes("/src/") || importPath.includes("/dist/"))) {
10039
- const resolvedTarget = path30.normalize(path30.resolve(path30.dirname(fullPath), importPath));
10259
+ const resolvedTarget = path31.normalize(path31.resolve(path31.dirname(fullPath), importPath));
10040
10260
  const targetPkg = findPackageForFile(resolvedTarget, wsInfo);
10041
10261
  if (targetPkg && targetPkg.name !== currentPkg.name) {
10042
10262
  violations.push({
@@ -10085,26 +10305,26 @@ __export(docDrift_exports, {
10085
10305
  formatDocDrift: () => formatDocDrift,
10086
10306
  scanDocDrift: () => scanDocDrift
10087
10307
  });
10088
- import fs28 from "fs";
10089
- import path31 from "path";
10308
+ import fs29 from "fs";
10309
+ import path32 from "path";
10090
10310
  import { execSync as execSync9 } from "child_process";
10091
10311
  function collectDocFiles(root) {
10092
10312
  const cwd = root || getProjectRoot();
10093
10313
  const out = [];
10094
10314
  const pushIfMd = (dir, rel) => {
10095
10315
  try {
10096
- for (const f of fs28.readdirSync(dir)) {
10316
+ for (const f of fs29.readdirSync(dir)) {
10097
10317
  if (out.length >= MAX_DOCS) return;
10098
- const full = path31.join(dir, f);
10318
+ const full = path32.join(dir, f);
10099
10319
  try {
10100
- if (fs28.statSync(full).isFile() && /\.md$/i.test(f)) out.push(rel(f));
10320
+ if (fs29.statSync(full).isFile() && /\.md$/i.test(f)) out.push(rel(f));
10101
10321
  } catch {
10102
10322
  }
10103
10323
  }
10104
10324
  } catch {
10105
10325
  }
10106
10326
  };
10107
- pushIfMd(path31.join(cwd, "docs"), (f) => path31.join("docs", f));
10327
+ pushIfMd(path32.join(cwd, "docs"), (f) => path32.join("docs", f));
10108
10328
  pushIfMd(cwd, (f) => f);
10109
10329
  return out;
10110
10330
  }
@@ -10166,7 +10386,7 @@ function scanDocDrift(root) {
10166
10386
  let claims = [];
10167
10387
  for (const rel of collectDocFiles(cwd)) {
10168
10388
  try {
10169
- const content = fs28.readFileSync(path31.join(cwd, rel), "utf-8");
10389
+ const content = fs29.readFileSync(path32.join(cwd, rel), "utf-8");
10170
10390
  if (isExemptDoc(rel, content)) {
10171
10391
  skipped.push(rel);
10172
10392
  continue;
@@ -10337,16 +10557,16 @@ __export(kumaCheckpoint_exports, {
10337
10557
  pruneCheckpoints: () => pruneCheckpoints,
10338
10558
  rollbackToCheckpoint: () => rollbackToCheckpoint
10339
10559
  });
10340
- import fs29 from "fs";
10341
- import path32 from "path";
10560
+ import fs30 from "fs";
10561
+ import path33 from "path";
10342
10562
  async function createCheckpoint(label, description) {
10343
10563
  try {
10344
10564
  const root = getProjectRoot();
10345
- const cpDir = path32.join(root, CHECKPOINT_DIR, sanitizeLabel(label));
10346
- if (fs29.existsSync(cpDir)) {
10565
+ const cpDir = path33.join(root, CHECKPOINT_DIR, sanitizeLabel(label));
10566
+ if (fs30.existsSync(cpDir)) {
10347
10567
  return `\u26A0\uFE0F Checkpoint "${label}" already exists. Use a different label or remove it first.`;
10348
10568
  }
10349
- fs29.mkdirSync(cpDir, { recursive: true });
10569
+ fs30.mkdirSync(cpDir, { recursive: true });
10350
10570
  let gitHead;
10351
10571
  let isGitClean = false;
10352
10572
  try {
@@ -10412,15 +10632,15 @@ async function createCheckpoint(label, description) {
10412
10632
  }
10413
10633
  const files = [];
10414
10634
  for (const fp of candidatePaths) {
10415
- const fullPath = path32.resolve(root, fp);
10635
+ const fullPath = path33.resolve(root, fp);
10416
10636
  try {
10417
- if (fs29.existsSync(fullPath) && fs29.statSync(fullPath).isFile()) {
10418
- const content = fs29.readFileSync(fullPath, "utf-8");
10637
+ if (fs30.existsSync(fullPath) && fs30.statSync(fullPath).isFile()) {
10638
+ const content = fs30.readFileSync(fullPath, "utf-8");
10419
10639
  const hash = simpleHash2(content);
10420
- const snapFile = path32.join(cpDir, "files", `${fp}.kuma-snap`);
10421
- const fileDir = path32.dirname(snapFile);
10422
- if (!fs29.existsSync(fileDir)) fs29.mkdirSync(fileDir, { recursive: true });
10423
- fs29.writeFileSync(snapFile, content, "utf-8");
10640
+ const snapFile = path33.join(cpDir, "files", `${fp}.kuma-snap`);
10641
+ const fileDir = path33.dirname(snapFile);
10642
+ if (!fs30.existsSync(fileDir)) fs30.mkdirSync(fileDir, { recursive: true });
10643
+ fs30.writeFileSync(snapFile, content, "utf-8");
10424
10644
  files.push({ path: fp, hash });
10425
10645
  }
10426
10646
  } catch {
@@ -10428,7 +10648,7 @@ async function createCheckpoint(label, description) {
10428
10648
  }
10429
10649
  const db = await getDb();
10430
10650
  const dbData = db.export();
10431
- fs29.writeFileSync(path32.join(cpDir, "kuma.db"), Buffer.from(dbData));
10651
+ fs30.writeFileSync(path33.join(cpDir, "kuma.db"), Buffer.from(dbData));
10432
10652
  const manifest = {
10433
10653
  label,
10434
10654
  timestamp: Date.now(),
@@ -10438,8 +10658,8 @@ async function createCheckpoint(label, description) {
10438
10658
  dbSnapshot: true,
10439
10659
  description
10440
10660
  };
10441
- fs29.writeFileSync(
10442
- path32.join(cpDir, "manifest.json"),
10661
+ fs30.writeFileSync(
10662
+ path33.join(cpDir, "manifest.json"),
10443
10663
  JSON.stringify(manifest, null, 2),
10444
10664
  "utf-8"
10445
10665
  );
@@ -10467,29 +10687,29 @@ async function createCheckpoint(label, description) {
10467
10687
  async function rollbackToCheckpoint(label) {
10468
10688
  try {
10469
10689
  const root = getProjectRoot();
10470
- const cpDir = path32.join(root, CHECKPOINT_DIR, sanitizeLabel(label));
10471
- const manifestPath = path32.join(cpDir, "manifest.json");
10472
- if (!fs29.existsSync(manifestPath)) {
10690
+ const cpDir = path33.join(root, CHECKPOINT_DIR, sanitizeLabel(label));
10691
+ const manifestPath = path33.join(cpDir, "manifest.json");
10692
+ if (!fs30.existsSync(manifestPath)) {
10473
10693
  return `\u274C Checkpoint "${label}" not found. Available checkpoints:
10474
10694
 
10475
10695
  ${listCheckpoints()}`;
10476
10696
  }
10477
10697
  const manifest = JSON.parse(
10478
- fs29.readFileSync(manifestPath, "utf-8")
10698
+ fs30.readFileSync(manifestPath, "utf-8")
10479
10699
  );
10480
10700
  let restored = 0;
10481
10701
  let failed = 0;
10482
10702
  for (const f of manifest.files) {
10483
- const snapPath = path32.join(cpDir, "files", `${f.path}.kuma-snap`);
10484
- const legacyPath = path32.join(cpDir, "files", f.path);
10485
- const sourcePath = fs29.existsSync(snapPath) ? snapPath : legacyPath;
10486
- if (fs29.existsSync(sourcePath)) {
10703
+ const snapPath = path33.join(cpDir, "files", `${f.path}.kuma-snap`);
10704
+ const legacyPath = path33.join(cpDir, "files", f.path);
10705
+ const sourcePath = fs30.existsSync(snapPath) ? snapPath : legacyPath;
10706
+ if (fs30.existsSync(sourcePath)) {
10487
10707
  try {
10488
- const content = fs29.readFileSync(sourcePath, "utf-8");
10489
- const targetPath = path32.resolve(root, f.path);
10490
- const targetDir = path32.dirname(targetPath);
10491
- if (!fs29.existsSync(targetDir)) fs29.mkdirSync(targetDir, { recursive: true });
10492
- fs29.writeFileSync(targetPath, content, "utf-8");
10708
+ const content = fs30.readFileSync(sourcePath, "utf-8");
10709
+ const targetPath = path33.resolve(root, f.path);
10710
+ const targetDir = path33.dirname(targetPath);
10711
+ if (!fs30.existsSync(targetDir)) fs30.mkdirSync(targetDir, { recursive: true });
10712
+ fs30.writeFileSync(targetPath, content, "utf-8");
10493
10713
  restored++;
10494
10714
  } catch {
10495
10715
  failed++;
@@ -10510,12 +10730,12 @@ ${listCheckpoints()}`;
10510
10730
  failed++;
10511
10731
  }
10512
10732
  }
10513
- const dbSnapshotPath = path32.join(cpDir, "kuma.db");
10514
- if (fs29.existsSync(dbSnapshotPath)) {
10515
- const kumaDir = path32.join(root, ".kuma");
10516
- const dbPath = path32.join(kumaDir, "kuma.db");
10517
- const snapshotData = fs29.readFileSync(dbSnapshotPath);
10518
- fs29.writeFileSync(dbPath, snapshotData);
10733
+ const dbSnapshotPath = path33.join(cpDir, "kuma.db");
10734
+ if (fs30.existsSync(dbSnapshotPath)) {
10735
+ const kumaDir = path33.join(root, ".kuma");
10736
+ const dbPath = path33.join(kumaDir, "kuma.db");
10737
+ const snapshotData = fs30.readFileSync(dbSnapshotPath);
10738
+ fs30.writeFileSync(dbPath, snapshotData);
10519
10739
  resetDbInstance();
10520
10740
  }
10521
10741
  sessionMemory.recordToolCall("kuma_checkpoint_rollback", {
@@ -10540,18 +10760,18 @@ ${listCheckpoints()}`;
10540
10760
  function listCheckpoints() {
10541
10761
  try {
10542
10762
  const root = getProjectRoot();
10543
- const cpDir = path32.join(root, CHECKPOINT_DIR);
10544
- if (!fs29.existsSync(cpDir)) {
10763
+ const cpDir = path33.join(root, CHECKPOINT_DIR);
10764
+ if (!fs30.existsSync(cpDir)) {
10545
10765
  return "\u{1F4ED} No checkpoints found. Use kuma_safety({ action: 'checkpoint', label: 'pre-feature-x' }) to create one.";
10546
10766
  }
10547
- const entries = fs29.readdirSync(cpDir);
10767
+ const entries = fs30.readdirSync(cpDir);
10548
10768
  const checkpoints = [];
10549
10769
  for (const entry of entries) {
10550
- const manifestPath = path32.join(cpDir, entry, "manifest.json");
10551
- if (fs29.existsSync(manifestPath)) {
10770
+ const manifestPath = path33.join(cpDir, entry, "manifest.json");
10771
+ if (fs30.existsSync(manifestPath)) {
10552
10772
  try {
10553
10773
  const manifest = JSON.parse(
10554
- fs29.readFileSync(manifestPath, "utf-8")
10774
+ fs30.readFileSync(manifestPath, "utf-8")
10555
10775
  );
10556
10776
  checkpoints.push({ label: entry, manifest });
10557
10777
  } catch {
@@ -10583,12 +10803,12 @@ function listCheckpoints() {
10583
10803
  function pruneCheckpoints(keep = 5) {
10584
10804
  try {
10585
10805
  const root = getProjectRoot();
10586
- const cpDir = path32.join(root, CHECKPOINT_DIR);
10587
- if (!fs29.existsSync(cpDir)) return "\u{1F4ED} No checkpoints to prune.";
10588
- const entries = fs29.readdirSync(cpDir).map((e) => ({ name: e, time: fs29.statSync(path32.join(cpDir, e)).mtimeMs })).sort((a, b) => b.time - a.time);
10806
+ const cpDir = path33.join(root, CHECKPOINT_DIR);
10807
+ if (!fs30.existsSync(cpDir)) return "\u{1F4ED} No checkpoints to prune.";
10808
+ const entries = fs30.readdirSync(cpDir).map((e) => ({ name: e, time: fs30.statSync(path33.join(cpDir, e)).mtimeMs })).sort((a, b) => b.time - a.time);
10589
10809
  let removed = 0;
10590
10810
  for (let i = keep; i < entries.length; i++) {
10591
- fs29.rmSync(path32.join(cpDir, entries[i].name), { recursive: true, force: true });
10811
+ fs30.rmSync(path33.join(cpDir, entries[i].name), { recursive: true, force: true });
10592
10812
  removed++;
10593
10813
  }
10594
10814
  return removed > 0 ? `\u{1F9F9} Pruned **${removed} old checkpoint(s)**. Kept ${Math.min(keep, entries.length)} most recent.` : "\u2705 No checkpoints needed pruning.";
@@ -10613,9 +10833,9 @@ function isRiskyEditPath(filePath) {
10613
10833
  }
10614
10834
  function loadAutoCpDone(root) {
10615
10835
  try {
10616
- const fp = path32.join(root, AUTO_CP_STATE);
10617
- if (fs29.existsSync(fp)) {
10618
- const parsed = JSON.parse(fs29.readFileSync(fp, "utf-8"));
10836
+ const fp = path33.join(root, AUTO_CP_STATE);
10837
+ if (fs30.existsSync(fp)) {
10838
+ const parsed = JSON.parse(fs30.readFileSync(fp, "utf-8"));
10619
10839
  return parsed?.autoCheckpoints ?? {};
10620
10840
  }
10621
10841
  } catch {
@@ -10624,10 +10844,10 @@ function loadAutoCpDone(root) {
10624
10844
  }
10625
10845
  function saveAutoCpDone(root, done) {
10626
10846
  try {
10627
- const fp = path32.join(root, AUTO_CP_STATE);
10628
- const parsed = fs29.existsSync(fp) ? JSON.parse(fs29.readFileSync(fp, "utf-8")) : {};
10847
+ const fp = path33.join(root, AUTO_CP_STATE);
10848
+ const parsed = fs30.existsSync(fp) ? JSON.parse(fs30.readFileSync(fp, "utf-8")) : {};
10629
10849
  parsed.autoCheckpoints = done;
10630
- fs29.writeFileSync(fp, JSON.stringify(parsed), "utf-8");
10850
+ fs30.writeFileSync(fp, JSON.stringify(parsed), "utf-8");
10631
10851
  } catch {
10632
10852
  }
10633
10853
  }
@@ -10637,14 +10857,14 @@ function maybeAutoCheckpoint(filePath) {
10637
10857
  const root = getProjectRoot();
10638
10858
  const done = loadAutoCpDone(root);
10639
10859
  if (done[filePath]) return null;
10640
- const abs = path32.isAbsolute(filePath) ? filePath : path32.join(root, filePath);
10641
- if (!fs29.existsSync(abs) || !fs29.statSync(abs).isFile()) return null;
10642
- const label = `auto-pre-${sanitizeLabel(path32.basename(filePath))}`;
10643
- const cpDir = path32.join(root, CHECKPOINT_DIR, label);
10644
- if (!fs29.existsSync(cpDir)) fs29.mkdirSync(cpDir, { recursive: true });
10645
- fs29.copyFileSync(abs, path32.join(cpDir, path32.basename(abs)));
10646
- fs29.writeFileSync(
10647
- path32.join(cpDir, "manifest.json"),
10860
+ const abs = path33.isAbsolute(filePath) ? filePath : path33.join(root, filePath);
10861
+ if (!fs30.existsSync(abs) || !fs30.statSync(abs).isFile()) return null;
10862
+ const label = `auto-pre-${sanitizeLabel(path33.basename(filePath))}`;
10863
+ const cpDir = path33.join(root, CHECKPOINT_DIR, label);
10864
+ if (!fs30.existsSync(cpDir)) fs30.mkdirSync(cpDir, { recursive: true });
10865
+ fs30.copyFileSync(abs, path33.join(cpDir, path33.basename(abs)));
10866
+ fs30.writeFileSync(
10867
+ path33.join(cpDir, "manifest.json"),
10648
10868
  JSON.stringify({
10649
10869
  label,
10650
10870
  timestamp: Date.now(),
@@ -10684,8 +10904,8 @@ __export(init_exports, {
10684
10904
  generateInitMdContent: () => generateInitMdContent,
10685
10905
  runInit: () => runInit
10686
10906
  });
10687
- import fs30 from "fs";
10688
- import path33 from "path";
10907
+ import fs31 from "fs";
10908
+ import path34 from "path";
10689
10909
  function configFilePath(type) {
10690
10910
  switch (type) {
10691
10911
  case "claude":
@@ -11319,21 +11539,21 @@ function handleOpencodeSecondary(root, results) {
11319
11539
  "",
11320
11540
  "\u{1F4D6} Full rules: `.kuma/init.md`"
11321
11541
  ].join("\n");
11322
- const skillPath = path33.resolve(root, ".agents", "skills", "kuma", "SKILL.md");
11542
+ const skillPath = path34.resolve(root, ".agents", "skills", "kuma", "SKILL.md");
11323
11543
  if (!results.some((r) => r.filePath === ".agents/skills/kuma/SKILL.md")) {
11324
11544
  try {
11325
- const dir = path33.dirname(skillPath);
11326
- if (fs30.existsSync(skillPath)) {
11327
- const existing = fs30.readFileSync(skillPath, "utf-8");
11545
+ const dir = path34.dirname(skillPath);
11546
+ if (fs31.existsSync(skillPath)) {
11547
+ const existing = fs31.readFileSync(skillPath, "utf-8");
11328
11548
  if (existing.includes("kuma-mcp")) {
11329
11549
  results.push({ type: "opencode", filePath: ".agents/skills/kuma/SKILL.md", action: "skipped" });
11330
11550
  } else {
11331
- fs30.writeFileSync(skillPath, existing.trimEnd() + "\n\n---\n\n" + opencodeContent, "utf-8");
11551
+ fs31.writeFileSync(skillPath, existing.trimEnd() + "\n\n---\n\n" + opencodeContent, "utf-8");
11332
11552
  results.push({ type: "opencode", filePath: ".agents/skills/kuma/SKILL.md", action: "appended" });
11333
11553
  }
11334
11554
  } else {
11335
- if (!fs30.existsSync(dir)) fs30.mkdirSync(dir, { recursive: true });
11336
- fs30.writeFileSync(skillPath, opencodeContent, "utf-8");
11555
+ if (!fs31.existsSync(dir)) fs31.mkdirSync(dir, { recursive: true });
11556
+ fs31.writeFileSync(skillPath, opencodeContent, "utf-8");
11337
11557
  results.push({ type: "opencode", filePath: ".agents/skills/kuma/SKILL.md", action: "created" });
11338
11558
  }
11339
11559
  } catch (err) {
@@ -11345,21 +11565,21 @@ function handleOpencodeSecondary(root, results) {
11345
11565
  });
11346
11566
  }
11347
11567
  }
11348
- const opencodeSkillPath = path33.resolve(root, ".opencode", "skills", "kuma", "SKILL.md");
11568
+ const opencodeSkillPath = path34.resolve(root, ".opencode", "skills", "kuma", "SKILL.md");
11349
11569
  if (!results.some((r) => r.filePath === ".opencode/skills/kuma/SKILL.md")) {
11350
11570
  try {
11351
- const dir = path33.dirname(opencodeSkillPath);
11352
- if (fs30.existsSync(opencodeSkillPath)) {
11353
- const existing = fs30.readFileSync(opencodeSkillPath, "utf-8");
11571
+ const dir = path34.dirname(opencodeSkillPath);
11572
+ if (fs31.existsSync(opencodeSkillPath)) {
11573
+ const existing = fs31.readFileSync(opencodeSkillPath, "utf-8");
11354
11574
  if (existing.includes("kuma-mcp")) {
11355
11575
  results.push({ type: "opencode", filePath: ".opencode/skills/kuma/SKILL.md", action: "skipped" });
11356
11576
  } else {
11357
- fs30.writeFileSync(opencodeSkillPath, existing.trimEnd() + "\n\n---\n\n" + opencodeContent, "utf-8");
11577
+ fs31.writeFileSync(opencodeSkillPath, existing.trimEnd() + "\n\n---\n\n" + opencodeContent, "utf-8");
11358
11578
  results.push({ type: "opencode", filePath: ".opencode/skills/kuma/SKILL.md", action: "appended" });
11359
11579
  }
11360
11580
  } else {
11361
- if (!fs30.existsSync(dir)) fs30.mkdirSync(dir, { recursive: true });
11362
- fs30.writeFileSync(opencodeSkillPath, opencodeContent, "utf-8");
11581
+ if (!fs31.existsSync(dir)) fs31.mkdirSync(dir, { recursive: true });
11582
+ fs31.writeFileSync(opencodeSkillPath, opencodeContent, "utf-8");
11363
11583
  results.push({ type: "opencode", filePath: ".opencode/skills/kuma/SKILL.md", action: "created" });
11364
11584
  }
11365
11585
  } catch (err) {
@@ -11371,21 +11591,21 @@ function handleOpencodeSecondary(root, results) {
11371
11591
  });
11372
11592
  }
11373
11593
  }
11374
- const pluginPath = path33.resolve(root, ".opencode", "plugins", "kuma.js");
11594
+ const pluginPath = path34.resolve(root, ".opencode", "plugins", "kuma.js");
11375
11595
  if (!results.some((r) => r.filePath === ".opencode/plugins/kuma.js")) {
11376
11596
  try {
11377
- const dir = path33.dirname(pluginPath);
11378
- if (fs30.existsSync(pluginPath)) {
11379
- const existing = fs30.readFileSync(pluginPath, "utf-8");
11597
+ const dir = path34.dirname(pluginPath);
11598
+ if (fs31.existsSync(pluginPath)) {
11599
+ const existing = fs31.readFileSync(pluginPath, "utf-8");
11380
11600
  if (existing.includes("KumaPlugin") || existing.includes("kuma")) {
11381
11601
  results.push({ type: "opencode", filePath: ".opencode/plugins/kuma.js", action: "skipped" });
11382
11602
  } else {
11383
- fs30.writeFileSync(pluginPath, existing.trimEnd() + "\n\n" + opencodePluginTemplate(), "utf-8");
11603
+ fs31.writeFileSync(pluginPath, existing.trimEnd() + "\n\n" + opencodePluginTemplate(), "utf-8");
11384
11604
  results.push({ type: "opencode", filePath: ".opencode/plugins/kuma.js", action: "appended" });
11385
11605
  }
11386
11606
  } else {
11387
- if (!fs30.existsSync(dir)) fs30.mkdirSync(dir, { recursive: true });
11388
- fs30.writeFileSync(pluginPath, opencodePluginTemplate(), "utf-8");
11607
+ if (!fs31.existsSync(dir)) fs31.mkdirSync(dir, { recursive: true });
11608
+ fs31.writeFileSync(pluginPath, opencodePluginTemplate(), "utf-8");
11389
11609
  results.push({ type: "opencode", filePath: ".opencode/plugins/kuma.js", action: "created" });
11390
11610
  }
11391
11611
  } catch (err) {
@@ -11399,21 +11619,21 @@ function handleOpencodeSecondary(root, results) {
11399
11619
  }
11400
11620
  }
11401
11621
  function handleCodexSecondary(root, results) {
11402
- const tomlPath = path33.resolve(root, ".codex/config.toml");
11622
+ const tomlPath = path34.resolve(root, ".codex/config.toml");
11403
11623
  if (results.some((r) => r.filePath === ".codex/config.toml")) return;
11404
11624
  try {
11405
- const dir = path33.dirname(tomlPath);
11406
- if (!fs30.existsSync(dir)) fs30.mkdirSync(dir, { recursive: true });
11407
- if (fs30.existsSync(tomlPath)) {
11408
- const existingContent = fs30.readFileSync(tomlPath, "utf-8");
11625
+ const dir = path34.dirname(tomlPath);
11626
+ if (!fs31.existsSync(dir)) fs31.mkdirSync(dir, { recursive: true });
11627
+ if (fs31.existsSync(tomlPath)) {
11628
+ const existingContent = fs31.readFileSync(tomlPath, "utf-8");
11409
11629
  if (existingContent.includes("kuma")) {
11410
11630
  results.push({ type: "codex", filePath: ".codex/config.toml", action: "skipped" });
11411
11631
  return;
11412
11632
  }
11413
- fs30.writeFileSync(tomlPath, existingContent.trimEnd() + "\n\n" + codexConfigTomlTemplate(), "utf-8");
11633
+ fs31.writeFileSync(tomlPath, existingContent.trimEnd() + "\n\n" + codexConfigTomlTemplate(), "utf-8");
11414
11634
  results.push({ type: "codex", filePath: ".codex/config.toml", action: "appended" });
11415
11635
  } else {
11416
- fs30.writeFileSync(tomlPath, codexConfigTomlTemplate(), "utf-8");
11636
+ fs31.writeFileSync(tomlPath, codexConfigTomlTemplate(), "utf-8");
11417
11637
  results.push({ type: "codex", filePath: ".codex/config.toml", action: "created" });
11418
11638
  }
11419
11639
  } catch (err) {
@@ -11426,11 +11646,11 @@ function handleCodexSecondary(root, results) {
11426
11646
  }
11427
11647
  }
11428
11648
  function handleQwenSecondary(root, results) {
11429
- const settingsPath = path33.resolve(root, "settings.json");
11649
+ const settingsPath = path34.resolve(root, "settings.json");
11430
11650
  if (results.some((r) => r.filePath === "settings.json")) return;
11431
11651
  try {
11432
- if (fs30.existsSync(settingsPath)) {
11433
- const existingContent = fs30.readFileSync(settingsPath, "utf-8");
11652
+ if (fs31.existsSync(settingsPath)) {
11653
+ const existingContent = fs31.readFileSync(settingsPath, "utf-8");
11434
11654
  if (existingContent.includes("kuma")) {
11435
11655
  if (!existingContent.includes("_Generated by Kuma MCP_")) {
11436
11656
  try {
@@ -11438,7 +11658,7 @@ function handleQwenSecondary(root, results) {
11438
11658
  parsed.mcpServers = parsed.mcpServers || {};
11439
11659
  if (!parsed.mcpServers.kuma) {
11440
11660
  parsed.mcpServers.kuma = { command: "npx", args: ["-y", "@plumpslabs/kuma"], env: {} };
11441
- fs30.writeFileSync(settingsPath, JSON.stringify(parsed, null, 2) + "\n", "utf-8");
11661
+ fs31.writeFileSync(settingsPath, JSON.stringify(parsed, null, 2) + "\n", "utf-8");
11442
11662
  results.push({ type: "qwen", filePath: "settings.json", action: "appended" });
11443
11663
  return;
11444
11664
  }
@@ -11453,13 +11673,13 @@ function handleQwenSecondary(root, results) {
11453
11673
  parsed.mcpServers = parsed.mcpServers || {};
11454
11674
  if (!parsed.mcpServers.kuma) {
11455
11675
  parsed.mcpServers.kuma = { command: "npx", args: ["-y", "@plumpslabs/kuma"], env: {} };
11456
- fs30.writeFileSync(settingsPath, JSON.stringify(parsed, null, 2) + "\n", "utf-8");
11676
+ fs31.writeFileSync(settingsPath, JSON.stringify(parsed, null, 2) + "\n", "utf-8");
11457
11677
  results.push({ type: "qwen", filePath: "settings.json", action: "appended" });
11458
11678
  }
11459
11679
  } catch {
11460
11680
  }
11461
11681
  } else {
11462
- fs30.writeFileSync(settingsPath, qwenSettingsTemplate(), "utf-8");
11682
+ fs31.writeFileSync(settingsPath, qwenSettingsTemplate(), "utf-8");
11463
11683
  results.push({ type: "qwen", filePath: "settings.json", action: "created" });
11464
11684
  }
11465
11685
  } catch (err) {
@@ -11561,12 +11781,12 @@ function getCombinedAgentsMd(selectedTypes) {
11561
11781
  return lines.join("\n");
11562
11782
  }
11563
11783
  function handleAntigravityMcpConfig(root, results) {
11564
- const mcpPath = path33.resolve(root, ".agents/mcp_config.json");
11784
+ const mcpPath = path34.resolve(root, ".agents/mcp_config.json");
11565
11785
  if (results.some((r) => r.filePath === ".agents/mcp_config.json")) return;
11566
11786
  try {
11567
- const mcpDir = path33.dirname(mcpPath);
11568
- if (fs30.existsSync(mcpPath)) {
11569
- const existingContent = fs30.readFileSync(mcpPath, "utf-8");
11787
+ const mcpDir = path34.dirname(mcpPath);
11788
+ if (fs31.existsSync(mcpPath)) {
11789
+ const existingContent = fs31.readFileSync(mcpPath, "utf-8");
11570
11790
  if (existingContent.includes("kuma")) {
11571
11791
  results.push({ type: "antigravity", filePath: ".agents/mcp_config.json", action: "skipped" });
11572
11792
  return;
@@ -11575,14 +11795,14 @@ function handleAntigravityMcpConfig(root, results) {
11575
11795
  const parsed = JSON.parse(existingContent);
11576
11796
  parsed.mcpServers = parsed.mcpServers || {};
11577
11797
  parsed.mcpServers.kuma = { command: "npx", args: ["-y", "@plumpslabs/kuma"], env: {} };
11578
- fs30.writeFileSync(mcpPath, JSON.stringify(parsed, null, 2) + "\n", "utf-8");
11798
+ fs31.writeFileSync(mcpPath, JSON.stringify(parsed, null, 2) + "\n", "utf-8");
11579
11799
  results.push({ type: "antigravity", filePath: ".agents/mcp_config.json", action: "appended" });
11580
11800
  } catch {
11581
11801
  results.push({ type: "antigravity", filePath: ".agents/mcp_config.json", action: "error", error: "Invalid JSON in existing mcp_config.json" });
11582
11802
  }
11583
11803
  } else {
11584
- if (!fs30.existsSync(mcpDir)) fs30.mkdirSync(mcpDir, { recursive: true });
11585
- fs30.writeFileSync(mcpPath, antigravityMcpConfigTemplate(), "utf-8");
11804
+ if (!fs31.existsSync(mcpDir)) fs31.mkdirSync(mcpDir, { recursive: true });
11805
+ fs31.writeFileSync(mcpPath, antigravityMcpConfigTemplate(), "utf-8");
11586
11806
  results.push({ type: "antigravity", filePath: ".agents/mcp_config.json", action: "created" });
11587
11807
  }
11588
11808
  } catch (err) {
@@ -11595,21 +11815,21 @@ function handleAntigravityMcpConfig(root, results) {
11595
11815
  }
11596
11816
  }
11597
11817
  function handleAntigravityRules(root, results) {
11598
- const rulePath = path33.resolve(root, ".agents", "rules", "kuma.md");
11818
+ const rulePath = path34.resolve(root, ".agents", "rules", "kuma.md");
11599
11819
  if (results.some((r) => r.filePath === ".agents/rules/kuma.md")) return;
11600
11820
  try {
11601
- const dir = path33.dirname(rulePath);
11602
- if (!fs30.existsSync(dir)) fs30.mkdirSync(dir, { recursive: true });
11603
- if (fs30.existsSync(rulePath)) {
11604
- const existing = fs30.readFileSync(rulePath, "utf-8");
11821
+ const dir = path34.dirname(rulePath);
11822
+ if (!fs31.existsSync(dir)) fs31.mkdirSync(dir, { recursive: true });
11823
+ if (fs31.existsSync(rulePath)) {
11824
+ const existing = fs31.readFileSync(rulePath, "utf-8");
11605
11825
  if (existing.includes("Kuma MCP") || existing.includes("kuma-mcp")) {
11606
11826
  results.push({ type: "antigravity", filePath: ".agents/rules/kuma.md", action: "skipped" });
11607
11827
  return;
11608
11828
  }
11609
- fs30.writeFileSync(rulePath, existing.trimEnd() + "\n\n---\n\n" + antigravityRuleTemplate(), "utf-8");
11829
+ fs31.writeFileSync(rulePath, existing.trimEnd() + "\n\n---\n\n" + antigravityRuleTemplate(), "utf-8");
11610
11830
  results.push({ type: "antigravity", filePath: ".agents/rules/kuma.md", action: "appended" });
11611
11831
  } else {
11612
- fs30.writeFileSync(rulePath, antigravityRuleTemplate(), "utf-8");
11832
+ fs31.writeFileSync(rulePath, antigravityRuleTemplate(), "utf-8");
11613
11833
  results.push({ type: "antigravity", filePath: ".agents/rules/kuma.md", action: "created" });
11614
11834
  }
11615
11835
  } catch (err) {
@@ -11622,19 +11842,19 @@ function handleAntigravityRules(root, results) {
11622
11842
  }
11623
11843
  }
11624
11844
  function handleGeminiMd(root, results) {
11625
- const geminiPath = path33.resolve(root, "GEMINI.md");
11845
+ const geminiPath = path34.resolve(root, "GEMINI.md");
11626
11846
  if (results.some((r) => r.filePath === "GEMINI.md")) return;
11627
11847
  try {
11628
- if (fs30.existsSync(geminiPath)) {
11629
- const existing = fs30.readFileSync(geminiPath, "utf-8");
11848
+ if (fs31.existsSync(geminiPath)) {
11849
+ const existing = fs31.readFileSync(geminiPath, "utf-8");
11630
11850
  if (existing.includes("Kuma MCP") || existing.includes("kuma_context")) {
11631
11851
  results.push({ type: "antigravity", filePath: "GEMINI.md", action: "skipped" });
11632
11852
  return;
11633
11853
  }
11634
- fs30.writeFileSync(geminiPath, existing.trimEnd() + "\n\n---\n\n" + geminiTemplate(), "utf-8");
11854
+ fs31.writeFileSync(geminiPath, existing.trimEnd() + "\n\n---\n\n" + geminiTemplate(), "utf-8");
11635
11855
  results.push({ type: "antigravity", filePath: "GEMINI.md", action: "appended" });
11636
11856
  } else {
11637
- fs30.writeFileSync(geminiPath, geminiTemplate(), "utf-8");
11857
+ fs31.writeFileSync(geminiPath, geminiTemplate(), "utf-8");
11638
11858
  results.push({ type: "antigravity", filePath: "GEMINI.md", action: "created" });
11639
11859
  }
11640
11860
  } catch (err) {
@@ -11652,19 +11872,19 @@ function handleAntigravitySecondary(root, results) {
11652
11872
  handleGeminiMd(root, results);
11653
11873
  }
11654
11874
  function handleWindsurfSecondary(root, results) {
11655
- const rulesPath = path33.resolve(root, ".windsurfrules");
11875
+ const rulesPath = path34.resolve(root, ".windsurfrules");
11656
11876
  if (results.some((r) => r.filePath === ".windsurfrules")) return;
11657
11877
  try {
11658
- if (fs30.existsSync(rulesPath)) {
11659
- const existing = fs30.readFileSync(rulesPath, "utf-8");
11878
+ if (fs31.existsSync(rulesPath)) {
11879
+ const existing = fs31.readFileSync(rulesPath, "utf-8");
11660
11880
  if (existing.includes("Kuma MCP") || existing.includes("kuma_context")) {
11661
11881
  results.push({ type: "windsurf", filePath: ".windsurfrules", action: "skipped" });
11662
11882
  return;
11663
11883
  }
11664
- fs30.writeFileSync(rulesPath, existing.trimEnd() + "\n\n---\n\n" + windsurfrulesTemplate(), "utf-8");
11884
+ fs31.writeFileSync(rulesPath, existing.trimEnd() + "\n\n---\n\n" + windsurfrulesTemplate(), "utf-8");
11665
11885
  results.push({ type: "windsurf", filePath: ".windsurfrules", action: "appended" });
11666
11886
  } else {
11667
- fs30.writeFileSync(rulesPath, windsurfrulesTemplate(), "utf-8");
11887
+ fs31.writeFileSync(rulesPath, windsurfrulesTemplate(), "utf-8");
11668
11888
  results.push({ type: "windsurf", filePath: ".windsurfrules", action: "created" });
11669
11889
  }
11670
11890
  } catch (err) {
@@ -11677,21 +11897,21 @@ function handleWindsurfSecondary(root, results) {
11677
11897
  }
11678
11898
  }
11679
11899
  function handleClineSecondary(root, results) {
11680
- const rooPath = path33.resolve(root, ".roo", "rules", "kuma.md");
11900
+ const rooPath = path34.resolve(root, ".roo", "rules", "kuma.md");
11681
11901
  if (!results.some((r) => r.filePath === ".roo/rules/kuma.md")) {
11682
11902
  try {
11683
- const dir = path33.dirname(rooPath);
11684
- if (fs30.existsSync(rooPath)) {
11685
- const existing = fs30.readFileSync(rooPath, "utf-8");
11903
+ const dir = path34.dirname(rooPath);
11904
+ if (fs31.existsSync(rooPath)) {
11905
+ const existing = fs31.readFileSync(rooPath, "utf-8");
11686
11906
  if (existing.includes("kuma-mcp") || existing.includes("Kuma MCP")) {
11687
11907
  results.push({ type: "cline", filePath: ".roo/rules/kuma.md", action: "skipped" });
11688
11908
  } else {
11689
- fs30.writeFileSync(rooPath, existing.trimEnd() + "\n\n---\n\n" + rooRulesTemplate(), "utf-8");
11909
+ fs31.writeFileSync(rooPath, existing.trimEnd() + "\n\n---\n\n" + rooRulesTemplate(), "utf-8");
11690
11910
  results.push({ type: "cline", filePath: ".roo/rules/kuma.md", action: "appended" });
11691
11911
  }
11692
11912
  } else {
11693
- if (!fs30.existsSync(dir)) fs30.mkdirSync(dir, { recursive: true });
11694
- fs30.writeFileSync(rooPath, rooRulesTemplate(), "utf-8");
11913
+ if (!fs31.existsSync(dir)) fs31.mkdirSync(dir, { recursive: true });
11914
+ fs31.writeFileSync(rooPath, rooRulesTemplate(), "utf-8");
11695
11915
  results.push({ type: "cline", filePath: ".roo/rules/kuma.md", action: "created" });
11696
11916
  }
11697
11917
  } catch (err) {
@@ -11703,21 +11923,21 @@ function handleClineSecondary(root, results) {
11703
11923
  });
11704
11924
  }
11705
11925
  }
11706
- const traePath = path33.resolve(root, ".trae", "rules", "kuma.md");
11926
+ const traePath = path34.resolve(root, ".trae", "rules", "kuma.md");
11707
11927
  if (!results.some((r) => r.filePath === ".trae/rules/kuma.md")) {
11708
11928
  try {
11709
- const dir = path33.dirname(traePath);
11710
- if (fs30.existsSync(traePath)) {
11711
- const existing = fs30.readFileSync(traePath, "utf-8");
11929
+ const dir = path34.dirname(traePath);
11930
+ if (fs31.existsSync(traePath)) {
11931
+ const existing = fs31.readFileSync(traePath, "utf-8");
11712
11932
  if (existing.includes("Kuma MCP")) {
11713
11933
  results.push({ type: "cline", filePath: ".trae/rules/kuma.md", action: "skipped" });
11714
11934
  } else {
11715
- fs30.writeFileSync(traePath, existing.trimEnd() + "\n\n---\n\n" + traeRulesTemplate(), "utf-8");
11935
+ fs31.writeFileSync(traePath, existing.trimEnd() + "\n\n---\n\n" + traeRulesTemplate(), "utf-8");
11716
11936
  results.push({ type: "cline", filePath: ".trae/rules/kuma.md", action: "appended" });
11717
11937
  }
11718
11938
  } else {
11719
- if (!fs30.existsSync(dir)) fs30.mkdirSync(dir, { recursive: true });
11720
- fs30.writeFileSync(traePath, traeRulesTemplate(), "utf-8");
11939
+ if (!fs31.existsSync(dir)) fs31.mkdirSync(dir, { recursive: true });
11940
+ fs31.writeFileSync(traePath, traeRulesTemplate(), "utf-8");
11721
11941
  results.push({ type: "cline", filePath: ".trae/rules/kuma.md", action: "created" });
11722
11942
  }
11723
11943
  } catch (err) {
@@ -11729,21 +11949,21 @@ function handleClineSecondary(root, results) {
11729
11949
  });
11730
11950
  }
11731
11951
  }
11732
- const qoderPath = path33.resolve(root, ".qoder", "rules", "kuma.md");
11952
+ const qoderPath = path34.resolve(root, ".qoder", "rules", "kuma.md");
11733
11953
  if (!results.some((r) => r.filePath === ".qoder/rules/kuma.md")) {
11734
11954
  try {
11735
- const dir = path33.dirname(qoderPath);
11736
- if (fs30.existsSync(qoderPath)) {
11737
- const existing = fs30.readFileSync(qoderPath, "utf-8");
11955
+ const dir = path34.dirname(qoderPath);
11956
+ if (fs31.existsSync(qoderPath)) {
11957
+ const existing = fs31.readFileSync(qoderPath, "utf-8");
11738
11958
  if (existing.includes("Kuma MCP")) {
11739
11959
  results.push({ type: "cline", filePath: ".qoder/rules/kuma.md", action: "skipped" });
11740
11960
  } else {
11741
- fs30.writeFileSync(qoderPath, existing.trimEnd() + "\n\n---\n\n" + qoderRulesTemplate(), "utf-8");
11961
+ fs31.writeFileSync(qoderPath, existing.trimEnd() + "\n\n---\n\n" + qoderRulesTemplate(), "utf-8");
11742
11962
  results.push({ type: "cline", filePath: ".qoder/rules/kuma.md", action: "appended" });
11743
11963
  }
11744
11964
  } else {
11745
- if (!fs30.existsSync(dir)) fs30.mkdirSync(dir, { recursive: true });
11746
- fs30.writeFileSync(qoderPath, qoderRulesTemplate(), "utf-8");
11965
+ if (!fs31.existsSync(dir)) fs31.mkdirSync(dir, { recursive: true });
11966
+ fs31.writeFileSync(qoderPath, qoderRulesTemplate(), "utf-8");
11747
11967
  results.push({ type: "cline", filePath: ".qoder/rules/kuma.md", action: "created" });
11748
11968
  }
11749
11969
  } catch (err) {
@@ -11757,18 +11977,18 @@ function handleClineSecondary(root, results) {
11757
11977
  }
11758
11978
  }
11759
11979
  function handleAiderSecondary(root, results) {
11760
- const ymlPath = path33.resolve(root, ".aider.conf.yml");
11980
+ const ymlPath = path34.resolve(root, ".aider.conf.yml");
11761
11981
  if (results.some((r) => r.filePath === ".aider.conf.yml")) return;
11762
11982
  try {
11763
11983
  const conventionsRef = "read: CONVENTIONS.md";
11764
- if (fs30.existsSync(ymlPath)) {
11765
- const existingContent = fs30.readFileSync(ymlPath, "utf-8");
11984
+ if (fs31.existsSync(ymlPath)) {
11985
+ const existingContent = fs31.readFileSync(ymlPath, "utf-8");
11766
11986
  if (existingContent.includes("CONVENTIONS.md") || existingContent.includes("kuma")) {
11767
11987
  results.push({ type: "aider", filePath: ".aider.conf.yml", action: "skipped" });
11768
11988
  return;
11769
11989
  }
11770
11990
  const newContent = existingContent.trimEnd() + "\n\n# Kuma MCP conventions\n" + conventionsRef + "\n";
11771
- fs30.writeFileSync(ymlPath, newContent, "utf-8");
11991
+ fs31.writeFileSync(ymlPath, newContent, "utf-8");
11772
11992
  results.push({ type: "aider", filePath: ".aider.conf.yml", action: "appended" });
11773
11993
  } else {
11774
11994
  const content = [
@@ -11778,7 +11998,7 @@ function handleAiderSecondary(root, results) {
11778
11998
  conventionsRef,
11779
11999
  ""
11780
12000
  ].join("\n");
11781
- fs30.writeFileSync(ymlPath, content, "utf-8");
12001
+ fs31.writeFileSync(ymlPath, content, "utf-8");
11782
12002
  results.push({ type: "aider", filePath: ".aider.conf.yml", action: "created" });
11783
12003
  }
11784
12004
  } catch (err) {
@@ -11791,10 +12011,10 @@ function handleAiderSecondary(root, results) {
11791
12011
  }
11792
12012
  }
11793
12013
  function handleCopilotSecondary(root, results) {
11794
- const skillPath = path33.resolve(root, ".github/skills/kuma/SKILL.md");
12014
+ const skillPath = path34.resolve(root, ".github/skills/kuma/SKILL.md");
11795
12015
  if (results.some((r) => r.filePath === ".github/skills/kuma/SKILL.md")) return;
11796
12016
  try {
11797
- const dir = path33.dirname(skillPath);
12017
+ const dir = path34.dirname(skillPath);
11798
12018
  const content = [
11799
12019
  "---",
11800
12020
  "name: kuma-mcp",
@@ -11805,17 +12025,17 @@ function handleCopilotSecondary(root, results) {
11805
12025
  "",
11806
12026
  "\u{1F4D6} Read `.kuma/init.md` for detailed rules."
11807
12027
  ].join("\n");
11808
- if (fs30.existsSync(skillPath)) {
11809
- const existingContent = fs30.readFileSync(skillPath, "utf-8");
12028
+ if (fs31.existsSync(skillPath)) {
12029
+ const existingContent = fs31.readFileSync(skillPath, "utf-8");
11810
12030
  if (existingContent.includes("kuma")) {
11811
12031
  results.push({ type: "copilot", filePath: ".github/skills/kuma/SKILL.md", action: "skipped" });
11812
12032
  return;
11813
12033
  }
11814
- fs30.writeFileSync(skillPath, existingContent.trimEnd() + "\n\n" + content, "utf-8");
12034
+ fs31.writeFileSync(skillPath, existingContent.trimEnd() + "\n\n" + content, "utf-8");
11815
12035
  results.push({ type: "copilot", filePath: ".github/skills/kuma/SKILL.md", action: "appended" });
11816
12036
  } else {
11817
- if (!fs30.existsSync(dir)) fs30.mkdirSync(dir, { recursive: true });
11818
- fs30.writeFileSync(skillPath, content, "utf-8");
12037
+ if (!fs31.existsSync(dir)) fs31.mkdirSync(dir, { recursive: true });
12038
+ fs31.writeFileSync(skillPath, content, "utf-8");
11819
12039
  results.push({ type: "copilot", filePath: ".github/skills/kuma/SKILL.md", action: "created" });
11820
12040
  }
11821
12041
  } catch (err) {
@@ -11828,21 +12048,21 @@ function handleCopilotSecondary(root, results) {
11828
12048
  }
11829
12049
  }
11830
12050
  function handleOpenclawSecondary(root, results) {
11831
- const mcpPath = path33.resolve(root, ".agents/mcp_config.json");
12051
+ const mcpPath = path34.resolve(root, ".agents/mcp_config.json");
11832
12052
  if (results.some((r) => r.filePath === ".agents/mcp_config.json")) return;
11833
12053
  try {
11834
- const dir = path33.dirname(mcpPath);
11835
- if (fs30.existsSync(mcpPath)) {
11836
- const existingContent = fs30.readFileSync(mcpPath, "utf-8");
12054
+ const dir = path34.dirname(mcpPath);
12055
+ if (fs31.existsSync(mcpPath)) {
12056
+ const existingContent = fs31.readFileSync(mcpPath, "utf-8");
11837
12057
  if (existingContent.includes("kuma")) return;
11838
12058
  const parsed = JSON.parse(existingContent);
11839
12059
  parsed.mcpServers = parsed.mcpServers || {};
11840
12060
  parsed.mcpServers.kuma = { command: "npx", args: ["-y", "@plumpslabs/kuma"], env: {} };
11841
- fs30.writeFileSync(mcpPath, JSON.stringify(parsed, null, 2) + "\n", "utf-8");
12061
+ fs31.writeFileSync(mcpPath, JSON.stringify(parsed, null, 2) + "\n", "utf-8");
11842
12062
  results.push({ type: "openclaw", filePath: ".agents/mcp_config.json", action: "appended" });
11843
12063
  } else {
11844
- if (!fs30.existsSync(dir)) fs30.mkdirSync(dir, { recursive: true });
11845
- fs30.writeFileSync(mcpPath, antigravityMcpConfigTemplate(), "utf-8");
12064
+ if (!fs31.existsSync(dir)) fs31.mkdirSync(dir, { recursive: true });
12065
+ fs31.writeFileSync(mcpPath, antigravityMcpConfigTemplate(), "utf-8");
11846
12066
  results.push({ type: "openclaw", filePath: ".agents/mcp_config.json", action: "created" });
11847
12067
  }
11848
12068
  } catch (err) {
@@ -11855,20 +12075,20 @@ function handleOpenclawSecondary(root, results) {
11855
12075
  }
11856
12076
  }
11857
12077
  function handleInitMdGeneration(root, results) {
11858
- const initMdPath = path33.resolve(root, ".kuma/init.md");
12078
+ const initMdPath = path34.resolve(root, ".kuma/init.md");
11859
12079
  try {
11860
- const kumaDir = path33.dirname(initMdPath);
11861
- if (!fs30.existsSync(kumaDir)) fs30.mkdirSync(kumaDir, { recursive: true });
11862
- if (fs30.existsSync(initMdPath)) {
11863
- const existing = fs30.readFileSync(initMdPath, "utf-8");
12080
+ const kumaDir = path34.dirname(initMdPath);
12081
+ if (!fs31.existsSync(kumaDir)) fs31.mkdirSync(kumaDir, { recursive: true });
12082
+ if (fs31.existsSync(initMdPath)) {
12083
+ const existing = fs31.readFileSync(initMdPath, "utf-8");
11864
12084
  if (existing.includes("_Generated by Kuma MCP_")) {
11865
12085
  results.push({ type: "claude", filePath: ".kuma/init.md", action: "skipped" });
11866
12086
  return;
11867
12087
  }
11868
- fs30.writeFileSync(initMdPath, existing.trimEnd() + "\n\n" + generateInitMdContent(), "utf-8");
12088
+ fs31.writeFileSync(initMdPath, existing.trimEnd() + "\n\n" + generateInitMdContent(), "utf-8");
11869
12089
  results.push({ type: "claude", filePath: ".kuma/init.md", action: "appended" });
11870
12090
  } else {
11871
- fs30.writeFileSync(initMdPath, generateInitMdContent(), "utf-8");
12091
+ fs31.writeFileSync(initMdPath, generateInitMdContent(), "utf-8");
11872
12092
  results.push({ type: "claude", filePath: ".kuma/init.md", action: "created" });
11873
12093
  }
11874
12094
  } catch (err) {
@@ -11881,20 +12101,20 @@ function handleInitMdGeneration(root, results) {
11881
12101
  }
11882
12102
  }
11883
12103
  function handleCodewhaleSecondary(root, results) {
11884
- const mcpPath = path33.resolve(root, ".codewhale/mcp.json");
12104
+ const mcpPath = path34.resolve(root, ".codewhale/mcp.json");
11885
12105
  if (results.some((r) => r.filePath === ".codewhale/mcp.json")) return;
11886
12106
  try {
11887
- const dir = path33.dirname(mcpPath);
11888
- if (fs30.existsSync(mcpPath)) {
11889
- const existingContent = fs30.readFileSync(mcpPath, "utf-8");
12107
+ const dir = path34.dirname(mcpPath);
12108
+ if (fs31.existsSync(mcpPath)) {
12109
+ const existingContent = fs31.readFileSync(mcpPath, "utf-8");
11890
12110
  if (existingContent.includes("kuma")) return;
11891
12111
  const parsed = JSON.parse(existingContent);
11892
12112
  parsed.mcpServers = parsed.mcpServers || {};
11893
12113
  parsed.mcpServers.kuma = { command: "npx", args: ["-y", "@plumpslabs/kuma"], env: {} };
11894
- fs30.writeFileSync(mcpPath, JSON.stringify(parsed, null, 2) + "\n", "utf-8");
12114
+ fs31.writeFileSync(mcpPath, JSON.stringify(parsed, null, 2) + "\n", "utf-8");
11895
12115
  results.push({ type: "codewhale", filePath: ".codewhale/mcp.json", action: "appended" });
11896
12116
  } else {
11897
- if (!fs30.existsSync(dir)) fs30.mkdirSync(dir, { recursive: true });
12117
+ if (!fs31.existsSync(dir)) fs31.mkdirSync(dir, { recursive: true });
11898
12118
  const config = {
11899
12119
  mcpServers: {
11900
12120
  kuma: {
@@ -11904,7 +12124,7 @@ function handleCodewhaleSecondary(root, results) {
11904
12124
  }
11905
12125
  }
11906
12126
  };
11907
- fs30.writeFileSync(mcpPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
12127
+ fs31.writeFileSync(mcpPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
11908
12128
  results.push({ type: "codewhale", filePath: ".codewhale/mcp.json", action: "created" });
11909
12129
  }
11910
12130
  } catch (err) {
@@ -11917,7 +12137,7 @@ function handleCodewhaleSecondary(root, results) {
11917
12137
  }
11918
12138
  }
11919
12139
  function handleClaudeSecondary(root, results) {
11920
- const settingsPath = path33.resolve(root, ".claude", "settings.json");
12140
+ const settingsPath = path34.resolve(root, ".claude", "settings.json");
11921
12141
  const hookBlock = {
11922
12142
  hooks: {
11923
12143
  PreToolUse: [
@@ -11948,8 +12168,8 @@ function handleClaudeSecondary(root, results) {
11948
12168
  }
11949
12169
  };
11950
12170
  try {
11951
- if (fs30.existsSync(settingsPath)) {
11952
- const existing = JSON.parse(fs30.readFileSync(settingsPath, "utf-8"));
12171
+ if (fs31.existsSync(settingsPath)) {
12172
+ const existing = JSON.parse(fs31.readFileSync(settingsPath, "utf-8"));
11953
12173
  const existingHooks = existing.hooks || {};
11954
12174
  const mergedPre = [...existingHooks.PreToolUse || []];
11955
12175
  for (const entry of hookBlock.hooks.PreToolUse) {
@@ -11973,12 +12193,12 @@ function handleClaudeSecondary(root, results) {
11973
12193
  ...existing,
11974
12194
  hooks: { ...existingHooks, PreToolUse: mergedPre, SessionStart: mergedStart, PreCompact: mergedCompact }
11975
12195
  };
11976
- fs30.writeFileSync(settingsPath, JSON.stringify(merged, null, 2) + "\n", "utf-8");
12196
+ fs31.writeFileSync(settingsPath, JSON.stringify(merged, null, 2) + "\n", "utf-8");
11977
12197
  results.push({ type: "claude", filePath: ".claude/settings.json", action: "appended" });
11978
12198
  } else {
11979
- const dir = path33.dirname(settingsPath);
11980
- if (!fs30.existsSync(dir)) fs30.mkdirSync(dir, { recursive: true });
11981
- fs30.writeFileSync(settingsPath, JSON.stringify(hookBlock, null, 2) + "\n", "utf-8");
12199
+ const dir = path34.dirname(settingsPath);
12200
+ if (!fs31.existsSync(dir)) fs31.mkdirSync(dir, { recursive: true });
12201
+ fs31.writeFileSync(settingsPath, JSON.stringify(hookBlock, null, 2) + "\n", "utf-8");
11982
12202
  results.push({ type: "claude", filePath: ".claude/settings.json", action: "created" });
11983
12203
  }
11984
12204
  } catch (err) {
@@ -11989,10 +12209,10 @@ function handleClaudeSecondary(root, results) {
11989
12209
  error: err instanceof Error ? err.message : String(err)
11990
12210
  });
11991
12211
  }
11992
- const skillPath = path33.resolve(root, ".claude", "skills", "kuma", "SKILL.md");
12212
+ const skillPath = path34.resolve(root, ".claude", "skills", "kuma", "SKILL.md");
11993
12213
  if (!results.some((r) => r.filePath === ".claude/skills/kuma/SKILL.md")) {
11994
12214
  try {
11995
- const dir = path33.dirname(skillPath);
12215
+ const dir = path34.dirname(skillPath);
11996
12216
  const content = [
11997
12217
  "---",
11998
12218
  "name: kuma-mcp",
@@ -12004,17 +12224,17 @@ function handleClaudeSecondary(root, results) {
12004
12224
  "\u{1F4D6} Read `.kuma/init.md` for detailed rules.",
12005
12225
  "\u{1F4C2} Readable state: `.kuma/KNOWN_GOTCHAS.md` (gotchas) \xB7 `.kuma/memories/decisions.md` (decisions)"
12006
12226
  ].join("\n");
12007
- if (fs30.existsSync(skillPath)) {
12008
- const existing = fs30.readFileSync(skillPath, "utf-8");
12227
+ if (fs31.existsSync(skillPath)) {
12228
+ const existing = fs31.readFileSync(skillPath, "utf-8");
12009
12229
  if (existing.includes("kuma-mcp")) {
12010
12230
  results.push({ type: "claude", filePath: ".claude/skills/kuma/SKILL.md", action: "skipped" });
12011
12231
  } else {
12012
- fs30.writeFileSync(skillPath, existing.trimEnd() + "\n\n---\n\n" + content, "utf-8");
12232
+ fs31.writeFileSync(skillPath, existing.trimEnd() + "\n\n---\n\n" + content, "utf-8");
12013
12233
  results.push({ type: "claude", filePath: ".claude/skills/kuma/SKILL.md", action: "appended" });
12014
12234
  }
12015
12235
  } else {
12016
- if (!fs30.existsSync(dir)) fs30.mkdirSync(dir, { recursive: true });
12017
- fs30.writeFileSync(skillPath, content, "utf-8");
12236
+ if (!fs31.existsSync(dir)) fs31.mkdirSync(dir, { recursive: true });
12237
+ fs31.writeFileSync(skillPath, content, "utf-8");
12018
12238
  results.push({ type: "claude", filePath: ".claude/skills/kuma/SKILL.md", action: "created" });
12019
12239
  }
12020
12240
  } catch (err) {
@@ -12028,27 +12248,27 @@ function handleClaudeSecondary(root, results) {
12028
12248
  }
12029
12249
  }
12030
12250
  function writeHooksFile(root, relPath, type, results, build) {
12031
- const fullPath = path33.resolve(root, relPath);
12251
+ const fullPath = path34.resolve(root, relPath);
12032
12252
  try {
12033
12253
  let existing = {};
12034
12254
  let existed = false;
12035
- if (fs30.existsSync(fullPath)) {
12255
+ if (fs31.existsSync(fullPath)) {
12036
12256
  existed = true;
12037
12257
  try {
12038
- existing = JSON.parse(fs30.readFileSync(fullPath, "utf-8"));
12258
+ existing = JSON.parse(fs31.readFileSync(fullPath, "utf-8"));
12039
12259
  } catch {
12040
12260
  existing = {};
12041
12261
  }
12042
12262
  } else {
12043
- const dir = path33.dirname(fullPath);
12044
- if (!fs30.existsSync(dir)) fs30.mkdirSync(dir, { recursive: true });
12263
+ const dir = path34.dirname(fullPath);
12264
+ if (!fs31.existsSync(dir)) fs31.mkdirSync(dir, { recursive: true });
12045
12265
  }
12046
12266
  const { doc, changed } = build(existing);
12047
12267
  if (!changed) {
12048
12268
  results.push({ type, filePath: relPath, action: "skipped" });
12049
12269
  return;
12050
12270
  }
12051
- fs30.writeFileSync(fullPath, JSON.stringify(doc, null, 2) + "\n", "utf-8");
12271
+ fs31.writeFileSync(fullPath, JSON.stringify(doc, null, 2) + "\n", "utf-8");
12052
12272
  results.push({ type, filePath: relPath, action: existed ? "appended" : "created" });
12053
12273
  } catch (err) {
12054
12274
  results.push({ type, filePath: relPath, action: "error", error: err instanceof Error ? err.message : String(err) });
@@ -12129,18 +12349,18 @@ function handleCodexHooks(root, results) {
12129
12349
  });
12130
12350
  }
12131
12351
  function handleCursorGotchaRules(root, results) {
12132
- const rulesDir2 = path33.resolve(root, ".cursor", "rules", "kuma-gotchas");
12352
+ const rulesDir2 = path34.resolve(root, ".cursor", "rules", "kuma-gotchas");
12133
12353
  try {
12134
12354
  let gotchas = [];
12135
12355
  try {
12136
12356
  gotchas = getActiveGotchas().filter((g) => g.severity === "high" || g.severity === "critical");
12137
12357
  } catch {
12138
12358
  }
12139
- if (fs30.existsSync(rulesDir2)) {
12140
- for (const f of fs30.readdirSync(rulesDir2)) {
12359
+ if (fs31.existsSync(rulesDir2)) {
12360
+ for (const f of fs31.readdirSync(rulesDir2)) {
12141
12361
  if (f.endsWith(".mdc")) {
12142
12362
  try {
12143
- fs30.rmSync(path33.join(rulesDir2, f), { force: true });
12363
+ fs31.rmSync(path34.join(rulesDir2, f), { force: true });
12144
12364
  } catch {
12145
12365
  }
12146
12366
  }
@@ -12150,7 +12370,7 @@ function handleCursorGotchaRules(root, results) {
12150
12370
  results.push({ type: "cursor", filePath: ".cursor/rules/kuma-gotchas/", action: "skipped" });
12151
12371
  return;
12152
12372
  }
12153
- fs30.mkdirSync(rulesDir2, { recursive: true });
12373
+ fs31.mkdirSync(rulesDir2, { recursive: true });
12154
12374
  const seen = /* @__PURE__ */ new Set();
12155
12375
  let created = 0;
12156
12376
  for (const g of gotchas) {
@@ -12171,7 +12391,7 @@ function handleCursorGotchaRules(root, results) {
12171
12391
  "`kuma_context({ action: 'history', target: '<file>' })`",
12172
12392
  ""
12173
12393
  ].join("\n");
12174
- fs30.writeFileSync(path33.join(rulesDir2, `${slug2}.mdc`), md, "utf-8");
12394
+ fs31.writeFileSync(path34.join(rulesDir2, `${slug2}.mdc`), md, "utf-8");
12175
12395
  created++;
12176
12396
  }
12177
12397
  results.push({
@@ -12198,28 +12418,28 @@ function runInit(options) {
12198
12418
  let agentsMdHandled = false;
12199
12419
  for (const type of selected) {
12200
12420
  const relativePath = configFilePath(type);
12201
- const fullPath = path33.resolve(root, relativePath);
12421
+ const fullPath = path34.resolve(root, relativePath);
12202
12422
  const getTemplate = TEMPLATES[type];
12203
12423
  try {
12204
12424
  if (AGENTS_MD_TYPES.includes(type) && !agentsMdHandled) {
12205
12425
  agentsMdHandled = true;
12206
12426
  const combinedContent = getCombinedAgentsMd(new Set(agentsMdSelected));
12207
- if (fs30.existsSync(fullPath)) {
12427
+ if (fs31.existsSync(fullPath)) {
12208
12428
  if (options.skipExisting) {
12209
12429
  results.push({ type, filePath: relativePath, action: "skipped" });
12210
12430
  } else {
12211
- const existingContent = fs30.readFileSync(fullPath, "utf-8");
12431
+ const existingContent = fs31.readFileSync(fullPath, "utf-8");
12212
12432
  if (existingContent.includes("_Generated by Kuma MCP_")) {
12213
12433
  results.push({ type, filePath: relativePath, action: "skipped" });
12214
12434
  } else {
12215
- fs30.writeFileSync(fullPath, existingContent.trimEnd() + "\n\n" + combinedContent, "utf-8");
12435
+ fs31.writeFileSync(fullPath, existingContent.trimEnd() + "\n\n" + combinedContent, "utf-8");
12216
12436
  results.push({ type, filePath: relativePath, action: "appended" });
12217
12437
  }
12218
12438
  }
12219
12439
  } else {
12220
- const dir = path33.dirname(fullPath);
12221
- if (!fs30.existsSync(dir)) fs30.mkdirSync(dir, { recursive: true });
12222
- fs30.writeFileSync(fullPath, combinedContent, "utf-8");
12440
+ const dir = path34.dirname(fullPath);
12441
+ if (!fs31.existsSync(dir)) fs31.mkdirSync(dir, { recursive: true });
12442
+ fs31.writeFileSync(fullPath, combinedContent, "utf-8");
12223
12443
  results.push({ type, filePath: relativePath, action: "created" });
12224
12444
  }
12225
12445
  if (selectedSet.has("opencode")) handleOpencodeSecondary(root, results);
@@ -12231,12 +12451,12 @@ function runInit(options) {
12231
12451
  continue;
12232
12452
  } else {
12233
12453
  const template = getTemplate();
12234
- if (fs30.existsSync(fullPath)) {
12454
+ if (fs31.existsSync(fullPath)) {
12235
12455
  if (options.skipExisting) {
12236
12456
  results.push({ type, filePath: relativePath, action: "skipped" });
12237
12457
  continue;
12238
12458
  }
12239
- const existingContent = fs30.readFileSync(fullPath, "utf-8");
12459
+ const existingContent = fs31.readFileSync(fullPath, "utf-8");
12240
12460
  if (existingContent.includes("_Generated by Kuma MCP_")) {
12241
12461
  if (type === "antigravity") {
12242
12462
  handleAntigravitySecondary(root, results);
@@ -12253,14 +12473,14 @@ function runInit(options) {
12253
12473
  continue;
12254
12474
  }
12255
12475
  const newContent = existingContent.trimEnd() + APPEND_SEPARATOR + template;
12256
- fs30.writeFileSync(fullPath, newContent, "utf-8");
12476
+ fs31.writeFileSync(fullPath, newContent, "utf-8");
12257
12477
  results.push({ type, filePath: relativePath, action: "appended" });
12258
12478
  } else {
12259
- const dir = path33.dirname(fullPath);
12260
- if (!fs30.existsSync(dir)) {
12261
- fs30.mkdirSync(dir, { recursive: true });
12479
+ const dir = path34.dirname(fullPath);
12480
+ if (!fs31.existsSync(dir)) {
12481
+ fs31.mkdirSync(dir, { recursive: true });
12262
12482
  }
12263
- fs30.writeFileSync(fullPath, template, "utf-8");
12483
+ fs31.writeFileSync(fullPath, template, "utf-8");
12264
12484
  results.push({ type, filePath: relativePath, action: "created" });
12265
12485
  }
12266
12486
  if (type === "antigravity") {
@@ -12432,8 +12652,8 @@ var compactionContext_exports = {};
12432
12652
  __export(compactionContext_exports, {
12433
12653
  getCompactionContext: () => getCompactionContext
12434
12654
  });
12435
- import fs31 from "fs";
12436
- import path34 from "path";
12655
+ import fs32 from "fs";
12656
+ import path35 from "path";
12437
12657
  async function getCompactionContext() {
12438
12658
  const parts = [];
12439
12659
  try {
@@ -12446,8 +12666,8 @@ async function getCompactionContext() {
12446
12666
  } catch {
12447
12667
  }
12448
12668
  try {
12449
- const dbFile = path34.join(getProjectRoot(), ".kuma", "kuma.db");
12450
- if (fs31.existsSync(dbFile)) {
12669
+ const dbFile = path35.join(getProjectRoot(), ".kuma", "kuma.db");
12670
+ if (fs32.existsSync(dbFile)) {
12451
12671
  const { getDb: getDb2 } = await Promise.resolve().then(() => (init_kumaDb(), kumaDb_exports));
12452
12672
  const db = await getDb2();
12453
12673
  const stmt = db.prepare(
@@ -12473,9 +12693,9 @@ async function getCompactionContext() {
12473
12693
  } catch {
12474
12694
  }
12475
12695
  try {
12476
- const cpDir = path34.join(getProjectRoot(), ".kuma", "checkpoints");
12477
- if (fs31.existsSync(cpDir)) {
12478
- const cps = fs31.readdirSync(cpDir).slice(0, 3);
12696
+ const cpDir = path35.join(getProjectRoot(), ".kuma", "checkpoints");
12697
+ if (fs32.existsSync(cpDir)) {
12698
+ const cps = fs32.readdirSync(cpDir).slice(0, 3);
12479
12699
  if (cps.length > 0) parts.push(`Checkpoints: ${cps.join(", ")}`);
12480
12700
  }
12481
12701
  } catch {
@@ -12503,22 +12723,22 @@ __export(kumaDaemon_exports, {
12503
12723
  daemonStop: () => daemonStop,
12504
12724
  daemonTick: () => daemonTick
12505
12725
  });
12506
- import fs32 from "fs";
12507
- import path35 from "path";
12726
+ import fs33 from "fs";
12727
+ import path36 from "path";
12508
12728
  import { spawn } from "child_process";
12509
12729
  function paths(root) {
12510
12730
  const r = root || getProjectRoot();
12511
12731
  return {
12512
- pid: path35.join(r, PID_FILE),
12513
- status: path35.join(r, STATUS_FILE),
12514
- log: path35.join(r, LOG_FILE)
12732
+ pid: path36.join(r, PID_FILE),
12733
+ status: path36.join(r, STATUS_FILE),
12734
+ log: path36.join(r, LOG_FILE)
12515
12735
  };
12516
12736
  }
12517
12737
  function readPid(root) {
12518
12738
  try {
12519
12739
  const fp = paths(root).pid;
12520
- if (!fs32.existsSync(fp)) return null;
12521
- const pid = Number(fs32.readFileSync(fp, "utf-8").trim());
12740
+ if (!fs33.existsSync(fp)) return null;
12741
+ const pid = Number(fs33.readFileSync(fp, "utf-8").trim());
12522
12742
  return Number.isFinite(pid) && pid > 0 ? pid : null;
12523
12743
  } catch {
12524
12744
  return null;
@@ -12536,6 +12756,12 @@ async function daemonTick(root) {
12536
12756
  const r = root || getProjectRoot();
12537
12757
  const p = paths(r);
12538
12758
  const notes = [];
12759
+ try {
12760
+ const { ensureBackbone: ensureBackbone2, formatBackbone: formatBackbone2 } = await Promise.resolve().then(() => (init_mapBackbone(), mapBackbone_exports));
12761
+ const bb = await ensureBackbone2();
12762
+ if (bb) notes.push(formatBackbone2(bb));
12763
+ } catch {
12764
+ }
12539
12765
  try {
12540
12766
  const { syncModifiedFiles: syncModifiedFiles2 } = await Promise.resolve().then(() => (init_kumaCodeScanner(), kumaCodeScanner_exports));
12541
12767
  const scan = await syncModifiedFiles2(50);
@@ -12569,8 +12795,8 @@ async function daemonTick(root) {
12569
12795
  };
12570
12796
  try {
12571
12797
  let prev = {};
12572
- if (fs32.existsSync(p.status)) prev = JSON.parse(fs32.readFileSync(p.status, "utf-8"));
12573
- fs32.writeFileSync(p.status, JSON.stringify({ ...prev, ...status }, null, 2), "utf-8");
12798
+ if (fs33.existsSync(p.status)) prev = JSON.parse(fs33.readFileSync(p.status, "utf-8"));
12799
+ fs33.writeFileSync(p.status, JSON.stringify({ ...prev, ...status }, null, 2), "utf-8");
12574
12800
  } catch {
12575
12801
  }
12576
12802
  return notes.join(" \xB7 ");
@@ -12580,7 +12806,7 @@ async function runLoop(intervalMs) {
12580
12806
  const p = paths(r);
12581
12807
  const log = (msg) => {
12582
12808
  try {
12583
- fs32.appendFileSync(p.log, `${(/* @__PURE__ */ new Date()).toISOString()} ${msg}
12809
+ fs33.appendFileSync(p.log, `${(/* @__PURE__ */ new Date()).toISOString()} ${msg}
12584
12810
  `, "utf-8");
12585
12811
  } catch {
12586
12812
  }
@@ -12611,8 +12837,8 @@ async function daemonStart(intervalMs = DEFAULT_INTERVAL_MS, root) {
12611
12837
  });
12612
12838
  child.unref();
12613
12839
  try {
12614
- fs32.writeFileSync(p.pid, String(child.pid), "utf-8");
12615
- fs32.writeFileSync(
12840
+ fs33.writeFileSync(p.pid, String(child.pid), "utf-8");
12841
+ fs33.writeFileSync(
12616
12842
  p.status,
12617
12843
  JSON.stringify({ running: true, pid: child.pid, startedAt: Date.now(), lastRunAt: null, lastResult: null, intervalMs }, null, 2),
12618
12844
  "utf-8"
@@ -12628,7 +12854,7 @@ async function daemonStop(root) {
12628
12854
  if (!pid) return "\u{1F43B} Daemon not running (no pid file).";
12629
12855
  if (!isAlive(pid)) {
12630
12856
  try {
12631
- fs32.rmSync(p.pid, { force: true });
12857
+ fs33.rmSync(p.pid, { force: true });
12632
12858
  } catch {
12633
12859
  }
12634
12860
  return "\u{1F43B} Daemon pid file was stale \u2014 cleaned up (process already gone).";
@@ -12636,7 +12862,7 @@ async function daemonStop(root) {
12636
12862
  try {
12637
12863
  process.kill(pid, "SIGTERM");
12638
12864
  try {
12639
- fs32.rmSync(p.pid, { force: true });
12865
+ fs33.rmSync(p.pid, { force: true });
12640
12866
  } catch {
12641
12867
  }
12642
12868
  return `\u{1F43B} Daemon stopped (was pid ${pid}).`;
@@ -12650,7 +12876,7 @@ async function daemonStatus(root) {
12650
12876
  const pid = readPid(r);
12651
12877
  let status = { running: false, pid: null, startedAt: null, lastRunAt: null, lastResult: null, intervalMs: DEFAULT_INTERVAL_MS };
12652
12878
  try {
12653
- if (fs32.existsSync(p.status)) status = { ...status, ...JSON.parse(fs32.readFileSync(p.status, "utf-8")) };
12879
+ if (fs33.existsSync(p.status)) status = { ...status, ...JSON.parse(fs33.readFileSync(p.status, "utf-8")) };
12654
12880
  } catch {
12655
12881
  }
12656
12882
  const alive = pid !== null && isAlive(pid);
@@ -12685,19 +12911,19 @@ __export(agentDetector_exports, {
12685
12911
  getSkillPath: () => getSkillPath,
12686
12912
  skillExists: () => skillExists
12687
12913
  });
12688
- import fs33 from "fs";
12689
- import path36 from "path";
12914
+ import fs34 from "fs";
12915
+ import path37 from "path";
12690
12916
  function checkFile(root, filePath) {
12691
12917
  try {
12692
- return fs33.existsSync(path36.join(root, filePath));
12918
+ return fs34.existsSync(path37.join(root, filePath));
12693
12919
  } catch {
12694
12920
  return false;
12695
12921
  }
12696
12922
  }
12697
12923
  function checkDir(root, dirPath) {
12698
12924
  try {
12699
- const fullPath = path36.join(root, dirPath);
12700
- return fs33.existsSync(fullPath) && fs33.statSync(fullPath).isDirectory();
12925
+ const fullPath = path37.join(root, dirPath);
12926
+ return fs34.existsSync(fullPath) && fs34.statSync(fullPath).isDirectory();
12701
12927
  } catch {
12702
12928
  return false;
12703
12929
  }
@@ -12765,7 +12991,7 @@ function getAgentLabel(type) {
12765
12991
  function skillExists(type, projectRoot) {
12766
12992
  const root = projectRoot ?? getProjectRoot();
12767
12993
  const skillPath = getSkillPath(type);
12768
- return fs33.existsSync(path36.join(root, skillPath));
12994
+ return fs34.existsSync(path37.join(root, skillPath));
12769
12995
  }
12770
12996
  var AGENT_DETECTORS;
12771
12997
  var init_agentDetector = __esm({
@@ -13361,8 +13587,8 @@ init_kumaGraph();
13361
13587
  init_kumaMemory();
13362
13588
  init_kumaDriftDetector();
13363
13589
  init_pathValidator();
13364
- import fs22 from "fs";
13365
- import path25 from "path";
13590
+ import fs23 from "fs";
13591
+ import path26 from "path";
13366
13592
  var CONTEXT_ALIASES = {
13367
13593
  "research": "research",
13368
13594
  "search": "research",
@@ -13481,6 +13707,15 @@ async function handleCluster(_params) {
13481
13707
  async function handleInit(_params) {
13482
13708
  sessionMemory.setGoal(_params.goal || "Exploring project");
13483
13709
  sessionMemory.recordToolCall("kuma_context_init", {});
13710
+ let backboneNote = "";
13711
+ try {
13712
+ const { ensureBackbone: ensureBackbone2, formatBackbone: formatBackbone2 } = await Promise.resolve().then(() => (init_mapBackbone(), mapBackbone_exports));
13713
+ const bb = await ensureBackbone2();
13714
+ if (bb) backboneNote = `
13715
+ ${formatBackbone2(bb)}
13716
+ `;
13717
+ } catch {
13718
+ }
13484
13719
  const branch = sessionMemory.getCurrentBranch();
13485
13720
  const branchTag = branch ? ` [git: \`${branch}\`]` : "";
13486
13721
  const lines = [
@@ -13490,6 +13725,7 @@ async function handleInit(_params) {
13490
13725
  `\u{1F4C1} Project: ${getProjectRoot().split("/").pop() || "unknown"}${branchTag}`,
13491
13726
  ""
13492
13727
  ];
13728
+ if (backboneNote) lines.push(backboneNote);
13493
13729
  const branchTransition = sessionMemory.getBranchTransition();
13494
13730
  if (branchTransition?.switched) {
13495
13731
  lines.push(`\u{1F500} **Branch switched**: from \`${branchTransition.from}\` to \`${branchTransition.to}\`. Session context updated.`);
@@ -13689,6 +13925,14 @@ async function handleResearch(params, dirtySynced = 0) {
13689
13925
  } else lines.push(" \u23F3 No content hash available \u2014 will research fresh");
13690
13926
  lines.push("");
13691
13927
  lines.push("**Step 3/5: Graph Query + Code Scan**");
13928
+ try {
13929
+ if (params.scope && (params.scope.includes("/") || params.scope.includes("."))) {
13930
+ const { ensureMapped: ensureMapped2 } = await Promise.resolve().then(() => (init_mapBackbone(), mapBackbone_exports));
13931
+ const { filled } = await ensureMapped2([params.scope]);
13932
+ if (filled > 0) lines.push(` \u{1F5FA}\uFE0F Precision tier filled on demand: ${filled} file(s) indexed (no user action needed)`);
13933
+ }
13934
+ } catch {
13935
+ }
13692
13936
  try {
13693
13937
  const graphResult = await searchGraph(scope, 15);
13694
13938
  const graphLines = graphResult.split("\n");
@@ -13814,7 +14058,7 @@ ${gitHistory}`);
13814
14058
  try {
13815
14059
  const { getDb: getDb2 } = await Promise.resolve().then(() => (init_kumaDb(), kumaDb_exports));
13816
14060
  const db = await getDb2();
13817
- const base = path25.basename(target);
14061
+ const base = path26.basename(target);
13818
14062
  const stmt = db.prepare(`
13819
14063
  SELECT description, last_verified_at FROM known_gotchas
13820
14064
  WHERE status = 'resolved' AND (file_path LIKE ? OR file_path LIKE ?)
@@ -13827,9 +14071,9 @@ ${gitHistory}`);
13827
14071
  if (resolved.length === 0) {
13828
14072
  try {
13829
14073
  const { getProjectRoot: getProjectRoot2 } = await Promise.resolve().then(() => (init_pathValidator(), pathValidator_exports));
13830
- const mdPath = path25.join(getProjectRoot2(), ".kuma", "KNOWN_GOTCHAS.md");
13831
- if (fs22.existsSync(mdPath)) {
13832
- const mdContent = fs22.readFileSync(mdPath, "utf-8");
14074
+ const mdPath = path26.join(getProjectRoot2(), ".kuma", "KNOWN_GOTCHAS.md");
14075
+ if (fs23.existsSync(mdPath)) {
14076
+ const mdContent = fs23.readFileSync(mdPath, "utf-8");
13833
14077
  const sections = mdContent.split(/^###\s+/m);
13834
14078
  for (const sec of sections) {
13835
14079
  const secLower = sec.toLowerCase();
@@ -13901,8 +14145,8 @@ init_kumaDb();
13901
14145
  init_kumaMemory();
13902
14146
  init_pathValidator();
13903
14147
  init_pathValidator();
13904
- import fs24 from "fs";
13905
- import path27 from "path";
14148
+ import fs25 from "fs";
14149
+ import path28 from "path";
13906
14150
  var MEMORY_ALIASES = {
13907
14151
  "decision": "decision",
13908
14152
  "adr": "decision",
@@ -14013,9 +14257,9 @@ async function handleResearchSave(params) {
14013
14257
  } catch {
14014
14258
  }
14015
14259
  try {
14016
- const researchDir = path27.join(getProjectRoot(), ".kuma", "research");
14017
- if (!fs24.existsSync(researchDir)) fs24.mkdirSync(researchDir, { recursive: true });
14018
- fs24.writeFileSync(path27.join(researchDir, `${scope}.json`), JSON.stringify(JSON.parse(record), null, 2), "utf-8");
14260
+ const researchDir = path28.join(getProjectRoot(), ".kuma", "research");
14261
+ if (!fs25.existsSync(researchDir)) fs25.mkdirSync(researchDir, { recursive: true });
14262
+ fs25.writeFileSync(path28.join(researchDir, `${scope}.json`), JSON.stringify(JSON.parse(record), null, 2), "utf-8");
14019
14263
  } catch {
14020
14264
  }
14021
14265
  sessionMemory.recordMemoryAction("research_save");
@@ -14211,8 +14455,8 @@ init_sessionMemory();
14211
14455
  init_pathValidator();
14212
14456
  init_sessionMemory();
14213
14457
  init_kumaShared();
14214
- import fs25 from "fs";
14215
- import path28 from "path";
14458
+ import fs26 from "fs";
14459
+ import path29 from "path";
14216
14460
  import { execSync as execSync7 } from "child_process";
14217
14461
  var SCRIPT_PATCH_PATTERNS = [
14218
14462
  "writeFileSync",
@@ -14239,20 +14483,20 @@ function findPatchScripts(projectRoot) {
14239
14483
  const warnings = [];
14240
14484
  const recentFiles = scanRecentFiles(projectRoot);
14241
14485
  for (const file of recentFiles) {
14242
- const ext = path28.extname(file).toLowerCase();
14486
+ const ext = path29.extname(file).toLowerCase();
14243
14487
  if (!SCRIPT_EXTENSIONS.includes(ext)) continue;
14244
- const relativePath = path28.relative(projectRoot, file);
14488
+ const relativePath = path29.relative(projectRoot, file);
14245
14489
  if (relativePath.startsWith("src") || relativePath.startsWith("test") || relativePath.startsWith("node_modules") || relativePath.startsWith(".") || relativePath.startsWith(".kuma/scratch")) {
14246
14490
  continue;
14247
14491
  }
14248
14492
  try {
14249
- const content = fs25.readFileSync(file, "utf-8").toLowerCase();
14493
+ const content = fs26.readFileSync(file, "utf-8").toLowerCase();
14250
14494
  const matchedPattern = SCRIPT_PATCH_PATTERNS.find((p) => content.includes(p.toLowerCase()));
14251
14495
  if (matchedPattern) {
14252
14496
  warnings.push({
14253
14497
  severity: "high",
14254
14498
  pattern: "script-patching",
14255
- message: `Created script file that modifies other files: ${path28.basename(file)}`,
14499
+ message: `Created script file that modifies other files: ${path29.basename(file)}`,
14256
14500
  suggestion: "Use your native edit tools instead \u2014 targeted edits with auto-backup and rollback",
14257
14501
  evidence: `File: ${relativePath} contains '${matchedPattern}'`,
14258
14502
  filePath: relativePath
@@ -14286,15 +14530,15 @@ function detectBashGrepUsage() {
14286
14530
  function scanRecentFiles(projectRoot) {
14287
14531
  const recent = [];
14288
14532
  try {
14289
- const entries = fs25.readdirSync(projectRoot, { withFileTypes: true });
14533
+ const entries = fs26.readdirSync(projectRoot, { withFileTypes: true });
14290
14534
  const now = Date.now();
14291
14535
  const recentThreshold = 30 * 60 * 1e3;
14292
14536
  for (const entry of entries) {
14293
14537
  if (!entry.isFile()) continue;
14294
14538
  try {
14295
- const stat = fs25.statSync(path28.join(projectRoot, entry.name));
14539
+ const stat = fs26.statSync(path29.join(projectRoot, entry.name));
14296
14540
  if (now - stat.mtimeMs < recentThreshold || now - stat.ctimeMs < recentThreshold) {
14297
- recent.push(path28.join(projectRoot, entry.name));
14541
+ recent.push(path29.join(projectRoot, entry.name));
14298
14542
  }
14299
14543
  } catch {
14300
14544
  continue;
@@ -14318,14 +14562,14 @@ function detectGitPatchScripts(projectRoot) {
14318
14562
  const prefix = line.substring(0, 2);
14319
14563
  if (prefix !== "??" && prefix !== "A ") continue;
14320
14564
  const file = line.substring(3).trim();
14321
- const ext = path28.extname(file).toLowerCase();
14565
+ const ext = path29.extname(file).toLowerCase();
14322
14566
  if (!SCRIPT_EXTENSIONS.includes(ext)) continue;
14323
14567
  const isRootLevel = !file.includes("/");
14324
14568
  const isScriptsDir = file.startsWith("scripts/") || file.startsWith("patches/");
14325
14569
  if (!isRootLevel && !isScriptsDir) continue;
14326
- const fullPath = path28.join(projectRoot, file);
14327
- if (fs25.existsSync(fullPath)) {
14328
- const content = fs25.readFileSync(fullPath, "utf-8").toLowerCase();
14570
+ const fullPath = path29.join(projectRoot, file);
14571
+ if (fs26.existsSync(fullPath)) {
14572
+ const content = fs26.readFileSync(fullPath, "utf-8").toLowerCase();
14329
14573
  const matchedPattern = SCRIPT_PATCH_PATTERNS.find((p) => content.includes(p.toLowerCase()));
14330
14574
  if (matchedPattern) {
14331
14575
  warnings.push({
@@ -14348,7 +14592,7 @@ function detectGitPatchScripts(projectRoot) {
14348
14592
  if (deletedStdout) {
14349
14593
  const deletedFiles = deletedStdout.split("\n").filter(Boolean);
14350
14594
  for (const file of deletedFiles) {
14351
- const ext = path28.extname(file).toLowerCase();
14595
+ const ext = path29.extname(file).toLowerCase();
14352
14596
  if (SCRIPT_EXTENSIONS.includes(ext)) {
14353
14597
  warnings.push({
14354
14598
  severity: "high",
@@ -14410,21 +14654,21 @@ function detectAllAntiPatterns() {
14410
14654
  // src/engine/contextSnapshot.ts
14411
14655
  init_sessionMemory();
14412
14656
  init_pathValidator();
14413
- import fs26 from "fs";
14414
- import path29 from "path";
14657
+ import fs27 from "fs";
14658
+ import path30 from "path";
14415
14659
  import { execSync as execSync8 } from "child_process";
14416
14660
  var SNAPSHOT_DIR = "context-snapshots";
14417
14661
  function snapshotDir() {
14418
- return path29.join(getProjectRoot(), ".kuma", SNAPSHOT_DIR);
14662
+ return path30.join(getProjectRoot(), ".kuma", SNAPSHOT_DIR);
14419
14663
  }
14420
14664
  function ensureSnapshotDir() {
14421
14665
  const dir = snapshotDir();
14422
- if (!fs26.existsSync(dir)) {
14423
- fs26.mkdirSync(dir, { recursive: true });
14666
+ if (!fs27.existsSync(dir)) {
14667
+ fs27.mkdirSync(dir, { recursive: true });
14424
14668
  }
14425
14669
  }
14426
14670
  function snapshotFilePath(timestamp) {
14427
- return path29.join(snapshotDir(), `${timestamp}.json`);
14671
+ return path30.join(snapshotDir(), `${timestamp}.json`);
14428
14672
  }
14429
14673
  function saveSnapshot(goal) {
14430
14674
  try {
@@ -14445,7 +14689,7 @@ function saveSnapshot(goal) {
14445
14689
  hasConventions: !!summary.hasConventions
14446
14690
  };
14447
14691
  try {
14448
- fs26.writeFileSync(snapshotFilePath(Date.now()), JSON.stringify(snapshot, null, 2), "utf-8");
14692
+ fs27.writeFileSync(snapshotFilePath(Date.now()), JSON.stringify(snapshot, null, 2), "utf-8");
14449
14693
  } catch {
14450
14694
  }
14451
14695
  sessionMemory.recordToolCall("kuma_context", { action: "save", goal: snapshot.goal });
@@ -15238,14 +15482,14 @@ async function main() {
15238
15482
  console.error("");
15239
15483
  let killedCount = 0;
15240
15484
  try {
15241
- const path37 = await import("path");
15242
- const fs34 = await import("fs");
15243
- const lockDir = path37.resolve(process.cwd(), ".kuma/verifier.lock");
15244
- if (fs34.existsSync(lockDir)) {
15245
- const pidFile = path37.join(lockDir, "pid");
15246
- if (fs34.existsSync(pidFile)) {
15485
+ const path38 = await import("path");
15486
+ const fs35 = await import("fs");
15487
+ const lockDir = path38.resolve(process.cwd(), ".kuma/verifier.lock");
15488
+ if (fs35.existsSync(lockDir)) {
15489
+ const pidFile = path38.join(lockDir, "pid");
15490
+ if (fs35.existsSync(pidFile)) {
15247
15491
  try {
15248
- const pid = parseInt(fs34.readFileSync(pidFile, "utf-8"), 10);
15492
+ const pid = parseInt(fs35.readFileSync(pidFile, "utf-8"), 10);
15249
15493
  if (pid && pid !== process.pid) {
15250
15494
  try {
15251
15495
  process.kill(-pid, "SIGKILL");
@@ -15261,7 +15505,7 @@ async function main() {
15261
15505
  } catch {
15262
15506
  }
15263
15507
  }
15264
- fs34.rmSync(lockDir, { recursive: true, force: true });
15508
+ fs35.rmSync(lockDir, { recursive: true, force: true });
15265
15509
  }
15266
15510
  if (killedCount === 0) {
15267
15511
  console.error("\u2705 No running verifications found to kill.");
@@ -15506,6 +15750,12 @@ ${line}
15506
15750
  const root = getProjectRoot2();
15507
15751
  const proj = root.split("/").pop() || "unknown";
15508
15752
  const lines = [`\u{1F43B} [Kuma session brief] ${proj}`];
15753
+ try {
15754
+ const { ensureBackbone: ensureBackbone2, formatBackbone: formatBackbone2 } = await Promise.resolve().then(() => (init_mapBackbone(), mapBackbone_exports));
15755
+ const bb = await ensureBackbone2();
15756
+ if (bb) lines.push(formatBackbone2(bb));
15757
+ } catch {
15758
+ }
15509
15759
  try {
15510
15760
  const { execSync: execSync10 } = await import("child_process");
15511
15761
  const branch = execSync10("git rev-parse --abbrev-ref HEAD", {
@@ -15626,23 +15876,23 @@ ${line}
15626
15876
  });
15627
15877
  const output = formatInitResults(results);
15628
15878
  console.log(output);
15629
- const fs34 = await import("fs");
15630
- const path37 = await import("path");
15631
- const matchaSkills = path37.resolve(process.cwd(), "skills/matcha/SKILL.md");
15632
- const matchaAgents = path37.resolve(
15879
+ const fs35 = await import("fs");
15880
+ const path38 = await import("path");
15881
+ const matchaSkills = path38.resolve(process.cwd(), "skills/matcha/SKILL.md");
15882
+ const matchaAgents = path38.resolve(
15633
15883
  process.cwd(),
15634
15884
  ".agents/skills/matcha/SKILL.md"
15635
15885
  );
15636
- const matchaRootSkills = path37.resolve(
15886
+ const matchaRootSkills = path38.resolve(
15637
15887
  process.cwd(),
15638
15888
  "skills/matcha/SKILL.md"
15639
15889
  );
15640
- const matchaAgentsMd = path37.resolve(process.cwd(), "AGENTS.md");
15641
- const matchaWindsurfRules = path37.resolve(
15890
+ const matchaAgentsMd = path38.resolve(process.cwd(), "AGENTS.md");
15891
+ const matchaWindsurfRules = path38.resolve(
15642
15892
  process.cwd(),
15643
15893
  ".windsurf"
15644
15894
  );
15645
- if (fs34.existsSync(matchaSkills) || fs34.existsSync(matchaAgents) || fs34.existsSync(matchaRootSkills) || fs34.existsSync(matchaAgentsMd) || fs34.existsSync(matchaWindsurfRules)) {
15895
+ if (fs35.existsSync(matchaSkills) || fs35.existsSync(matchaAgents) || fs35.existsSync(matchaRootSkills) || fs35.existsSync(matchaAgentsMd) || fs35.existsSync(matchaWindsurfRules)) {
15646
15896
  console.error(
15647
15897
  "\n\u{1F375} Hey, I see matcha is installed \u2014 they pair well together!"
15648
15898
  );
@@ -15656,13 +15906,13 @@ ${line}
15656
15906
  (async () => {
15657
15907
  try {
15658
15908
  const { generateInitMdContent: generateInitMdContent2 } = await Promise.resolve().then(() => (init_init(), init_exports));
15659
- const fs34 = await import("fs");
15660
- const path37 = await import("path");
15661
- const initMdPath = path37.resolve(process.cwd(), ".kuma/init.md");
15662
- if (!fs34.existsSync(initMdPath)) {
15663
- const kumaDir = path37.dirname(initMdPath);
15664
- if (!fs34.existsSync(kumaDir)) fs34.mkdirSync(kumaDir, { recursive: true });
15665
- fs34.writeFileSync(initMdPath, generateInitMdContent2(), "utf-8");
15909
+ const fs35 = await import("fs");
15910
+ const path38 = await import("path");
15911
+ const initMdPath = path38.resolve(process.cwd(), ".kuma/init.md");
15912
+ if (!fs35.existsSync(initMdPath)) {
15913
+ const kumaDir = path38.dirname(initMdPath);
15914
+ if (!fs35.existsSync(kumaDir)) fs35.mkdirSync(kumaDir, { recursive: true });
15915
+ fs35.writeFileSync(initMdPath, generateInitMdContent2(), "utf-8");
15666
15916
  console.error(`[${SERVER_NAME}] Auto-generated .kuma/init.md`);
15667
15917
  }
15668
15918
  } catch (err) {
@@ -15673,8 +15923,8 @@ ${line}
15673
15923
  try {
15674
15924
  const { detectAgent: detectAgent2, getSkillPath: getSkillPath2, getAgentLabel: getAgentLabel2 } = await Promise.resolve().then(() => (init_agentDetector(), agentDetector_exports));
15675
15925
  const { generateSkill: generateSkill2, getSecondaryFiles: getSecondaryFiles2 } = await Promise.resolve().then(() => (init_skillGenerator(), skillGenerator_exports));
15676
- const fs34 = await import("fs");
15677
- const path37 = await import("path");
15926
+ const fs35 = await import("fs");
15927
+ const path38 = await import("path");
15678
15928
  const detection = detectAgent2();
15679
15929
  if (!detection.primary) {
15680
15930
  console.error(`[${SERVER_NAME}] No AI agent detected \u2014 skipping auto-skill creation`);
@@ -15682,22 +15932,22 @@ ${line}
15682
15932
  }
15683
15933
  const agentType = detection.primary;
15684
15934
  const skillPath = getSkillPath2(agentType);
15685
- const fullPath = path37.resolve(process.cwd(), skillPath);
15686
- if (fs34.existsSync(fullPath)) {
15935
+ const fullPath = path38.resolve(process.cwd(), skillPath);
15936
+ if (fs35.existsSync(fullPath)) {
15687
15937
  console.error(`[${SERVER_NAME}] Skill exists for ${getAgentLabel2(agentType)} \u2014 skipping`);
15688
15938
  return;
15689
15939
  }
15690
- const dir = path37.dirname(fullPath);
15691
- if (!fs34.existsSync(dir)) fs34.mkdirSync(dir, { recursive: true });
15692
- fs34.writeFileSync(fullPath, generateSkill2(agentType), "utf-8");
15940
+ const dir = path38.dirname(fullPath);
15941
+ if (!fs35.existsSync(dir)) fs35.mkdirSync(dir, { recursive: true });
15942
+ fs35.writeFileSync(fullPath, generateSkill2(agentType), "utf-8");
15693
15943
  console.error(`[${SERVER_NAME}] Auto-created ${skillPath} for ${getAgentLabel2(agentType)}`);
15694
15944
  const secondaryFiles = getSecondaryFiles2(agentType);
15695
15945
  for (const sf of secondaryFiles) {
15696
- const sfPath = path37.resolve(process.cwd(), sf.path);
15697
- const sfDir = path37.dirname(sfPath);
15698
- if (!fs34.existsSync(sfPath)) {
15699
- if (!fs34.existsSync(sfDir)) fs34.mkdirSync(sfDir, { recursive: true });
15700
- fs34.writeFileSync(sfPath, sf.content, "utf-8");
15946
+ const sfPath = path38.resolve(process.cwd(), sf.path);
15947
+ const sfDir = path38.dirname(sfPath);
15948
+ if (!fs35.existsSync(sfPath)) {
15949
+ if (!fs35.existsSync(sfDir)) fs35.mkdirSync(sfDir, { recursive: true });
15950
+ fs35.writeFileSync(sfPath, sf.content, "utf-8");
15701
15951
  console.error(`[${SERVER_NAME}] Auto-created ${sf.path}`);
15702
15952
  }
15703
15953
  }