@archetypeai/ds-cli 0.3.16 → 0.3.18
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/README.md +12 -2
- package/bin.js +7 -4
- package/commands/create.js +125 -51
- package/commands/init.js +114 -36
- package/files/AGENTS.md +16 -0
- package/files/CLAUDE.md +15 -1
- package/files/rules/charts.md +1 -97
- package/files/rules/components.md +1 -16
- package/files/rules/design-principles.md +16 -1
- package/files/rules/frontend-architecture.md +11 -0
- package/files/rules/state.md +2 -34
- package/files/rules/styling.md +24 -119
- package/files/skills/build-pattern/SKILL.md +2 -0
- package/files/skills/create-dashboard/SKILL.md +22 -3
- package/files/skills/embedding-from-file/SKILL.md +14 -1
- package/files/skills/embedding-from-sensor/SKILL.md +14 -1
- package/files/skills/embedding-upload/SKILL.md +14 -1
- package/files/skills/newton-activity-monitor-lens-on-video/SKILL.md +1 -1
- package/files/skills/newton-camera-frame-analysis/SKILL.md +14 -1
- package/files/skills/newton-direct-query/SKILL.md +9 -0
- package/files/skills/newton-machine-state-from-file/SKILL.md +15 -1
- package/files/skills/newton-machine-state-from-sensor/SKILL.md +15 -1
- package/lib/install-fonts-local.js +212 -0
- package/lib/is-interactive.js +0 -9
- package/lib/scaffold-ds-svelte-project.js +31 -28
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -26,13 +26,19 @@ Sets up a SvelteKit + Tailwind v4 + shadcn-svelte project with design tokens, co
|
|
|
26
26
|
|------|--------|---------|
|
|
27
27
|
| `--framework` | `svelte` | prompt |
|
|
28
28
|
| `--pm` | `npm`, `pnpm`, `bun`, `yarn` | prompt |
|
|
29
|
+
| `--fonts <path>` | path to PP Neue Montreal fonts folder | prompt |
|
|
30
|
+
| `--no-fonts` | skip font installation (use system fallback) | — |
|
|
29
31
|
| `--no-components` | skip component install | install all |
|
|
30
32
|
| `--codeagent` | `cursor`, `claude`, `none` | prompt |
|
|
33
|
+
| `--defaults` | force non-interactive mode | — |
|
|
31
34
|
|
|
32
35
|
```bash
|
|
33
|
-
npx @archetypeai/ds-cli create my-app --
|
|
36
|
+
npx @archetypeai/ds-cli create my-app --pm pnpm --no-fonts --codeagent claude
|
|
37
|
+
npx @archetypeai/ds-cli create my-app --pm npm --fonts /path/to/fonts --codeagent claude
|
|
34
38
|
```
|
|
35
39
|
|
|
40
|
+
**Non-interactive mode** (no TTY or `--defaults`): all required flags must be specified. The CLI lists missing options and exits so agents can ask the user before proceeding.
|
|
41
|
+
|
|
36
42
|
---
|
|
37
43
|
|
|
38
44
|
### `init` → Add DS to an existing project
|
|
@@ -47,11 +53,15 @@ Run from a SvelteKit project root. Auto-detects your package manager, installs t
|
|
|
47
53
|
| Flag | Values | Default |
|
|
48
54
|
|------|--------|---------|
|
|
49
55
|
| `--pm` | `npm`, `pnpm`, `bun`, `yarn` | auto-detect |
|
|
56
|
+
| `--fonts <path>` | path to PP Neue Montreal fonts folder | prompt |
|
|
57
|
+
| `--no-fonts` | skip font installation (use system fallback) | — |
|
|
50
58
|
| `--no-components` | skip component install | install all |
|
|
51
59
|
| `--codeagent` | `cursor`, `claude`, `none` | prompt |
|
|
60
|
+
| `--defaults` | force non-interactive mode | — |
|
|
52
61
|
|
|
53
62
|
```bash
|
|
54
|
-
npx @archetypeai/ds-cli init --pm npm --codeagent
|
|
63
|
+
npx @archetypeai/ds-cli init --pm npm --no-fonts --codeagent claude
|
|
64
|
+
npx @archetypeai/ds-cli init --pm npm --fonts /path/to/fonts --codeagent claude
|
|
55
65
|
```
|
|
56
66
|
|
|
57
67
|
---
|
package/bin.js
CHANGED
|
@@ -28,19 +28,22 @@ Usage:
|
|
|
28
28
|
Create flags:
|
|
29
29
|
--framework <svelte> Framework to use (default: prompt)
|
|
30
30
|
--pm <npm|pnpm|bun|yarn> Package manager (default: prompt)
|
|
31
|
-
--fonts
|
|
31
|
+
--fonts <path> Install fonts from local folder
|
|
32
|
+
--no-fonts Skip font installation
|
|
32
33
|
--no-components Skip component installation (default: install all)
|
|
33
34
|
--codeagent <cursor|claude|none> Agent configuration (default: prompt)
|
|
34
35
|
--defaults Skip prompts, use sensible defaults
|
|
35
36
|
|
|
36
37
|
Init flags:
|
|
37
38
|
--pm <npm|pnpm|bun|yarn> Package manager (default: auto-detect)
|
|
38
|
-
--fonts
|
|
39
|
+
--fonts <path> Install fonts from local folder
|
|
40
|
+
--no-fonts Skip font installation
|
|
39
41
|
--no-components Skip component installation (default: install all)
|
|
40
42
|
--codeagent <cursor|claude|none> Agent configuration (default: prompt)
|
|
41
|
-
--defaults
|
|
43
|
+
--defaults Force non-interactive mode
|
|
42
44
|
|
|
43
|
-
Non-interactive
|
|
45
|
+
Non-interactive mode (no TTY or --defaults):
|
|
46
|
+
All required options must be specified via flags. Missing options are listed and the CLI exits.
|
|
44
47
|
|
|
45
48
|
Add targets:
|
|
46
49
|
ds-ui-svelte Install all design system components
|
package/commands/create.js
CHANGED
|
@@ -14,7 +14,8 @@ import {
|
|
|
14
14
|
createDemoPage,
|
|
15
15
|
installAgentConfig
|
|
16
16
|
} from '../lib/scaffold-ds-svelte-project.js';
|
|
17
|
-
import {
|
|
17
|
+
import { validateFontsPath, installLocalFonts } from '../lib/install-fonts-local.js';
|
|
18
|
+
import { isInteractive, DEFAULTS } from '../lib/is-interactive.js';
|
|
18
19
|
|
|
19
20
|
// parse flags
|
|
20
21
|
export function parseFlags(args) {
|
|
@@ -22,6 +23,7 @@ export function parseFlags(args) {
|
|
|
22
23
|
name: null,
|
|
23
24
|
framework: null,
|
|
24
25
|
pm: null,
|
|
26
|
+
fonts: null,
|
|
25
27
|
components: true,
|
|
26
28
|
agent: null,
|
|
27
29
|
defaults: false
|
|
@@ -33,6 +35,10 @@ export function parseFlags(args) {
|
|
|
33
35
|
flags.framework = args[++i];
|
|
34
36
|
} else if (arg === '--pm' && args[i + 1]) {
|
|
35
37
|
flags.pm = args[++i];
|
|
38
|
+
} else if (arg === '--fonts' && args[i + 1]) {
|
|
39
|
+
flags.fonts = args[++i];
|
|
40
|
+
} else if (arg === '--no-fonts') {
|
|
41
|
+
flags.fonts = false;
|
|
36
42
|
} else if (arg === '--no-components') {
|
|
37
43
|
flags.components = false;
|
|
38
44
|
} else if (arg === '--codeagent' && args[i + 1]) {
|
|
@@ -52,6 +58,30 @@ export async function create(args) {
|
|
|
52
58
|
const flags = parseFlags(args);
|
|
53
59
|
const interactive = isInteractive(flags);
|
|
54
60
|
|
|
61
|
+
// preflight: in non-interactive mode, list all unspecified options and exit
|
|
62
|
+
if (!interactive) {
|
|
63
|
+
const missing = [];
|
|
64
|
+
if (!flags.name)
|
|
65
|
+
missing.push(' <project-name> Project name (positional argument)');
|
|
66
|
+
if (!flags.pm) missing.push(' --pm <npm (default)|pnpm|bun|yarn> Package manager');
|
|
67
|
+
if (flags.fonts === null)
|
|
68
|
+
missing.push(' --fonts <path> | --no-fonts Internal fonts (PP Neue Montreal)');
|
|
69
|
+
if (!flags.agent) missing.push(' --codeagent <cursor|claude|none> AI agent configuration');
|
|
70
|
+
|
|
71
|
+
if (missing.length > 0) {
|
|
72
|
+
console.log(
|
|
73
|
+
'[CONFIGURATION REQUIRED] Do not assume defaults. Ask the user to choose each option:\n\n' +
|
|
74
|
+
missing.join('\n') +
|
|
75
|
+
'\n\nOptional:\n' +
|
|
76
|
+
' --no-components Skip component installation\n\n' +
|
|
77
|
+
'Once the user has answered, re-run with their choices:\n' +
|
|
78
|
+
' ds create my-app --pm <choice> --fonts <path> --codeagent <choice>\n' +
|
|
79
|
+
' ds create my-app --pm <choice> --no-fonts --codeagent <choice>\n'
|
|
80
|
+
);
|
|
81
|
+
process.exit(1);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
55
85
|
p.intro('Create a new project using Archetype AI Design System.');
|
|
56
86
|
|
|
57
87
|
// specify project name
|
|
@@ -95,44 +125,87 @@ export async function create(args) {
|
|
|
95
125
|
process.exit(1);
|
|
96
126
|
}
|
|
97
127
|
|
|
98
|
-
// specify framework
|
|
99
|
-
let framework = flags.framework;
|
|
100
|
-
if (!framework) {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
if (p.isCancel(framework)) {
|
|
109
|
-
p.cancel('Setup cancelled.');
|
|
110
|
-
process.exit(0);
|
|
111
|
-
}
|
|
128
|
+
// specify framework (only svelte supported, default silently)
|
|
129
|
+
let framework = flags.framework || 'svelte';
|
|
130
|
+
if (!flags.framework && interactive) {
|
|
131
|
+
framework = await p.select({
|
|
132
|
+
message: 'Which framework?',
|
|
133
|
+
options: [{ value: 'svelte', label: 'SvelteKit', hint: 'Svelte 5 + Tailwind v4, default' }]
|
|
134
|
+
});
|
|
135
|
+
if (p.isCancel(framework)) {
|
|
136
|
+
p.cancel('Setup cancelled.');
|
|
137
|
+
process.exit(0);
|
|
112
138
|
}
|
|
113
139
|
}
|
|
114
140
|
|
|
115
141
|
// specify package manager
|
|
116
142
|
let pmName = flags.pm;
|
|
117
143
|
if (!pmName) {
|
|
118
|
-
|
|
119
|
-
|
|
144
|
+
pmName = await p.select({
|
|
145
|
+
message: 'Which package manager?',
|
|
146
|
+
options: pmNames.map((n) => ({
|
|
147
|
+
value: n,
|
|
148
|
+
label: n,
|
|
149
|
+
...(n === DEFAULTS.pm && { hint: 'default' })
|
|
150
|
+
}))
|
|
151
|
+
});
|
|
152
|
+
if (p.isCancel(pmName)) {
|
|
153
|
+
p.cancel('Setup cancelled.');
|
|
154
|
+
process.exit(0);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
const pm = getPm(pmName);
|
|
158
|
+
|
|
159
|
+
// specify fonts
|
|
160
|
+
let fontsPath = null;
|
|
161
|
+
let includeFonts = false;
|
|
162
|
+
if (flags.fonts === false) {
|
|
163
|
+
// --no-fonts: skip
|
|
164
|
+
} else if (typeof flags.fonts === 'string') {
|
|
165
|
+
fontsPath = flags.fonts;
|
|
166
|
+
const result = validateFontsPath(fontsPath);
|
|
167
|
+
if (!result.valid) {
|
|
168
|
+
if (!interactive) {
|
|
169
|
+
p.log.error(result.error);
|
|
170
|
+
process.exit(1);
|
|
171
|
+
}
|
|
172
|
+
p.log.warn(result.error);
|
|
173
|
+
p.log.warn('Continuing without fonts.');
|
|
174
|
+
fontsPath = null;
|
|
120
175
|
} else {
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
176
|
+
includeFonts = true;
|
|
177
|
+
}
|
|
178
|
+
} else {
|
|
179
|
+
const useFonts = await p.confirm({
|
|
180
|
+
message: 'Do you want to use internal fonts?',
|
|
181
|
+
initialValue: false
|
|
182
|
+
});
|
|
183
|
+
if (p.isCancel(useFonts)) {
|
|
184
|
+
p.cancel('Setup cancelled.');
|
|
185
|
+
process.exit(0);
|
|
186
|
+
}
|
|
187
|
+
if (useFonts) {
|
|
188
|
+
const fontInput = await p.text({
|
|
189
|
+
message: 'Drop your fonts folder here:',
|
|
190
|
+
placeholder: '/path/to/fonts'
|
|
128
191
|
});
|
|
129
|
-
if (p.isCancel(
|
|
192
|
+
if (p.isCancel(fontInput)) {
|
|
130
193
|
p.cancel('Setup cancelled.');
|
|
131
194
|
process.exit(0);
|
|
132
195
|
}
|
|
196
|
+
if (fontInput && fontInput.trim()) {
|
|
197
|
+
fontsPath = fontInput.trim();
|
|
198
|
+
const result = validateFontsPath(fontsPath);
|
|
199
|
+
if (!result.valid) {
|
|
200
|
+
p.log.warn(result.error);
|
|
201
|
+
p.log.warn('Continuing without fonts.');
|
|
202
|
+
fontsPath = null;
|
|
203
|
+
} else {
|
|
204
|
+
includeFonts = true;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
133
207
|
}
|
|
134
208
|
}
|
|
135
|
-
const pm = getPm(pmName);
|
|
136
209
|
|
|
137
210
|
// verify package manager is installed
|
|
138
211
|
if (!isPmInstalled(pmName)) {
|
|
@@ -177,8 +250,22 @@ export async function create(args) {
|
|
|
177
250
|
// init shadcn-svelte
|
|
178
251
|
await initShadcn(pm, projectPath);
|
|
179
252
|
|
|
253
|
+
// install local fonts
|
|
254
|
+
if (includeFonts && fontsPath) {
|
|
255
|
+
const s = p.spinner();
|
|
256
|
+
s.start('Installing fonts');
|
|
257
|
+
const fontResult = installLocalFonts(fontsPath, projectPath);
|
|
258
|
+
if (fontResult.success) {
|
|
259
|
+
s.stop(`${fontResult.fileCount} font files installed`);
|
|
260
|
+
} else {
|
|
261
|
+
s.stop('Failed to install fonts');
|
|
262
|
+
p.log.warn(fontResult.error);
|
|
263
|
+
p.log.warn('Continuing without fonts.');
|
|
264
|
+
includeFonts = false;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
180
268
|
// configure CSS
|
|
181
|
-
const includeFonts = false;
|
|
182
269
|
configureCss(projectPath, includeFonts);
|
|
183
270
|
|
|
184
271
|
// set up linting and formatting
|
|
@@ -202,33 +289,20 @@ export async function create(args) {
|
|
|
202
289
|
// specify agent config
|
|
203
290
|
let agent = flags.agent;
|
|
204
291
|
if (!agent) {
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
if (p.isCancel(agent)) {
|
|
217
|
-
p.cancel('Setup cancelled.');
|
|
218
|
-
process.exit(0);
|
|
219
|
-
}
|
|
292
|
+
agent = await p.select({
|
|
293
|
+
message: 'Install AI agent configuration?',
|
|
294
|
+
options: [
|
|
295
|
+
{ value: 'none', label: 'None' },
|
|
296
|
+
{ value: 'cursor', label: 'Cursor', hint: 'AGENTS.md + skills + rules' },
|
|
297
|
+
{ value: 'claude', label: 'Claude Code', hint: 'CLAUDE.md + skills + rules, default' }
|
|
298
|
+
]
|
|
299
|
+
});
|
|
300
|
+
if (p.isCancel(agent)) {
|
|
301
|
+
p.cancel('Setup cancelled.');
|
|
302
|
+
process.exit(0);
|
|
220
303
|
}
|
|
221
304
|
}
|
|
222
305
|
|
|
223
|
-
// log defaults notice
|
|
224
|
-
if (!interactive) {
|
|
225
|
-
const applied = {};
|
|
226
|
-
if (!flags.framework) applied.framework = framework;
|
|
227
|
-
if (!flags.pm) applied.pm = pmName;
|
|
228
|
-
if (!flags.agent) applied.codeagent = agent;
|
|
229
|
-
logDefaultsNotice(applied);
|
|
230
|
-
}
|
|
231
|
-
|
|
232
306
|
const validAgents = ['cursor', 'claude', 'none'];
|
|
233
307
|
if (!validAgents.includes(agent)) {
|
|
234
308
|
p.log.error(`Invalid --codeagent value "${agent}". Must be one of: ${validAgents.join(', ')}`);
|
package/commands/init.js
CHANGED
|
@@ -13,12 +13,14 @@ import {
|
|
|
13
13
|
installComponents,
|
|
14
14
|
installAgentConfig
|
|
15
15
|
} from '../lib/scaffold-ds-svelte-project.js';
|
|
16
|
-
import {
|
|
16
|
+
import { validateFontsPath, installLocalFonts } from '../lib/install-fonts-local.js';
|
|
17
|
+
import { isInteractive, DEFAULTS } from '../lib/is-interactive.js';
|
|
17
18
|
|
|
18
19
|
// parse flags
|
|
19
20
|
export function parseFlags(args) {
|
|
20
21
|
const flags = {
|
|
21
22
|
pm: null,
|
|
23
|
+
fonts: null,
|
|
22
24
|
components: true,
|
|
23
25
|
agent: null,
|
|
24
26
|
defaults: false
|
|
@@ -28,6 +30,10 @@ export function parseFlags(args) {
|
|
|
28
30
|
const arg = args[i];
|
|
29
31
|
if (arg === '--pm' && args[i + 1]) {
|
|
30
32
|
flags.pm = args[++i];
|
|
33
|
+
} else if (arg === '--fonts' && args[i + 1]) {
|
|
34
|
+
flags.fonts = args[++i];
|
|
35
|
+
} else if (arg === '--no-fonts') {
|
|
36
|
+
flags.fonts = false;
|
|
31
37
|
} else if (arg === '--no-components') {
|
|
32
38
|
flags.components = false;
|
|
33
39
|
} else if (arg === '--codeagent' && args[i + 1]) {
|
|
@@ -57,6 +63,29 @@ export async function init(args) {
|
|
|
57
63
|
const interactive = isInteractive(flags);
|
|
58
64
|
const projectPath = process.cwd();
|
|
59
65
|
|
|
66
|
+
// preflight: in non-interactive mode, list all unspecified options and exit
|
|
67
|
+
if (!interactive) {
|
|
68
|
+
const missing = [];
|
|
69
|
+
if (!flags.pm && !detectPm(projectPath))
|
|
70
|
+
missing.push(' --pm <npm (default)|pnpm|bun|yarn> Package manager');
|
|
71
|
+
if (flags.fonts === null)
|
|
72
|
+
missing.push(' --fonts <path> | --no-fonts Internal fonts (PP Neue Montreal)');
|
|
73
|
+
if (!flags.agent) missing.push(' --codeagent <cursor|claude|none> AI agent configuration');
|
|
74
|
+
|
|
75
|
+
if (missing.length > 0) {
|
|
76
|
+
console.log(
|
|
77
|
+
'[CONFIGURATION REQUIRED] Do not assume defaults. Ask the user to choose each option:\n\n' +
|
|
78
|
+
missing.join('\n') +
|
|
79
|
+
'\n\nOptional:\n' +
|
|
80
|
+
' --no-components Skip component installation\n\n' +
|
|
81
|
+
'Once the user has answered, re-run with their choices:\n' +
|
|
82
|
+
' ds init --pm <choice> --fonts <path> --codeagent <choice>\n' +
|
|
83
|
+
' ds init --pm <choice> --no-fonts --codeagent <choice>\n'
|
|
84
|
+
);
|
|
85
|
+
process.exit(1);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
60
89
|
// validate --pm flag
|
|
61
90
|
if (flags.pm && !pmNames.includes(flags.pm)) {
|
|
62
91
|
p.log.error(`Invalid --pm value "${flags.pm}". Must be one of: ${pmNames.join(', ')}`);
|
|
@@ -91,32 +120,71 @@ export async function init(args) {
|
|
|
91
120
|
}
|
|
92
121
|
}
|
|
93
122
|
if (!pmName) {
|
|
94
|
-
|
|
95
|
-
|
|
123
|
+
pmName = await p.select({
|
|
124
|
+
message: 'Which package manager?',
|
|
125
|
+
options: pmNames.map((n) => ({
|
|
126
|
+
value: n,
|
|
127
|
+
label: n,
|
|
128
|
+
...(n === DEFAULTS.pm && { hint: 'default' })
|
|
129
|
+
}))
|
|
130
|
+
});
|
|
131
|
+
if (p.isCancel(pmName)) {
|
|
132
|
+
p.cancel('Setup cancelled.');
|
|
133
|
+
process.exit(0);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
const pm = getPm(pmName);
|
|
137
|
+
|
|
138
|
+
// specify fonts
|
|
139
|
+
let fontsPath = null;
|
|
140
|
+
let includeFonts = false;
|
|
141
|
+
if (flags.fonts === false) {
|
|
142
|
+
// --no-fonts: skip
|
|
143
|
+
} else if (typeof flags.fonts === 'string') {
|
|
144
|
+
fontsPath = flags.fonts;
|
|
145
|
+
const result = validateFontsPath(fontsPath);
|
|
146
|
+
if (!result.valid) {
|
|
147
|
+
if (!interactive) {
|
|
148
|
+
p.log.error(result.error);
|
|
149
|
+
process.exit(1);
|
|
150
|
+
}
|
|
151
|
+
p.log.warn(result.error);
|
|
152
|
+
p.log.warn('Continuing without fonts.');
|
|
153
|
+
fontsPath = null;
|
|
96
154
|
} else {
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
155
|
+
includeFonts = true;
|
|
156
|
+
}
|
|
157
|
+
} else {
|
|
158
|
+
const useFonts = await p.confirm({
|
|
159
|
+
message: 'Do you want to use internal fonts?',
|
|
160
|
+
initialValue: false
|
|
161
|
+
});
|
|
162
|
+
if (p.isCancel(useFonts)) {
|
|
163
|
+
p.cancel('Setup cancelled.');
|
|
164
|
+
process.exit(0);
|
|
165
|
+
}
|
|
166
|
+
if (useFonts) {
|
|
167
|
+
const fontInput = await p.text({
|
|
168
|
+
message: 'Drop your fonts folder here:',
|
|
169
|
+
placeholder: '/path/to/fonts'
|
|
104
170
|
});
|
|
105
|
-
if (p.isCancel(
|
|
171
|
+
if (p.isCancel(fontInput)) {
|
|
106
172
|
p.cancel('Setup cancelled.');
|
|
107
173
|
process.exit(0);
|
|
108
174
|
}
|
|
175
|
+
if (fontInput && fontInput.trim()) {
|
|
176
|
+
fontsPath = fontInput.trim();
|
|
177
|
+
const result = validateFontsPath(fontsPath);
|
|
178
|
+
if (!result.valid) {
|
|
179
|
+
p.log.warn(result.error);
|
|
180
|
+
p.log.warn('Continuing without fonts.');
|
|
181
|
+
fontsPath = null;
|
|
182
|
+
} else {
|
|
183
|
+
includeFonts = true;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
109
186
|
}
|
|
110
187
|
}
|
|
111
|
-
const pm = getPm(pmName);
|
|
112
|
-
|
|
113
|
-
// log defaults notice
|
|
114
|
-
if (!interactive) {
|
|
115
|
-
const applied = {};
|
|
116
|
-
if (!flags.pm) applied.pm = pmName;
|
|
117
|
-
if (!flags.agent) applied.codeagent = DEFAULTS.agent;
|
|
118
|
-
logDefaultsNotice(applied);
|
|
119
|
-
}
|
|
120
188
|
|
|
121
189
|
// verify package manager is installed
|
|
122
190
|
if (!isPmInstalled(pmName)) {
|
|
@@ -142,8 +210,22 @@ export async function init(args) {
|
|
|
142
210
|
// init shadcn-svelte
|
|
143
211
|
await initShadcn(pm, projectPath);
|
|
144
212
|
|
|
213
|
+
// install local fonts
|
|
214
|
+
if (includeFonts && fontsPath) {
|
|
215
|
+
const s = p.spinner();
|
|
216
|
+
s.start('Installing fonts');
|
|
217
|
+
const fontResult = installLocalFonts(fontsPath, projectPath);
|
|
218
|
+
if (fontResult.success) {
|
|
219
|
+
s.stop(`${fontResult.fileCount} font files installed`);
|
|
220
|
+
} else {
|
|
221
|
+
s.stop('Failed to install fonts');
|
|
222
|
+
p.log.warn(fontResult.error);
|
|
223
|
+
p.log.warn('Continuing without fonts.');
|
|
224
|
+
includeFonts = false;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
145
228
|
// configure CSS (prepend to existing)
|
|
146
|
-
const includeFonts = false;
|
|
147
229
|
prependCss(projectPath, includeFonts);
|
|
148
230
|
|
|
149
231
|
// set up linting and formatting
|
|
@@ -167,21 +249,17 @@ export async function init(args) {
|
|
|
167
249
|
// specify agent config
|
|
168
250
|
let agent = flags.agent;
|
|
169
251
|
if (!agent) {
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
if (p.isCancel(agent)) {
|
|
182
|
-
p.cancel('Setup cancelled.');
|
|
183
|
-
process.exit(0);
|
|
184
|
-
}
|
|
252
|
+
agent = await p.select({
|
|
253
|
+
message: 'Install AI agent configuration?',
|
|
254
|
+
options: [
|
|
255
|
+
{ value: 'none', label: 'None' },
|
|
256
|
+
{ value: 'cursor', label: 'Cursor', hint: 'AGENTS.md + skills + rules' },
|
|
257
|
+
{ value: 'claude', label: 'Claude Code', hint: 'CLAUDE.md + skills + rules, default' }
|
|
258
|
+
]
|
|
259
|
+
});
|
|
260
|
+
if (p.isCancel(agent)) {
|
|
261
|
+
p.cancel('Setup cancelled.');
|
|
262
|
+
process.exit(0);
|
|
185
263
|
}
|
|
186
264
|
}
|
|
187
265
|
|
package/files/AGENTS.md
CHANGED
|
@@ -44,8 +44,24 @@ Standard Tailwind is fine for:
|
|
|
44
44
|
- **Variants**: `tailwind-variants` (tv) for component variants
|
|
45
45
|
- **Slots**: `{@render children?.()}`
|
|
46
46
|
|
|
47
|
+
## Pattern Registry
|
|
48
|
+
|
|
49
|
+
Before building a new component, fetch the pattern catalog from:
|
|
50
|
+
`https://design-system.archetypeai.workers.dev/r/patterns.json`
|
|
51
|
+
|
|
52
|
+
Each entry includes a `name`, `title`, `description`, and `registryDependencies`. Reuse or extend existing patterns instead of rebuilding from scratch.
|
|
53
|
+
|
|
54
|
+
Before installing, check if the pattern already exists locally in `$lib/components/ui/patterns/{name}/`. Only install if it is missing:
|
|
55
|
+
`npx shadcn-svelte@latest add https://design-system.archetypeai.workers.dev/r/{name}.json`
|
|
56
|
+
|
|
47
57
|
## Skills
|
|
48
58
|
|
|
59
|
+
**Skill composition:** When building a demo that uses a Newton or Embedding API skill:
|
|
60
|
+
1. Use `@skills/create-dashboard` for the page layout (dashboard with Menubar)
|
|
61
|
+
2. Fetch `https://design-system.archetypeai.workers.dev/r/patterns.json` and reuse existing patterns before creating new components
|
|
62
|
+
3. Apply `@rules/design-principles` aesthetic conventions (BackgroundCard for single-purpose cards, mono font for headers/numbers)
|
|
63
|
+
4. Only include chart components if the user's request involves time-series or explicitly mentions charts
|
|
64
|
+
|
|
49
65
|
Read these when relevant to your task:
|
|
50
66
|
|
|
51
67
|
- `@skills/apply-ds` - apply DS tokens, components, and patterns to an existing demo
|
package/files/CLAUDE.md
CHANGED
|
@@ -44,9 +44,23 @@ Standard Tailwind is fine for:
|
|
|
44
44
|
- **Variants**: `tailwind-variants` (tv) for component variants
|
|
45
45
|
- **Slots**: `{@render children?.()}`
|
|
46
46
|
|
|
47
|
+
## Pattern Registry
|
|
48
|
+
|
|
49
|
+
Before building a new component, fetch the pattern catalog from:
|
|
50
|
+
`https://design-system.archetypeai.workers.dev/r/patterns.json`
|
|
51
|
+
|
|
52
|
+
Each entry includes a `name`, `title`, `description`, and `registryDependencies`. Reuse or extend existing patterns instead of rebuilding from scratch.
|
|
53
|
+
|
|
54
|
+
Before installing, check if the pattern already exists locally in `$lib/components/ui/patterns/{name}/`. Only install if it is missing:
|
|
55
|
+
`npx shadcn-svelte@latest add https://design-system.archetypeai.workers.dev/r/{name}.json`
|
|
56
|
+
|
|
47
57
|
## Skills
|
|
48
58
|
|
|
49
|
-
**Skill composition:** When building a demo that uses a Newton or Embedding API skill
|
|
59
|
+
**Skill composition:** When building a demo that uses a Newton or Embedding API skill:
|
|
60
|
+
1. Use `@skills/create-dashboard` for the page layout (dashboard with Menubar)
|
|
61
|
+
2. Fetch `https://design-system.archetypeai.workers.dev/r/patterns.json` and reuse existing patterns before creating new components
|
|
62
|
+
3. Apply `@rules/design-principles` aesthetic conventions (BackgroundCard for single-purpose cards, mono font for headers/numbers)
|
|
63
|
+
4. Only include chart components if the user's request involves time-series or explicitly mentions charts
|
|
50
64
|
|
|
51
65
|
Read these when relevant to your task:
|
|
52
66
|
|
package/files/rules/charts.md
CHANGED
|
@@ -253,100 +253,4 @@ Manual legend below chart:
|
|
|
253
253
|
{/if}
|
|
254
254
|
```
|
|
255
255
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
```svelte
|
|
259
|
-
<script>
|
|
260
|
-
import { cn } from '$lib/utils.js';
|
|
261
|
-
import { Card, CardHeader, CardTitle, CardContent } from '$lib/components/ui/primitives/card/index.js';
|
|
262
|
-
import * as Chart from '$lib/components/ui/primitives/chart/index.js';
|
|
263
|
-
import { LineChart } from 'layerchart';
|
|
264
|
-
import { curveNatural } from 'd3-shape';
|
|
265
|
-
import { scaleUtc, scaleLinear } from 'd3-scale';
|
|
266
|
-
|
|
267
|
-
let {
|
|
268
|
-
title = 'SENSOR',
|
|
269
|
-
icon: Icon = undefined,
|
|
270
|
-
data = [],
|
|
271
|
-
signals = {},
|
|
272
|
-
xKey = 'timestamp',
|
|
273
|
-
maxPoints = undefined,
|
|
274
|
-
yMin,
|
|
275
|
-
yMax,
|
|
276
|
-
yTicks,
|
|
277
|
-
class: className,
|
|
278
|
-
...restProps
|
|
279
|
-
} = $props();
|
|
280
|
-
|
|
281
|
-
const chartColors = [
|
|
282
|
-
'var(--chart-1)',
|
|
283
|
-
'var(--chart-2)',
|
|
284
|
-
'var(--chart-3)',
|
|
285
|
-
'var(--chart-4)',
|
|
286
|
-
'var(--chart-5)'
|
|
287
|
-
];
|
|
288
|
-
|
|
289
|
-
let displayData = $derived(maxPoints && data.length > maxPoints ? data.slice(-maxPoints) : data);
|
|
290
|
-
|
|
291
|
-
let indexedData = $derived(displayData.map((d, i) => ({ ...d, _index: i })));
|
|
292
|
-
|
|
293
|
-
let series = $derived(
|
|
294
|
-
Object.entries(signals).map(([key, label], i) => ({
|
|
295
|
-
key,
|
|
296
|
-
label,
|
|
297
|
-
color: chartColors[i % chartColors.length]
|
|
298
|
-
}))
|
|
299
|
-
);
|
|
300
|
-
|
|
301
|
-
let chartConfig = $derived(
|
|
302
|
-
Object.fromEntries(series.map((s) => [s.key, { label: s.label, color: s.color }]))
|
|
303
|
-
);
|
|
304
|
-
|
|
305
|
-
let useIndexX = $derived(maxPoints !== undefined);
|
|
306
|
-
let xDomain = $derived(useIndexX ? [0, (maxPoints || displayData.length) - 1] : undefined);
|
|
307
|
-
</script>
|
|
308
|
-
|
|
309
|
-
<Card class={cn('p-4', className)} {...restProps}>
|
|
310
|
-
<CardHeader class="flex flex-row items-center justify-between p-0">
|
|
311
|
-
<CardTitle class="text-foreground font-mono text-base uppercase">
|
|
312
|
-
{title}
|
|
313
|
-
</CardTitle>
|
|
314
|
-
{#if Icon}
|
|
315
|
-
<Icon strokeWidth={1.25} class="text-muted-foreground size-6" />
|
|
316
|
-
{/if}
|
|
317
|
-
</CardHeader>
|
|
318
|
-
|
|
319
|
-
<CardContent class="flex flex-col gap-6 p-0">
|
|
320
|
-
<Chart.Container config={chartConfig} class="aspect-auto h-[220px] w-full">
|
|
321
|
-
<LineChart
|
|
322
|
-
data={indexedData}
|
|
323
|
-
x={useIndexX ? '_index' : xKey}
|
|
324
|
-
xScale={useIndexX ? scaleLinear() : scaleUtc()}
|
|
325
|
-
{xDomain}
|
|
326
|
-
yScale={scaleLinear()}
|
|
327
|
-
yDomain={[yMin, yMax]}
|
|
328
|
-
{series}
|
|
329
|
-
tooltip={false}
|
|
330
|
-
props={{
|
|
331
|
-
spline: { curve: curveNatural, strokeWidth: 1.5 },
|
|
332
|
-
yAxis: { ticks: yTicks }
|
|
333
|
-
}}
|
|
334
|
-
/>
|
|
335
|
-
</Chart.Container>
|
|
336
|
-
|
|
337
|
-
{#if series.length > 0}
|
|
338
|
-
<div class="flex items-center justify-center gap-10">
|
|
339
|
-
{#each series as s (s.key)}
|
|
340
|
-
<div class="flex items-center gap-2">
|
|
341
|
-
<div
|
|
342
|
-
class="size-2 rounded-full bg-(--legend-color)"
|
|
343
|
-
style:--legend-color={s.color}
|
|
344
|
-
></div>
|
|
345
|
-
<span class="text-foreground text-sm">{s.label}</span>
|
|
346
|
-
</div>
|
|
347
|
-
{/each}
|
|
348
|
-
</div>
|
|
349
|
-
{/if}
|
|
350
|
-
</CardContent>
|
|
351
|
-
</Card>
|
|
352
|
-
```
|
|
256
|
+
For a complete chart pattern example, see the `sensor-chart` pattern source in `$lib/components/ui/patterns/sensor-chart/`.
|