dsh-agy 0.4.0 → 0.4.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/README.md +21 -10
- package/lib/{accounts-BN4h0AU4.mjs → accounts-BjdDqUq1.mjs} +180 -13
- package/lib/accounts-BjdDqUq1.mjs.map +1 -0
- package/lib/cli/index.d.mts.map +1 -1
- package/lib/cli/index.mjs +4 -2
- package/lib/cli/index.mjs.map +1 -1
- package/lib/client.js +382 -34
- package/lib/index.mjs +2 -2
- package/lib/{plugin-common-N7p9Cm-3.mjs → plugin-common-B7OSfnyl.mjs} +300 -14
- package/lib/plugin-common-B7OSfnyl.mjs.map +1 -0
- package/lib/web/plugin.mjs +35 -13
- package/lib/web/plugin.mjs.map +1 -1
- package/package.json +1 -1
- package/lib/accounts-BN4h0AU4.mjs.map +0 -1
- package/lib/plugin-common-N7p9Cm-3.mjs.map +0 -1
package/lib/cli/index.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../../src/oauth/constants.ts","../../src/cli/index.ts"],"mappings":";;;cAsDa;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../../src/oauth/constants.ts","../../src/cli/index.ts"],"mappings":";;;cAsDa;;;;;;;;;;;iBCuOG,cAAc,cAAc;iBAuL5B,iBAAiB"}
|
package/lib/cli/index.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { n as AGY_DEFAULT_REDIRECT_URI } from "../constants-BpyRirvk.mjs";
|
|
2
2
|
import { i as normalizeProxyUrl, n as isProxyReachable, o as proxiedFetch, t as accountFetch } from "../proxy-DfaL73mL.mjs";
|
|
3
|
-
import { _ as
|
|
3
|
+
import { _ as resolveDshHome, c as resolveAntigravityVersionBounded, d as migrateToAgyDir, h as loadMasterKey, i as isAgyDisabled, m as deriveKey, n as maskProxyUrl, p as createAesGcmCodec, r as AgySessionManager, t as JsonAccountStore, v as resolveMasterKeyCodec } from "../accounts-BjdDqUq1.mjs";
|
|
4
4
|
import { t as exchangeAntigravity } from "../exchange-LzEyxve1.mjs";
|
|
5
5
|
import { n as upsertImportedAccount, r as authorizeAntigravity, t as importManySources } from "../import-CotRHNDk.mjs";
|
|
6
6
|
import { r as encodeCredentialBlob } from "../blob-D1e7_uT1.mjs";
|
|
@@ -111,6 +111,8 @@ async function openBrowser(url) {
|
|
|
111
111
|
const { version: PACKAGE_VERSION } = JSON.parse(readFileSync(new URL("../../package.json", import.meta.url), "utf8"));
|
|
112
112
|
function createStore(options = {}) {
|
|
113
113
|
const dshHome = resolveDshHome();
|
|
114
|
+
const accounts = migrateToAgyDir("agy-accounts.json", dshHome);
|
|
115
|
+
if (accounts.skew) console.error("dsh-agy: legacy agy-accounts.json detected next to the agy folder — an older dsh-agy process may still be writing it; its changes stay invisible until every dsh surface is restarted");
|
|
114
116
|
let codec;
|
|
115
117
|
if (options.readOnly) {
|
|
116
118
|
const masterKey = loadMasterKey(dshHome);
|
|
@@ -118,7 +120,7 @@ function createStore(options = {}) {
|
|
|
118
120
|
codec = createAesGcmCodec(deriveKey(masterKey));
|
|
119
121
|
} else codec = resolveMasterKeyCodec(dshHome).codec;
|
|
120
122
|
return new JsonAccountStore({
|
|
121
|
-
file:
|
|
123
|
+
file: accounts.file,
|
|
122
124
|
codec
|
|
123
125
|
});
|
|
124
126
|
}
|
package/lib/cli/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../../src/cli/callback-server.ts","../../src/cli/index.ts"],"sourcesContent":["/** Loopback OAuth callback server for the standalone CLI login flow. */\n\nimport { createServer } from 'node:http'\nimport type { Server } from 'node:http'\n\nexport interface CallbackResult {\n code: string\n state: string\n url: string\n}\n\nexport interface CallbackHandle {\n result: Promise<CallbackResult>\n /** Resolves once the loopback listener is bound; rejects on bind errors. */\n ready: Promise<void>\n close(): Promise<void>\n}\n\nconst SUCCESS_HTML = `<!doctype html><html><head><meta charset=\"utf-8\"><title>Login successful</title></head>\n<body style=\"font-family:system-ui;text-align:center;padding:3rem\">\n<h2>✓ Authentication successful</h2>\n<p>You can close this tab and return to the terminal.</p>\n</body></html>`\n\n/** Listen on 127.0.0.1:<port>/oauth-callback and resolve with the code+state. */\nexport function startCallbackServer(options: { port?: number; timeoutMs?: number } = {}): CallbackHandle {\n const port = options.port ?? 51121\n const timeoutMs = options.timeoutMs ?? 300_000\n\n let resolveResult: (value: CallbackResult) => void\n let rejectResult: (reason: Error) => void\n const result = new Promise<CallbackResult>((resolve, reject) => {\n resolveResult = resolve\n rejectResult = reject\n })\n\n let resolveReady: () => void\n let rejectReady: (reason: Error) => void\n const ready = new Promise<void>((resolve, reject) => {\n resolveReady = resolve\n rejectReady = reject\n })\n\n const server: Server = createServer((req, res) => {\n const url = new URL(req.url ?? '/', 'http://localhost')\n if (url.pathname === '/oauth-callback') {\n const code = url.searchParams.get('code')\n const state = url.searchParams.get('state')\n if (!code || !state) {\n res.writeHead(400, { 'Content-Type': 'text/html' })\n res.end('<h2>Missing code or state</h2>')\n return\n }\n res.writeHead(200, { 'Content-Type': 'text/html', connection: 'close' })\n res.end(SUCCESS_HTML)\n resolveResult({ code, state, url: url.toString() })\n // Give the browser a moment to render before the server closes.\n setTimeout(() => server.close(), 1500)\n return\n }\n res.writeHead(404)\n res.end('Not found')\n })\n\n server.on('error', (error: NodeJS.ErrnoException) => {\n if (error.code === 'EADDRINUSE') {\n rejectResult(new Error(`Port ${port} is already in use — pass --port to pick another.`))\n } else {\n rejectResult(error)\n }\n rejectReady(error)\n })\n\n server.listen(port, '127.0.0.1', () => {\n resolveReady()\n })\n\n const timeout = setTimeout(() => {\n rejectResult(new Error('Authentication timed out — no callback received.'))\n server.close()\n }, timeoutMs)\n\n const handle: CallbackHandle = {\n result,\n ready,\n async close() {\n clearTimeout(timeout)\n if (server.listening) {\n // The success page's keep-alive connection would otherwise hold\n // server.close() (and the CLI process) open indefinitely.\n server.closeAllConnections()\n await new Promise<void>((resolve) => server.close(() => resolve()))\n }\n },\n }\n return handle\n}\n\n/** Open a URL in the system browser (best effort). */\nexport async function openBrowser(url: string): Promise<boolean> {\n const { spawn } = await import('node:child_process')\n const platform = process.platform\n const command = platform === 'darwin' ? ['open', url]\n : platform === 'win32' ? ['cmd', '/c', 'start', '', url]\n : ['xdg-open', url]\n return new Promise<boolean>((resolve) => {\n const child = spawn(command[0]!, command.slice(1), { stdio: 'ignore' })\n child.on('error', () => resolve(false))\n child.on('spawn', () => resolve(true))\n })\n}\n","/**\n * dsh-agy CLI: login / status / import / verify / logout.\n * Standalone bin — the dsh launcher has no plugin subcommand slot, and the\n * remote paste-blob flow must run on machines without a harness.\n */\n\nimport { Command } from 'commander'\nimport { readFileSync, writeFileSync } from 'node:fs'\nimport { join } from 'node:path'\nimport { createInterface } from 'node:readline/promises'\nimport { stdin as input, stdout as output } from 'node:process'\nimport { authorizeAntigravity } from '../oauth/authorize.ts'\nimport { exchangeAntigravity } from '../oauth/exchange.ts'\nimport { encodeCredentialBlob } from '../oauth/blob.ts'\nimport { AGY_DEFAULT_REDIRECT_URI } from '../oauth/constants.ts'\nimport { createAesGcmCodec, deriveKey, loadMasterKey, resolveDshHome, resolveMasterKeyCodec } from '../store/keyring.ts'\nimport type { SecretCodec } from '../store/keyring.ts'\nimport { JsonAccountStore, maskProxyUrl } from '../store/accounts.ts'\nimport { AgySessionManager } from '../session.ts'\nimport { isAgyDisabled } from '../runtime/risk.ts'\nimport { resolveAntigravityVersionBounded } from '../runtime/version.ts'\nimport { startCallbackServer, openBrowser } from './callback-server.ts'\nimport { importManySources, upsertImportedAccount } from './import.ts'\nimport { accountFetch, isProxyReachable, normalizeProxyUrl, proxiedFetch } from '../proxy.ts'\n\n/** Package version, read from the shipped package.json — never hard-coded twice. */\nconst { version: PACKAGE_VERSION } = JSON.parse(\n readFileSync(new URL('../../package.json', import.meta.url), 'utf8'),\n) as { version: string }\n\nfunction createStore(options: { readOnly?: boolean } = {}): JsonAccountStore {\n const dshHome = resolveDshHome()\n let codec: SecretCodec\n if (options.readOnly) {\n // Read-only commands must never create the master key or the credentials\n // document: they would fail for no reason on a read-only HOME and write\n // files nobody asked for anywhere else.\n const masterKey = loadMasterKey(dshHome)\n if (!masterKey) {\n throw new Error('No agy account store found — run `dsh-agy login` first.')\n }\n codec = createAesGcmCodec(deriveKey(masterKey))\n } else {\n codec = resolveMasterKeyCodec(dshHome).codec\n }\n return new JsonAccountStore({ file: `${dshHome}/agy-accounts.json`, codec })\n}\n\n/** Read-only store with a friendly error when no credentials exist yet. */\nfunction createReadOnlyStoreOrExit(): JsonAccountStore {\n try {\n return createStore({ readOnly: true })\n } catch (error) {\n console.error(error instanceof Error ? error.message : String(error))\n process.exit(1)\n }\n}\n\nfunction resolveProxyOption(raw: string | undefined): string | undefined {\n if (raw === undefined) return undefined\n if (!raw.trim()) return ''\n try {\n return normalizeProxyUrl(raw)\n } catch (error) {\n console.error(`Invalid proxy URL: ${error instanceof Error ? error.message : String(error)}`)\n process.exit(1)\n }\n}\n\nasync function ask(question: string): Promise<string> {\n const rl = createInterface({ input, output })\n try {\n return (await rl.question(question)).trim()\n } finally {\n rl.close()\n }\n}\n\n/** Remote/SSH sessions cannot reach a local browser; auto-select headless paste. */\nfunction isRemoteSession(): boolean {\n return !!(process.env.SSH_CONNECTION || process.env.SSH_CLIENT || process.env.SSH_TTY)\n}\n\nasync function loginCommand(options: { headless: boolean; blob: boolean; port: number; project?: string; timeout?: string; proxy?: string }) {\n const proxyInput = resolveProxyOption(options.proxy)\n // proxy \"\" sentinel means clear; normalizeProxyUrl already handled\n const normalizedProxy = proxyInput === '' ? '' : proxyInput\n const store = createStore()\n const redirectUri = `http://localhost:${options.port}/oauth-callback`\n if (!options.headless && isRemoteSession()) {\n console.log('(SSH session detected — using headless paste flow; pass --headless explicitly to force)')\n options.headless = true\n }\n\n let callback: Awaited<ReturnType<typeof startCallbackServer>> | undefined\n if (!options.headless) {\n // Bind the loopback listener BEFORE the URL is shown: a local process\n // squatting on the fixed port could otherwise capture code+state (the\n // state carries the PKCE verifier) and steal the refresh token.\n callback = startCallbackServer({ port: options.port, timeoutMs: Number(options.timeout) || 300_000 })\n try {\n await callback.ready\n } catch (error) {\n console.error(error instanceof Error ? error.message : String(error))\n process.exit(1)\n }\n }\n\n const { url, verifier } = await authorizeAntigravity(redirectUri, options.project ?? '')\n console.log(`\\nOpen this URL in a browser to authorize:\\n\\n ${url}\\n`)\n\n // Resolve the client version while the user is still in the browser. The token\n // exchange is the one request that MINTS credentials, and sending it with the\n // pinned fallback advertises a client that may no longer exist — the exact\n // stale-version anomaly the plugin path resolves away. Bounded and fail-soft:\n // on timeout the fallback stands, and a login never waits more than this.\n // Routed like the exchange itself, so a `--proxy` login does not probe direct.\n const versionProbe = resolveAntigravityVersionBounded(\n 1_500,\n normalizedProxy ? accountFetch({ proxyUrl: normalizedProxy }) : proxiedFetch,\n )\n\n let code: string\n let state: string\n\n if (options.headless) {\n const pasted = await ask('After approving, paste the full redirected URL here: ')\n const parsed = new URL(pasted)\n code = parsed.searchParams.get('code') ?? ''\n state = parsed.searchParams.get('state') ?? ''\n if (!code || !state) {\n console.error('Error: pasted URL is missing code or state.')\n process.exit(1)\n }\n } else {\n const opened = await openBrowser(url)\n if (!opened) console.log('(Could not open a browser automatically — open the URL manually.)')\n let callbackResult: { code: string; state: string; url: string }\n try {\n callbackResult = await callback!.result\n } catch (error) {\n console.error(error instanceof Error ? error.message : String(error))\n process.exit(1)\n }\n code = callbackResult.code\n state = callbackResult.state\n }\n\n // Bind the exchange to the verifier we issued: a state from any other login\n // (pasted from another session, or fabricated) must be rejected.\n // Route the exchange over the proxy being bound: it targets Google (never the\n // loopback callback, which is forced direct), and leaving it unproxied would\n // leak the host's real IP at exactly the moment the user asked to isolate it.\n await versionProbe\n const result = await exchangeAntigravity(code, state, redirectUri, verifier, {\n ...(normalizedProxy ? { proxyUrl: normalizedProxy } : {}),\n })\n if (result.type === 'failed') {\n console.error(`Login failed: ${result.error}`)\n process.exit(1)\n }\n\n if (options.blob) {\n if (normalizedProxy !== undefined) {\n console.log('(Note: --proxy is ignored with --blob; proxy is only stored with the account)')\n }\n const blob = encodeCredentialBlob('agy', {\n access_token: result.access,\n refresh_token: result.refresh.split('|')[0],\n expires_in: Math.max(0, Math.round((result.expires - Date.now()) / 1000)),\n })\n console.log(`\\nPaste this blob into the remote dashboard/CLI:\\n\\n${blob}\\n`)\n } else {\n const proxyForUpsert = normalizedProxy !== undefined ? normalizedProxy : undefined\n const { account, created } = await upsertImportedAccount(store, {\n accessToken: result.access,\n refreshToken: result.refresh.split('|')[0]!,\n tokenType: 'Bearer',\n expiresAt: new Date(result.expires).toISOString(),\n authMethod: 'oauth',\n email: result.email ?? null,\n projectId: result.projectId || null,\n clientId: result.clientId || null,\n }, { overwriteExisting: true, ...(proxyForUpsert !== undefined ? { proxy: proxyForUpsert } : {}) })\n const masked = maskProxyUrl(account.proxy)\n console.log(`${created ? 'Added' : 'Updated'} account: ${account.email ?? '(no email)'} (project: ${result.projectId || 'default'})${masked ? ` proxy: ${masked}` : ''}`)\n }\n\n await callback?.close()\n}\n\nasync function statusCommand() {\n const store = createReadOnlyStoreOrExit()\n const storage = await store.load()\n if (storage.accounts.length === 0) {\n console.log('No agy accounts. Run `dsh-agy login` first.')\n return\n }\n console.log(`\\n${storage.accounts.length} account(s), active index ${storage.activeIndex}:\\n`)\n const sessions = new AgySessionManager({ store })\n for (const [index, account] of storage.accounts.entries()) {\n const marker = index === storage.activeIndex ? '★' : ' '\n const state = account.enabled === false ? 'disabled'\n : account.verificationRequired ? 'verification-required'\n : account.coolingDownUntil && account.coolingDownUntil > Date.now() ? 'cooling'\n : 'active'\n const maskedProxy = maskProxyUrl(account.proxy)\n console.log(` ${marker} [${index}] ${account.email ?? '(no email)'} — ${state}${account.projectId ? ` (project: ${account.projectId})` : ''}${maskedProxy ? ` proxy: ${maskedProxy}` : ''}`)\n\n // Best-effort quota summary via fetchAvailableModels (fresh access token).\n const session = await sessions.getSession().catch(() => undefined)\n if (session && session.index === index) {\n try {\n const { fetchAvailableModels } = await import('../adapter/models.ts')\n // Account-scoped: route through the account's proxy so a status check\n // never reveals the host's real IP for a proxied account.\n const discovered = await fetchAvailableModels(\n session.auth.access,\n session.account.projectId,\n accountFetch({ proxyUrl: session.account.proxy }),\n )\n const entries = Object.entries(discovered.models ?? {})\n if (entries.length > 0) {\n const withQuota = entries\n .map(([id, entry]) => ({ id, ...entry.quotaInfo }))\n .filter((e) => typeof e.remainingFraction === 'number')\n .sort((a, b) => (a.remainingFraction ?? 0) - (b.remainingFraction ?? 0))\n if (withQuota.length > 0) {\n const lowest = withQuota[0]!\n console.log(` models: ${entries.length}, lowest quota: ${Math.round((lowest.remainingFraction ?? 0) * 100)}% (${lowest.id})${lowest.resetTime ? `, resets ${new Date(lowest.resetTime).toISOString()}` : ''}`)\n } else {\n console.log(` models: ${entries.length} (no per-model quota reported)`)\n }\n }\n } catch (error) {\n console.log(` quota: unavailable (${error instanceof Error ? error.message : String(error)})`)\n }\n }\n }\n}\n\nasync function importCommand(options: { blob: boolean; files?: string[]; email?: string; overwrite: boolean; proxy?: string }) {\n const store = createStore()\n const proxyForUpsert = resolveProxyOption(options.proxy)\n let items: Array<{ source: unknown; kind: 'json' | 'blob' }>\n if (options.files && options.files.length > 0) {\n items = options.files.map((file) => {\n const raw = readFileSync(file, 'utf8')\n return { source: options.blob ? raw : (JSON.parse(raw) as unknown), kind: options.blob ? 'blob' : 'json' }\n })\n } else {\n const pasted = await ask('Paste the agy token JSON (or blob with --blob): ')\n items = [{ source: pasted, kind: options.blob ? 'blob' : 'json' }]\n }\n const importOpts: { email?: string; overwriteExisting?: boolean; proxy?: string } = {\n email: options.email,\n overwriteExisting: options.overwrite,\n }\n if (proxyForUpsert !== undefined) importOpts.proxy = proxyForUpsert\n const result = await importManySources(items, store, importOpts)\n console.log(`Imported ${result.imported}, replaced ${result.replaced}${result.errors.length > 0 ? `, ${result.errors.length} failed` : ''}`)\n for (const error of result.errors) console.log(` ! ${error}`)\n}\n\n/**\n * Write one exported credential blob to disk.\n *\n * 0600: a blob carries a live access+refresh token in plain base64. Every other\n * credential write in this repo sets an owner-only mode; this was the one\n * `writeFileSync` without it, so the default umask (0644) left the export\n * world-readable on a shared machine.\n */\nexport function writeBlobFile(file: string, blob: string): void {\n writeFileSync(file, blob + '\\n', { mode: 0o600 })\n}\n\nasync function exportCommand(options: { index?: string; out?: string }) {\n const store = createReadOnlyStoreOrExit()\n const sessions = new AgySessionManager({ store })\n const storage = await store.load()\n const indices = options.index !== undefined\n ? [Number(options.index)]\n : storage.accounts.map((_, i) => i)\n\n let exported = 0\n for (const index of indices) {\n const account = storage.accounts[index]\n if (!account) {\n console.log(`[${index}] not found`)\n continue\n }\n const result = await sessions.exportBlob(index)\n if (!result.blob) {\n console.log(`[${index}] ${account.email ?? ''} — FAILED: ${result.error}`)\n continue\n }\n if (options.out) {\n const file = join(options.out, `dsh-agy-${index}.blob`)\n writeBlobFile(file, result.blob)\n console.log(`[${index}] ${account.email ?? ''} — wrote ${file}`)\n } else {\n console.log(result.blob)\n }\n exported++\n }\n if (!options.out) console.log(`\\n${exported} blob(s) exported — one line each, paste into a remote import`)\n}\n\nasync function verifyCommand(options: { index?: string }) {\n const store = createReadOnlyStoreOrExit()\n const sessions = new AgySessionManager({ store })\n const storage = await store.load()\n const indices = options.index !== undefined\n ? [Number(options.index)]\n : storage.accounts.map((_, i) => i)\n\n for (const index of indices) {\n const account = storage.accounts[index]\n if (!account) {\n console.log(`[${index}] not found`)\n continue\n }\n const result = await sessions.verifyAccount(index)\n if (result.ok) {\n console.log(`[${index}] ${account.email ?? ''} — OK${result.email && result.email !== account.email ? ` (userinfo: ${result.email})` : ''}`)\n } else {\n console.log(`[${index}] ${account.email ?? ''} — FAILED: ${result.error}`)\n }\n }\n}\n\nasync function healthCommand(options: { interval?: string; index?: string[] }) {\n const store = createReadOnlyStoreOrExit()\n const sessions = new AgySessionManager({\n store,\n onHealthReport: (results) => {\n for (const result of results) {\n if (result.ok) console.log(`[${result.index}] ${result.email ?? ''} — OK`)\n else console.log(`[${result.index}] ${result.email ?? ''} — FAILED: ${result.error}`)\n }\n },\n })\n const indices = options.index?.map((value) => Number(value))\n\n if (options.interval) {\n const intervalMs = Number(options.interval)\n if (!Number.isFinite(intervalMs) || intervalMs <= 0) {\n console.error('Error: --interval must be a positive number of milliseconds.')\n process.exit(1)\n }\n console.log(`Health probe every ${intervalMs}ms (Ctrl+C to stop).`)\n sessions.startHealthProbe(intervalMs, { unref: false })\n await new Promise<void>(() => {}) // keep the loop alive\n return\n }\n\n const results = await sessions.checkAccounts(indices)\n if (results.length === 0) console.log('No enabled accounts — run `dsh-agy login` first.')\n}\n\nasync function logoutCommand(options: { index?: string; email?: string }) {\n const store = createReadOnlyStoreOrExit()\n await store.mutate((storage) => {\n const index = options.index !== undefined\n ? Number(options.index)\n : options.email\n ? storage.accounts.findIndex((a) => a.email?.toLowerCase() === options.email!.toLowerCase())\n : storage.activeIndex\n if (index < 0 || index >= storage.accounts.length) {\n throw new Error(`account not found (index ${index})`)\n }\n const [removed] = storage.accounts.splice(index, 1)\n if (storage.activeIndex >= storage.accounts.length) storage.activeIndex = 0\n console.log(`Removed account: ${removed?.email ?? `[${index}]`}`)\n })\n}\n\nasync function proxySetCommand(options: { index: string; proxy: string }) {\n const idx = Number(options.index)\n if (!Number.isInteger(idx) || idx < 0) {\n console.error('Invalid --index (must be >= 0)')\n process.exit(1)\n }\n const raw = options.proxy ?? ''\n if (!raw.trim()) {\n console.error('Missing --proxy value')\n process.exit(1)\n }\n let normalized: string\n try {\n normalized = normalizeProxyUrl(raw)\n } catch (error) {\n console.error(`Invalid proxy URL: ${error instanceof Error ? error.message : String(error)}`)\n process.exit(1)\n }\n const store = createStore()\n await store.mutate((storage) => {\n const account = storage.accounts[idx]\n if (!account) throw new Error(`account not found (index ${idx})`)\n account.proxy = normalized\n })\n console.log(`[${idx}] proxy set to ${maskProxyUrl(normalized)}`)\n}\n\nasync function proxyClearCommand(options: { index: string }) {\n const idx = Number(options.index)\n if (!Number.isInteger(idx) || idx < 0) {\n console.error('Invalid --index (must be >= 0)')\n process.exit(1)\n }\n const store = createStore()\n await store.mutate((storage) => {\n const account = storage.accounts[idx]\n if (!account) throw new Error(`account not found (index ${idx})`)\n delete (account as { proxy?: string }).proxy\n })\n console.log(`[${idx}] proxy cleared`)\n}\n\nasync function proxyTestCommand(options: { index: string }) {\n const idx = Number(options.index)\n if (!Number.isInteger(idx) || idx < 0) {\n console.error('Invalid --index (must be >= 0)')\n process.exit(1)\n }\n const store = createReadOnlyStoreOrExit()\n const storage = await store.load()\n const account = storage.accounts[idx]\n if (!account) {\n console.error(`account not found (index ${idx})`)\n process.exit(1)\n }\n if (!account.proxy) {\n console.log(`[${idx}] no proxy configured`)\n return\n }\n const masked = maskProxyUrl(account.proxy)\n const reachable = await isProxyReachable(account.proxy)\n if (reachable) console.log(`[${idx}] ${masked} — ok`)\n else console.log(`[${idx}] ${masked} — proxy_unreachable`)\n}\n\nasync function proxyListCommand() {\n const store = createReadOnlyStoreOrExit()\n const storage = await store.load()\n if (storage.accounts.length === 0) {\n console.log('No agy accounts.')\n return\n }\n for (const [index, account] of storage.accounts.entries()) {\n const masked = maskProxyUrl(account.proxy)\n console.log(` [${index}] ${account.email ?? '(no email)'} — ${masked ?? '(no proxy)'}`)\n }\n}\n\nexport function createProgram(): Command {\n const program = new Command()\n program\n .name('dsh-agy')\n .description('Google Antigravity (agy) account management for DeepSeek Harness')\n .version(PACKAGE_VERSION)\n\n program.hook('preAction', () => {\n if (isAgyDisabled()) {\n console.error('dsh-agy is disabled (DSH_AGY_DISABLE=1).')\n process.exit(1)\n }\n })\n\n program\n .command('login')\n .description('OAuth login (browser, or headless paste)')\n .option('--headless', 'print the URL and wait for a pasted redirect URL', false)\n .option('--blob', 'print a paste-credential blob instead of storing the account', false)\n .option('--port <n>', 'loopback callback port', '51121')\n .option('--project <id>', 'bind the login to a specific project')\n .option('--timeout <ms>', 'callback timeout', '300000')\n .option('--proxy <url>', 'per-account proxy URL (http/https/socks5); empty to clear')\n .action(async (options) => {\n await loginCommand({ ...options, timeout: options.timeout })\n })\n\n program\n .command('status')\n .description('List accounts and their health')\n .action(async () => {\n await statusCommand()\n })\n\n program\n .command('import')\n .description('Import agy token files or paste credentials')\n .argument('[files...]', 'paths to agy auth.json token files (multiple allowed)')\n .option('--blob', 'the pasted value is a credential blob', false)\n .option('--email <email>', 'account email (skips userinfo verification)')\n .option('--overwrite', 'replace an existing account with the same email', false)\n .option('--proxy <url>', 'per-account proxy URL (http/https/socks5); empty to clear')\n .action(async (files: string[] | undefined, options: { blob: boolean; email?: string; overwrite: boolean; proxy?: string }) => {\n await importCommand({ ...options, files })\n })\n\n program\n .command('export')\n .description('Export account credentials as paste blobs')\n .option('--index <n>', 'export one account by index; default all')\n .option('--out <dir>', 'write one dsh-agy-<index>.blob file per account into this directory (default: print to stdout)')\n .action(async (options: { index?: string; out?: string }) => {\n await exportCommand(options)\n })\n\n program\n .command('verify')\n .description('Verify account credentials (refresh + userinfo)')\n .option('--index <n>', 'verify one account by index; default all')\n .action(async (options: { index?: string }) => {\n await verifyCommand(options)\n })\n\n program\n .command('health')\n .description('Check every enabled account (refresh + userinfo), optionally on an interval')\n .option('--interval <ms>', 'repeat on an interval instead of once')\n .option('--index <n...>', 'check only these accounts')\n .action(async (options: { interval?: string; index?: string[] }) => {\n await healthCommand(options)\n })\n\n program\n .command('logout')\n .description('Remove an account')\n .option('--index <n>', 'account index (default: active)')\n .option('--email <email>', 'account email')\n .action(async (options: { index?: string; email?: string }) => {\n await logoutCommand(options)\n })\n\n const proxy = program.command('proxy').description('Manage per-account proxies')\n proxy\n .command('set')\n .description('Set proxy for an account')\n .requiredOption('--index <n>', 'account index')\n .requiredOption('--proxy <url>', 'proxy URL (http/https/socks5)')\n .action(async (options: { index: string; proxy: string }) => {\n await proxySetCommand(options)\n })\n proxy\n .command('clear')\n .description('Clear proxy for an account')\n .requiredOption('--index <n>', 'account index')\n .action(async (options: { index: string }) => {\n await proxyClearCommand(options)\n })\n proxy\n .command('test')\n .description('Test proxy reachability for an account (TCP 2s fast-fail)')\n .requiredOption('--index <n>', 'account index')\n .action(async (options: { index: string }) => {\n await proxyTestCommand(options)\n })\n proxy\n .command('list')\n .description('List accounts with masked proxies')\n .action(async () => {\n await proxyListCommand()\n })\n\n return program\n}\n\nexport { AGY_DEFAULT_REDIRECT_URI }\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../../src/cli/callback-server.ts","../../src/cli/index.ts"],"sourcesContent":["/** Loopback OAuth callback server for the standalone CLI login flow. */\n\nimport { createServer } from 'node:http'\nimport type { Server } from 'node:http'\n\nexport interface CallbackResult {\n code: string\n state: string\n url: string\n}\n\nexport interface CallbackHandle {\n result: Promise<CallbackResult>\n /** Resolves once the loopback listener is bound; rejects on bind errors. */\n ready: Promise<void>\n close(): Promise<void>\n}\n\nconst SUCCESS_HTML = `<!doctype html><html><head><meta charset=\"utf-8\"><title>Login successful</title></head>\n<body style=\"font-family:system-ui;text-align:center;padding:3rem\">\n<h2>✓ Authentication successful</h2>\n<p>You can close this tab and return to the terminal.</p>\n</body></html>`\n\n/** Listen on 127.0.0.1:<port>/oauth-callback and resolve with the code+state. */\nexport function startCallbackServer(options: { port?: number; timeoutMs?: number } = {}): CallbackHandle {\n const port = options.port ?? 51121\n const timeoutMs = options.timeoutMs ?? 300_000\n\n let resolveResult: (value: CallbackResult) => void\n let rejectResult: (reason: Error) => void\n const result = new Promise<CallbackResult>((resolve, reject) => {\n resolveResult = resolve\n rejectResult = reject\n })\n\n let resolveReady: () => void\n let rejectReady: (reason: Error) => void\n const ready = new Promise<void>((resolve, reject) => {\n resolveReady = resolve\n rejectReady = reject\n })\n\n const server: Server = createServer((req, res) => {\n const url = new URL(req.url ?? '/', 'http://localhost')\n if (url.pathname === '/oauth-callback') {\n const code = url.searchParams.get('code')\n const state = url.searchParams.get('state')\n if (!code || !state) {\n res.writeHead(400, { 'Content-Type': 'text/html' })\n res.end('<h2>Missing code or state</h2>')\n return\n }\n res.writeHead(200, { 'Content-Type': 'text/html', connection: 'close' })\n res.end(SUCCESS_HTML)\n resolveResult({ code, state, url: url.toString() })\n // Give the browser a moment to render before the server closes.\n setTimeout(() => server.close(), 1500)\n return\n }\n res.writeHead(404)\n res.end('Not found')\n })\n\n server.on('error', (error: NodeJS.ErrnoException) => {\n if (error.code === 'EADDRINUSE') {\n rejectResult(new Error(`Port ${port} is already in use — pass --port to pick another.`))\n } else {\n rejectResult(error)\n }\n rejectReady(error)\n })\n\n server.listen(port, '127.0.0.1', () => {\n resolveReady()\n })\n\n const timeout = setTimeout(() => {\n rejectResult(new Error('Authentication timed out — no callback received.'))\n server.close()\n }, timeoutMs)\n\n const handle: CallbackHandle = {\n result,\n ready,\n async close() {\n clearTimeout(timeout)\n if (server.listening) {\n // The success page's keep-alive connection would otherwise hold\n // server.close() (and the CLI process) open indefinitely.\n server.closeAllConnections()\n await new Promise<void>((resolve) => server.close(() => resolve()))\n }\n },\n }\n return handle\n}\n\n/** Open a URL in the system browser (best effort). */\nexport async function openBrowser(url: string): Promise<boolean> {\n const { spawn } = await import('node:child_process')\n const platform = process.platform\n const command = platform === 'darwin' ? ['open', url]\n : platform === 'win32' ? ['cmd', '/c', 'start', '', url]\n : ['xdg-open', url]\n return new Promise<boolean>((resolve) => {\n const child = spawn(command[0]!, command.slice(1), { stdio: 'ignore' })\n child.on('error', () => resolve(false))\n child.on('spawn', () => resolve(true))\n })\n}\n","/**\n * dsh-agy CLI: login / status / import / verify / logout.\n * Standalone bin — the dsh launcher has no plugin subcommand slot, and the\n * remote paste-blob flow must run on machines without a harness.\n */\n\nimport { Command } from 'commander'\nimport { readFileSync, writeFileSync } from 'node:fs'\nimport { join } from 'node:path'\nimport { createInterface } from 'node:readline/promises'\nimport { stdin as input, stdout as output } from 'node:process'\nimport { authorizeAntigravity } from '../oauth/authorize.ts'\nimport { exchangeAntigravity } from '../oauth/exchange.ts'\nimport { encodeCredentialBlob } from '../oauth/blob.ts'\nimport { AGY_DEFAULT_REDIRECT_URI } from '../oauth/constants.ts'\nimport { createAesGcmCodec, deriveKey, loadMasterKey, resolveDshHome, resolveMasterKeyCodec } from '../store/keyring.ts'\nimport type { SecretCodec } from '../store/keyring.ts'\nimport { migrateToAgyDir } from '../store/paths.ts'\nimport { JsonAccountStore, maskProxyUrl } from '../store/accounts.ts'\nimport { AgySessionManager } from '../session.ts'\nimport { isAgyDisabled } from '../runtime/risk.ts'\nimport { resolveAntigravityVersionBounded } from '../runtime/version.ts'\nimport { startCallbackServer, openBrowser } from './callback-server.ts'\nimport { importManySources, upsertImportedAccount } from './import.ts'\nimport { accountFetch, isProxyReachable, normalizeProxyUrl, proxiedFetch } from '../proxy.ts'\n\n/** Package version, read from the shipped package.json — never hard-coded twice. */\nconst { version: PACKAGE_VERSION } = JSON.parse(\n readFileSync(new URL('../../package.json', import.meta.url), 'utf8'),\n) as { version: string }\n\nfunction createStore(options: { readOnly?: boolean } = {}): JsonAccountStore {\n const dshHome = resolveDshHome()\n // One-time move of the legacy home-directory file into `$DSH_HOME/agy/`.\n // `skew` here means the NEW file already exists while a legacy one sits next\n // to it — an old-version process wrote it again — so say so once, on stderr,\n // and keep using the new layout.\n const accounts = migrateToAgyDir('agy-accounts.json', dshHome)\n if (accounts.skew) {\n console.error(\n 'dsh-agy: legacy agy-accounts.json detected next to the agy folder — an older '\n + 'dsh-agy process may still be writing it; its changes stay invisible until '\n + 'every dsh surface is restarted',\n )\n }\n let codec: SecretCodec\n if (options.readOnly) {\n // Read-only commands must never create the master key or the credentials\n // document: they would fail for no reason on a read-only HOME and write\n // files nobody asked for anywhere else.\n const masterKey = loadMasterKey(dshHome)\n if (!masterKey) {\n throw new Error('No agy account store found — run `dsh-agy login` first.')\n }\n codec = createAesGcmCodec(deriveKey(masterKey))\n } else {\n codec = resolveMasterKeyCodec(dshHome).codec\n }\n return new JsonAccountStore({ file: accounts.file, codec })\n}\n\n/** Read-only store with a friendly error when no credentials exist yet. */\nfunction createReadOnlyStoreOrExit(): JsonAccountStore {\n try {\n return createStore({ readOnly: true })\n } catch (error) {\n console.error(error instanceof Error ? error.message : String(error))\n process.exit(1)\n }\n}\n\nfunction resolveProxyOption(raw: string | undefined): string | undefined {\n if (raw === undefined) return undefined\n if (!raw.trim()) return ''\n try {\n return normalizeProxyUrl(raw)\n } catch (error) {\n console.error(`Invalid proxy URL: ${error instanceof Error ? error.message : String(error)}`)\n process.exit(1)\n }\n}\n\nasync function ask(question: string): Promise<string> {\n const rl = createInterface({ input, output })\n try {\n return (await rl.question(question)).trim()\n } finally {\n rl.close()\n }\n}\n\n/** Remote/SSH sessions cannot reach a local browser; auto-select headless paste. */\nfunction isRemoteSession(): boolean {\n return !!(process.env.SSH_CONNECTION || process.env.SSH_CLIENT || process.env.SSH_TTY)\n}\n\nasync function loginCommand(options: { headless: boolean; blob: boolean; port: number; project?: string; timeout?: string; proxy?: string }) {\n const proxyInput = resolveProxyOption(options.proxy)\n // proxy \"\" sentinel means clear; normalizeProxyUrl already handled\n const normalizedProxy = proxyInput === '' ? '' : proxyInput\n const store = createStore()\n const redirectUri = `http://localhost:${options.port}/oauth-callback`\n if (!options.headless && isRemoteSession()) {\n console.log('(SSH session detected — using headless paste flow; pass --headless explicitly to force)')\n options.headless = true\n }\n\n let callback: Awaited<ReturnType<typeof startCallbackServer>> | undefined\n if (!options.headless) {\n // Bind the loopback listener BEFORE the URL is shown: a local process\n // squatting on the fixed port could otherwise capture code+state (the\n // state carries the PKCE verifier) and steal the refresh token.\n callback = startCallbackServer({ port: options.port, timeoutMs: Number(options.timeout) || 300_000 })\n try {\n await callback.ready\n } catch (error) {\n console.error(error instanceof Error ? error.message : String(error))\n process.exit(1)\n }\n }\n\n const { url, verifier } = await authorizeAntigravity(redirectUri, options.project ?? '')\n console.log(`\\nOpen this URL in a browser to authorize:\\n\\n ${url}\\n`)\n\n // Resolve the client version while the user is still in the browser. The token\n // exchange is the one request that MINTS credentials, and sending it with the\n // pinned fallback advertises a client that may no longer exist — the exact\n // stale-version anomaly the plugin path resolves away. Bounded and fail-soft:\n // on timeout the fallback stands, and a login never waits more than this.\n // Routed like the exchange itself, so a `--proxy` login does not probe direct.\n const versionProbe = resolveAntigravityVersionBounded(\n 1_500,\n normalizedProxy ? accountFetch({ proxyUrl: normalizedProxy }) : proxiedFetch,\n )\n\n let code: string\n let state: string\n\n if (options.headless) {\n const pasted = await ask('After approving, paste the full redirected URL here: ')\n const parsed = new URL(pasted)\n code = parsed.searchParams.get('code') ?? ''\n state = parsed.searchParams.get('state') ?? ''\n if (!code || !state) {\n console.error('Error: pasted URL is missing code or state.')\n process.exit(1)\n }\n } else {\n const opened = await openBrowser(url)\n if (!opened) console.log('(Could not open a browser automatically — open the URL manually.)')\n let callbackResult: { code: string; state: string; url: string }\n try {\n callbackResult = await callback!.result\n } catch (error) {\n console.error(error instanceof Error ? error.message : String(error))\n process.exit(1)\n }\n code = callbackResult.code\n state = callbackResult.state\n }\n\n // Bind the exchange to the verifier we issued: a state from any other login\n // (pasted from another session, or fabricated) must be rejected.\n // Route the exchange over the proxy being bound: it targets Google (never the\n // loopback callback, which is forced direct), and leaving it unproxied would\n // leak the host's real IP at exactly the moment the user asked to isolate it.\n await versionProbe\n const result = await exchangeAntigravity(code, state, redirectUri, verifier, {\n ...(normalizedProxy ? { proxyUrl: normalizedProxy } : {}),\n })\n if (result.type === 'failed') {\n console.error(`Login failed: ${result.error}`)\n process.exit(1)\n }\n\n if (options.blob) {\n if (normalizedProxy !== undefined) {\n console.log('(Note: --proxy is ignored with --blob; proxy is only stored with the account)')\n }\n const blob = encodeCredentialBlob('agy', {\n access_token: result.access,\n refresh_token: result.refresh.split('|')[0],\n expires_in: Math.max(0, Math.round((result.expires - Date.now()) / 1000)),\n })\n console.log(`\\nPaste this blob into the remote dashboard/CLI:\\n\\n${blob}\\n`)\n } else {\n const proxyForUpsert = normalizedProxy !== undefined ? normalizedProxy : undefined\n const { account, created } = await upsertImportedAccount(store, {\n accessToken: result.access,\n refreshToken: result.refresh.split('|')[0]!,\n tokenType: 'Bearer',\n expiresAt: new Date(result.expires).toISOString(),\n authMethod: 'oauth',\n email: result.email ?? null,\n projectId: result.projectId || null,\n clientId: result.clientId || null,\n }, { overwriteExisting: true, ...(proxyForUpsert !== undefined ? { proxy: proxyForUpsert } : {}) })\n const masked = maskProxyUrl(account.proxy)\n console.log(`${created ? 'Added' : 'Updated'} account: ${account.email ?? '(no email)'} (project: ${result.projectId || 'default'})${masked ? ` proxy: ${masked}` : ''}`)\n }\n\n await callback?.close()\n}\n\nasync function statusCommand() {\n const store = createReadOnlyStoreOrExit()\n const storage = await store.load()\n if (storage.accounts.length === 0) {\n console.log('No agy accounts. Run `dsh-agy login` first.')\n return\n }\n console.log(`\\n${storage.accounts.length} account(s), active index ${storage.activeIndex}:\\n`)\n const sessions = new AgySessionManager({ store })\n for (const [index, account] of storage.accounts.entries()) {\n const marker = index === storage.activeIndex ? '★' : ' '\n const state = account.enabled === false ? 'disabled'\n : account.verificationRequired ? 'verification-required'\n : account.coolingDownUntil && account.coolingDownUntil > Date.now() ? 'cooling'\n : 'active'\n const maskedProxy = maskProxyUrl(account.proxy)\n console.log(` ${marker} [${index}] ${account.email ?? '(no email)'} — ${state}${account.projectId ? ` (project: ${account.projectId})` : ''}${maskedProxy ? ` proxy: ${maskedProxy}` : ''}`)\n\n // Best-effort quota summary via fetchAvailableModels (fresh access token).\n const session = await sessions.getSession().catch(() => undefined)\n if (session && session.index === index) {\n try {\n const { fetchAvailableModels } = await import('../adapter/models.ts')\n // Account-scoped: route through the account's proxy so a status check\n // never reveals the host's real IP for a proxied account.\n const discovered = await fetchAvailableModels(\n session.auth.access,\n session.account.projectId,\n accountFetch({ proxyUrl: session.account.proxy }),\n )\n const entries = Object.entries(discovered.models ?? {})\n if (entries.length > 0) {\n const withQuota = entries\n .map(([id, entry]) => ({ id, ...entry.quotaInfo }))\n .filter((e) => typeof e.remainingFraction === 'number')\n .sort((a, b) => (a.remainingFraction ?? 0) - (b.remainingFraction ?? 0))\n if (withQuota.length > 0) {\n const lowest = withQuota[0]!\n console.log(` models: ${entries.length}, lowest quota: ${Math.round((lowest.remainingFraction ?? 0) * 100)}% (${lowest.id})${lowest.resetTime ? `, resets ${new Date(lowest.resetTime).toISOString()}` : ''}`)\n } else {\n console.log(` models: ${entries.length} (no per-model quota reported)`)\n }\n }\n } catch (error) {\n console.log(` quota: unavailable (${error instanceof Error ? error.message : String(error)})`)\n }\n }\n }\n}\n\nasync function importCommand(options: { blob: boolean; files?: string[]; email?: string; overwrite: boolean; proxy?: string }) {\n const store = createStore()\n const proxyForUpsert = resolveProxyOption(options.proxy)\n let items: Array<{ source: unknown; kind: 'json' | 'blob' }>\n if (options.files && options.files.length > 0) {\n items = options.files.map((file) => {\n const raw = readFileSync(file, 'utf8')\n return { source: options.blob ? raw : (JSON.parse(raw) as unknown), kind: options.blob ? 'blob' : 'json' }\n })\n } else {\n const pasted = await ask('Paste the agy token JSON (or blob with --blob): ')\n items = [{ source: pasted, kind: options.blob ? 'blob' : 'json' }]\n }\n const importOpts: { email?: string; overwriteExisting?: boolean; proxy?: string } = {\n email: options.email,\n overwriteExisting: options.overwrite,\n }\n if (proxyForUpsert !== undefined) importOpts.proxy = proxyForUpsert\n const result = await importManySources(items, store, importOpts)\n console.log(`Imported ${result.imported}, replaced ${result.replaced}${result.errors.length > 0 ? `, ${result.errors.length} failed` : ''}`)\n for (const error of result.errors) console.log(` ! ${error}`)\n}\n\n/**\n * Write one exported credential blob to disk.\n *\n * 0600: a blob carries a live access+refresh token in plain base64. Every other\n * credential write in this repo sets an owner-only mode; this was the one\n * `writeFileSync` without it, so the default umask (0644) left the export\n * world-readable on a shared machine.\n */\nexport function writeBlobFile(file: string, blob: string): void {\n writeFileSync(file, blob + '\\n', { mode: 0o600 })\n}\n\nasync function exportCommand(options: { index?: string; out?: string }) {\n const store = createReadOnlyStoreOrExit()\n const sessions = new AgySessionManager({ store })\n const storage = await store.load()\n const indices = options.index !== undefined\n ? [Number(options.index)]\n : storage.accounts.map((_, i) => i)\n\n let exported = 0\n for (const index of indices) {\n const account = storage.accounts[index]\n if (!account) {\n console.log(`[${index}] not found`)\n continue\n }\n const result = await sessions.exportBlob(index)\n if (!result.blob) {\n console.log(`[${index}] ${account.email ?? ''} — FAILED: ${result.error}`)\n continue\n }\n if (options.out) {\n const file = join(options.out, `dsh-agy-${index}.blob`)\n writeBlobFile(file, result.blob)\n console.log(`[${index}] ${account.email ?? ''} — wrote ${file}`)\n } else {\n console.log(result.blob)\n }\n exported++\n }\n if (!options.out) console.log(`\\n${exported} blob(s) exported — one line each, paste into a remote import`)\n}\n\nasync function verifyCommand(options: { index?: string }) {\n const store = createReadOnlyStoreOrExit()\n const sessions = new AgySessionManager({ store })\n const storage = await store.load()\n const indices = options.index !== undefined\n ? [Number(options.index)]\n : storage.accounts.map((_, i) => i)\n\n for (const index of indices) {\n const account = storage.accounts[index]\n if (!account) {\n console.log(`[${index}] not found`)\n continue\n }\n const result = await sessions.verifyAccount(index)\n if (result.ok) {\n console.log(`[${index}] ${account.email ?? ''} — OK${result.email && result.email !== account.email ? ` (userinfo: ${result.email})` : ''}`)\n } else {\n console.log(`[${index}] ${account.email ?? ''} — FAILED: ${result.error}`)\n }\n }\n}\n\nasync function healthCommand(options: { interval?: string; index?: string[] }) {\n const store = createReadOnlyStoreOrExit()\n const sessions = new AgySessionManager({\n store,\n onHealthReport: (results) => {\n for (const result of results) {\n if (result.ok) console.log(`[${result.index}] ${result.email ?? ''} — OK`)\n else console.log(`[${result.index}] ${result.email ?? ''} — FAILED: ${result.error}`)\n }\n },\n })\n const indices = options.index?.map((value) => Number(value))\n\n if (options.interval) {\n const intervalMs = Number(options.interval)\n if (!Number.isFinite(intervalMs) || intervalMs <= 0) {\n console.error('Error: --interval must be a positive number of milliseconds.')\n process.exit(1)\n }\n console.log(`Health probe every ${intervalMs}ms (Ctrl+C to stop).`)\n sessions.startHealthProbe(intervalMs, { unref: false })\n await new Promise<void>(() => {}) // keep the loop alive\n return\n }\n\n const results = await sessions.checkAccounts(indices)\n if (results.length === 0) console.log('No enabled accounts — run `dsh-agy login` first.')\n}\n\nasync function logoutCommand(options: { index?: string; email?: string }) {\n const store = createReadOnlyStoreOrExit()\n await store.mutate((storage) => {\n const index = options.index !== undefined\n ? Number(options.index)\n : options.email\n ? storage.accounts.findIndex((a) => a.email?.toLowerCase() === options.email!.toLowerCase())\n : storage.activeIndex\n if (index < 0 || index >= storage.accounts.length) {\n throw new Error(`account not found (index ${index})`)\n }\n const [removed] = storage.accounts.splice(index, 1)\n if (storage.activeIndex >= storage.accounts.length) storage.activeIndex = 0\n console.log(`Removed account: ${removed?.email ?? `[${index}]`}`)\n })\n}\n\nasync function proxySetCommand(options: { index: string; proxy: string }) {\n const idx = Number(options.index)\n if (!Number.isInteger(idx) || idx < 0) {\n console.error('Invalid --index (must be >= 0)')\n process.exit(1)\n }\n const raw = options.proxy ?? ''\n if (!raw.trim()) {\n console.error('Missing --proxy value')\n process.exit(1)\n }\n let normalized: string\n try {\n normalized = normalizeProxyUrl(raw)\n } catch (error) {\n console.error(`Invalid proxy URL: ${error instanceof Error ? error.message : String(error)}`)\n process.exit(1)\n }\n const store = createStore()\n await store.mutate((storage) => {\n const account = storage.accounts[idx]\n if (!account) throw new Error(`account not found (index ${idx})`)\n account.proxy = normalized\n })\n console.log(`[${idx}] proxy set to ${maskProxyUrl(normalized)}`)\n}\n\nasync function proxyClearCommand(options: { index: string }) {\n const idx = Number(options.index)\n if (!Number.isInteger(idx) || idx < 0) {\n console.error('Invalid --index (must be >= 0)')\n process.exit(1)\n }\n const store = createStore()\n await store.mutate((storage) => {\n const account = storage.accounts[idx]\n if (!account) throw new Error(`account not found (index ${idx})`)\n delete (account as { proxy?: string }).proxy\n })\n console.log(`[${idx}] proxy cleared`)\n}\n\nasync function proxyTestCommand(options: { index: string }) {\n const idx = Number(options.index)\n if (!Number.isInteger(idx) || idx < 0) {\n console.error('Invalid --index (must be >= 0)')\n process.exit(1)\n }\n const store = createReadOnlyStoreOrExit()\n const storage = await store.load()\n const account = storage.accounts[idx]\n if (!account) {\n console.error(`account not found (index ${idx})`)\n process.exit(1)\n }\n if (!account.proxy) {\n console.log(`[${idx}] no proxy configured`)\n return\n }\n const masked = maskProxyUrl(account.proxy)\n const reachable = await isProxyReachable(account.proxy)\n if (reachable) console.log(`[${idx}] ${masked} — ok`)\n else console.log(`[${idx}] ${masked} — proxy_unreachable`)\n}\n\nasync function proxyListCommand() {\n const store = createReadOnlyStoreOrExit()\n const storage = await store.load()\n if (storage.accounts.length === 0) {\n console.log('No agy accounts.')\n return\n }\n for (const [index, account] of storage.accounts.entries()) {\n const masked = maskProxyUrl(account.proxy)\n console.log(` [${index}] ${account.email ?? '(no email)'} — ${masked ?? '(no proxy)'}`)\n }\n}\n\nexport function createProgram(): Command {\n const program = new Command()\n program\n .name('dsh-agy')\n .description('Google Antigravity (agy) account management for DeepSeek Harness')\n .version(PACKAGE_VERSION)\n\n program.hook('preAction', () => {\n if (isAgyDisabled()) {\n console.error('dsh-agy is disabled (DSH_AGY_DISABLE=1).')\n process.exit(1)\n }\n })\n\n program\n .command('login')\n .description('OAuth login (browser, or headless paste)')\n .option('--headless', 'print the URL and wait for a pasted redirect URL', false)\n .option('--blob', 'print a paste-credential blob instead of storing the account', false)\n .option('--port <n>', 'loopback callback port', '51121')\n .option('--project <id>', 'bind the login to a specific project')\n .option('--timeout <ms>', 'callback timeout', '300000')\n .option('--proxy <url>', 'per-account proxy URL (http/https/socks5); empty to clear')\n .action(async (options) => {\n await loginCommand({ ...options, timeout: options.timeout })\n })\n\n program\n .command('status')\n .description('List accounts and their health')\n .action(async () => {\n await statusCommand()\n })\n\n program\n .command('import')\n .description('Import agy token files or paste credentials')\n .argument('[files...]', 'paths to agy auth.json token files (multiple allowed)')\n .option('--blob', 'the pasted value is a credential blob', false)\n .option('--email <email>', 'account email (skips userinfo verification)')\n .option('--overwrite', 'replace an existing account with the same email', false)\n .option('--proxy <url>', 'per-account proxy URL (http/https/socks5); empty to clear')\n .action(async (files: string[] | undefined, options: { blob: boolean; email?: string; overwrite: boolean; proxy?: string }) => {\n await importCommand({ ...options, files })\n })\n\n program\n .command('export')\n .description('Export account credentials as paste blobs')\n .option('--index <n>', 'export one account by index; default all')\n .option('--out <dir>', 'write one dsh-agy-<index>.blob file per account into this directory (default: print to stdout)')\n .action(async (options: { index?: string; out?: string }) => {\n await exportCommand(options)\n })\n\n program\n .command('verify')\n .description('Verify account credentials (refresh + userinfo)')\n .option('--index <n>', 'verify one account by index; default all')\n .action(async (options: { index?: string }) => {\n await verifyCommand(options)\n })\n\n program\n .command('health')\n .description('Check every enabled account (refresh + userinfo), optionally on an interval')\n .option('--interval <ms>', 'repeat on an interval instead of once')\n .option('--index <n...>', 'check only these accounts')\n .action(async (options: { interval?: string; index?: string[] }) => {\n await healthCommand(options)\n })\n\n program\n .command('logout')\n .description('Remove an account')\n .option('--index <n>', 'account index (default: active)')\n .option('--email <email>', 'account email')\n .action(async (options: { index?: string; email?: string }) => {\n await logoutCommand(options)\n })\n\n const proxy = program.command('proxy').description('Manage per-account proxies')\n proxy\n .command('set')\n .description('Set proxy for an account')\n .requiredOption('--index <n>', 'account index')\n .requiredOption('--proxy <url>', 'proxy URL (http/https/socks5)')\n .action(async (options: { index: string; proxy: string }) => {\n await proxySetCommand(options)\n })\n proxy\n .command('clear')\n .description('Clear proxy for an account')\n .requiredOption('--index <n>', 'account index')\n .action(async (options: { index: string }) => {\n await proxyClearCommand(options)\n })\n proxy\n .command('test')\n .description('Test proxy reachability for an account (TCP 2s fast-fail)')\n .requiredOption('--index <n>', 'account index')\n .action(async (options: { index: string }) => {\n await proxyTestCommand(options)\n })\n proxy\n .command('list')\n .description('List accounts with masked proxies')\n .action(async () => {\n await proxyListCommand()\n })\n\n return program\n}\n\nexport { AGY_DEFAULT_REDIRECT_URI }\n"],"mappings":"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"}
|