@plumpslabs/kuma 2.3.8 → 2.3.9
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/{chunk-NAM7SCBT.js → chunk-3TX6Q37T.js} +26 -1
- package/dist/{chunk-RTGLQDMI.js → chunk-OJALFQ4H.js} +2 -2
- package/dist/{chunk-53J56QCQ.js → chunk-Q2444HWO.js} +1 -1
- package/dist/{chunk-SLRRDKQ2.js → chunk-R6B3VUSB.js} +2 -2
- package/dist/{chunk-PTEPJK6M.js → chunk-RI3DKY62.js} +1 -1
- package/dist/{chunk-FL2TLLMX.js → chunk-SPHI2BOO.js} +1 -1
- package/dist/{chunk-4OB3XMHT.js → chunk-ZKDYTYMS.js} +108 -2
- package/dist/{contextDigest-4PCK3DSM.js → contextDigest-5JXLH56Z.js} +3 -3
- package/dist/{domainRules-LDZPOIGZ.js → domainRules-ED6EOFVY.js} +2 -2
- package/dist/index.js +253 -65
- package/dist/kumaCheckpoint-XIQWRMGV.js +207 -0
- package/dist/kumaCodeScanner-LFJGPJNH.js +566 -0
- package/dist/kumaContractEngine-KX27T4N7.js +305 -0
- package/dist/{kumaDb-6D53ERFP.js → kumaDb-IC7UX7PU.js} +3 -1
- package/dist/{kumaDriftDetector-OESI5GTC.js → kumaDriftDetector-QBY6OJOO.js} +1 -1
- package/dist/{kumaGotchas-DU5H6N7X.js → kumaGotchas-5HODT5RI.js} +3 -3
- package/dist/{kumaGraph-AWP743TJ.js → kumaGraph-GUQM75WL.js} +8 -2
- package/dist/{kumaMemory-7TCUDVZX.js → kumaMemory-FMOWIODH.js} +2 -2
- package/dist/{kumaMiner-FFXSRHAO.js → kumaMiner-3RXEOCBP.js} +3 -3
- package/dist/{kumaPolicyEngine-S2PXN3C7.js → kumaPolicyEngine-ORBWL5PT.js} +2 -2
- package/dist/kumaProgressiveContext-CVSNPY3W.js +231 -0
- package/dist/{kumaSearch-QGB4QVXS.js → kumaSearch-B5WVYHHD.js} +1 -1
- package/dist/kumaTrajectory-T6DXGOG4.js +460 -0
- package/dist/{kumaVerifier-ARSGPZAM.js → kumaVerifier-KAYJHR5K.js} +2 -2
- package/dist/{kumaVisualize-TECABHUY.js → kumaVisualize-AFL7STLL.js} +1 -1
- package/dist/{safetyAudit-55IVCG5B.js → safetyAudit-32WSA4Z5.js} +2 -2
- package/dist/{safetyScore-GR5N55CU.js → safetyScore-WU27EOG4.js} +5 -5
- package/dist/{sessionMemory-CA34TCPF.js → sessionMemory-4UWA3E5J.js} +1 -1
- package/package.json +18 -13
- package/packages/ide/studio/dist/index.js +140 -0
- package/packages/ide/studio/public/index.html +500 -0
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
import {
|
|
2
|
+
sessionMemory
|
|
3
|
+
} from "./chunk-R6B3VUSB.js";
|
|
4
|
+
import {
|
|
5
|
+
getDb,
|
|
6
|
+
resetDbInstance
|
|
7
|
+
} from "./chunk-3TX6Q37T.js";
|
|
8
|
+
import {
|
|
9
|
+
getProjectRoot
|
|
10
|
+
} from "./chunk-E2KFPEBT.js";
|
|
11
|
+
|
|
12
|
+
// src/engine/kumaCheckpoint.ts
|
|
13
|
+
import fs from "fs";
|
|
14
|
+
import path from "path";
|
|
15
|
+
var CHECKPOINT_DIR = ".kuma/checkpoints";
|
|
16
|
+
async function createCheckpoint(label, description) {
|
|
17
|
+
try {
|
|
18
|
+
const root = getProjectRoot();
|
|
19
|
+
const cpDir = path.join(root, CHECKPOINT_DIR, sanitizeLabel(label));
|
|
20
|
+
if (fs.existsSync(cpDir)) {
|
|
21
|
+
return `\u26A0\uFE0F Checkpoint "${label}" already exists. Use a different label or remove it first.`;
|
|
22
|
+
}
|
|
23
|
+
fs.mkdirSync(cpDir, { recursive: true });
|
|
24
|
+
const db = await getDb();
|
|
25
|
+
const filesStmt = db.prepare(
|
|
26
|
+
"SELECT DISTINCT file_path FROM change_log ORDER BY id DESC LIMIT 100"
|
|
27
|
+
);
|
|
28
|
+
const files = [];
|
|
29
|
+
while (filesStmt.step()) {
|
|
30
|
+
const row = filesStmt.getAsObject();
|
|
31
|
+
const fp = row.file_path;
|
|
32
|
+
const fullPath = path.resolve(root, fp);
|
|
33
|
+
if (fs.existsSync(fullPath)) {
|
|
34
|
+
const content = fs.readFileSync(fullPath, "utf-8");
|
|
35
|
+
const hash = simpleHash(content);
|
|
36
|
+
const fileDir = path.dirname(path.join(cpDir, "files", fp));
|
|
37
|
+
if (!fs.existsSync(fileDir)) fs.mkdirSync(fileDir, { recursive: true });
|
|
38
|
+
fs.writeFileSync(path.join(cpDir, "files", fp), content, "utf-8");
|
|
39
|
+
files.push({ path: fp, hash });
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
filesStmt.free();
|
|
43
|
+
const dbData = db.export();
|
|
44
|
+
fs.writeFileSync(path.join(cpDir, "kuma.db"), Buffer.from(dbData));
|
|
45
|
+
const manifest = {
|
|
46
|
+
label,
|
|
47
|
+
timestamp: Date.now(),
|
|
48
|
+
files,
|
|
49
|
+
dbSnapshot: true,
|
|
50
|
+
description
|
|
51
|
+
};
|
|
52
|
+
fs.writeFileSync(
|
|
53
|
+
path.join(cpDir, "manifest.json"),
|
|
54
|
+
JSON.stringify(manifest, null, 2),
|
|
55
|
+
"utf-8"
|
|
56
|
+
);
|
|
57
|
+
sessionMemory.recordToolCall("kuma_checkpoint_create", {
|
|
58
|
+
label,
|
|
59
|
+
filesCount: files.length
|
|
60
|
+
});
|
|
61
|
+
return [
|
|
62
|
+
`\u2705 **Checkpoint Created**: "${label}"`,
|
|
63
|
+
`\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501`,
|
|
64
|
+
``,
|
|
65
|
+
`\u{1F4E6} **${files.length} file(s)** snapshotted`,
|
|
66
|
+
`\u{1F5C4}\uFE0F **Database** snapshotted`,
|
|
67
|
+
`\u{1F4CD} ${cpDir}`,
|
|
68
|
+
``,
|
|
69
|
+
`\u{1F4A1} To restore: kuma_safety({ action: 'rollback', label: '${label}' })`,
|
|
70
|
+
description ? `\u{1F4DD} ${description}` : ""
|
|
71
|
+
].filter(Boolean).join("\n");
|
|
72
|
+
} catch (err) {
|
|
73
|
+
return `\u274C Checkpoint failed: ${err}`;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
async function rollbackToCheckpoint(label) {
|
|
77
|
+
try {
|
|
78
|
+
const root = getProjectRoot();
|
|
79
|
+
const cpDir = path.join(root, CHECKPOINT_DIR, sanitizeLabel(label));
|
|
80
|
+
const manifestPath = path.join(cpDir, "manifest.json");
|
|
81
|
+
if (!fs.existsSync(manifestPath)) {
|
|
82
|
+
return `\u274C Checkpoint "${label}" not found. Use kuma_safety({ action: 'checkpoint_list' }) to see available checkpoints.`;
|
|
83
|
+
}
|
|
84
|
+
const manifest = JSON.parse(
|
|
85
|
+
fs.readFileSync(manifestPath, "utf-8")
|
|
86
|
+
);
|
|
87
|
+
let restored = 0;
|
|
88
|
+
let failed = 0;
|
|
89
|
+
for (const f of manifest.files) {
|
|
90
|
+
const snapshotPath = path.join(cpDir, "files", f.path);
|
|
91
|
+
if (fs.existsSync(snapshotPath)) {
|
|
92
|
+
try {
|
|
93
|
+
const content = fs.readFileSync(snapshotPath, "utf-8");
|
|
94
|
+
const targetPath = path.resolve(root, f.path);
|
|
95
|
+
const targetDir = path.dirname(targetPath);
|
|
96
|
+
if (!fs.existsSync(targetDir)) fs.mkdirSync(targetDir, { recursive: true });
|
|
97
|
+
fs.writeFileSync(targetPath, content, "utf-8");
|
|
98
|
+
restored++;
|
|
99
|
+
} catch {
|
|
100
|
+
failed++;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
const dbSnapshotPath = path.join(cpDir, "kuma.db");
|
|
105
|
+
if (fs.existsSync(dbSnapshotPath)) {
|
|
106
|
+
const kumaDir = path.join(root, ".kuma");
|
|
107
|
+
const dbPath = path.join(kumaDir, "kuma.db");
|
|
108
|
+
const snapshotData = fs.readFileSync(dbSnapshotPath);
|
|
109
|
+
fs.writeFileSync(dbPath, snapshotData);
|
|
110
|
+
resetDbInstance();
|
|
111
|
+
}
|
|
112
|
+
sessionMemory.recordToolCall("kuma_checkpoint_rollback", {
|
|
113
|
+
label,
|
|
114
|
+
restored,
|
|
115
|
+
failed
|
|
116
|
+
});
|
|
117
|
+
return [
|
|
118
|
+
`\u{1F504} **Rollback Complete**: "${label}"`,
|
|
119
|
+
`\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501`,
|
|
120
|
+
``,
|
|
121
|
+
`\u2705 Restored **${restored} file(s)**`,
|
|
122
|
+
failed > 0 ? `\u26A0\uFE0F ${failed} file(s) failed to restore` : "",
|
|
123
|
+
`\u{1F5C4}\uFE0F Database restored to checkpoint state`,
|
|
124
|
+
``,
|
|
125
|
+
`\u{1F4A1} You may need to restart your language server for full effect.`
|
|
126
|
+
].filter(Boolean).join("\n");
|
|
127
|
+
} catch (err) {
|
|
128
|
+
return `\u274C Rollback failed: ${err}`;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
function listCheckpoints() {
|
|
132
|
+
try {
|
|
133
|
+
const root = getProjectRoot();
|
|
134
|
+
const cpDir = path.join(root, CHECKPOINT_DIR);
|
|
135
|
+
if (!fs.existsSync(cpDir)) {
|
|
136
|
+
return "\u{1F4ED} No checkpoints found. Use kuma_safety({ action: 'checkpoint', label: 'pre-feature-x' }) to create one.";
|
|
137
|
+
}
|
|
138
|
+
const entries = fs.readdirSync(cpDir);
|
|
139
|
+
const checkpoints = [];
|
|
140
|
+
for (const entry of entries) {
|
|
141
|
+
const manifestPath = path.join(cpDir, entry, "manifest.json");
|
|
142
|
+
if (fs.existsSync(manifestPath)) {
|
|
143
|
+
try {
|
|
144
|
+
const manifest = JSON.parse(
|
|
145
|
+
fs.readFileSync(manifestPath, "utf-8")
|
|
146
|
+
);
|
|
147
|
+
checkpoints.push({ label: entry, manifest });
|
|
148
|
+
} catch {
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
if (checkpoints.length === 0) {
|
|
153
|
+
return "\u{1F4ED} No valid checkpoints found.";
|
|
154
|
+
}
|
|
155
|
+
const lines = [
|
|
156
|
+
"\u{1F4E6} **Checkpoints**",
|
|
157
|
+
"\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501",
|
|
158
|
+
""
|
|
159
|
+
];
|
|
160
|
+
for (const cp of checkpoints) {
|
|
161
|
+
const time = new Date(cp.manifest.timestamp).toLocaleString();
|
|
162
|
+
lines.push(` \u{1F4CC} **${cp.manifest.label}**`);
|
|
163
|
+
lines.push(` \u{1F550} ${time} | \u{1F4C1} ${cp.manifest.files.length} files | \u{1F4BE} ${cp.manifest.dbSnapshot ? "DB included" : "no DB"}`);
|
|
164
|
+
if (cp.manifest.description) {
|
|
165
|
+
lines.push(` \u{1F4DD} ${cp.manifest.description}`);
|
|
166
|
+
}
|
|
167
|
+
lines.push("");
|
|
168
|
+
}
|
|
169
|
+
return lines.join("\n");
|
|
170
|
+
} catch (err) {
|
|
171
|
+
return `Error: ${err}`;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
function pruneCheckpoints(keep = 5) {
|
|
175
|
+
try {
|
|
176
|
+
const root = getProjectRoot();
|
|
177
|
+
const cpDir = path.join(root, CHECKPOINT_DIR);
|
|
178
|
+
if (!fs.existsSync(cpDir)) return "\u{1F4ED} No checkpoints to prune.";
|
|
179
|
+
const entries = fs.readdirSync(cpDir).map((e) => ({ name: e, time: fs.statSync(path.join(cpDir, e)).mtimeMs })).sort((a, b) => b.time - a.time);
|
|
180
|
+
let removed = 0;
|
|
181
|
+
for (let i = keep; i < entries.length; i++) {
|
|
182
|
+
fs.rmSync(path.join(cpDir, entries[i].name), { recursive: true, force: true });
|
|
183
|
+
removed++;
|
|
184
|
+
}
|
|
185
|
+
return removed > 0 ? `\u{1F9F9} Pruned **${removed} old checkpoint(s)**. Kept ${Math.min(keep, entries.length)} most recent.` : "\u2705 No checkpoints needed pruning.";
|
|
186
|
+
} catch (err) {
|
|
187
|
+
return `Error: ${err}`;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
function sanitizeLabel(label) {
|
|
191
|
+
return label.replace(/[^a-zA-Z0-9_-]/g, "_").substring(0, 64);
|
|
192
|
+
}
|
|
193
|
+
function simpleHash(str) {
|
|
194
|
+
let hash = 0;
|
|
195
|
+
for (let i = 0; i < str.length; i++) {
|
|
196
|
+
const char = str.charCodeAt(i);
|
|
197
|
+
hash = (hash << 5) - hash + char;
|
|
198
|
+
hash = hash & hash;
|
|
199
|
+
}
|
|
200
|
+
return Math.abs(hash).toString(36);
|
|
201
|
+
}
|
|
202
|
+
export {
|
|
203
|
+
createCheckpoint,
|
|
204
|
+
listCheckpoints,
|
|
205
|
+
pruneCheckpoints,
|
|
206
|
+
rollbackToCheckpoint
|
|
207
|
+
};
|