@plumpslabs/kuma 2.4.15 → 2.4.17

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 +951 -544
  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: execSync10 } = await import("child_process");
1224
- const psOutput = execSync10(
1223
+ const { execSync: execSync11 } = await import("child_process");
1224
+ const psOutput = execSync11(
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();
@@ -3957,13 +3957,18 @@ var init_kumaSelfHeal = __esm({
3957
3957
  // src/engine/kumaDriftDetector.ts
3958
3958
  var kumaDriftDetector_exports = {};
3959
3959
  __export(kumaDriftDetector_exports, {
3960
+ DRIFT_REPORT_FILE: () => DRIFT_REPORT_FILE,
3961
+ DRIFT_REPORT_MAX_ITEMS: () => DRIFT_REPORT_MAX_ITEMS,
3960
3962
  computeProjectHash: () => computeProjectHash,
3961
3963
  computeScopeHash: () => computeScopeHash,
3962
3964
  detectDrift: () => detectDrift,
3963
3965
  flagStaleRecords: () => flagStaleRecords,
3964
3966
  formatDriftReport: () => formatDriftReport,
3965
3967
  getDriftSummary: () => getDriftSummary,
3966
- hashFile: () => hashFile
3968
+ hashFile: () => hashFile,
3969
+ readDriftReport: () => readDriftReport,
3970
+ toDriftActionItem: () => toDriftActionItem,
3971
+ writeDriftReport: () => writeDriftReport
3967
3972
  });
3968
3973
  import fs7 from "fs";
3969
3974
  import path9 from "path";
@@ -4184,13 +4189,51 @@ async function getDriftSummary() {
4184
4189
  if (staleCount === 0) return "\u2705 All records fresh";
4185
4190
  return `\u26A0\uFE0F ${staleCount} stale record(s) detected. Use kuma_memory({ action: 'heal' }) to repair.`;
4186
4191
  }
4187
- var computeProjectHash;
4192
+ function toDriftActionItem(r) {
4193
+ const stale = r.severity === "stale";
4194
+ const missing = r.severity === "missing";
4195
+ const action = r.source === "research_cache" ? `re-run kuma_context({ action: 'research', scope: '${r.description}' })` : r.filePath ? `rescan '${r.filePath}' (touch via any context call) or run heal` : `run kuma_memory({ action: 'heal' }) to repair`;
4196
+ return {
4197
+ id: `${r.source}#${r.id}`,
4198
+ kind: r.source,
4199
+ target: r.filePath || r.description,
4200
+ reason: missing ? "source gone (file/record missing)" : `content hash mismatch vs current (age ${r.age})`,
4201
+ action: stale || missing ? action : "monitor"
4202
+ };
4203
+ }
4204
+ async function writeDriftReport(maxItems = DRIFT_REPORT_MAX_ITEMS) {
4205
+ const fp = path9.join(getProjectRoot(), DRIFT_REPORT_FILE);
4206
+ const records = await detectDrift();
4207
+ const actionable = records.filter((r) => r.severity === "stale" || r.severity === "missing");
4208
+ const items = actionable.slice(0, maxItems).map(toDriftActionItem);
4209
+ try {
4210
+ fs7.writeFileSync(
4211
+ fp,
4212
+ JSON.stringify({ generatedAt: (/* @__PURE__ */ new Date()).toISOString(), count: actionable.length, items }, null, 2),
4213
+ "utf-8"
4214
+ );
4215
+ } catch {
4216
+ }
4217
+ return { items: items.length, path: fp };
4218
+ }
4219
+ function readDriftReport() {
4220
+ try {
4221
+ const fp = path9.join(getProjectRoot(), DRIFT_REPORT_FILE);
4222
+ if (!fs7.existsSync(fp)) return null;
4223
+ return JSON.parse(fs7.readFileSync(fp, "utf-8"));
4224
+ } catch {
4225
+ return null;
4226
+ }
4227
+ }
4228
+ var computeProjectHash, DRIFT_REPORT_FILE, DRIFT_REPORT_MAX_ITEMS;
4188
4229
  var init_kumaDriftDetector = __esm({
4189
4230
  "src/engine/kumaDriftDetector.ts"() {
4190
4231
  "use strict";
4191
4232
  init_kumaDb();
4192
4233
  init_pathValidator();
4193
4234
  computeProjectHash = (scope) => computeScopeHash(scope) || Date.now().toString(16);
4235
+ DRIFT_REPORT_FILE = ".kuma/drift.json";
4236
+ DRIFT_REPORT_MAX_ITEMS = 20;
4194
4237
  }
4195
4238
  });
4196
4239
 
@@ -4589,15 +4632,293 @@ var init_workspaceIntelligence = __esm({
4589
4632
  }
4590
4633
  });
4591
4634
 
4635
+ // src/engine/mapBackbone.ts
4636
+ var mapBackbone_exports = {};
4637
+ __export(mapBackbone_exports, {
4638
+ BACKBONE_MAX_FILES: () => BACKBONE_MAX_FILES,
4639
+ buildBackbone: () => buildBackbone,
4640
+ ensureBackbone: () => ensureBackbone,
4641
+ ensureMapped: () => ensureMapped,
4642
+ extractImportSources: () => extractImportSources,
4643
+ formatBackbone: () => formatBackbone,
4644
+ getWorktreeChangedFiles: () => getWorktreeChangedFiles,
4645
+ isMapEmpty: () => isMapEmpty,
4646
+ isWorktreeDirty: () => isWorktreeDirty,
4647
+ readMapMeta: () => readMapMeta,
4648
+ readWorktreeDirty: () => readWorktreeDirty,
4649
+ updateWorktreeDirty: () => updateWorktreeDirty
4650
+ });
4651
+ import fs9 from "fs";
4652
+ import path11 from "path";
4653
+ import fastGlob3 from "fast-glob";
4654
+ import { execSync as execSync4 } from "child_process";
4655
+ function extractImportSources(line) {
4656
+ const out = [];
4657
+ const t = line.trim();
4658
+ if (t.startsWith("//") || t.startsWith("#") || t.startsWith("*")) return out;
4659
+ for (const re of IMPORT_RES) {
4660
+ re.lastIndex = 0;
4661
+ let m;
4662
+ while ((m = re.exec(line)) !== null) {
4663
+ if (m[1] && m[1].startsWith(".")) out.push(m[1]);
4664
+ }
4665
+ }
4666
+ return out;
4667
+ }
4668
+ function mapMetaPath(root) {
4669
+ return path11.join(root || getProjectRoot(), MAP_META);
4670
+ }
4671
+ function readMapMeta(root) {
4672
+ try {
4673
+ const fp = mapMetaPath(root);
4674
+ if (fs9.existsSync(fp)) return JSON.parse(fs9.readFileSync(fp, "utf-8"));
4675
+ } catch {
4676
+ }
4677
+ return {};
4678
+ }
4679
+ function writeMapMeta(patch, root) {
4680
+ try {
4681
+ const fp = mapMetaPath(root);
4682
+ const prev = readMapMeta(root);
4683
+ fs9.writeFileSync(fp, JSON.stringify({ ...prev, ...patch }, null, 2), "utf-8");
4684
+ } catch {
4685
+ }
4686
+ }
4687
+ async function isMapEmpty() {
4688
+ try {
4689
+ const { getDb: getDb2 } = await Promise.resolve().then(() => (init_kumaDb(), kumaDb_exports));
4690
+ const db = await getDb2();
4691
+ const stmt = db.prepare(`SELECT COUNT(*) as cnt FROM nodes WHERE type = 'file'`);
4692
+ let n = 0;
4693
+ if (stmt.step()) n = Number(stmt.getAsObject().cnt) || 0;
4694
+ stmt.free();
4695
+ return n === 0;
4696
+ } catch {
4697
+ return true;
4698
+ }
4699
+ }
4700
+ async function buildBackbone(maxFiles = BACKBONE_MAX_FILES) {
4701
+ const started = Date.now();
4702
+ const root = getProjectRoot();
4703
+ const result = { files: 0, capped: false, nodes: 0, edges: 0, ms: 0, filesPerSec: 0 };
4704
+ let files = [];
4705
+ try {
4706
+ files = await fastGlob3([...DEFAULT_SOURCE_INCLUDES], {
4707
+ cwd: root,
4708
+ ignore: ["**/node_modules/**", "**/.git/**", "**/dist/**", "**/build/**", "**/.next/**", "**/coverage/**", "**/*.d.ts", "**/.kuma/**"],
4709
+ onlyFiles: true,
4710
+ deep: 7,
4711
+ dot: false
4712
+ });
4713
+ } catch {
4714
+ return result;
4715
+ }
4716
+ const capped = files.length > maxFiles;
4717
+ const batch = files.slice(0, maxFiles);
4718
+ result.files = batch.length;
4719
+ result.capped = capped;
4720
+ const existingEdges = /* @__PURE__ */ new Set();
4721
+ const existingFiles = /* @__PURE__ */ new Set();
4722
+ try {
4723
+ const { getDb: getDb2 } = await Promise.resolve().then(() => (init_kumaDb(), kumaDb_exports));
4724
+ const db = await getDb2();
4725
+ const stmt = db.prepare(`SELECT source_id, target_id FROM edges WHERE type = 'imports'`);
4726
+ while (stmt.step()) {
4727
+ const r = stmt.getAsObject();
4728
+ existingEdges.add(`${r.source_id}\u2192${r.target_id}`);
4729
+ }
4730
+ stmt.free();
4731
+ const fStmt = db.prepare(`SELECT id FROM nodes WHERE type = 'file'`);
4732
+ while (fStmt.step()) existingFiles.add(fStmt.getAsObject().id);
4733
+ fStmt.free();
4734
+ } catch {
4735
+ }
4736
+ for (const filePath of batch) {
4737
+ try {
4738
+ const full = path11.join(root, filePath);
4739
+ const stat = fs9.statSync(full);
4740
+ if (!stat.isFile() || stat.size > 512 * 1024) continue;
4741
+ const fileId = `file::${filePath}`;
4742
+ if (!existingFiles.has(fileId)) {
4743
+ try {
4744
+ await upsertNode({ id: fileId, type: "file", name: filePath, filePath, metadata: { backbone: true } });
4745
+ existingFiles.add(fileId);
4746
+ result.nodes++;
4747
+ } catch {
4748
+ continue;
4749
+ }
4750
+ }
4751
+ const content = fs9.readFileSync(full, "utf-8");
4752
+ const seen = /* @__PURE__ */ new Set();
4753
+ for (const line of content.split("\n")) {
4754
+ for (const src of extractImportSources(line)) {
4755
+ if (seen.has(src)) continue;
4756
+ seen.add(src);
4757
+ try {
4758
+ const resolved = resolveImportPath(filePath, src, root);
4759
+ const key = resolved ? `${fileId}\u2192file::${resolved}` : "";
4760
+ if (resolved && !existingEdges.has(key)) {
4761
+ await addEdge({ sourceId: fileId, targetId: `file::${resolved}`, type: "imports" });
4762
+ existingEdges.add(key);
4763
+ result.edges++;
4764
+ }
4765
+ } catch {
4766
+ }
4767
+ }
4768
+ }
4769
+ } catch {
4770
+ }
4771
+ }
4772
+ result.ms = Date.now() - started;
4773
+ result.filesPerSec = result.ms > 0 ? Math.round(result.files / result.ms * 1e3) : result.files;
4774
+ writeMapMeta({
4775
+ backboneAt: Date.now(),
4776
+ backboneFiles: result.files,
4777
+ backboneCapped: result.capped,
4778
+ backboneMs: result.ms,
4779
+ filesPerSec: result.filesPerSec
4780
+ });
4781
+ return result;
4782
+ }
4783
+ async function ensureBackbone() {
4784
+ try {
4785
+ if (!await isMapEmpty()) return null;
4786
+ return await buildBackbone();
4787
+ } catch {
4788
+ return null;
4789
+ }
4790
+ }
4791
+ function formatBackbone(r) {
4792
+ 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.`;
4793
+ }
4794
+ function getWorktreeChangedFiles(root, cap = WORKTREE_CAP) {
4795
+ const out = [];
4796
+ try {
4797
+ const cwd = root || getProjectRoot();
4798
+ const porcelain = execSync4("git status --porcelain --untracked-files=all", {
4799
+ cwd,
4800
+ encoding: "utf-8",
4801
+ timeout: 5e3,
4802
+ stdio: ["pipe", "pipe", "pipe"]
4803
+ });
4804
+ if (!porcelain.trim()) return out;
4805
+ for (const rawLine of porcelain.split("\n")) {
4806
+ if (out.length >= cap) break;
4807
+ const line = rawLine.replace(/\s+$/, "");
4808
+ if (!line) continue;
4809
+ const m = line.match(/^(.{2})\s+(.+)$/);
4810
+ if (!m) continue;
4811
+ const code = m[1];
4812
+ let p = m[2].trim();
4813
+ const arrow = p.indexOf(" -> ");
4814
+ if (arrow >= 0) p = p.slice(arrow + 4).trim();
4815
+ p = p.replace(/^"|"$/g, "");
4816
+ if (!p) continue;
4817
+ const ext = p.slice(p.lastIndexOf(".")).toLowerCase();
4818
+ if (!WORKTREE_EXTS.has(ext)) continue;
4819
+ const untracked = code[0] === "?" || code[1] === "?";
4820
+ out.push({ file: p, state: untracked ? "untracked" : "modified" });
4821
+ }
4822
+ } catch {
4823
+ }
4824
+ return out;
4825
+ }
4826
+ function updateWorktreeDirty(files, root) {
4827
+ writeMapMeta({ worktreeDirty: [...new Set(files)].slice(0, WORKTREE_CAP), worktreeDirtyAt: Date.now() }, root);
4828
+ }
4829
+ function readWorktreeDirty(root) {
4830
+ const meta = readMapMeta(root);
4831
+ return Array.isArray(meta.worktreeDirty) ? meta.worktreeDirty.filter((f) => typeof f === "string") : [];
4832
+ }
4833
+ function isWorktreeDirty(target, root) {
4834
+ const norm = target.replace(/\\/g, "/");
4835
+ return readWorktreeDirty(root).some((f) => {
4836
+ const nf = f.replace(/\\/g, "/");
4837
+ return nf === norm || nf.endsWith(`/${norm}`) || norm.endsWith(`/${nf}`);
4838
+ });
4839
+ }
4840
+ async function ensureMapped(files) {
4841
+ const targets = [...new Set(files.map((f) => f.trim()).filter(Boolean))].slice(0, 10);
4842
+ if (targets.length === 0) return { filled: 0 };
4843
+ let missing = [];
4844
+ try {
4845
+ const { getDb: getDb2 } = await Promise.resolve().then(() => (init_kumaDb(), kumaDb_exports));
4846
+ const db = await getDb2();
4847
+ for (const f of targets) {
4848
+ const stmt = db.prepare(
4849
+ `SELECT COUNT(*) as cnt FROM nodes WHERE type IN ('function','class','method','interface') AND file_path LIKE ?`
4850
+ );
4851
+ stmt.bind([`%${path11.basename(f)}%`]);
4852
+ let n = 0;
4853
+ if (stmt.step()) n = Number(stmt.getAsObject().cnt) || 0;
4854
+ stmt.free();
4855
+ if (n === 0) missing.push(f);
4856
+ }
4857
+ } catch {
4858
+ missing = targets;
4859
+ }
4860
+ if (missing.length === 0) return { filled: 0 };
4861
+ try {
4862
+ const { scanCodebase: scanCodebase2 } = await Promise.resolve().then(() => (init_kumaCodeScanner(), kumaCodeScanner_exports));
4863
+ const res = await scanCodebase2({ include: missing, force: true, maxFiles: missing.length });
4864
+ if (res.filesScanned > 0) writeMapMeta({ precisionAt: Date.now() });
4865
+ return { filled: Math.min(missing.length, res.filesScanned) };
4866
+ } catch {
4867
+ return { filled: 0 };
4868
+ }
4869
+ }
4870
+ var BACKBONE_MAX_FILES, MAP_META, IMPORT_RES, WORKTREE_CAP, WORKTREE_EXTS;
4871
+ var init_mapBackbone = __esm({
4872
+ "src/engine/mapBackbone.ts"() {
4873
+ "use strict";
4874
+ init_pathValidator();
4875
+ init_kumaGraph();
4876
+ init_kumaCodeScanner();
4877
+ init_languageSupport();
4878
+ BACKBONE_MAX_FILES = 2e3;
4879
+ MAP_META = ".kuma/map-meta.json";
4880
+ IMPORT_RES = [
4881
+ /(?:import)\s+(?:[\w*{},\s]+\s+from\s+|[\w$]+\s+)?['"]([^'"]+)['"]/g,
4882
+ /(?:from)\s+["']?([a-zA-Z0-9_./-]+)["']?\s+import\s+/g,
4883
+ /require\s*\(\s*['"]([^'"]+)['"]\s*\)/g
4884
+ ];
4885
+ WORKTREE_CAP = 50;
4886
+ WORKTREE_EXTS = /* @__PURE__ */ new Set([
4887
+ ".ts",
4888
+ ".tsx",
4889
+ ".js",
4890
+ ".jsx",
4891
+ ".mjs",
4892
+ ".cjs",
4893
+ ".py",
4894
+ ".go",
4895
+ ".rs",
4896
+ ".java",
4897
+ ".rb",
4898
+ ".php",
4899
+ ".swift",
4900
+ ".kt",
4901
+ ".cs",
4902
+ ".vue",
4903
+ ".svelte",
4904
+ ".json",
4905
+ ".yml",
4906
+ ".yaml",
4907
+ ".toml",
4908
+ ".md"
4909
+ ]);
4910
+ }
4911
+ });
4912
+
4592
4913
  // src/engine/symbolReach.ts
4593
4914
  var symbolReach_exports = {};
4594
4915
  __export(symbolReach_exports, {
4595
4916
  formatReachability: () => formatReachability,
4596
4917
  symbolReachability: () => symbolReachability
4597
4918
  });
4598
- import fs9 from "fs";
4599
- import path11 from "path";
4600
- import { execSync as execSync4 } from "child_process";
4919
+ import fs10 from "fs";
4920
+ import path12 from "path";
4921
+ import { execSync as execSync5 } from "child_process";
4601
4922
  async function graphReach(symbol, limit) {
4602
4923
  const rows = [];
4603
4924
  try {
@@ -4649,7 +4970,7 @@ async function graphReach(symbol, limit) {
4649
4970
  function ripgrepReach(symbol, root, limit) {
4650
4971
  const rows = [];
4651
4972
  try {
4652
- const out = execSync4(
4973
+ const out = execSync5(
4653
4974
  `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`,
4654
4975
  { cwd: root, encoding: "utf-8", timeout: 8e3, maxBuffer: 256 * 1024 }
4655
4976
  ).trim();
@@ -4663,16 +4984,16 @@ function ripgrepReach(symbol, root, limit) {
4663
4984
  }
4664
4985
  for (const c of [...callers].slice(0, BERBEDA)) {
4665
4986
  const [fp] = c.split(":");
4666
- const dir = path11.dirname(fp);
4667
- const stem = path11.basename(fp, path11.extname(fp)).split(/[-_.]/)[0];
4987
+ const dir = path12.dirname(fp);
4988
+ const stem = path12.basename(fp, path12.extname(fp)).split(/[-_.]/)[0];
4668
4989
  try {
4669
- const dirFull = path11.join(root, dir);
4670
- if (!fs9.existsSync(dirFull)) continue;
4671
- for (const f of fs9.readdirSync(dirFull)) {
4990
+ const dirFull = path12.join(root, dir);
4991
+ if (!fs10.existsSync(dirFull)) continue;
4992
+ for (const f of fs10.readdirSync(dirFull)) {
4672
4993
  if (!/(\.test\.|\.spec\.|_test\.)/i.test(f)) continue;
4673
4994
  const low = f.toLowerCase();
4674
4995
  if (low.includes(stem.toLowerCase()) || low.includes(symbol.toLowerCase())) {
4675
- const rel = path11.join(dir, f);
4996
+ const rel = path12.join(dir, f);
4676
4997
  if (!rows.some((r) => r.test === rel)) {
4677
4998
  rows.push({ test: rel, via: fp, evidence: `${rel} sibling-matches caller ${fp} (called at ${c})` });
4678
4999
  }
@@ -4822,17 +5143,17 @@ __export(impactAnalysis_exports, {
4822
5143
  classifyDiffShape: () => classifyDiffShape,
4823
5144
  getIndexerStatus: () => getIndexerStatus
4824
5145
  });
4825
- import fs10 from "fs";
4826
- import path12 from "path";
4827
- import { execSync as execSync5 } from "child_process";
4828
- import fastGlob3 from "fast-glob";
5146
+ import fs11 from "fs";
5147
+ import path13 from "path";
5148
+ import { execSync as execSync6 } from "child_process";
5149
+ import fastGlob4 from "fast-glob";
4829
5150
  function extOf(target) {
4830
- const base = path12.basename(target);
5151
+ const base = path13.basename(target);
4831
5152
  const dot = base.lastIndexOf(".");
4832
5153
  return dot > 0 ? base.slice(dot).toLowerCase() : "";
4833
5154
  }
4834
5155
  function isExampleOrDocName(target) {
4835
- const base = path12.basename(target).toLowerCase();
5156
+ const base = path13.basename(target).toLowerCase();
4836
5157
  return base.endsWith(".example") || base.startsWith(".env") || base.endsWith(".md") || base.endsWith(".txt") || base.endsWith(".rst") || base === "license" || base.startsWith("license.");
4837
5158
  }
4838
5159
  function classifyDiffShape(target, root) {
@@ -4845,7 +5166,7 @@ function classifyDiffShape(target, root) {
4845
5166
  }
4846
5167
  try {
4847
5168
  const cwd = root || getProjectRoot();
4848
- const diff = execSync5(`git diff --unified=0 -- "${target}"`, {
5169
+ const diff = execSync6(`git diff --unified=0 -- "${target}"`, {
4849
5170
  cwd,
4850
5171
  encoding: "utf-8",
4851
5172
  timeout: 4e3,
@@ -4865,7 +5186,7 @@ function classifyDiffShape(target, root) {
4865
5186
  return { shape: "runtime-code", detail: "runtime code change" };
4866
5187
  }
4867
5188
  async function findImportingFiles(targetFile, root) {
4868
- const normTarget = normalizeScope(path12.normalize(targetFile)) || path12.normalize(targetFile);
5189
+ const normTarget = normalizeScope(path13.normalize(targetFile)) || path13.normalize(targetFile);
4869
5190
  try {
4870
5191
  const db = await getDb();
4871
5192
  const targetFileId = `file::${normTarget}`;
@@ -4904,10 +5225,10 @@ async function findImportingFiles(targetFile, root) {
4904
5225
  }
4905
5226
  } catch {
4906
5227
  }
4907
- const baseName = path12.basename(normTarget, path12.extname(normTarget));
4908
- const relTarget = path12.isAbsolute(normTarget) ? path12.relative(root, normTarget) : normTarget;
5228
+ const baseName = path13.basename(normTarget, path13.extname(normTarget));
5229
+ const relTarget = path13.isAbsolute(normTarget) ? path13.relative(root, normTarget) : normTarget;
4909
5230
  try {
4910
- const files = await fastGlob3(
5231
+ const files = await fastGlob4(
4911
5232
  ["**/*.{ts,tsx,js,jsx,mjs,cjs,py,go,rs}"],
4912
5233
  {
4913
5234
  cwd: root,
@@ -4922,10 +5243,10 @@ async function findImportingFiles(targetFile, root) {
4922
5243
  "i"
4923
5244
  );
4924
5245
  for (const f of files) {
4925
- if (path12.normalize(f) === path12.normalize(relTarget)) continue;
4926
- const fullPath = path12.join(root, f);
5246
+ if (path13.normalize(f) === path13.normalize(relTarget)) continue;
5247
+ const fullPath = path13.join(root, f);
4927
5248
  try {
4928
- const content = fs10.readFileSync(fullPath, "utf-8");
5249
+ const content = fs11.readFileSync(fullPath, "utf-8");
4929
5250
  const lines = content.split("\n");
4930
5251
  const hitIdx = lines.findIndex((l) => importRegex.test(l));
4931
5252
  if (hitIdx >= 0) {
@@ -4941,7 +5262,7 @@ async function findImportingFiles(targetFile, root) {
4941
5262
  }
4942
5263
  }
4943
5264
  async function findRelatedTests(targetFile, root, owningPackage, additionalDependents = [], exactOnly = false) {
4944
- const normTarget = normalizeScope(path12.normalize(targetFile)) || path12.normalize(targetFile);
5265
+ const normTarget = normalizeScope(path13.normalize(targetFile)) || path13.normalize(targetFile);
4945
5266
  try {
4946
5267
  const db = await getDb();
4947
5268
  const targetFileId = `file::${normTarget}`;
@@ -4965,13 +5286,13 @@ async function findRelatedTests(targetFile, root, owningPackage, additionalDepen
4965
5286
  }
4966
5287
  } catch {
4967
5288
  }
4968
- const baseName = path12.basename(normTarget, path12.extname(normTarget));
5289
+ const baseName = path13.basename(normTarget, path13.extname(normTarget));
4969
5290
  const testFiles = [];
4970
5291
  const stems = /* @__PURE__ */ new Set();
4971
5292
  if (baseName) stems.add(baseName);
4972
5293
  if (!exactOnly) {
4973
5294
  for (const dep of additionalDependents.slice(0, 3)) {
4974
- const depBase = path12.basename(dep, path12.extname(dep));
5295
+ const depBase = path13.basename(dep, path13.extname(dep));
4975
5296
  if (depBase) stems.add(depBase);
4976
5297
  }
4977
5298
  }
@@ -4987,7 +5308,7 @@ async function findRelatedTests(targetFile, root, owningPackage, additionalDepen
4987
5308
  );
4988
5309
  }
4989
5310
  try {
4990
- const matches = await fastGlob3(testPatterns, {
5311
+ const matches = await fastGlob4(testPatterns, {
4991
5312
  cwd: root,
4992
5313
  ignore: ["**/node_modules/**", "**/dist/**", "**/.git/**", "**/.kuma/**"],
4993
5314
  onlyFiles: true
@@ -5006,13 +5327,13 @@ async function findRelatedTests(targetFile, root, owningPackage, additionalDepen
5006
5327
  `**/__tests__/**/*${stem}*.*`
5007
5328
  );
5008
5329
  }
5009
- const pkgTests = await fastGlob3(pkgPatterns, {
5010
- cwd: path12.join(root, owningPackage.path),
5330
+ const pkgTests = await fastGlob4(pkgPatterns, {
5331
+ cwd: path13.join(root, owningPackage.path),
5011
5332
  ignore: ["**/node_modules/**", "**/dist/**"],
5012
5333
  onlyFiles: true
5013
5334
  });
5014
5335
  for (const pt of pkgTests) {
5015
- const fullRel = path12.join(owningPackage.path, pt);
5336
+ const fullRel = path13.join(owningPackage.path, pt);
5016
5337
  if (!testFiles.includes(fullRel)) {
5017
5338
  testFiles.push(fullRel);
5018
5339
  }
@@ -5063,18 +5384,29 @@ function assessRisk(target, targetType, directDependents, downstreamPackages, af
5063
5384
  }
5064
5385
  async function getIndexerStatus() {
5065
5386
  let graphEdges = false;
5387
+ let backboneOnly = false;
5066
5388
  try {
5067
5389
  const db = await getDb();
5068
5390
  const stmt = db.prepare(`SELECT COUNT(*) as cnt FROM edges WHERE type IN ('imports','depends_on','calls','tests')`);
5069
5391
  if (stmt.step()) graphEdges = Number(stmt.getAsObject().cnt) > 0;
5070
5392
  stmt.free();
5393
+ const fStmt = db.prepare(`SELECT COUNT(*) as cnt FROM nodes WHERE type = 'file'`);
5394
+ let files = 0;
5395
+ if (fStmt.step()) files = Number(fStmt.getAsObject().cnt) || 0;
5396
+ fStmt.free();
5397
+ const sStmt = db.prepare(`SELECT COUNT(*) as cnt FROM nodes WHERE type IN ('function','class','method','interface')`);
5398
+ let syms = 0;
5399
+ if (sStmt.step()) syms = Number(sStmt.getAsObject().cnt) || 0;
5400
+ sStmt.free();
5401
+ backboneOnly = files > 0 && syms === 0;
5071
5402
  } catch {
5072
5403
  }
5073
5404
  return {
5074
5405
  tier: graphEdges ? 1 : 2,
5075
5406
  graphEdges,
5407
+ backboneOnly,
5076
5408
  languages: ["ts", "tsx", "js", "jsx", "mjs", "cjs", "py", "go", "rs"],
5077
- note: graphEdges ? "Tier 1: graph edges grounded the verdict (Tier 2 ripgrep fallback available)" : "Tier 2: ripgrep import-regex fallback (no graph edges; run a scan to reach Tier 1; LSP indexers are future work per #35)"
5409
+ note: backboneOnly ? "Backbone-tier coverage: import graph only (approximate) \u2014 symbols fill in on demand when impact/research touches an area" : graphEdges ? "Tier 1: graph edges grounded the verdict (Tier 2 ripgrep fallback available)" : "Tier 2: ripgrep import-regex fallback (no graph edges; run a scan to reach Tier 1; LSP indexers are future work per #35)"
5078
5410
  };
5079
5411
  }
5080
5412
  async function calculateBlastRadius(target, options = {}) {
@@ -5100,6 +5432,21 @@ async function calculateBlastRadius(target, options = {}) {
5100
5432
  const rev = getReverseDependencies(owningPackage.name, wsInfo);
5101
5433
  downstreamPackages.push(...rev.map((p) => p.name));
5102
5434
  }
5435
+ let worktreeNote = "";
5436
+ try {
5437
+ const { isWorktreeDirty: isWorktreeDirty2 } = await Promise.resolve().then(() => (init_mapBackbone(), mapBackbone_exports));
5438
+ if (targetType === "file" && isWorktreeDirty2(target, root)) {
5439
+ worktreeNote = "\u{1F4DD} Uncommitted worktree changes on this target \u2014 map reflects work in progress, not committed state";
5440
+ }
5441
+ } catch {
5442
+ }
5443
+ if (targetType === "file") {
5444
+ try {
5445
+ const { ensureMapped: ensureMapped2 } = await Promise.resolve().then(() => (init_mapBackbone(), mapBackbone_exports));
5446
+ await ensureMapped2([target]);
5447
+ } catch {
5448
+ }
5449
+ }
5103
5450
  let directDependents = [];
5104
5451
  let evidence = [];
5105
5452
  if (targetType === "file" || targetType === "symbol") {
@@ -5160,6 +5507,7 @@ async function calculateBlastRadius(target, options = {}) {
5160
5507
  `\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501`,
5161
5508
  `\u26A0\uFE0F **Risk Level: ${risk.toUpperCase()}**`,
5162
5509
  `\u{1F4D0} Diff shape: \`${diffShape}\` (${shapeDetail})`,
5510
+ ...worktreeNote ? [worktreeNote] : [],
5163
5511
  owningPackage ? `\u{1F4E6} Owning package: \`${owningPackage.name}\` (${owningPackage.path})` : ""
5164
5512
  ];
5165
5513
  if (riskFlags.length > 0) {
@@ -6339,27 +6687,27 @@ async function codebaseSearchFallback(query, limit = 20) {
6339
6687
  if (results.length >= limit || depth > MAX_WALK_DEPTH) return;
6340
6688
  let entries = [];
6341
6689
  try {
6342
- entries = fs34.readdirSync(dir);
6690
+ entries = fs35.readdirSync(dir);
6343
6691
  } catch {
6344
6692
  return;
6345
6693
  }
6346
6694
  for (const entry of entries) {
6347
6695
  if (entry.startsWith(".") || entry === "node_modules" || entry === "dist" || entry === "build") continue;
6348
- const full = path37.join(dir, entry);
6696
+ const full = path38.join(dir, entry);
6349
6697
  try {
6350
- const stat = fs34.statSync(full);
6698
+ const stat = fs35.statSync(full);
6351
6699
  if (stat.isDirectory()) {
6352
6700
  walk2(full, depth + 1);
6353
6701
  } else if (entry.toLowerCase().includes(query.toLowerCase())) {
6354
- results.push(path37.relative(root, full));
6702
+ results.push(path38.relative(root, full));
6355
6703
  }
6356
6704
  } catch {
6357
6705
  }
6358
6706
  }
6359
6707
  };
6360
6708
  var walk = walk2;
6361
- const fs34 = await import("fs");
6362
- const path37 = await import("path");
6709
+ const fs35 = await import("fs");
6710
+ const path38 = await import("path");
6363
6711
  const root = process.cwd();
6364
6712
  const results = [];
6365
6713
  const MAX_WALK_DEPTH = 8;
@@ -6492,9 +6840,9 @@ ${summary}`;
6492
6840
  }
6493
6841
  async function codebaseImpactFallback(target) {
6494
6842
  try {
6495
- const { execSync: execSync10 } = await import("child_process");
6843
+ const { execSync: execSync11 } = await import("child_process");
6496
6844
  const root = process.cwd();
6497
- const grepResult = execSync10(
6845
+ const grepResult = execSync11(
6498
6846
  `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`,
6499
6847
  { cwd: root, encoding: "utf-8", timeout: 5e3, maxBuffer: 256 * 1024 }
6500
6848
  ).trim();
@@ -6640,9 +6988,9 @@ __export(kumaShared_exports, {
6640
6988
  isReadTool: () => isReadTool,
6641
6989
  isTestTool: () => isTestTool
6642
6990
  });
6643
- import { execSync as execSync6 } from "child_process";
6644
- import fs11 from "fs";
6645
- import path13 from "path";
6991
+ import { execSync as execSync7 } from "child_process";
6992
+ import fs12 from "fs";
6993
+ import path14 from "path";
6646
6994
  function isEditTool(toolName) {
6647
6995
  const n = (toolName || "").toLowerCase();
6648
6996
  return n.includes("edit") || n.includes("write") || n.includes("patch") || n.includes("apply") || n.includes("replace");
@@ -6680,7 +7028,7 @@ function getSessionStats(inputGoal) {
6680
7028
  function getGitDiffStat(timeout = 3e3) {
6681
7029
  try {
6682
7030
  const root = getProjectRoot();
6683
- return execSync6("git diff --stat", {
7031
+ return execSync7("git diff --stat", {
6684
7032
  cwd: root,
6685
7033
  encoding: "utf-8",
6686
7034
  timeout
@@ -6693,13 +7041,16 @@ function getUncommittedFiles(timeout = 3e3) {
6693
7041
  const files = /* @__PURE__ */ new Set();
6694
7042
  try {
6695
7043
  const root = getProjectRoot();
6696
- const porcelain = execSync6("git status --porcelain", {
7044
+ const porcelain = execSync7("git status --porcelain", {
6697
7045
  cwd: root,
6698
7046
  encoding: "utf-8",
6699
7047
  timeout,
6700
7048
  stdio: ["pipe", "pipe", "pipe"]
6701
- }).trim();
6702
- for (const line of porcelain.split("\n")) {
7049
+ });
7050
+ if (!porcelain.trim()) return files;
7051
+ for (const rawLine of porcelain.split("\n")) {
7052
+ const line = rawLine.replace(/\s+$/, "");
7053
+ if (!line) continue;
6703
7054
  const m = line.match(/^.{3}(.+?)(?:\s+->\s+.+)?$/);
6704
7055
  if (m && m[1]) files.add(m[1].trim().replace(/^"|"$/g, ""));
6705
7056
  }
@@ -6712,17 +7063,17 @@ function getBranchCommittedFiles(timeout = 5e3) {
6712
7063
  let base = "";
6713
7064
  try {
6714
7065
  const root = getProjectRoot();
6715
- const branch = execSync6("git rev-parse --abbrev-ref HEAD", {
7066
+ const branch = execSync7("git rev-parse --abbrev-ref HEAD", {
6716
7067
  cwd: root,
6717
7068
  encoding: "utf-8",
6718
7069
  timeout,
6719
7070
  stdio: ["pipe", "pipe", "pipe"]
6720
7071
  }).trim();
6721
- const baseRef = execSync6(
7072
+ const baseRef = execSync7(
6722
7073
  `git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null || echo origin/${branch === "main" || branch === "master" ? "HEAD" : "main"}`,
6723
7074
  { cwd: root, encoding: "utf-8", timeout, stdio: ["pipe", "pipe", "pipe"] }
6724
7075
  ).trim().replace("refs/remotes/", "");
6725
- const mergeBase = execSync6(`git merge-base HEAD ${baseRef} 2>/dev/null || git rev-list --max-parents=0 HEAD`, {
7076
+ const mergeBase = execSync7(`git merge-base HEAD ${baseRef} 2>/dev/null || git rev-list --max-parents=0 HEAD`, {
6726
7077
  cwd: root,
6727
7078
  encoding: "utf-8",
6728
7079
  timeout,
@@ -6730,7 +7081,7 @@ function getBranchCommittedFiles(timeout = 5e3) {
6730
7081
  }).trim().split("\n")[0];
6731
7082
  base = baseRef;
6732
7083
  if (mergeBase) {
6733
- const out = execSync6(`git diff --name-only ${mergeBase} HEAD`, {
7084
+ const out = execSync7(`git diff --name-only ${mergeBase} HEAD`, {
6734
7085
  cwd: root,
6735
7086
  encoding: "utf-8",
6736
7087
  timeout,
@@ -6748,10 +7099,10 @@ function hasVerificationEvidence(toolCalls) {
6748
7099
  }
6749
7100
  function hasVerificationInHookLog(hours = 24) {
6750
7101
  try {
6751
- const fp = path13.join(getProjectRoot(), ".kuma", "injections.jsonl");
6752
- if (!fs11.existsSync(fp)) return false;
7102
+ const fp = path14.join(getProjectRoot(), ".kuma", "injections.jsonl");
7103
+ if (!fs12.existsSync(fp)) return false;
6753
7104
  const cutoff = Date.now() - hours * 60 * 60 * 1e3;
6754
- const lines = fs11.readFileSync(fp, "utf-8").split("\n");
7105
+ const lines = fs12.readFileSync(fp, "utf-8").split("\n");
6755
7106
  for (const line of lines) {
6756
7107
  if (!line.trim()) continue;
6757
7108
  try {
@@ -6854,7 +7205,7 @@ function detectTestWeakening(files, root) {
6854
7205
  for (const f of files) {
6855
7206
  if (!TEST_FILE_PATTERN.test(f)) continue;
6856
7207
  try {
6857
- const diff = execSync6(`git diff --unified=0 -- "${f}"`, {
7208
+ const diff = execSync7(`git diff --unified=0 -- "${f}"`, {
6858
7209
  cwd,
6859
7210
  encoding: "utf-8",
6860
7211
  timeout: 4e3,
@@ -6893,19 +7244,19 @@ __export(kumaMemory_exports, {
6893
7244
  scoreMemoryRelevance: () => scoreMemoryRelevance,
6894
7245
  shouldRecordDecision: () => shouldRecordDecision
6895
7246
  });
6896
- import fs12 from "fs";
6897
- import path14 from "path";
7247
+ import fs13 from "fs";
7248
+ import path15 from "path";
6898
7249
  function scoreMemoryRelevance(context, limit = 5) {
6899
7250
  const results = [];
6900
- const kumaDir = path14.join(getProjectRoot(), MEMORY_DIR);
6901
- if (!fs12.existsSync(kumaDir)) return [];
7251
+ const kumaDir = path15.join(getProjectRoot(), MEMORY_DIR);
7252
+ if (!fs13.existsSync(kumaDir)) return [];
6902
7253
  const terms = Array.from(new Set(context.toLowerCase().split(/[\s/._-]+/).filter((w) => w.length > 2)));
6903
7254
  if (terms.length === 0) return [];
6904
7255
  try {
6905
- const files = fs12.readdirSync(kumaDir).filter((f) => f.endsWith(".md"));
7256
+ const files = fs13.readdirSync(kumaDir).filter((f) => f.endsWith(".md"));
6906
7257
  for (const file of files) {
6907
7258
  try {
6908
- const content = fs12.readFileSync(path14.join(kumaDir, file), "utf-8");
7259
+ const content = fs13.readFileSync(path15.join(kumaDir, file), "utf-8");
6909
7260
  const lower = content.toLowerCase();
6910
7261
  let matchCount = 0;
6911
7262
  for (const term of terms) {
@@ -7087,8 +7438,8 @@ __export(cacheFreshness_exports, {
7087
7438
  isStale: () => isStale,
7088
7439
  markDirty: () => markDirty
7089
7440
  });
7090
- import fs13 from "fs";
7091
- import path15 from "path";
7441
+ import fs14 from "fs";
7442
+ import path16 from "path";
7092
7443
  function isStale(savedAtMs, ttlMs, nowMs = Date.now()) {
7093
7444
  if (!savedAtMs) return true;
7094
7445
  return nowMs - savedAtMs > ttlMs;
@@ -7101,13 +7452,13 @@ function formatAge(savedAtMs, nowMs = Date.now()) {
7101
7452
  return `${Math.floor(s / 86400)}d`;
7102
7453
  }
7103
7454
  function dirtyPath() {
7104
- return path15.join(getProjectRoot(), DIRTY_FILE);
7455
+ return path16.join(getProjectRoot(), DIRTY_FILE);
7105
7456
  }
7106
7457
  function loadDirty() {
7107
7458
  try {
7108
7459
  const fp = dirtyPath();
7109
- if (fs13.existsSync(fp)) {
7110
- const parsed = JSON.parse(fs13.readFileSync(fp, "utf-8"));
7460
+ if (fs14.existsSync(fp)) {
7461
+ const parsed = JSON.parse(fs14.readFileSync(fp, "utf-8"));
7111
7462
  if (parsed && typeof parsed === "object") return parsed;
7112
7463
  }
7113
7464
  } catch {
@@ -7117,14 +7468,14 @@ function loadDirty() {
7117
7468
  function markDirty(filePath) {
7118
7469
  try {
7119
7470
  const fp = dirtyPath();
7120
- const dir = path15.dirname(fp);
7121
- if (!fs13.existsSync(dir)) fs13.mkdirSync(dir, { recursive: true });
7471
+ const dir = path16.dirname(fp);
7472
+ if (!fs14.existsSync(dir)) fs14.mkdirSync(dir, { recursive: true });
7122
7473
  const dirty = loadDirty();
7123
7474
  dirty[filePath] = Date.now();
7124
7475
  const keys = Object.keys(dirty).sort((a, b) => dirty[b] - dirty[a]).slice(0, 200);
7125
7476
  const bounded = {};
7126
7477
  for (const k of keys) bounded[k] = dirty[k];
7127
- fs13.writeFileSync(fp, JSON.stringify(bounded), "utf-8");
7478
+ fs14.writeFileSync(fp, JSON.stringify(bounded), "utf-8");
7128
7479
  } catch {
7129
7480
  }
7130
7481
  }
@@ -7134,7 +7485,7 @@ function getDirtyFiles() {
7134
7485
  function clearDirty() {
7135
7486
  try {
7136
7487
  const fp = dirtyPath();
7137
- if (fs13.existsSync(fp)) fs13.rmSync(fp, { force: true });
7488
+ if (fs14.existsSync(fp)) fs14.rmSync(fp, { force: true });
7138
7489
  } catch {
7139
7490
  }
7140
7491
  }
@@ -7154,8 +7505,8 @@ var codeReuseEngine_exports = {};
7154
7505
  __export(codeReuseEngine_exports, {
7155
7506
  findReusableSymbols: () => findReusableSymbols
7156
7507
  });
7157
- import path16 from "path";
7158
- import fs14 from "fs";
7508
+ import path17 from "path";
7509
+ import fs15 from "fs";
7159
7510
  async function findReusableSymbols(query, scope) {
7160
7511
  const cleanQuery = query.trim().toLowerCase();
7161
7512
  const searchTokens = cleanQuery.replace(/[^a-zA-Z0-9_\s]/g, " ").split(/\s+/).filter((t) => t.length >= 2);
@@ -7278,7 +7629,7 @@ function detectRecommendedUtilDirectory() {
7278
7629
  "utils"
7279
7630
  ];
7280
7631
  for (const c of candidates) {
7281
- if (fs14.existsSync(path16.resolve(root, c))) {
7632
+ if (fs15.existsSync(path17.resolve(root, c))) {
7282
7633
  return c;
7283
7634
  }
7284
7635
  }
@@ -7297,7 +7648,7 @@ var domainClusterEngine_exports = {};
7297
7648
  __export(domainClusterEngine_exports, {
7298
7649
  buildSubsystemClusters: () => buildSubsystemClusters
7299
7650
  });
7300
- import path17 from "path";
7651
+ import path18 from "path";
7301
7652
  async function buildSubsystemClusters() {
7302
7653
  const db = await getDb();
7303
7654
  const fileStmt = db.prepare(`
@@ -7374,7 +7725,7 @@ async function buildSubsystemClusters() {
7374
7725
  for (const [cKey, files] of clusterFileMap.entries()) {
7375
7726
  for (const f of files) {
7376
7727
  fileToCluster.set(f, cKey);
7377
- fileToCluster.set(path17.normalize(f), cKey);
7728
+ fileToCluster.set(path18.normalize(f), cKey);
7378
7729
  }
7379
7730
  }
7380
7731
  const clusterInteractions = /* @__PURE__ */ new Map();
@@ -7382,8 +7733,8 @@ async function buildSubsystemClusters() {
7382
7733
  const srcFile = extractFilePathFromNodeId(e.source);
7383
7734
  const tgtFile = extractFilePathFromNodeId(e.target);
7384
7735
  if (!srcFile || !tgtFile) continue;
7385
- const srcCluster = fileToCluster.get(srcFile) || fileToCluster.get(path17.normalize(srcFile));
7386
- const tgtCluster = fileToCluster.get(tgtFile) || fileToCluster.get(path17.normalize(tgtFile));
7736
+ const srcCluster = fileToCluster.get(srcFile) || fileToCluster.get(path18.normalize(srcFile));
7737
+ const tgtCluster = fileToCluster.get(tgtFile) || fileToCluster.get(path18.normalize(tgtFile));
7387
7738
  if (srcCluster && tgtCluster && srcCluster !== tgtCluster) {
7388
7739
  const pairKey = `${srcCluster}->${tgtCluster}`;
7389
7740
  const stats = clusterInteractions.get(pairKey) || { calls: 0, imports: 0 };
@@ -7405,13 +7756,13 @@ async function buildSubsystemClusters() {
7405
7756
  const clusterId = nodeId("feature_domain", cKey);
7406
7757
  const name = formatClusterName(cKey);
7407
7758
  const role = inferSubsystemRole(cKey, files);
7408
- const entrypoints = files.filter((f) => /index|main|server|app|engine|root/i.test(path17.basename(f))).slice(0, 3);
7759
+ const entrypoints = files.filter((f) => /index|main|server|app|engine|root/i.test(path18.basename(f))).slice(0, 3);
7409
7760
  if (entrypoints.length === 0 && files.length > 0) {
7410
7761
  entrypoints.push(files[0]);
7411
7762
  }
7412
7763
  const allSyms = [];
7413
7764
  for (const f of files) {
7414
- const syms = fileSymbols.get(f) || fileSymbols.get(path17.normalize(f)) || [];
7765
+ const syms = fileSymbols.get(f) || fileSymbols.get(path18.normalize(f)) || [];
7415
7766
  for (const s of syms) {
7416
7767
  if (!allSyms.includes(s)) allSyms.push(s);
7417
7768
  }
@@ -7590,7 +7941,7 @@ function inferSubsystemRole(key, files) {
7590
7941
  if (k.includes("util") || k.includes("common")) {
7591
7942
  return "Shared path validation, configuration loading, and platform detection helpers.";
7592
7943
  }
7593
- return `Core subsystem handling ${files.slice(0, 3).map((f) => path17.basename(f)).join(", ")}.`;
7944
+ return `Core subsystem handling ${files.slice(0, 3).map((f) => path18.basename(f)).join(", ")}.`;
7594
7945
  }
7595
7946
  function inferTypedVerb(sourceKey, targetKey, _stats) {
7596
7947
  const src = sourceKey.toLowerCase();
@@ -7669,18 +8020,18 @@ __export(domainRules_exports, {
7669
8020
  readLayer: () => readLayer,
7670
8021
  writeLayer: () => writeLayer
7671
8022
  });
7672
- import fs15 from "fs";
7673
- import path18 from "path";
8023
+ import fs16 from "fs";
8024
+ import path19 from "path";
7674
8025
  function layerFilePath(layer) {
7675
- return path18.join(getProjectRoot(), ".kuma", LAYER_FILES[layer].filename);
8026
+ return path19.join(getProjectRoot(), ".kuma", LAYER_FILES[layer].filename);
7676
8027
  }
7677
8028
  function ensureLayerFile(layer) {
7678
8029
  const fp = layerFilePath(layer);
7679
- if (!fs15.existsSync(fp)) {
8030
+ if (!fs16.existsSync(fp)) {
7680
8031
  const template = layer === "arch_flow" ? ARCH_FLOW_TEMPLATE : GOTCHAS_TEMPLATE;
7681
- const dir = path18.dirname(fp);
7682
- if (!fs15.existsSync(dir)) fs15.mkdirSync(dir, { recursive: true });
7683
- fs15.writeFileSync(fp, template, "utf-8");
8032
+ const dir = path19.dirname(fp);
8033
+ if (!fs16.existsSync(dir)) fs16.mkdirSync(dir, { recursive: true });
8034
+ fs16.writeFileSync(fp, template, "utf-8");
7684
8035
  console.error(`[DomainRules] Auto-created ${LAYER_FILES[layer].filename}`);
7685
8036
  }
7686
8037
  return fp;
@@ -7688,7 +8039,7 @@ function ensureLayerFile(layer) {
7688
8039
  function readLayer(layer) {
7689
8040
  try {
7690
8041
  const fp = ensureLayerFile(layer);
7691
- return fs15.readFileSync(fp, "utf-8");
8042
+ return fs16.readFileSync(fp, "utf-8");
7692
8043
  } catch (err) {
7693
8044
  return `Error reading ${layer}: ${err}`;
7694
8045
  }
@@ -7696,7 +8047,7 @@ function readLayer(layer) {
7696
8047
  function writeLayer(layer, content) {
7697
8048
  try {
7698
8049
  const fp = ensureLayerFile(layer);
7699
- fs15.writeFileSync(fp, content, "utf-8");
8050
+ fs16.writeFileSync(fp, content, "utf-8");
7700
8051
  const label = LAYER_FILES[layer].label;
7701
8052
  sessionMemory.recordToolCall("kuma_memory", { action: `write_${layer}` });
7702
8053
  return `\u2705 **${label}** updated successfully.`;
@@ -7707,9 +8058,9 @@ function writeLayer(layer, content) {
7707
8058
  function appendToLayer(layer, entry) {
7708
8059
  try {
7709
8060
  const fp = ensureLayerFile(layer);
7710
- const existing = fs15.readFileSync(fp, "utf-8");
8061
+ const existing = fs16.readFileSync(fp, "utf-8");
7711
8062
  const newContent = existing.trimEnd() + "\n\n" + entry.trim() + "\n";
7712
- fs15.writeFileSync(fp, newContent, "utf-8");
8063
+ fs16.writeFileSync(fp, newContent, "utf-8");
7713
8064
  return `\u2705 Entry added to **${LAYER_FILES[layer].label}**.`;
7714
8065
  } catch (err) {
7715
8066
  return `\u274C Failed to append: ${err}`;
@@ -7719,7 +8070,7 @@ function getActiveGotchas() {
7719
8070
  const results = [];
7720
8071
  try {
7721
8072
  const fp = ensureLayerFile("gotcha");
7722
- const content = fs15.readFileSync(fp, "utf-8");
8073
+ const content = fs16.readFileSync(fp, "utf-8");
7723
8074
  const lines = content.split("\n");
7724
8075
  let currentSection = "";
7725
8076
  let currentFilePath = "";
@@ -7755,9 +8106,9 @@ function getActiveGotchas() {
7755
8106
  function checkFileGotchas(filePath) {
7756
8107
  const gotchas = getActiveGotchas();
7757
8108
  const warnings = [];
7758
- const base = path18.basename(filePath);
8109
+ const base = path19.basename(filePath);
7759
8110
  for (const g of gotchas) {
7760
- const gBase = path18.basename(g.filePath);
8111
+ const gBase = path19.basename(g.filePath);
7761
8112
  if (filePath.includes(g.filePath) || g.filePath.includes(filePath) || base && gBase && base === gBase) {
7762
8113
  const icon = g.severity === "critical" ? "\u{1F534}" : g.severity === "high" ? "\u{1F7E0}" : g.severity === "medium" ? "\u{1F7E1}" : "\u{1F7E2}";
7763
8114
  warnings.push(`${icon} **Gotcha**: ${g.description} (${g.severity})`);
@@ -7857,8 +8208,8 @@ __export(kumaInject_exports, {
7857
8208
  parseHookInput: () => parseHookInput,
7858
8209
  trackFileEditLoop: () => trackFileEditLoop
7859
8210
  });
7860
- import fs16 from "fs";
7861
- import path19 from "path";
8211
+ import fs17 from "fs";
8212
+ import path20 from "path";
7862
8213
  function hashFileContent(filePath) {
7863
8214
  return hashFile(filePath);
7864
8215
  }
@@ -7869,10 +8220,10 @@ function isGotchaFresh(storedHash, currentHash) {
7869
8220
  }
7870
8221
  async function getFreshGotchasForFile(filePath, limit = 5, includeStale = false) {
7871
8222
  const root = getProjectRoot();
7872
- const base = path19.basename(filePath);
8223
+ const base = path20.basename(filePath);
7873
8224
  try {
7874
- const dbFile = path19.join(root, ".kuma", "kuma.db");
7875
- if (fs16.existsSync(dbFile)) {
8225
+ const dbFile = path20.join(root, ".kuma", "kuma.db");
8226
+ if (fs17.existsSync(dbFile)) {
7876
8227
  const { getDb: getDb2 } = await Promise.resolve().then(() => (init_kumaDb(), kumaDb_exports));
7877
8228
  const db = await getDb2();
7878
8229
  const stmt = db.prepare(`
@@ -7913,11 +8264,11 @@ async function getFreshGotchasForFile(filePath, limit = 5, includeStale = false)
7913
8264
  } catch {
7914
8265
  }
7915
8266
  try {
7916
- if (!fs16.existsSync(path19.join(root, ".kuma"))) return [];
8267
+ if (!fs17.existsSync(path20.join(root, ".kuma"))) return [];
7917
8268
  const { getActiveGotchas: getActiveGotchas2 } = await Promise.resolve().then(() => (init_domainRules(), domainRules_exports));
7918
8269
  const allGotchas = getActiveGotchas2();
7919
8270
  const matched = allGotchas.filter(
7920
- (g) => g.filePath.includes(filePath) || filePath.includes(g.filePath) || base && path19.basename(g.filePath) === base
8271
+ (g) => g.filePath.includes(filePath) || filePath.includes(g.filePath) || base && path20.basename(g.filePath) === base
7921
8272
  );
7922
8273
  if (matched.length > 0) {
7923
8274
  return matched.slice(0, limit).map((g) => ({
@@ -7936,8 +8287,8 @@ async function getFreshGotchasForFile(filePath, limit = 5, includeStale = false)
7936
8287
  async function getFileTrace(filePath, limit = 8) {
7937
8288
  try {
7938
8289
  const root = getProjectRoot();
7939
- const dbFile = path19.join(root, ".kuma", "kuma.db");
7940
- if (!fs16.existsSync(dbFile)) return [];
8290
+ const dbFile = path20.join(root, ".kuma", "kuma.db");
8291
+ if (!fs17.existsSync(dbFile)) return [];
7941
8292
  const { getDb: getDb2 } = await Promise.resolve().then(() => (init_kumaDb(), kumaDb_exports));
7942
8293
  const db = await getDb2();
7943
8294
  const stmt = db.prepare(`
@@ -7947,7 +8298,7 @@ async function getFileTrace(filePath, limit = 8) {
7947
8298
  ORDER BY cl.created_at DESC
7948
8299
  LIMIT ?
7949
8300
  `);
7950
- stmt.bind([`%${path19.basename(filePath)}%`, limit]);
8301
+ stmt.bind([`%${path20.basename(filePath)}%`, limit]);
7951
8302
  const rows = [];
7952
8303
  while (stmt.step()) rows.push(stmt.getAsObject());
7953
8304
  stmt.free();
@@ -7965,7 +8316,7 @@ async function getFileTrace(filePath, limit = 8) {
7965
8316
  function formatFileTrace(entries, filePath) {
7966
8317
  if (entries.length === 0) return "";
7967
8318
  const lines = [
7968
- `\u{1F570}\uFE0F **Why is ${path19.basename(filePath)} written this way?** \u2014 ${entries.length} change(s) recorded:`
8319
+ `\u{1F570}\uFE0F **Why is ${path20.basename(filePath)} written this way?** \u2014 ${entries.length} change(s) recorded:`
7969
8320
  ];
7970
8321
  for (const e of entries) {
7971
8322
  const date = new Date((e.createdAt || 0) * 1e3).toLocaleDateString("en-US", {
@@ -7981,12 +8332,12 @@ function formatFileTrace(entries, filePath) {
7981
8332
  async function getDecisionsForFile(filePath, limit = 3) {
7982
8333
  const decisions = [];
7983
8334
  const root = getProjectRoot();
7984
- const base = path19.basename(filePath);
8335
+ const base = path20.basename(filePath);
7985
8336
  const baseWithoutExt = base.replace(/\.[^.]+$/, "");
7986
8337
  try {
7987
- const decisionsMdPath = path19.join(root, ".kuma", "memories", "decisions.md");
7988
- if (fs16.existsSync(decisionsMdPath)) {
7989
- const content = fs16.readFileSync(decisionsMdPath, "utf-8");
8338
+ const decisionsMdPath = path20.join(root, ".kuma", "memories", "decisions.md");
8339
+ if (fs17.existsSync(decisionsMdPath)) {
8340
+ const content = fs17.readFileSync(decisionsMdPath, "utf-8");
7990
8341
  const sections = content.split(/^##\s+/m);
7991
8342
  for (const section of sections) {
7992
8343
  if (!section.trim() || section.startsWith("# ")) continue;
@@ -8091,13 +8442,13 @@ async function getRelevantContext(filePath, goal) {
8091
8442
  if (traceStr) parts.push(traceStr);
8092
8443
  try {
8093
8444
  const root = getProjectRoot();
8094
- if (fs16.existsSync(path19.join(root, ".kuma", "kuma.db"))) {
8445
+ if (fs17.existsSync(path20.join(root, ".kuma", "kuma.db"))) {
8095
8446
  const { getDb: getDb2 } = await Promise.resolve().then(() => (init_kumaDb(), kumaDb_exports));
8096
8447
  const db = await getDb2();
8097
8448
  const stmt = db.prepare(
8098
8449
  `SELECT COUNT(*) FROM known_gotchas WHERE status = 'resolved' AND file_path LIKE ?`
8099
8450
  );
8100
- stmt.bind([`%${path19.basename(filePath)}%`]);
8451
+ stmt.bind([`%${path20.basename(filePath)}%`]);
8101
8452
  const found = stmt.step();
8102
8453
  const count = found ? Number(stmt.getAsObject()["COUNT(*)"]) : 0;
8103
8454
  stmt.free();
@@ -8108,7 +8459,7 @@ async function getRelevantContext(filePath, goal) {
8108
8459
  } catch {
8109
8460
  }
8110
8461
  if (gotchas.length > 0) {
8111
- const scopeHint = path19.basename(path19.dirname(filePath)) || "current change";
8462
+ const scopeHint = path20.basename(path20.dirname(filePath)) || "current change";
8112
8463
  parts.push(
8113
8464
  `\u2705 AFTER editing, verify: kuma_safety({ action: "verify", scope: "${scopeHint}" })`
8114
8465
  );
@@ -8124,11 +8475,11 @@ async function getRelevantContext(filePath, goal) {
8124
8475
  async function getFileSummary2(filePath) {
8125
8476
  try {
8126
8477
  const root = getProjectRoot();
8127
- const dbFile = path19.join(root, ".kuma", "kuma.db");
8128
- if (!fs16.existsSync(dbFile)) return null;
8478
+ const dbFile = path20.join(root, ".kuma", "kuma.db");
8479
+ if (!fs17.existsSync(dbFile)) return null;
8129
8480
  const { getDb: getDb2 } = await Promise.resolve().then(() => (init_kumaDb(), kumaDb_exports));
8130
8481
  const db = await getDb2();
8131
- const base = path19.basename(filePath);
8482
+ const base = path20.basename(filePath);
8132
8483
  const stmt = db.prepare(`
8133
8484
  SELECT
8134
8485
  (SELECT COUNT(*) FROM known_gotchas WHERE status = 'active' AND (file_path = ? OR file_path LIKE ?)) as active_gotchas,
@@ -8220,9 +8571,9 @@ async function getCommandContext(command) {
8220
8571
  }
8221
8572
  function loadHookState(root) {
8222
8573
  try {
8223
- const fp = path19.join(root, HOOK_STATE_FILE);
8224
- if (fs16.existsSync(fp)) {
8225
- return JSON.parse(fs16.readFileSync(fp, "utf-8"));
8574
+ const fp = path20.join(root, HOOK_STATE_FILE);
8575
+ if (fs17.existsSync(fp)) {
8576
+ return JSON.parse(fs17.readFileSync(fp, "utf-8"));
8226
8577
  }
8227
8578
  } catch {
8228
8579
  }
@@ -8230,10 +8581,10 @@ function loadHookState(root) {
8230
8581
  }
8231
8582
  function saveHookState(root, state) {
8232
8583
  try {
8233
- const fp = path19.join(root, HOOK_STATE_FILE);
8234
- const dir = path19.dirname(fp);
8235
- if (!fs16.existsSync(dir)) fs16.mkdirSync(dir, { recursive: true });
8236
- fs16.writeFileSync(fp, JSON.stringify(state), "utf-8");
8584
+ const fp = path20.join(root, HOOK_STATE_FILE);
8585
+ const dir = path20.dirname(fp);
8586
+ if (!fs17.existsSync(dir)) fs17.mkdirSync(dir, { recursive: true });
8587
+ fs17.writeFileSync(fp, JSON.stringify(state), "utf-8");
8237
8588
  } catch {
8238
8589
  }
8239
8590
  }
@@ -8267,7 +8618,7 @@ async function trackFileEditLoop(filePath) {
8267
8618
  saveHookState(root, state);
8268
8619
  if (recorded) {
8269
8620
  try {
8270
- if (!fs16.existsSync(path19.join(root, ".kuma", "kuma.db"))) return entry.count;
8621
+ if (!fs17.existsSync(path20.join(root, ".kuma", "kuma.db"))) return entry.count;
8271
8622
  const { addGotcha: addGotcha2 } = await Promise.resolve().then(() => (init_kumaGotchas(), kumaGotchas_exports));
8272
8623
  await addGotcha2({
8273
8624
  filePath,
@@ -8321,8 +8672,8 @@ __export(kumaGotchas_exports, {
8321
8672
  syncGotchasToDb: () => syncGotchasToDb,
8322
8673
  tokenizeForSimilarity: () => tokenizeForSimilarity
8323
8674
  });
8324
- import fs17 from "fs";
8325
- import path20 from "path";
8675
+ import fs18 from "fs";
8676
+ import path21 from "path";
8326
8677
  async function ensureGotchasSchema() {
8327
8678
  const db = await getDb();
8328
8679
  db.exec(`
@@ -8744,8 +9095,8 @@ async function getActiveGotchasForCommand(command) {
8744
9095
  }
8745
9096
  async function recordInjection(params) {
8746
9097
  try {
8747
- const fp = path20.join(getProjectRoot(), ".kuma", "injections.jsonl");
8748
- if (!fs17.existsSync(path20.dirname(fp))) fs17.mkdirSync(path20.dirname(fp), { recursive: true });
9098
+ const fp = path21.join(getProjectRoot(), ".kuma", "injections.jsonl");
9099
+ if (!fs18.existsSync(path21.dirname(fp))) fs18.mkdirSync(path21.dirname(fp), { recursive: true });
8749
9100
  const line = JSON.stringify({
8750
9101
  filePath: params.filePath || null,
8751
9102
  command: params.command || null,
@@ -8754,16 +9105,16 @@ async function recordInjection(params) {
8754
9105
  // conservative estimate: avoided re-research / re-discovery
8755
9106
  at: Date.now()
8756
9107
  });
8757
- fs17.appendFileSync(fp, line + "\n", "utf-8");
9108
+ fs18.appendFileSync(fp, line + "\n", "utf-8");
8758
9109
  } catch {
8759
9110
  }
8760
9111
  }
8761
9112
  function getInjectionStats(hours = 24) {
8762
9113
  try {
8763
- const fp = path20.join(getProjectRoot(), ".kuma", "injections.jsonl");
8764
- if (!fs17.existsSync(fp)) return { count: 0, savedMs: 0 };
9114
+ const fp = path21.join(getProjectRoot(), ".kuma", "injections.jsonl");
9115
+ if (!fs18.existsSync(fp)) return { count: 0, savedMs: 0 };
8765
9116
  const cutoff = Date.now() - hours * 60 * 60 * 1e3;
8766
- const lines = fs17.readFileSync(fp, "utf-8").split("\n");
9117
+ const lines = fs18.readFileSync(fp, "utf-8").split("\n");
8767
9118
  let count = 0;
8768
9119
  let savedMs = 0;
8769
9120
  for (const line of lines) {
@@ -8821,9 +9172,9 @@ async function getGotchasByStatus(status, limit = 20) {
8821
9172
  }
8822
9173
  function syncGotchaStatusToMarkdown(targetPaths, newStatus, reason) {
8823
9174
  try {
8824
- const mdPath = path20.join(getProjectRoot(), ".kuma", "KNOWN_GOTCHAS.md");
8825
- if (!fs17.existsSync(mdPath)) return false;
8826
- const content = fs17.readFileSync(mdPath, "utf-8");
9175
+ const mdPath = path21.join(getProjectRoot(), ".kuma", "KNOWN_GOTCHAS.md");
9176
+ if (!fs18.existsSync(mdPath)) return false;
9177
+ const content = fs18.readFileSync(mdPath, "utf-8");
8827
9178
  const lines = content.split("\n");
8828
9179
  const normalizedTargets = targetPaths.map((p) => p.trim().toLowerCase()).filter(Boolean);
8829
9180
  if (normalizedTargets.length === 0) return false;
@@ -8840,9 +9191,9 @@ function syncGotchaStatusToMarkdown(targetPaths, newStatus, reason) {
8840
9191
  modified = true;
8841
9192
  }
8842
9193
  const headingFile = headingMatch[1].trim().toLowerCase();
8843
- const headingBase = path20.basename(headingFile);
9194
+ const headingBase = path21.basename(headingFile);
8844
9195
  inMatchingSection = normalizedTargets.some(
8845
- (t) => headingFile.includes(t) || t.includes(headingFile) || headingBase === t || headingBase === path20.basename(t)
9196
+ (t) => headingFile.includes(t) || t.includes(headingFile) || headingBase === t || headingBase === path21.basename(t)
8846
9197
  );
8847
9198
  sectionHasStatus = false;
8848
9199
  outputLines.push(line);
@@ -8864,7 +9215,7 @@ function syncGotchaStatusToMarkdown(targetPaths, newStatus, reason) {
8864
9215
  modified = true;
8865
9216
  }
8866
9217
  if (modified) {
8867
- fs17.writeFileSync(mdPath, outputLines.join("\n"), "utf-8");
9218
+ fs18.writeFileSync(mdPath, outputLines.join("\n"), "utf-8");
8868
9219
  }
8869
9220
  return modified;
8870
9221
  } catch {
@@ -9005,24 +9356,24 @@ var kumaMaintenance_exports = {};
9005
9356
  __export(kumaMaintenance_exports, {
9006
9357
  maybeRunAutoCleanup: () => maybeRunAutoCleanup
9007
9358
  });
9008
- import fs18 from "fs";
9009
- import path21 from "path";
9359
+ import fs19 from "fs";
9360
+ import path22 from "path";
9010
9361
  async function maybeRunAutoCleanup() {
9011
9362
  try {
9012
9363
  const root = getProjectRoot();
9013
- const stateFile = path21.join(root, GC_STATE_FILE);
9364
+ const stateFile = path22.join(root, GC_STATE_FILE);
9014
9365
  const now = Date.now();
9015
9366
  let lastRun = 0;
9016
- if (fs18.existsSync(stateFile)) {
9367
+ if (fs19.existsSync(stateFile)) {
9017
9368
  try {
9018
- lastRun = JSON.parse(fs18.readFileSync(stateFile, "utf-8")).lastRun || 0;
9369
+ lastRun = JSON.parse(fs19.readFileSync(stateFile, "utf-8")).lastRun || 0;
9019
9370
  } catch {
9020
9371
  lastRun = 0;
9021
9372
  }
9022
9373
  }
9023
9374
  if (now - lastRun < GC_INTERVAL_MS) return "";
9024
- fs18.mkdirSync(path21.dirname(stateFile), { recursive: true });
9025
- fs18.writeFileSync(stateFile, JSON.stringify({ lastRun: now }), "utf-8");
9375
+ fs19.mkdirSync(path22.dirname(stateFile), { recursive: true });
9376
+ fs19.writeFileSync(stateFile, JSON.stringify({ lastRun: now }), "utf-8");
9026
9377
  const { syncGotchasToDb: syncGotchasToDb2 } = await Promise.resolve().then(() => (init_kumaGotchas(), kumaGotchas_exports));
9027
9378
  await syncGotchasToDb2();
9028
9379
  const { runGarbageCollection: runGarbageCollection2 } = await Promise.resolve().then(() => (init_kumaDb(), kumaDb_exports));
@@ -9058,22 +9409,22 @@ __export(kumaPathRules_exports, {
9058
9409
  loadPathRules: () => loadPathRules,
9059
9410
  matchRulePath: () => matchRulePath
9060
9411
  });
9061
- import fs19 from "fs";
9062
- import path22 from "path";
9412
+ import fs20 from "fs";
9413
+ import path23 from "path";
9063
9414
  function rulesDir() {
9064
- return path22.join(getProjectRoot(), RULES_DIR);
9415
+ return path23.join(getProjectRoot(), RULES_DIR);
9065
9416
  }
9066
9417
  function ensureRulesDir() {
9067
9418
  try {
9068
9419
  const dir = rulesDir();
9069
- if (!fs19.existsSync(dir)) fs19.mkdirSync(dir, { recursive: true });
9420
+ if (!fs20.existsSync(dir)) fs20.mkdirSync(dir, { recursive: true });
9070
9421
  } catch {
9071
9422
  }
9072
9423
  }
9073
9424
  function parseRuleFile(filePath) {
9074
9425
  try {
9075
- const raw = fs19.readFileSync(filePath, "utf-8");
9076
- const id = path22.basename(filePath, ".md");
9426
+ const raw = fs20.readFileSync(filePath, "utf-8");
9427
+ const id = path23.basename(filePath, ".md");
9077
9428
  const fm = raw.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/);
9078
9429
  if (!fm) {
9079
9430
  return { id, description: id, paths: ["*"], content: raw.trim(), filePath };
@@ -9098,7 +9449,7 @@ function loadPathRules() {
9098
9449
  ensureRulesDir();
9099
9450
  try {
9100
9451
  const dir = rulesDir();
9101
- return fs19.readdirSync(dir).filter((f) => f.endsWith(".md")).map((f) => parseRuleFile(path22.join(dir, f))).filter((r) => r !== null);
9452
+ return fs20.readdirSync(dir).filter((f) => f.endsWith(".md")).map((f) => parseRuleFile(path23.join(dir, f))).filter((r) => r !== null);
9102
9453
  } catch {
9103
9454
  return [];
9104
9455
  }
@@ -9186,8 +9537,8 @@ __export(kumaFlowCache_exports, {
9186
9537
  getFreshDomainFlow: () => getFreshDomainFlow,
9187
9538
  getHopsForDomain: () => getHopsForDomain
9188
9539
  });
9189
- import fs20 from "fs";
9190
- import path23 from "path";
9540
+ import fs21 from "fs";
9541
+ import path24 from "path";
9191
9542
  async function getFlowFreshness(domain) {
9192
9543
  try {
9193
9544
  const { getDb: getDb2 } = await Promise.resolve().then(() => (init_kumaDb(), kumaDb_exports));
@@ -9222,26 +9573,26 @@ async function getFlowFreshness(domain) {
9222
9573
  }
9223
9574
  function resolveImport(fromFile, spec) {
9224
9575
  const root = getProjectRoot();
9225
- const fromDir = path23.dirname(fromFile);
9576
+ const fromDir = path24.dirname(fromFile);
9226
9577
  const candidates = [];
9227
9578
  if (spec.startsWith(".")) {
9228
- const abs = path23.resolve(fromDir, spec);
9579
+ const abs = path24.resolve(fromDir, spec);
9229
9580
  candidates.push(abs);
9230
9581
  } else {
9231
- candidates.push(path23.join(root, spec));
9582
+ candidates.push(path24.join(root, spec));
9232
9583
  }
9233
9584
  for (const c of candidates) {
9234
9585
  for (const ext of SOURCE_EXTENSIONS) {
9235
9586
  const withExt = `${c}${ext}`;
9236
- if (fs20.existsSync(withExt)) return path23.relative(root, withExt);
9237
- if (fs20.existsSync(c) && fs20.statSync(c).isDirectory()) {
9238
- const idx = path23.join(c, "index") + ext;
9239
- if (fs20.existsSync(idx)) return path23.relative(root, idx);
9587
+ if (fs21.existsSync(withExt)) return path24.relative(root, withExt);
9588
+ if (fs21.existsSync(c) && fs21.statSync(c).isDirectory()) {
9589
+ const idx = path24.join(c, "index") + ext;
9590
+ if (fs21.existsSync(idx)) return path24.relative(root, idx);
9240
9591
  }
9241
9592
  }
9242
- if (fs20.existsSync(c)) {
9593
+ if (fs21.existsSync(c)) {
9243
9594
  try {
9244
- if (fs20.statSync(c).isFile()) return path23.relative(root, c);
9595
+ if (fs21.statSync(c).isFile()) return path24.relative(root, c);
9245
9596
  } catch {
9246
9597
  }
9247
9598
  }
@@ -9250,13 +9601,13 @@ function resolveImport(fromFile, spec) {
9250
9601
  }
9251
9602
  function deriveHopsFromImports(entryFile, maxHops = 6) {
9252
9603
  const root = getProjectRoot();
9253
- const absEntry = path23.isAbsolute(entryFile) ? entryFile : path23.resolve(root, entryFile);
9254
- if (!fs20.existsSync(absEntry)) return [];
9604
+ const absEntry = path24.isAbsolute(entryFile) ? entryFile : path24.resolve(root, entryFile);
9605
+ if (!fs21.existsSync(absEntry)) return [];
9255
9606
  const hops = [];
9256
9607
  const seen = /* @__PURE__ */ new Set([entryFile]);
9257
- const fromName = path23.basename(absEntry);
9608
+ const fromName = path24.basename(absEntry);
9258
9609
  try {
9259
- const lines = fs20.readFileSync(absEntry, "utf-8").split("\n");
9610
+ const lines = fs21.readFileSync(absEntry, "utf-8").split("\n");
9260
9611
  for (const line of lines) {
9261
9612
  if (hops.length >= maxHops) break;
9262
9613
  const spec = matchImportPath(line);
@@ -9266,9 +9617,9 @@ function deriveHopsFromImports(entryFile, maxHops = 6) {
9266
9617
  seen.add(resolved);
9267
9618
  hops.push({
9268
9619
  from: fromName,
9269
- to: path23.basename(resolved),
9620
+ to: path24.basename(resolved),
9270
9621
  relation: "imports",
9271
- description: `${fromName} imports ${path23.basename(resolved)}`
9622
+ description: `${fromName} imports ${path24.basename(resolved)}`
9272
9623
  });
9273
9624
  }
9274
9625
  } catch {
@@ -9331,9 +9682,9 @@ async function getHopsForDomain(domain) {
9331
9682
  }
9332
9683
  try {
9333
9684
  const root = getProjectRoot();
9334
- const archPath = path23.join(root, ".kuma", "ARCHITECTURE_FLOW.md");
9335
- if (fs20.existsSync(archPath)) {
9336
- const content = fs20.readFileSync(archPath, "utf-8");
9685
+ const archPath = path24.join(root, ".kuma", "ARCHITECTURE_FLOW.md");
9686
+ if (fs21.existsSync(archPath)) {
9687
+ const content = fs21.readFileSync(archPath, "utf-8");
9337
9688
  const lines = content.split("\n");
9338
9689
  for (const line of lines) {
9339
9690
  const domMatch = line.match(new RegExp(`domain:\\s*${escapeRegex(domain)}\\s*\\|\\s*hops:\\s*(.+)`, "i"));
@@ -9378,7 +9729,7 @@ Record one with kuma_memory({ action: 'arch_flow', content: 'domain: ${domain} |
9378
9729
  hops: derivedHops,
9379
9730
  filePaths: freshness.filePaths
9380
9731
  });
9381
- lines.push(`\u2705 Re-derived ${derivedHops.length} hop(s) from ${path23.basename(entry)} \u2014 cache refreshed.`);
9732
+ lines.push(`\u2705 Re-derived ${derivedHops.length} hop(s) from ${path24.basename(entry)} \u2014 cache refreshed.`);
9382
9733
  hops.splice(0, hops.length, ...derivedHops);
9383
9734
  } else {
9384
9735
  lines.push("\u26A0\uFE0F No imports to follow \u2014 cache left as-is (record hops manually if needed).");
@@ -9431,10 +9782,10 @@ __export(packageBriefs_exports, {
9431
9782
  readBrief: () => readBrief,
9432
9783
  refreshPackageBriefs: () => refreshPackageBriefs
9433
9784
  });
9434
- import fs21 from "fs";
9435
- import path24 from "path";
9785
+ import fs22 from "fs";
9786
+ import path25 from "path";
9436
9787
  function briefsDir(root) {
9437
- return path24.join(root || getProjectRoot(), BRIEFS_DIR);
9788
+ return path25.join(root || getProjectRoot(), BRIEFS_DIR);
9438
9789
  }
9439
9790
  function slug(name) {
9440
9791
  return name.replace(/[^a-zA-Z0-9_-]/g, "_").slice(0, 60) || "root";
@@ -9498,13 +9849,13 @@ async function refreshPackageBriefs() {
9498
9849
  const dir = briefsDir(root);
9499
9850
  try {
9500
9851
  const ws = await getWorkspaceInfo(root);
9501
- if (!fs21.existsSync(dir)) fs21.mkdirSync(dir, { recursive: true });
9852
+ if (!fs22.existsSync(dir)) fs22.mkdirSync(dir, { recursive: true });
9502
9853
  let count = 0;
9503
9854
  const pkgs = ws.isWorkspace ? ws.packages : [{ name: "root", path: ".", isRoot: true }];
9504
9855
  for (const p of pkgs.slice(0, 20)) {
9505
9856
  const pkg = p;
9506
9857
  const content = await buildPackageBrief(pkg.name, pkg.path, root);
9507
- fs21.writeFileSync(path24.join(dir, `${slug(pkg.name)}.md`), content, "utf-8");
9858
+ fs22.writeFileSync(path25.join(dir, `${slug(pkg.name)}.md`), content, "utf-8");
9508
9859
  count++;
9509
9860
  }
9510
9861
  return { count, dir };
@@ -9514,9 +9865,9 @@ async function refreshPackageBriefs() {
9514
9865
  }
9515
9866
  function briefFreshness(pkgName) {
9516
9867
  try {
9517
- const fp = path24.join(briefsDir(), `${slug(pkgName)}.md`);
9518
- if (!fs21.existsSync(fp)) return { exists: false, fresh: false, age: "missing" };
9519
- const ageMs = Date.now() - fs21.statSync(fp).mtimeMs;
9868
+ const fp = path25.join(briefsDir(), `${slug(pkgName)}.md`);
9869
+ if (!fs22.existsSync(fp)) return { exists: false, fresh: false, age: "missing" };
9870
+ const ageMs = Date.now() - fs22.statSync(fp).mtimeMs;
9520
9871
  return { exists: true, fresh: !isStale(Date.now() - ageMs, MAP_TTL_MS), age: formatAge(Date.now() - ageMs) };
9521
9872
  } catch {
9522
9873
  return { exists: false, fresh: false, age: "missing" };
@@ -9524,9 +9875,9 @@ function briefFreshness(pkgName) {
9524
9875
  }
9525
9876
  function readBrief(pkgName, maxChars = 1200) {
9526
9877
  try {
9527
- const fp = path24.join(briefsDir(), `${slug(pkgName)}.md`);
9528
- if (!fs21.existsSync(fp)) return null;
9529
- const content = fs21.readFileSync(fp, "utf-8");
9878
+ const fp = path25.join(briefsDir(), `${slug(pkgName)}.md`);
9879
+ if (!fs22.existsSync(fp)) return null;
9880
+ const content = fs22.readFileSync(fp, "utf-8");
9530
9881
  return content.length > maxChars ? content.slice(0, maxChars) + "\n\u2026(truncated)" : content;
9531
9882
  } catch {
9532
9883
  return null;
@@ -9555,8 +9906,8 @@ __export(kumaSearch_exports, {
9555
9906
  formatHybridResults: () => formatHybridResults,
9556
9907
  hybridSearch: () => hybridSearch
9557
9908
  });
9558
- import fs23 from "fs";
9559
- import path26 from "path";
9909
+ import fs24 from "fs";
9910
+ import path27 from "path";
9560
9911
  function expandQueryTerms(query) {
9561
9912
  const terms = query.toLowerCase().split(/[\s_-]+/).filter((t) => t.length > 2);
9562
9913
  const expanded = /* @__PURE__ */ new Map();
@@ -9619,13 +9970,13 @@ async function buildSearchVectors() {
9619
9970
  }
9620
9971
  try {
9621
9972
  const root = getProjectRoot();
9622
- const memDir = path26.join(root, ".kuma", "memories");
9623
- if (fs23.existsSync(memDir)) {
9624
- const files = fs23.readdirSync(memDir).filter((f) => f.endsWith(".md")).slice(0, SCALE_LIMITS.maxMemoryFiles);
9973
+ const memDir = path27.join(root, ".kuma", "memories");
9974
+ if (fs24.existsSync(memDir)) {
9975
+ const files = fs24.readdirSync(memDir).filter((f) => f.endsWith(".md")).slice(0, SCALE_LIMITS.maxMemoryFiles);
9625
9976
  for (const file of files) {
9626
9977
  try {
9627
- const fullPath = path26.join(memDir, file);
9628
- const content = fs23.readFileSync(fullPath, "utf-8");
9978
+ const fullPath = path27.join(memDir, file);
9979
+ const content = fs24.readFileSync(fullPath, "utf-8");
9629
9980
  const text = content.toLowerCase();
9630
9981
  const rawTerms = extractTerms(text);
9631
9982
  const termCounts = /* @__PURE__ */ new Map();
@@ -9636,7 +9987,7 @@ async function buildSearchVectors() {
9636
9987
  terms: termCounts,
9637
9988
  source: file.replace(/\.md$/, ""),
9638
9989
  sourceType: "memory",
9639
- recency: recencyScore(Math.floor(fs23.statSync(fullPath).mtimeMs / 1e3))
9990
+ recency: recencyScore(Math.floor(fs24.statSync(fullPath).mtimeMs / 1e3))
9640
9991
  });
9641
9992
  } catch {
9642
9993
  }
@@ -9953,14 +10304,14 @@ __export(architectureGuard_exports, {
9953
10304
  detectWorkspaceCircularDeps: () => detectWorkspaceCircularDeps,
9954
10305
  loadArchitectureRules: () => loadArchitectureRules
9955
10306
  });
9956
- import fs27 from "fs";
9957
- import path30 from "path";
9958
- import fastGlob4 from "fast-glob";
10307
+ import fs28 from "fs";
10308
+ import path31 from "path";
10309
+ import fastGlob5 from "fast-glob";
9959
10310
  function loadArchitectureRules(root) {
9960
- const rulesPath = path30.join(root, ".kuma", "architecture.json");
9961
- if (fs27.existsSync(rulesPath)) {
10311
+ const rulesPath = path31.join(root, ".kuma", "architecture.json");
10312
+ if (fs28.existsSync(rulesPath)) {
9962
10313
  try {
9963
- const data = JSON.parse(fs27.readFileSync(rulesPath, "utf-8"));
10314
+ const data = JSON.parse(fs28.readFileSync(rulesPath, "utf-8"));
9964
10315
  if (Array.isArray(data.rules)) {
9965
10316
  return data.rules;
9966
10317
  }
@@ -10013,7 +10364,7 @@ async function checkArchitectureBoundaries(filesToCheck, customRoot) {
10013
10364
  }
10014
10365
  let targetFiles = filesToCheck;
10015
10366
  if (!targetFiles || targetFiles.length === 0) {
10016
- targetFiles = await fastGlob4(["**/*.{ts,tsx,js,jsx,mjs,cjs}"], {
10367
+ targetFiles = await fastGlob5(["**/*.{ts,tsx,js,jsx,mjs,cjs}"], {
10017
10368
  cwd: root,
10018
10369
  ignore: ["**/node_modules/**", "**/dist/**", "**/build/**", "**/.git/**", "**/.kuma/**"],
10019
10370
  onlyFiles: true
@@ -10022,11 +10373,11 @@ async function checkArchitectureBoundaries(filesToCheck, customRoot) {
10022
10373
  const customRules = loadArchitectureRules(root);
10023
10374
  const importRegex = /(?:import|export\s+.*from|require\s*\()\s*['"]([^'"]+)['"]/g;
10024
10375
  for (const file of targetFiles) {
10025
- const fullPath = path30.isAbsolute(file) ? file : path30.join(root, file);
10026
- if (!fs27.existsSync(fullPath)) continue;
10376
+ const fullPath = path31.isAbsolute(file) ? file : path31.join(root, file);
10377
+ if (!fs28.existsSync(fullPath)) continue;
10027
10378
  let content = "";
10028
10379
  try {
10029
- content = fs27.readFileSync(fullPath, "utf-8");
10380
+ content = fs28.readFileSync(fullPath, "utf-8");
10030
10381
  } catch {
10031
10382
  continue;
10032
10383
  }
@@ -10036,7 +10387,7 @@ async function checkArchitectureBoundaries(filesToCheck, customRoot) {
10036
10387
  const importPath = match[1];
10037
10388
  if (wsInfo.isWorkspace && currentPkg && !currentPkg.isRoot) {
10038
10389
  if (importPath.startsWith("../") && (importPath.includes("/src/") || importPath.includes("/dist/"))) {
10039
- const resolvedTarget = path30.normalize(path30.resolve(path30.dirname(fullPath), importPath));
10390
+ const resolvedTarget = path31.normalize(path31.resolve(path31.dirname(fullPath), importPath));
10040
10391
  const targetPkg = findPackageForFile(resolvedTarget, wsInfo);
10041
10392
  if (targetPkg && targetPkg.name !== currentPkg.name) {
10042
10393
  violations.push({
@@ -10085,26 +10436,26 @@ __export(docDrift_exports, {
10085
10436
  formatDocDrift: () => formatDocDrift,
10086
10437
  scanDocDrift: () => scanDocDrift
10087
10438
  });
10088
- import fs28 from "fs";
10089
- import path31 from "path";
10090
- import { execSync as execSync9 } from "child_process";
10439
+ import fs29 from "fs";
10440
+ import path32 from "path";
10441
+ import { execSync as execSync10 } from "child_process";
10091
10442
  function collectDocFiles(root) {
10092
10443
  const cwd = root || getProjectRoot();
10093
10444
  const out = [];
10094
10445
  const pushIfMd = (dir, rel) => {
10095
10446
  try {
10096
- for (const f of fs28.readdirSync(dir)) {
10447
+ for (const f of fs29.readdirSync(dir)) {
10097
10448
  if (out.length >= MAX_DOCS) return;
10098
- const full = path31.join(dir, f);
10449
+ const full = path32.join(dir, f);
10099
10450
  try {
10100
- if (fs28.statSync(full).isFile() && /\.md$/i.test(f)) out.push(rel(f));
10451
+ if (fs29.statSync(full).isFile() && /\.md$/i.test(f)) out.push(rel(f));
10101
10452
  } catch {
10102
10453
  }
10103
10454
  }
10104
10455
  } catch {
10105
10456
  }
10106
10457
  };
10107
- pushIfMd(path31.join(cwd, "docs"), (f) => path31.join("docs", f));
10458
+ pushIfMd(path32.join(cwd, "docs"), (f) => path32.join("docs", f));
10108
10459
  pushIfMd(cwd, (f) => f);
10109
10460
  return out;
10110
10461
  }
@@ -10146,7 +10497,7 @@ function codeContainsBatch(root, needles) {
10146
10497
  const chunk = clean.slice(i, i + 50);
10147
10498
  try {
10148
10499
  const args = chunk.map((n) => `-e "${n}"`).join(" ");
10149
- const out = execSync9(
10500
+ const out = execSync10(
10150
10501
  `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`,
10151
10502
  { cwd: root, encoding: "utf-8", timeout: 8e3, maxBuffer: 256 * 1024 }
10152
10503
  ).trim();
@@ -10166,7 +10517,7 @@ function scanDocDrift(root) {
10166
10517
  let claims = [];
10167
10518
  for (const rel of collectDocFiles(cwd)) {
10168
10519
  try {
10169
- const content = fs28.readFileSync(path31.join(cwd, rel), "utf-8");
10520
+ const content = fs29.readFileSync(path32.join(cwd, rel), "utf-8");
10170
10521
  if (isExemptDoc(rel, content)) {
10171
10522
  skipped.push(rel);
10172
10523
  continue;
@@ -10337,27 +10688,27 @@ __export(kumaCheckpoint_exports, {
10337
10688
  pruneCheckpoints: () => pruneCheckpoints,
10338
10689
  rollbackToCheckpoint: () => rollbackToCheckpoint
10339
10690
  });
10340
- import fs29 from "fs";
10341
- import path32 from "path";
10691
+ import fs30 from "fs";
10692
+ import path33 from "path";
10342
10693
  async function createCheckpoint(label, description) {
10343
10694
  try {
10344
10695
  const root = getProjectRoot();
10345
- const cpDir = path32.join(root, CHECKPOINT_DIR, sanitizeLabel(label));
10346
- if (fs29.existsSync(cpDir)) {
10696
+ const cpDir = path33.join(root, CHECKPOINT_DIR, sanitizeLabel(label));
10697
+ if (fs30.existsSync(cpDir)) {
10347
10698
  return `\u26A0\uFE0F Checkpoint "${label}" already exists. Use a different label or remove it first.`;
10348
10699
  }
10349
- fs29.mkdirSync(cpDir, { recursive: true });
10700
+ fs30.mkdirSync(cpDir, { recursive: true });
10350
10701
  let gitHead;
10351
10702
  let isGitClean = false;
10352
10703
  try {
10353
- const { execSync: execSync10 } = await import("child_process");
10354
- gitHead = execSync10("git rev-parse HEAD", {
10704
+ const { execSync: execSync11 } = await import("child_process");
10705
+ gitHead = execSync11("git rev-parse HEAD", {
10355
10706
  cwd: root,
10356
10707
  encoding: "utf-8",
10357
10708
  timeout: 3e3,
10358
10709
  stdio: ["pipe", "pipe", "pipe"]
10359
10710
  }).trim();
10360
- const statusOut = execSync10("git status --porcelain", {
10711
+ const statusOut = execSync11("git status --porcelain", {
10361
10712
  cwd: root,
10362
10713
  encoding: "utf-8",
10363
10714
  timeout: 3e3,
@@ -10368,8 +10719,8 @@ async function createCheckpoint(label, description) {
10368
10719
  }
10369
10720
  const candidatePaths = /* @__PURE__ */ new Set();
10370
10721
  try {
10371
- const { execSync: execSync10 } = await import("child_process");
10372
- const gitOut = execSync10("git status --porcelain", {
10722
+ const { execSync: execSync11 } = await import("child_process");
10723
+ const gitOut = execSync11("git status --porcelain", {
10373
10724
  cwd: root,
10374
10725
  encoding: "utf-8",
10375
10726
  timeout: 4e3,
@@ -10412,15 +10763,15 @@ async function createCheckpoint(label, description) {
10412
10763
  }
10413
10764
  const files = [];
10414
10765
  for (const fp of candidatePaths) {
10415
- const fullPath = path32.resolve(root, fp);
10766
+ const fullPath = path33.resolve(root, fp);
10416
10767
  try {
10417
- if (fs29.existsSync(fullPath) && fs29.statSync(fullPath).isFile()) {
10418
- const content = fs29.readFileSync(fullPath, "utf-8");
10768
+ if (fs30.existsSync(fullPath) && fs30.statSync(fullPath).isFile()) {
10769
+ const content = fs30.readFileSync(fullPath, "utf-8");
10419
10770
  const hash = simpleHash2(content);
10420
- const snapFile = path32.join(cpDir, "files", `${fp}.kuma-snap`);
10421
- const fileDir = path32.dirname(snapFile);
10422
- if (!fs29.existsSync(fileDir)) fs29.mkdirSync(fileDir, { recursive: true });
10423
- fs29.writeFileSync(snapFile, content, "utf-8");
10771
+ const snapFile = path33.join(cpDir, "files", `${fp}.kuma-snap`);
10772
+ const fileDir = path33.dirname(snapFile);
10773
+ if (!fs30.existsSync(fileDir)) fs30.mkdirSync(fileDir, { recursive: true });
10774
+ fs30.writeFileSync(snapFile, content, "utf-8");
10424
10775
  files.push({ path: fp, hash });
10425
10776
  }
10426
10777
  } catch {
@@ -10428,7 +10779,7 @@ async function createCheckpoint(label, description) {
10428
10779
  }
10429
10780
  const db = await getDb();
10430
10781
  const dbData = db.export();
10431
- fs29.writeFileSync(path32.join(cpDir, "kuma.db"), Buffer.from(dbData));
10782
+ fs30.writeFileSync(path33.join(cpDir, "kuma.db"), Buffer.from(dbData));
10432
10783
  const manifest = {
10433
10784
  label,
10434
10785
  timestamp: Date.now(),
@@ -10438,8 +10789,8 @@ async function createCheckpoint(label, description) {
10438
10789
  dbSnapshot: true,
10439
10790
  description
10440
10791
  };
10441
- fs29.writeFileSync(
10442
- path32.join(cpDir, "manifest.json"),
10792
+ fs30.writeFileSync(
10793
+ path33.join(cpDir, "manifest.json"),
10443
10794
  JSON.stringify(manifest, null, 2),
10444
10795
  "utf-8"
10445
10796
  );
@@ -10467,29 +10818,29 @@ async function createCheckpoint(label, description) {
10467
10818
  async function rollbackToCheckpoint(label) {
10468
10819
  try {
10469
10820
  const root = getProjectRoot();
10470
- const cpDir = path32.join(root, CHECKPOINT_DIR, sanitizeLabel(label));
10471
- const manifestPath = path32.join(cpDir, "manifest.json");
10472
- if (!fs29.existsSync(manifestPath)) {
10821
+ const cpDir = path33.join(root, CHECKPOINT_DIR, sanitizeLabel(label));
10822
+ const manifestPath = path33.join(cpDir, "manifest.json");
10823
+ if (!fs30.existsSync(manifestPath)) {
10473
10824
  return `\u274C Checkpoint "${label}" not found. Available checkpoints:
10474
10825
 
10475
10826
  ${listCheckpoints()}`;
10476
10827
  }
10477
10828
  const manifest = JSON.parse(
10478
- fs29.readFileSync(manifestPath, "utf-8")
10829
+ fs30.readFileSync(manifestPath, "utf-8")
10479
10830
  );
10480
10831
  let restored = 0;
10481
10832
  let failed = 0;
10482
10833
  for (const f of manifest.files) {
10483
- const snapPath = path32.join(cpDir, "files", `${f.path}.kuma-snap`);
10484
- const legacyPath = path32.join(cpDir, "files", f.path);
10485
- const sourcePath = fs29.existsSync(snapPath) ? snapPath : legacyPath;
10486
- if (fs29.existsSync(sourcePath)) {
10834
+ const snapPath = path33.join(cpDir, "files", `${f.path}.kuma-snap`);
10835
+ const legacyPath = path33.join(cpDir, "files", f.path);
10836
+ const sourcePath = fs30.existsSync(snapPath) ? snapPath : legacyPath;
10837
+ if (fs30.existsSync(sourcePath)) {
10487
10838
  try {
10488
- const content = fs29.readFileSync(sourcePath, "utf-8");
10489
- const targetPath = path32.resolve(root, f.path);
10490
- const targetDir = path32.dirname(targetPath);
10491
- if (!fs29.existsSync(targetDir)) fs29.mkdirSync(targetDir, { recursive: true });
10492
- fs29.writeFileSync(targetPath, content, "utf-8");
10839
+ const content = fs30.readFileSync(sourcePath, "utf-8");
10840
+ const targetPath = path33.resolve(root, f.path);
10841
+ const targetDir = path33.dirname(targetPath);
10842
+ if (!fs30.existsSync(targetDir)) fs30.mkdirSync(targetDir, { recursive: true });
10843
+ fs30.writeFileSync(targetPath, content, "utf-8");
10493
10844
  restored++;
10494
10845
  } catch {
10495
10846
  failed++;
@@ -10498,8 +10849,8 @@ ${listCheckpoints()}`;
10498
10849
  }
10499
10850
  if (manifest.files.length === 0 && manifest.gitHead) {
10500
10851
  try {
10501
- const { execSync: execSync10 } = await import("child_process");
10502
- execSync10(`git checkout ${manifest.gitHead} -- .`, {
10852
+ const { execSync: execSync11 } = await import("child_process");
10853
+ execSync11(`git checkout ${manifest.gitHead} -- .`, {
10503
10854
  cwd: root,
10504
10855
  encoding: "utf-8",
10505
10856
  timeout: 8e3,
@@ -10510,12 +10861,12 @@ ${listCheckpoints()}`;
10510
10861
  failed++;
10511
10862
  }
10512
10863
  }
10513
- const dbSnapshotPath = path32.join(cpDir, "kuma.db");
10514
- if (fs29.existsSync(dbSnapshotPath)) {
10515
- const kumaDir = path32.join(root, ".kuma");
10516
- const dbPath = path32.join(kumaDir, "kuma.db");
10517
- const snapshotData = fs29.readFileSync(dbSnapshotPath);
10518
- fs29.writeFileSync(dbPath, snapshotData);
10864
+ const dbSnapshotPath = path33.join(cpDir, "kuma.db");
10865
+ if (fs30.existsSync(dbSnapshotPath)) {
10866
+ const kumaDir = path33.join(root, ".kuma");
10867
+ const dbPath = path33.join(kumaDir, "kuma.db");
10868
+ const snapshotData = fs30.readFileSync(dbSnapshotPath);
10869
+ fs30.writeFileSync(dbPath, snapshotData);
10519
10870
  resetDbInstance();
10520
10871
  }
10521
10872
  sessionMemory.recordToolCall("kuma_checkpoint_rollback", {
@@ -10540,18 +10891,18 @@ ${listCheckpoints()}`;
10540
10891
  function listCheckpoints() {
10541
10892
  try {
10542
10893
  const root = getProjectRoot();
10543
- const cpDir = path32.join(root, CHECKPOINT_DIR);
10544
- if (!fs29.existsSync(cpDir)) {
10894
+ const cpDir = path33.join(root, CHECKPOINT_DIR);
10895
+ if (!fs30.existsSync(cpDir)) {
10545
10896
  return "\u{1F4ED} No checkpoints found. Use kuma_safety({ action: 'checkpoint', label: 'pre-feature-x' }) to create one.";
10546
10897
  }
10547
- const entries = fs29.readdirSync(cpDir);
10898
+ const entries = fs30.readdirSync(cpDir);
10548
10899
  const checkpoints = [];
10549
10900
  for (const entry of entries) {
10550
- const manifestPath = path32.join(cpDir, entry, "manifest.json");
10551
- if (fs29.existsSync(manifestPath)) {
10901
+ const manifestPath = path33.join(cpDir, entry, "manifest.json");
10902
+ if (fs30.existsSync(manifestPath)) {
10552
10903
  try {
10553
10904
  const manifest = JSON.parse(
10554
- fs29.readFileSync(manifestPath, "utf-8")
10905
+ fs30.readFileSync(manifestPath, "utf-8")
10555
10906
  );
10556
10907
  checkpoints.push({ label: entry, manifest });
10557
10908
  } catch {
@@ -10583,12 +10934,12 @@ function listCheckpoints() {
10583
10934
  function pruneCheckpoints(keep = 5) {
10584
10935
  try {
10585
10936
  const root = getProjectRoot();
10586
- const cpDir = path32.join(root, CHECKPOINT_DIR);
10587
- if (!fs29.existsSync(cpDir)) return "\u{1F4ED} No checkpoints to prune.";
10588
- const entries = fs29.readdirSync(cpDir).map((e) => ({ name: e, time: fs29.statSync(path32.join(cpDir, e)).mtimeMs })).sort((a, b) => b.time - a.time);
10937
+ const cpDir = path33.join(root, CHECKPOINT_DIR);
10938
+ if (!fs30.existsSync(cpDir)) return "\u{1F4ED} No checkpoints to prune.";
10939
+ const entries = fs30.readdirSync(cpDir).map((e) => ({ name: e, time: fs30.statSync(path33.join(cpDir, e)).mtimeMs })).sort((a, b) => b.time - a.time);
10589
10940
  let removed = 0;
10590
10941
  for (let i = keep; i < entries.length; i++) {
10591
- fs29.rmSync(path32.join(cpDir, entries[i].name), { recursive: true, force: true });
10942
+ fs30.rmSync(path33.join(cpDir, entries[i].name), { recursive: true, force: true });
10592
10943
  removed++;
10593
10944
  }
10594
10945
  return removed > 0 ? `\u{1F9F9} Pruned **${removed} old checkpoint(s)**. Kept ${Math.min(keep, entries.length)} most recent.` : "\u2705 No checkpoints needed pruning.";
@@ -10613,9 +10964,9 @@ function isRiskyEditPath(filePath) {
10613
10964
  }
10614
10965
  function loadAutoCpDone(root) {
10615
10966
  try {
10616
- const fp = path32.join(root, AUTO_CP_STATE);
10617
- if (fs29.existsSync(fp)) {
10618
- const parsed = JSON.parse(fs29.readFileSync(fp, "utf-8"));
10967
+ const fp = path33.join(root, AUTO_CP_STATE);
10968
+ if (fs30.existsSync(fp)) {
10969
+ const parsed = JSON.parse(fs30.readFileSync(fp, "utf-8"));
10619
10970
  return parsed?.autoCheckpoints ?? {};
10620
10971
  }
10621
10972
  } catch {
@@ -10624,10 +10975,10 @@ function loadAutoCpDone(root) {
10624
10975
  }
10625
10976
  function saveAutoCpDone(root, done) {
10626
10977
  try {
10627
- const fp = path32.join(root, AUTO_CP_STATE);
10628
- const parsed = fs29.existsSync(fp) ? JSON.parse(fs29.readFileSync(fp, "utf-8")) : {};
10978
+ const fp = path33.join(root, AUTO_CP_STATE);
10979
+ const parsed = fs30.existsSync(fp) ? JSON.parse(fs30.readFileSync(fp, "utf-8")) : {};
10629
10980
  parsed.autoCheckpoints = done;
10630
- fs29.writeFileSync(fp, JSON.stringify(parsed), "utf-8");
10981
+ fs30.writeFileSync(fp, JSON.stringify(parsed), "utf-8");
10631
10982
  } catch {
10632
10983
  }
10633
10984
  }
@@ -10637,14 +10988,14 @@ function maybeAutoCheckpoint(filePath) {
10637
10988
  const root = getProjectRoot();
10638
10989
  const done = loadAutoCpDone(root);
10639
10990
  if (done[filePath]) return null;
10640
- const abs = path32.isAbsolute(filePath) ? filePath : path32.join(root, filePath);
10641
- if (!fs29.existsSync(abs) || !fs29.statSync(abs).isFile()) return null;
10642
- const label = `auto-pre-${sanitizeLabel(path32.basename(filePath))}`;
10643
- const cpDir = path32.join(root, CHECKPOINT_DIR, label);
10644
- if (!fs29.existsSync(cpDir)) fs29.mkdirSync(cpDir, { recursive: true });
10645
- fs29.copyFileSync(abs, path32.join(cpDir, path32.basename(abs)));
10646
- fs29.writeFileSync(
10647
- path32.join(cpDir, "manifest.json"),
10991
+ const abs = path33.isAbsolute(filePath) ? filePath : path33.join(root, filePath);
10992
+ if (!fs30.existsSync(abs) || !fs30.statSync(abs).isFile()) return null;
10993
+ const label = `auto-pre-${sanitizeLabel(path33.basename(filePath))}`;
10994
+ const cpDir = path33.join(root, CHECKPOINT_DIR, label);
10995
+ if (!fs30.existsSync(cpDir)) fs30.mkdirSync(cpDir, { recursive: true });
10996
+ fs30.copyFileSync(abs, path33.join(cpDir, path33.basename(abs)));
10997
+ fs30.writeFileSync(
10998
+ path33.join(cpDir, "manifest.json"),
10648
10999
  JSON.stringify({
10649
11000
  label,
10650
11001
  timestamp: Date.now(),
@@ -10684,8 +11035,8 @@ __export(init_exports, {
10684
11035
  generateInitMdContent: () => generateInitMdContent,
10685
11036
  runInit: () => runInit
10686
11037
  });
10687
- import fs30 from "fs";
10688
- import path33 from "path";
11038
+ import fs31 from "fs";
11039
+ import path34 from "path";
10689
11040
  function configFilePath(type) {
10690
11041
  switch (type) {
10691
11042
  case "claude":
@@ -11319,21 +11670,21 @@ function handleOpencodeSecondary(root, results) {
11319
11670
  "",
11320
11671
  "\u{1F4D6} Full rules: `.kuma/init.md`"
11321
11672
  ].join("\n");
11322
- const skillPath = path33.resolve(root, ".agents", "skills", "kuma", "SKILL.md");
11673
+ const skillPath = path34.resolve(root, ".agents", "skills", "kuma", "SKILL.md");
11323
11674
  if (!results.some((r) => r.filePath === ".agents/skills/kuma/SKILL.md")) {
11324
11675
  try {
11325
- const dir = path33.dirname(skillPath);
11326
- if (fs30.existsSync(skillPath)) {
11327
- const existing = fs30.readFileSync(skillPath, "utf-8");
11676
+ const dir = path34.dirname(skillPath);
11677
+ if (fs31.existsSync(skillPath)) {
11678
+ const existing = fs31.readFileSync(skillPath, "utf-8");
11328
11679
  if (existing.includes("kuma-mcp")) {
11329
11680
  results.push({ type: "opencode", filePath: ".agents/skills/kuma/SKILL.md", action: "skipped" });
11330
11681
  } else {
11331
- fs30.writeFileSync(skillPath, existing.trimEnd() + "\n\n---\n\n" + opencodeContent, "utf-8");
11682
+ fs31.writeFileSync(skillPath, existing.trimEnd() + "\n\n---\n\n" + opencodeContent, "utf-8");
11332
11683
  results.push({ type: "opencode", filePath: ".agents/skills/kuma/SKILL.md", action: "appended" });
11333
11684
  }
11334
11685
  } else {
11335
- if (!fs30.existsSync(dir)) fs30.mkdirSync(dir, { recursive: true });
11336
- fs30.writeFileSync(skillPath, opencodeContent, "utf-8");
11686
+ if (!fs31.existsSync(dir)) fs31.mkdirSync(dir, { recursive: true });
11687
+ fs31.writeFileSync(skillPath, opencodeContent, "utf-8");
11337
11688
  results.push({ type: "opencode", filePath: ".agents/skills/kuma/SKILL.md", action: "created" });
11338
11689
  }
11339
11690
  } catch (err) {
@@ -11345,21 +11696,21 @@ function handleOpencodeSecondary(root, results) {
11345
11696
  });
11346
11697
  }
11347
11698
  }
11348
- const opencodeSkillPath = path33.resolve(root, ".opencode", "skills", "kuma", "SKILL.md");
11699
+ const opencodeSkillPath = path34.resolve(root, ".opencode", "skills", "kuma", "SKILL.md");
11349
11700
  if (!results.some((r) => r.filePath === ".opencode/skills/kuma/SKILL.md")) {
11350
11701
  try {
11351
- const dir = path33.dirname(opencodeSkillPath);
11352
- if (fs30.existsSync(opencodeSkillPath)) {
11353
- const existing = fs30.readFileSync(opencodeSkillPath, "utf-8");
11702
+ const dir = path34.dirname(opencodeSkillPath);
11703
+ if (fs31.existsSync(opencodeSkillPath)) {
11704
+ const existing = fs31.readFileSync(opencodeSkillPath, "utf-8");
11354
11705
  if (existing.includes("kuma-mcp")) {
11355
11706
  results.push({ type: "opencode", filePath: ".opencode/skills/kuma/SKILL.md", action: "skipped" });
11356
11707
  } else {
11357
- fs30.writeFileSync(opencodeSkillPath, existing.trimEnd() + "\n\n---\n\n" + opencodeContent, "utf-8");
11708
+ fs31.writeFileSync(opencodeSkillPath, existing.trimEnd() + "\n\n---\n\n" + opencodeContent, "utf-8");
11358
11709
  results.push({ type: "opencode", filePath: ".opencode/skills/kuma/SKILL.md", action: "appended" });
11359
11710
  }
11360
11711
  } else {
11361
- if (!fs30.existsSync(dir)) fs30.mkdirSync(dir, { recursive: true });
11362
- fs30.writeFileSync(opencodeSkillPath, opencodeContent, "utf-8");
11712
+ if (!fs31.existsSync(dir)) fs31.mkdirSync(dir, { recursive: true });
11713
+ fs31.writeFileSync(opencodeSkillPath, opencodeContent, "utf-8");
11363
11714
  results.push({ type: "opencode", filePath: ".opencode/skills/kuma/SKILL.md", action: "created" });
11364
11715
  }
11365
11716
  } catch (err) {
@@ -11371,21 +11722,21 @@ function handleOpencodeSecondary(root, results) {
11371
11722
  });
11372
11723
  }
11373
11724
  }
11374
- const pluginPath = path33.resolve(root, ".opencode", "plugins", "kuma.js");
11725
+ const pluginPath = path34.resolve(root, ".opencode", "plugins", "kuma.js");
11375
11726
  if (!results.some((r) => r.filePath === ".opencode/plugins/kuma.js")) {
11376
11727
  try {
11377
- const dir = path33.dirname(pluginPath);
11378
- if (fs30.existsSync(pluginPath)) {
11379
- const existing = fs30.readFileSync(pluginPath, "utf-8");
11728
+ const dir = path34.dirname(pluginPath);
11729
+ if (fs31.existsSync(pluginPath)) {
11730
+ const existing = fs31.readFileSync(pluginPath, "utf-8");
11380
11731
  if (existing.includes("KumaPlugin") || existing.includes("kuma")) {
11381
11732
  results.push({ type: "opencode", filePath: ".opencode/plugins/kuma.js", action: "skipped" });
11382
11733
  } else {
11383
- fs30.writeFileSync(pluginPath, existing.trimEnd() + "\n\n" + opencodePluginTemplate(), "utf-8");
11734
+ fs31.writeFileSync(pluginPath, existing.trimEnd() + "\n\n" + opencodePluginTemplate(), "utf-8");
11384
11735
  results.push({ type: "opencode", filePath: ".opencode/plugins/kuma.js", action: "appended" });
11385
11736
  }
11386
11737
  } else {
11387
- if (!fs30.existsSync(dir)) fs30.mkdirSync(dir, { recursive: true });
11388
- fs30.writeFileSync(pluginPath, opencodePluginTemplate(), "utf-8");
11738
+ if (!fs31.existsSync(dir)) fs31.mkdirSync(dir, { recursive: true });
11739
+ fs31.writeFileSync(pluginPath, opencodePluginTemplate(), "utf-8");
11389
11740
  results.push({ type: "opencode", filePath: ".opencode/plugins/kuma.js", action: "created" });
11390
11741
  }
11391
11742
  } catch (err) {
@@ -11399,21 +11750,21 @@ function handleOpencodeSecondary(root, results) {
11399
11750
  }
11400
11751
  }
11401
11752
  function handleCodexSecondary(root, results) {
11402
- const tomlPath = path33.resolve(root, ".codex/config.toml");
11753
+ const tomlPath = path34.resolve(root, ".codex/config.toml");
11403
11754
  if (results.some((r) => r.filePath === ".codex/config.toml")) return;
11404
11755
  try {
11405
- const dir = path33.dirname(tomlPath);
11406
- if (!fs30.existsSync(dir)) fs30.mkdirSync(dir, { recursive: true });
11407
- if (fs30.existsSync(tomlPath)) {
11408
- const existingContent = fs30.readFileSync(tomlPath, "utf-8");
11756
+ const dir = path34.dirname(tomlPath);
11757
+ if (!fs31.existsSync(dir)) fs31.mkdirSync(dir, { recursive: true });
11758
+ if (fs31.existsSync(tomlPath)) {
11759
+ const existingContent = fs31.readFileSync(tomlPath, "utf-8");
11409
11760
  if (existingContent.includes("kuma")) {
11410
11761
  results.push({ type: "codex", filePath: ".codex/config.toml", action: "skipped" });
11411
11762
  return;
11412
11763
  }
11413
- fs30.writeFileSync(tomlPath, existingContent.trimEnd() + "\n\n" + codexConfigTomlTemplate(), "utf-8");
11764
+ fs31.writeFileSync(tomlPath, existingContent.trimEnd() + "\n\n" + codexConfigTomlTemplate(), "utf-8");
11414
11765
  results.push({ type: "codex", filePath: ".codex/config.toml", action: "appended" });
11415
11766
  } else {
11416
- fs30.writeFileSync(tomlPath, codexConfigTomlTemplate(), "utf-8");
11767
+ fs31.writeFileSync(tomlPath, codexConfigTomlTemplate(), "utf-8");
11417
11768
  results.push({ type: "codex", filePath: ".codex/config.toml", action: "created" });
11418
11769
  }
11419
11770
  } catch (err) {
@@ -11426,11 +11777,11 @@ function handleCodexSecondary(root, results) {
11426
11777
  }
11427
11778
  }
11428
11779
  function handleQwenSecondary(root, results) {
11429
- const settingsPath = path33.resolve(root, "settings.json");
11780
+ const settingsPath = path34.resolve(root, "settings.json");
11430
11781
  if (results.some((r) => r.filePath === "settings.json")) return;
11431
11782
  try {
11432
- if (fs30.existsSync(settingsPath)) {
11433
- const existingContent = fs30.readFileSync(settingsPath, "utf-8");
11783
+ if (fs31.existsSync(settingsPath)) {
11784
+ const existingContent = fs31.readFileSync(settingsPath, "utf-8");
11434
11785
  if (existingContent.includes("kuma")) {
11435
11786
  if (!existingContent.includes("_Generated by Kuma MCP_")) {
11436
11787
  try {
@@ -11438,7 +11789,7 @@ function handleQwenSecondary(root, results) {
11438
11789
  parsed.mcpServers = parsed.mcpServers || {};
11439
11790
  if (!parsed.mcpServers.kuma) {
11440
11791
  parsed.mcpServers.kuma = { command: "npx", args: ["-y", "@plumpslabs/kuma"], env: {} };
11441
- fs30.writeFileSync(settingsPath, JSON.stringify(parsed, null, 2) + "\n", "utf-8");
11792
+ fs31.writeFileSync(settingsPath, JSON.stringify(parsed, null, 2) + "\n", "utf-8");
11442
11793
  results.push({ type: "qwen", filePath: "settings.json", action: "appended" });
11443
11794
  return;
11444
11795
  }
@@ -11453,13 +11804,13 @@ function handleQwenSecondary(root, results) {
11453
11804
  parsed.mcpServers = parsed.mcpServers || {};
11454
11805
  if (!parsed.mcpServers.kuma) {
11455
11806
  parsed.mcpServers.kuma = { command: "npx", args: ["-y", "@plumpslabs/kuma"], env: {} };
11456
- fs30.writeFileSync(settingsPath, JSON.stringify(parsed, null, 2) + "\n", "utf-8");
11807
+ fs31.writeFileSync(settingsPath, JSON.stringify(parsed, null, 2) + "\n", "utf-8");
11457
11808
  results.push({ type: "qwen", filePath: "settings.json", action: "appended" });
11458
11809
  }
11459
11810
  } catch {
11460
11811
  }
11461
11812
  } else {
11462
- fs30.writeFileSync(settingsPath, qwenSettingsTemplate(), "utf-8");
11813
+ fs31.writeFileSync(settingsPath, qwenSettingsTemplate(), "utf-8");
11463
11814
  results.push({ type: "qwen", filePath: "settings.json", action: "created" });
11464
11815
  }
11465
11816
  } catch (err) {
@@ -11561,12 +11912,12 @@ function getCombinedAgentsMd(selectedTypes) {
11561
11912
  return lines.join("\n");
11562
11913
  }
11563
11914
  function handleAntigravityMcpConfig(root, results) {
11564
- const mcpPath = path33.resolve(root, ".agents/mcp_config.json");
11915
+ const mcpPath = path34.resolve(root, ".agents/mcp_config.json");
11565
11916
  if (results.some((r) => r.filePath === ".agents/mcp_config.json")) return;
11566
11917
  try {
11567
- const mcpDir = path33.dirname(mcpPath);
11568
- if (fs30.existsSync(mcpPath)) {
11569
- const existingContent = fs30.readFileSync(mcpPath, "utf-8");
11918
+ const mcpDir = path34.dirname(mcpPath);
11919
+ if (fs31.existsSync(mcpPath)) {
11920
+ const existingContent = fs31.readFileSync(mcpPath, "utf-8");
11570
11921
  if (existingContent.includes("kuma")) {
11571
11922
  results.push({ type: "antigravity", filePath: ".agents/mcp_config.json", action: "skipped" });
11572
11923
  return;
@@ -11575,14 +11926,14 @@ function handleAntigravityMcpConfig(root, results) {
11575
11926
  const parsed = JSON.parse(existingContent);
11576
11927
  parsed.mcpServers = parsed.mcpServers || {};
11577
11928
  parsed.mcpServers.kuma = { command: "npx", args: ["-y", "@plumpslabs/kuma"], env: {} };
11578
- fs30.writeFileSync(mcpPath, JSON.stringify(parsed, null, 2) + "\n", "utf-8");
11929
+ fs31.writeFileSync(mcpPath, JSON.stringify(parsed, null, 2) + "\n", "utf-8");
11579
11930
  results.push({ type: "antigravity", filePath: ".agents/mcp_config.json", action: "appended" });
11580
11931
  } catch {
11581
11932
  results.push({ type: "antigravity", filePath: ".agents/mcp_config.json", action: "error", error: "Invalid JSON in existing mcp_config.json" });
11582
11933
  }
11583
11934
  } else {
11584
- if (!fs30.existsSync(mcpDir)) fs30.mkdirSync(mcpDir, { recursive: true });
11585
- fs30.writeFileSync(mcpPath, antigravityMcpConfigTemplate(), "utf-8");
11935
+ if (!fs31.existsSync(mcpDir)) fs31.mkdirSync(mcpDir, { recursive: true });
11936
+ fs31.writeFileSync(mcpPath, antigravityMcpConfigTemplate(), "utf-8");
11586
11937
  results.push({ type: "antigravity", filePath: ".agents/mcp_config.json", action: "created" });
11587
11938
  }
11588
11939
  } catch (err) {
@@ -11595,21 +11946,21 @@ function handleAntigravityMcpConfig(root, results) {
11595
11946
  }
11596
11947
  }
11597
11948
  function handleAntigravityRules(root, results) {
11598
- const rulePath = path33.resolve(root, ".agents", "rules", "kuma.md");
11949
+ const rulePath = path34.resolve(root, ".agents", "rules", "kuma.md");
11599
11950
  if (results.some((r) => r.filePath === ".agents/rules/kuma.md")) return;
11600
11951
  try {
11601
- const dir = path33.dirname(rulePath);
11602
- if (!fs30.existsSync(dir)) fs30.mkdirSync(dir, { recursive: true });
11603
- if (fs30.existsSync(rulePath)) {
11604
- const existing = fs30.readFileSync(rulePath, "utf-8");
11952
+ const dir = path34.dirname(rulePath);
11953
+ if (!fs31.existsSync(dir)) fs31.mkdirSync(dir, { recursive: true });
11954
+ if (fs31.existsSync(rulePath)) {
11955
+ const existing = fs31.readFileSync(rulePath, "utf-8");
11605
11956
  if (existing.includes("Kuma MCP") || existing.includes("kuma-mcp")) {
11606
11957
  results.push({ type: "antigravity", filePath: ".agents/rules/kuma.md", action: "skipped" });
11607
11958
  return;
11608
11959
  }
11609
- fs30.writeFileSync(rulePath, existing.trimEnd() + "\n\n---\n\n" + antigravityRuleTemplate(), "utf-8");
11960
+ fs31.writeFileSync(rulePath, existing.trimEnd() + "\n\n---\n\n" + antigravityRuleTemplate(), "utf-8");
11610
11961
  results.push({ type: "antigravity", filePath: ".agents/rules/kuma.md", action: "appended" });
11611
11962
  } else {
11612
- fs30.writeFileSync(rulePath, antigravityRuleTemplate(), "utf-8");
11963
+ fs31.writeFileSync(rulePath, antigravityRuleTemplate(), "utf-8");
11613
11964
  results.push({ type: "antigravity", filePath: ".agents/rules/kuma.md", action: "created" });
11614
11965
  }
11615
11966
  } catch (err) {
@@ -11622,19 +11973,19 @@ function handleAntigravityRules(root, results) {
11622
11973
  }
11623
11974
  }
11624
11975
  function handleGeminiMd(root, results) {
11625
- const geminiPath = path33.resolve(root, "GEMINI.md");
11976
+ const geminiPath = path34.resolve(root, "GEMINI.md");
11626
11977
  if (results.some((r) => r.filePath === "GEMINI.md")) return;
11627
11978
  try {
11628
- if (fs30.existsSync(geminiPath)) {
11629
- const existing = fs30.readFileSync(geminiPath, "utf-8");
11979
+ if (fs31.existsSync(geminiPath)) {
11980
+ const existing = fs31.readFileSync(geminiPath, "utf-8");
11630
11981
  if (existing.includes("Kuma MCP") || existing.includes("kuma_context")) {
11631
11982
  results.push({ type: "antigravity", filePath: "GEMINI.md", action: "skipped" });
11632
11983
  return;
11633
11984
  }
11634
- fs30.writeFileSync(geminiPath, existing.trimEnd() + "\n\n---\n\n" + geminiTemplate(), "utf-8");
11985
+ fs31.writeFileSync(geminiPath, existing.trimEnd() + "\n\n---\n\n" + geminiTemplate(), "utf-8");
11635
11986
  results.push({ type: "antigravity", filePath: "GEMINI.md", action: "appended" });
11636
11987
  } else {
11637
- fs30.writeFileSync(geminiPath, geminiTemplate(), "utf-8");
11988
+ fs31.writeFileSync(geminiPath, geminiTemplate(), "utf-8");
11638
11989
  results.push({ type: "antigravity", filePath: "GEMINI.md", action: "created" });
11639
11990
  }
11640
11991
  } catch (err) {
@@ -11652,19 +12003,19 @@ function handleAntigravitySecondary(root, results) {
11652
12003
  handleGeminiMd(root, results);
11653
12004
  }
11654
12005
  function handleWindsurfSecondary(root, results) {
11655
- const rulesPath = path33.resolve(root, ".windsurfrules");
12006
+ const rulesPath = path34.resolve(root, ".windsurfrules");
11656
12007
  if (results.some((r) => r.filePath === ".windsurfrules")) return;
11657
12008
  try {
11658
- if (fs30.existsSync(rulesPath)) {
11659
- const existing = fs30.readFileSync(rulesPath, "utf-8");
12009
+ if (fs31.existsSync(rulesPath)) {
12010
+ const existing = fs31.readFileSync(rulesPath, "utf-8");
11660
12011
  if (existing.includes("Kuma MCP") || existing.includes("kuma_context")) {
11661
12012
  results.push({ type: "windsurf", filePath: ".windsurfrules", action: "skipped" });
11662
12013
  return;
11663
12014
  }
11664
- fs30.writeFileSync(rulesPath, existing.trimEnd() + "\n\n---\n\n" + windsurfrulesTemplate(), "utf-8");
12015
+ fs31.writeFileSync(rulesPath, existing.trimEnd() + "\n\n---\n\n" + windsurfrulesTemplate(), "utf-8");
11665
12016
  results.push({ type: "windsurf", filePath: ".windsurfrules", action: "appended" });
11666
12017
  } else {
11667
- fs30.writeFileSync(rulesPath, windsurfrulesTemplate(), "utf-8");
12018
+ fs31.writeFileSync(rulesPath, windsurfrulesTemplate(), "utf-8");
11668
12019
  results.push({ type: "windsurf", filePath: ".windsurfrules", action: "created" });
11669
12020
  }
11670
12021
  } catch (err) {
@@ -11677,21 +12028,21 @@ function handleWindsurfSecondary(root, results) {
11677
12028
  }
11678
12029
  }
11679
12030
  function handleClineSecondary(root, results) {
11680
- const rooPath = path33.resolve(root, ".roo", "rules", "kuma.md");
12031
+ const rooPath = path34.resolve(root, ".roo", "rules", "kuma.md");
11681
12032
  if (!results.some((r) => r.filePath === ".roo/rules/kuma.md")) {
11682
12033
  try {
11683
- const dir = path33.dirname(rooPath);
11684
- if (fs30.existsSync(rooPath)) {
11685
- const existing = fs30.readFileSync(rooPath, "utf-8");
12034
+ const dir = path34.dirname(rooPath);
12035
+ if (fs31.existsSync(rooPath)) {
12036
+ const existing = fs31.readFileSync(rooPath, "utf-8");
11686
12037
  if (existing.includes("kuma-mcp") || existing.includes("Kuma MCP")) {
11687
12038
  results.push({ type: "cline", filePath: ".roo/rules/kuma.md", action: "skipped" });
11688
12039
  } else {
11689
- fs30.writeFileSync(rooPath, existing.trimEnd() + "\n\n---\n\n" + rooRulesTemplate(), "utf-8");
12040
+ fs31.writeFileSync(rooPath, existing.trimEnd() + "\n\n---\n\n" + rooRulesTemplate(), "utf-8");
11690
12041
  results.push({ type: "cline", filePath: ".roo/rules/kuma.md", action: "appended" });
11691
12042
  }
11692
12043
  } else {
11693
- if (!fs30.existsSync(dir)) fs30.mkdirSync(dir, { recursive: true });
11694
- fs30.writeFileSync(rooPath, rooRulesTemplate(), "utf-8");
12044
+ if (!fs31.existsSync(dir)) fs31.mkdirSync(dir, { recursive: true });
12045
+ fs31.writeFileSync(rooPath, rooRulesTemplate(), "utf-8");
11695
12046
  results.push({ type: "cline", filePath: ".roo/rules/kuma.md", action: "created" });
11696
12047
  }
11697
12048
  } catch (err) {
@@ -11703,21 +12054,21 @@ function handleClineSecondary(root, results) {
11703
12054
  });
11704
12055
  }
11705
12056
  }
11706
- const traePath = path33.resolve(root, ".trae", "rules", "kuma.md");
12057
+ const traePath = path34.resolve(root, ".trae", "rules", "kuma.md");
11707
12058
  if (!results.some((r) => r.filePath === ".trae/rules/kuma.md")) {
11708
12059
  try {
11709
- const dir = path33.dirname(traePath);
11710
- if (fs30.existsSync(traePath)) {
11711
- const existing = fs30.readFileSync(traePath, "utf-8");
12060
+ const dir = path34.dirname(traePath);
12061
+ if (fs31.existsSync(traePath)) {
12062
+ const existing = fs31.readFileSync(traePath, "utf-8");
11712
12063
  if (existing.includes("Kuma MCP")) {
11713
12064
  results.push({ type: "cline", filePath: ".trae/rules/kuma.md", action: "skipped" });
11714
12065
  } else {
11715
- fs30.writeFileSync(traePath, existing.trimEnd() + "\n\n---\n\n" + traeRulesTemplate(), "utf-8");
12066
+ fs31.writeFileSync(traePath, existing.trimEnd() + "\n\n---\n\n" + traeRulesTemplate(), "utf-8");
11716
12067
  results.push({ type: "cline", filePath: ".trae/rules/kuma.md", action: "appended" });
11717
12068
  }
11718
12069
  } else {
11719
- if (!fs30.existsSync(dir)) fs30.mkdirSync(dir, { recursive: true });
11720
- fs30.writeFileSync(traePath, traeRulesTemplate(), "utf-8");
12070
+ if (!fs31.existsSync(dir)) fs31.mkdirSync(dir, { recursive: true });
12071
+ fs31.writeFileSync(traePath, traeRulesTemplate(), "utf-8");
11721
12072
  results.push({ type: "cline", filePath: ".trae/rules/kuma.md", action: "created" });
11722
12073
  }
11723
12074
  } catch (err) {
@@ -11729,21 +12080,21 @@ function handleClineSecondary(root, results) {
11729
12080
  });
11730
12081
  }
11731
12082
  }
11732
- const qoderPath = path33.resolve(root, ".qoder", "rules", "kuma.md");
12083
+ const qoderPath = path34.resolve(root, ".qoder", "rules", "kuma.md");
11733
12084
  if (!results.some((r) => r.filePath === ".qoder/rules/kuma.md")) {
11734
12085
  try {
11735
- const dir = path33.dirname(qoderPath);
11736
- if (fs30.existsSync(qoderPath)) {
11737
- const existing = fs30.readFileSync(qoderPath, "utf-8");
12086
+ const dir = path34.dirname(qoderPath);
12087
+ if (fs31.existsSync(qoderPath)) {
12088
+ const existing = fs31.readFileSync(qoderPath, "utf-8");
11738
12089
  if (existing.includes("Kuma MCP")) {
11739
12090
  results.push({ type: "cline", filePath: ".qoder/rules/kuma.md", action: "skipped" });
11740
12091
  } else {
11741
- fs30.writeFileSync(qoderPath, existing.trimEnd() + "\n\n---\n\n" + qoderRulesTemplate(), "utf-8");
12092
+ fs31.writeFileSync(qoderPath, existing.trimEnd() + "\n\n---\n\n" + qoderRulesTemplate(), "utf-8");
11742
12093
  results.push({ type: "cline", filePath: ".qoder/rules/kuma.md", action: "appended" });
11743
12094
  }
11744
12095
  } else {
11745
- if (!fs30.existsSync(dir)) fs30.mkdirSync(dir, { recursive: true });
11746
- fs30.writeFileSync(qoderPath, qoderRulesTemplate(), "utf-8");
12096
+ if (!fs31.existsSync(dir)) fs31.mkdirSync(dir, { recursive: true });
12097
+ fs31.writeFileSync(qoderPath, qoderRulesTemplate(), "utf-8");
11747
12098
  results.push({ type: "cline", filePath: ".qoder/rules/kuma.md", action: "created" });
11748
12099
  }
11749
12100
  } catch (err) {
@@ -11757,18 +12108,18 @@ function handleClineSecondary(root, results) {
11757
12108
  }
11758
12109
  }
11759
12110
  function handleAiderSecondary(root, results) {
11760
- const ymlPath = path33.resolve(root, ".aider.conf.yml");
12111
+ const ymlPath = path34.resolve(root, ".aider.conf.yml");
11761
12112
  if (results.some((r) => r.filePath === ".aider.conf.yml")) return;
11762
12113
  try {
11763
12114
  const conventionsRef = "read: CONVENTIONS.md";
11764
- if (fs30.existsSync(ymlPath)) {
11765
- const existingContent = fs30.readFileSync(ymlPath, "utf-8");
12115
+ if (fs31.existsSync(ymlPath)) {
12116
+ const existingContent = fs31.readFileSync(ymlPath, "utf-8");
11766
12117
  if (existingContent.includes("CONVENTIONS.md") || existingContent.includes("kuma")) {
11767
12118
  results.push({ type: "aider", filePath: ".aider.conf.yml", action: "skipped" });
11768
12119
  return;
11769
12120
  }
11770
12121
  const newContent = existingContent.trimEnd() + "\n\n# Kuma MCP conventions\n" + conventionsRef + "\n";
11771
- fs30.writeFileSync(ymlPath, newContent, "utf-8");
12122
+ fs31.writeFileSync(ymlPath, newContent, "utf-8");
11772
12123
  results.push({ type: "aider", filePath: ".aider.conf.yml", action: "appended" });
11773
12124
  } else {
11774
12125
  const content = [
@@ -11778,7 +12129,7 @@ function handleAiderSecondary(root, results) {
11778
12129
  conventionsRef,
11779
12130
  ""
11780
12131
  ].join("\n");
11781
- fs30.writeFileSync(ymlPath, content, "utf-8");
12132
+ fs31.writeFileSync(ymlPath, content, "utf-8");
11782
12133
  results.push({ type: "aider", filePath: ".aider.conf.yml", action: "created" });
11783
12134
  }
11784
12135
  } catch (err) {
@@ -11791,10 +12142,10 @@ function handleAiderSecondary(root, results) {
11791
12142
  }
11792
12143
  }
11793
12144
  function handleCopilotSecondary(root, results) {
11794
- const skillPath = path33.resolve(root, ".github/skills/kuma/SKILL.md");
12145
+ const skillPath = path34.resolve(root, ".github/skills/kuma/SKILL.md");
11795
12146
  if (results.some((r) => r.filePath === ".github/skills/kuma/SKILL.md")) return;
11796
12147
  try {
11797
- const dir = path33.dirname(skillPath);
12148
+ const dir = path34.dirname(skillPath);
11798
12149
  const content = [
11799
12150
  "---",
11800
12151
  "name: kuma-mcp",
@@ -11805,17 +12156,17 @@ function handleCopilotSecondary(root, results) {
11805
12156
  "",
11806
12157
  "\u{1F4D6} Read `.kuma/init.md` for detailed rules."
11807
12158
  ].join("\n");
11808
- if (fs30.existsSync(skillPath)) {
11809
- const existingContent = fs30.readFileSync(skillPath, "utf-8");
12159
+ if (fs31.existsSync(skillPath)) {
12160
+ const existingContent = fs31.readFileSync(skillPath, "utf-8");
11810
12161
  if (existingContent.includes("kuma")) {
11811
12162
  results.push({ type: "copilot", filePath: ".github/skills/kuma/SKILL.md", action: "skipped" });
11812
12163
  return;
11813
12164
  }
11814
- fs30.writeFileSync(skillPath, existingContent.trimEnd() + "\n\n" + content, "utf-8");
12165
+ fs31.writeFileSync(skillPath, existingContent.trimEnd() + "\n\n" + content, "utf-8");
11815
12166
  results.push({ type: "copilot", filePath: ".github/skills/kuma/SKILL.md", action: "appended" });
11816
12167
  } else {
11817
- if (!fs30.existsSync(dir)) fs30.mkdirSync(dir, { recursive: true });
11818
- fs30.writeFileSync(skillPath, content, "utf-8");
12168
+ if (!fs31.existsSync(dir)) fs31.mkdirSync(dir, { recursive: true });
12169
+ fs31.writeFileSync(skillPath, content, "utf-8");
11819
12170
  results.push({ type: "copilot", filePath: ".github/skills/kuma/SKILL.md", action: "created" });
11820
12171
  }
11821
12172
  } catch (err) {
@@ -11828,21 +12179,21 @@ function handleCopilotSecondary(root, results) {
11828
12179
  }
11829
12180
  }
11830
12181
  function handleOpenclawSecondary(root, results) {
11831
- const mcpPath = path33.resolve(root, ".agents/mcp_config.json");
12182
+ const mcpPath = path34.resolve(root, ".agents/mcp_config.json");
11832
12183
  if (results.some((r) => r.filePath === ".agents/mcp_config.json")) return;
11833
12184
  try {
11834
- const dir = path33.dirname(mcpPath);
11835
- if (fs30.existsSync(mcpPath)) {
11836
- const existingContent = fs30.readFileSync(mcpPath, "utf-8");
12185
+ const dir = path34.dirname(mcpPath);
12186
+ if (fs31.existsSync(mcpPath)) {
12187
+ const existingContent = fs31.readFileSync(mcpPath, "utf-8");
11837
12188
  if (existingContent.includes("kuma")) return;
11838
12189
  const parsed = JSON.parse(existingContent);
11839
12190
  parsed.mcpServers = parsed.mcpServers || {};
11840
12191
  parsed.mcpServers.kuma = { command: "npx", args: ["-y", "@plumpslabs/kuma"], env: {} };
11841
- fs30.writeFileSync(mcpPath, JSON.stringify(parsed, null, 2) + "\n", "utf-8");
12192
+ fs31.writeFileSync(mcpPath, JSON.stringify(parsed, null, 2) + "\n", "utf-8");
11842
12193
  results.push({ type: "openclaw", filePath: ".agents/mcp_config.json", action: "appended" });
11843
12194
  } else {
11844
- if (!fs30.existsSync(dir)) fs30.mkdirSync(dir, { recursive: true });
11845
- fs30.writeFileSync(mcpPath, antigravityMcpConfigTemplate(), "utf-8");
12195
+ if (!fs31.existsSync(dir)) fs31.mkdirSync(dir, { recursive: true });
12196
+ fs31.writeFileSync(mcpPath, antigravityMcpConfigTemplate(), "utf-8");
11846
12197
  results.push({ type: "openclaw", filePath: ".agents/mcp_config.json", action: "created" });
11847
12198
  }
11848
12199
  } catch (err) {
@@ -11855,20 +12206,20 @@ function handleOpenclawSecondary(root, results) {
11855
12206
  }
11856
12207
  }
11857
12208
  function handleInitMdGeneration(root, results) {
11858
- const initMdPath = path33.resolve(root, ".kuma/init.md");
12209
+ const initMdPath = path34.resolve(root, ".kuma/init.md");
11859
12210
  try {
11860
- const kumaDir = path33.dirname(initMdPath);
11861
- if (!fs30.existsSync(kumaDir)) fs30.mkdirSync(kumaDir, { recursive: true });
11862
- if (fs30.existsSync(initMdPath)) {
11863
- const existing = fs30.readFileSync(initMdPath, "utf-8");
12211
+ const kumaDir = path34.dirname(initMdPath);
12212
+ if (!fs31.existsSync(kumaDir)) fs31.mkdirSync(kumaDir, { recursive: true });
12213
+ if (fs31.existsSync(initMdPath)) {
12214
+ const existing = fs31.readFileSync(initMdPath, "utf-8");
11864
12215
  if (existing.includes("_Generated by Kuma MCP_")) {
11865
12216
  results.push({ type: "claude", filePath: ".kuma/init.md", action: "skipped" });
11866
12217
  return;
11867
12218
  }
11868
- fs30.writeFileSync(initMdPath, existing.trimEnd() + "\n\n" + generateInitMdContent(), "utf-8");
12219
+ fs31.writeFileSync(initMdPath, existing.trimEnd() + "\n\n" + generateInitMdContent(), "utf-8");
11869
12220
  results.push({ type: "claude", filePath: ".kuma/init.md", action: "appended" });
11870
12221
  } else {
11871
- fs30.writeFileSync(initMdPath, generateInitMdContent(), "utf-8");
12222
+ fs31.writeFileSync(initMdPath, generateInitMdContent(), "utf-8");
11872
12223
  results.push({ type: "claude", filePath: ".kuma/init.md", action: "created" });
11873
12224
  }
11874
12225
  } catch (err) {
@@ -11881,20 +12232,20 @@ function handleInitMdGeneration(root, results) {
11881
12232
  }
11882
12233
  }
11883
12234
  function handleCodewhaleSecondary(root, results) {
11884
- const mcpPath = path33.resolve(root, ".codewhale/mcp.json");
12235
+ const mcpPath = path34.resolve(root, ".codewhale/mcp.json");
11885
12236
  if (results.some((r) => r.filePath === ".codewhale/mcp.json")) return;
11886
12237
  try {
11887
- const dir = path33.dirname(mcpPath);
11888
- if (fs30.existsSync(mcpPath)) {
11889
- const existingContent = fs30.readFileSync(mcpPath, "utf-8");
12238
+ const dir = path34.dirname(mcpPath);
12239
+ if (fs31.existsSync(mcpPath)) {
12240
+ const existingContent = fs31.readFileSync(mcpPath, "utf-8");
11890
12241
  if (existingContent.includes("kuma")) return;
11891
12242
  const parsed = JSON.parse(existingContent);
11892
12243
  parsed.mcpServers = parsed.mcpServers || {};
11893
12244
  parsed.mcpServers.kuma = { command: "npx", args: ["-y", "@plumpslabs/kuma"], env: {} };
11894
- fs30.writeFileSync(mcpPath, JSON.stringify(parsed, null, 2) + "\n", "utf-8");
12245
+ fs31.writeFileSync(mcpPath, JSON.stringify(parsed, null, 2) + "\n", "utf-8");
11895
12246
  results.push({ type: "codewhale", filePath: ".codewhale/mcp.json", action: "appended" });
11896
12247
  } else {
11897
- if (!fs30.existsSync(dir)) fs30.mkdirSync(dir, { recursive: true });
12248
+ if (!fs31.existsSync(dir)) fs31.mkdirSync(dir, { recursive: true });
11898
12249
  const config = {
11899
12250
  mcpServers: {
11900
12251
  kuma: {
@@ -11904,7 +12255,7 @@ function handleCodewhaleSecondary(root, results) {
11904
12255
  }
11905
12256
  }
11906
12257
  };
11907
- fs30.writeFileSync(mcpPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
12258
+ fs31.writeFileSync(mcpPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
11908
12259
  results.push({ type: "codewhale", filePath: ".codewhale/mcp.json", action: "created" });
11909
12260
  }
11910
12261
  } catch (err) {
@@ -11917,7 +12268,7 @@ function handleCodewhaleSecondary(root, results) {
11917
12268
  }
11918
12269
  }
11919
12270
  function handleClaudeSecondary(root, results) {
11920
- const settingsPath = path33.resolve(root, ".claude", "settings.json");
12271
+ const settingsPath = path34.resolve(root, ".claude", "settings.json");
11921
12272
  const hookBlock = {
11922
12273
  hooks: {
11923
12274
  PreToolUse: [
@@ -11948,8 +12299,8 @@ function handleClaudeSecondary(root, results) {
11948
12299
  }
11949
12300
  };
11950
12301
  try {
11951
- if (fs30.existsSync(settingsPath)) {
11952
- const existing = JSON.parse(fs30.readFileSync(settingsPath, "utf-8"));
12302
+ if (fs31.existsSync(settingsPath)) {
12303
+ const existing = JSON.parse(fs31.readFileSync(settingsPath, "utf-8"));
11953
12304
  const existingHooks = existing.hooks || {};
11954
12305
  const mergedPre = [...existingHooks.PreToolUse || []];
11955
12306
  for (const entry of hookBlock.hooks.PreToolUse) {
@@ -11973,12 +12324,12 @@ function handleClaudeSecondary(root, results) {
11973
12324
  ...existing,
11974
12325
  hooks: { ...existingHooks, PreToolUse: mergedPre, SessionStart: mergedStart, PreCompact: mergedCompact }
11975
12326
  };
11976
- fs30.writeFileSync(settingsPath, JSON.stringify(merged, null, 2) + "\n", "utf-8");
12327
+ fs31.writeFileSync(settingsPath, JSON.stringify(merged, null, 2) + "\n", "utf-8");
11977
12328
  results.push({ type: "claude", filePath: ".claude/settings.json", action: "appended" });
11978
12329
  } else {
11979
- const dir = path33.dirname(settingsPath);
11980
- if (!fs30.existsSync(dir)) fs30.mkdirSync(dir, { recursive: true });
11981
- fs30.writeFileSync(settingsPath, JSON.stringify(hookBlock, null, 2) + "\n", "utf-8");
12330
+ const dir = path34.dirname(settingsPath);
12331
+ if (!fs31.existsSync(dir)) fs31.mkdirSync(dir, { recursive: true });
12332
+ fs31.writeFileSync(settingsPath, JSON.stringify(hookBlock, null, 2) + "\n", "utf-8");
11982
12333
  results.push({ type: "claude", filePath: ".claude/settings.json", action: "created" });
11983
12334
  }
11984
12335
  } catch (err) {
@@ -11989,10 +12340,10 @@ function handleClaudeSecondary(root, results) {
11989
12340
  error: err instanceof Error ? err.message : String(err)
11990
12341
  });
11991
12342
  }
11992
- const skillPath = path33.resolve(root, ".claude", "skills", "kuma", "SKILL.md");
12343
+ const skillPath = path34.resolve(root, ".claude", "skills", "kuma", "SKILL.md");
11993
12344
  if (!results.some((r) => r.filePath === ".claude/skills/kuma/SKILL.md")) {
11994
12345
  try {
11995
- const dir = path33.dirname(skillPath);
12346
+ const dir = path34.dirname(skillPath);
11996
12347
  const content = [
11997
12348
  "---",
11998
12349
  "name: kuma-mcp",
@@ -12004,17 +12355,17 @@ function handleClaudeSecondary(root, results) {
12004
12355
  "\u{1F4D6} Read `.kuma/init.md` for detailed rules.",
12005
12356
  "\u{1F4C2} Readable state: `.kuma/KNOWN_GOTCHAS.md` (gotchas) \xB7 `.kuma/memories/decisions.md` (decisions)"
12006
12357
  ].join("\n");
12007
- if (fs30.existsSync(skillPath)) {
12008
- const existing = fs30.readFileSync(skillPath, "utf-8");
12358
+ if (fs31.existsSync(skillPath)) {
12359
+ const existing = fs31.readFileSync(skillPath, "utf-8");
12009
12360
  if (existing.includes("kuma-mcp")) {
12010
12361
  results.push({ type: "claude", filePath: ".claude/skills/kuma/SKILL.md", action: "skipped" });
12011
12362
  } else {
12012
- fs30.writeFileSync(skillPath, existing.trimEnd() + "\n\n---\n\n" + content, "utf-8");
12363
+ fs31.writeFileSync(skillPath, existing.trimEnd() + "\n\n---\n\n" + content, "utf-8");
12013
12364
  results.push({ type: "claude", filePath: ".claude/skills/kuma/SKILL.md", action: "appended" });
12014
12365
  }
12015
12366
  } else {
12016
- if (!fs30.existsSync(dir)) fs30.mkdirSync(dir, { recursive: true });
12017
- fs30.writeFileSync(skillPath, content, "utf-8");
12367
+ if (!fs31.existsSync(dir)) fs31.mkdirSync(dir, { recursive: true });
12368
+ fs31.writeFileSync(skillPath, content, "utf-8");
12018
12369
  results.push({ type: "claude", filePath: ".claude/skills/kuma/SKILL.md", action: "created" });
12019
12370
  }
12020
12371
  } catch (err) {
@@ -12028,27 +12379,27 @@ function handleClaudeSecondary(root, results) {
12028
12379
  }
12029
12380
  }
12030
12381
  function writeHooksFile(root, relPath, type, results, build) {
12031
- const fullPath = path33.resolve(root, relPath);
12382
+ const fullPath = path34.resolve(root, relPath);
12032
12383
  try {
12033
12384
  let existing = {};
12034
12385
  let existed = false;
12035
- if (fs30.existsSync(fullPath)) {
12386
+ if (fs31.existsSync(fullPath)) {
12036
12387
  existed = true;
12037
12388
  try {
12038
- existing = JSON.parse(fs30.readFileSync(fullPath, "utf-8"));
12389
+ existing = JSON.parse(fs31.readFileSync(fullPath, "utf-8"));
12039
12390
  } catch {
12040
12391
  existing = {};
12041
12392
  }
12042
12393
  } else {
12043
- const dir = path33.dirname(fullPath);
12044
- if (!fs30.existsSync(dir)) fs30.mkdirSync(dir, { recursive: true });
12394
+ const dir = path34.dirname(fullPath);
12395
+ if (!fs31.existsSync(dir)) fs31.mkdirSync(dir, { recursive: true });
12045
12396
  }
12046
12397
  const { doc, changed } = build(existing);
12047
12398
  if (!changed) {
12048
12399
  results.push({ type, filePath: relPath, action: "skipped" });
12049
12400
  return;
12050
12401
  }
12051
- fs30.writeFileSync(fullPath, JSON.stringify(doc, null, 2) + "\n", "utf-8");
12402
+ fs31.writeFileSync(fullPath, JSON.stringify(doc, null, 2) + "\n", "utf-8");
12052
12403
  results.push({ type, filePath: relPath, action: existed ? "appended" : "created" });
12053
12404
  } catch (err) {
12054
12405
  results.push({ type, filePath: relPath, action: "error", error: err instanceof Error ? err.message : String(err) });
@@ -12129,18 +12480,18 @@ function handleCodexHooks(root, results) {
12129
12480
  });
12130
12481
  }
12131
12482
  function handleCursorGotchaRules(root, results) {
12132
- const rulesDir2 = path33.resolve(root, ".cursor", "rules", "kuma-gotchas");
12483
+ const rulesDir2 = path34.resolve(root, ".cursor", "rules", "kuma-gotchas");
12133
12484
  try {
12134
12485
  let gotchas = [];
12135
12486
  try {
12136
12487
  gotchas = getActiveGotchas().filter((g) => g.severity === "high" || g.severity === "critical");
12137
12488
  } catch {
12138
12489
  }
12139
- if (fs30.existsSync(rulesDir2)) {
12140
- for (const f of fs30.readdirSync(rulesDir2)) {
12490
+ if (fs31.existsSync(rulesDir2)) {
12491
+ for (const f of fs31.readdirSync(rulesDir2)) {
12141
12492
  if (f.endsWith(".mdc")) {
12142
12493
  try {
12143
- fs30.rmSync(path33.join(rulesDir2, f), { force: true });
12494
+ fs31.rmSync(path34.join(rulesDir2, f), { force: true });
12144
12495
  } catch {
12145
12496
  }
12146
12497
  }
@@ -12150,7 +12501,7 @@ function handleCursorGotchaRules(root, results) {
12150
12501
  results.push({ type: "cursor", filePath: ".cursor/rules/kuma-gotchas/", action: "skipped" });
12151
12502
  return;
12152
12503
  }
12153
- fs30.mkdirSync(rulesDir2, { recursive: true });
12504
+ fs31.mkdirSync(rulesDir2, { recursive: true });
12154
12505
  const seen = /* @__PURE__ */ new Set();
12155
12506
  let created = 0;
12156
12507
  for (const g of gotchas) {
@@ -12171,7 +12522,7 @@ function handleCursorGotchaRules(root, results) {
12171
12522
  "`kuma_context({ action: 'history', target: '<file>' })`",
12172
12523
  ""
12173
12524
  ].join("\n");
12174
- fs30.writeFileSync(path33.join(rulesDir2, `${slug2}.mdc`), md, "utf-8");
12525
+ fs31.writeFileSync(path34.join(rulesDir2, `${slug2}.mdc`), md, "utf-8");
12175
12526
  created++;
12176
12527
  }
12177
12528
  results.push({
@@ -12198,28 +12549,28 @@ function runInit(options) {
12198
12549
  let agentsMdHandled = false;
12199
12550
  for (const type of selected) {
12200
12551
  const relativePath = configFilePath(type);
12201
- const fullPath = path33.resolve(root, relativePath);
12552
+ const fullPath = path34.resolve(root, relativePath);
12202
12553
  const getTemplate = TEMPLATES[type];
12203
12554
  try {
12204
12555
  if (AGENTS_MD_TYPES.includes(type) && !agentsMdHandled) {
12205
12556
  agentsMdHandled = true;
12206
12557
  const combinedContent = getCombinedAgentsMd(new Set(agentsMdSelected));
12207
- if (fs30.existsSync(fullPath)) {
12558
+ if (fs31.existsSync(fullPath)) {
12208
12559
  if (options.skipExisting) {
12209
12560
  results.push({ type, filePath: relativePath, action: "skipped" });
12210
12561
  } else {
12211
- const existingContent = fs30.readFileSync(fullPath, "utf-8");
12562
+ const existingContent = fs31.readFileSync(fullPath, "utf-8");
12212
12563
  if (existingContent.includes("_Generated by Kuma MCP_")) {
12213
12564
  results.push({ type, filePath: relativePath, action: "skipped" });
12214
12565
  } else {
12215
- fs30.writeFileSync(fullPath, existingContent.trimEnd() + "\n\n" + combinedContent, "utf-8");
12566
+ fs31.writeFileSync(fullPath, existingContent.trimEnd() + "\n\n" + combinedContent, "utf-8");
12216
12567
  results.push({ type, filePath: relativePath, action: "appended" });
12217
12568
  }
12218
12569
  }
12219
12570
  } else {
12220
- const dir = path33.dirname(fullPath);
12221
- if (!fs30.existsSync(dir)) fs30.mkdirSync(dir, { recursive: true });
12222
- fs30.writeFileSync(fullPath, combinedContent, "utf-8");
12571
+ const dir = path34.dirname(fullPath);
12572
+ if (!fs31.existsSync(dir)) fs31.mkdirSync(dir, { recursive: true });
12573
+ fs31.writeFileSync(fullPath, combinedContent, "utf-8");
12223
12574
  results.push({ type, filePath: relativePath, action: "created" });
12224
12575
  }
12225
12576
  if (selectedSet.has("opencode")) handleOpencodeSecondary(root, results);
@@ -12231,12 +12582,12 @@ function runInit(options) {
12231
12582
  continue;
12232
12583
  } else {
12233
12584
  const template = getTemplate();
12234
- if (fs30.existsSync(fullPath)) {
12585
+ if (fs31.existsSync(fullPath)) {
12235
12586
  if (options.skipExisting) {
12236
12587
  results.push({ type, filePath: relativePath, action: "skipped" });
12237
12588
  continue;
12238
12589
  }
12239
- const existingContent = fs30.readFileSync(fullPath, "utf-8");
12590
+ const existingContent = fs31.readFileSync(fullPath, "utf-8");
12240
12591
  if (existingContent.includes("_Generated by Kuma MCP_")) {
12241
12592
  if (type === "antigravity") {
12242
12593
  handleAntigravitySecondary(root, results);
@@ -12253,14 +12604,14 @@ function runInit(options) {
12253
12604
  continue;
12254
12605
  }
12255
12606
  const newContent = existingContent.trimEnd() + APPEND_SEPARATOR + template;
12256
- fs30.writeFileSync(fullPath, newContent, "utf-8");
12607
+ fs31.writeFileSync(fullPath, newContent, "utf-8");
12257
12608
  results.push({ type, filePath: relativePath, action: "appended" });
12258
12609
  } else {
12259
- const dir = path33.dirname(fullPath);
12260
- if (!fs30.existsSync(dir)) {
12261
- fs30.mkdirSync(dir, { recursive: true });
12610
+ const dir = path34.dirname(fullPath);
12611
+ if (!fs31.existsSync(dir)) {
12612
+ fs31.mkdirSync(dir, { recursive: true });
12262
12613
  }
12263
- fs30.writeFileSync(fullPath, template, "utf-8");
12614
+ fs31.writeFileSync(fullPath, template, "utf-8");
12264
12615
  results.push({ type, filePath: relativePath, action: "created" });
12265
12616
  }
12266
12617
  if (type === "antigravity") {
@@ -12432,8 +12783,8 @@ var compactionContext_exports = {};
12432
12783
  __export(compactionContext_exports, {
12433
12784
  getCompactionContext: () => getCompactionContext
12434
12785
  });
12435
- import fs31 from "fs";
12436
- import path34 from "path";
12786
+ import fs32 from "fs";
12787
+ import path35 from "path";
12437
12788
  async function getCompactionContext() {
12438
12789
  const parts = [];
12439
12790
  try {
@@ -12446,8 +12797,8 @@ async function getCompactionContext() {
12446
12797
  } catch {
12447
12798
  }
12448
12799
  try {
12449
- const dbFile = path34.join(getProjectRoot(), ".kuma", "kuma.db");
12450
- if (fs31.existsSync(dbFile)) {
12800
+ const dbFile = path35.join(getProjectRoot(), ".kuma", "kuma.db");
12801
+ if (fs32.existsSync(dbFile)) {
12451
12802
  const { getDb: getDb2 } = await Promise.resolve().then(() => (init_kumaDb(), kumaDb_exports));
12452
12803
  const db = await getDb2();
12453
12804
  const stmt = db.prepare(
@@ -12473,9 +12824,9 @@ async function getCompactionContext() {
12473
12824
  } catch {
12474
12825
  }
12475
12826
  try {
12476
- const cpDir = path34.join(getProjectRoot(), ".kuma", "checkpoints");
12477
- if (fs31.existsSync(cpDir)) {
12478
- const cps = fs31.readdirSync(cpDir).slice(0, 3);
12827
+ const cpDir = path35.join(getProjectRoot(), ".kuma", "checkpoints");
12828
+ if (fs32.existsSync(cpDir)) {
12829
+ const cps = fs32.readdirSync(cpDir).slice(0, 3);
12479
12830
  if (cps.length > 0) parts.push(`Checkpoints: ${cps.join(", ")}`);
12480
12831
  }
12481
12832
  } catch {
@@ -12503,22 +12854,22 @@ __export(kumaDaemon_exports, {
12503
12854
  daemonStop: () => daemonStop,
12504
12855
  daemonTick: () => daemonTick
12505
12856
  });
12506
- import fs32 from "fs";
12507
- import path35 from "path";
12857
+ import fs33 from "fs";
12858
+ import path36 from "path";
12508
12859
  import { spawn } from "child_process";
12509
12860
  function paths(root) {
12510
12861
  const r = root || getProjectRoot();
12511
12862
  return {
12512
- pid: path35.join(r, PID_FILE),
12513
- status: path35.join(r, STATUS_FILE),
12514
- log: path35.join(r, LOG_FILE)
12863
+ pid: path36.join(r, PID_FILE),
12864
+ status: path36.join(r, STATUS_FILE),
12865
+ log: path36.join(r, LOG_FILE)
12515
12866
  };
12516
12867
  }
12517
12868
  function readPid(root) {
12518
12869
  try {
12519
12870
  const fp = paths(root).pid;
12520
- if (!fs32.existsSync(fp)) return null;
12521
- const pid = Number(fs32.readFileSync(fp, "utf-8").trim());
12871
+ if (!fs33.existsSync(fp)) return null;
12872
+ const pid = Number(fs33.readFileSync(fp, "utf-8").trim());
12522
12873
  return Number.isFinite(pid) && pid > 0 ? pid : null;
12523
12874
  } catch {
12524
12875
  return null;
@@ -12536,6 +12887,12 @@ async function daemonTick(root) {
12536
12887
  const r = root || getProjectRoot();
12537
12888
  const p = paths(r);
12538
12889
  const notes = [];
12890
+ try {
12891
+ const { ensureBackbone: ensureBackbone2, formatBackbone: formatBackbone2 } = await Promise.resolve().then(() => (init_mapBackbone(), mapBackbone_exports));
12892
+ const bb = await ensureBackbone2();
12893
+ if (bb) notes.push(formatBackbone2(bb));
12894
+ } catch {
12895
+ }
12539
12896
  try {
12540
12897
  const { syncModifiedFiles: syncModifiedFiles2 } = await Promise.resolve().then(() => (init_kumaCodeScanner(), kumaCodeScanner_exports));
12541
12898
  const scan = await syncModifiedFiles2(50);
@@ -12543,6 +12900,20 @@ async function daemonTick(root) {
12543
12900
  } catch (err) {
12544
12901
  notes.push(`map: skipped (${err})`);
12545
12902
  }
12903
+ try {
12904
+ const { getWorktreeChangedFiles: getWorktreeChangedFiles2, updateWorktreeDirty: updateWorktreeDirty2 } = await Promise.resolve().then(() => (init_mapBackbone(), mapBackbone_exports));
12905
+ const { scanCodebase: scanCodebase2 } = await Promise.resolve().then(() => (init_kumaCodeScanner(), kumaCodeScanner_exports));
12906
+ const dirty = getWorktreeChangedFiles2(r, 50);
12907
+ if (dirty.length > 0) {
12908
+ const res = await scanCodebase2({ include: dirty.map((d) => d.file), force: true, maxFiles: dirty.length });
12909
+ updateWorktreeDirty2(dirty.map((d) => d.file), r);
12910
+ notes.push(`worktree: ${dirty.length} dirty forced (${res.filesScanned} scanned)`);
12911
+ } else {
12912
+ updateWorktreeDirty2([], r);
12913
+ }
12914
+ } catch (err) {
12915
+ notes.push(`worktree: skipped (${err})`);
12916
+ }
12546
12917
  try {
12547
12918
  const { refreshPackageBriefs: refreshPackageBriefs2 } = await Promise.resolve().then(() => (init_packageBriefs(), packageBriefs_exports));
12548
12919
  const { count } = await refreshPackageBriefs2();
@@ -12558,6 +12929,12 @@ async function daemonTick(root) {
12558
12929
  } catch {
12559
12930
  notes.push("drift: skipped");
12560
12931
  }
12932
+ try {
12933
+ const { writeDriftReport: writeDriftReport2 } = await Promise.resolve().then(() => (init_kumaDriftDetector(), kumaDriftDetector_exports));
12934
+ const { items } = await writeDriftReport2();
12935
+ notes.push(`drift-report: ${items} item(s) \u2192 .kuma/drift.json`);
12936
+ } catch {
12937
+ }
12561
12938
  try {
12562
12939
  const { clearDirty: clearDirty2 } = await Promise.resolve().then(() => (init_cacheFreshness(), cacheFreshness_exports));
12563
12940
  clearDirty2();
@@ -12569,8 +12946,8 @@ async function daemonTick(root) {
12569
12946
  };
12570
12947
  try {
12571
12948
  let prev = {};
12572
- if (fs32.existsSync(p.status)) prev = JSON.parse(fs32.readFileSync(p.status, "utf-8"));
12573
- fs32.writeFileSync(p.status, JSON.stringify({ ...prev, ...status }, null, 2), "utf-8");
12949
+ if (fs33.existsSync(p.status)) prev = JSON.parse(fs33.readFileSync(p.status, "utf-8"));
12950
+ fs33.writeFileSync(p.status, JSON.stringify({ ...prev, ...status }, null, 2), "utf-8");
12574
12951
  } catch {
12575
12952
  }
12576
12953
  return notes.join(" \xB7 ");
@@ -12580,7 +12957,7 @@ async function runLoop(intervalMs) {
12580
12957
  const p = paths(r);
12581
12958
  const log = (msg) => {
12582
12959
  try {
12583
- fs32.appendFileSync(p.log, `${(/* @__PURE__ */ new Date()).toISOString()} ${msg}
12960
+ fs33.appendFileSync(p.log, `${(/* @__PURE__ */ new Date()).toISOString()} ${msg}
12584
12961
  `, "utf-8");
12585
12962
  } catch {
12586
12963
  }
@@ -12611,8 +12988,8 @@ async function daemonStart(intervalMs = DEFAULT_INTERVAL_MS, root) {
12611
12988
  });
12612
12989
  child.unref();
12613
12990
  try {
12614
- fs32.writeFileSync(p.pid, String(child.pid), "utf-8");
12615
- fs32.writeFileSync(
12991
+ fs33.writeFileSync(p.pid, String(child.pid), "utf-8");
12992
+ fs33.writeFileSync(
12616
12993
  p.status,
12617
12994
  JSON.stringify({ running: true, pid: child.pid, startedAt: Date.now(), lastRunAt: null, lastResult: null, intervalMs }, null, 2),
12618
12995
  "utf-8"
@@ -12628,7 +13005,7 @@ async function daemonStop(root) {
12628
13005
  if (!pid) return "\u{1F43B} Daemon not running (no pid file).";
12629
13006
  if (!isAlive(pid)) {
12630
13007
  try {
12631
- fs32.rmSync(p.pid, { force: true });
13008
+ fs33.rmSync(p.pid, { force: true });
12632
13009
  } catch {
12633
13010
  }
12634
13011
  return "\u{1F43B} Daemon pid file was stale \u2014 cleaned up (process already gone).";
@@ -12636,7 +13013,7 @@ async function daemonStop(root) {
12636
13013
  try {
12637
13014
  process.kill(pid, "SIGTERM");
12638
13015
  try {
12639
- fs32.rmSync(p.pid, { force: true });
13016
+ fs33.rmSync(p.pid, { force: true });
12640
13017
  } catch {
12641
13018
  }
12642
13019
  return `\u{1F43B} Daemon stopped (was pid ${pid}).`;
@@ -12650,7 +13027,7 @@ async function daemonStatus(root) {
12650
13027
  const pid = readPid(r);
12651
13028
  let status = { running: false, pid: null, startedAt: null, lastRunAt: null, lastResult: null, intervalMs: DEFAULT_INTERVAL_MS };
12652
13029
  try {
12653
- if (fs32.existsSync(p.status)) status = { ...status, ...JSON.parse(fs32.readFileSync(p.status, "utf-8")) };
13030
+ if (fs33.existsSync(p.status)) status = { ...status, ...JSON.parse(fs33.readFileSync(p.status, "utf-8")) };
12654
13031
  } catch {
12655
13032
  }
12656
13033
  const alive = pid !== null && isAlive(pid);
@@ -12685,19 +13062,19 @@ __export(agentDetector_exports, {
12685
13062
  getSkillPath: () => getSkillPath,
12686
13063
  skillExists: () => skillExists
12687
13064
  });
12688
- import fs33 from "fs";
12689
- import path36 from "path";
13065
+ import fs34 from "fs";
13066
+ import path37 from "path";
12690
13067
  function checkFile(root, filePath) {
12691
13068
  try {
12692
- return fs33.existsSync(path36.join(root, filePath));
13069
+ return fs34.existsSync(path37.join(root, filePath));
12693
13070
  } catch {
12694
13071
  return false;
12695
13072
  }
12696
13073
  }
12697
13074
  function checkDir(root, dirPath) {
12698
13075
  try {
12699
- const fullPath = path36.join(root, dirPath);
12700
- return fs33.existsSync(fullPath) && fs33.statSync(fullPath).isDirectory();
13076
+ const fullPath = path37.join(root, dirPath);
13077
+ return fs34.existsSync(fullPath) && fs34.statSync(fullPath).isDirectory();
12701
13078
  } catch {
12702
13079
  return false;
12703
13080
  }
@@ -12765,7 +13142,7 @@ function getAgentLabel(type) {
12765
13142
  function skillExists(type, projectRoot) {
12766
13143
  const root = projectRoot ?? getProjectRoot();
12767
13144
  const skillPath = getSkillPath(type);
12768
- return fs33.existsSync(path36.join(root, skillPath));
13145
+ return fs34.existsSync(path37.join(root, skillPath));
12769
13146
  }
12770
13147
  var AGENT_DETECTORS;
12771
13148
  var init_agentDetector = __esm({
@@ -13361,8 +13738,8 @@ init_kumaGraph();
13361
13738
  init_kumaMemory();
13362
13739
  init_kumaDriftDetector();
13363
13740
  init_pathValidator();
13364
- import fs22 from "fs";
13365
- import path25 from "path";
13741
+ import fs23 from "fs";
13742
+ import path26 from "path";
13366
13743
  var CONTEXT_ALIASES = {
13367
13744
  "research": "research",
13368
13745
  "search": "research",
@@ -13481,6 +13858,15 @@ async function handleCluster(_params) {
13481
13858
  async function handleInit(_params) {
13482
13859
  sessionMemory.setGoal(_params.goal || "Exploring project");
13483
13860
  sessionMemory.recordToolCall("kuma_context_init", {});
13861
+ let backboneNote = "";
13862
+ try {
13863
+ const { ensureBackbone: ensureBackbone2, formatBackbone: formatBackbone2 } = await Promise.resolve().then(() => (init_mapBackbone(), mapBackbone_exports));
13864
+ const bb = await ensureBackbone2();
13865
+ if (bb) backboneNote = `
13866
+ ${formatBackbone2(bb)}
13867
+ `;
13868
+ } catch {
13869
+ }
13484
13870
  const branch = sessionMemory.getCurrentBranch();
13485
13871
  const branchTag = branch ? ` [git: \`${branch}\`]` : "";
13486
13872
  const lines = [
@@ -13490,6 +13876,7 @@ async function handleInit(_params) {
13490
13876
  `\u{1F4C1} Project: ${getProjectRoot().split("/").pop() || "unknown"}${branchTag}`,
13491
13877
  ""
13492
13878
  ];
13879
+ if (backboneNote) lines.push(backboneNote);
13493
13880
  const branchTransition = sessionMemory.getBranchTransition();
13494
13881
  if (branchTransition?.switched) {
13495
13882
  lines.push(`\u{1F500} **Branch switched**: from \`${branchTransition.from}\` to \`${branchTransition.to}\`. Session context updated.`);
@@ -13689,6 +14076,14 @@ async function handleResearch(params, dirtySynced = 0) {
13689
14076
  } else lines.push(" \u23F3 No content hash available \u2014 will research fresh");
13690
14077
  lines.push("");
13691
14078
  lines.push("**Step 3/5: Graph Query + Code Scan**");
14079
+ try {
14080
+ if (params.scope && (params.scope.includes("/") || params.scope.includes("."))) {
14081
+ const { ensureMapped: ensureMapped2 } = await Promise.resolve().then(() => (init_mapBackbone(), mapBackbone_exports));
14082
+ const { filled } = await ensureMapped2([params.scope]);
14083
+ if (filled > 0) lines.push(` \u{1F5FA}\uFE0F Precision tier filled on demand: ${filled} file(s) indexed (no user action needed)`);
14084
+ }
14085
+ } catch {
14086
+ }
13692
14087
  try {
13693
14088
  const graphResult = await searchGraph(scope, 15);
13694
14089
  const graphLines = graphResult.split("\n");
@@ -13779,10 +14174,10 @@ async function handleHistory(params) {
13779
14174
  lines.push(traceFormatted);
13780
14175
  } else {
13781
14176
  try {
13782
- const { execSync: execSync10 } = await import("child_process");
14177
+ const { execSync: execSync11 } = await import("child_process");
13783
14178
  const { getProjectRoot: getProjectRoot2 } = await Promise.resolve().then(() => (init_pathValidator(), pathValidator_exports));
13784
14179
  const root = getProjectRoot2();
13785
- const gitHistory = execSync10(
14180
+ const gitHistory = execSync11(
13786
14181
  `git log -n 5 --pretty=format:" \u2022 %h (%ad) %s" --date=short -- "${target}"`,
13787
14182
  { cwd: root, encoding: "utf-8", timeout: 3e3, stdio: ["pipe", "pipe", "pipe"] }
13788
14183
  ).trim();
@@ -13814,7 +14209,7 @@ ${gitHistory}`);
13814
14209
  try {
13815
14210
  const { getDb: getDb2 } = await Promise.resolve().then(() => (init_kumaDb(), kumaDb_exports));
13816
14211
  const db = await getDb2();
13817
- const base = path25.basename(target);
14212
+ const base = path26.basename(target);
13818
14213
  const stmt = db.prepare(`
13819
14214
  SELECT description, last_verified_at FROM known_gotchas
13820
14215
  WHERE status = 'resolved' AND (file_path LIKE ? OR file_path LIKE ?)
@@ -13827,9 +14222,9 @@ ${gitHistory}`);
13827
14222
  if (resolved.length === 0) {
13828
14223
  try {
13829
14224
  const { getProjectRoot: getProjectRoot2 } = await Promise.resolve().then(() => (init_pathValidator(), pathValidator_exports));
13830
- const mdPath = path25.join(getProjectRoot2(), ".kuma", "KNOWN_GOTCHAS.md");
13831
- if (fs22.existsSync(mdPath)) {
13832
- const mdContent = fs22.readFileSync(mdPath, "utf-8");
14225
+ const mdPath = path26.join(getProjectRoot2(), ".kuma", "KNOWN_GOTCHAS.md");
14226
+ if (fs23.existsSync(mdPath)) {
14227
+ const mdContent = fs23.readFileSync(mdPath, "utf-8");
13833
14228
  const sections = mdContent.split(/^###\s+/m);
13834
14229
  for (const sec of sections) {
13835
14230
  const secLower = sec.toLowerCase();
@@ -13901,8 +14296,8 @@ init_kumaDb();
13901
14296
  init_kumaMemory();
13902
14297
  init_pathValidator();
13903
14298
  init_pathValidator();
13904
- import fs24 from "fs";
13905
- import path27 from "path";
14299
+ import fs25 from "fs";
14300
+ import path28 from "path";
13906
14301
  var MEMORY_ALIASES = {
13907
14302
  "decision": "decision",
13908
14303
  "adr": "decision",
@@ -14013,9 +14408,9 @@ async function handleResearchSave(params) {
14013
14408
  } catch {
14014
14409
  }
14015
14410
  try {
14016
- const researchDir = path27.join(getProjectRoot(), ".kuma", "research");
14017
- if (!fs24.existsSync(researchDir)) fs24.mkdirSync(researchDir, { recursive: true });
14018
- fs24.writeFileSync(path27.join(researchDir, `${scope}.json`), JSON.stringify(JSON.parse(record), null, 2), "utf-8");
14411
+ const researchDir = path28.join(getProjectRoot(), ".kuma", "research");
14412
+ if (!fs25.existsSync(researchDir)) fs25.mkdirSync(researchDir, { recursive: true });
14413
+ fs25.writeFileSync(path28.join(researchDir, `${scope}.json`), JSON.stringify(JSON.parse(record), null, 2), "utf-8");
14019
14414
  } catch {
14020
14415
  }
14021
14416
  sessionMemory.recordMemoryAction("research_save");
@@ -14211,9 +14606,9 @@ init_sessionMemory();
14211
14606
  init_pathValidator();
14212
14607
  init_sessionMemory();
14213
14608
  init_kumaShared();
14214
- import fs25 from "fs";
14215
- import path28 from "path";
14216
- import { execSync as execSync7 } from "child_process";
14609
+ import fs26 from "fs";
14610
+ import path29 from "path";
14611
+ import { execSync as execSync8 } from "child_process";
14217
14612
  var SCRIPT_PATCH_PATTERNS = [
14218
14613
  "writeFileSync",
14219
14614
  "writeFile",
@@ -14239,20 +14634,20 @@ function findPatchScripts(projectRoot) {
14239
14634
  const warnings = [];
14240
14635
  const recentFiles = scanRecentFiles(projectRoot);
14241
14636
  for (const file of recentFiles) {
14242
- const ext = path28.extname(file).toLowerCase();
14637
+ const ext = path29.extname(file).toLowerCase();
14243
14638
  if (!SCRIPT_EXTENSIONS.includes(ext)) continue;
14244
- const relativePath = path28.relative(projectRoot, file);
14639
+ const relativePath = path29.relative(projectRoot, file);
14245
14640
  if (relativePath.startsWith("src") || relativePath.startsWith("test") || relativePath.startsWith("node_modules") || relativePath.startsWith(".") || relativePath.startsWith(".kuma/scratch")) {
14246
14641
  continue;
14247
14642
  }
14248
14643
  try {
14249
- const content = fs25.readFileSync(file, "utf-8").toLowerCase();
14644
+ const content = fs26.readFileSync(file, "utf-8").toLowerCase();
14250
14645
  const matchedPattern = SCRIPT_PATCH_PATTERNS.find((p) => content.includes(p.toLowerCase()));
14251
14646
  if (matchedPattern) {
14252
14647
  warnings.push({
14253
14648
  severity: "high",
14254
14649
  pattern: "script-patching",
14255
- message: `Created script file that modifies other files: ${path28.basename(file)}`,
14650
+ message: `Created script file that modifies other files: ${path29.basename(file)}`,
14256
14651
  suggestion: "Use your native edit tools instead \u2014 targeted edits with auto-backup and rollback",
14257
14652
  evidence: `File: ${relativePath} contains '${matchedPattern}'`,
14258
14653
  filePath: relativePath
@@ -14286,15 +14681,15 @@ function detectBashGrepUsage() {
14286
14681
  function scanRecentFiles(projectRoot) {
14287
14682
  const recent = [];
14288
14683
  try {
14289
- const entries = fs25.readdirSync(projectRoot, { withFileTypes: true });
14684
+ const entries = fs26.readdirSync(projectRoot, { withFileTypes: true });
14290
14685
  const now = Date.now();
14291
14686
  const recentThreshold = 30 * 60 * 1e3;
14292
14687
  for (const entry of entries) {
14293
14688
  if (!entry.isFile()) continue;
14294
14689
  try {
14295
- const stat = fs25.statSync(path28.join(projectRoot, entry.name));
14690
+ const stat = fs26.statSync(path29.join(projectRoot, entry.name));
14296
14691
  if (now - stat.mtimeMs < recentThreshold || now - stat.ctimeMs < recentThreshold) {
14297
- recent.push(path28.join(projectRoot, entry.name));
14692
+ recent.push(path29.join(projectRoot, entry.name));
14298
14693
  }
14299
14694
  } catch {
14300
14695
  continue;
@@ -14307,7 +14702,7 @@ function scanRecentFiles(projectRoot) {
14307
14702
  function detectGitPatchScripts(projectRoot) {
14308
14703
  const warnings = [];
14309
14704
  try {
14310
- const statusStdout = execSync7("git status --porcelain", {
14705
+ const statusStdout = execSync8("git status --porcelain", {
14311
14706
  cwd: projectRoot,
14312
14707
  encoding: "utf-8",
14313
14708
  timeout: 3e3
@@ -14318,14 +14713,14 @@ function detectGitPatchScripts(projectRoot) {
14318
14713
  const prefix = line.substring(0, 2);
14319
14714
  if (prefix !== "??" && prefix !== "A ") continue;
14320
14715
  const file = line.substring(3).trim();
14321
- const ext = path28.extname(file).toLowerCase();
14716
+ const ext = path29.extname(file).toLowerCase();
14322
14717
  if (!SCRIPT_EXTENSIONS.includes(ext)) continue;
14323
14718
  const isRootLevel = !file.includes("/");
14324
14719
  const isScriptsDir = file.startsWith("scripts/") || file.startsWith("patches/");
14325
14720
  if (!isRootLevel && !isScriptsDir) continue;
14326
- const fullPath = path28.join(projectRoot, file);
14327
- if (fs25.existsSync(fullPath)) {
14328
- const content = fs25.readFileSync(fullPath, "utf-8").toLowerCase();
14721
+ const fullPath = path29.join(projectRoot, file);
14722
+ if (fs26.existsSync(fullPath)) {
14723
+ const content = fs26.readFileSync(fullPath, "utf-8").toLowerCase();
14329
14724
  const matchedPattern = SCRIPT_PATCH_PATTERNS.find((p) => content.includes(p.toLowerCase()));
14330
14725
  if (matchedPattern) {
14331
14726
  warnings.push({
@@ -14340,7 +14735,7 @@ function detectGitPatchScripts(projectRoot) {
14340
14735
  }
14341
14736
  }
14342
14737
  }
14343
- const deletedStdout = execSync7("git diff --name-only --diff-filter=D HEAD", {
14738
+ const deletedStdout = execSync8("git diff --name-only --diff-filter=D HEAD", {
14344
14739
  cwd: projectRoot,
14345
14740
  encoding: "utf-8",
14346
14741
  timeout: 3e3
@@ -14348,7 +14743,7 @@ function detectGitPatchScripts(projectRoot) {
14348
14743
  if (deletedStdout) {
14349
14744
  const deletedFiles = deletedStdout.split("\n").filter(Boolean);
14350
14745
  for (const file of deletedFiles) {
14351
- const ext = path28.extname(file).toLowerCase();
14746
+ const ext = path29.extname(file).toLowerCase();
14352
14747
  if (SCRIPT_EXTENSIONS.includes(ext)) {
14353
14748
  warnings.push({
14354
14749
  severity: "high",
@@ -14410,21 +14805,21 @@ function detectAllAntiPatterns() {
14410
14805
  // src/engine/contextSnapshot.ts
14411
14806
  init_sessionMemory();
14412
14807
  init_pathValidator();
14413
- import fs26 from "fs";
14414
- import path29 from "path";
14415
- import { execSync as execSync8 } from "child_process";
14808
+ import fs27 from "fs";
14809
+ import path30 from "path";
14810
+ import { execSync as execSync9 } from "child_process";
14416
14811
  var SNAPSHOT_DIR = "context-snapshots";
14417
14812
  function snapshotDir() {
14418
- return path29.join(getProjectRoot(), ".kuma", SNAPSHOT_DIR);
14813
+ return path30.join(getProjectRoot(), ".kuma", SNAPSHOT_DIR);
14419
14814
  }
14420
14815
  function ensureSnapshotDir() {
14421
14816
  const dir = snapshotDir();
14422
- if (!fs26.existsSync(dir)) {
14423
- fs26.mkdirSync(dir, { recursive: true });
14817
+ if (!fs27.existsSync(dir)) {
14818
+ fs27.mkdirSync(dir, { recursive: true });
14424
14819
  }
14425
14820
  }
14426
14821
  function snapshotFilePath(timestamp) {
14427
- return path29.join(snapshotDir(), `${timestamp}.json`);
14822
+ return path30.join(snapshotDir(), `${timestamp}.json`);
14428
14823
  }
14429
14824
  function saveSnapshot(goal) {
14430
14825
  try {
@@ -14445,7 +14840,7 @@ function saveSnapshot(goal) {
14445
14840
  hasConventions: !!summary.hasConventions
14446
14841
  };
14447
14842
  try {
14448
- fs26.writeFileSync(snapshotFilePath(Date.now()), JSON.stringify(snapshot, null, 2), "utf-8");
14843
+ fs27.writeFileSync(snapshotFilePath(Date.now()), JSON.stringify(snapshot, null, 2), "utf-8");
14449
14844
  } catch {
14450
14845
  }
14451
14846
  sessionMemory.recordToolCall("kuma_context", { action: "save", goal: snapshot.goal });
@@ -14484,7 +14879,7 @@ function formatSnapshot(snapshot) {
14484
14879
  function getGitDiffStat2() {
14485
14880
  try {
14486
14881
  const root = getProjectRoot();
14487
- const stdout = execSync8("git diff --stat", {
14882
+ const stdout = execSync9("git diff --stat", {
14488
14883
  cwd: root,
14489
14884
  encoding: "utf-8",
14490
14885
  timeout: 3e3
@@ -15238,14 +15633,14 @@ async function main() {
15238
15633
  console.error("");
15239
15634
  let killedCount = 0;
15240
15635
  try {
15241
- const path37 = await import("path");
15242
- const fs34 = await import("fs");
15243
- const lockDir = path37.resolve(process.cwd(), ".kuma/verifier.lock");
15244
- if (fs34.existsSync(lockDir)) {
15245
- const pidFile = path37.join(lockDir, "pid");
15246
- if (fs34.existsSync(pidFile)) {
15636
+ const path38 = await import("path");
15637
+ const fs35 = await import("fs");
15638
+ const lockDir = path38.resolve(process.cwd(), ".kuma/verifier.lock");
15639
+ if (fs35.existsSync(lockDir)) {
15640
+ const pidFile = path38.join(lockDir, "pid");
15641
+ if (fs35.existsSync(pidFile)) {
15247
15642
  try {
15248
- const pid = parseInt(fs34.readFileSync(pidFile, "utf-8"), 10);
15643
+ const pid = parseInt(fs35.readFileSync(pidFile, "utf-8"), 10);
15249
15644
  if (pid && pid !== process.pid) {
15250
15645
  try {
15251
15646
  process.kill(-pid, "SIGKILL");
@@ -15261,7 +15656,7 @@ async function main() {
15261
15656
  } catch {
15262
15657
  }
15263
15658
  }
15264
- fs34.rmSync(lockDir, { recursive: true, force: true });
15659
+ fs35.rmSync(lockDir, { recursive: true, force: true });
15265
15660
  }
15266
15661
  if (killedCount === 0) {
15267
15662
  console.error("\u2705 No running verifications found to kill.");
@@ -15269,25 +15664,25 @@ async function main() {
15269
15664
  } catch {
15270
15665
  }
15271
15666
  try {
15272
- const { execSync: execSync10 } = await import("child_process");
15667
+ const { execSync: execSync11 } = await import("child_process");
15273
15668
  try {
15274
- execSync10("pkill -f 'jest' 2>/dev/null || true");
15669
+ execSync11("pkill -f 'jest' 2>/dev/null || true");
15275
15670
  } catch {
15276
15671
  }
15277
15672
  try {
15278
- execSync10("pkill -f 'jest-worker' 2>/dev/null || true");
15673
+ execSync11("pkill -f 'jest-worker' 2>/dev/null || true");
15279
15674
  } catch {
15280
15675
  }
15281
15676
  try {
15282
- execSync10("pkill -f 'pnpm test' 2>/dev/null || true");
15677
+ execSync11("pkill -f 'pnpm test' 2>/dev/null || true");
15283
15678
  } catch {
15284
15679
  }
15285
15680
  try {
15286
- execSync10("pkill -f 'npm test' 2>/dev/null || true");
15681
+ execSync11("pkill -f 'npm test' 2>/dev/null || true");
15287
15682
  } catch {
15288
15683
  }
15289
15684
  try {
15290
- execSync10("pkill -f 'yarn test' 2>/dev/null || true");
15685
+ execSync11("pkill -f 'yarn test' 2>/dev/null || true");
15291
15686
  } catch {
15292
15687
  }
15293
15688
  console.error("\u2705 Killed orphaned test processes");
@@ -15436,6 +15831,12 @@ ${context}` : "";
15436
15831
  await refreshPackageBriefs2();
15437
15832
  } catch {
15438
15833
  }
15834
+ try {
15835
+ const { getWorktreeChangedFiles: getWorktreeChangedFiles2, updateWorktreeDirty: updateWorktreeDirty2 } = await Promise.resolve().then(() => (init_mapBackbone(), mapBackbone_exports));
15836
+ const { getProjectRoot: getProjectRoot2 } = await Promise.resolve().then(() => (init_pathValidator(), pathValidator_exports));
15837
+ updateWorktreeDirty2(getWorktreeChangedFiles2(getProjectRoot2(), 50).map((d) => d.file), getProjectRoot2());
15838
+ } catch {
15839
+ }
15439
15840
  try {
15440
15841
  const { clearDirty: clearDirty2 } = await Promise.resolve().then(() => (init_cacheFreshness(), cacheFreshness_exports));
15441
15842
  clearDirty2();
@@ -15507,8 +15908,14 @@ ${line}
15507
15908
  const proj = root.split("/").pop() || "unknown";
15508
15909
  const lines = [`\u{1F43B} [Kuma session brief] ${proj}`];
15509
15910
  try {
15510
- const { execSync: execSync10 } = await import("child_process");
15511
- const branch = execSync10("git rev-parse --abbrev-ref HEAD", {
15911
+ const { ensureBackbone: ensureBackbone2, formatBackbone: formatBackbone2 } = await Promise.resolve().then(() => (init_mapBackbone(), mapBackbone_exports));
15912
+ const bb = await ensureBackbone2();
15913
+ if (bb) lines.push(formatBackbone2(bb));
15914
+ } catch {
15915
+ }
15916
+ try {
15917
+ const { execSync: execSync11 } = await import("child_process");
15918
+ const branch = execSync11("git rev-parse --abbrev-ref HEAD", {
15512
15919
  cwd: root,
15513
15920
  encoding: "utf-8",
15514
15921
  timeout: 2e3,
@@ -15626,23 +16033,23 @@ ${line}
15626
16033
  });
15627
16034
  const output = formatInitResults(results);
15628
16035
  console.log(output);
15629
- const fs34 = await import("fs");
15630
- const path37 = await import("path");
15631
- const matchaSkills = path37.resolve(process.cwd(), "skills/matcha/SKILL.md");
15632
- const matchaAgents = path37.resolve(
16036
+ const fs35 = await import("fs");
16037
+ const path38 = await import("path");
16038
+ const matchaSkills = path38.resolve(process.cwd(), "skills/matcha/SKILL.md");
16039
+ const matchaAgents = path38.resolve(
15633
16040
  process.cwd(),
15634
16041
  ".agents/skills/matcha/SKILL.md"
15635
16042
  );
15636
- const matchaRootSkills = path37.resolve(
16043
+ const matchaRootSkills = path38.resolve(
15637
16044
  process.cwd(),
15638
16045
  "skills/matcha/SKILL.md"
15639
16046
  );
15640
- const matchaAgentsMd = path37.resolve(process.cwd(), "AGENTS.md");
15641
- const matchaWindsurfRules = path37.resolve(
16047
+ const matchaAgentsMd = path38.resolve(process.cwd(), "AGENTS.md");
16048
+ const matchaWindsurfRules = path38.resolve(
15642
16049
  process.cwd(),
15643
16050
  ".windsurf"
15644
16051
  );
15645
- if (fs34.existsSync(matchaSkills) || fs34.existsSync(matchaAgents) || fs34.existsSync(matchaRootSkills) || fs34.existsSync(matchaAgentsMd) || fs34.existsSync(matchaWindsurfRules)) {
16052
+ if (fs35.existsSync(matchaSkills) || fs35.existsSync(matchaAgents) || fs35.existsSync(matchaRootSkills) || fs35.existsSync(matchaAgentsMd) || fs35.existsSync(matchaWindsurfRules)) {
15646
16053
  console.error(
15647
16054
  "\n\u{1F375} Hey, I see matcha is installed \u2014 they pair well together!"
15648
16055
  );
@@ -15656,13 +16063,13 @@ ${line}
15656
16063
  (async () => {
15657
16064
  try {
15658
16065
  const { generateInitMdContent: generateInitMdContent2 } = await Promise.resolve().then(() => (init_init(), init_exports));
15659
- const fs34 = await import("fs");
15660
- const path37 = await import("path");
15661
- const initMdPath = path37.resolve(process.cwd(), ".kuma/init.md");
15662
- if (!fs34.existsSync(initMdPath)) {
15663
- const kumaDir = path37.dirname(initMdPath);
15664
- if (!fs34.existsSync(kumaDir)) fs34.mkdirSync(kumaDir, { recursive: true });
15665
- fs34.writeFileSync(initMdPath, generateInitMdContent2(), "utf-8");
16066
+ const fs35 = await import("fs");
16067
+ const path38 = await import("path");
16068
+ const initMdPath = path38.resolve(process.cwd(), ".kuma/init.md");
16069
+ if (!fs35.existsSync(initMdPath)) {
16070
+ const kumaDir = path38.dirname(initMdPath);
16071
+ if (!fs35.existsSync(kumaDir)) fs35.mkdirSync(kumaDir, { recursive: true });
16072
+ fs35.writeFileSync(initMdPath, generateInitMdContent2(), "utf-8");
15666
16073
  console.error(`[${SERVER_NAME}] Auto-generated .kuma/init.md`);
15667
16074
  }
15668
16075
  } catch (err) {
@@ -15673,8 +16080,8 @@ ${line}
15673
16080
  try {
15674
16081
  const { detectAgent: detectAgent2, getSkillPath: getSkillPath2, getAgentLabel: getAgentLabel2 } = await Promise.resolve().then(() => (init_agentDetector(), agentDetector_exports));
15675
16082
  const { generateSkill: generateSkill2, getSecondaryFiles: getSecondaryFiles2 } = await Promise.resolve().then(() => (init_skillGenerator(), skillGenerator_exports));
15676
- const fs34 = await import("fs");
15677
- const path37 = await import("path");
16083
+ const fs35 = await import("fs");
16084
+ const path38 = await import("path");
15678
16085
  const detection = detectAgent2();
15679
16086
  if (!detection.primary) {
15680
16087
  console.error(`[${SERVER_NAME}] No AI agent detected \u2014 skipping auto-skill creation`);
@@ -15682,22 +16089,22 @@ ${line}
15682
16089
  }
15683
16090
  const agentType = detection.primary;
15684
16091
  const skillPath = getSkillPath2(agentType);
15685
- const fullPath = path37.resolve(process.cwd(), skillPath);
15686
- if (fs34.existsSync(fullPath)) {
16092
+ const fullPath = path38.resolve(process.cwd(), skillPath);
16093
+ if (fs35.existsSync(fullPath)) {
15687
16094
  console.error(`[${SERVER_NAME}] Skill exists for ${getAgentLabel2(agentType)} \u2014 skipping`);
15688
16095
  return;
15689
16096
  }
15690
- const dir = path37.dirname(fullPath);
15691
- if (!fs34.existsSync(dir)) fs34.mkdirSync(dir, { recursive: true });
15692
- fs34.writeFileSync(fullPath, generateSkill2(agentType), "utf-8");
16097
+ const dir = path38.dirname(fullPath);
16098
+ if (!fs35.existsSync(dir)) fs35.mkdirSync(dir, { recursive: true });
16099
+ fs35.writeFileSync(fullPath, generateSkill2(agentType), "utf-8");
15693
16100
  console.error(`[${SERVER_NAME}] Auto-created ${skillPath} for ${getAgentLabel2(agentType)}`);
15694
16101
  const secondaryFiles = getSecondaryFiles2(agentType);
15695
16102
  for (const sf of secondaryFiles) {
15696
- const sfPath = path37.resolve(process.cwd(), sf.path);
15697
- const sfDir = path37.dirname(sfPath);
15698
- if (!fs34.existsSync(sfPath)) {
15699
- if (!fs34.existsSync(sfDir)) fs34.mkdirSync(sfDir, { recursive: true });
15700
- fs34.writeFileSync(sfPath, sf.content, "utf-8");
16103
+ const sfPath = path38.resolve(process.cwd(), sf.path);
16104
+ const sfDir = path38.dirname(sfPath);
16105
+ if (!fs35.existsSync(sfPath)) {
16106
+ if (!fs35.existsSync(sfDir)) fs35.mkdirSync(sfDir, { recursive: true });
16107
+ fs35.writeFileSync(sfPath, sf.content, "utf-8");
15701
16108
  console.error(`[${SERVER_NAME}] Auto-created ${sf.path}`);
15702
16109
  }
15703
16110
  }