@archetypeai/ds-cli 0.3.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.
Files changed (37) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +123 -0
  3. package/bin.js +77 -0
  4. package/commands/add.js +42 -0
  5. package/commands/create.js +238 -0
  6. package/commands/init.js +199 -0
  7. package/files/AGENTS.md +63 -0
  8. package/files/CLAUDE.md +63 -0
  9. package/files/LICENSE +21 -0
  10. package/files/rules/accessibility.md +219 -0
  11. package/files/rules/charts.md +352 -0
  12. package/files/rules/components.md +267 -0
  13. package/files/rules/design-principles.md +56 -0
  14. package/files/rules/linting.md +31 -0
  15. package/files/rules/state.md +405 -0
  16. package/files/rules/styling.md +245 -0
  17. package/files/skills/apply-ds/SKILL.md +117 -0
  18. package/files/skills/apply-ds/scripts/setup.sh +271 -0
  19. package/files/skills/build-pattern/SKILL.md +202 -0
  20. package/files/skills/create-dashboard/SKILL.md +189 -0
  21. package/files/skills/deploy-worker/SKILL.md +231 -0
  22. package/files/skills/deploy-worker/references/wrangler-commands.md +327 -0
  23. package/files/skills/fix-accessibility/SKILL.md +184 -0
  24. package/files/skills/fix-metadata/SKILL.md +118 -0
  25. package/files/skills/fix-metadata/assets/favicon.ico +0 -0
  26. package/files/skills/setup-chart/SKILL.md +225 -0
  27. package/files/skills/setup-chart/data/embedding.csv +42 -0
  28. package/files/skills/setup-chart/data/timeseries.csv +173 -0
  29. package/files/skills/setup-chart/references/scatter-chart.md +229 -0
  30. package/files/skills/setup-chart/references/sensor-chart.md +156 -0
  31. package/lib/add-ds-config-codeagent.js +154 -0
  32. package/lib/add-ds-ui-svelte.js +93 -0
  33. package/lib/scaffold-ds-svelte-project.js +272 -0
  34. package/lib/use-package-manager.js +65 -0
  35. package/lib/use-shadcn-svelte-registry.js +26 -0
  36. package/lib/validate-url.js +31 -0
  37. package/package.json +34 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Archetype AI
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,123 @@
1
+ ## @archetypeai/ds-cli
2
+
3
+ `@archetypeai/ds-cli` is the CLI for the **Archetype AI Design System**. It provides commands for creating, configuring, and managing projects that use the design system.
4
+
5
+ ---
6
+
7
+ ## Commands
8
+
9
+ ### `create` — Scaffold a new project
10
+
11
+ ```bash
12
+ npx @archetypeai/ds-cli create my-app
13
+ ```
14
+
15
+ Scaffolds a full SvelteKit + Tailwind v4 + shadcn-svelte project:
16
+
17
+ 1. Creates a SvelteKit project via `sv create`
18
+ 2. Installs design tokens (`@archetypeai/ds-lib-tokens`)
19
+ 3. Optionally installs internal fonts (`@archetypeai/ds-lib-fonts-internal`)
20
+ 4. Initializes shadcn-svelte (`components.json`, `utils.js`, dependencies)
21
+ 5. Configures CSS (`layout.css` with design tokens and optional fonts import)
22
+ 6. Installs all components from the design system registry
23
+ 7. Optionally installs AI agent configuration (Cursor or Claude Code)
24
+ 8. Creates a demo page with Button examples
25
+
26
+ #### Create flags
27
+
28
+ | Flag | Values | Default |
29
+ |------|--------|---------|
30
+ | `--framework` | `svelte` | prompt |
31
+ | `--pm` | `npm`, `pnpm`, `bun`, `yarn` | prompt |
32
+ | `--fonts` / `--no-fonts` | boolean | prompt (default: yes) |
33
+ | `--no-components` | skip component installation | install all |
34
+ | `--codeagent` | `cursor`, `claude`, `none` | prompt |
35
+
36
+ ```bash
37
+ npx @archetypeai/ds-cli create my-app --framework svelte --pm pnpm --no-fonts --codeagent none
38
+ ```
39
+
40
+ ---
41
+
42
+ ### `init` — Add DS to an existing project
43
+
44
+ ```bash
45
+ cd my-existing-app
46
+ npx @archetypeai/ds-cli init
47
+ ```
48
+
49
+ Run from an existing SvelteKit project root. Detects your package manager from the lockfile and installs the design system without creating a new project:
50
+
51
+ 1. Detects project (verifies `package.json` and `svelte.config.js`)
52
+ 2. Auto-detects package manager from lockfile
53
+ 3. Installs Tailwind CSS v4 if not already present
54
+ 4. Installs design tokens
55
+ 5. Optionally installs internal fonts
56
+ 6. Initializes shadcn-svelte
57
+ 7. Prepends DS imports to existing `layout.css` (preserves your styles)
58
+ 8. Installs all components from the registry
59
+ 9. Optionally installs AI agent configuration
60
+
61
+ #### Init flags
62
+
63
+ | Flag | Values | Default |
64
+ |------|--------|---------|
65
+ | `--pm` | `npm`, `pnpm`, `bun`, `yarn` | auto-detect from lockfile |
66
+ | `--fonts` / `--no-fonts` | boolean | prompt (default: yes) |
67
+ | `--no-components` | skip component installation | install all |
68
+ | `--codeagent` | `cursor`, `claude`, `none` | prompt |
69
+
70
+ ```bash
71
+ npx @archetypeai/ds-cli init --pm npm --no-fonts --codeagent none
72
+ ```
73
+
74
+ ---
75
+
76
+ ### `add` — Add components or agent configurations
77
+
78
+ #### `add ds-ui-svelte` — Install all design system components
79
+
80
+ ```bash
81
+ npx @archetypeai/ds-cli add ds-ui-svelte
82
+ ```
83
+
84
+ Installs all components from the design system registry into your project. Requires shadcn-svelte to be initialized (`components.json` must exist).
85
+
86
+ #### `add ds-config-codeagent` — Install agent configuration
87
+
88
+ ```bash
89
+ npx @archetypeai/ds-cli add ds-config-codeagent --cursor
90
+ npx @archetypeai/ds-cli add ds-config-codeagent --claude
91
+ ```
92
+
93
+ Installs agent configuration files (AGENTS.md/CLAUDE.md, skills, and rules) for the specified IDE. If no flag is provided, an interactive prompt will ask which IDE to configure.
94
+
95
+ | Flag | Effect |
96
+ |------|--------|
97
+ | `--cursor` | Copies AGENTS.md, skills, and rules to `.cursor/` |
98
+ | `--claude` | Copies CLAUDE.md, skills, and rules to `.claude/` |
99
+
100
+ ---
101
+
102
+ ## Environment Variables
103
+
104
+ | Variable | Default | Description |
105
+ |----------|---------|-------------|
106
+ | `REGISTRY_URL` | `https://design-system.archetypeai.workers.dev` | Override the component registry URL for testing or private registries |
107
+
108
+ ---
109
+
110
+ ## Security
111
+
112
+ The CLI validates all data from external sources before use:
113
+
114
+ - **Registry URLs** are validated against an HTTPS + `/r/<name>.json` pattern before being passed to any shell command
115
+ - **Shell commands** use `execFileSync` (no shell interpolation) to prevent injection even if validation is bypassed
116
+ - **Package manager** and **framework** flag values are validated against known allowlists
117
+ - **Fetch requests** have a 15-second timeout to prevent hanging on unresponsive registries
118
+
119
+ ---
120
+
121
+ ## Fonts
122
+
123
+ The internal fonts package (`@archetypeai/ds-lib-fonts-internal`) is not yet published. When available, it will be on npmjs.org. If omitted, the theme falls back to system fonts.
package/bin.js ADDED
@@ -0,0 +1,77 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { readFileSync } from 'fs';
4
+ import { fileURLToPath } from 'url';
5
+ import { dirname, join } from 'path';
6
+ import { create } from './commands/create.js';
7
+ import { init } from './commands/init.js';
8
+ import { add } from './commands/add.js';
9
+
10
+ const __dirname = dirname(fileURLToPath(import.meta.url));
11
+
12
+ function getVersion() {
13
+ const pkg = JSON.parse(readFileSync(join(__dirname, 'package.json'), 'utf-8'));
14
+ return pkg.version;
15
+ }
16
+
17
+ function printUsage() {
18
+ console.log(`
19
+ ds - Archetype AI Design System CLI
20
+
21
+ Usage:
22
+ npx @archetypeai/ds-cli create [project-name] [flags] Create a new project
23
+ npx @archetypeai/ds-cli init [flags] Init DS in existing project
24
+ npx @archetypeai/ds-cli add <target> [flags] Add components or configs
25
+ npx @archetypeai/ds-cli --help Show this help message
26
+ npx @archetypeai/ds-cli --version Show version
27
+
28
+ Create flags:
29
+ --framework <svelte> Framework to use (default: prompt)
30
+ --pm <npm|pnpm|bun|yarn> Package manager (default: prompt)
31
+ --fonts / --no-fonts Install internal fonts (default: prompt)
32
+ --no-components Skip component installation (default: install all)
33
+ --codeagent <cursor|claude|none> Agent configuration (default: prompt)
34
+
35
+ Init flags:
36
+ --pm <npm|pnpm|bun|yarn> Package manager (default: auto-detect)
37
+ --fonts / --no-fonts Install internal fonts (default: prompt)
38
+ --no-components Skip component installation (default: install all)
39
+ --codeagent <cursor|claude|none> Agent configuration (default: prompt)
40
+
41
+ Add targets:
42
+ ds-ui-svelte Install all design system components
43
+ ds-config-codeagent [flags] Install agent configuration files
44
+ --cursor Setup for Cursor IDE
45
+ --claude Setup for Claude Code
46
+ `);
47
+ }
48
+
49
+ const command = process.argv[2];
50
+ const args = process.argv.slice(3);
51
+
52
+ switch (command) {
53
+ case 'create':
54
+ await create(args);
55
+ break;
56
+ case 'init':
57
+ await init(args);
58
+ break;
59
+ case 'add':
60
+ await add(args);
61
+ break;
62
+ case '--help':
63
+ case '-h':
64
+ printUsage();
65
+ break;
66
+ case '--version':
67
+ case '-v':
68
+ console.log(getVersion());
69
+ break;
70
+ default:
71
+ if (command) {
72
+ console.error(`Unknown command: ${command}\n`);
73
+ }
74
+ printUsage();
75
+ if (command) process.exit(1);
76
+ break;
77
+ }
@@ -0,0 +1,42 @@
1
+ import * as p from '@clack/prompts';
2
+ import { addDsUiSvelte } from '../lib/add-ds-ui-svelte.js';
3
+ import { addDsConfigCodeagent } from '../lib/add-ds-config-codeagent.js';
4
+
5
+ const VALID_TARGETS = ['ds-ui-svelte', 'ds-config-codeagent'];
6
+
7
+ function printUsage() {
8
+ console.log(`
9
+ ds add - Add components or configurations
10
+
11
+ Usage:
12
+ npx @archetypeai/ds-cli add ds-ui-svelte Install all design system components
13
+ npx @archetypeai/ds-cli add ds-config-codeagent [flags] Install agent configuration
14
+ --cursor Setup for Cursor IDE
15
+ --claude Setup for Claude Code
16
+ `);
17
+ }
18
+
19
+ export async function add(args) {
20
+ const target = args[0];
21
+ const flags = args.slice(1);
22
+
23
+ switch (target) {
24
+ case 'ds-ui-svelte':
25
+ await addDsUiSvelte(flags);
26
+ break;
27
+ case 'ds-config-codeagent':
28
+ await addDsConfigCodeagent(flags);
29
+ break;
30
+ case '--help':
31
+ case '-h':
32
+ printUsage();
33
+ break;
34
+ default:
35
+ if (target) {
36
+ p.log.error(`Unknown add target: "${target}". Valid targets: ${VALID_TARGETS.join(', ')}`);
37
+ }
38
+ printUsage();
39
+ if (target) process.exit(1);
40
+ break;
41
+ }
42
+ }
@@ -0,0 +1,238 @@
1
+ import { resolve } from 'path';
2
+ import { existsSync } from 'fs';
3
+ import * as p from '@clack/prompts';
4
+ import { getPm, pmNames, isPmInstalled } from '../lib/use-package-manager.js';
5
+ import { fetchComponents } from '../lib/use-shadcn-svelte-registry.js';
6
+ import {
7
+ runSvCreate,
8
+ installTokens,
9
+ installFonts,
10
+ initShadcn,
11
+ configureCss,
12
+ installComponents,
13
+ createDemoPage,
14
+ installAgentConfig
15
+ } from '../lib/scaffold-ds-svelte-project.js';
16
+
17
+ // parse flags
18
+ export function parseFlags(args) {
19
+ const flags = {
20
+ name: null,
21
+ framework: null,
22
+ pm: null,
23
+ fonts: null,
24
+ components: true,
25
+ agent: null
26
+ };
27
+
28
+ for (let i = 0; i < args.length; i++) {
29
+ const arg = args[i];
30
+ if (arg === '--framework' && args[i + 1]) {
31
+ flags.framework = args[++i];
32
+ } else if (arg === '--pm' && args[i + 1]) {
33
+ flags.pm = args[++i];
34
+ } else if (arg === '--fonts') {
35
+ flags.fonts = true;
36
+ } else if (arg === '--no-fonts') {
37
+ flags.fonts = false;
38
+ } else if (arg === '--no-components') {
39
+ flags.components = false;
40
+ } else if (arg === '--codeagent' && args[i + 1]) {
41
+ flags.agent = args[++i];
42
+ } else if (!arg.startsWith('--') && !flags.name) {
43
+ flags.name = arg;
44
+ }
45
+ }
46
+
47
+ return flags;
48
+ }
49
+
50
+ // create a new project
51
+ export async function create(args) {
52
+ const flags = parseFlags(args);
53
+
54
+ p.intro('Create a new project using Archetype AI Design System.');
55
+
56
+ // specify project name
57
+ let name = flags.name;
58
+ if (!name) {
59
+ name = await p.text({
60
+ message: 'What is your project name?',
61
+ placeholder: 'my-app',
62
+ validate(value) {
63
+ if (!value.trim()) return 'Project name is required.';
64
+ if (!/^[a-z0-9-]+$/.test(value.trim()))
65
+ return 'Use lowercase letters, numbers, and hyphens only.';
66
+ }
67
+ });
68
+ if (p.isCancel(name)) {
69
+ p.cancel('Setup cancelled.');
70
+ process.exit(0);
71
+ }
72
+ }
73
+ name = name.trim();
74
+ if (!/^[a-z0-9-]+$/.test(name)) {
75
+ p.log.error('Invalid project name. Use lowercase letters, numbers, and hyphens only.');
76
+ process.exit(1);
77
+ }
78
+
79
+ // validate --pm flag
80
+ if (flags.pm && !pmNames.includes(flags.pm)) {
81
+ p.log.error(`Invalid --pm value "${flags.pm}". Must be one of: ${pmNames.join(', ')}`);
82
+ process.exit(1);
83
+ }
84
+
85
+ // validate --framework flag
86
+ if (flags.framework && flags.framework !== 'svelte') {
87
+ p.log.error(
88
+ `Unsupported framework "${flags.framework}". Currently only "svelte" is supported.`
89
+ );
90
+ process.exit(1);
91
+ }
92
+
93
+ // specify framework
94
+ let framework = flags.framework;
95
+ if (!framework) {
96
+ framework = await p.select({
97
+ message: 'Which framework?',
98
+ options: [{ value: 'svelte', label: 'SvelteKit', hint: 'Svelte 5 + Tailwind v4' }]
99
+ });
100
+ if (p.isCancel(framework)) {
101
+ p.cancel('Setup cancelled.');
102
+ process.exit(0);
103
+ }
104
+ }
105
+
106
+ // specify package manager
107
+ let pmName = flags.pm;
108
+ if (!pmName) {
109
+ pmName = await p.select({
110
+ message: 'Which package manager?',
111
+ options: pmNames.map((n) => ({ value: n, label: n }))
112
+ });
113
+ if (p.isCancel(pmName)) {
114
+ p.cancel('Setup cancelled.');
115
+ process.exit(0);
116
+ }
117
+ }
118
+ const pm = getPm(pmName);
119
+
120
+ // verify package manager is installed
121
+ if (!isPmInstalled(pmName)) {
122
+ p.log.error(`${pmName} is not installed. Please install it first and try again.`);
123
+ process.exit(1);
124
+ }
125
+
126
+ // check if directory exists
127
+ const targetDir = process.cwd();
128
+ const projectPath = resolve(targetDir, name);
129
+
130
+ if (existsSync(projectPath)) {
131
+ const overwrite = await p.confirm({
132
+ message: `Directory "${name}" already exists. Continue anyway?`,
133
+ initialValue: false
134
+ });
135
+ if (p.isCancel(overwrite) || !overwrite) {
136
+ p.cancel('Setup cancelled.');
137
+ process.exit(0);
138
+ }
139
+ }
140
+
141
+ // create SvelteKit project
142
+ const created = runSvCreate(pm, name, targetDir);
143
+ if (!created) {
144
+ process.exit(1);
145
+ }
146
+
147
+ // specify fonts
148
+ let includeFonts = flags.fonts;
149
+ if (includeFonts === null) {
150
+ includeFonts = await p.confirm({
151
+ message: 'Install internal fonts package?',
152
+ initialValue: true
153
+ });
154
+ if (p.isCancel(includeFonts)) {
155
+ p.cancel('Setup cancelled.');
156
+ process.exit(0);
157
+ }
158
+ }
159
+
160
+ // install packages
161
+ const tokensOk = installTokens(pm, projectPath);
162
+ if (!tokensOk) {
163
+ process.exit(1);
164
+ }
165
+
166
+ if (includeFonts) {
167
+ installFonts(pm, projectPath);
168
+ }
169
+
170
+ // init shadcn-svelte
171
+ initShadcn(pm, projectPath);
172
+
173
+ // configure CSS
174
+ configureCss(projectPath, includeFonts);
175
+
176
+ // install components
177
+ if (flags.components) {
178
+ try {
179
+ const s = p.spinner();
180
+ s.start('Fetching component list');
181
+ const components = await fetchComponents();
182
+ s.stop(`Found ${components.length} components`);
183
+ installComponents(pm, projectPath, components);
184
+ } catch (error) {
185
+ p.log.warn(`Component installation skipped: ${error.message}`);
186
+ }
187
+ } else {
188
+ p.log.info('Skipped component installation (--no-components)');
189
+ }
190
+
191
+ // specify agent config
192
+ let agent = flags.agent;
193
+ if (!agent) {
194
+ agent = await p.select({
195
+ message: 'Install AI agent configuration?',
196
+ options: [
197
+ { value: 'none', label: 'None' },
198
+ { value: 'cursor', label: 'Cursor', hint: 'AGENTS.md + skills + rules' },
199
+ { value: 'claude', label: 'Claude Code', hint: 'CLAUDE.md + skills + rules' }
200
+ ]
201
+ });
202
+ if (p.isCancel(agent)) {
203
+ p.cancel('Setup cancelled.');
204
+ process.exit(0);
205
+ }
206
+ }
207
+
208
+ const validAgents = ['cursor', 'claude', 'none'];
209
+ if (!validAgents.includes(agent)) {
210
+ p.log.error(`Invalid --codeagent value "${agent}". Must be one of: ${validAgents.join(', ')}`);
211
+ process.exit(1);
212
+ }
213
+
214
+ if (agent !== 'none') {
215
+ installAgentConfig(projectPath, agent);
216
+ }
217
+
218
+ // create demo page
219
+ createDemoPage(projectPath);
220
+
221
+ // summary
222
+ const summary = [
223
+ `Project: ${name}`,
224
+ `Location: ${projectPath}`,
225
+ `Framework: ${framework}`,
226
+ `Package Manager: ${pm.name}`,
227
+ `Fonts: ${includeFonts ? 'installed' : 'skipped'}`,
228
+ `Components: ${flags.components ? 'all' : 'skipped'}`,
229
+ `Agent Configuration: ${agent}`
230
+ ].join('\n');
231
+
232
+ p.note(summary, 'Summary');
233
+
234
+ p.log.step(`cd ${name}`);
235
+ p.log.step(`${pm.name} run dev`);
236
+
237
+ p.outro('You are all set!');
238
+ }
@@ -0,0 +1,199 @@
1
+ import { readFileSync, existsSync } from 'fs';
2
+ import { join } from 'path';
3
+ import * as p from '@clack/prompts';
4
+ import { getPm, pmNames, isPmInstalled, detectPm } from '../lib/use-package-manager.js';
5
+ import { fetchComponents } from '../lib/use-shadcn-svelte-registry.js';
6
+ import {
7
+ installTailwind,
8
+ installTokens,
9
+ installFonts,
10
+ initShadcn,
11
+ prependCss,
12
+ installComponents,
13
+ installAgentConfig
14
+ } from '../lib/scaffold-ds-svelte-project.js';
15
+
16
+ // parse flags
17
+ export function parseFlags(args) {
18
+ const flags = {
19
+ pm: null,
20
+ fonts: null,
21
+ components: true,
22
+ agent: null
23
+ };
24
+
25
+ for (let i = 0; i < args.length; i++) {
26
+ const arg = args[i];
27
+ if (arg === '--pm' && args[i + 1]) {
28
+ flags.pm = args[++i];
29
+ } else if (arg === '--fonts') {
30
+ flags.fonts = true;
31
+ } else if (arg === '--no-fonts') {
32
+ flags.fonts = false;
33
+ } else if (arg === '--no-components') {
34
+ flags.components = false;
35
+ } else if (arg === '--codeagent' && args[i + 1]) {
36
+ flags.agent = args[++i];
37
+ }
38
+ }
39
+
40
+ return flags;
41
+ }
42
+
43
+ // check if project has Tailwind CSS
44
+ function hasTailwind(projectPath) {
45
+ try {
46
+ const pkg = JSON.parse(readFileSync(join(projectPath, 'package.json'), 'utf-8'));
47
+ const deps = { ...pkg.dependencies, ...pkg.devDependencies };
48
+ return 'tailwindcss' in deps;
49
+ } catch {
50
+ return false;
51
+ }
52
+ }
53
+
54
+ // initialize the design system in an existing project
55
+ export async function init(args) {
56
+ const flags = parseFlags(args);
57
+ const projectPath = process.cwd();
58
+
59
+ // validate --pm flag
60
+ if (flags.pm && !pmNames.includes(flags.pm)) {
61
+ p.log.error(`Invalid --pm value "${flags.pm}". Must be one of: ${pmNames.join(', ')}`);
62
+ process.exit(1);
63
+ }
64
+
65
+ p.intro('Initialize Archetype AI Design System in existing project.');
66
+
67
+ // detect project
68
+ if (!existsSync(join(projectPath, 'package.json'))) {
69
+ p.log.error('No package.json found. Run this command from your project root.');
70
+ process.exit(1);
71
+ }
72
+
73
+ const hasSvelteConfig =
74
+ existsSync(join(projectPath, 'svelte.config.js')) ||
75
+ existsSync(join(projectPath, 'svelte.config.mjs')) ||
76
+ existsSync(join(projectPath, 'svelte.config.ts'));
77
+ if (!hasSvelteConfig) {
78
+ p.log.warn('No svelte.config found. This command is designed for SvelteKit projects.');
79
+ }
80
+
81
+ // detect package manager
82
+ let pmName = flags.pm;
83
+ if (!pmName) {
84
+ pmName = detectPm(projectPath);
85
+ if (pmName) {
86
+ p.log.info(`Detected package manager: ${pmName}`);
87
+ }
88
+ }
89
+ if (!pmName) {
90
+ pmName = await p.select({
91
+ message: 'Which package manager?',
92
+ options: pmNames.map((n) => ({ value: n, label: n }))
93
+ });
94
+ if (p.isCancel(pmName)) {
95
+ p.cancel('Setup cancelled.');
96
+ process.exit(0);
97
+ }
98
+ }
99
+ const pm = getPm(pmName);
100
+
101
+ // verify package manager is installed
102
+ if (!isPmInstalled(pmName)) {
103
+ p.log.error(`${pmName} is not installed. Please install it first and try again.`);
104
+ process.exit(1);
105
+ }
106
+
107
+ // detect and install Tailwind if missing
108
+ if (!hasTailwind(projectPath)) {
109
+ p.log.info('Tailwind CSS not found in dependencies.');
110
+ const tailwindOk = installTailwind(pm, projectPath);
111
+ if (!tailwindOk) {
112
+ process.exit(1);
113
+ }
114
+ }
115
+
116
+ // specify fonts
117
+ let includeFonts = flags.fonts;
118
+ if (includeFonts === null) {
119
+ includeFonts = await p.confirm({
120
+ message: 'Install internal fonts package?',
121
+ initialValue: true
122
+ });
123
+ if (p.isCancel(includeFonts)) {
124
+ p.cancel('Setup cancelled.');
125
+ process.exit(0);
126
+ }
127
+ }
128
+
129
+ // install packages
130
+ const tokensOk = installTokens(pm, projectPath);
131
+ if (!tokensOk) {
132
+ process.exit(1);
133
+ }
134
+
135
+ if (includeFonts) {
136
+ installFonts(pm, projectPath);
137
+ }
138
+
139
+ // init shadcn-svelte
140
+ initShadcn(pm, projectPath);
141
+
142
+ // configure CSS (prepend to existing)
143
+ prependCss(projectPath, includeFonts);
144
+
145
+ // install components
146
+ if (flags.components) {
147
+ try {
148
+ const s = p.spinner();
149
+ s.start('Fetching component list');
150
+ const components = await fetchComponents();
151
+ s.stop(`Found ${components.length} components`);
152
+ installComponents(pm, projectPath, components);
153
+ } catch (error) {
154
+ p.log.warn(`Component installation skipped: ${error.message}`);
155
+ }
156
+ } else {
157
+ p.log.info('Skipped component installation (--no-components)');
158
+ }
159
+
160
+ // specify agent config
161
+ let agent = flags.agent;
162
+ if (!agent) {
163
+ agent = await p.select({
164
+ message: 'Install AI agent configuration?',
165
+ options: [
166
+ { value: 'none', label: 'None' },
167
+ { value: 'cursor', label: 'Cursor', hint: 'AGENTS.md + skills + rules' },
168
+ { value: 'claude', label: 'Claude Code', hint: 'CLAUDE.md + skills + rules' }
169
+ ]
170
+ });
171
+ if (p.isCancel(agent)) {
172
+ p.cancel('Setup cancelled.');
173
+ process.exit(0);
174
+ }
175
+ }
176
+
177
+ const validAgents = ['cursor', 'claude', 'none'];
178
+ if (!validAgents.includes(agent)) {
179
+ p.log.error(`Invalid --codeagent value "${agent}". Must be one of: ${validAgents.join(', ')}`);
180
+ process.exit(1);
181
+ }
182
+
183
+ if (agent !== 'none') {
184
+ installAgentConfig(projectPath, agent);
185
+ }
186
+
187
+ // summary
188
+ const summary = [
189
+ `Location: ${projectPath}`,
190
+ `Package Manager: ${pm.name}`,
191
+ `Fonts: ${includeFonts ? 'installed' : 'skipped'}`,
192
+ `Components: ${flags.components ? 'all' : 'skipped'}`,
193
+ `Agent Config: ${agent}`
194
+ ].join('\n');
195
+
196
+ p.note(summary, 'Summary');
197
+
198
+ p.outro('You are all set!');
199
+ }