assistant-ui 0.0.115 → 0.0.116

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,7 @@
1
1
  import { SpawnExitError, SpawnSignalError, runSpawn } from "./run-spawn.js";
2
2
  import { logger } from "./utils/logger.js";
3
3
  import { readProjectFiles } from "./utils/file-scanner.js";
4
+ import { detectRegistryPlatform, resolveRegistryItemUrl } from "./utils/registry.js";
4
5
  import * as fs$1 from "node:fs";
5
6
  import * as path$1 from "node:path";
6
7
  import { downloadTemplate } from "giget";
@@ -97,25 +98,21 @@ async function transformProject(projectDir, opts) {
97
98
  logger.step("Transforming project files...");
98
99
  transformTsConfig(projectDir);
99
100
  transformCssFiles(projectDir);
100
- let assistantUI;
101
- let shadcnUI;
102
- if (!opts.hasLocalComponents) {
103
- const components = scanRequiredComponents(projectDir);
104
- assistantUI = components.assistantUI;
105
- shadcnUI = components.shadcnUI;
106
- }
101
+ const components = opts.hasLocalComponents ? void 0 : resolveRegistryComponents(projectDir, scanRequiredComponents(projectDir));
107
102
  const pm = opts.packageManager;
108
- if (!opts.skipInstall) {
109
- logger.step("Installing dependencies...");
110
- await installDependencies(projectDir, pm);
103
+ if (opts.skipInstall) {
104
+ if (!components) return {};
105
+ const [cmd, dlxArgs] = dlxCommand(pm);
106
+ return { registryInstallCommand: `${cmd} ${[
107
+ ...dlxArgs,
108
+ "shadcn@latest",
109
+ "add",
110
+ ...components
111
+ ].join(" ")}` };
111
112
  }
112
- if (!opts.skipInstall && !opts.hasLocalComponents && shadcnUI && assistantUI) {
113
- const auiComponents = assistantUI.map((c) => `@assistant-ui/${c}`);
114
- const components = [
115
- "@assistant-ui/utils",
116
- ...shadcnUI,
117
- ...auiComponents
118
- ];
113
+ logger.step("Installing dependencies...");
114
+ await installDependencies(projectDir, pm);
115
+ if (components) {
119
116
  logger.step(`Installing components: ${components.join(", ")}...`);
120
117
  const failure = await installShadcnRegistry(projectDir, components, "components", pm);
121
118
  if (failure) return { registryInstallFailure: failure };
@@ -123,6 +120,18 @@ async function transformProject(projectDir, opts) {
123
120
  }
124
121
  return {};
125
122
  }
123
+ function resolveRegistryComponents(projectDir, { assistantUI, shadcnUI }) {
124
+ if (detectRegistryPlatform(projectDir) === "native") return [
125
+ "utils",
126
+ ...shadcnUI,
127
+ ...assistantUI
128
+ ].map((component) => resolveRegistryItemUrl(component, void 0, "native"));
129
+ return [
130
+ "@assistant-ui/utils",
131
+ ...shadcnUI,
132
+ ...assistantUI.map((component) => `@assistant-ui/${component}`)
133
+ ];
134
+ }
126
135
  function transformPackageJson(projectDir) {
127
136
  const pkgPath = path$1.join(projectDir, "package.json");
128
137
  const pkg = JSON.parse(fs$1.readFileSync(pkgPath, "utf-8"));
@@ -360,6 +369,6 @@ async function installShadcnRegistry(projectDir, components, label, pm) {
360
369
  }
361
370
  }
362
371
  //#endregion
363
- export { dlxCommand, downloadProject, reconcileAssistantUIImportLayout, resolveLatestReleaseRef, resolvePackageManager, scaffoldProject, transformProject };
372
+ export { dlxCommand, downloadProject, reconcileAssistantUIImportLayout, resolveLatestReleaseRef, resolvePackageManager, scaffoldProject, scanRequiredComponents, transformProject };
364
373
 
365
374
  //# sourceMappingURL=create-project.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"create-project.js","names":["path","fs","parseJsonc"],"sources":["../../src/lib/create-project.ts"],"sourcesContent":["import * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport { downloadTemplate } from \"giget\";\nimport {\n parse as parseJsonc,\n printParseErrorCode,\n type ParseError,\n} from \"jsonc-parser\";\nimport { logger } from \"./utils/logger\";\nimport { runSpawn, SpawnExitError, SpawnSignalError } from \"./run-spawn\";\nimport { type PackageManagerName } from \"./utils/package-manager\";\nimport { readProjectFiles } from \"./utils/file-scanner\";\n\nexport function dlxCommand(pm: PackageManagerName): [string, string[]] {\n switch (pm) {\n case \"pnpm\":\n return [\"pnpm\", [\"dlx\"]];\n case \"yarn\":\n return [\"yarn\", [\"dlx\"]];\n case \"bun\":\n return [\"bunx\", []];\n case \"npm\":\n return [\"npx\", [\"--yes\"]];\n }\n}\n\nexport interface TransformOptions {\n hasLocalComponents: boolean;\n skipInstall?: boolean;\n packageManager: PackageManagerName;\n}\n\nexport type ProjectSource =\n | {\n kind: \"github\";\n ref: string | undefined;\n }\n | {\n kind: \"local\";\n rootDir: string;\n };\n\nconst LOCAL_PROJECT_ARTIFACT_DIRS: readonly string[] = [\n \"node_modules\",\n \".next\",\n \"dist\",\n \"build\",\n];\n\nconst LOCAL_PROJECT_ARTIFACT_GLOB_IGNORES = LOCAL_PROJECT_ARTIFACT_DIRS.map(\n (dir) => `**/${dir}/**`,\n);\n\nexport function resolvePackageManager(opts: {\n useNpm?: boolean;\n usePnpm?: boolean;\n useYarn?: boolean;\n useBun?: boolean;\n}): PackageManagerName | undefined {\n if (opts.useNpm) return \"npm\";\n if (opts.usePnpm) return \"pnpm\";\n if (opts.useYarn) return \"yarn\";\n if (opts.useBun) return \"bun\";\n return undefined;\n}\n\nfunction resolveGitHubAuthToken(): string | undefined {\n const token =\n process.env.GIGET_AUTH ?? process.env.GITHUB_TOKEN ?? process.env.GH_TOKEN;\n const trimmed = token?.trim();\n return trimmed || undefined;\n}\n\nfunction toBearerAuthHeader(token: string): string {\n return token.toLowerCase().startsWith(\"bearer \") ? token : `Bearer ${token}`;\n}\n\nexport async function resolveLatestReleaseRef(): Promise<string | undefined> {\n try {\n const authToken = resolveGitHubAuthToken();\n const res = await fetch(\n \"https://api.github.com/repos/assistant-ui/assistant-ui/releases/latest\",\n authToken\n ? { headers: { Authorization: toBearerAuthHeader(authToken) } }\n : undefined,\n );\n if (!res.ok) return undefined;\n const release = (await res.json()) as { tag_name: string };\n return release.tag_name || undefined;\n } catch {\n return undefined;\n }\n}\n\nconst DOWNLOAD_TIMEOUT_MS = 30_000;\n\nexport async function downloadProject(\n repoPath: string,\n destDir: string,\n ref?: string,\n): Promise<void> {\n const source = ref\n ? `gh:assistant-ui/assistant-ui/${repoPath}#${ref}`\n : `gh:assistant-ui/assistant-ui/${repoPath}`;\n\n // Suppress giget's debug output. The `debug` package (used by the upgrade\n // command) sets process.env.DEBUG at module-load time, and giget logs to\n // console.debug whenever that env var is truthy — even for unrelated\n // namespaces. Temporarily unsetting it targets the root cause.\n const origDebug = process.env.DEBUG;\n delete process.env.DEBUG;\n try {\n const authToken = resolveGitHubAuthToken();\n const downloadPromise = downloadTemplate(source, {\n dir: destDir,\n force: true,\n silent: true,\n ...(authToken ? { auth: authToken } : {}),\n });\n\n let timer: ReturnType<typeof setTimeout>;\n const timeoutPromise = new Promise<never>((_, reject) => {\n timer = setTimeout(\n () =>\n reject(\n new Error(\n \"Download timed out. This may be due to GitHub rate limiting or a network issue. Try again in a few minutes.\",\n ),\n ),\n DOWNLOAD_TIMEOUT_MS,\n );\n });\n\n try {\n await Promise.race([downloadPromise, timeoutPromise]);\n } finally {\n clearTimeout(timer!);\n }\n } finally {\n if (origDebug !== undefined) {\n process.env.DEBUG = origDebug;\n }\n }\n}\n\nfunction shouldCopyLocalProjectPath(src: string, projectDir: string): boolean {\n const relative = path.relative(projectDir, src);\n if (!relative) return true;\n\n const segments = relative.split(path.sep);\n return !segments.some((segment) =>\n LOCAL_PROJECT_ARTIFACT_DIRS.includes(segment),\n );\n}\n\nexport async function scaffoldProject(\n repoPath: string,\n destDir: string,\n source: ProjectSource,\n): Promise<void> {\n if (source.kind === \"github\") {\n await downloadProject(repoPath, destDir, source.ref);\n return;\n }\n\n const localProjectDir = path.resolve(source.rootDir, repoPath);\n try {\n fs.cpSync(localProjectDir, destDir, {\n recursive: true,\n force: true,\n filter: (src) => shouldCopyLocalProjectPath(src, localProjectDir),\n });\n } catch (error) {\n const code =\n error instanceof Error\n ? (error as NodeJS.ErrnoException).code\n : undefined;\n if (code === \"ENOENT\") {\n throw new Error(\n `Local project source does not exist: ${localProjectDir}`,\n );\n }\n throw error;\n }\n}\n\nexport interface TransformResult {\n registryInstallFailure?: { retryCommand: string };\n}\n\nexport async function transformProject(\n projectDir: string,\n opts: TransformOptions,\n): Promise<TransformResult> {\n logger.step(\"Transforming package.json...\");\n transformPackageJson(projectDir);\n\n logger.step(\"Transforming project files...\");\n transformTsConfig(projectDir);\n transformCssFiles(projectDir);\n\n let assistantUI: string[] | undefined;\n let shadcnUI: string[] | undefined;\n\n if (!opts.hasLocalComponents) {\n const components = scanRequiredComponents(projectDir);\n assistantUI = components.assistantUI;\n shadcnUI = components.shadcnUI;\n }\n\n const pm = opts.packageManager;\n if (!opts.skipInstall) {\n logger.step(\"Installing dependencies...\");\n await installDependencies(projectDir, pm);\n }\n\n if (\n !opts.skipInstall &&\n !opts.hasLocalComponents &&\n shadcnUI &&\n assistantUI\n ) {\n const auiComponents = assistantUI.map((c) => `@assistant-ui/${c}`);\n const components = [\"@assistant-ui/utils\", ...shadcnUI, ...auiComponents];\n logger.step(`Installing components: ${components.join(\", \")}...`);\n const failure = await installShadcnRegistry(\n projectDir,\n components,\n \"components\",\n pm,\n );\n if (failure) return { registryInstallFailure: failure };\n await reconcileAssistantUIImportLayout(projectDir);\n }\n return {};\n}\n\nfunction transformPackageJson(projectDir: string): void {\n const pkgPath = path.join(projectDir, \"package.json\");\n const pkg = JSON.parse(fs.readFileSync(pkgPath, \"utf-8\"));\n\n // Remove @assistant-ui/ui dependency\n if (pkg.dependencies?.[\"@assistant-ui/ui\"]) {\n delete pkg.dependencies[\"@assistant-ui/ui\"];\n }\n\n // Transform workspace dependencies to latest\n for (const depType of [\"dependencies\", \"devDependencies\"] as const) {\n const deps = pkg[depType];\n if (!deps) continue;\n\n for (const [name, version] of Object.entries(deps)) {\n if (String(version).includes(\"workspace:\")) {\n deps[name] = \"latest\";\n }\n }\n }\n\n // Remove devDependencies that are workspace-only\n if (pkg.devDependencies?.[\"@assistant-ui/x-buildutils\"]) {\n delete pkg.devDependencies[\"@assistant-ui/x-buildutils\"];\n }\n\n // Update package name to be unique\n const dirName = path.basename(projectDir);\n pkg.name = dirName;\n\n fs.writeFileSync(pkgPath, `${JSON.stringify(pkg, null, 2)}\\n`);\n}\n\nfunction parseTsConfig(content: string): any {\n const errors: ParseError[] = [];\n const tsconfig = parseJsonc(content, errors, { allowTrailingComma: true });\n const error = errors[0];\n if (error) {\n throw new SyntaxError(\n `Invalid tsconfig.json: ${printParseErrorCode(error.error)} at offset ${error.offset}`,\n );\n }\n return tsconfig;\n}\n\nfunction transformTsConfig(projectDir: string): void {\n const tsconfigPath = path.join(projectDir, \"tsconfig.json\");\n\n if (!fs.existsSync(tsconfigPath)) {\n return;\n }\n\n const content = fs.readFileSync(tsconfigPath, \"utf-8\");\n const tsconfig = parseTsConfig(content);\n\n // Remove workspace paths\n if (tsconfig.compilerOptions?.paths) {\n const workspaceKeys = new Set([\n \"@/components/assistant-ui/*\",\n \"@/components/icons/*\",\n \"@/components/ui/*\",\n \"@/components/ui/radix/*\",\n \"@/hooks/*\",\n \"@/lib/utils\",\n \"@assistant-ui/ui/*\",\n ]);\n for (const [key, targets] of Object.entries(\n tsconfig.compilerOptions.paths as Record<string, unknown>,\n )) {\n const targetsWorkspace =\n Array.isArray(targets) &&\n targets.some(\n (target) =>\n typeof target === \"string\" &&\n (target.includes(\"packages/ui/\") || target.startsWith(\"../\")),\n );\n if (workspaceKeys.has(key) || targetsWorkspace) {\n delete tsconfig.compilerOptions.paths[key];\n }\n }\n\n if (Object.keys(tsconfig.compilerOptions.paths).length === 0) {\n delete tsconfig.compilerOptions.paths;\n }\n }\n\n // If extends uses @assistant-ui/x-buildutils, replace with inline config\n if (tsconfig.extends?.includes(\"@assistant-ui/x-buildutils\")) {\n const isNext = tsconfig.extends.includes(\"ts/next\");\n delete tsconfig.extends;\n\n const inlinedCompilerOptions = {\n target: \"ESNext\",\n lib: [\"dom\", \"dom.iterable\", \"ES2023\"],\n skipLibCheck: true,\n strict: true,\n noEmit: true,\n esModuleInterop: true,\n module: \"ESNext\",\n moduleResolution: \"bundler\",\n resolveJsonModule: true,\n isolatedModules: true,\n jsx: \"react-jsx\",\n ...(isNext ? { plugins: [{ name: \"next\" }] } : {}),\n };\n\n tsconfig.compilerOptions = {\n ...inlinedCompilerOptions,\n ...tsconfig.compilerOptions,\n paths: {\n \"@/*\": [\"./*\"],\n ...(tsconfig.compilerOptions?.paths || {}),\n },\n };\n }\n\n fs.writeFileSync(tsconfigPath, `${JSON.stringify(tsconfig, null, 2)}\\n`);\n}\n\nfunction transformCssFiles(projectDir: string): void {\n for (const { fullPath, content } of readProjectFiles(\"**/*.css\", {\n cwd: projectDir,\n ignore: LOCAL_PROJECT_ARTIFACT_GLOB_IGNORES,\n })) {\n try {\n const newContent = content.replace(\n /@source\\s+[\"'][^\"']*packages\\/ui\\/src[^\"']*[\"'];\\s*\\n?/g,\n \"\",\n );\n\n if (newContent !== content) {\n fs.writeFileSync(fullPath, newContent);\n }\n } catch {\n continue;\n }\n }\n}\n\ninterface RequiredComponents {\n assistantUI: string[];\n shadcnUI: string[];\n}\n\nfunction stripImportExtension(component: string): string {\n return component.replace(/\\.[cm]?[tj]sx?$/, \"\");\n}\n\nconst ASSISTANT_UI_OWNED_UI = new Set([\n \"accordion\",\n \"badge\",\n \"diff-viewer\",\n \"direction\",\n \"dot-matrix\",\n \"number-roll\",\n \"select\",\n \"tabs\",\n]);\n\nconst BARE_ELEMENT_ITEMS = new Set([\n \"file\",\n \"generative-ui\",\n \"heat-graph\",\n \"image\",\n \"logos\",\n \"markdown-text\",\n \"syntax-highlighter\",\n \"tooltip-icon-button\",\n]);\n\nfunction toAssistantUIItem(specifier: string): string | null {\n let name = stripImportExtension(specifier);\n const inElements = name.startsWith(\"elements/\");\n if (inElements) {\n name = name.slice(\"elements/\".length);\n } else if (name.includes(\"/\")) {\n return null;\n }\n if (name.endsWith(\".aui\")) {\n return name.slice(0, -\".aui\".length);\n }\n return inElements && !BARE_ELEMENT_ITEMS.has(name)\n ? `elements-${name}`\n : name;\n}\n\n/**\n * Example snapshots are downloaded at a release tag while the shadcn registry\n * is live, so a snapshot may import components at the legacy flat path\n * (`@/components/assistant-ui/<name>`) after the registry has moved the file\n * to `components/assistant-ui/elements/<name>.aui.tsx`. Resolve each legacy\n * specifier against the files the registry actually installed and rewrite it\n * only when the legacy path is absent and the elements layout has it.\n */\nexport async function reconcileAssistantUIImportLayout(\n projectDir: string,\n): Promise<void> {\n const componentRoots = [\"components\", \"src/components\"]\n .map((dir) => path.join(projectDir, dir, \"assistant-ui\"))\n .filter((dir) => fs.existsSync(dir));\n if (componentRoots.length === 0) return;\n\n const resolvesAtLegacyPath = (name: string) =>\n componentRoots.some((root) =>\n [\".tsx\", \".ts\", \"/index.tsx\", \"/index.ts\"].some((suffix) =>\n fs.existsSync(path.join(root, `${name}${suffix}`)),\n ),\n );\n\n // Index the installed tree by import name so the rewrite follows whatever\n // layout the registry delivered — some items install as\n // elements/<name>.aui.tsx, others as elements/<name>.tsx, and a future\n // layout move should not require new knowledge here.\n const installedByName = new Map<string, string>();\n for (const root of componentRoots) {\n for (const { file } of readProjectFiles(\"**/*.{ts,tsx}\", { cwd: root })) {\n const normalized = file.split(path.sep).join(\"/\");\n if (!normalized.includes(\"/\")) continue;\n const specifier = normalized.replace(/\\.[cm]?[tj]sx?$/, \"\");\n const name = path.posix.basename(specifier).replace(/\\.aui$/, \"\");\n // A flat legacy import maps to the registry's `<name>` item, which is\n // the `.aui` file; a colliding bare file with the same basename belongs\n // to the distinct `elements-<name>` item, so the `.aui` variant wins.\n const existing = installedByName.get(name);\n if (\n existing === undefined ||\n (!existing.endsWith(\".aui\") && specifier.endsWith(\".aui\"))\n ) {\n installedByName.set(name, specifier);\n }\n }\n }\n if (installedByName.size === 0) return;\n\n const { default: jscodeshift } = await import(\"jscodeshift\");\n const parsers = {\n ts: jscodeshift.withParser(\"ts\"),\n tsx: jscodeshift.withParser(\"tsx\"),\n };\n\n for (const { fullPath, content } of readProjectFiles(\"**/*.{ts,tsx}\", {\n cwd: projectDir,\n ignore: LOCAL_PROJECT_ARTIFACT_GLOB_IGNORES,\n })) {\n if (!content.includes(\"@/components/assistant-ui/\")) continue;\n\n const replacements: Array<{ start: number; end: number; value: string }> =\n [];\n const collectReplacement = (source: {\n value?: unknown;\n start?: number | null;\n end?: number | null;\n }) => {\n if (\n typeof source.value !== \"string\" ||\n source.start == null ||\n source.end == null\n ) {\n return;\n }\n\n const prefix = \"@/components/assistant-ui/\";\n if (!source.value.startsWith(prefix)) return;\n const specifier = source.value.slice(prefix.length);\n if (specifier.includes(\"/\")) return;\n\n const name = stripImportExtension(specifier);\n const installed = installedByName.get(name);\n if (resolvesAtLegacyPath(name) || installed === undefined) return;\n\n const raw = content.slice(source.start, source.end);\n const quote = raw[0];\n if ((quote !== '\"' && quote !== \"'\") || raw.at(-1) !== quote) return;\n replacements.push({\n start: source.start,\n end: source.end,\n value: `${quote}@/components/assistant-ui/${installed}${quote}`,\n });\n };\n\n const j = fullPath.endsWith(\".tsx\") ? parsers.tsx : parsers.ts;\n let root;\n try {\n root = j(content);\n } catch {\n continue;\n }\n root\n .find(j.ImportDeclaration)\n .forEach(({ node }) => collectReplacement(node.source));\n root\n .find(j.ExportNamedDeclaration)\n .forEach(({ node }) => node.source && collectReplacement(node.source));\n root\n .find(j.ExportAllDeclaration)\n .forEach(({ node }) => collectReplacement(node.source));\n\n let next = content;\n for (const replacement of replacements.sort((a, b) => b.start - a.start)) {\n next =\n next.slice(0, replacement.start) +\n replacement.value +\n next.slice(replacement.end);\n }\n if (next !== content) fs.writeFileSync(fullPath, next);\n }\n}\n\nfunction scanRequiredComponents(projectDir: string): RequiredComponents {\n const assistantUIComponents = new Set<string>();\n const shadcnUIComponents = new Set<string>();\n\n for (const { content } of readProjectFiles(\"**/*.{ts,tsx}\", {\n cwd: projectDir,\n ignore: LOCAL_PROJECT_ARTIFACT_GLOB_IGNORES,\n })) {\n const assistantUIRegex =\n /from\\s+[\"']@\\/components\\/assistant-ui\\/([^\"']+)[\"']/g;\n for (const match of content.matchAll(assistantUIRegex)) {\n const item = toAssistantUIItem(match[1]!);\n if (item) assistantUIComponents.add(item);\n }\n\n const uiRegex = /from\\s+[\"']@\\/components\\/ui\\/([^\"']+)[\"']/g;\n for (const match of content.matchAll(uiRegex)) {\n const name = stripImportExtension(match[1]!);\n if (ASSISTANT_UI_OWNED_UI.has(name)) {\n assistantUIComponents.add(name);\n } else {\n shadcnUIComponents.add(name);\n }\n }\n }\n\n return {\n assistantUI: Array.from(assistantUIComponents),\n shadcnUI: Array.from(shadcnUIComponents),\n };\n}\n\nasync function installDependencies(\n projectDir: string,\n pm: PackageManagerName,\n): Promise<void> {\n const args = pm === \"yarn\" ? [] : [\"install\"];\n try {\n await runSpawn(pm, args, projectDir);\n } catch (error) {\n if (error instanceof SpawnSignalError) {\n throw error;\n }\n if (error instanceof SpawnExitError) {\n throw new Error(`${pm} install exited with code ${error.code}`);\n }\n const message = error instanceof Error ? error.message : String(error);\n throw new Error(`Failed to install dependencies: ${message}`);\n }\n}\n\nasync function installShadcnRegistry(\n projectDir: string,\n components: string[],\n label: string,\n pm: PackageManagerName,\n): Promise<{ retryCommand: string } | undefined> {\n const [cmd, dlxArgs] = dlxCommand(pm);\n // For npm, dlxArgs may already include `--yes` for npx auto-install.\n // The trailing `--yes` is for shadcn's own confirmation prompt.\n const retryArgs = [...dlxArgs, \"shadcn@latest\", \"add\", ...components];\n const addArgs = [...retryArgs, \"--yes\"];\n\n try {\n await runSpawn(cmd, addArgs, projectDir);\n return undefined;\n } catch (error) {\n if (error instanceof SpawnSignalError) {\n throw error;\n }\n if (error instanceof SpawnExitError) {\n logger.warn(`shadcn exited with code ${error.code}.`);\n return { retryCommand: `${cmd} ${retryArgs.join(\" \")}` };\n }\n\n const message = error instanceof Error ? error.message : String(error);\n throw new Error(`Failed to install ${label}: ${message}`);\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"create-project.js","names":["path","fs","parseJsonc"],"sources":["../../src/lib/create-project.ts"],"sourcesContent":["import * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport { downloadTemplate } from \"giget\";\nimport {\n parse as parseJsonc,\n printParseErrorCode,\n type ParseError,\n} from \"jsonc-parser\";\nimport { logger } from \"./utils/logger\";\nimport { runSpawn, SpawnExitError, SpawnSignalError } from \"./run-spawn\";\nimport { type PackageManagerName } from \"./utils/package-manager\";\nimport { readProjectFiles } from \"./utils/file-scanner\";\nimport {\n detectRegistryPlatform,\n resolveRegistryItemUrl,\n} from \"./utils/registry\";\n\nexport function dlxCommand(pm: PackageManagerName): [string, string[]] {\n switch (pm) {\n case \"pnpm\":\n return [\"pnpm\", [\"dlx\"]];\n case \"yarn\":\n return [\"yarn\", [\"dlx\"]];\n case \"bun\":\n return [\"bunx\", []];\n case \"npm\":\n return [\"npx\", [\"--yes\"]];\n }\n}\n\nexport interface TransformOptions {\n hasLocalComponents: boolean;\n skipInstall?: boolean;\n packageManager: PackageManagerName;\n}\n\nexport type ProjectSource =\n | {\n kind: \"github\";\n ref: string | undefined;\n }\n | {\n kind: \"local\";\n rootDir: string;\n };\n\nconst LOCAL_PROJECT_ARTIFACT_DIRS: readonly string[] = [\n \"node_modules\",\n \".next\",\n \"dist\",\n \"build\",\n];\n\nconst LOCAL_PROJECT_ARTIFACT_GLOB_IGNORES = LOCAL_PROJECT_ARTIFACT_DIRS.map(\n (dir) => `**/${dir}/**`,\n);\n\nexport function resolvePackageManager(opts: {\n useNpm?: boolean;\n usePnpm?: boolean;\n useYarn?: boolean;\n useBun?: boolean;\n}): PackageManagerName | undefined {\n if (opts.useNpm) return \"npm\";\n if (opts.usePnpm) return \"pnpm\";\n if (opts.useYarn) return \"yarn\";\n if (opts.useBun) return \"bun\";\n return undefined;\n}\n\nfunction resolveGitHubAuthToken(): string | undefined {\n const token =\n process.env.GIGET_AUTH ?? process.env.GITHUB_TOKEN ?? process.env.GH_TOKEN;\n const trimmed = token?.trim();\n return trimmed || undefined;\n}\n\nfunction toBearerAuthHeader(token: string): string {\n return token.toLowerCase().startsWith(\"bearer \") ? token : `Bearer ${token}`;\n}\n\nexport async function resolveLatestReleaseRef(): Promise<string | undefined> {\n try {\n const authToken = resolveGitHubAuthToken();\n const res = await fetch(\n \"https://api.github.com/repos/assistant-ui/assistant-ui/releases/latest\",\n authToken\n ? { headers: { Authorization: toBearerAuthHeader(authToken) } }\n : undefined,\n );\n if (!res.ok) return undefined;\n const release = (await res.json()) as { tag_name: string };\n return release.tag_name || undefined;\n } catch {\n return undefined;\n }\n}\n\nconst DOWNLOAD_TIMEOUT_MS = 30_000;\n\nexport async function downloadProject(\n repoPath: string,\n destDir: string,\n ref?: string,\n): Promise<void> {\n const source = ref\n ? `gh:assistant-ui/assistant-ui/${repoPath}#${ref}`\n : `gh:assistant-ui/assistant-ui/${repoPath}`;\n\n // Suppress giget's debug output. The `debug` package (used by the upgrade\n // command) sets process.env.DEBUG at module-load time, and giget logs to\n // console.debug whenever that env var is truthy — even for unrelated\n // namespaces. Temporarily unsetting it targets the root cause.\n const origDebug = process.env.DEBUG;\n delete process.env.DEBUG;\n try {\n const authToken = resolveGitHubAuthToken();\n const downloadPromise = downloadTemplate(source, {\n dir: destDir,\n force: true,\n silent: true,\n ...(authToken ? { auth: authToken } : {}),\n });\n\n let timer: ReturnType<typeof setTimeout>;\n const timeoutPromise = new Promise<never>((_, reject) => {\n timer = setTimeout(\n () =>\n reject(\n new Error(\n \"Download timed out. This may be due to GitHub rate limiting or a network issue. Try again in a few minutes.\",\n ),\n ),\n DOWNLOAD_TIMEOUT_MS,\n );\n });\n\n try {\n await Promise.race([downloadPromise, timeoutPromise]);\n } finally {\n clearTimeout(timer!);\n }\n } finally {\n if (origDebug !== undefined) {\n process.env.DEBUG = origDebug;\n }\n }\n}\n\nfunction shouldCopyLocalProjectPath(src: string, projectDir: string): boolean {\n const relative = path.relative(projectDir, src);\n if (!relative) return true;\n\n const segments = relative.split(path.sep);\n return !segments.some((segment) =>\n LOCAL_PROJECT_ARTIFACT_DIRS.includes(segment),\n );\n}\n\nexport async function scaffoldProject(\n repoPath: string,\n destDir: string,\n source: ProjectSource,\n): Promise<void> {\n if (source.kind === \"github\") {\n await downloadProject(repoPath, destDir, source.ref);\n return;\n }\n\n const localProjectDir = path.resolve(source.rootDir, repoPath);\n try {\n fs.cpSync(localProjectDir, destDir, {\n recursive: true,\n force: true,\n filter: (src) => shouldCopyLocalProjectPath(src, localProjectDir),\n });\n } catch (error) {\n const code =\n error instanceof Error\n ? (error as NodeJS.ErrnoException).code\n : undefined;\n if (code === \"ENOENT\") {\n throw new Error(\n `Local project source does not exist: ${localProjectDir}`,\n );\n }\n throw error;\n }\n}\n\nexport interface TransformResult {\n registryInstallFailure?: { retryCommand: string };\n registryInstallCommand?: string;\n}\n\nexport async function transformProject(\n projectDir: string,\n opts: TransformOptions,\n): Promise<TransformResult> {\n logger.step(\"Transforming package.json...\");\n transformPackageJson(projectDir);\n\n logger.step(\"Transforming project files...\");\n transformTsConfig(projectDir);\n transformCssFiles(projectDir);\n\n const components = opts.hasLocalComponents\n ? undefined\n : resolveRegistryComponents(projectDir, scanRequiredComponents(projectDir));\n\n const pm = opts.packageManager;\n if (opts.skipInstall) {\n if (!components) return {};\n const [cmd, dlxArgs] = dlxCommand(pm);\n return {\n registryInstallCommand: `${cmd} ${[...dlxArgs, \"shadcn@latest\", \"add\", ...components].join(\" \")}`,\n };\n }\n\n logger.step(\"Installing dependencies...\");\n await installDependencies(projectDir, pm);\n\n if (components) {\n logger.step(`Installing components: ${components.join(\", \")}...`);\n const failure = await installShadcnRegistry(\n projectDir,\n components,\n \"components\",\n pm,\n );\n if (failure) return { registryInstallFailure: failure };\n await reconcileAssistantUIImportLayout(projectDir);\n }\n return {};\n}\n\nfunction resolveRegistryComponents(\n projectDir: string,\n { assistantUI, shadcnUI }: RequiredComponents,\n): string[] {\n if (detectRegistryPlatform(projectDir) === \"native\") {\n return [\"utils\", ...shadcnUI, ...assistantUI].map((component) =>\n resolveRegistryItemUrl(component, undefined, \"native\"),\n );\n }\n return [\n \"@assistant-ui/utils\",\n ...shadcnUI,\n ...assistantUI.map((component) => `@assistant-ui/${component}`),\n ];\n}\n\nfunction transformPackageJson(projectDir: string): void {\n const pkgPath = path.join(projectDir, \"package.json\");\n const pkg = JSON.parse(fs.readFileSync(pkgPath, \"utf-8\"));\n\n // Remove @assistant-ui/ui dependency\n if (pkg.dependencies?.[\"@assistant-ui/ui\"]) {\n delete pkg.dependencies[\"@assistant-ui/ui\"];\n }\n\n // Transform workspace dependencies to latest\n for (const depType of [\"dependencies\", \"devDependencies\"] as const) {\n const deps = pkg[depType];\n if (!deps) continue;\n\n for (const [name, version] of Object.entries(deps)) {\n if (String(version).includes(\"workspace:\")) {\n deps[name] = \"latest\";\n }\n }\n }\n\n // Remove devDependencies that are workspace-only\n if (pkg.devDependencies?.[\"@assistant-ui/x-buildutils\"]) {\n delete pkg.devDependencies[\"@assistant-ui/x-buildutils\"];\n }\n\n // Update package name to be unique\n const dirName = path.basename(projectDir);\n pkg.name = dirName;\n\n fs.writeFileSync(pkgPath, `${JSON.stringify(pkg, null, 2)}\\n`);\n}\n\nfunction parseTsConfig(content: string): any {\n const errors: ParseError[] = [];\n const tsconfig = parseJsonc(content, errors, { allowTrailingComma: true });\n const error = errors[0];\n if (error) {\n throw new SyntaxError(\n `Invalid tsconfig.json: ${printParseErrorCode(error.error)} at offset ${error.offset}`,\n );\n }\n return tsconfig;\n}\n\nfunction transformTsConfig(projectDir: string): void {\n const tsconfigPath = path.join(projectDir, \"tsconfig.json\");\n\n if (!fs.existsSync(tsconfigPath)) {\n return;\n }\n\n const content = fs.readFileSync(tsconfigPath, \"utf-8\");\n const tsconfig = parseTsConfig(content);\n\n // Remove workspace paths\n if (tsconfig.compilerOptions?.paths) {\n const workspaceKeys = new Set([\n \"@/components/assistant-ui/*\",\n \"@/components/icons/*\",\n \"@/components/ui/*\",\n \"@/components/ui/radix/*\",\n \"@/hooks/*\",\n \"@/lib/utils\",\n \"@assistant-ui/ui/*\",\n ]);\n for (const [key, targets] of Object.entries(\n tsconfig.compilerOptions.paths as Record<string, unknown>,\n )) {\n const targetsWorkspace =\n Array.isArray(targets) &&\n targets.some(\n (target) =>\n typeof target === \"string\" &&\n (target.includes(\"packages/ui/\") || target.startsWith(\"../\")),\n );\n if (workspaceKeys.has(key) || targetsWorkspace) {\n delete tsconfig.compilerOptions.paths[key];\n }\n }\n\n if (Object.keys(tsconfig.compilerOptions.paths).length === 0) {\n delete tsconfig.compilerOptions.paths;\n }\n }\n\n // If extends uses @assistant-ui/x-buildutils, replace with inline config\n if (tsconfig.extends?.includes(\"@assistant-ui/x-buildutils\")) {\n const isNext = tsconfig.extends.includes(\"ts/next\");\n delete tsconfig.extends;\n\n const inlinedCompilerOptions = {\n target: \"ESNext\",\n lib: [\"dom\", \"dom.iterable\", \"ES2023\"],\n skipLibCheck: true,\n strict: true,\n noEmit: true,\n esModuleInterop: true,\n module: \"ESNext\",\n moduleResolution: \"bundler\",\n resolveJsonModule: true,\n isolatedModules: true,\n jsx: \"react-jsx\",\n ...(isNext ? { plugins: [{ name: \"next\" }] } : {}),\n };\n\n tsconfig.compilerOptions = {\n ...inlinedCompilerOptions,\n ...tsconfig.compilerOptions,\n paths: {\n \"@/*\": [\"./*\"],\n ...(tsconfig.compilerOptions?.paths || {}),\n },\n };\n }\n\n fs.writeFileSync(tsconfigPath, `${JSON.stringify(tsconfig, null, 2)}\\n`);\n}\n\nfunction transformCssFiles(projectDir: string): void {\n for (const { fullPath, content } of readProjectFiles(\"**/*.css\", {\n cwd: projectDir,\n ignore: LOCAL_PROJECT_ARTIFACT_GLOB_IGNORES,\n })) {\n try {\n const newContent = content.replace(\n /@source\\s+[\"'][^\"']*packages\\/ui\\/src[^\"']*[\"'];\\s*\\n?/g,\n \"\",\n );\n\n if (newContent !== content) {\n fs.writeFileSync(fullPath, newContent);\n }\n } catch {\n continue;\n }\n }\n}\n\ninterface RequiredComponents {\n assistantUI: string[];\n shadcnUI: string[];\n}\n\nfunction stripImportExtension(component: string): string {\n return component.replace(/\\.[cm]?[tj]sx?$/, \"\");\n}\n\nconst ASSISTANT_UI_OWNED_UI = new Set([\n \"accordion\",\n \"badge\",\n \"diff-viewer\",\n \"direction\",\n \"dot-matrix\",\n \"number-roll\",\n \"select\",\n \"tabs\",\n]);\n\nconst BARE_ELEMENT_ITEMS = new Set([\n \"file\",\n \"generative-ui\",\n \"heat-graph\",\n \"image\",\n \"logos\",\n \"markdown-text\",\n \"syntax-highlighter\",\n \"tooltip-icon-button\",\n]);\n\nfunction toAssistantUIItem(specifier: string): string | null {\n let name = stripImportExtension(specifier);\n const inElements = name.startsWith(\"elements/\");\n if (inElements) {\n name = name.slice(\"elements/\".length);\n } else if (name.includes(\"/\")) {\n return null;\n }\n if (name.endsWith(\".aui\")) {\n return name.slice(0, -\".aui\".length);\n }\n return inElements && !BARE_ELEMENT_ITEMS.has(name)\n ? `elements-${name}`\n : name;\n}\n\n/**\n * Example snapshots are downloaded at a release tag while the shadcn registry\n * is live, so a snapshot may import components at the legacy flat path\n * (`@/components/assistant-ui/<name>`) after the registry has moved the file\n * to `components/assistant-ui/elements/<name>.aui.tsx`. Resolve each legacy\n * specifier against the files the registry actually installed and rewrite it\n * only when the legacy path is absent and the elements layout has it.\n */\nexport async function reconcileAssistantUIImportLayout(\n projectDir: string,\n): Promise<void> {\n const componentRoots = [\"components\", \"src/components\"]\n .map((dir) => path.join(projectDir, dir, \"assistant-ui\"))\n .filter((dir) => fs.existsSync(dir));\n if (componentRoots.length === 0) return;\n\n const resolvesAtLegacyPath = (name: string) =>\n componentRoots.some((root) =>\n [\".tsx\", \".ts\", \"/index.tsx\", \"/index.ts\"].some((suffix) =>\n fs.existsSync(path.join(root, `${name}${suffix}`)),\n ),\n );\n\n // Index the installed tree by import name so the rewrite follows whatever\n // layout the registry delivered — some items install as\n // elements/<name>.aui.tsx, others as elements/<name>.tsx, and a future\n // layout move should not require new knowledge here.\n const installedByName = new Map<string, string>();\n for (const root of componentRoots) {\n for (const { file } of readProjectFiles(\"**/*.{ts,tsx}\", { cwd: root })) {\n const normalized = file.split(path.sep).join(\"/\");\n if (!normalized.includes(\"/\")) continue;\n const specifier = normalized.replace(/\\.[cm]?[tj]sx?$/, \"\");\n const name = path.posix.basename(specifier).replace(/\\.aui$/, \"\");\n // A flat legacy import maps to the registry's `<name>` item, which is\n // the `.aui` file; a colliding bare file with the same basename belongs\n // to the distinct `elements-<name>` item, so the `.aui` variant wins.\n const existing = installedByName.get(name);\n if (\n existing === undefined ||\n (!existing.endsWith(\".aui\") && specifier.endsWith(\".aui\"))\n ) {\n installedByName.set(name, specifier);\n }\n }\n }\n if (installedByName.size === 0) return;\n\n const { default: jscodeshift } = await import(\"jscodeshift\");\n const parsers = {\n ts: jscodeshift.withParser(\"ts\"),\n tsx: jscodeshift.withParser(\"tsx\"),\n };\n\n for (const { fullPath, content } of readProjectFiles(\"**/*.{ts,tsx}\", {\n cwd: projectDir,\n ignore: LOCAL_PROJECT_ARTIFACT_GLOB_IGNORES,\n })) {\n if (!content.includes(\"@/components/assistant-ui/\")) continue;\n\n const replacements: Array<{ start: number; end: number; value: string }> =\n [];\n const collectReplacement = (source: {\n value?: unknown;\n start?: number | null;\n end?: number | null;\n }) => {\n if (\n typeof source.value !== \"string\" ||\n source.start == null ||\n source.end == null\n ) {\n return;\n }\n\n const prefix = \"@/components/assistant-ui/\";\n if (!source.value.startsWith(prefix)) return;\n const specifier = source.value.slice(prefix.length);\n if (specifier.includes(\"/\")) return;\n\n const name = stripImportExtension(specifier);\n const installed = installedByName.get(name);\n if (resolvesAtLegacyPath(name) || installed === undefined) return;\n\n const raw = content.slice(source.start, source.end);\n const quote = raw[0];\n if ((quote !== '\"' && quote !== \"'\") || raw.at(-1) !== quote) return;\n replacements.push({\n start: source.start,\n end: source.end,\n value: `${quote}@/components/assistant-ui/${installed}${quote}`,\n });\n };\n\n const j = fullPath.endsWith(\".tsx\") ? parsers.tsx : parsers.ts;\n let root;\n try {\n root = j(content);\n } catch {\n continue;\n }\n root\n .find(j.ImportDeclaration)\n .forEach(({ node }) => collectReplacement(node.source));\n root\n .find(j.ExportNamedDeclaration)\n .forEach(({ node }) => node.source && collectReplacement(node.source));\n root\n .find(j.ExportAllDeclaration)\n .forEach(({ node }) => collectReplacement(node.source));\n\n let next = content;\n for (const replacement of replacements.sort((a, b) => b.start - a.start)) {\n next =\n next.slice(0, replacement.start) +\n replacement.value +\n next.slice(replacement.end);\n }\n if (next !== content) fs.writeFileSync(fullPath, next);\n }\n}\n\nexport function scanRequiredComponents(projectDir: string): RequiredComponents {\n const assistantUIComponents = new Set<string>();\n const shadcnUIComponents = new Set<string>();\n\n for (const { content } of readProjectFiles(\"**/*.{ts,tsx}\", {\n cwd: projectDir,\n ignore: LOCAL_PROJECT_ARTIFACT_GLOB_IGNORES,\n })) {\n const assistantUIRegex =\n /from\\s+[\"']@\\/components\\/assistant-ui\\/([^\"']+)[\"']/g;\n for (const match of content.matchAll(assistantUIRegex)) {\n const item = toAssistantUIItem(match[1]!);\n if (item) assistantUIComponents.add(item);\n }\n\n const uiRegex = /from\\s+[\"']@\\/components\\/ui\\/([^\"']+)[\"']/g;\n for (const match of content.matchAll(uiRegex)) {\n const name = stripImportExtension(match[1]!);\n if (ASSISTANT_UI_OWNED_UI.has(name)) {\n assistantUIComponents.add(name);\n } else {\n shadcnUIComponents.add(name);\n }\n }\n }\n\n return {\n assistantUI: Array.from(assistantUIComponents),\n shadcnUI: Array.from(shadcnUIComponents),\n };\n}\n\nasync function installDependencies(\n projectDir: string,\n pm: PackageManagerName,\n): Promise<void> {\n const args = pm === \"yarn\" ? [] : [\"install\"];\n try {\n await runSpawn(pm, args, projectDir);\n } catch (error) {\n if (error instanceof SpawnSignalError) {\n throw error;\n }\n if (error instanceof SpawnExitError) {\n throw new Error(`${pm} install exited with code ${error.code}`);\n }\n const message = error instanceof Error ? error.message : String(error);\n throw new Error(`Failed to install dependencies: ${message}`);\n }\n}\n\nasync function installShadcnRegistry(\n projectDir: string,\n components: string[],\n label: string,\n pm: PackageManagerName,\n): Promise<{ retryCommand: string } | undefined> {\n const [cmd, dlxArgs] = dlxCommand(pm);\n // For npm, dlxArgs may already include `--yes` for npx auto-install.\n // The trailing `--yes` is for shadcn's own confirmation prompt.\n const retryArgs = [...dlxArgs, \"shadcn@latest\", \"add\", ...components];\n const addArgs = [...retryArgs, \"--yes\"];\n\n try {\n await runSpawn(cmd, addArgs, projectDir);\n return undefined;\n } catch (error) {\n if (error instanceof SpawnSignalError) {\n throw error;\n }\n if (error instanceof SpawnExitError) {\n logger.warn(`shadcn exited with code ${error.code}.`);\n return { retryCommand: `${cmd} ${retryArgs.join(\" \")}` };\n }\n\n const message = error instanceof Error ? error.message : String(error);\n throw new Error(`Failed to install ${label}: ${message}`);\n }\n}\n"],"mappings":";;;;;;;;;AAiBA,SAAgB,WAAW,IAA4C;CACrE,QAAQ,IAAR;EACE,KAAK,QACH,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC;EACzB,KAAK,QACH,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC;EACzB,KAAK,OACH,OAAO,CAAC,QAAQ,CAAC,CAAC;EACpB,KAAK,OACH,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC;CAC5B;AACF;AAkBA,MAAM,8BAAiD;CACrD;CACA;CACA;CACA;AACF;AAEA,MAAM,sCAAsC,4BAA4B,KACrE,QAAQ,MAAM,IAAI,IACrB;AAEA,SAAgB,sBAAsB,MAKH;CACjC,IAAI,KAAK,QAAQ,OAAO;CACxB,IAAI,KAAK,SAAS,OAAO;CACzB,IAAI,KAAK,SAAS,OAAO;CACzB,IAAI,KAAK,QAAQ,OAAO;AAE1B;AAEA,SAAS,yBAA6C;CAIpD,QAFE,QAAQ,IAAI,cAAc,QAAQ,IAAI,gBAAgB,QAAQ,IAAI,SAAA,EAC7C,KAAK,KACV,KAAA;AACpB;AAEA,SAAS,mBAAmB,OAAuB;CACjD,OAAO,MAAM,YAAY,CAAC,CAAC,WAAW,SAAS,IAAI,QAAQ,UAAU;AACvE;AAEA,eAAsB,0BAAuD;CAC3E,IAAI;EACF,MAAM,YAAY,uBAAuB;EACzC,MAAM,MAAM,MAAM,MAChB,0EACA,YACI,EAAE,SAAS,EAAE,eAAe,mBAAmB,SAAS,EAAE,EAAE,IAC5D,KAAA,CACN;EACA,IAAI,CAAC,IAAI,IAAI,OAAO,KAAA;EAEpB,QAAO,MADgB,IAAI,KAAK,EAAA,CACjB,YAAY,KAAA;CAC7B,QAAQ;EACN;CACF;AACF;AAEA,MAAM,sBAAsB;AAE5B,eAAsB,gBACpB,UACA,SACA,KACe;CACf,MAAM,SAAS,MACX,gCAAgC,SAAS,GAAG,QAC5C,gCAAgC;CAMpC,MAAM,YAAY,QAAQ,IAAI;CAC9B,OAAO,QAAQ,IAAI;CACnB,IAAI;EACF,MAAM,YAAY,uBAAuB;EACzC,MAAM,kBAAkB,iBAAiB,QAAQ;GAC/C,KAAK;GACL,OAAO;GACP,QAAQ;GACR,GAAI,YAAY,EAAE,MAAM,UAAU,IAAI,CAAC;EACzC,CAAC;EAED,IAAI;EACJ,MAAM,iBAAiB,IAAI,SAAgB,GAAG,WAAW;GACvD,QAAQ,iBAEJ,uBACE,IAAI,MACF,6GACF,CACF,GACF,mBACF;EACF,CAAC;EAED,IAAI;GACF,MAAM,QAAQ,KAAK,CAAC,iBAAiB,cAAc,CAAC;EACtD,UAAU;GACR,aAAa,KAAM;EACrB;CACF,UAAU;EACR,IAAI,cAAc,KAAA,GAChB,QAAQ,IAAI,QAAQ;CAExB;AACF;AAEA,SAAS,2BAA2B,KAAa,YAA6B;CAC5E,MAAM,WAAWA,OAAK,SAAS,YAAY,GAAG;CAC9C,IAAI,CAAC,UAAU,OAAO;CAGtB,OAAO,CADU,SAAS,MAAMA,OAAK,GACtB,CAAC,CAAC,MAAM,YACrB,4BAA4B,SAAS,OAAO,CAC9C;AACF;AAEA,eAAsB,gBACpB,UACA,SACA,QACe;CACf,IAAI,OAAO,SAAS,UAAU;EAC5B,MAAM,gBAAgB,UAAU,SAAS,OAAO,GAAG;EACnD;CACF;CAEA,MAAM,kBAAkBA,OAAK,QAAQ,OAAO,SAAS,QAAQ;CAC7D,IAAI;EACF,KAAG,OAAO,iBAAiB,SAAS;GAClC,WAAW;GACX,OAAO;GACP,SAAS,QAAQ,2BAA2B,KAAK,eAAe;EAClE,CAAC;CACH,SAAS,OAAO;EAKd,KAHE,iBAAiB,QACZ,MAAgC,OACjC,KAAA,OACO,UACX,MAAM,IAAI,MACR,wCAAwC,iBAC1C;EAEF,MAAM;CACR;AACF;AAOA,eAAsB,iBACpB,YACA,MAC0B;CAC1B,OAAO,KAAK,8BAA8B;CAC1C,qBAAqB,UAAU;CAE/B,OAAO,KAAK,+BAA+B;CAC3C,kBAAkB,UAAU;CAC5B,kBAAkB,UAAU;CAE5B,MAAM,aAAa,KAAK,qBACpB,KAAA,IACA,0BAA0B,YAAY,uBAAuB,UAAU,CAAC;CAE5E,MAAM,KAAK,KAAK;CAChB,IAAI,KAAK,aAAa;EACpB,IAAI,CAAC,YAAY,OAAO,CAAC;EACzB,MAAM,CAAC,KAAK,WAAW,WAAW,EAAE;EACpC,OAAO,EACL,wBAAwB,GAAG,IAAI,GAAG;GAAC,GAAG;GAAS;GAAiB;GAAO,GAAG;EAAU,CAAC,CAAC,KAAK,GAAG,IAChG;CACF;CAEA,OAAO,KAAK,4BAA4B;CACxC,MAAM,oBAAoB,YAAY,EAAE;CAExC,IAAI,YAAY;EACd,OAAO,KAAK,0BAA0B,WAAW,KAAK,IAAI,EAAE,IAAI;EAChE,MAAM,UAAU,MAAM,sBACpB,YACA,YACA,cACA,EACF;EACA,IAAI,SAAS,OAAO,EAAE,wBAAwB,QAAQ;EACtD,MAAM,iCAAiC,UAAU;CACnD;CACA,OAAO,CAAC;AACV;AAEA,SAAS,0BACP,YACA,EAAE,aAAa,YACL;CACV,IAAI,uBAAuB,UAAU,MAAM,UACzC,OAAO;EAAC;EAAS,GAAG;EAAU,GAAG;CAAW,CAAC,CAAC,KAAK,cACjD,uBAAuB,WAAW,KAAA,GAAW,QAAQ,CACvD;CAEF,OAAO;EACL;EACA,GAAG;EACH,GAAG,YAAY,KAAK,cAAc,iBAAiB,WAAW;CAChE;AACF;AAEA,SAAS,qBAAqB,YAA0B;CACtD,MAAM,UAAUA,OAAK,KAAK,YAAY,cAAc;CACpD,MAAM,MAAM,KAAK,MAAMC,KAAG,aAAa,SAAS,OAAO,CAAC;CAGxD,IAAI,IAAI,eAAe,qBACrB,OAAO,IAAI,aAAa;CAI1B,KAAK,MAAM,WAAW,CAAC,gBAAgB,iBAAiB,GAAY;EAClE,MAAM,OAAO,IAAI;EACjB,IAAI,CAAC,MAAM;EAEX,KAAK,MAAM,CAAC,MAAM,YAAY,OAAO,QAAQ,IAAI,GAC/C,IAAI,OAAO,OAAO,CAAC,CAAC,SAAS,YAAY,GACvC,KAAK,QAAQ;CAGnB;CAGA,IAAI,IAAI,kBAAkB,+BACxB,OAAO,IAAI,gBAAgB;CAK7B,IAAI,OADYD,OAAK,SAAS,UACb;CAEjB,KAAG,cAAc,SAAS,GAAG,KAAK,UAAU,KAAK,MAAM,CAAC,EAAE,GAAG;AAC/D;AAEA,SAAS,cAAc,SAAsB;CAC3C,MAAM,SAAuB,CAAC;CAC9B,MAAM,WAAWE,MAAW,SAAS,QAAQ,EAAE,oBAAoB,KAAK,CAAC;CACzE,MAAM,QAAQ,OAAO;CACrB,IAAI,OACF,MAAM,IAAI,YACR,0BAA0B,oBAAoB,MAAM,KAAK,EAAE,aAAa,MAAM,QAChF;CAEF,OAAO;AACT;AAEA,SAAS,kBAAkB,YAA0B;CACnD,MAAM,eAAeF,OAAK,KAAK,YAAY,eAAe;CAE1D,IAAI,CAACC,KAAG,WAAW,YAAY,GAC7B;CAIF,MAAM,WAAW,cADDA,KAAG,aAAa,cAAc,OACT,CAAC;CAGtC,IAAI,SAAS,iBAAiB,OAAO;EACnC,MAAM,gCAAgB,IAAI,IAAI;GAC5B;GACA;GACA;GACA;GACA;GACA;GACA;EACF,CAAC;EACD,KAAK,MAAM,CAAC,KAAK,YAAY,OAAO,QAClC,SAAS,gBAAgB,KAC3B,GAAG;GACD,MAAM,mBACJ,MAAM,QAAQ,OAAO,KACrB,QAAQ,MACL,WACC,OAAO,WAAW,aACjB,OAAO,SAAS,cAAc,KAAK,OAAO,WAAW,KAAK,EAC/D;GACF,IAAI,cAAc,IAAI,GAAG,KAAK,kBAC5B,OAAO,SAAS,gBAAgB,MAAM;EAE1C;EAEA,IAAI,OAAO,KAAK,SAAS,gBAAgB,KAAK,CAAC,CAAC,WAAW,GACzD,OAAO,SAAS,gBAAgB;CAEpC;CAGA,IAAI,SAAS,SAAS,SAAS,4BAA4B,GAAG;EAC5D,MAAM,SAAS,SAAS,QAAQ,SAAS,SAAS;EAClD,OAAO,SAAS;EAiBhB,SAAS,kBAAkB;GAdzB,QAAQ;GACR,KAAK;IAAC;IAAO;IAAgB;GAAQ;GACrC,cAAc;GACd,QAAQ;GACR,QAAQ;GACR,iBAAiB;GACjB,QAAQ;GACR,kBAAkB;GAClB,mBAAmB;GACnB,iBAAiB;GACjB,KAAK;GACL,GAAI,SAAS,EAAE,SAAS,CAAC,EAAE,MAAM,OAAO,CAAC,EAAE,IAAI,CAAC;GAKhD,GAAG,SAAS;GACZ,OAAO;IACL,OAAO,CAAC,KAAK;IACb,GAAI,SAAS,iBAAiB,SAAS,CAAC;GAC1C;EACF;CACF;CAEA,KAAG,cAAc,cAAc,GAAG,KAAK,UAAU,UAAU,MAAM,CAAC,EAAE,GAAG;AACzE;AAEA,SAAS,kBAAkB,YAA0B;CACnD,KAAK,MAAM,EAAE,UAAU,aAAa,iBAAiB,YAAY;EAC/D,KAAK;EACL,QAAQ;CACV,CAAC,GACC,IAAI;EACF,MAAM,aAAa,QAAQ,QACzB,2DACA,EACF;EAEA,IAAI,eAAe,SACjB,KAAG,cAAc,UAAU,UAAU;CAEzC,QAAQ;EACN;CACF;AAEJ;AAOA,SAAS,qBAAqB,WAA2B;CACvD,OAAO,UAAU,QAAQ,mBAAmB,EAAE;AAChD;AAEA,MAAM,wCAAwB,IAAI,IAAI;CACpC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;AAED,MAAM,qCAAqB,IAAI,IAAI;CACjC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;AAED,SAAS,kBAAkB,WAAkC;CAC3D,IAAI,OAAO,qBAAqB,SAAS;CACzC,MAAM,aAAa,KAAK,WAAW,WAAW;CAC9C,IAAI,YACF,OAAO,KAAK,MAAM,CAAkB;MAC/B,IAAI,KAAK,SAAS,GAAG,GAC1B,OAAO;CAET,IAAI,KAAK,SAAS,MAAM,GACtB,OAAO,KAAK,MAAM,GAAG,EAAc;CAErC,OAAO,cAAc,CAAC,mBAAmB,IAAI,IAAI,IAC7C,YAAY,SACZ;AACN;;;;;;;;;AAUA,eAAsB,iCACpB,YACe;CACf,MAAM,iBAAiB,CAAC,cAAc,gBAAgB,CAAC,CACpD,KAAK,QAAQD,OAAK,KAAK,YAAY,KAAK,cAAc,CAAC,CAAC,CACxD,QAAQ,QAAQC,KAAG,WAAW,GAAG,CAAC;CACrC,IAAI,eAAe,WAAW,GAAG;CAEjC,MAAM,wBAAwB,SAC5B,eAAe,MAAM,SACnB;EAAC;EAAQ;EAAO;EAAc;CAAW,CAAC,CAAC,MAAM,WAC/CA,KAAG,WAAWD,OAAK,KAAK,MAAM,GAAG,OAAO,QAAQ,CAAC,CACnD,CACF;CAMF,MAAM,kCAAkB,IAAI,IAAoB;CAChD,KAAK,MAAM,QAAQ,gBACjB,KAAK,MAAM,EAAE,UAAU,iBAAiB,iBAAiB,EAAE,KAAK,KAAK,CAAC,GAAG;EACvE,MAAM,aAAa,KAAK,MAAMA,OAAK,GAAG,CAAC,CAAC,KAAK,GAAG;EAChD,IAAI,CAAC,WAAW,SAAS,GAAG,GAAG;EAC/B,MAAM,YAAY,WAAW,QAAQ,mBAAmB,EAAE;EAC1D,MAAM,OAAOA,OAAK,MAAM,SAAS,SAAS,CAAC,CAAC,QAAQ,UAAU,EAAE;EAIhE,MAAM,WAAW,gBAAgB,IAAI,IAAI;EACzC,IACE,aAAa,KAAA,KACZ,CAAC,SAAS,SAAS,MAAM,KAAK,UAAU,SAAS,MAAM,GAExD,gBAAgB,IAAI,MAAM,SAAS;CAEvC;CAEF,IAAI,gBAAgB,SAAS,GAAG;CAEhC,MAAM,EAAE,SAAS,gBAAgB,MAAM,OAAO;CAC9C,MAAM,UAAU;EACd,IAAI,YAAY,WAAW,IAAI;EAC/B,KAAK,YAAY,WAAW,KAAK;CACnC;CAEA,KAAK,MAAM,EAAE,UAAU,aAAa,iBAAiB,iBAAiB;EACpE,KAAK;EACL,QAAQ;CACV,CAAC,GAAG;EACF,IAAI,CAAC,QAAQ,SAAS,4BAA4B,GAAG;EAErD,MAAM,eACJ,CAAC;EACH,MAAM,sBAAsB,WAItB;GACJ,IACE,OAAO,OAAO,UAAU,YACxB,OAAO,SAAS,QAChB,OAAO,OAAO,MAEd;GAIF,IAAI,CAAC,OAAO,MAAM,WAAW,4BAAM,GAAG;GACtC,MAAM,YAAY,OAAO,MAAM,MAAM,EAAa;GAClD,IAAI,UAAU,SAAS,GAAG,GAAG;GAE7B,MAAM,OAAO,qBAAqB,SAAS;GAC3C,MAAM,YAAY,gBAAgB,IAAI,IAAI;GAC1C,IAAI,qBAAqB,IAAI,KAAK,cAAc,KAAA,GAAW;GAE3D,MAAM,MAAM,QAAQ,MAAM,OAAO,OAAO,OAAO,GAAG;GAClD,MAAM,QAAQ,IAAI;GAClB,IAAK,UAAU,QAAO,UAAU,OAAQ,IAAI,GAAG,EAAE,MAAM,OAAO;GAC9D,aAAa,KAAK;IAChB,OAAO,OAAO;IACd,KAAK,OAAO;IACZ,OAAO,GAAG,MAAM,4BAA4B,YAAY;GAC1D,CAAC;EACH;EAEA,MAAM,IAAI,SAAS,SAAS,MAAM,IAAI,QAAQ,MAAM,QAAQ;EAC5D,IAAI;EACJ,IAAI;GACF,OAAO,EAAE,OAAO;EAClB,QAAQ;GACN;EACF;EACA,KACG,KAAK,EAAE,iBAAiB,CAAC,CACzB,SAAS,EAAE,WAAW,mBAAmB,KAAK,MAAM,CAAC;EACxD,KACG,KAAK,EAAE,sBAAsB,CAAC,CAC9B,SAAS,EAAE,WAAW,KAAK,UAAU,mBAAmB,KAAK,MAAM,CAAC;EACvE,KACG,KAAK,EAAE,oBAAoB,CAAC,CAC5B,SAAS,EAAE,WAAW,mBAAmB,KAAK,MAAM,CAAC;EAExD,IAAI,OAAO;EACX,KAAK,MAAM,eAAe,aAAa,MAAM,GAAG,MAAM,EAAE,QAAQ,EAAE,KAAK,GACrE,OACE,KAAK,MAAM,GAAG,YAAY,KAAK,IAC/B,YAAY,QACZ,KAAK,MAAM,YAAY,GAAG;EAE9B,IAAI,SAAS,SAAS,KAAG,cAAc,UAAU,IAAI;CACvD;AACF;AAEA,SAAgB,uBAAuB,YAAwC;CAC7E,MAAM,wCAAwB,IAAI,IAAY;CAC9C,MAAM,qCAAqB,IAAI,IAAY;CAE3C,KAAK,MAAM,EAAE,aAAa,iBAAiB,iBAAiB;EAC1D,KAAK;EACL,QAAQ;CACV,CAAC,GAAG;EAGF,KAAK,MAAM,SAAS,QAAQ,SAAS,uDAAgB,GAAG;GACtD,MAAM,OAAO,kBAAkB,MAAM,EAAG;GACxC,IAAI,MAAM,sBAAsB,IAAI,IAAI;EAC1C;EAGA,KAAK,MAAM,SAAS,QAAQ,SAAS,6CAAO,GAAG;GAC7C,MAAM,OAAO,qBAAqB,MAAM,EAAG;GAC3C,IAAI,sBAAsB,IAAI,IAAI,GAChC,sBAAsB,IAAI,IAAI;QAE9B,mBAAmB,IAAI,IAAI;EAE/B;CACF;CAEA,OAAO;EACL,aAAa,MAAM,KAAK,qBAAqB;EAC7C,UAAU,MAAM,KAAK,kBAAkB;CACzC;AACF;AAEA,eAAe,oBACb,YACA,IACe;CACf,MAAM,OAAO,OAAO,SAAS,CAAC,IAAI,CAAC,SAAS;CAC5C,IAAI;EACF,MAAM,SAAS,IAAI,MAAM,UAAU;CACrC,SAAS,OAAO;EACd,IAAI,iBAAiB,kBACnB,MAAM;EAER,IAAI,iBAAiB,gBACnB,MAAM,IAAI,MAAM,GAAG,GAAG,4BAA4B,MAAM,MAAM;EAEhE,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;EACrE,MAAM,IAAI,MAAM,mCAAmC,SAAS;CAC9D;AACF;AAEA,eAAe,sBACb,YACA,YACA,OACA,IAC+C;CAC/C,MAAM,CAAC,KAAK,WAAW,WAAW,EAAE;CAGpC,MAAM,YAAY;EAAC,GAAG;EAAS;EAAiB;EAAO,GAAG;CAAU;CACpE,MAAM,UAAU,CAAC,GAAG,WAAW,OAAO;CAEtC,IAAI;EACF,MAAM,SAAS,KAAK,SAAS,UAAU;EACvC;CACF,SAAS,OAAO;EACd,IAAI,iBAAiB,kBACnB,MAAM;EAER,IAAI,iBAAiB,gBAAgB;GACnC,OAAO,KAAK,2BAA2B,MAAM,KAAK,EAAE;GACpD,OAAO,EAAE,cAAc,GAAG,IAAI,GAAG,UAAU,KAAK,GAAG,IAAI;EACzD;EAEA,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;EACrE,MAAM,IAAI,MAAM,qBAAqB,MAAM,IAAI,SAAS;CAC1D;AACF"}
@@ -1,7 +1,9 @@
1
1
  //#region src/lib/utils/registry.d.ts
2
+ declare const SHARED_REGISTRY_ITEMS: Set<string>;
3
+ declare function detectRegistryPlatform(cwd: string): "web" | "native";
2
4
  declare function getComponentsJsonStyle(cwd: string): string | undefined;
3
5
  declare function resolveQuickStartRegistryUrl(style?: string): string;
4
- declare function resolveRegistryItemUrl(component: string, style?: string): string;
6
+ declare function resolveRegistryItemUrl(component: string, style?: string, platform?: "web" | "native"): string;
5
7
  //#endregion
6
- export { getComponentsJsonStyle, resolveQuickStartRegistryUrl, resolveRegistryItemUrl };
8
+ export { SHARED_REGISTRY_ITEMS, detectRegistryPlatform, getComponentsJsonStyle, resolveQuickStartRegistryUrl, resolveRegistryItemUrl };
7
9
  //# sourceMappingURL=registry.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"registry.d.ts","names":[],"sources":["../../../src/lib/utils/registry.ts"],"mappings":";iBAKgB,uBAAuB;iBAavB,6BAA6B;iBAW7B,uBACd,mBACA"}
1
+ {"version":3,"file":"registry.d.ts","names":[],"sources":["../../../src/lib/utils/registry.ts"],"mappings":";cAIa,uBAAqB;iBAElB,uBAAuB;iBA2BvB,uBAAuB;iBAavB,6BAA6B;iBAW7B,uBACd,mBACA,gBACA"}
@@ -2,6 +2,16 @@ import * as fs$1 from "node:fs";
2
2
  import * as path$1 from "node:path";
3
3
  //#region src/lib/utils/registry.ts
4
4
  const REGISTRY_BASE_URL = "https://r.assistant-ui.com";
5
+ const SHARED_REGISTRY_ITEMS = /* @__PURE__ */ new Set(["utils"]);
6
+ function detectRegistryPlatform(cwd) {
7
+ try {
8
+ const packageJsonPath = path$1.join(cwd, "package.json");
9
+ const packageJson = JSON.parse(fs$1.readFileSync(packageJsonPath, "utf8"));
10
+ return [packageJson.dependencies, packageJson.devDependencies].some((dependencies) => typeof dependencies === "object" && dependencies !== null && Object.hasOwn(dependencies, "react-native")) ? "native" : "web";
11
+ } catch {
12
+ return "web";
13
+ }
14
+ }
5
15
  function getComponentsJsonStyle(cwd) {
6
16
  try {
7
17
  const configPath = path$1.join(cwd, "components.json");
@@ -15,11 +25,12 @@ function resolveQuickStartRegistryUrl(style) {
15
25
  if (style === void 0 || style.startsWith("base-")) return `${REGISTRY_BASE_URL}/base/chat/b/ai-sdk-quick-start/json`;
16
26
  return `${REGISTRY_BASE_URL}/chat/b/ai-sdk-quick-start/json`;
17
27
  }
18
- function resolveRegistryItemUrl(component, style) {
28
+ function resolveRegistryItemUrl(component, style, platform = "web") {
29
+ if (platform === "native") return SHARED_REGISTRY_ITEMS.has(component) ? `${REGISTRY_BASE_URL}/${encodeURIComponent(component)}.json` : `${REGISTRY_BASE_URL}/native/${encodeURIComponent(component)}.json`;
19
30
  if (style === void 0) return `${REGISTRY_BASE_URL}/base/${encodeURIComponent(component)}.json`;
20
31
  return `${style.startsWith("base-") ? `${REGISTRY_BASE_URL}/styles/${encodeURIComponent(style)}` : REGISTRY_BASE_URL}/${encodeURIComponent(component)}.json`;
21
32
  }
22
33
  //#endregion
23
- export { getComponentsJsonStyle, resolveQuickStartRegistryUrl, resolveRegistryItemUrl };
34
+ export { SHARED_REGISTRY_ITEMS, detectRegistryPlatform, getComponentsJsonStyle, resolveQuickStartRegistryUrl, resolveRegistryItemUrl };
24
35
 
25
36
  //# sourceMappingURL=registry.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"registry.js","names":["path","fs"],"sources":["../../../src/lib/utils/registry.ts"],"sourcesContent":["import * as fs from \"node:fs\";\nimport * as path from \"node:path\";\n\nconst REGISTRY_BASE_URL = \"https://r.assistant-ui.com\";\n\nexport function getComponentsJsonStyle(cwd: string): string | undefined {\n try {\n const configPath = path.join(cwd, \"components.json\");\n const config = JSON.parse(fs.readFileSync(configPath, \"utf8\")) as {\n style?: unknown;\n };\n\n return typeof config.style === \"string\" ? config.style : undefined;\n } catch {\n return undefined;\n }\n}\n\nexport function resolveQuickStartRegistryUrl(style?: string): string {\n // The shadcn CLI appends a literal /json segment to fetched URLs containing\n // /chat/b/ unless they already end with it, so this item must use the direct\n // tree URLs rather than the /styles/ template.\n if (style === undefined || style.startsWith(\"base-\")) {\n return `${REGISTRY_BASE_URL}/base/chat/b/ai-sdk-quick-start/json`;\n }\n\n return `${REGISTRY_BASE_URL}/chat/b/ai-sdk-quick-start/json`;\n}\n\nexport function resolveRegistryItemUrl(\n component: string,\n style?: string,\n): string {\n if (style === undefined) {\n return `${REGISTRY_BASE_URL}/base/${encodeURIComponent(component)}.json`;\n }\n\n const registryUrl = style.startsWith(\"base-\")\n ? `${REGISTRY_BASE_URL}/styles/${encodeURIComponent(style)}`\n : REGISTRY_BASE_URL;\n\n return `${registryUrl}/${encodeURIComponent(component)}.json`;\n}\n"],"mappings":";;;AAGA,MAAM,oBAAoB;AAE1B,SAAgB,uBAAuB,KAAiC;CACtE,IAAI;EACF,MAAM,aAAaA,OAAK,KAAK,KAAK,iBAAiB;EACnD,MAAM,SAAS,KAAK,MAAMC,KAAG,aAAa,YAAY,MAAM,CAAC;EAI7D,OAAO,OAAO,OAAO,UAAU,WAAW,OAAO,QAAQ,KAAA;CAC3D,QAAQ;EACN;CACF;AACF;AAEA,SAAgB,6BAA6B,OAAwB;CAInE,IAAI,UAAU,KAAA,KAAa,MAAM,WAAW,OAAO,GACjD,OAAO,GAAG,kBAAkB;CAG9B,OAAO,GAAG,kBAAkB;AAC9B;AAEA,SAAgB,uBACd,WACA,OACQ;CACR,IAAI,UAAU,KAAA,GACZ,OAAO,GAAG,kBAAkB,QAAQ,mBAAmB,SAAS,EAAE;CAOpE,OAAO,GAJa,MAAM,WAAW,OAAO,IACxC,GAAG,kBAAkB,UAAU,mBAAmB,KAAK,MACvD,kBAEkB,GAAG,mBAAmB,SAAS,EAAE;AACzD"}
1
+ {"version":3,"file":"registry.js","names":["path","fs"],"sources":["../../../src/lib/utils/registry.ts"],"sourcesContent":["import * as fs from \"node:fs\";\nimport * as path from \"node:path\";\n\nconst REGISTRY_BASE_URL = \"https://r.assistant-ui.com\";\nexport const SHARED_REGISTRY_ITEMS = new Set([\"utils\"]);\n\nexport function detectRegistryPlatform(cwd: string): \"web\" | \"native\" {\n try {\n const packageJsonPath = path.join(cwd, \"package.json\");\n const packageJson = JSON.parse(\n fs.readFileSync(packageJsonPath, \"utf8\"),\n ) as {\n dependencies?: unknown;\n devDependencies?: unknown;\n };\n const dependencyGroups = [\n packageJson.dependencies,\n packageJson.devDependencies,\n ];\n\n return dependencyGroups.some(\n (dependencies) =>\n typeof dependencies === \"object\" &&\n dependencies !== null &&\n Object.hasOwn(dependencies, \"react-native\"),\n )\n ? \"native\"\n : \"web\";\n } catch {\n return \"web\";\n }\n}\n\nexport function getComponentsJsonStyle(cwd: string): string | undefined {\n try {\n const configPath = path.join(cwd, \"components.json\");\n const config = JSON.parse(fs.readFileSync(configPath, \"utf8\")) as {\n style?: unknown;\n };\n\n return typeof config.style === \"string\" ? config.style : undefined;\n } catch {\n return undefined;\n }\n}\n\nexport function resolveQuickStartRegistryUrl(style?: string): string {\n // The shadcn CLI appends a literal /json segment to fetched URLs containing\n // /chat/b/ unless they already end with it, so this item must use the direct\n // tree URLs rather than the /styles/ template.\n if (style === undefined || style.startsWith(\"base-\")) {\n return `${REGISTRY_BASE_URL}/base/chat/b/ai-sdk-quick-start/json`;\n }\n\n return `${REGISTRY_BASE_URL}/chat/b/ai-sdk-quick-start/json`;\n}\n\nexport function resolveRegistryItemUrl(\n component: string,\n style?: string,\n platform: \"web\" | \"native\" = \"web\",\n): string {\n if (platform === \"native\") {\n return SHARED_REGISTRY_ITEMS.has(component)\n ? `${REGISTRY_BASE_URL}/${encodeURIComponent(component)}.json`\n : `${REGISTRY_BASE_URL}/native/${encodeURIComponent(component)}.json`;\n }\n\n if (style === undefined) {\n return `${REGISTRY_BASE_URL}/base/${encodeURIComponent(component)}.json`;\n }\n\n const registryUrl = style.startsWith(\"base-\")\n ? `${REGISTRY_BASE_URL}/styles/${encodeURIComponent(style)}`\n : REGISTRY_BASE_URL;\n\n return `${registryUrl}/${encodeURIComponent(component)}.json`;\n}\n"],"mappings":";;;AAGA,MAAM,oBAAoB;AAC1B,MAAa,wCAAwB,IAAI,IAAI,CAAC,OAAO,CAAC;AAEtD,SAAgB,uBAAuB,KAA+B;CACpE,IAAI;EACF,MAAM,kBAAkBA,OAAK,KAAK,KAAK,cAAc;EACrD,MAAM,cAAc,KAAK,MACvBC,KAAG,aAAa,iBAAiB,MAAM,CACzC;EASA,OAAO,CAJL,YAAY,cACZ,YAAY,eAGQ,CAAC,CAAC,MACrB,iBACC,OAAO,iBAAiB,YACxB,iBAAiB,QACjB,OAAO,OAAO,cAAc,cAAc,CAC9C,IACI,WACA;CACN,QAAQ;EACN,OAAO;CACT;AACF;AAEA,SAAgB,uBAAuB,KAAiC;CACtE,IAAI;EACF,MAAM,aAAaD,OAAK,KAAK,KAAK,iBAAiB;EACnD,MAAM,SAAS,KAAK,MAAMC,KAAG,aAAa,YAAY,MAAM,CAAC;EAI7D,OAAO,OAAO,OAAO,UAAU,WAAW,OAAO,QAAQ,KAAA;CAC3D,QAAQ;EACN;CACF;AACF;AAEA,SAAgB,6BAA6B,OAAwB;CAInE,IAAI,UAAU,KAAA,KAAa,MAAM,WAAW,OAAO,GACjD,OAAO,GAAG,kBAAkB;CAG9B,OAAO,GAAG,kBAAkB;AAC9B;AAEA,SAAgB,uBACd,WACA,OACA,WAA6B,OACrB;CACR,IAAI,aAAa,UACf,OAAO,sBAAsB,IAAI,SAAS,IACtC,GAAG,kBAAkB,GAAG,mBAAmB,SAAS,EAAE,SACtD,GAAG,kBAAkB,UAAU,mBAAmB,SAAS,EAAE;CAGnE,IAAI,UAAU,KAAA,GACZ,OAAO,GAAG,kBAAkB,QAAQ,mBAAmB,SAAS,EAAE;CAOpE,OAAO,GAJa,MAAM,WAAW,OAAO,IACxC,GAAG,kBAAkB,UAAU,mBAAmB,KAAK,MACvD,kBAEkB,GAAG,mBAAmB,SAAS,EAAE;AACzD"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "assistant-ui",
3
- "version": "0.0.115",
3
+ "version": "0.0.116",
4
4
  "description": "CLI for assistant-ui",
5
5
  "keywords": [
6
6
  "cli",
@@ -41,15 +41,15 @@
41
41
  "semver": "^7.8.5"
42
42
  },
43
43
  "devDependencies": {
44
- "@assistant-ui/x-buildutils": "0.0.26",
44
+ "@assistant-ui/x-buildutils": "0.0.27",
45
45
  "@types/cli-progress": "^3.11.6",
46
46
  "@types/cross-spawn": "^6.0.6",
47
47
  "@types/debug": "^4.1.13",
48
48
  "@types/jscodeshift": "^17.3.0",
49
49
  "@types/node": "^26.4.1",
50
50
  "@types/semver": "^7.8.0",
51
- "@vitest/coverage-v8": "^4.1.11",
52
- "vitest": "^4.1.11"
51
+ "@vitest/coverage-v8": "^5.0.0",
52
+ "vitest": "^5.0.0"
53
53
  },
54
54
  "publishConfig": {
55
55
  "access": "public",
@@ -2,6 +2,7 @@ import { Command } from "commander";
2
2
  import { logger } from "../lib/utils/logger";
3
3
  import { hasConfig } from "../lib/utils/config";
4
4
  import {
5
+ detectRegistryPlatform,
5
6
  getComponentsJsonStyle,
6
7
  resolveRegistryItemUrl,
7
8
  } from "../lib/utils/registry";
@@ -24,12 +25,13 @@ export function createAddComponentsPlan(params: {
24
25
  overwrite?: boolean;
25
26
  path?: string;
26
27
  style?: string;
28
+ platform?: "web" | "native";
27
29
  }): AddComponentsPlan {
28
30
  const componentsToAdd = params.components.map((c) => {
29
31
  if (!/^[a-zA-Z0-9-/]+$/.test(c)) {
30
32
  throw new Error(`Invalid component name: ${c}`);
31
33
  }
32
- return resolveRegistryItemUrl(c, params.style);
34
+ return resolveRegistryItemUrl(c, params.style, params.platform);
33
35
  });
34
36
 
35
37
  const [command, dlxArgs] = dlxCommand(params.packageManager);
@@ -61,21 +63,25 @@ export const add = new Command()
61
63
  .option("--use-yarn", "explicitly use yarn")
62
64
  .option("--use-bun", "explicitly use bun")
63
65
  .action(async (components: string[], opts) => {
66
+ const platform = detectRegistryPlatform(opts.cwd);
67
+
64
68
  // Check if project is initialized
65
69
  if (!hasConfig(opts.cwd)) {
66
70
  logger.warn(
67
- "It looks like you haven't initialized your project yet — defaulting to Base UI flavored components. Run 'assistant-ui init' first for a configured setup.",
71
+ `It looks like you haven't initialized your project yet. Defaulting to ${platform === "native" ? "the native component tree" : "Base UI flavored components"}. Run 'assistant-ui init' first for a configured setup.`,
68
72
  );
69
73
  logger.break();
70
74
  }
71
75
 
76
+ logger.info(`Using the ${platform} registry tree.`);
72
77
  logger.step(`Adding ${components.length} component(s)...`);
73
78
 
74
79
  const packageManager = await resolvePackageManagerForCwd(
75
80
  opts.cwd,
76
81
  resolvePackageManager(opts),
77
82
  );
78
- const style = getComponentsJsonStyle(opts.cwd);
83
+ const style =
84
+ platform === "web" ? getComponentsJsonStyle(opts.cwd) : undefined;
79
85
  const { command, args } = createAddComponentsPlan({
80
86
  components,
81
87
  packageManager,
@@ -83,6 +89,7 @@ export const add = new Command()
83
89
  overwrite: opts.overwrite,
84
90
  path: opts.path,
85
91
  ...(style === undefined ? {} : { style }),
92
+ platform,
86
93
  });
87
94
 
88
95
  try {
@@ -195,7 +195,7 @@ export const PROJECT_METADATA: ProjectMetadata[] = [
195
195
  description: "Expo / React Native",
196
196
  category: "example",
197
197
  path: "examples/with-expo",
198
- hasLocalComponents: true,
198
+ hasLocalComponents: false,
199
199
  },
200
200
  {
201
201
  name: "with-interactables",
@@ -282,8 +282,6 @@ export const PROJECT_METADATA: ProjectMetadata[] = [
282
282
  // Examples that exist in the monorepo but are intentionally excluded from the CLI:
283
283
  //
284
284
  // - waterfall: Still in development, not ready for production.
285
- // - with-cloud-standalone: For cloud without assistant-ui — not for the
286
- // assistant-ui CLI.
287
285
  // - with-store: In development, not ready for public use of the tap store.
288
286
  // - with-tap-runtime: In development, not ready for public use of the tap
289
287
  // store.
@@ -799,6 +797,9 @@ export const create = new Command()
799
797
  logger.info(` ${cdCommand}`);
800
798
  if (opts.skipInstall) {
801
799
  logger.info(` ${pm} install`);
800
+ if (transformResult.registryInstallCommand) {
801
+ logger.info(` ${transformResult.registryInstallCommand}`);
802
+ }
802
803
  }
803
804
  logger.info(` # Set up your environment variables in ${envFile}`);
804
805
  logger.info(` ${runCmd} ${devScript}`);
@@ -23,7 +23,6 @@ const ASSISTANT_UI_PACKAGES = [
23
23
  // Streaming & Cloud
24
24
  "assistant-stream",
25
25
  "assistant-cloud",
26
- "@assistant-ui/cloud-ai-sdk",
27
26
  // Adapters
28
27
  "@assistant-ui/eve",
29
28
  "@assistant-ui/ai-sdk",
@@ -75,9 +75,6 @@ const MCP_CONFIGS: Record<
75
75
  if (process.platform === "win32") {
76
76
  return path.join(process.env.APPDATA || "", "Zed", "settings.json");
77
77
  }
78
- if (process.platform === "darwin") {
79
- return path.join(os.homedir(), ".zed", "settings.json");
80
- }
81
78
  return path.join(os.homedir(), ".config", "zed", "settings.json");
82
79
  },
83
80
  config: {
@@ -10,6 +10,10 @@ import { logger } from "./utils/logger";
10
10
  import { runSpawn, SpawnExitError, SpawnSignalError } from "./run-spawn";
11
11
  import { type PackageManagerName } from "./utils/package-manager";
12
12
  import { readProjectFiles } from "./utils/file-scanner";
13
+ import {
14
+ detectRegistryPlatform,
15
+ resolveRegistryItemUrl,
16
+ } from "./utils/registry";
13
17
 
14
18
  export function dlxCommand(pm: PackageManagerName): [string, string[]] {
15
19
  switch (pm) {
@@ -186,6 +190,7 @@ export async function scaffoldProject(
186
190
 
187
191
  export interface TransformResult {
188
192
  registryInstallFailure?: { retryCommand: string };
193
+ registryInstallCommand?: string;
189
194
  }
190
195
 
191
196
  export async function transformProject(
@@ -199,29 +204,23 @@ export async function transformProject(
199
204
  transformTsConfig(projectDir);
200
205
  transformCssFiles(projectDir);
201
206
 
202
- let assistantUI: string[] | undefined;
203
- let shadcnUI: string[] | undefined;
204
-
205
- if (!opts.hasLocalComponents) {
206
- const components = scanRequiredComponents(projectDir);
207
- assistantUI = components.assistantUI;
208
- shadcnUI = components.shadcnUI;
209
- }
207
+ const components = opts.hasLocalComponents
208
+ ? undefined
209
+ : resolveRegistryComponents(projectDir, scanRequiredComponents(projectDir));
210
210
 
211
211
  const pm = opts.packageManager;
212
- if (!opts.skipInstall) {
213
- logger.step("Installing dependencies...");
214
- await installDependencies(projectDir, pm);
212
+ if (opts.skipInstall) {
213
+ if (!components) return {};
214
+ const [cmd, dlxArgs] = dlxCommand(pm);
215
+ return {
216
+ registryInstallCommand: `${cmd} ${[...dlxArgs, "shadcn@latest", "add", ...components].join(" ")}`,
217
+ };
215
218
  }
216
219
 
217
- if (
218
- !opts.skipInstall &&
219
- !opts.hasLocalComponents &&
220
- shadcnUI &&
221
- assistantUI
222
- ) {
223
- const auiComponents = assistantUI.map((c) => `@assistant-ui/${c}`);
224
- const components = ["@assistant-ui/utils", ...shadcnUI, ...auiComponents];
220
+ logger.step("Installing dependencies...");
221
+ await installDependencies(projectDir, pm);
222
+
223
+ if (components) {
225
224
  logger.step(`Installing components: ${components.join(", ")}...`);
226
225
  const failure = await installShadcnRegistry(
227
226
  projectDir,
@@ -235,6 +234,22 @@ export async function transformProject(
235
234
  return {};
236
235
  }
237
236
 
237
+ function resolveRegistryComponents(
238
+ projectDir: string,
239
+ { assistantUI, shadcnUI }: RequiredComponents,
240
+ ): string[] {
241
+ if (detectRegistryPlatform(projectDir) === "native") {
242
+ return ["utils", ...shadcnUI, ...assistantUI].map((component) =>
243
+ resolveRegistryItemUrl(component, undefined, "native"),
244
+ );
245
+ }
246
+ return [
247
+ "@assistant-ui/utils",
248
+ ...shadcnUI,
249
+ ...assistantUI.map((component) => `@assistant-ui/${component}`),
250
+ ];
251
+ }
252
+
238
253
  function transformPackageJson(projectDir: string): void {
239
254
  const pkgPath = path.join(projectDir, "package.json");
240
255
  const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
@@ -543,7 +558,7 @@ export async function reconcileAssistantUIImportLayout(
543
558
  }
544
559
  }
545
560
 
546
- function scanRequiredComponents(projectDir: string): RequiredComponents {
561
+ export function scanRequiredComponents(projectDir: string): RequiredComponents {
547
562
  const assistantUIComponents = new Set<string>();
548
563
  const shadcnUIComponents = new Set<string>();
549
564
 
@@ -36,7 +36,6 @@ const trackSignal = (signal: NodeJS.Signals) => {
36
36
  describe("runSpawn", () => {
37
37
  afterEach(() => {
38
38
  vi.restoreAllMocks();
39
- vi.clearAllMocks();
40
39
  });
41
40
 
42
41
  it("forwards the first termination signal and cleans up listeners", async () => {
@@ -3,6 +3,7 @@ import * as os from "node:os";
3
3
  import * as path from "node:path";
4
4
  import { afterEach, beforeEach, describe, expect, it } from "vitest";
5
5
  import {
6
+ detectRegistryPlatform,
6
7
  getComponentsJsonStyle,
7
8
  resolveQuickStartRegistryUrl,
8
9
  resolveRegistryItemUrl,
@@ -61,6 +62,49 @@ describe("getComponentsJsonStyle", () => {
61
62
  });
62
63
  });
63
64
 
65
+ describe("detectRegistryPlatform", () => {
66
+ let cwd: string;
67
+
68
+ beforeEach(() => {
69
+ cwd = fs.mkdtempSync(path.join(os.tmpdir(), "assistant-ui-cli-"));
70
+ });
71
+
72
+ afterEach(() => {
73
+ fs.rmSync(cwd, { recursive: true, force: true });
74
+ });
75
+
76
+ it("detects react-native in dependencies", () => {
77
+ fs.writeFileSync(
78
+ path.join(cwd, "package.json"),
79
+ JSON.stringify({ dependencies: { "react-native": "0.86.3" } }),
80
+ );
81
+
82
+ expect(detectRegistryPlatform(cwd)).toBe("native");
83
+ });
84
+
85
+ it("detects react-native in devDependencies", () => {
86
+ fs.writeFileSync(
87
+ path.join(cwd, "package.json"),
88
+ JSON.stringify({ devDependencies: { "react-native": "0.86.3" } }),
89
+ );
90
+
91
+ expect(detectRegistryPlatform(cwd)).toBe("native");
92
+ });
93
+
94
+ it("uses web without react-native", () => {
95
+ fs.writeFileSync(
96
+ path.join(cwd, "package.json"),
97
+ JSON.stringify({ dependencies: { react: "19.2.3" } }),
98
+ );
99
+
100
+ expect(detectRegistryPlatform(cwd)).toBe("web");
101
+ });
102
+
103
+ it("uses web when package.json is missing", () => {
104
+ expect(detectRegistryPlatform(cwd)).toBe("web");
105
+ });
106
+ });
107
+
64
108
  describe("resolveQuickStartRegistryUrl", () => {
65
109
  it("uses the base quick start for base styles", () => {
66
110
  expect(resolveQuickStartRegistryUrl("base-nova")).toBe(
@@ -111,4 +155,16 @@ describe("resolveRegistryItemUrl", () => {
111
155
  "https://r.assistant-ui.com/styles/base-nova%3Fpreview%3D1/thread.json",
112
156
  );
113
157
  });
158
+
159
+ it("uses the native URL regardless of style", () => {
160
+ expect(resolveRegistryItemUrl("thread", "base-nova", "native")).toBe(
161
+ "https://r.assistant-ui.com/native/thread.json",
162
+ );
163
+ });
164
+
165
+ it("keeps shared items at the root URL on native", () => {
166
+ expect(resolveRegistryItemUrl("utils", undefined, "native")).toBe(
167
+ "https://r.assistant-ui.com/utils.json",
168
+ );
169
+ });
114
170
  });
@@ -2,6 +2,34 @@ import * as fs from "node:fs";
2
2
  import * as path from "node:path";
3
3
 
4
4
  const REGISTRY_BASE_URL = "https://r.assistant-ui.com";
5
+ export const SHARED_REGISTRY_ITEMS = new Set(["utils"]);
6
+
7
+ export function detectRegistryPlatform(cwd: string): "web" | "native" {
8
+ try {
9
+ const packageJsonPath = path.join(cwd, "package.json");
10
+ const packageJson = JSON.parse(
11
+ fs.readFileSync(packageJsonPath, "utf8"),
12
+ ) as {
13
+ dependencies?: unknown;
14
+ devDependencies?: unknown;
15
+ };
16
+ const dependencyGroups = [
17
+ packageJson.dependencies,
18
+ packageJson.devDependencies,
19
+ ];
20
+
21
+ return dependencyGroups.some(
22
+ (dependencies) =>
23
+ typeof dependencies === "object" &&
24
+ dependencies !== null &&
25
+ Object.hasOwn(dependencies, "react-native"),
26
+ )
27
+ ? "native"
28
+ : "web";
29
+ } catch {
30
+ return "web";
31
+ }
32
+ }
5
33
 
6
34
  export function getComponentsJsonStyle(cwd: string): string | undefined {
7
35
  try {
@@ -30,7 +58,14 @@ export function resolveQuickStartRegistryUrl(style?: string): string {
30
58
  export function resolveRegistryItemUrl(
31
59
  component: string,
32
60
  style?: string,
61
+ platform: "web" | "native" = "web",
33
62
  ): string {
63
+ if (platform === "native") {
64
+ return SHARED_REGISTRY_ITEMS.has(component)
65
+ ? `${REGISTRY_BASE_URL}/${encodeURIComponent(component)}.json`
66
+ : `${REGISTRY_BASE_URL}/native/${encodeURIComponent(component)}.json`;
67
+ }
68
+
34
69
  if (style === undefined) {
35
70
  return `${REGISTRY_BASE_URL}/base/${encodeURIComponent(component)}.json`;
36
71
  }