digdesign 0.7.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +300 -139
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -5,7 +5,7 @@ import { Command } from "commander";
5
5
 
6
6
  // src/commands/add.ts
7
7
  import { access as access4, mkdir as mkdir3, writeFile as writeFile5 } from "fs/promises";
8
- import path7 from "path";
8
+ import path8 from "path";
9
9
 
10
10
  // src/lib/config.ts
11
11
  import { access, readFile, writeFile } from "fs/promises";
@@ -55,6 +55,10 @@ async function writeConfig(config, cwd = process.cwd()) {
55
55
  );
56
56
  }
57
57
 
58
+ // src/lib/framework.ts
59
+ import { readFile as readFile2 } from "fs/promises";
60
+ import path2 from "path";
61
+
58
62
  // src/lib/errors.ts
59
63
  var DigError = class extends Error {
60
64
  constructor(message, options) {
@@ -63,6 +67,48 @@ var DigError = class extends Error {
63
67
  }
64
68
  };
65
69
 
70
+ // src/lib/framework.ts
71
+ var CLI_FRAMEWORKS = ["react", "vue"];
72
+ function parseFramework(value) {
73
+ const normalized = value.trim().toLowerCase();
74
+ if (CLI_FRAMEWORKS.includes(normalized)) return normalized;
75
+ if (normalized === "svelte" || normalized === "angular") {
76
+ throw new DigError(
77
+ `CLI \u0647\u0646\u0648\u0632 ${normalized === "svelte" ? "Svelte" : "Angular"} \u0631\u0627 \u0646\u0635\u0628 \u0646\u0645\u06CC\u200C\u06A9\u0646\u062F.
78
+ \u06A9\u062F \u06A9\u0627\u0645\u067E\u0648\u0646\u0646\u062A \u0631\u0627 \u0627\u0632 \u062A\u0628 \xAB\u062F\u0633\u062A\u06CC\xBB \u0635\u0641\u062D\u0647\u0654 \u0645\u0633\u062A\u0646\u062F\u0627\u062A \u0628\u06AF\u06CC\u0631\u06CC\u062F\u060C \u06CC\u0627 /r/${normalized}/<name>.json \u0631\u0627 \u062F\u0633\u062A\u06CC \u0628\u0646\u0648\u06CC\u0633\u06CC\u062F.`
79
+ );
80
+ }
81
+ throw new DigError(`\u0641\u0631\u06CC\u0645\u200C\u0648\u0631\u06A9 \xAB${value}\xBB \u0634\u0646\u0627\u062E\u062A\u0647 \u0646\u0634\u062F. \u06CC\u06A9\u06CC \u0627\u0632 ${CLI_FRAMEWORKS.join("\u060C ")} \u0631\u0627 \u0628\u062F\u0647\u06CC\u062F.`);
82
+ }
83
+ async function readPackageJson(cwd) {
84
+ try {
85
+ return JSON.parse(await readFile2(path2.join(cwd, "package.json"), "utf8"));
86
+ } catch {
87
+ return null;
88
+ }
89
+ }
90
+ async function detectFramework(cwd) {
91
+ const pkg = await readPackageJson(cwd);
92
+ if (!pkg) return void 0;
93
+ const deps = { ...pkg.devDependencies, ...pkg.dependencies };
94
+ if ("react" in deps || "next" in deps) return "react";
95
+ if ("vue" in deps || "nuxt" in deps) return "vue";
96
+ return void 0;
97
+ }
98
+ async function resolveFramework(cwd, config, flag) {
99
+ if (flag) return parseFramework(flag);
100
+ if (config?.framework) return config.framework;
101
+ const detected = await detectFramework(cwd);
102
+ if (detected) return detected;
103
+ try {
104
+ const shadcn = JSON.parse(await readFile2(path2.join(cwd, "components.json"), "utf8"));
105
+ const hint = `${shadcn.framework ?? ""} ${shadcn.$schema ?? ""} ${shadcn.tailwind?.css ?? ""}`.toLowerCase();
106
+ if (/vue|nuxt/.test(hint)) return "vue";
107
+ } catch {
108
+ }
109
+ return "react";
110
+ }
111
+
66
112
  // src/lib/prompt.ts
67
113
  import * as readline from "readline/promises";
68
114
  import { stdin, stdout } from "process";
@@ -127,19 +173,19 @@ function hashContent(content) {
127
173
  }
128
174
 
129
175
  // src/lib/lock.ts
130
- import { mkdir, readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
131
- import path2 from "path";
176
+ import { mkdir, readFile as readFile3, writeFile as writeFile2 } from "fs/promises";
177
+ import path3 from "path";
132
178
  var LOCK_DIR = ".dig";
133
179
  var LOCK_FILE_NAME = "registry-lock.json";
134
180
  function emptyLock() {
135
181
  return { components: {} };
136
182
  }
137
183
  function lockFilePath(cwd) {
138
- return path2.join(cwd, LOCK_DIR, LOCK_FILE_NAME);
184
+ return path3.join(cwd, LOCK_DIR, LOCK_FILE_NAME);
139
185
  }
140
186
  async function readLock(cwd = process.cwd()) {
141
187
  try {
142
- const raw = await readFile2(lockFilePath(cwd), "utf8");
188
+ const raw = await readFile3(lockFilePath(cwd), "utf8");
143
189
  const parsed = JSON.parse(raw);
144
190
  return { components: parsed?.components ?? {} };
145
191
  } catch (error) {
@@ -148,7 +194,7 @@ async function readLock(cwd = process.cwd()) {
148
194
  }
149
195
  }
150
196
  async function writeLock(lock, cwd = process.cwd()) {
151
- await mkdir(path2.join(cwd, LOCK_DIR), { recursive: true });
197
+ await mkdir(path3.join(cwd, LOCK_DIR), { recursive: true });
152
198
  await writeFile2(lockFilePath(cwd), `${JSON.stringify(lock, null, 2)}
153
199
  `, "utf8");
154
200
  }
@@ -168,7 +214,7 @@ function mergeComponentEntry(existing, patch) {
168
214
  // src/lib/package-manager.ts
169
215
  import { access as access2 } from "fs/promises";
170
216
  import { spawn } from "child_process";
171
- import path3 from "path";
217
+ import path4 from "path";
172
218
  var LOCKFILES = [
173
219
  ["pnpm", "pnpm-lock.yaml"],
174
220
  ["yarn", "yarn.lock"],
@@ -178,7 +224,7 @@ var LOCKFILES = [
178
224
  async function detectPackageManager(cwd = process.cwd()) {
179
225
  for (const [pm, lockfile] of LOCKFILES) {
180
226
  try {
181
- await access2(path3.join(cwd, lockfile));
227
+ await access2(path4.join(cwd, lockfile));
182
228
  return pm;
183
229
  } catch {
184
230
  continue;
@@ -248,9 +294,12 @@ function installDependencies(pm, deps, options = {}) {
248
294
  }
249
295
 
250
296
  // src/lib/registry.ts
251
- function resolveUrl(nameOrUrl, registryUrl) {
297
+ function registryBase(registryUrl, framework) {
298
+ return !framework || framework === "react" ? `${registryUrl}/r` : `${registryUrl}/r/${framework}`;
299
+ }
300
+ function resolveUrl(nameOrUrl, registryUrl, framework) {
252
301
  if (/^https?:\/\//.test(nameOrUrl)) return nameOrUrl;
253
- return `${registryUrl}/r/${nameOrUrl}.json`;
302
+ return `${registryBase(registryUrl, framework)}/${nameOrUrl}.json`;
254
303
  }
255
304
  async function fetchFromRegistry(url, subject) {
256
305
  let response;
@@ -288,28 +337,28 @@ async function fetchFromRegistry(url, subject) {
288
337
  function normalizeType(type) {
289
338
  return type.startsWith("registry:") ? `dig:${type.slice("registry:".length)}` : type;
290
339
  }
291
- async function fetchRegistryIndex(registryUrl) {
292
- const url = `${registryUrl}/r/registry.json`;
340
+ async function fetchRegistryIndex(registryUrl, framework) {
341
+ const url = `${registryBase(registryUrl, framework)}/registry.json`;
293
342
  const response = await fetchFromRegistry(url, "\u0641\u0647\u0631\u0633\u062A\u0650 \u0631\u062C\u06CC\u0633\u062A\u0631\u06CC");
294
343
  const index = await response.json();
295
344
  for (const item of index.items) item.type = normalizeType(item.type);
296
345
  return index;
297
346
  }
298
- async function fetchRegistryItem(nameOrUrl, registryUrl) {
299
- const url = resolveUrl(nameOrUrl, registryUrl);
347
+ async function fetchRegistryItem(nameOrUrl, registryUrl, framework) {
348
+ const url = resolveUrl(nameOrUrl, registryUrl, framework);
300
349
  const response = await fetchFromRegistry(url, `\xAB${nameOrUrl}\xBB`);
301
350
  const item = await response.json();
302
351
  item.type = normalizeType(item.type);
303
352
  for (const file of item.files ?? []) file.type = normalizeType(file.type);
304
353
  return item;
305
354
  }
306
- async function resolveRegistryTree(names, registryUrl) {
355
+ async function resolveRegistryTree(names, registryUrl, framework) {
307
356
  const resolved = /* @__PURE__ */ new Map();
308
357
  const queued = new Set(names);
309
358
  const queue = [...names];
310
359
  while (queue.length) {
311
360
  const next = queue.shift();
312
- const item = await fetchRegistryItem(next, registryUrl);
361
+ const item = await fetchRegistryItem(next, registryUrl, framework);
313
362
  if (resolved.has(item.name)) continue;
314
363
  resolved.set(item.name, item);
315
364
  for (const dep of item.registryDependencies ?? []) {
@@ -323,14 +372,14 @@ async function resolveRegistryTree(names, registryUrl) {
323
372
  }
324
373
 
325
374
  // src/lib/snapshot.ts
326
- import { access as access3, mkdir as mkdir2, readFile as readFile3, rm, writeFile as writeFile3 } from "fs/promises";
327
- import path4 from "path";
328
- var SNAPSHOT_ROOT = path4.join(".dig", "snapshots");
375
+ import { access as access3, mkdir as mkdir2, readFile as readFile4, rm, writeFile as writeFile3 } from "fs/promises";
376
+ import path5 from "path";
377
+ var SNAPSHOT_ROOT = path5.join(".dig", "snapshots");
329
378
  function snapshotDirFor(cwd, name, version) {
330
- return path4.join(cwd, SNAPSHOT_ROOT, name, version);
379
+ return path5.join(cwd, SNAPSHOT_ROOT, name, version);
331
380
  }
332
381
  function snapshotRelativePath(name, version) {
333
- return `${SNAPSHOT_ROOT.split(path4.sep).join("/")}/${name}/${version}`;
382
+ return `${SNAPSHOT_ROOT.split(path5.sep).join("/")}/${name}/${version}`;
334
383
  }
335
384
  async function fileExists(target) {
336
385
  try {
@@ -347,19 +396,19 @@ async function writeComponentSnapshot(cwd, name, version, files) {
347
396
  const dir = snapshotDirFor(cwd, name, version);
348
397
  const pending = [];
349
398
  for (const [relFilePath, content] of entries) {
350
- const target = path4.join(dir, relFilePath);
399
+ const target = path5.join(dir, relFilePath);
351
400
  const existedBefore = await fileExists(target);
352
401
  pending.push({
353
402
  target,
354
403
  content,
355
404
  existedBefore,
356
- originalContent: existedBefore ? await readFile3(target, "utf8") : void 0
405
+ originalContent: existedBefore ? await readFile4(target, "utf8") : void 0
357
406
  });
358
407
  }
359
408
  const written = [];
360
409
  try {
361
410
  for (const item of pending) {
362
- await mkdir2(path4.dirname(item.target), { recursive: true });
411
+ await mkdir2(path5.dirname(item.target), { recursive: true });
363
412
  await writeFile3(item.target, item.content, "utf8");
364
413
  written.push(item);
365
414
  }
@@ -377,7 +426,7 @@ async function writeComponentSnapshot(cwd, name, version, files) {
377
426
  }
378
427
  async function readSnapshotFile(cwd, name, version, relFilePath) {
379
428
  try {
380
- return await readFile3(path4.join(snapshotDirFor(cwd, name, version), relFilePath), "utf8");
429
+ return await readFile4(path5.join(snapshotDirFor(cwd, name, version), relFilePath), "utf8");
381
430
  } catch (error) {
382
431
  if (error.code === "ENOENT") return void 0;
383
432
  throw error;
@@ -385,9 +434,9 @@ async function readSnapshotFile(cwd, name, version, relFilePath) {
385
434
  }
386
435
 
387
436
  // src/lib/target.ts
388
- import path5 from "path";
437
+ import path6 from "path";
389
438
  function toPosixPath(relativePath) {
390
- return relativePath.split(path5.sep).join("/");
439
+ return relativePath.split(path6.sep).join("/");
391
440
  }
392
441
  function targetPathOptions(config) {
393
442
  return { tailwindCss: config.tailwind.css, themeCss: config.tailwind.theme };
@@ -414,8 +463,8 @@ function resolveTargetPath(filePath, aliases, options = {}) {
414
463
  }
415
464
 
416
465
  // src/commands/design-md.ts
417
- import { readFile as readFile4, writeFile as writeFile4 } from "fs/promises";
418
- import path6 from "path";
466
+ import { readFile as readFile5, writeFile as writeFile4 } from "fs/promises";
467
+ import path7 from "path";
419
468
  var DESIGN_MD_FILE = "DESIGN.md";
420
469
  var GENERATED_MARK = "Generated by Dig";
421
470
  async function fetchDesignMd(registryUrl, options) {
@@ -438,13 +487,13 @@ async function fetchDesignMd(registryUrl, options) {
438
487
  }
439
488
  async function readIfExists(target) {
440
489
  try {
441
- return await readFile4(target, "utf8");
490
+ return await readFile5(target, "utf8");
442
491
  } catch {
443
492
  return null;
444
493
  }
445
494
  }
446
495
  async function writeDesignMd(cwd, registryUrl, options) {
447
- const target = path6.join(cwd, DESIGN_MD_FILE);
496
+ const target = path7.join(cwd, DESIGN_MD_FILE);
448
497
  const existing = await readIfExists(target);
449
498
  if (existing !== null && !options.force) {
450
499
  const generated = existing.includes(GENERATED_MARK);
@@ -472,7 +521,7 @@ function readDesignMdSettings(text) {
472
521
  }
473
522
  }
474
523
  async function refreshDesignMd(cwd, registryUrl, overrides = {}, log = console.log) {
475
- const target = path6.join(cwd, DESIGN_MD_FILE);
524
+ const target = path7.join(cwd, DESIGN_MD_FILE);
476
525
  const existing = await readIfExists(target);
477
526
  if (existing === null || !existing.includes(GENERATED_MARK)) return "skipped";
478
527
  try {
@@ -489,7 +538,7 @@ async function refreshDesignMd(cwd, registryUrl, overrides = {}, log = console.l
489
538
  async function designMdCommand(options) {
490
539
  const cwd = process.cwd();
491
540
  const config = await configExists(cwd) ? await readConfig(cwd) : defaultConfig();
492
- const previous = readDesignMdSettings(await readIfExists(path6.join(cwd, DESIGN_MD_FILE)) ?? "");
541
+ const previous = readDesignMdSettings(await readIfExists(path7.join(cwd, DESIGN_MD_FILE)) ?? "");
493
542
  const explicit = Object.fromEntries(Object.entries(options).filter(([, value]) => value !== void 0 && value !== false));
494
543
  options = { ...previous, ...explicit };
495
544
  const result = await writeDesignMd(cwd, config.registryUrl, { ...options, replaceGenerated: true });
@@ -507,13 +556,13 @@ async function pathExists(target) {
507
556
  return false;
508
557
  }
509
558
  }
510
- async function pickComponents(registryUrl) {
559
+ async function pickComponents(registryUrl, framework) {
511
560
  if (!process.stdin.isTTY) {
512
561
  throw new DigError(
513
562
  "\u0646\u0627\u0645 \u06A9\u0627\u0645\u067E\u0648\u0646\u0646\u062A \u0631\u0627 \u0628\u062F\u0647\u06CC\u062F: dig add button\n \u0628\u0631\u0627\u06CC \u062F\u06CC\u062F\u0646\u0650 \u0641\u0647\u0631\u0633\u062A: dig list"
514
563
  );
515
564
  }
516
- const index = await fetchRegistryIndex(registryUrl);
565
+ const index = await fetchRegistryIndex(registryUrl, framework);
517
566
  const choices = index.items.filter((item) => item.type === "dig:ui").map((item) => ({
518
567
  value: item.name,
519
568
  label: item.title ? `${item.name} \u2014 ${item.title}` : item.name
@@ -533,18 +582,25 @@ ${choices.length} \u06A9\u0627\u0645\u067E\u0648\u0646\u0646\u062A \u062F\u0631
533
582
  }
534
583
  async function addCommand(components, options) {
535
584
  const cwd = process.cwd();
536
- const config = await configExists(cwd) ? await readConfig(cwd) : defaultConfig();
537
- const names = components.length ? components : await pickComponents(config.registryUrl);
585
+ const hasConfig = await configExists(cwd);
586
+ const config = hasConfig ? await readConfig(cwd) : defaultConfig();
587
+ const framework = await resolveFramework(cwd, config, options.framework);
588
+ if (hasConfig && framework !== "react" && config.framework !== framework && !options.dryRun) {
589
+ config.framework = framework;
590
+ await writeConfig(config, cwd);
591
+ }
592
+ config.framework = framework === "react" ? config.framework : framework;
593
+ const names = components.length ? components : await pickComponents(config.registryUrl, framework);
538
594
  if (names.length === 0) return;
539
- console.log(`\u062F\u0631\u06CC\u0627\u0641\u062A \u0627\u0632 ${config.registryUrl} \u2026`);
540
- const items = await resolveRegistryTree(names, config.registryUrl);
595
+ console.log(`\u062F\u0631\u06CC\u0627\u0641\u062A \u0627\u0632 ${config.registryUrl}${framework === "react" ? "" : ` (${framework})`} \u2026`);
596
+ const items = await resolveRegistryTree(names, config.registryUrl, framework);
541
597
  let overwrite = Boolean(options.overwrite);
542
598
  if (!overwrite && !options.skipExisting) {
543
599
  const existing = [];
544
600
  for (const item of items.values()) {
545
601
  for (const file of item.files) {
546
- const target = path7.join(cwd, resolveTargetPath(file.path, config.aliases, targetPathOptions(config)));
547
- if (await pathExists(target)) existing.push(path7.relative(cwd, target));
602
+ const target = path8.join(cwd, resolveTargetPath(file.path, config.aliases, targetPathOptions(config)));
603
+ if (await pathExists(target)) existing.push(path8.relative(cwd, target));
548
604
  }
549
605
  }
550
606
  if (existing.length) {
@@ -565,11 +621,11 @@ ${existing.length} \u0641\u0627\u06CC\u0644 \u0627\u0632 \u0642\u0628\u0644 \u06
565
621
  for (const item of items.values()) {
566
622
  for (const dep of item.dependencies ?? []) npmDeps.add(dep);
567
623
  for (const file of item.files) {
568
- const target = path7.join(cwd, resolveTargetPath(file.path, config.aliases, targetPathOptions(config)));
624
+ const target = path8.join(cwd, resolveTargetPath(file.path, config.aliases, targetPathOptions(config)));
569
625
  const exists3 = await pathExists(target);
570
626
  const mark = exists3 ? overwrite ? "~" : "-" : "+";
571
627
  const note = exists3 ? overwrite ? " (\u0628\u0627\u0632\u0646\u0648\u06CC\u0633\u06CC)" : " (\u0631\u062F \u0645\u06CC\u200C\u0634\u0648\u062F\u060C \u0648\u062C\u0648\u062F \u062F\u0627\u0631\u062F)" : "";
572
- console.log(`${mark} ${path7.relative(cwd, target)}${note}`);
628
+ console.log(`${mark} ${path8.relative(cwd, target)}${note}`);
573
629
  }
574
630
  }
575
631
  console.log(`
@@ -592,17 +648,17 @@ ${items.size} \u0622\u06CC\u062A\u0645 \u0627\u0632 \u0631\u062C\u06CC\u0633\u06
592
648
  const writtenFiles = {};
593
649
  const writtenContents = {};
594
650
  for (const file of item.files) {
595
- const target = path7.join(cwd, resolveTargetPath(file.path, config.aliases, targetPathOptions(config)));
651
+ const target = path8.join(cwd, resolveTargetPath(file.path, config.aliases, targetPathOptions(config)));
596
652
  if (!overwrite && await pathExists(target)) {
597
- if (!options.skipExisting) console.log(`- \u0631\u062F \u0634\u062F (\u0648\u062C\u0648\u062F \u062F\u0627\u0631\u062F): ${path7.relative(cwd, target)}`);
653
+ if (!options.skipExisting) console.log(`- \u0631\u062F \u0634\u062F (\u0648\u062C\u0648\u062F \u062F\u0627\u0631\u062F): ${path8.relative(cwd, target)}`);
598
654
  skipped++;
599
655
  continue;
600
656
  }
601
- await mkdir3(path7.dirname(target), { recursive: true });
657
+ await mkdir3(path8.dirname(target), { recursive: true });
602
658
  await writeFile5(target, file.content, "utf8");
603
- console.log(`+ ${path7.relative(cwd, target)}`);
659
+ console.log(`+ ${path8.relative(cwd, target)}`);
604
660
  written++;
605
- const relPath = toPosixPath(path7.relative(cwd, target));
661
+ const relPath = toPosixPath(path8.relative(cwd, target));
606
662
  writtenFiles[relPath] = file.hash ?? hashContent(file.content);
607
663
  writtenContents[relPath] = file.content;
608
664
  }
@@ -625,7 +681,7 @@ ${items.size} \u0622\u06CC\u062A\u0645 \u0627\u0632 \u0631\u062C\u06CC\u0633\u06
625
681
  if (lockChanged) {
626
682
  await writeLock(lock, cwd);
627
683
  console.log(`
628
- \u062B\u0628\u062A \u0634\u062F \u062F\u0631 ${path7.join(".dig", "registry-lock.json")}`);
684
+ \u062B\u0628\u062A \u0634\u062F \u062F\u0631 ${path8.join(".dig", "registry-lock.json")}`);
629
685
  }
630
686
  console.log(`
631
687
  ${written} \u0641\u0627\u06CC\u0644 \u0646\u0648\u0634\u062A\u0647 \u0634\u062F\u060C ${skipped} \u0641\u0627\u06CC\u0644 \u0631\u062F \u0634\u062F.`);
@@ -700,7 +756,7 @@ var TYPE_LABEL = {
700
756
  };
701
757
  async function loadItems(cwd) {
702
758
  const config = await configExists(cwd) ? await readConfig(cwd) : defaultConfig();
703
- const index = await fetchRegistryIndex(config.registryUrl);
759
+ const index = await fetchRegistryIndex(config.registryUrl, config.framework);
704
760
  return index.items;
705
761
  }
706
762
  function matchesType(item, type) {
@@ -752,8 +808,8 @@ async function searchCommand(query, options) {
752
808
  }
753
809
 
754
810
  // src/lib/diff.ts
755
- import { readFile as readFile5 } from "fs/promises";
756
- import path8 from "path";
811
+ import { readFile as readFile6 } from "fs/promises";
812
+ import path9 from "path";
757
813
  var STATUS_PRIORITY = [
758
814
  "conflict",
759
815
  "untracked",
@@ -783,7 +839,7 @@ function overallStatus(files) {
783
839
  }
784
840
  async function readLocalHash(target) {
785
841
  try {
786
- const content = await readFile5(target, "utf8");
842
+ const content = await readFile6(target, "utf8");
787
843
  return hashContent(content);
788
844
  } catch (error) {
789
845
  if (error.code === "ENOENT") return void 0;
@@ -791,8 +847,8 @@ async function readLocalHash(target) {
791
847
  }
792
848
  }
793
849
  async function computeFileDrift(cwd, aliases, lockEntry, file, paths) {
794
- const target = path8.join(cwd, resolveTargetPath(file.path, aliases, paths));
795
- const relPath = toPosixPath(path8.relative(cwd, target));
850
+ const target = path9.join(cwd, resolveTargetPath(file.path, aliases, paths));
851
+ const relPath = toPosixPath(path9.relative(cwd, target));
796
852
  const registryHash = file.hash ?? hashContent(file.content);
797
853
  const installedHash = lockEntry?.files[relPath];
798
854
  const localHash = await readLocalHash(target);
@@ -821,8 +877,8 @@ async function computeComponentDrift(params) {
821
877
  }
822
878
 
823
879
  // src/lib/file-diff-details.ts
824
- import { readFile as readFile6 } from "fs/promises";
825
- import path9 from "path";
880
+ import { readFile as readFile7 } from "fs/promises";
881
+ import path10 from "path";
826
882
 
827
883
  // src/lib/text-diff.ts
828
884
  var DEFAULT_CONTEXT = 3;
@@ -931,7 +987,7 @@ function looksBinary(buffer) {
931
987
  async function readTextFileSafely(target) {
932
988
  let buffer;
933
989
  try {
934
- buffer = await readFile6(target);
990
+ buffer = await readFile7(target);
935
991
  } catch (error) {
936
992
  if (error.code === "ENOENT") return void 0;
937
993
  throw error;
@@ -971,7 +1027,7 @@ async function computeFileDiffDetails(params) {
971
1027
  note: file.registryHash === file.installedHash ? "\u0641\u0627\u06CC\u0644 \u0628\u0647\u200C\u0635\u0648\u0631\u062A \u0645\u062D\u0644\u06CC \u062D\u0630\u0641 \u0634\u062F\u0647\u061B \u0631\u062C\u06CC\u0633\u062A\u0631\u06CC \u0627\u0632 \u0632\u0645\u0627\u0646 \u0646\u0635\u0628 \u062A\u063A\u06CC\u06CC\u0631\u06CC \u0646\u06A9\u0631\u062F\u0647." : "\u0641\u0627\u06CC\u0644 \u0628\u0647\u200C\u0635\u0648\u0631\u062A \u0645\u062D\u0644\u06CC \u062D\u0630\u0641 \u0634\u062F\u0647 \u0648 \u0631\u062C\u06CC\u0633\u062A\u0631\u06CC \u0647\u0645 \u062A\u063A\u06CC\u06CC\u0631 \u06A9\u0631\u062F\u0647 \u2014 \u0645\u0642\u0627\u06CC\u0633\u0647\u200C\u0627\u06CC \u0628\u0627 \u0641\u0627\u06CC\u0644 \u062D\u0630\u0641\u200C\u0634\u062F\u0647 \u0645\u0645\u06A9\u0646 \u0646\u06CC\u0633\u062A."
972
1028
  };
973
1029
  }
974
- const target = path9.join(cwd, resolveTargetPath(registryFile.path, aliases, paths));
1030
+ const target = path10.join(cwd, resolveTargetPath(registryFile.path, aliases, paths));
975
1031
  const localContent = await readTextFileSafely(target);
976
1032
  if (localContent === "binary") {
977
1033
  return {
@@ -1057,7 +1113,7 @@ async function diffCommand(components, options) {
1057
1113
  for (const name of components) {
1058
1114
  let registryItem;
1059
1115
  try {
1060
- registryItem = await fetchRegistryItem(name, config.registryUrl);
1116
+ registryItem = await fetchRegistryItem(name, config.registryUrl, config.framework);
1061
1117
  } catch (error) {
1062
1118
  console.error(`\u2717 ${name}: ${error.message}`);
1063
1119
  continue;
@@ -1528,8 +1584,8 @@ function dependencyRiskLevel(highImpactComponents) {
1528
1584
  }
1529
1585
 
1530
1586
  // src/lib/repo-scanner.ts
1531
- import { readFile as readFile7, readdir } from "fs/promises";
1532
- import path10 from "path";
1587
+ import { readFile as readFile8, readdir } from "fs/promises";
1588
+ import path11 from "path";
1533
1589
  import ts2 from "typescript";
1534
1590
 
1535
1591
  // src/lib/ast-engine.ts
@@ -1604,11 +1660,11 @@ async function collectSourceFiles(root) {
1604
1660
  for (const entry of entries) {
1605
1661
  if (entry.isDirectory()) {
1606
1662
  if (IGNORED_DIRS.has(entry.name) || entry.name.startsWith(".")) continue;
1607
- await walk(path10.join(dir, entry.name));
1663
+ await walk(path11.join(dir, entry.name));
1608
1664
  continue;
1609
1665
  }
1610
- if (entry.isFile() && SCAN_EXTENSIONS.has(path10.extname(entry.name))) {
1611
- results.push(path10.join(dir, entry.name));
1666
+ if (entry.isFile() && SCAN_EXTENSIONS.has(path11.extname(entry.name))) {
1667
+ results.push(path11.join(dir, entry.name));
1612
1668
  }
1613
1669
  }
1614
1670
  }
@@ -1635,7 +1691,7 @@ async function scanRepositoryForComponent(params) {
1635
1691
  for (const filePath of sourceFilePaths) {
1636
1692
  let content;
1637
1693
  try {
1638
- content = await readFile7(filePath, "utf8");
1694
+ content = await readFile8(filePath, "utf8");
1639
1695
  } catch {
1640
1696
  continue;
1641
1697
  }
@@ -1649,7 +1705,7 @@ async function scanRepositoryForComponent(params) {
1649
1705
  const snippets = findJsxUsagesInSource(sourceFile, tagName);
1650
1706
  if (snippets.length === 0) continue;
1651
1707
  files.push({
1652
- path: toPosixPath(path10.relative(projectRoot, filePath)),
1708
+ path: toPosixPath(path11.relative(projectRoot, filePath)),
1653
1709
  usages: snippets.length,
1654
1710
  snippets
1655
1711
  });
@@ -2055,11 +2111,11 @@ async function impactCommand(name, options) {
2055
2111
  }
2056
2112
 
2057
2113
  // src/commands/review.ts
2058
- import { readFile as readFile8 } from "fs/promises";
2059
- import path11 from "path";
2114
+ import { readFile as readFile9 } from "fs/promises";
2115
+ import path12 from "path";
2060
2116
 
2061
2117
  // src/lib/version.ts
2062
- var CLI_VERSION = "0.7.0";
2118
+ var CLI_VERSION = "0.8.0";
2063
2119
 
2064
2120
  // src/commands/mcp.ts
2065
2121
  import { createInterface as createInterface2 } from "readline";
@@ -2155,15 +2211,15 @@ var MAX_FILES_PER_CALL = 25;
2155
2211
  async function readReviewFiles(paths, cwd) {
2156
2212
  const files = [];
2157
2213
  for (const input of paths) {
2158
- const absolute = path11.resolve(cwd, input);
2214
+ const absolute = path12.resolve(cwd, input);
2159
2215
  let code;
2160
2216
  try {
2161
- code = await readFile8(absolute, "utf8");
2217
+ code = await readFile9(absolute, "utf8");
2162
2218
  } catch {
2163
2219
  throw new DigError(`\u0641\u0627\u06CC\u0644 \u062E\u0648\u0627\u0646\u062F\u0647 \u0646\u0634\u062F: ${input}`);
2164
2220
  }
2165
2221
  if (code.length > MAX_FILE_CHARS) throw new DigError(`${input} \u0628\u0632\u0631\u06AF\u200C\u062A\u0631 \u0627\u0632 ${MAX_FILE_CHARS} \u0646\u0648\u06CC\u0633\u0647 \u0627\u0633\u062A\u061B \u0628\u0647 \u0641\u0627\u06CC\u0644\u200C\u0647\u0627\u06CC \u06A9\u0648\u0686\u06A9\u200C\u062A\u0631 \u0628\u0634\u06A9\u0646.`);
2166
- files.push({ path: path11.relative(cwd, absolute) || input, code });
2222
+ files.push({ path: path12.relative(cwd, absolute) || input, code });
2167
2223
  }
2168
2224
  return files;
2169
2225
  }
@@ -2225,7 +2281,7 @@ async function reviewCommand(paths, options) {
2225
2281
 
2226
2282
  // src/commands/skill.ts
2227
2283
  import { mkdir as mkdir4, writeFile as writeFile6 } from "fs/promises";
2228
- import path12 from "path";
2284
+ import path13 from "path";
2229
2285
  var SKILL_PATH = ".claude/skills/dig-design-system/SKILL.md";
2230
2286
  async function skillCommand() {
2231
2287
  const cwd = process.cwd();
@@ -2238,21 +2294,21 @@ async function skillCommand() {
2238
2294
  throw new DigError(`\u0627\u062A\u0635\u0627\u0644 \u0628\u0647 ${url.origin} \u0628\u0631\u0627\u06CC \u06AF\u0631\u0641\u062A\u0646\u0650 Skill \u0628\u0631\u0642\u0631\u0627\u0631 \u0646\u0634\u062F.`);
2239
2295
  }
2240
2296
  if (!response.ok) throw new DigError(`Skill \u06AF\u0631\u0641\u062A\u0647 \u0646\u0634\u062F: ${response.status}`);
2241
- const target = path12.join(cwd, SKILL_PATH);
2242
- await mkdir4(path12.dirname(target), { recursive: true });
2297
+ const target = path13.join(cwd, SKILL_PATH);
2298
+ await mkdir4(path13.dirname(target), { recursive: true });
2243
2299
  await writeFile6(target, await response.text(), "utf8");
2244
2300
  console.log(`\u2713 ${SKILL_PATH} \u0646\u0648\u0634\u062A\u0647 \u0634\u062F (Skill\u0650 \u0631\u0633\u0645\u06CC\u0650 \u062F\u06CC\u06AF \u0628\u0631\u0627\u06CC Claude Code).`);
2245
2301
  }
2246
2302
 
2247
2303
  // src/commands/tokens.ts
2248
- import { mkdir as mkdir5, readFile as readFile9, writeFile as writeFile7 } from "fs/promises";
2249
- import path13 from "path";
2304
+ import { mkdir as mkdir5, readFile as readFile10, writeFile as writeFile7 } from "fs/promises";
2305
+ import path14 from "path";
2250
2306
  async function tokensCommand(options) {
2251
2307
  const cwd = process.cwd();
2252
2308
  const registryUrl = await configExists(cwd) ? (await readConfig(cwd)).registryUrl : defaultConfig().registryUrl;
2253
- const designMd = await readFile9(path13.join(cwd, DESIGN_MD_FILE), "utf8").catch(() => "");
2309
+ const designMd = await readFile10(path14.join(cwd, DESIGN_MD_FILE), "utf8").catch(() => "");
2254
2310
  const brand = options.brand ?? readDesignMdSettings(designMd).brand;
2255
- const outDir = path13.join(cwd, options.out ?? "tokens");
2311
+ const outDir = path14.join(cwd, options.out ?? "tokens");
2256
2312
  await mkdir5(outDir, { recursive: true });
2257
2313
  for (const mode of ["light", "dark"]) {
2258
2314
  const url = new URL("/api/tokens", registryUrl);
@@ -2268,20 +2324,20 @@ async function tokensCommand(options) {
2268
2324
  const body = await response.json().catch(() => null);
2269
2325
  throw new DigError(`\u062A\u0648\u06A9\u0646\u200C\u0647\u0627 \u06AF\u0631\u0641\u062A\u0647 \u0646\u0634\u062F: ${body?.error ?? response.status}`);
2270
2326
  }
2271
- const file = path13.join(outDir, `dig-${mode}.tokens.json`);
2327
+ const file = path14.join(outDir, `dig-${mode}.tokens.json`);
2272
2328
  await writeFile7(file, await response.text(), "utf8");
2273
- console.log(`\u2713 ${path13.relative(cwd, file)} \u0646\u0648\u0634\u062A\u0647 \u0634\u062F${brand ? ` (\u0628\u0631\u0646\u062F ${brand})` : ""}.`);
2329
+ console.log(`\u2713 ${path14.relative(cwd, file)} \u0646\u0648\u0634\u062A\u0647 \u0634\u062F${brand ? ` (\u0628\u0631\u0646\u062F ${brand})` : ""}.`);
2274
2330
  }
2275
2331
  console.log("\n\u062F\u0631 \u0641\u06CC\u06AF\u0645\u0627 \u0647\u0631 \u0641\u0627\u06CC\u0644 \u0631\u0627 \u06CC\u06A9 mode \u0627\u0632 Variables \u0648\u0627\u0631\u062F \u06A9\u0646\u06CC\u062F (\u0631\u0648\u0634\u0646 \u0648 \u062A\u06CC\u0631\u0647).");
2276
2332
  }
2277
2333
 
2278
2334
  // src/commands/init.ts
2279
- import { readFile as readFile12, writeFile as writeFile10 } from "fs/promises";
2280
- import path17 from "path";
2335
+ import { readFile as readFile13, writeFile as writeFile11 } from "fs/promises";
2336
+ import path19 from "path";
2281
2337
 
2282
2338
  // src/lib/agent-instructions.ts
2283
- import { mkdir as mkdir6, readFile as readFile10, writeFile as writeFile8 } from "fs/promises";
2284
- import path14 from "path";
2339
+ import { mkdir as mkdir6, readFile as readFile11, writeFile as writeFile8 } from "fs/promises";
2340
+ import path15 from "path";
2285
2341
  var AGENT_CLIENTS = [
2286
2342
  { value: "claude-code", label: "Claude Code (CLAUDE.md)" },
2287
2343
  { value: "codex", label: "Codex (AGENTS.md)" },
@@ -2333,25 +2389,94 @@ async function writeAgentInstructions(cwd, registryUrl, options) {
2333
2389
  const files = await fetchSetupFiles(registryUrl, options);
2334
2390
  const instructions = files.find((item) => /^[A-Z]+\.md$/.test(item.path) && item.path !== "DESIGN.md");
2335
2391
  if (!instructions) throw new DigError("\u0641\u0627\u06CC\u0644\u0650 \u0627\u06CC\u062C\u0646\u062A \u062F\u0631 \u067E\u0627\u0633\u062E\u0650 \u0633\u0631\u0648\u0631 \u0646\u0628\u0648\u062F.");
2336
- const target = path14.join(cwd, instructions.path);
2337
- const existing = await readFile10(target, "utf8").catch(() => null);
2392
+ const target = path15.join(cwd, instructions.path);
2393
+ const existing = await readFile11(target, "utf8").catch(() => null);
2338
2394
  await writeFile8(target, mergeInstructions(existing, instructions.content), "utf8");
2339
2395
  console.log(
2340
2396
  existing === null ? `\u2713 ${instructions.path} \u0646\u0648\u0634\u062A\u0647 \u0634\u062F (\u0627\u06CC\u062C\u0646\u062A \u0641\u0648\u0646\u062A \u0648 \u0631\u0646\u06AF \u0631\u0627 \u0627\u0632 \u0627\u06CC\u0646 \u0641\u0627\u06CC\u0644 \u0645\u06CC\u200C\u062E\u0648\u0627\u0646\u062F \u0648 \u062F\u0648\u0628\u0627\u0631\u0647 \u0646\u0645\u06CC\u200C\u067E\u0631\u0633\u062F).` : `\u2713 \u0628\u062E\u0634\u0650 \u062F\u06CC\u06AF \u062F\u0631 ${instructions.path} \u0628\u0647\u200C\u0631\u0648\u0632 \u0634\u062F\u061B \u0628\u0642\u06CC\u0647\u0654 \u0641\u0627\u06CC\u0644 \u062F\u0633\u062A \u0646\u062E\u0648\u0631\u062F.`
2341
2397
  );
2342
2398
  const skill = files.find((item) => item.path.endsWith("/SKILL.md"));
2343
2399
  if (skill) {
2344
- const skillTarget = path14.join(cwd, skill.path);
2345
- await mkdir6(path14.dirname(skillTarget), { recursive: true });
2400
+ const skillTarget = path15.join(cwd, skill.path);
2401
+ await mkdir6(path15.dirname(skillTarget), { recursive: true });
2346
2402
  await writeFile8(skillTarget, skill.content, "utf8");
2347
2403
  console.log(`\u2713 ${skill.path} \u0646\u0648\u0634\u062A\u0647 \u0634\u062F (Skill\u0650 \u0631\u0633\u0645\u06CC\u0650 \u062F\u06CC\u06AF \u0628\u0631\u0627\u06CC \u0633\u0627\u062E\u062A\u0646\u0650 \u0635\u0641\u062D\u0647).`);
2348
2404
  }
2349
2405
  return instructions.path;
2350
2406
  }
2351
2407
 
2352
- // src/commands/theme.ts
2353
- import { access as access5, mkdir as mkdir7, readFile as readFile11, writeFile as writeFile9 } from "fs/promises";
2408
+ // src/lib/fonts.ts
2409
+ import { mkdir as mkdir7, writeFile as writeFile9 } from "fs/promises";
2354
2410
  import path16 from "path";
2411
+ var WEIGHTS = [
2412
+ ["Thin", 100],
2413
+ ["UltraLight", 200],
2414
+ ["Light", 300],
2415
+ ["Regular", 400],
2416
+ ["Medium", 500],
2417
+ ["DemiBold", 600],
2418
+ ["Bold", 700],
2419
+ ["ExtraBold", 800],
2420
+ ["Black", 900]
2421
+ ];
2422
+ var YEKAN_WEIGHTS = [
2423
+ ["Thin", 100],
2424
+ ["Light", 300],
2425
+ ["Regular", 400],
2426
+ ["Medium", 500],
2427
+ ["Bold", 700],
2428
+ ["ExtraBold", 800],
2429
+ ["Black", 900]
2430
+ ];
2431
+ var VAZIR_URL = "https://cdn.jsdelivr.net/npm/@fontsource-variable/vazirmatn/files/vazirmatn-arabic-wght-normal.woff2";
2432
+ function fontPlan(font) {
2433
+ if (font === "yekan") {
2434
+ return { family: "IRANYekanFN", files: YEKAN_WEIGHTS.map(([n, weight]) => ({ file: `IRANYekan${n}.woff2`, weight })) };
2435
+ }
2436
+ if (font === "vazirmatn") return { family: "Vazirmatn", remote: VAZIR_URL };
2437
+ return { family: "IRANSansX", files: WEIGHTS.map(([n, weight]) => ({ file: `IRANSansXFaNum-${n}.woff2`, weight })) };
2438
+ }
2439
+ function fontFaceCss(font) {
2440
+ const plan = fontPlan(font);
2441
+ const header = "/* \u0641\u0648\u0646\u062A\u0650 \u0641\u0627\u0631\u0633\u06CC\u0650 \u067E\u0631\u0648\u0698\u0647\u061B \u0628\u0627 \xABdig init --font \u2026\xBB \u0633\u0627\u062E\u062A\u0647 \u0634\u062F. \u0644\u0646\u06AF\u0631 \u062F\u0631 brand.css \u06CC\u0627 dig-theme.css \u0627\u0633\u062A. */\n";
2442
+ if ("remote" in plan) {
2443
+ return `${header}@font-face {
2444
+ font-family: "${plan.family}";
2445
+ src: url("${plan.remote}") format("woff2");
2446
+ font-weight: 100 900;
2447
+ font-display: swap;
2448
+ }
2449
+ `;
2450
+ }
2451
+ return header + plan.files.map(
2452
+ ({ file, weight }) => `@font-face {
2453
+ font-family: "${plan.family}";
2454
+ src: url("/fonts/${file}") format("woff2");
2455
+ font-weight: ${weight};
2456
+ font-display: swap;
2457
+ }
2458
+ `
2459
+ ).join("");
2460
+ }
2461
+ async function installFonts(cwd, registryUrl, font, cssRel) {
2462
+ const plan = fontPlan(font);
2463
+ if ("files" in plan) {
2464
+ const dir = path16.join(cwd, "public", "fonts");
2465
+ await mkdir7(dir, { recursive: true });
2466
+ for (const { file } of plan.files) {
2467
+ const res = await fetch(new URL(`/fonts/${file}`, registryUrl));
2468
+ if (!res.ok) return false;
2469
+ await writeFile9(path16.join(dir, file), Buffer.from(await res.arrayBuffer()));
2470
+ }
2471
+ }
2472
+ const target = path16.join(cwd, cssRel);
2473
+ await mkdir7(path16.dirname(target), { recursive: true });
2474
+ await writeFile9(target, fontFaceCss(font), "utf8");
2475
+ return true;
2476
+ }
2477
+
2478
+ // src/lib/theme-files.ts
2479
+ import path17 from "path";
2355
2480
 
2356
2481
  // src/lib/brand-ramp.ts
2357
2482
  var RAMP_STEPS = [50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950];
@@ -2455,9 +2580,8 @@ function buildBrandRamp(hex) {
2455
2580
  }
2456
2581
 
2457
2582
  // src/lib/theme-files.ts
2458
- import path15 from "path";
2459
2583
  function importPath(fromFile, toFile) {
2460
- const rel = toPosixPath(path15.relative(path15.dirname(fromFile), toFile));
2584
+ const rel = toPosixPath(path17.relative(path17.dirname(fromFile), toFile));
2461
2585
  return rel.startsWith(".") ? rel : `./${rel}`;
2462
2586
  }
2463
2587
  function globalsCss(paths, extraStatements = []) {
@@ -2619,10 +2743,12 @@ function splitTheme(projectCss, digThemeCss) {
2619
2743
  }
2620
2744
 
2621
2745
  // src/commands/theme.ts
2746
+ import { access as access5, mkdir as mkdir8, readFile as readFile12, writeFile as writeFile10 } from "fs/promises";
2747
+ import path18 from "path";
2622
2748
  var THEME_ITEM = "theme";
2623
2749
  async function readIfExists2(target) {
2624
2750
  try {
2625
- return await readFile11(target, "utf8");
2751
+ return await readFile12(target, "utf8");
2626
2752
  } catch {
2627
2753
  return null;
2628
2754
  }
@@ -2636,7 +2762,7 @@ async function exists(target) {
2636
2762
  }
2637
2763
  }
2638
2764
  function themePaths(config) {
2639
- const dir = path16.posix.dirname(toPosixPath(config.tailwind.css));
2765
+ const dir = path18.posix.dirname(toPosixPath(config.tailwind.css));
2640
2766
  return {
2641
2767
  css: config.tailwind.css,
2642
2768
  theme: config.tailwind.theme ?? `${dir}/dig-theme.css`,
@@ -2670,9 +2796,9 @@ async function recordTheme(cwd, config, themeRel, item) {
2670
2796
  await writeLock(lock, cwd);
2671
2797
  }
2672
2798
  async function writeText(cwd, rel, content) {
2673
- const target = path16.join(cwd, rel);
2674
- await mkdir7(path16.dirname(target), { recursive: true });
2675
- await writeFile9(target, content, "utf8");
2799
+ const target = path18.join(cwd, rel);
2800
+ await mkdir8(path18.dirname(target), { recursive: true });
2801
+ await writeFile10(target, content, "utf8");
2676
2802
  }
2677
2803
  async function installTheme(cwd, config, options) {
2678
2804
  const paths = themePaths(config);
@@ -2680,7 +2806,7 @@ async function installTheme(cwd, config, options) {
2680
2806
  const ramp = options.brand ? buildBrandRamp(options.brand) : void 0;
2681
2807
  await writeText(cwd, paths.theme, item.content);
2682
2808
  console.log(`\u2713 \u062A\u0645\u0650 \u062F\u06CC\u06AF \u062F\u0631 ${paths.theme} \u0646\u0648\u0634\u062A\u0647 \u0634\u062F (\u0645\u0627\u0644\u0650 \u062F\u06CC\u06AF\u061B \u0628\u0627 \xABdig update theme\xBB \u0628\u0647\u200C\u0631\u0648\u0632 \u0645\u06CC\u200C\u0634\u0648\u062F).`);
2683
- const existingBrand = await readIfExists2(path16.join(cwd, paths.brand));
2809
+ const existingBrand = await readIfExists2(path18.join(cwd, paths.brand));
2684
2810
  if (existingBrand === null) {
2685
2811
  await writeText(cwd, paths.brand, brandCss({ ramp, hex: options.brand }));
2686
2812
  console.log(`\u2713 ${paths.brand} \u0633\u0627\u062E\u062A\u0647 \u0634\u062F (\u0645\u0627\u0644\u0650 \u067E\u0631\u0648\u0698\u0647\u061B \u062F\u06CC\u06AF \u0647\u0631\u06AF\u0632 \u0628\u0627\u0632\u0646\u0648\u06CC\u0633\u06CC\u200C\u0627\u0634 \u0646\u0645\u06CC\u200C\u06A9\u0646\u062F).`);
@@ -2691,10 +2817,10 @@ async function installTheme(cwd, config, options) {
2691
2817
  console.log(`- ${paths.brand} \u0627\u0632 \u0642\u0628\u0644 \u0647\u0633\u062A\u061B \u062F\u0633\u062A \u0646\u062E\u0648\u0631\u062F.`);
2692
2818
  }
2693
2819
  if (ramp) reportContrast(ramp.primaryContrast);
2694
- const cssTarget = path16.join(cwd, paths.css);
2820
+ const cssTarget = path18.join(cwd, paths.css);
2695
2821
  const existingCss = await readIfExists2(cssTarget);
2696
2822
  if (!isBoilerplateCss(existingCss) && existingCss !== null) {
2697
- await writeFile9(`${cssTarget}.backup`, existingCss, "utf8");
2823
+ await writeFile10(`${cssTarget}.backup`, existingCss, "utf8");
2698
2824
  console.log(` \u0646\u0633\u062E\u0647\u0654 \u0642\u0628\u0644\u06CC\u0650 ${paths.css} \u062F\u0631 ${paths.css}.backup \u0646\u06AF\u0647 \u062F\u0627\u0634\u062A\u0647 \u0634\u062F.`);
2699
2825
  console.log(` \u0627\u06AF\u0631 \u0622\u0646 \u0641\u0627\u06CC\u0644 \u062A\u0645\u0650 \u0642\u062F\u06CC\u0645\u06CC\u0650 \u062F\u06CC\u06AF \u0628\u0648\u062F\u060C \u0628\u0647\u200C\u062C\u0627\u06CC init \u0627\u0632 \xABdig theme split\xBB \u0627\u0633\u062A\u0641\u0627\u062F\u0647 \u06A9\u0646\u06CC\u062F.`);
2700
2826
  }
@@ -2727,11 +2853,11 @@ async function themeSplitCommand(options) {
2727
2853
  return;
2728
2854
  }
2729
2855
  const paths = themePaths(config);
2730
- const current = await readIfExists2(path16.join(cwd, paths.css));
2856
+ const current = await readIfExists2(path18.join(cwd, paths.css));
2731
2857
  if (current === null || isBoilerplateCss(current)) {
2732
2858
  throw new DigError(`${paths.css} \u062A\u0645\u06CC \u0646\u062F\u0627\u0631\u062F\u061B \u0628\u0631\u0627\u06CC \u0646\u0635\u0628\u0650 \u062A\u0627\u0632\u0647 \xABdig init\xBB \u0631\u0627 \u0627\u062C\u0631\u0627 \u06A9\u0646\u06CC\u062F.`);
2733
2859
  }
2734
- if (await exists(path16.join(cwd, paths.brand))) {
2860
+ if (await exists(path18.join(cwd, paths.brand))) {
2735
2861
  throw new DigError(`${paths.brand} \u0627\u0632 \u0642\u0628\u0644 \u0648\u062C\u0648\u062F \u062F\u0627\u0631\u062F\u061B \u0628\u0631\u0627\u06CC \u062C\u0644\u0648\u06AF\u06CC\u0631\u06CC \u0627\u0632 \u0628\u0627\u0632\u0646\u0648\u06CC\u0633\u06CC\u060C \u0627\u0648\u0644 \u062C\u0627\u0628\u0647\u200C\u062C\u0627\u06CC\u0634 \u06A9\u0646\u06CC\u062F.`);
2736
2862
  }
2737
2863
  console.log(`\u062F\u0631\u06CC\u0627\u0641\u062A\u0650 \u062A\u0645\u0650 \u062F\u06CC\u06AF \u0627\u0632 ${config.registryUrl} \u2026`);
@@ -2750,7 +2876,7 @@ ${split.changed} \u062A\u0648\u06A9\u0646\u0650 \u0639\u0648\u0636\u200C\u0634\u
2750
2876
  console.log(split.body || "(\u062E\u0627\u0644\u06CC: \u067E\u0631\u0648\u0698\u0647 \u0686\u06CC\u0632\u06CC \u062F\u0631 \u062A\u0645 \u0639\u0648\u0636 \u0646\u06A9\u0631\u062F\u0647)");
2751
2877
  return;
2752
2878
  }
2753
- await writeFile9(path16.join(cwd, `${paths.css}.backup`), current, "utf8");
2879
+ await writeFile10(path18.join(cwd, `${paths.css}.backup`), current, "utf8");
2754
2880
  await writeText(cwd, paths.theme, item.content);
2755
2881
  await writeText(cwd, paths.brand, brandCss({ body: split.body }));
2756
2882
  await writeText(cwd, paths.css, globalsCss(paths, split.extraStatements));
@@ -2774,7 +2900,7 @@ async function themeBrandCommand(hex) {
2774
2900
  }
2775
2901
  const paths = themePaths(config);
2776
2902
  const ramp = buildBrandRamp(hex);
2777
- const existing = await readIfExists2(path16.join(cwd, paths.brand)) ?? brandCss({});
2903
+ const existing = await readIfExists2(path18.join(cwd, paths.brand)) ?? brandCss({});
2778
2904
  const next = replaceBrandRamp(existing, ramp, hex);
2779
2905
  await writeText(cwd, paths.brand, next);
2780
2906
  console.log(`\u2713 \u0631\u0645\u067E\u0650 \u0628\u0631\u0646\u062F \u062F\u0631 ${paths.brand} \u0627\u0632 ${hex} \u0633\u0627\u062E\u062A\u0647 \u0634\u062F (Shade \u06F6\u06F0\u06F0 = \u0631\u0646\u06AF\u0650 \u062F\u0627\u062F\u0647\u200C\u0634\u062F\u0647).`);
@@ -2792,14 +2918,14 @@ async function themeBrandCommand(hex) {
2792
2918
  // src/commands/init.ts
2793
2919
  async function readIfExists3(target) {
2794
2920
  try {
2795
- return await readFile12(target, "utf8");
2921
+ return await readFile13(target, "utf8");
2796
2922
  } catch {
2797
2923
  return null;
2798
2924
  }
2799
2925
  }
2800
2926
  async function writeTheme(config, cwd, options) {
2801
2927
  const paths = themePaths(config);
2802
- const existing = await readIfExists3(path17.join(cwd, paths.css));
2928
+ const existing = await readIfExists3(path19.join(cwd, paths.css));
2803
2929
  if (!isBoilerplateCss(existing) && !options.yes) {
2804
2930
  console.log(`
2805
2931
  ${paths.css} \u0627\u0632 \u0642\u0628\u0644 \u0645\u062D\u062A\u0648\u0627 \u062F\u0627\u0631\u062F.`);
@@ -2820,11 +2946,37 @@ ${paths.css} \u0627\u0632 \u0642\u0628\u0644 \u0645\u062D\u062A\u0648\u0627 \u06
2820
2946
  \u0646\u0635\u0628 \u0648\u0627\u0628\u0633\u062A\u06AF\u06CC\u200C\u0647\u0627\u06CC \u062A\u0645 \u0628\u0627 ${pm} \u2026`);
2821
2947
  await installDependencies(pm, item.dependencies, { cwd });
2822
2948
  }
2949
+ await writeFonts(cwd, config, paths, options.font);
2823
2950
  return "written";
2824
2951
  }
2952
+ async function writeFonts(cwd, config, paths, font) {
2953
+ const fontsCss = `${path19.posix.dirname(paths.css.split(path19.sep).join("/"))}/dig-fonts.css`;
2954
+ const ok = await installFonts(cwd, config.registryUrl, font, fontsCss).catch(() => false);
2955
+ if (!ok) {
2956
+ console.log("- \u0641\u0627\u06CC\u0644\u200C\u0647\u0627\u06CC \u0641\u0648\u0646\u062A \u062F\u0627\u0646\u0644\u0648\u062F \u0646\u0634\u062F\u061B \u0628\u0639\u062F\u0627\u064B \xABdig init\xBB \u0631\u0627 \u062F\u0648\u0628\u0627\u0631\u0647 \u0627\u062C\u0631\u0627 \u06A9\u0646\u06CC\u062F (\u062A\u0627 \u0622\u0646 \u0645\u0648\u0642\u0639 \u0641\u0648\u0646\u062A\u0650 \u0633\u06CC\u0633\u062A\u0645 \u0645\u06CC\u200C\u0646\u0634\u06CC\u0646\u062F).");
2957
+ return;
2958
+ }
2959
+ const fontStatement = `@import "${importPath(paths.css, fontsCss)}";`;
2960
+ await writeFile11(path19.join(cwd, paths.css), globalsCss(paths, [fontStatement]), "utf8");
2961
+ console.log(`\u2713 \u0641\u0648\u0646\u062A\u0650 ${fontPlan(font).family} \u062F\u0631 ${fontsCss} \u0648 public/fonts \u0646\u0635\u0628 \u0634\u062F.`);
2962
+ if (font && font !== "iransans") {
2963
+ const brandPath = path19.join(cwd, paths.brand);
2964
+ const brand = await readIfExists3(brandPath) ?? "";
2965
+ await writeFile11(
2966
+ brandPath,
2967
+ `${brand.trimEnd()}
2968
+
2969
+ :root {
2970
+ --font-anchor: "${fontPlan(font).family}";
2971
+ }
2972
+ `,
2973
+ "utf8"
2974
+ );
2975
+ }
2976
+ }
2825
2977
  async function applyRtl(cwd) {
2826
2978
  for (const candidate of ["src/app/layout.tsx", "app/layout.tsx"]) {
2827
- const target = path17.join(cwd, candidate);
2979
+ const target = path19.join(cwd, candidate);
2828
2980
  const source = await readIfExists3(target);
2829
2981
  if (source === null) continue;
2830
2982
  if (/<html[^>]*\sdir=/.test(source)) {
@@ -2837,7 +2989,7 @@ async function applyRtl(cwd) {
2837
2989
  match[0],
2838
2990
  `<html${match[1]} dir="rtl">`.replace(/\s+dir="rtl">$/, ' dir="rtl">')
2839
2991
  );
2840
- await writeFile10(target, updated, "utf8");
2992
+ await writeFile11(target, updated, "utf8");
2841
2993
  console.log(`\u2713 dir="rtl" \u0628\u0647 ${candidate} \u0627\u0636\u0627\u0641\u0647 \u0634\u062F.`);
2842
2994
  return;
2843
2995
  }
@@ -2856,7 +3008,14 @@ async function askProjectDecisions(options) {
2856
3008
  }
2857
3009
  async function initCommand(options) {
2858
3010
  const cwd = process.cwd();
3011
+ const framework = await resolveFramework(cwd, void 0, options.framework);
2859
3012
  const base = defaultConfig();
3013
+ if (framework === "vue") {
3014
+ const css = await readIfExists3(path19.join(cwd, "src/assets/main.css")) !== null ? "src/assets/main.css" : "src/style.css";
3015
+ const dir = path19.posix.dirname(css);
3016
+ base.framework = "vue";
3017
+ base.tailwind = { ...base.tailwind, css, theme: `${dir}/dig-theme.css`, brand: `${dir}/brand.css` };
3018
+ }
2860
3019
  if (await configExists(cwd)) {
2861
3020
  const overwrite = options.yes || await confirm("dig.json \u0627\u0632 \u0642\u0628\u0644 \u0648\u062C\u0648\u062F \u062F\u0627\u0631\u062F. \u0628\u0627\u0632\u0646\u0648\u06CC\u0633\u06CC \u0634\u0648\u062F\u061F", false);
2862
3021
  if (!overwrite) {
@@ -2869,16 +3028,18 @@ async function initCommand(options) {
2869
3028
  rtl: await confirm("\u067E\u0631\u0648\u0698\u0647 \u0631\u0627\u0633\u062A\u200C\u0628\u0647\u200C\u0686\u067E (RTL) \u0627\u0633\u062A\u061F", base.rtl),
2870
3029
  tailwind: await (async () => {
2871
3030
  const css = await ask("\u0645\u0633\u06CC\u0631 \u0641\u0627\u06CC\u0644 CSS \u0627\u0635\u0644\u06CC \u062A\u06CC\u0644\u0648\u06CC\u0646\u062F\u061F", base.tailwind.css);
2872
- const dir = path17.posix.dirname(css.split(path17.sep).join("/"));
3031
+ const dir = path19.posix.dirname(css.split(path19.sep).join("/"));
2873
3032
  return { ...base.tailwind, css, theme: `${dir}/dig-theme.css`, brand: `${dir}/brand.css` };
2874
3033
  })()
2875
3034
  };
2876
3035
  const decisions = await askProjectDecisions(options);
2877
3036
  options = { ...options, brand: decisions.brand };
2878
3037
  await writeConfig(config, cwd);
2879
- console.log(`\u2713 ${path17.join(cwd, "dig.json")} \u0646\u0648\u0634\u062A\u0647 \u0634\u062F.`);
2880
- const theme2 = await writeTheme(config, cwd, options);
2881
- if (config.rtl) {
3038
+ console.log(`\u2713 ${path19.join(cwd, "dig.json")} \u0646\u0648\u0634\u062A\u0647 \u0634\u062F.`);
3039
+ const theme2 = await writeTheme(config, cwd, { ...options, font: decisions.font });
3040
+ if (config.rtl && framework === "vue") {
3041
+ console.log('- dir="rtl" \u0631\u0627 \u062E\u0648\u062F\u062A\u0627\u0646 \u0631\u0648\u06CC \u062A\u06AF <html> \u062F\u0631 index.html \u0628\u06AF\u0630\u0627\u0631\u06CC\u062F (Vue \u0686\u06CC\u062F\u0645\u0627\u0646\u0650 \u0631\u06CC\u0634\u0647\u200C\u0627\u06CC \u0646\u062F\u0627\u0631\u062F \u06A9\u0647 \u062E\u0648\u062F\u06A9\u0627\u0631 \u062F\u0633\u062A \u0628\u062E\u0648\u0631\u062F).');
3042
+ } else if (config.rtl) {
2882
3043
  await applyRtl(cwd);
2883
3044
  }
2884
3045
  await writeDesignMd(cwd, config.registryUrl, { brand: decisions.brand, font: decisions.font }).catch((error) => {
@@ -2901,8 +3062,8 @@ async function initCommand(options) {
2901
3062
  }
2902
3063
 
2903
3064
  // src/lib/migration-apply.ts
2904
- import { readFile as readFile13, writeFile as writeFile11 } from "fs/promises";
2905
- import path18 from "path";
3065
+ import { readFile as readFile14, writeFile as writeFile12 } from "fs/promises";
3066
+ import path20 from "path";
2906
3067
 
2907
3068
  // src/lib/migration-strategy.ts
2908
3069
  var TextReplaceStrategy = class {
@@ -2979,7 +3140,7 @@ function looksBinary2(buffer) {
2979
3140
  async function readTextFileSafely2(target) {
2980
3141
  let buffer;
2981
3142
  try {
2982
- buffer = await readFile13(target);
3143
+ buffer = await readFile14(target);
2983
3144
  } catch (error) {
2984
3145
  if (error.code === "ENOENT") return void 0;
2985
3146
  throw error;
@@ -3024,8 +3185,8 @@ async function planOrApplyMigrations(params) {
3024
3185
  };
3025
3186
  }
3026
3187
  const fileTargets = registryItem.files.map((file) => {
3027
- const target = path18.join(cwd, resolveTargetPath(file.path, aliases, paths));
3028
- return { relPath: toPosixPath(path18.relative(cwd, target)), target };
3188
+ const target = path20.join(cwd, resolveTargetPath(file.path, aliases, paths));
3189
+ return { relPath: toPosixPath(path20.relative(cwd, target)), target };
3029
3190
  });
3030
3191
  const currentContents = /* @__PURE__ */ new Map();
3031
3192
  for (const ft of fileTargets) {
@@ -3091,12 +3252,12 @@ async function planOrApplyMigrations(params) {
3091
3252
  const written = [];
3092
3253
  try {
3093
3254
  for (const item of pending) {
3094
- await writeFile11(item.target, item.newContent, "utf8");
3255
+ await writeFile12(item.target, item.newContent, "utf8");
3095
3256
  written.push(item);
3096
3257
  }
3097
3258
  } catch (error) {
3098
3259
  for (const item of written) {
3099
- await writeFile11(item.target, item.originalContent, "utf8");
3260
+ await writeFile12(item.target, item.originalContent, "utf8");
3100
3261
  }
3101
3262
  return {
3102
3263
  name,
@@ -3154,7 +3315,7 @@ async function runPlan(components, options) {
3154
3315
  continue;
3155
3316
  }
3156
3317
  try {
3157
- const item = await fetchRegistryItem(name, config.registryUrl);
3318
+ const item = await fetchRegistryItem(name, config.registryUrl, config.framework);
3158
3319
  const toVersion = item.version ?? "0.0.0";
3159
3320
  const migrations = getApplicableMigrations(
3160
3321
  parseMigrations(name, item.migrations),
@@ -3225,7 +3386,7 @@ async function runApplyOrDryRun(components, options, dryRun) {
3225
3386
  for (const name of components) {
3226
3387
  let registryItem;
3227
3388
  try {
3228
- registryItem = await fetchRegistryItem(name, config.registryUrl);
3389
+ registryItem = await fetchRegistryItem(name, config.registryUrl, config.framework);
3229
3390
  } catch (error) {
3230
3391
  console.error(`\u2717 ${name}: ${error.message}`);
3231
3392
  continue;
@@ -3420,7 +3581,7 @@ ${message}`);
3420
3581
  }
3421
3582
  let item;
3422
3583
  try {
3423
- item = await fetchRegistryItem(component, config.registryUrl);
3584
+ item = await fetchRegistryItem(component, config.registryUrl, config.framework);
3424
3585
  } catch (error) {
3425
3586
  console.error(`\u2717 ${component}: ${error.message}`);
3426
3587
  return;
@@ -3508,7 +3669,7 @@ async function releaseCommand(components, options) {
3508
3669
  const entries = [];
3509
3670
  for (const name of components) {
3510
3671
  try {
3511
- const item = await fetchRegistryItem(name, config.registryUrl);
3672
+ const item = await fetchRegistryItem(name, config.registryUrl, config.framework);
3512
3673
  const version = item.version ?? "0.0.0";
3513
3674
  entries.push({
3514
3675
  name,
@@ -3615,7 +3776,7 @@ async function statusCommand(components, options) {
3615
3776
  const entries = [];
3616
3777
  for (const name of components) {
3617
3778
  try {
3618
- const item = await fetchRegistryItem(name, config.registryUrl);
3779
+ const item = await fetchRegistryItem(name, config.registryUrl, config.framework);
3619
3780
  const version = item.version ?? "0.0.0";
3620
3781
  const lifecycle = parseLifecycle(name, version, item.deprecation);
3621
3782
  const release = parseRelease(name, version, item.release);
@@ -3709,7 +3870,7 @@ ${entry.migrationHint}`);
3709
3870
 
3710
3871
  // src/lib/missing-dependencies.ts
3711
3872
  import { access as access6 } from "fs/promises";
3712
- import path19 from "path";
3873
+ import path21 from "path";
3713
3874
  async function exists2(target) {
3714
3875
  try {
3715
3876
  await access6(target);
@@ -3725,12 +3886,12 @@ async function findMissingDependencies(params) {
3725
3886
  ...new Set(items.flatMap((item) => item.registryDependencies ?? []))
3726
3887
  ].filter((name) => !requested.has(name));
3727
3888
  if (direct.length === 0) return [];
3728
- const tree = await resolveRegistryTree(direct, config.registryUrl);
3889
+ const tree = await resolveRegistryTree(direct, config.registryUrl, config.framework);
3729
3890
  const missing = [];
3730
3891
  for (const item of tree.values()) {
3731
3892
  if (requested.has(item.name) || lock.components[item.name]) continue;
3732
3893
  for (const file of item.files) {
3733
- const target = path19.join(
3894
+ const target = path21.join(
3734
3895
  cwd,
3735
3896
  resolveTargetPath(file.path, config.aliases, targetPathOptions(config))
3736
3897
  );
@@ -3744,8 +3905,8 @@ async function findMissingDependencies(params) {
3744
3905
  }
3745
3906
 
3746
3907
  // src/lib/update.ts
3747
- import { mkdir as mkdir8, readFile as readFile14, rm as rm2, writeFile as writeFile12 } from "fs/promises";
3748
- import path20 from "path";
3908
+ import { mkdir as mkdir9, readFile as readFile15, rm as rm2, writeFile as writeFile13 } from "fs/promises";
3909
+ import path22 from "path";
3749
3910
  function safeFileIndexes(drift) {
3750
3911
  const indexes = [];
3751
3912
  drift.files.forEach((file, index) => {
@@ -3765,7 +3926,7 @@ async function applySafeFiles(cwd, aliases, drift, registryItem, dryRun, paths)
3765
3926
  for (const index of safeIndexes) {
3766
3927
  const file = drift.files[index];
3767
3928
  const registryFile = registryItem.files[index];
3768
- const target = path20.join(cwd, resolveTargetPath(registryFile.path, aliases, paths));
3929
+ const target = path22.join(cwd, resolveTargetPath(registryFile.path, aliases, paths));
3769
3930
  const isNewFile = file.status === "new_upstream";
3770
3931
  pending.push({
3771
3932
  index,
@@ -3773,14 +3934,14 @@ async function applySafeFiles(cwd, aliases, drift, registryItem, dryRun, paths)
3773
3934
  newContent: registryFile.content,
3774
3935
  newHash: registryFile.hash ?? hashContent(registryFile.content),
3775
3936
  isNewFile,
3776
- originalContent: isNewFile ? void 0 : await readFile14(target, "utf8")
3937
+ originalContent: isNewFile ? void 0 : await readFile15(target, "utf8")
3777
3938
  });
3778
3939
  }
3779
3940
  const written = [];
3780
3941
  try {
3781
3942
  for (const item of pending) {
3782
- if (item.isNewFile) await mkdir8(path20.dirname(item.target), { recursive: true });
3783
- await writeFile12(item.target, item.newContent, "utf8");
3943
+ if (item.isNewFile) await mkdir9(path22.dirname(item.target), { recursive: true });
3944
+ await writeFile13(item.target, item.newContent, "utf8");
3784
3945
  written.push(item);
3785
3946
  }
3786
3947
  } catch (error) {
@@ -3788,7 +3949,7 @@ async function applySafeFiles(cwd, aliases, drift, registryItem, dryRun, paths)
3788
3949
  if (item.isNewFile) {
3789
3950
  await rm2(item.target, { force: true });
3790
3951
  } else {
3791
- await writeFile12(item.target, item.originalContent, "utf8");
3952
+ await writeFile13(item.target, item.originalContent, "utf8");
3792
3953
  }
3793
3954
  }
3794
3955
  return { actions, writtenHashes: {}, rollbackError: error.message };
@@ -3882,7 +4043,7 @@ async function updateCommand(components, options) {
3882
4043
  for (const name of components) {
3883
4044
  let registryItem;
3884
4045
  try {
3885
- registryItem = await fetchRegistryItem(name, config.registryUrl);
4046
+ registryItem = await fetchRegistryItem(name, config.registryUrl, config.framework);
3886
4047
  } catch (error) {
3887
4048
  console.error(`\u2717 ${name}: ${error.message}`);
3888
4049
  continue;
@@ -4116,7 +4277,7 @@ var program = new Command();
4116
4277
  program.name("dig").description("CLI \u0631\u0633\u0645\u06CC \u062F\u06CC\u0632\u0627\u06CC\u0646 \u0633\u06CC\u0633\u062A\u0645 \u062F\u06CC\u06AF").version(CLI_VERSION);
4117
4278
  program.command("init").description(
4118
4279
  '\u0631\u0627\u0647\u200C\u0627\u0646\u062F\u0627\u0632\u06CC \u062F\u06CC\u06AF \u062F\u0631 \u067E\u0631\u0648\u0698\u0647: dig.json\u060C \u062A\u0645 \u0648 \u062A\u0648\u06A9\u0646\u200C\u0647\u0627\u060C dir="rtl"\u060C DESIGN.md \u0648 \u0641\u0627\u06CC\u0644\u0650 \u062F\u0633\u062A\u0648\u0631\u0650 \u06A9\u0627\u0631\u06CC\u0650 \u0627\u06CC\u062C\u0646\u062A'
4119
- ).option("--yes", "\u067E\u0627\u0633\u062E \u067E\u06CC\u0634\u200C\u0641\u0631\u0636 \u0628\u0647 \u0647\u0645\u0647\u0654 \u0633\u0648\u0627\u0644\u0627\u062A", false).option("--brand <hex>", "\u0633\u0627\u062E\u062A\u0646\u0650 \u0631\u0645\u067E\u0650 \u0628\u0631\u0646\u062F \u0627\u0632 \u06CC\u06A9 \u0631\u0646\u06AF (\u0631\u0648\u06CC Shade \u06F6\u06F0\u06F0 \u0645\u06CC\u200C\u0646\u0634\u06CC\u0646\u062F)\u060C \u0645\u062B\u0644 #2C4C5B").option("--font <font>", "\u0641\u0648\u0646\u062A: iransans\u060C yekan \u06CC\u0627 vazirmatn").option("--agent <agent>", "\u0627\u06CC\u062C\u0646\u062A: claude-code\u060C codex\u060C cursor\u060C vscode \u06CC\u0627 gemini (\u0646\u0627\u0645\u0650 \u0641\u0627\u06CC\u0644\u0650 \u062F\u0633\u062A\u0648\u0631\u0650 \u06A9\u0627\u0631\u06CC \u0631\u0627 \u062A\u0639\u06CC\u06CC\u0646 \u0645\u06CC\u200C\u06A9\u0646\u062F)").action(initCommand);
4280
+ ).option("--yes", "\u067E\u0627\u0633\u062E \u067E\u06CC\u0634\u200C\u0641\u0631\u0636 \u0628\u0647 \u0647\u0645\u0647\u0654 \u0633\u0648\u0627\u0644\u0627\u062A", false).option("--brand <hex>", "\u0633\u0627\u062E\u062A\u0646\u0650 \u0631\u0645\u067E\u0650 \u0628\u0631\u0646\u062F \u0627\u0632 \u06CC\u06A9 \u0631\u0646\u06AF (\u0631\u0648\u06CC Shade \u06F6\u06F0\u06F0 \u0645\u06CC\u200C\u0646\u0634\u06CC\u0646\u062F)\u060C \u0645\u062B\u0644 #2C4C5B").option("--font <font>", "\u0641\u0648\u0646\u062A: iransans\u060C yekan \u06CC\u0627 vazirmatn").option("--agent <agent>", "\u0627\u06CC\u062C\u0646\u062A: claude-code\u060C codex\u060C cursor\u060C vscode \u06CC\u0627 gemini (\u0646\u0627\u0645\u0650 \u0641\u0627\u06CC\u0644\u0650 \u062F\u0633\u062A\u0648\u0631\u0650 \u06A9\u0627\u0631\u06CC \u0631\u0627 \u062A\u0639\u06CC\u06CC\u0646 \u0645\u06CC\u200C\u06A9\u0646\u062F)").option("--framework <framework>", "react \u06CC\u0627 vue\u061B \u067E\u06CC\u0634\u200C\u0641\u0631\u0636 \u0627\u0632 package.json \u062D\u062F\u0633 \u0632\u062F\u0647 \u0645\u06CC\u200C\u0634\u0648\u062F").action(initCommand);
4120
4281
  program.command("tokens").description("\u062A\u0648\u06A9\u0646\u200C\u0647\u0627\u06CC \u062F\u06CC\u06AF \u062F\u0631 \u0642\u0627\u0644\u0628\u0650 \u0627\u0633\u062A\u0627\u0646\u062F\u0627\u0631\u062F\u0650 DTCG \u0628\u0631\u0627\u06CC \u0641\u06CC\u06AF\u0645\u0627 \u0648 \u0627\u0628\u0632\u0627\u0631\u0647\u0627\u06CC \u0637\u0631\u0627\u062D\u06CC\u060C \u06CC\u06A9 \u0641\u0627\u06CC\u0644 \u0628\u0631\u0627\u06CC \u0647\u0631 \u062D\u0627\u0644\u062A").option("--brand <hex>", "\u0631\u0646\u06AF \u0628\u0631\u0646\u062F\u061B \u067E\u06CC\u0634\u200C\u0641\u0631\u0636 \u0627\u0632 DESIGN.md\u0650 \u067E\u0631\u0648\u0698\u0647").option("--out <dir>", "\u067E\u0648\u0634\u0647\u0654 \u062E\u0631\u0648\u062C\u06CC (\u067E\u06CC\u0634\u200C\u0641\u0631\u0636 tokens)").action(tokensCommand);
4121
4282
  program.command("skill").description("\u06AF\u0630\u0627\u0634\u062A\u0646 \u06CC\u0627 \u0628\u0647\u200C\u0631\u0648\u0632\u06A9\u0631\u062F\u0646\u0650 Skill\u0650 \u0631\u0633\u0645\u06CC\u0650 \u062F\u06CC\u06AF \u0628\u0631\u0627\u06CC Claude Code \u062F\u0631 .claude/skills").action(skillCommand);
4122
4283
  program.command("design-md").description("\u0633\u0627\u062E\u062A\u0646\u0650 DESIGN.md \u062F\u0631 \u0631\u06CC\u0634\u0647\u0654 \u067E\u0631\u0648\u0698\u0647: \u062A\u0648\u06A9\u0646\u200C\u0647\u0627 \u0648 \u0642\u0627\u0639\u062F\u0647\u200C\u0647\u0627\u06CC \u062F\u06CC\u06AF \u0628\u0631\u0627\u06CC \u0627\u06CC\u062C\u0646\u062A\u200C\u0647\u0627\u06CC \u06A9\u062F\u0646\u0648\u06CC\u0633").option("--brand <hex>", "\u0631\u0646\u06AF \u0628\u0631\u0646\u062F \u062A\u0627 \u0631\u0646\u06AF\u200C\u0647\u0627\u06CC \u0648\u0627\u0642\u0639\u06CC\u0650 \u0628\u0631\u0646\u062F \u062F\u0631 \u0641\u0627\u06CC\u0644 \u0628\u06CC\u0627\u06CC\u062F\u060C \u0645\u062B\u0644 #2C4C5B").option("--secondary <hex>", "\u0631\u0646\u06AF \u062F\u0648\u0645\u0650 \u0628\u0631\u0646\u062F").option("--name <name>", "\u0646\u0627\u0645 \u0645\u062D\u0635\u0648\u0644").option("--font <font>", "\u0641\u0648\u0646\u062A: iransans\u060C yekan \u06CC\u0627 vazirmatn").option("--radius <radius>", "\u0634\u0639\u0627\u0639: none\u060C sm\u060C md\u060C lg\u060C xl \u06CC\u0627 full").option("--force", "\u0628\u0627\u0632\u0646\u0648\u06CC\u0633\u06CC\u0650 DESIGN.md\u0650 \u062F\u0633\u062A\u200C\u0646\u0648\u0634\u062A\u0647", false).action(designMdCommand);
@@ -4125,7 +4286,7 @@ var theme = program.command("theme").description("\u062A\u0645 \u0648 \u0628\u06
4125
4286
  theme.command("split").description("\u067E\u0631\u0648\u0698\u0647\u0654 \u0642\u062F\u06CC\u0645\u06CC \u0631\u0627 \u0628\u0647 \u0633\u0627\u062E\u062A\u0627\u0631\u0650 \u062F\u0648\u0641\u0627\u06CC\u0644\u06CC \u0645\u06CC\u200C\u0628\u0631\u062F (dig-theme.css \u0645\u0627\u0644\u0650 \u062F\u06CC\u06AF\u060C brand.css \u0645\u0627\u0644\u0650 \u067E\u0631\u0648\u0698\u0647)").option("--dry-run", "\u0641\u0642\u0637 \u0646\u0634\u0627\u0646 \u0628\u062F\u0647 \u0686\u0647 \u0686\u06CC\u0632\u06CC \u0628\u0647 brand.css \u0645\u06CC\u200C\u0631\u0648\u062F\u060C \u0686\u06CC\u0632\u06CC \u0646\u0646\u0648\u06CC\u0633", false).action(themeSplitCommand);
4126
4287
  theme.command("brand").description("\u0631\u0645\u067E\u0650 \u0628\u0631\u0646\u062F \u0631\u0627 \u062F\u0631 brand.css \u0627\u0632 \u06CC\u06A9 \u0631\u0646\u06AF \u0645\u06CC\u200C\u0633\u0627\u0632\u062F\u061B \u0628\u0642\u06CC\u0647\u0654 \u0641\u0627\u06CC\u0644 \u062F\u0633\u062A \u0646\u0645\u06CC\u200C\u062E\u0648\u0631\u062F").argument("<hex>", "\u0631\u0646\u06AF\u0650 \u0627\u0635\u0644\u06CC\u0650 \u0628\u0631\u0646\u062F\u060C \u0645\u062B\u0644 #2C4C5B").action(themeBrandCommand);
4127
4288
  program.command("mcp").description("\u0633\u0631\u0648\u0631 MCP \u062F\u06CC\u06AF \u0628\u0647 \u0634\u06A9\u0644 \u0633\u0631\u0648\u0631 \u0645\u062D\u0644\u06CC stdio\u060C \u0628\u0631\u0627\u06CC \u06A9\u0644\u0627\u06CC\u0646\u062A\u200C\u0647\u0627\u06CC\u06CC \u06A9\u0647 \u0622\u062F\u0631\u0633 HTTP \u0646\u0645\u06CC\u200C\u06AF\u06CC\u0631\u0646\u062F").option("--url <url>", "\u0622\u062F\u0631\u0633 \u0633\u0631\u0648\u0631 MCP (\u067E\u06CC\u0634\u200C\u0641\u0631\u0636 https://docs.digdesign.ir/api/mcp)").action(mcpCommand);
4128
- program.command("add").description("\u0627\u0641\u0632\u0648\u062F\u0646 \u06CC\u06A9 \u06CC\u0627 \u0686\u0646\u062F \u06A9\u0627\u0645\u067E\u0648\u0646\u0646\u062A \u0627\u0632 \u0631\u062C\u06CC\u0633\u062A\u0631\u06CC \u062F\u06CC\u06AF").argument("[components...]", "\u0646\u0627\u0645 \u06A9\u0627\u0645\u067E\u0648\u0646\u0646\u062A\u200C\u0647\u0627 (\u0645\u062B\u0644 button) \u06CC\u0627 \u0622\u062F\u0631\u0633 \u0631\u062C\u06CC\u0633\u062A\u0631\u06CC\u061B \u0628\u062F\u0648\u0646 \u0622\u0631\u06AF\u0648\u0645\u0627\u0646 \u0641\u0647\u0631\u0633\u062A \u0631\u0627 \u0646\u0634\u0627\u0646 \u0645\u06CC\u200C\u062F\u0647\u062F").option("--overwrite", "\u0628\u0627\u0632\u0646\u0648\u06CC\u0633\u06CC \u0641\u0627\u06CC\u0644\u200C\u0647\u0627\u06CC \u0645\u0648\u062C\u0648\u062F", false).option("-y, --yes", "\u0628\u062F\u0648\u0646 \u067E\u0631\u0633\u0634\u060C \u0641\u0627\u06CC\u0644\u200C\u0647\u0627\u06CC \u0645\u0648\u062C\u0648\u062F \u0631\u0627 \u0628\u0627\u0632\u0646\u0648\u06CC\u0633\u06CC \u06A9\u0646", false).option("--dry-run", "\u0641\u0642\u0637 \u0646\u0634\u0627\u0646 \u0628\u062F\u0647 \u0686\u0647 \u0641\u0627\u06CC\u0644\u200C\u0647\u0627\u06CC\u06CC \u0646\u0648\u0634\u062A\u0647 \u0645\u06CC\u200C\u0634\u0648\u062F\u060C \u0686\u06CC\u0632\u06CC \u0646\u0646\u0648\u06CC\u0633", false).option("--no-install", "\u0641\u0642\u0637 \u0641\u0627\u06CC\u0644\u200C\u0647\u0627 \u0631\u0627 \u0628\u0646\u0648\u06CC\u0633\u060C \u0648\u0627\u0628\u0633\u062A\u06AF\u06CC\u200C\u0647\u0627 \u0631\u0627 \u0646\u0635\u0628 \u0646\u06A9\u0646").action(addCommand);
4289
+ program.command("add").description("\u0627\u0641\u0632\u0648\u062F\u0646 \u06CC\u06A9 \u06CC\u0627 \u0686\u0646\u062F \u06A9\u0627\u0645\u067E\u0648\u0646\u0646\u062A \u0627\u0632 \u0631\u062C\u06CC\u0633\u062A\u0631\u06CC \u062F\u06CC\u06AF").argument("[components...]", "\u0646\u0627\u0645 \u06A9\u0627\u0645\u067E\u0648\u0646\u0646\u062A\u200C\u0647\u0627 (\u0645\u062B\u0644 button) \u06CC\u0627 \u0622\u062F\u0631\u0633 \u0631\u062C\u06CC\u0633\u062A\u0631\u06CC\u061B \u0628\u062F\u0648\u0646 \u0622\u0631\u06AF\u0648\u0645\u0627\u0646 \u0641\u0647\u0631\u0633\u062A \u0631\u0627 \u0646\u0634\u0627\u0646 \u0645\u06CC\u200C\u062F\u0647\u062F").option("--overwrite", "\u0628\u0627\u0632\u0646\u0648\u06CC\u0633\u06CC \u0641\u0627\u06CC\u0644\u200C\u0647\u0627\u06CC \u0645\u0648\u062C\u0648\u062F", false).option("-y, --yes", "\u0628\u062F\u0648\u0646 \u067E\u0631\u0633\u0634\u060C \u0641\u0627\u06CC\u0644\u200C\u0647\u0627\u06CC \u0645\u0648\u062C\u0648\u062F \u0631\u0627 \u0628\u0627\u0632\u0646\u0648\u06CC\u0633\u06CC \u06A9\u0646", false).option("--dry-run", "\u0641\u0642\u0637 \u0646\u0634\u0627\u0646 \u0628\u062F\u0647 \u0686\u0647 \u0641\u0627\u06CC\u0644\u200C\u0647\u0627\u06CC\u06CC \u0646\u0648\u0634\u062A\u0647 \u0645\u06CC\u200C\u0634\u0648\u062F\u060C \u0686\u06CC\u0632\u06CC \u0646\u0646\u0648\u06CC\u0633", false).option("--no-install", "\u0641\u0642\u0637 \u0641\u0627\u06CC\u0644\u200C\u0647\u0627 \u0631\u0627 \u0628\u0646\u0648\u06CC\u0633\u060C \u0648\u0627\u0628\u0633\u062A\u06AF\u06CC\u200C\u0647\u0627 \u0631\u0627 \u0646\u0635\u0628 \u0646\u06A9\u0646").option("--framework <framework>", "react \u06CC\u0627 vue\u061B \u067E\u06CC\u0634\u200C\u0641\u0631\u0636 \u0627\u0632 dig.json \u0648 \u0628\u0639\u062F package.json (\u0648\u0627\u0628\u0633\u062A\u06AF\u06CC vue \u06CC\u0639\u0646\u06CC Vue) \u062D\u062F\u0633 \u0632\u062F\u0647 \u0645\u06CC\u200C\u0634\u0648\u062F").action(addCommand);
4129
4290
  program.command("list").description("\u0641\u0647\u0631\u0633\u062A \u0622\u06CC\u062A\u0645\u200C\u0647\u0627\u06CC \u0631\u062C\u06CC\u0633\u062A\u0631\u06CC \u062F\u06CC\u06AF").option("--type <type>", "\u0641\u06CC\u0644\u062A\u0631 \u0646\u0648\u0639: ui\u060C lib \u06CC\u0627 theme").option("--json", "\u062E\u0631\u0648\u062C\u06CC JSON \u0628\u0631\u0627\u06CC \u0627\u0633\u06A9\u0631\u06CC\u067E\u062A/\u0627\u0628\u0632\u0627\u0631", false).action(listCommand);
4130
4291
  program.command("search").description("\u062C\u0633\u062A\u062C\u0648\u06CC \u06A9\u0627\u0645\u067E\u0648\u0646\u0646\u062A \u062F\u0631 \u0631\u062C\u06CC\u0633\u062A\u0631\u06CC\u060C \u0628\u0627 \u0646\u0627\u0645 \u0641\u0627\u0631\u0633\u06CC \u06CC\u0627 \u0627\u0646\u06AF\u0644\u06CC\u0633\u06CC").argument("<query>", "\u0639\u0628\u0627\u0631\u062A \u062C\u0633\u062A\u062C\u0648").option("--json", "\u062E\u0631\u0648\u062C\u06CC JSON \u0628\u0631\u0627\u06CC \u0627\u0633\u06A9\u0631\u06CC\u067E\u062A/\u0627\u0628\u0632\u0627\u0631", false).action(searchCommand);
4131
4292
  program.command("diff").description(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "digdesign",
3
- "version": "0.7.0",
3
+ "version": "0.8.0",
4
4
  "description": "CLI رسمی برای نصب کامپوننت‌های دیزاین سیستم دیگ",
5
5
  "type": "module",
6
6
  "license": "MIT",