assistant-ui 0.0.105 → 0.0.106
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/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-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 +7 -4
- 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 +12 -4
- 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 +57 -21
- 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 +12 -15
- 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/lib/agent-skill.d.ts +0 -1
- package/dist/lib/agent-skill.d.ts.map +1 -1
- package/dist/lib/create-project.d.ts.map +1 -1
- package/dist/lib/create-project.js +22 -8
- 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 +24 -0
- package/dist/lib/utils/registry.js.map +1 -0
- package/dist/program.d.ts +0 -1
- package/dist/program.d.ts.map +1 -1
- package/package.json +10 -7
- package/src/commands/add.ts +8 -3
- package/src/commands/create.ts +12 -4
- package/src/commands/doctor.ts +83 -34
- package/src/commands/info.ts +32 -26
- 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 +40 -7
- package/src/lib/utils/registry.test.ts +108 -0
- package/src/lib/utils/registry.ts +39 -0
package/src/commands/init.ts
CHANGED
|
@@ -8,35 +8,28 @@ import {
|
|
|
8
8
|
} from "../lib/create-project";
|
|
9
9
|
import { runSpawn, SpawnExitError } from "../lib/run-spawn";
|
|
10
10
|
import { logger } from "../lib/utils/logger";
|
|
11
|
+
import {
|
|
12
|
+
getComponentsJsonStyle,
|
|
13
|
+
resolveQuickStartRegistryUrl,
|
|
14
|
+
} from "../lib/utils/registry";
|
|
11
15
|
import { create } from "./create";
|
|
12
16
|
|
|
13
|
-
const DEFAULT_REGISTRY_URL =
|
|
14
|
-
"https://r.assistant-ui.com/chat/b/ai-sdk-quick-start/json";
|
|
15
|
-
|
|
16
17
|
interface ExistingProjectInitPlan {
|
|
17
|
-
initArgs: string[]
|
|
18
|
+
initArgs: string[];
|
|
18
19
|
addArgs: string[];
|
|
19
20
|
}
|
|
20
21
|
|
|
21
22
|
export function createExistingProjectInitPlan(params: {
|
|
22
23
|
yes: boolean;
|
|
23
24
|
overwrite: boolean;
|
|
24
|
-
registryUrl: string;
|
|
25
25
|
}): ExistingProjectInitPlan {
|
|
26
|
-
const { yes, overwrite
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
return { initArgs: null, addArgs };
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
const initArgs = [`shadcn@latest`, "init", "--defaults", "--yes"];
|
|
36
|
-
|
|
37
|
-
const addArgs = [`shadcn@latest`, "add", "--yes"];
|
|
26
|
+
const { yes, overwrite } = params;
|
|
27
|
+
const initArgs = yes
|
|
28
|
+
? [`shadcn@latest`, "init", "--defaults", "--yes"]
|
|
29
|
+
: [`shadcn@latest`, "init"];
|
|
30
|
+
const addArgs = [`shadcn@latest`, "add"];
|
|
31
|
+
if (yes) addArgs.push("--yes");
|
|
38
32
|
if (overwrite) addArgs.push("--overwrite");
|
|
39
|
-
addArgs.push(registryUrl);
|
|
40
33
|
|
|
41
34
|
return { initArgs, addArgs };
|
|
42
35
|
}
|
|
@@ -106,7 +99,6 @@ export const init = new Command()
|
|
|
106
99
|
return;
|
|
107
100
|
}
|
|
108
101
|
|
|
109
|
-
const registryUrl = DEFAULT_REGISTRY_URL;
|
|
110
102
|
logger.info("Initializing assistant-ui in existing project...");
|
|
111
103
|
logger.break();
|
|
112
104
|
|
|
@@ -131,13 +123,13 @@ export const init = new Command()
|
|
|
131
123
|
const { initArgs, addArgs } = createExistingProjectInitPlan({
|
|
132
124
|
yes: opts.yes,
|
|
133
125
|
overwrite: opts.overwrite,
|
|
134
|
-
registryUrl,
|
|
135
126
|
});
|
|
136
127
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
128
|
+
await runSpawn(dlxCmd, [...dlxArgs, ...initArgs], targetDir);
|
|
129
|
+
const registryUrl = resolveQuickStartRegistryUrl(
|
|
130
|
+
getComponentsJsonStyle(targetDir),
|
|
131
|
+
);
|
|
132
|
+
await runSpawn(dlxCmd, [...dlxArgs, ...addArgs, registryUrl], targetDir);
|
|
141
133
|
|
|
142
134
|
logger.break();
|
|
143
135
|
logger.success("Project initialized successfully!");
|
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
|
|
|
@@ -281,6 +286,18 @@ function transformPackageJson(projectDir: string): void {
|
|
|
281
286
|
fs.writeFileSync(pkgPath, `${JSON.stringify(pkg, null, 2)}\n`);
|
|
282
287
|
}
|
|
283
288
|
|
|
289
|
+
function parseTsConfig(content: string): any {
|
|
290
|
+
const errors: ParseError[] = [];
|
|
291
|
+
const tsconfig = parseJsonc(content, errors, { allowTrailingComma: true });
|
|
292
|
+
const error = errors[0];
|
|
293
|
+
if (error) {
|
|
294
|
+
throw new SyntaxError(
|
|
295
|
+
`Invalid tsconfig.json: ${printParseErrorCode(error.error)} at offset ${error.offset}`,
|
|
296
|
+
);
|
|
297
|
+
}
|
|
298
|
+
return tsconfig;
|
|
299
|
+
}
|
|
300
|
+
|
|
284
301
|
function transformTsConfig(projectDir: string): void {
|
|
285
302
|
const tsconfigPath = path.join(projectDir, "tsconfig.json");
|
|
286
303
|
|
|
@@ -289,16 +306,32 @@ function transformTsConfig(projectDir: string): void {
|
|
|
289
306
|
}
|
|
290
307
|
|
|
291
308
|
const content = fs.readFileSync(tsconfigPath, "utf-8");
|
|
292
|
-
const tsconfig =
|
|
309
|
+
const tsconfig = parseTsConfig(content);
|
|
293
310
|
|
|
294
311
|
// Remove workspace paths
|
|
295
312
|
if (tsconfig.compilerOptions?.paths) {
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
313
|
+
const workspaceKeys = new Set([
|
|
314
|
+
"@/components/assistant-ui/*",
|
|
315
|
+
"@/components/icons/*",
|
|
316
|
+
"@/components/ui/*",
|
|
317
|
+
"@/components/ui/radix/*",
|
|
318
|
+
"@/hooks/*",
|
|
319
|
+
"@/lib/utils",
|
|
320
|
+
"@assistant-ui/ui/*",
|
|
321
|
+
]);
|
|
322
|
+
for (const [key, targets] of Object.entries(
|
|
323
|
+
tsconfig.compilerOptions.paths as Record<string, unknown>,
|
|
324
|
+
)) {
|
|
325
|
+
const targetsWorkspace =
|
|
326
|
+
Array.isArray(targets) &&
|
|
327
|
+
targets.some(
|
|
328
|
+
(target) =>
|
|
329
|
+
typeof target === "string" && target.includes("packages/ui/"),
|
|
330
|
+
);
|
|
331
|
+
if (workspaceKeys.has(key) || targetsWorkspace) {
|
|
332
|
+
delete tsconfig.compilerOptions.paths[key];
|
|
333
|
+
}
|
|
334
|
+
}
|
|
302
335
|
|
|
303
336
|
if (Object.keys(tsconfig.compilerOptions.paths).length === 0) {
|
|
304
337
|
delete tsconfig.compilerOptions.paths;
|
|
@@ -0,0 +1,108 @@
|
|
|
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 plain URL without a style", () => {
|
|
98
|
+
expect(resolveRegistryItemUrl("thread")).toBe(
|
|
99
|
+
"https://r.assistant-ui.com/thread.json",
|
|
100
|
+
);
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
it("keeps the style inside a single path segment", () => {
|
|
104
|
+
expect(resolveRegistryItemUrl("thread", "base-nova?preview=1")).toBe(
|
|
105
|
+
"https://r.assistant-ui.com/styles/base-nova%3Fpreview%3D1/thread.json",
|
|
106
|
+
);
|
|
107
|
+
});
|
|
108
|
+
});
|
|
@@ -0,0 +1,39 @@
|
|
|
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
|
+
const registryUrl = style?.startsWith("base-")
|
|
35
|
+
? `${REGISTRY_BASE_URL}/styles/${encodeURIComponent(style)}`
|
|
36
|
+
: REGISTRY_BASE_URL;
|
|
37
|
+
|
|
38
|
+
return `${registryUrl}/${encodeURIComponent(component)}.json`;
|
|
39
|
+
}
|