@blueprintit/shop-os-install 0.5.5 → 0.5.7

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.
@@ -0,0 +1,179 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Shop OS skills updater.
4
+ *
5
+ * Pulls the latest skills from GitHub without re-running the full installer.
6
+ * Safe to run at any time — does not touch your vault or license.
7
+ *
8
+ * Mac / Linux:
9
+ * npx -y --package=@blueprintit/shop-os-install shop-os-update
10
+ *
11
+ * Windows (PowerShell):
12
+ * npx -y --package=@blueprintit/shop-os-install shop-os-update
13
+ */
14
+
15
+ import { homedir } from "node:os";
16
+ import { join, dirname } from "node:path";
17
+ import { spawnSync } from "node:child_process";
18
+ import {
19
+ existsSync,
20
+ mkdirSync,
21
+ readFileSync,
22
+ rmSync,
23
+ writeFileSync,
24
+ } from "node:fs";
25
+ import { stdout, stderr, exit } from "node:process";
26
+
27
+ // ---------- output helpers ----------
28
+
29
+ const SUPPORTS_COLOR = stdout.isTTY && !process.env.NO_COLOR;
30
+ const c = (code, s) => (SUPPORTS_COLOR ? `\x1b[${code}m${s}\x1b[0m` : s);
31
+ const dim = (s) => c("2", s);
32
+ const bold = (s) => c("1", s);
33
+ const green = (s) => c("32", s);
34
+ const yellow = (s) => c("33", s);
35
+ const red = (s) => c("31", s);
36
+ const cyan = (s) => c("36", s);
37
+
38
+ const print = (msg = "") => stdout.write(msg + "\n");
39
+ const warn = (msg) => stderr.write(yellow("! ") + msg + "\n");
40
+ const fail = (msg) => { stderr.write(red("✗ ") + msg + "\n"); exit(1); };
41
+ const ok = (msg) => print(" " + green("✓") + " " + msg);
42
+ const info = (msg) => print(" " + dim("·") + " " + msg);
43
+
44
+ // ---------- helpers ----------
45
+
46
+ function readJSON(path, fallback) {
47
+ if (!existsSync(path)) return fallback;
48
+ try { return JSON.parse(readFileSync(path, "utf8")); }
49
+ catch { return fallback; }
50
+ }
51
+
52
+ function writeJSON(path, obj) {
53
+ mkdirSync(dirname(path), { recursive: true });
54
+ writeFileSync(path, JSON.stringify(obj, null, 2) + "\n", "utf8");
55
+ }
56
+
57
+ // ---------- main ----------
58
+
59
+ function banner() {
60
+ [
61
+ "",
62
+ bold(" ╔════════════════════════════════════════════════════════════╗"),
63
+ bold(" ║ ║"),
64
+ bold(" ║ ") + cyan("Shop OS Skills Updater") + bold(" ║"),
65
+ bold(" ║ ") + dim("Pull the latest skills from Blueprint IT") + bold(" ║"),
66
+ bold(" ║ ║"),
67
+ bold(" ╚════════════════════════════════════════════════════════════╝"),
68
+ "",
69
+ ].forEach((l) => print(l));
70
+ }
71
+
72
+ function preflight() {
73
+ const major = Number(process.versions.node.split(".")[0]);
74
+ if (major < 18) fail(`Node.js 18+ required. You have ${process.version}.`);
75
+
76
+ const probe = spawnSync(
77
+ process.platform === "win32" ? "where" : "which",
78
+ ["claude"],
79
+ { stdio: "ignore", shell: false },
80
+ );
81
+ if (probe.status !== 0) {
82
+ fail("Claude Code not found. Make sure it is installed and on your PATH.");
83
+ }
84
+
85
+ return join(homedir(), ".claude");
86
+ }
87
+
88
+ function refreshMarketplace(claudeRoot) {
89
+ const installLocation = join(claudeRoot, "plugins", "marketplaces", "blueprint-skills");
90
+ const repoUrl = "https://github.com/blueprintit-ai/blueprint-skills.git";
91
+
92
+ if (existsSync(join(installLocation, ".git"))) {
93
+ const fetch = spawnSync("git", ["fetch", "origin", "main", "--depth=1"], {
94
+ cwd: installLocation,
95
+ stdio: "ignore",
96
+ });
97
+ if (fetch.status === 0) {
98
+ const reset = spawnSync("git", ["reset", "--hard", "FETCH_HEAD"], {
99
+ cwd: installLocation,
100
+ stdio: "ignore",
101
+ });
102
+ if (reset.status === 0) {
103
+ ok("Skills pulled from GitHub");
104
+ return;
105
+ }
106
+ }
107
+ // fetch/reset failed — wipe and re-clone
108
+ warn("git pull failed, re-cloning marketplace...");
109
+ try { rmSync(installLocation, { recursive: true, force: true }); } catch { /* best-effort */ }
110
+ } else {
111
+ info("Marketplace not found locally — cloning fresh...");
112
+ }
113
+
114
+ mkdirSync(dirname(installLocation), { recursive: true });
115
+ const clone = spawnSync("git", ["clone", "--depth=1", repoUrl, installLocation], {
116
+ stdio: "ignore",
117
+ });
118
+ if (clone.status !== 0) fail("Could not reach GitHub. Check your internet connection and try again.");
119
+ ok("Skills cloned from GitHub");
120
+ }
121
+
122
+ function wipePluginCache(claudeRoot) {
123
+ const cacheDir = join(claudeRoot, "plugins", "cache", "blueprint-skills", "obsidian");
124
+ if (existsSync(cacheDir)) {
125
+ try {
126
+ rmSync(cacheDir, { recursive: true, force: true });
127
+ ok("Plugin cache cleared");
128
+ } catch {
129
+ warn("Could not clear plugin cache — Claude Code may load a stale version. Try restarting Claude Code twice.");
130
+ }
131
+ } else {
132
+ ok("Plugin cache already clean");
133
+ }
134
+ }
135
+
136
+ function resetPluginEntry(claudeRoot) {
137
+ const pluginsPath = join(claudeRoot, "plugins", "installed_plugins.json");
138
+ const data = readJSON(pluginsPath, { version: 2, plugins: {} });
139
+ if (!data.plugins) data.plugins = {};
140
+
141
+ const id = "obsidian@blueprint-skills";
142
+ const now = new Date().toISOString();
143
+
144
+ data.plugins[id] = [
145
+ {
146
+ scope: "user",
147
+ installPath: null,
148
+ version: "pending",
149
+ installedAt: data.plugins[id]?.[0]?.installedAt ?? now,
150
+ lastUpdated: now,
151
+ gitCommitSha: "pending-sync",
152
+ },
153
+ ];
154
+
155
+ writeJSON(pluginsPath, data);
156
+ ok("Plugin marked for re-install on next Claude Code launch");
157
+ }
158
+
159
+ banner();
160
+ print(dim(" Updating Shop OS skills. Your vault and license are not affected.\n"));
161
+
162
+ print(dim(" [1/3] Refreshing skill files from GitHub"));
163
+ const claudeRoot = preflight();
164
+ refreshMarketplace(claudeRoot);
165
+
166
+ print("");
167
+ print(dim(" [2/3] Clearing plugin cache"));
168
+ wipePluginCache(claudeRoot);
169
+
170
+ print("");
171
+ print(dim(" [3/3] Resetting plugin entry"));
172
+ resetPluginEntry(claudeRoot);
173
+
174
+ print("");
175
+ print(green(" ✓ Update complete."));
176
+ print("");
177
+ print(" " + bold("Restart Claude Code") + " to load the updated skills.");
178
+ print(" Your vault files, license key, and settings are unchanged.");
179
+ print("");
package/package.json CHANGED
@@ -1,10 +1,11 @@
1
1
  {
2
2
  "name": "@blueprintit/shop-os-install",
3
- "version": "0.5.5",
3
+ "version": "0.5.7",
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": {
7
- "shop-os-install": "./bin/shop-os-install.js"
7
+ "shop-os-install": "bin/shop-os-install.js",
8
+ "shop-os-update": "bin/shop-os-update.js"
8
9
  },
9
10
  "files": [
10
11
  "bin",