assistant-ui 0.0.106 → 0.0.108
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/dist/codemods/v0-12/assistant-api-to-aui.js.map +1 -1
- package/dist/codemods/v0-15/aui-accessor-calls-to-properties.d.ts +5 -0
- package/dist/codemods/v0-15/aui-accessor-calls-to-properties.d.ts.map +1 -0
- package/dist/codemods/v0-15/aui-accessor-calls-to-properties.js +58 -0
- package/dist/codemods/v0-15/aui-accessor-calls-to-properties.js.map +1 -0
- package/dist/codemods/v0-8/ui-package-split.js.map +1 -1
- package/dist/commands/add.js +1 -1
- package/dist/commands/add.js.map +1 -1
- package/dist/commands/create.d.ts.map +1 -1
- package/dist/commands/create.js +14 -4
- package/dist/commands/create.js.map +1 -1
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +11 -10
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/info.d.ts +1 -1
- package/dist/commands/info.d.ts.map +1 -1
- package/dist/commands/info.js +13 -14
- package/dist/commands/info.js.map +1 -1
- package/dist/commands/upgrade.js +2 -2
- package/dist/commands/upgrade.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +5 -5
- package/dist/index.js.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 +13 -10
- package/dist/lib/create-project.js.map +1 -1
- package/dist/lib/run-spawn.d.ts.map +1 -1
- package/dist/lib/upgrade.d.ts.map +1 -1
- package/dist/lib/upgrade.js +2 -1
- package/dist/lib/upgrade.js.map +1 -1
- package/dist/lib/utils/logger.d.ts.map +1 -1
- package/dist/lib/utils/registry.js +2 -1
- package/dist/lib/utils/registry.js.map +1 -1
- 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/run.d.ts +5 -0
- package/dist/run.d.ts.map +1 -0
- package/dist/run.js +9 -0
- package/dist/run.js.map +1 -0
- package/package.json +4 -4
- package/plugin/skills/assistant-ui/SKILL.md +24 -5
- package/src/codemods/v0-15/__tests__/aui-accessor-calls-to-properties.test.ts +109 -0
- package/src/codemods/v0-15/aui-accessor-calls-to-properties.ts +83 -0
- package/src/commands/add.ts +1 -1
- package/src/commands/create.ts +16 -4
- package/src/commands/doctor.ts +17 -13
- package/src/commands/info.ts +21 -20
- package/src/commands/upgrade.ts +2 -2
- package/src/index.ts +5 -6
- package/src/lib/create-project.ts +25 -14
- package/src/lib/upgrade.ts +1 -0
- package/src/lib/utils/registry.test.ts +8 -2
- package/src/lib/utils/registry.ts +5 -1
- package/src/lib/utils/workspace.ts +34 -0
- package/src/run.test.ts +27 -0
- package/src/run.ts +5 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.js","names":["path","fs"],"sources":["../../../src/lib/utils/registry.ts"],"sourcesContent":["import * as fs from \"node:fs\";\nimport * as path from \"node:path\";\n\nconst REGISTRY_BASE_URL = \"https://r.assistant-ui.com\";\n\nexport function getComponentsJsonStyle(cwd: string): string | undefined {\n try {\n const configPath = path.join(cwd, \"components.json\");\n const config = JSON.parse(fs.readFileSync(configPath, \"utf8\")) as {\n style?: unknown;\n };\n\n return typeof config.style === \"string\" ? config.style : undefined;\n } catch {\n return undefined;\n }\n}\n\nexport function resolveQuickStartRegistryUrl(style?: string): string {\n // The shadcn CLI appends a literal /json segment to fetched URLs containing\n // /chat/b/ unless they already end with it, so this item must use the direct\n // tree URLs rather than the /styles/ template.\n if (style === undefined || style.startsWith(\"base-\")) {\n return `${REGISTRY_BASE_URL}/base/chat/b/ai-sdk-quick-start/json`;\n }\n\n return `${REGISTRY_BASE_URL}/chat/b/ai-sdk-quick-start/json`;\n}\n\nexport function resolveRegistryItemUrl(\n component: string,\n style?: string,\n): string {\n const registryUrl = style
|
|
1
|
+
{"version":3,"file":"registry.js","names":["path","fs"],"sources":["../../../src/lib/utils/registry.ts"],"sourcesContent":["import * as fs from \"node:fs\";\nimport * as path from \"node:path\";\n\nconst REGISTRY_BASE_URL = \"https://r.assistant-ui.com\";\n\nexport function getComponentsJsonStyle(cwd: string): string | undefined {\n try {\n const configPath = path.join(cwd, \"components.json\");\n const config = JSON.parse(fs.readFileSync(configPath, \"utf8\")) as {\n style?: unknown;\n };\n\n return typeof config.style === \"string\" ? config.style : undefined;\n } catch {\n return undefined;\n }\n}\n\nexport function resolveQuickStartRegistryUrl(style?: string): string {\n // The shadcn CLI appends a literal /json segment to fetched URLs containing\n // /chat/b/ unless they already end with it, so this item must use the direct\n // tree URLs rather than the /styles/ template.\n if (style === undefined || style.startsWith(\"base-\")) {\n return `${REGISTRY_BASE_URL}/base/chat/b/ai-sdk-quick-start/json`;\n }\n\n return `${REGISTRY_BASE_URL}/chat/b/ai-sdk-quick-start/json`;\n}\n\nexport function resolveRegistryItemUrl(\n component: string,\n style?: string,\n): string {\n if (style === undefined) {\n return `${REGISTRY_BASE_URL}/base/${encodeURIComponent(component)}.json`;\n }\n\n const registryUrl = style.startsWith(\"base-\")\n ? `${REGISTRY_BASE_URL}/styles/${encodeURIComponent(style)}`\n : REGISTRY_BASE_URL;\n\n return `${registryUrl}/${encodeURIComponent(component)}.json`;\n}\n"],"mappings":";;;AAGA,MAAM,oBAAoB;AAE1B,SAAgB,uBAAuB,KAAiC;CACtE,IAAI;EACF,MAAM,aAAaA,OAAK,KAAK,KAAK,iBAAiB;EACnD,MAAM,SAAS,KAAK,MAAMC,KAAG,aAAa,YAAY,MAAM,CAAC;EAI7D,OAAO,OAAO,OAAO,UAAU,WAAW,OAAO,QAAQ,KAAA;CAC3D,QAAQ;EACN;CACF;AACF;AAEA,SAAgB,6BAA6B,OAAwB;CAInE,IAAI,UAAU,KAAA,KAAa,MAAM,WAAW,OAAO,GACjD,OAAO,GAAG,kBAAkB;CAG9B,OAAO,GAAG,kBAAkB;AAC9B;AAEA,SAAgB,uBACd,WACA,OACQ;CACR,IAAI,UAAU,KAAA,GACZ,OAAO,GAAG,kBAAkB,QAAQ,mBAAmB,SAAS,EAAE;CAOpE,OAAO,GAJa,MAAM,WAAW,OAAO,IACxC,GAAG,kBAAkB,UAAU,mBAAmB,KAAK,MACvD,kBAEkB,GAAG,mBAAmB,SAAS,EAAE;AACzD"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
//#region src/lib/utils/workspace.d.ts
|
|
2
|
+
declare function resolveRealPath(inputPath: string): string;
|
|
3
|
+
declare function findWorkspaceRoot(cwd: string): string | null;
|
|
4
|
+
//#endregion
|
|
5
|
+
export { findWorkspaceRoot, resolveRealPath };
|
|
6
|
+
//# sourceMappingURL=workspace.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workspace.d.ts","names":[],"sources":["../../../src/lib/utils/workspace.ts"],"mappings":";iBAGgB,gBAAgB;iBAUhB,kBAAkB"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import * as fs$1 from "node:fs";
|
|
2
|
+
import * as path$1 from "node:path";
|
|
3
|
+
//#region src/lib/utils/workspace.ts
|
|
4
|
+
function resolveRealPath(inputPath) {
|
|
5
|
+
const resolved = path$1.resolve(inputPath);
|
|
6
|
+
try {
|
|
7
|
+
return fs$1.realpathSync(resolved);
|
|
8
|
+
} catch {
|
|
9
|
+
return resolved;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
function findWorkspaceRoot(cwd) {
|
|
13
|
+
let dir = path$1.resolve(cwd);
|
|
14
|
+
const root = path$1.parse(dir).root;
|
|
15
|
+
while (true) {
|
|
16
|
+
if (fs$1.existsSync(path$1.join(dir, "pnpm-workspace.yaml"))) return dir;
|
|
17
|
+
const pkgPath = path$1.join(dir, "package.json");
|
|
18
|
+
if (fs$1.existsSync(pkgPath)) try {
|
|
19
|
+
if (JSON.parse(fs$1.readFileSync(pkgPath, "utf8")).workspaces) return dir;
|
|
20
|
+
} catch {}
|
|
21
|
+
if (dir === root) return null;
|
|
22
|
+
dir = path$1.dirname(dir);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
//#endregion
|
|
26
|
+
export { findWorkspaceRoot, resolveRealPath };
|
|
27
|
+
|
|
28
|
+
//# sourceMappingURL=workspace.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workspace.js","names":["path","fs"],"sources":["../../../src/lib/utils/workspace.ts"],"sourcesContent":["import * as fs from \"node:fs\";\nimport * as path from \"node:path\";\n\nexport function resolveRealPath(inputPath: string): string {\n const resolved = path.resolve(inputPath);\n\n try {\n return fs.realpathSync(resolved);\n } catch {\n return resolved;\n }\n}\n\nexport function findWorkspaceRoot(cwd: string): string | null {\n let dir = path.resolve(cwd);\n const root = path.parse(dir).root;\n\n while (true) {\n if (fs.existsSync(path.join(dir, \"pnpm-workspace.yaml\"))) return dir;\n\n const pkgPath = path.join(dir, \"package.json\");\n if (fs.existsSync(pkgPath)) {\n try {\n const pkg = JSON.parse(fs.readFileSync(pkgPath, \"utf8\"));\n if (pkg.workspaces) return dir;\n } catch {\n // Malformed package manifests are not workspace markers.\n }\n }\n\n if (dir === root) return null;\n dir = path.dirname(dir);\n }\n}\n"],"mappings":";;;AAGA,SAAgB,gBAAgB,WAA2B;CACzD,MAAM,WAAWA,OAAK,QAAQ,SAAS;CAEvC,IAAI;EACF,OAAOC,KAAG,aAAa,QAAQ;CACjC,QAAQ;EACN,OAAO;CACT;AACF;AAEA,SAAgB,kBAAkB,KAA4B;CAC5D,IAAI,MAAMD,OAAK,QAAQ,GAAG;CAC1B,MAAM,OAAOA,OAAK,MAAM,GAAG,CAAC,CAAC;CAE7B,OAAO,MAAM;EACX,IAAIC,KAAG,WAAWD,OAAK,KAAK,KAAK,qBAAqB,CAAC,GAAG,OAAO;EAEjE,MAAM,UAAUA,OAAK,KAAK,KAAK,cAAc;EAC7C,IAAIC,KAAG,WAAW,OAAO,GACvB,IAAI;GAEF,IADY,KAAK,MAAMA,KAAG,aAAa,SAAS,MAAM,CAChD,CAAC,CAAC,YAAY,OAAO;EAC7B,QAAQ,CAER;EAGF,IAAI,QAAQ,MAAM,OAAO;EACzB,MAAMD,OAAK,QAAQ,GAAG;CACxB;AACF"}
|
package/dist/run.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run.d.ts","names":[],"sources":["../src/run.ts"],"mappings":";iBAEsB,UAAU"}
|
package/dist/run.js
ADDED
package/dist/run.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run.js","names":[],"sources":["../src/run.ts"],"sourcesContent":["import { buildProgram } from \"./program\";\n\nexport async function runCli(): Promise<void> {\n await buildProgram().parseAsync();\n}\n"],"mappings":";;AAEA,eAAsB,SAAwB;CAC5C,MAAM,aAAa,CAAC,CAAC,WAAW;AAClC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "assistant-ui",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.108",
|
|
4
4
|
"description": "CLI for assistant-ui",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cli",
|
|
@@ -33,9 +33,9 @@
|
|
|
33
33
|
"cross-spawn": "^7.0.6",
|
|
34
34
|
"debug": "^4.4.3",
|
|
35
35
|
"detect-package-manager": "^3.0.2",
|
|
36
|
-
"giget": "^3.3.
|
|
36
|
+
"giget": "^3.3.1",
|
|
37
37
|
"glob": "^13.0.6",
|
|
38
|
-
"jscodeshift": "^17.
|
|
38
|
+
"jscodeshift": "^17.4.0",
|
|
39
39
|
"jsonc-parser": "^3.3.1",
|
|
40
40
|
"semver": "^7.8.5",
|
|
41
41
|
"@assistant-ui/agent-launcher": "0.1.9"
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
"@types/semver": "^7.7.1",
|
|
50
50
|
"@vitest/coverage-v8": "^4.1.10",
|
|
51
51
|
"vitest": "^4.1.10",
|
|
52
|
-
"@assistant-ui/x-buildutils": "0.0.
|
|
52
|
+
"@assistant-ui/x-buildutils": "0.0.20"
|
|
53
53
|
},
|
|
54
54
|
"publishConfig": {
|
|
55
55
|
"access": "public",
|
|
@@ -24,20 +24,39 @@ This initializes shadcn and installs the default assistant-ui chat components.
|
|
|
24
24
|
Install components via the shadcn registry:
|
|
25
25
|
|
|
26
26
|
```bash
|
|
27
|
-
npx shadcn@latest add "https://r.assistant-ui.com/chat/b/ai-sdk-quick-start/json"
|
|
27
|
+
npx shadcn@latest add "https://r.assistant-ui.com/base/chat/b/ai-sdk-quick-start/json"
|
|
28
28
|
```
|
|
29
29
|
|
|
30
|
+
For Radix-styled projects (`components.json` style not starting with `base-`), use `https://r.assistant-ui.com/chat/b/ai-sdk-quick-start/json` instead.
|
|
31
|
+
|
|
30
32
|
Available component presets:
|
|
31
33
|
|
|
32
34
|
| Preset | Registry URL |
|
|
33
35
|
|--------|-------------|
|
|
34
|
-
| AI SDK Quick Start | `https://r.assistant-ui.com/chat/b/ai-sdk-quick-start/json` |
|
|
36
|
+
| AI SDK Quick Start | `https://r.assistant-ui.com/base/chat/b/ai-sdk-quick-start/json` |
|
|
37
|
+
|
|
38
|
+
You can also add individual assistant-ui components with the assistant-ui CLI, which picks the right flavor from `components.json`:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
npx assistant-ui add thread
|
|
42
|
+
npx assistant-ui add markdown-text
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
To use the shadcn CLI directly instead, add the assistant-ui registry to `components.json`:
|
|
46
|
+
|
|
47
|
+
```json
|
|
48
|
+
{
|
|
49
|
+
"registries": {
|
|
50
|
+
"@assistant-ui": "https://r.assistant-ui.com/styles/{style}/{name}.json"
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
```
|
|
35
54
|
|
|
36
|
-
|
|
55
|
+
Then add components with the namespaced form:
|
|
37
56
|
|
|
38
57
|
```bash
|
|
39
|
-
npx shadcn@latest add assistant-ui/thread
|
|
40
|
-
npx shadcn@latest add assistant-ui/markdown-text
|
|
58
|
+
npx shadcn@latest add @assistant-ui/thread
|
|
59
|
+
npx shadcn@latest add @assistant-ui/markdown-text
|
|
41
60
|
```
|
|
42
61
|
|
|
43
62
|
## Step 3: Runtime Setup
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import jscodeshift, { type API } from "jscodeshift";
|
|
3
|
+
import transform from "../aui-accessor-calls-to-properties";
|
|
4
|
+
|
|
5
|
+
const j = jscodeshift.withParser("tsx");
|
|
6
|
+
|
|
7
|
+
function applyTransform(source: string): string | null {
|
|
8
|
+
const fileInfo = {
|
|
9
|
+
path: "test.tsx",
|
|
10
|
+
source,
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
const api: API = {
|
|
14
|
+
jscodeshift: j,
|
|
15
|
+
j,
|
|
16
|
+
stats: () => {},
|
|
17
|
+
report: () => {},
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
return transform(fileInfo, api, {});
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
describe("aui-accessor-calls-to-properties", () => {
|
|
24
|
+
it("rewrites nullary accessor calls on a useAui variable", () => {
|
|
25
|
+
const input = `
|
|
26
|
+
const client = useAui();
|
|
27
|
+
client.thread().cancelRun();
|
|
28
|
+
const state = client.composer().getState();
|
|
29
|
+
`;
|
|
30
|
+
const expected = `
|
|
31
|
+
const client = useAui();
|
|
32
|
+
client.thread.cancelRun();
|
|
33
|
+
const state = client.composer.getState();
|
|
34
|
+
`;
|
|
35
|
+
expect(applyTransform(input)?.trim()).toBe(expected.trim());
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it("rewrites only the accessor call in chained expressions", () => {
|
|
39
|
+
const input = `
|
|
40
|
+
const aui = useAui();
|
|
41
|
+
const part = aui.message().part({ index: 0 });
|
|
42
|
+
aui.message().composer().send();
|
|
43
|
+
`;
|
|
44
|
+
const expected = `
|
|
45
|
+
const aui = useAui();
|
|
46
|
+
const part = aui.message.part({ index: 0 });
|
|
47
|
+
aui.message.composer().send();
|
|
48
|
+
`;
|
|
49
|
+
expect(applyTransform(input)?.trim()).toBe(expected.trim());
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it("rewrites identifiers named aui without a declaration", () => {
|
|
53
|
+
const input = `
|
|
54
|
+
const Derived = {
|
|
55
|
+
get: (aui) => aui.thread().message({ index: 0 }),
|
|
56
|
+
};
|
|
57
|
+
`;
|
|
58
|
+
const expected = `
|
|
59
|
+
const Derived = {
|
|
60
|
+
get: (aui) => aui.thread.message({ index: 0 }),
|
|
61
|
+
};
|
|
62
|
+
`;
|
|
63
|
+
expect(applyTransform(input)?.trim()).toBe(expected.trim());
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it("rewrites parameters typed AssistantClient", () => {
|
|
67
|
+
const input = `
|
|
68
|
+
const getItem = (client: AssistantClient) => client.threadListItem().getState();
|
|
69
|
+
`;
|
|
70
|
+
const expected = `
|
|
71
|
+
const getItem = (client: AssistantClient) => client.threadListItem.getState();
|
|
72
|
+
`;
|
|
73
|
+
expect(applyTransform(input)?.trim()).toBe(expected.trim());
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it("leaves calls with arguments untouched", () => {
|
|
77
|
+
const input = `
|
|
78
|
+
const aui = useAui();
|
|
79
|
+
const t = aui.threads().thread({ id: "t1" });
|
|
80
|
+
`;
|
|
81
|
+
const expected = `
|
|
82
|
+
const aui = useAui();
|
|
83
|
+
const t = aui.threads.thread({ id: "t1" });
|
|
84
|
+
`;
|
|
85
|
+
expect(applyTransform(input)?.trim()).toBe(expected.trim());
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
it("does not rewrite unknown receivers", () => {
|
|
89
|
+
const input = `
|
|
90
|
+
toolkit.tools();
|
|
91
|
+
message.composer().send();
|
|
92
|
+
ref.current.thread().getState();
|
|
93
|
+
`;
|
|
94
|
+
expect(applyTransform(input)).toBeNull();
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it("does not rewrite non-scope member calls on aui", () => {
|
|
98
|
+
const input = `
|
|
99
|
+
const aui = useAui();
|
|
100
|
+
aui.subscribe(() => {});
|
|
101
|
+
aui.on("thread.updated", () => {});
|
|
102
|
+
`;
|
|
103
|
+
expect(applyTransform(input)).toBeNull();
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it("returns null when nothing changes", () => {
|
|
107
|
+
expect(applyTransform(`const x = 1;`)).toBeNull();
|
|
108
|
+
});
|
|
109
|
+
});
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { createTransformer } from "../utils/createTransformer";
|
|
2
|
+
|
|
3
|
+
// Nullary scope accessors that became properties in v0.15. Parameterized
|
|
4
|
+
// lookups (e.g. `aui.thread.message({ id })`) stay as real calls.
|
|
5
|
+
const NULLARY_SCOPES = new Set([
|
|
6
|
+
"threads",
|
|
7
|
+
"threadListItem",
|
|
8
|
+
"thread",
|
|
9
|
+
"message",
|
|
10
|
+
"part",
|
|
11
|
+
"composer",
|
|
12
|
+
"attachment",
|
|
13
|
+
"modelContext",
|
|
14
|
+
"suggestions",
|
|
15
|
+
"suggestion",
|
|
16
|
+
"chainOfThought",
|
|
17
|
+
"queueItem",
|
|
18
|
+
"tools",
|
|
19
|
+
"dataRenderers",
|
|
20
|
+
"interactables",
|
|
21
|
+
"unstable_interactables",
|
|
22
|
+
"mcp",
|
|
23
|
+
"mcpServer",
|
|
24
|
+
"span",
|
|
25
|
+
]);
|
|
26
|
+
|
|
27
|
+
const AUI_HOOKS = new Set(["useAui", "useAssistantApi"]);
|
|
28
|
+
|
|
29
|
+
const auiAccessorCallsToProperties = createTransformer(
|
|
30
|
+
({ j, root, markAsChanged }) => {
|
|
31
|
+
const auiNames = new Set(["aui"]);
|
|
32
|
+
|
|
33
|
+
root.find(j.VariableDeclarator).forEach((path: any) => {
|
|
34
|
+
const { id, init } = path.value;
|
|
35
|
+
if (
|
|
36
|
+
j.Identifier.check(id) &&
|
|
37
|
+
init &&
|
|
38
|
+
j.CallExpression.check(init) &&
|
|
39
|
+
j.Identifier.check(init.callee) &&
|
|
40
|
+
AUI_HOOKS.has(init.callee.name)
|
|
41
|
+
) {
|
|
42
|
+
auiNames.add(id.name);
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
const collectParam = (param: any) => {
|
|
47
|
+
const annotation = param?.typeAnnotation?.typeAnnotation;
|
|
48
|
+
if (
|
|
49
|
+
j.Identifier.check(param) &&
|
|
50
|
+
annotation &&
|
|
51
|
+
j.TSTypeReference.check(annotation) &&
|
|
52
|
+
j.Identifier.check(annotation.typeName) &&
|
|
53
|
+
annotation.typeName.name === "AssistantClient"
|
|
54
|
+
) {
|
|
55
|
+
auiNames.add(param.name);
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
for (const fnType of [
|
|
59
|
+
j.FunctionDeclaration,
|
|
60
|
+
j.FunctionExpression,
|
|
61
|
+
j.ArrowFunctionExpression,
|
|
62
|
+
] as const) {
|
|
63
|
+
root.find(fnType as typeof j.FunctionDeclaration).forEach((path: any) => {
|
|
64
|
+
path.value.params.forEach(collectParam);
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
root.find(j.CallExpression).forEach((path: any) => {
|
|
69
|
+
const node = path.value;
|
|
70
|
+
if (node.arguments.length !== 0) return;
|
|
71
|
+
const callee = node.callee;
|
|
72
|
+
if (!j.MemberExpression.check(callee) || callee.computed) return;
|
|
73
|
+
if (!j.Identifier.check(callee.property)) return;
|
|
74
|
+
if (!NULLARY_SCOPES.has(callee.property.name)) return;
|
|
75
|
+
if (!j.Identifier.check(callee.object)) return;
|
|
76
|
+
if (!auiNames.has(callee.object.name)) return;
|
|
77
|
+
j(path).replaceWith(callee);
|
|
78
|
+
markAsChanged();
|
|
79
|
+
});
|
|
80
|
+
},
|
|
81
|
+
);
|
|
82
|
+
|
|
83
|
+
export default auiAccessorCallsToProperties;
|
package/src/commands/add.ts
CHANGED
|
@@ -67,7 +67,7 @@ export const add = new Command()
|
|
|
67
67
|
// Check if project is initialized
|
|
68
68
|
if (!hasConfig(opts.cwd)) {
|
|
69
69
|
logger.warn(
|
|
70
|
-
"It looks like you haven't initialized your project yet. Run 'assistant-ui init' first.",
|
|
70
|
+
"It looks like you haven't initialized your project yet — defaulting to Base UI flavored components. Run 'assistant-ui init' first for a configured setup.",
|
|
71
71
|
);
|
|
72
72
|
logger.break();
|
|
73
73
|
}
|
package/src/commands/create.ts
CHANGED
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
resolvePackageManagerForCwd,
|
|
13
13
|
scaffoldProject,
|
|
14
14
|
transformProject,
|
|
15
|
+
type TransformResult,
|
|
15
16
|
} from "../lib/create-project";
|
|
16
17
|
import { runSpawn, SpawnExitError } from "../lib/run-spawn";
|
|
17
18
|
import {
|
|
@@ -165,7 +166,7 @@ export const PROJECT_METADATA: ProjectMetadata[] = [
|
|
|
165
166
|
description: "Realtime voice with ElevenLabs",
|
|
166
167
|
category: "example",
|
|
167
168
|
path: "examples/with-elevenlabs-conversational",
|
|
168
|
-
hasLocalComponents:
|
|
169
|
+
hasLocalComponents: false,
|
|
169
170
|
},
|
|
170
171
|
{
|
|
171
172
|
name: "with-elevenlabs-scribe",
|
|
@@ -181,7 +182,7 @@ export const PROJECT_METADATA: ProjectMetadata[] = [
|
|
|
181
182
|
description: "Realtime voice with LiveKit",
|
|
182
183
|
category: "example",
|
|
183
184
|
path: "examples/with-livekit",
|
|
184
|
-
hasLocalComponents:
|
|
185
|
+
hasLocalComponents: false,
|
|
185
186
|
},
|
|
186
187
|
{
|
|
187
188
|
name: "with-expo",
|
|
@@ -197,7 +198,7 @@ export const PROJECT_METADATA: ProjectMetadata[] = [
|
|
|
197
198
|
description: "AI-driven interactive UI components",
|
|
198
199
|
category: "example",
|
|
199
200
|
path: "examples/with-interactables",
|
|
200
|
-
hasLocalComponents:
|
|
201
|
+
hasLocalComponents: false,
|
|
201
202
|
},
|
|
202
203
|
{
|
|
203
204
|
name: "with-external-store",
|
|
@@ -609,6 +610,7 @@ export const create = new Command()
|
|
|
609
610
|
? `Copying project from local source: ${localSourceRoot}`
|
|
610
611
|
: "Downloading project...",
|
|
611
612
|
);
|
|
613
|
+
let transformResult: TransformResult;
|
|
612
614
|
try {
|
|
613
615
|
const source = localSourceRoot
|
|
614
616
|
? { kind: "local" as const, rootDir: localSourceRoot }
|
|
@@ -632,7 +634,7 @@ export const create = new Command()
|
|
|
632
634
|
}
|
|
633
635
|
|
|
634
636
|
// 5. Run transform pipeline
|
|
635
|
-
await transformProject(absoluteProjectDir, {
|
|
637
|
+
transformResult = await transformProject(absoluteProjectDir, {
|
|
636
638
|
hasLocalComponents: project.hasLocalComponents,
|
|
637
639
|
skipInstall: opts.skipInstall,
|
|
638
640
|
packageManager: pm,
|
|
@@ -657,6 +659,16 @@ export const create = new Command()
|
|
|
657
659
|
throw err;
|
|
658
660
|
}
|
|
659
661
|
|
|
662
|
+
if (transformResult.registryInstallFailure) {
|
|
663
|
+
process.removeListener("exit", cleanupOnExit);
|
|
664
|
+
logger.break();
|
|
665
|
+
logger.error("Project created with missing components.");
|
|
666
|
+
logger.info("Retry the component install with:");
|
|
667
|
+
logger.info(` cd ${resolvedProjectDirectory}`);
|
|
668
|
+
logger.info(` ${transformResult.registryInstallFailure.retryCommand}`);
|
|
669
|
+
process.exit(1);
|
|
670
|
+
}
|
|
671
|
+
|
|
660
672
|
// 6. Apply preset if provided
|
|
661
673
|
if (scaffoldSelector.preset) {
|
|
662
674
|
const presetUrl = resolvePresetUrl(scaffoldSelector.preset);
|
package/src/commands/doctor.ts
CHANGED
|
@@ -3,6 +3,7 @@ import * as fs from "node:fs";
|
|
|
3
3
|
import * as path from "node:path";
|
|
4
4
|
import chalk from "chalk";
|
|
5
5
|
import { compare, valid } from "semver";
|
|
6
|
+
import { findWorkspaceRoot, resolveRealPath } from "../lib/utils/workspace";
|
|
6
7
|
|
|
7
8
|
const ASSISTANT_UI_PACKAGE_NAMES = new Set([
|
|
8
9
|
"assistant-stream",
|
|
@@ -39,13 +40,7 @@ function processPackageDir(
|
|
|
39
40
|
results: DiscoveredPackage[],
|
|
40
41
|
visited: ProcessedDir,
|
|
41
42
|
): void {
|
|
42
|
-
const real = (
|
|
43
|
-
try {
|
|
44
|
-
return fs.realpathSync(pkgDir);
|
|
45
|
-
} catch {
|
|
46
|
-
return pkgDir;
|
|
47
|
-
}
|
|
48
|
-
})();
|
|
43
|
+
const real = resolveRealPath(pkgDir);
|
|
49
44
|
if (visited.set.has(real)) return;
|
|
50
45
|
visited.set.add(real);
|
|
51
46
|
|
|
@@ -183,14 +178,23 @@ function walkPnpmStore(
|
|
|
183
178
|
}
|
|
184
179
|
|
|
185
180
|
// Discover every installation of an assistant-ui-family package reachable
|
|
186
|
-
// from `cwd`.
|
|
187
|
-
//
|
|
188
|
-
//
|
|
181
|
+
// from `cwd`. Node resolves packages through ancestor node_modules directories,
|
|
182
|
+
// so inspect each level to include workspace-hoisted installs. Nested installs
|
|
183
|
+
// and pnpm virtual stores are scanned to catch duplicate transitive copies.
|
|
189
184
|
export function discoverInstalledPackages(cwd: string): DiscoveredPackage[] {
|
|
190
185
|
const results: DiscoveredPackage[] = [];
|
|
191
186
|
const visited: ProcessedDir = { set: new Set() };
|
|
192
|
-
|
|
193
|
-
|
|
187
|
+
let dir = resolveRealPath(cwd);
|
|
188
|
+
const scanRoot = findWorkspaceRoot(dir) ?? dir;
|
|
189
|
+
|
|
190
|
+
while (true) {
|
|
191
|
+
walkNodeModulesAt(dir, results, visited);
|
|
192
|
+
walkPnpmStore(dir, results, visited);
|
|
193
|
+
|
|
194
|
+
if (dir === scanRoot) break;
|
|
195
|
+
dir = path.dirname(dir);
|
|
196
|
+
}
|
|
197
|
+
|
|
194
198
|
return results;
|
|
195
199
|
}
|
|
196
200
|
|
|
@@ -369,7 +373,7 @@ export const doctor = new Command()
|
|
|
369
373
|
)
|
|
370
374
|
.option("--no-network", "Skip the npm registry check for latest versions.")
|
|
371
375
|
.action(async (opts: { cwd: string; network: boolean }) => {
|
|
372
|
-
const cwd =
|
|
376
|
+
const cwd = resolveRealPath(opts.cwd);
|
|
373
377
|
const packageJsonPath = path.join(cwd, "package.json");
|
|
374
378
|
|
|
375
379
|
if (!fs.existsSync(packageJsonPath)) {
|
package/src/commands/info.ts
CHANGED
|
@@ -6,6 +6,9 @@ import { spawnSync } from "node:child_process";
|
|
|
6
6
|
import chalk from "chalk";
|
|
7
7
|
import { detect } from "detect-package-manager";
|
|
8
8
|
import { satisfies } from "semver";
|
|
9
|
+
import { findWorkspaceRoot, resolveRealPath } from "../lib/utils/workspace";
|
|
10
|
+
|
|
11
|
+
export { findWorkspaceRoot };
|
|
9
12
|
|
|
10
13
|
const ASSISTANT_UI_PACKAGES = [
|
|
11
14
|
// Distribution
|
|
@@ -89,25 +92,6 @@ function getInstalledVersion(pkg: string, cwd: string): string | null {
|
|
|
89
92
|
return null;
|
|
90
93
|
}
|
|
91
94
|
|
|
92
|
-
export function findWorkspaceRoot(cwd: string): string | null {
|
|
93
|
-
let dir = cwd;
|
|
94
|
-
const root = path.parse(dir).root;
|
|
95
|
-
while (true) {
|
|
96
|
-
if (fs.existsSync(path.join(dir, "pnpm-workspace.yaml"))) return dir;
|
|
97
|
-
const pkgPath = path.join(dir, "package.json");
|
|
98
|
-
if (fs.existsSync(pkgPath)) {
|
|
99
|
-
try {
|
|
100
|
-
const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf8"));
|
|
101
|
-
if (pkg.workspaces) return dir;
|
|
102
|
-
} catch {
|
|
103
|
-
// ignore
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
if (dir === root) return null;
|
|
107
|
-
dir = path.dirname(dir);
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
|
|
111
95
|
function readProjectDeps(
|
|
112
96
|
projectPkg: Record<string, unknown>,
|
|
113
97
|
): Record<string, string> {
|
|
@@ -197,6 +181,19 @@ function getOsInfo(): string {
|
|
|
197
181
|
}
|
|
198
182
|
}
|
|
199
183
|
|
|
184
|
+
function getCliVersion(): string {
|
|
185
|
+
try {
|
|
186
|
+
const packageJson = JSON.parse(
|
|
187
|
+
fs.readFileSync(new URL("../../package.json", import.meta.url), "utf8"),
|
|
188
|
+
) as { version?: unknown };
|
|
189
|
+
return typeof packageJson.version === "string"
|
|
190
|
+
? packageJson.version
|
|
191
|
+
: "unknown";
|
|
192
|
+
} catch {
|
|
193
|
+
return "unknown";
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
200
197
|
async function getPackageManagerInfo(
|
|
201
198
|
cwd: string,
|
|
202
199
|
): Promise<{ name: string; version: string }> {
|
|
@@ -230,6 +227,7 @@ interface PackageInfo {
|
|
|
230
227
|
}
|
|
231
228
|
|
|
232
229
|
interface InfoData {
|
|
230
|
+
cliVersion: string;
|
|
233
231
|
os: string;
|
|
234
232
|
node: string;
|
|
235
233
|
pm: { name: string; version: string };
|
|
@@ -317,6 +315,7 @@ async function collectInfo(
|
|
|
317
315
|
const warnings = collectWarnings(packages, cwd, projectPkg);
|
|
318
316
|
|
|
319
317
|
return {
|
|
318
|
+
cliVersion: getCliVersion(),
|
|
320
319
|
os: getOsInfo(),
|
|
321
320
|
node: process.version,
|
|
322
321
|
pm,
|
|
@@ -344,6 +343,7 @@ function renderPlain(data: InfoData): string[] {
|
|
|
344
343
|
const lines: string[] = [];
|
|
345
344
|
|
|
346
345
|
lines.push("Environment:");
|
|
346
|
+
lines.push(` assistant-ui CLI: ${data.cliVersion}`);
|
|
347
347
|
lines.push(` OS: ${data.os}`);
|
|
348
348
|
lines.push(` Node.js: ${data.node}`);
|
|
349
349
|
lines.push(` Package Manager: ${data.pm.name} ${data.pm.version}`);
|
|
@@ -370,6 +370,7 @@ function renderColored(data: InfoData): string[] {
|
|
|
370
370
|
const lines: string[] = [];
|
|
371
371
|
|
|
372
372
|
lines.push(chalk.bold("Environment:"));
|
|
373
|
+
lines.push(` assistant-ui CLI: ${data.cliVersion}`);
|
|
373
374
|
lines.push(` OS: ${data.os}`);
|
|
374
375
|
lines.push(` Node.js: ${data.node}`);
|
|
375
376
|
lines.push(` Package Manager: ${data.pm.name} ${data.pm.version}`);
|
|
@@ -415,7 +416,7 @@ export const info = new Command()
|
|
|
415
416
|
process.cwd(),
|
|
416
417
|
)
|
|
417
418
|
.action(async (opts) => {
|
|
418
|
-
const cwd =
|
|
419
|
+
const cwd = resolveRealPath(opts.cwd);
|
|
419
420
|
const packageJsonPath = path.join(cwd, "package.json");
|
|
420
421
|
|
|
421
422
|
if (!fs.existsSync(packageJsonPath)) {
|
package/src/commands/upgrade.ts
CHANGED
|
@@ -48,9 +48,9 @@ export const upgradeCommand = addTransformOptions(
|
|
|
48
48
|
new Command()
|
|
49
49
|
.command("upgrade")
|
|
50
50
|
.description("Upgrade ai package dependencies and apply codemods"),
|
|
51
|
-
).action((options: TransformOptions) => {
|
|
51
|
+
).action(async (options: TransformOptions) => {
|
|
52
52
|
try {
|
|
53
|
-
upgrade(options);
|
|
53
|
+
await upgrade(options);
|
|
54
54
|
} catch (err) {
|
|
55
55
|
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
56
56
|
const errorStack = err instanceof Error ? err.stack : undefined;
|
package/src/index.ts
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { runCli } from "./run";
|
|
4
4
|
|
|
5
5
|
process.on("SIGINT", () => process.exit(0));
|
|
6
6
|
process.on("SIGTERM", () => process.exit(0));
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
main();
|
|
8
|
+
void runCli().catch((error: unknown) => {
|
|
9
|
+
console.error(error);
|
|
10
|
+
process.exitCode = 1;
|
|
11
|
+
});
|