devrager 0.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +988 -0
- package/dist/cli.js.map +7 -0
- package/dist/lib/adapters/amp.d.ts +3 -0
- package/dist/lib/adapters/amp.d.ts.map +1 -0
- package/dist/lib/adapters/amp.js +74 -0
- package/dist/lib/adapters/amp.js.map +1 -0
- package/dist/lib/adapters/claude.d.ts +3 -0
- package/dist/lib/adapters/claude.d.ts.map +1 -0
- package/dist/lib/adapters/claude.js +137 -0
- package/dist/lib/adapters/claude.js.map +1 -0
- package/dist/lib/adapters/cline.d.ts +3 -0
- package/dist/lib/adapters/cline.d.ts.map +1 -0
- package/dist/lib/adapters/cline.js +122 -0
- package/dist/lib/adapters/cline.js.map +1 -0
- package/dist/lib/adapters/codex.d.ts +3 -0
- package/dist/lib/adapters/codex.d.ts.map +1 -0
- package/dist/lib/adapters/codex.js +99 -0
- package/dist/lib/adapters/codex.js.map +1 -0
- package/dist/lib/adapters/index.d.ts +17 -0
- package/dist/lib/adapters/index.d.ts.map +1 -0
- package/dist/lib/adapters/index.js +27 -0
- package/dist/lib/adapters/index.js.map +1 -0
- package/dist/lib/adapters/opencode.d.ts +3 -0
- package/dist/lib/adapters/opencode.d.ts.map +1 -0
- package/dist/lib/adapters/opencode.js +86 -0
- package/dist/lib/adapters/opencode.js.map +1 -0
- package/dist/lib/adapters/pi.d.ts +3 -0
- package/dist/lib/adapters/pi.d.ts.map +1 -0
- package/dist/lib/adapters/pi.js +112 -0
- package/dist/lib/adapters/pi.js.map +1 -0
- package/dist/lib/adapters/zed.d.ts +3 -0
- package/dist/lib/adapters/zed.d.ts.map +1 -0
- package/dist/lib/adapters/zed.js +156 -0
- package/dist/lib/adapters/zed.js.map +1 -0
- package/dist/lib/detector/index.d.ts +32 -0
- package/dist/lib/detector/index.d.ts.map +1 -0
- package/dist/lib/detector/index.js +224 -0
- package/dist/lib/detector/index.js.map +1 -0
- package/dist/lib/index.d.ts +3 -0
- package/dist/lib/index.d.ts.map +1 -0
- package/dist/lib/index.js +3 -0
- package/dist/lib/index.js.map +1 -0
- package/package.json +40 -0
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/adapters/amp.ts", "../src/adapters/claude.ts", "../src/adapters/cline.ts", "../src/adapters/codex.ts", "../src/adapters/opencode.ts", "../src/adapters/pi.ts", "../src/adapters/zed.ts", "../src/adapters/index.ts", "../src/detector/index.ts", "../src/commands/scan.ts", "../src/cli.ts"],
|
|
4
|
+
"sourcesContent": ["import { readdir, readFile } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport type { Adapter, AdapterOptions, Message } from \"./index\";\n\n/**\n * Amp (Sourcegraph) stores threads as JSON files at:\n * ~/.local/share/amp/threads/<thread-id>.json\n *\n * Each file is a JSON object with a `messages` array:\n * { \"messages\": [{ \"role\": \"user\"|\"assistant\", \"content\": \"...\", ... }], \"usageLedger\": {...}, ... }\n *\n * Messages have `role`, `content` (string or array), and optionally a timestamp.\n */\n\nfunction getAmpThreadsDir(): string {\n return join(\n process.env[\"XDG_DATA_HOME\"] ?? join(homedir(), \".local\", \"share\"),\n \"amp\",\n \"threads\",\n );\n}\n\nexport function ampAdapter(): Adapter {\n return {\n name: \"amp\",\n async *messages(options?: AdapterOptions): AsyncGenerator<Message> {\n const threadsDir = getAmpThreadsDir();\n\n let files: string[];\n try {\n files = await readdir(threadsDir);\n } catch {\n return; // Amp not installed or no threads\n }\n\n const jsonFiles = files.filter((f) => f.endsWith(\".json\"));\n\n for (const file of jsonFiles) {\n const filePath = join(threadsDir, file);\n const threadId = file.replace(\".json\", \"\");\n\n try {\n const raw = await readFile(filePath, \"utf-8\");\n const thread = JSON.parse(raw) as AmpThread;\n\n if (!thread.messages || !Array.isArray(thread.messages)) continue;\n\n for (const msg of thread.messages) {\n if (msg.role !== \"user\") continue;\n\n const text = extractText(msg.content);\n if (!text) continue;\n\n const timestamp = msg.timestamp ?? msg.createdAt ?? undefined;\n if (options?.since && timestamp) {\n const ts = new Date(timestamp);\n if (ts < options.since) continue;\n }\n\n yield {\n text,\n timestamp,\n session: threadId,\n };\n }\n } catch {\n // Skip malformed files\n }\n }\n },\n };\n}\n\nfunction extractText(content: unknown): string | null {\n if (typeof content === \"string\") return content;\n if (Array.isArray(content)) {\n const parts = content\n .filter(\n (p): p is { type: string; text: string } =>\n typeof p === \"object\" && p !== null && typeof p.text === \"string\",\n )\n .map((p) => p.text);\n return parts.length > 0 ? parts.join(\" \") : null;\n }\n return null;\n}\n\ninterface AmpMessage {\n role?: string;\n content?: unknown;\n timestamp?: string;\n createdAt?: string;\n}\n\ninterface AmpThread {\n messages?: AmpMessage[];\n}\n", "import { createReadStream } from \"node:fs\";\nimport { readdir, stat } from \"node:fs/promises\";\nimport { createInterface } from \"node:readline\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport type { Adapter, AdapterOptions, Message } from \"./index\";\n\n/**\n * Claude Code stores sessions as JSONL files at:\n * ~/.claude/projects/<project-path>/<session-uuid>.jsonl\n *\n * Each line is a JSON object. User messages have:\n * { \"type\": \"human\", \"message\": { \"content\": [...] } }\n * or sometimes:\n * { \"role\": \"user\", \"content\": \"...\" }\n */\n\nconst CLAUDE_DIR = join(homedir(), \".claude\", \"projects\");\n\nexport function claudeAdapter(): Adapter {\n return {\n name: \"claude\",\n async *messages(options?: AdapterOptions): AsyncGenerator<Message> {\n const projectsDir = CLAUDE_DIR;\n\n let projectDirs: string[];\n try {\n projectDirs = await readdir(projectsDir);\n } catch {\n return; // Claude Code not installed or no sessions\n }\n\n for (const projectDir of projectDirs) {\n const projectPath = join(projectsDir, projectDir);\n const projectStat = await stat(projectPath);\n if (!projectStat.isDirectory()) continue;\n\n const entries = await readdir(projectPath);\n const jsonlFiles = entries.filter((f) => f.endsWith(\".jsonl\"));\n\n for (const file of jsonlFiles) {\n const filePath = join(projectPath, file);\n const session = file.replace(\".jsonl\", \"\");\n\n yield* parseClaudeJsonl(filePath, {\n session,\n project: projectDir,\n since: options?.since,\n });\n }\n\n // Also check for subagent JSONL files in session subdirectories\n const subdirs = entries.filter((f) => !f.includes(\".\"));\n for (const subdir of subdirs) {\n const subagentsDir = join(projectPath, subdir, \"subagents\");\n try {\n const subFiles = await readdir(subagentsDir);\n const subJsonl = subFiles.filter((f) => f.endsWith(\".jsonl\"));\n for (const file of subJsonl) {\n yield* parseClaudeJsonl(join(subagentsDir, file), {\n session: `${subdir}/${file.replace(\".jsonl\", \"\")}`,\n project: projectDir,\n since: options?.since,\n });\n }\n } catch {\n // No subagents directory, skip\n }\n }\n }\n },\n };\n}\n\nasync function* parseClaudeJsonl(\n filePath: string,\n context: { session: string; project: string; since?: Date },\n): AsyncGenerator<Message> {\n const rl = createInterface({\n input: createReadStream(filePath, { encoding: \"utf-8\" }),\n crlfDelay: Infinity,\n });\n\n for await (const line of rl) {\n if (!line.trim()) continue;\n\n try {\n const entry = JSON.parse(line) as Record<string, unknown>;\n const text = extractUserText(entry);\n if (!text) continue;\n\n const timestamp = extractTimestamp(entry);\n if (context.since && timestamp) {\n const ts = new Date(timestamp);\n if (ts < context.since) continue;\n }\n\n yield {\n text,\n timestamp: timestamp ?? undefined,\n session: context.session,\n project: context.project,\n };\n } catch {\n // Skip malformed lines\n }\n }\n}\n\nfunction extractUserText(entry: Record<string, unknown>): string | null {\n // Format: { \"type\": \"user\", \"message\": { \"role\": \"user\", \"content\": \"...\" } }\n if (entry[\"type\"] === \"user\") {\n const message = entry[\"message\"] as Record<string, unknown> | undefined;\n if (!message) return null;\n return contentToString(message[\"content\"]);\n }\n\n // Legacy format: { \"type\": \"human\", \"message\": { \"content\": [...] } }\n if (entry[\"type\"] === \"human\") {\n const message = entry[\"message\"] as Record<string, unknown> | undefined;\n if (!message) return null;\n return contentToString(message[\"content\"]);\n }\n\n // Flat format: { \"role\": \"user\", \"content\": \"...\" }\n if (entry[\"role\"] === \"user\") {\n return contentToString(entry[\"content\"]);\n }\n\n return null;\n}\n\nfunction contentToString(content: unknown): string | null {\n if (typeof content === \"string\") return content;\n if (Array.isArray(content)) {\n const parts = content\n .filter(\n (p): p is { type: string; text: string } =>\n typeof p === \"object\" && p !== null && p.type === \"text\",\n )\n .map((p) => p.text);\n return parts.length > 0 ? parts.join(\" \") : null;\n }\n return null;\n}\n\nfunction extractTimestamp(entry: Record<string, unknown>): string | null {\n if (typeof entry[\"timestamp\"] === \"string\") return entry[\"timestamp\"];\n if (typeof entry[\"createdAt\"] === \"string\") return entry[\"createdAt\"];\n return null;\n}\n", "import { readdir, readFile, stat } from \"node:fs/promises\";\nimport { existsSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport type { Adapter, AdapterOptions, Message } from \"./index\";\n\n/**\n * Cline (formerly Claude Dev) stores task history at:\n *\n * VS Code extension:\n * macOS: ~/Library/Application Support/Code/User/globalStorage/saoudrizwan.claude-dev/tasks/<task-id>/api_conversation_history.json\n * Linux: ~/.config/Code/User/globalStorage/saoudrizwan.claude-dev/tasks/<task-id>/api_conversation_history.json\n * Windows: %APPDATA%/Code/User/globalStorage/saoudrizwan.claude-dev/tasks/<task-id>/api_conversation_history.json\n *\n * Standalone CLI / JetBrains (newer):\n * ~/.cline/data/tasks/<task-id>/api_conversation_history.json\n *\n * Roo Code (fork) uses the same format at:\n * globalStorage/rooveterinaryinc.roo-cline/tasks/<task-id>/api_conversation_history.json\n *\n * Each api_conversation_history.json is a JSON array of messages:\n * [{ \"role\": \"user\"|\"assistant\", \"content\": \"...\" | [{type: \"text\", text: \"...\"}] }]\n */\n\nfunction getClineTaskDirs(): string[] {\n const dirs: string[] = [];\n\n // VS Code extension paths\n const vscodePaths = getVSCodeGlobalStoragePaths();\n const extensionIds = [\"saoudrizwan.claude-dev\", \"rooveterinaryinc.roo-cline\"];\n\n for (const basePath of vscodePaths) {\n for (const extId of extensionIds) {\n const tasksDir = join(basePath, extId, \"tasks\");\n if (existsSync(tasksDir)) dirs.push(tasksDir);\n }\n }\n\n // Standalone CLI path\n const clineStandalone = join(homedir(), \".cline\", \"data\", \"tasks\");\n if (existsSync(clineStandalone)) dirs.push(clineStandalone);\n\n return dirs;\n}\n\nfunction getVSCodeGlobalStoragePaths(): string[] {\n const paths: string[] = [];\n\n if (process.platform === \"darwin\") {\n paths.push(\n join(homedir(), \"Library\", \"Application Support\", \"Code\", \"User\", \"globalStorage\"),\n join(homedir(), \"Library\", \"Application Support\", \"Code - Insiders\", \"User\", \"globalStorage\"),\n join(homedir(), \"Library\", \"Application Support\", \"Cursor\", \"User\", \"globalStorage\"),\n );\n } else if (process.platform === \"linux\") {\n const configBase = process.env[\"XDG_CONFIG_HOME\"] ?? join(homedir(), \".config\");\n paths.push(\n join(configBase, \"Code\", \"User\", \"globalStorage\"),\n join(configBase, \"Code - Insiders\", \"User\", \"globalStorage\"),\n join(configBase, \"Cursor\", \"User\", \"globalStorage\"),\n );\n } else {\n // Windows\n const appData = process.env[\"APPDATA\"] ?? join(homedir(), \"AppData\", \"Roaming\");\n paths.push(\n join(appData, \"Code\", \"User\", \"globalStorage\"),\n join(appData, \"Code - Insiders\", \"User\", \"globalStorage\"),\n join(appData, \"Cursor\", \"User\", \"globalStorage\"),\n );\n }\n\n return paths;\n}\n\nexport function clineAdapter(): Adapter {\n return {\n name: \"cline\",\n async *messages(options?: AdapterOptions): AsyncGenerator<Message> {\n const taskDirs = getClineTaskDirs();\n\n for (const tasksDir of taskDirs) {\n let taskIds: string[];\n try {\n taskIds = await readdir(tasksDir);\n } catch {\n continue;\n }\n\n for (const taskId of taskIds) {\n const taskDir = join(tasksDir, taskId);\n const taskStat = await stat(taskDir).catch(() => null);\n if (!taskStat?.isDirectory()) continue;\n\n const historyFile = join(taskDir, \"api_conversation_history.json\");\n\n try {\n const raw = await readFile(historyFile, \"utf-8\");\n const messages = JSON.parse(raw) as ClineMessage[];\n\n if (!Array.isArray(messages)) continue;\n\n for (const msg of messages) {\n if (msg.role !== \"user\") continue;\n\n const text = extractText(msg.content);\n if (!text) continue;\n\n // Cline doesn't store per-message timestamps in the conversation file\n // Use the task metadata file for approximate timing\n const timestamp = msg.ts ?? undefined;\n if (options?.since && timestamp) {\n const ts = new Date(timestamp);\n if (ts < options.since) continue;\n }\n\n yield {\n text,\n session: taskId,\n };\n }\n } catch {\n // Skip tasks without history or malformed files\n }\n }\n }\n },\n };\n}\n\nfunction extractText(content: unknown): string | null {\n if (typeof content === \"string\") return content;\n if (Array.isArray(content)) {\n const parts = content\n .filter(\n (p): p is { type: string; text: string } =>\n typeof p === \"object\" &&\n p !== null &&\n p.type === \"text\" &&\n typeof p.text === \"string\",\n )\n .map((p) => p.text);\n return parts.length > 0 ? parts.join(\" \") : null;\n }\n return null;\n}\n\ninterface ClineMessage {\n role?: string;\n content?: unknown;\n ts?: string;\n}\n", "import { createReadStream } from \"node:fs\";\nimport { readdir, stat } from \"node:fs/promises\";\nimport { createInterface } from \"node:readline\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport type { Adapter, AdapterOptions, Message } from \"./index\";\n\n/**\n * Codex stores sessions as JSONL files at:\n * ~/.codex/sessions/YYYY/MM/DD/rollout-*.jsonl\n *\n * Each line is JSON with structure:\n * { \"timestamp\": \"...\", \"type\": \"response_item\", \"payload\": { \"type\": \"message\", \"role\": \"user\", \"content\": [...] } }\n *\n * User messages have payload.role === \"user\" and content is an array of\n * { \"type\": \"input_text\", \"text\": \"...\" }\n *\n * We skip messages that are just environment context injections.\n */\n\nconst CODEX_SESSIONS_DIR = join(homedir(), \".codex\", \"sessions\");\n\nexport function codexAdapter(): Adapter {\n return {\n name: \"codex\",\n async *messages(options?: AdapterOptions): AsyncGenerator<Message> {\n yield* walkCodexSessions(CODEX_SESSIONS_DIR, options);\n },\n };\n}\n\nasync function* walkCodexSessions(\n dir: string,\n options?: AdapterOptions,\n): AsyncGenerator<Message> {\n let entries: string[];\n try {\n entries = await readdir(dir);\n } catch {\n return; // Codex not installed or no sessions\n }\n\n for (const entry of entries) {\n const fullPath = join(dir, entry);\n const entryStat = await stat(fullPath);\n\n if (entryStat.isDirectory()) {\n yield* walkCodexSessions(fullPath, options);\n } else if (entry.endsWith(\".jsonl\")) {\n const session = entry.replace(\".jsonl\", \"\");\n yield* parseCodexJsonl(fullPath, { session, since: options?.since });\n }\n }\n}\n\nasync function* parseCodexJsonl(\n filePath: string,\n context: { session: string; since?: Date },\n): AsyncGenerator<Message> {\n const rl = createInterface({\n input: createReadStream(filePath, { encoding: \"utf-8\" }),\n crlfDelay: Infinity,\n });\n\n for await (const line of rl) {\n if (!line.trim()) continue;\n\n try {\n const entry = JSON.parse(line) as CodexEntry;\n\n // Only care about response_item entries with user messages\n if (entry.type !== \"response_item\") continue;\n\n const payload = entry.payload;\n if (!payload || payload.role !== \"user\") continue;\n\n const text = extractText(payload.content);\n if (!text) continue;\n\n // Skip environment context injections (they start with <environment_context>)\n if (text.startsWith(\"<environment_context>\")) continue;\n // Skip permission/sandbox instructions\n if (text.startsWith(\"<permissions instructions>\")) continue;\n\n if (context.since && entry.timestamp) {\n const ts = new Date(entry.timestamp);\n if (ts < context.since) continue;\n }\n\n yield {\n text,\n timestamp: entry.timestamp,\n session: context.session,\n };\n } catch {\n // Skip malformed lines\n }\n }\n}\n\nfunction extractText(content: unknown): string | null {\n if (!Array.isArray(content)) return null;\n\n const parts = content\n .filter(\n (p): p is { type: string; text: string } =>\n typeof p === \"object\" &&\n p !== null &&\n p.type === \"input_text\" &&\n typeof p.text === \"string\",\n )\n .map((p) => p.text);\n\n return parts.length > 0 ? parts.join(\" \") : null;\n}\n\ninterface CodexEntry {\n timestamp?: string;\n type: string;\n payload?: {\n type?: string;\n role?: string;\n content?: unknown;\n };\n}\n", "import { existsSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport type { Adapter, AdapterOptions, Message } from \"./index\";\n\n/**\n * OpenCode stores sessions in a SQLite database at:\n * ~/.local/share/opencode/opencode.db\n *\n * Schema:\n * message: { id, session_id, time_created (epoch ms), time_updated, data (JSON) }\n * part: { id, message_id, session_id, time_created, time_updated, data (JSON) }\n *\n * message.data: { \"role\": \"user\"|\"assistant\", \"time\": {...}, \"agent\": \"...\", ... }\n * part.data: { \"type\": \"text\", \"text\": \"the user's message\" }\n *\n * User messages have role=\"user\" in message.data. The actual text content is in\n * the associated part rows where part.data.type === \"text\".\n */\n\nfunction getOpencodeDatabasePath(): string | null {\n // macOS: ~/.local/share/opencode/opencode.db (despite XDG, this is where it actually lives)\n const xdgPath = join(\n process.env[\"XDG_DATA_HOME\"] ?? join(homedir(), \".local\", \"share\"),\n \"opencode\",\n \"opencode.db\",\n );\n if (existsSync(xdgPath)) return xdgPath;\n\n // macOS Application Support fallback\n if (process.platform === \"darwin\") {\n const macPath = join(\n homedir(),\n \"Library\",\n \"Application Support\",\n \"opencode\",\n \"opencode.db\",\n );\n if (existsSync(macPath)) return macPath;\n }\n\n return null;\n}\n\nexport function opencodeAdapter(): Adapter {\n return {\n name: \"opencode\",\n async *messages(options?: AdapterOptions): AsyncGenerator<Message> {\n const dbPath = getOpencodeDatabasePath();\n if (!dbPath) return;\n\n // Dynamic import so the CLI doesn't crash if better-sqlite3 isn't available\n let db: import(\"better-sqlite3\").Database;\n try {\n const BetterSqlite3 = await import(\"better-sqlite3\");\n const Ctor = BetterSqlite3.default ?? BetterSqlite3;\n db = new (Ctor as unknown as new (...args: unknown[]) => import(\"better-sqlite3\").Database)(dbPath, { readonly: true });\n } catch {\n console.warn(\n \"devrage: better-sqlite3 not available, skipping OpenCode sessions\",\n );\n return;\n }\n\n try {\n yield* queryUserMessages(db, options);\n } finally {\n db.close();\n }\n },\n };\n}\n\nfunction* queryUserMessages(\n db: import(\"better-sqlite3\").Database,\n options?: AdapterOptions,\n): Generator<Message> {\n // Query: join message + part, filter to user role and text parts\n let query = `\n SELECT\n m.session_id,\n m.time_created,\n json_extract(p.data, '$.text') as text\n FROM message m\n JOIN part p ON p.message_id = m.id\n WHERE json_extract(m.data, '$.role') = 'user'\n AND json_extract(p.data, '$.type') = 'text'\n `;\n\n if (options?.since) {\n const sinceMs = options.since.getTime();\n query += ` AND m.time_created >= ${sinceMs}`;\n }\n\n query += ` ORDER BY m.time_created ASC`;\n\n const rows = db.prepare(query).all() as {\n session_id: string;\n time_created: number;\n text: string;\n }[];\n\n for (const row of rows) {\n if (!row.text || !row.text.trim()) continue;\n\n yield {\n text: row.text,\n timestamp: new Date(row.time_created).toISOString(),\n session: row.session_id,\n };\n }\n}\n", "import { createReadStream } from \"node:fs\";\nimport { readdir, stat } from \"node:fs/promises\";\nimport { createInterface } from \"node:readline\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport type { Adapter, AdapterOptions, Message } from \"./index\";\n\n/**\n * pi stores sessions as JSONL files at:\n * ~/.pi/agent/sessions/<project-dir>/<timestamp>_<uuid>.jsonl\n *\n * Project directories are path-encoded (e.g. --Users-justin-twiddle--\n * for /Users/justin/twiddle).\n *\n * Each line is JSON. User messages have:\n * { \"type\": \"message\", \"timestamp\": \"...\", \"message\": { \"role\": \"user\", \"content\": [{\"type\": \"text\", \"text\": \"...\"}] } }\n *\n * The session-starter line has `type: \"session\"` with `cwd` \u2014 we use that\n * as the project name.\n */\n\nconst PI_SESSIONS_DIR = join(homedir(), \".pi\", \"agent\", \"sessions\");\n\nexport function piAdapter(): Adapter {\n return {\n name: \"pi\",\n async *messages(options?: AdapterOptions): AsyncGenerator<Message> {\n let projectDirs: string[];\n try {\n projectDirs = await readdir(PI_SESSIONS_DIR);\n } catch {\n return; // pi not installed or no sessions\n }\n\n for (const dirName of projectDirs) {\n const projectDirPath = join(PI_SESSIONS_DIR, dirName);\n const dirStat = await stat(projectDirPath).catch(() => null);\n if (!dirStat?.isDirectory()) continue;\n\n // Skip subagent-artifacts directories\n if (dirName === \"subagent-artifacts\") continue;\n\n let sessionFiles: string[];\n try {\n sessionFiles = await readdir(projectDirPath);\n } catch {\n continue;\n }\n\n const jsonlFiles = sessionFiles.filter((f) => f.endsWith(\".jsonl\"));\n\n for (const file of jsonlFiles) {\n const filePath = join(projectDirPath, file);\n const sessionId = file.replace(\".jsonl\", \"\");\n\n yield* parsePiJsonl(filePath, {\n session: sessionId,\n project: dirName,\n since: options?.since,\n });\n }\n }\n },\n };\n}\n\nasync function* parsePiJsonl(\n filePath: string,\n context: { session: string; project: string; since?: Date },\n): AsyncGenerator<Message> {\n const rl = createInterface({\n input: createReadStream(filePath, { encoding: \"utf-8\" }),\n crlfDelay: Infinity,\n });\n\n for await (const line of rl) {\n if (!line.trim()) continue;\n\n try {\n const entry = JSON.parse(line) as PiEntry;\n\n // Only process user messages\n if (entry.type !== \"message\") continue;\n\n const msg = entry.message;\n if (!msg || msg.role !== \"user\") continue;\n\n const text = extractText(msg.content);\n if (!text) continue;\n\n const timestamp = entry.timestamp\n ?? (msg.timestamp != null ? new Date(msg.timestamp).toISOString() : undefined);\n\n if (context.since && timestamp) {\n const ts = new Date(timestamp);\n if (ts < context.since) continue;\n }\n\n yield {\n text,\n timestamp,\n session: context.session,\n project: context.project,\n };\n } catch {\n // Skip malformed lines\n }\n }\n}\n\nfunction extractText(content: unknown): string | null {\n if (typeof content === \"string\") return content;\n if (Array.isArray(content)) {\n const parts = content\n .filter(\n (p): p is { type: string; text: string } =>\n typeof p === \"object\" &&\n p !== null &&\n p.type === \"text\" &&\n typeof p.text === \"string\",\n )\n .map((p) => p.text);\n return parts.length > 0 ? parts.join(\" \") : null;\n }\n return null;\n}\n\ninterface PiEntry {\n type: string;\n timestamp?: string;\n message?: {\n role?: string;\n content?: unknown;\n timestamp?: number;\n };\n}\n", "import { readdir, readFile } from \"node:fs/promises\";\nimport { existsSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport type { Adapter, AdapterOptions, Message } from \"./index\";\n\n/**\n * Zed stores AI conversations in two places:\n *\n * 1. Text threads (older assistant panel):\n * ~/.local/share/zed/conversations/*.json (Linux)\n * ~/Library/Application Support/Zed/conversations/*.json (macOS)\n * These are markdown-like JSON with messages.\n *\n * 2. Agent threads (newer):\n * Stored in SQLite at ~/.local/share/zed/db (Linux)\n * or ~/Library/Application Support/Zed/db (macOS)\n * We'd need to query this, but the schema isn't well documented.\n *\n * We support the text thread JSON files for now, and the SQLite agent\n * threads when better-sqlite3 is available.\n */\n\nfunction getZedPaths(): { conversations: string; db: string } {\n if (process.platform === \"darwin\") {\n const base = join(homedir(), \"Library\", \"Application Support\", \"Zed\");\n return {\n conversations: join(base, \"conversations\"),\n db: join(base, \"db\"),\n };\n }\n // Linux / others\n const base = join(\n process.env[\"XDG_DATA_HOME\"] ?? join(homedir(), \".local\", \"share\"),\n \"zed\",\n );\n return {\n conversations: join(base, \"conversations\"),\n db: join(base, \"db\"),\n };\n}\n\nexport function zedAdapter(): Adapter {\n return {\n name: \"zed\",\n async *messages(options?: AdapterOptions): AsyncGenerator<Message> {\n const paths = getZedPaths();\n\n // 1. Parse text thread JSON conversations\n yield* parseTextThreads(paths.conversations, options);\n\n // 2. Try SQLite agent threads\n yield* parseAgentThreads(paths.db, options);\n },\n };\n}\n\nasync function* parseTextThreads(\n dir: string,\n _options?: AdapterOptions,\n): AsyncGenerator<Message> {\n if (!existsSync(dir)) return;\n\n let files: string[];\n try {\n files = await readdir(dir);\n } catch {\n return;\n }\n\n const jsonFiles = files.filter((f) => f.endsWith(\".json\"));\n\n for (const file of jsonFiles) {\n const filePath = join(dir, file);\n const session = file.replace(\".json\", \"\");\n\n try {\n const raw = await readFile(filePath, \"utf-8\");\n const conversation = JSON.parse(raw) as ZedConversation;\n\n if (!conversation.messages || !Array.isArray(conversation.messages)) continue;\n\n for (const msg of conversation.messages) {\n if (msg.role !== \"user\") continue;\n\n const text = typeof msg.content === \"string\" ? msg.content : null;\n if (!text) continue;\n\n yield {\n text,\n session,\n };\n }\n } catch {\n // Skip malformed files\n }\n }\n}\n\nasync function* parseAgentThreads(\n dbDir: string,\n _options?: AdapterOptions,\n): AsyncGenerator<Message> {\n // Zed uses a directory of SQLite databases. The main one is typically\n // a file like 0-dev.db or similar inside the db/ directory.\n if (!existsSync(dbDir)) return;\n\n let dbFiles: string[];\n try {\n const entries = await readdir(dbDir);\n dbFiles = entries.filter((f) => f.endsWith(\".db\"));\n } catch {\n return;\n }\n\n if (dbFiles.length === 0) return;\n\n let Database: unknown;\n try {\n const mod = await import(\"better-sqlite3\");\n Database = mod.default ?? mod;\n } catch {\n return; // better-sqlite3 not available\n }\n\n for (const dbFile of dbFiles) {\n const dbPath = join(dbDir, dbFile);\n let db: import(\"better-sqlite3\").Database;\n\n try {\n db = new (Database as new (...args: unknown[]) => import(\"better-sqlite3\").Database)(\n dbPath,\n { readonly: true },\n );\n } catch {\n continue; // Can't open this DB\n }\n\n try {\n // Check if this DB has a threads/messages table\n const tables = db\n .prepare(\"SELECT name FROM sqlite_master WHERE type='table'\")\n .all() as { name: string }[];\n const tableNames = tables.map((t) => t.name);\n\n // Look for message-like tables (Zed's schema may vary by version)\n const msgTable = tableNames.find(\n (t) => t === \"messages\" || t === \"thread_messages\" || t.includes(\"message\"),\n );\n\n if (!msgTable) {\n db.close();\n continue;\n }\n\n const columns = db.prepare(`PRAGMA table_info(\"${msgTable}\")`).all() as {\n name: string;\n }[];\n const colNames = columns.map((c) => c.name);\n\n const hasRole = colNames.includes(\"role\");\n\n if (!hasRole) {\n db.close();\n continue;\n }\n\n const contentCol = colNames.includes(\"content\")\n ? \"content\"\n : colNames.includes(\"body\")\n ? \"body\"\n : \"text\";\n\n let query = `SELECT \"${contentCol}\" as text FROM \"${msgTable}\" WHERE role = 'user'`;\n\n const rows = db.prepare(query).all() as { text: string }[];\n for (const row of rows) {\n if (!row.text?.trim()) continue;\n yield { text: row.text };\n }\n } catch {\n // Schema mismatch or other error\n } finally {\n db.close();\n }\n }\n}\n\ninterface ZedConversation {\n messages?: { role?: string; content?: unknown }[];\n}\n", "import { ampAdapter } from \"./amp\";\nimport { claudeAdapter } from \"./claude\";\nimport { clineAdapter } from \"./cline\";\nimport { codexAdapter } from \"./codex\";\nimport { opencodeAdapter } from \"./opencode\";\nimport { piAdapter } from \"./pi\";\nimport { zedAdapter } from \"./zed\";\n\nexport interface Message {\n text: string;\n timestamp?: string;\n session?: string;\n project?: string;\n}\n\nexport interface Adapter {\n name: string;\n /** Discover and yield all user messages from local session storage */\n messages(options?: AdapterOptions): AsyncGenerator<Message>;\n}\n\nexport interface AdapterOptions {\n since?: Date;\n}\n\nconst ADAPTERS: Record<string, () => Adapter> = {\n claude: claudeAdapter,\n codex: codexAdapter,\n opencode: opencodeAdapter,\n amp: ampAdapter,\n cline: clineAdapter,\n pi: piAdapter,\n zed: zedAdapter,\n};\n\nexport function createAdapter(name: string): Adapter {\n const factory = ADAPTERS[name];\n if (!factory) {\n throw new Error(\n `unknown adapter: ${name} (available: ${Object.keys(ADAPTERS).join(\", \")})`,\n );\n }\n return factory();\n}\n\nexport function allAdapters(): Adapter[] {\n return Object.values(ADAPTERS).map((f) => f());\n}\n", "export interface DetectionResult {\n /** Total swear words found in the text */\n count: number;\n /** Individual matches */\n matches: Match[];\n}\n\nexport interface Match {\n word: string;\n index: number;\n severity: Severity;\n group: string;\n}\n\nexport type Severity = \"mild\" | \"moderate\" | \"strong\";\n\ninterface WordDef {\n word: string;\n severity: Severity;\n group: string;\n}\n\n/**\n * Core wordlist: canonical forms, conjugations, compound words, and common typos.\n * Grouped by root word for reporting rollup.\n *\n * Sources:\n * - swearjar npm (en_US.json) for compound words\n * - Manual typo variants based on common keyboard transpositions\n */\nconst WORDLIST: WordDef[] = [\n // === FUCK family (strong) ===\n // Canonical forms\n { word: \"fuck\", severity: \"strong\", group: \"fuck\" },\n { word: \"fucking\", severity: \"strong\", group: \"fuck\" },\n { word: \"fucked\", severity: \"strong\", group: \"fuck\" },\n { word: \"fucker\", severity: \"strong\", group: \"fuck\" },\n { word: \"fuckin\", severity: \"strong\", group: \"fuck\" },\n { word: \"fucks\", severity: \"strong\", group: \"fuck\" },\n // Compound words\n { word: \"motherfucker\", severity: \"strong\", group: \"fuck\" },\n { word: \"motherfucking\", severity: \"strong\", group: \"fuck\" },\n { word: \"mothafucka\", severity: \"strong\", group: \"fuck\" },\n { word: \"fuckup\", severity: \"strong\", group: \"fuck\" },\n { word: \"fuckoff\", severity: \"strong\", group: \"fuck\" },\n { word: \"clusterfuck\", severity: \"strong\", group: \"fuck\" },\n { word: \"fuckwit\", severity: \"strong\", group: \"fuck\" },\n { word: \"fucktard\", severity: \"strong\", group: \"fuck\" },\n { word: \"fuckface\", severity: \"strong\", group: \"fuck\" },\n { word: \"fuckhead\", severity: \"strong\", group: \"fuck\" },\n // Typos \u2014 transpositions\n { word: \"fukc\", severity: \"strong\", group: \"fuck\" },\n { word: \"fukcing\", severity: \"strong\", group: \"fuck\" },\n { word: \"fukced\", severity: \"strong\", group: \"fuck\" },\n { word: \"fukcer\", severity: \"strong\", group: \"fuck\" },\n { word: \"fcuk\", severity: \"strong\", group: \"fuck\" },\n { word: \"fcuking\", severity: \"strong\", group: \"fuck\" },\n { word: \"fcuked\", severity: \"strong\", group: \"fuck\" },\n { word: \"fuk\", severity: \"strong\", group: \"fuck\" },\n { word: \"fuking\", severity: \"strong\", group: \"fuck\" },\n { word: \"fuked\", severity: \"strong\", group: \"fuck\" },\n { word: \"fuker\", severity: \"strong\", group: \"fuck\" },\n { word: \"fuxk\", severity: \"strong\", group: \"fuck\" },\n { word: \"fuxking\", severity: \"strong\", group: \"fuck\" },\n\n // === SHIT family (strong) ===\n { word: \"shit\", severity: \"strong\", group: \"shit\" },\n { word: \"shitty\", severity: \"strong\", group: \"shit\" },\n { word: \"shitting\", severity: \"strong\", group: \"shit\" },\n { word: \"shits\", severity: \"strong\", group: \"shit\" },\n { word: \"shitted\", severity: \"strong\", group: \"shit\" },\n // Compound words\n { word: \"bullshit\", severity: \"strong\", group: \"shit\" },\n { word: \"horseshit\", severity: \"strong\", group: \"shit\" },\n { word: \"dipshit\", severity: \"strong\", group: \"shit\" },\n { word: \"shitshow\", severity: \"strong\", group: \"shit\" },\n { word: \"shithead\", severity: \"strong\", group: \"shit\" },\n { word: \"shithole\", severity: \"strong\", group: \"shit\" },\n { word: \"shitface\", severity: \"strong\", group: \"shit\" },\n { word: \"shitfaced\", severity: \"strong\", group: \"shit\" },\n { word: \"shitstain\", severity: \"strong\", group: \"shit\" },\n { word: \"shitbag\", severity: \"strong\", group: \"shit\" },\n // Typos\n { word: \"hsit\", severity: \"strong\", group: \"shit\" },\n { word: \"siht\", severity: \"strong\", group: \"shit\" },\n { word: \"shti\", severity: \"strong\", group: \"shit\" },\n { word: \"sjit\", severity: \"strong\", group: \"shit\" },\n { word: \"shjt\", severity: \"strong\", group: \"shit\" },\n { word: \"bulshit\", severity: \"strong\", group: \"shit\" },\n { word: \"bullsht\", severity: \"strong\", group: \"shit\" },\n\n // === ASS family (moderate) ===\n { word: \"ass\", severity: \"moderate\", group: \"ass\" },\n { word: \"asses\", severity: \"moderate\", group: \"ass\" },\n // Compound words (these are strong)\n { word: \"asshole\", severity: \"strong\", group: \"ass\" },\n { word: \"assholes\", severity: \"strong\", group: \"ass\" },\n { word: \"jackass\", severity: \"strong\", group: \"ass\" },\n { word: \"dumbass\", severity: \"strong\", group: \"ass\" },\n { word: \"fatass\", severity: \"moderate\", group: \"ass\" },\n { word: \"asshat\", severity: \"strong\", group: \"ass\" },\n { word: \"asswipe\", severity: \"strong\", group: \"ass\" },\n { word: \"badass\", severity: \"mild\", group: \"ass\" },\n\n // === DAMN family (moderate) ===\n { word: \"damn\", severity: \"moderate\", group: \"damn\" },\n { word: \"damned\", severity: \"moderate\", group: \"damn\" },\n { word: \"damnit\", severity: \"moderate\", group: \"damn\" },\n { word: \"dammit\", severity: \"moderate\", group: \"damn\" },\n { word: \"goddamn\", severity: \"moderate\", group: \"damn\" },\n { word: \"goddamnit\", severity: \"moderate\", group: \"damn\" },\n { word: \"goddammit\", severity: \"moderate\", group: \"damn\" },\n\n // === BITCH family (strong) ===\n { word: \"bitch\", severity: \"strong\", group: \"bitch\" },\n { word: \"bitches\", severity: \"strong\", group: \"bitch\" },\n { word: \"bitching\", severity: \"strong\", group: \"bitch\" },\n { word: \"bitchy\", severity: \"strong\", group: \"bitch\" },\n { word: \"bitchass\", severity: \"strong\", group: \"bitch\" },\n\n // === BASTARD (strong) ===\n { word: \"bastard\", severity: \"strong\", group: \"bastard\" },\n { word: \"bastards\", severity: \"strong\", group: \"bastard\" },\n\n // === PISS family (moderate) ===\n { word: \"piss\", severity: \"moderate\", group: \"piss\" },\n { word: \"pissed\", severity: \"moderate\", group: \"piss\" },\n { word: \"pissing\", severity: \"moderate\", group: \"piss\" },\n { word: \"pissoff\", severity: \"moderate\", group: \"piss\" },\n\n // === DICK (moderate) ===\n { word: \"dick\", severity: \"moderate\", group: \"dick\" },\n { word: \"dickhead\", severity: \"strong\", group: \"dick\" },\n\n // === CRAP (moderate) ===\n { word: \"crap\", severity: \"moderate\", group: \"crap\" },\n { word: \"crappy\", severity: \"moderate\", group: \"crap\" },\n { word: \"crapping\", severity: \"moderate\", group: \"crap\" },\n\n // === HELL (mild) ===\n { word: \"hell\", severity: \"mild\", group: \"hell\" },\n\n // === Abbreviations (mild) ===\n { word: \"wtf\", severity: \"mild\", group: \"wtf\" },\n { word: \"stfu\", severity: \"mild\", group: \"stfu\" },\n { word: \"lmfao\", severity: \"mild\", group: \"lmfao\" },\n { word: \"lmao\", severity: \"mild\", group: \"lmao\" },\n\n // === CUNT (strong) ===\n { word: \"cunt\", severity: \"strong\", group: \"cunt\" },\n { word: \"cunts\", severity: \"strong\", group: \"cunt\" },\n];\n\n/**\n * Normalize text before matching:\n * 1. Collapse repeated characters (3+ of the same char \u2192 2)\n * e.g. \"fuuuuck\" \u2192 \"fuuck\", \"shiiiiit\" \u2192 \"shiit\"\n * This lets \"fuuuuck\" match against \"fuck\" after the regex runs,\n * because the pattern also includes \"fuuck\" style intermediates.\n *\n * Actually \u2014 better approach: collapse ALL runs of 2+ to 1 for matching\n * purposes, while keeping the original text for position tracking.\n * e.g. \"fuuuuck\" \u2192 \"fuck\", \"shiiiit\" \u2192 \"shit\"\n * This directly normalizes to the root word.\n */\nfunction collapseRepeats(text: string): string {\n return text.replace(/(.)\\1+/g, \"$1\");\n}\n\n/**\n * Build the detection regex from the wordlist.\n * Sort longer words first so \"motherfucker\" matches before \"fuck\".\n */\nfunction buildPattern(words: WordDef[]): RegExp {\n const sorted = [...words].sort((a, b) => b.word.length - a.word.length);\n const pattern = sorted.map((w) => w.word).join(\"|\");\n return new RegExp(`\\\\b(${pattern})\\\\b`, \"gi\");\n}\n\nconst DEFAULT_PATTERN = buildPattern(WORDLIST);\nconst WORD_MAP = new Map(WORDLIST.map((w) => [w.word.toLowerCase(), w]));\n\n/**\n * Detect profanity in a string.\n *\n * Runs detection in two passes:\n * 1. Direct match on original text (preserves positions)\n * 2. Match on repeat-collapsed text (catches fuuuuck, shiiiiit, etc.)\n */\nexport function detect(text: string): DetectionResult {\n const matches: Match[] = [];\n const seen = new Set<number>(); // track original-text positions we've already matched\n\n // Pass 1: direct match on original (lowercase) text\n runPattern(text, text.toLowerCase(), matches, seen);\n\n // Pass 2: match on collapsed text to catch repeated chars\n const collapsed = collapseRepeats(text.toLowerCase());\n if (collapsed !== text.toLowerCase()) {\n runPattern(text, collapsed, matches, seen);\n }\n\n return { count: matches.length, matches };\n}\n\nfunction runPattern(\n _originalText: string,\n searchText: string,\n matches: Match[],\n seen: Set<number>,\n): void {\n DEFAULT_PATTERN.lastIndex = 0;\n\n let match: RegExpExecArray | null;\n while ((match = DEFAULT_PATTERN.exec(searchText)) !== null) {\n if (seen.has(match.index)) continue;\n\n const word = match[0].toLowerCase();\n const entry = WORD_MAP.get(word);\n if (!entry) continue;\n\n seen.add(match.index);\n matches.push({\n word,\n index: match.index,\n severity: entry.severity,\n group: entry.group,\n });\n }\n}\n\n/**\n * Create a custom detector with additional words.\n */\nexport function createDetector(\n extraWords?: WordDef[],\n): (text: string) => DetectionResult {\n const allWords = extraWords ? [...WORDLIST, ...extraWords] : WORDLIST;\n const pattern = buildPattern(allWords);\n const wordMap = new Map(allWords.map((w) => [w.word.toLowerCase(), w]));\n\n return (text: string): DetectionResult => {\n const matches: Match[] = [];\n const seen = new Set<number>();\n\n const lower = text.toLowerCase();\n pattern.lastIndex = 0;\n let match: RegExpExecArray | null;\n while ((match = pattern.exec(lower)) !== null) {\n if (seen.has(match.index)) continue;\n const word = match[0].toLowerCase();\n const entry = wordMap.get(word);\n if (!entry) continue;\n seen.add(match.index);\n matches.push({ word, index: match.index, severity: entry.severity, group: entry.group });\n }\n\n const collapsed = collapseRepeats(lower);\n if (collapsed !== lower) {\n pattern.lastIndex = 0;\n while ((match = pattern.exec(collapsed)) !== null) {\n if (seen.has(match.index)) continue;\n const word = match[0].toLowerCase();\n const entry = wordMap.get(word);\n if (!entry) continue;\n seen.add(match.index);\n matches.push({ word, index: match.index, severity: entry.severity, group: entry.group });\n }\n }\n\n return { count: matches.length, matches };\n };\n}\n\nexport type { WordDef as WordEntry };\n", "import { allAdapters, createAdapter } from \"../adapters/index\";\nimport { detect } from \"../detector/index\";\n\n// ANSI color helpers \u2014 no dependencies needed\nconst c = {\n reset: \"\\x1b[0m\",\n bold: \"\\x1b[1m\",\n dim: \"\\x1b[2m\",\n red: \"\\x1b[31m\",\n green: \"\\x1b[32m\",\n yellow: \"\\x1b[33m\",\n blue: \"\\x1b[34m\",\n magenta: \"\\x1b[35m\",\n cyan: \"\\x1b[36m\",\n white: \"\\x1b[37m\",\n gray: \"\\x1b[90m\",\n};\n\nconst SPINNER_MESSAGES = [\n \"Tallying the damage\",\n \"Reviewing your outbursts\",\n \"Judging your vocabulary\",\n \"Computing your shame\",\n \"Cataloging the profanity\",\n \"Measuring your frustration\",\n \"Assessing the verbal carnage\",\n \"Quantifying your displeasure\",\n \"Auditing your language\",\n \"Tabulating regrets\",\n];\n\nfunction createSpinner() {\n let messageIdx = 0;\n let dotCount = 0;\n let timer: ReturnType<typeof setInterval> | null = null;\n\n return {\n start() {\n messageIdx = Math.floor(Math.random() * SPINNER_MESSAGES.length);\n timer = setInterval(() => {\n dotCount = (dotCount + 1) % 4;\n const msg = SPINNER_MESSAGES[messageIdx % SPINNER_MESSAGES.length];\n const dots = \".\".repeat(dotCount || 1);\n process.stdout.write(\n `\\r ${c.dim}${msg}${dots}${c.reset} `,\n );\n }, 300);\n },\n update() {\n messageIdx++;\n },\n stop() {\n if (timer) {\n clearInterval(timer);\n timer = null;\n }\n process.stdout.write(\"\\r\" + \" \".repeat(60) + \"\\r\");\n },\n };\n}\n\ninterface ScanOptions {\n agent?: string;\n since?: Date;\n}\n\nfunction parseArgs(args: string[]): ScanOptions {\n const options: ScanOptions = {};\n\n for (let i = 0; i < args.length; i++) {\n const arg = args[i];\n if (arg === \"--agent\" || arg === \"-a\") {\n options.agent = args[++i];\n } else if (arg === \"--since\" || arg === \"-s\") {\n const val = args[++i];\n if (val) {\n options.since = new Date(val);\n if (isNaN(options.since.getTime())) {\n console.error(`invalid date: ${val}`);\n process.exit(1);\n }\n }\n } else if (arg === \"--help\" || arg === \"-h\") {\n console.log(`devrager scan \u2014 scan sessions for profanity\n\nOptions:\n --agent, -a <name> Scan only a specific agent (claude, codex, opencode, amp, cline, zed)\n --since, -s <date> Only scan messages after this date (ISO 8601)\n --help, -h Show this help`);\n process.exit(0);\n }\n }\n\n return options;\n}\n\nexport async function scan(args: string[]): Promise<void> {\n const options = parseArgs(args);\n\n const adapters = options.agent\n ? [createAdapter(options.agent)]\n : allAdapters();\n\n const spinner = createSpinner();\n spinner.start();\n\n const groupTally: Record<string, number> = {};\n const variantTally: Record<string, Record<string, number>> = {};\n\n let totalMessages = 0;\n let totalSwears = 0;\n const perAgent: Record<string, { messages: number; swears: number }> = {};\n\n for (const adapter of adapters) {\n let agentMessages = 0;\n let agentSwears = 0;\n spinner.update();\n\n for await (const message of adapter.messages({ since: options.since })) {\n totalMessages++;\n agentMessages++;\n\n const result = detect(message.text);\n if (result.count > 0) {\n totalSwears += result.count;\n agentSwears += result.count;\n\n for (const match of result.matches) {\n groupTally[match.group] = (groupTally[match.group] ?? 0) + 1;\n\n const variants = (variantTally[match.group] ??= {});\n variants[match.word] = (variants[match.word] ?? 0) + 1;\n }\n }\n }\n\n if (agentMessages > 0) {\n perAgent[adapter.name] = { messages: agentMessages, swears: agentSwears };\n }\n }\n\n spinner.stop();\n\n // Report\n console.log(\"\");\n console.log(` ${c.bold}${c.red}devrage${c.reset} ${c.dim}report${c.reset}`);\n console.log(` ${c.dim}${\"\u2500\".repeat(30)}${c.reset}`);\n console.log(\"\");\n console.log(` ${c.dim}messages scanned${c.reset} ${c.bold}${totalMessages}${c.reset}`);\n console.log(` ${c.dim}total swears${c.reset} ${c.bold}${c.red}${totalSwears}${c.reset}`);\n\n const activeAgents = Object.entries(perAgent);\n if (activeAgents.length > 1) {\n console.log(\"\");\n console.log(` ${c.bold}by agent${c.reset}`);\n for (const [name, stats] of activeAgents) {\n const rate = ((stats.swears / stats.messages) * 100).toFixed(1);\n console.log(\n ` ${c.cyan}${name.padEnd(10)}${c.reset} ${c.bold}${String(stats.swears).padStart(4)}${c.reset} ${c.dim}in ${stats.messages} messages (${rate}%)${c.reset}`,\n );\n }\n }\n\n if (totalSwears > 0) {\n const sorted = Object.entries(groupTally).sort(([, a], [, b]) => b - a);\n console.log(\"\");\n console.log(` ${c.bold}top words${c.reset}`);\n for (const [group, count] of sorted.slice(0, 10)) {\n const variants = variantTally[group] ?? {};\n const variantList = Object.entries(variants)\n .sort(([, a], [, b]) => b - a)\n .filter(([v]) => v !== group)\n .slice(0, 15)\n .map(([v, cnt]) => `${c.dim}${v}${c.reset} ${cnt}`)\n .join(`${c.dim},${c.reset} `);\n const suffix = variantList ? ` ${c.dim}(${c.reset}${variantList}${c.dim})${c.reset}` : \"\";\n console.log(\n ` ${c.yellow}${group.padEnd(12)}${c.reset} ${c.bold}${String(count).padStart(4)}${c.reset}${suffix}`,\n );\n }\n }\n\n console.log(\"\");\n if (totalSwears === 0) {\n console.log(` ${c.green}squeaky clean! not a single swear found.${c.reset}`);\n console.log(\"\");\n }\n}\n\n\n", "import { scan } from \"./commands/scan\";\n\nconst COMMANDS: Record<string, (args: string[]) => Promise<void>> = {\n scan,\n};\n\nfunction usage(): void {\n console.log(`devrager \u2014 count how many times you swear at your coding agents\n\nUsage:\n devrager <command> [options]\n\nCommands:\n scan Scan sessions for profanity\n\nOptions:\n --help, -h Show this help message\n --version Show version\n\nExamples:\n devrager scan\n devrager scan --agent claude\n devrager scan --since 2025-01-01`);\n}\n\nasync function main(): Promise<void> {\n const args = process.argv.slice(2);\n const command = args[0];\n\n if (command === \"--help\" || command === \"-h\") {\n usage();\n process.exit(0);\n }\n\n if (command === \"--version\") {\n console.log(\"0.0.4\");\n process.exit(0);\n }\n\n // If no command or not a known command, default to scan\n const handler = command ? COMMANDS[command] : undefined;\n if (handler) {\n await handler(args.slice(1));\n } else {\n // Pass all args through to scan (covers both no-arg and unknown-arg cases)\n await scan(args);\n }\n}\n\nmain().catch((err: unknown) => {\n console.error(err);\n process.exit(1);\n});\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["readdir", "homedir", "join", "readdir", "readFile", "stat", "homedir", "join", "extractText", "createReadStream", "readdir", "stat", "createInterface", "homedir", "join", "extractText", "existsSync", "homedir", "join", "createReadStream", "readdir", "stat", "createInterface", "homedir", "join", "extractText", "readdir", "readFile", "existsSync", "homedir", "join", "base", "c"]
|
|
7
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"amp.d.ts","sourceRoot":"","sources":["../../../src/adapters/amp.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAA2B,MAAM,SAAS,CAAC;AAoBhE,wBAAgB,UAAU,IAAI,OAAO,CAiDpC"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { readdir, readFile } from "node:fs/promises";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
/**
|
|
5
|
+
* Amp (Sourcegraph) stores threads as JSON files at:
|
|
6
|
+
* ~/.local/share/amp/threads/<thread-id>.json
|
|
7
|
+
*
|
|
8
|
+
* Each file is a JSON object with a `messages` array:
|
|
9
|
+
* { "messages": [{ "role": "user"|"assistant", "content": "...", ... }], "usageLedger": {...}, ... }
|
|
10
|
+
*
|
|
11
|
+
* Messages have `role`, `content` (string or array), and optionally a timestamp.
|
|
12
|
+
*/
|
|
13
|
+
function getAmpThreadsDir() {
|
|
14
|
+
return join(process.env["XDG_DATA_HOME"] ?? join(homedir(), ".local", "share"), "amp", "threads");
|
|
15
|
+
}
|
|
16
|
+
export function ampAdapter() {
|
|
17
|
+
return {
|
|
18
|
+
name: "amp",
|
|
19
|
+
async *messages(options) {
|
|
20
|
+
const threadsDir = getAmpThreadsDir();
|
|
21
|
+
let files;
|
|
22
|
+
try {
|
|
23
|
+
files = await readdir(threadsDir);
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
return; // Amp not installed or no threads
|
|
27
|
+
}
|
|
28
|
+
const jsonFiles = files.filter((f) => f.endsWith(".json"));
|
|
29
|
+
for (const file of jsonFiles) {
|
|
30
|
+
const filePath = join(threadsDir, file);
|
|
31
|
+
const threadId = file.replace(".json", "");
|
|
32
|
+
try {
|
|
33
|
+
const raw = await readFile(filePath, "utf-8");
|
|
34
|
+
const thread = JSON.parse(raw);
|
|
35
|
+
if (!thread.messages || !Array.isArray(thread.messages))
|
|
36
|
+
continue;
|
|
37
|
+
for (const msg of thread.messages) {
|
|
38
|
+
if (msg.role !== "user")
|
|
39
|
+
continue;
|
|
40
|
+
const text = extractText(msg.content);
|
|
41
|
+
if (!text)
|
|
42
|
+
continue;
|
|
43
|
+
const timestamp = msg.timestamp ?? msg.createdAt ?? undefined;
|
|
44
|
+
if (options?.since && timestamp) {
|
|
45
|
+
const ts = new Date(timestamp);
|
|
46
|
+
if (ts < options.since)
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
yield {
|
|
50
|
+
text,
|
|
51
|
+
timestamp,
|
|
52
|
+
session: threadId,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
// Skip malformed files
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
function extractText(content) {
|
|
64
|
+
if (typeof content === "string")
|
|
65
|
+
return content;
|
|
66
|
+
if (Array.isArray(content)) {
|
|
67
|
+
const parts = content
|
|
68
|
+
.filter((p) => typeof p === "object" && p !== null && typeof p.text === "string")
|
|
69
|
+
.map((p) => p.text);
|
|
70
|
+
return parts.length > 0 ? parts.join(" ") : null;
|
|
71
|
+
}
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=amp.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"amp.js","sourceRoot":"","sources":["../../../src/adapters/amp.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude.d.ts","sourceRoot":"","sources":["../../../src/adapters/claude.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,OAAO,EAA2B,MAAM,SAAS,CAAC;AAchE,wBAAgB,aAAa,IAAI,OAAO,CAqDvC"}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { createReadStream } from "node:fs";
|
|
2
|
+
import { readdir, stat } from "node:fs/promises";
|
|
3
|
+
import { createInterface } from "node:readline";
|
|
4
|
+
import { homedir } from "node:os";
|
|
5
|
+
import { join } from "node:path";
|
|
6
|
+
/**
|
|
7
|
+
* Claude Code stores sessions as JSONL files at:
|
|
8
|
+
* ~/.claude/projects/<project-path>/<session-uuid>.jsonl
|
|
9
|
+
*
|
|
10
|
+
* Each line is a JSON object. User messages have:
|
|
11
|
+
* { "type": "human", "message": { "content": [...] } }
|
|
12
|
+
* or sometimes:
|
|
13
|
+
* { "role": "user", "content": "..." }
|
|
14
|
+
*/
|
|
15
|
+
const CLAUDE_DIR = join(homedir(), ".claude", "projects");
|
|
16
|
+
export function claudeAdapter() {
|
|
17
|
+
return {
|
|
18
|
+
name: "claude",
|
|
19
|
+
async *messages(options) {
|
|
20
|
+
const projectsDir = CLAUDE_DIR;
|
|
21
|
+
let projectDirs;
|
|
22
|
+
try {
|
|
23
|
+
projectDirs = await readdir(projectsDir);
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
return; // Claude Code not installed or no sessions
|
|
27
|
+
}
|
|
28
|
+
for (const projectDir of projectDirs) {
|
|
29
|
+
const projectPath = join(projectsDir, projectDir);
|
|
30
|
+
const projectStat = await stat(projectPath);
|
|
31
|
+
if (!projectStat.isDirectory())
|
|
32
|
+
continue;
|
|
33
|
+
const entries = await readdir(projectPath);
|
|
34
|
+
const jsonlFiles = entries.filter((f) => f.endsWith(".jsonl"));
|
|
35
|
+
for (const file of jsonlFiles) {
|
|
36
|
+
const filePath = join(projectPath, file);
|
|
37
|
+
const session = file.replace(".jsonl", "");
|
|
38
|
+
yield* parseClaudeJsonl(filePath, {
|
|
39
|
+
session,
|
|
40
|
+
project: projectDir,
|
|
41
|
+
since: options?.since,
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
// Also check for subagent JSONL files in session subdirectories
|
|
45
|
+
const subdirs = entries.filter((f) => !f.includes("."));
|
|
46
|
+
for (const subdir of subdirs) {
|
|
47
|
+
const subagentsDir = join(projectPath, subdir, "subagents");
|
|
48
|
+
try {
|
|
49
|
+
const subFiles = await readdir(subagentsDir);
|
|
50
|
+
const subJsonl = subFiles.filter((f) => f.endsWith(".jsonl"));
|
|
51
|
+
for (const file of subJsonl) {
|
|
52
|
+
yield* parseClaudeJsonl(join(subagentsDir, file), {
|
|
53
|
+
session: `${subdir}/${file.replace(".jsonl", "")}`,
|
|
54
|
+
project: projectDir,
|
|
55
|
+
since: options?.since,
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
// No subagents directory, skip
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
async function* parseClaudeJsonl(filePath, context) {
|
|
68
|
+
const rl = createInterface({
|
|
69
|
+
input: createReadStream(filePath, { encoding: "utf-8" }),
|
|
70
|
+
crlfDelay: Infinity,
|
|
71
|
+
});
|
|
72
|
+
for await (const line of rl) {
|
|
73
|
+
if (!line.trim())
|
|
74
|
+
continue;
|
|
75
|
+
try {
|
|
76
|
+
const entry = JSON.parse(line);
|
|
77
|
+
const text = extractUserText(entry);
|
|
78
|
+
if (!text)
|
|
79
|
+
continue;
|
|
80
|
+
const timestamp = extractTimestamp(entry);
|
|
81
|
+
if (context.since && timestamp) {
|
|
82
|
+
const ts = new Date(timestamp);
|
|
83
|
+
if (ts < context.since)
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
yield {
|
|
87
|
+
text,
|
|
88
|
+
timestamp: timestamp ?? undefined,
|
|
89
|
+
session: context.session,
|
|
90
|
+
project: context.project,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
catch {
|
|
94
|
+
// Skip malformed lines
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
function extractUserText(entry) {
|
|
99
|
+
// Format: { "type": "user", "message": { "role": "user", "content": "..." } }
|
|
100
|
+
if (entry["type"] === "user") {
|
|
101
|
+
const message = entry["message"];
|
|
102
|
+
if (!message)
|
|
103
|
+
return null;
|
|
104
|
+
return contentToString(message["content"]);
|
|
105
|
+
}
|
|
106
|
+
// Legacy format: { "type": "human", "message": { "content": [...] } }
|
|
107
|
+
if (entry["type"] === "human") {
|
|
108
|
+
const message = entry["message"];
|
|
109
|
+
if (!message)
|
|
110
|
+
return null;
|
|
111
|
+
return contentToString(message["content"]);
|
|
112
|
+
}
|
|
113
|
+
// Flat format: { "role": "user", "content": "..." }
|
|
114
|
+
if (entry["role"] === "user") {
|
|
115
|
+
return contentToString(entry["content"]);
|
|
116
|
+
}
|
|
117
|
+
return null;
|
|
118
|
+
}
|
|
119
|
+
function contentToString(content) {
|
|
120
|
+
if (typeof content === "string")
|
|
121
|
+
return content;
|
|
122
|
+
if (Array.isArray(content)) {
|
|
123
|
+
const parts = content
|
|
124
|
+
.filter((p) => typeof p === "object" && p !== null && p.type === "text")
|
|
125
|
+
.map((p) => p.text);
|
|
126
|
+
return parts.length > 0 ? parts.join(" ") : null;
|
|
127
|
+
}
|
|
128
|
+
return null;
|
|
129
|
+
}
|
|
130
|
+
function extractTimestamp(entry) {
|
|
131
|
+
if (typeof entry["timestamp"] === "string")
|
|
132
|
+
return entry["timestamp"];
|
|
133
|
+
if (typeof entry["createdAt"] === "string")
|
|
134
|
+
return entry["createdAt"];
|
|
135
|
+
return null;
|
|
136
|
+
}
|
|
137
|
+
//# sourceMappingURL=claude.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude.js","sourceRoot":"","sources":["../../../src/adapters/claude.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cline.d.ts","sourceRoot":"","sources":["../../../src/adapters/cline.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,OAAO,EAA2B,MAAM,SAAS,CAAC;AAsEhE,wBAAgB,YAAY,IAAI,OAAO,CAqDtC"}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { readdir, readFile, stat } from "node:fs/promises";
|
|
2
|
+
import { existsSync } from "node:fs";
|
|
3
|
+
import { homedir } from "node:os";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
/**
|
|
6
|
+
* Cline (formerly Claude Dev) stores task history at:
|
|
7
|
+
*
|
|
8
|
+
* VS Code extension:
|
|
9
|
+
* macOS: ~/Library/Application Support/Code/User/globalStorage/saoudrizwan.claude-dev/tasks/<task-id>/api_conversation_history.json
|
|
10
|
+
* Linux: ~/.config/Code/User/globalStorage/saoudrizwan.claude-dev/tasks/<task-id>/api_conversation_history.json
|
|
11
|
+
* Windows: %APPDATA%/Code/User/globalStorage/saoudrizwan.claude-dev/tasks/<task-id>/api_conversation_history.json
|
|
12
|
+
*
|
|
13
|
+
* Standalone CLI / JetBrains (newer):
|
|
14
|
+
* ~/.cline/data/tasks/<task-id>/api_conversation_history.json
|
|
15
|
+
*
|
|
16
|
+
* Roo Code (fork) uses the same format at:
|
|
17
|
+
* globalStorage/rooveterinaryinc.roo-cline/tasks/<task-id>/api_conversation_history.json
|
|
18
|
+
*
|
|
19
|
+
* Each api_conversation_history.json is a JSON array of messages:
|
|
20
|
+
* [{ "role": "user"|"assistant", "content": "..." | [{type: "text", text: "..."}] }]
|
|
21
|
+
*/
|
|
22
|
+
function getClineTaskDirs() {
|
|
23
|
+
const dirs = [];
|
|
24
|
+
// VS Code extension paths
|
|
25
|
+
const vscodePaths = getVSCodeGlobalStoragePaths();
|
|
26
|
+
const extensionIds = ["saoudrizwan.claude-dev", "rooveterinaryinc.roo-cline"];
|
|
27
|
+
for (const basePath of vscodePaths) {
|
|
28
|
+
for (const extId of extensionIds) {
|
|
29
|
+
const tasksDir = join(basePath, extId, "tasks");
|
|
30
|
+
if (existsSync(tasksDir))
|
|
31
|
+
dirs.push(tasksDir);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
// Standalone CLI path
|
|
35
|
+
const clineStandalone = join(homedir(), ".cline", "data", "tasks");
|
|
36
|
+
if (existsSync(clineStandalone))
|
|
37
|
+
dirs.push(clineStandalone);
|
|
38
|
+
return dirs;
|
|
39
|
+
}
|
|
40
|
+
function getVSCodeGlobalStoragePaths() {
|
|
41
|
+
const paths = [];
|
|
42
|
+
if (process.platform === "darwin") {
|
|
43
|
+
paths.push(join(homedir(), "Library", "Application Support", "Code", "User", "globalStorage"), join(homedir(), "Library", "Application Support", "Code - Insiders", "User", "globalStorage"), join(homedir(), "Library", "Application Support", "Cursor", "User", "globalStorage"));
|
|
44
|
+
}
|
|
45
|
+
else if (process.platform === "linux") {
|
|
46
|
+
const configBase = process.env["XDG_CONFIG_HOME"] ?? join(homedir(), ".config");
|
|
47
|
+
paths.push(join(configBase, "Code", "User", "globalStorage"), join(configBase, "Code - Insiders", "User", "globalStorage"), join(configBase, "Cursor", "User", "globalStorage"));
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
// Windows
|
|
51
|
+
const appData = process.env["APPDATA"] ?? join(homedir(), "AppData", "Roaming");
|
|
52
|
+
paths.push(join(appData, "Code", "User", "globalStorage"), join(appData, "Code - Insiders", "User", "globalStorage"), join(appData, "Cursor", "User", "globalStorage"));
|
|
53
|
+
}
|
|
54
|
+
return paths;
|
|
55
|
+
}
|
|
56
|
+
export function clineAdapter() {
|
|
57
|
+
return {
|
|
58
|
+
name: "cline",
|
|
59
|
+
async *messages(options) {
|
|
60
|
+
const taskDirs = getClineTaskDirs();
|
|
61
|
+
for (const tasksDir of taskDirs) {
|
|
62
|
+
let taskIds;
|
|
63
|
+
try {
|
|
64
|
+
taskIds = await readdir(tasksDir);
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
for (const taskId of taskIds) {
|
|
70
|
+
const taskDir = join(tasksDir, taskId);
|
|
71
|
+
const taskStat = await stat(taskDir).catch(() => null);
|
|
72
|
+
if (!taskStat?.isDirectory())
|
|
73
|
+
continue;
|
|
74
|
+
const historyFile = join(taskDir, "api_conversation_history.json");
|
|
75
|
+
try {
|
|
76
|
+
const raw = await readFile(historyFile, "utf-8");
|
|
77
|
+
const messages = JSON.parse(raw);
|
|
78
|
+
if (!Array.isArray(messages))
|
|
79
|
+
continue;
|
|
80
|
+
for (const msg of messages) {
|
|
81
|
+
if (msg.role !== "user")
|
|
82
|
+
continue;
|
|
83
|
+
const text = extractText(msg.content);
|
|
84
|
+
if (!text)
|
|
85
|
+
continue;
|
|
86
|
+
// Cline doesn't store per-message timestamps in the conversation file
|
|
87
|
+
// Use the task metadata file for approximate timing
|
|
88
|
+
const timestamp = msg.ts ?? undefined;
|
|
89
|
+
if (options?.since && timestamp) {
|
|
90
|
+
const ts = new Date(timestamp);
|
|
91
|
+
if (ts < options.since)
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
yield {
|
|
95
|
+
text,
|
|
96
|
+
session: taskId,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
catch {
|
|
101
|
+
// Skip tasks without history or malformed files
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
function extractText(content) {
|
|
109
|
+
if (typeof content === "string")
|
|
110
|
+
return content;
|
|
111
|
+
if (Array.isArray(content)) {
|
|
112
|
+
const parts = content
|
|
113
|
+
.filter((p) => typeof p === "object" &&
|
|
114
|
+
p !== null &&
|
|
115
|
+
p.type === "text" &&
|
|
116
|
+
typeof p.text === "string")
|
|
117
|
+
.map((p) => p.text);
|
|
118
|
+
return parts.length > 0 ? parts.join(" ") : null;
|
|
119
|
+
}
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
//# sourceMappingURL=cline.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cline.js","sourceRoot":"","sources":["../../../src/adapters/cline.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAC3D,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAGjC;;;;;;;;;;;;;;;;GAgBG;AAEH,SAAS,gBAAgB;IACvB,MAAM,IAAI,GAAa,EAAE,CAAC;IAE1B,0BAA0B;IAC1B,MAAM,WAAW,GAAG,2BAA2B,EAAE,CAAC;IAClD,MAAM,YAAY,GAAG,CAAC,wBAAwB,EAAE,4BAA4B,CAAC,CAAC;IAE9E,KAAK,MAAM,QAAQ,IAAI,WAAW,EAAE,CAAC;QACnC,KAAK,MAAM,KAAK,IAAI,YAAY,EAAE,CAAC;YACjC,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;YAChD,IAAI,UAAU,CAAC,QAAQ,CAAC;gBAAE,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAChD,CAAC;IACH,CAAC;IAED,sBAAsB;IACtB,MAAM,eAAe,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;IACnE,IAAI,UAAU,CAAC,eAAe,CAAC;QAAE,IAAI,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;IAE5D,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,2BAA2B;IAClC,MAAM,KAAK,GAAa,EAAE,CAAC;IAE3B,IAAI,OAAO,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAClC,KAAK,CAAC,IAAI,CACR,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,qBAAqB,EAAE,MAAM,EAAE,MAAM,EAAE,eAAe,CAAC,EAClF,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,MAAM,EAAE,eAAe,CAAC,EAC7F,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,qBAAqB,EAAE,QAAQ,EAAE,MAAM,EAAE,eAAe,CAAC,CACrF,CAAC;IACJ,CAAC;SAAM,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;QACxC,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,CAAC,CAAC;QAChF,KAAK,CAAC,IAAI,CACR,IAAI,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,eAAe,CAAC,EACjD,IAAI,CAAC,UAAU,EAAE,iBAAiB,EAAE,MAAM,EAAE,eAAe,CAAC,EAC5D,IAAI,CAAC,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,eAAe,CAAC,CACpD,CAAC;IACJ,CAAC;SAAM,CAAC;QACN,UAAU;QACV,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC;QAChF,KAAK,CAAC,IAAI,CACR,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,eAAe,CAAC,EAC9C,IAAI,CAAC,OAAO,EAAE,iBAAiB,EAAE,MAAM,EAAE,eAAe,CAAC,EACzD,IAAI,CAAC,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,eAAe,CAAC,CACjD,CAAC;IACJ,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,UAAU,YAAY;IAC1B,OAAO;QACL,IAAI,EAAE,OAAO;QACb,KAAK,CAAC,CAAC,QAAQ,CAAC,OAAwB;YACtC,MAAM,QAAQ,GAAG,gBAAgB,EAAE,CAAC;YAEpC,KAAK,MAAM,QAAQ,IAAI,QAAQ,EAAE,CAAC;gBAChC,IAAI,OAAiB,CAAC;gBACtB,IAAI,CAAC;oBACH,OAAO,GAAG,MAAM,OAAO,CAAC,QAAQ,CAAC,CAAC;gBACpC,CAAC;gBAAC,MAAM,CAAC;oBACP,SAAS;gBACX,CAAC;gBAED,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;oBAC7B,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;oBACvC,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;oBACvD,IAAI,CAAC,QAAQ,EAAE,WAAW,EAAE;wBAAE,SAAS;oBAEvC,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,EAAE,+BAA+B,CAAC,CAAC;oBAEnE,IAAI,CAAC;wBACH,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;wBACjD,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAmB,CAAC;wBAEnD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC;4BAAE,SAAS;wBAEvC,KAAK,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAC;4BAC3B,IAAI,GAAG,CAAC,IAAI,KAAK,MAAM;gCAAE,SAAS;4BAElC,MAAM,IAAI,GAAG,WAAW,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;4BACtC,IAAI,CAAC,IAAI;gCAAE,SAAS;4BAEpB,sEAAsE;4BACtE,oDAAoD;4BACpD,MAAM,SAAS,GAAG,GAAG,CAAC,EAAE,IAAI,SAAS,CAAC;4BACtC,IAAI,OAAO,EAAE,KAAK,IAAI,SAAS,EAAE,CAAC;gCAChC,MAAM,EAAE,GAAG,IAAI,IAAI,CAAC,SAAS,CAAC,CAAC;gCAC/B,IAAI,EAAE,GAAG,OAAO,CAAC,KAAK;oCAAE,SAAS;4BACnC,CAAC;4BAED,MAAM;gCACJ,IAAI;gCACJ,OAAO,EAAE,MAAM;6BAChB,CAAC;wBACJ,CAAC;oBACH,CAAC;oBAAC,MAAM,CAAC;wBACP,gDAAgD;oBAClD,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC;AAED,SAAS,WAAW,CAAC,OAAgB;IACnC,IAAI,OAAO,OAAO,KAAK,QAAQ;QAAE,OAAO,OAAO,CAAC;IAChD,IAAI,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QAC3B,MAAM,KAAK,GAAG,OAAO;aAClB,MAAM,CACL,CAAC,CAAC,EAAuC,EAAE,CACzC,OAAO,CAAC,KAAK,QAAQ;YACrB,CAAC,KAAK,IAAI;YACV,CAAC,CAAC,IAAI,KAAK,MAAM;YACjB,OAAO,CAAC,CAAC,IAAI,KAAK,QAAQ,CAC7B;aACA,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QACtB,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IACnD,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codex.d.ts","sourceRoot":"","sources":["../../../src/adapters/codex.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,OAAO,EAA2B,MAAM,SAAS,CAAC;AAiBhE,wBAAgB,YAAY,IAAI,OAAO,CAOtC"}
|