@blueprintit/shop-os-install 0.4.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.
- package/bin/shop-os-install.js +61 -33
- 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.1" } });
|
|
142
143
|
} catch (e) {
|
|
143
144
|
return { ok: false, error: `network: ${e.message}` };
|
|
144
145
|
}
|
|
@@ -172,49 +173,75 @@ function writeJSON(path, obj) {
|
|
|
172
173
|
}
|
|
173
174
|
|
|
174
175
|
function ensureMarketplaces(claudeRoot) {
|
|
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.
|
|
175
185
|
const path = join(claudeRoot, "plugins", "known_marketplaces.json");
|
|
176
186
|
const known = readJSON(path, {});
|
|
177
187
|
const added = [];
|
|
178
188
|
for (const mp of MARKETPLACES) {
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
189
|
+
const installLocation = join(claudeRoot, "plugins", "marketplaces", mp.name);
|
|
190
|
+
if (!known[mp.name]) added.push(mp.name);
|
|
191
|
+
known[mp.name] = {
|
|
192
|
+
source: { source: mp.source.type, repo: mp.source.repo },
|
|
193
|
+
installLocation,
|
|
194
|
+
lastUpdated: new Date().toISOString(),
|
|
195
|
+
};
|
|
196
|
+
if (existsSync(installLocation)) {
|
|
197
|
+
try {
|
|
198
|
+
rmSync(installLocation, { recursive: true, force: true });
|
|
199
|
+
} catch {
|
|
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.
|
|
203
|
+
}
|
|
186
204
|
}
|
|
187
205
|
}
|
|
188
|
-
|
|
206
|
+
writeJSON(path, known);
|
|
189
207
|
return { added, total: MARKETPLACES.length };
|
|
190
208
|
}
|
|
191
209
|
|
|
192
210
|
function ensurePluginsInstalled(claudeRoot) {
|
|
193
|
-
//
|
|
194
|
-
//
|
|
195
|
-
//
|
|
211
|
+
// Always reset the Shop OS-required plugin entries to a pending user-scope
|
|
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.
|
|
217
|
+
//
|
|
218
|
+
// This wipes any project-scope variants of these specific plugin ids — that's
|
|
219
|
+
// intentional. Shop OS is meant to be enabled at user scope so the same
|
|
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.
|
|
196
225
|
const path = join(claudeRoot, "plugins", "installed_plugins.json");
|
|
197
226
|
const existing = readJSON(path, { version: 2, plugins: {} });
|
|
198
227
|
if (!existing.plugins) existing.plugins = {};
|
|
199
228
|
const installedAt = new Date().toISOString();
|
|
200
|
-
|
|
229
|
+
const queued = [];
|
|
201
230
|
for (const id of PLUGINS_TO_ENABLE) {
|
|
202
|
-
if (!existing.plugins[id])
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
changed = true;
|
|
214
|
-
}
|
|
231
|
+
if (!existing.plugins[id]) queued.push(id);
|
|
232
|
+
existing.plugins[id] = [
|
|
233
|
+
{
|
|
234
|
+
scope: "user",
|
|
235
|
+
installPath: null, // filled in by Claude Code on next marketplace sync
|
|
236
|
+
version: "pending",
|
|
237
|
+
installedAt,
|
|
238
|
+
lastUpdated: installedAt,
|
|
239
|
+
gitCommitSha: "pending-sync",
|
|
240
|
+
},
|
|
241
|
+
];
|
|
215
242
|
}
|
|
216
|
-
|
|
217
|
-
return
|
|
243
|
+
writeJSON(path, existing);
|
|
244
|
+
return { queued, total: PLUGINS_TO_ENABLE.length };
|
|
218
245
|
}
|
|
219
246
|
|
|
220
247
|
function enableForVault(vaultPath) {
|
|
@@ -233,6 +260,7 @@ function createVaultClaudeMd(vaultPath, license) {
|
|
|
233
260
|
if (existsSync(claudeMd)) return false; // do not overwrite an existing vault
|
|
234
261
|
const content = `---
|
|
235
262
|
os-mode: business
|
|
263
|
+
bp-setup-state: pending
|
|
236
264
|
license-customer: ${license.customer}
|
|
237
265
|
license-product: ${license.product}
|
|
238
266
|
installed-at: ${new Date().toISOString()}
|
|
@@ -590,12 +618,12 @@ async function main() {
|
|
|
590
618
|
}
|
|
591
619
|
|
|
592
620
|
print(dim(" [2/6] Enabling plugins for installation"));
|
|
593
|
-
const
|
|
594
|
-
if (
|
|
595
|
-
for (const id of PLUGINS_TO_ENABLE) ok(`Queued plugin: ${id}`);
|
|
596
|
-
info("Claude Code will sync the actual plugin files from the marketplaces on next launch.");
|
|
597
|
-
} else {
|
|
621
|
+
const pluginsResult = ensurePluginsInstalled(claudeRoot);
|
|
622
|
+
if (pluginsResult.queued.length === 0) {
|
|
598
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.");
|
|
599
627
|
}
|
|
600
628
|
|
|
601
629
|
print(dim(` [3/6] ${isExisting ? "Configuring" : "Creating"} vault at ${vaultPath}`));
|