assistant-ui 0.0.49 → 0.0.50

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 (46) hide show
  1. package/dist/codemods/utils/createTransformer.d.ts +15 -0
  2. package/dist/codemods/utils/createTransformer.d.ts.map +1 -0
  3. package/dist/codemods/v0-8/ui-package-split.d.ts +3 -0
  4. package/dist/codemods/v0-8/ui-package-split.d.ts.map +1 -0
  5. package/dist/codemods/v0-9/edge-package-split.d.ts +3 -0
  6. package/dist/codemods/v0-9/edge-package-split.d.ts.map +1 -0
  7. package/dist/commands/add.d.ts +3 -0
  8. package/dist/commands/add.d.ts.map +1 -0
  9. package/dist/commands/create.d.ts +3 -0
  10. package/dist/commands/create.d.ts.map +1 -0
  11. package/dist/commands/init.d.ts +3 -0
  12. package/dist/commands/init.d.ts.map +1 -0
  13. package/dist/commands/update.d.ts +3 -0
  14. package/dist/commands/update.d.ts.map +1 -0
  15. package/dist/commands/upgrade.d.ts +10 -0
  16. package/dist/commands/upgrade.d.ts.map +1 -0
  17. package/dist/index.d.ts +3 -0
  18. package/dist/index.d.ts.map +1 -0
  19. package/dist/lib/install-ai-sdk-lib.d.ts +2 -0
  20. package/dist/lib/install-ai-sdk-lib.d.ts.map +1 -0
  21. package/dist/lib/install-edge-lib.d.ts +2 -0
  22. package/dist/lib/install-edge-lib.d.ts.map +1 -0
  23. package/dist/lib/install-ui-lib.d.ts +2 -0
  24. package/dist/lib/install-ui-lib.d.ts.map +1 -0
  25. package/dist/lib/transform-options.d.ts +7 -0
  26. package/dist/lib/transform-options.d.ts.map +1 -0
  27. package/dist/lib/transform.d.ts +21 -0
  28. package/dist/lib/transform.d.ts.map +1 -0
  29. package/dist/lib/upgrade.d.ts +9 -0
  30. package/dist/lib/upgrade.d.ts.map +1 -0
  31. package/package.json +3 -5
  32. package/src/codemods/utils/createTransformer.ts +41 -0
  33. package/src/codemods/v0-8/ui-package-split.ts +203 -0
  34. package/src/codemods/v0-9/edge-package-split.ts +226 -0
  35. package/src/commands/add.ts +47 -0
  36. package/src/commands/create.ts +92 -0
  37. package/src/commands/init.ts +50 -0
  38. package/src/commands/update.ts +60 -0
  39. package/src/commands/upgrade.ts +55 -0
  40. package/src/index.ts +28 -0
  41. package/src/lib/install-ai-sdk-lib.ts +92 -0
  42. package/src/lib/install-edge-lib.ts +92 -0
  43. package/src/lib/install-ui-lib.ts +92 -0
  44. package/src/lib/transform-options.ts +6 -0
  45. package/src/lib/transform.ts +177 -0
  46. package/src/lib/upgrade.ts +83 -0
@@ -0,0 +1,226 @@
1
+ import { createTransformer } from "../utils/createTransformer";
2
+
3
+ const reactEdgeExports: string[] = [
4
+ // Edge Runtime
5
+ "useEdgeRuntime",
6
+ "EdgeRuntimeOptions",
7
+ "EdgeModelAdapter",
8
+ "EdgeChatAdapter",
9
+ "EdgeRuntimeRequestOptions",
10
+ "createEdgeRuntimeAPI",
11
+ "getEdgeRuntimeResponse",
12
+
13
+ // Core Types
14
+ "CoreMessage",
15
+ "CoreUserMessage",
16
+ "CoreAssistantMessage",
17
+ "CoreSystemMessage",
18
+ "CoreUserContentPart",
19
+ "CoreAssistantContentPart",
20
+ "CoreToolCallContentPart",
21
+
22
+ // Core message converters
23
+ "fromCoreMessages",
24
+ "fromCoreMessage",
25
+ "toCoreMessages",
26
+ "toCoreMessage",
27
+ ];
28
+
29
+ // Language model converters to be moved to react-ai-sdk
30
+ const reactAiSdkExports: string[] = [
31
+ "toLanguageModelMessages",
32
+ "toLanguageModelTools",
33
+ "fromLanguageModelMessages",
34
+ "fromLanguageModelTools",
35
+ "useDangerousInBrowserRuntime",
36
+ ];
37
+
38
+ const migrateToEdgePackage = createTransformer(({ j, root, markAsChanged }) => {
39
+ const sourcesToMigrate: string[] = ["@assistant-ui/react"];
40
+ const movedEdgeSpecifiers: any[] = [];
41
+ const movedAiSdkSpecifiers: any[] = [];
42
+ let lastMigratedImportPath: any = null;
43
+
44
+ root
45
+ .find(j.ImportDeclaration)
46
+ .filter((path: any) => sourcesToMigrate.includes(path.value.source.value))
47
+ .forEach((path: any) => {
48
+ let hadMigratedSpecifiers = false;
49
+ const remainingSpecifiers: any[] = [];
50
+ path.value.specifiers.forEach((specifier: any) => {
51
+ if (
52
+ j.ImportSpecifier.check(specifier) &&
53
+ reactEdgeExports.includes(specifier.imported.name as string)
54
+ ) {
55
+ movedEdgeSpecifiers.push(specifier);
56
+ hadMigratedSpecifiers = true;
57
+ } else if (
58
+ j.ImportSpecifier.check(specifier) &&
59
+ reactAiSdkExports.includes(specifier.imported.name as string)
60
+ ) {
61
+ movedAiSdkSpecifiers.push(specifier);
62
+ hadMigratedSpecifiers = true;
63
+ } else {
64
+ remainingSpecifiers.push(specifier);
65
+ }
66
+ });
67
+ if (hadMigratedSpecifiers) {
68
+ lastMigratedImportPath = path;
69
+ }
70
+ if (remainingSpecifiers.length === 0) {
71
+ j(path).remove();
72
+ markAsChanged();
73
+ } else if (remainingSpecifiers.length !== path.value.specifiers.length) {
74
+ path.value.specifiers = remainingSpecifiers;
75
+ markAsChanged();
76
+ }
77
+ });
78
+
79
+ // Add imports for react-edge
80
+ if (movedEdgeSpecifiers.length > 0) {
81
+ const existingEdgeImport = root.find(j.ImportDeclaration, {
82
+ source: { value: "@assistant-ui/react-edge" },
83
+ });
84
+ if (existingEdgeImport.size() > 0) {
85
+ existingEdgeImport.forEach((path: any) => {
86
+ movedEdgeSpecifiers.forEach((specifier: any) => {
87
+ if (
88
+ !path.value.specifiers.some(
89
+ (s: any) => s.imported.name === specifier.imported.name,
90
+ )
91
+ ) {
92
+ path.value.specifiers.push(specifier);
93
+ }
94
+ });
95
+ });
96
+ } else {
97
+ const newImport = j.importDeclaration(
98
+ movedEdgeSpecifiers,
99
+ j.literal("@assistant-ui/react-edge"),
100
+ );
101
+ if (lastMigratedImportPath) {
102
+ j(lastMigratedImportPath).insertAfter(newImport);
103
+ } else {
104
+ const firstImport = root.find(j.ImportDeclaration).at(0);
105
+ if (firstImport.size() > 0) {
106
+ firstImport.insertBefore(newImport);
107
+ } else {
108
+ root.get().node.program.body.unshift(newImport);
109
+ }
110
+ }
111
+ }
112
+ markAsChanged();
113
+ }
114
+
115
+ // Add imports for react-ai-sdk
116
+ if (movedAiSdkSpecifiers.length > 0) {
117
+ const existingAiSdkImport = root.find(j.ImportDeclaration, {
118
+ source: { value: "@assistant-ui/react-ai-sdk" },
119
+ });
120
+ if (existingAiSdkImport.size() > 0) {
121
+ existingAiSdkImport.forEach((path: any) => {
122
+ movedAiSdkSpecifiers.forEach((specifier: any) => {
123
+ if (
124
+ !path.value.specifiers.some(
125
+ (s: any) => s.imported.name === specifier.imported.name,
126
+ )
127
+ ) {
128
+ path.value.specifiers.push(specifier);
129
+ }
130
+ });
131
+ });
132
+ } else {
133
+ const newImport = j.importDeclaration(
134
+ movedAiSdkSpecifiers,
135
+ j.literal("@assistant-ui/react-ai-sdk"),
136
+ );
137
+ if (lastMigratedImportPath) {
138
+ j(lastMigratedImportPath).insertAfter(newImport);
139
+ } else {
140
+ const firstImport = root.find(j.ImportDeclaration).at(0);
141
+ if (firstImport.size() > 0) {
142
+ firstImport.insertBefore(newImport);
143
+ } else {
144
+ root.get().node.program.body.unshift(newImport);
145
+ }
146
+ }
147
+ }
148
+ markAsChanged();
149
+ }
150
+
151
+ // Migrate imports from edge/converters
152
+ root.find(j.ImportDeclaration).forEach((path: any) => {
153
+ const sourceValue: string = path.value.source.value;
154
+ if (
155
+ sourceValue.startsWith("@assistant-ui/react/") &&
156
+ (sourceValue.includes("edge/") ||
157
+ sourceValue.includes("dangerous-in-browser/"))
158
+ ) {
159
+ path.value.source = j.literal(
160
+ sourceValue.replace(
161
+ "@assistant-ui/react/",
162
+ "@assistant-ui/react-edge/",
163
+ ),
164
+ );
165
+ markAsChanged();
166
+ }
167
+ });
168
+
169
+ // Migrate language model converter imports from react-edge to react-ai-sdk
170
+ root.find(j.ImportDeclaration).forEach((path: any) => {
171
+ const sourceValue: string = path.value.source.value;
172
+ if (sourceValue === "@assistant-ui/react-edge") {
173
+ let hasLanguageModelConverters = false;
174
+ const remainingSpecifiers: any[] = [];
175
+ const aiSdkSpecifiers: any[] = [];
176
+
177
+ path.value.specifiers.forEach((specifier: any) => {
178
+ if (
179
+ j.ImportSpecifier.check(specifier) &&
180
+ reactAiSdkExports.includes(specifier.imported.name as string)
181
+ ) {
182
+ aiSdkSpecifiers.push(specifier);
183
+ hasLanguageModelConverters = true;
184
+ } else {
185
+ remainingSpecifiers.push(specifier);
186
+ }
187
+ });
188
+
189
+ if (hasLanguageModelConverters) {
190
+ if (remainingSpecifiers.length === 0) {
191
+ j(path).remove();
192
+ } else {
193
+ path.value.specifiers = remainingSpecifiers;
194
+ }
195
+
196
+ const existingAiSdkImport = root.find(j.ImportDeclaration, {
197
+ source: { value: "@assistant-ui/react-ai-sdk" },
198
+ });
199
+
200
+ if (existingAiSdkImport.size() > 0) {
201
+ existingAiSdkImport.forEach((importPath: any) => {
202
+ aiSdkSpecifiers.forEach((specifier: any) => {
203
+ if (
204
+ !importPath.value.specifiers.some(
205
+ (s: any) => s.imported.name === specifier.imported.name,
206
+ )
207
+ ) {
208
+ importPath.value.specifiers.push(specifier);
209
+ }
210
+ });
211
+ });
212
+ } else {
213
+ const newImport = j.importDeclaration(
214
+ aiSdkSpecifiers,
215
+ j.literal("@assistant-ui/react-ai-sdk"),
216
+ );
217
+ j(path).insertAfter(newImport);
218
+ }
219
+
220
+ markAsChanged();
221
+ }
222
+ }
223
+ });
224
+ });
225
+
226
+ export default migrateToEdgePackage;
@@ -0,0 +1,47 @@
1
+ import { Command } from "commander";
2
+ import { spawn } from "cross-spawn";
3
+
4
+ const REGISTRY_BASE_URL = "https://r.assistant-ui.com";
5
+
6
+ export const add = new Command()
7
+ .name("add")
8
+ .description("add a component to your project")
9
+ .argument("<components...>", "the components to add")
10
+ .option("-y, --yes", "skip confirmation prompt.", true)
11
+ .option("-o, --overwrite", "overwrite existing files.", false)
12
+ .option(
13
+ "-c, --cwd <cwd>",
14
+ "the working directory. defaults to the current directory.",
15
+ process.cwd(),
16
+ )
17
+ .option("-p, --path <path>", "the path to add the component to.")
18
+ .action((components: string[], opts) => {
19
+ const componentsToAdd = components.map((c) => {
20
+ if (!/^[a-zA-Z0-9-\/]+$/.test(c)) {
21
+ throw new Error(`Invalid component name: ${c}`);
22
+ }
23
+ return `${REGISTRY_BASE_URL}/${encodeURIComponent(c)}`;
24
+ });
25
+
26
+ const args = [`shadcn@latest`, "add", ...componentsToAdd];
27
+
28
+ if (opts.yes) args.push("--yes");
29
+ if (opts.overwrite) args.push("--overwrite");
30
+ if (opts.cwd) args.push("--cwd", opts.cwd);
31
+ if (opts.path) args.push("--path", opts.path);
32
+
33
+ const child = spawn("npx", args, {
34
+ stdio: "inherit",
35
+ shell: true,
36
+ });
37
+
38
+ child.on("error", (error) => {
39
+ console.error(`Error: ${error.message}`);
40
+ });
41
+
42
+ child.on("close", (code) => {
43
+ if (code !== 0) {
44
+ console.log(`other-package-script process exited with code ${code}`);
45
+ }
46
+ });
47
+ });
@@ -0,0 +1,92 @@
1
+ import { Command } from "commander";
2
+ import chalk from "chalk";
3
+ import { spawn } from "cross-spawn";
4
+
5
+ export const create = new Command()
6
+ .name("create")
7
+ .description("create a new project")
8
+ .argument("[project-directory]")
9
+ .usage(`${chalk.green("[project-directory]")} [options]`)
10
+ .option(
11
+ "-t, --template <template>",
12
+ `
13
+
14
+ The template to use for the project, e.g. default, langgraph
15
+ `,
16
+ )
17
+ .option(
18
+ "--use-npm",
19
+ `
20
+
21
+ Explicitly tell the CLI to bootstrap the application using npm
22
+ `,
23
+ )
24
+ .option(
25
+ "--use-pnpm",
26
+ `
27
+
28
+ Explicitly tell the CLI to bootstrap the application using pnpm
29
+ `,
30
+ )
31
+ .option(
32
+ "--use-yarn",
33
+ `
34
+
35
+ Explicitly tell the CLI to bootstrap the application using Yarn
36
+ `,
37
+ )
38
+ .option(
39
+ "--use-bun",
40
+ `
41
+
42
+ Explicitly tell the CLI to bootstrap the application using Bun
43
+ `,
44
+ )
45
+ .option(
46
+ "--skip-install",
47
+ `
48
+
49
+ Explicitly tell the CLI to skip installing packages
50
+ `,
51
+ )
52
+ .action((_, opts) => {
53
+ const templates = {
54
+ default: "https://github.com/assistant-ui/assistant-ui-starter",
55
+ langgraph:
56
+ "https://github.com/assistant-ui/assistant-ui-starter-langgraph",
57
+ };
58
+
59
+ const templateUrl =
60
+ templates[(opts.template as keyof typeof templates) ?? "default"];
61
+ if (!templateUrl) {
62
+ console.error(`Unknown template: ${opts.template}`);
63
+ process.exit(1);
64
+ }
65
+
66
+ const filteredArgs = process.argv.slice(3).filter((arg, index, arr) => {
67
+ return !(
68
+ arg === "-t" ||
69
+ arg === "--template" ||
70
+ arr[index - 1] === "-t" ||
71
+ arr[index - 1] === "--template"
72
+ );
73
+ });
74
+
75
+ const child = spawn(
76
+ "npx",
77
+ [`create-next-app@latest`, ...filteredArgs, "-e", templateUrl],
78
+ {
79
+ stdio: "inherit",
80
+ },
81
+ );
82
+
83
+ child.on("error", (error) => {
84
+ console.error(`Error: ${error.message}`);
85
+ });
86
+
87
+ child.on("close", (code) => {
88
+ if (code !== 0) {
89
+ console.log(`other-package-script process exited with code ${code}`);
90
+ }
91
+ });
92
+ });
@@ -0,0 +1,50 @@
1
+ import { Command } from "commander";
2
+ import { spawn } from "cross-spawn";
3
+ import fs from "fs";
4
+ import path from "path";
5
+ import chalk from "chalk";
6
+ import { create } from "./create";
7
+
8
+ export const init = new Command()
9
+ .name("init")
10
+ .description("initialize assistant-ui in a new or existing project")
11
+ .action(async () => {
12
+ // Check if package.json exists in the current directory
13
+ const packageJsonPath = path.join(process.cwd(), "package.json");
14
+ const packageJsonExists = fs.existsSync(packageJsonPath);
15
+
16
+ if (packageJsonExists) {
17
+ // If package.json exists, run shadcn add command
18
+ console.log(
19
+ chalk.blue("Initializing assistant-ui in existing project..."),
20
+ );
21
+
22
+ const child = spawn(
23
+ "npx",
24
+ [
25
+ `shadcn@latest`,
26
+ "add",
27
+ "https://r.assistant-ui.com/chat/b/ai-sdk-quick-start/json",
28
+ ],
29
+ {
30
+ stdio: "inherit",
31
+ },
32
+ );
33
+
34
+ child.on("error", (error) => {
35
+ console.error(`Error: ${error.message}`);
36
+ });
37
+
38
+ child.on("close", (code) => {
39
+ if (code !== 0) {
40
+ console.log(`shadcn process exited with code ${code}`);
41
+ }
42
+ });
43
+ } else {
44
+ // If package.json doesn't exist, use the create command
45
+ console.log(chalk.blue("Creating a new assistant-ui project..."));
46
+
47
+ // Execute the create command with default template
48
+ await create.parseAsync([]);
49
+ }
50
+ });
@@ -0,0 +1,60 @@
1
+ import { Command } from "commander";
2
+ import fs from "fs";
3
+ import path from "path";
4
+ import chalk from "chalk";
5
+ import { detect } from "detect-package-manager";
6
+ import { sync as spawnSync } from "cross-spawn";
7
+
8
+ export const update = new Command()
9
+ .name("update")
10
+ .description(
11
+ "Update all '@assistant-ui/*' and 'assistant-stream' packages in package.json to latest versions using your package manager.",
12
+ )
13
+ .option("--dry", "Print the package manager command instead of running it.")
14
+ .action(async (opts) => {
15
+ const packageJsonPath = path.join(process.cwd(), "package.json");
16
+ if (!fs.existsSync(packageJsonPath)) {
17
+ console.error(
18
+ chalk.red("No package.json found in the current directory."),
19
+ );
20
+ process.exit(1);
21
+ }
22
+ const pkg = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8"));
23
+ const sections = ["dependencies", "devDependencies"];
24
+ const targets: string[] = [];
25
+ for (const section of sections) {
26
+ if (!pkg[section]) continue;
27
+ for (const dep in pkg[section]) {
28
+ if (dep.startsWith("@assistant-ui/") || dep === "assistant-stream") {
29
+ targets.push(dep);
30
+ }
31
+ }
32
+ }
33
+ if (!targets.length) {
34
+ console.log(chalk.yellow("No matching packages found to update."));
35
+ return;
36
+ }
37
+ const pm = await detect({ cwd: process.cwd() });
38
+ let cmd: string;
39
+ if (pm === "yarn") {
40
+ cmd = `yarn add ${targets.map((d) => `${d}@latest`).join(" ")}`;
41
+ } else if (pm === "pnpm") {
42
+ cmd = `pnpm add ${targets.map((d) => `${d}@latest`).join(" ")}`;
43
+ } else if (pm === "bun") {
44
+ cmd = `bun add ${targets.map((d) => `${d}@latest`).join(" ")}`;
45
+ } else {
46
+ cmd = `npm install ${targets.map((d) => `${d}@latest`).join(" ")}`;
47
+ }
48
+ if (opts.dry) {
49
+ console.log(chalk.blue("\nDry run: would run the following command:"));
50
+ console.log(cmd);
51
+ return;
52
+ }
53
+ console.log(chalk.blue(`\nRunning: ${cmd}`));
54
+ const result = spawnSync(cmd, { shell: true, stdio: "inherit" });
55
+ if (result.status !== 0) {
56
+ console.error(chalk.red("Package manager update failed."));
57
+ process.exit(result.status || 1);
58
+ }
59
+ console.log(chalk.green("\nAll packages updated to latest version!"));
60
+ });
@@ -0,0 +1,55 @@
1
+ import { Command } from "commander";
2
+ import { transform } from "../lib/transform";
3
+ import { upgrade } from "../lib/upgrade";
4
+ import debug from "debug";
5
+
6
+ export interface TransformOptions {
7
+ dry?: boolean;
8
+ print?: boolean;
9
+ verbose?: boolean;
10
+ jscodeshift?: string;
11
+ }
12
+
13
+ const error = debug("codemod:error");
14
+ debug.enable("codemod:*");
15
+
16
+ const addTransformOptions = (command: Command): Command => {
17
+ return command
18
+ .option("-d, --dry", "Dry run (no changes are made to files)")
19
+ .option("-p, --print", "Print transformed files to stdout")
20
+ .option("--verbose", "Show more information about the transform process")
21
+ .option(
22
+ "-j, --jscodeshift <options>",
23
+ "Pass options directly to jscodeshift",
24
+ );
25
+ };
26
+
27
+ export const codemodCommand = addTransformOptions(
28
+ new Command()
29
+ .name("codemod")
30
+ .description("CLI tool for running codemods")
31
+ .argument("<codemod>", "Codemod to run (e.g., rewrite-framework-imports)")
32
+ .argument("<source>", "Path to source files or directory to transform"),
33
+ ).action((codemod, source, options: TransformOptions) => {
34
+ try {
35
+ transform(codemod, source, options);
36
+ } catch (err: any) {
37
+ error(`Error transforming: ${err}`);
38
+ error(err.stack);
39
+ process.exit(1);
40
+ }
41
+ });
42
+
43
+ export const upgradeCommand = addTransformOptions(
44
+ new Command()
45
+ .command("upgrade")
46
+ .description("Upgrade ai package dependencies and apply codemods"),
47
+ ).action((options: TransformOptions) => {
48
+ try {
49
+ upgrade(options);
50
+ } catch (err: any) {
51
+ error(`Error upgrading: ${err}`);
52
+ error(err.stack);
53
+ process.exit(1);
54
+ }
55
+ });
package/src/index.ts ADDED
@@ -0,0 +1,28 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { Command } from "commander";
4
+ import { create } from "./commands/create";
5
+ import { add } from "./commands/add";
6
+ import { codemodCommand, upgradeCommand } from "./commands/upgrade";
7
+ import { init } from "./commands/init";
8
+ import { update } from "./commands/update";
9
+
10
+ process.on("SIGINT", () => process.exit(0));
11
+ process.on("SIGTERM", () => process.exit(0));
12
+
13
+ function main() {
14
+ const program = new Command()
15
+ .name("assistant-ui")
16
+ .description("add components and dependencies to your project");
17
+
18
+ program.addCommand(add);
19
+ program.addCommand(create);
20
+ program.addCommand(init);
21
+ program.addCommand(codemodCommand);
22
+ program.addCommand(upgradeCommand);
23
+ program.addCommand(update);
24
+
25
+ program.parse();
26
+ }
27
+
28
+ main();
@@ -0,0 +1,92 @@
1
+ import * as fs from "fs";
2
+ import * as path from "path";
3
+ import { execSync } from "child_process";
4
+ import { sync as globSync } from "glob";
5
+ import * as readline from "readline";
6
+ import { detect } from "detect-package-manager";
7
+
8
+ function askQuestion(query: string): Promise<string> {
9
+ return new Promise((resolve) => {
10
+ const rl = readline.createInterface({
11
+ input: process.stdin,
12
+ output: process.stdout,
13
+ });
14
+ rl.question(query, (answer) => {
15
+ rl.close();
16
+ resolve(answer);
17
+ });
18
+ });
19
+ }
20
+
21
+ function isPackageInstalled(pkg: string): boolean {
22
+ const cwd = process.cwd();
23
+ try {
24
+ const pkgJsonPath = path.join(cwd, "package.json");
25
+ if (fs.existsSync(pkgJsonPath)) {
26
+ const pkgJson = JSON.parse(fs.readFileSync(pkgJsonPath, "utf8"));
27
+ const deps = pkgJson.dependencies || {};
28
+ const devDeps = pkgJson.devDependencies || {};
29
+ if (deps[pkg] || devDeps[pkg]) {
30
+ return true;
31
+ }
32
+ }
33
+ } catch (e) {
34
+ // Fall back to node_modules check below.
35
+ }
36
+ const modulePath = path.join(cwd, "node_modules", ...pkg.split("/"));
37
+ return fs.existsSync(modulePath);
38
+ }
39
+
40
+ export default async function installAiSdkLib(): Promise<void> {
41
+ const cwd = process.cwd();
42
+ const pattern = "**/*.{js,jsx,ts,tsx}";
43
+ const files = globSync(pattern, {
44
+ cwd,
45
+ ignore: ["**/node_modules/**", "**/dist/**", "**/build/**"],
46
+ });
47
+
48
+ let found = false;
49
+ for (const file of files) {
50
+ const fullPath = path.join(cwd, file);
51
+ const content = fs.readFileSync(fullPath, "utf8");
52
+ if (content.includes("@assistant-ui/react-ai-sdk")) {
53
+ found = true;
54
+ break;
55
+ }
56
+ }
57
+
58
+ if (found) {
59
+ if (isPackageInstalled("@assistant-ui/react-ai-sdk")) {
60
+ console.log(
61
+ "@assistant-ui/react-ai-sdk is already installed. Skipping installation.",
62
+ );
63
+ return;
64
+ }
65
+
66
+ const answer = await askQuestion(
67
+ "AI SDK imports were added but @assistant-ui/react-ai-sdk is not installed. Do you want to install it? (Y/n) ",
68
+ );
69
+ if (answer === "" || answer.toLowerCase().startsWith("y")) {
70
+ const pm = await detect();
71
+ let cmd = "";
72
+ if (pm === "yarn") {
73
+ cmd = "yarn add @assistant-ui/react-ai-sdk";
74
+ } else if (pm === "pnpm") {
75
+ cmd = "pnpm add @assistant-ui/react-ai-sdk";
76
+ } else if (pm === "bun") {
77
+ cmd = "bun add @assistant-ui/react-ai-sdk";
78
+ } else {
79
+ cmd = "npm install @assistant-ui/react-ai-sdk";
80
+ }
81
+ try {
82
+ execSync(cmd, { stdio: "inherit" });
83
+ } catch (e) {
84
+ console.error("Installation failed:", e);
85
+ }
86
+ } else {
87
+ console.log("Skipping installation.");
88
+ }
89
+ } else {
90
+ console.log("No AI SDK imports found; skipping installation.");
91
+ }
92
+ }