@stayicon/drift-guard 0.2.1 โ 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 +23 -4
- package/dist/cli/index.js +146 -55
- package/dist/cli/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -7,9 +7,18 @@
|
|
|
7
7
|
[](https://www.npmjs.com/package/@stayicon/drift-guard)
|
|
8
8
|
[](https://opensource.org/licenses/MIT)
|
|
9
9
|
[](https://github.com/Hwani-Net/drift-guard)
|
|
10
|
+
[](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
|
|
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
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
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";
|
|
@@ -85,6 +169,13 @@ async function checkCommand(options) {
|
|
|
85
169
|
const config = loadConfig(projectRoot);
|
|
86
170
|
const threshold = options.threshold ? parseInt(options.threshold, 10) : config.threshold;
|
|
87
171
|
console.log(chalk2.bold("\n\u{1F6E1}\uFE0F drift-guard check\n"));
|
|
172
|
+
const snapshotAge = Date.now() - new Date(snapshot.createdAt).getTime();
|
|
173
|
+
const ageDays = Math.floor(snapshotAge / (1e3 * 60 * 60 * 24));
|
|
174
|
+
if (ageDays >= 7) {
|
|
175
|
+
const ageStr = ageDays >= 30 ? `${Math.floor(ageDays / 30)} month(s)` : `${ageDays} days`;
|
|
176
|
+
console.log(chalk2.yellow(`\u26A0\uFE0F Snapshot is ${ageStr} old (created ${snapshot.createdAt.split("T")[0]}).`));
|
|
177
|
+
console.log(chalk2.yellow(" If your design has changed, run: ") + chalk2.cyan("drift-guard init --from <latest.html>\n"));
|
|
178
|
+
}
|
|
88
179
|
console.log(chalk2.dim(`Comparing against snapshot from ${snapshot.createdAt}...
|
|
89
180
|
`));
|
|
90
181
|
const report = await detectDrift(projectRoot, snapshot, threshold);
|
|
@@ -221,32 +312,32 @@ async function snapshotCommand(options) {
|
|
|
221
312
|
}
|
|
222
313
|
|
|
223
314
|
// src/cli/hook.ts
|
|
224
|
-
import
|
|
225
|
-
import
|
|
315
|
+
import fs2 from "fs";
|
|
316
|
+
import path2 from "path";
|
|
226
317
|
import chalk5 from "chalk";
|
|
227
318
|
async function hookInstallCommand(options) {
|
|
228
319
|
const cwd = process.cwd();
|
|
229
320
|
const threshold = options.threshold ?? "10";
|
|
230
|
-
if (!
|
|
321
|
+
if (!fs2.existsSync(path2.join(cwd, ".git"))) {
|
|
231
322
|
console.error(chalk5.red("\u2717 Not a git repository. Run this from a git project root."));
|
|
232
323
|
process.exit(1);
|
|
233
324
|
}
|
|
234
|
-
const hasHusky =
|
|
235
|
-
const hasLefthook =
|
|
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"));
|
|
236
327
|
if (hasHusky) {
|
|
237
|
-
const hookFile2 =
|
|
328
|
+
const hookFile2 = path2.join(cwd, ".husky", "pre-commit");
|
|
238
329
|
const hookCommand = `npx drift-guard check --threshold ${threshold} --ci`;
|
|
239
|
-
if (
|
|
240
|
-
const existing =
|
|
330
|
+
if (fs2.existsSync(hookFile2)) {
|
|
331
|
+
const existing = fs2.readFileSync(hookFile2, "utf-8");
|
|
241
332
|
if (existing.includes("drift-guard")) {
|
|
242
333
|
console.log(chalk5.yellow("\u26A0 drift-guard hook already exists in .husky/pre-commit"));
|
|
243
334
|
return;
|
|
244
335
|
}
|
|
245
|
-
|
|
336
|
+
fs2.appendFileSync(hookFile2, `
|
|
246
337
|
${hookCommand}
|
|
247
338
|
`);
|
|
248
339
|
} else {
|
|
249
|
-
|
|
340
|
+
fs2.writeFileSync(hookFile2, `#!/usr/bin/env sh
|
|
250
341
|
. "$(dirname -- "$0")/_/husky.sh"
|
|
251
342
|
|
|
252
343
|
${hookCommand}
|
|
@@ -265,8 +356,8 @@ pre-commit:
|
|
|
265
356
|
`));
|
|
266
357
|
return;
|
|
267
358
|
}
|
|
268
|
-
const hooksDir =
|
|
269
|
-
const hookFile =
|
|
359
|
+
const hooksDir = path2.join(cwd, ".git", "hooks");
|
|
360
|
+
const hookFile = path2.join(hooksDir, "pre-commit");
|
|
270
361
|
const hookScript = `#!/usr/bin/env sh
|
|
271
362
|
# drift-guard pre-commit hook
|
|
272
363
|
# Checks for design token drift before commits
|
|
@@ -283,22 +374,22 @@ if [ $? -ne 0 ]; then
|
|
|
283
374
|
exit 1
|
|
284
375
|
fi
|
|
285
376
|
`;
|
|
286
|
-
if (!
|
|
287
|
-
|
|
377
|
+
if (!fs2.existsSync(hooksDir)) {
|
|
378
|
+
fs2.mkdirSync(hooksDir, { recursive: true });
|
|
288
379
|
}
|
|
289
|
-
if (
|
|
290
|
-
const existing =
|
|
380
|
+
if (fs2.existsSync(hookFile)) {
|
|
381
|
+
const existing = fs2.readFileSync(hookFile, "utf-8");
|
|
291
382
|
if (existing.includes("drift-guard")) {
|
|
292
383
|
console.log(chalk5.yellow("\u26A0 drift-guard hook already installed"));
|
|
293
384
|
return;
|
|
294
385
|
}
|
|
295
|
-
|
|
386
|
+
fs2.appendFileSync(hookFile, `
|
|
296
387
|
${hookScript}`);
|
|
297
388
|
console.log(chalk5.green("\u2713 Appended drift-guard to existing pre-commit hook"));
|
|
298
389
|
} else {
|
|
299
|
-
|
|
390
|
+
fs2.writeFileSync(hookFile, hookScript);
|
|
300
391
|
try {
|
|
301
|
-
|
|
392
|
+
fs2.chmodSync(hookFile, 493);
|
|
302
393
|
} catch {
|
|
303
394
|
}
|
|
304
395
|
console.log(chalk5.green("\u2713 Installed drift-guard pre-commit hook"));
|
|
@@ -308,26 +399,26 @@ ${hookScript}`);
|
|
|
308
399
|
}
|
|
309
400
|
async function hookUninstallCommand() {
|
|
310
401
|
const cwd = process.cwd();
|
|
311
|
-
const huskyHook =
|
|
312
|
-
if (
|
|
313
|
-
const content =
|
|
402
|
+
const huskyHook = path2.join(cwd, ".husky", "pre-commit");
|
|
403
|
+
if (fs2.existsSync(huskyHook)) {
|
|
404
|
+
const content = fs2.readFileSync(huskyHook, "utf-8");
|
|
314
405
|
if (content.includes("drift-guard")) {
|
|
315
406
|
const cleaned = content.replace(/\n?npx drift-guard.*\n?/g, "\n");
|
|
316
|
-
|
|
407
|
+
fs2.writeFileSync(huskyHook, cleaned);
|
|
317
408
|
console.log(chalk5.green("\u2713 Removed drift-guard from .husky/pre-commit"));
|
|
318
409
|
return;
|
|
319
410
|
}
|
|
320
411
|
}
|
|
321
|
-
const gitHook =
|
|
322
|
-
if (
|
|
323
|
-
const content =
|
|
412
|
+
const gitHook = path2.join(cwd, ".git", "hooks", "pre-commit");
|
|
413
|
+
if (fs2.existsSync(gitHook)) {
|
|
414
|
+
const content = fs2.readFileSync(gitHook, "utf-8");
|
|
324
415
|
if (content.includes("drift-guard")) {
|
|
325
416
|
if (content.includes("# drift-guard pre-commit hook") && !content.includes("\n#!/usr/bin/env sh\n")) {
|
|
326
|
-
|
|
417
|
+
fs2.unlinkSync(gitHook);
|
|
327
418
|
console.log(chalk5.green("\u2713 Removed drift-guard pre-commit hook"));
|
|
328
419
|
} else {
|
|
329
420
|
const cleaned = content.replace(/# drift-guard pre-commit hook[\s\S]*?fi\n?/g, "");
|
|
330
|
-
|
|
421
|
+
fs2.writeFileSync(gitHook, cleaned);
|
|
331
422
|
console.log(chalk5.green("\u2713 Removed drift-guard from pre-commit hook"));
|
|
332
423
|
}
|
|
333
424
|
return;
|
|
@@ -338,8 +429,8 @@ async function hookUninstallCommand() {
|
|
|
338
429
|
|
|
339
430
|
// src/cli/sync.ts
|
|
340
431
|
import { Command } from "commander";
|
|
341
|
-
import
|
|
342
|
-
import
|
|
432
|
+
import path3 from "path";
|
|
433
|
+
import fs3 from "fs";
|
|
343
434
|
import fg from "fast-glob";
|
|
344
435
|
var syncCommand = new Command("sync").description("Synchronize design tokens between Stitch and your codebase").requiredOption(
|
|
345
436
|
"-d, --direction <direction>",
|
|
@@ -440,12 +531,12 @@ async function handleToCode(projectRoot, options) {
|
|
|
440
531
|
);
|
|
441
532
|
process.exit(1);
|
|
442
533
|
}
|
|
443
|
-
const absPath =
|
|
444
|
-
if (!
|
|
534
|
+
const absPath = path3.resolve(projectRoot, stitchHtmlPath);
|
|
535
|
+
if (!fs3.existsSync(absPath)) {
|
|
445
536
|
console.error(`\u274C Stitch HTML file not found: ${absPath}`);
|
|
446
537
|
process.exit(1);
|
|
447
538
|
}
|
|
448
|
-
const htmlContent =
|
|
539
|
+
const htmlContent = fs3.readFileSync(absPath, "utf-8");
|
|
449
540
|
const stitchTokens = [];
|
|
450
541
|
const htmlTokens = parseHtml(htmlContent, stitchHtmlPath);
|
|
451
542
|
stitchTokens.push(...htmlTokens);
|
|
@@ -471,10 +562,10 @@ async function handleToCode(projectRoot, options) {
|
|
|
471
562
|
if (localStitchFiles.length > 0) {
|
|
472
563
|
console.log("\u{1F4C4} Step 1: Full HTML replacement");
|
|
473
564
|
for (const localFile of localStitchFiles) {
|
|
474
|
-
const localAbsPath =
|
|
475
|
-
const localContent =
|
|
565
|
+
const localAbsPath = path3.resolve(projectRoot, localFile);
|
|
566
|
+
const localContent = fs3.readFileSync(localAbsPath, "utf-8");
|
|
476
567
|
if (localContent !== htmlContent) {
|
|
477
|
-
|
|
568
|
+
fs3.writeFileSync(localAbsPath, htmlContent, "utf-8");
|
|
478
569
|
console.log(` \u2705 Replaced: ${localFile} (Stitch \u2192 local)`);
|
|
479
570
|
htmlReplaced = true;
|
|
480
571
|
} else {
|
|
@@ -498,8 +589,8 @@ async function handleToCode(projectRoot, options) {
|
|
|
498
589
|
const { modifiedFiles, appliedCount } = applySyncChanges(result.changes, cssFileMap);
|
|
499
590
|
if (appliedCount > 0) {
|
|
500
591
|
for (const [file, content] of modifiedFiles) {
|
|
501
|
-
const fullPath =
|
|
502
|
-
|
|
592
|
+
const fullPath = path3.resolve(projectRoot, file);
|
|
593
|
+
fs3.writeFileSync(fullPath, content, "utf-8");
|
|
503
594
|
console.log(` \u2705 Patched: ${file}`);
|
|
504
595
|
}
|
|
505
596
|
}
|
|
@@ -511,7 +602,7 @@ async function handleToCode(projectRoot, options) {
|
|
|
511
602
|
const { execSync } = await import("child_process");
|
|
512
603
|
try {
|
|
513
604
|
execSync(
|
|
514
|
-
`node "${
|
|
605
|
+
`node "${path3.resolve(projectRoot, "..", "drift-guard", "dist", "cli", "index.js")}" snapshot update`,
|
|
515
606
|
{ cwd: projectRoot, stdio: "pipe" }
|
|
516
607
|
);
|
|
517
608
|
} catch {
|
|
@@ -530,8 +621,8 @@ async function handleToCode(projectRoot, options) {
|
|
|
530
621
|
if (localStitchFiles.length > 0) {
|
|
531
622
|
let allMatch = true;
|
|
532
623
|
for (const localFile of localStitchFiles) {
|
|
533
|
-
const localAbsPath =
|
|
534
|
-
const localContent =
|
|
624
|
+
const localAbsPath = path3.resolve(projectRoot, localFile);
|
|
625
|
+
const localContent = fs3.readFileSync(localAbsPath, "utf-8");
|
|
535
626
|
if (localContent === htmlContent) {
|
|
536
627
|
console.log(` \u2705 ${localFile} \u2014 100% identical to Stitch`);
|
|
537
628
|
} else {
|
|
@@ -567,12 +658,12 @@ async function handleToCode(projectRoot, options) {
|
|
|
567
658
|
console.log("");
|
|
568
659
|
console.log("\u2501".repeat(60));
|
|
569
660
|
if (!options.dryRun) {
|
|
570
|
-
const patchPath =
|
|
661
|
+
const patchPath = path3.join(
|
|
571
662
|
projectRoot,
|
|
572
663
|
".design-guard",
|
|
573
664
|
"sync-patch.css"
|
|
574
665
|
);
|
|
575
|
-
|
|
666
|
+
fs3.writeFileSync(patchPath, result.patchFile, "utf-8");
|
|
576
667
|
console.log(`
|
|
577
668
|
\u{1F4BE} Patch saved to: ${patchPath}`);
|
|
578
669
|
console.log(" Use --apply for full HTML content + token sync.");
|
|
@@ -594,7 +685,7 @@ async function findLocalStitchHtml(projectRoot, sourceAbsPath, targetPath) {
|
|
|
594
685
|
absolute: false
|
|
595
686
|
}
|
|
596
687
|
);
|
|
597
|
-
const sourceRelative =
|
|
688
|
+
const sourceRelative = path3.relative(projectRoot, sourceAbsPath);
|
|
598
689
|
return stitchFiles.filter((f) => f !== sourceRelative);
|
|
599
690
|
}
|
|
600
691
|
async function loadProjectCssFiles(projectRoot, config) {
|
|
@@ -606,9 +697,9 @@ async function loadProjectCssFiles(projectRoot, config) {
|
|
|
606
697
|
absolute: false
|
|
607
698
|
});
|
|
608
699
|
for (const file of matches) {
|
|
609
|
-
const absPath =
|
|
610
|
-
if (
|
|
611
|
-
cssFileMap.set(file,
|
|
700
|
+
const absPath = path3.resolve(projectRoot, file);
|
|
701
|
+
if (fs3.existsSync(absPath)) {
|
|
702
|
+
cssFileMap.set(file, fs3.readFileSync(absPath, "utf-8"));
|
|
612
703
|
}
|
|
613
704
|
}
|
|
614
705
|
}
|
|
@@ -620,9 +711,9 @@ async function loadProjectCssFiles(projectRoot, config) {
|
|
|
620
711
|
absolute: false
|
|
621
712
|
});
|
|
622
713
|
for (const file of htmlMatches) {
|
|
623
|
-
const absPath =
|
|
624
|
-
if (
|
|
625
|
-
cssFileMap.set(file,
|
|
714
|
+
const absPath = path3.resolve(projectRoot, file);
|
|
715
|
+
if (fs3.existsSync(absPath)) {
|
|
716
|
+
cssFileMap.set(file, fs3.readFileSync(absPath, "utf-8"));
|
|
626
717
|
}
|
|
627
718
|
}
|
|
628
719
|
return cssFileMap;
|
|
@@ -633,7 +724,7 @@ var program = new Command2();
|
|
|
633
724
|
program.name("drift-guard").description(
|
|
634
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."
|
|
635
726
|
).version("0.2.0");
|
|
636
|
-
program.command("init").description("Initialize drift-guard
|
|
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);
|
|
637
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);
|
|
638
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);
|
|
639
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);
|
package/dist/cli/index.js.map
CHANGED
|
@@ -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 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