@ztffn/presentation-generator-plugin 1.4.2 → 1.4.3

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 (2) hide show
  1. package/bin/index.js +43 -27
  2. package/package.json +1 -1
package/bin/index.js CHANGED
@@ -244,39 +244,56 @@ function cleanOldCacheVersions(keepVersion) {
244
244
  }
245
245
  }
246
246
 
247
- function purgeInstalledPluginsJson() {
248
- // Directly remove all entries for this plugin from Claude's global registry
249
- // so that a subsequent `claude plugin install` always writes a fresh entry.
247
+ function writeInstalledPluginsJson(version, installDir, scope) {
248
+ // Claude Code's `claude plugin install` writes stale version/installPath data
249
+ // (a known bug: https://github.com/anthropics/claude-code/issues/15642).
250
+ // We overwrite the entry directly with the correct values after install.
250
251
  const registryPath = path.join(
251
252
  os.homedir(), ".claude", "plugins", "installed_plugins.json"
252
253
  );
253
- if (!fs.existsSync(registryPath)) return;
254
- try {
255
- const registry = JSON.parse(fs.readFileSync(registryPath, "utf8"));
256
- const key = `${PLUGIN_NAME}@${MARKETPLACE_NAME}`;
257
- if (registry.plugins && key in registry.plugins) {
258
- delete registry.plugins[key];
259
- fs.writeFileSync(registryPath, JSON.stringify(registry, null, 2) + "\n");
260
- }
261
- } catch {
262
- // registry unreadable/corrupt leave it alone
254
+
255
+ // Ensure the cache dir exists and contains the plugin files.
256
+ const cacheDir = path.join(
257
+ os.homedir(), ".claude", "plugins", "cache", MARKETPLACE_NAME, PLUGIN_NAME, version
258
+ );
259
+ if (!fs.existsSync(cacheDir)) {
260
+ execSync(`cp -r "${installDir}/." "${cacheDir}"`, { stdio: "pipe" });
261
+ }
262
+
263
+ let registry = { version: 2, plugins: {} };
264
+ if (fs.existsSync(registryPath)) {
265
+ try { registry = JSON.parse(fs.readFileSync(registryPath, "utf8")); } catch {}
263
266
  }
267
+
268
+ const key = `${PLUGIN_NAME}@${MARKETPLACE_NAME}`;
269
+ const now = new Date().toISOString();
270
+ const existing = (registry.plugins[key] || []).find((e) => e.scope === scope);
271
+ const entry = {
272
+ scope,
273
+ installPath: cacheDir,
274
+ version,
275
+ installedAt: existing?.installedAt || now,
276
+ lastUpdated: now,
277
+ projectPath: process.cwd(),
278
+ };
279
+
280
+ // Replace all entries for this scope, keep entries for other scopes.
281
+ const others = (registry.plugins[key] || []).filter((e) => e.scope !== scope);
282
+ registry.plugins[key] = [...others, entry];
283
+ fs.mkdirSync(path.dirname(registryPath), { recursive: true });
284
+ fs.writeFileSync(registryPath, JSON.stringify(registry, null, 2) + "\n");
264
285
  }
265
286
 
266
- function registerWithClaude(installDir, scope) {
287
+ function registerWithClaude(installDir, scope, version) {
267
288
  const pluginsDir = path.dirname(installDir);
268
289
  ensureMarketplaceJson(pluginsDir);
269
290
 
270
- // Remove any stale registration (e.g. from a previous install at a different path)
271
- // before adding the current one. Errors are ignored — it may not exist yet.
291
+ // Remove any stale marketplace registration before re-adding.
272
292
  try {
273
293
  execSync(`claude plugin marketplace remove "${MARKETPLACE_NAME}"`, { stdio: "pipe" });
274
- } catch {
275
- // didn't exist or not removable — ignore
276
- }
294
+ } catch {}
277
295
 
278
- // Uninstall any stale plugin entries from both scopes before re-installing.
279
- // This prevents Claude from reusing a cached entry pointing at an old version path.
296
+ // Uninstall stale plugin entries from both scopes before re-installing.
280
297
  try {
281
298
  execSync(`claude plugin uninstall ${PLUGIN_NAME}@${MARKETPLACE_NAME} --scope project`, { stdio: "pipe" });
282
299
  } catch {}
@@ -284,14 +301,13 @@ function registerWithClaude(installDir, scope) {
284
301
  execSync(`claude plugin uninstall ${PLUGIN_NAME}@${MARKETPLACE_NAME} --scope user`, { stdio: "pipe" });
285
302
  } catch {}
286
303
 
287
- // Belt-and-suspenders: also purge the registry JSON directly in case
288
- // `claude plugin uninstall` doesn't clean installed_plugins.json reliably.
289
- purgeInstalledPluginsJson();
290
-
291
304
  execSync(`claude plugin marketplace add "${pluginsDir}"`, { stdio: "pipe" });
292
305
 
293
306
  const scopeFlag = scope === "project" ? "--scope project" : "--scope user";
294
307
  execSync(`claude plugin install ${PLUGIN_NAME}@${MARKETPLACE_NAME} ${scopeFlag}`, { stdio: "pipe" });
308
+
309
+ // Overwrite whatever Claude wrote with the correct version and cache path.
310
+ writeInstalledPluginsJson(version, installDir, scope);
295
311
  }
296
312
 
297
313
  function removeFromSettings(settingsPath) {
@@ -352,7 +368,7 @@ async function install() {
352
368
  console.log(`\nInstalled v${meta.version} to: ${label}`);
353
369
 
354
370
  console.log("\nRegistering plugin with Claude Code...");
355
- registerWithClaude(installDir, scope);
371
+ registerWithClaude(installDir, scope, meta.version);
356
372
  cleanOldCacheVersions(meta.version);
357
373
 
358
374
  const settingsLabel = scope === "project" ? ".claude/settings.json" : "~/.claude/settings.json";
@@ -390,7 +406,7 @@ async function update() {
390
406
  console.log(`\n${label}: updating v${before || "unknown"} → v${meta.version}...`);
391
407
  await downloadAndExtract(meta.version, meta.tarball, installDir);
392
408
  const updateScope = installDir === GLOBAL_INSTALL_DIR ? "user" : "project";
393
- registerWithClaude(installDir, updateScope);
409
+ registerWithClaude(installDir, updateScope, meta.version);
394
410
  cleanOldCacheVersions(meta.version);
395
411
  console.log(`${label}: updated to v${meta.version} ✓`);
396
412
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ztffn/presentation-generator-plugin",
3
- "version": "1.4.2",
3
+ "version": "1.4.3",
4
4
  "description": "Claude Code plugin for generating graph-based presentations",
5
5
  "bin": {
6
6
  "presentation-generator-plugin": "bin/index.js"