digdesign 0.6.2 → 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 +465 -227
  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
  });
@@ -2054,9 +2110,178 @@ async function impactCommand(name, options) {
2054
2110
  }
2055
2111
  }
2056
2112
 
2113
+ // src/commands/review.ts
2114
+ import { readFile as readFile9 } from "fs/promises";
2115
+ import path12 from "path";
2116
+
2117
+ // src/lib/version.ts
2118
+ var CLI_VERSION = "0.8.0";
2119
+
2120
+ // src/commands/mcp.ts
2121
+ import { createInterface as createInterface2 } from "readline";
2122
+ var DEFAULT_MCP_URL = "https://docs.digdesign.ir/api/mcp";
2123
+ function parseSse(body) {
2124
+ const messages = [];
2125
+ for (const event of body.split(/\r?\n\r?\n/)) {
2126
+ const data = event.split(/\r?\n/).filter((line) => line.startsWith("data:")).map((line) => line.slice(5).replace(/^ /, "")).join("\n");
2127
+ if (!data) continue;
2128
+ try {
2129
+ messages.push(JSON.parse(data));
2130
+ } catch {
2131
+ }
2132
+ }
2133
+ return messages;
2134
+ }
2135
+ function requestIds(message) {
2136
+ const list = Array.isArray(message) ? message : [message];
2137
+ return list.filter((item) => typeof item === "object" && item !== null).filter((item) => item.method !== void 0 && item.id !== void 0 && item.id !== null).map((item) => item.id);
2138
+ }
2139
+ function createBridge(url, fetchImpl = fetch) {
2140
+ let sessionId;
2141
+ let protocolVersion;
2142
+ return {
2143
+ async handle(line) {
2144
+ let message;
2145
+ try {
2146
+ message = JSON.parse(line);
2147
+ } catch {
2148
+ return [{ jsonrpc: "2.0", id: null, error: { code: -32700, message: "Parse error" } }];
2149
+ }
2150
+ const ids = requestIds(message);
2151
+ const fail = (reason) => ids.map((id) => ({ jsonrpc: "2.0", id, error: { code: -32603, message: `Dig MCP (${url}): ${reason}` } }));
2152
+ let response;
2153
+ try {
2154
+ response = await fetchImpl(url, {
2155
+ method: "POST",
2156
+ headers: {
2157
+ "content-type": "application/json",
2158
+ accept: "application/json, text/event-stream",
2159
+ "user-agent": `digdesign-cli/${CLI_VERSION}`,
2160
+ ...sessionId && { "mcp-session-id": sessionId },
2161
+ ...protocolVersion && { "mcp-protocol-version": protocolVersion }
2162
+ },
2163
+ body: line
2164
+ });
2165
+ } catch (error) {
2166
+ return fail(`network error: ${error.message}`);
2167
+ }
2168
+ sessionId = response.headers.get("mcp-session-id") ?? sessionId;
2169
+ if (response.status === 202) return [];
2170
+ const body = await response.text();
2171
+ if (!response.ok) return fail(`HTTP ${response.status} ${body.slice(0, 200)}`);
2172
+ let replies;
2173
+ if ((response.headers.get("content-type") ?? "").includes("text/event-stream")) replies = parseSse(body);
2174
+ else {
2175
+ try {
2176
+ replies = body.trim() ? [JSON.parse(body)] : [];
2177
+ } catch {
2178
+ return fail(`invalid JSON response: ${body.slice(0, 200)}`);
2179
+ }
2180
+ }
2181
+ for (const reply of replies.flat()) {
2182
+ const result = reply?.result;
2183
+ if (result?.protocolVersion) protocolVersion = result.protocolVersion;
2184
+ }
2185
+ return replies;
2186
+ }
2187
+ };
2188
+ }
2189
+ async function mcpCommand(options) {
2190
+ const url = options.url ?? process.env.DIG_MCP_URL ?? DEFAULT_MCP_URL;
2191
+ const bridge = createBridge(url);
2192
+ const pending = /* @__PURE__ */ new Set();
2193
+ process.stderr.write(`dig mcp: stdio bridge to ${url}
2194
+ `);
2195
+ const input = createInterface2({ input: process.stdin, crlfDelay: Infinity });
2196
+ for await (const line of input) {
2197
+ if (!line.trim()) continue;
2198
+ const task = bridge.handle(line).then((replies) => {
2199
+ for (const reply of replies) process.stdout.write(`${JSON.stringify(reply)}
2200
+ `);
2201
+ });
2202
+ pending.add(task);
2203
+ void task.finally(() => pending.delete(task));
2204
+ }
2205
+ await Promise.all(pending);
2206
+ }
2207
+
2208
+ // src/commands/review.ts
2209
+ var MAX_FILE_CHARS = 2e5;
2210
+ var MAX_FILES_PER_CALL = 25;
2211
+ async function readReviewFiles(paths, cwd) {
2212
+ const files = [];
2213
+ for (const input of paths) {
2214
+ const absolute = path12.resolve(cwd, input);
2215
+ let code;
2216
+ try {
2217
+ code = await readFile9(absolute, "utf8");
2218
+ } catch {
2219
+ throw new DigError(`\u0641\u0627\u06CC\u0644 \u062E\u0648\u0627\u0646\u062F\u0647 \u0646\u0634\u062F: ${input}`);
2220
+ }
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.`);
2222
+ files.push({ path: path12.relative(cwd, absolute) || input, code });
2223
+ }
2224
+ return files;
2225
+ }
2226
+ async function callReview(url, files, fetchImpl = fetch) {
2227
+ let response;
2228
+ try {
2229
+ response = await fetchImpl(url, {
2230
+ method: "POST",
2231
+ headers: {
2232
+ "content-type": "application/json",
2233
+ accept: "application/json, text/event-stream",
2234
+ "user-agent": `digdesign-cli/${CLI_VERSION}`
2235
+ },
2236
+ body: JSON.stringify({
2237
+ jsonrpc: "2.0",
2238
+ id: 1,
2239
+ method: "tools/call",
2240
+ params: { name: "review_code", arguments: { files } }
2241
+ })
2242
+ });
2243
+ } catch (error) {
2244
+ throw new DigError(`\u0627\u062A\u0635\u0627\u0644 \u0628\u0647 ${url} \u0628\u0631\u0642\u0631\u0627\u0631 \u0646\u0634\u062F: ${error.message}`);
2245
+ }
2246
+ const body = await response.text();
2247
+ if (!response.ok) throw new DigError(`\u0628\u0627\u0632\u0628\u06CC\u0646\u06CC \u0634\u06A9\u0633\u062A \u062E\u0648\u0631\u062F (HTTP ${response.status}).`);
2248
+ const message = (response.headers.get("content-type") ?? "").includes("text/event-stream") ? parseSse(body)[0] : JSON.parse(body);
2249
+ const text = message?.result?.content?.[0]?.text;
2250
+ if (!text) throw new DigError("\u067E\u0627\u0633\u062E\u0650 \u0646\u0627\u0645\u0639\u062A\u0628\u0631 \u0627\u0632 \u0633\u0631\u0648\u0631 MCP.");
2251
+ return JSON.parse(text);
2252
+ }
2253
+ async function reviewCommand(paths, options) {
2254
+ if (paths.length === 0) throw new DigError("\u062D\u062F\u0627\u0642\u0644 \u06CC\u06A9 \u0645\u0633\u06CC\u0631 \u0641\u0627\u06CC\u0644 \u0628\u062F\u0647: dig review src/app/page.tsx");
2255
+ const url = options.url ?? process.env.DIG_MCP_URL ?? DEFAULT_MCP_URL;
2256
+ const files = await readReviewFiles(paths, process.cwd());
2257
+ const merged = [];
2258
+ const reviewed = [];
2259
+ for (let i = 0; i < files.length; i += MAX_FILES_PER_CALL) {
2260
+ const result = await callReview(url, files.slice(i, i + MAX_FILES_PER_CALL));
2261
+ if (result.status === "invalid_input") throw new DigError(result.message ?? "\u0648\u0631\u0648\u062F\u06CC\u0650 \u0628\u0627\u0632\u0628\u06CC\u0646\u06CC \u0646\u0627\u0645\u0639\u062A\u0628\u0631 \u0627\u0633\u062A.");
2262
+ merged.push(...result.findings ?? []);
2263
+ reviewed.push(...result.reviewed ?? []);
2264
+ }
2265
+ const errors = merged.filter((finding) => finding.severity !== "warning").length;
2266
+ const status = errors > 0 ? "issues" : merged.length > 0 ? "warnings" : "ok";
2267
+ if (options.json) {
2268
+ console.log(JSON.stringify({ status, findings: merged, reviewed }, null, 2));
2269
+ } else {
2270
+ for (const finding of merged) {
2271
+ const where = `${finding.file ?? ""}:${finding.line}`;
2272
+ console.log(`${where} [${finding.severity ?? "error"}] ${finding.rule}
2273
+ ${finding.found}
2274
+ \u2190 ${finding.fix}`);
2275
+ }
2276
+ const lines = reviewed.reduce((sum, file) => sum + file.lines, 0);
2277
+ console.log(merged.length === 0 ? `\u062A\u062E\u0644\u0641\u06CC \u067E\u06CC\u062F\u0627 \u0646\u0634\u062F (${files.length} \u0641\u0627\u06CC\u0644\u060C ${lines} \u062E\u0637).` : `${merged.length} \u06CC\u0627\u0641\u062A\u0647 \u062F\u0631 ${files.length} \u0641\u0627\u06CC\u0644 (${lines} \u062E\u0637).`);
2278
+ }
2279
+ if (errors > 0) process.exitCode = 1;
2280
+ }
2281
+
2057
2282
  // src/commands/skill.ts
2058
2283
  import { mkdir as mkdir4, writeFile as writeFile6 } from "fs/promises";
2059
- import path11 from "path";
2284
+ import path13 from "path";
2060
2285
  var SKILL_PATH = ".claude/skills/dig-design-system/SKILL.md";
2061
2286
  async function skillCommand() {
2062
2287
  const cwd = process.cwd();
@@ -2069,21 +2294,21 @@ async function skillCommand() {
2069
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.`);
2070
2295
  }
2071
2296
  if (!response.ok) throw new DigError(`Skill \u06AF\u0631\u0641\u062A\u0647 \u0646\u0634\u062F: ${response.status}`);
2072
- const target = path11.join(cwd, SKILL_PATH);
2073
- await mkdir4(path11.dirname(target), { recursive: true });
2297
+ const target = path13.join(cwd, SKILL_PATH);
2298
+ await mkdir4(path13.dirname(target), { recursive: true });
2074
2299
  await writeFile6(target, await response.text(), "utf8");
2075
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).`);
2076
2301
  }
2077
2302
 
2078
2303
  // src/commands/tokens.ts
2079
- import { mkdir as mkdir5, readFile as readFile8, writeFile as writeFile7 } from "fs/promises";
2080
- import path12 from "path";
2304
+ import { mkdir as mkdir5, readFile as readFile10, writeFile as writeFile7 } from "fs/promises";
2305
+ import path14 from "path";
2081
2306
  async function tokensCommand(options) {
2082
2307
  const cwd = process.cwd();
2083
2308
  const registryUrl = await configExists(cwd) ? (await readConfig(cwd)).registryUrl : defaultConfig().registryUrl;
2084
- const designMd = await readFile8(path12.join(cwd, DESIGN_MD_FILE), "utf8").catch(() => "");
2309
+ const designMd = await readFile10(path14.join(cwd, DESIGN_MD_FILE), "utf8").catch(() => "");
2085
2310
  const brand = options.brand ?? readDesignMdSettings(designMd).brand;
2086
- const outDir = path12.join(cwd, options.out ?? "tokens");
2311
+ const outDir = path14.join(cwd, options.out ?? "tokens");
2087
2312
  await mkdir5(outDir, { recursive: true });
2088
2313
  for (const mode of ["light", "dark"]) {
2089
2314
  const url = new URL("/api/tokens", registryUrl);
@@ -2099,20 +2324,20 @@ async function tokensCommand(options) {
2099
2324
  const body = await response.json().catch(() => null);
2100
2325
  throw new DigError(`\u062A\u0648\u06A9\u0646\u200C\u0647\u0627 \u06AF\u0631\u0641\u062A\u0647 \u0646\u0634\u062F: ${body?.error ?? response.status}`);
2101
2326
  }
2102
- const file = path12.join(outDir, `dig-${mode}.tokens.json`);
2327
+ const file = path14.join(outDir, `dig-${mode}.tokens.json`);
2103
2328
  await writeFile7(file, await response.text(), "utf8");
2104
- console.log(`\u2713 ${path12.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})` : ""}.`);
2105
2330
  }
2106
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).");
2107
2332
  }
2108
2333
 
2109
2334
  // src/commands/init.ts
2110
- import { readFile as readFile11, writeFile as writeFile10 } from "fs/promises";
2111
- import path16 from "path";
2335
+ import { readFile as readFile13, writeFile as writeFile11 } from "fs/promises";
2336
+ import path19 from "path";
2112
2337
 
2113
2338
  // src/lib/agent-instructions.ts
2114
- import { mkdir as mkdir6, readFile as readFile9, writeFile as writeFile8 } from "fs/promises";
2115
- import path13 from "path";
2339
+ import { mkdir as mkdir6, readFile as readFile11, writeFile as writeFile8 } from "fs/promises";
2340
+ import path15 from "path";
2116
2341
  var AGENT_CLIENTS = [
2117
2342
  { value: "claude-code", label: "Claude Code (CLAUDE.md)" },
2118
2343
  { value: "codex", label: "Codex (AGENTS.md)" },
@@ -2164,25 +2389,94 @@ async function writeAgentInstructions(cwd, registryUrl, options) {
2164
2389
  const files = await fetchSetupFiles(registryUrl, options);
2165
2390
  const instructions = files.find((item) => /^[A-Z]+\.md$/.test(item.path) && item.path !== "DESIGN.md");
2166
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.");
2167
- const target = path13.join(cwd, instructions.path);
2168
- const existing = await readFile9(target, "utf8").catch(() => null);
2392
+ const target = path15.join(cwd, instructions.path);
2393
+ const existing = await readFile11(target, "utf8").catch(() => null);
2169
2394
  await writeFile8(target, mergeInstructions(existing, instructions.content), "utf8");
2170
2395
  console.log(
2171
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.`
2172
2397
  );
2173
2398
  const skill = files.find((item) => item.path.endsWith("/SKILL.md"));
2174
2399
  if (skill) {
2175
- const skillTarget = path13.join(cwd, skill.path);
2176
- await mkdir6(path13.dirname(skillTarget), { recursive: true });
2400
+ const skillTarget = path15.join(cwd, skill.path);
2401
+ await mkdir6(path15.dirname(skillTarget), { recursive: true });
2177
2402
  await writeFile8(skillTarget, skill.content, "utf8");
2178
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).`);
2179
2404
  }
2180
2405
  return instructions.path;
2181
2406
  }
2182
2407
 
2183
- // src/commands/theme.ts
2184
- import { access as access5, mkdir as mkdir7, readFile as readFile10, writeFile as writeFile9 } from "fs/promises";
2185
- import path15 from "path";
2408
+ // src/lib/fonts.ts
2409
+ import { mkdir as mkdir7, writeFile as writeFile9 } from "fs/promises";
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";
2186
2480
 
2187
2481
  // src/lib/brand-ramp.ts
2188
2482
  var RAMP_STEPS = [50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950];
@@ -2286,9 +2580,8 @@ function buildBrandRamp(hex) {
2286
2580
  }
2287
2581
 
2288
2582
  // src/lib/theme-files.ts
2289
- import path14 from "path";
2290
2583
  function importPath(fromFile, toFile) {
2291
- const rel = toPosixPath(path14.relative(path14.dirname(fromFile), toFile));
2584
+ const rel = toPosixPath(path17.relative(path17.dirname(fromFile), toFile));
2292
2585
  return rel.startsWith(".") ? rel : `./${rel}`;
2293
2586
  }
2294
2587
  function globalsCss(paths, extraStatements = []) {
@@ -2450,10 +2743,12 @@ function splitTheme(projectCss, digThemeCss) {
2450
2743
  }
2451
2744
 
2452
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";
2453
2748
  var THEME_ITEM = "theme";
2454
2749
  async function readIfExists2(target) {
2455
2750
  try {
2456
- return await readFile10(target, "utf8");
2751
+ return await readFile12(target, "utf8");
2457
2752
  } catch {
2458
2753
  return null;
2459
2754
  }
@@ -2467,7 +2762,7 @@ async function exists(target) {
2467
2762
  }
2468
2763
  }
2469
2764
  function themePaths(config) {
2470
- const dir = path15.posix.dirname(toPosixPath(config.tailwind.css));
2765
+ const dir = path18.posix.dirname(toPosixPath(config.tailwind.css));
2471
2766
  return {
2472
2767
  css: config.tailwind.css,
2473
2768
  theme: config.tailwind.theme ?? `${dir}/dig-theme.css`,
@@ -2501,9 +2796,9 @@ async function recordTheme(cwd, config, themeRel, item) {
2501
2796
  await writeLock(lock, cwd);
2502
2797
  }
2503
2798
  async function writeText(cwd, rel, content) {
2504
- const target = path15.join(cwd, rel);
2505
- await mkdir7(path15.dirname(target), { recursive: true });
2506
- 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");
2507
2802
  }
2508
2803
  async function installTheme(cwd, config, options) {
2509
2804
  const paths = themePaths(config);
@@ -2511,7 +2806,7 @@ async function installTheme(cwd, config, options) {
2511
2806
  const ramp = options.brand ? buildBrandRamp(options.brand) : void 0;
2512
2807
  await writeText(cwd, paths.theme, item.content);
2513
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).`);
2514
- const existingBrand = await readIfExists2(path15.join(cwd, paths.brand));
2809
+ const existingBrand = await readIfExists2(path18.join(cwd, paths.brand));
2515
2810
  if (existingBrand === null) {
2516
2811
  await writeText(cwd, paths.brand, brandCss({ ramp, hex: options.brand }));
2517
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).`);
@@ -2522,10 +2817,10 @@ async function installTheme(cwd, config, options) {
2522
2817
  console.log(`- ${paths.brand} \u0627\u0632 \u0642\u0628\u0644 \u0647\u0633\u062A\u061B \u062F\u0633\u062A \u0646\u062E\u0648\u0631\u062F.`);
2523
2818
  }
2524
2819
  if (ramp) reportContrast(ramp.primaryContrast);
2525
- const cssTarget = path15.join(cwd, paths.css);
2820
+ const cssTarget = path18.join(cwd, paths.css);
2526
2821
  const existingCss = await readIfExists2(cssTarget);
2527
2822
  if (!isBoilerplateCss(existingCss) && existingCss !== null) {
2528
- await writeFile9(`${cssTarget}.backup`, existingCss, "utf8");
2823
+ await writeFile10(`${cssTarget}.backup`, existingCss, "utf8");
2529
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.`);
2530
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.`);
2531
2826
  }
@@ -2558,11 +2853,11 @@ async function themeSplitCommand(options) {
2558
2853
  return;
2559
2854
  }
2560
2855
  const paths = themePaths(config);
2561
- const current = await readIfExists2(path15.join(cwd, paths.css));
2856
+ const current = await readIfExists2(path18.join(cwd, paths.css));
2562
2857
  if (current === null || isBoilerplateCss(current)) {
2563
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.`);
2564
2859
  }
2565
- if (await exists(path15.join(cwd, paths.brand))) {
2860
+ if (await exists(path18.join(cwd, paths.brand))) {
2566
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.`);
2567
2862
  }
2568
2863
  console.log(`\u062F\u0631\u06CC\u0627\u0641\u062A\u0650 \u062A\u0645\u0650 \u062F\u06CC\u06AF \u0627\u0632 ${config.registryUrl} \u2026`);
@@ -2581,7 +2876,7 @@ ${split.changed} \u062A\u0648\u06A9\u0646\u0650 \u0639\u0648\u0636\u200C\u0634\u
2581
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)");
2582
2877
  return;
2583
2878
  }
2584
- await writeFile9(path15.join(cwd, `${paths.css}.backup`), current, "utf8");
2879
+ await writeFile10(path18.join(cwd, `${paths.css}.backup`), current, "utf8");
2585
2880
  await writeText(cwd, paths.theme, item.content);
2586
2881
  await writeText(cwd, paths.brand, brandCss({ body: split.body }));
2587
2882
  await writeText(cwd, paths.css, globalsCss(paths, split.extraStatements));
@@ -2605,7 +2900,7 @@ async function themeBrandCommand(hex) {
2605
2900
  }
2606
2901
  const paths = themePaths(config);
2607
2902
  const ramp = buildBrandRamp(hex);
2608
- const existing = await readIfExists2(path15.join(cwd, paths.brand)) ?? brandCss({});
2903
+ const existing = await readIfExists2(path18.join(cwd, paths.brand)) ?? brandCss({});
2609
2904
  const next = replaceBrandRamp(existing, ramp, hex);
2610
2905
  await writeText(cwd, paths.brand, next);
2611
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).`);
@@ -2623,14 +2918,14 @@ async function themeBrandCommand(hex) {
2623
2918
  // src/commands/init.ts
2624
2919
  async function readIfExists3(target) {
2625
2920
  try {
2626
- return await readFile11(target, "utf8");
2921
+ return await readFile13(target, "utf8");
2627
2922
  } catch {
2628
2923
  return null;
2629
2924
  }
2630
2925
  }
2631
2926
  async function writeTheme(config, cwd, options) {
2632
2927
  const paths = themePaths(config);
2633
- const existing = await readIfExists3(path16.join(cwd, paths.css));
2928
+ const existing = await readIfExists3(path19.join(cwd, paths.css));
2634
2929
  if (!isBoilerplateCss(existing) && !options.yes) {
2635
2930
  console.log(`
2636
2931
  ${paths.css} \u0627\u0632 \u0642\u0628\u0644 \u0645\u062D\u062A\u0648\u0627 \u062F\u0627\u0631\u062F.`);
@@ -2651,11 +2946,37 @@ ${paths.css} \u0627\u0632 \u0642\u0628\u0644 \u0645\u062D\u062A\u0648\u0627 \u06
2651
2946
  \u0646\u0635\u0628 \u0648\u0627\u0628\u0633\u062A\u06AF\u06CC\u200C\u0647\u0627\u06CC \u062A\u0645 \u0628\u0627 ${pm} \u2026`);
2652
2947
  await installDependencies(pm, item.dependencies, { cwd });
2653
2948
  }
2949
+ await writeFonts(cwd, config, paths, options.font);
2654
2950
  return "written";
2655
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
+ }
2656
2977
  async function applyRtl(cwd) {
2657
2978
  for (const candidate of ["src/app/layout.tsx", "app/layout.tsx"]) {
2658
- const target = path16.join(cwd, candidate);
2979
+ const target = path19.join(cwd, candidate);
2659
2980
  const source = await readIfExists3(target);
2660
2981
  if (source === null) continue;
2661
2982
  if (/<html[^>]*\sdir=/.test(source)) {
@@ -2668,7 +2989,7 @@ async function applyRtl(cwd) {
2668
2989
  match[0],
2669
2990
  `<html${match[1]} dir="rtl">`.replace(/\s+dir="rtl">$/, ' dir="rtl">')
2670
2991
  );
2671
- await writeFile10(target, updated, "utf8");
2992
+ await writeFile11(target, updated, "utf8");
2672
2993
  console.log(`\u2713 dir="rtl" \u0628\u0647 ${candidate} \u0627\u0636\u0627\u0641\u0647 \u0634\u062F.`);
2673
2994
  return;
2674
2995
  }
@@ -2687,7 +3008,14 @@ async function askProjectDecisions(options) {
2687
3008
  }
2688
3009
  async function initCommand(options) {
2689
3010
  const cwd = process.cwd();
3011
+ const framework = await resolveFramework(cwd, void 0, options.framework);
2690
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
+ }
2691
3019
  if (await configExists(cwd)) {
2692
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);
2693
3021
  if (!overwrite) {
@@ -2700,16 +3028,18 @@ async function initCommand(options) {
2700
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),
2701
3029
  tailwind: await (async () => {
2702
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);
2703
- const dir = path16.posix.dirname(css.split(path16.sep).join("/"));
3031
+ const dir = path19.posix.dirname(css.split(path19.sep).join("/"));
2704
3032
  return { ...base.tailwind, css, theme: `${dir}/dig-theme.css`, brand: `${dir}/brand.css` };
2705
3033
  })()
2706
3034
  };
2707
3035
  const decisions = await askProjectDecisions(options);
2708
3036
  options = { ...options, brand: decisions.brand };
2709
3037
  await writeConfig(config, cwd);
2710
- console.log(`\u2713 ${path16.join(cwd, "dig.json")} \u0646\u0648\u0634\u062A\u0647 \u0634\u062F.`);
2711
- const theme2 = await writeTheme(config, cwd, options);
2712
- 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) {
2713
3043
  await applyRtl(cwd);
2714
3044
  }
2715
3045
  await writeDesignMd(cwd, config.registryUrl, { brand: decisions.brand, font: decisions.font }).catch((error) => {
@@ -2731,102 +3061,9 @@ async function initCommand(options) {
2731
3061
  }
2732
3062
  }
2733
3063
 
2734
- // src/commands/mcp.ts
2735
- import { createInterface as createInterface2 } from "readline";
2736
-
2737
- // src/lib/version.ts
2738
- var CLI_VERSION = "0.6.2";
2739
-
2740
- // src/commands/mcp.ts
2741
- var DEFAULT_MCP_URL = "https://docs.digdesign.ir/api/mcp";
2742
- function parseSse(body) {
2743
- const messages = [];
2744
- for (const event of body.split(/\r?\n\r?\n/)) {
2745
- const data = event.split(/\r?\n/).filter((line) => line.startsWith("data:")).map((line) => line.slice(5).replace(/^ /, "")).join("\n");
2746
- if (!data) continue;
2747
- try {
2748
- messages.push(JSON.parse(data));
2749
- } catch {
2750
- }
2751
- }
2752
- return messages;
2753
- }
2754
- function requestIds(message) {
2755
- const list = Array.isArray(message) ? message : [message];
2756
- return list.filter((item) => typeof item === "object" && item !== null).filter((item) => item.method !== void 0 && item.id !== void 0 && item.id !== null).map((item) => item.id);
2757
- }
2758
- function createBridge(url, fetchImpl = fetch) {
2759
- let sessionId;
2760
- let protocolVersion;
2761
- return {
2762
- async handle(line) {
2763
- let message;
2764
- try {
2765
- message = JSON.parse(line);
2766
- } catch {
2767
- return [{ jsonrpc: "2.0", id: null, error: { code: -32700, message: "Parse error" } }];
2768
- }
2769
- const ids = requestIds(message);
2770
- const fail = (reason) => ids.map((id) => ({ jsonrpc: "2.0", id, error: { code: -32603, message: `Dig MCP (${url}): ${reason}` } }));
2771
- let response;
2772
- try {
2773
- response = await fetchImpl(url, {
2774
- method: "POST",
2775
- headers: {
2776
- "content-type": "application/json",
2777
- accept: "application/json, text/event-stream",
2778
- "user-agent": `digdesign-cli/${CLI_VERSION}`,
2779
- ...sessionId && { "mcp-session-id": sessionId },
2780
- ...protocolVersion && { "mcp-protocol-version": protocolVersion }
2781
- },
2782
- body: line
2783
- });
2784
- } catch (error) {
2785
- return fail(`network error: ${error.message}`);
2786
- }
2787
- sessionId = response.headers.get("mcp-session-id") ?? sessionId;
2788
- if (response.status === 202) return [];
2789
- const body = await response.text();
2790
- if (!response.ok) return fail(`HTTP ${response.status} ${body.slice(0, 200)}`);
2791
- let replies;
2792
- if ((response.headers.get("content-type") ?? "").includes("text/event-stream")) replies = parseSse(body);
2793
- else {
2794
- try {
2795
- replies = body.trim() ? [JSON.parse(body)] : [];
2796
- } catch {
2797
- return fail(`invalid JSON response: ${body.slice(0, 200)}`);
2798
- }
2799
- }
2800
- for (const reply of replies.flat()) {
2801
- const result = reply?.result;
2802
- if (result?.protocolVersion) protocolVersion = result.protocolVersion;
2803
- }
2804
- return replies;
2805
- }
2806
- };
2807
- }
2808
- async function mcpCommand(options) {
2809
- const url = options.url ?? process.env.DIG_MCP_URL ?? DEFAULT_MCP_URL;
2810
- const bridge = createBridge(url);
2811
- const pending = /* @__PURE__ */ new Set();
2812
- process.stderr.write(`dig mcp: stdio bridge to ${url}
2813
- `);
2814
- const input = createInterface2({ input: process.stdin, crlfDelay: Infinity });
2815
- for await (const line of input) {
2816
- if (!line.trim()) continue;
2817
- const task = bridge.handle(line).then((replies) => {
2818
- for (const reply of replies) process.stdout.write(`${JSON.stringify(reply)}
2819
- `);
2820
- });
2821
- pending.add(task);
2822
- void task.finally(() => pending.delete(task));
2823
- }
2824
- await Promise.all(pending);
2825
- }
2826
-
2827
3064
  // src/lib/migration-apply.ts
2828
- import { readFile as readFile12, writeFile as writeFile11 } from "fs/promises";
2829
- import path17 from "path";
3065
+ import { readFile as readFile14, writeFile as writeFile12 } from "fs/promises";
3066
+ import path20 from "path";
2830
3067
 
2831
3068
  // src/lib/migration-strategy.ts
2832
3069
  var TextReplaceStrategy = class {
@@ -2903,7 +3140,7 @@ function looksBinary2(buffer) {
2903
3140
  async function readTextFileSafely2(target) {
2904
3141
  let buffer;
2905
3142
  try {
2906
- buffer = await readFile12(target);
3143
+ buffer = await readFile14(target);
2907
3144
  } catch (error) {
2908
3145
  if (error.code === "ENOENT") return void 0;
2909
3146
  throw error;
@@ -2948,8 +3185,8 @@ async function planOrApplyMigrations(params) {
2948
3185
  };
2949
3186
  }
2950
3187
  const fileTargets = registryItem.files.map((file) => {
2951
- const target = path17.join(cwd, resolveTargetPath(file.path, aliases, paths));
2952
- return { relPath: toPosixPath(path17.relative(cwd, target)), target };
3188
+ const target = path20.join(cwd, resolveTargetPath(file.path, aliases, paths));
3189
+ return { relPath: toPosixPath(path20.relative(cwd, target)), target };
2953
3190
  });
2954
3191
  const currentContents = /* @__PURE__ */ new Map();
2955
3192
  for (const ft of fileTargets) {
@@ -3015,12 +3252,12 @@ async function planOrApplyMigrations(params) {
3015
3252
  const written = [];
3016
3253
  try {
3017
3254
  for (const item of pending) {
3018
- await writeFile11(item.target, item.newContent, "utf8");
3255
+ await writeFile12(item.target, item.newContent, "utf8");
3019
3256
  written.push(item);
3020
3257
  }
3021
3258
  } catch (error) {
3022
3259
  for (const item of written) {
3023
- await writeFile11(item.target, item.originalContent, "utf8");
3260
+ await writeFile12(item.target, item.originalContent, "utf8");
3024
3261
  }
3025
3262
  return {
3026
3263
  name,
@@ -3078,7 +3315,7 @@ async function runPlan(components, options) {
3078
3315
  continue;
3079
3316
  }
3080
3317
  try {
3081
- const item = await fetchRegistryItem(name, config.registryUrl);
3318
+ const item = await fetchRegistryItem(name, config.registryUrl, config.framework);
3082
3319
  const toVersion = item.version ?? "0.0.0";
3083
3320
  const migrations = getApplicableMigrations(
3084
3321
  parseMigrations(name, item.migrations),
@@ -3149,7 +3386,7 @@ async function runApplyOrDryRun(components, options, dryRun) {
3149
3386
  for (const name of components) {
3150
3387
  let registryItem;
3151
3388
  try {
3152
- registryItem = await fetchRegistryItem(name, config.registryUrl);
3389
+ registryItem = await fetchRegistryItem(name, config.registryUrl, config.framework);
3153
3390
  } catch (error) {
3154
3391
  console.error(`\u2717 ${name}: ${error.message}`);
3155
3392
  continue;
@@ -3344,7 +3581,7 @@ ${message}`);
3344
3581
  }
3345
3582
  let item;
3346
3583
  try {
3347
- item = await fetchRegistryItem(component, config.registryUrl);
3584
+ item = await fetchRegistryItem(component, config.registryUrl, config.framework);
3348
3585
  } catch (error) {
3349
3586
  console.error(`\u2717 ${component}: ${error.message}`);
3350
3587
  return;
@@ -3432,7 +3669,7 @@ async function releaseCommand(components, options) {
3432
3669
  const entries = [];
3433
3670
  for (const name of components) {
3434
3671
  try {
3435
- const item = await fetchRegistryItem(name, config.registryUrl);
3672
+ const item = await fetchRegistryItem(name, config.registryUrl, config.framework);
3436
3673
  const version = item.version ?? "0.0.0";
3437
3674
  entries.push({
3438
3675
  name,
@@ -3539,7 +3776,7 @@ async function statusCommand(components, options) {
3539
3776
  const entries = [];
3540
3777
  for (const name of components) {
3541
3778
  try {
3542
- const item = await fetchRegistryItem(name, config.registryUrl);
3779
+ const item = await fetchRegistryItem(name, config.registryUrl, config.framework);
3543
3780
  const version = item.version ?? "0.0.0";
3544
3781
  const lifecycle = parseLifecycle(name, version, item.deprecation);
3545
3782
  const release = parseRelease(name, version, item.release);
@@ -3633,7 +3870,7 @@ ${entry.migrationHint}`);
3633
3870
 
3634
3871
  // src/lib/missing-dependencies.ts
3635
3872
  import { access as access6 } from "fs/promises";
3636
- import path18 from "path";
3873
+ import path21 from "path";
3637
3874
  async function exists2(target) {
3638
3875
  try {
3639
3876
  await access6(target);
@@ -3649,12 +3886,12 @@ async function findMissingDependencies(params) {
3649
3886
  ...new Set(items.flatMap((item) => item.registryDependencies ?? []))
3650
3887
  ].filter((name) => !requested.has(name));
3651
3888
  if (direct.length === 0) return [];
3652
- const tree = await resolveRegistryTree(direct, config.registryUrl);
3889
+ const tree = await resolveRegistryTree(direct, config.registryUrl, config.framework);
3653
3890
  const missing = [];
3654
3891
  for (const item of tree.values()) {
3655
3892
  if (requested.has(item.name) || lock.components[item.name]) continue;
3656
3893
  for (const file of item.files) {
3657
- const target = path18.join(
3894
+ const target = path21.join(
3658
3895
  cwd,
3659
3896
  resolveTargetPath(file.path, config.aliases, targetPathOptions(config))
3660
3897
  );
@@ -3668,8 +3905,8 @@ async function findMissingDependencies(params) {
3668
3905
  }
3669
3906
 
3670
3907
  // src/lib/update.ts
3671
- import { mkdir as mkdir8, readFile as readFile13, rm as rm2, writeFile as writeFile12 } from "fs/promises";
3672
- import path19 from "path";
3908
+ import { mkdir as mkdir9, readFile as readFile15, rm as rm2, writeFile as writeFile13 } from "fs/promises";
3909
+ import path22 from "path";
3673
3910
  function safeFileIndexes(drift) {
3674
3911
  const indexes = [];
3675
3912
  drift.files.forEach((file, index) => {
@@ -3689,7 +3926,7 @@ async function applySafeFiles(cwd, aliases, drift, registryItem, dryRun, paths)
3689
3926
  for (const index of safeIndexes) {
3690
3927
  const file = drift.files[index];
3691
3928
  const registryFile = registryItem.files[index];
3692
- const target = path19.join(cwd, resolveTargetPath(registryFile.path, aliases, paths));
3929
+ const target = path22.join(cwd, resolveTargetPath(registryFile.path, aliases, paths));
3693
3930
  const isNewFile = file.status === "new_upstream";
3694
3931
  pending.push({
3695
3932
  index,
@@ -3697,14 +3934,14 @@ async function applySafeFiles(cwd, aliases, drift, registryItem, dryRun, paths)
3697
3934
  newContent: registryFile.content,
3698
3935
  newHash: registryFile.hash ?? hashContent(registryFile.content),
3699
3936
  isNewFile,
3700
- originalContent: isNewFile ? void 0 : await readFile13(target, "utf8")
3937
+ originalContent: isNewFile ? void 0 : await readFile15(target, "utf8")
3701
3938
  });
3702
3939
  }
3703
3940
  const written = [];
3704
3941
  try {
3705
3942
  for (const item of pending) {
3706
- if (item.isNewFile) await mkdir8(path19.dirname(item.target), { recursive: true });
3707
- 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");
3708
3945
  written.push(item);
3709
3946
  }
3710
3947
  } catch (error) {
@@ -3712,7 +3949,7 @@ async function applySafeFiles(cwd, aliases, drift, registryItem, dryRun, paths)
3712
3949
  if (item.isNewFile) {
3713
3950
  await rm2(item.target, { force: true });
3714
3951
  } else {
3715
- await writeFile12(item.target, item.originalContent, "utf8");
3952
+ await writeFile13(item.target, item.originalContent, "utf8");
3716
3953
  }
3717
3954
  }
3718
3955
  return { actions, writtenHashes: {}, rollbackError: error.message };
@@ -3806,7 +4043,7 @@ async function updateCommand(components, options) {
3806
4043
  for (const name of components) {
3807
4044
  let registryItem;
3808
4045
  try {
3809
- registryItem = await fetchRegistryItem(name, config.registryUrl);
4046
+ registryItem = await fetchRegistryItem(name, config.registryUrl, config.framework);
3810
4047
  } catch (error) {
3811
4048
  console.error(`\u2717 ${name}: ${error.message}`);
3812
4049
  continue;
@@ -4040,15 +4277,16 @@ var program = new Command();
4040
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);
4041
4278
  program.command("init").description(
4042
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'
4043
- ).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);
4044
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);
4045
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);
4046
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);
4284
+ program.command("review").description("\u0628\u0627\u0632\u0628\u06CC\u0646\u06CC\u0650 \u0641\u0627\u06CC\u0644\u200C\u0647\u0627\u06CC \u0631\u0627\u0628\u0637 \u0628\u0627 \u0642\u0648\u0627\u0639\u062F \u062F\u06CC\u06AF (\u0647\u0645\u0627\u0646 review_code \u062F\u0631 MCP)\u060C \u0628\u0627 \u0634\u0645\u0627\u0631\u0647\u0654 \u062E\u0637\u0650 \u0647\u0631 \u06CC\u0627\u0641\u062A\u0647").argument("<paths...>", "\u0645\u0633\u06CC\u0631 \u0641\u0627\u06CC\u0644\u200C\u0647\u0627\u06CC tsx/jsx").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)").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(reviewCommand);
4047
4285
  var theme = program.command("theme").description("\u062A\u0645 \u0648 \u0628\u0631\u0646\u062F: \u062C\u062F\u0627 \u06A9\u0631\u062F\u0646\u0650 \u062A\u0645\u0650 \u062F\u06CC\u06AF \u0627\u0632 \u0628\u0631\u0646\u062F\u0650 \u067E\u0631\u0648\u0698\u0647");
4048
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);
4049
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);
4050
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);
4051
- 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);
4052
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);
4053
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);
4054
4292
  program.command("diff").description(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "digdesign",
3
- "version": "0.6.2",
3
+ "version": "0.8.0",
4
4
  "description": "CLI رسمی برای نصب کامپوننت‌های دیزاین سیستم دیگ",
5
5
  "type": "module",
6
6
  "license": "MIT",