@dryui/mcp 0.2.1 → 0.3.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.
@@ -4334,21 +4334,10 @@ var compositionRecipes = [
4334
4334
  </body>
4335
4335
  </html>
4336
4336
 
4337
- <!-- 2. src/app.css — global reset with DryUI tokens -->
4337
+ <!-- 2. src/app.css — import themes (resets are built in) -->
4338
4338
  @import '@dryui/ui/themes/default.css';
4339
4339
  @import '@dryui/ui/themes/dark.css';
4340
4340
 
4341
- *, *::before, *::after { box-sizing: border-box; margin: 0; }
4342
-
4343
- html {
4344
- font-family: var(--dry-font-sans);
4345
- color: var(--dry-color-text-strong);
4346
- background: var(--dry-color-bg-base);
4347
- -webkit-font-smoothing: antialiased;
4348
- }
4349
-
4350
- body { margin: 0; min-height: 100dvh; }
4351
-
4352
4341
  <!-- 3. src/routes/+layout.svelte — root layout -->
4353
4342
  <script>
4354
4343
  import '../app.css';
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "schema": "DolphinGraph",
3
- "packageVersion": "0.1.8",
3
+ "packageVersion": "0.1.12",
4
4
  "summary": {
5
5
  "componentNodes": 292,
6
6
  "partNodes": 662,
@@ -4334,21 +4334,10 @@ var compositionRecipes = [
4334
4334
  </body>
4335
4335
  </html>
4336
4336
 
4337
- <!-- 2. src/app.css — global reset with DryUI tokens -->
4337
+ <!-- 2. src/app.css — import themes (resets are built in) -->
4338
4338
  @import '@dryui/ui/themes/default.css';
4339
4339
  @import '@dryui/ui/themes/dark.css';
4340
4340
 
4341
- *, *::before, *::after { box-sizing: border-box; margin: 0; }
4342
-
4343
- html {
4344
- font-family: var(--dry-font-sans);
4345
- color: var(--dry-color-text-strong);
4346
- background: var(--dry-color-bg-base);
4347
- -webkit-font-smoothing: antialiased;
4348
- }
4349
-
4350
- body { margin: 0; min-height: 100dvh; }
4351
-
4352
4341
  <!-- 3. src/routes/+layout.svelte — root layout -->
4353
4342
  <script>
4354
4343
  import '../app.css';
@@ -3,7 +3,7 @@
3
3
  "version": 1,
4
4
  "package": {
5
5
  "name": "@dryui/ui",
6
- "version": "0.1.8"
6
+ "version": "0.1.12"
7
7
  },
8
8
  "counts": {
9
9
  "components": 144,
@@ -11855,14 +11855,18 @@
11855
11855
  ]
11856
11856
  },
11857
11857
  "cssVars": {
11858
+ "--dry-alpha-rgb": "Rgb",
11858
11859
  "--dry-color-picker-area-height": "Picker Area Height",
11859
11860
  "--dry-color-picker-area-width": "Picker Area Width",
11860
11861
  "--dry-color-picker-grid-dark": "Picker Grid Dark",
11861
11862
  "--dry-color-picker-grid-light": "Picker Grid Light",
11862
11863
  "--dry-color-picker-grid-size": "Picker Grid Size",
11863
11864
  "--dry-color-picker-indicator-border": "Picker Indicator Border",
11865
+ "--dry-color-picker-indicator-color": "Picker Indicator Color",
11866
+ "--dry-color-picker-indicator-left": "Picker Indicator Left",
11864
11867
  "--dry-color-picker-indicator-shadow": "Picker Indicator Shadow",
11865
11868
  "--dry-color-picker-indicator-size": "Picker Indicator Size",
11869
+ "--dry-color-picker-indicator-top": "Picker Indicator Top",
11866
11870
  "--dry-color-picker-slider-thumb-bg": "Picker Slider Thumb Bg",
11867
11871
  "--dry-color-picker-slider-thumb-border": "Picker Slider Thumb Border",
11868
11872
  "--dry-color-picker-slider-thumb-shadow": "Picker Slider Thumb Shadow",
@@ -11873,7 +11877,9 @@
11873
11877
  "--dry-color-picker-swatch-size": "Picker Swatch Size",
11874
11878
  "--dry-color-picker-width": "Picker Width",
11875
11879
  "--dry-slider-thumb-size": "Thumb size",
11876
- "--dry-slider-track-height": "Track height"
11880
+ "--dry-slider-track-height": "Track height",
11881
+ "--dry-swatch-color": "Text color",
11882
+ "--dry-swatch-opacity": "Opacity"
11877
11883
  },
11878
11884
  "dataAttributes": [
11879
11885
  {
@@ -12337,7 +12343,13 @@
12337
12343
  ],
12338
12344
  "note": "Forwards <div> attributes via rest props."
12339
12345
  },
12340
- "cssVars": {},
12346
+ "cssVars": {
12347
+ "--dry-spotlight-color": "Text color",
12348
+ "--dry-spotlight-intensity": "Intensity",
12349
+ "--dry-spotlight-radius": "Border radius",
12350
+ "--dry-spotlight-x": "X",
12351
+ "--dry-spotlight-y": "Y"
12352
+ },
12341
12353
  "dataAttributes": [
12342
12354
  {
12343
12355
  "name": "data-active",
@@ -12424,8 +12436,10 @@
12424
12436
  "--dry-aurora-color-2": "Color 2",
12425
12437
  "--dry-aurora-color-3": "Color 3",
12426
12438
  "--dry-aurora-duration": "Duration",
12439
+ "--dry-aurora-intensity": "Intensity",
12427
12440
  "--dry-aurora-shift": "Shift",
12428
- "--dry-aurora-surface": "Surface"
12441
+ "--dry-aurora-surface": "Surface",
12442
+ "--dry-aurora-waviness": "Waviness"
12429
12443
  },
12430
12444
  "dataAttributes": [
12431
12445
  {
@@ -13076,6 +13090,9 @@
13076
13090
  "dataAttributes": [
13077
13091
  {
13078
13092
  "name": "data-virtual-list"
13093
+ },
13094
+ {
13095
+ "name": "data-virtual-list-inner"
13079
13096
  }
13080
13097
  ],
13081
13098
  "example": "<VirtualList>Content</VirtualList>"
@@ -15335,6 +15352,7 @@
15335
15352
  "--dry-image-comparison-handle-shadow": "Comparison Handle Shadow",
15336
15353
  "--dry-image-comparison-handle-width": "Comparison Handle Width",
15337
15354
  "--dry-image-comparison-handle-z-index": "Comparison Handle Z Index",
15355
+ "--dry-image-comparison-position": "Comparison Position",
15338
15356
  "--dry-image-comparison-radius": "Comparison Radius"
15339
15357
  },
15340
15358
  "dataAttributes": [
@@ -17616,7 +17634,13 @@
17616
17634
  ],
17617
17635
  "note": "Forwards <div> attributes via rest props."
17618
17636
  },
17619
- "cssVars": {},
17637
+ "cssVars": {
17638
+ "--dry-beam-angle": "Angle",
17639
+ "--dry-beam-color": "Text color",
17640
+ "--dry-beam-intensity": "Intensity",
17641
+ "--dry-beam-speed": "Speed",
17642
+ "--dry-beam-width": "Width"
17643
+ },
17620
17644
  "dataAttributes": [
17621
17645
  {
17622
17646
  "name": "data-beam"
@@ -17735,7 +17759,14 @@
17735
17759
  ],
17736
17760
  "note": "Forwards <div> attributes via rest props."
17737
17761
  },
17738
- "cssVars": {},
17762
+ "cssVars": {
17763
+ "--dry-rays-blend": "Blend",
17764
+ "--dry-rays-color": "Text color",
17765
+ "--dry-rays-cx": "Cx",
17766
+ "--dry-rays-cy": "Cy",
17767
+ "--dry-rays-intensity": "Intensity",
17768
+ "--dry-rays-speed": "Speed"
17769
+ },
17739
17770
  "dataAttributes": [
17740
17771
  {
17741
17772
  "name": "data-animated"
@@ -22321,7 +22352,7 @@
22321
22352
  "components": [
22322
22353
  "Container"
22323
22354
  ],
22324
- "snippet": "<!-- 1. app.html — add theme-auto class -->\n<!doctype html>\n<html lang=\"en\" class=\"theme-auto\">\n <head>\n <meta charset=\"utf-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n %sveltekit.head%\n </head>\n <body>\n <div style=\"display: contents\">%sveltekit.body%</div>\n </body>\n</html>\n\n<!-- 2. src/app.css — global reset with DryUI tokens -->\n@import '@dryui/ui/themes/default.css';\n@import '@dryui/ui/themes/dark.css';\n\n*, *::before, *::after { box-sizing: border-box; margin: 0; }\n\nhtml {\n font-family: var(--dry-font-sans);\n color: var(--dry-color-text-strong);\n background: var(--dry-color-bg-base);\n -webkit-font-smoothing: antialiased;\n}\n\nbody { margin: 0; min-height: 100dvh; }\n\n<!-- 3. src/routes/+layout.svelte — root layout -->\n<script>\n import '../app.css';\n import { Container } from '@dryui/ui';\n\n let { children } = $props();\n</script>\n\n<header>\n <Container>\n <div class=\"app-header\">My App</div>\n </Container>\n</header>\n<main>\n <Container>\n <div class=\"page-content\">\n {@render children()}\n </div>\n </Container>\n</main>\n\n<style>\n .app-header { padding: var(--dry-space-4) 0; font-weight: bold; }\n .page-content { display: grid; gap: var(--dry-space-6); }\n</style>"
22355
+ "snippet": "<!-- 1. app.html — add theme-auto class -->\n<!doctype html>\n<html lang=\"en\" class=\"theme-auto\">\n <head>\n <meta charset=\"utf-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n %sveltekit.head%\n </head>\n <body>\n <div style=\"display: contents\">%sveltekit.body%</div>\n </body>\n</html>\n\n<!-- 2. src/app.css — import themes (resets are built in) -->\n@import '@dryui/ui/themes/default.css';\n@import '@dryui/ui/themes/dark.css';\n\n<!-- 3. src/routes/+layout.svelte — root layout -->\n<script>\n import '../app.css';\n import { Container } from '@dryui/ui';\n\n let { children } = $props();\n</script>\n\n<header>\n <Container>\n <div class=\"app-header\">My App</div>\n </Container>\n</header>\n<main>\n <Container>\n <div class=\"page-content\">\n {@render children()}\n </div>\n </Container>\n</main>\n\n<style>\n .app-header { padding: var(--dry-space-4) 0; font-weight: bold; }\n .page-content { display: grid; gap: var(--dry-space-6); }\n</style>"
22325
22356
  },
22326
22357
  "page-shell-simple": {
22327
22358
  "name": "page-shell-simple",
package/dist/index.js CHANGED
@@ -8026,6 +8026,18 @@ function detectPackageManager(root) {
8026
8026
  return "yarn";
8027
8027
  return "unknown";
8028
8028
  }
8029
+ function detectPackageManagerFromEnv() {
8030
+ const ua = process.env.npm_config_user_agent ?? "";
8031
+ if (ua.startsWith("bun/"))
8032
+ return "bun";
8033
+ if (ua.startsWith("pnpm/"))
8034
+ return "pnpm";
8035
+ if (ua.startsWith("yarn/"))
8036
+ return "yarn";
8037
+ if (ua.startsWith("npm/"))
8038
+ return "npm";
8039
+ return "npm";
8040
+ }
8029
8041
  function readPackageJson(packageJsonPath) {
8030
8042
  if (!packageJsonPath)
8031
8043
  return null;
@@ -8178,17 +8190,216 @@ function detectProject(spec, inputPath) {
8178
8190
  warnings
8179
8191
  };
8180
8192
  }
8181
- function planInstall(spec, inputPath) {
8182
- const detection = detectProject(spec, inputPath);
8193
+ var SCAFFOLD_PACKAGE_JSON = `{
8194
+ "name": "my-dryui-app",
8195
+ "type": "module",
8196
+ "scripts": {
8197
+ "dev": "vite dev",
8198
+ "build": "vite build",
8199
+ "preview": "vite preview"
8200
+ }
8201
+ }
8202
+ `;
8203
+ var SCAFFOLD_SVELTE_CONFIG = `import adapter from '@sveltejs/adapter-auto';
8204
+
8205
+ export default {
8206
+ kit: {
8207
+ adapter: adapter(),
8208
+ },
8209
+ };
8210
+ `;
8211
+ var SCAFFOLD_VITE_CONFIG = `import { sveltekit } from '@sveltejs/kit/vite';
8212
+ import { defineConfig } from 'vite';
8213
+
8214
+ export default defineConfig({
8215
+ plugins: [sveltekit()],
8216
+ });
8217
+ `;
8218
+ var SCAFFOLD_TSCONFIG = `{
8219
+ "extends": "./.svelte-kit/tsconfig.json",
8220
+ "compilerOptions": {
8221
+ "lib": ["ES2020", "DOM", "DOM.Iterable"],
8222
+ "target": "ES2020"
8223
+ }
8224
+ }
8225
+ `;
8226
+ var SCAFFOLD_APP_HTML = `<!doctype html>
8227
+ <html lang="en" class="theme-auto">
8228
+ <head>
8229
+ <meta charset="utf-8" />
8230
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
8231
+ <link rel="icon" href="/favicon.svg" />
8232
+ %sveltekit.head%
8233
+ </head>
8234
+ <body data-sveltekit-preload-data="hover">
8235
+ <div style="display: contents">%sveltekit.body%</div>
8236
+ </body>
8237
+ </html>
8238
+ `;
8239
+ var SCAFFOLD_APP_CSS = `/* Global reset with DryUI tokens */
8240
+ *,
8241
+ *::before,
8242
+ *::after {
8243
+ box-sizing: border-box;
8244
+ margin: 0;
8245
+ }
8246
+
8247
+ html {
8248
+ font-family: var(--dry-font-sans);
8249
+ color: var(--dry-color-text-strong);
8250
+ background: var(--dry-color-bg-base);
8251
+ -webkit-font-smoothing: antialiased;
8252
+ }
8253
+
8254
+ body {
8255
+ margin: 0;
8256
+ min-height: 100dvh;
8257
+ }
8258
+ `;
8259
+ function buildScaffoldRootLayout(spec) {
8260
+ return `<script>
8261
+ import '../app.css';
8262
+ import '${spec.themeImports.default}';
8263
+ import '${spec.themeImports.dark}';
8264
+
8265
+ let { children } = $props();
8266
+ </script>
8267
+
8268
+ {@render children()}
8269
+ `;
8270
+ }
8271
+ var SCAFFOLD_STARTER_PAGE = `<script lang="ts">
8272
+ import { Container, Heading, Text } from '@dryui/ui';
8273
+ </script>
8274
+
8275
+ <svelte:head>
8276
+ <title>My App</title>
8277
+ </svelte:head>
8278
+
8279
+ <div class="starter">
8280
+ <Container size="md">
8281
+ <Heading level={1}>Hello, World</Heading>
8282
+ <Text size="lg" color="muted">Your DryUI project is ready. Start building.</Text>
8283
+ </Container>
8284
+ </div>
8285
+
8286
+ <style>
8287
+ .starter {
8288
+ padding-block: var(--dry-space-16);
8289
+ display: grid;
8290
+ gap: var(--dry-space-4);
8291
+ }
8292
+ </style>
8293
+ `;
8294
+ var SCAFFOLD_FAVICON = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" fill="none">
8295
+ <rect width="64" height="64" rx="18" fill="#16171f"/>
8296
+ <rect x="10" y="10" width="44" height="44" rx="14" fill="#eef2ff"/>
8297
+ <path d="M20 20h10v24H20z" fill="#1f2937"/>
8298
+ <path d="M34 20h10c4.418 0 8 3.582 8 8v0c0 4.418-3.582 8-8 8h-4v8h-6V20z" fill="#4f46e5"/>
8299
+ <circle cx="44" cy="28" r="4" fill="#f59e0b"/>
8300
+ </svg>
8301
+ `;
8302
+ function getScaffoldFiles(spec) {
8303
+ return [
8304
+ {
8305
+ relativePath: "package.json",
8306
+ content: SCAFFOLD_PACKAGE_JSON,
8307
+ description: "Project manifest with SvelteKit scripts"
8308
+ },
8309
+ {
8310
+ relativePath: "svelte.config.js",
8311
+ content: SCAFFOLD_SVELTE_CONFIG,
8312
+ description: "SvelteKit configuration with adapter-auto"
8313
+ },
8314
+ {
8315
+ relativePath: "vite.config.ts",
8316
+ content: SCAFFOLD_VITE_CONFIG,
8317
+ description: "Vite configuration with SvelteKit plugin"
8318
+ },
8319
+ {
8320
+ relativePath: "tsconfig.json",
8321
+ content: SCAFFOLD_TSCONFIG,
8322
+ description: "TypeScript configuration"
8323
+ },
8324
+ {
8325
+ relativePath: "src/app.html",
8326
+ content: SCAFFOLD_APP_HTML,
8327
+ description: "HTML shell with theme-auto class"
8328
+ },
8329
+ {
8330
+ relativePath: "src/app.css",
8331
+ content: SCAFFOLD_APP_CSS,
8332
+ description: "Foundation CSS reset with DryUI tokens"
8333
+ },
8334
+ {
8335
+ relativePath: "src/routes/+layout.svelte",
8336
+ content: buildScaffoldRootLayout(spec),
8337
+ description: "Root layout with theme imports"
8338
+ },
8339
+ {
8340
+ relativePath: "src/routes/+page.svelte",
8341
+ content: SCAFFOLD_STARTER_PAGE,
8342
+ description: "Starter page with DryUI components"
8343
+ },
8344
+ {
8345
+ relativePath: "static/favicon.svg",
8346
+ content: SCAFFOLD_FAVICON,
8347
+ description: "DryUI project favicon"
8348
+ }
8349
+ ];
8350
+ }
8351
+ function scaffoldCommand(packageManager) {
8352
+ const deps = "svelte @sveltejs/kit @sveltejs/vite-plugin-svelte @sveltejs/adapter-auto vite";
8353
+ switch (packageManager) {
8354
+ case "bun":
8355
+ return `bun add -d ${deps}`;
8356
+ case "pnpm":
8357
+ return `pnpm add -D ${deps}`;
8358
+ case "yarn":
8359
+ return `yarn add -D ${deps}`;
8360
+ default:
8361
+ return `npm install -D ${deps}`;
8362
+ }
8363
+ }
8364
+ function buildScaffoldSteps(spec, root, packageManager, hasPackageJson) {
8183
8365
  const steps = [];
8184
- if (detection.status === "unsupported") {
8366
+ const files = getScaffoldFiles(spec);
8367
+ for (const file of files) {
8368
+ if (file.relativePath === "package.json" && hasPackageJson)
8369
+ continue;
8185
8370
  steps.push({
8186
- kind: "blocked",
8187
- status: "blocked",
8188
- title: "Project detection incomplete",
8189
- description: detection.warnings.join(" ") || "DryUI install planning requires a Svelte or SvelteKit project with a package.json."
8371
+ kind: "create-file",
8372
+ status: "pending",
8373
+ title: `Create ${file.relativePath}`,
8374
+ description: file.description,
8375
+ path: resolve(root, file.relativePath),
8376
+ snippet: file.content
8190
8377
  });
8191
- return { detection, steps };
8378
+ }
8379
+ steps.push({
8380
+ kind: "run-command",
8381
+ status: "pending",
8382
+ title: "Install SvelteKit dependencies",
8383
+ description: "Install Svelte, SvelteKit, Vite, and adapter-auto as dev dependencies.",
8384
+ command: scaffoldCommand(packageManager)
8385
+ });
8386
+ steps.push({
8387
+ kind: "install-package",
8388
+ status: "pending",
8389
+ title: "Install @dryui/ui",
8390
+ description: "Add the styled DryUI package to the project.",
8391
+ command: installCommand(packageManager)
8392
+ });
8393
+ return steps;
8394
+ }
8395
+ function planInstall(spec, inputPath, options) {
8396
+ const detection = detectProject(spec, inputPath);
8397
+ const steps = [];
8398
+ if (detection.status === "unsupported") {
8399
+ const root = detection.root ?? detection.inputPath;
8400
+ const pm = options?.packageManager ?? (detection.packageManager !== "unknown" ? detection.packageManager : detectPackageManagerFromEnv());
8401
+ const scaffoldSteps = buildScaffoldSteps(spec, root, pm, Boolean(detection.packageJsonPath));
8402
+ return { detection, steps: scaffoldSteps };
8192
8403
  }
8193
8404
  if (!detection.dependencies.ui) {
8194
8405
  steps.push({
@@ -9281,25 +9492,31 @@ function toonProjectDetection(detection) {
9281
9492
  return lines.join(`
9282
9493
  `);
9283
9494
  }
9284
- function toonStep(step, index) {
9495
+ function toonStep(step, index, showSnippets = false) {
9285
9496
  const parts = [`${index + 1}. [${step.status}] ${step.title}: ${step.description}`];
9286
9497
  if (step.command)
9287
9498
  parts.push(` cmd: ${step.command}`);
9288
9499
  if (step.path)
9289
9500
  parts.push(` file: ${step.path}`);
9501
+ if (showSnippets && step.snippet && step.kind === "create-file") {
9502
+ parts.push(` ---
9503
+ ${step.snippet} ---`);
9504
+ }
9290
9505
  return parts.join(`
9291
9506
  `);
9292
9507
  }
9293
9508
  function toonInstallPlan(plan) {
9294
9509
  const lines = [];
9510
+ const isScaffold = plan.detection.status === "unsupported" && plan.steps.some((s) => s.kind === "create-file");
9295
9511
  lines.push(toonProjectDetection(plan.detection));
9296
9512
  lines.push("");
9297
9513
  if (plan.steps.length === 0) {
9298
9514
  lines.push("steps[0]: none needed");
9299
9515
  } else {
9300
- lines.push(header("steps", plan.steps.length, ["status", "title", "description"]));
9516
+ const label = isScaffold ? "scaffold-steps" : "steps";
9517
+ lines.push(header(label, plan.steps.length, ["status", "title", "description"]));
9301
9518
  for (const [i, step] of plan.steps.entries()) {
9302
- lines.push(toonStep(step, i));
9519
+ lines.push(toonStep(step, i, isScaffold));
9303
9520
  }
9304
9521
  }
9305
9522
  const help = buildContextualHelp({ command: "install" });
@@ -1,7 +1,7 @@
1
1
  export type DryuiFramework = 'sveltekit' | 'svelte' | 'unknown';
2
2
  export type DryuiPackageManager = 'bun' | 'pnpm' | 'npm' | 'yarn' | 'unknown';
3
3
  export type DryuiProjectStatus = 'ready' | 'partial' | 'unsupported';
4
- export type DryuiPlanStepKind = 'install-package' | 'edit-file' | 'create-file' | 'note' | 'blocked';
4
+ export type DryuiPlanStepKind = 'install-package' | 'run-command' | 'edit-file' | 'create-file' | 'note' | 'blocked';
5
5
  export type DryuiPlanStepStatus = 'done' | 'pending' | 'info' | 'blocked';
6
6
  export interface ProjectPlannerComponentDef {
7
7
  readonly import: string;
@@ -68,6 +68,10 @@ export interface PlanAddOptions {
68
68
  readonly subpath?: boolean;
69
69
  readonly withTheme?: boolean;
70
70
  }
71
+ export declare function detectPackageManagerFromEnv(): DryuiPackageManager;
71
72
  export declare function detectProject(spec: Pick<ProjectPlannerSpec, 'themeImports'>, inputPath?: string): ProjectDetection;
72
- export declare function planInstall(spec: ProjectPlannerSpec, inputPath?: string): InstallPlan;
73
+ export interface PlanInstallOptions {
74
+ readonly packageManager?: DryuiPackageManager;
75
+ }
76
+ export declare function planInstall(spec: ProjectPlannerSpec, inputPath?: string, options?: PlanInstallOptions): InstallPlan;
73
77
  export declare function planAdd(spec: ProjectPlannerSpec, query: string, options?: PlanAddOptions): AddPlan;
@@ -104,6 +104,18 @@ function detectPackageManager(root) {
104
104
  return "yarn";
105
105
  return "unknown";
106
106
  }
107
+ function detectPackageManagerFromEnv() {
108
+ const ua = process.env.npm_config_user_agent ?? "";
109
+ if (ua.startsWith("bun/"))
110
+ return "bun";
111
+ if (ua.startsWith("pnpm/"))
112
+ return "pnpm";
113
+ if (ua.startsWith("yarn/"))
114
+ return "yarn";
115
+ if (ua.startsWith("npm/"))
116
+ return "npm";
117
+ return "npm";
118
+ }
107
119
  function readPackageJson(packageJsonPath) {
108
120
  if (!packageJsonPath)
109
121
  return null;
@@ -256,17 +268,216 @@ function detectProject(spec, inputPath) {
256
268
  warnings
257
269
  };
258
270
  }
259
- function planInstall(spec, inputPath) {
260
- const detection = detectProject(spec, inputPath);
271
+ var SCAFFOLD_PACKAGE_JSON = `{
272
+ "name": "my-dryui-app",
273
+ "type": "module",
274
+ "scripts": {
275
+ "dev": "vite dev",
276
+ "build": "vite build",
277
+ "preview": "vite preview"
278
+ }
279
+ }
280
+ `;
281
+ var SCAFFOLD_SVELTE_CONFIG = `import adapter from '@sveltejs/adapter-auto';
282
+
283
+ export default {
284
+ kit: {
285
+ adapter: adapter(),
286
+ },
287
+ };
288
+ `;
289
+ var SCAFFOLD_VITE_CONFIG = `import { sveltekit } from '@sveltejs/kit/vite';
290
+ import { defineConfig } from 'vite';
291
+
292
+ export default defineConfig({
293
+ plugins: [sveltekit()],
294
+ });
295
+ `;
296
+ var SCAFFOLD_TSCONFIG = `{
297
+ "extends": "./.svelte-kit/tsconfig.json",
298
+ "compilerOptions": {
299
+ "lib": ["ES2020", "DOM", "DOM.Iterable"],
300
+ "target": "ES2020"
301
+ }
302
+ }
303
+ `;
304
+ var SCAFFOLD_APP_HTML = `<!doctype html>
305
+ <html lang="en" class="theme-auto">
306
+ <head>
307
+ <meta charset="utf-8" />
308
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
309
+ <link rel="icon" href="/favicon.svg" />
310
+ %sveltekit.head%
311
+ </head>
312
+ <body data-sveltekit-preload-data="hover">
313
+ <div style="display: contents">%sveltekit.body%</div>
314
+ </body>
315
+ </html>
316
+ `;
317
+ var SCAFFOLD_APP_CSS = `/* Global reset with DryUI tokens */
318
+ *,
319
+ *::before,
320
+ *::after {
321
+ box-sizing: border-box;
322
+ margin: 0;
323
+ }
324
+
325
+ html {
326
+ font-family: var(--dry-font-sans);
327
+ color: var(--dry-color-text-strong);
328
+ background: var(--dry-color-bg-base);
329
+ -webkit-font-smoothing: antialiased;
330
+ }
331
+
332
+ body {
333
+ margin: 0;
334
+ min-height: 100dvh;
335
+ }
336
+ `;
337
+ function buildScaffoldRootLayout(spec) {
338
+ return `<script>
339
+ import '../app.css';
340
+ import '${spec.themeImports.default}';
341
+ import '${spec.themeImports.dark}';
342
+
343
+ let { children } = $props();
344
+ </script>
345
+
346
+ {@render children()}
347
+ `;
348
+ }
349
+ var SCAFFOLD_STARTER_PAGE = `<script lang="ts">
350
+ import { Container, Heading, Text } from '@dryui/ui';
351
+ </script>
352
+
353
+ <svelte:head>
354
+ <title>My App</title>
355
+ </svelte:head>
356
+
357
+ <div class="starter">
358
+ <Container size="md">
359
+ <Heading level={1}>Hello, World</Heading>
360
+ <Text size="lg" color="muted">Your DryUI project is ready. Start building.</Text>
361
+ </Container>
362
+ </div>
363
+
364
+ <style>
365
+ .starter {
366
+ padding-block: var(--dry-space-16);
367
+ display: grid;
368
+ gap: var(--dry-space-4);
369
+ }
370
+ </style>
371
+ `;
372
+ var SCAFFOLD_FAVICON = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" fill="none">
373
+ <rect width="64" height="64" rx="18" fill="#16171f"/>
374
+ <rect x="10" y="10" width="44" height="44" rx="14" fill="#eef2ff"/>
375
+ <path d="M20 20h10v24H20z" fill="#1f2937"/>
376
+ <path d="M34 20h10c4.418 0 8 3.582 8 8v0c0 4.418-3.582 8-8 8h-4v8h-6V20z" fill="#4f46e5"/>
377
+ <circle cx="44" cy="28" r="4" fill="#f59e0b"/>
378
+ </svg>
379
+ `;
380
+ function getScaffoldFiles(spec) {
381
+ return [
382
+ {
383
+ relativePath: "package.json",
384
+ content: SCAFFOLD_PACKAGE_JSON,
385
+ description: "Project manifest with SvelteKit scripts"
386
+ },
387
+ {
388
+ relativePath: "svelte.config.js",
389
+ content: SCAFFOLD_SVELTE_CONFIG,
390
+ description: "SvelteKit configuration with adapter-auto"
391
+ },
392
+ {
393
+ relativePath: "vite.config.ts",
394
+ content: SCAFFOLD_VITE_CONFIG,
395
+ description: "Vite configuration with SvelteKit plugin"
396
+ },
397
+ {
398
+ relativePath: "tsconfig.json",
399
+ content: SCAFFOLD_TSCONFIG,
400
+ description: "TypeScript configuration"
401
+ },
402
+ {
403
+ relativePath: "src/app.html",
404
+ content: SCAFFOLD_APP_HTML,
405
+ description: "HTML shell with theme-auto class"
406
+ },
407
+ {
408
+ relativePath: "src/app.css",
409
+ content: SCAFFOLD_APP_CSS,
410
+ description: "Foundation CSS reset with DryUI tokens"
411
+ },
412
+ {
413
+ relativePath: "src/routes/+layout.svelte",
414
+ content: buildScaffoldRootLayout(spec),
415
+ description: "Root layout with theme imports"
416
+ },
417
+ {
418
+ relativePath: "src/routes/+page.svelte",
419
+ content: SCAFFOLD_STARTER_PAGE,
420
+ description: "Starter page with DryUI components"
421
+ },
422
+ {
423
+ relativePath: "static/favicon.svg",
424
+ content: SCAFFOLD_FAVICON,
425
+ description: "DryUI project favicon"
426
+ }
427
+ ];
428
+ }
429
+ function scaffoldCommand(packageManager) {
430
+ const deps = "svelte @sveltejs/kit @sveltejs/vite-plugin-svelte @sveltejs/adapter-auto vite";
431
+ switch (packageManager) {
432
+ case "bun":
433
+ return `bun add -d ${deps}`;
434
+ case "pnpm":
435
+ return `pnpm add -D ${deps}`;
436
+ case "yarn":
437
+ return `yarn add -D ${deps}`;
438
+ default:
439
+ return `npm install -D ${deps}`;
440
+ }
441
+ }
442
+ function buildScaffoldSteps(spec, root, packageManager, hasPackageJson) {
261
443
  const steps = [];
262
- if (detection.status === "unsupported") {
444
+ const files = getScaffoldFiles(spec);
445
+ for (const file of files) {
446
+ if (file.relativePath === "package.json" && hasPackageJson)
447
+ continue;
263
448
  steps.push({
264
- kind: "blocked",
265
- status: "blocked",
266
- title: "Project detection incomplete",
267
- description: detection.warnings.join(" ") || "DryUI install planning requires a Svelte or SvelteKit project with a package.json."
449
+ kind: "create-file",
450
+ status: "pending",
451
+ title: `Create ${file.relativePath}`,
452
+ description: file.description,
453
+ path: resolve(root, file.relativePath),
454
+ snippet: file.content
268
455
  });
269
- return { detection, steps };
456
+ }
457
+ steps.push({
458
+ kind: "run-command",
459
+ status: "pending",
460
+ title: "Install SvelteKit dependencies",
461
+ description: "Install Svelte, SvelteKit, Vite, and adapter-auto as dev dependencies.",
462
+ command: scaffoldCommand(packageManager)
463
+ });
464
+ steps.push({
465
+ kind: "install-package",
466
+ status: "pending",
467
+ title: "Install @dryui/ui",
468
+ description: "Add the styled DryUI package to the project.",
469
+ command: installCommand(packageManager)
470
+ });
471
+ return steps;
472
+ }
473
+ function planInstall(spec, inputPath, options) {
474
+ const detection = detectProject(spec, inputPath);
475
+ const steps = [];
476
+ if (detection.status === "unsupported") {
477
+ const root = detection.root ?? detection.inputPath;
478
+ const pm = options?.packageManager ?? (detection.packageManager !== "unknown" ? detection.packageManager : detectPackageManagerFromEnv());
479
+ const scaffoldSteps = buildScaffoldSteps(spec, root, pm, Boolean(detection.packageJsonPath));
480
+ return { detection, steps: scaffoldSteps };
270
481
  }
271
482
  if (!detection.dependencies.ui) {
272
483
  steps.push({
@@ -382,5 +593,6 @@ ${component.def.example}`
382
593
  export {
383
594
  planInstall,
384
595
  planAdd,
385
- detectProject
596
+ detectProject,
597
+ detectPackageManagerFromEnv
386
598
  };
package/dist/spec.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "0.1.8",
2
+ "version": "0.1.12",
3
3
  "package": "@dryui/ui",
4
4
  "themeImports": {
5
5
  "default": "@dryui/ui/themes/default.css",
@@ -11711,14 +11711,18 @@
11711
11711
  ]
11712
11712
  },
11713
11713
  "cssVars": {
11714
+ "--dry-alpha-rgb": "Rgb",
11714
11715
  "--dry-color-picker-area-height": "Picker Area Height",
11715
11716
  "--dry-color-picker-area-width": "Picker Area Width",
11716
11717
  "--dry-color-picker-grid-dark": "Picker Grid Dark",
11717
11718
  "--dry-color-picker-grid-light": "Picker Grid Light",
11718
11719
  "--dry-color-picker-grid-size": "Picker Grid Size",
11719
11720
  "--dry-color-picker-indicator-border": "Picker Indicator Border",
11721
+ "--dry-color-picker-indicator-color": "Picker Indicator Color",
11722
+ "--dry-color-picker-indicator-left": "Picker Indicator Left",
11720
11723
  "--dry-color-picker-indicator-shadow": "Picker Indicator Shadow",
11721
11724
  "--dry-color-picker-indicator-size": "Picker Indicator Size",
11725
+ "--dry-color-picker-indicator-top": "Picker Indicator Top",
11722
11726
  "--dry-color-picker-slider-thumb-bg": "Picker Slider Thumb Bg",
11723
11727
  "--dry-color-picker-slider-thumb-border": "Picker Slider Thumb Border",
11724
11728
  "--dry-color-picker-slider-thumb-shadow": "Picker Slider Thumb Shadow",
@@ -11729,7 +11733,9 @@
11729
11733
  "--dry-color-picker-swatch-size": "Picker Swatch Size",
11730
11734
  "--dry-color-picker-width": "Picker Width",
11731
11735
  "--dry-slider-thumb-size": "Thumb size",
11732
- "--dry-slider-track-height": "Track height"
11736
+ "--dry-slider-track-height": "Track height",
11737
+ "--dry-swatch-color": "Text color",
11738
+ "--dry-swatch-opacity": "Opacity"
11733
11739
  },
11734
11740
  "dataAttributes": [
11735
11741
  {
@@ -12193,7 +12199,13 @@
12193
12199
  ],
12194
12200
  "note": "Forwards <div> attributes via rest props."
12195
12201
  },
12196
- "cssVars": {},
12202
+ "cssVars": {
12203
+ "--dry-spotlight-color": "Text color",
12204
+ "--dry-spotlight-intensity": "Intensity",
12205
+ "--dry-spotlight-radius": "Border radius",
12206
+ "--dry-spotlight-x": "X",
12207
+ "--dry-spotlight-y": "Y"
12208
+ },
12197
12209
  "dataAttributes": [
12198
12210
  {
12199
12211
  "name": "data-active",
@@ -12280,8 +12292,10 @@
12280
12292
  "--dry-aurora-color-2": "Color 2",
12281
12293
  "--dry-aurora-color-3": "Color 3",
12282
12294
  "--dry-aurora-duration": "Duration",
12295
+ "--dry-aurora-intensity": "Intensity",
12283
12296
  "--dry-aurora-shift": "Shift",
12284
- "--dry-aurora-surface": "Surface"
12297
+ "--dry-aurora-surface": "Surface",
12298
+ "--dry-aurora-waviness": "Waviness"
12285
12299
  },
12286
12300
  "dataAttributes": [
12287
12301
  {
@@ -12932,6 +12946,9 @@
12932
12946
  "dataAttributes": [
12933
12947
  {
12934
12948
  "name": "data-virtual-list"
12949
+ },
12950
+ {
12951
+ "name": "data-virtual-list-inner"
12935
12952
  }
12936
12953
  ],
12937
12954
  "example": "<VirtualList>Content</VirtualList>"
@@ -15191,6 +15208,7 @@
15191
15208
  "--dry-image-comparison-handle-shadow": "Comparison Handle Shadow",
15192
15209
  "--dry-image-comparison-handle-width": "Comparison Handle Width",
15193
15210
  "--dry-image-comparison-handle-z-index": "Comparison Handle Z Index",
15211
+ "--dry-image-comparison-position": "Comparison Position",
15194
15212
  "--dry-image-comparison-radius": "Comparison Radius"
15195
15213
  },
15196
15214
  "dataAttributes": [
@@ -17472,7 +17490,13 @@
17472
17490
  ],
17473
17491
  "note": "Forwards <div> attributes via rest props."
17474
17492
  },
17475
- "cssVars": {},
17493
+ "cssVars": {
17494
+ "--dry-beam-angle": "Angle",
17495
+ "--dry-beam-color": "Text color",
17496
+ "--dry-beam-intensity": "Intensity",
17497
+ "--dry-beam-speed": "Speed",
17498
+ "--dry-beam-width": "Width"
17499
+ },
17476
17500
  "dataAttributes": [
17477
17501
  {
17478
17502
  "name": "data-beam"
@@ -17591,7 +17615,14 @@
17591
17615
  ],
17592
17616
  "note": "Forwards <div> attributes via rest props."
17593
17617
  },
17594
- "cssVars": {},
17618
+ "cssVars": {
17619
+ "--dry-rays-blend": "Blend",
17620
+ "--dry-rays-color": "Text color",
17621
+ "--dry-rays-cx": "Cx",
17622
+ "--dry-rays-cy": "Cy",
17623
+ "--dry-rays-intensity": "Intensity",
17624
+ "--dry-rays-speed": "Speed"
17625
+ },
17595
17626
  "dataAttributes": [
17596
17627
  {
17597
17628
  "name": "data-animated"
@@ -22177,7 +22208,7 @@
22177
22208
  "components": [
22178
22209
  "Container"
22179
22210
  ],
22180
- "snippet": "<!-- 1. app.html — add theme-auto class -->\n<!doctype html>\n<html lang=\"en\" class=\"theme-auto\">\n <head>\n <meta charset=\"utf-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n %sveltekit.head%\n </head>\n <body>\n <div style=\"display: contents\">%sveltekit.body%</div>\n </body>\n</html>\n\n<!-- 2. src/app.css — global reset with DryUI tokens -->\n@import '@dryui/ui/themes/default.css';\n@import '@dryui/ui/themes/dark.css';\n\n*, *::before, *::after { box-sizing: border-box; margin: 0; }\n\nhtml {\n font-family: var(--dry-font-sans);\n color: var(--dry-color-text-strong);\n background: var(--dry-color-bg-base);\n -webkit-font-smoothing: antialiased;\n}\n\nbody { margin: 0; min-height: 100dvh; }\n\n<!-- 3. src/routes/+layout.svelte — root layout -->\n<script>\n import '../app.css';\n import { Container } from '@dryui/ui';\n\n let { children } = $props();\n</script>\n\n<header>\n <Container>\n <div class=\"app-header\">My App</div>\n </Container>\n</header>\n<main>\n <Container>\n <div class=\"page-content\">\n {@render children()}\n </div>\n </Container>\n</main>\n\n<style>\n .app-header { padding: var(--dry-space-4) 0; font-weight: bold; }\n .page-content { display: grid; gap: var(--dry-space-6); }\n</style>"
22211
+ "snippet": "<!-- 1. app.html — add theme-auto class -->\n<!doctype html>\n<html lang=\"en\" class=\"theme-auto\">\n <head>\n <meta charset=\"utf-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n %sveltekit.head%\n </head>\n <body>\n <div style=\"display: contents\">%sveltekit.body%</div>\n </body>\n</html>\n\n<!-- 2. src/app.css — import themes (resets are built in) -->\n@import '@dryui/ui/themes/default.css';\n@import '@dryui/ui/themes/dark.css';\n\n<!-- 3. src/routes/+layout.svelte — root layout -->\n<script>\n import '../app.css';\n import { Container } from '@dryui/ui';\n\n let { children } = $props();\n</script>\n\n<header>\n <Container>\n <div class=\"app-header\">My App</div>\n </Container>\n</header>\n<main>\n <Container>\n <div class=\"page-content\">\n {@render children()}\n </div>\n </Container>\n</main>\n\n<style>\n .app-header { padding: var(--dry-space-4) 0; font-weight: bold; }\n .page-content { display: grid; gap: var(--dry-space-6); }\n</style>"
22181
22212
  },
22182
22213
  "page-shell-simple": {
22183
22214
  "name": "page-shell-simple",
package/dist/toon.js CHANGED
@@ -396,25 +396,31 @@ function toonProjectDetection(detection) {
396
396
  return lines.join(`
397
397
  `);
398
398
  }
399
- function toonStep(step, index) {
399
+ function toonStep(step, index, showSnippets = false) {
400
400
  const parts = [`${index + 1}. [${step.status}] ${step.title}: ${step.description}`];
401
401
  if (step.command)
402
402
  parts.push(` cmd: ${step.command}`);
403
403
  if (step.path)
404
404
  parts.push(` file: ${step.path}`);
405
+ if (showSnippets && step.snippet && step.kind === "create-file") {
406
+ parts.push(` ---
407
+ ${step.snippet} ---`);
408
+ }
405
409
  return parts.join(`
406
410
  `);
407
411
  }
408
412
  function toonInstallPlan(plan) {
409
413
  const lines = [];
414
+ const isScaffold = plan.detection.status === "unsupported" && plan.steps.some((s) => s.kind === "create-file");
410
415
  lines.push(toonProjectDetection(plan.detection));
411
416
  lines.push("");
412
417
  if (plan.steps.length === 0) {
413
418
  lines.push("steps[0]: none needed");
414
419
  } else {
415
- lines.push(header("steps", plan.steps.length, ["status", "title", "description"]));
420
+ const label = isScaffold ? "scaffold-steps" : "steps";
421
+ lines.push(header(label, plan.steps.length, ["status", "title", "description"]));
416
422
  for (const [i, step] of plan.steps.entries()) {
417
- lines.push(toonStep(step, i));
423
+ lines.push(toonStep(step, i, isScaffold));
418
424
  }
419
425
  }
420
426
  const help = buildContextualHelp({ command: "install" });
@@ -1553,6 +1553,18 @@ function detectPackageManager(root) {
1553
1553
  return "yarn";
1554
1554
  return "unknown";
1555
1555
  }
1556
+ function detectPackageManagerFromEnv() {
1557
+ const ua = process.env.npm_config_user_agent ?? "";
1558
+ if (ua.startsWith("bun/"))
1559
+ return "bun";
1560
+ if (ua.startsWith("pnpm/"))
1561
+ return "pnpm";
1562
+ if (ua.startsWith("yarn/"))
1563
+ return "yarn";
1564
+ if (ua.startsWith("npm/"))
1565
+ return "npm";
1566
+ return "npm";
1567
+ }
1556
1568
  function readPackageJson(packageJsonPath) {
1557
1569
  if (!packageJsonPath)
1558
1570
  return null;
@@ -1705,17 +1717,216 @@ function detectProject(spec, inputPath) {
1705
1717
  warnings
1706
1718
  };
1707
1719
  }
1708
- function planInstall(spec, inputPath) {
1709
- const detection = detectProject(spec, inputPath);
1720
+ var SCAFFOLD_PACKAGE_JSON = `{
1721
+ "name": "my-dryui-app",
1722
+ "type": "module",
1723
+ "scripts": {
1724
+ "dev": "vite dev",
1725
+ "build": "vite build",
1726
+ "preview": "vite preview"
1727
+ }
1728
+ }
1729
+ `;
1730
+ var SCAFFOLD_SVELTE_CONFIG = `import adapter from '@sveltejs/adapter-auto';
1731
+
1732
+ export default {
1733
+ kit: {
1734
+ adapter: adapter(),
1735
+ },
1736
+ };
1737
+ `;
1738
+ var SCAFFOLD_VITE_CONFIG = `import { sveltekit } from '@sveltejs/kit/vite';
1739
+ import { defineConfig } from 'vite';
1740
+
1741
+ export default defineConfig({
1742
+ plugins: [sveltekit()],
1743
+ });
1744
+ `;
1745
+ var SCAFFOLD_TSCONFIG = `{
1746
+ "extends": "./.svelte-kit/tsconfig.json",
1747
+ "compilerOptions": {
1748
+ "lib": ["ES2020", "DOM", "DOM.Iterable"],
1749
+ "target": "ES2020"
1750
+ }
1751
+ }
1752
+ `;
1753
+ var SCAFFOLD_APP_HTML = `<!doctype html>
1754
+ <html lang="en" class="theme-auto">
1755
+ <head>
1756
+ <meta charset="utf-8" />
1757
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
1758
+ <link rel="icon" href="/favicon.svg" />
1759
+ %sveltekit.head%
1760
+ </head>
1761
+ <body data-sveltekit-preload-data="hover">
1762
+ <div style="display: contents">%sveltekit.body%</div>
1763
+ </body>
1764
+ </html>
1765
+ `;
1766
+ var SCAFFOLD_APP_CSS = `/* Global reset with DryUI tokens */
1767
+ *,
1768
+ *::before,
1769
+ *::after {
1770
+ box-sizing: border-box;
1771
+ margin: 0;
1772
+ }
1773
+
1774
+ html {
1775
+ font-family: var(--dry-font-sans);
1776
+ color: var(--dry-color-text-strong);
1777
+ background: var(--dry-color-bg-base);
1778
+ -webkit-font-smoothing: antialiased;
1779
+ }
1780
+
1781
+ body {
1782
+ margin: 0;
1783
+ min-height: 100dvh;
1784
+ }
1785
+ `;
1786
+ function buildScaffoldRootLayout(spec) {
1787
+ return `<script>
1788
+ import '../app.css';
1789
+ import '${spec.themeImports.default}';
1790
+ import '${spec.themeImports.dark}';
1791
+
1792
+ let { children } = $props();
1793
+ </script>
1794
+
1795
+ {@render children()}
1796
+ `;
1797
+ }
1798
+ var SCAFFOLD_STARTER_PAGE = `<script lang="ts">
1799
+ import { Container, Heading, Text } from '@dryui/ui';
1800
+ </script>
1801
+
1802
+ <svelte:head>
1803
+ <title>My App</title>
1804
+ </svelte:head>
1805
+
1806
+ <div class="starter">
1807
+ <Container size="md">
1808
+ <Heading level={1}>Hello, World</Heading>
1809
+ <Text size="lg" color="muted">Your DryUI project is ready. Start building.</Text>
1810
+ </Container>
1811
+ </div>
1812
+
1813
+ <style>
1814
+ .starter {
1815
+ padding-block: var(--dry-space-16);
1816
+ display: grid;
1817
+ gap: var(--dry-space-4);
1818
+ }
1819
+ </style>
1820
+ `;
1821
+ var SCAFFOLD_FAVICON = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" fill="none">
1822
+ <rect width="64" height="64" rx="18" fill="#16171f"/>
1823
+ <rect x="10" y="10" width="44" height="44" rx="14" fill="#eef2ff"/>
1824
+ <path d="M20 20h10v24H20z" fill="#1f2937"/>
1825
+ <path d="M34 20h10c4.418 0 8 3.582 8 8v0c0 4.418-3.582 8-8 8h-4v8h-6V20z" fill="#4f46e5"/>
1826
+ <circle cx="44" cy="28" r="4" fill="#f59e0b"/>
1827
+ </svg>
1828
+ `;
1829
+ function getScaffoldFiles(spec) {
1830
+ return [
1831
+ {
1832
+ relativePath: "package.json",
1833
+ content: SCAFFOLD_PACKAGE_JSON,
1834
+ description: "Project manifest with SvelteKit scripts"
1835
+ },
1836
+ {
1837
+ relativePath: "svelte.config.js",
1838
+ content: SCAFFOLD_SVELTE_CONFIG,
1839
+ description: "SvelteKit configuration with adapter-auto"
1840
+ },
1841
+ {
1842
+ relativePath: "vite.config.ts",
1843
+ content: SCAFFOLD_VITE_CONFIG,
1844
+ description: "Vite configuration with SvelteKit plugin"
1845
+ },
1846
+ {
1847
+ relativePath: "tsconfig.json",
1848
+ content: SCAFFOLD_TSCONFIG,
1849
+ description: "TypeScript configuration"
1850
+ },
1851
+ {
1852
+ relativePath: "src/app.html",
1853
+ content: SCAFFOLD_APP_HTML,
1854
+ description: "HTML shell with theme-auto class"
1855
+ },
1856
+ {
1857
+ relativePath: "src/app.css",
1858
+ content: SCAFFOLD_APP_CSS,
1859
+ description: "Foundation CSS reset with DryUI tokens"
1860
+ },
1861
+ {
1862
+ relativePath: "src/routes/+layout.svelte",
1863
+ content: buildScaffoldRootLayout(spec),
1864
+ description: "Root layout with theme imports"
1865
+ },
1866
+ {
1867
+ relativePath: "src/routes/+page.svelte",
1868
+ content: SCAFFOLD_STARTER_PAGE,
1869
+ description: "Starter page with DryUI components"
1870
+ },
1871
+ {
1872
+ relativePath: "static/favicon.svg",
1873
+ content: SCAFFOLD_FAVICON,
1874
+ description: "DryUI project favicon"
1875
+ }
1876
+ ];
1877
+ }
1878
+ function scaffoldCommand(packageManager) {
1879
+ const deps = "svelte @sveltejs/kit @sveltejs/vite-plugin-svelte @sveltejs/adapter-auto vite";
1880
+ switch (packageManager) {
1881
+ case "bun":
1882
+ return `bun add -d ${deps}`;
1883
+ case "pnpm":
1884
+ return `pnpm add -D ${deps}`;
1885
+ case "yarn":
1886
+ return `yarn add -D ${deps}`;
1887
+ default:
1888
+ return `npm install -D ${deps}`;
1889
+ }
1890
+ }
1891
+ function buildScaffoldSteps(spec, root, packageManager, hasPackageJson) {
1710
1892
  const steps = [];
1711
- if (detection.status === "unsupported") {
1893
+ const files = getScaffoldFiles(spec);
1894
+ for (const file of files) {
1895
+ if (file.relativePath === "package.json" && hasPackageJson)
1896
+ continue;
1712
1897
  steps.push({
1713
- kind: "blocked",
1714
- status: "blocked",
1715
- title: "Project detection incomplete",
1716
- description: detection.warnings.join(" ") || "DryUI install planning requires a Svelte or SvelteKit project with a package.json."
1898
+ kind: "create-file",
1899
+ status: "pending",
1900
+ title: `Create ${file.relativePath}`,
1901
+ description: file.description,
1902
+ path: resolve(root, file.relativePath),
1903
+ snippet: file.content
1717
1904
  });
1718
- return { detection, steps };
1905
+ }
1906
+ steps.push({
1907
+ kind: "run-command",
1908
+ status: "pending",
1909
+ title: "Install SvelteKit dependencies",
1910
+ description: "Install Svelte, SvelteKit, Vite, and adapter-auto as dev dependencies.",
1911
+ command: scaffoldCommand(packageManager)
1912
+ });
1913
+ steps.push({
1914
+ kind: "install-package",
1915
+ status: "pending",
1916
+ title: "Install @dryui/ui",
1917
+ description: "Add the styled DryUI package to the project.",
1918
+ command: installCommand(packageManager)
1919
+ });
1920
+ return steps;
1921
+ }
1922
+ function planInstall(spec, inputPath, options) {
1923
+ const detection = detectProject(spec, inputPath);
1924
+ const steps = [];
1925
+ if (detection.status === "unsupported") {
1926
+ const root = detection.root ?? detection.inputPath;
1927
+ const pm = options?.packageManager ?? (detection.packageManager !== "unknown" ? detection.packageManager : detectPackageManagerFromEnv());
1928
+ const scaffoldSteps = buildScaffoldSteps(spec, root, pm, Boolean(detection.packageJsonPath));
1929
+ return { detection, steps: scaffoldSteps };
1719
1930
  }
1720
1931
  if (!detection.dependencies.ui) {
1721
1932
  steps.push({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dryui/mcp",
3
- "version": "0.2.1",
3
+ "version": "0.3.0",
4
4
  "author": "Rob Balfre",
5
5
  "license": "MIT",
6
6
  "repository": {