@archetypeai/ds-cli 0.9.1 → 0.10.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.
- package/README.md +3 -3
- package/commands/create.js +2 -2
- package/commands/init.js +2 -2
- package/files/AGENTS.md +128 -70
- package/files/CLAUDE.md +128 -70
- package/files/ds-manifest.json +998 -1024
- package/lib/add-ds-config-codeagent.js +3 -57
- package/package.json +2 -2
- package/files/LICENSE +0 -21
- package/files/rules/accessibility.md +0 -268
- package/files/rules/charts.md +0 -256
- package/files/rules/components.md +0 -251
- package/files/rules/design-principles.md +0 -71
- package/files/rules/frontend-architecture.md +0 -86
- package/files/rules/linting.md +0 -31
- package/files/rules/state.md +0 -373
- package/files/rules/styling.md +0 -142
- package/files/skills/apply-ds/SKILL.md +0 -121
- package/files/skills/apply-ds/scripts/audit.sh +0 -169
- package/files/skills/apply-ds/scripts/setup.sh +0 -153
- package/files/skills/build-component/SKILL.md +0 -153
- package/files/skills/create-dashboard/SKILL.md +0 -220
- package/files/skills/deploy-worker/SKILL.md +0 -231
- package/files/skills/deploy-worker/references/wrangler-commands.md +0 -327
- package/files/skills/fix-accessibility/SKILL.md +0 -232
- package/files/skills/fix-metadata/SKILL.md +0 -118
- package/files/skills/fix-metadata/assets/favicon.ico +0 -0
- package/files/skills/setup-chart/SKILL.md +0 -223
- package/files/skills/setup-chart/data/embedding.csv +0 -42
- package/files/skills/setup-chart/data/timeseries.csv +0 -173
- package/files/skills/setup-chart/references/scatter-chart.md +0 -229
- package/files/skills/setup-chart/references/sensor-chart.md +0 -156
|
@@ -1,251 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
paths:
|
|
3
|
-
- '**/components/**/*.svelte'
|
|
4
|
-
- '$lib/**/*.svelte'
|
|
5
|
-
- '**/custom/**/*.svelte'
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
# Component Authoring Rules
|
|
9
|
-
|
|
10
|
-
## Props Pattern
|
|
11
|
-
|
|
12
|
-
Every component should destructure props using `$props()` with this standard pattern:
|
|
13
|
-
|
|
14
|
-
```svelte
|
|
15
|
-
<script>
|
|
16
|
-
import { cn } from '$lib/utils.js';
|
|
17
|
-
|
|
18
|
-
let { ref = $bindable(null), class: className, children, ...restProps } = $props();
|
|
19
|
-
</script>
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
Key points:
|
|
23
|
-
|
|
24
|
-
- `ref = $bindable(null)` - enables parent to bind to DOM element
|
|
25
|
-
- `class: className` - rename to avoid reserved word conflict
|
|
26
|
-
- `children` - snippet for slot content
|
|
27
|
-
- `...restProps` - capture remaining props for spreading
|
|
28
|
-
|
|
29
|
-
## data-slot Attributes
|
|
30
|
-
|
|
31
|
-
Add `data-slot` to root elements for identification and styling hooks:
|
|
32
|
-
|
|
33
|
-
```svelte
|
|
34
|
-
<div bind:this={ref} data-slot="card" class={cn('bg-card ...', className)} {...restProps}>
|
|
35
|
-
{@render children?.()}
|
|
36
|
-
</div>
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
This enables parent styling like `*:data-[slot=card]:p-4`.
|
|
40
|
-
|
|
41
|
-
## Class Merging with cn()
|
|
42
|
-
|
|
43
|
-
Always use `cn()` for class composition - never raw string concatenation:
|
|
44
|
-
|
|
45
|
-
```svelte
|
|
46
|
-
<!-- Correct -->
|
|
47
|
-
<div class={cn('bg-card text-card-foreground', className)}>
|
|
48
|
-
|
|
49
|
-
<!-- Wrong -->
|
|
50
|
-
<div class={`bg-card text-card-foreground ${className}`}>
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
`cn()` uses clsx + tailwind-merge to properly handle class conflicts.
|
|
54
|
-
|
|
55
|
-
## bits-ui Wrapper Pattern
|
|
56
|
-
|
|
57
|
-
When wrapping bits-ui primitives, import the primitive and wrap it:
|
|
58
|
-
|
|
59
|
-
```svelte
|
|
60
|
-
<script>
|
|
61
|
-
import { Select as SelectPrimitive } from 'bits-ui';
|
|
62
|
-
import { cn } from '$lib/utils.js';
|
|
63
|
-
|
|
64
|
-
let { ref = $bindable(null), class: className, children, ...restProps } = $props();
|
|
65
|
-
</script>
|
|
66
|
-
|
|
67
|
-
<SelectPrimitive.Trigger
|
|
68
|
-
bind:ref
|
|
69
|
-
data-slot="select-trigger"
|
|
70
|
-
class={cn('border-input bg-transparent ...', className)}
|
|
71
|
-
{...restProps}
|
|
72
|
-
>
|
|
73
|
-
{@render children?.()}
|
|
74
|
-
</SelectPrimitive.Trigger>
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
For the full component catalog with import paths, read `ds-manifest.json` at the project root (see `@skills/build-component`).
|
|
78
|
-
|
|
79
|
-
## tailwind-variants (tv)
|
|
80
|
-
|
|
81
|
-
Define variants in `<script module>` for reuse and export:
|
|
82
|
-
|
|
83
|
-
```svelte
|
|
84
|
-
<script module>
|
|
85
|
-
import { cn } from '$lib/utils.js';
|
|
86
|
-
import { tv } from 'tailwind-variants';
|
|
87
|
-
|
|
88
|
-
export const buttonVariants = tv({
|
|
89
|
-
base: 'inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors',
|
|
90
|
-
variants: {
|
|
91
|
-
variant: {
|
|
92
|
-
default: 'bg-primary text-primary-foreground hover:bg-primary/90',
|
|
93
|
-
destructive: 'bg-destructive text-white hover:bg-destructive/90',
|
|
94
|
-
outline: 'border bg-background hover:bg-accent',
|
|
95
|
-
secondary: 'bg-secondary text-secondary-foreground hover:bg-secondary/80',
|
|
96
|
-
ghost: 'hover:bg-accent hover:text-accent-foreground',
|
|
97
|
-
link: 'text-primary underline-offset-4 hover:underline'
|
|
98
|
-
},
|
|
99
|
-
size: {
|
|
100
|
-
default: 'h-9 px-4 py-2',
|
|
101
|
-
sm: 'h-8 px-3 rounded-md',
|
|
102
|
-
lg: 'h-10 px-6 rounded-md',
|
|
103
|
-
icon: 'size-9'
|
|
104
|
-
}
|
|
105
|
-
},
|
|
106
|
-
defaultVariants: {
|
|
107
|
-
variant: 'default',
|
|
108
|
-
size: 'default'
|
|
109
|
-
}
|
|
110
|
-
});
|
|
111
|
-
</script>
|
|
112
|
-
|
|
113
|
-
<script>
|
|
114
|
-
let { variant = 'default', size = 'default', class: className, ...restProps } = $props();
|
|
115
|
-
</script>
|
|
116
|
-
|
|
117
|
-
<button class={cn(buttonVariants({ variant, size }), className)} {...restProps}>
|
|
118
|
-
{@render children?.()}
|
|
119
|
-
</button>
|
|
120
|
-
```
|
|
121
|
-
|
|
122
|
-
## Snippet Slots
|
|
123
|
-
|
|
124
|
-
Use `{@render}` for slot content:
|
|
125
|
-
|
|
126
|
-
```svelte
|
|
127
|
-
<!-- Default slot -->
|
|
128
|
-
{@render children?.()}
|
|
129
|
-
|
|
130
|
-
<!-- Named snippets (passed as props) -->
|
|
131
|
-
{#snippet icon()}
|
|
132
|
-
<ChevronDown />
|
|
133
|
-
{/snippet}
|
|
134
|
-
|
|
135
|
-
<Button {icon}>Click me</Button>
|
|
136
|
-
|
|
137
|
-
<!-- In component, render the snippet prop -->
|
|
138
|
-
{@render icon?.()}
|
|
139
|
-
```
|
|
140
|
-
|
|
141
|
-
## restProps Spreading
|
|
142
|
-
|
|
143
|
-
Always spread `...restProps` on the root element to pass through attributes:
|
|
144
|
-
|
|
145
|
-
```svelte
|
|
146
|
-
<button
|
|
147
|
-
bind:this={ref}
|
|
148
|
-
data-slot="button"
|
|
149
|
-
class={cn(buttonVariants({ variant, size }), className)}
|
|
150
|
-
{type}
|
|
151
|
-
{disabled}
|
|
152
|
-
{...restProps}
|
|
153
|
-
>
|
|
154
|
-
{@render children?.()}
|
|
155
|
-
</button>
|
|
156
|
-
```
|
|
157
|
-
|
|
158
|
-
## Conditional Rendering
|
|
159
|
-
|
|
160
|
-
Use standard Svelte `{#if}` blocks for conditional content:
|
|
161
|
-
|
|
162
|
-
```svelte
|
|
163
|
-
{#if href}
|
|
164
|
-
<a bind:this={ref} data-slot="button" {href} {...restProps}>
|
|
165
|
-
{@render children?.()}
|
|
166
|
-
</a>
|
|
167
|
-
{:else}
|
|
168
|
-
<button bind:this={ref} data-slot="button" {...restProps}>
|
|
169
|
-
{@render children?.()}
|
|
170
|
-
</button>
|
|
171
|
-
{/if}
|
|
172
|
-
```
|
|
173
|
-
|
|
174
|
-
## Icon Handling
|
|
175
|
-
|
|
176
|
-
Icons from Lucide use consistent sizing classes:
|
|
177
|
-
|
|
178
|
-
```svelte
|
|
179
|
-
<script>
|
|
180
|
-
import ChevronDownIcon from '@lucide/svelte/icons/chevron-down';
|
|
181
|
-
</script>
|
|
182
|
-
|
|
183
|
-
<ChevronDownIcon class="size-4 opacity-50" />
|
|
184
|
-
```
|
|
185
|
-
|
|
186
|
-
Default icon sizing in buttons: `[&_svg:not([class*='size-'])]:size-4`
|
|
187
|
-
|
|
188
|
-
## Example: Complete Card Component
|
|
189
|
-
|
|
190
|
-
```svelte
|
|
191
|
-
<script>
|
|
192
|
-
import { cn } from '$lib/utils.js';
|
|
193
|
-
|
|
194
|
-
let { ref = $bindable(null), class: className, children, ...restProps } = $props();
|
|
195
|
-
</script>
|
|
196
|
-
|
|
197
|
-
<div
|
|
198
|
-
bind:this={ref}
|
|
199
|
-
data-slot="card"
|
|
200
|
-
class={cn(
|
|
201
|
-
'bg-card text-card-foreground flex flex-col gap-6 rounded-md border py-6 shadow-sm',
|
|
202
|
-
className
|
|
203
|
-
)}
|
|
204
|
-
{...restProps}
|
|
205
|
-
>
|
|
206
|
-
{@render children?.()}
|
|
207
|
-
</div>
|
|
208
|
-
```
|
|
209
|
-
|
|
210
|
-
## Example: Dialog Content with bits-ui
|
|
211
|
-
|
|
212
|
-
```svelte
|
|
213
|
-
<script>
|
|
214
|
-
import { Dialog as DialogPrimitive } from 'bits-ui';
|
|
215
|
-
import DialogPortal from './dialog-portal.svelte';
|
|
216
|
-
import XIcon from '@lucide/svelte/icons/x';
|
|
217
|
-
import * as Dialog from './index.js';
|
|
218
|
-
import { cn } from '$lib/utils.js';
|
|
219
|
-
|
|
220
|
-
let {
|
|
221
|
-
ref = $bindable(null),
|
|
222
|
-
class: className,
|
|
223
|
-
portalProps,
|
|
224
|
-
children,
|
|
225
|
-
showCloseButton = true,
|
|
226
|
-
...restProps
|
|
227
|
-
} = $props();
|
|
228
|
-
</script>
|
|
229
|
-
|
|
230
|
-
<DialogPortal {...portalProps}>
|
|
231
|
-
<Dialog.Overlay />
|
|
232
|
-
<DialogPrimitive.Content
|
|
233
|
-
bind:ref
|
|
234
|
-
data-slot="dialog-content"
|
|
235
|
-
class={cn(
|
|
236
|
-
'bg-background fixed top-[50%] left-[50%] z-50 w-full max-w-lg translate-x-[-50%] translate-y-[-50%] rounded-lg border p-6 shadow-lg',
|
|
237
|
-
'data-[state=open]:animate-in data-[state=closed]:animate-out',
|
|
238
|
-
className
|
|
239
|
-
)}
|
|
240
|
-
{...restProps}
|
|
241
|
-
>
|
|
242
|
-
{@render children?.()}
|
|
243
|
-
{#if showCloseButton}
|
|
244
|
-
<DialogPrimitive.Close class="absolute end-4 top-4 rounded-xs opacity-70 hover:opacity-100">
|
|
245
|
-
<XIcon />
|
|
246
|
-
<span class="sr-only">Close</span>
|
|
247
|
-
</DialogPrimitive.Close>
|
|
248
|
-
{/if}
|
|
249
|
-
</DialogPrimitive.Content>
|
|
250
|
-
</DialogPortal>
|
|
251
|
-
```
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
paths:
|
|
3
|
-
- '**/*.svelte'
|
|
4
|
-
- '**/+page.svelte'
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
# Physical AI Design Principles
|
|
8
|
-
|
|
9
|
-
## Scope
|
|
10
|
-
|
|
11
|
-
This design system targets the **Measure** and **Reason** layers of the Physical AI stack. Interfaces built with it should support **augmentation** (helping humans perceive the physical world) and **dialogue** (helping humans reason about it). Operation and cooperation — where AI takes action in the world — are out of scope currently but will become relevant in the future.
|
|
12
|
-
|
|
13
|
-
## The Physical AI Stack
|
|
14
|
-
|
|
15
|
-
Physical AI capabilities form a dependency stack where each layer builds on the one below:
|
|
16
|
-
|
|
17
|
-
1. **Interpret** — Make the physical world legible by surfacing signals, anomalies, and structures from sensor data
|
|
18
|
-
2. **Reason** — Enable shared reasoning between humans and AI: explore hypotheses, compare alternatives, support decisions
|
|
19
|
-
3. **Operate** — Delegated action: human sets intent, system executes within defined boundaries (future scope)
|
|
20
|
-
4. **Co-operate** — Joint action: shared agency through mutual adjustment between humans and AI (future scope)
|
|
21
|
-
|
|
22
|
-
## Agency
|
|
23
|
-
|
|
24
|
-
### Human Agency Comes First
|
|
25
|
-
|
|
26
|
-
At the Measure layer, the AI augments human perception — it surfaces what would otherwise remain invisible. The human retains full responsibility to interpret and act. Interfaces should present information without prescribing conclusions.
|
|
27
|
-
|
|
28
|
-
At the Reason layer, interaction is dialogic. The AI contributes explanations and comparisons, but the human drives inquiry and judgment. Interfaces should enable exploration, not deliver verdicts.
|
|
29
|
-
|
|
30
|
-
At the Operate layer, humans shift from direct control to goal-setting and supervision. The AI executes within defined boundaries, and responsibility becomes distributed. Interfaces should make intent, constraints, and system behavior transparent.
|
|
31
|
-
|
|
32
|
-
At the Co-operate layer, humans and AI act as coordinated participants. Action is jointly negotiated, and intent, context, and responsibility are shared and continuously adjusted. Interfaces should support mutual awareness and fluid handoffs.
|
|
33
|
-
|
|
34
|
-
### Interaction Is Situated
|
|
35
|
-
|
|
36
|
-
Interaction unfolds within a three-way relationship: **person, system, and physical world**. Meaning arises from how sensor data, context, and human intent come together in a specific place and moment. Interfaces must maintain this connection to the physical context being observed — sensor sources, locations, time ranges, environmental conditions. Do not abstract away the situational grounding.
|
|
37
|
-
|
|
38
|
-
## Design Implications
|
|
39
|
-
|
|
40
|
-
### Make the World Legible
|
|
41
|
-
|
|
42
|
-
- Prioritize data clarity: visualizations should reveal structure in sensor data — trends, anomalies, distributions, correlations
|
|
43
|
-
- Use semantic tokens (e.g. `text-atai-good`, `text-atai-warning`, `text-atai-critical`) to communicate meaningful states, not for decorative emphasis
|
|
44
|
-
- Design for continuous monitoring: prefer dashboards and live views over static reports
|
|
45
|
-
|
|
46
|
-
### Support Dialogue, Not Monologue
|
|
47
|
-
|
|
48
|
-
- Provide entry points for inquiry: interfaces should invite questions, comparisons, and hypothesis exploration
|
|
49
|
-
- Frame AI output as contribution, not conclusion — use language and layout that position AI reasoning as input to human judgment
|
|
50
|
-
- Enable iterative refinement: conversational flows, follow-up exploration, adjustable parameters
|
|
51
|
-
|
|
52
|
-
### Preserve Physical Context
|
|
53
|
-
|
|
54
|
-
- Show provenance: which sensors, what time range, what conditions produced the data being displayed
|
|
55
|
-
- Ground abstract representations in physical reality — link charts to sensor locations, timestamps to real events
|
|
56
|
-
- Consider operational environments: interfaces may be used in the field, not only at a desk
|
|
57
|
-
|
|
58
|
-
### Respect the Stack Boundary
|
|
59
|
-
|
|
60
|
-
- Default to interfaces that support perception and reasoning rather than autonomous AI action
|
|
61
|
-
- Where possible, distinguish between "the system shows" (Measure) and "the system suggests" (Reason)
|
|
62
|
-
- Prefer framing AI output as observations or suggestions rather than commands or decisions
|
|
63
|
-
|
|
64
|
-
## Aesthetic Conventions
|
|
65
|
-
|
|
66
|
-
### Typography
|
|
67
|
-
- Use mono font (`font-mono`) with careful consideration: prefer it on badges, buttons, card headers, and numeric values. Do not apply mono to body text or descriptions.
|
|
68
|
-
|
|
69
|
-
### Card Defaults
|
|
70
|
-
- For single-purpose card components (status display, score, chart), use BackgroundCard as the default container.
|
|
71
|
-
- Status cards showing a single metric or state often do not need a CardHeader — omit when content is self-explanatory.
|
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
paths:
|
|
3
|
-
- '**/routes/**/*.svelte'
|
|
4
|
-
- '**/+page.svelte'
|
|
5
|
-
- '**/+layout.svelte'
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
# Frontend Architecture
|
|
9
|
-
|
|
10
|
-
When building a page that involves more than a simple static layout, decompose it into components rather than writing a monolithic `+page.svelte`.
|
|
11
|
-
|
|
12
|
-
## When to extract a component
|
|
13
|
-
|
|
14
|
-
Extract a component when a section of UI has:
|
|
15
|
-
|
|
16
|
-
- 3+ primitives composed together (Card + Badge + Button = a status card)
|
|
17
|
-
- Its own reactive state (`$state`, `$derived`)
|
|
18
|
-
- Potential for reuse across pages or skills
|
|
19
|
-
|
|
20
|
-
Common extraction candidates: media inputs, status displays, result/summary views, streaming logs, file upload flows.
|
|
21
|
-
|
|
22
|
-
## Gold-standard references
|
|
23
|
-
|
|
24
|
-
The labs package ships composite components that demonstrate these conventions. Study their source (registry URLs in `ds-manifest.json`) before building new ones:
|
|
25
|
-
|
|
26
|
-
- `video-player` (labs) — media playback with controls, composes console Card + Button with labs AspectRatio + Slider
|
|
27
|
-
- `menubar` (labs) — branded header with snippet slots, composes console Button + the theme `darkMode` store
|
|
28
|
-
- `sensor-chart` / `scatter-chart` (labs) — chart cards with typed data/axis config
|
|
29
|
-
|
|
30
|
-
Check `ds-manifest.json` for an existing component that fits before building a new one. Use `@skills/build-component` to create new components that follow these same conventions.
|
|
31
|
-
|
|
32
|
-
## Directory structure
|
|
33
|
-
|
|
34
|
-
Components come from the npm packages by default — most projects need no local copies at all.
|
|
35
|
-
|
|
36
|
-
```
|
|
37
|
-
$lib/components/ui/
|
|
38
|
-
custom/ — project-specific components composed from the packages
|
|
39
|
-
<name>/ — registry-installed editable source (only for deliberately modified components)
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
Place custom components (ones you create for this project) in `$lib/components/ui/custom/`. Never edit anything in `node_modules`, and never put custom components next to registry-installed source.
|
|
43
|
-
|
|
44
|
-
## Component conventions
|
|
45
|
-
|
|
46
|
-
Follow `@rules/components` for the full conventions. The essentials:
|
|
47
|
-
|
|
48
|
-
- `let { class: className, ...restProps } = $props();`
|
|
49
|
-
- `cn()` for all class merging — never raw string concatenation
|
|
50
|
-
- `$derived` for computed state
|
|
51
|
-
- Spread `...restProps` on the root element
|
|
52
|
-
- Compose from DS package components (Card, Badge, Button, etc.) — not raw HTML
|
|
53
|
-
|
|
54
|
-
## Page-level orchestration
|
|
55
|
-
|
|
56
|
-
`+page.svelte` is the orchestrator. It should:
|
|
57
|
-
|
|
58
|
-
- Own flow state (status, session IDs, error messages)
|
|
59
|
-
- Import and compose child components
|
|
60
|
-
- Pass data down via props
|
|
61
|
-
- Handle top-level layout (using `@skills/create-dashboard` for dashboard layouts)
|
|
62
|
-
|
|
63
|
-
Components should be presentational where possible — receive data via props, emit events up.
|
|
64
|
-
|
|
65
|
-
## API and streaming logic extraction
|
|
66
|
-
|
|
67
|
-
SSE consumers, fetch wrappers, polling loops, and data transforms belong in a utility file, not inline in components or pages:
|
|
68
|
-
|
|
69
|
-
```
|
|
70
|
-
src/lib/api/activity-monitor.js — SSE + session management
|
|
71
|
-
src/lib/api/machine-state.js — streaming + windowing
|
|
72
|
-
```
|
|
73
|
-
|
|
74
|
-
This keeps components focused on rendering and makes API logic testable and reusable.
|
|
75
|
-
|
|
76
|
-
## Streaming UI
|
|
77
|
-
|
|
78
|
-
For skills that stream results (SSE, polling), prefer:
|
|
79
|
-
|
|
80
|
-
- Progressive rendering — show results as they arrive, don't wait for completion
|
|
81
|
-
- Live counters or progress indicators
|
|
82
|
-
- Auto-scrolling log views
|
|
83
|
-
|
|
84
|
-
## Override clause
|
|
85
|
-
|
|
86
|
-
If the user explicitly requests a single-file prototype, a minimal example, or specifies a different structure, follow their instruction. These guidelines apply to production-quality demos, not quick experiments.
|
package/files/rules/linting.md
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
# Linting & Formatting
|
|
2
|
-
|
|
3
|
-
## Commands
|
|
4
|
-
|
|
5
|
-
| Command | Description |
|
|
6
|
-
| ---------------------- | -------------------------------- |
|
|
7
|
-
| `npm run lint` | Check for linting errors |
|
|
8
|
-
| `npm run lint:fix` | Auto-fix linting errors |
|
|
9
|
-
| `npm run format` | Format all files with Prettier |
|
|
10
|
-
| `npm run format:check` | Check formatting without changes |
|
|
11
|
-
|
|
12
|
-
## Stack
|
|
13
|
-
|
|
14
|
-
- **ESLint** - Flat config (v9+) with `eslint-plugin-svelte`
|
|
15
|
-
- **Prettier** - Code formatting
|
|
16
|
-
- **prettier-plugin-svelte** - Svelte file formatting
|
|
17
|
-
- **prettier-plugin-tailwindcss** - Auto-sorts Tailwind classes
|
|
18
|
-
|
|
19
|
-
## Workflow
|
|
20
|
-
|
|
21
|
-
Run linting and formatting before committing:
|
|
22
|
-
|
|
23
|
-
```bash
|
|
24
|
-
npm run lint:fix && npm run format
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
Or check without auto-fixing:
|
|
28
|
-
|
|
29
|
-
```bash
|
|
30
|
-
npm run lint && npm run format:check
|
|
31
|
-
```
|