@plumpslabs/kuma 2.4.14 → 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 +1125 -526
  2. package/package.json +1 -1
  3. package/plugin.json +1 -1
package/dist/index.js CHANGED
@@ -1220,8 +1220,8 @@ async function runDoctor() {
1220
1220
  } catch {
1221
1221
  }
1222
1222
  try {
1223
- const { execSync: execSync9 } = await import("child_process");
1224
- const psOutput = execSync9(
1223
+ const { execSync: execSync10 } = await import("child_process");
1224
+ const psOutput = execSync10(
1225
1225
  `ps -eo pid,ppid,command | grep -E "(jest|pnpm test|npm test|yarn test)" | grep -v grep | head -10`,
1226
1226
  { encoding: "utf-8", timeout: 5e3 }
1227
1227
  ).trim();
@@ -3251,6 +3251,18 @@ function parseFallbackRegex(filePath, content) {
3251
3251
  if (impMatch && (impMatch[1].startsWith(".") || impMatch[1].startsWith("/"))) {
3252
3252
  result.imports.push({ source: impMatch[1], symbols: [], isDefault: false });
3253
3253
  }
3254
+ if (!fnMatch && !clsMatch) {
3255
+ const callRe = /([a-zA-Z_][a-zA-Z0-9_]*)\s*\(/g;
3256
+ let m;
3257
+ let count = 0;
3258
+ while ((m = callRe.exec(line)) !== null && count < 5) {
3259
+ const name = m[1];
3260
+ if (!isJsBuiltin(name) && !result.calledSymbols.includes(name)) {
3261
+ result.calledSymbols.push(name);
3262
+ count++;
3263
+ }
3264
+ }
3265
+ }
3254
3266
  }
3255
3267
  return result;
3256
3268
  }
@@ -4577,6 +4589,326 @@ var init_workspaceIntelligence = __esm({
4577
4589
  }
4578
4590
  });
4579
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
+
4794
+ // src/engine/symbolReach.ts
4795
+ var symbolReach_exports = {};
4796
+ __export(symbolReach_exports, {
4797
+ formatReachability: () => formatReachability,
4798
+ symbolReachability: () => symbolReachability
4799
+ });
4800
+ import fs10 from "fs";
4801
+ import path12 from "path";
4802
+ import { execSync as execSync4 } from "child_process";
4803
+ async function graphReach(symbol, limit) {
4804
+ const rows = [];
4805
+ try {
4806
+ const { getDb: getDb2 } = await Promise.resolve().then(() => (init_kumaDb(), kumaDb_exports));
4807
+ const db = await getDb2();
4808
+ const symStmt = db.prepare(
4809
+ `SELECT id, file_path FROM nodes WHERE type IN ('function','class','method') AND (name = ? OR name LIKE ?) LIMIT 5`
4810
+ );
4811
+ symStmt.bind([symbol, `%::${symbol}`]);
4812
+ const symIds = [];
4813
+ while (symStmt.step()) {
4814
+ const r = symStmt.getAsObject();
4815
+ symIds.push({ id: r.id, file: r.file_path });
4816
+ }
4817
+ symStmt.free();
4818
+ if (symIds.length === 0) return [];
4819
+ for (const s of symIds) {
4820
+ const cStmt = db.prepare(
4821
+ `SELECT DISTINCT n_src.file_path as fp FROM edges e JOIN nodes n_src ON n_src.id = e.source_id WHERE e.target_id = ? AND e.type = 'calls' LIMIT 20`
4822
+ );
4823
+ cStmt.bind([s.id]);
4824
+ const callers = /* @__PURE__ */ new Set();
4825
+ while (cStmt.step()) {
4826
+ const fp = cStmt.getAsObject().fp;
4827
+ if (fp) callers.add(fp);
4828
+ }
4829
+ cStmt.free();
4830
+ for (const fp of [...callers, s.file]) {
4831
+ const tStmt = db.prepare(
4832
+ `SELECT DISTINCT n.file_path as tfp FROM edges e JOIN nodes n ON n.id = e.source_id WHERE e.type = 'tests' AND (e.target_id LIKE ? OR e.target_id LIKE ?) LIMIT 5`
4833
+ );
4834
+ tStmt.bind([`%${fp}%`, `%${s.id}%`]);
4835
+ while (tStmt.step()) {
4836
+ const tfp = tStmt.getAsObject().tfp;
4837
+ if (tfp && !rows.some((r) => r.test === tfp)) {
4838
+ rows.push({ test: tfp, via: fp, evidence: `${tfp} tests ${fp} (graph edge)` });
4839
+ }
4840
+ if (rows.length >= limit) break;
4841
+ }
4842
+ tStmt.free();
4843
+ if (rows.length >= limit) break;
4844
+ }
4845
+ if (rows.length >= limit) break;
4846
+ }
4847
+ } catch {
4848
+ }
4849
+ return rows;
4850
+ }
4851
+ function ripgrepReach(symbol, root, limit) {
4852
+ const rows = [];
4853
+ try {
4854
+ const out = execSync4(
4855
+ `grep -rn -F --include="*.ts" --include="*.tsx" --include="*.js" --include="*.jsx" --include="*.py" --include="*.go" --include="*.rs" "${symbol.replace(/"/g, "")}" . 2>/dev/null | grep -v node_modules | grep -v "/dist/" | grep -v "/.git/" | grep -v "/.kuma/" | head -40`,
4856
+ { cwd: root, encoding: "utf-8", timeout: 8e3, maxBuffer: 256 * 1024 }
4857
+ ).trim();
4858
+ if (!out) return [];
4859
+ const callers = /* @__PURE__ */ new Set();
4860
+ for (const line of out.split("\n")) {
4861
+ const m = line.match(/^([^:]+):(\d+):(.*)$/);
4862
+ if (!m) continue;
4863
+ const [, fp, ln, code] = m;
4864
+ if (new RegExp(`\\b${symbol}\\s*\\(`).test(code)) callers.add(`${fp}:${ln}`);
4865
+ }
4866
+ for (const c of [...callers].slice(0, BERBEDA)) {
4867
+ const [fp] = c.split(":");
4868
+ const dir = path12.dirname(fp);
4869
+ const stem = path12.basename(fp, path12.extname(fp)).split(/[-_.]/)[0];
4870
+ try {
4871
+ const dirFull = path12.join(root, dir);
4872
+ if (!fs10.existsSync(dirFull)) continue;
4873
+ for (const f of fs10.readdirSync(dirFull)) {
4874
+ if (!/(\.test\.|\.spec\.|_test\.)/i.test(f)) continue;
4875
+ const low = f.toLowerCase();
4876
+ if (low.includes(stem.toLowerCase()) || low.includes(symbol.toLowerCase())) {
4877
+ const rel = path12.join(dir, f);
4878
+ if (!rows.some((r) => r.test === rel)) {
4879
+ rows.push({ test: rel, via: fp, evidence: `${rel} sibling-matches caller ${fp} (called at ${c})` });
4880
+ }
4881
+ }
4882
+ if (rows.length >= limit) break;
4883
+ }
4884
+ } catch {
4885
+ }
4886
+ if (rows.length >= limit) break;
4887
+ }
4888
+ } catch {
4889
+ }
4890
+ return rows;
4891
+ }
4892
+ async function symbolReachability(symbol, limit = 10, root) {
4893
+ const g = await graphReach(symbol, limit);
4894
+ if (g.length > 0) return { tier: 1, rows: g };
4895
+ return { tier: 2, rows: ripgrepReach(symbol, root || getProjectRoot(), limit) };
4896
+ }
4897
+ function formatReachability(symbol, tier, rows) {
4898
+ if (rows.length === 0) return `\u{1F50E} Reachability \`${symbol}\` (tier ${tier}): no tests reach this symbol.`;
4899
+ const lines = [`\u{1F50E} Reachability \`${symbol}\` (tier ${tier}, ${rows.length} test(s)):`];
4900
+ for (const r of rows.slice(0, 5)) lines.push(` \u2022 \`${r.test}\` via \`${r.via}\` \u2014 ${r.evidence}`);
4901
+ return lines.join("\n");
4902
+ }
4903
+ var BERBEDA;
4904
+ var init_symbolReach = __esm({
4905
+ "src/engine/symbolReach.ts"() {
4906
+ "use strict";
4907
+ init_pathValidator();
4908
+ BERBEDA = 10;
4909
+ }
4910
+ });
4911
+
4580
4912
  // src/engine/testHistory.ts
4581
4913
  var testHistory_exports = {};
4582
4914
  __export(testHistory_exports, {
@@ -4692,17 +5024,17 @@ __export(impactAnalysis_exports, {
4692
5024
  classifyDiffShape: () => classifyDiffShape,
4693
5025
  getIndexerStatus: () => getIndexerStatus
4694
5026
  });
4695
- import fs9 from "fs";
4696
- import path11 from "path";
4697
- import { execSync as execSync4 } from "child_process";
4698
- import fastGlob3 from "fast-glob";
5027
+ import fs11 from "fs";
5028
+ import path13 from "path";
5029
+ import { execSync as execSync5 } from "child_process";
5030
+ import fastGlob4 from "fast-glob";
4699
5031
  function extOf(target) {
4700
- const base = path11.basename(target);
5032
+ const base = path13.basename(target);
4701
5033
  const dot = base.lastIndexOf(".");
4702
5034
  return dot > 0 ? base.slice(dot).toLowerCase() : "";
4703
5035
  }
4704
5036
  function isExampleOrDocName(target) {
4705
- const base = path11.basename(target).toLowerCase();
5037
+ const base = path13.basename(target).toLowerCase();
4706
5038
  return base.endsWith(".example") || base.startsWith(".env") || base.endsWith(".md") || base.endsWith(".txt") || base.endsWith(".rst") || base === "license" || base.startsWith("license.");
4707
5039
  }
4708
5040
  function classifyDiffShape(target, root) {
@@ -4715,7 +5047,7 @@ function classifyDiffShape(target, root) {
4715
5047
  }
4716
5048
  try {
4717
5049
  const cwd = root || getProjectRoot();
4718
- const diff = execSync4(`git diff --unified=0 -- "${target}"`, {
5050
+ const diff = execSync5(`git diff --unified=0 -- "${target}"`, {
4719
5051
  cwd,
4720
5052
  encoding: "utf-8",
4721
5053
  timeout: 4e3,
@@ -4735,7 +5067,7 @@ function classifyDiffShape(target, root) {
4735
5067
  return { shape: "runtime-code", detail: "runtime code change" };
4736
5068
  }
4737
5069
  async function findImportingFiles(targetFile, root) {
4738
- const normTarget = normalizeScope(path11.normalize(targetFile)) || path11.normalize(targetFile);
5070
+ const normTarget = normalizeScope(path13.normalize(targetFile)) || path13.normalize(targetFile);
4739
5071
  try {
4740
5072
  const db = await getDb();
4741
5073
  const targetFileId = `file::${normTarget}`;
@@ -4774,10 +5106,10 @@ async function findImportingFiles(targetFile, root) {
4774
5106
  }
4775
5107
  } catch {
4776
5108
  }
4777
- const baseName = path11.basename(normTarget, path11.extname(normTarget));
4778
- const relTarget = path11.isAbsolute(normTarget) ? path11.relative(root, normTarget) : normTarget;
5109
+ const baseName = path13.basename(normTarget, path13.extname(normTarget));
5110
+ const relTarget = path13.isAbsolute(normTarget) ? path13.relative(root, normTarget) : normTarget;
4779
5111
  try {
4780
- const files = await fastGlob3(
5112
+ const files = await fastGlob4(
4781
5113
  ["**/*.{ts,tsx,js,jsx,mjs,cjs,py,go,rs}"],
4782
5114
  {
4783
5115
  cwd: root,
@@ -4788,14 +5120,14 @@ async function findImportingFiles(targetFile, root) {
4788
5120
  const dependents = [];
4789
5121
  const evidence = [];
4790
5122
  const importRegex = new RegExp(
4791
- `(?:import|from|require\\s*\\(|export\\s+.*from)\\s*['"][^'"]*\\b${baseName}(?:\\.[a-zA-Z0-9]+)?['"]`,
5123
+ `(?:import|from|require\\s*\\()[\\w{}*,.\\s]*['"][^'"]*\\b${baseName}(?:\\.[a-zA-Z0-9]+)?['"]`,
4792
5124
  "i"
4793
5125
  );
4794
5126
  for (const f of files) {
4795
- if (path11.normalize(f) === path11.normalize(relTarget)) continue;
4796
- const fullPath = path11.join(root, f);
5127
+ if (path13.normalize(f) === path13.normalize(relTarget)) continue;
5128
+ const fullPath = path13.join(root, f);
4797
5129
  try {
4798
- const content = fs9.readFileSync(fullPath, "utf-8");
5130
+ const content = fs11.readFileSync(fullPath, "utf-8");
4799
5131
  const lines = content.split("\n");
4800
5132
  const hitIdx = lines.findIndex((l) => importRegex.test(l));
4801
5133
  if (hitIdx >= 0) {
@@ -4811,7 +5143,7 @@ async function findImportingFiles(targetFile, root) {
4811
5143
  }
4812
5144
  }
4813
5145
  async function findRelatedTests(targetFile, root, owningPackage, additionalDependents = [], exactOnly = false) {
4814
- const normTarget = normalizeScope(path11.normalize(targetFile)) || path11.normalize(targetFile);
5146
+ const normTarget = normalizeScope(path13.normalize(targetFile)) || path13.normalize(targetFile);
4815
5147
  try {
4816
5148
  const db = await getDb();
4817
5149
  const targetFileId = `file::${normTarget}`;
@@ -4835,13 +5167,13 @@ async function findRelatedTests(targetFile, root, owningPackage, additionalDepen
4835
5167
  }
4836
5168
  } catch {
4837
5169
  }
4838
- const baseName = path11.basename(normTarget, path11.extname(normTarget));
5170
+ const baseName = path13.basename(normTarget, path13.extname(normTarget));
4839
5171
  const testFiles = [];
4840
5172
  const stems = /* @__PURE__ */ new Set();
4841
5173
  if (baseName) stems.add(baseName);
4842
5174
  if (!exactOnly) {
4843
5175
  for (const dep of additionalDependents.slice(0, 3)) {
4844
- const depBase = path11.basename(dep, path11.extname(dep));
5176
+ const depBase = path13.basename(dep, path13.extname(dep));
4845
5177
  if (depBase) stems.add(depBase);
4846
5178
  }
4847
5179
  }
@@ -4857,7 +5189,7 @@ async function findRelatedTests(targetFile, root, owningPackage, additionalDepen
4857
5189
  );
4858
5190
  }
4859
5191
  try {
4860
- const matches = await fastGlob3(testPatterns, {
5192
+ const matches = await fastGlob4(testPatterns, {
4861
5193
  cwd: root,
4862
5194
  ignore: ["**/node_modules/**", "**/dist/**", "**/.git/**", "**/.kuma/**"],
4863
5195
  onlyFiles: true
@@ -4876,13 +5208,13 @@ async function findRelatedTests(targetFile, root, owningPackage, additionalDepen
4876
5208
  `**/__tests__/**/*${stem}*.*`
4877
5209
  );
4878
5210
  }
4879
- const pkgTests = await fastGlob3(pkgPatterns, {
4880
- cwd: path11.join(root, owningPackage.path),
5211
+ const pkgTests = await fastGlob4(pkgPatterns, {
5212
+ cwd: path13.join(root, owningPackage.path),
4881
5213
  ignore: ["**/node_modules/**", "**/dist/**"],
4882
5214
  onlyFiles: true
4883
5215
  });
4884
5216
  for (const pt of pkgTests) {
4885
- const fullRel = path11.join(owningPackage.path, pt);
5217
+ const fullRel = path13.join(owningPackage.path, pt);
4886
5218
  if (!testFiles.includes(fullRel)) {
4887
5219
  testFiles.push(fullRel);
4888
5220
  }
@@ -4933,18 +5265,29 @@ function assessRisk(target, targetType, directDependents, downstreamPackages, af
4933
5265
  }
4934
5266
  async function getIndexerStatus() {
4935
5267
  let graphEdges = false;
5268
+ let backboneOnly = false;
4936
5269
  try {
4937
5270
  const db = await getDb();
4938
5271
  const stmt = db.prepare(`SELECT COUNT(*) as cnt FROM edges WHERE type IN ('imports','depends_on','calls','tests')`);
4939
5272
  if (stmt.step()) graphEdges = Number(stmt.getAsObject().cnt) > 0;
4940
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;
4941
5283
  } catch {
4942
5284
  }
4943
5285
  return {
4944
5286
  tier: graphEdges ? 1 : 2,
4945
5287
  graphEdges,
5288
+ backboneOnly,
4946
5289
  languages: ["ts", "tsx", "js", "jsx", "mjs", "cjs", "py", "go", "rs"],
4947
- 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)"
4948
5291
  };
4949
5292
  }
4950
5293
  async function calculateBlastRadius(target, options = {}) {
@@ -4970,6 +5313,13 @@ async function calculateBlastRadius(target, options = {}) {
4970
5313
  const rev = getReverseDependencies(owningPackage.name, wsInfo);
4971
5314
  downstreamPackages.push(...rev.map((p) => p.name));
4972
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
+ }
4973
5323
  let directDependents = [];
4974
5324
  let evidence = [];
4975
5325
  if (targetType === "file" || targetType === "symbol") {
@@ -4981,6 +5331,20 @@ async function calculateBlastRadius(target, options = {}) {
4981
5331
  const nonRuntime = diffShape !== "runtime-code";
4982
5332
  const affectedTests = await findRelatedTests(target, root, owningPackage, directDependents, nonRuntime);
4983
5333
  let testReasons = /* @__PURE__ */ new Map();
5334
+ if (targetType === "symbol") {
5335
+ try {
5336
+ const { symbolReachability: symbolReachability2 } = await Promise.resolve().then(() => (init_symbolReach(), symbolReach_exports));
5337
+ const reach = await symbolReachability2(target, 10, root);
5338
+ for (const r of reach.rows) {
5339
+ if (!affectedTests.includes(r.test)) {
5340
+ affectedTests.push(r.test);
5341
+ testReasons.set(r.test, `reachability tier ${reach.tier}: ${r.evidence.substring(0, 80)}`);
5342
+ }
5343
+ evidence.push(r.evidence);
5344
+ }
5345
+ } catch {
5346
+ }
5347
+ }
4984
5348
  try {
4985
5349
  const { rankTestsByHistory: rankTestsByHistory2 } = await Promise.resolve().then(() => (init_testHistory(), testHistory_exports));
4986
5350
  const ranked = await rankTestsByHistory2(target, affectedTests);
@@ -6195,27 +6559,27 @@ async function codebaseSearchFallback(query, limit = 20) {
6195
6559
  if (results.length >= limit || depth > MAX_WALK_DEPTH) return;
6196
6560
  let entries = [];
6197
6561
  try {
6198
- entries = fs32.readdirSync(dir);
6562
+ entries = fs35.readdirSync(dir);
6199
6563
  } catch {
6200
6564
  return;
6201
6565
  }
6202
6566
  for (const entry of entries) {
6203
6567
  if (entry.startsWith(".") || entry === "node_modules" || entry === "dist" || entry === "build") continue;
6204
- const full = path35.join(dir, entry);
6568
+ const full = path38.join(dir, entry);
6205
6569
  try {
6206
- const stat = fs32.statSync(full);
6570
+ const stat = fs35.statSync(full);
6207
6571
  if (stat.isDirectory()) {
6208
6572
  walk2(full, depth + 1);
6209
6573
  } else if (entry.toLowerCase().includes(query.toLowerCase())) {
6210
- results.push(path35.relative(root, full));
6574
+ results.push(path38.relative(root, full));
6211
6575
  }
6212
6576
  } catch {
6213
6577
  }
6214
6578
  }
6215
6579
  };
6216
6580
  var walk = walk2;
6217
- const fs32 = await import("fs");
6218
- const path35 = await import("path");
6581
+ const fs35 = await import("fs");
6582
+ const path38 = await import("path");
6219
6583
  const root = process.cwd();
6220
6584
  const results = [];
6221
6585
  const MAX_WALK_DEPTH = 8;
@@ -6348,9 +6712,9 @@ ${summary}`;
6348
6712
  }
6349
6713
  async function codebaseImpactFallback(target) {
6350
6714
  try {
6351
- const { execSync: execSync9 } = await import("child_process");
6715
+ const { execSync: execSync10 } = await import("child_process");
6352
6716
  const root = process.cwd();
6353
- const grepResult = execSync9(
6717
+ const grepResult = execSync10(
6354
6718
  `grep -rn ${grepIncludeFlags()} --include="*.json" --include="*.md" -l "${target.replace(/"/g, '\\"')}" . 2>/dev/null | grep -v node_modules | grep -v .git | grep -v dist | grep -v .kuma | head -50`,
6355
6719
  { cwd: root, encoding: "utf-8", timeout: 5e3, maxBuffer: 256 * 1024 }
6356
6720
  ).trim();
@@ -6496,9 +6860,9 @@ __export(kumaShared_exports, {
6496
6860
  isReadTool: () => isReadTool,
6497
6861
  isTestTool: () => isTestTool
6498
6862
  });
6499
- import { execSync as execSync5 } from "child_process";
6500
- import fs10 from "fs";
6501
- import path12 from "path";
6863
+ import { execSync as execSync6 } from "child_process";
6864
+ import fs12 from "fs";
6865
+ import path14 from "path";
6502
6866
  function isEditTool(toolName) {
6503
6867
  const n = (toolName || "").toLowerCase();
6504
6868
  return n.includes("edit") || n.includes("write") || n.includes("patch") || n.includes("apply") || n.includes("replace");
@@ -6536,7 +6900,7 @@ function getSessionStats(inputGoal) {
6536
6900
  function getGitDiffStat(timeout = 3e3) {
6537
6901
  try {
6538
6902
  const root = getProjectRoot();
6539
- return execSync5("git diff --stat", {
6903
+ return execSync6("git diff --stat", {
6540
6904
  cwd: root,
6541
6905
  encoding: "utf-8",
6542
6906
  timeout
@@ -6549,7 +6913,7 @@ function getUncommittedFiles(timeout = 3e3) {
6549
6913
  const files = /* @__PURE__ */ new Set();
6550
6914
  try {
6551
6915
  const root = getProjectRoot();
6552
- const porcelain = execSync5("git status --porcelain", {
6916
+ const porcelain = execSync6("git status --porcelain", {
6553
6917
  cwd: root,
6554
6918
  encoding: "utf-8",
6555
6919
  timeout,
@@ -6568,17 +6932,17 @@ function getBranchCommittedFiles(timeout = 5e3) {
6568
6932
  let base = "";
6569
6933
  try {
6570
6934
  const root = getProjectRoot();
6571
- const branch = execSync5("git rev-parse --abbrev-ref HEAD", {
6935
+ const branch = execSync6("git rev-parse --abbrev-ref HEAD", {
6572
6936
  cwd: root,
6573
6937
  encoding: "utf-8",
6574
6938
  timeout,
6575
6939
  stdio: ["pipe", "pipe", "pipe"]
6576
6940
  }).trim();
6577
- const baseRef = execSync5(
6941
+ const baseRef = execSync6(
6578
6942
  `git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null || echo origin/${branch === "main" || branch === "master" ? "HEAD" : "main"}`,
6579
6943
  { cwd: root, encoding: "utf-8", timeout, stdio: ["pipe", "pipe", "pipe"] }
6580
6944
  ).trim().replace("refs/remotes/", "");
6581
- const mergeBase = execSync5(`git merge-base HEAD ${baseRef} 2>/dev/null || git rev-list --max-parents=0 HEAD`, {
6945
+ const mergeBase = execSync6(`git merge-base HEAD ${baseRef} 2>/dev/null || git rev-list --max-parents=0 HEAD`, {
6582
6946
  cwd: root,
6583
6947
  encoding: "utf-8",
6584
6948
  timeout,
@@ -6586,7 +6950,7 @@ function getBranchCommittedFiles(timeout = 5e3) {
6586
6950
  }).trim().split("\n")[0];
6587
6951
  base = baseRef;
6588
6952
  if (mergeBase) {
6589
- const out = execSync5(`git diff --name-only ${mergeBase} HEAD`, {
6953
+ const out = execSync6(`git diff --name-only ${mergeBase} HEAD`, {
6590
6954
  cwd: root,
6591
6955
  encoding: "utf-8",
6592
6956
  timeout,
@@ -6604,10 +6968,10 @@ function hasVerificationEvidence(toolCalls) {
6604
6968
  }
6605
6969
  function hasVerificationInHookLog(hours = 24) {
6606
6970
  try {
6607
- const fp = path12.join(getProjectRoot(), ".kuma", "injections.jsonl");
6608
- if (!fs10.existsSync(fp)) return false;
6971
+ const fp = path14.join(getProjectRoot(), ".kuma", "injections.jsonl");
6972
+ if (!fs12.existsSync(fp)) return false;
6609
6973
  const cutoff = Date.now() - hours * 60 * 60 * 1e3;
6610
- const lines = fs10.readFileSync(fp, "utf-8").split("\n");
6974
+ const lines = fs12.readFileSync(fp, "utf-8").split("\n");
6611
6975
  for (const line of lines) {
6612
6976
  if (!line.trim()) continue;
6613
6977
  try {
@@ -6710,7 +7074,7 @@ function detectTestWeakening(files, root) {
6710
7074
  for (const f of files) {
6711
7075
  if (!TEST_FILE_PATTERN.test(f)) continue;
6712
7076
  try {
6713
- const diff = execSync5(`git diff --unified=0 -- "${f}"`, {
7077
+ const diff = execSync6(`git diff --unified=0 -- "${f}"`, {
6714
7078
  cwd,
6715
7079
  encoding: "utf-8",
6716
7080
  timeout: 4e3,
@@ -6749,19 +7113,19 @@ __export(kumaMemory_exports, {
6749
7113
  scoreMemoryRelevance: () => scoreMemoryRelevance,
6750
7114
  shouldRecordDecision: () => shouldRecordDecision
6751
7115
  });
6752
- import fs11 from "fs";
6753
- import path13 from "path";
7116
+ import fs13 from "fs";
7117
+ import path15 from "path";
6754
7118
  function scoreMemoryRelevance(context, limit = 5) {
6755
7119
  const results = [];
6756
- const kumaDir = path13.join(getProjectRoot(), MEMORY_DIR);
6757
- if (!fs11.existsSync(kumaDir)) return [];
7120
+ const kumaDir = path15.join(getProjectRoot(), MEMORY_DIR);
7121
+ if (!fs13.existsSync(kumaDir)) return [];
6758
7122
  const terms = Array.from(new Set(context.toLowerCase().split(/[\s/._-]+/).filter((w) => w.length > 2)));
6759
7123
  if (terms.length === 0) return [];
6760
7124
  try {
6761
- const files = fs11.readdirSync(kumaDir).filter((f) => f.endsWith(".md"));
7125
+ const files = fs13.readdirSync(kumaDir).filter((f) => f.endsWith(".md"));
6762
7126
  for (const file of files) {
6763
7127
  try {
6764
- const content = fs11.readFileSync(path13.join(kumaDir, file), "utf-8");
7128
+ const content = fs13.readFileSync(path15.join(kumaDir, file), "utf-8");
6765
7129
  const lower = content.toLowerCase();
6766
7130
  let matchCount = 0;
6767
7131
  for (const term of terms) {
@@ -6943,8 +7307,8 @@ __export(cacheFreshness_exports, {
6943
7307
  isStale: () => isStale,
6944
7308
  markDirty: () => markDirty
6945
7309
  });
6946
- import fs12 from "fs";
6947
- import path14 from "path";
7310
+ import fs14 from "fs";
7311
+ import path16 from "path";
6948
7312
  function isStale(savedAtMs, ttlMs, nowMs = Date.now()) {
6949
7313
  if (!savedAtMs) return true;
6950
7314
  return nowMs - savedAtMs > ttlMs;
@@ -6957,13 +7321,13 @@ function formatAge(savedAtMs, nowMs = Date.now()) {
6957
7321
  return `${Math.floor(s / 86400)}d`;
6958
7322
  }
6959
7323
  function dirtyPath() {
6960
- return path14.join(getProjectRoot(), DIRTY_FILE);
7324
+ return path16.join(getProjectRoot(), DIRTY_FILE);
6961
7325
  }
6962
7326
  function loadDirty() {
6963
7327
  try {
6964
7328
  const fp = dirtyPath();
6965
- if (fs12.existsSync(fp)) {
6966
- const parsed = JSON.parse(fs12.readFileSync(fp, "utf-8"));
7329
+ if (fs14.existsSync(fp)) {
7330
+ const parsed = JSON.parse(fs14.readFileSync(fp, "utf-8"));
6967
7331
  if (parsed && typeof parsed === "object") return parsed;
6968
7332
  }
6969
7333
  } catch {
@@ -6973,14 +7337,14 @@ function loadDirty() {
6973
7337
  function markDirty(filePath) {
6974
7338
  try {
6975
7339
  const fp = dirtyPath();
6976
- const dir = path14.dirname(fp);
6977
- if (!fs12.existsSync(dir)) fs12.mkdirSync(dir, { recursive: true });
7340
+ const dir = path16.dirname(fp);
7341
+ if (!fs14.existsSync(dir)) fs14.mkdirSync(dir, { recursive: true });
6978
7342
  const dirty = loadDirty();
6979
7343
  dirty[filePath] = Date.now();
6980
7344
  const keys = Object.keys(dirty).sort((a, b) => dirty[b] - dirty[a]).slice(0, 200);
6981
7345
  const bounded = {};
6982
7346
  for (const k of keys) bounded[k] = dirty[k];
6983
- fs12.writeFileSync(fp, JSON.stringify(bounded), "utf-8");
7347
+ fs14.writeFileSync(fp, JSON.stringify(bounded), "utf-8");
6984
7348
  } catch {
6985
7349
  }
6986
7350
  }
@@ -6990,7 +7354,7 @@ function getDirtyFiles() {
6990
7354
  function clearDirty() {
6991
7355
  try {
6992
7356
  const fp = dirtyPath();
6993
- if (fs12.existsSync(fp)) fs12.rmSync(fp, { force: true });
7357
+ if (fs14.existsSync(fp)) fs14.rmSync(fp, { force: true });
6994
7358
  } catch {
6995
7359
  }
6996
7360
  }
@@ -7010,8 +7374,8 @@ var codeReuseEngine_exports = {};
7010
7374
  __export(codeReuseEngine_exports, {
7011
7375
  findReusableSymbols: () => findReusableSymbols
7012
7376
  });
7013
- import path15 from "path";
7014
- import fs13 from "fs";
7377
+ import path17 from "path";
7378
+ import fs15 from "fs";
7015
7379
  async function findReusableSymbols(query, scope) {
7016
7380
  const cleanQuery = query.trim().toLowerCase();
7017
7381
  const searchTokens = cleanQuery.replace(/[^a-zA-Z0-9_\s]/g, " ").split(/\s+/).filter((t) => t.length >= 2);
@@ -7134,7 +7498,7 @@ function detectRecommendedUtilDirectory() {
7134
7498
  "utils"
7135
7499
  ];
7136
7500
  for (const c of candidates) {
7137
- if (fs13.existsSync(path15.resolve(root, c))) {
7501
+ if (fs15.existsSync(path17.resolve(root, c))) {
7138
7502
  return c;
7139
7503
  }
7140
7504
  }
@@ -7153,7 +7517,7 @@ var domainClusterEngine_exports = {};
7153
7517
  __export(domainClusterEngine_exports, {
7154
7518
  buildSubsystemClusters: () => buildSubsystemClusters
7155
7519
  });
7156
- import path16 from "path";
7520
+ import path18 from "path";
7157
7521
  async function buildSubsystemClusters() {
7158
7522
  const db = await getDb();
7159
7523
  const fileStmt = db.prepare(`
@@ -7230,7 +7594,7 @@ async function buildSubsystemClusters() {
7230
7594
  for (const [cKey, files] of clusterFileMap.entries()) {
7231
7595
  for (const f of files) {
7232
7596
  fileToCluster.set(f, cKey);
7233
- fileToCluster.set(path16.normalize(f), cKey);
7597
+ fileToCluster.set(path18.normalize(f), cKey);
7234
7598
  }
7235
7599
  }
7236
7600
  const clusterInteractions = /* @__PURE__ */ new Map();
@@ -7238,8 +7602,8 @@ async function buildSubsystemClusters() {
7238
7602
  const srcFile = extractFilePathFromNodeId(e.source);
7239
7603
  const tgtFile = extractFilePathFromNodeId(e.target);
7240
7604
  if (!srcFile || !tgtFile) continue;
7241
- const srcCluster = fileToCluster.get(srcFile) || fileToCluster.get(path16.normalize(srcFile));
7242
- const tgtCluster = fileToCluster.get(tgtFile) || fileToCluster.get(path16.normalize(tgtFile));
7605
+ const srcCluster = fileToCluster.get(srcFile) || fileToCluster.get(path18.normalize(srcFile));
7606
+ const tgtCluster = fileToCluster.get(tgtFile) || fileToCluster.get(path18.normalize(tgtFile));
7243
7607
  if (srcCluster && tgtCluster && srcCluster !== tgtCluster) {
7244
7608
  const pairKey = `${srcCluster}->${tgtCluster}`;
7245
7609
  const stats = clusterInteractions.get(pairKey) || { calls: 0, imports: 0 };
@@ -7261,13 +7625,13 @@ async function buildSubsystemClusters() {
7261
7625
  const clusterId = nodeId("feature_domain", cKey);
7262
7626
  const name = formatClusterName(cKey);
7263
7627
  const role = inferSubsystemRole(cKey, files);
7264
- const entrypoints = files.filter((f) => /index|main|server|app|engine|root/i.test(path16.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);
7265
7629
  if (entrypoints.length === 0 && files.length > 0) {
7266
7630
  entrypoints.push(files[0]);
7267
7631
  }
7268
7632
  const allSyms = [];
7269
7633
  for (const f of files) {
7270
- const syms = fileSymbols.get(f) || fileSymbols.get(path16.normalize(f)) || [];
7634
+ const syms = fileSymbols.get(f) || fileSymbols.get(path18.normalize(f)) || [];
7271
7635
  for (const s of syms) {
7272
7636
  if (!allSyms.includes(s)) allSyms.push(s);
7273
7637
  }
@@ -7446,7 +7810,7 @@ function inferSubsystemRole(key, files) {
7446
7810
  if (k.includes("util") || k.includes("common")) {
7447
7811
  return "Shared path validation, configuration loading, and platform detection helpers.";
7448
7812
  }
7449
- return `Core subsystem handling ${files.slice(0, 3).map((f) => path16.basename(f)).join(", ")}.`;
7813
+ return `Core subsystem handling ${files.slice(0, 3).map((f) => path18.basename(f)).join(", ")}.`;
7450
7814
  }
7451
7815
  function inferTypedVerb(sourceKey, targetKey, _stats) {
7452
7816
  const src = sourceKey.toLowerCase();
@@ -7525,18 +7889,18 @@ __export(domainRules_exports, {
7525
7889
  readLayer: () => readLayer,
7526
7890
  writeLayer: () => writeLayer
7527
7891
  });
7528
- import fs14 from "fs";
7529
- import path17 from "path";
7892
+ import fs16 from "fs";
7893
+ import path19 from "path";
7530
7894
  function layerFilePath(layer) {
7531
- return path17.join(getProjectRoot(), ".kuma", LAYER_FILES[layer].filename);
7895
+ return path19.join(getProjectRoot(), ".kuma", LAYER_FILES[layer].filename);
7532
7896
  }
7533
7897
  function ensureLayerFile(layer) {
7534
7898
  const fp = layerFilePath(layer);
7535
- if (!fs14.existsSync(fp)) {
7899
+ if (!fs16.existsSync(fp)) {
7536
7900
  const template = layer === "arch_flow" ? ARCH_FLOW_TEMPLATE : GOTCHAS_TEMPLATE;
7537
- const dir = path17.dirname(fp);
7538
- if (!fs14.existsSync(dir)) fs14.mkdirSync(dir, { recursive: true });
7539
- fs14.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");
7540
7904
  console.error(`[DomainRules] Auto-created ${LAYER_FILES[layer].filename}`);
7541
7905
  }
7542
7906
  return fp;
@@ -7544,7 +7908,7 @@ function ensureLayerFile(layer) {
7544
7908
  function readLayer(layer) {
7545
7909
  try {
7546
7910
  const fp = ensureLayerFile(layer);
7547
- return fs14.readFileSync(fp, "utf-8");
7911
+ return fs16.readFileSync(fp, "utf-8");
7548
7912
  } catch (err) {
7549
7913
  return `Error reading ${layer}: ${err}`;
7550
7914
  }
@@ -7552,7 +7916,7 @@ function readLayer(layer) {
7552
7916
  function writeLayer(layer, content) {
7553
7917
  try {
7554
7918
  const fp = ensureLayerFile(layer);
7555
- fs14.writeFileSync(fp, content, "utf-8");
7919
+ fs16.writeFileSync(fp, content, "utf-8");
7556
7920
  const label = LAYER_FILES[layer].label;
7557
7921
  sessionMemory.recordToolCall("kuma_memory", { action: `write_${layer}` });
7558
7922
  return `\u2705 **${label}** updated successfully.`;
@@ -7563,9 +7927,9 @@ function writeLayer(layer, content) {
7563
7927
  function appendToLayer(layer, entry) {
7564
7928
  try {
7565
7929
  const fp = ensureLayerFile(layer);
7566
- const existing = fs14.readFileSync(fp, "utf-8");
7930
+ const existing = fs16.readFileSync(fp, "utf-8");
7567
7931
  const newContent = existing.trimEnd() + "\n\n" + entry.trim() + "\n";
7568
- fs14.writeFileSync(fp, newContent, "utf-8");
7932
+ fs16.writeFileSync(fp, newContent, "utf-8");
7569
7933
  return `\u2705 Entry added to **${LAYER_FILES[layer].label}**.`;
7570
7934
  } catch (err) {
7571
7935
  return `\u274C Failed to append: ${err}`;
@@ -7575,7 +7939,7 @@ function getActiveGotchas() {
7575
7939
  const results = [];
7576
7940
  try {
7577
7941
  const fp = ensureLayerFile("gotcha");
7578
- const content = fs14.readFileSync(fp, "utf-8");
7942
+ const content = fs16.readFileSync(fp, "utf-8");
7579
7943
  const lines = content.split("\n");
7580
7944
  let currentSection = "";
7581
7945
  let currentFilePath = "";
@@ -7611,9 +7975,9 @@ function getActiveGotchas() {
7611
7975
  function checkFileGotchas(filePath) {
7612
7976
  const gotchas = getActiveGotchas();
7613
7977
  const warnings = [];
7614
- const base = path17.basename(filePath);
7978
+ const base = path19.basename(filePath);
7615
7979
  for (const g of gotchas) {
7616
- const gBase = path17.basename(g.filePath);
7980
+ const gBase = path19.basename(g.filePath);
7617
7981
  if (filePath.includes(g.filePath) || g.filePath.includes(filePath) || base && gBase && base === gBase) {
7618
7982
  const icon = g.severity === "critical" ? "\u{1F534}" : g.severity === "high" ? "\u{1F7E0}" : g.severity === "medium" ? "\u{1F7E1}" : "\u{1F7E2}";
7619
7983
  warnings.push(`${icon} **Gotcha**: ${g.description} (${g.severity})`);
@@ -7713,8 +8077,8 @@ __export(kumaInject_exports, {
7713
8077
  parseHookInput: () => parseHookInput,
7714
8078
  trackFileEditLoop: () => trackFileEditLoop
7715
8079
  });
7716
- import fs15 from "fs";
7717
- import path18 from "path";
8080
+ import fs17 from "fs";
8081
+ import path20 from "path";
7718
8082
  function hashFileContent(filePath) {
7719
8083
  return hashFile(filePath);
7720
8084
  }
@@ -7725,10 +8089,10 @@ function isGotchaFresh(storedHash, currentHash) {
7725
8089
  }
7726
8090
  async function getFreshGotchasForFile(filePath, limit = 5, includeStale = false) {
7727
8091
  const root = getProjectRoot();
7728
- const base = path18.basename(filePath);
8092
+ const base = path20.basename(filePath);
7729
8093
  try {
7730
- const dbFile = path18.join(root, ".kuma", "kuma.db");
7731
- if (fs15.existsSync(dbFile)) {
8094
+ const dbFile = path20.join(root, ".kuma", "kuma.db");
8095
+ if (fs17.existsSync(dbFile)) {
7732
8096
  const { getDb: getDb2 } = await Promise.resolve().then(() => (init_kumaDb(), kumaDb_exports));
7733
8097
  const db = await getDb2();
7734
8098
  const stmt = db.prepare(`
@@ -7769,11 +8133,11 @@ async function getFreshGotchasForFile(filePath, limit = 5, includeStale = false)
7769
8133
  } catch {
7770
8134
  }
7771
8135
  try {
7772
- if (!fs15.existsSync(path18.join(root, ".kuma"))) return [];
8136
+ if (!fs17.existsSync(path20.join(root, ".kuma"))) return [];
7773
8137
  const { getActiveGotchas: getActiveGotchas2 } = await Promise.resolve().then(() => (init_domainRules(), domainRules_exports));
7774
8138
  const allGotchas = getActiveGotchas2();
7775
8139
  const matched = allGotchas.filter(
7776
- (g) => g.filePath.includes(filePath) || filePath.includes(g.filePath) || base && path18.basename(g.filePath) === base
8140
+ (g) => g.filePath.includes(filePath) || filePath.includes(g.filePath) || base && path20.basename(g.filePath) === base
7777
8141
  );
7778
8142
  if (matched.length > 0) {
7779
8143
  return matched.slice(0, limit).map((g) => ({
@@ -7792,8 +8156,8 @@ async function getFreshGotchasForFile(filePath, limit = 5, includeStale = false)
7792
8156
  async function getFileTrace(filePath, limit = 8) {
7793
8157
  try {
7794
8158
  const root = getProjectRoot();
7795
- const dbFile = path18.join(root, ".kuma", "kuma.db");
7796
- if (!fs15.existsSync(dbFile)) return [];
8159
+ const dbFile = path20.join(root, ".kuma", "kuma.db");
8160
+ if (!fs17.existsSync(dbFile)) return [];
7797
8161
  const { getDb: getDb2 } = await Promise.resolve().then(() => (init_kumaDb(), kumaDb_exports));
7798
8162
  const db = await getDb2();
7799
8163
  const stmt = db.prepare(`
@@ -7803,7 +8167,7 @@ async function getFileTrace(filePath, limit = 8) {
7803
8167
  ORDER BY cl.created_at DESC
7804
8168
  LIMIT ?
7805
8169
  `);
7806
- stmt.bind([`%${path18.basename(filePath)}%`, limit]);
8170
+ stmt.bind([`%${path20.basename(filePath)}%`, limit]);
7807
8171
  const rows = [];
7808
8172
  while (stmt.step()) rows.push(stmt.getAsObject());
7809
8173
  stmt.free();
@@ -7821,7 +8185,7 @@ async function getFileTrace(filePath, limit = 8) {
7821
8185
  function formatFileTrace(entries, filePath) {
7822
8186
  if (entries.length === 0) return "";
7823
8187
  const lines = [
7824
- `\u{1F570}\uFE0F **Why is ${path18.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:`
7825
8189
  ];
7826
8190
  for (const e of entries) {
7827
8191
  const date = new Date((e.createdAt || 0) * 1e3).toLocaleDateString("en-US", {
@@ -7837,12 +8201,12 @@ function formatFileTrace(entries, filePath) {
7837
8201
  async function getDecisionsForFile(filePath, limit = 3) {
7838
8202
  const decisions = [];
7839
8203
  const root = getProjectRoot();
7840
- const base = path18.basename(filePath);
8204
+ const base = path20.basename(filePath);
7841
8205
  const baseWithoutExt = base.replace(/\.[^.]+$/, "");
7842
8206
  try {
7843
- const decisionsMdPath = path18.join(root, ".kuma", "memories", "decisions.md");
7844
- if (fs15.existsSync(decisionsMdPath)) {
7845
- const content = fs15.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");
7846
8210
  const sections = content.split(/^##\s+/m);
7847
8211
  for (const section of sections) {
7848
8212
  if (!section.trim() || section.startsWith("# ")) continue;
@@ -7947,13 +8311,13 @@ async function getRelevantContext(filePath, goal) {
7947
8311
  if (traceStr) parts.push(traceStr);
7948
8312
  try {
7949
8313
  const root = getProjectRoot();
7950
- if (fs15.existsSync(path18.join(root, ".kuma", "kuma.db"))) {
8314
+ if (fs17.existsSync(path20.join(root, ".kuma", "kuma.db"))) {
7951
8315
  const { getDb: getDb2 } = await Promise.resolve().then(() => (init_kumaDb(), kumaDb_exports));
7952
8316
  const db = await getDb2();
7953
8317
  const stmt = db.prepare(
7954
8318
  `SELECT COUNT(*) FROM known_gotchas WHERE status = 'resolved' AND file_path LIKE ?`
7955
8319
  );
7956
- stmt.bind([`%${path18.basename(filePath)}%`]);
8320
+ stmt.bind([`%${path20.basename(filePath)}%`]);
7957
8321
  const found = stmt.step();
7958
8322
  const count = found ? Number(stmt.getAsObject()["COUNT(*)"]) : 0;
7959
8323
  stmt.free();
@@ -7964,7 +8328,7 @@ async function getRelevantContext(filePath, goal) {
7964
8328
  } catch {
7965
8329
  }
7966
8330
  if (gotchas.length > 0) {
7967
- const scopeHint = path18.basename(path18.dirname(filePath)) || "current change";
8331
+ const scopeHint = path20.basename(path20.dirname(filePath)) || "current change";
7968
8332
  parts.push(
7969
8333
  `\u2705 AFTER editing, verify: kuma_safety({ action: "verify", scope: "${scopeHint}" })`
7970
8334
  );
@@ -7980,11 +8344,11 @@ async function getRelevantContext(filePath, goal) {
7980
8344
  async function getFileSummary2(filePath) {
7981
8345
  try {
7982
8346
  const root = getProjectRoot();
7983
- const dbFile = path18.join(root, ".kuma", "kuma.db");
7984
- if (!fs15.existsSync(dbFile)) return null;
8347
+ const dbFile = path20.join(root, ".kuma", "kuma.db");
8348
+ if (!fs17.existsSync(dbFile)) return null;
7985
8349
  const { getDb: getDb2 } = await Promise.resolve().then(() => (init_kumaDb(), kumaDb_exports));
7986
8350
  const db = await getDb2();
7987
- const base = path18.basename(filePath);
8351
+ const base = path20.basename(filePath);
7988
8352
  const stmt = db.prepare(`
7989
8353
  SELECT
7990
8354
  (SELECT COUNT(*) FROM known_gotchas WHERE status = 'active' AND (file_path = ? OR file_path LIKE ?)) as active_gotchas,
@@ -8018,9 +8382,9 @@ function parseHookInput(raw) {
8018
8382
  const root = data && typeof data === "object" ? data : {};
8019
8383
  const ti = root.tool_input && typeof root.tool_input === "object" ? root.tool_input : {};
8020
8384
  const args = root.args && typeof root.args === "object" ? root.args : {};
8021
- const paths = /* @__PURE__ */ new Set();
8385
+ const paths2 = /* @__PURE__ */ new Set();
8022
8386
  const add = (p) => {
8023
- if (typeof p === "string" && p.trim()) paths.add(p.trim());
8387
+ if (typeof p === "string" && p.trim()) paths2.add(p.trim());
8024
8388
  };
8025
8389
  add(ti.file_path);
8026
8390
  add(ti.new_file_path);
@@ -8038,7 +8402,7 @@ function parseHookInput(raw) {
8038
8402
  add(args.file);
8039
8403
  const cmd = (typeof ti.command === "string" ? ti.command : void 0) ?? (typeof root.command === "string" ? root.command : void 0) ?? (typeof root.commandline === "string" ? root.commandline : void 0) ?? (typeof args.command === "string" ? args.command : void 0);
8040
8404
  const goal = (typeof ti.goal === "string" ? ti.goal : void 0) ?? (typeof root.goal === "string" ? root.goal : void 0);
8041
- const out = { filePaths: [...paths] };
8405
+ const out = { filePaths: [...paths2] };
8042
8406
  if (goal) out.goal = goal;
8043
8407
  if (cmd) out.command = cmd;
8044
8408
  return out;
@@ -8076,9 +8440,9 @@ async function getCommandContext(command) {
8076
8440
  }
8077
8441
  function loadHookState(root) {
8078
8442
  try {
8079
- const fp = path18.join(root, HOOK_STATE_FILE);
8080
- if (fs15.existsSync(fp)) {
8081
- return JSON.parse(fs15.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"));
8082
8446
  }
8083
8447
  } catch {
8084
8448
  }
@@ -8086,10 +8450,10 @@ function loadHookState(root) {
8086
8450
  }
8087
8451
  function saveHookState(root, state) {
8088
8452
  try {
8089
- const fp = path18.join(root, HOOK_STATE_FILE);
8090
- const dir = path18.dirname(fp);
8091
- if (!fs15.existsSync(dir)) fs15.mkdirSync(dir, { recursive: true });
8092
- fs15.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");
8093
8457
  } catch {
8094
8458
  }
8095
8459
  }
@@ -8123,7 +8487,7 @@ async function trackFileEditLoop(filePath) {
8123
8487
  saveHookState(root, state);
8124
8488
  if (recorded) {
8125
8489
  try {
8126
- if (!fs15.existsSync(path18.join(root, ".kuma", "kuma.db"))) return entry.count;
8490
+ if (!fs17.existsSync(path20.join(root, ".kuma", "kuma.db"))) return entry.count;
8127
8491
  const { addGotcha: addGotcha2 } = await Promise.resolve().then(() => (init_kumaGotchas(), kumaGotchas_exports));
8128
8492
  await addGotcha2({
8129
8493
  filePath,
@@ -8177,8 +8541,8 @@ __export(kumaGotchas_exports, {
8177
8541
  syncGotchasToDb: () => syncGotchasToDb,
8178
8542
  tokenizeForSimilarity: () => tokenizeForSimilarity
8179
8543
  });
8180
- import fs16 from "fs";
8181
- import path19 from "path";
8544
+ import fs18 from "fs";
8545
+ import path21 from "path";
8182
8546
  async function ensureGotchasSchema() {
8183
8547
  const db = await getDb();
8184
8548
  db.exec(`
@@ -8600,8 +8964,8 @@ async function getActiveGotchasForCommand(command) {
8600
8964
  }
8601
8965
  async function recordInjection(params) {
8602
8966
  try {
8603
- const fp = path19.join(getProjectRoot(), ".kuma", "injections.jsonl");
8604
- if (!fs16.existsSync(path19.dirname(fp))) fs16.mkdirSync(path19.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 });
8605
8969
  const line = JSON.stringify({
8606
8970
  filePath: params.filePath || null,
8607
8971
  command: params.command || null,
@@ -8610,16 +8974,16 @@ async function recordInjection(params) {
8610
8974
  // conservative estimate: avoided re-research / re-discovery
8611
8975
  at: Date.now()
8612
8976
  });
8613
- fs16.appendFileSync(fp, line + "\n", "utf-8");
8977
+ fs18.appendFileSync(fp, line + "\n", "utf-8");
8614
8978
  } catch {
8615
8979
  }
8616
8980
  }
8617
8981
  function getInjectionStats(hours = 24) {
8618
8982
  try {
8619
- const fp = path19.join(getProjectRoot(), ".kuma", "injections.jsonl");
8620
- if (!fs16.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 };
8621
8985
  const cutoff = Date.now() - hours * 60 * 60 * 1e3;
8622
- const lines = fs16.readFileSync(fp, "utf-8").split("\n");
8986
+ const lines = fs18.readFileSync(fp, "utf-8").split("\n");
8623
8987
  let count = 0;
8624
8988
  let savedMs = 0;
8625
8989
  for (const line of lines) {
@@ -8677,9 +9041,9 @@ async function getGotchasByStatus(status, limit = 20) {
8677
9041
  }
8678
9042
  function syncGotchaStatusToMarkdown(targetPaths, newStatus, reason) {
8679
9043
  try {
8680
- const mdPath = path19.join(getProjectRoot(), ".kuma", "KNOWN_GOTCHAS.md");
8681
- if (!fs16.existsSync(mdPath)) return false;
8682
- const content = fs16.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");
8683
9047
  const lines = content.split("\n");
8684
9048
  const normalizedTargets = targetPaths.map((p) => p.trim().toLowerCase()).filter(Boolean);
8685
9049
  if (normalizedTargets.length === 0) return false;
@@ -8696,9 +9060,9 @@ function syncGotchaStatusToMarkdown(targetPaths, newStatus, reason) {
8696
9060
  modified = true;
8697
9061
  }
8698
9062
  const headingFile = headingMatch[1].trim().toLowerCase();
8699
- const headingBase = path19.basename(headingFile);
9063
+ const headingBase = path21.basename(headingFile);
8700
9064
  inMatchingSection = normalizedTargets.some(
8701
- (t) => headingFile.includes(t) || t.includes(headingFile) || headingBase === t || headingBase === path19.basename(t)
9065
+ (t) => headingFile.includes(t) || t.includes(headingFile) || headingBase === t || headingBase === path21.basename(t)
8702
9066
  );
8703
9067
  sectionHasStatus = false;
8704
9068
  outputLines.push(line);
@@ -8720,7 +9084,7 @@ function syncGotchaStatusToMarkdown(targetPaths, newStatus, reason) {
8720
9084
  modified = true;
8721
9085
  }
8722
9086
  if (modified) {
8723
- fs16.writeFileSync(mdPath, outputLines.join("\n"), "utf-8");
9087
+ fs18.writeFileSync(mdPath, outputLines.join("\n"), "utf-8");
8724
9088
  }
8725
9089
  return modified;
8726
9090
  } catch {
@@ -8861,24 +9225,24 @@ var kumaMaintenance_exports = {};
8861
9225
  __export(kumaMaintenance_exports, {
8862
9226
  maybeRunAutoCleanup: () => maybeRunAutoCleanup
8863
9227
  });
8864
- import fs17 from "fs";
8865
- import path20 from "path";
9228
+ import fs19 from "fs";
9229
+ import path22 from "path";
8866
9230
  async function maybeRunAutoCleanup() {
8867
9231
  try {
8868
9232
  const root = getProjectRoot();
8869
- const stateFile = path20.join(root, GC_STATE_FILE);
9233
+ const stateFile = path22.join(root, GC_STATE_FILE);
8870
9234
  const now = Date.now();
8871
9235
  let lastRun = 0;
8872
- if (fs17.existsSync(stateFile)) {
9236
+ if (fs19.existsSync(stateFile)) {
8873
9237
  try {
8874
- lastRun = JSON.parse(fs17.readFileSync(stateFile, "utf-8")).lastRun || 0;
9238
+ lastRun = JSON.parse(fs19.readFileSync(stateFile, "utf-8")).lastRun || 0;
8875
9239
  } catch {
8876
9240
  lastRun = 0;
8877
9241
  }
8878
9242
  }
8879
9243
  if (now - lastRun < GC_INTERVAL_MS) return "";
8880
- fs17.mkdirSync(path20.dirname(stateFile), { recursive: true });
8881
- fs17.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");
8882
9246
  const { syncGotchasToDb: syncGotchasToDb2 } = await Promise.resolve().then(() => (init_kumaGotchas(), kumaGotchas_exports));
8883
9247
  await syncGotchasToDb2();
8884
9248
  const { runGarbageCollection: runGarbageCollection2 } = await Promise.resolve().then(() => (init_kumaDb(), kumaDb_exports));
@@ -8914,22 +9278,22 @@ __export(kumaPathRules_exports, {
8914
9278
  loadPathRules: () => loadPathRules,
8915
9279
  matchRulePath: () => matchRulePath
8916
9280
  });
8917
- import fs18 from "fs";
8918
- import path21 from "path";
9281
+ import fs20 from "fs";
9282
+ import path23 from "path";
8919
9283
  function rulesDir() {
8920
- return path21.join(getProjectRoot(), RULES_DIR);
9284
+ return path23.join(getProjectRoot(), RULES_DIR);
8921
9285
  }
8922
9286
  function ensureRulesDir() {
8923
9287
  try {
8924
9288
  const dir = rulesDir();
8925
- if (!fs18.existsSync(dir)) fs18.mkdirSync(dir, { recursive: true });
9289
+ if (!fs20.existsSync(dir)) fs20.mkdirSync(dir, { recursive: true });
8926
9290
  } catch {
8927
9291
  }
8928
9292
  }
8929
9293
  function parseRuleFile(filePath) {
8930
9294
  try {
8931
- const raw = fs18.readFileSync(filePath, "utf-8");
8932
- const id = path21.basename(filePath, ".md");
9295
+ const raw = fs20.readFileSync(filePath, "utf-8");
9296
+ const id = path23.basename(filePath, ".md");
8933
9297
  const fm = raw.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/);
8934
9298
  if (!fm) {
8935
9299
  return { id, description: id, paths: ["*"], content: raw.trim(), filePath };
@@ -8937,15 +9301,15 @@ function parseRuleFile(filePath) {
8937
9301
  const meta = fm[1];
8938
9302
  const body = fm[2].trim();
8939
9303
  const description = meta.match(/description:\s*(.+)/)?.[1]?.trim() || id;
8940
- const paths = [];
9304
+ const paths2 = [];
8941
9305
  const pathSection = meta.match(/paths:\s*\r?\n([\s\S]*?)(?=\r?\n\S|$)/);
8942
9306
  if (pathSection) {
8943
9307
  for (const line of pathSection[1].split("\n")) {
8944
9308
  const m = line.match(/^\s*-\s*['"]?([^'"]+)['"]?\s*$/);
8945
- if (m) paths.push(m[1].trim());
9309
+ if (m) paths2.push(m[1].trim());
8946
9310
  }
8947
9311
  }
8948
- return { id, description, paths: paths.length ? paths : ["*"], content: body, filePath };
9312
+ return { id, description, paths: paths2.length ? paths2 : ["*"], content: body, filePath };
8949
9313
  } catch {
8950
9314
  return null;
8951
9315
  }
@@ -8954,7 +9318,7 @@ function loadPathRules() {
8954
9318
  ensureRulesDir();
8955
9319
  try {
8956
9320
  const dir = rulesDir();
8957
- return fs18.readdirSync(dir).filter((f) => f.endsWith(".md")).map((f) => parseRuleFile(path21.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);
8958
9322
  } catch {
8959
9323
  return [];
8960
9324
  }
@@ -9042,8 +9406,8 @@ __export(kumaFlowCache_exports, {
9042
9406
  getFreshDomainFlow: () => getFreshDomainFlow,
9043
9407
  getHopsForDomain: () => getHopsForDomain
9044
9408
  });
9045
- import fs19 from "fs";
9046
- import path22 from "path";
9409
+ import fs21 from "fs";
9410
+ import path24 from "path";
9047
9411
  async function getFlowFreshness(domain) {
9048
9412
  try {
9049
9413
  const { getDb: getDb2 } = await Promise.resolve().then(() => (init_kumaDb(), kumaDb_exports));
@@ -9078,26 +9442,26 @@ async function getFlowFreshness(domain) {
9078
9442
  }
9079
9443
  function resolveImport(fromFile, spec) {
9080
9444
  const root = getProjectRoot();
9081
- const fromDir = path22.dirname(fromFile);
9445
+ const fromDir = path24.dirname(fromFile);
9082
9446
  const candidates = [];
9083
9447
  if (spec.startsWith(".")) {
9084
- const abs = path22.resolve(fromDir, spec);
9448
+ const abs = path24.resolve(fromDir, spec);
9085
9449
  candidates.push(abs);
9086
9450
  } else {
9087
- candidates.push(path22.join(root, spec));
9451
+ candidates.push(path24.join(root, spec));
9088
9452
  }
9089
9453
  for (const c of candidates) {
9090
9454
  for (const ext of SOURCE_EXTENSIONS) {
9091
9455
  const withExt = `${c}${ext}`;
9092
- if (fs19.existsSync(withExt)) return path22.relative(root, withExt);
9093
- if (fs19.existsSync(c) && fs19.statSync(c).isDirectory()) {
9094
- const idx = path22.join(c, "index") + ext;
9095
- if (fs19.existsSync(idx)) return path22.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);
9096
9460
  }
9097
9461
  }
9098
- if (fs19.existsSync(c)) {
9462
+ if (fs21.existsSync(c)) {
9099
9463
  try {
9100
- if (fs19.statSync(c).isFile()) return path22.relative(root, c);
9464
+ if (fs21.statSync(c).isFile()) return path24.relative(root, c);
9101
9465
  } catch {
9102
9466
  }
9103
9467
  }
@@ -9106,13 +9470,13 @@ function resolveImport(fromFile, spec) {
9106
9470
  }
9107
9471
  function deriveHopsFromImports(entryFile, maxHops = 6) {
9108
9472
  const root = getProjectRoot();
9109
- const absEntry = path22.isAbsolute(entryFile) ? entryFile : path22.resolve(root, entryFile);
9110
- if (!fs19.existsSync(absEntry)) return [];
9473
+ const absEntry = path24.isAbsolute(entryFile) ? entryFile : path24.resolve(root, entryFile);
9474
+ if (!fs21.existsSync(absEntry)) return [];
9111
9475
  const hops = [];
9112
9476
  const seen = /* @__PURE__ */ new Set([entryFile]);
9113
- const fromName = path22.basename(absEntry);
9477
+ const fromName = path24.basename(absEntry);
9114
9478
  try {
9115
- const lines = fs19.readFileSync(absEntry, "utf-8").split("\n");
9479
+ const lines = fs21.readFileSync(absEntry, "utf-8").split("\n");
9116
9480
  for (const line of lines) {
9117
9481
  if (hops.length >= maxHops) break;
9118
9482
  const spec = matchImportPath(line);
@@ -9122,9 +9486,9 @@ function deriveHopsFromImports(entryFile, maxHops = 6) {
9122
9486
  seen.add(resolved);
9123
9487
  hops.push({
9124
9488
  from: fromName,
9125
- to: path22.basename(resolved),
9489
+ to: path24.basename(resolved),
9126
9490
  relation: "imports",
9127
- description: `${fromName} imports ${path22.basename(resolved)}`
9491
+ description: `${fromName} imports ${path24.basename(resolved)}`
9128
9492
  });
9129
9493
  }
9130
9494
  } catch {
@@ -9187,9 +9551,9 @@ async function getHopsForDomain(domain) {
9187
9551
  }
9188
9552
  try {
9189
9553
  const root = getProjectRoot();
9190
- const archPath = path22.join(root, ".kuma", "ARCHITECTURE_FLOW.md");
9191
- if (fs19.existsSync(archPath)) {
9192
- const content = fs19.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");
9193
9557
  const lines = content.split("\n");
9194
9558
  for (const line of lines) {
9195
9559
  const domMatch = line.match(new RegExp(`domain:\\s*${escapeRegex(domain)}\\s*\\|\\s*hops:\\s*(.+)`, "i"));
@@ -9234,7 +9598,7 @@ Record one with kuma_memory({ action: 'arch_flow', content: 'domain: ${domain} |
9234
9598
  hops: derivedHops,
9235
9599
  filePaths: freshness.filePaths
9236
9600
  });
9237
- lines.push(`\u2705 Re-derived ${derivedHops.length} hop(s) from ${path22.basename(entry)} \u2014 cache refreshed.`);
9601
+ lines.push(`\u2705 Re-derived ${derivedHops.length} hop(s) from ${path24.basename(entry)} \u2014 cache refreshed.`);
9238
9602
  hops.splice(0, hops.length, ...derivedHops);
9239
9603
  } else {
9240
9604
  lines.push("\u26A0\uFE0F No imports to follow \u2014 cache left as-is (record hops manually if needed).");
@@ -9287,10 +9651,10 @@ __export(packageBriefs_exports, {
9287
9651
  readBrief: () => readBrief,
9288
9652
  refreshPackageBriefs: () => refreshPackageBriefs
9289
9653
  });
9290
- import fs20 from "fs";
9291
- import path23 from "path";
9654
+ import fs22 from "fs";
9655
+ import path25 from "path";
9292
9656
  function briefsDir(root) {
9293
- return path23.join(root || getProjectRoot(), BRIEFS_DIR);
9657
+ return path25.join(root || getProjectRoot(), BRIEFS_DIR);
9294
9658
  }
9295
9659
  function slug(name) {
9296
9660
  return name.replace(/[^a-zA-Z0-9_-]/g, "_").slice(0, 60) || "root";
@@ -9354,13 +9718,13 @@ async function refreshPackageBriefs() {
9354
9718
  const dir = briefsDir(root);
9355
9719
  try {
9356
9720
  const ws = await getWorkspaceInfo(root);
9357
- if (!fs20.existsSync(dir)) fs20.mkdirSync(dir, { recursive: true });
9721
+ if (!fs22.existsSync(dir)) fs22.mkdirSync(dir, { recursive: true });
9358
9722
  let count = 0;
9359
9723
  const pkgs = ws.isWorkspace ? ws.packages : [{ name: "root", path: ".", isRoot: true }];
9360
9724
  for (const p of pkgs.slice(0, 20)) {
9361
9725
  const pkg = p;
9362
9726
  const content = await buildPackageBrief(pkg.name, pkg.path, root);
9363
- fs20.writeFileSync(path23.join(dir, `${slug(pkg.name)}.md`), content, "utf-8");
9727
+ fs22.writeFileSync(path25.join(dir, `${slug(pkg.name)}.md`), content, "utf-8");
9364
9728
  count++;
9365
9729
  }
9366
9730
  return { count, dir };
@@ -9370,9 +9734,9 @@ async function refreshPackageBriefs() {
9370
9734
  }
9371
9735
  function briefFreshness(pkgName) {
9372
9736
  try {
9373
- const fp = path23.join(briefsDir(), `${slug(pkgName)}.md`);
9374
- if (!fs20.existsSync(fp)) return { exists: false, fresh: false, age: "missing" };
9375
- const ageMs = Date.now() - fs20.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;
9376
9740
  return { exists: true, fresh: !isStale(Date.now() - ageMs, MAP_TTL_MS), age: formatAge(Date.now() - ageMs) };
9377
9741
  } catch {
9378
9742
  return { exists: false, fresh: false, age: "missing" };
@@ -9380,9 +9744,9 @@ function briefFreshness(pkgName) {
9380
9744
  }
9381
9745
  function readBrief(pkgName, maxChars = 1200) {
9382
9746
  try {
9383
- const fp = path23.join(briefsDir(), `${slug(pkgName)}.md`);
9384
- if (!fs20.existsSync(fp)) return null;
9385
- const content = fs20.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");
9386
9750
  return content.length > maxChars ? content.slice(0, maxChars) + "\n\u2026(truncated)" : content;
9387
9751
  } catch {
9388
9752
  return null;
@@ -9411,8 +9775,8 @@ __export(kumaSearch_exports, {
9411
9775
  formatHybridResults: () => formatHybridResults,
9412
9776
  hybridSearch: () => hybridSearch
9413
9777
  });
9414
- import fs22 from "fs";
9415
- import path25 from "path";
9778
+ import fs24 from "fs";
9779
+ import path27 from "path";
9416
9780
  function expandQueryTerms(query) {
9417
9781
  const terms = query.toLowerCase().split(/[\s_-]+/).filter((t) => t.length > 2);
9418
9782
  const expanded = /* @__PURE__ */ new Map();
@@ -9475,13 +9839,13 @@ async function buildSearchVectors() {
9475
9839
  }
9476
9840
  try {
9477
9841
  const root = getProjectRoot();
9478
- const memDir = path25.join(root, ".kuma", "memories");
9479
- if (fs22.existsSync(memDir)) {
9480
- const files = fs22.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);
9481
9845
  for (const file of files) {
9482
9846
  try {
9483
- const fullPath = path25.join(memDir, file);
9484
- const content = fs22.readFileSync(fullPath, "utf-8");
9847
+ const fullPath = path27.join(memDir, file);
9848
+ const content = fs24.readFileSync(fullPath, "utf-8");
9485
9849
  const text = content.toLowerCase();
9486
9850
  const rawTerms = extractTerms(text);
9487
9851
  const termCounts = /* @__PURE__ */ new Map();
@@ -9492,7 +9856,7 @@ async function buildSearchVectors() {
9492
9856
  terms: termCounts,
9493
9857
  source: file.replace(/\.md$/, ""),
9494
9858
  sourceType: "memory",
9495
- recency: recencyScore(Math.floor(fs22.statSync(fullPath).mtimeMs / 1e3))
9859
+ recency: recencyScore(Math.floor(fs24.statSync(fullPath).mtimeMs / 1e3))
9496
9860
  });
9497
9861
  } catch {
9498
9862
  }
@@ -9809,14 +10173,14 @@ __export(architectureGuard_exports, {
9809
10173
  detectWorkspaceCircularDeps: () => detectWorkspaceCircularDeps,
9810
10174
  loadArchitectureRules: () => loadArchitectureRules
9811
10175
  });
9812
- import fs26 from "fs";
9813
- import path29 from "path";
9814
- import fastGlob4 from "fast-glob";
10176
+ import fs28 from "fs";
10177
+ import path31 from "path";
10178
+ import fastGlob5 from "fast-glob";
9815
10179
  function loadArchitectureRules(root) {
9816
- const rulesPath = path29.join(root, ".kuma", "architecture.json");
9817
- if (fs26.existsSync(rulesPath)) {
10180
+ const rulesPath = path31.join(root, ".kuma", "architecture.json");
10181
+ if (fs28.existsSync(rulesPath)) {
9818
10182
  try {
9819
- const data = JSON.parse(fs26.readFileSync(rulesPath, "utf-8"));
10183
+ const data = JSON.parse(fs28.readFileSync(rulesPath, "utf-8"));
9820
10184
  if (Array.isArray(data.rules)) {
9821
10185
  return data.rules;
9822
10186
  }
@@ -9869,7 +10233,7 @@ async function checkArchitectureBoundaries(filesToCheck, customRoot) {
9869
10233
  }
9870
10234
  let targetFiles = filesToCheck;
9871
10235
  if (!targetFiles || targetFiles.length === 0) {
9872
- targetFiles = await fastGlob4(["**/*.{ts,tsx,js,jsx,mjs,cjs}"], {
10236
+ targetFiles = await fastGlob5(["**/*.{ts,tsx,js,jsx,mjs,cjs}"], {
9873
10237
  cwd: root,
9874
10238
  ignore: ["**/node_modules/**", "**/dist/**", "**/build/**", "**/.git/**", "**/.kuma/**"],
9875
10239
  onlyFiles: true
@@ -9878,11 +10242,11 @@ async function checkArchitectureBoundaries(filesToCheck, customRoot) {
9878
10242
  const customRules = loadArchitectureRules(root);
9879
10243
  const importRegex = /(?:import|export\s+.*from|require\s*\()\s*['"]([^'"]+)['"]/g;
9880
10244
  for (const file of targetFiles) {
9881
- const fullPath = path29.isAbsolute(file) ? file : path29.join(root, file);
9882
- if (!fs26.existsSync(fullPath)) continue;
10245
+ const fullPath = path31.isAbsolute(file) ? file : path31.join(root, file);
10246
+ if (!fs28.existsSync(fullPath)) continue;
9883
10247
  let content = "";
9884
10248
  try {
9885
- content = fs26.readFileSync(fullPath, "utf-8");
10249
+ content = fs28.readFileSync(fullPath, "utf-8");
9886
10250
  } catch {
9887
10251
  continue;
9888
10252
  }
@@ -9892,7 +10256,7 @@ async function checkArchitectureBoundaries(filesToCheck, customRoot) {
9892
10256
  const importPath = match[1];
9893
10257
  if (wsInfo.isWorkspace && currentPkg && !currentPkg.isRoot) {
9894
10258
  if (importPath.startsWith("../") && (importPath.includes("/src/") || importPath.includes("/dist/"))) {
9895
- const resolvedTarget = path29.normalize(path29.resolve(path29.dirname(fullPath), importPath));
10259
+ const resolvedTarget = path31.normalize(path31.resolve(path31.dirname(fullPath), importPath));
9896
10260
  const targetPkg = findPackageForFile(resolvedTarget, wsInfo);
9897
10261
  if (targetPkg && targetPkg.name !== currentPkg.name) {
9898
10262
  violations.push({
@@ -9941,26 +10305,26 @@ __export(docDrift_exports, {
9941
10305
  formatDocDrift: () => formatDocDrift,
9942
10306
  scanDocDrift: () => scanDocDrift
9943
10307
  });
9944
- import fs27 from "fs";
9945
- import path30 from "path";
9946
- import { execSync as execSync8 } from "child_process";
10308
+ import fs29 from "fs";
10309
+ import path32 from "path";
10310
+ import { execSync as execSync9 } from "child_process";
9947
10311
  function collectDocFiles(root) {
9948
10312
  const cwd = root || getProjectRoot();
9949
10313
  const out = [];
9950
10314
  const pushIfMd = (dir, rel) => {
9951
10315
  try {
9952
- for (const f of fs27.readdirSync(dir)) {
10316
+ for (const f of fs29.readdirSync(dir)) {
9953
10317
  if (out.length >= MAX_DOCS) return;
9954
- const full = path30.join(dir, f);
10318
+ const full = path32.join(dir, f);
9955
10319
  try {
9956
- if (fs27.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));
9957
10321
  } catch {
9958
10322
  }
9959
10323
  }
9960
10324
  } catch {
9961
10325
  }
9962
10326
  };
9963
- pushIfMd(path30.join(cwd, "docs"), (f) => path30.join("docs", f));
10327
+ pushIfMd(path32.join(cwd, "docs"), (f) => path32.join("docs", f));
9964
10328
  pushIfMd(cwd, (f) => f);
9965
10329
  return out;
9966
10330
  }
@@ -10002,7 +10366,7 @@ function codeContainsBatch(root, needles) {
10002
10366
  const chunk = clean.slice(i, i + 50);
10003
10367
  try {
10004
10368
  const args = chunk.map((n) => `-e "${n}"`).join(" ");
10005
- const out = execSync8(
10369
+ const out = execSync9(
10006
10370
  `grep -rn --include="*.ts" --include="*.js" --include="*.tsx" --include="*.jsx" --include="*.py" --include="*.go" --include="*.rs" --include="*.json" --include="*.yml" --include="*.yaml" --include="*.toml" --include=".env*" -F ${args} . 2>/dev/null | grep -v node_modules | grep -v "/dist/" | grep -v "/.git/" | grep -v "/.kuma/" | head -100`,
10007
10371
  { cwd: root, encoding: "utf-8", timeout: 8e3, maxBuffer: 256 * 1024 }
10008
10372
  ).trim();
@@ -10022,7 +10386,7 @@ function scanDocDrift(root) {
10022
10386
  let claims = [];
10023
10387
  for (const rel of collectDocFiles(cwd)) {
10024
10388
  try {
10025
- const content = fs27.readFileSync(path30.join(cwd, rel), "utf-8");
10389
+ const content = fs29.readFileSync(path32.join(cwd, rel), "utf-8");
10026
10390
  if (isExemptDoc(rel, content)) {
10027
10391
  skipped.push(rel);
10028
10392
  continue;
@@ -10193,27 +10557,27 @@ __export(kumaCheckpoint_exports, {
10193
10557
  pruneCheckpoints: () => pruneCheckpoints,
10194
10558
  rollbackToCheckpoint: () => rollbackToCheckpoint
10195
10559
  });
10196
- import fs28 from "fs";
10197
- import path31 from "path";
10560
+ import fs30 from "fs";
10561
+ import path33 from "path";
10198
10562
  async function createCheckpoint(label, description) {
10199
10563
  try {
10200
10564
  const root = getProjectRoot();
10201
- const cpDir = path31.join(root, CHECKPOINT_DIR, sanitizeLabel(label));
10202
- if (fs28.existsSync(cpDir)) {
10565
+ const cpDir = path33.join(root, CHECKPOINT_DIR, sanitizeLabel(label));
10566
+ if (fs30.existsSync(cpDir)) {
10203
10567
  return `\u26A0\uFE0F Checkpoint "${label}" already exists. Use a different label or remove it first.`;
10204
10568
  }
10205
- fs28.mkdirSync(cpDir, { recursive: true });
10569
+ fs30.mkdirSync(cpDir, { recursive: true });
10206
10570
  let gitHead;
10207
10571
  let isGitClean = false;
10208
10572
  try {
10209
- const { execSync: execSync9 } = await import("child_process");
10210
- gitHead = execSync9("git rev-parse HEAD", {
10573
+ const { execSync: execSync10 } = await import("child_process");
10574
+ gitHead = execSync10("git rev-parse HEAD", {
10211
10575
  cwd: root,
10212
10576
  encoding: "utf-8",
10213
10577
  timeout: 3e3,
10214
10578
  stdio: ["pipe", "pipe", "pipe"]
10215
10579
  }).trim();
10216
- const statusOut = execSync9("git status --porcelain", {
10580
+ const statusOut = execSync10("git status --porcelain", {
10217
10581
  cwd: root,
10218
10582
  encoding: "utf-8",
10219
10583
  timeout: 3e3,
@@ -10224,8 +10588,8 @@ async function createCheckpoint(label, description) {
10224
10588
  }
10225
10589
  const candidatePaths = /* @__PURE__ */ new Set();
10226
10590
  try {
10227
- const { execSync: execSync9 } = await import("child_process");
10228
- const gitOut = execSync9("git status --porcelain", {
10591
+ const { execSync: execSync10 } = await import("child_process");
10592
+ const gitOut = execSync10("git status --porcelain", {
10229
10593
  cwd: root,
10230
10594
  encoding: "utf-8",
10231
10595
  timeout: 4e3,
@@ -10268,15 +10632,15 @@ async function createCheckpoint(label, description) {
10268
10632
  }
10269
10633
  const files = [];
10270
10634
  for (const fp of candidatePaths) {
10271
- const fullPath = path31.resolve(root, fp);
10635
+ const fullPath = path33.resolve(root, fp);
10272
10636
  try {
10273
- if (fs28.existsSync(fullPath) && fs28.statSync(fullPath).isFile()) {
10274
- const content = fs28.readFileSync(fullPath, "utf-8");
10637
+ if (fs30.existsSync(fullPath) && fs30.statSync(fullPath).isFile()) {
10638
+ const content = fs30.readFileSync(fullPath, "utf-8");
10275
10639
  const hash = simpleHash2(content);
10276
- const snapFile = path31.join(cpDir, "files", `${fp}.kuma-snap`);
10277
- const fileDir = path31.dirname(snapFile);
10278
- if (!fs28.existsSync(fileDir)) fs28.mkdirSync(fileDir, { recursive: true });
10279
- fs28.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");
10280
10644
  files.push({ path: fp, hash });
10281
10645
  }
10282
10646
  } catch {
@@ -10284,7 +10648,7 @@ async function createCheckpoint(label, description) {
10284
10648
  }
10285
10649
  const db = await getDb();
10286
10650
  const dbData = db.export();
10287
- fs28.writeFileSync(path31.join(cpDir, "kuma.db"), Buffer.from(dbData));
10651
+ fs30.writeFileSync(path33.join(cpDir, "kuma.db"), Buffer.from(dbData));
10288
10652
  const manifest = {
10289
10653
  label,
10290
10654
  timestamp: Date.now(),
@@ -10294,8 +10658,8 @@ async function createCheckpoint(label, description) {
10294
10658
  dbSnapshot: true,
10295
10659
  description
10296
10660
  };
10297
- fs28.writeFileSync(
10298
- path31.join(cpDir, "manifest.json"),
10661
+ fs30.writeFileSync(
10662
+ path33.join(cpDir, "manifest.json"),
10299
10663
  JSON.stringify(manifest, null, 2),
10300
10664
  "utf-8"
10301
10665
  );
@@ -10323,29 +10687,29 @@ async function createCheckpoint(label, description) {
10323
10687
  async function rollbackToCheckpoint(label) {
10324
10688
  try {
10325
10689
  const root = getProjectRoot();
10326
- const cpDir = path31.join(root, CHECKPOINT_DIR, sanitizeLabel(label));
10327
- const manifestPath = path31.join(cpDir, "manifest.json");
10328
- if (!fs28.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)) {
10329
10693
  return `\u274C Checkpoint "${label}" not found. Available checkpoints:
10330
10694
 
10331
10695
  ${listCheckpoints()}`;
10332
10696
  }
10333
10697
  const manifest = JSON.parse(
10334
- fs28.readFileSync(manifestPath, "utf-8")
10698
+ fs30.readFileSync(manifestPath, "utf-8")
10335
10699
  );
10336
10700
  let restored = 0;
10337
10701
  let failed = 0;
10338
10702
  for (const f of manifest.files) {
10339
- const snapPath = path31.join(cpDir, "files", `${f.path}.kuma-snap`);
10340
- const legacyPath = path31.join(cpDir, "files", f.path);
10341
- const sourcePath = fs28.existsSync(snapPath) ? snapPath : legacyPath;
10342
- if (fs28.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)) {
10343
10707
  try {
10344
- const content = fs28.readFileSync(sourcePath, "utf-8");
10345
- const targetPath = path31.resolve(root, f.path);
10346
- const targetDir = path31.dirname(targetPath);
10347
- if (!fs28.existsSync(targetDir)) fs28.mkdirSync(targetDir, { recursive: true });
10348
- fs28.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");
10349
10713
  restored++;
10350
10714
  } catch {
10351
10715
  failed++;
@@ -10354,8 +10718,8 @@ ${listCheckpoints()}`;
10354
10718
  }
10355
10719
  if (manifest.files.length === 0 && manifest.gitHead) {
10356
10720
  try {
10357
- const { execSync: execSync9 } = await import("child_process");
10358
- execSync9(`git checkout ${manifest.gitHead} -- .`, {
10721
+ const { execSync: execSync10 } = await import("child_process");
10722
+ execSync10(`git checkout ${manifest.gitHead} -- .`, {
10359
10723
  cwd: root,
10360
10724
  encoding: "utf-8",
10361
10725
  timeout: 8e3,
@@ -10366,12 +10730,12 @@ ${listCheckpoints()}`;
10366
10730
  failed++;
10367
10731
  }
10368
10732
  }
10369
- const dbSnapshotPath = path31.join(cpDir, "kuma.db");
10370
- if (fs28.existsSync(dbSnapshotPath)) {
10371
- const kumaDir = path31.join(root, ".kuma");
10372
- const dbPath = path31.join(kumaDir, "kuma.db");
10373
- const snapshotData = fs28.readFileSync(dbSnapshotPath);
10374
- fs28.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);
10375
10739
  resetDbInstance();
10376
10740
  }
10377
10741
  sessionMemory.recordToolCall("kuma_checkpoint_rollback", {
@@ -10396,18 +10760,18 @@ ${listCheckpoints()}`;
10396
10760
  function listCheckpoints() {
10397
10761
  try {
10398
10762
  const root = getProjectRoot();
10399
- const cpDir = path31.join(root, CHECKPOINT_DIR);
10400
- if (!fs28.existsSync(cpDir)) {
10763
+ const cpDir = path33.join(root, CHECKPOINT_DIR);
10764
+ if (!fs30.existsSync(cpDir)) {
10401
10765
  return "\u{1F4ED} No checkpoints found. Use kuma_safety({ action: 'checkpoint', label: 'pre-feature-x' }) to create one.";
10402
10766
  }
10403
- const entries = fs28.readdirSync(cpDir);
10767
+ const entries = fs30.readdirSync(cpDir);
10404
10768
  const checkpoints = [];
10405
10769
  for (const entry of entries) {
10406
- const manifestPath = path31.join(cpDir, entry, "manifest.json");
10407
- if (fs28.existsSync(manifestPath)) {
10770
+ const manifestPath = path33.join(cpDir, entry, "manifest.json");
10771
+ if (fs30.existsSync(manifestPath)) {
10408
10772
  try {
10409
10773
  const manifest = JSON.parse(
10410
- fs28.readFileSync(manifestPath, "utf-8")
10774
+ fs30.readFileSync(manifestPath, "utf-8")
10411
10775
  );
10412
10776
  checkpoints.push({ label: entry, manifest });
10413
10777
  } catch {
@@ -10439,12 +10803,12 @@ function listCheckpoints() {
10439
10803
  function pruneCheckpoints(keep = 5) {
10440
10804
  try {
10441
10805
  const root = getProjectRoot();
10442
- const cpDir = path31.join(root, CHECKPOINT_DIR);
10443
- if (!fs28.existsSync(cpDir)) return "\u{1F4ED} No checkpoints to prune.";
10444
- const entries = fs28.readdirSync(cpDir).map((e) => ({ name: e, time: fs28.statSync(path31.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);
10445
10809
  let removed = 0;
10446
10810
  for (let i = keep; i < entries.length; i++) {
10447
- fs28.rmSync(path31.join(cpDir, entries[i].name), { recursive: true, force: true });
10811
+ fs30.rmSync(path33.join(cpDir, entries[i].name), { recursive: true, force: true });
10448
10812
  removed++;
10449
10813
  }
10450
10814
  return removed > 0 ? `\u{1F9F9} Pruned **${removed} old checkpoint(s)**. Kept ${Math.min(keep, entries.length)} most recent.` : "\u2705 No checkpoints needed pruning.";
@@ -10469,9 +10833,9 @@ function isRiskyEditPath(filePath) {
10469
10833
  }
10470
10834
  function loadAutoCpDone(root) {
10471
10835
  try {
10472
- const fp = path31.join(root, AUTO_CP_STATE);
10473
- if (fs28.existsSync(fp)) {
10474
- const parsed = JSON.parse(fs28.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"));
10475
10839
  return parsed?.autoCheckpoints ?? {};
10476
10840
  }
10477
10841
  } catch {
@@ -10480,10 +10844,10 @@ function loadAutoCpDone(root) {
10480
10844
  }
10481
10845
  function saveAutoCpDone(root, done) {
10482
10846
  try {
10483
- const fp = path31.join(root, AUTO_CP_STATE);
10484
- const parsed = fs28.existsSync(fp) ? JSON.parse(fs28.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")) : {};
10485
10849
  parsed.autoCheckpoints = done;
10486
- fs28.writeFileSync(fp, JSON.stringify(parsed), "utf-8");
10850
+ fs30.writeFileSync(fp, JSON.stringify(parsed), "utf-8");
10487
10851
  } catch {
10488
10852
  }
10489
10853
  }
@@ -10493,14 +10857,14 @@ function maybeAutoCheckpoint(filePath) {
10493
10857
  const root = getProjectRoot();
10494
10858
  const done = loadAutoCpDone(root);
10495
10859
  if (done[filePath]) return null;
10496
- const abs = path31.isAbsolute(filePath) ? filePath : path31.join(root, filePath);
10497
- if (!fs28.existsSync(abs) || !fs28.statSync(abs).isFile()) return null;
10498
- const label = `auto-pre-${sanitizeLabel(path31.basename(filePath))}`;
10499
- const cpDir = path31.join(root, CHECKPOINT_DIR, label);
10500
- if (!fs28.existsSync(cpDir)) fs28.mkdirSync(cpDir, { recursive: true });
10501
- fs28.copyFileSync(abs, path31.join(cpDir, path31.basename(abs)));
10502
- fs28.writeFileSync(
10503
- path31.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"),
10504
10868
  JSON.stringify({
10505
10869
  label,
10506
10870
  timestamp: Date.now(),
@@ -10540,8 +10904,8 @@ __export(init_exports, {
10540
10904
  generateInitMdContent: () => generateInitMdContent,
10541
10905
  runInit: () => runInit
10542
10906
  });
10543
- import fs29 from "fs";
10544
- import path32 from "path";
10907
+ import fs31 from "fs";
10908
+ import path34 from "path";
10545
10909
  function configFilePath(type) {
10546
10910
  switch (type) {
10547
10911
  case "claude":
@@ -11175,21 +11539,21 @@ function handleOpencodeSecondary(root, results) {
11175
11539
  "",
11176
11540
  "\u{1F4D6} Full rules: `.kuma/init.md`"
11177
11541
  ].join("\n");
11178
- const skillPath = path32.resolve(root, ".agents", "skills", "kuma", "SKILL.md");
11542
+ const skillPath = path34.resolve(root, ".agents", "skills", "kuma", "SKILL.md");
11179
11543
  if (!results.some((r) => r.filePath === ".agents/skills/kuma/SKILL.md")) {
11180
11544
  try {
11181
- const dir = path32.dirname(skillPath);
11182
- if (fs29.existsSync(skillPath)) {
11183
- const existing = fs29.readFileSync(skillPath, "utf-8");
11545
+ const dir = path34.dirname(skillPath);
11546
+ if (fs31.existsSync(skillPath)) {
11547
+ const existing = fs31.readFileSync(skillPath, "utf-8");
11184
11548
  if (existing.includes("kuma-mcp")) {
11185
11549
  results.push({ type: "opencode", filePath: ".agents/skills/kuma/SKILL.md", action: "skipped" });
11186
11550
  } else {
11187
- fs29.writeFileSync(skillPath, existing.trimEnd() + "\n\n---\n\n" + opencodeContent, "utf-8");
11551
+ fs31.writeFileSync(skillPath, existing.trimEnd() + "\n\n---\n\n" + opencodeContent, "utf-8");
11188
11552
  results.push({ type: "opencode", filePath: ".agents/skills/kuma/SKILL.md", action: "appended" });
11189
11553
  }
11190
11554
  } else {
11191
- if (!fs29.existsSync(dir)) fs29.mkdirSync(dir, { recursive: true });
11192
- fs29.writeFileSync(skillPath, opencodeContent, "utf-8");
11555
+ if (!fs31.existsSync(dir)) fs31.mkdirSync(dir, { recursive: true });
11556
+ fs31.writeFileSync(skillPath, opencodeContent, "utf-8");
11193
11557
  results.push({ type: "opencode", filePath: ".agents/skills/kuma/SKILL.md", action: "created" });
11194
11558
  }
11195
11559
  } catch (err) {
@@ -11201,21 +11565,21 @@ function handleOpencodeSecondary(root, results) {
11201
11565
  });
11202
11566
  }
11203
11567
  }
11204
- const opencodeSkillPath = path32.resolve(root, ".opencode", "skills", "kuma", "SKILL.md");
11568
+ const opencodeSkillPath = path34.resolve(root, ".opencode", "skills", "kuma", "SKILL.md");
11205
11569
  if (!results.some((r) => r.filePath === ".opencode/skills/kuma/SKILL.md")) {
11206
11570
  try {
11207
- const dir = path32.dirname(opencodeSkillPath);
11208
- if (fs29.existsSync(opencodeSkillPath)) {
11209
- const existing = fs29.readFileSync(opencodeSkillPath, "utf-8");
11571
+ const dir = path34.dirname(opencodeSkillPath);
11572
+ if (fs31.existsSync(opencodeSkillPath)) {
11573
+ const existing = fs31.readFileSync(opencodeSkillPath, "utf-8");
11210
11574
  if (existing.includes("kuma-mcp")) {
11211
11575
  results.push({ type: "opencode", filePath: ".opencode/skills/kuma/SKILL.md", action: "skipped" });
11212
11576
  } else {
11213
- fs29.writeFileSync(opencodeSkillPath, existing.trimEnd() + "\n\n---\n\n" + opencodeContent, "utf-8");
11577
+ fs31.writeFileSync(opencodeSkillPath, existing.trimEnd() + "\n\n---\n\n" + opencodeContent, "utf-8");
11214
11578
  results.push({ type: "opencode", filePath: ".opencode/skills/kuma/SKILL.md", action: "appended" });
11215
11579
  }
11216
11580
  } else {
11217
- if (!fs29.existsSync(dir)) fs29.mkdirSync(dir, { recursive: true });
11218
- fs29.writeFileSync(opencodeSkillPath, opencodeContent, "utf-8");
11581
+ if (!fs31.existsSync(dir)) fs31.mkdirSync(dir, { recursive: true });
11582
+ fs31.writeFileSync(opencodeSkillPath, opencodeContent, "utf-8");
11219
11583
  results.push({ type: "opencode", filePath: ".opencode/skills/kuma/SKILL.md", action: "created" });
11220
11584
  }
11221
11585
  } catch (err) {
@@ -11227,21 +11591,21 @@ function handleOpencodeSecondary(root, results) {
11227
11591
  });
11228
11592
  }
11229
11593
  }
11230
- const pluginPath = path32.resolve(root, ".opencode", "plugins", "kuma.js");
11594
+ const pluginPath = path34.resolve(root, ".opencode", "plugins", "kuma.js");
11231
11595
  if (!results.some((r) => r.filePath === ".opencode/plugins/kuma.js")) {
11232
11596
  try {
11233
- const dir = path32.dirname(pluginPath);
11234
- if (fs29.existsSync(pluginPath)) {
11235
- const existing = fs29.readFileSync(pluginPath, "utf-8");
11597
+ const dir = path34.dirname(pluginPath);
11598
+ if (fs31.existsSync(pluginPath)) {
11599
+ const existing = fs31.readFileSync(pluginPath, "utf-8");
11236
11600
  if (existing.includes("KumaPlugin") || existing.includes("kuma")) {
11237
11601
  results.push({ type: "opencode", filePath: ".opencode/plugins/kuma.js", action: "skipped" });
11238
11602
  } else {
11239
- fs29.writeFileSync(pluginPath, existing.trimEnd() + "\n\n" + opencodePluginTemplate(), "utf-8");
11603
+ fs31.writeFileSync(pluginPath, existing.trimEnd() + "\n\n" + opencodePluginTemplate(), "utf-8");
11240
11604
  results.push({ type: "opencode", filePath: ".opencode/plugins/kuma.js", action: "appended" });
11241
11605
  }
11242
11606
  } else {
11243
- if (!fs29.existsSync(dir)) fs29.mkdirSync(dir, { recursive: true });
11244
- fs29.writeFileSync(pluginPath, opencodePluginTemplate(), "utf-8");
11607
+ if (!fs31.existsSync(dir)) fs31.mkdirSync(dir, { recursive: true });
11608
+ fs31.writeFileSync(pluginPath, opencodePluginTemplate(), "utf-8");
11245
11609
  results.push({ type: "opencode", filePath: ".opencode/plugins/kuma.js", action: "created" });
11246
11610
  }
11247
11611
  } catch (err) {
@@ -11255,21 +11619,21 @@ function handleOpencodeSecondary(root, results) {
11255
11619
  }
11256
11620
  }
11257
11621
  function handleCodexSecondary(root, results) {
11258
- const tomlPath = path32.resolve(root, ".codex/config.toml");
11622
+ const tomlPath = path34.resolve(root, ".codex/config.toml");
11259
11623
  if (results.some((r) => r.filePath === ".codex/config.toml")) return;
11260
11624
  try {
11261
- const dir = path32.dirname(tomlPath);
11262
- if (!fs29.existsSync(dir)) fs29.mkdirSync(dir, { recursive: true });
11263
- if (fs29.existsSync(tomlPath)) {
11264
- const existingContent = fs29.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");
11265
11629
  if (existingContent.includes("kuma")) {
11266
11630
  results.push({ type: "codex", filePath: ".codex/config.toml", action: "skipped" });
11267
11631
  return;
11268
11632
  }
11269
- fs29.writeFileSync(tomlPath, existingContent.trimEnd() + "\n\n" + codexConfigTomlTemplate(), "utf-8");
11633
+ fs31.writeFileSync(tomlPath, existingContent.trimEnd() + "\n\n" + codexConfigTomlTemplate(), "utf-8");
11270
11634
  results.push({ type: "codex", filePath: ".codex/config.toml", action: "appended" });
11271
11635
  } else {
11272
- fs29.writeFileSync(tomlPath, codexConfigTomlTemplate(), "utf-8");
11636
+ fs31.writeFileSync(tomlPath, codexConfigTomlTemplate(), "utf-8");
11273
11637
  results.push({ type: "codex", filePath: ".codex/config.toml", action: "created" });
11274
11638
  }
11275
11639
  } catch (err) {
@@ -11282,11 +11646,11 @@ function handleCodexSecondary(root, results) {
11282
11646
  }
11283
11647
  }
11284
11648
  function handleQwenSecondary(root, results) {
11285
- const settingsPath = path32.resolve(root, "settings.json");
11649
+ const settingsPath = path34.resolve(root, "settings.json");
11286
11650
  if (results.some((r) => r.filePath === "settings.json")) return;
11287
11651
  try {
11288
- if (fs29.existsSync(settingsPath)) {
11289
- const existingContent = fs29.readFileSync(settingsPath, "utf-8");
11652
+ if (fs31.existsSync(settingsPath)) {
11653
+ const existingContent = fs31.readFileSync(settingsPath, "utf-8");
11290
11654
  if (existingContent.includes("kuma")) {
11291
11655
  if (!existingContent.includes("_Generated by Kuma MCP_")) {
11292
11656
  try {
@@ -11294,7 +11658,7 @@ function handleQwenSecondary(root, results) {
11294
11658
  parsed.mcpServers = parsed.mcpServers || {};
11295
11659
  if (!parsed.mcpServers.kuma) {
11296
11660
  parsed.mcpServers.kuma = { command: "npx", args: ["-y", "@plumpslabs/kuma"], env: {} };
11297
- fs29.writeFileSync(settingsPath, JSON.stringify(parsed, null, 2) + "\n", "utf-8");
11661
+ fs31.writeFileSync(settingsPath, JSON.stringify(parsed, null, 2) + "\n", "utf-8");
11298
11662
  results.push({ type: "qwen", filePath: "settings.json", action: "appended" });
11299
11663
  return;
11300
11664
  }
@@ -11309,13 +11673,13 @@ function handleQwenSecondary(root, results) {
11309
11673
  parsed.mcpServers = parsed.mcpServers || {};
11310
11674
  if (!parsed.mcpServers.kuma) {
11311
11675
  parsed.mcpServers.kuma = { command: "npx", args: ["-y", "@plumpslabs/kuma"], env: {} };
11312
- fs29.writeFileSync(settingsPath, JSON.stringify(parsed, null, 2) + "\n", "utf-8");
11676
+ fs31.writeFileSync(settingsPath, JSON.stringify(parsed, null, 2) + "\n", "utf-8");
11313
11677
  results.push({ type: "qwen", filePath: "settings.json", action: "appended" });
11314
11678
  }
11315
11679
  } catch {
11316
11680
  }
11317
11681
  } else {
11318
- fs29.writeFileSync(settingsPath, qwenSettingsTemplate(), "utf-8");
11682
+ fs31.writeFileSync(settingsPath, qwenSettingsTemplate(), "utf-8");
11319
11683
  results.push({ type: "qwen", filePath: "settings.json", action: "created" });
11320
11684
  }
11321
11685
  } catch (err) {
@@ -11417,12 +11781,12 @@ function getCombinedAgentsMd(selectedTypes) {
11417
11781
  return lines.join("\n");
11418
11782
  }
11419
11783
  function handleAntigravityMcpConfig(root, results) {
11420
- const mcpPath = path32.resolve(root, ".agents/mcp_config.json");
11784
+ const mcpPath = path34.resolve(root, ".agents/mcp_config.json");
11421
11785
  if (results.some((r) => r.filePath === ".agents/mcp_config.json")) return;
11422
11786
  try {
11423
- const mcpDir = path32.dirname(mcpPath);
11424
- if (fs29.existsSync(mcpPath)) {
11425
- const existingContent = fs29.readFileSync(mcpPath, "utf-8");
11787
+ const mcpDir = path34.dirname(mcpPath);
11788
+ if (fs31.existsSync(mcpPath)) {
11789
+ const existingContent = fs31.readFileSync(mcpPath, "utf-8");
11426
11790
  if (existingContent.includes("kuma")) {
11427
11791
  results.push({ type: "antigravity", filePath: ".agents/mcp_config.json", action: "skipped" });
11428
11792
  return;
@@ -11431,14 +11795,14 @@ function handleAntigravityMcpConfig(root, results) {
11431
11795
  const parsed = JSON.parse(existingContent);
11432
11796
  parsed.mcpServers = parsed.mcpServers || {};
11433
11797
  parsed.mcpServers.kuma = { command: "npx", args: ["-y", "@plumpslabs/kuma"], env: {} };
11434
- fs29.writeFileSync(mcpPath, JSON.stringify(parsed, null, 2) + "\n", "utf-8");
11798
+ fs31.writeFileSync(mcpPath, JSON.stringify(parsed, null, 2) + "\n", "utf-8");
11435
11799
  results.push({ type: "antigravity", filePath: ".agents/mcp_config.json", action: "appended" });
11436
11800
  } catch {
11437
11801
  results.push({ type: "antigravity", filePath: ".agents/mcp_config.json", action: "error", error: "Invalid JSON in existing mcp_config.json" });
11438
11802
  }
11439
11803
  } else {
11440
- if (!fs29.existsSync(mcpDir)) fs29.mkdirSync(mcpDir, { recursive: true });
11441
- fs29.writeFileSync(mcpPath, antigravityMcpConfigTemplate(), "utf-8");
11804
+ if (!fs31.existsSync(mcpDir)) fs31.mkdirSync(mcpDir, { recursive: true });
11805
+ fs31.writeFileSync(mcpPath, antigravityMcpConfigTemplate(), "utf-8");
11442
11806
  results.push({ type: "antigravity", filePath: ".agents/mcp_config.json", action: "created" });
11443
11807
  }
11444
11808
  } catch (err) {
@@ -11451,21 +11815,21 @@ function handleAntigravityMcpConfig(root, results) {
11451
11815
  }
11452
11816
  }
11453
11817
  function handleAntigravityRules(root, results) {
11454
- const rulePath = path32.resolve(root, ".agents", "rules", "kuma.md");
11818
+ const rulePath = path34.resolve(root, ".agents", "rules", "kuma.md");
11455
11819
  if (results.some((r) => r.filePath === ".agents/rules/kuma.md")) return;
11456
11820
  try {
11457
- const dir = path32.dirname(rulePath);
11458
- if (!fs29.existsSync(dir)) fs29.mkdirSync(dir, { recursive: true });
11459
- if (fs29.existsSync(rulePath)) {
11460
- const existing = fs29.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");
11461
11825
  if (existing.includes("Kuma MCP") || existing.includes("kuma-mcp")) {
11462
11826
  results.push({ type: "antigravity", filePath: ".agents/rules/kuma.md", action: "skipped" });
11463
11827
  return;
11464
11828
  }
11465
- fs29.writeFileSync(rulePath, existing.trimEnd() + "\n\n---\n\n" + antigravityRuleTemplate(), "utf-8");
11829
+ fs31.writeFileSync(rulePath, existing.trimEnd() + "\n\n---\n\n" + antigravityRuleTemplate(), "utf-8");
11466
11830
  results.push({ type: "antigravity", filePath: ".agents/rules/kuma.md", action: "appended" });
11467
11831
  } else {
11468
- fs29.writeFileSync(rulePath, antigravityRuleTemplate(), "utf-8");
11832
+ fs31.writeFileSync(rulePath, antigravityRuleTemplate(), "utf-8");
11469
11833
  results.push({ type: "antigravity", filePath: ".agents/rules/kuma.md", action: "created" });
11470
11834
  }
11471
11835
  } catch (err) {
@@ -11478,19 +11842,19 @@ function handleAntigravityRules(root, results) {
11478
11842
  }
11479
11843
  }
11480
11844
  function handleGeminiMd(root, results) {
11481
- const geminiPath = path32.resolve(root, "GEMINI.md");
11845
+ const geminiPath = path34.resolve(root, "GEMINI.md");
11482
11846
  if (results.some((r) => r.filePath === "GEMINI.md")) return;
11483
11847
  try {
11484
- if (fs29.existsSync(geminiPath)) {
11485
- const existing = fs29.readFileSync(geminiPath, "utf-8");
11848
+ if (fs31.existsSync(geminiPath)) {
11849
+ const existing = fs31.readFileSync(geminiPath, "utf-8");
11486
11850
  if (existing.includes("Kuma MCP") || existing.includes("kuma_context")) {
11487
11851
  results.push({ type: "antigravity", filePath: "GEMINI.md", action: "skipped" });
11488
11852
  return;
11489
11853
  }
11490
- fs29.writeFileSync(geminiPath, existing.trimEnd() + "\n\n---\n\n" + geminiTemplate(), "utf-8");
11854
+ fs31.writeFileSync(geminiPath, existing.trimEnd() + "\n\n---\n\n" + geminiTemplate(), "utf-8");
11491
11855
  results.push({ type: "antigravity", filePath: "GEMINI.md", action: "appended" });
11492
11856
  } else {
11493
- fs29.writeFileSync(geminiPath, geminiTemplate(), "utf-8");
11857
+ fs31.writeFileSync(geminiPath, geminiTemplate(), "utf-8");
11494
11858
  results.push({ type: "antigravity", filePath: "GEMINI.md", action: "created" });
11495
11859
  }
11496
11860
  } catch (err) {
@@ -11508,19 +11872,19 @@ function handleAntigravitySecondary(root, results) {
11508
11872
  handleGeminiMd(root, results);
11509
11873
  }
11510
11874
  function handleWindsurfSecondary(root, results) {
11511
- const rulesPath = path32.resolve(root, ".windsurfrules");
11875
+ const rulesPath = path34.resolve(root, ".windsurfrules");
11512
11876
  if (results.some((r) => r.filePath === ".windsurfrules")) return;
11513
11877
  try {
11514
- if (fs29.existsSync(rulesPath)) {
11515
- const existing = fs29.readFileSync(rulesPath, "utf-8");
11878
+ if (fs31.existsSync(rulesPath)) {
11879
+ const existing = fs31.readFileSync(rulesPath, "utf-8");
11516
11880
  if (existing.includes("Kuma MCP") || existing.includes("kuma_context")) {
11517
11881
  results.push({ type: "windsurf", filePath: ".windsurfrules", action: "skipped" });
11518
11882
  return;
11519
11883
  }
11520
- fs29.writeFileSync(rulesPath, existing.trimEnd() + "\n\n---\n\n" + windsurfrulesTemplate(), "utf-8");
11884
+ fs31.writeFileSync(rulesPath, existing.trimEnd() + "\n\n---\n\n" + windsurfrulesTemplate(), "utf-8");
11521
11885
  results.push({ type: "windsurf", filePath: ".windsurfrules", action: "appended" });
11522
11886
  } else {
11523
- fs29.writeFileSync(rulesPath, windsurfrulesTemplate(), "utf-8");
11887
+ fs31.writeFileSync(rulesPath, windsurfrulesTemplate(), "utf-8");
11524
11888
  results.push({ type: "windsurf", filePath: ".windsurfrules", action: "created" });
11525
11889
  }
11526
11890
  } catch (err) {
@@ -11533,21 +11897,21 @@ function handleWindsurfSecondary(root, results) {
11533
11897
  }
11534
11898
  }
11535
11899
  function handleClineSecondary(root, results) {
11536
- const rooPath = path32.resolve(root, ".roo", "rules", "kuma.md");
11900
+ const rooPath = path34.resolve(root, ".roo", "rules", "kuma.md");
11537
11901
  if (!results.some((r) => r.filePath === ".roo/rules/kuma.md")) {
11538
11902
  try {
11539
- const dir = path32.dirname(rooPath);
11540
- if (fs29.existsSync(rooPath)) {
11541
- const existing = fs29.readFileSync(rooPath, "utf-8");
11903
+ const dir = path34.dirname(rooPath);
11904
+ if (fs31.existsSync(rooPath)) {
11905
+ const existing = fs31.readFileSync(rooPath, "utf-8");
11542
11906
  if (existing.includes("kuma-mcp") || existing.includes("Kuma MCP")) {
11543
11907
  results.push({ type: "cline", filePath: ".roo/rules/kuma.md", action: "skipped" });
11544
11908
  } else {
11545
- fs29.writeFileSync(rooPath, existing.trimEnd() + "\n\n---\n\n" + rooRulesTemplate(), "utf-8");
11909
+ fs31.writeFileSync(rooPath, existing.trimEnd() + "\n\n---\n\n" + rooRulesTemplate(), "utf-8");
11546
11910
  results.push({ type: "cline", filePath: ".roo/rules/kuma.md", action: "appended" });
11547
11911
  }
11548
11912
  } else {
11549
- if (!fs29.existsSync(dir)) fs29.mkdirSync(dir, { recursive: true });
11550
- fs29.writeFileSync(rooPath, rooRulesTemplate(), "utf-8");
11913
+ if (!fs31.existsSync(dir)) fs31.mkdirSync(dir, { recursive: true });
11914
+ fs31.writeFileSync(rooPath, rooRulesTemplate(), "utf-8");
11551
11915
  results.push({ type: "cline", filePath: ".roo/rules/kuma.md", action: "created" });
11552
11916
  }
11553
11917
  } catch (err) {
@@ -11559,21 +11923,21 @@ function handleClineSecondary(root, results) {
11559
11923
  });
11560
11924
  }
11561
11925
  }
11562
- const traePath = path32.resolve(root, ".trae", "rules", "kuma.md");
11926
+ const traePath = path34.resolve(root, ".trae", "rules", "kuma.md");
11563
11927
  if (!results.some((r) => r.filePath === ".trae/rules/kuma.md")) {
11564
11928
  try {
11565
- const dir = path32.dirname(traePath);
11566
- if (fs29.existsSync(traePath)) {
11567
- const existing = fs29.readFileSync(traePath, "utf-8");
11929
+ const dir = path34.dirname(traePath);
11930
+ if (fs31.existsSync(traePath)) {
11931
+ const existing = fs31.readFileSync(traePath, "utf-8");
11568
11932
  if (existing.includes("Kuma MCP")) {
11569
11933
  results.push({ type: "cline", filePath: ".trae/rules/kuma.md", action: "skipped" });
11570
11934
  } else {
11571
- fs29.writeFileSync(traePath, existing.trimEnd() + "\n\n---\n\n" + traeRulesTemplate(), "utf-8");
11935
+ fs31.writeFileSync(traePath, existing.trimEnd() + "\n\n---\n\n" + traeRulesTemplate(), "utf-8");
11572
11936
  results.push({ type: "cline", filePath: ".trae/rules/kuma.md", action: "appended" });
11573
11937
  }
11574
11938
  } else {
11575
- if (!fs29.existsSync(dir)) fs29.mkdirSync(dir, { recursive: true });
11576
- fs29.writeFileSync(traePath, traeRulesTemplate(), "utf-8");
11939
+ if (!fs31.existsSync(dir)) fs31.mkdirSync(dir, { recursive: true });
11940
+ fs31.writeFileSync(traePath, traeRulesTemplate(), "utf-8");
11577
11941
  results.push({ type: "cline", filePath: ".trae/rules/kuma.md", action: "created" });
11578
11942
  }
11579
11943
  } catch (err) {
@@ -11585,21 +11949,21 @@ function handleClineSecondary(root, results) {
11585
11949
  });
11586
11950
  }
11587
11951
  }
11588
- const qoderPath = path32.resolve(root, ".qoder", "rules", "kuma.md");
11952
+ const qoderPath = path34.resolve(root, ".qoder", "rules", "kuma.md");
11589
11953
  if (!results.some((r) => r.filePath === ".qoder/rules/kuma.md")) {
11590
11954
  try {
11591
- const dir = path32.dirname(qoderPath);
11592
- if (fs29.existsSync(qoderPath)) {
11593
- const existing = fs29.readFileSync(qoderPath, "utf-8");
11955
+ const dir = path34.dirname(qoderPath);
11956
+ if (fs31.existsSync(qoderPath)) {
11957
+ const existing = fs31.readFileSync(qoderPath, "utf-8");
11594
11958
  if (existing.includes("Kuma MCP")) {
11595
11959
  results.push({ type: "cline", filePath: ".qoder/rules/kuma.md", action: "skipped" });
11596
11960
  } else {
11597
- fs29.writeFileSync(qoderPath, existing.trimEnd() + "\n\n---\n\n" + qoderRulesTemplate(), "utf-8");
11961
+ fs31.writeFileSync(qoderPath, existing.trimEnd() + "\n\n---\n\n" + qoderRulesTemplate(), "utf-8");
11598
11962
  results.push({ type: "cline", filePath: ".qoder/rules/kuma.md", action: "appended" });
11599
11963
  }
11600
11964
  } else {
11601
- if (!fs29.existsSync(dir)) fs29.mkdirSync(dir, { recursive: true });
11602
- fs29.writeFileSync(qoderPath, qoderRulesTemplate(), "utf-8");
11965
+ if (!fs31.existsSync(dir)) fs31.mkdirSync(dir, { recursive: true });
11966
+ fs31.writeFileSync(qoderPath, qoderRulesTemplate(), "utf-8");
11603
11967
  results.push({ type: "cline", filePath: ".qoder/rules/kuma.md", action: "created" });
11604
11968
  }
11605
11969
  } catch (err) {
@@ -11613,18 +11977,18 @@ function handleClineSecondary(root, results) {
11613
11977
  }
11614
11978
  }
11615
11979
  function handleAiderSecondary(root, results) {
11616
- const ymlPath = path32.resolve(root, ".aider.conf.yml");
11980
+ const ymlPath = path34.resolve(root, ".aider.conf.yml");
11617
11981
  if (results.some((r) => r.filePath === ".aider.conf.yml")) return;
11618
11982
  try {
11619
11983
  const conventionsRef = "read: CONVENTIONS.md";
11620
- if (fs29.existsSync(ymlPath)) {
11621
- const existingContent = fs29.readFileSync(ymlPath, "utf-8");
11984
+ if (fs31.existsSync(ymlPath)) {
11985
+ const existingContent = fs31.readFileSync(ymlPath, "utf-8");
11622
11986
  if (existingContent.includes("CONVENTIONS.md") || existingContent.includes("kuma")) {
11623
11987
  results.push({ type: "aider", filePath: ".aider.conf.yml", action: "skipped" });
11624
11988
  return;
11625
11989
  }
11626
11990
  const newContent = existingContent.trimEnd() + "\n\n# Kuma MCP conventions\n" + conventionsRef + "\n";
11627
- fs29.writeFileSync(ymlPath, newContent, "utf-8");
11991
+ fs31.writeFileSync(ymlPath, newContent, "utf-8");
11628
11992
  results.push({ type: "aider", filePath: ".aider.conf.yml", action: "appended" });
11629
11993
  } else {
11630
11994
  const content = [
@@ -11634,7 +11998,7 @@ function handleAiderSecondary(root, results) {
11634
11998
  conventionsRef,
11635
11999
  ""
11636
12000
  ].join("\n");
11637
- fs29.writeFileSync(ymlPath, content, "utf-8");
12001
+ fs31.writeFileSync(ymlPath, content, "utf-8");
11638
12002
  results.push({ type: "aider", filePath: ".aider.conf.yml", action: "created" });
11639
12003
  }
11640
12004
  } catch (err) {
@@ -11647,10 +12011,10 @@ function handleAiderSecondary(root, results) {
11647
12011
  }
11648
12012
  }
11649
12013
  function handleCopilotSecondary(root, results) {
11650
- const skillPath = path32.resolve(root, ".github/skills/kuma/SKILL.md");
12014
+ const skillPath = path34.resolve(root, ".github/skills/kuma/SKILL.md");
11651
12015
  if (results.some((r) => r.filePath === ".github/skills/kuma/SKILL.md")) return;
11652
12016
  try {
11653
- const dir = path32.dirname(skillPath);
12017
+ const dir = path34.dirname(skillPath);
11654
12018
  const content = [
11655
12019
  "---",
11656
12020
  "name: kuma-mcp",
@@ -11661,17 +12025,17 @@ function handleCopilotSecondary(root, results) {
11661
12025
  "",
11662
12026
  "\u{1F4D6} Read `.kuma/init.md` for detailed rules."
11663
12027
  ].join("\n");
11664
- if (fs29.existsSync(skillPath)) {
11665
- const existingContent = fs29.readFileSync(skillPath, "utf-8");
12028
+ if (fs31.existsSync(skillPath)) {
12029
+ const existingContent = fs31.readFileSync(skillPath, "utf-8");
11666
12030
  if (existingContent.includes("kuma")) {
11667
12031
  results.push({ type: "copilot", filePath: ".github/skills/kuma/SKILL.md", action: "skipped" });
11668
12032
  return;
11669
12033
  }
11670
- fs29.writeFileSync(skillPath, existingContent.trimEnd() + "\n\n" + content, "utf-8");
12034
+ fs31.writeFileSync(skillPath, existingContent.trimEnd() + "\n\n" + content, "utf-8");
11671
12035
  results.push({ type: "copilot", filePath: ".github/skills/kuma/SKILL.md", action: "appended" });
11672
12036
  } else {
11673
- if (!fs29.existsSync(dir)) fs29.mkdirSync(dir, { recursive: true });
11674
- fs29.writeFileSync(skillPath, content, "utf-8");
12037
+ if (!fs31.existsSync(dir)) fs31.mkdirSync(dir, { recursive: true });
12038
+ fs31.writeFileSync(skillPath, content, "utf-8");
11675
12039
  results.push({ type: "copilot", filePath: ".github/skills/kuma/SKILL.md", action: "created" });
11676
12040
  }
11677
12041
  } catch (err) {
@@ -11684,21 +12048,21 @@ function handleCopilotSecondary(root, results) {
11684
12048
  }
11685
12049
  }
11686
12050
  function handleOpenclawSecondary(root, results) {
11687
- const mcpPath = path32.resolve(root, ".agents/mcp_config.json");
12051
+ const mcpPath = path34.resolve(root, ".agents/mcp_config.json");
11688
12052
  if (results.some((r) => r.filePath === ".agents/mcp_config.json")) return;
11689
12053
  try {
11690
- const dir = path32.dirname(mcpPath);
11691
- if (fs29.existsSync(mcpPath)) {
11692
- const existingContent = fs29.readFileSync(mcpPath, "utf-8");
12054
+ const dir = path34.dirname(mcpPath);
12055
+ if (fs31.existsSync(mcpPath)) {
12056
+ const existingContent = fs31.readFileSync(mcpPath, "utf-8");
11693
12057
  if (existingContent.includes("kuma")) return;
11694
12058
  const parsed = JSON.parse(existingContent);
11695
12059
  parsed.mcpServers = parsed.mcpServers || {};
11696
12060
  parsed.mcpServers.kuma = { command: "npx", args: ["-y", "@plumpslabs/kuma"], env: {} };
11697
- fs29.writeFileSync(mcpPath, JSON.stringify(parsed, null, 2) + "\n", "utf-8");
12061
+ fs31.writeFileSync(mcpPath, JSON.stringify(parsed, null, 2) + "\n", "utf-8");
11698
12062
  results.push({ type: "openclaw", filePath: ".agents/mcp_config.json", action: "appended" });
11699
12063
  } else {
11700
- if (!fs29.existsSync(dir)) fs29.mkdirSync(dir, { recursive: true });
11701
- fs29.writeFileSync(mcpPath, antigravityMcpConfigTemplate(), "utf-8");
12064
+ if (!fs31.existsSync(dir)) fs31.mkdirSync(dir, { recursive: true });
12065
+ fs31.writeFileSync(mcpPath, antigravityMcpConfigTemplate(), "utf-8");
11702
12066
  results.push({ type: "openclaw", filePath: ".agents/mcp_config.json", action: "created" });
11703
12067
  }
11704
12068
  } catch (err) {
@@ -11711,20 +12075,20 @@ function handleOpenclawSecondary(root, results) {
11711
12075
  }
11712
12076
  }
11713
12077
  function handleInitMdGeneration(root, results) {
11714
- const initMdPath = path32.resolve(root, ".kuma/init.md");
12078
+ const initMdPath = path34.resolve(root, ".kuma/init.md");
11715
12079
  try {
11716
- const kumaDir = path32.dirname(initMdPath);
11717
- if (!fs29.existsSync(kumaDir)) fs29.mkdirSync(kumaDir, { recursive: true });
11718
- if (fs29.existsSync(initMdPath)) {
11719
- const existing = fs29.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");
11720
12084
  if (existing.includes("_Generated by Kuma MCP_")) {
11721
12085
  results.push({ type: "claude", filePath: ".kuma/init.md", action: "skipped" });
11722
12086
  return;
11723
12087
  }
11724
- fs29.writeFileSync(initMdPath, existing.trimEnd() + "\n\n" + generateInitMdContent(), "utf-8");
12088
+ fs31.writeFileSync(initMdPath, existing.trimEnd() + "\n\n" + generateInitMdContent(), "utf-8");
11725
12089
  results.push({ type: "claude", filePath: ".kuma/init.md", action: "appended" });
11726
12090
  } else {
11727
- fs29.writeFileSync(initMdPath, generateInitMdContent(), "utf-8");
12091
+ fs31.writeFileSync(initMdPath, generateInitMdContent(), "utf-8");
11728
12092
  results.push({ type: "claude", filePath: ".kuma/init.md", action: "created" });
11729
12093
  }
11730
12094
  } catch (err) {
@@ -11737,20 +12101,20 @@ function handleInitMdGeneration(root, results) {
11737
12101
  }
11738
12102
  }
11739
12103
  function handleCodewhaleSecondary(root, results) {
11740
- const mcpPath = path32.resolve(root, ".codewhale/mcp.json");
12104
+ const mcpPath = path34.resolve(root, ".codewhale/mcp.json");
11741
12105
  if (results.some((r) => r.filePath === ".codewhale/mcp.json")) return;
11742
12106
  try {
11743
- const dir = path32.dirname(mcpPath);
11744
- if (fs29.existsSync(mcpPath)) {
11745
- const existingContent = fs29.readFileSync(mcpPath, "utf-8");
12107
+ const dir = path34.dirname(mcpPath);
12108
+ if (fs31.existsSync(mcpPath)) {
12109
+ const existingContent = fs31.readFileSync(mcpPath, "utf-8");
11746
12110
  if (existingContent.includes("kuma")) return;
11747
12111
  const parsed = JSON.parse(existingContent);
11748
12112
  parsed.mcpServers = parsed.mcpServers || {};
11749
12113
  parsed.mcpServers.kuma = { command: "npx", args: ["-y", "@plumpslabs/kuma"], env: {} };
11750
- fs29.writeFileSync(mcpPath, JSON.stringify(parsed, null, 2) + "\n", "utf-8");
12114
+ fs31.writeFileSync(mcpPath, JSON.stringify(parsed, null, 2) + "\n", "utf-8");
11751
12115
  results.push({ type: "codewhale", filePath: ".codewhale/mcp.json", action: "appended" });
11752
12116
  } else {
11753
- if (!fs29.existsSync(dir)) fs29.mkdirSync(dir, { recursive: true });
12117
+ if (!fs31.existsSync(dir)) fs31.mkdirSync(dir, { recursive: true });
11754
12118
  const config = {
11755
12119
  mcpServers: {
11756
12120
  kuma: {
@@ -11760,7 +12124,7 @@ function handleCodewhaleSecondary(root, results) {
11760
12124
  }
11761
12125
  }
11762
12126
  };
11763
- fs29.writeFileSync(mcpPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
12127
+ fs31.writeFileSync(mcpPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
11764
12128
  results.push({ type: "codewhale", filePath: ".codewhale/mcp.json", action: "created" });
11765
12129
  }
11766
12130
  } catch (err) {
@@ -11773,7 +12137,7 @@ function handleCodewhaleSecondary(root, results) {
11773
12137
  }
11774
12138
  }
11775
12139
  function handleClaudeSecondary(root, results) {
11776
- const settingsPath = path32.resolve(root, ".claude", "settings.json");
12140
+ const settingsPath = path34.resolve(root, ".claude", "settings.json");
11777
12141
  const hookBlock = {
11778
12142
  hooks: {
11779
12143
  PreToolUse: [
@@ -11804,8 +12168,8 @@ function handleClaudeSecondary(root, results) {
11804
12168
  }
11805
12169
  };
11806
12170
  try {
11807
- if (fs29.existsSync(settingsPath)) {
11808
- const existing = JSON.parse(fs29.readFileSync(settingsPath, "utf-8"));
12171
+ if (fs31.existsSync(settingsPath)) {
12172
+ const existing = JSON.parse(fs31.readFileSync(settingsPath, "utf-8"));
11809
12173
  const existingHooks = existing.hooks || {};
11810
12174
  const mergedPre = [...existingHooks.PreToolUse || []];
11811
12175
  for (const entry of hookBlock.hooks.PreToolUse) {
@@ -11829,12 +12193,12 @@ function handleClaudeSecondary(root, results) {
11829
12193
  ...existing,
11830
12194
  hooks: { ...existingHooks, PreToolUse: mergedPre, SessionStart: mergedStart, PreCompact: mergedCompact }
11831
12195
  };
11832
- fs29.writeFileSync(settingsPath, JSON.stringify(merged, null, 2) + "\n", "utf-8");
12196
+ fs31.writeFileSync(settingsPath, JSON.stringify(merged, null, 2) + "\n", "utf-8");
11833
12197
  results.push({ type: "claude", filePath: ".claude/settings.json", action: "appended" });
11834
12198
  } else {
11835
- const dir = path32.dirname(settingsPath);
11836
- if (!fs29.existsSync(dir)) fs29.mkdirSync(dir, { recursive: true });
11837
- fs29.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");
11838
12202
  results.push({ type: "claude", filePath: ".claude/settings.json", action: "created" });
11839
12203
  }
11840
12204
  } catch (err) {
@@ -11845,10 +12209,10 @@ function handleClaudeSecondary(root, results) {
11845
12209
  error: err instanceof Error ? err.message : String(err)
11846
12210
  });
11847
12211
  }
11848
- const skillPath = path32.resolve(root, ".claude", "skills", "kuma", "SKILL.md");
12212
+ const skillPath = path34.resolve(root, ".claude", "skills", "kuma", "SKILL.md");
11849
12213
  if (!results.some((r) => r.filePath === ".claude/skills/kuma/SKILL.md")) {
11850
12214
  try {
11851
- const dir = path32.dirname(skillPath);
12215
+ const dir = path34.dirname(skillPath);
11852
12216
  const content = [
11853
12217
  "---",
11854
12218
  "name: kuma-mcp",
@@ -11860,17 +12224,17 @@ function handleClaudeSecondary(root, results) {
11860
12224
  "\u{1F4D6} Read `.kuma/init.md` for detailed rules.",
11861
12225
  "\u{1F4C2} Readable state: `.kuma/KNOWN_GOTCHAS.md` (gotchas) \xB7 `.kuma/memories/decisions.md` (decisions)"
11862
12226
  ].join("\n");
11863
- if (fs29.existsSync(skillPath)) {
11864
- const existing = fs29.readFileSync(skillPath, "utf-8");
12227
+ if (fs31.existsSync(skillPath)) {
12228
+ const existing = fs31.readFileSync(skillPath, "utf-8");
11865
12229
  if (existing.includes("kuma-mcp")) {
11866
12230
  results.push({ type: "claude", filePath: ".claude/skills/kuma/SKILL.md", action: "skipped" });
11867
12231
  } else {
11868
- fs29.writeFileSync(skillPath, existing.trimEnd() + "\n\n---\n\n" + content, "utf-8");
12232
+ fs31.writeFileSync(skillPath, existing.trimEnd() + "\n\n---\n\n" + content, "utf-8");
11869
12233
  results.push({ type: "claude", filePath: ".claude/skills/kuma/SKILL.md", action: "appended" });
11870
12234
  }
11871
12235
  } else {
11872
- if (!fs29.existsSync(dir)) fs29.mkdirSync(dir, { recursive: true });
11873
- fs29.writeFileSync(skillPath, content, "utf-8");
12236
+ if (!fs31.existsSync(dir)) fs31.mkdirSync(dir, { recursive: true });
12237
+ fs31.writeFileSync(skillPath, content, "utf-8");
11874
12238
  results.push({ type: "claude", filePath: ".claude/skills/kuma/SKILL.md", action: "created" });
11875
12239
  }
11876
12240
  } catch (err) {
@@ -11884,27 +12248,27 @@ function handleClaudeSecondary(root, results) {
11884
12248
  }
11885
12249
  }
11886
12250
  function writeHooksFile(root, relPath, type, results, build) {
11887
- const fullPath = path32.resolve(root, relPath);
12251
+ const fullPath = path34.resolve(root, relPath);
11888
12252
  try {
11889
12253
  let existing = {};
11890
12254
  let existed = false;
11891
- if (fs29.existsSync(fullPath)) {
12255
+ if (fs31.existsSync(fullPath)) {
11892
12256
  existed = true;
11893
12257
  try {
11894
- existing = JSON.parse(fs29.readFileSync(fullPath, "utf-8"));
12258
+ existing = JSON.parse(fs31.readFileSync(fullPath, "utf-8"));
11895
12259
  } catch {
11896
12260
  existing = {};
11897
12261
  }
11898
12262
  } else {
11899
- const dir = path32.dirname(fullPath);
11900
- if (!fs29.existsSync(dir)) fs29.mkdirSync(dir, { recursive: true });
12263
+ const dir = path34.dirname(fullPath);
12264
+ if (!fs31.existsSync(dir)) fs31.mkdirSync(dir, { recursive: true });
11901
12265
  }
11902
12266
  const { doc, changed } = build(existing);
11903
12267
  if (!changed) {
11904
12268
  results.push({ type, filePath: relPath, action: "skipped" });
11905
12269
  return;
11906
12270
  }
11907
- fs29.writeFileSync(fullPath, JSON.stringify(doc, null, 2) + "\n", "utf-8");
12271
+ fs31.writeFileSync(fullPath, JSON.stringify(doc, null, 2) + "\n", "utf-8");
11908
12272
  results.push({ type, filePath: relPath, action: existed ? "appended" : "created" });
11909
12273
  } catch (err) {
11910
12274
  results.push({ type, filePath: relPath, action: "error", error: err instanceof Error ? err.message : String(err) });
@@ -11985,18 +12349,18 @@ function handleCodexHooks(root, results) {
11985
12349
  });
11986
12350
  }
11987
12351
  function handleCursorGotchaRules(root, results) {
11988
- const rulesDir2 = path32.resolve(root, ".cursor", "rules", "kuma-gotchas");
12352
+ const rulesDir2 = path34.resolve(root, ".cursor", "rules", "kuma-gotchas");
11989
12353
  try {
11990
12354
  let gotchas = [];
11991
12355
  try {
11992
12356
  gotchas = getActiveGotchas().filter((g) => g.severity === "high" || g.severity === "critical");
11993
12357
  } catch {
11994
12358
  }
11995
- if (fs29.existsSync(rulesDir2)) {
11996
- for (const f of fs29.readdirSync(rulesDir2)) {
12359
+ if (fs31.existsSync(rulesDir2)) {
12360
+ for (const f of fs31.readdirSync(rulesDir2)) {
11997
12361
  if (f.endsWith(".mdc")) {
11998
12362
  try {
11999
- fs29.rmSync(path32.join(rulesDir2, f), { force: true });
12363
+ fs31.rmSync(path34.join(rulesDir2, f), { force: true });
12000
12364
  } catch {
12001
12365
  }
12002
12366
  }
@@ -12006,7 +12370,7 @@ function handleCursorGotchaRules(root, results) {
12006
12370
  results.push({ type: "cursor", filePath: ".cursor/rules/kuma-gotchas/", action: "skipped" });
12007
12371
  return;
12008
12372
  }
12009
- fs29.mkdirSync(rulesDir2, { recursive: true });
12373
+ fs31.mkdirSync(rulesDir2, { recursive: true });
12010
12374
  const seen = /* @__PURE__ */ new Set();
12011
12375
  let created = 0;
12012
12376
  for (const g of gotchas) {
@@ -12027,7 +12391,7 @@ function handleCursorGotchaRules(root, results) {
12027
12391
  "`kuma_context({ action: 'history', target: '<file>' })`",
12028
12392
  ""
12029
12393
  ].join("\n");
12030
- fs29.writeFileSync(path32.join(rulesDir2, `${slug2}.mdc`), md, "utf-8");
12394
+ fs31.writeFileSync(path34.join(rulesDir2, `${slug2}.mdc`), md, "utf-8");
12031
12395
  created++;
12032
12396
  }
12033
12397
  results.push({
@@ -12054,28 +12418,28 @@ function runInit(options) {
12054
12418
  let agentsMdHandled = false;
12055
12419
  for (const type of selected) {
12056
12420
  const relativePath = configFilePath(type);
12057
- const fullPath = path32.resolve(root, relativePath);
12421
+ const fullPath = path34.resolve(root, relativePath);
12058
12422
  const getTemplate = TEMPLATES[type];
12059
12423
  try {
12060
12424
  if (AGENTS_MD_TYPES.includes(type) && !agentsMdHandled) {
12061
12425
  agentsMdHandled = true;
12062
12426
  const combinedContent = getCombinedAgentsMd(new Set(agentsMdSelected));
12063
- if (fs29.existsSync(fullPath)) {
12427
+ if (fs31.existsSync(fullPath)) {
12064
12428
  if (options.skipExisting) {
12065
12429
  results.push({ type, filePath: relativePath, action: "skipped" });
12066
12430
  } else {
12067
- const existingContent = fs29.readFileSync(fullPath, "utf-8");
12431
+ const existingContent = fs31.readFileSync(fullPath, "utf-8");
12068
12432
  if (existingContent.includes("_Generated by Kuma MCP_")) {
12069
12433
  results.push({ type, filePath: relativePath, action: "skipped" });
12070
12434
  } else {
12071
- fs29.writeFileSync(fullPath, existingContent.trimEnd() + "\n\n" + combinedContent, "utf-8");
12435
+ fs31.writeFileSync(fullPath, existingContent.trimEnd() + "\n\n" + combinedContent, "utf-8");
12072
12436
  results.push({ type, filePath: relativePath, action: "appended" });
12073
12437
  }
12074
12438
  }
12075
12439
  } else {
12076
- const dir = path32.dirname(fullPath);
12077
- if (!fs29.existsSync(dir)) fs29.mkdirSync(dir, { recursive: true });
12078
- fs29.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");
12079
12443
  results.push({ type, filePath: relativePath, action: "created" });
12080
12444
  }
12081
12445
  if (selectedSet.has("opencode")) handleOpencodeSecondary(root, results);
@@ -12087,12 +12451,12 @@ function runInit(options) {
12087
12451
  continue;
12088
12452
  } else {
12089
12453
  const template = getTemplate();
12090
- if (fs29.existsSync(fullPath)) {
12454
+ if (fs31.existsSync(fullPath)) {
12091
12455
  if (options.skipExisting) {
12092
12456
  results.push({ type, filePath: relativePath, action: "skipped" });
12093
12457
  continue;
12094
12458
  }
12095
- const existingContent = fs29.readFileSync(fullPath, "utf-8");
12459
+ const existingContent = fs31.readFileSync(fullPath, "utf-8");
12096
12460
  if (existingContent.includes("_Generated by Kuma MCP_")) {
12097
12461
  if (type === "antigravity") {
12098
12462
  handleAntigravitySecondary(root, results);
@@ -12109,14 +12473,14 @@ function runInit(options) {
12109
12473
  continue;
12110
12474
  }
12111
12475
  const newContent = existingContent.trimEnd() + APPEND_SEPARATOR + template;
12112
- fs29.writeFileSync(fullPath, newContent, "utf-8");
12476
+ fs31.writeFileSync(fullPath, newContent, "utf-8");
12113
12477
  results.push({ type, filePath: relativePath, action: "appended" });
12114
12478
  } else {
12115
- const dir = path32.dirname(fullPath);
12116
- if (!fs29.existsSync(dir)) {
12117
- fs29.mkdirSync(dir, { recursive: true });
12479
+ const dir = path34.dirname(fullPath);
12480
+ if (!fs31.existsSync(dir)) {
12481
+ fs31.mkdirSync(dir, { recursive: true });
12118
12482
  }
12119
- fs29.writeFileSync(fullPath, template, "utf-8");
12483
+ fs31.writeFileSync(fullPath, template, "utf-8");
12120
12484
  results.push({ type, filePath: relativePath, action: "created" });
12121
12485
  }
12122
12486
  if (type === "antigravity") {
@@ -12288,8 +12652,8 @@ var compactionContext_exports = {};
12288
12652
  __export(compactionContext_exports, {
12289
12653
  getCompactionContext: () => getCompactionContext
12290
12654
  });
12291
- import fs30 from "fs";
12292
- import path33 from "path";
12655
+ import fs32 from "fs";
12656
+ import path35 from "path";
12293
12657
  async function getCompactionContext() {
12294
12658
  const parts = [];
12295
12659
  try {
@@ -12302,8 +12666,8 @@ async function getCompactionContext() {
12302
12666
  } catch {
12303
12667
  }
12304
12668
  try {
12305
- const dbFile = path33.join(getProjectRoot(), ".kuma", "kuma.db");
12306
- if (fs30.existsSync(dbFile)) {
12669
+ const dbFile = path35.join(getProjectRoot(), ".kuma", "kuma.db");
12670
+ if (fs32.existsSync(dbFile)) {
12307
12671
  const { getDb: getDb2 } = await Promise.resolve().then(() => (init_kumaDb(), kumaDb_exports));
12308
12672
  const db = await getDb2();
12309
12673
  const stmt = db.prepare(
@@ -12329,9 +12693,9 @@ async function getCompactionContext() {
12329
12693
  } catch {
12330
12694
  }
12331
12695
  try {
12332
- const cpDir = path33.join(getProjectRoot(), ".kuma", "checkpoints");
12333
- if (fs30.existsSync(cpDir)) {
12334
- const cps = fs30.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);
12335
12699
  if (cps.length > 0) parts.push(`Checkpoints: ${cps.join(", ")}`);
12336
12700
  }
12337
12701
  } catch {
@@ -12349,6 +12713,196 @@ var init_compactionContext = __esm({
12349
12713
  }
12350
12714
  });
12351
12715
 
12716
+ // src/engine/kumaDaemon.ts
12717
+ var kumaDaemon_exports = {};
12718
+ __export(kumaDaemon_exports, {
12719
+ DEFAULT_INTERVAL_MS: () => DEFAULT_INTERVAL_MS,
12720
+ daemonRunChild: () => daemonRunChild,
12721
+ daemonStart: () => daemonStart,
12722
+ daemonStatus: () => daemonStatus,
12723
+ daemonStop: () => daemonStop,
12724
+ daemonTick: () => daemonTick
12725
+ });
12726
+ import fs33 from "fs";
12727
+ import path36 from "path";
12728
+ import { spawn } from "child_process";
12729
+ function paths(root) {
12730
+ const r = root || getProjectRoot();
12731
+ return {
12732
+ pid: path36.join(r, PID_FILE),
12733
+ status: path36.join(r, STATUS_FILE),
12734
+ log: path36.join(r, LOG_FILE)
12735
+ };
12736
+ }
12737
+ function readPid(root) {
12738
+ try {
12739
+ const fp = paths(root).pid;
12740
+ if (!fs33.existsSync(fp)) return null;
12741
+ const pid = Number(fs33.readFileSync(fp, "utf-8").trim());
12742
+ return Number.isFinite(pid) && pid > 0 ? pid : null;
12743
+ } catch {
12744
+ return null;
12745
+ }
12746
+ }
12747
+ function isAlive(pid) {
12748
+ try {
12749
+ process.kill(pid, 0);
12750
+ return true;
12751
+ } catch {
12752
+ return false;
12753
+ }
12754
+ }
12755
+ async function daemonTick(root) {
12756
+ const r = root || getProjectRoot();
12757
+ const p = paths(r);
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
+ }
12765
+ try {
12766
+ const { syncModifiedFiles: syncModifiedFiles2 } = await Promise.resolve().then(() => (init_kumaCodeScanner(), kumaCodeScanner_exports));
12767
+ const scan = await syncModifiedFiles2(50);
12768
+ notes.push(`map: ${scan.filesScanned}f/${scan.nodeCount}n/${scan.edgeCount}e`);
12769
+ } catch (err) {
12770
+ notes.push(`map: skipped (${err})`);
12771
+ }
12772
+ try {
12773
+ const { refreshPackageBriefs: refreshPackageBriefs2 } = await Promise.resolve().then(() => (init_packageBriefs(), packageBriefs_exports));
12774
+ const { count } = await refreshPackageBriefs2();
12775
+ notes.push(`briefs: ${count}`);
12776
+ } catch {
12777
+ notes.push("briefs: skipped");
12778
+ }
12779
+ try {
12780
+ const { detectDrift: detectDrift2 } = await Promise.resolve().then(() => (init_kumaDriftDetector(), kumaDriftDetector_exports));
12781
+ const records = await detectDrift2();
12782
+ const stale = records.filter((x) => x.severity === "stale" || x.severity === "missing").length;
12783
+ notes.push(`drift: ${stale}/${records.length} stale`);
12784
+ } catch {
12785
+ notes.push("drift: skipped");
12786
+ }
12787
+ try {
12788
+ const { clearDirty: clearDirty2 } = await Promise.resolve().then(() => (init_cacheFreshness(), cacheFreshness_exports));
12789
+ clearDirty2();
12790
+ } catch {
12791
+ }
12792
+ const status = {
12793
+ lastRunAt: Date.now(),
12794
+ lastResult: notes.join(" \xB7 ")
12795
+ };
12796
+ try {
12797
+ let prev = {};
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");
12800
+ } catch {
12801
+ }
12802
+ return notes.join(" \xB7 ");
12803
+ }
12804
+ async function runLoop(intervalMs) {
12805
+ const r = getProjectRoot();
12806
+ const p = paths(r);
12807
+ const log = (msg) => {
12808
+ try {
12809
+ fs33.appendFileSync(p.log, `${(/* @__PURE__ */ new Date()).toISOString()} ${msg}
12810
+ `, "utf-8");
12811
+ } catch {
12812
+ }
12813
+ };
12814
+ log(`daemon started (interval ${intervalMs}ms)`);
12815
+ for (; ; ) {
12816
+ try {
12817
+ const res = await daemonTick(r);
12818
+ log(`tick: ${res}`);
12819
+ } catch (err) {
12820
+ log(`tick failed: ${err}`);
12821
+ }
12822
+ await new Promise((resolve) => setTimeout(resolve, intervalMs));
12823
+ }
12824
+ }
12825
+ async function daemonStart(intervalMs = DEFAULT_INTERVAL_MS, root) {
12826
+ const r = root || getProjectRoot();
12827
+ const p = paths(r);
12828
+ const existing = readPid(r);
12829
+ if (existing && isAlive(existing)) {
12830
+ return `\u{1F43B} Daemon already running (pid ${existing}). Use \`kuma daemon stop\` first.`;
12831
+ }
12832
+ const entry = process.argv[1];
12833
+ const child = spawn(process.execPath, [entry, "daemon", "run", String(intervalMs)], {
12834
+ cwd: r,
12835
+ detached: true,
12836
+ stdio: "ignore"
12837
+ });
12838
+ child.unref();
12839
+ try {
12840
+ fs33.writeFileSync(p.pid, String(child.pid), "utf-8");
12841
+ fs33.writeFileSync(
12842
+ p.status,
12843
+ JSON.stringify({ running: true, pid: child.pid, startedAt: Date.now(), lastRunAt: null, lastResult: null, intervalMs }, null, 2),
12844
+ "utf-8"
12845
+ );
12846
+ } catch {
12847
+ }
12848
+ return `\u{1F43B} Daemon started (pid ${child.pid}, every ${Math.round(intervalMs / 6e4)}m). Status: .kuma/daemon-status.json`;
12849
+ }
12850
+ async function daemonStop(root) {
12851
+ const r = root || getProjectRoot();
12852
+ const p = paths(r);
12853
+ const pid = readPid(r);
12854
+ if (!pid) return "\u{1F43B} Daemon not running (no pid file).";
12855
+ if (!isAlive(pid)) {
12856
+ try {
12857
+ fs33.rmSync(p.pid, { force: true });
12858
+ } catch {
12859
+ }
12860
+ return "\u{1F43B} Daemon pid file was stale \u2014 cleaned up (process already gone).";
12861
+ }
12862
+ try {
12863
+ process.kill(pid, "SIGTERM");
12864
+ try {
12865
+ fs33.rmSync(p.pid, { force: true });
12866
+ } catch {
12867
+ }
12868
+ return `\u{1F43B} Daemon stopped (was pid ${pid}).`;
12869
+ } catch (err) {
12870
+ return `\u{1F43B} Could not stop daemon pid ${pid}: ${err}`;
12871
+ }
12872
+ }
12873
+ async function daemonStatus(root) {
12874
+ const r = root || getProjectRoot();
12875
+ const p = paths(r);
12876
+ const pid = readPid(r);
12877
+ let status = { running: false, pid: null, startedAt: null, lastRunAt: null, lastResult: null, intervalMs: DEFAULT_INTERVAL_MS };
12878
+ try {
12879
+ if (fs33.existsSync(p.status)) status = { ...status, ...JSON.parse(fs33.readFileSync(p.status, "utf-8")) };
12880
+ } catch {
12881
+ }
12882
+ const alive = pid !== null && isAlive(pid);
12883
+ status.running = alive;
12884
+ status.pid = alive ? pid : null;
12885
+ if (!alive) {
12886
+ return `\u{1F43B} Daemon: stopped.${status.lastRunAt ? ` Last tick ${new Date(status.lastRunAt).toISOString()}: ${status.lastResult || "n/a"}` : " Never ran."} Start with \`kuma daemon start\`.`;
12887
+ }
12888
+ return `\u{1F43B} Daemon: running (pid ${pid}).${status.lastRunAt ? ` Last tick ${new Date(status.lastRunAt).toISOString()}: ${status.lastResult || "n/a"}` : " Warming up\u2026"}`;
12889
+ }
12890
+ async function daemonRunChild(intervalMs) {
12891
+ const ms = Number.isFinite(intervalMs) && intervalMs >= 3e4 ? intervalMs : DEFAULT_INTERVAL_MS;
12892
+ await runLoop(ms);
12893
+ }
12894
+ var PID_FILE, STATUS_FILE, LOG_FILE, DEFAULT_INTERVAL_MS;
12895
+ var init_kumaDaemon = __esm({
12896
+ "src/engine/kumaDaemon.ts"() {
12897
+ "use strict";
12898
+ init_pathValidator();
12899
+ PID_FILE = ".kuma/daemon.pid";
12900
+ STATUS_FILE = ".kuma/daemon-status.json";
12901
+ LOG_FILE = ".kuma/daemon.log";
12902
+ DEFAULT_INTERVAL_MS = 5 * 60 * 1e3;
12903
+ }
12904
+ });
12905
+
12352
12906
  // src/utils/agentDetector.ts
12353
12907
  var agentDetector_exports = {};
12354
12908
  __export(agentDetector_exports, {
@@ -12357,19 +12911,19 @@ __export(agentDetector_exports, {
12357
12911
  getSkillPath: () => getSkillPath,
12358
12912
  skillExists: () => skillExists
12359
12913
  });
12360
- import fs31 from "fs";
12361
- import path34 from "path";
12914
+ import fs34 from "fs";
12915
+ import path37 from "path";
12362
12916
  function checkFile(root, filePath) {
12363
12917
  try {
12364
- return fs31.existsSync(path34.join(root, filePath));
12918
+ return fs34.existsSync(path37.join(root, filePath));
12365
12919
  } catch {
12366
12920
  return false;
12367
12921
  }
12368
12922
  }
12369
12923
  function checkDir(root, dirPath) {
12370
12924
  try {
12371
- const fullPath = path34.join(root, dirPath);
12372
- return fs31.existsSync(fullPath) && fs31.statSync(fullPath).isDirectory();
12925
+ const fullPath = path37.join(root, dirPath);
12926
+ return fs34.existsSync(fullPath) && fs34.statSync(fullPath).isDirectory();
12373
12927
  } catch {
12374
12928
  return false;
12375
12929
  }
@@ -12437,7 +12991,7 @@ function getAgentLabel(type) {
12437
12991
  function skillExists(type, projectRoot) {
12438
12992
  const root = projectRoot ?? getProjectRoot();
12439
12993
  const skillPath = getSkillPath(type);
12440
- return fs31.existsSync(path34.join(root, skillPath));
12994
+ return fs34.existsSync(path37.join(root, skillPath));
12441
12995
  }
12442
12996
  var AGENT_DETECTORS;
12443
12997
  var init_agentDetector = __esm({
@@ -13033,8 +13587,8 @@ init_kumaGraph();
13033
13587
  init_kumaMemory();
13034
13588
  init_kumaDriftDetector();
13035
13589
  init_pathValidator();
13036
- import fs21 from "fs";
13037
- import path24 from "path";
13590
+ import fs23 from "fs";
13591
+ import path26 from "path";
13038
13592
  var CONTEXT_ALIASES = {
13039
13593
  "research": "research",
13040
13594
  "search": "research",
@@ -13153,6 +13707,15 @@ async function handleCluster(_params) {
13153
13707
  async function handleInit(_params) {
13154
13708
  sessionMemory.setGoal(_params.goal || "Exploring project");
13155
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
+ }
13156
13719
  const branch = sessionMemory.getCurrentBranch();
13157
13720
  const branchTag = branch ? ` [git: \`${branch}\`]` : "";
13158
13721
  const lines = [
@@ -13162,6 +13725,7 @@ async function handleInit(_params) {
13162
13725
  `\u{1F4C1} Project: ${getProjectRoot().split("/").pop() || "unknown"}${branchTag}`,
13163
13726
  ""
13164
13727
  ];
13728
+ if (backboneNote) lines.push(backboneNote);
13165
13729
  const branchTransition = sessionMemory.getBranchTransition();
13166
13730
  if (branchTransition?.switched) {
13167
13731
  lines.push(`\u{1F500} **Branch switched**: from \`${branchTransition.from}\` to \`${branchTransition.to}\`. Session context updated.`);
@@ -13361,6 +13925,14 @@ async function handleResearch(params, dirtySynced = 0) {
13361
13925
  } else lines.push(" \u23F3 No content hash available \u2014 will research fresh");
13362
13926
  lines.push("");
13363
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
+ }
13364
13936
  try {
13365
13937
  const graphResult = await searchGraph(scope, 15);
13366
13938
  const graphLines = graphResult.split("\n");
@@ -13451,10 +14023,10 @@ async function handleHistory(params) {
13451
14023
  lines.push(traceFormatted);
13452
14024
  } else {
13453
14025
  try {
13454
- const { execSync: execSync9 } = await import("child_process");
14026
+ const { execSync: execSync10 } = await import("child_process");
13455
14027
  const { getProjectRoot: getProjectRoot2 } = await Promise.resolve().then(() => (init_pathValidator(), pathValidator_exports));
13456
14028
  const root = getProjectRoot2();
13457
- const gitHistory = execSync9(
14029
+ const gitHistory = execSync10(
13458
14030
  `git log -n 5 --pretty=format:" \u2022 %h (%ad) %s" --date=short -- "${target}"`,
13459
14031
  { cwd: root, encoding: "utf-8", timeout: 3e3, stdio: ["pipe", "pipe", "pipe"] }
13460
14032
  ).trim();
@@ -13486,7 +14058,7 @@ ${gitHistory}`);
13486
14058
  try {
13487
14059
  const { getDb: getDb2 } = await Promise.resolve().then(() => (init_kumaDb(), kumaDb_exports));
13488
14060
  const db = await getDb2();
13489
- const base = path24.basename(target);
14061
+ const base = path26.basename(target);
13490
14062
  const stmt = db.prepare(`
13491
14063
  SELECT description, last_verified_at FROM known_gotchas
13492
14064
  WHERE status = 'resolved' AND (file_path LIKE ? OR file_path LIKE ?)
@@ -13499,9 +14071,9 @@ ${gitHistory}`);
13499
14071
  if (resolved.length === 0) {
13500
14072
  try {
13501
14073
  const { getProjectRoot: getProjectRoot2 } = await Promise.resolve().then(() => (init_pathValidator(), pathValidator_exports));
13502
- const mdPath = path24.join(getProjectRoot2(), ".kuma", "KNOWN_GOTCHAS.md");
13503
- if (fs21.existsSync(mdPath)) {
13504
- const mdContent = fs21.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");
13505
14077
  const sections = mdContent.split(/^###\s+/m);
13506
14078
  for (const sec of sections) {
13507
14079
  const secLower = sec.toLowerCase();
@@ -13573,8 +14145,8 @@ init_kumaDb();
13573
14145
  init_kumaMemory();
13574
14146
  init_pathValidator();
13575
14147
  init_pathValidator();
13576
- import fs23 from "fs";
13577
- import path26 from "path";
14148
+ import fs25 from "fs";
14149
+ import path28 from "path";
13578
14150
  var MEMORY_ALIASES = {
13579
14151
  "decision": "decision",
13580
14152
  "adr": "decision",
@@ -13685,9 +14257,9 @@ async function handleResearchSave(params) {
13685
14257
  } catch {
13686
14258
  }
13687
14259
  try {
13688
- const researchDir = path26.join(getProjectRoot(), ".kuma", "research");
13689
- if (!fs23.existsSync(researchDir)) fs23.mkdirSync(researchDir, { recursive: true });
13690
- fs23.writeFileSync(path26.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");
13691
14263
  } catch {
13692
14264
  }
13693
14265
  sessionMemory.recordMemoryAction("research_save");
@@ -13883,9 +14455,9 @@ init_sessionMemory();
13883
14455
  init_pathValidator();
13884
14456
  init_sessionMemory();
13885
14457
  init_kumaShared();
13886
- import fs24 from "fs";
13887
- import path27 from "path";
13888
- import { execSync as execSync6 } from "child_process";
14458
+ import fs26 from "fs";
14459
+ import path29 from "path";
14460
+ import { execSync as execSync7 } from "child_process";
13889
14461
  var SCRIPT_PATCH_PATTERNS = [
13890
14462
  "writeFileSync",
13891
14463
  "writeFile",
@@ -13911,20 +14483,20 @@ function findPatchScripts(projectRoot) {
13911
14483
  const warnings = [];
13912
14484
  const recentFiles = scanRecentFiles(projectRoot);
13913
14485
  for (const file of recentFiles) {
13914
- const ext = path27.extname(file).toLowerCase();
14486
+ const ext = path29.extname(file).toLowerCase();
13915
14487
  if (!SCRIPT_EXTENSIONS.includes(ext)) continue;
13916
- const relativePath = path27.relative(projectRoot, file);
14488
+ const relativePath = path29.relative(projectRoot, file);
13917
14489
  if (relativePath.startsWith("src") || relativePath.startsWith("test") || relativePath.startsWith("node_modules") || relativePath.startsWith(".") || relativePath.startsWith(".kuma/scratch")) {
13918
14490
  continue;
13919
14491
  }
13920
14492
  try {
13921
- const content = fs24.readFileSync(file, "utf-8").toLowerCase();
14493
+ const content = fs26.readFileSync(file, "utf-8").toLowerCase();
13922
14494
  const matchedPattern = SCRIPT_PATCH_PATTERNS.find((p) => content.includes(p.toLowerCase()));
13923
14495
  if (matchedPattern) {
13924
14496
  warnings.push({
13925
14497
  severity: "high",
13926
14498
  pattern: "script-patching",
13927
- message: `Created script file that modifies other files: ${path27.basename(file)}`,
14499
+ message: `Created script file that modifies other files: ${path29.basename(file)}`,
13928
14500
  suggestion: "Use your native edit tools instead \u2014 targeted edits with auto-backup and rollback",
13929
14501
  evidence: `File: ${relativePath} contains '${matchedPattern}'`,
13930
14502
  filePath: relativePath
@@ -13958,15 +14530,15 @@ function detectBashGrepUsage() {
13958
14530
  function scanRecentFiles(projectRoot) {
13959
14531
  const recent = [];
13960
14532
  try {
13961
- const entries = fs24.readdirSync(projectRoot, { withFileTypes: true });
14533
+ const entries = fs26.readdirSync(projectRoot, { withFileTypes: true });
13962
14534
  const now = Date.now();
13963
14535
  const recentThreshold = 30 * 60 * 1e3;
13964
14536
  for (const entry of entries) {
13965
14537
  if (!entry.isFile()) continue;
13966
14538
  try {
13967
- const stat = fs24.statSync(path27.join(projectRoot, entry.name));
14539
+ const stat = fs26.statSync(path29.join(projectRoot, entry.name));
13968
14540
  if (now - stat.mtimeMs < recentThreshold || now - stat.ctimeMs < recentThreshold) {
13969
- recent.push(path27.join(projectRoot, entry.name));
14541
+ recent.push(path29.join(projectRoot, entry.name));
13970
14542
  }
13971
14543
  } catch {
13972
14544
  continue;
@@ -13979,7 +14551,7 @@ function scanRecentFiles(projectRoot) {
13979
14551
  function detectGitPatchScripts(projectRoot) {
13980
14552
  const warnings = [];
13981
14553
  try {
13982
- const statusStdout = execSync6("git status --porcelain", {
14554
+ const statusStdout = execSync7("git status --porcelain", {
13983
14555
  cwd: projectRoot,
13984
14556
  encoding: "utf-8",
13985
14557
  timeout: 3e3
@@ -13990,14 +14562,14 @@ function detectGitPatchScripts(projectRoot) {
13990
14562
  const prefix = line.substring(0, 2);
13991
14563
  if (prefix !== "??" && prefix !== "A ") continue;
13992
14564
  const file = line.substring(3).trim();
13993
- const ext = path27.extname(file).toLowerCase();
14565
+ const ext = path29.extname(file).toLowerCase();
13994
14566
  if (!SCRIPT_EXTENSIONS.includes(ext)) continue;
13995
14567
  const isRootLevel = !file.includes("/");
13996
14568
  const isScriptsDir = file.startsWith("scripts/") || file.startsWith("patches/");
13997
14569
  if (!isRootLevel && !isScriptsDir) continue;
13998
- const fullPath = path27.join(projectRoot, file);
13999
- if (fs24.existsSync(fullPath)) {
14000
- const content = fs24.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();
14001
14573
  const matchedPattern = SCRIPT_PATCH_PATTERNS.find((p) => content.includes(p.toLowerCase()));
14002
14574
  if (matchedPattern) {
14003
14575
  warnings.push({
@@ -14012,7 +14584,7 @@ function detectGitPatchScripts(projectRoot) {
14012
14584
  }
14013
14585
  }
14014
14586
  }
14015
- const deletedStdout = execSync6("git diff --name-only --diff-filter=D HEAD", {
14587
+ const deletedStdout = execSync7("git diff --name-only --diff-filter=D HEAD", {
14016
14588
  cwd: projectRoot,
14017
14589
  encoding: "utf-8",
14018
14590
  timeout: 3e3
@@ -14020,7 +14592,7 @@ function detectGitPatchScripts(projectRoot) {
14020
14592
  if (deletedStdout) {
14021
14593
  const deletedFiles = deletedStdout.split("\n").filter(Boolean);
14022
14594
  for (const file of deletedFiles) {
14023
- const ext = path27.extname(file).toLowerCase();
14595
+ const ext = path29.extname(file).toLowerCase();
14024
14596
  if (SCRIPT_EXTENSIONS.includes(ext)) {
14025
14597
  warnings.push({
14026
14598
  severity: "high",
@@ -14082,21 +14654,21 @@ function detectAllAntiPatterns() {
14082
14654
  // src/engine/contextSnapshot.ts
14083
14655
  init_sessionMemory();
14084
14656
  init_pathValidator();
14085
- import fs25 from "fs";
14086
- import path28 from "path";
14087
- import { execSync as execSync7 } from "child_process";
14657
+ import fs27 from "fs";
14658
+ import path30 from "path";
14659
+ import { execSync as execSync8 } from "child_process";
14088
14660
  var SNAPSHOT_DIR = "context-snapshots";
14089
14661
  function snapshotDir() {
14090
- return path28.join(getProjectRoot(), ".kuma", SNAPSHOT_DIR);
14662
+ return path30.join(getProjectRoot(), ".kuma", SNAPSHOT_DIR);
14091
14663
  }
14092
14664
  function ensureSnapshotDir() {
14093
14665
  const dir = snapshotDir();
14094
- if (!fs25.existsSync(dir)) {
14095
- fs25.mkdirSync(dir, { recursive: true });
14666
+ if (!fs27.existsSync(dir)) {
14667
+ fs27.mkdirSync(dir, { recursive: true });
14096
14668
  }
14097
14669
  }
14098
14670
  function snapshotFilePath(timestamp) {
14099
- return path28.join(snapshotDir(), `${timestamp}.json`);
14671
+ return path30.join(snapshotDir(), `${timestamp}.json`);
14100
14672
  }
14101
14673
  function saveSnapshot(goal) {
14102
14674
  try {
@@ -14117,7 +14689,7 @@ function saveSnapshot(goal) {
14117
14689
  hasConventions: !!summary.hasConventions
14118
14690
  };
14119
14691
  try {
14120
- fs25.writeFileSync(snapshotFilePath(Date.now()), JSON.stringify(snapshot, null, 2), "utf-8");
14692
+ fs27.writeFileSync(snapshotFilePath(Date.now()), JSON.stringify(snapshot, null, 2), "utf-8");
14121
14693
  } catch {
14122
14694
  }
14123
14695
  sessionMemory.recordToolCall("kuma_context", { action: "save", goal: snapshot.goal });
@@ -14156,7 +14728,7 @@ function formatSnapshot(snapshot) {
14156
14728
  function getGitDiffStat2() {
14157
14729
  try {
14158
14730
  const root = getProjectRoot();
14159
- const stdout = execSync7("git diff --stat", {
14731
+ const stdout = execSync8("git diff --stat", {
14160
14732
  cwd: root,
14161
14733
  encoding: "utf-8",
14162
14734
  timeout: 3e3
@@ -14817,6 +15389,7 @@ Usage:
14817
15389
  npx @plumpslabs/kuma hook pre-compact PreCompact hook \u2014 survival set (goal + critical gotchas + dirty)
14818
15390
  npx @plumpslabs/kuma hook post-commit Git post-commit \u2014 periodic incremental map sync (no rebuild)
14819
15391
  npx @plumpslabs/kuma hook install-git Install the git post-commit hook (idempotent)
15392
+ npx @plumpslabs/kuma daemon start|stop|status Background sensors (map + briefs + drift) every 5m
14820
15393
 
14821
15394
  Available config files:
14822
15395
  --claude CLAUDE.md (Claude Code)
@@ -14909,14 +15482,14 @@ async function main() {
14909
15482
  console.error("");
14910
15483
  let killedCount = 0;
14911
15484
  try {
14912
- const path35 = await import("path");
14913
- const fs32 = await import("fs");
14914
- const lockDir = path35.resolve(process.cwd(), ".kuma/verifier.lock");
14915
- if (fs32.existsSync(lockDir)) {
14916
- const pidFile = path35.join(lockDir, "pid");
14917
- if (fs32.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)) {
14918
15491
  try {
14919
- const pid = parseInt(fs32.readFileSync(pidFile, "utf-8"), 10);
15492
+ const pid = parseInt(fs35.readFileSync(pidFile, "utf-8"), 10);
14920
15493
  if (pid && pid !== process.pid) {
14921
15494
  try {
14922
15495
  process.kill(-pid, "SIGKILL");
@@ -14932,7 +15505,7 @@ async function main() {
14932
15505
  } catch {
14933
15506
  }
14934
15507
  }
14935
- fs32.rmSync(lockDir, { recursive: true, force: true });
15508
+ fs35.rmSync(lockDir, { recursive: true, force: true });
14936
15509
  }
14937
15510
  if (killedCount === 0) {
14938
15511
  console.error("\u2705 No running verifications found to kill.");
@@ -14940,25 +15513,25 @@ async function main() {
14940
15513
  } catch {
14941
15514
  }
14942
15515
  try {
14943
- const { execSync: execSync9 } = await import("child_process");
15516
+ const { execSync: execSync10 } = await import("child_process");
14944
15517
  try {
14945
- execSync9("pkill -f 'jest' 2>/dev/null || true");
15518
+ execSync10("pkill -f 'jest' 2>/dev/null || true");
14946
15519
  } catch {
14947
15520
  }
14948
15521
  try {
14949
- execSync9("pkill -f 'jest-worker' 2>/dev/null || true");
15522
+ execSync10("pkill -f 'jest-worker' 2>/dev/null || true");
14950
15523
  } catch {
14951
15524
  }
14952
15525
  try {
14953
- execSync9("pkill -f 'pnpm test' 2>/dev/null || true");
15526
+ execSync10("pkill -f 'pnpm test' 2>/dev/null || true");
14954
15527
  } catch {
14955
15528
  }
14956
15529
  try {
14957
- execSync9("pkill -f 'npm test' 2>/dev/null || true");
15530
+ execSync10("pkill -f 'npm test' 2>/dev/null || true");
14958
15531
  } catch {
14959
15532
  }
14960
15533
  try {
14961
- execSync9("pkill -f 'yarn test' 2>/dev/null || true");
15534
+ execSync10("pkill -f 'yarn test' 2>/dev/null || true");
14962
15535
  } catch {
14963
15536
  }
14964
15537
  console.error("\u2705 Killed orphaned test processes");
@@ -14987,7 +15560,7 @@ async function main() {
14987
15560
  if (args[0] === "studio") {
14988
15561
  const { fileURLToPath } = await import("url");
14989
15562
  const { dirname, join } = await import("path");
14990
- const { spawn } = await import("child_process");
15563
+ const { spawn: spawn2 } = await import("child_process");
14991
15564
  const { existsSync } = await import("fs");
14992
15565
  const distDir = dirname(fileURLToPath(import.meta.url));
14993
15566
  const studioPath = join(distDir, "..", "packages", "ide", "studio", "dist", "index.js");
@@ -14998,7 +15571,7 @@ async function main() {
14998
15571
  process.exit(1);
14999
15572
  }
15000
15573
  const studioArgs = args.slice(1);
15001
- const child = spawn("node", [studioPath, ...studioArgs], {
15574
+ const child = spawn2("node", [studioPath, ...studioArgs], {
15002
15575
  stdio: "inherit",
15003
15576
  cwd: process.cwd()
15004
15577
  });
@@ -15131,14 +15704,14 @@ ${context}` : "";
15131
15704
  process.stdout.write("\u{1F43B} [Kuma] git post-commit hook already installed.");
15132
15705
  } else {
15133
15706
  fsMod.appendFileSync(hookPath, `
15134
- # Kuma periodic mapping (industry auto-map)
15707
+ # Kuma periodic mapping
15135
15708
  ${line}
15136
15709
  `, "utf-8");
15137
15710
  process.stdout.write("\u{1F43B} [Kuma] appended to existing git post-commit hook.");
15138
15711
  }
15139
15712
  } else {
15140
15713
  fsMod.writeFileSync(hookPath, `#!/bin/sh
15141
- # Kuma periodic mapping (industry auto-map)
15714
+ # Kuma periodic mapping
15142
15715
  ${line}
15143
15716
  `, { mode: 493 });
15144
15717
  process.stdout.write("\u{1F43B} [Kuma] git post-commit hook installed.");
@@ -15148,6 +15721,26 @@ ${line}
15148
15721
  }
15149
15722
  process.exit(0);
15150
15723
  }
15724
+ if (args[0] === "daemon") {
15725
+ const sub = args[1] || "status";
15726
+ try {
15727
+ const { daemonStart: daemonStart2, daemonStop: daemonStop2, daemonStatus: daemonStatus2, daemonRunChild: daemonRunChild2, DEFAULT_INTERVAL_MS: DEFAULT_INTERVAL_MS2 } = await Promise.resolve().then(() => (init_kumaDaemon(), kumaDaemon_exports));
15728
+ if (sub === "start") {
15729
+ const ms = Number(args[2]) > 0 ? Number(args[2]) : DEFAULT_INTERVAL_MS2;
15730
+ process.stdout.write(await daemonStart2(ms));
15731
+ } else if (sub === "stop") {
15732
+ process.stdout.write(await daemonStop2());
15733
+ } else if (sub === "run") {
15734
+ await daemonRunChild2(Number(args[2]));
15735
+ return;
15736
+ } else {
15737
+ process.stdout.write(await daemonStatus2());
15738
+ }
15739
+ } catch (err) {
15740
+ process.stdout.write(`\u{1F43B} Daemon error: ${err}`);
15741
+ }
15742
+ process.exit(0);
15743
+ }
15151
15744
  if (args[0] === "--hook") {
15152
15745
  process.exit(0);
15153
15746
  }
@@ -15158,8 +15751,14 @@ ${line}
15158
15751
  const proj = root.split("/").pop() || "unknown";
15159
15752
  const lines = [`\u{1F43B} [Kuma session brief] ${proj}`];
15160
15753
  try {
15161
- const { execSync: execSync9 } = await import("child_process");
15162
- const branch = execSync9("git rev-parse --abbrev-ref HEAD", {
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
+ }
15759
+ try {
15760
+ const { execSync: execSync10 } = await import("child_process");
15761
+ const branch = execSync10("git rev-parse --abbrev-ref HEAD", {
15163
15762
  cwd: root,
15164
15763
  encoding: "utf-8",
15165
15764
  timeout: 2e3,
@@ -15277,23 +15876,23 @@ ${line}
15277
15876
  });
15278
15877
  const output = formatInitResults(results);
15279
15878
  console.log(output);
15280
- const fs32 = await import("fs");
15281
- const path35 = await import("path");
15282
- const matchaSkills = path35.resolve(process.cwd(), "skills/matcha/SKILL.md");
15283
- const matchaAgents = path35.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(
15284
15883
  process.cwd(),
15285
15884
  ".agents/skills/matcha/SKILL.md"
15286
15885
  );
15287
- const matchaRootSkills = path35.resolve(
15886
+ const matchaRootSkills = path38.resolve(
15288
15887
  process.cwd(),
15289
15888
  "skills/matcha/SKILL.md"
15290
15889
  );
15291
- const matchaAgentsMd = path35.resolve(process.cwd(), "AGENTS.md");
15292
- const matchaWindsurfRules = path35.resolve(
15890
+ const matchaAgentsMd = path38.resolve(process.cwd(), "AGENTS.md");
15891
+ const matchaWindsurfRules = path38.resolve(
15293
15892
  process.cwd(),
15294
15893
  ".windsurf"
15295
15894
  );
15296
- if (fs32.existsSync(matchaSkills) || fs32.existsSync(matchaAgents) || fs32.existsSync(matchaRootSkills) || fs32.existsSync(matchaAgentsMd) || fs32.existsSync(matchaWindsurfRules)) {
15895
+ if (fs35.existsSync(matchaSkills) || fs35.existsSync(matchaAgents) || fs35.existsSync(matchaRootSkills) || fs35.existsSync(matchaAgentsMd) || fs35.existsSync(matchaWindsurfRules)) {
15297
15896
  console.error(
15298
15897
  "\n\u{1F375} Hey, I see matcha is installed \u2014 they pair well together!"
15299
15898
  );
@@ -15307,13 +15906,13 @@ ${line}
15307
15906
  (async () => {
15308
15907
  try {
15309
15908
  const { generateInitMdContent: generateInitMdContent2 } = await Promise.resolve().then(() => (init_init(), init_exports));
15310
- const fs32 = await import("fs");
15311
- const path35 = await import("path");
15312
- const initMdPath = path35.resolve(process.cwd(), ".kuma/init.md");
15313
- if (!fs32.existsSync(initMdPath)) {
15314
- const kumaDir = path35.dirname(initMdPath);
15315
- if (!fs32.existsSync(kumaDir)) fs32.mkdirSync(kumaDir, { recursive: true });
15316
- fs32.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");
15317
15916
  console.error(`[${SERVER_NAME}] Auto-generated .kuma/init.md`);
15318
15917
  }
15319
15918
  } catch (err) {
@@ -15324,8 +15923,8 @@ ${line}
15324
15923
  try {
15325
15924
  const { detectAgent: detectAgent2, getSkillPath: getSkillPath2, getAgentLabel: getAgentLabel2 } = await Promise.resolve().then(() => (init_agentDetector(), agentDetector_exports));
15326
15925
  const { generateSkill: generateSkill2, getSecondaryFiles: getSecondaryFiles2 } = await Promise.resolve().then(() => (init_skillGenerator(), skillGenerator_exports));
15327
- const fs32 = await import("fs");
15328
- const path35 = await import("path");
15926
+ const fs35 = await import("fs");
15927
+ const path38 = await import("path");
15329
15928
  const detection = detectAgent2();
15330
15929
  if (!detection.primary) {
15331
15930
  console.error(`[${SERVER_NAME}] No AI agent detected \u2014 skipping auto-skill creation`);
@@ -15333,22 +15932,22 @@ ${line}
15333
15932
  }
15334
15933
  const agentType = detection.primary;
15335
15934
  const skillPath = getSkillPath2(agentType);
15336
- const fullPath = path35.resolve(process.cwd(), skillPath);
15337
- if (fs32.existsSync(fullPath)) {
15935
+ const fullPath = path38.resolve(process.cwd(), skillPath);
15936
+ if (fs35.existsSync(fullPath)) {
15338
15937
  console.error(`[${SERVER_NAME}] Skill exists for ${getAgentLabel2(agentType)} \u2014 skipping`);
15339
15938
  return;
15340
15939
  }
15341
- const dir = path35.dirname(fullPath);
15342
- if (!fs32.existsSync(dir)) fs32.mkdirSync(dir, { recursive: true });
15343
- fs32.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");
15344
15943
  console.error(`[${SERVER_NAME}] Auto-created ${skillPath} for ${getAgentLabel2(agentType)}`);
15345
15944
  const secondaryFiles = getSecondaryFiles2(agentType);
15346
15945
  for (const sf of secondaryFiles) {
15347
- const sfPath = path35.resolve(process.cwd(), sf.path);
15348
- const sfDir = path35.dirname(sfPath);
15349
- if (!fs32.existsSync(sfPath)) {
15350
- if (!fs32.existsSync(sfDir)) fs32.mkdirSync(sfDir, { recursive: true });
15351
- fs32.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");
15352
15951
  console.error(`[${SERVER_NAME}] Auto-created ${sf.path}`);
15353
15952
  }
15354
15953
  }