assistant-ui 0.0.78 → 0.0.80

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.
@@ -1,41 +1,97 @@
1
- import { Command } from "commander";
1
+ import { Command, Option } from "commander";
2
2
  import { spawn } from "cross-spawn";
3
3
  import fs from "node:fs";
4
4
  import path from "node:path";
5
5
  import { logger } from "../lib/utils/logger";
6
- import { hasConfig } from "../lib/utils/config";
6
+ import { create } from "./create";
7
7
 
8
8
  const DEFAULT_REGISTRY_URL =
9
9
  "https://r.assistant-ui.com/chat/b/ai-sdk-quick-start/json";
10
10
 
11
- // Keep in sync with packages/create-assistant-ui/src/index.ts
12
- const templates = {
13
- default: "https://github.com/assistant-ui/assistant-ui-starter",
14
- minimal: "https://github.com/assistant-ui/assistant-ui-starter-minimal",
15
- cloud: "https://github.com/assistant-ui/assistant-ui-starter-cloud",
16
- langgraph: "https://github.com/assistant-ui/assistant-ui-starter-langgraph",
17
- mcp: "https://github.com/assistant-ui/assistant-ui-starter-mcp",
18
- };
19
-
20
- const templateNames = Object.keys(templates);
11
+ class SpawnExitError extends Error {
12
+ code: number;
13
+
14
+ constructor(code: number) {
15
+ super(`Process exited with code ${code}`);
16
+ this.code = code;
17
+ }
18
+ }
19
+
20
+ interface ExistingProjectInitPlan {
21
+ initArgs: string[] | null;
22
+ addArgs: string[];
23
+ }
24
+
25
+ export function createExistingProjectInitPlan(params: {
26
+ yes: boolean;
27
+ overwrite: boolean;
28
+ registryUrl: string;
29
+ }): ExistingProjectInitPlan {
30
+ const { yes, overwrite, registryUrl } = params;
31
+
32
+ if (!yes) {
33
+ const addArgs = [`shadcn@latest`, "add"];
34
+ if (overwrite) addArgs.push("--overwrite");
35
+ addArgs.push(registryUrl);
36
+ return { initArgs: null, addArgs };
37
+ }
38
+
39
+ const initArgs = [`shadcn@latest`, "init", "--defaults", "--yes"];
40
+
41
+ const addArgs = [`shadcn@latest`, "add", "--yes"];
42
+ if (overwrite) addArgs.push("--overwrite");
43
+ addArgs.push(registryUrl);
44
+
45
+ return { initArgs, addArgs };
46
+ }
47
+
48
+ export function isNonInteractiveShell(
49
+ stdinIsTTY = process.stdin.isTTY,
50
+ ): boolean {
51
+ return !stdinIsTTY;
52
+ }
53
+
54
+ async function runSpawn(
55
+ command: string,
56
+ args: string[],
57
+ cwd: string,
58
+ ): Promise<void> {
59
+ return new Promise((resolve, reject) => {
60
+ const child = spawn(command, args, {
61
+ stdio: "inherit",
62
+ cwd,
63
+ });
64
+
65
+ child.on("error", (error) => {
66
+ reject(error);
67
+ });
68
+
69
+ child.on("close", (code) => {
70
+ if (code !== 0) {
71
+ reject(new SpawnExitError(code || 1));
72
+ } else {
73
+ resolve();
74
+ }
75
+ });
76
+ });
77
+ }
21
78
 
22
79
  export const init = new Command()
23
80
  .name("init")
24
- .description("initialize assistant-ui in a new or existing project")
81
+ .description("initialize assistant-ui in an existing project")
25
82
  .argument("[project-directory]", "directory for the new project")
83
+ .option("-y, --yes", "skip confirmation prompt.", false)
84
+ .option("-o, --overwrite", "overwrite existing files.", false)
26
85
  .option(
27
86
  "-c, --cwd <cwd>",
28
87
  "the working directory. defaults to the current directory.",
29
88
  process.cwd(),
30
89
  )
31
- .option(
32
- "-p, --preset <url>",
33
- "preset URL from playground (e.g., https://www.assistant-ui.com/playground/init?preset=chatgpt)",
34
- )
35
- .option(
36
- "-t, --template <template>",
37
- `template to use (${templateNames.join(", ")})`,
38
- "minimal",
90
+ .addOption(
91
+ new Option(
92
+ "-p, --preset <url>",
93
+ "preset URL from playground (forwarded to 'assistant-ui create')",
94
+ ).hideHelp(),
39
95
  )
40
96
  .option("--use-npm", "explicitly use npm")
41
97
  .option("--use-pnpm", "explicitly use pnpm")
@@ -44,12 +100,14 @@ export const init = new Command()
44
100
  .option("--skip-install", "skip installing packages")
45
101
  .action(async (projectDirectory, opts) => {
46
102
  const cwd = opts.cwd;
103
+ const presetUrl = opts.preset as string | undefined;
47
104
  const targetDir = projectDirectory
48
105
  ? path.resolve(cwd, projectDirectory)
49
106
  : cwd;
50
- const presetUrl = opts.preset;
51
107
 
52
- if (hasConfig(targetDir)) {
108
+ const componentsConfigPath = path.join(targetDir, "components.json");
109
+
110
+ if (!presetUrl && fs.existsSync(componentsConfigPath)) {
53
111
  logger.warn("Project is already initialized.");
54
112
  logger.info("Use 'assistant-ui add' to add more components.");
55
113
  return;
@@ -58,78 +116,62 @@ export const init = new Command()
58
116
  const packageJsonPath = path.join(targetDir, "package.json");
59
117
  const packageJsonExists = fs.existsSync(packageJsonPath);
60
118
 
61
- if (packageJsonExists) {
62
- const registryUrl = presetUrl ?? DEFAULT_REGISTRY_URL;
63
-
64
- if (presetUrl) {
65
- logger.info("Initializing assistant-ui with preset configuration...");
66
- } else {
67
- logger.info("Initializing assistant-ui in existing project...");
119
+ if (presetUrl || !packageJsonExists) {
120
+ if (!presetUrl) {
121
+ logger.info("No existing project found. Running 'create' instead...");
122
+ logger.break();
68
123
  }
69
- logger.break();
70
124
 
71
- const child = spawn("npx", [`shadcn@latest`, "add", registryUrl], {
72
- stdio: "inherit",
73
- cwd: targetDir,
74
- });
75
-
76
- child.on("error", (error) => {
77
- logger.error(`Failed to initialize: ${error.message}`);
78
- process.exit(1);
79
- });
125
+ const createArgs: string[] = [];
126
+ if (projectDirectory) createArgs.push(projectDirectory);
127
+ if (presetUrl) createArgs.push("--preset", presetUrl);
128
+ if (opts.useNpm) createArgs.push("--use-npm");
129
+ if (opts.usePnpm) createArgs.push("--use-pnpm");
130
+ if (opts.useYarn) createArgs.push("--use-yarn");
131
+ if (opts.useBun) createArgs.push("--use-bun");
132
+ if (opts.skipInstall) createArgs.push("--skip-install");
80
133
 
81
- child.on("close", (code) => {
82
- if (code !== 0) {
83
- logger.error(`Initialization failed with code ${code}`);
84
- process.exit(code || 1);
85
- } else {
86
- logger.break();
87
- logger.success("Project initialized successfully!");
88
- logger.info(
89
- "You can now add more components with 'assistant-ui add'",
90
- );
91
- }
92
- });
93
- } else {
94
- const templateName = opts.template as keyof typeof templates;
95
- const templateUrl = templates[templateName];
96
-
97
- if (!templateUrl) {
98
- logger.error(`Unknown template: ${opts.template}`);
99
- logger.info(`Available templates: ${templateNames.join(", ")}`);
100
- process.exit(1);
101
- }
134
+ await create.parseAsync(createArgs, { from: "user" });
135
+ return;
136
+ }
102
137
 
103
- logger.info(
104
- `Creating a new assistant-ui project (template: ${templateName})...`,
138
+ const registryUrl = DEFAULT_REGISTRY_URL;
139
+ logger.info("Initializing assistant-ui in existing project...");
140
+ logger.break();
141
+
142
+ if (!opts.yes && isNonInteractiveShell()) {
143
+ logger.error(
144
+ [
145
+ "Detected a non-interactive shell, but 'assistant-ui init' needs interactive prompts by default.",
146
+ "To run this in CI/agent mode, re-run with '--yes' so shadcn initialization and component install run non-interactively.",
147
+ "Example: assistant-ui init --yes",
148
+ ].join("\n"),
105
149
  );
106
- logger.break();
107
-
108
- const cnaArgs: string[] = ["create-next-app@latest"];
109
- cnaArgs.push(projectDirectory || ".");
110
- cnaArgs.push("-e", templateUrl);
111
-
112
- if (opts.useNpm) cnaArgs.push("--use-npm");
113
- if (opts.usePnpm) cnaArgs.push("--use-pnpm");
114
- if (opts.useYarn) cnaArgs.push("--use-yarn");
115
- if (opts.useBun) cnaArgs.push("--use-bun");
116
- if (opts.skipInstall) cnaArgs.push("--skip-install");
117
-
118
- const child = spawn("npx", cnaArgs, { stdio: "inherit", cwd });
150
+ process.exit(1);
151
+ }
119
152
 
120
- child.on("error", (error) => {
121
- logger.error(`Failed to create project: ${error.message}`);
122
- process.exit(1);
153
+ try {
154
+ const { initArgs, addArgs } = createExistingProjectInitPlan({
155
+ yes: opts.yes,
156
+ overwrite: opts.overwrite,
157
+ registryUrl,
123
158
  });
124
159
 
125
- child.on("close", (code) => {
126
- if (code !== 0) {
127
- logger.error(`Project creation failed with code ${code}`);
128
- process.exit(code || 1);
129
- } else {
130
- logger.break();
131
- logger.success("Project created successfully!");
132
- }
133
- });
160
+ if (initArgs) {
161
+ await runSpawn("npx", initArgs, targetDir);
162
+ }
163
+ await runSpawn("npx", addArgs, targetDir);
164
+
165
+ logger.break();
166
+ logger.success("Project initialized successfully!");
167
+ logger.info("You can now add more components with 'assistant-ui add'");
168
+ } catch (error) {
169
+ if (error instanceof SpawnExitError) {
170
+ logger.error(`Initialization failed with code ${error.code}`);
171
+ process.exit(error.code);
172
+ }
173
+ const message = error instanceof Error ? error.message : String(error);
174
+ logger.error(`Failed to initialize: ${message}`);
175
+ process.exit(1);
134
176
  }
135
177
  });
@@ -16,7 +16,9 @@ export interface CreateFromExampleOptions {
16
16
  const VALID_EXAMPLES = [
17
17
  "with-ag-ui",
18
18
  "with-ai-sdk-v6",
19
+ "with-artifacts",
19
20
  "with-assistant-transport",
21
+ "with-chain-of-thought",
20
22
  "with-cloud",
21
23
  "with-custom-thread-list",
22
24
  "with-elevenlabs-scribe",
@@ -87,10 +89,13 @@ export async function createFromExample(
87
89
  }
88
90
 
89
91
  // 9. Install shadcn UI components (standard shadcn components like button, tooltip, etc.)
90
- if (shadcnUI.length > 0) {
91
- logger.step(`Installing shadcn UI components: ${shadcnUI.join(", ")}...`);
92
- await installShadcnComponents(absoluteProjectDir, shadcnUI);
92
+ // Always include "utils" since assistant-ui components import cn from @/lib/utils
93
+ // and shadcn does not declare it as a registryDependency of button/tooltip/etc.
94
+ if (!shadcnUI.includes("utils")) {
95
+ shadcnUI.push("utils");
93
96
  }
97
+ logger.step(`Installing shadcn UI components: ${shadcnUI.join(", ")}...`);
98
+ await installShadcnComponents(absoluteProjectDir, shadcnUI);
94
99
 
95
100
  // 10. Install assistant-ui components
96
101
  if (assistantUI.length > 0) {
@@ -211,6 +216,7 @@ async function transformTsConfig(projectDir: string): Promise<void> {
211
216
  if (tsconfig.compilerOptions?.paths) {
212
217
  delete tsconfig.compilerOptions.paths["@/components/assistant-ui/*"];
213
218
  delete tsconfig.compilerOptions.paths["@/components/ui/*"];
219
+ delete tsconfig.compilerOptions.paths["@/lib/utils"];
214
220
  delete tsconfig.compilerOptions.paths["@assistant-ui/ui/*"];
215
221
 
216
222
  // If paths is empty, remove it
@@ -13,6 +13,7 @@ const bundle = [
13
13
  "v0-11/content-part-to-message-part",
14
14
  "v0-12/assistant-api-to-aui",
15
15
  "v0-12/event-names-to-camelcase",
16
+ "v0-12/primitive-if-to-aui-if",
16
17
  ];
17
18
 
18
19
  const log = debug("codemod:upgrade");