@glassanalytics/cli
Advanced tools
+4
-4
@@ -299,5 +299,5 @@ #!/usr/bin/env node | ||
| return { | ||
| pkg: "@glass/node", | ||
| pkg: "@glassanalytics/node", | ||
| file: "glass.ts", | ||
| code: `import { GlassNode } from '@glass/node'; | ||
| code: `import { GlassNode } from '@glassanalytics/node'; | ||
@@ -309,5 +309,5 @@ export const glass = new GlassNode({ projectKey: '${project.ingest_key}', ingestHost: '${project.ingest_host}' }); | ||
| return { | ||
| pkg: "@glass/browser", | ||
| pkg: "@glassanalytics/browser", | ||
| file: "glass.ts", | ||
| code: `import glass from '@glass/browser'; | ||
| code: `import glass from '@glassanalytics/browser'; | ||
@@ -314,0 +314,0 @@ glass.init({ projectKey: '${project.ingest_key}', ingestHost: '${project.ingest_host}' }); |
+1
-1
@@ -1,1 +0,1 @@ | ||
| {"version":3,"sources":["../src/cli.ts","../src/commands.ts","../src/output.ts","../src/api.ts","../src/config.ts"],"sourcesContent":["import { parseArgs } from 'node:util';\nimport * as cmd from './commands.js';\nimport { ExitCode, fail, setFormat, setJsonMode } from './output.js';\n\n/**\n * `glass` — the agent-friendly terminal surface (`CLI.md`). Setup in one command\n * (`glass init`, no signup), then the same typed query primitives the dashboard\n * uses. `--json` + stable exit codes make it scriptable by humans and agents.\n */\n\nconst HELP = `glass <command> [options]\n\nSetup\n init [--force] Provision a project with no signup (writes glass.json)\n install [--framework F] [--no-install] Install + wire the SDK\n status Show whether events are being received\n doctor Diagnose setup problems\n claim Get the claim URL to keep your data\n login [--token T] Store a Clerk session for human-scoped access\n logout Clear the stored session\n whoami Show the current principal (GET /v1/me)\n link --project ID Point glass.json at another project you can access\n\nQuery (all accept --last 7d, --json, --confirm, --max-scan <MB>)\n trend --event E [--bucket day] [--breakdown B] [--aggregate count|unique_users|sum]\n funnel --steps a,b,c | --id <def> [--window 1d]\n retention --id <def> --return E [--periods 8]\n segment --group-by a,b [--event E]\n errors\n replays [--limit 50]\n query --query '<json>' | -f <file> | (piped stdin)\n\nManage\n define --file spec.json | --kind funnel --steps a,b | --list\n tokens list | create [--budget-r2sql 1GB/day] | revoke <id>\n link <project-id>\n\nGlobal: --json --csv --ndjson --api-host --ingest-host\n --max-scan <500MB|1GB> --yes/--no-input (auth: --token | GLASS_TOKEN)\nEnv: GLASS_TOKEN GLASS_PROJECT GLASS_INGEST_KEY GLASS_API_HOST`;\n\nasync function main(): Promise<void> {\n const argv = process.argv.slice(2);\n const command = argv[0];\n const sub = argv[1] && !argv[1].startsWith('-') ? argv[1] : undefined;\n\n const { values, positionals } = parseArgs({\n args: argv.slice(1),\n allowPositionals: true,\n options: {\n json: { type: 'boolean' },\n csv: { type: 'boolean' },\n ndjson: { type: 'boolean' },\n confirm: { type: 'boolean' },\n reissue: { type: 'boolean' },\n force: { type: 'boolean' },\n 'no-install': { type: 'boolean' },\n yes: { type: 'boolean' },\n 'no-input': { type: 'boolean' },\n list: { type: 'boolean' },\n 'max-scan': { type: 'string' },\n last: { type: 'string' },\n event: { type: 'string' },\n bucket: { type: 'string' },\n breakdown: { type: 'string' },\n aggregate: { type: 'string' },\n steps: { type: 'string' },\n window: { type: 'string' },\n scope: { type: 'string' },\n kind: { type: 'string' },\n id: { type: 'string' },\n return: { type: 'string' },\n periods: { type: 'string' },\n 'group-by': { type: 'string' },\n group: { type: 'string' },\n status: { type: 'string' },\n limit: { type: 'string' },\n user: { type: 'string' },\n query: { type: 'string' },\n file: { type: 'string', short: 'f' },\n name: { type: 'string' },\n role: { type: 'string' },\n framework: { type: 'string' },\n project: { type: 'string' },\n 'budget-r2sql': { type: 'string' },\n token: { type: 'string' },\n 'api-host': { type: 'string' },\n 'ingest-host': { type: 'string' },\n },\n });\n\n const flags = values as Record<string, string | boolean>;\n if (flags.json) setJsonMode(true);\n else if (flags.ndjson) setFormat('ndjson');\n else if (flags.csv) setFormat('csv');\n\n switch (command) {\n case 'init':\n return void (await cmd.init(flags));\n case 'install':\n return void cmd.install(flags);\n case 'status':\n return void (await cmd.status(flags));\n case 'doctor':\n return void (await cmd.doctor(flags));\n case 'claim':\n return void (await cmd.claim(flags));\n case 'login':\n return void (await cmd.login(flags));\n case 'logout':\n return void cmd.logout(flags);\n case 'whoami':\n return void (await cmd.whoami(flags));\n case 'link':\n return void (await cmd.link(flags, positionals));\n case 'trend':\n return void (await cmd.trend(flags));\n case 'funnel':\n return void (await cmd.funnel(flags));\n case 'retention':\n return void (await cmd.retention(flags));\n case 'segment':\n return void (await cmd.segment(flags));\n case 'errors':\n return void (await cmd.errors(flags));\n case 'replays':\n return void (await cmd.replays(flags));\n case 'query':\n return void (await cmd.query(flags));\n case 'define':\n return void (await cmd.define(flags));\n case 'tokens':\n // positionals[0] is the sub-action; pass the remainder (e.g. token id).\n return void (await cmd.tokens(sub ?? 'list', flags, positionals.slice(1)));\n case 'help':\n case undefined:\n case '--help':\n case '-h':\n process.stdout.write(`${HELP}\\n`);\n process.exit(ExitCode.OK);\n break;\n default:\n fail(ExitCode.USAGE, `unknown command: ${command}\\n\\n${HELP}`);\n }\n}\n\nmain().catch((e) => fail(ExitCode.ERROR, String(e?.message ?? e)));\n","import { spawnSync } from 'node:child_process';\nimport { existsSync, readFileSync, writeFileSync } from 'node:fs';\nimport { dirname, relative } from 'node:path';\nimport type { GlassQuery } from '@glassanalytics/core';\nimport { Api } from './api.js';\nimport { readCredentials, readProject, tokenFor, writeCredentials, writeProject } from './config.js';\nimport { ExitCode, fail, ok, parseBytes } from './output.js';\n\ntype Flags = Record<string, string | boolean>;\n\nfunction requireProject() {\n const project = readProject();\n if (!project) fail(ExitCode.USAGE, 'no glass.json found — run `glass init` first');\n return project;\n}\n\n/**\n * Token precedence (`CLI.md` §2): explicit --token > GLASS_TOKEN env > stored\n * per-project token > stored Clerk session. Lets CI inject a token without\n * touching the filesystem.\n */\nfunction resolveToken(flags: Flags, projectId?: string): string | undefined {\n if (typeof flags.token === 'string' && flags.token) return flags.token;\n if (process.env.GLASS_TOKEN) return process.env.GLASS_TOKEN;\n if (projectId) {\n const t = tokenFor(projectId);\n if (t) return t;\n }\n return readCredentials().session;\n}\n\nfunction authedApi(flags: Flags = {}) {\n const project = requireProject();\n const token = resolveToken(flags, project.project_id);\n if (!token) fail(ExitCode.AUTH, 'no credentials — run `glass init`, `glass login`, or set GLASS_TOKEN');\n return { api: new Api(project.api_host, token, project.project_id), project };\n}\n\n// --- glass init (zero-auth provisioning) -------------------------------------\n\nexport async function init(flags: Flags): Promise<never> {\n // Idempotent: don't re-provision if a project is already linked here.\n const existing = readProject();\n if (existing && flags.force !== true) {\n return ok({ project_id: existing.project_id, linked: true }, () => {\n process.stdout.write(`Already linked to ${existing.project_id} (glass.json present).\\n`);\n process.stdout.write('Use `glass init --force` to provision a new project, or `glass install` to wire the SDK.\\n');\n });\n }\n\n const apiHost = (flags['api-host'] as string) ?? 'https://api.glass.dev';\n const api = new Api(apiHost);\n const res = await api.request<{\n project_id: string;\n ingest_key: string;\n provisioning_token: string;\n claim_url: string;\n }>('POST', '/v1/projects/provision', { name: (flags.name as string) ?? undefined });\n\n writeProject({\n project_id: res.project_id,\n ingest_key: res.ingest_key,\n ingest_host: (flags['ingest-host'] as string) ?? 'https://in.glass.dev',\n api_host: apiHost,\n claim_url: res.claim_url,\n });\n const creds = readCredentials();\n creds.tokens[res.project_id] = res.provisioning_token;\n writeCredentials(creds);\n\n return ok(res, () => {\n process.stdout.write(`Created project ${res.project_id}\\n`);\n process.stdout.write('Wrote glass.json and ~/.glass/credentials.json (0600)\\n');\n process.stdout.write(`\\nClaim it to keep your data:\\n ${res.claim_url}\\n`);\n process.stdout.write('\\nNext: `glass install` to wire up the SDK.\\n');\n });\n}\n\n// --- glass install (framework detection) -------------------------------------\n\ntype Framework = 'next' | 'react' | 'vite' | 'node' | 'browser';\n\nfunction detectFramework(): Framework {\n try {\n const pkg = JSON.parse(readFileSync('package.json', 'utf8')) as { dependencies?: Record<string, string>; devDependencies?: Record<string, string> };\n const deps = { ...pkg.dependencies, ...pkg.devDependencies };\n if (deps.next) return 'next';\n if (deps.express || deps.fastify || deps.hono) return 'node';\n if (deps.react) return 'react';\n if (deps.vite) return 'vite';\n } catch {\n /* no package.json — assume browser */\n }\n return 'browser';\n}\n\n/** Pick the package manager from the lockfile present in cwd. */\nfunction detectPackageManager(): { cmd: string; args: string[] } {\n if (existsSync('pnpm-lock.yaml')) return { cmd: 'pnpm', args: ['add'] };\n if (existsSync('yarn.lock')) return { cmd: 'yarn', args: ['add'] };\n if (existsSync('bun.lockb')) return { cmd: 'bun', args: ['add'] };\n return { cmd: 'npm', args: ['install'] };\n}\n\nfunction snippetFor(framework: Framework, project: { ingest_key: string; ingest_host: string }): { file: string; code: string; pkg: string } {\n if (framework === 'node') {\n return {\n pkg: '@glass/node',\n file: 'glass.ts',\n code: `import { GlassNode } from '@glass/node';\\n\\nexport const glass = new GlassNode({ projectKey: '${project.ingest_key}', ingestHost: '${project.ingest_host}' });\\n`,\n };\n }\n return {\n pkg: '@glass/browser',\n file: 'glass.ts',\n code: `import glass from '@glass/browser';\\n\\nglass.init({ projectKey: '${project.ingest_key}', ingestHost: '${project.ingest_host}' });\\n\\nexport default glass;\\n`,\n };\n}\n\n/** Candidate entry-point files per framework, in preference order. */\nfunction entryCandidates(framework: Framework): string[] {\n switch (framework) {\n case 'next':\n return ['app/layout.tsx', 'app/layout.jsx', 'src/app/layout.tsx', 'src/app/layout.jsx'];\n case 'react':\n case 'vite':\n return ['src/main.tsx', 'src/main.jsx', 'src/index.tsx', 'src/index.jsx', 'src/main.ts', 'src/index.ts'];\n case 'node':\n return ['src/index.ts', 'src/server.ts', 'index.ts', 'server.ts', 'src/main.ts'];\n default:\n return [];\n }\n}\n\n/**\n * Inject `import '<glass>'` into the app's entry point so the SDK actually\n * initialises (`CLI.md` §3.1) — writing `glass.ts` alone wires nothing. We only\n * touch a file that exists and doesn't already import it, and we never reorder\n * existing code (the import is prepended, after a leading \"use client\" if present).\n */\nfunction injectEntryPoint(framework: Framework, glassFile: string): { entry: string | null; injected: boolean } {\n for (const entry of entryCandidates(framework)) {\n if (!existsSync(entry)) continue;\n const src = readFileSync(entry, 'utf8');\n let spec = relative(dirname(entry), glassFile).replace(/\\.(ts|tsx|js|jsx)$/, '');\n if (!spec.startsWith('.')) spec = `./${spec}`;\n if (src.includes(`'${spec}'`) || src.includes(`\"${spec}\"`)) return { entry, injected: false };\n const importLine = `import '${spec}';\\n`;\n // Preserve a leading directive (\"use client\"/\"use server\") as the first line.\n const directive = /^\\s*(['\"])use (client|server)\\1;?\\s*\\n/.exec(src);\n const next = directive\n ? src.slice(0, directive[0].length) + importLine + src.slice(directive[0].length)\n : importLine + src;\n writeFileSync(entry, next);\n return { entry, injected: true };\n }\n return { entry: null, injected: false };\n}\n\nexport function install(flags: Flags): never {\n const project = requireProject();\n const framework = ((flags.framework as Framework) ?? detectFramework()) as Framework;\n const { pkg, file, code } = snippetFor(framework, project);\n\n // 1. Install the SDK dependency (fixed argv — never a shell string).\n let installed = false;\n if (flags['no-install'] !== true) {\n const pm = detectPackageManager();\n const r = spawnSync(pm.cmd, [...pm.args, pkg], { stdio: 'inherit' });\n installed = r.status === 0;\n if (!installed && r.error) {\n return fail(ExitCode.ERROR, `failed to run ${pm.cmd}: ${String(r.error.message)} — install ${pkg} manually`);\n }\n }\n\n // 2. Write the wiring file if absent (never clobber existing app code).\n let wrote = false;\n if (!existsSync(file)) {\n writeFileSync(file, code);\n wrote = true;\n }\n\n // 3. Inject the import into the framework entry point so init actually runs.\n const { entry, injected } = injectEntryPoint(framework, file);\n\n return ok({ framework, package: pkg, installed, file, wrote_file: wrote, entry, injected, snippet: code }, () => {\n process.stdout.write(`Detected: ${framework}\\n`);\n process.stdout.write(installed ? `Installed ${pkg}.\\n` : `Skipped install — add ${pkg} yourself.\\n`);\n process.stdout.write(wrote ? `Wrote ${file}.\\n` : `${file} already exists; left untouched.\\n`);\n if (injected && entry) process.stdout.write(`Wired ${file} into ${entry}.\\n`);\n else if (entry) process.stdout.write(`${entry} already imports ${file}.\\n`);\n else process.stdout.write(`No entry point found — import \"./${file.replace(/\\.(ts|tsx)$/, '')}\" yourself.\\n`);\n });\n}\n\n// --- status / doctor ----------------------------------------------------------\n\nexport async function status(flags: Flags): Promise<never> {\n const { api } = authedApi(flags);\n const res = await api.request('GET', '/v1/ingest/status');\n return ok(res);\n}\n\nexport async function doctor(flags: Flags): Promise<never> {\n const project = readProject();\n const checks: { name: string; ok: boolean; detail?: string }[] = [];\n checks.push({ name: 'glass.json present', ok: !!project });\n if (project) {\n const tok = resolveToken(flags, project.project_id);\n checks.push({ name: 'credentials present', ok: !!tok });\n try {\n const api = new Api(project.api_host, tok, project.project_id);\n const s = await api.request<{ receiving: boolean }>('GET', '/v1/ingest/status');\n checks.push({ name: 'events received', ok: s.receiving, detail: s.receiving ? undefined : 'no events in last 24h' });\n } catch {\n checks.push({ name: 'control plane reachable', ok: false });\n }\n }\n const allOk = checks.every((c) => c.ok);\n return allOk ? ok({ checks }) : fail(ExitCode.ERROR, 'doctor found problems', { checks });\n}\n\n// --- claim / login ------------------------------------------------------------\n\nexport async function claim(flags: Flags): Promise<never> {\n const project = requireProject();\n\n // Default: show the claim URL stored at `glass init` WITHOUT contacting the\n // control plane (so we never invalidate a link the user may already be using).\n if (flags.reissue !== true && project.claim_url) {\n return ok({ claim_url: project.claim_url, reissued: false }, () =>\n process.stdout.write(`Claim URL:\\n ${project.claim_url}\\n\\n(Use \\`glass claim --reissue\\` to mint a fresh single-use link.)\\n`),\n );\n }\n\n // `--reissue` (or no stored URL): mint a fresh single-use claim link.\n const token = tokenFor(project.project_id);\n if (!token) fail(ExitCode.AUTH, 'no provisioning token for this project');\n const api = new Api(project.api_host, token);\n const res = await api.request<{ claim_url: string }>('POST', `/v1/projects/${project.project_id}/claim-url`);\n // Persist the new link so subsequent `glass claim` shows it without reissuing.\n writeProject({ ...project, claim_url: res.claim_url });\n return ok({ ...res, reissued: true }, () => process.stdout.write(`Claim URL (reissued):\\n ${res.claim_url}\\n`));\n}\n\nconst sleep = (ms: number) => new Promise<void>((r) => setTimeout(r, ms));\n\n/**\n * `glass login` (`CLI.md` §2). `--token <session>` stores a session directly\n * (CI/non-interactive); otherwise runs the OAuth-style device flow: start a\n * grant, print the verification URL + short user-code, then poll until a\n * signed-in human approves it in the dashboard.\n */\nexport async function login(flags: Flags): Promise<never> {\n const apiHost = (flags['api-host'] as string) ?? readProject()?.api_host ?? 'https://api.glass.dev';\n\n // Non-interactive path: store an explicitly-provided session.\n const provided = flags.token as string | undefined;\n if (provided) {\n const creds = readCredentials();\n creds.session = provided;\n writeCredentials(creds);\n return ok({ message: 'Logged in. Session stored in ~/.glass/credentials.json' }, () =>\n process.stdout.write('Logged in. Session stored in ~/.glass/credentials.json\\n'),\n );\n }\n\n // The device flow needs a human to approve in a browser; in non-interactive\n // mode (`--no-input`/`--yes`, or CI) fail fast and ask for a token instead.\n if (flags['no-input'] === true || flags.yes === true || (!process.stdin.isTTY && !process.stdout.isTTY)) {\n return fail(ExitCode.AUTH, 'login is interactive — pass `--token <session>` or set GLASS_TOKEN for non-interactive use');\n }\n\n // Device flow.\n const api = new Api(apiHost);\n const grant = await api.request<{\n device_code: string;\n user_code: string;\n verification_uri: string;\n verification_uri_complete?: string;\n interval: number;\n expires_in: number;\n }>('POST', '/v1/cli/device/start');\n\n if (!flags.json) {\n process.stdout.write('\\nTo sign in, open:\\n');\n process.stdout.write(` ${grant.verification_uri_complete ?? grant.verification_uri}\\n\\n`);\n process.stdout.write(`and enter the code: ${grant.user_code}\\n\\n`);\n process.stdout.write('Waiting for approval…\\n');\n }\n\n const deadline = Date.now() + grant.expires_in * 1000;\n const intervalMs = Math.max(1, grant.interval) * 1000;\n while (Date.now() < deadline) {\n await sleep(intervalMs);\n let resp: { session?: string; status?: string } | null = null;\n try {\n resp = await api.request<{ session?: string; status?: string }>('POST', '/v1/cli/device/token', {\n device_code: grant.device_code,\n });\n } catch {\n // 202 (pending) / 410 (expired) surface as request errors depending on the\n // client; treat transient failures as \"keep polling\" until the deadline.\n continue;\n }\n if (resp?.session) {\n const creds = readCredentials();\n creds.session = resp.session;\n writeCredentials(creds);\n return ok({ message: 'Logged in. Session stored in ~/.glass/credentials.json' }, () =>\n process.stdout.write('\\nLogged in. Session stored in ~/.glass/credentials.json\\n'),\n );\n }\n }\n return fail(ExitCode.AUTH, 'device authorization timed out — run `glass login` again');\n}\n\nexport function logout(_flags: Flags): never {\n const creds = readCredentials();\n creds.session = undefined;\n writeCredentials(creds);\n return ok({ message: 'Logged out. Cleared stored session.' }, () => process.stdout.write('Logged out.\\n'));\n}\n\nexport async function whoami(flags: Flags): Promise<never> {\n const project = readProject();\n const token = resolveToken(flags, project?.project_id);\n if (!token) fail(ExitCode.AUTH, 'not logged in — run `glass login` or set GLASS_TOKEN');\n const api = new Api(project?.api_host ?? (flags['api-host'] as string) ?? 'https://api.glass.dev', token, project?.project_id);\n return ok(await api.request('GET', '/v1/me'));\n}\n\n/** Switch the active project in glass.json after verifying access. */\nexport async function link(flags: Flags, positionals: string[] = []): Promise<never> {\n // Accept both `glass link <id>` and `glass link --project <id>`.\n const projectId = (flags.project as string | undefined) ?? positionals[0];\n if (!projectId) fail(ExitCode.USAGE, 'link needs a project id: `glass link <id>`');\n const existing = readProject();\n const apiHost = (flags['api-host'] as string) ?? existing?.api_host ?? 'https://api.glass.dev';\n const token = resolveToken(flags, projectId);\n if (!token) fail(ExitCode.AUTH, 'no credentials — run `glass login` or set GLASS_TOKEN');\n const api = new Api(apiHost, token, projectId);\n const proj = await api.request<{ id: string; publishableKey?: string; ingestHost?: string }>('GET', '/v1/project');\n writeProject({\n project_id: projectId,\n ingest_key: proj.publishableKey ?? existing?.ingest_key ?? '',\n ingest_host: proj.ingestHost ?? existing?.ingest_host ?? 'https://in.glass.dev',\n api_host: apiHost,\n });\n return ok({ linked: projectId }, () => process.stdout.write(`Linked glass.json to ${projectId}.\\n`));\n}\n\n// --- query + sugar ------------------------------------------------------------\n\n/**\n * `glass query` source resolution (`CLI.md` §4): a GlassQuery can come from\n * `--query '<json>'`, `--file/-f <path>`, or stdin (so it composes in a pipe:\n * `cat q.json | glass query --json`). Exactly one source is used, in that order.\n */\nexport async function query(flags: Flags): Promise<never> {\n let raw: string | undefined;\n if (typeof flags.query === 'string' && flags.query) raw = flags.query;\n else if (typeof flags.file === 'string' && flags.file) raw = readFileSync(flags.file, 'utf8');\n else if (!process.stdin.isTTY) raw = readFileSync(0, 'utf8').trim() || undefined;\n\n if (!raw) fail(ExitCode.USAGE, \"query needs --query '<json>', --file <path>, or piped stdin\");\n let parsed: GlassQuery;\n try {\n parsed = JSON.parse(raw) as GlassQuery;\n } catch (e) {\n return fail(ExitCode.USAGE, `query is not valid JSON: ${String((e as Error).message)}`);\n }\n return runQuery(parsed, flags);\n}\n\nexport async function runQuery(query: GlassQuery, flags: Flags): Promise<never> {\n const { api } = authedApi(flags);\n const body: Record<string, unknown> = { query, confirm: flags.confirm === true };\n if (flags['max-scan']) {\n // Accept a bare number (legacy: MB) or a unit string (`500MB`, `1GB`).\n const raw = String(flags['max-scan']);\n const bytes = /^[0-9]*\\.?[0-9]+$/.test(raw.trim())\n ? Number(raw) * 1024 * 1024\n : parseBytes(raw);\n if (bytes == null) fail(ExitCode.USAGE, `invalid --max-scan: ${raw} (try 500MB or 1GB)`);\n body.max_scan_bytes = bytes;\n }\n const res = await api.request('POST', '/v1/query', body);\n return ok(res);\n}\n\nfunction parseTime(flags: Flags) {\n return { last: (flags.last as string) ?? '7d' };\n}\n\nexport async function trend(flags: Flags): Promise<never> {\n return runQuery(\n {\n v: 1,\n kind: 'trend',\n time: parseTime(flags),\n measure: { aggregate: (flags.aggregate as 'count' | 'unique_users' | 'sum') ?? 'count', ...(flags.event ? { event: flags.event as string } : {}) },\n bucket: (flags.bucket as 'hour' | 'day' | 'week' | 'month') ?? 'day',\n ...(flags.breakdown ? { breakdown: flags.breakdown as string } : {}),\n },\n flags,\n );\n}\n\nexport async function funnel(flags: Flags): Promise<never> {\n const steps = String(flags.steps ?? '').split(',').map((e) => ({ event: e.trim() })).filter((s) => s.event);\n if (flags.id) return runQuery({ v: 1, kind: 'funnel', time: parseTime(flags), definition_id: flags.id as string }, flags);\n if (steps.length < 2) fail(ExitCode.USAGE, 'funnel needs --steps a,b,c (>=2) or --id <definition>');\n return runQuery({ v: 1, kind: 'funnel', time: parseTime(flags), steps, ...(flags.window ? { window: flags.window as string } : {}) }, flags);\n}\n\nexport async function retention(flags: Flags): Promise<never> {\n if (!flags.id) fail(ExitCode.USAGE, 'retention needs --id <definition>');\n return runQuery({ v: 1, kind: 'retention', time: parseTime(flags), definition_id: flags.id as string, return_event: (flags.return as string) ?? '$pageview', periods: Number(flags.periods ?? 8) }, flags);\n}\n\nexport async function segment(flags: Flags): Promise<never> {\n const groupBy = String(flags['group-by'] ?? '').split(',').map((s) => s.trim()).filter(Boolean);\n if (groupBy.length === 0) fail(ExitCode.USAGE, 'segment needs --group-by a,b');\n return runQuery({ v: 1, kind: 'segmentation', time: parseTime(flags), group_by: groupBy, ...(flags.event ? { event: flags.event as string } : {}) }, flags);\n}\n\nexport async function errors(flags: Flags): Promise<never> {\n return runQuery(\n {\n v: 1,\n kind: 'errors',\n time: parseTime(flags),\n limit: Number(flags.limit ?? 50),\n ...(flags.group ? { group: flags.group as string } : {}),\n ...(flags.status ? { status: flags.status as 'unresolved' | 'resolved' | 'ignored' } : {}),\n },\n flags,\n );\n}\n\nexport async function replays(flags: Flags): Promise<never> {\n return runQuery(\n {\n v: 1,\n kind: 'replays',\n time: parseTime(flags),\n limit: Number(flags.limit ?? 50),\n ...(flags.user ? { session_filters: [{ property: 'user_id', op: 'eq' as const, value: flags.user as string }] } : {}),\n },\n flags,\n );\n}\n\n// --- define / tokens ----------------------------------------------------------\n\nexport async function define(flags: Flags): Promise<never> {\n const { api } = authedApi(flags);\n\n // `define --list` — show existing definitions.\n if (flags.list) return ok(await api.request('GET', '/v1/definitions'));\n\n // Flag-based sugar: build a spec from flags without writing JSON.\n let spec: unknown;\n if (flags.kind === 'funnel') {\n const steps = String(flags.steps ?? '').split(',').map((e) => ({ event: e.trim() })).filter((s) => s.event);\n if (steps.length < 2) fail(ExitCode.USAGE, 'define --kind funnel needs --steps a,b,c (>=2)');\n spec = { v: 1, kind: 'funnel', name: (flags.name as string) ?? 'funnel', steps, scope: (flags.scope as string) ?? 'within-session', ...(flags.window ? { window: flags.window as string } : {}) };\n } else if (flags.kind === 'metric') {\n spec = { v: 1, kind: 'metric', name: (flags.name as string) ?? 'metric', aggregate: (flags.aggregate as string) ?? 'count', bucket: (flags.bucket as string) ?? 'day', ...(flags.event ? { event: flags.event as string } : {}) };\n } else {\n const raw = flags.file ? readFileSync(flags.file as string, 'utf8') : readFileSync(0, 'utf8');\n spec = JSON.parse(raw);\n }\n const res = await api.request('POST', '/v1/definitions', { spec });\n return ok(res);\n}\n\nexport async function tokens(action: string, flags: Flags, positionals: string[] = []): Promise<never> {\n const { api } = authedApi(flags);\n if (action === 'list') return ok(await api.request('GET', '/v1/tokens'));\n if (action === 'create') {\n let budget: number | undefined;\n if (flags['budget-r2sql']) {\n // Accept human units + an optional `/day` rate suffix (`1GB/day`).\n const parsed = parseBytes(String(flags['budget-r2sql']));\n if (parsed == null) fail(ExitCode.USAGE, `invalid --budget-r2sql: ${flags['budget-r2sql']} (try 1GB/day)`);\n budget = parsed;\n }\n const res = await api.request<{ id: string; token: string; prefix: string }>('POST', '/v1/tokens', {\n name: (flags.name as string) ?? 'agent',\n role: (flags.role as string) ?? 'read',\n ...(budget != null ? { budget_r2sql_bytes_per_day: budget } : {}),\n });\n // The secret is shown ONCE — print it verbatim (not through the redactor).\n return ok(res, () => {\n process.stdout.write(`Created token ${res.id}\\n\\n ${res.token}\\n\\nThis is shown once. Store it now (e.g. as GLASS_TOKEN).\\n`);\n });\n }\n if (action === 'revoke') {\n // Accept both `glass tokens revoke <id>` and `--id <id>`.\n const id = (flags.id as string | undefined) ?? positionals[0];\n if (!id) fail(ExitCode.USAGE, 'tokens revoke needs a token id: `glass tokens revoke <id>`');\n return ok(await api.request('DELETE', `/v1/tokens/${id}`));\n }\n return fail(ExitCode.USAGE, 'tokens <list|create|revoke>');\n}\n","/**\n * Stable, scriptable output (`CLI.md` §5). The CLI is built for agents as much\n * as humans: `--json` emits a uniform envelope and EXIT CODES are stable so a\n * caller can branch on them without parsing prose.\n */\n\nexport const ExitCode = {\n OK: 0,\n ERROR: 1,\n USAGE: 2,\n AUTH: 3,\n COST_GATE: 4,\n BUDGET: 5,\n} as const;\nexport type ExitCodeValue = (typeof ExitCode)[keyof typeof ExitCode];\n\ntype OutputFormat = 'human' | 'json' | 'csv' | 'ndjson';\nlet format: OutputFormat = 'human';\nexport function setFormat(f: OutputFormat): void {\n format = f;\n}\n/** Back-compat shim for `--json`. */\nexport function setJsonMode(on: boolean): void {\n if (on) format = 'json';\n}\n\n/** Mask token-like secrets in human output so they're never accidentally logged. */\nconst SECRET_RE =\n /\\b(glass_(?:sk|pt)_[A-Za-z0-9]+)\\b|\\b(eyJ[A-Za-z0-9_-]{10,}\\.[A-Za-z0-9_-]{10,}\\.[A-Za-z0-9_-]{10,})\\b/g;\nexport function redact(text: string): string {\n return text.replace(SECRET_RE, (m) => `${m.slice(0, 12)}…<redacted>`);\n}\n\n/** Flatten an array of flat records to CSV; falls back to JSON for non-tabular data. */\nexport function toCsv(data: unknown): string | null {\n const rows = Array.isArray(data) ? data : extractRows(data);\n if (!rows || rows.length === 0) return null;\n const cols = [...new Set(rows.flatMap((r) => Object.keys(r)))];\n const esc = (v: unknown) => {\n const s = v == null ? '' : typeof v === 'object' ? JSON.stringify(v) : String(v);\n return /[\",\\n]/.test(s) ? `\"${s.replace(/\"/g, '\"\"')}\"` : s;\n };\n return [\n cols.join(','),\n ...rows.map((r) => cols.map((c) => esc((r as Record<string, unknown>)[c])).join(',')),\n ].join('\\n');\n}\n\n/**\n * Parse a human byte budget into bytes (`CLI.md` §4): accepts plain numbers and\n * unit suffixes (`500MB`, `1GB`, `2 TiB`), with an optional `/day` rate suffix\n * that we strip (the API stores per-day budgets). Returns null on garbage.\n */\nconst BYTE_UNITS: Record<string, number> = {\n b: 1,\n kb: 1e3,\n mb: 1e6,\n gb: 1e9,\n tb: 1e12,\n kib: 1024,\n mib: 1024 ** 2,\n gib: 1024 ** 3,\n tib: 1024 ** 4,\n};\nexport function parseBytes(input: string): number | null {\n const s = input.trim().toLowerCase().replace(/\\/(day|d|hr|hour|h)$/, '');\n const m = /^([0-9]*\\.?[0-9]+)\\s*([a-z]+)?$/.exec(s);\n if (!m) return null;\n const value = Number(m[1]);\n if (!Number.isFinite(value)) return null;\n if (!m[2]) return value; // bare number = bytes\n const unit = BYTE_UNITS[m[2]];\n if (!unit) return null;\n return Math.round(value * unit);\n}\n\n/** Find the first array-of-objects field (e.g. {rows:[...]}, {issues:[...]}). */\nexport function extractRows(data: unknown): Record<string, unknown>[] | null {\n if (Array.isArray(data)) return data as Record<string, unknown>[];\n if (data && typeof data === 'object') {\n for (const v of Object.values(data)) {\n if (Array.isArray(v) && v.every((x) => x && typeof x === 'object'))\n return v as Record<string, unknown>[];\n }\n }\n return null;\n}\n\n/**\n * Render an array of flat records as an aligned ASCII table for human output.\n * Returns null when the data isn't tabular so callers can fall back to JSON.\n */\nexport function humanTable(data: unknown): string | null {\n const rows = extractRows(data);\n if (!rows || rows.length === 0) return null;\n const cols = [...new Set(rows.flatMap((r) => Object.keys(r)))];\n if (cols.length === 0) return null;\n const cell = (v: unknown) => {\n const s = v == null ? '' : typeof v === 'object' ? JSON.stringify(v) : String(v);\n return redact(s).replace(/\\n/g, ' ');\n };\n const widths = cols.map((c) =>\n Math.max(c.length, ...rows.map((r) => cell((r as Record<string, unknown>)[c]).length)),\n );\n const line = (cells: string[]) => cells.map((s, i) => s.padEnd(widths[i] ?? 0)).join(' ').trimEnd();\n const header = line(cols);\n const sep = widths.map((w) => '-'.repeat(w)).join(' ');\n const body = rows.map((r) => line(cols.map((c) => cell((r as Record<string, unknown>)[c]))));\n return [header, sep, ...body].join('\\n');\n}\n\n/**\n * One-line provenance badge for a query result (`UI.md` ResultBadge parity):\n * surfaces whether a number is exact or sampled, and its source, so an agent\n * reading stdout knows how much to trust it. Returns null when not applicable.\n */\nexport function resultBadge(data: unknown): string | null {\n if (!data || typeof data !== 'object') return null;\n const d = data as Record<string, unknown>;\n if (typeof d.exact !== 'boolean' && !d.source && !d.sampled) return null;\n const parts: string[] = [];\n parts.push(d.exact === false ? 'sampled' : 'exact');\n if (d.source) parts.push(String(d.source));\n const sampled = d.sampled as { interval?: number } | undefined;\n if (sampled?.interval && sampled.interval > 1) parts.push(`1/${sampled.interval}`);\n return `[${parts.join(' · ')}]`;\n}\n\nexport function ok(data: unknown, human?: () => void): never {\n if (format === 'json') {\n process.stdout.write(`${JSON.stringify({ ok: true, data }, null, 2)}\\n`);\n } else if (format === 'ndjson') {\n const rows = extractRows(data) ?? [data];\n for (const r of rows) process.stdout.write(`${JSON.stringify(r)}\\n`);\n } else if (format === 'csv') {\n const csv = toCsv(data);\n process.stdout.write(csv ? `${csv}\\n` : `${JSON.stringify(data, null, 2)}\\n`);\n } else if (human) {\n human();\n } else {\n const table = humanTable(data);\n if (table) {\n const badge = resultBadge(data);\n process.stdout.write(`${table}\\n`);\n if (badge) process.stdout.write(`${badge}\\n`);\n } else {\n process.stdout.write(`${redact(JSON.stringify(data, null, 2))}\\n`);\n }\n }\n process.exit(ExitCode.OK);\n}\n\nexport function fail(code: ExitCodeValue, message: string, extra?: unknown): never {\n if (format === 'json' || format === 'ndjson') {\n process.stdout.write(\n `${JSON.stringify({ ok: false, error: { code, message, ...(extra ? { extra } : {}) } }, null, 2)}\\n`,\n );\n } else {\n process.stderr.write(`glass: ${message}\\n`);\n if (extra) process.stderr.write(`${redact(JSON.stringify(extra, null, 2))}\\n`);\n }\n process.exit(code);\n}\n","import { ExitCode, fail } from './output.js';\n\n/**\n * Thin control-plane client. Maps HTTP status to the CLI's stable exit codes so\n * `--json` callers (agents) can branch deterministically (`CLI.md` §5):\n * 401/403 → AUTH(3), 402 → COST_GATE(4), 429 → BUDGET(5).\n */\nexport class Api {\n constructor(\n private apiHost: string,\n private token?: string,\n private projectId?: string,\n ) {}\n\n async request<T = unknown>(method: string, path: string, body?: unknown): Promise<T> {\n const headers: Record<string, string> = { 'Content-Type': 'application/json' };\n if (this.token) headers.Authorization = `Bearer ${this.token}`;\n if (this.projectId) headers['X-Glass-Project'] = this.projectId;\n\n const res = await fetch(`${this.apiHost}${path}`, {\n method,\n headers,\n ...(body !== undefined ? { body: JSON.stringify(body) } : {}),\n }).catch((e) => fail(ExitCode.ERROR, `network error: ${String(e)}`));\n\n const text = await res.text();\n const json = text ? (JSON.parse(text) as T) : ({} as T);\n\n if (res.status === 401 || res.status === 403) fail(ExitCode.AUTH, 'unauthorized', json);\n if (res.status === 402) fail(ExitCode.COST_GATE, 'cost gate: re-run with --confirm', json);\n if (res.status === 429) fail(ExitCode.BUDGET, 'budget or rate limit exceeded', json);\n if (!res.ok) fail(ExitCode.ERROR, `request failed (${res.status})`, json);\n return json;\n }\n}\n","import { chmodSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { dirname, join } from 'node:path';\n\n/**\n * Local config (`CLI.md` §2/§3). Project pointer in `glass.json` (committable,\n * contains only the write-only publishable key); SECRETS in\n * `~/.glass/credentials.json` with `0600` perms, never in the repo.\n */\n\nexport interface ProjectFile {\n project_id: string;\n ingest_key: string;\n ingest_host: string;\n api_host: string;\n /** The claim URL minted at provisioning (single-use); shown by `glass claim`. */\n claim_url?: string;\n}\n\nexport interface Credentials {\n /** provisioning/agent tokens keyed by project_id. */\n tokens: Record<string, string>;\n /** Clerk session from `glass login` (device flow). */\n session?: string;\n}\n\nconst PROJECT_FILE = join(process.cwd(), 'glass.json');\nconst CRED_FILE = join(homedir(), '.glass', 'credentials.json');\n\n/**\n * Read the project pointer, with environment overrides layered on top\n * (`CLI.md` §2): `GLASS_PROJECT` selects/overrides the project id and\n * `GLASS_INGEST_KEY` the publishable key — so CI can run without a committed\n * `glass.json`. If neither the file nor `GLASS_PROJECT` is present, returns null.\n */\nexport function readProject(): ProjectFile | null {\n let file: ProjectFile | null = null;\n try {\n file = JSON.parse(readFileSync(PROJECT_FILE, 'utf8')) as ProjectFile;\n } catch {\n file = null;\n }\n\n const envProject = process.env.GLASS_PROJECT;\n const envIngest = process.env.GLASS_INGEST_KEY;\n if (!file && !envProject) return null;\n\n return {\n project_id: envProject ?? file?.project_id ?? '',\n ingest_key: envIngest ?? file?.ingest_key ?? '',\n ingest_host: process.env.GLASS_INGEST_HOST ?? file?.ingest_host ?? 'https://in.glass.dev',\n api_host: process.env.GLASS_API_HOST ?? file?.api_host ?? 'https://api.glass.dev',\n ...(file?.claim_url ? { claim_url: file.claim_url } : {}),\n };\n}\n\nexport function writeProject(p: ProjectFile): void {\n writeFileSync(PROJECT_FILE, `${JSON.stringify(p, null, 2)}\\n`);\n}\n\nexport function readCredentials(): Credentials {\n try {\n return JSON.parse(readFileSync(CRED_FILE, 'utf8')) as Credentials;\n } catch {\n return { tokens: {} };\n }\n}\n\nexport function writeCredentials(c: Credentials): void {\n mkdirSync(dirname(CRED_FILE), { recursive: true, mode: 0o700 });\n writeFileSync(CRED_FILE, `${JSON.stringify(c, null, 2)}\\n`, { mode: 0o600 });\n chmodSync(CRED_FILE, 0o600); // enforce even if the file pre-existed\n}\n\nexport function tokenFor(projectId: string): string | undefined {\n return readCredentials().tokens[projectId];\n}\n"],"mappings":"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","names":["readFileSync","writeFileSync","dirname","readFileSync","dirname","writeFileSync","query"]} | ||
| {"version":3,"sources":["../src/cli.ts","../src/commands.ts","../src/output.ts","../src/api.ts","../src/config.ts"],"sourcesContent":["import { parseArgs } from 'node:util';\nimport * as cmd from './commands.js';\nimport { ExitCode, fail, setFormat, setJsonMode } from './output.js';\n\n/**\n * `glass` — the agent-friendly terminal surface (`CLI.md`). Setup in one command\n * (`glass init`, no signup), then the same typed query primitives the dashboard\n * uses. `--json` + stable exit codes make it scriptable by humans and agents.\n */\n\nconst HELP = `glass <command> [options]\n\nSetup\n init [--force] Provision a project with no signup (writes glass.json)\n install [--framework F] [--no-install] Install + wire the SDK\n status Show whether events are being received\n doctor Diagnose setup problems\n claim Get the claim URL to keep your data\n login [--token T] Store a Clerk session for human-scoped access\n logout Clear the stored session\n whoami Show the current principal (GET /v1/me)\n link --project ID Point glass.json at another project you can access\n\nQuery (all accept --last 7d, --json, --confirm, --max-scan <MB>)\n trend --event E [--bucket day] [--breakdown B] [--aggregate count|unique_users|sum]\n funnel --steps a,b,c | --id <def> [--window 1d]\n retention --id <def> --return E [--periods 8]\n segment --group-by a,b [--event E]\n errors\n replays [--limit 50]\n query --query '<json>' | -f <file> | (piped stdin)\n\nManage\n define --file spec.json | --kind funnel --steps a,b | --list\n tokens list | create [--budget-r2sql 1GB/day] | revoke <id>\n link <project-id>\n\nGlobal: --json --csv --ndjson --api-host --ingest-host\n --max-scan <500MB|1GB> --yes/--no-input (auth: --token | GLASS_TOKEN)\nEnv: GLASS_TOKEN GLASS_PROJECT GLASS_INGEST_KEY GLASS_API_HOST`;\n\nasync function main(): Promise<void> {\n const argv = process.argv.slice(2);\n const command = argv[0];\n const sub = argv[1] && !argv[1].startsWith('-') ? argv[1] : undefined;\n\n const { values, positionals } = parseArgs({\n args: argv.slice(1),\n allowPositionals: true,\n options: {\n json: { type: 'boolean' },\n csv: { type: 'boolean' },\n ndjson: { type: 'boolean' },\n confirm: { type: 'boolean' },\n reissue: { type: 'boolean' },\n force: { type: 'boolean' },\n 'no-install': { type: 'boolean' },\n yes: { type: 'boolean' },\n 'no-input': { type: 'boolean' },\n list: { type: 'boolean' },\n 'max-scan': { type: 'string' },\n last: { type: 'string' },\n event: { type: 'string' },\n bucket: { type: 'string' },\n breakdown: { type: 'string' },\n aggregate: { type: 'string' },\n steps: { type: 'string' },\n window: { type: 'string' },\n scope: { type: 'string' },\n kind: { type: 'string' },\n id: { type: 'string' },\n return: { type: 'string' },\n periods: { type: 'string' },\n 'group-by': { type: 'string' },\n group: { type: 'string' },\n status: { type: 'string' },\n limit: { type: 'string' },\n user: { type: 'string' },\n query: { type: 'string' },\n file: { type: 'string', short: 'f' },\n name: { type: 'string' },\n role: { type: 'string' },\n framework: { type: 'string' },\n project: { type: 'string' },\n 'budget-r2sql': { type: 'string' },\n token: { type: 'string' },\n 'api-host': { type: 'string' },\n 'ingest-host': { type: 'string' },\n },\n });\n\n const flags = values as Record<string, string | boolean>;\n if (flags.json) setJsonMode(true);\n else if (flags.ndjson) setFormat('ndjson');\n else if (flags.csv) setFormat('csv');\n\n switch (command) {\n case 'init':\n return void (await cmd.init(flags));\n case 'install':\n return void cmd.install(flags);\n case 'status':\n return void (await cmd.status(flags));\n case 'doctor':\n return void (await cmd.doctor(flags));\n case 'claim':\n return void (await cmd.claim(flags));\n case 'login':\n return void (await cmd.login(flags));\n case 'logout':\n return void cmd.logout(flags);\n case 'whoami':\n return void (await cmd.whoami(flags));\n case 'link':\n return void (await cmd.link(flags, positionals));\n case 'trend':\n return void (await cmd.trend(flags));\n case 'funnel':\n return void (await cmd.funnel(flags));\n case 'retention':\n return void (await cmd.retention(flags));\n case 'segment':\n return void (await cmd.segment(flags));\n case 'errors':\n return void (await cmd.errors(flags));\n case 'replays':\n return void (await cmd.replays(flags));\n case 'query':\n return void (await cmd.query(flags));\n case 'define':\n return void (await cmd.define(flags));\n case 'tokens':\n // positionals[0] is the sub-action; pass the remainder (e.g. token id).\n return void (await cmd.tokens(sub ?? 'list', flags, positionals.slice(1)));\n case 'help':\n case undefined:\n case '--help':\n case '-h':\n process.stdout.write(`${HELP}\\n`);\n process.exit(ExitCode.OK);\n break;\n default:\n fail(ExitCode.USAGE, `unknown command: ${command}\\n\\n${HELP}`);\n }\n}\n\nmain().catch((e) => fail(ExitCode.ERROR, String(e?.message ?? e)));\n","import { spawnSync } from 'node:child_process';\nimport { existsSync, readFileSync, writeFileSync } from 'node:fs';\nimport { dirname, relative } from 'node:path';\nimport type { GlassQuery } from '@glassanalytics/core';\nimport { Api } from './api.js';\nimport { readCredentials, readProject, tokenFor, writeCredentials, writeProject } from './config.js';\nimport { ExitCode, fail, ok, parseBytes } from './output.js';\n\ntype Flags = Record<string, string | boolean>;\n\nfunction requireProject() {\n const project = readProject();\n if (!project) fail(ExitCode.USAGE, 'no glass.json found — run `glass init` first');\n return project;\n}\n\n/**\n * Token precedence (`CLI.md` §2): explicit --token > GLASS_TOKEN env > stored\n * per-project token > stored Clerk session. Lets CI inject a token without\n * touching the filesystem.\n */\nfunction resolveToken(flags: Flags, projectId?: string): string | undefined {\n if (typeof flags.token === 'string' && flags.token) return flags.token;\n if (process.env.GLASS_TOKEN) return process.env.GLASS_TOKEN;\n if (projectId) {\n const t = tokenFor(projectId);\n if (t) return t;\n }\n return readCredentials().session;\n}\n\nfunction authedApi(flags: Flags = {}) {\n const project = requireProject();\n const token = resolveToken(flags, project.project_id);\n if (!token) fail(ExitCode.AUTH, 'no credentials — run `glass init`, `glass login`, or set GLASS_TOKEN');\n return { api: new Api(project.api_host, token, project.project_id), project };\n}\n\n// --- glass init (zero-auth provisioning) -------------------------------------\n\nexport async function init(flags: Flags): Promise<never> {\n // Idempotent: don't re-provision if a project is already linked here.\n const existing = readProject();\n if (existing && flags.force !== true) {\n return ok({ project_id: existing.project_id, linked: true }, () => {\n process.stdout.write(`Already linked to ${existing.project_id} (glass.json present).\\n`);\n process.stdout.write('Use `glass init --force` to provision a new project, or `glass install` to wire the SDK.\\n');\n });\n }\n\n const apiHost = (flags['api-host'] as string) ?? 'https://api.glass.dev';\n const api = new Api(apiHost);\n const res = await api.request<{\n project_id: string;\n ingest_key: string;\n provisioning_token: string;\n claim_url: string;\n }>('POST', '/v1/projects/provision', { name: (flags.name as string) ?? undefined });\n\n writeProject({\n project_id: res.project_id,\n ingest_key: res.ingest_key,\n ingest_host: (flags['ingest-host'] as string) ?? 'https://in.glass.dev',\n api_host: apiHost,\n claim_url: res.claim_url,\n });\n const creds = readCredentials();\n creds.tokens[res.project_id] = res.provisioning_token;\n writeCredentials(creds);\n\n return ok(res, () => {\n process.stdout.write(`Created project ${res.project_id}\\n`);\n process.stdout.write('Wrote glass.json and ~/.glass/credentials.json (0600)\\n');\n process.stdout.write(`\\nClaim it to keep your data:\\n ${res.claim_url}\\n`);\n process.stdout.write('\\nNext: `glass install` to wire up the SDK.\\n');\n });\n}\n\n// --- glass install (framework detection) -------------------------------------\n\ntype Framework = 'next' | 'react' | 'vite' | 'node' | 'browser';\n\nfunction detectFramework(): Framework {\n try {\n const pkg = JSON.parse(readFileSync('package.json', 'utf8')) as { dependencies?: Record<string, string>; devDependencies?: Record<string, string> };\n const deps = { ...pkg.dependencies, ...pkg.devDependencies };\n if (deps.next) return 'next';\n if (deps.express || deps.fastify || deps.hono) return 'node';\n if (deps.react) return 'react';\n if (deps.vite) return 'vite';\n } catch {\n /* no package.json — assume browser */\n }\n return 'browser';\n}\n\n/** Pick the package manager from the lockfile present in cwd. */\nfunction detectPackageManager(): { cmd: string; args: string[] } {\n if (existsSync('pnpm-lock.yaml')) return { cmd: 'pnpm', args: ['add'] };\n if (existsSync('yarn.lock')) return { cmd: 'yarn', args: ['add'] };\n if (existsSync('bun.lockb')) return { cmd: 'bun', args: ['add'] };\n return { cmd: 'npm', args: ['install'] };\n}\n\nfunction snippetFor(framework: Framework, project: { ingest_key: string; ingest_host: string }): { file: string; code: string; pkg: string } {\n if (framework === 'node') {\n return {\n pkg: '@glassanalytics/node',\n file: 'glass.ts',\n code: `import { GlassNode } from '@glassanalytics/node';\\n\\nexport const glass = new GlassNode({ projectKey: '${project.ingest_key}', ingestHost: '${project.ingest_host}' });\\n`,\n };\n }\n return {\n pkg: '@glassanalytics/browser',\n file: 'glass.ts',\n code: `import glass from '@glassanalytics/browser';\\n\\nglass.init({ projectKey: '${project.ingest_key}', ingestHost: '${project.ingest_host}' });\\n\\nexport default glass;\\n`,\n };\n}\n\n/** Candidate entry-point files per framework, in preference order. */\nfunction entryCandidates(framework: Framework): string[] {\n switch (framework) {\n case 'next':\n return ['app/layout.tsx', 'app/layout.jsx', 'src/app/layout.tsx', 'src/app/layout.jsx'];\n case 'react':\n case 'vite':\n return ['src/main.tsx', 'src/main.jsx', 'src/index.tsx', 'src/index.jsx', 'src/main.ts', 'src/index.ts'];\n case 'node':\n return ['src/index.ts', 'src/server.ts', 'index.ts', 'server.ts', 'src/main.ts'];\n default:\n return [];\n }\n}\n\n/**\n * Inject `import '<glass>'` into the app's entry point so the SDK actually\n * initialises (`CLI.md` §3.1) — writing `glass.ts` alone wires nothing. We only\n * touch a file that exists and doesn't already import it, and we never reorder\n * existing code (the import is prepended, after a leading \"use client\" if present).\n */\nfunction injectEntryPoint(framework: Framework, glassFile: string): { entry: string | null; injected: boolean } {\n for (const entry of entryCandidates(framework)) {\n if (!existsSync(entry)) continue;\n const src = readFileSync(entry, 'utf8');\n let spec = relative(dirname(entry), glassFile).replace(/\\.(ts|tsx|js|jsx)$/, '');\n if (!spec.startsWith('.')) spec = `./${spec}`;\n if (src.includes(`'${spec}'`) || src.includes(`\"${spec}\"`)) return { entry, injected: false };\n const importLine = `import '${spec}';\\n`;\n // Preserve a leading directive (\"use client\"/\"use server\") as the first line.\n const directive = /^\\s*(['\"])use (client|server)\\1;?\\s*\\n/.exec(src);\n const next = directive\n ? src.slice(0, directive[0].length) + importLine + src.slice(directive[0].length)\n : importLine + src;\n writeFileSync(entry, next);\n return { entry, injected: true };\n }\n return { entry: null, injected: false };\n}\n\nexport function install(flags: Flags): never {\n const project = requireProject();\n const framework = ((flags.framework as Framework) ?? detectFramework()) as Framework;\n const { pkg, file, code } = snippetFor(framework, project);\n\n // 1. Install the SDK dependency (fixed argv — never a shell string).\n let installed = false;\n if (flags['no-install'] !== true) {\n const pm = detectPackageManager();\n const r = spawnSync(pm.cmd, [...pm.args, pkg], { stdio: 'inherit' });\n installed = r.status === 0;\n if (!installed && r.error) {\n return fail(ExitCode.ERROR, `failed to run ${pm.cmd}: ${String(r.error.message)} — install ${pkg} manually`);\n }\n }\n\n // 2. Write the wiring file if absent (never clobber existing app code).\n let wrote = false;\n if (!existsSync(file)) {\n writeFileSync(file, code);\n wrote = true;\n }\n\n // 3. Inject the import into the framework entry point so init actually runs.\n const { entry, injected } = injectEntryPoint(framework, file);\n\n return ok({ framework, package: pkg, installed, file, wrote_file: wrote, entry, injected, snippet: code }, () => {\n process.stdout.write(`Detected: ${framework}\\n`);\n process.stdout.write(installed ? `Installed ${pkg}.\\n` : `Skipped install — add ${pkg} yourself.\\n`);\n process.stdout.write(wrote ? `Wrote ${file}.\\n` : `${file} already exists; left untouched.\\n`);\n if (injected && entry) process.stdout.write(`Wired ${file} into ${entry}.\\n`);\n else if (entry) process.stdout.write(`${entry} already imports ${file}.\\n`);\n else process.stdout.write(`No entry point found — import \"./${file.replace(/\\.(ts|tsx)$/, '')}\" yourself.\\n`);\n });\n}\n\n// --- status / doctor ----------------------------------------------------------\n\nexport async function status(flags: Flags): Promise<never> {\n const { api } = authedApi(flags);\n const res = await api.request('GET', '/v1/ingest/status');\n return ok(res);\n}\n\nexport async function doctor(flags: Flags): Promise<never> {\n const project = readProject();\n const checks: { name: string; ok: boolean; detail?: string }[] = [];\n checks.push({ name: 'glass.json present', ok: !!project });\n if (project) {\n const tok = resolveToken(flags, project.project_id);\n checks.push({ name: 'credentials present', ok: !!tok });\n try {\n const api = new Api(project.api_host, tok, project.project_id);\n const s = await api.request<{ receiving: boolean }>('GET', '/v1/ingest/status');\n checks.push({ name: 'events received', ok: s.receiving, detail: s.receiving ? undefined : 'no events in last 24h' });\n } catch {\n checks.push({ name: 'control plane reachable', ok: false });\n }\n }\n const allOk = checks.every((c) => c.ok);\n return allOk ? ok({ checks }) : fail(ExitCode.ERROR, 'doctor found problems', { checks });\n}\n\n// --- claim / login ------------------------------------------------------------\n\nexport async function claim(flags: Flags): Promise<never> {\n const project = requireProject();\n\n // Default: show the claim URL stored at `glass init` WITHOUT contacting the\n // control plane (so we never invalidate a link the user may already be using).\n if (flags.reissue !== true && project.claim_url) {\n return ok({ claim_url: project.claim_url, reissued: false }, () =>\n process.stdout.write(`Claim URL:\\n ${project.claim_url}\\n\\n(Use \\`glass claim --reissue\\` to mint a fresh single-use link.)\\n`),\n );\n }\n\n // `--reissue` (or no stored URL): mint a fresh single-use claim link.\n const token = tokenFor(project.project_id);\n if (!token) fail(ExitCode.AUTH, 'no provisioning token for this project');\n const api = new Api(project.api_host, token);\n const res = await api.request<{ claim_url: string }>('POST', `/v1/projects/${project.project_id}/claim-url`);\n // Persist the new link so subsequent `glass claim` shows it without reissuing.\n writeProject({ ...project, claim_url: res.claim_url });\n return ok({ ...res, reissued: true }, () => process.stdout.write(`Claim URL (reissued):\\n ${res.claim_url}\\n`));\n}\n\nconst sleep = (ms: number) => new Promise<void>((r) => setTimeout(r, ms));\n\n/**\n * `glass login` (`CLI.md` §2). `--token <session>` stores a session directly\n * (CI/non-interactive); otherwise runs the OAuth-style device flow: start a\n * grant, print the verification URL + short user-code, then poll until a\n * signed-in human approves it in the dashboard.\n */\nexport async function login(flags: Flags): Promise<never> {\n const apiHost = (flags['api-host'] as string) ?? readProject()?.api_host ?? 'https://api.glass.dev';\n\n // Non-interactive path: store an explicitly-provided session.\n const provided = flags.token as string | undefined;\n if (provided) {\n const creds = readCredentials();\n creds.session = provided;\n writeCredentials(creds);\n return ok({ message: 'Logged in. Session stored in ~/.glass/credentials.json' }, () =>\n process.stdout.write('Logged in. Session stored in ~/.glass/credentials.json\\n'),\n );\n }\n\n // The device flow needs a human to approve in a browser; in non-interactive\n // mode (`--no-input`/`--yes`, or CI) fail fast and ask for a token instead.\n if (flags['no-input'] === true || flags.yes === true || (!process.stdin.isTTY && !process.stdout.isTTY)) {\n return fail(ExitCode.AUTH, 'login is interactive — pass `--token <session>` or set GLASS_TOKEN for non-interactive use');\n }\n\n // Device flow.\n const api = new Api(apiHost);\n const grant = await api.request<{\n device_code: string;\n user_code: string;\n verification_uri: string;\n verification_uri_complete?: string;\n interval: number;\n expires_in: number;\n }>('POST', '/v1/cli/device/start');\n\n if (!flags.json) {\n process.stdout.write('\\nTo sign in, open:\\n');\n process.stdout.write(` ${grant.verification_uri_complete ?? grant.verification_uri}\\n\\n`);\n process.stdout.write(`and enter the code: ${grant.user_code}\\n\\n`);\n process.stdout.write('Waiting for approval…\\n');\n }\n\n const deadline = Date.now() + grant.expires_in * 1000;\n const intervalMs = Math.max(1, grant.interval) * 1000;\n while (Date.now() < deadline) {\n await sleep(intervalMs);\n let resp: { session?: string; status?: string } | null = null;\n try {\n resp = await api.request<{ session?: string; status?: string }>('POST', '/v1/cli/device/token', {\n device_code: grant.device_code,\n });\n } catch {\n // 202 (pending) / 410 (expired) surface as request errors depending on the\n // client; treat transient failures as \"keep polling\" until the deadline.\n continue;\n }\n if (resp?.session) {\n const creds = readCredentials();\n creds.session = resp.session;\n writeCredentials(creds);\n return ok({ message: 'Logged in. Session stored in ~/.glass/credentials.json' }, () =>\n process.stdout.write('\\nLogged in. Session stored in ~/.glass/credentials.json\\n'),\n );\n }\n }\n return fail(ExitCode.AUTH, 'device authorization timed out — run `glass login` again');\n}\n\nexport function logout(_flags: Flags): never {\n const creds = readCredentials();\n creds.session = undefined;\n writeCredentials(creds);\n return ok({ message: 'Logged out. Cleared stored session.' }, () => process.stdout.write('Logged out.\\n'));\n}\n\nexport async function whoami(flags: Flags): Promise<never> {\n const project = readProject();\n const token = resolveToken(flags, project?.project_id);\n if (!token) fail(ExitCode.AUTH, 'not logged in — run `glass login` or set GLASS_TOKEN');\n const api = new Api(project?.api_host ?? (flags['api-host'] as string) ?? 'https://api.glass.dev', token, project?.project_id);\n return ok(await api.request('GET', '/v1/me'));\n}\n\n/** Switch the active project in glass.json after verifying access. */\nexport async function link(flags: Flags, positionals: string[] = []): Promise<never> {\n // Accept both `glass link <id>` and `glass link --project <id>`.\n const projectId = (flags.project as string | undefined) ?? positionals[0];\n if (!projectId) fail(ExitCode.USAGE, 'link needs a project id: `glass link <id>`');\n const existing = readProject();\n const apiHost = (flags['api-host'] as string) ?? existing?.api_host ?? 'https://api.glass.dev';\n const token = resolveToken(flags, projectId);\n if (!token) fail(ExitCode.AUTH, 'no credentials — run `glass login` or set GLASS_TOKEN');\n const api = new Api(apiHost, token, projectId);\n const proj = await api.request<{ id: string; publishableKey?: string; ingestHost?: string }>('GET', '/v1/project');\n writeProject({\n project_id: projectId,\n ingest_key: proj.publishableKey ?? existing?.ingest_key ?? '',\n ingest_host: proj.ingestHost ?? existing?.ingest_host ?? 'https://in.glass.dev',\n api_host: apiHost,\n });\n return ok({ linked: projectId }, () => process.stdout.write(`Linked glass.json to ${projectId}.\\n`));\n}\n\n// --- query + sugar ------------------------------------------------------------\n\n/**\n * `glass query` source resolution (`CLI.md` §4): a GlassQuery can come from\n * `--query '<json>'`, `--file/-f <path>`, or stdin (so it composes in a pipe:\n * `cat q.json | glass query --json`). Exactly one source is used, in that order.\n */\nexport async function query(flags: Flags): Promise<never> {\n let raw: string | undefined;\n if (typeof flags.query === 'string' && flags.query) raw = flags.query;\n else if (typeof flags.file === 'string' && flags.file) raw = readFileSync(flags.file, 'utf8');\n else if (!process.stdin.isTTY) raw = readFileSync(0, 'utf8').trim() || undefined;\n\n if (!raw) fail(ExitCode.USAGE, \"query needs --query '<json>', --file <path>, or piped stdin\");\n let parsed: GlassQuery;\n try {\n parsed = JSON.parse(raw) as GlassQuery;\n } catch (e) {\n return fail(ExitCode.USAGE, `query is not valid JSON: ${String((e as Error).message)}`);\n }\n return runQuery(parsed, flags);\n}\n\nexport async function runQuery(query: GlassQuery, flags: Flags): Promise<never> {\n const { api } = authedApi(flags);\n const body: Record<string, unknown> = { query, confirm: flags.confirm === true };\n if (flags['max-scan']) {\n // Accept a bare number (legacy: MB) or a unit string (`500MB`, `1GB`).\n const raw = String(flags['max-scan']);\n const bytes = /^[0-9]*\\.?[0-9]+$/.test(raw.trim())\n ? Number(raw) * 1024 * 1024\n : parseBytes(raw);\n if (bytes == null) fail(ExitCode.USAGE, `invalid --max-scan: ${raw} (try 500MB or 1GB)`);\n body.max_scan_bytes = bytes;\n }\n const res = await api.request('POST', '/v1/query', body);\n return ok(res);\n}\n\nfunction parseTime(flags: Flags) {\n return { last: (flags.last as string) ?? '7d' };\n}\n\nexport async function trend(flags: Flags): Promise<never> {\n return runQuery(\n {\n v: 1,\n kind: 'trend',\n time: parseTime(flags),\n measure: { aggregate: (flags.aggregate as 'count' | 'unique_users' | 'sum') ?? 'count', ...(flags.event ? { event: flags.event as string } : {}) },\n bucket: (flags.bucket as 'hour' | 'day' | 'week' | 'month') ?? 'day',\n ...(flags.breakdown ? { breakdown: flags.breakdown as string } : {}),\n },\n flags,\n );\n}\n\nexport async function funnel(flags: Flags): Promise<never> {\n const steps = String(flags.steps ?? '').split(',').map((e) => ({ event: e.trim() })).filter((s) => s.event);\n if (flags.id) return runQuery({ v: 1, kind: 'funnel', time: parseTime(flags), definition_id: flags.id as string }, flags);\n if (steps.length < 2) fail(ExitCode.USAGE, 'funnel needs --steps a,b,c (>=2) or --id <definition>');\n return runQuery({ v: 1, kind: 'funnel', time: parseTime(flags), steps, ...(flags.window ? { window: flags.window as string } : {}) }, flags);\n}\n\nexport async function retention(flags: Flags): Promise<never> {\n if (!flags.id) fail(ExitCode.USAGE, 'retention needs --id <definition>');\n return runQuery({ v: 1, kind: 'retention', time: parseTime(flags), definition_id: flags.id as string, return_event: (flags.return as string) ?? '$pageview', periods: Number(flags.periods ?? 8) }, flags);\n}\n\nexport async function segment(flags: Flags): Promise<never> {\n const groupBy = String(flags['group-by'] ?? '').split(',').map((s) => s.trim()).filter(Boolean);\n if (groupBy.length === 0) fail(ExitCode.USAGE, 'segment needs --group-by a,b');\n return runQuery({ v: 1, kind: 'segmentation', time: parseTime(flags), group_by: groupBy, ...(flags.event ? { event: flags.event as string } : {}) }, flags);\n}\n\nexport async function errors(flags: Flags): Promise<never> {\n return runQuery(\n {\n v: 1,\n kind: 'errors',\n time: parseTime(flags),\n limit: Number(flags.limit ?? 50),\n ...(flags.group ? { group: flags.group as string } : {}),\n ...(flags.status ? { status: flags.status as 'unresolved' | 'resolved' | 'ignored' } : {}),\n },\n flags,\n );\n}\n\nexport async function replays(flags: Flags): Promise<never> {\n return runQuery(\n {\n v: 1,\n kind: 'replays',\n time: parseTime(flags),\n limit: Number(flags.limit ?? 50),\n ...(flags.user ? { session_filters: [{ property: 'user_id', op: 'eq' as const, value: flags.user as string }] } : {}),\n },\n flags,\n );\n}\n\n// --- define / tokens ----------------------------------------------------------\n\nexport async function define(flags: Flags): Promise<never> {\n const { api } = authedApi(flags);\n\n // `define --list` — show existing definitions.\n if (flags.list) return ok(await api.request('GET', '/v1/definitions'));\n\n // Flag-based sugar: build a spec from flags without writing JSON.\n let spec: unknown;\n if (flags.kind === 'funnel') {\n const steps = String(flags.steps ?? '').split(',').map((e) => ({ event: e.trim() })).filter((s) => s.event);\n if (steps.length < 2) fail(ExitCode.USAGE, 'define --kind funnel needs --steps a,b,c (>=2)');\n spec = { v: 1, kind: 'funnel', name: (flags.name as string) ?? 'funnel', steps, scope: (flags.scope as string) ?? 'within-session', ...(flags.window ? { window: flags.window as string } : {}) };\n } else if (flags.kind === 'metric') {\n spec = { v: 1, kind: 'metric', name: (flags.name as string) ?? 'metric', aggregate: (flags.aggregate as string) ?? 'count', bucket: (flags.bucket as string) ?? 'day', ...(flags.event ? { event: flags.event as string } : {}) };\n } else {\n const raw = flags.file ? readFileSync(flags.file as string, 'utf8') : readFileSync(0, 'utf8');\n spec = JSON.parse(raw);\n }\n const res = await api.request('POST', '/v1/definitions', { spec });\n return ok(res);\n}\n\nexport async function tokens(action: string, flags: Flags, positionals: string[] = []): Promise<never> {\n const { api } = authedApi(flags);\n if (action === 'list') return ok(await api.request('GET', '/v1/tokens'));\n if (action === 'create') {\n let budget: number | undefined;\n if (flags['budget-r2sql']) {\n // Accept human units + an optional `/day` rate suffix (`1GB/day`).\n const parsed = parseBytes(String(flags['budget-r2sql']));\n if (parsed == null) fail(ExitCode.USAGE, `invalid --budget-r2sql: ${flags['budget-r2sql']} (try 1GB/day)`);\n budget = parsed;\n }\n const res = await api.request<{ id: string; token: string; prefix: string }>('POST', '/v1/tokens', {\n name: (flags.name as string) ?? 'agent',\n role: (flags.role as string) ?? 'read',\n ...(budget != null ? { budget_r2sql_bytes_per_day: budget } : {}),\n });\n // The secret is shown ONCE — print it verbatim (not through the redactor).\n return ok(res, () => {\n process.stdout.write(`Created token ${res.id}\\n\\n ${res.token}\\n\\nThis is shown once. Store it now (e.g. as GLASS_TOKEN).\\n`);\n });\n }\n if (action === 'revoke') {\n // Accept both `glass tokens revoke <id>` and `--id <id>`.\n const id = (flags.id as string | undefined) ?? positionals[0];\n if (!id) fail(ExitCode.USAGE, 'tokens revoke needs a token id: `glass tokens revoke <id>`');\n return ok(await api.request('DELETE', `/v1/tokens/${id}`));\n }\n return fail(ExitCode.USAGE, 'tokens <list|create|revoke>');\n}\n","/**\n * Stable, scriptable output (`CLI.md` §5). The CLI is built for agents as much\n * as humans: `--json` emits a uniform envelope and EXIT CODES are stable so a\n * caller can branch on them without parsing prose.\n */\n\nexport const ExitCode = {\n OK: 0,\n ERROR: 1,\n USAGE: 2,\n AUTH: 3,\n COST_GATE: 4,\n BUDGET: 5,\n} as const;\nexport type ExitCodeValue = (typeof ExitCode)[keyof typeof ExitCode];\n\ntype OutputFormat = 'human' | 'json' | 'csv' | 'ndjson';\nlet format: OutputFormat = 'human';\nexport function setFormat(f: OutputFormat): void {\n format = f;\n}\n/** Back-compat shim for `--json`. */\nexport function setJsonMode(on: boolean): void {\n if (on) format = 'json';\n}\n\n/** Mask token-like secrets in human output so they're never accidentally logged. */\nconst SECRET_RE =\n /\\b(glass_(?:sk|pt)_[A-Za-z0-9]+)\\b|\\b(eyJ[A-Za-z0-9_-]{10,}\\.[A-Za-z0-9_-]{10,}\\.[A-Za-z0-9_-]{10,})\\b/g;\nexport function redact(text: string): string {\n return text.replace(SECRET_RE, (m) => `${m.slice(0, 12)}…<redacted>`);\n}\n\n/** Flatten an array of flat records to CSV; falls back to JSON for non-tabular data. */\nexport function toCsv(data: unknown): string | null {\n const rows = Array.isArray(data) ? data : extractRows(data);\n if (!rows || rows.length === 0) return null;\n const cols = [...new Set(rows.flatMap((r) => Object.keys(r)))];\n const esc = (v: unknown) => {\n const s = v == null ? '' : typeof v === 'object' ? JSON.stringify(v) : String(v);\n return /[\",\\n]/.test(s) ? `\"${s.replace(/\"/g, '\"\"')}\"` : s;\n };\n return [\n cols.join(','),\n ...rows.map((r) => cols.map((c) => esc((r as Record<string, unknown>)[c])).join(',')),\n ].join('\\n');\n}\n\n/**\n * Parse a human byte budget into bytes (`CLI.md` §4): accepts plain numbers and\n * unit suffixes (`500MB`, `1GB`, `2 TiB`), with an optional `/day` rate suffix\n * that we strip (the API stores per-day budgets). Returns null on garbage.\n */\nconst BYTE_UNITS: Record<string, number> = {\n b: 1,\n kb: 1e3,\n mb: 1e6,\n gb: 1e9,\n tb: 1e12,\n kib: 1024,\n mib: 1024 ** 2,\n gib: 1024 ** 3,\n tib: 1024 ** 4,\n};\nexport function parseBytes(input: string): number | null {\n const s = input.trim().toLowerCase().replace(/\\/(day|d|hr|hour|h)$/, '');\n const m = /^([0-9]*\\.?[0-9]+)\\s*([a-z]+)?$/.exec(s);\n if (!m) return null;\n const value = Number(m[1]);\n if (!Number.isFinite(value)) return null;\n if (!m[2]) return value; // bare number = bytes\n const unit = BYTE_UNITS[m[2]];\n if (!unit) return null;\n return Math.round(value * unit);\n}\n\n/** Find the first array-of-objects field (e.g. {rows:[...]}, {issues:[...]}). */\nexport function extractRows(data: unknown): Record<string, unknown>[] | null {\n if (Array.isArray(data)) return data as Record<string, unknown>[];\n if (data && typeof data === 'object') {\n for (const v of Object.values(data)) {\n if (Array.isArray(v) && v.every((x) => x && typeof x === 'object'))\n return v as Record<string, unknown>[];\n }\n }\n return null;\n}\n\n/**\n * Render an array of flat records as an aligned ASCII table for human output.\n * Returns null when the data isn't tabular so callers can fall back to JSON.\n */\nexport function humanTable(data: unknown): string | null {\n const rows = extractRows(data);\n if (!rows || rows.length === 0) return null;\n const cols = [...new Set(rows.flatMap((r) => Object.keys(r)))];\n if (cols.length === 0) return null;\n const cell = (v: unknown) => {\n const s = v == null ? '' : typeof v === 'object' ? JSON.stringify(v) : String(v);\n return redact(s).replace(/\\n/g, ' ');\n };\n const widths = cols.map((c) =>\n Math.max(c.length, ...rows.map((r) => cell((r as Record<string, unknown>)[c]).length)),\n );\n const line = (cells: string[]) => cells.map((s, i) => s.padEnd(widths[i] ?? 0)).join(' ').trimEnd();\n const header = line(cols);\n const sep = widths.map((w) => '-'.repeat(w)).join(' ');\n const body = rows.map((r) => line(cols.map((c) => cell((r as Record<string, unknown>)[c]))));\n return [header, sep, ...body].join('\\n');\n}\n\n/**\n * One-line provenance badge for a query result (`UI.md` ResultBadge parity):\n * surfaces whether a number is exact or sampled, and its source, so an agent\n * reading stdout knows how much to trust it. Returns null when not applicable.\n */\nexport function resultBadge(data: unknown): string | null {\n if (!data || typeof data !== 'object') return null;\n const d = data as Record<string, unknown>;\n if (typeof d.exact !== 'boolean' && !d.source && !d.sampled) return null;\n const parts: string[] = [];\n parts.push(d.exact === false ? 'sampled' : 'exact');\n if (d.source) parts.push(String(d.source));\n const sampled = d.sampled as { interval?: number } | undefined;\n if (sampled?.interval && sampled.interval > 1) parts.push(`1/${sampled.interval}`);\n return `[${parts.join(' · ')}]`;\n}\n\nexport function ok(data: unknown, human?: () => void): never {\n if (format === 'json') {\n process.stdout.write(`${JSON.stringify({ ok: true, data }, null, 2)}\\n`);\n } else if (format === 'ndjson') {\n const rows = extractRows(data) ?? [data];\n for (const r of rows) process.stdout.write(`${JSON.stringify(r)}\\n`);\n } else if (format === 'csv') {\n const csv = toCsv(data);\n process.stdout.write(csv ? `${csv}\\n` : `${JSON.stringify(data, null, 2)}\\n`);\n } else if (human) {\n human();\n } else {\n const table = humanTable(data);\n if (table) {\n const badge = resultBadge(data);\n process.stdout.write(`${table}\\n`);\n if (badge) process.stdout.write(`${badge}\\n`);\n } else {\n process.stdout.write(`${redact(JSON.stringify(data, null, 2))}\\n`);\n }\n }\n process.exit(ExitCode.OK);\n}\n\nexport function fail(code: ExitCodeValue, message: string, extra?: unknown): never {\n if (format === 'json' || format === 'ndjson') {\n process.stdout.write(\n `${JSON.stringify({ ok: false, error: { code, message, ...(extra ? { extra } : {}) } }, null, 2)}\\n`,\n );\n } else {\n process.stderr.write(`glass: ${message}\\n`);\n if (extra) process.stderr.write(`${redact(JSON.stringify(extra, null, 2))}\\n`);\n }\n process.exit(code);\n}\n","import { ExitCode, fail } from './output.js';\n\n/**\n * Thin control-plane client. Maps HTTP status to the CLI's stable exit codes so\n * `--json` callers (agents) can branch deterministically (`CLI.md` §5):\n * 401/403 → AUTH(3), 402 → COST_GATE(4), 429 → BUDGET(5).\n */\nexport class Api {\n constructor(\n private apiHost: string,\n private token?: string,\n private projectId?: string,\n ) {}\n\n async request<T = unknown>(method: string, path: string, body?: unknown): Promise<T> {\n const headers: Record<string, string> = { 'Content-Type': 'application/json' };\n if (this.token) headers.Authorization = `Bearer ${this.token}`;\n if (this.projectId) headers['X-Glass-Project'] = this.projectId;\n\n const res = await fetch(`${this.apiHost}${path}`, {\n method,\n headers,\n ...(body !== undefined ? { body: JSON.stringify(body) } : {}),\n }).catch((e) => fail(ExitCode.ERROR, `network error: ${String(e)}`));\n\n const text = await res.text();\n const json = text ? (JSON.parse(text) as T) : ({} as T);\n\n if (res.status === 401 || res.status === 403) fail(ExitCode.AUTH, 'unauthorized', json);\n if (res.status === 402) fail(ExitCode.COST_GATE, 'cost gate: re-run with --confirm', json);\n if (res.status === 429) fail(ExitCode.BUDGET, 'budget or rate limit exceeded', json);\n if (!res.ok) fail(ExitCode.ERROR, `request failed (${res.status})`, json);\n return json;\n }\n}\n","import { chmodSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { dirname, join } from 'node:path';\n\n/**\n * Local config (`CLI.md` §2/§3). Project pointer in `glass.json` (committable,\n * contains only the write-only publishable key); SECRETS in\n * `~/.glass/credentials.json` with `0600` perms, never in the repo.\n */\n\nexport interface ProjectFile {\n project_id: string;\n ingest_key: string;\n ingest_host: string;\n api_host: string;\n /** The claim URL minted at provisioning (single-use); shown by `glass claim`. */\n claim_url?: string;\n}\n\nexport interface Credentials {\n /** provisioning/agent tokens keyed by project_id. */\n tokens: Record<string, string>;\n /** Clerk session from `glass login` (device flow). */\n session?: string;\n}\n\nconst PROJECT_FILE = join(process.cwd(), 'glass.json');\nconst CRED_FILE = join(homedir(), '.glass', 'credentials.json');\n\n/**\n * Read the project pointer, with environment overrides layered on top\n * (`CLI.md` §2): `GLASS_PROJECT` selects/overrides the project id and\n * `GLASS_INGEST_KEY` the publishable key — so CI can run without a committed\n * `glass.json`. If neither the file nor `GLASS_PROJECT` is present, returns null.\n */\nexport function readProject(): ProjectFile | null {\n let file: ProjectFile | null = null;\n try {\n file = JSON.parse(readFileSync(PROJECT_FILE, 'utf8')) as ProjectFile;\n } catch {\n file = null;\n }\n\n const envProject = process.env.GLASS_PROJECT;\n const envIngest = process.env.GLASS_INGEST_KEY;\n if (!file && !envProject) return null;\n\n return {\n project_id: envProject ?? file?.project_id ?? '',\n ingest_key: envIngest ?? file?.ingest_key ?? '',\n ingest_host: process.env.GLASS_INGEST_HOST ?? file?.ingest_host ?? 'https://in.glass.dev',\n api_host: process.env.GLASS_API_HOST ?? file?.api_host ?? 'https://api.glass.dev',\n ...(file?.claim_url ? { claim_url: file.claim_url } : {}),\n };\n}\n\nexport function writeProject(p: ProjectFile): void {\n writeFileSync(PROJECT_FILE, `${JSON.stringify(p, null, 2)}\\n`);\n}\n\nexport function readCredentials(): Credentials {\n try {\n return JSON.parse(readFileSync(CRED_FILE, 'utf8')) as Credentials;\n } catch {\n return { tokens: {} };\n }\n}\n\nexport function writeCredentials(c: Credentials): void {\n mkdirSync(dirname(CRED_FILE), { recursive: true, mode: 0o700 });\n writeFileSync(CRED_FILE, `${JSON.stringify(c, null, 2)}\\n`, { mode: 0o600 });\n chmodSync(CRED_FILE, 0o600); // enforce even if the file pre-existed\n}\n\nexport function tokenFor(projectId: string): string | undefined {\n return readCredentials().tokens[projectId];\n}\n"],"mappings":"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","names":["readFileSync","writeFileSync","dirname","readFileSync","dirname","writeFileSync","query"]} |
+1
-1
| { | ||
| "name": "@glassanalytics/cli", | ||
| "version": "0.1.0", | ||
| "version": "0.1.1", | ||
| "description": "Glass CLI — zero-auth provisioning, SDK install, and typed querying from the terminal. Agent-friendly: --json + stable exit codes.", | ||
@@ -5,0 +5,0 @@ "license": "Apache-2.0", |
89131
0.08%