@plumpslabs/kuma 2.4.15 → 2.4.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +750 -500
- package/package.json +1 -1
- package/plugin.json +1 -1
package/dist/index.js
CHANGED
|
@@ -4589,14 +4589,216 @@ var init_workspaceIntelligence = __esm({
|
|
|
4589
4589
|
}
|
|
4590
4590
|
});
|
|
4591
4591
|
|
|
4592
|
+
// src/engine/mapBackbone.ts
|
|
4593
|
+
var mapBackbone_exports = {};
|
|
4594
|
+
__export(mapBackbone_exports, {
|
|
4595
|
+
BACKBONE_MAX_FILES: () => BACKBONE_MAX_FILES,
|
|
4596
|
+
buildBackbone: () => buildBackbone,
|
|
4597
|
+
ensureBackbone: () => ensureBackbone,
|
|
4598
|
+
ensureMapped: () => ensureMapped,
|
|
4599
|
+
extractImportSources: () => extractImportSources,
|
|
4600
|
+
formatBackbone: () => formatBackbone,
|
|
4601
|
+
isMapEmpty: () => isMapEmpty,
|
|
4602
|
+
readMapMeta: () => readMapMeta
|
|
4603
|
+
});
|
|
4604
|
+
import fs9 from "fs";
|
|
4605
|
+
import path11 from "path";
|
|
4606
|
+
import fastGlob3 from "fast-glob";
|
|
4607
|
+
function extractImportSources(line) {
|
|
4608
|
+
const out = [];
|
|
4609
|
+
const t = line.trim();
|
|
4610
|
+
if (t.startsWith("//") || t.startsWith("#") || t.startsWith("*")) return out;
|
|
4611
|
+
for (const re of IMPORT_RES) {
|
|
4612
|
+
re.lastIndex = 0;
|
|
4613
|
+
let m;
|
|
4614
|
+
while ((m = re.exec(line)) !== null) {
|
|
4615
|
+
if (m[1] && m[1].startsWith(".")) out.push(m[1]);
|
|
4616
|
+
}
|
|
4617
|
+
}
|
|
4618
|
+
return out;
|
|
4619
|
+
}
|
|
4620
|
+
function mapMetaPath(root) {
|
|
4621
|
+
return path11.join(root || getProjectRoot(), MAP_META);
|
|
4622
|
+
}
|
|
4623
|
+
function readMapMeta(root) {
|
|
4624
|
+
try {
|
|
4625
|
+
const fp = mapMetaPath(root);
|
|
4626
|
+
if (fs9.existsSync(fp)) return JSON.parse(fs9.readFileSync(fp, "utf-8"));
|
|
4627
|
+
} catch {
|
|
4628
|
+
}
|
|
4629
|
+
return {};
|
|
4630
|
+
}
|
|
4631
|
+
function writeMapMeta(patch, root) {
|
|
4632
|
+
try {
|
|
4633
|
+
const fp = mapMetaPath(root);
|
|
4634
|
+
const prev = readMapMeta(root);
|
|
4635
|
+
fs9.writeFileSync(fp, JSON.stringify({ ...prev, ...patch }, null, 2), "utf-8");
|
|
4636
|
+
} catch {
|
|
4637
|
+
}
|
|
4638
|
+
}
|
|
4639
|
+
async function isMapEmpty() {
|
|
4640
|
+
try {
|
|
4641
|
+
const { getDb: getDb2 } = await Promise.resolve().then(() => (init_kumaDb(), kumaDb_exports));
|
|
4642
|
+
const db = await getDb2();
|
|
4643
|
+
const stmt = db.prepare(`SELECT COUNT(*) as cnt FROM nodes WHERE type = 'file'`);
|
|
4644
|
+
let n = 0;
|
|
4645
|
+
if (stmt.step()) n = Number(stmt.getAsObject().cnt) || 0;
|
|
4646
|
+
stmt.free();
|
|
4647
|
+
return n === 0;
|
|
4648
|
+
} catch {
|
|
4649
|
+
return true;
|
|
4650
|
+
}
|
|
4651
|
+
}
|
|
4652
|
+
async function buildBackbone(maxFiles = BACKBONE_MAX_FILES) {
|
|
4653
|
+
const started = Date.now();
|
|
4654
|
+
const root = getProjectRoot();
|
|
4655
|
+
const result = { files: 0, capped: false, nodes: 0, edges: 0, ms: 0, filesPerSec: 0 };
|
|
4656
|
+
let files = [];
|
|
4657
|
+
try {
|
|
4658
|
+
files = await fastGlob3([...DEFAULT_SOURCE_INCLUDES], {
|
|
4659
|
+
cwd: root,
|
|
4660
|
+
ignore: ["**/node_modules/**", "**/.git/**", "**/dist/**", "**/build/**", "**/.next/**", "**/coverage/**", "**/*.d.ts", "**/.kuma/**"],
|
|
4661
|
+
onlyFiles: true,
|
|
4662
|
+
deep: 7,
|
|
4663
|
+
dot: false
|
|
4664
|
+
});
|
|
4665
|
+
} catch {
|
|
4666
|
+
return result;
|
|
4667
|
+
}
|
|
4668
|
+
const capped = files.length > maxFiles;
|
|
4669
|
+
const batch = files.slice(0, maxFiles);
|
|
4670
|
+
result.files = batch.length;
|
|
4671
|
+
result.capped = capped;
|
|
4672
|
+
const existingEdges = /* @__PURE__ */ new Set();
|
|
4673
|
+
const existingFiles = /* @__PURE__ */ new Set();
|
|
4674
|
+
try {
|
|
4675
|
+
const { getDb: getDb2 } = await Promise.resolve().then(() => (init_kumaDb(), kumaDb_exports));
|
|
4676
|
+
const db = await getDb2();
|
|
4677
|
+
const stmt = db.prepare(`SELECT source_id, target_id FROM edges WHERE type = 'imports'`);
|
|
4678
|
+
while (stmt.step()) {
|
|
4679
|
+
const r = stmt.getAsObject();
|
|
4680
|
+
existingEdges.add(`${r.source_id}\u2192${r.target_id}`);
|
|
4681
|
+
}
|
|
4682
|
+
stmt.free();
|
|
4683
|
+
const fStmt = db.prepare(`SELECT id FROM nodes WHERE type = 'file'`);
|
|
4684
|
+
while (fStmt.step()) existingFiles.add(fStmt.getAsObject().id);
|
|
4685
|
+
fStmt.free();
|
|
4686
|
+
} catch {
|
|
4687
|
+
}
|
|
4688
|
+
for (const filePath of batch) {
|
|
4689
|
+
try {
|
|
4690
|
+
const full = path11.join(root, filePath);
|
|
4691
|
+
const stat = fs9.statSync(full);
|
|
4692
|
+
if (!stat.isFile() || stat.size > 512 * 1024) continue;
|
|
4693
|
+
const fileId = `file::${filePath}`;
|
|
4694
|
+
if (!existingFiles.has(fileId)) {
|
|
4695
|
+
try {
|
|
4696
|
+
await upsertNode({ id: fileId, type: "file", name: filePath, filePath, metadata: { backbone: true } });
|
|
4697
|
+
existingFiles.add(fileId);
|
|
4698
|
+
result.nodes++;
|
|
4699
|
+
} catch {
|
|
4700
|
+
continue;
|
|
4701
|
+
}
|
|
4702
|
+
}
|
|
4703
|
+
const content = fs9.readFileSync(full, "utf-8");
|
|
4704
|
+
const seen = /* @__PURE__ */ new Set();
|
|
4705
|
+
for (const line of content.split("\n")) {
|
|
4706
|
+
for (const src of extractImportSources(line)) {
|
|
4707
|
+
if (seen.has(src)) continue;
|
|
4708
|
+
seen.add(src);
|
|
4709
|
+
try {
|
|
4710
|
+
const resolved = resolveImportPath(filePath, src, root);
|
|
4711
|
+
const key = resolved ? `${fileId}\u2192file::${resolved}` : "";
|
|
4712
|
+
if (resolved && !existingEdges.has(key)) {
|
|
4713
|
+
await addEdge({ sourceId: fileId, targetId: `file::${resolved}`, type: "imports" });
|
|
4714
|
+
existingEdges.add(key);
|
|
4715
|
+
result.edges++;
|
|
4716
|
+
}
|
|
4717
|
+
} catch {
|
|
4718
|
+
}
|
|
4719
|
+
}
|
|
4720
|
+
}
|
|
4721
|
+
} catch {
|
|
4722
|
+
}
|
|
4723
|
+
}
|
|
4724
|
+
result.ms = Date.now() - started;
|
|
4725
|
+
result.filesPerSec = result.ms > 0 ? Math.round(result.files / result.ms * 1e3) : result.files;
|
|
4726
|
+
writeMapMeta({
|
|
4727
|
+
backboneAt: Date.now(),
|
|
4728
|
+
backboneFiles: result.files,
|
|
4729
|
+
backboneCapped: result.capped,
|
|
4730
|
+
backboneMs: result.ms,
|
|
4731
|
+
filesPerSec: result.filesPerSec
|
|
4732
|
+
});
|
|
4733
|
+
return result;
|
|
4734
|
+
}
|
|
4735
|
+
async function ensureBackbone() {
|
|
4736
|
+
try {
|
|
4737
|
+
if (!await isMapEmpty()) return null;
|
|
4738
|
+
return await buildBackbone();
|
|
4739
|
+
} catch {
|
|
4740
|
+
return null;
|
|
4741
|
+
}
|
|
4742
|
+
}
|
|
4743
|
+
function formatBackbone(r) {
|
|
4744
|
+
return `\u{1F5FA}\uFE0F Backbone: ${r.files} file(s)${r.capped ? ` (capped at ${BACKBONE_MAX_FILES})` : ""}, ${r.edges} import edge(s) in ${r.ms}ms (~${r.filesPerSec} files/s) \u2014 approximate tier, symbols fill in on demand.`;
|
|
4745
|
+
}
|
|
4746
|
+
async function ensureMapped(files) {
|
|
4747
|
+
const targets = [...new Set(files.map((f) => f.trim()).filter(Boolean))].slice(0, 10);
|
|
4748
|
+
if (targets.length === 0) return { filled: 0 };
|
|
4749
|
+
let missing = [];
|
|
4750
|
+
try {
|
|
4751
|
+
const { getDb: getDb2 } = await Promise.resolve().then(() => (init_kumaDb(), kumaDb_exports));
|
|
4752
|
+
const db = await getDb2();
|
|
4753
|
+
for (const f of targets) {
|
|
4754
|
+
const stmt = db.prepare(
|
|
4755
|
+
`SELECT COUNT(*) as cnt FROM nodes WHERE type IN ('function','class','method','interface') AND file_path LIKE ?`
|
|
4756
|
+
);
|
|
4757
|
+
stmt.bind([`%${path11.basename(f)}%`]);
|
|
4758
|
+
let n = 0;
|
|
4759
|
+
if (stmt.step()) n = Number(stmt.getAsObject().cnt) || 0;
|
|
4760
|
+
stmt.free();
|
|
4761
|
+
if (n === 0) missing.push(f);
|
|
4762
|
+
}
|
|
4763
|
+
} catch {
|
|
4764
|
+
missing = targets;
|
|
4765
|
+
}
|
|
4766
|
+
if (missing.length === 0) return { filled: 0 };
|
|
4767
|
+
try {
|
|
4768
|
+
const { scanCodebase: scanCodebase2 } = await Promise.resolve().then(() => (init_kumaCodeScanner(), kumaCodeScanner_exports));
|
|
4769
|
+
const res = await scanCodebase2({ include: missing, force: true, maxFiles: missing.length });
|
|
4770
|
+
if (res.filesScanned > 0) writeMapMeta({ precisionAt: Date.now() });
|
|
4771
|
+
return { filled: Math.min(missing.length, res.filesScanned) };
|
|
4772
|
+
} catch {
|
|
4773
|
+
return { filled: 0 };
|
|
4774
|
+
}
|
|
4775
|
+
}
|
|
4776
|
+
var BACKBONE_MAX_FILES, MAP_META, IMPORT_RES;
|
|
4777
|
+
var init_mapBackbone = __esm({
|
|
4778
|
+
"src/engine/mapBackbone.ts"() {
|
|
4779
|
+
"use strict";
|
|
4780
|
+
init_pathValidator();
|
|
4781
|
+
init_kumaGraph();
|
|
4782
|
+
init_kumaCodeScanner();
|
|
4783
|
+
init_languageSupport();
|
|
4784
|
+
BACKBONE_MAX_FILES = 2e3;
|
|
4785
|
+
MAP_META = ".kuma/map-meta.json";
|
|
4786
|
+
IMPORT_RES = [
|
|
4787
|
+
/(?:import)\s+(?:[\w*{},\s]+\s+from\s+|[\w$]+\s+)?['"]([^'"]+)['"]/g,
|
|
4788
|
+
/(?:from)\s+["']?([a-zA-Z0-9_./-]+)["']?\s+import\s+/g,
|
|
4789
|
+
/require\s*\(\s*['"]([^'"]+)['"]\s*\)/g
|
|
4790
|
+
];
|
|
4791
|
+
}
|
|
4792
|
+
});
|
|
4793
|
+
|
|
4592
4794
|
// src/engine/symbolReach.ts
|
|
4593
4795
|
var symbolReach_exports = {};
|
|
4594
4796
|
__export(symbolReach_exports, {
|
|
4595
4797
|
formatReachability: () => formatReachability,
|
|
4596
4798
|
symbolReachability: () => symbolReachability
|
|
4597
4799
|
});
|
|
4598
|
-
import
|
|
4599
|
-
import
|
|
4800
|
+
import fs10 from "fs";
|
|
4801
|
+
import path12 from "path";
|
|
4600
4802
|
import { execSync as execSync4 } from "child_process";
|
|
4601
4803
|
async function graphReach(symbol, limit) {
|
|
4602
4804
|
const rows = [];
|
|
@@ -4663,16 +4865,16 @@ function ripgrepReach(symbol, root, limit) {
|
|
|
4663
4865
|
}
|
|
4664
4866
|
for (const c of [...callers].slice(0, BERBEDA)) {
|
|
4665
4867
|
const [fp] = c.split(":");
|
|
4666
|
-
const dir =
|
|
4667
|
-
const stem =
|
|
4868
|
+
const dir = path12.dirname(fp);
|
|
4869
|
+
const stem = path12.basename(fp, path12.extname(fp)).split(/[-_.]/)[0];
|
|
4668
4870
|
try {
|
|
4669
|
-
const dirFull =
|
|
4670
|
-
if (!
|
|
4671
|
-
for (const f of
|
|
4871
|
+
const dirFull = path12.join(root, dir);
|
|
4872
|
+
if (!fs10.existsSync(dirFull)) continue;
|
|
4873
|
+
for (const f of fs10.readdirSync(dirFull)) {
|
|
4672
4874
|
if (!/(\.test\.|\.spec\.|_test\.)/i.test(f)) continue;
|
|
4673
4875
|
const low = f.toLowerCase();
|
|
4674
4876
|
if (low.includes(stem.toLowerCase()) || low.includes(symbol.toLowerCase())) {
|
|
4675
|
-
const rel =
|
|
4877
|
+
const rel = path12.join(dir, f);
|
|
4676
4878
|
if (!rows.some((r) => r.test === rel)) {
|
|
4677
4879
|
rows.push({ test: rel, via: fp, evidence: `${rel} sibling-matches caller ${fp} (called at ${c})` });
|
|
4678
4880
|
}
|
|
@@ -4822,17 +5024,17 @@ __export(impactAnalysis_exports, {
|
|
|
4822
5024
|
classifyDiffShape: () => classifyDiffShape,
|
|
4823
5025
|
getIndexerStatus: () => getIndexerStatus
|
|
4824
5026
|
});
|
|
4825
|
-
import
|
|
4826
|
-
import
|
|
5027
|
+
import fs11 from "fs";
|
|
5028
|
+
import path13 from "path";
|
|
4827
5029
|
import { execSync as execSync5 } from "child_process";
|
|
4828
|
-
import
|
|
5030
|
+
import fastGlob4 from "fast-glob";
|
|
4829
5031
|
function extOf(target) {
|
|
4830
|
-
const base =
|
|
5032
|
+
const base = path13.basename(target);
|
|
4831
5033
|
const dot = base.lastIndexOf(".");
|
|
4832
5034
|
return dot > 0 ? base.slice(dot).toLowerCase() : "";
|
|
4833
5035
|
}
|
|
4834
5036
|
function isExampleOrDocName(target) {
|
|
4835
|
-
const base =
|
|
5037
|
+
const base = path13.basename(target).toLowerCase();
|
|
4836
5038
|
return base.endsWith(".example") || base.startsWith(".env") || base.endsWith(".md") || base.endsWith(".txt") || base.endsWith(".rst") || base === "license" || base.startsWith("license.");
|
|
4837
5039
|
}
|
|
4838
5040
|
function classifyDiffShape(target, root) {
|
|
@@ -4865,7 +5067,7 @@ function classifyDiffShape(target, root) {
|
|
|
4865
5067
|
return { shape: "runtime-code", detail: "runtime code change" };
|
|
4866
5068
|
}
|
|
4867
5069
|
async function findImportingFiles(targetFile, root) {
|
|
4868
|
-
const normTarget = normalizeScope(
|
|
5070
|
+
const normTarget = normalizeScope(path13.normalize(targetFile)) || path13.normalize(targetFile);
|
|
4869
5071
|
try {
|
|
4870
5072
|
const db = await getDb();
|
|
4871
5073
|
const targetFileId = `file::${normTarget}`;
|
|
@@ -4904,10 +5106,10 @@ async function findImportingFiles(targetFile, root) {
|
|
|
4904
5106
|
}
|
|
4905
5107
|
} catch {
|
|
4906
5108
|
}
|
|
4907
|
-
const baseName =
|
|
4908
|
-
const relTarget =
|
|
5109
|
+
const baseName = path13.basename(normTarget, path13.extname(normTarget));
|
|
5110
|
+
const relTarget = path13.isAbsolute(normTarget) ? path13.relative(root, normTarget) : normTarget;
|
|
4909
5111
|
try {
|
|
4910
|
-
const files = await
|
|
5112
|
+
const files = await fastGlob4(
|
|
4911
5113
|
["**/*.{ts,tsx,js,jsx,mjs,cjs,py,go,rs}"],
|
|
4912
5114
|
{
|
|
4913
5115
|
cwd: root,
|
|
@@ -4922,10 +5124,10 @@ async function findImportingFiles(targetFile, root) {
|
|
|
4922
5124
|
"i"
|
|
4923
5125
|
);
|
|
4924
5126
|
for (const f of files) {
|
|
4925
|
-
if (
|
|
4926
|
-
const fullPath =
|
|
5127
|
+
if (path13.normalize(f) === path13.normalize(relTarget)) continue;
|
|
5128
|
+
const fullPath = path13.join(root, f);
|
|
4927
5129
|
try {
|
|
4928
|
-
const content =
|
|
5130
|
+
const content = fs11.readFileSync(fullPath, "utf-8");
|
|
4929
5131
|
const lines = content.split("\n");
|
|
4930
5132
|
const hitIdx = lines.findIndex((l) => importRegex.test(l));
|
|
4931
5133
|
if (hitIdx >= 0) {
|
|
@@ -4941,7 +5143,7 @@ async function findImportingFiles(targetFile, root) {
|
|
|
4941
5143
|
}
|
|
4942
5144
|
}
|
|
4943
5145
|
async function findRelatedTests(targetFile, root, owningPackage, additionalDependents = [], exactOnly = false) {
|
|
4944
|
-
const normTarget = normalizeScope(
|
|
5146
|
+
const normTarget = normalizeScope(path13.normalize(targetFile)) || path13.normalize(targetFile);
|
|
4945
5147
|
try {
|
|
4946
5148
|
const db = await getDb();
|
|
4947
5149
|
const targetFileId = `file::${normTarget}`;
|
|
@@ -4965,13 +5167,13 @@ async function findRelatedTests(targetFile, root, owningPackage, additionalDepen
|
|
|
4965
5167
|
}
|
|
4966
5168
|
} catch {
|
|
4967
5169
|
}
|
|
4968
|
-
const baseName =
|
|
5170
|
+
const baseName = path13.basename(normTarget, path13.extname(normTarget));
|
|
4969
5171
|
const testFiles = [];
|
|
4970
5172
|
const stems = /* @__PURE__ */ new Set();
|
|
4971
5173
|
if (baseName) stems.add(baseName);
|
|
4972
5174
|
if (!exactOnly) {
|
|
4973
5175
|
for (const dep of additionalDependents.slice(0, 3)) {
|
|
4974
|
-
const depBase =
|
|
5176
|
+
const depBase = path13.basename(dep, path13.extname(dep));
|
|
4975
5177
|
if (depBase) stems.add(depBase);
|
|
4976
5178
|
}
|
|
4977
5179
|
}
|
|
@@ -4987,7 +5189,7 @@ async function findRelatedTests(targetFile, root, owningPackage, additionalDepen
|
|
|
4987
5189
|
);
|
|
4988
5190
|
}
|
|
4989
5191
|
try {
|
|
4990
|
-
const matches = await
|
|
5192
|
+
const matches = await fastGlob4(testPatterns, {
|
|
4991
5193
|
cwd: root,
|
|
4992
5194
|
ignore: ["**/node_modules/**", "**/dist/**", "**/.git/**", "**/.kuma/**"],
|
|
4993
5195
|
onlyFiles: true
|
|
@@ -5006,13 +5208,13 @@ async function findRelatedTests(targetFile, root, owningPackage, additionalDepen
|
|
|
5006
5208
|
`**/__tests__/**/*${stem}*.*`
|
|
5007
5209
|
);
|
|
5008
5210
|
}
|
|
5009
|
-
const pkgTests = await
|
|
5010
|
-
cwd:
|
|
5211
|
+
const pkgTests = await fastGlob4(pkgPatterns, {
|
|
5212
|
+
cwd: path13.join(root, owningPackage.path),
|
|
5011
5213
|
ignore: ["**/node_modules/**", "**/dist/**"],
|
|
5012
5214
|
onlyFiles: true
|
|
5013
5215
|
});
|
|
5014
5216
|
for (const pt of pkgTests) {
|
|
5015
|
-
const fullRel =
|
|
5217
|
+
const fullRel = path13.join(owningPackage.path, pt);
|
|
5016
5218
|
if (!testFiles.includes(fullRel)) {
|
|
5017
5219
|
testFiles.push(fullRel);
|
|
5018
5220
|
}
|
|
@@ -5063,18 +5265,29 @@ function assessRisk(target, targetType, directDependents, downstreamPackages, af
|
|
|
5063
5265
|
}
|
|
5064
5266
|
async function getIndexerStatus() {
|
|
5065
5267
|
let graphEdges = false;
|
|
5268
|
+
let backboneOnly = false;
|
|
5066
5269
|
try {
|
|
5067
5270
|
const db = await getDb();
|
|
5068
5271
|
const stmt = db.prepare(`SELECT COUNT(*) as cnt FROM edges WHERE type IN ('imports','depends_on','calls','tests')`);
|
|
5069
5272
|
if (stmt.step()) graphEdges = Number(stmt.getAsObject().cnt) > 0;
|
|
5070
5273
|
stmt.free();
|
|
5274
|
+
const fStmt = db.prepare(`SELECT COUNT(*) as cnt FROM nodes WHERE type = 'file'`);
|
|
5275
|
+
let files = 0;
|
|
5276
|
+
if (fStmt.step()) files = Number(fStmt.getAsObject().cnt) || 0;
|
|
5277
|
+
fStmt.free();
|
|
5278
|
+
const sStmt = db.prepare(`SELECT COUNT(*) as cnt FROM nodes WHERE type IN ('function','class','method','interface')`);
|
|
5279
|
+
let syms = 0;
|
|
5280
|
+
if (sStmt.step()) syms = Number(sStmt.getAsObject().cnt) || 0;
|
|
5281
|
+
sStmt.free();
|
|
5282
|
+
backboneOnly = files > 0 && syms === 0;
|
|
5071
5283
|
} catch {
|
|
5072
5284
|
}
|
|
5073
5285
|
return {
|
|
5074
5286
|
tier: graphEdges ? 1 : 2,
|
|
5075
5287
|
graphEdges,
|
|
5288
|
+
backboneOnly,
|
|
5076
5289
|
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)"
|
|
5290
|
+
note: backboneOnly ? "Backbone-tier coverage: import graph only (approximate) \u2014 symbols fill in on demand when impact/research touches an area" : graphEdges ? "Tier 1: graph edges grounded the verdict (Tier 2 ripgrep fallback available)" : "Tier 2: ripgrep import-regex fallback (no graph edges; run a scan to reach Tier 1; LSP indexers are future work per #35)"
|
|
5078
5291
|
};
|
|
5079
5292
|
}
|
|
5080
5293
|
async function calculateBlastRadius(target, options = {}) {
|
|
@@ -5100,6 +5313,13 @@ async function calculateBlastRadius(target, options = {}) {
|
|
|
5100
5313
|
const rev = getReverseDependencies(owningPackage.name, wsInfo);
|
|
5101
5314
|
downstreamPackages.push(...rev.map((p) => p.name));
|
|
5102
5315
|
}
|
|
5316
|
+
if (targetType === "file") {
|
|
5317
|
+
try {
|
|
5318
|
+
const { ensureMapped: ensureMapped2 } = await Promise.resolve().then(() => (init_mapBackbone(), mapBackbone_exports));
|
|
5319
|
+
await ensureMapped2([target]);
|
|
5320
|
+
} catch {
|
|
5321
|
+
}
|
|
5322
|
+
}
|
|
5103
5323
|
let directDependents = [];
|
|
5104
5324
|
let evidence = [];
|
|
5105
5325
|
if (targetType === "file" || targetType === "symbol") {
|
|
@@ -6339,27 +6559,27 @@ async function codebaseSearchFallback(query, limit = 20) {
|
|
|
6339
6559
|
if (results.length >= limit || depth > MAX_WALK_DEPTH) return;
|
|
6340
6560
|
let entries = [];
|
|
6341
6561
|
try {
|
|
6342
|
-
entries =
|
|
6562
|
+
entries = fs35.readdirSync(dir);
|
|
6343
6563
|
} catch {
|
|
6344
6564
|
return;
|
|
6345
6565
|
}
|
|
6346
6566
|
for (const entry of entries) {
|
|
6347
6567
|
if (entry.startsWith(".") || entry === "node_modules" || entry === "dist" || entry === "build") continue;
|
|
6348
|
-
const full =
|
|
6568
|
+
const full = path38.join(dir, entry);
|
|
6349
6569
|
try {
|
|
6350
|
-
const stat =
|
|
6570
|
+
const stat = fs35.statSync(full);
|
|
6351
6571
|
if (stat.isDirectory()) {
|
|
6352
6572
|
walk2(full, depth + 1);
|
|
6353
6573
|
} else if (entry.toLowerCase().includes(query.toLowerCase())) {
|
|
6354
|
-
results.push(
|
|
6574
|
+
results.push(path38.relative(root, full));
|
|
6355
6575
|
}
|
|
6356
6576
|
} catch {
|
|
6357
6577
|
}
|
|
6358
6578
|
}
|
|
6359
6579
|
};
|
|
6360
6580
|
var walk = walk2;
|
|
6361
|
-
const
|
|
6362
|
-
const
|
|
6581
|
+
const fs35 = await import("fs");
|
|
6582
|
+
const path38 = await import("path");
|
|
6363
6583
|
const root = process.cwd();
|
|
6364
6584
|
const results = [];
|
|
6365
6585
|
const MAX_WALK_DEPTH = 8;
|
|
@@ -6641,8 +6861,8 @@ __export(kumaShared_exports, {
|
|
|
6641
6861
|
isTestTool: () => isTestTool
|
|
6642
6862
|
});
|
|
6643
6863
|
import { execSync as execSync6 } from "child_process";
|
|
6644
|
-
import
|
|
6645
|
-
import
|
|
6864
|
+
import fs12 from "fs";
|
|
6865
|
+
import path14 from "path";
|
|
6646
6866
|
function isEditTool(toolName) {
|
|
6647
6867
|
const n = (toolName || "").toLowerCase();
|
|
6648
6868
|
return n.includes("edit") || n.includes("write") || n.includes("patch") || n.includes("apply") || n.includes("replace");
|
|
@@ -6748,10 +6968,10 @@ function hasVerificationEvidence(toolCalls) {
|
|
|
6748
6968
|
}
|
|
6749
6969
|
function hasVerificationInHookLog(hours = 24) {
|
|
6750
6970
|
try {
|
|
6751
|
-
const fp =
|
|
6752
|
-
if (!
|
|
6971
|
+
const fp = path14.join(getProjectRoot(), ".kuma", "injections.jsonl");
|
|
6972
|
+
if (!fs12.existsSync(fp)) return false;
|
|
6753
6973
|
const cutoff = Date.now() - hours * 60 * 60 * 1e3;
|
|
6754
|
-
const lines =
|
|
6974
|
+
const lines = fs12.readFileSync(fp, "utf-8").split("\n");
|
|
6755
6975
|
for (const line of lines) {
|
|
6756
6976
|
if (!line.trim()) continue;
|
|
6757
6977
|
try {
|
|
@@ -6893,19 +7113,19 @@ __export(kumaMemory_exports, {
|
|
|
6893
7113
|
scoreMemoryRelevance: () => scoreMemoryRelevance,
|
|
6894
7114
|
shouldRecordDecision: () => shouldRecordDecision
|
|
6895
7115
|
});
|
|
6896
|
-
import
|
|
6897
|
-
import
|
|
7116
|
+
import fs13 from "fs";
|
|
7117
|
+
import path15 from "path";
|
|
6898
7118
|
function scoreMemoryRelevance(context, limit = 5) {
|
|
6899
7119
|
const results = [];
|
|
6900
|
-
const kumaDir =
|
|
6901
|
-
if (!
|
|
7120
|
+
const kumaDir = path15.join(getProjectRoot(), MEMORY_DIR);
|
|
7121
|
+
if (!fs13.existsSync(kumaDir)) return [];
|
|
6902
7122
|
const terms = Array.from(new Set(context.toLowerCase().split(/[\s/._-]+/).filter((w) => w.length > 2)));
|
|
6903
7123
|
if (terms.length === 0) return [];
|
|
6904
7124
|
try {
|
|
6905
|
-
const files =
|
|
7125
|
+
const files = fs13.readdirSync(kumaDir).filter((f) => f.endsWith(".md"));
|
|
6906
7126
|
for (const file of files) {
|
|
6907
7127
|
try {
|
|
6908
|
-
const content =
|
|
7128
|
+
const content = fs13.readFileSync(path15.join(kumaDir, file), "utf-8");
|
|
6909
7129
|
const lower = content.toLowerCase();
|
|
6910
7130
|
let matchCount = 0;
|
|
6911
7131
|
for (const term of terms) {
|
|
@@ -7087,8 +7307,8 @@ __export(cacheFreshness_exports, {
|
|
|
7087
7307
|
isStale: () => isStale,
|
|
7088
7308
|
markDirty: () => markDirty
|
|
7089
7309
|
});
|
|
7090
|
-
import
|
|
7091
|
-
import
|
|
7310
|
+
import fs14 from "fs";
|
|
7311
|
+
import path16 from "path";
|
|
7092
7312
|
function isStale(savedAtMs, ttlMs, nowMs = Date.now()) {
|
|
7093
7313
|
if (!savedAtMs) return true;
|
|
7094
7314
|
return nowMs - savedAtMs > ttlMs;
|
|
@@ -7101,13 +7321,13 @@ function formatAge(savedAtMs, nowMs = Date.now()) {
|
|
|
7101
7321
|
return `${Math.floor(s / 86400)}d`;
|
|
7102
7322
|
}
|
|
7103
7323
|
function dirtyPath() {
|
|
7104
|
-
return
|
|
7324
|
+
return path16.join(getProjectRoot(), DIRTY_FILE);
|
|
7105
7325
|
}
|
|
7106
7326
|
function loadDirty() {
|
|
7107
7327
|
try {
|
|
7108
7328
|
const fp = dirtyPath();
|
|
7109
|
-
if (
|
|
7110
|
-
const parsed = JSON.parse(
|
|
7329
|
+
if (fs14.existsSync(fp)) {
|
|
7330
|
+
const parsed = JSON.parse(fs14.readFileSync(fp, "utf-8"));
|
|
7111
7331
|
if (parsed && typeof parsed === "object") return parsed;
|
|
7112
7332
|
}
|
|
7113
7333
|
} catch {
|
|
@@ -7117,14 +7337,14 @@ function loadDirty() {
|
|
|
7117
7337
|
function markDirty(filePath) {
|
|
7118
7338
|
try {
|
|
7119
7339
|
const fp = dirtyPath();
|
|
7120
|
-
const dir =
|
|
7121
|
-
if (!
|
|
7340
|
+
const dir = path16.dirname(fp);
|
|
7341
|
+
if (!fs14.existsSync(dir)) fs14.mkdirSync(dir, { recursive: true });
|
|
7122
7342
|
const dirty = loadDirty();
|
|
7123
7343
|
dirty[filePath] = Date.now();
|
|
7124
7344
|
const keys = Object.keys(dirty).sort((a, b) => dirty[b] - dirty[a]).slice(0, 200);
|
|
7125
7345
|
const bounded = {};
|
|
7126
7346
|
for (const k of keys) bounded[k] = dirty[k];
|
|
7127
|
-
|
|
7347
|
+
fs14.writeFileSync(fp, JSON.stringify(bounded), "utf-8");
|
|
7128
7348
|
} catch {
|
|
7129
7349
|
}
|
|
7130
7350
|
}
|
|
@@ -7134,7 +7354,7 @@ function getDirtyFiles() {
|
|
|
7134
7354
|
function clearDirty() {
|
|
7135
7355
|
try {
|
|
7136
7356
|
const fp = dirtyPath();
|
|
7137
|
-
if (
|
|
7357
|
+
if (fs14.existsSync(fp)) fs14.rmSync(fp, { force: true });
|
|
7138
7358
|
} catch {
|
|
7139
7359
|
}
|
|
7140
7360
|
}
|
|
@@ -7154,8 +7374,8 @@ var codeReuseEngine_exports = {};
|
|
|
7154
7374
|
__export(codeReuseEngine_exports, {
|
|
7155
7375
|
findReusableSymbols: () => findReusableSymbols
|
|
7156
7376
|
});
|
|
7157
|
-
import
|
|
7158
|
-
import
|
|
7377
|
+
import path17 from "path";
|
|
7378
|
+
import fs15 from "fs";
|
|
7159
7379
|
async function findReusableSymbols(query, scope) {
|
|
7160
7380
|
const cleanQuery = query.trim().toLowerCase();
|
|
7161
7381
|
const searchTokens = cleanQuery.replace(/[^a-zA-Z0-9_\s]/g, " ").split(/\s+/).filter((t) => t.length >= 2);
|
|
@@ -7278,7 +7498,7 @@ function detectRecommendedUtilDirectory() {
|
|
|
7278
7498
|
"utils"
|
|
7279
7499
|
];
|
|
7280
7500
|
for (const c of candidates) {
|
|
7281
|
-
if (
|
|
7501
|
+
if (fs15.existsSync(path17.resolve(root, c))) {
|
|
7282
7502
|
return c;
|
|
7283
7503
|
}
|
|
7284
7504
|
}
|
|
@@ -7297,7 +7517,7 @@ var domainClusterEngine_exports = {};
|
|
|
7297
7517
|
__export(domainClusterEngine_exports, {
|
|
7298
7518
|
buildSubsystemClusters: () => buildSubsystemClusters
|
|
7299
7519
|
});
|
|
7300
|
-
import
|
|
7520
|
+
import path18 from "path";
|
|
7301
7521
|
async function buildSubsystemClusters() {
|
|
7302
7522
|
const db = await getDb();
|
|
7303
7523
|
const fileStmt = db.prepare(`
|
|
@@ -7374,7 +7594,7 @@ async function buildSubsystemClusters() {
|
|
|
7374
7594
|
for (const [cKey, files] of clusterFileMap.entries()) {
|
|
7375
7595
|
for (const f of files) {
|
|
7376
7596
|
fileToCluster.set(f, cKey);
|
|
7377
|
-
fileToCluster.set(
|
|
7597
|
+
fileToCluster.set(path18.normalize(f), cKey);
|
|
7378
7598
|
}
|
|
7379
7599
|
}
|
|
7380
7600
|
const clusterInteractions = /* @__PURE__ */ new Map();
|
|
@@ -7382,8 +7602,8 @@ async function buildSubsystemClusters() {
|
|
|
7382
7602
|
const srcFile = extractFilePathFromNodeId(e.source);
|
|
7383
7603
|
const tgtFile = extractFilePathFromNodeId(e.target);
|
|
7384
7604
|
if (!srcFile || !tgtFile) continue;
|
|
7385
|
-
const srcCluster = fileToCluster.get(srcFile) || fileToCluster.get(
|
|
7386
|
-
const tgtCluster = fileToCluster.get(tgtFile) || fileToCluster.get(
|
|
7605
|
+
const srcCluster = fileToCluster.get(srcFile) || fileToCluster.get(path18.normalize(srcFile));
|
|
7606
|
+
const tgtCluster = fileToCluster.get(tgtFile) || fileToCluster.get(path18.normalize(tgtFile));
|
|
7387
7607
|
if (srcCluster && tgtCluster && srcCluster !== tgtCluster) {
|
|
7388
7608
|
const pairKey = `${srcCluster}->${tgtCluster}`;
|
|
7389
7609
|
const stats = clusterInteractions.get(pairKey) || { calls: 0, imports: 0 };
|
|
@@ -7405,13 +7625,13 @@ async function buildSubsystemClusters() {
|
|
|
7405
7625
|
const clusterId = nodeId("feature_domain", cKey);
|
|
7406
7626
|
const name = formatClusterName(cKey);
|
|
7407
7627
|
const role = inferSubsystemRole(cKey, files);
|
|
7408
|
-
const entrypoints = files.filter((f) => /index|main|server|app|engine|root/i.test(
|
|
7628
|
+
const entrypoints = files.filter((f) => /index|main|server|app|engine|root/i.test(path18.basename(f))).slice(0, 3);
|
|
7409
7629
|
if (entrypoints.length === 0 && files.length > 0) {
|
|
7410
7630
|
entrypoints.push(files[0]);
|
|
7411
7631
|
}
|
|
7412
7632
|
const allSyms = [];
|
|
7413
7633
|
for (const f of files) {
|
|
7414
|
-
const syms = fileSymbols.get(f) || fileSymbols.get(
|
|
7634
|
+
const syms = fileSymbols.get(f) || fileSymbols.get(path18.normalize(f)) || [];
|
|
7415
7635
|
for (const s of syms) {
|
|
7416
7636
|
if (!allSyms.includes(s)) allSyms.push(s);
|
|
7417
7637
|
}
|
|
@@ -7590,7 +7810,7 @@ function inferSubsystemRole(key, files) {
|
|
|
7590
7810
|
if (k.includes("util") || k.includes("common")) {
|
|
7591
7811
|
return "Shared path validation, configuration loading, and platform detection helpers.";
|
|
7592
7812
|
}
|
|
7593
|
-
return `Core subsystem handling ${files.slice(0, 3).map((f) =>
|
|
7813
|
+
return `Core subsystem handling ${files.slice(0, 3).map((f) => path18.basename(f)).join(", ")}.`;
|
|
7594
7814
|
}
|
|
7595
7815
|
function inferTypedVerb(sourceKey, targetKey, _stats) {
|
|
7596
7816
|
const src = sourceKey.toLowerCase();
|
|
@@ -7669,18 +7889,18 @@ __export(domainRules_exports, {
|
|
|
7669
7889
|
readLayer: () => readLayer,
|
|
7670
7890
|
writeLayer: () => writeLayer
|
|
7671
7891
|
});
|
|
7672
|
-
import
|
|
7673
|
-
import
|
|
7892
|
+
import fs16 from "fs";
|
|
7893
|
+
import path19 from "path";
|
|
7674
7894
|
function layerFilePath(layer) {
|
|
7675
|
-
return
|
|
7895
|
+
return path19.join(getProjectRoot(), ".kuma", LAYER_FILES[layer].filename);
|
|
7676
7896
|
}
|
|
7677
7897
|
function ensureLayerFile(layer) {
|
|
7678
7898
|
const fp = layerFilePath(layer);
|
|
7679
|
-
if (!
|
|
7899
|
+
if (!fs16.existsSync(fp)) {
|
|
7680
7900
|
const template = layer === "arch_flow" ? ARCH_FLOW_TEMPLATE : GOTCHAS_TEMPLATE;
|
|
7681
|
-
const dir =
|
|
7682
|
-
if (!
|
|
7683
|
-
|
|
7901
|
+
const dir = path19.dirname(fp);
|
|
7902
|
+
if (!fs16.existsSync(dir)) fs16.mkdirSync(dir, { recursive: true });
|
|
7903
|
+
fs16.writeFileSync(fp, template, "utf-8");
|
|
7684
7904
|
console.error(`[DomainRules] Auto-created ${LAYER_FILES[layer].filename}`);
|
|
7685
7905
|
}
|
|
7686
7906
|
return fp;
|
|
@@ -7688,7 +7908,7 @@ function ensureLayerFile(layer) {
|
|
|
7688
7908
|
function readLayer(layer) {
|
|
7689
7909
|
try {
|
|
7690
7910
|
const fp = ensureLayerFile(layer);
|
|
7691
|
-
return
|
|
7911
|
+
return fs16.readFileSync(fp, "utf-8");
|
|
7692
7912
|
} catch (err) {
|
|
7693
7913
|
return `Error reading ${layer}: ${err}`;
|
|
7694
7914
|
}
|
|
@@ -7696,7 +7916,7 @@ function readLayer(layer) {
|
|
|
7696
7916
|
function writeLayer(layer, content) {
|
|
7697
7917
|
try {
|
|
7698
7918
|
const fp = ensureLayerFile(layer);
|
|
7699
|
-
|
|
7919
|
+
fs16.writeFileSync(fp, content, "utf-8");
|
|
7700
7920
|
const label = LAYER_FILES[layer].label;
|
|
7701
7921
|
sessionMemory.recordToolCall("kuma_memory", { action: `write_${layer}` });
|
|
7702
7922
|
return `\u2705 **${label}** updated successfully.`;
|
|
@@ -7707,9 +7927,9 @@ function writeLayer(layer, content) {
|
|
|
7707
7927
|
function appendToLayer(layer, entry) {
|
|
7708
7928
|
try {
|
|
7709
7929
|
const fp = ensureLayerFile(layer);
|
|
7710
|
-
const existing =
|
|
7930
|
+
const existing = fs16.readFileSync(fp, "utf-8");
|
|
7711
7931
|
const newContent = existing.trimEnd() + "\n\n" + entry.trim() + "\n";
|
|
7712
|
-
|
|
7932
|
+
fs16.writeFileSync(fp, newContent, "utf-8");
|
|
7713
7933
|
return `\u2705 Entry added to **${LAYER_FILES[layer].label}**.`;
|
|
7714
7934
|
} catch (err) {
|
|
7715
7935
|
return `\u274C Failed to append: ${err}`;
|
|
@@ -7719,7 +7939,7 @@ function getActiveGotchas() {
|
|
|
7719
7939
|
const results = [];
|
|
7720
7940
|
try {
|
|
7721
7941
|
const fp = ensureLayerFile("gotcha");
|
|
7722
|
-
const content =
|
|
7942
|
+
const content = fs16.readFileSync(fp, "utf-8");
|
|
7723
7943
|
const lines = content.split("\n");
|
|
7724
7944
|
let currentSection = "";
|
|
7725
7945
|
let currentFilePath = "";
|
|
@@ -7755,9 +7975,9 @@ function getActiveGotchas() {
|
|
|
7755
7975
|
function checkFileGotchas(filePath) {
|
|
7756
7976
|
const gotchas = getActiveGotchas();
|
|
7757
7977
|
const warnings = [];
|
|
7758
|
-
const base =
|
|
7978
|
+
const base = path19.basename(filePath);
|
|
7759
7979
|
for (const g of gotchas) {
|
|
7760
|
-
const gBase =
|
|
7980
|
+
const gBase = path19.basename(g.filePath);
|
|
7761
7981
|
if (filePath.includes(g.filePath) || g.filePath.includes(filePath) || base && gBase && base === gBase) {
|
|
7762
7982
|
const icon = g.severity === "critical" ? "\u{1F534}" : g.severity === "high" ? "\u{1F7E0}" : g.severity === "medium" ? "\u{1F7E1}" : "\u{1F7E2}";
|
|
7763
7983
|
warnings.push(`${icon} **Gotcha**: ${g.description} (${g.severity})`);
|
|
@@ -7857,8 +8077,8 @@ __export(kumaInject_exports, {
|
|
|
7857
8077
|
parseHookInput: () => parseHookInput,
|
|
7858
8078
|
trackFileEditLoop: () => trackFileEditLoop
|
|
7859
8079
|
});
|
|
7860
|
-
import
|
|
7861
|
-
import
|
|
8080
|
+
import fs17 from "fs";
|
|
8081
|
+
import path20 from "path";
|
|
7862
8082
|
function hashFileContent(filePath) {
|
|
7863
8083
|
return hashFile(filePath);
|
|
7864
8084
|
}
|
|
@@ -7869,10 +8089,10 @@ function isGotchaFresh(storedHash, currentHash) {
|
|
|
7869
8089
|
}
|
|
7870
8090
|
async function getFreshGotchasForFile(filePath, limit = 5, includeStale = false) {
|
|
7871
8091
|
const root = getProjectRoot();
|
|
7872
|
-
const base =
|
|
8092
|
+
const base = path20.basename(filePath);
|
|
7873
8093
|
try {
|
|
7874
|
-
const dbFile =
|
|
7875
|
-
if (
|
|
8094
|
+
const dbFile = path20.join(root, ".kuma", "kuma.db");
|
|
8095
|
+
if (fs17.existsSync(dbFile)) {
|
|
7876
8096
|
const { getDb: getDb2 } = await Promise.resolve().then(() => (init_kumaDb(), kumaDb_exports));
|
|
7877
8097
|
const db = await getDb2();
|
|
7878
8098
|
const stmt = db.prepare(`
|
|
@@ -7913,11 +8133,11 @@ async function getFreshGotchasForFile(filePath, limit = 5, includeStale = false)
|
|
|
7913
8133
|
} catch {
|
|
7914
8134
|
}
|
|
7915
8135
|
try {
|
|
7916
|
-
if (!
|
|
8136
|
+
if (!fs17.existsSync(path20.join(root, ".kuma"))) return [];
|
|
7917
8137
|
const { getActiveGotchas: getActiveGotchas2 } = await Promise.resolve().then(() => (init_domainRules(), domainRules_exports));
|
|
7918
8138
|
const allGotchas = getActiveGotchas2();
|
|
7919
8139
|
const matched = allGotchas.filter(
|
|
7920
|
-
(g) => g.filePath.includes(filePath) || filePath.includes(g.filePath) || base &&
|
|
8140
|
+
(g) => g.filePath.includes(filePath) || filePath.includes(g.filePath) || base && path20.basename(g.filePath) === base
|
|
7921
8141
|
);
|
|
7922
8142
|
if (matched.length > 0) {
|
|
7923
8143
|
return matched.slice(0, limit).map((g) => ({
|
|
@@ -7936,8 +8156,8 @@ async function getFreshGotchasForFile(filePath, limit = 5, includeStale = false)
|
|
|
7936
8156
|
async function getFileTrace(filePath, limit = 8) {
|
|
7937
8157
|
try {
|
|
7938
8158
|
const root = getProjectRoot();
|
|
7939
|
-
const dbFile =
|
|
7940
|
-
if (!
|
|
8159
|
+
const dbFile = path20.join(root, ".kuma", "kuma.db");
|
|
8160
|
+
if (!fs17.existsSync(dbFile)) return [];
|
|
7941
8161
|
const { getDb: getDb2 } = await Promise.resolve().then(() => (init_kumaDb(), kumaDb_exports));
|
|
7942
8162
|
const db = await getDb2();
|
|
7943
8163
|
const stmt = db.prepare(`
|
|
@@ -7947,7 +8167,7 @@ async function getFileTrace(filePath, limit = 8) {
|
|
|
7947
8167
|
ORDER BY cl.created_at DESC
|
|
7948
8168
|
LIMIT ?
|
|
7949
8169
|
`);
|
|
7950
|
-
stmt.bind([`%${
|
|
8170
|
+
stmt.bind([`%${path20.basename(filePath)}%`, limit]);
|
|
7951
8171
|
const rows = [];
|
|
7952
8172
|
while (stmt.step()) rows.push(stmt.getAsObject());
|
|
7953
8173
|
stmt.free();
|
|
@@ -7965,7 +8185,7 @@ async function getFileTrace(filePath, limit = 8) {
|
|
|
7965
8185
|
function formatFileTrace(entries, filePath) {
|
|
7966
8186
|
if (entries.length === 0) return "";
|
|
7967
8187
|
const lines = [
|
|
7968
|
-
`\u{1F570}\uFE0F **Why is ${
|
|
8188
|
+
`\u{1F570}\uFE0F **Why is ${path20.basename(filePath)} written this way?** \u2014 ${entries.length} change(s) recorded:`
|
|
7969
8189
|
];
|
|
7970
8190
|
for (const e of entries) {
|
|
7971
8191
|
const date = new Date((e.createdAt || 0) * 1e3).toLocaleDateString("en-US", {
|
|
@@ -7981,12 +8201,12 @@ function formatFileTrace(entries, filePath) {
|
|
|
7981
8201
|
async function getDecisionsForFile(filePath, limit = 3) {
|
|
7982
8202
|
const decisions = [];
|
|
7983
8203
|
const root = getProjectRoot();
|
|
7984
|
-
const base =
|
|
8204
|
+
const base = path20.basename(filePath);
|
|
7985
8205
|
const baseWithoutExt = base.replace(/\.[^.]+$/, "");
|
|
7986
8206
|
try {
|
|
7987
|
-
const decisionsMdPath =
|
|
7988
|
-
if (
|
|
7989
|
-
const content =
|
|
8207
|
+
const decisionsMdPath = path20.join(root, ".kuma", "memories", "decisions.md");
|
|
8208
|
+
if (fs17.existsSync(decisionsMdPath)) {
|
|
8209
|
+
const content = fs17.readFileSync(decisionsMdPath, "utf-8");
|
|
7990
8210
|
const sections = content.split(/^##\s+/m);
|
|
7991
8211
|
for (const section of sections) {
|
|
7992
8212
|
if (!section.trim() || section.startsWith("# ")) continue;
|
|
@@ -8091,13 +8311,13 @@ async function getRelevantContext(filePath, goal) {
|
|
|
8091
8311
|
if (traceStr) parts.push(traceStr);
|
|
8092
8312
|
try {
|
|
8093
8313
|
const root = getProjectRoot();
|
|
8094
|
-
if (
|
|
8314
|
+
if (fs17.existsSync(path20.join(root, ".kuma", "kuma.db"))) {
|
|
8095
8315
|
const { getDb: getDb2 } = await Promise.resolve().then(() => (init_kumaDb(), kumaDb_exports));
|
|
8096
8316
|
const db = await getDb2();
|
|
8097
8317
|
const stmt = db.prepare(
|
|
8098
8318
|
`SELECT COUNT(*) FROM known_gotchas WHERE status = 'resolved' AND file_path LIKE ?`
|
|
8099
8319
|
);
|
|
8100
|
-
stmt.bind([`%${
|
|
8320
|
+
stmt.bind([`%${path20.basename(filePath)}%`]);
|
|
8101
8321
|
const found = stmt.step();
|
|
8102
8322
|
const count = found ? Number(stmt.getAsObject()["COUNT(*)"]) : 0;
|
|
8103
8323
|
stmt.free();
|
|
@@ -8108,7 +8328,7 @@ async function getRelevantContext(filePath, goal) {
|
|
|
8108
8328
|
} catch {
|
|
8109
8329
|
}
|
|
8110
8330
|
if (gotchas.length > 0) {
|
|
8111
|
-
const scopeHint =
|
|
8331
|
+
const scopeHint = path20.basename(path20.dirname(filePath)) || "current change";
|
|
8112
8332
|
parts.push(
|
|
8113
8333
|
`\u2705 AFTER editing, verify: kuma_safety({ action: "verify", scope: "${scopeHint}" })`
|
|
8114
8334
|
);
|
|
@@ -8124,11 +8344,11 @@ async function getRelevantContext(filePath, goal) {
|
|
|
8124
8344
|
async function getFileSummary2(filePath) {
|
|
8125
8345
|
try {
|
|
8126
8346
|
const root = getProjectRoot();
|
|
8127
|
-
const dbFile =
|
|
8128
|
-
if (!
|
|
8347
|
+
const dbFile = path20.join(root, ".kuma", "kuma.db");
|
|
8348
|
+
if (!fs17.existsSync(dbFile)) return null;
|
|
8129
8349
|
const { getDb: getDb2 } = await Promise.resolve().then(() => (init_kumaDb(), kumaDb_exports));
|
|
8130
8350
|
const db = await getDb2();
|
|
8131
|
-
const base =
|
|
8351
|
+
const base = path20.basename(filePath);
|
|
8132
8352
|
const stmt = db.prepare(`
|
|
8133
8353
|
SELECT
|
|
8134
8354
|
(SELECT COUNT(*) FROM known_gotchas WHERE status = 'active' AND (file_path = ? OR file_path LIKE ?)) as active_gotchas,
|
|
@@ -8220,9 +8440,9 @@ async function getCommandContext(command) {
|
|
|
8220
8440
|
}
|
|
8221
8441
|
function loadHookState(root) {
|
|
8222
8442
|
try {
|
|
8223
|
-
const fp =
|
|
8224
|
-
if (
|
|
8225
|
-
return JSON.parse(
|
|
8443
|
+
const fp = path20.join(root, HOOK_STATE_FILE);
|
|
8444
|
+
if (fs17.existsSync(fp)) {
|
|
8445
|
+
return JSON.parse(fs17.readFileSync(fp, "utf-8"));
|
|
8226
8446
|
}
|
|
8227
8447
|
} catch {
|
|
8228
8448
|
}
|
|
@@ -8230,10 +8450,10 @@ function loadHookState(root) {
|
|
|
8230
8450
|
}
|
|
8231
8451
|
function saveHookState(root, state) {
|
|
8232
8452
|
try {
|
|
8233
|
-
const fp =
|
|
8234
|
-
const dir =
|
|
8235
|
-
if (!
|
|
8236
|
-
|
|
8453
|
+
const fp = path20.join(root, HOOK_STATE_FILE);
|
|
8454
|
+
const dir = path20.dirname(fp);
|
|
8455
|
+
if (!fs17.existsSync(dir)) fs17.mkdirSync(dir, { recursive: true });
|
|
8456
|
+
fs17.writeFileSync(fp, JSON.stringify(state), "utf-8");
|
|
8237
8457
|
} catch {
|
|
8238
8458
|
}
|
|
8239
8459
|
}
|
|
@@ -8267,7 +8487,7 @@ async function trackFileEditLoop(filePath) {
|
|
|
8267
8487
|
saveHookState(root, state);
|
|
8268
8488
|
if (recorded) {
|
|
8269
8489
|
try {
|
|
8270
|
-
if (!
|
|
8490
|
+
if (!fs17.existsSync(path20.join(root, ".kuma", "kuma.db"))) return entry.count;
|
|
8271
8491
|
const { addGotcha: addGotcha2 } = await Promise.resolve().then(() => (init_kumaGotchas(), kumaGotchas_exports));
|
|
8272
8492
|
await addGotcha2({
|
|
8273
8493
|
filePath,
|
|
@@ -8321,8 +8541,8 @@ __export(kumaGotchas_exports, {
|
|
|
8321
8541
|
syncGotchasToDb: () => syncGotchasToDb,
|
|
8322
8542
|
tokenizeForSimilarity: () => tokenizeForSimilarity
|
|
8323
8543
|
});
|
|
8324
|
-
import
|
|
8325
|
-
import
|
|
8544
|
+
import fs18 from "fs";
|
|
8545
|
+
import path21 from "path";
|
|
8326
8546
|
async function ensureGotchasSchema() {
|
|
8327
8547
|
const db = await getDb();
|
|
8328
8548
|
db.exec(`
|
|
@@ -8744,8 +8964,8 @@ async function getActiveGotchasForCommand(command) {
|
|
|
8744
8964
|
}
|
|
8745
8965
|
async function recordInjection(params) {
|
|
8746
8966
|
try {
|
|
8747
|
-
const fp =
|
|
8748
|
-
if (!
|
|
8967
|
+
const fp = path21.join(getProjectRoot(), ".kuma", "injections.jsonl");
|
|
8968
|
+
if (!fs18.existsSync(path21.dirname(fp))) fs18.mkdirSync(path21.dirname(fp), { recursive: true });
|
|
8749
8969
|
const line = JSON.stringify({
|
|
8750
8970
|
filePath: params.filePath || null,
|
|
8751
8971
|
command: params.command || null,
|
|
@@ -8754,16 +8974,16 @@ async function recordInjection(params) {
|
|
|
8754
8974
|
// conservative estimate: avoided re-research / re-discovery
|
|
8755
8975
|
at: Date.now()
|
|
8756
8976
|
});
|
|
8757
|
-
|
|
8977
|
+
fs18.appendFileSync(fp, line + "\n", "utf-8");
|
|
8758
8978
|
} catch {
|
|
8759
8979
|
}
|
|
8760
8980
|
}
|
|
8761
8981
|
function getInjectionStats(hours = 24) {
|
|
8762
8982
|
try {
|
|
8763
|
-
const fp =
|
|
8764
|
-
if (!
|
|
8983
|
+
const fp = path21.join(getProjectRoot(), ".kuma", "injections.jsonl");
|
|
8984
|
+
if (!fs18.existsSync(fp)) return { count: 0, savedMs: 0 };
|
|
8765
8985
|
const cutoff = Date.now() - hours * 60 * 60 * 1e3;
|
|
8766
|
-
const lines =
|
|
8986
|
+
const lines = fs18.readFileSync(fp, "utf-8").split("\n");
|
|
8767
8987
|
let count = 0;
|
|
8768
8988
|
let savedMs = 0;
|
|
8769
8989
|
for (const line of lines) {
|
|
@@ -8821,9 +9041,9 @@ async function getGotchasByStatus(status, limit = 20) {
|
|
|
8821
9041
|
}
|
|
8822
9042
|
function syncGotchaStatusToMarkdown(targetPaths, newStatus, reason) {
|
|
8823
9043
|
try {
|
|
8824
|
-
const mdPath =
|
|
8825
|
-
if (!
|
|
8826
|
-
const content =
|
|
9044
|
+
const mdPath = path21.join(getProjectRoot(), ".kuma", "KNOWN_GOTCHAS.md");
|
|
9045
|
+
if (!fs18.existsSync(mdPath)) return false;
|
|
9046
|
+
const content = fs18.readFileSync(mdPath, "utf-8");
|
|
8827
9047
|
const lines = content.split("\n");
|
|
8828
9048
|
const normalizedTargets = targetPaths.map((p) => p.trim().toLowerCase()).filter(Boolean);
|
|
8829
9049
|
if (normalizedTargets.length === 0) return false;
|
|
@@ -8840,9 +9060,9 @@ function syncGotchaStatusToMarkdown(targetPaths, newStatus, reason) {
|
|
|
8840
9060
|
modified = true;
|
|
8841
9061
|
}
|
|
8842
9062
|
const headingFile = headingMatch[1].trim().toLowerCase();
|
|
8843
|
-
const headingBase =
|
|
9063
|
+
const headingBase = path21.basename(headingFile);
|
|
8844
9064
|
inMatchingSection = normalizedTargets.some(
|
|
8845
|
-
(t) => headingFile.includes(t) || t.includes(headingFile) || headingBase === t || headingBase ===
|
|
9065
|
+
(t) => headingFile.includes(t) || t.includes(headingFile) || headingBase === t || headingBase === path21.basename(t)
|
|
8846
9066
|
);
|
|
8847
9067
|
sectionHasStatus = false;
|
|
8848
9068
|
outputLines.push(line);
|
|
@@ -8864,7 +9084,7 @@ function syncGotchaStatusToMarkdown(targetPaths, newStatus, reason) {
|
|
|
8864
9084
|
modified = true;
|
|
8865
9085
|
}
|
|
8866
9086
|
if (modified) {
|
|
8867
|
-
|
|
9087
|
+
fs18.writeFileSync(mdPath, outputLines.join("\n"), "utf-8");
|
|
8868
9088
|
}
|
|
8869
9089
|
return modified;
|
|
8870
9090
|
} catch {
|
|
@@ -9005,24 +9225,24 @@ var kumaMaintenance_exports = {};
|
|
|
9005
9225
|
__export(kumaMaintenance_exports, {
|
|
9006
9226
|
maybeRunAutoCleanup: () => maybeRunAutoCleanup
|
|
9007
9227
|
});
|
|
9008
|
-
import
|
|
9009
|
-
import
|
|
9228
|
+
import fs19 from "fs";
|
|
9229
|
+
import path22 from "path";
|
|
9010
9230
|
async function maybeRunAutoCleanup() {
|
|
9011
9231
|
try {
|
|
9012
9232
|
const root = getProjectRoot();
|
|
9013
|
-
const stateFile =
|
|
9233
|
+
const stateFile = path22.join(root, GC_STATE_FILE);
|
|
9014
9234
|
const now = Date.now();
|
|
9015
9235
|
let lastRun = 0;
|
|
9016
|
-
if (
|
|
9236
|
+
if (fs19.existsSync(stateFile)) {
|
|
9017
9237
|
try {
|
|
9018
|
-
lastRun = JSON.parse(
|
|
9238
|
+
lastRun = JSON.parse(fs19.readFileSync(stateFile, "utf-8")).lastRun || 0;
|
|
9019
9239
|
} catch {
|
|
9020
9240
|
lastRun = 0;
|
|
9021
9241
|
}
|
|
9022
9242
|
}
|
|
9023
9243
|
if (now - lastRun < GC_INTERVAL_MS) return "";
|
|
9024
|
-
|
|
9025
|
-
|
|
9244
|
+
fs19.mkdirSync(path22.dirname(stateFile), { recursive: true });
|
|
9245
|
+
fs19.writeFileSync(stateFile, JSON.stringify({ lastRun: now }), "utf-8");
|
|
9026
9246
|
const { syncGotchasToDb: syncGotchasToDb2 } = await Promise.resolve().then(() => (init_kumaGotchas(), kumaGotchas_exports));
|
|
9027
9247
|
await syncGotchasToDb2();
|
|
9028
9248
|
const { runGarbageCollection: runGarbageCollection2 } = await Promise.resolve().then(() => (init_kumaDb(), kumaDb_exports));
|
|
@@ -9058,22 +9278,22 @@ __export(kumaPathRules_exports, {
|
|
|
9058
9278
|
loadPathRules: () => loadPathRules,
|
|
9059
9279
|
matchRulePath: () => matchRulePath
|
|
9060
9280
|
});
|
|
9061
|
-
import
|
|
9062
|
-
import
|
|
9281
|
+
import fs20 from "fs";
|
|
9282
|
+
import path23 from "path";
|
|
9063
9283
|
function rulesDir() {
|
|
9064
|
-
return
|
|
9284
|
+
return path23.join(getProjectRoot(), RULES_DIR);
|
|
9065
9285
|
}
|
|
9066
9286
|
function ensureRulesDir() {
|
|
9067
9287
|
try {
|
|
9068
9288
|
const dir = rulesDir();
|
|
9069
|
-
if (!
|
|
9289
|
+
if (!fs20.existsSync(dir)) fs20.mkdirSync(dir, { recursive: true });
|
|
9070
9290
|
} catch {
|
|
9071
9291
|
}
|
|
9072
9292
|
}
|
|
9073
9293
|
function parseRuleFile(filePath) {
|
|
9074
9294
|
try {
|
|
9075
|
-
const raw =
|
|
9076
|
-
const id =
|
|
9295
|
+
const raw = fs20.readFileSync(filePath, "utf-8");
|
|
9296
|
+
const id = path23.basename(filePath, ".md");
|
|
9077
9297
|
const fm = raw.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/);
|
|
9078
9298
|
if (!fm) {
|
|
9079
9299
|
return { id, description: id, paths: ["*"], content: raw.trim(), filePath };
|
|
@@ -9098,7 +9318,7 @@ function loadPathRules() {
|
|
|
9098
9318
|
ensureRulesDir();
|
|
9099
9319
|
try {
|
|
9100
9320
|
const dir = rulesDir();
|
|
9101
|
-
return
|
|
9321
|
+
return fs20.readdirSync(dir).filter((f) => f.endsWith(".md")).map((f) => parseRuleFile(path23.join(dir, f))).filter((r) => r !== null);
|
|
9102
9322
|
} catch {
|
|
9103
9323
|
return [];
|
|
9104
9324
|
}
|
|
@@ -9186,8 +9406,8 @@ __export(kumaFlowCache_exports, {
|
|
|
9186
9406
|
getFreshDomainFlow: () => getFreshDomainFlow,
|
|
9187
9407
|
getHopsForDomain: () => getHopsForDomain
|
|
9188
9408
|
});
|
|
9189
|
-
import
|
|
9190
|
-
import
|
|
9409
|
+
import fs21 from "fs";
|
|
9410
|
+
import path24 from "path";
|
|
9191
9411
|
async function getFlowFreshness(domain) {
|
|
9192
9412
|
try {
|
|
9193
9413
|
const { getDb: getDb2 } = await Promise.resolve().then(() => (init_kumaDb(), kumaDb_exports));
|
|
@@ -9222,26 +9442,26 @@ async function getFlowFreshness(domain) {
|
|
|
9222
9442
|
}
|
|
9223
9443
|
function resolveImport(fromFile, spec) {
|
|
9224
9444
|
const root = getProjectRoot();
|
|
9225
|
-
const fromDir =
|
|
9445
|
+
const fromDir = path24.dirname(fromFile);
|
|
9226
9446
|
const candidates = [];
|
|
9227
9447
|
if (spec.startsWith(".")) {
|
|
9228
|
-
const abs =
|
|
9448
|
+
const abs = path24.resolve(fromDir, spec);
|
|
9229
9449
|
candidates.push(abs);
|
|
9230
9450
|
} else {
|
|
9231
|
-
candidates.push(
|
|
9451
|
+
candidates.push(path24.join(root, spec));
|
|
9232
9452
|
}
|
|
9233
9453
|
for (const c of candidates) {
|
|
9234
9454
|
for (const ext of SOURCE_EXTENSIONS) {
|
|
9235
9455
|
const withExt = `${c}${ext}`;
|
|
9236
|
-
if (
|
|
9237
|
-
if (
|
|
9238
|
-
const idx =
|
|
9239
|
-
if (
|
|
9456
|
+
if (fs21.existsSync(withExt)) return path24.relative(root, withExt);
|
|
9457
|
+
if (fs21.existsSync(c) && fs21.statSync(c).isDirectory()) {
|
|
9458
|
+
const idx = path24.join(c, "index") + ext;
|
|
9459
|
+
if (fs21.existsSync(idx)) return path24.relative(root, idx);
|
|
9240
9460
|
}
|
|
9241
9461
|
}
|
|
9242
|
-
if (
|
|
9462
|
+
if (fs21.existsSync(c)) {
|
|
9243
9463
|
try {
|
|
9244
|
-
if (
|
|
9464
|
+
if (fs21.statSync(c).isFile()) return path24.relative(root, c);
|
|
9245
9465
|
} catch {
|
|
9246
9466
|
}
|
|
9247
9467
|
}
|
|
@@ -9250,13 +9470,13 @@ function resolveImport(fromFile, spec) {
|
|
|
9250
9470
|
}
|
|
9251
9471
|
function deriveHopsFromImports(entryFile, maxHops = 6) {
|
|
9252
9472
|
const root = getProjectRoot();
|
|
9253
|
-
const absEntry =
|
|
9254
|
-
if (!
|
|
9473
|
+
const absEntry = path24.isAbsolute(entryFile) ? entryFile : path24.resolve(root, entryFile);
|
|
9474
|
+
if (!fs21.existsSync(absEntry)) return [];
|
|
9255
9475
|
const hops = [];
|
|
9256
9476
|
const seen = /* @__PURE__ */ new Set([entryFile]);
|
|
9257
|
-
const fromName =
|
|
9477
|
+
const fromName = path24.basename(absEntry);
|
|
9258
9478
|
try {
|
|
9259
|
-
const lines =
|
|
9479
|
+
const lines = fs21.readFileSync(absEntry, "utf-8").split("\n");
|
|
9260
9480
|
for (const line of lines) {
|
|
9261
9481
|
if (hops.length >= maxHops) break;
|
|
9262
9482
|
const spec = matchImportPath(line);
|
|
@@ -9266,9 +9486,9 @@ function deriveHopsFromImports(entryFile, maxHops = 6) {
|
|
|
9266
9486
|
seen.add(resolved);
|
|
9267
9487
|
hops.push({
|
|
9268
9488
|
from: fromName,
|
|
9269
|
-
to:
|
|
9489
|
+
to: path24.basename(resolved),
|
|
9270
9490
|
relation: "imports",
|
|
9271
|
-
description: `${fromName} imports ${
|
|
9491
|
+
description: `${fromName} imports ${path24.basename(resolved)}`
|
|
9272
9492
|
});
|
|
9273
9493
|
}
|
|
9274
9494
|
} catch {
|
|
@@ -9331,9 +9551,9 @@ async function getHopsForDomain(domain) {
|
|
|
9331
9551
|
}
|
|
9332
9552
|
try {
|
|
9333
9553
|
const root = getProjectRoot();
|
|
9334
|
-
const archPath =
|
|
9335
|
-
if (
|
|
9336
|
-
const content =
|
|
9554
|
+
const archPath = path24.join(root, ".kuma", "ARCHITECTURE_FLOW.md");
|
|
9555
|
+
if (fs21.existsSync(archPath)) {
|
|
9556
|
+
const content = fs21.readFileSync(archPath, "utf-8");
|
|
9337
9557
|
const lines = content.split("\n");
|
|
9338
9558
|
for (const line of lines) {
|
|
9339
9559
|
const domMatch = line.match(new RegExp(`domain:\\s*${escapeRegex(domain)}\\s*\\|\\s*hops:\\s*(.+)`, "i"));
|
|
@@ -9378,7 +9598,7 @@ Record one with kuma_memory({ action: 'arch_flow', content: 'domain: ${domain} |
|
|
|
9378
9598
|
hops: derivedHops,
|
|
9379
9599
|
filePaths: freshness.filePaths
|
|
9380
9600
|
});
|
|
9381
|
-
lines.push(`\u2705 Re-derived ${derivedHops.length} hop(s) from ${
|
|
9601
|
+
lines.push(`\u2705 Re-derived ${derivedHops.length} hop(s) from ${path24.basename(entry)} \u2014 cache refreshed.`);
|
|
9382
9602
|
hops.splice(0, hops.length, ...derivedHops);
|
|
9383
9603
|
} else {
|
|
9384
9604
|
lines.push("\u26A0\uFE0F No imports to follow \u2014 cache left as-is (record hops manually if needed).");
|
|
@@ -9431,10 +9651,10 @@ __export(packageBriefs_exports, {
|
|
|
9431
9651
|
readBrief: () => readBrief,
|
|
9432
9652
|
refreshPackageBriefs: () => refreshPackageBriefs
|
|
9433
9653
|
});
|
|
9434
|
-
import
|
|
9435
|
-
import
|
|
9654
|
+
import fs22 from "fs";
|
|
9655
|
+
import path25 from "path";
|
|
9436
9656
|
function briefsDir(root) {
|
|
9437
|
-
return
|
|
9657
|
+
return path25.join(root || getProjectRoot(), BRIEFS_DIR);
|
|
9438
9658
|
}
|
|
9439
9659
|
function slug(name) {
|
|
9440
9660
|
return name.replace(/[^a-zA-Z0-9_-]/g, "_").slice(0, 60) || "root";
|
|
@@ -9498,13 +9718,13 @@ async function refreshPackageBriefs() {
|
|
|
9498
9718
|
const dir = briefsDir(root);
|
|
9499
9719
|
try {
|
|
9500
9720
|
const ws = await getWorkspaceInfo(root);
|
|
9501
|
-
if (!
|
|
9721
|
+
if (!fs22.existsSync(dir)) fs22.mkdirSync(dir, { recursive: true });
|
|
9502
9722
|
let count = 0;
|
|
9503
9723
|
const pkgs = ws.isWorkspace ? ws.packages : [{ name: "root", path: ".", isRoot: true }];
|
|
9504
9724
|
for (const p of pkgs.slice(0, 20)) {
|
|
9505
9725
|
const pkg = p;
|
|
9506
9726
|
const content = await buildPackageBrief(pkg.name, pkg.path, root);
|
|
9507
|
-
|
|
9727
|
+
fs22.writeFileSync(path25.join(dir, `${slug(pkg.name)}.md`), content, "utf-8");
|
|
9508
9728
|
count++;
|
|
9509
9729
|
}
|
|
9510
9730
|
return { count, dir };
|
|
@@ -9514,9 +9734,9 @@ async function refreshPackageBriefs() {
|
|
|
9514
9734
|
}
|
|
9515
9735
|
function briefFreshness(pkgName) {
|
|
9516
9736
|
try {
|
|
9517
|
-
const fp =
|
|
9518
|
-
if (!
|
|
9519
|
-
const ageMs = Date.now() -
|
|
9737
|
+
const fp = path25.join(briefsDir(), `${slug(pkgName)}.md`);
|
|
9738
|
+
if (!fs22.existsSync(fp)) return { exists: false, fresh: false, age: "missing" };
|
|
9739
|
+
const ageMs = Date.now() - fs22.statSync(fp).mtimeMs;
|
|
9520
9740
|
return { exists: true, fresh: !isStale(Date.now() - ageMs, MAP_TTL_MS), age: formatAge(Date.now() - ageMs) };
|
|
9521
9741
|
} catch {
|
|
9522
9742
|
return { exists: false, fresh: false, age: "missing" };
|
|
@@ -9524,9 +9744,9 @@ function briefFreshness(pkgName) {
|
|
|
9524
9744
|
}
|
|
9525
9745
|
function readBrief(pkgName, maxChars = 1200) {
|
|
9526
9746
|
try {
|
|
9527
|
-
const fp =
|
|
9528
|
-
if (!
|
|
9529
|
-
const content =
|
|
9747
|
+
const fp = path25.join(briefsDir(), `${slug(pkgName)}.md`);
|
|
9748
|
+
if (!fs22.existsSync(fp)) return null;
|
|
9749
|
+
const content = fs22.readFileSync(fp, "utf-8");
|
|
9530
9750
|
return content.length > maxChars ? content.slice(0, maxChars) + "\n\u2026(truncated)" : content;
|
|
9531
9751
|
} catch {
|
|
9532
9752
|
return null;
|
|
@@ -9555,8 +9775,8 @@ __export(kumaSearch_exports, {
|
|
|
9555
9775
|
formatHybridResults: () => formatHybridResults,
|
|
9556
9776
|
hybridSearch: () => hybridSearch
|
|
9557
9777
|
});
|
|
9558
|
-
import
|
|
9559
|
-
import
|
|
9778
|
+
import fs24 from "fs";
|
|
9779
|
+
import path27 from "path";
|
|
9560
9780
|
function expandQueryTerms(query) {
|
|
9561
9781
|
const terms = query.toLowerCase().split(/[\s_-]+/).filter((t) => t.length > 2);
|
|
9562
9782
|
const expanded = /* @__PURE__ */ new Map();
|
|
@@ -9619,13 +9839,13 @@ async function buildSearchVectors() {
|
|
|
9619
9839
|
}
|
|
9620
9840
|
try {
|
|
9621
9841
|
const root = getProjectRoot();
|
|
9622
|
-
const memDir =
|
|
9623
|
-
if (
|
|
9624
|
-
const files =
|
|
9842
|
+
const memDir = path27.join(root, ".kuma", "memories");
|
|
9843
|
+
if (fs24.existsSync(memDir)) {
|
|
9844
|
+
const files = fs24.readdirSync(memDir).filter((f) => f.endsWith(".md")).slice(0, SCALE_LIMITS.maxMemoryFiles);
|
|
9625
9845
|
for (const file of files) {
|
|
9626
9846
|
try {
|
|
9627
|
-
const fullPath =
|
|
9628
|
-
const content =
|
|
9847
|
+
const fullPath = path27.join(memDir, file);
|
|
9848
|
+
const content = fs24.readFileSync(fullPath, "utf-8");
|
|
9629
9849
|
const text = content.toLowerCase();
|
|
9630
9850
|
const rawTerms = extractTerms(text);
|
|
9631
9851
|
const termCounts = /* @__PURE__ */ new Map();
|
|
@@ -9636,7 +9856,7 @@ async function buildSearchVectors() {
|
|
|
9636
9856
|
terms: termCounts,
|
|
9637
9857
|
source: file.replace(/\.md$/, ""),
|
|
9638
9858
|
sourceType: "memory",
|
|
9639
|
-
recency: recencyScore(Math.floor(
|
|
9859
|
+
recency: recencyScore(Math.floor(fs24.statSync(fullPath).mtimeMs / 1e3))
|
|
9640
9860
|
});
|
|
9641
9861
|
} catch {
|
|
9642
9862
|
}
|
|
@@ -9953,14 +10173,14 @@ __export(architectureGuard_exports, {
|
|
|
9953
10173
|
detectWorkspaceCircularDeps: () => detectWorkspaceCircularDeps,
|
|
9954
10174
|
loadArchitectureRules: () => loadArchitectureRules
|
|
9955
10175
|
});
|
|
9956
|
-
import
|
|
9957
|
-
import
|
|
9958
|
-
import
|
|
10176
|
+
import fs28 from "fs";
|
|
10177
|
+
import path31 from "path";
|
|
10178
|
+
import fastGlob5 from "fast-glob";
|
|
9959
10179
|
function loadArchitectureRules(root) {
|
|
9960
|
-
const rulesPath =
|
|
9961
|
-
if (
|
|
10180
|
+
const rulesPath = path31.join(root, ".kuma", "architecture.json");
|
|
10181
|
+
if (fs28.existsSync(rulesPath)) {
|
|
9962
10182
|
try {
|
|
9963
|
-
const data = JSON.parse(
|
|
10183
|
+
const data = JSON.parse(fs28.readFileSync(rulesPath, "utf-8"));
|
|
9964
10184
|
if (Array.isArray(data.rules)) {
|
|
9965
10185
|
return data.rules;
|
|
9966
10186
|
}
|
|
@@ -10013,7 +10233,7 @@ async function checkArchitectureBoundaries(filesToCheck, customRoot) {
|
|
|
10013
10233
|
}
|
|
10014
10234
|
let targetFiles = filesToCheck;
|
|
10015
10235
|
if (!targetFiles || targetFiles.length === 0) {
|
|
10016
|
-
targetFiles = await
|
|
10236
|
+
targetFiles = await fastGlob5(["**/*.{ts,tsx,js,jsx,mjs,cjs}"], {
|
|
10017
10237
|
cwd: root,
|
|
10018
10238
|
ignore: ["**/node_modules/**", "**/dist/**", "**/build/**", "**/.git/**", "**/.kuma/**"],
|
|
10019
10239
|
onlyFiles: true
|
|
@@ -10022,11 +10242,11 @@ async function checkArchitectureBoundaries(filesToCheck, customRoot) {
|
|
|
10022
10242
|
const customRules = loadArchitectureRules(root);
|
|
10023
10243
|
const importRegex = /(?:import|export\s+.*from|require\s*\()\s*['"]([^'"]+)['"]/g;
|
|
10024
10244
|
for (const file of targetFiles) {
|
|
10025
|
-
const fullPath =
|
|
10026
|
-
if (!
|
|
10245
|
+
const fullPath = path31.isAbsolute(file) ? file : path31.join(root, file);
|
|
10246
|
+
if (!fs28.existsSync(fullPath)) continue;
|
|
10027
10247
|
let content = "";
|
|
10028
10248
|
try {
|
|
10029
|
-
content =
|
|
10249
|
+
content = fs28.readFileSync(fullPath, "utf-8");
|
|
10030
10250
|
} catch {
|
|
10031
10251
|
continue;
|
|
10032
10252
|
}
|
|
@@ -10036,7 +10256,7 @@ async function checkArchitectureBoundaries(filesToCheck, customRoot) {
|
|
|
10036
10256
|
const importPath = match[1];
|
|
10037
10257
|
if (wsInfo.isWorkspace && currentPkg && !currentPkg.isRoot) {
|
|
10038
10258
|
if (importPath.startsWith("../") && (importPath.includes("/src/") || importPath.includes("/dist/"))) {
|
|
10039
|
-
const resolvedTarget =
|
|
10259
|
+
const resolvedTarget = path31.normalize(path31.resolve(path31.dirname(fullPath), importPath));
|
|
10040
10260
|
const targetPkg = findPackageForFile(resolvedTarget, wsInfo);
|
|
10041
10261
|
if (targetPkg && targetPkg.name !== currentPkg.name) {
|
|
10042
10262
|
violations.push({
|
|
@@ -10085,26 +10305,26 @@ __export(docDrift_exports, {
|
|
|
10085
10305
|
formatDocDrift: () => formatDocDrift,
|
|
10086
10306
|
scanDocDrift: () => scanDocDrift
|
|
10087
10307
|
});
|
|
10088
|
-
import
|
|
10089
|
-
import
|
|
10308
|
+
import fs29 from "fs";
|
|
10309
|
+
import path32 from "path";
|
|
10090
10310
|
import { execSync as execSync9 } from "child_process";
|
|
10091
10311
|
function collectDocFiles(root) {
|
|
10092
10312
|
const cwd = root || getProjectRoot();
|
|
10093
10313
|
const out = [];
|
|
10094
10314
|
const pushIfMd = (dir, rel) => {
|
|
10095
10315
|
try {
|
|
10096
|
-
for (const f of
|
|
10316
|
+
for (const f of fs29.readdirSync(dir)) {
|
|
10097
10317
|
if (out.length >= MAX_DOCS) return;
|
|
10098
|
-
const full =
|
|
10318
|
+
const full = path32.join(dir, f);
|
|
10099
10319
|
try {
|
|
10100
|
-
if (
|
|
10320
|
+
if (fs29.statSync(full).isFile() && /\.md$/i.test(f)) out.push(rel(f));
|
|
10101
10321
|
} catch {
|
|
10102
10322
|
}
|
|
10103
10323
|
}
|
|
10104
10324
|
} catch {
|
|
10105
10325
|
}
|
|
10106
10326
|
};
|
|
10107
|
-
pushIfMd(
|
|
10327
|
+
pushIfMd(path32.join(cwd, "docs"), (f) => path32.join("docs", f));
|
|
10108
10328
|
pushIfMd(cwd, (f) => f);
|
|
10109
10329
|
return out;
|
|
10110
10330
|
}
|
|
@@ -10166,7 +10386,7 @@ function scanDocDrift(root) {
|
|
|
10166
10386
|
let claims = [];
|
|
10167
10387
|
for (const rel of collectDocFiles(cwd)) {
|
|
10168
10388
|
try {
|
|
10169
|
-
const content =
|
|
10389
|
+
const content = fs29.readFileSync(path32.join(cwd, rel), "utf-8");
|
|
10170
10390
|
if (isExemptDoc(rel, content)) {
|
|
10171
10391
|
skipped.push(rel);
|
|
10172
10392
|
continue;
|
|
@@ -10337,16 +10557,16 @@ __export(kumaCheckpoint_exports, {
|
|
|
10337
10557
|
pruneCheckpoints: () => pruneCheckpoints,
|
|
10338
10558
|
rollbackToCheckpoint: () => rollbackToCheckpoint
|
|
10339
10559
|
});
|
|
10340
|
-
import
|
|
10341
|
-
import
|
|
10560
|
+
import fs30 from "fs";
|
|
10561
|
+
import path33 from "path";
|
|
10342
10562
|
async function createCheckpoint(label, description) {
|
|
10343
10563
|
try {
|
|
10344
10564
|
const root = getProjectRoot();
|
|
10345
|
-
const cpDir =
|
|
10346
|
-
if (
|
|
10565
|
+
const cpDir = path33.join(root, CHECKPOINT_DIR, sanitizeLabel(label));
|
|
10566
|
+
if (fs30.existsSync(cpDir)) {
|
|
10347
10567
|
return `\u26A0\uFE0F Checkpoint "${label}" already exists. Use a different label or remove it first.`;
|
|
10348
10568
|
}
|
|
10349
|
-
|
|
10569
|
+
fs30.mkdirSync(cpDir, { recursive: true });
|
|
10350
10570
|
let gitHead;
|
|
10351
10571
|
let isGitClean = false;
|
|
10352
10572
|
try {
|
|
@@ -10412,15 +10632,15 @@ async function createCheckpoint(label, description) {
|
|
|
10412
10632
|
}
|
|
10413
10633
|
const files = [];
|
|
10414
10634
|
for (const fp of candidatePaths) {
|
|
10415
|
-
const fullPath =
|
|
10635
|
+
const fullPath = path33.resolve(root, fp);
|
|
10416
10636
|
try {
|
|
10417
|
-
if (
|
|
10418
|
-
const content =
|
|
10637
|
+
if (fs30.existsSync(fullPath) && fs30.statSync(fullPath).isFile()) {
|
|
10638
|
+
const content = fs30.readFileSync(fullPath, "utf-8");
|
|
10419
10639
|
const hash = simpleHash2(content);
|
|
10420
|
-
const snapFile =
|
|
10421
|
-
const fileDir =
|
|
10422
|
-
if (!
|
|
10423
|
-
|
|
10640
|
+
const snapFile = path33.join(cpDir, "files", `${fp}.kuma-snap`);
|
|
10641
|
+
const fileDir = path33.dirname(snapFile);
|
|
10642
|
+
if (!fs30.existsSync(fileDir)) fs30.mkdirSync(fileDir, { recursive: true });
|
|
10643
|
+
fs30.writeFileSync(snapFile, content, "utf-8");
|
|
10424
10644
|
files.push({ path: fp, hash });
|
|
10425
10645
|
}
|
|
10426
10646
|
} catch {
|
|
@@ -10428,7 +10648,7 @@ async function createCheckpoint(label, description) {
|
|
|
10428
10648
|
}
|
|
10429
10649
|
const db = await getDb();
|
|
10430
10650
|
const dbData = db.export();
|
|
10431
|
-
|
|
10651
|
+
fs30.writeFileSync(path33.join(cpDir, "kuma.db"), Buffer.from(dbData));
|
|
10432
10652
|
const manifest = {
|
|
10433
10653
|
label,
|
|
10434
10654
|
timestamp: Date.now(),
|
|
@@ -10438,8 +10658,8 @@ async function createCheckpoint(label, description) {
|
|
|
10438
10658
|
dbSnapshot: true,
|
|
10439
10659
|
description
|
|
10440
10660
|
};
|
|
10441
|
-
|
|
10442
|
-
|
|
10661
|
+
fs30.writeFileSync(
|
|
10662
|
+
path33.join(cpDir, "manifest.json"),
|
|
10443
10663
|
JSON.stringify(manifest, null, 2),
|
|
10444
10664
|
"utf-8"
|
|
10445
10665
|
);
|
|
@@ -10467,29 +10687,29 @@ async function createCheckpoint(label, description) {
|
|
|
10467
10687
|
async function rollbackToCheckpoint(label) {
|
|
10468
10688
|
try {
|
|
10469
10689
|
const root = getProjectRoot();
|
|
10470
|
-
const cpDir =
|
|
10471
|
-
const manifestPath =
|
|
10472
|
-
if (!
|
|
10690
|
+
const cpDir = path33.join(root, CHECKPOINT_DIR, sanitizeLabel(label));
|
|
10691
|
+
const manifestPath = path33.join(cpDir, "manifest.json");
|
|
10692
|
+
if (!fs30.existsSync(manifestPath)) {
|
|
10473
10693
|
return `\u274C Checkpoint "${label}" not found. Available checkpoints:
|
|
10474
10694
|
|
|
10475
10695
|
${listCheckpoints()}`;
|
|
10476
10696
|
}
|
|
10477
10697
|
const manifest = JSON.parse(
|
|
10478
|
-
|
|
10698
|
+
fs30.readFileSync(manifestPath, "utf-8")
|
|
10479
10699
|
);
|
|
10480
10700
|
let restored = 0;
|
|
10481
10701
|
let failed = 0;
|
|
10482
10702
|
for (const f of manifest.files) {
|
|
10483
|
-
const snapPath =
|
|
10484
|
-
const legacyPath =
|
|
10485
|
-
const sourcePath =
|
|
10486
|
-
if (
|
|
10703
|
+
const snapPath = path33.join(cpDir, "files", `${f.path}.kuma-snap`);
|
|
10704
|
+
const legacyPath = path33.join(cpDir, "files", f.path);
|
|
10705
|
+
const sourcePath = fs30.existsSync(snapPath) ? snapPath : legacyPath;
|
|
10706
|
+
if (fs30.existsSync(sourcePath)) {
|
|
10487
10707
|
try {
|
|
10488
|
-
const content =
|
|
10489
|
-
const targetPath =
|
|
10490
|
-
const targetDir =
|
|
10491
|
-
if (!
|
|
10492
|
-
|
|
10708
|
+
const content = fs30.readFileSync(sourcePath, "utf-8");
|
|
10709
|
+
const targetPath = path33.resolve(root, f.path);
|
|
10710
|
+
const targetDir = path33.dirname(targetPath);
|
|
10711
|
+
if (!fs30.existsSync(targetDir)) fs30.mkdirSync(targetDir, { recursive: true });
|
|
10712
|
+
fs30.writeFileSync(targetPath, content, "utf-8");
|
|
10493
10713
|
restored++;
|
|
10494
10714
|
} catch {
|
|
10495
10715
|
failed++;
|
|
@@ -10510,12 +10730,12 @@ ${listCheckpoints()}`;
|
|
|
10510
10730
|
failed++;
|
|
10511
10731
|
}
|
|
10512
10732
|
}
|
|
10513
|
-
const dbSnapshotPath =
|
|
10514
|
-
if (
|
|
10515
|
-
const kumaDir =
|
|
10516
|
-
const dbPath =
|
|
10517
|
-
const snapshotData =
|
|
10518
|
-
|
|
10733
|
+
const dbSnapshotPath = path33.join(cpDir, "kuma.db");
|
|
10734
|
+
if (fs30.existsSync(dbSnapshotPath)) {
|
|
10735
|
+
const kumaDir = path33.join(root, ".kuma");
|
|
10736
|
+
const dbPath = path33.join(kumaDir, "kuma.db");
|
|
10737
|
+
const snapshotData = fs30.readFileSync(dbSnapshotPath);
|
|
10738
|
+
fs30.writeFileSync(dbPath, snapshotData);
|
|
10519
10739
|
resetDbInstance();
|
|
10520
10740
|
}
|
|
10521
10741
|
sessionMemory.recordToolCall("kuma_checkpoint_rollback", {
|
|
@@ -10540,18 +10760,18 @@ ${listCheckpoints()}`;
|
|
|
10540
10760
|
function listCheckpoints() {
|
|
10541
10761
|
try {
|
|
10542
10762
|
const root = getProjectRoot();
|
|
10543
|
-
const cpDir =
|
|
10544
|
-
if (!
|
|
10763
|
+
const cpDir = path33.join(root, CHECKPOINT_DIR);
|
|
10764
|
+
if (!fs30.existsSync(cpDir)) {
|
|
10545
10765
|
return "\u{1F4ED} No checkpoints found. Use kuma_safety({ action: 'checkpoint', label: 'pre-feature-x' }) to create one.";
|
|
10546
10766
|
}
|
|
10547
|
-
const entries =
|
|
10767
|
+
const entries = fs30.readdirSync(cpDir);
|
|
10548
10768
|
const checkpoints = [];
|
|
10549
10769
|
for (const entry of entries) {
|
|
10550
|
-
const manifestPath =
|
|
10551
|
-
if (
|
|
10770
|
+
const manifestPath = path33.join(cpDir, entry, "manifest.json");
|
|
10771
|
+
if (fs30.existsSync(manifestPath)) {
|
|
10552
10772
|
try {
|
|
10553
10773
|
const manifest = JSON.parse(
|
|
10554
|
-
|
|
10774
|
+
fs30.readFileSync(manifestPath, "utf-8")
|
|
10555
10775
|
);
|
|
10556
10776
|
checkpoints.push({ label: entry, manifest });
|
|
10557
10777
|
} catch {
|
|
@@ -10583,12 +10803,12 @@ function listCheckpoints() {
|
|
|
10583
10803
|
function pruneCheckpoints(keep = 5) {
|
|
10584
10804
|
try {
|
|
10585
10805
|
const root = getProjectRoot();
|
|
10586
|
-
const cpDir =
|
|
10587
|
-
if (!
|
|
10588
|
-
const entries =
|
|
10806
|
+
const cpDir = path33.join(root, CHECKPOINT_DIR);
|
|
10807
|
+
if (!fs30.existsSync(cpDir)) return "\u{1F4ED} No checkpoints to prune.";
|
|
10808
|
+
const entries = fs30.readdirSync(cpDir).map((e) => ({ name: e, time: fs30.statSync(path33.join(cpDir, e)).mtimeMs })).sort((a, b) => b.time - a.time);
|
|
10589
10809
|
let removed = 0;
|
|
10590
10810
|
for (let i = keep; i < entries.length; i++) {
|
|
10591
|
-
|
|
10811
|
+
fs30.rmSync(path33.join(cpDir, entries[i].name), { recursive: true, force: true });
|
|
10592
10812
|
removed++;
|
|
10593
10813
|
}
|
|
10594
10814
|
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 +10833,9 @@ function isRiskyEditPath(filePath) {
|
|
|
10613
10833
|
}
|
|
10614
10834
|
function loadAutoCpDone(root) {
|
|
10615
10835
|
try {
|
|
10616
|
-
const fp =
|
|
10617
|
-
if (
|
|
10618
|
-
const parsed = JSON.parse(
|
|
10836
|
+
const fp = path33.join(root, AUTO_CP_STATE);
|
|
10837
|
+
if (fs30.existsSync(fp)) {
|
|
10838
|
+
const parsed = JSON.parse(fs30.readFileSync(fp, "utf-8"));
|
|
10619
10839
|
return parsed?.autoCheckpoints ?? {};
|
|
10620
10840
|
}
|
|
10621
10841
|
} catch {
|
|
@@ -10624,10 +10844,10 @@ function loadAutoCpDone(root) {
|
|
|
10624
10844
|
}
|
|
10625
10845
|
function saveAutoCpDone(root, done) {
|
|
10626
10846
|
try {
|
|
10627
|
-
const fp =
|
|
10628
|
-
const parsed =
|
|
10847
|
+
const fp = path33.join(root, AUTO_CP_STATE);
|
|
10848
|
+
const parsed = fs30.existsSync(fp) ? JSON.parse(fs30.readFileSync(fp, "utf-8")) : {};
|
|
10629
10849
|
parsed.autoCheckpoints = done;
|
|
10630
|
-
|
|
10850
|
+
fs30.writeFileSync(fp, JSON.stringify(parsed), "utf-8");
|
|
10631
10851
|
} catch {
|
|
10632
10852
|
}
|
|
10633
10853
|
}
|
|
@@ -10637,14 +10857,14 @@ function maybeAutoCheckpoint(filePath) {
|
|
|
10637
10857
|
const root = getProjectRoot();
|
|
10638
10858
|
const done = loadAutoCpDone(root);
|
|
10639
10859
|
if (done[filePath]) return null;
|
|
10640
|
-
const abs =
|
|
10641
|
-
if (!
|
|
10642
|
-
const label = `auto-pre-${sanitizeLabel(
|
|
10643
|
-
const cpDir =
|
|
10644
|
-
if (!
|
|
10645
|
-
|
|
10646
|
-
|
|
10647
|
-
|
|
10860
|
+
const abs = path33.isAbsolute(filePath) ? filePath : path33.join(root, filePath);
|
|
10861
|
+
if (!fs30.existsSync(abs) || !fs30.statSync(abs).isFile()) return null;
|
|
10862
|
+
const label = `auto-pre-${sanitizeLabel(path33.basename(filePath))}`;
|
|
10863
|
+
const cpDir = path33.join(root, CHECKPOINT_DIR, label);
|
|
10864
|
+
if (!fs30.existsSync(cpDir)) fs30.mkdirSync(cpDir, { recursive: true });
|
|
10865
|
+
fs30.copyFileSync(abs, path33.join(cpDir, path33.basename(abs)));
|
|
10866
|
+
fs30.writeFileSync(
|
|
10867
|
+
path33.join(cpDir, "manifest.json"),
|
|
10648
10868
|
JSON.stringify({
|
|
10649
10869
|
label,
|
|
10650
10870
|
timestamp: Date.now(),
|
|
@@ -10684,8 +10904,8 @@ __export(init_exports, {
|
|
|
10684
10904
|
generateInitMdContent: () => generateInitMdContent,
|
|
10685
10905
|
runInit: () => runInit
|
|
10686
10906
|
});
|
|
10687
|
-
import
|
|
10688
|
-
import
|
|
10907
|
+
import fs31 from "fs";
|
|
10908
|
+
import path34 from "path";
|
|
10689
10909
|
function configFilePath(type) {
|
|
10690
10910
|
switch (type) {
|
|
10691
10911
|
case "claude":
|
|
@@ -11319,21 +11539,21 @@ function handleOpencodeSecondary(root, results) {
|
|
|
11319
11539
|
"",
|
|
11320
11540
|
"\u{1F4D6} Full rules: `.kuma/init.md`"
|
|
11321
11541
|
].join("\n");
|
|
11322
|
-
const skillPath =
|
|
11542
|
+
const skillPath = path34.resolve(root, ".agents", "skills", "kuma", "SKILL.md");
|
|
11323
11543
|
if (!results.some((r) => r.filePath === ".agents/skills/kuma/SKILL.md")) {
|
|
11324
11544
|
try {
|
|
11325
|
-
const dir =
|
|
11326
|
-
if (
|
|
11327
|
-
const existing =
|
|
11545
|
+
const dir = path34.dirname(skillPath);
|
|
11546
|
+
if (fs31.existsSync(skillPath)) {
|
|
11547
|
+
const existing = fs31.readFileSync(skillPath, "utf-8");
|
|
11328
11548
|
if (existing.includes("kuma-mcp")) {
|
|
11329
11549
|
results.push({ type: "opencode", filePath: ".agents/skills/kuma/SKILL.md", action: "skipped" });
|
|
11330
11550
|
} else {
|
|
11331
|
-
|
|
11551
|
+
fs31.writeFileSync(skillPath, existing.trimEnd() + "\n\n---\n\n" + opencodeContent, "utf-8");
|
|
11332
11552
|
results.push({ type: "opencode", filePath: ".agents/skills/kuma/SKILL.md", action: "appended" });
|
|
11333
11553
|
}
|
|
11334
11554
|
} else {
|
|
11335
|
-
if (!
|
|
11336
|
-
|
|
11555
|
+
if (!fs31.existsSync(dir)) fs31.mkdirSync(dir, { recursive: true });
|
|
11556
|
+
fs31.writeFileSync(skillPath, opencodeContent, "utf-8");
|
|
11337
11557
|
results.push({ type: "opencode", filePath: ".agents/skills/kuma/SKILL.md", action: "created" });
|
|
11338
11558
|
}
|
|
11339
11559
|
} catch (err) {
|
|
@@ -11345,21 +11565,21 @@ function handleOpencodeSecondary(root, results) {
|
|
|
11345
11565
|
});
|
|
11346
11566
|
}
|
|
11347
11567
|
}
|
|
11348
|
-
const opencodeSkillPath =
|
|
11568
|
+
const opencodeSkillPath = path34.resolve(root, ".opencode", "skills", "kuma", "SKILL.md");
|
|
11349
11569
|
if (!results.some((r) => r.filePath === ".opencode/skills/kuma/SKILL.md")) {
|
|
11350
11570
|
try {
|
|
11351
|
-
const dir =
|
|
11352
|
-
if (
|
|
11353
|
-
const existing =
|
|
11571
|
+
const dir = path34.dirname(opencodeSkillPath);
|
|
11572
|
+
if (fs31.existsSync(opencodeSkillPath)) {
|
|
11573
|
+
const existing = fs31.readFileSync(opencodeSkillPath, "utf-8");
|
|
11354
11574
|
if (existing.includes("kuma-mcp")) {
|
|
11355
11575
|
results.push({ type: "opencode", filePath: ".opencode/skills/kuma/SKILL.md", action: "skipped" });
|
|
11356
11576
|
} else {
|
|
11357
|
-
|
|
11577
|
+
fs31.writeFileSync(opencodeSkillPath, existing.trimEnd() + "\n\n---\n\n" + opencodeContent, "utf-8");
|
|
11358
11578
|
results.push({ type: "opencode", filePath: ".opencode/skills/kuma/SKILL.md", action: "appended" });
|
|
11359
11579
|
}
|
|
11360
11580
|
} else {
|
|
11361
|
-
if (!
|
|
11362
|
-
|
|
11581
|
+
if (!fs31.existsSync(dir)) fs31.mkdirSync(dir, { recursive: true });
|
|
11582
|
+
fs31.writeFileSync(opencodeSkillPath, opencodeContent, "utf-8");
|
|
11363
11583
|
results.push({ type: "opencode", filePath: ".opencode/skills/kuma/SKILL.md", action: "created" });
|
|
11364
11584
|
}
|
|
11365
11585
|
} catch (err) {
|
|
@@ -11371,21 +11591,21 @@ function handleOpencodeSecondary(root, results) {
|
|
|
11371
11591
|
});
|
|
11372
11592
|
}
|
|
11373
11593
|
}
|
|
11374
|
-
const pluginPath =
|
|
11594
|
+
const pluginPath = path34.resolve(root, ".opencode", "plugins", "kuma.js");
|
|
11375
11595
|
if (!results.some((r) => r.filePath === ".opencode/plugins/kuma.js")) {
|
|
11376
11596
|
try {
|
|
11377
|
-
const dir =
|
|
11378
|
-
if (
|
|
11379
|
-
const existing =
|
|
11597
|
+
const dir = path34.dirname(pluginPath);
|
|
11598
|
+
if (fs31.existsSync(pluginPath)) {
|
|
11599
|
+
const existing = fs31.readFileSync(pluginPath, "utf-8");
|
|
11380
11600
|
if (existing.includes("KumaPlugin") || existing.includes("kuma")) {
|
|
11381
11601
|
results.push({ type: "opencode", filePath: ".opencode/plugins/kuma.js", action: "skipped" });
|
|
11382
11602
|
} else {
|
|
11383
|
-
|
|
11603
|
+
fs31.writeFileSync(pluginPath, existing.trimEnd() + "\n\n" + opencodePluginTemplate(), "utf-8");
|
|
11384
11604
|
results.push({ type: "opencode", filePath: ".opencode/plugins/kuma.js", action: "appended" });
|
|
11385
11605
|
}
|
|
11386
11606
|
} else {
|
|
11387
|
-
if (!
|
|
11388
|
-
|
|
11607
|
+
if (!fs31.existsSync(dir)) fs31.mkdirSync(dir, { recursive: true });
|
|
11608
|
+
fs31.writeFileSync(pluginPath, opencodePluginTemplate(), "utf-8");
|
|
11389
11609
|
results.push({ type: "opencode", filePath: ".opencode/plugins/kuma.js", action: "created" });
|
|
11390
11610
|
}
|
|
11391
11611
|
} catch (err) {
|
|
@@ -11399,21 +11619,21 @@ function handleOpencodeSecondary(root, results) {
|
|
|
11399
11619
|
}
|
|
11400
11620
|
}
|
|
11401
11621
|
function handleCodexSecondary(root, results) {
|
|
11402
|
-
const tomlPath =
|
|
11622
|
+
const tomlPath = path34.resolve(root, ".codex/config.toml");
|
|
11403
11623
|
if (results.some((r) => r.filePath === ".codex/config.toml")) return;
|
|
11404
11624
|
try {
|
|
11405
|
-
const dir =
|
|
11406
|
-
if (!
|
|
11407
|
-
if (
|
|
11408
|
-
const existingContent =
|
|
11625
|
+
const dir = path34.dirname(tomlPath);
|
|
11626
|
+
if (!fs31.existsSync(dir)) fs31.mkdirSync(dir, { recursive: true });
|
|
11627
|
+
if (fs31.existsSync(tomlPath)) {
|
|
11628
|
+
const existingContent = fs31.readFileSync(tomlPath, "utf-8");
|
|
11409
11629
|
if (existingContent.includes("kuma")) {
|
|
11410
11630
|
results.push({ type: "codex", filePath: ".codex/config.toml", action: "skipped" });
|
|
11411
11631
|
return;
|
|
11412
11632
|
}
|
|
11413
|
-
|
|
11633
|
+
fs31.writeFileSync(tomlPath, existingContent.trimEnd() + "\n\n" + codexConfigTomlTemplate(), "utf-8");
|
|
11414
11634
|
results.push({ type: "codex", filePath: ".codex/config.toml", action: "appended" });
|
|
11415
11635
|
} else {
|
|
11416
|
-
|
|
11636
|
+
fs31.writeFileSync(tomlPath, codexConfigTomlTemplate(), "utf-8");
|
|
11417
11637
|
results.push({ type: "codex", filePath: ".codex/config.toml", action: "created" });
|
|
11418
11638
|
}
|
|
11419
11639
|
} catch (err) {
|
|
@@ -11426,11 +11646,11 @@ function handleCodexSecondary(root, results) {
|
|
|
11426
11646
|
}
|
|
11427
11647
|
}
|
|
11428
11648
|
function handleQwenSecondary(root, results) {
|
|
11429
|
-
const settingsPath =
|
|
11649
|
+
const settingsPath = path34.resolve(root, "settings.json");
|
|
11430
11650
|
if (results.some((r) => r.filePath === "settings.json")) return;
|
|
11431
11651
|
try {
|
|
11432
|
-
if (
|
|
11433
|
-
const existingContent =
|
|
11652
|
+
if (fs31.existsSync(settingsPath)) {
|
|
11653
|
+
const existingContent = fs31.readFileSync(settingsPath, "utf-8");
|
|
11434
11654
|
if (existingContent.includes("kuma")) {
|
|
11435
11655
|
if (!existingContent.includes("_Generated by Kuma MCP_")) {
|
|
11436
11656
|
try {
|
|
@@ -11438,7 +11658,7 @@ function handleQwenSecondary(root, results) {
|
|
|
11438
11658
|
parsed.mcpServers = parsed.mcpServers || {};
|
|
11439
11659
|
if (!parsed.mcpServers.kuma) {
|
|
11440
11660
|
parsed.mcpServers.kuma = { command: "npx", args: ["-y", "@plumpslabs/kuma"], env: {} };
|
|
11441
|
-
|
|
11661
|
+
fs31.writeFileSync(settingsPath, JSON.stringify(parsed, null, 2) + "\n", "utf-8");
|
|
11442
11662
|
results.push({ type: "qwen", filePath: "settings.json", action: "appended" });
|
|
11443
11663
|
return;
|
|
11444
11664
|
}
|
|
@@ -11453,13 +11673,13 @@ function handleQwenSecondary(root, results) {
|
|
|
11453
11673
|
parsed.mcpServers = parsed.mcpServers || {};
|
|
11454
11674
|
if (!parsed.mcpServers.kuma) {
|
|
11455
11675
|
parsed.mcpServers.kuma = { command: "npx", args: ["-y", "@plumpslabs/kuma"], env: {} };
|
|
11456
|
-
|
|
11676
|
+
fs31.writeFileSync(settingsPath, JSON.stringify(parsed, null, 2) + "\n", "utf-8");
|
|
11457
11677
|
results.push({ type: "qwen", filePath: "settings.json", action: "appended" });
|
|
11458
11678
|
}
|
|
11459
11679
|
} catch {
|
|
11460
11680
|
}
|
|
11461
11681
|
} else {
|
|
11462
|
-
|
|
11682
|
+
fs31.writeFileSync(settingsPath, qwenSettingsTemplate(), "utf-8");
|
|
11463
11683
|
results.push({ type: "qwen", filePath: "settings.json", action: "created" });
|
|
11464
11684
|
}
|
|
11465
11685
|
} catch (err) {
|
|
@@ -11561,12 +11781,12 @@ function getCombinedAgentsMd(selectedTypes) {
|
|
|
11561
11781
|
return lines.join("\n");
|
|
11562
11782
|
}
|
|
11563
11783
|
function handleAntigravityMcpConfig(root, results) {
|
|
11564
|
-
const mcpPath =
|
|
11784
|
+
const mcpPath = path34.resolve(root, ".agents/mcp_config.json");
|
|
11565
11785
|
if (results.some((r) => r.filePath === ".agents/mcp_config.json")) return;
|
|
11566
11786
|
try {
|
|
11567
|
-
const mcpDir =
|
|
11568
|
-
if (
|
|
11569
|
-
const existingContent =
|
|
11787
|
+
const mcpDir = path34.dirname(mcpPath);
|
|
11788
|
+
if (fs31.existsSync(mcpPath)) {
|
|
11789
|
+
const existingContent = fs31.readFileSync(mcpPath, "utf-8");
|
|
11570
11790
|
if (existingContent.includes("kuma")) {
|
|
11571
11791
|
results.push({ type: "antigravity", filePath: ".agents/mcp_config.json", action: "skipped" });
|
|
11572
11792
|
return;
|
|
@@ -11575,14 +11795,14 @@ function handleAntigravityMcpConfig(root, results) {
|
|
|
11575
11795
|
const parsed = JSON.parse(existingContent);
|
|
11576
11796
|
parsed.mcpServers = parsed.mcpServers || {};
|
|
11577
11797
|
parsed.mcpServers.kuma = { command: "npx", args: ["-y", "@plumpslabs/kuma"], env: {} };
|
|
11578
|
-
|
|
11798
|
+
fs31.writeFileSync(mcpPath, JSON.stringify(parsed, null, 2) + "\n", "utf-8");
|
|
11579
11799
|
results.push({ type: "antigravity", filePath: ".agents/mcp_config.json", action: "appended" });
|
|
11580
11800
|
} catch {
|
|
11581
11801
|
results.push({ type: "antigravity", filePath: ".agents/mcp_config.json", action: "error", error: "Invalid JSON in existing mcp_config.json" });
|
|
11582
11802
|
}
|
|
11583
11803
|
} else {
|
|
11584
|
-
if (!
|
|
11585
|
-
|
|
11804
|
+
if (!fs31.existsSync(mcpDir)) fs31.mkdirSync(mcpDir, { recursive: true });
|
|
11805
|
+
fs31.writeFileSync(mcpPath, antigravityMcpConfigTemplate(), "utf-8");
|
|
11586
11806
|
results.push({ type: "antigravity", filePath: ".agents/mcp_config.json", action: "created" });
|
|
11587
11807
|
}
|
|
11588
11808
|
} catch (err) {
|
|
@@ -11595,21 +11815,21 @@ function handleAntigravityMcpConfig(root, results) {
|
|
|
11595
11815
|
}
|
|
11596
11816
|
}
|
|
11597
11817
|
function handleAntigravityRules(root, results) {
|
|
11598
|
-
const rulePath =
|
|
11818
|
+
const rulePath = path34.resolve(root, ".agents", "rules", "kuma.md");
|
|
11599
11819
|
if (results.some((r) => r.filePath === ".agents/rules/kuma.md")) return;
|
|
11600
11820
|
try {
|
|
11601
|
-
const dir =
|
|
11602
|
-
if (!
|
|
11603
|
-
if (
|
|
11604
|
-
const existing =
|
|
11821
|
+
const dir = path34.dirname(rulePath);
|
|
11822
|
+
if (!fs31.existsSync(dir)) fs31.mkdirSync(dir, { recursive: true });
|
|
11823
|
+
if (fs31.existsSync(rulePath)) {
|
|
11824
|
+
const existing = fs31.readFileSync(rulePath, "utf-8");
|
|
11605
11825
|
if (existing.includes("Kuma MCP") || existing.includes("kuma-mcp")) {
|
|
11606
11826
|
results.push({ type: "antigravity", filePath: ".agents/rules/kuma.md", action: "skipped" });
|
|
11607
11827
|
return;
|
|
11608
11828
|
}
|
|
11609
|
-
|
|
11829
|
+
fs31.writeFileSync(rulePath, existing.trimEnd() + "\n\n---\n\n" + antigravityRuleTemplate(), "utf-8");
|
|
11610
11830
|
results.push({ type: "antigravity", filePath: ".agents/rules/kuma.md", action: "appended" });
|
|
11611
11831
|
} else {
|
|
11612
|
-
|
|
11832
|
+
fs31.writeFileSync(rulePath, antigravityRuleTemplate(), "utf-8");
|
|
11613
11833
|
results.push({ type: "antigravity", filePath: ".agents/rules/kuma.md", action: "created" });
|
|
11614
11834
|
}
|
|
11615
11835
|
} catch (err) {
|
|
@@ -11622,19 +11842,19 @@ function handleAntigravityRules(root, results) {
|
|
|
11622
11842
|
}
|
|
11623
11843
|
}
|
|
11624
11844
|
function handleGeminiMd(root, results) {
|
|
11625
|
-
const geminiPath =
|
|
11845
|
+
const geminiPath = path34.resolve(root, "GEMINI.md");
|
|
11626
11846
|
if (results.some((r) => r.filePath === "GEMINI.md")) return;
|
|
11627
11847
|
try {
|
|
11628
|
-
if (
|
|
11629
|
-
const existing =
|
|
11848
|
+
if (fs31.existsSync(geminiPath)) {
|
|
11849
|
+
const existing = fs31.readFileSync(geminiPath, "utf-8");
|
|
11630
11850
|
if (existing.includes("Kuma MCP") || existing.includes("kuma_context")) {
|
|
11631
11851
|
results.push({ type: "antigravity", filePath: "GEMINI.md", action: "skipped" });
|
|
11632
11852
|
return;
|
|
11633
11853
|
}
|
|
11634
|
-
|
|
11854
|
+
fs31.writeFileSync(geminiPath, existing.trimEnd() + "\n\n---\n\n" + geminiTemplate(), "utf-8");
|
|
11635
11855
|
results.push({ type: "antigravity", filePath: "GEMINI.md", action: "appended" });
|
|
11636
11856
|
} else {
|
|
11637
|
-
|
|
11857
|
+
fs31.writeFileSync(geminiPath, geminiTemplate(), "utf-8");
|
|
11638
11858
|
results.push({ type: "antigravity", filePath: "GEMINI.md", action: "created" });
|
|
11639
11859
|
}
|
|
11640
11860
|
} catch (err) {
|
|
@@ -11652,19 +11872,19 @@ function handleAntigravitySecondary(root, results) {
|
|
|
11652
11872
|
handleGeminiMd(root, results);
|
|
11653
11873
|
}
|
|
11654
11874
|
function handleWindsurfSecondary(root, results) {
|
|
11655
|
-
const rulesPath =
|
|
11875
|
+
const rulesPath = path34.resolve(root, ".windsurfrules");
|
|
11656
11876
|
if (results.some((r) => r.filePath === ".windsurfrules")) return;
|
|
11657
11877
|
try {
|
|
11658
|
-
if (
|
|
11659
|
-
const existing =
|
|
11878
|
+
if (fs31.existsSync(rulesPath)) {
|
|
11879
|
+
const existing = fs31.readFileSync(rulesPath, "utf-8");
|
|
11660
11880
|
if (existing.includes("Kuma MCP") || existing.includes("kuma_context")) {
|
|
11661
11881
|
results.push({ type: "windsurf", filePath: ".windsurfrules", action: "skipped" });
|
|
11662
11882
|
return;
|
|
11663
11883
|
}
|
|
11664
|
-
|
|
11884
|
+
fs31.writeFileSync(rulesPath, existing.trimEnd() + "\n\n---\n\n" + windsurfrulesTemplate(), "utf-8");
|
|
11665
11885
|
results.push({ type: "windsurf", filePath: ".windsurfrules", action: "appended" });
|
|
11666
11886
|
} else {
|
|
11667
|
-
|
|
11887
|
+
fs31.writeFileSync(rulesPath, windsurfrulesTemplate(), "utf-8");
|
|
11668
11888
|
results.push({ type: "windsurf", filePath: ".windsurfrules", action: "created" });
|
|
11669
11889
|
}
|
|
11670
11890
|
} catch (err) {
|
|
@@ -11677,21 +11897,21 @@ function handleWindsurfSecondary(root, results) {
|
|
|
11677
11897
|
}
|
|
11678
11898
|
}
|
|
11679
11899
|
function handleClineSecondary(root, results) {
|
|
11680
|
-
const rooPath =
|
|
11900
|
+
const rooPath = path34.resolve(root, ".roo", "rules", "kuma.md");
|
|
11681
11901
|
if (!results.some((r) => r.filePath === ".roo/rules/kuma.md")) {
|
|
11682
11902
|
try {
|
|
11683
|
-
const dir =
|
|
11684
|
-
if (
|
|
11685
|
-
const existing =
|
|
11903
|
+
const dir = path34.dirname(rooPath);
|
|
11904
|
+
if (fs31.existsSync(rooPath)) {
|
|
11905
|
+
const existing = fs31.readFileSync(rooPath, "utf-8");
|
|
11686
11906
|
if (existing.includes("kuma-mcp") || existing.includes("Kuma MCP")) {
|
|
11687
11907
|
results.push({ type: "cline", filePath: ".roo/rules/kuma.md", action: "skipped" });
|
|
11688
11908
|
} else {
|
|
11689
|
-
|
|
11909
|
+
fs31.writeFileSync(rooPath, existing.trimEnd() + "\n\n---\n\n" + rooRulesTemplate(), "utf-8");
|
|
11690
11910
|
results.push({ type: "cline", filePath: ".roo/rules/kuma.md", action: "appended" });
|
|
11691
11911
|
}
|
|
11692
11912
|
} else {
|
|
11693
|
-
if (!
|
|
11694
|
-
|
|
11913
|
+
if (!fs31.existsSync(dir)) fs31.mkdirSync(dir, { recursive: true });
|
|
11914
|
+
fs31.writeFileSync(rooPath, rooRulesTemplate(), "utf-8");
|
|
11695
11915
|
results.push({ type: "cline", filePath: ".roo/rules/kuma.md", action: "created" });
|
|
11696
11916
|
}
|
|
11697
11917
|
} catch (err) {
|
|
@@ -11703,21 +11923,21 @@ function handleClineSecondary(root, results) {
|
|
|
11703
11923
|
});
|
|
11704
11924
|
}
|
|
11705
11925
|
}
|
|
11706
|
-
const traePath =
|
|
11926
|
+
const traePath = path34.resolve(root, ".trae", "rules", "kuma.md");
|
|
11707
11927
|
if (!results.some((r) => r.filePath === ".trae/rules/kuma.md")) {
|
|
11708
11928
|
try {
|
|
11709
|
-
const dir =
|
|
11710
|
-
if (
|
|
11711
|
-
const existing =
|
|
11929
|
+
const dir = path34.dirname(traePath);
|
|
11930
|
+
if (fs31.existsSync(traePath)) {
|
|
11931
|
+
const existing = fs31.readFileSync(traePath, "utf-8");
|
|
11712
11932
|
if (existing.includes("Kuma MCP")) {
|
|
11713
11933
|
results.push({ type: "cline", filePath: ".trae/rules/kuma.md", action: "skipped" });
|
|
11714
11934
|
} else {
|
|
11715
|
-
|
|
11935
|
+
fs31.writeFileSync(traePath, existing.trimEnd() + "\n\n---\n\n" + traeRulesTemplate(), "utf-8");
|
|
11716
11936
|
results.push({ type: "cline", filePath: ".trae/rules/kuma.md", action: "appended" });
|
|
11717
11937
|
}
|
|
11718
11938
|
} else {
|
|
11719
|
-
if (!
|
|
11720
|
-
|
|
11939
|
+
if (!fs31.existsSync(dir)) fs31.mkdirSync(dir, { recursive: true });
|
|
11940
|
+
fs31.writeFileSync(traePath, traeRulesTemplate(), "utf-8");
|
|
11721
11941
|
results.push({ type: "cline", filePath: ".trae/rules/kuma.md", action: "created" });
|
|
11722
11942
|
}
|
|
11723
11943
|
} catch (err) {
|
|
@@ -11729,21 +11949,21 @@ function handleClineSecondary(root, results) {
|
|
|
11729
11949
|
});
|
|
11730
11950
|
}
|
|
11731
11951
|
}
|
|
11732
|
-
const qoderPath =
|
|
11952
|
+
const qoderPath = path34.resolve(root, ".qoder", "rules", "kuma.md");
|
|
11733
11953
|
if (!results.some((r) => r.filePath === ".qoder/rules/kuma.md")) {
|
|
11734
11954
|
try {
|
|
11735
|
-
const dir =
|
|
11736
|
-
if (
|
|
11737
|
-
const existing =
|
|
11955
|
+
const dir = path34.dirname(qoderPath);
|
|
11956
|
+
if (fs31.existsSync(qoderPath)) {
|
|
11957
|
+
const existing = fs31.readFileSync(qoderPath, "utf-8");
|
|
11738
11958
|
if (existing.includes("Kuma MCP")) {
|
|
11739
11959
|
results.push({ type: "cline", filePath: ".qoder/rules/kuma.md", action: "skipped" });
|
|
11740
11960
|
} else {
|
|
11741
|
-
|
|
11961
|
+
fs31.writeFileSync(qoderPath, existing.trimEnd() + "\n\n---\n\n" + qoderRulesTemplate(), "utf-8");
|
|
11742
11962
|
results.push({ type: "cline", filePath: ".qoder/rules/kuma.md", action: "appended" });
|
|
11743
11963
|
}
|
|
11744
11964
|
} else {
|
|
11745
|
-
if (!
|
|
11746
|
-
|
|
11965
|
+
if (!fs31.existsSync(dir)) fs31.mkdirSync(dir, { recursive: true });
|
|
11966
|
+
fs31.writeFileSync(qoderPath, qoderRulesTemplate(), "utf-8");
|
|
11747
11967
|
results.push({ type: "cline", filePath: ".qoder/rules/kuma.md", action: "created" });
|
|
11748
11968
|
}
|
|
11749
11969
|
} catch (err) {
|
|
@@ -11757,18 +11977,18 @@ function handleClineSecondary(root, results) {
|
|
|
11757
11977
|
}
|
|
11758
11978
|
}
|
|
11759
11979
|
function handleAiderSecondary(root, results) {
|
|
11760
|
-
const ymlPath =
|
|
11980
|
+
const ymlPath = path34.resolve(root, ".aider.conf.yml");
|
|
11761
11981
|
if (results.some((r) => r.filePath === ".aider.conf.yml")) return;
|
|
11762
11982
|
try {
|
|
11763
11983
|
const conventionsRef = "read: CONVENTIONS.md";
|
|
11764
|
-
if (
|
|
11765
|
-
const existingContent =
|
|
11984
|
+
if (fs31.existsSync(ymlPath)) {
|
|
11985
|
+
const existingContent = fs31.readFileSync(ymlPath, "utf-8");
|
|
11766
11986
|
if (existingContent.includes("CONVENTIONS.md") || existingContent.includes("kuma")) {
|
|
11767
11987
|
results.push({ type: "aider", filePath: ".aider.conf.yml", action: "skipped" });
|
|
11768
11988
|
return;
|
|
11769
11989
|
}
|
|
11770
11990
|
const newContent = existingContent.trimEnd() + "\n\n# Kuma MCP conventions\n" + conventionsRef + "\n";
|
|
11771
|
-
|
|
11991
|
+
fs31.writeFileSync(ymlPath, newContent, "utf-8");
|
|
11772
11992
|
results.push({ type: "aider", filePath: ".aider.conf.yml", action: "appended" });
|
|
11773
11993
|
} else {
|
|
11774
11994
|
const content = [
|
|
@@ -11778,7 +11998,7 @@ function handleAiderSecondary(root, results) {
|
|
|
11778
11998
|
conventionsRef,
|
|
11779
11999
|
""
|
|
11780
12000
|
].join("\n");
|
|
11781
|
-
|
|
12001
|
+
fs31.writeFileSync(ymlPath, content, "utf-8");
|
|
11782
12002
|
results.push({ type: "aider", filePath: ".aider.conf.yml", action: "created" });
|
|
11783
12003
|
}
|
|
11784
12004
|
} catch (err) {
|
|
@@ -11791,10 +12011,10 @@ function handleAiderSecondary(root, results) {
|
|
|
11791
12011
|
}
|
|
11792
12012
|
}
|
|
11793
12013
|
function handleCopilotSecondary(root, results) {
|
|
11794
|
-
const skillPath =
|
|
12014
|
+
const skillPath = path34.resolve(root, ".github/skills/kuma/SKILL.md");
|
|
11795
12015
|
if (results.some((r) => r.filePath === ".github/skills/kuma/SKILL.md")) return;
|
|
11796
12016
|
try {
|
|
11797
|
-
const dir =
|
|
12017
|
+
const dir = path34.dirname(skillPath);
|
|
11798
12018
|
const content = [
|
|
11799
12019
|
"---",
|
|
11800
12020
|
"name: kuma-mcp",
|
|
@@ -11805,17 +12025,17 @@ function handleCopilotSecondary(root, results) {
|
|
|
11805
12025
|
"",
|
|
11806
12026
|
"\u{1F4D6} Read `.kuma/init.md` for detailed rules."
|
|
11807
12027
|
].join("\n");
|
|
11808
|
-
if (
|
|
11809
|
-
const existingContent =
|
|
12028
|
+
if (fs31.existsSync(skillPath)) {
|
|
12029
|
+
const existingContent = fs31.readFileSync(skillPath, "utf-8");
|
|
11810
12030
|
if (existingContent.includes("kuma")) {
|
|
11811
12031
|
results.push({ type: "copilot", filePath: ".github/skills/kuma/SKILL.md", action: "skipped" });
|
|
11812
12032
|
return;
|
|
11813
12033
|
}
|
|
11814
|
-
|
|
12034
|
+
fs31.writeFileSync(skillPath, existingContent.trimEnd() + "\n\n" + content, "utf-8");
|
|
11815
12035
|
results.push({ type: "copilot", filePath: ".github/skills/kuma/SKILL.md", action: "appended" });
|
|
11816
12036
|
} else {
|
|
11817
|
-
if (!
|
|
11818
|
-
|
|
12037
|
+
if (!fs31.existsSync(dir)) fs31.mkdirSync(dir, { recursive: true });
|
|
12038
|
+
fs31.writeFileSync(skillPath, content, "utf-8");
|
|
11819
12039
|
results.push({ type: "copilot", filePath: ".github/skills/kuma/SKILL.md", action: "created" });
|
|
11820
12040
|
}
|
|
11821
12041
|
} catch (err) {
|
|
@@ -11828,21 +12048,21 @@ function handleCopilotSecondary(root, results) {
|
|
|
11828
12048
|
}
|
|
11829
12049
|
}
|
|
11830
12050
|
function handleOpenclawSecondary(root, results) {
|
|
11831
|
-
const mcpPath =
|
|
12051
|
+
const mcpPath = path34.resolve(root, ".agents/mcp_config.json");
|
|
11832
12052
|
if (results.some((r) => r.filePath === ".agents/mcp_config.json")) return;
|
|
11833
12053
|
try {
|
|
11834
|
-
const dir =
|
|
11835
|
-
if (
|
|
11836
|
-
const existingContent =
|
|
12054
|
+
const dir = path34.dirname(mcpPath);
|
|
12055
|
+
if (fs31.existsSync(mcpPath)) {
|
|
12056
|
+
const existingContent = fs31.readFileSync(mcpPath, "utf-8");
|
|
11837
12057
|
if (existingContent.includes("kuma")) return;
|
|
11838
12058
|
const parsed = JSON.parse(existingContent);
|
|
11839
12059
|
parsed.mcpServers = parsed.mcpServers || {};
|
|
11840
12060
|
parsed.mcpServers.kuma = { command: "npx", args: ["-y", "@plumpslabs/kuma"], env: {} };
|
|
11841
|
-
|
|
12061
|
+
fs31.writeFileSync(mcpPath, JSON.stringify(parsed, null, 2) + "\n", "utf-8");
|
|
11842
12062
|
results.push({ type: "openclaw", filePath: ".agents/mcp_config.json", action: "appended" });
|
|
11843
12063
|
} else {
|
|
11844
|
-
if (!
|
|
11845
|
-
|
|
12064
|
+
if (!fs31.existsSync(dir)) fs31.mkdirSync(dir, { recursive: true });
|
|
12065
|
+
fs31.writeFileSync(mcpPath, antigravityMcpConfigTemplate(), "utf-8");
|
|
11846
12066
|
results.push({ type: "openclaw", filePath: ".agents/mcp_config.json", action: "created" });
|
|
11847
12067
|
}
|
|
11848
12068
|
} catch (err) {
|
|
@@ -11855,20 +12075,20 @@ function handleOpenclawSecondary(root, results) {
|
|
|
11855
12075
|
}
|
|
11856
12076
|
}
|
|
11857
12077
|
function handleInitMdGeneration(root, results) {
|
|
11858
|
-
const initMdPath =
|
|
12078
|
+
const initMdPath = path34.resolve(root, ".kuma/init.md");
|
|
11859
12079
|
try {
|
|
11860
|
-
const kumaDir =
|
|
11861
|
-
if (!
|
|
11862
|
-
if (
|
|
11863
|
-
const existing =
|
|
12080
|
+
const kumaDir = path34.dirname(initMdPath);
|
|
12081
|
+
if (!fs31.existsSync(kumaDir)) fs31.mkdirSync(kumaDir, { recursive: true });
|
|
12082
|
+
if (fs31.existsSync(initMdPath)) {
|
|
12083
|
+
const existing = fs31.readFileSync(initMdPath, "utf-8");
|
|
11864
12084
|
if (existing.includes("_Generated by Kuma MCP_")) {
|
|
11865
12085
|
results.push({ type: "claude", filePath: ".kuma/init.md", action: "skipped" });
|
|
11866
12086
|
return;
|
|
11867
12087
|
}
|
|
11868
|
-
|
|
12088
|
+
fs31.writeFileSync(initMdPath, existing.trimEnd() + "\n\n" + generateInitMdContent(), "utf-8");
|
|
11869
12089
|
results.push({ type: "claude", filePath: ".kuma/init.md", action: "appended" });
|
|
11870
12090
|
} else {
|
|
11871
|
-
|
|
12091
|
+
fs31.writeFileSync(initMdPath, generateInitMdContent(), "utf-8");
|
|
11872
12092
|
results.push({ type: "claude", filePath: ".kuma/init.md", action: "created" });
|
|
11873
12093
|
}
|
|
11874
12094
|
} catch (err) {
|
|
@@ -11881,20 +12101,20 @@ function handleInitMdGeneration(root, results) {
|
|
|
11881
12101
|
}
|
|
11882
12102
|
}
|
|
11883
12103
|
function handleCodewhaleSecondary(root, results) {
|
|
11884
|
-
const mcpPath =
|
|
12104
|
+
const mcpPath = path34.resolve(root, ".codewhale/mcp.json");
|
|
11885
12105
|
if (results.some((r) => r.filePath === ".codewhale/mcp.json")) return;
|
|
11886
12106
|
try {
|
|
11887
|
-
const dir =
|
|
11888
|
-
if (
|
|
11889
|
-
const existingContent =
|
|
12107
|
+
const dir = path34.dirname(mcpPath);
|
|
12108
|
+
if (fs31.existsSync(mcpPath)) {
|
|
12109
|
+
const existingContent = fs31.readFileSync(mcpPath, "utf-8");
|
|
11890
12110
|
if (existingContent.includes("kuma")) return;
|
|
11891
12111
|
const parsed = JSON.parse(existingContent);
|
|
11892
12112
|
parsed.mcpServers = parsed.mcpServers || {};
|
|
11893
12113
|
parsed.mcpServers.kuma = { command: "npx", args: ["-y", "@plumpslabs/kuma"], env: {} };
|
|
11894
|
-
|
|
12114
|
+
fs31.writeFileSync(mcpPath, JSON.stringify(parsed, null, 2) + "\n", "utf-8");
|
|
11895
12115
|
results.push({ type: "codewhale", filePath: ".codewhale/mcp.json", action: "appended" });
|
|
11896
12116
|
} else {
|
|
11897
|
-
if (!
|
|
12117
|
+
if (!fs31.existsSync(dir)) fs31.mkdirSync(dir, { recursive: true });
|
|
11898
12118
|
const config = {
|
|
11899
12119
|
mcpServers: {
|
|
11900
12120
|
kuma: {
|
|
@@ -11904,7 +12124,7 @@ function handleCodewhaleSecondary(root, results) {
|
|
|
11904
12124
|
}
|
|
11905
12125
|
}
|
|
11906
12126
|
};
|
|
11907
|
-
|
|
12127
|
+
fs31.writeFileSync(mcpPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
|
|
11908
12128
|
results.push({ type: "codewhale", filePath: ".codewhale/mcp.json", action: "created" });
|
|
11909
12129
|
}
|
|
11910
12130
|
} catch (err) {
|
|
@@ -11917,7 +12137,7 @@ function handleCodewhaleSecondary(root, results) {
|
|
|
11917
12137
|
}
|
|
11918
12138
|
}
|
|
11919
12139
|
function handleClaudeSecondary(root, results) {
|
|
11920
|
-
const settingsPath =
|
|
12140
|
+
const settingsPath = path34.resolve(root, ".claude", "settings.json");
|
|
11921
12141
|
const hookBlock = {
|
|
11922
12142
|
hooks: {
|
|
11923
12143
|
PreToolUse: [
|
|
@@ -11948,8 +12168,8 @@ function handleClaudeSecondary(root, results) {
|
|
|
11948
12168
|
}
|
|
11949
12169
|
};
|
|
11950
12170
|
try {
|
|
11951
|
-
if (
|
|
11952
|
-
const existing = JSON.parse(
|
|
12171
|
+
if (fs31.existsSync(settingsPath)) {
|
|
12172
|
+
const existing = JSON.parse(fs31.readFileSync(settingsPath, "utf-8"));
|
|
11953
12173
|
const existingHooks = existing.hooks || {};
|
|
11954
12174
|
const mergedPre = [...existingHooks.PreToolUse || []];
|
|
11955
12175
|
for (const entry of hookBlock.hooks.PreToolUse) {
|
|
@@ -11973,12 +12193,12 @@ function handleClaudeSecondary(root, results) {
|
|
|
11973
12193
|
...existing,
|
|
11974
12194
|
hooks: { ...existingHooks, PreToolUse: mergedPre, SessionStart: mergedStart, PreCompact: mergedCompact }
|
|
11975
12195
|
};
|
|
11976
|
-
|
|
12196
|
+
fs31.writeFileSync(settingsPath, JSON.stringify(merged, null, 2) + "\n", "utf-8");
|
|
11977
12197
|
results.push({ type: "claude", filePath: ".claude/settings.json", action: "appended" });
|
|
11978
12198
|
} else {
|
|
11979
|
-
const dir =
|
|
11980
|
-
if (!
|
|
11981
|
-
|
|
12199
|
+
const dir = path34.dirname(settingsPath);
|
|
12200
|
+
if (!fs31.existsSync(dir)) fs31.mkdirSync(dir, { recursive: true });
|
|
12201
|
+
fs31.writeFileSync(settingsPath, JSON.stringify(hookBlock, null, 2) + "\n", "utf-8");
|
|
11982
12202
|
results.push({ type: "claude", filePath: ".claude/settings.json", action: "created" });
|
|
11983
12203
|
}
|
|
11984
12204
|
} catch (err) {
|
|
@@ -11989,10 +12209,10 @@ function handleClaudeSecondary(root, results) {
|
|
|
11989
12209
|
error: err instanceof Error ? err.message : String(err)
|
|
11990
12210
|
});
|
|
11991
12211
|
}
|
|
11992
|
-
const skillPath =
|
|
12212
|
+
const skillPath = path34.resolve(root, ".claude", "skills", "kuma", "SKILL.md");
|
|
11993
12213
|
if (!results.some((r) => r.filePath === ".claude/skills/kuma/SKILL.md")) {
|
|
11994
12214
|
try {
|
|
11995
|
-
const dir =
|
|
12215
|
+
const dir = path34.dirname(skillPath);
|
|
11996
12216
|
const content = [
|
|
11997
12217
|
"---",
|
|
11998
12218
|
"name: kuma-mcp",
|
|
@@ -12004,17 +12224,17 @@ function handleClaudeSecondary(root, results) {
|
|
|
12004
12224
|
"\u{1F4D6} Read `.kuma/init.md` for detailed rules.",
|
|
12005
12225
|
"\u{1F4C2} Readable state: `.kuma/KNOWN_GOTCHAS.md` (gotchas) \xB7 `.kuma/memories/decisions.md` (decisions)"
|
|
12006
12226
|
].join("\n");
|
|
12007
|
-
if (
|
|
12008
|
-
const existing =
|
|
12227
|
+
if (fs31.existsSync(skillPath)) {
|
|
12228
|
+
const existing = fs31.readFileSync(skillPath, "utf-8");
|
|
12009
12229
|
if (existing.includes("kuma-mcp")) {
|
|
12010
12230
|
results.push({ type: "claude", filePath: ".claude/skills/kuma/SKILL.md", action: "skipped" });
|
|
12011
12231
|
} else {
|
|
12012
|
-
|
|
12232
|
+
fs31.writeFileSync(skillPath, existing.trimEnd() + "\n\n---\n\n" + content, "utf-8");
|
|
12013
12233
|
results.push({ type: "claude", filePath: ".claude/skills/kuma/SKILL.md", action: "appended" });
|
|
12014
12234
|
}
|
|
12015
12235
|
} else {
|
|
12016
|
-
if (!
|
|
12017
|
-
|
|
12236
|
+
if (!fs31.existsSync(dir)) fs31.mkdirSync(dir, { recursive: true });
|
|
12237
|
+
fs31.writeFileSync(skillPath, content, "utf-8");
|
|
12018
12238
|
results.push({ type: "claude", filePath: ".claude/skills/kuma/SKILL.md", action: "created" });
|
|
12019
12239
|
}
|
|
12020
12240
|
} catch (err) {
|
|
@@ -12028,27 +12248,27 @@ function handleClaudeSecondary(root, results) {
|
|
|
12028
12248
|
}
|
|
12029
12249
|
}
|
|
12030
12250
|
function writeHooksFile(root, relPath, type, results, build) {
|
|
12031
|
-
const fullPath =
|
|
12251
|
+
const fullPath = path34.resolve(root, relPath);
|
|
12032
12252
|
try {
|
|
12033
12253
|
let existing = {};
|
|
12034
12254
|
let existed = false;
|
|
12035
|
-
if (
|
|
12255
|
+
if (fs31.existsSync(fullPath)) {
|
|
12036
12256
|
existed = true;
|
|
12037
12257
|
try {
|
|
12038
|
-
existing = JSON.parse(
|
|
12258
|
+
existing = JSON.parse(fs31.readFileSync(fullPath, "utf-8"));
|
|
12039
12259
|
} catch {
|
|
12040
12260
|
existing = {};
|
|
12041
12261
|
}
|
|
12042
12262
|
} else {
|
|
12043
|
-
const dir =
|
|
12044
|
-
if (!
|
|
12263
|
+
const dir = path34.dirname(fullPath);
|
|
12264
|
+
if (!fs31.existsSync(dir)) fs31.mkdirSync(dir, { recursive: true });
|
|
12045
12265
|
}
|
|
12046
12266
|
const { doc, changed } = build(existing);
|
|
12047
12267
|
if (!changed) {
|
|
12048
12268
|
results.push({ type, filePath: relPath, action: "skipped" });
|
|
12049
12269
|
return;
|
|
12050
12270
|
}
|
|
12051
|
-
|
|
12271
|
+
fs31.writeFileSync(fullPath, JSON.stringify(doc, null, 2) + "\n", "utf-8");
|
|
12052
12272
|
results.push({ type, filePath: relPath, action: existed ? "appended" : "created" });
|
|
12053
12273
|
} catch (err) {
|
|
12054
12274
|
results.push({ type, filePath: relPath, action: "error", error: err instanceof Error ? err.message : String(err) });
|
|
@@ -12129,18 +12349,18 @@ function handleCodexHooks(root, results) {
|
|
|
12129
12349
|
});
|
|
12130
12350
|
}
|
|
12131
12351
|
function handleCursorGotchaRules(root, results) {
|
|
12132
|
-
const rulesDir2 =
|
|
12352
|
+
const rulesDir2 = path34.resolve(root, ".cursor", "rules", "kuma-gotchas");
|
|
12133
12353
|
try {
|
|
12134
12354
|
let gotchas = [];
|
|
12135
12355
|
try {
|
|
12136
12356
|
gotchas = getActiveGotchas().filter((g) => g.severity === "high" || g.severity === "critical");
|
|
12137
12357
|
} catch {
|
|
12138
12358
|
}
|
|
12139
|
-
if (
|
|
12140
|
-
for (const f of
|
|
12359
|
+
if (fs31.existsSync(rulesDir2)) {
|
|
12360
|
+
for (const f of fs31.readdirSync(rulesDir2)) {
|
|
12141
12361
|
if (f.endsWith(".mdc")) {
|
|
12142
12362
|
try {
|
|
12143
|
-
|
|
12363
|
+
fs31.rmSync(path34.join(rulesDir2, f), { force: true });
|
|
12144
12364
|
} catch {
|
|
12145
12365
|
}
|
|
12146
12366
|
}
|
|
@@ -12150,7 +12370,7 @@ function handleCursorGotchaRules(root, results) {
|
|
|
12150
12370
|
results.push({ type: "cursor", filePath: ".cursor/rules/kuma-gotchas/", action: "skipped" });
|
|
12151
12371
|
return;
|
|
12152
12372
|
}
|
|
12153
|
-
|
|
12373
|
+
fs31.mkdirSync(rulesDir2, { recursive: true });
|
|
12154
12374
|
const seen = /* @__PURE__ */ new Set();
|
|
12155
12375
|
let created = 0;
|
|
12156
12376
|
for (const g of gotchas) {
|
|
@@ -12171,7 +12391,7 @@ function handleCursorGotchaRules(root, results) {
|
|
|
12171
12391
|
"`kuma_context({ action: 'history', target: '<file>' })`",
|
|
12172
12392
|
""
|
|
12173
12393
|
].join("\n");
|
|
12174
|
-
|
|
12394
|
+
fs31.writeFileSync(path34.join(rulesDir2, `${slug2}.mdc`), md, "utf-8");
|
|
12175
12395
|
created++;
|
|
12176
12396
|
}
|
|
12177
12397
|
results.push({
|
|
@@ -12198,28 +12418,28 @@ function runInit(options) {
|
|
|
12198
12418
|
let agentsMdHandled = false;
|
|
12199
12419
|
for (const type of selected) {
|
|
12200
12420
|
const relativePath = configFilePath(type);
|
|
12201
|
-
const fullPath =
|
|
12421
|
+
const fullPath = path34.resolve(root, relativePath);
|
|
12202
12422
|
const getTemplate = TEMPLATES[type];
|
|
12203
12423
|
try {
|
|
12204
12424
|
if (AGENTS_MD_TYPES.includes(type) && !agentsMdHandled) {
|
|
12205
12425
|
agentsMdHandled = true;
|
|
12206
12426
|
const combinedContent = getCombinedAgentsMd(new Set(agentsMdSelected));
|
|
12207
|
-
if (
|
|
12427
|
+
if (fs31.existsSync(fullPath)) {
|
|
12208
12428
|
if (options.skipExisting) {
|
|
12209
12429
|
results.push({ type, filePath: relativePath, action: "skipped" });
|
|
12210
12430
|
} else {
|
|
12211
|
-
const existingContent =
|
|
12431
|
+
const existingContent = fs31.readFileSync(fullPath, "utf-8");
|
|
12212
12432
|
if (existingContent.includes("_Generated by Kuma MCP_")) {
|
|
12213
12433
|
results.push({ type, filePath: relativePath, action: "skipped" });
|
|
12214
12434
|
} else {
|
|
12215
|
-
|
|
12435
|
+
fs31.writeFileSync(fullPath, existingContent.trimEnd() + "\n\n" + combinedContent, "utf-8");
|
|
12216
12436
|
results.push({ type, filePath: relativePath, action: "appended" });
|
|
12217
12437
|
}
|
|
12218
12438
|
}
|
|
12219
12439
|
} else {
|
|
12220
|
-
const dir =
|
|
12221
|
-
if (!
|
|
12222
|
-
|
|
12440
|
+
const dir = path34.dirname(fullPath);
|
|
12441
|
+
if (!fs31.existsSync(dir)) fs31.mkdirSync(dir, { recursive: true });
|
|
12442
|
+
fs31.writeFileSync(fullPath, combinedContent, "utf-8");
|
|
12223
12443
|
results.push({ type, filePath: relativePath, action: "created" });
|
|
12224
12444
|
}
|
|
12225
12445
|
if (selectedSet.has("opencode")) handleOpencodeSecondary(root, results);
|
|
@@ -12231,12 +12451,12 @@ function runInit(options) {
|
|
|
12231
12451
|
continue;
|
|
12232
12452
|
} else {
|
|
12233
12453
|
const template = getTemplate();
|
|
12234
|
-
if (
|
|
12454
|
+
if (fs31.existsSync(fullPath)) {
|
|
12235
12455
|
if (options.skipExisting) {
|
|
12236
12456
|
results.push({ type, filePath: relativePath, action: "skipped" });
|
|
12237
12457
|
continue;
|
|
12238
12458
|
}
|
|
12239
|
-
const existingContent =
|
|
12459
|
+
const existingContent = fs31.readFileSync(fullPath, "utf-8");
|
|
12240
12460
|
if (existingContent.includes("_Generated by Kuma MCP_")) {
|
|
12241
12461
|
if (type === "antigravity") {
|
|
12242
12462
|
handleAntigravitySecondary(root, results);
|
|
@@ -12253,14 +12473,14 @@ function runInit(options) {
|
|
|
12253
12473
|
continue;
|
|
12254
12474
|
}
|
|
12255
12475
|
const newContent = existingContent.trimEnd() + APPEND_SEPARATOR + template;
|
|
12256
|
-
|
|
12476
|
+
fs31.writeFileSync(fullPath, newContent, "utf-8");
|
|
12257
12477
|
results.push({ type, filePath: relativePath, action: "appended" });
|
|
12258
12478
|
} else {
|
|
12259
|
-
const dir =
|
|
12260
|
-
if (!
|
|
12261
|
-
|
|
12479
|
+
const dir = path34.dirname(fullPath);
|
|
12480
|
+
if (!fs31.existsSync(dir)) {
|
|
12481
|
+
fs31.mkdirSync(dir, { recursive: true });
|
|
12262
12482
|
}
|
|
12263
|
-
|
|
12483
|
+
fs31.writeFileSync(fullPath, template, "utf-8");
|
|
12264
12484
|
results.push({ type, filePath: relativePath, action: "created" });
|
|
12265
12485
|
}
|
|
12266
12486
|
if (type === "antigravity") {
|
|
@@ -12432,8 +12652,8 @@ var compactionContext_exports = {};
|
|
|
12432
12652
|
__export(compactionContext_exports, {
|
|
12433
12653
|
getCompactionContext: () => getCompactionContext
|
|
12434
12654
|
});
|
|
12435
|
-
import
|
|
12436
|
-
import
|
|
12655
|
+
import fs32 from "fs";
|
|
12656
|
+
import path35 from "path";
|
|
12437
12657
|
async function getCompactionContext() {
|
|
12438
12658
|
const parts = [];
|
|
12439
12659
|
try {
|
|
@@ -12446,8 +12666,8 @@ async function getCompactionContext() {
|
|
|
12446
12666
|
} catch {
|
|
12447
12667
|
}
|
|
12448
12668
|
try {
|
|
12449
|
-
const dbFile =
|
|
12450
|
-
if (
|
|
12669
|
+
const dbFile = path35.join(getProjectRoot(), ".kuma", "kuma.db");
|
|
12670
|
+
if (fs32.existsSync(dbFile)) {
|
|
12451
12671
|
const { getDb: getDb2 } = await Promise.resolve().then(() => (init_kumaDb(), kumaDb_exports));
|
|
12452
12672
|
const db = await getDb2();
|
|
12453
12673
|
const stmt = db.prepare(
|
|
@@ -12473,9 +12693,9 @@ async function getCompactionContext() {
|
|
|
12473
12693
|
} catch {
|
|
12474
12694
|
}
|
|
12475
12695
|
try {
|
|
12476
|
-
const cpDir =
|
|
12477
|
-
if (
|
|
12478
|
-
const cps =
|
|
12696
|
+
const cpDir = path35.join(getProjectRoot(), ".kuma", "checkpoints");
|
|
12697
|
+
if (fs32.existsSync(cpDir)) {
|
|
12698
|
+
const cps = fs32.readdirSync(cpDir).slice(0, 3);
|
|
12479
12699
|
if (cps.length > 0) parts.push(`Checkpoints: ${cps.join(", ")}`);
|
|
12480
12700
|
}
|
|
12481
12701
|
} catch {
|
|
@@ -12503,22 +12723,22 @@ __export(kumaDaemon_exports, {
|
|
|
12503
12723
|
daemonStop: () => daemonStop,
|
|
12504
12724
|
daemonTick: () => daemonTick
|
|
12505
12725
|
});
|
|
12506
|
-
import
|
|
12507
|
-
import
|
|
12726
|
+
import fs33 from "fs";
|
|
12727
|
+
import path36 from "path";
|
|
12508
12728
|
import { spawn } from "child_process";
|
|
12509
12729
|
function paths(root) {
|
|
12510
12730
|
const r = root || getProjectRoot();
|
|
12511
12731
|
return {
|
|
12512
|
-
pid:
|
|
12513
|
-
status:
|
|
12514
|
-
log:
|
|
12732
|
+
pid: path36.join(r, PID_FILE),
|
|
12733
|
+
status: path36.join(r, STATUS_FILE),
|
|
12734
|
+
log: path36.join(r, LOG_FILE)
|
|
12515
12735
|
};
|
|
12516
12736
|
}
|
|
12517
12737
|
function readPid(root) {
|
|
12518
12738
|
try {
|
|
12519
12739
|
const fp = paths(root).pid;
|
|
12520
|
-
if (!
|
|
12521
|
-
const pid = Number(
|
|
12740
|
+
if (!fs33.existsSync(fp)) return null;
|
|
12741
|
+
const pid = Number(fs33.readFileSync(fp, "utf-8").trim());
|
|
12522
12742
|
return Number.isFinite(pid) && pid > 0 ? pid : null;
|
|
12523
12743
|
} catch {
|
|
12524
12744
|
return null;
|
|
@@ -12536,6 +12756,12 @@ async function daemonTick(root) {
|
|
|
12536
12756
|
const r = root || getProjectRoot();
|
|
12537
12757
|
const p = paths(r);
|
|
12538
12758
|
const notes = [];
|
|
12759
|
+
try {
|
|
12760
|
+
const { ensureBackbone: ensureBackbone2, formatBackbone: formatBackbone2 } = await Promise.resolve().then(() => (init_mapBackbone(), mapBackbone_exports));
|
|
12761
|
+
const bb = await ensureBackbone2();
|
|
12762
|
+
if (bb) notes.push(formatBackbone2(bb));
|
|
12763
|
+
} catch {
|
|
12764
|
+
}
|
|
12539
12765
|
try {
|
|
12540
12766
|
const { syncModifiedFiles: syncModifiedFiles2 } = await Promise.resolve().then(() => (init_kumaCodeScanner(), kumaCodeScanner_exports));
|
|
12541
12767
|
const scan = await syncModifiedFiles2(50);
|
|
@@ -12569,8 +12795,8 @@ async function daemonTick(root) {
|
|
|
12569
12795
|
};
|
|
12570
12796
|
try {
|
|
12571
12797
|
let prev = {};
|
|
12572
|
-
if (
|
|
12573
|
-
|
|
12798
|
+
if (fs33.existsSync(p.status)) prev = JSON.parse(fs33.readFileSync(p.status, "utf-8"));
|
|
12799
|
+
fs33.writeFileSync(p.status, JSON.stringify({ ...prev, ...status }, null, 2), "utf-8");
|
|
12574
12800
|
} catch {
|
|
12575
12801
|
}
|
|
12576
12802
|
return notes.join(" \xB7 ");
|
|
@@ -12580,7 +12806,7 @@ async function runLoop(intervalMs) {
|
|
|
12580
12806
|
const p = paths(r);
|
|
12581
12807
|
const log = (msg) => {
|
|
12582
12808
|
try {
|
|
12583
|
-
|
|
12809
|
+
fs33.appendFileSync(p.log, `${(/* @__PURE__ */ new Date()).toISOString()} ${msg}
|
|
12584
12810
|
`, "utf-8");
|
|
12585
12811
|
} catch {
|
|
12586
12812
|
}
|
|
@@ -12611,8 +12837,8 @@ async function daemonStart(intervalMs = DEFAULT_INTERVAL_MS, root) {
|
|
|
12611
12837
|
});
|
|
12612
12838
|
child.unref();
|
|
12613
12839
|
try {
|
|
12614
|
-
|
|
12615
|
-
|
|
12840
|
+
fs33.writeFileSync(p.pid, String(child.pid), "utf-8");
|
|
12841
|
+
fs33.writeFileSync(
|
|
12616
12842
|
p.status,
|
|
12617
12843
|
JSON.stringify({ running: true, pid: child.pid, startedAt: Date.now(), lastRunAt: null, lastResult: null, intervalMs }, null, 2),
|
|
12618
12844
|
"utf-8"
|
|
@@ -12628,7 +12854,7 @@ async function daemonStop(root) {
|
|
|
12628
12854
|
if (!pid) return "\u{1F43B} Daemon not running (no pid file).";
|
|
12629
12855
|
if (!isAlive(pid)) {
|
|
12630
12856
|
try {
|
|
12631
|
-
|
|
12857
|
+
fs33.rmSync(p.pid, { force: true });
|
|
12632
12858
|
} catch {
|
|
12633
12859
|
}
|
|
12634
12860
|
return "\u{1F43B} Daemon pid file was stale \u2014 cleaned up (process already gone).";
|
|
@@ -12636,7 +12862,7 @@ async function daemonStop(root) {
|
|
|
12636
12862
|
try {
|
|
12637
12863
|
process.kill(pid, "SIGTERM");
|
|
12638
12864
|
try {
|
|
12639
|
-
|
|
12865
|
+
fs33.rmSync(p.pid, { force: true });
|
|
12640
12866
|
} catch {
|
|
12641
12867
|
}
|
|
12642
12868
|
return `\u{1F43B} Daemon stopped (was pid ${pid}).`;
|
|
@@ -12650,7 +12876,7 @@ async function daemonStatus(root) {
|
|
|
12650
12876
|
const pid = readPid(r);
|
|
12651
12877
|
let status = { running: false, pid: null, startedAt: null, lastRunAt: null, lastResult: null, intervalMs: DEFAULT_INTERVAL_MS };
|
|
12652
12878
|
try {
|
|
12653
|
-
if (
|
|
12879
|
+
if (fs33.existsSync(p.status)) status = { ...status, ...JSON.parse(fs33.readFileSync(p.status, "utf-8")) };
|
|
12654
12880
|
} catch {
|
|
12655
12881
|
}
|
|
12656
12882
|
const alive = pid !== null && isAlive(pid);
|
|
@@ -12685,19 +12911,19 @@ __export(agentDetector_exports, {
|
|
|
12685
12911
|
getSkillPath: () => getSkillPath,
|
|
12686
12912
|
skillExists: () => skillExists
|
|
12687
12913
|
});
|
|
12688
|
-
import
|
|
12689
|
-
import
|
|
12914
|
+
import fs34 from "fs";
|
|
12915
|
+
import path37 from "path";
|
|
12690
12916
|
function checkFile(root, filePath) {
|
|
12691
12917
|
try {
|
|
12692
|
-
return
|
|
12918
|
+
return fs34.existsSync(path37.join(root, filePath));
|
|
12693
12919
|
} catch {
|
|
12694
12920
|
return false;
|
|
12695
12921
|
}
|
|
12696
12922
|
}
|
|
12697
12923
|
function checkDir(root, dirPath) {
|
|
12698
12924
|
try {
|
|
12699
|
-
const fullPath =
|
|
12700
|
-
return
|
|
12925
|
+
const fullPath = path37.join(root, dirPath);
|
|
12926
|
+
return fs34.existsSync(fullPath) && fs34.statSync(fullPath).isDirectory();
|
|
12701
12927
|
} catch {
|
|
12702
12928
|
return false;
|
|
12703
12929
|
}
|
|
@@ -12765,7 +12991,7 @@ function getAgentLabel(type) {
|
|
|
12765
12991
|
function skillExists(type, projectRoot) {
|
|
12766
12992
|
const root = projectRoot ?? getProjectRoot();
|
|
12767
12993
|
const skillPath = getSkillPath(type);
|
|
12768
|
-
return
|
|
12994
|
+
return fs34.existsSync(path37.join(root, skillPath));
|
|
12769
12995
|
}
|
|
12770
12996
|
var AGENT_DETECTORS;
|
|
12771
12997
|
var init_agentDetector = __esm({
|
|
@@ -13361,8 +13587,8 @@ init_kumaGraph();
|
|
|
13361
13587
|
init_kumaMemory();
|
|
13362
13588
|
init_kumaDriftDetector();
|
|
13363
13589
|
init_pathValidator();
|
|
13364
|
-
import
|
|
13365
|
-
import
|
|
13590
|
+
import fs23 from "fs";
|
|
13591
|
+
import path26 from "path";
|
|
13366
13592
|
var CONTEXT_ALIASES = {
|
|
13367
13593
|
"research": "research",
|
|
13368
13594
|
"search": "research",
|
|
@@ -13481,6 +13707,15 @@ async function handleCluster(_params) {
|
|
|
13481
13707
|
async function handleInit(_params) {
|
|
13482
13708
|
sessionMemory.setGoal(_params.goal || "Exploring project");
|
|
13483
13709
|
sessionMemory.recordToolCall("kuma_context_init", {});
|
|
13710
|
+
let backboneNote = "";
|
|
13711
|
+
try {
|
|
13712
|
+
const { ensureBackbone: ensureBackbone2, formatBackbone: formatBackbone2 } = await Promise.resolve().then(() => (init_mapBackbone(), mapBackbone_exports));
|
|
13713
|
+
const bb = await ensureBackbone2();
|
|
13714
|
+
if (bb) backboneNote = `
|
|
13715
|
+
${formatBackbone2(bb)}
|
|
13716
|
+
`;
|
|
13717
|
+
} catch {
|
|
13718
|
+
}
|
|
13484
13719
|
const branch = sessionMemory.getCurrentBranch();
|
|
13485
13720
|
const branchTag = branch ? ` [git: \`${branch}\`]` : "";
|
|
13486
13721
|
const lines = [
|
|
@@ -13490,6 +13725,7 @@ async function handleInit(_params) {
|
|
|
13490
13725
|
`\u{1F4C1} Project: ${getProjectRoot().split("/").pop() || "unknown"}${branchTag}`,
|
|
13491
13726
|
""
|
|
13492
13727
|
];
|
|
13728
|
+
if (backboneNote) lines.push(backboneNote);
|
|
13493
13729
|
const branchTransition = sessionMemory.getBranchTransition();
|
|
13494
13730
|
if (branchTransition?.switched) {
|
|
13495
13731
|
lines.push(`\u{1F500} **Branch switched**: from \`${branchTransition.from}\` to \`${branchTransition.to}\`. Session context updated.`);
|
|
@@ -13689,6 +13925,14 @@ async function handleResearch(params, dirtySynced = 0) {
|
|
|
13689
13925
|
} else lines.push(" \u23F3 No content hash available \u2014 will research fresh");
|
|
13690
13926
|
lines.push("");
|
|
13691
13927
|
lines.push("**Step 3/5: Graph Query + Code Scan**");
|
|
13928
|
+
try {
|
|
13929
|
+
if (params.scope && (params.scope.includes("/") || params.scope.includes("."))) {
|
|
13930
|
+
const { ensureMapped: ensureMapped2 } = await Promise.resolve().then(() => (init_mapBackbone(), mapBackbone_exports));
|
|
13931
|
+
const { filled } = await ensureMapped2([params.scope]);
|
|
13932
|
+
if (filled > 0) lines.push(` \u{1F5FA}\uFE0F Precision tier filled on demand: ${filled} file(s) indexed (no user action needed)`);
|
|
13933
|
+
}
|
|
13934
|
+
} catch {
|
|
13935
|
+
}
|
|
13692
13936
|
try {
|
|
13693
13937
|
const graphResult = await searchGraph(scope, 15);
|
|
13694
13938
|
const graphLines = graphResult.split("\n");
|
|
@@ -13814,7 +14058,7 @@ ${gitHistory}`);
|
|
|
13814
14058
|
try {
|
|
13815
14059
|
const { getDb: getDb2 } = await Promise.resolve().then(() => (init_kumaDb(), kumaDb_exports));
|
|
13816
14060
|
const db = await getDb2();
|
|
13817
|
-
const base =
|
|
14061
|
+
const base = path26.basename(target);
|
|
13818
14062
|
const stmt = db.prepare(`
|
|
13819
14063
|
SELECT description, last_verified_at FROM known_gotchas
|
|
13820
14064
|
WHERE status = 'resolved' AND (file_path LIKE ? OR file_path LIKE ?)
|
|
@@ -13827,9 +14071,9 @@ ${gitHistory}`);
|
|
|
13827
14071
|
if (resolved.length === 0) {
|
|
13828
14072
|
try {
|
|
13829
14073
|
const { getProjectRoot: getProjectRoot2 } = await Promise.resolve().then(() => (init_pathValidator(), pathValidator_exports));
|
|
13830
|
-
const mdPath =
|
|
13831
|
-
if (
|
|
13832
|
-
const mdContent =
|
|
14074
|
+
const mdPath = path26.join(getProjectRoot2(), ".kuma", "KNOWN_GOTCHAS.md");
|
|
14075
|
+
if (fs23.existsSync(mdPath)) {
|
|
14076
|
+
const mdContent = fs23.readFileSync(mdPath, "utf-8");
|
|
13833
14077
|
const sections = mdContent.split(/^###\s+/m);
|
|
13834
14078
|
for (const sec of sections) {
|
|
13835
14079
|
const secLower = sec.toLowerCase();
|
|
@@ -13901,8 +14145,8 @@ init_kumaDb();
|
|
|
13901
14145
|
init_kumaMemory();
|
|
13902
14146
|
init_pathValidator();
|
|
13903
14147
|
init_pathValidator();
|
|
13904
|
-
import
|
|
13905
|
-
import
|
|
14148
|
+
import fs25 from "fs";
|
|
14149
|
+
import path28 from "path";
|
|
13906
14150
|
var MEMORY_ALIASES = {
|
|
13907
14151
|
"decision": "decision",
|
|
13908
14152
|
"adr": "decision",
|
|
@@ -14013,9 +14257,9 @@ async function handleResearchSave(params) {
|
|
|
14013
14257
|
} catch {
|
|
14014
14258
|
}
|
|
14015
14259
|
try {
|
|
14016
|
-
const researchDir =
|
|
14017
|
-
if (!
|
|
14018
|
-
|
|
14260
|
+
const researchDir = path28.join(getProjectRoot(), ".kuma", "research");
|
|
14261
|
+
if (!fs25.existsSync(researchDir)) fs25.mkdirSync(researchDir, { recursive: true });
|
|
14262
|
+
fs25.writeFileSync(path28.join(researchDir, `${scope}.json`), JSON.stringify(JSON.parse(record), null, 2), "utf-8");
|
|
14019
14263
|
} catch {
|
|
14020
14264
|
}
|
|
14021
14265
|
sessionMemory.recordMemoryAction("research_save");
|
|
@@ -14211,8 +14455,8 @@ init_sessionMemory();
|
|
|
14211
14455
|
init_pathValidator();
|
|
14212
14456
|
init_sessionMemory();
|
|
14213
14457
|
init_kumaShared();
|
|
14214
|
-
import
|
|
14215
|
-
import
|
|
14458
|
+
import fs26 from "fs";
|
|
14459
|
+
import path29 from "path";
|
|
14216
14460
|
import { execSync as execSync7 } from "child_process";
|
|
14217
14461
|
var SCRIPT_PATCH_PATTERNS = [
|
|
14218
14462
|
"writeFileSync",
|
|
@@ -14239,20 +14483,20 @@ function findPatchScripts(projectRoot) {
|
|
|
14239
14483
|
const warnings = [];
|
|
14240
14484
|
const recentFiles = scanRecentFiles(projectRoot);
|
|
14241
14485
|
for (const file of recentFiles) {
|
|
14242
|
-
const ext =
|
|
14486
|
+
const ext = path29.extname(file).toLowerCase();
|
|
14243
14487
|
if (!SCRIPT_EXTENSIONS.includes(ext)) continue;
|
|
14244
|
-
const relativePath =
|
|
14488
|
+
const relativePath = path29.relative(projectRoot, file);
|
|
14245
14489
|
if (relativePath.startsWith("src") || relativePath.startsWith("test") || relativePath.startsWith("node_modules") || relativePath.startsWith(".") || relativePath.startsWith(".kuma/scratch")) {
|
|
14246
14490
|
continue;
|
|
14247
14491
|
}
|
|
14248
14492
|
try {
|
|
14249
|
-
const content =
|
|
14493
|
+
const content = fs26.readFileSync(file, "utf-8").toLowerCase();
|
|
14250
14494
|
const matchedPattern = SCRIPT_PATCH_PATTERNS.find((p) => content.includes(p.toLowerCase()));
|
|
14251
14495
|
if (matchedPattern) {
|
|
14252
14496
|
warnings.push({
|
|
14253
14497
|
severity: "high",
|
|
14254
14498
|
pattern: "script-patching",
|
|
14255
|
-
message: `Created script file that modifies other files: ${
|
|
14499
|
+
message: `Created script file that modifies other files: ${path29.basename(file)}`,
|
|
14256
14500
|
suggestion: "Use your native edit tools instead \u2014 targeted edits with auto-backup and rollback",
|
|
14257
14501
|
evidence: `File: ${relativePath} contains '${matchedPattern}'`,
|
|
14258
14502
|
filePath: relativePath
|
|
@@ -14286,15 +14530,15 @@ function detectBashGrepUsage() {
|
|
|
14286
14530
|
function scanRecentFiles(projectRoot) {
|
|
14287
14531
|
const recent = [];
|
|
14288
14532
|
try {
|
|
14289
|
-
const entries =
|
|
14533
|
+
const entries = fs26.readdirSync(projectRoot, { withFileTypes: true });
|
|
14290
14534
|
const now = Date.now();
|
|
14291
14535
|
const recentThreshold = 30 * 60 * 1e3;
|
|
14292
14536
|
for (const entry of entries) {
|
|
14293
14537
|
if (!entry.isFile()) continue;
|
|
14294
14538
|
try {
|
|
14295
|
-
const stat =
|
|
14539
|
+
const stat = fs26.statSync(path29.join(projectRoot, entry.name));
|
|
14296
14540
|
if (now - stat.mtimeMs < recentThreshold || now - stat.ctimeMs < recentThreshold) {
|
|
14297
|
-
recent.push(
|
|
14541
|
+
recent.push(path29.join(projectRoot, entry.name));
|
|
14298
14542
|
}
|
|
14299
14543
|
} catch {
|
|
14300
14544
|
continue;
|
|
@@ -14318,14 +14562,14 @@ function detectGitPatchScripts(projectRoot) {
|
|
|
14318
14562
|
const prefix = line.substring(0, 2);
|
|
14319
14563
|
if (prefix !== "??" && prefix !== "A ") continue;
|
|
14320
14564
|
const file = line.substring(3).trim();
|
|
14321
|
-
const ext =
|
|
14565
|
+
const ext = path29.extname(file).toLowerCase();
|
|
14322
14566
|
if (!SCRIPT_EXTENSIONS.includes(ext)) continue;
|
|
14323
14567
|
const isRootLevel = !file.includes("/");
|
|
14324
14568
|
const isScriptsDir = file.startsWith("scripts/") || file.startsWith("patches/");
|
|
14325
14569
|
if (!isRootLevel && !isScriptsDir) continue;
|
|
14326
|
-
const fullPath =
|
|
14327
|
-
if (
|
|
14328
|
-
const content =
|
|
14570
|
+
const fullPath = path29.join(projectRoot, file);
|
|
14571
|
+
if (fs26.existsSync(fullPath)) {
|
|
14572
|
+
const content = fs26.readFileSync(fullPath, "utf-8").toLowerCase();
|
|
14329
14573
|
const matchedPattern = SCRIPT_PATCH_PATTERNS.find((p) => content.includes(p.toLowerCase()));
|
|
14330
14574
|
if (matchedPattern) {
|
|
14331
14575
|
warnings.push({
|
|
@@ -14348,7 +14592,7 @@ function detectGitPatchScripts(projectRoot) {
|
|
|
14348
14592
|
if (deletedStdout) {
|
|
14349
14593
|
const deletedFiles = deletedStdout.split("\n").filter(Boolean);
|
|
14350
14594
|
for (const file of deletedFiles) {
|
|
14351
|
-
const ext =
|
|
14595
|
+
const ext = path29.extname(file).toLowerCase();
|
|
14352
14596
|
if (SCRIPT_EXTENSIONS.includes(ext)) {
|
|
14353
14597
|
warnings.push({
|
|
14354
14598
|
severity: "high",
|
|
@@ -14410,21 +14654,21 @@ function detectAllAntiPatterns() {
|
|
|
14410
14654
|
// src/engine/contextSnapshot.ts
|
|
14411
14655
|
init_sessionMemory();
|
|
14412
14656
|
init_pathValidator();
|
|
14413
|
-
import
|
|
14414
|
-
import
|
|
14657
|
+
import fs27 from "fs";
|
|
14658
|
+
import path30 from "path";
|
|
14415
14659
|
import { execSync as execSync8 } from "child_process";
|
|
14416
14660
|
var SNAPSHOT_DIR = "context-snapshots";
|
|
14417
14661
|
function snapshotDir() {
|
|
14418
|
-
return
|
|
14662
|
+
return path30.join(getProjectRoot(), ".kuma", SNAPSHOT_DIR);
|
|
14419
14663
|
}
|
|
14420
14664
|
function ensureSnapshotDir() {
|
|
14421
14665
|
const dir = snapshotDir();
|
|
14422
|
-
if (!
|
|
14423
|
-
|
|
14666
|
+
if (!fs27.existsSync(dir)) {
|
|
14667
|
+
fs27.mkdirSync(dir, { recursive: true });
|
|
14424
14668
|
}
|
|
14425
14669
|
}
|
|
14426
14670
|
function snapshotFilePath(timestamp) {
|
|
14427
|
-
return
|
|
14671
|
+
return path30.join(snapshotDir(), `${timestamp}.json`);
|
|
14428
14672
|
}
|
|
14429
14673
|
function saveSnapshot(goal) {
|
|
14430
14674
|
try {
|
|
@@ -14445,7 +14689,7 @@ function saveSnapshot(goal) {
|
|
|
14445
14689
|
hasConventions: !!summary.hasConventions
|
|
14446
14690
|
};
|
|
14447
14691
|
try {
|
|
14448
|
-
|
|
14692
|
+
fs27.writeFileSync(snapshotFilePath(Date.now()), JSON.stringify(snapshot, null, 2), "utf-8");
|
|
14449
14693
|
} catch {
|
|
14450
14694
|
}
|
|
14451
14695
|
sessionMemory.recordToolCall("kuma_context", { action: "save", goal: snapshot.goal });
|
|
@@ -15238,14 +15482,14 @@ async function main() {
|
|
|
15238
15482
|
console.error("");
|
|
15239
15483
|
let killedCount = 0;
|
|
15240
15484
|
try {
|
|
15241
|
-
const
|
|
15242
|
-
const
|
|
15243
|
-
const lockDir =
|
|
15244
|
-
if (
|
|
15245
|
-
const pidFile =
|
|
15246
|
-
if (
|
|
15485
|
+
const path38 = await import("path");
|
|
15486
|
+
const fs35 = await import("fs");
|
|
15487
|
+
const lockDir = path38.resolve(process.cwd(), ".kuma/verifier.lock");
|
|
15488
|
+
if (fs35.existsSync(lockDir)) {
|
|
15489
|
+
const pidFile = path38.join(lockDir, "pid");
|
|
15490
|
+
if (fs35.existsSync(pidFile)) {
|
|
15247
15491
|
try {
|
|
15248
|
-
const pid = parseInt(
|
|
15492
|
+
const pid = parseInt(fs35.readFileSync(pidFile, "utf-8"), 10);
|
|
15249
15493
|
if (pid && pid !== process.pid) {
|
|
15250
15494
|
try {
|
|
15251
15495
|
process.kill(-pid, "SIGKILL");
|
|
@@ -15261,7 +15505,7 @@ async function main() {
|
|
|
15261
15505
|
} catch {
|
|
15262
15506
|
}
|
|
15263
15507
|
}
|
|
15264
|
-
|
|
15508
|
+
fs35.rmSync(lockDir, { recursive: true, force: true });
|
|
15265
15509
|
}
|
|
15266
15510
|
if (killedCount === 0) {
|
|
15267
15511
|
console.error("\u2705 No running verifications found to kill.");
|
|
@@ -15506,6 +15750,12 @@ ${line}
|
|
|
15506
15750
|
const root = getProjectRoot2();
|
|
15507
15751
|
const proj = root.split("/").pop() || "unknown";
|
|
15508
15752
|
const lines = [`\u{1F43B} [Kuma session brief] ${proj}`];
|
|
15753
|
+
try {
|
|
15754
|
+
const { ensureBackbone: ensureBackbone2, formatBackbone: formatBackbone2 } = await Promise.resolve().then(() => (init_mapBackbone(), mapBackbone_exports));
|
|
15755
|
+
const bb = await ensureBackbone2();
|
|
15756
|
+
if (bb) lines.push(formatBackbone2(bb));
|
|
15757
|
+
} catch {
|
|
15758
|
+
}
|
|
15509
15759
|
try {
|
|
15510
15760
|
const { execSync: execSync10 } = await import("child_process");
|
|
15511
15761
|
const branch = execSync10("git rev-parse --abbrev-ref HEAD", {
|
|
@@ -15626,23 +15876,23 @@ ${line}
|
|
|
15626
15876
|
});
|
|
15627
15877
|
const output = formatInitResults(results);
|
|
15628
15878
|
console.log(output);
|
|
15629
|
-
const
|
|
15630
|
-
const
|
|
15631
|
-
const matchaSkills =
|
|
15632
|
-
const matchaAgents =
|
|
15879
|
+
const fs35 = await import("fs");
|
|
15880
|
+
const path38 = await import("path");
|
|
15881
|
+
const matchaSkills = path38.resolve(process.cwd(), "skills/matcha/SKILL.md");
|
|
15882
|
+
const matchaAgents = path38.resolve(
|
|
15633
15883
|
process.cwd(),
|
|
15634
15884
|
".agents/skills/matcha/SKILL.md"
|
|
15635
15885
|
);
|
|
15636
|
-
const matchaRootSkills =
|
|
15886
|
+
const matchaRootSkills = path38.resolve(
|
|
15637
15887
|
process.cwd(),
|
|
15638
15888
|
"skills/matcha/SKILL.md"
|
|
15639
15889
|
);
|
|
15640
|
-
const matchaAgentsMd =
|
|
15641
|
-
const matchaWindsurfRules =
|
|
15890
|
+
const matchaAgentsMd = path38.resolve(process.cwd(), "AGENTS.md");
|
|
15891
|
+
const matchaWindsurfRules = path38.resolve(
|
|
15642
15892
|
process.cwd(),
|
|
15643
15893
|
".windsurf"
|
|
15644
15894
|
);
|
|
15645
|
-
if (
|
|
15895
|
+
if (fs35.existsSync(matchaSkills) || fs35.existsSync(matchaAgents) || fs35.existsSync(matchaRootSkills) || fs35.existsSync(matchaAgentsMd) || fs35.existsSync(matchaWindsurfRules)) {
|
|
15646
15896
|
console.error(
|
|
15647
15897
|
"\n\u{1F375} Hey, I see matcha is installed \u2014 they pair well together!"
|
|
15648
15898
|
);
|
|
@@ -15656,13 +15906,13 @@ ${line}
|
|
|
15656
15906
|
(async () => {
|
|
15657
15907
|
try {
|
|
15658
15908
|
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
|
-
|
|
15909
|
+
const fs35 = await import("fs");
|
|
15910
|
+
const path38 = await import("path");
|
|
15911
|
+
const initMdPath = path38.resolve(process.cwd(), ".kuma/init.md");
|
|
15912
|
+
if (!fs35.existsSync(initMdPath)) {
|
|
15913
|
+
const kumaDir = path38.dirname(initMdPath);
|
|
15914
|
+
if (!fs35.existsSync(kumaDir)) fs35.mkdirSync(kumaDir, { recursive: true });
|
|
15915
|
+
fs35.writeFileSync(initMdPath, generateInitMdContent2(), "utf-8");
|
|
15666
15916
|
console.error(`[${SERVER_NAME}] Auto-generated .kuma/init.md`);
|
|
15667
15917
|
}
|
|
15668
15918
|
} catch (err) {
|
|
@@ -15673,8 +15923,8 @@ ${line}
|
|
|
15673
15923
|
try {
|
|
15674
15924
|
const { detectAgent: detectAgent2, getSkillPath: getSkillPath2, getAgentLabel: getAgentLabel2 } = await Promise.resolve().then(() => (init_agentDetector(), agentDetector_exports));
|
|
15675
15925
|
const { generateSkill: generateSkill2, getSecondaryFiles: getSecondaryFiles2 } = await Promise.resolve().then(() => (init_skillGenerator(), skillGenerator_exports));
|
|
15676
|
-
const
|
|
15677
|
-
const
|
|
15926
|
+
const fs35 = await import("fs");
|
|
15927
|
+
const path38 = await import("path");
|
|
15678
15928
|
const detection = detectAgent2();
|
|
15679
15929
|
if (!detection.primary) {
|
|
15680
15930
|
console.error(`[${SERVER_NAME}] No AI agent detected \u2014 skipping auto-skill creation`);
|
|
@@ -15682,22 +15932,22 @@ ${line}
|
|
|
15682
15932
|
}
|
|
15683
15933
|
const agentType = detection.primary;
|
|
15684
15934
|
const skillPath = getSkillPath2(agentType);
|
|
15685
|
-
const fullPath =
|
|
15686
|
-
if (
|
|
15935
|
+
const fullPath = path38.resolve(process.cwd(), skillPath);
|
|
15936
|
+
if (fs35.existsSync(fullPath)) {
|
|
15687
15937
|
console.error(`[${SERVER_NAME}] Skill exists for ${getAgentLabel2(agentType)} \u2014 skipping`);
|
|
15688
15938
|
return;
|
|
15689
15939
|
}
|
|
15690
|
-
const dir =
|
|
15691
|
-
if (!
|
|
15692
|
-
|
|
15940
|
+
const dir = path38.dirname(fullPath);
|
|
15941
|
+
if (!fs35.existsSync(dir)) fs35.mkdirSync(dir, { recursive: true });
|
|
15942
|
+
fs35.writeFileSync(fullPath, generateSkill2(agentType), "utf-8");
|
|
15693
15943
|
console.error(`[${SERVER_NAME}] Auto-created ${skillPath} for ${getAgentLabel2(agentType)}`);
|
|
15694
15944
|
const secondaryFiles = getSecondaryFiles2(agentType);
|
|
15695
15945
|
for (const sf of secondaryFiles) {
|
|
15696
|
-
const sfPath =
|
|
15697
|
-
const sfDir =
|
|
15698
|
-
if (!
|
|
15699
|
-
if (!
|
|
15700
|
-
|
|
15946
|
+
const sfPath = path38.resolve(process.cwd(), sf.path);
|
|
15947
|
+
const sfDir = path38.dirname(sfPath);
|
|
15948
|
+
if (!fs35.existsSync(sfPath)) {
|
|
15949
|
+
if (!fs35.existsSync(sfDir)) fs35.mkdirSync(sfDir, { recursive: true });
|
|
15950
|
+
fs35.writeFileSync(sfPath, sf.content, "utf-8");
|
|
15701
15951
|
console.error(`[${SERVER_NAME}] Auto-created ${sf.path}`);
|
|
15702
15952
|
}
|
|
15703
15953
|
}
|