voidui-cli 0.1.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 (65) hide show
  1. package/README.md +1 -0
  2. package/dist/commands/add.d.ts +28 -0
  3. package/dist/commands/add.d.ts.map +1 -0
  4. package/dist/commands/add.js +104 -0
  5. package/dist/commands/augment.d.ts +2 -0
  6. package/dist/commands/augment.d.ts.map +1 -0
  7. package/dist/commands/augment.js +97 -0
  8. package/dist/commands/diff.d.ts +19 -0
  9. package/dist/commands/diff.d.ts.map +1 -0
  10. package/dist/commands/diff.js +233 -0
  11. package/dist/commands/index.d.ts +3 -0
  12. package/dist/commands/index.d.ts.map +1 -0
  13. package/dist/commands/index.js +2 -0
  14. package/dist/commands/snapshot.d.ts +2 -0
  15. package/dist/commands/snapshot.d.ts.map +1 -0
  16. package/dist/commands/snapshot.js +99 -0
  17. package/dist/commands/update.d.ts +28 -0
  18. package/dist/commands/update.d.ts.map +1 -0
  19. package/dist/commands/update.js +203 -0
  20. package/dist/index.d.ts +3 -0
  21. package/dist/index.d.ts.map +1 -0
  22. package/dist/index.js +89 -0
  23. package/dist/types/changelog.d.ts +17 -0
  24. package/dist/types/changelog.d.ts.map +1 -0
  25. package/dist/types/changelog.js +1 -0
  26. package/dist/types/lock-file.d.ts +41 -0
  27. package/dist/types/lock-file.d.ts.map +1 -0
  28. package/dist/types/lock-file.js +4 -0
  29. package/dist/types/registry.d.ts +84 -0
  30. package/dist/types/registry.d.ts.map +1 -0
  31. package/dist/types/registry.js +4 -0
  32. package/dist/utils/checksum.d.ts +27 -0
  33. package/dist/utils/checksum.d.ts.map +1 -0
  34. package/dist/utils/checksum.js +50 -0
  35. package/dist/utils/component-locator.d.ts +23 -0
  36. package/dist/utils/component-locator.d.ts.map +1 -0
  37. package/dist/utils/component-locator.js +59 -0
  38. package/dist/utils/diff-formatter.d.ts +47 -0
  39. package/dist/utils/diff-formatter.d.ts.map +1 -0
  40. package/dist/utils/diff-formatter.js +186 -0
  41. package/dist/utils/file-operations.d.ts +7 -0
  42. package/dist/utils/file-operations.d.ts.map +1 -0
  43. package/dist/utils/file-operations.js +37 -0
  44. package/dist/utils/lock-file.d.ts +60 -0
  45. package/dist/utils/lock-file.d.ts.map +1 -0
  46. package/dist/utils/lock-file.js +110 -0
  47. package/dist/utils/merge.d.ts +54 -0
  48. package/dist/utils/merge.d.ts.map +1 -0
  49. package/dist/utils/merge.js +84 -0
  50. package/dist/utils/prompts.d.ts +8 -0
  51. package/dist/utils/prompts.d.ts.map +1 -0
  52. package/dist/utils/prompts.js +49 -0
  53. package/dist/utils/registry.d.ts +32 -0
  54. package/dist/utils/registry.d.ts.map +1 -0
  55. package/dist/utils/registry.js +139 -0
  56. package/dist/utils/shadcn.d.ts +30 -0
  57. package/dist/utils/shadcn.d.ts.map +1 -0
  58. package/dist/utils/shadcn.js +67 -0
  59. package/dist/validators/changelog.d.ts +50 -0
  60. package/dist/validators/changelog.d.ts.map +1 -0
  61. package/dist/validators/changelog.js +31 -0
  62. package/dist/validators/lock-file.d.ts +32 -0
  63. package/dist/validators/lock-file.d.ts.map +1 -0
  64. package/dist/validators/lock-file.js +39 -0
  65. package/package.json +56 -0
@@ -0,0 +1,203 @@
1
+ /**
2
+ * Update command implementation
3
+ * Updates components with smart merge support
4
+ */
5
+ import chalk from "chalk";
6
+ import prompts from "prompts";
7
+ import { readFile, writeFile } from "fs/promises";
8
+ import { locateComponent } from "../utils/component-locator.js";
9
+ import { computeChecksum, compareChecksums } from "../utils/checksum.js";
10
+ import { fetchRegistryItem, fetchComponentVersion, extractComponentCode, } from "../utils/registry.js";
11
+ import { readLockFile, writeLockFile, updateComponentEntry, getComponentEntry, } from "../utils/lock-file.js";
12
+ import { threeWayMerge, formatMergeMessage } from "../utils/merge.js";
13
+ import { formatDiff } from "../utils/diff-formatter.js";
14
+ const DEFAULT_REGISTRY_URL = "https://voidui.dev/r";
15
+ /**
16
+ * Main update command handler
17
+ * Updates a component to latest version with merge support
18
+ *
19
+ * @param component - Component name
20
+ * @param options - Command options
21
+ */
22
+ export async function updateCommand(component, options) {
23
+ const registryUrl = options.registry || DEFAULT_REGISTRY_URL;
24
+ const cwd = process.cwd();
25
+ // Validate component name
26
+ if (!component) {
27
+ console.error(chalk.red("āŒ Component name is required"));
28
+ console.error(chalk.gray("\nUsage:"));
29
+ console.error(chalk.gray(" voidui update <component>"));
30
+ console.error(chalk.gray(" voidui update <component> --force"));
31
+ console.error(chalk.gray(" voidui update <component> --merge"));
32
+ process.exit(1);
33
+ }
34
+ console.log(chalk.blue(`\nšŸ”„ Updating ${component}...\n`));
35
+ // 1. Read lock file
36
+ const lockFile = await readLockFile(cwd);
37
+ if (!lockFile) {
38
+ console.error(chalk.red("āŒ No lock file found"));
39
+ console.error(chalk.gray("\n Lock file will be created when you run:"));
40
+ console.error(chalk.gray(` voidui add ${component}`));
41
+ process.exit(1);
42
+ }
43
+ const entry = getComponentEntry(lockFile, component);
44
+ if (!entry) {
45
+ console.error(chalk.red(`āŒ Component "${component}" is not tracked in lock file`));
46
+ console.error(chalk.gray(`\n Add tracking with:`));
47
+ console.error(chalk.gray(` voidui add ${component} --scan`));
48
+ process.exit(1);
49
+ }
50
+ // 2. Fetch latest version from registry
51
+ console.log(chalk.gray("Checking for updates..."));
52
+ const registryItem = await fetchRegistryItem(component, registryUrl);
53
+ if (!registryItem) {
54
+ console.error(chalk.red(`āŒ Component "${component}" not found in registry`));
55
+ console.error(chalk.gray(` Registry: ${registryUrl}`));
56
+ process.exit(1);
57
+ }
58
+ const versioning = registryItem.meta?.versioning;
59
+ if (!versioning) {
60
+ console.error(chalk.red(`āŒ Component "${component}" does not have version tracking`));
61
+ process.exit(1);
62
+ }
63
+ const latestVersion = versioning.currentVersion;
64
+ // 3. Locate component file
65
+ const location = await locateComponent(component, cwd);
66
+ if (!location.exists) {
67
+ console.error(chalk.red(`āŒ Component file not found at: ${location.path}`));
68
+ process.exit(1);
69
+ }
70
+ // 4. Check for local modifications (even if on latest version)
71
+ const currentChecksum = await computeChecksum(location.path);
72
+ const isModified = !compareChecksums(entry.checksum, currentChecksum);
73
+ // Check if already on latest
74
+ if (entry.installedVersion === latestVersion) {
75
+ if (isModified) {
76
+ console.log(chalk.green(`āœ“ Already on the latest version (${latestVersion})`));
77
+ console.log(chalk.yellow("\nāš ļø However, local modifications detected"));
78
+ console.log(chalk.gray("\n Your file has been modified since installation."));
79
+ console.log(chalk.gray(" To reset to the original version, run:"));
80
+ console.log(chalk.gray(` voidui add ${component} --force`));
81
+ }
82
+ else {
83
+ console.log(chalk.green(`āœ“ Already on the latest version (${latestVersion})`));
84
+ }
85
+ return;
86
+ }
87
+ console.log(chalk.gray(` Current: ${entry.installedVersion} → Latest: ${latestVersion}`));
88
+ // Already have location, currentChecksum, isModified from above
89
+ if (isModified) {
90
+ console.log(chalk.yellow("\nāš ļø Local modifications detected"));
91
+ }
92
+ // 5. Determine update strategy
93
+ let updateStrategy = "overwrite";
94
+ if (isModified && !options.force && !options.merge) {
95
+ // Interactive prompt
96
+ const response = await prompts({
97
+ type: "select",
98
+ name: "strategy",
99
+ message: "How would you like to update?",
100
+ choices: [
101
+ {
102
+ title: "Attempt 3-way merge (preserve your changes)",
103
+ value: "merge",
104
+ },
105
+ {
106
+ title: "Overwrite (lose your local changes)",
107
+ value: "overwrite",
108
+ },
109
+ {
110
+ title: "Show diff and abort",
111
+ value: "diff",
112
+ },
113
+ {
114
+ title: "Cancel",
115
+ value: "abort",
116
+ },
117
+ ],
118
+ initial: 0,
119
+ });
120
+ if (!response.strategy || response.strategy === "abort") {
121
+ console.log(chalk.gray("\nUpdate cancelled"));
122
+ return;
123
+ }
124
+ if (response.strategy === "diff") {
125
+ // Show diff and exit
126
+ const localContent = await readFile(location.path, "utf-8");
127
+ const latestContent = extractComponentCode(registryItem);
128
+ const diff = formatDiff(localContent, latestContent, `${component}@${entry.installedVersion}.tsx`, `${component}@${latestVersion}.tsx`);
129
+ console.log("\n" + diff);
130
+ console.log(chalk.gray(`\nRun \`voidui update ${component} --merge\` to attempt merge`));
131
+ console.log(chalk.gray(`Run \`voidui update ${component} --force\` to overwrite`));
132
+ return;
133
+ }
134
+ updateStrategy = response.strategy;
135
+ }
136
+ else if (options.force) {
137
+ updateStrategy = "overwrite";
138
+ }
139
+ else if (options.merge) {
140
+ updateStrategy = "merge";
141
+ }
142
+ // 6. Perform update
143
+ let newContent;
144
+ let mergeSuccess = true;
145
+ if (updateStrategy === "merge" && isModified) {
146
+ // 3-way merge
147
+ console.log(chalk.gray("\n Performing 3-way merge..."));
148
+ const baseContent = await fetchComponentVersion(component, entry.installedVersion, registryUrl);
149
+ const oursContent = await readFile(location.path, "utf-8");
150
+ const theirsContent = extractComponentCode(registryItem);
151
+ if (!baseContent) {
152
+ console.error(chalk.yellow(`\nāš ļø Could not fetch base version (${entry.installedVersion})`));
153
+ console.error(chalk.gray(" Falling back to overwrite. Use --force to confirm."));
154
+ const confirmResponse = await prompts({
155
+ type: "confirm",
156
+ name: "overwrite",
157
+ message: "Overwrite local file with latest version?",
158
+ initial: false,
159
+ });
160
+ if (!confirmResponse.overwrite) {
161
+ console.log(chalk.gray("\nUpdate cancelled"));
162
+ return;
163
+ }
164
+ newContent = theirsContent;
165
+ }
166
+ else {
167
+ const mergeResult = threeWayMerge(baseContent, oursContent, theirsContent, {
168
+ ours: "your changes",
169
+ theirs: `v${latestVersion}`,
170
+ });
171
+ newContent = mergeResult.content;
172
+ mergeSuccess = mergeResult.success;
173
+ console.log(formatMergeMessage(mergeResult, location.path));
174
+ }
175
+ }
176
+ else {
177
+ // Simple overwrite
178
+ newContent = extractComponentCode(registryItem);
179
+ if (isModified) {
180
+ console.log(chalk.yellow("\nāš ļø Overwriting local changes with latest version"));
181
+ }
182
+ }
183
+ // 7. Write updated content
184
+ await writeFile(location.path, newContent, "utf-8");
185
+ // 8. Update lock file
186
+ const newChecksum = await computeChecksum(location.path);
187
+ const updatedLockFile = updateComponentEntry(lockFile, component, {
188
+ ...entry,
189
+ installedVersion: latestVersion,
190
+ installedAt: new Date().toISOString(),
191
+ checksum: newChecksum,
192
+ });
193
+ await writeLockFile(cwd, updatedLockFile);
194
+ // 9. Success message
195
+ if (mergeSuccess) {
196
+ console.log(chalk.green(`\nāœ“ Updated ${component} from ${entry.installedVersion} to ${latestVersion}`));
197
+ console.log(chalk.gray(` Location: ${location.path}`));
198
+ }
199
+ else {
200
+ console.log(chalk.yellow(`\nāš ļø Updated ${component} with conflicts. Please resolve manually.`));
201
+ }
202
+ console.log("");
203
+ }
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
package/dist/index.js ADDED
@@ -0,0 +1,89 @@
1
+ #!/usr/bin/env node
2
+ import { Command } from "commander";
3
+ import { snapshotCommand } from "./commands/snapshot.js";
4
+ import { augmentCommand } from "./commands/augment.js";
5
+ import { diffCommand } from "./commands/diff.js";
6
+ import { addCommand } from "./commands/add.js";
7
+ import { updateCommand } from "./commands/update.js";
8
+ import pkg from "../package.json" with { type: "json" };
9
+ const program = new Command();
10
+ program
11
+ .name("voidui")
12
+ .description("CLI tools for voidui component versioning")
13
+ .version(pkg.version);
14
+ program
15
+ .command("snapshot")
16
+ .description("Create a version snapshot of a component")
17
+ .argument("<component>", "Component name (e.g., separator)")
18
+ .argument("<version>", "Version number in semver format (e.g., 1.0.0)")
19
+ .action(async (component, version) => {
20
+ try {
21
+ await snapshotCommand(component, version);
22
+ }
23
+ catch (error) {
24
+ console.error("Error:", error);
25
+ process.exit(1);
26
+ }
27
+ });
28
+ program
29
+ .command("augment")
30
+ .description("Augment registry output with versioning metadata")
31
+ .action(async () => {
32
+ try {
33
+ await augmentCommand();
34
+ }
35
+ catch (error) {
36
+ console.error("Error:", error);
37
+ process.exit(1);
38
+ }
39
+ });
40
+ program
41
+ .command("diff")
42
+ .description("Compare local components against registry versions")
43
+ .argument("[component]", "Component name (e.g., separator)")
44
+ .argument("[from-version]", "Source version (optional)")
45
+ .argument("[to-version]", "Target version (optional)")
46
+ .option("--code", "Show full code diff with syntax highlighting")
47
+ .option("--registry <url>", "Registry URL", "https://voidui.dev/r")
48
+ .action(async (component, fromVersion, toVersion, options) => {
49
+ try {
50
+ await diffCommand(component, fromVersion, toVersion, options);
51
+ }
52
+ catch (error) {
53
+ console.error("Error:", error);
54
+ process.exit(1);
55
+ }
56
+ });
57
+ program
58
+ .command("add")
59
+ .description("Install a component with version tracking")
60
+ .argument("[component]", "Component name (e.g., separator)")
61
+ .option("--scan", "Add tracking to existing component without reinstalling")
62
+ .option("--force", "Reinstall and update lock file")
63
+ .option("--registry <url>", "Registry URL", "https://voidui.dev/r")
64
+ .action(async (component, options) => {
65
+ try {
66
+ await addCommand(component, options);
67
+ }
68
+ catch (error) {
69
+ console.error("Error:", error);
70
+ process.exit(1);
71
+ }
72
+ });
73
+ program
74
+ .command("update")
75
+ .description("Update a component to the latest version")
76
+ .argument("[component]", "Component name (e.g., separator)")
77
+ .option("--force", "Overwrite local changes")
78
+ .option("--merge", "Automatically attempt 3-way merge")
79
+ .option("--registry <url>", "Registry URL", "https://voidui.dev/r")
80
+ .action(async (component, options) => {
81
+ try {
82
+ await updateCommand(component, options);
83
+ }
84
+ catch (error) {
85
+ console.error("Error:", error);
86
+ process.exit(1);
87
+ }
88
+ });
89
+ program.parse();
@@ -0,0 +1,17 @@
1
+ export type ChangeType = "added" | "changed" | "deprecated" | "removed" | "fixed" | "security";
2
+ export interface ChangelogChange {
3
+ type: ChangeType;
4
+ description: string;
5
+ }
6
+ export interface ChangelogEntry {
7
+ version: string;
8
+ date: string;
9
+ changes: ChangelogChange[];
10
+ breaking?: boolean;
11
+ }
12
+ export interface ComponentChangelog {
13
+ component: string;
14
+ currentVersion: string;
15
+ entries: ChangelogEntry[];
16
+ }
17
+ //# sourceMappingURL=changelog.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"changelog.d.ts","sourceRoot":"","sources":["../../src/types/changelog.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,UAAU,GAClB,OAAO,GACP,SAAS,GACT,YAAY,GACZ,SAAS,GACT,OAAO,GACP,UAAU,CAAC;AAEf,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,UAAU,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,eAAe,EAAE,CAAC;IAC3B,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,OAAO,EAAE,cAAc,EAAE,CAAC;CAC3B"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Lock file types for tracking installed component versions
3
+ */
4
+ export interface ComponentLockEntry {
5
+ /**
6
+ * The installed version of the component (semver format)
7
+ * @example "1.2.0"
8
+ */
9
+ installedVersion: string;
10
+ /**
11
+ * ISO 8601 timestamp of when the component was installed
12
+ * @example "2025-01-20T10:30:00Z"
13
+ */
14
+ installedAt: string;
15
+ /**
16
+ * SHA-256 checksum of the installed component file
17
+ * @example "sha256:abc123..."
18
+ */
19
+ checksum: string;
20
+ /**
21
+ * Optional custom registry URL if not using default
22
+ * @example "https://custom-registry.dev/r"
23
+ */
24
+ registryUrl?: string;
25
+ }
26
+ export interface LockFile {
27
+ /**
28
+ * Optional JSON schema reference
29
+ */
30
+ $schema?: string;
31
+ /**
32
+ * Lock file format version
33
+ * @example "1.0"
34
+ */
35
+ version: string;
36
+ /**
37
+ * Map of component names to their lock entries
38
+ */
39
+ components: Record<string, ComponentLockEntry>;
40
+ }
41
+ //# sourceMappingURL=lock-file.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lock-file.d.ts","sourceRoot":"","sources":["../../src/types/lock-file.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,WAAW,kBAAkB;IACjC;;;OAGG;IACH,gBAAgB,EAAE,MAAM,CAAC;IAEzB;;;OAGG;IACH,WAAW,EAAE,MAAM,CAAC;IAEpB;;;OAGG;IACH,QAAQ,EAAE,MAAM,CAAC;IAEjB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,QAAQ;IACvB;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;;OAGG;IACH,OAAO,EAAE,MAAM,CAAC;IAEhB;;OAEG;IACH,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;CAChD"}
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Lock file types for tracking installed component versions
3
+ */
4
+ export {};
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Registry API types for fetching component metadata
3
+ */
4
+ import type { ComponentChangelog } from "./changelog.js";
5
+ export interface RegistryItemVersioning {
6
+ /**
7
+ * Current/latest version of the component
8
+ * @example "1.2.0"
9
+ */
10
+ currentVersion: string;
11
+ /**
12
+ * Complete changelog with all version entries
13
+ */
14
+ changelog: ComponentChangelog;
15
+ /**
16
+ * List of all available versions (sorted descending)
17
+ * @example ["1.2.0", "1.1.0", "1.0.0"]
18
+ */
19
+ availableVersions: string[];
20
+ }
21
+ export interface RegistryFile {
22
+ /**
23
+ * Relative path of the file in the component
24
+ * @example "registry/components/ui/separator.tsx"
25
+ */
26
+ path: string;
27
+ /**
28
+ * File content (source code)
29
+ */
30
+ content: string;
31
+ /**
32
+ * File type
33
+ * @example "registry:ui"
34
+ */
35
+ type: string;
36
+ /**
37
+ * Target path where the file should be copied
38
+ * @example "components/ui/separator.tsx"
39
+ */
40
+ target?: string;
41
+ }
42
+ export interface RegistryItem {
43
+ /**
44
+ * Component name
45
+ * @example "separator"
46
+ */
47
+ name: string;
48
+ /**
49
+ * Component type
50
+ * @example "registry:ui"
51
+ */
52
+ type: string;
53
+ /**
54
+ * Display title
55
+ * @example "Separator"
56
+ */
57
+ title?: string;
58
+ /**
59
+ * Component description
60
+ */
61
+ description?: string;
62
+ /**
63
+ * List of files included in this component
64
+ */
65
+ files: RegistryFile[];
66
+ /**
67
+ * Optional metadata including versioning info
68
+ */
69
+ meta?: {
70
+ /**
71
+ * Versioning metadata (voidui extension)
72
+ */
73
+ versioning?: RegistryItemVersioning;
74
+ };
75
+ /**
76
+ * Dependencies required by this component
77
+ */
78
+ dependencies?: string[];
79
+ /**
80
+ * Dev dependencies
81
+ */
82
+ devDependencies?: string[];
83
+ }
84
+ //# sourceMappingURL=registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/types/registry.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAEzD,MAAM,WAAW,sBAAsB;IACrC;;;OAGG;IACH,cAAc,EAAE,MAAM,CAAC;IAEvB;;OAEG;IACH,SAAS,EAAE,kBAAkB,CAAC;IAE9B;;;OAGG;IACH,iBAAiB,EAAE,MAAM,EAAE,CAAC;CAC7B;AAED,MAAM,WAAW,YAAY;IAC3B;;;OAGG;IACH,IAAI,EAAE,MAAM,CAAC;IAEb;;OAEG;IACH,OAAO,EAAE,MAAM,CAAC;IAEhB;;;OAGG;IACH,IAAI,EAAE,MAAM,CAAC;IAEb;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,YAAY;IAC3B;;;OAGG;IACH,IAAI,EAAE,MAAM,CAAC;IAEb;;;OAGG;IACH,IAAI,EAAE,MAAM,CAAC;IAEb;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;OAEG;IACH,KAAK,EAAE,YAAY,EAAE,CAAC;IAEtB;;OAEG;IACH,IAAI,CAAC,EAAE;QACL;;WAEG;QACH,UAAU,CAAC,EAAE,sBAAsB,CAAC;KACrC,CAAC;IAEF;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IAExB;;OAEG;IACH,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;CAC5B"}
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Registry API types for fetching component metadata
3
+ */
4
+ export {};
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Utilities for computing and comparing SHA-256 checksums
3
+ */
4
+ /**
5
+ * Compute SHA-256 checksum of a file
6
+ * Normalizes line endings (CRLF -> LF) for cross-platform consistency
7
+ *
8
+ * @param filePath - Absolute path to the file
9
+ * @returns Checksum in format: "sha256:abc123..."
10
+ */
11
+ export declare function computeChecksum(filePath: string): Promise<string>;
12
+ /**
13
+ * Compare two checksums for equality
14
+ *
15
+ * @param expected - Expected checksum
16
+ * @param actual - Actual checksum
17
+ * @returns True if checksums match
18
+ */
19
+ export declare function compareChecksums(expected: string, actual: string): boolean;
20
+ /**
21
+ * Format a checksum for display (truncated)
22
+ *
23
+ * @param checksum - Full checksum string
24
+ * @returns Truncated checksum for display (e.g., "sha256:abc123...def789")
25
+ */
26
+ export declare function formatChecksum(checksum: string): string;
27
+ //# sourceMappingURL=checksum.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"checksum.d.ts","sourceRoot":"","sources":["../../src/utils/checksum.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH;;;;;;GAMG;AACH,wBAAsB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAWvE;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAE1E;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAcvD"}
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Utilities for computing and comparing SHA-256 checksums
3
+ */
4
+ import { createHash } from "crypto";
5
+ import { readFile } from "fs/promises";
6
+ /**
7
+ * Compute SHA-256 checksum of a file
8
+ * Normalizes line endings (CRLF -> LF) for cross-platform consistency
9
+ *
10
+ * @param filePath - Absolute path to the file
11
+ * @returns Checksum in format: "sha256:abc123..."
12
+ */
13
+ export async function computeChecksum(filePath) {
14
+ const content = await readFile(filePath, "utf-8");
15
+ // Normalize line endings (CRLF -> LF) for cross-platform consistency
16
+ const normalizedContent = content.replace(/\r\n/g, "\n");
17
+ const hash = createHash("sha256");
18
+ hash.update(normalizedContent, "utf-8");
19
+ const digest = hash.digest("hex");
20
+ return `sha256:${digest}`;
21
+ }
22
+ /**
23
+ * Compare two checksums for equality
24
+ *
25
+ * @param expected - Expected checksum
26
+ * @param actual - Actual checksum
27
+ * @returns True if checksums match
28
+ */
29
+ export function compareChecksums(expected, actual) {
30
+ return expected === actual;
31
+ }
32
+ /**
33
+ * Format a checksum for display (truncated)
34
+ *
35
+ * @param checksum - Full checksum string
36
+ * @returns Truncated checksum for display (e.g., "sha256:abc123...def789")
37
+ */
38
+ export function formatChecksum(checksum) {
39
+ if (!checksum.startsWith("sha256:")) {
40
+ return checksum;
41
+ }
42
+ const hash = checksum.substring(7); // Remove "sha256:" prefix
43
+ if (hash.length <= 16) {
44
+ return checksum;
45
+ }
46
+ // Show first 6 and last 6 characters
47
+ const start = hash.substring(0, 6);
48
+ const end = hash.substring(hash.length - 6);
49
+ return `sha256:${start}...${end}`;
50
+ }
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Utilities for locating components in user projects
3
+ */
4
+ export interface ComponentLocation {
5
+ /**
6
+ * Absolute path to the component file
7
+ */
8
+ path: string;
9
+ /**
10
+ * Whether the component file exists
11
+ */
12
+ exists: boolean;
13
+ }
14
+ /**
15
+ * Locate a component file in the user's project
16
+ * Tries common paths and reads components.json for path aliases
17
+ *
18
+ * @param componentName - Name of the component (e.g., "separator")
19
+ * @param cwd - Current working directory
20
+ * @returns Component location with path and existence flag
21
+ */
22
+ export declare function locateComponent(componentName: string, cwd: string): Promise<ComponentLocation>;
23
+ //# sourceMappingURL=component-locator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"component-locator.d.ts","sourceRoot":"","sources":["../../src/utils/component-locator.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,MAAM,WAAW,iBAAiB;IAChC;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IAEb;;OAEG;IACH,MAAM,EAAE,OAAO,CAAC;CACjB;AAUD;;;;;;;GAOG;AACH,wBAAsB,eAAe,CACnC,aAAa,EAAE,MAAM,EACrB,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,iBAAiB,CAAC,CA0D5B"}
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Utilities for locating components in user projects
3
+ */
4
+ import path from "path";
5
+ import { fileExists, readJsonFile } from "./file-operations.js";
6
+ /**
7
+ * Locate a component file in the user's project
8
+ * Tries common paths and reads components.json for path aliases
9
+ *
10
+ * @param componentName - Name of the component (e.g., "separator")
11
+ * @param cwd - Current working directory
12
+ * @returns Component location with path and existence flag
13
+ */
14
+ export async function locateComponent(componentName, cwd) {
15
+ const fileName = `${componentName}.tsx`;
16
+ // Try to read components.json for aliases
17
+ let componentAlias;
18
+ const configPath = path.join(cwd, "components.json");
19
+ if (await fileExists(configPath)) {
20
+ const config = await readJsonFile(configPath);
21
+ if (config?.aliases?.ui) {
22
+ componentAlias = config.aliases.ui;
23
+ }
24
+ else if (config?.aliases?.components) {
25
+ componentAlias = config.aliases.components;
26
+ }
27
+ }
28
+ // Build list of paths to try
29
+ const pathsToTry = [];
30
+ // If we have an alias from config, try that first
31
+ if (componentAlias) {
32
+ // Handle path aliases like "@/components/ui"
33
+ const cleanAlias = componentAlias.replace(/^@\//, "");
34
+ pathsToTry.push(path.join(cwd, cleanAlias, fileName));
35
+ // Also try with "src/" prefix if alias doesn't start with it
36
+ if (!cleanAlias.startsWith("src/")) {
37
+ pathsToTry.push(path.join(cwd, "src", cleanAlias, fileName));
38
+ }
39
+ }
40
+ // Common fallback paths
41
+ pathsToTry.push(path.join(cwd, "components", "ui", fileName), path.join(cwd, "src", "components", "ui", fileName), path.join(cwd, "app", "components", "ui", fileName), path.join(cwd, "lib", "components", "ui", fileName));
42
+ // Try each path in order
43
+ for (const tryPath of pathsToTry) {
44
+ if (await fileExists(tryPath)) {
45
+ return {
46
+ path: tryPath,
47
+ exists: true,
48
+ };
49
+ }
50
+ }
51
+ // Component not found, return the most common default path
52
+ const defaultPath = componentAlias
53
+ ? path.join(cwd, componentAlias.replace(/^@\//, ""), fileName)
54
+ : path.join(cwd, "components", "ui", fileName);
55
+ return {
56
+ path: defaultPath,
57
+ exists: false,
58
+ };
59
+ }