assistant-ui 0.0.105 → 0.0.107
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/codemods/utils/createTransformer.d.ts +0 -1
- package/dist/codemods/utils/createTransformer.d.ts.map +1 -1
- package/dist/codemods/v0-11/content-part-to-message-part.d.ts.map +1 -1
- package/dist/codemods/v0-12/assistant-api-to-aui.d.ts.map +1 -1
- package/dist/codemods/v0-12/assistant-api-to-aui.js.map +1 -1
- package/dist/codemods/v0-12/event-names-to-camelcase.d.ts.map +1 -1
- package/dist/codemods/v0-12/primitive-if-to-aui-if.d.ts.map +1 -1
- package/dist/codemods/v0-8/ui-package-split.d.ts.map +1 -1
- package/dist/codemods/v0-8/ui-package-split.js.map +1 -1
- package/dist/codemods/v0-9/edge-package-split.d.ts.map +1 -1
- package/dist/commands/add.d.ts +1 -1
- package/dist/commands/add.d.ts.map +1 -1
- package/dist/commands/add.js +8 -5
- package/dist/commands/add.js.map +1 -1
- package/dist/commands/agent.d.ts +0 -1
- package/dist/commands/agent.d.ts.map +1 -1
- package/dist/commands/create.d.ts +0 -1
- package/dist/commands/create.d.ts.map +1 -1
- package/dist/commands/create.js +26 -8
- package/dist/commands/create.js.map +1 -1
- package/dist/commands/doctor.d.ts +0 -1
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +66 -29
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/info.d.ts +3 -2
- package/dist/commands/info.d.ts.map +1 -1
- package/dist/commands/info.js +22 -26
- package/dist/commands/info.js.map +1 -1
- package/dist/commands/init.d.ts +1 -3
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +14 -24
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/mcp.d.ts +0 -1
- package/dist/commands/mcp.d.ts.map +1 -1
- package/dist/commands/mcp.js +14 -4
- package/dist/commands/mcp.js.map +1 -1
- package/dist/commands/update.d.ts +0 -1
- package/dist/commands/update.d.ts.map +1 -1
- package/dist/commands/update.js +14 -1
- package/dist/commands/update.js.map +1 -1
- package/dist/commands/upgrade.d.ts +0 -1
- package/dist/commands/upgrade.d.ts.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/lib/agent-skill.d.ts +0 -1
- package/dist/lib/agent-skill.d.ts.map +1 -1
- package/dist/lib/create-project.d.ts +7 -2
- package/dist/lib/create-project.d.ts.map +1 -1
- package/dist/lib/create-project.js +34 -17
- package/dist/lib/create-project.js.map +1 -1
- package/dist/lib/install-ai-sdk-lib.d.ts.map +1 -1
- package/dist/lib/install-edge-lib.d.ts.map +1 -1
- package/dist/lib/install-ui-lib.d.ts.map +1 -1
- package/dist/lib/run-spawn.d.ts.map +1 -1
- package/dist/lib/transform-options.d.ts.map +1 -1
- package/dist/lib/transform.d.ts +0 -1
- package/dist/lib/transform.d.ts.map +1 -1
- package/dist/lib/upgrade.d.ts +0 -1
- package/dist/lib/upgrade.d.ts.map +1 -1
- package/dist/lib/utils/config.d.ts.map +1 -1
- package/dist/lib/utils/file-scanner.d.ts.map +1 -1
- package/dist/lib/utils/logger.d.ts.map +1 -1
- package/dist/lib/utils/package-installer.d.ts.map +1 -1
- package/dist/lib/utils/package-manager.d.ts.map +1 -1
- package/dist/lib/utils/registry.d.ts +7 -0
- package/dist/lib/utils/registry.d.ts.map +1 -0
- package/dist/lib/utils/registry.js +25 -0
- package/dist/lib/utils/registry.js.map +1 -0
- package/dist/lib/utils/workspace.d.ts +6 -0
- package/dist/lib/utils/workspace.d.ts.map +1 -0
- package/dist/lib/utils/workspace.js +28 -0
- package/dist/lib/utils/workspace.js.map +1 -0
- package/dist/program.d.ts +0 -1
- package/dist/program.d.ts.map +1 -1
- package/package.json +12 -9
- package/plugin/skills/assistant-ui/SKILL.md +24 -5
- package/src/commands/add.ts +9 -4
- package/src/commands/create.ts +28 -8
- package/src/commands/doctor.ts +97 -44
- package/src/commands/info.ts +49 -42
- package/src/commands/init.ts +16 -24
- package/src/commands/mcp.ts +20 -5
- package/src/commands/update.ts +17 -1
- package/src/lib/create-project.ts +64 -20
- package/src/lib/utils/registry.test.ts +114 -0
- package/src/lib/utils/registry.ts +43 -0
- package/src/lib/utils/workspace.ts +34 -0
package/src/commands/mcp.ts
CHANGED
|
@@ -135,6 +135,18 @@ function deepMerge(target: any, source: any): any {
|
|
|
135
135
|
return result;
|
|
136
136
|
}
|
|
137
137
|
|
|
138
|
+
class McpConfigParseError extends Error {
|
|
139
|
+
constructor(targetName: string, configPath: string, flag: string) {
|
|
140
|
+
super(
|
|
141
|
+
`Invalid ${targetName} MCP config JSON at ${configPath}. Fix the JSON syntax, then run: assistant-ui mcp ${flag}`,
|
|
142
|
+
);
|
|
143
|
+
this.name = "McpConfigParseError";
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const getTargetFlag = (target: Exclude<MCPTarget, "claude-code">) =>
|
|
148
|
+
`--${target}`;
|
|
149
|
+
|
|
138
150
|
async function installForTarget(target: MCPTarget): Promise<void> {
|
|
139
151
|
if (target === "claude-code") {
|
|
140
152
|
logger.info("Installing MCP server for Claude Code...");
|
|
@@ -204,12 +216,15 @@ async function installForTarget(target: MCPTarget): Promise<void> {
|
|
|
204
216
|
const content = fs.readFileSync(configPath, "utf-8");
|
|
205
217
|
try {
|
|
206
218
|
existingConfig = JSON.parse(content);
|
|
207
|
-
} catch
|
|
208
|
-
|
|
209
|
-
logger.error(
|
|
210
|
-
|
|
219
|
+
} catch {
|
|
220
|
+
const flag = getTargetFlag(target);
|
|
221
|
+
logger.error(`Could not parse ${targetConfig.name} MCP config.`);
|
|
222
|
+
logger.info(`Config path: ${configPath}`);
|
|
223
|
+
logger.info(
|
|
224
|
+
`Fix the JSON syntax in that file, then run: assistant-ui mcp ${flag}`,
|
|
211
225
|
);
|
|
212
|
-
|
|
226
|
+
logger.info("No changes were written.");
|
|
227
|
+
throw new McpConfigParseError(targetConfig.name, configPath, flag);
|
|
213
228
|
}
|
|
214
229
|
}
|
|
215
230
|
|
package/src/commands/update.ts
CHANGED
|
@@ -5,6 +5,15 @@ import { sync as spawnSync } from "cross-spawn";
|
|
|
5
5
|
import { logger } from "../lib/utils/logger";
|
|
6
6
|
import { getInstallCommand } from "../lib/utils/package-manager";
|
|
7
7
|
|
|
8
|
+
const logPackageJsonParseError = (packageJsonPath: string) => {
|
|
9
|
+
logger.error("Could not parse package.json.");
|
|
10
|
+
console.error(`Package path: ${packageJsonPath}`);
|
|
11
|
+
console.error(
|
|
12
|
+
"Fix the JSON syntax in that file, then run: assistant-ui update",
|
|
13
|
+
);
|
|
14
|
+
console.error("No changes were written.");
|
|
15
|
+
};
|
|
16
|
+
|
|
8
17
|
export const update = new Command()
|
|
9
18
|
.name("update")
|
|
10
19
|
.description(
|
|
@@ -23,7 +32,14 @@ export const update = new Command()
|
|
|
23
32
|
process.exit(1);
|
|
24
33
|
}
|
|
25
34
|
|
|
26
|
-
const
|
|
35
|
+
const packageJsonContent = fs.readFileSync(packageJsonPath, "utf-8");
|
|
36
|
+
let pkg: Record<string, Record<string, string> | undefined>;
|
|
37
|
+
try {
|
|
38
|
+
pkg = JSON.parse(packageJsonContent);
|
|
39
|
+
} catch {
|
|
40
|
+
logPackageJsonParseError(packageJsonPath);
|
|
41
|
+
process.exit(1);
|
|
42
|
+
}
|
|
27
43
|
const sections = ["dependencies", "devDependencies"];
|
|
28
44
|
const targets: string[] = [];
|
|
29
45
|
|
|
@@ -3,6 +3,11 @@ import * as path from "node:path";
|
|
|
3
3
|
import { downloadTemplate } from "giget";
|
|
4
4
|
import { sync as globSync } from "glob";
|
|
5
5
|
import { detect } from "detect-package-manager";
|
|
6
|
+
import {
|
|
7
|
+
parse as parseJsonc,
|
|
8
|
+
printParseErrorCode,
|
|
9
|
+
type ParseError,
|
|
10
|
+
} from "jsonc-parser";
|
|
6
11
|
import { logger } from "./utils/logger";
|
|
7
12
|
import { runSpawn, SpawnExitError } from "./run-spawn";
|
|
8
13
|
|
|
@@ -205,22 +210,25 @@ export async function resolvePackageManagerForCwd(
|
|
|
205
210
|
}
|
|
206
211
|
}
|
|
207
212
|
|
|
213
|
+
export interface TransformResult {
|
|
214
|
+
registryInstallFailure?: { retryCommand: string };
|
|
215
|
+
}
|
|
216
|
+
|
|
208
217
|
export async function transformProject(
|
|
209
218
|
projectDir: string,
|
|
210
219
|
opts: TransformOptions,
|
|
211
|
-
): Promise<
|
|
220
|
+
): Promise<TransformResult> {
|
|
212
221
|
logger.step("Transforming package.json...");
|
|
213
222
|
transformPackageJson(projectDir);
|
|
214
223
|
|
|
224
|
+
logger.step("Transforming project files...");
|
|
225
|
+
transformTsConfig(projectDir);
|
|
226
|
+
transformCssFiles(projectDir);
|
|
227
|
+
|
|
215
228
|
let assistantUI: string[] | undefined;
|
|
216
229
|
let shadcnUI: string[] | undefined;
|
|
217
230
|
|
|
218
231
|
if (!opts.hasLocalComponents) {
|
|
219
|
-
logger.step("Transforming project files...");
|
|
220
|
-
|
|
221
|
-
transformTsConfig(projectDir);
|
|
222
|
-
transformCssFiles(projectDir);
|
|
223
|
-
|
|
224
232
|
const components = scanRequiredComponents(projectDir);
|
|
225
233
|
assistantUI = components.assistantUI;
|
|
226
234
|
shadcnUI = components.shadcnUI;
|
|
@@ -244,8 +252,15 @@ export async function transformProject(
|
|
|
244
252
|
const auiComponents = assistantUI.map((c) => `@assistant-ui/${c}`);
|
|
245
253
|
const components = [...allShadcn, ...auiComponents];
|
|
246
254
|
logger.step(`Installing components: ${components.join(", ")}...`);
|
|
247
|
-
await installShadcnRegistry(
|
|
255
|
+
const failure = await installShadcnRegistry(
|
|
256
|
+
projectDir,
|
|
257
|
+
components,
|
|
258
|
+
"components",
|
|
259
|
+
pm,
|
|
260
|
+
);
|
|
261
|
+
if (failure) return { registryInstallFailure: failure };
|
|
248
262
|
}
|
|
263
|
+
return {};
|
|
249
264
|
}
|
|
250
265
|
|
|
251
266
|
function transformPackageJson(projectDir: string): void {
|
|
@@ -281,6 +296,18 @@ function transformPackageJson(projectDir: string): void {
|
|
|
281
296
|
fs.writeFileSync(pkgPath, `${JSON.stringify(pkg, null, 2)}\n`);
|
|
282
297
|
}
|
|
283
298
|
|
|
299
|
+
function parseTsConfig(content: string): any {
|
|
300
|
+
const errors: ParseError[] = [];
|
|
301
|
+
const tsconfig = parseJsonc(content, errors, { allowTrailingComma: true });
|
|
302
|
+
const error = errors[0];
|
|
303
|
+
if (error) {
|
|
304
|
+
throw new SyntaxError(
|
|
305
|
+
`Invalid tsconfig.json: ${printParseErrorCode(error.error)} at offset ${error.offset}`,
|
|
306
|
+
);
|
|
307
|
+
}
|
|
308
|
+
return tsconfig;
|
|
309
|
+
}
|
|
310
|
+
|
|
284
311
|
function transformTsConfig(projectDir: string): void {
|
|
285
312
|
const tsconfigPath = path.join(projectDir, "tsconfig.json");
|
|
286
313
|
|
|
@@ -289,16 +316,33 @@ function transformTsConfig(projectDir: string): void {
|
|
|
289
316
|
}
|
|
290
317
|
|
|
291
318
|
const content = fs.readFileSync(tsconfigPath, "utf-8");
|
|
292
|
-
const tsconfig =
|
|
319
|
+
const tsconfig = parseTsConfig(content);
|
|
293
320
|
|
|
294
321
|
// Remove workspace paths
|
|
295
322
|
if (tsconfig.compilerOptions?.paths) {
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
323
|
+
const workspaceKeys = new Set([
|
|
324
|
+
"@/components/assistant-ui/*",
|
|
325
|
+
"@/components/icons/*",
|
|
326
|
+
"@/components/ui/*",
|
|
327
|
+
"@/components/ui/radix/*",
|
|
328
|
+
"@/hooks/*",
|
|
329
|
+
"@/lib/utils",
|
|
330
|
+
"@assistant-ui/ui/*",
|
|
331
|
+
]);
|
|
332
|
+
for (const [key, targets] of Object.entries(
|
|
333
|
+
tsconfig.compilerOptions.paths as Record<string, unknown>,
|
|
334
|
+
)) {
|
|
335
|
+
const targetsWorkspace =
|
|
336
|
+
Array.isArray(targets) &&
|
|
337
|
+
targets.some(
|
|
338
|
+
(target) =>
|
|
339
|
+
typeof target === "string" &&
|
|
340
|
+
(target.includes("packages/ui/") || target.startsWith("../")),
|
|
341
|
+
);
|
|
342
|
+
if (workspaceKeys.has(key) || targetsWorkspace) {
|
|
343
|
+
delete tsconfig.compilerOptions.paths[key];
|
|
344
|
+
}
|
|
345
|
+
}
|
|
302
346
|
|
|
303
347
|
if (Object.keys(tsconfig.compilerOptions.paths).length === 0) {
|
|
304
348
|
delete tsconfig.compilerOptions.paths;
|
|
@@ -428,20 +472,20 @@ async function installShadcnRegistry(
|
|
|
428
472
|
components: string[],
|
|
429
473
|
label: string,
|
|
430
474
|
pm: PackageManagerName,
|
|
431
|
-
): Promise<
|
|
475
|
+
): Promise<{ retryCommand: string } | undefined> {
|
|
432
476
|
const [cmd, dlxArgs] = dlxCommand(pm);
|
|
433
477
|
// For npm, dlxArgs may already include `--yes` for npx auto-install.
|
|
434
478
|
// The trailing `--yes` is for shadcn's own confirmation prompt.
|
|
435
|
-
const
|
|
479
|
+
const retryArgs = [...dlxArgs, "shadcn@latest", "add", ...components];
|
|
480
|
+
const addArgs = [...retryArgs, "--yes"];
|
|
436
481
|
|
|
437
482
|
try {
|
|
438
483
|
await runSpawn(cmd, addArgs, projectDir);
|
|
484
|
+
return undefined;
|
|
439
485
|
} catch (error) {
|
|
440
486
|
if (error instanceof SpawnExitError) {
|
|
441
|
-
logger.warn(
|
|
442
|
-
|
|
443
|
-
);
|
|
444
|
-
return;
|
|
487
|
+
logger.warn(`shadcn exited with code ${error.code}.`);
|
|
488
|
+
return { retryCommand: `${cmd} ${retryArgs.join(" ")}` };
|
|
445
489
|
}
|
|
446
490
|
|
|
447
491
|
const message = error instanceof Error ? error.message : String(error);
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import * as fs from "node:fs";
|
|
2
|
+
import * as os from "node:os";
|
|
3
|
+
import * as path from "node:path";
|
|
4
|
+
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
|
5
|
+
import {
|
|
6
|
+
getComponentsJsonStyle,
|
|
7
|
+
resolveQuickStartRegistryUrl,
|
|
8
|
+
resolveRegistryItemUrl,
|
|
9
|
+
} from "./registry";
|
|
10
|
+
|
|
11
|
+
describe("getComponentsJsonStyle", () => {
|
|
12
|
+
let cwd: string;
|
|
13
|
+
|
|
14
|
+
beforeEach(() => {
|
|
15
|
+
cwd = fs.mkdtempSync(path.join(os.tmpdir(), "assistant-ui-cli-"));
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
afterEach(() => {
|
|
19
|
+
fs.rmSync(cwd, { recursive: true, force: true });
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it("reads the style from components.json", () => {
|
|
23
|
+
fs.writeFileSync(
|
|
24
|
+
path.join(cwd, "components.json"),
|
|
25
|
+
JSON.stringify({ style: "base-nova" }),
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
expect(getComponentsJsonStyle(cwd)).toBe("base-nova");
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it("ignores a stale assistant-ui.json", () => {
|
|
32
|
+
fs.writeFileSync(
|
|
33
|
+
path.join(cwd, "assistant-ui.json"),
|
|
34
|
+
JSON.stringify({ style: "new-york" }),
|
|
35
|
+
);
|
|
36
|
+
fs.writeFileSync(
|
|
37
|
+
path.join(cwd, "components.json"),
|
|
38
|
+
JSON.stringify({ style: "base-nova" }),
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
expect(getComponentsJsonStyle(cwd)).toBe("base-nova");
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it("falls back when components.json is missing", () => {
|
|
45
|
+
expect(getComponentsJsonStyle(cwd)).toBeUndefined();
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it("falls back when components.json cannot be parsed", () => {
|
|
49
|
+
fs.writeFileSync(path.join(cwd, "components.json"), "{");
|
|
50
|
+
|
|
51
|
+
expect(getComponentsJsonStyle(cwd)).toBeUndefined();
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it("falls back when the style is not a string", () => {
|
|
55
|
+
fs.writeFileSync(
|
|
56
|
+
path.join(cwd, "components.json"),
|
|
57
|
+
JSON.stringify({ style: 7 }),
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
expect(getComponentsJsonStyle(cwd)).toBeUndefined();
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
describe("resolveQuickStartRegistryUrl", () => {
|
|
65
|
+
it("uses the base quick start for base styles", () => {
|
|
66
|
+
expect(resolveQuickStartRegistryUrl("base-nova")).toBe(
|
|
67
|
+
"https://r.assistant-ui.com/base/chat/b/ai-sdk-quick-start/json",
|
|
68
|
+
);
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it("uses the radix quick start for radix styles", () => {
|
|
72
|
+
expect(resolveQuickStartRegistryUrl("radix-nova")).toBe(
|
|
73
|
+
"https://r.assistant-ui.com/chat/b/ai-sdk-quick-start/json",
|
|
74
|
+
);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it("uses the base quick start without a style", () => {
|
|
78
|
+
expect(resolveQuickStartRegistryUrl()).toBe(
|
|
79
|
+
"https://r.assistant-ui.com/base/chat/b/ai-sdk-quick-start/json",
|
|
80
|
+
);
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
describe("resolveRegistryItemUrl", () => {
|
|
85
|
+
it("uses the style scoped URL for base styles", () => {
|
|
86
|
+
expect(resolveRegistryItemUrl("thread", "base-nova")).toBe(
|
|
87
|
+
"https://r.assistant-ui.com/styles/base-nova/thread.json",
|
|
88
|
+
);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it("uses the plain URL for non-base styles", () => {
|
|
92
|
+
expect(resolveRegistryItemUrl("thread", "nova")).toBe(
|
|
93
|
+
"https://r.assistant-ui.com/thread.json",
|
|
94
|
+
);
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it("uses the base URL without a style", () => {
|
|
98
|
+
expect(resolveRegistryItemUrl("thread")).toBe(
|
|
99
|
+
"https://r.assistant-ui.com/base/thread.json",
|
|
100
|
+
);
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
it("uses the base URL for an explicit undefined style", () => {
|
|
104
|
+
expect(resolveRegistryItemUrl("thread", undefined)).toBe(
|
|
105
|
+
"https://r.assistant-ui.com/base/thread.json",
|
|
106
|
+
);
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
it("keeps the style inside a single path segment", () => {
|
|
110
|
+
expect(resolveRegistryItemUrl("thread", "base-nova?preview=1")).toBe(
|
|
111
|
+
"https://r.assistant-ui.com/styles/base-nova%3Fpreview%3D1/thread.json",
|
|
112
|
+
);
|
|
113
|
+
});
|
|
114
|
+
});
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import * as fs from "node:fs";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
|
|
4
|
+
const REGISTRY_BASE_URL = "https://r.assistant-ui.com";
|
|
5
|
+
|
|
6
|
+
export function getComponentsJsonStyle(cwd: string): string | undefined {
|
|
7
|
+
try {
|
|
8
|
+
const configPath = path.join(cwd, "components.json");
|
|
9
|
+
const config = JSON.parse(fs.readFileSync(configPath, "utf8")) as {
|
|
10
|
+
style?: unknown;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
return typeof config.style === "string" ? config.style : undefined;
|
|
14
|
+
} catch {
|
|
15
|
+
return undefined;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function resolveQuickStartRegistryUrl(style?: string): string {
|
|
20
|
+
// The shadcn CLI appends a literal /json segment to fetched URLs containing
|
|
21
|
+
// /chat/b/ unless they already end with it, so this item must use the direct
|
|
22
|
+
// tree URLs rather than the /styles/ template.
|
|
23
|
+
if (style === undefined || style.startsWith("base-")) {
|
|
24
|
+
return `${REGISTRY_BASE_URL}/base/chat/b/ai-sdk-quick-start/json`;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return `${REGISTRY_BASE_URL}/chat/b/ai-sdk-quick-start/json`;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function resolveRegistryItemUrl(
|
|
31
|
+
component: string,
|
|
32
|
+
style?: string,
|
|
33
|
+
): string {
|
|
34
|
+
if (style === undefined) {
|
|
35
|
+
return `${REGISTRY_BASE_URL}/base/${encodeURIComponent(component)}.json`;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const registryUrl = style.startsWith("base-")
|
|
39
|
+
? `${REGISTRY_BASE_URL}/styles/${encodeURIComponent(style)}`
|
|
40
|
+
: REGISTRY_BASE_URL;
|
|
41
|
+
|
|
42
|
+
return `${registryUrl}/${encodeURIComponent(component)}.json`;
|
|
43
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import * as fs from "node:fs";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
|
|
4
|
+
export function resolveRealPath(inputPath: string): string {
|
|
5
|
+
const resolved = path.resolve(inputPath);
|
|
6
|
+
|
|
7
|
+
try {
|
|
8
|
+
return fs.realpathSync(resolved);
|
|
9
|
+
} catch {
|
|
10
|
+
return resolved;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function findWorkspaceRoot(cwd: string): string | null {
|
|
15
|
+
let dir = path.resolve(cwd);
|
|
16
|
+
const root = path.parse(dir).root;
|
|
17
|
+
|
|
18
|
+
while (true) {
|
|
19
|
+
if (fs.existsSync(path.join(dir, "pnpm-workspace.yaml"))) return dir;
|
|
20
|
+
|
|
21
|
+
const pkgPath = path.join(dir, "package.json");
|
|
22
|
+
if (fs.existsSync(pkgPath)) {
|
|
23
|
+
try {
|
|
24
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf8"));
|
|
25
|
+
if (pkg.workspaces) return dir;
|
|
26
|
+
} catch {
|
|
27
|
+
// Malformed package manifests are not workspace markers.
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (dir === root) return null;
|
|
32
|
+
dir = path.dirname(dir);
|
|
33
|
+
}
|
|
34
|
+
}
|