@fml-inc/panopticon 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (124) hide show
  1. package/.claude-plugin/plugin.json +10 -0
  2. package/LICENSE +5 -0
  3. package/README.md +363 -0
  4. package/bin/hook-handler +3 -0
  5. package/bin/mcp-server +3 -0
  6. package/bin/panopticon +3 -0
  7. package/bin/proxy +3 -0
  8. package/bin/server +3 -0
  9. package/dist/api/client.d.ts +67 -0
  10. package/dist/api/client.js +48 -0
  11. package/dist/api/client.js.map +1 -0
  12. package/dist/chunk-3BUJ7URA.js +387 -0
  13. package/dist/chunk-3BUJ7URA.js.map +1 -0
  14. package/dist/chunk-3TZAKV3M.js +158 -0
  15. package/dist/chunk-3TZAKV3M.js.map +1 -0
  16. package/dist/chunk-4SM2H22C.js +169 -0
  17. package/dist/chunk-4SM2H22C.js.map +1 -0
  18. package/dist/chunk-7Q3BJMLG.js +62 -0
  19. package/dist/chunk-7Q3BJMLG.js.map +1 -0
  20. package/dist/chunk-BVOE7A2Z.js +412 -0
  21. package/dist/chunk-BVOE7A2Z.js.map +1 -0
  22. package/dist/chunk-CF4GPWLI.js +170 -0
  23. package/dist/chunk-CF4GPWLI.js.map +1 -0
  24. package/dist/chunk-DZ5HJFB4.js +467 -0
  25. package/dist/chunk-DZ5HJFB4.js.map +1 -0
  26. package/dist/chunk-HQCY722C.js +428 -0
  27. package/dist/chunk-HQCY722C.js.map +1 -0
  28. package/dist/chunk-HRCEIYKU.js +134 -0
  29. package/dist/chunk-HRCEIYKU.js.map +1 -0
  30. package/dist/chunk-K7YUPLES.js +76 -0
  31. package/dist/chunk-K7YUPLES.js.map +1 -0
  32. package/dist/chunk-L7G27XWF.js +130 -0
  33. package/dist/chunk-L7G27XWF.js.map +1 -0
  34. package/dist/chunk-LWXF7YRG.js +626 -0
  35. package/dist/chunk-LWXF7YRG.js.map +1 -0
  36. package/dist/chunk-NXH7AONS.js +1120 -0
  37. package/dist/chunk-NXH7AONS.js.map +1 -0
  38. package/dist/chunk-QK5442ZP.js +55 -0
  39. package/dist/chunk-QK5442ZP.js.map +1 -0
  40. package/dist/chunk-QVK6VGCV.js +1703 -0
  41. package/dist/chunk-QVK6VGCV.js.map +1 -0
  42. package/dist/chunk-RX2RXHBH.js +1699 -0
  43. package/dist/chunk-RX2RXHBH.js.map +1 -0
  44. package/dist/chunk-SEXU2WYG.js +788 -0
  45. package/dist/chunk-SEXU2WYG.js.map +1 -0
  46. package/dist/chunk-SUGSQ4YI.js +264 -0
  47. package/dist/chunk-SUGSQ4YI.js.map +1 -0
  48. package/dist/chunk-TGXFVAID.js +138 -0
  49. package/dist/chunk-TGXFVAID.js.map +1 -0
  50. package/dist/chunk-WLBNFVIG.js +447 -0
  51. package/dist/chunk-WLBNFVIG.js.map +1 -0
  52. package/dist/chunk-XLTCUH5A.js +1072 -0
  53. package/dist/chunk-XLTCUH5A.js.map +1 -0
  54. package/dist/chunk-YVRWVDIA.js +146 -0
  55. package/dist/chunk-YVRWVDIA.js.map +1 -0
  56. package/dist/chunk-ZEC4LRKS.js +176 -0
  57. package/dist/chunk-ZEC4LRKS.js.map +1 -0
  58. package/dist/cli.d.ts +1 -0
  59. package/dist/cli.js +1084 -0
  60. package/dist/cli.js.map +1 -0
  61. package/dist/config-NwoZC-GM.d.ts +20 -0
  62. package/dist/db.d.ts +46 -0
  63. package/dist/db.js +15 -0
  64. package/dist/db.js.map +1 -0
  65. package/dist/doctor.d.ts +37 -0
  66. package/dist/doctor.js +14 -0
  67. package/dist/doctor.js.map +1 -0
  68. package/dist/hooks/handler.d.ts +23 -0
  69. package/dist/hooks/handler.js +295 -0
  70. package/dist/hooks/handler.js.map +1 -0
  71. package/dist/index.d.ts +57 -0
  72. package/dist/index.js +101 -0
  73. package/dist/index.js.map +1 -0
  74. package/dist/mcp/server.d.ts +1 -0
  75. package/dist/mcp/server.js +243 -0
  76. package/dist/mcp/server.js.map +1 -0
  77. package/dist/otlp/server.d.ts +7 -0
  78. package/dist/otlp/server.js +17 -0
  79. package/dist/otlp/server.js.map +1 -0
  80. package/dist/permissions.d.ts +33 -0
  81. package/dist/permissions.js +14 -0
  82. package/dist/permissions.js.map +1 -0
  83. package/dist/pricing.d.ts +29 -0
  84. package/dist/pricing.js +13 -0
  85. package/dist/pricing.js.map +1 -0
  86. package/dist/proxy/server.d.ts +10 -0
  87. package/dist/proxy/server.js +20 -0
  88. package/dist/proxy/server.js.map +1 -0
  89. package/dist/prune.d.ts +18 -0
  90. package/dist/prune.js +13 -0
  91. package/dist/prune.js.map +1 -0
  92. package/dist/query.d.ts +56 -0
  93. package/dist/query.js +27 -0
  94. package/dist/query.js.map +1 -0
  95. package/dist/reparse-636YZCE3.js +14 -0
  96. package/dist/reparse-636YZCE3.js.map +1 -0
  97. package/dist/repo.d.ts +17 -0
  98. package/dist/repo.js +9 -0
  99. package/dist/repo.js.map +1 -0
  100. package/dist/scanner.d.ts +73 -0
  101. package/dist/scanner.js +15 -0
  102. package/dist/scanner.js.map +1 -0
  103. package/dist/sdk.d.ts +82 -0
  104. package/dist/sdk.js +208 -0
  105. package/dist/sdk.js.map +1 -0
  106. package/dist/server.d.ts +5 -0
  107. package/dist/server.js +25 -0
  108. package/dist/server.js.map +1 -0
  109. package/dist/setup.d.ts +35 -0
  110. package/dist/setup.js +19 -0
  111. package/dist/setup.js.map +1 -0
  112. package/dist/sync/index.d.ts +29 -0
  113. package/dist/sync/index.js +32 -0
  114. package/dist/sync/index.js.map +1 -0
  115. package/dist/targets.d.ts +279 -0
  116. package/dist/targets.js +20 -0
  117. package/dist/targets.js.map +1 -0
  118. package/dist/types-D-MYCBol.d.ts +128 -0
  119. package/dist/types.d.ts +164 -0
  120. package/dist/types.js +1 -0
  121. package/dist/types.js.map +1 -0
  122. package/hooks/hooks.json +274 -0
  123. package/package.json +124 -0
  124. package/skills/panopticon-optimize/SKILL.md +222 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/otlp/server.ts","../src/otlp/proto.ts","../src/otlp/decode-logs.ts","../src/otlp/decode-metrics.ts","../src/otlp/decode-traces.ts"],"sourcesContent":["import http from \"node:http\";\nimport { config } from \"../config.js\";\nimport { refreshIfStale } from \"../db/pricing.js\";\nimport {\n insertOtelLogs,\n insertOtelMetrics,\n insertOtelSpans,\n upsertSession,\n} from \"../db/store.js\";\nimport { log } from \"../log.js\";\nimport { captureException } from \"../sentry.js\";\nimport { allTargets } from \"../targets/index.js\";\nimport { decodeLogs } from \"./decode-logs.js\";\nimport { decodeMetrics } from \"./decode-metrics.js\";\nimport { decodeTraces } from \"./decode-traces.js\";\nimport {\n ExportLogsServiceResponse,\n ExportMetricsServiceResponse,\n ExportTracesServiceResponse,\n} from \"./proto.js\";\n\nfunction collectBody(req: http.IncomingMessage): Promise<Buffer> {\n return new Promise((resolve, reject) => {\n const chunks: Buffer[] = [];\n req.on(\"data\", (chunk: Buffer) => chunks.push(chunk));\n req.on(\"end\", () => resolve(Buffer.concat(chunks)));\n req.on(\"error\", reject);\n });\n}\n\n/** Map from OTel service.name to target ID, built lazily from target registry. */\nlet _serviceNameMap: Map<string, string> | null = null;\nfunction serviceNameMap(): Map<string, string> {\n if (!_serviceNameMap) {\n _serviceNameMap = new Map();\n for (const t of allTargets()) {\n if (t.otel?.serviceName) {\n _serviceNameMap.set(t.otel.serviceName, t.id);\n }\n }\n }\n return _serviceNameMap;\n}\n\n/**\n * Create/enrich session rows from OTLP data. Derives:\n * - target from service.name mapping\n * - started_at_ms from earliest timestamp in the batch\n * - otel_* token columns from token metric values\n * - model from metric attributes\n */\nfunction ensureSessionsFromOtel(\n rows: Array<{\n session_id?: string;\n timestamp_ns?: number;\n resource_attributes?: Record<string, unknown>;\n name?: string;\n value?: number;\n attributes?: Record<string, unknown>;\n }>,\n): void {\n const sessions = new Map<\n string,\n {\n target?: string;\n minTimestampMs?: number;\n model?: string;\n otelInput: number;\n otelOutput: number;\n otelCacheRead: number;\n otelCacheCreation: number;\n }\n >();\n\n for (const row of rows) {\n const sid = row.session_id;\n if (!sid) continue;\n\n if (!sessions.has(sid)) {\n const serviceName = row.resource_attributes?.[\"service.name\"];\n const target =\n typeof serviceName === \"string\"\n ? serviceNameMap().get(serviceName)\n : undefined;\n sessions.set(sid, {\n target,\n otelInput: 0,\n otelOutput: 0,\n otelCacheRead: 0,\n otelCacheCreation: 0,\n });\n }\n\n const sess = sessions.get(sid)!;\n\n // Derive timing from earliest timestamp\n if (row.timestamp_ns && row.timestamp_ns > 0) {\n const ms = Math.floor(row.timestamp_ns / 1_000_000);\n if (!sess.minTimestampMs || ms < sess.minTimestampMs) {\n sess.minTimestampMs = ms;\n }\n }\n\n // Extract model from attributes\n if (!sess.model && row.attributes) {\n const m = row.attributes.model ?? row.attributes[\"gen_ai.response.model\"];\n if (typeof m === \"string\") sess.model = m;\n }\n\n // Aggregate token metrics\n if (\n row.name &&\n typeof row.value === \"number\" &&\n row.name.includes(\"token\")\n ) {\n const tokenType =\n (row.attributes?.type as string) ??\n (row.attributes?.[\"gen_ai.token.type\"] as string) ??\n (row.attributes?.token_type as string);\n if (tokenType === \"input\") sess.otelInput += row.value;\n else if (tokenType === \"output\") sess.otelOutput += row.value;\n else if (tokenType === \"cacheRead\" || tokenType === \"cache_read\")\n sess.otelCacheRead += row.value;\n else if (tokenType === \"cacheCreation\" || tokenType === \"cache_write\")\n sess.otelCacheCreation += row.value;\n }\n }\n\n for (const [sessionId, sess] of sessions) {\n if (!sess.target) continue;\n upsertSession({\n session_id: sessionId,\n target: sess.target,\n started_at_ms: sess.minTimestampMs,\n model: sess.model,\n otel_input_tokens: sess.otelInput || undefined,\n otel_output_tokens: sess.otelOutput || undefined,\n otel_cache_read_tokens: sess.otelCacheRead || undefined,\n otel_cache_creation_tokens: sess.otelCacheCreation || undefined,\n has_otel: 1,\n });\n }\n}\n\nfunction isProtobuf(req: http.IncomingMessage): boolean {\n const ct = req.headers[\"content-type\"] ?? \"\";\n return (\n ct.includes(\"application/x-protobuf\") || ct.includes(\"application/protobuf\")\n );\n}\n\nfunction isJson(req: http.IncomingMessage): boolean {\n const ct = req.headers[\"content-type\"] ?? \"\";\n return ct.includes(\"application/json\");\n}\n\ntype Signal = \"logs\" | \"metrics\" | \"traces\";\n\nfunction detectSignal(url: string): Signal | null {\n if (url.includes(\"/logs\")) return \"logs\";\n if (url.includes(\"/metrics\")) return \"metrics\";\n if (url.includes(\"/traces\")) return \"traces\";\n return null;\n}\n\n/**\n * Gemini CLI sends all signals to \"/\" because it passes the base endpoint\n * as the full URL. Sniff the body to determine the signal type.\n */\nfunction sniffSignalFromBody(body: Buffer, protobuf: boolean): Signal | null {\n if (protobuf) {\n // Try decoding as each type — first successful one wins\n try {\n const rows = decodeLogs(body);\n if (rows.length > 0) return \"logs\";\n } catch {}\n try {\n const rows = decodeMetrics(body);\n if (rows.length > 0) return \"metrics\";\n } catch {}\n try {\n const rows = decodeTraces(body);\n if (rows.length > 0) return \"traces\";\n } catch {}\n return null;\n }\n // JSON: check top-level keys\n try {\n const data = JSON.parse(body.toString(\"utf-8\"));\n if (data.resourceLogs) return \"logs\";\n if (data.resourceMetrics) return \"metrics\";\n if (data.resourceSpans) return \"traces\";\n } catch {}\n return null;\n}\n\n/** Handle an OTLP ingest request (logs, metrics, traces). */\nexport async function handleOtlpRequest(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n): Promise<void> {\n const url = req.url ?? \"\";\n\n try {\n const body = await collectBody(req);\n\n // Detect signal from URL path, or sniff body for Gemini CLI (sends to \"/\")\n let signal = detectSignal(url);\n if (!signal && (url === \"/\" || url === \"\")) {\n signal = sniffSignalFromBody(body, isProtobuf(req));\n }\n\n if (signal === \"logs\") {\n if (isProtobuf(req)) {\n const rows = decodeLogs(body);\n if (rows.length > 0) {\n insertOtelLogs(rows);\n ensureSessionsFromOtel(rows);\n }\n const respBytes = ExportLogsServiceResponse.encode(\n ExportLogsServiceResponse.create({}),\n ).finish();\n res.writeHead(200, { \"Content-Type\": \"application/x-protobuf\" });\n res.end(Buffer.from(respBytes));\n } else if (isJson(req)) {\n const data = JSON.parse(body.toString(\"utf-8\"));\n const rows = jsonLogsToRows(data);\n if (rows.length > 0) {\n insertOtelLogs(rows);\n ensureSessionsFromOtel(rows);\n }\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(\"{}\");\n } else {\n res.writeHead(415);\n res.end();\n }\n } else if (signal === \"metrics\") {\n // Metrics carry token data that needs pricing for cost queries\n refreshIfStale().catch(() => {});\n\n if (isProtobuf(req)) {\n const rows = decodeMetrics(body);\n if (rows.length > 0) {\n insertOtelMetrics(rows);\n ensureSessionsFromOtel(rows);\n }\n const respBytes = ExportMetricsServiceResponse.encode(\n ExportMetricsServiceResponse.create({}),\n ).finish();\n res.writeHead(200, { \"Content-Type\": \"application/x-protobuf\" });\n res.end(Buffer.from(respBytes));\n } else if (isJson(req)) {\n const data = JSON.parse(body.toString(\"utf-8\"));\n const rows = jsonMetricsToRows(data);\n if (rows.length > 0) {\n insertOtelMetrics(rows);\n ensureSessionsFromOtel(rows);\n }\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(\"{}\");\n } else {\n res.writeHead(415);\n res.end();\n }\n } else if (signal === \"traces\") {\n if (isProtobuf(req)) {\n const rows = decodeTraces(body);\n if (rows.length > 0) {\n insertOtelSpans(rows);\n ensureSessionsFromOtel(\n rows.map((r) => ({\n session_id: r.session_id,\n timestamp_ns: r.start_time_ns,\n resource_attributes: r.resource_attributes,\n attributes: r.attributes,\n })),\n );\n }\n const respBytes = ExportTracesServiceResponse.encode(\n ExportTracesServiceResponse.create({}),\n ).finish();\n res.writeHead(200, { \"Content-Type\": \"application/x-protobuf\" });\n res.end(Buffer.from(respBytes));\n } else if (isJson(req)) {\n const data = JSON.parse(body.toString(\"utf-8\"));\n const rows = jsonTracesToRows(data);\n if (rows.length > 0) {\n insertOtelSpans(rows);\n ensureSessionsFromOtel(\n rows.map((r) => ({\n session_id: r.session_id,\n timestamp_ns: r.start_time_ns,\n resource_attributes: r.resource_attributes,\n attributes: r.attributes,\n })),\n );\n }\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(\"{}\");\n } else {\n res.writeHead(415);\n res.end();\n }\n } else {\n res.writeHead(404);\n res.end();\n }\n } catch (err) {\n log.otlp.error(\"OTLP handler error:\", err);\n captureException(err, { component: \"otlp\", url });\n if (!res.headersSent) {\n res.writeHead(500);\n res.end();\n }\n }\n}\n\nexport function createOtlpServer(): http.Server {\n return http.createServer(async (req, res) => {\n const url = req.url ?? \"\";\n const method = req.method ?? \"\";\n\n if (url === \"/health\" && method === \"GET\") {\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ status: \"ok\" }));\n return;\n }\n\n if (method !== \"POST\") {\n res.writeHead(405);\n res.end();\n return;\n }\n\n await handleOtlpRequest(req, res);\n });\n}\n\n// Minimal JSON OTLP log parsing (fallback for JSON content-type)\nfunction jsonLogsToRows(data: any): import(\"../db/store.js\").OtelLogRow[] {\n const rows: import(\"../db/store.js\").OtelLogRow[] = [];\n\n for (const rl of data.resourceLogs ?? []) {\n const resourceAttrs = kvListToMap(rl.resource?.attributes);\n const resourceSessionId =\n resourceAttrs[\"session.id\"] ??\n resourceAttrs[\"conversation.id\"] ??\n resourceAttrs[\"service.instance.id\"];\n\n for (const sl of rl.scopeLogs ?? []) {\n for (const lr of sl.logRecords ?? []) {\n const attrs = kvListToMap(lr.attributes);\n\n // Codex sends event name in attrs[\"event.name\"] with an empty body\n const rawBody = extractJsonAnyValue(lr.body);\n const body = rawBody ?? (attrs[\"event.name\"] as string) ?? undefined;\n\n // Codex sends timeUnixNano=0 with real time in attrs[\"event.timestamp\"]\n let timestamp_ns = parseInt(lr.timeUnixNano ?? \"0\", 10);\n if (!timestamp_ns && typeof attrs[\"event.timestamp\"] === \"string\") {\n timestamp_ns =\n new Date(attrs[\"event.timestamp\"] as string).getTime() * 1_000_000;\n }\n\n rows.push({\n timestamp_ns,\n observed_timestamp_ns: lr.observedTimeUnixNano\n ? parseInt(lr.observedTimeUnixNano, 10)\n : undefined,\n severity_number: lr.severityNumber,\n severity_text: lr.severityText,\n body,\n attributes: Object.keys(attrs).length > 0 ? attrs : undefined,\n resource_attributes:\n Object.keys(resourceAttrs).length > 0 ? resourceAttrs : undefined,\n session_id: (attrs[\"session.id\"] ??\n attrs[\"conversation.id\"] ??\n resourceSessionId) as string | undefined,\n prompt_id: (attrs[\"prompt.id\"] ?? attrs.prompt_id) as\n | string\n | undefined,\n trace_id: lr.traceId,\n span_id: lr.spanId,\n });\n }\n }\n }\n return rows;\n}\n\nfunction jsonMetricsToRows(\n data: any,\n): import(\"../db/store.js\").OtelMetricRow[] {\n const rows: import(\"../db/store.js\").OtelMetricRow[] = [];\n\n for (const rm of data.resourceMetrics ?? []) {\n const resourceAttrs = kvListToMap(rm.resource?.attributes);\n const resourceSessionId =\n resourceAttrs[\"session.id\"] ??\n resourceAttrs[\"conversation.id\"] ??\n resourceAttrs[\"service.instance.id\"];\n\n for (const sm of rm.scopeMetrics ?? []) {\n for (const m of sm.metrics ?? []) {\n const dps =\n m.gauge?.dataPoints ??\n m.sum?.dataPoints ??\n m.histogram?.dataPoints ??\n [];\n const metricType = m.gauge\n ? \"gauge\"\n : m.sum\n ? \"sum\"\n : m.histogram\n ? \"histogram\"\n : undefined;\n\n for (const dp of dps) {\n const attrs = kvListToMap(dp.attributes);\n const value = dp.asDouble ?? dp.asInt ?? dp.sum ?? dp.count ?? 0;\n\n rows.push({\n timestamp_ns: parseInt(dp.timeUnixNano ?? \"0\", 10),\n name: m.name,\n value: Number(value),\n metric_type: metricType,\n unit: m.unit || undefined,\n attributes: Object.keys(attrs).length > 0 ? attrs : undefined,\n resource_attributes:\n Object.keys(resourceAttrs).length > 0 ? resourceAttrs : undefined,\n session_id: (attrs[\"session.id\"] ??\n attrs[\"conversation.id\"] ??\n resourceSessionId) as string | undefined,\n });\n }\n }\n }\n }\n return rows;\n}\n\nfunction extractJsonConversationId(promptName: unknown): string | undefined {\n if (typeof promptName !== \"string\") return undefined;\n const sep = promptName.indexOf(\"########\");\n if (sep === -1) return undefined;\n const uuid = promptName.slice(0, sep);\n if (uuid.length === 36 && uuid[8] === \"-\") return uuid;\n return undefined;\n}\n\nfunction jsonTracesToRows(data: any): import(\"../db/store.js\").OtelSpanRow[] {\n const rows: import(\"../db/store.js\").OtelSpanRow[] = [];\n\n for (const rs of data.resourceSpans ?? []) {\n const resourceAttrs = kvListToMap(rs.resource?.attributes);\n const resourceSessionId =\n resourceAttrs[\"session.id\"] ??\n resourceAttrs[\"conversation.id\"] ??\n resourceAttrs[\"service.instance.id\"];\n\n // Build trace_id → conversation_id map from gen_ai.prompt.name\n const traceConversation = new Map<string, string>();\n for (const ss of rs.scopeSpans ?? []) {\n for (const span of ss.spans ?? []) {\n const attrs = kvListToMap(span.attributes);\n const convId = extractJsonConversationId(attrs[\"gen_ai.prompt.name\"]);\n if (convId && span.traceId) {\n traceConversation.set(span.traceId, convId);\n }\n }\n }\n\n for (const ss of rs.scopeSpans ?? []) {\n for (const span of ss.spans ?? []) {\n const attrs = kvListToMap(span.attributes);\n const conversationId = traceConversation.get(span.traceId ?? \"\");\n\n rows.push({\n trace_id: span.traceId ?? \"\",\n span_id: span.spanId ?? \"\",\n parent_span_id: span.parentSpanId || undefined,\n name: span.name ?? \"\",\n kind: span.kind ?? undefined,\n start_time_ns: parseInt(span.startTimeUnixNano ?? \"0\", 10),\n end_time_ns: parseInt(span.endTimeUnixNano ?? \"0\", 10),\n status_code: span.status?.code ?? undefined,\n status_message: span.status?.message || undefined,\n attributes: Object.keys(attrs).length > 0 ? attrs : undefined,\n resource_attributes:\n Object.keys(resourceAttrs).length > 0 ? resourceAttrs : undefined,\n session_id: (conversationId ??\n attrs[\"session.id\"] ??\n attrs[\"conversation.id\"] ??\n resourceSessionId) as string | undefined,\n });\n }\n }\n }\n return rows;\n}\n\nfunction kvListToMap(kvs: any[] | undefined): Record<string, unknown> {\n const out: Record<string, unknown> = {};\n if (!kvs) return out;\n for (const kv of kvs) {\n out[kv.key] = extractJsonAnyValue(kv.value);\n }\n return out;\n}\n\nfunction extractJsonAnyValue(v: any): any {\n if (!v) return null;\n if (v.stringValue !== undefined) return v.stringValue;\n if (v.intValue !== undefined) return Number(v.intValue);\n if (v.doubleValue !== undefined) return v.doubleValue;\n if (v.boolValue !== undefined) return v.boolValue;\n return JSON.stringify(v);\n}\n\n// When run directly, start the server\n// Use normalized separators so this works on both Unix (/) and Windows (\\)\nconst entryScript = process.argv[1]?.replaceAll(\"\\\\\", \"/\") ?? \"\";\nif (\n entryScript.endsWith(\"/otlp/server.js\") ||\n entryScript.endsWith(\"/otlp/server.ts\")\n) {\n const server = createOtlpServer();\n server.listen(config.otlpPort, config.otlpHost, () => {\n log.otlp.info(`Listening on ${config.otlpHost}:${config.otlpPort}`);\n });\n\n const shutdown = () => {\n server.close();\n process.exit(0);\n };\n process.on(\"SIGTERM\", shutdown);\n process.on(\"SIGINT\", shutdown);\n process.on(\"SIGHUP\", shutdown);\n}\n","import protobuf from \"protobufjs\";\n\n// Define OTLP proto types inline using protobufjs JSON descriptors.\n// This avoids needing to vendor .proto files.\n\nconst root = protobuf.Root.fromJSON({\n nested: {\n opentelemetry: {\n nested: {\n proto: {\n nested: {\n common: {\n nested: {\n v1: {\n nested: {\n AnyValue: {\n oneofs: {\n value: {\n oneof: [\n \"stringValue\",\n \"boolValue\",\n \"intValue\",\n \"doubleValue\",\n \"arrayValue\",\n \"kvlistValue\",\n \"bytesValue\",\n ],\n },\n },\n fields: {\n stringValue: { type: \"string\", id: 1 },\n boolValue: { type: \"bool\", id: 2 },\n intValue: { type: \"int64\", id: 3 },\n doubleValue: { type: \"double\", id: 4 },\n arrayValue: {\n type: \"ArrayValue\",\n id: 5,\n },\n kvlistValue: {\n type: \"KeyValueList\",\n id: 6,\n },\n bytesValue: { type: \"bytes\", id: 7 },\n },\n },\n ArrayValue: {\n fields: {\n values: {\n rule: \"repeated\",\n type: \"AnyValue\",\n id: 1,\n },\n },\n },\n KeyValueList: {\n fields: {\n values: {\n rule: \"repeated\",\n type: \"KeyValue\",\n id: 1,\n },\n },\n },\n KeyValue: {\n fields: {\n key: { type: \"string\", id: 1 },\n value: { type: \"AnyValue\", id: 2 },\n },\n },\n InstrumentationScope: {\n fields: {\n name: { type: \"string\", id: 1 },\n version: { type: \"string\", id: 2 },\n attributes: {\n rule: \"repeated\",\n type: \"KeyValue\",\n id: 3,\n },\n },\n },\n },\n },\n },\n },\n resource: {\n nested: {\n v1: {\n nested: {\n Resource: {\n fields: {\n attributes: {\n rule: \"repeated\",\n type: \"opentelemetry.proto.common.v1.KeyValue\",\n id: 1,\n },\n droppedAttributesCount: {\n type: \"uint32\",\n id: 2,\n },\n },\n },\n },\n },\n },\n },\n logs: {\n nested: {\n v1: {\n nested: {\n ExportLogsServiceRequest: {\n fields: {\n resourceLogs: {\n rule: \"repeated\",\n type: \"ResourceLogs\",\n id: 1,\n },\n },\n },\n ResourceLogs: {\n fields: {\n resource: {\n type: \"opentelemetry.proto.resource.v1.Resource\",\n id: 1,\n },\n scopeLogs: {\n rule: \"repeated\",\n type: \"ScopeLogs\",\n id: 2,\n },\n schemaUrl: { type: \"string\", id: 3 },\n },\n },\n ScopeLogs: {\n fields: {\n scope: {\n type: \"opentelemetry.proto.common.v1.InstrumentationScope\",\n id: 1,\n },\n logRecords: {\n rule: \"repeated\",\n type: \"LogRecord\",\n id: 2,\n },\n schemaUrl: { type: \"string\", id: 3 },\n },\n },\n LogRecord: {\n fields: {\n timeUnixNano: {\n type: \"fixed64\",\n id: 1,\n },\n severityNumber: { type: \"int32\", id: 2 },\n severityText: { type: \"string\", id: 3 },\n body: {\n type: \"opentelemetry.proto.common.v1.AnyValue\",\n id: 5,\n },\n attributes: {\n rule: \"repeated\",\n type: \"opentelemetry.proto.common.v1.KeyValue\",\n id: 6,\n },\n droppedAttributesCount: {\n type: \"uint32\",\n id: 7,\n },\n flags: { type: \"fixed32\", id: 8 },\n traceId: { type: \"bytes\", id: 9 },\n spanId: { type: \"bytes\", id: 10 },\n observedTimeUnixNano: {\n type: \"fixed64\",\n id: 11,\n },\n },\n },\n },\n },\n },\n },\n metrics: {\n nested: {\n v1: {\n nested: {\n ExportMetricsServiceRequest: {\n fields: {\n resourceMetrics: {\n rule: \"repeated\",\n type: \"ResourceMetrics\",\n id: 1,\n },\n },\n },\n ResourceMetrics: {\n fields: {\n resource: {\n type: \"opentelemetry.proto.resource.v1.Resource\",\n id: 1,\n },\n scopeMetrics: {\n rule: \"repeated\",\n type: \"ScopeMetrics\",\n id: 2,\n },\n schemaUrl: { type: \"string\", id: 3 },\n },\n },\n ScopeMetrics: {\n fields: {\n scope: {\n type: \"opentelemetry.proto.common.v1.InstrumentationScope\",\n id: 1,\n },\n metrics: {\n rule: \"repeated\",\n type: \"Metric\",\n id: 2,\n },\n schemaUrl: { type: \"string\", id: 3 },\n },\n },\n Metric: {\n oneofs: {\n data: {\n oneof: [\"gauge\", \"sum\", \"histogram\"],\n },\n },\n fields: {\n name: { type: \"string\", id: 1 },\n description: { type: \"string\", id: 2 },\n unit: { type: \"string\", id: 3 },\n gauge: { type: \"Gauge\", id: 5 },\n sum: { type: \"Sum\", id: 7 },\n histogram: { type: \"Histogram\", id: 9 },\n },\n },\n Gauge: {\n fields: {\n dataPoints: {\n rule: \"repeated\",\n type: \"NumberDataPoint\",\n id: 1,\n },\n },\n },\n Sum: {\n fields: {\n dataPoints: {\n rule: \"repeated\",\n type: \"NumberDataPoint\",\n id: 1,\n },\n aggregationTemporality: {\n type: \"int32\",\n id: 2,\n },\n isMonotonic: { type: \"bool\", id: 3 },\n },\n },\n Histogram: {\n fields: {\n dataPoints: {\n rule: \"repeated\",\n type: \"HistogramDataPoint\",\n id: 1,\n },\n aggregationTemporality: {\n type: \"int32\",\n id: 2,\n },\n },\n },\n NumberDataPoint: {\n oneofs: {\n value: {\n oneof: [\"asDouble\", \"asInt\"],\n },\n },\n fields: {\n attributes: {\n rule: \"repeated\",\n type: \"opentelemetry.proto.common.v1.KeyValue\",\n id: 7,\n },\n startTimeUnixNano: {\n type: \"fixed64\",\n id: 2,\n },\n timeUnixNano: {\n type: \"fixed64\",\n id: 3,\n },\n asDouble: { type: \"double\", id: 4 },\n asInt: { type: \"sfixed64\", id: 6 },\n },\n },\n HistogramDataPoint: {\n fields: {\n attributes: {\n rule: \"repeated\",\n type: \"opentelemetry.proto.common.v1.KeyValue\",\n id: 9,\n },\n startTimeUnixNano: {\n type: \"fixed64\",\n id: 2,\n },\n timeUnixNano: {\n type: \"fixed64\",\n id: 3,\n },\n count: { type: \"fixed64\", id: 4 },\n sum: { type: \"double\", id: 5 },\n bucketCounts: {\n rule: \"repeated\",\n type: \"fixed64\",\n id: 6,\n options: { packed: true },\n },\n explicitBounds: {\n rule: \"repeated\",\n type: \"double\",\n id: 7,\n options: { packed: true },\n },\n min: { type: \"double\", id: 11 },\n max: { type: \"double\", id: 12 },\n },\n },\n },\n },\n },\n },\n trace: {\n nested: {\n v1: {\n nested: {\n Span: {\n fields: {\n traceId: { type: \"bytes\", id: 1 },\n spanId: { type: \"bytes\", id: 2 },\n traceState: { type: \"string\", id: 3 },\n parentSpanId: { type: \"bytes\", id: 4 },\n name: { type: \"string\", id: 5 },\n kind: { type: \"int32\", id: 6 },\n startTimeUnixNano: {\n type: \"fixed64\",\n id: 7,\n },\n endTimeUnixNano: {\n type: \"fixed64\",\n id: 8,\n },\n attributes: {\n rule: \"repeated\",\n type: \"opentelemetry.proto.common.v1.KeyValue\",\n id: 9,\n },\n status: { type: \"Status\", id: 15 },\n },\n },\n Status: {\n fields: {\n message: { type: \"string\", id: 2 },\n code: { type: \"int32\", id: 3 },\n },\n },\n ResourceSpans: {\n fields: {\n resource: {\n type: \"opentelemetry.proto.resource.v1.Resource\",\n id: 1,\n },\n scopeSpans: {\n rule: \"repeated\",\n type: \"ScopeSpans\",\n id: 2,\n },\n schemaUrl: { type: \"string\", id: 3 },\n },\n },\n ScopeSpans: {\n fields: {\n scope: {\n type: \"opentelemetry.proto.common.v1.InstrumentationScope\",\n id: 1,\n },\n spans: {\n rule: \"repeated\",\n type: \"Span\",\n id: 2,\n },\n schemaUrl: { type: \"string\", id: 3 },\n },\n },\n },\n },\n },\n },\n collector: {\n nested: {\n logs: {\n nested: {\n v1: {\n nested: {\n ExportLogsServiceRequest: {\n fields: {\n resourceLogs: {\n rule: \"repeated\",\n type: \"opentelemetry.proto.logs.v1.ResourceLogs\",\n id: 1,\n },\n },\n },\n ExportLogsServiceResponse: {\n fields: {},\n },\n },\n },\n },\n },\n metrics: {\n nested: {\n v1: {\n nested: {\n ExportMetricsServiceRequest: {\n fields: {\n resourceMetrics: {\n rule: \"repeated\",\n type: \"opentelemetry.proto.metrics.v1.ResourceMetrics\",\n id: 1,\n },\n },\n },\n ExportMetricsServiceResponse: {\n fields: {},\n },\n },\n },\n },\n },\n trace: {\n nested: {\n v1: {\n nested: {\n ExportTracesServiceRequest: {\n fields: {\n resourceSpans: {\n rule: \"repeated\",\n type: \"opentelemetry.proto.trace.v1.ResourceSpans\",\n id: 1,\n },\n },\n },\n ExportTracesServiceResponse: {\n fields: {},\n },\n },\n },\n },\n },\n },\n },\n },\n },\n },\n },\n },\n});\n\nexport const ExportLogsServiceRequest = root.lookupType(\n \"opentelemetry.proto.collector.logs.v1.ExportLogsServiceRequest\",\n);\nexport const ExportMetricsServiceRequest = root.lookupType(\n \"opentelemetry.proto.collector.metrics.v1.ExportMetricsServiceRequest\",\n);\nexport const ExportLogsServiceResponse = root.lookupType(\n \"opentelemetry.proto.collector.logs.v1.ExportLogsServiceResponse\",\n);\nexport const ExportMetricsServiceResponse = root.lookupType(\n \"opentelemetry.proto.collector.metrics.v1.ExportMetricsServiceResponse\",\n);\nexport const ExportTracesServiceRequest = root.lookupType(\n \"opentelemetry.proto.collector.trace.v1.ExportTracesServiceRequest\",\n);\nexport const ExportTracesServiceResponse = root.lookupType(\n \"opentelemetry.proto.collector.trace.v1.ExportTracesServiceResponse\",\n);\n\n// Helper: extract a scalar value from a protobuf AnyValue\nexport function extractAnyValue(v: any): string | number | boolean | null {\n if (!v) return null;\n if (v.stringValue != null) return v.stringValue;\n if (v.intValue != null) {\n return typeof v.intValue === \"object\" && v.intValue.toNumber\n ? v.intValue.toNumber()\n : Number(v.intValue);\n }\n if (v.doubleValue != null) return v.doubleValue;\n if (v.boolValue != null) return v.boolValue;\n if (v.bytesValue != null) return Buffer.from(v.bytesValue).toString(\"hex\");\n if (v.arrayValue?.values)\n return v.arrayValue.values.map(extractAnyValue) as any;\n if (v.kvlistValue?.values) return attrsToMap(v.kvlistValue.values) as any;\n return null;\n}\n\n// Helper: convert repeated KeyValue to a plain object\nexport function attrsToMap(\n kvs: any[] | null | undefined,\n): Record<string, unknown> {\n const out: Record<string, unknown> = {};\n if (!kvs) return out;\n for (const kv of kvs) {\n if (kv.key) {\n out[kv.key] = extractAnyValue(kv.value);\n }\n }\n return out;\n}\n\n// Helper: convert Long-like fixed64 to number\nexport function longToNumber(val: any): number {\n if (val == null) return 0;\n if (typeof val === \"number\") return val;\n if (typeof val === \"bigint\") return Number(val);\n if (typeof val.toNumber === \"function\") return val.toNumber();\n return Number(val);\n}\n\n// Helper: convert bytes to hex string\nexport function bytesToHex(val: any): string {\n if (!val || val.length === 0) return \"\";\n return Buffer.from(val).toString(\"hex\");\n}\n","import type { OtelLogRow } from \"../db/store.js\";\nimport {\n attrsToMap,\n bytesToHex,\n ExportLogsServiceRequest,\n extractAnyValue,\n longToNumber,\n} from \"./proto.js\";\n\nexport function decodeLogs(buf: Uint8Array): OtelLogRow[] {\n const message = ExportLogsServiceRequest.decode(buf) as any;\n const rows: OtelLogRow[] = [];\n\n for (const resourceLog of message.resourceLogs ?? []) {\n const resourceAttrs = attrsToMap(resourceLog.resource?.attributes);\n // session.id may be in resource_attributes or per-record attributes\n const resourceSessionId =\n (resourceAttrs[\"session.id\"] as string) ??\n (resourceAttrs[\"conversation.id\"] as string) ??\n (resourceAttrs[\"service.instance.id\"] as string) ??\n undefined;\n\n for (const scopeLog of resourceLog.scopeLogs ?? []) {\n for (const record of scopeLog.logRecords ?? []) {\n const attrs = attrsToMap(record.attributes);\n const rawBody = extractAnyValue(record.body);\n\n // Codex sends event name in attrs[\"event.name\"] with an empty body\n const body =\n typeof rawBody === \"string\"\n ? rawBody\n : rawBody != null\n ? JSON.stringify(rawBody)\n : ((attrs[\"event.name\"] as string) ?? undefined);\n\n // Codex sends timestamp_ns=0 with real time in attrs[\"event.timestamp\"]\n let timestamp_ns = longToNumber(record.timeUnixNano);\n if (!timestamp_ns && typeof attrs[\"event.timestamp\"] === \"string\") {\n timestamp_ns =\n new Date(attrs[\"event.timestamp\"] as string).getTime() * 1_000_000;\n }\n\n rows.push({\n timestamp_ns,\n observed_timestamp_ns:\n longToNumber(record.observedTimeUnixNano) || undefined,\n severity_number: record.severityNumber ?? undefined,\n severity_text: record.severityText || undefined,\n body,\n attributes: Object.keys(attrs).length > 0 ? attrs : undefined,\n resource_attributes:\n Object.keys(resourceAttrs).length > 0 ? resourceAttrs : undefined,\n session_id:\n (attrs[\"session.id\"] as string) ??\n (attrs[\"conversation.id\"] as string) ??\n resourceSessionId,\n prompt_id: (attrs[\"prompt.id\"] ?? attrs.prompt_id) as\n | string\n | undefined,\n trace_id: bytesToHex(record.traceId) || undefined,\n span_id: bytesToHex(record.spanId) || undefined,\n });\n }\n }\n }\n\n return rows;\n}\n","import type { OtelMetricRow } from \"../db/store.js\";\nimport {\n attrsToMap,\n ExportMetricsServiceRequest,\n longToNumber,\n} from \"./proto.js\";\n\nexport function decodeMetrics(buf: Uint8Array): OtelMetricRow[] {\n const message = ExportMetricsServiceRequest.decode(buf) as any;\n const rows: OtelMetricRow[] = [];\n\n for (const resourceMetric of message.resourceMetrics ?? []) {\n const resourceAttrs = attrsToMap(resourceMetric.resource?.attributes);\n const resourceSessionId =\n (resourceAttrs[\"session.id\"] as string) ??\n (resourceAttrs[\"conversation.id\"] as string) ??\n (resourceAttrs[\"service.instance.id\"] as string) ??\n undefined;\n\n for (const scopeMetric of resourceMetric.scopeMetrics ?? []) {\n for (const metric of scopeMetric.metrics ?? []) {\n const name = metric.name;\n const unit = metric.unit || undefined;\n\n // Determine metric type and extract data points\n let metricType: string | undefined;\n let dataPoints: any[] = [];\n\n if (metric.gauge) {\n metricType = \"gauge\";\n dataPoints = metric.gauge.dataPoints ?? [];\n } else if (metric.sum) {\n metricType = \"sum\";\n dataPoints = metric.sum.dataPoints ?? [];\n } else if (metric.histogram) {\n metricType = \"histogram\";\n // For histograms, use sum as value\n for (const dp of metric.histogram.dataPoints ?? []) {\n const attrs = attrsToMap(dp.attributes);\n rows.push({\n timestamp_ns: longToNumber(dp.timeUnixNano),\n name,\n value: dp.sum ?? 0,\n metric_type: \"histogram\",\n unit,\n attributes: Object.keys(attrs).length > 0 ? attrs : undefined,\n resource_attributes:\n Object.keys(resourceAttrs).length > 0\n ? resourceAttrs\n : undefined,\n session_id:\n (attrs[\"session.id\"] as string) ??\n (attrs[\"conversation.id\"] as string) ??\n resourceSessionId,\n });\n }\n continue;\n }\n\n // NumberDataPoint (gauge and sum)\n for (const dp of dataPoints) {\n const attrs = attrsToMap(dp.attributes);\n const value =\n dp.asDouble != null\n ? dp.asDouble\n : dp.asInt != null\n ? longToNumber(dp.asInt)\n : 0;\n\n rows.push({\n timestamp_ns: longToNumber(dp.timeUnixNano),\n name,\n value,\n metric_type: metricType,\n unit,\n attributes: Object.keys(attrs).length > 0 ? attrs : undefined,\n resource_attributes:\n Object.keys(resourceAttrs).length > 0 ? resourceAttrs : undefined,\n session_id: (attrs[\"session.id\"] as string) ?? resourceSessionId,\n });\n }\n }\n }\n }\n\n return rows;\n}\n","import type { OtelSpanRow } from \"../db/store.js\";\nimport {\n attrsToMap,\n bytesToHex,\n ExportTracesServiceRequest,\n longToNumber,\n} from \"./proto.js\";\n\n/**\n * Extract conversation ID from gen_ai.prompt.name attribute.\n * Gemini CLI sets this to \"{conversation-uuid}########{turn}\", where the\n * conversation UUID matches the session file ID — distinct from the OTel\n * session.id which is a process-level ID that persists across /clear.\n */\nfunction extractConversationId(promptName: unknown): string | undefined {\n if (typeof promptName !== \"string\") return undefined;\n const sep = promptName.indexOf(\"########\");\n if (sep === -1) return undefined;\n const uuid = promptName.slice(0, sep);\n // Basic UUID format check (8-4-4-4-12)\n if (uuid.length === 36 && uuid[8] === \"-\") return uuid;\n return undefined;\n}\n\nexport function decodeTraces(buf: Uint8Array): OtelSpanRow[] {\n const message = ExportTracesServiceRequest.decode(buf) as any;\n const rows: OtelSpanRow[] = [];\n\n for (const resourceSpan of message.resourceSpans ?? []) {\n const resourceAttrs = attrsToMap(resourceSpan.resource?.attributes);\n const resourceSessionId =\n (resourceAttrs[\"session.id\"] as string) ??\n (resourceAttrs[\"conversation.id\"] as string) ??\n (resourceAttrs[\"service.instance.id\"] as string) ??\n undefined;\n\n // First pass: build trace_id → conversation_id map from spans that\n // carry gen_ai.prompt.name (Gemini llm_call spans). This lets us\n // assign the correct conversation-level session_id to all spans in\n // the same trace, even those without the attribute.\n const traceConversation = new Map<string, string>();\n for (const scopeSpan of resourceSpan.scopeSpans ?? []) {\n for (const span of scopeSpan.spans ?? []) {\n const attrs = attrsToMap(span.attributes);\n const convId = extractConversationId(attrs[\"gen_ai.prompt.name\"]);\n if (convId) {\n traceConversation.set(bytesToHex(span.traceId), convId);\n }\n }\n }\n\n for (const scopeSpan of resourceSpan.scopeSpans ?? []) {\n for (const span of scopeSpan.spans ?? []) {\n const attrs = attrsToMap(span.attributes);\n const traceId = bytesToHex(span.traceId);\n\n // Prefer conversation ID (matches session file) over OTel session.id\n const conversationId = traceConversation.get(traceId);\n\n rows.push({\n trace_id: traceId,\n span_id: bytesToHex(span.spanId),\n parent_span_id: bytesToHex(span.parentSpanId) || undefined,\n name: span.name ?? \"\",\n kind: span.kind ?? undefined,\n start_time_ns: longToNumber(span.startTimeUnixNano),\n end_time_ns: longToNumber(span.endTimeUnixNano),\n status_code: span.status?.code ?? undefined,\n status_message: span.status?.message || undefined,\n attributes: Object.keys(attrs).length > 0 ? attrs : undefined,\n resource_attributes:\n Object.keys(resourceAttrs).length > 0 ? resourceAttrs : undefined,\n session_id:\n conversationId ??\n (attrs[\"session.id\"] as string) ??\n (attrs[\"conversation.id\"] as string) ??\n resourceSessionId,\n });\n }\n }\n }\n\n return rows;\n}\n"],"mappings":"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","names":["protobuf"]}
@@ -0,0 +1,146 @@
1
+ // src/repo.ts
2
+ import { execFileSync } from "child_process";
3
+
4
+ // src/workspaces/superset.ts
5
+ import os from "os";
6
+ import path from "path";
7
+ import Database from "better-sqlite3";
8
+ var SUPERSET_MARKER = `${path.sep}.superset${path.sep}`;
9
+ var SUPERSET_DB_PATH = path.join(os.homedir(), ".superset", "local.db");
10
+ var SupersetProvider = class {
11
+ id = "superset";
12
+ db = null;
13
+ dbFailed = false;
14
+ canResolve(cwd) {
15
+ return cwd.includes(SUPERSET_MARKER);
16
+ }
17
+ resolve(cwd) {
18
+ const db = this.getDb();
19
+ if (!db) return null;
20
+ try {
21
+ const wt = db.prepare(
22
+ `SELECT p.main_repo_path, w.branch, p.github_owner, p.name as project_name
23
+ FROM worktrees w
24
+ JOIN projects p ON w.project_id = p.id
25
+ WHERE ? LIKE w.path || '%'
26
+ ORDER BY LENGTH(w.path) DESC
27
+ LIMIT 1`
28
+ ).get(cwd);
29
+ if (wt) return this.buildResult(wt);
30
+ const proj = db.prepare(
31
+ `SELECT main_repo_path, default_branch AS branch, github_owner, name as project_name
32
+ FROM projects
33
+ WHERE ? LIKE main_repo_path || '%'
34
+ ORDER BY LENGTH(main_repo_path) DESC
35
+ LIMIT 1`
36
+ ).get(cwd);
37
+ if (proj) return this.buildResult(proj);
38
+ } catch {
39
+ }
40
+ return null;
41
+ }
42
+ close() {
43
+ if (this.db) {
44
+ try {
45
+ this.db.close();
46
+ } catch {
47
+ }
48
+ this.db = null;
49
+ }
50
+ this.dbFailed = false;
51
+ }
52
+ buildResult(row) {
53
+ if (row.github_owner) {
54
+ return {
55
+ repo: `${row.github_owner}/${row.project_name}`,
56
+ branch: row.branch
57
+ };
58
+ }
59
+ return { repoDir: row.main_repo_path, branch: row.branch };
60
+ }
61
+ getDb() {
62
+ if (this.dbFailed) return null;
63
+ if (this.db) return this.db;
64
+ try {
65
+ this.db = new Database(SUPERSET_DB_PATH, {
66
+ readonly: true,
67
+ fileMustExist: true
68
+ });
69
+ return this.db;
70
+ } catch {
71
+ this.dbFailed = true;
72
+ return null;
73
+ }
74
+ }
75
+ };
76
+
77
+ // src/repo.ts
78
+ var repoCache = /* @__PURE__ */ new Map();
79
+ var providers = [new SupersetProvider()];
80
+ function resolveGitRemote(dir) {
81
+ try {
82
+ const url = execFileSync(
83
+ "git",
84
+ ["-C", dir, "remote", "get-url", "origin"],
85
+ {
86
+ encoding: "utf-8",
87
+ timeout: 5e3,
88
+ stdio: ["ignore", "pipe", "ignore"]
89
+ }
90
+ ).trim();
91
+ const sshMatch = url.match(/git@[^:]+:([^/]+\/[^/]+?)(?:\.git)?$/);
92
+ if (sshMatch) return sshMatch[1];
93
+ const httpsMatch = url.match(/\/([^/]+\/[^/]+?)(?:\.git)?$/);
94
+ if (httpsMatch) return httpsMatch[1];
95
+ } catch {
96
+ }
97
+ return null;
98
+ }
99
+ function resolveGitBranch(dir) {
100
+ try {
101
+ return execFileSync("git", ["-C", dir, "rev-parse", "--abbrev-ref", "HEAD"], {
102
+ encoding: "utf-8",
103
+ timeout: 5e3,
104
+ stdio: ["ignore", "pipe", "ignore"]
105
+ }).trim() || null;
106
+ } catch {
107
+ return null;
108
+ }
109
+ }
110
+ function resolveRepoFromCwd(cwd) {
111
+ if (repoCache.has(cwd)) return repoCache.get(cwd);
112
+ let result = null;
113
+ const repo = resolveGitRemote(cwd);
114
+ if (repo) {
115
+ result = { repo, branch: resolveGitBranch(cwd) };
116
+ } else {
117
+ for (const provider of providers) {
118
+ if (!provider.canResolve(cwd)) continue;
119
+ const resolved = provider.resolve(cwd);
120
+ if (!resolved) continue;
121
+ if (resolved.repo) {
122
+ result = { repo: resolved.repo, branch: resolved.branch };
123
+ break;
124
+ }
125
+ if (resolved.repoDir) {
126
+ const fallbackRepo = resolveGitRemote(resolved.repoDir);
127
+ if (fallbackRepo) {
128
+ result = { repo: fallbackRepo, branch: resolved.branch };
129
+ break;
130
+ }
131
+ }
132
+ }
133
+ }
134
+ repoCache.set(cwd, result);
135
+ return result;
136
+ }
137
+ function _resetRepoCache() {
138
+ repoCache.clear();
139
+ for (const p of providers) p.close?.();
140
+ }
141
+
142
+ export {
143
+ resolveRepoFromCwd,
144
+ _resetRepoCache
145
+ };
146
+ //# sourceMappingURL=chunk-YVRWVDIA.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/repo.ts","../src/workspaces/superset.ts"],"sourcesContent":["import { execFileSync } from \"node:child_process\";\nimport { SupersetProvider } from \"./workspaces/superset.js\";\nimport type { WorkspaceProvider } from \"./workspaces/types.js\";\n\nexport interface RepoInfo {\n repo: string;\n branch?: string | null;\n}\n\n// Cache: cwd → RepoInfo | null\nconst repoCache = new Map<string, RepoInfo | null>();\n\n// Registered workspace providers — checked in order when git fails.\nconst providers: WorkspaceProvider[] = [new SupersetProvider()];\n\n/** Resolve \"org/repo\" from a directory's git remote origin URL. */\nfunction resolveGitRemote(dir: string): string | null {\n try {\n const url = execFileSync(\n \"git\",\n [\"-C\", dir, \"remote\", \"get-url\", \"origin\"],\n {\n encoding: \"utf-8\",\n timeout: 5000,\n stdio: [\"ignore\", \"pipe\", \"ignore\"],\n },\n ).trim();\n\n // SSH: git@github.com:org/repo.git\n const sshMatch = url.match(/git@[^:]+:([^/]+\\/[^/]+?)(?:\\.git)?$/);\n if (sshMatch) return sshMatch[1];\n\n // HTTPS: https://github.com/org/repo.git\n const httpsMatch = url.match(/\\/([^/]+\\/[^/]+?)(?:\\.git)?$/);\n if (httpsMatch) return httpsMatch[1];\n } catch {\n // Not a git repo, no remote, etc.\n }\n return null;\n}\n\n/** Resolve the current git branch for a directory. */\nfunction resolveGitBranch(dir: string): string | null {\n try {\n return (\n execFileSync(\"git\", [\"-C\", dir, \"rev-parse\", \"--abbrev-ref\", \"HEAD\"], {\n encoding: \"utf-8\",\n timeout: 5000,\n stdio: [\"ignore\", \"pipe\", \"ignore\"],\n }).trim() || null\n );\n } catch {\n return null;\n }\n}\n\n/**\n * Resolve the GitHub \"org/repo\" and branch for a working directory.\n * Results are cached for the lifetime of the process.\n *\n * 1. Try git directly on the CWD\n * 2. On failure, ask registered workspace providers (e.g. Superset)\n * for an alternative repo directory to resolve against\n */\nexport function resolveRepoFromCwd(cwd: string): RepoInfo | null {\n if (repoCache.has(cwd)) return repoCache.get(cwd)!;\n\n let result: RepoInfo | null = null;\n\n const repo = resolveGitRemote(cwd);\n if (repo) {\n result = { repo, branch: resolveGitBranch(cwd) };\n } else {\n // Ask workspace providers for a fallback\n for (const provider of providers) {\n if (!provider.canResolve(cwd)) continue;\n const resolved = provider.resolve(cwd);\n if (!resolved) continue;\n\n // Provider returned repo name directly (no git needed)\n if (resolved.repo) {\n result = { repo: resolved.repo, branch: resolved.branch };\n break;\n }\n\n // Provider returned a directory to resolve via git\n if (resolved.repoDir) {\n const fallbackRepo = resolveGitRemote(resolved.repoDir);\n if (fallbackRepo) {\n result = { repo: fallbackRepo, branch: resolved.branch };\n break;\n }\n }\n }\n }\n\n repoCache.set(cwd, result);\n return result;\n}\n\n/** Reset caches (for testing). */\nexport function _resetRepoCache(): void {\n repoCache.clear();\n for (const p of providers) p.close?.();\n}\n","import os from \"node:os\";\nimport path from \"node:path\";\nimport Database from \"better-sqlite3\";\nimport type { WorkspaceProvider } from \"./types.js\";\n\nconst SUPERSET_MARKER = `${path.sep}.superset${path.sep}`;\nconst SUPERSET_DB_PATH = path.join(os.homedir(), \".superset\", \"local.db\");\n\ninterface WorktreeRow {\n main_repo_path: string;\n branch: string | null;\n github_owner: string | null;\n project_name: string;\n}\n\nexport class SupersetProvider implements WorkspaceProvider {\n readonly id = \"superset\";\n\n private db: Database.Database | null = null;\n private dbFailed = false;\n\n canResolve(cwd: string): boolean {\n return cwd.includes(SUPERSET_MARKER);\n }\n\n resolve(\n cwd: string,\n ): { repo?: string; repoDir?: string; branch?: string | null } | null {\n const db = this.getDb();\n if (!db) return null;\n\n try {\n // Try worktrees table first (for ~/.superset/worktrees/ paths)\n const wt = db\n .prepare(\n `SELECT p.main_repo_path, w.branch, p.github_owner, p.name as project_name\n FROM worktrees w\n JOIN projects p ON w.project_id = p.id\n WHERE ? LIKE w.path || '%'\n ORDER BY LENGTH(w.path) DESC\n LIMIT 1`,\n )\n .get(cwd) as WorktreeRow | undefined;\n if (wt) return this.buildResult(wt);\n\n // Fall back to projects table (for ~/.superset/projects/ paths)\n const proj = db\n .prepare(\n `SELECT main_repo_path, default_branch AS branch, github_owner, name as project_name\n FROM projects\n WHERE ? LIKE main_repo_path || '%'\n ORDER BY LENGTH(main_repo_path) DESC\n LIMIT 1`,\n )\n .get(cwd) as WorktreeRow | undefined;\n if (proj) return this.buildResult(proj);\n } catch {\n // Schema mismatch, corrupt DB, etc.\n }\n\n return null;\n }\n\n close(): void {\n if (this.db) {\n try {\n this.db.close();\n } catch {}\n this.db = null;\n }\n this.dbFailed = false;\n }\n\n private buildResult(row: WorktreeRow): {\n repo?: string;\n repoDir?: string;\n branch?: string | null;\n } {\n // Prefer deriving repo name directly from Superset DB (no git needed)\n if (row.github_owner) {\n return {\n repo: `${row.github_owner}/${row.project_name}`,\n branch: row.branch,\n };\n }\n // Fall back to git resolution on the main repo path\n return { repoDir: row.main_repo_path, branch: row.branch };\n }\n\n private getDb(): Database.Database | null {\n if (this.dbFailed) return null;\n if (this.db) return this.db;\n try {\n this.db = new Database(SUPERSET_DB_PATH, {\n readonly: true,\n fileMustExist: true,\n });\n return this.db;\n } catch {\n this.dbFailed = true;\n return null;\n }\n }\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,176 @@
1
+ import {
2
+ registerTarget
3
+ } from "./chunk-QVK6VGCV.js";
4
+
5
+ // src/targets/types.ts
6
+ var ALL_EVENTS = [
7
+ // ── Session lifecycle ────────────────────────────────────────────────────
8
+ // SessionStart: Fired once when `claude` launches or a new conversation begins.
9
+ // Payload: cwd, permission_mode, model, agent_version.
10
+ // Panopticon uses this to auto-start the server process (see handler.ts).
11
+ "SessionStart",
12
+ // SessionEnd: Fired when the session process exits (user quits, ctrl+C, or
13
+ // process terminates). May not fire on SIGKILL. Carries final session state.
14
+ "SessionEnd",
15
+ // Setup: Fired early in startup, after setCwd() but before the REPL renders.
16
+ // Runs before trust dialogs, so git commands may not have executed yet.
17
+ "Setup",
18
+ // ── User interaction ─────────────────────────────────────────────────────
19
+ // UserPromptSubmit: Fired when the user submits a prompt (presses Enter in
20
+ // REPL or sends via SDK). Payload: prompt text. Fires before model inference.
21
+ "UserPromptSubmit",
22
+ // ── Tool lifecycle (highest volume events) ───────────────────────────────
23
+ // PreToolUse: Fired BEFORE each tool execution. Payload: tool_name, tool_input.
24
+ // This is the permission enforcement point — hooks can return a
25
+ // permissionDecision ("allow"/"deny") to approve/reject without user prompt.
26
+ // Panopticon checks allowed.json here for auto-approval rules.
27
+ "PreToolUse",
28
+ // PostToolUse: Fired AFTER a tool executes successfully. Payload: tool_name,
29
+ // tool_input, tool_result. Good for auditing what tools actually did.
30
+ "PostToolUse",
31
+ // PostToolUseFailure: Fired AFTER a tool execution fails (error, file not found,
32
+ // permission denied, etc). Same shape as PostToolUse but indicates failure.
33
+ "PostToolUseFailure",
34
+ // ── Permission prompts ───────────────────────────────────────────────────
35
+ // PermissionRequest: Fired when Claude Code is about to show the user a
36
+ // permission prompt (tool needs approval). Payload: tool_name, tool_input.
37
+ "PermissionRequest",
38
+ // PermissionDenied: Fired when the user denies a permission prompt.
39
+ "PermissionDenied",
40
+ // ── Model turn lifecycle ─────────────────────────────────────────────────
41
+ // Stop: Fired when the model finishes a turn and stops generating (no more
42
+ // tool calls to make). Natural end of each assistant response cycle.
43
+ // A session has many Stop events but only one SessionEnd.
44
+ "Stop",
45
+ // StopFailure: Fired when the model stops due to an error — rate limit,
46
+ // prompt too long, auth failure, etc. The model never produced a valid
47
+ // response for this turn.
48
+ "StopFailure",
49
+ // ── Subagents ────────────────────────────────────────────────────────────
50
+ // SubagentStart: Fired when a subagent is spawned via the Agent tool.
51
+ // Payload includes the agent type and description.
52
+ "SubagentStart",
53
+ // SubagentStop: Fired when a subagent completes (success or failure).
54
+ "SubagentStop",
55
+ // ── Context compaction ───────────────────────────────────────────────────
56
+ // PreCompact: Fired before conversation context is compacted (summarized to
57
+ // reduce token count). Useful for capturing pre-compaction state.
58
+ "PreCompact",
59
+ // PostCompact: Fired after compaction completes. Payload includes token
60
+ // counts before/after compaction.
61
+ "PostCompact",
62
+ // ── Notifications ────────────────────────────────────────────────────────
63
+ // Notification: System notifications — rate limit warnings, usage alerts, etc.
64
+ "Notification",
65
+ // ── Team / background tasks ──────────────────────────────────────────────
66
+ // TeammateIdle: Fired when a teammate agent (swarm mode) has no work to do.
67
+ "TeammateIdle",
68
+ // TaskCreated: Fired when a background task is created (via TaskCreate tool).
69
+ "TaskCreated",
70
+ // TaskCompleted: Fired when a background task finishes.
71
+ "TaskCompleted",
72
+ // ── MCP auth / elicitation ───────────────────────────────────────────────
73
+ // Elicitation: Fired when an MCP server triggers an OAuth/auth flow prompt.
74
+ "Elicitation",
75
+ // ElicitationResult: Fired when the user completes or cancels the auth flow.
76
+ "ElicitationResult",
77
+ // ── Configuration & file system ──────────────────────────────────────────
78
+ // ConfigChange: Fired when settings.json, CLAUDE.md, or similar config changes.
79
+ "ConfigChange",
80
+ // InstructionsLoaded: Fired when CLAUDE.md files are loaded into context.
81
+ "InstructionsLoaded",
82
+ // CwdChanged: Fired when Claude Code's working directory changes (via /add-dir
83
+ // or similar). NOTE: `cd` in Bash does NOT trigger this — that only affects
84
+ // the subprocess shell, not the harness's cwd.
85
+ "CwdChanged",
86
+ // FileChanged: Fired when a watched file is modified on disk (external edit).
87
+ "FileChanged",
88
+ // ── Worktree management ──────────────────────────────────────────────────
89
+ // WorktreeCreate: Fired when a git worktree is created (--worktree flag or
90
+ // EnterWorktree tool).
91
+ "WorktreeCreate",
92
+ // WorktreeRemove: Fired when a git worktree is removed (ExitWorktree tool
93
+ // or session cleanup).
94
+ "WorktreeRemove"
95
+ ];
96
+
97
+ // src/targets/claude-desktop.ts
98
+ import fs from "fs";
99
+ import os from "os";
100
+ import path from "path";
101
+ var CLAUDE_DESKTOP_DIR = path.join(
102
+ os.homedir(),
103
+ "Library",
104
+ "Application Support",
105
+ "Claude"
106
+ );
107
+ var CLAUDE_DESKTOP_CONFIG = path.join(
108
+ CLAUDE_DESKTOP_DIR,
109
+ "claude_desktop_config.json"
110
+ );
111
+ var claudeDesktop = {
112
+ id: "claude-desktop",
113
+ config: {
114
+ dir: CLAUDE_DESKTOP_DIR,
115
+ configPath: CLAUDE_DESKTOP_CONFIG,
116
+ configFormat: "json"
117
+ },
118
+ hooks: {
119
+ // Claude Desktop uses MCP servers, not hooks
120
+ events: [],
121
+ applyInstallConfig(existing, opts) {
122
+ const cfg = { ...existing };
123
+ const serverBin = path.join(opts.pluginRoot, "bin", "mcp-server");
124
+ cfg.mcpServers = cfg.mcpServers ?? {};
125
+ cfg.mcpServers.panopticon = {
126
+ command: "node",
127
+ args: [serverBin]
128
+ };
129
+ return cfg;
130
+ },
131
+ removeInstallConfig(existing) {
132
+ const cfg = { ...existing };
133
+ const servers = cfg.mcpServers;
134
+ if (servers) {
135
+ delete servers.panopticon;
136
+ if (Object.keys(servers).length === 0) delete cfg.mcpServers;
137
+ }
138
+ return cfg;
139
+ }
140
+ },
141
+ shellEnv: {
142
+ envVars() {
143
+ return [];
144
+ }
145
+ },
146
+ events: {
147
+ eventMap: {},
148
+ formatPermissionResponse({ allow, reason }) {
149
+ return {
150
+ hookSpecificOutput: {
151
+ hookEventName: "PreToolUse",
152
+ permissionDecision: allow ? "allow" : "deny",
153
+ permissionDecisionReason: reason
154
+ }
155
+ };
156
+ }
157
+ },
158
+ detect: {
159
+ displayName: "Claude Desktop",
160
+ isInstalled: () => fs.existsSync(CLAUDE_DESKTOP_DIR),
161
+ isConfigured() {
162
+ try {
163
+ const cfg = JSON.parse(fs.readFileSync(CLAUDE_DESKTOP_CONFIG, "utf-8"));
164
+ return !!cfg.mcpServers?.panopticon;
165
+ } catch {
166
+ return false;
167
+ }
168
+ }
169
+ }
170
+ };
171
+ registerTarget(claudeDesktop);
172
+
173
+ export {
174
+ ALL_EVENTS
175
+ };
176
+ //# sourceMappingURL=chunk-ZEC4LRKS.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/targets/types.ts","../src/targets/claude-desktop.ts"],"sourcesContent":["/**\n * Target adapter types — each supported coding tool declares its specifics\n * via this interface so consumers can iterate over the registry instead of\n * hardcoding target-specific branches.\n */\n\nimport type { HookInput } from \"../hooks/ingest.js\";\n\n/**\n * All hook event names panopticon registers for.\n *\n * Claude Code fires these as shell commands via hooks.json — each invocation\n * pipes a JSON payload to stdin with session_id, hook_event_name, and\n * event-specific fields. Panopticon's hook-handler POSTs the payload to\n * the local server, which calls processHookEvent() in ingest.ts.\n *\n * Non-Claude targets (Gemini, Codex) map their native event names to these\n * canonical names via their adapter's eventMap.\n */\nexport const ALL_EVENTS = [\n // ── Session lifecycle ────────────────────────────────────────────────────\n // SessionStart: Fired once when `claude` launches or a new conversation begins.\n // Payload: cwd, permission_mode, model, agent_version.\n // Panopticon uses this to auto-start the server process (see handler.ts).\n \"SessionStart\",\n // SessionEnd: Fired when the session process exits (user quits, ctrl+C, or\n // process terminates). May not fire on SIGKILL. Carries final session state.\n \"SessionEnd\",\n // Setup: Fired early in startup, after setCwd() but before the REPL renders.\n // Runs before trust dialogs, so git commands may not have executed yet.\n \"Setup\",\n\n // ── User interaction ─────────────────────────────────────────────────────\n // UserPromptSubmit: Fired when the user submits a prompt (presses Enter in\n // REPL or sends via SDK). Payload: prompt text. Fires before model inference.\n \"UserPromptSubmit\",\n\n // ── Tool lifecycle (highest volume events) ───────────────────────────────\n // PreToolUse: Fired BEFORE each tool execution. Payload: tool_name, tool_input.\n // This is the permission enforcement point — hooks can return a\n // permissionDecision (\"allow\"/\"deny\") to approve/reject without user prompt.\n // Panopticon checks allowed.json here for auto-approval rules.\n \"PreToolUse\",\n // PostToolUse: Fired AFTER a tool executes successfully. Payload: tool_name,\n // tool_input, tool_result. Good for auditing what tools actually did.\n \"PostToolUse\",\n // PostToolUseFailure: Fired AFTER a tool execution fails (error, file not found,\n // permission denied, etc). Same shape as PostToolUse but indicates failure.\n \"PostToolUseFailure\",\n\n // ── Permission prompts ───────────────────────────────────────────────────\n // PermissionRequest: Fired when Claude Code is about to show the user a\n // permission prompt (tool needs approval). Payload: tool_name, tool_input.\n \"PermissionRequest\",\n // PermissionDenied: Fired when the user denies a permission prompt.\n \"PermissionDenied\",\n\n // ── Model turn lifecycle ─────────────────────────────────────────────────\n // Stop: Fired when the model finishes a turn and stops generating (no more\n // tool calls to make). Natural end of each assistant response cycle.\n // A session has many Stop events but only one SessionEnd.\n \"Stop\",\n // StopFailure: Fired when the model stops due to an error — rate limit,\n // prompt too long, auth failure, etc. The model never produced a valid\n // response for this turn.\n \"StopFailure\",\n\n // ── Subagents ────────────────────────────────────────────────────────────\n // SubagentStart: Fired when a subagent is spawned via the Agent tool.\n // Payload includes the agent type and description.\n \"SubagentStart\",\n // SubagentStop: Fired when a subagent completes (success or failure).\n \"SubagentStop\",\n\n // ── Context compaction ───────────────────────────────────────────────────\n // PreCompact: Fired before conversation context is compacted (summarized to\n // reduce token count). Useful for capturing pre-compaction state.\n \"PreCompact\",\n // PostCompact: Fired after compaction completes. Payload includes token\n // counts before/after compaction.\n \"PostCompact\",\n\n // ── Notifications ────────────────────────────────────────────────────────\n // Notification: System notifications — rate limit warnings, usage alerts, etc.\n \"Notification\",\n\n // ── Team / background tasks ──────────────────────────────────────────────\n // TeammateIdle: Fired when a teammate agent (swarm mode) has no work to do.\n \"TeammateIdle\",\n // TaskCreated: Fired when a background task is created (via TaskCreate tool).\n \"TaskCreated\",\n // TaskCompleted: Fired when a background task finishes.\n \"TaskCompleted\",\n\n // ── MCP auth / elicitation ───────────────────────────────────────────────\n // Elicitation: Fired when an MCP server triggers an OAuth/auth flow prompt.\n \"Elicitation\",\n // ElicitationResult: Fired when the user completes or cancels the auth flow.\n \"ElicitationResult\",\n\n // ── Configuration & file system ──────────────────────────────────────────\n // ConfigChange: Fired when settings.json, CLAUDE.md, or similar config changes.\n \"ConfigChange\",\n // InstructionsLoaded: Fired when CLAUDE.md files are loaded into context.\n \"InstructionsLoaded\",\n // CwdChanged: Fired when Claude Code's working directory changes (via /add-dir\n // or similar). NOTE: `cd` in Bash does NOT trigger this — that only affects\n // the subprocess shell, not the harness's cwd.\n \"CwdChanged\",\n // FileChanged: Fired when a watched file is modified on disk (external edit).\n \"FileChanged\",\n\n // ── Worktree management ──────────────────────────────────────────────────\n // WorktreeCreate: Fired when a git worktree is created (--worktree flag or\n // EnterWorktree tool).\n \"WorktreeCreate\",\n // WorktreeRemove: Fired when a git worktree is removed (ExitWorktree tool\n // or session cleanup).\n \"WorktreeRemove\",\n] as const;\n\n/** Union type of all supported event names. */\nexport type CanonicalEvent = (typeof ALL_EVENTS)[number];\n\n// ── Config & Paths ──────────────────────────────────────────────────────────\n\nexport interface TargetConfigSpec {\n /** Directory where this target stores its config, e.g. ~/.claude */\n dir: string;\n /** Path to the main config file */\n configPath: string;\n /** Format of the config file */\n configFormat: \"json\" | \"toml\";\n}\n\n// ── Hook Registration ───────────────────────────────────────────────────────\n\nexport interface TargetInstallOpts {\n pluginRoot: string;\n port: number;\n proxy?: boolean;\n}\n\nexport interface TargetHookSpec {\n /** Event names this target uses, in the target's own convention */\n events: string[];\n /**\n * Apply panopticon hook registration (and related config like MCP servers,\n * telemetry) to this target's existing config. Each target handles its own\n * deduplication/merge logic. Returns the modified config.\n */\n applyInstallConfig(\n existingConfig: Record<string, unknown>,\n opts: TargetInstallOpts,\n ): Record<string, unknown>;\n /**\n * Remove panopticon hook registration (and related config like MCP servers,\n * telemetry) from this target's existing config. Returns the modified config.\n */\n removeInstallConfig(\n existingConfig: Record<string, unknown>,\n ): Record<string, unknown>;\n}\n\n// ── Shell Environment ───────────────────────────────────────────────────────\n\nexport interface TargetShellEnvSpec {\n /**\n * Env vars to export as [varName, value] tuples.\n * These are target-specific; shared OTEL_* vars are handled separately.\n */\n envVars(port: number, proxy: boolean): Array<[string, string]>;\n}\n\n// ── Event Normalization ─────────────────────────────────────────────────────\n\nexport interface TargetEventSpec {\n /** Map from target's event name to canonical panopticon event name. */\n eventMap: Record<string, CanonicalEvent>;\n /**\n * Transform the raw hook payload before storage.\n * Used e.g. by Gemini to extract user_prompt from llm_request.messages.\n */\n normalizePayload?(data: HookInput): HookInput;\n /**\n * Format a permission response for this target's expected shape.\n */\n formatPermissionResponse(decision: {\n allow: boolean;\n reason: string;\n }): Record<string, unknown>;\n}\n\n// ── Doctor / Detection ──────────────────────────────────────────────────────\n\nexport interface TargetDetectSpec {\n /** Human-readable name for display, e.g. \"Claude Code\" */\n displayName: string;\n /** Check whether this target is installed on the system */\n isInstalled(): boolean;\n /** Check whether panopticon is configured within this target */\n isConfigured(): boolean;\n}\n\n// ── OTel Telemetry Schema ────────────────────────────────────────────────────\n\nexport interface MetricSpec {\n /** OTel metric name(s) this target emits for token usage */\n metricNames: string[];\n /** Aggregation function: 'SUM' for per-request deltas, 'MAX' for cumulative counters */\n aggregation: \"SUM\" | \"MAX\";\n /** JSON paths to extract token type from metric attributes (first non-null wins) */\n tokenTypeAttrs: string[];\n /** JSON paths to extract model name from metric attributes (first non-null wins) */\n modelAttrs: string[];\n /** Remap token_type values before aggregation, e.g. { cached_input: 'cacheRead' } */\n tokenTypeMap?: Record<string, string>;\n /** Token type values to exclude (e.g. 'total' to avoid double-counting) */\n excludeTokenTypes?: string[];\n}\n\nexport interface OtelLogFieldSpec {\n /** SQL expressions to extract event type from otel_logs (COALESCEd). Default: ['body'] */\n eventTypeExprs?: string[];\n /** SQL expressions to extract timestamp in ms from otel_logs. Default: ['CAST(timestamp_ns / 1000000 AS INTEGER)'] */\n timestampMsExprs?: string[];\n}\n\nexport interface TargetOtelSpec {\n /** OTel service.name this target emits. Used for session inference when metrics lack session_id. */\n serviceName?: string;\n /** Token usage metric declaration. Undefined means no token metrics. */\n metrics?: MetricSpec;\n /** How to extract event type and timestamp from otel_logs rows. */\n logFields?: OtelLogFieldSpec;\n}\n\n// ── Target Identification ────────────────────────────────────────────────────\n\nexport interface TargetIdentSpec {\n /** Model-name regex patterns for last-resort target identification from hook payloads */\n modelPatterns?: RegExp[];\n}\n\n// ── Proxy (optional — not all targets use the proxy) ────────────────────────\n\nexport interface TargetProxySpec {\n /**\n * Upstream host for API proxying.\n * String for simple mapping; function for dynamic routing (e.g. Codex JWT).\n */\n upstreamHost: string | ((headers: Record<string, string>) => string);\n /** Path rewrite rule, if needed. Default: pass through. */\n rewritePath?(path: string, headers: Record<string, string>): string;\n /** Which stream accumulator to use */\n accumulatorType: \"anthropic\" | \"openai\";\n}\n\n// ── Session File Scanner ─────────────────────────────────────────────────────\n\nexport interface DiscoveredFile {\n filePath: string;\n}\n\nexport interface ParsedTurn {\n sessionId: string;\n turnIndex: number;\n timestampMs: number;\n model?: string;\n role: \"user\" | \"assistant\";\n contentPreview?: string;\n inputTokens: number;\n outputTokens: number;\n cacheReadTokens: number;\n cacheCreationTokens: number;\n reasoningTokens: number;\n}\n\nexport type RelationshipType = \"subagent\" | \"continuation\" | \"fork\";\n\nexport interface ParsedSession {\n sessionId: string;\n parentSessionId?: string;\n relationshipType?: RelationshipType;\n model?: string;\n cwd?: string;\n cliVersion?: string;\n startedAtMs?: number;\n firstPrompt?: string;\n}\n\nexport interface ParsedEvent {\n sessionId: string;\n eventType: string; // tool_call, tool_result, error, agent_message, reasoning, file_snapshot, info\n timestampMs: number;\n toolName?: string;\n toolInput?: string;\n toolOutput?: string;\n content?: string;\n metadata?: Record<string, unknown>;\n}\n\n// ── Parsed messages & tool calls (for messages/tool_calls tables) ───────────\n\nexport interface ParsedToolCall {\n toolUseId: string;\n toolName: string;\n category: string;\n inputJson?: string;\n skillName?: string;\n resultContentLength?: number;\n resultContent?: string;\n subagentSessionId?: string;\n /** Timestamp (ms) when the tool was invoked (from the assistant message). */\n timestampMs?: number;\n}\n\nexport interface ParsedMessage {\n sessionId: string;\n ordinal: number;\n role: \"user\" | \"assistant\";\n content: string;\n timestampMs?: number;\n hasThinking: boolean;\n hasToolUse: boolean;\n isSystem: boolean;\n contentLength: number;\n model?: string;\n tokenUsage?: string;\n contextTokens?: number;\n outputTokens?: number;\n hasContextTokens: boolean;\n hasOutputTokens: boolean;\n /** DAG node UUID from the JSONL line that produced this message. */\n uuid?: string;\n /** Parent DAG node UUID (the line this message is a reply to). */\n parentUuid?: string;\n toolCalls: ParsedToolCall[];\n /** tool_use_id → raw result content (from tool_result blocks in user messages) */\n toolResults: Map<\n string,\n { contentLength: number; contentRaw: string; timestampMs?: number }\n >;\n}\n\nexport interface ParseResult {\n meta?: ParsedSession;\n turns: ParsedTurn[];\n events: ParsedEvent[];\n messages: ParsedMessage[];\n newByteOffset: number;\n /**\n * When true, turn indices are absolute (0-based from start of session)\n * and the caller should NOT re-index them. Used by parsers that re-read\n * the full file (e.g. Gemini JSON) rather than reading incrementally.\n * INSERT OR IGNORE handles dedup via the UNIQUE constraint.\n */\n absoluteIndices?: boolean;\n /** Additional sessions from DAG fork detection (branched conversations). */\n forks?: ParseResult[];\n /**\n * When true, the parser detected a DAG fork during incremental reading.\n * The caller should reset the file watermark and reparse from byte 0\n * so fork detection can run on the full file.\n */\n needsFullReparse?: boolean;\n /**\n * Tool results from filtered-out messages (e.g. tool-result-only user\n * messages) that still need to be backfilled into tool_calls.\n */\n orphanedToolResults?: Map<\n string,\n { contentLength: number; contentRaw: string; timestampMs?: number }\n >;\n}\n\nexport interface TargetScannerSpec {\n /** Discover session files on disk for this target. */\n discover(): DiscoveredFile[];\n /**\n * Parse a session file. Receives the file path and current byte offset.\n * Returns parsed data and new byte offset, or null if no new data.\n */\n parseFile(filePath: string, fromByteOffset: number): ParseResult | null;\n /** Normalize a tool name to a standard category for analytics grouping. */\n normalizeToolCategory(toolName: string): string;\n}\n\n// ── The Adapter ─────────────────────────────────────────────────────────────\n\nexport interface TargetAdapter {\n /** Machine identifier: \"claude\", \"gemini\", \"codex\", etc. */\n id: string;\n config: TargetConfigSpec;\n hooks: TargetHookSpec;\n shellEnv: TargetShellEnvSpec;\n events: TargetEventSpec;\n detect: TargetDetectSpec;\n /** Proxy spec is optional — not every target routes through the proxy */\n proxy?: TargetProxySpec;\n /** OTel telemetry schema — how this target emits metrics and logs */\n otel?: TargetOtelSpec;\n /** How to identify this target from hook payloads when no explicit source field is present */\n ident?: TargetIdentSpec;\n /** Session file scanner — reads local transcript files for token usage */\n scanner?: TargetScannerSpec;\n}\n","import fs from \"node:fs\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport { registerTarget } from \"./registry.js\";\nimport type { TargetAdapter } from \"./types.js\";\n\nconst CLAUDE_DESKTOP_DIR = path.join(\n os.homedir(),\n \"Library\",\n \"Application Support\",\n \"Claude\",\n);\nconst CLAUDE_DESKTOP_CONFIG = path.join(\n CLAUDE_DESKTOP_DIR,\n \"claude_desktop_config.json\",\n);\n\nconst claudeDesktop: TargetAdapter = {\n id: \"claude-desktop\",\n\n config: {\n dir: CLAUDE_DESKTOP_DIR,\n configPath: CLAUDE_DESKTOP_CONFIG,\n configFormat: \"json\",\n },\n\n hooks: {\n // Claude Desktop uses MCP servers, not hooks\n events: [],\n applyInstallConfig(existing, opts) {\n const cfg = { ...existing };\n const serverBin = path.join(opts.pluginRoot, \"bin\", \"mcp-server\");\n cfg.mcpServers = (cfg.mcpServers as Record<string, unknown>) ?? {};\n (cfg.mcpServers as Record<string, unknown>).panopticon = {\n command: \"node\",\n args: [serverBin],\n };\n return cfg;\n },\n removeInstallConfig(existing) {\n const cfg = { ...existing };\n const servers = cfg.mcpServers as Record<string, unknown> | undefined;\n if (servers) {\n delete servers.panopticon;\n if (Object.keys(servers).length === 0) delete cfg.mcpServers;\n }\n return cfg;\n },\n },\n\n shellEnv: {\n envVars() {\n return [];\n },\n },\n\n events: {\n eventMap: {},\n formatPermissionResponse({ allow, reason }) {\n return {\n hookSpecificOutput: {\n hookEventName: \"PreToolUse\",\n permissionDecision: allow ? \"allow\" : \"deny\",\n permissionDecisionReason: reason,\n },\n };\n },\n },\n\n detect: {\n displayName: \"Claude Desktop\",\n isInstalled: () => fs.existsSync(CLAUDE_DESKTOP_DIR),\n isConfigured() {\n try {\n const cfg = JSON.parse(fs.readFileSync(CLAUDE_DESKTOP_CONFIG, \"utf-8\"));\n return !!cfg.mcpServers?.panopticon;\n } catch {\n return false;\n }\n },\n },\n};\n\nregisterTarget(claudeDesktop);\n"],"mappings":";;;;;AAmBO,IAAM,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA,EAKxB;AAAA;AAAA;AAAA,EAGA;AAAA;AAAA;AAAA,EAGA;AAAA;AAAA;AAAA;AAAA,EAKA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA;AAAA;AAAA;AAAA,EAGA;AAAA;AAAA;AAAA,EAGA;AAAA;AAAA;AAAA;AAAA,EAKA;AAAA;AAAA,EAEA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA;AAAA;AAAA;AAAA;AAAA,EAIA;AAAA;AAAA;AAAA;AAAA,EAKA;AAAA;AAAA,EAEA;AAAA;AAAA;AAAA;AAAA,EAKA;AAAA;AAAA;AAAA,EAGA;AAAA;AAAA;AAAA,EAIA;AAAA;AAAA;AAAA,EAIA;AAAA;AAAA,EAEA;AAAA;AAAA,EAEA;AAAA;AAAA;AAAA,EAIA;AAAA;AAAA,EAEA;AAAA;AAAA;AAAA,EAIA;AAAA;AAAA,EAEA;AAAA;AAAA;AAAA;AAAA,EAIA;AAAA;AAAA,EAEA;AAAA;AAAA;AAAA;AAAA,EAKA;AAAA;AAAA;AAAA,EAGA;AACF;;;ACvHA,OAAO,QAAQ;AACf,OAAO,QAAQ;AACf,OAAO,UAAU;AAIjB,IAAM,qBAAqB,KAAK;AAAA,EAC9B,GAAG,QAAQ;AAAA,EACX;AAAA,EACA;AAAA,EACA;AACF;AACA,IAAM,wBAAwB,KAAK;AAAA,EACjC;AAAA,EACA;AACF;AAEA,IAAM,gBAA+B;AAAA,EACnC,IAAI;AAAA,EAEJ,QAAQ;AAAA,IACN,KAAK;AAAA,IACL,YAAY;AAAA,IACZ,cAAc;AAAA,EAChB;AAAA,EAEA,OAAO;AAAA;AAAA,IAEL,QAAQ,CAAC;AAAA,IACT,mBAAmB,UAAU,MAAM;AACjC,YAAM,MAAM,EAAE,GAAG,SAAS;AAC1B,YAAM,YAAY,KAAK,KAAK,KAAK,YAAY,OAAO,YAAY;AAChE,UAAI,aAAc,IAAI,cAA0C,CAAC;AACjE,MAAC,IAAI,WAAuC,aAAa;AAAA,QACvD,SAAS;AAAA,QACT,MAAM,CAAC,SAAS;AAAA,MAClB;AACA,aAAO;AAAA,IACT;AAAA,IACA,oBAAoB,UAAU;AAC5B,YAAM,MAAM,EAAE,GAAG,SAAS;AAC1B,YAAM,UAAU,IAAI;AACpB,UAAI,SAAS;AACX,eAAO,QAAQ;AACf,YAAI,OAAO,KAAK,OAAO,EAAE,WAAW,EAAG,QAAO,IAAI;AAAA,MACpD;AACA,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEA,UAAU;AAAA,IACR,UAAU;AACR,aAAO,CAAC;AAAA,IACV;AAAA,EACF;AAAA,EAEA,QAAQ;AAAA,IACN,UAAU,CAAC;AAAA,IACX,yBAAyB,EAAE,OAAO,OAAO,GAAG;AAC1C,aAAO;AAAA,QACL,oBAAoB;AAAA,UAClB,eAAe;AAAA,UACf,oBAAoB,QAAQ,UAAU;AAAA,UACtC,0BAA0B;AAAA,QAC5B;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EAEA,QAAQ;AAAA,IACN,aAAa;AAAA,IACb,aAAa,MAAM,GAAG,WAAW,kBAAkB;AAAA,IACnD,eAAe;AACb,UAAI;AACF,cAAM,MAAM,KAAK,MAAM,GAAG,aAAa,uBAAuB,OAAO,CAAC;AACtE,eAAO,CAAC,CAAC,IAAI,YAAY;AAAA,MAC3B,QAAQ;AACN,eAAO;AAAA,MACT;AAAA,IACF;AAAA,EACF;AACF;AAEA,eAAe,aAAa;","names":[]}
package/dist/cli.d.ts ADDED
@@ -0,0 +1 @@
1
+ #!/usr/bin/env node