@calo-design/cli 0.4.0 → 0.4.2

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.
Files changed (2) hide show
  1. package/bin/cli.js +17 -6
  2. package/package.json +13 -5
package/bin/cli.js CHANGED
@@ -148,9 +148,14 @@ async function ensureRuntime({ force } = {}) {
148
148
  ok(`shared runtime ready (${tilde(rt)})`);
149
149
  return;
150
150
  }
151
- log(c.b("\n[runtime] Building the shared Calo runtime (one-time, ~a couple of minutes)"));
151
+ const scaffolded = fs.existsSync(path.join(rt, "package.json"));
152
+ const repin = force && scaffolded && !has("--clean");
153
+ log(c.b(`\n[runtime] ${repin ? "Re-pinning" : "Building"} the shared Calo runtime${repin ? "" : " (one-time, ~a couple of minutes)"}`));
152
154
  fs.mkdirSync(rt, { recursive: true });
153
- if (force) {
155
+ // Re-pin is NON-destructive: `npm install` updates node_modules in place and aborts
156
+ // cleanly on failure (e.g. a peer conflict), so a working shared runtime is never left
157
+ // wiped. `--clean` opts into a from-scratch rebuild for a genuinely corrupted tree.
158
+ if (force && has("--clean")) {
154
159
  fs.rmSync(path.join(rt, "node_modules"), { recursive: true, force: true });
155
160
  try { fs.rmSync(runtimeManifestPath()); } catch {}
156
161
  }
@@ -163,7 +168,7 @@ async function ensureRuntime({ force } = {}) {
163
168
  runtimeManifestPath(),
164
169
  JSON.stringify({ builtAt: new Date().toISOString(), pkgSpecs: PKG_SPECS, peers: PEERS }, null, 2) + "\n"
165
170
  );
166
- ok(`shared runtime built -> ${tilde(rt)}`);
171
+ ok(`shared runtime ${repin ? "re-pinned" : "built"} -> ${tilde(rt)}`);
167
172
  }
168
173
 
169
174
  // ---------------------------------------------------------------- shared helpers
@@ -214,12 +219,14 @@ function scaffoldExpoApp(destDir = process.cwd()) {
214
219
  async function installCaloDeps(cwd) {
215
220
  // Private @calo/* installs authenticate with a short-lived broker-minted token,
216
221
  // injected into git for the npm subprocess only (no gh / PAT / SSH key).
222
+ // --legacy-peer-deps: the Expo/RN dep graph routinely has benign peerOptional conflicts
223
+ // (e.g. overlapping typescript ranges); without it a single conflict ERESOLVEs the whole install.
217
224
  const env = gitTokenEnv(await githubToken());
218
- runWithRetry("npm", ["install", ...PKG_SPECS], 3, { cwd, env });
225
+ runWithRetry("npm", ["install", ...PKG_SPECS, "--legacy-peer-deps"], 3, { cwd, env });
219
226
  if (isExpoProject(cwd)) run("npx", ["expo", "install", ...PEERS, "expo-font"], { cwd });
220
227
  else {
221
228
  warn("non-Expo project — installing latest peers; pin them to match your React Native version if needed.");
222
- run("npm", ["install", ...PEERS], { cwd });
229
+ run("npm", ["install", ...PEERS, "--legacy-peer-deps"], { cwd });
223
230
  }
224
231
  }
225
232
 
@@ -470,7 +477,10 @@ async function cmdUpdate() {
470
477
  await ensureLoggedIn();
471
478
  await installSkill();
472
479
  ok("skill updated to latest");
473
- if (runtimeExists() || has("--build")) {
480
+ // Re-pin when the runtime is fully present OR merely scaffolded (package.json on disk),
481
+ // so a half-installed runtime self-heals via plain `update` instead of being stranded.
482
+ const scaffolded = fs.existsSync(path.join(runtimeDir(), "package.json"));
483
+ if (runtimeExists() || scaffolded || has("--build")) {
474
484
  await ensureRuntime({ force: true });
475
485
  ok("shared runtime re-pinned — every linked prototype now uses the latest Calo stack");
476
486
  } else {
@@ -487,6 +497,7 @@ function help() {
487
497
  ${c.dim("init --isolated")} install the Calo stack into THIS folder (no shared runtime)
488
498
  ${c.dim("init --skip-packages")} skill only (no runtime)
489
499
  ${c.dim("update")} refresh the skill + re-pin the shared runtime (all linked prototypes float to latest)
500
+ ${c.dim(" update --clean")} re-pin with a from-scratch runtime rebuild (only if the tree is corrupted)
490
501
  ${c.dim("logout")} forget the saved Calo session
491
502
  ${c.dim("push")} publish THIS prototype to the Calo Mirror (login only — no EAS/Tigris creds needed)
492
503
  ${c.dim(" push --slug x --title \"…\" --owner \"…\" --screenshot path --dry-run --direct")}
package/package.json CHANGED
@@ -1,10 +1,18 @@
1
1
  {
2
2
  "name": "@calo-design/cli",
3
- "version": "0.4.0",
3
+ "version": "0.4.2",
4
4
  "description": "One-line setup for Calo design tooling: logs in with your Calo email and installs the calo-design skill + design-system packages. No GitHub account needed.",
5
- "bin": { "calo-design": "bin/cli.js" },
6
- "files": ["bin"],
7
- "publishConfig": { "access": "public" },
5
+ "bin": {
6
+ "calo-design": "bin/cli.js"
7
+ },
8
+ "files": [
9
+ "bin"
10
+ ],
11
+ "publishConfig": {
12
+ "access": "public"
13
+ },
8
14
  "license": "UNLICENSED",
9
- "engines": { "node": ">=18" }
15
+ "engines": {
16
+ "node": ">=18"
17
+ }
10
18
  }