create-assistant-ui 0.0.40 → 0.0.42

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/index.js CHANGED
@@ -2,21 +2,89 @@
2
2
  import { Command } from "commander";
3
3
  import chalk from "chalk";
4
4
  import { spawn } from "cross-spawn";
5
- // Keep in sync with packages/cli/src/lib/constants.ts
5
+ import path from "node:path";
6
+ import * as p from "@clack/prompts";
7
+ // Keep in sync with packages/cli/src/commands/create.ts
6
8
  const templates = {
7
- default: "https://github.com/assistant-ui/assistant-ui-starter",
8
- minimal: "https://github.com/assistant-ui/assistant-ui-starter-minimal",
9
- cloud: "https://github.com/assistant-ui/assistant-ui-starter-cloud",
10
- langgraph: "https://github.com/assistant-ui/assistant-ui-starter-langgraph",
11
- mcp: "https://github.com/assistant-ui/assistant-ui-starter-mcp",
9
+ default: {
10
+ url: "https://github.com/assistant-ui/assistant-ui-starter",
11
+ label: "Default",
12
+ hint: "Default template with Vercel AI SDK",
13
+ },
14
+ minimal: {
15
+ url: "https://github.com/assistant-ui/assistant-ui-starter-minimal",
16
+ label: "Minimal",
17
+ hint: "Bare-bones starting point",
18
+ },
19
+ cloud: {
20
+ url: "https://github.com/assistant-ui/assistant-cloud-starter",
21
+ label: "Cloud",
22
+ hint: "Cloud-backed persistence starter",
23
+ },
24
+ "cloud-clerk": {
25
+ url: "https://github.com/assistant-ui/assistant-ui-starter-cloud-clerk",
26
+ label: "Cloud + Clerk",
27
+ hint: "Cloud-backed starter with Clerk auth",
28
+ },
29
+ langgraph: {
30
+ url: "https://github.com/assistant-ui/assistant-ui-starter-langgraph",
31
+ label: "LangGraph",
32
+ hint: "LangGraph starter template",
33
+ },
34
+ mcp: {
35
+ url: "https://github.com/assistant-ui/assistant-ui-starter-mcp",
36
+ label: "MCP",
37
+ hint: "MCP starter template",
38
+ },
12
39
  };
40
+ const templateNames = Object.keys(templates);
41
+ class SpawnExitError extends Error {
42
+ code;
43
+ constructor(code) {
44
+ super(`Process exited with code ${code}`);
45
+ this.code = code;
46
+ }
47
+ }
48
+ async function runSpawn(command, args, cwd) {
49
+ return new Promise((resolve, reject) => {
50
+ const child = spawn(command, args, {
51
+ stdio: "inherit",
52
+ cwd,
53
+ });
54
+ child.on("error", (error) => reject(error));
55
+ child.on("close", (code) => {
56
+ if (code !== 0) {
57
+ reject(new SpawnExitError(code || 1));
58
+ }
59
+ else {
60
+ resolve();
61
+ }
62
+ });
63
+ });
64
+ }
65
+ function buildCreateNextAppArgs(commandArgs, templateUrl) {
66
+ const filteredArgs = commandArgs.filter((arg, index, arr) => {
67
+ const previousArg = arr[index - 1];
68
+ return !(arg === "-t" ||
69
+ arg === "--template" ||
70
+ arg.startsWith("--template=") ||
71
+ previousArg === "-t" ||
72
+ previousArg === "--template" ||
73
+ arg === "-p" ||
74
+ arg === "--preset" ||
75
+ arg.startsWith("--preset=") ||
76
+ previousArg === "-p" ||
77
+ previousArg === "--preset");
78
+ });
79
+ return ["create-next-app@latest", ...filteredArgs, "-e", templateUrl];
80
+ }
13
81
  const create = new Command()
14
82
  .name("create-assistant-ui")
15
83
  .description("create a new assistant-ui project")
16
84
  .argument("[project-directory]")
17
85
  .usage(`${chalk.green("[project-directory]")} [options]`)
18
86
  .option("-t, --template <template>", `
19
- The template to use (${Object.keys(templates).join(", ")})
87
+ The template to use (${templateNames.join(", ")})
20
88
  `)
21
89
  .option("--use-npm", `
22
90
 
@@ -38,31 +106,57 @@ const create = new Command()
38
106
 
39
107
  Explicitly tell the CLI to skip installing packages
40
108
  `)
41
- .action((_, opts) => {
42
- const templateUrl = templates[opts.template ?? "default"];
43
- if (!templateUrl) {
44
- console.error(`Unknown template: ${opts.template}\nAvailable templates: ${Object.keys(templates).join(", ")}`);
109
+ .option("-p, --preset <url>", `
110
+
111
+ Preset URL from playground (e.g., https://www.assistant-ui.com/playground/init?preset=chatgpt)
112
+ `)
113
+ .action(async (projectDirectory, opts) => {
114
+ if (opts.preset && !projectDirectory) {
115
+ console.error("Project directory is required when using --preset.");
45
116
  process.exit(1);
46
117
  }
47
- const filteredArgs = process.argv.slice(2).filter((arg, index, arr) => {
48
- return !(arg === "-t" ||
49
- arg === "--template" ||
50
- arr[index - 1] === "-t" ||
51
- arr[index - 1] === "--template");
52
- });
53
- const child = spawn("npx", [`create-next-app@latest`, ...filteredArgs, "-e", templateUrl], {
54
- stdio: "inherit",
55
- });
56
- child.on("error", (error) => {
57
- console.error(`Error: ${error.message}`);
118
+ let templateName;
119
+ if (opts.template) {
120
+ templateName = opts.template;
121
+ }
122
+ else if (process.stdin.isTTY) {
123
+ const selected = await p.select({
124
+ message: "Select a template:",
125
+ options: templateNames.map((name) => ({
126
+ value: name,
127
+ label: templates[name].label,
128
+ hint: templates[name].hint,
129
+ })),
130
+ });
131
+ if (p.isCancel(selected)) {
132
+ p.cancel("Project creation cancelled.");
133
+ process.exit(0);
134
+ }
135
+ templateName = selected;
136
+ }
137
+ else {
138
+ templateName = "default";
139
+ }
140
+ const templateUrl = templates[templateName]?.url;
141
+ if (!templateUrl) {
142
+ console.error(`Unknown template: ${opts.template}\nAvailable templates: ${templateNames.join(", ")}`);
58
143
  process.exit(1);
59
- });
60
- child.on("close", (code) => {
61
- if (code !== 0) {
62
- console.error(`create-next-app process exited with code ${code}`);
63
- process.exit(code || 1);
144
+ }
145
+ try {
146
+ await runSpawn("npx", buildCreateNextAppArgs(process.argv.slice(2), templateUrl));
147
+ if (opts.preset) {
148
+ await runSpawn("npx", ["shadcn@latest", "add", "--yes", opts.preset], path.resolve(process.cwd(), projectDirectory));
64
149
  }
65
- });
150
+ }
151
+ catch (error) {
152
+ if (error instanceof SpawnExitError) {
153
+ console.error(`create-next-app process exited with code ${error.code}`);
154
+ process.exit(error.code);
155
+ }
156
+ const message = error instanceof Error ? error.message : String(error);
157
+ console.error(`Error: ${message}`);
158
+ process.exit(1);
159
+ }
66
160
  });
67
161
  process.on("SIGINT", () => process.exit(0));
68
162
  process.on("SIGTERM", () => process.exit(0));
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-assistant-ui",
3
- "version": "0.0.40",
3
+ "version": "0.0.42",
4
4
  "description": "Create assistant-ui apps with one command",
5
5
  "keywords": [
6
6
  "cli",
@@ -25,6 +25,7 @@
25
25
  ],
26
26
  "sideEffects": false,
27
27
  "dependencies": {
28
+ "@clack/prompts": "^1.0.0",
28
29
  "chalk": "^5.6.2",
29
30
  "commander": "^14.0.3",
30
31
  "cross-spawn": "^7.0.6"
package/src/index.ts CHANGED
@@ -2,15 +2,95 @@
2
2
  import { Command } from "commander";
3
3
  import chalk from "chalk";
4
4
  import { spawn } from "cross-spawn";
5
+ import path from "node:path";
6
+ import * as p from "@clack/prompts";
5
7
 
6
- // Keep in sync with packages/cli/src/lib/constants.ts
8
+ // Keep in sync with packages/cli/src/commands/create.ts
7
9
  const templates = {
8
- default: "https://github.com/assistant-ui/assistant-ui-starter",
9
- minimal: "https://github.com/assistant-ui/assistant-ui-starter-minimal",
10
- cloud: "https://github.com/assistant-ui/assistant-ui-starter-cloud",
11
- langgraph: "https://github.com/assistant-ui/assistant-ui-starter-langgraph",
12
- mcp: "https://github.com/assistant-ui/assistant-ui-starter-mcp",
13
- };
10
+ default: {
11
+ url: "https://github.com/assistant-ui/assistant-ui-starter",
12
+ label: "Default",
13
+ hint: "Default template with Vercel AI SDK",
14
+ },
15
+ minimal: {
16
+ url: "https://github.com/assistant-ui/assistant-ui-starter-minimal",
17
+ label: "Minimal",
18
+ hint: "Bare-bones starting point",
19
+ },
20
+ cloud: {
21
+ url: "https://github.com/assistant-ui/assistant-cloud-starter",
22
+ label: "Cloud",
23
+ hint: "Cloud-backed persistence starter",
24
+ },
25
+ "cloud-clerk": {
26
+ url: "https://github.com/assistant-ui/assistant-ui-starter-cloud-clerk",
27
+ label: "Cloud + Clerk",
28
+ hint: "Cloud-backed starter with Clerk auth",
29
+ },
30
+ langgraph: {
31
+ url: "https://github.com/assistant-ui/assistant-ui-starter-langgraph",
32
+ label: "LangGraph",
33
+ hint: "LangGraph starter template",
34
+ },
35
+ mcp: {
36
+ url: "https://github.com/assistant-ui/assistant-ui-starter-mcp",
37
+ label: "MCP",
38
+ hint: "MCP starter template",
39
+ },
40
+ } as const;
41
+
42
+ type TemplateName = keyof typeof templates;
43
+ const templateNames = Object.keys(templates) as TemplateName[];
44
+
45
+ class SpawnExitError extends Error {
46
+ code: number;
47
+
48
+ constructor(code: number) {
49
+ super(`Process exited with code ${code}`);
50
+ this.code = code;
51
+ }
52
+ }
53
+
54
+ async function runSpawn(command: string, args: string[], cwd?: string) {
55
+ return new Promise<void>((resolve, reject) => {
56
+ const child = spawn(command, args, {
57
+ stdio: "inherit",
58
+ cwd,
59
+ });
60
+
61
+ child.on("error", (error) => reject(error));
62
+ child.on("close", (code) => {
63
+ if (code !== 0) {
64
+ reject(new SpawnExitError(code || 1));
65
+ } else {
66
+ resolve();
67
+ }
68
+ });
69
+ });
70
+ }
71
+
72
+ function buildCreateNextAppArgs(
73
+ commandArgs: string[],
74
+ templateUrl: string,
75
+ ): string[] {
76
+ const filteredArgs = commandArgs.filter((arg, index, arr) => {
77
+ const previousArg = arr[index - 1];
78
+ return !(
79
+ arg === "-t" ||
80
+ arg === "--template" ||
81
+ arg.startsWith("--template=") ||
82
+ previousArg === "-t" ||
83
+ previousArg === "--template" ||
84
+ arg === "-p" ||
85
+ arg === "--preset" ||
86
+ arg.startsWith("--preset=") ||
87
+ previousArg === "-p" ||
88
+ previousArg === "--preset"
89
+ );
90
+ });
91
+
92
+ return ["create-next-app@latest", ...filteredArgs, "-e", templateUrl];
93
+ }
14
94
 
15
95
  const create = new Command()
16
96
  .name("create-assistant-ui")
@@ -20,7 +100,7 @@ const create = new Command()
20
100
  .option(
21
101
  "-t, --template <template>",
22
102
  `
23
- The template to use (${Object.keys(templates).join(", ")})
103
+ The template to use (${templateNames.join(", ")})
24
104
  `,
25
105
  )
26
106
  .option(
@@ -58,44 +138,70 @@ const create = new Command()
58
138
  Explicitly tell the CLI to skip installing packages
59
139
  `,
60
140
  )
61
- .action((_, opts) => {
62
- const templateUrl =
63
- templates[(opts.template as keyof typeof templates) ?? "default"];
141
+ .option(
142
+ "-p, --preset <url>",
143
+ `
144
+
145
+ Preset URL from playground (e.g., https://www.assistant-ui.com/playground/init?preset=chatgpt)
146
+ `,
147
+ )
148
+ .action(async (projectDirectory, opts) => {
149
+ if (opts.preset && !projectDirectory) {
150
+ console.error("Project directory is required when using --preset.");
151
+ process.exit(1);
152
+ }
153
+
154
+ let templateName: TemplateName;
155
+ if (opts.template) {
156
+ templateName = opts.template as TemplateName;
157
+ } else if (process.stdin.isTTY) {
158
+ const selected = await p.select({
159
+ message: "Select a template:",
160
+ options: templateNames.map((name) => ({
161
+ value: name,
162
+ label: templates[name].label,
163
+ hint: templates[name].hint,
164
+ })),
165
+ });
166
+ if (p.isCancel(selected)) {
167
+ p.cancel("Project creation cancelled.");
168
+ process.exit(0);
169
+ }
170
+ templateName = selected as TemplateName;
171
+ } else {
172
+ templateName = "default";
173
+ }
174
+
175
+ const templateUrl = templates[templateName]?.url;
64
176
  if (!templateUrl) {
65
177
  console.error(
66
- `Unknown template: ${opts.template}\nAvailable templates: ${Object.keys(templates).join(", ")}`,
178
+ `Unknown template: ${opts.template}\nAvailable templates: ${templateNames.join(", ")}`,
67
179
  );
68
180
  process.exit(1);
69
181
  }
70
182
 
71
- const filteredArgs = process.argv.slice(2).filter((arg, index, arr) => {
72
- return !(
73
- arg === "-t" ||
74
- arg === "--template" ||
75
- arr[index - 1] === "-t" ||
76
- arr[index - 1] === "--template"
183
+ try {
184
+ await runSpawn(
185
+ "npx",
186
+ buildCreateNextAppArgs(process.argv.slice(2), templateUrl),
77
187
  );
78
- });
79
-
80
- const child = spawn(
81
- "npx",
82
- [`create-next-app@latest`, ...filteredArgs, "-e", templateUrl],
83
- {
84
- stdio: "inherit",
85
- },
86
- );
87
188
 
88
- child.on("error", (error) => {
89
- console.error(`Error: ${error.message}`);
90
- process.exit(1);
91
- });
92
-
93
- child.on("close", (code) => {
94
- if (code !== 0) {
95
- console.error(`create-next-app process exited with code ${code}`);
96
- process.exit(code || 1);
189
+ if (opts.preset) {
190
+ await runSpawn(
191
+ "npx",
192
+ ["shadcn@latest", "add", "--yes", opts.preset],
193
+ path.resolve(process.cwd(), projectDirectory),
194
+ );
97
195
  }
98
- });
196
+ } catch (error) {
197
+ if (error instanceof SpawnExitError) {
198
+ console.error(`create-next-app process exited with code ${error.code}`);
199
+ process.exit(error.code);
200
+ }
201
+ const message = error instanceof Error ? error.message : String(error);
202
+ console.error(`Error: ${message}`);
203
+ process.exit(1);
204
+ }
99
205
  });
100
206
 
101
207
  process.on("SIGINT", () => process.exit(0));