@dmrlzz/davecode 0.5.1 → 0.5.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/dist/{ChatApp-YMHKIAAH.js → ChatApp-IF5D7XNH.js} +7 -6
  2. package/dist/{ChatApp-YMHKIAAH.js.map → ChatApp-IF5D7XNH.js.map} +1 -1
  3. package/dist/{account-5QFYCVYM.js → account-KBXJ5KR7.js} +4 -3
  4. package/dist/{accounts-756BMMAL.js → accounts-XUJNDCFH.js} +6 -5
  5. package/dist/{budget-PGSNCVVK.js → budget-PHV4NRUS.js} +5 -4
  6. package/dist/{budget-PGSNCVVK.js.map → budget-PHV4NRUS.js.map} +1 -1
  7. package/dist/{chat-D3T4YG5D.js → chat-HGTX76DU.js} +9 -8
  8. package/dist/{chat-D3T4YG5D.js.map → chat-HGTX76DU.js.map} +1 -1
  9. package/dist/chunk-732GIHRQ.js +23 -0
  10. package/dist/chunk-732GIHRQ.js.map +1 -0
  11. package/dist/{chunk-6WUVR3R2.js → chunk-AFCQURO5.js} +3 -3
  12. package/dist/{chunk-6SHOBL2X.js → chunk-DFQW3MRD.js} +2 -2
  13. package/dist/{chunk-JSRPO2AR.js → chunk-EBV5A33R.js} +4 -4
  14. package/dist/{chunk-IOATP7KH.js → chunk-FPSLYBLU.js} +5 -21
  15. package/dist/chunk-FPSLYBLU.js.map +1 -0
  16. package/dist/{chunk-K5AA65RS.js → chunk-FZJNOG2T.js} +2 -2
  17. package/dist/{chunk-HENE4DA6.js → chunk-ING5HCIO.js} +71 -3
  18. package/dist/chunk-ING5HCIO.js.map +1 -0
  19. package/dist/{chunk-JFWMLYV7.js → chunk-YSD6W27K.js} +130 -89
  20. package/dist/chunk-YSD6W27K.js.map +1 -0
  21. package/dist/{chunk-ZNUNYYN6.js → chunk-ZVNX7CSO.js} +3 -3
  22. package/dist/{config-TKGGYEN7.js → config-DG2E4VDW.js} +4 -3
  23. package/dist/{config-TKGGYEN7.js.map → config-DG2E4VDW.js.map} +1 -1
  24. package/dist/dashboard/assets/{Accounts-DciFUg4y.js → Accounts-DXiGsutB.js} +1 -1
  25. package/dist/dashboard/assets/{Callout-WgXHDPg0.js → Callout-1E8Wsl9W.js} +1 -1
  26. package/dist/dashboard/assets/{Goals-C6HL1PNE.js → Goals-kL4VAxw3.js} +1 -1
  27. package/dist/dashboard/assets/{Library-DwpBYTbK.js → Library-DZxBVUo_.js} +1 -1
  28. package/dist/dashboard/assets/{Panes-DxFSwhb7.js → Panes-C-TJekjs.js} +1 -1
  29. package/dist/dashboard/assets/{RoutesPage-Cyo0MNd7.js → RoutesPage-DWYm9tW8.js} +1 -1
  30. package/dist/dashboard/assets/{Runner-CIL7RxpN.js → Runner-CmHBjECR.js} +1 -1
  31. package/dist/dashboard/assets/{Settings-B_PEB585.js → Settings-BANphxva.js} +1 -1
  32. package/dist/dashboard/assets/{Tasks-DEfPSaE6.js → Tasks-cSx1PKyQ.js} +1 -1
  33. package/dist/dashboard/assets/{Traffic-Dcz-WhsP.js → Traffic-DEAuM6jq.js} +1 -1
  34. package/dist/dashboard/assets/{Workspace-9UCw9q7C.js → Workspace-BQFjc1jH.js} +1 -1
  35. package/dist/dashboard/assets/index-B8kld9xo.js +104 -0
  36. package/dist/dashboard/index.html +1 -1
  37. package/dist/{dist-F3NRJ5FK.js → dist-IPMBGFJD.js} +4 -2
  38. package/dist/{doctor-V4XXVVGK.js → doctor-5APOWJ5D.js} +4 -3
  39. package/dist/{doctor-V4XXVVGK.js.map → doctor-5APOWJ5D.js.map} +1 -1
  40. package/dist/{goal-RUHYPVPA.js → goal-ETZWLVKO.js} +4 -3
  41. package/dist/{goal-RUHYPVPA.js.map → goal-ETZWLVKO.js.map} +1 -1
  42. package/dist/index.js +31 -31
  43. package/dist/{init-54FKQZ2Z.js → init-YDLNA3GD.js} +4 -3
  44. package/dist/{init-54FKQZ2Z.js.map → init-YDLNA3GD.js.map} +1 -1
  45. package/dist/{run-4R25J2VN.js → run-I6N7TLHV.js} +4 -3
  46. package/dist/{run-4R25J2VN.js.map → run-I6N7TLHV.js.map} +1 -1
  47. package/dist/runtime.js +3 -2
  48. package/dist/{start-GRHW3TGE.js → start-ECLELJGJ.js} +4 -3
  49. package/dist/{start-GRHW3TGE.js.map → start-ECLELJGJ.js.map} +1 -1
  50. package/dist/{status-QR2HNPBK.js → status-QQPP67I4.js} +5 -4
  51. package/dist/{tasks-BHWDV4JS.js → tasks-RNMC2XFN.js} +5 -4
  52. package/dist/{tasks-BHWDV4JS.js.map → tasks-RNMC2XFN.js.map} +1 -1
  53. package/package.json +4 -4
  54. package/dist/chunk-HENE4DA6.js.map +0 -1
  55. package/dist/chunk-IOATP7KH.js.map +0 -1
  56. package/dist/chunk-JFWMLYV7.js.map +0 -1
  57. package/dist/dashboard/assets/index-CpztPbom.js +0 -104
  58. /package/dist/{account-5QFYCVYM.js.map → account-KBXJ5KR7.js.map} +0 -0
  59. /package/dist/{accounts-756BMMAL.js.map → accounts-XUJNDCFH.js.map} +0 -0
  60. /package/dist/{chunk-6WUVR3R2.js.map → chunk-AFCQURO5.js.map} +0 -0
  61. /package/dist/{chunk-6SHOBL2X.js.map → chunk-DFQW3MRD.js.map} +0 -0
  62. /package/dist/{chunk-JSRPO2AR.js.map → chunk-EBV5A33R.js.map} +0 -0
  63. /package/dist/{chunk-K5AA65RS.js.map → chunk-FZJNOG2T.js.map} +0 -0
  64. /package/dist/{chunk-ZNUNYYN6.js.map → chunk-ZVNX7CSO.js.map} +0 -0
  65. /package/dist/{dist-F3NRJ5FK.js.map → dist-IPMBGFJD.js.map} +0 -0
  66. /package/dist/{status-QR2HNPBK.js.map → status-QQPP67I4.js.map} +0 -0
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/commands/chat.ts","../src/tui/backend.ts","../src/commands/onboard.ts"],"sourcesContent":["import { homedir } from 'node:os';\nimport { resolve, sep } from 'node:path';\nimport { loadConfig, type ProviderKind, VERSION } from '@davecode/core';\nimport { findGateway, GatewayClient } from '../client';\nimport type { CliContext } from '../context';\nimport { CliError, EXIT } from '../errors';\nimport { openAccounts } from '../lib/accounts-backend';\nimport { PromptCancelledError } from '../lib/prompter';\nimport { detectProjectRoot, type Runtime, startRuntime } from '../runtime';\nimport { type ChatBackend, httpBackend } from '../tui/backend';\nimport { chatAccountActions } from './account';\nimport { agentChoices, connectAgent, ensureReady } from './onboard';\n\nexport interface ChatOptions {\n model?: string;\n project?: string;\n}\n\n/**\n * Open the chat TUI against the running gateway, or start an in-process gateway on an ephemeral\n * loopback port when none is running (it stops when the TUI exits).\n */\n/** `C:\\Users\\me\\code\\app` → `~\\code\\app`, for the banner. */\nfunction displayPath(path: string): string {\n const home = homedir();\n return path === home || path.startsWith(home + sep) ? `~${path.slice(home.length)}` : path;\n}\n\nexport async function chatCommand(ctx: CliContext, opts: ChatOptions): Promise<number> {\n if (!ctx.io.stdin.isTTY || !ctx.io.stdout.isTTY) {\n throw new CliError('The chat TUI needs an interactive terminal', {\n hint: 'For scripts, call the OpenAI-compatible API: POST http://127.0.0.1:4040/v1/chat/completions',\n });\n }\n const ready = await ensureReady(ctx);\n if (!ready) return EXIT.failure;\n ctx = ready;\n const projectRoot = opts.project\n ? resolve(ctx.cwd, opts.project)\n : await detectProjectRoot(ctx.cwd, ctx.home);\n // /connect closes the chat so the vendor login can use the terminal, then opens it again.\n for (;;) {\n const provider = await runChat(ctx, opts, projectRoot);\n if (!provider) return EXIT.ok;\n await connectFromChat(ctx, provider);\n }\n}\n\nasync function connectFromChat(ctx: CliContext, provider: ProviderKind): Promise<void> {\n const { createInkPrompter } = await import('../tui/prompts');\n const prompter = createInkPrompter({\n stdout: ctx.io.stdout,\n stdin: ctx.io.stdin,\n theme: ctx.theme,\n });\n const backend = await openAccounts({ home: ctx.home, env: ctx.env, local: true });\n try {\n ctx.out();\n await connectAgent(ctx, provider, prompter, backend);\n } catch (err) {\n if (!(err instanceof PromptCancelledError)) throw err;\n } finally {\n backend.close();\n }\n}\n\n/** One chat session; resolves with the agent picked in /connect, if any. */\nasync function runChat(\n ctx: CliContext,\n opts: ChatOptions,\n projectRoot: string | undefined,\n): Promise<ProviderKind | undefined> {\n const config = loadConfig({\n home: ctx.home,\n env: ctx.env,\n ...(projectRoot ? { projectRoot } : {}),\n });\n\n let runtime: Runtime | undefined;\n let backend: ChatBackend;\n const running = await findGateway(config);\n if (running) {\n backend = httpBackend(running.client, false);\n } else {\n runtime = await startRuntime({\n home: ctx.home,\n env: ctx.env,\n cwd: ctx.cwd,\n host: '127.0.0.1',\n port: 0,\n dashboard: false,\n ...(projectRoot ? { projectDir: projectRoot } : { noProject: true }),\n });\n const target = config.server.authToken\n ? { baseUrl: runtime.url, token: config.server.authToken }\n : { baseUrl: runtime.url };\n backend = httpBackend(new GatewayClient(target), true);\n }\n\n const accountActions = chatAccountActions(ctx);\n let connectTo: ProviderKind | undefined;\n const connect = {\n agents: async () => agentChoices(ctx),\n choose: (provider: string) => {\n connectTo = provider as ProviderKind;\n },\n };\n try {\n const [{ render }, { createElement }, { ChatApp }] = await Promise.all([\n import('ink'),\n import('react'),\n import('../tui/ChatApp'),\n ]);\n const instance = render(\n createElement(ChatApp, {\n backend,\n theme: ctx.theme,\n model: opts.model ?? `davecode/${config.routing.defaultRoute}`,\n version: VERSION,\n project: displayPath(projectRoot ?? ctx.cwd),\n ...(accountActions ? { account: accountActions } : {}),\n connect,\n }),\n {\n stdout: ctx.io.stdout as NodeJS.WriteStream,\n stdin: process.stdin,\n exitOnCtrlC: false,\n kittyKeyboard: { mode: 'auto', flags: ['disambiguateEscapeCodes'] },\n },\n );\n await instance.waitUntilExit();\n } finally {\n await runtime?.close();\n }\n return connectTo;\n}\n","import type {\n Account,\n AccountUsage,\n ChatCompletionChunk,\n ChatRequest,\n ModelInfo,\n Route,\n RunnerStatus,\n TaskGraph,\n} from '@davecode/core';\nimport type { GatewayClient, HealthResponse, StreamMeta } from '../client';\n\n/** What the TUI needs from a gateway. Backed by HTTP in production and by fakes in tests. */\nexport interface ChatBackend {\n /** Base URL, e.g. `http://127.0.0.1:4040`. */\n url: string;\n /** The gateway was started inside this process (no `davecode start` running). */\n inProcess: boolean;\n health(): Promise<HealthResponse | undefined>;\n stream(\n request: ChatRequest,\n signal: AbortSignal,\n ): Promise<{ meta: StreamMeta; chunks: AsyncIterable<ChatCompletionChunk> }>;\n models(): Promise<ModelInfo[]>;\n routes(): Promise<{ defaultRoute: string; routes: Route[] }>;\n accounts(): Promise<Account[]>;\n usage(): Promise<AccountUsage[]>;\n tasks(): Promise<{ project: { root: string; name: string } | null; graph: TaskGraph }>;\n runner(): Promise<RunnerStatus>;\n}\n\nexport function httpBackend(client: GatewayClient, inProcess: boolean): ChatBackend {\n return {\n url: client.baseUrl,\n inProcess,\n health: () => client.health(1500).catch(() => undefined),\n stream: (request, signal) => client.chatStream(request, signal),\n models: async () => (await client.get<{ data: ModelInfo[] }>('/v1/models')).data,\n routes: () => client.get('/api/routes'),\n accounts: async () => (await client.get<{ accounts: Account[] }>('/api/accounts')).accounts,\n usage: async () => (await client.get<{ usage: AccountUsage[] }>('/api/usage')).usage,\n tasks: () => client.get('/api/tasks'),\n runner: async () => (await client.get<{ status: RunnerStatus }>('/api/runner')).status,\n };\n}\n","import { execFile } from 'node:child_process';\nimport {\n CLI_LOGINS,\n loadConfig,\n type ProviderKind,\n type Route,\n VERSION,\n writeGlobalRouting,\n} from '@davecode/core';\nimport type { CliContext } from '../context';\nimport { type AccountsBackend, openAccounts } from '../lib/accounts-backend';\nimport { readPreferences, writePreferences } from '../lib/preferences';\nimport { which as whichOnPath } from '../lib/proc';\nimport { PromptCancelledError, type Prompter } from '../lib/prompter';\nimport { brandBanner } from '../ui/banner';\nimport { createTheme, type ThemeMode } from '../ui/theme';\nimport { type AccountDeps, accountsEnabled, currentAccount, describeUser, signIn } from './account';\nimport { accountsLogin } from './accounts';\n\n/** Agents DaveCode can drive today, in the order they are offered. */\nexport const AGENTS: ReadonlyArray<{\n provider: ProviderKind;\n name: string;\n models: Array<{ value: string; label: string; hint?: string }>;\n}> = [\n {\n provider: 'claude-cli',\n name: 'Claude Code',\n models: [\n { value: 'default', label: 'Default', hint: 'Claude Code decides' },\n { value: 'opus', label: 'Opus', hint: 'most capable' },\n { value: 'sonnet', label: 'Sonnet', hint: 'balanced' },\n { value: 'haiku', label: 'Haiku', hint: 'fastest' },\n ],\n },\n {\n provider: 'codex-cli',\n name: 'Codex',\n models: [{ value: 'default', label: 'Default', hint: 'Codex decides' }],\n },\n {\n provider: 'antigravity-cli',\n name: 'Antigravity',\n models: [{ value: 'default', label: 'Default', hint: 'Antigravity decides' }],\n },\n];\n\ntype ModelChoice = { value: string; label: string; hint?: string };\n\n/** Antigravity lists its models with `agy models` as `id<TAB>name` lines. */\nexport function parseAgyModels(stdout: string): ModelChoice[] {\n return stdout\n .split(/\\r?\\n/)\n .map((line) => line.split('\\t'))\n .filter(([id, name]) => id && name && /^[\\w.:-]+$/.test(id.trim()))\n .map(([id, name]) => ({ value: (id as string).trim(), label: (name as string).trim() }));\n}\n\nfunction agyModels(binary: string, env: NodeJS.ProcessEnv): Promise<ModelChoice[]> {\n return new Promise((resolve) => {\n execFile(binary, ['models'], { env, timeout: 30_000, windowsHide: true }, (error, stdout) =>\n resolve(error ? [] : parseAgyModels(String(stdout))),\n );\n });\n}\n\nconst OTHER_MODEL = '__other__';\n\nexport interface OnboardDeps extends AccountDeps {\n prompter?: Prompter;\n backend?: AccountsBackend;\n which?: (binary: string) => string | undefined;\n /** Models an agent offers beyond its built-in list (defaults to asking `agy models`). */\n models?: (provider: ProviderKind) => Promise<ModelChoice[]>;\n /** Runs the vendor's official login for an account (defaults to `accounts login`). */\n vendorLogin?: (ctx: CliContext, accountId: string) => Promise<number>;\n}\n\nasync function prompterFor(ctx: CliContext, deps: OnboardDeps): Promise<Prompter> {\n if (deps.prompter) return deps.prompter;\n const { createInkPrompter } = await import('../tui/prompts');\n return createInkPrompter({ stdout: ctx.io.stdout, stdin: ctx.io.stdin, theme: ctx.theme });\n}\n\nfunction welcome(ctx: CliContext): void {\n const { theme } = ctx;\n ctx.out();\n const text = [\n `${theme.bold('Welcome to DaveCode')} ${theme.dim(`v${VERSION}`)}`,\n theme.dim('Run Claude Code, Codex and Antigravity side by side.'),\n ];\n for (const line of brandBanner(theme, text, ctx.columns)) ctx.out(` ${line}`);\n ctx.out();\n}\n\nfunction withTheme(ctx: CliContext, mode: ThemeMode): CliContext {\n return {\n ...ctx,\n theme: createTheme({ color: ctx.theme.color, unicode: ctx.theme.unicode, mode }),\n errTheme: createTheme({ color: ctx.errTheme.color, unicode: ctx.errTheme.unicode, mode }),\n };\n}\n\nasync function chooseTheme(ctx: CliContext, prompter: Prompter): Promise<ThemeMode> {\n return prompter.select<ThemeMode>(\n 'Choose a look for the terminal',\n [\n { value: 'dark', label: 'Dark', hint: 'white text on black' },\n { value: 'light', label: 'Light', hint: 'black text on white' },\n { value: 'auto', label: 'Match my terminal' },\n ],\n readPreferences(ctx.home).theme ?? 'dark',\n );\n}\n\nasync function signInStep(ctx: CliContext, prompter: Prompter, deps: OnboardDeps): Promise<void> {\n const choice = await prompter.select('Sign in to continue', [\n { value: 'browser', label: 'Sign in with your browser', hint: 'Google, GitHub or email' },\n { value: 'quit', label: 'Quit' },\n ]);\n if (choice === 'quit') throw new PromptCancelledError();\n const session = await signIn(ctx, deps);\n ctx.out(\n `${ctx.theme.ok(ctx.theme.glyph.ok)} Signed in as ${ctx.theme.bold(describeUser(session))}`,\n );\n ctx.out();\n}\n\nasync function setDefaultRoute(ctx: CliContext, route: Route): Promise<void> {\n const global = loadConfig({ home: ctx.home, env: ctx.env });\n await writeGlobalRouting(ctx.home, {\n routes: [...global.routing.routes.filter((r) => r.name !== route.name), route],\n defaultRoute: route.name,\n });\n}\n\n/**\n * Connect one agent: reuse its account (or create one), run the official login when it is not\n * signed in, choose a model and make it the default route. Returns false when the agent is not\n * installed.\n */\nexport async function connectAgent(\n ctx: CliContext,\n provider: ProviderKind,\n prompter: Prompter,\n backend: AccountsBackend,\n deps: OnboardDeps = {},\n): Promise<boolean> {\n const { theme } = ctx;\n const which = deps.which ?? ((binary: string) => whichOnPath(binary, ctx.env));\n const agent = AGENTS.find((a) => a.provider === provider);\n const spec = CLI_LOGINS[provider];\n if (!agent || !spec) throw new Error(`${provider} is not an agent DaveCode can connect`);\n if (!which(spec.binary)) {\n ctx.out(theme.warn(` ${agent.name} is not installed.`));\n ctx.out(theme.dim(` ${spec.installHint}`));\n ctx.out();\n return false;\n }\n\n const account =\n (await backend.list()).find((a) => a.provider === provider) ??\n (await backend.create({ provider, label: agent.name }));\n const connection = await backend.connection(account.id).catch(() => undefined);\n if (connection?.status !== 'connected' || account.status === 'error') {\n const exit = await (deps.vendorLogin ?? ((c, id) => accountsLogin(c, id, [], {}, { backend })))(\n ctx,\n account.id,\n );\n if (exit !== 0) {\n ctx.out(theme.warn(` ${agent.name} did not finish signing in. You can retry later with:`));\n ctx.out(theme.dim(` davecode accounts login ${account.id}`));\n }\n } else {\n ctx.out(`${theme.ok(theme.glyph.ok)} ${agent.name} is already signed in.`);\n }\n\n const discovered =\n provider === 'antigravity-cli'\n ? await (deps.models ?? (() => agyModels(which(spec.binary) ?? spec.binary, ctx.env)))(\n provider,\n )\n : [];\n let model = await prompter.select(`Model for ${agent.name}`, [\n ...agent.models,\n ...discovered,\n { value: OTHER_MODEL, label: 'Another model…', hint: 'type its id' },\n ]);\n if (model === OTHER_MODEL) {\n model = await prompter.text('Model id', {\n validate: (v) =>\n /^[\\w.:[\\]-]+$/.test(v.trim()) ? undefined : 'Use letters, digits, . : - _',\n });\n model = model.trim();\n }\n await setDefaultRoute(ctx, {\n name: 'auto',\n description: `${agent.name} (${model})`,\n targets: [{ provider, model, accountId: account.id }],\n });\n ctx.out(`${theme.ok(theme.glyph.ok)} DaveCode will use ${theme.bold(agent.name)} · ${model}`);\n ctx.out();\n return true;\n}\n\n/** The agent picker shared by first-run setup and /connect. */\nexport function agentChoices(\n ctx: CliContext,\n deps: Pick<OnboardDeps, 'which'> = {},\n): Array<{ value: ProviderKind; label: string; hint: string }> {\n const which = deps.which ?? ((binary: string) => whichOnPath(binary, ctx.env));\n return AGENTS.map((agent) => ({\n value: agent.provider,\n label: agent.name,\n hint: which(CLI_LOGINS[agent.provider]?.binary ?? '') ? 'installed' : 'not installed',\n }));\n}\n\n/** First agent: pick one that is installed, log in with its official CLI, choose a model. */\nasync function connectAgentStep(\n ctx: CliContext,\n prompter: Prompter,\n backend: AccountsBackend,\n deps: OnboardDeps,\n): Promise<void> {\n for (;;) {\n const choice = await prompter.select<string>('Connect your first agent', [\n ...agentChoices(ctx, deps),\n { value: 'later', label: 'Later', hint: 'davecode accounts add' },\n ]);\n if (choice === 'later') return;\n if (await connectAgent(ctx, choice as ProviderKind, prompter, backend, deps)) return;\n }\n}\n\n/**\n * First-run setup, Claude Code style: logo, look, DaveCode account, first agent. Later runs\n * only ask to sign in again when the session is gone. Returns the context to continue with\n * (the chosen theme applied), or undefined when the user quits.\n */\nexport async function ensureReady(\n ctx: CliContext,\n deps: OnboardDeps = {},\n): Promise<CliContext | undefined> {\n const prefs = readPreferences(ctx.home);\n const needsAccount = accountsEnabled(ctx, deps) && !(await currentAccount(ctx, deps));\n if (prefs.onboarded && !needsAccount) return ctx;\n\n let current = ctx;\n const prompter = await prompterFor(ctx, deps);\n try {\n if (!prefs.onboarded) {\n welcome(ctx);\n const mode = await chooseTheme(ctx, prompter);\n writePreferences(ctx.home, { theme: mode });\n current = withTheme(ctx, mode);\n }\n if (needsAccount) await signInStep(current, prompter, deps);\n if (!prefs.onboarded) {\n const backend =\n deps.backend ?? (await openAccounts({ home: current.home, env: current.env, local: true }));\n try {\n const existing = await backend.list();\n if (existing.length === 0) await connectAgentStep(current, prompter, backend, deps);\n } finally {\n if (!deps.backend) backend.close();\n }\n writePreferences(current.home, { onboarded: true });\n }\n return current;\n } catch (err) {\n if (err instanceof PromptCancelledError) {\n ctx.err(ctx.errTheme.dim('Setup cancelled. Run davecode again to continue.'));\n return undefined;\n }\n throw err;\n }\n}\n"],"mappings":"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","names":["resolve","which"]}
1
+ {"version":3,"sources":["../src/commands/chat.ts","../src/tui/backend.ts","../src/commands/onboard.ts"],"sourcesContent":["import { homedir } from 'node:os';\nimport { resolve, sep } from 'node:path';\nimport { loadConfig, type ProviderKind, VERSION } from '@davecode/core';\nimport { findGateway, GatewayClient } from '../client';\nimport type { CliContext } from '../context';\nimport { CliError, EXIT } from '../errors';\nimport { openAccounts } from '../lib/accounts-backend';\nimport { PromptCancelledError } from '../lib/prompter';\nimport { detectProjectRoot, type Runtime, startRuntime } from '../runtime';\nimport { type ChatBackend, httpBackend } from '../tui/backend';\nimport { chatAccountActions } from './account';\nimport { agentChoices, connectAgent, ensureReady } from './onboard';\n\nexport interface ChatOptions {\n model?: string;\n project?: string;\n}\n\n/**\n * Open the chat TUI against the running gateway, or start an in-process gateway on an ephemeral\n * loopback port when none is running (it stops when the TUI exits).\n */\n/** `C:\\Users\\me\\code\\app` → `~\\code\\app`, for the banner. */\nfunction displayPath(path: string): string {\n const home = homedir();\n return path === home || path.startsWith(home + sep) ? `~${path.slice(home.length)}` : path;\n}\n\nexport async function chatCommand(ctx: CliContext, opts: ChatOptions): Promise<number> {\n if (!ctx.io.stdin.isTTY || !ctx.io.stdout.isTTY) {\n throw new CliError('The chat TUI needs an interactive terminal', {\n hint: 'For scripts, call the OpenAI-compatible API: POST http://127.0.0.1:4040/v1/chat/completions',\n });\n }\n const ready = await ensureReady(ctx);\n if (!ready) return EXIT.failure;\n ctx = ready;\n const projectRoot = opts.project\n ? resolve(ctx.cwd, opts.project)\n : await detectProjectRoot(ctx.cwd, ctx.home);\n // /connect closes the chat so the vendor login can use the terminal, then opens it again.\n for (;;) {\n const provider = await runChat(ctx, opts, projectRoot);\n if (!provider) return EXIT.ok;\n await connectFromChat(ctx, provider);\n }\n}\n\nasync function connectFromChat(ctx: CliContext, provider: ProviderKind): Promise<void> {\n const { createInkPrompter } = await import('../tui/prompts');\n const prompter = createInkPrompter({\n stdout: ctx.io.stdout,\n stdin: ctx.io.stdin,\n theme: ctx.theme,\n });\n const backend = await openAccounts({ home: ctx.home, env: ctx.env, local: true });\n try {\n ctx.out();\n await connectAgent(ctx, provider, prompter, backend);\n } catch (err) {\n if (!(err instanceof PromptCancelledError)) throw err;\n } finally {\n backend.close();\n }\n}\n\n/** One chat session; resolves with the agent picked in /connect, if any. */\nasync function runChat(\n ctx: CliContext,\n opts: ChatOptions,\n projectRoot: string | undefined,\n): Promise<ProviderKind | undefined> {\n const config = loadConfig({\n home: ctx.home,\n env: ctx.env,\n ...(projectRoot ? { projectRoot } : {}),\n });\n\n let runtime: Runtime | undefined;\n let backend: ChatBackend;\n const running = await findGateway(config);\n if (running) {\n backend = httpBackend(running.client, false);\n } else {\n runtime = await startRuntime({\n home: ctx.home,\n env: ctx.env,\n cwd: ctx.cwd,\n host: '127.0.0.1',\n port: 0,\n dashboard: false,\n ...(projectRoot ? { projectDir: projectRoot } : { noProject: true }),\n });\n const target = config.server.authToken\n ? { baseUrl: runtime.url, token: config.server.authToken }\n : { baseUrl: runtime.url };\n backend = httpBackend(new GatewayClient(target), true);\n }\n\n const accountActions = chatAccountActions(ctx);\n let connectTo: ProviderKind | undefined;\n const connect = {\n agents: async () => agentChoices(ctx),\n choose: (provider: string) => {\n connectTo = provider as ProviderKind;\n },\n };\n try {\n const [{ render }, { createElement }, { ChatApp }] = await Promise.all([\n import('ink'),\n import('react'),\n import('../tui/ChatApp'),\n ]);\n const instance = render(\n createElement(ChatApp, {\n backend,\n theme: ctx.theme,\n model: opts.model ?? `davecode/${config.routing.defaultRoute}`,\n version: VERSION,\n project: displayPath(projectRoot ?? ctx.cwd),\n ...(accountActions ? { account: accountActions } : {}),\n connect,\n }),\n {\n stdout: ctx.io.stdout as NodeJS.WriteStream,\n stdin: process.stdin,\n exitOnCtrlC: false,\n kittyKeyboard: { mode: 'auto', flags: ['disambiguateEscapeCodes'] },\n },\n );\n await instance.waitUntilExit();\n } finally {\n await runtime?.close();\n }\n return connectTo;\n}\n","import type {\n Account,\n AccountUsage,\n ChatCompletionChunk,\n ChatRequest,\n ModelInfo,\n Route,\n RunnerStatus,\n TaskGraph,\n} from '@davecode/core';\nimport type { GatewayClient, HealthResponse, StreamMeta } from '../client';\n\n/** What the TUI needs from a gateway. Backed by HTTP in production and by fakes in tests. */\nexport interface ChatBackend {\n /** Base URL, e.g. `http://127.0.0.1:4040`. */\n url: string;\n /** The gateway was started inside this process (no `davecode start` running). */\n inProcess: boolean;\n health(): Promise<HealthResponse | undefined>;\n stream(\n request: ChatRequest,\n signal: AbortSignal,\n ): Promise<{ meta: StreamMeta; chunks: AsyncIterable<ChatCompletionChunk> }>;\n models(): Promise<ModelInfo[]>;\n routes(): Promise<{ defaultRoute: string; routes: Route[] }>;\n accounts(): Promise<Account[]>;\n usage(): Promise<AccountUsage[]>;\n tasks(): Promise<{ project: { root: string; name: string } | null; graph: TaskGraph }>;\n runner(): Promise<RunnerStatus>;\n}\n\nexport function httpBackend(client: GatewayClient, inProcess: boolean): ChatBackend {\n return {\n url: client.baseUrl,\n inProcess,\n health: () => client.health(1500).catch(() => undefined),\n stream: (request, signal) => client.chatStream(request, signal),\n models: async () => (await client.get<{ data: ModelInfo[] }>('/v1/models')).data,\n routes: () => client.get('/api/routes'),\n accounts: async () => (await client.get<{ accounts: Account[] }>('/api/accounts')).accounts,\n usage: async () => (await client.get<{ usage: AccountUsage[] }>('/api/usage')).usage,\n tasks: () => client.get('/api/tasks'),\n runner: async () => (await client.get<{ status: RunnerStatus }>('/api/runner')).status,\n };\n}\n","import { execFile } from 'node:child_process';\nimport {\n CLI_LOGINS,\n loadConfig,\n type ProviderKind,\n type Route,\n VERSION,\n writeGlobalRouting,\n} from '@davecode/core';\nimport type { CliContext } from '../context';\nimport { type AccountsBackend, openAccounts } from '../lib/accounts-backend';\nimport { readPreferences, writePreferences } from '../lib/preferences';\nimport { which as whichOnPath } from '../lib/proc';\nimport { PromptCancelledError, type Prompter } from '../lib/prompter';\nimport { brandBanner } from '../ui/banner';\nimport { createTheme, type ThemeMode } from '../ui/theme';\nimport { type AccountDeps, accountsEnabled, currentAccount, describeUser, signIn } from './account';\nimport { accountsLogin } from './accounts';\n\n/** Agents DaveCode can drive today, in the order they are offered. */\nexport const AGENTS: ReadonlyArray<{\n provider: ProviderKind;\n name: string;\n models: Array<{ value: string; label: string; hint?: string }>;\n}> = [\n {\n provider: 'claude-cli',\n name: 'Claude Code',\n models: [\n { value: 'default', label: 'Default', hint: 'Claude Code decides' },\n { value: 'opus', label: 'Opus', hint: 'most capable' },\n { value: 'sonnet', label: 'Sonnet', hint: 'balanced' },\n { value: 'haiku', label: 'Haiku', hint: 'fastest' },\n ],\n },\n {\n provider: 'codex-cli',\n name: 'Codex',\n models: [{ value: 'default', label: 'Default', hint: 'Codex decides' }],\n },\n {\n provider: 'antigravity-cli',\n name: 'Antigravity',\n models: [{ value: 'default', label: 'Default', hint: 'Antigravity decides' }],\n },\n];\n\ntype ModelChoice = { value: string; label: string; hint?: string };\n\n/** Antigravity lists its models with `agy models` as `id<TAB>name` lines. */\nexport function parseAgyModels(stdout: string): ModelChoice[] {\n return stdout\n .split(/\\r?\\n/)\n .map((line) => line.split('\\t'))\n .filter(([id, name]) => id && name && /^[\\w.:-]+$/.test(id.trim()))\n .map(([id, name]) => ({ value: (id as string).trim(), label: (name as string).trim() }));\n}\n\nfunction agyModels(binary: string, env: NodeJS.ProcessEnv): Promise<ModelChoice[]> {\n return new Promise((resolve) => {\n execFile(binary, ['models'], { env, timeout: 30_000, windowsHide: true }, (error, stdout) =>\n resolve(error ? [] : parseAgyModels(String(stdout))),\n );\n });\n}\n\nconst OTHER_MODEL = '__other__';\n\nexport interface OnboardDeps extends AccountDeps {\n prompter?: Prompter;\n backend?: AccountsBackend;\n which?: (binary: string) => string | undefined;\n /** Models an agent offers beyond its built-in list (defaults to asking `agy models`). */\n models?: (provider: ProviderKind) => Promise<ModelChoice[]>;\n /** Runs the vendor's official login for an account (defaults to `accounts login`). */\n vendorLogin?: (ctx: CliContext, accountId: string) => Promise<number>;\n}\n\nasync function prompterFor(ctx: CliContext, deps: OnboardDeps): Promise<Prompter> {\n if (deps.prompter) return deps.prompter;\n const { createInkPrompter } = await import('../tui/prompts');\n return createInkPrompter({ stdout: ctx.io.stdout, stdin: ctx.io.stdin, theme: ctx.theme });\n}\n\nfunction welcome(ctx: CliContext): void {\n const { theme } = ctx;\n ctx.out();\n const text = [\n `${theme.bold('Welcome to DaveCode')} ${theme.dim(`v${VERSION}`)}`,\n theme.dim('Run Claude Code, Codex and Antigravity side by side.'),\n ];\n for (const line of brandBanner(theme, text, ctx.columns)) ctx.out(` ${line}`);\n ctx.out();\n}\n\nfunction withTheme(ctx: CliContext, mode: ThemeMode): CliContext {\n return {\n ...ctx,\n theme: createTheme({ color: ctx.theme.color, unicode: ctx.theme.unicode, mode }),\n errTheme: createTheme({ color: ctx.errTheme.color, unicode: ctx.errTheme.unicode, mode }),\n };\n}\n\nasync function chooseTheme(ctx: CliContext, prompter: Prompter): Promise<ThemeMode> {\n return prompter.select<ThemeMode>(\n 'Choose a look for the terminal',\n [\n { value: 'dark', label: 'Dark', hint: 'white text on black' },\n { value: 'light', label: 'Light', hint: 'black text on white' },\n { value: 'auto', label: 'Match my terminal' },\n ],\n readPreferences(ctx.home).theme ?? 'dark',\n );\n}\n\nasync function signInStep(ctx: CliContext, prompter: Prompter, deps: OnboardDeps): Promise<void> {\n const choice = await prompter.select('Sign in to continue', [\n { value: 'browser', label: 'Sign in with your browser', hint: 'Google, GitHub or email' },\n { value: 'quit', label: 'Quit' },\n ]);\n if (choice === 'quit') throw new PromptCancelledError();\n const session = await signIn(ctx, deps);\n ctx.out(\n `${ctx.theme.ok(ctx.theme.glyph.ok)} Signed in as ${ctx.theme.bold(describeUser(session))}`,\n );\n ctx.out();\n}\n\nasync function setDefaultRoute(ctx: CliContext, route: Route): Promise<void> {\n const global = loadConfig({ home: ctx.home, env: ctx.env });\n await writeGlobalRouting(ctx.home, {\n routes: [...global.routing.routes.filter((r) => r.name !== route.name), route],\n defaultRoute: route.name,\n });\n}\n\n/**\n * Connect one agent: reuse its account (or create one), run the official login when it is not\n * signed in, choose a model and make it the default route. Returns false when the agent is not\n * installed.\n */\nexport async function connectAgent(\n ctx: CliContext,\n provider: ProviderKind,\n prompter: Prompter,\n backend: AccountsBackend,\n deps: OnboardDeps = {},\n): Promise<boolean> {\n const { theme } = ctx;\n const which = deps.which ?? ((binary: string) => whichOnPath(binary, ctx.env));\n const agent = AGENTS.find((a) => a.provider === provider);\n const spec = CLI_LOGINS[provider];\n if (!agent || !spec) throw new Error(`${provider} is not an agent DaveCode can connect`);\n if (!which(spec.binary)) {\n ctx.out(theme.warn(` ${agent.name} is not installed.`));\n ctx.out(theme.dim(` ${spec.installHint}`));\n ctx.out();\n return false;\n }\n\n const account =\n (await backend.list()).find((a) => a.provider === provider) ??\n (await backend.create({ provider, label: agent.name }));\n const connection = await backend.connection(account.id).catch(() => undefined);\n if (connection?.status !== 'connected' || account.status === 'error') {\n const exit = await (deps.vendorLogin ?? ((c, id) => accountsLogin(c, id, [], {}, { backend })))(\n ctx,\n account.id,\n );\n if (exit !== 0) {\n ctx.out(theme.warn(` ${agent.name} did not finish signing in. You can retry later with:`));\n ctx.out(theme.dim(` davecode accounts login ${account.id}`));\n }\n } else {\n ctx.out(`${theme.ok(theme.glyph.ok)} ${agent.name} is already signed in.`);\n }\n\n const discovered =\n provider === 'antigravity-cli'\n ? await (deps.models ?? (() => agyModels(which(spec.binary) ?? spec.binary, ctx.env)))(\n provider,\n )\n : [];\n let model = await prompter.select(`Model for ${agent.name}`, [\n ...agent.models,\n ...discovered,\n { value: OTHER_MODEL, label: 'Another model…', hint: 'type its id' },\n ]);\n if (model === OTHER_MODEL) {\n model = await prompter.text('Model id', {\n validate: (v) =>\n /^[\\w.:[\\]-]+$/.test(v.trim()) ? undefined : 'Use letters, digits, . : - _',\n });\n model = model.trim();\n }\n await setDefaultRoute(ctx, {\n name: 'auto',\n description: `${agent.name} (${model})`,\n targets: [{ provider, model, accountId: account.id }],\n });\n ctx.out(`${theme.ok(theme.glyph.ok)} DaveCode will use ${theme.bold(agent.name)} · ${model}`);\n ctx.out();\n return true;\n}\n\n/** The agent picker shared by first-run setup and /connect. */\nexport function agentChoices(\n ctx: CliContext,\n deps: Pick<OnboardDeps, 'which'> = {},\n): Array<{ value: ProviderKind; label: string; hint: string }> {\n const which = deps.which ?? ((binary: string) => whichOnPath(binary, ctx.env));\n return AGENTS.map((agent) => ({\n value: agent.provider,\n label: agent.name,\n hint: which(CLI_LOGINS[agent.provider]?.binary ?? '') ? 'installed' : 'not installed',\n }));\n}\n\n/** First agent: pick one that is installed, log in with its official CLI, choose a model. */\nasync function connectAgentStep(\n ctx: CliContext,\n prompter: Prompter,\n backend: AccountsBackend,\n deps: OnboardDeps,\n): Promise<void> {\n for (;;) {\n const choice = await prompter.select<string>('Connect your first agent', [\n ...agentChoices(ctx, deps),\n { value: 'later', label: 'Later', hint: 'davecode accounts add' },\n ]);\n if (choice === 'later') return;\n if (await connectAgent(ctx, choice as ProviderKind, prompter, backend, deps)) return;\n }\n}\n\n/**\n * First-run setup, Claude Code style: logo, look, DaveCode account, first agent. Later runs\n * only ask to sign in again when the session is gone. Returns the context to continue with\n * (the chosen theme applied), or undefined when the user quits.\n */\nexport async function ensureReady(\n ctx: CliContext,\n deps: OnboardDeps = {},\n): Promise<CliContext | undefined> {\n const prefs = readPreferences(ctx.home);\n const needsAccount = accountsEnabled(ctx, deps) && !(await currentAccount(ctx, deps));\n if (prefs.onboarded && !needsAccount) return ctx;\n\n let current = ctx;\n const prompter = await prompterFor(ctx, deps);\n try {\n if (!prefs.onboarded) {\n welcome(ctx);\n const mode = await chooseTheme(ctx, prompter);\n writePreferences(ctx.home, { theme: mode });\n current = withTheme(ctx, mode);\n }\n if (needsAccount) await signInStep(current, prompter, deps);\n if (!prefs.onboarded) {\n const backend =\n deps.backend ?? (await openAccounts({ home: current.home, env: current.env, local: true }));\n try {\n const existing = await backend.list();\n if (existing.length === 0) await connectAgentStep(current, prompter, backend, deps);\n } finally {\n if (!deps.backend) backend.close();\n }\n writePreferences(current.home, { onboarded: true });\n }\n return current;\n } catch (err) {\n if (err instanceof PromptCancelledError) {\n ctx.err(ctx.errTheme.dim('Setup cancelled. Run davecode again to continue.'));\n return undefined;\n }\n throw err;\n }\n}\n"],"mappings":"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","names":["resolve","which"]}
@@ -0,0 +1,23 @@
1
+ // src/lib/browser.ts
2
+ import { spawn } from "child_process";
3
+ var detached = (command, args) => new Promise((resolve) => {
4
+ const child = spawn(command, args, { detached: true, stdio: "ignore", windowsHide: true });
5
+ child.once("error", () => resolve(false));
6
+ child.once("spawn", () => {
7
+ child.unref();
8
+ resolve(true);
9
+ });
10
+ });
11
+ async function openBrowser(url, platform = process.platform, launch = detached) {
12
+ const parsed = new URL(url);
13
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") return false;
14
+ const target = parsed.toString();
15
+ if (platform === "win32") return launch("rundll32", ["url.dll,FileProtocolHandler", target]);
16
+ if (platform === "darwin") return launch("open", [target]);
17
+ return launch("xdg-open", [target]);
18
+ }
19
+
20
+ export {
21
+ openBrowser
22
+ };
23
+ //# sourceMappingURL=chunk-732GIHRQ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/lib/browser.ts"],"sourcesContent":["import { spawn } from 'node:child_process';\n\nexport type Launcher = (command: string, args: string[]) => Promise<boolean>;\n\nconst detached: Launcher = (command, args) =>\n new Promise((resolve) => {\n const child = spawn(command, args, { detached: true, stdio: 'ignore', windowsHide: true });\n child.once('error', () => resolve(false));\n child.once('spawn', () => {\n child.unref();\n resolve(true);\n });\n });\n\n/**\n * Open an http(s) URL in the default browser. Returns false when nothing could be launched, so\n * the caller can print the URL instead.\n */\nexport async function openBrowser(\n url: string,\n platform: NodeJS.Platform = process.platform,\n launch: Launcher = detached,\n): Promise<boolean> {\n const parsed = new URL(url);\n if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') return false;\n const target = parsed.toString();\n // No shell is involved, so the URL is never interpreted as a command.\n if (platform === 'win32') return launch('rundll32', ['url.dll,FileProtocolHandler', target]);\n if (platform === 'darwin') return launch('open', [target]);\n return launch('xdg-open', [target]);\n}\n"],"mappings":";AAAA,SAAS,aAAa;AAItB,IAAM,WAAqB,CAAC,SAAS,SACnC,IAAI,QAAQ,CAAC,YAAY;AACvB,QAAM,QAAQ,MAAM,SAAS,MAAM,EAAE,UAAU,MAAM,OAAO,UAAU,aAAa,KAAK,CAAC;AACzF,QAAM,KAAK,SAAS,MAAM,QAAQ,KAAK,CAAC;AACxC,QAAM,KAAK,SAAS,MAAM;AACxB,UAAM,MAAM;AACZ,YAAQ,IAAI;AAAA,EACd,CAAC;AACH,CAAC;AAMH,eAAsB,YACpB,KACA,WAA4B,QAAQ,UACpC,SAAmB,UACD;AAClB,QAAM,SAAS,IAAI,IAAI,GAAG;AAC1B,MAAI,OAAO,aAAa,WAAW,OAAO,aAAa,SAAU,QAAO;AACxE,QAAM,SAAS,OAAO,SAAS;AAE/B,MAAI,aAAa,QAAS,QAAO,OAAO,YAAY,CAAC,+BAA+B,MAAM,CAAC;AAC3F,MAAI,aAAa,SAAU,QAAO,OAAO,QAAQ,CAAC,MAAM,CAAC;AACzD,SAAO,OAAO,YAAY,CAAC,MAAM,CAAC;AACpC;","names":[]}
@@ -2,14 +2,14 @@ import {
2
2
  accountCreateSchema,
3
3
  accountPatchSchema,
4
4
  findGateway
5
- } from "./chunk-JFWMLYV7.js";
5
+ } from "./chunk-YSD6W27K.js";
6
6
  import {
7
7
  CliError
8
8
  } from "./chunk-7XVXEO7U.js";
9
9
  import {
10
10
  createEngine,
11
11
  endpointRebindIssue
12
- } from "./chunk-HENE4DA6.js";
12
+ } from "./chunk-ING5HCIO.js";
13
13
 
14
14
  // src/lib/accounts-backend.ts
15
15
  import { z } from "zod";
@@ -183,4 +183,4 @@ export {
183
183
  openAccounts,
184
184
  resolveAccount
185
185
  };
186
- //# sourceMappingURL=chunk-6WUVR3R2.js.map
186
+ //# sourceMappingURL=chunk-AFCQURO5.js.map
@@ -7,7 +7,7 @@ import {
7
7
  nextTask,
8
8
  summarize,
9
9
  topologicalOrder
10
- } from "./chunk-HENE4DA6.js";
10
+ } from "./chunk-ING5HCIO.js";
11
11
 
12
12
  // src/lib/task-tree.ts
13
13
  function statusGlyph(theme, task, blocked) {
@@ -111,4 +111,4 @@ export {
111
111
  formatTaskTree,
112
112
  formatTaskDetail
113
113
  };
114
- //# sourceMappingURL=chunk-6SHOBL2X.js.map
114
+ //# sourceMappingURL=chunk-DFQW3MRD.js.map
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  openAccounts,
3
3
  resolveAccount
4
- } from "./chunk-6WUVR3R2.js";
4
+ } from "./chunk-AFCQURO5.js";
5
5
  import {
6
6
  PromptCancelledError
7
7
  } from "./chunk-IC3TDONV.js";
@@ -16,7 +16,7 @@ import {
16
16
  detectProjectRoot,
17
17
  spawnInteractive,
18
18
  which
19
- } from "./chunk-JFWMLYV7.js";
19
+ } from "./chunk-YSD6W27K.js";
20
20
  import {
21
21
  CliError,
22
22
  EXIT
@@ -29,7 +29,7 @@ import {
29
29
  cliBinaryFor,
30
30
  globalPaths,
31
31
  loginEnv
32
- } from "./chunk-HENE4DA6.js";
32
+ } from "./chunk-ING5HCIO.js";
33
33
 
34
34
  // src/commands/accounts.ts
35
35
  import { createInterface } from "readline";
@@ -729,4 +729,4 @@ export {
729
729
  accountsLogin,
730
730
  accountsConnect
731
731
  };
732
- //# sourceMappingURL=chunk-JSRPO2AR.js.map
732
+ //# sourceMappingURL=chunk-EBV5A33R.js.map
@@ -2,31 +2,15 @@ import {
2
2
  CliError,
3
3
  EXIT
4
4
  } from "./chunk-7XVXEO7U.js";
5
+ import {
6
+ openBrowser
7
+ } from "./chunk-732GIHRQ.js";
5
8
  import {
6
9
  AccountClient,
7
10
  AccountStore,
8
11
  accountService,
9
12
  startAccountLogin
10
- } from "./chunk-HENE4DA6.js";
11
-
12
- // src/lib/browser.ts
13
- import { spawn } from "child_process";
14
- var detached = (command, args) => new Promise((resolve) => {
15
- const child = spawn(command, args, { detached: true, stdio: "ignore", windowsHide: true });
16
- child.once("error", () => resolve(false));
17
- child.once("spawn", () => {
18
- child.unref();
19
- resolve(true);
20
- });
21
- });
22
- async function openBrowser(url, platform = process.platform, launch = detached) {
23
- const parsed = new URL(url);
24
- if (parsed.protocol !== "http:" && parsed.protocol !== "https:") return false;
25
- const target = parsed.toString();
26
- if (platform === "win32") return launch("rundll32", ["url.dll,FileProtocolHandler", target]);
27
- if (platform === "darwin") return launch("open", [target]);
28
- return launch("xdg-open", [target]);
29
- }
13
+ } from "./chunk-ING5HCIO.js";
30
14
 
31
15
  // src/commands/account.ts
32
16
  function serviceFor(ctx, deps) {
@@ -141,4 +125,4 @@ export {
141
125
  accountCommand,
142
126
  chatAccountActions
143
127
  };
144
- //# sourceMappingURL=chunk-IOATP7KH.js.map
128
+ //# sourceMappingURL=chunk-FPSLYBLU.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/account.ts"],"sourcesContent":["import {\n AccountClient,\n type AccountServiceConfig,\n type AccountSession,\n AccountStore,\n accountService,\n startAccountLogin,\n} from '@davecode/core';\nimport type { CliContext } from '../context';\nimport { CliError, EXIT } from '../errors';\nimport { openBrowser } from '../lib/browser';\n\nexport interface AccountDeps {\n service?: AccountServiceConfig;\n fetch?: typeof fetch;\n open?: (url: string) => Promise<boolean>;\n}\n\nfunction serviceFor(ctx: CliContext, deps: AccountDeps): AccountServiceConfig | undefined {\n return deps.service ?? accountService(ctx.env);\n}\n\nfunction clientFor(service: AccountServiceConfig, deps: AccountDeps): AccountClient {\n return new AccountClient(service, deps.fetch ? { fetch: deps.fetch } : {});\n}\n\nexport function describeUser(session: AccountSession): string {\n return session.user.email ?? session.user.name ?? session.user.id;\n}\n\n/** The signed-in session (refreshed when needed), or undefined. */\nexport async function currentAccount(\n ctx: CliContext,\n deps: AccountDeps = {},\n): Promise<AccountSession | undefined> {\n const service = serviceFor(ctx, deps);\n if (!service) return undefined;\n return new AccountStore(ctx.home, ctx.env).current(clientFor(service, deps));\n}\n\n/** Whether this build signs in to DaveCode accounts at all (it needs a configured service). */\nexport function accountsEnabled(ctx: CliContext, deps: AccountDeps = {}): boolean {\n return serviceFor(ctx, deps) !== undefined;\n}\n\n/**\n * Open the browser sign-in page and wait for it to finish. Prints the URL too, for machines\n * where no browser can be launched (SSH, containers).\n */\nexport async function signIn(\n ctx: CliContext,\n deps: AccountDeps = {},\n announce?: (url: string, opened: boolean) => void,\n): Promise<AccountSession> {\n const service = serviceFor(ctx, deps);\n if (!service) {\n throw new CliError('DaveCode accounts are not available in this build');\n }\n const { theme } = ctx;\n const login = await startAccountLogin({ client: clientFor(service, deps) });\n const opened = await (deps.open ?? openBrowser)(login.url).catch(() => false);\n if (announce) announce(login.url, opened);\n else {\n ctx.out(\n opened\n ? `${theme.accent(theme.glyph.arrow)} Opened your browser to sign in.`\n : `${theme.accent(theme.glyph.arrow)} Open this link to sign in:`,\n );\n ctx.out(theme.dim(` ${login.url}`));\n ctx.out(theme.dim(' Waiting for you to finish in the browser. Ctrl+C cancels.'));\n }\n const cancel = () => void login.close();\n process.once('SIGINT', cancel);\n try {\n const session = await login.session;\n new AccountStore(ctx.home, ctx.env).save(session);\n return session;\n } finally {\n process.off('SIGINT', cancel);\n }\n}\n\nexport async function loginCommand(ctx: CliContext, deps: AccountDeps = {}): Promise<number> {\n const session = await signIn(ctx, deps);\n ctx.out(\n `${ctx.theme.ok(ctx.theme.glyph.ok)} Signed in as ${ctx.theme.bold(describeUser(session))}`,\n );\n return EXIT.ok;\n}\n\nexport async function logoutCommand(ctx: CliContext, deps: AccountDeps = {}): Promise<number> {\n const store = new AccountStore(ctx.home, ctx.env);\n const session = store.load();\n const service = serviceFor(ctx, deps);\n if (session && service) await clientFor(service, deps).signOut(session.accessToken);\n store.clear();\n ctx.out(session ? 'Signed out.' : 'You were not signed in.');\n return EXIT.ok;\n}\n\nexport async function accountCommand(ctx: CliContext, deps: AccountDeps = {}): Promise<number> {\n const session = await currentAccount(ctx, deps);\n if (ctx.json) {\n ctx.out(JSON.stringify({ signedIn: Boolean(session), user: session?.user ?? null }));\n return session ? EXIT.ok : EXIT.failure;\n }\n if (!session) {\n ctx.out(`Not signed in. Run ${ctx.theme.accent('davecode login')}.`);\n return EXIT.failure;\n }\n const via = session.user.provider ? ctx.theme.dim(` (${session.user.provider})`) : '';\n ctx.out(`Signed in as ${ctx.theme.bold(describeUser(session))}${via}`);\n return EXIT.ok;\n}\n\n/** Account actions for the chat's /login, /logout and /account (they return text, never print). */\nexport interface ChatAccountActions {\n status(): Promise<string>;\n login(notify: (text: string) => void): Promise<string>;\n logout(): Promise<string>;\n}\n\nexport function chatAccountActions(\n ctx: CliContext,\n deps: AccountDeps = {},\n): ChatAccountActions | undefined {\n if (!accountsEnabled(ctx, deps)) return undefined;\n return {\n status: async () => {\n const session = await currentAccount(ctx, deps);\n return session ? `Signed in as ${describeUser(session)}` : 'Not signed in. Type /login.';\n },\n login: async (notify) => {\n const session = await signIn(ctx, deps, (url, opened) =>\n notify(\n `${opened ? 'Opened your browser to sign in.' : 'Open this link to sign in:'}\\n${url}`,\n ),\n );\n return `Signed in as ${describeUser(session)}`;\n },\n logout: async () => {\n const store = new AccountStore(ctx.home, ctx.env);\n const session = store.load();\n const service = serviceFor(ctx, deps);\n if (session && service) await clientFor(service, deps).signOut(session.accessToken);\n store.clear();\n return session ? 'Signed out. Type /login to sign in again.' : 'You were not signed in.';\n },\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;AAkBA,SAAS,WAAW,KAAiB,MAAqD;AACxF,SAAO,KAAK,WAAW,eAAe,IAAI,GAAG;AAC/C;AAEA,SAAS,UAAU,SAA+B,MAAkC;AAClF,SAAO,IAAI,cAAc,SAAS,KAAK,QAAQ,EAAE,OAAO,KAAK,MAAM,IAAI,CAAC,CAAC;AAC3E;AAEO,SAAS,aAAa,SAAiC;AAC5D,SAAO,QAAQ,KAAK,SAAS,QAAQ,KAAK,QAAQ,QAAQ,KAAK;AACjE;AAGA,eAAsB,eACpB,KACA,OAAoB,CAAC,GACgB;AACrC,QAAM,UAAU,WAAW,KAAK,IAAI;AACpC,MAAI,CAAC,QAAS,QAAO;AACrB,SAAO,IAAI,aAAa,IAAI,MAAM,IAAI,GAAG,EAAE,QAAQ,UAAU,SAAS,IAAI,CAAC;AAC7E;AAGO,SAAS,gBAAgB,KAAiB,OAAoB,CAAC,GAAY;AAChF,SAAO,WAAW,KAAK,IAAI,MAAM;AACnC;AAMA,eAAsB,OACpB,KACA,OAAoB,CAAC,GACrB,UACyB;AACzB,QAAM,UAAU,WAAW,KAAK,IAAI;AACpC,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI,SAAS,mDAAmD;AAAA,EACxE;AACA,QAAM,EAAE,MAAM,IAAI;AAClB,QAAM,QAAQ,MAAM,kBAAkB,EAAE,QAAQ,UAAU,SAAS,IAAI,EAAE,CAAC;AAC1E,QAAM,SAAS,OAAO,KAAK,QAAQ,aAAa,MAAM,GAAG,EAAE,MAAM,MAAM,KAAK;AAC5E,MAAI,SAAU,UAAS,MAAM,KAAK,MAAM;AAAA,OACnC;AACH,QAAI;AAAA,MACF,SACI,GAAG,MAAM,OAAO,MAAM,MAAM,KAAK,CAAC,qCAClC,GAAG,MAAM,OAAO,MAAM,MAAM,KAAK,CAAC;AAAA,IACxC;AACA,QAAI,IAAI,MAAM,IAAI,KAAK,MAAM,GAAG,EAAE,CAAC;AACnC,QAAI,IAAI,MAAM,IAAI,6DAA6D,CAAC;AAAA,EAClF;AACA,QAAM,SAAS,MAAM,KAAK,MAAM,MAAM;AACtC,UAAQ,KAAK,UAAU,MAAM;AAC7B,MAAI;AACF,UAAM,UAAU,MAAM,MAAM;AAC5B,QAAI,aAAa,IAAI,MAAM,IAAI,GAAG,EAAE,KAAK,OAAO;AAChD,WAAO;AAAA,EACT,UAAE;AACA,YAAQ,IAAI,UAAU,MAAM;AAAA,EAC9B;AACF;AAEA,eAAsB,aAAa,KAAiB,OAAoB,CAAC,GAAoB;AAC3F,QAAM,UAAU,MAAM,OAAO,KAAK,IAAI;AACtC,MAAI;AAAA,IACF,GAAG,IAAI,MAAM,GAAG,IAAI,MAAM,MAAM,EAAE,CAAC,iBAAiB,IAAI,MAAM,KAAK,aAAa,OAAO,CAAC,CAAC;AAAA,EAC3F;AACA,SAAO,KAAK;AACd;AAEA,eAAsB,cAAc,KAAiB,OAAoB,CAAC,GAAoB;AAC5F,QAAM,QAAQ,IAAI,aAAa,IAAI,MAAM,IAAI,GAAG;AAChD,QAAM,UAAU,MAAM,KAAK;AAC3B,QAAM,UAAU,WAAW,KAAK,IAAI;AACpC,MAAI,WAAW,QAAS,OAAM,UAAU,SAAS,IAAI,EAAE,QAAQ,QAAQ,WAAW;AAClF,QAAM,MAAM;AACZ,MAAI,IAAI,UAAU,gBAAgB,yBAAyB;AAC3D,SAAO,KAAK;AACd;AAEA,eAAsB,eAAe,KAAiB,OAAoB,CAAC,GAAoB;AAC7F,QAAM,UAAU,MAAM,eAAe,KAAK,IAAI;AAC9C,MAAI,IAAI,MAAM;AACZ,QAAI,IAAI,KAAK,UAAU,EAAE,UAAU,QAAQ,OAAO,GAAG,MAAM,SAAS,QAAQ,KAAK,CAAC,CAAC;AACnF,WAAO,UAAU,KAAK,KAAK,KAAK;AAAA,EAClC;AACA,MAAI,CAAC,SAAS;AACZ,QAAI,IAAI,sBAAsB,IAAI,MAAM,OAAO,gBAAgB,CAAC,GAAG;AACnE,WAAO,KAAK;AAAA,EACd;AACA,QAAM,MAAM,QAAQ,KAAK,WAAW,IAAI,MAAM,IAAI,KAAK,QAAQ,KAAK,QAAQ,GAAG,IAAI;AACnF,MAAI,IAAI,gBAAgB,IAAI,MAAM,KAAK,aAAa,OAAO,CAAC,CAAC,GAAG,GAAG,EAAE;AACrE,SAAO,KAAK;AACd;AASO,SAAS,mBACd,KACA,OAAoB,CAAC,GACW;AAChC,MAAI,CAAC,gBAAgB,KAAK,IAAI,EAAG,QAAO;AACxC,SAAO;AAAA,IACL,QAAQ,YAAY;AAClB,YAAM,UAAU,MAAM,eAAe,KAAK,IAAI;AAC9C,aAAO,UAAU,gBAAgB,aAAa,OAAO,CAAC,KAAK;AAAA,IAC7D;AAAA,IACA,OAAO,OAAO,WAAW;AACvB,YAAM,UAAU,MAAM;AAAA,QAAO;AAAA,QAAK;AAAA,QAAM,CAAC,KAAK,WAC5C;AAAA,UACE,GAAG,SAAS,oCAAoC,4BAA4B;AAAA,EAAK,GAAG;AAAA,QACtF;AAAA,MACF;AACA,aAAO,gBAAgB,aAAa,OAAO,CAAC;AAAA,IAC9C;AAAA,IACA,QAAQ,YAAY;AAClB,YAAM,QAAQ,IAAI,aAAa,IAAI,MAAM,IAAI,GAAG;AAChD,YAAM,UAAU,MAAM,KAAK;AAC3B,YAAM,UAAU,WAAW,KAAK,IAAI;AACpC,UAAI,WAAW,QAAS,OAAM,UAAU,SAAS,IAAI,EAAE,QAAQ,QAAQ,WAAW;AAClF,YAAM,MAAM;AACZ,aAAO,UAAU,8CAA8C;AAAA,IACjE;AAAA,EACF;AACF;","names":[]}
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  brandLogo
3
- } from "./chunk-HENE4DA6.js";
3
+ } from "./chunk-ING5HCIO.js";
4
4
 
5
5
  // src/ui/banner.ts
6
6
  function brandBanner(theme, text, columns = 80, minColumns = 56) {
@@ -17,4 +17,4 @@ function brandBanner(theme, text, columns = 80, minColumns = 56) {
17
17
  export {
18
18
  brandBanner
19
19
  };
20
- //# sourceMappingURL=chunk-K5AA65RS.js.map
20
+ //# sourceMappingURL=chunk-FZJNOG2T.js.map
@@ -4035,7 +4035,7 @@ var SUBSCRIPTION_PROVIDER_KINDS = [
4035
4035
  "antigravity-cli",
4036
4036
  "gemini-web"
4037
4037
  ];
4038
- var VERSION = "0.5.1";
4038
+ var VERSION = "0.5.3";
4039
4039
  var QUOTA_WINDOWS = ["1m", "5h", "24h"];
4040
4040
  var WINDOW_MS = {
4041
4041
  "1m": 6e4,
@@ -8442,8 +8442,9 @@ async function startAccountLogin(options) {
8442
8442
  () => setTimeout(() => void close(), 1e3).unref(),
8443
8443
  () => setTimeout(() => void close(), 1e3).unref()
8444
8444
  );
8445
+ const redirectTo = `http://127.0.0.1:${port}${callbackPath}`;
8445
8446
  return {
8446
- url: client.loginUrl(`http://127.0.0.1:${port}${callbackPath}`, pkce.challenge),
8447
+ url: options.provider ? client.authorizeUrl(options.provider, redirectTo, pkce.challenge) : client.loginUrl(redirectTo, pkce.challenge),
8447
8448
  session,
8448
8449
  close: async () => {
8449
8450
  clearTimeout(timeout);
@@ -8601,6 +8602,72 @@ function isInvalidToken(err) {
8601
8602
  return err.status === 400 || err.status === 401;
8602
8603
  }
8603
8604
  var isWindowsBusy = (err) => ["EPERM", "EBUSY"].includes(err.code ?? "");
8605
+ var SIGN_IN_FAILED = "Sign-in did not finish. Please try again.";
8606
+ function createAccountControl(options) {
8607
+ const service = options.service ?? accountService(options.env);
8608
+ if (!service) return void 0;
8609
+ const client = new AccountClient(service, options.fetch ? { fetch: options.fetch } : {});
8610
+ const store = () => new AccountStore(options.home, options.env);
8611
+ let active;
8612
+ let error = null;
8613
+ async function stop() {
8614
+ const login = active;
8615
+ active = void 0;
8616
+ await login?.close();
8617
+ }
8618
+ async function finish(login) {
8619
+ try {
8620
+ const session = await login.session;
8621
+ if (active !== login) return;
8622
+ active = void 0;
8623
+ store().save(session);
8624
+ } catch {
8625
+ if (active !== login) return;
8626
+ active = void 0;
8627
+ error = SIGN_IN_FAILED;
8628
+ }
8629
+ }
8630
+ return {
8631
+ async state() {
8632
+ const session = await store().current(client);
8633
+ return {
8634
+ signedIn: Boolean(session),
8635
+ user: session?.user ?? null,
8636
+ pending: active !== void 0,
8637
+ error
8638
+ };
8639
+ },
8640
+ async login(provider) {
8641
+ await stop();
8642
+ error = null;
8643
+ const login = await startAccountLogin({
8644
+ client,
8645
+ ...provider ? { provider } : {},
8646
+ ...options.timeoutMs !== void 0 ? { timeoutMs: options.timeoutMs } : {}
8647
+ });
8648
+ active = login;
8649
+ void finish(login);
8650
+ const opened = await options.open(login.url).catch(() => false);
8651
+ return { url: login.url, opened };
8652
+ },
8653
+ async cancel() {
8654
+ error = null;
8655
+ await stop();
8656
+ },
8657
+ async logout() {
8658
+ await stop();
8659
+ error = null;
8660
+ const accounts = store();
8661
+ const session = accounts.load();
8662
+ try {
8663
+ if (session) await client.signOut(session.accessToken);
8664
+ } catch {
8665
+ }
8666
+ accounts.clear();
8667
+ },
8668
+ close: stop
8669
+ };
8670
+ }
8604
8671
  var BRAND_MARK_SVG = '<svg viewBox="0 0 1214 1214" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path fill="currentColor" fill-rule="evenodd" d="M324.3 1096.5C324.6 1095.4 326.5 1088.3 328.5 1080.8C341.4 1031.3 375.8 953.4 419.7 874.0C445.8 826.9 448.4 822.4 471.8 783.0C501.5 733.1 530.1 687.6 556.4 648.5C563.7 637.5 569.7 628.4 569.5 628.2C569.4 628.1 563.1 631.7 555.4 636.3C513.8 661.4 468.0 683.9 411.0 707.5C337.2 737.9 321.7 744.7 296.0 757.2C241.9 783.5 199.1 809.4 152.0 844.3C119.5 868.4 98.8 885.9 71.3 912.4C64.0 919.5 58.0 925.0 58.0 924.7C58.0 923.1 64.7 902.4 68.8 891.0C116.1 762.1 215.0 644.2 351.0 554.8C385.2 532.3 411.6 516.9 445.5 499.4C521.4 460.4 589.4 435.7 636.0 430.0C676.8 425.1 715.1 437.0 743.9 463.6C763.4 481.6 779.0 509.9 785.2 538.5C787.7 550.1 788.7 579.7 787.1 592.5C782.6 626.4 769.7 661.5 746.5 702.0C717.7 752.5 675.6 806.9 627.0 856.4C599.5 884.4 575.9 905.4 542.5 931.6C510.0 957.1 500.7 964.2 432.5 1015.0C409.4 1032.3 382.6 1052.5 373.0 1060.0C354.5 1074.4 327.4 1095.5 325.1 1097.4C324.0 1098.3 323.8 1098.1 324.3 1096.5ZM783.2 1017.8C797.1 999.5 820.2 966.0 831.7 947.5C868.5 888.3 888.8 840.5 903.4 778.5C917.9 716.9 921.2 643.7 912.0 591.0C904.6 549.3 889.7 511.9 866.7 477.5C856.6 462.3 853.1 457.8 837.4 439.6C817.4 416.6 806.6 402.0 800.5 389.5C793.6 375.5 791.7 368.1 791.7 356.0C791.7 335.3 799.3 319.6 819.0 299.9C849.7 269.2 900.2 247.9 956.8 241.9C963.0 241.2 967.7 240.3 967.3 239.9C966.1 238.8 948.5 236.3 933.0 234.9C913.6 233.2 875.2 234.3 859.0 237.0C839.7 240.2 827.8 242.9 813.0 247.5C753.9 265.9 700.6 300.9 659.2 348.5C648.9 360.4 636.6 376.5 632.4 383.5C630.3 387.1 629.0 388.2 624.7 389.6C603.8 396.4 554.6 417.6 513.5 437.5C447.6 469.4 395.4 496.8 341.5 528.1L337.5 530.4L339.5 527.9C340.6 526.6 346.2 520.3 352.0 514.0C374.4 489.6 390.2 470.8 411.2 443.5C429.3 419.9 444.6 398.2 488.5 333.5C510.5 301.0 529.1 278.0 550.9 256.3C593.0 214.1 640.3 183.6 691.5 165.5C727.7 152.8 756.5 147.7 792.5 147.7C854.3 147.8 906.4 164.9 954.1 200.6C967.5 210.8 974.1 214.6 981.5 217.0C991.4 220.1 1022.1 231.9 1038.5 238.8C1061.9 248.7 1099.0 267.4 1097.7 268.7C1097.4 268.9 1089.3 268.5 1079.7 267.9C1033.7 264.7 984.5 274.1 946.2 293.4C932.3 300.4 915.0 313.0 903.4 324.5C881.0 346.6 870.0 369.6 870.0 394.4C870.0 413.7 876.8 433.1 894.7 465.2C908.8 490.3 914.6 501.1 922.8 517.5C961.3 594.3 980.0 662.5 980.0 725.4C980.0 770.9 967.3 818.9 944.4 860.4C927.6 890.8 912.0 911.0 882.5 940.6C856.5 966.7 828.5 989.7 797.0 1010.7C779.6 1022.2 780.0 1022.0 783.2 1017.8Z"/></svg>';
8605
8672
  var LOGO_ART = [
8606
8673
  " \u2584\u2584\u2584\u2588\u2584\u2584\u2584",
@@ -9805,6 +9872,7 @@ export {
9805
9872
  startAccountLogin,
9806
9873
  accountFile,
9807
9874
  AccountStore,
9875
+ createAccountControl,
9808
9876
  BRAND_MARK_SVG,
9809
9877
  brandLogo,
9810
9878
  DEFAULT_ROLES,
@@ -9823,4 +9891,4 @@ export {
9823
9891
  GoalStore,
9824
9892
  createGoalService
9825
9893
  };
9826
- //# sourceMappingURL=chunk-HENE4DA6.js.map
9894
+ //# sourceMappingURL=chunk-ING5HCIO.js.map