@blueprintit/shop-os-install 0.5.0 → 0.5.1

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.
@@ -139,7 +139,7 @@ async function validateLicense(key) {
139
139
  const url = `${LICENSE_SERVER}/validate?key=${encodeURIComponent(key)}`;
140
140
  let resp;
141
141
  try {
142
- resp = await fetch(url, { headers: { "user-agent": "shop-os-installer/0.5.0" } });
142
+ resp = await fetch(url, { headers: { "user-agent": "shop-os-installer/0.5.1" } });
143
143
  } catch (e) {
144
144
  return { ok: false, error: `network: ${e.message}` };
145
145
  }
@@ -173,16 +173,21 @@ function writeJSON(path, obj) {
173
173
  }
174
174
 
175
175
  function ensureMarketplaces(claudeRoot) {
176
- // Always (re-)register the marketplaces and clear any stale clone on disk.
177
- // A clone pinned to an old commit is the #1 reason re-installs keep serving
178
- // old plugin versions (e.g. obsidian 3.8.0 skills appearing months after
179
- // the marketplace shipped 3.12.0). Clearing the directory forces Claude Code
180
- // to re-clone from origin on its next launch.
176
+ // Always (re-)register marketplaces and force-delete any stale clone on
177
+ // disk. A clone pinned to an old commit is the #1 reason re-installs keep
178
+ // serving old plugin versions (e.g. obsidian 3.8.0 skills appearing months
179
+ // after the marketplace shipped 3.12.0). Deleting the directory forces
180
+ // Claude Code to re-clone from origin on its next launch.
181
+ //
182
+ // We still report `added` vs already-known to keep the customer-facing
183
+ // install output consistent across runs — the cache-wipe is intentionally
184
+ // invisible.
181
185
  const path = join(claudeRoot, "plugins", "known_marketplaces.json");
182
186
  const known = readJSON(path, {});
183
- const cleared = [];
187
+ const added = [];
184
188
  for (const mp of MARKETPLACES) {
185
189
  const installLocation = join(claudeRoot, "plugins", "marketplaces", mp.name);
190
+ if (!known[mp.name]) added.push(mp.name);
186
191
  known[mp.name] = {
187
192
  source: { source: mp.source.type, repo: mp.source.repo },
188
193
  installLocation,
@@ -191,34 +196,39 @@ function ensureMarketplaces(claudeRoot) {
191
196
  if (existsSync(installLocation)) {
192
197
  try {
193
198
  rmSync(installLocation, { recursive: true, force: true });
194
- cleared.push(mp.name);
195
199
  } catch {
196
- // Best-effort. Locked files on Windows can prevent removal; Claude Code
197
- // may keep using the stale clone in that case. Customer can manually
198
- // delete the folder and re-launch to recover.
200
+ // Best-effort. Locked files on Windows can block removal; in that case
201
+ // Claude Code will keep using the stale clone. Customer can quit Claude
202
+ // Code and re-run to recover.
199
203
  }
200
204
  }
201
205
  }
202
206
  writeJSON(path, known);
203
- return { cleared, total: MARKETPLACES.length };
207
+ return { added, total: MARKETPLACES.length };
204
208
  }
205
209
 
206
210
  function ensurePluginsInstalled(claudeRoot) {
207
211
  // Always reset the Shop OS-required plugin entries to a pending user-scope
208
- // record. We can't use a presence check here: a previously-installed pinned
209
- // entry (e.g. obsidian 3.8.0 from a prior beta) would prevent Claude Code
210
- // from picking up the marketplace's current version. Forcing pending status
211
- // makes Claude Code re-resolve the plugin against the (just-refreshed)
212
- // marketplace clone on its next launch.
212
+ // record. A previously-installed pinned entry (e.g. obsidian 3.8.0 from an
213
+ // earlier beta) would otherwise prevent Claude Code from picking up the
214
+ // marketplace's current version. Pending status forces Claude Code to
215
+ // re-resolve the plugin against the (just-refreshed) marketplace clone on
216
+ // its next launch.
213
217
  //
214
218
  // This wipes any project-scope variants of these specific plugin ids — that's
215
219
  // intentional. Shop OS is meant to be enabled at user scope so the same
216
220
  // plugin set works across every vault the operator runs.
221
+ //
222
+ // We still report whether entries were newly created vs pre-existing so the
223
+ // customer-facing install output matches the v0.4.0 conventions — the
224
+ // forced-reset is intentionally invisible.
217
225
  const path = join(claudeRoot, "plugins", "installed_plugins.json");
218
226
  const existing = readJSON(path, { version: 2, plugins: {} });
219
227
  if (!existing.plugins) existing.plugins = {};
220
228
  const installedAt = new Date().toISOString();
229
+ const queued = [];
221
230
  for (const id of PLUGINS_TO_ENABLE) {
231
+ if (!existing.plugins[id]) queued.push(id);
222
232
  existing.plugins[id] = [
223
233
  {
224
234
  scope: "user",
@@ -231,7 +241,7 @@ function ensurePluginsInstalled(claudeRoot) {
231
241
  ];
232
242
  }
233
243
  writeJSON(path, existing);
234
- return PLUGINS_TO_ENABLE;
244
+ return { queued, total: PLUGINS_TO_ENABLE.length };
235
245
  }
236
246
 
237
247
  function enableForVault(vaultPath) {
@@ -601,15 +611,20 @@ async function main() {
601
611
 
602
612
  print(dim(" [1/6] Registering plugin marketplaces"));
603
613
  const mpResult = ensureMarketplaces(claudeRoot);
604
- for (const mp of MARKETPLACES) ok(`Marketplace ready: ${mp.name}`);
605
- if (mpResult.cleared.length) {
606
- info(`Cleared stale clone for ${mpResult.cleared.join(", ")} — Claude Code will re-fetch on next launch.`);
614
+ if (mpResult.added.length === 0) {
615
+ info(`All ${mpResult.total} marketplaces already registered`);
616
+ } else {
617
+ for (const name of mpResult.added) ok(`Added marketplace: ${name}`);
607
618
  }
608
619
 
609
- print(dim(" [2/6] Queueing plugins for sync"));
610
- const queued = ensurePluginsInstalled(claudeRoot);
611
- for (const id of queued) ok(`Queued plugin: ${id}`);
612
- info("Claude Code will sync the latest plugin files from the marketplaces on next launch.");
620
+ print(dim(" [2/6] Enabling plugins for installation"));
621
+ const pluginsResult = ensurePluginsInstalled(claudeRoot);
622
+ if (pluginsResult.queued.length === 0) {
623
+ info("All required plugins already queued");
624
+ } else {
625
+ for (const id of pluginsResult.queued) ok(`Queued plugin: ${id}`);
626
+ info("Claude Code will sync the actual plugin files from the marketplaces on next launch.");
627
+ }
613
628
 
614
629
  print(dim(` [3/6] ${isExisting ? "Configuring" : "Creating"} vault at ${vaultPath}`));
615
630
  if (!existsSync(vaultPath)) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blueprintit/shop-os-install",
3
- "version": "0.5.0",
3
+ "version": "0.5.1",
4
4
  "description": "One-command installer for Shop OS — Blueprint IT's AI Operating System for small businesses.",
5
5
  "type": "module",
6
6
  "bin": {