assistant-ui 0.0.117 → 0.0.118

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 (125) hide show
  1. package/dist/codemods/utils/createTransformer.d.ts +10 -12
  2. package/dist/codemods/utils/createTransformer.d.ts.map +1 -1
  3. package/dist/codemods/utils/resolveBinding.d.ts +3 -0
  4. package/dist/codemods/utils/resolveBinding.d.ts.map +1 -0
  5. package/dist/codemods/utils/resolveBinding.js +78 -0
  6. package/dist/codemods/utils/resolveBinding.js.map +1 -0
  7. package/dist/codemods/v0-11/content-part-to-message-part.d.ts +1 -3
  8. package/dist/codemods/v0-11/content-part-to-message-part.d.ts.map +1 -1
  9. package/dist/codemods/v0-12/assistant-api-to-aui.d.ts +1 -3
  10. package/dist/codemods/v0-12/assistant-api-to-aui.d.ts.map +1 -1
  11. package/dist/codemods/v0-12/assistant-api-to-aui.js +51 -99
  12. package/dist/codemods/v0-12/assistant-api-to-aui.js.map +1 -1
  13. package/dist/codemods/v0-12/event-names-to-camelcase.d.ts +1 -3
  14. package/dist/codemods/v0-12/event-names-to-camelcase.d.ts.map +1 -1
  15. package/dist/codemods/v0-12/primitive-if-to-aui-if.d.ts +1 -3
  16. package/dist/codemods/v0-12/primitive-if-to-aui-if.d.ts.map +1 -1
  17. package/dist/codemods/v0-15/aui-accessor-calls-to-properties.d.ts +1 -3
  18. package/dist/codemods/v0-15/aui-accessor-calls-to-properties.d.ts.map +1 -1
  19. package/dist/codemods/v0-15/aui-accessor-calls-to-properties.js +33 -5
  20. package/dist/codemods/v0-15/aui-accessor-calls-to-properties.js.map +1 -1
  21. package/dist/codemods/v0-8/ui-package-split.d.ts +1 -3
  22. package/dist/codemods/v0-8/ui-package-split.d.ts.map +1 -1
  23. package/dist/codemods/v0-9/edge-package-split.d.ts +1 -3
  24. package/dist/codemods/v0-9/edge-package-split.d.ts.map +1 -1
  25. package/dist/commands/add.d.ts +10 -12
  26. package/dist/commands/add.d.ts.map +1 -1
  27. package/dist/commands/add.js +3 -3
  28. package/dist/commands/agent.d.ts +0 -2
  29. package/dist/commands/agent.d.ts.map +1 -1
  30. package/dist/commands/agent.js +16 -13
  31. package/dist/commands/agent.js.map +1 -1
  32. package/dist/commands/create.d.ts +33 -28
  33. package/dist/commands/create.d.ts.map +1 -1
  34. package/dist/commands/create.js +19 -15
  35. package/dist/commands/create.js.map +1 -1
  36. package/dist/commands/doctor.d.ts +8 -10
  37. package/dist/commands/doctor.d.ts.map +1 -1
  38. package/dist/commands/info.d.ts +2 -4
  39. package/dist/commands/info.d.ts.map +1 -1
  40. package/dist/commands/info.js +3 -3
  41. package/dist/commands/init.d.ts +5 -6
  42. package/dist/commands/init.d.ts.map +1 -1
  43. package/dist/commands/init.js +2 -2
  44. package/dist/commands/mcp.d.ts +0 -2
  45. package/dist/commands/mcp.d.ts.map +1 -1
  46. package/dist/commands/mcp.js +2 -2
  47. package/dist/commands/update.d.ts +0 -2
  48. package/dist/commands/update.d.ts.map +1 -1
  49. package/dist/commands/update.js +1 -1
  50. package/dist/commands/upgrade.d.ts +4 -6
  51. package/dist/commands/upgrade.d.ts.map +1 -1
  52. package/dist/index.d.ts +3 -1
  53. package/dist/index.d.ts.map +1 -0
  54. package/dist/lib/agent-skill.d.ts +8 -6
  55. package/dist/lib/agent-skill.d.ts.map +1 -1
  56. package/dist/lib/agent-skill.js +78 -2
  57. package/dist/lib/agent-skill.js.map +1 -1
  58. package/dist/lib/create-project.d.ts +22 -20
  59. package/dist/lib/create-project.d.ts.map +1 -1
  60. package/dist/lib/create-project.js +91 -5
  61. package/dist/lib/create-project.js.map +1 -1
  62. package/dist/lib/handle-cli-error.d.ts +0 -2
  63. package/dist/lib/handle-cli-error.d.ts.map +1 -1
  64. package/dist/lib/install-ai-sdk-lib.d.ts +0 -2
  65. package/dist/lib/install-ai-sdk-lib.d.ts.map +1 -1
  66. package/dist/lib/install-edge-lib.d.ts +0 -2
  67. package/dist/lib/install-edge-lib.d.ts.map +1 -1
  68. package/dist/lib/run-spawn.d.ts +11 -12
  69. package/dist/lib/run-spawn.d.ts.map +1 -1
  70. package/dist/lib/run-spawn.js +25 -10
  71. package/dist/lib/run-spawn.js.map +1 -1
  72. package/dist/lib/transform-options.d.ts +4 -6
  73. package/dist/lib/transform-options.d.ts.map +1 -1
  74. package/dist/lib/transform.d.ts +11 -13
  75. package/dist/lib/transform.d.ts.map +1 -1
  76. package/dist/lib/transform.js +19 -35
  77. package/dist/lib/transform.js.map +1 -1
  78. package/dist/lib/upgrade.d.ts +2 -4
  79. package/dist/lib/upgrade.d.ts.map +1 -1
  80. package/dist/lib/upgrade.js +6 -11
  81. package/dist/lib/upgrade.js.map +1 -1
  82. package/dist/lib/utils/config.d.ts +14 -16
  83. package/dist/lib/utils/config.d.ts.map +1 -1
  84. package/dist/lib/utils/file-scanner.d.ts +8 -10
  85. package/dist/lib/utils/file-scanner.d.ts.map +1 -1
  86. package/dist/lib/utils/logger.d.ts +6 -8
  87. package/dist/lib/utils/logger.d.ts.map +1 -1
  88. package/dist/lib/utils/package-installer.d.ts +5 -7
  89. package/dist/lib/utils/package-installer.d.ts.map +1 -1
  90. package/dist/lib/utils/package-json.d.ts +0 -2
  91. package/dist/lib/utils/package-json.d.ts.map +1 -1
  92. package/dist/lib/utils/package-manager.d.ts +2 -4
  93. package/dist/lib/utils/package-manager.d.ts.map +1 -1
  94. package/dist/lib/utils/package-manager.js +13 -2
  95. package/dist/lib/utils/package-manager.js.map +1 -1
  96. package/dist/lib/utils/registry.d.ts +0 -2
  97. package/dist/lib/utils/registry.d.ts.map +1 -1
  98. package/dist/lib/utils/workspace.d.ts +0 -2
  99. package/dist/lib/utils/workspace.d.ts.map +1 -1
  100. package/dist/program.d.ts +0 -2
  101. package/dist/program.d.ts.map +1 -1
  102. package/dist/program.js +6 -6
  103. package/dist/run.d.ts +0 -2
  104. package/dist/run.d.ts.map +1 -1
  105. package/package.json +2 -3
  106. package/src/codemods/utils/resolveBinding.test.ts +107 -0
  107. package/src/codemods/utils/resolveBinding.ts +130 -0
  108. package/src/codemods/v0-12/__tests__/assistant-api-to-aui.test.ts +256 -0
  109. package/src/codemods/v0-12/assistant-api-to-aui.ts +125 -225
  110. package/src/codemods/v0-15/__tests__/aui-accessor-calls-to-properties.test.ts +101 -0
  111. package/src/codemods/v0-15/aui-accessor-calls-to-properties.ts +60 -5
  112. package/src/commands/agent.ts +15 -22
  113. package/src/commands/create.ts +24 -15
  114. package/src/lib/agent-skill.ts +103 -1
  115. package/src/lib/create-project.ts +99 -4
  116. package/src/lib/run-spawn.test.ts +47 -0
  117. package/src/lib/run-spawn.ts +29 -17
  118. package/src/lib/transform-files.test.ts +71 -0
  119. package/src/lib/transform.test.ts +69 -1
  120. package/src/lib/transform.ts +23 -38
  121. package/src/lib/upgrade.ts +9 -13
  122. package/src/lib/utils/package-manager.ts +24 -1
  123. package/plugin/.claude-plugin/plugin.json +0 -8
  124. package/plugin/skills/assistant-ui/SKILL.md +0 -199
  125. package/plugin/skills/assistant-ui/shipables.json +0 -22
@@ -1,5 +1,5 @@
1
- import { SpawnSignalError, runSpawn } from "../run-spawn.js";
2
1
  import { logger } from "./logger.js";
2
+ import { SpawnSignalError, runSpawn } from "../run-spawn.js";
3
3
  import * as fs$1 from "node:fs";
4
4
  import * as path$1 from "node:path";
5
5
  import { detect } from "detect-package-manager";
@@ -7,13 +7,24 @@ import * as readline from "node:readline";
7
7
  //#region src/lib/utils/package-manager.ts
8
8
  function askQuestion(query) {
9
9
  return new Promise((resolve) => {
10
+ if (process.stdin.readableEnded) {
11
+ resolve("");
12
+ return;
13
+ }
10
14
  const rl = readline.createInterface({
11
15
  input: process.stdin,
12
16
  output: process.stdout
13
17
  });
14
- rl.question(query, (answer) => {
18
+ let cancelled = false;
19
+ rl.on("SIGINT", () => {
20
+ cancelled = true;
15
21
  rl.close();
22
+ });
23
+ rl.on("line", resolve);
24
+ rl.on("close", () => resolve(cancelled ? "n" : ""));
25
+ rl.question(query, (answer) => {
16
26
  resolve(answer);
27
+ rl.close();
17
28
  });
18
29
  });
19
30
  }
@@ -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 { 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"}
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 // A stream only reaches EOF once, so a run that already consumed stdin gets\n // no further `end` and an interface built over it would wait on a `close`\n // that cannot arrive. An upgrade asks up to three questions.\n if (process.stdin.readableEnded) {\n resolve(\"\");\n return;\n }\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n // stdin at EOF (a piped or CI run) emits `close` without a `line`, so the\n // question callback alone would leave this pending forever and the process\n // would exit 0 with the remaining work silently skipped. An empty answer is\n // what pressing Enter sends, so EOF lands on the prompt's own default.\n // A final answer with no trailing newline arrives as `line` instead of\n // through the callback, and has to win over that default.\n // Ctrl-C in raw mode is delivered as this event rather than as a signal,\n // and without a listener readline answers it by closing — which the EOF\n // default would then read as approval. A cancelled prompt declines.\n let cancelled = false;\n rl.on(\"SIGINT\", () => {\n cancelled = true;\n rl.close();\n });\n rl.on(\"line\", resolve);\n rl.on(\"close\", () => resolve(cancelled ? \"n\" : \"\"));\n rl.question(query, (answer) => {\n resolve(answer);\n rl.close();\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;EAI9B,IAAI,QAAQ,MAAM,eAAe;GAC/B,QAAQ,EAAE;GACV;EACF;EACA,MAAM,KAAK,SAAS,gBAAgB;GAClC,OAAO,QAAQ;GACf,QAAQ,QAAQ;EAClB,CAAC;EAUD,IAAI,YAAY;EAChB,GAAG,GAAG,gBAAgB;GACpB,YAAY;GACZ,GAAG,MAAM;EACX,CAAC;EACD,GAAG,GAAG,QAAQ,OAAO;EACrB,GAAG,GAAG,eAAe,QAAQ,YAAY,MAAM,EAAE,CAAC;EAClD,GAAG,SAAS,QAAQ,WAAW;GAC7B,QAAQ,MAAM;GACd,GAAG,MAAM;EACX,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"}
@@ -1,8 +1,6 @@
1
- //#region src/lib/utils/registry.d.ts
2
1
  export declare const SHARED_REGISTRY_ITEMS: Set<string>;
3
2
  export declare function detectRegistryPlatform(cwd: string): "web" | "native";
4
3
  export declare function getComponentsJsonStyle(cwd: string): string | undefined;
5
4
  export declare function resolveQuickStartRegistryUrl(style?: string): string;
6
5
  export declare function resolveRegistryItemUrl(component: string, style?: string, platform?: "web" | "native"): string;
7
- //#endregion
8
6
  //# sourceMappingURL=registry.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"registry.d.ts","names":[],"sources":["../../../src/lib/utils/registry.ts"],"mappings":";qBAIa,uBAAqB;wBAElB,uBAAuB;wBA2BvB,uBAAuB;wBAavB,6BAA6B;wBAW7B,uBACd,mBACA,gBACA"}
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../../src/lib/utils/registry.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,qBAAqB,aAAqB,CAAC;AAExD,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,MAAM,GAAG,KAAK,GAAG,QAAQ,CAyBpE;AAED,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAWtE;AAED,wBAAgB,4BAA4B,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CASnE;AAED,wBAAgB,sBAAsB,CACpC,SAAS,EAAE,MAAM,EACjB,KAAK,CAAC,EAAE,MAAM,EACd,QAAQ,GAAE,KAAK,GAAG,QAAgB,GACjC,MAAM,CAgBR"}
@@ -1,5 +1,3 @@
1
- //#region src/lib/utils/workspace.d.ts
2
1
  export declare function resolveRealPath(inputPath: string): string;
3
2
  export declare function findWorkspaceRoot(cwd: string): string | null;
4
- //#endregion
5
3
  //# sourceMappingURL=workspace.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"workspace.d.ts","names":[],"sources":["../../../src/lib/utils/workspace.ts"],"mappings":";wBAGgB,gBAAgB;wBAUhB,kBAAkB"}
1
+ {"version":3,"file":"workspace.d.ts","sourceRoot":"","sources":["../../../src/lib/utils/workspace.ts"],"names":[],"mappings":"AAGA,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAQzD;AAED,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAoB5D"}
package/dist/program.d.ts CHANGED
@@ -1,5 +1,3 @@
1
1
  import { Command } from "commander";
2
- //#region src/program.d.ts
3
2
  export declare function buildProgram(): Command;
4
- //#endregion
5
3
  //# sourceMappingURL=program.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"program.d.ts","names":[],"sources":["../src/program.ts"],"mappings":";;wBAWgB,gBAAY"}
1
+ {"version":3,"file":"program.d.ts","sourceRoot":"","sources":["../src/program.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAWpC,wBAAgB,YAAY,YAc3B"}
package/dist/program.js CHANGED
@@ -1,12 +1,12 @@
1
- import { create } from "./commands/create.js";
2
1
  import { add } from "./commands/add.js";
3
- import { codemodCommand, upgradeCommand } from "./commands/upgrade.js";
4
- import { init } from "./commands/init.js";
5
- import { update } from "./commands/update.js";
6
- import { mcp } from "./commands/mcp.js";
7
2
  import { agent } from "./commands/agent.js";
8
- import { info } from "./commands/info.js";
3
+ import { create } from "./commands/create.js";
9
4
  import { doctor } from "./commands/doctor.js";
5
+ import { info } from "./commands/info.js";
6
+ import { init } from "./commands/init.js";
7
+ import { mcp } from "./commands/mcp.js";
8
+ import { update } from "./commands/update.js";
9
+ import { codemodCommand, upgradeCommand } from "./commands/upgrade.js";
10
10
  import { Command } from "commander";
11
11
  //#region src/program.ts
12
12
  function buildProgram() {
package/dist/run.d.ts CHANGED
@@ -1,4 +1,2 @@
1
- //#region src/run.d.ts
2
1
  export declare function runCli(): Promise<void>;
3
- //#endregion
4
2
  //# sourceMappingURL=run.d.ts.map
package/dist/run.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"run.d.ts","names":[],"sources":["../src/run.ts"],"mappings":";wBAEsB,UAAU"}
1
+ {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../src/run.ts"],"names":[],"mappings":"AAEA,wBAAsB,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,CAE5C"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "assistant-ui",
3
- "version": "0.0.117",
3
+ "version": "0.0.118",
4
4
  "description": "CLI for assistant-ui",
5
5
  "keywords": [
6
6
  "cli",
@@ -20,7 +20,6 @@
20
20
  "files": [
21
21
  "bin",
22
22
  "dist",
23
- "plugin",
24
23
  "src",
25
24
  "README.md"
26
25
  ],
@@ -41,7 +40,7 @@
41
40
  "semver": "^7.8.5"
42
41
  },
43
42
  "devDependencies": {
44
- "@assistant-ui/x-buildutils": "0.0.28",
43
+ "@assistant-ui/x-buildutils": "0.0.29",
45
44
  "@types/cli-progress": "^3.11.6",
46
45
  "@types/cross-spawn": "^6.0.6",
47
46
  "@types/debug": "^4.1.13",
@@ -0,0 +1,107 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import jscodeshift from "jscodeshift";
3
+ import { resolveBinding } from "./resolveBinding";
4
+
5
+ const j = jscodeshift.withParser("tsx");
6
+
7
+ describe("resolveBinding", () => {
8
+ it.each([
9
+ ["const", "of"],
10
+ ["let", "of"],
11
+ ["const", "in"],
12
+ ["let", "in"],
13
+ ])(
14
+ "resolves the uninitialized %s binding in a for-%s right-hand side",
15
+ (kind, operator) => {
16
+ const root = j(
17
+ `const client = outer(); for (${kind} client ${operator} read(client)) {}`,
18
+ );
19
+ const reference = root
20
+ .find(j.CallExpression, { callee: { name: "read" } })
21
+ .paths()[0]!
22
+ .get("arguments", 0);
23
+ const loopBinding = root.find(j.VariableDeclarator).nodes()[1]!.id;
24
+ expect(resolveBinding(j, reference, "client")).toBe(loopBinding);
25
+ },
26
+ );
27
+
28
+ it.each([
29
+ ["namespace Local { const client = inner(); read(client); }", "inner"],
30
+ [
31
+ "namespace Local { if (ready) { var client = inner(); } read(client); }",
32
+ "inner",
33
+ ],
34
+ ["namespace Local { var client = inner(); } read(client);", "outer"],
35
+ [
36
+ "function worker() { if (ready) { var client = inner(); } read(client); }",
37
+ "inner",
38
+ ],
39
+ [
40
+ "function worker(value = read(client)) { var client = inner(); }",
41
+ "outer",
42
+ ],
43
+ ["{ const client = inner(); read(client); }", "inner"],
44
+ ["{ const { client } = inner(); read(client); }", "inner"],
45
+ ["{ const [client] = inner(); read(client); }", "inner"],
46
+ [
47
+ "function worker() { { const client = inner(); } read(client); }",
48
+ "outer",
49
+ ],
50
+ ["switch (read(client)) { case 1: const client = inner(); }", "outer"],
51
+ [
52
+ "switch (value) { case 1: const client = inner(); read(client); }",
53
+ "inner",
54
+ ],
55
+ ["for (const client = inner(); ready;) { read(client); }", "inner"],
56
+ [
57
+ "function worker() { function other() { var client = inner(); } read(client); }",
58
+ "outer",
59
+ ],
60
+ ["{ type client = Other; read(client); }", "outer"],
61
+ ])("resolves %s", (scope, expected) => {
62
+ const root = j(`const client = outer(); ${scope}`);
63
+ const reference = root
64
+ .find(j.CallExpression, { callee: { name: "read" } })
65
+ .paths()[0]!
66
+ .get("arguments", 0);
67
+ const binding = resolveBinding(j, reference, "client");
68
+ const declaration = root
69
+ .find(j.VariableDeclarator, { init: { callee: { name: expected } } })
70
+ .nodes()[0]!;
71
+ const identifiers = j(declaration.id)
72
+ .find(j.Identifier, { name: "client" })
73
+ .nodes();
74
+ expect(binding).toBe(
75
+ j.Identifier.check(declaration.id) ? declaration.id : identifiers.at(-1),
76
+ );
77
+ });
78
+
79
+ it.each([
80
+ "function worker(client) { read(client); }",
81
+ "function worker({ client }) { read(client); }",
82
+ "function worker(client = fallback) { read(client); }",
83
+ "try {} catch (client) { read(client); }",
84
+ "class Reader { constructor(private client: Client) { read(client); } }",
85
+ ])("resolves a parameter binding: %s", (source) => {
86
+ const root = j(source);
87
+ const reference = root
88
+ .find(j.CallExpression, { callee: { name: "read" } })
89
+ .paths()[0]!
90
+ .get("arguments", 0);
91
+ const binding = resolveBinding(j, reference, "client");
92
+ expect(binding?.name).toBe("client");
93
+ expect(binding).not.toBe(reference.value);
94
+ });
95
+
96
+ it("resolves imports and distinguishes an unbound identifier", () => {
97
+ const root = j('import { client } from "./client"; read(client);');
98
+ const reference = root
99
+ .find(j.CallExpression)
100
+ .paths()[0]!
101
+ .get("arguments", 0);
102
+ expect(resolveBinding(j, reference, "client")).toBe(
103
+ root.find(j.ImportSpecifier).nodes()[0]!.local,
104
+ );
105
+ expect(resolveBinding(j, reference, "missing")).toBeUndefined();
106
+ });
107
+ });
@@ -0,0 +1,130 @@
1
+ import type { JSCodeshift } from "jscodeshift";
2
+
3
+ const patternBinding = (node: any, name: string): any => {
4
+ switch (node?.type) {
5
+ case "Identifier":
6
+ return node.name === name ? node : undefined;
7
+ case "TSParameterProperty":
8
+ return patternBinding(node.parameter, name);
9
+ case "AssignmentPattern":
10
+ return patternBinding(node.left, name);
11
+ case "RestElement":
12
+ return patternBinding(node.argument, name);
13
+ case "ObjectPattern":
14
+ return node.properties
15
+ .map((p: any) => patternBinding(p.value ?? p.argument, name))
16
+ .find(Boolean);
17
+ case "ArrayPattern":
18
+ return node.elements
19
+ .map((p: any) => patternBinding(p, name))
20
+ .find(Boolean);
21
+ }
22
+ };
23
+
24
+ const declarationBinding = (node: any, name: string): any => {
25
+ switch (node?.type) {
26
+ case "ExportNamedDeclaration":
27
+ case "ExportDefaultDeclaration":
28
+ return declarationBinding(node.declaration, name);
29
+ case "VariableDeclaration":
30
+ return node.declarations
31
+ .map((d: any) => patternBinding(d.id, name))
32
+ .find(Boolean);
33
+ case "ImportDeclaration":
34
+ if (node.importKind === "type") return;
35
+ return node.specifiers
36
+ ?.filter((s: any) => s.importKind !== "type")
37
+ .map((s: any) => patternBinding(s.local, name))
38
+ .find(Boolean);
39
+ case "TSTypeAliasDeclaration":
40
+ case "TSInterfaceDeclaration":
41
+ case "TSDeclareFunction":
42
+ return;
43
+ default:
44
+ return patternBinding(node?.id, name);
45
+ }
46
+ };
47
+
48
+ const hoistedBinding = (j: JSCodeshift, body: any, name: string): any => {
49
+ let binding: any;
50
+ j.types.visit(body, {
51
+ visitFunction() {
52
+ return false;
53
+ },
54
+ visitClassDeclaration() {
55
+ return false;
56
+ },
57
+ visitClassExpression() {
58
+ return false;
59
+ },
60
+ visitTSModuleBlock(path) {
61
+ if (path.node !== body) return false;
62
+ this.traverse(path);
63
+ return undefined;
64
+ },
65
+ visitVariableDeclaration(path) {
66
+ if (path.node.kind === "var")
67
+ binding ??= declarationBinding(path.node, name);
68
+ this.traverse(path);
69
+ },
70
+ });
71
+ return binding;
72
+ };
73
+
74
+ // ast-types scopes do not distinguish block-scoped declarations.
75
+ export const resolveBinding = (
76
+ j: JSCodeshift,
77
+ path: any,
78
+ name: string,
79
+ ): any => {
80
+ let child = path;
81
+ for (
82
+ let current = path.parent;
83
+ current;
84
+ child = current, current = current.parent
85
+ ) {
86
+ const node = current.value;
87
+ let binding: any;
88
+ if (Array.isArray(node.params)) {
89
+ binding =
90
+ node.params.map((p: any) => patternBinding(p, name)).find(Boolean) ??
91
+ patternBinding(node.id, name) ??
92
+ (child.value === node.body
93
+ ? hoistedBinding(j, node.body, name)
94
+ : undefined);
95
+ } else if (node.type === "CatchClause") {
96
+ binding = patternBinding(node.param, name);
97
+ } else if (node.type === "ClassExpression") {
98
+ binding = patternBinding(node.id, name);
99
+ } else if (node.type === "ForStatement") {
100
+ binding = declarationBinding(node.init, name);
101
+ } else if (
102
+ node.type === "ForInStatement" ||
103
+ node.type === "ForOfStatement"
104
+ ) {
105
+ binding = declarationBinding(node.left, name);
106
+ } else {
107
+ const statements =
108
+ node.type === "SwitchStatement" && child.value !== node.discriminant
109
+ ? node.cases.flatMap((c: any) => c.consequent)
110
+ : [
111
+ "BlockStatement",
112
+ "Program",
113
+ "StaticBlock",
114
+ "TSModuleBlock",
115
+ ].includes(node.type)
116
+ ? node.body
117
+ : [];
118
+ binding = statements
119
+ .map((s: any) => declarationBinding(s, name))
120
+ .find(Boolean);
121
+ if (
122
+ !binding &&
123
+ ["Program", "StaticBlock", "TSModuleBlock"].includes(node.type)
124
+ ) {
125
+ binding = hoistedBinding(j, node, name);
126
+ }
127
+ }
128
+ if (binding) return binding;
129
+ }
130
+ };
@@ -21,6 +21,262 @@ function applyTransform(source: string): string | null {
21
21
  }
22
22
 
23
23
  describe("assistant-api-to-aui", () => {
24
+ it.each([
25
+ "const aui = props.aui; const api = useAui(); api.thread();",
26
+ "const api = useAui(); const aui = props.aui; api.thread();",
27
+ "const api = useAui(); function read(aui) { return api.thread(); }",
28
+ "const api = useAui(); { const aui = props.aui; api.thread(); }",
29
+ "function read(aui) { const api = useAui(); return api.thread(); }",
30
+ ])("preserves api when renaming would collide or capture: %s", (source) => {
31
+ const input = `import { useAui } from "@assistant-ui/react";\n${source}`;
32
+ expect(applyTransform(input)).toBeNull();
33
+ });
34
+
35
+ it("still migrates the hook when the api local name must be preserved", () => {
36
+ const output =
37
+ applyTransform(`import { useAssistantApi } from "@assistant-ui/react";
38
+ const aui = props.aui;
39
+ const api = useAssistantApi();
40
+ api.thread();`);
41
+ expect(output).toContain('import { useAui } from "@assistant-ui/react";');
42
+ expect(output).toContain("const api = useAui();");
43
+ expect(output).toContain("api.thread();");
44
+ expect(applyTransform(output!)).toBeNull();
45
+ });
46
+
47
+ it("does not let one colliding api binding prevent independent renames", () => {
48
+ const blocked =
49
+ "function blocked(aui) { const api = useAui(); return api.thread(); }";
50
+ const output = applyTransform(`import { useAui } from "@assistant-ui/react";
51
+ ${blocked}
52
+ function safe() { const api = useAui(); return api.thread(); }`);
53
+ expect(output).toContain(blocked);
54
+ expect(output).toContain(
55
+ "function safe() { const aui = useAui(); return aui.thread(); }",
56
+ );
57
+ expect(applyTransform(output!)).toBeNull();
58
+ });
59
+
60
+ it.each([
61
+ ["AssistantProvider", "AuiProvider"],
62
+ ["useAssistantState", "useAuiState"],
63
+ ])("preserves qualified type members named %s", (oldName, newName) => {
64
+ const output =
65
+ applyTransform(`import { ${oldName} } from "@assistant-ui/react";
66
+ import type { Components } from "./types";
67
+ type Foreign = Components.${oldName};
68
+ type Nested = Components.Nested.${oldName};
69
+ type ForeignValue = typeof Components.${oldName};
70
+ type LocalValue = typeof ${oldName};
71
+ type LocalMember = typeof ${oldName}.displayName;
72
+ const value = ${oldName};`);
73
+ expect(output).toContain(`type Foreign = Components.${oldName};`);
74
+ expect(output).toContain(`type Nested = Components.Nested.${oldName};`);
75
+ expect(output).toContain(
76
+ `type ForeignValue = typeof Components.${oldName};`,
77
+ );
78
+ expect(output).toContain(`type LocalValue = typeof ${newName};`);
79
+ expect(output).toContain(
80
+ `type LocalMember = typeof ${newName}.displayName;`,
81
+ );
82
+ expect(output).toContain(`const value = ${newName};`);
83
+ expect(applyTransform(output!)).toBeNull();
84
+ });
85
+
86
+ it.each([
87
+ ["const", "of"],
88
+ ["let", "of"],
89
+ ["const", "in"],
90
+ ["let", "in"],
91
+ ])(
92
+ "preserves %s for-%s bindings in their right-hand side",
93
+ (kind, operator) => {
94
+ const loop = `for (${kind} api ${operator} api.thread()) { api.thread(); }`;
95
+ const output =
96
+ applyTransform(`import { useAssistantApi } from "@assistant-ui/react";
97
+ const api = useAssistantApi();
98
+ ${loop}
99
+ api.thread();`);
100
+ expect(output).toContain(loop);
101
+ expect(output).toContain("const aui = useAui();");
102
+ expect(output).toContain("\naui.thread();");
103
+ },
104
+ );
105
+
106
+ it.each(["useAssistantApi", "useAui"])(
107
+ "preserves api initialized from a foreign %s import",
108
+ (hook) => {
109
+ const input = `import { ${hook} } from "./local-hooks";
110
+ const api = ${hook}();
111
+ api.thread();`;
112
+ expect(applyTransform(input)).toBeNull();
113
+ },
114
+ );
115
+
116
+ it.each(["useAssistantApi", "useAui"])(
117
+ "preserves api initialized from a shadowed %s import",
118
+ (hook) => {
119
+ const shadowed = `function local(${hook}) { const api = ${hook}(); return api.thread(); }
120
+ { const ${hook} = other; const api = ${hook}(); api.thread(); }
121
+ function hoisted() { const api = ${hook}(); if (ready) { var ${hook} = other; } return api.thread(); }`;
122
+ const output =
123
+ applyTransform(`import { ${hook} } from "@assistant-ui/react";
124
+ ${shadowed}
125
+ const api = ${hook}();
126
+ api.thread();`);
127
+ expect(output).toContain(shadowed);
128
+ expect(output).toContain("const aui = useAui();");
129
+ expect(output).toContain("\naui.thread();");
130
+ expect(applyTransform(output!)).toBeNull();
131
+ },
132
+ );
133
+
134
+ it.each(["useAssistantApi", "useAui"])(
135
+ "renames api initialized from an aliased %s import",
136
+ (hook) => {
137
+ const output =
138
+ applyTransform(`import { ${hook} as useClient } from "@assistant-ui/react";
139
+ const api = useClient();
140
+ api.thread();`);
141
+ expect(output).toContain("useAui as useClient");
142
+ expect(output).toContain("const aui = useClient();");
143
+ expect(output).toContain("aui.thread();");
144
+ expect(applyTransform(output!)).toBeNull();
145
+ },
146
+ );
147
+
148
+ it.each([
149
+ 'import type { useAssistantApi } from "@assistant-ui/react";',
150
+ 'import { type useAssistantApi } from "@assistant-ui/react";',
151
+ ])(
152
+ "does not infer an api value from type-only imports: %s",
153
+ (declaration) => {
154
+ const output = applyTransform(`${declaration}
155
+ const api = useAssistantApi();
156
+ api.thread();`);
157
+ expect(output).toContain("const api = useAssistantApi();");
158
+ expect(output).toContain("api.thread();");
159
+ },
160
+ );
161
+
162
+ it.each(["useAssistantApi", "useAui"])(
163
+ "leaves unresolved %s calls alone",
164
+ (hook) => {
165
+ expect(applyTransform(`const api = ${hook}(); api.thread();`)).toBeNull();
166
+ },
167
+ );
168
+
169
+ it("preserves hooks and components imported from another package", () => {
170
+ const input = `import { useAssistantState, AssistantIf } from "./local-hooks";
171
+ import { useAui } from "@assistant-ui/react";
172
+ const read = () => useAssistantState();
173
+ const view = <AssistantIf />;`;
174
+ expect(applyTransform(input)).toBeNull();
175
+ });
176
+
177
+ it.each([
178
+ "function local(useAssistantState) { return useAssistantState(); }",
179
+ "{ const useAssistantState = other; useAssistantState(); }",
180
+ "{ const { useAssistantState } = other; useAssistantState(); }",
181
+ "function local() { if (ready) { var useAssistantState = other; } return useAssistantState(); }",
182
+ ])("preserves a shadowed hook: %s", (unrelated) => {
183
+ const output = applyTransform(
184
+ `import { useAssistantState } from "@assistant-ui/react";\n${unrelated}\nuseAssistantState();`,
185
+ );
186
+ expect(output).toContain(unrelated);
187
+ expect(output).toContain("\nuseAuiState();");
188
+ });
189
+
190
+ it("preserves hook import aliases", () => {
191
+ const output =
192
+ applyTransform(`import { useAssistantState as useLocalState } from "@assistant-ui/react";
193
+ useLocalState();`);
194
+ expect(output).toContain("useAuiState as useLocalState");
195
+ expect(output).toContain("useLocalState();");
196
+ expect(applyTransform(output!)).toBeNull();
197
+ });
198
+
199
+ it("avoids duplicating an existing import of the new local name", () => {
200
+ const output =
201
+ applyTransform(`import { useAssistantState } from "@assistant-ui/react";
202
+ import { useAuiState } from "./other";
203
+ useAssistantState();
204
+ useAuiState();`);
205
+ expect(output).toContain("useAuiState as useAssistantState");
206
+ expect(output).toContain('import { useAuiState } from "./other";');
207
+ expect(output).toContain("\nuseAssistantState();");
208
+ });
209
+
210
+ it("preserves public property and export names", () => {
211
+ const output =
212
+ applyTransform(`import { useAssistantState } from "@assistant-ui/react";
213
+ const value = { useAssistantState };
214
+ obj.useAssistantState();
215
+ const config = { useAssistantState: "unchanged" };
216
+ export { useAssistantState };
217
+ export { useAssistantState as remote } from "./other";`);
218
+ expect(output).toMatch(/useAssistantState: useAuiState/);
219
+ expect(output).toContain("obj.useAssistantState();");
220
+ expect(output).toContain('useAssistantState: "unchanged"');
221
+ expect(output).toContain("useAuiState as useAssistantState");
222
+ expect(output).toContain(
223
+ 'export { useAssistantState as remote } from "./other";',
224
+ );
225
+ });
226
+
227
+ it("does not capture references with an existing new-name binding", () => {
228
+ const output =
229
+ applyTransform(`import { useAssistantState } from "@assistant-ui/react";
230
+ function local(useAuiState) { return useAssistantState(); }`);
231
+ expect(output).toContain("useAuiState as useAssistantState");
232
+ expect(output).toContain(
233
+ "function local(useAuiState) { return useAssistantState(); }",
234
+ );
235
+ });
236
+
237
+ it("preserves a shadowed JSX component and JSX property names", () => {
238
+ const output =
239
+ applyTransform(`import { AssistantIf } from "@assistant-ui/react";
240
+ const view = <AssistantIf AssistantIf="attribute" />;
241
+ function local(AssistantIf) { return <AssistantIf />; }
242
+ const other = <components.AssistantIf />;`);
243
+ expect(output).toContain('<AuiIf AssistantIf="attribute" />');
244
+ expect(output).toContain(
245
+ "function local(AssistantIf) { return <AssistantIf />; }",
246
+ );
247
+ expect(output).toContain("<components.AssistantIf />");
248
+ });
249
+
250
+ it("preserves local names for type-only imports", () => {
251
+ const output =
252
+ applyTransform(`import type { AssistantProvider } from "@assistant-ui/react";
253
+ type Provider = typeof AssistantProvider;`);
254
+ expect(output).toContain("AuiProvider as AssistantProvider");
255
+ expect(output).toContain("typeof AssistantProvider");
256
+ });
257
+ it("does not rename references to a hoisted body variable", () => {
258
+ const input = `import { useAssistantApi } from "@assistant-ui/react";
259
+ const api = useAssistantApi();
260
+ function worker() { if (ready) { var api = other(); } return api.value; }
261
+ api.thread();`;
262
+ const output = applyTransform(input);
263
+ expect(output).toContain(
264
+ "if (ready) { var api = other(); } return api.value;",
265
+ );
266
+ expect(output).toContain("aui.thread();");
267
+ });
268
+
269
+ it("resolves switch discriminants and parameter defaults outside body bindings", () => {
270
+ const output =
271
+ applyTransform(`import { useAssistantApi } from "@assistant-ui/react";
272
+ const api = useAssistantApi();
273
+ function worker(value = api.thread()) { var api = other(); return api.value; }
274
+ switch (api.kind) { case 1: const api = other(); api.thread(); }`);
275
+ expect(output).toContain("value = aui.thread()");
276
+ expect(output).toContain("switch (aui.kind)");
277
+ expect(output).toContain("var api = other(); return api.value;");
278
+ expect(output).toContain("const api = other(); api.thread();");
279
+ });
24
280
  it("should rename useAssistantApi to useAui", () => {
25
281
  const input = `
26
282
  import { useAssistantApi } from "@assistant-ui/react";