@ztffn/presentation-generator-plugin 1.4.1 → 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 +59 -10
  2. package/package.json +1 -1
package/bin/index.js CHANGED
@@ -125,8 +125,8 @@ function promptChoice(title, choices) {
125
125
 
126
126
  const draw = (first = false) => {
127
127
  if (!first) {
128
- // Reposition to top of the widget and clear downward
129
- process.stdout.write(C.up(lineCount() - 1) + C.clear());
128
+ // \r resets to col 0 before moving up, so C.clear() wipes from the true start of the line
129
+ process.stdout.write("\r" + C.up(lineCount() - 1) + C.clear());
130
130
  }
131
131
  process.stdout.write(`\n◆ ${title}\n`);
132
132
  choices.forEach((c, i) => {
@@ -244,22 +244,70 @@ function cleanOldCacheVersions(keepVersion) {
244
244
  }
245
245
  }
246
246
 
247
- function registerWithClaude(installDir, scope) {
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.
251
+ const registryPath = path.join(
252
+ os.homedir(), ".claude", "plugins", "installed_plugins.json"
253
+ );
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 {}
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");
285
+ }
286
+
287
+ function registerWithClaude(installDir, scope, version) {
248
288
  const pluginsDir = path.dirname(installDir);
249
289
  ensureMarketplaceJson(pluginsDir);
250
290
 
251
- // Remove any stale registration (e.g. from a previous install at a different path)
252
- // before adding the current one. Errors are ignored — it may not exist yet.
291
+ // Remove any stale marketplace registration before re-adding.
253
292
  try {
254
293
  execSync(`claude plugin marketplace remove "${MARKETPLACE_NAME}"`, { stdio: "pipe" });
255
- } catch {
256
- // didn't exist or not removable — ignore
257
- }
294
+ } catch {}
295
+
296
+ // Uninstall stale plugin entries from both scopes before re-installing.
297
+ try {
298
+ execSync(`claude plugin uninstall ${PLUGIN_NAME}@${MARKETPLACE_NAME} --scope project`, { stdio: "pipe" });
299
+ } catch {}
300
+ try {
301
+ execSync(`claude plugin uninstall ${PLUGIN_NAME}@${MARKETPLACE_NAME} --scope user`, { stdio: "pipe" });
302
+ } catch {}
258
303
 
259
304
  execSync(`claude plugin marketplace add "${pluginsDir}"`, { stdio: "pipe" });
260
305
 
261
306
  const scopeFlag = scope === "project" ? "--scope project" : "--scope user";
262
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);
263
311
  }
264
312
 
265
313
  function removeFromSettings(settingsPath) {
@@ -320,7 +368,8 @@ async function install() {
320
368
  console.log(`\nInstalled v${meta.version} to: ${label}`);
321
369
 
322
370
  console.log("\nRegistering plugin with Claude Code...");
323
- registerWithClaude(installDir, scope);
371
+ registerWithClaude(installDir, scope, meta.version);
372
+ cleanOldCacheVersions(meta.version);
324
373
 
325
374
  const settingsLabel = scope === "project" ? ".claude/settings.json" : "~/.claude/settings.json";
326
375
  console.log(`Plugin registered in ${settingsLabel} ✓`);
@@ -357,7 +406,7 @@ async function update() {
357
406
  console.log(`\n${label}: updating v${before || "unknown"} → v${meta.version}...`);
358
407
  await downloadAndExtract(meta.version, meta.tarball, installDir);
359
408
  const updateScope = installDir === GLOBAL_INSTALL_DIR ? "user" : "project";
360
- registerWithClaude(installDir, updateScope);
409
+ registerWithClaude(installDir, updateScope, meta.version);
361
410
  cleanOldCacheVersions(meta.version);
362
411
  console.log(`${label}: updated to v${meta.version} ✓`);
363
412
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ztffn/presentation-generator-plugin",
3
- "version": "1.4.1",
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"