@plumpslabs/kuma 2.4.16 → 2.4.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1220,8 +1220,8 @@ async function runDoctor() {
1220
1220
  } catch {
1221
1221
  }
1222
1222
  try {
1223
- const { execSync: execSync10 } = await import("child_process");
1224
- const psOutput = execSync10(
1223
+ const { execSync: execSync11 } = await import("child_process");
1224
+ const psOutput = execSync11(
1225
1225
  `ps -eo pid,ppid,command | grep -E "(jest|pnpm test|npm test|yarn test)" | grep -v grep | head -10`,
1226
1226
  { encoding: "utf-8", timeout: 5e3 }
1227
1227
  ).trim();
@@ -3957,13 +3957,18 @@ var init_kumaSelfHeal = __esm({
3957
3957
  // src/engine/kumaDriftDetector.ts
3958
3958
  var kumaDriftDetector_exports = {};
3959
3959
  __export(kumaDriftDetector_exports, {
3960
+ DRIFT_REPORT_FILE: () => DRIFT_REPORT_FILE,
3961
+ DRIFT_REPORT_MAX_ITEMS: () => DRIFT_REPORT_MAX_ITEMS,
3960
3962
  computeProjectHash: () => computeProjectHash,
3961
3963
  computeScopeHash: () => computeScopeHash,
3962
3964
  detectDrift: () => detectDrift,
3963
3965
  flagStaleRecords: () => flagStaleRecords,
3964
3966
  formatDriftReport: () => formatDriftReport,
3965
3967
  getDriftSummary: () => getDriftSummary,
3966
- hashFile: () => hashFile
3968
+ hashFile: () => hashFile,
3969
+ readDriftReport: () => readDriftReport,
3970
+ toDriftActionItem: () => toDriftActionItem,
3971
+ writeDriftReport: () => writeDriftReport
3967
3972
  });
3968
3973
  import fs7 from "fs";
3969
3974
  import path9 from "path";
@@ -4184,13 +4189,51 @@ async function getDriftSummary() {
4184
4189
  if (staleCount === 0) return "\u2705 All records fresh";
4185
4190
  return `\u26A0\uFE0F ${staleCount} stale record(s) detected. Use kuma_memory({ action: 'heal' }) to repair.`;
4186
4191
  }
4187
- var computeProjectHash;
4192
+ function toDriftActionItem(r) {
4193
+ const stale = r.severity === "stale";
4194
+ const missing = r.severity === "missing";
4195
+ const action = r.source === "research_cache" ? `re-run kuma_context({ action: 'research', scope: '${r.description}' })` : r.filePath ? `rescan '${r.filePath}' (touch via any context call) or run heal` : `run kuma_memory({ action: 'heal' }) to repair`;
4196
+ return {
4197
+ id: `${r.source}#${r.id}`,
4198
+ kind: r.source,
4199
+ target: r.filePath || r.description,
4200
+ reason: missing ? "source gone (file/record missing)" : `content hash mismatch vs current (age ${r.age})`,
4201
+ action: stale || missing ? action : "monitor"
4202
+ };
4203
+ }
4204
+ async function writeDriftReport(maxItems = DRIFT_REPORT_MAX_ITEMS) {
4205
+ const fp = path9.join(getProjectRoot(), DRIFT_REPORT_FILE);
4206
+ const records = await detectDrift();
4207
+ const actionable = records.filter((r) => r.severity === "stale" || r.severity === "missing");
4208
+ const items = actionable.slice(0, maxItems).map(toDriftActionItem);
4209
+ try {
4210
+ fs7.writeFileSync(
4211
+ fp,
4212
+ JSON.stringify({ generatedAt: (/* @__PURE__ */ new Date()).toISOString(), count: actionable.length, items }, null, 2),
4213
+ "utf-8"
4214
+ );
4215
+ } catch {
4216
+ }
4217
+ return { items: items.length, path: fp };
4218
+ }
4219
+ function readDriftReport() {
4220
+ try {
4221
+ const fp = path9.join(getProjectRoot(), DRIFT_REPORT_FILE);
4222
+ if (!fs7.existsSync(fp)) return null;
4223
+ return JSON.parse(fs7.readFileSync(fp, "utf-8"));
4224
+ } catch {
4225
+ return null;
4226
+ }
4227
+ }
4228
+ var computeProjectHash, DRIFT_REPORT_FILE, DRIFT_REPORT_MAX_ITEMS;
4188
4229
  var init_kumaDriftDetector = __esm({
4189
4230
  "src/engine/kumaDriftDetector.ts"() {
4190
4231
  "use strict";
4191
4232
  init_kumaDb();
4192
4233
  init_pathValidator();
4193
4234
  computeProjectHash = (scope) => computeScopeHash(scope) || Date.now().toString(16);
4235
+ DRIFT_REPORT_FILE = ".kuma/drift.json";
4236
+ DRIFT_REPORT_MAX_ITEMS = 20;
4194
4237
  }
4195
4238
  });
4196
4239
 
@@ -4598,12 +4641,17 @@ __export(mapBackbone_exports, {
4598
4641
  ensureMapped: () => ensureMapped,
4599
4642
  extractImportSources: () => extractImportSources,
4600
4643
  formatBackbone: () => formatBackbone,
4644
+ getWorktreeChangedFiles: () => getWorktreeChangedFiles,
4601
4645
  isMapEmpty: () => isMapEmpty,
4602
- readMapMeta: () => readMapMeta
4646
+ isWorktreeDirty: () => isWorktreeDirty,
4647
+ readMapMeta: () => readMapMeta,
4648
+ readWorktreeDirty: () => readWorktreeDirty,
4649
+ updateWorktreeDirty: () => updateWorktreeDirty
4603
4650
  });
4604
4651
  import fs9 from "fs";
4605
4652
  import path11 from "path";
4606
4653
  import fastGlob3 from "fast-glob";
4654
+ import { execSync as execSync4 } from "child_process";
4607
4655
  function extractImportSources(line) {
4608
4656
  const out = [];
4609
4657
  const t = line.trim();
@@ -4743,6 +4791,52 @@ async function ensureBackbone() {
4743
4791
  function formatBackbone(r) {
4744
4792
  return `\u{1F5FA}\uFE0F Backbone: ${r.files} file(s)${r.capped ? ` (capped at ${BACKBONE_MAX_FILES})` : ""}, ${r.edges} import edge(s) in ${r.ms}ms (~${r.filesPerSec} files/s) \u2014 approximate tier, symbols fill in on demand.`;
4745
4793
  }
4794
+ function getWorktreeChangedFiles(root, cap = WORKTREE_CAP) {
4795
+ const out = [];
4796
+ try {
4797
+ const cwd = root || getProjectRoot();
4798
+ const porcelain = execSync4("git status --porcelain --untracked-files=all", {
4799
+ cwd,
4800
+ encoding: "utf-8",
4801
+ timeout: 5e3,
4802
+ stdio: ["pipe", "pipe", "pipe"]
4803
+ });
4804
+ if (!porcelain.trim()) return out;
4805
+ for (const rawLine of porcelain.split("\n")) {
4806
+ if (out.length >= cap) break;
4807
+ const line = rawLine.replace(/\s+$/, "");
4808
+ if (!line) continue;
4809
+ const m = line.match(/^(.{2})\s+(.+)$/);
4810
+ if (!m) continue;
4811
+ const code = m[1];
4812
+ let p = m[2].trim();
4813
+ const arrow = p.indexOf(" -> ");
4814
+ if (arrow >= 0) p = p.slice(arrow + 4).trim();
4815
+ p = p.replace(/^"|"$/g, "");
4816
+ if (!p) continue;
4817
+ const ext = p.slice(p.lastIndexOf(".")).toLowerCase();
4818
+ if (!WORKTREE_EXTS.has(ext)) continue;
4819
+ const untracked = code[0] === "?" || code[1] === "?";
4820
+ out.push({ file: p, state: untracked ? "untracked" : "modified" });
4821
+ }
4822
+ } catch {
4823
+ }
4824
+ return out;
4825
+ }
4826
+ function updateWorktreeDirty(files, root) {
4827
+ writeMapMeta({ worktreeDirty: [...new Set(files)].slice(0, WORKTREE_CAP), worktreeDirtyAt: Date.now() }, root);
4828
+ }
4829
+ function readWorktreeDirty(root) {
4830
+ const meta = readMapMeta(root);
4831
+ return Array.isArray(meta.worktreeDirty) ? meta.worktreeDirty.filter((f) => typeof f === "string") : [];
4832
+ }
4833
+ function isWorktreeDirty(target, root) {
4834
+ const norm = target.replace(/\\/g, "/");
4835
+ return readWorktreeDirty(root).some((f) => {
4836
+ const nf = f.replace(/\\/g, "/");
4837
+ return nf === norm || nf.endsWith(`/${norm}`) || norm.endsWith(`/${nf}`);
4838
+ });
4839
+ }
4746
4840
  async function ensureMapped(files) {
4747
4841
  const targets = [...new Set(files.map((f) => f.trim()).filter(Boolean))].slice(0, 10);
4748
4842
  if (targets.length === 0) return { filled: 0 };
@@ -4773,7 +4867,7 @@ async function ensureMapped(files) {
4773
4867
  return { filled: 0 };
4774
4868
  }
4775
4869
  }
4776
- var BACKBONE_MAX_FILES, MAP_META, IMPORT_RES;
4870
+ var BACKBONE_MAX_FILES, MAP_META, IMPORT_RES, WORKTREE_CAP, WORKTREE_EXTS;
4777
4871
  var init_mapBackbone = __esm({
4778
4872
  "src/engine/mapBackbone.ts"() {
4779
4873
  "use strict";
@@ -4788,6 +4882,31 @@ var init_mapBackbone = __esm({
4788
4882
  /(?:from)\s+["']?([a-zA-Z0-9_./-]+)["']?\s+import\s+/g,
4789
4883
  /require\s*\(\s*['"]([^'"]+)['"]\s*\)/g
4790
4884
  ];
4885
+ WORKTREE_CAP = 50;
4886
+ WORKTREE_EXTS = /* @__PURE__ */ new Set([
4887
+ ".ts",
4888
+ ".tsx",
4889
+ ".js",
4890
+ ".jsx",
4891
+ ".mjs",
4892
+ ".cjs",
4893
+ ".py",
4894
+ ".go",
4895
+ ".rs",
4896
+ ".java",
4897
+ ".rb",
4898
+ ".php",
4899
+ ".swift",
4900
+ ".kt",
4901
+ ".cs",
4902
+ ".vue",
4903
+ ".svelte",
4904
+ ".json",
4905
+ ".yml",
4906
+ ".yaml",
4907
+ ".toml",
4908
+ ".md"
4909
+ ]);
4791
4910
  }
4792
4911
  });
4793
4912
 
@@ -4799,7 +4918,7 @@ __export(symbolReach_exports, {
4799
4918
  });
4800
4919
  import fs10 from "fs";
4801
4920
  import path12 from "path";
4802
- import { execSync as execSync4 } from "child_process";
4921
+ import { execSync as execSync5 } from "child_process";
4803
4922
  async function graphReach(symbol, limit) {
4804
4923
  const rows = [];
4805
4924
  try {
@@ -4851,7 +4970,7 @@ async function graphReach(symbol, limit) {
4851
4970
  function ripgrepReach(symbol, root, limit) {
4852
4971
  const rows = [];
4853
4972
  try {
4854
- const out = execSync4(
4973
+ const out = execSync5(
4855
4974
  `grep -rn -F --include="*.ts" --include="*.tsx" --include="*.js" --include="*.jsx" --include="*.py" --include="*.go" --include="*.rs" "${symbol.replace(/"/g, "")}" . 2>/dev/null | grep -v node_modules | grep -v "/dist/" | grep -v "/.git/" | grep -v "/.kuma/" | head -40`,
4856
4975
  { cwd: root, encoding: "utf-8", timeout: 8e3, maxBuffer: 256 * 1024 }
4857
4976
  ).trim();
@@ -5026,7 +5145,7 @@ __export(impactAnalysis_exports, {
5026
5145
  });
5027
5146
  import fs11 from "fs";
5028
5147
  import path13 from "path";
5029
- import { execSync as execSync5 } from "child_process";
5148
+ import { execSync as execSync6 } from "child_process";
5030
5149
  import fastGlob4 from "fast-glob";
5031
5150
  function extOf(target) {
5032
5151
  const base = path13.basename(target);
@@ -5047,7 +5166,7 @@ function classifyDiffShape(target, root) {
5047
5166
  }
5048
5167
  try {
5049
5168
  const cwd = root || getProjectRoot();
5050
- const diff = execSync5(`git diff --unified=0 -- "${target}"`, {
5169
+ const diff = execSync6(`git diff --unified=0 -- "${target}"`, {
5051
5170
  cwd,
5052
5171
  encoding: "utf-8",
5053
5172
  timeout: 4e3,
@@ -5313,6 +5432,14 @@ async function calculateBlastRadius(target, options = {}) {
5313
5432
  const rev = getReverseDependencies(owningPackage.name, wsInfo);
5314
5433
  downstreamPackages.push(...rev.map((p) => p.name));
5315
5434
  }
5435
+ let worktreeNote = "";
5436
+ try {
5437
+ const { isWorktreeDirty: isWorktreeDirty2 } = await Promise.resolve().then(() => (init_mapBackbone(), mapBackbone_exports));
5438
+ if (targetType === "file" && isWorktreeDirty2(target, root)) {
5439
+ worktreeNote = "\u{1F4DD} Uncommitted worktree changes on this target \u2014 map reflects work in progress, not committed state";
5440
+ }
5441
+ } catch {
5442
+ }
5316
5443
  if (targetType === "file") {
5317
5444
  try {
5318
5445
  const { ensureMapped: ensureMapped2 } = await Promise.resolve().then(() => (init_mapBackbone(), mapBackbone_exports));
@@ -5380,6 +5507,7 @@ async function calculateBlastRadius(target, options = {}) {
5380
5507
  `\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501`,
5381
5508
  `\u26A0\uFE0F **Risk Level: ${risk.toUpperCase()}**`,
5382
5509
  `\u{1F4D0} Diff shape: \`${diffShape}\` (${shapeDetail})`,
5510
+ ...worktreeNote ? [worktreeNote] : [],
5383
5511
  owningPackage ? `\u{1F4E6} Owning package: \`${owningPackage.name}\` (${owningPackage.path})` : ""
5384
5512
  ];
5385
5513
  if (riskFlags.length > 0) {
@@ -6712,9 +6840,9 @@ ${summary}`;
6712
6840
  }
6713
6841
  async function codebaseImpactFallback(target) {
6714
6842
  try {
6715
- const { execSync: execSync10 } = await import("child_process");
6843
+ const { execSync: execSync11 } = await import("child_process");
6716
6844
  const root = process.cwd();
6717
- const grepResult = execSync10(
6845
+ const grepResult = execSync11(
6718
6846
  `grep -rn ${grepIncludeFlags()} --include="*.json" --include="*.md" -l "${target.replace(/"/g, '\\"')}" . 2>/dev/null | grep -v node_modules | grep -v .git | grep -v dist | grep -v .kuma | head -50`,
6719
6847
  { cwd: root, encoding: "utf-8", timeout: 5e3, maxBuffer: 256 * 1024 }
6720
6848
  ).trim();
@@ -6860,7 +6988,7 @@ __export(kumaShared_exports, {
6860
6988
  isReadTool: () => isReadTool,
6861
6989
  isTestTool: () => isTestTool
6862
6990
  });
6863
- import { execSync as execSync6 } from "child_process";
6991
+ import { execSync as execSync7 } from "child_process";
6864
6992
  import fs12 from "fs";
6865
6993
  import path14 from "path";
6866
6994
  function isEditTool(toolName) {
@@ -6900,7 +7028,7 @@ function getSessionStats(inputGoal) {
6900
7028
  function getGitDiffStat(timeout = 3e3) {
6901
7029
  try {
6902
7030
  const root = getProjectRoot();
6903
- return execSync6("git diff --stat", {
7031
+ return execSync7("git diff --stat", {
6904
7032
  cwd: root,
6905
7033
  encoding: "utf-8",
6906
7034
  timeout
@@ -6913,13 +7041,16 @@ function getUncommittedFiles(timeout = 3e3) {
6913
7041
  const files = /* @__PURE__ */ new Set();
6914
7042
  try {
6915
7043
  const root = getProjectRoot();
6916
- const porcelain = execSync6("git status --porcelain", {
7044
+ const porcelain = execSync7("git status --porcelain", {
6917
7045
  cwd: root,
6918
7046
  encoding: "utf-8",
6919
7047
  timeout,
6920
7048
  stdio: ["pipe", "pipe", "pipe"]
6921
- }).trim();
6922
- for (const line of porcelain.split("\n")) {
7049
+ });
7050
+ if (!porcelain.trim()) return files;
7051
+ for (const rawLine of porcelain.split("\n")) {
7052
+ const line = rawLine.replace(/\s+$/, "");
7053
+ if (!line) continue;
6923
7054
  const m = line.match(/^.{3}(.+?)(?:\s+->\s+.+)?$/);
6924
7055
  if (m && m[1]) files.add(m[1].trim().replace(/^"|"$/g, ""));
6925
7056
  }
@@ -6932,17 +7063,17 @@ function getBranchCommittedFiles(timeout = 5e3) {
6932
7063
  let base = "";
6933
7064
  try {
6934
7065
  const root = getProjectRoot();
6935
- const branch = execSync6("git rev-parse --abbrev-ref HEAD", {
7066
+ const branch = execSync7("git rev-parse --abbrev-ref HEAD", {
6936
7067
  cwd: root,
6937
7068
  encoding: "utf-8",
6938
7069
  timeout,
6939
7070
  stdio: ["pipe", "pipe", "pipe"]
6940
7071
  }).trim();
6941
- const baseRef = execSync6(
7072
+ const baseRef = execSync7(
6942
7073
  `git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null || echo origin/${branch === "main" || branch === "master" ? "HEAD" : "main"}`,
6943
7074
  { cwd: root, encoding: "utf-8", timeout, stdio: ["pipe", "pipe", "pipe"] }
6944
7075
  ).trim().replace("refs/remotes/", "");
6945
- const mergeBase = execSync6(`git merge-base HEAD ${baseRef} 2>/dev/null || git rev-list --max-parents=0 HEAD`, {
7076
+ const mergeBase = execSync7(`git merge-base HEAD ${baseRef} 2>/dev/null || git rev-list --max-parents=0 HEAD`, {
6946
7077
  cwd: root,
6947
7078
  encoding: "utf-8",
6948
7079
  timeout,
@@ -6950,7 +7081,7 @@ function getBranchCommittedFiles(timeout = 5e3) {
6950
7081
  }).trim().split("\n")[0];
6951
7082
  base = baseRef;
6952
7083
  if (mergeBase) {
6953
- const out = execSync6(`git diff --name-only ${mergeBase} HEAD`, {
7084
+ const out = execSync7(`git diff --name-only ${mergeBase} HEAD`, {
6954
7085
  cwd: root,
6955
7086
  encoding: "utf-8",
6956
7087
  timeout,
@@ -7074,7 +7205,7 @@ function detectTestWeakening(files, root) {
7074
7205
  for (const f of files) {
7075
7206
  if (!TEST_FILE_PATTERN.test(f)) continue;
7076
7207
  try {
7077
- const diff = execSync6(`git diff --unified=0 -- "${f}"`, {
7208
+ const diff = execSync7(`git diff --unified=0 -- "${f}"`, {
7078
7209
  cwd,
7079
7210
  encoding: "utf-8",
7080
7211
  timeout: 4e3,
@@ -10307,7 +10438,7 @@ __export(docDrift_exports, {
10307
10438
  });
10308
10439
  import fs29 from "fs";
10309
10440
  import path32 from "path";
10310
- import { execSync as execSync9 } from "child_process";
10441
+ import { execSync as execSync10 } from "child_process";
10311
10442
  function collectDocFiles(root) {
10312
10443
  const cwd = root || getProjectRoot();
10313
10444
  const out = [];
@@ -10366,7 +10497,7 @@ function codeContainsBatch(root, needles) {
10366
10497
  const chunk = clean.slice(i, i + 50);
10367
10498
  try {
10368
10499
  const args = chunk.map((n) => `-e "${n}"`).join(" ");
10369
- const out = execSync9(
10500
+ const out = execSync10(
10370
10501
  `grep -rn --include="*.ts" --include="*.js" --include="*.tsx" --include="*.jsx" --include="*.py" --include="*.go" --include="*.rs" --include="*.json" --include="*.yml" --include="*.yaml" --include="*.toml" --include=".env*" -F ${args} . 2>/dev/null | grep -v node_modules | grep -v "/dist/" | grep -v "/.git/" | grep -v "/.kuma/" | head -100`,
10371
10502
  { cwd: root, encoding: "utf-8", timeout: 8e3, maxBuffer: 256 * 1024 }
10372
10503
  ).trim();
@@ -10570,14 +10701,14 @@ async function createCheckpoint(label, description) {
10570
10701
  let gitHead;
10571
10702
  let isGitClean = false;
10572
10703
  try {
10573
- const { execSync: execSync10 } = await import("child_process");
10574
- gitHead = execSync10("git rev-parse HEAD", {
10704
+ const { execSync: execSync11 } = await import("child_process");
10705
+ gitHead = execSync11("git rev-parse HEAD", {
10575
10706
  cwd: root,
10576
10707
  encoding: "utf-8",
10577
10708
  timeout: 3e3,
10578
10709
  stdio: ["pipe", "pipe", "pipe"]
10579
10710
  }).trim();
10580
- const statusOut = execSync10("git status --porcelain", {
10711
+ const statusOut = execSync11("git status --porcelain", {
10581
10712
  cwd: root,
10582
10713
  encoding: "utf-8",
10583
10714
  timeout: 3e3,
@@ -10588,8 +10719,8 @@ async function createCheckpoint(label, description) {
10588
10719
  }
10589
10720
  const candidatePaths = /* @__PURE__ */ new Set();
10590
10721
  try {
10591
- const { execSync: execSync10 } = await import("child_process");
10592
- const gitOut = execSync10("git status --porcelain", {
10722
+ const { execSync: execSync11 } = await import("child_process");
10723
+ const gitOut = execSync11("git status --porcelain", {
10593
10724
  cwd: root,
10594
10725
  encoding: "utf-8",
10595
10726
  timeout: 4e3,
@@ -10718,8 +10849,8 @@ ${listCheckpoints()}`;
10718
10849
  }
10719
10850
  if (manifest.files.length === 0 && manifest.gitHead) {
10720
10851
  try {
10721
- const { execSync: execSync10 } = await import("child_process");
10722
- execSync10(`git checkout ${manifest.gitHead} -- .`, {
10852
+ const { execSync: execSync11 } = await import("child_process");
10853
+ execSync11(`git checkout ${manifest.gitHead} -- .`, {
10723
10854
  cwd: root,
10724
10855
  encoding: "utf-8",
10725
10856
  timeout: 8e3,
@@ -12769,6 +12900,20 @@ async function daemonTick(root) {
12769
12900
  } catch (err) {
12770
12901
  notes.push(`map: skipped (${err})`);
12771
12902
  }
12903
+ try {
12904
+ const { getWorktreeChangedFiles: getWorktreeChangedFiles2, updateWorktreeDirty: updateWorktreeDirty2 } = await Promise.resolve().then(() => (init_mapBackbone(), mapBackbone_exports));
12905
+ const { scanCodebase: scanCodebase2 } = await Promise.resolve().then(() => (init_kumaCodeScanner(), kumaCodeScanner_exports));
12906
+ const dirty = getWorktreeChangedFiles2(r, 50);
12907
+ if (dirty.length > 0) {
12908
+ const res = await scanCodebase2({ include: dirty.map((d) => d.file), force: true, maxFiles: dirty.length });
12909
+ updateWorktreeDirty2(dirty.map((d) => d.file), r);
12910
+ notes.push(`worktree: ${dirty.length} dirty forced (${res.filesScanned} scanned)`);
12911
+ } else {
12912
+ updateWorktreeDirty2([], r);
12913
+ }
12914
+ } catch (err) {
12915
+ notes.push(`worktree: skipped (${err})`);
12916
+ }
12772
12917
  try {
12773
12918
  const { refreshPackageBriefs: refreshPackageBriefs2 } = await Promise.resolve().then(() => (init_packageBriefs(), packageBriefs_exports));
12774
12919
  const { count } = await refreshPackageBriefs2();
@@ -12784,6 +12929,12 @@ async function daemonTick(root) {
12784
12929
  } catch {
12785
12930
  notes.push("drift: skipped");
12786
12931
  }
12932
+ try {
12933
+ const { writeDriftReport: writeDriftReport2 } = await Promise.resolve().then(() => (init_kumaDriftDetector(), kumaDriftDetector_exports));
12934
+ const { items } = await writeDriftReport2();
12935
+ notes.push(`drift-report: ${items} item(s) \u2192 .kuma/drift.json`);
12936
+ } catch {
12937
+ }
12787
12938
  try {
12788
12939
  const { clearDirty: clearDirty2 } = await Promise.resolve().then(() => (init_cacheFreshness(), cacheFreshness_exports));
12789
12940
  clearDirty2();
@@ -14023,10 +14174,10 @@ async function handleHistory(params) {
14023
14174
  lines.push(traceFormatted);
14024
14175
  } else {
14025
14176
  try {
14026
- const { execSync: execSync10 } = await import("child_process");
14177
+ const { execSync: execSync11 } = await import("child_process");
14027
14178
  const { getProjectRoot: getProjectRoot2 } = await Promise.resolve().then(() => (init_pathValidator(), pathValidator_exports));
14028
14179
  const root = getProjectRoot2();
14029
- const gitHistory = execSync10(
14180
+ const gitHistory = execSync11(
14030
14181
  `git log -n 5 --pretty=format:" \u2022 %h (%ad) %s" --date=short -- "${target}"`,
14031
14182
  { cwd: root, encoding: "utf-8", timeout: 3e3, stdio: ["pipe", "pipe", "pipe"] }
14032
14183
  ).trim();
@@ -14457,7 +14608,7 @@ init_sessionMemory();
14457
14608
  init_kumaShared();
14458
14609
  import fs26 from "fs";
14459
14610
  import path29 from "path";
14460
- import { execSync as execSync7 } from "child_process";
14611
+ import { execSync as execSync8 } from "child_process";
14461
14612
  var SCRIPT_PATCH_PATTERNS = [
14462
14613
  "writeFileSync",
14463
14614
  "writeFile",
@@ -14551,7 +14702,7 @@ function scanRecentFiles(projectRoot) {
14551
14702
  function detectGitPatchScripts(projectRoot) {
14552
14703
  const warnings = [];
14553
14704
  try {
14554
- const statusStdout = execSync7("git status --porcelain", {
14705
+ const statusStdout = execSync8("git status --porcelain", {
14555
14706
  cwd: projectRoot,
14556
14707
  encoding: "utf-8",
14557
14708
  timeout: 3e3
@@ -14584,7 +14735,7 @@ function detectGitPatchScripts(projectRoot) {
14584
14735
  }
14585
14736
  }
14586
14737
  }
14587
- const deletedStdout = execSync7("git diff --name-only --diff-filter=D HEAD", {
14738
+ const deletedStdout = execSync8("git diff --name-only --diff-filter=D HEAD", {
14588
14739
  cwd: projectRoot,
14589
14740
  encoding: "utf-8",
14590
14741
  timeout: 3e3
@@ -14656,7 +14807,7 @@ init_sessionMemory();
14656
14807
  init_pathValidator();
14657
14808
  import fs27 from "fs";
14658
14809
  import path30 from "path";
14659
- import { execSync as execSync8 } from "child_process";
14810
+ import { execSync as execSync9 } from "child_process";
14660
14811
  var SNAPSHOT_DIR = "context-snapshots";
14661
14812
  function snapshotDir() {
14662
14813
  return path30.join(getProjectRoot(), ".kuma", SNAPSHOT_DIR);
@@ -14728,7 +14879,7 @@ function formatSnapshot(snapshot) {
14728
14879
  function getGitDiffStat2() {
14729
14880
  try {
14730
14881
  const root = getProjectRoot();
14731
- const stdout = execSync8("git diff --stat", {
14882
+ const stdout = execSync9("git diff --stat", {
14732
14883
  cwd: root,
14733
14884
  encoding: "utf-8",
14734
14885
  timeout: 3e3
@@ -15513,25 +15664,25 @@ async function main() {
15513
15664
  } catch {
15514
15665
  }
15515
15666
  try {
15516
- const { execSync: execSync10 } = await import("child_process");
15667
+ const { execSync: execSync11 } = await import("child_process");
15517
15668
  try {
15518
- execSync10("pkill -f 'jest' 2>/dev/null || true");
15669
+ execSync11("pkill -f 'jest' 2>/dev/null || true");
15519
15670
  } catch {
15520
15671
  }
15521
15672
  try {
15522
- execSync10("pkill -f 'jest-worker' 2>/dev/null || true");
15673
+ execSync11("pkill -f 'jest-worker' 2>/dev/null || true");
15523
15674
  } catch {
15524
15675
  }
15525
15676
  try {
15526
- execSync10("pkill -f 'pnpm test' 2>/dev/null || true");
15677
+ execSync11("pkill -f 'pnpm test' 2>/dev/null || true");
15527
15678
  } catch {
15528
15679
  }
15529
15680
  try {
15530
- execSync10("pkill -f 'npm test' 2>/dev/null || true");
15681
+ execSync11("pkill -f 'npm test' 2>/dev/null || true");
15531
15682
  } catch {
15532
15683
  }
15533
15684
  try {
15534
- execSync10("pkill -f 'yarn test' 2>/dev/null || true");
15685
+ execSync11("pkill -f 'yarn test' 2>/dev/null || true");
15535
15686
  } catch {
15536
15687
  }
15537
15688
  console.error("\u2705 Killed orphaned test processes");
@@ -15680,6 +15831,12 @@ ${context}` : "";
15680
15831
  await refreshPackageBriefs2();
15681
15832
  } catch {
15682
15833
  }
15834
+ try {
15835
+ const { getWorktreeChangedFiles: getWorktreeChangedFiles2, updateWorktreeDirty: updateWorktreeDirty2 } = await Promise.resolve().then(() => (init_mapBackbone(), mapBackbone_exports));
15836
+ const { getProjectRoot: getProjectRoot2 } = await Promise.resolve().then(() => (init_pathValidator(), pathValidator_exports));
15837
+ updateWorktreeDirty2(getWorktreeChangedFiles2(getProjectRoot2(), 50).map((d) => d.file), getProjectRoot2());
15838
+ } catch {
15839
+ }
15683
15840
  try {
15684
15841
  const { clearDirty: clearDirty2 } = await Promise.resolve().then(() => (init_cacheFreshness(), cacheFreshness_exports));
15685
15842
  clearDirty2();
@@ -15757,8 +15914,8 @@ ${line}
15757
15914
  } catch {
15758
15915
  }
15759
15916
  try {
15760
- const { execSync: execSync10 } = await import("child_process");
15761
- const branch = execSync10("git rev-parse --abbrev-ref HEAD", {
15917
+ const { execSync: execSync11 } = await import("child_process");
15918
+ const branch = execSync11("git rev-parse --abbrev-ref HEAD", {
15762
15919
  cwd: root,
15763
15920
  encoding: "utf-8",
15764
15921
  timeout: 2e3,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@plumpslabs/kuma",
3
- "version": "2.4.16",
3
+ "version": "2.4.17",
4
4
  "description": "Safety-first context & orchestration engine for AI coding agents. MCP server with mandatory research pipeline, knowledge graph, impact analysis, decision memory, and safety guard — works with any MCP client.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
package/plugin.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://antigravity.google/schemas/v1/plugin.json",
3
3
  "name": "kuma",
4
- "version": "2.4.16",
4
+ "version": "2.4.17",
5
5
  "description": "Safety-first context & orchestration engine for AI coding agents. Shadow memory, gotcha lifecycle, blast radius impact analysis, and test verification.",
6
6
  "author": {
7
7
  "name": "plumpslabs",