@stayicon/drift-guard 0.2.2 โ†’ 0.2.3

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 CHANGED
@@ -7,9 +7,18 @@
7
7
  [![npm version](https://img.shields.io/npm/v/@stayicon/drift-guard)](https://www.npmjs.com/package/@stayicon/drift-guard)
8
8
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
9
9
  [![Tests](https://img.shields.io/badge/tests-130%2F130-brightgreen)](https://github.com/Hwani-Net/drift-guard)
10
+ [![Zero Dependencies](https://img.shields.io/badge/dependencies-zero-blue)](https://www.npmjs.com/package/@stayicon/drift-guard)
10
11
 
11
12
  <p align="center">
12
- <img src="docs/assets/cli-demo.png" alt="drift-guard CLI demo" width="680">
13
+ <img src="docs/assets/cli-demo.png" alt="drift-guard CLI demo showing design drift detection" width="680">
14
+ </p>
15
+
16
+ <p align="center">
17
+ <b>
18
+ <a href="https://hwani-net.github.io/drift-guard/">๐ŸŽฎ Try the Interactive Demo</a> ยท
19
+ <a href="https://www.npmjs.com/package/@stayicon/drift-guard">๐Ÿ“ฆ npm</a> ยท
20
+ <a href="#quick-start">๐Ÿš€ Quick Start</a>
21
+ </b>
13
22
  </p>
14
23
 
15
24
  ---
@@ -39,6 +48,10 @@ npx drift-guard rules
39
48
  npx drift-guard check
40
49
  ```
41
50
 
51
+ **Zero token overhead.** No MCP server. No configuration. Just CLI.
52
+
53
+ > ๐Ÿ“บ **[Try the Interactive Demo โ†’](https://hwani-net.github.io/drift-guard/)** โ€” See drift-guard in action, right in your browser.
54
+
42
55
  ## How It Works
43
56
 
44
57
  ```
@@ -115,7 +128,7 @@ npx drift-guard snapshot update
115
128
  ## What Gets Protected
116
129
 
117
130
  | Category | Properties | Example |
118
- |----------|-----------|---------|
131
+ |----------|-----------|---------|
119
132
  | ๐ŸŽจ Colors | `color`, `background-color`, `border-color`, CSS variables | `--primary: #1a73e8` |
120
133
  | ๐Ÿ“ Fonts | `font-family`, `font-size`, `font-weight`, `line-height` | `font-family: Inter` |
121
134
  | ๐Ÿ“ Spacing | `margin`, `padding`, `gap` | `padding: 16px 24px` |
@@ -125,9 +138,9 @@ npx drift-guard snapshot update
125
138
  | โœจ Effects | `backdrop-filter`, `filter`, `animation`, `transition` | `backdrop-filter: blur(10px)` |
126
139
  | ๐Ÿ—๏ธ Structure | Semantic tags, DOM depth, layout hash, child sequence | `<header> โ†’ <nav> โ†’ <main> โ†’ <footer>` |
127
140
 
128
- ### DOM Structure Detection (v0.2.0)
141
+ ### DOM Structure Detection (v0.2.0+)
129
142
 
130
- drift-guard now fingerprints your HTML structure โ€” not just CSS tokens.
143
+ drift-guard fingerprints your HTML structure โ€” not just CSS tokens.
131
144
 
132
145
  ```bash
133
146
  # Initialize with structure tracking (on by default)
@@ -216,6 +229,12 @@ const rules = generateRules(snapshot, 'claude-md');
216
229
  | **Token overhead** | 0 tokens (CLI) | N/A |
217
230
  | **Cost** | Free, forever | Percy: $99+/mo for teams |
218
231
 
232
+ ## Why CLI, Not MCP?
233
+
234
+ > MCP tool registration costs ~10,000+ tokens per server at conversation start. drift-guard's CLI costs **0 tokens**. AI agents already know how to run `npx` commands.
235
+
236
+ Read more: [ADR-007: CLI-First Strategy](docs/DECISIONS.md#adr-007-cli-first-์ „๋žต--mcp-๋ž˜ํผ-๋ฐฐํฌ-๋ณด๋ฅ˜-2026-03-12)
237
+
219
238
  ## Philosophy
220
239
 
221
240
  > AI should **add features**, not **destroy design**.
package/dist/cli/index.js CHANGED
@@ -24,6 +24,8 @@ import { Command as Command2 } from "commander";
24
24
  import chalk6 from "chalk";
25
25
 
26
26
  // src/cli/init.ts
27
+ import fs from "fs";
28
+ import path from "path";
27
29
  import chalk from "chalk";
28
30
  async function initCommand(options) {
29
31
  const projectRoot = process.cwd();
@@ -65,12 +67,94 @@ async function initCommand(options) {
65
67
  console.log(chalk.dim(" \u{1F3D7}\uFE0F layout hash: ") + chalk.white(s.layoutHash));
66
68
  }
67
69
  console.log();
68
- console.log(chalk.dim("Next steps:"));
69
- console.log(chalk.cyan(" 1. ") + "Add .design-guard/ to .gitignore (optional)");
70
- console.log(chalk.cyan(" 2. ") + chalk.bold("npx drift-guard rules") + " \u2014 Generate AI agent protection rules");
71
- console.log(chalk.cyan(" 3. ") + chalk.bold("npx drift-guard check") + " \u2014 Check for design drift anytime");
70
+ if (!options.skipRules) {
71
+ try {
72
+ const content = generateRules(snapshot, "agents-md");
73
+ const rulesPath = saveRules(projectRoot, "agents-md", content, false);
74
+ console.log(chalk.green("\u2705 AI agent rules generated: ") + chalk.white(rulesPath));
75
+ } catch (error) {
76
+ console.log(chalk.yellow("\u26A0\uFE0F Could not generate rules: ") + chalk.dim(error.message));
77
+ }
78
+ } else {
79
+ console.log(chalk.dim(" \u23ED Skipped rules generation (--skip-rules)"));
80
+ }
81
+ if (!options.skipHook) {
82
+ const hasGit = fs.existsSync(path.join(projectRoot, ".git"));
83
+ if (hasGit) {
84
+ try {
85
+ installHookSilent(projectRoot, threshold.toString());
86
+ console.log(chalk.green("\u2705 Pre-commit hook installed: ") + chalk.dim("drift-guard check runs before every commit"));
87
+ } catch (error) {
88
+ console.log(chalk.yellow("\u26A0\uFE0F Could not install hook: ") + chalk.dim(error.message));
89
+ }
90
+ } else {
91
+ console.log(chalk.dim(" \u23ED No .git directory found \u2014 skipping hook install"));
92
+ }
93
+ } else {
94
+ console.log(chalk.dim(" \u23ED Skipped hook installation (--skip-hook)"));
95
+ }
96
+ console.log();
97
+ console.log(chalk.green.bold(" \u{1F6E1}\uFE0F Protection active!"));
98
+ console.log(chalk.dim(" Run ") + chalk.cyan("npx drift-guard check") + chalk.dim(" anytime to verify design integrity."));
99
+ if (!options.skipRules) {
100
+ console.log(chalk.dim(" Run ") + chalk.cyan("npx drift-guard rules --format all") + chalk.dim(" for additional AI tool formats."));
101
+ }
72
102
  console.log();
73
103
  }
104
+ function installHookSilent(projectRoot, threshold) {
105
+ const hasHusky = fs.existsSync(path.join(projectRoot, ".husky"));
106
+ const hookCommand = `npx drift-guard check --threshold ${threshold} --ci`;
107
+ if (hasHusky) {
108
+ const hookFile2 = path.join(projectRoot, ".husky", "pre-commit");
109
+ if (fs.existsSync(hookFile2)) {
110
+ const existing = fs.readFileSync(hookFile2, "utf-8");
111
+ if (existing.includes("drift-guard")) return;
112
+ fs.appendFileSync(hookFile2, `
113
+ ${hookCommand}
114
+ `);
115
+ } else {
116
+ fs.writeFileSync(hookFile2, `#!/usr/bin/env sh
117
+ . "$(dirname -- "$0")/_/husky.sh"
118
+
119
+ ${hookCommand}
120
+ `);
121
+ }
122
+ return;
123
+ }
124
+ const hooksDir = path.join(projectRoot, ".git", "hooks");
125
+ const hookFile = path.join(hooksDir, "pre-commit");
126
+ const hookScript = `#!/usr/bin/env sh
127
+ # drift-guard pre-commit hook
128
+ # Checks for design token drift before commits
129
+ # Bypass: git commit --no-verify
130
+
131
+ npx drift-guard check --threshold ${threshold} --ci
132
+
133
+ if [ $? -ne 0 ]; then
134
+ echo ""
135
+ echo "\\033[31m\u2717 Design drift detected! Commit blocked.\\033[0m"
136
+ echo " Run 'npx drift-guard check' for details."
137
+ echo " If changes are intentional, run 'npx drift-guard snapshot update'"
138
+ echo " Or use 'git commit --no-verify' to bypass."
139
+ exit 1
140
+ fi
141
+ `;
142
+ if (!fs.existsSync(hooksDir)) {
143
+ fs.mkdirSync(hooksDir, { recursive: true });
144
+ }
145
+ if (fs.existsSync(hookFile)) {
146
+ const existing = fs.readFileSync(hookFile, "utf-8");
147
+ if (existing.includes("drift-guard")) return;
148
+ fs.appendFileSync(hookFile, `
149
+ ${hookScript}`);
150
+ } else {
151
+ fs.writeFileSync(hookFile, hookScript);
152
+ try {
153
+ fs.chmodSync(hookFile, 493);
154
+ } catch {
155
+ }
156
+ }
157
+ }
74
158
 
75
159
  // src/cli/check.ts
76
160
  import chalk2 from "chalk";
@@ -228,32 +312,32 @@ async function snapshotCommand(options) {
228
312
  }
229
313
 
230
314
  // src/cli/hook.ts
231
- import fs from "fs";
232
- import path from "path";
315
+ import fs2 from "fs";
316
+ import path2 from "path";
233
317
  import chalk5 from "chalk";
234
318
  async function hookInstallCommand(options) {
235
319
  const cwd = process.cwd();
236
320
  const threshold = options.threshold ?? "10";
237
- if (!fs.existsSync(path.join(cwd, ".git"))) {
321
+ if (!fs2.existsSync(path2.join(cwd, ".git"))) {
238
322
  console.error(chalk5.red("\u2717 Not a git repository. Run this from a git project root."));
239
323
  process.exit(1);
240
324
  }
241
- const hasHusky = fs.existsSync(path.join(cwd, ".husky"));
242
- const hasLefthook = fs.existsSync(path.join(cwd, "lefthook.yml")) || fs.existsSync(path.join(cwd, ".lefthook.yml"));
325
+ const hasHusky = fs2.existsSync(path2.join(cwd, ".husky"));
326
+ const hasLefthook = fs2.existsSync(path2.join(cwd, "lefthook.yml")) || fs2.existsSync(path2.join(cwd, ".lefthook.yml"));
243
327
  if (hasHusky) {
244
- const hookFile2 = path.join(cwd, ".husky", "pre-commit");
328
+ const hookFile2 = path2.join(cwd, ".husky", "pre-commit");
245
329
  const hookCommand = `npx drift-guard check --threshold ${threshold} --ci`;
246
- if (fs.existsSync(hookFile2)) {
247
- const existing = fs.readFileSync(hookFile2, "utf-8");
330
+ if (fs2.existsSync(hookFile2)) {
331
+ const existing = fs2.readFileSync(hookFile2, "utf-8");
248
332
  if (existing.includes("drift-guard")) {
249
333
  console.log(chalk5.yellow("\u26A0 drift-guard hook already exists in .husky/pre-commit"));
250
334
  return;
251
335
  }
252
- fs.appendFileSync(hookFile2, `
336
+ fs2.appendFileSync(hookFile2, `
253
337
  ${hookCommand}
254
338
  `);
255
339
  } else {
256
- fs.writeFileSync(hookFile2, `#!/usr/bin/env sh
340
+ fs2.writeFileSync(hookFile2, `#!/usr/bin/env sh
257
341
  . "$(dirname -- "$0")/_/husky.sh"
258
342
 
259
343
  ${hookCommand}
@@ -272,8 +356,8 @@ pre-commit:
272
356
  `));
273
357
  return;
274
358
  }
275
- const hooksDir = path.join(cwd, ".git", "hooks");
276
- const hookFile = path.join(hooksDir, "pre-commit");
359
+ const hooksDir = path2.join(cwd, ".git", "hooks");
360
+ const hookFile = path2.join(hooksDir, "pre-commit");
277
361
  const hookScript = `#!/usr/bin/env sh
278
362
  # drift-guard pre-commit hook
279
363
  # Checks for design token drift before commits
@@ -290,22 +374,22 @@ if [ $? -ne 0 ]; then
290
374
  exit 1
291
375
  fi
292
376
  `;
293
- if (!fs.existsSync(hooksDir)) {
294
- fs.mkdirSync(hooksDir, { recursive: true });
377
+ if (!fs2.existsSync(hooksDir)) {
378
+ fs2.mkdirSync(hooksDir, { recursive: true });
295
379
  }
296
- if (fs.existsSync(hookFile)) {
297
- const existing = fs.readFileSync(hookFile, "utf-8");
380
+ if (fs2.existsSync(hookFile)) {
381
+ const existing = fs2.readFileSync(hookFile, "utf-8");
298
382
  if (existing.includes("drift-guard")) {
299
383
  console.log(chalk5.yellow("\u26A0 drift-guard hook already installed"));
300
384
  return;
301
385
  }
302
- fs.appendFileSync(hookFile, `
386
+ fs2.appendFileSync(hookFile, `
303
387
  ${hookScript}`);
304
388
  console.log(chalk5.green("\u2713 Appended drift-guard to existing pre-commit hook"));
305
389
  } else {
306
- fs.writeFileSync(hookFile, hookScript);
390
+ fs2.writeFileSync(hookFile, hookScript);
307
391
  try {
308
- fs.chmodSync(hookFile, 493);
392
+ fs2.chmodSync(hookFile, 493);
309
393
  } catch {
310
394
  }
311
395
  console.log(chalk5.green("\u2713 Installed drift-guard pre-commit hook"));
@@ -315,26 +399,26 @@ ${hookScript}`);
315
399
  }
316
400
  async function hookUninstallCommand() {
317
401
  const cwd = process.cwd();
318
- const huskyHook = path.join(cwd, ".husky", "pre-commit");
319
- if (fs.existsSync(huskyHook)) {
320
- const content = fs.readFileSync(huskyHook, "utf-8");
402
+ const huskyHook = path2.join(cwd, ".husky", "pre-commit");
403
+ if (fs2.existsSync(huskyHook)) {
404
+ const content = fs2.readFileSync(huskyHook, "utf-8");
321
405
  if (content.includes("drift-guard")) {
322
406
  const cleaned = content.replace(/\n?npx drift-guard.*\n?/g, "\n");
323
- fs.writeFileSync(huskyHook, cleaned);
407
+ fs2.writeFileSync(huskyHook, cleaned);
324
408
  console.log(chalk5.green("\u2713 Removed drift-guard from .husky/pre-commit"));
325
409
  return;
326
410
  }
327
411
  }
328
- const gitHook = path.join(cwd, ".git", "hooks", "pre-commit");
329
- if (fs.existsSync(gitHook)) {
330
- const content = fs.readFileSync(gitHook, "utf-8");
412
+ const gitHook = path2.join(cwd, ".git", "hooks", "pre-commit");
413
+ if (fs2.existsSync(gitHook)) {
414
+ const content = fs2.readFileSync(gitHook, "utf-8");
331
415
  if (content.includes("drift-guard")) {
332
416
  if (content.includes("# drift-guard pre-commit hook") && !content.includes("\n#!/usr/bin/env sh\n")) {
333
- fs.unlinkSync(gitHook);
417
+ fs2.unlinkSync(gitHook);
334
418
  console.log(chalk5.green("\u2713 Removed drift-guard pre-commit hook"));
335
419
  } else {
336
420
  const cleaned = content.replace(/# drift-guard pre-commit hook[\s\S]*?fi\n?/g, "");
337
- fs.writeFileSync(gitHook, cleaned);
421
+ fs2.writeFileSync(gitHook, cleaned);
338
422
  console.log(chalk5.green("\u2713 Removed drift-guard from pre-commit hook"));
339
423
  }
340
424
  return;
@@ -345,8 +429,8 @@ async function hookUninstallCommand() {
345
429
 
346
430
  // src/cli/sync.ts
347
431
  import { Command } from "commander";
348
- import path2 from "path";
349
- import fs2 from "fs";
432
+ import path3 from "path";
433
+ import fs3 from "fs";
350
434
  import fg from "fast-glob";
351
435
  var syncCommand = new Command("sync").description("Synchronize design tokens between Stitch and your codebase").requiredOption(
352
436
  "-d, --direction <direction>",
@@ -447,12 +531,12 @@ async function handleToCode(projectRoot, options) {
447
531
  );
448
532
  process.exit(1);
449
533
  }
450
- const absPath = path2.resolve(projectRoot, stitchHtmlPath);
451
- if (!fs2.existsSync(absPath)) {
534
+ const absPath = path3.resolve(projectRoot, stitchHtmlPath);
535
+ if (!fs3.existsSync(absPath)) {
452
536
  console.error(`\u274C Stitch HTML file not found: ${absPath}`);
453
537
  process.exit(1);
454
538
  }
455
- const htmlContent = fs2.readFileSync(absPath, "utf-8");
539
+ const htmlContent = fs3.readFileSync(absPath, "utf-8");
456
540
  const stitchTokens = [];
457
541
  const htmlTokens = parseHtml(htmlContent, stitchHtmlPath);
458
542
  stitchTokens.push(...htmlTokens);
@@ -478,10 +562,10 @@ async function handleToCode(projectRoot, options) {
478
562
  if (localStitchFiles.length > 0) {
479
563
  console.log("\u{1F4C4} Step 1: Full HTML replacement");
480
564
  for (const localFile of localStitchFiles) {
481
- const localAbsPath = path2.resolve(projectRoot, localFile);
482
- const localContent = fs2.readFileSync(localAbsPath, "utf-8");
565
+ const localAbsPath = path3.resolve(projectRoot, localFile);
566
+ const localContent = fs3.readFileSync(localAbsPath, "utf-8");
483
567
  if (localContent !== htmlContent) {
484
- fs2.writeFileSync(localAbsPath, htmlContent, "utf-8");
568
+ fs3.writeFileSync(localAbsPath, htmlContent, "utf-8");
485
569
  console.log(` \u2705 Replaced: ${localFile} (Stitch \u2192 local)`);
486
570
  htmlReplaced = true;
487
571
  } else {
@@ -505,8 +589,8 @@ async function handleToCode(projectRoot, options) {
505
589
  const { modifiedFiles, appliedCount } = applySyncChanges(result.changes, cssFileMap);
506
590
  if (appliedCount > 0) {
507
591
  for (const [file, content] of modifiedFiles) {
508
- const fullPath = path2.resolve(projectRoot, file);
509
- fs2.writeFileSync(fullPath, content, "utf-8");
592
+ const fullPath = path3.resolve(projectRoot, file);
593
+ fs3.writeFileSync(fullPath, content, "utf-8");
510
594
  console.log(` \u2705 Patched: ${file}`);
511
595
  }
512
596
  }
@@ -518,7 +602,7 @@ async function handleToCode(projectRoot, options) {
518
602
  const { execSync } = await import("child_process");
519
603
  try {
520
604
  execSync(
521
- `node "${path2.resolve(projectRoot, "..", "drift-guard", "dist", "cli", "index.js")}" snapshot update`,
605
+ `node "${path3.resolve(projectRoot, "..", "drift-guard", "dist", "cli", "index.js")}" snapshot update`,
522
606
  { cwd: projectRoot, stdio: "pipe" }
523
607
  );
524
608
  } catch {
@@ -537,8 +621,8 @@ async function handleToCode(projectRoot, options) {
537
621
  if (localStitchFiles.length > 0) {
538
622
  let allMatch = true;
539
623
  for (const localFile of localStitchFiles) {
540
- const localAbsPath = path2.resolve(projectRoot, localFile);
541
- const localContent = fs2.readFileSync(localAbsPath, "utf-8");
624
+ const localAbsPath = path3.resolve(projectRoot, localFile);
625
+ const localContent = fs3.readFileSync(localAbsPath, "utf-8");
542
626
  if (localContent === htmlContent) {
543
627
  console.log(` \u2705 ${localFile} \u2014 100% identical to Stitch`);
544
628
  } else {
@@ -574,12 +658,12 @@ async function handleToCode(projectRoot, options) {
574
658
  console.log("");
575
659
  console.log("\u2501".repeat(60));
576
660
  if (!options.dryRun) {
577
- const patchPath = path2.join(
661
+ const patchPath = path3.join(
578
662
  projectRoot,
579
663
  ".design-guard",
580
664
  "sync-patch.css"
581
665
  );
582
- fs2.writeFileSync(patchPath, result.patchFile, "utf-8");
666
+ fs3.writeFileSync(patchPath, result.patchFile, "utf-8");
583
667
  console.log(`
584
668
  \u{1F4BE} Patch saved to: ${patchPath}`);
585
669
  console.log(" Use --apply for full HTML content + token sync.");
@@ -601,7 +685,7 @@ async function findLocalStitchHtml(projectRoot, sourceAbsPath, targetPath) {
601
685
  absolute: false
602
686
  }
603
687
  );
604
- const sourceRelative = path2.relative(projectRoot, sourceAbsPath);
688
+ const sourceRelative = path3.relative(projectRoot, sourceAbsPath);
605
689
  return stitchFiles.filter((f) => f !== sourceRelative);
606
690
  }
607
691
  async function loadProjectCssFiles(projectRoot, config) {
@@ -613,9 +697,9 @@ async function loadProjectCssFiles(projectRoot, config) {
613
697
  absolute: false
614
698
  });
615
699
  for (const file of matches) {
616
- const absPath = path2.resolve(projectRoot, file);
617
- if (fs2.existsSync(absPath)) {
618
- cssFileMap.set(file, fs2.readFileSync(absPath, "utf-8"));
700
+ const absPath = path3.resolve(projectRoot, file);
701
+ if (fs3.existsSync(absPath)) {
702
+ cssFileMap.set(file, fs3.readFileSync(absPath, "utf-8"));
619
703
  }
620
704
  }
621
705
  }
@@ -627,9 +711,9 @@ async function loadProjectCssFiles(projectRoot, config) {
627
711
  absolute: false
628
712
  });
629
713
  for (const file of htmlMatches) {
630
- const absPath = path2.resolve(projectRoot, file);
631
- if (fs2.existsSync(absPath)) {
632
- cssFileMap.set(file, fs2.readFileSync(absPath, "utf-8"));
714
+ const absPath = path3.resolve(projectRoot, file);
715
+ if (fs3.existsSync(absPath)) {
716
+ cssFileMap.set(file, fs3.readFileSync(absPath, "utf-8"));
633
717
  }
634
718
  }
635
719
  return cssFileMap;
@@ -640,7 +724,7 @@ var program = new Command2();
640
724
  program.name("drift-guard").description(
641
725
  chalk6.bold("\u{1F6E1}\uFE0F drift-guard") + " \u2014 Protect your UI from AI coding agents' design drift.\n\n Detect and prevent design token changes during AI-assisted development.\n Lock your colors, fonts, spacing, and layout before AI agents touch your code."
642
726
  ).version("0.2.0");
643
- program.command("init").description("Initialize drift-guard and create a design snapshot").option("--from <path>", "Create snapshot from a Stitch/HTML file").option("--threshold <number>", "Set default drift threshold percentage", "10").action(initCommand);
727
+ program.command("init").description("Initialize drift-guard: snapshot + AI rules + git hook (all-in-one)").option("--from <path>", "Create snapshot from a Stitch/HTML file").option("--threshold <number>", "Set default drift threshold percentage", "10").option("--skip-rules", "Skip auto-generating AGENTS.md rules file").option("--skip-hook", "Skip auto-installing pre-commit git hook").action(initCommand);
644
728
  program.command("check").description("Check for design drift against the saved snapshot").option("--threshold <number>", "Override drift threshold percentage").option("--output <format>", "Output format: text or json", "text").option("--ci", "CI mode: exit with code 1 on drift exceeding threshold").action(checkCommand);
645
729
  program.command("rules").description("Generate AI agent rule files from the design snapshot").option("--format <type>", "Rule format: cursorrules, claude-md, agents-md, copilot, clinerules, all", "all").option("--append", "Append to existing rule files instead of overwriting").action(rulesCommand);
646
730
  program.command("snapshot").description("Manage design snapshots").command("update").description("Update the snapshot to reflect current design (after intentional changes)").option("--from <path>", "Update from a specific Stitch/HTML file").action(snapshotCommand);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/cli/index.ts","../../src/cli/init.ts","../../src/cli/check.ts","../../src/cli/rules.ts","../../src/cli/snapshot-cmd.ts","../../src/cli/hook.ts","../../src/cli/sync.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { Command } from 'commander';\nimport chalk from 'chalk';\nimport { initCommand } from './init.js';\nimport { checkCommand } from './check.js';\nimport { rulesCommand } from './rules.js';\nimport { snapshotCommand } from './snapshot-cmd.js';\nimport { hookInstallCommand, hookUninstallCommand } from './hook.js';\nimport { syncCommand } from './sync.js';\n\nconst program = new Command();\n\nprogram\n .name('drift-guard')\n .description(\n chalk.bold('๐Ÿ›ก๏ธ drift-guard') +\n ' โ€” Protect your UI from AI coding agents\\' design drift.\\n\\n' +\n ' Detect and prevent design token changes during AI-assisted development.\\n' +\n ' Lock your colors, fonts, spacing, and layout before AI agents touch your code.'\n )\n .version('0.2.0');\n\nprogram\n .command('init')\n .description('Initialize drift-guard and create a design snapshot')\n .option('--from <path>', 'Create snapshot from a Stitch/HTML file')\n .option('--threshold <number>', 'Set default drift threshold percentage', '10')\n .action(initCommand);\n\nprogram\n .command('check')\n .description('Check for design drift against the saved snapshot')\n .option('--threshold <number>', 'Override drift threshold percentage')\n .option('--output <format>', 'Output format: text or json', 'text')\n .option('--ci', 'CI mode: exit with code 1 on drift exceeding threshold')\n .action(checkCommand);\n\nprogram\n .command('rules')\n .description('Generate AI agent rule files from the design snapshot')\n .option('--format <type>', 'Rule format: cursorrules, claude-md, agents-md, copilot, clinerules, all', 'all')\n .option('--append', 'Append to existing rule files instead of overwriting')\n .action(rulesCommand);\n\nprogram\n .command('snapshot')\n .description('Manage design snapshots')\n .command('update')\n .description('Update the snapshot to reflect current design (after intentional changes)')\n .option('--from <path>', 'Update from a specific Stitch/HTML file')\n .action(snapshotCommand);\n\nconst hook = program\n .command('hook')\n .description('Manage pre-commit hook for automatic drift checking');\n\nhook\n .command('install')\n .description('Install a pre-commit hook that runs drift-guard check')\n .option('--threshold <number>', 'Drift threshold percentage for the hook', '10')\n .action(hookInstallCommand);\n\nhook\n .command('uninstall')\n .description('Remove the drift-guard pre-commit hook')\n .action(hookUninstallCommand);\n\nprogram.addCommand(syncCommand);\n\nprogram.parse();\n\n","import chalk from 'chalk';\nimport { createSnapshot, saveSnapshot, saveConfig } from '../core/snapshot.js';\nimport { DEFAULT_CONFIG } from '../types/index.js';\n\ninterface InitOptions {\n from?: string;\n threshold?: string;\n}\n\nexport async function initCommand(options: InitOptions): Promise<void> {\n const projectRoot = process.cwd();\n const threshold = parseInt(options.threshold ?? '10', 10);\n\n console.log(chalk.bold('\\n๐Ÿ›ก๏ธ drift-guard init\\n'));\n console.log(chalk.dim('Scanning project for design tokens...\\n'));\n\n // Save config\n const config = { ...DEFAULT_CONFIG, threshold };\n saveConfig(projectRoot, config);\n\n // Create snapshot\n const snapshot = await createSnapshot(projectRoot, options.from);\n\n if (snapshot.tokens.length === 0) {\n console.log(chalk.yellow('โš ๏ธ No design tokens found.'));\n console.log(chalk.dim(' Make sure you have CSS files or use --from <stitch.html>'));\n console.log(chalk.dim(' Supported patterns: src/**/*.css, app/**/*.css, styles/**/*.css\\n'));\n return;\n }\n\n // Save snapshot\n const snapshotPath = saveSnapshot(projectRoot, snapshot);\n\n // Report\n console.log(chalk.green('โœ… Design snapshot created!\\n'));\n console.log(chalk.dim(' Snapshot: ') + chalk.white(snapshotPath));\n console.log(chalk.dim(' Files scanned: ') + chalk.white(snapshot.sourceFiles.length.toString()));\n console.log(chalk.dim(' Tokens locked: ') + chalk.white(snapshot.tokens.length.toString()));\n console.log(chalk.dim(' Threshold: ') + chalk.white(`${threshold}%`));\n console.log();\n\n // Token summary\n console.log(chalk.bold(' Token Summary:'));\n const categories = ['color', 'font', 'spacing', 'shadow', 'radius', 'layout'] as const;\n for (const cat of categories) {\n const count = snapshot.summary[cat];\n if (count > 0) {\n const icon = { color: '๐ŸŽจ', font: '๐Ÿ“', spacing: '๐Ÿ“', shadow: '๐ŸŒซ๏ธ', radius: 'โญ•', layout: '๐Ÿ“' }[cat];\n console.log(chalk.dim(` ${icon} ${cat}: `) + chalk.white(count.toString()));\n }\n }\n\n // Structure fingerprint summary (v0.2.0+)\n if (snapshot.structure) {\n const s = snapshot.structure;\n const tagList = Object.entries(s.semanticTags)\n .filter(([, count]) => count > 0)\n .map(([tag, count]) => `${tag}(${count})`)\n .join(', ');\n console.log();\n console.log(chalk.bold(' Structure Fingerprint:'));\n console.log(chalk.dim(' ๐Ÿ—๏ธ semantic tags: ') + chalk.white(tagList));\n console.log(chalk.dim(' ๐Ÿ—๏ธ max depth: ') + chalk.white(s.maxDepth.toString()));\n console.log(chalk.dim(' ๐Ÿ—๏ธ layout hash: ') + chalk.white(s.layoutHash));\n }\n\n console.log();\n console.log(chalk.dim('Next steps:'));\n console.log(chalk.cyan(' 1. ') + 'Add .design-guard/ to .gitignore (optional)');\n console.log(chalk.cyan(' 2. ') + chalk.bold('npx drift-guard rules') + ' โ€” Generate AI agent protection rules');\n console.log(chalk.cyan(' 3. ') + chalk.bold('npx drift-guard check') + ' โ€” Check for design drift anytime');\n console.log();\n}\n","import chalk from 'chalk';\nimport { loadSnapshot, loadConfig } from '../core/snapshot.js';\nimport { detectDrift } from '../core/drift.js';\nimport type { DriftReport, DriftItem } from '../types/index.js';\n\ninterface CheckOptions {\n threshold?: string;\n output?: string;\n ci?: boolean;\n}\n\nexport async function checkCommand(options: CheckOptions): Promise<void> {\n const projectRoot = process.cwd();\n\n // Load snapshot\n const snapshot = loadSnapshot(projectRoot);\n if (!snapshot) {\n console.log(chalk.red('\\nโŒ No snapshot found.'));\n console.log(chalk.dim(' Run ') + chalk.cyan('npx drift-guard init') + chalk.dim(' first.\\n'));\n process.exit(1);\n }\n\n const config = loadConfig(projectRoot);\n const threshold = options.threshold\n ? parseInt(options.threshold, 10)\n : config.threshold;\n\n console.log(chalk.bold('\\n๐Ÿ›ก๏ธ drift-guard check\\n'));\n\n // Snapshot age warning\n const snapshotAge = Date.now() - new Date(snapshot.createdAt).getTime();\n const ageDays = Math.floor(snapshotAge / (1000 * 60 * 60 * 24));\n if (ageDays >= 7) {\n const ageStr = ageDays >= 30 ? `${Math.floor(ageDays / 30)} month(s)` : `${ageDays} days`;\n console.log(chalk.yellow(`โš ๏ธ Snapshot is ${ageStr} old (created ${snapshot.createdAt.split('T')[0]}).`));\n console.log(chalk.yellow(' If your design has changed, run: ') + chalk.cyan('drift-guard init --from <latest.html>\\n'));\n }\n\n console.log(chalk.dim(`Comparing against snapshot from ${snapshot.createdAt}...\\n`));\n\n // Detect drift\n const report = await detectDrift(projectRoot, snapshot, threshold);\n\n if (options.output === 'json') {\n console.log(JSON.stringify(report, null, 2));\n } else {\n printTextReport(report);\n }\n\n // Exit code for CI\n if (!report.passed && (options.ci || process.env['CI'])) {\n process.exit(1);\n }\n\n if (!report.passed) {\n process.exitCode = 1;\n }\n}\n\nfunction printTextReport(report: DriftReport): void {\n // Score display\n const scoreColor = report.passed ? chalk.green : chalk.red;\n const icon = report.passed ? 'โœ…' : '๐Ÿšจ';\n\n console.log(`${icon} ${chalk.bold('Drift Score:')} ${scoreColor(`${report.driftScore}%`)} (threshold: ${report.threshold}%)`);\n console.log(chalk.dim(` ${report.changedTokens} of ${report.totalTokens} tokens changed\\n`));\n\n if (report.items.length === 0 && !(report.structureDrift?.changed)) {\n console.log(chalk.green(' No design drift detected. Your design is intact! ๐ŸŽ‰\\n'));\n return;\n }\n\n if (report.items.length > 0) {\n // Category breakdown\n console.log(chalk.bold(' Category Breakdown:'));\n const categories = ['color', 'font', 'spacing', 'shadow', 'radius', 'layout'] as const;\n for (const cat of categories) {\n const summary = report.categorySummary[cat];\n if (summary.total === 0) continue;\n\n const catIcon = { color: '๐ŸŽจ', font: '๐Ÿ“', spacing: '๐Ÿ“', shadow: '๐ŸŒซ๏ธ', radius: 'โญ•', layout: '๐Ÿ“' }[cat];\n const catColor = summary.changed > 0 ? chalk.red : chalk.green;\n console.log(` ${catIcon} ${cat}: ${catColor(`${summary.changed}/${summary.total}`)} (${summary.driftPercent}%)`);\n }\n console.log();\n\n // Detailed changes (max 20)\n const itemsToShow = report.items.slice(0, 20);\n if (itemsToShow.length > 0) {\n console.log(chalk.bold(' Changes:'));\n for (const item of itemsToShow) {\n printDriftItem(item);\n }\n\n if (report.items.length > 20) {\n console.log(chalk.dim(` ... and ${report.items.length - 20} more changes\\n`));\n }\n }\n\n console.log();\n }\n\n // Structure drift (v0.2.0+)\n if (report.structureDrift) {\n if (report.structureDrift.changed) {\n console.log(chalk.bold(' ๐Ÿ—๏ธ Structure Drift:'));\n for (const detail of report.structureDrift.details) {\n console.log(chalk.yellow(` โš ๏ธ ${detail}`));\n }\n console.log();\n } else {\n console.log(chalk.green(' ๐Ÿ—๏ธ DOM structure: No changes detected โœ…\\n'));\n }\n }\n\n if (!report.passed) {\n console.log(chalk.yellow(' ๐Ÿ’ก To accept these changes, run:'));\n console.log(chalk.cyan(' npx drift-guard snapshot update\\n'));\n }\n}\n\nfunction printDriftItem(item: DriftItem): void {\n const { original, current, changeType } = item;\n\n switch (changeType) {\n case 'modified':\n console.log(\n chalk.yellow(' ~') +\n chalk.dim(` ${original.file} `) +\n chalk.white(`${original.property}: `) +\n chalk.red(original.value) +\n chalk.dim(' โ†’ ') +\n chalk.green(current?.value ?? 'removed')\n );\n break;\n case 'deleted':\n console.log(\n chalk.red(' -') +\n chalk.dim(` ${original.file} `) +\n chalk.white(`${original.property}: `) +\n chalk.red(original.value) +\n chalk.dim(' [deleted]')\n );\n break;\n case 'added':\n console.log(\n chalk.green(' +') +\n chalk.dim(` ${original.file} `) +\n chalk.white(`${original.property}: `) +\n chalk.green(original.value)\n );\n break;\n }\n}\n","import chalk from 'chalk';\nimport { loadSnapshot } from '../core/snapshot.js';\nimport { generateRules, saveRules } from '../core/rules-generator.js';\nimport type { RuleFormat } from '../types/index.js';\n\ninterface RulesOptions {\n format?: string;\n append?: boolean;\n}\n\nconst ALL_FORMATS: RuleFormat[] = ['cursorrules', 'claude-md', 'agents-md', 'copilot', 'clinerules'];\n\nexport async function rulesCommand(options: RulesOptions): Promise<void> {\n const projectRoot = process.cwd();\n\n const snapshot = loadSnapshot(projectRoot);\n if (!snapshot) {\n console.log(chalk.red('\\nโŒ No snapshot found.'));\n console.log(chalk.dim(' Run ') + chalk.cyan('npx drift-guard init') + chalk.dim(' first.\\n'));\n process.exit(1);\n }\n\n const formats: RuleFormat[] = options.format === 'all' || !options.format\n ? ALL_FORMATS\n : [options.format as RuleFormat];\n\n console.log(chalk.bold('\\n๐Ÿ›ก๏ธ drift-guard rules\\n'));\n console.log(chalk.dim(`Generating AI protection rules from ${snapshot.tokens.length} locked tokens...\\n`));\n\n for (const format of formats) {\n try {\n const content = generateRules(snapshot, format);\n const filePath = saveRules(projectRoot, format, content, options.append ?? false);\n console.log(chalk.green(' โœ… ') + chalk.white(filePath));\n } catch (error) {\n console.log(chalk.red(' โŒ ') + chalk.white(format) + chalk.dim(`: ${(error as Error).message}`));\n }\n }\n\n console.log();\n console.log(chalk.dim('Your AI coding agents will now protect these design tokens.'));\n console.log(chalk.dim('Supported tools: Cursor, Claude Code, Codex, GitHub Copilot, Cline\\n'));\n}\n","import chalk from 'chalk';\nimport { createSnapshot, saveSnapshot } from '../core/snapshot.js';\n\ninterface SnapshotOptions {\n from?: string;\n}\n\nexport async function snapshotCommand(options: SnapshotOptions): Promise<void> {\n const projectRoot = process.cwd();\n\n console.log(chalk.bold('\\n๐Ÿ›ก๏ธ drift-guard snapshot update\\n'));\n console.log(chalk.dim('Re-scanning project and updating snapshot...\\n'));\n\n const snapshot = await createSnapshot(projectRoot, options.from);\n\n if (snapshot.tokens.length === 0) {\n console.log(chalk.yellow('โš ๏ธ No design tokens found.\\n'));\n return;\n }\n\n const snapshotPath = saveSnapshot(projectRoot, snapshot);\n\n console.log(chalk.green('โœ… Snapshot updated!\\n'));\n console.log(chalk.dim(' File: ') + chalk.white(snapshotPath));\n console.log(chalk.dim(' Tokens: ') + chalk.white(snapshot.tokens.length.toString()));\n console.log(chalk.dim(' Updated: ') + chalk.white(snapshot.createdAt));\n console.log();\n console.log(chalk.dim('๐Ÿ’ก Remember to regenerate rules: ') + chalk.cyan('npx drift-guard rules\\n'));\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport { execSync } from 'node:child_process';\nimport chalk from 'chalk';\n\n/**\n * Install a pre-commit hook that runs drift-guard check\n */\nexport async function hookInstallCommand(options: { threshold?: string }): Promise<void> {\n const cwd = process.cwd();\n const threshold = options.threshold ?? '10';\n\n // Check if git repo\n if (!fs.existsSync(path.join(cwd, '.git'))) {\n console.error(chalk.red('โœ— Not a git repository. Run this from a git project root.'));\n process.exit(1);\n }\n\n // Detect hook manager\n const hasHusky = fs.existsSync(path.join(cwd, '.husky'));\n const hasLefthook = fs.existsSync(path.join(cwd, 'lefthook.yml')) ||\n fs.existsSync(path.join(cwd, '.lefthook.yml'));\n\n if (hasHusky) {\n // Add to existing husky setup\n const hookFile = path.join(cwd, '.husky', 'pre-commit');\n const hookCommand = `npx drift-guard check --threshold ${threshold} --ci`;\n\n if (fs.existsSync(hookFile)) {\n const existing = fs.readFileSync(hookFile, 'utf-8');\n if (existing.includes('drift-guard')) {\n console.log(chalk.yellow('โš  drift-guard hook already exists in .husky/pre-commit'));\n return;\n }\n fs.appendFileSync(hookFile, `\\n${hookCommand}\\n`);\n } else {\n fs.writeFileSync(hookFile, `#!/usr/bin/env sh\\n. \"$(dirname -- \"$0\")/_/husky.sh\"\\n\\n${hookCommand}\\n`);\n }\n\n console.log(chalk.green('โœ“ Added drift-guard check to .husky/pre-commit'));\n return;\n }\n\n if (hasLefthook) {\n console.log(chalk.yellow('โš  lefthook detected. Add this to your lefthook.yml:'));\n console.log(chalk.cyan(`\npre-commit:\n commands:\n drift-guard:\n run: npx drift-guard check --threshold ${threshold} --ci\n`));\n return;\n }\n\n // No hook manager โ€” install via .git/hooks directly\n const hooksDir = path.join(cwd, '.git', 'hooks');\n const hookFile = path.join(hooksDir, 'pre-commit');\n const hookScript = `#!/usr/bin/env sh\n# drift-guard pre-commit hook\n# Checks for design token drift before commits\n# Use --force flag to bypass: git commit --no-verify\n\nnpx drift-guard check --threshold ${threshold} --ci\n\nif [ $? -ne 0 ]; then\n echo \"\"\n echo \"\\\\033[31mโœ— Design drift detected! Commit blocked.\\\\033[0m\"\n echo \" Run 'npx drift-guard check' for details.\"\n echo \" If changes are intentional, run 'npx drift-guard snapshot update'\"\n echo \" Or use 'git commit --no-verify' to bypass.\"\n exit 1\nfi\n`;\n\n if (!fs.existsSync(hooksDir)) {\n fs.mkdirSync(hooksDir, { recursive: true });\n }\n\n if (fs.existsSync(hookFile)) {\n const existing = fs.readFileSync(hookFile, 'utf-8');\n if (existing.includes('drift-guard')) {\n console.log(chalk.yellow('โš  drift-guard hook already installed'));\n return;\n }\n // Append to existing hook\n fs.appendFileSync(hookFile, `\\n${hookScript}`);\n console.log(chalk.green('โœ“ Appended drift-guard to existing pre-commit hook'));\n } else {\n fs.writeFileSync(hookFile, hookScript);\n // Make executable on Unix\n try {\n fs.chmodSync(hookFile, 0o755);\n } catch {\n // Windows may not support chmod, skip\n }\n console.log(chalk.green('โœ“ Installed drift-guard pre-commit hook'));\n }\n\n console.log(chalk.dim(` Threshold: ${threshold}%`));\n console.log(chalk.dim(' Bypass: git commit --no-verify'));\n}\n\n/**\n * Uninstall the pre-commit hook\n */\nexport async function hookUninstallCommand(): Promise<void> {\n const cwd = process.cwd();\n\n // Check husky\n const huskyHook = path.join(cwd, '.husky', 'pre-commit');\n if (fs.existsSync(huskyHook)) {\n const content = fs.readFileSync(huskyHook, 'utf-8');\n if (content.includes('drift-guard')) {\n const cleaned = content.replace(/\\n?npx drift-guard.*\\n?/g, '\\n');\n fs.writeFileSync(huskyHook, cleaned);\n console.log(chalk.green('โœ“ Removed drift-guard from .husky/pre-commit'));\n return;\n }\n }\n\n // Check .git/hooks\n const gitHook = path.join(cwd, '.git', 'hooks', 'pre-commit');\n if (fs.existsSync(gitHook)) {\n const content = fs.readFileSync(gitHook, 'utf-8');\n if (content.includes('drift-guard')) {\n // If the entire file is our hook, remove it\n if (content.includes('# drift-guard pre-commit hook') && !content.includes('\\n#!/usr/bin/env sh\\n')) {\n fs.unlinkSync(gitHook);\n console.log(chalk.green('โœ“ Removed drift-guard pre-commit hook'));\n } else {\n // Remove just our part\n const cleaned = content.replace(/# drift-guard pre-commit hook[\\s\\S]*?fi\\n?/g, '');\n fs.writeFileSync(gitHook, cleaned);\n console.log(chalk.green('โœ“ Removed drift-guard from pre-commit hook'));\n }\n return;\n }\n }\n\n console.log(chalk.yellow('โš  No drift-guard hook found to uninstall'));\n}\n","import { Command } from 'commander';\nimport path from 'node:path';\nimport fs from 'node:fs';\nimport fg from 'fast-glob';\nimport { loadSnapshot, loadConfig } from '../core/snapshot.js';\nimport { detectDrift } from '../core/drift.js';\nimport {\n syncToStitch,\n syncFromStitch,\n applySyncChanges,\n} from '../core/sync.js';\nimport { parseCss, extractCssVariables } from '../parsers/css-parser.js';\nimport { parseHtml, extractStyleBlocks, extractTailwindConfig } from '../parsers/html-parser.js';\nimport type { DesignToken, SyncDirection } from '../types/index.js';\n\nexport const syncCommand = new Command('sync')\n .description('Synchronize design tokens between Stitch and your codebase')\n .requiredOption(\n '-d, --direction <direction>',\n 'Sync direction: to-stitch (push code changes to Stitch) or to-code (pull Stitch changes)',\n )\n .option(\n '--stitch-html <path>',\n 'Path to Stitch HTML file (for to-code direction)',\n )\n .option(\n '--stitch-project <id>',\n 'Stitch project ID (for to-stitch direction)',\n )\n .option(\n '--stitch-screen <id>',\n 'Stitch screen ID (for to-stitch direction)',\n )\n .option('--apply', 'Auto-apply changes: full HTML replacement + CSS patching (to-code only)', false)\n .option('--target <path>', 'Target local HTML file to replace with Stitch version (to-code --apply)')\n .option('--dry-run', 'Preview changes without applying', false)\n .option('--json', 'Output as JSON', false)\n .action(async (options) => {\n const projectRoot = process.cwd();\n const direction = options.direction as SyncDirection;\n\n if (direction !== 'to-stitch' && direction !== 'to-code') {\n console.error(\n 'โŒ Invalid direction. Use \"to-stitch\" or \"to-code\".',\n );\n process.exit(1);\n }\n\n if (direction === 'to-stitch') {\n await handleToStitch(projectRoot, options);\n } else {\n await handleToCode(projectRoot, options);\n }\n });\n\n/**\n * Handle to-stitch direction:\n * Compare current code against snapshot โ†’ generate Stitch edit prompt\n */\nasync function handleToStitch(\n projectRoot: string,\n options: { dryRun: boolean; json: boolean; stitchProject?: string; stitchScreen?: string },\n): Promise<void> {\n const snapshot = loadSnapshot(projectRoot);\n if (!snapshot) {\n console.error('โŒ No snapshot found. Run \"drift-guard init\" first.');\n process.exit(1);\n }\n\n // Detect drift (code vs snapshot)\n const report = await detectDrift(projectRoot, snapshot, 0);\n\n if (report.items.length === 0) {\n console.log('โœ… No changes detected. Stitch and code are in sync!');\n return;\n }\n\n const result = syncToStitch(report.items);\n\n if (options.json) {\n console.log(JSON.stringify(result, null, 2));\n return;\n }\n\n // Pretty output\n console.log('');\n console.log('๐Ÿ”„ drift-guard sync โ†’ to-stitch');\n console.log(` ${result.changes.length} change(s) detected\\n`);\n\n for (const change of result.changes) {\n const icon =\n change.action === 'update' ? 'โœ๏ธ' :\n change.action === 'add' ? 'โž•' : '๐Ÿ—‘๏ธ';\n console.log(\n ` ${icon} ${change.property}: ${change.fromValue || '(none)'} โ†’ ${change.toValue || '(removed)'}`,\n );\n }\n\n console.log('');\n console.log('โ”'.repeat(60));\n console.log('๐Ÿ“‹ Stitch edit_screens prompt:');\n console.log('โ”'.repeat(60));\n console.log('');\n console.log(result.prompt);\n console.log('');\n console.log('โ”'.repeat(60));\n\n const projectId = options.stitchProject;\n const screenId = options.stitchScreen;\n\n if (projectId && screenId) {\n console.log('');\n console.log('๐Ÿ’ก To apply these changes in Stitch, run:');\n console.log('');\n console.log(` edit_screens({`);\n console.log(` projectId: \"${projectId}\",`);\n console.log(` selectedScreenIds: [\"${screenId}\"],`);\n console.log(` prompt: \"<the prompt above>\"`);\n console.log(` })`);\n } else {\n console.log('');\n console.log(\n '๐Ÿ’ก Copy the prompt above and use it with Stitch MCP edit_screens',\n );\n console.log(\n ' or pass --stitch-project and --stitch-screen for a ready-to-use call.',\n );\n }\n}\n\n/**\n * Handle to-code direction:\n * Compare Stitch HTML against snapshot โ†’ generate CSS patch โ†’ optionally apply.\n *\n * With --apply: Stitch HTML is the SOURCE OF TRUTH.\n * 1. Replace the local Stitch HTML file entirely (fixes text/layout/content diffs)\n * 2. Patch design tokens in other CSS files\n * 3. Update snapshot\n * 4. Verify 0% drift\n */\nasync function handleToCode(\n projectRoot: string,\n options: { dryRun: boolean; json: boolean; apply: boolean; stitchHtml?: string; target?: string },\n): Promise<void> {\n const snapshot = loadSnapshot(projectRoot);\n if (!snapshot) {\n console.error('โŒ No snapshot found. Run \"drift-guard init\" first.');\n process.exit(1);\n }\n\n // Get Stitch HTML path (new/downloaded version)\n const config = loadConfig(projectRoot);\n const stitchHtmlPath =\n options.stitchHtml ?? config.stitch?.htmlPath;\n\n if (!stitchHtmlPath) {\n console.error(\n 'โŒ No Stitch HTML file specified.',\n );\n console.error(\n ' Use --stitch-html <path> or set stitch.htmlPath in .design-guard/config.json',\n );\n process.exit(1);\n }\n\n const absPath = path.resolve(projectRoot, stitchHtmlPath);\n if (!fs.existsSync(absPath)) {\n console.error(`โŒ Stitch HTML file not found: ${absPath}`);\n process.exit(1);\n }\n\n // Parse Stitch HTML for tokens\n const htmlContent = fs.readFileSync(absPath, 'utf-8');\n const stitchTokens: DesignToken[] = [];\n\n const htmlTokens = parseHtml(htmlContent, stitchHtmlPath);\n stitchTokens.push(...htmlTokens);\n\n const styleBlocks = extractStyleBlocks(htmlContent);\n for (const block of styleBlocks) {\n stitchTokens.push(...parseCss(block, stitchHtmlPath));\n stitchTokens.push(...extractCssVariables(block, stitchHtmlPath));\n }\n\n const twTokens = extractTailwindConfig(htmlContent, stitchHtmlPath);\n stitchTokens.push(...twTokens);\n\n // Compare Stitch tokens against snapshot\n const result = syncFromStitch(stitchTokens, snapshot.tokens);\n\n if (options.json) {\n console.log(JSON.stringify(result, null, 2));\n return;\n }\n\n // === FULL SYNC (--apply): Stitch is source of truth ===\n if (options.apply && !options.dryRun) {\n console.log('');\n console.log('๐Ÿ”„ drift-guard sync โ†’ to-code (FULL SYNC)');\n console.log(' Stitch HTML is the source of truth.\\n');\n\n // Step 1: Find local Stitch HTML files to replace\n const targetPath = options.target;\n const localStitchFiles = await findLocalStitchHtml(projectRoot, absPath, targetPath);\n let htmlReplaced = false;\n\n if (localStitchFiles.length > 0) {\n console.log('๐Ÿ“„ Step 1: Full HTML replacement');\n for (const localFile of localStitchFiles) {\n const localAbsPath = path.resolve(projectRoot, localFile);\n const localContent = fs.readFileSync(localAbsPath, 'utf-8');\n\n if (localContent !== htmlContent) {\n fs.writeFileSync(localAbsPath, htmlContent, 'utf-8');\n console.log(` โœ… Replaced: ${localFile} (Stitch โ†’ local)`);\n htmlReplaced = true;\n } else {\n console.log(` โ„น๏ธ Already identical: ${localFile}`);\n }\n }\n } else {\n console.log('๐Ÿ“„ Step 1: No local Stitch HTML found to replace.');\n console.log(' ๐Ÿ’ก Use --target <path> to specify the target file.');\n }\n\n // Step 2: Patch design tokens in CSS files\n if (result.changes.length > 0) {\n console.log(`\\n๐Ÿ“ Step 2: Patching ${result.changes.length} design token(s) in CSS files`);\n for (const change of result.changes) {\n const icon =\n change.action === 'update' ? 'โœ๏ธ' :\n change.action === 'add' ? 'โž•' : '๐Ÿ—‘๏ธ';\n console.log(\n ` ${icon} ${change.property}: ${change.fromValue || '(none)'} โ†’ ${change.toValue || '(removed)'}`,\n );\n }\n\n const cssFileMap = await loadProjectCssFiles(projectRoot, config);\n const { modifiedFiles, appliedCount } = applySyncChanges(result.changes, cssFileMap);\n\n if (appliedCount > 0) {\n for (const [file, content] of modifiedFiles) {\n const fullPath = path.resolve(projectRoot, file);\n fs.writeFileSync(fullPath, content, 'utf-8');\n console.log(` โœ… Patched: ${file}`);\n }\n }\n } else {\n console.log('\\n๐Ÿ“ Step 2: No design token changes โ€” tokens already match.');\n }\n\n // Step 3: Update snapshot to reflect new state\n if (htmlReplaced || result.changes.length > 0) {\n console.log('\\n๐Ÿ“ธ Step 3: Updating snapshot...');\n\n const { execSync } = await import('node:child_process');\n try {\n execSync(\n `node \"${path.resolve(projectRoot, '..', 'drift-guard', 'dist', 'cli', 'index.js')}\" snapshot update`,\n { cwd: projectRoot, stdio: 'pipe' },\n );\n } catch {\n // Try the global command\n try {\n execSync('npx drift-guard snapshot update', {\n cwd: projectRoot,\n stdio: 'pipe',\n });\n } catch {\n console.log(' โš ๏ธ Could not auto-update snapshot. Run: drift-guard snapshot update');\n }\n }\n console.log(' โœ… Snapshot updated.');\n }\n\n // Step 4: Verify full sync\n console.log('\\n๐Ÿ” Step 4: Verifying full sync...');\n\n // Compare the Stitch source HTML with the local file\n if (localStitchFiles.length > 0) {\n let allMatch = true;\n for (const localFile of localStitchFiles) {\n const localAbsPath = path.resolve(projectRoot, localFile);\n const localContent = fs.readFileSync(localAbsPath, 'utf-8');\n if (localContent === htmlContent) {\n console.log(` โœ… ${localFile} โ€” 100% identical to Stitch`);\n } else {\n console.log(` โŒ ${localFile} โ€” content differs!`);\n allMatch = false;\n }\n }\n if (allMatch) {\n console.log('\\n ๐ŸŽ‰ FULL SYNC VERIFIED โ€” Stitch and code are 100% identical!');\n }\n }\n } else if (result.changes.length === 0) {\n console.log('โœ… Stitch and code design tokens are already in sync!');\n console.log(' ๐Ÿ’ก Use --apply for full HTML content sync (text, layout, structure).');\n } else {\n // Show token diff and patch\n console.log('');\n console.log('๐Ÿ”„ drift-guard sync โ†’ to-code');\n console.log(` ${result.changes.length} design token change(s) from Stitch\\n`);\n\n for (const change of result.changes) {\n const icon =\n change.action === 'update' ? 'โœ๏ธ' :\n change.action === 'add' ? 'โž•' : '๐Ÿ—‘๏ธ';\n console.log(\n ` ${icon} ${change.property}: ${change.fromValue || '(none)'} โ†’ ${change.toValue || '(removed)'}`,\n );\n }\n\n if (result.patchFile) {\n console.log('');\n console.log('โ”'.repeat(60));\n console.log('๐Ÿ“‹ CSS patch to apply:');\n console.log('โ”'.repeat(60));\n console.log('');\n console.log(result.patchFile);\n console.log('');\n console.log('โ”'.repeat(60));\n\n if (!options.dryRun) {\n const patchPath = path.join(\n projectRoot,\n '.design-guard',\n 'sync-patch.css',\n );\n fs.writeFileSync(patchPath, result.patchFile, 'utf-8');\n console.log(`\\n๐Ÿ’พ Patch saved to: ${patchPath}`);\n console.log(' Use --apply for full HTML content + token sync.');\n } else {\n console.log('\\n๐Ÿ” Dry run โ€” no files written.');\n }\n }\n }\n}\n\n/**\n * Find local Stitch HTML files that should be replaced.\n * Searches for stitch-design.html or files matching --target.\n */\nasync function findLocalStitchHtml(\n projectRoot: string,\n sourceAbsPath: string,\n targetPath?: string,\n): Promise<string[]> {\n if (targetPath) {\n return [targetPath];\n }\n\n // Search for stitch-design.html files in the project\n const stitchFiles = await fg(\n ['**/stitch-design.html', '**/stitch*.html'],\n {\n cwd: projectRoot,\n ignore: ['node_modules/**', 'dist/**', 'build/**'],\n absolute: false,\n },\n );\n\n // Exclude the source file itself\n const sourceRelative = path.relative(projectRoot, sourceAbsPath);\n return stitchFiles.filter(f => f !== sourceRelative);\n}\n\n/**\n * Load all CSS files from the project into a map\n */\nasync function loadProjectCssFiles(\n projectRoot: string,\n config: { cssFiles: string[]; ignore: string[] },\n): Promise<Map<string, string>> {\n const cssFileMap = new Map<string, string>();\n\n for (const pattern of config.cssFiles) {\n const matches = await fg(pattern, {\n cwd: projectRoot,\n ignore: config.ignore,\n absolute: false,\n });\n\n for (const file of matches) {\n const absPath = path.resolve(projectRoot, file);\n if (fs.existsSync(absPath)) {\n cssFileMap.set(file, fs.readFileSync(absPath, 'utf-8'));\n }\n }\n }\n\n // Also include HTML files that might have Tailwind config\n const htmlPatterns = ['**/*.html'];\n const htmlIgnore = ['node_modules/**', 'dist/**', 'build/**', '.next/**'];\n const htmlMatches = await fg(htmlPatterns, {\n cwd: projectRoot,\n ignore: htmlIgnore,\n absolute: false,\n });\n\n for (const file of htmlMatches) {\n const absPath = path.resolve(projectRoot, file);\n if (fs.existsSync(absPath)) {\n cssFileMap.set(file, fs.readFileSync(absPath, 'utf-8'));\n }\n }\n\n return cssFileMap;\n}\n"],"mappings":"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","names":["Command","chalk","chalk","chalk","chalk","chalk","chalk","chalk","chalk","hookFile","path","fs","path","fs","Command","chalk"]}
1
+ {"version":3,"sources":["../../src/cli/index.ts","../../src/cli/init.ts","../../src/cli/check.ts","../../src/cli/rules.ts","../../src/cli/snapshot-cmd.ts","../../src/cli/hook.ts","../../src/cli/sync.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { Command } from 'commander';\nimport chalk from 'chalk';\nimport { initCommand } from './init.js';\nimport { checkCommand } from './check.js';\nimport { rulesCommand } from './rules.js';\nimport { snapshotCommand } from './snapshot-cmd.js';\nimport { hookInstallCommand, hookUninstallCommand } from './hook.js';\nimport { syncCommand } from './sync.js';\n\nconst program = new Command();\n\nprogram\n .name('drift-guard')\n .description(\n chalk.bold('๐Ÿ›ก๏ธ drift-guard') +\n ' โ€” Protect your UI from AI coding agents\\' design drift.\\n\\n' +\n ' Detect and prevent design token changes during AI-assisted development.\\n' +\n ' Lock your colors, fonts, spacing, and layout before AI agents touch your code.'\n )\n .version('0.2.0');\n\nprogram\n .command('init')\n .description('Initialize drift-guard: snapshot + AI rules + git hook (all-in-one)')\n .option('--from <path>', 'Create snapshot from a Stitch/HTML file')\n .option('--threshold <number>', 'Set default drift threshold percentage', '10')\n .option('--skip-rules', 'Skip auto-generating AGENTS.md rules file')\n .option('--skip-hook', 'Skip auto-installing pre-commit git hook')\n .action(initCommand);\n\nprogram\n .command('check')\n .description('Check for design drift against the saved snapshot')\n .option('--threshold <number>', 'Override drift threshold percentage')\n .option('--output <format>', 'Output format: text or json', 'text')\n .option('--ci', 'CI mode: exit with code 1 on drift exceeding threshold')\n .action(checkCommand);\n\nprogram\n .command('rules')\n .description('Generate AI agent rule files from the design snapshot')\n .option('--format <type>', 'Rule format: cursorrules, claude-md, agents-md, copilot, clinerules, all', 'all')\n .option('--append', 'Append to existing rule files instead of overwriting')\n .action(rulesCommand);\n\nprogram\n .command('snapshot')\n .description('Manage design snapshots')\n .command('update')\n .description('Update the snapshot to reflect current design (after intentional changes)')\n .option('--from <path>', 'Update from a specific Stitch/HTML file')\n .action(snapshotCommand);\n\nconst hook = program\n .command('hook')\n .description('Manage pre-commit hook for automatic drift checking');\n\nhook\n .command('install')\n .description('Install a pre-commit hook that runs drift-guard check')\n .option('--threshold <number>', 'Drift threshold percentage for the hook', '10')\n .action(hookInstallCommand);\n\nhook\n .command('uninstall')\n .description('Remove the drift-guard pre-commit hook')\n .action(hookUninstallCommand);\n\nprogram.addCommand(syncCommand);\n\nprogram.parse();\n\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport chalk from 'chalk';\nimport { createSnapshot, saveSnapshot, saveConfig } from '../core/snapshot.js';\nimport { generateRules, saveRules } from '../core/rules-generator.js';\nimport { DEFAULT_CONFIG } from '../types/index.js';\n\ninterface InitOptions {\n from?: string;\n threshold?: string;\n skipRules?: boolean;\n skipHook?: boolean;\n}\n\nexport async function initCommand(options: InitOptions): Promise<void> {\n const projectRoot = process.cwd();\n const threshold = parseInt(options.threshold ?? '10', 10);\n\n console.log(chalk.bold('\\n๐Ÿ›ก๏ธ drift-guard init\\n'));\n console.log(chalk.dim('Scanning project for design tokens...\\n'));\n\n // Save config\n const config = { ...DEFAULT_CONFIG, threshold };\n saveConfig(projectRoot, config);\n\n // Create snapshot\n const snapshot = await createSnapshot(projectRoot, options.from);\n\n if (snapshot.tokens.length === 0) {\n console.log(chalk.yellow('โš ๏ธ No design tokens found.'));\n console.log(chalk.dim(' Make sure you have CSS files or use --from <stitch.html>'));\n console.log(chalk.dim(' Supported patterns: src/**/*.css, app/**/*.css, styles/**/*.css\\n'));\n return;\n }\n\n // Save snapshot\n const snapshotPath = saveSnapshot(projectRoot, snapshot);\n\n // Report\n console.log(chalk.green('โœ… Design snapshot created!\\n'));\n console.log(chalk.dim(' Snapshot: ') + chalk.white(snapshotPath));\n console.log(chalk.dim(' Files scanned: ') + chalk.white(snapshot.sourceFiles.length.toString()));\n console.log(chalk.dim(' Tokens locked: ') + chalk.white(snapshot.tokens.length.toString()));\n console.log(chalk.dim(' Threshold: ') + chalk.white(`${threshold}%`));\n console.log();\n\n // Token summary\n console.log(chalk.bold(' Token Summary:'));\n const categories = ['color', 'font', 'spacing', 'shadow', 'radius', 'layout'] as const;\n for (const cat of categories) {\n const count = snapshot.summary[cat];\n if (count > 0) {\n const icon = { color: '๐ŸŽจ', font: '๐Ÿ“', spacing: '๐Ÿ“', shadow: '๐ŸŒซ๏ธ', radius: 'โญ•', layout: '๐Ÿ“' }[cat];\n console.log(chalk.dim(` ${icon} ${cat}: `) + chalk.white(count.toString()));\n }\n }\n\n // Structure fingerprint summary (v0.2.0+)\n if (snapshot.structure) {\n const s = snapshot.structure;\n const tagList = Object.entries(s.semanticTags)\n .filter(([, count]) => count > 0)\n .map(([tag, count]) => `${tag}(${count})`)\n .join(', ');\n console.log();\n console.log(chalk.bold(' Structure Fingerprint:'));\n console.log(chalk.dim(' ๐Ÿ—๏ธ semantic tags: ') + chalk.white(tagList));\n console.log(chalk.dim(' ๐Ÿ—๏ธ max depth: ') + chalk.white(s.maxDepth.toString()));\n console.log(chalk.dim(' ๐Ÿ—๏ธ layout hash: ') + chalk.white(s.layoutHash));\n }\n\n console.log();\n\n // โ”€โ”€โ”€ Auto-generate AI agent rules (AGENTS.md) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n if (!options.skipRules) {\n try {\n const content = generateRules(snapshot, 'agents-md');\n const rulesPath = saveRules(projectRoot, 'agents-md', content, false);\n console.log(chalk.green('โœ… AI agent rules generated: ') + chalk.white(rulesPath));\n } catch (error) {\n console.log(chalk.yellow('โš ๏ธ Could not generate rules: ') + chalk.dim((error as Error).message));\n }\n } else {\n console.log(chalk.dim(' โญ Skipped rules generation (--skip-rules)'));\n }\n\n // โ”€โ”€โ”€ Auto-install git pre-commit hook โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n if (!options.skipHook) {\n const hasGit = fs.existsSync(path.join(projectRoot, '.git'));\n if (hasGit) {\n try {\n installHookSilent(projectRoot, threshold.toString());\n console.log(chalk.green('โœ… Pre-commit hook installed: ') + chalk.dim('drift-guard check runs before every commit'));\n } catch (error) {\n console.log(chalk.yellow('โš ๏ธ Could not install hook: ') + chalk.dim((error as Error).message));\n }\n } else {\n console.log(chalk.dim(' โญ No .git directory found โ€” skipping hook install'));\n }\n } else {\n console.log(chalk.dim(' โญ Skipped hook installation (--skip-hook)'));\n }\n\n console.log();\n console.log(chalk.green.bold(' ๐Ÿ›ก๏ธ Protection active!'));\n console.log(chalk.dim(' Run ') + chalk.cyan('npx drift-guard check') + chalk.dim(' anytime to verify design integrity.'));\n if (!options.skipRules) {\n console.log(chalk.dim(' Run ') + chalk.cyan('npx drift-guard rules --format all') + chalk.dim(' for additional AI tool formats.'));\n }\n console.log();\n}\n\n/**\n * Install pre-commit hook without verbose output (used by init auto-setup)\n */\nfunction installHookSilent(projectRoot: string, threshold: string): void {\n const hasHusky = fs.existsSync(path.join(projectRoot, '.husky'));\n const hookCommand = `npx drift-guard check --threshold ${threshold} --ci`;\n\n if (hasHusky) {\n const hookFile = path.join(projectRoot, '.husky', 'pre-commit');\n if (fs.existsSync(hookFile)) {\n const existing = fs.readFileSync(hookFile, 'utf-8');\n if (existing.includes('drift-guard')) return; // already installed\n fs.appendFileSync(hookFile, `\\n${hookCommand}\\n`);\n } else {\n fs.writeFileSync(hookFile, `#!/usr/bin/env sh\\n. \"$(dirname -- \"$0\")/_/husky.sh\"\\n\\n${hookCommand}\\n`);\n }\n return;\n }\n\n // Direct .git/hooks installation\n const hooksDir = path.join(projectRoot, '.git', 'hooks');\n const hookFile = path.join(hooksDir, 'pre-commit');\n const hookScript = `#!/usr/bin/env sh\n# drift-guard pre-commit hook\n# Checks for design token drift before commits\n# Bypass: git commit --no-verify\n\nnpx drift-guard check --threshold ${threshold} --ci\n\nif [ $? -ne 0 ]; then\n echo \"\"\n echo \"\\\\033[31mโœ— Design drift detected! Commit blocked.\\\\033[0m\"\n echo \" Run 'npx drift-guard check' for details.\"\n echo \" If changes are intentional, run 'npx drift-guard snapshot update'\"\n echo \" Or use 'git commit --no-verify' to bypass.\"\n exit 1\nfi\n`;\n\n if (!fs.existsSync(hooksDir)) {\n fs.mkdirSync(hooksDir, { recursive: true });\n }\n\n if (fs.existsSync(hookFile)) {\n const existing = fs.readFileSync(hookFile, 'utf-8');\n if (existing.includes('drift-guard')) return; // already installed\n fs.appendFileSync(hookFile, `\\n${hookScript}`);\n } else {\n fs.writeFileSync(hookFile, hookScript);\n try {\n fs.chmodSync(hookFile, 0o755);\n } catch {\n // Windows may not support chmod\n }\n }\n}\n","import chalk from 'chalk';\nimport { loadSnapshot, loadConfig } from '../core/snapshot.js';\nimport { detectDrift } from '../core/drift.js';\nimport type { DriftReport, DriftItem } from '../types/index.js';\n\ninterface CheckOptions {\n threshold?: string;\n output?: string;\n ci?: boolean;\n}\n\nexport async function checkCommand(options: CheckOptions): Promise<void> {\n const projectRoot = process.cwd();\n\n // Load snapshot\n const snapshot = loadSnapshot(projectRoot);\n if (!snapshot) {\n console.log(chalk.red('\\nโŒ No snapshot found.'));\n console.log(chalk.dim(' Run ') + chalk.cyan('npx drift-guard init') + chalk.dim(' first.\\n'));\n process.exit(1);\n }\n\n const config = loadConfig(projectRoot);\n const threshold = options.threshold\n ? parseInt(options.threshold, 10)\n : config.threshold;\n\n console.log(chalk.bold('\\n๐Ÿ›ก๏ธ drift-guard check\\n'));\n\n // Snapshot age warning\n const snapshotAge = Date.now() - new Date(snapshot.createdAt).getTime();\n const ageDays = Math.floor(snapshotAge / (1000 * 60 * 60 * 24));\n if (ageDays >= 7) {\n const ageStr = ageDays >= 30 ? `${Math.floor(ageDays / 30)} month(s)` : `${ageDays} days`;\n console.log(chalk.yellow(`โš ๏ธ Snapshot is ${ageStr} old (created ${snapshot.createdAt.split('T')[0]}).`));\n console.log(chalk.yellow(' If your design has changed, run: ') + chalk.cyan('drift-guard init --from <latest.html>\\n'));\n }\n\n console.log(chalk.dim(`Comparing against snapshot from ${snapshot.createdAt}...\\n`));\n\n // Detect drift\n const report = await detectDrift(projectRoot, snapshot, threshold);\n\n if (options.output === 'json') {\n console.log(JSON.stringify(report, null, 2));\n } else {\n printTextReport(report);\n }\n\n // Exit code for CI\n if (!report.passed && (options.ci || process.env['CI'])) {\n process.exit(1);\n }\n\n if (!report.passed) {\n process.exitCode = 1;\n }\n}\n\nfunction printTextReport(report: DriftReport): void {\n // Score display\n const scoreColor = report.passed ? chalk.green : chalk.red;\n const icon = report.passed ? 'โœ…' : '๐Ÿšจ';\n\n console.log(`${icon} ${chalk.bold('Drift Score:')} ${scoreColor(`${report.driftScore}%`)} (threshold: ${report.threshold}%)`);\n console.log(chalk.dim(` ${report.changedTokens} of ${report.totalTokens} tokens changed\\n`));\n\n if (report.items.length === 0 && !(report.structureDrift?.changed)) {\n console.log(chalk.green(' No design drift detected. Your design is intact! ๐ŸŽ‰\\n'));\n return;\n }\n\n if (report.items.length > 0) {\n // Category breakdown\n console.log(chalk.bold(' Category Breakdown:'));\n const categories = ['color', 'font', 'spacing', 'shadow', 'radius', 'layout'] as const;\n for (const cat of categories) {\n const summary = report.categorySummary[cat];\n if (summary.total === 0) continue;\n\n const catIcon = { color: '๐ŸŽจ', font: '๐Ÿ“', spacing: '๐Ÿ“', shadow: '๐ŸŒซ๏ธ', radius: 'โญ•', layout: '๐Ÿ“' }[cat];\n const catColor = summary.changed > 0 ? chalk.red : chalk.green;\n console.log(` ${catIcon} ${cat}: ${catColor(`${summary.changed}/${summary.total}`)} (${summary.driftPercent}%)`);\n }\n console.log();\n\n // Detailed changes (max 20)\n const itemsToShow = report.items.slice(0, 20);\n if (itemsToShow.length > 0) {\n console.log(chalk.bold(' Changes:'));\n for (const item of itemsToShow) {\n printDriftItem(item);\n }\n\n if (report.items.length > 20) {\n console.log(chalk.dim(` ... and ${report.items.length - 20} more changes\\n`));\n }\n }\n\n console.log();\n }\n\n // Structure drift (v0.2.0+)\n if (report.structureDrift) {\n if (report.structureDrift.changed) {\n console.log(chalk.bold(' ๐Ÿ—๏ธ Structure Drift:'));\n for (const detail of report.structureDrift.details) {\n console.log(chalk.yellow(` โš ๏ธ ${detail}`));\n }\n console.log();\n } else {\n console.log(chalk.green(' ๐Ÿ—๏ธ DOM structure: No changes detected โœ…\\n'));\n }\n }\n\n if (!report.passed) {\n console.log(chalk.yellow(' ๐Ÿ’ก To accept these changes, run:'));\n console.log(chalk.cyan(' npx drift-guard snapshot update\\n'));\n }\n}\n\nfunction printDriftItem(item: DriftItem): void {\n const { original, current, changeType } = item;\n\n switch (changeType) {\n case 'modified':\n console.log(\n chalk.yellow(' ~') +\n chalk.dim(` ${original.file} `) +\n chalk.white(`${original.property}: `) +\n chalk.red(original.value) +\n chalk.dim(' โ†’ ') +\n chalk.green(current?.value ?? 'removed')\n );\n break;\n case 'deleted':\n console.log(\n chalk.red(' -') +\n chalk.dim(` ${original.file} `) +\n chalk.white(`${original.property}: `) +\n chalk.red(original.value) +\n chalk.dim(' [deleted]')\n );\n break;\n case 'added':\n console.log(\n chalk.green(' +') +\n chalk.dim(` ${original.file} `) +\n chalk.white(`${original.property}: `) +\n chalk.green(original.value)\n );\n break;\n }\n}\n","import chalk from 'chalk';\nimport { loadSnapshot } from '../core/snapshot.js';\nimport { generateRules, saveRules } from '../core/rules-generator.js';\nimport type { RuleFormat } from '../types/index.js';\n\ninterface RulesOptions {\n format?: string;\n append?: boolean;\n}\n\nconst ALL_FORMATS: RuleFormat[] = ['cursorrules', 'claude-md', 'agents-md', 'copilot', 'clinerules'];\n\nexport async function rulesCommand(options: RulesOptions): Promise<void> {\n const projectRoot = process.cwd();\n\n const snapshot = loadSnapshot(projectRoot);\n if (!snapshot) {\n console.log(chalk.red('\\nโŒ No snapshot found.'));\n console.log(chalk.dim(' Run ') + chalk.cyan('npx drift-guard init') + chalk.dim(' first.\\n'));\n process.exit(1);\n }\n\n const formats: RuleFormat[] = options.format === 'all' || !options.format\n ? ALL_FORMATS\n : [options.format as RuleFormat];\n\n console.log(chalk.bold('\\n๐Ÿ›ก๏ธ drift-guard rules\\n'));\n console.log(chalk.dim(`Generating AI protection rules from ${snapshot.tokens.length} locked tokens...\\n`));\n\n for (const format of formats) {\n try {\n const content = generateRules(snapshot, format);\n const filePath = saveRules(projectRoot, format, content, options.append ?? false);\n console.log(chalk.green(' โœ… ') + chalk.white(filePath));\n } catch (error) {\n console.log(chalk.red(' โŒ ') + chalk.white(format) + chalk.dim(`: ${(error as Error).message}`));\n }\n }\n\n console.log();\n console.log(chalk.dim('Your AI coding agents will now protect these design tokens.'));\n console.log(chalk.dim('Supported tools: Cursor, Claude Code, Codex, GitHub Copilot, Cline\\n'));\n}\n","import chalk from 'chalk';\nimport { createSnapshot, saveSnapshot } from '../core/snapshot.js';\n\ninterface SnapshotOptions {\n from?: string;\n}\n\nexport async function snapshotCommand(options: SnapshotOptions): Promise<void> {\n const projectRoot = process.cwd();\n\n console.log(chalk.bold('\\n๐Ÿ›ก๏ธ drift-guard snapshot update\\n'));\n console.log(chalk.dim('Re-scanning project and updating snapshot...\\n'));\n\n const snapshot = await createSnapshot(projectRoot, options.from);\n\n if (snapshot.tokens.length === 0) {\n console.log(chalk.yellow('โš ๏ธ No design tokens found.\\n'));\n return;\n }\n\n const snapshotPath = saveSnapshot(projectRoot, snapshot);\n\n console.log(chalk.green('โœ… Snapshot updated!\\n'));\n console.log(chalk.dim(' File: ') + chalk.white(snapshotPath));\n console.log(chalk.dim(' Tokens: ') + chalk.white(snapshot.tokens.length.toString()));\n console.log(chalk.dim(' Updated: ') + chalk.white(snapshot.createdAt));\n console.log();\n console.log(chalk.dim('๐Ÿ’ก Remember to regenerate rules: ') + chalk.cyan('npx drift-guard rules\\n'));\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport { execSync } from 'node:child_process';\nimport chalk from 'chalk';\n\n/**\n * Install a pre-commit hook that runs drift-guard check\n */\nexport async function hookInstallCommand(options: { threshold?: string }): Promise<void> {\n const cwd = process.cwd();\n const threshold = options.threshold ?? '10';\n\n // Check if git repo\n if (!fs.existsSync(path.join(cwd, '.git'))) {\n console.error(chalk.red('โœ— Not a git repository. Run this from a git project root.'));\n process.exit(1);\n }\n\n // Detect hook manager\n const hasHusky = fs.existsSync(path.join(cwd, '.husky'));\n const hasLefthook = fs.existsSync(path.join(cwd, 'lefthook.yml')) ||\n fs.existsSync(path.join(cwd, '.lefthook.yml'));\n\n if (hasHusky) {\n // Add to existing husky setup\n const hookFile = path.join(cwd, '.husky', 'pre-commit');\n const hookCommand = `npx drift-guard check --threshold ${threshold} --ci`;\n\n if (fs.existsSync(hookFile)) {\n const existing = fs.readFileSync(hookFile, 'utf-8');\n if (existing.includes('drift-guard')) {\n console.log(chalk.yellow('โš  drift-guard hook already exists in .husky/pre-commit'));\n return;\n }\n fs.appendFileSync(hookFile, `\\n${hookCommand}\\n`);\n } else {\n fs.writeFileSync(hookFile, `#!/usr/bin/env sh\\n. \"$(dirname -- \"$0\")/_/husky.sh\"\\n\\n${hookCommand}\\n`);\n }\n\n console.log(chalk.green('โœ“ Added drift-guard check to .husky/pre-commit'));\n return;\n }\n\n if (hasLefthook) {\n console.log(chalk.yellow('โš  lefthook detected. Add this to your lefthook.yml:'));\n console.log(chalk.cyan(`\npre-commit:\n commands:\n drift-guard:\n run: npx drift-guard check --threshold ${threshold} --ci\n`));\n return;\n }\n\n // No hook manager โ€” install via .git/hooks directly\n const hooksDir = path.join(cwd, '.git', 'hooks');\n const hookFile = path.join(hooksDir, 'pre-commit');\n const hookScript = `#!/usr/bin/env sh\n# drift-guard pre-commit hook\n# Checks for design token drift before commits\n# Use --force flag to bypass: git commit --no-verify\n\nnpx drift-guard check --threshold ${threshold} --ci\n\nif [ $? -ne 0 ]; then\n echo \"\"\n echo \"\\\\033[31mโœ— Design drift detected! Commit blocked.\\\\033[0m\"\n echo \" Run 'npx drift-guard check' for details.\"\n echo \" If changes are intentional, run 'npx drift-guard snapshot update'\"\n echo \" Or use 'git commit --no-verify' to bypass.\"\n exit 1\nfi\n`;\n\n if (!fs.existsSync(hooksDir)) {\n fs.mkdirSync(hooksDir, { recursive: true });\n }\n\n if (fs.existsSync(hookFile)) {\n const existing = fs.readFileSync(hookFile, 'utf-8');\n if (existing.includes('drift-guard')) {\n console.log(chalk.yellow('โš  drift-guard hook already installed'));\n return;\n }\n // Append to existing hook\n fs.appendFileSync(hookFile, `\\n${hookScript}`);\n console.log(chalk.green('โœ“ Appended drift-guard to existing pre-commit hook'));\n } else {\n fs.writeFileSync(hookFile, hookScript);\n // Make executable on Unix\n try {\n fs.chmodSync(hookFile, 0o755);\n } catch {\n // Windows may not support chmod, skip\n }\n console.log(chalk.green('โœ“ Installed drift-guard pre-commit hook'));\n }\n\n console.log(chalk.dim(` Threshold: ${threshold}%`));\n console.log(chalk.dim(' Bypass: git commit --no-verify'));\n}\n\n/**\n * Uninstall the pre-commit hook\n */\nexport async function hookUninstallCommand(): Promise<void> {\n const cwd = process.cwd();\n\n // Check husky\n const huskyHook = path.join(cwd, '.husky', 'pre-commit');\n if (fs.existsSync(huskyHook)) {\n const content = fs.readFileSync(huskyHook, 'utf-8');\n if (content.includes('drift-guard')) {\n const cleaned = content.replace(/\\n?npx drift-guard.*\\n?/g, '\\n');\n fs.writeFileSync(huskyHook, cleaned);\n console.log(chalk.green('โœ“ Removed drift-guard from .husky/pre-commit'));\n return;\n }\n }\n\n // Check .git/hooks\n const gitHook = path.join(cwd, '.git', 'hooks', 'pre-commit');\n if (fs.existsSync(gitHook)) {\n const content = fs.readFileSync(gitHook, 'utf-8');\n if (content.includes('drift-guard')) {\n // If the entire file is our hook, remove it\n if (content.includes('# drift-guard pre-commit hook') && !content.includes('\\n#!/usr/bin/env sh\\n')) {\n fs.unlinkSync(gitHook);\n console.log(chalk.green('โœ“ Removed drift-guard pre-commit hook'));\n } else {\n // Remove just our part\n const cleaned = content.replace(/# drift-guard pre-commit hook[\\s\\S]*?fi\\n?/g, '');\n fs.writeFileSync(gitHook, cleaned);\n console.log(chalk.green('โœ“ Removed drift-guard from pre-commit hook'));\n }\n return;\n }\n }\n\n console.log(chalk.yellow('โš  No drift-guard hook found to uninstall'));\n}\n","import { Command } from 'commander';\nimport path from 'node:path';\nimport fs from 'node:fs';\nimport fg from 'fast-glob';\nimport { loadSnapshot, loadConfig } from '../core/snapshot.js';\nimport { detectDrift } from '../core/drift.js';\nimport {\n syncToStitch,\n syncFromStitch,\n applySyncChanges,\n} from '../core/sync.js';\nimport { parseCss, extractCssVariables } from '../parsers/css-parser.js';\nimport { parseHtml, extractStyleBlocks, extractTailwindConfig } from '../parsers/html-parser.js';\nimport type { DesignToken, SyncDirection } from '../types/index.js';\n\nexport const syncCommand = new Command('sync')\n .description('Synchronize design tokens between Stitch and your codebase')\n .requiredOption(\n '-d, --direction <direction>',\n 'Sync direction: to-stitch (push code changes to Stitch) or to-code (pull Stitch changes)',\n )\n .option(\n '--stitch-html <path>',\n 'Path to Stitch HTML file (for to-code direction)',\n )\n .option(\n '--stitch-project <id>',\n 'Stitch project ID (for to-stitch direction)',\n )\n .option(\n '--stitch-screen <id>',\n 'Stitch screen ID (for to-stitch direction)',\n )\n .option('--apply', 'Auto-apply changes: full HTML replacement + CSS patching (to-code only)', false)\n .option('--target <path>', 'Target local HTML file to replace with Stitch version (to-code --apply)')\n .option('--dry-run', 'Preview changes without applying', false)\n .option('--json', 'Output as JSON', false)\n .action(async (options) => {\n const projectRoot = process.cwd();\n const direction = options.direction as SyncDirection;\n\n if (direction !== 'to-stitch' && direction !== 'to-code') {\n console.error(\n 'โŒ Invalid direction. Use \"to-stitch\" or \"to-code\".',\n );\n process.exit(1);\n }\n\n if (direction === 'to-stitch') {\n await handleToStitch(projectRoot, options);\n } else {\n await handleToCode(projectRoot, options);\n }\n });\n\n/**\n * Handle to-stitch direction:\n * Compare current code against snapshot โ†’ generate Stitch edit prompt\n */\nasync function handleToStitch(\n projectRoot: string,\n options: { dryRun: boolean; json: boolean; stitchProject?: string; stitchScreen?: string },\n): Promise<void> {\n const snapshot = loadSnapshot(projectRoot);\n if (!snapshot) {\n console.error('โŒ No snapshot found. Run \"drift-guard init\" first.');\n process.exit(1);\n }\n\n // Detect drift (code vs snapshot)\n const report = await detectDrift(projectRoot, snapshot, 0);\n\n if (report.items.length === 0) {\n console.log('โœ… No changes detected. Stitch and code are in sync!');\n return;\n }\n\n const result = syncToStitch(report.items);\n\n if (options.json) {\n console.log(JSON.stringify(result, null, 2));\n return;\n }\n\n // Pretty output\n console.log('');\n console.log('๐Ÿ”„ drift-guard sync โ†’ to-stitch');\n console.log(` ${result.changes.length} change(s) detected\\n`);\n\n for (const change of result.changes) {\n const icon =\n change.action === 'update' ? 'โœ๏ธ' :\n change.action === 'add' ? 'โž•' : '๐Ÿ—‘๏ธ';\n console.log(\n ` ${icon} ${change.property}: ${change.fromValue || '(none)'} โ†’ ${change.toValue || '(removed)'}`,\n );\n }\n\n console.log('');\n console.log('โ”'.repeat(60));\n console.log('๐Ÿ“‹ Stitch edit_screens prompt:');\n console.log('โ”'.repeat(60));\n console.log('');\n console.log(result.prompt);\n console.log('');\n console.log('โ”'.repeat(60));\n\n const projectId = options.stitchProject;\n const screenId = options.stitchScreen;\n\n if (projectId && screenId) {\n console.log('');\n console.log('๐Ÿ’ก To apply these changes in Stitch, run:');\n console.log('');\n console.log(` edit_screens({`);\n console.log(` projectId: \"${projectId}\",`);\n console.log(` selectedScreenIds: [\"${screenId}\"],`);\n console.log(` prompt: \"<the prompt above>\"`);\n console.log(` })`);\n } else {\n console.log('');\n console.log(\n '๐Ÿ’ก Copy the prompt above and use it with Stitch MCP edit_screens',\n );\n console.log(\n ' or pass --stitch-project and --stitch-screen for a ready-to-use call.',\n );\n }\n}\n\n/**\n * Handle to-code direction:\n * Compare Stitch HTML against snapshot โ†’ generate CSS patch โ†’ optionally apply.\n *\n * With --apply: Stitch HTML is the SOURCE OF TRUTH.\n * 1. Replace the local Stitch HTML file entirely (fixes text/layout/content diffs)\n * 2. Patch design tokens in other CSS files\n * 3. Update snapshot\n * 4. Verify 0% drift\n */\nasync function handleToCode(\n projectRoot: string,\n options: { dryRun: boolean; json: boolean; apply: boolean; stitchHtml?: string; target?: string },\n): Promise<void> {\n const snapshot = loadSnapshot(projectRoot);\n if (!snapshot) {\n console.error('โŒ No snapshot found. Run \"drift-guard init\" first.');\n process.exit(1);\n }\n\n // Get Stitch HTML path (new/downloaded version)\n const config = loadConfig(projectRoot);\n const stitchHtmlPath =\n options.stitchHtml ?? config.stitch?.htmlPath;\n\n if (!stitchHtmlPath) {\n console.error(\n 'โŒ No Stitch HTML file specified.',\n );\n console.error(\n ' Use --stitch-html <path> or set stitch.htmlPath in .design-guard/config.json',\n );\n process.exit(1);\n }\n\n const absPath = path.resolve(projectRoot, stitchHtmlPath);\n if (!fs.existsSync(absPath)) {\n console.error(`โŒ Stitch HTML file not found: ${absPath}`);\n process.exit(1);\n }\n\n // Parse Stitch HTML for tokens\n const htmlContent = fs.readFileSync(absPath, 'utf-8');\n const stitchTokens: DesignToken[] = [];\n\n const htmlTokens = parseHtml(htmlContent, stitchHtmlPath);\n stitchTokens.push(...htmlTokens);\n\n const styleBlocks = extractStyleBlocks(htmlContent);\n for (const block of styleBlocks) {\n stitchTokens.push(...parseCss(block, stitchHtmlPath));\n stitchTokens.push(...extractCssVariables(block, stitchHtmlPath));\n }\n\n const twTokens = extractTailwindConfig(htmlContent, stitchHtmlPath);\n stitchTokens.push(...twTokens);\n\n // Compare Stitch tokens against snapshot\n const result = syncFromStitch(stitchTokens, snapshot.tokens);\n\n if (options.json) {\n console.log(JSON.stringify(result, null, 2));\n return;\n }\n\n // === FULL SYNC (--apply): Stitch is source of truth ===\n if (options.apply && !options.dryRun) {\n console.log('');\n console.log('๐Ÿ”„ drift-guard sync โ†’ to-code (FULL SYNC)');\n console.log(' Stitch HTML is the source of truth.\\n');\n\n // Step 1: Find local Stitch HTML files to replace\n const targetPath = options.target;\n const localStitchFiles = await findLocalStitchHtml(projectRoot, absPath, targetPath);\n let htmlReplaced = false;\n\n if (localStitchFiles.length > 0) {\n console.log('๐Ÿ“„ Step 1: Full HTML replacement');\n for (const localFile of localStitchFiles) {\n const localAbsPath = path.resolve(projectRoot, localFile);\n const localContent = fs.readFileSync(localAbsPath, 'utf-8');\n\n if (localContent !== htmlContent) {\n fs.writeFileSync(localAbsPath, htmlContent, 'utf-8');\n console.log(` โœ… Replaced: ${localFile} (Stitch โ†’ local)`);\n htmlReplaced = true;\n } else {\n console.log(` โ„น๏ธ Already identical: ${localFile}`);\n }\n }\n } else {\n console.log('๐Ÿ“„ Step 1: No local Stitch HTML found to replace.');\n console.log(' ๐Ÿ’ก Use --target <path> to specify the target file.');\n }\n\n // Step 2: Patch design tokens in CSS files\n if (result.changes.length > 0) {\n console.log(`\\n๐Ÿ“ Step 2: Patching ${result.changes.length} design token(s) in CSS files`);\n for (const change of result.changes) {\n const icon =\n change.action === 'update' ? 'โœ๏ธ' :\n change.action === 'add' ? 'โž•' : '๐Ÿ—‘๏ธ';\n console.log(\n ` ${icon} ${change.property}: ${change.fromValue || '(none)'} โ†’ ${change.toValue || '(removed)'}`,\n );\n }\n\n const cssFileMap = await loadProjectCssFiles(projectRoot, config);\n const { modifiedFiles, appliedCount } = applySyncChanges(result.changes, cssFileMap);\n\n if (appliedCount > 0) {\n for (const [file, content] of modifiedFiles) {\n const fullPath = path.resolve(projectRoot, file);\n fs.writeFileSync(fullPath, content, 'utf-8');\n console.log(` โœ… Patched: ${file}`);\n }\n }\n } else {\n console.log('\\n๐Ÿ“ Step 2: No design token changes โ€” tokens already match.');\n }\n\n // Step 3: Update snapshot to reflect new state\n if (htmlReplaced || result.changes.length > 0) {\n console.log('\\n๐Ÿ“ธ Step 3: Updating snapshot...');\n\n const { execSync } = await import('node:child_process');\n try {\n execSync(\n `node \"${path.resolve(projectRoot, '..', 'drift-guard', 'dist', 'cli', 'index.js')}\" snapshot update`,\n { cwd: projectRoot, stdio: 'pipe' },\n );\n } catch {\n // Try the global command\n try {\n execSync('npx drift-guard snapshot update', {\n cwd: projectRoot,\n stdio: 'pipe',\n });\n } catch {\n console.log(' โš ๏ธ Could not auto-update snapshot. Run: drift-guard snapshot update');\n }\n }\n console.log(' โœ… Snapshot updated.');\n }\n\n // Step 4: Verify full sync\n console.log('\\n๐Ÿ” Step 4: Verifying full sync...');\n\n // Compare the Stitch source HTML with the local file\n if (localStitchFiles.length > 0) {\n let allMatch = true;\n for (const localFile of localStitchFiles) {\n const localAbsPath = path.resolve(projectRoot, localFile);\n const localContent = fs.readFileSync(localAbsPath, 'utf-8');\n if (localContent === htmlContent) {\n console.log(` โœ… ${localFile} โ€” 100% identical to Stitch`);\n } else {\n console.log(` โŒ ${localFile} โ€” content differs!`);\n allMatch = false;\n }\n }\n if (allMatch) {\n console.log('\\n ๐ŸŽ‰ FULL SYNC VERIFIED โ€” Stitch and code are 100% identical!');\n }\n }\n } else if (result.changes.length === 0) {\n console.log('โœ… Stitch and code design tokens are already in sync!');\n console.log(' ๐Ÿ’ก Use --apply for full HTML content sync (text, layout, structure).');\n } else {\n // Show token diff and patch\n console.log('');\n console.log('๐Ÿ”„ drift-guard sync โ†’ to-code');\n console.log(` ${result.changes.length} design token change(s) from Stitch\\n`);\n\n for (const change of result.changes) {\n const icon =\n change.action === 'update' ? 'โœ๏ธ' :\n change.action === 'add' ? 'โž•' : '๐Ÿ—‘๏ธ';\n console.log(\n ` ${icon} ${change.property}: ${change.fromValue || '(none)'} โ†’ ${change.toValue || '(removed)'}`,\n );\n }\n\n if (result.patchFile) {\n console.log('');\n console.log('โ”'.repeat(60));\n console.log('๐Ÿ“‹ CSS patch to apply:');\n console.log('โ”'.repeat(60));\n console.log('');\n console.log(result.patchFile);\n console.log('');\n console.log('โ”'.repeat(60));\n\n if (!options.dryRun) {\n const patchPath = path.join(\n projectRoot,\n '.design-guard',\n 'sync-patch.css',\n );\n fs.writeFileSync(patchPath, result.patchFile, 'utf-8');\n console.log(`\\n๐Ÿ’พ Patch saved to: ${patchPath}`);\n console.log(' Use --apply for full HTML content + token sync.');\n } else {\n console.log('\\n๐Ÿ” Dry run โ€” no files written.');\n }\n }\n }\n}\n\n/**\n * Find local Stitch HTML files that should be replaced.\n * Searches for stitch-design.html or files matching --target.\n */\nasync function findLocalStitchHtml(\n projectRoot: string,\n sourceAbsPath: string,\n targetPath?: string,\n): Promise<string[]> {\n if (targetPath) {\n return [targetPath];\n }\n\n // Search for stitch-design.html files in the project\n const stitchFiles = await fg(\n ['**/stitch-design.html', '**/stitch*.html'],\n {\n cwd: projectRoot,\n ignore: ['node_modules/**', 'dist/**', 'build/**'],\n absolute: false,\n },\n );\n\n // Exclude the source file itself\n const sourceRelative = path.relative(projectRoot, sourceAbsPath);\n return stitchFiles.filter(f => f !== sourceRelative);\n}\n\n/**\n * Load all CSS files from the project into a map\n */\nasync function loadProjectCssFiles(\n projectRoot: string,\n config: { cssFiles: string[]; ignore: string[] },\n): Promise<Map<string, string>> {\n const cssFileMap = new Map<string, string>();\n\n for (const pattern of config.cssFiles) {\n const matches = await fg(pattern, {\n cwd: projectRoot,\n ignore: config.ignore,\n absolute: false,\n });\n\n for (const file of matches) {\n const absPath = path.resolve(projectRoot, file);\n if (fs.existsSync(absPath)) {\n cssFileMap.set(file, fs.readFileSync(absPath, 'utf-8'));\n }\n }\n }\n\n // Also include HTML files that might have Tailwind config\n const htmlPatterns = ['**/*.html'];\n const htmlIgnore = ['node_modules/**', 'dist/**', 'build/**', '.next/**'];\n const htmlMatches = await fg(htmlPatterns, {\n cwd: projectRoot,\n ignore: htmlIgnore,\n absolute: false,\n });\n\n for (const file of htmlMatches) {\n const absPath = path.resolve(projectRoot, file);\n if (fs.existsSync(absPath)) {\n cssFileMap.set(file, fs.readFileSync(absPath, 'utf-8'));\n }\n }\n\n return cssFileMap;\n}\n"],"mappings":"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","names":["Command","chalk","hookFile","chalk","chalk","chalk","chalk","chalk","chalk","fs","path","chalk","hookFile","path","fs","path","fs","Command","chalk"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stayicon/drift-guard",
3
- "version": "0.2.2",
3
+ "version": "0.2.3",
4
4
  "description": "Protect your UI from AI coding agents' design drift. Detect, prevent, and lock design tokens during AI-assisted development.",
5
5
  "keywords": [
6
6
  "design-drift",