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