@blueprintit/shop-os-install 0.4.0 → 0.5.0
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/shop-os-install.js +55 -42
- package/package.json +1 -1
package/bin/shop-os-install.js
CHANGED
|
@@ -25,6 +25,7 @@ import {
|
|
|
25
25
|
existsSync,
|
|
26
26
|
mkdirSync,
|
|
27
27
|
readFileSync,
|
|
28
|
+
rmSync,
|
|
28
29
|
writeFileSync,
|
|
29
30
|
chmodSync,
|
|
30
31
|
} from "node:fs";
|
|
@@ -138,7 +139,7 @@ async function validateLicense(key) {
|
|
|
138
139
|
const url = `${LICENSE_SERVER}/validate?key=${encodeURIComponent(key)}`;
|
|
139
140
|
let resp;
|
|
140
141
|
try {
|
|
141
|
-
resp = await fetch(url, { headers: { "user-agent": "shop-os-installer/0.
|
|
142
|
+
resp = await fetch(url, { headers: { "user-agent": "shop-os-installer/0.5.0" } });
|
|
142
143
|
} catch (e) {
|
|
143
144
|
return { ok: false, error: `network: ${e.message}` };
|
|
144
145
|
}
|
|
@@ -172,49 +173,65 @@ function writeJSON(path, obj) {
|
|
|
172
173
|
}
|
|
173
174
|
|
|
174
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.
|
|
175
181
|
const path = join(claudeRoot, "plugins", "known_marketplaces.json");
|
|
176
182
|
const known = readJSON(path, {});
|
|
177
|
-
const
|
|
183
|
+
const cleared = [];
|
|
178
184
|
for (const mp of MARKETPLACES) {
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
185
|
+
const installLocation = join(claudeRoot, "plugins", "marketplaces", mp.name);
|
|
186
|
+
known[mp.name] = {
|
|
187
|
+
source: { source: mp.source.type, repo: mp.source.repo },
|
|
188
|
+
installLocation,
|
|
189
|
+
lastUpdated: new Date().toISOString(),
|
|
190
|
+
};
|
|
191
|
+
if (existsSync(installLocation)) {
|
|
192
|
+
try {
|
|
193
|
+
rmSync(installLocation, { recursive: true, force: true });
|
|
194
|
+
cleared.push(mp.name);
|
|
195
|
+
} 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.
|
|
199
|
+
}
|
|
186
200
|
}
|
|
187
201
|
}
|
|
188
|
-
|
|
189
|
-
return {
|
|
202
|
+
writeJSON(path, known);
|
|
203
|
+
return { cleared, total: MARKETPLACES.length };
|
|
190
204
|
}
|
|
191
205
|
|
|
192
206
|
function ensurePluginsInstalled(claudeRoot) {
|
|
193
|
-
//
|
|
194
|
-
//
|
|
195
|
-
//
|
|
207
|
+
// 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.
|
|
213
|
+
//
|
|
214
|
+
// This wipes any project-scope variants of these specific plugin ids — that's
|
|
215
|
+
// intentional. Shop OS is meant to be enabled at user scope so the same
|
|
216
|
+
// plugin set works across every vault the operator runs.
|
|
196
217
|
const path = join(claudeRoot, "plugins", "installed_plugins.json");
|
|
197
218
|
const existing = readJSON(path, { version: 2, plugins: {} });
|
|
198
219
|
if (!existing.plugins) existing.plugins = {};
|
|
199
220
|
const installedAt = new Date().toISOString();
|
|
200
|
-
let changed = false;
|
|
201
221
|
for (const id of PLUGINS_TO_ENABLE) {
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
];
|
|
213
|
-
changed = true;
|
|
214
|
-
}
|
|
222
|
+
existing.plugins[id] = [
|
|
223
|
+
{
|
|
224
|
+
scope: "user",
|
|
225
|
+
installPath: null, // filled in by Claude Code on next marketplace sync
|
|
226
|
+
version: "pending",
|
|
227
|
+
installedAt,
|
|
228
|
+
lastUpdated: installedAt,
|
|
229
|
+
gitCommitSha: "pending-sync",
|
|
230
|
+
},
|
|
231
|
+
];
|
|
215
232
|
}
|
|
216
|
-
|
|
217
|
-
return
|
|
233
|
+
writeJSON(path, existing);
|
|
234
|
+
return PLUGINS_TO_ENABLE;
|
|
218
235
|
}
|
|
219
236
|
|
|
220
237
|
function enableForVault(vaultPath) {
|
|
@@ -233,6 +250,7 @@ function createVaultClaudeMd(vaultPath, license) {
|
|
|
233
250
|
if (existsSync(claudeMd)) return false; // do not overwrite an existing vault
|
|
234
251
|
const content = `---
|
|
235
252
|
os-mode: business
|
|
253
|
+
bp-setup-state: pending
|
|
236
254
|
license-customer: ${license.customer}
|
|
237
255
|
license-product: ${license.product}
|
|
238
256
|
installed-at: ${new Date().toISOString()}
|
|
@@ -583,20 +601,15 @@ async function main() {
|
|
|
583
601
|
|
|
584
602
|
print(dim(" [1/6] Registering plugin marketplaces"));
|
|
585
603
|
const mpResult = ensureMarketplaces(claudeRoot);
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
for (const name of mpResult.added) ok(`Added marketplace: ${name}`);
|
|
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.`);
|
|
590
607
|
}
|
|
591
608
|
|
|
592
|
-
print(dim(" [2/6]
|
|
593
|
-
const
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
info("Claude Code will sync the actual plugin files from the marketplaces on next launch.");
|
|
597
|
-
} else {
|
|
598
|
-
info("All required plugins already queued");
|
|
599
|
-
}
|
|
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.");
|
|
600
613
|
|
|
601
614
|
print(dim(` [3/6] ${isExisting ? "Configuring" : "Creating"} vault at ${vaultPath}`));
|
|
602
615
|
if (!existsSync(vaultPath)) {
|