cascivo 0.1.4 → 0.2.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.
@@ -0,0 +1,179 @@
1
+ import { r as writeFileSafe } from "./fs-m7ZvuBBm.mjs";
2
+ import { join, resolve } from "node:path";
3
+ import { existsSync } from "node:fs";
4
+ import { readFile } from "node:fs/promises";
5
+ //#region src/commands/template-init.ts
6
+ function pascal(name) {
7
+ return name.split(/[-_/]/).filter(Boolean).map((s) => s.charAt(0).toUpperCase() + s.slice(1)).join("");
8
+ }
9
+ function rawUrl(repo, path) {
10
+ if (!repo) return path;
11
+ return `https://raw.githubusercontent.com/${repo}/main/${path}`;
12
+ }
13
+ function pageSource(name, components) {
14
+ const comp = pascal(name);
15
+ return `${components.length > 0 ? `// Components installed via the template's registryDependencies:\n// ${components.join(", ")}\n` : ""}import './${name}.module.css'
16
+
17
+ /**
18
+ * ${comp} template page. Owned, copy-paste source — adapt freely.
19
+ * Presentational only: no useState/useEffect (cascade house rules).
20
+ */
21
+ export function ${comp}Page() {
22
+ return (
23
+ <main className="${name}-page">
24
+ <h1>${comp}</h1>
25
+ {/* Compose the template's components here. */}
26
+ </main>
27
+ )
28
+ }
29
+ `;
30
+ }
31
+ function cssSource(name) {
32
+ return `@layer components {
33
+ .${name}-page {
34
+ display: grid;
35
+ gap: var(--cascivo-space-4, 1rem);
36
+ padding: var(--cascivo-space-4, 1rem);
37
+ }
38
+ }
39
+ `;
40
+ }
41
+ function fixturesSource(name) {
42
+ return `/** Mock data for the ${name} template. Replace with your real source. */
43
+ export const ${name.replace(/-/g, "_")}Fixtures = {
44
+ items: [],
45
+ }
46
+ `;
47
+ }
48
+ function templateMetaSource(meta) {
49
+ return `import type { TemplateMeta } from '@cascivo/registry'
50
+
51
+ export const meta: TemplateMeta = ${JSON.stringify(meta, null, 2)}
52
+ `;
53
+ }
54
+ /**
55
+ * Build the files + registry item for a new template. Pure — no I/O — so it can
56
+ * be unit-tested. The caller writes the files and merges the item into
57
+ * `cascade-registry.json`.
58
+ */
59
+ function buildTemplateScaffold(opts) {
60
+ const { name, category, framework, components, repo, license, author } = opts;
61
+ const dir = `src/${name}`;
62
+ const pageTarget = `src/pages/${name}.tsx`;
63
+ const cssTarget = `src/pages/${name}.module.css`;
64
+ const fixturesTarget = `src/fixtures/${name}.ts`;
65
+ const files = [
66
+ {
67
+ path: `${dir}/${name}.tsx`,
68
+ contents: pageSource(name, components)
69
+ },
70
+ {
71
+ path: `${dir}/${name}.module.css`,
72
+ contents: cssSource(name)
73
+ },
74
+ {
75
+ path: `${dir}/fixtures.ts`,
76
+ contents: fixturesSource(name)
77
+ }
78
+ ];
79
+ const meta = {
80
+ intent: `${pascal(name)} template`,
81
+ framework,
82
+ category,
83
+ screenshots: [{
84
+ light: rawUrl(repo, `screenshots/${name}-light.png`),
85
+ alt: `${name} preview (light)`
86
+ }],
87
+ fileRoles: {
88
+ [pageTarget]: "page",
89
+ [cssTarget]: "asset",
90
+ [fixturesTarget]: "fixture"
91
+ },
92
+ pages: [{
93
+ name: pascal(name),
94
+ target: pageTarget
95
+ }]
96
+ };
97
+ const item = {
98
+ schemaVersion: 2,
99
+ name,
100
+ type: "template",
101
+ description: `${pascal(name)} template`,
102
+ category,
103
+ version: "0.1.0",
104
+ license,
105
+ ...author ? { author } : {},
106
+ ...repo ? { homepage: `https://github.com/${repo}` } : {},
107
+ files: [
108
+ {
109
+ url: rawUrl(repo, `${dir}/${name}.tsx`),
110
+ target: pageTarget
111
+ },
112
+ {
113
+ url: rawUrl(repo, `${dir}/${name}.module.css`),
114
+ target: cssTarget
115
+ },
116
+ {
117
+ url: rawUrl(repo, `${dir}/fixtures.ts`),
118
+ target: fixturesTarget
119
+ }
120
+ ],
121
+ dependencies: [],
122
+ registryDependencies: components,
123
+ tags: [category, "template"],
124
+ meta
125
+ };
126
+ files.push({
127
+ path: `${dir}/${name}.template.ts`,
128
+ contents: templateMetaSource(meta)
129
+ });
130
+ return {
131
+ files,
132
+ item
133
+ };
134
+ }
135
+ function flag(args, key) {
136
+ const eq = args.find((a) => a.startsWith(`--${key}=`));
137
+ if (eq) return eq.slice(key.length + 3);
138
+ const idx = args.indexOf(`--${key}`);
139
+ const next = idx !== -1 ? args[idx + 1] : void 0;
140
+ return next && !next.startsWith("--") ? next : void 0;
141
+ }
142
+ async function templateInit(args, cwd = process.cwd()) {
143
+ const name = args.find((a) => !a.startsWith("-"));
144
+ if (!name) {
145
+ console.error("Usage: cascivo template init <name> [--category dashboard] [--framework react-vite] [--components card,line-chart] [--repo owner/repo]");
146
+ process.exitCode = 1;
147
+ return;
148
+ }
149
+ const componentsArg = flag(args, "components");
150
+ const opts = {
151
+ name,
152
+ category: flag(args, "category") ?? "misc",
153
+ framework: flag(args, "framework") ?? "react-vite",
154
+ components: componentsArg ? componentsArg.split(",").map((c) => c.trim()).filter(Boolean) : [],
155
+ license: flag(args, "license") ?? "MIT",
156
+ ...flag(args, "repo") ? { repo: flag(args, "repo") } : {},
157
+ ...flag(args, "author") ? { author: flag(args, "author") } : {}
158
+ };
159
+ const { files, item } = buildTemplateScaffold(opts);
160
+ for (const file of files) await writeFileSafe(join(cwd, file.path), file.contents);
161
+ const registryPath = resolve(cwd, "cascivo-registry.json");
162
+ let index;
163
+ if (existsSync(registryPath)) {
164
+ index = JSON.parse(await readFile(registryPath, "utf8"));
165
+ index.items = (index.items ?? []).filter((i) => i.name !== item.name);
166
+ index.items.push(item);
167
+ } else index = {
168
+ schemaVersion: 2,
169
+ name: opts.repo ?? name,
170
+ items: [item]
171
+ };
172
+ await writeFileSafe(registryPath, `${JSON.stringify(index, null, 2)}\n`);
173
+ console.log(`Scaffolded template "${name}" (${files.length} files + cascivo-registry.json).`);
174
+ console.log("Next: fill in the page, capture screenshots, then `cascivo registry build`.");
175
+ }
176
+ //#endregion
177
+ export { templateInit };
178
+
179
+ //# sourceMappingURL=template-init-DGEgatij.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"template-init-DGEgatij.mjs","names":[],"sources":["../src/commands/template-init.ts"],"sourcesContent":["import { existsSync } from 'node:fs'\nimport { readFile } from 'node:fs/promises'\nimport { join, resolve } from 'node:path'\nimport type { RegistryItem, TemplateMeta } from '@cascivo/registry'\nimport { writeFileSafe } from '../utils/fs.js'\n\nexport interface TemplateInitOptions {\n /** kebab-case template name (also the source folder + registry item name). */\n name: string\n /** Discovery category, e.g. \"dashboard\". */\n category: string\n /** Target framework for the page source. */\n framework: TemplateMeta['framework']\n /** Components the template composes (registry names). */\n components: string[]\n /** Repo owner/name used to build raw file URLs and the homepage. */\n repo?: string\n /** License SPDX id. */\n license: string\n /** Author. */\n author?: string\n}\n\nexport interface ScaffoldFile {\n /** Path relative to the template repo root. */\n path: string\n contents: string\n}\n\nfunction pascal(name: string): string {\n return name\n .split(/[-_/]/)\n .filter(Boolean)\n .map((s) => s.charAt(0).toUpperCase() + s.slice(1))\n .join('')\n}\n\nfunction rawUrl(repo: string | undefined, path: string): string {\n if (!repo) return path\n return `https://raw.githubusercontent.com/${repo}/main/${path}`\n}\n\nfunction pageSource(name: string, components: string[]): string {\n const comp = pascal(name)\n const importLine =\n components.length > 0\n ? `// Components installed via the template's registryDependencies:\\n// ${components.join(', ')}\\n`\n : ''\n return `${importLine}import './${name}.module.css'\n\n/**\n * ${comp} template page. Owned, copy-paste source — adapt freely.\n * Presentational only: no useState/useEffect (cascade house rules).\n */\nexport function ${comp}Page() {\n return (\n <main className=\"${name}-page\">\n <h1>${comp}</h1>\n {/* Compose the template's components here. */}\n </main>\n )\n}\n`\n}\n\nfunction cssSource(name: string): string {\n return `@layer components {\n .${name}-page {\n display: grid;\n gap: var(--cascivo-space-4, 1rem);\n padding: var(--cascivo-space-4, 1rem);\n }\n}\n`\n}\n\nfunction fixturesSource(name: string): string {\n return `/** Mock data for the ${name} template. Replace with your real source. */\nexport const ${name.replace(/-/g, '_')}Fixtures = {\n items: [],\n}\n`\n}\n\nfunction templateMetaSource(meta: TemplateMeta): string {\n return `import type { TemplateMeta } from '@cascivo/registry'\n\nexport const meta: TemplateMeta = ${JSON.stringify(meta, null, 2)}\n`\n}\n\n/**\n * Build the files + registry item for a new template. Pure — no I/O — so it can\n * be unit-tested. The caller writes the files and merges the item into\n * `cascade-registry.json`.\n */\nexport function buildTemplateScaffold(opts: TemplateInitOptions): {\n files: ScaffoldFile[]\n item: RegistryItem\n} {\n const { name, category, framework, components, repo, license, author } = opts\n const dir = `src/${name}`\n const pageTarget = `src/pages/${name}.tsx`\n const cssTarget = `src/pages/${name}.module.css`\n const fixturesTarget = `src/fixtures/${name}.ts`\n\n const files: ScaffoldFile[] = [\n { path: `${dir}/${name}.tsx`, contents: pageSource(name, components) },\n { path: `${dir}/${name}.module.css`, contents: cssSource(name) },\n { path: `${dir}/fixtures.ts`, contents: fixturesSource(name) },\n ]\n\n const meta: TemplateMeta = {\n intent: `${pascal(name)} template`,\n framework,\n category,\n screenshots: [\n { light: rawUrl(repo, `screenshots/${name}-light.png`), alt: `${name} preview (light)` },\n ],\n fileRoles: {\n [pageTarget]: 'page',\n [cssTarget]: 'asset',\n [fixturesTarget]: 'fixture',\n },\n pages: [{ name: pascal(name), target: pageTarget }],\n }\n\n const item: RegistryItem = {\n schemaVersion: 2,\n name,\n type: 'template',\n description: `${pascal(name)} template`,\n category,\n version: '0.1.0',\n license,\n ...(author ? { author } : {}),\n ...(repo ? { homepage: `https://github.com/${repo}` } : {}),\n files: [\n { url: rawUrl(repo, `${dir}/${name}.tsx`), target: pageTarget },\n { url: rawUrl(repo, `${dir}/${name}.module.css`), target: cssTarget },\n { url: rawUrl(repo, `${dir}/fixtures.ts`), target: fixturesTarget },\n ],\n dependencies: [],\n registryDependencies: components,\n tags: [category, 'template'],\n meta,\n }\n\n files.push({ path: `${dir}/${name}.template.ts`, contents: templateMetaSource(meta) })\n\n return { files, item }\n}\n\nfunction flag(args: string[], key: string): string | undefined {\n const eq = args.find((a) => a.startsWith(`--${key}=`))\n if (eq) return eq.slice(key.length + 3)\n const idx = args.indexOf(`--${key}`)\n const next = idx !== -1 ? args[idx + 1] : undefined\n return next && !next.startsWith('--') ? next : undefined\n}\n\nexport async function templateInit(args: string[], cwd: string = process.cwd()): Promise<void> {\n const name = args.find((a) => !a.startsWith('-'))\n if (!name) {\n console.error(\n 'Usage: cascivo template init <name> [--category dashboard] [--framework react-vite] [--components card,line-chart] [--repo owner/repo]',\n )\n process.exitCode = 1\n return\n }\n\n const componentsArg = flag(args, 'components')\n const opts: TemplateInitOptions = {\n name,\n category: flag(args, 'category') ?? 'misc',\n framework: (flag(args, 'framework') as TemplateMeta['framework']) ?? 'react-vite',\n components: componentsArg\n ? componentsArg\n .split(',')\n .map((c) => c.trim())\n .filter(Boolean)\n : [],\n license: flag(args, 'license') ?? 'MIT',\n ...(flag(args, 'repo') ? { repo: flag(args, 'repo')! } : {}),\n ...(flag(args, 'author') ? { author: flag(args, 'author')! } : {}),\n }\n\n const { files, item } = buildTemplateScaffold(opts)\n\n for (const file of files) {\n await writeFileSafe(join(cwd, file.path), file.contents)\n }\n\n // Merge into cascivo-registry.json (create if missing).\n const registryPath = resolve(cwd, 'cascivo-registry.json')\n let index: { schemaVersion: 2; name: string; items: RegistryItem[] }\n if (existsSync(registryPath)) {\n index = JSON.parse(await readFile(registryPath, 'utf8')) as typeof index\n index.items = (index.items ?? []).filter((i) => i.name !== item.name)\n index.items.push(item)\n } else {\n index = { schemaVersion: 2, name: opts.repo ?? name, items: [item] }\n }\n await writeFileSafe(registryPath, `${JSON.stringify(index, null, 2)}\\n`)\n\n console.log(`Scaffolded template \"${name}\" (${files.length} files + cascivo-registry.json).`)\n console.log('Next: fill in the page, capture screenshots, then `cascivo registry build`.')\n}\n"],"mappings":";;;;;AA6BA,SAAS,OAAO,MAAsB;CACpC,OAAO,KACJ,MAAM,OAAO,CAAC,CACd,OAAO,OAAO,CAAC,CACf,KAAK,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,YAAY,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,CAClD,KAAK,EAAE;AACZ;AAEA,SAAS,OAAO,MAA0B,MAAsB;CAC9D,IAAI,CAAC,MAAM,OAAO;CAClB,OAAO,qCAAqC,KAAK,QAAQ;AAC3D;AAEA,SAAS,WAAW,MAAc,YAA8B;CAC9D,MAAM,OAAO,OAAO,IAAI;CAKxB,OAAO,GAHL,WAAW,SAAS,IAChB,wEAAwE,WAAW,KAAK,IAAI,EAAE,MAC9F,GACe,YAAY,KAAK;;;KAGnC,KAAK;;;kBAGQ,KAAK;;uBAEA,KAAK;YAChB,KAAK;;;;;;AAMjB;AAEA,SAAS,UAAU,MAAsB;CACvC,OAAO;KACJ,KAAK;;;;;;;AAOV;AAEA,SAAS,eAAe,MAAsB;CAC5C,OAAO,yBAAyB,KAAK;eACxB,KAAK,QAAQ,MAAM,GAAG,EAAE;;;;AAIvC;AAEA,SAAS,mBAAmB,MAA4B;CACtD,OAAO;;oCAE2B,KAAK,UAAU,MAAM,MAAM,CAAC,EAAE;;AAElE;;;;;;AAOA,SAAgB,sBAAsB,MAGpC;CACA,MAAM,EAAE,MAAM,UAAU,WAAW,YAAY,MAAM,SAAS,WAAW;CACzE,MAAM,MAAM,OAAO;CACnB,MAAM,aAAa,aAAa,KAAK;CACrC,MAAM,YAAY,aAAa,KAAK;CACpC,MAAM,iBAAiB,gBAAgB,KAAK;CAE5C,MAAM,QAAwB;EAC5B;GAAE,MAAM,GAAG,IAAI,GAAG,KAAK;GAAO,UAAU,WAAW,MAAM,UAAU;EAAE;EACrE;GAAE,MAAM,GAAG,IAAI,GAAG,KAAK;GAAc,UAAU,UAAU,IAAI;EAAE;EAC/D;GAAE,MAAM,GAAG,IAAI;GAAe,UAAU,eAAe,IAAI;EAAE;CAC/D;CAEA,MAAM,OAAqB;EACzB,QAAQ,GAAG,OAAO,IAAI,EAAE;EACxB;EACA;EACA,aAAa,CACX;GAAE,OAAO,OAAO,MAAM,eAAe,KAAK,WAAW;GAAG,KAAK,GAAG,KAAK;EAAkB,CACzF;EACA,WAAW;IACR,aAAa;IACb,YAAY;IACZ,iBAAiB;EACpB;EACA,OAAO,CAAC;GAAE,MAAM,OAAO,IAAI;GAAG,QAAQ;EAAW,CAAC;CACpD;CAEA,MAAM,OAAqB;EACzB,eAAe;EACf;EACA,MAAM;EACN,aAAa,GAAG,OAAO,IAAI,EAAE;EAC7B;EACA,SAAS;EACT;EACA,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;EAC3B,GAAI,OAAO,EAAE,UAAU,sBAAsB,OAAO,IAAI,CAAC;EACzD,OAAO;GACL;IAAE,KAAK,OAAO,MAAM,GAAG,IAAI,GAAG,KAAK,KAAK;IAAG,QAAQ;GAAW;GAC9D;IAAE,KAAK,OAAO,MAAM,GAAG,IAAI,GAAG,KAAK,YAAY;IAAG,QAAQ;GAAU;GACpE;IAAE,KAAK,OAAO,MAAM,GAAG,IAAI,aAAa;IAAG,QAAQ;GAAe;EACpE;EACA,cAAc,CAAC;EACf,sBAAsB;EACtB,MAAM,CAAC,UAAU,UAAU;EAC3B;CACF;CAEA,MAAM,KAAK;EAAE,MAAM,GAAG,IAAI,GAAG,KAAK;EAAe,UAAU,mBAAmB,IAAI;CAAE,CAAC;CAErF,OAAO;EAAE;EAAO;CAAK;AACvB;AAEA,SAAS,KAAK,MAAgB,KAAiC;CAC7D,MAAM,KAAK,KAAK,MAAM,MAAM,EAAE,WAAW,KAAK,IAAI,EAAE,CAAC;CACrD,IAAI,IAAI,OAAO,GAAG,MAAM,IAAI,SAAS,CAAC;CACtC,MAAM,MAAM,KAAK,QAAQ,KAAK,KAAK;CACnC,MAAM,OAAO,QAAQ,KAAK,KAAK,MAAM,KAAK,KAAA;CAC1C,OAAO,QAAQ,CAAC,KAAK,WAAW,IAAI,IAAI,OAAO,KAAA;AACjD;AAEA,eAAsB,aAAa,MAAgB,MAAc,QAAQ,IAAI,GAAkB;CAC7F,MAAM,OAAO,KAAK,MAAM,MAAM,CAAC,EAAE,WAAW,GAAG,CAAC;CAChD,IAAI,CAAC,MAAM;EACT,QAAQ,MACN,wIACF;EACA,QAAQ,WAAW;EACnB;CACF;CAEA,MAAM,gBAAgB,KAAK,MAAM,YAAY;CAC7C,MAAM,OAA4B;EAChC;EACA,UAAU,KAAK,MAAM,UAAU,KAAK;EACpC,WAAY,KAAK,MAAM,WAAW,KAAmC;EACrE,YAAY,gBACR,cACG,MAAM,GAAG,CAAC,CACV,KAAK,MAAM,EAAE,KAAK,CAAC,CAAC,CACpB,OAAO,OAAO,IACjB,CAAC;EACL,SAAS,KAAK,MAAM,SAAS,KAAK;EAClC,GAAI,KAAK,MAAM,MAAM,IAAI,EAAE,MAAM,KAAK,MAAM,MAAM,EAAG,IAAI,CAAC;EAC1D,GAAI,KAAK,MAAM,QAAQ,IAAI,EAAE,QAAQ,KAAK,MAAM,QAAQ,EAAG,IAAI,CAAC;CAClE;CAEA,MAAM,EAAE,OAAO,SAAS,sBAAsB,IAAI;CAElD,KAAK,MAAM,QAAQ,OACjB,MAAM,cAAc,KAAK,KAAK,KAAK,IAAI,GAAG,KAAK,QAAQ;CAIzD,MAAM,eAAe,QAAQ,KAAK,uBAAuB;CACzD,IAAI;CACJ,IAAI,WAAW,YAAY,GAAG;EAC5B,QAAQ,KAAK,MAAM,MAAM,SAAS,cAAc,MAAM,CAAC;EACvD,MAAM,SAAS,MAAM,SAAS,CAAC,EAAA,CAAG,QAAQ,MAAM,EAAE,SAAS,KAAK,IAAI;EACpE,MAAM,MAAM,KAAK,IAAI;CACvB,OACE,QAAQ;EAAE,eAAe;EAAG,MAAM,KAAK,QAAQ;EAAM,OAAO,CAAC,IAAI;CAAE;CAErE,MAAM,cAAc,cAAc,GAAG,KAAK,UAAU,OAAO,MAAM,CAAC,EAAE,GAAG;CAEvE,QAAQ,IAAI,wBAAwB,KAAK,KAAK,MAAM,OAAO,iCAAiC;CAC5F,QAAQ,IAAI,6EAA6E;AAC3F"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cascivo",
3
- "version": "0.1.4",
3
+ "version": "0.2.0",
4
4
  "private": false,
5
5
  "description": "CLI — npx cascivo init / add / list / update",
6
6
  "keywords": [
@@ -42,7 +42,7 @@
42
42
  "provenance": true
43
43
  },
44
44
  "dependencies": {
45
- "@cascivo/registry": "^0.1.2"
45
+ "@cascivo/registry": "^0.1.5"
46
46
  },
47
47
  "devDependencies": {
48
48
  "@types/node": "^25",
package/readme.body.md CHANGED
@@ -3,17 +3,23 @@ The `cascivo` CLI drives the copy-paste workflow — it scaffolds config, copies
3
3
  ## Commands
4
4
 
5
5
  ```sh
6
- npx cascivo init # scaffold cascivo.config.ts + tokens; detects your package manager
7
- cascivo add button card # copy component source from the registry into your project
8
- cascivo add owner/repo/button # install from any third-party registry
9
- cascivo list # list available components
10
- cascivo update # pull newer versions of copied components
11
- cascivo audit --ai # flag hard-coded values, invented props, missing wiring
12
- cascivo build # build a registry from your own components
6
+ npx cascivo create my-app # scaffold a full app — Vite + React, app shell, side nav, theme
7
+ npx cascivo create my-app --template owner/repo/dashboard # …and start from a template
8
+ npx cascivo init # scaffold cascivo.config.ts + tokens; detects your package manager
9
+ cascivo add button card # copy component source from the registry into your project
10
+ cascivo add owner/repo/button # install from any third-party registry
11
+ cascivo add owner/repo/dashboard # install a template (its components + page/fixture files)
12
+ cascivo view owner/repo/dashboard # preview an item (or template) before installing
13
+ cascivo list # list available components
14
+ cascivo update # pull newer versions of copied components
15
+ cascivo audit --ai # flag hard-coded values, invented props, missing wiring
16
+ cascivo build # build a registry from your own components
13
17
  ```
14
18
 
19
+ A **template** is a registry item (`type: "template"`) that bundles a working page with the components it composes (in `registryDependencies`) and its own page/fixture files (each with a `target`). `cascivo add` installs the component closure into your components directory and writes the template's files to their targets; `create --template` does the same into a freshly scaffolded app.
20
+
15
21
  ## How it works
16
22
 
17
- `init` detects npm / pnpm / yarn / bun, writes `cascivo.config.ts`, and wires up the token and theme imports. `add` resolves each component from [`registry.json`](https://github.com/cascivo/cascivo/blob/main/registry.json), fetches its source (TSX + CSS module + manifest) from GitHub raw URLs, and drops it into the path from your config — pulling in any dependencies it needs.
23
+ `create` scaffolds a complete Vite + React + TypeScript app — pre-wired with the cascivo app shell, side navigation, header, and your chosen theme. It asks for a project name, theme, and the nav sections you want, then generates a section component for each. Pass `--theme`, `--sections "Dashboard, Reports"`, or `--yes` to skip the prompts. `init` detects npm / pnpm / yarn / bun, writes `cascivo.config.ts`, and wires up the token and theme imports. `add` resolves each component from [`registry.json`](https://github.com/cascivo/cascivo/blob/main/registry.json), fetches its source (TSX + CSS module + manifest) from GitHub raw URLs, and drops it into the path from your config — pulling in any dependencies it needs.
18
24
 
19
25
  Because the registry model is open, `add owner/repo/component` installs from any compatible registry, not just the first-party one. See the [registry starter](https://github.com/cascivo/cascivo/tree/main/apps/examples/registry-starter) to publish your own.