@bulkgrid/cli 0.1.0 → 0.2.0
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 +73 -0
- package/dist/auth-C7pTl5XB.js +723 -0
- package/dist/auth-C7pTl5XB.js.map +1 -0
- package/dist/cli.d.ts +1 -1
- package/dist/cli.js +81 -22
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +79 -18
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -6
- package/package.json +6 -5
- package/dist/chunk-OUGLFLZG.js +0 -351
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth-C7pTl5XB.js","names":[],"sources":["../src/init.ts","../src/authStorage.ts","../src/oauthCallback.ts","../src/auth.ts"],"sourcesContent":["import { spawnSync } from 'node:child_process';\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { dirname, join } from 'node:path';\nimport { checkbox, confirm, input, password, select } from '@inquirer/prompts';\n\nconst DEFAULT_SERVER_NAME = 'bulkgrid';\nconst API_KEY_ENV_VAR = 'BULKGRID_API_KEY';\nconst MCP_URL_ENV_VAR = 'BULKGRID_MCP_URL';\nconst DASHBOARD_API_KEYS_URL = 'https://bulkgrid.com/dashboard/settings/api-keys';\n\ntype AgentName = 'cursor' | 'vscode' | 'claude' | 'codex';\ntype AuthMode = 'browser' | 'manual' | 'skip';\n\nconst AGENT_CHOICES: readonly { label: string; value: AgentName }[] = [\n { label: 'Cursor', value: 'cursor' },\n { label: 'VS Code', value: 'vscode' },\n { label: 'Claude Code', value: 'claude' },\n { label: 'Codex', value: 'codex' },\n];\n\ninterface InitFlags {\n readonly all?: boolean;\n readonly cursor?: boolean;\n readonly vscode?: boolean;\n readonly claude?: boolean;\n readonly codex?: boolean;\n}\n\nexport interface InitCommandOptions extends InitFlags {\n readonly mcpUrl?: string;\n readonly apiKey?: string;\n readonly global?: boolean;\n readonly project?: boolean;\n readonly yes?: boolean;\n readonly writeApiKey?: boolean;\n readonly installGlobal?: boolean;\n readonly auth?: AuthMode;\n}\n\ninterface InitContext {\n readonly agents: readonly AgentName[];\n readonly mcpUrl: string;\n readonly apiKey?: string;\n readonly scope: 'project' | 'global';\n readonly writeApiKey: boolean;\n}\n\ntype McpConfigContext = Pick<InitContext, 'apiKey' | 'mcpUrl' | 'writeApiKey'>;\nexport type JsonObject = { [key: string]: JsonValue };\ntype JsonValue = string | number | boolean | null | JsonObject | JsonValue[];\n\ninterface SetupResult {\n readonly agent: AgentName;\n readonly status: 'configured' | 'skipped';\n readonly message: string;\n}\n\nfunction isJsonObject(value: unknown): value is JsonObject {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction parseJsonObject(filePath: string): JsonObject {\n if (!existsSync(filePath)) {\n return {};\n }\n\n const parsed: unknown = JSON.parse(readFileSync(filePath, 'utf8'));\n if (!isJsonObject(parsed)) {\n throw new Error(`${filePath} must contain a JSON object`);\n }\n\n return parsed;\n}\n\nfunction writeJsonFile(filePath: string, data: JsonObject): void {\n mkdirSync(dirname(filePath), { recursive: true });\n writeFileSync(filePath, `${JSON.stringify(data, null, 2)}\\n`);\n}\n\nfunction getObjectProperty(parent: JsonObject, key: string): JsonObject {\n const current = parent[key];\n if (isJsonObject(current)) {\n return current;\n }\n\n const next: JsonObject = {};\n parent[key] = next;\n return next;\n}\n\nfunction buildAuthorizationHeader(context: McpConfigContext, inputExpression: string): string {\n if (context.writeApiKey && context.apiKey) {\n return `Bearer ${context.apiKey}`;\n }\n\n return `Bearer ${inputExpression}`;\n}\n\nfunction buildCursorServer(context: McpConfigContext): JsonObject {\n return {\n url: context.mcpUrl,\n headers: {\n Authorization: buildAuthorizationHeader(context, `\\${env:${API_KEY_ENV_VAR}}`),\n },\n };\n}\n\nexport function mergeCursorConfig(existing: JsonObject, context: McpConfigContext): JsonObject {\n const next = { ...existing };\n const servers = getObjectProperty(next, 'mcpServers');\n servers[DEFAULT_SERVER_NAME] = buildCursorServer(context);\n return next;\n}\n\nfunction buildVsCodeConfig(context: McpConfigContext): JsonObject {\n return {\n inputs: [\n {\n type: 'promptString',\n id: 'bulkgrid-api-key',\n description: 'Bulkgrid API Key',\n password: true,\n },\n ],\n servers: {\n [DEFAULT_SERVER_NAME]: {\n type: 'http',\n url: context.mcpUrl,\n headers: {\n Authorization: buildAuthorizationHeader(context, '${input:bulkgrid-api-key}'),\n },\n },\n },\n };\n}\n\nexport function mergeVsCodeConfig(existing: JsonObject, context: McpConfigContext): JsonObject {\n const next = { ...existing };\n const config = buildVsCodeConfig(context);\n const existingServers = getObjectProperty(next, 'servers');\n const configServers = getObjectProperty(config, 'servers');\n existingServers[DEFAULT_SERVER_NAME] = configServers[DEFAULT_SERVER_NAME] ?? {};\n\n if (!Array.isArray(next.inputs)) {\n next.inputs = config.inputs ?? [];\n return next;\n }\n\n const hasInput = next.inputs.some(item => isJsonObject(item) && item.id === 'bulkgrid-api-key');\n if (!hasInput && Array.isArray(config.inputs)) {\n next.inputs = [...next.inputs, ...config.inputs];\n }\n\n return next;\n}\n\nfunction resolveCursorPath(scope: InitContext['scope']): string {\n if (scope === 'global') {\n return join(homedir(), '.cursor', 'mcp.json');\n }\n\n return join(process.cwd(), '.cursor', 'mcp.json');\n}\n\nfunction resolveVsCodePath(scope: InitContext['scope']): string {\n if (scope === 'global') {\n if (process.platform === 'darwin') {\n return join(homedir(), 'Library', 'Application Support', 'Code', 'User', 'mcp.json');\n }\n if (process.platform === 'win32') {\n return join(homedir(), 'AppData', 'Roaming', 'Code', 'User', 'mcp.json');\n }\n\n return join(homedir(), '.config', 'Code', 'User', 'mcp.json');\n }\n\n return join(process.cwd(), '.vscode', 'mcp.json');\n}\n\nfunction setupCursor(context: InitContext): SetupResult {\n const filePath = resolveCursorPath(context.scope);\n const config = mergeCursorConfig(parseJsonObject(filePath), context);\n writeJsonFile(filePath, config);\n\n return {\n agent: 'cursor',\n status: 'configured',\n message: `Wrote ${filePath}`,\n };\n}\n\nfunction setupVsCode(context: InitContext): SetupResult {\n const filePath = resolveVsCodePath(context.scope);\n const config = mergeVsCodeConfig(parseJsonObject(filePath), context);\n writeJsonFile(filePath, config);\n\n return {\n agent: 'vscode',\n status: 'configured',\n message: `Wrote ${filePath}`,\n };\n}\n\nfunction commandExists(command: string): boolean {\n const result = spawnSync(command, ['--version'], { encoding: 'utf8', stdio: 'ignore' });\n return result.status === 0;\n}\n\nfunction runCommand(command: string, args: readonly string[]): void {\n const result = spawnSync(command, args, { encoding: 'utf8', stdio: 'inherit' });\n if (result.error) {\n throw result.error;\n }\n if (result.status !== 0) {\n throw new Error(`${command} ${args.join(' ')} failed with exit code ${result.status ?? 'unknown'}`);\n }\n}\n\nfunction printInitBanner(): void {\n console.log('');\n console.log(' ▦ Bulkgrid init');\n console.log('');\n}\n\nasync function promptForConfirmation(message: string, defaultValue: boolean): Promise<boolean> {\n return confirm({\n message,\n default: defaultValue,\n });\n}\n\nasync function promptForSelect<TValue extends string>(\n message: string,\n choices: readonly { label: string; value: TValue }[],\n): Promise<TValue> {\n return select({\n message,\n choices: choices.map(choice => ({\n name: choice.label,\n value: choice.value,\n })),\n });\n}\n\nasync function promptForMultiSelect<TValue extends string>(\n message: string,\n choices: readonly { label: string; value: TValue }[],\n): Promise<readonly TValue[]> {\n return checkbox({\n message,\n choices: choices.map(choice => ({\n name: choice.label,\n value: choice.value,\n checked: true,\n })),\n required: true,\n pageSize: choices.length,\n });\n}\n\nasync function maybeInstallGlobally(options: InitCommandOptions): Promise<void> {\n if (options.installGlobal) {\n runCommand('npm', ['install', '-g', '@bulkgrid/cli']);\n return;\n }\n\n if (options.yes) {\n return;\n }\n\n const shouldInstall = await promptForConfirmation('Install @bulkgrid/cli globally?', false);\n if (shouldInstall) {\n runCommand('npm', ['install', '-g', '@bulkgrid/cli']);\n }\n}\n\nfunction openBrowser(url: string): void {\n let command: string;\n let args: string[];\n\n if (process.platform === 'darwin') {\n command = 'open';\n args = [url];\n } else if (process.platform === 'win32') {\n command = 'cmd';\n args = ['/c', 'start', '', url];\n } else {\n command = 'xdg-open';\n args = [url];\n }\n\n const result = spawnSync(command, args, { encoding: 'utf8', stdio: 'ignore' });\n if (result.status !== 0) {\n console.log(`Open ${url} to create a Bulkgrid API key.`);\n }\n}\n\nasync function resolveApiKey(options: InitCommandOptions): Promise<string | undefined> {\n const configuredApiKey = options.apiKey ?? process.env[API_KEY_ENV_VAR];\n if (configuredApiKey || options.yes) {\n return configuredApiKey;\n }\n\n const authMode =\n options.auth ??\n (await promptForSelect('Authenticate to Bulkgrid', [\n { label: 'Open the dashboard and paste a new API key', value: 'browser' },\n { label: 'Enter an existing API key', value: 'manual' },\n { label: 'Skip this step', value: 'skip' },\n ]));\n\n if (authMode === 'skip') {\n console.log(`Skipped. Set ${API_KEY_ENV_VAR} later or use client-side prompts.`);\n return undefined;\n }\n\n if (authMode === 'browser') {\n openBrowser(DASHBOARD_API_KEYS_URL);\n console.log('Create an API key with mcp:use and search:query scopes.');\n }\n\n const apiKey = await password({\n message: 'Bulkgrid API key',\n mask: '*',\n validate: value => value.trim().length > 0 || 'Enter a Bulkgrid API key.',\n });\n return apiKey || undefined;\n}\n\nfunction setupCodex(context: InitContext): SetupResult {\n if (!commandExists('codex')) {\n return {\n agent: 'codex',\n status: 'skipped',\n message: 'codex command was not found',\n };\n }\n\n runCommand('codex', ['mcp', 'add', DEFAULT_SERVER_NAME, '--url', context.mcpUrl, '--bearer-token-env-var', API_KEY_ENV_VAR]);\n\n return {\n agent: 'codex',\n status: 'configured',\n message: `Registered ${DEFAULT_SERVER_NAME} with codex mcp add`,\n };\n}\n\nfunction setupClaude(context: InitContext): SetupResult {\n if (!commandExists('claude')) {\n return {\n agent: 'claude',\n status: 'skipped',\n message: 'claude command was not found',\n };\n }\n\n if (!context.apiKey) {\n return {\n agent: 'claude',\n status: 'skipped',\n message: `Set ${API_KEY_ENV_VAR} or pass --api-key to configure Claude Code`,\n };\n }\n\n const args = ['mcp', 'add', '--transport', 'http'];\n if (context.scope === 'global') {\n args.push('--scope', 'user');\n }\n args.push(DEFAULT_SERVER_NAME, context.mcpUrl, '--header', `Authorization: Bearer ${context.apiKey}`);\n runCommand('claude', args);\n\n return {\n agent: 'claude',\n status: 'configured',\n message: `Registered ${DEFAULT_SERVER_NAME} with claude mcp add`,\n };\n}\n\nasync function resolveAgents(options: InitCommandOptions): Promise<readonly AgentName[]> {\n if (options.all || (!options.cursor && !options.vscode && !options.claude && !options.codex)) {\n if (!options.all && !options.yes) {\n const shouldConfigure = await promptForConfirmation('Configure the Bulkgrid MCP server for clients?', true);\n if (!shouldConfigure) {\n return [];\n }\n\n return promptForMultiSelect('Choose MCP clients to configure:', AGENT_CHOICES);\n }\n\n return ['cursor', 'vscode', 'claude', 'codex'];\n }\n\n const agents: AgentName[] = [];\n if (options.cursor) {\n agents.push('cursor');\n }\n if (options.vscode) {\n agents.push('vscode');\n }\n if (options.claude) {\n agents.push('claude');\n }\n if (options.codex) {\n agents.push('codex');\n }\n\n return agents;\n}\n\nasync function promptForValue(message: string): Promise<string> {\n return input({\n message,\n validate: value => value.trim().length > 0 || 'Enter a value.',\n });\n}\n\nasync function buildContext(options: InitCommandOptions): Promise<InitContext> {\n const configuredUrl = options.mcpUrl ?? process.env[MCP_URL_ENV_VAR];\n const mcpUrl = configuredUrl ?? (options.yes ? undefined : await promptForValue('Bulkgrid MCP URL: '));\n if (!mcpUrl) {\n throw new Error(`Missing MCP URL. Pass --mcp-url or set ${MCP_URL_ENV_VAR}.`);\n }\n\n const apiKey = await resolveApiKey(options);\n const agents = await resolveAgents(options);\n\n return {\n agents,\n mcpUrl,\n apiKey,\n scope: options.global ? 'global' : 'project',\n writeApiKey: options.writeApiKey ?? false,\n };\n}\n\nexport async function runInitCommand(options: InitCommandOptions): Promise<readonly SetupResult[]> {\n printInitBanner();\n await maybeInstallGlobally(options);\n\n const context = await buildContext(options);\n const results: SetupResult[] = [];\n\n for (const agent of context.agents) {\n if (agent === 'cursor') {\n results.push(setupCursor(context));\n } else if (agent === 'vscode') {\n results.push(setupVsCode(context));\n } else if (agent === 'claude') {\n results.push(setupClaude(context));\n } else if (agent === 'codex') {\n results.push(setupCodex(context));\n }\n }\n\n return results;\n}\n","import { createHash, randomUUID } from 'node:crypto';\nimport { chmod, mkdir, readFile, rename, unlink, writeFile } from 'node:fs/promises';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\nimport { z } from 'zod';\n\nexport const credentialsSchema = z.object({\n origin: z.string().url(),\n issuer: z.string().url(),\n tokenEndpoint: z.string().url(),\n clientId: z.string().min(1),\n accessToken: z.string().min(1),\n refreshToken: z.string().min(1),\n expiresAt: z.number().finite(),\n});\nexport type CliCredentials = z.infer<typeof credentialsSchema>;\n\nfunction hasCode(error: unknown, code: string): boolean {\n return error instanceof Error && 'code' in error && error.code === code;\n}\n\nexport class AuthStorage {\n constructor(private readonly directory = join(homedir(), '.config', 'bulkgrid')) {}\n\n private path(origin: string): string {\n return join(this.directory, `${createHash('sha256').update(origin).digest('hex')}.json`);\n }\n\n async read(origin: string): Promise<CliCredentials | undefined> {\n try {\n const result = credentialsSchema.safeParse(JSON.parse(await readFile(this.path(origin), 'utf8')));\n if (!result.success || result.data.origin !== origin) {\n throw new Error('Invalid saved CLI credentials. Run bulkgrid logout --local to clear them.');\n }\n return result.data;\n } catch (error) {\n if (hasCode(error, 'ENOENT')) {\n return undefined;\n }\n if (error instanceof SyntaxError) {\n throw new Error('Invalid saved CLI credentials. Run bulkgrid logout --local to clear them.');\n }\n throw error;\n }\n }\n\n async save(credentials: CliCredentials): Promise<void> {\n await mkdir(this.directory, { recursive: true, mode: 0o700 });\n await chmod(this.directory, 0o700);\n const target = this.path(credentials.origin);\n const temporary = `${target}.${randomUUID()}.tmp`;\n try {\n await writeFile(temporary, JSON.stringify(credentials), { mode: 0o600, flag: 'wx' });\n await rename(temporary, target);\n } finally {\n await unlink(temporary).catch(error => {\n if (!hasCode(error, 'ENOENT')) {\n throw error;\n }\n });\n }\n }\n\n async clear(origin: string): Promise<void> {\n await unlink(this.path(origin)).catch(error => {\n if (!hasCode(error, 'ENOENT')) {\n throw error;\n }\n });\n }\n\n // Hold one lock across refresh and persistence, including across CLI processes.\n async exclusive<T>(origin: string, operation: () => Promise<T>): Promise<T> {\n await mkdir(this.directory, { recursive: true, mode: 0o700 });\n const lock = `${this.path(origin)}.lock`;\n try {\n await writeFile(lock, String(process.pid), { flag: 'wx', mode: 0o600 });\n } catch (error) {\n if (hasCode(error, 'EEXIST')) {\n throw new Error(`Another CLI authentication operation is running. If it has stopped, remove ${lock} and retry.`);\n }\n throw error;\n }\n try {\n return await operation();\n } finally {\n await unlink(lock);\n }\n }\n}\n","import { createServer } from 'node:http';\nimport { timingSafeEqual } from 'node:crypto';\n\nexport const CLI_CALLBACK_PATH = '/bulkgrid/cli/callback';\n\nexport async function listenForOAuthCallback(state: string, issuer: string, timeoutMs = 300_000) {\n let resolveCode!: (code: string) => void;\n let rejectCode!: (error: Error) => void;\n const code = new Promise<string>((resolve, reject) => {\n resolveCode = resolve;\n rejectCode = reject;\n });\n // Discovery can fail before the caller begins waiting for the callback.\n void code.catch(() => undefined);\n let redirectUri = '';\n const server = createServer((request, response) => {\n response.setHeader('Content-Type', 'text/plain; charset=utf-8');\n response.setHeader('Cache-Control', 'no-store');\n response.setHeader('Referrer-Policy', 'no-referrer');\n let url: URL;\n try {\n url = new URL(request.url ?? '/', redirectUri);\n } catch {\n response.writeHead(400).end('Invalid callback URL.');\n return;\n }\n if (request.method !== 'GET' || url.pathname !== CLI_CALLBACK_PATH || request.headers.host !== new URL(redirectUri).host) {\n response.writeHead(404).end('Not found');\n return;\n }\n const receivedState = url.searchParams.get('state') ?? '';\n if (\n Buffer.byteLength(receivedState) !== Buffer.byteLength(state) ||\n !timingSafeEqual(Buffer.from(receivedState), Buffer.from(state))\n ) {\n response.writeHead(400).end('Invalid login state. Return to the original login tab.');\n return;\n }\n if (url.searchParams.has('iss') && url.searchParams.get('iss') !== issuer) {\n response.writeHead(400).end('Invalid authorization server.');\n rejectCode(new Error('OAuth callback issuer did not match.'));\n return;\n }\n if (url.searchParams.has('error')) {\n response.writeHead(400).end('Login was declined. Return to your terminal.');\n rejectCode(new Error('Authorization was declined. Run bulkgrid login to try again.'));\n return;\n }\n const authorizationCode = url.searchParams.get('code');\n if (!authorizationCode) {\n response.writeHead(400).end('Missing authorization code.');\n return;\n }\n response.end('Authorization received. Return to your terminal to check login completed.');\n resolveCode(authorizationCode);\n });\n await new Promise<void>((resolve, reject) => {\n server.once('error', reject);\n server.listen(0, '127.0.0.1', () => {\n server.removeListener('error', reject);\n resolve();\n });\n });\n const address = server.address();\n if (!address || typeof address === 'string') {\n server.close();\n throw new Error('Unable to start the CLI login callback.');\n }\n redirectUri = `http://127.0.0.1:${address.port}${CLI_CALLBACK_PATH}`;\n const timer = setTimeout(() => rejectCode(new Error('Login timed out. Run bulkgrid login to try again.')), timeoutMs);\n const cancel = () => rejectCode(new Error('Login cancelled.'));\n process.once('SIGINT', cancel);\n process.once('SIGTERM', cancel);\n return {\n redirectUri,\n code,\n close: () => {\n clearTimeout(timer);\n process.removeListener('SIGINT', cancel);\n process.removeListener('SIGTERM', cancel);\n server.closeAllConnections();\n server.close();\n },\n };\n}\n","import { spawn } from 'node:child_process';\nimport { createHash, randomBytes } from 'node:crypto';\nimport { z } from 'zod';\nimport { AuthStorage, type CliCredentials } from './authStorage.js';\nimport { listenForOAuthCallback } from './oauthCallback.js';\n\nconst DEFAULT_ORIGIN = 'https://bulkgrid.com';\nconst identityScopes = 'openid email profile';\nconst metadataSchema = z.object({\n issuer: z.string().url(),\n authorization_endpoint: z.string().url(),\n token_endpoint: z.string().url(),\n registration_endpoint: z.string().url(),\n code_challenge_methods_supported: z.array(z.string()),\n});\nconst tokensSchema = z.object({\n access_token: z.string().min(1),\n refresh_token: z.string().min(1),\n token_type: z.string().refine(value => value.toLowerCase() === 'bearer'),\n expires_in: z.number().positive().finite(),\n});\nconst sessionSchema = z.object({\n userId: z.string(),\n workspaceId: z.string(),\n clientName: z.string().nullable(),\n scopes: z.array(z.string()),\n collectionScope: z.enum(['all', 'selected']),\n});\nexport type CliSession = z.infer<typeof sessionSchema>;\nexport interface LoginOptions {\n readonly url?: string;\n readonly browser?: boolean;\n}\n\nclass HttpError extends Error {\n constructor(readonly status: number) {\n super(`Authentication request failed (HTTP ${status}). Check the server configuration or run bulkgrid login again.`);\n }\n}\n\nfunction secureUrl(value: string): URL {\n const url = new URL(value);\n const local = ['localhost', '127.0.0.1', '[::1]'].includes(url.hostname);\n if ((url.protocol !== 'https:' && !(url.protocol === 'http:' && local)) || url.username || url.password || url.hash) {\n throw new Error('Authentication URLs must use HTTPS (HTTP is allowed only for local development).');\n }\n return url;\n}\n\nexport function resolveOrigin(value = process.env.BULKGRID_URL ?? DEFAULT_ORIGIN): string {\n const url = secureUrl(value);\n if (url.pathname !== '/' || url.search) {\n throw new Error('Use the Bulkgrid base URL, such as https://bulkgrid.com, without a path or query.');\n }\n return url.origin;\n}\n\nexport function openLoginBrowser(url: string): void {\n // The generated URL is passed as an argument, never interpolated into a shell command.\n const command = process.platform === 'darwin' ? 'open' : process.platform === 'win32' ? 'rundll32' : 'xdg-open';\n const args = process.platform === 'win32' ? ['url.dll,FileProtocolHandler', url] : [url];\n const child = spawn(command, args, { stdio: 'ignore', detached: true });\n child.on('error', () => console.log('Could not open a browser. Open the login URL above manually.'));\n child.unref();\n}\n\nexport class CliAuth {\n constructor(\n private readonly storage = new AuthStorage(),\n private readonly fetcher: typeof fetch = fetch,\n ) {}\n\n private async request(url: string, init?: RequestInit): Promise<Response> {\n secureUrl(url);\n const response = await this.fetcher(url, { ...init, redirect: 'error', signal: AbortSignal.timeout(15_000) });\n if (!response.ok) {\n throw new HttpError(response.status);\n }\n return response;\n }\n\n private async requestJson(url: string, init?: RequestInit): Promise<unknown> {\n const response = await this.request(url, init);\n try {\n return await response.json();\n } catch {\n throw new Error('The authentication server returned invalid JSON.');\n }\n }\n\n private async discover(origin: string) {\n const resource = `${origin}/api/v1/mcp`;\n const response = await this.requestJson(`${origin}/.well-known/oauth-protected-resource/api/v1/mcp`);\n const protectedResource = z\n .object({ resource: z.literal(resource), authorization_servers: z.array(z.string().url()).length(1) })\n .parse(response);\n const issuer = secureUrl(protectedResource.authorization_servers[0]!);\n if (issuer.search) {\n throw new Error('Invalid authorization server issuer.');\n }\n const discoveryUrl = `${issuer.origin}/.well-known/oauth-authorization-server${issuer.pathname === '/' ? '' : issuer.pathname}`;\n const metadata = metadataSchema.parse(await this.requestJson(discoveryUrl));\n if (\n metadata.issuer !== protectedResource.authorization_servers[0] ||\n !metadata.code_challenge_methods_supported.includes('S256')\n ) {\n throw new Error('Authorization server discovery must match its issuer and support PKCE S256.');\n }\n for (const endpoint of [metadata.authorization_endpoint, metadata.token_endpoint, metadata.registration_endpoint]) {\n if (secureUrl(endpoint).origin !== issuer.origin) {\n throw new Error('OAuth endpoints must belong to the discovered authorization server.');\n }\n }\n return metadata;\n }\n\n async login(options: LoginOptions = {}, openBrowser: (url: string) => void = openLoginBrowser): Promise<CliSession> {\n const origin = resolveOrigin(options.url);\n return this.storage.exclusive(origin, async () => {\n if (await this.storage.read(origin)) {\n throw new Error('A CLI login is already saved for this server. Use bulkgrid status or bulkgrid logout first.');\n }\n const metadata = await this.discover(origin);\n const verifier = randomBytes(32).toString('base64url');\n const state = randomBytes(32).toString('base64url');\n const callback = await listenForOAuthCallback(state, metadata.issuer);\n try {\n const registration = z.object({ client_id: z.string().min(1) }).parse(\n await this.requestJson(metadata.registration_endpoint, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n client_name: 'Bulkgrid CLI',\n client_uri: origin,\n redirect_uris: [callback.redirectUri],\n grant_types: ['authorization_code', 'refresh_token'],\n response_types: ['code'],\n token_endpoint_auth_method: 'none',\n scope: identityScopes,\n }),\n }),\n );\n const authorizationUrl = new URL(metadata.authorization_endpoint);\n authorizationUrl.search = new URLSearchParams({\n response_type: 'code',\n client_id: registration.client_id,\n redirect_uri: callback.redirectUri,\n scope: identityScopes,\n state,\n code_challenge: createHash('sha256').update(verifier).digest('base64url'),\n code_challenge_method: 'S256',\n prompt: 'consent',\n }).toString();\n console.log(`Sign in and approve access:\\n${authorizationUrl.href}`);\n if (options.browser !== false) {\n openBrowser(authorizationUrl.href);\n }\n const code = await callback.code;\n const tokens = await this.exchange(metadata.token_endpoint, {\n grant_type: 'authorization_code',\n client_id: registration.client_id,\n code,\n redirect_uri: callback.redirectUri,\n code_verifier: verifier,\n });\n const credentials: CliCredentials = {\n origin,\n issuer: metadata.issuer,\n tokenEndpoint: metadata.token_endpoint,\n clientId: registration.client_id,\n accessToken: tokens.access_token,\n refreshToken: tokens.refresh_token,\n expiresAt: Date.now() + tokens.expires_in * 1000,\n };\n // Persist before checking the resource so a transient API failure can be retried or logged out.\n await this.storage.save(credentials);\n return await this.session(credentials);\n } finally {\n callback.close();\n }\n });\n }\n\n private async exchange(endpoint: string, body: Record<string, string>) {\n return tokensSchema.parse(\n await this.requestJson(endpoint, {\n method: 'POST',\n headers: { 'Content-Type': 'application/x-www-form-urlencoded' },\n body: new URLSearchParams(body),\n }),\n );\n }\n\n private async credentials(origin: string): Promise<CliCredentials> {\n const saved = await this.storage.read(origin);\n if (!saved) {\n throw new Error('Not logged in. Run bulkgrid login.');\n }\n if (secureUrl(saved.tokenEndpoint).origin !== secureUrl(saved.issuer).origin) {\n throw new Error('Saved token endpoint does not match the authorization server. Log out locally and sign in again.');\n }\n if (saved.expiresAt > Date.now() + 60_000) {\n return saved;\n }\n const tokens = await this.exchange(saved.tokenEndpoint, {\n grant_type: 'refresh_token',\n client_id: saved.clientId,\n refresh_token: saved.refreshToken,\n });\n const refreshed = {\n ...saved,\n accessToken: tokens.access_token,\n refreshToken: tokens.refresh_token,\n expiresAt: Date.now() + tokens.expires_in * 1000,\n };\n await this.storage.save(refreshed);\n return refreshed;\n }\n\n private async session(credentials: CliCredentials): Promise<CliSession> {\n return sessionSchema.parse(\n await this.requestJson(`${credentials.origin}/api/v1/cli/session`, {\n headers: { Authorization: `Bearer ${credentials.accessToken}` },\n }),\n );\n }\n\n async status(url?: string): Promise<CliSession> {\n const origin = resolveOrigin(url);\n return this.storage.exclusive(origin, async () => this.session(await this.credentials(origin)));\n }\n\n /** For CLI API consumers; tokens are never copied into agent/project configuration. */\n async getAccessToken(url?: string): Promise<string> {\n const origin = resolveOrigin(url);\n return this.storage.exclusive(origin, async () => {\n const credentials = await this.credentials(origin);\n await this.session(credentials);\n return credentials.accessToken;\n });\n }\n\n async logout(options: { url?: string; local?: boolean } = {}): Promise<void> {\n const origin = resolveOrigin(options.url);\n await this.storage.exclusive(origin, async () => {\n if (options.local) {\n await this.storage.clear(origin);\n return;\n }\n if (!(await this.storage.read(origin))) {\n return;\n }\n try {\n const credentials = await this.credentials(origin);\n await this.request(`${origin}/api/v1/cli/session`, {\n method: 'DELETE',\n headers: { Authorization: `Bearer ${credentials.accessToken}` },\n });\n } catch {\n throw new Error(\n 'Could not revoke the CLI connection. Retry, or revoke it in Connected Apps and use bulkgrid logout --local.',\n );\n }\n await this.storage.clear(origin);\n });\n }\n}\n"],"mappings":";;;;;;;;;;AAMA,MAAM,sBAAsB;AAC5B,MAAM,kBAAkB;AACxB,MAAM,kBAAkB;AACxB,MAAM,yBAAyB;AAK/B,MAAM,gBAAgE;CACpE;EAAE,OAAO;EAAU,OAAO;CAAS;CACnC;EAAE,OAAO;EAAW,OAAO;CAAS;CACpC;EAAE,OAAO;EAAe,OAAO;CAAS;CACxC;EAAE,OAAO;EAAS,OAAO;CAAQ;AACnC;AAuCA,SAAS,aAAa,OAAqC;CACzD,OAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK;AAC5E;AAEA,SAAS,gBAAgB,UAA8B;CACrD,IAAI,CAAC,WAAW,QAAQ,GACtB,OAAO,CAAC;CAGV,MAAM,SAAkB,KAAK,MAAM,aAAa,UAAU,MAAM,CAAC;CACjE,IAAI,CAAC,aAAa,MAAM,GACtB,MAAM,IAAI,MAAM,GAAG,SAAS,4BAA4B;CAG1D,OAAO;AACT;AAEA,SAAS,cAAc,UAAkB,MAAwB;CAC/D,UAAU,QAAQ,QAAQ,GAAG,EAAE,WAAW,KAAK,CAAC;CAChD,cAAc,UAAU,GAAG,KAAK,UAAU,MAAM,MAAM,CAAC,EAAE,GAAG;AAC9D;AAEA,SAAS,kBAAkB,QAAoB,KAAyB;CACtE,MAAM,UAAU,OAAO;CACvB,IAAI,aAAa,OAAO,GACtB,OAAO;CAGT,MAAM,OAAmB,CAAC;CAC1B,OAAO,OAAO;CACd,OAAO;AACT;AAEA,SAAS,yBAAyB,SAA2B,iBAAiC;CAC5F,IAAI,QAAQ,eAAe,QAAQ,QACjC,OAAO,UAAU,QAAQ;CAG3B,OAAO,UAAU;AACnB;AAEA,SAAS,kBAAkB,SAAuC;CAChE,OAAO;EACL,KAAK,QAAQ;EACb,SAAS,EACP,eAAe,yBAAyB,SAAS,UAAU,gBAAgB,EAAE,EAC/E;CACF;AACF;AAEA,SAAgB,kBAAkB,UAAsB,SAAuC;CAC7F,MAAM,OAAO,EAAE,GAAG,SAAS;CAC3B,MAAM,UAAU,kBAAkB,MAAM,YAAY;CACpD,QAAQ,uBAAuB,kBAAkB,OAAO;CACxD,OAAO;AACT;AAEA,SAAS,kBAAkB,SAAuC;CAChE,OAAO;EACL,QAAQ,CACN;GACE,MAAM;GACN,IAAI;GACJ,aAAa;GACb,UAAU;EACZ,CACF;EACA,SAAS,GACN,sBAAsB;GACrB,MAAM;GACN,KAAK,QAAQ;GACb,SAAS,EACP,eAAe,yBAAyB,SAAS,2BAA2B,EAC9E;EACF,EACF;CACF;AACF;AAEA,SAAgB,kBAAkB,UAAsB,SAAuC;CAC7F,MAAM,OAAO,EAAE,GAAG,SAAS;CAC3B,MAAM,SAAS,kBAAkB,OAAO;CACxC,MAAM,kBAAkB,kBAAkB,MAAM,SAAS;CACzD,MAAM,gBAAgB,kBAAkB,QAAQ,SAAS;CACzD,gBAAgB,uBAAuB,cAAc,wBAAwB,CAAC;CAE9E,IAAI,CAAC,MAAM,QAAQ,KAAK,MAAM,GAAG;EAC/B,KAAK,SAAS,OAAO,UAAU,CAAC;EAChC,OAAO;CACT;CAGA,IAAI,CADa,KAAK,OAAO,MAAK,SAAQ,aAAa,IAAI,KAAK,KAAK,OAAO,kBAChE,KAAK,MAAM,QAAQ,OAAO,MAAM,GAC1C,KAAK,SAAS,CAAC,GAAG,KAAK,QAAQ,GAAG,OAAO,MAAM;CAGjD,OAAO;AACT;AAEA,SAAS,kBAAkB,OAAqC;CAC9D,IAAI,UAAU,UACZ,OAAO,KAAK,QAAQ,GAAG,WAAW,UAAU;CAG9C,OAAO,KAAK,QAAQ,IAAI,GAAG,WAAW,UAAU;AAClD;AAEA,SAAS,kBAAkB,OAAqC;CAC9D,IAAI,UAAU,UAAU;EACtB,IAAI,QAAQ,aAAa,UACvB,OAAO,KAAK,QAAQ,GAAG,WAAW,uBAAuB,QAAQ,QAAQ,UAAU;EAErF,IAAI,QAAQ,aAAa,SACvB,OAAO,KAAK,QAAQ,GAAG,WAAW,WAAW,QAAQ,QAAQ,UAAU;EAGzE,OAAO,KAAK,QAAQ,GAAG,WAAW,QAAQ,QAAQ,UAAU;CAC9D;CAEA,OAAO,KAAK,QAAQ,IAAI,GAAG,WAAW,UAAU;AAClD;AAEA,SAAS,YAAY,SAAmC;CACtD,MAAM,WAAW,kBAAkB,QAAQ,KAAK;CAEhD,cAAc,UADC,kBAAkB,gBAAgB,QAAQ,GAAG,OAC/B,CAAC;CAE9B,OAAO;EACL,OAAO;EACP,QAAQ;EACR,SAAS,SAAS;CACpB;AACF;AAEA,SAAS,YAAY,SAAmC;CACtD,MAAM,WAAW,kBAAkB,QAAQ,KAAK;CAEhD,cAAc,UADC,kBAAkB,gBAAgB,QAAQ,GAAG,OAC/B,CAAC;CAE9B,OAAO;EACL,OAAO;EACP,QAAQ;EACR,SAAS,SAAS;CACpB;AACF;AAEA,SAAS,cAAc,SAA0B;CAE/C,OADe,UAAU,SAAS,CAAC,WAAW,GAAG;EAAE,UAAU;EAAQ,OAAO;CAAS,CACzE,CAAC,CAAC,WAAW;AAC3B;AAEA,SAAS,WAAW,SAAiB,MAA+B;CAClE,MAAM,SAAS,UAAU,SAAS,MAAM;EAAE,UAAU;EAAQ,OAAO;CAAU,CAAC;CAC9E,IAAI,OAAO,OACT,MAAM,OAAO;CAEf,IAAI,OAAO,WAAW,GACpB,MAAM,IAAI,MAAM,GAAG,QAAQ,GAAG,KAAK,KAAK,GAAG,EAAE,yBAAyB,OAAO,UAAU,WAAW;AAEtG;AAEA,SAAS,kBAAwB;CAC/B,QAAQ,IAAI,EAAE;CACd,QAAQ,IAAI,mBAAmB;CAC/B,QAAQ,IAAI,EAAE;AAChB;AAEA,eAAe,sBAAsB,SAAiB,cAAyC;CAC7F,OAAO,QAAQ;EACb;EACA,SAAS;CACX,CAAC;AACH;AAEA,eAAe,gBACb,SACA,SACiB;CACjB,OAAO,OAAO;EACZ;EACA,SAAS,QAAQ,KAAI,YAAW;GAC9B,MAAM,OAAO;GACb,OAAO,OAAO;EAChB,EAAE;CACJ,CAAC;AACH;AAEA,eAAe,qBACb,SACA,SAC4B;CAC5B,OAAO,SAAS;EACd;EACA,SAAS,QAAQ,KAAI,YAAW;GAC9B,MAAM,OAAO;GACb,OAAO,OAAO;GACd,SAAS;EACX,EAAE;EACF,UAAU;EACV,UAAU,QAAQ;CACpB,CAAC;AACH;AAEA,eAAe,qBAAqB,SAA4C;CAC9E,IAAI,QAAQ,eAAe;EACzB,WAAW,OAAO;GAAC;GAAW;GAAM;EAAe,CAAC;EACpD;CACF;CAEA,IAAI,QAAQ,KACV;CAIF,IAAI,MADwB,sBAAsB,mCAAmC,KAAK,GAExF,WAAW,OAAO;EAAC;EAAW;EAAM;CAAe,CAAC;AAExD;AAEA,SAAS,YAAY,KAAmB;CACtC,IAAI;CACJ,IAAI;CAEJ,IAAI,QAAQ,aAAa,UAAU;EACjC,UAAU;EACV,OAAO,CAAC,GAAG;CACb,OAAO,IAAI,QAAQ,aAAa,SAAS;EACvC,UAAU;EACV,OAAO;GAAC;GAAM;GAAS;GAAI;EAAG;CAChC,OAAO;EACL,UAAU;EACV,OAAO,CAAC,GAAG;CACb;CAGA,IADe,UAAU,SAAS,MAAM;EAAE,UAAU;EAAQ,OAAO;CAAS,CACnE,CAAC,CAAC,WAAW,GACpB,QAAQ,IAAI,QAAQ,IAAI,+BAA+B;AAE3D;AAEA,eAAe,cAAc,SAA0D;CACrF,MAAM,mBAAmB,QAAQ,UAAU,QAAQ,IAAI;CACvD,IAAI,oBAAoB,QAAQ,KAC9B,OAAO;CAGT,MAAM,WACJ,QAAQ,QACP,MAAM,gBAAgB,4BAA4B;EACjD;GAAE,OAAO;GAA8C,OAAO;EAAU;EACxE;GAAE,OAAO;GAA6B,OAAO;EAAS;EACtD;GAAE,OAAO;GAAkB,OAAO;EAAO;CAC3C,CAAC;CAEH,IAAI,aAAa,QAAQ;EACvB,QAAQ,IAAI,gBAAgB,gBAAgB,mCAAmC;EAC/E;CACF;CAEA,IAAI,aAAa,WAAW;EAC1B,YAAY,sBAAsB;EAClC,QAAQ,IAAI,yDAAyD;CACvE;CAOA,OAAO,MALc,SAAS;EAC5B,SAAS;EACT,MAAM;EACN,WAAU,UAAS,MAAM,KAAK,CAAC,CAAC,SAAS,KAAK;CAChD,CAAC,KACgB,KAAA;AACnB;AAEA,SAAS,WAAW,SAAmC;CACrD,IAAI,CAAC,cAAc,OAAO,GACxB,OAAO;EACL,OAAO;EACP,QAAQ;EACR,SAAS;CACX;CAGF,WAAW,SAAS;EAAC;EAAO;EAAO;EAAqB;EAAS,QAAQ;EAAQ;EAA0B;CAAe,CAAC;CAE3H,OAAO;EACL,OAAO;EACP,QAAQ;EACR,SAAS,cAAc,oBAAoB;CAC7C;AACF;AAEA,SAAS,YAAY,SAAmC;CACtD,IAAI,CAAC,cAAc,QAAQ,GACzB,OAAO;EACL,OAAO;EACP,QAAQ;EACR,SAAS;CACX;CAGF,IAAI,CAAC,QAAQ,QACX,OAAO;EACL,OAAO;EACP,QAAQ;EACR,SAAS,OAAO,gBAAgB;CAClC;CAGF,MAAM,OAAO;EAAC;EAAO;EAAO;EAAe;CAAM;CACjD,IAAI,QAAQ,UAAU,UACpB,KAAK,KAAK,WAAW,MAAM;CAE7B,KAAK,KAAK,qBAAqB,QAAQ,QAAQ,YAAY,yBAAyB,QAAQ,QAAQ;CACpG,WAAW,UAAU,IAAI;CAEzB,OAAO;EACL,OAAO;EACP,QAAQ;EACR,SAAS,cAAc,oBAAoB;CAC7C;AACF;AAEA,eAAe,cAAc,SAA4D;CACvF,IAAI,QAAQ,OAAQ,CAAC,QAAQ,UAAU,CAAC,QAAQ,UAAU,CAAC,QAAQ,UAAU,CAAC,QAAQ,OAAQ;EAC5F,IAAI,CAAC,QAAQ,OAAO,CAAC,QAAQ,KAAK;GAEhC,IAAI,CAAC,MADyB,sBAAsB,kDAAkD,IAAI,GAExG,OAAO,CAAC;GAGV,OAAO,qBAAqB,oCAAoC,aAAa;EAC/E;EAEA,OAAO;GAAC;GAAU;GAAU;GAAU;EAAO;CAC/C;CAEA,MAAM,SAAsB,CAAC;CAC7B,IAAI,QAAQ,QACV,OAAO,KAAK,QAAQ;CAEtB,IAAI,QAAQ,QACV,OAAO,KAAK,QAAQ;CAEtB,IAAI,QAAQ,QACV,OAAO,KAAK,QAAQ;CAEtB,IAAI,QAAQ,OACV,OAAO,KAAK,OAAO;CAGrB,OAAO;AACT;AAEA,eAAe,eAAe,SAAkC;CAC9D,OAAO,MAAM;EACX;EACA,WAAU,UAAS,MAAM,KAAK,CAAC,CAAC,SAAS,KAAK;CAChD,CAAC;AACH;AAEA,eAAe,aAAa,SAAmD;CAE7E,MAAM,SADgB,QAAQ,UAAU,QAAQ,IAAI,qBACnB,QAAQ,MAAM,KAAA,IAAY,MAAM,eAAe,oBAAoB;CACpG,IAAI,CAAC,QACH,MAAM,IAAI,MAAM,0CAA0C,gBAAgB,EAAE;CAG9E,MAAM,SAAS,MAAM,cAAc,OAAO;CAG1C,OAAO;EACL,QAAA,MAHmB,cAAc,OAAO;EAIxC;EACA;EACA,OAAO,QAAQ,SAAS,WAAW;EACnC,aAAa,QAAQ,eAAe;CACtC;AACF;AAEA,eAAsB,eAAe,SAA8D;CACjG,gBAAgB;CAChB,MAAM,qBAAqB,OAAO;CAElC,MAAM,UAAU,MAAM,aAAa,OAAO;CAC1C,MAAM,UAAyB,CAAC;CAEhC,KAAK,MAAM,SAAS,QAAQ,QAC1B,IAAI,UAAU,UACZ,QAAQ,KAAK,YAAY,OAAO,CAAC;MAC5B,IAAI,UAAU,UACnB,QAAQ,KAAK,YAAY,OAAO,CAAC;MAC5B,IAAI,UAAU,UACnB,QAAQ,KAAK,YAAY,OAAO,CAAC;MAC5B,IAAI,UAAU,SACnB,QAAQ,KAAK,WAAW,OAAO,CAAC;CAIpC,OAAO;AACT;;;AClcA,MAAa,oBAAoB,EAAE,OAAO;CACxC,QAAQ,EAAE,OAAO,CAAC,CAAC,IAAI;CACvB,QAAQ,EAAE,OAAO,CAAC,CAAC,IAAI;CACvB,eAAe,EAAE,OAAO,CAAC,CAAC,IAAI;CAC9B,UAAU,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC;CAC1B,aAAa,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC;CAC7B,cAAc,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC;CAC9B,WAAW,EAAE,OAAO,CAAC,CAAC,OAAO;AAC/B,CAAC;AAGD,SAAS,QAAQ,OAAgB,MAAuB;CACtD,OAAO,iBAAiB,SAAS,UAAU,SAAS,MAAM,SAAS;AACrE;AAEA,IAAa,cAAb,MAAyB;CACM;CAA7B,YAAY,YAA6B,KAAK,QAAQ,GAAG,WAAW,UAAU,GAAG;EAApD,KAAA,YAAA;CAAqD;CAElF,KAAa,QAAwB;EACnC,OAAO,KAAK,KAAK,WAAW,GAAG,WAAW,QAAQ,CAAC,CAAC,OAAO,MAAM,CAAC,CAAC,OAAO,KAAK,EAAE,MAAM;CACzF;CAEA,MAAM,KAAK,QAAqD;EAC9D,IAAI;GACF,MAAM,SAAS,kBAAkB,UAAU,KAAK,MAAM,MAAM,SAAS,KAAK,KAAK,MAAM,GAAG,MAAM,CAAC,CAAC;GAChG,IAAI,CAAC,OAAO,WAAW,OAAO,KAAK,WAAW,QAC5C,MAAM,IAAI,MAAM,2EAA2E;GAE7F,OAAO,OAAO;EAChB,SAAS,OAAO;GACd,IAAI,QAAQ,OAAO,QAAQ,GACzB;GAEF,IAAI,iBAAiB,aACnB,MAAM,IAAI,MAAM,2EAA2E;GAE7F,MAAM;EACR;CACF;CAEA,MAAM,KAAK,aAA4C;EACrD,MAAM,MAAM,KAAK,WAAW;GAAE,WAAW;GAAM,MAAM;EAAM,CAAC;EAC5D,MAAM,MAAM,KAAK,WAAW,GAAK;EACjC,MAAM,SAAS,KAAK,KAAK,YAAY,MAAM;EAC3C,MAAM,YAAY,GAAG,OAAO,GAAG,WAAW,EAAE;EAC5C,IAAI;GACF,MAAM,UAAU,WAAW,KAAK,UAAU,WAAW,GAAG;IAAE,MAAM;IAAO,MAAM;GAAK,CAAC;GACnF,MAAM,OAAO,WAAW,MAAM;EAChC,UAAU;GACR,MAAM,OAAO,SAAS,CAAC,CAAC,OAAM,UAAS;IACrC,IAAI,CAAC,QAAQ,OAAO,QAAQ,GAC1B,MAAM;GAEV,CAAC;EACH;CACF;CAEA,MAAM,MAAM,QAA+B;EACzC,MAAM,OAAO,KAAK,KAAK,MAAM,CAAC,CAAC,CAAC,OAAM,UAAS;GAC7C,IAAI,CAAC,QAAQ,OAAO,QAAQ,GAC1B,MAAM;EAEV,CAAC;CACH;CAGA,MAAM,UAAa,QAAgB,WAAyC;EAC1E,MAAM,MAAM,KAAK,WAAW;GAAE,WAAW;GAAM,MAAM;EAAM,CAAC;EAC5D,MAAM,OAAO,GAAG,KAAK,KAAK,MAAM,EAAE;EAClC,IAAI;GACF,MAAM,UAAU,MAAM,OAAO,QAAQ,GAAG,GAAG;IAAE,MAAM;IAAM,MAAM;GAAM,CAAC;EACxE,SAAS,OAAO;GACd,IAAI,QAAQ,OAAO,QAAQ,GACzB,MAAM,IAAI,MAAM,8EAA8E,KAAK,YAAY;GAEjH,MAAM;EACR;EACA,IAAI;GACF,OAAO,MAAM,UAAU;EACzB,UAAU;GACR,MAAM,OAAO,IAAI;EACnB;CACF;AACF;;;ACtFA,MAAa,oBAAoB;AAEjC,eAAsB,uBAAuB,OAAe,QAAgB,YAAY,KAAS;CAC/F,IAAI;CACJ,IAAI;CACJ,MAAM,OAAO,IAAI,SAAiB,SAAS,WAAW;EACpD,cAAc;EACd,aAAa;CACf,CAAC;CAED,KAAU,YAAY,KAAA,CAAS;CAC/B,IAAI,cAAc;CAClB,MAAM,SAAS,cAAc,SAAS,aAAa;EACjD,SAAS,UAAU,gBAAgB,2BAA2B;EAC9D,SAAS,UAAU,iBAAiB,UAAU;EAC9C,SAAS,UAAU,mBAAmB,aAAa;EACnD,IAAI;EACJ,IAAI;GACF,MAAM,IAAI,IAAI,QAAQ,OAAO,KAAK,WAAW;EAC/C,QAAQ;GACN,SAAS,UAAU,GAAG,CAAC,CAAC,IAAI,uBAAuB;GACnD;EACF;EACA,IAAI,QAAQ,WAAW,SAAS,IAAI,aAAA,4BAAkC,QAAQ,QAAQ,SAAS,IAAI,IAAI,WAAW,CAAC,CAAC,MAAM;GACxH,SAAS,UAAU,GAAG,CAAC,CAAC,IAAI,WAAW;GACvC;EACF;EACA,MAAM,gBAAgB,IAAI,aAAa,IAAI,OAAO,KAAK;EACvD,IACE,OAAO,WAAW,aAAa,MAAM,OAAO,WAAW,KAAK,KAC5D,CAAC,gBAAgB,OAAO,KAAK,aAAa,GAAG,OAAO,KAAK,KAAK,CAAC,GAC/D;GACA,SAAS,UAAU,GAAG,CAAC,CAAC,IAAI,wDAAwD;GACpF;EACF;EACA,IAAI,IAAI,aAAa,IAAI,KAAK,KAAK,IAAI,aAAa,IAAI,KAAK,MAAM,QAAQ;GACzE,SAAS,UAAU,GAAG,CAAC,CAAC,IAAI,+BAA+B;GAC3D,2BAAW,IAAI,MAAM,sCAAsC,CAAC;GAC5D;EACF;EACA,IAAI,IAAI,aAAa,IAAI,OAAO,GAAG;GACjC,SAAS,UAAU,GAAG,CAAC,CAAC,IAAI,8CAA8C;GAC1E,2BAAW,IAAI,MAAM,8DAA8D,CAAC;GACpF;EACF;EACA,MAAM,oBAAoB,IAAI,aAAa,IAAI,MAAM;EACrD,IAAI,CAAC,mBAAmB;GACtB,SAAS,UAAU,GAAG,CAAC,CAAC,IAAI,6BAA6B;GACzD;EACF;EACA,SAAS,IAAI,2EAA2E;EACxF,YAAY,iBAAiB;CAC/B,CAAC;CACD,MAAM,IAAI,SAAe,SAAS,WAAW;EAC3C,OAAO,KAAK,SAAS,MAAM;EAC3B,OAAO,OAAO,GAAG,mBAAmB;GAClC,OAAO,eAAe,SAAS,MAAM;GACrC,QAAQ;EACV,CAAC;CACH,CAAC;CACD,MAAM,UAAU,OAAO,QAAQ;CAC/B,IAAI,CAAC,WAAW,OAAO,YAAY,UAAU;EAC3C,OAAO,MAAM;EACb,MAAM,IAAI,MAAM,yCAAyC;CAC3D;CACA,cAAc,oBAAoB,QAAQ,OAAO;CACjD,MAAM,QAAQ,iBAAiB,2BAAW,IAAI,MAAM,mDAAmD,CAAC,GAAG,SAAS;CACpH,MAAM,eAAe,2BAAW,IAAI,MAAM,kBAAkB,CAAC;CAC7D,QAAQ,KAAK,UAAU,MAAM;CAC7B,QAAQ,KAAK,WAAW,MAAM;CAC9B,OAAO;EACL;EACA;EACA,aAAa;GACX,aAAa,KAAK;GAClB,QAAQ,eAAe,UAAU,MAAM;GACvC,QAAQ,eAAe,WAAW,MAAM;GACxC,OAAO,oBAAoB;GAC3B,OAAO,MAAM;EACf;CACF;AACF;;;AC9EA,MAAM,iBAAiB;AACvB,MAAM,iBAAiB;AACvB,MAAM,iBAAiB,EAAE,OAAO;CAC9B,QAAQ,EAAE,OAAO,CAAC,CAAC,IAAI;CACvB,wBAAwB,EAAE,OAAO,CAAC,CAAC,IAAI;CACvC,gBAAgB,EAAE,OAAO,CAAC,CAAC,IAAI;CAC/B,uBAAuB,EAAE,OAAO,CAAC,CAAC,IAAI;CACtC,kCAAkC,EAAE,MAAM,EAAE,OAAO,CAAC;AACtD,CAAC;AACD,MAAM,eAAe,EAAE,OAAO;CAC5B,cAAc,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC;CAC9B,eAAe,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC;CAC/B,YAAY,EAAE,OAAO,CAAC,CAAC,QAAO,UAAS,MAAM,YAAY,MAAM,QAAQ;CACvE,YAAY,EAAE,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO;AAC3C,CAAC;AACD,MAAM,gBAAgB,EAAE,OAAO;CAC7B,QAAQ,EAAE,OAAO;CACjB,aAAa,EAAE,OAAO;CACtB,YAAY,EAAE,OAAO,CAAC,CAAC,SAAS;CAChC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC;CAC1B,iBAAiB,EAAE,KAAK,CAAC,OAAO,UAAU,CAAC;AAC7C,CAAC;AAOD,IAAM,YAAN,cAAwB,MAAM;CACP;CAArB,YAAY,QAAyB;EACnC,MAAM,uCAAuC,OAAO,+DAA+D;EADhG,KAAA,SAAA;CAErB;AACF;AAEA,SAAS,UAAU,OAAoB;CACrC,MAAM,MAAM,IAAI,IAAI,KAAK;CACzB,MAAM,QAAQ;EAAC;EAAa;EAAa;CAAO,CAAC,CAAC,SAAS,IAAI,QAAQ;CACvE,IAAK,IAAI,aAAa,YAAY,EAAE,IAAI,aAAa,WAAW,UAAW,IAAI,YAAY,IAAI,YAAY,IAAI,MAC7G,MAAM,IAAI,MAAM,kFAAkF;CAEpG,OAAO;AACT;AAEA,SAAgB,cAAc,QAAQ,QAAQ,IAAI,gBAAgB,gBAAwB;CACxF,MAAM,MAAM,UAAU,KAAK;CAC3B,IAAI,IAAI,aAAa,OAAO,IAAI,QAC9B,MAAM,IAAI,MAAM,mFAAmF;CAErG,OAAO,IAAI;AACb;AAEA,SAAgB,iBAAiB,KAAmB;CAElD,MAAM,UAAU,QAAQ,aAAa,WAAW,SAAS,QAAQ,aAAa,UAAU,aAAa;CACrG,MAAM,OAAO,QAAQ,aAAa,UAAU,CAAC,+BAA+B,GAAG,IAAI,CAAC,GAAG;CACvF,MAAM,QAAQ,MAAM,SAAS,MAAM;EAAE,OAAO;EAAU,UAAU;CAAK,CAAC;CACtE,MAAM,GAAG,eAAe,QAAQ,IAAI,8DAA8D,CAAC;CACnG,MAAM,MAAM;AACd;AAEA,IAAa,UAAb,MAAqB;CAEA;CACA;CAFnB,YACE,UAA2B,IAAI,YAAY,GAC3C,UAAyC,OACzC;EAFiB,KAAA,UAAA;EACA,KAAA,UAAA;CAChB;CAEH,MAAc,QAAQ,KAAa,MAAuC;EACxE,UAAU,GAAG;EACb,MAAM,WAAW,MAAM,KAAK,QAAQ,KAAK;GAAE,GAAG;GAAM,UAAU;GAAS,QAAQ,YAAY,QAAQ,IAAM;EAAE,CAAC;EAC5G,IAAI,CAAC,SAAS,IACZ,MAAM,IAAI,UAAU,SAAS,MAAM;EAErC,OAAO;CACT;CAEA,MAAc,YAAY,KAAa,MAAsC;EAC3E,MAAM,WAAW,MAAM,KAAK,QAAQ,KAAK,IAAI;EAC7C,IAAI;GACF,OAAO,MAAM,SAAS,KAAK;EAC7B,QAAQ;GACN,MAAM,IAAI,MAAM,kDAAkD;EACpE;CACF;CAEA,MAAc,SAAS,QAAgB;EACrC,MAAM,WAAW,GAAG,OAAO;EAC3B,MAAM,WAAW,MAAM,KAAK,YAAY,GAAG,OAAO,iDAAiD;EACnG,MAAM,oBAAoB,EACvB,OAAO;GAAE,UAAU,EAAE,QAAQ,QAAQ;GAAG,uBAAuB,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC;EAAE,CAAC,CAAC,CACrG,MAAM,QAAQ;EACjB,MAAM,SAAS,UAAU,kBAAkB,sBAAsB,EAAG;EACpE,IAAI,OAAO,QACT,MAAM,IAAI,MAAM,sCAAsC;EAExD,MAAM,eAAe,GAAG,OAAO,OAAO,yCAAyC,OAAO,aAAa,MAAM,KAAK,OAAO;EACrH,MAAM,WAAW,eAAe,MAAM,MAAM,KAAK,YAAY,YAAY,CAAC;EAC1E,IACE,SAAS,WAAW,kBAAkB,sBAAsB,MAC5D,CAAC,SAAS,iCAAiC,SAAS,MAAM,GAE1D,MAAM,IAAI,MAAM,6EAA6E;EAE/F,KAAK,MAAM,YAAY;GAAC,SAAS;GAAwB,SAAS;GAAgB,SAAS;EAAqB,GAC9G,IAAI,UAAU,QAAQ,CAAC,CAAC,WAAW,OAAO,QACxC,MAAM,IAAI,MAAM,qEAAqE;EAGzF,OAAO;CACT;CAEA,MAAM,MAAM,UAAwB,CAAC,GAAG,cAAqC,kBAAuC;EAClH,MAAM,SAAS,cAAc,QAAQ,GAAG;EACxC,OAAO,KAAK,QAAQ,UAAU,QAAQ,YAAY;GAChD,IAAI,MAAM,KAAK,QAAQ,KAAK,MAAM,GAChC,MAAM,IAAI,MAAM,6FAA6F;GAE/G,MAAM,WAAW,MAAM,KAAK,SAAS,MAAM;GAC3C,MAAM,WAAW,YAAY,EAAE,CAAC,CAAC,SAAS,WAAW;GACrD,MAAM,QAAQ,YAAY,EAAE,CAAC,CAAC,SAAS,WAAW;GAClD,MAAM,WAAW,MAAM,uBAAuB,OAAO,SAAS,MAAM;GACpE,IAAI;IACF,MAAM,eAAe,EAAE,OAAO,EAAE,WAAW,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,MAC9D,MAAM,KAAK,YAAY,SAAS,uBAAuB;KACrD,QAAQ;KACR,SAAS,EAAE,gBAAgB,mBAAmB;KAC9C,MAAM,KAAK,UAAU;MACnB,aAAa;MACb,YAAY;MACZ,eAAe,CAAC,SAAS,WAAW;MACpC,aAAa,CAAC,sBAAsB,eAAe;MACnD,gBAAgB,CAAC,MAAM;MACvB,4BAA4B;MAC5B,OAAO;KACT,CAAC;IACH,CAAC,CACH;IACA,MAAM,mBAAmB,IAAI,IAAI,SAAS,sBAAsB;IAChE,iBAAiB,SAAS,IAAI,gBAAgB;KAC5C,eAAe;KACf,WAAW,aAAa;KACxB,cAAc,SAAS;KACvB,OAAO;KACP;KACA,gBAAgB,WAAW,QAAQ,CAAC,CAAC,OAAO,QAAQ,CAAC,CAAC,OAAO,WAAW;KACxE,uBAAuB;KACvB,QAAQ;IACV,CAAC,CAAC,CAAC,SAAS;IACZ,QAAQ,IAAI,gCAAgC,iBAAiB,MAAM;IACnE,IAAI,QAAQ,YAAY,OACtB,YAAY,iBAAiB,IAAI;IAEnC,MAAM,OAAO,MAAM,SAAS;IAC5B,MAAM,SAAS,MAAM,KAAK,SAAS,SAAS,gBAAgB;KAC1D,YAAY;KACZ,WAAW,aAAa;KACxB;KACA,cAAc,SAAS;KACvB,eAAe;IACjB,CAAC;IACD,MAAM,cAA8B;KAClC;KACA,QAAQ,SAAS;KACjB,eAAe,SAAS;KACxB,UAAU,aAAa;KACvB,aAAa,OAAO;KACpB,cAAc,OAAO;KACrB,WAAW,KAAK,IAAI,IAAI,OAAO,aAAa;IAC9C;IAEA,MAAM,KAAK,QAAQ,KAAK,WAAW;IACnC,OAAO,MAAM,KAAK,QAAQ,WAAW;GACvC,UAAU;IACR,SAAS,MAAM;GACjB;EACF,CAAC;CACH;CAEA,MAAc,SAAS,UAAkB,MAA8B;EACrE,OAAO,aAAa,MAClB,MAAM,KAAK,YAAY,UAAU;GAC/B,QAAQ;GACR,SAAS,EAAE,gBAAgB,oCAAoC;GAC/D,MAAM,IAAI,gBAAgB,IAAI;EAChC,CAAC,CACH;CACF;CAEA,MAAc,YAAY,QAAyC;EACjE,MAAM,QAAQ,MAAM,KAAK,QAAQ,KAAK,MAAM;EAC5C,IAAI,CAAC,OACH,MAAM,IAAI,MAAM,oCAAoC;EAEtD,IAAI,UAAU,MAAM,aAAa,CAAC,CAAC,WAAW,UAAU,MAAM,MAAM,CAAC,CAAC,QACpE,MAAM,IAAI,MAAM,kGAAkG;EAEpH,IAAI,MAAM,YAAY,KAAK,IAAI,IAAI,KACjC,OAAO;EAET,MAAM,SAAS,MAAM,KAAK,SAAS,MAAM,eAAe;GACtD,YAAY;GACZ,WAAW,MAAM;GACjB,eAAe,MAAM;EACvB,CAAC;EACD,MAAM,YAAY;GAChB,GAAG;GACH,aAAa,OAAO;GACpB,cAAc,OAAO;GACrB,WAAW,KAAK,IAAI,IAAI,OAAO,aAAa;EAC9C;EACA,MAAM,KAAK,QAAQ,KAAK,SAAS;EACjC,OAAO;CACT;CAEA,MAAc,QAAQ,aAAkD;EACtE,OAAO,cAAc,MACnB,MAAM,KAAK,YAAY,GAAG,YAAY,OAAO,sBAAsB,EACjE,SAAS,EAAE,eAAe,UAAU,YAAY,cAAc,EAChE,CAAC,CACH;CACF;CAEA,MAAM,OAAO,KAAmC;EAC9C,MAAM,SAAS,cAAc,GAAG;EAChC,OAAO,KAAK,QAAQ,UAAU,QAAQ,YAAY,KAAK,QAAQ,MAAM,KAAK,YAAY,MAAM,CAAC,CAAC;CAChG;;CAGA,MAAM,eAAe,KAA+B;EAClD,MAAM,SAAS,cAAc,GAAG;EAChC,OAAO,KAAK,QAAQ,UAAU,QAAQ,YAAY;GAChD,MAAM,cAAc,MAAM,KAAK,YAAY,MAAM;GACjD,MAAM,KAAK,QAAQ,WAAW;GAC9B,OAAO,YAAY;EACrB,CAAC;CACH;CAEA,MAAM,OAAO,UAA6C,CAAC,GAAkB;EAC3E,MAAM,SAAS,cAAc,QAAQ,GAAG;EACxC,MAAM,KAAK,QAAQ,UAAU,QAAQ,YAAY;GAC/C,IAAI,QAAQ,OAAO;IACjB,MAAM,KAAK,QAAQ,MAAM,MAAM;IAC/B;GACF;GACA,IAAI,CAAE,MAAM,KAAK,QAAQ,KAAK,MAAM,GAClC;GAEF,IAAI;IACF,MAAM,cAAc,MAAM,KAAK,YAAY,MAAM;IACjD,MAAM,KAAK,QAAQ,GAAG,OAAO,sBAAsB;KACjD,QAAQ;KACR,SAAS,EAAE,eAAe,UAAU,YAAY,cAAc;IAChE,CAAC;GACH,QAAQ;IACN,MAAM,IAAI,MACR,6GACF;GACF;GACA,MAAM,KAAK,QAAQ,MAAM,MAAM;EACjC,CAAC;CACH;AACF"}
|
package/dist/cli.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
export {}
|
package/dist/cli.js
CHANGED
|
@@ -1,27 +1,86 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
} from "
|
|
5
|
-
|
|
6
|
-
// src/cli.ts
|
|
2
|
+
import { r as runInitCommand, t as CliAuth } from "./auth-C7pTl5XB.js";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
import { BulkgridClient, sourceInputSchemas } from "@bulkgrid/sdk";
|
|
7
5
|
import { Command } from "commander";
|
|
8
|
-
|
|
6
|
+
//#region src/sources.ts
|
|
7
|
+
const uuid = z.uuid();
|
|
8
|
+
function createSourceClient(options) {
|
|
9
|
+
const apiKey = process.env.BULKGRID_API_KEY;
|
|
10
|
+
if (!apiKey) throw new Error("Source commands require BULKGRID_API_KEY with explicit source/collection scopes. CLI OAuth login remains search-only.");
|
|
11
|
+
const baseUrl = new URL(options.url ?? process.env.BULKGRID_URL ?? "https://bulkgrid.com");
|
|
12
|
+
if (baseUrl.username || baseUrl.password || baseUrl.search || baseUrl.hash || baseUrl.pathname !== "/") throw new Error("Use a Bulkgrid origin URL without credentials, a path, query, or fragment.");
|
|
13
|
+
if (baseUrl.protocol !== "https:" && !(baseUrl.protocol === "http:" && [
|
|
14
|
+
"localhost",
|
|
15
|
+
"127.0.0.1",
|
|
16
|
+
"[::1]"
|
|
17
|
+
].includes(baseUrl.hostname))) throw new Error("Remote Bulkgrid deployments require HTTPS.");
|
|
18
|
+
return new BulkgridClient({
|
|
19
|
+
apiKey,
|
|
20
|
+
baseUrl: baseUrl.origin
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
function registerSourceCommands(program, clientFactory = createSourceClient) {
|
|
24
|
+
const sources = program.command("sources").description("Inspect and manage sources with a scoped API key; outputs JSON");
|
|
25
|
+
const command = (name, description) => sources.command(name).description(description).option("--url <url>", "Bulkgrid origin; defaults to BULKGRID_URL or https://bulkgrid.com");
|
|
26
|
+
const print = (result) => console.log(JSON.stringify(result, null, 2));
|
|
27
|
+
command("find <query>", "Find existing sources before adding one").action(async (query, options) => print(await clientFactory(options).sources.search(query)));
|
|
28
|
+
command("analyze <sourceUrl>", "Start deeper analysis; may create a crawl run and consume resources").action(async (url, options) => print(await clientFactory(options).sources.analyze({ url })));
|
|
29
|
+
command("analysis-status <analysisId>", "Read analysis progress and warnings").action(async (analysisId, options) => print(await clientFactory(options).sources.getAnalysis(uuid.parse(analysisId))));
|
|
30
|
+
command("add", "Create or subscribe to a source; may initiate ongoing ingestion").requiredOption("--input <json>", "Source configuration JSON including explicit visibility, boundaries and refresh interval").action(async (options) => {
|
|
31
|
+
const input = sourceInputSchemas.create.safeExtend({ visibility: z.enum(["public", "private"]) }).parse(JSON.parse(options.input ?? "{}"));
|
|
32
|
+
print(await clientFactory(options).sources.create(input));
|
|
33
|
+
});
|
|
34
|
+
command("status <sourceId>", "Read crawl status, errors, size and indexed item counts").action(async (sourceId, options) => print(await clientFactory(options).sources.status(uuid.parse(sourceId))));
|
|
35
|
+
command("recrawl <sourceId>", "Start a manual refresh using saved configuration; may consume credits").action(async (sourceId, options) => print(await clientFactory(options).sources.recrawl(uuid.parse(sourceId))));
|
|
36
|
+
command("collections", "List collections available for source management").action(async (options) => print(await clientFactory(options).collections.list()));
|
|
37
|
+
command("rules <collectionId>", "Inspect collection rules before changing membership").action(async (collectionId, options) => print(await clientFactory(options).collections.rules(uuid.parse(collectionId))));
|
|
38
|
+
command("include <sourceId> <collectionId>", "Include the entire source in a collection, broadening its retrieval coverage").action(async (sourceId, collectionId, options) => print(await clientFactory(options).collections.addSource({
|
|
39
|
+
sourceId: uuid.parse(sourceId),
|
|
40
|
+
collectionId: uuid.parse(collectionId)
|
|
41
|
+
})));
|
|
42
|
+
}
|
|
43
|
+
//#endregion
|
|
44
|
+
//#region src/cli.ts
|
|
45
|
+
const program = new Command();
|
|
9
46
|
program.name("bulkgrid").description("Bulkgrid developer tooling").version("0.1.0");
|
|
47
|
+
const auth = new CliAuth();
|
|
48
|
+
program.command("login").description("Sign in to Bulkgrid in your browser").option("--url <url>", "Bulkgrid base URL; defaults to BULKGRID_URL or https://bulkgrid.com").option("--no-browser", "print the login URL without opening a browser").action(async (options) => {
|
|
49
|
+
const session = await auth.login(options);
|
|
50
|
+
console.log(`Logged in to workspace ${session.workspaceId}. Manage access in Settings → Connected Apps.`);
|
|
51
|
+
});
|
|
52
|
+
program.command("status").description("Verify the saved CLI connection and show its access").option("--url <url>", "Bulkgrid base URL; defaults to BULKGRID_URL or https://bulkgrid.com").action(async (options) => {
|
|
53
|
+
const session = await auth.status(options.url);
|
|
54
|
+
console.log(`Connected as ${session.userId} to workspace ${session.workspaceId}.`);
|
|
55
|
+
console.log(`Permissions: ${session.scopes.join(", ")}; collections: ${session.collectionScope}.`);
|
|
56
|
+
});
|
|
57
|
+
program.command("logout").description("Revoke this CLI connection and remove its saved tokens").option("--url <url>", "Bulkgrid base URL; defaults to BULKGRID_URL or https://bulkgrid.com").option("--local", "only remove local tokens; revoke access separately in Connected Apps").action(async (options) => {
|
|
58
|
+
await auth.logout(options);
|
|
59
|
+
console.log(options.local ? "Local credentials removed. Server access was not revoked." : "Logged out.");
|
|
60
|
+
});
|
|
10
61
|
program.command("init").description("Configure the Bulkgrid MCP server").option("--all", "configure all supported agents").option("--cursor", "configure Cursor").option("--vscode", "configure VS Code").option("--claude", "configure Claude Code").option("--codex", "configure Codex").option("--mcp-url <url>", "Bulkgrid MCP server URL").option("--api-key <key>", "Bulkgrid API key; defaults to BULKGRID_API_KEY").option("--global", "write global user configuration where supported").option("--project", "write project configuration where supported").option("--yes", "do not prompt for missing values").option("--write-api-key", "write the API key into generated JSON config files").option("--install-global", "install @bulkgrid/cli globally before configuring agents").option("--auth <mode>", "authentication mode: browser, manual, or skip").action(async (options) => {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
62
|
+
try {
|
|
63
|
+
const results = await runInitCommand(options);
|
|
64
|
+
if (results.length === 0) {
|
|
65
|
+
console.log("No MCP clients configured.");
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
for (const result of results) {
|
|
69
|
+
const marker = result.status === "configured" ? "configured" : "skipped";
|
|
70
|
+
console.log(`${result.agent}: ${marker} - ${result.message}`);
|
|
71
|
+
}
|
|
72
|
+
} catch (error) {
|
|
73
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
74
|
+
console.error(`bulkgrid init failed: ${message}`);
|
|
75
|
+
process.exitCode = 1;
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
registerSourceCommands(program);
|
|
79
|
+
program.parseAsync().catch((error) => {
|
|
80
|
+
console.error(`bulkgrid: ${error instanceof Error ? error.message : "Command failed"}`);
|
|
81
|
+
process.exitCode = 1;
|
|
26
82
|
});
|
|
27
|
-
|
|
83
|
+
//#endregion
|
|
84
|
+
export {};
|
|
85
|
+
|
|
86
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","names":[],"sources":["../src/sources.ts","../src/cli.ts"],"sourcesContent":["import { Command } from 'commander';\nimport { BulkgridClient, sourceInputSchemas } from '@bulkgrid/sdk';\nimport { z } from 'zod';\n\ninterface SourceCommandOptions {\n url?: string;\n input?: string;\n}\ntype ClientFactory = (options: SourceCommandOptions) => BulkgridClient;\nconst uuid = z.uuid();\n\nexport function createSourceClient(options: SourceCommandOptions): BulkgridClient {\n const apiKey = process.env.BULKGRID_API_KEY;\n if (!apiKey) {\n throw new Error(\n 'Source commands require BULKGRID_API_KEY with explicit source/collection scopes. CLI OAuth login remains search-only.',\n );\n }\n const baseUrl = new URL(options.url ?? process.env.BULKGRID_URL ?? 'https://bulkgrid.com');\n if (baseUrl.username || baseUrl.password || baseUrl.search || baseUrl.hash || baseUrl.pathname !== '/') {\n throw new Error('Use a Bulkgrid origin URL without credentials, a path, query, or fragment.');\n }\n if (\n baseUrl.protocol !== 'https:' &&\n !(baseUrl.protocol === 'http:' && ['localhost', '127.0.0.1', '[::1]'].includes(baseUrl.hostname))\n ) {\n throw new Error('Remote Bulkgrid deployments require HTTPS.');\n }\n return new BulkgridClient({ apiKey, baseUrl: baseUrl.origin });\n}\n\nexport function registerSourceCommands(program: Command, clientFactory: ClientFactory = createSourceClient): void {\n const sources = program.command('sources').description('Inspect and manage sources with a scoped API key; outputs JSON');\n const command = (name: string, description: string) =>\n sources\n .command(name)\n .description(description)\n .option('--url <url>', 'Bulkgrid origin; defaults to BULKGRID_URL or https://bulkgrid.com');\n const print = (result: unknown) => console.log(JSON.stringify(result, null, 2));\n command('find <query>', 'Find existing sources before adding one').action(\n async (query: string, options: SourceCommandOptions) => print(await clientFactory(options).sources.search(query)),\n );\n command('analyze <sourceUrl>', 'Start deeper analysis; may create a crawl run and consume resources').action(\n async (url: string, options: SourceCommandOptions) => print(await clientFactory(options).sources.analyze({ url })),\n );\n command('analysis-status <analysisId>', 'Read analysis progress and warnings').action(\n async (analysisId: string, options: SourceCommandOptions) =>\n print(await clientFactory(options).sources.getAnalysis(uuid.parse(analysisId))),\n );\n command('add', 'Create or subscribe to a source; may initiate ongoing ingestion')\n .requiredOption('--input <json>', 'Source configuration JSON including explicit visibility, boundaries and refresh interval')\n .action(async (options: SourceCommandOptions) => {\n const input = sourceInputSchemas.create\n .safeExtend({ visibility: z.enum(['public', 'private']) })\n .parse(JSON.parse(options.input ?? '{}'));\n print(await clientFactory(options).sources.create(input));\n });\n command('status <sourceId>', 'Read crawl status, errors, size and indexed item counts').action(\n async (sourceId: string, options: SourceCommandOptions) =>\n print(await clientFactory(options).sources.status(uuid.parse(sourceId))),\n );\n command('recrawl <sourceId>', 'Start a manual refresh using saved configuration; may consume credits').action(\n async (sourceId: string, options: SourceCommandOptions) =>\n print(await clientFactory(options).sources.recrawl(uuid.parse(sourceId))),\n );\n command('collections', 'List collections available for source management').action(async (options: SourceCommandOptions) =>\n print(await clientFactory(options).collections.list()),\n );\n command('rules <collectionId>', 'Inspect collection rules before changing membership').action(\n async (collectionId: string, options: SourceCommandOptions) =>\n print(await clientFactory(options).collections.rules(uuid.parse(collectionId))),\n );\n command(\n 'include <sourceId> <collectionId>',\n 'Include the entire source in a collection, broadening its retrieval coverage',\n ).action(async (sourceId: string, collectionId: string, options: SourceCommandOptions) =>\n print(\n await clientFactory(options).collections.addSource({\n sourceId: uuid.parse(sourceId),\n collectionId: uuid.parse(collectionId),\n }),\n ),\n );\n}\n","#!/usr/bin/env node\nimport { registerSourceCommands } from './sources.js';\nimport { Command } from 'commander';\n\nimport { CliAuth } from './auth.js';\n\nimport { runInitCommand } from './init.js';\n\nconst program = new Command();\n\nprogram.name('bulkgrid').description('Bulkgrid developer tooling').version('0.1.0');\n\nconst auth = new CliAuth();\n\nprogram\n .command('login')\n .description('Sign in to Bulkgrid in your browser')\n .option('--url <url>', 'Bulkgrid base URL; defaults to BULKGRID_URL or https://bulkgrid.com')\n .option('--no-browser', 'print the login URL without opening a browser')\n .action(async options => {\n const session = await auth.login(options);\n console.log(`Logged in to workspace ${session.workspaceId}. Manage access in Settings → Connected Apps.`);\n });\n\nprogram\n .command('status')\n .description('Verify the saved CLI connection and show its access')\n .option('--url <url>', 'Bulkgrid base URL; defaults to BULKGRID_URL or https://bulkgrid.com')\n .action(async options => {\n const session = await auth.status(options.url);\n console.log(`Connected as ${session.userId} to workspace ${session.workspaceId}.`);\n console.log(`Permissions: ${session.scopes.join(', ')}; collections: ${session.collectionScope}.`);\n });\n\nprogram\n .command('logout')\n .description('Revoke this CLI connection and remove its saved tokens')\n .option('--url <url>', 'Bulkgrid base URL; defaults to BULKGRID_URL or https://bulkgrid.com')\n .option('--local', 'only remove local tokens; revoke access separately in Connected Apps')\n .action(async options => {\n await auth.logout(options);\n console.log(options.local ? 'Local credentials removed. Server access was not revoked.' : 'Logged out.');\n });\n\nprogram\n .command('init')\n .description('Configure the Bulkgrid MCP server')\n .option('--all', 'configure all supported agents')\n .option('--cursor', 'configure Cursor')\n .option('--vscode', 'configure VS Code')\n .option('--claude', 'configure Claude Code')\n .option('--codex', 'configure Codex')\n .option('--mcp-url <url>', 'Bulkgrid MCP server URL')\n .option('--api-key <key>', 'Bulkgrid API key; defaults to BULKGRID_API_KEY')\n .option('--global', 'write global user configuration where supported')\n .option('--project', 'write project configuration where supported')\n .option('--yes', 'do not prompt for missing values')\n .option('--write-api-key', 'write the API key into generated JSON config files')\n .option('--install-global', 'install @bulkgrid/cli globally before configuring agents')\n .option('--auth <mode>', 'authentication mode: browser, manual, or skip')\n .action(async options => {\n try {\n const results = await runInitCommand(options);\n if (results.length === 0) {\n console.log('No MCP clients configured.');\n return;\n }\n for (const result of results) {\n const marker = result.status === 'configured' ? 'configured' : 'skipped';\n console.log(`${result.agent}: ${marker} - ${result.message}`);\n }\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Unknown error';\n console.error(`bulkgrid init failed: ${message}`);\n process.exitCode = 1;\n }\n });\n\nregisterSourceCommands(program);\n\nprogram.parseAsync().catch(error => {\n console.error(`bulkgrid: ${error instanceof Error ? error.message : 'Command failed'}`);\n process.exitCode = 1;\n});\n"],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,27 +1,88 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
//#region src/init.d.ts
|
|
1
3
|
type AgentName = 'cursor' | 'vscode' | 'claude' | 'codex';
|
|
2
4
|
type AuthMode = 'browser' | 'manual' | 'skip';
|
|
3
5
|
interface InitFlags {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
readonly all?: boolean;
|
|
7
|
+
readonly cursor?: boolean;
|
|
8
|
+
readonly vscode?: boolean;
|
|
9
|
+
readonly claude?: boolean;
|
|
10
|
+
readonly codex?: boolean;
|
|
9
11
|
}
|
|
10
12
|
interface InitCommandOptions extends InitFlags {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
13
|
+
readonly mcpUrl?: string;
|
|
14
|
+
readonly apiKey?: string;
|
|
15
|
+
readonly global?: boolean;
|
|
16
|
+
readonly project?: boolean;
|
|
17
|
+
readonly yes?: boolean;
|
|
18
|
+
readonly writeApiKey?: boolean;
|
|
19
|
+
readonly installGlobal?: boolean;
|
|
20
|
+
readonly auth?: AuthMode;
|
|
19
21
|
}
|
|
20
22
|
interface SetupResult {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
23
|
+
readonly agent: AgentName;
|
|
24
|
+
readonly status: 'configured' | 'skipped';
|
|
25
|
+
readonly message: string;
|
|
24
26
|
}
|
|
25
27
|
declare function runInitCommand(options: InitCommandOptions): Promise<readonly SetupResult[]>;
|
|
26
|
-
|
|
27
|
-
|
|
28
|
+
//#endregion
|
|
29
|
+
//#region src/authStorage.d.ts
|
|
30
|
+
declare const credentialsSchema: z.ZodObject<{
|
|
31
|
+
origin: z.ZodString;
|
|
32
|
+
issuer: z.ZodString;
|
|
33
|
+
tokenEndpoint: z.ZodString;
|
|
34
|
+
clientId: z.ZodString;
|
|
35
|
+
accessToken: z.ZodString;
|
|
36
|
+
refreshToken: z.ZodString;
|
|
37
|
+
expiresAt: z.ZodNumber;
|
|
38
|
+
}, z.core.$strip>;
|
|
39
|
+
type CliCredentials = z.infer<typeof credentialsSchema>;
|
|
40
|
+
declare class AuthStorage {
|
|
41
|
+
private readonly directory;
|
|
42
|
+
constructor(directory?: string);
|
|
43
|
+
private path;
|
|
44
|
+
read(origin: string): Promise<CliCredentials | undefined>;
|
|
45
|
+
save(credentials: CliCredentials): Promise<void>;
|
|
46
|
+
clear(origin: string): Promise<void>;
|
|
47
|
+
exclusive<T>(origin: string, operation: () => Promise<T>): Promise<T>;
|
|
48
|
+
}
|
|
49
|
+
//#endregion
|
|
50
|
+
//#region src/auth.d.ts
|
|
51
|
+
declare const sessionSchema: z.ZodObject<{
|
|
52
|
+
userId: z.ZodString;
|
|
53
|
+
workspaceId: z.ZodString;
|
|
54
|
+
clientName: z.ZodNullable<z.ZodString>;
|
|
55
|
+
scopes: z.ZodArray<z.ZodString>;
|
|
56
|
+
collectionScope: z.ZodEnum<{
|
|
57
|
+
all: "all";
|
|
58
|
+
selected: "selected";
|
|
59
|
+
}>;
|
|
60
|
+
}, z.core.$strip>;
|
|
61
|
+
type CliSession = z.infer<typeof sessionSchema>;
|
|
62
|
+
interface LoginOptions {
|
|
63
|
+
readonly url?: string;
|
|
64
|
+
readonly browser?: boolean;
|
|
65
|
+
}
|
|
66
|
+
declare function resolveOrigin(value?: string): string;
|
|
67
|
+
declare class CliAuth {
|
|
68
|
+
private readonly storage;
|
|
69
|
+
private readonly fetcher;
|
|
70
|
+
constructor(storage?: AuthStorage, fetcher?: typeof fetch);
|
|
71
|
+
private request;
|
|
72
|
+
private requestJson;
|
|
73
|
+
private discover;
|
|
74
|
+
login(options?: LoginOptions, openBrowser?: (url: string) => void): Promise<CliSession>;
|
|
75
|
+
private exchange;
|
|
76
|
+
private credentials;
|
|
77
|
+
private session;
|
|
78
|
+
status(url?: string): Promise<CliSession>;
|
|
79
|
+
/** For CLI API consumers; tokens are never copied into agent/project configuration. */
|
|
80
|
+
getAccessToken(url?: string): Promise<string>;
|
|
81
|
+
logout(options?: {
|
|
82
|
+
url?: string;
|
|
83
|
+
local?: boolean;
|
|
84
|
+
}): Promise<void>;
|
|
85
|
+
}
|
|
86
|
+
//#endregion
|
|
87
|
+
export { CliAuth, type CliSession, type InitCommandOptions, type LoginOptions, resolveOrigin, runInitCommand };
|
|
88
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/init.ts","../src/authStorage.ts","../src/auth.ts"],"mappings":";;KAWK;KACA;UASK;WACC;WACA;WACA;WACA;WACA;;UAGM,2BAA2B;WACjC;WACA;WACA;WACA;WACA;WACA;WACA;WACA,OAAO;;UAeR;WACC,OAAO;WACP;WACA;;iBA6XW,eAAe,SAAS,qBAAqB,iBAAiB;;;cC9avE,mBAAiB,EAAA;;;;;;;;GAQ5B,EAAA,KAAA;KACU,iBAAiB,EAAE,aAAa;cAM/B;mBACkB;EAAA,YAAA;UAErB;EAIF,KAAK,iBAAiB,QAAQ;EAkB9B,KAAK,aAAa,iBAAiB;EAiBnC,MAAM,iBAAiB;EASvB,UAAU,GAAG,gBAAgB,iBAAiB,QAAQ,KAAK,QAAQ;;;;cCnDrE,eAAa,EAAA;;;;;;;;;GAMjB,EAAA,KAAA;KACU,aAAa,EAAE,aAAa;UACvB;WACN;WACA;;iBAkBK,cAAc;cAiBjB;mBAEQ;mBACA;EADA,YAAA,UAAO,aACP,iBAAgB;UAGrB;UASA;UASA;EA0BR,MAAM,UAAS,cAAmB,eAAc,uBAA0C,QAAQ;UAmE1F;UAUA;UA0BA;EAQR,OAAO,eAAe,QAAQ;;EAM9B,eAAe,eAAe;EAS9B,OAAO;IAAW;IAAc;MAAyB"}
|
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bulkgrid/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"dist"
|
|
17
17
|
],
|
|
18
18
|
"scripts": {
|
|
19
|
-
"build": "
|
|
19
|
+
"build": "tsdown",
|
|
20
20
|
"lint": "eslint .",
|
|
21
21
|
"check-types": "tsc --noEmit",
|
|
22
22
|
"test": "vitest run",
|
|
@@ -26,13 +26,14 @@
|
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
28
|
"@inquirer/prompts": "7.10.1",
|
|
29
|
-
"commander": "14.0.3"
|
|
29
|
+
"commander": "14.0.3",
|
|
30
|
+
"zod": "4.4.3",
|
|
31
|
+
"@bulkgrid/sdk": "^0.2.0"
|
|
30
32
|
},
|
|
31
33
|
"devDependencies": {
|
|
32
34
|
"@repo/eslint-config": "*",
|
|
33
35
|
"@repo/typescript-config": "*",
|
|
34
|
-
"
|
|
35
|
-
"vitest": "4.1.2"
|
|
36
|
+
"vitest": "4.1.10"
|
|
36
37
|
},
|
|
37
38
|
"publishConfig": {
|
|
38
39
|
"access": "public"
|