@plumpslabs/kuma 2.4.14 → 2.4.15

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 +868 -519
  2. package/package.json +1 -1
  3. package/plugin.json +1 -1
package/dist/index.js CHANGED
@@ -1220,8 +1220,8 @@ async function runDoctor() {
1220
1220
  } catch {
1221
1221
  }
1222
1222
  try {
1223
- const { execSync: execSync9 } = await import("child_process");
1224
- const psOutput = execSync9(
1223
+ const { execSync: execSync10 } = await import("child_process");
1224
+ const psOutput = execSync10(
1225
1225
  `ps -eo pid,ppid,command | grep -E "(jest|pnpm test|npm test|yarn test)" | grep -v grep | head -10`,
1226
1226
  { encoding: "utf-8", timeout: 5e3 }
1227
1227
  ).trim();
@@ -3251,6 +3251,18 @@ function parseFallbackRegex(filePath, content) {
3251
3251
  if (impMatch && (impMatch[1].startsWith(".") || impMatch[1].startsWith("/"))) {
3252
3252
  result.imports.push({ source: impMatch[1], symbols: [], isDefault: false });
3253
3253
  }
3254
+ if (!fnMatch && !clsMatch) {
3255
+ const callRe = /([a-zA-Z_][a-zA-Z0-9_]*)\s*\(/g;
3256
+ let m;
3257
+ let count = 0;
3258
+ while ((m = callRe.exec(line)) !== null && count < 5) {
3259
+ const name = m[1];
3260
+ if (!isJsBuiltin(name) && !result.calledSymbols.includes(name)) {
3261
+ result.calledSymbols.push(name);
3262
+ count++;
3263
+ }
3264
+ }
3265
+ }
3254
3266
  }
3255
3267
  return result;
3256
3268
  }
@@ -4577,6 +4589,124 @@ var init_workspaceIntelligence = __esm({
4577
4589
  }
4578
4590
  });
4579
4591
 
4592
+ // src/engine/symbolReach.ts
4593
+ var symbolReach_exports = {};
4594
+ __export(symbolReach_exports, {
4595
+ formatReachability: () => formatReachability,
4596
+ symbolReachability: () => symbolReachability
4597
+ });
4598
+ import fs9 from "fs";
4599
+ import path11 from "path";
4600
+ import { execSync as execSync4 } from "child_process";
4601
+ async function graphReach(symbol, limit) {
4602
+ const rows = [];
4603
+ try {
4604
+ const { getDb: getDb2 } = await Promise.resolve().then(() => (init_kumaDb(), kumaDb_exports));
4605
+ const db = await getDb2();
4606
+ const symStmt = db.prepare(
4607
+ `SELECT id, file_path FROM nodes WHERE type IN ('function','class','method') AND (name = ? OR name LIKE ?) LIMIT 5`
4608
+ );
4609
+ symStmt.bind([symbol, `%::${symbol}`]);
4610
+ const symIds = [];
4611
+ while (symStmt.step()) {
4612
+ const r = symStmt.getAsObject();
4613
+ symIds.push({ id: r.id, file: r.file_path });
4614
+ }
4615
+ symStmt.free();
4616
+ if (symIds.length === 0) return [];
4617
+ for (const s of symIds) {
4618
+ const cStmt = db.prepare(
4619
+ `SELECT DISTINCT n_src.file_path as fp FROM edges e JOIN nodes n_src ON n_src.id = e.source_id WHERE e.target_id = ? AND e.type = 'calls' LIMIT 20`
4620
+ );
4621
+ cStmt.bind([s.id]);
4622
+ const callers = /* @__PURE__ */ new Set();
4623
+ while (cStmt.step()) {
4624
+ const fp = cStmt.getAsObject().fp;
4625
+ if (fp) callers.add(fp);
4626
+ }
4627
+ cStmt.free();
4628
+ for (const fp of [...callers, s.file]) {
4629
+ const tStmt = db.prepare(
4630
+ `SELECT DISTINCT n.file_path as tfp FROM edges e JOIN nodes n ON n.id = e.source_id WHERE e.type = 'tests' AND (e.target_id LIKE ? OR e.target_id LIKE ?) LIMIT 5`
4631
+ );
4632
+ tStmt.bind([`%${fp}%`, `%${s.id}%`]);
4633
+ while (tStmt.step()) {
4634
+ const tfp = tStmt.getAsObject().tfp;
4635
+ if (tfp && !rows.some((r) => r.test === tfp)) {
4636
+ rows.push({ test: tfp, via: fp, evidence: `${tfp} tests ${fp} (graph edge)` });
4637
+ }
4638
+ if (rows.length >= limit) break;
4639
+ }
4640
+ tStmt.free();
4641
+ if (rows.length >= limit) break;
4642
+ }
4643
+ if (rows.length >= limit) break;
4644
+ }
4645
+ } catch {
4646
+ }
4647
+ return rows;
4648
+ }
4649
+ function ripgrepReach(symbol, root, limit) {
4650
+ const rows = [];
4651
+ try {
4652
+ const out = execSync4(
4653
+ `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
+ { cwd: root, encoding: "utf-8", timeout: 8e3, maxBuffer: 256 * 1024 }
4655
+ ).trim();
4656
+ if (!out) return [];
4657
+ const callers = /* @__PURE__ */ new Set();
4658
+ for (const line of out.split("\n")) {
4659
+ const m = line.match(/^([^:]+):(\d+):(.*)$/);
4660
+ if (!m) continue;
4661
+ const [, fp, ln, code] = m;
4662
+ if (new RegExp(`\\b${symbol}\\s*\\(`).test(code)) callers.add(`${fp}:${ln}`);
4663
+ }
4664
+ for (const c of [...callers].slice(0, BERBEDA)) {
4665
+ const [fp] = c.split(":");
4666
+ const dir = path11.dirname(fp);
4667
+ const stem = path11.basename(fp, path11.extname(fp)).split(/[-_.]/)[0];
4668
+ try {
4669
+ const dirFull = path11.join(root, dir);
4670
+ if (!fs9.existsSync(dirFull)) continue;
4671
+ for (const f of fs9.readdirSync(dirFull)) {
4672
+ if (!/(\.test\.|\.spec\.|_test\.)/i.test(f)) continue;
4673
+ const low = f.toLowerCase();
4674
+ if (low.includes(stem.toLowerCase()) || low.includes(symbol.toLowerCase())) {
4675
+ const rel = path11.join(dir, f);
4676
+ if (!rows.some((r) => r.test === rel)) {
4677
+ rows.push({ test: rel, via: fp, evidence: `${rel} sibling-matches caller ${fp} (called at ${c})` });
4678
+ }
4679
+ }
4680
+ if (rows.length >= limit) break;
4681
+ }
4682
+ } catch {
4683
+ }
4684
+ if (rows.length >= limit) break;
4685
+ }
4686
+ } catch {
4687
+ }
4688
+ return rows;
4689
+ }
4690
+ async function symbolReachability(symbol, limit = 10, root) {
4691
+ const g = await graphReach(symbol, limit);
4692
+ if (g.length > 0) return { tier: 1, rows: g };
4693
+ return { tier: 2, rows: ripgrepReach(symbol, root || getProjectRoot(), limit) };
4694
+ }
4695
+ function formatReachability(symbol, tier, rows) {
4696
+ if (rows.length === 0) return `\u{1F50E} Reachability \`${symbol}\` (tier ${tier}): no tests reach this symbol.`;
4697
+ const lines = [`\u{1F50E} Reachability \`${symbol}\` (tier ${tier}, ${rows.length} test(s)):`];
4698
+ for (const r of rows.slice(0, 5)) lines.push(` \u2022 \`${r.test}\` via \`${r.via}\` \u2014 ${r.evidence}`);
4699
+ return lines.join("\n");
4700
+ }
4701
+ var BERBEDA;
4702
+ var init_symbolReach = __esm({
4703
+ "src/engine/symbolReach.ts"() {
4704
+ "use strict";
4705
+ init_pathValidator();
4706
+ BERBEDA = 10;
4707
+ }
4708
+ });
4709
+
4580
4710
  // src/engine/testHistory.ts
4581
4711
  var testHistory_exports = {};
4582
4712
  __export(testHistory_exports, {
@@ -4692,17 +4822,17 @@ __export(impactAnalysis_exports, {
4692
4822
  classifyDiffShape: () => classifyDiffShape,
4693
4823
  getIndexerStatus: () => getIndexerStatus
4694
4824
  });
4695
- import fs9 from "fs";
4696
- import path11 from "path";
4697
- import { execSync as execSync4 } from "child_process";
4825
+ import fs10 from "fs";
4826
+ import path12 from "path";
4827
+ import { execSync as execSync5 } from "child_process";
4698
4828
  import fastGlob3 from "fast-glob";
4699
4829
  function extOf(target) {
4700
- const base = path11.basename(target);
4830
+ const base = path12.basename(target);
4701
4831
  const dot = base.lastIndexOf(".");
4702
4832
  return dot > 0 ? base.slice(dot).toLowerCase() : "";
4703
4833
  }
4704
4834
  function isExampleOrDocName(target) {
4705
- const base = path11.basename(target).toLowerCase();
4835
+ const base = path12.basename(target).toLowerCase();
4706
4836
  return base.endsWith(".example") || base.startsWith(".env") || base.endsWith(".md") || base.endsWith(".txt") || base.endsWith(".rst") || base === "license" || base.startsWith("license.");
4707
4837
  }
4708
4838
  function classifyDiffShape(target, root) {
@@ -4715,7 +4845,7 @@ function classifyDiffShape(target, root) {
4715
4845
  }
4716
4846
  try {
4717
4847
  const cwd = root || getProjectRoot();
4718
- const diff = execSync4(`git diff --unified=0 -- "${target}"`, {
4848
+ const diff = execSync5(`git diff --unified=0 -- "${target}"`, {
4719
4849
  cwd,
4720
4850
  encoding: "utf-8",
4721
4851
  timeout: 4e3,
@@ -4735,7 +4865,7 @@ function classifyDiffShape(target, root) {
4735
4865
  return { shape: "runtime-code", detail: "runtime code change" };
4736
4866
  }
4737
4867
  async function findImportingFiles(targetFile, root) {
4738
- const normTarget = normalizeScope(path11.normalize(targetFile)) || path11.normalize(targetFile);
4868
+ const normTarget = normalizeScope(path12.normalize(targetFile)) || path12.normalize(targetFile);
4739
4869
  try {
4740
4870
  const db = await getDb();
4741
4871
  const targetFileId = `file::${normTarget}`;
@@ -4774,8 +4904,8 @@ async function findImportingFiles(targetFile, root) {
4774
4904
  }
4775
4905
  } catch {
4776
4906
  }
4777
- const baseName = path11.basename(normTarget, path11.extname(normTarget));
4778
- const relTarget = path11.isAbsolute(normTarget) ? path11.relative(root, normTarget) : normTarget;
4907
+ const baseName = path12.basename(normTarget, path12.extname(normTarget));
4908
+ const relTarget = path12.isAbsolute(normTarget) ? path12.relative(root, normTarget) : normTarget;
4779
4909
  try {
4780
4910
  const files = await fastGlob3(
4781
4911
  ["**/*.{ts,tsx,js,jsx,mjs,cjs,py,go,rs}"],
@@ -4788,14 +4918,14 @@ async function findImportingFiles(targetFile, root) {
4788
4918
  const dependents = [];
4789
4919
  const evidence = [];
4790
4920
  const importRegex = new RegExp(
4791
- `(?:import|from|require\\s*\\(|export\\s+.*from)\\s*['"][^'"]*\\b${baseName}(?:\\.[a-zA-Z0-9]+)?['"]`,
4921
+ `(?:import|from|require\\s*\\()[\\w{}*,.\\s]*['"][^'"]*\\b${baseName}(?:\\.[a-zA-Z0-9]+)?['"]`,
4792
4922
  "i"
4793
4923
  );
4794
4924
  for (const f of files) {
4795
- if (path11.normalize(f) === path11.normalize(relTarget)) continue;
4796
- const fullPath = path11.join(root, f);
4925
+ if (path12.normalize(f) === path12.normalize(relTarget)) continue;
4926
+ const fullPath = path12.join(root, f);
4797
4927
  try {
4798
- const content = fs9.readFileSync(fullPath, "utf-8");
4928
+ const content = fs10.readFileSync(fullPath, "utf-8");
4799
4929
  const lines = content.split("\n");
4800
4930
  const hitIdx = lines.findIndex((l) => importRegex.test(l));
4801
4931
  if (hitIdx >= 0) {
@@ -4811,7 +4941,7 @@ async function findImportingFiles(targetFile, root) {
4811
4941
  }
4812
4942
  }
4813
4943
  async function findRelatedTests(targetFile, root, owningPackage, additionalDependents = [], exactOnly = false) {
4814
- const normTarget = normalizeScope(path11.normalize(targetFile)) || path11.normalize(targetFile);
4944
+ const normTarget = normalizeScope(path12.normalize(targetFile)) || path12.normalize(targetFile);
4815
4945
  try {
4816
4946
  const db = await getDb();
4817
4947
  const targetFileId = `file::${normTarget}`;
@@ -4835,13 +4965,13 @@ async function findRelatedTests(targetFile, root, owningPackage, additionalDepen
4835
4965
  }
4836
4966
  } catch {
4837
4967
  }
4838
- const baseName = path11.basename(normTarget, path11.extname(normTarget));
4968
+ const baseName = path12.basename(normTarget, path12.extname(normTarget));
4839
4969
  const testFiles = [];
4840
4970
  const stems = /* @__PURE__ */ new Set();
4841
4971
  if (baseName) stems.add(baseName);
4842
4972
  if (!exactOnly) {
4843
4973
  for (const dep of additionalDependents.slice(0, 3)) {
4844
- const depBase = path11.basename(dep, path11.extname(dep));
4974
+ const depBase = path12.basename(dep, path12.extname(dep));
4845
4975
  if (depBase) stems.add(depBase);
4846
4976
  }
4847
4977
  }
@@ -4877,12 +5007,12 @@ async function findRelatedTests(targetFile, root, owningPackage, additionalDepen
4877
5007
  );
4878
5008
  }
4879
5009
  const pkgTests = await fastGlob3(pkgPatterns, {
4880
- cwd: path11.join(root, owningPackage.path),
5010
+ cwd: path12.join(root, owningPackage.path),
4881
5011
  ignore: ["**/node_modules/**", "**/dist/**"],
4882
5012
  onlyFiles: true
4883
5013
  });
4884
5014
  for (const pt of pkgTests) {
4885
- const fullRel = path11.join(owningPackage.path, pt);
5015
+ const fullRel = path12.join(owningPackage.path, pt);
4886
5016
  if (!testFiles.includes(fullRel)) {
4887
5017
  testFiles.push(fullRel);
4888
5018
  }
@@ -4981,6 +5111,20 @@ async function calculateBlastRadius(target, options = {}) {
4981
5111
  const nonRuntime = diffShape !== "runtime-code";
4982
5112
  const affectedTests = await findRelatedTests(target, root, owningPackage, directDependents, nonRuntime);
4983
5113
  let testReasons = /* @__PURE__ */ new Map();
5114
+ if (targetType === "symbol") {
5115
+ try {
5116
+ const { symbolReachability: symbolReachability2 } = await Promise.resolve().then(() => (init_symbolReach(), symbolReach_exports));
5117
+ const reach = await symbolReachability2(target, 10, root);
5118
+ for (const r of reach.rows) {
5119
+ if (!affectedTests.includes(r.test)) {
5120
+ affectedTests.push(r.test);
5121
+ testReasons.set(r.test, `reachability tier ${reach.tier}: ${r.evidence.substring(0, 80)}`);
5122
+ }
5123
+ evidence.push(r.evidence);
5124
+ }
5125
+ } catch {
5126
+ }
5127
+ }
4984
5128
  try {
4985
5129
  const { rankTestsByHistory: rankTestsByHistory2 } = await Promise.resolve().then(() => (init_testHistory(), testHistory_exports));
4986
5130
  const ranked = await rankTestsByHistory2(target, affectedTests);
@@ -6195,27 +6339,27 @@ async function codebaseSearchFallback(query, limit = 20) {
6195
6339
  if (results.length >= limit || depth > MAX_WALK_DEPTH) return;
6196
6340
  let entries = [];
6197
6341
  try {
6198
- entries = fs32.readdirSync(dir);
6342
+ entries = fs34.readdirSync(dir);
6199
6343
  } catch {
6200
6344
  return;
6201
6345
  }
6202
6346
  for (const entry of entries) {
6203
6347
  if (entry.startsWith(".") || entry === "node_modules" || entry === "dist" || entry === "build") continue;
6204
- const full = path35.join(dir, entry);
6348
+ const full = path37.join(dir, entry);
6205
6349
  try {
6206
- const stat = fs32.statSync(full);
6350
+ const stat = fs34.statSync(full);
6207
6351
  if (stat.isDirectory()) {
6208
6352
  walk2(full, depth + 1);
6209
6353
  } else if (entry.toLowerCase().includes(query.toLowerCase())) {
6210
- results.push(path35.relative(root, full));
6354
+ results.push(path37.relative(root, full));
6211
6355
  }
6212
6356
  } catch {
6213
6357
  }
6214
6358
  }
6215
6359
  };
6216
6360
  var walk = walk2;
6217
- const fs32 = await import("fs");
6218
- const path35 = await import("path");
6361
+ const fs34 = await import("fs");
6362
+ const path37 = await import("path");
6219
6363
  const root = process.cwd();
6220
6364
  const results = [];
6221
6365
  const MAX_WALK_DEPTH = 8;
@@ -6348,9 +6492,9 @@ ${summary}`;
6348
6492
  }
6349
6493
  async function codebaseImpactFallback(target) {
6350
6494
  try {
6351
- const { execSync: execSync9 } = await import("child_process");
6495
+ const { execSync: execSync10 } = await import("child_process");
6352
6496
  const root = process.cwd();
6353
- const grepResult = execSync9(
6497
+ const grepResult = execSync10(
6354
6498
  `grep -rn ${grepIncludeFlags()} --include="*.json" --include="*.md" -l "${target.replace(/"/g, '\\"')}" . 2>/dev/null | grep -v node_modules | grep -v .git | grep -v dist | grep -v .kuma | head -50`,
6355
6499
  { cwd: root, encoding: "utf-8", timeout: 5e3, maxBuffer: 256 * 1024 }
6356
6500
  ).trim();
@@ -6496,9 +6640,9 @@ __export(kumaShared_exports, {
6496
6640
  isReadTool: () => isReadTool,
6497
6641
  isTestTool: () => isTestTool
6498
6642
  });
6499
- import { execSync as execSync5 } from "child_process";
6500
- import fs10 from "fs";
6501
- import path12 from "path";
6643
+ import { execSync as execSync6 } from "child_process";
6644
+ import fs11 from "fs";
6645
+ import path13 from "path";
6502
6646
  function isEditTool(toolName) {
6503
6647
  const n = (toolName || "").toLowerCase();
6504
6648
  return n.includes("edit") || n.includes("write") || n.includes("patch") || n.includes("apply") || n.includes("replace");
@@ -6536,7 +6680,7 @@ function getSessionStats(inputGoal) {
6536
6680
  function getGitDiffStat(timeout = 3e3) {
6537
6681
  try {
6538
6682
  const root = getProjectRoot();
6539
- return execSync5("git diff --stat", {
6683
+ return execSync6("git diff --stat", {
6540
6684
  cwd: root,
6541
6685
  encoding: "utf-8",
6542
6686
  timeout
@@ -6549,7 +6693,7 @@ function getUncommittedFiles(timeout = 3e3) {
6549
6693
  const files = /* @__PURE__ */ new Set();
6550
6694
  try {
6551
6695
  const root = getProjectRoot();
6552
- const porcelain = execSync5("git status --porcelain", {
6696
+ const porcelain = execSync6("git status --porcelain", {
6553
6697
  cwd: root,
6554
6698
  encoding: "utf-8",
6555
6699
  timeout,
@@ -6568,17 +6712,17 @@ function getBranchCommittedFiles(timeout = 5e3) {
6568
6712
  let base = "";
6569
6713
  try {
6570
6714
  const root = getProjectRoot();
6571
- const branch = execSync5("git rev-parse --abbrev-ref HEAD", {
6715
+ const branch = execSync6("git rev-parse --abbrev-ref HEAD", {
6572
6716
  cwd: root,
6573
6717
  encoding: "utf-8",
6574
6718
  timeout,
6575
6719
  stdio: ["pipe", "pipe", "pipe"]
6576
6720
  }).trim();
6577
- const baseRef = execSync5(
6721
+ const baseRef = execSync6(
6578
6722
  `git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null || echo origin/${branch === "main" || branch === "master" ? "HEAD" : "main"}`,
6579
6723
  { cwd: root, encoding: "utf-8", timeout, stdio: ["pipe", "pipe", "pipe"] }
6580
6724
  ).trim().replace("refs/remotes/", "");
6581
- const mergeBase = execSync5(`git merge-base HEAD ${baseRef} 2>/dev/null || git rev-list --max-parents=0 HEAD`, {
6725
+ const mergeBase = execSync6(`git merge-base HEAD ${baseRef} 2>/dev/null || git rev-list --max-parents=0 HEAD`, {
6582
6726
  cwd: root,
6583
6727
  encoding: "utf-8",
6584
6728
  timeout,
@@ -6586,7 +6730,7 @@ function getBranchCommittedFiles(timeout = 5e3) {
6586
6730
  }).trim().split("\n")[0];
6587
6731
  base = baseRef;
6588
6732
  if (mergeBase) {
6589
- const out = execSync5(`git diff --name-only ${mergeBase} HEAD`, {
6733
+ const out = execSync6(`git diff --name-only ${mergeBase} HEAD`, {
6590
6734
  cwd: root,
6591
6735
  encoding: "utf-8",
6592
6736
  timeout,
@@ -6604,10 +6748,10 @@ function hasVerificationEvidence(toolCalls) {
6604
6748
  }
6605
6749
  function hasVerificationInHookLog(hours = 24) {
6606
6750
  try {
6607
- const fp = path12.join(getProjectRoot(), ".kuma", "injections.jsonl");
6608
- if (!fs10.existsSync(fp)) return false;
6751
+ const fp = path13.join(getProjectRoot(), ".kuma", "injections.jsonl");
6752
+ if (!fs11.existsSync(fp)) return false;
6609
6753
  const cutoff = Date.now() - hours * 60 * 60 * 1e3;
6610
- const lines = fs10.readFileSync(fp, "utf-8").split("\n");
6754
+ const lines = fs11.readFileSync(fp, "utf-8").split("\n");
6611
6755
  for (const line of lines) {
6612
6756
  if (!line.trim()) continue;
6613
6757
  try {
@@ -6710,7 +6854,7 @@ function detectTestWeakening(files, root) {
6710
6854
  for (const f of files) {
6711
6855
  if (!TEST_FILE_PATTERN.test(f)) continue;
6712
6856
  try {
6713
- const diff = execSync5(`git diff --unified=0 -- "${f}"`, {
6857
+ const diff = execSync6(`git diff --unified=0 -- "${f}"`, {
6714
6858
  cwd,
6715
6859
  encoding: "utf-8",
6716
6860
  timeout: 4e3,
@@ -6749,19 +6893,19 @@ __export(kumaMemory_exports, {
6749
6893
  scoreMemoryRelevance: () => scoreMemoryRelevance,
6750
6894
  shouldRecordDecision: () => shouldRecordDecision
6751
6895
  });
6752
- import fs11 from "fs";
6753
- import path13 from "path";
6896
+ import fs12 from "fs";
6897
+ import path14 from "path";
6754
6898
  function scoreMemoryRelevance(context, limit = 5) {
6755
6899
  const results = [];
6756
- const kumaDir = path13.join(getProjectRoot(), MEMORY_DIR);
6757
- if (!fs11.existsSync(kumaDir)) return [];
6900
+ const kumaDir = path14.join(getProjectRoot(), MEMORY_DIR);
6901
+ if (!fs12.existsSync(kumaDir)) return [];
6758
6902
  const terms = Array.from(new Set(context.toLowerCase().split(/[\s/._-]+/).filter((w) => w.length > 2)));
6759
6903
  if (terms.length === 0) return [];
6760
6904
  try {
6761
- const files = fs11.readdirSync(kumaDir).filter((f) => f.endsWith(".md"));
6905
+ const files = fs12.readdirSync(kumaDir).filter((f) => f.endsWith(".md"));
6762
6906
  for (const file of files) {
6763
6907
  try {
6764
- const content = fs11.readFileSync(path13.join(kumaDir, file), "utf-8");
6908
+ const content = fs12.readFileSync(path14.join(kumaDir, file), "utf-8");
6765
6909
  const lower = content.toLowerCase();
6766
6910
  let matchCount = 0;
6767
6911
  for (const term of terms) {
@@ -6943,8 +7087,8 @@ __export(cacheFreshness_exports, {
6943
7087
  isStale: () => isStale,
6944
7088
  markDirty: () => markDirty
6945
7089
  });
6946
- import fs12 from "fs";
6947
- import path14 from "path";
7090
+ import fs13 from "fs";
7091
+ import path15 from "path";
6948
7092
  function isStale(savedAtMs, ttlMs, nowMs = Date.now()) {
6949
7093
  if (!savedAtMs) return true;
6950
7094
  return nowMs - savedAtMs > ttlMs;
@@ -6957,13 +7101,13 @@ function formatAge(savedAtMs, nowMs = Date.now()) {
6957
7101
  return `${Math.floor(s / 86400)}d`;
6958
7102
  }
6959
7103
  function dirtyPath() {
6960
- return path14.join(getProjectRoot(), DIRTY_FILE);
7104
+ return path15.join(getProjectRoot(), DIRTY_FILE);
6961
7105
  }
6962
7106
  function loadDirty() {
6963
7107
  try {
6964
7108
  const fp = dirtyPath();
6965
- if (fs12.existsSync(fp)) {
6966
- const parsed = JSON.parse(fs12.readFileSync(fp, "utf-8"));
7109
+ if (fs13.existsSync(fp)) {
7110
+ const parsed = JSON.parse(fs13.readFileSync(fp, "utf-8"));
6967
7111
  if (parsed && typeof parsed === "object") return parsed;
6968
7112
  }
6969
7113
  } catch {
@@ -6973,14 +7117,14 @@ function loadDirty() {
6973
7117
  function markDirty(filePath) {
6974
7118
  try {
6975
7119
  const fp = dirtyPath();
6976
- const dir = path14.dirname(fp);
6977
- if (!fs12.existsSync(dir)) fs12.mkdirSync(dir, { recursive: true });
7120
+ const dir = path15.dirname(fp);
7121
+ if (!fs13.existsSync(dir)) fs13.mkdirSync(dir, { recursive: true });
6978
7122
  const dirty = loadDirty();
6979
7123
  dirty[filePath] = Date.now();
6980
7124
  const keys = Object.keys(dirty).sort((a, b) => dirty[b] - dirty[a]).slice(0, 200);
6981
7125
  const bounded = {};
6982
7126
  for (const k of keys) bounded[k] = dirty[k];
6983
- fs12.writeFileSync(fp, JSON.stringify(bounded), "utf-8");
7127
+ fs13.writeFileSync(fp, JSON.stringify(bounded), "utf-8");
6984
7128
  } catch {
6985
7129
  }
6986
7130
  }
@@ -6990,7 +7134,7 @@ function getDirtyFiles() {
6990
7134
  function clearDirty() {
6991
7135
  try {
6992
7136
  const fp = dirtyPath();
6993
- if (fs12.existsSync(fp)) fs12.rmSync(fp, { force: true });
7137
+ if (fs13.existsSync(fp)) fs13.rmSync(fp, { force: true });
6994
7138
  } catch {
6995
7139
  }
6996
7140
  }
@@ -7010,8 +7154,8 @@ var codeReuseEngine_exports = {};
7010
7154
  __export(codeReuseEngine_exports, {
7011
7155
  findReusableSymbols: () => findReusableSymbols
7012
7156
  });
7013
- import path15 from "path";
7014
- import fs13 from "fs";
7157
+ import path16 from "path";
7158
+ import fs14 from "fs";
7015
7159
  async function findReusableSymbols(query, scope) {
7016
7160
  const cleanQuery = query.trim().toLowerCase();
7017
7161
  const searchTokens = cleanQuery.replace(/[^a-zA-Z0-9_\s]/g, " ").split(/\s+/).filter((t) => t.length >= 2);
@@ -7134,7 +7278,7 @@ function detectRecommendedUtilDirectory() {
7134
7278
  "utils"
7135
7279
  ];
7136
7280
  for (const c of candidates) {
7137
- if (fs13.existsSync(path15.resolve(root, c))) {
7281
+ if (fs14.existsSync(path16.resolve(root, c))) {
7138
7282
  return c;
7139
7283
  }
7140
7284
  }
@@ -7153,7 +7297,7 @@ var domainClusterEngine_exports = {};
7153
7297
  __export(domainClusterEngine_exports, {
7154
7298
  buildSubsystemClusters: () => buildSubsystemClusters
7155
7299
  });
7156
- import path16 from "path";
7300
+ import path17 from "path";
7157
7301
  async function buildSubsystemClusters() {
7158
7302
  const db = await getDb();
7159
7303
  const fileStmt = db.prepare(`
@@ -7230,7 +7374,7 @@ async function buildSubsystemClusters() {
7230
7374
  for (const [cKey, files] of clusterFileMap.entries()) {
7231
7375
  for (const f of files) {
7232
7376
  fileToCluster.set(f, cKey);
7233
- fileToCluster.set(path16.normalize(f), cKey);
7377
+ fileToCluster.set(path17.normalize(f), cKey);
7234
7378
  }
7235
7379
  }
7236
7380
  const clusterInteractions = /* @__PURE__ */ new Map();
@@ -7238,8 +7382,8 @@ async function buildSubsystemClusters() {
7238
7382
  const srcFile = extractFilePathFromNodeId(e.source);
7239
7383
  const tgtFile = extractFilePathFromNodeId(e.target);
7240
7384
  if (!srcFile || !tgtFile) continue;
7241
- const srcCluster = fileToCluster.get(srcFile) || fileToCluster.get(path16.normalize(srcFile));
7242
- const tgtCluster = fileToCluster.get(tgtFile) || fileToCluster.get(path16.normalize(tgtFile));
7385
+ const srcCluster = fileToCluster.get(srcFile) || fileToCluster.get(path17.normalize(srcFile));
7386
+ const tgtCluster = fileToCluster.get(tgtFile) || fileToCluster.get(path17.normalize(tgtFile));
7243
7387
  if (srcCluster && tgtCluster && srcCluster !== tgtCluster) {
7244
7388
  const pairKey = `${srcCluster}->${tgtCluster}`;
7245
7389
  const stats = clusterInteractions.get(pairKey) || { calls: 0, imports: 0 };
@@ -7261,13 +7405,13 @@ async function buildSubsystemClusters() {
7261
7405
  const clusterId = nodeId("feature_domain", cKey);
7262
7406
  const name = formatClusterName(cKey);
7263
7407
  const role = inferSubsystemRole(cKey, files);
7264
- const entrypoints = files.filter((f) => /index|main|server|app|engine|root/i.test(path16.basename(f))).slice(0, 3);
7408
+ const entrypoints = files.filter((f) => /index|main|server|app|engine|root/i.test(path17.basename(f))).slice(0, 3);
7265
7409
  if (entrypoints.length === 0 && files.length > 0) {
7266
7410
  entrypoints.push(files[0]);
7267
7411
  }
7268
7412
  const allSyms = [];
7269
7413
  for (const f of files) {
7270
- const syms = fileSymbols.get(f) || fileSymbols.get(path16.normalize(f)) || [];
7414
+ const syms = fileSymbols.get(f) || fileSymbols.get(path17.normalize(f)) || [];
7271
7415
  for (const s of syms) {
7272
7416
  if (!allSyms.includes(s)) allSyms.push(s);
7273
7417
  }
@@ -7446,7 +7590,7 @@ function inferSubsystemRole(key, files) {
7446
7590
  if (k.includes("util") || k.includes("common")) {
7447
7591
  return "Shared path validation, configuration loading, and platform detection helpers.";
7448
7592
  }
7449
- return `Core subsystem handling ${files.slice(0, 3).map((f) => path16.basename(f)).join(", ")}.`;
7593
+ return `Core subsystem handling ${files.slice(0, 3).map((f) => path17.basename(f)).join(", ")}.`;
7450
7594
  }
7451
7595
  function inferTypedVerb(sourceKey, targetKey, _stats) {
7452
7596
  const src = sourceKey.toLowerCase();
@@ -7525,18 +7669,18 @@ __export(domainRules_exports, {
7525
7669
  readLayer: () => readLayer,
7526
7670
  writeLayer: () => writeLayer
7527
7671
  });
7528
- import fs14 from "fs";
7529
- import path17 from "path";
7672
+ import fs15 from "fs";
7673
+ import path18 from "path";
7530
7674
  function layerFilePath(layer) {
7531
- return path17.join(getProjectRoot(), ".kuma", LAYER_FILES[layer].filename);
7675
+ return path18.join(getProjectRoot(), ".kuma", LAYER_FILES[layer].filename);
7532
7676
  }
7533
7677
  function ensureLayerFile(layer) {
7534
7678
  const fp = layerFilePath(layer);
7535
- if (!fs14.existsSync(fp)) {
7679
+ if (!fs15.existsSync(fp)) {
7536
7680
  const template = layer === "arch_flow" ? ARCH_FLOW_TEMPLATE : GOTCHAS_TEMPLATE;
7537
- const dir = path17.dirname(fp);
7538
- if (!fs14.existsSync(dir)) fs14.mkdirSync(dir, { recursive: true });
7539
- fs14.writeFileSync(fp, template, "utf-8");
7681
+ const dir = path18.dirname(fp);
7682
+ if (!fs15.existsSync(dir)) fs15.mkdirSync(dir, { recursive: true });
7683
+ fs15.writeFileSync(fp, template, "utf-8");
7540
7684
  console.error(`[DomainRules] Auto-created ${LAYER_FILES[layer].filename}`);
7541
7685
  }
7542
7686
  return fp;
@@ -7544,7 +7688,7 @@ function ensureLayerFile(layer) {
7544
7688
  function readLayer(layer) {
7545
7689
  try {
7546
7690
  const fp = ensureLayerFile(layer);
7547
- return fs14.readFileSync(fp, "utf-8");
7691
+ return fs15.readFileSync(fp, "utf-8");
7548
7692
  } catch (err) {
7549
7693
  return `Error reading ${layer}: ${err}`;
7550
7694
  }
@@ -7552,7 +7696,7 @@ function readLayer(layer) {
7552
7696
  function writeLayer(layer, content) {
7553
7697
  try {
7554
7698
  const fp = ensureLayerFile(layer);
7555
- fs14.writeFileSync(fp, content, "utf-8");
7699
+ fs15.writeFileSync(fp, content, "utf-8");
7556
7700
  const label = LAYER_FILES[layer].label;
7557
7701
  sessionMemory.recordToolCall("kuma_memory", { action: `write_${layer}` });
7558
7702
  return `\u2705 **${label}** updated successfully.`;
@@ -7563,9 +7707,9 @@ function writeLayer(layer, content) {
7563
7707
  function appendToLayer(layer, entry) {
7564
7708
  try {
7565
7709
  const fp = ensureLayerFile(layer);
7566
- const existing = fs14.readFileSync(fp, "utf-8");
7710
+ const existing = fs15.readFileSync(fp, "utf-8");
7567
7711
  const newContent = existing.trimEnd() + "\n\n" + entry.trim() + "\n";
7568
- fs14.writeFileSync(fp, newContent, "utf-8");
7712
+ fs15.writeFileSync(fp, newContent, "utf-8");
7569
7713
  return `\u2705 Entry added to **${LAYER_FILES[layer].label}**.`;
7570
7714
  } catch (err) {
7571
7715
  return `\u274C Failed to append: ${err}`;
@@ -7575,7 +7719,7 @@ function getActiveGotchas() {
7575
7719
  const results = [];
7576
7720
  try {
7577
7721
  const fp = ensureLayerFile("gotcha");
7578
- const content = fs14.readFileSync(fp, "utf-8");
7722
+ const content = fs15.readFileSync(fp, "utf-8");
7579
7723
  const lines = content.split("\n");
7580
7724
  let currentSection = "";
7581
7725
  let currentFilePath = "";
@@ -7611,9 +7755,9 @@ function getActiveGotchas() {
7611
7755
  function checkFileGotchas(filePath) {
7612
7756
  const gotchas = getActiveGotchas();
7613
7757
  const warnings = [];
7614
- const base = path17.basename(filePath);
7758
+ const base = path18.basename(filePath);
7615
7759
  for (const g of gotchas) {
7616
- const gBase = path17.basename(g.filePath);
7760
+ const gBase = path18.basename(g.filePath);
7617
7761
  if (filePath.includes(g.filePath) || g.filePath.includes(filePath) || base && gBase && base === gBase) {
7618
7762
  const icon = g.severity === "critical" ? "\u{1F534}" : g.severity === "high" ? "\u{1F7E0}" : g.severity === "medium" ? "\u{1F7E1}" : "\u{1F7E2}";
7619
7763
  warnings.push(`${icon} **Gotcha**: ${g.description} (${g.severity})`);
@@ -7713,8 +7857,8 @@ __export(kumaInject_exports, {
7713
7857
  parseHookInput: () => parseHookInput,
7714
7858
  trackFileEditLoop: () => trackFileEditLoop
7715
7859
  });
7716
- import fs15 from "fs";
7717
- import path18 from "path";
7860
+ import fs16 from "fs";
7861
+ import path19 from "path";
7718
7862
  function hashFileContent(filePath) {
7719
7863
  return hashFile(filePath);
7720
7864
  }
@@ -7725,10 +7869,10 @@ function isGotchaFresh(storedHash, currentHash) {
7725
7869
  }
7726
7870
  async function getFreshGotchasForFile(filePath, limit = 5, includeStale = false) {
7727
7871
  const root = getProjectRoot();
7728
- const base = path18.basename(filePath);
7872
+ const base = path19.basename(filePath);
7729
7873
  try {
7730
- const dbFile = path18.join(root, ".kuma", "kuma.db");
7731
- if (fs15.existsSync(dbFile)) {
7874
+ const dbFile = path19.join(root, ".kuma", "kuma.db");
7875
+ if (fs16.existsSync(dbFile)) {
7732
7876
  const { getDb: getDb2 } = await Promise.resolve().then(() => (init_kumaDb(), kumaDb_exports));
7733
7877
  const db = await getDb2();
7734
7878
  const stmt = db.prepare(`
@@ -7769,11 +7913,11 @@ async function getFreshGotchasForFile(filePath, limit = 5, includeStale = false)
7769
7913
  } catch {
7770
7914
  }
7771
7915
  try {
7772
- if (!fs15.existsSync(path18.join(root, ".kuma"))) return [];
7916
+ if (!fs16.existsSync(path19.join(root, ".kuma"))) return [];
7773
7917
  const { getActiveGotchas: getActiveGotchas2 } = await Promise.resolve().then(() => (init_domainRules(), domainRules_exports));
7774
7918
  const allGotchas = getActiveGotchas2();
7775
7919
  const matched = allGotchas.filter(
7776
- (g) => g.filePath.includes(filePath) || filePath.includes(g.filePath) || base && path18.basename(g.filePath) === base
7920
+ (g) => g.filePath.includes(filePath) || filePath.includes(g.filePath) || base && path19.basename(g.filePath) === base
7777
7921
  );
7778
7922
  if (matched.length > 0) {
7779
7923
  return matched.slice(0, limit).map((g) => ({
@@ -7792,8 +7936,8 @@ async function getFreshGotchasForFile(filePath, limit = 5, includeStale = false)
7792
7936
  async function getFileTrace(filePath, limit = 8) {
7793
7937
  try {
7794
7938
  const root = getProjectRoot();
7795
- const dbFile = path18.join(root, ".kuma", "kuma.db");
7796
- if (!fs15.existsSync(dbFile)) return [];
7939
+ const dbFile = path19.join(root, ".kuma", "kuma.db");
7940
+ if (!fs16.existsSync(dbFile)) return [];
7797
7941
  const { getDb: getDb2 } = await Promise.resolve().then(() => (init_kumaDb(), kumaDb_exports));
7798
7942
  const db = await getDb2();
7799
7943
  const stmt = db.prepare(`
@@ -7803,7 +7947,7 @@ async function getFileTrace(filePath, limit = 8) {
7803
7947
  ORDER BY cl.created_at DESC
7804
7948
  LIMIT ?
7805
7949
  `);
7806
- stmt.bind([`%${path18.basename(filePath)}%`, limit]);
7950
+ stmt.bind([`%${path19.basename(filePath)}%`, limit]);
7807
7951
  const rows = [];
7808
7952
  while (stmt.step()) rows.push(stmt.getAsObject());
7809
7953
  stmt.free();
@@ -7821,7 +7965,7 @@ async function getFileTrace(filePath, limit = 8) {
7821
7965
  function formatFileTrace(entries, filePath) {
7822
7966
  if (entries.length === 0) return "";
7823
7967
  const lines = [
7824
- `\u{1F570}\uFE0F **Why is ${path18.basename(filePath)} written this way?** \u2014 ${entries.length} change(s) recorded:`
7968
+ `\u{1F570}\uFE0F **Why is ${path19.basename(filePath)} written this way?** \u2014 ${entries.length} change(s) recorded:`
7825
7969
  ];
7826
7970
  for (const e of entries) {
7827
7971
  const date = new Date((e.createdAt || 0) * 1e3).toLocaleDateString("en-US", {
@@ -7837,12 +7981,12 @@ function formatFileTrace(entries, filePath) {
7837
7981
  async function getDecisionsForFile(filePath, limit = 3) {
7838
7982
  const decisions = [];
7839
7983
  const root = getProjectRoot();
7840
- const base = path18.basename(filePath);
7984
+ const base = path19.basename(filePath);
7841
7985
  const baseWithoutExt = base.replace(/\.[^.]+$/, "");
7842
7986
  try {
7843
- const decisionsMdPath = path18.join(root, ".kuma", "memories", "decisions.md");
7844
- if (fs15.existsSync(decisionsMdPath)) {
7845
- const content = fs15.readFileSync(decisionsMdPath, "utf-8");
7987
+ const decisionsMdPath = path19.join(root, ".kuma", "memories", "decisions.md");
7988
+ if (fs16.existsSync(decisionsMdPath)) {
7989
+ const content = fs16.readFileSync(decisionsMdPath, "utf-8");
7846
7990
  const sections = content.split(/^##\s+/m);
7847
7991
  for (const section of sections) {
7848
7992
  if (!section.trim() || section.startsWith("# ")) continue;
@@ -7947,13 +8091,13 @@ async function getRelevantContext(filePath, goal) {
7947
8091
  if (traceStr) parts.push(traceStr);
7948
8092
  try {
7949
8093
  const root = getProjectRoot();
7950
- if (fs15.existsSync(path18.join(root, ".kuma", "kuma.db"))) {
8094
+ if (fs16.existsSync(path19.join(root, ".kuma", "kuma.db"))) {
7951
8095
  const { getDb: getDb2 } = await Promise.resolve().then(() => (init_kumaDb(), kumaDb_exports));
7952
8096
  const db = await getDb2();
7953
8097
  const stmt = db.prepare(
7954
8098
  `SELECT COUNT(*) FROM known_gotchas WHERE status = 'resolved' AND file_path LIKE ?`
7955
8099
  );
7956
- stmt.bind([`%${path18.basename(filePath)}%`]);
8100
+ stmt.bind([`%${path19.basename(filePath)}%`]);
7957
8101
  const found = stmt.step();
7958
8102
  const count = found ? Number(stmt.getAsObject()["COUNT(*)"]) : 0;
7959
8103
  stmt.free();
@@ -7964,7 +8108,7 @@ async function getRelevantContext(filePath, goal) {
7964
8108
  } catch {
7965
8109
  }
7966
8110
  if (gotchas.length > 0) {
7967
- const scopeHint = path18.basename(path18.dirname(filePath)) || "current change";
8111
+ const scopeHint = path19.basename(path19.dirname(filePath)) || "current change";
7968
8112
  parts.push(
7969
8113
  `\u2705 AFTER editing, verify: kuma_safety({ action: "verify", scope: "${scopeHint}" })`
7970
8114
  );
@@ -7980,11 +8124,11 @@ async function getRelevantContext(filePath, goal) {
7980
8124
  async function getFileSummary2(filePath) {
7981
8125
  try {
7982
8126
  const root = getProjectRoot();
7983
- const dbFile = path18.join(root, ".kuma", "kuma.db");
7984
- if (!fs15.existsSync(dbFile)) return null;
8127
+ const dbFile = path19.join(root, ".kuma", "kuma.db");
8128
+ if (!fs16.existsSync(dbFile)) return null;
7985
8129
  const { getDb: getDb2 } = await Promise.resolve().then(() => (init_kumaDb(), kumaDb_exports));
7986
8130
  const db = await getDb2();
7987
- const base = path18.basename(filePath);
8131
+ const base = path19.basename(filePath);
7988
8132
  const stmt = db.prepare(`
7989
8133
  SELECT
7990
8134
  (SELECT COUNT(*) FROM known_gotchas WHERE status = 'active' AND (file_path = ? OR file_path LIKE ?)) as active_gotchas,
@@ -8018,9 +8162,9 @@ function parseHookInput(raw) {
8018
8162
  const root = data && typeof data === "object" ? data : {};
8019
8163
  const ti = root.tool_input && typeof root.tool_input === "object" ? root.tool_input : {};
8020
8164
  const args = root.args && typeof root.args === "object" ? root.args : {};
8021
- const paths = /* @__PURE__ */ new Set();
8165
+ const paths2 = /* @__PURE__ */ new Set();
8022
8166
  const add = (p) => {
8023
- if (typeof p === "string" && p.trim()) paths.add(p.trim());
8167
+ if (typeof p === "string" && p.trim()) paths2.add(p.trim());
8024
8168
  };
8025
8169
  add(ti.file_path);
8026
8170
  add(ti.new_file_path);
@@ -8038,7 +8182,7 @@ function parseHookInput(raw) {
8038
8182
  add(args.file);
8039
8183
  const cmd = (typeof ti.command === "string" ? ti.command : void 0) ?? (typeof root.command === "string" ? root.command : void 0) ?? (typeof root.commandline === "string" ? root.commandline : void 0) ?? (typeof args.command === "string" ? args.command : void 0);
8040
8184
  const goal = (typeof ti.goal === "string" ? ti.goal : void 0) ?? (typeof root.goal === "string" ? root.goal : void 0);
8041
- const out = { filePaths: [...paths] };
8185
+ const out = { filePaths: [...paths2] };
8042
8186
  if (goal) out.goal = goal;
8043
8187
  if (cmd) out.command = cmd;
8044
8188
  return out;
@@ -8076,9 +8220,9 @@ async function getCommandContext(command) {
8076
8220
  }
8077
8221
  function loadHookState(root) {
8078
8222
  try {
8079
- const fp = path18.join(root, HOOK_STATE_FILE);
8080
- if (fs15.existsSync(fp)) {
8081
- return JSON.parse(fs15.readFileSync(fp, "utf-8"));
8223
+ const fp = path19.join(root, HOOK_STATE_FILE);
8224
+ if (fs16.existsSync(fp)) {
8225
+ return JSON.parse(fs16.readFileSync(fp, "utf-8"));
8082
8226
  }
8083
8227
  } catch {
8084
8228
  }
@@ -8086,10 +8230,10 @@ function loadHookState(root) {
8086
8230
  }
8087
8231
  function saveHookState(root, state) {
8088
8232
  try {
8089
- const fp = path18.join(root, HOOK_STATE_FILE);
8090
- const dir = path18.dirname(fp);
8091
- if (!fs15.existsSync(dir)) fs15.mkdirSync(dir, { recursive: true });
8092
- fs15.writeFileSync(fp, JSON.stringify(state), "utf-8");
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");
8093
8237
  } catch {
8094
8238
  }
8095
8239
  }
@@ -8123,7 +8267,7 @@ async function trackFileEditLoop(filePath) {
8123
8267
  saveHookState(root, state);
8124
8268
  if (recorded) {
8125
8269
  try {
8126
- if (!fs15.existsSync(path18.join(root, ".kuma", "kuma.db"))) return entry.count;
8270
+ if (!fs16.existsSync(path19.join(root, ".kuma", "kuma.db"))) return entry.count;
8127
8271
  const { addGotcha: addGotcha2 } = await Promise.resolve().then(() => (init_kumaGotchas(), kumaGotchas_exports));
8128
8272
  await addGotcha2({
8129
8273
  filePath,
@@ -8177,8 +8321,8 @@ __export(kumaGotchas_exports, {
8177
8321
  syncGotchasToDb: () => syncGotchasToDb,
8178
8322
  tokenizeForSimilarity: () => tokenizeForSimilarity
8179
8323
  });
8180
- import fs16 from "fs";
8181
- import path19 from "path";
8324
+ import fs17 from "fs";
8325
+ import path20 from "path";
8182
8326
  async function ensureGotchasSchema() {
8183
8327
  const db = await getDb();
8184
8328
  db.exec(`
@@ -8600,8 +8744,8 @@ async function getActiveGotchasForCommand(command) {
8600
8744
  }
8601
8745
  async function recordInjection(params) {
8602
8746
  try {
8603
- const fp = path19.join(getProjectRoot(), ".kuma", "injections.jsonl");
8604
- if (!fs16.existsSync(path19.dirname(fp))) fs16.mkdirSync(path19.dirname(fp), { recursive: true });
8747
+ const fp = path20.join(getProjectRoot(), ".kuma", "injections.jsonl");
8748
+ if (!fs17.existsSync(path20.dirname(fp))) fs17.mkdirSync(path20.dirname(fp), { recursive: true });
8605
8749
  const line = JSON.stringify({
8606
8750
  filePath: params.filePath || null,
8607
8751
  command: params.command || null,
@@ -8610,16 +8754,16 @@ async function recordInjection(params) {
8610
8754
  // conservative estimate: avoided re-research / re-discovery
8611
8755
  at: Date.now()
8612
8756
  });
8613
- fs16.appendFileSync(fp, line + "\n", "utf-8");
8757
+ fs17.appendFileSync(fp, line + "\n", "utf-8");
8614
8758
  } catch {
8615
8759
  }
8616
8760
  }
8617
8761
  function getInjectionStats(hours = 24) {
8618
8762
  try {
8619
- const fp = path19.join(getProjectRoot(), ".kuma", "injections.jsonl");
8620
- if (!fs16.existsSync(fp)) return { count: 0, savedMs: 0 };
8763
+ const fp = path20.join(getProjectRoot(), ".kuma", "injections.jsonl");
8764
+ if (!fs17.existsSync(fp)) return { count: 0, savedMs: 0 };
8621
8765
  const cutoff = Date.now() - hours * 60 * 60 * 1e3;
8622
- const lines = fs16.readFileSync(fp, "utf-8").split("\n");
8766
+ const lines = fs17.readFileSync(fp, "utf-8").split("\n");
8623
8767
  let count = 0;
8624
8768
  let savedMs = 0;
8625
8769
  for (const line of lines) {
@@ -8677,9 +8821,9 @@ async function getGotchasByStatus(status, limit = 20) {
8677
8821
  }
8678
8822
  function syncGotchaStatusToMarkdown(targetPaths, newStatus, reason) {
8679
8823
  try {
8680
- const mdPath = path19.join(getProjectRoot(), ".kuma", "KNOWN_GOTCHAS.md");
8681
- if (!fs16.existsSync(mdPath)) return false;
8682
- const content = fs16.readFileSync(mdPath, "utf-8");
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");
8683
8827
  const lines = content.split("\n");
8684
8828
  const normalizedTargets = targetPaths.map((p) => p.trim().toLowerCase()).filter(Boolean);
8685
8829
  if (normalizedTargets.length === 0) return false;
@@ -8696,9 +8840,9 @@ function syncGotchaStatusToMarkdown(targetPaths, newStatus, reason) {
8696
8840
  modified = true;
8697
8841
  }
8698
8842
  const headingFile = headingMatch[1].trim().toLowerCase();
8699
- const headingBase = path19.basename(headingFile);
8843
+ const headingBase = path20.basename(headingFile);
8700
8844
  inMatchingSection = normalizedTargets.some(
8701
- (t) => headingFile.includes(t) || t.includes(headingFile) || headingBase === t || headingBase === path19.basename(t)
8845
+ (t) => headingFile.includes(t) || t.includes(headingFile) || headingBase === t || headingBase === path20.basename(t)
8702
8846
  );
8703
8847
  sectionHasStatus = false;
8704
8848
  outputLines.push(line);
@@ -8720,7 +8864,7 @@ function syncGotchaStatusToMarkdown(targetPaths, newStatus, reason) {
8720
8864
  modified = true;
8721
8865
  }
8722
8866
  if (modified) {
8723
- fs16.writeFileSync(mdPath, outputLines.join("\n"), "utf-8");
8867
+ fs17.writeFileSync(mdPath, outputLines.join("\n"), "utf-8");
8724
8868
  }
8725
8869
  return modified;
8726
8870
  } catch {
@@ -8861,24 +9005,24 @@ var kumaMaintenance_exports = {};
8861
9005
  __export(kumaMaintenance_exports, {
8862
9006
  maybeRunAutoCleanup: () => maybeRunAutoCleanup
8863
9007
  });
8864
- import fs17 from "fs";
8865
- import path20 from "path";
9008
+ import fs18 from "fs";
9009
+ import path21 from "path";
8866
9010
  async function maybeRunAutoCleanup() {
8867
9011
  try {
8868
9012
  const root = getProjectRoot();
8869
- const stateFile = path20.join(root, GC_STATE_FILE);
9013
+ const stateFile = path21.join(root, GC_STATE_FILE);
8870
9014
  const now = Date.now();
8871
9015
  let lastRun = 0;
8872
- if (fs17.existsSync(stateFile)) {
9016
+ if (fs18.existsSync(stateFile)) {
8873
9017
  try {
8874
- lastRun = JSON.parse(fs17.readFileSync(stateFile, "utf-8")).lastRun || 0;
9018
+ lastRun = JSON.parse(fs18.readFileSync(stateFile, "utf-8")).lastRun || 0;
8875
9019
  } catch {
8876
9020
  lastRun = 0;
8877
9021
  }
8878
9022
  }
8879
9023
  if (now - lastRun < GC_INTERVAL_MS) return "";
8880
- fs17.mkdirSync(path20.dirname(stateFile), { recursive: true });
8881
- fs17.writeFileSync(stateFile, JSON.stringify({ lastRun: now }), "utf-8");
9024
+ fs18.mkdirSync(path21.dirname(stateFile), { recursive: true });
9025
+ fs18.writeFileSync(stateFile, JSON.stringify({ lastRun: now }), "utf-8");
8882
9026
  const { syncGotchasToDb: syncGotchasToDb2 } = await Promise.resolve().then(() => (init_kumaGotchas(), kumaGotchas_exports));
8883
9027
  await syncGotchasToDb2();
8884
9028
  const { runGarbageCollection: runGarbageCollection2 } = await Promise.resolve().then(() => (init_kumaDb(), kumaDb_exports));
@@ -8914,22 +9058,22 @@ __export(kumaPathRules_exports, {
8914
9058
  loadPathRules: () => loadPathRules,
8915
9059
  matchRulePath: () => matchRulePath
8916
9060
  });
8917
- import fs18 from "fs";
8918
- import path21 from "path";
9061
+ import fs19 from "fs";
9062
+ import path22 from "path";
8919
9063
  function rulesDir() {
8920
- return path21.join(getProjectRoot(), RULES_DIR);
9064
+ return path22.join(getProjectRoot(), RULES_DIR);
8921
9065
  }
8922
9066
  function ensureRulesDir() {
8923
9067
  try {
8924
9068
  const dir = rulesDir();
8925
- if (!fs18.existsSync(dir)) fs18.mkdirSync(dir, { recursive: true });
9069
+ if (!fs19.existsSync(dir)) fs19.mkdirSync(dir, { recursive: true });
8926
9070
  } catch {
8927
9071
  }
8928
9072
  }
8929
9073
  function parseRuleFile(filePath) {
8930
9074
  try {
8931
- const raw = fs18.readFileSync(filePath, "utf-8");
8932
- const id = path21.basename(filePath, ".md");
9075
+ const raw = fs19.readFileSync(filePath, "utf-8");
9076
+ const id = path22.basename(filePath, ".md");
8933
9077
  const fm = raw.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/);
8934
9078
  if (!fm) {
8935
9079
  return { id, description: id, paths: ["*"], content: raw.trim(), filePath };
@@ -8937,15 +9081,15 @@ function parseRuleFile(filePath) {
8937
9081
  const meta = fm[1];
8938
9082
  const body = fm[2].trim();
8939
9083
  const description = meta.match(/description:\s*(.+)/)?.[1]?.trim() || id;
8940
- const paths = [];
9084
+ const paths2 = [];
8941
9085
  const pathSection = meta.match(/paths:\s*\r?\n([\s\S]*?)(?=\r?\n\S|$)/);
8942
9086
  if (pathSection) {
8943
9087
  for (const line of pathSection[1].split("\n")) {
8944
9088
  const m = line.match(/^\s*-\s*['"]?([^'"]+)['"]?\s*$/);
8945
- if (m) paths.push(m[1].trim());
9089
+ if (m) paths2.push(m[1].trim());
8946
9090
  }
8947
9091
  }
8948
- return { id, description, paths: paths.length ? paths : ["*"], content: body, filePath };
9092
+ return { id, description, paths: paths2.length ? paths2 : ["*"], content: body, filePath };
8949
9093
  } catch {
8950
9094
  return null;
8951
9095
  }
@@ -8954,7 +9098,7 @@ function loadPathRules() {
8954
9098
  ensureRulesDir();
8955
9099
  try {
8956
9100
  const dir = rulesDir();
8957
- return fs18.readdirSync(dir).filter((f) => f.endsWith(".md")).map((f) => parseRuleFile(path21.join(dir, f))).filter((r) => r !== null);
9101
+ return fs19.readdirSync(dir).filter((f) => f.endsWith(".md")).map((f) => parseRuleFile(path22.join(dir, f))).filter((r) => r !== null);
8958
9102
  } catch {
8959
9103
  return [];
8960
9104
  }
@@ -9042,8 +9186,8 @@ __export(kumaFlowCache_exports, {
9042
9186
  getFreshDomainFlow: () => getFreshDomainFlow,
9043
9187
  getHopsForDomain: () => getHopsForDomain
9044
9188
  });
9045
- import fs19 from "fs";
9046
- import path22 from "path";
9189
+ import fs20 from "fs";
9190
+ import path23 from "path";
9047
9191
  async function getFlowFreshness(domain) {
9048
9192
  try {
9049
9193
  const { getDb: getDb2 } = await Promise.resolve().then(() => (init_kumaDb(), kumaDb_exports));
@@ -9078,26 +9222,26 @@ async function getFlowFreshness(domain) {
9078
9222
  }
9079
9223
  function resolveImport(fromFile, spec) {
9080
9224
  const root = getProjectRoot();
9081
- const fromDir = path22.dirname(fromFile);
9225
+ const fromDir = path23.dirname(fromFile);
9082
9226
  const candidates = [];
9083
9227
  if (spec.startsWith(".")) {
9084
- const abs = path22.resolve(fromDir, spec);
9228
+ const abs = path23.resolve(fromDir, spec);
9085
9229
  candidates.push(abs);
9086
9230
  } else {
9087
- candidates.push(path22.join(root, spec));
9231
+ candidates.push(path23.join(root, spec));
9088
9232
  }
9089
9233
  for (const c of candidates) {
9090
9234
  for (const ext of SOURCE_EXTENSIONS) {
9091
9235
  const withExt = `${c}${ext}`;
9092
- if (fs19.existsSync(withExt)) return path22.relative(root, withExt);
9093
- if (fs19.existsSync(c) && fs19.statSync(c).isDirectory()) {
9094
- const idx = path22.join(c, "index") + ext;
9095
- if (fs19.existsSync(idx)) return path22.relative(root, idx);
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);
9096
9240
  }
9097
9241
  }
9098
- if (fs19.existsSync(c)) {
9242
+ if (fs20.existsSync(c)) {
9099
9243
  try {
9100
- if (fs19.statSync(c).isFile()) return path22.relative(root, c);
9244
+ if (fs20.statSync(c).isFile()) return path23.relative(root, c);
9101
9245
  } catch {
9102
9246
  }
9103
9247
  }
@@ -9106,13 +9250,13 @@ function resolveImport(fromFile, spec) {
9106
9250
  }
9107
9251
  function deriveHopsFromImports(entryFile, maxHops = 6) {
9108
9252
  const root = getProjectRoot();
9109
- const absEntry = path22.isAbsolute(entryFile) ? entryFile : path22.resolve(root, entryFile);
9110
- if (!fs19.existsSync(absEntry)) return [];
9253
+ const absEntry = path23.isAbsolute(entryFile) ? entryFile : path23.resolve(root, entryFile);
9254
+ if (!fs20.existsSync(absEntry)) return [];
9111
9255
  const hops = [];
9112
9256
  const seen = /* @__PURE__ */ new Set([entryFile]);
9113
- const fromName = path22.basename(absEntry);
9257
+ const fromName = path23.basename(absEntry);
9114
9258
  try {
9115
- const lines = fs19.readFileSync(absEntry, "utf-8").split("\n");
9259
+ const lines = fs20.readFileSync(absEntry, "utf-8").split("\n");
9116
9260
  for (const line of lines) {
9117
9261
  if (hops.length >= maxHops) break;
9118
9262
  const spec = matchImportPath(line);
@@ -9122,9 +9266,9 @@ function deriveHopsFromImports(entryFile, maxHops = 6) {
9122
9266
  seen.add(resolved);
9123
9267
  hops.push({
9124
9268
  from: fromName,
9125
- to: path22.basename(resolved),
9269
+ to: path23.basename(resolved),
9126
9270
  relation: "imports",
9127
- description: `${fromName} imports ${path22.basename(resolved)}`
9271
+ description: `${fromName} imports ${path23.basename(resolved)}`
9128
9272
  });
9129
9273
  }
9130
9274
  } catch {
@@ -9187,9 +9331,9 @@ async function getHopsForDomain(domain) {
9187
9331
  }
9188
9332
  try {
9189
9333
  const root = getProjectRoot();
9190
- const archPath = path22.join(root, ".kuma", "ARCHITECTURE_FLOW.md");
9191
- if (fs19.existsSync(archPath)) {
9192
- const content = fs19.readFileSync(archPath, "utf-8");
9334
+ const archPath = path23.join(root, ".kuma", "ARCHITECTURE_FLOW.md");
9335
+ if (fs20.existsSync(archPath)) {
9336
+ const content = fs20.readFileSync(archPath, "utf-8");
9193
9337
  const lines = content.split("\n");
9194
9338
  for (const line of lines) {
9195
9339
  const domMatch = line.match(new RegExp(`domain:\\s*${escapeRegex(domain)}\\s*\\|\\s*hops:\\s*(.+)`, "i"));
@@ -9234,7 +9378,7 @@ Record one with kuma_memory({ action: 'arch_flow', content: 'domain: ${domain} |
9234
9378
  hops: derivedHops,
9235
9379
  filePaths: freshness.filePaths
9236
9380
  });
9237
- lines.push(`\u2705 Re-derived ${derivedHops.length} hop(s) from ${path22.basename(entry)} \u2014 cache refreshed.`);
9381
+ lines.push(`\u2705 Re-derived ${derivedHops.length} hop(s) from ${path23.basename(entry)} \u2014 cache refreshed.`);
9238
9382
  hops.splice(0, hops.length, ...derivedHops);
9239
9383
  } else {
9240
9384
  lines.push("\u26A0\uFE0F No imports to follow \u2014 cache left as-is (record hops manually if needed).");
@@ -9287,10 +9431,10 @@ __export(packageBriefs_exports, {
9287
9431
  readBrief: () => readBrief,
9288
9432
  refreshPackageBriefs: () => refreshPackageBriefs
9289
9433
  });
9290
- import fs20 from "fs";
9291
- import path23 from "path";
9434
+ import fs21 from "fs";
9435
+ import path24 from "path";
9292
9436
  function briefsDir(root) {
9293
- return path23.join(root || getProjectRoot(), BRIEFS_DIR);
9437
+ return path24.join(root || getProjectRoot(), BRIEFS_DIR);
9294
9438
  }
9295
9439
  function slug(name) {
9296
9440
  return name.replace(/[^a-zA-Z0-9_-]/g, "_").slice(0, 60) || "root";
@@ -9354,13 +9498,13 @@ async function refreshPackageBriefs() {
9354
9498
  const dir = briefsDir(root);
9355
9499
  try {
9356
9500
  const ws = await getWorkspaceInfo(root);
9357
- if (!fs20.existsSync(dir)) fs20.mkdirSync(dir, { recursive: true });
9501
+ if (!fs21.existsSync(dir)) fs21.mkdirSync(dir, { recursive: true });
9358
9502
  let count = 0;
9359
9503
  const pkgs = ws.isWorkspace ? ws.packages : [{ name: "root", path: ".", isRoot: true }];
9360
9504
  for (const p of pkgs.slice(0, 20)) {
9361
9505
  const pkg = p;
9362
9506
  const content = await buildPackageBrief(pkg.name, pkg.path, root);
9363
- fs20.writeFileSync(path23.join(dir, `${slug(pkg.name)}.md`), content, "utf-8");
9507
+ fs21.writeFileSync(path24.join(dir, `${slug(pkg.name)}.md`), content, "utf-8");
9364
9508
  count++;
9365
9509
  }
9366
9510
  return { count, dir };
@@ -9370,9 +9514,9 @@ async function refreshPackageBriefs() {
9370
9514
  }
9371
9515
  function briefFreshness(pkgName) {
9372
9516
  try {
9373
- const fp = path23.join(briefsDir(), `${slug(pkgName)}.md`);
9374
- if (!fs20.existsSync(fp)) return { exists: false, fresh: false, age: "missing" };
9375
- const ageMs = Date.now() - fs20.statSync(fp).mtimeMs;
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;
9376
9520
  return { exists: true, fresh: !isStale(Date.now() - ageMs, MAP_TTL_MS), age: formatAge(Date.now() - ageMs) };
9377
9521
  } catch {
9378
9522
  return { exists: false, fresh: false, age: "missing" };
@@ -9380,9 +9524,9 @@ function briefFreshness(pkgName) {
9380
9524
  }
9381
9525
  function readBrief(pkgName, maxChars = 1200) {
9382
9526
  try {
9383
- const fp = path23.join(briefsDir(), `${slug(pkgName)}.md`);
9384
- if (!fs20.existsSync(fp)) return null;
9385
- const content = fs20.readFileSync(fp, "utf-8");
9527
+ const fp = path24.join(briefsDir(), `${slug(pkgName)}.md`);
9528
+ if (!fs21.existsSync(fp)) return null;
9529
+ const content = fs21.readFileSync(fp, "utf-8");
9386
9530
  return content.length > maxChars ? content.slice(0, maxChars) + "\n\u2026(truncated)" : content;
9387
9531
  } catch {
9388
9532
  return null;
@@ -9411,8 +9555,8 @@ __export(kumaSearch_exports, {
9411
9555
  formatHybridResults: () => formatHybridResults,
9412
9556
  hybridSearch: () => hybridSearch
9413
9557
  });
9414
- import fs22 from "fs";
9415
- import path25 from "path";
9558
+ import fs23 from "fs";
9559
+ import path26 from "path";
9416
9560
  function expandQueryTerms(query) {
9417
9561
  const terms = query.toLowerCase().split(/[\s_-]+/).filter((t) => t.length > 2);
9418
9562
  const expanded = /* @__PURE__ */ new Map();
@@ -9475,13 +9619,13 @@ async function buildSearchVectors() {
9475
9619
  }
9476
9620
  try {
9477
9621
  const root = getProjectRoot();
9478
- const memDir = path25.join(root, ".kuma", "memories");
9479
- if (fs22.existsSync(memDir)) {
9480
- const files = fs22.readdirSync(memDir).filter((f) => f.endsWith(".md")).slice(0, SCALE_LIMITS.maxMemoryFiles);
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);
9481
9625
  for (const file of files) {
9482
9626
  try {
9483
- const fullPath = path25.join(memDir, file);
9484
- const content = fs22.readFileSync(fullPath, "utf-8");
9627
+ const fullPath = path26.join(memDir, file);
9628
+ const content = fs23.readFileSync(fullPath, "utf-8");
9485
9629
  const text = content.toLowerCase();
9486
9630
  const rawTerms = extractTerms(text);
9487
9631
  const termCounts = /* @__PURE__ */ new Map();
@@ -9492,7 +9636,7 @@ async function buildSearchVectors() {
9492
9636
  terms: termCounts,
9493
9637
  source: file.replace(/\.md$/, ""),
9494
9638
  sourceType: "memory",
9495
- recency: recencyScore(Math.floor(fs22.statSync(fullPath).mtimeMs / 1e3))
9639
+ recency: recencyScore(Math.floor(fs23.statSync(fullPath).mtimeMs / 1e3))
9496
9640
  });
9497
9641
  } catch {
9498
9642
  }
@@ -9809,14 +9953,14 @@ __export(architectureGuard_exports, {
9809
9953
  detectWorkspaceCircularDeps: () => detectWorkspaceCircularDeps,
9810
9954
  loadArchitectureRules: () => loadArchitectureRules
9811
9955
  });
9812
- import fs26 from "fs";
9813
- import path29 from "path";
9956
+ import fs27 from "fs";
9957
+ import path30 from "path";
9814
9958
  import fastGlob4 from "fast-glob";
9815
9959
  function loadArchitectureRules(root) {
9816
- const rulesPath = path29.join(root, ".kuma", "architecture.json");
9817
- if (fs26.existsSync(rulesPath)) {
9960
+ const rulesPath = path30.join(root, ".kuma", "architecture.json");
9961
+ if (fs27.existsSync(rulesPath)) {
9818
9962
  try {
9819
- const data = JSON.parse(fs26.readFileSync(rulesPath, "utf-8"));
9963
+ const data = JSON.parse(fs27.readFileSync(rulesPath, "utf-8"));
9820
9964
  if (Array.isArray(data.rules)) {
9821
9965
  return data.rules;
9822
9966
  }
@@ -9878,11 +10022,11 @@ async function checkArchitectureBoundaries(filesToCheck, customRoot) {
9878
10022
  const customRules = loadArchitectureRules(root);
9879
10023
  const importRegex = /(?:import|export\s+.*from|require\s*\()\s*['"]([^'"]+)['"]/g;
9880
10024
  for (const file of targetFiles) {
9881
- const fullPath = path29.isAbsolute(file) ? file : path29.join(root, file);
9882
- if (!fs26.existsSync(fullPath)) continue;
10025
+ const fullPath = path30.isAbsolute(file) ? file : path30.join(root, file);
10026
+ if (!fs27.existsSync(fullPath)) continue;
9883
10027
  let content = "";
9884
10028
  try {
9885
- content = fs26.readFileSync(fullPath, "utf-8");
10029
+ content = fs27.readFileSync(fullPath, "utf-8");
9886
10030
  } catch {
9887
10031
  continue;
9888
10032
  }
@@ -9892,7 +10036,7 @@ async function checkArchitectureBoundaries(filesToCheck, customRoot) {
9892
10036
  const importPath = match[1];
9893
10037
  if (wsInfo.isWorkspace && currentPkg && !currentPkg.isRoot) {
9894
10038
  if (importPath.startsWith("../") && (importPath.includes("/src/") || importPath.includes("/dist/"))) {
9895
- const resolvedTarget = path29.normalize(path29.resolve(path29.dirname(fullPath), importPath));
10039
+ const resolvedTarget = path30.normalize(path30.resolve(path30.dirname(fullPath), importPath));
9896
10040
  const targetPkg = findPackageForFile(resolvedTarget, wsInfo);
9897
10041
  if (targetPkg && targetPkg.name !== currentPkg.name) {
9898
10042
  violations.push({
@@ -9941,26 +10085,26 @@ __export(docDrift_exports, {
9941
10085
  formatDocDrift: () => formatDocDrift,
9942
10086
  scanDocDrift: () => scanDocDrift
9943
10087
  });
9944
- import fs27 from "fs";
9945
- import path30 from "path";
9946
- import { execSync as execSync8 } from "child_process";
10088
+ import fs28 from "fs";
10089
+ import path31 from "path";
10090
+ import { execSync as execSync9 } from "child_process";
9947
10091
  function collectDocFiles(root) {
9948
10092
  const cwd = root || getProjectRoot();
9949
10093
  const out = [];
9950
10094
  const pushIfMd = (dir, rel) => {
9951
10095
  try {
9952
- for (const f of fs27.readdirSync(dir)) {
10096
+ for (const f of fs28.readdirSync(dir)) {
9953
10097
  if (out.length >= MAX_DOCS) return;
9954
- const full = path30.join(dir, f);
10098
+ const full = path31.join(dir, f);
9955
10099
  try {
9956
- if (fs27.statSync(full).isFile() && /\.md$/i.test(f)) out.push(rel(f));
10100
+ if (fs28.statSync(full).isFile() && /\.md$/i.test(f)) out.push(rel(f));
9957
10101
  } catch {
9958
10102
  }
9959
10103
  }
9960
10104
  } catch {
9961
10105
  }
9962
10106
  };
9963
- pushIfMd(path30.join(cwd, "docs"), (f) => path30.join("docs", f));
10107
+ pushIfMd(path31.join(cwd, "docs"), (f) => path31.join("docs", f));
9964
10108
  pushIfMd(cwd, (f) => f);
9965
10109
  return out;
9966
10110
  }
@@ -10002,7 +10146,7 @@ function codeContainsBatch(root, needles) {
10002
10146
  const chunk = clean.slice(i, i + 50);
10003
10147
  try {
10004
10148
  const args = chunk.map((n) => `-e "${n}"`).join(" ");
10005
- const out = execSync8(
10149
+ const out = execSync9(
10006
10150
  `grep -rn --include="*.ts" --include="*.js" --include="*.tsx" --include="*.jsx" --include="*.py" --include="*.go" --include="*.rs" --include="*.json" --include="*.yml" --include="*.yaml" --include="*.toml" --include=".env*" -F ${args} . 2>/dev/null | grep -v node_modules | grep -v "/dist/" | grep -v "/.git/" | grep -v "/.kuma/" | head -100`,
10007
10151
  { cwd: root, encoding: "utf-8", timeout: 8e3, maxBuffer: 256 * 1024 }
10008
10152
  ).trim();
@@ -10022,7 +10166,7 @@ function scanDocDrift(root) {
10022
10166
  let claims = [];
10023
10167
  for (const rel of collectDocFiles(cwd)) {
10024
10168
  try {
10025
- const content = fs27.readFileSync(path30.join(cwd, rel), "utf-8");
10169
+ const content = fs28.readFileSync(path31.join(cwd, rel), "utf-8");
10026
10170
  if (isExemptDoc(rel, content)) {
10027
10171
  skipped.push(rel);
10028
10172
  continue;
@@ -10193,27 +10337,27 @@ __export(kumaCheckpoint_exports, {
10193
10337
  pruneCheckpoints: () => pruneCheckpoints,
10194
10338
  rollbackToCheckpoint: () => rollbackToCheckpoint
10195
10339
  });
10196
- import fs28 from "fs";
10197
- import path31 from "path";
10340
+ import fs29 from "fs";
10341
+ import path32 from "path";
10198
10342
  async function createCheckpoint(label, description) {
10199
10343
  try {
10200
10344
  const root = getProjectRoot();
10201
- const cpDir = path31.join(root, CHECKPOINT_DIR, sanitizeLabel(label));
10202
- if (fs28.existsSync(cpDir)) {
10345
+ const cpDir = path32.join(root, CHECKPOINT_DIR, sanitizeLabel(label));
10346
+ if (fs29.existsSync(cpDir)) {
10203
10347
  return `\u26A0\uFE0F Checkpoint "${label}" already exists. Use a different label or remove it first.`;
10204
10348
  }
10205
- fs28.mkdirSync(cpDir, { recursive: true });
10349
+ fs29.mkdirSync(cpDir, { recursive: true });
10206
10350
  let gitHead;
10207
10351
  let isGitClean = false;
10208
10352
  try {
10209
- const { execSync: execSync9 } = await import("child_process");
10210
- gitHead = execSync9("git rev-parse HEAD", {
10353
+ const { execSync: execSync10 } = await import("child_process");
10354
+ gitHead = execSync10("git rev-parse HEAD", {
10211
10355
  cwd: root,
10212
10356
  encoding: "utf-8",
10213
10357
  timeout: 3e3,
10214
10358
  stdio: ["pipe", "pipe", "pipe"]
10215
10359
  }).trim();
10216
- const statusOut = execSync9("git status --porcelain", {
10360
+ const statusOut = execSync10("git status --porcelain", {
10217
10361
  cwd: root,
10218
10362
  encoding: "utf-8",
10219
10363
  timeout: 3e3,
@@ -10224,8 +10368,8 @@ async function createCheckpoint(label, description) {
10224
10368
  }
10225
10369
  const candidatePaths = /* @__PURE__ */ new Set();
10226
10370
  try {
10227
- const { execSync: execSync9 } = await import("child_process");
10228
- const gitOut = execSync9("git status --porcelain", {
10371
+ const { execSync: execSync10 } = await import("child_process");
10372
+ const gitOut = execSync10("git status --porcelain", {
10229
10373
  cwd: root,
10230
10374
  encoding: "utf-8",
10231
10375
  timeout: 4e3,
@@ -10268,15 +10412,15 @@ async function createCheckpoint(label, description) {
10268
10412
  }
10269
10413
  const files = [];
10270
10414
  for (const fp of candidatePaths) {
10271
- const fullPath = path31.resolve(root, fp);
10415
+ const fullPath = path32.resolve(root, fp);
10272
10416
  try {
10273
- if (fs28.existsSync(fullPath) && fs28.statSync(fullPath).isFile()) {
10274
- const content = fs28.readFileSync(fullPath, "utf-8");
10417
+ if (fs29.existsSync(fullPath) && fs29.statSync(fullPath).isFile()) {
10418
+ const content = fs29.readFileSync(fullPath, "utf-8");
10275
10419
  const hash = simpleHash2(content);
10276
- const snapFile = path31.join(cpDir, "files", `${fp}.kuma-snap`);
10277
- const fileDir = path31.dirname(snapFile);
10278
- if (!fs28.existsSync(fileDir)) fs28.mkdirSync(fileDir, { recursive: true });
10279
- fs28.writeFileSync(snapFile, content, "utf-8");
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");
10280
10424
  files.push({ path: fp, hash });
10281
10425
  }
10282
10426
  } catch {
@@ -10284,7 +10428,7 @@ async function createCheckpoint(label, description) {
10284
10428
  }
10285
10429
  const db = await getDb();
10286
10430
  const dbData = db.export();
10287
- fs28.writeFileSync(path31.join(cpDir, "kuma.db"), Buffer.from(dbData));
10431
+ fs29.writeFileSync(path32.join(cpDir, "kuma.db"), Buffer.from(dbData));
10288
10432
  const manifest = {
10289
10433
  label,
10290
10434
  timestamp: Date.now(),
@@ -10294,8 +10438,8 @@ async function createCheckpoint(label, description) {
10294
10438
  dbSnapshot: true,
10295
10439
  description
10296
10440
  };
10297
- fs28.writeFileSync(
10298
- path31.join(cpDir, "manifest.json"),
10441
+ fs29.writeFileSync(
10442
+ path32.join(cpDir, "manifest.json"),
10299
10443
  JSON.stringify(manifest, null, 2),
10300
10444
  "utf-8"
10301
10445
  );
@@ -10323,29 +10467,29 @@ async function createCheckpoint(label, description) {
10323
10467
  async function rollbackToCheckpoint(label) {
10324
10468
  try {
10325
10469
  const root = getProjectRoot();
10326
- const cpDir = path31.join(root, CHECKPOINT_DIR, sanitizeLabel(label));
10327
- const manifestPath = path31.join(cpDir, "manifest.json");
10328
- if (!fs28.existsSync(manifestPath)) {
10470
+ const cpDir = path32.join(root, CHECKPOINT_DIR, sanitizeLabel(label));
10471
+ const manifestPath = path32.join(cpDir, "manifest.json");
10472
+ if (!fs29.existsSync(manifestPath)) {
10329
10473
  return `\u274C Checkpoint "${label}" not found. Available checkpoints:
10330
10474
 
10331
10475
  ${listCheckpoints()}`;
10332
10476
  }
10333
10477
  const manifest = JSON.parse(
10334
- fs28.readFileSync(manifestPath, "utf-8")
10478
+ fs29.readFileSync(manifestPath, "utf-8")
10335
10479
  );
10336
10480
  let restored = 0;
10337
10481
  let failed = 0;
10338
10482
  for (const f of manifest.files) {
10339
- const snapPath = path31.join(cpDir, "files", `${f.path}.kuma-snap`);
10340
- const legacyPath = path31.join(cpDir, "files", f.path);
10341
- const sourcePath = fs28.existsSync(snapPath) ? snapPath : legacyPath;
10342
- if (fs28.existsSync(sourcePath)) {
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)) {
10343
10487
  try {
10344
- const content = fs28.readFileSync(sourcePath, "utf-8");
10345
- const targetPath = path31.resolve(root, f.path);
10346
- const targetDir = path31.dirname(targetPath);
10347
- if (!fs28.existsSync(targetDir)) fs28.mkdirSync(targetDir, { recursive: true });
10348
- fs28.writeFileSync(targetPath, content, "utf-8");
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");
10349
10493
  restored++;
10350
10494
  } catch {
10351
10495
  failed++;
@@ -10354,8 +10498,8 @@ ${listCheckpoints()}`;
10354
10498
  }
10355
10499
  if (manifest.files.length === 0 && manifest.gitHead) {
10356
10500
  try {
10357
- const { execSync: execSync9 } = await import("child_process");
10358
- execSync9(`git checkout ${manifest.gitHead} -- .`, {
10501
+ const { execSync: execSync10 } = await import("child_process");
10502
+ execSync10(`git checkout ${manifest.gitHead} -- .`, {
10359
10503
  cwd: root,
10360
10504
  encoding: "utf-8",
10361
10505
  timeout: 8e3,
@@ -10366,12 +10510,12 @@ ${listCheckpoints()}`;
10366
10510
  failed++;
10367
10511
  }
10368
10512
  }
10369
- const dbSnapshotPath = path31.join(cpDir, "kuma.db");
10370
- if (fs28.existsSync(dbSnapshotPath)) {
10371
- const kumaDir = path31.join(root, ".kuma");
10372
- const dbPath = path31.join(kumaDir, "kuma.db");
10373
- const snapshotData = fs28.readFileSync(dbSnapshotPath);
10374
- fs28.writeFileSync(dbPath, snapshotData);
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);
10375
10519
  resetDbInstance();
10376
10520
  }
10377
10521
  sessionMemory.recordToolCall("kuma_checkpoint_rollback", {
@@ -10396,18 +10540,18 @@ ${listCheckpoints()}`;
10396
10540
  function listCheckpoints() {
10397
10541
  try {
10398
10542
  const root = getProjectRoot();
10399
- const cpDir = path31.join(root, CHECKPOINT_DIR);
10400
- if (!fs28.existsSync(cpDir)) {
10543
+ const cpDir = path32.join(root, CHECKPOINT_DIR);
10544
+ if (!fs29.existsSync(cpDir)) {
10401
10545
  return "\u{1F4ED} No checkpoints found. Use kuma_safety({ action: 'checkpoint', label: 'pre-feature-x' }) to create one.";
10402
10546
  }
10403
- const entries = fs28.readdirSync(cpDir);
10547
+ const entries = fs29.readdirSync(cpDir);
10404
10548
  const checkpoints = [];
10405
10549
  for (const entry of entries) {
10406
- const manifestPath = path31.join(cpDir, entry, "manifest.json");
10407
- if (fs28.existsSync(manifestPath)) {
10550
+ const manifestPath = path32.join(cpDir, entry, "manifest.json");
10551
+ if (fs29.existsSync(manifestPath)) {
10408
10552
  try {
10409
10553
  const manifest = JSON.parse(
10410
- fs28.readFileSync(manifestPath, "utf-8")
10554
+ fs29.readFileSync(manifestPath, "utf-8")
10411
10555
  );
10412
10556
  checkpoints.push({ label: entry, manifest });
10413
10557
  } catch {
@@ -10439,12 +10583,12 @@ function listCheckpoints() {
10439
10583
  function pruneCheckpoints(keep = 5) {
10440
10584
  try {
10441
10585
  const root = getProjectRoot();
10442
- const cpDir = path31.join(root, CHECKPOINT_DIR);
10443
- if (!fs28.existsSync(cpDir)) return "\u{1F4ED} No checkpoints to prune.";
10444
- const entries = fs28.readdirSync(cpDir).map((e) => ({ name: e, time: fs28.statSync(path31.join(cpDir, e)).mtimeMs })).sort((a, b) => b.time - a.time);
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);
10445
10589
  let removed = 0;
10446
10590
  for (let i = keep; i < entries.length; i++) {
10447
- fs28.rmSync(path31.join(cpDir, entries[i].name), { recursive: true, force: true });
10591
+ fs29.rmSync(path32.join(cpDir, entries[i].name), { recursive: true, force: true });
10448
10592
  removed++;
10449
10593
  }
10450
10594
  return removed > 0 ? `\u{1F9F9} Pruned **${removed} old checkpoint(s)**. Kept ${Math.min(keep, entries.length)} most recent.` : "\u2705 No checkpoints needed pruning.";
@@ -10469,9 +10613,9 @@ function isRiskyEditPath(filePath) {
10469
10613
  }
10470
10614
  function loadAutoCpDone(root) {
10471
10615
  try {
10472
- const fp = path31.join(root, AUTO_CP_STATE);
10473
- if (fs28.existsSync(fp)) {
10474
- const parsed = JSON.parse(fs28.readFileSync(fp, "utf-8"));
10616
+ const fp = path32.join(root, AUTO_CP_STATE);
10617
+ if (fs29.existsSync(fp)) {
10618
+ const parsed = JSON.parse(fs29.readFileSync(fp, "utf-8"));
10475
10619
  return parsed?.autoCheckpoints ?? {};
10476
10620
  }
10477
10621
  } catch {
@@ -10480,10 +10624,10 @@ function loadAutoCpDone(root) {
10480
10624
  }
10481
10625
  function saveAutoCpDone(root, done) {
10482
10626
  try {
10483
- const fp = path31.join(root, AUTO_CP_STATE);
10484
- const parsed = fs28.existsSync(fp) ? JSON.parse(fs28.readFileSync(fp, "utf-8")) : {};
10627
+ const fp = path32.join(root, AUTO_CP_STATE);
10628
+ const parsed = fs29.existsSync(fp) ? JSON.parse(fs29.readFileSync(fp, "utf-8")) : {};
10485
10629
  parsed.autoCheckpoints = done;
10486
- fs28.writeFileSync(fp, JSON.stringify(parsed), "utf-8");
10630
+ fs29.writeFileSync(fp, JSON.stringify(parsed), "utf-8");
10487
10631
  } catch {
10488
10632
  }
10489
10633
  }
@@ -10493,14 +10637,14 @@ function maybeAutoCheckpoint(filePath) {
10493
10637
  const root = getProjectRoot();
10494
10638
  const done = loadAutoCpDone(root);
10495
10639
  if (done[filePath]) return null;
10496
- const abs = path31.isAbsolute(filePath) ? filePath : path31.join(root, filePath);
10497
- if (!fs28.existsSync(abs) || !fs28.statSync(abs).isFile()) return null;
10498
- const label = `auto-pre-${sanitizeLabel(path31.basename(filePath))}`;
10499
- const cpDir = path31.join(root, CHECKPOINT_DIR, label);
10500
- if (!fs28.existsSync(cpDir)) fs28.mkdirSync(cpDir, { recursive: true });
10501
- fs28.copyFileSync(abs, path31.join(cpDir, path31.basename(abs)));
10502
- fs28.writeFileSync(
10503
- path31.join(cpDir, "manifest.json"),
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"),
10504
10648
  JSON.stringify({
10505
10649
  label,
10506
10650
  timestamp: Date.now(),
@@ -10540,8 +10684,8 @@ __export(init_exports, {
10540
10684
  generateInitMdContent: () => generateInitMdContent,
10541
10685
  runInit: () => runInit
10542
10686
  });
10543
- import fs29 from "fs";
10544
- import path32 from "path";
10687
+ import fs30 from "fs";
10688
+ import path33 from "path";
10545
10689
  function configFilePath(type) {
10546
10690
  switch (type) {
10547
10691
  case "claude":
@@ -11175,21 +11319,21 @@ function handleOpencodeSecondary(root, results) {
11175
11319
  "",
11176
11320
  "\u{1F4D6} Full rules: `.kuma/init.md`"
11177
11321
  ].join("\n");
11178
- const skillPath = path32.resolve(root, ".agents", "skills", "kuma", "SKILL.md");
11322
+ const skillPath = path33.resolve(root, ".agents", "skills", "kuma", "SKILL.md");
11179
11323
  if (!results.some((r) => r.filePath === ".agents/skills/kuma/SKILL.md")) {
11180
11324
  try {
11181
- const dir = path32.dirname(skillPath);
11182
- if (fs29.existsSync(skillPath)) {
11183
- const existing = fs29.readFileSync(skillPath, "utf-8");
11325
+ const dir = path33.dirname(skillPath);
11326
+ if (fs30.existsSync(skillPath)) {
11327
+ const existing = fs30.readFileSync(skillPath, "utf-8");
11184
11328
  if (existing.includes("kuma-mcp")) {
11185
11329
  results.push({ type: "opencode", filePath: ".agents/skills/kuma/SKILL.md", action: "skipped" });
11186
11330
  } else {
11187
- fs29.writeFileSync(skillPath, existing.trimEnd() + "\n\n---\n\n" + opencodeContent, "utf-8");
11331
+ fs30.writeFileSync(skillPath, existing.trimEnd() + "\n\n---\n\n" + opencodeContent, "utf-8");
11188
11332
  results.push({ type: "opencode", filePath: ".agents/skills/kuma/SKILL.md", action: "appended" });
11189
11333
  }
11190
11334
  } else {
11191
- if (!fs29.existsSync(dir)) fs29.mkdirSync(dir, { recursive: true });
11192
- fs29.writeFileSync(skillPath, opencodeContent, "utf-8");
11335
+ if (!fs30.existsSync(dir)) fs30.mkdirSync(dir, { recursive: true });
11336
+ fs30.writeFileSync(skillPath, opencodeContent, "utf-8");
11193
11337
  results.push({ type: "opencode", filePath: ".agents/skills/kuma/SKILL.md", action: "created" });
11194
11338
  }
11195
11339
  } catch (err) {
@@ -11201,21 +11345,21 @@ function handleOpencodeSecondary(root, results) {
11201
11345
  });
11202
11346
  }
11203
11347
  }
11204
- const opencodeSkillPath = path32.resolve(root, ".opencode", "skills", "kuma", "SKILL.md");
11348
+ const opencodeSkillPath = path33.resolve(root, ".opencode", "skills", "kuma", "SKILL.md");
11205
11349
  if (!results.some((r) => r.filePath === ".opencode/skills/kuma/SKILL.md")) {
11206
11350
  try {
11207
- const dir = path32.dirname(opencodeSkillPath);
11208
- if (fs29.existsSync(opencodeSkillPath)) {
11209
- const existing = fs29.readFileSync(opencodeSkillPath, "utf-8");
11351
+ const dir = path33.dirname(opencodeSkillPath);
11352
+ if (fs30.existsSync(opencodeSkillPath)) {
11353
+ const existing = fs30.readFileSync(opencodeSkillPath, "utf-8");
11210
11354
  if (existing.includes("kuma-mcp")) {
11211
11355
  results.push({ type: "opencode", filePath: ".opencode/skills/kuma/SKILL.md", action: "skipped" });
11212
11356
  } else {
11213
- fs29.writeFileSync(opencodeSkillPath, existing.trimEnd() + "\n\n---\n\n" + opencodeContent, "utf-8");
11357
+ fs30.writeFileSync(opencodeSkillPath, existing.trimEnd() + "\n\n---\n\n" + opencodeContent, "utf-8");
11214
11358
  results.push({ type: "opencode", filePath: ".opencode/skills/kuma/SKILL.md", action: "appended" });
11215
11359
  }
11216
11360
  } else {
11217
- if (!fs29.existsSync(dir)) fs29.mkdirSync(dir, { recursive: true });
11218
- fs29.writeFileSync(opencodeSkillPath, opencodeContent, "utf-8");
11361
+ if (!fs30.existsSync(dir)) fs30.mkdirSync(dir, { recursive: true });
11362
+ fs30.writeFileSync(opencodeSkillPath, opencodeContent, "utf-8");
11219
11363
  results.push({ type: "opencode", filePath: ".opencode/skills/kuma/SKILL.md", action: "created" });
11220
11364
  }
11221
11365
  } catch (err) {
@@ -11227,21 +11371,21 @@ function handleOpencodeSecondary(root, results) {
11227
11371
  });
11228
11372
  }
11229
11373
  }
11230
- const pluginPath = path32.resolve(root, ".opencode", "plugins", "kuma.js");
11374
+ const pluginPath = path33.resolve(root, ".opencode", "plugins", "kuma.js");
11231
11375
  if (!results.some((r) => r.filePath === ".opencode/plugins/kuma.js")) {
11232
11376
  try {
11233
- const dir = path32.dirname(pluginPath);
11234
- if (fs29.existsSync(pluginPath)) {
11235
- const existing = fs29.readFileSync(pluginPath, "utf-8");
11377
+ const dir = path33.dirname(pluginPath);
11378
+ if (fs30.existsSync(pluginPath)) {
11379
+ const existing = fs30.readFileSync(pluginPath, "utf-8");
11236
11380
  if (existing.includes("KumaPlugin") || existing.includes("kuma")) {
11237
11381
  results.push({ type: "opencode", filePath: ".opencode/plugins/kuma.js", action: "skipped" });
11238
11382
  } else {
11239
- fs29.writeFileSync(pluginPath, existing.trimEnd() + "\n\n" + opencodePluginTemplate(), "utf-8");
11383
+ fs30.writeFileSync(pluginPath, existing.trimEnd() + "\n\n" + opencodePluginTemplate(), "utf-8");
11240
11384
  results.push({ type: "opencode", filePath: ".opencode/plugins/kuma.js", action: "appended" });
11241
11385
  }
11242
11386
  } else {
11243
- if (!fs29.existsSync(dir)) fs29.mkdirSync(dir, { recursive: true });
11244
- fs29.writeFileSync(pluginPath, opencodePluginTemplate(), "utf-8");
11387
+ if (!fs30.existsSync(dir)) fs30.mkdirSync(dir, { recursive: true });
11388
+ fs30.writeFileSync(pluginPath, opencodePluginTemplate(), "utf-8");
11245
11389
  results.push({ type: "opencode", filePath: ".opencode/plugins/kuma.js", action: "created" });
11246
11390
  }
11247
11391
  } catch (err) {
@@ -11255,21 +11399,21 @@ function handleOpencodeSecondary(root, results) {
11255
11399
  }
11256
11400
  }
11257
11401
  function handleCodexSecondary(root, results) {
11258
- const tomlPath = path32.resolve(root, ".codex/config.toml");
11402
+ const tomlPath = path33.resolve(root, ".codex/config.toml");
11259
11403
  if (results.some((r) => r.filePath === ".codex/config.toml")) return;
11260
11404
  try {
11261
- const dir = path32.dirname(tomlPath);
11262
- if (!fs29.existsSync(dir)) fs29.mkdirSync(dir, { recursive: true });
11263
- if (fs29.existsSync(tomlPath)) {
11264
- const existingContent = fs29.readFileSync(tomlPath, "utf-8");
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");
11265
11409
  if (existingContent.includes("kuma")) {
11266
11410
  results.push({ type: "codex", filePath: ".codex/config.toml", action: "skipped" });
11267
11411
  return;
11268
11412
  }
11269
- fs29.writeFileSync(tomlPath, existingContent.trimEnd() + "\n\n" + codexConfigTomlTemplate(), "utf-8");
11413
+ fs30.writeFileSync(tomlPath, existingContent.trimEnd() + "\n\n" + codexConfigTomlTemplate(), "utf-8");
11270
11414
  results.push({ type: "codex", filePath: ".codex/config.toml", action: "appended" });
11271
11415
  } else {
11272
- fs29.writeFileSync(tomlPath, codexConfigTomlTemplate(), "utf-8");
11416
+ fs30.writeFileSync(tomlPath, codexConfigTomlTemplate(), "utf-8");
11273
11417
  results.push({ type: "codex", filePath: ".codex/config.toml", action: "created" });
11274
11418
  }
11275
11419
  } catch (err) {
@@ -11282,11 +11426,11 @@ function handleCodexSecondary(root, results) {
11282
11426
  }
11283
11427
  }
11284
11428
  function handleQwenSecondary(root, results) {
11285
- const settingsPath = path32.resolve(root, "settings.json");
11429
+ const settingsPath = path33.resolve(root, "settings.json");
11286
11430
  if (results.some((r) => r.filePath === "settings.json")) return;
11287
11431
  try {
11288
- if (fs29.existsSync(settingsPath)) {
11289
- const existingContent = fs29.readFileSync(settingsPath, "utf-8");
11432
+ if (fs30.existsSync(settingsPath)) {
11433
+ const existingContent = fs30.readFileSync(settingsPath, "utf-8");
11290
11434
  if (existingContent.includes("kuma")) {
11291
11435
  if (!existingContent.includes("_Generated by Kuma MCP_")) {
11292
11436
  try {
@@ -11294,7 +11438,7 @@ function handleQwenSecondary(root, results) {
11294
11438
  parsed.mcpServers = parsed.mcpServers || {};
11295
11439
  if (!parsed.mcpServers.kuma) {
11296
11440
  parsed.mcpServers.kuma = { command: "npx", args: ["-y", "@plumpslabs/kuma"], env: {} };
11297
- fs29.writeFileSync(settingsPath, JSON.stringify(parsed, null, 2) + "\n", "utf-8");
11441
+ fs30.writeFileSync(settingsPath, JSON.stringify(parsed, null, 2) + "\n", "utf-8");
11298
11442
  results.push({ type: "qwen", filePath: "settings.json", action: "appended" });
11299
11443
  return;
11300
11444
  }
@@ -11309,13 +11453,13 @@ function handleQwenSecondary(root, results) {
11309
11453
  parsed.mcpServers = parsed.mcpServers || {};
11310
11454
  if (!parsed.mcpServers.kuma) {
11311
11455
  parsed.mcpServers.kuma = { command: "npx", args: ["-y", "@plumpslabs/kuma"], env: {} };
11312
- fs29.writeFileSync(settingsPath, JSON.stringify(parsed, null, 2) + "\n", "utf-8");
11456
+ fs30.writeFileSync(settingsPath, JSON.stringify(parsed, null, 2) + "\n", "utf-8");
11313
11457
  results.push({ type: "qwen", filePath: "settings.json", action: "appended" });
11314
11458
  }
11315
11459
  } catch {
11316
11460
  }
11317
11461
  } else {
11318
- fs29.writeFileSync(settingsPath, qwenSettingsTemplate(), "utf-8");
11462
+ fs30.writeFileSync(settingsPath, qwenSettingsTemplate(), "utf-8");
11319
11463
  results.push({ type: "qwen", filePath: "settings.json", action: "created" });
11320
11464
  }
11321
11465
  } catch (err) {
@@ -11417,12 +11561,12 @@ function getCombinedAgentsMd(selectedTypes) {
11417
11561
  return lines.join("\n");
11418
11562
  }
11419
11563
  function handleAntigravityMcpConfig(root, results) {
11420
- const mcpPath = path32.resolve(root, ".agents/mcp_config.json");
11564
+ const mcpPath = path33.resolve(root, ".agents/mcp_config.json");
11421
11565
  if (results.some((r) => r.filePath === ".agents/mcp_config.json")) return;
11422
11566
  try {
11423
- const mcpDir = path32.dirname(mcpPath);
11424
- if (fs29.existsSync(mcpPath)) {
11425
- const existingContent = fs29.readFileSync(mcpPath, "utf-8");
11567
+ const mcpDir = path33.dirname(mcpPath);
11568
+ if (fs30.existsSync(mcpPath)) {
11569
+ const existingContent = fs30.readFileSync(mcpPath, "utf-8");
11426
11570
  if (existingContent.includes("kuma")) {
11427
11571
  results.push({ type: "antigravity", filePath: ".agents/mcp_config.json", action: "skipped" });
11428
11572
  return;
@@ -11431,14 +11575,14 @@ function handleAntigravityMcpConfig(root, results) {
11431
11575
  const parsed = JSON.parse(existingContent);
11432
11576
  parsed.mcpServers = parsed.mcpServers || {};
11433
11577
  parsed.mcpServers.kuma = { command: "npx", args: ["-y", "@plumpslabs/kuma"], env: {} };
11434
- fs29.writeFileSync(mcpPath, JSON.stringify(parsed, null, 2) + "\n", "utf-8");
11578
+ fs30.writeFileSync(mcpPath, JSON.stringify(parsed, null, 2) + "\n", "utf-8");
11435
11579
  results.push({ type: "antigravity", filePath: ".agents/mcp_config.json", action: "appended" });
11436
11580
  } catch {
11437
11581
  results.push({ type: "antigravity", filePath: ".agents/mcp_config.json", action: "error", error: "Invalid JSON in existing mcp_config.json" });
11438
11582
  }
11439
11583
  } else {
11440
- if (!fs29.existsSync(mcpDir)) fs29.mkdirSync(mcpDir, { recursive: true });
11441
- fs29.writeFileSync(mcpPath, antigravityMcpConfigTemplate(), "utf-8");
11584
+ if (!fs30.existsSync(mcpDir)) fs30.mkdirSync(mcpDir, { recursive: true });
11585
+ fs30.writeFileSync(mcpPath, antigravityMcpConfigTemplate(), "utf-8");
11442
11586
  results.push({ type: "antigravity", filePath: ".agents/mcp_config.json", action: "created" });
11443
11587
  }
11444
11588
  } catch (err) {
@@ -11451,21 +11595,21 @@ function handleAntigravityMcpConfig(root, results) {
11451
11595
  }
11452
11596
  }
11453
11597
  function handleAntigravityRules(root, results) {
11454
- const rulePath = path32.resolve(root, ".agents", "rules", "kuma.md");
11598
+ const rulePath = path33.resolve(root, ".agents", "rules", "kuma.md");
11455
11599
  if (results.some((r) => r.filePath === ".agents/rules/kuma.md")) return;
11456
11600
  try {
11457
- const dir = path32.dirname(rulePath);
11458
- if (!fs29.existsSync(dir)) fs29.mkdirSync(dir, { recursive: true });
11459
- if (fs29.existsSync(rulePath)) {
11460
- const existing = fs29.readFileSync(rulePath, "utf-8");
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");
11461
11605
  if (existing.includes("Kuma MCP") || existing.includes("kuma-mcp")) {
11462
11606
  results.push({ type: "antigravity", filePath: ".agents/rules/kuma.md", action: "skipped" });
11463
11607
  return;
11464
11608
  }
11465
- fs29.writeFileSync(rulePath, existing.trimEnd() + "\n\n---\n\n" + antigravityRuleTemplate(), "utf-8");
11609
+ fs30.writeFileSync(rulePath, existing.trimEnd() + "\n\n---\n\n" + antigravityRuleTemplate(), "utf-8");
11466
11610
  results.push({ type: "antigravity", filePath: ".agents/rules/kuma.md", action: "appended" });
11467
11611
  } else {
11468
- fs29.writeFileSync(rulePath, antigravityRuleTemplate(), "utf-8");
11612
+ fs30.writeFileSync(rulePath, antigravityRuleTemplate(), "utf-8");
11469
11613
  results.push({ type: "antigravity", filePath: ".agents/rules/kuma.md", action: "created" });
11470
11614
  }
11471
11615
  } catch (err) {
@@ -11478,19 +11622,19 @@ function handleAntigravityRules(root, results) {
11478
11622
  }
11479
11623
  }
11480
11624
  function handleGeminiMd(root, results) {
11481
- const geminiPath = path32.resolve(root, "GEMINI.md");
11625
+ const geminiPath = path33.resolve(root, "GEMINI.md");
11482
11626
  if (results.some((r) => r.filePath === "GEMINI.md")) return;
11483
11627
  try {
11484
- if (fs29.existsSync(geminiPath)) {
11485
- const existing = fs29.readFileSync(geminiPath, "utf-8");
11628
+ if (fs30.existsSync(geminiPath)) {
11629
+ const existing = fs30.readFileSync(geminiPath, "utf-8");
11486
11630
  if (existing.includes("Kuma MCP") || existing.includes("kuma_context")) {
11487
11631
  results.push({ type: "antigravity", filePath: "GEMINI.md", action: "skipped" });
11488
11632
  return;
11489
11633
  }
11490
- fs29.writeFileSync(geminiPath, existing.trimEnd() + "\n\n---\n\n" + geminiTemplate(), "utf-8");
11634
+ fs30.writeFileSync(geminiPath, existing.trimEnd() + "\n\n---\n\n" + geminiTemplate(), "utf-8");
11491
11635
  results.push({ type: "antigravity", filePath: "GEMINI.md", action: "appended" });
11492
11636
  } else {
11493
- fs29.writeFileSync(geminiPath, geminiTemplate(), "utf-8");
11637
+ fs30.writeFileSync(geminiPath, geminiTemplate(), "utf-8");
11494
11638
  results.push({ type: "antigravity", filePath: "GEMINI.md", action: "created" });
11495
11639
  }
11496
11640
  } catch (err) {
@@ -11508,19 +11652,19 @@ function handleAntigravitySecondary(root, results) {
11508
11652
  handleGeminiMd(root, results);
11509
11653
  }
11510
11654
  function handleWindsurfSecondary(root, results) {
11511
- const rulesPath = path32.resolve(root, ".windsurfrules");
11655
+ const rulesPath = path33.resolve(root, ".windsurfrules");
11512
11656
  if (results.some((r) => r.filePath === ".windsurfrules")) return;
11513
11657
  try {
11514
- if (fs29.existsSync(rulesPath)) {
11515
- const existing = fs29.readFileSync(rulesPath, "utf-8");
11658
+ if (fs30.existsSync(rulesPath)) {
11659
+ const existing = fs30.readFileSync(rulesPath, "utf-8");
11516
11660
  if (existing.includes("Kuma MCP") || existing.includes("kuma_context")) {
11517
11661
  results.push({ type: "windsurf", filePath: ".windsurfrules", action: "skipped" });
11518
11662
  return;
11519
11663
  }
11520
- fs29.writeFileSync(rulesPath, existing.trimEnd() + "\n\n---\n\n" + windsurfrulesTemplate(), "utf-8");
11664
+ fs30.writeFileSync(rulesPath, existing.trimEnd() + "\n\n---\n\n" + windsurfrulesTemplate(), "utf-8");
11521
11665
  results.push({ type: "windsurf", filePath: ".windsurfrules", action: "appended" });
11522
11666
  } else {
11523
- fs29.writeFileSync(rulesPath, windsurfrulesTemplate(), "utf-8");
11667
+ fs30.writeFileSync(rulesPath, windsurfrulesTemplate(), "utf-8");
11524
11668
  results.push({ type: "windsurf", filePath: ".windsurfrules", action: "created" });
11525
11669
  }
11526
11670
  } catch (err) {
@@ -11533,21 +11677,21 @@ function handleWindsurfSecondary(root, results) {
11533
11677
  }
11534
11678
  }
11535
11679
  function handleClineSecondary(root, results) {
11536
- const rooPath = path32.resolve(root, ".roo", "rules", "kuma.md");
11680
+ const rooPath = path33.resolve(root, ".roo", "rules", "kuma.md");
11537
11681
  if (!results.some((r) => r.filePath === ".roo/rules/kuma.md")) {
11538
11682
  try {
11539
- const dir = path32.dirname(rooPath);
11540
- if (fs29.existsSync(rooPath)) {
11541
- const existing = fs29.readFileSync(rooPath, "utf-8");
11683
+ const dir = path33.dirname(rooPath);
11684
+ if (fs30.existsSync(rooPath)) {
11685
+ const existing = fs30.readFileSync(rooPath, "utf-8");
11542
11686
  if (existing.includes("kuma-mcp") || existing.includes("Kuma MCP")) {
11543
11687
  results.push({ type: "cline", filePath: ".roo/rules/kuma.md", action: "skipped" });
11544
11688
  } else {
11545
- fs29.writeFileSync(rooPath, existing.trimEnd() + "\n\n---\n\n" + rooRulesTemplate(), "utf-8");
11689
+ fs30.writeFileSync(rooPath, existing.trimEnd() + "\n\n---\n\n" + rooRulesTemplate(), "utf-8");
11546
11690
  results.push({ type: "cline", filePath: ".roo/rules/kuma.md", action: "appended" });
11547
11691
  }
11548
11692
  } else {
11549
- if (!fs29.existsSync(dir)) fs29.mkdirSync(dir, { recursive: true });
11550
- fs29.writeFileSync(rooPath, rooRulesTemplate(), "utf-8");
11693
+ if (!fs30.existsSync(dir)) fs30.mkdirSync(dir, { recursive: true });
11694
+ fs30.writeFileSync(rooPath, rooRulesTemplate(), "utf-8");
11551
11695
  results.push({ type: "cline", filePath: ".roo/rules/kuma.md", action: "created" });
11552
11696
  }
11553
11697
  } catch (err) {
@@ -11559,21 +11703,21 @@ function handleClineSecondary(root, results) {
11559
11703
  });
11560
11704
  }
11561
11705
  }
11562
- const traePath = path32.resolve(root, ".trae", "rules", "kuma.md");
11706
+ const traePath = path33.resolve(root, ".trae", "rules", "kuma.md");
11563
11707
  if (!results.some((r) => r.filePath === ".trae/rules/kuma.md")) {
11564
11708
  try {
11565
- const dir = path32.dirname(traePath);
11566
- if (fs29.existsSync(traePath)) {
11567
- const existing = fs29.readFileSync(traePath, "utf-8");
11709
+ const dir = path33.dirname(traePath);
11710
+ if (fs30.existsSync(traePath)) {
11711
+ const existing = fs30.readFileSync(traePath, "utf-8");
11568
11712
  if (existing.includes("Kuma MCP")) {
11569
11713
  results.push({ type: "cline", filePath: ".trae/rules/kuma.md", action: "skipped" });
11570
11714
  } else {
11571
- fs29.writeFileSync(traePath, existing.trimEnd() + "\n\n---\n\n" + traeRulesTemplate(), "utf-8");
11715
+ fs30.writeFileSync(traePath, existing.trimEnd() + "\n\n---\n\n" + traeRulesTemplate(), "utf-8");
11572
11716
  results.push({ type: "cline", filePath: ".trae/rules/kuma.md", action: "appended" });
11573
11717
  }
11574
11718
  } else {
11575
- if (!fs29.existsSync(dir)) fs29.mkdirSync(dir, { recursive: true });
11576
- fs29.writeFileSync(traePath, traeRulesTemplate(), "utf-8");
11719
+ if (!fs30.existsSync(dir)) fs30.mkdirSync(dir, { recursive: true });
11720
+ fs30.writeFileSync(traePath, traeRulesTemplate(), "utf-8");
11577
11721
  results.push({ type: "cline", filePath: ".trae/rules/kuma.md", action: "created" });
11578
11722
  }
11579
11723
  } catch (err) {
@@ -11585,21 +11729,21 @@ function handleClineSecondary(root, results) {
11585
11729
  });
11586
11730
  }
11587
11731
  }
11588
- const qoderPath = path32.resolve(root, ".qoder", "rules", "kuma.md");
11732
+ const qoderPath = path33.resolve(root, ".qoder", "rules", "kuma.md");
11589
11733
  if (!results.some((r) => r.filePath === ".qoder/rules/kuma.md")) {
11590
11734
  try {
11591
- const dir = path32.dirname(qoderPath);
11592
- if (fs29.existsSync(qoderPath)) {
11593
- const existing = fs29.readFileSync(qoderPath, "utf-8");
11735
+ const dir = path33.dirname(qoderPath);
11736
+ if (fs30.existsSync(qoderPath)) {
11737
+ const existing = fs30.readFileSync(qoderPath, "utf-8");
11594
11738
  if (existing.includes("Kuma MCP")) {
11595
11739
  results.push({ type: "cline", filePath: ".qoder/rules/kuma.md", action: "skipped" });
11596
11740
  } else {
11597
- fs29.writeFileSync(qoderPath, existing.trimEnd() + "\n\n---\n\n" + qoderRulesTemplate(), "utf-8");
11741
+ fs30.writeFileSync(qoderPath, existing.trimEnd() + "\n\n---\n\n" + qoderRulesTemplate(), "utf-8");
11598
11742
  results.push({ type: "cline", filePath: ".qoder/rules/kuma.md", action: "appended" });
11599
11743
  }
11600
11744
  } else {
11601
- if (!fs29.existsSync(dir)) fs29.mkdirSync(dir, { recursive: true });
11602
- fs29.writeFileSync(qoderPath, qoderRulesTemplate(), "utf-8");
11745
+ if (!fs30.existsSync(dir)) fs30.mkdirSync(dir, { recursive: true });
11746
+ fs30.writeFileSync(qoderPath, qoderRulesTemplate(), "utf-8");
11603
11747
  results.push({ type: "cline", filePath: ".qoder/rules/kuma.md", action: "created" });
11604
11748
  }
11605
11749
  } catch (err) {
@@ -11613,18 +11757,18 @@ function handleClineSecondary(root, results) {
11613
11757
  }
11614
11758
  }
11615
11759
  function handleAiderSecondary(root, results) {
11616
- const ymlPath = path32.resolve(root, ".aider.conf.yml");
11760
+ const ymlPath = path33.resolve(root, ".aider.conf.yml");
11617
11761
  if (results.some((r) => r.filePath === ".aider.conf.yml")) return;
11618
11762
  try {
11619
11763
  const conventionsRef = "read: CONVENTIONS.md";
11620
- if (fs29.existsSync(ymlPath)) {
11621
- const existingContent = fs29.readFileSync(ymlPath, "utf-8");
11764
+ if (fs30.existsSync(ymlPath)) {
11765
+ const existingContent = fs30.readFileSync(ymlPath, "utf-8");
11622
11766
  if (existingContent.includes("CONVENTIONS.md") || existingContent.includes("kuma")) {
11623
11767
  results.push({ type: "aider", filePath: ".aider.conf.yml", action: "skipped" });
11624
11768
  return;
11625
11769
  }
11626
11770
  const newContent = existingContent.trimEnd() + "\n\n# Kuma MCP conventions\n" + conventionsRef + "\n";
11627
- fs29.writeFileSync(ymlPath, newContent, "utf-8");
11771
+ fs30.writeFileSync(ymlPath, newContent, "utf-8");
11628
11772
  results.push({ type: "aider", filePath: ".aider.conf.yml", action: "appended" });
11629
11773
  } else {
11630
11774
  const content = [
@@ -11634,7 +11778,7 @@ function handleAiderSecondary(root, results) {
11634
11778
  conventionsRef,
11635
11779
  ""
11636
11780
  ].join("\n");
11637
- fs29.writeFileSync(ymlPath, content, "utf-8");
11781
+ fs30.writeFileSync(ymlPath, content, "utf-8");
11638
11782
  results.push({ type: "aider", filePath: ".aider.conf.yml", action: "created" });
11639
11783
  }
11640
11784
  } catch (err) {
@@ -11647,10 +11791,10 @@ function handleAiderSecondary(root, results) {
11647
11791
  }
11648
11792
  }
11649
11793
  function handleCopilotSecondary(root, results) {
11650
- const skillPath = path32.resolve(root, ".github/skills/kuma/SKILL.md");
11794
+ const skillPath = path33.resolve(root, ".github/skills/kuma/SKILL.md");
11651
11795
  if (results.some((r) => r.filePath === ".github/skills/kuma/SKILL.md")) return;
11652
11796
  try {
11653
- const dir = path32.dirname(skillPath);
11797
+ const dir = path33.dirname(skillPath);
11654
11798
  const content = [
11655
11799
  "---",
11656
11800
  "name: kuma-mcp",
@@ -11661,17 +11805,17 @@ function handleCopilotSecondary(root, results) {
11661
11805
  "",
11662
11806
  "\u{1F4D6} Read `.kuma/init.md` for detailed rules."
11663
11807
  ].join("\n");
11664
- if (fs29.existsSync(skillPath)) {
11665
- const existingContent = fs29.readFileSync(skillPath, "utf-8");
11808
+ if (fs30.existsSync(skillPath)) {
11809
+ const existingContent = fs30.readFileSync(skillPath, "utf-8");
11666
11810
  if (existingContent.includes("kuma")) {
11667
11811
  results.push({ type: "copilot", filePath: ".github/skills/kuma/SKILL.md", action: "skipped" });
11668
11812
  return;
11669
11813
  }
11670
- fs29.writeFileSync(skillPath, existingContent.trimEnd() + "\n\n" + content, "utf-8");
11814
+ fs30.writeFileSync(skillPath, existingContent.trimEnd() + "\n\n" + content, "utf-8");
11671
11815
  results.push({ type: "copilot", filePath: ".github/skills/kuma/SKILL.md", action: "appended" });
11672
11816
  } else {
11673
- if (!fs29.existsSync(dir)) fs29.mkdirSync(dir, { recursive: true });
11674
- fs29.writeFileSync(skillPath, content, "utf-8");
11817
+ if (!fs30.existsSync(dir)) fs30.mkdirSync(dir, { recursive: true });
11818
+ fs30.writeFileSync(skillPath, content, "utf-8");
11675
11819
  results.push({ type: "copilot", filePath: ".github/skills/kuma/SKILL.md", action: "created" });
11676
11820
  }
11677
11821
  } catch (err) {
@@ -11684,21 +11828,21 @@ function handleCopilotSecondary(root, results) {
11684
11828
  }
11685
11829
  }
11686
11830
  function handleOpenclawSecondary(root, results) {
11687
- const mcpPath = path32.resolve(root, ".agents/mcp_config.json");
11831
+ const mcpPath = path33.resolve(root, ".agents/mcp_config.json");
11688
11832
  if (results.some((r) => r.filePath === ".agents/mcp_config.json")) return;
11689
11833
  try {
11690
- const dir = path32.dirname(mcpPath);
11691
- if (fs29.existsSync(mcpPath)) {
11692
- const existingContent = fs29.readFileSync(mcpPath, "utf-8");
11834
+ const dir = path33.dirname(mcpPath);
11835
+ if (fs30.existsSync(mcpPath)) {
11836
+ const existingContent = fs30.readFileSync(mcpPath, "utf-8");
11693
11837
  if (existingContent.includes("kuma")) return;
11694
11838
  const parsed = JSON.parse(existingContent);
11695
11839
  parsed.mcpServers = parsed.mcpServers || {};
11696
11840
  parsed.mcpServers.kuma = { command: "npx", args: ["-y", "@plumpslabs/kuma"], env: {} };
11697
- fs29.writeFileSync(mcpPath, JSON.stringify(parsed, null, 2) + "\n", "utf-8");
11841
+ fs30.writeFileSync(mcpPath, JSON.stringify(parsed, null, 2) + "\n", "utf-8");
11698
11842
  results.push({ type: "openclaw", filePath: ".agents/mcp_config.json", action: "appended" });
11699
11843
  } else {
11700
- if (!fs29.existsSync(dir)) fs29.mkdirSync(dir, { recursive: true });
11701
- fs29.writeFileSync(mcpPath, antigravityMcpConfigTemplate(), "utf-8");
11844
+ if (!fs30.existsSync(dir)) fs30.mkdirSync(dir, { recursive: true });
11845
+ fs30.writeFileSync(mcpPath, antigravityMcpConfigTemplate(), "utf-8");
11702
11846
  results.push({ type: "openclaw", filePath: ".agents/mcp_config.json", action: "created" });
11703
11847
  }
11704
11848
  } catch (err) {
@@ -11711,20 +11855,20 @@ function handleOpenclawSecondary(root, results) {
11711
11855
  }
11712
11856
  }
11713
11857
  function handleInitMdGeneration(root, results) {
11714
- const initMdPath = path32.resolve(root, ".kuma/init.md");
11858
+ const initMdPath = path33.resolve(root, ".kuma/init.md");
11715
11859
  try {
11716
- const kumaDir = path32.dirname(initMdPath);
11717
- if (!fs29.existsSync(kumaDir)) fs29.mkdirSync(kumaDir, { recursive: true });
11718
- if (fs29.existsSync(initMdPath)) {
11719
- const existing = fs29.readFileSync(initMdPath, "utf-8");
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");
11720
11864
  if (existing.includes("_Generated by Kuma MCP_")) {
11721
11865
  results.push({ type: "claude", filePath: ".kuma/init.md", action: "skipped" });
11722
11866
  return;
11723
11867
  }
11724
- fs29.writeFileSync(initMdPath, existing.trimEnd() + "\n\n" + generateInitMdContent(), "utf-8");
11868
+ fs30.writeFileSync(initMdPath, existing.trimEnd() + "\n\n" + generateInitMdContent(), "utf-8");
11725
11869
  results.push({ type: "claude", filePath: ".kuma/init.md", action: "appended" });
11726
11870
  } else {
11727
- fs29.writeFileSync(initMdPath, generateInitMdContent(), "utf-8");
11871
+ fs30.writeFileSync(initMdPath, generateInitMdContent(), "utf-8");
11728
11872
  results.push({ type: "claude", filePath: ".kuma/init.md", action: "created" });
11729
11873
  }
11730
11874
  } catch (err) {
@@ -11737,20 +11881,20 @@ function handleInitMdGeneration(root, results) {
11737
11881
  }
11738
11882
  }
11739
11883
  function handleCodewhaleSecondary(root, results) {
11740
- const mcpPath = path32.resolve(root, ".codewhale/mcp.json");
11884
+ const mcpPath = path33.resolve(root, ".codewhale/mcp.json");
11741
11885
  if (results.some((r) => r.filePath === ".codewhale/mcp.json")) return;
11742
11886
  try {
11743
- const dir = path32.dirname(mcpPath);
11744
- if (fs29.existsSync(mcpPath)) {
11745
- const existingContent = fs29.readFileSync(mcpPath, "utf-8");
11887
+ const dir = path33.dirname(mcpPath);
11888
+ if (fs30.existsSync(mcpPath)) {
11889
+ const existingContent = fs30.readFileSync(mcpPath, "utf-8");
11746
11890
  if (existingContent.includes("kuma")) return;
11747
11891
  const parsed = JSON.parse(existingContent);
11748
11892
  parsed.mcpServers = parsed.mcpServers || {};
11749
11893
  parsed.mcpServers.kuma = { command: "npx", args: ["-y", "@plumpslabs/kuma"], env: {} };
11750
- fs29.writeFileSync(mcpPath, JSON.stringify(parsed, null, 2) + "\n", "utf-8");
11894
+ fs30.writeFileSync(mcpPath, JSON.stringify(parsed, null, 2) + "\n", "utf-8");
11751
11895
  results.push({ type: "codewhale", filePath: ".codewhale/mcp.json", action: "appended" });
11752
11896
  } else {
11753
- if (!fs29.existsSync(dir)) fs29.mkdirSync(dir, { recursive: true });
11897
+ if (!fs30.existsSync(dir)) fs30.mkdirSync(dir, { recursive: true });
11754
11898
  const config = {
11755
11899
  mcpServers: {
11756
11900
  kuma: {
@@ -11760,7 +11904,7 @@ function handleCodewhaleSecondary(root, results) {
11760
11904
  }
11761
11905
  }
11762
11906
  };
11763
- fs29.writeFileSync(mcpPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
11907
+ fs30.writeFileSync(mcpPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
11764
11908
  results.push({ type: "codewhale", filePath: ".codewhale/mcp.json", action: "created" });
11765
11909
  }
11766
11910
  } catch (err) {
@@ -11773,7 +11917,7 @@ function handleCodewhaleSecondary(root, results) {
11773
11917
  }
11774
11918
  }
11775
11919
  function handleClaudeSecondary(root, results) {
11776
- const settingsPath = path32.resolve(root, ".claude", "settings.json");
11920
+ const settingsPath = path33.resolve(root, ".claude", "settings.json");
11777
11921
  const hookBlock = {
11778
11922
  hooks: {
11779
11923
  PreToolUse: [
@@ -11804,8 +11948,8 @@ function handleClaudeSecondary(root, results) {
11804
11948
  }
11805
11949
  };
11806
11950
  try {
11807
- if (fs29.existsSync(settingsPath)) {
11808
- const existing = JSON.parse(fs29.readFileSync(settingsPath, "utf-8"));
11951
+ if (fs30.existsSync(settingsPath)) {
11952
+ const existing = JSON.parse(fs30.readFileSync(settingsPath, "utf-8"));
11809
11953
  const existingHooks = existing.hooks || {};
11810
11954
  const mergedPre = [...existingHooks.PreToolUse || []];
11811
11955
  for (const entry of hookBlock.hooks.PreToolUse) {
@@ -11829,12 +11973,12 @@ function handleClaudeSecondary(root, results) {
11829
11973
  ...existing,
11830
11974
  hooks: { ...existingHooks, PreToolUse: mergedPre, SessionStart: mergedStart, PreCompact: mergedCompact }
11831
11975
  };
11832
- fs29.writeFileSync(settingsPath, JSON.stringify(merged, null, 2) + "\n", "utf-8");
11976
+ fs30.writeFileSync(settingsPath, JSON.stringify(merged, null, 2) + "\n", "utf-8");
11833
11977
  results.push({ type: "claude", filePath: ".claude/settings.json", action: "appended" });
11834
11978
  } else {
11835
- const dir = path32.dirname(settingsPath);
11836
- if (!fs29.existsSync(dir)) fs29.mkdirSync(dir, { recursive: true });
11837
- fs29.writeFileSync(settingsPath, JSON.stringify(hookBlock, null, 2) + "\n", "utf-8");
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");
11838
11982
  results.push({ type: "claude", filePath: ".claude/settings.json", action: "created" });
11839
11983
  }
11840
11984
  } catch (err) {
@@ -11845,10 +11989,10 @@ function handleClaudeSecondary(root, results) {
11845
11989
  error: err instanceof Error ? err.message : String(err)
11846
11990
  });
11847
11991
  }
11848
- const skillPath = path32.resolve(root, ".claude", "skills", "kuma", "SKILL.md");
11992
+ const skillPath = path33.resolve(root, ".claude", "skills", "kuma", "SKILL.md");
11849
11993
  if (!results.some((r) => r.filePath === ".claude/skills/kuma/SKILL.md")) {
11850
11994
  try {
11851
- const dir = path32.dirname(skillPath);
11995
+ const dir = path33.dirname(skillPath);
11852
11996
  const content = [
11853
11997
  "---",
11854
11998
  "name: kuma-mcp",
@@ -11860,17 +12004,17 @@ function handleClaudeSecondary(root, results) {
11860
12004
  "\u{1F4D6} Read `.kuma/init.md` for detailed rules.",
11861
12005
  "\u{1F4C2} Readable state: `.kuma/KNOWN_GOTCHAS.md` (gotchas) \xB7 `.kuma/memories/decisions.md` (decisions)"
11862
12006
  ].join("\n");
11863
- if (fs29.existsSync(skillPath)) {
11864
- const existing = fs29.readFileSync(skillPath, "utf-8");
12007
+ if (fs30.existsSync(skillPath)) {
12008
+ const existing = fs30.readFileSync(skillPath, "utf-8");
11865
12009
  if (existing.includes("kuma-mcp")) {
11866
12010
  results.push({ type: "claude", filePath: ".claude/skills/kuma/SKILL.md", action: "skipped" });
11867
12011
  } else {
11868
- fs29.writeFileSync(skillPath, existing.trimEnd() + "\n\n---\n\n" + content, "utf-8");
12012
+ fs30.writeFileSync(skillPath, existing.trimEnd() + "\n\n---\n\n" + content, "utf-8");
11869
12013
  results.push({ type: "claude", filePath: ".claude/skills/kuma/SKILL.md", action: "appended" });
11870
12014
  }
11871
12015
  } else {
11872
- if (!fs29.existsSync(dir)) fs29.mkdirSync(dir, { recursive: true });
11873
- fs29.writeFileSync(skillPath, content, "utf-8");
12016
+ if (!fs30.existsSync(dir)) fs30.mkdirSync(dir, { recursive: true });
12017
+ fs30.writeFileSync(skillPath, content, "utf-8");
11874
12018
  results.push({ type: "claude", filePath: ".claude/skills/kuma/SKILL.md", action: "created" });
11875
12019
  }
11876
12020
  } catch (err) {
@@ -11884,27 +12028,27 @@ function handleClaudeSecondary(root, results) {
11884
12028
  }
11885
12029
  }
11886
12030
  function writeHooksFile(root, relPath, type, results, build) {
11887
- const fullPath = path32.resolve(root, relPath);
12031
+ const fullPath = path33.resolve(root, relPath);
11888
12032
  try {
11889
12033
  let existing = {};
11890
12034
  let existed = false;
11891
- if (fs29.existsSync(fullPath)) {
12035
+ if (fs30.existsSync(fullPath)) {
11892
12036
  existed = true;
11893
12037
  try {
11894
- existing = JSON.parse(fs29.readFileSync(fullPath, "utf-8"));
12038
+ existing = JSON.parse(fs30.readFileSync(fullPath, "utf-8"));
11895
12039
  } catch {
11896
12040
  existing = {};
11897
12041
  }
11898
12042
  } else {
11899
- const dir = path32.dirname(fullPath);
11900
- if (!fs29.existsSync(dir)) fs29.mkdirSync(dir, { recursive: true });
12043
+ const dir = path33.dirname(fullPath);
12044
+ if (!fs30.existsSync(dir)) fs30.mkdirSync(dir, { recursive: true });
11901
12045
  }
11902
12046
  const { doc, changed } = build(existing);
11903
12047
  if (!changed) {
11904
12048
  results.push({ type, filePath: relPath, action: "skipped" });
11905
12049
  return;
11906
12050
  }
11907
- fs29.writeFileSync(fullPath, JSON.stringify(doc, null, 2) + "\n", "utf-8");
12051
+ fs30.writeFileSync(fullPath, JSON.stringify(doc, null, 2) + "\n", "utf-8");
11908
12052
  results.push({ type, filePath: relPath, action: existed ? "appended" : "created" });
11909
12053
  } catch (err) {
11910
12054
  results.push({ type, filePath: relPath, action: "error", error: err instanceof Error ? err.message : String(err) });
@@ -11985,18 +12129,18 @@ function handleCodexHooks(root, results) {
11985
12129
  });
11986
12130
  }
11987
12131
  function handleCursorGotchaRules(root, results) {
11988
- const rulesDir2 = path32.resolve(root, ".cursor", "rules", "kuma-gotchas");
12132
+ const rulesDir2 = path33.resolve(root, ".cursor", "rules", "kuma-gotchas");
11989
12133
  try {
11990
12134
  let gotchas = [];
11991
12135
  try {
11992
12136
  gotchas = getActiveGotchas().filter((g) => g.severity === "high" || g.severity === "critical");
11993
12137
  } catch {
11994
12138
  }
11995
- if (fs29.existsSync(rulesDir2)) {
11996
- for (const f of fs29.readdirSync(rulesDir2)) {
12139
+ if (fs30.existsSync(rulesDir2)) {
12140
+ for (const f of fs30.readdirSync(rulesDir2)) {
11997
12141
  if (f.endsWith(".mdc")) {
11998
12142
  try {
11999
- fs29.rmSync(path32.join(rulesDir2, f), { force: true });
12143
+ fs30.rmSync(path33.join(rulesDir2, f), { force: true });
12000
12144
  } catch {
12001
12145
  }
12002
12146
  }
@@ -12006,7 +12150,7 @@ function handleCursorGotchaRules(root, results) {
12006
12150
  results.push({ type: "cursor", filePath: ".cursor/rules/kuma-gotchas/", action: "skipped" });
12007
12151
  return;
12008
12152
  }
12009
- fs29.mkdirSync(rulesDir2, { recursive: true });
12153
+ fs30.mkdirSync(rulesDir2, { recursive: true });
12010
12154
  const seen = /* @__PURE__ */ new Set();
12011
12155
  let created = 0;
12012
12156
  for (const g of gotchas) {
@@ -12027,7 +12171,7 @@ function handleCursorGotchaRules(root, results) {
12027
12171
  "`kuma_context({ action: 'history', target: '<file>' })`",
12028
12172
  ""
12029
12173
  ].join("\n");
12030
- fs29.writeFileSync(path32.join(rulesDir2, `${slug2}.mdc`), md, "utf-8");
12174
+ fs30.writeFileSync(path33.join(rulesDir2, `${slug2}.mdc`), md, "utf-8");
12031
12175
  created++;
12032
12176
  }
12033
12177
  results.push({
@@ -12054,28 +12198,28 @@ function runInit(options) {
12054
12198
  let agentsMdHandled = false;
12055
12199
  for (const type of selected) {
12056
12200
  const relativePath = configFilePath(type);
12057
- const fullPath = path32.resolve(root, relativePath);
12201
+ const fullPath = path33.resolve(root, relativePath);
12058
12202
  const getTemplate = TEMPLATES[type];
12059
12203
  try {
12060
12204
  if (AGENTS_MD_TYPES.includes(type) && !agentsMdHandled) {
12061
12205
  agentsMdHandled = true;
12062
12206
  const combinedContent = getCombinedAgentsMd(new Set(agentsMdSelected));
12063
- if (fs29.existsSync(fullPath)) {
12207
+ if (fs30.existsSync(fullPath)) {
12064
12208
  if (options.skipExisting) {
12065
12209
  results.push({ type, filePath: relativePath, action: "skipped" });
12066
12210
  } else {
12067
- const existingContent = fs29.readFileSync(fullPath, "utf-8");
12211
+ const existingContent = fs30.readFileSync(fullPath, "utf-8");
12068
12212
  if (existingContent.includes("_Generated by Kuma MCP_")) {
12069
12213
  results.push({ type, filePath: relativePath, action: "skipped" });
12070
12214
  } else {
12071
- fs29.writeFileSync(fullPath, existingContent.trimEnd() + "\n\n" + combinedContent, "utf-8");
12215
+ fs30.writeFileSync(fullPath, existingContent.trimEnd() + "\n\n" + combinedContent, "utf-8");
12072
12216
  results.push({ type, filePath: relativePath, action: "appended" });
12073
12217
  }
12074
12218
  }
12075
12219
  } else {
12076
- const dir = path32.dirname(fullPath);
12077
- if (!fs29.existsSync(dir)) fs29.mkdirSync(dir, { recursive: true });
12078
- fs29.writeFileSync(fullPath, combinedContent, "utf-8");
12220
+ const dir = path33.dirname(fullPath);
12221
+ if (!fs30.existsSync(dir)) fs30.mkdirSync(dir, { recursive: true });
12222
+ fs30.writeFileSync(fullPath, combinedContent, "utf-8");
12079
12223
  results.push({ type, filePath: relativePath, action: "created" });
12080
12224
  }
12081
12225
  if (selectedSet.has("opencode")) handleOpencodeSecondary(root, results);
@@ -12087,12 +12231,12 @@ function runInit(options) {
12087
12231
  continue;
12088
12232
  } else {
12089
12233
  const template = getTemplate();
12090
- if (fs29.existsSync(fullPath)) {
12234
+ if (fs30.existsSync(fullPath)) {
12091
12235
  if (options.skipExisting) {
12092
12236
  results.push({ type, filePath: relativePath, action: "skipped" });
12093
12237
  continue;
12094
12238
  }
12095
- const existingContent = fs29.readFileSync(fullPath, "utf-8");
12239
+ const existingContent = fs30.readFileSync(fullPath, "utf-8");
12096
12240
  if (existingContent.includes("_Generated by Kuma MCP_")) {
12097
12241
  if (type === "antigravity") {
12098
12242
  handleAntigravitySecondary(root, results);
@@ -12109,14 +12253,14 @@ function runInit(options) {
12109
12253
  continue;
12110
12254
  }
12111
12255
  const newContent = existingContent.trimEnd() + APPEND_SEPARATOR + template;
12112
- fs29.writeFileSync(fullPath, newContent, "utf-8");
12256
+ fs30.writeFileSync(fullPath, newContent, "utf-8");
12113
12257
  results.push({ type, filePath: relativePath, action: "appended" });
12114
12258
  } else {
12115
- const dir = path32.dirname(fullPath);
12116
- if (!fs29.existsSync(dir)) {
12117
- fs29.mkdirSync(dir, { recursive: true });
12259
+ const dir = path33.dirname(fullPath);
12260
+ if (!fs30.existsSync(dir)) {
12261
+ fs30.mkdirSync(dir, { recursive: true });
12118
12262
  }
12119
- fs29.writeFileSync(fullPath, template, "utf-8");
12263
+ fs30.writeFileSync(fullPath, template, "utf-8");
12120
12264
  results.push({ type, filePath: relativePath, action: "created" });
12121
12265
  }
12122
12266
  if (type === "antigravity") {
@@ -12288,8 +12432,8 @@ var compactionContext_exports = {};
12288
12432
  __export(compactionContext_exports, {
12289
12433
  getCompactionContext: () => getCompactionContext
12290
12434
  });
12291
- import fs30 from "fs";
12292
- import path33 from "path";
12435
+ import fs31 from "fs";
12436
+ import path34 from "path";
12293
12437
  async function getCompactionContext() {
12294
12438
  const parts = [];
12295
12439
  try {
@@ -12302,8 +12446,8 @@ async function getCompactionContext() {
12302
12446
  } catch {
12303
12447
  }
12304
12448
  try {
12305
- const dbFile = path33.join(getProjectRoot(), ".kuma", "kuma.db");
12306
- if (fs30.existsSync(dbFile)) {
12449
+ const dbFile = path34.join(getProjectRoot(), ".kuma", "kuma.db");
12450
+ if (fs31.existsSync(dbFile)) {
12307
12451
  const { getDb: getDb2 } = await Promise.resolve().then(() => (init_kumaDb(), kumaDb_exports));
12308
12452
  const db = await getDb2();
12309
12453
  const stmt = db.prepare(
@@ -12329,9 +12473,9 @@ async function getCompactionContext() {
12329
12473
  } catch {
12330
12474
  }
12331
12475
  try {
12332
- const cpDir = path33.join(getProjectRoot(), ".kuma", "checkpoints");
12333
- if (fs30.existsSync(cpDir)) {
12334
- const cps = fs30.readdirSync(cpDir).slice(0, 3);
12476
+ const cpDir = path34.join(getProjectRoot(), ".kuma", "checkpoints");
12477
+ if (fs31.existsSync(cpDir)) {
12478
+ const cps = fs31.readdirSync(cpDir).slice(0, 3);
12335
12479
  if (cps.length > 0) parts.push(`Checkpoints: ${cps.join(", ")}`);
12336
12480
  }
12337
12481
  } catch {
@@ -12349,6 +12493,190 @@ var init_compactionContext = __esm({
12349
12493
  }
12350
12494
  });
12351
12495
 
12496
+ // src/engine/kumaDaemon.ts
12497
+ var kumaDaemon_exports = {};
12498
+ __export(kumaDaemon_exports, {
12499
+ DEFAULT_INTERVAL_MS: () => DEFAULT_INTERVAL_MS,
12500
+ daemonRunChild: () => daemonRunChild,
12501
+ daemonStart: () => daemonStart,
12502
+ daemonStatus: () => daemonStatus,
12503
+ daemonStop: () => daemonStop,
12504
+ daemonTick: () => daemonTick
12505
+ });
12506
+ import fs32 from "fs";
12507
+ import path35 from "path";
12508
+ import { spawn } from "child_process";
12509
+ function paths(root) {
12510
+ const r = root || getProjectRoot();
12511
+ return {
12512
+ pid: path35.join(r, PID_FILE),
12513
+ status: path35.join(r, STATUS_FILE),
12514
+ log: path35.join(r, LOG_FILE)
12515
+ };
12516
+ }
12517
+ function readPid(root) {
12518
+ try {
12519
+ const fp = paths(root).pid;
12520
+ if (!fs32.existsSync(fp)) return null;
12521
+ const pid = Number(fs32.readFileSync(fp, "utf-8").trim());
12522
+ return Number.isFinite(pid) && pid > 0 ? pid : null;
12523
+ } catch {
12524
+ return null;
12525
+ }
12526
+ }
12527
+ function isAlive(pid) {
12528
+ try {
12529
+ process.kill(pid, 0);
12530
+ return true;
12531
+ } catch {
12532
+ return false;
12533
+ }
12534
+ }
12535
+ async function daemonTick(root) {
12536
+ const r = root || getProjectRoot();
12537
+ const p = paths(r);
12538
+ const notes = [];
12539
+ try {
12540
+ const { syncModifiedFiles: syncModifiedFiles2 } = await Promise.resolve().then(() => (init_kumaCodeScanner(), kumaCodeScanner_exports));
12541
+ const scan = await syncModifiedFiles2(50);
12542
+ notes.push(`map: ${scan.filesScanned}f/${scan.nodeCount}n/${scan.edgeCount}e`);
12543
+ } catch (err) {
12544
+ notes.push(`map: skipped (${err})`);
12545
+ }
12546
+ try {
12547
+ const { refreshPackageBriefs: refreshPackageBriefs2 } = await Promise.resolve().then(() => (init_packageBriefs(), packageBriefs_exports));
12548
+ const { count } = await refreshPackageBriefs2();
12549
+ notes.push(`briefs: ${count}`);
12550
+ } catch {
12551
+ notes.push("briefs: skipped");
12552
+ }
12553
+ try {
12554
+ const { detectDrift: detectDrift2 } = await Promise.resolve().then(() => (init_kumaDriftDetector(), kumaDriftDetector_exports));
12555
+ const records = await detectDrift2();
12556
+ const stale = records.filter((x) => x.severity === "stale" || x.severity === "missing").length;
12557
+ notes.push(`drift: ${stale}/${records.length} stale`);
12558
+ } catch {
12559
+ notes.push("drift: skipped");
12560
+ }
12561
+ try {
12562
+ const { clearDirty: clearDirty2 } = await Promise.resolve().then(() => (init_cacheFreshness(), cacheFreshness_exports));
12563
+ clearDirty2();
12564
+ } catch {
12565
+ }
12566
+ const status = {
12567
+ lastRunAt: Date.now(),
12568
+ lastResult: notes.join(" \xB7 ")
12569
+ };
12570
+ try {
12571
+ 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");
12574
+ } catch {
12575
+ }
12576
+ return notes.join(" \xB7 ");
12577
+ }
12578
+ async function runLoop(intervalMs) {
12579
+ const r = getProjectRoot();
12580
+ const p = paths(r);
12581
+ const log = (msg) => {
12582
+ try {
12583
+ fs32.appendFileSync(p.log, `${(/* @__PURE__ */ new Date()).toISOString()} ${msg}
12584
+ `, "utf-8");
12585
+ } catch {
12586
+ }
12587
+ };
12588
+ log(`daemon started (interval ${intervalMs}ms)`);
12589
+ for (; ; ) {
12590
+ try {
12591
+ const res = await daemonTick(r);
12592
+ log(`tick: ${res}`);
12593
+ } catch (err) {
12594
+ log(`tick failed: ${err}`);
12595
+ }
12596
+ await new Promise((resolve) => setTimeout(resolve, intervalMs));
12597
+ }
12598
+ }
12599
+ async function daemonStart(intervalMs = DEFAULT_INTERVAL_MS, root) {
12600
+ const r = root || getProjectRoot();
12601
+ const p = paths(r);
12602
+ const existing = readPid(r);
12603
+ if (existing && isAlive(existing)) {
12604
+ return `\u{1F43B} Daemon already running (pid ${existing}). Use \`kuma daemon stop\` first.`;
12605
+ }
12606
+ const entry = process.argv[1];
12607
+ const child = spawn(process.execPath, [entry, "daemon", "run", String(intervalMs)], {
12608
+ cwd: r,
12609
+ detached: true,
12610
+ stdio: "ignore"
12611
+ });
12612
+ child.unref();
12613
+ try {
12614
+ fs32.writeFileSync(p.pid, String(child.pid), "utf-8");
12615
+ fs32.writeFileSync(
12616
+ p.status,
12617
+ JSON.stringify({ running: true, pid: child.pid, startedAt: Date.now(), lastRunAt: null, lastResult: null, intervalMs }, null, 2),
12618
+ "utf-8"
12619
+ );
12620
+ } catch {
12621
+ }
12622
+ return `\u{1F43B} Daemon started (pid ${child.pid}, every ${Math.round(intervalMs / 6e4)}m). Status: .kuma/daemon-status.json`;
12623
+ }
12624
+ async function daemonStop(root) {
12625
+ const r = root || getProjectRoot();
12626
+ const p = paths(r);
12627
+ const pid = readPid(r);
12628
+ if (!pid) return "\u{1F43B} Daemon not running (no pid file).";
12629
+ if (!isAlive(pid)) {
12630
+ try {
12631
+ fs32.rmSync(p.pid, { force: true });
12632
+ } catch {
12633
+ }
12634
+ return "\u{1F43B} Daemon pid file was stale \u2014 cleaned up (process already gone).";
12635
+ }
12636
+ try {
12637
+ process.kill(pid, "SIGTERM");
12638
+ try {
12639
+ fs32.rmSync(p.pid, { force: true });
12640
+ } catch {
12641
+ }
12642
+ return `\u{1F43B} Daemon stopped (was pid ${pid}).`;
12643
+ } catch (err) {
12644
+ return `\u{1F43B} Could not stop daemon pid ${pid}: ${err}`;
12645
+ }
12646
+ }
12647
+ async function daemonStatus(root) {
12648
+ const r = root || getProjectRoot();
12649
+ const p = paths(r);
12650
+ const pid = readPid(r);
12651
+ let status = { running: false, pid: null, startedAt: null, lastRunAt: null, lastResult: null, intervalMs: DEFAULT_INTERVAL_MS };
12652
+ try {
12653
+ if (fs32.existsSync(p.status)) status = { ...status, ...JSON.parse(fs32.readFileSync(p.status, "utf-8")) };
12654
+ } catch {
12655
+ }
12656
+ const alive = pid !== null && isAlive(pid);
12657
+ status.running = alive;
12658
+ status.pid = alive ? pid : null;
12659
+ if (!alive) {
12660
+ return `\u{1F43B} Daemon: stopped.${status.lastRunAt ? ` Last tick ${new Date(status.lastRunAt).toISOString()}: ${status.lastResult || "n/a"}` : " Never ran."} Start with \`kuma daemon start\`.`;
12661
+ }
12662
+ return `\u{1F43B} Daemon: running (pid ${pid}).${status.lastRunAt ? ` Last tick ${new Date(status.lastRunAt).toISOString()}: ${status.lastResult || "n/a"}` : " Warming up\u2026"}`;
12663
+ }
12664
+ async function daemonRunChild(intervalMs) {
12665
+ const ms = Number.isFinite(intervalMs) && intervalMs >= 3e4 ? intervalMs : DEFAULT_INTERVAL_MS;
12666
+ await runLoop(ms);
12667
+ }
12668
+ var PID_FILE, STATUS_FILE, LOG_FILE, DEFAULT_INTERVAL_MS;
12669
+ var init_kumaDaemon = __esm({
12670
+ "src/engine/kumaDaemon.ts"() {
12671
+ "use strict";
12672
+ init_pathValidator();
12673
+ PID_FILE = ".kuma/daemon.pid";
12674
+ STATUS_FILE = ".kuma/daemon-status.json";
12675
+ LOG_FILE = ".kuma/daemon.log";
12676
+ DEFAULT_INTERVAL_MS = 5 * 60 * 1e3;
12677
+ }
12678
+ });
12679
+
12352
12680
  // src/utils/agentDetector.ts
12353
12681
  var agentDetector_exports = {};
12354
12682
  __export(agentDetector_exports, {
@@ -12357,19 +12685,19 @@ __export(agentDetector_exports, {
12357
12685
  getSkillPath: () => getSkillPath,
12358
12686
  skillExists: () => skillExists
12359
12687
  });
12360
- import fs31 from "fs";
12361
- import path34 from "path";
12688
+ import fs33 from "fs";
12689
+ import path36 from "path";
12362
12690
  function checkFile(root, filePath) {
12363
12691
  try {
12364
- return fs31.existsSync(path34.join(root, filePath));
12692
+ return fs33.existsSync(path36.join(root, filePath));
12365
12693
  } catch {
12366
12694
  return false;
12367
12695
  }
12368
12696
  }
12369
12697
  function checkDir(root, dirPath) {
12370
12698
  try {
12371
- const fullPath = path34.join(root, dirPath);
12372
- return fs31.existsSync(fullPath) && fs31.statSync(fullPath).isDirectory();
12699
+ const fullPath = path36.join(root, dirPath);
12700
+ return fs33.existsSync(fullPath) && fs33.statSync(fullPath).isDirectory();
12373
12701
  } catch {
12374
12702
  return false;
12375
12703
  }
@@ -12437,7 +12765,7 @@ function getAgentLabel(type) {
12437
12765
  function skillExists(type, projectRoot) {
12438
12766
  const root = projectRoot ?? getProjectRoot();
12439
12767
  const skillPath = getSkillPath(type);
12440
- return fs31.existsSync(path34.join(root, skillPath));
12768
+ return fs33.existsSync(path36.join(root, skillPath));
12441
12769
  }
12442
12770
  var AGENT_DETECTORS;
12443
12771
  var init_agentDetector = __esm({
@@ -13033,8 +13361,8 @@ init_kumaGraph();
13033
13361
  init_kumaMemory();
13034
13362
  init_kumaDriftDetector();
13035
13363
  init_pathValidator();
13036
- import fs21 from "fs";
13037
- import path24 from "path";
13364
+ import fs22 from "fs";
13365
+ import path25 from "path";
13038
13366
  var CONTEXT_ALIASES = {
13039
13367
  "research": "research",
13040
13368
  "search": "research",
@@ -13451,10 +13779,10 @@ async function handleHistory(params) {
13451
13779
  lines.push(traceFormatted);
13452
13780
  } else {
13453
13781
  try {
13454
- const { execSync: execSync9 } = await import("child_process");
13782
+ const { execSync: execSync10 } = await import("child_process");
13455
13783
  const { getProjectRoot: getProjectRoot2 } = await Promise.resolve().then(() => (init_pathValidator(), pathValidator_exports));
13456
13784
  const root = getProjectRoot2();
13457
- const gitHistory = execSync9(
13785
+ const gitHistory = execSync10(
13458
13786
  `git log -n 5 --pretty=format:" \u2022 %h (%ad) %s" --date=short -- "${target}"`,
13459
13787
  { cwd: root, encoding: "utf-8", timeout: 3e3, stdio: ["pipe", "pipe", "pipe"] }
13460
13788
  ).trim();
@@ -13486,7 +13814,7 @@ ${gitHistory}`);
13486
13814
  try {
13487
13815
  const { getDb: getDb2 } = await Promise.resolve().then(() => (init_kumaDb(), kumaDb_exports));
13488
13816
  const db = await getDb2();
13489
- const base = path24.basename(target);
13817
+ const base = path25.basename(target);
13490
13818
  const stmt = db.prepare(`
13491
13819
  SELECT description, last_verified_at FROM known_gotchas
13492
13820
  WHERE status = 'resolved' AND (file_path LIKE ? OR file_path LIKE ?)
@@ -13499,9 +13827,9 @@ ${gitHistory}`);
13499
13827
  if (resolved.length === 0) {
13500
13828
  try {
13501
13829
  const { getProjectRoot: getProjectRoot2 } = await Promise.resolve().then(() => (init_pathValidator(), pathValidator_exports));
13502
- const mdPath = path24.join(getProjectRoot2(), ".kuma", "KNOWN_GOTCHAS.md");
13503
- if (fs21.existsSync(mdPath)) {
13504
- const mdContent = fs21.readFileSync(mdPath, "utf-8");
13830
+ const mdPath = path25.join(getProjectRoot2(), ".kuma", "KNOWN_GOTCHAS.md");
13831
+ if (fs22.existsSync(mdPath)) {
13832
+ const mdContent = fs22.readFileSync(mdPath, "utf-8");
13505
13833
  const sections = mdContent.split(/^###\s+/m);
13506
13834
  for (const sec of sections) {
13507
13835
  const secLower = sec.toLowerCase();
@@ -13573,8 +13901,8 @@ init_kumaDb();
13573
13901
  init_kumaMemory();
13574
13902
  init_pathValidator();
13575
13903
  init_pathValidator();
13576
- import fs23 from "fs";
13577
- import path26 from "path";
13904
+ import fs24 from "fs";
13905
+ import path27 from "path";
13578
13906
  var MEMORY_ALIASES = {
13579
13907
  "decision": "decision",
13580
13908
  "adr": "decision",
@@ -13685,9 +14013,9 @@ async function handleResearchSave(params) {
13685
14013
  } catch {
13686
14014
  }
13687
14015
  try {
13688
- const researchDir = path26.join(getProjectRoot(), ".kuma", "research");
13689
- if (!fs23.existsSync(researchDir)) fs23.mkdirSync(researchDir, { recursive: true });
13690
- fs23.writeFileSync(path26.join(researchDir, `${scope}.json`), JSON.stringify(JSON.parse(record), null, 2), "utf-8");
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");
13691
14019
  } catch {
13692
14020
  }
13693
14021
  sessionMemory.recordMemoryAction("research_save");
@@ -13883,9 +14211,9 @@ init_sessionMemory();
13883
14211
  init_pathValidator();
13884
14212
  init_sessionMemory();
13885
14213
  init_kumaShared();
13886
- import fs24 from "fs";
13887
- import path27 from "path";
13888
- import { execSync as execSync6 } from "child_process";
14214
+ import fs25 from "fs";
14215
+ import path28 from "path";
14216
+ import { execSync as execSync7 } from "child_process";
13889
14217
  var SCRIPT_PATCH_PATTERNS = [
13890
14218
  "writeFileSync",
13891
14219
  "writeFile",
@@ -13911,20 +14239,20 @@ function findPatchScripts(projectRoot) {
13911
14239
  const warnings = [];
13912
14240
  const recentFiles = scanRecentFiles(projectRoot);
13913
14241
  for (const file of recentFiles) {
13914
- const ext = path27.extname(file).toLowerCase();
14242
+ const ext = path28.extname(file).toLowerCase();
13915
14243
  if (!SCRIPT_EXTENSIONS.includes(ext)) continue;
13916
- const relativePath = path27.relative(projectRoot, file);
14244
+ const relativePath = path28.relative(projectRoot, file);
13917
14245
  if (relativePath.startsWith("src") || relativePath.startsWith("test") || relativePath.startsWith("node_modules") || relativePath.startsWith(".") || relativePath.startsWith(".kuma/scratch")) {
13918
14246
  continue;
13919
14247
  }
13920
14248
  try {
13921
- const content = fs24.readFileSync(file, "utf-8").toLowerCase();
14249
+ const content = fs25.readFileSync(file, "utf-8").toLowerCase();
13922
14250
  const matchedPattern = SCRIPT_PATCH_PATTERNS.find((p) => content.includes(p.toLowerCase()));
13923
14251
  if (matchedPattern) {
13924
14252
  warnings.push({
13925
14253
  severity: "high",
13926
14254
  pattern: "script-patching",
13927
- message: `Created script file that modifies other files: ${path27.basename(file)}`,
14255
+ message: `Created script file that modifies other files: ${path28.basename(file)}`,
13928
14256
  suggestion: "Use your native edit tools instead \u2014 targeted edits with auto-backup and rollback",
13929
14257
  evidence: `File: ${relativePath} contains '${matchedPattern}'`,
13930
14258
  filePath: relativePath
@@ -13958,15 +14286,15 @@ function detectBashGrepUsage() {
13958
14286
  function scanRecentFiles(projectRoot) {
13959
14287
  const recent = [];
13960
14288
  try {
13961
- const entries = fs24.readdirSync(projectRoot, { withFileTypes: true });
14289
+ const entries = fs25.readdirSync(projectRoot, { withFileTypes: true });
13962
14290
  const now = Date.now();
13963
14291
  const recentThreshold = 30 * 60 * 1e3;
13964
14292
  for (const entry of entries) {
13965
14293
  if (!entry.isFile()) continue;
13966
14294
  try {
13967
- const stat = fs24.statSync(path27.join(projectRoot, entry.name));
14295
+ const stat = fs25.statSync(path28.join(projectRoot, entry.name));
13968
14296
  if (now - stat.mtimeMs < recentThreshold || now - stat.ctimeMs < recentThreshold) {
13969
- recent.push(path27.join(projectRoot, entry.name));
14297
+ recent.push(path28.join(projectRoot, entry.name));
13970
14298
  }
13971
14299
  } catch {
13972
14300
  continue;
@@ -13979,7 +14307,7 @@ function scanRecentFiles(projectRoot) {
13979
14307
  function detectGitPatchScripts(projectRoot) {
13980
14308
  const warnings = [];
13981
14309
  try {
13982
- const statusStdout = execSync6("git status --porcelain", {
14310
+ const statusStdout = execSync7("git status --porcelain", {
13983
14311
  cwd: projectRoot,
13984
14312
  encoding: "utf-8",
13985
14313
  timeout: 3e3
@@ -13990,14 +14318,14 @@ function detectGitPatchScripts(projectRoot) {
13990
14318
  const prefix = line.substring(0, 2);
13991
14319
  if (prefix !== "??" && prefix !== "A ") continue;
13992
14320
  const file = line.substring(3).trim();
13993
- const ext = path27.extname(file).toLowerCase();
14321
+ const ext = path28.extname(file).toLowerCase();
13994
14322
  if (!SCRIPT_EXTENSIONS.includes(ext)) continue;
13995
14323
  const isRootLevel = !file.includes("/");
13996
14324
  const isScriptsDir = file.startsWith("scripts/") || file.startsWith("patches/");
13997
14325
  if (!isRootLevel && !isScriptsDir) continue;
13998
- const fullPath = path27.join(projectRoot, file);
13999
- if (fs24.existsSync(fullPath)) {
14000
- const content = fs24.readFileSync(fullPath, "utf-8").toLowerCase();
14326
+ const fullPath = path28.join(projectRoot, file);
14327
+ if (fs25.existsSync(fullPath)) {
14328
+ const content = fs25.readFileSync(fullPath, "utf-8").toLowerCase();
14001
14329
  const matchedPattern = SCRIPT_PATCH_PATTERNS.find((p) => content.includes(p.toLowerCase()));
14002
14330
  if (matchedPattern) {
14003
14331
  warnings.push({
@@ -14012,7 +14340,7 @@ function detectGitPatchScripts(projectRoot) {
14012
14340
  }
14013
14341
  }
14014
14342
  }
14015
- const deletedStdout = execSync6("git diff --name-only --diff-filter=D HEAD", {
14343
+ const deletedStdout = execSync7("git diff --name-only --diff-filter=D HEAD", {
14016
14344
  cwd: projectRoot,
14017
14345
  encoding: "utf-8",
14018
14346
  timeout: 3e3
@@ -14020,7 +14348,7 @@ function detectGitPatchScripts(projectRoot) {
14020
14348
  if (deletedStdout) {
14021
14349
  const deletedFiles = deletedStdout.split("\n").filter(Boolean);
14022
14350
  for (const file of deletedFiles) {
14023
- const ext = path27.extname(file).toLowerCase();
14351
+ const ext = path28.extname(file).toLowerCase();
14024
14352
  if (SCRIPT_EXTENSIONS.includes(ext)) {
14025
14353
  warnings.push({
14026
14354
  severity: "high",
@@ -14082,21 +14410,21 @@ function detectAllAntiPatterns() {
14082
14410
  // src/engine/contextSnapshot.ts
14083
14411
  init_sessionMemory();
14084
14412
  init_pathValidator();
14085
- import fs25 from "fs";
14086
- import path28 from "path";
14087
- import { execSync as execSync7 } from "child_process";
14413
+ import fs26 from "fs";
14414
+ import path29 from "path";
14415
+ import { execSync as execSync8 } from "child_process";
14088
14416
  var SNAPSHOT_DIR = "context-snapshots";
14089
14417
  function snapshotDir() {
14090
- return path28.join(getProjectRoot(), ".kuma", SNAPSHOT_DIR);
14418
+ return path29.join(getProjectRoot(), ".kuma", SNAPSHOT_DIR);
14091
14419
  }
14092
14420
  function ensureSnapshotDir() {
14093
14421
  const dir = snapshotDir();
14094
- if (!fs25.existsSync(dir)) {
14095
- fs25.mkdirSync(dir, { recursive: true });
14422
+ if (!fs26.existsSync(dir)) {
14423
+ fs26.mkdirSync(dir, { recursive: true });
14096
14424
  }
14097
14425
  }
14098
14426
  function snapshotFilePath(timestamp) {
14099
- return path28.join(snapshotDir(), `${timestamp}.json`);
14427
+ return path29.join(snapshotDir(), `${timestamp}.json`);
14100
14428
  }
14101
14429
  function saveSnapshot(goal) {
14102
14430
  try {
@@ -14117,7 +14445,7 @@ function saveSnapshot(goal) {
14117
14445
  hasConventions: !!summary.hasConventions
14118
14446
  };
14119
14447
  try {
14120
- fs25.writeFileSync(snapshotFilePath(Date.now()), JSON.stringify(snapshot, null, 2), "utf-8");
14448
+ fs26.writeFileSync(snapshotFilePath(Date.now()), JSON.stringify(snapshot, null, 2), "utf-8");
14121
14449
  } catch {
14122
14450
  }
14123
14451
  sessionMemory.recordToolCall("kuma_context", { action: "save", goal: snapshot.goal });
@@ -14156,7 +14484,7 @@ function formatSnapshot(snapshot) {
14156
14484
  function getGitDiffStat2() {
14157
14485
  try {
14158
14486
  const root = getProjectRoot();
14159
- const stdout = execSync7("git diff --stat", {
14487
+ const stdout = execSync8("git diff --stat", {
14160
14488
  cwd: root,
14161
14489
  encoding: "utf-8",
14162
14490
  timeout: 3e3
@@ -14817,6 +15145,7 @@ Usage:
14817
15145
  npx @plumpslabs/kuma hook pre-compact PreCompact hook \u2014 survival set (goal + critical gotchas + dirty)
14818
15146
  npx @plumpslabs/kuma hook post-commit Git post-commit \u2014 periodic incremental map sync (no rebuild)
14819
15147
  npx @plumpslabs/kuma hook install-git Install the git post-commit hook (idempotent)
15148
+ npx @plumpslabs/kuma daemon start|stop|status Background sensors (map + briefs + drift) every 5m
14820
15149
 
14821
15150
  Available config files:
14822
15151
  --claude CLAUDE.md (Claude Code)
@@ -14909,14 +15238,14 @@ async function main() {
14909
15238
  console.error("");
14910
15239
  let killedCount = 0;
14911
15240
  try {
14912
- const path35 = await import("path");
14913
- const fs32 = await import("fs");
14914
- const lockDir = path35.resolve(process.cwd(), ".kuma/verifier.lock");
14915
- if (fs32.existsSync(lockDir)) {
14916
- const pidFile = path35.join(lockDir, "pid");
14917
- if (fs32.existsSync(pidFile)) {
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)) {
14918
15247
  try {
14919
- const pid = parseInt(fs32.readFileSync(pidFile, "utf-8"), 10);
15248
+ const pid = parseInt(fs34.readFileSync(pidFile, "utf-8"), 10);
14920
15249
  if (pid && pid !== process.pid) {
14921
15250
  try {
14922
15251
  process.kill(-pid, "SIGKILL");
@@ -14932,7 +15261,7 @@ async function main() {
14932
15261
  } catch {
14933
15262
  }
14934
15263
  }
14935
- fs32.rmSync(lockDir, { recursive: true, force: true });
15264
+ fs34.rmSync(lockDir, { recursive: true, force: true });
14936
15265
  }
14937
15266
  if (killedCount === 0) {
14938
15267
  console.error("\u2705 No running verifications found to kill.");
@@ -14940,25 +15269,25 @@ async function main() {
14940
15269
  } catch {
14941
15270
  }
14942
15271
  try {
14943
- const { execSync: execSync9 } = await import("child_process");
15272
+ const { execSync: execSync10 } = await import("child_process");
14944
15273
  try {
14945
- execSync9("pkill -f 'jest' 2>/dev/null || true");
15274
+ execSync10("pkill -f 'jest' 2>/dev/null || true");
14946
15275
  } catch {
14947
15276
  }
14948
15277
  try {
14949
- execSync9("pkill -f 'jest-worker' 2>/dev/null || true");
15278
+ execSync10("pkill -f 'jest-worker' 2>/dev/null || true");
14950
15279
  } catch {
14951
15280
  }
14952
15281
  try {
14953
- execSync9("pkill -f 'pnpm test' 2>/dev/null || true");
15282
+ execSync10("pkill -f 'pnpm test' 2>/dev/null || true");
14954
15283
  } catch {
14955
15284
  }
14956
15285
  try {
14957
- execSync9("pkill -f 'npm test' 2>/dev/null || true");
15286
+ execSync10("pkill -f 'npm test' 2>/dev/null || true");
14958
15287
  } catch {
14959
15288
  }
14960
15289
  try {
14961
- execSync9("pkill -f 'yarn test' 2>/dev/null || true");
15290
+ execSync10("pkill -f 'yarn test' 2>/dev/null || true");
14962
15291
  } catch {
14963
15292
  }
14964
15293
  console.error("\u2705 Killed orphaned test processes");
@@ -14987,7 +15316,7 @@ async function main() {
14987
15316
  if (args[0] === "studio") {
14988
15317
  const { fileURLToPath } = await import("url");
14989
15318
  const { dirname, join } = await import("path");
14990
- const { spawn } = await import("child_process");
15319
+ const { spawn: spawn2 } = await import("child_process");
14991
15320
  const { existsSync } = await import("fs");
14992
15321
  const distDir = dirname(fileURLToPath(import.meta.url));
14993
15322
  const studioPath = join(distDir, "..", "packages", "ide", "studio", "dist", "index.js");
@@ -14998,7 +15327,7 @@ async function main() {
14998
15327
  process.exit(1);
14999
15328
  }
15000
15329
  const studioArgs = args.slice(1);
15001
- const child = spawn("node", [studioPath, ...studioArgs], {
15330
+ const child = spawn2("node", [studioPath, ...studioArgs], {
15002
15331
  stdio: "inherit",
15003
15332
  cwd: process.cwd()
15004
15333
  });
@@ -15131,14 +15460,14 @@ ${context}` : "";
15131
15460
  process.stdout.write("\u{1F43B} [Kuma] git post-commit hook already installed.");
15132
15461
  } else {
15133
15462
  fsMod.appendFileSync(hookPath, `
15134
- # Kuma periodic mapping (industry auto-map)
15463
+ # Kuma periodic mapping
15135
15464
  ${line}
15136
15465
  `, "utf-8");
15137
15466
  process.stdout.write("\u{1F43B} [Kuma] appended to existing git post-commit hook.");
15138
15467
  }
15139
15468
  } else {
15140
15469
  fsMod.writeFileSync(hookPath, `#!/bin/sh
15141
- # Kuma periodic mapping (industry auto-map)
15470
+ # Kuma periodic mapping
15142
15471
  ${line}
15143
15472
  `, { mode: 493 });
15144
15473
  process.stdout.write("\u{1F43B} [Kuma] git post-commit hook installed.");
@@ -15148,6 +15477,26 @@ ${line}
15148
15477
  }
15149
15478
  process.exit(0);
15150
15479
  }
15480
+ if (args[0] === "daemon") {
15481
+ const sub = args[1] || "status";
15482
+ try {
15483
+ const { daemonStart: daemonStart2, daemonStop: daemonStop2, daemonStatus: daemonStatus2, daemonRunChild: daemonRunChild2, DEFAULT_INTERVAL_MS: DEFAULT_INTERVAL_MS2 } = await Promise.resolve().then(() => (init_kumaDaemon(), kumaDaemon_exports));
15484
+ if (sub === "start") {
15485
+ const ms = Number(args[2]) > 0 ? Number(args[2]) : DEFAULT_INTERVAL_MS2;
15486
+ process.stdout.write(await daemonStart2(ms));
15487
+ } else if (sub === "stop") {
15488
+ process.stdout.write(await daemonStop2());
15489
+ } else if (sub === "run") {
15490
+ await daemonRunChild2(Number(args[2]));
15491
+ return;
15492
+ } else {
15493
+ process.stdout.write(await daemonStatus2());
15494
+ }
15495
+ } catch (err) {
15496
+ process.stdout.write(`\u{1F43B} Daemon error: ${err}`);
15497
+ }
15498
+ process.exit(0);
15499
+ }
15151
15500
  if (args[0] === "--hook") {
15152
15501
  process.exit(0);
15153
15502
  }
@@ -15158,8 +15507,8 @@ ${line}
15158
15507
  const proj = root.split("/").pop() || "unknown";
15159
15508
  const lines = [`\u{1F43B} [Kuma session brief] ${proj}`];
15160
15509
  try {
15161
- const { execSync: execSync9 } = await import("child_process");
15162
- const branch = execSync9("git rev-parse --abbrev-ref HEAD", {
15510
+ const { execSync: execSync10 } = await import("child_process");
15511
+ const branch = execSync10("git rev-parse --abbrev-ref HEAD", {
15163
15512
  cwd: root,
15164
15513
  encoding: "utf-8",
15165
15514
  timeout: 2e3,
@@ -15277,23 +15626,23 @@ ${line}
15277
15626
  });
15278
15627
  const output = formatInitResults(results);
15279
15628
  console.log(output);
15280
- const fs32 = await import("fs");
15281
- const path35 = await import("path");
15282
- const matchaSkills = path35.resolve(process.cwd(), "skills/matcha/SKILL.md");
15283
- const matchaAgents = path35.resolve(
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(
15284
15633
  process.cwd(),
15285
15634
  ".agents/skills/matcha/SKILL.md"
15286
15635
  );
15287
- const matchaRootSkills = path35.resolve(
15636
+ const matchaRootSkills = path37.resolve(
15288
15637
  process.cwd(),
15289
15638
  "skills/matcha/SKILL.md"
15290
15639
  );
15291
- const matchaAgentsMd = path35.resolve(process.cwd(), "AGENTS.md");
15292
- const matchaWindsurfRules = path35.resolve(
15640
+ const matchaAgentsMd = path37.resolve(process.cwd(), "AGENTS.md");
15641
+ const matchaWindsurfRules = path37.resolve(
15293
15642
  process.cwd(),
15294
15643
  ".windsurf"
15295
15644
  );
15296
- if (fs32.existsSync(matchaSkills) || fs32.existsSync(matchaAgents) || fs32.existsSync(matchaRootSkills) || fs32.existsSync(matchaAgentsMd) || fs32.existsSync(matchaWindsurfRules)) {
15645
+ if (fs34.existsSync(matchaSkills) || fs34.existsSync(matchaAgents) || fs34.existsSync(matchaRootSkills) || fs34.existsSync(matchaAgentsMd) || fs34.existsSync(matchaWindsurfRules)) {
15297
15646
  console.error(
15298
15647
  "\n\u{1F375} Hey, I see matcha is installed \u2014 they pair well together!"
15299
15648
  );
@@ -15307,13 +15656,13 @@ ${line}
15307
15656
  (async () => {
15308
15657
  try {
15309
15658
  const { generateInitMdContent: generateInitMdContent2 } = await Promise.resolve().then(() => (init_init(), init_exports));
15310
- const fs32 = await import("fs");
15311
- const path35 = await import("path");
15312
- const initMdPath = path35.resolve(process.cwd(), ".kuma/init.md");
15313
- if (!fs32.existsSync(initMdPath)) {
15314
- const kumaDir = path35.dirname(initMdPath);
15315
- if (!fs32.existsSync(kumaDir)) fs32.mkdirSync(kumaDir, { recursive: true });
15316
- fs32.writeFileSync(initMdPath, generateInitMdContent2(), "utf-8");
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");
15317
15666
  console.error(`[${SERVER_NAME}] Auto-generated .kuma/init.md`);
15318
15667
  }
15319
15668
  } catch (err) {
@@ -15324,8 +15673,8 @@ ${line}
15324
15673
  try {
15325
15674
  const { detectAgent: detectAgent2, getSkillPath: getSkillPath2, getAgentLabel: getAgentLabel2 } = await Promise.resolve().then(() => (init_agentDetector(), agentDetector_exports));
15326
15675
  const { generateSkill: generateSkill2, getSecondaryFiles: getSecondaryFiles2 } = await Promise.resolve().then(() => (init_skillGenerator(), skillGenerator_exports));
15327
- const fs32 = await import("fs");
15328
- const path35 = await import("path");
15676
+ const fs34 = await import("fs");
15677
+ const path37 = await import("path");
15329
15678
  const detection = detectAgent2();
15330
15679
  if (!detection.primary) {
15331
15680
  console.error(`[${SERVER_NAME}] No AI agent detected \u2014 skipping auto-skill creation`);
@@ -15333,22 +15682,22 @@ ${line}
15333
15682
  }
15334
15683
  const agentType = detection.primary;
15335
15684
  const skillPath = getSkillPath2(agentType);
15336
- const fullPath = path35.resolve(process.cwd(), skillPath);
15337
- if (fs32.existsSync(fullPath)) {
15685
+ const fullPath = path37.resolve(process.cwd(), skillPath);
15686
+ if (fs34.existsSync(fullPath)) {
15338
15687
  console.error(`[${SERVER_NAME}] Skill exists for ${getAgentLabel2(agentType)} \u2014 skipping`);
15339
15688
  return;
15340
15689
  }
15341
- const dir = path35.dirname(fullPath);
15342
- if (!fs32.existsSync(dir)) fs32.mkdirSync(dir, { recursive: true });
15343
- fs32.writeFileSync(fullPath, generateSkill2(agentType), "utf-8");
15690
+ const dir = path37.dirname(fullPath);
15691
+ if (!fs34.existsSync(dir)) fs34.mkdirSync(dir, { recursive: true });
15692
+ fs34.writeFileSync(fullPath, generateSkill2(agentType), "utf-8");
15344
15693
  console.error(`[${SERVER_NAME}] Auto-created ${skillPath} for ${getAgentLabel2(agentType)}`);
15345
15694
  const secondaryFiles = getSecondaryFiles2(agentType);
15346
15695
  for (const sf of secondaryFiles) {
15347
- const sfPath = path35.resolve(process.cwd(), sf.path);
15348
- const sfDir = path35.dirname(sfPath);
15349
- if (!fs32.existsSync(sfPath)) {
15350
- if (!fs32.existsSync(sfDir)) fs32.mkdirSync(sfDir, { recursive: true });
15351
- fs32.writeFileSync(sfPath, sf.content, "utf-8");
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");
15352
15701
  console.error(`[${SERVER_NAME}] Auto-created ${sf.path}`);
15353
15702
  }
15354
15703
  }