@vocoder/cli 0.15.0 → 0.16.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin.mjs +1996 -1980
- package/dist/bin.mjs.map +1 -1
- package/dist/{chunk-62KCB6C6.mjs → chunk-2JERZ6DL.mjs} +79 -237
- package/dist/chunk-2JERZ6DL.mjs.map +1 -0
- package/dist/lib.d.mts +7 -7
- package/dist/lib.mjs +159 -2
- package/dist/lib.mjs.map +1 -1
- package/package.json +3 -3
- package/dist/chunk-62KCB6C6.mjs.map +0 -1
package/dist/bin.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/bin.ts","../src/commands/init.ts","../src/utils/write-config.ts","../src/utils/theme.ts","../src/utils/project-create.ts","../src/utils/app-dir-select.ts","../src/utils/branch-select.ts","../src/utils/locale-search.ts","../src/utils/github-connect.ts","../src/utils/local-server.ts","../src/utils/git-identity.ts","../src/utils/organization.ts","../src/commands/locales.ts","../src/commands/sync.ts","../src/utils/branch.ts","../src/utils/config.ts","../src/commands/logout.ts","../src/commands/app-config.ts","../src/commands/translations.ts","../src/commands/create-app.ts","../src/commands/whoami.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { Command } from \"commander\";\nimport { init } from \"./commands/init.js\";\nimport {\n\taddLocales,\n\tlistProjectLocales,\n\tlistSupportedLocales,\n\tremoveLocales,\n} from \"./commands/locales.js\";\nimport { logout } from \"./commands/logout.js\";\nimport { appConfig } from \"./commands/app-config.js\";\nimport { sync } from \"./commands/sync.js\";\nimport { getTranslations } from \"./commands/translations.js\";\nimport { createApp } from \"./commands/create-app.js\";\nimport { whoami } from \"./commands/whoami.js\";\n\n/**\n * Collector function for repeated CLI options\n * Allows multiple --include or --exclude flags\n */\nfunction collect(value: string, previous: string[] = []): string[] {\n\treturn previous.concat([value]);\n}\n\nasync function runCommand(\n\tcommand: (options: any) => Promise<number>,\n\toptions: any,\n): Promise<void> {\n\tconst exitCode = await command(options);\n\t// Force exit so open stdin handles from readline/clack don't stall the process.\n\tprocess.exit(exitCode);\n}\n\nconst program = new Command();\n\nprogram\n\t.name(\"vocoder\")\n\t.description(\"Vocoder CLI - Project setup and string extraction\")\n\t.version(\"0.1.5\");\n\nprogram\n\t.command(\"init\")\n\t.description(\"Authenticate and provision Vocoder for this project\")\n\t.option(\"--api-url <url>\", \"Override Vocoder API URL\")\n\t.option(\"--yes\", \"Allow overwriting existing local config values\")\n\t.option(\n\t\t\"--ci\",\n\t\t\"Non-interactive mode: print auth URL to stdout, skip browser open\",\n\t)\n\t.option(\"--app-name <name>\", \"Starter app name to create\")\n\t.option(\"--source-locale <locale>\", \"Source locale for the starter project\")\n\t.option(\n\t\t\"--target-locales <list>\",\n\t\t\"Comma-separated target locales (e.g. es,fr,de)\",\n\t)\n\t.action((options) => runCommand(init, options));\n\nprogram\n\t.command(\"sync\")\n\t.description(\"Extract strings and sync translations\")\n\t.option(\"--branch <branch>\", \"Override detected branch\")\n\t.option(\"--mode <mode>\", \"Sync mode: auto, required, best-effort\", \"auto\")\n\t.option(\"--max-wait <ms>\", \"Max wait for translations (ms)\")\n\t.option(\"--force\", \"Force re-extraction even if no changes\")\n\t.option(\"--dry-run\", \"Preview without syncing\")\n\t.option(\"--no-fallback\", \"Disable fallback to cached translations\")\n\t.option(\"--include <pattern>\", \"Include glob pattern\", collect, [])\n\t.option(\"--exclude <pattern>\", \"Exclude glob pattern\", collect, [])\n\t.option(\"--verbose\", \"Detailed output\")\n\t.action((options) => {\n\t\tconst translated: Record<string, unknown> = { ...options };\n\t\tif (options.maxWait) translated.maxWaitMs = Number(options.maxWait);\n\t\tif (options.fallback === false) translated.noFallback = true;\n\t\treturn runCommand(sync, translated);\n\t});\n\nprogram\n\t.command(\"logout\")\n\t.description(\"Log out and remove stored credentials\")\n\t.option(\"--api-url <url>\", \"Override Vocoder API URL\")\n\t.action((options) => runCommand(logout, options));\n\nprogram\n\t.command(\"whoami\")\n\t.description(\"Show the currently authenticated user\")\n\t.option(\"--api-url <url>\", \"Override Vocoder API URL\")\n\t.action((options) => runCommand(whoami, options));\n\n// ── Project management ────────────────────────────────────────────────────────\n\nconst localesCmd = program\n\t.command(\"locales\")\n\t.description(\"Manage project target locales\")\n\t.option(\"--api-url <url>\", \"Override Vocoder API URL\")\n\t.action((options) => runCommand(listProjectLocales, options));\n\nlocalesCmd\n\t.command(\"add <codes...>\")\n\t.description(\"Add one or more target locales by BCP 47 code (e.g. fr de pt-BR)\")\n\t.option(\"--api-url <url>\", \"Override Vocoder API URL\")\n\t.action((codes: string[], options) =>\n\t\trunCommand((opts) => addLocales(codes, opts), options),\n\t);\n\nlocalesCmd\n\t.command(\"remove <codes...>\")\n\t.description(\"Remove one or more target locales by BCP 47 code\")\n\t.option(\"--api-url <url>\", \"Override Vocoder API URL\")\n\t.action((codes: string[], options) =>\n\t\trunCommand((opts) => removeLocales(codes, opts), options),\n\t);\n\nlocalesCmd\n\t.command(\"supported\")\n\t.description(\"List all locales supported by Vocoder\")\n\t.option(\"--api-url <url>\", \"Override Vocoder API URL\")\n\t.action((options) => runCommand(listSupportedLocales, options));\n\nprogram\n\t.command(\"project\")\n\t.description(\"Show current app configuration\")\n\t.option(\"--api-url <url>\", \"Override Vocoder API URL\")\n\t.action((options) => runCommand(appConfig, options));\n\nprogram\n\t.command(\"translations\")\n\t.description(\"Download the current translation snapshot\")\n\t.option(\"--branch <branch>\", \"Git branch (auto-detected if omitted)\")\n\t.option(\"--locale <locale>\", \"Fetch a specific locale only\")\n\t.option(\"--output <dir>\", \"Write locale JSON files to this directory\")\n\t.option(\"--api-url <url>\", \"Override Vocoder API URL\")\n\t.action((options) => runCommand(getTranslations, options));\n\nprogram\n\t.command(\"create-app\")\n\t.description(\"Create a new Vocoder app (requires prior `vocoder init`)\")\n\t.requiredOption(\"--name <name>\", \"App display name\")\n\t.requiredOption(\"--source-locale <code>\", \"Source language BCP 47 code (e.g. en)\")\n\t.requiredOption(\"--organization <org-id>\", \"Organization ID\")\n\t.option(\n\t\t\"--target-locales <codes>\",\n\t\t\"Comma-separated target locale codes (e.g. fr,de,pt-BR)\",\n\t)\n\t.option(\n\t\t\"--target-branches <branches>\",\n\t\t\"Comma-separated branch names to sync (default: main)\",\n\t)\n\t.option(\n\t\t\"--repo <canonical>\",\n\t\t\"Git repo canonical (e.g. github:owner/repo). Auto-detected from git remote if omitted.\",\n\t)\n\t.option(\n\t\t\"--app-dir <path>\",\n\t\t\"App directory within the repo for monorepos (default: .)\",\n\t)\n\t.option(\"--api-url <url>\", \"Override Vocoder API URL\")\n\t.action((options) => {\n\t\tconst translated = {\n\t\t\t...options,\n\t\t\t// Commander camelCases dashed options\n\t\t\tsourceLocale: options.sourceLocale,\n\t\t\ttargetLocales: options.targetLocales,\n\t\t\ttargetBranches: options.targetBranches,\n\t\t\torganization: options.organization,\n\t\t};\n\t\treturn runCommand(createApp, translated);\n\t});\n\nprogram.parse(process.argv);\n","import * as p from \"@clack/prompts\";\n\nimport { VocoderAPI, VocoderAPIError } from \"../utils/api.js\";\nimport {\n buildInstallCommand,\n detectLocalEcosystem,\n getPackagesToInstall,\n} from \"../utils/detect-local.js\";\nimport {\n clearAuthData,\n readAuthData,\n verifyStoredAuth,\n writeAuthData,\n} from \"../utils/auth-store.js\";\nimport { execSync, spawn } from \"node:child_process\";\nimport { existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport {\n findExistingConfig,\n writeVocoderConfig,\n} from \"../utils/write-config.js\";\nimport { highlight, info } from \"../utils/theme.js\";\nimport { join, resolve } from \"node:path\";\nimport { runAppCreate, runProjectCreate } from \"../utils/project-create.js\";\nimport {\n runGitHubDiscoveryFlow,\n runGitHubInstallFlow,\n selectGitHubInstallation,\n} from \"../utils/github-connect.js\";\n\nimport type { InitOptions } from \"../types.js\";\nimport chalk from \"chalk\";\nimport { getSetupSnippets } from \"../utils/setup-snippets.js\";\nimport { config as loadEnv } from \"dotenv\";\nimport { resolveGitContext } from \"../utils/git-identity.js\";\nimport { selectOrganization } from \"../utils/organization.js\";\nimport { startCallbackServer } from \"../utils/local-server.js\";\n\nloadEnv();\n\nconst SUBSCRIPTION_SETTINGS_PATH =\n \"/dashboard/workspace/settings?tab=subscription\";\n\nasync function sleep(ms: number): Promise<void> {\n await new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nasync function tryOpenBrowser(url: string): Promise<boolean> {\n if (!process.stdout.isTTY || process.env.CI === \"true\") {\n return false;\n }\n\n let command: string;\n let args: string[];\n\n if (process.platform === \"darwin\") {\n command = \"open\";\n args = [url];\n } else if (process.platform === \"win32\") {\n command = \"rundll32\";\n args = [\"url.dll,FileProtocolHandler\", url];\n } else {\n command = \"xdg-open\";\n args = [url];\n }\n\n return await new Promise<boolean>((resolve) => {\n try {\n const child = spawn(command, args, {\n detached: true,\n stdio: \"ignore\",\n windowsHide: true,\n });\n\n let settled = false;\n child.once(\"spawn\", () => {\n if (settled) return;\n settled = true;\n child.unref();\n resolve(true);\n });\n child.once(\"error\", () => {\n if (settled) return;\n settled = true;\n resolve(false);\n });\n setTimeout(() => {\n if (settled) return;\n settled = true;\n resolve(false);\n }, 300);\n } catch {\n resolve(false);\n }\n });\n}\n\nfunction isPlanLimitFailure(message?: string): boolean {\n if (!message) return false;\n return /limit|upgrade/i.test(message);\n}\n\nfunction getSubscriptionSettingsUrl(apiUrl: string): string {\n return new URL(SUBSCRIPTION_SETTINGS_PATH, apiUrl).toString();\n}\n\nfunction printPlanLimitMessage(apiUrl: string, message: string): void {\n p.log.error(`You are over your plan limits.\\n ${message}`);\n p.log.info(`Manage subscription: ${getSubscriptionSettingsUrl(apiUrl)}`);\n}\n\ninterface ScaffoldParams {\n sourceLocale: string;\n targetBranches: string[];\n}\n\nfunction runScaffold(params: ScaffoldParams): void {\n const { sourceLocale, targetBranches } = params;\n\n const detection = detectLocalEcosystem();\n const useTypeScript = detection.isTypeScript;\n\n if (detection.ecosystem) {\n const frameworkLabel = detection.framework ?? detection.ecosystem;\n const pmLabel = detection.packageManager;\n p.log.info(`Detected: ${chalk.bold(frameworkLabel)} (${pmLabel})`);\n }\n\n const { devPackages, runtimePackages } = getPackagesToInstall(detection);\n const allPackages = [...devPackages, ...runtimePackages];\n if (allPackages.length > 0) {\n p.log.info(\"\");\n const installSpinner = p.spinner();\n installSpinner.start(`Installing ${allPackages.join(\", \")}...`);\n\n try {\n if (devPackages.length > 0) {\n execSync(\n buildInstallCommand(detection.packageManager, devPackages, true),\n { stdio: \"pipe\", cwd: process.cwd() },\n );\n }\n if (runtimePackages.length > 0) {\n execSync(\n buildInstallCommand(detection.packageManager, runtimePackages, false),\n { stdio: \"pipe\", cwd: process.cwd() },\n );\n }\n installSpinner.stop(`Installed ${allPackages.join(\", \")}`);\n } catch {\n installSpinner.stop(\"Package installation failed\");\n const cmds = [\n devPackages.length > 0\n ? buildInstallCommand(detection.packageManager, devPackages, true)\n : null,\n runtimePackages.length > 0\n ? buildInstallCommand(\n detection.packageManager,\n runtimePackages,\n false,\n )\n : null,\n ]\n .filter(Boolean)\n .join(\" && \");\n p.log.warn(`Run manually: ${highlight(cmds)}`);\n }\n } else if (detection.ecosystem) {\n p.log.info(`Packages: ${chalk.green(\"already installed\")}`);\n }\n\n const snippets = getSetupSnippets({\n framework: detection.framework,\n ecosystem: detection.ecosystem,\n sourceLocale,\n targetBranches,\n });\n\n const steps: Array<{ label: string; hint: string; code: string }> = [];\n\n if (snippets.pluginStep) {\n steps.push({\n label: snippets.pluginStep.file,\n hint: \"register the build plugin so Vocoder can extract your strings\",\n code: snippets.pluginStep.code,\n });\n }\n\n if (snippets.providerStep) {\n steps.push({\n label: snippets.providerStep.file,\n hint: \"wrap your app so translations load at runtime\",\n code: snippets.providerStep.code,\n });\n }\n\n steps.push({\n label: \"wrap translatable text\",\n hint: \"mark strings for extraction — Vocoder picks these up on push\",\n code: snippets.wrapStep.code,\n });\n\n p.log.message(\"\");\n p.log.message(chalk.bold(\"Finish setup in your code\"));\n p.log.message(\"\");\n\n for (let i = 0; i < steps.length; i++) {\n const step = steps[i]!;\n p.log.step(`${chalk.bold(step.label)} ${chalk.dim(`— ${step.hint}`)}`);\n printCodeBlock(step.code);\n if (i < steps.length - 1) p.log.message(\"\");\n }\n\n p.log.message(\"\");\n const branchList =\n targetBranches.length > 0\n ? targetBranches.map((b) => highlight(b)).join(\" or \")\n : highlight(\"your target branch\");\n p.log.success(`Push to ${branchList} to trigger your first translation run.`);\n p.log.message(info(\" Docs: https://vocoder.app/docs/getting-started\"));\n}\n\nfunction writeApiKeyToEnv(apiKey: string, repoRoot?: string): boolean {\n const envPath = join(repoRoot ?? process.cwd(), \".env\");\n if (!existsSync(envPath)) return false;\n\n try {\n const content = readFileSync(envPath, \"utf-8\");\n const keyLine = `VOCODER_API_KEY=${apiKey}`;\n let updated: string;\n\n if (/^VOCODER_API_KEY=/m.test(content)) {\n updated = content.replace(/^VOCODER_API_KEY=.*/m, keyLine);\n } else {\n const sep = content.length > 0 && !content.endsWith(\"\\n\") ? \"\\n\" : \"\";\n updated = `${content}${sep}${keyLine}\\n`;\n }\n\n writeFileSync(envPath, updated);\n return true;\n } catch {\n return false;\n }\n}\n\nfunction printApiKey(apiKey: string, repoRoot?: string): void {\n const saved = writeApiKeyToEnv(apiKey, repoRoot);\n\n p.log.message(\"\");\n p.log.message(chalk.bold(\"Your API Key\"));\n printCodeBlock(`VOCODER_API_KEY=${apiKey}`);\n if (saved) {\n p.log.success(chalk.dim(\"Saved to .env\"));\n } else {\n p.log.message(chalk.dim(\" Add the above to your .env file\"));\n }\n}\n\n/**\n * Write one vocoder.config.ts per app directory and log the result.\n * Non-monorepo projects write a single config at the project root.\n */\nfunction writeAppConfigs(\n apps: Array<{ appDir: string; appId: string }>,\n targetBranches: string[],\n useTypeScript: boolean,\n repoRoot?: string,\n): void {\n const base = repoRoot ?? process.cwd();\n for (const app of apps) {\n const dir = app.appDir ? resolve(base, app.appDir) : base;\n const written = writeVocoderConfig({\n targetBranches,\n appId: app.appId,\n cwd: dir,\n useTypeScript,\n });\n if (written) {\n const displayPath = app.appDir ? `${app.appDir}/${written}` : written;\n p.log.success(`Created ${highlight(displayPath)}`);\n } else if (!findExistingConfig(dir)) {\n const ext = useTypeScript ? \"ts\" : \"js\";\n p.log.warn(\n `Could not write ${app.appDir ? `${app.appDir}/` : \"\"}vocoder.config.${ext} — create it manually.`,\n );\n }\n }\n}\n\n// TODO: uncomment when @vocoder/mcp is published and functional\n// function printMcpSetup(apiKey: string): void {\n// \tconst addCommand = `claude mcp add --scope project --transport stdio \\\\\\n --env VOCODER_API_KEY=${apiKey} \\\\\\n vocoder -- npx -y @vocoder/mcp`;\n//\n// \tconst teamConfig = JSON.stringify(\n// \t\t{\n// \t\t\tmcpServers: {\n// \t\t\t\tvocoder: {\n// \t\t\t\t\ttype: \"stdio\",\n// \t\t\t\t\tcommand: \"npx\",\n// \t\t\t\t\targs: [\"-y\", \"@vocoder/mcp\"]\n// \t\t\t\t},\n// \t\t\t},\n// \t\t},\n// \t\tnull,\n// \t\t2,\n// \t);\n//\n// \tp.log.message(\"\");\n// \tp.log.message(chalk.bold(\"Use Vocoder with Claude Code\"));\n// \tp.log.message(\"\");\n// \tp.log.message(\"Run once to register the MCP server (embeds your key locally):\");\n// \tprintCodeBlock(addCommand);\n// \tp.log.message(\"\");\n// \tp.log.message(\n// \t\t\"To share with your team, commit \" +\n// \t\t\thighlight(\".mcp.json\") +\n// \t\t\t\" with an env var reference —\",\n// \t);\n// \tp.log.message(\n// \t\t\"each developer sets \" + highlight(\"VOCODER_API_KEY\") + \" in their own .env:\",\n// \t);\n// \tprintCodeBlock(teamConfig);\n// \tp.log.message(\"\");\n// \tp.log.message(chalk.gray(\"Docs: https://vocoder.app/docs/mcp\"));\n// }\n\nfunction printCodeBlock(code: string): void {\n const lines = code.split(\"\\n\");\n const maxLen = lines.reduce(\n (max: number, line: string) => Math.max(max, line.length),\n 0,\n );\n const bar = chalk.gray(\"│\");\n const pad = (s: string) => s + \" \".repeat(maxLen - s.length);\n\n process.stdout.write(`${chalk.gray(\"│\")}\\n`);\n process.stdout.write(\n `${chalk.gray(\"│\")} ${chalk.gray(`┌${\"─\".repeat(maxLen + 2)}┐`)}\\n`,\n );\n for (const line of lines) {\n process.stdout.write(`${chalk.gray(\"│\")} ${bar} ${pad(line)} ${bar}\\n`);\n }\n process.stdout.write(\n `${chalk.gray(\"│\")} ${chalk.gray(`└${\"─\".repeat(maxLen + 2)}┘`)}\\n`,\n );\n}\n\n// ── Auth helpers ─────────────────────────────────────────────────────────────\n\n/**\n * Run the browser authentication flow.\n * Returns `{ token, userInfo, organizationId? }` on success, or null if cancelled.\n * When `organizationId` is set, the GitHub App was installed in the same browser\n * trip — the caller should skip workspace selection and GitHub connect.\n *\n * @param reauth - When true, the user has an expired token and already has a workspace.\n * Use verificationUrl (auth/cli page) instead of installUrl so we don't create a\n * duplicate workspace. The direct-to-GitHub install URL is only for first-time setup.\n */\nasync function runAuthFlow(\n api: VocoderAPI,\n options: InitOptions,\n reauth = false,\n repoCanonical?: string,\n): Promise<{\n token: string;\n userId: string;\n email: string;\n name: string | null;\n organizationId?: string;\n discoveryReady?: boolean;\n} | null> {\n // Try to start a local callback server for instant token delivery.\n // In --ci mode the browser step is handled externally, so skip the callback\n // server and go straight to polling — simpler and testable.\n let server: Awaited<ReturnType<typeof startCallbackServer>> | null = null;\n if (!options.ci) {\n try {\n server = await startCallbackServer();\n } catch {\n // Port conflict or other issue — fall back to polling\n }\n }\n\n const session = await api.startCliAuthSession(server?.port, repoCanonical);\n // Re-auth: user already has a workspace — use verificationUrl (auth/cli page)\n // so we don't trigger a new GitHub App install and create a duplicate workspace.\n // First-time: use installUrl to combine Vocoder auth + App install in one trip.\n const browserUrl = reauth\n ? session.verificationUrl\n : (session.installUrl ?? session.verificationUrl);\n const expiresAt = new Date(session.expiresAt).getTime();\n\n if (options.ci) {\n // Machine-readable output for automated test harnesses.\n // Parsed by e2e/helpers/cli.ts: /^VOCODER_AUTH_URL: (.+)$/m\n process.stdout.write(`VOCODER_AUTH_URL: ${browserUrl}\\n`);\n // Also emit the session ID separately so tests can expire/complete sessions\n process.stdout.write(`VOCODER_SESSION_ID: ${session.sessionId}\\n`);\n } else if (\n process.stdin.isTTY &&\n process.stdout.isTTY &&\n process.env.CI !== \"true\"\n ) {\n if (reauth) {\n // Re-auth: token expired, just sign in — no install choice needed\n if (!options.yes) {\n const shouldOpen = await p.confirm({\n message: \"Open your browser to sign in again?\",\n });\n if (p.isCancel(shouldOpen)) {\n server?.close();\n p.cancel(\"Setup cancelled.\");\n return null;\n }\n if (!shouldOpen) {\n server?.close();\n p.cancel(\"Setup cancelled.\");\n return null;\n } else {\n const opened = await tryOpenBrowser(browserUrl);\n if (!opened) {\n p.note(browserUrl, \"Sign In\");\n p.log.info(\"Open the URL above manually to continue.\");\n }\n }\n } else {\n await tryOpenBrowser(browserUrl);\n }\n } else {\n // First-time setup: let user choose install vs link existing\n let isLinkFlow = false;\n if (!options.yes) {\n const connectChoice = await p.select<string>({\n message:\n \"Vocoder needs to be installed on your GitHub account to get started\",\n options: [\n {\n value: \"install\",\n label: \"Install GitHub App\",\n hint: \"new user\",\n },\n {\n value: \"link\",\n label: \"Already installed? Link your account\",\n hint: \"returning user\",\n },\n ],\n });\n\n if (p.isCancel(connectChoice)) {\n server?.close();\n p.cancel(\"Setup cancelled.\");\n return null;\n }\n\n isLinkFlow = connectChoice === \"link\";\n }\n\n // For \"link\": get the OAuth-only URL from the server (no install page shown)\n let urlToOpen = browserUrl;\n if (isLinkFlow) {\n try {\n const linkSession = await api.startCliGitHubLinkSession(\n session.sessionId,\n server?.port,\n );\n urlToOpen = linkSession.oauthUrl;\n } catch {\n // Fall back to install URL if link-start fails\n urlToOpen = browserUrl;\n }\n }\n\n // Open browser immediately — no separate confirm needed\n const opened = await tryOpenBrowser(urlToOpen);\n if (!opened) {\n // Only show URL as a fallback if auto-open fails\n p.log.warn(\"Could not open your browser automatically.\");\n p.note(urlToOpen, \"GitHub\");\n p.log.info(\"Open the URL above to continue.\");\n }\n }\n }\n\n const authSpinner = p.spinner();\n authSpinner.start(\"Waiting for GitHub authorization...\");\n\n let rawToken: string | null = null;\n let callbackOrganizationId: string | undefined;\n let callbackDiscoveryReady = false;\n\n const deadline = Math.min(expiresAt, Date.now() + 10 * 60 * 1000);\n let stopPolling = false;\n\n // Local server future — null if no server or on error\n const serverCallback: Promise<Record<string, string> | null> = server\n ? server.waitForCallback().catch(() => null)\n : Promise.resolve(null);\n\n // Polling runs concurrently with the server wait so a missed local-server\n // callback (browser blocked fetch, mixed-content, port conflict) doesn't\n // block for the full server timeout before the CLI gets the token.\n const sessionPoll = (async () => {\n while (!stopPolling && Date.now() < expiresAt) {\n try {\n const result = await api.pollCliAuthSession(session.sessionId);\n if (result.status === \"complete\" || result.status === \"failed\") {\n return result;\n }\n } catch {\n // transient network error — keep trying\n }\n if (!stopPolling) await sleep(2000);\n }\n return null;\n })();\n\n // Three-way race: local server, polling, hard deadline\n const winner = await new Promise<\n | { kind: \"server\"; params: Record<string, string> }\n | {\n kind: \"poll\";\n result:\n | { status: \"complete\"; token: string; organizationId?: string }\n | { status: \"failed\"; reason: string };\n }\n | null\n >((resolve) => {\n let done = false;\n\n serverCallback\n .then((params) => {\n if (done || params === null || typeof params.token !== \"string\") return;\n done = true;\n resolve({ kind: \"server\", params });\n })\n .catch(() => {});\n\n sessionPoll\n .then((result) => {\n if (done || result === null) return;\n if (result.status === \"complete\" || result.status === \"failed\") {\n done = true;\n resolve({\n kind: \"poll\",\n result: result as\n | { status: \"complete\"; token: string; organizationId?: string }\n | { status: \"failed\"; reason: string },\n });\n }\n })\n .catch(() => {});\n\n setTimeout(\n () => {\n if (!done) {\n done = true;\n resolve(null);\n }\n },\n Math.max(0, deadline - Date.now()),\n );\n });\n\n stopPolling = true;\n server?.close();\n\n if (winner !== null) {\n if (winner.kind === \"server\") {\n rawToken = winner.params.token;\n if (\n typeof winner.params.organizationId === \"string\" &&\n winner.params.organizationId\n ) {\n callbackOrganizationId = winner.params.organizationId;\n }\n if (winner.params.discovery_ready === \"1\") {\n callbackDiscoveryReady = true;\n }\n } else if (winner.result.status === \"complete\") {\n rawToken = winner.result.token;\n if (winner.result.organizationId) {\n callbackOrganizationId = winner.result.organizationId;\n }\n } else {\n authSpinner.stop();\n p.log.error(winner.result.reason);\n return null;\n }\n }\n\n if (!rawToken) {\n authSpinner.stop();\n p.log.error(\"The authentication link expired. Run `vocoder init` again.\");\n return null;\n }\n\n // Validate the token and get user info\n const userInfo = await api.getCliUserInfo(rawToken);\n authSpinner.stop(`Authenticated as ${chalk.bold(userInfo.email)}`);\n\n return {\n token: rawToken,\n ...userInfo,\n organizationId: callbackOrganizationId,\n discoveryReady: callbackDiscoveryReady,\n };\n}\n\n// ── Main command ─────────────────────────────────────────────────────────────\n\nexport async function init(options: InitOptions = {}): Promise<number> {\n const apiUrl =\n options.apiUrl || process.env.VOCODER_API_URL || \"https://vocoder.app\";\n\n p.intro(chalk.bold(\"Vocoder Setup\"));\n\n try {\n // ── Detect git context ──────────────────────────────────────────────────\n const gitContext = resolveGitContext();\n const identity = gitContext.identity;\n\n if (gitContext.warnings.length > 0) {\n for (const warning of gitContext.warnings) {\n p.log.warn(warning);\n }\n }\n\n // ── Fast lookup: does a project already exist for this repo? ────────────\n // No spinner — this is a fast DB read and we don't want an empty ◇ on miss.\n let existingAppsForRepo: Array<{\n appDir: string;\n appId: string;\n projectId: string;\n projectName: string;\n organizationName: string;\n }> = [];\n let repoProjectId: string | null = null;\n let repoProjectName: string | null = null;\n let lookup: Awaited<ReturnType<VocoderAPI[\"lookupAppByRepo\"]>> | null =\n null;\n\n if (identity) {\n const anonApi = new VocoderAPI({ apiUrl, apiKey: \"\" });\n lookup = await anonApi.lookupAppByRepo({\n repoCanonical: identity.repoCanonical,\n appDir: \"\",\n });\n\n // Any apps found for this repo: unified \"project already set up\" routing.\n // All existingApps entries contain all configured apps for the repo.\n if (lookup.existingApps.length > 0) {\n const allApps = lookup.existingApps;\n const firstApp = allApps[0]!;\n\n p.log.success(`Project: ${chalk.bold(firstApp.projectName)}`);\n p.log.info(\n `Configured apps: ${allApps.map((a) => highlight(a.appDir || \"(entire repo)\")).join(\", \")}`,\n );\n\n const routeAction = await p.select<string>({\n message: \"This repo is already set up. What would you like to do?\",\n options: [\n { value: \"key\", label: \"Get an API key for this project\" },\n { value: \"add\", label: \"Add a new app directory\" },\n ],\n });\n\n if (p.isCancel(routeAction)) {\n p.cancel(\"Setup cancelled.\");\n return 1;\n }\n\n if (routeAction === \"key\") {\n const anonApi = new VocoderAPI({ apiUrl, apiKey: \"\" });\n const authResult = await runAuthFlow(anonApi, options, /* reauth */ true);\n if (!authResult) return 1;\n\n const spinner = p.spinner();\n spinner.start(\"Generating API key...\");\n let apiKey: string;\n try {\n ({ apiKey } = await anonApi.regenerateProjectApiKey(\n authResult.token,\n firstApp.projectId,\n ));\n spinner.stop(\"API key ready\");\n } catch (err) {\n spinner.stop(\"Failed to generate key\");\n const msg = err instanceof Error ? err.message : String(err);\n p.log.error(`Could not generate API key: ${msg}`);\n p.log.info(\"Try again or generate one from the dashboard.\");\n return 1;\n }\n\n printApiKey(apiKey, identity.repoRoot);\n\n const detection = detectLocalEcosystem();\n const targetBranches = lookup.exactMatch?.targetBranches ?? [\"main\"];\n writeAppConfigs(\n allApps.map((a) => ({ appDir: a.appDir, appId: a.appId })),\n targetBranches,\n detection.isTypeScript,\n identity.repoRoot,\n );\n\n p.outro(\"Vocoder is set up for this repository.\");\n return 0;\n }\n\n // \"add\" path: fall through to runAppCreate block below.\n existingAppsForRepo = allApps;\n repoProjectId = firstApp.projectId;\n repoProjectName = firstApp.projectName;\n }\n }\n\n // ── Auth: check stored token, prompt if missing ─────────────────────────\n const api = new VocoderAPI({ apiUrl, apiKey: \"\" });\n let userToken: string;\n let userEmail: string;\n let userName: string | null;\n\n // organizationId is set when auth+GitHub install completed in one browser trip\n let authOrganizationId: string | undefined;\n\n const storedAuth = await verifyStoredAuth(api);\n\n if (storedAuth.status === \"valid\") {\n p.log.success(`Authenticated as ${chalk.bold(storedAuth.email)}`);\n userToken = storedAuth.token;\n userEmail = storedAuth.email;\n userName = storedAuth.name;\n } else {\n // \"gone\" = user deleted from DB → full first-time flow (installUrl)\n // \"expired\" = token rejected → reauth via verificationUrl (no new org)\n // \"none\" = no stored token → full first-time flow (installUrl)\n const reauth = storedAuth.status === \"expired\";\n if (reauth) {\n p.log.warn(\"Stored credentials expired — signing in again\");\n } else if (storedAuth.status === \"gone\") {\n p.log.warn(\"Account not found — starting fresh setup\");\n }\n const authResult = await runAuthFlow(\n api,\n options,\n reauth,\n identity?.repoCanonical,\n );\n if (!authResult) return 1;\n userToken = authResult.token;\n userEmail = authResult.email;\n userName = authResult.name;\n authOrganizationId = authResult.organizationId;\n\n writeAuthData({\n token: userToken,\n userId: authResult.userId,\n email: userEmail,\n name: userName,\n createdAt: new Date().toISOString(),\n });\n }\n\n // ── Workspace selection ─────────────────────────────────────────────────────\n let selectedOrganizationId: string;\n let selectedOrganizationName: string;\n\n // Fast path: repo is already linked to a workspace in our DB (git connection\n // exists but no project yet). Skip GitHub installation selection entirely —\n // the user just needs to create their first project in the known workspace.\n const repoOrgContext = identity\n ? (lookup?.organizationContext ?? null)\n : null;\n\n if (authOrganizationId) {\n // Install path: auth+install completed in one browser trip, workspace already created.\n const organizationData = await api.listOrganizations(userToken);\n const ws = organizationData.organizations.find(\n (w) => w.id === authOrganizationId,\n );\n selectedOrganizationId = authOrganizationId;\n selectedOrganizationName = ws?.name ?? userEmail;\n p.log.success(\n `Connected as ${chalk.bold(userEmail)} — workspace: ${chalk.bold(selectedOrganizationName)}`,\n );\n } else if (repoOrgContext && !repoProjectId) {\n // Repo is already linked to a workspace (git connection exists) but no project\n // created yet. Skip GitHub installation selection — use the known workspace.\n selectedOrganizationId = repoOrgContext.organizationId;\n selectedOrganizationName = repoOrgContext.organizationName;\n p.log.success(`Workspace: ${chalk.bold(selectedOrganizationName)}`);\n } else {\n // ── Repo-aware workspace resolution ──────────────────────────────────────\n // Always resolve org membership first. cachedInstallations (fresh GitHub App\n // installs) are only consulted when the user has zero existing connections —\n // this prevents \"already connected to another organization\" errors for users\n // who have an org but haven't created a project yet.\n const organizationData = await api.listOrganizations(userToken, {\n repo: identity?.repoCanonical,\n });\n\n {\n const repoCanonical = identity?.repoCanonical ?? null;\n // Workspaces whose GitHub installation covers the current repo\n const covering = repoCanonical\n ? organizationData.organizations.filter((w) => w.coversRepo === true)\n : [];\n // Workspaces that have any GitHub connection (may not cover this repo)\n const connected = organizationData.organizations.filter(\n (w) => w.hasGitHubConnection,\n );\n\n if (repoCanonical && covering.length === 1) {\n // ── Scenario 1: exactly one workspace covers this repo — auto-select ──\n const ws = covering[0]!;\n selectedOrganizationId = ws.id;\n selectedOrganizationName = ws.name;\n p.log.success(`Workspace: ${chalk.bold(selectedOrganizationName)}`);\n } else if (repoCanonical && covering.length > 1) {\n // ── Scenario 2: multiple workspaces cover this repo — let user pick ──\n const choice = await p.select<string>({\n message: \"Select workspace for this repo\",\n options: covering.map((w) => ({\n value: w.id,\n label: `${w.name} ${chalk.dim(`(${w.appCount} app${w.appCount !== 1 ? \"s\" : \"\"})`)}`,\n })),\n });\n if (p.isCancel(choice)) {\n p.cancel(\"Setup cancelled.\");\n return 1;\n }\n const ws = covering.find((w) => w.id === choice)!;\n selectedOrganizationId = ws.id;\n selectedOrganizationName = ws.name;\n p.log.success(`Workspace: ${chalk.bold(selectedOrganizationName)}`);\n } else if (\n repoCanonical &&\n covering.length === 0 &&\n connected.length > 0\n ) {\n // ── Scenario 3: connected workspaces exist but none cover this repo ──\n const shortRepo = repoCanonical.split(\":\")[1] ?? repoCanonical;\n p.log.warn(\n `${chalk.bold(shortRepo)} isn't accessible from your Vocoder installation.\\n` +\n ` Grant access to this repository or install on the account that owns it.`,\n );\n\n const fixOptions: Array<{ value: string; label: string }> = [];\n for (const ws of connected) {\n if (ws.installationConfigureUrl) {\n fixOptions.push({\n value: `grant:${ws.id}`,\n label: `Configure ${chalk.bold(ws.connectionLabel ?? ws.name)}'s GitHub App installation`,\n });\n }\n }\n fixOptions.push({\n value: \"install_new\",\n label: `Install on a different GitHub account ${chalk.dim(\"(creates a new personal workspace)\")}`,\n });\n fixOptions.push({ value: \"cancel\", label: \"Cancel\" });\n\n const fix = await p.select<string>({\n message: \"How would you like to fix this?\",\n options: fixOptions,\n });\n\n if (p.isCancel(fix) || fix === \"cancel\") {\n p.cancel(\"Setup cancelled.\");\n return 1;\n }\n\n if (fix.startsWith(\"grant:\")) {\n const ws = connected.find((w) => `grant:${w.id}` === fix)!;\n await tryOpenBrowser(ws.installationConfigureUrl!);\n p.cancel(\n `Grant access to ${chalk.bold(shortRepo)} in your browser,\\n` +\n ` then re-run ${chalk.bold(\"vocoder init\")}.`,\n );\n return 1;\n }\n\n // install_new: full install → creates new workspace covering the new account\n const connectResult = await runGitHubInstallFlow({\n api,\n userToken,\n yes: options.yes,\n });\n if (!connectResult) {\n p.log.error(\n \"GitHub App installation did not complete. Run `vocoder init` again.\",\n );\n return 1;\n }\n selectedOrganizationId = connectResult.organizationId;\n selectedOrganizationName = connectResult.organizationName;\n p.log.success(`Workspace: ${chalk.bold(selectedOrganizationName)}`);\n } else {\n // ── Fallback: no existing connections — first-time user ───────────────\n // Only now check for a fresh cached GitHub App installation. We reach\n // this path only when covering === 0 && connected === 0, so claiming\n // a cached installation can never error with \"already connected\".\n const discoveryResult = await api\n .getCliGitHubDiscovery(userToken)\n .catch(() => null);\n const cachedInstallations = discoveryResult?.installations ?? [];\n\n if (cachedInstallations.length > 0) {\n if (identity?.repoCanonical) {\n const repoOwner = identity.repoCanonical\n .split(\":\")[1]\n ?.split(\"/\")[0]\n ?.toLowerCase();\n if (repoOwner) {\n const hasMatchingAccount = cachedInstallations.some(\n (i) => i.accountLogin.toLowerCase() === repoOwner,\n );\n if (!hasMatchingAccount) {\n p.log.warn(\n `None of your GitHub App installations belong to \"${repoOwner}\", ` +\n `the account that owns this repository.\\n` +\n ` The project will be created but translations won't trigger automatically.\\n` +\n ` To fix: install the Vocoder GitHub App on \"${repoOwner}\" instead.`,\n );\n }\n }\n }\n\n const validInstallations = cachedInstallations.filter(\n (i) => !i.isSuspended && !i.conflictLabel,\n );\n let selectedInstallationId: number | string | null = null;\n if (\n validInstallations.length === 1 &&\n cachedInstallations.length === 1\n ) {\n selectedInstallationId = validInstallations[0]!.installationId;\n } else {\n selectedInstallationId = await selectGitHubInstallation(\n cachedInstallations.map((inst) => ({\n installationId: inst.installationId,\n accountLogin: inst.accountLogin,\n accountType: inst.accountType,\n isSuspended: inst.isSuspended,\n conflictLabel: inst.conflictLabel,\n })),\n false,\n );\n }\n if (\n selectedInstallationId === null ||\n selectedInstallationId === \"install_new\"\n ) {\n p.cancel(\n \"Setup cancelled. Re-run `vocoder init` and choose Install GitHub App.\",\n );\n return 1;\n }\n const claimResult = await api.claimCliGitHubInstallation(\n userToken,\n {\n installationId: String(selectedInstallationId),\n organizationId: null,\n },\n );\n selectedOrganizationId = claimResult.organizationId;\n selectedOrganizationName = claimResult.organizationName;\n p.log.success(`Workspace: ${chalk.bold(selectedOrganizationName)}`);\n } else if (\n organizationData.organizations.length === 1 &&\n !organizationData.canCreateOrganization\n ) {\n const ws = organizationData.organizations[0]!;\n selectedOrganizationId = ws.id;\n selectedOrganizationName = ws.name;\n p.log.success(`Workspace: ${chalk.bold(selectedOrganizationName)}`);\n } else {\n const organizationResult =\n await selectOrganization(organizationData);\n\n if (organizationResult.action === \"cancelled\") {\n p.cancel(\"Setup cancelled.\");\n return 1;\n }\n\n if (organizationResult.action === \"use\") {\n selectedOrganizationId = organizationResult.organization.id;\n selectedOrganizationName = organizationResult.organization.name;\n p.log.success(\n `Workspace: ${chalk.bold(selectedOrganizationName)}`,\n );\n } else {\n // ── New workspace: GitHub connect flow ────────────────────────────────\n const connectChoice = await p.select<string>({\n message: \"Connect your new workspace to GitHub\",\n options: [\n { value: \"install\", label: \"Install the Vocoder GitHub App\" },\n { value: \"link\", label: \"Link an existing installation\" },\n ],\n });\n\n if (p.isCancel(connectChoice)) {\n p.cancel(\"Setup cancelled.\");\n return 1;\n }\n\n if (connectChoice === \"install\") {\n const connectResult = await runGitHubInstallFlow({\n api,\n userToken,\n yes: options.yes,\n });\n if (!connectResult) {\n p.log.error(\n \"GitHub App installation did not complete. Run `vocoder init` again.\",\n );\n return 1;\n }\n selectedOrganizationId = connectResult.organizationId;\n selectedOrganizationName = connectResult.organizationName;\n p.log.success(\n `Workspace: ${chalk.bold(selectedOrganizationName)}`,\n );\n } else {\n const installations = await runGitHubDiscoveryFlow({\n api,\n userToken,\n yes: options.yes,\n });\n if (!installations) return 1;\n\n if (installations.length === 0) {\n p.log.warn(\n \"No GitHub installations found. Install the Vocoder GitHub App first.\",\n );\n const installNow = await p.confirm({\n message: \"Open GitHub to install the App?\",\n });\n if (p.isCancel(installNow) || !installNow) return 1;\n const connectResult = await runGitHubInstallFlow({\n api,\n userToken,\n yes: options.yes,\n });\n if (!connectResult) return 1;\n selectedOrganizationId = connectResult.organizationId;\n selectedOrganizationName = connectResult.organizationName;\n } else {\n const selectedInstallationId = await selectGitHubInstallation(\n installations.map((inst) => ({\n installationId: inst.installationId,\n accountLogin: inst.accountLogin,\n accountType: inst.accountType,\n isSuspended: inst.isSuspended,\n conflictLabel: inst.conflictLabel,\n })),\n true,\n );\n\n if (selectedInstallationId === null) {\n p.cancel(\"Setup cancelled.\");\n return 1;\n }\n\n if (selectedInstallationId === \"install_new\") {\n const connectResult = await runGitHubInstallFlow({\n api,\n userToken,\n yes: options.yes,\n });\n if (!connectResult) return 1;\n selectedOrganizationId = connectResult.organizationId;\n selectedOrganizationName = connectResult.organizationName;\n } else {\n const claimResult = await api.claimCliGitHubInstallation(\n userToken,\n {\n installationId: String(selectedInstallationId),\n organizationId: null,\n },\n );\n selectedOrganizationId = claimResult.organizationId;\n selectedOrganizationName = claimResult.organizationName;\n }\n }\n p.log.success(\n `Workspace: ${chalk.bold(selectedOrganizationName)}`,\n );\n }\n } // closes new workspace else\n } // closes auto-select else\n } // closes main scenario if/else chain\n } // closes cachedInstallations else\n } // closes if (authOrganizationId) else\n\n // ── Add-app path: repo already has a project with scoped apps ───────────────\n // Skip plan limit check — we're adding an App to an existing project,\n // not creating a new one. Run the project config prompts then call\n // POST /api/cli/apps.\n if (repoProjectId && repoProjectName && existingAppsForRepo.length > 0) {\n const appResult = await runAppCreate({\n api,\n userToken,\n projectId: repoProjectId,\n projectName: repoProjectName,\n organizationName: selectedOrganizationName,\n repoCanonical: identity?.repoCanonical,\n existingApps: existingAppsForRepo,\n });\n\n if (!appResult) {\n p.log.error(\"App setup failed. Run `vocoder init` again.\");\n return 1;\n }\n\n const detection = detectLocalEcosystem();\n runScaffold({\n sourceLocale: appResult.sourceLocale,\n targetBranches: appResult.targetBranches,\n });\n writeAppConfigs(\n [{ appDir: appResult.appDir, appId: appResult.appId }],\n appResult.targetBranches,\n detection.isTypeScript,\n identity?.repoRoot,\n );\n p.log.info(\n chalk.dim(\"Use the VOCODER_API_KEY already in your root .env\"),\n );\n p.outro(\"You're all set.\");\n return 0;\n }\n\n // ── Plan limit pre-flight ────────────────────────────────────────────────────\n // Compute remaining app slots to enforce the limit in the app directory TUI.\n // Silently ignored on error — the server enforces the limit on creation too.\n let remainingApps: number | undefined;\n try {\n const wsCheck = await api.listOrganizations(userToken);\n const ws = wsCheck.organizations.find(\n (w) => w.id === selectedOrganizationId,\n );\n if (ws) {\n if (ws.maxApps !== -1 && ws.appCount >= ws.maxApps) {\n p.log.warn(\n `App limit reached — ${ws.appCount}/${ws.maxApps} on your ${chalk.bold(ws.planId)} plan.`,\n );\n\n const limitAction = await p.select<string>({\n message: \"What would you like to do?\",\n options: [\n { value: \"upgrade\", label: \"Upgrade plan\" },\n { value: \"cancel\", label: \"Cancel\" },\n ],\n });\n\n if (p.isCancel(limitAction) || limitAction === \"cancel\") {\n p.cancel(\"Setup cancelled.\");\n return 1;\n }\n\n await tryOpenBrowser(`${apiUrl}${SUBSCRIPTION_SETTINGS_PATH}`);\n p.cancel(\n \"Upgrade your plan in the browser, then re-run `vocoder init`.\",\n );\n return 1;\n }\n remainingApps = ws.maxApps === -1 ? undefined : Math.max(0, ws.maxApps - ws.appCount);\n }\n } catch {\n // Non-fatal — server enforces limits on creation\n }\n\n // ── Project configuration ────────────────────────────────────────────────────\n const projectResult = await runProjectCreate({\n api,\n userToken,\n organizationId: selectedOrganizationId,\n defaultName: identity?.repoCanonical\n ? identity.repoCanonical.split(\"/\").pop()\n : undefined,\n defaultSourceLocale: \"en\",\n repoCanonical: identity?.repoCanonical,\n repoRoot: identity?.repoRoot,\n defaultBranches: [\"main\"],\n maxAppDirs: remainingApps,\n });\n\n if (!projectResult) {\n p.log.error(\"Project creation failed. Run `vocoder init` again.\");\n return 1;\n }\n\n // Warn if the current repo isn't accessible to the GitHub App installation.\n // This means translations won't trigger on push until the App is granted access.\n if (!projectResult.repositoryBound && identity?.repoCanonical) {\n p.log.warn(\n `This repository isn't accessible to your GitHub App installation.\\n` +\n `Translations won't run automatically until you grant access.\\n\\n` +\n ` To fix: go to your GitHub App installation settings and add this\\n` +\n ` repository to the allowed list, or switch to \"All repositories\".\\n` +\n (projectResult.configureUrl\n ? `\\n ${chalk.dim(projectResult.configureUrl)}\\n`\n : \"\"),\n );\n }\n\n // ── Scaffold: ecosystem detection, install instructions, setup snippets ──────\n const detection = detectLocalEcosystem();\n runScaffold({\n sourceLocale: projectResult.sourceLocale,\n targetBranches: projectResult.targetBranches,\n });\n\n // ── Write per-app config files and the shared project key ────────────────────\n writeAppConfigs(\n projectResult.apps,\n projectResult.targetBranches,\n detection.isTypeScript,\n identity?.repoRoot,\n );\n printApiKey(projectResult.apiKey, identity?.repoRoot);\n\n p.outro(\"You're all set.\");\n return 0;\n } catch (error) {\n if (error instanceof Error) {\n if (isPlanLimitFailure(error.message)) {\n printPlanLimitMessage(apiUrl, error.message);\n return 1;\n }\n p.log.error(`Error: ${error.message}`);\n } else {\n p.log.error(\"Unknown setup error\");\n }\n\n return 1;\n }\n}\n","import { existsSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\n\n/**\n * Returns the path of an existing vocoder.config file in cwd, trying\n * .ts → .js → .json in order. Returns null when none is found.\n */\nexport function findExistingConfig(cwd: string = process.cwd()): string | null {\n\tfor (const name of [\n\t\t\"vocoder.config.ts\",\n\t\t\"vocoder.config.js\",\n\t\t\"vocoder.config.json\",\n\t]) {\n\t\tconst candidate = join(cwd, name);\n\t\tif (existsSync(candidate)) return candidate;\n\t}\n\treturn null;\n}\n\n/**\n * Write a vocoder.config file to cwd if one doesn't already exist.\n * Pass `useTypeScript: false` for plain-JS projects — writes vocoder.config.js\n * instead of vocoder.config.ts. The config content is identical; only the\n * file extension (and therefore the import style in the user's editor) differs.\n *\n * Returns the filename that was written, or null if the file already existed\n * or the write failed.\n */\n/**\n * Write a vocoder.config file to cwd if one doesn't already exist.\n * Pass `useTypeScript: false` for plain-JS projects — writes vocoder.config.js\n * instead of vocoder.config.ts. The config content is identical; only the\n * file extension (and therefore the import style in the user's editor) differs.\n *\n * Returns the filename that was written, or null if the file already existed\n * or the write failed.\n */\nexport function writeVocoderConfig(options: {\n\ttargetBranches?: string[];\n\tuseTypeScript?: boolean;\n\tcwd?: string;\n\t/** App ID to embed in the config — written by init, used by CLI to identify the app. */\n\tappId?: string;\n}): string | null {\n\tconst {\n\t\ttargetBranches = [\"main\"],\n\t\tuseTypeScript = true,\n\t\tcwd = process.cwd(),\n\t\tappId,\n\t} = options;\n\n\t// Don't write if any config variant already exists\n\tif (findExistingConfig(cwd)) return null;\n\n\tconst ext = useTypeScript ? \"ts\" : \"js\";\n\tconst configPath = join(cwd, `vocoder.config.${ext}`);\n\tconst branchesStr = targetBranches.map((b) => `'${b}'`).join(\", \");\n\n\t// Patterns are always relative to the config file's own directory.\n\t// In a monorepo, the config lives in the app subdirectory, so `**` naturally\n\t// scopes to that app — no `appDir/` prefix needed (and adding it would break\n\t// extraction when the CLI or build plugin runs with the app dir as cwd).\n\tconst includes = [\"**/*.{tsx,jsx,ts,js}\"];\n\tconst includesStr = includes.map((p) => `'${p}'`).join(\", \");\n\tconst appIdLine = appId ? ` appId: '${appId}',\\n` : \"\";\n\n\t// Both TS and JS use ESM import syntax — the content is identical.\n\t// TypeScript users get type-checking from defineConfig; JS users get\n\t// the same runtime behaviour with no TS toolchain required.\n\tconst content = `import { defineConfig } from '@vocoder/config'\n\nexport default defineConfig({\n${appIdLine} targetBranches: [${branchesStr}],\n include: [${includesStr}],\n})\n`;\n\n\ttry {\n\t\twriteFileSync(configPath, content, \"utf-8\");\n\t\treturn `vocoder.config.${ext}`;\n\t} catch {\n\t\treturn null;\n\t}\n}\n","import chalk from \"chalk\";\n\nconst ORANGE = \"#FC5206\";\nconst PINK = \"#D51977\";\nconst BLUE = \"#2450A9\";\n\nconst noColor = process.env.NO_COLOR === \"1\" || process.env.FORCE_COLOR === \"0\";\nconst hex = (color: string) => (s: string) =>\n\tnoColor ? s : chalk.hex(color)(s);\n\nexport const dim = (s: string) => (noColor ? s : chalk.dim(s));\nexport const bld = (s: string) => (noColor ? s : chalk.bold(s));\nexport const grn = (s: string) => (noColor ? s : chalk.green(s));\nexport const ylw = (s: string) => (noColor ? s : chalk.yellow(s));\nexport const red = (s: string) => (noColor ? s : chalk.red(s));\n\n/** Named values: file paths, locale codes, branch names, variable names */\nexport const highlight = hex(PINK);\n\n/** Structural info: bars, info logs, notes, links, selected checkmarks */\nexport const info = hex(BLUE);\n\n/** Brand identity: intro/outro text, active cursor ◆, spinner label accents */\nexport const active = hex(ORANGE);\n","import * as p from \"@clack/prompts\";\nimport chalk from \"chalk\";\nimport type { VocoderAPI } from \"./api.js\";\nimport { collectAppDirs, promptSingleAppDir } from \"./app-dir-select.js\";\nimport { detectGitBranches, filterableBranchSelect } from \"./branch-select.js\";\nimport type { LocaleOption } from \"./locale-search.js\";\nimport {\n\tsearchMultiSelectLocales,\n\tsearchSelectLocale,\n} from \"./locale-search.js\";\n\nexport interface ExistingApp {\n\tappDir: string;\n\tappId: string;\n\tprojectId: string;\n\tprojectName: string;\n\torganizationName: string;\n}\n\nexport interface ProjectCreateParams {\n\tapi: VocoderAPI;\n\tuserToken: string;\n\torganizationId: string;\n\t/** Default project name (repo name or directory name) */\n\tdefaultName?: string;\n\t/** Pre-detected source locale, e.g. \"en\" */\n\tdefaultSourceLocale?: string;\n\t/** Repo canonical for binding the project, e.g. \"github:owner/repo\" */\n\trepoCanonical?: string;\n\t/** Default target branches */\n\tdefaultBranches?: string[];\n\t/** Git repository root — used as base for app directory validation */\n\trepoRoot?: string;\n\t/**\n\t * Maximum number of app directories the user may add in this session.\n\t * Derived from the workspace's remaining app entitlement (maxApps - appCount).\n\t * Undefined means unlimited.\n\t */\n\tmaxAppDirs?: number;\n}\n\nexport interface AppCreateParams {\n\tapi: VocoderAPI;\n\tuserToken: string;\n\tprojectId: string;\n\tprojectName: string;\n\torganizationName: string;\n\trepoCanonical?: string;\n\t/** Existing apps to display and validate against */\n\texistingApps: ExistingApp[];\n}\n\nexport interface AppCreateResult {\n\tprojectId: string;\n\tprojectName: string;\n\tappDir: string;\n\tappId: string;\n\tsourceLocale: string;\n\ttargetLocales: string[];\n\ttargetBranches: string[];\n}\n\nexport interface ProjectCreateResult {\n\tprojectId: string;\n\tprojectName: string;\n\t/** Project-scoped API key (vcp_) — one key covers all apps in this project. */\n\tapiKey: string;\n\tsourceLocale: string;\n\ttargetLocales: string[];\n\ttargetBranches: string[];\n\trepositoryBound: boolean;\n\tconfigureUrl?: string;\n\t/** One entry per created app, each with its own appId for vocoder.config.ts. */\n\tapps: Array<{ appDir: string; appId: string }>;\n}\n\n/** All locales — used for target language selection. */\nfunction buildLocaleOptions(\n\tlocales: Array<{ code: string; name: string; nativeName?: string }>,\n): LocaleOption[] {\n\treturn locales.map((l) => ({\n\t\tbcp47: l.code,\n\t\tlabel: `${l.name} — ${l.code}`,\n\t}));\n}\n\n/**\n * Deduplicated language list — used for source language selection.\n * Groups locales by language family (prefix before first hyphen) and keeps one\n * representative per family, preferring the shortest/base code (e.g. \"en\" over\n * \"en-US\"). This prevents showing \"English\", \"English (American)\", \"English\n * (British)\" as three separate choices when the user just means \"English\".\n */\nfunction buildLanguageOptions(\n\tlocales: Array<{ code: string; name: string; nativeName?: string }>,\n): LocaleOption[] {\n\tconst byFamily = new Map<string, LocaleOption>();\n\n\tfor (const l of locales) {\n\t\tconst family = l.code.split(\"-\")[0]!.toLowerCase();\n\t\tconst opt: LocaleOption = { bcp47: l.code, label: `${l.name} — ${l.code}` };\n\t\tconst existing = byFamily.get(family);\n\t\t// Prefer base code (shorter, no region suffix) over regional variants\n\t\tif (!existing || l.code.length < existing.bcp47.length) {\n\t\t\tbyFamily.set(family, opt);\n\t\t}\n\t}\n\n\treturn Array.from(byFamily.values());\n}\n\n/**\n * Run the full project configuration TUI: prompts for app directories, source locale,\n * target locales, and target branches, then calls POST /api/cli/apps.\n *\n * Returns the created project info (including project-scoped API key and per-app IDs),\n * or null if cancelled.\n */\nexport async function runProjectCreate(\n\tparams: ProjectCreateParams,\n): Promise<ProjectCreateResult | null> {\n\tconst { api, userToken, organizationId, repoCanonical, repoRoot } = params;\n\n\t// ── Project name ────────────────────────────────────────────────────────────\n\t// Use the detected repo name automatically — no prompt needed.\n\tconst projectName = (params.defaultName ?? \"my-project\").trim();\n\tp.log.success(`Project: ${chalk.bold(projectName)}`);\n\n\t// ── Fetch source locales ────────────────────────────────────────────────────\n\tlet sourceLocales: Array<{ code: string; name: string; nativeName?: string }>;\n\ttry {\n\t\t({ sourceLocales } = await api.listLocales(userToken));\n\t} catch {\n\t\tp.log.error(\n\t\t\t\"Failed to fetch supported locales. Check your connection and try again.\",\n\t\t);\n\t\treturn null;\n\t}\n\n\tconst languageOptions = buildLanguageOptions(sourceLocales);\n\n\t// ── App directories (monorepo support) ──────────────────────────────────────\n\tconst appDirs = await collectAppDirs({ cwd: repoRoot, maxDirs: params.maxAppDirs });\n\tif (appDirs === null) return null;\n\n\tif (appDirs.length > 0) {\n\t\tp.log.success(`App directories: ${appDirs.map((d) => chalk.bold(d)).join(\", \")}`);\n\t}\n\n\t// ── Source locale ───────────────────────────────────────────────────────────\n\tconst sourceLocale = await searchSelectLocale(\n\t\tlanguageOptions,\n\t\t\"Source language (the language your code is written in)\",\n\t\tparams.defaultSourceLocale ?? \"en\",\n\t);\n\n\tif (sourceLocale === null) return null;\n\n\t// ── Compatible target locales (fetched after source is known) ───────────────\n\tlet compatibleTargets: Array<{ code: string; name: string; nativeName?: string }>;\n\ttry {\n\t\tcompatibleTargets = await api.listCompatibleLocales(userToken, sourceLocale);\n\t} catch {\n\t\tp.log.error(\n\t\t\t\"Failed to fetch compatible target locales. Check your connection and try again.\",\n\t\t);\n\t\treturn null;\n\t}\n\n\tconst localeOptions = buildLocaleOptions(compatibleTargets);\n\n\t// ── Target locales ──────────────────────────────────────────────────────────\n\tconst targetOptions = localeOptions.filter(\n\t\t(opt) => opt.bcp47 !== sourceLocale,\n\t);\n\n\tconst targetLocales = await searchMultiSelectLocales(\n\t\ttargetOptions,\n\t\t\"Target languages (languages to translate into)\",\n\t);\n\n\tif (targetLocales === null) return null;\n\n\tif (targetLocales.length === 0) {\n\t\tp.log.warn(\n\t\t\t\"No target languages selected — you can add them later from the dashboard.\",\n\t\t);\n\t}\n\n\t// ── Branch triggers ─────────────────────────────────────────────────────────\n\tconst detected = detectGitBranches();\n\tconst initialBranches = params.defaultBranches?.length\n\t\t? params.defaultBranches\n\t\t: [detected.defaultBranch];\n\n\tlet pushBranches: string[] = [];\n\t{\n\t\tlet initial = initialBranches;\n\t\twhile (pushBranches.length === 0) {\n\t\t\tconst result = await filterableBranchSelect({\n\t\t\t\tmessage: \"Which branches should trigger translations?\",\n\t\t\t\tbranches: detected.branches,\n\t\t\t\tdefaultBranch: detected.defaultBranch,\n\t\t\t\tinitialValues: initial,\n\t\t\t});\n\t\t\tif (result === null) return null;\n\t\t\tif (result.length === 0) {\n\t\t\t\tp.log.warn(\n\t\t\t\t\t\"At least one branch is required. Please select at least one.\",\n\t\t\t\t);\n\t\t\t\tinitial = [detected.defaultBranch];\n\t\t\t} else {\n\t\t\t\tpushBranches = result;\n\t\t\t}\n\t\t}\n\t}\n\n\tconst targetBranches = pushBranches;\n\n\t// ── Create project ──────────────────────────────────────────────────────────\n\ttry {\n\t\tconst result = await api.createProject(userToken, {\n\t\t\torganizationId,\n\t\t\tname: projectName,\n\t\t\tsourceLocale,\n\t\t\ttargetLocales,\n\t\t\ttargetBranches,\n\t\t\tappDirs,\n\t\t\trepoCanonical,\n\t\t});\n\n\t\tp.log.success(`Project ${chalk.bold(result.projectName)} created!`);\n\t\treturn {\n\t\t\tprojectId: result.projectId,\n\t\t\tprojectName: result.projectName,\n\t\t\tapiKey: result.apiKey,\n\t\t\tsourceLocale,\n\t\t\ttargetLocales,\n\t\t\ttargetBranches,\n\t\t\trepositoryBound: result.repositoryBound,\n\t\t\tconfigureUrl: result.configureUrl,\n\t\t\tapps: result.apps,\n\t\t};\n\t} catch (error) {\n\t\tconst message = error instanceof Error ? error.message : \"Unknown error\";\n\t\tp.log.error(`Failed to create project: ${message}`);\n\t\treturn null;\n\t}\n}\n\n/**\n * Configure and create a new App under an existing project.\n * Used when the repo already has a project (monorepo: adding a new app directory).\n * No plan limit check runs — only a new App is created, not a new Project.\n */\nexport async function runAppCreate(\n\tparams: AppCreateParams,\n): Promise<AppCreateResult | null> {\n\tconst { api, userToken, projectId, projectName, repoCanonical } = params;\n\tconst existingDirs = params.existingApps.map((a) => a.appDir);\n\n\t// ── App directory ───────────────────────────────────────────────────────────\n\tconst appDir = await promptSingleAppDir({ existingDirs });\n\tif (appDir === null) return null;\n\tif (appDir) {\n\t\tp.log.success(`App directory: ${chalk.bold(appDir)}`);\n\t}\n\n\t// ── Fetch source locales ────────────────────────────────────────────────────\n\tlet sourceLocales: Array<{ code: string; name: string; nativeName?: string }>;\n\ttry {\n\t\t({ sourceLocales } = await api.listLocales(userToken));\n\t} catch {\n\t\tp.log.error(\n\t\t\t\"Failed to fetch supported locales. Check your connection and try again.\",\n\t\t);\n\t\treturn null;\n\t}\n\n\tconst languageOptions = buildLanguageOptions(sourceLocales);\n\n\t// ── Source locale ───────────────────────────────────────────────────────────\n\tconst sourceLocale = await searchSelectLocale(\n\t\tlanguageOptions,\n\t\t\"Source language\",\n\t\t\"en\",\n\t);\n\tif (sourceLocale === null) return null;\n\n\t// ── Compatible target locales (fetched after source is known) ───────────────\n\tlet compatibleTargets: Array<{ code: string; name: string; nativeName?: string }>;\n\ttry {\n\t\tcompatibleTargets = await api.listCompatibleLocales(userToken, sourceLocale);\n\t} catch {\n\t\tp.log.error(\n\t\t\t\"Failed to fetch compatible target locales. Check your connection and try again.\",\n\t\t);\n\t\treturn null;\n\t}\n\n\t// ── Target locales ──────────────────────────────────────────────────────────\n\tconst targetOptions = buildLocaleOptions(compatibleTargets).filter(\n\t\t(opt) => opt.bcp47 !== sourceLocale,\n\t);\n\tconst targetLocales = await searchMultiSelectLocales(\n\t\ttargetOptions,\n\t\t\"Target languages\",\n\t);\n\tif (targetLocales === null) return null;\n\tif (targetLocales.length === 0) {\n\t\tp.log.warn(\n\t\t\t\"No target languages selected — you can add them later from the dashboard.\",\n\t\t);\n\t}\n\n\t// ── Branch triggers ─────────────────────────────────────────────────────────\n\tconst detectedApp = detectGitBranches();\n\n\tlet appPushBranches: string[] = [];\n\t{\n\t\tlet initial = [detectedApp.defaultBranch];\n\t\twhile (appPushBranches.length === 0) {\n\t\t\tconst result = await filterableBranchSelect({\n\t\t\t\tmessage: \"Which branches should trigger translations?\",\n\t\t\t\tbranches: detectedApp.branches,\n\t\t\t\tdefaultBranch: detectedApp.defaultBranch,\n\t\t\t\tinitialValues: initial,\n\t\t\t});\n\t\t\tif (result === null) return null;\n\t\t\tif (result.length === 0) {\n\t\t\t\tp.log.warn(\"At least one branch is required.\");\n\t\t\t\tinitial = [detectedApp.defaultBranch];\n\t\t\t} else {\n\t\t\t\tappPushBranches = result;\n\t\t\t}\n\t\t}\n\t}\n\n\tconst targetBranches = appPushBranches;\n\n\t// ── Create the App ─────────────────────────────────────────────────────────\n\ttry {\n\t\tconst result = await api.createApp(userToken, {\n\t\t\tprojectId,\n\t\t\tappDir,\n\t\t\tsourceLocale,\n\t\t\ttargetLocales,\n\t\t\ttargetBranches,\n\t\t\trepoCanonical: repoCanonical ?? \"\",\n\t\t});\n\n\t\tp.log.success(\n\t\t\t`App ${chalk.bold(appDir || \"(root)\")} added to ${chalk.bold(projectName)}!`,\n\t\t);\n\t\treturn {\n\t\t\tprojectId: result.projectId,\n\t\t\tprojectName: result.projectName,\n\t\t\tappDir: result.appDir,\n\t\t\tappId: result.appId,\n\t\t\tsourceLocale,\n\t\t\ttargetLocales,\n\t\t\ttargetBranches,\n\t\t};\n\t} catch (error) {\n\t\tconst message = error instanceof Error ? error.message : \"Unknown error\";\n\t\tp.log.error(`Failed to add app: ${message}`);\n\t\treturn null;\n\t}\n}\n","import { existsSync, statSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport { isCancel, Prompt } from \"@clack/core\";\nimport * as p from \"@clack/prompts\";\nimport { active, bld, dim, grn, info, red, ylw } from \"./theme.js\";\n\n// ── Symbols ───────────────────────────────────────────────────────────────────\n\nconst S_BAR = \"│\";\nconst S_BAR_END = \"└\";\nconst S_ACTIVE = \"◆\";\nconst S_SUBMIT = \"◆\";\nconst S_CANCEL = \"■\";\nconst S_ERROR = \"▲\";\n\nfunction symbol(state: string): string {\n\tswitch (state) {\n\t\tcase \"submit\":\n\t\t\treturn grn(S_SUBMIT);\n\t\tcase \"cancel\":\n\t\t\treturn red(S_CANCEL);\n\t\tcase \"error\":\n\t\t\treturn ylw(S_ERROR);\n\t\tdefault:\n\t\t\treturn active(S_ACTIVE);\n\t}\n}\n\n// ── Validation ────────────────────────────────────────────────────────────────\n\n/**\n * Validate an app directory path. Returns an error string or null if valid.\n * Checks path safety, mutual exclusion invariant, and filesystem existence.\n */\nexport function validateAppDirPath(\n\tval: string,\n\texisting: string[],\n\topts: { cwd?: string } = {},\n): string | null {\n\tif (val.startsWith(\"/\")) return \"Must be a relative path (e.g. apps/web)\";\n\tif (val.includes(\"..\")) return \"Path traversal not allowed\";\n\n\tconst hasWholeRepo = existing.includes(\"\");\n\tconst hasScoped = existing.some((d) => d !== \"\");\n\tif (val === \"\" && hasScoped) return \"Cannot add whole-repo scope to a monorepo project\";\n\tif (val !== \"\" && hasWholeRepo) return \"Cannot add a scoped directory to a whole-repo project\";\n\tif (existing.includes(val)) return `Already added: ${val}`;\n\n\t// Reject nested paths — e.g. adding \"apps\" when \"apps/vite\" already exists (or vice versa)\n\tconst nested = existing.find(\n\t\t(d) => d !== \"\" && (val.startsWith(d + \"/\") || d.startsWith(val + \"/\")),\n\t);\n\tif (nested) return `\"${val}\" overlaps with already-added \"${nested}\"`;\n\n\tif (val !== \"\") {\n\t\tconst abs = resolve(opts.cwd ?? process.cwd(), val);\n\t\tif (!existsSync(abs)) return `Directory not found: ${val}`;\n\t\tif (!statSync(abs).isDirectory()) return `Not a directory: ${val}`;\n\t}\n\n\treturn null;\n}\n\n// ── collectAppDirs ────────────────────────────────────────────────────────────\n\n/**\n * Interactively collect app directory paths from the user for monorepo projects.\n *\n * Type a path → press Space to add it. Navigate ↑↓ to existing dirs and press\n * Space to remove. Press Enter when done. An empty submission (no dirs added)\n * means single-app / whole-repo project.\n *\n * @param opts.maxDirs - Maximum directories the user may add. When reached the\n * Space key is blocked and the render shows \"App limit reached (N/N on your\n * plan)\" in place of the add affordance. The server also enforces this limit\n * on creation — this is a UX-level guard to surface the constraint early.\n *\n * Returns the collected directories, or null if the user cancels.\n */\nexport async function collectAppDirs(opts: { cwd?: string; maxDirs?: number } = {}): Promise<string[] | null> {\n\tconst added: string[] = [];\n\tlet filter = \"\";\n\tlet cursor = 0;\n\tlet addCursor = false;\n\n\tconst isNewDir = () => {\n\t\tconst t = filter.trim();\n\t\treturn t.length > 0 && !added.includes(t);\n\t};\n\n\tconst clampCursor = () => {\n\t\tconst max = added.length - 1;\n\t\tif (cursor > max) cursor = Math.max(0, max);\n\t};\n\n\tconst prompt = new (Prompt as any)(\n\t\t{\n\t\t\tvalidate() {\n\t\t\t\treturn undefined;\n\t\t\t},\n\t\t\trender(this: { state: string; error: string }) {\n\t\t\t\tconst trimmed = filter.trim();\n\t\t\t\tconst hdr = `${dim(S_BAR)}\\n${symbol(this.state)} App directories\\n`;\n\n\t\t\t\tswitch (this.state) {\n\t\t\t\t\tcase \"submit\": {\n\t\t\t\t\t\tconst summary =\n\t\t\t\t\t\t\tadded.length > 0\n\t\t\t\t\t\t\t\t? bld(added.join(\", \"))\n\t\t\t\t\t\t\t\t: dim(\"none (single-app project)\");\n\t\t\t\t\t\treturn `${hdr}${dim(S_BAR)} ${summary}`;\n\t\t\t\t\t}\n\t\t\t\t\tcase \"cancel\":\n\t\t\t\t\t\treturn `${hdr}${dim(S_BAR)}`;\n\t\t\t\t\tdefault: {\n\t\t\t\t\t\tconst inputHint =\n\t\t\t\t\t\t\tfilter.length > 0\n\t\t\t\t\t\t\t\t? filter\n\t\t\t\t\t\t\t\t: added.length === 0\n\t\t\t\t\t\t\t\t\t? dim(\"e.g. apps/web\")\n\t\t\t\t\t\t\t\t\t: dim(\"e.g. apps/api\");\n\n\t\t\t\t\t\tconst lines: string[] = [\n\t\t\t\t\t\t\thdr.trimEnd(),\n\t\t\t\t\t\t\t`${info(S_BAR)} ${dim(\"/\")} ${inputHint}`,\n\t\t\t\t\t\t\tinfo(S_BAR),\n\t\t\t\t\t\t];\n\n\t\t\t\t\t\tfor (let i = 0; i < added.length; i++) {\n\t\t\t\t\t\t\tconst isCursor = i === cursor && !addCursor;\n\t\t\t\t\t\t\tconst icon = isCursor ? active(\"◼\") : info(\"◼\");\n\t\t\t\t\t\t\tconst label = isCursor ? bld(added[i]!) : added[i]!;\n\t\t\t\t\t\t\tlines.push(`${info(S_BAR)} ${icon} ${label}`);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst atLimit = opts.maxDirs !== undefined && added.length >= opts.maxDirs;\n\t\t\t\t\t\tif (atLimit) {\n\t\t\t\t\t\t\tlines.push(`${info(S_BAR)} ${dim(`App limit reached (${added.length}/${opts.maxDirs} on your plan)`)}`);\n\t\t\t\t\t\t} else if (isNewDir()) {\n\t\t\t\t\t\t\tconst err = validateAppDirPath(trimmed, added, opts);\n\t\t\t\t\t\t\tconst icon = addCursor ? active(\"◻\") : dim(\"◻\");\n\t\t\t\t\t\t\tconst label = err\n\t\t\t\t\t\t\t\t? `${ylw(\"+\")} ${dim(`\"${trimmed}\" — ${err}`)}`\n\t\t\t\t\t\t\t\t: `${grn(\"+\")} Add \"${trimmed}\"`;\n\t\t\t\t\t\t\tlines.push(`${info(S_BAR)} ${icon} ${label}`);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tlines.push(info(S_BAR));\n\n\t\t\t\t\t\tif (atLimit) {\n\t\t\t\t\t\t\tlines.push(dim(`${S_BAR} ↑↓ to select, Space to remove · Enter to confirm`));\n\t\t\t\t\t\t} else if (added.length === 0 && !isNewDir()) {\n\t\t\t\t\t\t\tlines.push(dim(`${S_BAR} Monorepo? Type each app's subdirectory path and press Space.`));\n\t\t\t\t\t\t\tlines.push(dim(`${S_BAR} Single app? Press Enter to skip this step.`));\n\t\t\t\t\t\t} else if (added.length > 0) {\n\t\t\t\t\t\t\tlines.push(dim(`${S_BAR} ${added.length} added · ↑↓ to select, Space to remove · Enter to confirm`));\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst barEnd =\n\t\t\t\t\t\t\tthis.state === \"error\" ? ylw(S_BAR_END) : info(S_BAR_END);\n\t\t\t\t\t\tif (this.state === \"error\") {\n\t\t\t\t\t\t\tlines.push(`${ylw(S_BAR_END)} ${ylw(this.error)}`);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tlines.push(barEnd);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tlines.push(\"\");\n\t\t\t\t\t\treturn lines.join(\"\\n\");\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t\tfalse,\n\t) as InstanceType<typeof Prompt> & { value: unknown; state: string };\n\n\tprompt.on(\"key\", (key: string | undefined) => {\n\t\tif (!key || key === \" \") return;\n\t\tconst cp = key.codePointAt(0) ?? 0;\n\t\tif (cp === 0x7f || cp === 0x08) {\n\t\t\tfilter = filter.slice(0, -1);\n\t\t\taddCursor = false;\n\t\t} else if (cp >= 32 && cp !== 127) {\n\t\t\tfilter += key;\n\t\t\tcursor = 0;\n\t\t\taddCursor = false;\n\t\t}\n\t});\n\n\tprompt.on(\"cursor\", (action: string | undefined) => {\n\t\tswitch (action) {\n\t\t\tcase \"up\":\n\t\t\t\tif (addCursor) {\n\t\t\t\t\taddCursor = false;\n\t\t\t\t\tcursor = Math.max(0, added.length - 1);\n\t\t\t\t} else {\n\t\t\t\t\tcursor = Math.max(0, cursor - 1);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase \"down\":\n\t\t\t\tif (!addCursor && cursor >= added.length - 1 && isNewDir()) {\n\t\t\t\t\taddCursor = true;\n\t\t\t\t} else if (!addCursor) {\n\t\t\t\t\tcursor = Math.min(added.length - 1, cursor + 1);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase \"space\": {\n\t\t\t\tif (addCursor || (filter.trim().length > 0 && isNewDir())) {\n\t\t\t\t\tif (opts.maxDirs !== undefined && added.length >= opts.maxDirs) break;\n\t\t\t\t\tconst trimmed = filter.trim();\n\t\t\t\t\tconst err = validateAppDirPath(trimmed, added, opts);\n\t\t\t\t\tif (!err) {\n\t\t\t\t\t\tadded.push(trimmed);\n\t\t\t\t\t\tfilter = \"\";\n\t\t\t\t\t\taddCursor = false;\n\t\t\t\t\t\tcursor = 0;\n\t\t\t\t\t}\n\t\t\t\t} else if (added.length > 0 && !isNewDir()) {\n\t\t\t\t\tclampCursor();\n\t\t\t\t\tadded.splice(cursor, 1);\n\t\t\t\t\tif (cursor >= added.length) cursor = Math.max(0, added.length - 1);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t});\n\n\tprompt.on(\"finalize\", () => {\n\t\tif ((prompt as any).state === \"submit\") {\n\t\t\t(prompt as any).value = [...added];\n\t\t}\n\t});\n\n\tconst result = await prompt.prompt();\n\tif (isCancel(result)) return null;\n\treturn result as string[];\n}\n\n// ── promptSingleAppDir ────────────────────────────────────────────────────────\n\n/**\n * Prompt the user for a single app directory to add to an existing project.\n *\n * Validates path safety, filesystem existence, and the monorepo/whole-repo\n * mutual exclusion invariant against the provided existing directories.\n *\n * Returns the entered directory string, or null if the user cancels.\n */\nexport async function promptSingleAppDir(params: {\n\texistingDirs: string[];\n\tcwd?: string;\n}): Promise<string | null> {\n\tconst { existingDirs, cwd } = params;\n\n\tconst input = await p.text({\n\t\tmessage: \"App directory to add\",\n\t\tplaceholder: \"apps/web\",\n\t\tvalidate(val) {\n\t\t\t// Mutual exclusion checked before required — empty string is a valid whole-repo intent\n\t\t\tconst err = validateAppDirPath(val ?? \"\", existingDirs, { cwd });\n\t\t\tif (err) return err;\n\t\t\tif (!val) return \"Directory is required\";\n\t\t\treturn undefined;\n\t\t},\n\t});\n\n\tif (p.isCancel(input)) return null;\n\treturn input as string;\n}\n","import { execSync } from \"node:child_process\";\nimport { isCancel, Prompt } from \"@clack/core\";\nimport { active, bld, dim, grn, info, red, ylw } from \"./theme.js\";\n\n// ── Symbols ───────────────────────────────────────────────────────────────────\n\nconst S_BAR = \"│\";\nconst S_BAR_END = \"└\";\nconst S_ACTIVE = \"◆\";\nconst S_SUBMIT = \"◆\";\nconst S_CANCEL = \"■\";\nconst S_ERROR = \"▲\";\n\nfunction symbol(state: string): string {\n\tswitch (state) {\n\t\tcase \"submit\":\n\t\t\treturn grn(S_SUBMIT);\n\t\tcase \"cancel\":\n\t\t\treturn red(S_CANCEL);\n\t\tcase \"error\":\n\t\t\treturn ylw(S_ERROR);\n\t\tdefault:\n\t\t\treturn active(S_ACTIVE);\n\t}\n}\n\n// ── Git detection ─────────────────────────────────────────────────────────────\n\nexport interface DetectedBranches {\n\tbranches: string[];\n\tdefaultBranch: string;\n}\n\nexport function detectGitBranches(cwd?: string): DetectedBranches {\n\tconst workDir = cwd ?? process.cwd();\n\ttry {\n\t\t// Local branches\n\t\tconst localOut = execSync(\"git branch\", {\n\t\t\tcwd: workDir,\n\t\t\tstdio: \"pipe\",\n\t\t}).toString();\n\t\tconst localBranches = localOut\n\t\t\t.split(\"\\n\")\n\t\t\t.filter(Boolean)\n\t\t\t.map((b) => b.replace(/^\\*?\\s*/, \"\").trim())\n\t\t\t.filter(Boolean);\n\n\t\t// Remote branches (strip \"origin/\" prefix, skip HEAD pointer)\n\t\tlet remoteBranches: string[] = [];\n\t\ttry {\n\t\t\tconst remoteOut = execSync(\"git branch -r\", {\n\t\t\t\tcwd: workDir,\n\t\t\t\tstdio: \"pipe\",\n\t\t\t}).toString();\n\t\t\tremoteBranches = remoteOut\n\t\t\t\t.split(\"\\n\")\n\t\t\t\t.map((b) => b.trim())\n\t\t\t\t.filter((b) => b && !b.includes(\"HEAD\"))\n\t\t\t\t.map((b) => b.replace(/^[^/]+\\//, \"\")); // strip \"origin/\" (or any remote name)\n\t\t} catch {\n\t\t\t/* no remote */\n\t\t}\n\n\t\tconst branches = [...new Set([...localBranches, ...remoteBranches])].sort();\n\n\t\t// Default branch: ask git for origin's HEAD (local cache, no network call).\n\t\t// Falls back to 'main' if the remote HEAD isn't cached.\n\t\tlet defaultBranch = \"main\";\n\t\ttry {\n\t\t\tconst ref = execSync(\"git symbolic-ref refs/remotes/origin/HEAD\", {\n\t\t\t\tcwd: workDir,\n\t\t\t\tstdio: \"pipe\",\n\t\t\t})\n\t\t\t\t.toString()\n\t\t\t\t.trim();\n\t\t\t// ref = \"refs/remotes/origin/main\"\n\t\t\tdefaultBranch = ref.split(\"/\").pop() ?? \"main\";\n\t\t} catch {\n\t\t\t/* HEAD not cached — run \"git remote set-head origin --auto\" to fix */\n\t\t}\n\n\t\treturn {\n\t\t\tbranches: branches.length > 0 ? branches : [defaultBranch],\n\t\t\tdefaultBranch,\n\t\t};\n\t} catch {\n\t\treturn { branches: [\"main\"], defaultBranch: \"main\" };\n\t}\n}\n\n// ── Validation ────────────────────────────────────────────────────────────────\n\nconst INVALID_CHARS = /[\\s?^~:[\\]\\\\]/;\n\nexport function validateBranchPattern(pattern: string): string | null {\n\tconst t = pattern.trim();\n\tif (!t) return \"Pattern cannot be empty\";\n\tif (INVALID_CHARS.test(t))\n\t\treturn \"Invalid characters — avoid spaces, ?, ^, ~, :, [, ], \\\\\";\n\tif (t.startsWith(\"/\") || t.endsWith(\"/\")) return \"Cannot start or end with /\";\n\tif (t.includes(\"//\")) return \"Cannot contain //\";\n\treturn null;\n}\n\n// ── List renderer ─────────────────────────────────────────────────────────────\n\nconst MAX_VISIBLE = 10;\nconst _ADD_PATTERN_VALUE = \"__add__\";\n\ninterface BranchItem {\n\tvalue: string;\n\tlabel: string;\n\tisCustom?: boolean;\n}\n\nfunction buildItems(\n\tbranches: string[],\n\tdefaultBranch: string,\n\tcustomPatterns: string[],\n): BranchItem[] {\n\tconst items: BranchItem[] = branches.map((b) => ({\n\t\tvalue: b,\n\t\tlabel: b === defaultBranch ? `${b} (default branch)` : b,\n\t}));\n\tfor (const pt of customPatterns) {\n\t\tif (!branches.includes(pt)) {\n\t\t\titems.push({ value: pt, label: pt, isCustom: true });\n\t\t}\n\t}\n\treturn items;\n}\n\nfunction filterItems(items: BranchItem[], query: string): BranchItem[] {\n\tif (!query.trim()) return items;\n\tconst lower = query.toLowerCase();\n\treturn items.filter((i) => i.value.toLowerCase().includes(lower));\n}\n\nfunction buildList(\n\tfiltered: BranchItem[],\n\tcursor: number,\n\tscrollOffset: number,\n\tselected: Set<string>,\n\tfilter: string,\n\tcustomPatterns: string[],\n\taddCursor: boolean,\n\texcludedPatterns: Set<string> = new Set(),\n): string {\n\tconst lines: string[] = [info(S_BAR)];\n\tconst end = Math.min(filtered.length, scrollOffset + MAX_VISIBLE);\n\n\tfor (let i = scrollOffset; i < end; i++) {\n\t\tconst item = filtered[i]!;\n\t\tconst isCursor = i === cursor && !addCursor;\n\t\tconst isChecked = selected.has(item.value);\n\n\t\tconst icon = isChecked\n\t\t\t? isCursor\n\t\t\t\t? info(\"◼\")\n\t\t\t\t: info(\"◼\")\n\t\t\t: isCursor\n\t\t\t\t? active(\"◻\")\n\t\t\t\t: dim(\"◻\");\n\n\t\tlet label = item.isCustom ? `${item.label} ${dim(\"(custom)\")}` : item.label;\n\t\tif (isCursor) label = bld(label);\n\n\t\tlines.push(`${info(S_BAR)} ${icon} ${label}`);\n\t}\n\n\t// \"Add pattern\" option\n\tconst trimmed = filter.trim();\n\tconst isNewPattern =\n\t\ttrimmed.length > 0 &&\n\t\t!filtered.some((i) => i.value === trimmed) &&\n\t\t!customPatterns.includes(trimmed);\n\n\tif (isNewPattern) {\n\t\tconst err =\n\t\t\tvalidateBranchPattern(trimmed) ??\n\t\t\t(excludedPatterns.has(trimmed)\n\t\t\t\t? \"Already used for automatic translation\"\n\t\t\t\t: null);\n\t\tconst icon = addCursor ? active(\"◻\") : dim(\"◻\");\n\t\tconst label = err\n\t\t\t? `${ylw(\"+\")} ${dim(`\"${trimmed}\" — ${err}`)}`\n\t\t\t: `${grn(\"+\")} Add \"${trimmed}\" as branch pattern`;\n\t\tlines.push(`${info(S_BAR)} ${icon} ${label}`);\n\t} else if (filtered.length === 0 && trimmed.length === 0) {\n\t\tlines.push(dim(`${S_BAR} No branches detected`));\n\t}\n\n\tconst hidden = filtered.length - (end - scrollOffset);\n\tif (hidden > 0) lines.push(dim(`${S_BAR} ${hidden} more`));\n\n\treturn lines.join(\"\\n\");\n}\n\n// ── Component ─────────────────────────────────────────────────────────────────\n\nexport async function filterableBranchSelect(params: {\n\tmessage: string;\n\tbranches: string[];\n\tdefaultBranch: string;\n\tinitialValues?: string[];\n\t/** When true, empty selection is accepted (Enter = skip) */\n\toptional?: boolean;\n\t/** Branches already claimed by other trigger types — block custom entry of these */\n\texcludedPatterns?: string[];\n}): Promise<string[] | null> {\n\tconst { message, branches, defaultBranch } = params;\n\tconst optional = params.optional ?? false;\n\tconst excludedSet = new Set(params.excludedPatterns ?? []);\n\n\tlet filter = \"\";\n\tlet cursor = 0;\n\tlet scrollOffset = 0;\n\tlet addCursor = false;\n\tconst customPatterns: string[] = [];\n\tconst selected = new Set<string>(params.initialValues ?? [defaultBranch]);\n\n\tconst getItems = () => buildItems(branches, defaultBranch, customPatterns);\n\tconst getFiltered = () => filterItems(getItems(), filter);\n\n\tconst isNewPattern = () => {\n\t\tconst t = filter.trim();\n\t\tif (!t) return false;\n\t\treturn (\n\t\t\t!getItems().some((i) => i.value === t) && !customPatterns.includes(t)\n\t\t);\n\t};\n\n\tconst clampCursor = (filtered: BranchItem[]) => {\n\t\tconst hasAdd = isNewPattern();\n\t\tconst max = filtered.length - 1 + (hasAdd ? 1 : 0);\n\t\tif (cursor > max && !addCursor) cursor = Math.max(0, max);\n\t\tif (!addCursor) {\n\t\t\tif (cursor < scrollOffset) scrollOffset = cursor;\n\t\t\tif (cursor >= scrollOffset + MAX_VISIBLE)\n\t\t\t\tscrollOffset = cursor - MAX_VISIBLE + 1;\n\t\t\tif (scrollOffset < 0) scrollOffset = 0;\n\t\t}\n\t};\n\n\tconst prompt = new (Prompt as any)(\n\t\t{\n\t\t\tvalidate() {\n\t\t\t\tif (!optional && selected.size === 0)\n\t\t\t\t\treturn \"At least one branch is required.\";\n\t\t\t\treturn undefined;\n\t\t\t},\n\t\t\trender(this: { state: string; error: string }) {\n\t\t\t\tconst filtered = getFiltered();\n\t\t\t\tclampCursor(filtered);\n\n\t\t\t\tconst hdr = `${dim(S_BAR)}\\n${symbol(this.state)} ${message}\\n`;\n\t\t\t\tconst inputHint =\n\t\t\t\t\tfilter.length > 0\n\t\t\t\t\t\t? filter\n\t\t\t\t\t\t: dim(\"type to filter · type a custom pattern to add it\");\n\n\t\t\t\tconst footer =\n\t\t\t\t\tselected.size > 0\n\t\t\t\t\t\t? dim(`${S_BAR} ${selected.size} selected · ↑↓ navigate · Space to select · Enter to confirm`)\n\t\t\t\t\t\t: optional\n\t\t\t\t\t\t\t? dim(`${S_BAR} ↑↓ navigate · Space to select · Enter to skip`)\n\t\t\t\t\t\t\t: dim(`${S_BAR} ↑↓ navigate · Space to select · Enter to confirm`);\n\n\t\t\t\tswitch (this.state) {\n\t\t\t\t\tcase \"submit\": {\n\t\t\t\t\t\tconst summary =\n\t\t\t\t\t\t\tselected.size > 0\n\t\t\t\t\t\t\t\t? bld(Array.from(selected).join(\", \"))\n\t\t\t\t\t\t\t\t: dim(\"none\");\n\t\t\t\t\t\treturn `${hdr}${dim(S_BAR)} ${summary}`;\n\t\t\t\t\t}\n\t\t\t\t\tcase \"cancel\":\n\t\t\t\t\t\treturn `${hdr}${dim(S_BAR)}`;\n\t\t\t\t\tcase \"error\":\n\t\t\t\t\t\treturn [\n\t\t\t\t\t\t\thdr.trimEnd(),\n\t\t\t\t\t\t\t`${ylw(S_BAR)} ${dim(\"/\")} ${inputHint}`,\n\t\t\t\t\t\t\tbuildList(filtered, cursor, scrollOffset, selected, filter, customPatterns, addCursor, excludedSet),\n\t\t\t\t\t\t\tfooter,\n\t\t\t\t\t\t\t`${ylw(S_BAR_END)} ${ylw(this.error)}`,\n\t\t\t\t\t\t\t\"\",\n\t\t\t\t\t\t].join(\"\\n\");\n\t\t\t\t\tdefault:\n\t\t\t\t\t\treturn [\n\t\t\t\t\t\t\thdr.trimEnd(),\n\t\t\t\t\t\t\t`${info(S_BAR)} ${dim(\"/\")} ${inputHint}`,\n\t\t\t\t\t\t\tbuildList(filtered, cursor, scrollOffset, selected, filter, customPatterns, addCursor, excludedSet),\n\t\t\t\t\t\t\tfooter,\n\t\t\t\t\t\t\t`${info(S_BAR_END)}`,\n\t\t\t\t\t\t\t\"\",\n\t\t\t\t\t\t].join(\"\\n\");\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t\tfalse,\n\t) as InstanceType<typeof Prompt> & { value: unknown; state: string };\n\n\tprompt.on(\"key\", (key: string | undefined) => {\n\t\tif (!key || key === \" \") return;\n\t\tconst cp = key.codePointAt(0) ?? 0;\n\t\tif (cp === 0x7f || cp === 0x08) {\n\t\t\tfilter = filter.slice(0, -1);\n\t\t\tcursor = 0;\n\t\t\tscrollOffset = 0;\n\t\t\taddCursor = false;\n\t\t} else if (cp >= 32 && cp !== 127) {\n\t\t\tfilter += key;\n\t\t\tcursor = 0;\n\t\t\tscrollOffset = 0;\n\t\t\taddCursor = false;\n\t\t}\n\t});\n\n\tprompt.on(\"cursor\", (action: string | undefined) => {\n\t\tconst filtered = getFiltered();\n\t\tconst hasAdd = isNewPattern();\n\n\t\tswitch (action) {\n\t\t\tcase \"up\":\n\t\t\t\tif (addCursor) {\n\t\t\t\t\taddCursor = false;\n\t\t\t\t\tcursor = Math.max(0, filtered.length - 1);\n\t\t\t\t} else cursor = Math.max(0, cursor - 1);\n\t\t\t\tbreak;\n\t\t\tcase \"down\":\n\t\t\t\tif (!addCursor && cursor >= filtered.length - 1 && hasAdd)\n\t\t\t\t\taddCursor = true;\n\t\t\t\telse if (!addCursor) cursor = Math.min(filtered.length - 1, cursor + 1);\n\t\t\t\tbreak;\n\t\t\tcase \"space\":\n\t\t\t\tif (addCursor) {\n\t\t\t\t\tconst t = filter.trim();\n\t\t\t\t\tconst err =\n\t\t\t\t\t\tvalidateBranchPattern(t) ??\n\t\t\t\t\t\t(excludedSet.has(t)\n\t\t\t\t\t\t\t? \"Already used for automatic translation\"\n\t\t\t\t\t\t\t: null);\n\t\t\t\t\tif (!err) {\n\t\t\t\t\t\tcustomPatterns.push(t);\n\t\t\t\t\t\tselected.add(t);\n\t\t\t\t\t\tfilter = \"\";\n\t\t\t\t\t\tcursor = 0;\n\t\t\t\t\t\tscrollOffset = 0;\n\t\t\t\t\t\taddCursor = false;\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tconst item = filtered[cursor];\n\t\t\t\t\tif (item) {\n\t\t\t\t\t\tif (selected.has(item.value)) selected.delete(item.value);\n\t\t\t\t\t\telse selected.add(item.value);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t}\n\t});\n\n\tprompt.on(\"finalize\", () => {\n\t\tif ((prompt as any).state === \"submit\") {\n\t\t\t(prompt as any).value = Array.from(selected);\n\t\t}\n\t});\n\n\tconst result = await prompt.prompt();\n\tif (isCancel(result)) return null;\n\treturn result as unknown as string[];\n}\n","import { isCancel, Prompt } from \"@clack/core\";\nimport * as p from \"@clack/prompts\";\nimport { active, bld, dim, grn, info, red, ylw } from \"./theme.js\";\n\nexport interface LocaleOption {\n\tbcp47: string;\n\t/** Human-readable label, e.g. \"English — en\" */\n\tlabel: string;\n}\n\n// ── Symbols (match @clack/prompts style) ──────────────────────────────────────\n\nconst S_BAR = \"│\";\nconst S_BAR_END = \"└\";\nconst S_ACTIVE = \"◆\";\nconst S_SUBMIT = \"◆\";\nconst S_CANCEL = \"■\";\nconst S_ERROR = \"▲\";\n\nfunction symbol(state: string): string {\n\tswitch (state) {\n\t\tcase \"submit\":\n\t\t\treturn grn(S_SUBMIT);\n\t\tcase \"cancel\":\n\t\t\treturn red(S_CANCEL);\n\t\tcase \"error\":\n\t\t\treturn ylw(S_ERROR);\n\t\tdefault:\n\t\t\treturn active(S_ACTIVE);\n\t}\n}\n\n// ── Filter ────────────────────────────────────────────────────────────────────\n\nconst MAX_VISIBLE = 12;\n\nfunction filterLocales(options: LocaleOption[], query: string): LocaleOption[] {\n\tif (!query.trim()) return options;\n\tconst lower = query.toLowerCase();\n\treturn options.filter(\n\t\t(o) =>\n\t\t\to.bcp47.toLowerCase().includes(lower) ||\n\t\t\to.label.toLowerCase().includes(lower),\n\t);\n}\n\n// ── List renderer ─────────────────────────────────────────────────────────────\n\nfunction buildList(\n\tfiltered: LocaleOption[],\n\tcursor: number,\n\tscrollOffset: number,\n\tselected: Set<string> | null, // null = single-select\n): string {\n\tconst isMulti = selected !== null;\n\tconst end = Math.min(filtered.length, scrollOffset + MAX_VISIBLE);\n\tconst visibleLines: string[] = [info(S_BAR)];\n\n\tfor (let i = scrollOffset; i < end; i++) {\n\t\tconst opt = filtered[i]!;\n\t\tconst isCursor = i === cursor;\n\t\tconst isChecked = isMulti && selected!.has(opt.bcp47);\n\n\t\tconst icon = isMulti\n\t\t\t? isChecked\n\t\t\t\t? isCursor\n\t\t\t\t\t? info(\"◼\")\n\t\t\t\t\t: info(\"◼\")\n\t\t\t\t: isCursor\n\t\t\t\t\t? active(\"◻\")\n\t\t\t\t\t: dim(\"◻\")\n\t\t\t: isCursor\n\t\t\t\t? active(\"●\")\n\t\t\t\t: dim(\"○\");\n\n\t\tvisibleLines.push(\n\t\t\t`${info(S_BAR)} ${icon} ${isCursor ? bld(opt.label) : opt.label}`,\n\t\t);\n\t}\n\n\tconst hidden = filtered.length - (end - scrollOffset);\n\tif (hidden > 0)\n\t\tvisibleLines.push(dim(`${S_BAR} ${hidden} more — keep typing to narrow`));\n\tif (filtered.length === 0) visibleLines.push(dim(`${S_BAR} No matches`));\n\n\treturn visibleLines.join(\"\\n\");\n}\n\n// ── Core prompt factory ───────────────────────────────────────────────────────\n\nasync function runFilterablePrompt(opts: {\n\tmessage: string;\n\toptions: LocaleOption[];\n\tmulti: boolean;\n\tinitialValue?: string;\n\tinitialValues?: string[];\n}): Promise<string | string[] | null> {\n\tconst { message, options, multi } = opts;\n\n\tlet filter = \"\";\n\tlet cursor = 0;\n\tlet scrollOffset = 0;\n\tconst selected = new Set<string>(multi ? (opts.initialValues ?? []) : []);\n\n\tif (!multi && opts.initialValue) {\n\t\tconst idx = options.findIndex((o) => o.bcp47 === opts.initialValue);\n\t\tif (idx >= 0) cursor = idx;\n\t}\n\n\tconst getFiltered = () => filterLocales(options, filter);\n\n\t// Keep cursor in bounds and scroll window centred\n\tconst clampCursor = (filtered: LocaleOption[]) => {\n\t\tif (cursor >= filtered.length) cursor = Math.max(0, filtered.length - 1);\n\t\tif (cursor < scrollOffset) scrollOffset = cursor;\n\t\tif (cursor >= scrollOffset + MAX_VISIBLE)\n\t\t\tscrollOffset = cursor - MAX_VISIBLE + 1;\n\t\tif (scrollOffset < 0) scrollOffset = 0;\n\t};\n\n\t// @clack/core Prompt: render() returns the ENTIRE frame; clack handles\n\t// re-rendering (cursor movement + diff) automatically.\n\t// Using `any` cast to pass `trackValue=false` (2nd constructor arg).\n\tconst prompt = new (Prompt as any)(\n\t\t{\n\t\t\tinitialValue: !multi ? (options[cursor]?.bcp47 ?? null) : null,\n\t\t\tvalidate() {\n\t\t\t\tconst f = getFiltered();\n\t\t\t\tif (multi && selected.size === 0)\n\t\t\t\t\treturn \"At least one target language is required.\";\n\t\t\t\tif (!multi && !f[cursor]) return \"Please select a language.\";\n\t\t\t\treturn undefined;\n\t\t\t},\n\t\t\trender(this: { state: string; error: string; value: unknown }) {\n\t\t\t\tconst filtered = getFiltered();\n\t\t\t\tclampCursor(filtered);\n\n\t\t\t\tconst hdr = `${dim(S_BAR)}\\n${symbol(this.state)} ${message}\\n`;\n\t\t\t\tconst inputHint = filter.length > 0 ? filter : dim(\"type to filter\");\n\n\t\t\t\tconst footer = multi\n\t\t\t\t\t? selected.size > 0\n\t\t\t\t\t\t? dim(`${S_BAR} ${selected.size} selected · ↑↓ navigate · Space to select · Enter to confirm`)\n\t\t\t\t\t\t: dim(`${S_BAR} ↑↓ navigate · Space to select · Enter to confirm`)\n\t\t\t\t\t: dim(`${S_BAR} ↑↓ navigate · Enter to confirm`);\n\n\t\t\t\tswitch (this.state) {\n\t\t\t\t\tcase \"submit\": {\n\t\t\t\t\t\tconst val = multi\n\t\t\t\t\t\t\t? Array.from(selected)\n\t\t\t\t\t\t\t\t\t.map((id) => options.find((o) => o.bcp47 === id)?.label ?? id)\n\t\t\t\t\t\t\t\t\t.join(\", \")\n\t\t\t\t\t\t\t: (options.find((o) => o.bcp47 === (this.value as string))\n\t\t\t\t\t\t\t\t\t?.label ?? \"\");\n\t\t\t\t\t\treturn `${hdr}${dim(S_BAR)} ${bld(val || dim(\"none\"))}`;\n\t\t\t\t\t}\n\t\t\t\t\tcase \"cancel\":\n\t\t\t\t\t\treturn `${hdr}${dim(S_BAR)}`;\n\t\t\t\t\tcase \"error\":\n\t\t\t\t\t\treturn [\n\t\t\t\t\t\t\thdr.trimEnd(),\n\t\t\t\t\t\t\t`${ylw(S_BAR)} ${dim(\"/\")} ${inputHint}`,\n\t\t\t\t\t\t\tbuildList(filtered, cursor, scrollOffset, multi ? selected : null),\n\t\t\t\t\t\t\tfooter,\n\t\t\t\t\t\t\t`${ylw(S_BAR_END)} ${ylw(this.error)}`,\n\t\t\t\t\t\t\t\"\",\n\t\t\t\t\t\t].join(\"\\n\");\n\t\t\t\t\tdefault:\n\t\t\t\t\t\treturn [\n\t\t\t\t\t\t\thdr.trimEnd(),\n\t\t\t\t\t\t\t`${info(S_BAR)} ${dim(\"/\")} ${inputHint}`,\n\t\t\t\t\t\t\tbuildList(filtered, cursor, scrollOffset, multi ? selected : null),\n\t\t\t\t\t\t\tfooter,\n\t\t\t\t\t\t\t`${info(S_BAR_END)}`,\n\t\t\t\t\t\t\t\"\",\n\t\t\t\t\t\t].join(\"\\n\");\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t\tfalse, // trackValue=false — we manage value manually\n\t) as InstanceType<typeof Prompt> & { value: unknown; state: string };\n\n\t// Character input → update filter\n\tprompt.on(\"key\", (key: string | undefined) => {\n\t\tif (!key || key === \" \") return; // space handled by cursor event\n\t\tconst cp = key.codePointAt(0) ?? 0;\n\t\tif (cp === 0x7f || cp === 0x08) {\n\t\t\t// backspace\n\t\t\tfilter = filter.slice(0, -1);\n\t\t\tcursor = 0;\n\t\t\tscrollOffset = 0;\n\t\t} else if (cp >= 32 && cp !== 127) {\n\t\t\tfilter += key;\n\t\t\tcursor = 0;\n\t\t\tscrollOffset = 0;\n\t\t}\n\t});\n\n\t// Navigation + toggle\n\tprompt.on(\"cursor\", (action: string | undefined) => {\n\t\tconst filtered = getFiltered();\n\t\tswitch (action) {\n\t\t\tcase \"up\":\n\t\t\t\tcursor = Math.max(0, cursor - 1);\n\t\t\t\tbreak;\n\t\t\tcase \"down\":\n\t\t\t\tcursor = Math.min(Math.max(filtered.length - 1, 0), cursor + 1);\n\t\t\t\tbreak;\n\t\t\tcase \"space\":\n\t\t\t\tif (multi) {\n\t\t\t\t\tconst opt = filtered[cursor];\n\t\t\t\t\tif (opt) {\n\t\t\t\t\t\tif (selected.has(opt.bcp47)) selected.delete(opt.bcp47);\n\t\t\t\t\t\telse selected.add(opt.bcp47);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t}\n\t\t// Sync prompt.value for single-select so submit gets the right value\n\t\tif (!multi) {\n\t\t\tconst opt = getFiltered()[cursor];\n\t\t\t(prompt as any).value = opt?.bcp47 ?? null;\n\t\t}\n\t});\n\n\t// Before submit resolves, set value to the selected items (multi) or current cursor (single)\n\tprompt.on(\"finalize\", () => {\n\t\tif ((prompt as any).state === \"submit\") {\n\t\t\tif (multi) {\n\t\t\t\t(prompt as any).value = Array.from(selected);\n\t\t\t} else {\n\t\t\t\tconst f = getFiltered();\n\t\t\t\t(prompt as any).value = f[cursor]?.bcp47 ?? null;\n\t\t\t}\n\t\t}\n\t});\n\n\tconst result = await prompt.prompt();\n\n\tif (isCancel(result)) return null;\n\treturn result as string | string[];\n}\n\n// ── Public API ────────────────────────────────────────────────────────────────\n\nexport async function searchSelectLocale(\n\toptions: LocaleOption[],\n\tmessage: string,\n\tinitialValue?: string,\n): Promise<string | null> {\n\tconst result = await runFilterablePrompt({\n\t\tmessage,\n\t\toptions,\n\t\tmulti: false,\n\t\tinitialValue,\n\t});\n\treturn typeof result === \"string\" ? result : null;\n}\n\nexport async function searchMultiSelectLocales(\n\toptions: LocaleOption[],\n\tmessage: string,\n\tinitialValues?: string[],\n): Promise<string[] | null> {\n\tconst result = await runFilterablePrompt({\n\t\tmessage,\n\t\toptions,\n\t\tmulti: true,\n\t\tinitialValues,\n\t});\n\tif (result === null) return null;\n\tconst picks = result as string[];\n\t// Validate already prevents empty on first try; this handles the retry path\n\tif (picks.length === 0) {\n\t\tp.log.warn(\n\t\t\t\"At least one target language is required. Please select at least one.\",\n\t\t);\n\t\treturn searchMultiSelectLocales(options, message, initialValues);\n\t}\n\treturn picks;\n}\n","import * as p from \"@clack/prompts\";\n\nimport type { VocoderAPI } from \"./api.js\";\nimport chalk from \"chalk\";\nimport { spawn } from \"node:child_process\";\nimport { startCallbackServer } from \"./local-server.js\";\n\nasync function tryOpenBrowser(url: string): Promise<boolean> {\n\tif (!process.stdout.isTTY || process.env.CI === \"true\") {\n\t\treturn false;\n\t}\n\n\tconst platform = process.platform;\n\tlet command: string;\n\tlet args: string[];\n\n\tif (platform === \"darwin\") {\n\t\tcommand = \"open\";\n\t\targs = [url];\n\t} else if (platform === \"win32\") {\n\t\tcommand = \"rundll32\";\n\t\targs = [\"url.dll,FileProtocolHandler\", url];\n\t} else {\n\t\tcommand = \"xdg-open\";\n\t\targs = [url];\n\t}\n\n\treturn new Promise<boolean>((resolve) => {\n\t\ttry {\n\t\t\tconst child = spawn(command, args, {\n\t\t\t\tdetached: true,\n\t\t\t\tstdio: \"ignore\",\n\t\t\t\twindowsHide: true,\n\t\t\t});\n\n\t\t\tlet settled = false;\n\t\t\tchild.once(\"spawn\", () => {\n\t\t\t\tif (settled) return;\n\t\t\t\tsettled = true;\n\t\t\t\tchild.unref();\n\t\t\t\tresolve(true);\n\t\t\t});\n\t\t\tchild.once(\"error\", () => {\n\t\t\t\tif (settled) return;\n\t\t\t\tsettled = true;\n\t\t\t\tresolve(false);\n\t\t\t});\n\t\t\tsetTimeout(() => {\n\t\t\t\tif (settled) return;\n\t\t\t\tsettled = true;\n\t\t\t\tresolve(false);\n\t\t\t}, 300);\n\t\t} catch {\n\t\t\tresolve(false);\n\t\t}\n\t});\n}\n\nexport interface GitHubConnectResult {\n\torganizationId: string;\n\torganizationName: string;\n\tconnectionLabel: string;\n}\n\n/**\n * Run the full GitHub App install flow for a new workspace.\n * Opens the browser to the GitHub App install page and waits for completion.\n *\n * Returns `null` if the user cancelled or an error occurred.\n */\nexport async function runGitHubInstallFlow(params: {\n\tapi: VocoderAPI;\n\tuserToken: string;\n\torganizationId?: string;\n\tyes?: boolean;\n}): Promise<GitHubConnectResult | null> {\n\t// Try to start a local callback server for instant notification\n\tlet server: Awaited<ReturnType<typeof startCallbackServer>> | null = null;\n\ttry {\n\t\tserver = await startCallbackServer();\n\t} catch {\n\t\t// Fall through — the user can re-run if something goes wrong\n\t}\n\n\tconst { installUrl } = await params.api.startCliGitHubInstall(\n\t\tparams.userToken,\n\t\t{\n\t\t\torganizationId: params.organizationId,\n\t\t\tcallbackPort: server?.port,\n\t\t},\n\t);\n\n\tp.log.info(\"Opening GitHub to install the Vocoder App...\");\n\n\tif (\n\t\tprocess.stdin.isTTY &&\n\t\tprocess.stdout.isTTY &&\n\t\tprocess.env.CI !== \"true\"\n\t) {\n\t\tconst shouldOpen = params.yes\n\t\t\t? true\n\t\t\t: await p.confirm({ message: \"Open in your browser?\" });\n\n\t\tif (p.isCancel(shouldOpen)) {\n\t\t\tserver?.close();\n\t\t\treturn null;\n\t\t}\n\n\t\tif (shouldOpen) {\n\t\t\tconst opened = await tryOpenBrowser(installUrl);\n\t\t\tif (!opened) {\n\t\t\t\tp.log.info(\n\t\t\t\t\t\"Could not open a browser automatically. Use the URL above.\",\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\tconst connectSpinner = p.spinner();\n\tconnectSpinner.start(\"Waiting for GitHub App installation...\");\n\n\tif (server) {\n\t\ttry {\n\t\t\tconst params_timeout = 15 * 60 * 1000; // 15 minutes\n\t\t\tconst callbackParams = await Promise.race([\n\t\t\t\tserver.waitForCallback(),\n\t\t\t\tnew Promise<null>((resolve) =>\n\t\t\t\t\tsetTimeout(() => resolve(null), params_timeout),\n\t\t\t\t),\n\t\t\t]);\n\n\t\t\tserver.close();\n\n\t\t\tif (!callbackParams) {\n\t\t\t\tconnectSpinner.stop(\"GitHub App installation timed out\");\n\t\t\t\tp.log.error(\n\t\t\t\t\t\"The installation flow timed out. Run `vocoder init` again.\",\n\t\t\t\t);\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tif (callbackParams.error) {\n\t\t\t\tconnectSpinner.stop(\"GitHub App installation failed\");\n\t\t\t\tp.log.error(callbackParams.error);\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tconst { organizationId, connectionLabel, workspace_created } =\n\t\t\t\tcallbackParams;\n\n\t\t\tif (!organizationId || !connectionLabel) {\n\t\t\t\tconnectSpinner.stop(\"GitHub App installation incomplete\");\n\t\t\t\tp.log.error(\"Missing organization or connection data from callback.\");\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tconnectSpinner.stop(\n\t\t\t\t`Connected to GitHub as ${chalk.bold(connectionLabel)}`,\n\t\t\t);\n\n\t\t\t// Fetch the org name\n\t\t\tconst orgName = workspace_created ? connectionLabel : organizationId;\n\t\t\treturn {\n\t\t\t\torganizationId,\n\t\t\t\torganizationName: orgName,\n\t\t\t\tconnectionLabel,\n\t\t\t};\n\t\t} catch {\n\t\t\tserver.close();\n\t\t\tconnectSpinner.stop(\"GitHub App installation failed\");\n\t\t\treturn null;\n\t\t}\n\t}\n\n\t// No local server — there's no polling fallback for install; just wait\n\tconnectSpinner.stop(\"Could not detect GitHub App installation automatically\");\n\tp.log.warn(\n\t\t\"Complete the installation in your browser, then run `vocoder init` again.\",\n\t);\n\treturn null;\n}\n\n/**\n * Run the GitHub OAuth discovery flow to find existing installations.\n * Returns the list of installations with conflict labels, or null on cancellation/error.\n */\nexport async function runGitHubDiscoveryFlow(params: {\n\tapi: VocoderAPI;\n\tuserToken: string;\n\torganizationId?: string;\n\tyes?: boolean;\n}): Promise<Array<{\n\tinstallationId: number;\n\taccountLogin: string;\n\taccountType: string;\n\tisSuspended: boolean;\n\tconflictLabel: string | null;\n}> | null> {\n\t// Try local callback server\n\tlet server: Awaited<ReturnType<typeof startCallbackServer>> | null = null;\n\ttry {\n\t\tserver = await startCallbackServer();\n\t} catch {\n\t\t// Fall through\n\t}\n\n\tconst { oauthUrl } = await params.api.startCliGitHubOAuth(params.userToken, {\n\t\torganizationId: params.organizationId,\n\t\tcallbackPort: server?.port,\n\t});\n\n\tp.log.info(\"Opening GitHub to authorize your account...\");\n\tp.note(\"Complete authorization in your browser.\");\n\n\tif (\n\t\tprocess.stdin.isTTY &&\n\t\tprocess.stdout.isTTY &&\n\t\tprocess.env.CI !== \"true\"\n\t) {\n\t\tconst shouldOpen = params.yes\n\t\t\t? true\n\t\t\t: await p.confirm({ message: \"Open in your browser?\" });\n\n\t\tif (p.isCancel(shouldOpen)) {\n\t\t\tserver?.close();\n\t\t\treturn null;\n\t\t}\n\n\t\tif (shouldOpen) {\n\t\t\tconst opened = await tryOpenBrowser(oauthUrl);\n\t\t\tif (!opened) {\n\t\t\t\tp.log.info(`Could not open browser automatically. Visit: ${oauthUrl}`);\n\t\t\t}\n\t\t}\n\t}\n\n\tconst oauthSpinner = p.spinner();\n\toauthSpinner.start(\"Waiting for GitHub authorization...\");\n\n\tif (server) {\n\t\ttry {\n\t\t\tconst timeoutMs = 10 * 60 * 1000;\n\t\t\tconst callbackParams = await Promise.race([\n\t\t\t\tserver.waitForCallback(),\n\t\t\t\tnew Promise<null>((resolve) =>\n\t\t\t\t\tsetTimeout(() => resolve(null), timeoutMs),\n\t\t\t\t),\n\t\t\t]);\n\n\t\t\tserver.close();\n\n\t\t\tif (!callbackParams) {\n\t\t\t\toauthSpinner.stop(\"GitHub authorization timed out\");\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tif (callbackParams.error) {\n\t\t\t\toauthSpinner.stop(\"GitHub authorization failed\");\n\t\t\t\tp.log.error(callbackParams.error);\n\t\t\t\treturn null;\n\t\t\t}\n\t\t} catch {\n\t\t\tserver.close();\n\t\t\toauthSpinner.stop(\"GitHub authorization failed\");\n\t\t\treturn null;\n\t\t}\n\t}\n\n\toauthSpinner.stop(\"GitHub account authorized\");\n\n\t// Fetch discovery results\n\tconst discoveryResult = await params.api.getCliGitHubDiscovery(\n\t\tparams.userToken,\n\t);\n\treturn discoveryResult.installations;\n}\n\ntype DiscoveredInstallation = {\n\tinstallationId: number;\n\taccountLogin: string;\n\taccountType: string;\n\tisSuspended: boolean;\n\tconflictLabel: string | null;\n};\n\n/**\n * Prompt the user to select a GitHub installation from discovery results.\n * Returns the selected installation ID, 'install_new' to trigger install flow,\n * or null on cancellation.\n */\nexport async function selectGitHubInstallation(\n\tinstallations: DiscoveredInstallation[],\n\tcanInstallNew: boolean,\n): Promise<number | \"install_new\" | null> {\n\ttype SelectValue = string;\n\n\tconst options: Array<{ value: SelectValue; label: string; hint?: string }> =\n\t\tinstallations.map((inst) => ({\n\t\t\tvalue: String(inst.installationId),\n\t\t\tlabel: inst.accountLogin,\n\t\t\thint:\n\t\t\t\t[\n\t\t\t\t\tinst.accountType === \"Organization\" ? \"organization\" : \"personal\",\n\t\t\t\t\tinst.conflictLabel ? `connected to ${inst.conflictLabel}` : \"\",\n\t\t\t\t\tinst.isSuspended ? \"suspended\" : \"\",\n\t\t\t\t]\n\t\t\t\t\t.filter(Boolean)\n\t\t\t\t\t.join(\" · \") || undefined,\n\t\t}));\n\n\tif (canInstallNew) {\n\t\toptions.push({\n\t\t\tvalue: \"install_new\",\n\t\t\tlabel: `Install on a new account ${chalk.dim(\"(creates a new personal workspace)\")}`,\n\t\t});\n\t}\n\n\tconst selected = await p.select<SelectValue>({\n\t\tmessage: \"Select a GitHub installation\",\n\t\toptions,\n\t});\n\n\tif (p.isCancel(selected)) return null;\n\tif (selected === \"install_new\") return \"install_new\";\n\n\treturn Number(selected);\n}\n","import { createServer } from \"node:http\";\nimport type { AddressInfo } from \"node:net\";\nimport { URL } from \"node:url\";\n\nexport interface LocalServerHandle {\n\tport: number;\n\twaitForCallback: () => Promise<Record<string, string>>;\n\tclose: () => void;\n}\n\n/**\n * Starts a local HTTP server on a random available port.\n * Returns the port and a promise that resolves when the browser\n * redirects to /callback with query parameters.\n *\n * Used for the browser→CLI token handoff pattern:\n * 1. CLI passes `port` to the auth session start request\n * 2. After browser auth, vocoder.app redirects to localhost:<port>/callback?token=...\n * 3. `waitForCallback()` resolves with the query params\n */\nexport function startCallbackServer(): Promise<LocalServerHandle> {\n\treturn new Promise((resolve, reject) => {\n\t\tlet settled = false;\n\t\tlet callbackResolve: ((params: Record<string, string>) => void) | null =\n\t\t\tnull;\n\t\tlet callbackReject: ((err: Error) => void) | null = null;\n\n\t\tconst callbackPromise = new Promise<Record<string, string>>((res, rej) => {\n\t\t\tcallbackResolve = res;\n\t\t\tcallbackReject = rej;\n\t\t});\n\n\t\tconst server = createServer((req, res) => {\n\t\t\tif (!req.url) {\n\t\t\t\tres.writeHead(400);\n\t\t\t\tres.end();\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tlet pathname: string;\n\t\t\tlet params: Record<string, string>;\n\n\t\t\ttry {\n\t\t\t\tconst parsed = new URL(req.url, \"http://localhost\");\n\t\t\t\tpathname = parsed.pathname;\n\t\t\t\tparams = Object.fromEntries(parsed.searchParams.entries());\n\t\t\t} catch {\n\t\t\t\tres.writeHead(400);\n\t\t\t\tres.end(\"Bad request\");\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (pathname !== \"/callback\") {\n\t\t\t\tres.writeHead(404);\n\t\t\t\tres.end(\"Not found\");\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tres.writeHead(200, { \"Content-Type\": \"text/html\" });\n\t\t\tres.end(\n\t\t\t\t\"<!DOCTYPE html><html><head><title>Authenticated</title></head>\" +\n\t\t\t\t\t'<body style=\"font-family:sans-serif;text-align:center;padding:3rem;\">' +\n\t\t\t\t\t\"<h2>Authenticated</h2>\" +\n\t\t\t\t\t\"<p>Return to your terminal to continue. You can close this tab.</p>\" +\n\t\t\t\t\t\"</body></html>\",\n\t\t\t);\n\n\t\t\tif (callbackResolve) {\n\t\t\t\tcallbackResolve(params);\n\t\t\t\tcallbackResolve = null;\n\t\t\t}\n\n\t\t\tsetImmediate(() => server.close());\n\t\t});\n\n\t\tserver.on(\"error\", (err) => {\n\t\t\tif (!settled) {\n\t\t\t\tsettled = true;\n\t\t\t\tif (callbackReject) callbackReject(err);\n\t\t\t\treject(err);\n\t\t\t}\n\t\t});\n\n\t\t// Bind to a random port on localhost only\n\t\tserver.listen(0, \"127.0.0.1\", () => {\n\t\t\tif (settled) return;\n\t\t\tsettled = true;\n\n\t\t\tconst port = (server.address() as AddressInfo).port;\n\n\t\t\tresolve({\n\t\t\t\tport,\n\t\t\t\twaitForCallback: () => callbackPromise,\n\t\t\t\tclose: () => server.close(),\n\t\t\t});\n\t\t});\n\t});\n}\n","import { execSync } from \"node:child_process\";\n\nexport type GitRepositoryIdentity = {\n\trepoCanonical: string;\n\t/** Absolute path to the git repository root (`git rev-parse --show-toplevel`). */\n\trepoRoot: string;\n};\n\nexport type GitContext = {\n\tidentity: GitRepositoryIdentity | null;\n\twarnings: string[];\n};\n\nconst SHA_REGEX = /^[0-9a-f]{40}$/i;\n\n/**\n * Detect the current commit SHA from CI env vars or git.\n * Must produce the same result as detectCommitSha() in @vocoder/plugin\n * so fingerprints computed by CLI sync and unplugin build match.\n */\nexport function detectCommitSha(): string | null {\n\tif (\n\t\tprocess.env.VOCODER_COMMIT_SHA &&\n\t\tSHA_REGEX.test(process.env.VOCODER_COMMIT_SHA)\n\t) {\n\t\treturn process.env.VOCODER_COMMIT_SHA;\n\t}\n\n\tconst knownSha =\n\t\tprocess.env.GITHUB_SHA ||\n\t\tprocess.env.VERCEL_GIT_COMMIT_SHA ||\n\t\tprocess.env.CI_COMMIT_SHA ||\n\t\tprocess.env.BITBUCKET_COMMIT ||\n\t\tprocess.env.CIRCLE_SHA1 ||\n\t\tprocess.env.RENDER_GIT_COMMIT;\n\n\tif (knownSha && SHA_REGEX.test(knownSha)) return knownSha;\n\n\treturn safeExec(\"git rev-parse HEAD\");\n}\n\nfunction safeExec(command: string): string | null {\n\ttry {\n\t\tconst output = execSync(command, {\n\t\t\tencoding: \"utf-8\",\n\t\t\tstdio: [\"pipe\", \"pipe\", \"ignore\"],\n\t\t}).trim();\n\t\treturn output.length > 0 ? output : null;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nfunction normalizePath(pathname: string): string | null {\n\tconst cleaned = pathname\n\t\t.replace(/^\\/+/, \"\")\n\t\t.replace(/\\.git$/i, \"\")\n\t\t.trim();\n\n\tif (!cleaned || !cleaned.includes(\"/\")) {\n\t\treturn null;\n\t}\n\n\treturn cleaned;\n}\n\nfunction parseRemoteUrl(remoteUrl: string): {\n\thost: string;\n\townerRepoPath: string;\n} | null {\n\tconst trimmed = remoteUrl.trim();\n\tif (!trimmed) {\n\t\treturn null;\n\t}\n\n\t// SCP-like syntax: git@github.com:owner/repo.git\n\tif (!trimmed.includes(\"://\")) {\n\t\tconst scpMatch = trimmed.match(/^(?:.+@)?([^:]+):(.+)$/);\n\t\tif (scpMatch) {\n\t\t\tconst host = (scpMatch[1] || \"\").toLowerCase();\n\t\t\tconst ownerRepoPath = normalizePath(scpMatch[2] || \"\");\n\t\t\tif (!host || !ownerRepoPath) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\treturn { host, ownerRepoPath };\n\t\t}\n\t\treturn null;\n\t}\n\n\ttry {\n\t\tconst parsed = new URL(trimmed);\n\t\tconst host = parsed.hostname.toLowerCase();\n\t\tconst ownerRepoPath = normalizePath(decodeURIComponent(parsed.pathname));\n\t\tif (!host || !ownerRepoPath) {\n\t\t\treturn null;\n\t\t}\n\t\treturn { host, ownerRepoPath };\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nfunction toCanonical(host: string, ownerRepoPath: string): string {\n\tif (host.includes(\"github.com\")) {\n\t\treturn `github:${ownerRepoPath.toLowerCase()}`;\n\t}\n\tif (host.includes(\"gitlab.com\")) {\n\t\treturn `gitlab:${ownerRepoPath.toLowerCase()}`;\n\t}\n\tif (host.includes(\"bitbucket.org\")) {\n\t\treturn `bitbucket:${ownerRepoPath.toLowerCase()}`;\n\t}\n\treturn `git:${host}/${ownerRepoPath.toLowerCase()}`;\n}\n\nexport function resolveGitRepositoryIdentity(): GitRepositoryIdentity | null {\n\tconst remoteUrl = safeExec(\"git config --get remote.origin.url\");\n\tif (!remoteUrl) {\n\t\treturn null;\n\t}\n\n\tconst parsed = parseRemoteUrl(remoteUrl);\n\tif (!parsed) {\n\t\treturn null;\n\t}\n\n\tconst repoRoot = safeExec(\"git rev-parse --show-toplevel\");\n\tif (!repoRoot) {\n\t\treturn null;\n\t}\n\n\treturn {\n\t\trepoCanonical: toCanonical(parsed.host, parsed.ownerRepoPath),\n\t\trepoRoot,\n\t};\n}\n\nexport function resolveGitContext(): GitContext {\n\tconst warnings: string[] = [];\n\tconst identity = resolveGitRepositoryIdentity();\n\n\tif (!identity) {\n\t\twarnings.push(\n\t\t\t\"Could not detect git remote origin. Repo binding will be skipped until sync can detect it.\",\n\t\t);\n\t}\n\n\treturn { identity, warnings };\n}\n","import * as p from \"@clack/prompts\";\nimport chalk from \"chalk\";\n\nexport interface OrganizationInfo {\n\tid: string;\n\tname: string;\n\tplanId: string;\n\tprojectCount: number;\n\thasGitHubConnection: boolean;\n\tconnectionLabel: string | null;\n}\n\nexport interface OrganizationListResult {\n\torganizations: OrganizationInfo[];\n\tcanCreateOrganization: boolean;\n}\n\nexport type OrganizationSelection =\n\t| { action: \"use\"; organization: OrganizationInfo }\n\t| { action: \"create\" }\n\t| { action: \"cancelled\" };\n\nfunction _organizationLabel(org: OrganizationInfo): string {\n\tconst parts: string[] = [org.name];\n\tconst meta: string[] = [];\n\n\tif (org.projectCount === 1) {\n\t\tmeta.push(\"1 project\");\n\t} else if (org.projectCount > 1) {\n\t\tmeta.push(`${org.projectCount} projects`);\n\t}\n\n\tif (org.connectionLabel) {\n\t\tmeta.push(`GitHub: ${org.connectionLabel}`);\n\t}\n\n\tif (meta.length > 0) {\n\t\tparts.push(chalk.dim(`(${meta.join(\", \")})`));\n\t}\n\n\treturn parts.join(\" \");\n}\n\n/**\n * Prompt the user to select an organization or create a new one.\n * Returns an `OrganizationSelection` describing what the user chose.\n */\nexport async function selectOrganization(\n\tresult: OrganizationListResult,\n): Promise<OrganizationSelection> {\n\tconst { organizations, canCreateOrganization } = result;\n\n\tif (organizations.length === 0) {\n\t\t// No organizations — must create\n\t\treturn { action: \"create\" };\n\t}\n\n\ttype SelectValue = string | \"create\";\n\n\tconst options: Array<{ value: SelectValue; label: string; hint?: string }> =\n\t\torganizations.map((org) => ({\n\t\t\tvalue: org.id,\n\t\t\tlabel: org.name,\n\t\t\thint:\n\t\t\t\t[\n\t\t\t\t\torg.projectCount > 0\n\t\t\t\t\t\t? `${org.projectCount} project${org.projectCount !== 1 ? \"s\" : \"\"}`\n\t\t\t\t\t\t: \"\",\n\t\t\t\t\torg.connectionLabel ? `GitHub: ${org.connectionLabel}` : \"\",\n\t\t\t\t]\n\t\t\t\t\t.filter(Boolean)\n\t\t\t\t\t.join(\" · \") || undefined,\n\t\t}));\n\n\tif (canCreateOrganization) {\n\t\toptions.push({ value: \"create\", label: \"Create new workspace\" });\n\t}\n\n\tconst selected = await p.select<SelectValue>({\n\t\tmessage: \"Select workspace\",\n\t\toptions,\n\t});\n\n\tif (p.isCancel(selected)) {\n\t\treturn { action: \"cancelled\" };\n\t}\n\n\tif (selected === \"create\") {\n\t\treturn { action: \"create\" };\n\t}\n\n\tconst organization = organizations.find((org) => org.id === selected);\n\tif (!organization) {\n\t\treturn { action: \"cancelled\" };\n\t}\n\n\treturn { action: \"use\", organization };\n}\n","import * as p from \"@clack/prompts\";\nimport chalk from \"chalk\";\nimport { active, highlight } from \"../utils/theme.js\";\nimport { config as loadEnv } from \"dotenv\";\nimport { readFileSync } from \"node:fs\";\nimport { VocoderAPI, VocoderAPIError } from \"../utils/api.js\";\nimport { findExistingConfig } from \"../utils/write-config.js\";\nimport { getLimitErrorGuidance } from \"./sync.js\";\n\nloadEnv();\n\nexport interface LocaleCommandOptions {\n\tapiUrl?: string;\n}\n\n/**\n * Read the appId from the nearest vocoder.config.ts/js in the CWD.\n * Returns undefined when no config file is found or it contains no appId.\n */\nfunction readLocalAppId(): string | undefined {\n\tconst configPath = findExistingConfig(process.cwd());\n\tif (!configPath) return undefined;\n\ttry {\n\t\tconst content = readFileSync(configPath, \"utf-8\");\n\t\tconst match = content.match(/appId:\\s*['\"]([^'\"]+)['\"]/);\n\t\treturn match?.[1];\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\nfunction getApiConfig(options: LocaleCommandOptions): {\n\tapiKey: string;\n\tapiUrl: string;\n} | null {\n\tconst apiKey = process.env.VOCODER_API_KEY;\n\tif (!apiKey) {\n\t\tp.log.error(\n\t\t\t\"VOCODER_API_KEY is not set. Run `npx @vocoder/cli init` to set up your project.\",\n\t\t);\n\t\treturn null;\n\t}\n\treturn {\n\t\tapiKey,\n\t\tapiUrl: options.apiUrl ?? process.env.VOCODER_API_URL ?? \"https://vocoder.app\",\n\t};\n}\n\n/**\n * Lists the project's configured source locale and target locales.\n * Reads the project API key from VOCODER_API_KEY.\n *\n * Endpoint: GET /api/cli/config\n *\n * @throws If VOCODER_API_KEY is missing or the API call fails.\n */\nexport async function listProjectLocales(options: LocaleCommandOptions = {}): Promise<number> {\n\tconst config = getApiConfig(options);\n\tif (!config) return 1;\n\n\tconst api = new VocoderAPI(config);\n\n\ttry {\n\t\tconst projectConfig = await api.getAppConfig();\n\n\t\tp.log.info(\n\t\t\t`Source locale: ${highlight(projectConfig.sourceLocale)}`,\n\t\t);\n\n\t\tif (projectConfig.targetLocales.length === 0) {\n\t\t\tp.log.info(\"Target locales: (none configured)\");\n\t\t} else {\n\t\t\tp.log.info(\n\t\t\t\t`Target locales: ${projectConfig.targetLocales.map((l) => highlight(l)).join(\", \")}`,\n\t\t\t);\n\t\t}\n\n\t\treturn 0;\n\t} catch (error) {\n\t\tp.log.error(\n\t\t\terror instanceof Error ? error.message : \"Failed to fetch project locales.\",\n\t\t);\n\t\treturn 1;\n\t}\n}\n\n/**\n * Adds one or more target locales to the project.\n * Loops per locale — the API accepts one locale at a time.\n * Idempotent: locales already configured are silently skipped.\n *\n * Endpoint: POST /api/cli/app/locales (one call per locale)\n *\n * @param locales Array of BCP 47 locale codes to add, e.g. [\"fr\", \"de\", \"pt-BR\"].\n * @throws {VocoderAPIError} status 422 for invalid/unsupported locale code.\n * @throws {VocoderAPIError} status 403 when the plan's maxTargetLocalesPerProject limit is reached.\n */\nexport async function addLocales(\n\tlocales: string[],\n\toptions: LocaleCommandOptions = {},\n): Promise<number> {\n\tif (locales.length === 0) {\n\t\tp.log.error(\"No locale codes provided.\");\n\t\treturn 1;\n\t}\n\n\tconst config = getApiConfig(options);\n\tif (!config) return 1;\n\n\tconst api = new VocoderAPI(config);\n\tconst appId = readLocalAppId();\n\tlet lastTargetLocales: string[] = [];\n\tlet hadError = false;\n\n\tfor (const locale of locales) {\n\t\tconst spinner = p.spinner();\n\t\tspinner.start(`Adding ${locale}…`);\n\n\t\ttry {\n\t\t\tconst result = await api.addLocale(locale, undefined, appId);\n\t\t\tlastTargetLocales = result.targetLocales;\n\t\t\tspinner.stop(`Added ${highlight(locale)}`);\n\t\t} catch (error) {\n\t\t\tspinner.stop(`Failed to add ${chalk.red(locale)}`);\n\t\t\thadError = true;\n\n\t\t\tif (error instanceof VocoderAPIError && error.limitError) {\n\t\t\t\tconst { limitError } = error;\n\t\t\t\tp.log.error(limitError.message);\n\t\t\t\tfor (const line of getLimitErrorGuidance(limitError)) {\n\t\t\t\t\tp.log.info(line);\n\t\t\t\t}\n\t\t\t\t// Plan limit hit — remaining locales will also fail, so stop early\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tp.log.error(\n\t\t\t\terror instanceof Error ? error.message : \"Unknown error\",\n\t\t\t);\n\t\t}\n\t}\n\n\tif (lastTargetLocales.length > 0) {\n\t\tp.log.info(\n\t\t\t`Target locales now: ${lastTargetLocales.map((l) => highlight(l)).join(\", \")}`,\n\t\t);\n\t}\n\n\treturn hadError ? 1 : 0;\n}\n\n/**\n * Removes one or more target locales from the project.\n * Loops per locale — the API accepts one locale at a time.\n * Idempotent: locales not currently configured are silently skipped.\n *\n * Endpoint: DELETE /api/cli/app/locales (one call per locale)\n *\n * @param locales Array of BCP 47 locale codes to remove, e.g. [\"fr\", \"de\"].\n */\nexport async function removeLocales(\n\tlocales: string[],\n\toptions: LocaleCommandOptions = {},\n): Promise<number> {\n\tif (locales.length === 0) {\n\t\tp.log.error(\"No locale codes provided.\");\n\t\treturn 1;\n\t}\n\n\tconst config = getApiConfig(options);\n\tif (!config) return 1;\n\n\tconst api = new VocoderAPI(config);\n\tconst appId = readLocalAppId();\n\tlet lastTargetLocales: string[] = [];\n\tlet hadError = false;\n\n\tfor (const locale of locales) {\n\t\tconst spinner = p.spinner();\n\t\tspinner.start(`Removing ${locale}…`);\n\n\t\ttry {\n\t\t\tconst result = await api.removeLocale(locale, undefined, appId);\n\t\t\tlastTargetLocales = result.targetLocales;\n\t\t\tspinner.stop(`Removed ${highlight(locale)}`);\n\t\t} catch (error) {\n\t\t\tspinner.stop(`Failed to remove ${chalk.red(locale)}`);\n\t\t\thadError = true;\n\t\t\tp.log.error(\n\t\t\t\terror instanceof Error ? error.message : \"Unknown error\",\n\t\t\t);\n\t\t}\n\t}\n\n\tif (lastTargetLocales.length > 0) {\n\t\tp.log.info(\n\t\t\t`Target locales now: ${lastTargetLocales.map((l) => highlight(l)).join(\", \")}`,\n\t\t);\n\t} else if (!hadError) {\n\t\tp.log.info(\"Target locales now: (none configured)\");\n\t}\n\n\treturn hadError ? 1 : 0;\n}\n\n/**\n * Lists all locales supported by Vocoder.\n * Useful for discovering valid BCP 47 codes before calling `add`.\n *\n * Endpoint: GET /api/cli/locales (accepts both user tokens and project API keys)\n */\nexport async function listSupportedLocales(options: LocaleCommandOptions = {}): Promise<number> {\n\tconst config = getApiConfig(options);\n\tif (!config) return 1;\n\n\tconst api = new VocoderAPI(config);\n\n\ttry {\n\t\t// GET /api/cli/locales accepts both user tokens and project API keys as Bearer tokens\n\t\tconst result = await api.listLocales(config.apiKey);\n\t\tp.log.info(chalk.bold(\"Source locales:\"));\n\t\tprintLocaleTable(result.sourceLocales);\n\t\tp.log.info(\"\");\n\t\tp.log.info(chalk.bold(\"Target locales:\"));\n\t\tprintLocaleTable(result.targetLocales);\n\t\treturn 0;\n\t} catch (error) {\n\t\tp.log.error(\n\t\t\terror instanceof Error ? error.message : \"Failed to fetch supported locales.\",\n\t\t);\n\t\treturn 1;\n\t}\n}\n\nfunction printLocaleTable(\n\tlocales: Array<{ code: string; name: string; nativeName?: string }>,\n): void {\n\tfor (const locale of locales) {\n\t\tconst native =\n\t\t\tlocale.nativeName && locale.nativeName !== locale.name\n\t\t\t\t? ` (${locale.nativeName})`\n\t\t\t\t: \"\";\n\t\tp.log.info(` ${highlight(locale.code.padEnd(10))} ${locale.name}${native}`);\n\t}\n}\n","import { randomUUID } from \"node:crypto\";\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport * as p from \"@clack/prompts\";\nimport chalk from \"chalk\";\nimport { highlight } from \"../utils/theme.js\";\nimport type { VocoderTranslationData } from \"@vocoder/config\";\nimport { computeFingerprint, loadVocoderConfig } from \"@vocoder/extractor\";\nimport type {\n\tEffectiveSyncMode,\n\tExtractedString,\n\tLimitErrorResponse,\n\tLocalesMap,\n\tProjectConfig,\n\tRequestedSyncMode,\n\tSyncPolicyConfig,\n\tTranslateOptions,\n\tTranslationStringEntry,\n} from \"../types.js\";\nimport { VocoderAPI, VocoderAPIError } from \"../utils/api.js\";\nimport { detectBranch, isTargetBranch } from \"../utils/branch.js\";\nimport { extractShortCodeFromApiKey, getMergedConfig, validateLocalConfig } from \"../utils/config.js\";\nimport { StringExtractor } from \"../utils/extract.js\";\nimport {\n\tdetectCommitSha,\n\tresolveGitRepositoryIdentity,\n} from \"../utils/git-identity.js\";\n\ntype LocaleMetadataMap = LocalesMap;\ntype TranslationMap = Record<string, Record<string, string>>;\ntype TranslationArtifactSource = \"fresh\" | \"local-cache\" | \"api-snapshot\";\n\ntype TranslationArtifacts = {\n\tsource: TranslationArtifactSource;\n\ttranslations: TranslationMap;\n\tlocaleMetadata?: LocaleMetadataMap;\n\tsnapshotBatchId?: string;\n\tcompletedAt?: string | null;\n};\n\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction parseLocaleMetadata(value: unknown): LocaleMetadataMap | undefined {\n\tif (!isRecord(value)) {\n\t\treturn undefined;\n\t}\n\n\tconst metadata: LocaleMetadataMap = {};\n\tfor (const [locale, rawValue] of Object.entries(value)) {\n\t\tif (!isRecord(rawValue)) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst nativeName = rawValue.nativeName;\n\t\tif (typeof nativeName !== \"string\" || nativeName.trim().length === 0) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst entry: { nativeName: string; dir?: \"rtl\" } = { nativeName };\n\t\tif (rawValue.dir === \"rtl\") {\n\t\t\tentry.dir = \"rtl\";\n\t\t}\n\n\t\tmetadata[locale] = entry;\n\t}\n\n\treturn Object.keys(metadata).length > 0 ? metadata : undefined;\n}\n\nfunction parseTranslations(value: unknown): TranslationMap | null {\n\tif (!isRecord(value)) {\n\t\treturn null;\n\t}\n\n\tconst translations: TranslationMap = {};\n\n\tfor (const [locale, localeValue] of Object.entries(value)) {\n\t\tif (!isRecord(localeValue)) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst localeTranslations: Record<string, string> = {};\n\t\tfor (const [source, translated] of Object.entries(localeValue)) {\n\t\t\tif (typeof translated === \"string\") {\n\t\t\t\tlocaleTranslations[source] = translated;\n\t\t\t}\n\t\t}\n\n\t\ttranslations[locale] = localeTranslations;\n\t}\n\n\treturn Object.keys(translations).length > 0 ? translations : null;\n}\n\nfunction getCacheFilePath(projectRoot: string, fingerprint: string): string {\n\treturn join(projectRoot, \"node_modules\", \".vocoder\", \"cache\", `${fingerprint}.json`);\n}\n\nfunction buildTranslationData(params: {\n\tsourceLocale: string;\n\ttargetLocales: string[];\n\ttranslations: TranslationMap;\n\tlocaleMetadata?: LocaleMetadataMap;\n\tupdatedAt: string;\n}): VocoderTranslationData {\n\t// Translations from the API are already key-keyed ({ [sourceKey]: translatedText }).\n\t// No remapping needed — pass through directly.\n\tconst locales: Record<string, { nativeName: string; dir?: \"rtl\" }> = {};\n\tfor (const code of [params.sourceLocale, ...params.targetLocales]) {\n\t\tconst meta = params.localeMetadata?.[code];\n\t\tif (meta) locales[code] = { nativeName: meta.nativeName, ...(meta.dir ? { dir: meta.dir } : {}) };\n\t}\n\n\treturn {\n\t\tconfig: { sourceLocale: params.sourceLocale, targetLocales: params.targetLocales, locales },\n\t\ttranslations: params.translations,\n\t\tupdatedAt: params.updatedAt,\n\t};\n}\n\nfunction readLocalCache(params: {\n\tprojectRoot: string;\n\tfingerprint: string;\n}): TranslationArtifacts | null {\n\tconst cacheFilePath = getCacheFilePath(params.projectRoot, params.fingerprint);\n\tif (!existsSync(cacheFilePath)) return null;\n\ttry {\n\t\tconst raw = readFileSync(cacheFilePath, \"utf-8\");\n\t\tconst parsed = JSON.parse(raw) as unknown;\n\t\tif (!isRecord(parsed)) return null;\n\t\t// VocoderTranslationData shape: { config, translations, updatedAt }\n\t\tconst inner = isRecord(parsed.config) ? parsed : null;\n\t\tif (!inner) return null;\n\t\tconst translations = parseTranslations(inner.translations);\n\t\tif (!translations) return null;\n\t\tconst localeMetadata = isRecord(inner.config)\n\t\t\t? parseLocaleMetadata(inner.config.locales)\n\t\t\t: undefined;\n\t\treturn { source: \"local-cache\", translations, localeMetadata };\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nfunction writeCache(params: {\n\tprojectRoot: string;\n\tfingerprint: string;\n\tdata: VocoderTranslationData;\n}): string {\n\tconst cacheDir = join(params.projectRoot, \"node_modules\", \".vocoder\", \"cache\");\n\tmkdirSync(cacheDir, { recursive: true });\n\tconst cacheFilePath = getCacheFilePath(params.projectRoot, params.fingerprint);\n\twriteFileSync(cacheFilePath, JSON.stringify(params.data), \"utf-8\");\n\treturn cacheFilePath;\n}\n\nfunction resolveEffectiveModeFromPolicy(params: {\n\tbranch: string;\n\trequestedMode: RequestedSyncMode;\n\tpolicy: SyncPolicyConfig;\n}): EffectiveSyncMode {\n\tconst { requestedMode, policy, branch } = params;\n\n\tlet mode: EffectiveSyncMode;\n\tif (requestedMode === \"auto\") {\n\t\tconst isBlockingBranch = isTargetBranch(branch, policy.blockingBranches);\n\t\tmode = isBlockingBranch ? policy.blockingMode : policy.nonBlockingMode;\n\t} else {\n\t\tmode = requestedMode;\n\t}\n\n\treturn mode;\n}\n\nfunction resolveWaitTimeoutMs(params: {\n\trequestedMaxWaitMs?: number;\n\tpolicyDefaultMaxWaitMs?: number;\n\tfallbackTimeoutMs: number;\n}): number {\n\tif (\n\t\ttypeof params.requestedMaxWaitMs === \"number\" &&\n\t\tNumber.isFinite(params.requestedMaxWaitMs) &&\n\t\tparams.requestedMaxWaitMs > 0\n\t) {\n\t\treturn Math.floor(params.requestedMaxWaitMs);\n\t}\n\n\tif (\n\t\ttypeof params.policyDefaultMaxWaitMs === \"number\" &&\n\t\tNumber.isFinite(params.policyDefaultMaxWaitMs) &&\n\t\tparams.policyDefaultMaxWaitMs > 0\n\t) {\n\t\treturn Math.floor(params.policyDefaultMaxWaitMs);\n\t}\n\n\treturn params.fallbackTimeoutMs;\n}\n\nfunction normalizeTranslations(params: {\n\tsourceLocale: string;\n\ttargetLocales: string[];\n\tstringEntries: TranslationStringEntry[];\n\ttranslations: TranslationMap;\n}): TranslationMap {\n\tconst merged: TranslationMap = {};\n\n\tfor (const [locale, values] of Object.entries(params.translations)) {\n\t\tmerged[locale] = { ...values };\n\t}\n\n\tconst expectedLocales = [\n\t\tparams.sourceLocale,\n\t\t...params.targetLocales.filter((locale) => locale !== params.sourceLocale),\n\t];\n\n\tfor (const locale of expectedLocales) {\n\t\tif (!merged[locale]) {\n\t\t\tmerged[locale] = {};\n\t\t}\n\t}\n\n\tif (!merged[params.sourceLocale]) {\n\t\tmerged[params.sourceLocale] = {};\n\t}\n\n\t// Ensure source locale has an identity mapping (key → text) for all known strings.\n\t// id-only entries (text: null) are skipped — their source text is in a localesPath file.\n\tfor (const entry of params.stringEntries) {\n\t\tif (!entry.text) continue;\n\t\tif (!(entry.key in merged[params.sourceLocale]!)) {\n\t\t\tmerged[params.sourceLocale]![entry.key] = entry.text;\n\t\t}\n\t}\n\n\treturn merged;\n}\n\nexport function getLimitErrorGuidance(\n\tlimitError: LimitErrorResponse,\n): string[] {\n\tif (limitError.limitType === \"providers\") {\n\t\treturn [\n\t\t\t\"Provider setup required.\",\n\t\t\t\"Add a DeepL API key in Dashboard -> Workspace Settings -> Providers.\",\n\t\t\t`Open settings: ${limitError.upgradeUrl}`,\n\t\t];\n\t}\n\n\tif (limitError.limitType === \"translation_chars\") {\n\t\treturn [\n\t\t\t\"Monthly translation character limit reached.\",\n\t\t\t`Used this month: ${limitError.current.toLocaleString()} chars`,\n\t\t\t`Requested after sync: ${limitError.required.toLocaleString()} chars`,\n\t\t\t`Upgrade plan: ${limitError.upgradeUrl}`,\n\t\t];\n\t}\n\n\tif (limitError.limitType === \"source_strings\") {\n\t\treturn [\n\t\t\t\"Active source string limit reached.\",\n\t\t\t`Current active strings: ${limitError.current.toLocaleString()}`,\n\t\t\t`Required for this sync: ${limitError.required.toLocaleString()}`,\n\t\t\t`Upgrade plan: ${limitError.upgradeUrl}`,\n\t\t];\n\t}\n\n\tif (limitError.limitType === \"target_locales\") {\n\t\treturn [\n\t\t\t`Current target locales: ${limitError.current}`,\n\t\t\t`Plan limit: ${limitError.current} (${limitError.planId})`,\n\t\t\t`Upgrade plan: ${limitError.upgradeUrl}`,\n\t\t];\n\t}\n\n\treturn [\n\t\t`Plan: ${limitError.planId}`,\n\t\t`Current: ${limitError.current}`,\n\t\t`Required: ${limitError.required}`,\n\t\t`Upgrade: ${limitError.upgradeUrl}`,\n\t];\n}\n\nfunction getSyncPolicyErrorGuidance(\n\terror: NonNullable<VocoderAPIError[\"syncPolicyError\"]>,\n): string[] {\n\tif (error.errorCode === \"BRANCH_NOT_ALLOWED\") {\n\t\tconst lines = [\"This branch is not allowed for this project.\"];\n\t\tif (error.branch) {\n\t\t\tlines.push(`Current branch: ${error.branch}`);\n\t\t}\n\t\t// targetBranches removed — configure branches in project settings\n\t\tlines.push(\n\t\t\t\"Update your project target branches in the dashboard if needed.\",\n\t\t);\n\t\treturn lines;\n\t}\n\n\tconst lines = [\"This project is bound to a different repository.\"];\n\tif (error.boundRepoLabel) {\n\t\tlines.push(`Bound repository: ${error.boundRepoLabel}`);\n\t}\n\tif (error.boundScopePath) {\n\t\tlines.push(`Bound scope: ${error.boundScopePath}`);\n\t}\n\tlines.push(\n\t\t\"Run `vocoder init` from the correct repository or create a separate project.\",\n\t);\n\treturn lines;\n}\n\nfunction mergeContext(\n\tcurrent: string | undefined,\n\tincoming: string | undefined,\n): string | undefined {\n\tif (!incoming) return current;\n\tif (!current) return incoming;\n\tif (current === incoming) return current;\n\n\tconst merged = new Set(\n\t\t[...current.split(\" | \"), ...incoming.split(\" | \")]\n\t\t\t.map((part) => part.trim())\n\t\t\t.filter(Boolean),\n\t);\n\treturn Array.from(merged).join(\" | \");\n}\n\nfunction buildStringEntries(\n\textractedStrings: ExtractedString[],\n): TranslationStringEntry[] {\n\tconst byKey = new Map<string, TranslationStringEntry>();\n\n\tfor (const str of extractedStrings) {\n\t\tconst existing = byKey.get(str.key);\n\t\tif (!existing) {\n\t\t\tbyKey.set(str.key, {\n\t\t\t\tkey: str.key,\n\t\t\t\ttext: str.text,\n\t\t\t\t...(str.context ? { context: str.context } : {}),\n\t\t\t\t...(str.formality ? { formality: str.formality } : {}),\n\t\t\t\t...(str.uiRole ? { uiRole: str.uiRole } : {}),\n\t\t\t});\n\t\t\tcontinue;\n\t\t}\n\n\t\texisting.context = mergeContext(existing.context, str.context);\n\n\t\tif (!existing.formality && str.formality) {\n\t\t\texisting.formality = str.formality;\n\t\t} else if (\n\t\t\texisting.formality &&\n\t\t\tstr.formality &&\n\t\t\texisting.formality !== str.formality\n\t\t) {\n\t\t\texisting.formality = \"auto\";\n\t\t}\n\t}\n\n\treturn Array.from(byKey.values());\n}\n\nasync function fetchApiSnapshot(\n\tapi: VocoderAPI,\n\tparams: {\n\t\tbranch: string;\n\t\ttargetLocales: string[];\n\t},\n): Promise<TranslationArtifacts | null> {\n\tconst snapshot = await api.getTranslationSnapshot({\n\t\tbranch: params.branch,\n\t\ttargetLocales: params.targetLocales,\n\t});\n\n\tif (snapshot.status !== \"FOUND\" || !snapshot.translations) {\n\t\treturn null;\n\t}\n\n\treturn {\n\t\tsource: \"api-snapshot\",\n\t\ttranslations: snapshot.translations,\n\t\tlocaleMetadata: snapshot.localeMetadata,\n\t\tsnapshotBatchId: snapshot.snapshotBatchId,\n\t\tcompletedAt: snapshot.completedAt,\n\t};\n}\n\n/**\n * Main sync command\n */\nexport async function sync(options: TranslateOptions = {}): Promise<number> {\n\tconst startTime = Date.now();\n\tconst projectRoot = process.cwd();\n\n\tp.intro(chalk.bold(\"Vocoder Sync\"));\n\n\t// Check for API key before doing any work — missing key is an onboarding\n\t// issue, not an error. Show friendly guidance and exit cleanly.\n\tconst mergedConfig = await getMergedConfig(options, options.verbose);\n\tif (!mergedConfig.apiKey) {\n\t\tp.log.warn(\"No API key found. Run init to get started:\");\n\t\tp.log.info(\" npx @vocoder/cli init\");\n\t\tp.log.info(\"\");\n\t\tp.log.info(\n\t\t\t\" Or add your key to .env: VOCODER_API_KEY=vca_...\",\n\t\t);\n\t\tp.outro(\"Run `npx @vocoder/cli init` to set up your project.\");\n\t\treturn 1;\n\t}\n\n\tconst spinner = p.spinner();\n\n\ttry {\n\t\tconst branch = detectBranch(options.branch);\n\n\t\tspinner.start(\"Loading project configuration\");\n\n\t\tconst localConfig = {\n\t\t\tapiKey: mergedConfig.apiKey,\n\t\t\tapiUrl: mergedConfig.apiUrl || \"https://vocoder.app\",\n\t\t};\n\t\tvalidateLocalConfig(localConfig);\n\n\t\tconst api = new VocoderAPI(localConfig);\n\t\tconst apiConfig = await api.getAppConfig();\n\n\t\tconst requestedMode = mergedConfig.mode;\n\t\tconst waitTimeoutMs = resolveWaitTimeoutMs({\n\t\t\trequestedMaxWaitMs: mergedConfig.maxWaitMs,\n\t\t\tpolicyDefaultMaxWaitMs: apiConfig.syncPolicy.defaultMaxWaitMs,\n\t\t\tfallbackTimeoutMs: 60_000,\n\t\t});\n\n\t\tconst fileConfig = loadVocoderConfig(process.cwd());\n\t\tconst config: ProjectConfig = {\n\t\t\t...localConfig,\n\t\t\t...apiConfig,\n\t\t\tincludePattern: mergedConfig.includePattern,\n\t\t\texcludePattern: mergedConfig.excludePattern,\n\t\t\ttimeout: waitTimeoutMs,\n\t\t\t...(fileConfig?.appIndustry ? { appIndustry: fileConfig.appIndustry } : {}),\n\t\t\t...(fileConfig?.formality ? { formality: fileConfig.formality } : {}),\n\t\t};\n\n\t\tspinner.stop(`Branch: ${highlight(branch)}`);\n\n\t\tif (!options.force && !isTargetBranch(branch, config.targetBranches)) {\n\t\t\tp.log.warn(\n\t\t\t\t`Skipping translations (${highlight(branch)} is not a target branch)`,\n\t\t\t);\n\t\t\tp.log.info(`Target branches: ${config.targetBranches.map((b) => highlight(b)).join(\", \")}`);\n\t\t\tp.log.info(\"Use --force to translate anyway\");\n\t\t\tp.outro(\"\");\n\t\t\treturn 0;\n\t\t}\n\n\t\tconst patternsDisplay = Array.isArray(config.includePattern)\n\t\t\t? config.includePattern.join(\", \")\n\t\t\t: config.includePattern;\n\n\t\tspinner.start(`Extracting strings from ${patternsDisplay}`);\n\t\tconst extractor = new StringExtractor();\n\t\tconst extractedStrings = await extractor.extractFromProject(\n\t\t\tconfig.includePattern,\n\t\t\tprojectRoot,\n\t\t\tconfig.excludePattern,\n\t\t);\n\n\t\tif (extractedStrings.length === 0) {\n\t\t\tspinner.stop(\"No translatable strings found\");\n\t\t\tp.log.warn(\n\t\t\t\t\"Make sure you are wrapping translatable strings with Vocoder\",\n\t\t\t);\n\t\t\tp.outro(\"\");\n\t\t\treturn 0;\n\t\t}\n\n\t\tspinner.stop(\n\t\t\t`Extracted ${highlight(extractedStrings.length)} strings from ${highlight(patternsDisplay)}`,\n\t\t);\n\n\t\tif (options.verbose) {\n\t\t\tconst sampleLines = extractedStrings\n\t\t\t\t.slice(0, 5)\n\t\t\t\t.map((s: ExtractedString) => ` \"${s.text}\" (${s.file}:${s.line})`);\n\t\t\tif (extractedStrings.length > 5) {\n\t\t\t\tsampleLines.push(` ... and ${extractedStrings.length - 5} more`);\n\t\t\t}\n\t\t\tp.note(sampleLines.join(\"\\n\"), \"Sample strings\");\n\t\t}\n\n\t\tif (options.dryRun) {\n\t\t\tp.note(\n\t\t\t\t[\n\t\t\t\t\t`Strings: ${extractedStrings.length}`,\n\t\t\t\t\t`Branch: ${branch}`,\n\t\t\t\t\t`Target locales: ${config.targetLocales.map((l) => highlight(l)).join(\", \")}`,\n\t\t\t\t\t`Requested mode: ${requestedMode}`,\n\t\t\t\t\t`Max wait: ${waitTimeoutMs}ms`,\n\t\t\t\t\t`No fallback: ${mergedConfig.noFallback ? \"yes\" : \"no\"}`,\n\t\t\t\t].join(\"\\n\"),\n\t\t\t\t\"Dry run - would translate\",\n\t\t\t);\n\t\t\tp.outro(\"No API calls made.\");\n\t\t\treturn 0;\n\t\t}\n\n\t\tconst repoIdentity = resolveGitRepositoryIdentity();\n\t\tif (!repoIdentity && options.verbose) {\n\t\t\tp.log.warn(\n\t\t\t\t\"Could not detect git remote origin. Sync will continue without repo metadata.\",\n\t\t\t);\n\t\t}\n\t\tconst commitSha = detectCommitSha() ?? undefined;\n\n\t\tconst stringEntries = buildStringEntries(extractedStrings);\n\n\t\tif (options.verbose && stringEntries.length !== extractedStrings.length) {\n\t\t\tp.log.info(\n\t\t\t\t`Deduped ${extractedStrings.length} extracted entries into ${stringEntries.length} unique strings`,\n\t\t\t);\n\t\t}\n\n\t\t// Fingerprint uses source keys (not texts) — one text can produce multiple keys via\n\t\t// formality/context, so keying by text would produce an incorrect CDN bundle URL.\n\t\tconst sourceKeys = stringEntries.map((entry) => entry.key);\n\t\tconst fingerprint = computeFingerprint(extractShortCodeFromApiKey(localConfig.apiKey), sourceKeys);\n\n\t\t// Local cache check — skip API submission if translations already exist for this fingerprint.\n\t\tif (!options.force) {\n\t\t\tconst cacheFile = getCacheFilePath(projectRoot, fingerprint);\n\t\t\tif (existsSync(cacheFile)) {\n\t\t\t\tif (options.verbose) {\n\t\t\t\t\tp.log.info(`Cache hit: ${chalk.dim(cacheFile)} (fingerprint ${highlight(fingerprint)})`);\n\t\t\t\t}\n\t\t\t\tconst duration = ((Date.now() - startTime) / 1000).toFixed(1);\n\t\t\t\tp.outro(`Up to date (${duration}s)`);\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t\tif (options.verbose) {\n\t\t\t\tp.log.info(`No cache for fingerprint ${highlight(fingerprint)} — will submit to API`);\n\t\t\t}\n\t\t}\n\n\t\tspinner.start(\"Submitting strings to Vocoder API\");\n\n\t\tconst batchResponse = await api.submitTranslation(\n\t\t\tbranch,\n\t\t\tstringEntries,\n\t\t\tconfig.targetLocales,\n\t\t\t{\n\t\t\t\trequestedMode,\n\t\t\t\trequestedMaxWaitMs: waitTimeoutMs,\n\t\t\t\tclientRunId: randomUUID(),\n\t\t\t\tforce: options.force,\n\t\t\t\t// Sync appIndustry from vocoder.config.ts to App on every push\n\t\t\t\t...(config.appIndustry ? { appIndustry: config.appIndustry } : {}),\n\t\t\t},\n\t\t\trepoIdentity ? { ...repoIdentity, commitSha } : { commitSha },\n\t\t);\n\n\t\tspinner.stop(\"Strings submitted\");\n\n\t\tconst effectiveMode =\n\t\t\tbatchResponse.effectiveMode ??\n\t\t\tresolveEffectiveModeFromPolicy({\n\t\t\t\tbranch,\n\t\t\t\trequestedMode,\n\t\t\t\tpolicy: config.syncPolicy,\n\t\t\t});\n\n\t\tif (options.verbose) {\n\t\t\tp.log.info(`Batch: ${chalk.dim(batchResponse.batchId)}`);\n\t\t\tp.log.info(`Requested mode: ${requestedMode}`);\n\t\t\tp.log.info(`Effective mode: ${effectiveMode}`);\n\t\t\tp.log.info(`Wait timeout: ${waitTimeoutMs}ms`);\n\t\t\tif (batchResponse.queueStatus) {\n\t\t\t\tp.log.info(`Queue status: ${batchResponse.queueStatus}`);\n\t\t\t}\n\t\t}\n\n\t\tif (batchResponse.status === \"UP_TO_DATE\" && batchResponse.noChanges) {\n\t\t\tp.log.success(`Up to date — ${highlight(batchResponse.totalStrings)} strings, no changes`);\n\t\t} else if (batchResponse.newStrings === 0) {\n\t\t\tconst archivedNote =\n\t\t\t\tbatchResponse.deletedStrings && batchResponse.deletedStrings > 0\n\t\t\t\t\t? `, ${chalk.yellow(batchResponse.deletedStrings)} archived`\n\t\t\t\t\t: \"\";\n\t\t\tp.log.success(`No new strings — ${highlight(batchResponse.totalStrings)} total${archivedNote}, using existing translations`);\n\t\t} else {\n\t\t\tconst statParts = [`${highlight(batchResponse.newStrings)} new, ${highlight(batchResponse.totalStrings)} total`];\n\t\t\tif (batchResponse.deletedStrings && batchResponse.deletedStrings > 0) {\n\t\t\t\tstatParts.push(`${chalk.yellow(batchResponse.deletedStrings)} archived`);\n\t\t\t}\n\t\t\tconst estTime = batchResponse.estimatedTime ? ` (~${batchResponse.estimatedTime}s)` : \"\";\n\t\t\tp.log.info(`${statParts.join(\", \")} → syncing to ${config.targetLocales.map((l) => highlight(l)).join(\", \")}${estTime}`);\n\t\t}\n\n\t\tlet artifacts: TranslationArtifacts | null = null;\n\t\tif (batchResponse.translations) {\n\t\t\tartifacts = {\n\t\t\t\tsource: \"fresh\",\n\t\t\t\ttranslations: batchResponse.translations,\n\t\t\t};\n\t\t}\n\n\t\tlet waitError: Error | null = null;\n\t\tif (\n\t\t\t!artifacts &&\n\t\t\t(effectiveMode === \"required\" || effectiveMode === \"best-effort\")\n\t\t) {\n\t\t\tconst waitTimeoutSecs = Math.round(waitTimeoutMs / 1000);\n\t\t\tspinner.start(`Waiting for translations (max ${waitTimeoutSecs}s)`);\n\n\t\t\tlet lastProgress = 0;\n\t\t\ttry {\n\t\t\t\tconst completion = await api.waitForCompletion(\n\t\t\t\t\tbatchResponse.batchId,\n\t\t\t\t\twaitTimeoutMs,\n\t\t\t\t\t(progress) => {\n\t\t\t\t\t\tconst percent = Math.round(progress * 100);\n\t\t\t\t\t\tif (percent > lastProgress) {\n\t\t\t\t\t\t\tspinner.message(`Translating... ${percent}%`);\n\t\t\t\t\t\t\tlastProgress = percent;\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t);\n\n\t\t\t\tartifacts = {\n\t\t\t\t\tsource: \"fresh\",\n\t\t\t\t\ttranslations: completion.translations,\n\t\t\t\t\tlocaleMetadata: completion.localeMetadata,\n\t\t\t\t};\n\t\t\t\tspinner.stop(\"Translations complete\");\n\t\t\t} catch (error) {\n\t\t\t\tspinner.stop(\"Translation wait incomplete\");\n\t\t\t\twaitError = error instanceof Error ? error : new Error(String(error));\n\n\t\t\t\tif (effectiveMode === \"required\") {\n\t\t\t\t\tthrow waitError;\n\t\t\t\t}\n\n\t\t\t\tp.log.warn(`Best-effort wait ended early: ${waitError.message}`);\n\t\t\t}\n\t\t}\n\n\t\tif (!artifacts) {\n\t\t\tif (mergedConfig.noFallback) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t\"Fresh translations are not available and fallback is disabled (--no-fallback).\",\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tspinner.start(\"Loading fallback translations\");\n\n\t\t\tconst localFallback = readLocalCache({\n\t\t\t\tprojectRoot,\n\t\t\t\tfingerprint,\n\t\t\t});\n\n\t\t\tif (localFallback) {\n\t\t\t\tartifacts = localFallback;\n\t\t\t\tspinner.stop(`Using local cached snapshot (${fingerprint})`);\n\t\t\t} else {\n\t\t\t\ttry {\n\t\t\t\t\tconst apiSnapshot = await fetchApiSnapshot(api, {\n\t\t\t\t\t\tbranch,\n\t\t\t\t\t\ttargetLocales: config.targetLocales,\n\t\t\t\t\t});\n\n\t\t\t\t\tif (apiSnapshot) {\n\t\t\t\t\t\tartifacts = apiSnapshot;\n\t\t\t\t\t\tspinner.stop(\"Using latest completed API snapshot\");\n\t\t\t\t\t} else {\n\t\t\t\t\t\tspinner.stop(\"No completed API snapshot available\");\n\t\t\t\t\t}\n\t\t\t\t} catch (error) {\n\t\t\t\t\tspinner.stop(\"Failed to fetch API snapshot\");\n\t\t\t\t\tif (options.verbose) {\n\t\t\t\t\t\tconst message =\n\t\t\t\t\t\t\terror instanceof Error\n\t\t\t\t\t\t\t\t? error.message\n\t\t\t\t\t\t\t\t: \"Unknown snapshot fetch error\";\n\t\t\t\t\t\tp.log.warn(`Snapshot fetch error: ${message}`);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (!artifacts) {\n\t\t\t\tif (waitError) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`No fallback snapshot available after wait failure: ${waitError.message}`,\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tthrow new Error(\n\t\t\t\t\t\"No fallback snapshot available. Try again shortly or run with --mode required.\",\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tconst finalTranslations = normalizeTranslations({\n\t\t\tsourceLocale: config.sourceLocale,\n\t\t\ttargetLocales: config.targetLocales,\n\t\t\tstringEntries,\n\t\t\ttranslations: artifacts.translations,\n\t\t});\n\n\t\ttry {\n\t\t\tconst data = buildTranslationData({\n\t\t\t\tsourceLocale: config.sourceLocale,\n\t\t\t\ttargetLocales: config.targetLocales,\n\t\t\t\ttranslations: finalTranslations,\n\t\t\t\tlocaleMetadata: artifacts.localeMetadata,\n\t\t\t\tupdatedAt: new Date().toISOString(),\n\t\t\t});\n\t\t\tconst cachePath = writeCache({ projectRoot, fingerprint, data });\n\t\t\tif (options.verbose) {\n\t\t\t\tp.log.info(`Cache written: ${highlight(cachePath)}`);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tif (options.verbose) {\n\t\t\t\tconst message =\n\t\t\t\t\terror instanceof Error ? error.message : \"Unknown cache write error\";\n\t\t\t\tp.log.warn(`Failed to write cache: ${message}`);\n\t\t\t}\n\t\t}\n\n\t\tif (artifacts.source !== \"fresh\") {\n\t\t\tconst sourceLabel =\n\t\t\t\tartifacts.source === \"local-cache\"\n\t\t\t\t\t? \"local cached snapshot\"\n\t\t\t\t\t: \"completed API snapshot\";\n\t\t\tp.log.warn(\n\t\t\t\t`Using ${sourceLabel}. New strings may appear after the background sync completes.`,\n\t\t\t);\n\t\t}\n\n\t\tconst duration = ((Date.now() - startTime) / 1000).toFixed(1);\n\t\tp.outro(`Sync complete! (${duration}s)`);\n\t\treturn 0;\n\t} catch (error) {\n\t\tspinner.stop();\n\n\t\tif (error instanceof VocoderAPIError && error.syncPolicyError) {\n\t\t\tp.log.error(error.syncPolicyError.message);\n\t\t\tconst guidance = getSyncPolicyErrorGuidance(error.syncPolicyError);\n\t\t\tfor (const line of guidance) {\n\t\t\t\tp.log.info(line);\n\t\t\t}\n\t\t\treturn 1;\n\t\t}\n\n\t\tif (error instanceof VocoderAPIError && error.limitError) {\n\t\t\tconst { limitError } = error;\n\t\t\tp.log.error(limitError.message);\n\t\t\tconst guidance = getLimitErrorGuidance(limitError);\n\t\t\tfor (const line of guidance) {\n\t\t\t\tp.log.info(line);\n\t\t\t}\n\t\t\treturn 1;\n\t\t}\n\n\t\tif (error instanceof Error) {\n\t\t\tp.log.error(error.message);\n\n\t\t\tconst isInvalidKey =\n\t\t\t\terror.message.toLowerCase().includes(\"invalid api key\") ||\n\t\t\t\t(error instanceof VocoderAPIError && error.status === 401);\n\n\t\t\tif (isInvalidKey) {\n\t\t\t\tp.log.warn(\n\t\t\t\t\t\"API key rejected — the project may have been deleted or the key revoked.\",\n\t\t\t\t);\n\t\t\t\tp.log.info(\n\t\t\t\t\t\" Run `npx @vocoder/cli init` to create a new project and key.\",\n\t\t\t\t);\n\t\t\t} else if (error.message.includes(\"git branch\")) {\n\t\t\t\tp.log.warn(\"Run from a git repository, or use:\");\n\t\t\t\tp.log.info(\" vocoder sync --branch main\");\n\t\t\t}\n\n\t\t\tif (options.verbose) {\n\t\t\t\tp.log.info(`Full error: ${error.stack ?? error}`);\n\t\t\t}\n\t\t}\n\n\t\treturn 1;\n\t}\n}\n","import { execSync } from \"node:child_process\";\n\nconst REGEX_SPECIAL_CHARS = /[.+?^${}()|[\\]\\\\]/g;\n\nfunction escapeRegexChar(value: string): string {\n\treturn value.replace(REGEX_SPECIAL_CHARS, \"\\\\$&\");\n}\n\n/**\n * Detects the current git branch from multiple sources in priority order:\n * 1. Explicit --branch flag (passed as parameter)\n * 2. CI environment variables (GitHub Actions, Vercel, Netlify, etc.)\n * 3. Git command (local development)\n *\n * @param override - Optional branch name to override detection\n * @returns The current branch name\n */\nexport function detectBranch(override?: string): string {\n\t// 1. Explicit override (from --branch flag)\n\tif (override) {\n\t\treturn override;\n\t}\n\n\t// 2. CI environment variables\n\tconst envBranch =\n\t\tprocess.env.GITHUB_HEAD_REF || // GitHub Actions (PR source branch)\n\t\tprocess.env.GITHUB_REF_NAME || // GitHub Actions (push)\n\t\tprocess.env.VERCEL_GIT_COMMIT_REF || // Vercel\n\t\tprocess.env.BRANCH || // Netlify\n\t\tprocess.env.CF_PAGES_BRANCH || // Cloudflare Pages\n\t\tprocess.env.CI_COMMIT_REF_NAME || // GitLab CI\n\t\tprocess.env.BITBUCKET_BRANCH || // Bitbucket Pipelines\n\t\tprocess.env.CIRCLE_BRANCH || // CircleCI\n\t\tprocess.env.RENDER_GIT_BRANCH; // Render\n\n\tif (envBranch) {\n\t\treturn envBranch;\n\t}\n\n\t// 3. Git command (local development)\n\ttry {\n\t\tconst branch = execSync(\"git rev-parse --abbrev-ref HEAD\", {\n\t\t\tencoding: \"utf-8\",\n\t\t\tstdio: [\"pipe\", \"pipe\", \"ignore\"],\n\t\t}).trim();\n\n\t\treturn branch;\n\t} catch (_error) {\n\t\tthrow new Error(\n\t\t\t\"Failed to detect git branch. Make sure you are in a git repository or set the --branch flag.\",\n\t\t);\n\t}\n}\n\n/**\n * Checks if the current branch is a target branch that should trigger translations\n *\n * @param currentBranch - The current branch name\n * @param targetBranches - List of branches that should trigger translations\n * @returns True if the branch should trigger translations\n */\nexport function isTargetBranch(\n\tcurrentBranch: string,\n\ttargetBranches: string[],\n): boolean {\n\treturn targetBranches.some((pattern) =>\n\t\tmatchBranchPattern(currentBranch, pattern),\n\t);\n}\n\nexport function matchBranchPattern(branch: string, pattern: string): boolean {\n\tconst trimmedPattern = pattern.trim();\n\tif (!trimmedPattern) {\n\t\treturn false;\n\t}\n\n\tlet regexSource = \"^\";\n\tfor (let i = 0; i < trimmedPattern.length; i += 1) {\n\t\tconst char = trimmedPattern[i];\n\t\tif (!char) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (char === \"*\") {\n\t\t\tconst next = trimmedPattern[i + 1];\n\t\t\tif (next === \"*\") {\n\t\t\t\tregexSource += \".*\";\n\t\t\t\ti += 1;\n\t\t\t} else {\n\t\t\t\tregexSource += \"[^/]*\";\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\tregexSource += escapeRegexChar(char);\n\t}\n\tregexSource += \"$\";\n\n\treturn new RegExp(regexSource).test(branch);\n}\n","import * as p from \"@clack/prompts\";\nimport chalk from \"chalk\";\nimport { active, highlight } from \"./theme.js\";\nimport { config as loadEnv } from \"dotenv\";\nimport { loadVocoderConfig } from \"@vocoder/extractor\";\nimport type {\n\tLocalConfig,\n\tRequestedSyncMode,\n\tTranslateOptions,\n} from \"../types.js\";\n\n// Load .env file if present\nloadEnv();\n\n/**\n * Extracts the app short code embedded in the API key token.\n * Key format: vca_{shortCode(10)}_{random(22)}\n * Safe to call offline — no network required.\n */\nexport function extractShortCodeFromApiKey(apiKey: string): string {\n\treturn apiKey.slice(4, 14);\n}\n\n/**\n * Validates the local configuration\n */\nexport function validateLocalConfig(config: LocalConfig): void {\n\tif (!config.apiKey || config.apiKey.length === 0) {\n\t\tthrow new Error(\"VOCODER_API_KEY is required. Set it in your .env file.\");\n\t}\n\n\tif (!config.apiKey.startsWith(\"vca_\")) {\n\t\tthrow new Error(\n\t\t\t\"Invalid API key format. Expected an app API key starting with vca_.\",\n\t\t);\n\t}\n\n\tif (!config.apiUrl || !config.apiUrl.startsWith(\"http\")) {\n\t\tthrow new Error(\"Invalid API URL\");\n\t}\n}\n\n/**\n * Merge configuration from all sources with priority:\n * 1. CLI flags (highest priority)\n * 2. Environment variables\n * 3. Defaults (lowest priority)\n *\n * @param cliOptions - Options from CLI flags\n * @param verbose - Whether to log config sources\n * @returns Merged configuration with source information\n */\nexport async function getMergedConfig(\n\tcliOptions: TranslateOptions,\n\tverbose: boolean = false,\n\t_startDir?: string,\n): Promise<{\n\tincludePattern: string[];\n\texcludePattern: string[];\n\tapiKey?: string;\n\tapiUrl?: string;\n\tmode: RequestedSyncMode;\n\tmaxWaitMs?: number;\n\tnoFallback: boolean;\n\tconfigSources: {\n\t\tincludePattern: string;\n\t\texcludePattern: string;\n\t\tapiKey: string;\n\t\tapiUrl: string;\n\t\tmode: string;\n\t\tmaxWaitMs: string;\n\t\tnoFallback: string;\n\t};\n}> {\n\tconst configSources = {\n\t\tincludePattern: \"default\",\n\t\texcludePattern: \"default\",\n\t\tapiKey: \"environment\",\n\t\tapiUrl: \"default\",\n\t\tmode: \"default\",\n\t\tmaxWaitMs: \"default\",\n\t\tnoFallback: \"default\",\n\t};\n\n\t// 1. Defaults\n\tconst defaults = {\n\t\tincludePattern: [\"**/*.{tsx,jsx,ts,js}\"],\n\t\texcludePattern: [\n\t\t\t\"**/node_modules/**\",\n\t\t\t\"**/.next/**\",\n\t\t\t\"**/.nuxt/**\",\n\t\t\t\"**/.svelte-kit/**\",\n\t\t\t\"**/.output/**\",\n\t\t\t\"**/dist/**\",\n\t\t\t\"**/build/**\",\n\t\t\t\"**/out/**\",\n\t\t\t\"**/.vite/**\",\n\t\t\t\"**/.turbo/**\",\n\t\t\t\"**/coverage/**\",\n\t\t\t\"**/.cache/**\",\n\t\t\t\"**/*.min.js\",\n\t\t\t\"**/*.min.ts\",\n\t\t\t\"**/__generated__/**\",\n\t\t\t\"**/*.test.*\",\n\t\t\t\"**/*.spec.*\",\n\t\t\t\"**/*.stories.*\",\n\t\t\t\"**/__tests__/**\",\n\t\t],\n\t\tapiUrl: \"https://vocoder.app\",\n\t};\n\n\t// 2. vocoder.config.ts — the canonical source for extraction patterns.\n\t// CLI flags still override it for one-off runs.\n\tconst fileConfig = loadVocoderConfig(process.cwd());\n\n\tif (!fileConfig) {\n\t\tp.log.warn(\n\t\t\t`No ${highlight(\"vocoder.config.ts\")} found — run ${highlight(\"npx @vocoder/cli init\")} to generate one.`,\n\t\t);\n\t}\n\n\t// 3. Environment variables (legacy, lower priority than config file)\n\tconst envExtractionPattern = process.env.VOCODER_INCLUDE_PATTERN;\n\tconst envExcludePattern = process.env.VOCODER_EXCLUDE_PATTERN;\n\tconst envApiUrl = process.env.VOCODER_API_URL;\n\tconst envSyncMode = process.env.VOCODER_SYNC_MODE;\n\tconst envSyncMaxWaitMs = process.env.VOCODER_SYNC_MAX_WAIT_MS;\n\tconst envSyncNoFallback = process.env.VOCODER_SYNC_NO_FALLBACK;\n\n\t// 4. Merge with priority: CLI flag > vocoder.config.ts > env > defaults\n\n\t// Extract patterns (include)\n\tlet includePattern: string[];\n\tif (cliOptions.include && cliOptions.include.length > 0) {\n\t\tincludePattern = cliOptions.include;\n\t\tconfigSources.includePattern = \"CLI flag\";\n\t} else if (fileConfig?.include && fileConfig.include.length > 0) {\n\t\tincludePattern = fileConfig.include;\n\t\tconfigSources.includePattern = \"vocoder.config\";\n\t} else if (envExtractionPattern) {\n\t\tincludePattern = [envExtractionPattern];\n\t\tconfigSources.includePattern = \"environment\";\n\t} else {\n\t\tincludePattern = defaults.includePattern;\n\t}\n\n\t// Exclude patterns\n\tlet excludePattern: string[];\n\tif (cliOptions.exclude && cliOptions.exclude.length > 0) {\n\t\texcludePattern = cliOptions.exclude;\n\t\tconfigSources.excludePattern = \"CLI flag\";\n\t} else if (fileConfig?.exclude && fileConfig.exclude.length > 0) {\n\t\texcludePattern = fileConfig.exclude;\n\t\tconfigSources.excludePattern = \"vocoder.config\";\n\t} else if (envExcludePattern) {\n\t\texcludePattern = envExcludePattern\n\t\t\t.split(\",\")\n\t\t\t.map((p: string) => p.trim())\n\t\t\t.filter(Boolean);\n\t\tconfigSources.excludePattern = \"environment\";\n\t} else {\n\t\texcludePattern = defaults.excludePattern;\n\t}\n\n\t// API key (from env)\n\tlet apiKey: string | undefined;\n\tif (process.env.VOCODER_API_KEY) {\n\t\tapiKey = process.env.VOCODER_API_KEY;\n\t\tconfigSources.apiKey = \"environment\";\n\t}\n\n\t// API URL\n\tlet apiUrl: string;\n\tif (envApiUrl) {\n\t\tapiUrl = envApiUrl;\n\t\tconfigSources.apiUrl = \"environment\";\n\t} else {\n\t\tapiUrl = defaults.apiUrl;\n\t}\n\n\tconst modeCandidates = [\"auto\", \"required\", \"best-effort\"] as const;\n\tlet mode: RequestedSyncMode = \"auto\";\n\tif (cliOptions.mode && modeCandidates.includes(cliOptions.mode)) {\n\t\tmode = cliOptions.mode;\n\t\tconfigSources.mode = \"CLI flag\";\n\t} else if (\n\t\tenvSyncMode &&\n\t\tmodeCandidates.includes(envSyncMode as RequestedSyncMode)\n\t) {\n\t\tmode = envSyncMode as RequestedSyncMode;\n\t\tconfigSources.mode = \"environment\";\n\t}\n\n\tlet maxWaitMs: number | undefined;\n\tif (\n\t\ttypeof cliOptions.maxWaitMs === \"number\" &&\n\t\tNumber.isFinite(cliOptions.maxWaitMs) &&\n\t\tcliOptions.maxWaitMs > 0\n\t) {\n\t\tmaxWaitMs = Math.floor(cliOptions.maxWaitMs);\n\t\tconfigSources.maxWaitMs = \"CLI flag\";\n\t} else if (envSyncMaxWaitMs) {\n\t\tconst parsed = Number.parseInt(envSyncMaxWaitMs, 10);\n\t\tif (Number.isFinite(parsed) && parsed > 0) {\n\t\t\tmaxWaitMs = parsed;\n\t\t\tconfigSources.maxWaitMs = \"environment\";\n\t\t}\n\t}\n\n\tlet noFallback = false;\n\tif (typeof cliOptions.noFallback === \"boolean\") {\n\t\tnoFallback = cliOptions.noFallback;\n\t\tconfigSources.noFallback = \"CLI flag\";\n\t} else if (envSyncNoFallback) {\n\t\tnoFallback = [\"1\", \"true\", \"yes\", \"on\"].includes(\n\t\t\tenvSyncNoFallback.toLowerCase(),\n\t\t);\n\t\tconfigSources.noFallback = \"environment\";\n\t}\n\n\t// Log config sources in verbose mode\n\tif (verbose) {\n\t\tconst lines = [\n\t\t\t`Include patterns: ${highlight(configSources.includePattern)}`,\n\t\t\t...(excludePattern.length > 0\n\t\t\t\t? [`Exclude patterns: ${highlight(configSources.excludePattern)}`]\n\t\t\t\t: []),\n\t\t\t`API key: ${highlight(configSources.apiKey)}`,\n\t\t\t`API URL: ${highlight(configSources.apiUrl)}`,\n\t\t\t`Sync mode: ${highlight(configSources.mode)}`,\n\t\t\t...(maxWaitMs\n\t\t\t\t? [`Max wait: ${highlight(String(configSources.maxWaitMs))}`]\n\t\t\t\t: []),\n\t\t\t`No fallback: ${highlight(String(configSources.noFallback))}`,\n\t\t];\n\t\tp.note(lines.join(\"\\n\"), \"Configuration sources\");\n\t}\n\n\treturn {\n\t\tincludePattern,\n\t\texcludePattern,\n\t\tapiKey,\n\t\tapiUrl,\n\t\tmode,\n\t\tmaxWaitMs,\n\t\tnoFallback,\n\t\tconfigSources,\n\t};\n}\n","import * as p from \"@clack/prompts\";\nimport { VocoderAPI } from \"../utils/api.js\";\nimport { clearAuthData, readAuthData } from \"../utils/auth-store.js\";\n\nexport interface LogoutOptions {\n\tapiUrl?: string;\n}\n\nexport async function logout(options: LogoutOptions = {}): Promise<number> {\n\tconst stored = readAuthData();\n\n\tif (!stored) {\n\t\tp.log.info(\"Not currently authenticated.\");\n\t\treturn 0;\n\t}\n\n\tconst apiUrl = options.apiUrl ?? stored.apiUrl ?? \"https://vocoder.app\";\n\tconst api = new VocoderAPI({ apiUrl, apiKey: \"\" });\n\n\ttry {\n\t\tawait api.revokeCliToken(stored.token);\n\t} catch {\n\t\t// Ignore errors — we still clear local data even if the server call fails\n\t}\n\n\tclearAuthData();\n\tp.log.success(`Logged out (was ${stored.email})`);\n\treturn 0;\n}\n","import * as p from \"@clack/prompts\";\nimport chalk from \"chalk\";\nimport { active, highlight } from \"../utils/theme.js\";\nimport { config as loadEnv } from \"dotenv\";\nimport { VocoderAPI } from \"../utils/api.js\";\n\nloadEnv();\n\nexport interface AppConfigOptions {\n\tapiUrl?: string;\n}\n\n/**\n * Displays the current Vocoder app configuration.\n *\n * Shows: project name, organization, source locale, target locales,\n * target branches, primary branch, and sync policy settings.\n *\n * Reads the app API key from VOCODER_API_KEY.\n * Endpoint: GET /api/cli/config\n *\n * @throws If VOCODER_API_KEY is missing or invalid.\n */\nexport async function appConfig(options: AppConfigOptions = {}): Promise<number> {\n\tconst apiKey = process.env.VOCODER_API_KEY;\n\tif (!apiKey) {\n\t\tp.log.error(\n\t\t\t\"VOCODER_API_KEY is not set. Run `npx @vocoder/cli init` to set up your project.\",\n\t\t);\n\t\treturn 1;\n\t}\n\n\tconst apiUrl = options.apiUrl ?? process.env.VOCODER_API_URL ?? \"https://vocoder.app\";\n\tconst api = new VocoderAPI({ apiKey, apiUrl });\n\n\ttry {\n\t\tconst config = await api.getAppConfig();\n\n\t\tconst lines = [\n\t\t\t`App: ${chalk.bold(config.projectName)}`,\n\t\t\t`Organization: ${config.organizationName}`,\n\t\t\t`Source locale: ${highlight(config.sourceLocale)}`,\n\t\t\t`Target locales: ${\n\t\t\t\tconfig.targetLocales.length > 0\n\t\t\t\t\t? config.targetLocales.map((l) => highlight(l)).join(\", \")\n\t\t\t\t\t: chalk.dim(\"(none)\")\n\t\t\t}`,\n\t\t\t`Target branches: ${config.targetBranches.map((b) => highlight(b)).join(\", \")}`,\n\t\t\t...(config.primaryBranch\n\t\t\t\t? [`Primary branch: ${highlight(config.primaryBranch)}`]\n\t\t\t\t: []),\n\t\t\t`Sync policy:`,\n\t\t\t` Blocking branches: ${config.syncPolicy.blockingBranches.map((b) => highlight(b)).join(\", \")}`,\n\t\t\t` Blocking mode: ${highlight(config.syncPolicy.blockingMode)}`,\n\t\t\t` Non-blocking mode: ${highlight(config.syncPolicy.nonBlockingMode)}`,\n\t\t\t` Max wait: ${highlight(String(config.syncPolicy.defaultMaxWaitMs))} ms`,\n\t\t];\n\n\t\tp.note(lines.join(\"\\n\"), `${config.projectName} — app config`);\n\t\treturn 0;\n\t} catch (error) {\n\t\tp.log.error(\n\t\t\terror instanceof Error ? error.message : \"Failed to fetch project config.\",\n\t\t);\n\t\treturn 1;\n\t}\n}\n","import { mkdirSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport * as p from \"@clack/prompts\";\nimport chalk from \"chalk\";\nimport { active, highlight } from \"../utils/theme.js\";\nimport { config as loadEnv } from \"dotenv\";\nimport { VocoderAPI } from \"../utils/api.js\";\nimport { detectBranch } from \"../utils/branch.js\";\n\nloadEnv();\n\nexport interface TranslationsOptions {\n\t/** Git branch. Auto-detected from git/CI env if omitted. */\n\tbranch?: string;\n\t/** Specific target locale to fetch. All configured locales if omitted. */\n\tlocale?: string;\n\t/**\n\t * Output directory for locale JSON files.\n\t * When set, writes one <locale>.json per locale to this directory.\n\t * When omitted, prints the full snapshot as JSON to stdout.\n\t */\n\toutput?: string;\n\tapiUrl?: string;\n}\n\n/**\n * Downloads the current translation snapshot for the project.\n *\n * With --output <dir>: writes one <locale>.json file per locale to the\n * specified directory. Each file shape: { \"source text\": \"translated text\" }.\n *\n * Without --output: prints the full snapshot JSON to stdout, suitable\n * for piping or programmatic use.\n *\n * Reads the project API key from VOCODER_API_KEY.\n * Endpoint: GET /api/cli/sync/snapshot\n *\n * @param options.branch Git branch (auto-detected from git/CI if omitted).\n * @param options.locale Specific target locale; all configured locales if omitted.\n * @param options.output Output directory. Omit to print to stdout.\n *\n * @throws If VOCODER_API_KEY is missing or invalid.\n */\nexport async function getTranslations(options: TranslationsOptions = {}): Promise<number> {\n\tconst apiKey = process.env.VOCODER_API_KEY;\n\tif (!apiKey) {\n\t\tp.log.error(\n\t\t\t\"VOCODER_API_KEY is not set. Run `npx @vocoder/cli init` to set up your project.\",\n\t\t);\n\t\treturn 1;\n\t}\n\n\tconst apiUrl = options.apiUrl ?? process.env.VOCODER_API_URL ?? \"https://vocoder.app\";\n\tconst api = new VocoderAPI({ apiKey, apiUrl });\n\n\tlet branch: string;\n\ttry {\n\t\tbranch = detectBranch(options.branch);\n\t} catch (error) {\n\t\tp.log.error(\n\t\t\terror instanceof Error ? error.message : \"Failed to detect branch.\",\n\t\t);\n\t\treturn 1;\n\t}\n\n\tconst spinner = p.spinner();\n\tspinner.start(`Fetching translations for ${highlight(branch)}…`);\n\n\ttry {\n\t\t// Fetch the project config to resolve which target locales to request\n\t\tconst projectConfig = await api.getAppConfig();\n\t\tconst targetLocales = options.locale\n\t\t\t? [options.locale]\n\t\t\t: projectConfig.targetLocales;\n\n\t\tif (targetLocales.length === 0) {\n\t\t\tspinner.stop(\"No target locales configured.\");\n\t\t\tp.log.info(\"Add target locales with `vocoder locales add <code>`.\");\n\t\t\treturn 1;\n\t\t}\n\n\t\tconst snapshot = await api.getTranslationSnapshot({ branch, targetLocales });\n\t\tspinner.stop(`Fetched translations for ${highlight(branch)}`);\n\n\t\tif (snapshot.status === \"NOT_FOUND\") {\n\t\t\tp.log.warn(\n\t\t\t\t`No translation snapshot found for branch \"${branch}\". ` +\n\t\t\t\t\t\"Run `vocoder sync` to generate one.\",\n\t\t\t);\n\t\t\treturn 1;\n\t\t}\n\n\t\tconst translations = snapshot.translations ?? {};\n\n\t\tif (options.output) {\n\t\t\twriteLocaleFiles(translations, options.output);\n\t\t} else {\n\t\t\t// stdout — raw JSON for piping/programmatic use\n\t\t\tprocess.stdout.write(JSON.stringify(translations, null, 2));\n\t\t\tprocess.stdout.write(\"\\n\");\n\t\t}\n\n\t\treturn 0;\n\t} catch (error) {\n\t\tspinner.stop(\"Failed to fetch translations.\");\n\t\tp.log.error(\n\t\t\terror instanceof Error ? error.message : \"Unknown error.\",\n\t\t);\n\t\treturn 1;\n\t}\n}\n\n/**\n * Writes one <locale>.json file per locale to the output directory.\n * Creates the directory if it does not exist.\n * Each file shape: { \"source text\": \"translated text\" }\n */\nfunction writeLocaleFiles(\n\ttranslations: Record<string, Record<string, string>>,\n\toutputDir: string,\n): void {\n\tmkdirSync(outputDir, { recursive: true });\n\n\tfor (const [locale, strings] of Object.entries(translations)) {\n\t\tconst filePath = join(outputDir, `${locale}.json`);\n\t\twriteFileSync(filePath, JSON.stringify(strings, null, 2) + \"\\n\", \"utf-8\");\n\t\tp.log.success(`Wrote ${highlight(filePath)}`);\n\t}\n}\n","import * as p from \"@clack/prompts\";\nimport chalk from \"chalk\";\nimport { active, highlight } from \"../utils/theme.js\";\nimport { config as loadEnv } from \"dotenv\";\nimport { VocoderAPI, VocoderAPIError } from \"../utils/api.js\";\nimport { readAuthData } from \"../utils/auth-store.js\";\nimport { resolveGitRepositoryIdentity } from \"../utils/git-identity.js\";\nimport { getLimitErrorGuidance } from \"./sync.js\";\n\nloadEnv();\n\nexport interface CreateAppOptions {\n\t/** Project display name (required). */\n\tname: string;\n\t/** BCP 47 source locale code, e.g. \"en\" (required). */\n\tsourceLocale: string;\n\t/** Comma-separated target locale codes, e.g. \"fr,de,pt-BR\". */\n\ttargetLocales?: string;\n\t/** Comma-separated branch names to enable sync on. Defaults to \"main\". */\n\ttargetBranches?: string;\n\t/** Organization ID to create the project in (required). */\n\torganization: string;\n\t/**\n\t * Explicit git repository canonical, e.g. \"github:owner/repo\".\n\t * Auto-detected from git remote if omitted.\n\t */\n\trepo?: string;\n\t/**\n\t * App directory within the repository for monorepos, e.g. \"apps/web\".\n\t * Defaults to \".\" (repo root).\n\t */\n\tappDir?: string;\n\tapiUrl?: string;\n}\n\n/**\n * Creates a new Vocoder project without the interactive init flow.\n *\n * Requires a valid user token in the local auth store (run `vocoder init` first).\n * Prints the generated VOCODER_API_KEY to stdout on success.\n *\n * Git identity is auto-detected from the git remote. The detected repository\n * must be accessible via the workspace's GitHub App installation for\n * push-based sync to function. Use --repo to override auto-detection, or\n * omit repo binding entirely if not in a git repository.\n *\n * Endpoint: POST /api/cli/apps\n *\n * @param options.name Project display name (required).\n * @param options.sourceLocale Source language BCP 47 code (required).\n * @param options.targetLocales Comma-separated target locale codes.\n * @param options.targetBranches Comma-separated branch names (default: \"main\").\n * @param options.organization Organization ID (required).\n * @param options.repo Git repo canonical override.\n * @param options.appDir App directory for monorepos (default: \".\").\n *\n * @throws If user token is missing, organization is invalid, or the plan's\n * maxProjects limit is exceeded.\n */\nexport async function createApp(options: CreateAppOptions): Promise<number> {\n\tconst authData = readAuthData();\n\tif (!authData) {\n\t\tp.log.error(\n\t\t\t\"Not logged in. Run `npx @vocoder/cli init` to authenticate first.\",\n\t\t);\n\t\treturn 1;\n\t}\n\n\tconst apiUrl = options.apiUrl ?? process.env.VOCODER_API_URL ?? \"https://vocoder.app\";\n\tconst api = new VocoderAPI({ apiKey: \"\", apiUrl });\n\n\t// Resolve repo identity — auto-detect if not overridden\n\tlet repoCanonical: string | undefined;\n\tlet appDir = options.appDir ?? \".\";\n\n\tif (options.repo) {\n\t\trepoCanonical = options.repo;\n\t} else {\n\t\tconst identity = resolveGitRepositoryIdentity();\n\t\tif (identity) {\n\t\t\trepoCanonical = identity.repoCanonical;\n\t\t\t// Only override appDir from git if the caller didn't specify one\n\t\t\tif (!options.appDir && identity.repoAppDir) {\n\t\t\t\tappDir = identity.repoAppDir;\n\t\t\t}\n\t\t} else {\n\t\t\tp.log.warn(\n\t\t\t\t\"Could not detect a git remote. The project will be created without repo binding — \" +\n\t\t\t\t\t\"sync-on-push will not function until a repository is connected via the Vocoder dashboard.\",\n\t\t\t);\n\t\t}\n\t}\n\n\tconst targetLocales = options.targetLocales\n\t\t? options.targetLocales.split(\",\").map((l) => l.trim()).filter(Boolean)\n\t\t: [];\n\n\tconst targetBranches = options.targetBranches\n\t\t? options.targetBranches.split(\",\").map((b) => b.trim()).filter(Boolean)\n\t\t: [\"main\"];\n\n\tconst spinner = p.spinner();\n\tspinner.start(`Creating app \"${options.name}\"…`);\n\n\ttry {\n\t\tconst result = await api.createProject(authData.token, {\n\t\t\torganizationId: options.organization,\n\t\t\tname: options.name,\n\t\t\tsourceLocale: options.sourceLocale,\n\t\t\ttargetLocales,\n\t\t\ttargetBranches,\n\t\t\tappDirs: [appDir],\n\t\t\t...(repoCanonical ? { repoCanonical } : {}),\n\t\t});\n\n\t\tspinner.stop(`Created app ${chalk.bold(result.projectName)}`);\n\n\t\tconst lines = [\n\t\t\t`Project ID: ${result.projectId}`,\n\t\t\t`Source locale: ${highlight(result.sourceLocale)}`,\n\t\t\t`Target locales: ${result.targetLocales.length > 0 ? result.targetLocales.map((l) => highlight(l)).join(\", \") : chalk.dim(\"(none)\")}`,\n\t\t\t`Branches: ${result.targetBranches.map((b) => highlight(b)).join(\", \")}`,\n\t\t\t...(repoCanonical\n\t\t\t\t? [`Repository: ${highlight(repoCanonical)}${appDir !== \".\" ? ` (${appDir})` : \"\"}`]\n\t\t\t\t: []),\n\t\t\t\"\",\n\t\t\t`Add this to your .env file:`,\n\t\t\t` ${chalk.bold(\"VOCODER_API_KEY\")}=${highlight(result.apiKey)}`,\n\t\t];\n\n\t\tp.note(lines.join(\"\\n\"), \"Project created\");\n\n\t\tif (!result.repositoryBound && repoCanonical) {\n\t\t\tp.log.warn(\n\t\t\t\t`Repository \"${repoCanonical}\" was not automatically connected. ` +\n\t\t\t\t\t\"Ensure your GitHub App installation covers this repository.\",\n\t\t\t);\n\t\t}\n\n\t\treturn 0;\n\t} catch (error) {\n\t\tspinner.stop(\"Failed to create project.\");\n\n\t\tif (error instanceof VocoderAPIError && error.limitError) {\n\t\t\tconst { limitError } = error;\n\t\t\tp.log.error(limitError.message);\n\t\t\tfor (const line of getLimitErrorGuidance(limitError)) {\n\t\t\t\tp.log.info(line);\n\t\t\t}\n\t\t\treturn 1;\n\t\t}\n\n\t\tp.log.error(\n\t\t\terror instanceof Error ? error.message : \"Unknown error.\",\n\t\t);\n\t\treturn 1;\n\t}\n}\n","import * as p from \"@clack/prompts\";\nimport chalk from \"chalk\";\nimport { VocoderAPI } from \"../utils/api.js\";\nimport { readAuthData } from \"../utils/auth-store.js\";\n\nexport interface WhoamiOptions {\n\tapiUrl?: string;\n}\n\nexport async function whoami(options: WhoamiOptions = {}): Promise<number> {\n\tconst stored = readAuthData();\n\n\tif (!stored) {\n\t\tp.log.info(\"Not logged in. Run `vocoder init` to authenticate.\");\n\t\treturn 1;\n\t}\n\n\tconst apiUrl = options.apiUrl ?? stored.apiUrl ?? \"https://vocoder.app\";\n\tconst api = new VocoderAPI({ apiUrl, apiKey: \"\" });\n\n\ttry {\n\t\tconst info = await api.getCliUserInfo(stored.token);\n\t\tp.log.info(`Logged in as ${chalk.bold(info.email)}`);\n\t\tif (info.name) {\n\t\t\tp.log.info(`Name: ${info.name}`);\n\t\t}\n\t\tp.log.info(`API: ${apiUrl}`);\n\t\treturn 0;\n\t} catch {\n\t\tp.log.error(\n\t\t\t\"Stored credentials are invalid or expired. Run `vocoder init` to re-authenticate.\",\n\t\t);\n\t\treturn 1;\n\t}\n}\n"],"mappings":"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","names":["p","execSync","spawn","existsSync","writeFileSync","p","join","resolve","p","chalk","existsSync","existsSync","isCancel","Prompt","S_BAR","S_BAR_END","S_ACTIVE","S_SUBMIT","S_CANCEL","S_ERROR","symbol","S_BAR","Prompt","symbol","S_BAR_END","isCancel","isCancel","Prompt","p","S_BAR","S_BAR_END","S_ACTIVE","S_SUBMIT","S_CANCEL","S_ERROR","symbol","MAX_VISIBLE","buildList","Prompt","isCancel","chalk","p","chalk","URL","resolve","resolve","chalk","chalk","execSync","p","chalk","resolve","tryOpenBrowser","spawn","chalk","execSync","join","existsSync","writeFileSync","anonApi","spinner","detection","p","chalk","loadEnv","readFileSync","existsSync","readFileSync","writeFileSync","join","p","chalk","execSync","p","loadEnv","loadEnv","p","join","existsSync","readFileSync","writeFileSync","lines","chalk","spinner","duration","loadEnv","readFileSync","spinner","chalk","p","p","chalk","loadEnv","loadEnv","chalk","mkdirSync","writeFileSync","join","p","loadEnv","loadEnv","spinner","mkdirSync","join","writeFileSync","p","chalk","loadEnv","loadEnv","spinner","chalk","p","chalk","info","chalk"]}
|
|
1
|
+
{"version":3,"sources":["../src/bin.ts","../src/commands/init.ts","../src/utils/auth-flow.ts","../src/utils/browser.ts","../src/utils/local-server.ts","../src/utils/output.ts","../src/utils/scaffold.ts","../src/utils/theme.ts","../src/utils/write-config.ts","../src/utils/mcp-setup.ts","../src/utils/plan-check.ts","../src/utils/organization-select.ts","../src/utils/github-connect.ts","../src/utils/organization.ts","../src/utils/project-create.ts","../src/utils/app-dir-select.ts","../src/utils/branch-select.ts","../src/utils/locale-search.ts","../src/utils/git-identity.ts","../src/commands/locales.ts","../src/commands/sync.ts","../src/utils/branch.ts","../src/utils/config.ts","../src/commands/logout.ts","../src/commands/app-config.ts","../src/commands/translations.ts","../src/commands/create-app.ts","../src/commands/whoami.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { Command } from \"commander\";\nimport { init } from \"./commands/init.js\";\nimport {\n\taddLocales,\n\tlistProjectLocales,\n\tlistSupportedLocales,\n\tremoveLocales,\n} from \"./commands/locales.js\";\nimport { logout } from \"./commands/logout.js\";\nimport { appConfig } from \"./commands/app-config.js\";\nimport { sync } from \"./commands/sync.js\";\nimport { getTranslations } from \"./commands/translations.js\";\nimport { createApp } from \"./commands/create-app.js\";\nimport { whoami } from \"./commands/whoami.js\";\n\n/**\n * Collector function for repeated CLI options\n * Allows multiple --include or --exclude flags\n */\nfunction collect(value: string, previous: string[] = []): string[] {\n\treturn previous.concat([value]);\n}\n\nasync function runCommand(\n\tcommand: (options: any) => Promise<number>,\n\toptions: any,\n): Promise<void> {\n\tconst exitCode = await command(options);\n\t// Force exit so open stdin handles from readline/clack don't stall the process.\n\tprocess.exit(exitCode);\n}\n\nconst program = new Command();\n\nprogram\n\t.name(\"vocoder\")\n\t.description(\"Vocoder CLI - Project setup and string extraction\")\n\t.version(\"0.1.5\");\n\nprogram\n\t.command(\"init\")\n\t.description(\"Authenticate and provision Vocoder for this project\")\n\t.option(\"--api-url <url>\", \"Override Vocoder API URL\")\n\t.option(\"--yes\", \"Allow overwriting existing local config values\")\n\t.option(\n\t\t\"--ci\",\n\t\t\"Non-interactive mode: print auth URL to stdout, skip browser open\",\n\t)\n\t.option(\"--app-name <name>\", \"Starter app name to create\")\n\t.option(\"--source-locale <locale>\", \"Source locale for the starter project\")\n\t.option(\n\t\t\"--target-locales <list>\",\n\t\t\"Comma-separated target locales (e.g. es,fr,de)\",\n\t)\n\t.action((options) => runCommand(init, options));\n\nprogram\n\t.command(\"sync\")\n\t.description(\"Extract strings and sync translations\")\n\t.option(\"--branch <branch>\", \"Override detected branch\")\n\t.option(\"--mode <mode>\", \"Sync mode: auto, required, best-effort\", \"auto\")\n\t.option(\"--max-wait <ms>\", \"Max wait for translations (ms)\")\n\t.option(\"--force\", \"Force re-extraction even if no changes\")\n\t.option(\"--dry-run\", \"Preview without syncing\")\n\t.option(\"--no-fallback\", \"Disable fallback to cached translations\")\n\t.option(\"--include <pattern>\", \"Include glob pattern\", collect, [])\n\t.option(\"--exclude <pattern>\", \"Exclude glob pattern\", collect, [])\n\t.option(\"--verbose\", \"Detailed output\")\n\t.action((options) => {\n\t\tconst translated: Record<string, unknown> = { ...options };\n\t\tif (options.maxWait) translated.maxWaitMs = Number(options.maxWait);\n\t\tif (options.fallback === false) translated.noFallback = true;\n\t\treturn runCommand(sync, translated);\n\t});\n\nprogram\n\t.command(\"logout\")\n\t.description(\"Log out and remove stored credentials\")\n\t.option(\"--api-url <url>\", \"Override Vocoder API URL\")\n\t.action((options) => runCommand(logout, options));\n\nprogram\n\t.command(\"whoami\")\n\t.description(\"Show the currently authenticated user\")\n\t.option(\"--api-url <url>\", \"Override Vocoder API URL\")\n\t.action((options) => runCommand(whoami, options));\n\n// ── Project management ────────────────────────────────────────────────────────\n\nconst localesCmd = program\n\t.command(\"locales\")\n\t.description(\"Manage project target locales\")\n\t.option(\"--api-url <url>\", \"Override Vocoder API URL\")\n\t.action((options) => runCommand(listProjectLocales, options));\n\nlocalesCmd\n\t.command(\"add <codes...>\")\n\t.description(\"Add one or more target locales by BCP 47 code (e.g. fr de pt-BR)\")\n\t.option(\"--api-url <url>\", \"Override Vocoder API URL\")\n\t.action((codes: string[], options) =>\n\t\trunCommand((opts) => addLocales(codes, opts), options),\n\t);\n\nlocalesCmd\n\t.command(\"remove <codes...>\")\n\t.description(\"Remove one or more target locales by BCP 47 code\")\n\t.option(\"--api-url <url>\", \"Override Vocoder API URL\")\n\t.action((codes: string[], options) =>\n\t\trunCommand((opts) => removeLocales(codes, opts), options),\n\t);\n\nlocalesCmd\n\t.command(\"supported\")\n\t.description(\"List all locales supported by Vocoder\")\n\t.option(\"--api-url <url>\", \"Override Vocoder API URL\")\n\t.action((options) => runCommand(listSupportedLocales, options));\n\nprogram\n\t.command(\"project\")\n\t.description(\"Show current app configuration\")\n\t.option(\"--api-url <url>\", \"Override Vocoder API URL\")\n\t.action((options) => runCommand(appConfig, options));\n\nprogram\n\t.command(\"translations\")\n\t.description(\"Download the current translation snapshot\")\n\t.option(\"--branch <branch>\", \"Git branch (auto-detected if omitted)\")\n\t.option(\"--locale <locale>\", \"Fetch a specific locale only\")\n\t.option(\"--output <dir>\", \"Write locale JSON files to this directory\")\n\t.option(\"--api-url <url>\", \"Override Vocoder API URL\")\n\t.action((options) => runCommand(getTranslations, options));\n\nprogram\n\t.command(\"create-app\")\n\t.description(\"Create a new Vocoder app (requires prior `vocoder init`)\")\n\t.requiredOption(\"--name <name>\", \"App display name\")\n\t.requiredOption(\"--source-locale <code>\", \"Source language BCP 47 code (e.g. en)\")\n\t.requiredOption(\"--organization <org-id>\", \"Organization ID\")\n\t.option(\n\t\t\"--target-locales <codes>\",\n\t\t\"Comma-separated target locale codes (e.g. fr,de,pt-BR)\",\n\t)\n\t.option(\n\t\t\"--target-branches <branches>\",\n\t\t\"Comma-separated branch names to sync (default: main)\",\n\t)\n\t.option(\n\t\t\"--repo <canonical>\",\n\t\t\"Git repo canonical (e.g. github:owner/repo). Auto-detected from git remote if omitted.\",\n\t)\n\t.option(\n\t\t\"--app-dir <path>\",\n\t\t\"App directory within the repo for monorepos (default: .)\",\n\t)\n\t.option(\"--api-url <url>\", \"Override Vocoder API URL\")\n\t.action((options) => {\n\t\tconst translated = {\n\t\t\t...options,\n\t\t\t// Commander camelCases dashed options\n\t\t\tsourceLocale: options.sourceLocale,\n\t\t\ttargetLocales: options.targetLocales,\n\t\t\ttargetBranches: options.targetBranches,\n\t\t\torganization: options.organization,\n\t\t};\n\t\treturn runCommand(createApp, translated);\n\t});\n\nprogram.parse(process.argv);\n","import * as p from \"@clack/prompts\";\n\nimport { VocoderAPI } from \"../utils/api.js\";\nimport {\n\tverifyStoredAuth,\n\twriteAuthData,\n} from \"../utils/auth-store.js\";\nimport { runAuthFlow } from \"../utils/auth-flow.js\";\nimport { detectLocalEcosystem } from \"../utils/detect-local.js\";\nimport { printApiKey } from \"../utils/output.js\";\nimport { runScaffold, writeAppConfigs } from \"../utils/scaffold.js\";\nimport { runMcpSetup } from \"../utils/mcp-setup.js\";\nimport { checkPlanLimits, isPlanLimitFailure, printPlanLimitMessage } from \"../utils/plan-check.js\";\nimport { selectOrganizationForInit } from \"../utils/organization-select.js\";\nimport { runAppCreate, runProjectCreate } from \"../utils/project-create.js\";\n\nimport type { InitOptions } from \"../types.js\";\nimport chalk from \"chalk\";\n\nimport { config as loadEnv } from \"dotenv\";\nimport { resolveGitContext } from \"../utils/git-identity.js\";\nimport { highlight } from \"../utils/theme.js\";\n\nloadEnv();\n\n// ── Main command ──────────────────────────────────────────────────────────────\n\nexport async function init(options: InitOptions = {}): Promise<number> {\n\tconst apiUrl =\n\t\toptions.apiUrl || process.env.VOCODER_API_URL || \"https://vocoder.app\";\n\n\tp.intro(chalk.bold(\"Vocoder Setup\"));\n\n\ttry {\n\t\t// ── 1. Detect git context ───────────────────────────────────────────────\n\t\tconst gitContext = resolveGitContext();\n\t\tconst identity = gitContext.identity;\n\n\t\tfor (const warning of gitContext.warnings) {\n\t\t\tp.log.warn(warning);\n\t\t}\n\n\t\t// ── 2. Fast lookup: does a project already exist for this repo? ─────────\n\t\t// No spinner — fast DB read, and we don't want a stray ◇ on a miss.\n\t\tlet existingAppsForRepo: Array<{\n\t\t\tappDir: string;\n\t\t\tappId: string;\n\t\t\tprojectId: string;\n\t\t\tprojectName: string;\n\t\t\torganizationName: string;\n\t\t}> = [];\n\t\tlet repoProjectId: string | null = null;\n\t\tlet repoProjectName: string | null = null;\n\t\tlet lookup: Awaited<ReturnType<VocoderAPI[\"lookupAppByRepo\"]>> | null = null;\n\n\t\tif (identity) {\n\t\t\tconst anonApi = new VocoderAPI({ apiUrl, apiKey: \"\" });\n\t\t\tlookup = await anonApi.lookupAppByRepo({\n\t\t\t\trepoCanonical: identity.repoCanonical,\n\t\t\t\tappDir: \"\",\n\t\t\t});\n\n\t\t\tif (lookup.existingApps.length > 0) {\n\t\t\t\tconst allApps = lookup.existingApps;\n\t\t\t\tconst firstApp = allApps[0]!;\n\n\t\t\t\tp.log.success(`Project: ${chalk.bold(firstApp.projectName)}`);\n\t\t\t\tp.log.info(\n\t\t\t\t\t`Configured apps: ${allApps.map((a) => highlight(a.appDir || \"(entire repo)\")).join(\", \")}`,\n\t\t\t\t);\n\n\t\t\t\tconst routeAction = await p.select<string>({\n\t\t\t\t\tmessage: \"This repo is already set up. What would you like to do?\",\n\t\t\t\t\toptions: [\n\t\t\t\t\t\t{ value: \"key\", label: \"Get an API key for this project\" },\n\t\t\t\t\t\t{ value: \"add\", label: \"Add a new app directory\" },\n\t\t\t\t\t],\n\t\t\t\t});\n\n\t\t\t\tif (p.isCancel(routeAction)) {\n\t\t\t\t\tp.cancel(\"Setup cancelled.\");\n\t\t\t\t\treturn 1;\n\t\t\t\t}\n\n\t\t\t\tif (routeAction === \"key\") {\n\t\t\t\t\tconst anonApi2 = new VocoderAPI({ apiUrl, apiKey: \"\" });\n\t\t\t\t\tconst authResult = await runAuthFlow(anonApi2, options, /* reauth */ true);\n\t\t\t\t\tif (!authResult) return 1;\n\n\t\t\t\t\tconst spinner = p.spinner();\n\t\t\t\t\tspinner.start(\"Generating API key...\");\n\t\t\t\t\tlet apiKey: string;\n\t\t\t\t\ttry {\n\t\t\t\t\t\t({ apiKey } = await anonApi2.regenerateProjectApiKey(\n\t\t\t\t\t\t\tauthResult.token,\n\t\t\t\t\t\t\tfirstApp.projectId,\n\t\t\t\t\t\t));\n\t\t\t\t\t\tspinner.stop(\"API key ready\");\n\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\tspinner.stop(\"Failed to generate key\");\n\t\t\t\t\t\tconst msg = err instanceof Error ? err.message : String(err);\n\t\t\t\t\t\tp.log.error(`Could not generate API key: ${msg}`);\n\t\t\t\t\t\tp.log.info(\"Try again or generate one from the dashboard.\");\n\t\t\t\t\t\treturn 1;\n\t\t\t\t\t}\n\n\t\t\t\t\tprintApiKey(apiKey, identity.repoRoot);\n\n\t\t\t\t\tconst detection = detectLocalEcosystem();\n\t\t\t\t\tconst targetBranches = lookup.exactMatch?.targetBranches ?? [\"main\"];\n\t\t\t\t\twriteAppConfigs(\n\t\t\t\t\t\tallApps.map((a) => ({ appDir: a.appDir, appId: a.appId })),\n\t\t\t\t\t\ttargetBranches,\n\t\t\t\t\t\tdetection.isTypeScript,\n\t\t\t\t\t\tidentity.repoRoot,\n\t\t\t\t\t);\n\n\t\t\t\t\tp.outro(\"Vocoder is set up for this repository.\");\n\t\t\t\t\treturn 0;\n\t\t\t\t}\n\n\t\t\t\t// \"add\" path — fall through to runAppCreate block below\n\t\t\t\texistingAppsForRepo = allApps;\n\t\t\t\trepoProjectId = firstApp.projectId;\n\t\t\t\trepoProjectName = firstApp.projectName;\n\t\t\t}\n\t\t}\n\n\t\t// ── 3. Auth: check stored token, prompt if missing ──────────────────────\n\t\tconst api = new VocoderAPI({ apiUrl, apiKey: \"\" });\n\t\tlet userToken: string;\n\t\tlet userEmail: string;\n\t\tlet userName: string | null;\n\t\tlet authOrganizationId: string | undefined;\n\n\t\tconst storedAuth = await verifyStoredAuth(api);\n\n\t\tif (storedAuth.status === \"valid\") {\n\t\t\tp.log.success(`Authenticated as ${chalk.bold(storedAuth.email)}`);\n\t\t\tuserToken = storedAuth.token;\n\t\t\tuserEmail = storedAuth.email;\n\t\t\tuserName = storedAuth.name;\n\t\t} else {\n\t\t\t// \"gone\" = user deleted → full first-time flow (installUrl)\n\t\t\t// \"expired\" = token rejected → reauth via verificationUrl (no new org)\n\t\t\t// \"none\" = no stored token → full first-time flow (installUrl)\n\t\t\tconst reauth = storedAuth.status === \"expired\";\n\t\t\tif (reauth) {\n\t\t\t\tp.log.warn(\"Stored credentials expired — signing in again\");\n\t\t\t} else if (storedAuth.status === \"gone\") {\n\t\t\t\tp.log.warn(\"Account not found — starting fresh setup\");\n\t\t\t}\n\t\t\tconst authResult = await runAuthFlow(\n\t\t\t\tapi,\n\t\t\t\toptions,\n\t\t\t\treauth,\n\t\t\t\tidentity?.repoCanonical,\n\t\t\t);\n\t\t\tif (!authResult) return 1;\n\t\t\tuserToken = authResult.token;\n\t\t\tuserEmail = authResult.email;\n\t\t\tuserName = authResult.name;\n\t\t\tauthOrganizationId = authResult.organizationId;\n\n\t\t\twriteAuthData({\n\t\t\t\ttoken: userToken,\n\t\t\t\tuserId: authResult.userId,\n\t\t\t\temail: userEmail,\n\t\t\t\tname: userName,\n\t\t\t\tcreatedAt: new Date().toISOString(),\n\t\t\t});\n\t\t}\n\n\t\t// ── 4. Organization selection ────────────────────────────────────────────\n\t\tconst organizationResult = await selectOrganizationForInit({\n\t\t\tapi,\n\t\t\tuserToken,\n\t\t\tuserEmail,\n\t\t\tidentity: identity ?? null,\n\t\t\tlookup,\n\t\t\trepoProjectId,\n\t\t\tauthOrganizationId,\n\t\t\toptions,\n\t\t});\n\n\t\tif (!organizationResult) return 1;\n\n\t\tconst { organizationId: selectedOrganizationId, organizationName: selectedOrganizationName } =\n\t\t\torganizationResult;\n\n\t\t// ── 5. Add-app path: repo already has a project with scoped apps ─────────\n\t\t// Skips plan limit check — only a new App is added, not a new Project.\n\t\tif (repoProjectId && repoProjectName && existingAppsForRepo.length > 0) {\n\t\t\tconst appResult = await runAppCreate({\n\t\t\t\tapi,\n\t\t\t\tuserToken,\n\t\t\t\tprojectId: repoProjectId,\n\t\t\t\tprojectName: repoProjectName,\n\t\t\t\torganizationName: selectedOrganizationName,\n\t\t\t\trepoCanonical: identity?.repoCanonical,\n\t\t\t\texistingApps: existingAppsForRepo,\n\t\t\t});\n\n\t\t\tif (!appResult) {\n\t\t\t\tp.log.error(\"App setup failed. Run `vocoder init` again.\");\n\t\t\t\treturn 1;\n\t\t\t}\n\n\t\t\tconst detection = detectLocalEcosystem();\n\t\t\trunScaffold({ targetBranches: appResult.targetBranches });\n\t\t\twriteAppConfigs(\n\t\t\t\t[{ appDir: appResult.appDir, appId: appResult.appId }],\n\t\t\t\tappResult.targetBranches,\n\t\t\t\tdetection.isTypeScript,\n\t\t\t\tidentity?.repoRoot,\n\t\t\t);\n\t\t\tp.log.info(chalk.dim(\"Use the VOCODER_API_KEY already in your root .env\"));\n\t\t\tp.outro(\"You're all set.\");\n\t\t\treturn 0;\n\t\t}\n\n\t\t// ── 6. Plan limit pre-flight ─────────────────────────────────────────────\n\t\t// Compute remaining app slots to cap the app-directory TUI.\n\t\tconst planCheck = await checkPlanLimits(\n\t\t\tapi,\n\t\t\tuserToken,\n\t\t\tselectedOrganizationId,\n\t\t\tapiUrl,\n\t\t);\n\t\tif (planCheck.atLimit) return 1;\n\n\t\t// ── 7. Project configuration ─────────────────────────────────────────────\n\t\tconst projectResult = await runProjectCreate({\n\t\t\tapi,\n\t\t\tuserToken,\n\t\t\torganizationId: selectedOrganizationId,\n\t\t\tdefaultName: identity?.repoCanonical\n\t\t\t\t? identity.repoCanonical.split(\"/\").pop()\n\t\t\t\t: undefined,\n\t\t\tdefaultSourceLocale: \"en\",\n\t\t\trepoCanonical: identity?.repoCanonical,\n\t\t\trepoRoot: identity?.repoRoot,\n\t\t\tdefaultBranches: [\"main\"],\n\t\t\tmaxAppDirs: planCheck.remaining,\n\t\t});\n\n\t\t// null means user cancelled a prompt — individual steps already logged\n\t\tif (!projectResult) return 1;\n\n\t\tif (!projectResult.repositoryBound && identity?.repoCanonical) {\n\t\t\tp.log.warn(\n\t\t\t\t`This repository isn't accessible to your GitHub App installation.\\n` +\n\t\t\t\t\t`Translations won't run automatically until you grant access.\\n\\n` +\n\t\t\t\t\t` To fix: go to your GitHub App installation settings and add this\\n` +\n\t\t\t\t\t` repository to the allowed list, or switch to \"All repositories\".\\n` +\n\t\t\t\t\t(projectResult.configureUrl\n\t\t\t\t\t\t? `\\n ${chalk.dim(projectResult.configureUrl)}\\n`\n\t\t\t\t\t\t: \"\"),\n\t\t\t);\n\t\t}\n\n\t\t// ── 8. Scaffold + config write ───────────────────────────────────────────\n\t\tconst detection = detectLocalEcosystem();\n\t\trunScaffold({ targetBranches: projectResult.targetBranches });\n\t\twriteAppConfigs(\n\t\t\tprojectResult.apps,\n\t\t\tprojectResult.targetBranches,\n\t\t\tdetection.isTypeScript,\n\t\t\tidentity?.repoRoot,\n\t\t);\n\t\tprintApiKey(projectResult.apiKey, identity?.repoRoot);\n\n\t\t// ── 9. MCP setup ─────────────────────────────────────────────────────────\n\t\tconst wantsMcp = await p.confirm({\n\t\t\tmessage: \"Set up the Vocoder MCP server for your AI editor?\",\n\t\t});\n\t\tif (!p.isCancel(wantsMcp) && wantsMcp) {\n\t\t\tawait runMcpSetup(projectResult.apiKey);\n\t\t}\n\n\t\tp.outro(\"You're all set.\");\n\t\treturn 0;\n\t} catch (error) {\n\t\tconst message = error instanceof Error ? error.message : \"Unknown setup error\";\n\t\tif (isPlanLimitFailure(message)) {\n\t\t\tprintPlanLimitMessage(apiUrl, message);\n\t\t} else {\n\t\t\tp.log.error(message);\n\t\t}\n\t\treturn 1;\n\t}\n}\n","/**\n * @module auth-flow\n *\n * Browser-based authentication flow for `vocoder init`.\n * Scenarios:\n * - First-time setup: shows install vs link choice, opens installUrl.\n * - Re-auth (expired token): skips install choice, uses verificationUrl.\n * - CI mode: emits machine-readable VOCODER_AUTH_URL / VOCODER_SESSION_ID lines.\n * - No TTY / CI env: skips browser prompt, falls back to polling only.\n *\n * Three-way race: local callback server (instant) vs session poll (2 s intervals)\n * vs hard deadline (min of session expiry, 10 min). First to resolve wins.\n *\n * Exports: runAuthFlow, sleep\n */\n\nimport * as p from \"@clack/prompts\";\nimport chalk from \"chalk\";\nimport type { VocoderAPI } from \"./api.js\";\nimport { tryOpenBrowser } from \"./browser.js\";\nimport { startCallbackServer } from \"./local-server.js\";\nimport type { InitOptions } from \"../types.js\";\n\nexport async function sleep(ms: number): Promise<void> {\n\tawait new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nexport interface AuthFlowResult {\n\ttoken: string;\n\tuserId: string;\n\temail: string;\n\tname: string | null;\n\t/** Set when auth + GitHub App install completed in one browser trip. */\n\torganizationId?: string;\n\t/** True when the browser session completed a GitHub OAuth discovery step. */\n\tdiscoveryReady?: boolean;\n}\n\n/**\n * Runs the full browser authentication flow and returns user credentials.\n * Returns null if the user cancelled or the session expired.\n *\n * @param reauth - When true (expired token), uses verificationUrl instead of\n * installUrl to avoid creating a duplicate workspace.\n */\nexport async function runAuthFlow(\n\tapi: VocoderAPI,\n\toptions: InitOptions,\n\treauth = false,\n\trepoCanonical?: string,\n): Promise<AuthFlowResult | null> {\n\t// In CI mode, skip the callback server — the browser step is external and\n\t// polling is simpler and more testable than a local HTTP server.\n\tlet server: Awaited<ReturnType<typeof startCallbackServer>> | null = null;\n\tif (!options.ci) {\n\t\ttry {\n\t\t\tserver = await startCallbackServer();\n\t\t} catch {\n\t\t\t// Port conflict or other issue — fall back to polling\n\t\t}\n\t}\n\n\tconst session = await api.startCliAuthSession(server?.port, repoCanonical);\n\tconst browserUrl = reauth\n\t\t? session.verificationUrl\n\t\t: (session.installUrl ?? session.verificationUrl);\n\tconst expiresAt = new Date(session.expiresAt).getTime();\n\tp.log.info(browserUrl);\n\n\tif (options.ci) {\n\t\t// Machine-readable output parsed by e2e/helpers/cli.ts\n\t\tprocess.stdout.write(`VOCODER_AUTH_URL: ${browserUrl}\\n`);\n\t\tprocess.stdout.write(`VOCODER_SESSION_ID: ${session.sessionId}\\n`);\n\t} else if (\n\t\tprocess.stdin.isTTY &&\n\t\tprocess.stdout.isTTY &&\n\t\tprocess.env.CI !== \"true\"\n\t) {\n\t\tif (reauth) {\n\t\t\tif (!options.yes) {\n\t\t\t\tconst shouldOpen = await p.confirm({\n\t\t\t\t\tmessage: \"Open your browser to sign in again?\",\n\t\t\t\t});\n\t\t\t\tif (p.isCancel(shouldOpen)) {\n\t\t\t\t\tserver?.close();\n\t\t\t\t\tp.cancel(\"Setup cancelled.\");\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t\tif (!shouldOpen) {\n\t\t\t\t\tserver?.close();\n\t\t\t\t\tp.cancel(\"Setup cancelled.\");\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t\tconst opened = await tryOpenBrowser(browserUrl);\n\t\t\t\tif (!opened) {\n\t\t\t\t\tp.note(browserUrl, \"Sign In\");\n\t\t\t\t\tp.log.info(\"Open the URL above manually to continue.\");\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tawait tryOpenBrowser(browserUrl);\n\t\t\t}\n\t\t} else {\n\t\t\t// First-time setup: let user choose install vs link existing\n\t\t\tlet isLinkFlow = false;\n\t\t\tif (!options.yes) {\n\t\t\t\tconst connectChoice = await p.select<string>({\n\t\t\t\t\tmessage:\n\t\t\t\t\t\t\"Vocoder needs to be installed on your GitHub account to get started\",\n\t\t\t\t\toptions: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tvalue: \"install\",\n\t\t\t\t\t\t\tlabel: \"Install GitHub App\",\n\t\t\t\t\t\t\thint: \"new user\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tvalue: \"link\",\n\t\t\t\t\t\t\tlabel: \"Already installed? Link your account\",\n\t\t\t\t\t\t\thint: \"returning user\",\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t});\n\n\t\t\t\tif (p.isCancel(connectChoice)) {\n\t\t\t\t\tserver?.close();\n\t\t\t\t\tp.cancel(\"Setup cancelled.\");\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\n\t\t\t\tisLinkFlow = connectChoice === \"link\";\n\t\t\t}\n\n\t\t\tlet urlToOpen = browserUrl;\n\t\t\tif (isLinkFlow) {\n\t\t\t\ttry {\n\t\t\t\t\tconst linkSession = await api.startCliGitHubLinkSession(\n\t\t\t\t\t\tsession.sessionId,\n\t\t\t\t\t\tserver?.port,\n\t\t\t\t\t);\n\t\t\t\t\turlToOpen = linkSession.oauthUrl;\n\t\t\t\t} catch {\n\t\t\t\t\t// Fall back to install URL if link-start fails\n\t\t\t\t\turlToOpen = browserUrl;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst opened = await tryOpenBrowser(urlToOpen);\n\t\t\tif (!opened) {\n\t\t\t\tp.log.warn(\"Could not open your browser automatically.\");\n\t\t\t\tp.note(urlToOpen, \"GitHub\");\n\t\t\t\tp.log.info(\"Open the URL above to continue.\");\n\t\t\t}\n\t\t}\n\t}\n\n\tconst authSpinner = p.spinner();\n\tauthSpinner.start(\"Waiting for GitHub authorization...\");\n\n\tlet rawToken: string | null = null;\n\tlet callbackOrganizationId: string | undefined;\n\tlet callbackDiscoveryReady = false;\n\n\tconst deadline = Math.min(expiresAt, Date.now() + 10 * 60 * 1000);\n\tlet stopPolling = false;\n\n\tconst serverCallback: Promise<Record<string, string> | null> = server\n\t\t? server.waitForCallback().catch(() => null)\n\t\t: Promise.resolve(null);\n\n\t// Polling runs concurrently with the server wait so a missed local-server\n\t// callback (browser blocked fetch, mixed-content, port conflict) doesn't\n\t// stall until the server timeout.\n\tconst sessionPoll = (async () => {\n\t\twhile (!stopPolling && Date.now() < expiresAt) {\n\t\t\ttry {\n\t\t\t\tconst result = await api.pollCliAuthSession(session.sessionId);\n\t\t\t\tif (result.status === \"complete\" || result.status === \"failed\") {\n\t\t\t\t\treturn result;\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\t// Transient network error — keep trying\n\t\t\t}\n\t\t\tif (!stopPolling) await sleep(2000);\n\t\t}\n\t\treturn null;\n\t})();\n\n\tconst winner = await new Promise<\n\t\t| { kind: \"server\"; params: Record<string, string> }\n\t\t| {\n\t\t\t\tkind: \"poll\";\n\t\t\t\tresult:\n\t\t\t\t\t| { status: \"complete\"; token: string; organizationId?: string }\n\t\t\t\t\t| { status: \"failed\"; reason: string };\n\t\t }\n\t\t| null\n\t>((resolve) => {\n\t\tlet done = false;\n\n\t\tserverCallback\n\t\t\t.then((params) => {\n\t\t\t\tif (done || params === null || typeof params.token !== \"string\") return;\n\t\t\t\tdone = true;\n\t\t\t\tresolve({ kind: \"server\", params });\n\t\t\t})\n\t\t\t.catch(() => {});\n\n\t\tsessionPoll\n\t\t\t.then((result) => {\n\t\t\t\tif (done || result === null) return;\n\t\t\t\tif (result.status === \"complete\" || result.status === \"failed\") {\n\t\t\t\t\tdone = true;\n\t\t\t\t\tresolve({\n\t\t\t\t\t\tkind: \"poll\",\n\t\t\t\t\t\tresult: result as\n\t\t\t\t\t\t\t| { status: \"complete\"; token: string; organizationId?: string }\n\t\t\t\t\t\t\t| { status: \"failed\"; reason: string },\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t})\n\t\t\t.catch(() => {});\n\n\t\tsetTimeout(\n\t\t\t() => {\n\t\t\t\tif (!done) {\n\t\t\t\t\tdone = true;\n\t\t\t\t\tresolve(null);\n\t\t\t\t}\n\t\t\t},\n\t\t\tMath.max(0, deadline - Date.now()),\n\t\t);\n\t});\n\n\tstopPolling = true;\n\tserver?.close();\n\n\tif (winner !== null) {\n\t\tif (winner.kind === \"server\") {\n\t\t\trawToken = winner.params.token;\n\t\t\tif (\n\t\t\t\ttypeof winner.params.organizationId === \"string\" &&\n\t\t\t\twinner.params.organizationId\n\t\t\t) {\n\t\t\t\tcallbackOrganizationId = winner.params.organizationId;\n\t\t\t}\n\t\t\tif (winner.params.discovery_ready === \"1\") {\n\t\t\t\tcallbackDiscoveryReady = true;\n\t\t\t}\n\t\t} else if (winner.result.status === \"complete\") {\n\t\t\trawToken = winner.result.token;\n\t\t\tif (winner.result.organizationId) {\n\t\t\t\tcallbackOrganizationId = winner.result.organizationId;\n\t\t\t}\n\t\t} else {\n\t\t\tauthSpinner.stop();\n\t\t\tp.log.error(winner.result.reason);\n\t\t\treturn null;\n\t\t}\n\t}\n\n\tif (!rawToken) {\n\t\tauthSpinner.stop();\n\t\tp.log.error(\"The authentication link expired. Run `vocoder init` again.\");\n\t\treturn null;\n\t}\n\n\tconst userInfo = await api.getCliUserInfo(rawToken);\n\tauthSpinner.stop(`Authenticated as ${chalk.bold(userInfo.email)}`);\n\n\treturn {\n\t\ttoken: rawToken,\n\t\t...userInfo,\n\t\torganizationId: callbackOrganizationId,\n\t\tdiscoveryReady: callbackDiscoveryReady,\n\t};\n}\n","/**\n * @module browser\n *\n * Cross-platform utility for opening a URL in the user's default browser.\n * Used by auth-flow and plan-check flows that need to direct users to a URL.\n *\n * Exports: tryOpenBrowser\n */\n\nimport { spawn } from \"node:child_process\";\n\n/**\n * Attempts to open a URL in the system browser. Returns false in CI or when\n * the launch fails — callers should fall back to displaying the URL as text.\n */\nexport async function tryOpenBrowser(url: string): Promise<boolean> {\n\tif (!process.stdout.isTTY || process.env.CI === \"true\") {\n\t\treturn false;\n\t}\n\n\tlet command: string;\n\tlet args: string[];\n\n\tif (process.platform === \"darwin\") {\n\t\tcommand = \"open\";\n\t\targs = [url];\n\t} else if (process.platform === \"win32\") {\n\t\tcommand = \"rundll32\";\n\t\targs = [\"url.dll,FileProtocolHandler\", url];\n\t} else {\n\t\tcommand = \"xdg-open\";\n\t\targs = [url];\n\t}\n\n\treturn new Promise<boolean>((resolve) => {\n\t\ttry {\n\t\t\tconst child = spawn(command, args, {\n\t\t\t\tdetached: true,\n\t\t\t\tstdio: \"ignore\",\n\t\t\t\twindowsHide: true,\n\t\t\t});\n\n\t\t\tlet settled = false;\n\t\t\tchild.once(\"spawn\", () => {\n\t\t\t\tif (settled) return;\n\t\t\t\tsettled = true;\n\t\t\t\tchild.unref();\n\t\t\t\tresolve(true);\n\t\t\t});\n\t\t\tchild.once(\"error\", () => {\n\t\t\t\tif (settled) return;\n\t\t\t\tsettled = true;\n\t\t\t\tresolve(false);\n\t\t\t});\n\t\t\tsetTimeout(() => {\n\t\t\t\tif (settled) return;\n\t\t\t\tsettled = true;\n\t\t\t\tresolve(false);\n\t\t\t}, 300);\n\t\t} catch {\n\t\t\tresolve(false);\n\t\t}\n\t});\n}\n","import { createServer } from \"node:http\";\nimport type { AddressInfo } from \"node:net\";\nimport { URL } from \"node:url\";\n\nexport interface LocalServerHandle {\n\tport: number;\n\twaitForCallback: () => Promise<Record<string, string>>;\n\tclose: () => void;\n}\n\n/**\n * Starts a local HTTP server on a random available port.\n * Returns the port and a promise that resolves when the browser\n * redirects to /callback with query parameters.\n *\n * Used for the browser→CLI token handoff pattern:\n * 1. CLI passes `port` to the auth session start request\n * 2. After browser auth, vocoder.app redirects to localhost:<port>/callback?token=...\n * 3. `waitForCallback()` resolves with the query params\n */\nexport function startCallbackServer(): Promise<LocalServerHandle> {\n\treturn new Promise((resolve, reject) => {\n\t\tlet settled = false;\n\t\tlet callbackResolve: ((params: Record<string, string>) => void) | null =\n\t\t\tnull;\n\t\tlet callbackReject: ((err: Error) => void) | null = null;\n\n\t\tconst callbackPromise = new Promise<Record<string, string>>((res, rej) => {\n\t\t\tcallbackResolve = res;\n\t\t\tcallbackReject = rej;\n\t\t});\n\n\t\tconst server = createServer((req, res) => {\n\t\t\tif (!req.url) {\n\t\t\t\tres.writeHead(400);\n\t\t\t\tres.end();\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tlet pathname: string;\n\t\t\tlet params: Record<string, string>;\n\n\t\t\ttry {\n\t\t\t\tconst parsed = new URL(req.url, \"http://localhost\");\n\t\t\t\tpathname = parsed.pathname;\n\t\t\t\tparams = Object.fromEntries(parsed.searchParams.entries());\n\t\t\t} catch {\n\t\t\t\tres.writeHead(400);\n\t\t\t\tres.end(\"Bad request\");\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (pathname !== \"/callback\") {\n\t\t\t\tres.writeHead(404);\n\t\t\t\tres.end(\"Not found\");\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tres.writeHead(200, { \"Content-Type\": \"text/html\" });\n\t\t\tres.end(\n\t\t\t\t\"<!DOCTYPE html><html><head><title>Authenticated</title></head>\" +\n\t\t\t\t\t'<body style=\"font-family:sans-serif;text-align:center;padding:3rem;\">' +\n\t\t\t\t\t\"<h2>Authenticated</h2>\" +\n\t\t\t\t\t\"<p>Return to your terminal to continue. You can close this tab.</p>\" +\n\t\t\t\t\t\"</body></html>\",\n\t\t\t);\n\n\t\t\tif (callbackResolve) {\n\t\t\t\tcallbackResolve(params);\n\t\t\t\tcallbackResolve = null;\n\t\t\t}\n\n\t\t\tsetImmediate(() => server.close());\n\t\t});\n\n\t\tserver.on(\"error\", (err) => {\n\t\t\tif (!settled) {\n\t\t\t\tsettled = true;\n\t\t\t\tif (callbackReject) callbackReject(err);\n\t\t\t\treject(err);\n\t\t\t}\n\t\t});\n\n\t\t// Bind to a random port on localhost only\n\t\tserver.listen(0, \"127.0.0.1\", () => {\n\t\t\tif (settled) return;\n\t\t\tsettled = true;\n\n\t\t\tconst port = (server.address() as AddressInfo).port;\n\n\t\t\tresolve({\n\t\t\t\tport,\n\t\t\t\twaitForCallback: () => callbackPromise,\n\t\t\t\tclose: () => server.close(),\n\t\t\t});\n\t\t});\n\t});\n}\n","/**\n * @module output\n *\n * Terminal output helpers for the init command: API key display, env file writing,\n * clipboard copy, and formatted command/code-block rendering.\n *\n * Exports: tryClipboard, printCommand, printCodeBlock, printApiKey, writeApiKeyToEnv\n */\n\nimport * as p from \"@clack/prompts\";\nimport chalk from \"chalk\";\nimport { execSync } from \"node:child_process\";\nimport { existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\n\n/**\n * Tries to copy text to the system clipboard using common CLI tools.\n * Returns true if any tool succeeded.\n */\nexport function tryClipboard(text: string): boolean {\n\tconst tools: Array<{ cmd: string; args?: string[] }> = [\n\t\t{ cmd: \"pbcopy\" },\n\t\t{ cmd: \"xclip\", args: [\"-selection\", \"clipboard\"] },\n\t\t{ cmd: \"xsel\", args: [\"--clipboard\", \"--input\"] },\n\t\t{ cmd: \"wl-copy\" },\n\t\t{ cmd: \"clip\" },\n\t];\n\tfor (const { cmd, args = [] } of tools) {\n\t\ttry {\n\t\t\texecSync([cmd, ...args].join(\" \"), {\n\t\t\t\tinput: text,\n\t\t\t\tstdio: [\"pipe\", \"ignore\", \"ignore\"],\n\t\t\t});\n\t\t\treturn true;\n\t\t} catch {\n\t\t\tcontinue;\n\t\t}\n\t}\n\treturn false;\n}\n\n/**\n * Prints a shell command prefixed with `$`, auto-copies to clipboard, and\n * notes if the copy succeeded. Single-line format avoids box-drawing characters\n * that terminal selection includes verbatim.\n */\nexport function printCommand(cmd: string): void {\n\tconst copied = tryClipboard(cmd);\n\tprocess.stdout.write(\"\\n\");\n\tprocess.stdout.write(` ${chalk.dim(\"$\")} ${chalk.cyan(cmd)}\\n`);\n\tif (copied) process.stdout.write(` ${chalk.dim(\"↑ copied to clipboard\")}\\n`);\n\tprocess.stdout.write(\"\\n\");\n}\n\n/**\n * Prints a multi-line code block with 2-space indentation. No box characters —\n * safe for terminal copy-paste selection.\n */\nexport function printCodeBlock(code: string): void {\n\tprocess.stdout.write(\"\\n\");\n\tfor (const line of code.split(\"\\n\")) {\n\t\tprocess.stdout.write(` ${line}\\n`);\n\t}\n\tprocess.stdout.write(\"\\n\");\n}\n\n/**\n * Writes VOCODER_API_KEY to the .env file at repoRoot (or cwd).\n * Updates an existing entry in-place; appends if absent. Returns false if no .env exists.\n */\nexport function writeApiKeyToEnv(apiKey: string, repoRoot?: string): boolean {\n\tconst envPath = join(repoRoot ?? process.cwd(), \".env\");\n\tif (!existsSync(envPath)) return false;\n\n\ttry {\n\t\tconst content = readFileSync(envPath, \"utf-8\");\n\t\tconst keyLine = `VOCODER_API_KEY=${apiKey}`;\n\t\tlet updated: string;\n\n\t\tif (/^VOCODER_API_KEY=/m.test(content)) {\n\t\t\tupdated = content.replace(/^VOCODER_API_KEY=.*/m, keyLine);\n\t\t} else {\n\t\t\tconst sep = content.length > 0 && !content.endsWith(\"\\n\") ? \"\\n\" : \"\";\n\t\t\tupdated = `${content}${sep}${keyLine}\\n`;\n\t\t}\n\n\t\twriteFileSync(envPath, updated);\n\t\treturn true;\n\t} catch {\n\t\treturn false;\n\t}\n}\n\n/**\n * Displays the API key, saves it to .env if possible, and instructs the user\n * to add it manually otherwise.\n */\nexport function printApiKey(apiKey: string, repoRoot?: string): void {\n\tconst saved = writeApiKeyToEnv(apiKey, repoRoot);\n\n\tp.log.message(\"\");\n\tp.log.message(chalk.bold(\"Your API Key\"));\n\tprintCodeBlock(`VOCODER_API_KEY=${apiKey}`);\n\tif (saved) {\n\t\tp.log.success(chalk.dim(\"Saved to .env\"));\n\t} else {\n\t\tp.log.message(chalk.dim(\" Add the above to your .env file\"));\n\t}\n}\n","/**\n * @module scaffold\n *\n * Post-project-creation scaffolding: package installation, config file writing,\n * and getting-started output. Runs after the project and app records exist in\n * the API so failures here do not block the user's project from being created.\n *\n * Exports: runScaffold, writeAppConfigs\n */\n\nimport * as p from \"@clack/prompts\";\nimport chalk from \"chalk\";\nimport { execSync } from \"node:child_process\";\nimport { resolve } from \"node:path\";\nimport {\n\tbuildInstallCommand,\n\tdetectLocalEcosystem,\n\tgetPackagesToInstall,\n} from \"./detect-local.js\";\nimport { highlight, info } from \"./theme.js\";\nimport { findExistingConfig, writeVocoderConfig } from \"./write-config.js\";\n\nexport interface ScaffoldParams {\n\ttargetBranches: string[];\n}\n\n/**\n * Detects the local ecosystem, installs missing packages, and prints push\n * instructions + docs link. Called after project creation in both new-project\n * and add-app paths.\n */\nexport function runScaffold(params: ScaffoldParams): void {\n\tconst { targetBranches } = params;\n\n\tconst detection = detectLocalEcosystem();\n\n\tif (detection.ecosystem) {\n\t\tconst frameworkLabel = detection.framework ?? detection.ecosystem;\n\t\tconst pmLabel = detection.packageManager;\n\t\tp.log.info(`Detected: ${chalk.bold(frameworkLabel)} (${pmLabel})`);\n\t}\n\n\tconst { devPackages, runtimePackages } = getPackagesToInstall(detection);\n\tconst allPackages = [...devPackages, ...runtimePackages];\n\tif (allPackages.length > 0) {\n\t\tp.log.info(\"\");\n\t\tconst installSpinner = p.spinner();\n\t\tinstallSpinner.start(`Installing ${allPackages.join(\", \")}...`);\n\n\t\ttry {\n\t\t\tif (devPackages.length > 0) {\n\t\t\t\texecSync(\n\t\t\t\t\tbuildInstallCommand(detection.packageManager, devPackages, true),\n\t\t\t\t\t{ stdio: \"pipe\", cwd: process.cwd() },\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (runtimePackages.length > 0) {\n\t\t\t\texecSync(\n\t\t\t\t\tbuildInstallCommand(detection.packageManager, runtimePackages, false),\n\t\t\t\t\t{ stdio: \"pipe\", cwd: process.cwd() },\n\t\t\t\t);\n\t\t\t}\n\t\t\tinstallSpinner.stop(`Installed ${allPackages.join(\", \")}`);\n\t\t} catch {\n\t\t\tinstallSpinner.stop(\"Package installation failed\");\n\t\t\tconst cmds = [\n\t\t\t\tdevPackages.length > 0\n\t\t\t\t\t? buildInstallCommand(detection.packageManager, devPackages, true)\n\t\t\t\t\t: null,\n\t\t\t\truntimePackages.length > 0\n\t\t\t\t\t? buildInstallCommand(detection.packageManager, runtimePackages, false)\n\t\t\t\t\t: null,\n\t\t\t]\n\t\t\t\t.filter(Boolean)\n\t\t\t\t.join(\" && \");\n\t\t\tp.log.warn(`Run manually: ${highlight(cmds)}`);\n\t\t}\n\t} else if (detection.ecosystem) {\n\t\tp.log.info(`Packages: ${chalk.green(\"already installed\")}`);\n\t}\n\n\tconst branchList =\n\t\ttargetBranches.length > 0\n\t\t\t? targetBranches.map((b) => highlight(b)).join(\" or \")\n\t\t\t: highlight(\"your target branch\");\n\tp.log.message(\"\");\n\tp.log.success(`Push to ${branchList} to trigger your first translation run.`);\n\tp.log.message(info(\" Docs: https://vocoder.app/docs/getting-started\"));\n}\n\n/**\n * Writes one vocoder.config.ts (or .js) per app directory and logs the result.\n * Non-monorepo projects write a single config at the project root.\n */\nexport function writeAppConfigs(\n\tapps: Array<{ appDir: string; appId: string }>,\n\ttargetBranches: string[],\n\tuseTypeScript: boolean,\n\trepoRoot?: string,\n): void {\n\tconst base = repoRoot ?? process.cwd();\n\tfor (const app of apps) {\n\t\tconst dir = app.appDir ? resolve(base, app.appDir) : base;\n\t\tconst written = writeVocoderConfig({\n\t\t\ttargetBranches,\n\t\t\tappId: app.appId,\n\t\t\tcwd: dir,\n\t\t\tuseTypeScript,\n\t\t});\n\t\tif (written) {\n\t\t\tconst displayPath = app.appDir ? `${app.appDir}/${written}` : written;\n\t\t\tp.log.success(`Created ${highlight(displayPath)}`);\n\t\t} else if (!findExistingConfig(dir)) {\n\t\t\tconst ext = useTypeScript ? \"ts\" : \"js\";\n\t\t\tp.log.warn(\n\t\t\t\t`Could not write ${app.appDir ? `${app.appDir}/` : \"\"}vocoder.config.${ext} — create it manually.`,\n\t\t\t);\n\t\t}\n\t}\n}\n","import chalk from \"chalk\";\n\nconst ORANGE = \"#FC5206\";\nconst PINK = \"#D51977\";\nconst BLUE = \"#2450A9\";\n\nconst noColor = process.env.NO_COLOR === \"1\" || process.env.FORCE_COLOR === \"0\";\nconst hex = (color: string) => (s: string) =>\n\tnoColor ? s : chalk.hex(color)(s);\n\nexport const dim = (s: string) => (noColor ? s : chalk.dim(s));\nexport const bld = (s: string) => (noColor ? s : chalk.bold(s));\nexport const grn = (s: string) => (noColor ? s : chalk.green(s));\nexport const ylw = (s: string) => (noColor ? s : chalk.yellow(s));\nexport const red = (s: string) => (noColor ? s : chalk.red(s));\n\n/** Named values: file paths, locale codes, branch names, variable names */\nexport const highlight = hex(PINK);\n\n/** Structural info: bars, info logs, notes, links, selected checkmarks */\nexport const info = hex(BLUE);\n\n/** Brand identity: intro/outro text, active cursor ◆, spinner label accents */\nexport const active = hex(ORANGE);\n","import { existsSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\n\n/**\n * Returns the path of an existing vocoder.config file in cwd, trying\n * .ts → .js → .json in order. Returns null when none is found.\n */\nexport function findExistingConfig(cwd: string = process.cwd()): string | null {\n\tfor (const name of [\n\t\t\"vocoder.config.ts\",\n\t\t\"vocoder.config.js\",\n\t\t\"vocoder.config.json\",\n\t]) {\n\t\tconst candidate = join(cwd, name);\n\t\tif (existsSync(candidate)) return candidate;\n\t}\n\treturn null;\n}\n\n/**\n * Write a vocoder.config file to cwd if one doesn't already exist.\n * Pass `useTypeScript: false` for plain-JS projects — writes vocoder.config.js\n * instead of vocoder.config.ts. The config content is identical; only the\n * file extension (and therefore the import style in the user's editor) differs.\n *\n * Returns the filename that was written, or null if the file already existed\n * or the write failed.\n */\n/**\n * Write a vocoder.config file to cwd if one doesn't already exist.\n * Pass `useTypeScript: false` for plain-JS projects — writes vocoder.config.js\n * instead of vocoder.config.ts. The config content is identical; only the\n * file extension (and therefore the import style in the user's editor) differs.\n *\n * Returns the filename that was written, or null if the file already existed\n * or the write failed.\n */\nexport function writeVocoderConfig(options: {\n\ttargetBranches?: string[];\n\tuseTypeScript?: boolean;\n\tcwd?: string;\n\t/** App ID to embed in the config — written by init, used by CLI to identify the app. */\n\tappId?: string;\n}): string | null {\n\tconst {\n\t\ttargetBranches = [\"main\"],\n\t\tuseTypeScript = true,\n\t\tcwd = process.cwd(),\n\t\tappId,\n\t} = options;\n\n\t// Don't write if any config variant already exists\n\tif (findExistingConfig(cwd)) return null;\n\n\tconst ext = useTypeScript ? \"ts\" : \"js\";\n\tconst configPath = join(cwd, `vocoder.config.${ext}`);\n\tconst branchesStr = targetBranches.map((b) => `'${b}'`).join(\", \");\n\n\t// Patterns are always relative to the config file's own directory.\n\t// In a monorepo, the config lives in the app subdirectory, so `**` naturally\n\t// scopes to that app — no `appDir/` prefix needed (and adding it would break\n\t// extraction when the CLI or build plugin runs with the app dir as cwd).\n\tconst includes = [\"**/*.{tsx,jsx,ts,js}\"];\n\tconst includesStr = includes.map((p) => `'${p}'`).join(\", \");\n\tconst appIdLine = appId ? ` appId: '${appId}',\\n` : \"\";\n\n\t// Both TS and JS use ESM import syntax — the content is identical.\n\t// TypeScript users get type-checking from defineConfig; JS users get\n\t// the same runtime behaviour with no TS toolchain required.\n\tconst content = `import { defineConfig } from '@vocoder/config'\n\nexport default defineConfig({\n${appIdLine} targetBranches: [${branchesStr}],\n include: [${includesStr}],\n})\n`;\n\n\ttry {\n\t\twriteFileSync(configPath, content, \"utf-8\");\n\t\treturn `vocoder.config.${ext}`;\n\t} catch {\n\t\treturn null;\n\t}\n}\n","/**\n * @module mcp-setup\n *\n * Interactive prompt to add the Vocoder MCP server to the user's AI editor.\n * Handles Claude Code (runs `claude mcp add` automatically), Cursor, Windsurf,\n * VS Code, and a generic fallback that shows the raw JSON config.\n *\n * Exports: runMcpSetup, mcpServerJson\n */\n\nimport * as p from \"@clack/prompts\";\nimport chalk from \"chalk\";\nimport { execSync } from \"node:child_process\";\nimport { info } from \"./theme.js\";\nimport { printCodeBlock, printCommand } from \"./output.js\";\n\nconst MCP_DOCS_URL = \"https://vocoder.app/docs/mcp\";\n\n/** Returns the JSON config block for adding the Vocoder MCP server to any editor. */\nexport function mcpServerJson(apiKey: string): string {\n\treturn JSON.stringify(\n\t\t{\n\t\t\tmcpServers: {\n\t\t\t\tvocoder: {\n\t\t\t\t\ttype: \"stdio\",\n\t\t\t\t\tcommand: \"npx\",\n\t\t\t\t\targs: [\"-y\", \"@vocoder/mcp\"],\n\t\t\t\t\tenv: { VOCODER_API_KEY: apiKey },\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tnull,\n\t\t2,\n\t);\n}\n\n/**\n * Prompts the user to select their AI editor and registers the Vocoder MCP\n * server. For Claude Code, attempts automatic registration via `claude mcp add`.\n * For all others, prints the config JSON to paste into the editor's config file.\n */\nexport async function runMcpSetup(apiKey: string): Promise<void> {\n\ttype Tool = \"claude\" | \"cursor\" | \"windsurf\" | \"vscode\" | \"other\";\n\n\tconst tool = await p.select<Tool>({\n\t\tmessage: \"Which AI editor?\",\n\t\toptions: [\n\t\t\t{ value: \"claude\", label: \"Claude Code\" },\n\t\t\t{ value: \"cursor\", label: \"Cursor\" },\n\t\t\t{ value: \"windsurf\", label: \"Windsurf\" },\n\t\t\t{ value: \"vscode\", label: \"VS Code (GitHub Copilot)\" },\n\t\t\t{ value: \"other\", label: \"Other — show the config JSON\" },\n\t\t],\n\t});\n\n\tif (p.isCancel(tool)) return;\n\n\tif (tool === \"claude\") {\n\t\ttry {\n\t\t\texecSync(\n\t\t\t\t`claude mcp add --scope user --transport stdio --env VOCODER_API_KEY=${apiKey} vocoder -- npx -y @vocoder/mcp`,\n\t\t\t\t{ stdio: \"pipe\" },\n\t\t\t);\n\t\t\tp.log.success(\"Vocoder MCP server registered in Claude Code.\");\n\t\t} catch {\n\t\t\tp.log.message(\"Run this to register the MCP server:\");\n\t\t\tprintCommand(\n\t\t\t\t`claude mcp add --scope user --transport stdio --env VOCODER_API_KEY=${apiKey} vocoder -- npx -y @vocoder/mcp`,\n\t\t\t);\n\t\t\tp.log.message(info(` Docs: ${MCP_DOCS_URL}`));\n\t\t}\n\t\treturn;\n\t}\n\n\tconst configPaths: Record<Exclude<Tool, \"claude\">, { path: string; merge: boolean }> = {\n\t\tcursor: { path: \"~/.cursor/mcp.json\", merge: true },\n\t\twindsurf: { path: \"~/.codeium/windsurf/mcp_config.json\", merge: true },\n\t\tvscode: { path: \".vscode/mcp.json\", merge: true },\n\t\tother: { path: \".mcp.json\", merge: false },\n\t};\n\n\tconst { path: configPath, merge } = configPaths[tool];\n\tconst mergeNote = merge\n\t\t? chalk.dim(` Merge into ${configPath} (create if missing):`)\n\t\t: chalk.dim(` Add to ${configPath}:`);\n\n\tp.log.message(mergeNote);\n\tprintCodeBlock(mcpServerJson(apiKey));\n\tp.log.message(info(` Docs: ${MCP_DOCS_URL}`));\n}\n","/**\n * @module plan-check\n *\n * Workspace plan limit enforcement for the init command.\n * Scenarios:\n * - At limit: prompt to upgrade, open browser to subscription settings, exit.\n * - Near limit: return remaining slot count so the app-dir selector can cap input.\n * - API failure: warn and continue — the server enforces limits on creation too.\n * - Plan limit error from server POST: detect via message text, show upgrade URL.\n *\n * Exports: checkPlanLimits, isPlanLimitFailure, printPlanLimitMessage, getSubscriptionSettingsUrl\n */\n\nimport * as p from \"@clack/prompts\";\nimport chalk from \"chalk\";\nimport type { VocoderAPI } from \"./api.js\";\nimport { tryOpenBrowser } from \"./browser.js\";\n\nconst SUBSCRIPTION_SETTINGS_PATH =\n\t\"/dashboard/workspace/settings?tab=subscription\";\n\n/** Constructs the absolute URL for the workspace subscription settings page. */\nexport function getSubscriptionSettingsUrl(apiUrl: string): string {\n\treturn new URL(SUBSCRIPTION_SETTINGS_PATH, apiUrl).toString();\n}\n\n/** Returns true when a server error message indicates a plan limit was hit. */\nexport function isPlanLimitFailure(message?: string): boolean {\n\tif (!message) return false;\n\treturn /limit|upgrade/i.test(message);\n}\n\n/** Logs a plan limit error and the subscription settings URL for upgrading. */\nexport function printPlanLimitMessage(apiUrl: string, message: string): void {\n\tp.log.error(`You are over your plan limits.\\n ${message}`);\n\tp.log.info(`Manage subscription: ${getSubscriptionSettingsUrl(apiUrl)}`);\n}\n\nexport interface PlanCheckResult {\n\t/** True when the workspace is at or over its app limit. */\n\tatLimit: boolean;\n\t/** Remaining app slots, or undefined when the plan has no limit (-1). */\n\tremaining?: number;\n}\n\n/**\n * Fetches plan limits for the selected organization and enforces them\n * interactively. Returns `{ atLimit: true }` if the user was at limit and\n * chose to cancel, or `{ atLimit: false, remaining }` to continue.\n *\n * On API failure, warns and returns `{ atLimit: false }` — the server will\n * re-enforce the limit on project creation.\n */\nexport async function checkPlanLimits(\n\tapi: VocoderAPI,\n\tuserToken: string,\n\torganizationId: string,\n\tapiUrl: string,\n): Promise<PlanCheckResult> {\n\ttry {\n\t\tconst { organizations } = await api.listOrganizations(userToken);\n\t\tconst organization = organizations.find((o) => o.id === organizationId);\n\n\t\tif (!organization) {\n\t\t\treturn { atLimit: false };\n\t\t}\n\n\t\tif (organization.maxApps !== -1 && organization.appCount >= organization.maxApps) {\n\t\t\tp.log.warn(\n\t\t\t\t`App limit reached — ${organization.appCount}/${organization.maxApps} on your ${chalk.bold(organization.planId)} plan.`,\n\t\t\t);\n\n\t\t\tconst limitAction = await p.select<string>({\n\t\t\t\tmessage: \"What would you like to do?\",\n\t\t\t\toptions: [\n\t\t\t\t\t{ value: \"upgrade\", label: \"Upgrade plan\" },\n\t\t\t\t\t{ value: \"cancel\", label: \"Cancel\" },\n\t\t\t\t],\n\t\t\t});\n\n\t\t\tif (p.isCancel(limitAction) || limitAction === \"cancel\") {\n\t\t\t\tp.cancel(\"Setup cancelled.\");\n\t\t\t\treturn { atLimit: true };\n\t\t\t}\n\n\t\t\tawait tryOpenBrowser(getSubscriptionSettingsUrl(apiUrl));\n\t\t\tp.cancel(\"Upgrade your plan in the browser, then re-run `vocoder init`.\");\n\t\t\treturn { atLimit: true };\n\t\t}\n\n\t\tconst remaining =\n\t\t\torganization.maxApps === -1\n\t\t\t\t? undefined\n\t\t\t\t: Math.max(0, organization.maxApps - organization.appCount);\n\n\t\treturn { atLimit: false, remaining };\n\t} catch {\n\t\tp.log.warn(\n\t\t\t\"Could not verify plan limits — proceeding, the server will enforce them.\",\n\t\t);\n\t\treturn { atLimit: false };\n\t}\n}\n","/**\n * @module organization-select\n *\n * Organization (workspace) resolution for `vocoder init`. Handles all scenarios\n * a user may encounter when selecting which organization to create a project in:\n *\n * 1. Auth+install completed in one browser trip — org already known, skip selection.\n * 2. Repo already linked to an org via git connection — auto-select, skip GitHub steps.\n * 3. Exactly one org's GitHub App installation covers this repo — auto-select.\n * 4. Multiple orgs cover this repo — prompt user to pick one.\n * 5. Connected orgs exist but none cover this repo — surface fix options\n * (configure existing install, or install on a different account).\n * 6. No connections — first-time user path: check cached installs → claim or\n * run full discovery → select or create a new organization.\n *\n * Exports: selectOrganizationForInit\n */\n\nimport * as p from \"@clack/prompts\";\nimport chalk from \"chalk\";\nimport type { VocoderAPI } from \"./api.js\";\nimport {\n\trunGitHubDiscoveryFlow,\n\trunGitHubInstallFlow,\n\tselectGitHubInstallation,\n} from \"./github-connect.js\";\nimport { tryOpenBrowser } from \"./browser.js\";\nimport { selectOrganization } from \"./organization.js\";\n\nexport interface SelectOrganizationParams {\n\tapi: VocoderAPI;\n\tuserToken: string;\n\tuserEmail: string;\n\t/** Git identity from the current repo. Null when not in a git repo. */\n\tidentity: { repoCanonical: string; repoRoot: string } | null;\n\t/** Result of the anonymous repo lookup performed before auth. */\n\tlookup: { organizationContext?: { organizationId: string; organizationName: string } | null } | null;\n\t/** Set when the repo already has a project — causes this function to skip straight to org resolution. */\n\trepoProjectId: string | null;\n\t/** Set when auth + GitHub install completed in one browser trip. */\n\tauthOrganizationId?: string;\n\toptions: { yes?: boolean };\n}\n\nexport interface SelectOrganizationResult {\n\torganizationId: string;\n\torganizationName: string;\n}\n\n/**\n * Resolves which organization to use for project creation. Returns the selected\n * organization, or null if the user cancelled or an unrecoverable error occurred.\n */\nexport async function selectOrganizationForInit(\n\tparams: SelectOrganizationParams,\n): Promise<SelectOrganizationResult | null> {\n\tconst { api, userToken, userEmail, identity, lookup, repoProjectId, options } = params;\n\n\t// ── Scenario 1: auth + install completed in one browser trip ─────────────────\n\tif (params.authOrganizationId) {\n\t\tconst organizationData = await api.listOrganizations(userToken);\n\t\tconst organization = organizationData.organizations.find(\n\t\t\t(o) => o.id === params.authOrganizationId,\n\t\t);\n\t\tconst organizationName = organization?.name ?? userEmail;\n\t\tp.log.success(\n\t\t\t`Connected as ${chalk.bold(userEmail)} — workspace: ${chalk.bold(organizationName)}`,\n\t\t);\n\t\treturn { organizationId: params.authOrganizationId, organizationName };\n\t}\n\n\t// ── Scenario 2: repo already linked to an org (git connection exists, no project yet) ──\n\tconst repoOrgContext = identity ? (lookup?.organizationContext ?? null) : null;\n\tif (repoOrgContext && !repoProjectId) {\n\t\tp.log.success(`Workspace: ${chalk.bold(repoOrgContext.organizationName)}`);\n\t\treturn {\n\t\t\torganizationId: repoOrgContext.organizationId,\n\t\t\torganizationName: repoOrgContext.organizationName,\n\t\t};\n\t}\n\n\t// ── Main path: resolve via org membership + GitHub installation state ─────────\n\tconst organizationData = await api.listOrganizations(userToken, {\n\t\trepo: identity?.repoCanonical,\n\t});\n\n\tconst repoCanonical = identity?.repoCanonical ?? null;\n\tconst covering = repoCanonical\n\t\t? organizationData.organizations.filter((o) => o.coversRepo === true)\n\t\t: [];\n\tconst connected = organizationData.organizations.filter(\n\t\t(o) => o.hasGitHubConnection,\n\t);\n\n\tif (repoCanonical && covering.length === 1) {\n\t\t// ── Scenario 3: exactly one org covers this repo — auto-select ───────────\n\t\tconst organization = covering[0]!;\n\t\tp.log.success(`Workspace: ${chalk.bold(organization.name)}`);\n\t\treturn { organizationId: organization.id, organizationName: organization.name };\n\t}\n\n\tif (repoCanonical && covering.length > 1) {\n\t\t// ── Scenario 4: multiple orgs cover this repo — prompt ───────────────────\n\t\tconst choice = await p.select<string>({\n\t\t\tmessage: \"Select workspace for this repo\",\n\t\t\toptions: covering.map((o) => ({\n\t\t\t\tvalue: o.id,\n\t\t\t\tlabel: `${o.name} ${chalk.dim(`(${o.appCount} app${o.appCount !== 1 ? \"s\" : \"\"})`)}`,\n\t\t\t})),\n\t\t});\n\t\tif (p.isCancel(choice)) {\n\t\t\tp.cancel(\"Setup cancelled.\");\n\t\t\treturn null;\n\t\t}\n\t\tconst organization = covering.find((o) => o.id === choice)!;\n\t\tp.log.success(`Workspace: ${chalk.bold(organization.name)}`);\n\t\treturn { organizationId: organization.id, organizationName: organization.name };\n\t}\n\n\tif (repoCanonical && covering.length === 0 && connected.length > 0) {\n\t\t// ── Scenario 5: connected orgs exist but none cover this repo ────────────\n\t\tconst shortRepo = repoCanonical.split(\":\")[1] ?? repoCanonical;\n\t\tp.log.warn(\n\t\t\t`${chalk.bold(shortRepo)} isn't accessible from your Vocoder installation.\\n` +\n\t\t\t\t` Grant access to this repository or install on the account that owns it.`,\n\t\t);\n\n\t\tconst fixOptions: Array<{ value: string; label: string }> = [];\n\t\tfor (const organization of connected) {\n\t\t\tif (organization.installationConfigureUrl) {\n\t\t\t\tfixOptions.push({\n\t\t\t\t\tvalue: `grant:${organization.id}`,\n\t\t\t\t\tlabel: `Configure ${chalk.bold(organization.connectionLabel ?? organization.name)}'s GitHub App installation`,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\tfixOptions.push({\n\t\t\tvalue: \"install_new\",\n\t\t\tlabel: `Install on a different GitHub account ${chalk.dim(\"(creates a new personal workspace)\")}`,\n\t\t});\n\t\tfixOptions.push({ value: \"cancel\", label: \"Cancel\" });\n\n\t\tconst fix = await p.select<string>({\n\t\t\tmessage: \"How would you like to fix this?\",\n\t\t\toptions: fixOptions,\n\t\t});\n\n\t\tif (p.isCancel(fix) || fix === \"cancel\") {\n\t\t\tp.cancel(\"Setup cancelled.\");\n\t\t\treturn null;\n\t\t}\n\n\t\tif (fix.startsWith(\"grant:\")) {\n\t\t\tconst organization = connected.find((o) => `grant:${o.id}` === fix)!;\n\t\t\tawait tryOpenBrowser(organization.installationConfigureUrl!);\n\t\t\tp.cancel(\n\t\t\t\t`Grant access to ${chalk.bold(shortRepo)} in your browser,\\n` +\n\t\t\t\t\t` then re-run ${chalk.bold(\"vocoder init\")}.`,\n\t\t\t);\n\t\t\treturn null;\n\t\t}\n\n\t\t// install_new: full install → creates new org covering the new account\n\t\tconst connectResult = await runGitHubInstallFlow({\n\t\t\tapi,\n\t\t\tuserToken,\n\t\t\tyes: options.yes,\n\t\t});\n\t\tif (!connectResult) {\n\t\t\tp.log.error(\"GitHub App installation did not complete. Run `vocoder init` again.\");\n\t\t\treturn null;\n\t\t}\n\t\tp.log.success(`Workspace: ${chalk.bold(connectResult.organizationName)}`);\n\t\treturn {\n\t\t\torganizationId: connectResult.organizationId,\n\t\t\torganizationName: connectResult.organizationName,\n\t\t};\n\t}\n\n\t// ── Scenario 6: fallback — no connections, first-time user path ──────────────\n\t// Only check cached GitHub App installs here (covering === 0 && connected === 0),\n\t// so claiming a cached installation can never error with \"already connected\".\n\tconst discoveryResult = await api.getCliGitHubDiscovery(userToken).catch(() => null);\n\tconst cachedInstallations = discoveryResult?.installations ?? [];\n\n\tif (cachedInstallations.length > 0) {\n\t\tif (repoCanonical) {\n\t\t\tconst repoOwner = repoCanonical.split(\":\")[1]?.split(\"/\")[0]?.toLowerCase();\n\t\t\tif (repoOwner) {\n\t\t\t\tconst hasMatchingAccount = cachedInstallations.some(\n\t\t\t\t\t(i) => i.accountLogin.toLowerCase() === repoOwner,\n\t\t\t\t);\n\t\t\t\tif (!hasMatchingAccount) {\n\t\t\t\t\tp.log.warn(\n\t\t\t\t\t\t`None of your GitHub App installations belong to \"${repoOwner}\", ` +\n\t\t\t\t\t\t\t`the account that owns this repository.\\n` +\n\t\t\t\t\t\t\t` The project will be created but translations won't trigger automatically.\\n` +\n\t\t\t\t\t\t\t` To fix: install the Vocoder GitHub App on \"${repoOwner}\" instead.`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tconst validInstallations = cachedInstallations.filter(\n\t\t\t(i) => !i.isSuspended && !i.conflictLabel,\n\t\t);\n\n\t\tlet selectedInstallationId: number | string | null = null;\n\t\tif (validInstallations.length === 1 && cachedInstallations.length === 1) {\n\t\t\tselectedInstallationId = validInstallations[0]!.installationId;\n\t\t} else {\n\t\t\tselectedInstallationId = await selectGitHubInstallation(\n\t\t\t\tcachedInstallations.map((inst) => ({\n\t\t\t\t\tinstallationId: inst.installationId,\n\t\t\t\t\taccountLogin: inst.accountLogin,\n\t\t\t\t\taccountType: inst.accountType,\n\t\t\t\t\tisSuspended: inst.isSuspended,\n\t\t\t\t\tconflictLabel: inst.conflictLabel,\n\t\t\t\t})),\n\t\t\t\tfalse,\n\t\t\t);\n\t\t}\n\n\t\tif (\n\t\t\tselectedInstallationId === null ||\n\t\t\tselectedInstallationId === \"install_new\"\n\t\t) {\n\t\t\tp.cancel(\"Setup cancelled. Re-run `vocoder init` and choose Install GitHub App.\");\n\t\t\treturn null;\n\t\t}\n\n\t\tconst claimResult = await api.claimCliGitHubInstallation(userToken, {\n\t\t\tinstallationId: String(selectedInstallationId),\n\t\t\torganizationId: null,\n\t\t});\n\t\tp.log.success(`Workspace: ${chalk.bold(claimResult.organizationName)}`);\n\t\treturn {\n\t\t\torganizationId: claimResult.organizationId,\n\t\t\torganizationName: claimResult.organizationName,\n\t\t};\n\t}\n\n\tif (\n\t\torganizationData.organizations.length === 1 &&\n\t\t!organizationData.canCreateOrganization\n\t) {\n\t\tconst organization = organizationData.organizations[0]!;\n\t\tp.log.success(`Workspace: ${chalk.bold(organization.name)}`);\n\t\treturn { organizationId: organization.id, organizationName: organization.name };\n\t}\n\n\t// Let user pick an existing org or trigger create-new flow\n\tconst organizationResult = await selectOrganization(organizationData);\n\n\tif (organizationResult.action === \"cancelled\") {\n\t\tp.cancel(\"Setup cancelled.\");\n\t\treturn null;\n\t}\n\n\tif (organizationResult.action === \"use\") {\n\t\tconst { organization } = organizationResult;\n\t\tp.log.success(`Workspace: ${chalk.bold(organization.name)}`);\n\t\treturn { organizationId: organization.id, organizationName: organization.name };\n\t}\n\n\t// ── New workspace: GitHub connect flow ───────────────────────────────────────\n\tconst connectChoice = await p.select<string>({\n\t\tmessage: \"Connect your new workspace to GitHub\",\n\t\toptions: [\n\t\t\t{ value: \"install\", label: \"Install the Vocoder GitHub App\" },\n\t\t\t{ value: \"link\", label: \"Link an existing installation\" },\n\t\t],\n\t});\n\n\tif (p.isCancel(connectChoice)) {\n\t\tp.cancel(\"Setup cancelled.\");\n\t\treturn null;\n\t}\n\n\tif (connectChoice === \"install\") {\n\t\tconst connectResult = await runGitHubInstallFlow({\n\t\t\tapi,\n\t\t\tuserToken,\n\t\t\tyes: options.yes,\n\t\t});\n\t\tif (!connectResult) {\n\t\t\tp.log.error(\"GitHub App installation did not complete. Run `vocoder init` again.\");\n\t\t\treturn null;\n\t\t}\n\t\tp.log.success(`Workspace: ${chalk.bold(connectResult.organizationName)}`);\n\t\treturn {\n\t\t\torganizationId: connectResult.organizationId,\n\t\t\torganizationName: connectResult.organizationName,\n\t\t};\n\t}\n\n\t// \"link\" — run discovery to find existing installations\n\tconst installations = await runGitHubDiscoveryFlow({\n\t\tapi,\n\t\tuserToken,\n\t\tyes: options.yes,\n\t});\n\tif (!installations) return null;\n\n\tif (installations.length === 0) {\n\t\tp.log.warn(\"No GitHub installations found. Install the Vocoder GitHub App first.\");\n\t\tconst installNow = await p.confirm({\n\t\t\tmessage: \"Open GitHub to install the App?\",\n\t\t});\n\t\tif (p.isCancel(installNow) || !installNow) return null;\n\t\tconst connectResult = await runGitHubInstallFlow({\n\t\t\tapi,\n\t\t\tuserToken,\n\t\t\tyes: options.yes,\n\t\t});\n\t\tif (!connectResult) return null;\n\t\tp.log.success(`Workspace: ${chalk.bold(connectResult.organizationName)}`);\n\t\treturn {\n\t\t\torganizationId: connectResult.organizationId,\n\t\t\torganizationName: connectResult.organizationName,\n\t\t};\n\t}\n\n\tconst selectedInstallationId = await selectGitHubInstallation(\n\t\tinstallations.map((inst) => ({\n\t\t\tinstallationId: inst.installationId,\n\t\t\taccountLogin: inst.accountLogin,\n\t\t\taccountType: inst.accountType,\n\t\t\tisSuspended: inst.isSuspended,\n\t\t\tconflictLabel: inst.conflictLabel,\n\t\t})),\n\t\ttrue,\n\t);\n\n\tif (selectedInstallationId === null) {\n\t\tp.cancel(\"Setup cancelled.\");\n\t\treturn null;\n\t}\n\n\tif (selectedInstallationId === \"install_new\") {\n\t\tconst connectResult = await runGitHubInstallFlow({\n\t\t\tapi,\n\t\t\tuserToken,\n\t\t\tyes: options.yes,\n\t\t});\n\t\tif (!connectResult) return null;\n\t\tp.log.success(`Workspace: ${chalk.bold(connectResult.organizationName)}`);\n\t\treturn {\n\t\t\torganizationId: connectResult.organizationId,\n\t\t\torganizationName: connectResult.organizationName,\n\t\t};\n\t}\n\n\tconst claimResult = await api.claimCliGitHubInstallation(userToken, {\n\t\tinstallationId: String(selectedInstallationId),\n\t\torganizationId: null,\n\t});\n\tp.log.success(`Workspace: ${chalk.bold(claimResult.organizationName)}`);\n\treturn {\n\t\torganizationId: claimResult.organizationId,\n\t\torganizationName: claimResult.organizationName,\n\t};\n}\n","import * as p from \"@clack/prompts\";\n\nimport type { VocoderAPI } from \"./api.js\";\nimport chalk from \"chalk\";\nimport { startCallbackServer } from \"./local-server.js\";\nimport { tryOpenBrowser } from \"./browser.js\";\n\nexport interface GitHubConnectResult {\n\torganizationId: string;\n\torganizationName: string;\n\tconnectionLabel: string;\n}\n\n/**\n * Run the full GitHub App install flow for a new workspace.\n * Opens the browser to the GitHub App install page and waits for completion.\n *\n * Returns `null` if the user cancelled or an error occurred.\n */\nexport async function runGitHubInstallFlow(params: {\n\tapi: VocoderAPI;\n\tuserToken: string;\n\torganizationId?: string;\n\tyes?: boolean;\n}): Promise<GitHubConnectResult | null> {\n\t// Try to start a local callback server for instant notification\n\tlet server: Awaited<ReturnType<typeof startCallbackServer>> | null = null;\n\ttry {\n\t\tserver = await startCallbackServer();\n\t} catch {\n\t\t// Fall through — the user can re-run if something goes wrong\n\t}\n\n\tconst { installUrl } = await params.api.startCliGitHubInstall(\n\t\tparams.userToken,\n\t\t{\n\t\t\torganizationId: params.organizationId,\n\t\t\tcallbackPort: server?.port,\n\t\t},\n\t);\n\n\tp.log.info(\"Opening GitHub to install the Vocoder App...\");\n\n\tif (\n\t\tprocess.stdin.isTTY &&\n\t\tprocess.stdout.isTTY &&\n\t\tprocess.env.CI !== \"true\"\n\t) {\n\t\tconst shouldOpen = params.yes\n\t\t\t? true\n\t\t\t: await p.confirm({ message: \"Open in your browser?\" });\n\n\t\tif (p.isCancel(shouldOpen)) {\n\t\t\tserver?.close();\n\t\t\treturn null;\n\t\t}\n\n\t\tif (shouldOpen) {\n\t\t\tconst opened = await tryOpenBrowser(installUrl);\n\t\t\tif (!opened) {\n\t\t\t\tp.log.info(\n\t\t\t\t\t\"Could not open a browser automatically. Use the URL above.\",\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\tconst connectSpinner = p.spinner();\n\tconnectSpinner.start(\"Waiting for GitHub App installation...\");\n\n\tif (server) {\n\t\ttry {\n\t\t\tconst params_timeout = 15 * 60 * 1000; // 15 minutes\n\t\t\tconst callbackParams = await Promise.race([\n\t\t\t\tserver.waitForCallback(),\n\t\t\t\tnew Promise<null>((resolve) =>\n\t\t\t\t\tsetTimeout(() => resolve(null), params_timeout),\n\t\t\t\t),\n\t\t\t]);\n\n\t\t\tserver.close();\n\n\t\t\tif (!callbackParams) {\n\t\t\t\tconnectSpinner.stop(\"GitHub App installation timed out\");\n\t\t\t\tp.log.error(\n\t\t\t\t\t\"The installation flow timed out. Run `vocoder init` again.\",\n\t\t\t\t);\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tif (callbackParams.error) {\n\t\t\t\tconnectSpinner.stop(\"GitHub App installation failed\");\n\t\t\t\tp.log.error(callbackParams.error);\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tconst { organizationId, connectionLabel, workspace_created } =\n\t\t\t\tcallbackParams;\n\n\t\t\tif (!organizationId || !connectionLabel) {\n\t\t\t\tconnectSpinner.stop(\"GitHub App installation incomplete\");\n\t\t\t\tp.log.error(\"Missing organization or connection data from callback.\");\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tconnectSpinner.stop(\n\t\t\t\t`Connected to GitHub as ${chalk.bold(connectionLabel)}`,\n\t\t\t);\n\n\t\t\t// Fetch the org name\n\t\t\tconst orgName = workspace_created ? connectionLabel : organizationId;\n\t\t\treturn {\n\t\t\t\torganizationId,\n\t\t\t\torganizationName: orgName,\n\t\t\t\tconnectionLabel,\n\t\t\t};\n\t\t} catch {\n\t\t\tserver.close();\n\t\t\tconnectSpinner.stop(\"GitHub App installation failed\");\n\t\t\treturn null;\n\t\t}\n\t}\n\n\t// No local server — there's no polling fallback for install; just wait\n\tconnectSpinner.stop(\"Could not detect GitHub App installation automatically\");\n\tp.log.warn(\n\t\t\"Complete the installation in your browser, then run `vocoder init` again.\",\n\t);\n\treturn null;\n}\n\n/**\n * Run the GitHub OAuth discovery flow to find existing installations.\n * Returns the list of installations with conflict labels, or null on cancellation/error.\n */\nexport async function runGitHubDiscoveryFlow(params: {\n\tapi: VocoderAPI;\n\tuserToken: string;\n\torganizationId?: string;\n\tyes?: boolean;\n}): Promise<Array<{\n\tinstallationId: number;\n\taccountLogin: string;\n\taccountType: string;\n\tisSuspended: boolean;\n\tconflictLabel: string | null;\n}> | null> {\n\t// Try local callback server\n\tlet server: Awaited<ReturnType<typeof startCallbackServer>> | null = null;\n\ttry {\n\t\tserver = await startCallbackServer();\n\t} catch {\n\t\t// Fall through\n\t}\n\n\tconst { oauthUrl } = await params.api.startCliGitHubOAuth(params.userToken, {\n\t\torganizationId: params.organizationId,\n\t\tcallbackPort: server?.port,\n\t});\n\n\tp.log.info(\"Opening GitHub to authorize your account...\");\n\n\tif (\n\t\tprocess.stdin.isTTY &&\n\t\tprocess.stdout.isTTY &&\n\t\tprocess.env.CI !== \"true\"\n\t) {\n\t\tconst shouldOpen = params.yes\n\t\t\t? true\n\t\t\t: await p.confirm({ message: \"Open in your browser?\" });\n\n\t\tif (p.isCancel(shouldOpen)) {\n\t\t\tserver?.close();\n\t\t\treturn null;\n\t\t}\n\n\t\tif (shouldOpen) {\n\t\t\tconst opened = await tryOpenBrowser(oauthUrl);\n\t\t\tif (!opened) {\n\t\t\t\tp.log.info(`Could not open browser automatically. Visit: ${oauthUrl}`);\n\t\t\t}\n\t\t}\n\t}\n\n\tconst oauthSpinner = p.spinner();\n\toauthSpinner.start(\"Waiting for GitHub authorization...\");\n\n\tif (server) {\n\t\ttry {\n\t\t\tconst timeoutMs = 10 * 60 * 1000;\n\t\t\tconst callbackParams = await Promise.race([\n\t\t\t\tserver.waitForCallback(),\n\t\t\t\tnew Promise<null>((resolve) =>\n\t\t\t\t\tsetTimeout(() => resolve(null), timeoutMs),\n\t\t\t\t),\n\t\t\t]);\n\n\t\t\tserver.close();\n\n\t\t\tif (!callbackParams) {\n\t\t\t\toauthSpinner.stop(\"GitHub authorization timed out\");\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tif (callbackParams.error) {\n\t\t\t\toauthSpinner.stop(\"GitHub authorization failed\");\n\t\t\t\tp.log.error(callbackParams.error);\n\t\t\t\treturn null;\n\t\t\t}\n\t\t} catch {\n\t\t\tserver.close();\n\t\t\toauthSpinner.stop(\"GitHub authorization failed\");\n\t\t\treturn null;\n\t\t}\n\t}\n\n\toauthSpinner.stop(\"GitHub account authorized\");\n\n\t// Fetch discovery results\n\tconst discoveryResult = await params.api.getCliGitHubDiscovery(\n\t\tparams.userToken,\n\t);\n\treturn discoveryResult.installations;\n}\n\ntype DiscoveredInstallation = {\n\tinstallationId: number;\n\taccountLogin: string;\n\taccountType: string;\n\tisSuspended: boolean;\n\tconflictLabel: string | null;\n};\n\n/**\n * Prompt the user to select a GitHub installation from discovery results.\n * Returns the selected installation ID, 'install_new' to trigger install flow,\n * or null on cancellation.\n */\nexport async function selectGitHubInstallation(\n\tinstallations: DiscoveredInstallation[],\n\tcanInstallNew: boolean,\n): Promise<number | \"install_new\" | null> {\n\ttype SelectValue = string;\n\n\tconst options: Array<{ value: SelectValue; label: string; hint?: string }> =\n\t\tinstallations.map((inst) => ({\n\t\t\tvalue: String(inst.installationId),\n\t\t\tlabel: inst.accountLogin,\n\t\t\thint:\n\t\t\t\t[\n\t\t\t\t\tinst.accountType === \"Organization\" ? \"GitHub org\" : \"personal account\",\n\t\t\t\t\tinst.conflictLabel ? `connected to ${inst.conflictLabel}` : \"\",\n\t\t\t\t\tinst.isSuspended ? \"suspended\" : \"\",\n\t\t\t\t]\n\t\t\t\t\t.filter(Boolean)\n\t\t\t\t\t.join(\" · \") || undefined,\n\t\t}));\n\n\tif (canInstallNew) {\n\t\toptions.push({\n\t\t\tvalue: \"install_new\",\n\t\t\tlabel: `Install on a new account ${chalk.dim(\"(creates a new workspace)\")}`,\n\t\t});\n\t}\n\n\tconst selected = await p.select<SelectValue>({\n\t\tmessage: \"Which GitHub account should this workspace connect to?\",\n\t\toptions,\n\t});\n\n\tif (p.isCancel(selected)) return null;\n\tif (selected === \"install_new\") return \"install_new\";\n\n\treturn Number(selected);\n}\n","import * as p from \"@clack/prompts\";\nimport chalk from \"chalk\";\n\nexport interface OrganizationInfo {\n\tid: string;\n\tname: string;\n\tplanId: string;\n\tprojectCount: number;\n\t/** Total app count across all projects. */\n\tappCount: number;\n\t/** Plan limit on total apps (-1 = unlimited). */\n\tmaxApps: number;\n\thasGitHubConnection: boolean;\n\tconnectionLabel: string | null;\n\t/** True when this org's GitHub App installation covers the queried repo. Null when no repo was queried. */\n\tcoversRepo: boolean | null;\n\tinstallationConfigureUrl: string | null;\n}\n\nexport interface OrganizationListResult {\n\torganizations: OrganizationInfo[];\n\tcanCreateOrganization: boolean;\n}\n\nexport type OrganizationSelection =\n\t| { action: \"use\"; organization: OrganizationInfo }\n\t| { action: \"create\" }\n\t| { action: \"cancelled\" };\n\n/**\n * Prompt the user to select an organization or create a new one.\n * Returns an `OrganizationSelection` describing what the user chose.\n */\nexport async function selectOrganization(\n\tresult: OrganizationListResult,\n): Promise<OrganizationSelection> {\n\tconst { organizations, canCreateOrganization } = result;\n\n\tif (organizations.length === 0) {\n\t\t// No organizations — must create\n\t\treturn { action: \"create\" };\n\t}\n\n\ttype SelectValue = string | \"create\";\n\n\tconst options: Array<{ value: SelectValue; label: string; hint?: string }> =\n\t\torganizations.map((org) => {\n\t\t\tconst atLimit = org.maxApps !== -1 && org.appCount >= org.maxApps;\n\t\t\tconst hint =\n\t\t\t\t[\n\t\t\t\t\torg.projectCount > 0\n\t\t\t\t\t\t? `${org.projectCount} project${org.projectCount !== 1 ? \"s\" : \"\"}`\n\t\t\t\t\t\t: \"\",\n\t\t\t\t\torg.connectionLabel ? `GitHub: ${org.connectionLabel}` : \"\",\n\t\t\t\t\tatLimit ? chalk.yellow(`${org.appCount}/${org.maxApps} apps — upgrade for more`) : \"\",\n\t\t\t\t]\n\t\t\t\t\t.filter(Boolean)\n\t\t\t\t\t.join(\" · \") || undefined;\n\t\t\treturn { value: org.id, label: org.name, hint };\n\t\t});\n\n\tif (canCreateOrganization) {\n\t\toptions.push({ value: \"create\", label: \"Create new workspace\" });\n\t}\n\n\tconst selected = await p.select<SelectValue>({\n\t\tmessage: \"Select workspace\",\n\t\toptions,\n\t});\n\n\tif (p.isCancel(selected)) {\n\t\treturn { action: \"cancelled\" };\n\t}\n\n\tif (selected === \"create\") {\n\t\treturn { action: \"create\" };\n\t}\n\n\tconst organization = organizations.find((org) => org.id === selected);\n\tif (!organization) {\n\t\treturn { action: \"cancelled\" };\n\t}\n\n\treturn { action: \"use\", organization };\n}\n","import * as p from \"@clack/prompts\";\nimport chalk from \"chalk\";\nimport type { VocoderAPI } from \"./api.js\";\nimport { collectAppDirs, promptSingleAppDir } from \"./app-dir-select.js\";\nimport { detectGitBranches, filterableBranchSelect } from \"./branch-select.js\";\nimport type { LocaleOption } from \"./locale-search.js\";\nimport {\n\tsearchMultiSelectLocales,\n\tsearchSelectLocale,\n} from \"./locale-search.js\";\n\nexport interface ExistingApp {\n\tappDir: string;\n\tappId: string;\n\tprojectId: string;\n\tprojectName: string;\n\torganizationName: string;\n}\n\nexport interface ProjectCreateParams {\n\tapi: VocoderAPI;\n\tuserToken: string;\n\torganizationId: string;\n\t/** Default project name (repo name or directory name) */\n\tdefaultName?: string;\n\t/** Pre-detected source locale, e.g. \"en\" */\n\tdefaultSourceLocale?: string;\n\t/** Repo canonical for binding the project, e.g. \"github:owner/repo\" */\n\trepoCanonical?: string;\n\t/** Default target branches */\n\tdefaultBranches?: string[];\n\t/** Git repository root — used as base for app directory validation */\n\trepoRoot?: string;\n\t/**\n\t * Maximum number of app directories the user may add in this session.\n\t * Derived from the workspace's remaining app entitlement (maxApps - appCount).\n\t * Undefined means unlimited.\n\t */\n\tmaxAppDirs?: number;\n}\n\nexport interface AppCreateParams {\n\tapi: VocoderAPI;\n\tuserToken: string;\n\tprojectId: string;\n\tprojectName: string;\n\torganizationName: string;\n\trepoCanonical?: string;\n\t/** Existing apps to display and validate against */\n\texistingApps: ExistingApp[];\n}\n\nexport interface AppCreateResult {\n\tprojectId: string;\n\tprojectName: string;\n\tappDir: string;\n\tappId: string;\n\tsourceLocale: string;\n\ttargetLocales: string[];\n\ttargetBranches: string[];\n}\n\nexport interface ProjectCreateResult {\n\tprojectId: string;\n\tprojectName: string;\n\t/** Project-scoped API key (vcp_) — one key covers all apps in this project. */\n\tapiKey: string;\n\tsourceLocale: string;\n\ttargetLocales: string[];\n\ttargetBranches: string[];\n\trepositoryBound: boolean;\n\tconfigureUrl?: string;\n\t/** One entry per created app, each with its own appId for vocoder.config.ts. */\n\tapps: Array<{ appDir: string; appId: string }>;\n}\n\n/** All locales — used for target language selection. */\nfunction buildLocaleOptions(\n\tlocales: Array<{ code: string; name: string; nativeName?: string }>,\n): LocaleOption[] {\n\treturn locales.map((l) => ({\n\t\tbcp47: l.code,\n\t\tlabel: `${l.name} — ${l.code}`,\n\t}));\n}\n\n/**\n * Deduplicated language list — used for source language selection.\n * Groups locales by language family (prefix before first hyphen) and keeps one\n * representative per family, preferring the shortest/base code (e.g. \"en\" over\n * \"en-US\"). This prevents showing \"English\", \"English (American)\", \"English\n * (British)\" as three separate choices when the user just means \"English\".\n */\nfunction buildLanguageOptions(\n\tlocales: Array<{ code: string; name: string; nativeName?: string }>,\n): LocaleOption[] {\n\tconst byFamily = new Map<string, LocaleOption>();\n\n\tfor (const l of locales) {\n\t\tconst family = l.code.split(\"-\")[0]!.toLowerCase();\n\t\tconst opt: LocaleOption = { bcp47: l.code, label: `${l.name} — ${l.code}` };\n\t\tconst existing = byFamily.get(family);\n\t\t// Prefer base code (shorter, no region suffix) over regional variants\n\t\tif (!existing || l.code.length < existing.bcp47.length) {\n\t\t\tbyFamily.set(family, opt);\n\t\t}\n\t}\n\n\treturn Array.from(byFamily.values());\n}\n\n/**\n * Run the full project configuration TUI: prompts for app directories, source locale,\n * target locales, and target branches, then calls POST /api/cli/apps.\n *\n * Returns the created project info (including project-scoped API key and per-app IDs),\n * or null if cancelled.\n */\nexport async function runProjectCreate(\n\tparams: ProjectCreateParams,\n): Promise<ProjectCreateResult | null> {\n\tconst { api, userToken, organizationId, repoCanonical, repoRoot } = params;\n\n\t// ── Project name ────────────────────────────────────────────────────────────\n\t// Use the detected repo name automatically — no prompt needed.\n\tconst projectName = (params.defaultName ?? \"my-project\").trim();\n\tp.log.success(`Project: ${chalk.bold(projectName)}`);\n\n\t// ── Fetch source locales ────────────────────────────────────────────────────\n\tlet sourceLocales: Array<{ code: string; name: string; nativeName?: string }>;\n\ttry {\n\t\t({ sourceLocales } = await api.listLocales(userToken));\n\t} catch {\n\t\tp.log.error(\n\t\t\t\"Failed to fetch supported locales. Check your connection and try again.\",\n\t\t);\n\t\treturn null;\n\t}\n\n\tconst languageOptions = buildLanguageOptions(sourceLocales);\n\n\t// ── App directories (monorepo support) ──────────────────────────────────────\n\tconst appDirs = await collectAppDirs({ cwd: repoRoot, maxDirs: params.maxAppDirs });\n\tif (appDirs === null) return null;\n\n\tif (appDirs.length > 0) {\n\t\tp.log.success(`App directories: ${appDirs.map((d) => chalk.bold(d)).join(\", \")}`);\n\t}\n\n\t// ── Source locale ───────────────────────────────────────────────────────────\n\tconst sourceLocale = await searchSelectLocale(\n\t\tlanguageOptions,\n\t\t\"Source language (the language your code is written in)\",\n\t\tparams.defaultSourceLocale ?? \"en\",\n\t);\n\n\tif (sourceLocale === null) return null;\n\n\t// ── Compatible target locales (fetched after source is known) ───────────────\n\tlet compatibleTargets: Array<{ code: string; name: string; nativeName?: string }>;\n\ttry {\n\t\tcompatibleTargets = await api.listCompatibleLocales(userToken, sourceLocale);\n\t} catch {\n\t\tp.log.error(\n\t\t\t\"Failed to fetch compatible target locales. Check your connection and try again.\",\n\t\t);\n\t\treturn null;\n\t}\n\n\tconst localeOptions = buildLocaleOptions(compatibleTargets);\n\n\t// ── Target locales ──────────────────────────────────────────────────────────\n\tconst targetOptions = localeOptions.filter(\n\t\t(opt) => opt.bcp47 !== sourceLocale,\n\t);\n\n\tconst targetLocales = await searchMultiSelectLocales(\n\t\ttargetOptions,\n\t\t\"Target languages (languages to translate into)\",\n\t);\n\n\tif (targetLocales === null) return null;\n\n\tif (targetLocales.length === 0) {\n\t\tp.log.warn(\n\t\t\t\"No target languages selected — you can add them later from the dashboard.\",\n\t\t);\n\t}\n\n\t// ── Branch triggers ─────────────────────────────────────────────────────────\n\tconst detected = detectGitBranches();\n\tconst initialBranches = params.defaultBranches?.length\n\t\t? params.defaultBranches\n\t\t: [detected.defaultBranch];\n\n\tlet pushBranches: string[] = [];\n\t{\n\t\tlet initial = initialBranches;\n\t\twhile (pushBranches.length === 0) {\n\t\t\tconst result = await filterableBranchSelect({\n\t\t\t\tmessage: \"Which branches should trigger translations?\",\n\t\t\t\tbranches: detected.branches,\n\t\t\t\tdefaultBranch: detected.defaultBranch,\n\t\t\t\tinitialValues: initial,\n\t\t\t});\n\t\t\tif (result === null) return null;\n\t\t\tif (result.length === 0) {\n\t\t\t\tp.log.warn(\n\t\t\t\t\t\"At least one branch is required. Please select at least one.\",\n\t\t\t\t);\n\t\t\t\tinitial = [detected.defaultBranch];\n\t\t\t} else {\n\t\t\t\tpushBranches = result;\n\t\t\t}\n\t\t}\n\t}\n\n\tconst targetBranches = pushBranches;\n\n\t// ── Create project ──────────────────────────────────────────────────────────\n\t// Errors (including plan limit errors) propagate to the caller so it can\n\t// decide whether to show an upgrade link or a generic error message.\n\tconst result = await api.createProject(userToken, {\n\t\torganizationId,\n\t\tname: projectName,\n\t\tsourceLocale,\n\t\ttargetLocales,\n\t\ttargetBranches,\n\t\tappDirs,\n\t\trepoCanonical,\n\t});\n\n\tp.log.success(`Project ${chalk.bold(result.projectName)} created!`);\n\treturn {\n\t\tprojectId: result.projectId,\n\t\tprojectName: result.projectName,\n\t\tapiKey: result.apiKey,\n\t\tsourceLocale,\n\t\ttargetLocales,\n\t\ttargetBranches,\n\t\trepositoryBound: result.repositoryBound,\n\t\tconfigureUrl: result.configureUrl,\n\t\tapps: result.apps,\n\t};\n}\n\n/**\n * Configure and create a new App under an existing project.\n * Used when the repo already has a project (monorepo: adding a new app directory).\n * No plan limit check runs — only a new App is created, not a new Project.\n */\nexport async function runAppCreate(\n\tparams: AppCreateParams,\n): Promise<AppCreateResult | null> {\n\tconst { api, userToken, projectId, projectName, repoCanonical } = params;\n\tconst existingDirs = params.existingApps.map((a) => a.appDir);\n\n\t// ── App directory ───────────────────────────────────────────────────────────\n\tconst appDir = await promptSingleAppDir({ existingDirs });\n\tif (appDir === null) return null;\n\tif (appDir) {\n\t\tp.log.success(`App directory: ${chalk.bold(appDir)}`);\n\t}\n\n\t// ── Fetch source locales ────────────────────────────────────────────────────\n\tlet sourceLocales: Array<{ code: string; name: string; nativeName?: string }>;\n\ttry {\n\t\t({ sourceLocales } = await api.listLocales(userToken));\n\t} catch {\n\t\tp.log.error(\n\t\t\t\"Failed to fetch supported locales. Check your connection and try again.\",\n\t\t);\n\t\treturn null;\n\t}\n\n\tconst languageOptions = buildLanguageOptions(sourceLocales);\n\n\t// ── Source locale ───────────────────────────────────────────────────────────\n\tconst sourceLocale = await searchSelectLocale(\n\t\tlanguageOptions,\n\t\t\"Source language\",\n\t\t\"en\",\n\t);\n\tif (sourceLocale === null) return null;\n\n\t// ── Compatible target locales (fetched after source is known) ───────────────\n\tlet compatibleTargets: Array<{ code: string; name: string; nativeName?: string }>;\n\ttry {\n\t\tcompatibleTargets = await api.listCompatibleLocales(userToken, sourceLocale);\n\t} catch {\n\t\tp.log.error(\n\t\t\t\"Failed to fetch compatible target locales. Check your connection and try again.\",\n\t\t);\n\t\treturn null;\n\t}\n\n\t// ── Target locales ──────────────────────────────────────────────────────────\n\tconst targetOptions = buildLocaleOptions(compatibleTargets).filter(\n\t\t(opt) => opt.bcp47 !== sourceLocale,\n\t);\n\tconst targetLocales = await searchMultiSelectLocales(\n\t\ttargetOptions,\n\t\t\"Target languages\",\n\t);\n\tif (targetLocales === null) return null;\n\tif (targetLocales.length === 0) {\n\t\tp.log.warn(\n\t\t\t\"No target languages selected — you can add them later from the dashboard.\",\n\t\t);\n\t}\n\n\t// ── Branch triggers ─────────────────────────────────────────────────────────\n\tconst detectedApp = detectGitBranches();\n\n\tlet appPushBranches: string[] = [];\n\t{\n\t\tlet initial = [detectedApp.defaultBranch];\n\t\twhile (appPushBranches.length === 0) {\n\t\t\tconst result = await filterableBranchSelect({\n\t\t\t\tmessage: \"Which branches should trigger translations?\",\n\t\t\t\tbranches: detectedApp.branches,\n\t\t\t\tdefaultBranch: detectedApp.defaultBranch,\n\t\t\t\tinitialValues: initial,\n\t\t\t});\n\t\t\tif (result === null) return null;\n\t\t\tif (result.length === 0) {\n\t\t\t\tp.log.warn(\"At least one branch is required.\");\n\t\t\t\tinitial = [detectedApp.defaultBranch];\n\t\t\t} else {\n\t\t\t\tappPushBranches = result;\n\t\t\t}\n\t\t}\n\t}\n\n\tconst targetBranches = appPushBranches;\n\n\t// ── Create the App ─────────────────────────────────────────────────────────\n\t// Errors propagate to the caller for consistent plan-limit / error handling.\n\tconst result = await api.createApp(userToken, {\n\t\tprojectId,\n\t\tappDir,\n\t\tsourceLocale,\n\t\ttargetLocales,\n\t\ttargetBranches,\n\t\trepoCanonical: repoCanonical ?? \"\",\n\t});\n\n\tp.log.success(\n\t\t`App ${chalk.bold(appDir || \"(root)\")} added to ${chalk.bold(projectName)}!`,\n\t);\n\treturn {\n\t\tprojectId: result.projectId,\n\t\tprojectName: result.projectName,\n\t\tappDir: result.appDir,\n\t\tappId: result.appId,\n\t\tsourceLocale,\n\t\ttargetLocales,\n\t\ttargetBranches,\n\t};\n}\n","import { existsSync, statSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport { isCancel, Prompt } from \"@clack/core\";\nimport * as p from \"@clack/prompts\";\nimport { active, bld, dim, grn, info, red, ylw } from \"./theme.js\";\n\n// ── Symbols ───────────────────────────────────────────────────────────────────\n\nconst S_BAR = \"│\";\nconst S_BAR_END = \"└\";\nconst S_ACTIVE = \"◆\";\nconst S_SUBMIT = \"◆\";\nconst S_CANCEL = \"■\";\nconst S_ERROR = \"▲\";\n\nfunction symbol(state: string): string {\n\tswitch (state) {\n\t\tcase \"submit\":\n\t\t\treturn grn(S_SUBMIT);\n\t\tcase \"cancel\":\n\t\t\treturn red(S_CANCEL);\n\t\tcase \"error\":\n\t\t\treturn ylw(S_ERROR);\n\t\tdefault:\n\t\t\treturn active(S_ACTIVE);\n\t}\n}\n\n// ── Validation ────────────────────────────────────────────────────────────────\n\n/**\n * Validate an app directory path. Returns an error string or null if valid.\n * Checks path safety, mutual exclusion invariant, and filesystem existence.\n */\nexport function validateAppDirPath(\n\tval: string,\n\texisting: string[],\n\topts: { cwd?: string } = {},\n): string | null {\n\tif (val.startsWith(\"/\")) return \"Must be a relative path (e.g. apps/web)\";\n\tif (val.includes(\"..\")) return \"Path traversal not allowed\";\n\n\tconst hasWholeRepo = existing.includes(\"\");\n\tconst hasScoped = existing.some((d) => d !== \"\");\n\tif (val === \"\" && hasScoped) return \"Cannot add whole-repo scope to a monorepo project\";\n\tif (val !== \"\" && hasWholeRepo) return \"Cannot add a scoped directory to a whole-repo project\";\n\tif (existing.includes(val)) return `Already added: ${val}`;\n\n\t// Reject nested paths — e.g. adding \"apps\" when \"apps/vite\" already exists (or vice versa)\n\tconst nested = existing.find(\n\t\t(d) => d !== \"\" && (val.startsWith(d + \"/\") || d.startsWith(val + \"/\")),\n\t);\n\tif (nested) return `\"${val}\" overlaps with already-added \"${nested}\"`;\n\n\tif (val !== \"\") {\n\t\tconst abs = resolve(opts.cwd ?? process.cwd(), val);\n\t\tif (!existsSync(abs)) return `Directory not found: ${val}`;\n\t\tif (!statSync(abs).isDirectory()) return `Not a directory: ${val}`;\n\t}\n\n\treturn null;\n}\n\n// ── collectAppDirs ────────────────────────────────────────────────────────────\n\n/**\n * Interactively collect app directory paths from the user for monorepo projects.\n *\n * Type a path → press Space to add it. Navigate ↑↓ to existing dirs and press\n * Space to remove. Press Enter when done. An empty submission (no dirs added)\n * means single-app / whole-repo project.\n *\n * @param opts.maxDirs - Maximum directories the user may add. When reached the\n * Space key is blocked and the render shows \"App limit reached (N/N on your\n * plan)\" in place of the add affordance. The server also enforces this limit\n * on creation — this is a UX-level guard to surface the constraint early.\n *\n * Returns the collected directories, or null if the user cancels.\n */\nexport async function collectAppDirs(opts: { cwd?: string; maxDirs?: number } = {}): Promise<string[] | null> {\n\tconst added: string[] = [];\n\tlet filter = \"\";\n\tlet cursor = 0;\n\tlet addCursor = false;\n\n\tconst isNewDir = () => {\n\t\tconst t = filter.trim();\n\t\treturn t.length > 0 && !added.includes(t);\n\t};\n\n\tconst clampCursor = () => {\n\t\tconst max = added.length - 1;\n\t\tif (cursor > max) cursor = Math.max(0, max);\n\t};\n\n\tconst prompt = new (Prompt as any)(\n\t\t{\n\t\t\tvalidate() {\n\t\t\t\treturn undefined;\n\t\t\t},\n\t\t\trender(this: { state: string; error: string }) {\n\t\t\t\tconst trimmed = filter.trim();\n\t\t\t\tconst hdr = `${dim(S_BAR)}\\n${symbol(this.state)} App directories\\n`;\n\n\t\t\t\tswitch (this.state) {\n\t\t\t\t\tcase \"submit\": {\n\t\t\t\t\t\tconst summary =\n\t\t\t\t\t\t\tadded.length > 0\n\t\t\t\t\t\t\t\t? bld(added.join(\", \"))\n\t\t\t\t\t\t\t\t: dim(\"none (single-app project)\");\n\t\t\t\t\t\treturn `${hdr}${dim(S_BAR)} ${summary}`;\n\t\t\t\t\t}\n\t\t\t\t\tcase \"cancel\":\n\t\t\t\t\t\treturn `${hdr}${dim(S_BAR)}`;\n\t\t\t\t\tdefault: {\n\t\t\t\t\t\tconst inputHint =\n\t\t\t\t\t\t\tfilter.length > 0\n\t\t\t\t\t\t\t\t? filter\n\t\t\t\t\t\t\t\t: added.length === 0\n\t\t\t\t\t\t\t\t\t? dim(\"e.g. apps/web\")\n\t\t\t\t\t\t\t\t\t: dim(\"e.g. apps/api\");\n\n\t\t\t\t\t\tconst lines: string[] = [\n\t\t\t\t\t\t\thdr.trimEnd(),\n\t\t\t\t\t\t\t`${info(S_BAR)} ${dim(\"/\")} ${inputHint}`,\n\t\t\t\t\t\t\tinfo(S_BAR),\n\t\t\t\t\t\t];\n\n\t\t\t\t\t\tfor (let i = 0; i < added.length; i++) {\n\t\t\t\t\t\t\tconst isCursor = i === cursor && !addCursor;\n\t\t\t\t\t\t\tconst icon = active(\"◼\");\n\t\t\t\t\t\t\tconst label = isCursor ? bld(added[i]!) : added[i]!;\n\t\t\t\t\t\t\tlines.push(`${info(S_BAR)} ${icon} ${label}`);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst atLimit = opts.maxDirs !== undefined && added.length >= opts.maxDirs;\n\t\t\t\t\t\tif (atLimit) {\n\t\t\t\t\t\t\tlines.push(`${info(S_BAR)} ${dim(`App limit reached (${added.length}/${opts.maxDirs} on your plan)`)}`);\n\t\t\t\t\t\t} else if (isNewDir()) {\n\t\t\t\t\t\t\tconst err = validateAppDirPath(trimmed, added, opts);\n\t\t\t\t\t\t\tconst icon = addCursor ? active(\"◻\") : dim(\"◻\");\n\t\t\t\t\t\t\tconst label = err\n\t\t\t\t\t\t\t\t? `${ylw(\"+\")} ${dim(`\"${trimmed}\" — ${err}`)}`\n\t\t\t\t\t\t\t\t: `${grn(\"+\")} Add \"${trimmed}\"`;\n\t\t\t\t\t\t\tlines.push(`${info(S_BAR)} ${icon} ${label}`);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tlines.push(info(S_BAR));\n\n\t\t\t\t\t\tif (atLimit) {\n\t\t\t\t\t\t\tlines.push(dim(`${S_BAR} ↑↓ to select, Space to remove · Enter to confirm`));\n\t\t\t\t\t\t} else if (added.length === 0 && !isNewDir()) {\n\t\t\t\t\t\t\tlines.push(dim(`${S_BAR} Monorepo? Type each app's subdirectory path and press Space.`));\n\t\t\t\t\t\t\tlines.push(dim(`${S_BAR} Single app? Press Enter to skip this step.`));\n\t\t\t\t\t\t} else if (added.length > 0) {\n\t\t\t\t\t\t\tlines.push(dim(`${S_BAR} ${added.length} added · ↑↓ to select, Space to remove · Enter to confirm`));\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst barEnd =\n\t\t\t\t\t\t\tthis.state === \"error\" ? ylw(S_BAR_END) : info(S_BAR_END);\n\t\t\t\t\t\tif (this.state === \"error\") {\n\t\t\t\t\t\t\tlines.push(`${ylw(S_BAR_END)} ${ylw(this.error)}`);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tlines.push(barEnd);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tlines.push(\"\");\n\t\t\t\t\t\treturn lines.join(\"\\n\");\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t\tfalse,\n\t) as InstanceType<typeof Prompt> & { value: unknown; state: string };\n\n\tprompt.on(\"key\", (key: string | undefined) => {\n\t\tif (!key || key === \" \") return;\n\t\tconst cp = key.codePointAt(0) ?? 0;\n\t\tif (cp === 0x7f || cp === 0x08) {\n\t\t\tfilter = filter.slice(0, -1);\n\t\t\taddCursor = false;\n\t\t} else if (cp >= 32 && cp !== 127) {\n\t\t\tfilter += key;\n\t\t\tcursor = 0;\n\t\t\taddCursor = false;\n\t\t}\n\t});\n\n\tprompt.on(\"cursor\", (action: string | undefined) => {\n\t\tswitch (action) {\n\t\t\tcase \"up\":\n\t\t\t\tif (addCursor) {\n\t\t\t\t\taddCursor = false;\n\t\t\t\t\tcursor = Math.max(0, added.length - 1);\n\t\t\t\t} else {\n\t\t\t\t\tcursor = Math.max(0, cursor - 1);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase \"down\":\n\t\t\t\tif (!addCursor && cursor >= added.length - 1 && isNewDir()) {\n\t\t\t\t\taddCursor = true;\n\t\t\t\t} else if (!addCursor) {\n\t\t\t\t\tcursor = Math.min(added.length - 1, cursor + 1);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase \"space\": {\n\t\t\t\tif (addCursor || (filter.trim().length > 0 && isNewDir())) {\n\t\t\t\t\tif (opts.maxDirs !== undefined && added.length >= opts.maxDirs) break;\n\t\t\t\t\tconst trimmed = filter.trim();\n\t\t\t\t\tconst err = validateAppDirPath(trimmed, added, opts);\n\t\t\t\t\tif (!err) {\n\t\t\t\t\t\tadded.push(trimmed);\n\t\t\t\t\t\tfilter = \"\";\n\t\t\t\t\t\taddCursor = false;\n\t\t\t\t\t\tcursor = 0;\n\t\t\t\t\t}\n\t\t\t\t} else if (added.length > 0 && !isNewDir()) {\n\t\t\t\t\tclampCursor();\n\t\t\t\t\tadded.splice(cursor, 1);\n\t\t\t\t\tif (cursor >= added.length) cursor = Math.max(0, added.length - 1);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t});\n\n\tprompt.on(\"finalize\", () => {\n\t\tif ((prompt as any).state === \"submit\") {\n\t\t\t(prompt as any).value = [...added];\n\t\t}\n\t});\n\n\tconst result = await prompt.prompt();\n\tif (isCancel(result)) return null;\n\treturn result as string[];\n}\n\n// ── promptSingleAppDir ────────────────────────────────────────────────────────\n\n/**\n * Prompt the user for a single app directory to add to an existing project.\n *\n * Validates path safety, filesystem existence, and the monorepo/whole-repo\n * mutual exclusion invariant against the provided existing directories.\n *\n * Returns the entered directory string, or null if the user cancels.\n */\nexport async function promptSingleAppDir(params: {\n\texistingDirs: string[];\n\tcwd?: string;\n}): Promise<string | null> {\n\tconst { existingDirs, cwd } = params;\n\n\tconst input = await p.text({\n\t\tmessage: \"App directory to add\",\n\t\tplaceholder: \"apps/web\",\n\t\tvalidate(val) {\n\t\t\t// Mutual exclusion checked before required — empty string is a valid whole-repo intent\n\t\t\tconst err = validateAppDirPath(val ?? \"\", existingDirs, { cwd });\n\t\t\tif (err) return err;\n\t\t\tif (!val) return \"Directory is required\";\n\t\t\treturn undefined;\n\t\t},\n\t});\n\n\tif (p.isCancel(input)) return null;\n\treturn input as string;\n}\n","import { execSync } from \"node:child_process\";\nimport { isCancel, Prompt } from \"@clack/core\";\nimport { active, bld, dim, grn, info, red, ylw } from \"./theme.js\";\n\n// ── Symbols ───────────────────────────────────────────────────────────────────\n\nconst S_BAR = \"│\";\nconst S_BAR_END = \"└\";\nconst S_ACTIVE = \"◆\";\nconst S_SUBMIT = \"◆\";\nconst S_CANCEL = \"■\";\nconst S_ERROR = \"▲\";\n\nfunction symbol(state: string): string {\n\tswitch (state) {\n\t\tcase \"submit\":\n\t\t\treturn grn(S_SUBMIT);\n\t\tcase \"cancel\":\n\t\t\treturn red(S_CANCEL);\n\t\tcase \"error\":\n\t\t\treturn ylw(S_ERROR);\n\t\tdefault:\n\t\t\treturn active(S_ACTIVE);\n\t}\n}\n\n// ── Git detection ─────────────────────────────────────────────────────────────\n\nexport interface DetectedBranches {\n\tbranches: string[];\n\tdefaultBranch: string;\n}\n\nexport function detectGitBranches(cwd?: string): DetectedBranches {\n\tconst workDir = cwd ?? process.cwd();\n\ttry {\n\t\t// Local branches\n\t\tconst localOut = execSync(\"git branch\", {\n\t\t\tcwd: workDir,\n\t\t\tstdio: \"pipe\",\n\t\t}).toString();\n\t\tconst localBranches = localOut\n\t\t\t.split(\"\\n\")\n\t\t\t.filter(Boolean)\n\t\t\t.map((b) => b.replace(/^\\*?\\s*/, \"\").trim())\n\t\t\t.filter(Boolean);\n\n\t\t// Remote branches (strip \"origin/\" prefix, skip HEAD pointer)\n\t\tlet remoteBranches: string[] = [];\n\t\ttry {\n\t\t\tconst remoteOut = execSync(\"git branch -r\", {\n\t\t\t\tcwd: workDir,\n\t\t\t\tstdio: \"pipe\",\n\t\t\t}).toString();\n\t\t\tremoteBranches = remoteOut\n\t\t\t\t.split(\"\\n\")\n\t\t\t\t.map((b) => b.trim())\n\t\t\t\t.filter((b) => b && !b.includes(\"HEAD\"))\n\t\t\t\t.map((b) => b.replace(/^[^/]+\\//, \"\")); // strip \"origin/\" (or any remote name)\n\t\t} catch {\n\t\t\t/* no remote */\n\t\t}\n\n\t\tconst branches = [...new Set([...localBranches, ...remoteBranches])].sort();\n\n\t\t// Default branch: ask git for origin's HEAD (local cache, no network call).\n\t\t// Falls back to 'main' if the remote HEAD isn't cached.\n\t\tlet defaultBranch = \"main\";\n\t\ttry {\n\t\t\tconst ref = execSync(\"git symbolic-ref refs/remotes/origin/HEAD\", {\n\t\t\t\tcwd: workDir,\n\t\t\t\tstdio: \"pipe\",\n\t\t\t})\n\t\t\t\t.toString()\n\t\t\t\t.trim();\n\t\t\t// ref = \"refs/remotes/origin/main\"\n\t\t\tdefaultBranch = ref.split(\"/\").pop() ?? \"main\";\n\t\t} catch {\n\t\t\t/* HEAD not cached — run \"git remote set-head origin --auto\" to fix */\n\t\t}\n\n\t\treturn {\n\t\t\tbranches: branches.length > 0 ? branches : [defaultBranch],\n\t\t\tdefaultBranch,\n\t\t};\n\t} catch {\n\t\treturn { branches: [\"main\"], defaultBranch: \"main\" };\n\t}\n}\n\n// ── Validation ────────────────────────────────────────────────────────────────\n\nconst INVALID_CHARS = /[\\s?^~:[\\]\\\\]/;\n\nexport function validateBranchPattern(pattern: string): string | null {\n\tconst t = pattern.trim();\n\tif (!t) return \"Pattern cannot be empty\";\n\tif (INVALID_CHARS.test(t))\n\t\treturn \"Invalid characters — avoid spaces, ?, ^, ~, :, [, ], \\\\\";\n\tif (t.startsWith(\"/\") || t.endsWith(\"/\")) return \"Cannot start or end with /\";\n\tif (t.includes(\"//\")) return \"Cannot contain //\";\n\treturn null;\n}\n\n// ── List renderer ─────────────────────────────────────────────────────────────\n\nconst MAX_VISIBLE = 10;\nconst _ADD_PATTERN_VALUE = \"__add__\";\n\ninterface BranchItem {\n\tvalue: string;\n\tlabel: string;\n\tisCustom?: boolean;\n}\n\nfunction buildItems(\n\tbranches: string[],\n\tdefaultBranch: string,\n\tcustomPatterns: string[],\n): BranchItem[] {\n\tconst items: BranchItem[] = branches.map((b) => ({\n\t\tvalue: b,\n\t\tlabel: b === defaultBranch ? `${b} (default branch)` : b,\n\t}));\n\tfor (const pt of customPatterns) {\n\t\tif (!branches.includes(pt)) {\n\t\t\titems.push({ value: pt, label: pt, isCustom: true });\n\t\t}\n\t}\n\treturn items;\n}\n\nfunction filterItems(items: BranchItem[], query: string): BranchItem[] {\n\tif (!query.trim()) return items;\n\tconst lower = query.toLowerCase();\n\treturn items.filter((i) => i.value.toLowerCase().includes(lower));\n}\n\nfunction buildList(\n\tfiltered: BranchItem[],\n\tcursor: number,\n\tscrollOffset: number,\n\tselected: Set<string>,\n\tfilter: string,\n\tcustomPatterns: string[],\n\taddCursor: boolean,\n\texcludedPatterns: Set<string> = new Set(),\n): string {\n\tconst lines: string[] = [info(S_BAR)];\n\tconst end = Math.min(filtered.length, scrollOffset + MAX_VISIBLE);\n\n\tfor (let i = scrollOffset; i < end; i++) {\n\t\tconst item = filtered[i]!;\n\t\tconst isCursor = i === cursor && !addCursor;\n\t\tconst isChecked = selected.has(item.value);\n\n\t\tconst icon = isChecked\n\t\t\t? active(\"◼\")\n\t\t\t: isCursor\n\t\t\t\t? active(\"◻\")\n\t\t\t\t: dim(\"◻\");\n\n\t\tlet label = item.isCustom ? `${item.label} ${dim(\"(custom)\")}` : item.label;\n\t\tif (isCursor) label = bld(label);\n\n\t\tlines.push(`${info(S_BAR)} ${icon} ${label}`);\n\t}\n\n\t// \"Add pattern\" option\n\tconst trimmed = filter.trim();\n\tconst isNewPattern =\n\t\ttrimmed.length > 0 &&\n\t\t!filtered.some((i) => i.value === trimmed) &&\n\t\t!customPatterns.includes(trimmed);\n\n\tif (isNewPattern) {\n\t\tconst err =\n\t\t\tvalidateBranchPattern(trimmed) ??\n\t\t\t(excludedPatterns.has(trimmed)\n\t\t\t\t? \"Already used for automatic translation\"\n\t\t\t\t: null);\n\t\tconst icon = addCursor ? active(\"◻\") : dim(\"◻\");\n\t\tconst label = err\n\t\t\t? `${ylw(\"+\")} ${dim(`\"${trimmed}\" — ${err}`)}`\n\t\t\t: `${grn(\"+\")} Add \"${trimmed}\" as branch pattern`;\n\t\tlines.push(`${info(S_BAR)} ${icon} ${label}`);\n\t} else if (filtered.length === 0 && trimmed.length === 0) {\n\t\tlines.push(dim(`${S_BAR} No branches detected`));\n\t}\n\n\tconst hidden = filtered.length - (end - scrollOffset);\n\tif (hidden > 0) lines.push(dim(`${S_BAR} ${hidden} more — keep typing to narrow`));\n\n\treturn lines.join(\"\\n\");\n}\n\n// ── Component ─────────────────────────────────────────────────────────────────\n\nexport async function filterableBranchSelect(params: {\n\tmessage: string;\n\tbranches: string[];\n\tdefaultBranch: string;\n\tinitialValues?: string[];\n\t/** When true, empty selection is accepted (Enter = skip) */\n\toptional?: boolean;\n\t/** Branches already claimed by other trigger types — block custom entry of these */\n\texcludedPatterns?: string[];\n}): Promise<string[] | null> {\n\tconst { message, branches, defaultBranch } = params;\n\tconst optional = params.optional ?? false;\n\tconst excludedSet = new Set(params.excludedPatterns ?? []);\n\n\tlet filter = \"\";\n\tlet cursor = 0;\n\tlet scrollOffset = 0;\n\tlet addCursor = false;\n\tconst customPatterns: string[] = [];\n\tconst selected = new Set<string>(params.initialValues ?? [defaultBranch]);\n\n\tconst getItems = () => buildItems(branches, defaultBranch, customPatterns);\n\tconst getFiltered = () => filterItems(getItems(), filter);\n\n\tconst isNewPattern = () => {\n\t\tconst t = filter.trim();\n\t\tif (!t) return false;\n\t\treturn (\n\t\t\t!getItems().some((i) => i.value === t) && !customPatterns.includes(t)\n\t\t);\n\t};\n\n\tconst clampCursor = (filtered: BranchItem[]) => {\n\t\tconst hasAdd = isNewPattern();\n\t\tconst max = filtered.length - 1 + (hasAdd ? 1 : 0);\n\t\tif (cursor > max && !addCursor) cursor = Math.max(0, max);\n\t\tif (!addCursor) {\n\t\t\tif (cursor < scrollOffset) scrollOffset = cursor;\n\t\t\tif (cursor >= scrollOffset + MAX_VISIBLE)\n\t\t\t\tscrollOffset = cursor - MAX_VISIBLE + 1;\n\t\t\tif (scrollOffset < 0) scrollOffset = 0;\n\t\t}\n\t};\n\n\tconst prompt = new (Prompt as any)(\n\t\t{\n\t\t\tvalidate() {\n\t\t\t\tif (!optional && selected.size === 0)\n\t\t\t\t\treturn \"At least one branch is required.\";\n\t\t\t\treturn undefined;\n\t\t\t},\n\t\t\trender(this: { state: string; error: string }) {\n\t\t\t\tconst filtered = getFiltered();\n\t\t\t\tclampCursor(filtered);\n\n\t\t\t\tconst hdr = `${dim(S_BAR)}\\n${symbol(this.state)} ${message}\\n`;\n\t\t\t\tconst inputHint =\n\t\t\t\t\tfilter.length > 0\n\t\t\t\t\t\t? filter\n\t\t\t\t\t\t: dim(\"type to filter · type a custom pattern to add it\");\n\n\t\t\t\tconst trimmedFilter = filter.trim();\n\t\t\t\tconst footer = (() => {\n\t\t\t\t\tif (trimmedFilter.length > 0 && isNewPattern()) {\n\t\t\t\t\t\treturn dim(`${S_BAR} Space to add \"${trimmedFilter}\" · ↑↓ navigate · Enter to confirm`);\n\t\t\t\t\t}\n\t\t\t\t\tif (selected.size > 0) {\n\t\t\t\t\t\treturn dim(`${S_BAR} ${selected.size} selected · ↑↓ navigate · Space to select · Enter to confirm`);\n\t\t\t\t\t}\n\t\t\t\t\treturn optional\n\t\t\t\t\t\t? dim(`${S_BAR} ↑↓ navigate · Space to select · Enter to skip`)\n\t\t\t\t\t\t: dim(`${S_BAR} ↑↓ navigate · Space to select · Enter to confirm`);\n\t\t\t\t})();\n\n\t\t\t\tswitch (this.state) {\n\t\t\t\t\tcase \"submit\": {\n\t\t\t\t\t\tconst summary =\n\t\t\t\t\t\t\tselected.size > 0\n\t\t\t\t\t\t\t\t? bld(Array.from(selected).join(\", \"))\n\t\t\t\t\t\t\t\t: dim(\"none\");\n\t\t\t\t\t\treturn `${hdr}${dim(S_BAR)} ${summary}`;\n\t\t\t\t\t}\n\t\t\t\t\tcase \"cancel\":\n\t\t\t\t\t\treturn `${hdr}${dim(S_BAR)}`;\n\t\t\t\t\tcase \"error\":\n\t\t\t\t\t\treturn [\n\t\t\t\t\t\t\thdr.trimEnd(),\n\t\t\t\t\t\t\t`${ylw(S_BAR)} ${dim(\"/\")} ${inputHint}`,\n\t\t\t\t\t\t\tbuildList(filtered, cursor, scrollOffset, selected, filter, customPatterns, addCursor, excludedSet),\n\t\t\t\t\t\t\tfooter,\n\t\t\t\t\t\t\t`${ylw(S_BAR_END)} ${ylw(this.error)}`,\n\t\t\t\t\t\t\t\"\",\n\t\t\t\t\t\t].join(\"\\n\");\n\t\t\t\t\tdefault:\n\t\t\t\t\t\treturn [\n\t\t\t\t\t\t\thdr.trimEnd(),\n\t\t\t\t\t\t\t`${info(S_BAR)} ${dim(\"/\")} ${inputHint}`,\n\t\t\t\t\t\t\tbuildList(filtered, cursor, scrollOffset, selected, filter, customPatterns, addCursor, excludedSet),\n\t\t\t\t\t\t\tfooter,\n\t\t\t\t\t\t\t`${info(S_BAR_END)}`,\n\t\t\t\t\t\t\t\"\",\n\t\t\t\t\t\t].join(\"\\n\");\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t\tfalse,\n\t) as InstanceType<typeof Prompt> & { value: unknown; state: string };\n\n\tprompt.on(\"key\", (key: string | undefined) => {\n\t\tif (!key || key === \" \") return;\n\t\tconst cp = key.codePointAt(0) ?? 0;\n\t\tif (cp === 0x7f || cp === 0x08) {\n\t\t\tfilter = filter.slice(0, -1);\n\t\t\tcursor = 0;\n\t\t\tscrollOffset = 0;\n\t\t\taddCursor = false;\n\t\t} else if (cp >= 32 && cp !== 127) {\n\t\t\tfilter += key;\n\t\t\tcursor = 0;\n\t\t\tscrollOffset = 0;\n\t\t\taddCursor = false;\n\t\t}\n\t\t// Auto-focus the \"+\" row as soon as typed text diverges from all existing branches\n\t\tif (isNewPattern()) {\n\t\t\taddCursor = true;\n\t\t}\n\t});\n\n\tprompt.on(\"cursor\", (action: string | undefined) => {\n\t\tconst filtered = getFiltered();\n\t\tconst hasAdd = isNewPattern();\n\n\t\tswitch (action) {\n\t\t\tcase \"up\":\n\t\t\t\tif (addCursor) {\n\t\t\t\t\taddCursor = false;\n\t\t\t\t\tcursor = Math.max(0, filtered.length - 1);\n\t\t\t\t} else cursor = Math.max(0, cursor - 1);\n\t\t\t\tbreak;\n\t\t\tcase \"down\":\n\t\t\t\tif (!addCursor && cursor >= filtered.length - 1 && hasAdd)\n\t\t\t\t\taddCursor = true;\n\t\t\t\telse if (!addCursor) cursor = Math.min(filtered.length - 1, cursor + 1);\n\t\t\t\tbreak;\n\t\t\tcase \"space\": {\n\t\t\t\tconst t = filter.trim();\n\t\t\t\tif (addCursor || (t.length > 0 && isNewPattern())) {\n\t\t\t\t\tconst err =\n\t\t\t\t\t\tvalidateBranchPattern(t) ??\n\t\t\t\t\t\t(excludedSet.has(t)\n\t\t\t\t\t\t\t? \"Already used for automatic translation\"\n\t\t\t\t\t\t\t: null);\n\t\t\t\t\tif (!err) {\n\t\t\t\t\t\tcustomPatterns.push(t);\n\t\t\t\t\t\tselected.add(t);\n\t\t\t\t\t\tfilter = \"\";\n\t\t\t\t\t\tcursor = 0;\n\t\t\t\t\t\tscrollOffset = 0;\n\t\t\t\t\t\taddCursor = false;\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tconst item = filtered[cursor];\n\t\t\t\t\tif (item) {\n\t\t\t\t\t\tif (selected.has(item.value)) selected.delete(item.value);\n\t\t\t\t\t\telse selected.add(item.value);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t});\n\n\tprompt.on(\"finalize\", () => {\n\t\tif ((prompt as any).state === \"submit\") {\n\t\t\t(prompt as any).value = Array.from(selected);\n\t\t}\n\t});\n\n\tconst result = await prompt.prompt();\n\tif (isCancel(result)) return null;\n\treturn result as unknown as string[];\n}\n","import { isCancel, Prompt } from \"@clack/core\";\nimport * as p from \"@clack/prompts\";\nimport { active, bld, dim, grn, info, red, ylw } from \"./theme.js\";\n\nexport interface LocaleOption {\n\tbcp47: string;\n\t/** Human-readable label, e.g. \"English — en\" */\n\tlabel: string;\n}\n\n// ── Symbols (match @clack/prompts style) ──────────────────────────────────────\n\nconst S_BAR = \"│\";\nconst S_BAR_END = \"└\";\nconst S_ACTIVE = \"◆\";\nconst S_SUBMIT = \"◆\";\nconst S_CANCEL = \"■\";\nconst S_ERROR = \"▲\";\n\nfunction symbol(state: string): string {\n\tswitch (state) {\n\t\tcase \"submit\":\n\t\t\treturn grn(S_SUBMIT);\n\t\tcase \"cancel\":\n\t\t\treturn red(S_CANCEL);\n\t\tcase \"error\":\n\t\t\treturn ylw(S_ERROR);\n\t\tdefault:\n\t\t\treturn active(S_ACTIVE);\n\t}\n}\n\n// ── Filter ────────────────────────────────────────────────────────────────────\n\nconst MAX_VISIBLE = 12;\n\nfunction filterLocales(options: LocaleOption[], query: string): LocaleOption[] {\n\tif (!query.trim()) return options;\n\tconst lower = query.toLowerCase();\n\treturn options.filter(\n\t\t(o) =>\n\t\t\to.bcp47.toLowerCase().includes(lower) ||\n\t\t\to.label.toLowerCase().includes(lower),\n\t);\n}\n\n// ── List renderer ─────────────────────────────────────────────────────────────\n\nfunction buildList(\n\tfiltered: LocaleOption[],\n\tcursor: number,\n\tscrollOffset: number,\n\tselected: Set<string> | null, // null = single-select\n): string {\n\tconst isMulti = selected !== null;\n\tconst end = Math.min(filtered.length, scrollOffset + MAX_VISIBLE);\n\tconst visibleLines: string[] = [info(S_BAR)];\n\n\tfor (let i = scrollOffset; i < end; i++) {\n\t\tconst opt = filtered[i]!;\n\t\tconst isCursor = i === cursor;\n\t\tconst isChecked = isMulti && selected!.has(opt.bcp47);\n\n\t\tconst icon = isMulti\n\t\t\t? isChecked\n\t\t\t\t? active(\"◼\")\n\t\t\t\t: isCursor\n\t\t\t\t\t? active(\"◻\")\n\t\t\t\t\t: dim(\"◻\")\n\t\t\t: isCursor\n\t\t\t\t? active(\"●\")\n\t\t\t\t: dim(\"○\");\n\n\t\tvisibleLines.push(\n\t\t\t`${info(S_BAR)} ${icon} ${isCursor ? bld(opt.label) : opt.label}`,\n\t\t);\n\t}\n\n\tconst hidden = filtered.length - (end - scrollOffset);\n\tif (hidden > 0) visibleLines.push(dim(`${S_BAR} ${hidden} more — keep typing to narrow`));\n\tif (filtered.length === 0) visibleLines.push(dim(`${S_BAR} No matches`));\n\n\treturn visibleLines.join(\"\\n\");\n}\n\n// ── Core prompt factory ───────────────────────────────────────────────────────\n\nasync function runFilterablePrompt(opts: {\n\tmessage: string;\n\toptions: LocaleOption[];\n\tmulti: boolean;\n\tinitialValue?: string;\n\tinitialValues?: string[];\n}): Promise<string | string[] | null> {\n\tconst { message, options, multi } = opts;\n\n\tlet filter = \"\";\n\tlet cursor = 0;\n\tlet scrollOffset = 0;\n\tconst selected = new Set<string>(multi ? (opts.initialValues ?? []) : []);\n\n\tif (!multi && opts.initialValue) {\n\t\tconst idx = options.findIndex((o) => o.bcp47 === opts.initialValue);\n\t\tif (idx >= 0) cursor = idx;\n\t}\n\n\tconst getFiltered = () => filterLocales(options, filter);\n\n\t// Keep cursor in bounds and scroll window centred\n\tconst clampCursor = (filtered: LocaleOption[]) => {\n\t\tif (cursor >= filtered.length) cursor = Math.max(0, filtered.length - 1);\n\t\tif (cursor < scrollOffset) scrollOffset = cursor;\n\t\tif (cursor >= scrollOffset + MAX_VISIBLE)\n\t\t\tscrollOffset = cursor - MAX_VISIBLE + 1;\n\t\tif (scrollOffset < 0) scrollOffset = 0;\n\t};\n\n\t// @clack/core Prompt: render() returns the ENTIRE frame; clack handles\n\t// re-rendering (cursor movement + diff) automatically.\n\t// Using `any` cast to pass `trackValue=false` (2nd constructor arg).\n\tconst prompt = new (Prompt as any)(\n\t\t{\n\t\t\tinitialValue: !multi ? (options[cursor]?.bcp47 ?? null) : null,\n\t\t\tvalidate() {\n\t\t\t\tconst f = getFiltered();\n\t\t\t\tif (multi && selected.size === 0)\n\t\t\t\t\treturn \"At least one target language is required.\";\n\t\t\t\tif (!multi && !f[cursor]) return \"Please select a language.\";\n\t\t\t\treturn undefined;\n\t\t\t},\n\t\t\trender(this: { state: string; error: string; value: unknown }) {\n\t\t\t\tconst filtered = getFiltered();\n\t\t\t\tclampCursor(filtered);\n\n\t\t\t\tconst hdr = `${dim(S_BAR)}\\n${symbol(this.state)} ${message}\\n`;\n\t\t\t\tconst inputHint = filter.length > 0 ? filter : dim(\"type to filter\");\n\n\t\t\t\tconst footer = multi\n\t\t\t\t\t? selected.size > 0\n\t\t\t\t\t\t? dim(`${S_BAR} ${selected.size} selected · ↑↓ navigate · Space to select · Enter to confirm`)\n\t\t\t\t\t\t: dim(`${S_BAR} ↑↓ navigate · Space to select · Enter to confirm`)\n\t\t\t\t\t: dim(`${S_BAR} ↑↓ navigate · Enter to confirm`);\n\n\t\t\t\tswitch (this.state) {\n\t\t\t\t\tcase \"submit\": {\n\t\t\t\t\t\tconst val = multi\n\t\t\t\t\t\t\t? Array.from(selected)\n\t\t\t\t\t\t\t\t\t.map((id) => options.find((o) => o.bcp47 === id)?.label ?? id)\n\t\t\t\t\t\t\t\t\t.join(\", \")\n\t\t\t\t\t\t\t: (options.find((o) => o.bcp47 === (this.value as string))\n\t\t\t\t\t\t\t\t\t?.label ?? \"\");\n\t\t\t\t\t\treturn `${hdr}${dim(S_BAR)} ${bld(val || dim(\"none\"))}`;\n\t\t\t\t\t}\n\t\t\t\t\tcase \"cancel\":\n\t\t\t\t\t\treturn `${hdr}${dim(S_BAR)}`;\n\t\t\t\t\tcase \"error\":\n\t\t\t\t\t\treturn [\n\t\t\t\t\t\t\thdr.trimEnd(),\n\t\t\t\t\t\t\t`${ylw(S_BAR)} ${dim(\"/\")} ${inputHint}`,\n\t\t\t\t\t\t\tbuildList(filtered, cursor, scrollOffset, multi ? selected : null),\n\t\t\t\t\t\t\tfooter,\n\t\t\t\t\t\t\t`${ylw(S_BAR_END)} ${ylw(this.error)}`,\n\t\t\t\t\t\t\t\"\",\n\t\t\t\t\t\t].join(\"\\n\");\n\t\t\t\t\tdefault:\n\t\t\t\t\t\treturn [\n\t\t\t\t\t\t\thdr.trimEnd(),\n\t\t\t\t\t\t\t`${info(S_BAR)} ${dim(\"/\")} ${inputHint}`,\n\t\t\t\t\t\t\tbuildList(filtered, cursor, scrollOffset, multi ? selected : null),\n\t\t\t\t\t\t\tfooter,\n\t\t\t\t\t\t\t`${info(S_BAR_END)}`,\n\t\t\t\t\t\t\t\"\",\n\t\t\t\t\t\t].join(\"\\n\");\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t\tfalse, // trackValue=false — we manage value manually\n\t) as InstanceType<typeof Prompt> & { value: unknown; state: string };\n\n\t// Character input → update filter\n\tprompt.on(\"key\", (key: string | undefined) => {\n\t\tif (!key || key === \" \") return; // space handled by cursor event\n\t\tconst cp = key.codePointAt(0) ?? 0;\n\t\tif (cp === 0x7f || cp === 0x08) {\n\t\t\t// backspace\n\t\t\tfilter = filter.slice(0, -1);\n\t\t\tcursor = 0;\n\t\t\tscrollOffset = 0;\n\t\t} else if (cp >= 32 && cp !== 127) {\n\t\t\tfilter += key;\n\t\t\tcursor = 0;\n\t\t\tscrollOffset = 0;\n\t\t}\n\t});\n\n\t// Navigation + toggle\n\tprompt.on(\"cursor\", (action: string | undefined) => {\n\t\tconst filtered = getFiltered();\n\t\tswitch (action) {\n\t\t\tcase \"up\":\n\t\t\t\tcursor = Math.max(0, cursor - 1);\n\t\t\t\tbreak;\n\t\t\tcase \"down\":\n\t\t\t\tcursor = Math.min(Math.max(filtered.length - 1, 0), cursor + 1);\n\t\t\t\tbreak;\n\t\t\tcase \"space\":\n\t\t\t\tif (multi) {\n\t\t\t\t\tconst opt = filtered[cursor];\n\t\t\t\t\tif (opt) {\n\t\t\t\t\t\tif (selected.has(opt.bcp47)) selected.delete(opt.bcp47);\n\t\t\t\t\t\telse selected.add(opt.bcp47);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t}\n\t\t// Sync prompt.value for single-select so submit gets the right value\n\t\tif (!multi) {\n\t\t\tconst opt = getFiltered()[cursor];\n\t\t\t(prompt as any).value = opt?.bcp47 ?? null;\n\t\t}\n\t});\n\n\t// Before submit resolves, set value to the selected items (multi) or current cursor (single)\n\tprompt.on(\"finalize\", () => {\n\t\tif ((prompt as any).state === \"submit\") {\n\t\t\tif (multi) {\n\t\t\t\t(prompt as any).value = Array.from(selected);\n\t\t\t} else {\n\t\t\t\tconst f = getFiltered();\n\t\t\t\t(prompt as any).value = f[cursor]?.bcp47 ?? null;\n\t\t\t}\n\t\t}\n\t});\n\n\tconst result = await prompt.prompt();\n\n\tif (isCancel(result)) return null;\n\treturn result as string | string[];\n}\n\n// ── Public API ────────────────────────────────────────────────────────────────\n\nexport async function searchSelectLocale(\n\toptions: LocaleOption[],\n\tmessage: string,\n\tinitialValue?: string,\n): Promise<string | null> {\n\tconst result = await runFilterablePrompt({\n\t\tmessage,\n\t\toptions,\n\t\tmulti: false,\n\t\tinitialValue,\n\t});\n\treturn typeof result === \"string\" ? result : null;\n}\n\nexport async function searchMultiSelectLocales(\n\toptions: LocaleOption[],\n\tmessage: string,\n\tinitialValues?: string[],\n): Promise<string[] | null> {\n\tconst result = await runFilterablePrompt({\n\t\tmessage,\n\t\toptions,\n\t\tmulti: true,\n\t\tinitialValues,\n\t});\n\tif (result === null) return null;\n\tconst picks = result as string[];\n\t// Validate already prevents empty on first try; this handles the retry path\n\tif (picks.length === 0) {\n\t\tp.log.warn(\n\t\t\t\"At least one target language is required. Please select at least one.\",\n\t\t);\n\t\treturn searchMultiSelectLocales(options, message, initialValues);\n\t}\n\treturn picks;\n}\n","import { execSync } from \"node:child_process\";\n\nexport type GitRepositoryIdentity = {\n\trepoCanonical: string;\n\t/** Absolute path to the git repository root (`git rev-parse --show-toplevel`). */\n\trepoRoot: string;\n};\n\nexport type GitContext = {\n\tidentity: GitRepositoryIdentity | null;\n\twarnings: string[];\n};\n\nconst SHA_REGEX = /^[0-9a-f]{40}$/i;\n\n/**\n * Detect the current commit SHA from CI env vars or git.\n * Must produce the same result as detectCommitSha() in @vocoder/plugin\n * so fingerprints computed by CLI sync and unplugin build match.\n */\nexport function detectCommitSha(): string | null {\n\tif (\n\t\tprocess.env.VOCODER_COMMIT_SHA &&\n\t\tSHA_REGEX.test(process.env.VOCODER_COMMIT_SHA)\n\t) {\n\t\treturn process.env.VOCODER_COMMIT_SHA;\n\t}\n\n\tconst knownSha =\n\t\tprocess.env.GITHUB_SHA ||\n\t\tprocess.env.VERCEL_GIT_COMMIT_SHA ||\n\t\tprocess.env.CI_COMMIT_SHA ||\n\t\tprocess.env.BITBUCKET_COMMIT ||\n\t\tprocess.env.CIRCLE_SHA1 ||\n\t\tprocess.env.RENDER_GIT_COMMIT;\n\n\tif (knownSha && SHA_REGEX.test(knownSha)) return knownSha;\n\n\treturn safeExec(\"git rev-parse HEAD\");\n}\n\nfunction safeExec(command: string): string | null {\n\ttry {\n\t\tconst output = execSync(command, {\n\t\t\tencoding: \"utf-8\",\n\t\t\tstdio: [\"pipe\", \"pipe\", \"ignore\"],\n\t\t}).trim();\n\t\treturn output.length > 0 ? output : null;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nfunction normalizePath(pathname: string): string | null {\n\tconst cleaned = pathname\n\t\t.replace(/^\\/+/, \"\")\n\t\t.replace(/\\.git$/i, \"\")\n\t\t.trim();\n\n\tif (!cleaned || !cleaned.includes(\"/\")) {\n\t\treturn null;\n\t}\n\n\treturn cleaned;\n}\n\nfunction parseRemoteUrl(remoteUrl: string): {\n\thost: string;\n\townerRepoPath: string;\n} | null {\n\tconst trimmed = remoteUrl.trim();\n\tif (!trimmed) {\n\t\treturn null;\n\t}\n\n\t// SCP-like syntax: git@github.com:owner/repo.git\n\tif (!trimmed.includes(\"://\")) {\n\t\tconst scpMatch = trimmed.match(/^(?:.+@)?([^:]+):(.+)$/);\n\t\tif (scpMatch) {\n\t\t\tconst host = (scpMatch[1] || \"\").toLowerCase();\n\t\t\tconst ownerRepoPath = normalizePath(scpMatch[2] || \"\");\n\t\t\tif (!host || !ownerRepoPath) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\treturn { host, ownerRepoPath };\n\t\t}\n\t\treturn null;\n\t}\n\n\ttry {\n\t\tconst parsed = new URL(trimmed);\n\t\tconst host = parsed.hostname.toLowerCase();\n\t\tconst ownerRepoPath = normalizePath(decodeURIComponent(parsed.pathname));\n\t\tif (!host || !ownerRepoPath) {\n\t\t\treturn null;\n\t\t}\n\t\treturn { host, ownerRepoPath };\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nfunction toCanonical(host: string, ownerRepoPath: string): string {\n\tif (host.includes(\"github.com\")) {\n\t\treturn `github:${ownerRepoPath.toLowerCase()}`;\n\t}\n\tif (host.includes(\"gitlab.com\")) {\n\t\treturn `gitlab:${ownerRepoPath.toLowerCase()}`;\n\t}\n\tif (host.includes(\"bitbucket.org\")) {\n\t\treturn `bitbucket:${ownerRepoPath.toLowerCase()}`;\n\t}\n\treturn `git:${host}/${ownerRepoPath.toLowerCase()}`;\n}\n\nexport function resolveGitRepositoryIdentity(): GitRepositoryIdentity | null {\n\tconst remoteUrl = safeExec(\"git config --get remote.origin.url\");\n\tif (!remoteUrl) {\n\t\treturn null;\n\t}\n\n\tconst parsed = parseRemoteUrl(remoteUrl);\n\tif (!parsed) {\n\t\treturn null;\n\t}\n\n\tconst repoRoot = safeExec(\"git rev-parse --show-toplevel\");\n\tif (!repoRoot) {\n\t\treturn null;\n\t}\n\n\treturn {\n\t\trepoCanonical: toCanonical(parsed.host, parsed.ownerRepoPath),\n\t\trepoRoot,\n\t};\n}\n\nexport function resolveGitContext(): GitContext {\n\tconst warnings: string[] = [];\n\tconst identity = resolveGitRepositoryIdentity();\n\n\tif (!identity) {\n\t\twarnings.push(\n\t\t\t\"Could not detect git remote origin. Repo binding will be skipped until sync can detect it.\",\n\t\t);\n\t}\n\n\treturn { identity, warnings };\n}\n","import * as p from \"@clack/prompts\";\nimport chalk from \"chalk\";\nimport { active, highlight } from \"../utils/theme.js\";\nimport { config as loadEnv } from \"dotenv\";\nimport { readFileSync } from \"node:fs\";\nimport { VocoderAPI, VocoderAPIError } from \"../utils/api.js\";\nimport { findExistingConfig } from \"../utils/write-config.js\";\nimport { getLimitErrorGuidance } from \"./sync.js\";\n\nloadEnv();\n\nexport interface LocaleCommandOptions {\n\tapiUrl?: string;\n}\n\n/**\n * Read the appId from the nearest vocoder.config.ts/js in the CWD.\n * Returns undefined when no config file is found or it contains no appId.\n */\nfunction readLocalAppId(): string | undefined {\n\tconst configPath = findExistingConfig(process.cwd());\n\tif (!configPath) return undefined;\n\ttry {\n\t\tconst content = readFileSync(configPath, \"utf-8\");\n\t\tconst match = content.match(/appId:\\s*['\"]([^'\"]+)['\"]/);\n\t\treturn match?.[1];\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\nfunction getApiConfig(options: LocaleCommandOptions): {\n\tapiKey: string;\n\tapiUrl: string;\n} | null {\n\tconst apiKey = process.env.VOCODER_API_KEY;\n\tif (!apiKey) {\n\t\tp.log.error(\n\t\t\t\"VOCODER_API_KEY is not set. Run `npx @vocoder/cli init` to set up your project.\",\n\t\t);\n\t\treturn null;\n\t}\n\treturn {\n\t\tapiKey,\n\t\tapiUrl: options.apiUrl ?? process.env.VOCODER_API_URL ?? \"https://vocoder.app\",\n\t};\n}\n\n/**\n * Lists the project's configured source locale and target locales.\n * Reads the project API key from VOCODER_API_KEY.\n *\n * Endpoint: GET /api/cli/config\n *\n * @throws If VOCODER_API_KEY is missing or the API call fails.\n */\nexport async function listProjectLocales(options: LocaleCommandOptions = {}): Promise<number> {\n\tconst config = getApiConfig(options);\n\tif (!config) return 1;\n\n\tconst api = new VocoderAPI(config);\n\n\ttry {\n\t\tconst projectConfig = await api.getAppConfig();\n\n\t\tp.log.info(\n\t\t\t`Source locale: ${highlight(projectConfig.sourceLocale)}`,\n\t\t);\n\n\t\tif (projectConfig.targetLocales.length === 0) {\n\t\t\tp.log.info(\"Target locales: (none configured)\");\n\t\t} else {\n\t\t\tp.log.info(\n\t\t\t\t`Target locales: ${projectConfig.targetLocales.map((l) => highlight(l)).join(\", \")}`,\n\t\t\t);\n\t\t}\n\n\t\treturn 0;\n\t} catch (error) {\n\t\tp.log.error(\n\t\t\terror instanceof Error ? error.message : \"Failed to fetch project locales.\",\n\t\t);\n\t\treturn 1;\n\t}\n}\n\n/**\n * Adds one or more target locales to the project.\n * Loops per locale — the API accepts one locale at a time.\n * Idempotent: locales already configured are silently skipped.\n *\n * Endpoint: POST /api/cli/app/locales (one call per locale)\n *\n * @param locales Array of BCP 47 locale codes to add, e.g. [\"fr\", \"de\", \"pt-BR\"].\n * @throws {VocoderAPIError} status 422 for invalid/unsupported locale code.\n * @throws {VocoderAPIError} status 403 when the plan's maxTargetLocalesPerProject limit is reached.\n */\nexport async function addLocales(\n\tlocales: string[],\n\toptions: LocaleCommandOptions = {},\n): Promise<number> {\n\tif (locales.length === 0) {\n\t\tp.log.error(\"No locale codes provided.\");\n\t\treturn 1;\n\t}\n\n\tconst config = getApiConfig(options);\n\tif (!config) return 1;\n\n\tconst api = new VocoderAPI(config);\n\tconst appId = readLocalAppId();\n\tlet lastTargetLocales: string[] = [];\n\tlet hadError = false;\n\n\tfor (const locale of locales) {\n\t\tconst spinner = p.spinner();\n\t\tspinner.start(`Adding ${locale}…`);\n\n\t\ttry {\n\t\t\tconst result = await api.addLocale(locale, undefined, appId);\n\t\t\tlastTargetLocales = result.targetLocales;\n\t\t\tspinner.stop(`Added ${highlight(locale)}`);\n\t\t} catch (error) {\n\t\t\tspinner.stop(`Failed to add ${chalk.red(locale)}`);\n\t\t\thadError = true;\n\n\t\t\tif (error instanceof VocoderAPIError && error.limitError) {\n\t\t\t\tconst { limitError } = error;\n\t\t\t\tp.log.error(limitError.message);\n\t\t\t\tfor (const line of getLimitErrorGuidance(limitError)) {\n\t\t\t\t\tp.log.info(line);\n\t\t\t\t}\n\t\t\t\t// Plan limit hit — remaining locales will also fail, so stop early\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tp.log.error(\n\t\t\t\terror instanceof Error ? error.message : \"Unknown error\",\n\t\t\t);\n\t\t}\n\t}\n\n\tif (lastTargetLocales.length > 0) {\n\t\tp.log.info(\n\t\t\t`Target locales now: ${lastTargetLocales.map((l) => highlight(l)).join(\", \")}`,\n\t\t);\n\t}\n\n\treturn hadError ? 1 : 0;\n}\n\n/**\n * Removes one or more target locales from the project.\n * Loops per locale — the API accepts one locale at a time.\n * Idempotent: locales not currently configured are silently skipped.\n *\n * Endpoint: DELETE /api/cli/app/locales (one call per locale)\n *\n * @param locales Array of BCP 47 locale codes to remove, e.g. [\"fr\", \"de\"].\n */\nexport async function removeLocales(\n\tlocales: string[],\n\toptions: LocaleCommandOptions = {},\n): Promise<number> {\n\tif (locales.length === 0) {\n\t\tp.log.error(\"No locale codes provided.\");\n\t\treturn 1;\n\t}\n\n\tconst config = getApiConfig(options);\n\tif (!config) return 1;\n\n\tconst api = new VocoderAPI(config);\n\tconst appId = readLocalAppId();\n\tlet lastTargetLocales: string[] = [];\n\tlet hadError = false;\n\n\tfor (const locale of locales) {\n\t\tconst spinner = p.spinner();\n\t\tspinner.start(`Removing ${locale}…`);\n\n\t\ttry {\n\t\t\tconst result = await api.removeLocale(locale, undefined, appId);\n\t\t\tlastTargetLocales = result.targetLocales;\n\t\t\tspinner.stop(`Removed ${highlight(locale)}`);\n\t\t} catch (error) {\n\t\t\tspinner.stop(`Failed to remove ${chalk.red(locale)}`);\n\t\t\thadError = true;\n\t\t\tp.log.error(\n\t\t\t\terror instanceof Error ? error.message : \"Unknown error\",\n\t\t\t);\n\t\t}\n\t}\n\n\tif (lastTargetLocales.length > 0) {\n\t\tp.log.info(\n\t\t\t`Target locales now: ${lastTargetLocales.map((l) => highlight(l)).join(\", \")}`,\n\t\t);\n\t} else if (!hadError) {\n\t\tp.log.info(\"Target locales now: (none configured)\");\n\t}\n\n\treturn hadError ? 1 : 0;\n}\n\n/**\n * Lists all locales supported by Vocoder.\n * Useful for discovering valid BCP 47 codes before calling `add`.\n *\n * Endpoint: GET /api/cli/locales (accepts both user tokens and project API keys)\n */\nexport async function listSupportedLocales(options: LocaleCommandOptions = {}): Promise<number> {\n\tconst config = getApiConfig(options);\n\tif (!config) return 1;\n\n\tconst api = new VocoderAPI(config);\n\n\ttry {\n\t\t// GET /api/cli/locales accepts both user tokens and project API keys as Bearer tokens\n\t\tconst result = await api.listLocales(config.apiKey);\n\t\tp.log.info(chalk.bold(\"Source locales:\"));\n\t\tprintLocaleTable(result.sourceLocales);\n\t\tp.log.info(\"\");\n\t\tp.log.info(chalk.bold(\"Target locales:\"));\n\t\tprintLocaleTable(result.targetLocales);\n\t\treturn 0;\n\t} catch (error) {\n\t\tp.log.error(\n\t\t\terror instanceof Error ? error.message : \"Failed to fetch supported locales.\",\n\t\t);\n\t\treturn 1;\n\t}\n}\n\nfunction printLocaleTable(\n\tlocales: Array<{ code: string; name: string; nativeName?: string }>,\n): void {\n\tfor (const locale of locales) {\n\t\tconst native =\n\t\t\tlocale.nativeName && locale.nativeName !== locale.name\n\t\t\t\t? ` (${locale.nativeName})`\n\t\t\t\t: \"\";\n\t\tp.log.info(` ${highlight(locale.code.padEnd(10))} ${locale.name}${native}`);\n\t}\n}\n","import { randomUUID } from \"node:crypto\";\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport * as p from \"@clack/prompts\";\nimport chalk from \"chalk\";\nimport { highlight } from \"../utils/theme.js\";\nimport type { VocoderTranslationData } from \"@vocoder/config\";\nimport { computeFingerprint, loadVocoderConfig } from \"@vocoder/extractor\";\nimport type {\n\tEffectiveSyncMode,\n\tExtractedString,\n\tLimitErrorResponse,\n\tLocalesMap,\n\tProjectConfig,\n\tRequestedSyncMode,\n\tSyncPolicyConfig,\n\tTranslateOptions,\n\tTranslationStringEntry,\n} from \"../types.js\";\nimport { VocoderAPI, VocoderAPIError } from \"../utils/api.js\";\nimport { detectBranch, isTargetBranch } from \"../utils/branch.js\";\nimport { extractShortCodeFromApiKey, getMergedConfig, validateLocalConfig } from \"../utils/config.js\";\nimport { StringExtractor } from \"../utils/extract.js\";\nimport {\n\tdetectCommitSha,\n\tresolveGitRepositoryIdentity,\n} from \"../utils/git-identity.js\";\n\ntype LocaleMetadataMap = LocalesMap;\ntype TranslationMap = Record<string, Record<string, string>>;\ntype TranslationArtifactSource = \"fresh\" | \"local-cache\" | \"api-snapshot\";\n\ntype TranslationArtifacts = {\n\tsource: TranslationArtifactSource;\n\ttranslations: TranslationMap;\n\tlocaleMetadata?: LocaleMetadataMap;\n\tsnapshotBatchId?: string;\n\tcompletedAt?: string | null;\n};\n\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction parseLocaleMetadata(value: unknown): LocaleMetadataMap | undefined {\n\tif (!isRecord(value)) {\n\t\treturn undefined;\n\t}\n\n\tconst metadata: LocaleMetadataMap = {};\n\tfor (const [locale, rawValue] of Object.entries(value)) {\n\t\tif (!isRecord(rawValue)) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst nativeName = rawValue.nativeName;\n\t\tif (typeof nativeName !== \"string\" || nativeName.trim().length === 0) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst entry: { nativeName: string; dir?: \"rtl\" } = { nativeName };\n\t\tif (rawValue.dir === \"rtl\") {\n\t\t\tentry.dir = \"rtl\";\n\t\t}\n\n\t\tmetadata[locale] = entry;\n\t}\n\n\treturn Object.keys(metadata).length > 0 ? metadata : undefined;\n}\n\nfunction parseTranslations(value: unknown): TranslationMap | null {\n\tif (!isRecord(value)) {\n\t\treturn null;\n\t}\n\n\tconst translations: TranslationMap = {};\n\n\tfor (const [locale, localeValue] of Object.entries(value)) {\n\t\tif (!isRecord(localeValue)) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst localeTranslations: Record<string, string> = {};\n\t\tfor (const [source, translated] of Object.entries(localeValue)) {\n\t\t\tif (typeof translated === \"string\") {\n\t\t\t\tlocaleTranslations[source] = translated;\n\t\t\t}\n\t\t}\n\n\t\ttranslations[locale] = localeTranslations;\n\t}\n\n\treturn Object.keys(translations).length > 0 ? translations : null;\n}\n\nfunction getCacheFilePath(projectRoot: string, fingerprint: string): string {\n\treturn join(projectRoot, \"node_modules\", \".vocoder\", \"cache\", `${fingerprint}.json`);\n}\n\nfunction buildTranslationData(params: {\n\tsourceLocale: string;\n\ttargetLocales: string[];\n\ttranslations: TranslationMap;\n\tlocaleMetadata?: LocaleMetadataMap;\n\tupdatedAt: string;\n}): VocoderTranslationData {\n\t// Translations from the API are already key-keyed ({ [sourceKey]: translatedText }).\n\t// No remapping needed — pass through directly.\n\tconst locales: Record<string, { nativeName: string; dir?: \"rtl\" }> = {};\n\tfor (const code of [params.sourceLocale, ...params.targetLocales]) {\n\t\tconst meta = params.localeMetadata?.[code];\n\t\tif (meta) locales[code] = { nativeName: meta.nativeName, ...(meta.dir ? { dir: meta.dir } : {}) };\n\t}\n\n\treturn {\n\t\tconfig: { sourceLocale: params.sourceLocale, targetLocales: params.targetLocales, locales },\n\t\ttranslations: params.translations,\n\t\tupdatedAt: params.updatedAt,\n\t};\n}\n\nfunction readLocalCache(params: {\n\tprojectRoot: string;\n\tfingerprint: string;\n}): TranslationArtifacts | null {\n\tconst cacheFilePath = getCacheFilePath(params.projectRoot, params.fingerprint);\n\tif (!existsSync(cacheFilePath)) return null;\n\ttry {\n\t\tconst raw = readFileSync(cacheFilePath, \"utf-8\");\n\t\tconst parsed = JSON.parse(raw) as unknown;\n\t\tif (!isRecord(parsed)) return null;\n\t\t// VocoderTranslationData shape: { config, translations, updatedAt }\n\t\tconst inner = isRecord(parsed.config) ? parsed : null;\n\t\tif (!inner) return null;\n\t\tconst translations = parseTranslations(inner.translations);\n\t\tif (!translations) return null;\n\t\tconst localeMetadata = isRecord(inner.config)\n\t\t\t? parseLocaleMetadata(inner.config.locales)\n\t\t\t: undefined;\n\t\treturn { source: \"local-cache\", translations, localeMetadata };\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nfunction writeCache(params: {\n\tprojectRoot: string;\n\tfingerprint: string;\n\tdata: VocoderTranslationData;\n}): string {\n\tconst cacheDir = join(params.projectRoot, \"node_modules\", \".vocoder\", \"cache\");\n\tmkdirSync(cacheDir, { recursive: true });\n\tconst cacheFilePath = getCacheFilePath(params.projectRoot, params.fingerprint);\n\twriteFileSync(cacheFilePath, JSON.stringify(params.data), \"utf-8\");\n\treturn cacheFilePath;\n}\n\nfunction resolveEffectiveModeFromPolicy(params: {\n\tbranch: string;\n\trequestedMode: RequestedSyncMode;\n\tpolicy: SyncPolicyConfig;\n}): EffectiveSyncMode {\n\tconst { requestedMode, policy, branch } = params;\n\n\tlet mode: EffectiveSyncMode;\n\tif (requestedMode === \"auto\") {\n\t\tconst isBlockingBranch = isTargetBranch(branch, policy.blockingBranches);\n\t\tmode = isBlockingBranch ? policy.blockingMode : policy.nonBlockingMode;\n\t} else {\n\t\tmode = requestedMode;\n\t}\n\n\treturn mode;\n}\n\nfunction resolveWaitTimeoutMs(params: {\n\trequestedMaxWaitMs?: number;\n\tpolicyDefaultMaxWaitMs?: number;\n\tfallbackTimeoutMs: number;\n}): number {\n\tif (\n\t\ttypeof params.requestedMaxWaitMs === \"number\" &&\n\t\tNumber.isFinite(params.requestedMaxWaitMs) &&\n\t\tparams.requestedMaxWaitMs > 0\n\t) {\n\t\treturn Math.floor(params.requestedMaxWaitMs);\n\t}\n\n\tif (\n\t\ttypeof params.policyDefaultMaxWaitMs === \"number\" &&\n\t\tNumber.isFinite(params.policyDefaultMaxWaitMs) &&\n\t\tparams.policyDefaultMaxWaitMs > 0\n\t) {\n\t\treturn Math.floor(params.policyDefaultMaxWaitMs);\n\t}\n\n\treturn params.fallbackTimeoutMs;\n}\n\nfunction normalizeTranslations(params: {\n\tsourceLocale: string;\n\ttargetLocales: string[];\n\tstringEntries: TranslationStringEntry[];\n\ttranslations: TranslationMap;\n}): TranslationMap {\n\tconst merged: TranslationMap = {};\n\n\tfor (const [locale, values] of Object.entries(params.translations)) {\n\t\tmerged[locale] = { ...values };\n\t}\n\n\tconst expectedLocales = [\n\t\tparams.sourceLocale,\n\t\t...params.targetLocales.filter((locale) => locale !== params.sourceLocale),\n\t];\n\n\tfor (const locale of expectedLocales) {\n\t\tif (!merged[locale]) {\n\t\t\tmerged[locale] = {};\n\t\t}\n\t}\n\n\tif (!merged[params.sourceLocale]) {\n\t\tmerged[params.sourceLocale] = {};\n\t}\n\n\t// Ensure source locale has an identity mapping (key → text) for all known strings.\n\t// id-only entries (text: null) are skipped — their source text is in a localesPath file.\n\tfor (const entry of params.stringEntries) {\n\t\tif (!entry.text) continue;\n\t\tif (!(entry.key in merged[params.sourceLocale]!)) {\n\t\t\tmerged[params.sourceLocale]![entry.key] = entry.text;\n\t\t}\n\t}\n\n\treturn merged;\n}\n\nexport function getLimitErrorGuidance(\n\tlimitError: LimitErrorResponse,\n): string[] {\n\tif (limitError.limitType === \"providers\") {\n\t\treturn [\n\t\t\t\"Provider setup required.\",\n\t\t\t\"Add a DeepL API key in Dashboard -> Workspace Settings -> Providers.\",\n\t\t\t`Open settings: ${limitError.upgradeUrl}`,\n\t\t];\n\t}\n\n\tif (limitError.limitType === \"translation_chars\") {\n\t\treturn [\n\t\t\t\"Monthly translation character limit reached.\",\n\t\t\t`Used this month: ${limitError.current.toLocaleString()} chars`,\n\t\t\t`Requested after sync: ${limitError.required.toLocaleString()} chars`,\n\t\t\t`Upgrade plan: ${limitError.upgradeUrl}`,\n\t\t];\n\t}\n\n\tif (limitError.limitType === \"source_strings\") {\n\t\treturn [\n\t\t\t\"Active source string limit reached.\",\n\t\t\t`Current active strings: ${limitError.current.toLocaleString()}`,\n\t\t\t`Required for this sync: ${limitError.required.toLocaleString()}`,\n\t\t\t`Upgrade plan: ${limitError.upgradeUrl}`,\n\t\t];\n\t}\n\n\tif (limitError.limitType === \"target_locales\") {\n\t\treturn [\n\t\t\t`Current target locales: ${limitError.current}`,\n\t\t\t`Plan limit: ${limitError.current} (${limitError.planId})`,\n\t\t\t`Upgrade plan: ${limitError.upgradeUrl}`,\n\t\t];\n\t}\n\n\treturn [\n\t\t`Plan: ${limitError.planId}`,\n\t\t`Current: ${limitError.current}`,\n\t\t`Required: ${limitError.required}`,\n\t\t`Upgrade: ${limitError.upgradeUrl}`,\n\t];\n}\n\nfunction getSyncPolicyErrorGuidance(\n\terror: NonNullable<VocoderAPIError[\"syncPolicyError\"]>,\n): string[] {\n\tif (error.errorCode === \"BRANCH_NOT_ALLOWED\") {\n\t\tconst lines = [\"This branch is not allowed for this project.\"];\n\t\tif (error.branch) {\n\t\t\tlines.push(`Current branch: ${error.branch}`);\n\t\t}\n\t\t// targetBranches removed — configure branches in project settings\n\t\tlines.push(\n\t\t\t\"Update your project target branches in the dashboard if needed.\",\n\t\t);\n\t\treturn lines;\n\t}\n\n\tconst lines = [\"This project is bound to a different repository.\"];\n\tif (error.boundRepoLabel) {\n\t\tlines.push(`Bound repository: ${error.boundRepoLabel}`);\n\t}\n\tif (error.boundScopePath) {\n\t\tlines.push(`Bound scope: ${error.boundScopePath}`);\n\t}\n\tlines.push(\n\t\t\"Run `vocoder init` from the correct repository or create a separate project.\",\n\t);\n\treturn lines;\n}\n\nfunction mergeContext(\n\tcurrent: string | undefined,\n\tincoming: string | undefined,\n): string | undefined {\n\tif (!incoming) return current;\n\tif (!current) return incoming;\n\tif (current === incoming) return current;\n\n\tconst merged = new Set(\n\t\t[...current.split(\" | \"), ...incoming.split(\" | \")]\n\t\t\t.map((part) => part.trim())\n\t\t\t.filter(Boolean),\n\t);\n\treturn Array.from(merged).join(\" | \");\n}\n\nfunction buildStringEntries(\n\textractedStrings: ExtractedString[],\n): TranslationStringEntry[] {\n\tconst byKey = new Map<string, TranslationStringEntry>();\n\n\tfor (const str of extractedStrings) {\n\t\tconst existing = byKey.get(str.key);\n\t\tif (!existing) {\n\t\t\tbyKey.set(str.key, {\n\t\t\t\tkey: str.key,\n\t\t\t\ttext: str.text,\n\t\t\t\t...(str.context ? { context: str.context } : {}),\n\t\t\t\t...(str.formality ? { formality: str.formality } : {}),\n\t\t\t\t...(str.uiRole ? { uiRole: str.uiRole } : {}),\n\t\t\t});\n\t\t\tcontinue;\n\t\t}\n\n\t\texisting.context = mergeContext(existing.context, str.context);\n\n\t\tif (!existing.formality && str.formality) {\n\t\t\texisting.formality = str.formality;\n\t\t} else if (\n\t\t\texisting.formality &&\n\t\t\tstr.formality &&\n\t\t\texisting.formality !== str.formality\n\t\t) {\n\t\t\texisting.formality = \"auto\";\n\t\t}\n\t}\n\n\treturn Array.from(byKey.values());\n}\n\nasync function fetchApiSnapshot(\n\tapi: VocoderAPI,\n\tparams: {\n\t\tbranch: string;\n\t\ttargetLocales: string[];\n\t},\n): Promise<TranslationArtifacts | null> {\n\tconst snapshot = await api.getTranslationSnapshot({\n\t\tbranch: params.branch,\n\t\ttargetLocales: params.targetLocales,\n\t});\n\n\tif (snapshot.status !== \"FOUND\" || !snapshot.translations) {\n\t\treturn null;\n\t}\n\n\treturn {\n\t\tsource: \"api-snapshot\",\n\t\ttranslations: snapshot.translations,\n\t\tlocaleMetadata: snapshot.localeMetadata,\n\t\tsnapshotBatchId: snapshot.snapshotBatchId,\n\t\tcompletedAt: snapshot.completedAt,\n\t};\n}\n\n/**\n * Main sync command\n */\nexport async function sync(options: TranslateOptions = {}): Promise<number> {\n\tconst startTime = Date.now();\n\tconst projectRoot = process.cwd();\n\n\tp.intro(chalk.bold(\"Vocoder Sync\"));\n\n\t// Check for API key before doing any work — missing key is an onboarding\n\t// issue, not an error. Show friendly guidance and exit cleanly.\n\tconst mergedConfig = await getMergedConfig(options, options.verbose);\n\tif (!mergedConfig.apiKey) {\n\t\tp.log.warn(\"No API key found. Run init to get started:\");\n\t\tp.log.info(\" npx @vocoder/cli init\");\n\t\tp.log.info(\"\");\n\t\tp.log.info(\n\t\t\t\" Or add your key to .env: VOCODER_API_KEY=vca_...\",\n\t\t);\n\t\tp.outro(\"Run `npx @vocoder/cli init` to set up your project.\");\n\t\treturn 1;\n\t}\n\n\tconst spinner = p.spinner();\n\n\ttry {\n\t\tconst branch = detectBranch(options.branch);\n\n\t\tspinner.start(\"Loading project configuration\");\n\n\t\tconst localConfig = {\n\t\t\tapiKey: mergedConfig.apiKey,\n\t\t\tapiUrl: mergedConfig.apiUrl || \"https://vocoder.app\",\n\t\t};\n\t\tvalidateLocalConfig(localConfig);\n\n\t\tconst api = new VocoderAPI(localConfig);\n\t\tconst apiConfig = await api.getAppConfig();\n\n\t\tconst requestedMode = mergedConfig.mode;\n\t\tconst waitTimeoutMs = resolveWaitTimeoutMs({\n\t\t\trequestedMaxWaitMs: mergedConfig.maxWaitMs,\n\t\t\tpolicyDefaultMaxWaitMs: apiConfig.syncPolicy.defaultMaxWaitMs,\n\t\t\tfallbackTimeoutMs: 60_000,\n\t\t});\n\n\t\tconst fileConfig = loadVocoderConfig(process.cwd());\n\t\tconst config: ProjectConfig = {\n\t\t\t...localConfig,\n\t\t\t...apiConfig,\n\t\t\tincludePattern: mergedConfig.includePattern,\n\t\t\texcludePattern: mergedConfig.excludePattern,\n\t\t\ttimeout: waitTimeoutMs,\n\t\t\t...(fileConfig?.industry ?? fileConfig?.appIndustry ? { industry: fileConfig?.industry ?? fileConfig?.appIndustry } : {}),\n\t\t\t...(fileConfig?.formality ? { formality: fileConfig.formality } : {}),\n\t\t};\n\n\t\tspinner.stop(`Branch: ${highlight(branch)}`);\n\n\t\tif (!options.force && !isTargetBranch(branch, config.targetBranches)) {\n\t\t\tp.log.warn(\n\t\t\t\t`Skipping translations (${highlight(branch)} is not a target branch)`,\n\t\t\t);\n\t\t\tp.log.info(`Target branches: ${config.targetBranches.map((b) => highlight(b)).join(\", \")}`);\n\t\t\tp.log.info(\"Use --force to translate anyway\");\n\t\t\tp.outro(\"\");\n\t\t\treturn 0;\n\t\t}\n\n\t\tconst patternsDisplay = Array.isArray(config.includePattern)\n\t\t\t? config.includePattern.join(\", \")\n\t\t\t: config.includePattern;\n\n\t\tspinner.start(`Extracting strings from ${patternsDisplay}`);\n\t\tconst extractor = new StringExtractor();\n\t\tconst extractedStrings = await extractor.extractFromProject(\n\t\t\tconfig.includePattern,\n\t\t\tprojectRoot,\n\t\t\tconfig.excludePattern,\n\t\t);\n\n\t\tif (extractedStrings.length === 0) {\n\t\t\tspinner.stop(\"No translatable strings found\");\n\t\t\tp.log.warn(\n\t\t\t\t\"Make sure you are wrapping translatable strings with Vocoder\",\n\t\t\t);\n\t\t\tp.outro(\"\");\n\t\t\treturn 0;\n\t\t}\n\n\t\tspinner.stop(\n\t\t\t`Extracted ${highlight(extractedStrings.length)} strings from ${highlight(patternsDisplay)}`,\n\t\t);\n\n\t\tif (options.verbose) {\n\t\t\tconst sampleLines = extractedStrings\n\t\t\t\t.slice(0, 5)\n\t\t\t\t.map((s: ExtractedString) => ` \"${s.text}\" (${s.file}:${s.line})`);\n\t\t\tif (extractedStrings.length > 5) {\n\t\t\t\tsampleLines.push(` ... and ${extractedStrings.length - 5} more`);\n\t\t\t}\n\t\t\tp.note(sampleLines.join(\"\\n\"), \"Sample strings\");\n\t\t}\n\n\t\tif (options.dryRun) {\n\t\t\tp.note(\n\t\t\t\t[\n\t\t\t\t\t`Strings: ${extractedStrings.length}`,\n\t\t\t\t\t`Branch: ${branch}`,\n\t\t\t\t\t`Target locales: ${config.targetLocales.map((l) => highlight(l)).join(\", \")}`,\n\t\t\t\t\t`Requested mode: ${requestedMode}`,\n\t\t\t\t\t`Max wait: ${waitTimeoutMs}ms`,\n\t\t\t\t\t`No fallback: ${mergedConfig.noFallback ? \"yes\" : \"no\"}`,\n\t\t\t\t].join(\"\\n\"),\n\t\t\t\t\"Dry run - would translate\",\n\t\t\t);\n\t\t\tp.outro(\"No API calls made.\");\n\t\t\treturn 0;\n\t\t}\n\n\t\tconst repoIdentity = resolveGitRepositoryIdentity();\n\t\tif (!repoIdentity && options.verbose) {\n\t\t\tp.log.warn(\n\t\t\t\t\"Could not detect git remote origin. Sync will continue without repo metadata.\",\n\t\t\t);\n\t\t}\n\t\tconst commitSha = detectCommitSha() ?? undefined;\n\n\t\tconst stringEntries = buildStringEntries(extractedStrings);\n\n\t\tif (options.verbose && stringEntries.length !== extractedStrings.length) {\n\t\t\tp.log.info(\n\t\t\t\t`Deduped ${extractedStrings.length} extracted entries into ${stringEntries.length} unique strings`,\n\t\t\t);\n\t\t}\n\n\t\t// Fingerprint uses source keys (not texts) — one text can produce multiple keys via\n\t\t// formality/context, so keying by text would produce an incorrect CDN bundle URL.\n\t\tconst sourceKeys = stringEntries.map((entry) => entry.key);\n\t\tconst fingerprint = computeFingerprint(extractShortCodeFromApiKey(localConfig.apiKey), sourceKeys);\n\n\t\t// Local cache check — skip API submission if translations already exist for this fingerprint.\n\t\tif (!options.force) {\n\t\t\tconst cacheFile = getCacheFilePath(projectRoot, fingerprint);\n\t\t\tif (existsSync(cacheFile)) {\n\t\t\t\tif (options.verbose) {\n\t\t\t\t\tp.log.info(`Cache hit: ${chalk.dim(cacheFile)} (fingerprint ${highlight(fingerprint)})`);\n\t\t\t\t}\n\t\t\t\tconst duration = ((Date.now() - startTime) / 1000).toFixed(1);\n\t\t\t\tp.outro(`Up to date (${duration}s)`);\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t\tif (options.verbose) {\n\t\t\t\tp.log.info(`No cache for fingerprint ${highlight(fingerprint)} — will submit to API`);\n\t\t\t}\n\t\t}\n\n\t\tspinner.start(\"Submitting strings to Vocoder API\");\n\n\t\tconst batchResponse = await api.submitTranslation(\n\t\t\tbranch,\n\t\t\tstringEntries,\n\t\t\tconfig.targetLocales,\n\t\t\t{\n\t\t\t\trequestedMode,\n\t\t\t\trequestedMaxWaitMs: waitTimeoutMs,\n\t\t\t\tclientRunId: randomUUID(),\n\t\t\t\tforce: options.force,\n\t\t\t\t...(config.industry ? { industry: config.industry } : {}),\n\t\t\t},\n\t\t\trepoIdentity ? { ...repoIdentity, commitSha } : { commitSha },\n\t\t);\n\n\t\tspinner.stop(\"Strings submitted\");\n\n\t\tconst effectiveMode =\n\t\t\tbatchResponse.effectiveMode ??\n\t\t\tresolveEffectiveModeFromPolicy({\n\t\t\t\tbranch,\n\t\t\t\trequestedMode,\n\t\t\t\tpolicy: config.syncPolicy,\n\t\t\t});\n\n\t\tif (options.verbose) {\n\t\t\tp.log.info(`Batch: ${chalk.dim(batchResponse.batchId)}`);\n\t\t\tp.log.info(`Requested mode: ${requestedMode}`);\n\t\t\tp.log.info(`Effective mode: ${effectiveMode}`);\n\t\t\tp.log.info(`Wait timeout: ${waitTimeoutMs}ms`);\n\t\t\tif (batchResponse.queueStatus) {\n\t\t\t\tp.log.info(`Queue status: ${batchResponse.queueStatus}`);\n\t\t\t}\n\t\t}\n\n\t\tif (batchResponse.status === \"UP_TO_DATE\" && batchResponse.noChanges) {\n\t\t\tp.log.success(`Up to date — ${highlight(batchResponse.totalStrings)} strings, no changes`);\n\t\t} else if (batchResponse.newStrings === 0) {\n\t\t\tconst archivedNote =\n\t\t\t\tbatchResponse.deletedStrings && batchResponse.deletedStrings > 0\n\t\t\t\t\t? `, ${chalk.yellow(batchResponse.deletedStrings)} archived`\n\t\t\t\t\t: \"\";\n\t\t\tp.log.success(`No new strings — ${highlight(batchResponse.totalStrings)} total${archivedNote}, using existing translations`);\n\t\t} else {\n\t\t\tconst statParts = [`${highlight(batchResponse.newStrings)} new, ${highlight(batchResponse.totalStrings)} total`];\n\t\t\tif (batchResponse.deletedStrings && batchResponse.deletedStrings > 0) {\n\t\t\t\tstatParts.push(`${chalk.yellow(batchResponse.deletedStrings)} archived`);\n\t\t\t}\n\t\t\tconst estTime = batchResponse.estimatedTime ? ` (~${batchResponse.estimatedTime}s)` : \"\";\n\t\t\tp.log.info(`${statParts.join(\", \")} → syncing to ${config.targetLocales.map((l) => highlight(l)).join(\", \")}${estTime}`);\n\t\t}\n\n\t\tlet artifacts: TranslationArtifacts | null = null;\n\t\tif (batchResponse.translations) {\n\t\t\tartifacts = {\n\t\t\t\tsource: \"fresh\",\n\t\t\t\ttranslations: batchResponse.translations,\n\t\t\t};\n\t\t}\n\n\t\tlet waitError: Error | null = null;\n\t\tif (\n\t\t\t!artifacts &&\n\t\t\t(effectiveMode === \"required\" || effectiveMode === \"best-effort\")\n\t\t) {\n\t\t\tconst waitTimeoutSecs = Math.round(waitTimeoutMs / 1000);\n\t\t\tspinner.start(`Waiting for translations (max ${waitTimeoutSecs}s)`);\n\n\t\t\tlet lastProgress = 0;\n\t\t\ttry {\n\t\t\t\tconst completion = await api.waitForCompletion(\n\t\t\t\t\tbatchResponse.batchId,\n\t\t\t\t\twaitTimeoutMs,\n\t\t\t\t\t(progress) => {\n\t\t\t\t\t\tconst percent = Math.round(progress * 100);\n\t\t\t\t\t\tif (percent > lastProgress) {\n\t\t\t\t\t\t\tspinner.message(`Translating... ${percent}%`);\n\t\t\t\t\t\t\tlastProgress = percent;\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t);\n\n\t\t\t\tartifacts = {\n\t\t\t\t\tsource: \"fresh\",\n\t\t\t\t\ttranslations: completion.translations,\n\t\t\t\t\tlocaleMetadata: completion.localeMetadata,\n\t\t\t\t};\n\t\t\t\tspinner.stop(\"Translations complete\");\n\t\t\t} catch (error) {\n\t\t\t\tspinner.stop(\"Translation wait incomplete\");\n\t\t\t\twaitError = error instanceof Error ? error : new Error(String(error));\n\n\t\t\t\tif (effectiveMode === \"required\") {\n\t\t\t\t\tthrow waitError;\n\t\t\t\t}\n\n\t\t\t\tp.log.warn(`Best-effort wait ended early: ${waitError.message}`);\n\t\t\t}\n\t\t}\n\n\t\tif (!artifacts) {\n\t\t\tif (mergedConfig.noFallback) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t\"Fresh translations are not available and fallback is disabled (--no-fallback).\",\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tspinner.start(\"Loading fallback translations\");\n\n\t\t\tconst localFallback = readLocalCache({\n\t\t\t\tprojectRoot,\n\t\t\t\tfingerprint,\n\t\t\t});\n\n\t\t\tif (localFallback) {\n\t\t\t\tartifacts = localFallback;\n\t\t\t\tspinner.stop(`Using local cached snapshot (${fingerprint})`);\n\t\t\t} else {\n\t\t\t\ttry {\n\t\t\t\t\tconst apiSnapshot = await fetchApiSnapshot(api, {\n\t\t\t\t\t\tbranch,\n\t\t\t\t\t\ttargetLocales: config.targetLocales,\n\t\t\t\t\t});\n\n\t\t\t\t\tif (apiSnapshot) {\n\t\t\t\t\t\tartifacts = apiSnapshot;\n\t\t\t\t\t\tspinner.stop(\"Using latest completed API snapshot\");\n\t\t\t\t\t} else {\n\t\t\t\t\t\tspinner.stop(\"No completed API snapshot available\");\n\t\t\t\t\t}\n\t\t\t\t} catch (error) {\n\t\t\t\t\tspinner.stop(\"Failed to fetch API snapshot\");\n\t\t\t\t\tif (options.verbose) {\n\t\t\t\t\t\tconst message =\n\t\t\t\t\t\t\terror instanceof Error\n\t\t\t\t\t\t\t\t? error.message\n\t\t\t\t\t\t\t\t: \"Unknown snapshot fetch error\";\n\t\t\t\t\t\tp.log.warn(`Snapshot fetch error: ${message}`);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (!artifacts) {\n\t\t\t\tif (waitError) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`No fallback snapshot available after wait failure: ${waitError.message}`,\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tthrow new Error(\n\t\t\t\t\t\"No fallback snapshot available. Try again shortly or run with --mode required.\",\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tconst finalTranslations = normalizeTranslations({\n\t\t\tsourceLocale: config.sourceLocale,\n\t\t\ttargetLocales: config.targetLocales,\n\t\t\tstringEntries,\n\t\t\ttranslations: artifacts.translations,\n\t\t});\n\n\t\ttry {\n\t\t\tconst data = buildTranslationData({\n\t\t\t\tsourceLocale: config.sourceLocale,\n\t\t\t\ttargetLocales: config.targetLocales,\n\t\t\t\ttranslations: finalTranslations,\n\t\t\t\tlocaleMetadata: artifacts.localeMetadata,\n\t\t\t\tupdatedAt: new Date().toISOString(),\n\t\t\t});\n\t\t\tconst cachePath = writeCache({ projectRoot, fingerprint, data });\n\t\t\tif (options.verbose) {\n\t\t\t\tp.log.info(`Cache written: ${highlight(cachePath)}`);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tif (options.verbose) {\n\t\t\t\tconst message =\n\t\t\t\t\terror instanceof Error ? error.message : \"Unknown cache write error\";\n\t\t\t\tp.log.warn(`Failed to write cache: ${message}`);\n\t\t\t}\n\t\t}\n\n\t\tif (artifacts.source !== \"fresh\") {\n\t\t\tconst sourceLabel =\n\t\t\t\tartifacts.source === \"local-cache\"\n\t\t\t\t\t? \"local cached snapshot\"\n\t\t\t\t\t: \"completed API snapshot\";\n\t\t\tp.log.warn(\n\t\t\t\t`Using ${sourceLabel}. New strings may appear after the background sync completes.`,\n\t\t\t);\n\t\t}\n\n\t\tconst duration = ((Date.now() - startTime) / 1000).toFixed(1);\n\t\tp.outro(`Sync complete! (${duration}s)`);\n\t\treturn 0;\n\t} catch (error) {\n\t\tspinner.stop();\n\n\t\tif (error instanceof VocoderAPIError && error.syncPolicyError) {\n\t\t\tp.log.error(error.syncPolicyError.message);\n\t\t\tconst guidance = getSyncPolicyErrorGuidance(error.syncPolicyError);\n\t\t\tfor (const line of guidance) {\n\t\t\t\tp.log.info(line);\n\t\t\t}\n\t\t\treturn 1;\n\t\t}\n\n\t\tif (error instanceof VocoderAPIError && error.limitError) {\n\t\t\tconst { limitError } = error;\n\t\t\tp.log.error(limitError.message);\n\t\t\tconst guidance = getLimitErrorGuidance(limitError);\n\t\t\tfor (const line of guidance) {\n\t\t\t\tp.log.info(line);\n\t\t\t}\n\t\t\treturn 1;\n\t\t}\n\n\t\tif (error instanceof Error) {\n\t\t\tp.log.error(error.message);\n\n\t\t\tconst isInvalidKey =\n\t\t\t\terror.message.toLowerCase().includes(\"invalid api key\") ||\n\t\t\t\t(error instanceof VocoderAPIError && error.status === 401);\n\n\t\t\tif (isInvalidKey) {\n\t\t\t\tp.log.warn(\n\t\t\t\t\t\"API key rejected — the project may have been deleted or the key revoked.\",\n\t\t\t\t);\n\t\t\t\tp.log.info(\n\t\t\t\t\t\" Run `npx @vocoder/cli init` to create a new project and key.\",\n\t\t\t\t);\n\t\t\t} else if (error.message.includes(\"git branch\")) {\n\t\t\t\tp.log.warn(\"Run from a git repository, or use:\");\n\t\t\t\tp.log.info(\" vocoder sync --branch main\");\n\t\t\t}\n\n\t\t\tif (options.verbose) {\n\t\t\t\tp.log.info(`Full error: ${error.stack ?? error}`);\n\t\t\t}\n\t\t}\n\n\t\treturn 1;\n\t}\n}\n","import { execSync } from \"node:child_process\";\n\nconst REGEX_SPECIAL_CHARS = /[.+?^${}()|[\\]\\\\]/g;\n\nfunction escapeRegexChar(value: string): string {\n\treturn value.replace(REGEX_SPECIAL_CHARS, \"\\\\$&\");\n}\n\n/**\n * Detects the current git branch from multiple sources in priority order:\n * 1. Explicit --branch flag (passed as parameter)\n * 2. CI environment variables (GitHub Actions, Vercel, Netlify, etc.)\n * 3. Git command (local development)\n *\n * @param override - Optional branch name to override detection\n * @returns The current branch name\n */\nexport function detectBranch(override?: string): string {\n\t// 1. Explicit override (from --branch flag)\n\tif (override) {\n\t\treturn override;\n\t}\n\n\t// 2. CI environment variables\n\tconst envBranch =\n\t\tprocess.env.GITHUB_HEAD_REF || // GitHub Actions (PR source branch)\n\t\tprocess.env.GITHUB_REF_NAME || // GitHub Actions (push)\n\t\tprocess.env.VERCEL_GIT_COMMIT_REF || // Vercel\n\t\tprocess.env.BRANCH || // Netlify\n\t\tprocess.env.CF_PAGES_BRANCH || // Cloudflare Pages\n\t\tprocess.env.CI_COMMIT_REF_NAME || // GitLab CI\n\t\tprocess.env.BITBUCKET_BRANCH || // Bitbucket Pipelines\n\t\tprocess.env.CIRCLE_BRANCH || // CircleCI\n\t\tprocess.env.RENDER_GIT_BRANCH; // Render\n\n\tif (envBranch) {\n\t\treturn envBranch;\n\t}\n\n\t// 3. Git command (local development)\n\ttry {\n\t\tconst branch = execSync(\"git rev-parse --abbrev-ref HEAD\", {\n\t\t\tencoding: \"utf-8\",\n\t\t\tstdio: [\"pipe\", \"pipe\", \"ignore\"],\n\t\t}).trim();\n\n\t\treturn branch;\n\t} catch (_error) {\n\t\tthrow new Error(\n\t\t\t\"Failed to detect git branch. Make sure you are in a git repository or set the --branch flag.\",\n\t\t);\n\t}\n}\n\n/**\n * Checks if the current branch is a target branch that should trigger translations\n *\n * @param currentBranch - The current branch name\n * @param targetBranches - List of branches that should trigger translations\n * @returns True if the branch should trigger translations\n */\nexport function isTargetBranch(\n\tcurrentBranch: string,\n\ttargetBranches: string[],\n): boolean {\n\treturn targetBranches.some((pattern) =>\n\t\tmatchBranchPattern(currentBranch, pattern),\n\t);\n}\n\nexport function matchBranchPattern(branch: string, pattern: string): boolean {\n\tconst trimmedPattern = pattern.trim();\n\tif (!trimmedPattern) {\n\t\treturn false;\n\t}\n\n\tlet regexSource = \"^\";\n\tfor (let i = 0; i < trimmedPattern.length; i += 1) {\n\t\tconst char = trimmedPattern[i];\n\t\tif (!char) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (char === \"*\") {\n\t\t\tconst next = trimmedPattern[i + 1];\n\t\t\tif (next === \"*\") {\n\t\t\t\tregexSource += \".*\";\n\t\t\t\ti += 1;\n\t\t\t} else {\n\t\t\t\tregexSource += \"[^/]*\";\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\tregexSource += escapeRegexChar(char);\n\t}\n\tregexSource += \"$\";\n\n\treturn new RegExp(regexSource).test(branch);\n}\n","import * as p from \"@clack/prompts\";\nimport chalk from \"chalk\";\nimport { active, highlight } from \"./theme.js\";\nimport { config as loadEnv } from \"dotenv\";\nimport { loadVocoderConfig } from \"@vocoder/extractor\";\nimport type {\n\tLocalConfig,\n\tRequestedSyncMode,\n\tTranslateOptions,\n} from \"../types.js\";\n\n// Load .env file if present\nloadEnv();\n\n/**\n * Extracts the app short code embedded in the API key token.\n * Key format: vca_{shortCode(10)}_{random(22)}\n * Safe to call offline — no network required.\n */\nexport function extractShortCodeFromApiKey(apiKey: string): string {\n\treturn apiKey.slice(4, 14);\n}\n\n/**\n * Validates the local configuration\n */\nexport function validateLocalConfig(config: LocalConfig): void {\n\tif (!config.apiKey || config.apiKey.length === 0) {\n\t\tthrow new Error(\"VOCODER_API_KEY is required. Set it in your .env file.\");\n\t}\n\n\tif (!config.apiKey.startsWith(\"vca_\")) {\n\t\tthrow new Error(\n\t\t\t\"Invalid API key format. Expected an app API key starting with vca_.\",\n\t\t);\n\t}\n\n\tif (!config.apiUrl || !config.apiUrl.startsWith(\"http\")) {\n\t\tthrow new Error(\"Invalid API URL\");\n\t}\n}\n\n/**\n * Merge configuration from all sources with priority:\n * 1. CLI flags (highest priority)\n * 2. Environment variables\n * 3. Defaults (lowest priority)\n *\n * @param cliOptions - Options from CLI flags\n * @param verbose - Whether to log config sources\n * @returns Merged configuration with source information\n */\nexport async function getMergedConfig(\n\tcliOptions: TranslateOptions,\n\tverbose: boolean = false,\n\t_startDir?: string,\n): Promise<{\n\tincludePattern: string[];\n\texcludePattern: string[];\n\tapiKey?: string;\n\tapiUrl?: string;\n\tmode: RequestedSyncMode;\n\tmaxWaitMs?: number;\n\tnoFallback: boolean;\n\tconfigSources: {\n\t\tincludePattern: string;\n\t\texcludePattern: string;\n\t\tapiKey: string;\n\t\tapiUrl: string;\n\t\tmode: string;\n\t\tmaxWaitMs: string;\n\t\tnoFallback: string;\n\t};\n}> {\n\tconst configSources = {\n\t\tincludePattern: \"default\",\n\t\texcludePattern: \"default\",\n\t\tapiKey: \"environment\",\n\t\tapiUrl: \"default\",\n\t\tmode: \"default\",\n\t\tmaxWaitMs: \"default\",\n\t\tnoFallback: \"default\",\n\t};\n\n\t// 1. Defaults\n\tconst defaults = {\n\t\tincludePattern: [\"**/*.{tsx,jsx,ts,js}\"],\n\t\texcludePattern: [\n\t\t\t\"**/node_modules/**\",\n\t\t\t\"**/.next/**\",\n\t\t\t\"**/.nuxt/**\",\n\t\t\t\"**/.svelte-kit/**\",\n\t\t\t\"**/.output/**\",\n\t\t\t\"**/dist/**\",\n\t\t\t\"**/build/**\",\n\t\t\t\"**/out/**\",\n\t\t\t\"**/.vite/**\",\n\t\t\t\"**/.turbo/**\",\n\t\t\t\"**/coverage/**\",\n\t\t\t\"**/.cache/**\",\n\t\t\t\"**/*.min.js\",\n\t\t\t\"**/*.min.ts\",\n\t\t\t\"**/__generated__/**\",\n\t\t\t\"**/*.test.*\",\n\t\t\t\"**/*.spec.*\",\n\t\t\t\"**/*.stories.*\",\n\t\t\t\"**/__tests__/**\",\n\t\t],\n\t\tapiUrl: \"https://vocoder.app\",\n\t};\n\n\t// 2. vocoder.config.ts — the canonical source for extraction patterns.\n\t// CLI flags still override it for one-off runs.\n\tconst fileConfig = loadVocoderConfig(process.cwd());\n\n\tif (!fileConfig) {\n\t\tp.log.warn(\n\t\t\t`No ${highlight(\"vocoder.config.ts\")} found — run ${highlight(\"npx @vocoder/cli init\")} to generate one.`,\n\t\t);\n\t}\n\n\t// 3. Environment variables (legacy, lower priority than config file)\n\tconst envExtractionPattern = process.env.VOCODER_INCLUDE_PATTERN;\n\tconst envExcludePattern = process.env.VOCODER_EXCLUDE_PATTERN;\n\tconst envApiUrl = process.env.VOCODER_API_URL;\n\tconst envSyncMode = process.env.VOCODER_SYNC_MODE;\n\tconst envSyncMaxWaitMs = process.env.VOCODER_SYNC_MAX_WAIT_MS;\n\tconst envSyncNoFallback = process.env.VOCODER_SYNC_NO_FALLBACK;\n\n\t// 4. Merge with priority: CLI flag > vocoder.config.ts > env > defaults\n\n\t// Extract patterns (include)\n\tlet includePattern: string[];\n\tif (cliOptions.include && cliOptions.include.length > 0) {\n\t\tincludePattern = cliOptions.include;\n\t\tconfigSources.includePattern = \"CLI flag\";\n\t} else if (fileConfig?.include && fileConfig.include.length > 0) {\n\t\tincludePattern = fileConfig.include;\n\t\tconfigSources.includePattern = \"vocoder.config\";\n\t} else if (envExtractionPattern) {\n\t\tincludePattern = [envExtractionPattern];\n\t\tconfigSources.includePattern = \"environment\";\n\t} else {\n\t\tincludePattern = defaults.includePattern;\n\t}\n\n\t// Exclude patterns\n\tlet excludePattern: string[];\n\tif (cliOptions.exclude && cliOptions.exclude.length > 0) {\n\t\texcludePattern = cliOptions.exclude;\n\t\tconfigSources.excludePattern = \"CLI flag\";\n\t} else if (fileConfig?.exclude && fileConfig.exclude.length > 0) {\n\t\texcludePattern = fileConfig.exclude;\n\t\tconfigSources.excludePattern = \"vocoder.config\";\n\t} else if (envExcludePattern) {\n\t\texcludePattern = envExcludePattern\n\t\t\t.split(\",\")\n\t\t\t.map((p: string) => p.trim())\n\t\t\t.filter(Boolean);\n\t\tconfigSources.excludePattern = \"environment\";\n\t} else {\n\t\texcludePattern = defaults.excludePattern;\n\t}\n\n\t// API key (from env)\n\tlet apiKey: string | undefined;\n\tif (process.env.VOCODER_API_KEY) {\n\t\tapiKey = process.env.VOCODER_API_KEY;\n\t\tconfigSources.apiKey = \"environment\";\n\t}\n\n\t// API URL\n\tlet apiUrl: string;\n\tif (envApiUrl) {\n\t\tapiUrl = envApiUrl;\n\t\tconfigSources.apiUrl = \"environment\";\n\t} else {\n\t\tapiUrl = defaults.apiUrl;\n\t}\n\n\tconst modeCandidates = [\"auto\", \"required\", \"best-effort\"] as const;\n\tlet mode: RequestedSyncMode = \"auto\";\n\tif (cliOptions.mode && modeCandidates.includes(cliOptions.mode)) {\n\t\tmode = cliOptions.mode;\n\t\tconfigSources.mode = \"CLI flag\";\n\t} else if (\n\t\tenvSyncMode &&\n\t\tmodeCandidates.includes(envSyncMode as RequestedSyncMode)\n\t) {\n\t\tmode = envSyncMode as RequestedSyncMode;\n\t\tconfigSources.mode = \"environment\";\n\t}\n\n\tlet maxWaitMs: number | undefined;\n\tif (\n\t\ttypeof cliOptions.maxWaitMs === \"number\" &&\n\t\tNumber.isFinite(cliOptions.maxWaitMs) &&\n\t\tcliOptions.maxWaitMs > 0\n\t) {\n\t\tmaxWaitMs = Math.floor(cliOptions.maxWaitMs);\n\t\tconfigSources.maxWaitMs = \"CLI flag\";\n\t} else if (envSyncMaxWaitMs) {\n\t\tconst parsed = Number.parseInt(envSyncMaxWaitMs, 10);\n\t\tif (Number.isFinite(parsed) && parsed > 0) {\n\t\t\tmaxWaitMs = parsed;\n\t\t\tconfigSources.maxWaitMs = \"environment\";\n\t\t}\n\t}\n\n\tlet noFallback = false;\n\tif (typeof cliOptions.noFallback === \"boolean\") {\n\t\tnoFallback = cliOptions.noFallback;\n\t\tconfigSources.noFallback = \"CLI flag\";\n\t} else if (envSyncNoFallback) {\n\t\tnoFallback = [\"1\", \"true\", \"yes\", \"on\"].includes(\n\t\t\tenvSyncNoFallback.toLowerCase(),\n\t\t);\n\t\tconfigSources.noFallback = \"environment\";\n\t}\n\n\t// Log config sources in verbose mode\n\tif (verbose) {\n\t\tconst lines = [\n\t\t\t`Include patterns: ${highlight(configSources.includePattern)}`,\n\t\t\t...(excludePattern.length > 0\n\t\t\t\t? [`Exclude patterns: ${highlight(configSources.excludePattern)}`]\n\t\t\t\t: []),\n\t\t\t`API key: ${highlight(configSources.apiKey)}`,\n\t\t\t`API URL: ${highlight(configSources.apiUrl)}`,\n\t\t\t`Sync mode: ${highlight(configSources.mode)}`,\n\t\t\t...(maxWaitMs\n\t\t\t\t? [`Max wait: ${highlight(String(configSources.maxWaitMs))}`]\n\t\t\t\t: []),\n\t\t\t`No fallback: ${highlight(String(configSources.noFallback))}`,\n\t\t];\n\t\tp.note(lines.join(\"\\n\"), \"Configuration sources\");\n\t}\n\n\treturn {\n\t\tincludePattern,\n\t\texcludePattern,\n\t\tapiKey,\n\t\tapiUrl,\n\t\tmode,\n\t\tmaxWaitMs,\n\t\tnoFallback,\n\t\tconfigSources,\n\t};\n}\n","import * as p from \"@clack/prompts\";\nimport { VocoderAPI } from \"../utils/api.js\";\nimport { clearAuthData, readAuthData } from \"../utils/auth-store.js\";\n\nexport interface LogoutOptions {\n\tapiUrl?: string;\n}\n\nexport async function logout(options: LogoutOptions = {}): Promise<number> {\n\tconst stored = readAuthData();\n\n\tif (!stored) {\n\t\tp.log.info(\"Not currently authenticated.\");\n\t\treturn 0;\n\t}\n\n\tconst apiUrl = options.apiUrl ?? stored.apiUrl ?? \"https://vocoder.app\";\n\tconst api = new VocoderAPI({ apiUrl, apiKey: \"\" });\n\n\ttry {\n\t\tawait api.revokeCliToken(stored.token);\n\t} catch {\n\t\t// Ignore errors — we still clear local data even if the server call fails\n\t}\n\n\tclearAuthData();\n\tp.log.success(`Logged out (was ${stored.email})`);\n\treturn 0;\n}\n","import * as p from \"@clack/prompts\";\nimport chalk from \"chalk\";\nimport { active, highlight } from \"../utils/theme.js\";\nimport { config as loadEnv } from \"dotenv\";\nimport { VocoderAPI } from \"../utils/api.js\";\n\nloadEnv();\n\nexport interface AppConfigOptions {\n\tapiUrl?: string;\n}\n\n/**\n * Displays the current Vocoder app configuration.\n *\n * Shows: project name, organization, source locale, target locales,\n * target branches, primary branch, and sync policy settings.\n *\n * Reads the app API key from VOCODER_API_KEY.\n * Endpoint: GET /api/cli/config\n *\n * @throws If VOCODER_API_KEY is missing or invalid.\n */\nexport async function appConfig(options: AppConfigOptions = {}): Promise<number> {\n\tconst apiKey = process.env.VOCODER_API_KEY;\n\tif (!apiKey) {\n\t\tp.log.error(\n\t\t\t\"VOCODER_API_KEY is not set. Run `npx @vocoder/cli init` to set up your project.\",\n\t\t);\n\t\treturn 1;\n\t}\n\n\tconst apiUrl = options.apiUrl ?? process.env.VOCODER_API_URL ?? \"https://vocoder.app\";\n\tconst api = new VocoderAPI({ apiKey, apiUrl });\n\n\ttry {\n\t\tconst config = await api.getAppConfig();\n\n\t\tconst lines = [\n\t\t\t`App: ${chalk.bold(config.projectName)}`,\n\t\t\t`Organization: ${config.organizationName}`,\n\t\t\t`Source locale: ${highlight(config.sourceLocale)}`,\n\t\t\t`Target locales: ${\n\t\t\t\tconfig.targetLocales.length > 0\n\t\t\t\t\t? config.targetLocales.map((l) => highlight(l)).join(\", \")\n\t\t\t\t\t: chalk.dim(\"(none)\")\n\t\t\t}`,\n\t\t\t`Target branches: ${config.targetBranches.map((b) => highlight(b)).join(\", \")}`,\n\t\t\t...(config.primaryBranch\n\t\t\t\t? [`Primary branch: ${highlight(config.primaryBranch)}`]\n\t\t\t\t: []),\n\t\t\t`Sync policy:`,\n\t\t\t` Blocking branches: ${config.syncPolicy.blockingBranches.map((b) => highlight(b)).join(\", \")}`,\n\t\t\t` Blocking mode: ${highlight(config.syncPolicy.blockingMode)}`,\n\t\t\t` Non-blocking mode: ${highlight(config.syncPolicy.nonBlockingMode)}`,\n\t\t\t` Max wait: ${highlight(String(config.syncPolicy.defaultMaxWaitMs))} ms`,\n\t\t];\n\n\t\tp.note(lines.join(\"\\n\"), `${config.projectName} — app config`);\n\t\treturn 0;\n\t} catch (error) {\n\t\tp.log.error(\n\t\t\terror instanceof Error ? error.message : \"Failed to fetch project config.\",\n\t\t);\n\t\treturn 1;\n\t}\n}\n","import { mkdirSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport * as p from \"@clack/prompts\";\nimport chalk from \"chalk\";\nimport { active, highlight } from \"../utils/theme.js\";\nimport { config as loadEnv } from \"dotenv\";\nimport { VocoderAPI } from \"../utils/api.js\";\nimport { detectBranch } from \"../utils/branch.js\";\n\nloadEnv();\n\nexport interface TranslationsOptions {\n\t/** Git branch. Auto-detected from git/CI env if omitted. */\n\tbranch?: string;\n\t/** Specific target locale to fetch. All configured locales if omitted. */\n\tlocale?: string;\n\t/**\n\t * Output directory for locale JSON files.\n\t * When set, writes one <locale>.json per locale to this directory.\n\t * When omitted, prints the full snapshot as JSON to stdout.\n\t */\n\toutput?: string;\n\tapiUrl?: string;\n}\n\n/**\n * Downloads the current translation snapshot for the project.\n *\n * With --output <dir>: writes one <locale>.json file per locale to the\n * specified directory. Each file shape: { \"source text\": \"translated text\" }.\n *\n * Without --output: prints the full snapshot JSON to stdout, suitable\n * for piping or programmatic use.\n *\n * Reads the project API key from VOCODER_API_KEY.\n * Endpoint: GET /api/cli/sync/snapshot\n *\n * @param options.branch Git branch (auto-detected from git/CI if omitted).\n * @param options.locale Specific target locale; all configured locales if omitted.\n * @param options.output Output directory. Omit to print to stdout.\n *\n * @throws If VOCODER_API_KEY is missing or invalid.\n */\nexport async function getTranslations(options: TranslationsOptions = {}): Promise<number> {\n\tconst apiKey = process.env.VOCODER_API_KEY;\n\tif (!apiKey) {\n\t\tp.log.error(\n\t\t\t\"VOCODER_API_KEY is not set. Run `npx @vocoder/cli init` to set up your project.\",\n\t\t);\n\t\treturn 1;\n\t}\n\n\tconst apiUrl = options.apiUrl ?? process.env.VOCODER_API_URL ?? \"https://vocoder.app\";\n\tconst api = new VocoderAPI({ apiKey, apiUrl });\n\n\tlet branch: string;\n\ttry {\n\t\tbranch = detectBranch(options.branch);\n\t} catch (error) {\n\t\tp.log.error(\n\t\t\terror instanceof Error ? error.message : \"Failed to detect branch.\",\n\t\t);\n\t\treturn 1;\n\t}\n\n\tconst spinner = p.spinner();\n\tspinner.start(`Fetching translations for ${highlight(branch)}…`);\n\n\ttry {\n\t\t// Fetch the project config to resolve which target locales to request\n\t\tconst projectConfig = await api.getAppConfig();\n\t\tconst targetLocales = options.locale\n\t\t\t? [options.locale]\n\t\t\t: projectConfig.targetLocales;\n\n\t\tif (targetLocales.length === 0) {\n\t\t\tspinner.stop(\"No target locales configured.\");\n\t\t\tp.log.info(\"Add target locales with `vocoder locales add <code>`.\");\n\t\t\treturn 1;\n\t\t}\n\n\t\tconst snapshot = await api.getTranslationSnapshot({ branch, targetLocales });\n\t\tspinner.stop(`Fetched translations for ${highlight(branch)}`);\n\n\t\tif (snapshot.status === \"NOT_FOUND\") {\n\t\t\tp.log.warn(\n\t\t\t\t`No translation snapshot found for branch \"${branch}\". ` +\n\t\t\t\t\t\"Run `vocoder sync` to generate one.\",\n\t\t\t);\n\t\t\treturn 1;\n\t\t}\n\n\t\tconst translations = snapshot.translations ?? {};\n\n\t\tif (options.output) {\n\t\t\twriteLocaleFiles(translations, options.output);\n\t\t} else {\n\t\t\t// stdout — raw JSON for piping/programmatic use\n\t\t\tprocess.stdout.write(JSON.stringify(translations, null, 2));\n\t\t\tprocess.stdout.write(\"\\n\");\n\t\t}\n\n\t\treturn 0;\n\t} catch (error) {\n\t\tspinner.stop(\"Failed to fetch translations.\");\n\t\tp.log.error(\n\t\t\terror instanceof Error ? error.message : \"Unknown error.\",\n\t\t);\n\t\treturn 1;\n\t}\n}\n\n/**\n * Writes one <locale>.json file per locale to the output directory.\n * Creates the directory if it does not exist.\n * Each file shape: { \"source text\": \"translated text\" }\n */\nfunction writeLocaleFiles(\n\ttranslations: Record<string, Record<string, string>>,\n\toutputDir: string,\n): void {\n\tmkdirSync(outputDir, { recursive: true });\n\n\tfor (const [locale, strings] of Object.entries(translations)) {\n\t\tconst filePath = join(outputDir, `${locale}.json`);\n\t\twriteFileSync(filePath, JSON.stringify(strings, null, 2) + \"\\n\", \"utf-8\");\n\t\tp.log.success(`Wrote ${highlight(filePath)}`);\n\t}\n}\n","import * as p from \"@clack/prompts\";\nimport chalk from \"chalk\";\nimport { active, highlight } from \"../utils/theme.js\";\nimport { config as loadEnv } from \"dotenv\";\nimport { VocoderAPI, VocoderAPIError } from \"../utils/api.js\";\nimport { readAuthData } from \"../utils/auth-store.js\";\nimport { resolveGitRepositoryIdentity } from \"../utils/git-identity.js\";\nimport { getLimitErrorGuidance } from \"./sync.js\";\n\nloadEnv();\n\nexport interface CreateAppOptions {\n\t/** Project display name (required). */\n\tname: string;\n\t/** BCP 47 source locale code, e.g. \"en\" (required). */\n\tsourceLocale: string;\n\t/** Comma-separated target locale codes, e.g. \"fr,de,pt-BR\". */\n\ttargetLocales?: string;\n\t/** Comma-separated branch names to enable sync on. Defaults to \"main\". */\n\ttargetBranches?: string;\n\t/** Organization ID to create the project in (required). */\n\torganization: string;\n\t/**\n\t * Explicit git repository canonical, e.g. \"github:owner/repo\".\n\t * Auto-detected from git remote if omitted.\n\t */\n\trepo?: string;\n\t/**\n\t * App directory within the repository for monorepos, e.g. \"apps/web\".\n\t * Defaults to \".\" (repo root).\n\t */\n\tappDir?: string;\n\tapiUrl?: string;\n}\n\n/**\n * Creates a new Vocoder project without the interactive init flow.\n *\n * Requires a valid user token in the local auth store (run `vocoder init` first).\n * Prints the generated VOCODER_API_KEY to stdout on success.\n *\n * Git identity is auto-detected from the git remote. The detected repository\n * must be accessible via the workspace's GitHub App installation for\n * push-based sync to function. Use --repo to override auto-detection, or\n * omit repo binding entirely if not in a git repository.\n *\n * Endpoint: POST /api/cli/apps\n *\n * @param options.name Project display name (required).\n * @param options.sourceLocale Source language BCP 47 code (required).\n * @param options.targetLocales Comma-separated target locale codes.\n * @param options.targetBranches Comma-separated branch names (default: \"main\").\n * @param options.organization Organization ID (required).\n * @param options.repo Git repo canonical override.\n * @param options.appDir App directory for monorepos (default: \".\").\n *\n * @throws If user token is missing, organization is invalid, or the plan's\n * maxProjects limit is exceeded.\n */\nexport async function createApp(options: CreateAppOptions): Promise<number> {\n\tconst authData = readAuthData();\n\tif (!authData) {\n\t\tp.log.error(\n\t\t\t\"Not logged in. Run `npx @vocoder/cli init` to authenticate first.\",\n\t\t);\n\t\treturn 1;\n\t}\n\n\tconst apiUrl = options.apiUrl ?? process.env.VOCODER_API_URL ?? \"https://vocoder.app\";\n\tconst api = new VocoderAPI({ apiKey: \"\", apiUrl });\n\n\t// Resolve repo identity — auto-detect if not overridden\n\tlet repoCanonical: string | undefined;\n\tlet appDir = options.appDir ?? \".\";\n\n\tif (options.repo) {\n\t\trepoCanonical = options.repo;\n\t} else {\n\t\tconst identity = resolveGitRepositoryIdentity();\n\t\tif (identity) {\n\t\t\trepoCanonical = identity.repoCanonical;\n\t\t\t// Only override appDir from git if the caller didn't specify one\n\t\t\tif (!options.appDir && identity.repoAppDir) {\n\t\t\t\tappDir = identity.repoAppDir;\n\t\t\t}\n\t\t} else {\n\t\t\tp.log.warn(\n\t\t\t\t\"Could not detect a git remote. The project will be created without repo binding — \" +\n\t\t\t\t\t\"sync-on-push will not function until a repository is connected via the Vocoder dashboard.\",\n\t\t\t);\n\t\t}\n\t}\n\n\tconst targetLocales = options.targetLocales\n\t\t? options.targetLocales.split(\",\").map((l) => l.trim()).filter(Boolean)\n\t\t: [];\n\n\tconst targetBranches = options.targetBranches\n\t\t? options.targetBranches.split(\",\").map((b) => b.trim()).filter(Boolean)\n\t\t: [\"main\"];\n\n\tconst spinner = p.spinner();\n\tspinner.start(`Creating app \"${options.name}\"…`);\n\n\ttry {\n\t\tconst result = await api.createProject(authData.token, {\n\t\t\torganizationId: options.organization,\n\t\t\tname: options.name,\n\t\t\tsourceLocale: options.sourceLocale,\n\t\t\ttargetLocales,\n\t\t\ttargetBranches,\n\t\t\tappDirs: [appDir],\n\t\t\t...(repoCanonical ? { repoCanonical } : {}),\n\t\t});\n\n\t\tspinner.stop(`Created app ${chalk.bold(result.projectName)}`);\n\n\t\tconst lines = [\n\t\t\t`Project ID: ${result.projectId}`,\n\t\t\t`Source locale: ${highlight(result.sourceLocale)}`,\n\t\t\t`Target locales: ${result.targetLocales.length > 0 ? result.targetLocales.map((l) => highlight(l)).join(\", \") : chalk.dim(\"(none)\")}`,\n\t\t\t`Branches: ${result.targetBranches.map((b) => highlight(b)).join(\", \")}`,\n\t\t\t...(repoCanonical\n\t\t\t\t? [`Repository: ${highlight(repoCanonical)}${appDir !== \".\" ? ` (${appDir})` : \"\"}`]\n\t\t\t\t: []),\n\t\t\t\"\",\n\t\t\t`Add this to your .env file:`,\n\t\t\t` ${chalk.bold(\"VOCODER_API_KEY\")}=${highlight(result.apiKey)}`,\n\t\t];\n\n\t\tp.note(lines.join(\"\\n\"), \"Project created\");\n\n\t\tif (!result.repositoryBound && repoCanonical) {\n\t\t\tp.log.warn(\n\t\t\t\t`Repository \"${repoCanonical}\" was not automatically connected. ` +\n\t\t\t\t\t\"Ensure your GitHub App installation covers this repository.\",\n\t\t\t);\n\t\t}\n\n\t\treturn 0;\n\t} catch (error) {\n\t\tspinner.stop(\"Failed to create project.\");\n\n\t\tif (error instanceof VocoderAPIError && error.limitError) {\n\t\t\tconst { limitError } = error;\n\t\t\tp.log.error(limitError.message);\n\t\t\tfor (const line of getLimitErrorGuidance(limitError)) {\n\t\t\t\tp.log.info(line);\n\t\t\t}\n\t\t\treturn 1;\n\t\t}\n\n\t\tp.log.error(\n\t\t\terror instanceof Error ? error.message : \"Unknown error.\",\n\t\t);\n\t\treturn 1;\n\t}\n}\n","import * as p from \"@clack/prompts\";\nimport chalk from \"chalk\";\nimport { VocoderAPI } from \"../utils/api.js\";\nimport { readAuthData } from \"../utils/auth-store.js\";\n\nexport interface WhoamiOptions {\n\tapiUrl?: string;\n}\n\nexport async function whoami(options: WhoamiOptions = {}): Promise<number> {\n\tconst stored = readAuthData();\n\n\tif (!stored) {\n\t\tp.log.info(\"Not logged in. Run `vocoder init` to authenticate.\");\n\t\treturn 1;\n\t}\n\n\tconst apiUrl = options.apiUrl ?? stored.apiUrl ?? \"https://vocoder.app\";\n\tconst api = new VocoderAPI({ apiUrl, apiKey: \"\" });\n\n\ttry {\n\t\tconst info = await api.getCliUserInfo(stored.token);\n\t\tp.log.info(`Logged in as ${chalk.bold(info.email)}`);\n\t\tif (info.name) {\n\t\t\tp.log.info(`Name: ${info.name}`);\n\t\t}\n\t\tp.log.info(`API: ${apiUrl}`);\n\t\treturn 0;\n\t} catch {\n\t\tp.log.error(\n\t\t\t\"Stored credentials are invalid or expired. Run `vocoder init` to re-authenticate.\",\n\t\t);\n\t\treturn 1;\n\t}\n}\n"],"mappings":"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","names":["p","resolve","URL","resolve","resolve","p","chalk","text","p","chalk","execSync","chalk","existsSync","writeFileSync","join","p","chalk","execSync","p","chalk","execSync","execSync","chalk","p","chalk","chalk","p","chalk","p","chalk","resolve","chalk","p","chalk","organizationData","chalk","selectedInstallationId","claimResult","p","chalk","existsSync","resolve","isCancel","p","resolve","existsSync","isCancel","execSync","isCancel","Prompt","S_BAR","S_BAR_END","S_ACTIVE","S_SUBMIT","S_CANCEL","S_ERROR","symbol","execSync","S_BAR","Prompt","symbol","S_BAR_END","isCancel","isCancel","Prompt","p","S_BAR","S_BAR_END","S_ACTIVE","S_SUBMIT","S_CANCEL","S_ERROR","symbol","MAX_VISIBLE","buildList","Prompt","isCancel","chalk","result","chalk","execSync","chalk","spinner","detection","p","chalk","loadEnv","readFileSync","existsSync","readFileSync","writeFileSync","join","p","chalk","execSync","p","loadEnv","loadEnv","p","join","existsSync","readFileSync","writeFileSync","lines","chalk","spinner","duration","loadEnv","readFileSync","spinner","chalk","p","p","chalk","loadEnv","loadEnv","chalk","mkdirSync","writeFileSync","join","p","loadEnv","loadEnv","spinner","mkdirSync","join","writeFileSync","p","chalk","loadEnv","loadEnv","spinner","chalk","p","chalk","info","chalk"]}
|