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.
Files changed (3) hide show
  1. package/dist/cli.js +120 -9
  2. package/dist/plugin.js +52 -18
  3. 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.4.0";
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 pluginPackage = "memory-bank-skill";
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: [pluginPackage]
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
- if (!config.plugin.includes(pluginPackage)) {
191
- config.plugin.push(pluginPackage);
192
- changes.push(`Added plugin: ${pluginPackage}`);
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
- pluginConfigured = Array.isArray(config.plugin) && config.plugin.includes("memory-bank-skill");
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("memory-bank-skill");
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("Add 'memory-bank-skill' to plugin array in opencode.json");
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
- if (output.system.some((s) => s.includes(SENTINEL_OPEN)))
566
- return;
567
- const ctx = await buildMemoryBankContext(projectRoot);
568
- if (ctx) {
569
- output.system.push(ctx);
570
- return;
571
- }
572
- const initInstruction = `${SENTINEL_OPEN}
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
- output.system.push(initInstruction);
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
- if (output.context.some((s) => s.includes(SENTINEL_OPEN)))
584
- return;
585
- const ctx = await buildMemoryBankContext(projectRoot);
586
- if (ctx) {
587
- output.context.push(ctx);
588
- return;
589
- }
590
- const initInstruction = `${SENTINEL_OPEN}
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
- output.context.push(initInstruction);
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.0",
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
  }