assistant-ui 0.0.114 → 0.0.116

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 (43) hide show
  1. package/dist/codemods/v0-12/assistant-api-to-aui.js +1 -0
  2. package/dist/codemods/v0-12/assistant-api-to-aui.js.map +1 -1
  3. package/dist/codemods/v0-12/primitive-if-to-aui-if.d.ts.map +1 -1
  4. package/dist/codemods/v0-12/primitive-if-to-aui-if.js +7 -5
  5. package/dist/codemods/v0-12/primitive-if-to-aui-if.js.map +1 -1
  6. package/dist/commands/add.d.ts +1 -1
  7. package/dist/commands/add.d.ts.map +1 -1
  8. package/dist/commands/add.js +8 -7
  9. package/dist/commands/add.js.map +1 -1
  10. package/dist/commands/create.d.ts +9 -1
  11. package/dist/commands/create.d.ts.map +1 -1
  12. package/dist/commands/create.js +25 -8
  13. package/dist/commands/create.js.map +1 -1
  14. package/dist/commands/info.d.ts.map +1 -1
  15. package/dist/commands/info.js +0 -1
  16. package/dist/commands/info.js.map +1 -1
  17. package/dist/commands/init.js +2 -2
  18. package/dist/commands/init.js.map +1 -1
  19. package/dist/commands/mcp.d.ts.map +1 -1
  20. package/dist/commands/mcp.js +0 -1
  21. package/dist/commands/mcp.js.map +1 -1
  22. package/dist/lib/create-project.d.ts +7 -1
  23. package/dist/lib/create-project.d.ts.map +1 -1
  24. package/dist/lib/create-project.js +27 -18
  25. package/dist/lib/create-project.js.map +1 -1
  26. package/dist/lib/utils/registry.d.ts +4 -2
  27. package/dist/lib/utils/registry.d.ts.map +1 -1
  28. package/dist/lib/utils/registry.js +13 -2
  29. package/dist/lib/utils/registry.js.map +1 -1
  30. package/package.json +6 -6
  31. package/src/codemods/v0-12/__tests__/primitive-if-to-aui-if.test.ts +48 -1
  32. package/src/codemods/v0-12/assistant-api-to-aui.ts +4 -1
  33. package/src/codemods/v0-12/primitive-if-to-aui-if.ts +18 -7
  34. package/src/commands/add.ts +10 -6
  35. package/src/commands/create.ts +47 -8
  36. package/src/commands/info.ts +0 -1
  37. package/src/commands/init.ts +1 -1
  38. package/src/commands/mcp.ts +0 -3
  39. package/src/lib/create-project.ts +35 -20
  40. package/src/lib/run-spawn.test.ts +0 -1
  41. package/src/lib/utils/registry.test.ts +56 -0
  42. package/src/lib/utils/registry.ts +35 -0
  43. package/src/run.test.ts +1 -5
@@ -10,6 +10,10 @@ import { logger } from "./utils/logger";
10
10
  import { runSpawn, SpawnExitError, SpawnSignalError } from "./run-spawn";
11
11
  import { type PackageManagerName } from "./utils/package-manager";
12
12
  import { readProjectFiles } from "./utils/file-scanner";
13
+ import {
14
+ detectRegistryPlatform,
15
+ resolveRegistryItemUrl,
16
+ } from "./utils/registry";
13
17
 
14
18
  export function dlxCommand(pm: PackageManagerName): [string, string[]] {
15
19
  switch (pm) {
@@ -186,6 +190,7 @@ export async function scaffoldProject(
186
190
 
187
191
  export interface TransformResult {
188
192
  registryInstallFailure?: { retryCommand: string };
193
+ registryInstallCommand?: string;
189
194
  }
190
195
 
191
196
  export async function transformProject(
@@ -199,29 +204,23 @@ export async function transformProject(
199
204
  transformTsConfig(projectDir);
200
205
  transformCssFiles(projectDir);
201
206
 
202
- let assistantUI: string[] | undefined;
203
- let shadcnUI: string[] | undefined;
204
-
205
- if (!opts.hasLocalComponents) {
206
- const components = scanRequiredComponents(projectDir);
207
- assistantUI = components.assistantUI;
208
- shadcnUI = components.shadcnUI;
209
- }
207
+ const components = opts.hasLocalComponents
208
+ ? undefined
209
+ : resolveRegistryComponents(projectDir, scanRequiredComponents(projectDir));
210
210
 
211
211
  const pm = opts.packageManager;
212
- if (!opts.skipInstall) {
213
- logger.step("Installing dependencies...");
214
- await installDependencies(projectDir, pm);
212
+ if (opts.skipInstall) {
213
+ if (!components) return {};
214
+ const [cmd, dlxArgs] = dlxCommand(pm);
215
+ return {
216
+ registryInstallCommand: `${cmd} ${[...dlxArgs, "shadcn@latest", "add", ...components].join(" ")}`,
217
+ };
215
218
  }
216
219
 
217
- if (
218
- !opts.skipInstall &&
219
- !opts.hasLocalComponents &&
220
- shadcnUI &&
221
- assistantUI
222
- ) {
223
- const auiComponents = assistantUI.map((c) => `@assistant-ui/${c}`);
224
- const components = ["@assistant-ui/utils", ...shadcnUI, ...auiComponents];
220
+ logger.step("Installing dependencies...");
221
+ await installDependencies(projectDir, pm);
222
+
223
+ if (components) {
225
224
  logger.step(`Installing components: ${components.join(", ")}...`);
226
225
  const failure = await installShadcnRegistry(
227
226
  projectDir,
@@ -235,6 +234,22 @@ export async function transformProject(
235
234
  return {};
236
235
  }
237
236
 
237
+ function resolveRegistryComponents(
238
+ projectDir: string,
239
+ { assistantUI, shadcnUI }: RequiredComponents,
240
+ ): string[] {
241
+ if (detectRegistryPlatform(projectDir) === "native") {
242
+ return ["utils", ...shadcnUI, ...assistantUI].map((component) =>
243
+ resolveRegistryItemUrl(component, undefined, "native"),
244
+ );
245
+ }
246
+ return [
247
+ "@assistant-ui/utils",
248
+ ...shadcnUI,
249
+ ...assistantUI.map((component) => `@assistant-ui/${component}`),
250
+ ];
251
+ }
252
+
238
253
  function transformPackageJson(projectDir: string): void {
239
254
  const pkgPath = path.join(projectDir, "package.json");
240
255
  const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
@@ -543,7 +558,7 @@ export async function reconcileAssistantUIImportLayout(
543
558
  }
544
559
  }
545
560
 
546
- function scanRequiredComponents(projectDir: string): RequiredComponents {
561
+ export function scanRequiredComponents(projectDir: string): RequiredComponents {
547
562
  const assistantUIComponents = new Set<string>();
548
563
  const shadcnUIComponents = new Set<string>();
549
564
 
@@ -36,7 +36,6 @@ const trackSignal = (signal: NodeJS.Signals) => {
36
36
  describe("runSpawn", () => {
37
37
  afterEach(() => {
38
38
  vi.restoreAllMocks();
39
- vi.clearAllMocks();
40
39
  });
41
40
 
42
41
  it("forwards the first termination signal and cleans up listeners", async () => {
@@ -3,6 +3,7 @@ import * as os from "node:os";
3
3
  import * as path from "node:path";
4
4
  import { afterEach, beforeEach, describe, expect, it } from "vitest";
5
5
  import {
6
+ detectRegistryPlatform,
6
7
  getComponentsJsonStyle,
7
8
  resolveQuickStartRegistryUrl,
8
9
  resolveRegistryItemUrl,
@@ -61,6 +62,49 @@ describe("getComponentsJsonStyle", () => {
61
62
  });
62
63
  });
63
64
 
65
+ describe("detectRegistryPlatform", () => {
66
+ let cwd: string;
67
+
68
+ beforeEach(() => {
69
+ cwd = fs.mkdtempSync(path.join(os.tmpdir(), "assistant-ui-cli-"));
70
+ });
71
+
72
+ afterEach(() => {
73
+ fs.rmSync(cwd, { recursive: true, force: true });
74
+ });
75
+
76
+ it("detects react-native in dependencies", () => {
77
+ fs.writeFileSync(
78
+ path.join(cwd, "package.json"),
79
+ JSON.stringify({ dependencies: { "react-native": "0.86.3" } }),
80
+ );
81
+
82
+ expect(detectRegistryPlatform(cwd)).toBe("native");
83
+ });
84
+
85
+ it("detects react-native in devDependencies", () => {
86
+ fs.writeFileSync(
87
+ path.join(cwd, "package.json"),
88
+ JSON.stringify({ devDependencies: { "react-native": "0.86.3" } }),
89
+ );
90
+
91
+ expect(detectRegistryPlatform(cwd)).toBe("native");
92
+ });
93
+
94
+ it("uses web without react-native", () => {
95
+ fs.writeFileSync(
96
+ path.join(cwd, "package.json"),
97
+ JSON.stringify({ dependencies: { react: "19.2.3" } }),
98
+ );
99
+
100
+ expect(detectRegistryPlatform(cwd)).toBe("web");
101
+ });
102
+
103
+ it("uses web when package.json is missing", () => {
104
+ expect(detectRegistryPlatform(cwd)).toBe("web");
105
+ });
106
+ });
107
+
64
108
  describe("resolveQuickStartRegistryUrl", () => {
65
109
  it("uses the base quick start for base styles", () => {
66
110
  expect(resolveQuickStartRegistryUrl("base-nova")).toBe(
@@ -111,4 +155,16 @@ describe("resolveRegistryItemUrl", () => {
111
155
  "https://r.assistant-ui.com/styles/base-nova%3Fpreview%3D1/thread.json",
112
156
  );
113
157
  });
158
+
159
+ it("uses the native URL regardless of style", () => {
160
+ expect(resolveRegistryItemUrl("thread", "base-nova", "native")).toBe(
161
+ "https://r.assistant-ui.com/native/thread.json",
162
+ );
163
+ });
164
+
165
+ it("keeps shared items at the root URL on native", () => {
166
+ expect(resolveRegistryItemUrl("utils", undefined, "native")).toBe(
167
+ "https://r.assistant-ui.com/utils.json",
168
+ );
169
+ });
114
170
  });
@@ -2,6 +2,34 @@ import * as fs from "node:fs";
2
2
  import * as path from "node:path";
3
3
 
4
4
  const REGISTRY_BASE_URL = "https://r.assistant-ui.com";
5
+ export const SHARED_REGISTRY_ITEMS = new Set(["utils"]);
6
+
7
+ export function detectRegistryPlatform(cwd: string): "web" | "native" {
8
+ try {
9
+ const packageJsonPath = path.join(cwd, "package.json");
10
+ const packageJson = JSON.parse(
11
+ fs.readFileSync(packageJsonPath, "utf8"),
12
+ ) as {
13
+ dependencies?: unknown;
14
+ devDependencies?: unknown;
15
+ };
16
+ const dependencyGroups = [
17
+ packageJson.dependencies,
18
+ packageJson.devDependencies,
19
+ ];
20
+
21
+ return dependencyGroups.some(
22
+ (dependencies) =>
23
+ typeof dependencies === "object" &&
24
+ dependencies !== null &&
25
+ Object.hasOwn(dependencies, "react-native"),
26
+ )
27
+ ? "native"
28
+ : "web";
29
+ } catch {
30
+ return "web";
31
+ }
32
+ }
5
33
 
6
34
  export function getComponentsJsonStyle(cwd: string): string | undefined {
7
35
  try {
@@ -30,7 +58,14 @@ export function resolveQuickStartRegistryUrl(style?: string): string {
30
58
  export function resolveRegistryItemUrl(
31
59
  component: string,
32
60
  style?: string,
61
+ platform: "web" | "native" = "web",
33
62
  ): string {
63
+ if (platform === "native") {
64
+ return SHARED_REGISTRY_ITEMS.has(component)
65
+ ? `${REGISTRY_BASE_URL}/${encodeURIComponent(component)}.json`
66
+ : `${REGISTRY_BASE_URL}/native/${encodeURIComponent(component)}.json`;
67
+ }
68
+
34
69
  if (style === undefined) {
35
70
  return `${REGISTRY_BASE_URL}/base/${encodeURIComponent(component)}.json`;
36
71
  }
package/src/run.test.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { beforeEach, describe, expect, it, vi } from "vitest";
1
+ import { describe, expect, it, vi } from "vitest";
2
2
 
3
3
  const mocks = vi.hoisted(() => ({
4
4
  parseAsync: vi.fn(),
@@ -13,10 +13,6 @@ vi.mock("./program", () => ({
13
13
  import { runCli } from "./run";
14
14
 
15
15
  describe("runCli", () => {
16
- beforeEach(() => {
17
- vi.clearAllMocks();
18
- });
19
-
20
16
  it("awaits and propagates asynchronous command failures", async () => {
21
17
  const error = new Error("command failed");
22
18
  mocks.parseAsync.mockRejectedValue(error);