@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/hooks/handler.ts","../../src/api/util.ts"],"sourcesContent":["#!/usr/bin/env node\n\n/**\n * Hook handler — thin stdin→HTTP→stdout bridge.\n *\n * Reads JSON from stdin (same format Claude Code / Gemini CLI / Codex CLI send),\n * POSTs it to the unified panopticon server at /hooks, and relays the response\n * to stdout. Drops events if the server is unreachable.\n */\n\nimport { spawn } from \"node:child_process\";\nimport fs from \"node:fs\";\nimport http from \"node:http\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { isServerRunning, waitForServer } from \"../api/util.js\";\nimport { config, ensureDataDir } from \"../config.js\";\nimport { refreshIfStale } from \"../db/pricing.js\";\nimport { logPaths, openLogFd } from \"../log.js\";\nimport { addBreadcrumb, captureException, initSentry } from \"../sentry.js\";\nimport type { HookInput } from \"./ingest.js\";\n\ndeclare const __PANOPTICON_VERSION__: string;\nfunction getAgentVersion(): string | undefined {\n return typeof __PANOPTICON_VERSION__ !== \"undefined\"\n ? __PANOPTICON_VERSION__\n : undefined;\n}\n\n// NOTE: ensureDataDir() here can recreate the data dir. This is safe because\n// logHook is only called inside runHandler(), which has an early-exit guard\n// when the data dir is missing (preventing resurrection after --purge).\nfunction logHook(message: string, meta?: Record<string, unknown>): void {\n try {\n ensureDataDir();\n const suffix = meta ? ` ${JSON.stringify(meta)}` : \"\";\n fs.appendFileSync(\n logPaths.hook,\n `${new Date().toISOString()} ${message}${suffix}\\n`,\n );\n } catch {}\n}\n\n/**\n * Atomically claim the right to start the server using O_EXCL on a lock file.\n * Returns true if this process won the race, false if another process already claimed it.\n */\nfunction acquireStartLock(): boolean {\n ensureDataDir();\n const lockFile = `${config.serverPidFile}.lock`;\n try {\n const fd = fs.openSync(\n lockFile,\n fs.constants.O_CREAT | fs.constants.O_EXCL | fs.constants.O_WRONLY,\n );\n fs.writeSync(fd, String(process.pid));\n fs.closeSync(fd);\n return true;\n } catch {\n return false;\n }\n}\n\nfunction releaseStartLock(): void {\n try {\n fs.unlinkSync(`${config.serverPidFile}.lock`);\n } catch {}\n}\n\nfunction startServer(): void {\n ensureDataDir();\n\n const serverScript = path.resolve(\n path.dirname(fileURLToPath(import.meta.url)),\n \"..\",\n \"server.js\",\n );\n\n const logFd = openLogFd(\"server\");\n\n const child = spawn(\"node\", [serverScript], {\n detached: true,\n stdio: [\"ignore\", logFd, logFd],\n env: {\n ...process.env,\n PANOPTICON_PORT: String(config.port),\n },\n });\n\n if (child.pid) {\n fs.writeFileSync(config.serverPidFile, String(child.pid));\n }\n child.unref();\n fs.closeSync(logFd);\n}\n\nasync function readStdin(): Promise<string> {\n const chunks: Buffer[] = [];\n for await (const chunk of process.stdin) {\n chunks.push(chunk as Buffer);\n }\n return Buffer.concat(chunks).toString(\"utf-8\");\n}\n\nfunction postToServer(\n data: HookInput,\n port: number,\n): Promise<Record<string, unknown>> {\n return new Promise((resolve, reject) => {\n const body = JSON.stringify(data);\n const req = http.request(\n {\n hostname: \"127.0.0.1\",\n port,\n path: \"/hooks\",\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"Content-Length\": Buffer.byteLength(body),\n },\n timeout: 5000,\n },\n (res) => {\n const chunks: Buffer[] = [];\n res.on(\"data\", (chunk: Buffer) => chunks.push(chunk));\n res.on(\"end\", () => {\n try {\n resolve(JSON.parse(Buffer.concat(chunks).toString(\"utf-8\")));\n } catch {\n resolve({});\n }\n });\n },\n );\n req.on(\"error\", reject);\n req.on(\"timeout\", () => {\n req.destroy();\n reject(new Error(\"timeout\"));\n });\n req.write(body);\n req.end();\n });\n}\n\n/** Parse CLI args: `node hook-handler [target] [port] [--proxy]` */\nfunction parseArgs(argv: string[]): {\n targetId?: string;\n port: number;\n proxy: boolean;\n} {\n const args = argv.slice(2);\n let targetId: string | undefined;\n let port = config.port;\n let proxy = false;\n\n for (const arg of args) {\n if (arg === \"--proxy\") {\n proxy = true;\n } else if (/^\\d+$/.test(arg)) {\n port = parseInt(arg, 10);\n } else if (arg && !arg.startsWith(\"-\")) {\n targetId = arg;\n }\n }\n\n return { targetId, port, proxy };\n}\n\n/**\n * Run the hook handler.\n *\n * CLI args set at install time provide:\n * - targetId: which CLI invoked us (e.g. \"gemini\", \"codex\")\n * - port: the panopticon server port to POST to\n * - proxy: whether the API proxy is active for this target\n */\nexport async function runHandler(opts: {\n targetId?: string;\n port: number;\n proxy: boolean;\n}): Promise<void> {\n // After uninstall --purge the data dir is gone. Exit silently to avoid\n // resurrecting it — hooks must never block the calling CLI.\n if (!fs.existsSync(config.dataDir)) {\n process.stdout.write(JSON.stringify({}));\n return;\n }\n\n const { targetId, port, proxy } = opts;\n\n try {\n logHook(\"hook-handler invoked\", {\n pid: process.pid,\n cwd: process.cwd(),\n pwd: process.env.PWD,\n target: targetId,\n port,\n proxy,\n });\n\n const input = await readStdin();\n if (!input.trim()) {\n logHook(\"empty stdin\");\n process.exit(0);\n }\n\n logHook(\"stdin received\", { bytes: Buffer.byteLength(input) });\n\n const data: HookInput = JSON.parse(input);\n\n // Inject context from CLI args set at install time\n if (targetId && !data.source && !data.target) {\n data.source = targetId;\n }\n if (proxy) {\n data.proxy_enabled = true;\n }\n\n const eventType = data.hook_event_name ?? \"Unknown\";\n logHook(\"event parsed\", {\n eventType,\n sessionId: data.session_id,\n toolName: data.tool_name,\n source: data.source,\n });\n\n addBreadcrumb(\"hook-handler\", `Processing ${eventType}`, {\n session_id: data.session_id,\n tool_name: data.tool_name,\n source: data.source,\n });\n\n // On SessionStart, ensure the unified server is running. This is the\n // only event that triggers server startup — all other events POST to\n // the already-running server and silently drop if it's unreachable.\n // The server process outlives any single session and serves all\n // concurrent ones. Uses an atomic lock file (O_EXCL) to prevent two\n // concurrent hook invocations from both spawning a server (TOCTOU race).\n if (eventType === \"SessionStart\" || eventType === \"session_start\") {\n const serverRunning = isServerRunning();\n logHook(\"session start\", { serverRunning });\n if (!serverRunning) {\n if (acquireStartLock()) {\n try {\n logHook(\"starting server (lock acquired)\");\n startServer();\n const ready = await waitForServer(port);\n logHook(\"server readiness\", { ready });\n } finally {\n releaseStartLock();\n }\n } else {\n // Another hook handler is starting the server — wait for it\n logHook(\"waiting for server (another handler starting)\");\n const ready = await waitForServer(port);\n logHook(\"server readiness (waited)\", { ready });\n }\n }\n refreshIfStale().catch(() => {});\n }\n\n // Tag with agent version for observability\n const agentVersion = getAgentVersion();\n if (agentVersion) data.agent_version = agentVersion;\n\n // Capture shell PWD (prefer what Claude Code sends over handler's own PWD)\n if (!data.shell_pwd) {\n const shellPwd = process.env.PWD ?? undefined;\n if (shellPwd) data.shell_pwd = shellPwd;\n }\n\n // Post to the panopticon server. If unreachable, drop the event —\n // direct DB writes add latency, risk lock contention, and mask a\n // misconfigured server. The server auto-starts on SessionStart above.\n let result: Record<string, unknown>;\n try {\n logHook(\"posting to server\", { port });\n result = await postToServer(data, port);\n logHook(\"server post succeeded\", { resultKeys: Object.keys(result) });\n } catch {\n logHook(\"server post failed, dropping event\");\n result = {};\n }\n\n process.stdout.write(JSON.stringify(result));\n logHook(\"response written\", {\n bytes: Buffer.byteLength(JSON.stringify(result)),\n });\n } catch (err) {\n // Silently fail — hooks must not block the calling CLI\n const errorMessage = err instanceof Error ? err.message : String(err);\n logHook(\"hook-handler failed\", { error: errorMessage });\n captureException(err, { component: \"hook-handler\", event_type: \"unknown\" });\n if (process.env.PANOPTICON_DEBUG) {\n console.error(\"panopticon hook error:\", err);\n }\n process.stdout.write(JSON.stringify({ error: \"panopticon hook failed\" }));\n }\n}\n\ninitSentry();\n// CLI args are set at install time: `node hook-handler <target> <port> [--proxy]`\n// When invoked without args (e.g. by Claude Code's plugin system), falls back\n// to config defaults and server-side target detection.\nrunHandler(parseArgs(process.argv));\n","/**\n * Shared utilities for communicating with the panopticon server.\n * Extracted from hooks/handler.ts so both the hook handler and the\n * API client can reuse them.\n */\nimport fs from \"node:fs\";\nimport http from \"node:http\";\nimport { config } from \"../config.js\";\n\n/** Check if the server process is running via PID file. */\nexport function isServerRunning(): boolean {\n if (!fs.existsSync(config.serverPidFile)) return false;\n const pid = parseInt(\n fs.readFileSync(config.serverPidFile, \"utf-8\").trim(),\n 10,\n );\n try {\n process.kill(pid, 0);\n return true;\n } catch {\n try {\n fs.unlinkSync(config.serverPidFile);\n } catch {}\n return false;\n }\n}\n\n/** Poll the server until it responds or timeout (default 3s). */\nexport async function waitForServer(\n port: number,\n timeoutMs = 3000,\n): Promise<boolean> {\n const start = Date.now();\n const interval = 50;\n while (Date.now() - start < timeoutMs) {\n try {\n await new Promise<void>((resolve, reject) => {\n const req = http.request(\n {\n hostname: \"127.0.0.1\",\n port,\n path: \"/health\",\n method: \"GET\",\n timeout: 500,\n },\n (res) => {\n res.resume();\n resolve();\n },\n );\n req.on(\"error\", reject);\n req.on(\"timeout\", () => {\n req.destroy();\n reject(new Error(\"timeout\"));\n });\n req.end();\n });\n return true;\n } catch {\n await new Promise((r) => setTimeout(r, interval));\n }\n }\n return false;\n}\n"],"mappings":"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","names":["fs","http","fs","http"]}
@@ -0,0 +1,57 @@
1
+ export { c as config, e as ensureDataDir } from './config-NwoZC-GM.js';
2
+ export { refreshPricing } from './pricing.js';
3
+ export { autoPrune, pruneEstimate, pruneExecute } from './prune.js';
4
+ export { activitySummary, costBreakdown, dbStats, listPlans, listSessions, print, rawQuery, search, sessionTimeline } from './query.js';
5
+ export { HookEventRow, OtelLogRow, OtelMetricRow, closeDb, getDb } from './db.js';
6
+ import { S as SyncTarget, a as SyncFilter } from './types-D-MYCBol.js';
7
+ export { CheckResult, DoctorResult, RecentError, RecentEvent, doctor } from './doctor.js';
8
+ export { permissionsApply, permissionsShow } from './permissions.js';
9
+ export { RepoInfo, resolveRepoFromCwd } from './repo.js';
10
+ export { ClaudeCodeConfig, ConfigLayer, readConfig, writeFile, writeSettings } from './scanner.js';
11
+ export { createUnifiedServer } from './server.js';
12
+ export { ShellEnvOptions, configureShellEnv, fetchPricing, initDb } from './setup.js';
13
+ export { ActivitySessionDetail, ActivitySummaryResult, ChildSession, SearchMatch, SearchResult, Session, SessionListResult, SessionTimelineResult, SpendingGroup, SpendingResult, TimelineMessage, TimelineToolCall } from './types.js';
14
+ import 'better-sqlite3';
15
+ import 'zod';
16
+ import 'node:http';
17
+
18
+ interface RetentionConfig {
19
+ maxAgeDays: number;
20
+ maxSizeMb: number;
21
+ /** Delete synced rows older than this many days. Undefined = disabled. */
22
+ syncedMaxAgeDays?: number;
23
+ }
24
+ interface UnifiedConfig {
25
+ /** Whether panopticon hooks are installed (plugin mode). When true, OTLP sync
26
+ * filters out body types that hooks already cover to avoid double-counting. */
27
+ hooksInstalled?: boolean;
28
+ /** Sentry DSN for error reporting. When set, uncaught exceptions and key
29
+ * error paths are reported to Sentry. */
30
+ sentryDsn?: string;
31
+ sync: {
32
+ targets: SyncTarget[];
33
+ filter?: SyncFilter;
34
+ };
35
+ retention: RetentionConfig;
36
+ }
37
+ declare function loadUnifiedConfig(): UnifiedConfig;
38
+ declare function saveUnifiedConfig(cfg: UnifiedConfig): void;
39
+ declare function loadRetentionConfig(): RetentionConfig;
40
+
41
+ interface SyncPruneResult {
42
+ hook_events: number;
43
+ otel_logs: number;
44
+ otel_metrics: number;
45
+ }
46
+ /**
47
+ * Aggressively prune rows that have been confirmed synced to ALL targets
48
+ * and are older than `syncedMaxAgeDays`.
49
+ *
50
+ * No-op when:
51
+ * - No sync targets configured
52
+ * - `syncedMaxAgeDays` is not set
53
+ * - Any target has watermark 0 for a given table (hasn't completed first sync)
54
+ */
55
+ declare function syncAwarePrune(targets: SyncTarget[], retention: RetentionConfig): SyncPruneResult;
56
+
57
+ export { type RetentionConfig, type UnifiedConfig, loadRetentionConfig, loadUnifiedConfig, saveUnifiedConfig, syncAwarePrune };
package/dist/index.js ADDED
@@ -0,0 +1,101 @@
1
+ import {
2
+ permissionsApply,
3
+ permissionsShow
4
+ } from "./chunk-TGXFVAID.js";
5
+ import {
6
+ createUnifiedServer,
7
+ syncAwarePrune
8
+ } from "./chunk-WLBNFVIG.js";
9
+ import "./chunk-XLTCUH5A.js";
10
+ import "./chunk-RX2RXHBH.js";
11
+ import "./chunk-HQCY722C.js";
12
+ import "./chunk-NXH7AONS.js";
13
+ import "./chunk-BVOE7A2Z.js";
14
+ import {
15
+ resolveRepoFromCwd
16
+ } from "./chunk-YVRWVDIA.js";
17
+ import {
18
+ autoPrune,
19
+ pruneEstimate,
20
+ pruneExecute
21
+ } from "./chunk-HRCEIYKU.js";
22
+ import {
23
+ readConfig,
24
+ writeFile,
25
+ writeSettings
26
+ } from "./chunk-3BUJ7URA.js";
27
+ import "./chunk-CF4GPWLI.js";
28
+ import "./chunk-7Q3BJMLG.js";
29
+ import {
30
+ configureShellEnv,
31
+ fetchPricing,
32
+ initDb
33
+ } from "./chunk-L7G27XWF.js";
34
+ import {
35
+ refreshPricing
36
+ } from "./chunk-3TZAKV3M.js";
37
+ import {
38
+ doctor
39
+ } from "./chunk-SUGSQ4YI.js";
40
+ import "./chunk-SEXU2WYG.js";
41
+ import {
42
+ loadRetentionConfig,
43
+ loadUnifiedConfig,
44
+ saveUnifiedConfig
45
+ } from "./chunk-QK5442ZP.js";
46
+ import {
47
+ activitySummary,
48
+ costBreakdown,
49
+ dbStats,
50
+ listPlans,
51
+ listSessions,
52
+ print,
53
+ rawQuery,
54
+ search,
55
+ sessionTimeline
56
+ } from "./chunk-LWXF7YRG.js";
57
+ import "./chunk-ZEC4LRKS.js";
58
+ import "./chunk-QVK6VGCV.js";
59
+ import {
60
+ closeDb,
61
+ getDb
62
+ } from "./chunk-DZ5HJFB4.js";
63
+ import {
64
+ config,
65
+ ensureDataDir
66
+ } from "./chunk-K7YUPLES.js";
67
+ export {
68
+ activitySummary,
69
+ autoPrune,
70
+ closeDb,
71
+ config,
72
+ configureShellEnv,
73
+ costBreakdown,
74
+ createUnifiedServer,
75
+ dbStats,
76
+ doctor,
77
+ ensureDataDir,
78
+ fetchPricing,
79
+ getDb,
80
+ initDb,
81
+ listPlans,
82
+ listSessions,
83
+ loadRetentionConfig,
84
+ loadUnifiedConfig,
85
+ permissionsApply,
86
+ permissionsShow,
87
+ print,
88
+ pruneEstimate,
89
+ pruneExecute,
90
+ rawQuery,
91
+ readConfig,
92
+ refreshPricing,
93
+ resolveRepoFromCwd,
94
+ saveUnifiedConfig,
95
+ search,
96
+ sessionTimeline,
97
+ syncAwarePrune,
98
+ writeFile,
99
+ writeSettings
100
+ };
101
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1 @@
1
+ #!/usr/bin/env node
@@ -0,0 +1,243 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ activitySummary,
4
+ costBreakdown,
5
+ dbStats,
6
+ listPlans,
7
+ listSessions,
8
+ print,
9
+ rawQuery,
10
+ search,
11
+ sessionTimeline
12
+ } from "../chunk-4SM2H22C.js";
13
+ import {
14
+ log,
15
+ logPaths
16
+ } from "../chunk-7Q3BJMLG.js";
17
+ import "../chunk-K7YUPLES.js";
18
+
19
+ // src/mcp/server.ts
20
+ import fs from "fs";
21
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
22
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
23
+ import { z } from "zod";
24
+ var server = new McpServer({
25
+ name: "panopticon",
26
+ version: "0.1.0"
27
+ });
28
+ server.tool(
29
+ "sessions",
30
+ "List recent sessions with stats (tokens, cost, model, project)",
31
+ {
32
+ limit: z.number().optional().describe("Max sessions to return (default 20)"),
33
+ since: z.string().optional().describe('Time filter: ISO date or relative like "24h", "7d", "30m"')
34
+ },
35
+ async ({ limit, since }) => {
36
+ const results = await listSessions({ limit, since });
37
+ return {
38
+ content: [
39
+ { type: "text", text: JSON.stringify(results, null, 2) }
40
+ ]
41
+ };
42
+ }
43
+ );
44
+ server.tool(
45
+ "timeline",
46
+ "Get messages and tool calls for a session. Includes child sessions (forks, subagents) and DAG metadata (uuid/parentUuid). Content truncated to 500 chars by default.",
47
+ {
48
+ sessionId: z.string().describe("The session ID to query"),
49
+ limit: z.number().optional().describe("Max messages to return (default 50)"),
50
+ offset: z.number().optional().describe("Number of messages to skip (for pagination)"),
51
+ fullPayloads: z.boolean().optional().describe("Return full content instead of truncated (default false)")
52
+ },
53
+ async ({ sessionId, limit, offset, fullPayloads }) => {
54
+ const result = await sessionTimeline({
55
+ sessionId,
56
+ limit,
57
+ offset,
58
+ fullPayloads
59
+ });
60
+ return {
61
+ content: [
62
+ { type: "text", text: JSON.stringify(result, null, 2) }
63
+ ]
64
+ };
65
+ }
66
+ );
67
+ server.tool(
68
+ "costs",
69
+ "Token usage and cost breakdowns from scanner data, grouped by session, model, or day",
70
+ {
71
+ since: z.string().optional().describe('Time filter: ISO date or relative like "24h", "7d"'),
72
+ groupBy: z.enum(["session", "model", "day"]).optional().describe("Group results by session, model, or day (default: session)")
73
+ },
74
+ async ({ since, groupBy }) => {
75
+ const results = await costBreakdown({ since, groupBy });
76
+ return {
77
+ content: [
78
+ { type: "text", text: JSON.stringify(results, null, 2) }
79
+ ]
80
+ };
81
+ }
82
+ );
83
+ server.tool(
84
+ "summary",
85
+ "Activity summary \u2014 sessions, prompts, tools used, files changed, and costs. Ideal for standup updates and daily reports.",
86
+ {
87
+ since: z.string().optional().describe(
88
+ 'Time window (default "24h"). ISO date or relative like "24h", "7d"'
89
+ )
90
+ },
91
+ async ({ since }) => {
92
+ const summary = await activitySummary({ since });
93
+ return {
94
+ content: [
95
+ { type: "text", text: JSON.stringify(summary, null, 2) }
96
+ ]
97
+ };
98
+ }
99
+ );
100
+ server.tool(
101
+ "plans",
102
+ "List plans created by Claude Code (from ExitPlanMode events). Returns plan markdown, allowed prompts, session ID, and timestamp.",
103
+ {
104
+ session_id: z.string().optional().describe("Filter to a specific session"),
105
+ since: z.string().optional().describe('Time filter: ISO date or relative like "24h", "7d"'),
106
+ limit: z.number().optional().describe("Max plans to return (default 20)")
107
+ },
108
+ async ({ session_id, since, limit }) => {
109
+ const plans = await listPlans({ session_id, since, limit });
110
+ return {
111
+ content: [
112
+ { type: "text", text: JSON.stringify(plans, null, 2) }
113
+ ]
114
+ };
115
+ }
116
+ );
117
+ server.tool(
118
+ "search",
119
+ "Full-text search across events and messages (FTS5). Returns matching hook events, OTel logs, and message content. Payloads truncated to 500 chars by default.",
120
+ {
121
+ query: z.string().describe("Text to search for"),
122
+ eventTypes: z.array(z.string()).optional().describe("Filter to specific event types (applies to hook events only)"),
123
+ since: z.string().optional().describe('Time filter: ISO date or relative like "24h", "7d"'),
124
+ limit: z.number().optional().describe("Max results (default 20)"),
125
+ offset: z.number().optional().describe("Number of results to skip (for pagination)"),
126
+ fullPayloads: z.boolean().optional().describe("Return full payloads instead of truncated (default false)")
127
+ },
128
+ async ({ query, eventTypes, since, limit, offset, fullPayloads }) => {
129
+ const result = await search({
130
+ query,
131
+ eventTypes,
132
+ since,
133
+ limit,
134
+ offset,
135
+ fullPayloads
136
+ });
137
+ return {
138
+ content: [
139
+ { type: "text", text: JSON.stringify(result, null, 2) }
140
+ ]
141
+ };
142
+ }
143
+ );
144
+ server.tool(
145
+ "get",
146
+ "Get full details for a record by source and ID. Returns complete content without truncation.",
147
+ {
148
+ source: z.enum(["hook", "otel", "message"]).describe(
149
+ "Record source: 'hook' for hook events, 'otel' for OTel logs, 'message' for parsed messages"
150
+ ),
151
+ id: z.number().describe("Record ID from search/timeline results")
152
+ },
153
+ async ({ source, id }) => {
154
+ const result = await print({ source, id });
155
+ if (!result) {
156
+ return {
157
+ content: [
158
+ {
159
+ type: "text",
160
+ text: `No ${source} record found with id ${id}`
161
+ }
162
+ ],
163
+ isError: true
164
+ };
165
+ }
166
+ return {
167
+ content: [
168
+ { type: "text", text: JSON.stringify(result, null, 2) }
169
+ ]
170
+ };
171
+ }
172
+ );
173
+ server.tool(
174
+ "query",
175
+ `Execute a read-only SQL query against the panopticon database.
176
+
177
+ Schema:
178
+ sessions(session_id PK, target, started_at_ms, ended_at_ms, first_prompt, permission_mode, agent_version, model, cli_version, scanner_file_path, total_input_tokens, total_output_tokens, total_cache_read_tokens, total_cache_creation_tokens, total_reasoning_tokens, turn_count, otel_input_tokens, otel_output_tokens, otel_cache_read_tokens, otel_cache_creation_tokens, models, has_hooks, has_otel, has_scanner, summary, summary_version, message_count, user_message_count, parent_session_id, relationship_type, is_automated, created_at, project, machine)
179
+ session_repositories(session_id, repository, first_seen_ms, git_user_name, git_user_email, branch)
180
+ session_cwds(session_id, cwd, first_seen_ms)
181
+ messages(id, session_id, ordinal, role, content, timestamp_ms, has_thinking, has_tool_use, content_length, is_system, model, token_usage, context_tokens, output_tokens, has_context_tokens, has_output_tokens, uuid, parent_uuid)
182
+ tool_calls(id, message_id, session_id, tool_name, category, tool_use_id, input_json, skill_name, result_content_length, result_content, subagent_session_id, duration_ms)
183
+ scanner_turns(id, session_id, source, turn_index, timestamp_ms, model, role, content_preview, input_tokens, output_tokens, cache_read_tokens, cache_creation_tokens, reasoning_tokens)
184
+ scanner_events(id, session_id, source, event_type, timestamp_ms, tool_name, tool_input, tool_output, content, metadata JSON)
185
+ session_summary_deltas(id, session_id, delta_index, created_at_ms, from_turn, to_turn, content, method)
186
+ hook_events(id, session_id, event_type, timestamp_ms, cwd, repository, tool_name, target, user_prompt, file_path, command, tool_result, plan, allowed_prompts, payload BLOB)
187
+ otel_logs(id, timestamp_ns, observed_timestamp_ns, severity_number, severity_text, body, attributes JSON, resource_attributes JSON, session_id, prompt_id, trace_id, span_id)
188
+ otel_metrics(id, timestamp_ns, name, value, metric_type, unit, attributes JSON, resource_attributes JSON, session_id)
189
+ otel_spans(id, trace_id, span_id, parent_span_id, name, kind, start_time_ns, end_time_ns, status_code, status_message, attributes JSON, resource_attributes JSON, session_id)
190
+ model_pricing(id, model_id, input_per_m, output_per_m, cache_read_per_m, cache_write_per_m, updated_ms)
191
+
192
+ Join on session_id across tables. hook_events payload is gzipped \u2014 use decompress(payload) to read. messages.uuid/parent_uuid form a DAG for conversation branching. tool_calls.duration_ms is the time between tool invocation and result.`,
193
+ {
194
+ sql: z.string().describe("SQL query (SELECT/WITH/PRAGMA only)")
195
+ },
196
+ async ({ sql }) => {
197
+ try {
198
+ const results = await rawQuery(sql);
199
+ return {
200
+ content: [
201
+ { type: "text", text: JSON.stringify(results, null, 2) }
202
+ ]
203
+ };
204
+ } catch (err) {
205
+ return {
206
+ content: [
207
+ {
208
+ type: "text",
209
+ text: `Error: ${err instanceof Error ? err.message : String(err)}`
210
+ }
211
+ ],
212
+ isError: true
213
+ };
214
+ }
215
+ }
216
+ );
217
+ server.tool(
218
+ "status",
219
+ "Show panopticon database stats: row counts for each table",
220
+ {},
221
+ async () => {
222
+ const stats = await dbStats();
223
+ return {
224
+ content: [
225
+ { type: "text", text: JSON.stringify(stats, null, 2) }
226
+ ]
227
+ };
228
+ }
229
+ );
230
+ async function main() {
231
+ const logFd = fs.openSync(logPaths.mcp, "a");
232
+ const logStream = fs.createWriteStream("", { fd: logFd });
233
+ process.stderr.write = logStream.write.bind(
234
+ logStream
235
+ );
236
+ const transport = new StdioServerTransport();
237
+ await server.connect(transport);
238
+ }
239
+ main().catch((err) => {
240
+ log.mcp.error("MCP server error:", err);
241
+ process.exit(1);
242
+ });
243
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/mcp/server.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport fs from \"node:fs\";\nimport { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport { z } from \"zod\";\nimport {\n activitySummary,\n costBreakdown,\n dbStats,\n listPlans,\n listSessions,\n print,\n rawQuery,\n search,\n sessionTimeline,\n} from \"../api/client.js\";\nimport { log, logPaths } from \"../log.js\";\n\nconst server = new McpServer({\n name: \"panopticon\",\n version: \"0.1.0\",\n});\n\nserver.tool(\n \"sessions\",\n \"List recent sessions with stats (tokens, cost, model, project)\",\n {\n limit: z\n .number()\n .optional()\n .describe(\"Max sessions to return (default 20)\"),\n since: z\n .string()\n .optional()\n .describe('Time filter: ISO date or relative like \"24h\", \"7d\", \"30m\"'),\n },\n async ({ limit, since }) => {\n const results = await listSessions({ limit, since });\n return {\n content: [\n { type: \"text\" as const, text: JSON.stringify(results, null, 2) },\n ],\n };\n },\n);\n\nserver.tool(\n \"timeline\",\n \"Get messages and tool calls for a session. Includes child sessions (forks, subagents) and DAG metadata (uuid/parentUuid). Content truncated to 500 chars by default.\",\n {\n sessionId: z.string().describe(\"The session ID to query\"),\n limit: z\n .number()\n .optional()\n .describe(\"Max messages to return (default 50)\"),\n offset: z\n .number()\n .optional()\n .describe(\"Number of messages to skip (for pagination)\"),\n fullPayloads: z\n .boolean()\n .optional()\n .describe(\"Return full content instead of truncated (default false)\"),\n },\n async ({ sessionId, limit, offset, fullPayloads }) => {\n const result = await sessionTimeline({\n sessionId,\n limit,\n offset,\n fullPayloads,\n });\n return {\n content: [\n { type: \"text\" as const, text: JSON.stringify(result, null, 2) },\n ],\n };\n },\n);\n\nserver.tool(\n \"costs\",\n \"Token usage and cost breakdowns from scanner data, grouped by session, model, or day\",\n {\n since: z\n .string()\n .optional()\n .describe('Time filter: ISO date or relative like \"24h\", \"7d\"'),\n groupBy: z\n .enum([\"session\", \"model\", \"day\"])\n .optional()\n .describe(\"Group results by session, model, or day (default: session)\"),\n },\n async ({ since, groupBy }) => {\n const results = await costBreakdown({ since, groupBy });\n return {\n content: [\n { type: \"text\" as const, text: JSON.stringify(results, null, 2) },\n ],\n };\n },\n);\n\nserver.tool(\n \"summary\",\n \"Activity summary — sessions, prompts, tools used, files changed, and costs. Ideal for standup updates and daily reports.\",\n {\n since: z\n .string()\n .optional()\n .describe(\n 'Time window (default \"24h\"). ISO date or relative like \"24h\", \"7d\"',\n ),\n },\n async ({ since }) => {\n const summary = await activitySummary({ since });\n return {\n content: [\n { type: \"text\" as const, text: JSON.stringify(summary, null, 2) },\n ],\n };\n },\n);\n\nserver.tool(\n \"plans\",\n \"List plans created by Claude Code (from ExitPlanMode events). Returns plan markdown, allowed prompts, session ID, and timestamp.\",\n {\n session_id: z.string().optional().describe(\"Filter to a specific session\"),\n since: z\n .string()\n .optional()\n .describe('Time filter: ISO date or relative like \"24h\", \"7d\"'),\n limit: z.number().optional().describe(\"Max plans to return (default 20)\"),\n },\n async ({ session_id, since, limit }) => {\n const plans = await listPlans({ session_id, since, limit });\n return {\n content: [\n { type: \"text\" as const, text: JSON.stringify(plans, null, 2) },\n ],\n };\n },\n);\n\nserver.tool(\n \"search\",\n \"Full-text search across events and messages (FTS5). Returns matching hook events, OTel logs, and message content. Payloads truncated to 500 chars by default.\",\n {\n query: z.string().describe(\"Text to search for\"),\n eventTypes: z\n .array(z.string())\n .optional()\n .describe(\"Filter to specific event types (applies to hook events only)\"),\n since: z\n .string()\n .optional()\n .describe('Time filter: ISO date or relative like \"24h\", \"7d\"'),\n limit: z.number().optional().describe(\"Max results (default 20)\"),\n offset: z\n .number()\n .optional()\n .describe(\"Number of results to skip (for pagination)\"),\n fullPayloads: z\n .boolean()\n .optional()\n .describe(\"Return full payloads instead of truncated (default false)\"),\n },\n async ({ query, eventTypes, since, limit, offset, fullPayloads }) => {\n const result = await search({\n query,\n eventTypes,\n since,\n limit,\n offset,\n fullPayloads,\n });\n return {\n content: [\n { type: \"text\" as const, text: JSON.stringify(result, null, 2) },\n ],\n };\n },\n);\n\nserver.tool(\n \"get\",\n \"Get full details for a record by source and ID. Returns complete content without truncation.\",\n {\n source: z\n .enum([\"hook\", \"otel\", \"message\"])\n .describe(\n \"Record source: 'hook' for hook events, 'otel' for OTel logs, 'message' for parsed messages\",\n ),\n id: z.number().describe(\"Record ID from search/timeline results\"),\n },\n async ({ source, id }) => {\n const result = await print({ source, id });\n if (!result) {\n return {\n content: [\n {\n type: \"text\" as const,\n text: `No ${source} record found with id ${id}`,\n },\n ],\n isError: true,\n };\n }\n return {\n content: [\n { type: \"text\" as const, text: JSON.stringify(result, null, 2) },\n ],\n };\n },\n);\n\nserver.tool(\n \"query\",\n `Execute a read-only SQL query against the panopticon database.\n\nSchema:\n sessions(session_id PK, target, started_at_ms, ended_at_ms, first_prompt, permission_mode, agent_version, model, cli_version, scanner_file_path, total_input_tokens, total_output_tokens, total_cache_read_tokens, total_cache_creation_tokens, total_reasoning_tokens, turn_count, otel_input_tokens, otel_output_tokens, otel_cache_read_tokens, otel_cache_creation_tokens, models, has_hooks, has_otel, has_scanner, summary, summary_version, message_count, user_message_count, parent_session_id, relationship_type, is_automated, created_at, project, machine)\n session_repositories(session_id, repository, first_seen_ms, git_user_name, git_user_email, branch)\n session_cwds(session_id, cwd, first_seen_ms)\n messages(id, session_id, ordinal, role, content, timestamp_ms, has_thinking, has_tool_use, content_length, is_system, model, token_usage, context_tokens, output_tokens, has_context_tokens, has_output_tokens, uuid, parent_uuid)\n tool_calls(id, message_id, session_id, tool_name, category, tool_use_id, input_json, skill_name, result_content_length, result_content, subagent_session_id, duration_ms)\n scanner_turns(id, session_id, source, turn_index, timestamp_ms, model, role, content_preview, input_tokens, output_tokens, cache_read_tokens, cache_creation_tokens, reasoning_tokens)\n scanner_events(id, session_id, source, event_type, timestamp_ms, tool_name, tool_input, tool_output, content, metadata JSON)\n session_summary_deltas(id, session_id, delta_index, created_at_ms, from_turn, to_turn, content, method)\n hook_events(id, session_id, event_type, timestamp_ms, cwd, repository, tool_name, target, user_prompt, file_path, command, tool_result, plan, allowed_prompts, payload BLOB)\n otel_logs(id, timestamp_ns, observed_timestamp_ns, severity_number, severity_text, body, attributes JSON, resource_attributes JSON, session_id, prompt_id, trace_id, span_id)\n otel_metrics(id, timestamp_ns, name, value, metric_type, unit, attributes JSON, resource_attributes JSON, session_id)\n otel_spans(id, trace_id, span_id, parent_span_id, name, kind, start_time_ns, end_time_ns, status_code, status_message, attributes JSON, resource_attributes JSON, session_id)\n model_pricing(id, model_id, input_per_m, output_per_m, cache_read_per_m, cache_write_per_m, updated_ms)\n\nJoin on session_id across tables. hook_events payload is gzipped — use decompress(payload) to read. messages.uuid/parent_uuid form a DAG for conversation branching. tool_calls.duration_ms is the time between tool invocation and result.`,\n {\n sql: z.string().describe(\"SQL query (SELECT/WITH/PRAGMA only)\"),\n },\n async ({ sql }) => {\n try {\n const results = await rawQuery(sql);\n return {\n content: [\n { type: \"text\" as const, text: JSON.stringify(results, null, 2) },\n ],\n };\n } catch (err: unknown) {\n return {\n content: [\n {\n type: \"text\" as const,\n text: `Error: ${err instanceof Error ? err.message : String(err)}`,\n },\n ],\n isError: true,\n };\n }\n },\n);\n\nserver.tool(\n \"status\",\n \"Show panopticon database stats: row counts for each table\",\n {},\n async () => {\n const stats = await dbStats();\n return {\n content: [\n { type: \"text\" as const, text: JSON.stringify(stats, null, 2) },\n ],\n };\n },\n);\n\nasync function main() {\n // Redirect stderr to log file (stdout is reserved for MCP JSON-RPC protocol)\n const logFd = fs.openSync(logPaths.mcp, \"a\");\n const logStream = fs.createWriteStream(\"\", { fd: logFd });\n process.stderr.write = logStream.write.bind(\n logStream,\n ) as typeof process.stderr.write;\n\n const transport = new StdioServerTransport();\n await server.connect(transport);\n}\n\nmain().catch((err) => {\n log.mcp.error(\"MCP server error:\", err);\n process.exit(1);\n});\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAEA,OAAO,QAAQ;AACf,SAAS,iBAAiB;AAC1B,SAAS,4BAA4B;AACrC,SAAS,SAAS;AAclB,IAAM,SAAS,IAAI,UAAU;AAAA,EAC3B,MAAM;AAAA,EACN,SAAS;AACX,CAAC;AAED,OAAO;AAAA,EACL;AAAA,EACA;AAAA,EACA;AAAA,IACE,OAAO,EACJ,OAAO,EACP,SAAS,EACT,SAAS,qCAAqC;AAAA,IACjD,OAAO,EACJ,OAAO,EACP,SAAS,EACT,SAAS,2DAA2D;AAAA,EACzE;AAAA,EACA,OAAO,EAAE,OAAO,MAAM,MAAM;AAC1B,UAAM,UAAU,MAAM,aAAa,EAAE,OAAO,MAAM,CAAC;AACnD,WAAO;AAAA,MACL,SAAS;AAAA,QACP,EAAE,MAAM,QAAiB,MAAM,KAAK,UAAU,SAAS,MAAM,CAAC,EAAE;AAAA,MAClE;AAAA,IACF;AAAA,EACF;AACF;AAEA,OAAO;AAAA,EACL;AAAA,EACA;AAAA,EACA;AAAA,IACE,WAAW,EAAE,OAAO,EAAE,SAAS,yBAAyB;AAAA,IACxD,OAAO,EACJ,OAAO,EACP,SAAS,EACT,SAAS,qCAAqC;AAAA,IACjD,QAAQ,EACL,OAAO,EACP,SAAS,EACT,SAAS,6CAA6C;AAAA,IACzD,cAAc,EACX,QAAQ,EACR,SAAS,EACT,SAAS,0DAA0D;AAAA,EACxE;AAAA,EACA,OAAO,EAAE,WAAW,OAAO,QAAQ,aAAa,MAAM;AACpD,UAAM,SAAS,MAAM,gBAAgB;AAAA,MACnC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AACD,WAAO;AAAA,MACL,SAAS;AAAA,QACP,EAAE,MAAM,QAAiB,MAAM,KAAK,UAAU,QAAQ,MAAM,CAAC,EAAE;AAAA,MACjE;AAAA,IACF;AAAA,EACF;AACF;AAEA,OAAO;AAAA,EACL;AAAA,EACA;AAAA,EACA;AAAA,IACE,OAAO,EACJ,OAAO,EACP,SAAS,EACT,SAAS,oDAAoD;AAAA,IAChE,SAAS,EACN,KAAK,CAAC,WAAW,SAAS,KAAK,CAAC,EAChC,SAAS,EACT,SAAS,4DAA4D;AAAA,EAC1E;AAAA,EACA,OAAO,EAAE,OAAO,QAAQ,MAAM;AAC5B,UAAM,UAAU,MAAM,cAAc,EAAE,OAAO,QAAQ,CAAC;AACtD,WAAO;AAAA,MACL,SAAS;AAAA,QACP,EAAE,MAAM,QAAiB,MAAM,KAAK,UAAU,SAAS,MAAM,CAAC,EAAE;AAAA,MAClE;AAAA,IACF;AAAA,EACF;AACF;AAEA,OAAO;AAAA,EACL;AAAA,EACA;AAAA,EACA;AAAA,IACE,OAAO,EACJ,OAAO,EACP,SAAS,EACT;AAAA,MACC;AAAA,IACF;AAAA,EACJ;AAAA,EACA,OAAO,EAAE,MAAM,MAAM;AACnB,UAAM,UAAU,MAAM,gBAAgB,EAAE,MAAM,CAAC;AAC/C,WAAO;AAAA,MACL,SAAS;AAAA,QACP,EAAE,MAAM,QAAiB,MAAM,KAAK,UAAU,SAAS,MAAM,CAAC,EAAE;AAAA,MAClE;AAAA,IACF;AAAA,EACF;AACF;AAEA,OAAO;AAAA,EACL;AAAA,EACA;AAAA,EACA;AAAA,IACE,YAAY,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,8BAA8B;AAAA,IACzE,OAAO,EACJ,OAAO,EACP,SAAS,EACT,SAAS,oDAAoD;AAAA,IAChE,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,kCAAkC;AAAA,EAC1E;AAAA,EACA,OAAO,EAAE,YAAY,OAAO,MAAM,MAAM;AACtC,UAAM,QAAQ,MAAM,UAAU,EAAE,YAAY,OAAO,MAAM,CAAC;AAC1D,WAAO;AAAA,MACL,SAAS;AAAA,QACP,EAAE,MAAM,QAAiB,MAAM,KAAK,UAAU,OAAO,MAAM,CAAC,EAAE;AAAA,MAChE;AAAA,IACF;AAAA,EACF;AACF;AAEA,OAAO;AAAA,EACL;AAAA,EACA;AAAA,EACA;AAAA,IACE,OAAO,EAAE,OAAO,EAAE,SAAS,oBAAoB;AAAA,IAC/C,YAAY,EACT,MAAM,EAAE,OAAO,CAAC,EAChB,SAAS,EACT,SAAS,8DAA8D;AAAA,IAC1E,OAAO,EACJ,OAAO,EACP,SAAS,EACT,SAAS,oDAAoD;AAAA,IAChE,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,0BAA0B;AAAA,IAChE,QAAQ,EACL,OAAO,EACP,SAAS,EACT,SAAS,4CAA4C;AAAA,IACxD,cAAc,EACX,QAAQ,EACR,SAAS,EACT,SAAS,2DAA2D;AAAA,EACzE;AAAA,EACA,OAAO,EAAE,OAAO,YAAY,OAAO,OAAO,QAAQ,aAAa,MAAM;AACnE,UAAM,SAAS,MAAM,OAAO;AAAA,MAC1B;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AACD,WAAO;AAAA,MACL,SAAS;AAAA,QACP,EAAE,MAAM,QAAiB,MAAM,KAAK,UAAU,QAAQ,MAAM,CAAC,EAAE;AAAA,MACjE;AAAA,IACF;AAAA,EACF;AACF;AAEA,OAAO;AAAA,EACL;AAAA,EACA;AAAA,EACA;AAAA,IACE,QAAQ,EACL,KAAK,CAAC,QAAQ,QAAQ,SAAS,CAAC,EAChC;AAAA,MACC;AAAA,IACF;AAAA,IACF,IAAI,EAAE,OAAO,EAAE,SAAS,wCAAwC;AAAA,EAClE;AAAA,EACA,OAAO,EAAE,QAAQ,GAAG,MAAM;AACxB,UAAM,SAAS,MAAM,MAAM,EAAE,QAAQ,GAAG,CAAC;AACzC,QAAI,CAAC,QAAQ;AACX,aAAO;AAAA,QACL,SAAS;AAAA,UACP;AAAA,YACE,MAAM;AAAA,YACN,MAAM,MAAM,MAAM,yBAAyB,EAAE;AAAA,UAC/C;AAAA,QACF;AAAA,QACA,SAAS;AAAA,MACX;AAAA,IACF;AACA,WAAO;AAAA,MACL,SAAS;AAAA,QACP,EAAE,MAAM,QAAiB,MAAM,KAAK,UAAU,QAAQ,MAAM,CAAC,EAAE;AAAA,MACjE;AAAA,IACF;AAAA,EACF;AACF;AAEA,OAAO;AAAA,EACL;AAAA,EACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAkBA;AAAA,IACE,KAAK,EAAE,OAAO,EAAE,SAAS,qCAAqC;AAAA,EAChE;AAAA,EACA,OAAO,EAAE,IAAI,MAAM;AACjB,QAAI;AACF,YAAM,UAAU,MAAM,SAAS,GAAG;AAClC,aAAO;AAAA,QACL,SAAS;AAAA,UACP,EAAE,MAAM,QAAiB,MAAM,KAAK,UAAU,SAAS,MAAM,CAAC,EAAE;AAAA,QAClE;AAAA,MACF;AAAA,IACF,SAAS,KAAc;AACrB,aAAO;AAAA,QACL,SAAS;AAAA,UACP;AAAA,YACE,MAAM;AAAA,YACN,MAAM,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,UAClE;AAAA,QACF;AAAA,QACA,SAAS;AAAA,MACX;AAAA,IACF;AAAA,EACF;AACF;AAEA,OAAO;AAAA,EACL;AAAA,EACA;AAAA,EACA,CAAC;AAAA,EACD,YAAY;AACV,UAAM,QAAQ,MAAM,QAAQ;AAC5B,WAAO;AAAA,MACL,SAAS;AAAA,QACP,EAAE,MAAM,QAAiB,MAAM,KAAK,UAAU,OAAO,MAAM,CAAC,EAAE;AAAA,MAChE;AAAA,IACF;AAAA,EACF;AACF;AAEA,eAAe,OAAO;AAEpB,QAAM,QAAQ,GAAG,SAAS,SAAS,KAAK,GAAG;AAC3C,QAAM,YAAY,GAAG,kBAAkB,IAAI,EAAE,IAAI,MAAM,CAAC;AACxD,UAAQ,OAAO,QAAQ,UAAU,MAAM;AAAA,IACrC;AAAA,EACF;AAEA,QAAM,YAAY,IAAI,qBAAqB;AAC3C,QAAM,OAAO,QAAQ,SAAS;AAChC;AAEA,KAAK,EAAE,MAAM,CAAC,QAAQ;AACpB,MAAI,IAAI,MAAM,qBAAqB,GAAG;AACtC,UAAQ,KAAK,CAAC;AAChB,CAAC;","names":[]}
@@ -0,0 +1,7 @@
1
+ import http from 'node:http';
2
+
3
+ /** Handle an OTLP ingest request (logs, metrics, traces). */
4
+ declare function handleOtlpRequest(req: http.IncomingMessage, res: http.ServerResponse): Promise<void>;
5
+ declare function createOtlpServer(): http.Server;
6
+
7
+ export { createOtlpServer, handleOtlpRequest };
@@ -0,0 +1,17 @@
1
+ import {
2
+ createOtlpServer,
3
+ handleOtlpRequest
4
+ } from "../chunk-XLTCUH5A.js";
5
+ import "../chunk-BVOE7A2Z.js";
6
+ import "../chunk-CF4GPWLI.js";
7
+ import "../chunk-7Q3BJMLG.js";
8
+ import "../chunk-3TZAKV3M.js";
9
+ import "../chunk-ZEC4LRKS.js";
10
+ import "../chunk-QVK6VGCV.js";
11
+ import "../chunk-DZ5HJFB4.js";
12
+ import "../chunk-K7YUPLES.js";
13
+ export {
14
+ createOtlpServer,
15
+ handleOtlpRequest
16
+ };
17
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,33 @@
1
+ import { z } from 'zod';
2
+
3
+ declare function permissionsShow(): {
4
+ approvals: any;
5
+ approvals_path: string;
6
+ allowed: any;
7
+ allowed_path: string;
8
+ };
9
+ declare const categorySchema: z.ZodObject<{
10
+ status: z.ZodEnum<{
11
+ approved: "approved";
12
+ denied: "denied";
13
+ skipped: "skipped";
14
+ }>;
15
+ patterns: z.ZodArray<z.ZodString>;
16
+ observed_commands: z.ZodArray<z.ZodString>;
17
+ call_count: z.ZodNumber;
18
+ }, z.core.$strip>;
19
+ type CategoryEntry = z.infer<typeof categorySchema>;
20
+ interface PermissionsApplyParams {
21
+ repository?: string;
22
+ approved_categories: string[];
23
+ denied_categories: string[];
24
+ custom_overrides?: Record<string, string>;
25
+ permissions: string[];
26
+ categories: Record<string, CategoryEntry>;
27
+ }
28
+ declare function permissionsApply({ repository, approved_categories, denied_categories, custom_overrides, permissions, categories, }: PermissionsApplyParams): {
29
+ success: true;
30
+ details: string[];
31
+ };
32
+
33
+ export { type CategoryEntry, type PermissionsApplyParams, categorySchema, permissionsApply, permissionsShow };
@@ -0,0 +1,14 @@
1
+ import {
2
+ categorySchema,
3
+ permissionsApply,
4
+ permissionsShow
5
+ } from "./chunk-TGXFVAID.js";
6
+ import "./chunk-ZEC4LRKS.js";
7
+ import "./chunk-QVK6VGCV.js";
8
+ import "./chunk-K7YUPLES.js";
9
+ export {
10
+ categorySchema,
11
+ permissionsApply,
12
+ permissionsShow
13
+ };
14
+ //# sourceMappingURL=permissions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,29 @@
1
+ interface ModelPricing {
2
+ input: number;
3
+ output: number;
4
+ cache_read: number;
5
+ cache_write: number;
6
+ }
7
+ interface PricingCache {
8
+ updated: string;
9
+ models: Record<string, ModelPricing>;
10
+ }
11
+ /**
12
+ * Fetch pricing from LiteLLM, save to disk cache, and upsert into SQLite.
13
+ * Models are keyed by their LiteLLM ID (e.g. "claude-opus-4-6").
14
+ */
15
+ declare function refreshPricing(): Promise<PricingCache | null>;
16
+ /** Refresh pricing if cache is missing or older than 24h. */
17
+ declare function refreshIfStale(): Promise<void>;
18
+ /**
19
+ * SQL expression that computes cost for a row with (model, token_type, tokens) columns.
20
+ * Looks up the best matching model in the model_pricing table by longest prefix match.
21
+ */
22
+ /**
23
+ * SQL expression that computes cost for a row with (model, token_type, tokens) columns.
24
+ * Looks up the best matching model in the model_pricing table by longest prefix match,
25
+ * using the most recent price entry (highest updated_ms) for that model.
26
+ */
27
+ declare const COST_EXPR = "\n tokens * COALESCE((\n SELECT CASE token_type\n WHEN 'input' THEN mp.input_per_m\n WHEN 'output' THEN mp.output_per_m\n WHEN 'cacheRead' THEN mp.cache_read_per_m\n WHEN 'cacheWrite' THEN mp.cache_write_per_m\n ELSE 0\n END\n FROM model_pricing mp\n WHERE model LIKE mp.model_id || '%'\n ORDER BY LENGTH(mp.model_id) DESC, mp.updated_ms DESC\n LIMIT 1\n ), 0) / 1000000.0";
28
+
29
+ export { COST_EXPR, refreshIfStale, refreshPricing };
@@ -0,0 +1,13 @@
1
+ import {
2
+ COST_EXPR,
3
+ refreshIfStale,
4
+ refreshPricing
5
+ } from "./chunk-3TZAKV3M.js";
6
+ import "./chunk-DZ5HJFB4.js";
7
+ import "./chunk-K7YUPLES.js";
8
+ export {
9
+ COST_EXPR,
10
+ refreshIfStale,
11
+ refreshPricing
12
+ };
13
+ //# sourceMappingURL=pricing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,10 @@
1
+ import * as node_stream from 'node:stream';
2
+ import http from 'node:http';
3
+
4
+ declare function tunnelWebSocket(req: http.IncomingMessage, clientSocket: node_stream.Duplex, head: Buffer): void;
5
+ /** Handle a proxy API request. Expects the URL to have a target prefix. */
6
+ declare function handleProxyRequest(req: http.IncomingMessage, res: http.ServerResponse): Promise<void>;
7
+
8
+ declare function createProxyServer(): http.Server;
9
+
10
+ export { createProxyServer, handleProxyRequest, tunnelWebSocket };
@@ -0,0 +1,20 @@
1
+ import {
2
+ createProxyServer,
3
+ handleProxyRequest,
4
+ tunnelWebSocket
5
+ } from "../chunk-RX2RXHBH.js";
6
+ import "../chunk-BVOE7A2Z.js";
7
+ import "../chunk-YVRWVDIA.js";
8
+ import "../chunk-3BUJ7URA.js";
9
+ import "../chunk-CF4GPWLI.js";
10
+ import "../chunk-7Q3BJMLG.js";
11
+ import "../chunk-ZEC4LRKS.js";
12
+ import "../chunk-QVK6VGCV.js";
13
+ import "../chunk-DZ5HJFB4.js";
14
+ import "../chunk-K7YUPLES.js";
15
+ export {
16
+ createProxyServer,
17
+ handleProxyRequest,
18
+ tunnelWebSocket
19
+ };
20
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}