agent-insights 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cli.ts","../src/commands/cursor.ts","../src/config/config.ts","../src/config/paths.ts","../src/privacy/sanitize.ts","../src/util/identity.ts","../src/privacy/hash.ts","../src/util/log.ts","../src/commands/disable.ts","../src/adapters/claude-code.ts","../src/adapters/cursor.ts","../src/adapters/registry.ts","../src/commands/doctor.ts","../src/transcript/store.ts","../src/commands/hook.ts","../src/commands/init.ts","../src/commands/status.ts"],"sourcesContent":["import { Command } from \"commander\";\nimport { runCursorWrapper } from \"./commands/cursor.js\";\nimport { runDisable } from \"./commands/disable.js\";\nimport { runDoctor } from \"./commands/doctor.js\";\nimport { runHook } from \"./commands/hook.js\";\nimport { runInit } from \"./commands/init.js\";\nimport { runStatus } from \"./commands/status.js\";\nimport { log } from \"./util/log.js\";\n\nconst VERSION = \"0.0.1\";\n\nconst program = new Command();\n\nprogram\n .name(\"agent-insights\")\n .description(\n \"Internal CLI for AI coding agent observability (Claude Code, Cursor).\",\n )\n .version(VERSION);\n\nprogram\n .command(\"init\")\n .description(\"Set up agent-insights in this repo.\")\n .option(\n \"--agents <list>\",\n \"Comma-separated agent ids (claude-code,cursor)\",\n \"claude-code,cursor\",\n )\n .option(\"--transcripts\", \"Opt into transcript sync to Vercel Blob\")\n .option(\"--no-transcripts\", \"Skip transcript sync\")\n .option(\"--analysis\", \"Opt into SessionEnd analysis (Phase 2)\")\n .option(\"--telemetry\", \"Opt into OTLP event telemetry (Phase 3)\")\n .option(\"--no-hooks\", \"Skip installing per-agent hooks\")\n .option(\"--force\", \"Overwrite existing config\")\n .action(async (opts) => {\n await runInit(opts);\n });\n\nprogram\n .command(\"status\")\n .description(\"Show current config, consent, and adapter state.\")\n .option(\"--json\", \"Emit machine-readable JSON\")\n .action(async (opts) => {\n await runStatus(opts);\n });\n\nprogram\n .command(\"doctor\")\n .description(\"Verify config, Vercel link, Blob, and per-agent hook install.\")\n .option(\"--json\", \"Emit machine-readable JSON\")\n .action(async (opts) => {\n await runDoctor(opts);\n });\n\nprogram\n .command(\"disable\")\n .description(\"Disable agent-insights and/or remove installed hooks.\")\n .option(\"--agent <name>\", \"Disable a specific adapter (claude-code|cursor)\")\n .option(\"--purge\", \"Also delete the local config and caches\")\n .action(async (opts) => {\n await runDisable(opts);\n });\n\nprogram\n .command(\"hook <eventName>\")\n .description(\"Internal: invoked by an agent's hook configuration.\")\n .option(\"--agent <name>\", \"Override agent inference (claude-code|cursor)\")\n .action(async (eventName: string, opts: { agent?: string }) => {\n await runHook(eventName, opts);\n });\n\nprogram\n .command(\"cursor [path]\")\n .description(\"Launch Cursor with session start/end emitted (fallback).\")\n .action(async (path: string | undefined) => {\n await runCursorWrapper({ ...(path !== undefined ? { path } : {}) });\n });\n\nprogram.parseAsync(process.argv).catch((err: unknown) => {\n log.fail((err as Error).message ?? String(err));\n process.exit(1);\n});\n","import { spawn } from \"node:child_process\";\nimport { randomUUID } from \"node:crypto\";\nimport { loadConfig } from \"../config/config.js\";\nimport { sanitize } from \"../privacy/sanitize.js\";\nimport type { AgentEvent } from \"../types.js\";\nimport { repoHash, userHash, workspaceHash } from \"../util/identity.js\";\nimport { debug, log } from \"../util/log.js\";\n\nexport type CursorOptions = {\n path?: string;\n};\n\n/**\n * Wrapper for launching Cursor when native hooks aren't installed yet.\n * Emits session.start / session.end without prompts or tool inputs.\n */\nexport async function runCursorWrapper(opts: CursorOptions): Promise<void> {\n const cfg = await loadConfig();\n if (!cfg) {\n log.fail(\"agent-insights is not initialized — run `agent-insights init`\");\n process.exitCode = 1;\n return;\n }\n const path = opts.path ?? process.cwd();\n const sessionId = randomUUID();\n\n const baseEvent = {\n agent: \"cursor\" as const,\n sessionId,\n userHash: userHash(),\n repoHash: repoHash(),\n workspaceHash: workspaceHash(),\n };\n\n emit({\n ...baseEvent,\n type: \"session.start\",\n timestamp: new Date().toISOString(),\n });\n\n const code = await spawnCursor(path);\n\n emit({\n ...baseEvent,\n type: \"session.end\",\n timestamp: new Date().toISOString(),\n outcome: code === 0 ? \"success\" : \"error\",\n });\n\n process.exitCode = code;\n}\n\nfunction spawnCursor(path: string): Promise<number> {\n return new Promise((resolve) => {\n const child = spawn(\"cursor\", [path], {\n stdio: \"inherit\",\n env: process.env,\n });\n child.on(\"error\", (err) => {\n log.fail(`failed to launch cursor: ${err.message}`);\n resolve(127);\n });\n child.on(\"exit\", (code) => resolve(code ?? 0));\n });\n}\n\nfunction emit(event: AgentEvent): void {\n debug(\"cursor wrapper event\", {\n type: event.type,\n sessionId: event.sessionId,\n });\n // Phase 3 (OTLP) will export sanitized events here.\n void sanitize(event);\n}\n","import { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport { dirname } from \"node:path\";\nimport { configFile, logsDir, sessionCacheDir } from \"./paths.js\";\n\nexport type ExporterConfig = {\n type: \"otlp\";\n endpoint: string;\n headers: Record<string, string>;\n dataset: string;\n};\n\nexport type TranscriptStoreConfig =\n | {\n type: \"blob\";\n tokenEnv: string;\n prefix: string;\n }\n | {\n type: \"none\";\n };\n\nexport type SessionAnalysisConfig = {\n /** Server-side enablement; user opts in via `userConsent.sessionAnalysis`. */\n enabled: boolean;\n /** Analyzer endpoint base URL. CLI POSTs to `${analyzerUrl}/api/sessions`. */\n analyzerUrl: string;\n /** Env var name holding an optional shared secret. Sent as `x-agent-insights-secret`. */\n secretEnv: string;\n /** GitHub repo for pre-filled new-issue URLs (display only; constructed by analyzer). */\n githubIssueRepo: string;\n};\n\nexport type AgentConfig = {\n enabled: boolean;\n};\n\nexport type AgentInsightsConfig = {\n version: 1;\n enabled: boolean;\n vercel: {\n team: string;\n project: string;\n };\n userConsent: {\n eventTelemetry: boolean;\n transcriptSync: boolean;\n sessionAnalysis: boolean;\n };\n exporter: ExporterConfig;\n transcriptStore: TranscriptStoreConfig;\n sessionAnalysis: SessionAnalysisConfig;\n agents: Record<\"claudeCode\" | \"cursor\", AgentConfig>;\n privacy: {\n capturePrompts: false;\n captureMessages: false;\n captureToolInputs: false;\n captureFileContents: false;\n };\n};\n\nexport function defaultConfig(): AgentInsightsConfig {\n return {\n version: 1,\n enabled: true,\n vercel: {\n team: \"vercel-labs\",\n project: \"agent-insights\",\n },\n userConsent: {\n eventTelemetry: false,\n transcriptSync: false,\n sessionAnalysis: false,\n },\n exporter: {\n type: \"otlp\",\n endpoint: process.env.AGENT_INSIGHTS_OTEL_ENDPOINT ?? \"\",\n headers: {},\n dataset: \"agent-insights\",\n },\n transcriptStore: {\n type: \"blob\",\n tokenEnv: \"BLOB_READ_WRITE_TOKEN\",\n prefix: \"sessions/\",\n },\n sessionAnalysis: {\n enabled: false,\n analyzerUrl: process.env.AGENT_INSIGHTS_ANALYZER_URL ?? \"\",\n secretEnv: \"AGENT_INSIGHTS_INGEST_SECRET\",\n githubIssueRepo: \"vercel-labs/agent-insights\",\n },\n agents: {\n claudeCode: { enabled: false },\n cursor: { enabled: false },\n },\n privacy: {\n capturePrompts: false,\n captureMessages: false,\n captureToolInputs: false,\n captureFileContents: false,\n },\n };\n}\n\nexport async function loadConfig(): Promise<AgentInsightsConfig | undefined> {\n try {\n const raw = await readFile(configFile(), \"utf8\");\n const parsed = JSON.parse(raw) as Partial<AgentInsightsConfig>;\n return mergeConfig(defaultConfig(), parsed);\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === \"ENOENT\") return undefined;\n throw err;\n }\n}\n\nexport async function saveConfig(cfg: AgentInsightsConfig): Promise<void> {\n await ensureDirs();\n await writeFile(configFile(), `${JSON.stringify(cfg, null, 2)}\\n`, \"utf8\");\n}\n\nexport async function ensureDirs(): Promise<void> {\n await mkdir(dirname(configFile()), { recursive: true });\n await mkdir(sessionCacheDir(), { recursive: true });\n await mkdir(logsDir(), { recursive: true });\n}\n\nfunction mergeConfig(\n base: AgentInsightsConfig,\n patch: Partial<AgentInsightsConfig>,\n): AgentInsightsConfig {\n return {\n ...base,\n ...patch,\n vercel: { ...base.vercel, ...(patch.vercel ?? {}) },\n userConsent: { ...base.userConsent, ...(patch.userConsent ?? {}) },\n exporter: { ...base.exporter, ...(patch.exporter ?? {}) },\n transcriptStore: (patch.transcriptStore ??\n base.transcriptStore) as TranscriptStoreConfig,\n sessionAnalysis: {\n ...base.sessionAnalysis,\n ...(patch.sessionAnalysis ?? {}),\n },\n agents: {\n claudeCode: {\n ...base.agents.claudeCode,\n ...(patch.agents?.claudeCode ?? {}),\n },\n cursor: { ...base.agents.cursor, ...(patch.agents?.cursor ?? {}) },\n },\n privacy: base.privacy,\n };\n}\n","import { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\n/** Root directory for agent-insights state. Honors `AGENT_INSIGHTS_HOME`. */\nexport function configRoot(): string {\n return process.env.AGENT_INSIGHTS_HOME ?? join(homedir(), \".agent-insights\");\n}\n\nexport function configFile(): string {\n return join(configRoot(), \"config.json\");\n}\n\nexport function sessionCacheDir(): string {\n return join(configRoot(), \"session-cache\");\n}\n\nexport function logsDir(): string {\n return join(configRoot(), \"logs\");\n}\n\nexport const CLAUDE_SETTINGS_FILE = \".claude/settings.json\";\nexport const CURSOR_HOOKS_FILE = \".cursor/hooks.json\";\n","/**\n * Keys that must never appear in any payload that leaves the machine.\n *\n * Matching is case-insensitive and snake_case/camelCase agnostic — we strip a\n * key if its normalized form equals one of these values.\n */\nconst FORBIDDEN_KEYS: ReadonlySet<string> = new Set([\n \"prompt\",\n \"prompts\",\n \"message\",\n \"messages\",\n \"content\",\n \"text\",\n \"transcript\",\n \"toolinput\",\n \"input\",\n \"arguments\",\n \"args\",\n \"params\",\n \"file\",\n \"filecontent\",\n \"filecontents\",\n \"diff\",\n \"patch\",\n \"secret\",\n \"secrets\",\n \"token\",\n \"apikey\",\n \"authorization\",\n \"password\",\n \"credentials\",\n]);\n\nconst MAX_STRING_LENGTH = 256;\n\n/** Allowed primitive value types in sanitized metadata. */\nexport type SanitizedPrimitive = string | number | boolean | null;\n\nfunction normalizeKey(key: string): string {\n return key.toLowerCase().replace(/[_\\-\\s]/g, \"\");\n}\n\nfunction truncate(value: string): string {\n if (value.length <= MAX_STRING_LENGTH) return value;\n return `${value.slice(0, MAX_STRING_LENGTH)}…[truncated]`;\n}\n\nfunction sanitizePrimitive(value: unknown): SanitizedPrimitive | undefined {\n if (value === null) return null;\n switch (typeof value) {\n case \"string\":\n return truncate(value);\n case \"number\":\n return Number.isFinite(value) ? value : null;\n case \"boolean\":\n return value;\n default:\n return undefined;\n }\n}\n\n/**\n * Recursively remove forbidden keys from an arbitrary payload.\n *\n * Returned shape:\n * - Objects keep allowed primitive fields (truncated to {@link MAX_STRING_LENGTH}).\n * - Arrays keep allowed primitive elements; nested objects/arrays are recursed.\n * - Non-primitive, non-container values (functions, symbols, Buffers, …) are dropped.\n */\nexport function sanitize(input: unknown): unknown {\n return sanitizeInner(input);\n}\n\nfunction sanitizeInner(value: unknown): unknown {\n if (Array.isArray(value)) {\n const out: unknown[] = [];\n for (const item of value) {\n const sanitizedItem = sanitizeInner(item);\n if (sanitizedItem !== undefined) {\n out.push(sanitizedItem);\n }\n }\n return out;\n }\n\n if (value && typeof value === \"object\") {\n const out: Record<string, unknown> = {};\n for (const [rawKey, rawValue] of Object.entries(value)) {\n if (FORBIDDEN_KEYS.has(normalizeKey(rawKey))) {\n continue;\n }\n if (rawValue && typeof rawValue === \"object\") {\n out[rawKey] = sanitizeInner(rawValue);\n } else {\n const primitive = sanitizePrimitive(rawValue);\n if (primitive !== undefined) {\n out[rawKey] = primitive;\n }\n }\n }\n return out;\n }\n\n return sanitizePrimitive(value);\n}\n\nexport const __testing = { FORBIDDEN_KEYS, normalizeKey };\n","import { execSync } from \"node:child_process\";\nimport { hostname, userInfo } from \"node:os\";\nimport { sha256 } from \"../privacy/hash.js\";\n\n/** Stable hashed identity of the local user. */\nexport function userHash(): string {\n try {\n const user = userInfo().username;\n return sha256(`${user}@${hostname()}`);\n } catch {\n return sha256(\"unknown\");\n }\n}\n\n/**\n * Stable hashed identity of a repository, derived from `git remote get-url\n * origin` when available, else from `cwd`.\n */\nexport function repoHash(cwd: string = process.cwd()): string {\n const remote = tryGit([\"config\", \"--get\", \"remote.origin.url\"], cwd);\n return sha256(remote ?? cwd);\n}\n\n/** Stable hashed identity of the workspace path. */\nexport function workspaceHash(cwd: string = process.cwd()): string {\n return sha256(cwd);\n}\n\nfunction tryGit(args: string[], cwd: string): string | undefined {\n try {\n const out = execSync(`git ${args.join(\" \")}`, {\n cwd,\n stdio: [\"ignore\", \"pipe\", \"ignore\"],\n encoding: \"utf8\",\n timeout: 1500,\n });\n const trimmed = out.trim();\n return trimmed === \"\" ? undefined : trimmed;\n } catch {\n return undefined;\n }\n}\n","import { createHash } from \"node:crypto\";\n\n/**\n * Stable SHA-256 hash of a value, hex-encoded.\n *\n * Used to anonymize usernames, repo remote URLs, workspace paths, and\n * session identifiers before they leave the machine.\n */\nexport function sha256(value: string): string {\n return createHash(\"sha256\").update(value, \"utf8\").digest(\"hex\");\n}\n\n/** Short prefix of `sha256(value)` for human-readable dashboards. */\nexport function shortHash(value: string, length = 12): string {\n return sha256(value).slice(0, length);\n}\n","import kleur from \"kleur\";\n\nexport const log = {\n info: (msg: string): void => {\n process.stdout.write(`${msg}\\n`);\n },\n ok: (msg: string): void => {\n process.stdout.write(`${kleur.green(\"✓\")} ${msg}\\n`);\n },\n warn: (msg: string): void => {\n process.stdout.write(`${kleur.yellow(\"!\")} ${msg}\\n`);\n },\n fail: (msg: string): void => {\n process.stderr.write(`${kleur.red(\"✗\")} ${msg}\\n`);\n },\n hint: (msg: string): void => {\n process.stdout.write(`${kleur.dim(msg)}\\n`);\n },\n json: (obj: unknown): void => {\n process.stdout.write(`${JSON.stringify(obj, null, 2)}\\n`);\n },\n};\n\nexport function debug(msg: string, extra?: Record<string, unknown>): void {\n if (process.env.AGENT_INSIGHTS_DEBUG) {\n const payload = extra ? ` ${JSON.stringify(extra)}` : \"\";\n process.stderr.write(`[agent-insights] ${msg}${payload}\\n`);\n }\n}\n","import { rm } from \"node:fs/promises\";\nimport { adapterList } from \"../adapters/registry.js\";\nimport { loadConfig, saveConfig } from \"../config/config.js\";\nimport { configRoot } from \"../config/paths.js\";\nimport { log } from \"../util/log.js\";\nimport type { AgentId } from \"../adapters/types.js\";\n\nexport type DisableOptions = {\n agent?: string;\n purge?: boolean;\n};\n\nexport async function runDisable(opts: DisableOptions): Promise<void> {\n const repoRoot = process.cwd();\n const targets = opts.agent ? [opts.agent] : adapterList.map((a) => a.id);\n\n for (const id of targets) {\n if (id !== \"claude-code\" && id !== \"cursor\") {\n log.warn(`Unknown agent id \"${id}\"`);\n continue;\n }\n const adapter = adapterList.find((a) => a.id === (id as AgentId));\n if (!adapter) continue;\n const { removed, path } = await adapter.uninstall(repoRoot);\n if (removed) log.ok(`Removed ${adapter.label} hooks from ${path}`);\n else log.hint(`${adapter.label}: no hooks to remove (${path})`);\n }\n\n const cfg = await loadConfig();\n if (cfg) {\n if (!opts.agent || opts.agent === \"claude-code\") {\n cfg.agents.claudeCode.enabled = false;\n }\n if (!opts.agent || opts.agent === \"cursor\") {\n cfg.agents.cursor.enabled = false;\n }\n if (!opts.agent) cfg.enabled = false;\n await saveConfig(cfg);\n }\n\n if (opts.purge) {\n await rm(configRoot(), { recursive: true, force: true });\n log.ok(`Purged ${configRoot()}`);\n }\n}\n","import { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport { dirname, join } from \"node:path\";\nimport type { AgentEventType } from \"../types.js\";\nimport type { Adapter, HookPayload, MappedEvent } from \"./types.js\";\n\nconst HOOK_COMMAND_NAME = \"agent-insights\";\n\nconst HOOK_MAP: Record<string, AgentEventType> = {\n SessionStart: \"session.start\",\n SessionEnd: \"session.end\",\n UserPromptSubmit: \"user.prompt.submit\",\n PreToolUse: \"tool.start\",\n PostToolUse: \"tool.end\",\n PostToolUseFailure: \"tool.failure\",\n PermissionRequest: \"permission.request\",\n PermissionDenied: \"permission.denied\",\n SubagentStart: \"subagent.start\",\n SubagentStop: \"subagent.end\",\n Stop: \"agent.stop\",\n Notification: \"notification\",\n PreCompact: \"context.compact.start\",\n PostCompact: \"context.compact.end\",\n};\n\nexport const CLAUDE_HOOK_EVENTS: ReadonlyArray<string> = Object.keys(HOOK_MAP);\n\ntype ClaudeHookEntry = {\n type: \"command\";\n command: string;\n};\n\ntype ClaudeSettings = {\n hooks?: Record<string, ClaudeHookEntry[]>;\n [key: string]: unknown;\n};\n\nexport const claudeCodeAdapter: Adapter = {\n id: \"claude-code\",\n agent: \"claude-code\",\n label: \"Claude Code\",\n settingsFile: \".claude/settings.json\",\n\n map(payload: HookPayload): MappedEvent | undefined {\n const type = HOOK_MAP[payload.event];\n if (!type) return undefined;\n\n const data = payload.data ?? {};\n const sessionId =\n asString(data[\"session_id\"]) ?? asString(data[\"sessionId\"]);\n const toolName =\n asString(data[\"tool_name\"]) ??\n asString(data[\"toolName\"]) ??\n asString((data[\"tool\"] as Record<string, unknown> | undefined)?.[\"name\"]);\n const transcriptPath =\n asString(data[\"transcript_path\"]) ?? asString(data[\"transcriptPath\"]);\n\n return {\n type,\n ...(sessionId !== undefined ? { sessionId } : {}),\n ...(toolName !== undefined ? { toolName } : {}),\n ...(transcriptPath !== undefined ? { transcriptPath } : {}),\n };\n },\n\n async install(repoRoot: string) {\n const path = join(repoRoot, \".claude/settings.json\");\n const settings = await readJson<ClaudeSettings>(path);\n const next: ClaudeSettings = { ...(settings ?? {}) };\n const hooks: Record<string, ClaudeHookEntry[]> = { ...(next.hooks ?? {}) };\n\n for (const event of CLAUDE_HOOK_EVENTS) {\n const existing = (hooks[event] ?? []).filter(\n (h) => !isAgentInsightsCommand(h.command),\n );\n existing.push({\n type: \"command\",\n command: `${HOOK_COMMAND_NAME} hook ${event}`,\n });\n hooks[event] = existing;\n }\n\n next.hooks = hooks;\n await mkdir(dirname(path), { recursive: true });\n await writeFile(path, `${JSON.stringify(next, null, 2)}\\n`, \"utf8\");\n return { written: true, path };\n },\n\n async uninstall(repoRoot: string) {\n const path = join(repoRoot, \".claude/settings.json\");\n const settings = await readJson<ClaudeSettings>(path);\n if (!settings?.hooks) return { removed: false, path };\n const hooks = { ...settings.hooks };\n let touched = false;\n for (const [event, entries] of Object.entries(hooks)) {\n const filtered = entries.filter(\n (h) => !isAgentInsightsCommand(h.command),\n );\n if (filtered.length !== entries.length) touched = true;\n if (filtered.length === 0) {\n delete hooks[event];\n } else {\n hooks[event] = filtered;\n }\n }\n settings.hooks = hooks;\n await writeFile(path, `${JSON.stringify(settings, null, 2)}\\n`, \"utf8\");\n return { removed: touched, path };\n },\n\n async isInstalled(repoRoot: string) {\n const settings = await readJson<ClaudeSettings>(\n join(repoRoot, \".claude/settings.json\"),\n );\n if (!settings?.hooks) return false;\n return Object.values(settings.hooks).some((entries) =>\n entries.some((h) => isAgentInsightsCommand(h.command)),\n );\n },\n};\n\nfunction isAgentInsightsCommand(cmd: string | undefined): boolean {\n if (!cmd) return false;\n return cmd.startsWith(`${HOOK_COMMAND_NAME} hook`);\n}\n\nasync function readJson<T>(path: string): Promise<T | undefined> {\n try {\n const raw = await readFile(path, \"utf8\");\n return JSON.parse(raw) as T;\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === \"ENOENT\") return undefined;\n throw err;\n }\n}\n\nfunction asString(v: unknown): string | undefined {\n return typeof v === \"string\" && v.length > 0 ? v : undefined;\n}\n","import { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport { dirname, join } from \"node:path\";\nimport type { AgentEventType } from \"../types.js\";\nimport type { Adapter, HookPayload, MappedEvent } from \"./types.js\";\n\nconst HOOK_COMMAND_NAME = \"agent-insights\";\n\n/**\n * Cursor hook names → common schema. Confirm against current Cursor docs when\n * implementing; align with Claude where event names match.\n */\nconst HOOK_MAP: Record<string, AgentEventType> = {\n SessionStart: \"session.start\",\n SessionEnd: \"session.end\",\n UserPromptSubmit: \"user.prompt.submit\",\n PreToolUse: \"tool.start\",\n PostToolUse: \"tool.end\",\n Stop: \"agent.stop\",\n};\n\nexport const CURSOR_HOOK_EVENTS: ReadonlyArray<string> = Object.keys(HOOK_MAP);\n\ntype CursorHookEntry = {\n command: string;\n};\n\ntype CursorHooksConfig = {\n hooks?: Record<string, CursorHookEntry[]>;\n [key: string]: unknown;\n};\n\nexport const cursorAdapter: Adapter = {\n id: \"cursor\",\n agent: \"cursor\",\n label: \"Cursor\",\n settingsFile: \".cursor/hooks.json\",\n\n map(payload: HookPayload): MappedEvent | undefined {\n const type = HOOK_MAP[payload.event];\n if (!type) return undefined;\n\n const data = payload.data ?? {};\n const sessionId =\n asString(data[\"session_id\"]) ?? asString(data[\"sessionId\"]);\n const toolName = asString(data[\"tool_name\"]) ?? asString(data[\"toolName\"]);\n const transcriptPath =\n asString(data[\"transcript_path\"]) ?? asString(data[\"transcriptPath\"]);\n\n return {\n type,\n ...(sessionId !== undefined ? { sessionId } : {}),\n ...(toolName !== undefined ? { toolName } : {}),\n ...(transcriptPath !== undefined ? { transcriptPath } : {}),\n };\n },\n\n async install(repoRoot: string) {\n const path = join(repoRoot, \".cursor/hooks.json\");\n const settings = await readJson<CursorHooksConfig>(path);\n const next: CursorHooksConfig = { ...(settings ?? {}) };\n const hooks: Record<string, CursorHookEntry[]> = { ...(next.hooks ?? {}) };\n\n for (const event of CURSOR_HOOK_EVENTS) {\n const existing = (hooks[event] ?? []).filter(\n (h) => !isAgentInsightsCommand(h.command),\n );\n existing.push({ command: `${HOOK_COMMAND_NAME} hook ${event}` });\n hooks[event] = existing;\n }\n\n next.hooks = hooks;\n await mkdir(dirname(path), { recursive: true });\n await writeFile(path, `${JSON.stringify(next, null, 2)}\\n`, \"utf8\");\n return { written: true, path };\n },\n\n async uninstall(repoRoot: string) {\n const path = join(repoRoot, \".cursor/hooks.json\");\n const settings = await readJson<CursorHooksConfig>(path);\n if (!settings?.hooks) return { removed: false, path };\n const hooks = { ...settings.hooks };\n let touched = false;\n for (const [event, entries] of Object.entries(hooks)) {\n const filtered = entries.filter(\n (h) => !isAgentInsightsCommand(h.command),\n );\n if (filtered.length !== entries.length) touched = true;\n if (filtered.length === 0) {\n delete hooks[event];\n } else {\n hooks[event] = filtered;\n }\n }\n settings.hooks = hooks;\n await writeFile(path, `${JSON.stringify(settings, null, 2)}\\n`, \"utf8\");\n return { removed: touched, path };\n },\n\n async isInstalled(repoRoot: string) {\n const settings = await readJson<CursorHooksConfig>(\n join(repoRoot, \".cursor/hooks.json\"),\n );\n if (!settings?.hooks) return false;\n return Object.values(settings.hooks).some((entries) =>\n entries.some((h) => isAgentInsightsCommand(h.command)),\n );\n },\n};\n\nfunction isAgentInsightsCommand(cmd: string | undefined): boolean {\n if (!cmd) return false;\n return cmd.startsWith(`${HOOK_COMMAND_NAME} hook`);\n}\n\nasync function readJson<T>(path: string): Promise<T | undefined> {\n try {\n const raw = await readFile(path, \"utf8\");\n return JSON.parse(raw) as T;\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === \"ENOENT\") return undefined;\n throw err;\n }\n}\n\nfunction asString(v: unknown): string | undefined {\n return typeof v === \"string\" && v.length > 0 ? v : undefined;\n}\n","import { claudeCodeAdapter } from \"./claude-code.js\";\nimport { cursorAdapter } from \"./cursor.js\";\nimport type { Adapter, AgentId } from \"./types.js\";\n\nexport const adapters: Record<AgentId, Adapter> = {\n \"claude-code\": claudeCodeAdapter,\n cursor: cursorAdapter,\n};\n\nexport const adapterList: ReadonlyArray<Adapter> = Object.values(adapters);\n\nexport function getAdapter(id: AgentId): Adapter {\n return adapters[id];\n}\n","import { existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport kleur from \"kleur\";\nimport { adapterList } from \"../adapters/registry.js\";\nimport { loadConfig } from \"../config/config.js\";\nimport { configFile } from \"../config/paths.js\";\nimport { createTranscriptStore } from \"../transcript/store.js\";\nimport { log } from \"../util/log.js\";\n\nexport type DoctorOptions = {\n json?: boolean;\n};\n\ntype Check = {\n name: string;\n ok: boolean;\n detail?: string;\n};\n\nexport async function runDoctor(opts: DoctorOptions): Promise<void> {\n const repoRoot = process.cwd();\n const checks: Check[] = [];\n\n const cfg = await loadConfig();\n checks.push({\n name: \"config found\",\n ok: cfg != null,\n detail: cfg ? configFile() : `missing ${configFile()}`,\n });\n\n if (cfg) {\n checks.push({\n name: \"vercel project linked\",\n ok: existsSync(join(repoRoot, \".vercel/project.json\")),\n detail: \"run `vercel link --scope vercel-labs --project agent-insights`\",\n });\n\n if (cfg.userConsent.transcriptSync) {\n try {\n const store = createTranscriptStore(cfg.transcriptStore);\n const ping = await store.ping();\n if (ping.ok) {\n checks.push({ name: \"transcript store reachable\", ok: true });\n } else {\n checks.push({\n name: \"transcript store reachable\",\n ok: false,\n detail: ping.reason,\n });\n }\n } catch (err) {\n checks.push({\n name: \"transcript store reachable\",\n ok: false,\n detail: (err as Error).message,\n });\n }\n }\n\n for (const adapter of adapterList) {\n const enabled =\n adapter.id === \"claude-code\"\n ? cfg.agents.claudeCode.enabled\n : cfg.agents.cursor.enabled;\n if (!enabled) continue;\n const installed = await adapter.isInstalled(repoRoot);\n checks.push({\n name: `${adapter.label} hooks installed`,\n ok: installed,\n detail: installed\n ? join(repoRoot, adapter.settingsFile)\n : \"run `agent-insights init`\",\n });\n }\n }\n\n if (opts.json) {\n log.json({ ok: checks.every((c) => c.ok), checks });\n } else {\n for (const c of checks) {\n const tag = c.ok ? kleur.green(\"✓\") : kleur.red(\"✗\");\n const detail = c.detail ? kleur.dim(` (${c.detail})`) : \"\";\n log.info(`${tag} ${c.name}${detail}`);\n }\n }\n\n process.exitCode = checks.every((c) => c.ok) ? 0 : 1;\n}\n","import { readFile } from \"node:fs/promises\";\nimport { put } from \"@vercel/blob\";\nimport type { TranscriptStoreConfig } from \"../config/config.js\";\n\nexport type TranscriptUploadInput = {\n /** Absolute path on disk to the transcript file. */\n transcriptPath: string;\n /** SHA256-hashed user identifier. Used in the upload pathname. */\n userHash: string;\n /** Session identifier supplied by the agent. */\n sessionId: string;\n /** Agent name (e.g. \"claude-code\"). */\n agent: string;\n};\n\nexport type TranscriptUploadResult = {\n pathname: string;\n url: string;\n size: number;\n};\n\nexport interface TranscriptStore {\n upload(input: TranscriptUploadInput): Promise<TranscriptUploadResult>;\n /** Lightweight health check used by `doctor`. */\n ping(): Promise<{ ok: true } | { ok: false; reason: string }>;\n}\n\nclass NoopTranscriptStore implements TranscriptStore {\n async upload(): Promise<TranscriptUploadResult> {\n throw new Error(\"transcript store disabled (transcriptStore.type=none)\");\n }\n async ping(): Promise<{ ok: false; reason: string }> {\n return { ok: false, reason: \"transcript store disabled\" };\n }\n}\n\nclass BlobTranscriptStore implements TranscriptStore {\n constructor(\n private readonly token: string,\n private readonly prefix: string,\n ) {}\n\n async upload(input: TranscriptUploadInput): Promise<TranscriptUploadResult> {\n const body = await readFile(input.transcriptPath);\n const requestedPath = buildPathname(\n this.prefix,\n input.userHash,\n input.sessionId,\n );\n // addRandomSuffix avoids guessable URLs: transcripts contain prompts and\n // tool inputs, so URL knowledge is the only access control until we move\n // to private blobs + signed reads.\n const blob = await put(requestedPath, body, {\n access: \"public\",\n token: this.token,\n contentType: \"application/jsonl\",\n addRandomSuffix: true,\n });\n return { pathname: blob.pathname, url: blob.url, size: body.byteLength };\n }\n\n async ping(): Promise<{ ok: true } | { ok: false; reason: string }> {\n if (!this.token) return { ok: false, reason: \"missing token\" };\n return { ok: true };\n }\n}\n\nexport function createTranscriptStore(\n cfg: TranscriptStoreConfig,\n): TranscriptStore {\n if (cfg.type === \"none\") return new NoopTranscriptStore();\n const token = process.env[cfg.tokenEnv];\n if (!token) {\n throw new Error(\n `transcript store: env ${cfg.tokenEnv} is not set (run 'vercel env pull .env.local')`,\n );\n }\n return new BlobTranscriptStore(token, cfg.prefix);\n}\n\nfunction buildPathname(\n prefix: string,\n userHash: string,\n sessionId: string,\n): string {\n const safePrefix = prefix.endsWith(\"/\") ? prefix : `${prefix}/`;\n const safeSession = encodeURIComponent(sessionId);\n return `${safePrefix}${userHash}/${safeSession}/transcript.jsonl`;\n}\n","import { adapterList } from \"../adapters/registry.js\";\nimport { loadConfig } from \"../config/config.js\";\nimport { sanitize } from \"../privacy/sanitize.js\";\nimport { createTranscriptStore } from \"../transcript/store.js\";\nimport type { Adapter, AgentId, HookPayload } from \"../adapters/types.js\";\nimport type { AgentEvent } from \"../types.js\";\nimport { repoHash, userHash, workspaceHash } from \"../util/identity.js\";\nimport { debug, log } from \"../util/log.js\";\n\nexport type HookOptions = {\n agent?: string;\n};\n\n/**\n * Hook entrypoint. Reads JSON payload from stdin, resolves the adapter, maps\n * the native event into the common schema, and runs transcript upload on\n * session.end. Never fails the hook — errors are logged, exit code is 0.\n */\nexport async function runHook(\n eventName: string,\n opts: HookOptions,\n): Promise<void> {\n const cfg = await loadConfig();\n if (!cfg || !cfg.enabled) {\n debug(\"hook skipped — agent-insights not enabled\");\n return;\n }\n\n const stdin = await readStdinSafely();\n const data = parseJsonObject(stdin);\n const payload: HookPayload = { event: eventName, data };\n\n const adapter = pickAdapter(opts.agent, eventName);\n if (!adapter) {\n debug(`no adapter resolved for event ${eventName}`);\n return;\n }\n\n const mapped = adapter.map(payload);\n if (!mapped) {\n debug(`adapter ${adapter.id} did not map event ${eventName}`);\n return;\n }\n\n const event = buildEvent(adapter, mapped);\n debug(\"hook event\", {\n agent: event.agent,\n type: event.type,\n sessionId: event.sessionId,\n });\n\n if (\n mapped.type === \"session.end\" &&\n cfg.userConsent.transcriptSync &&\n mapped.transcriptPath\n ) {\n try {\n const store = createTranscriptStore(cfg.transcriptStore);\n const result = await store.upload({\n transcriptPath: mapped.transcriptPath,\n userHash: event.userHash ?? userHash(),\n sessionId: mapped.sessionId ?? \"unknown\",\n agent: adapter.id,\n });\n debug(\"transcript uploaded\", {\n size: result.size,\n pathname: result.pathname,\n });\n\n if (\n cfg.userConsent.sessionAnalysis &&\n cfg.sessionAnalysis.analyzerUrl\n ) {\n await notifyAnalyzer({\n analyzerUrl: cfg.sessionAnalysis.analyzerUrl,\n secretEnv: cfg.sessionAnalysis.secretEnv,\n payload: {\n sessionId: mapped.sessionId ?? \"unknown\",\n agent: adapter.id,\n userHash: event.userHash ?? userHash(),\n blobUrl: result.url,\n timestamp: event.timestamp,\n },\n });\n }\n } catch (err) {\n log.fail(`transcript upload failed: ${(err as Error).message}`);\n }\n }\n\n // Phase 3 (OTLP) will export `event` here.\n void sanitize(event);\n}\n\ntype AnalyzerPayload = {\n sessionId: string;\n agent: string;\n userHash: string;\n blobUrl: string;\n timestamp: string;\n};\n\nasync function notifyAnalyzer(opts: {\n analyzerUrl: string;\n secretEnv: string;\n payload: AnalyzerPayload;\n}): Promise<void> {\n try {\n const headers: Record<string, string> = {\n \"content-type\": \"application/json\",\n };\n const secret = process.env[opts.secretEnv];\n if (secret) headers[\"x-agent-insights-secret\"] = secret;\n\n const url = new URL(\"/api/sessions\", opts.analyzerUrl).toString();\n const res = await fetch(url, {\n method: \"POST\",\n headers,\n body: JSON.stringify(opts.payload),\n });\n if (!res.ok) {\n debug(`analyzer notify failed: ${res.status} ${res.statusText}`);\n return;\n }\n debug(\"analyzer notified\", { sessionId: opts.payload.sessionId });\n } catch (err) {\n // Never fail the hook because of analyzer issues.\n debug(`analyzer notify error: ${(err as Error).message}`);\n }\n}\n\nfunction pickAdapter(\n override: string | undefined,\n eventName: string,\n): Adapter | undefined {\n if (override) {\n return adapterList.find((a) => a.id === override);\n }\n for (const a of adapterList) {\n if (a.map({ event: eventName })) return a;\n }\n return undefined;\n}\n\nfunction buildEvent(\n adapter: { id: AgentId; agent: AgentEvent[\"agent\"] },\n mapped: NonNullable<ReturnType<Adapter[\"map\"]>>,\n): AgentEvent {\n return {\n type: mapped.type,\n agent: adapter.agent,\n timestamp: new Date().toISOString(),\n ...(mapped.sessionId !== undefined ? { sessionId: mapped.sessionId } : {}),\n ...(mapped.toolName !== undefined ? { toolName: mapped.toolName } : {}),\n ...(mapped.permissionType !== undefined\n ? { permissionType: mapped.permissionType }\n : {}),\n ...(mapped.outcome !== undefined ? { outcome: mapped.outcome } : {}),\n userHash: userHash(),\n repoHash: repoHash(),\n workspaceHash: workspaceHash(),\n };\n}\n\n/**\n * Read stdin if data is available. Returns an empty string when stdin is a\n * TTY or when nothing arrives within `STDIN_TIMEOUT_MS`. Hooks invoked\n * without piped JSON should never hang.\n */\nconst STDIN_TIMEOUT_MS = 200;\n\nasync function readStdinSafely(): Promise<string> {\n if (process.stdin.isTTY) return \"\";\n return new Promise<string>((resolve) => {\n let buf = \"\";\n let settled = false;\n const finish = (): void => {\n if (settled) return;\n settled = true;\n process.stdin.removeAllListeners(\"data\");\n process.stdin.removeAllListeners(\"end\");\n process.stdin.removeAllListeners(\"error\");\n // Release the event loop — `setEncoding` + 'data' listener cause Node\n // to keep reading stdin even after we've stopped listening.\n try {\n process.stdin.pause();\n process.stdin.unref();\n } catch {\n // ignore — stdin may already be destroyed\n }\n resolve(buf);\n };\n const idle = setTimeout(finish, STDIN_TIMEOUT_MS);\n idle.unref();\n process.stdin.setEncoding(\"utf8\");\n process.stdin.on(\"data\", (chunk) => {\n buf += chunk;\n idle.refresh();\n });\n process.stdin.on(\"end\", () => {\n clearTimeout(idle);\n finish();\n });\n process.stdin.on(\"error\", () => {\n clearTimeout(idle);\n finish();\n });\n });\n}\n\nfunction parseJsonObject(raw: string): Record<string, unknown> | undefined {\n if (!raw) return undefined;\n try {\n const parsed = JSON.parse(raw) as unknown;\n if (parsed && typeof parsed === \"object\" && !Array.isArray(parsed)) {\n return parsed as Record<string, unknown>;\n }\n return undefined;\n } catch {\n return undefined;\n }\n}\n","import { existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport kleur from \"kleur\";\nimport { adapterList } from \"../adapters/registry.js\";\nimport {\n defaultConfig,\n loadConfig,\n saveConfig,\n type AgentInsightsConfig,\n} from \"../config/config.js\";\nimport { configFile, configRoot } from \"../config/paths.js\";\nimport { log } from \"../util/log.js\";\n\nexport type InitOptions = {\n agents?: string;\n transcripts?: boolean;\n analysis?: boolean;\n telemetry?: boolean;\n force?: boolean;\n hooks?: boolean;\n};\n\nconst CONSENT_TEXT = `\\\nAgent Insights is opt-in (internal).\n\nOTLP / lifecycle metrics: event names, timestamps, tool names, outcomes,\nhashed user/repo/workspace IDs — never prompts, messages, or tool inputs.\n\nVercel Blob (optional): full session transcripts for internal analysis;\nusername stored as SHA256 only.\n\nSessionEnd analysis (optional): an internal LLM reviews transcript for\ntooling gaps; may post to Slack with a GitHub issue link.\\\n`;\n\nexport async function runInit(opts: InitOptions): Promise<void> {\n log.info(kleur.bold(\"Agent Insights setup\\n\"));\n log.hint(CONSENT_TEXT);\n log.info(\"\");\n\n const existing = await loadConfig();\n if (existing && !opts.force) {\n log.warn(\n `Config already exists at ${configFile()} — re-run with --force to overwrite.`,\n );\n }\n\n const requested = parseAgents(opts.agents);\n const cfg: AgentInsightsConfig = existing ?? defaultConfig();\n\n cfg.userConsent.transcriptSync = opts.transcripts ?? true;\n cfg.userConsent.sessionAnalysis = opts.analysis ?? false;\n cfg.userConsent.eventTelemetry = opts.telemetry ?? false;\n\n cfg.agents.claudeCode.enabled = requested.has(\"claude-code\");\n cfg.agents.cursor.enabled = requested.has(\"cursor\");\n\n await saveConfig(cfg);\n log.ok(`Wrote config to ${configFile()}`);\n\n const installHooks = opts.hooks ?? true;\n const repoRoot = process.cwd();\n if (installHooks) {\n for (const adapter of adapterList) {\n const enabled =\n (adapter.id === \"claude-code\" && cfg.agents.claudeCode.enabled) ||\n (adapter.id === \"cursor\" && cfg.agents.cursor.enabled);\n if (!enabled) continue;\n const { path } = await adapter.install(repoRoot);\n log.ok(`Installed ${adapter.label} hooks → ${rel(path)}`);\n }\n }\n\n printVercelHint(repoRoot);\n log.info(\"\");\n log.info(`Config root: ${configRoot()}`);\n log.hint(\"Run `agent-insights doctor` to verify the setup.\");\n}\n\nfunction parseAgents(value: string | undefined): Set<\"claude-code\" | \"cursor\"> {\n const out = new Set<\"claude-code\" | \"cursor\">();\n const list = (value ?? \"claude-code,cursor\")\n .split(\",\")\n .map((s) => s.trim())\n .filter(Boolean);\n for (const id of list) {\n if (id === \"claude-code\" || id === \"cursor\") out.add(id);\n else log.warn(`Unknown agent id \"${id}\" — skipping.`);\n }\n return out;\n}\n\nfunction printVercelHint(repoRoot: string): void {\n const linked = existsSync(join(repoRoot, \".vercel/project.json\"));\n const envFile = existsSync(join(repoRoot, \".env.local\"));\n\n if (!linked) {\n log.hint(\n \"Vercel project not linked. Run `vercel link --scope vercel-labs --project agent-insights`.\",\n );\n }\n if (!envFile) {\n log.hint(\n \"No .env.local found. Run `vercel env pull .env.local` to fetch BLOB_READ_WRITE_TOKEN.\",\n );\n }\n}\n\nfunction rel(p: string): string {\n const cwd = process.cwd();\n return p.startsWith(cwd) ? p.slice(cwd.length + 1) : p;\n}\n","import { existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport kleur from \"kleur\";\nimport { adapterList } from \"../adapters/registry.js\";\nimport { loadConfig } from \"../config/config.js\";\nimport { configFile } from \"../config/paths.js\";\nimport { log } from \"../util/log.js\";\n\nexport type StatusOptions = {\n json?: boolean;\n};\n\nexport async function runStatus(opts: StatusOptions): Promise<void> {\n const cfg = await loadConfig();\n const repoRoot = process.cwd();\n\n if (!cfg) {\n if (opts.json) log.json({ initialized: false });\n else log.warn(`No config found at ${configFile()} — run \\`agent-insights init\\`.`);\n return;\n }\n\n const adapterStatus = await Promise.all(\n adapterList.map(async (a) => ({\n id: a.id,\n label: a.label,\n enabled:\n a.id === \"claude-code\"\n ? cfg.agents.claudeCode.enabled\n : cfg.agents.cursor.enabled,\n installed: await a.isInstalled(repoRoot),\n })),\n );\n\n if (opts.json) {\n log.json({\n initialized: true,\n configPath: configFile(),\n enabled: cfg.enabled,\n consent: cfg.userConsent,\n vercel: {\n linked: existsSync(join(repoRoot, \".vercel/project.json\")),\n envFile: existsSync(join(repoRoot, \".env.local\")),\n },\n adapters: adapterStatus,\n });\n return;\n }\n\n log.info(kleur.bold(\"Agent Insights status\\n\"));\n log.info(`config ${configFile()}`);\n log.info(`enabled ${cfg.enabled ? \"yes\" : \"no\"}`);\n log.info(\"\");\n log.info(kleur.bold(\"Consent\"));\n log.info(` event telemetry ${yn(cfg.userConsent.eventTelemetry)}`);\n log.info(` transcript sync ${yn(cfg.userConsent.transcriptSync)}`);\n log.info(` session analysis ${yn(cfg.userConsent.sessionAnalysis)}`);\n log.info(\"\");\n log.info(kleur.bold(\"Adapters\"));\n for (const a of adapterStatus) {\n log.info(\n ` ${a.label.padEnd(12)} ${a.enabled ? \"enabled\" : \"disabled\"} hooks ${\n a.installed ? \"installed\" : \"not installed\"\n }`,\n );\n }\n log.info(\"\");\n log.info(kleur.bold(\"Vercel\"));\n log.info(\n ` linked ${yn(existsSync(join(repoRoot, \".vercel/project.json\")))}`,\n );\n log.info(` .env.local ${yn(existsSync(join(repoRoot, \".env.local\")))}`);\n}\n\nfunction yn(v: boolean): string {\n return v ? kleur.green(\"yes\") : kleur.dim(\"no\");\n}\n"],"mappings":"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","names":["mkdir","readFile","writeFile","dirname","join","mkdir","readFile","writeFile","dirname","join","HOOK_COMMAND_NAME","HOOK_MAP","asString","readJson","isAgentInsightsCommand","join","kleur","readFile","userHash","join","kleur","existsSync","join","kleur","kleur","existsSync","join","existsSync","join","kleur","existsSync","join","kleur"]}
@@ -0,0 +1,156 @@
1
+ type AgentName = "claude-code" | "cursor" | "opencode" | "codex" | "unknown";
2
+ type AgentEventType = "session.start" | "session.end" | "user.prompt.submit" | "tool.start" | "tool.end" | "tool.failure" | "permission.request" | "permission.denied" | "subagent.start" | "subagent.end" | "agent.stop" | "notification" | "context.compact.start" | "context.compact.end" | "error";
3
+ type AgentOutcome = "success" | "error" | "cancelled" | "unknown";
4
+ type AgentEvent = {
5
+ type: AgentEventType;
6
+ agent: AgentName;
7
+ timestamp: string;
8
+ sessionId?: string;
9
+ userHash?: string;
10
+ repoHash?: string;
11
+ workspaceHash?: string;
12
+ toolName?: string;
13
+ permissionType?: string;
14
+ outcome?: AgentOutcome;
15
+ metadata?: Record<string, string | number | boolean | null>;
16
+ };
17
+ type SessionGapType = "missing_skill" | "missing_tool" | "repeated_failure" | "wrong_info";
18
+
19
+ /**
20
+ * Stable SHA-256 hash of a value, hex-encoded.
21
+ *
22
+ * Used to anonymize usernames, repo remote URLs, workspace paths, and
23
+ * session identifiers before they leave the machine.
24
+ */
25
+ declare function sha256(value: string): string;
26
+ /** Short prefix of `sha256(value)` for human-readable dashboards. */
27
+ declare function shortHash(value: string, length?: number): string;
28
+
29
+ /**
30
+ * Recursively remove forbidden keys from an arbitrary payload.
31
+ *
32
+ * Returned shape:
33
+ * - Objects keep allowed primitive fields (truncated to {@link MAX_STRING_LENGTH}).
34
+ * - Arrays keep allowed primitive elements; nested objects/arrays are recursed.
35
+ * - Non-primitive, non-container values (functions, symbols, Buffers, …) are dropped.
36
+ */
37
+ declare function sanitize(input: unknown): unknown;
38
+
39
+ type AgentId = "claude-code" | "cursor";
40
+ type HookPayload = {
41
+ /** Native event name as emitted by the agent (e.g. `SessionStart`). */
42
+ event: string;
43
+ /** Parsed JSON body of the hook stdin (may be undefined for empty stdin). */
44
+ data?: Record<string, unknown> | undefined;
45
+ };
46
+ type MappedEvent = {
47
+ type: AgentEventType;
48
+ sessionId?: string;
49
+ toolName?: string;
50
+ permissionType?: string;
51
+ outcome?: AgentEvent["outcome"];
52
+ /** Absolute path to a session transcript file, if the hook exposed one. */
53
+ transcriptPath?: string;
54
+ };
55
+ type Adapter = {
56
+ id: AgentId;
57
+ agent: AgentName;
58
+ label: string;
59
+ settingsFile: string;
60
+ map(payload: HookPayload): MappedEvent | undefined;
61
+ install(repoRoot: string): Promise<{
62
+ written: boolean;
63
+ path: string;
64
+ }>;
65
+ uninstall(repoRoot: string): Promise<{
66
+ removed: boolean;
67
+ path: string;
68
+ }>;
69
+ isInstalled(repoRoot: string): Promise<boolean>;
70
+ };
71
+
72
+ declare const adapters: Record<AgentId, Adapter>;
73
+ declare const adapterList: ReadonlyArray<Adapter>;
74
+ declare function getAdapter(id: AgentId): Adapter;
75
+
76
+ type ExporterConfig = {
77
+ type: "otlp";
78
+ endpoint: string;
79
+ headers: Record<string, string>;
80
+ dataset: string;
81
+ };
82
+ type TranscriptStoreConfig = {
83
+ type: "blob";
84
+ tokenEnv: string;
85
+ prefix: string;
86
+ } | {
87
+ type: "none";
88
+ };
89
+ type SessionAnalysisConfig = {
90
+ /** Server-side enablement; user opts in via `userConsent.sessionAnalysis`. */
91
+ enabled: boolean;
92
+ /** Analyzer endpoint base URL. CLI POSTs to `${analyzerUrl}/api/sessions`. */
93
+ analyzerUrl: string;
94
+ /** Env var name holding an optional shared secret. Sent as `x-agent-insights-secret`. */
95
+ secretEnv: string;
96
+ /** GitHub repo for pre-filled new-issue URLs (display only; constructed by analyzer). */
97
+ githubIssueRepo: string;
98
+ };
99
+ type AgentConfig = {
100
+ enabled: boolean;
101
+ };
102
+ type AgentInsightsConfig = {
103
+ version: 1;
104
+ enabled: boolean;
105
+ vercel: {
106
+ team: string;
107
+ project: string;
108
+ };
109
+ userConsent: {
110
+ eventTelemetry: boolean;
111
+ transcriptSync: boolean;
112
+ sessionAnalysis: boolean;
113
+ };
114
+ exporter: ExporterConfig;
115
+ transcriptStore: TranscriptStoreConfig;
116
+ sessionAnalysis: SessionAnalysisConfig;
117
+ agents: Record<"claudeCode" | "cursor", AgentConfig>;
118
+ privacy: {
119
+ capturePrompts: false;
120
+ captureMessages: false;
121
+ captureToolInputs: false;
122
+ captureFileContents: false;
123
+ };
124
+ };
125
+ declare function defaultConfig(): AgentInsightsConfig;
126
+ declare function loadConfig(): Promise<AgentInsightsConfig | undefined>;
127
+ declare function saveConfig(cfg: AgentInsightsConfig): Promise<void>;
128
+
129
+ type TranscriptUploadInput = {
130
+ /** Absolute path on disk to the transcript file. */
131
+ transcriptPath: string;
132
+ /** SHA256-hashed user identifier. Used in the upload pathname. */
133
+ userHash: string;
134
+ /** Session identifier supplied by the agent. */
135
+ sessionId: string;
136
+ /** Agent name (e.g. "claude-code"). */
137
+ agent: string;
138
+ };
139
+ type TranscriptUploadResult = {
140
+ pathname: string;
141
+ url: string;
142
+ size: number;
143
+ };
144
+ interface TranscriptStore {
145
+ upload(input: TranscriptUploadInput): Promise<TranscriptUploadResult>;
146
+ /** Lightweight health check used by `doctor`. */
147
+ ping(): Promise<{
148
+ ok: true;
149
+ } | {
150
+ ok: false;
151
+ reason: string;
152
+ }>;
153
+ }
154
+ declare function createTranscriptStore(cfg: TranscriptStoreConfig): TranscriptStore;
155
+
156
+ export { type Adapter, type AgentEvent, type AgentEventType, type AgentId, type AgentInsightsConfig, type AgentName, type AgentOutcome, type ExporterConfig, type HookPayload, type MappedEvent, type SessionAnalysisConfig, type SessionGapType, type TranscriptStore, type TranscriptStoreConfig, type TranscriptUploadInput, type TranscriptUploadResult, adapterList, adapters, createTranscriptStore, defaultConfig, getAdapter, loadConfig, sanitize, saveConfig, sha256, shortHash };