assistant-ui 0.0.112 → 0.0.113
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.d.ts.map +1 -1
- package/dist/codemods/v0-12/assistant-api-to-aui.js +87 -62
- package/dist/codemods/v0-12/assistant-api-to-aui.js.map +1 -1
- package/dist/codemods/v0-12/primitive-if-to-aui-if.d.ts.map +1 -1
- package/dist/codemods/v0-12/primitive-if-to-aui-if.js +31 -45
- package/dist/codemods/v0-12/primitive-if-to-aui-if.js.map +1 -1
- package/dist/commands/add.d.ts +1 -1
- package/dist/commands/add.d.ts.map +1 -1
- package/dist/commands/add.js +4 -2
- package/dist/commands/add.js.map +1 -1
- package/dist/commands/create.d.ts.map +1 -1
- package/dist/commands/create.js +33 -10
- package/dist/commands/create.js.map +1 -1
- package/dist/commands/info.d.ts.map +1 -1
- package/dist/commands/info.js +2 -1
- package/dist/commands/info.js.map +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +4 -2
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/mcp.d.ts.map +1 -1
- package/dist/commands/mcp.js +25 -28
- package/dist/commands/mcp.js.map +1 -1
- package/dist/commands/update.js +6 -7
- package/dist/commands/update.js.map +1 -1
- package/dist/commands/upgrade.d.ts.map +1 -1
- package/dist/commands/upgrade.js +5 -2
- package/dist/commands/upgrade.js.map +1 -1
- package/dist/index.js +2 -6
- package/dist/index.js.map +1 -1
- package/dist/lib/agent-skill.d.ts +1 -1
- package/dist/lib/agent-skill.d.ts.map +1 -1
- package/dist/lib/agent-skill.js.map +1 -1
- package/dist/lib/create-project.d.ts +2 -3
- package/dist/lib/create-project.d.ts.map +1 -1
- package/dist/lib/create-project.js +17 -42
- package/dist/lib/create-project.js.map +1 -1
- package/dist/lib/handle-cli-error.d.ts +5 -0
- package/dist/lib/handle-cli-error.d.ts.map +1 -0
- package/dist/lib/handle-cli-error.js +17 -0
- package/dist/lib/handle-cli-error.js.map +1 -0
- package/dist/lib/install-ai-sdk-lib.js +8 -1
- package/dist/lib/install-ai-sdk-lib.js.map +1 -1
- package/dist/lib/install-edge-lib.js +4 -8
- package/dist/lib/install-edge-lib.js.map +1 -1
- package/dist/lib/run-spawn.d.ts +16 -2
- package/dist/lib/run-spawn.d.ts.map +1 -1
- package/dist/lib/run-spawn.js +87 -9
- package/dist/lib/run-spawn.js.map +1 -1
- package/dist/lib/transform.d.ts +1 -1
- package/dist/lib/transform.d.ts.map +1 -1
- package/dist/lib/transform.js +12 -25
- package/dist/lib/transform.js.map +1 -1
- package/dist/lib/upgrade.js +20 -16
- package/dist/lib/upgrade.js.map +1 -1
- package/dist/lib/utils/file-scanner.d.ts +9 -1
- package/dist/lib/utils/file-scanner.d.ts.map +1 -1
- package/dist/lib/utils/file-scanner.js +22 -20
- package/dist/lib/utils/file-scanner.js.map +1 -1
- package/dist/lib/utils/package-installer.js +1 -1
- package/dist/lib/utils/package-manager.d.ts +3 -1
- package/dist/lib/utils/package-manager.d.ts.map +1 -1
- package/dist/lib/utils/package-manager.js +22 -10
- package/dist/lib/utils/package-manager.js.map +1 -1
- package/package.json +6 -6
- package/plugin/skills/assistant-ui/SKILL.md +3 -3
- package/src/codemods/v0-12/__tests__/assistant-api-to-aui.test.ts +370 -0
- package/src/codemods/v0-12/__tests__/primitive-if-to-aui-if.test.ts +100 -0
- package/src/codemods/v0-12/assistant-api-to-aui.ts +227 -134
- package/src/codemods/v0-12/primitive-if-to-aui-if.ts +44 -72
- package/src/commands/add.ts +5 -5
- package/src/commands/create.ts +41 -7
- package/src/commands/info.ts +1 -0
- package/src/commands/init.ts +4 -6
- package/src/commands/mcp.ts +20 -29
- package/src/commands/update.ts +6 -8
- package/src/commands/upgrade.ts +5 -2
- package/src/index.ts +2 -7
- package/src/lib/agent-skill.ts +2 -1
- package/src/lib/create-project.ts +24 -58
- package/src/lib/handle-cli-error.test.ts +67 -0
- package/src/lib/handle-cli-error.ts +17 -0
- package/src/lib/install-ai-sdk-lib.ts +13 -1
- package/src/lib/install-edge-lib.ts +7 -8
- package/src/lib/run-spawn.test.ts +148 -0
- package/src/lib/run-spawn.ts +121 -11
- package/src/lib/transform.test.ts +62 -0
- package/src/lib/transform.ts +21 -37
- package/src/lib/upgrade.ts +23 -19
- package/src/lib/utils/file-scanner.ts +26 -20
- package/src/lib/utils/package-manager.ts +29 -12
package/src/commands/create.ts
CHANGED
|
@@ -9,12 +9,17 @@ import {
|
|
|
9
9
|
downloadProject,
|
|
10
10
|
resolveLatestReleaseRef,
|
|
11
11
|
resolvePackageManager,
|
|
12
|
-
resolvePackageManagerForCwd,
|
|
13
12
|
scaffoldProject,
|
|
14
13
|
transformProject,
|
|
15
14
|
type TransformResult,
|
|
16
15
|
} from "../lib/create-project";
|
|
17
|
-
import {
|
|
16
|
+
import {
|
|
17
|
+
hasActiveSpawn,
|
|
18
|
+
runSpawn,
|
|
19
|
+
SpawnExitError,
|
|
20
|
+
SpawnSignalError,
|
|
21
|
+
} from "../lib/run-spawn";
|
|
22
|
+
import { resolvePackageManagerForCwd } from "../lib/utils/package-manager";
|
|
18
23
|
import {
|
|
19
24
|
buildSkillsAddCommand,
|
|
20
25
|
resolveSkillsInstall,
|
|
@@ -597,10 +602,31 @@ export const create = new Command()
|
|
|
597
602
|
);
|
|
598
603
|
|
|
599
604
|
// Clean up partial project directory on unexpected exit (e.g. Ctrl+C)
|
|
605
|
+
let cleanupArmed = true;
|
|
600
606
|
const cleanupOnExit = () => {
|
|
607
|
+
if (!cleanupArmed) return;
|
|
608
|
+
cleanupArmed = false;
|
|
601
609
|
fs.rmSync(absoluteProjectDir, { recursive: true, force: true });
|
|
602
610
|
};
|
|
611
|
+
const disarmCleanup = () => {
|
|
612
|
+
cleanupArmed = false;
|
|
613
|
+
process.removeListener("exit", cleanupOnExit);
|
|
614
|
+
process.removeListener("SIGINT", cleanupOnSignal);
|
|
615
|
+
process.removeListener("SIGTERM", cleanupOnSignal);
|
|
616
|
+
};
|
|
617
|
+
// Node emits no "exit" when a signal kills the process. An in-flight
|
|
618
|
+
// runSpawn forwards the signal itself, so the directory is removed on the
|
|
619
|
+
// error path once the child is reaped rather than while it is still writing.
|
|
620
|
+
const cleanupOnSignal = (signal: NodeJS.Signals) => {
|
|
621
|
+
if (hasActiveSpawn()) return;
|
|
622
|
+
cleanupOnExit();
|
|
623
|
+
disarmCleanup();
|
|
624
|
+
process.kill(process.pid, signal);
|
|
625
|
+
};
|
|
626
|
+
|
|
603
627
|
process.once("exit", cleanupOnExit);
|
|
628
|
+
process.on("SIGINT", cleanupOnSignal);
|
|
629
|
+
process.on("SIGTERM", cleanupOnSignal);
|
|
604
630
|
|
|
605
631
|
try {
|
|
606
632
|
// 3. Resolve latest release ref (started before prompts)
|
|
@@ -655,7 +681,8 @@ export const create = new Command()
|
|
|
655
681
|
});
|
|
656
682
|
try {
|
|
657
683
|
await runSpawn(skillsCmd, skillsArgs, absoluteProjectDir);
|
|
658
|
-
} catch {
|
|
684
|
+
} catch (error) {
|
|
685
|
+
if (error instanceof SpawnSignalError) throw error;
|
|
659
686
|
logger.warn(
|
|
660
687
|
`Could not add assistant-ui agent skills. You can add them later with:\n ${skillsCmd} ${skillsArgs.join(" ")}`,
|
|
661
688
|
);
|
|
@@ -663,12 +690,13 @@ export const create = new Command()
|
|
|
663
690
|
}
|
|
664
691
|
} catch (err) {
|
|
665
692
|
// Clean up partially created project directory
|
|
666
|
-
|
|
693
|
+
cleanupOnExit();
|
|
694
|
+
disarmCleanup();
|
|
667
695
|
throw err;
|
|
668
696
|
}
|
|
669
697
|
|
|
670
698
|
if (transformResult.registryInstallFailure) {
|
|
671
|
-
|
|
699
|
+
disarmCleanup();
|
|
672
700
|
logger.break();
|
|
673
701
|
logger.error("Project created with missing components.");
|
|
674
702
|
logger.info("Retry the component install with:");
|
|
@@ -696,14 +724,15 @@ export const create = new Command()
|
|
|
696
724
|
],
|
|
697
725
|
absoluteProjectDir,
|
|
698
726
|
);
|
|
699
|
-
} catch {
|
|
727
|
+
} catch (error) {
|
|
728
|
+
if (error instanceof SpawnSignalError) throw error;
|
|
700
729
|
logger.warn(
|
|
701
730
|
`Preset application failed. You can retry manually with:\n ${dlxCmd} ${[...dlxArgs, "shadcn@latest", "add", presetUrl].join(" ")}`,
|
|
702
731
|
);
|
|
703
732
|
}
|
|
704
733
|
}
|
|
705
734
|
|
|
706
|
-
|
|
735
|
+
disarmCleanup();
|
|
707
736
|
|
|
708
737
|
logger.break();
|
|
709
738
|
logger.success("Project created successfully!");
|
|
@@ -736,6 +765,11 @@ export const create = new Command()
|
|
|
736
765
|
logger.info(` # Set up your environment variables in ${envFile}`);
|
|
737
766
|
logger.info(` ${runCmd} ${devScript}`);
|
|
738
767
|
} catch (error) {
|
|
768
|
+
if (error instanceof SpawnSignalError) {
|
|
769
|
+
cleanupOnExit();
|
|
770
|
+
disarmCleanup();
|
|
771
|
+
throw error;
|
|
772
|
+
}
|
|
739
773
|
if (error instanceof SpawnExitError) {
|
|
740
774
|
logger.error(`Project creation failed with code ${error.code}`);
|
|
741
775
|
process.exit(error.code);
|
package/src/commands/info.ts
CHANGED
package/src/commands/init.ts
CHANGED
|
@@ -1,13 +1,10 @@
|
|
|
1
1
|
import { Command, Option } from "commander";
|
|
2
2
|
import fs from "node:fs";
|
|
3
3
|
import path from "node:path";
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
resolvePackageManager,
|
|
7
|
-
resolvePackageManagerForCwd,
|
|
8
|
-
} from "../lib/create-project";
|
|
9
|
-
import { runSpawn, SpawnExitError } from "../lib/run-spawn";
|
|
4
|
+
import { dlxCommand, resolvePackageManager } from "../lib/create-project";
|
|
5
|
+
import { runSpawn, SpawnExitError, SpawnSignalError } from "../lib/run-spawn";
|
|
10
6
|
import { logger } from "../lib/utils/logger";
|
|
7
|
+
import { resolvePackageManagerForCwd } from "../lib/utils/package-manager";
|
|
11
8
|
import {
|
|
12
9
|
getComponentsJsonStyle,
|
|
13
10
|
resolveQuickStartRegistryUrl,
|
|
@@ -135,6 +132,7 @@ export const init = new Command()
|
|
|
135
132
|
logger.success("Project initialized successfully!");
|
|
136
133
|
logger.info("You can now add more components with 'assistant-ui add'");
|
|
137
134
|
} catch (error) {
|
|
135
|
+
if (error instanceof SpawnSignalError) throw error;
|
|
138
136
|
if (error instanceof SpawnExitError) {
|
|
139
137
|
logger.error(`Initialization failed with code ${error.code}`);
|
|
140
138
|
process.exit(error.code);
|
package/src/commands/mcp.ts
CHANGED
|
@@ -2,8 +2,8 @@ import { Command } from "commander";
|
|
|
2
2
|
import fs from "node:fs";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import os from "node:os";
|
|
5
|
-
import { spawn } from "cross-spawn";
|
|
6
5
|
import { logger } from "../lib/utils/logger";
|
|
6
|
+
import { runSpawn, SpawnExitError, SpawnSignalError } from "../lib/run-spawn";
|
|
7
7
|
import * as p from "@clack/prompts";
|
|
8
8
|
|
|
9
9
|
type MCPTarget =
|
|
@@ -152,9 +152,8 @@ async function installForTarget(target: MCPTarget): Promise<void> {
|
|
|
152
152
|
logger.info("Installing MCP server for Claude Code...");
|
|
153
153
|
logger.break();
|
|
154
154
|
|
|
155
|
-
|
|
156
|
-
"claude",
|
|
157
|
-
[
|
|
155
|
+
try {
|
|
156
|
+
await runSpawn("claude", [
|
|
158
157
|
"mcp",
|
|
159
158
|
"add",
|
|
160
159
|
"assistant-ui",
|
|
@@ -162,35 +161,26 @@ async function installForTarget(target: MCPTarget): Promise<void> {
|
|
|
162
161
|
"npx",
|
|
163
162
|
"-y",
|
|
164
163
|
"@assistant-ui/mcp-docs-server",
|
|
165
|
-
]
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
return new Promise((resolve, reject) => {
|
|
172
|
-
child.on("error", (error) => {
|
|
164
|
+
]);
|
|
165
|
+
} catch (error) {
|
|
166
|
+
if (error instanceof SpawnSignalError) throw error;
|
|
167
|
+
if (error instanceof SpawnExitError) {
|
|
168
|
+
logger.error(`Installation failed with code ${error.code}`);
|
|
169
|
+
} else if (error instanceof Error) {
|
|
173
170
|
logger.error(`Failed to install: ${error.message}`);
|
|
174
171
|
logger.info(
|
|
175
172
|
"Make sure Claude Code CLI is installed: https://docs.anthropic.com/en/docs/claude-code",
|
|
176
173
|
);
|
|
177
|
-
|
|
178
|
-
|
|
174
|
+
}
|
|
175
|
+
throw error;
|
|
176
|
+
}
|
|
179
177
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
logger.success("MCP server installed for Claude Code!");
|
|
187
|
-
logger.info(
|
|
188
|
-
"The server starts automatically. Try asking about assistant-ui!",
|
|
189
|
-
);
|
|
190
|
-
resolve();
|
|
191
|
-
}
|
|
192
|
-
});
|
|
193
|
-
});
|
|
178
|
+
logger.break();
|
|
179
|
+
logger.success("MCP server installed for Claude Code!");
|
|
180
|
+
logger.info(
|
|
181
|
+
"The server starts automatically. Try asking about assistant-ui!",
|
|
182
|
+
);
|
|
183
|
+
return;
|
|
194
184
|
}
|
|
195
185
|
|
|
196
186
|
if (target === "claude-desktop" && process.platform === "linux") {
|
|
@@ -288,7 +278,8 @@ export const mcp = new Command()
|
|
|
288
278
|
for (const target of targets) {
|
|
289
279
|
try {
|
|
290
280
|
await installForTarget(target);
|
|
291
|
-
} catch {
|
|
281
|
+
} catch (error) {
|
|
282
|
+
if (error instanceof SpawnSignalError) throw error;
|
|
292
283
|
process.exit(1);
|
|
293
284
|
}
|
|
294
285
|
}
|
package/src/commands/update.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { Command } from "commander";
|
|
2
2
|
import fs from "node:fs";
|
|
3
3
|
import path from "node:path";
|
|
4
|
-
import { sync as spawnSync } from "cross-spawn";
|
|
5
4
|
import { logger } from "../lib/utils/logger";
|
|
6
5
|
import { logPackageJsonParseError } from "../lib/utils/package-json";
|
|
7
6
|
import { getInstallCommand } from "../lib/utils/package-manager";
|
|
7
|
+
import { runSpawn, SpawnExitError, SpawnSignalError } from "../lib/run-spawn";
|
|
8
8
|
|
|
9
9
|
export const update = new Command()
|
|
10
10
|
.name("update")
|
|
@@ -73,14 +73,12 @@ export const update = new Command()
|
|
|
73
73
|
}
|
|
74
74
|
|
|
75
75
|
logger.step("Updating packages...");
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
if (result.status !== 0) {
|
|
76
|
+
try {
|
|
77
|
+
await runSpawn(installCmd.command, installCmd.args, opts.cwd);
|
|
78
|
+
} catch (error) {
|
|
79
|
+
if (error instanceof SpawnSignalError) throw error;
|
|
82
80
|
logger.error("Package manager update failed.");
|
|
83
|
-
process.exit(
|
|
81
|
+
process.exit(error instanceof SpawnExitError ? error.code : 1);
|
|
84
82
|
}
|
|
85
83
|
|
|
86
84
|
logger.break();
|
package/src/commands/upgrade.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Command } from "commander";
|
|
2
2
|
import { transform } from "../lib/transform";
|
|
3
3
|
import { upgrade } from "../lib/upgrade";
|
|
4
|
+
import { SpawnSignalError } from "../lib/run-spawn";
|
|
4
5
|
import debug from "debug";
|
|
5
6
|
|
|
6
7
|
export interface TransformOptions {
|
|
@@ -30,10 +31,11 @@ export const codemodCommand = addTransformOptions(
|
|
|
30
31
|
.description("CLI tool for running codemods")
|
|
31
32
|
.argument("<codemod>", "Codemod to run (e.g., rewrite-framework-imports)")
|
|
32
33
|
.argument("<source>", "Path to source files or directory to transform"),
|
|
33
|
-
).action((codemod, source, options: TransformOptions) => {
|
|
34
|
+
).action(async (codemod, source, options: TransformOptions) => {
|
|
34
35
|
try {
|
|
35
|
-
transform(codemod, source, options);
|
|
36
|
+
await transform(codemod, source, options);
|
|
36
37
|
} catch (err) {
|
|
38
|
+
if (err instanceof SpawnSignalError) throw err;
|
|
37
39
|
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
38
40
|
const errorStack = err instanceof Error ? err.stack : undefined;
|
|
39
41
|
error(`Error transforming: ${errorMessage}`);
|
|
@@ -52,6 +54,7 @@ export const upgradeCommand = addTransformOptions(
|
|
|
52
54
|
try {
|
|
53
55
|
await upgrade(options);
|
|
54
56
|
} catch (err) {
|
|
57
|
+
if (err instanceof SpawnSignalError) throw err;
|
|
55
58
|
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
56
59
|
const errorStack = err instanceof Error ? err.stack : undefined;
|
|
57
60
|
error(`Error upgrading: ${errorMessage}`);
|
package/src/index.ts
CHANGED
|
@@ -1,11 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
+
import { handleCliError } from "./lib/handle-cli-error";
|
|
3
4
|
import { runCli } from "./run";
|
|
4
5
|
|
|
5
|
-
|
|
6
|
-
process.on("SIGTERM", () => process.exit(0));
|
|
7
|
-
|
|
8
|
-
void runCli().catch((error: unknown) => {
|
|
9
|
-
console.error(error);
|
|
10
|
-
process.exitCode = 1;
|
|
11
|
-
});
|
|
6
|
+
void runCli().catch(handleCliError);
|
package/src/lib/agent-skill.ts
CHANGED
|
@@ -1,17 +1,15 @@
|
|
|
1
1
|
import * as fs from "node:fs";
|
|
2
2
|
import * as path from "node:path";
|
|
3
3
|
import { downloadTemplate } from "giget";
|
|
4
|
-
import { sync as globSync } from "glob";
|
|
5
|
-
import { detect } from "detect-package-manager";
|
|
6
4
|
import {
|
|
7
5
|
parse as parseJsonc,
|
|
8
6
|
printParseErrorCode,
|
|
9
7
|
type ParseError,
|
|
10
8
|
} from "jsonc-parser";
|
|
11
9
|
import { logger } from "./utils/logger";
|
|
12
|
-
import { runSpawn, SpawnExitError } from "./run-spawn";
|
|
13
|
-
|
|
14
|
-
|
|
10
|
+
import { runSpawn, SpawnExitError, SpawnSignalError } from "./run-spawn";
|
|
11
|
+
import { type PackageManagerName } from "./utils/package-manager";
|
|
12
|
+
import { readProjectFiles } from "./utils/file-scanner";
|
|
15
13
|
|
|
16
14
|
export function dlxCommand(pm: PackageManagerName): [string, string[]] {
|
|
17
15
|
switch (pm) {
|
|
@@ -186,30 +184,6 @@ export async function scaffoldProject(
|
|
|
186
184
|
}
|
|
187
185
|
}
|
|
188
186
|
|
|
189
|
-
function detectFromUserAgent(): PackageManagerName | undefined {
|
|
190
|
-
const ua = process.env.npm_config_user_agent;
|
|
191
|
-
if (!ua) return undefined;
|
|
192
|
-
if (ua.startsWith("bun/")) return "bun";
|
|
193
|
-
if (ua.startsWith("pnpm/")) return "pnpm";
|
|
194
|
-
if (ua.startsWith("yarn/")) return "yarn";
|
|
195
|
-
if (ua.startsWith("npm/")) return "npm";
|
|
196
|
-
return undefined;
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
export async function resolvePackageManagerForCwd(
|
|
200
|
-
cwd: string,
|
|
201
|
-
packageManager?: PackageManagerName,
|
|
202
|
-
): Promise<PackageManagerName> {
|
|
203
|
-
if (packageManager) return packageManager;
|
|
204
|
-
const fromAgent = detectFromUserAgent();
|
|
205
|
-
if (fromAgent) return fromAgent;
|
|
206
|
-
try {
|
|
207
|
-
return await detect({ cwd });
|
|
208
|
-
} catch {
|
|
209
|
-
return "npm";
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
|
|
213
187
|
export interface TransformResult {
|
|
214
188
|
registryInstallFailure?: { retryCommand: string };
|
|
215
189
|
}
|
|
@@ -383,16 +357,11 @@ function transformTsConfig(projectDir: string): void {
|
|
|
383
357
|
}
|
|
384
358
|
|
|
385
359
|
function transformCssFiles(projectDir: string): void {
|
|
386
|
-
const
|
|
360
|
+
for (const { fullPath, content } of readProjectFiles("**/*.css", {
|
|
387
361
|
cwd: projectDir,
|
|
388
362
|
ignore: LOCAL_PROJECT_ARTIFACT_GLOB_IGNORES,
|
|
389
|
-
})
|
|
390
|
-
|
|
391
|
-
for (const file of cssFiles) {
|
|
392
|
-
const fullPath = path.join(projectDir, file);
|
|
363
|
+
})) {
|
|
393
364
|
try {
|
|
394
|
-
const content = fs.readFileSync(fullPath, "utf-8");
|
|
395
|
-
|
|
396
365
|
const newContent = content.replace(
|
|
397
366
|
/@source\s+["'][^"']*packages\/ui\/src[^"']*["'];\s*\n?/g,
|
|
398
367
|
"",
|
|
@@ -402,7 +371,7 @@ function transformCssFiles(projectDir: string): void {
|
|
|
402
371
|
fs.writeFileSync(fullPath, newContent);
|
|
403
372
|
}
|
|
404
373
|
} catch {
|
|
405
|
-
|
|
374
|
+
continue;
|
|
406
375
|
}
|
|
407
376
|
}
|
|
408
377
|
}
|
|
@@ -417,31 +386,22 @@ function stripImportExtension(component: string): string {
|
|
|
417
386
|
}
|
|
418
387
|
|
|
419
388
|
function scanRequiredComponents(projectDir: string): RequiredComponents {
|
|
420
|
-
const files = globSync("**/*.{ts,tsx}", {
|
|
421
|
-
cwd: projectDir,
|
|
422
|
-
ignore: LOCAL_PROJECT_ARTIFACT_GLOB_IGNORES,
|
|
423
|
-
});
|
|
424
|
-
|
|
425
389
|
const assistantUIComponents = new Set<string>();
|
|
426
390
|
const shadcnUIComponents = new Set<string>();
|
|
427
391
|
|
|
428
|
-
for (const
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
}
|
|
392
|
+
for (const { content } of readProjectFiles("**/*.{ts,tsx}", {
|
|
393
|
+
cwd: projectDir,
|
|
394
|
+
ignore: LOCAL_PROJECT_ARTIFACT_GLOB_IGNORES,
|
|
395
|
+
})) {
|
|
396
|
+
const assistantUIRegex =
|
|
397
|
+
/from\s+["']@\/components\/assistant-ui\/([^"']+)["']/g;
|
|
398
|
+
for (const match of content.matchAll(assistantUIRegex)) {
|
|
399
|
+
assistantUIComponents.add(stripImportExtension(match[1]!));
|
|
400
|
+
}
|
|
438
401
|
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
}
|
|
443
|
-
} catch {
|
|
444
|
-
// Ignore files that cannot be read
|
|
402
|
+
const uiRegex = /from\s+["']@\/components\/ui\/([^"']+)["']/g;
|
|
403
|
+
for (const match of content.matchAll(uiRegex)) {
|
|
404
|
+
shadcnUIComponents.add(stripImportExtension(match[1]!));
|
|
445
405
|
}
|
|
446
406
|
}
|
|
447
407
|
|
|
@@ -459,6 +419,9 @@ async function installDependencies(
|
|
|
459
419
|
try {
|
|
460
420
|
await runSpawn(pm, args, projectDir);
|
|
461
421
|
} catch (error) {
|
|
422
|
+
if (error instanceof SpawnSignalError) {
|
|
423
|
+
throw error;
|
|
424
|
+
}
|
|
462
425
|
if (error instanceof SpawnExitError) {
|
|
463
426
|
throw new Error(`${pm} install exited with code ${error.code}`);
|
|
464
427
|
}
|
|
@@ -483,6 +446,9 @@ async function installShadcnRegistry(
|
|
|
483
446
|
await runSpawn(cmd, addArgs, projectDir);
|
|
484
447
|
return undefined;
|
|
485
448
|
} catch (error) {
|
|
449
|
+
if (error instanceof SpawnSignalError) {
|
|
450
|
+
throw error;
|
|
451
|
+
}
|
|
486
452
|
if (error instanceof SpawnExitError) {
|
|
487
453
|
logger.warn(`shadcn exited with code ${error.code}.`);
|
|
488
454
|
return { retryCommand: `${cmd} ${retryArgs.join(" ")}` };
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
2
|
+
|
|
3
|
+
import { handleCliError } from "./handle-cli-error";
|
|
4
|
+
import { SpawnExitError, SpawnSignalError } from "./run-spawn";
|
|
5
|
+
|
|
6
|
+
describe("handleCliError", () => {
|
|
7
|
+
afterEach(() => {
|
|
8
|
+
vi.restoreAllMocks();
|
|
9
|
+
process.exitCode = undefined;
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
it("exits by the forwarded signal's status and re-raises it", () => {
|
|
13
|
+
const kill = vi.spyOn(process, "kill").mockReturnValue(true);
|
|
14
|
+
|
|
15
|
+
handleCliError(new SpawnSignalError("SIGINT", true));
|
|
16
|
+
|
|
17
|
+
expect(process.exitCode).toBe(130);
|
|
18
|
+
expect(kill).toHaveBeenCalledWith(process.pid, "SIGINT");
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it("maps SIGTERM to 143", () => {
|
|
22
|
+
const kill = vi.spyOn(process, "kill").mockReturnValue(true);
|
|
23
|
+
|
|
24
|
+
handleCliError(new SpawnSignalError("SIGTERM", true));
|
|
25
|
+
|
|
26
|
+
expect(process.exitCode).toBe(143);
|
|
27
|
+
expect(kill).toHaveBeenCalledWith(process.pid, "SIGTERM");
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it("reports a signal the child raised on itself without re-raising it", () => {
|
|
31
|
+
const consoleError = vi
|
|
32
|
+
.spyOn(console, "error")
|
|
33
|
+
.mockImplementation(() => {});
|
|
34
|
+
const kill = vi.spyOn(process, "kill").mockReturnValue(true);
|
|
35
|
+
|
|
36
|
+
handleCliError(new SpawnSignalError("SIGKILL", false));
|
|
37
|
+
|
|
38
|
+
expect(process.exitCode).toBe(137);
|
|
39
|
+
expect(kill).not.toHaveBeenCalled();
|
|
40
|
+
expect(consoleError).toHaveBeenCalledWith("Process terminated by SIGKILL");
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it("stays silent on a signal the user sent", () => {
|
|
44
|
+
const consoleError = vi
|
|
45
|
+
.spyOn(console, "error")
|
|
46
|
+
.mockImplementation(() => {});
|
|
47
|
+
vi.spyOn(process, "kill").mockReturnValue(true);
|
|
48
|
+
|
|
49
|
+
handleCliError(new SpawnSignalError("SIGINT", true));
|
|
50
|
+
|
|
51
|
+
expect(consoleError).not.toHaveBeenCalled();
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it("reports any other failure as exit 1", () => {
|
|
55
|
+
const consoleError = vi
|
|
56
|
+
.spyOn(console, "error")
|
|
57
|
+
.mockImplementation(() => {});
|
|
58
|
+
const kill = vi.spyOn(process, "kill").mockReturnValue(true);
|
|
59
|
+
const error = new SpawnExitError(7);
|
|
60
|
+
|
|
61
|
+
handleCliError(error);
|
|
62
|
+
|
|
63
|
+
expect(process.exitCode).toBe(1);
|
|
64
|
+
expect(kill).not.toHaveBeenCalled();
|
|
65
|
+
expect(consoleError).toHaveBeenCalledWith(error);
|
|
66
|
+
});
|
|
67
|
+
});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { constants } from "node:os";
|
|
2
|
+
import { SpawnSignalError } from "./run-spawn";
|
|
3
|
+
|
|
4
|
+
export function handleCliError(error: unknown): void {
|
|
5
|
+
if (error instanceof SpawnSignalError) {
|
|
6
|
+
process.exitCode = 128 + (constants.signals[error.signal] ?? 0);
|
|
7
|
+
if (error.forwarded) {
|
|
8
|
+
process.kill(process.pid, error.signal);
|
|
9
|
+
} else {
|
|
10
|
+
console.error(error.message);
|
|
11
|
+
}
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
console.error(error);
|
|
16
|
+
process.exitCode = 1;
|
|
17
|
+
}
|
|
@@ -1,6 +1,18 @@
|
|
|
1
1
|
import { installPackageIfNeeded } from "./utils/package-installer";
|
|
2
2
|
|
|
3
3
|
export default async function installAiSdkLib(): Promise<void> {
|
|
4
|
+
await installPackageIfNeeded({
|
|
5
|
+
packageName: "@assistant-ui/ai-sdk",
|
|
6
|
+
importPatterns: ["@assistant-ui/ai-sdk"],
|
|
7
|
+
promptMessage:
|
|
8
|
+
"AI SDK imports were added but @assistant-ui/ai-sdk is not installed. Do you want to install it? (Y/n) ",
|
|
9
|
+
skipMessage:
|
|
10
|
+
"@assistant-ui/ai-sdk is already installed. Skipping installation.",
|
|
11
|
+
notFoundMessage: "No AI SDK imports found; skipping installation.",
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
// The previous name is a separate package, so an import of it needs that
|
|
15
|
+
// package installed; the neutral one would not make it resolvable.
|
|
4
16
|
await installPackageIfNeeded({
|
|
5
17
|
packageName: "@assistant-ui/react-ai-sdk",
|
|
6
18
|
importPatterns: ["@assistant-ui/react-ai-sdk"],
|
|
@@ -8,6 +20,6 @@ export default async function installAiSdkLib(): Promise<void> {
|
|
|
8
20
|
"AI SDK imports were added but @assistant-ui/react-ai-sdk is not installed. Do you want to install it? (Y/n) ",
|
|
9
21
|
skipMessage:
|
|
10
22
|
"@assistant-ui/react-ai-sdk is already installed. Skipping installation.",
|
|
11
|
-
notFoundMessage: "No AI SDK imports found; skipping installation.",
|
|
23
|
+
notFoundMessage: "No legacy AI SDK imports found; skipping installation.",
|
|
12
24
|
});
|
|
13
25
|
}
|
|
@@ -1,17 +1,16 @@
|
|
|
1
1
|
import { installPackageIfNeeded } from "./utils/package-installer";
|
|
2
2
|
|
|
3
3
|
export default async function installEdgeLib(): Promise<void> {
|
|
4
|
+
// Only the retired edge specifier is unambiguous here. `useChatRuntime` and
|
|
5
|
+
// the AI SDK package specifiers are shared by both AI SDK packages, so
|
|
6
|
+
// installAiSdkLib resolves those by the specifier the file actually imports.
|
|
4
7
|
await installPackageIfNeeded({
|
|
5
|
-
packageName: "@assistant-ui/
|
|
6
|
-
importPatterns: [
|
|
7
|
-
"@assistant-ui/react-edge",
|
|
8
|
-
"@assistant-ui/react-ai-sdk",
|
|
9
|
-
"useChatRuntime",
|
|
10
|
-
],
|
|
8
|
+
packageName: "@assistant-ui/ai-sdk",
|
|
9
|
+
importPatterns: ["@assistant-ui/react-edge"],
|
|
11
10
|
promptMessage:
|
|
12
|
-
"Edge Runtime imports were detected but @assistant-ui/
|
|
11
|
+
"Edge Runtime imports were detected but @assistant-ui/ai-sdk is not installed. Do you want to install it? (Y/n) ",
|
|
13
12
|
skipMessage:
|
|
14
|
-
"@assistant-ui/
|
|
13
|
+
"@assistant-ui/ai-sdk is already installed. Skipping installation.",
|
|
15
14
|
notFoundMessage: "No Edge Runtime imports found; skipping installation.",
|
|
16
15
|
});
|
|
17
16
|
}
|