@calo-design/cli 0.4.3 → 0.4.5
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/cli.js +93 -2
- package/bin/templates/gallery-assets/component-gallery/meal-photo.png +0 -0
- package/bin/templates/gallery-assets/component-gallery/smoothie-photo.png +0 -0
- package/bin/templates/gallery-assets/live-flows/active-subscriber-home/ingredient-penne.png +0 -0
- package/bin/templates/gallery-index.tsx +1678 -0
- package/bin/templates/gallery-suppress.ts +50 -0
- package/package.json +1 -1
package/bin/cli.js
CHANGED
|
@@ -408,6 +408,44 @@ export default function Index() {
|
|
|
408
408
|
`);
|
|
409
409
|
}
|
|
410
410
|
|
|
411
|
+
// The component gallery's routes: a root layout (fonts + providers, no local imports so it's
|
|
412
|
+
// portable) and the @calo/design-system showroom (bundled with the CLI) as the index route.
|
|
413
|
+
// Always (re)written so a `calo-design update` + relaunch also ships the latest showroom.
|
|
414
|
+
function writeGalleryApp(projectRoot) {
|
|
415
|
+
const srcDir = path.join(projectRoot, "src");
|
|
416
|
+
const appDir = path.join(srcDir, "app");
|
|
417
|
+
fs.mkdirSync(appDir, { recursive: true });
|
|
418
|
+
// Silences known non-actionable RNW-on-React-19 dev warnings (nested Pressables, deprecated
|
|
419
|
+
// style props) so the embedded gallery has a clean overlay. Imported first in _layout.
|
|
420
|
+
fs.cpSync(path.join(__dirname, "templates", "gallery-suppress.ts"), path.join(srcDir, "suppress-dev-warnings.ts"));
|
|
421
|
+
fs.writeFileSync(path.join(appDir, "_layout.tsx"), `import "../suppress-dev-warnings";
|
|
422
|
+
import { Stack } from "expo-router";
|
|
423
|
+
import { useFonts } from "expo-font";
|
|
424
|
+
import { CaloBottomSheetProvider, CaloScreen, caloFonts, caloTokens } from "@calo/design-system";
|
|
425
|
+
import { SafeAreaProvider } from "react-native-safe-area-context";
|
|
426
|
+
|
|
427
|
+
export default function Layout() {
|
|
428
|
+
const [loaded] = useFonts(caloFonts);
|
|
429
|
+
return (
|
|
430
|
+
<SafeAreaProvider>
|
|
431
|
+
{loaded ? (
|
|
432
|
+
<CaloBottomSheetProvider>
|
|
433
|
+
<Stack screenOptions={{ headerShown: false, contentStyle: { backgroundColor: caloTokens.color.canvas } }} />
|
|
434
|
+
</CaloBottomSheetProvider>
|
|
435
|
+
) : (
|
|
436
|
+
<CaloScreen />
|
|
437
|
+
)}
|
|
438
|
+
</SafeAreaProvider>
|
|
439
|
+
);
|
|
440
|
+
}
|
|
441
|
+
`);
|
|
442
|
+
const showroom = fs.readFileSync(path.join(__dirname, "templates", "gallery-index.tsx"), "utf8");
|
|
443
|
+
fs.writeFileSync(path.join(appDir, "index.tsx"), showroom);
|
|
444
|
+
// The showroom require()s a few local images (../assets/... from src/app) — ship them too.
|
|
445
|
+
const assetsSrc = path.join(__dirname, "templates", "gallery-assets");
|
|
446
|
+
if (fs.existsSync(assetsSrc)) fs.cpSync(assetsSrc, path.join(projectRoot, "src", "assets"), { recursive: true });
|
|
447
|
+
}
|
|
448
|
+
|
|
411
449
|
function writeGitignore(projectRoot) {
|
|
412
450
|
const gi = path.join(projectRoot, ".gitignore");
|
|
413
451
|
const needed = ["node_modules/", ".expo/", "dist/", "*.log"];
|
|
@@ -551,16 +589,35 @@ async function cmdUpdate() {
|
|
|
551
589
|
// Re-pin when the runtime is fully present OR merely scaffolded (package.json on disk),
|
|
552
590
|
// so a half-installed runtime self-heals via plain `update` instead of being stranded.
|
|
553
591
|
const scaffolded = fs.existsSync(path.join(runtimeDir(), "package.json"));
|
|
592
|
+
// Snapshot the pinned @calo commit SHAs BEFORE re-pinning, so we can tell whether this update
|
|
593
|
+
// actually moved anything. The design system is git-HEAD-tracked (pinned by commit, not by an
|
|
594
|
+
// npm version bump — its package.json version can sit unchanged across many real commits), so
|
|
595
|
+
// the SHA is the true "did anything change" signal.
|
|
596
|
+
const before = installedCaloShas(runtimeDir()) || {};
|
|
597
|
+
let repinned = false;
|
|
554
598
|
if (runtimeExists() || scaffolded || has("--build")) {
|
|
555
599
|
await ensureRuntime({ force: true });
|
|
556
600
|
ok("shared runtime re-pinned — every linked prototype now uses the latest Calo stack");
|
|
601
|
+
repinned = true;
|
|
557
602
|
} else {
|
|
558
603
|
log(c.dim(" No shared runtime yet — run `calo-design init` in a prototype folder to create one."));
|
|
559
604
|
}
|
|
560
|
-
//
|
|
605
|
+
// Only record an update event when the pinned code ACTUALLY changed (or we can't tell / it's a
|
|
606
|
+
// first install). A no-op re-pin — clicking Update when nothing new shipped — writes nothing,
|
|
607
|
+
// so the feed stops filling with identical "updated the design system to 0.2.0" rows.
|
|
608
|
+
const after = installedCaloShas(runtimeDir()) || {};
|
|
609
|
+
const changed = !Object.keys(before).length || JSON.stringify(before) !== JSON.stringify(after);
|
|
610
|
+
if (repinned && !changed) {
|
|
611
|
+
log(c.dim(" Already up to date — nothing new to record in the feed."));
|
|
612
|
+
return;
|
|
613
|
+
}
|
|
614
|
+
// Tag the feed entry with the DS version we floated to (read fresh from disk, not require()'s
|
|
615
|
+
// cache). Bump @calo/design-system's version on real releases (`npm run release` there) to make
|
|
616
|
+
// this number meaningful — the SHA gate above already guarantees it only logs on real change.
|
|
561
617
|
let dsVersion = "";
|
|
562
618
|
try {
|
|
563
|
-
|
|
619
|
+
const pj = JSON.parse(fs.readFileSync(path.join(runtimeDir(), "node_modules", "@calo", "design-system", "package.json"), "utf8"));
|
|
620
|
+
dsVersion = pj.version || "";
|
|
564
621
|
} catch { /* runtime not present — report without a version */ }
|
|
565
622
|
await reportEvent("update", dsVersion);
|
|
566
623
|
}
|
|
@@ -602,6 +659,37 @@ async function cmdFeed() {
|
|
|
602
659
|
for (const e of data.events) log(`${c.dim(e.ts)} ${e.email} ${c.b(e.action)} ${e.target || ""}`);
|
|
603
660
|
}
|
|
604
661
|
|
|
662
|
+
// Serve the component gallery (the @calo/design-system showroom) locally, rendered LIVE from
|
|
663
|
+
// the shared runtime — so `calo-design update` keeps it current (no rebuild/redeploy). Design
|
|
664
|
+
// Kitchen auto-starts this; it also works standalone in a terminal. Runs Metro in the
|
|
665
|
+
// foreground so whoever launched it owns the process lifecycle.
|
|
666
|
+
async function cmdGallery() {
|
|
667
|
+
if (!runtimeExists()) {
|
|
668
|
+
throw new Error("The Calo runtime isn't set up on this machine yet — run `calo-design init` first, then retry.");
|
|
669
|
+
}
|
|
670
|
+
const dir = path.join(designchefHome(), "gallery");
|
|
671
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
672
|
+
// Materialize / refresh a thin project linked to the shared runtime (same machinery as
|
|
673
|
+
// a linked prototype), then swap in the showroom routes.
|
|
674
|
+
writeThinConfigs(dir);
|
|
675
|
+
ensureBabelConfig(dir);
|
|
676
|
+
writeMetroConfig(dir);
|
|
677
|
+
writeGitignore(dir);
|
|
678
|
+
linkNodeModules(dir);
|
|
679
|
+
writeGalleryApp(dir);
|
|
680
|
+
|
|
681
|
+
let port = "8091";
|
|
682
|
+
const pj = args.find((a) => a.startsWith("--port="));
|
|
683
|
+
if (pj) port = pj.slice(7);
|
|
684
|
+
else { const pi = args.indexOf("--port"); if (pi >= 0) port = args[pi + 1] || port; }
|
|
685
|
+
if (!/^\d+$/.test(port)) port = "8091";
|
|
686
|
+
|
|
687
|
+
log(c.b(`\n[gallery] Serving the Calo component gallery on http://localhost:${port}`));
|
|
688
|
+
log(c.dim(` Live from the shared runtime (${tilde(runtimeDir())}) — always the installed @calo/design-system.`));
|
|
689
|
+
log(c.dim(" First launch compiles the design system (~30–60s). Ctrl-C to stop."));
|
|
690
|
+
run("npx", ["expo", "start", "--web", "--port", port], { cwd: dir });
|
|
691
|
+
}
|
|
692
|
+
|
|
605
693
|
function help() {
|
|
606
694
|
log(`${c.b("calo-design")} — one-line setup for Calo design tooling
|
|
607
695
|
|
|
@@ -617,6 +705,8 @@ function help() {
|
|
|
617
705
|
${c.dim(" push --slug x --title \"…\" --owner \"…\" --screenshot path --dry-run --direct")}
|
|
618
706
|
${c.dim("share")} publish THIS web prototype (React/Vite/CRA/Next) to Cloudflare Pages → share link
|
|
619
707
|
${c.dim(" share --slug x --dir dist --build --project calo-prototypes --dry-run")}
|
|
708
|
+
${c.dim("gallery")} serve the @calo/design-system component gallery locally (live from the runtime)
|
|
709
|
+
${c.dim(" gallery --port 8091")}
|
|
620
710
|
|
|
621
711
|
Login is required once before init; the session refreshes automatically.
|
|
622
712
|
init always installs the skill and ensures the shared ds/flows runtime on your machine;
|
|
@@ -636,6 +726,7 @@ function help() {
|
|
|
636
726
|
else if (cmd === "share") await cmdShare(args.slice(1));
|
|
637
727
|
else if (cmd === "feed") await cmdFeed();
|
|
638
728
|
else if (cmd === "whoami") await cmdWhoami();
|
|
729
|
+
else if (cmd === "gallery") await cmdGallery();
|
|
639
730
|
else help();
|
|
640
731
|
} catch (err) {
|
|
641
732
|
// Diagnostics go to stderr so stdout stays pure for machine callers (The Pass parses
|
|
Binary file
|