memory-bank-skill 5.5.0 → 5.5.2
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/cli.js +120 -9
- package/dist/plugin.js +52 -18
- package/package.json +4 -1
package/dist/cli.js
CHANGED
|
@@ -7,7 +7,7 @@ import { homedir } from "os";
|
|
|
7
7
|
import { join, dirname } from "path";
|
|
8
8
|
import { createHash } from "crypto";
|
|
9
9
|
import { fileURLToPath } from "url";
|
|
10
|
-
var VERSION = "5.
|
|
10
|
+
var VERSION = "5.5.2";
|
|
11
11
|
var colors = {
|
|
12
12
|
reset: "\x1B[0m",
|
|
13
13
|
bold: "\x1B[1m",
|
|
@@ -148,7 +148,8 @@ async function installSkillFiles(packageRoot, undoStack, manifestFiles) {
|
|
|
148
148
|
}
|
|
149
149
|
async function installPluginToConfig(undoStack) {
|
|
150
150
|
const configPath = join(homedir(), ".config", "opencode", "opencode.json");
|
|
151
|
-
const
|
|
151
|
+
const pluginPackageWithVersion = `memory-bank-skill@${VERSION}`;
|
|
152
|
+
const pluginPackagePrefix = "memory-bank-skill";
|
|
152
153
|
let config = {};
|
|
153
154
|
let existed = false;
|
|
154
155
|
let modified = false;
|
|
@@ -165,7 +166,7 @@ async function installPluginToConfig(undoStack) {
|
|
|
165
166
|
|
|
166
167
|
` + JSON.stringify({
|
|
167
168
|
permission: { skill: "allow" },
|
|
168
|
-
plugin: [
|
|
169
|
+
plugin: [pluginPackageWithVersion]
|
|
169
170
|
}, null, 2));
|
|
170
171
|
}
|
|
171
172
|
}
|
|
@@ -187,9 +188,30 @@ async function installPluginToConfig(undoStack) {
|
|
|
187
188
|
changes.push("Removed old file:// plugin reference");
|
|
188
189
|
modified = true;
|
|
189
190
|
}
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
191
|
+
const matchingIndices = [];
|
|
192
|
+
config.plugin.forEach((p, i) => {
|
|
193
|
+
if (p === pluginPackagePrefix || p.startsWith(`${pluginPackagePrefix}@`)) {
|
|
194
|
+
matchingIndices.push(i);
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
if (matchingIndices.length > 1) {
|
|
198
|
+
for (let i = matchingIndices.length - 1;i > 0; i--) {
|
|
199
|
+
const removed = config.plugin.splice(matchingIndices[i], 1)[0];
|
|
200
|
+
changes.push(`Removed duplicate: ${removed}`);
|
|
201
|
+
}
|
|
202
|
+
modified = true;
|
|
203
|
+
}
|
|
204
|
+
const existingIndex = config.plugin.findIndex((p) => p === pluginPackagePrefix || p.startsWith(`${pluginPackagePrefix}@`));
|
|
205
|
+
if (existingIndex !== -1) {
|
|
206
|
+
const existing = config.plugin[existingIndex];
|
|
207
|
+
if (existing !== pluginPackageWithVersion) {
|
|
208
|
+
config.plugin[existingIndex] = pluginPackageWithVersion;
|
|
209
|
+
changes.push(`Updated plugin: ${existing} \u2192 ${pluginPackageWithVersion}`);
|
|
210
|
+
modified = true;
|
|
211
|
+
}
|
|
212
|
+
} else {
|
|
213
|
+
config.plugin.push(pluginPackageWithVersion);
|
|
214
|
+
changes.push(`Added plugin: ${pluginPackageWithVersion}`);
|
|
193
215
|
modified = true;
|
|
194
216
|
}
|
|
195
217
|
if (modified) {
|
|
@@ -213,6 +235,60 @@ async function writeManifest(manifestFiles, undoStack) {
|
|
|
213
235
|
await atomicWriteFile(manifestPath, JSON.stringify(manifest, null, 2) + `
|
|
214
236
|
`, undoStack);
|
|
215
237
|
}
|
|
238
|
+
async function checkAndCleanOpenCodeCache() {
|
|
239
|
+
const cacheDir = join(homedir(), ".cache", "opencode");
|
|
240
|
+
const cachePackageJson = join(cacheDir, "package.json");
|
|
241
|
+
const pkgCacheDir = join(cacheDir, "node_modules", "memory-bank-skill");
|
|
242
|
+
const cacheNodeModulesPkg = join(pkgCacheDir, "package.json");
|
|
243
|
+
if (!await exists(cachePackageJson)) {
|
|
244
|
+
return { cleaned: false };
|
|
245
|
+
}
|
|
246
|
+
try {
|
|
247
|
+
const cacheDepContent = await fs.readFile(cachePackageJson, "utf-8");
|
|
248
|
+
const cacheDep = JSON.parse(cacheDepContent);
|
|
249
|
+
const recordedVersion = cacheDep.dependencies?.["memory-bank-skill"];
|
|
250
|
+
if (!recordedVersion) {
|
|
251
|
+
return { cleaned: false };
|
|
252
|
+
}
|
|
253
|
+
let actualVersion = null;
|
|
254
|
+
if (await exists(cacheNodeModulesPkg)) {
|
|
255
|
+
try {
|
|
256
|
+
const actualPkg = JSON.parse(await fs.readFile(cacheNodeModulesPkg, "utf-8"));
|
|
257
|
+
actualVersion = actualPkg.version;
|
|
258
|
+
} catch {}
|
|
259
|
+
}
|
|
260
|
+
const needsClean = recordedVersion === "latest" || recordedVersion !== VERSION || actualVersion && actualVersion !== VERSION;
|
|
261
|
+
if (needsClean) {
|
|
262
|
+
const realCacheDir = await fs.realpath(cacheDir).catch(() => null);
|
|
263
|
+
const expectedPrefix = join(homedir(), ".cache", "opencode");
|
|
264
|
+
if (!realCacheDir || !realCacheDir.startsWith(expectedPrefix)) {
|
|
265
|
+
return { cleaned: false };
|
|
266
|
+
}
|
|
267
|
+
if (await exists(pkgCacheDir)) {
|
|
268
|
+
await fs.rm(pkgCacheDir, { recursive: true, force: true });
|
|
269
|
+
}
|
|
270
|
+
const bunLockb = join(cacheDir, "bun.lockb");
|
|
271
|
+
if (await exists(bunLockb)) {
|
|
272
|
+
await fs.rm(bunLockb, { force: true });
|
|
273
|
+
}
|
|
274
|
+
const newDeps = { ...cacheDep.dependencies };
|
|
275
|
+
delete newDeps["memory-bank-skill"];
|
|
276
|
+
cacheDep.dependencies = newDeps;
|
|
277
|
+
const tmpPath = `${cachePackageJson}.tmp`;
|
|
278
|
+
await fs.writeFile(tmpPath, JSON.stringify(cacheDep, null, 2) + `
|
|
279
|
+
`);
|
|
280
|
+
await fs.rename(tmpPath, cachePackageJson);
|
|
281
|
+
const reason = recordedVersion === "latest" ? `"latest" \u2192 ${VERSION}` : `${recordedVersion} \u2192 ${VERSION}`;
|
|
282
|
+
return {
|
|
283
|
+
cleaned: true,
|
|
284
|
+
message: `Cleaned stale OpenCode cache (${reason})`
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
} catch {
|
|
288
|
+
return { cleaned: false };
|
|
289
|
+
}
|
|
290
|
+
return { cleaned: false };
|
|
291
|
+
}
|
|
216
292
|
async function install() {
|
|
217
293
|
log(`
|
|
218
294
|
${colors.bold}Memory Bank Skill Installer v${VERSION}${colors.reset}
|
|
@@ -222,6 +298,11 @@ ${colors.bold}Memory Bank Skill Installer v${VERSION}${colors.reset}
|
|
|
222
298
|
const manifestFiles = [];
|
|
223
299
|
const results = [];
|
|
224
300
|
try {
|
|
301
|
+
const cacheResult = await checkAndCleanOpenCodeCache();
|
|
302
|
+
if (cacheResult.cleaned) {
|
|
303
|
+
logSuccess(cacheResult.message || "Cleaned OpenCode cache");
|
|
304
|
+
log("");
|
|
305
|
+
}
|
|
225
306
|
logStep(1, 2, "Installing skill files...");
|
|
226
307
|
const r1 = await installSkillFiles(packageRoot, undoStack, manifestFiles);
|
|
227
308
|
logDetail(r1.details || "");
|
|
@@ -267,21 +348,51 @@ ${colors.bold}Memory Bank Skill Doctor v${VERSION}${colors.reset}
|
|
|
267
348
|
}
|
|
268
349
|
const configPath = join(homedir(), ".config", "opencode", "opencode.json");
|
|
269
350
|
let pluginConfigured = false;
|
|
351
|
+
let pluginVersion = "";
|
|
270
352
|
if (await exists(configPath)) {
|
|
271
353
|
try {
|
|
272
354
|
const content = await fs.readFile(configPath, "utf-8");
|
|
273
355
|
const config = JSON.parse(content);
|
|
274
|
-
|
|
356
|
+
if (Array.isArray(config.plugin)) {
|
|
357
|
+
const entry = config.plugin.find((p) => p === "memory-bank-skill" || p.startsWith("memory-bank-skill@"));
|
|
358
|
+
if (entry) {
|
|
359
|
+
pluginConfigured = true;
|
|
360
|
+
pluginVersion = entry;
|
|
361
|
+
}
|
|
362
|
+
}
|
|
275
363
|
} catch {}
|
|
276
364
|
}
|
|
277
365
|
if (pluginConfigured) {
|
|
278
366
|
log(`${colors.green}\u2713${colors.reset} Plugin configured in opencode.json`);
|
|
279
|
-
logDetail(
|
|
367
|
+
logDetail(pluginVersion);
|
|
368
|
+
if (!pluginVersion.includes("@")) {
|
|
369
|
+
log(`${colors.yellow}\u26A0${colors.reset} Consider using pinned version: memory-bank-skill@${VERSION}`);
|
|
370
|
+
}
|
|
280
371
|
} else {
|
|
281
372
|
log(`${colors.red}\u2717${colors.reset} Plugin not configured`);
|
|
282
|
-
logDetail(
|
|
373
|
+
logDetail(`Add 'memory-bank-skill@${VERSION}' to plugin array in opencode.json`);
|
|
283
374
|
allOk = false;
|
|
284
375
|
}
|
|
376
|
+
const cacheDir = join(homedir(), ".cache", "opencode");
|
|
377
|
+
const cachePackageJson = join(cacheDir, "package.json");
|
|
378
|
+
if (await exists(cachePackageJson)) {
|
|
379
|
+
try {
|
|
380
|
+
const content = await fs.readFile(cachePackageJson, "utf-8");
|
|
381
|
+
const cacheDep = JSON.parse(content);
|
|
382
|
+
const recordedVersion = cacheDep.dependencies?.["memory-bank-skill"];
|
|
383
|
+
if (recordedVersion) {
|
|
384
|
+
const cacheNodeModules = join(cacheDir, "node_modules", "memory-bank-skill", "package.json");
|
|
385
|
+
if (await exists(cacheNodeModules)) {
|
|
386
|
+
const actualPkg = JSON.parse(await fs.readFile(cacheNodeModules, "utf-8"));
|
|
387
|
+
if (recordedVersion !== actualPkg.version && recordedVersion !== "latest") {
|
|
388
|
+
log(`${colors.yellow}\u26A0${colors.reset} OpenCode cache version mismatch`);
|
|
389
|
+
logDetail(`Recorded: ${recordedVersion}, Actual: ${actualPkg.version}`);
|
|
390
|
+
logDetail(`Run 'bunx memory-bank-skill install' to fix`);
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
} catch {}
|
|
395
|
+
}
|
|
285
396
|
const manifestPath = join(homedir(), ".config", "opencode", "skill", "memory-bank", ".manifest.json");
|
|
286
397
|
if (await exists(manifestPath)) {
|
|
287
398
|
try {
|
package/dist/plugin.js
CHANGED
|
@@ -121,11 +121,19 @@ function truncateToBudget(text, budget) {
|
|
|
121
121
|
return text.slice(0, budget - reserve) + TRUNCATION_NOTICE;
|
|
122
122
|
}
|
|
123
123
|
async function buildMemoryBankContextWithMeta(projectRoot) {
|
|
124
|
+
const fnStart = Date.now();
|
|
125
|
+
if (DEBUG)
|
|
126
|
+
console.error(`[MB-DEBUG] buildMemoryBankContextWithMeta START projectRoot=${projectRoot}`);
|
|
124
127
|
const parts = [];
|
|
125
128
|
const files = [];
|
|
126
129
|
for (const rel of MEMORY_BANK_FILES) {
|
|
130
|
+
const fileStart = Date.now();
|
|
127
131
|
const abs = path.join(projectRoot, rel);
|
|
132
|
+
if (DEBUG)
|
|
133
|
+
console.error(`[MB-DEBUG] reading ${rel}...`);
|
|
128
134
|
const content = await readTextCached(abs);
|
|
135
|
+
if (DEBUG)
|
|
136
|
+
console.error(`[MB-DEBUG] read ${rel} done, hasContent=${!!content}, elapsed=${Date.now() - fileStart}ms`);
|
|
129
137
|
if (!content)
|
|
130
138
|
continue;
|
|
131
139
|
const trimmed = content.trim();
|
|
@@ -136,6 +144,8 @@ async function buildMemoryBankContextWithMeta(projectRoot) {
|
|
|
136
144
|
${trimmed}`);
|
|
137
145
|
files.push({ relPath: rel, chars: trimmed.length });
|
|
138
146
|
}
|
|
147
|
+
if (DEBUG)
|
|
148
|
+
console.error(`[MB-DEBUG] all files read, parts=${parts.length}, totalElapsed=${Date.now() - fnStart}ms`);
|
|
139
149
|
if (parts.length === 0)
|
|
140
150
|
return null;
|
|
141
151
|
const fileList = files.map((f) => f.relPath.replace("memory-bank/", "")).join(", ");
|
|
@@ -562,14 +572,22 @@ ${triggers.join(`
|
|
|
562
572
|
}
|
|
563
573
|
return {
|
|
564
574
|
"experimental.chat.system.transform": async (_input, output) => {
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
575
|
+
const hookStart = Date.now();
|
|
576
|
+
log.info("[HOOK] system.transform START");
|
|
577
|
+
try {
|
|
578
|
+
if (output.system.some((s) => s.includes(SENTINEL_OPEN))) {
|
|
579
|
+
log.info("[HOOK] system.transform SKIP (sentinel exists)", { elapsed: Date.now() - hookStart });
|
|
580
|
+
return;
|
|
581
|
+
}
|
|
582
|
+
log.info("[HOOK] system.transform building context...");
|
|
583
|
+
const ctx = await buildMemoryBankContext(projectRoot);
|
|
584
|
+
log.info("[HOOK] system.transform context built", { hasCtx: !!ctx, elapsed: Date.now() - hookStart });
|
|
585
|
+
if (ctx) {
|
|
586
|
+
output.system.push(ctx);
|
|
587
|
+
log.info("[HOOK] system.transform DONE (ctx pushed)", { elapsed: Date.now() - hookStart });
|
|
588
|
+
return;
|
|
589
|
+
}
|
|
590
|
+
const initInstruction = `${SENTINEL_OPEN}
|
|
573
591
|
` + `# Memory Bank \u672A\u521D\u59CB\u5316
|
|
574
592
|
|
|
575
593
|
` + `\u9879\u76EE \`${path.basename(projectRoot)}\` \u5C1A\u672A\u521D\u59CB\u5316 Memory Bank\u3002
|
|
@@ -577,17 +595,29 @@ ${triggers.join(`
|
|
|
577
595
|
` + `**AI \u884C\u4E3A\u6307\u4EE4**\uFF1A
|
|
578
596
|
` + `- **Todo \u521B\u5EFA\u89C4\u5219\uFF08\u5FC5\u987B\uFF09**\uFF1A\u521B\u5EFA todo \u65F6\uFF0C\u7B2C\u4E00\u9879\u5FC5\u987B\u662F"\u521D\u59CB\u5316 Memory Bank"\uFF08\u626B\u63CF\u9879\u76EE\u7ED3\u6784\uFF0C\u521B\u5EFA brief.md + tech.md + _index.md\uFF09\uFF0C\u6700\u540E\u4E00\u9879\u5FC5\u987B\u662F"\u66F4\u65B0 Memory Bank"\uFF08\u66F4\u65B0 active.md\uFF09
|
|
579
597
|
` + `${SENTINEL_CLOSE}`;
|
|
580
|
-
|
|
598
|
+
output.system.push(initInstruction);
|
|
599
|
+
log.info("[HOOK] system.transform DONE (init pushed)", { elapsed: Date.now() - hookStart });
|
|
600
|
+
} catch (err) {
|
|
601
|
+
log.error("[HOOK] system.transform ERROR", String(err), { elapsed: Date.now() - hookStart });
|
|
602
|
+
}
|
|
581
603
|
},
|
|
582
604
|
"experimental.session.compacting": async (_input, output) => {
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
605
|
+
const hookStart = Date.now();
|
|
606
|
+
log.info("[HOOK] session.compacting START");
|
|
607
|
+
try {
|
|
608
|
+
if (output.context.some((s) => s.includes(SENTINEL_OPEN))) {
|
|
609
|
+
log.info("[HOOK] session.compacting SKIP (sentinel exists)", { elapsed: Date.now() - hookStart });
|
|
610
|
+
return;
|
|
611
|
+
}
|
|
612
|
+
log.info("[HOOK] session.compacting building context...");
|
|
613
|
+
const ctx = await buildMemoryBankContext(projectRoot);
|
|
614
|
+
log.info("[HOOK] session.compacting context built", { hasCtx: !!ctx, elapsed: Date.now() - hookStart });
|
|
615
|
+
if (ctx) {
|
|
616
|
+
output.context.push(ctx);
|
|
617
|
+
log.info("[HOOK] session.compacting DONE (ctx pushed)", { elapsed: Date.now() - hookStart });
|
|
618
|
+
return;
|
|
619
|
+
}
|
|
620
|
+
const initInstruction = `${SENTINEL_OPEN}
|
|
591
621
|
` + `# Memory Bank \u672A\u521D\u59CB\u5316
|
|
592
622
|
|
|
593
623
|
` + `\u9879\u76EE \`${path.basename(projectRoot)}\` \u5C1A\u672A\u521D\u59CB\u5316 Memory Bank\u3002
|
|
@@ -595,7 +625,11 @@ ${triggers.join(`
|
|
|
595
625
|
` + `**AI \u884C\u4E3A\u6307\u4EE4**\uFF1A
|
|
596
626
|
` + `- **Todo \u521B\u5EFA\u89C4\u5219\uFF08\u5FC5\u987B\uFF09**\uFF1A\u521B\u5EFA todo \u65F6\uFF0C\u7B2C\u4E00\u9879\u5FC5\u987B\u662F"\u521D\u59CB\u5316 Memory Bank"\uFF08\u626B\u63CF\u9879\u76EE\u7ED3\u6784\uFF0C\u521B\u5EFA brief.md + tech.md + _index.md\uFF09\uFF0C\u6700\u540E\u4E00\u9879\u5FC5\u987B\u662F"\u66F4\u65B0 Memory Bank"\uFF08\u66F4\u65B0 active.md\uFF09
|
|
597
627
|
` + `${SENTINEL_CLOSE}`;
|
|
598
|
-
|
|
628
|
+
output.context.push(initInstruction);
|
|
629
|
+
log.info("[HOOK] session.compacting DONE (init pushed)", { elapsed: Date.now() - hookStart });
|
|
630
|
+
} catch (err) {
|
|
631
|
+
log.error("[HOOK] session.compacting ERROR", String(err), { elapsed: Date.now() - hookStart });
|
|
632
|
+
}
|
|
599
633
|
},
|
|
600
634
|
event: async ({ event }) => {
|
|
601
635
|
try {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "memory-bank-skill",
|
|
3
|
-
"version": "5.5.
|
|
3
|
+
"version": "5.5.2",
|
|
4
4
|
"description": "Memory Bank - 项目记忆系统,让 AI 助手在每次对话中都能快速理解项目上下文",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/plugin.js",
|
|
@@ -40,5 +40,8 @@
|
|
|
40
40
|
},
|
|
41
41
|
"publishConfig": {
|
|
42
42
|
"registry": "https://registry.npmjs.org/"
|
|
43
|
+
},
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"memory-bank-skill": "5.5.1"
|
|
43
46
|
}
|
|
44
47
|
}
|