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.
Files changed (90) hide show
  1. package/dist/codemods/v0-12/assistant-api-to-aui.d.ts.map +1 -1
  2. package/dist/codemods/v0-12/assistant-api-to-aui.js +87 -62
  3. package/dist/codemods/v0-12/assistant-api-to-aui.js.map +1 -1
  4. package/dist/codemods/v0-12/primitive-if-to-aui-if.d.ts.map +1 -1
  5. package/dist/codemods/v0-12/primitive-if-to-aui-if.js +31 -45
  6. package/dist/codemods/v0-12/primitive-if-to-aui-if.js.map +1 -1
  7. package/dist/commands/add.d.ts +1 -1
  8. package/dist/commands/add.d.ts.map +1 -1
  9. package/dist/commands/add.js +4 -2
  10. package/dist/commands/add.js.map +1 -1
  11. package/dist/commands/create.d.ts.map +1 -1
  12. package/dist/commands/create.js +33 -10
  13. package/dist/commands/create.js.map +1 -1
  14. package/dist/commands/info.d.ts.map +1 -1
  15. package/dist/commands/info.js +2 -1
  16. package/dist/commands/info.js.map +1 -1
  17. package/dist/commands/init.d.ts.map +1 -1
  18. package/dist/commands/init.js +4 -2
  19. package/dist/commands/init.js.map +1 -1
  20. package/dist/commands/mcp.d.ts.map +1 -1
  21. package/dist/commands/mcp.js +25 -28
  22. package/dist/commands/mcp.js.map +1 -1
  23. package/dist/commands/update.js +6 -7
  24. package/dist/commands/update.js.map +1 -1
  25. package/dist/commands/upgrade.d.ts.map +1 -1
  26. package/dist/commands/upgrade.js +5 -2
  27. package/dist/commands/upgrade.js.map +1 -1
  28. package/dist/index.js +2 -6
  29. package/dist/index.js.map +1 -1
  30. package/dist/lib/agent-skill.d.ts +1 -1
  31. package/dist/lib/agent-skill.d.ts.map +1 -1
  32. package/dist/lib/agent-skill.js.map +1 -1
  33. package/dist/lib/create-project.d.ts +2 -3
  34. package/dist/lib/create-project.d.ts.map +1 -1
  35. package/dist/lib/create-project.js +17 -42
  36. package/dist/lib/create-project.js.map +1 -1
  37. package/dist/lib/handle-cli-error.d.ts +5 -0
  38. package/dist/lib/handle-cli-error.d.ts.map +1 -0
  39. package/dist/lib/handle-cli-error.js +17 -0
  40. package/dist/lib/handle-cli-error.js.map +1 -0
  41. package/dist/lib/install-ai-sdk-lib.js +8 -1
  42. package/dist/lib/install-ai-sdk-lib.js.map +1 -1
  43. package/dist/lib/install-edge-lib.js +4 -8
  44. package/dist/lib/install-edge-lib.js.map +1 -1
  45. package/dist/lib/run-spawn.d.ts +16 -2
  46. package/dist/lib/run-spawn.d.ts.map +1 -1
  47. package/dist/lib/run-spawn.js +87 -9
  48. package/dist/lib/run-spawn.js.map +1 -1
  49. package/dist/lib/transform.d.ts +1 -1
  50. package/dist/lib/transform.d.ts.map +1 -1
  51. package/dist/lib/transform.js +12 -25
  52. package/dist/lib/transform.js.map +1 -1
  53. package/dist/lib/upgrade.js +20 -16
  54. package/dist/lib/upgrade.js.map +1 -1
  55. package/dist/lib/utils/file-scanner.d.ts +9 -1
  56. package/dist/lib/utils/file-scanner.d.ts.map +1 -1
  57. package/dist/lib/utils/file-scanner.js +22 -20
  58. package/dist/lib/utils/file-scanner.js.map +1 -1
  59. package/dist/lib/utils/package-installer.js +1 -1
  60. package/dist/lib/utils/package-manager.d.ts +3 -1
  61. package/dist/lib/utils/package-manager.d.ts.map +1 -1
  62. package/dist/lib/utils/package-manager.js +22 -10
  63. package/dist/lib/utils/package-manager.js.map +1 -1
  64. package/package.json +6 -6
  65. package/plugin/skills/assistant-ui/SKILL.md +3 -3
  66. package/src/codemods/v0-12/__tests__/assistant-api-to-aui.test.ts +370 -0
  67. package/src/codemods/v0-12/__tests__/primitive-if-to-aui-if.test.ts +100 -0
  68. package/src/codemods/v0-12/assistant-api-to-aui.ts +227 -134
  69. package/src/codemods/v0-12/primitive-if-to-aui-if.ts +44 -72
  70. package/src/commands/add.ts +5 -5
  71. package/src/commands/create.ts +41 -7
  72. package/src/commands/info.ts +1 -0
  73. package/src/commands/init.ts +4 -6
  74. package/src/commands/mcp.ts +20 -29
  75. package/src/commands/update.ts +6 -8
  76. package/src/commands/upgrade.ts +5 -2
  77. package/src/index.ts +2 -7
  78. package/src/lib/agent-skill.ts +2 -1
  79. package/src/lib/create-project.ts +24 -58
  80. package/src/lib/handle-cli-error.test.ts +67 -0
  81. package/src/lib/handle-cli-error.ts +17 -0
  82. package/src/lib/install-ai-sdk-lib.ts +13 -1
  83. package/src/lib/install-edge-lib.ts +7 -8
  84. package/src/lib/run-spawn.test.ts +148 -0
  85. package/src/lib/run-spawn.ts +121 -11
  86. package/src/lib/transform.test.ts +62 -0
  87. package/src/lib/transform.ts +21 -37
  88. package/src/lib/upgrade.ts +23 -19
  89. package/src/lib/utils/file-scanner.ts +26 -20
  90. package/src/lib/utils/package-manager.ts +29 -12
@@ -2,25 +2,103 @@ import { spawn } from "cross-spawn";
2
2
  //#region src/lib/run-spawn.ts
3
3
  var SpawnExitError = class extends Error {
4
4
  code;
5
- constructor(code) {
6
- super(`Process exited with code ${code}`);
5
+ stderr;
6
+ constructor(code, stderr = "") {
7
+ super(stderr ? `Process exited with code ${code}\n${stderr}` : `Process exited with code ${code}`);
7
8
  this.code = code;
9
+ this.stderr = stderr;
8
10
  }
9
11
  };
10
- function runSpawn(command, args, cwd) {
12
+ var SpawnSignalError = class extends Error {
13
+ signal;
14
+ forwarded;
15
+ constructor(signal, forwarded) {
16
+ super(`Process terminated by ${signal}`);
17
+ this.signal = signal;
18
+ this.forwarded = forwarded;
19
+ }
20
+ };
21
+ let activeSpawns = 0;
22
+ const hasActiveSpawn = () => activeSpawns > 0;
23
+ function spawnProcess(command, args, cwd, captureOutput) {
11
24
  return new Promise((resolve, reject) => {
12
25
  const child = spawn(command, args, {
13
- stdio: "inherit",
26
+ stdio: captureOutput ? [
27
+ "ignore",
28
+ "pipe",
29
+ "pipe"
30
+ ] : "inherit",
14
31
  cwd
15
32
  });
16
- child.on("error", (error) => reject(error));
17
- child.on("close", (code) => {
18
- if (code !== 0) reject(new SpawnExitError(code || 1));
19
- else resolve();
33
+ let forwardedSignal = null;
34
+ let settled = false;
35
+ let stdout = "";
36
+ let stderr = "";
37
+ if (captureOutput) {
38
+ child.stdout?.setEncoding("utf8");
39
+ child.stdout?.on("data", (chunk) => {
40
+ stdout += chunk;
41
+ });
42
+ child.stderr?.setEncoding("utf8");
43
+ child.stderr?.on("data", (chunk) => {
44
+ stderr += chunk;
45
+ });
46
+ }
47
+ const cleanup = () => {
48
+ activeSpawns -= 1;
49
+ process.off("SIGINT", onSigint);
50
+ process.off("SIGTERM", onSigterm);
51
+ };
52
+ const rejectWithSignal = (signal) => {
53
+ settled = true;
54
+ cleanup();
55
+ reject(new SpawnSignalError(signal, forwardedSignal !== null));
56
+ };
57
+ const forwardSignal = (signal) => {
58
+ if (forwardedSignal !== null) {
59
+ child.kill("SIGKILL");
60
+ rejectWithSignal(forwardedSignal);
61
+ return;
62
+ }
63
+ forwardedSignal = signal;
64
+ child.kill(signal);
65
+ };
66
+ const onSigint = () => forwardSignal("SIGINT");
67
+ const onSigterm = () => forwardSignal("SIGTERM");
68
+ activeSpawns += 1;
69
+ process.on("SIGINT", onSigint);
70
+ process.on("SIGTERM", onSigterm);
71
+ child.on("error", (error) => {
72
+ if (settled) return;
73
+ settled = true;
74
+ cleanup();
75
+ if (forwardedSignal !== null) reject(new SpawnSignalError(forwardedSignal, true));
76
+ else reject(error);
77
+ });
78
+ child.on("close", (code, signal) => {
79
+ if (settled) return;
80
+ settled = true;
81
+ cleanup();
82
+ if (forwardedSignal !== null) reject(new SpawnSignalError(forwardedSignal, true));
83
+ else resolve({
84
+ code,
85
+ signal: signal ?? null,
86
+ stdout,
87
+ stderr
88
+ });
20
89
  });
21
90
  });
22
91
  }
92
+ function runSpawn(command, args, cwd) {
93
+ return spawnProcess(command, args, cwd, false).then(({ code, signal }) => {
94
+ if (signal != null) throw new SpawnSignalError(signal, false);
95
+ if (code !== 0) throw new SpawnExitError(code || 1);
96
+ });
97
+ }
98
+ function runSpawnCapture(command, args, cwd) {
99
+ return spawnProcess(command, args, cwd, true);
100
+ }
23
101
  //#endregion
24
- export { SpawnExitError, runSpawn };
102
+ export { SpawnExitError, SpawnSignalError, hasActiveSpawn, runSpawn, runSpawnCapture };
25
103
 
26
104
  //# sourceMappingURL=run-spawn.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"run-spawn.js","names":[],"sources":["../../src/lib/run-spawn.ts"],"sourcesContent":["import { spawn } from \"cross-spawn\";\n\nexport class SpawnExitError extends Error {\n code: number;\n\n constructor(code: number) {\n super(`Process exited with code ${code}`);\n this.code = code;\n }\n}\n\nexport function runSpawn(\n command: string,\n args: string[],\n cwd?: string,\n): Promise<void> {\n return new Promise((resolve, reject) => {\n const child = spawn(command, args, {\n stdio: \"inherit\",\n cwd,\n });\n\n child.on(\"error\", (error) => reject(error));\n child.on(\"close\", (code) => {\n if (code !== 0) {\n reject(new SpawnExitError(code || 1));\n } else {\n resolve();\n }\n });\n });\n}\n"],"mappings":";;AAEA,IAAa,iBAAb,cAAoC,MAAM;CACxC;CAEA,YAAY,MAAc;EACxB,MAAM,4BAA4B,MAAM;EACxC,KAAK,OAAO;CACd;AACF;AAEA,SAAgB,SACd,SACA,MACA,KACe;CACf,OAAO,IAAI,SAAS,SAAS,WAAW;EACtC,MAAM,QAAQ,MAAM,SAAS,MAAM;GACjC,OAAO;GACP;EACF,CAAC;EAED,MAAM,GAAG,UAAU,UAAU,OAAO,KAAK,CAAC;EAC1C,MAAM,GAAG,UAAU,SAAS;GAC1B,IAAI,SAAS,GACX,OAAO,IAAI,eAAe,QAAQ,CAAC,CAAC;QAEpC,QAAQ;EAEZ,CAAC;CACH,CAAC;AACH"}
1
+ {"version":3,"file":"run-spawn.js","names":[],"sources":["../../src/lib/run-spawn.ts"],"sourcesContent":["import { spawn } from \"cross-spawn\";\n\nexport class SpawnExitError extends Error {\n code: number;\n stderr: string;\n\n constructor(code: number, stderr = \"\") {\n super(\n stderr\n ? `Process exited with code ${code}\\n${stderr}`\n : `Process exited with code ${code}`,\n );\n this.code = code;\n this.stderr = stderr;\n }\n}\n\nexport class SpawnSignalError extends Error {\n signal: NodeJS.Signals;\n forwarded: boolean;\n\n constructor(signal: NodeJS.Signals, forwarded: boolean) {\n super(`Process terminated by ${signal}`);\n this.signal = signal;\n this.forwarded = forwarded;\n }\n}\n\nexport interface SpawnResult {\n code: number | null;\n signal: NodeJS.Signals | null;\n stdout: string;\n stderr: string;\n}\n\nlet activeSpawns = 0;\n\n// A spawn that is forwarding a signal owns termination for that window, so\n// callers with their own cleanup listeners defer to it instead of racing it.\nexport const hasActiveSpawn = (): boolean => activeSpawns > 0;\n\nfunction spawnProcess(\n command: string,\n args: string[],\n cwd: string | undefined,\n captureOutput: boolean,\n): Promise<SpawnResult> {\n return new Promise((resolve, reject) => {\n const child = spawn(command, args, {\n stdio: captureOutput ? [\"ignore\", \"pipe\", \"pipe\"] : \"inherit\",\n cwd,\n });\n let forwardedSignal: NodeJS.Signals | null = null;\n let settled = false;\n let stdout = \"\";\n let stderr = \"\";\n\n if (captureOutput) {\n child.stdout?.setEncoding(\"utf8\");\n child.stdout?.on(\"data\", (chunk: string) => {\n stdout += chunk;\n });\n child.stderr?.setEncoding(\"utf8\");\n child.stderr?.on(\"data\", (chunk: string) => {\n stderr += chunk;\n });\n }\n\n const cleanup = () => {\n activeSpawns -= 1;\n process.off(\"SIGINT\", onSigint);\n process.off(\"SIGTERM\", onSigterm);\n };\n\n const rejectWithSignal = (signal: NodeJS.Signals) => {\n settled = true;\n cleanup();\n reject(new SpawnSignalError(signal, forwardedSignal !== null));\n };\n\n const forwardSignal = (signal: NodeJS.Signals) => {\n if (forwardedSignal !== null) {\n child.kill(\"SIGKILL\");\n rejectWithSignal(forwardedSignal);\n return;\n }\n\n forwardedSignal = signal;\n child.kill(signal);\n };\n const onSigint = () => forwardSignal(\"SIGINT\");\n const onSigterm = () => forwardSignal(\"SIGTERM\");\n\n activeSpawns += 1;\n process.on(\"SIGINT\", onSigint);\n process.on(\"SIGTERM\", onSigterm);\n\n child.on(\"error\", (error) => {\n if (settled) return;\n settled = true;\n cleanup();\n if (forwardedSignal !== null) {\n reject(new SpawnSignalError(forwardedSignal, true));\n } else {\n reject(error);\n }\n });\n child.on(\"close\", (code, signal) => {\n if (settled) return;\n settled = true;\n cleanup();\n if (forwardedSignal !== null) {\n reject(new SpawnSignalError(forwardedSignal, true));\n } else {\n resolve({ code, signal: signal ?? null, stdout, stderr });\n }\n });\n });\n}\n\nexport function runSpawn(\n command: string,\n args: string[],\n cwd?: string,\n): Promise<void> {\n return spawnProcess(command, args, cwd, false).then(({ code, signal }) => {\n if (signal != null) {\n throw new SpawnSignalError(signal, false);\n }\n if (code !== 0) {\n throw new SpawnExitError(code || 1);\n }\n });\n}\n\nexport function runSpawnCapture(\n command: string,\n args: string[],\n cwd?: string,\n): Promise<SpawnResult> {\n return spawnProcess(command, args, cwd, true);\n}\n"],"mappings":";;AAEA,IAAa,iBAAb,cAAoC,MAAM;CACxC;CACA;CAEA,YAAY,MAAc,SAAS,IAAI;EACrC,MACE,SACI,4BAA4B,KAAK,IAAI,WACrC,4BAA4B,MAClC;EACA,KAAK,OAAO;EACZ,KAAK,SAAS;CAChB;AACF;AAEA,IAAa,mBAAb,cAAsC,MAAM;CAC1C;CACA;CAEA,YAAY,QAAwB,WAAoB;EACtD,MAAM,yBAAyB,QAAQ;EACvC,KAAK,SAAS;EACd,KAAK,YAAY;CACnB;AACF;AASA,IAAI,eAAe;AAInB,MAAa,uBAAgC,eAAe;AAE5D,SAAS,aACP,SACA,MACA,KACA,eACsB;CACtB,OAAO,IAAI,SAAS,SAAS,WAAW;EACtC,MAAM,QAAQ,MAAM,SAAS,MAAM;GACjC,OAAO,gBAAgB;IAAC;IAAU;IAAQ;GAAM,IAAI;GACpD;EACF,CAAC;EACD,IAAI,kBAAyC;EAC7C,IAAI,UAAU;EACd,IAAI,SAAS;EACb,IAAI,SAAS;EAEb,IAAI,eAAe;GACjB,MAAM,QAAQ,YAAY,MAAM;GAChC,MAAM,QAAQ,GAAG,SAAS,UAAkB;IAC1C,UAAU;GACZ,CAAC;GACD,MAAM,QAAQ,YAAY,MAAM;GAChC,MAAM,QAAQ,GAAG,SAAS,UAAkB;IAC1C,UAAU;GACZ,CAAC;EACH;EAEA,MAAM,gBAAgB;GACpB,gBAAgB;GAChB,QAAQ,IAAI,UAAU,QAAQ;GAC9B,QAAQ,IAAI,WAAW,SAAS;EAClC;EAEA,MAAM,oBAAoB,WAA2B;GACnD,UAAU;GACV,QAAQ;GACR,OAAO,IAAI,iBAAiB,QAAQ,oBAAoB,IAAI,CAAC;EAC/D;EAEA,MAAM,iBAAiB,WAA2B;GAChD,IAAI,oBAAoB,MAAM;IAC5B,MAAM,KAAK,SAAS;IACpB,iBAAiB,eAAe;IAChC;GACF;GAEA,kBAAkB;GAClB,MAAM,KAAK,MAAM;EACnB;EACA,MAAM,iBAAiB,cAAc,QAAQ;EAC7C,MAAM,kBAAkB,cAAc,SAAS;EAE/C,gBAAgB;EAChB,QAAQ,GAAG,UAAU,QAAQ;EAC7B,QAAQ,GAAG,WAAW,SAAS;EAE/B,MAAM,GAAG,UAAU,UAAU;GAC3B,IAAI,SAAS;GACb,UAAU;GACV,QAAQ;GACR,IAAI,oBAAoB,MACtB,OAAO,IAAI,iBAAiB,iBAAiB,IAAI,CAAC;QAElD,OAAO,KAAK;EAEhB,CAAC;EACD,MAAM,GAAG,UAAU,MAAM,WAAW;GAClC,IAAI,SAAS;GACb,UAAU;GACV,QAAQ;GACR,IAAI,oBAAoB,MACtB,OAAO,IAAI,iBAAiB,iBAAiB,IAAI,CAAC;QAElD,QAAQ;IAAE;IAAM,QAAQ,UAAU;IAAM;IAAQ;GAAO,CAAC;EAE5D,CAAC;CACH,CAAC;AACH;AAEA,SAAgB,SACd,SACA,MACA,KACe;CACf,OAAO,aAAa,SAAS,MAAM,KAAK,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,aAAa;EACxE,IAAI,UAAU,MACZ,MAAM,IAAI,iBAAiB,QAAQ,KAAK;EAE1C,IAAI,SAAS,GACX,MAAM,IAAI,eAAe,QAAQ,CAAC;CAEtC,CAAC;AACH;AAEA,SAAgB,gBACd,SACA,MACA,KACsB;CACtB,OAAO,aAAa,SAAS,MAAM,KAAK,IAAI;AAC9C"}
@@ -18,7 +18,7 @@ declare function transform(codemod: string, source: string, transformOptions: Tr
18
18
  logStatus: boolean;
19
19
  onProgress?: (processedFiles: number) => void;
20
20
  relevantFiles?: string[];
21
- }): TransformErrors;
21
+ }): Promise<TransformErrors>;
22
22
  //#endregion
23
23
  export { TransformErrors, countFilesToProcess, getRelevantFiles, transform };
24
24
  //# sourceMappingURL=transform.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"transform.d.ts","names":[],"sources":["../../src/lib/transform.ts"],"mappings":";;;;;;iBAkBgB,iBAAiB;;;;iBA6BjB,oBAAoB;KAsCxB;EACV;EACA;EACA;;iBAoBc,UACd,iBACA,gBACA,kBAAkB,kBAClB;EACE;EACA,cAAc;EACd;IAED"}
1
+ {"version":3,"file":"transform.d.ts","names":[],"sources":["../../src/lib/transform.ts"],"mappings":";;;;;;iBAkBgB,iBAAiB;;;;iBA6BjB,oBAAoB;KAsCxB;EACV;EACA;EACA;;iBAoBoB,UACpB,iBACA,gBACA,kBAAkB,kBAClB;EACE;EACA,cAAc;EACd;IAED,QAAQ"}
@@ -1,7 +1,7 @@
1
+ import { SpawnExitError, SpawnSignalError, runSpawnCapture } from "./run-spawn.js";
1
2
  import * as fs$1 from "node:fs";
2
3
  import path from "node:path";
3
4
  import { sync } from "glob";
4
- import { execFileSync, spawnSync } from "node:child_process";
5
5
  import debug from "debug";
6
6
  import { fileURLToPath } from "node:url";
7
7
  //#region src/lib/transform.ts
@@ -71,7 +71,7 @@ function parseErrors(transform, output) {
71
71
  }
72
72
  return errors;
73
73
  }
74
- function transform(codemod, source, transformOptions, options = { logStatus: true }) {
74
+ async function transform(codemod, source, transformOptions, options = { logStatus: true }) {
75
75
  if (options.logStatus) log(`Applying codemod '${codemod}': ${source}`);
76
76
  const codemodPath = path.resolve(__dirname, `../codemods/${codemod}.js`);
77
77
  const targetFiles = options.relevantFiles || getRelevantFiles(source);
@@ -81,32 +81,19 @@ function transform(codemod, source, transformOptions, options = { logStatus: tru
81
81
  }
82
82
  log(`Found ${targetFiles.length} relevant files for codemod '${codemod}'`);
83
83
  const command = buildCommand(codemodPath, targetFiles, transformOptions);
84
+ const result = await runSpawnCapture(command[0], command.slice(1));
85
+ if (result.signal !== null) throw new SpawnSignalError(result.signal, false);
86
+ if (!options.onProgress && result.code !== 0) throw new SpawnExitError(result.code || 1, result.stderr);
87
+ const { stdout } = result;
84
88
  if (options.onProgress) {
85
- const stdout = spawnSync(command[0], command.slice(1), {
86
- encoding: "utf8",
87
- stdio: [
88
- "ignore",
89
- "pipe",
90
- "pipe"
91
- ]
92
- }).stdout || "";
93
89
  const processedFiles = (stdout.match(/Processing file/g) || []).length;
94
- if (options.onProgress) options.onProgress(processedFiles);
95
- const errors = parseErrors(codemod, stdout);
96
- if (options.logStatus && errors.length > 0) errors.forEach(({ transform, filename, summary }) => {
97
- error(`Error applying codemod [codemod=${transform}, path=${filename}, summary=${summary}]`);
98
- });
99
- return errors;
100
- } else {
101
- const errors = parseErrors(codemod, execFileSync(command[0], command.slice(1), {
102
- encoding: "utf8",
103
- stdio: "pipe"
104
- }));
105
- if (options.logStatus && errors.length > 0) errors.forEach(({ transform, filename, summary }) => {
106
- error(`Error applying codemod [codemod=${transform}, path=${filename}, summary=${summary}]`);
107
- });
108
- return errors;
90
+ options.onProgress(processedFiles);
109
91
  }
92
+ const errors = parseErrors(codemod, stdout);
93
+ if (options.logStatus && errors.length > 0) errors.forEach(({ transform, filename, summary }) => {
94
+ error(`Error applying codemod [codemod=${transform}, path=${filename}, summary=${summary}]`);
95
+ });
96
+ return errors;
110
97
  }
111
98
  //#endregion
112
99
  export { countFilesToProcess, getRelevantFiles, transform };
@@ -1 +1 @@
1
- {"version":3,"file":"transform.js","names":["globSync","fs"],"sources":["../../src/lib/transform.ts"],"sourcesContent":["import { execFileSync, spawnSync } from \"node:child_process\";\nimport debug from \"debug\";\nimport path from \"node:path\";\nimport type { TransformOptions } from \"./transform-options\";\nimport { fileURLToPath } from \"node:url\";\nimport * as fs from \"node:fs\";\nimport { sync as globSync } from \"glob\";\n\nconst log = debug(\"codemod:transform\");\nconst error = debug(\"codemod:transform:error\");\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = path.dirname(__filename);\n\n/**\n * Gets the list of files that need to be processed in the codebase\n * Only includes files that contain \"assistant-ui\" to optimize performance\n */\nexport function getRelevantFiles(cwd: string): string[] {\n const pattern = \"**/*.{js,jsx,ts,tsx}\";\n const files = globSync(pattern, {\n cwd,\n ignore: [\n \"**/node_modules/**\",\n \"**/dist/**\",\n \"**/build/**\",\n \"**/*.min.js\",\n \"**/*.bundle.js\",\n ],\n });\n\n // Filter files to only include those containing \"assistant-ui\"\n const relevantFiles = files.filter((file) => {\n try {\n const content = fs.readFileSync(path.join(cwd, file), \"utf8\");\n return content.includes(\"assistant-ui\");\n } catch {\n return false;\n }\n });\n\n return relevantFiles.map((file) => path.join(cwd, file));\n}\n\n/**\n * Counts the number of files that need to be processed\n */\nexport function countFilesToProcess(cwd: string): number {\n return getRelevantFiles(cwd).length;\n}\n\nfunction buildCommand(\n codemodPath: string,\n targetFiles: string[],\n options: TransformOptions,\n): string[] {\n const command = [\n \"npx\",\n \"jscodeshift\",\n \"-t\",\n codemodPath,\n ...targetFiles,\n \"--parser\",\n \"tsx\",\n ];\n\n if (options.dry) {\n command.push(\"--dry\");\n }\n\n if (options.print) {\n command.push(\"--print\");\n }\n\n if (options.verbose) {\n command.push(\"--verbose\");\n }\n\n if (options.jscodeshift) {\n command.push(options.jscodeshift);\n }\n\n return command;\n}\n\nexport type TransformErrors = {\n transform: string;\n filename: string;\n summary: string;\n}[];\n\nfunction parseErrors(transform: string, output: string): TransformErrors {\n const errors: TransformErrors = [];\n const errorRegex = /ERR (.+) Transformation error/g;\n const syntaxErrorRegex = /SyntaxError: .+/g;\n\n for (const match of output.matchAll(errorRegex)) {\n const filename = match[1]!;\n const syntaxErrorMatch = syntaxErrorRegex.exec(output);\n if (syntaxErrorMatch) {\n const summary = syntaxErrorMatch[0];\n errors.push({ transform, filename, summary });\n }\n }\n\n return errors;\n}\n\nexport function transform(\n codemod: string,\n source: string,\n transformOptions: TransformOptions,\n options: {\n logStatus: boolean;\n onProgress?: (processedFiles: number) => void;\n relevantFiles?: string[];\n } = { logStatus: true },\n): TransformErrors {\n if (options.logStatus) {\n log(`Applying codemod '${codemod}': ${source}`);\n }\n const codemodPath = path.resolve(__dirname, `../codemods/${codemod}.js`);\n\n // Use pre-computed relevant files if provided, otherwise get them\n const targetFiles = options.relevantFiles || getRelevantFiles(source);\n\n if (targetFiles.length === 0) {\n log(`No relevant files found for codemod '${codemod}'`);\n return [];\n }\n\n log(`Found ${targetFiles.length} relevant files for codemod '${codemod}'`);\n\n const command = buildCommand(codemodPath, targetFiles, transformOptions);\n\n // Use spawn instead of execFileSync to capture output in real-time\n if (options.onProgress) {\n const result = spawnSync(command[0]!, command.slice(1), {\n encoding: \"utf8\",\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n });\n\n const stdout = result.stdout || \"\";\n\n // Count the number of processed files from the output\n const processedFiles = (stdout.match(/Processing file/g) || []).length;\n if (options.onProgress) {\n options.onProgress(processedFiles);\n }\n\n const errors = parseErrors(codemod, stdout);\n if (options.logStatus && errors.length > 0) {\n errors.forEach(({ transform, filename, summary }) => {\n error(\n `Error applying codemod [codemod=${transform}, path=${filename}, summary=${summary}]`,\n );\n });\n }\n return errors;\n } else {\n // Use the original synchronous approach if no progress callback\n const stdout = execFileSync(command[0]!, command.slice(1), {\n encoding: \"utf8\",\n stdio: \"pipe\",\n });\n const errors = parseErrors(codemod, stdout);\n if (options.logStatus && errors.length > 0) {\n errors.forEach(({ transform, filename, summary }) => {\n error(\n `Error applying codemod [codemod=${transform}, path=${filename}, summary=${summary}]`,\n );\n });\n }\n return errors;\n }\n}\n"],"mappings":";;;;;;;AAQA,MAAM,MAAM,MAAM,mBAAmB;AACrC,MAAM,QAAQ,MAAM,yBAAyB;AAE7C,MAAM,aAAa,cAAc,YAAY,GAAG;AAChD,MAAM,YAAY,KAAK,QAAQ,UAAU;;;;;AAMzC,SAAgB,iBAAiB,KAAuB;CAuBtD,OArBcA,KAAS,wBAAS;EAC9B;EACA,QAAQ;GACN;GACA;GACA;GACA;GACA;EACF;CACF,CAG0B,CAAC,CAAC,QAAQ,SAAS;EAC3C,IAAI;GAEF,OADgBC,KAAG,aAAa,KAAK,KAAK,KAAK,IAAI,GAAG,MACzC,CAAC,CAAC,SAAS,cAAc;EACxC,QAAQ;GACN,OAAO;EACT;CACF,CAEmB,CAAC,CAAC,KAAK,SAAS,KAAK,KAAK,KAAK,IAAI,CAAC;AACzD;;;;AAKA,SAAgB,oBAAoB,KAAqB;CACvD,OAAO,iBAAiB,GAAG,CAAC,CAAC;AAC/B;AAEA,SAAS,aACP,aACA,aACA,SACU;CACV,MAAM,UAAU;EACd;EACA;EACA;EACA;EACA,GAAG;EACH;EACA;CACF;CAEA,IAAI,QAAQ,KACV,QAAQ,KAAK,OAAO;CAGtB,IAAI,QAAQ,OACV,QAAQ,KAAK,SAAS;CAGxB,IAAI,QAAQ,SACV,QAAQ,KAAK,WAAW;CAG1B,IAAI,QAAQ,aACV,QAAQ,KAAK,QAAQ,WAAW;CAGlC,OAAO;AACT;AAQA,SAAS,YAAY,WAAmB,QAAiC;CACvE,MAAM,SAA0B,CAAC;CACjC,MAAM,aAAa;CACnB,MAAM,mBAAmB;CAEzB,KAAK,MAAM,SAAS,OAAO,SAAS,UAAU,GAAG;EAC/C,MAAM,WAAW,MAAM;EACvB,MAAM,mBAAmB,iBAAiB,KAAK,MAAM;EACrD,IAAI,kBAAkB;GACpB,MAAM,UAAU,iBAAiB;GACjC,OAAO,KAAK;IAAE;IAAW;IAAU;GAAQ,CAAC;EAC9C;CACF;CAEA,OAAO;AACT;AAEA,SAAgB,UACd,SACA,QACA,kBACA,UAII,EAAE,WAAW,KAAK,GACL;CACjB,IAAI,QAAQ,WACV,IAAI,qBAAqB,QAAQ,KAAK,QAAQ;CAEhD,MAAM,cAAc,KAAK,QAAQ,WAAW,eAAe,QAAQ,IAAI;CAGvE,MAAM,cAAc,QAAQ,iBAAiB,iBAAiB,MAAM;CAEpE,IAAI,YAAY,WAAW,GAAG;EAC5B,IAAI,wCAAwC,QAAQ,EAAE;EACtD,OAAO,CAAC;CACV;CAEA,IAAI,SAAS,YAAY,OAAO,+BAA+B,QAAQ,EAAE;CAEzE,MAAM,UAAU,aAAa,aAAa,aAAa,gBAAgB;CAGvE,IAAI,QAAQ,YAAY;EAMtB,MAAM,SALS,UAAU,QAAQ,IAAK,QAAQ,MAAM,CAAC,GAAG;GACtD,UAAU;GACV,OAAO;IAAC;IAAU;IAAQ;GAAM;EAClC,CAEoB,CAAC,CAAC,UAAU;EAGhC,MAAM,kBAAkB,OAAO,MAAM,kBAAkB,KAAK,CAAC,EAAA,CAAG;EAChE,IAAI,QAAQ,YACV,QAAQ,WAAW,cAAc;EAGnC,MAAM,SAAS,YAAY,SAAS,MAAM;EAC1C,IAAI,QAAQ,aAAa,OAAO,SAAS,GACvC,OAAO,SAAS,EAAE,WAAW,UAAU,cAAc;GACnD,MACE,mCAAmC,UAAU,SAAS,SAAS,YAAY,QAAQ,EACrF;EACF,CAAC;EAEH,OAAO;CACT,OAAO;EAML,MAAM,SAAS,YAAY,SAJZ,aAAa,QAAQ,IAAK,QAAQ,MAAM,CAAC,GAAG;GACzD,UAAU;GACV,OAAO;EACT,CACyC,CAAC;EAC1C,IAAI,QAAQ,aAAa,OAAO,SAAS,GACvC,OAAO,SAAS,EAAE,WAAW,UAAU,cAAc;GACnD,MACE,mCAAmC,UAAU,SAAS,SAAS,YAAY,QAAQ,EACrF;EACF,CAAC;EAEH,OAAO;CACT;AACF"}
1
+ {"version":3,"file":"transform.js","names":["globSync","fs"],"sources":["../../src/lib/transform.ts"],"sourcesContent":["import debug from \"debug\";\nimport path from \"node:path\";\nimport type { TransformOptions } from \"./transform-options\";\nimport { fileURLToPath } from \"node:url\";\nimport * as fs from \"node:fs\";\nimport { sync as globSync } from \"glob\";\nimport { runSpawnCapture, SpawnExitError, SpawnSignalError } from \"./run-spawn\";\n\nconst log = debug(\"codemod:transform\");\nconst error = debug(\"codemod:transform:error\");\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = path.dirname(__filename);\n\n/**\n * Gets the list of files that need to be processed in the codebase\n * Only includes files that contain \"assistant-ui\" to optimize performance\n */\nexport function getRelevantFiles(cwd: string): string[] {\n const pattern = \"**/*.{js,jsx,ts,tsx}\";\n const files = globSync(pattern, {\n cwd,\n ignore: [\n \"**/node_modules/**\",\n \"**/dist/**\",\n \"**/build/**\",\n \"**/*.min.js\",\n \"**/*.bundle.js\",\n ],\n });\n\n // Filter files to only include those containing \"assistant-ui\"\n const relevantFiles = files.filter((file) => {\n try {\n const content = fs.readFileSync(path.join(cwd, file), \"utf8\");\n return content.includes(\"assistant-ui\");\n } catch {\n return false;\n }\n });\n\n return relevantFiles.map((file) => path.join(cwd, file));\n}\n\n/**\n * Counts the number of files that need to be processed\n */\nexport function countFilesToProcess(cwd: string): number {\n return getRelevantFiles(cwd).length;\n}\n\nfunction buildCommand(\n codemodPath: string,\n targetFiles: string[],\n options: TransformOptions,\n): string[] {\n const command = [\n \"npx\",\n \"jscodeshift\",\n \"-t\",\n codemodPath,\n ...targetFiles,\n \"--parser\",\n \"tsx\",\n ];\n\n if (options.dry) {\n command.push(\"--dry\");\n }\n\n if (options.print) {\n command.push(\"--print\");\n }\n\n if (options.verbose) {\n command.push(\"--verbose\");\n }\n\n if (options.jscodeshift) {\n command.push(options.jscodeshift);\n }\n\n return command;\n}\n\nexport type TransformErrors = {\n transform: string;\n filename: string;\n summary: string;\n}[];\n\nfunction parseErrors(transform: string, output: string): TransformErrors {\n const errors: TransformErrors = [];\n const errorRegex = /ERR (.+) Transformation error/g;\n const syntaxErrorRegex = /SyntaxError: .+/g;\n\n for (const match of output.matchAll(errorRegex)) {\n const filename = match[1]!;\n const syntaxErrorMatch = syntaxErrorRegex.exec(output);\n if (syntaxErrorMatch) {\n const summary = syntaxErrorMatch[0];\n errors.push({ transform, filename, summary });\n }\n }\n\n return errors;\n}\n\nexport async function transform(\n codemod: string,\n source: string,\n transformOptions: TransformOptions,\n options: {\n logStatus: boolean;\n onProgress?: (processedFiles: number) => void;\n relevantFiles?: string[];\n } = { logStatus: true },\n): Promise<TransformErrors> {\n if (options.logStatus) {\n log(`Applying codemod '${codemod}': ${source}`);\n }\n const codemodPath = path.resolve(__dirname, `../codemods/${codemod}.js`);\n\n // Use pre-computed relevant files if provided, otherwise get them\n const targetFiles = options.relevantFiles || getRelevantFiles(source);\n\n if (targetFiles.length === 0) {\n log(`No relevant files found for codemod '${codemod}'`);\n return [];\n }\n\n log(`Found ${targetFiles.length} relevant files for codemod '${codemod}'`);\n\n const command = buildCommand(codemodPath, targetFiles, transformOptions);\n\n const result = await runSpawnCapture(command[0]!, command.slice(1));\n if (result.signal !== null) {\n throw new SpawnSignalError(result.signal, false);\n }\n if (!options.onProgress && result.code !== 0) {\n throw new SpawnExitError(result.code || 1, result.stderr);\n }\n\n const { stdout } = result;\n\n if (options.onProgress) {\n const processedFiles = (stdout.match(/Processing file/g) || []).length;\n options.onProgress(processedFiles);\n }\n\n const errors = parseErrors(codemod, stdout);\n if (options.logStatus && errors.length > 0) {\n errors.forEach(({ transform, filename, summary }) => {\n error(\n `Error applying codemod [codemod=${transform}, path=${filename}, summary=${summary}]`,\n );\n });\n }\n return errors;\n}\n"],"mappings":";;;;;;;AAQA,MAAM,MAAM,MAAM,mBAAmB;AACrC,MAAM,QAAQ,MAAM,yBAAyB;AAE7C,MAAM,aAAa,cAAc,YAAY,GAAG;AAChD,MAAM,YAAY,KAAK,QAAQ,UAAU;;;;;AAMzC,SAAgB,iBAAiB,KAAuB;CAuBtD,OArBcA,KAAS,wBAAS;EAC9B;EACA,QAAQ;GACN;GACA;GACA;GACA;GACA;EACF;CACF,CAG0B,CAAC,CAAC,QAAQ,SAAS;EAC3C,IAAI;GAEF,OADgBC,KAAG,aAAa,KAAK,KAAK,KAAK,IAAI,GAAG,MACzC,CAAC,CAAC,SAAS,cAAc;EACxC,QAAQ;GACN,OAAO;EACT;CACF,CAEmB,CAAC,CAAC,KAAK,SAAS,KAAK,KAAK,KAAK,IAAI,CAAC;AACzD;;;;AAKA,SAAgB,oBAAoB,KAAqB;CACvD,OAAO,iBAAiB,GAAG,CAAC,CAAC;AAC/B;AAEA,SAAS,aACP,aACA,aACA,SACU;CACV,MAAM,UAAU;EACd;EACA;EACA;EACA;EACA,GAAG;EACH;EACA;CACF;CAEA,IAAI,QAAQ,KACV,QAAQ,KAAK,OAAO;CAGtB,IAAI,QAAQ,OACV,QAAQ,KAAK,SAAS;CAGxB,IAAI,QAAQ,SACV,QAAQ,KAAK,WAAW;CAG1B,IAAI,QAAQ,aACV,QAAQ,KAAK,QAAQ,WAAW;CAGlC,OAAO;AACT;AAQA,SAAS,YAAY,WAAmB,QAAiC;CACvE,MAAM,SAA0B,CAAC;CACjC,MAAM,aAAa;CACnB,MAAM,mBAAmB;CAEzB,KAAK,MAAM,SAAS,OAAO,SAAS,UAAU,GAAG;EAC/C,MAAM,WAAW,MAAM;EACvB,MAAM,mBAAmB,iBAAiB,KAAK,MAAM;EACrD,IAAI,kBAAkB;GACpB,MAAM,UAAU,iBAAiB;GACjC,OAAO,KAAK;IAAE;IAAW;IAAU;GAAQ,CAAC;EAC9C;CACF;CAEA,OAAO;AACT;AAEA,eAAsB,UACpB,SACA,QACA,kBACA,UAII,EAAE,WAAW,KAAK,GACI;CAC1B,IAAI,QAAQ,WACV,IAAI,qBAAqB,QAAQ,KAAK,QAAQ;CAEhD,MAAM,cAAc,KAAK,QAAQ,WAAW,eAAe,QAAQ,IAAI;CAGvE,MAAM,cAAc,QAAQ,iBAAiB,iBAAiB,MAAM;CAEpE,IAAI,YAAY,WAAW,GAAG;EAC5B,IAAI,wCAAwC,QAAQ,EAAE;EACtD,OAAO,CAAC;CACV;CAEA,IAAI,SAAS,YAAY,OAAO,+BAA+B,QAAQ,EAAE;CAEzE,MAAM,UAAU,aAAa,aAAa,aAAa,gBAAgB;CAEvE,MAAM,SAAS,MAAM,gBAAgB,QAAQ,IAAK,QAAQ,MAAM,CAAC,CAAC;CAClE,IAAI,OAAO,WAAW,MACpB,MAAM,IAAI,iBAAiB,OAAO,QAAQ,KAAK;CAEjD,IAAI,CAAC,QAAQ,cAAc,OAAO,SAAS,GACzC,MAAM,IAAI,eAAe,OAAO,QAAQ,GAAG,OAAO,MAAM;CAG1D,MAAM,EAAE,WAAW;CAEnB,IAAI,QAAQ,YAAY;EACtB,MAAM,kBAAkB,OAAO,MAAM,kBAAkB,KAAK,CAAC,EAAA,CAAG;EAChE,QAAQ,WAAW,cAAc;CACnC;CAEA,MAAM,SAAS,YAAY,SAAS,MAAM;CAC1C,IAAI,QAAQ,aAAa,OAAO,SAAS,GACvC,OAAO,SAAS,EAAE,WAAW,UAAU,cAAc;EACnD,MACE,mCAAmC,UAAU,SAAS,SAAS,YAAY,QAAQ,EACrF;CACF,CAAC;CAEH,OAAO;AACT"}
@@ -32,26 +32,30 @@ async function upgrade(options) {
32
32
  let completedWork = 0;
33
33
  const bar = new SingleBar({
34
34
  format: "Progress |{bar}| {percentage}% | ETA: {eta}s || {status}",
35
- hideCursor: true
35
+ hideCursor: true,
36
+ gracefulExit: true
36
37
  }, Presets.shades_classic);
37
38
  bar.start(totalWork, 0, { status: "Starting..." });
38
39
  const allErrors = [];
39
- for (const codemod of bundle) {
40
- bar.update(completedWork, { status: `Running ${codemod}...` });
41
- const errors = transform(codemod, cwd, options, {
42
- logStatus: false,
43
- onProgress: (processedFiles) => {
44
- completedWork = bundle.indexOf(codemod) * fileCount + processedFiles;
45
- bar.update(Math.min(completedWork, totalWork), { status: `Running ${codemod} (${processedFiles}/${fileCount} files)` });
46
- },
47
- relevantFiles
48
- });
49
- allErrors.push(...errors);
50
- completedWork = (bundle.indexOf(codemod) + 1) * fileCount;
51
- bar.update(completedWork, { status: `Completed ${codemod}` });
40
+ try {
41
+ for (const codemod of bundle) {
42
+ bar.update(completedWork, { status: `Running ${codemod}...` });
43
+ const errors = await transform(codemod, cwd, options, {
44
+ logStatus: false,
45
+ onProgress: (processedFiles) => {
46
+ completedWork = bundle.indexOf(codemod) * fileCount + processedFiles;
47
+ bar.update(Math.min(completedWork, totalWork), { status: `Running ${codemod} (${processedFiles}/${fileCount} files)` });
48
+ },
49
+ relevantFiles
50
+ });
51
+ allErrors.push(...errors);
52
+ completedWork = (bundle.indexOf(codemod) + 1) * fileCount;
53
+ bar.update(completedWork, { status: `Completed ${codemod}` });
54
+ }
55
+ bar.update(totalWork, { status: "Checking dependencies..." });
56
+ } finally {
57
+ bar.stop();
52
58
  }
53
- bar.update(totalWork, { status: "Checking dependencies..." });
54
- bar.stop();
55
59
  if (allErrors.length > 0) {
56
60
  log("Some codemods did not apply successfully to all files. Details:");
57
61
  allErrors.forEach(({ transform, filename, summary }) => {
@@ -1 +1 @@
1
- {"version":3,"file":"upgrade.js","names":[],"sources":["../../src/lib/upgrade.ts"],"sourcesContent":["import debug from \"debug\";\nimport { transform, type TransformErrors, getRelevantFiles } from \"./transform\";\nimport type { TransformOptions } from \"./transform-options\";\nimport { SingleBar, Presets } from \"cli-progress\";\nimport installEdgeLib from \"./install-edge-lib\";\nimport installAiSdkLib from \"./install-ai-sdk-lib\";\nimport { logger } from \"./utils/logger\";\n\nconst bundle = [\n \"v0-9/edge-package-split\",\n \"v0-11/content-part-to-message-part\",\n \"v0-12/assistant-api-to-aui\",\n \"v0-12/event-names-to-camelcase\",\n \"v0-12/primitive-if-to-aui-if\",\n \"v0-15/aui-accessor-calls-to-properties\",\n];\n\nconst log = debug(\"codemod:upgrade\");\nconst error = debug(\"codemod:upgrade:error\");\n\n/**\n * Runs the upgrade cycle:\n * - Runs each codemod in the bundle.\n * - Displays progress using cli-progress.\n * - After codemods run, checks if any file now imports from the new packages and prompts for install.\n */\nexport async function upgrade(options: TransformOptions) {\n const cwd = process.cwd();\n log(\"Starting upgrade...\");\n\n // Find relevant files once to avoid duplicate work\n logger.info(\"Analyzing codebase...\");\n const relevantFiles = getRelevantFiles(cwd);\n const fileCount = relevantFiles.length;\n logger.info(`Found ${fileCount} files to process.`);\n\n // Calculate total work units (files × codemods)\n const totalWork = fileCount * bundle.length;\n let completedWork = 0;\n\n const bar = new SingleBar(\n {\n format: \"Progress |{bar}| {percentage}% | ETA: {eta}s || {status}\",\n hideCursor: true,\n },\n Presets.shades_classic,\n );\n\n bar.start(totalWork, 0, { status: \"Starting...\" });\n const allErrors: TransformErrors = [];\n\n for (const codemod of bundle) {\n bar.update(completedWork, { status: `Running ${codemod}...` });\n\n // Use a custom progress callback to update the progress bar\n const errors = transform(codemod, cwd, options, {\n logStatus: false,\n onProgress: (processedFiles: number) => {\n completedWork = bundle.indexOf(codemod) * fileCount + processedFiles;\n bar.update(Math.min(completedWork, totalWork), {\n status: `Running ${codemod} (${processedFiles}/${fileCount} files)`,\n });\n },\n relevantFiles, // Pass the pre-computed relevant files\n });\n\n allErrors.push(...errors);\n completedWork = (bundle.indexOf(codemod) + 1) * fileCount;\n bar.update(completedWork, { status: `Completed ${codemod}` });\n }\n\n bar.update(totalWork, { status: \"Checking dependencies...\" });\n bar.stop();\n\n if (allErrors.length > 0) {\n log(\"Some codemods did not apply successfully to all files. Details:\");\n allErrors.forEach(({ transform, filename, summary }) => {\n error(`codemod=${transform}, path=${filename}, summary=${summary}`);\n });\n }\n\n // After codemods run, check if files import from the new packages and prompt for install.\n logger.info(\"Checking for package dependencies...\");\n await installEdgeLib();\n await installAiSdkLib();\n\n log(\"Upgrade complete.\");\n logger.success(\"Upgrade complete!\");\n}\n"],"mappings":";;;;;;;AAQA,MAAM,SAAS;CACb;CACA;CACA;CACA;CACA;CACA;AACF;AAEA,MAAM,MAAM,MAAM,iBAAiB;AACnC,MAAM,QAAQ,MAAM,uBAAuB;;;;;;;AAQ3C,eAAsB,QAAQ,SAA2B;CACvD,MAAM,MAAM,QAAQ,IAAI;CACxB,IAAI,qBAAqB;CAGzB,OAAO,KAAK,uBAAuB;CACnC,MAAM,gBAAgB,iBAAiB,GAAG;CAC1C,MAAM,YAAY,cAAc;CAChC,OAAO,KAAK,SAAS,UAAU,mBAAmB;CAGlD,MAAM,YAAY,YAAY,OAAO;CACrC,IAAI,gBAAgB;CAEpB,MAAM,MAAM,IAAI,UACd;EACE,QAAQ;EACR,YAAY;CACd,GACA,QAAQ,cACV;CAEA,IAAI,MAAM,WAAW,GAAG,EAAE,QAAQ,cAAc,CAAC;CACjD,MAAM,YAA6B,CAAC;CAEpC,KAAK,MAAM,WAAW,QAAQ;EAC5B,IAAI,OAAO,eAAe,EAAE,QAAQ,WAAW,QAAQ,KAAK,CAAC;EAG7D,MAAM,SAAS,UAAU,SAAS,KAAK,SAAS;GAC9C,WAAW;GACX,aAAa,mBAA2B;IACtC,gBAAgB,OAAO,QAAQ,OAAO,IAAI,YAAY;IACtD,IAAI,OAAO,KAAK,IAAI,eAAe,SAAS,GAAG,EAC7C,QAAQ,WAAW,QAAQ,IAAI,eAAe,GAAG,UAAU,SAC7D,CAAC;GACH;GACA;EACF,CAAC;EAED,UAAU,KAAK,GAAG,MAAM;EACxB,iBAAiB,OAAO,QAAQ,OAAO,IAAI,KAAK;EAChD,IAAI,OAAO,eAAe,EAAE,QAAQ,aAAa,UAAU,CAAC;CAC9D;CAEA,IAAI,OAAO,WAAW,EAAE,QAAQ,2BAA2B,CAAC;CAC5D,IAAI,KAAK;CAET,IAAI,UAAU,SAAS,GAAG;EACxB,IAAI,iEAAiE;EACrE,UAAU,SAAS,EAAE,WAAW,UAAU,cAAc;GACtD,MAAM,WAAW,UAAU,SAAS,SAAS,YAAY,SAAS;EACpE,CAAC;CACH;CAGA,OAAO,KAAK,sCAAsC;CAClD,MAAM,eAAe;CACrB,MAAM,gBAAgB;CAEtB,IAAI,mBAAmB;CACvB,OAAO,QAAQ,mBAAmB;AACpC"}
1
+ {"version":3,"file":"upgrade.js","names":[],"sources":["../../src/lib/upgrade.ts"],"sourcesContent":["import debug from \"debug\";\nimport { transform, type TransformErrors, getRelevantFiles } from \"./transform\";\nimport type { TransformOptions } from \"./transform-options\";\nimport { SingleBar, Presets } from \"cli-progress\";\nimport installEdgeLib from \"./install-edge-lib\";\nimport installAiSdkLib from \"./install-ai-sdk-lib\";\nimport { logger } from \"./utils/logger\";\n\nconst bundle = [\n \"v0-9/edge-package-split\",\n \"v0-11/content-part-to-message-part\",\n \"v0-12/assistant-api-to-aui\",\n \"v0-12/event-names-to-camelcase\",\n \"v0-12/primitive-if-to-aui-if\",\n \"v0-15/aui-accessor-calls-to-properties\",\n];\n\nconst log = debug(\"codemod:upgrade\");\nconst error = debug(\"codemod:upgrade:error\");\n\n/**\n * Runs the upgrade cycle:\n * - Runs each codemod in the bundle.\n * - Displays progress using cli-progress.\n * - After codemods run, checks if any file now imports from the new packages and prompts for install.\n */\nexport async function upgrade(options: TransformOptions) {\n const cwd = process.cwd();\n log(\"Starting upgrade...\");\n\n // Find relevant files once to avoid duplicate work\n logger.info(\"Analyzing codebase...\");\n const relevantFiles = getRelevantFiles(cwd);\n const fileCount = relevantFiles.length;\n logger.info(`Found ${fileCount} files to process.`);\n\n // Calculate total work units (files × codemods)\n const totalWork = fileCount * bundle.length;\n let completedWork = 0;\n\n const bar = new SingleBar(\n {\n format: \"Progress |{bar}| {percentage}% | ETA: {eta}s || {status}\",\n hideCursor: true,\n gracefulExit: true,\n },\n Presets.shades_classic,\n );\n\n bar.start(totalWork, 0, { status: \"Starting...\" });\n const allErrors: TransformErrors = [];\n\n try {\n for (const codemod of bundle) {\n bar.update(completedWork, { status: `Running ${codemod}...` });\n\n // Use a custom progress callback to update the progress bar\n const errors = await transform(codemod, cwd, options, {\n logStatus: false,\n onProgress: (processedFiles: number) => {\n completedWork = bundle.indexOf(codemod) * fileCount + processedFiles;\n bar.update(Math.min(completedWork, totalWork), {\n status: `Running ${codemod} (${processedFiles}/${fileCount} files)`,\n });\n },\n relevantFiles, // Pass the pre-computed relevant files\n });\n\n allErrors.push(...errors);\n completedWork = (bundle.indexOf(codemod) + 1) * fileCount;\n bar.update(completedWork, { status: `Completed ${codemod}` });\n }\n\n bar.update(totalWork, { status: \"Checking dependencies...\" });\n } finally {\n bar.stop();\n }\n\n if (allErrors.length > 0) {\n log(\"Some codemods did not apply successfully to all files. Details:\");\n allErrors.forEach(({ transform, filename, summary }) => {\n error(`codemod=${transform}, path=${filename}, summary=${summary}`);\n });\n }\n\n // After codemods run, check if files import from the new packages and prompt for install.\n logger.info(\"Checking for package dependencies...\");\n await installEdgeLib();\n await installAiSdkLib();\n\n log(\"Upgrade complete.\");\n logger.success(\"Upgrade complete!\");\n}\n"],"mappings":";;;;;;;AAQA,MAAM,SAAS;CACb;CACA;CACA;CACA;CACA;CACA;AACF;AAEA,MAAM,MAAM,MAAM,iBAAiB;AACnC,MAAM,QAAQ,MAAM,uBAAuB;;;;;;;AAQ3C,eAAsB,QAAQ,SAA2B;CACvD,MAAM,MAAM,QAAQ,IAAI;CACxB,IAAI,qBAAqB;CAGzB,OAAO,KAAK,uBAAuB;CACnC,MAAM,gBAAgB,iBAAiB,GAAG;CAC1C,MAAM,YAAY,cAAc;CAChC,OAAO,KAAK,SAAS,UAAU,mBAAmB;CAGlD,MAAM,YAAY,YAAY,OAAO;CACrC,IAAI,gBAAgB;CAEpB,MAAM,MAAM,IAAI,UACd;EACE,QAAQ;EACR,YAAY;EACZ,cAAc;CAChB,GACA,QAAQ,cACV;CAEA,IAAI,MAAM,WAAW,GAAG,EAAE,QAAQ,cAAc,CAAC;CACjD,MAAM,YAA6B,CAAC;CAEpC,IAAI;EACF,KAAK,MAAM,WAAW,QAAQ;GAC5B,IAAI,OAAO,eAAe,EAAE,QAAQ,WAAW,QAAQ,KAAK,CAAC;GAG7D,MAAM,SAAS,MAAM,UAAU,SAAS,KAAK,SAAS;IACpD,WAAW;IACX,aAAa,mBAA2B;KACtC,gBAAgB,OAAO,QAAQ,OAAO,IAAI,YAAY;KACtD,IAAI,OAAO,KAAK,IAAI,eAAe,SAAS,GAAG,EAC7C,QAAQ,WAAW,QAAQ,IAAI,eAAe,GAAG,UAAU,SAC7D,CAAC;IACH;IACA;GACF,CAAC;GAED,UAAU,KAAK,GAAG,MAAM;GACxB,iBAAiB,OAAO,QAAQ,OAAO,IAAI,KAAK;GAChD,IAAI,OAAO,eAAe,EAAE,QAAQ,aAAa,UAAU,CAAC;EAC9D;EAEA,IAAI,OAAO,WAAW,EAAE,QAAQ,2BAA2B,CAAC;CAC9D,UAAU;EACR,IAAI,KAAK;CACX;CAEA,IAAI,UAAU,SAAS,GAAG;EACxB,IAAI,iEAAiE;EACrE,UAAU,SAAS,EAAE,WAAW,UAAU,cAAc;GACtD,MAAM,WAAW,UAAU,SAAS,SAAS,YAAY,SAAS;EACpE,CAAC;CACH;CAGA,OAAO,KAAK,sCAAsC;CAClD,MAAM,eAAe;CACrB,MAAM,gBAAgB;CAEtB,IAAI,mBAAmB;CACvB,OAAO,QAAQ,mBAAmB;AACpC"}
@@ -4,8 +4,16 @@ interface ScanOptions {
4
4
  pattern?: string;
5
5
  ignore?: string[];
6
6
  }
7
+ declare function readProjectFiles(pattern: string, options: {
8
+ cwd: string;
9
+ ignore?: string[];
10
+ }): Generator<{
11
+ file: string;
12
+ fullPath: string;
13
+ content: string;
14
+ }>;
7
15
  declare function scanForImport(importPattern: string | string[], options?: ScanOptions): boolean;
8
16
  declare function getFilesContaining(searchString: string, options?: ScanOptions): string[];
9
17
  //#endregion
10
- export { ScanOptions, getFilesContaining, scanForImport };
18
+ export { ScanOptions, getFilesContaining, readProjectFiles, scanForImport };
11
19
  //# sourceMappingURL=file-scanner.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"file-scanner.d.ts","names":[],"sources":["../../../src/lib/utils/file-scanner.ts"],"mappings":";UAIiB;EACf;EACA;EACA;;iBAGc,cACd,kCACA,UAAS;iBA8BK,mBACd,sBACA,UAAS"}
1
+ {"version":3,"file":"file-scanner.d.ts","names":[],"sources":["../../../src/lib/utils/file-scanner.ts"],"mappings":";UAIiB;EACf;EACA;EACA;;iBAGe,iBACf,iBACA;EAAW;EAAa;IACvB;EAAY;EAAc;EAAkB;;iBAc/B,cACd,kCACA,UAAS;iBAuBK,mBACd,sBACA,UAAS"}
@@ -2,6 +2,21 @@ import * as fs$1 from "node:fs";
2
2
  import * as path$1 from "node:path";
3
3
  import { sync } from "glob";
4
4
  //#region src/lib/utils/file-scanner.ts
5
+ function* readProjectFiles(pattern, options) {
6
+ const files = sync(pattern, options);
7
+ for (const file of files) {
8
+ const fullPath = path$1.join(options.cwd, file);
9
+ try {
10
+ yield {
11
+ file,
12
+ fullPath,
13
+ content: fs$1.readFileSync(fullPath, "utf8")
14
+ };
15
+ } catch {
16
+ continue;
17
+ }
18
+ }
19
+ }
5
20
  function scanForImport(importPattern, options = {}) {
6
21
  const cwd = options.cwd || process.cwd();
7
22
  const pattern = options.pattern || "**/*.{js,jsx,ts,tsx}";
@@ -10,18 +25,11 @@ function scanForImport(importPattern, options = {}) {
10
25
  "**/dist/**",
11
26
  "**/build/**"
12
27
  ];
13
- const files = sync(pattern, {
28
+ const patterns = Array.isArray(importPattern) ? importPattern : [importPattern];
29
+ for (const { content } of readProjectFiles(pattern, {
14
30
  cwd,
15
31
  ignore
16
- });
17
- const patterns = Array.isArray(importPattern) ? importPattern : [importPattern];
18
- for (const file of files) {
19
- const fullPath = path$1.join(cwd, file);
20
- try {
21
- const content = fs$1.readFileSync(fullPath, "utf8");
22
- if (patterns.some((p) => content.includes(p))) return true;
23
- } catch {}
24
- }
32
+ })) if (patterns.some((p) => content.includes(p))) return true;
25
33
  return false;
26
34
  }
27
35
  function getFilesContaining(searchString, options = {}) {
@@ -32,20 +40,14 @@ function getFilesContaining(searchString, options = {}) {
32
40
  "**/dist/**",
33
41
  "**/build/**"
34
42
  ];
35
- const files = sync(pattern, {
43
+ const result = [];
44
+ for (const { fullPath, content } of readProjectFiles(pattern, {
36
45
  cwd,
37
46
  ignore
38
- });
39
- const result = [];
40
- for (const file of files) {
41
- const fullPath = path$1.join(cwd, file);
42
- try {
43
- if (fs$1.readFileSync(fullPath, "utf8").includes(searchString)) result.push(fullPath);
44
- } catch {}
45
- }
47
+ })) if (content.includes(searchString)) result.push(fullPath);
46
48
  return result;
47
49
  }
48
50
  //#endregion
49
- export { getFilesContaining, scanForImport };
51
+ export { getFilesContaining, readProjectFiles, scanForImport };
50
52
 
51
53
  //# sourceMappingURL=file-scanner.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"file-scanner.js","names":["globSync","path","fs"],"sources":["../../../src/lib/utils/file-scanner.ts"],"sourcesContent":["import * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport { sync as globSync } from \"glob\";\n\nexport interface ScanOptions {\n cwd?: string;\n pattern?: string;\n ignore?: string[];\n}\n\nexport function scanForImport(\n importPattern: string | string[],\n options: ScanOptions = {},\n): boolean {\n const cwd = options.cwd || process.cwd();\n const pattern = options.pattern || \"**/*.{js,jsx,ts,tsx}\";\n const ignore = options.ignore || [\n \"**/node_modules/**\",\n \"**/dist/**\",\n \"**/build/**\",\n ];\n\n const files = globSync(pattern, { cwd, ignore });\n const patterns = Array.isArray(importPattern)\n ? importPattern\n : [importPattern];\n\n for (const file of files) {\n const fullPath = path.join(cwd, file);\n try {\n const content = fs.readFileSync(fullPath, \"utf8\");\n if (patterns.some((p) => content.includes(p))) {\n return true;\n }\n } catch {\n // Ignore files that cannot be read\n }\n }\n\n return false;\n}\n\nexport function getFilesContaining(\n searchString: string,\n options: ScanOptions = {},\n): string[] {\n const cwd = options.cwd || process.cwd();\n const pattern = options.pattern || \"**/*.{js,jsx,ts,tsx}\";\n const ignore = options.ignore || [\n \"**/node_modules/**\",\n \"**/dist/**\",\n \"**/build/**\",\n ];\n\n const files = globSync(pattern, { cwd, ignore });\n const result: string[] = [];\n\n for (const file of files) {\n const fullPath = path.join(cwd, file);\n try {\n const content = fs.readFileSync(fullPath, \"utf8\");\n if (content.includes(searchString)) {\n result.push(fullPath);\n }\n } catch {\n // Ignore files that cannot be read\n }\n }\n\n return result;\n}\n"],"mappings":";;;;AAUA,SAAgB,cACd,eACA,UAAuB,CAAC,GACf;CACT,MAAM,MAAM,QAAQ,OAAO,QAAQ,IAAI;CACvC,MAAM,UAAU,QAAQ,WAAW;CACnC,MAAM,SAAS,QAAQ,UAAU;EAC/B;EACA;EACA;CACF;CAEA,MAAM,QAAQA,KAAS,SAAS;EAAE;EAAK;CAAO,CAAC;CAC/C,MAAM,WAAW,MAAM,QAAQ,aAAa,IACxC,gBACA,CAAC,aAAa;CAElB,KAAK,MAAM,QAAQ,OAAO;EACxB,MAAM,WAAWC,OAAK,KAAK,KAAK,IAAI;EACpC,IAAI;GACF,MAAM,UAAUC,KAAG,aAAa,UAAU,MAAM;GAChD,IAAI,SAAS,MAAM,MAAM,QAAQ,SAAS,CAAC,CAAC,GAC1C,OAAO;EAEX,QAAQ,CAER;CACF;CAEA,OAAO;AACT;AAEA,SAAgB,mBACd,cACA,UAAuB,CAAC,GACd;CACV,MAAM,MAAM,QAAQ,OAAO,QAAQ,IAAI;CACvC,MAAM,UAAU,QAAQ,WAAW;CACnC,MAAM,SAAS,QAAQ,UAAU;EAC/B;EACA;EACA;CACF;CAEA,MAAM,QAAQF,KAAS,SAAS;EAAE;EAAK;CAAO,CAAC;CAC/C,MAAM,SAAmB,CAAC;CAE1B,KAAK,MAAM,QAAQ,OAAO;EACxB,MAAM,WAAWC,OAAK,KAAK,KAAK,IAAI;EACpC,IAAI;GAEF,IADgBC,KAAG,aAAa,UAAU,MAChC,CAAC,CAAC,SAAS,YAAY,GAC/B,OAAO,KAAK,QAAQ;EAExB,QAAQ,CAER;CACF;CAEA,OAAO;AACT"}
1
+ {"version":3,"file":"file-scanner.js","names":["globSync","path","fs"],"sources":["../../../src/lib/utils/file-scanner.ts"],"sourcesContent":["import * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport { sync as globSync } from \"glob\";\n\nexport interface ScanOptions {\n cwd?: string;\n pattern?: string;\n ignore?: string[];\n}\n\nexport function* readProjectFiles(\n pattern: string,\n options: { cwd: string; ignore?: string[] },\n): Generator<{ file: string; fullPath: string; content: string }> {\n const files = globSync(pattern, options);\n\n for (const file of files) {\n const fullPath = path.join(options.cwd, file);\n try {\n const content = fs.readFileSync(fullPath, \"utf8\");\n yield { file, fullPath, content };\n } catch {\n continue;\n }\n }\n}\n\nexport function scanForImport(\n importPattern: string | string[],\n options: ScanOptions = {},\n): boolean {\n const cwd = options.cwd || process.cwd();\n const pattern = options.pattern || \"**/*.{js,jsx,ts,tsx}\";\n const ignore = options.ignore || [\n \"**/node_modules/**\",\n \"**/dist/**\",\n \"**/build/**\",\n ];\n\n const patterns = Array.isArray(importPattern)\n ? importPattern\n : [importPattern];\n\n for (const { content } of readProjectFiles(pattern, { cwd, ignore })) {\n if (patterns.some((p) => content.includes(p))) {\n return true;\n }\n }\n\n return false;\n}\n\nexport function getFilesContaining(\n searchString: string,\n options: ScanOptions = {},\n): string[] {\n const cwd = options.cwd || process.cwd();\n const pattern = options.pattern || \"**/*.{js,jsx,ts,tsx}\";\n const ignore = options.ignore || [\n \"**/node_modules/**\",\n \"**/dist/**\",\n \"**/build/**\",\n ];\n\n const result: string[] = [];\n\n for (const { fullPath, content } of readProjectFiles(pattern, {\n cwd,\n ignore,\n })) {\n if (content.includes(searchString)) {\n result.push(fullPath);\n }\n }\n\n return result;\n}\n"],"mappings":";;;;AAUA,UAAiB,iBACf,SACA,SACgE;CAChE,MAAM,QAAQA,KAAS,SAAS,OAAO;CAEvC,KAAK,MAAM,QAAQ,OAAO;EACxB,MAAM,WAAWC,OAAK,KAAK,QAAQ,KAAK,IAAI;EAC5C,IAAI;GAEF,MAAM;IAAE;IAAM;IAAU,SADRC,KAAG,aAAa,UAAU,MACZ;GAAE;EAClC,QAAQ;GACN;EACF;CACF;AACF;AAEA,SAAgB,cACd,eACA,UAAuB,CAAC,GACf;CACT,MAAM,MAAM,QAAQ,OAAO,QAAQ,IAAI;CACvC,MAAM,UAAU,QAAQ,WAAW;CACnC,MAAM,SAAS,QAAQ,UAAU;EAC/B;EACA;EACA;CACF;CAEA,MAAM,WAAW,MAAM,QAAQ,aAAa,IACxC,gBACA,CAAC,aAAa;CAElB,KAAK,MAAM,EAAE,aAAa,iBAAiB,SAAS;EAAE;EAAK;CAAO,CAAC,GACjE,IAAI,SAAS,MAAM,MAAM,QAAQ,SAAS,CAAC,CAAC,GAC1C,OAAO;CAIX,OAAO;AACT;AAEA,SAAgB,mBACd,cACA,UAAuB,CAAC,GACd;CACV,MAAM,MAAM,QAAQ,OAAO,QAAQ,IAAI;CACvC,MAAM,UAAU,QAAQ,WAAW;CACnC,MAAM,SAAS,QAAQ,UAAU;EAC/B;EACA;EACA;CACF;CAEA,MAAM,SAAmB,CAAC;CAE1B,KAAK,MAAM,EAAE,UAAU,aAAa,iBAAiB,SAAS;EAC5D;EACA;CACF,CAAC,GACC,IAAI,QAAQ,SAAS,YAAY,GAC/B,OAAO,KAAK,QAAQ;CAIxB,OAAO;AACT"}
@@ -1,6 +1,6 @@
1
1
  import { logger } from "./logger.js";
2
- import { scanForImport } from "./file-scanner.js";
3
2
  import { askQuestion, installPackage, isPackageInstalled } from "./package-manager.js";
3
+ import { scanForImport } from "./file-scanner.js";
4
4
  //#region src/lib/utils/package-installer.ts
5
5
  async function installPackageIfNeeded(config) {
6
6
  if (!scanForImport(config.importPatterns)) {
@@ -1,4 +1,5 @@
1
1
  //#region src/lib/utils/package-manager.d.ts
2
+ type PackageManagerName = "npm" | "pnpm" | "yarn" | "bun";
2
3
  declare function askQuestion(query: string): Promise<string>;
3
4
  declare function isPackageInstalled(pkg: string, cwd?: string): boolean;
4
5
  interface InstallCommand {
@@ -6,7 +7,8 @@ interface InstallCommand {
6
7
  args: string[];
7
8
  }
8
9
  declare function getInstallCommand(packageName: string | string[], cwd?: string): Promise<InstallCommand>;
10
+ declare function resolvePackageManagerForCwd(cwd: string, packageManager?: PackageManagerName): Promise<PackageManagerName>;
9
11
  declare function installPackage(packageName: string, cwd?: string): Promise<boolean>;
10
12
  //#endregion
11
- export { InstallCommand, askQuestion, getInstallCommand, installPackage, isPackageInstalled };
13
+ export { InstallCommand, PackageManagerName, askQuestion, getInstallCommand, installPackage, isPackageInstalled, resolvePackageManagerForCwd };
12
14
  //# sourceMappingURL=package-manager.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"package-manager.d.ts","names":[],"sources":["../../../src/lib/utils/package-manager.ts"],"mappings":";iBAOgB,YAAY,gBAAgB;iBAa5B,mBACd,aACA;UAmBe;EACf;EACA;;iBAGoB,kBACpB,gCACA,eACC,QAAQ;iBAeW,eACpB,qBACA,eACC"}
1
+ {"version":3,"file":"package-manager.d.ts","names":[],"sources":["../../../src/lib/utils/package-manager.ts"],"mappings":";KAOY;iBAEI,YAAY,gBAAgB;iBAa5B,mBACd,aACA;UAmBe;EACf;EACA;;iBAGoB,kBACpB,gCACA,eACC,QAAQ;iBAyBW,4BACpB,aACA,iBAAiB,qBAChB,QAAQ;iBAWW,eACpB,qBACA,eACC"}
@@ -1,8 +1,8 @@
1
+ import { SpawnSignalError, runSpawn } from "../run-spawn.js";
1
2
  import { logger } from "./logger.js";
2
3
  import * as fs$1 from "node:fs";
3
4
  import * as path$1 from "node:path";
4
5
  import { detect } from "detect-package-manager";
5
- import { spawnSync } from "node:child_process";
6
6
  import * as readline from "node:readline";
7
7
  //#region src/lib/utils/package-manager.ts
8
8
  function askQuestion(query) {
@@ -52,24 +52,36 @@ async function getInstallCommand(packageName, cwd) {
52
52
  };
53
53
  }
54
54
  }
55
+ function detectFromUserAgent() {
56
+ const ua = process.env.npm_config_user_agent;
57
+ if (!ua) return void 0;
58
+ if (ua.startsWith("bun/")) return "bun";
59
+ if (ua.startsWith("pnpm/")) return "pnpm";
60
+ if (ua.startsWith("yarn/")) return "yarn";
61
+ if (ua.startsWith("npm/")) return "npm";
62
+ }
63
+ async function resolvePackageManagerForCwd(cwd, packageManager) {
64
+ if (packageManager) return packageManager;
65
+ const fromAgent = detectFromUserAgent();
66
+ if (fromAgent) return fromAgent;
67
+ try {
68
+ return await detect({ cwd });
69
+ } catch {
70
+ return "npm";
71
+ }
72
+ }
55
73
  async function installPackage(packageName, cwd) {
56
74
  try {
57
75
  const { command, args } = await getInstallCommand(packageName, cwd);
58
- const result = spawnSync(command, args, {
59
- stdio: "inherit",
60
- cwd
61
- });
62
- if (result.error || result.status !== 0) {
63
- logger.error(`Installation failed${result.error ? `: ${String(result.error)}` : "."}`);
64
- return false;
65
- }
76
+ await runSpawn(command, args, cwd);
66
77
  return true;
67
78
  } catch (e) {
79
+ if (e instanceof SpawnSignalError) throw e;
68
80
  logger.error(`Installation failed: ${String(e)}`);
69
81
  return false;
70
82
  }
71
83
  }
72
84
  //#endregion
73
- export { askQuestion, getInstallCommand, installPackage, isPackageInstalled };
85
+ export { askQuestion, getInstallCommand, installPackage, isPackageInstalled, resolvePackageManagerForCwd };
74
86
 
75
87
  //# sourceMappingURL=package-manager.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"package-manager.js","names":["path","fs"],"sources":["../../../src/lib/utils/package-manager.ts"],"sourcesContent":["import * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport { spawnSync } from \"node:child_process\";\nimport { detect } from \"detect-package-manager\";\nimport * as readline from \"node:readline\";\nimport { logger } from \"./logger\";\n\nexport function askQuestion(query: string): Promise<string> {\n return new Promise((resolve) => {\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n rl.question(query, (answer) => {\n rl.close();\n resolve(answer);\n });\n });\n}\n\nexport function isPackageInstalled(\n pkg: string,\n cwd: string = process.cwd(),\n): boolean {\n try {\n const pkgJsonPath = path.join(cwd, \"package.json\");\n if (fs.existsSync(pkgJsonPath)) {\n const pkgJson = JSON.parse(fs.readFileSync(pkgJsonPath, \"utf8\"));\n const deps = pkgJson.dependencies || {};\n const devDeps = pkgJson.devDependencies || {};\n if (deps[pkg] || devDeps[pkg]) {\n return true;\n }\n }\n } catch {\n // Fall back to node_modules check below.\n }\n const modulePath = path.join(cwd, \"node_modules\", ...pkg.split(\"/\"));\n return fs.existsSync(modulePath);\n}\n\nexport interface InstallCommand {\n command: string;\n args: string[];\n}\n\nexport async function getInstallCommand(\n packageName: string | string[],\n cwd?: string,\n): Promise<InstallCommand> {\n const pm = await detect({ cwd });\n const packages = Array.isArray(packageName) ? packageName : [packageName];\n switch (pm) {\n case \"yarn\":\n return { command: \"yarn\", args: [\"add\", ...packages] };\n case \"pnpm\":\n return { command: \"pnpm\", args: [\"add\", ...packages] };\n case \"bun\":\n return { command: \"bun\", args: [\"add\", ...packages] };\n default:\n return { command: \"npm\", args: [\"install\", ...packages] };\n }\n}\n\nexport async function installPackage(\n packageName: string,\n cwd?: string,\n): Promise<boolean> {\n try {\n const { command, args } = await getInstallCommand(packageName, cwd);\n const result = spawnSync(command, args, { stdio: \"inherit\", cwd });\n\n if (result.error || result.status !== 0) {\n logger.error(\n `Installation failed${\n result.error ? `: ${String(result.error)}` : \".\"\n }`,\n );\n return false;\n }\n\n return true;\n } catch (e) {\n logger.error(`Installation failed: ${String(e)}`);\n return false;\n }\n}\n"],"mappings":";;;;;;;AAOA,SAAgB,YAAY,OAAgC;CAC1D,OAAO,IAAI,SAAS,YAAY;EAC9B,MAAM,KAAK,SAAS,gBAAgB;GAClC,OAAO,QAAQ;GACf,QAAQ,QAAQ;EAClB,CAAC;EACD,GAAG,SAAS,QAAQ,WAAW;GAC7B,GAAG,MAAM;GACT,QAAQ,MAAM;EAChB,CAAC;CACH,CAAC;AACH;AAEA,SAAgB,mBACd,KACA,MAAc,QAAQ,IAAI,GACjB;CACT,IAAI;EACF,MAAM,cAAcA,OAAK,KAAK,KAAK,cAAc;EACjD,IAAIC,KAAG,WAAW,WAAW,GAAG;GAC9B,MAAM,UAAU,KAAK,MAAMA,KAAG,aAAa,aAAa,MAAM,CAAC;GAC/D,MAAM,OAAO,QAAQ,gBAAgB,CAAC;GACtC,MAAM,UAAU,QAAQ,mBAAmB,CAAC;GAC5C,IAAI,KAAK,QAAQ,QAAQ,MACvB,OAAO;EAEX;CACF,QAAQ,CAER;CACA,MAAM,aAAaD,OAAK,KAAK,KAAK,gBAAgB,GAAG,IAAI,MAAM,GAAG,CAAC;CACnE,OAAOC,KAAG,WAAW,UAAU;AACjC;AAOA,eAAsB,kBACpB,aACA,KACyB;CACzB,MAAM,KAAK,MAAM,OAAO,EAAE,IAAI,CAAC;CAC/B,MAAM,WAAW,MAAM,QAAQ,WAAW,IAAI,cAAc,CAAC,WAAW;CACxE,QAAQ,IAAR;EACE,KAAK,QACH,OAAO;GAAE,SAAS;GAAQ,MAAM,CAAC,OAAO,GAAG,QAAQ;EAAE;EACvD,KAAK,QACH,OAAO;GAAE,SAAS;GAAQ,MAAM,CAAC,OAAO,GAAG,QAAQ;EAAE;EACvD,KAAK,OACH,OAAO;GAAE,SAAS;GAAO,MAAM,CAAC,OAAO,GAAG,QAAQ;EAAE;EACtD,SACE,OAAO;GAAE,SAAS;GAAO,MAAM,CAAC,WAAW,GAAG,QAAQ;EAAE;CAC5D;AACF;AAEA,eAAsB,eACpB,aACA,KACkB;CAClB,IAAI;EACF,MAAM,EAAE,SAAS,SAAS,MAAM,kBAAkB,aAAa,GAAG;EAClE,MAAM,SAAS,UAAU,SAAS,MAAM;GAAE,OAAO;GAAW;EAAI,CAAC;EAEjE,IAAI,OAAO,SAAS,OAAO,WAAW,GAAG;GACvC,OAAO,MACL,sBACE,OAAO,QAAQ,KAAK,OAAO,OAAO,KAAK,MAAM,KAEjD;GACA,OAAO;EACT;EAEA,OAAO;CACT,SAAS,GAAG;EACV,OAAO,MAAM,wBAAwB,OAAO,CAAC,GAAG;EAChD,OAAO;CACT;AACF"}
1
+ {"version":3,"file":"package-manager.js","names":["path","fs"],"sources":["../../../src/lib/utils/package-manager.ts"],"sourcesContent":["import * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport { detect } from \"detect-package-manager\";\nimport * as readline from \"node:readline\";\nimport { logger } from \"./logger\";\nimport { runSpawn, SpawnSignalError } from \"../run-spawn\";\n\nexport type PackageManagerName = \"npm\" | \"pnpm\" | \"yarn\" | \"bun\";\n\nexport function askQuestion(query: string): Promise<string> {\n return new Promise((resolve) => {\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n rl.question(query, (answer) => {\n rl.close();\n resolve(answer);\n });\n });\n}\n\nexport function isPackageInstalled(\n pkg: string,\n cwd: string = process.cwd(),\n): boolean {\n try {\n const pkgJsonPath = path.join(cwd, \"package.json\");\n if (fs.existsSync(pkgJsonPath)) {\n const pkgJson = JSON.parse(fs.readFileSync(pkgJsonPath, \"utf8\"));\n const deps = pkgJson.dependencies || {};\n const devDeps = pkgJson.devDependencies || {};\n if (deps[pkg] || devDeps[pkg]) {\n return true;\n }\n }\n } catch {\n // Fall back to node_modules check below.\n }\n const modulePath = path.join(cwd, \"node_modules\", ...pkg.split(\"/\"));\n return fs.existsSync(modulePath);\n}\n\nexport interface InstallCommand {\n command: string;\n args: string[];\n}\n\nexport async function getInstallCommand(\n packageName: string | string[],\n cwd?: string,\n): Promise<InstallCommand> {\n const pm = await detect({ cwd });\n const packages = Array.isArray(packageName) ? packageName : [packageName];\n switch (pm) {\n case \"yarn\":\n return { command: \"yarn\", args: [\"add\", ...packages] };\n case \"pnpm\":\n return { command: \"pnpm\", args: [\"add\", ...packages] };\n case \"bun\":\n return { command: \"bun\", args: [\"add\", ...packages] };\n default:\n return { command: \"npm\", args: [\"install\", ...packages] };\n }\n}\n\nfunction detectFromUserAgent(): PackageManagerName | undefined {\n const ua = process.env.npm_config_user_agent;\n if (!ua) return undefined;\n if (ua.startsWith(\"bun/\")) return \"bun\";\n if (ua.startsWith(\"pnpm/\")) return \"pnpm\";\n if (ua.startsWith(\"yarn/\")) return \"yarn\";\n if (ua.startsWith(\"npm/\")) return \"npm\";\n return undefined;\n}\n\nexport async function resolvePackageManagerForCwd(\n cwd: string,\n packageManager?: PackageManagerName,\n): Promise<PackageManagerName> {\n if (packageManager) return packageManager;\n const fromAgent = detectFromUserAgent();\n if (fromAgent) return fromAgent;\n try {\n return await detect({ cwd });\n } catch {\n return \"npm\";\n }\n}\n\nexport async function installPackage(\n packageName: string,\n cwd?: string,\n): Promise<boolean> {\n try {\n const { command, args } = await getInstallCommand(packageName, cwd);\n await runSpawn(command, args, cwd);\n return true;\n } catch (e) {\n if (e instanceof SpawnSignalError) throw e;\n logger.error(`Installation failed: ${String(e)}`);\n return false;\n }\n}\n"],"mappings":";;;;;;;AASA,SAAgB,YAAY,OAAgC;CAC1D,OAAO,IAAI,SAAS,YAAY;EAC9B,MAAM,KAAK,SAAS,gBAAgB;GAClC,OAAO,QAAQ;GACf,QAAQ,QAAQ;EAClB,CAAC;EACD,GAAG,SAAS,QAAQ,WAAW;GAC7B,GAAG,MAAM;GACT,QAAQ,MAAM;EAChB,CAAC;CACH,CAAC;AACH;AAEA,SAAgB,mBACd,KACA,MAAc,QAAQ,IAAI,GACjB;CACT,IAAI;EACF,MAAM,cAAcA,OAAK,KAAK,KAAK,cAAc;EACjD,IAAIC,KAAG,WAAW,WAAW,GAAG;GAC9B,MAAM,UAAU,KAAK,MAAMA,KAAG,aAAa,aAAa,MAAM,CAAC;GAC/D,MAAM,OAAO,QAAQ,gBAAgB,CAAC;GACtC,MAAM,UAAU,QAAQ,mBAAmB,CAAC;GAC5C,IAAI,KAAK,QAAQ,QAAQ,MACvB,OAAO;EAEX;CACF,QAAQ,CAER;CACA,MAAM,aAAaD,OAAK,KAAK,KAAK,gBAAgB,GAAG,IAAI,MAAM,GAAG,CAAC;CACnE,OAAOC,KAAG,WAAW,UAAU;AACjC;AAOA,eAAsB,kBACpB,aACA,KACyB;CACzB,MAAM,KAAK,MAAM,OAAO,EAAE,IAAI,CAAC;CAC/B,MAAM,WAAW,MAAM,QAAQ,WAAW,IAAI,cAAc,CAAC,WAAW;CACxE,QAAQ,IAAR;EACE,KAAK,QACH,OAAO;GAAE,SAAS;GAAQ,MAAM,CAAC,OAAO,GAAG,QAAQ;EAAE;EACvD,KAAK,QACH,OAAO;GAAE,SAAS;GAAQ,MAAM,CAAC,OAAO,GAAG,QAAQ;EAAE;EACvD,KAAK,OACH,OAAO;GAAE,SAAS;GAAO,MAAM,CAAC,OAAO,GAAG,QAAQ;EAAE;EACtD,SACE,OAAO;GAAE,SAAS;GAAO,MAAM,CAAC,WAAW,GAAG,QAAQ;EAAE;CAC5D;AACF;AAEA,SAAS,sBAAsD;CAC7D,MAAM,KAAK,QAAQ,IAAI;CACvB,IAAI,CAAC,IAAI,OAAO,KAAA;CAChB,IAAI,GAAG,WAAW,MAAM,GAAG,OAAO;CAClC,IAAI,GAAG,WAAW,OAAO,GAAG,OAAO;CACnC,IAAI,GAAG,WAAW,OAAO,GAAG,OAAO;CACnC,IAAI,GAAG,WAAW,MAAM,GAAG,OAAO;AAEpC;AAEA,eAAsB,4BACpB,KACA,gBAC6B;CAC7B,IAAI,gBAAgB,OAAO;CAC3B,MAAM,YAAY,oBAAoB;CACtC,IAAI,WAAW,OAAO;CACtB,IAAI;EACF,OAAO,MAAM,OAAO,EAAE,IAAI,CAAC;CAC7B,QAAQ;EACN,OAAO;CACT;AACF;AAEA,eAAsB,eACpB,aACA,KACkB;CAClB,IAAI;EACF,MAAM,EAAE,SAAS,SAAS,MAAM,kBAAkB,aAAa,GAAG;EAClE,MAAM,SAAS,SAAS,MAAM,GAAG;EACjC,OAAO;CACT,SAAS,GAAG;EACV,IAAI,aAAa,kBAAkB,MAAM;EACzC,OAAO,MAAM,wBAAwB,OAAO,CAAC,GAAG;EAChD,OAAO;CACT;AACF"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "assistant-ui",
3
- "version": "0.0.112",
3
+ "version": "0.0.113",
4
4
  "description": "CLI for assistant-ui",
5
5
  "keywords": [
6
6
  "cli",
@@ -26,6 +26,7 @@
26
26
  ],
27
27
  "sideEffects": false,
28
28
  "dependencies": {
29
+ "@assistant-ui/agent-launcher": "0.1.13",
29
30
  "@clack/prompts": "^1.7.0",
30
31
  "chalk": "^6.0.0",
31
32
  "cli-progress": "^3.12.0",
@@ -37,19 +38,18 @@
37
38
  "glob": "^13.0.6",
38
39
  "jscodeshift": "^17.4.0",
39
40
  "jsonc-parser": "^3.3.1",
40
- "semver": "^7.8.5",
41
- "@assistant-ui/agent-launcher": "0.1.12"
41
+ "semver": "^7.8.5"
42
42
  },
43
43
  "devDependencies": {
44
+ "@assistant-ui/x-buildutils": "0.0.24",
44
45
  "@types/cli-progress": "^3.11.6",
45
46
  "@types/cross-spawn": "^6.0.6",
46
47
  "@types/debug": "^4.1.13",
47
48
  "@types/jscodeshift": "^17.3.0",
48
49
  "@types/node": "^26.2.0",
49
50
  "@types/semver": "^7.8.0",
50
- "@vitest/coverage-v8": "^4.1.10",
51
- "vitest": "^4.1.10",
52
- "@assistant-ui/x-buildutils": "0.0.23"
51
+ "@vitest/coverage-v8": "^4.1.11",
52
+ "vitest": "^4.1.11"
53
53
  },
54
54
  "publishConfig": {
55
55
  "access": "public",
@@ -67,7 +67,7 @@ assistant-ui requires a runtime. The most common setup uses AI SDK:
67
67
 
68
68
  Install the integration package:
69
69
  ```bash
70
- npm install @assistant-ui/react-ai-sdk
70
+ npm install @assistant-ui/ai-sdk
71
71
  ```
72
72
 
73
73
  Create a chat API route (Next.js App Router):
@@ -98,7 +98,7 @@ Create the assistant component:
98
98
  "use client";
99
99
 
100
100
  import { AssistantRuntimeProvider } from "@assistant-ui/react";
101
- import { useChatRuntime } from "@assistant-ui/react-ai-sdk";
101
+ import { useChatRuntime } from "@assistant-ui/ai-sdk";
102
102
  import { Thread } from "@/components/assistant-ui/thread";
103
103
 
104
104
  export const Assistant = () => {
@@ -188,7 +188,7 @@ Do not use `makeAssistantToolUI`, `useAssistantToolUI`, `makeAssistantTool`, or
188
188
  | Package | Purpose |
189
189
  |---------|---------|
190
190
  | `@assistant-ui/react` | Core React components and primitives |
191
- | `@assistant-ui/react-ai-sdk` | Vercel AI SDK integration |
191
+ | `@assistant-ui/ai-sdk` | Vercel AI SDK integration |
192
192
  | `@assistant-ui/react-markdown` | Markdown rendering |
193
193
  | `@assistant-ui/react-syntax-highlighter` | Code highlighting |
194
194
  | `@assistant-ui/ui` | Pre-built shadcn/ui component set |