@ztffn/presentation-generator-plugin 1.4.2 → 1.4.4
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/bin/index.js +89 -27
- package/package.json +1 -1
package/bin/index.js
CHANGED
|
@@ -244,9 +244,9 @@ function cleanOldCacheVersions(keepVersion) {
|
|
|
244
244
|
}
|
|
245
245
|
}
|
|
246
246
|
|
|
247
|
-
function
|
|
248
|
-
//
|
|
249
|
-
//
|
|
247
|
+
function clearInstalledPluginsEntry() {
|
|
248
|
+
// Remove all registry entries for this plugin so `claude plugin install`
|
|
249
|
+
// starts from a clean slate and cannot restore a stale cache path/version.
|
|
250
250
|
const registryPath = path.join(
|
|
251
251
|
os.homedir(), ".claude", "plugins", "installed_plugins.json"
|
|
252
252
|
);
|
|
@@ -258,25 +258,59 @@ function purgeInstalledPluginsJson() {
|
|
|
258
258
|
delete registry.plugins[key];
|
|
259
259
|
fs.writeFileSync(registryPath, JSON.stringify(registry, null, 2) + "\n");
|
|
260
260
|
}
|
|
261
|
-
} catch {
|
|
262
|
-
|
|
261
|
+
} catch {}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
function writeInstalledPluginsJson(version, installDir, scope) {
|
|
265
|
+
// Claude Code's `claude plugin install` writes stale version/installPath data
|
|
266
|
+
// (a known bug: https://github.com/anthropics/claude-code/issues/15642).
|
|
267
|
+
// We overwrite the entry directly with the correct values after install.
|
|
268
|
+
const registryPath = path.join(
|
|
269
|
+
os.homedir(), ".claude", "plugins", "installed_plugins.json"
|
|
270
|
+
);
|
|
271
|
+
|
|
272
|
+
// Ensure the cache dir exists and contains the plugin files.
|
|
273
|
+
const cacheDir = path.join(
|
|
274
|
+
os.homedir(), ".claude", "plugins", "cache", MARKETPLACE_NAME, PLUGIN_NAME, version
|
|
275
|
+
);
|
|
276
|
+
if (!fs.existsSync(cacheDir)) {
|
|
277
|
+
execSync(`cp -r "${installDir}/." "${cacheDir}"`, { stdio: "pipe" });
|
|
263
278
|
}
|
|
279
|
+
|
|
280
|
+
let registry = { version: 2, plugins: {} };
|
|
281
|
+
if (fs.existsSync(registryPath)) {
|
|
282
|
+
try { registry = JSON.parse(fs.readFileSync(registryPath, "utf8")); } catch {}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
const key = `${PLUGIN_NAME}@${MARKETPLACE_NAME}`;
|
|
286
|
+
const now = new Date().toISOString();
|
|
287
|
+
const existing = (registry.plugins[key] || []).find((e) => e.scope === scope);
|
|
288
|
+
const entry = {
|
|
289
|
+
scope,
|
|
290
|
+
installPath: cacheDir,
|
|
291
|
+
version,
|
|
292
|
+
installedAt: existing?.installedAt || now,
|
|
293
|
+
lastUpdated: now,
|
|
294
|
+
projectPath: process.cwd(),
|
|
295
|
+
};
|
|
296
|
+
|
|
297
|
+
// Replace all entries for this scope, keep entries for other scopes.
|
|
298
|
+
const others = (registry.plugins[key] || []).filter((e) => e.scope !== scope);
|
|
299
|
+
registry.plugins[key] = [...others, entry];
|
|
300
|
+
fs.mkdirSync(path.dirname(registryPath), { recursive: true });
|
|
301
|
+
fs.writeFileSync(registryPath, JSON.stringify(registry, null, 2) + "\n");
|
|
264
302
|
}
|
|
265
303
|
|
|
266
|
-
function registerWithClaude(installDir, scope) {
|
|
304
|
+
function registerWithClaude(installDir, scope, version) {
|
|
267
305
|
const pluginsDir = path.dirname(installDir);
|
|
268
306
|
ensureMarketplaceJson(pluginsDir);
|
|
269
307
|
|
|
270
|
-
// Remove any stale registration
|
|
271
|
-
// before adding the current one. Errors are ignored — it may not exist yet.
|
|
308
|
+
// Remove any stale marketplace registration before re-adding.
|
|
272
309
|
try {
|
|
273
310
|
execSync(`claude plugin marketplace remove "${MARKETPLACE_NAME}"`, { stdio: "pipe" });
|
|
274
|
-
} catch {
|
|
275
|
-
// didn't exist or not removable — ignore
|
|
276
|
-
}
|
|
311
|
+
} catch {}
|
|
277
312
|
|
|
278
|
-
// Uninstall
|
|
279
|
-
// This prevents Claude from reusing a cached entry pointing at an old version path.
|
|
313
|
+
// Uninstall stale plugin entries from both scopes before re-installing.
|
|
280
314
|
try {
|
|
281
315
|
execSync(`claude plugin uninstall ${PLUGIN_NAME}@${MARKETPLACE_NAME} --scope project`, { stdio: "pipe" });
|
|
282
316
|
} catch {}
|
|
@@ -284,14 +318,26 @@ function registerWithClaude(installDir, scope) {
|
|
|
284
318
|
execSync(`claude plugin uninstall ${PLUGIN_NAME}@${MARKETPLACE_NAME} --scope user`, { stdio: "pipe" });
|
|
285
319
|
} catch {}
|
|
286
320
|
|
|
287
|
-
//
|
|
288
|
-
//
|
|
289
|
-
|
|
321
|
+
// Directly clear the registry entry regardless of whether the CLI uninstall
|
|
322
|
+
// removed it (the CLI skips entries whose projectPath != cwd).
|
|
323
|
+
clearInstalledPluginsEntry();
|
|
324
|
+
|
|
325
|
+
// Remove stale cache dirs so `claude plugin install` has nothing stale to
|
|
326
|
+
// restore. writeInstalledPluginsJson will recreate the correct version dir.
|
|
327
|
+
const cachePluginDir = path.join(
|
|
328
|
+
os.homedir(), ".claude", "plugins", "cache", MARKETPLACE_NAME, PLUGIN_NAME
|
|
329
|
+
);
|
|
330
|
+
if (fs.existsSync(cachePluginDir)) {
|
|
331
|
+
fs.rmSync(cachePluginDir, { recursive: true, force: true });
|
|
332
|
+
}
|
|
290
333
|
|
|
291
334
|
execSync(`claude plugin marketplace add "${pluginsDir}"`, { stdio: "pipe" });
|
|
292
335
|
|
|
293
336
|
const scopeFlag = scope === "project" ? "--scope project" : "--scope user";
|
|
294
337
|
execSync(`claude plugin install ${PLUGIN_NAME}@${MARKETPLACE_NAME} ${scopeFlag}`, { stdio: "pipe" });
|
|
338
|
+
|
|
339
|
+
// Overwrite whatever Claude wrote with the correct version and cache path.
|
|
340
|
+
writeInstalledPluginsJson(version, installDir, scope);
|
|
295
341
|
}
|
|
296
342
|
|
|
297
343
|
function removeFromSettings(settingsPath) {
|
|
@@ -313,14 +359,36 @@ function removeFromSettings(settingsPath) {
|
|
|
313
359
|
// ── Commands ──────────────────────────────────────────────────────────────────
|
|
314
360
|
|
|
315
361
|
async function install() {
|
|
362
|
+
// Warn if this installer binary is outdated (npx caches old versions).
|
|
363
|
+
// Stale installers lack bug fixes — users should run with @latest.
|
|
364
|
+
const latestMeta = await getLatestNpmMeta();
|
|
365
|
+
if (latestMeta) {
|
|
366
|
+
const versionLt = (a, b) => {
|
|
367
|
+
const [aMaj, aMin, aPat] = a.split(".").map(Number);
|
|
368
|
+
const [bMaj, bMin, bPat] = b.split(".").map(Number);
|
|
369
|
+
return aMaj < bMaj || (aMaj === bMaj && aMin < bMin) || (aMaj === bMaj && aMin === bMin && aPat < bPat);
|
|
370
|
+
};
|
|
371
|
+
if (versionLt(CURRENT_VERSION, latestMeta.version)) {
|
|
372
|
+
console.log(`\nWarning: installer v${CURRENT_VERSION} is outdated (v${latestMeta.version} available).`);
|
|
373
|
+
console.log(`Run with @latest to get the current installer:`);
|
|
374
|
+
console.log(` npx ${NPM_PACKAGE}@latest install\n`);
|
|
375
|
+
return;
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
const meta = latestMeta;
|
|
380
|
+
if (!meta) {
|
|
381
|
+
console.error("\nCould not fetch latest version from npm registry. Check your internet connection.\n");
|
|
382
|
+
process.exit(1);
|
|
383
|
+
}
|
|
384
|
+
|
|
316
385
|
const globalExists = fs.existsSync(GLOBAL_INSTALL_DIR);
|
|
317
386
|
const projectExists = fs.existsSync(PROJECT_INSTALL_DIR);
|
|
318
387
|
|
|
319
388
|
if (globalExists || projectExists) {
|
|
320
|
-
const meta = await getLatestNpmMeta();
|
|
321
389
|
if (globalExists) {
|
|
322
390
|
const v = getInstalledVersion(GLOBAL_INSTALL_DIR);
|
|
323
|
-
if (
|
|
391
|
+
if (v !== meta.version) {
|
|
324
392
|
console.log(`\nGlobal install found (v${v}). v${meta.version} available — run: npx ${NPM_PACKAGE} update\n`);
|
|
325
393
|
} else {
|
|
326
394
|
console.log(`\nGlobal install already up to date (v${v || "unknown"}).\n`);
|
|
@@ -328,7 +396,7 @@ async function install() {
|
|
|
328
396
|
}
|
|
329
397
|
if (projectExists) {
|
|
330
398
|
const v = getInstalledVersion(PROJECT_INSTALL_DIR);
|
|
331
|
-
if (
|
|
399
|
+
if (v !== meta.version) {
|
|
332
400
|
console.log(`\nProject install found (v${v}). v${meta.version} available — run: npx ${NPM_PACKAGE} update\n`);
|
|
333
401
|
} else {
|
|
334
402
|
console.log(`\nProject install already up to date (v${v || "unknown"}).\n`);
|
|
@@ -337,12 +405,6 @@ async function install() {
|
|
|
337
405
|
return;
|
|
338
406
|
}
|
|
339
407
|
|
|
340
|
-
const meta = await getLatestNpmMeta();
|
|
341
|
-
if (!meta) {
|
|
342
|
-
console.error("\nCould not fetch latest version from npm registry. Check your internet connection.\n");
|
|
343
|
-
process.exit(1);
|
|
344
|
-
}
|
|
345
|
-
|
|
346
408
|
const { installDir, scope } = await resolveInstallTarget();
|
|
347
409
|
|
|
348
410
|
console.log(`\nInstalling presentation-generator plugin...`);
|
|
@@ -352,7 +414,7 @@ async function install() {
|
|
|
352
414
|
console.log(`\nInstalled v${meta.version} to: ${label}`);
|
|
353
415
|
|
|
354
416
|
console.log("\nRegistering plugin with Claude Code...");
|
|
355
|
-
registerWithClaude(installDir, scope);
|
|
417
|
+
registerWithClaude(installDir, scope, meta.version);
|
|
356
418
|
cleanOldCacheVersions(meta.version);
|
|
357
419
|
|
|
358
420
|
const settingsLabel = scope === "project" ? ".claude/settings.json" : "~/.claude/settings.json";
|
|
@@ -390,7 +452,7 @@ async function update() {
|
|
|
390
452
|
console.log(`\n${label}: updating v${before || "unknown"} → v${meta.version}...`);
|
|
391
453
|
await downloadAndExtract(meta.version, meta.tarball, installDir);
|
|
392
454
|
const updateScope = installDir === GLOBAL_INSTALL_DIR ? "user" : "project";
|
|
393
|
-
registerWithClaude(installDir, updateScope);
|
|
455
|
+
registerWithClaude(installDir, updateScope, meta.version);
|
|
394
456
|
cleanOldCacheVersions(meta.version);
|
|
395
457
|
console.log(`${label}: updated to v${meta.version} ✓`);
|
|
396
458
|
}
|