devrage 0.0.1 → 0.0.3
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 +72 -13
- package/dist/cli.js.map +3 -3
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -515,7 +515,7 @@ async function* parseAgentThreads(dbDir, _options) {
|
|
|
515
515
|
continue;
|
|
516
516
|
}
|
|
517
517
|
const columns = db.prepare(`PRAGMA table_info("${msgTable}")`).all();
|
|
518
|
-
const colNames = columns.map((
|
|
518
|
+
const colNames = columns.map((c2) => c2.name);
|
|
519
519
|
const hasRole = colNames.includes("role");
|
|
520
520
|
if (!hasRole) {
|
|
521
521
|
db.close();
|
|
@@ -708,6 +708,59 @@ function runPattern(_originalText, searchText, matches, seen) {
|
|
|
708
708
|
}
|
|
709
709
|
|
|
710
710
|
// src/commands/scan.ts
|
|
711
|
+
var c = {
|
|
712
|
+
reset: "\x1B[0m",
|
|
713
|
+
bold: "\x1B[1m",
|
|
714
|
+
dim: "\x1B[2m",
|
|
715
|
+
red: "\x1B[31m",
|
|
716
|
+
green: "\x1B[32m",
|
|
717
|
+
yellow: "\x1B[33m",
|
|
718
|
+
blue: "\x1B[34m",
|
|
719
|
+
magenta: "\x1B[35m",
|
|
720
|
+
cyan: "\x1B[36m",
|
|
721
|
+
white: "\x1B[37m",
|
|
722
|
+
gray: "\x1B[90m"
|
|
723
|
+
};
|
|
724
|
+
var SPINNER_MESSAGES = [
|
|
725
|
+
"Tallying the damage",
|
|
726
|
+
"Reviewing your outbursts",
|
|
727
|
+
"Judging your vocabulary",
|
|
728
|
+
"Computing your shame",
|
|
729
|
+
"Cataloging the profanity",
|
|
730
|
+
"Measuring your frustration",
|
|
731
|
+
"Assessing the verbal carnage",
|
|
732
|
+
"Quantifying your displeasure",
|
|
733
|
+
"Auditing your language",
|
|
734
|
+
"Tabulating regrets"
|
|
735
|
+
];
|
|
736
|
+
function createSpinner() {
|
|
737
|
+
let messageIdx = 0;
|
|
738
|
+
let dotCount = 0;
|
|
739
|
+
let timer = null;
|
|
740
|
+
return {
|
|
741
|
+
start() {
|
|
742
|
+
messageIdx = Math.floor(Math.random() * SPINNER_MESSAGES.length);
|
|
743
|
+
timer = setInterval(() => {
|
|
744
|
+
dotCount = (dotCount + 1) % 4;
|
|
745
|
+
const msg = SPINNER_MESSAGES[messageIdx % SPINNER_MESSAGES.length];
|
|
746
|
+
const dots = ".".repeat(dotCount || 1);
|
|
747
|
+
process.stdout.write(
|
|
748
|
+
`\r ${c.dim}${msg}${dots}${c.reset} `
|
|
749
|
+
);
|
|
750
|
+
}, 300);
|
|
751
|
+
},
|
|
752
|
+
update() {
|
|
753
|
+
messageIdx++;
|
|
754
|
+
},
|
|
755
|
+
stop() {
|
|
756
|
+
if (timer) {
|
|
757
|
+
clearInterval(timer);
|
|
758
|
+
timer = null;
|
|
759
|
+
}
|
|
760
|
+
process.stdout.write("\r" + " ".repeat(60) + "\r");
|
|
761
|
+
}
|
|
762
|
+
};
|
|
763
|
+
}
|
|
711
764
|
function parseArgs(args) {
|
|
712
765
|
const options = {};
|
|
713
766
|
for (let i = 0; i < args.length; i++) {
|
|
@@ -738,6 +791,8 @@ Options:
|
|
|
738
791
|
async function scan(args) {
|
|
739
792
|
const options = parseArgs(args);
|
|
740
793
|
const adapters = options.agent ? [createAdapter(options.agent)] : allAdapters();
|
|
794
|
+
const spinner = createSpinner();
|
|
795
|
+
spinner.start();
|
|
741
796
|
const groupTally = {};
|
|
742
797
|
const variantTally = {};
|
|
743
798
|
let totalMessages = 0;
|
|
@@ -746,6 +801,7 @@ async function scan(args) {
|
|
|
746
801
|
for (const adapter of adapters) {
|
|
747
802
|
let agentMessages = 0;
|
|
748
803
|
let agentSwears = 0;
|
|
804
|
+
spinner.update();
|
|
749
805
|
for await (const message of adapter.messages({ since: options.since })) {
|
|
750
806
|
totalMessages++;
|
|
751
807
|
agentMessages++;
|
|
@@ -764,37 +820,40 @@ async function scan(args) {
|
|
|
764
820
|
perAgent[adapter.name] = { messages: agentMessages, swears: agentSwears };
|
|
765
821
|
}
|
|
766
822
|
}
|
|
823
|
+
spinner.stop();
|
|
767
824
|
console.log("");
|
|
768
|
-
console.log(
|
|
769
|
-
console.log(
|
|
825
|
+
console.log(` ${c.bold}${c.red}devrage${c.reset} ${c.dim}report${c.reset}`);
|
|
826
|
+
console.log(` ${c.dim}${"\u2500".repeat(30)}${c.reset}`);
|
|
770
827
|
console.log("");
|
|
771
|
-
console.log(` messages scanned
|
|
772
|
-
console.log(` total swears
|
|
828
|
+
console.log(` ${c.dim}messages scanned${c.reset} ${c.bold}${totalMessages}${c.reset}`);
|
|
829
|
+
console.log(` ${c.dim}total swears${c.reset} ${c.bold}${c.red}${totalSwears}${c.reset}`);
|
|
773
830
|
const activeAgents = Object.entries(perAgent);
|
|
774
831
|
if (activeAgents.length > 1) {
|
|
775
832
|
console.log("");
|
|
776
|
-
console.log(
|
|
833
|
+
console.log(` ${c.bold}by agent${c.reset}`);
|
|
777
834
|
for (const [name, stats] of activeAgents) {
|
|
778
835
|
const rate = (stats.swears / stats.messages * 100).toFixed(1);
|
|
779
836
|
console.log(
|
|
780
|
-
` ${name.padEnd(10)} ${String(stats.swears).padStart(4)}
|
|
837
|
+
` ${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}`
|
|
781
838
|
);
|
|
782
839
|
}
|
|
783
840
|
}
|
|
784
841
|
if (totalSwears > 0) {
|
|
785
842
|
const sorted = Object.entries(groupTally).sort(([, a], [, b]) => b - a);
|
|
786
843
|
console.log("");
|
|
787
|
-
console.log(
|
|
844
|
+
console.log(` ${c.bold}top words${c.reset}`);
|
|
788
845
|
for (const [group, count] of sorted.slice(0, 10)) {
|
|
789
846
|
const variants = variantTally[group] ?? {};
|
|
790
|
-
const variantList = Object.entries(variants).sort(([, a], [, b]) => b - a).filter(([v]) => v !== group).slice(0, 15).map(([v,
|
|
791
|
-
const suffix = variantList ? ` (${variantList})` : "";
|
|
792
|
-
console.log(
|
|
847
|
+
const variantList = Object.entries(variants).sort(([, a], [, b]) => b - a).filter(([v]) => v !== group).slice(0, 15).map(([v, cnt]) => `${c.dim}${v}${c.reset} ${cnt}`).join(`${c.dim},${c.reset} `);
|
|
848
|
+
const suffix = variantList ? ` ${c.dim}(${c.reset}${variantList}${c.dim})${c.reset}` : "";
|
|
849
|
+
console.log(
|
|
850
|
+
` ${c.yellow}${group.padEnd(12)}${c.reset} ${c.bold}${String(count).padStart(4)}${c.reset}${suffix}`
|
|
851
|
+
);
|
|
793
852
|
}
|
|
794
853
|
}
|
|
795
854
|
console.log("");
|
|
796
855
|
if (totalSwears === 0) {
|
|
797
|
-
console.log(
|
|
856
|
+
console.log(` ${c.green}squeaky clean! not a single swear found.${c.reset}`);
|
|
798
857
|
console.log("");
|
|
799
858
|
}
|
|
800
859
|
}
|
|
@@ -829,7 +888,7 @@ async function main() {
|
|
|
829
888
|
process.exit(0);
|
|
830
889
|
}
|
|
831
890
|
if (command === "--version") {
|
|
832
|
-
console.log("0.0.
|
|
891
|
+
console.log("0.0.3");
|
|
833
892
|
process.exit(0);
|
|
834
893
|
}
|
|
835
894
|
const handler = command ? COMMANDS[command] : void 0;
|
package/dist/cli.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
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/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 { 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 { 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 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\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(`devrage 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 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\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 // Report\n console.log(\"\");\n console.log(\" devrage report\");\n console.log(\" ===============\");\n console.log(\"\");\n console.log(` messages scanned: ${totalMessages}`);\n console.log(` total swears: ${totalSwears}`);\n\n\n\n const activeAgents = Object.entries(perAgent);\n if (activeAgents.length > 1) {\n console.log(\"\");\n console.log(\" by agent:\");\n for (const [name, stats] of activeAgents) {\n const rate = ((stats.swears / stats.messages) * 100).toFixed(1);\n console.log(\n ` ${name.padEnd(10)} ${String(stats.swears).padStart(4)} swears in ${stats.messages} messages (${rate}%)`,\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(\" top words:\");\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) // don't repeat the group name itself\n .slice(0, 15)\n .map(([v, c]) => `${v} ${c}`)\n .join(\", \");\n const suffix = variantList ? ` (${variantList})` : \"\";\n console.log(` ${group.padEnd(12)} ${String(count).padStart(4)}${suffix}`);\n }\n }\n\n console.log(\"\");\n if (totalSwears === 0) {\n console.log(\" squeaky clean! not a single swear found.\");\n console.log(\"\");\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(`devrage \u2014 count how many times you swear at your coding agents\n\nUsage:\n devrage <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 devrage scan\n devrage scan --agent claude\n devrage 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.1\");\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", "readdir", "readFile", "existsSync", "homedir", "join", "base"]
|
|
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 { 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 { 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 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(`devrage 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(`devrage \u2014 count how many times you swear at your coding agents\n\nUsage:\n devrage <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 devrage scan\n devrage scan --agent claude\n devrage 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.3\");\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": ";;;AAAA,SAAS,SAAS,gBAAgB;AAClC,SAAS,eAAe;AACxB,SAAS,YAAY;AAarB,SAAS,mBAA2B;AAClC,SAAO;AAAA,IACL,QAAQ,IAAI,eAAe,KAAK,KAAK,QAAQ,GAAG,UAAU,OAAO;AAAA,IACjE;AAAA,IACA;AAAA,EACF;AACF;AAEO,SAAS,aAAsB;AACpC,SAAO;AAAA,IACL,MAAM;AAAA,IACN,OAAO,SAAS,SAAmD;AACjE,YAAM,aAAa,iBAAiB;AAEpC,UAAI;AACJ,UAAI;AACF,gBAAQ,MAAM,QAAQ,UAAU;AAAA,MAClC,QAAQ;AACN;AAAA,MACF;AAEA,YAAM,YAAY,MAAM,OAAO,CAAC,MAAM,EAAE,SAAS,OAAO,CAAC;AAEzD,iBAAW,QAAQ,WAAW;AAC5B,cAAM,WAAW,KAAK,YAAY,IAAI;AACtC,cAAM,WAAW,KAAK,QAAQ,SAAS,EAAE;AAEzC,YAAI;AACF,gBAAM,MAAM,MAAM,SAAS,UAAU,OAAO;AAC5C,gBAAM,SAAS,KAAK,MAAM,GAAG;AAE7B,cAAI,CAAC,OAAO,YAAY,CAAC,MAAM,QAAQ,OAAO,QAAQ,EAAG;AAEzD,qBAAW,OAAO,OAAO,UAAU;AACjC,gBAAI,IAAI,SAAS,OAAQ;AAEzB,kBAAM,OAAO,YAAY,IAAI,OAAO;AACpC,gBAAI,CAAC,KAAM;AAEX,kBAAM,YAAY,IAAI,aAAa,IAAI,aAAa;AACpD,gBAAI,SAAS,SAAS,WAAW;AAC/B,oBAAM,KAAK,IAAI,KAAK,SAAS;AAC7B,kBAAI,KAAK,QAAQ,MAAO;AAAA,YAC1B;AAEA,kBAAM;AAAA,cACJ;AAAA,cACA;AAAA,cACA,SAAS;AAAA,YACX;AAAA,UACF;AAAA,QACF,QAAQ;AAAA,QAER;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;AAEA,SAAS,YAAY,SAAiC;AACpD,MAAI,OAAO,YAAY,SAAU,QAAO;AACxC,MAAI,MAAM,QAAQ,OAAO,GAAG;AAC1B,UAAM,QAAQ,QACX;AAAA,MACC,CAAC,MACC,OAAO,MAAM,YAAY,MAAM,QAAQ,OAAO,EAAE,SAAS;AAAA,IAC7D,EACC,IAAI,CAAC,MAAM,EAAE,IAAI;AACpB,WAAO,MAAM,SAAS,IAAI,MAAM,KAAK,GAAG,IAAI;AAAA,EAC9C;AACA,SAAO;AACT;;;ACtFA,SAAS,wBAAwB;AACjC,SAAS,WAAAA,UAAS,YAAY;AAC9B,SAAS,uBAAuB;AAChC,SAAS,WAAAC,gBAAe;AACxB,SAAS,QAAAC,aAAY;AAarB,IAAM,aAAaA,MAAKD,SAAQ,GAAG,WAAW,UAAU;AAEjD,SAAS,gBAAyB;AACvC,SAAO;AAAA,IACL,MAAM;AAAA,IACN,OAAO,SAAS,SAAmD;AACjE,YAAM,cAAc;AAEpB,UAAI;AACJ,UAAI;AACF,sBAAc,MAAMD,SAAQ,WAAW;AAAA,MACzC,QAAQ;AACN;AAAA,MACF;AAEA,iBAAW,cAAc,aAAa;AACpC,cAAM,cAAcE,MAAK,aAAa,UAAU;AAChD,cAAM,cAAc,MAAM,KAAK,WAAW;AAC1C,YAAI,CAAC,YAAY,YAAY,EAAG;AAEhC,cAAM,UAAU,MAAMF,SAAQ,WAAW;AACzC,cAAM,aAAa,QAAQ,OAAO,CAAC,MAAM,EAAE,SAAS,QAAQ,CAAC;AAE7D,mBAAW,QAAQ,YAAY;AAC7B,gBAAM,WAAWE,MAAK,aAAa,IAAI;AACvC,gBAAM,UAAU,KAAK,QAAQ,UAAU,EAAE;AAEzC,iBAAO,iBAAiB,UAAU;AAAA,YAChC;AAAA,YACA,SAAS;AAAA,YACT,OAAO,SAAS;AAAA,UAClB,CAAC;AAAA,QACH;AAGA,cAAM,UAAU,QAAQ,OAAO,CAAC,MAAM,CAAC,EAAE,SAAS,GAAG,CAAC;AACtD,mBAAW,UAAU,SAAS;AAC5B,gBAAM,eAAeA,MAAK,aAAa,QAAQ,WAAW;AAC1D,cAAI;AACF,kBAAM,WAAW,MAAMF,SAAQ,YAAY;AAC3C,kBAAM,WAAW,SAAS,OAAO,CAAC,MAAM,EAAE,SAAS,QAAQ,CAAC;AAC5D,uBAAW,QAAQ,UAAU;AAC3B,qBAAO,iBAAiBE,MAAK,cAAc,IAAI,GAAG;AAAA,gBAChD,SAAS,GAAG,MAAM,IAAI,KAAK,QAAQ,UAAU,EAAE,CAAC;AAAA,gBAChD,SAAS;AAAA,gBACT,OAAO,SAAS;AAAA,cAClB,CAAC;AAAA,YACH;AAAA,UACF,QAAQ;AAAA,UAER;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;AAEA,gBAAgB,iBACd,UACA,SACyB;AACzB,QAAM,KAAK,gBAAgB;AAAA,IACzB,OAAO,iBAAiB,UAAU,EAAE,UAAU,QAAQ,CAAC;AAAA,IACvD,WAAW;AAAA,EACb,CAAC;AAED,mBAAiB,QAAQ,IAAI;AAC3B,QAAI,CAAC,KAAK,KAAK,EAAG;AAElB,QAAI;AACF,YAAM,QAAQ,KAAK,MAAM,IAAI;AAC7B,YAAM,OAAO,gBAAgB,KAAK;AAClC,UAAI,CAAC,KAAM;AAEX,YAAM,YAAY,iBAAiB,KAAK;AACxC,UAAI,QAAQ,SAAS,WAAW;AAC9B,cAAM,KAAK,IAAI,KAAK,SAAS;AAC7B,YAAI,KAAK,QAAQ,MAAO;AAAA,MAC1B;AAEA,YAAM;AAAA,QACJ;AAAA,QACA,WAAW,aAAa;AAAA,QACxB,SAAS,QAAQ;AAAA,QACjB,SAAS,QAAQ;AAAA,MACnB;AAAA,IACF,QAAQ;AAAA,IAER;AAAA,EACF;AACF;AAEA,SAAS,gBAAgB,OAA+C;AAEtE,MAAI,MAAM,MAAM,MAAM,QAAQ;AAC5B,UAAM,UAAU,MAAM,SAAS;AAC/B,QAAI,CAAC,QAAS,QAAO;AACrB,WAAO,gBAAgB,QAAQ,SAAS,CAAC;AAAA,EAC3C;AAGA,MAAI,MAAM,MAAM,MAAM,SAAS;AAC7B,UAAM,UAAU,MAAM,SAAS;AAC/B,QAAI,CAAC,QAAS,QAAO;AACrB,WAAO,gBAAgB,QAAQ,SAAS,CAAC;AAAA,EAC3C;AAGA,MAAI,MAAM,MAAM,MAAM,QAAQ;AAC5B,WAAO,gBAAgB,MAAM,SAAS,CAAC;AAAA,EACzC;AAEA,SAAO;AACT;AAEA,SAAS,gBAAgB,SAAiC;AACxD,MAAI,OAAO,YAAY,SAAU,QAAO;AACxC,MAAI,MAAM,QAAQ,OAAO,GAAG;AAC1B,UAAM,QAAQ,QACX;AAAA,MACC,CAAC,MACC,OAAO,MAAM,YAAY,MAAM,QAAQ,EAAE,SAAS;AAAA,IACtD,EACC,IAAI,CAAC,MAAM,EAAE,IAAI;AACpB,WAAO,MAAM,SAAS,IAAI,MAAM,KAAK,GAAG,IAAI;AAAA,EAC9C;AACA,SAAO;AACT;AAEA,SAAS,iBAAiB,OAA+C;AACvE,MAAI,OAAO,MAAM,WAAW,MAAM,SAAU,QAAO,MAAM,WAAW;AACpE,MAAI,OAAO,MAAM,WAAW,MAAM,SAAU,QAAO,MAAM,WAAW;AACpE,SAAO;AACT;;;ACtJA,SAAS,WAAAC,UAAS,YAAAC,WAAU,QAAAC,aAAY;AACxC,SAAS,kBAAkB;AAC3B,SAAS,WAAAC,gBAAe;AACxB,SAAS,QAAAC,aAAY;AAqBrB,SAAS,mBAA6B;AACpC,QAAM,OAAiB,CAAC;AAGxB,QAAM,cAAc,4BAA4B;AAChD,QAAM,eAAe,CAAC,0BAA0B,4BAA4B;AAE5E,aAAW,YAAY,aAAa;AAClC,eAAW,SAAS,cAAc;AAChC,YAAM,WAAWA,MAAK,UAAU,OAAO,OAAO;AAC9C,UAAI,WAAW,QAAQ,EAAG,MAAK,KAAK,QAAQ;AAAA,IAC9C;AAAA,EACF;AAGA,QAAM,kBAAkBA,MAAKD,SAAQ,GAAG,UAAU,QAAQ,OAAO;AACjE,MAAI,WAAW,eAAe,EAAG,MAAK,KAAK,eAAe;AAE1D,SAAO;AACT;AAEA,SAAS,8BAAwC;AAC/C,QAAM,QAAkB,CAAC;AAEzB,MAAI,QAAQ,aAAa,UAAU;AACjC,UAAM;AAAA,MACJC,MAAKD,SAAQ,GAAG,WAAW,uBAAuB,QAAQ,QAAQ,eAAe;AAAA,MACjFC,MAAKD,SAAQ,GAAG,WAAW,uBAAuB,mBAAmB,QAAQ,eAAe;AAAA,MAC5FC,MAAKD,SAAQ,GAAG,WAAW,uBAAuB,UAAU,QAAQ,eAAe;AAAA,IACrF;AAAA,EACF,WAAW,QAAQ,aAAa,SAAS;AACvC,UAAM,aAAa,QAAQ,IAAI,iBAAiB,KAAKC,MAAKD,SAAQ,GAAG,SAAS;AAC9E,UAAM;AAAA,MACJC,MAAK,YAAY,QAAQ,QAAQ,eAAe;AAAA,MAChDA,MAAK,YAAY,mBAAmB,QAAQ,eAAe;AAAA,MAC3DA,MAAK,YAAY,UAAU,QAAQ,eAAe;AAAA,IACpD;AAAA,EACF,OAAO;AAEL,UAAM,UAAU,QAAQ,IAAI,SAAS,KAAKA,MAAKD,SAAQ,GAAG,WAAW,SAAS;AAC9E,UAAM;AAAA,MACJC,MAAK,SAAS,QAAQ,QAAQ,eAAe;AAAA,MAC7CA,MAAK,SAAS,mBAAmB,QAAQ,eAAe;AAAA,MACxDA,MAAK,SAAS,UAAU,QAAQ,eAAe;AAAA,IACjD;AAAA,EACF;AAEA,SAAO;AACT;AAEO,SAAS,eAAwB;AACtC,SAAO;AAAA,IACL,MAAM;AAAA,IACN,OAAO,SAAS,SAAmD;AACjE,YAAM,WAAW,iBAAiB;AAElC,iBAAW,YAAY,UAAU;AAC/B,YAAI;AACJ,YAAI;AACF,oBAAU,MAAMJ,SAAQ,QAAQ;AAAA,QAClC,QAAQ;AACN;AAAA,QACF;AAEA,mBAAW,UAAU,SAAS;AAC5B,gBAAM,UAAUI,MAAK,UAAU,MAAM;AACrC,gBAAM,WAAW,MAAMF,MAAK,OAAO,EAAE,MAAM,MAAM,IAAI;AACrD,cAAI,CAAC,UAAU,YAAY,EAAG;AAE9B,gBAAM,cAAcE,MAAK,SAAS,+BAA+B;AAEjE,cAAI;AACF,kBAAM,MAAM,MAAMH,UAAS,aAAa,OAAO;AAC/C,kBAAM,WAAW,KAAK,MAAM,GAAG;AAE/B,gBAAI,CAAC,MAAM,QAAQ,QAAQ,EAAG;AAE9B,uBAAW,OAAO,UAAU;AAC1B,kBAAI,IAAI,SAAS,OAAQ;AAEzB,oBAAM,OAAOI,aAAY,IAAI,OAAO;AACpC,kBAAI,CAAC,KAAM;AAIX,oBAAM,YAAY,IAAI,MAAM;AAC5B,kBAAI,SAAS,SAAS,WAAW;AAC/B,sBAAM,KAAK,IAAI,KAAK,SAAS;AAC7B,oBAAI,KAAK,QAAQ,MAAO;AAAA,cAC1B;AAEA,oBAAM;AAAA,gBACJ;AAAA,gBACA,SAAS;AAAA,cACX;AAAA,YACF;AAAA,UACF,QAAQ;AAAA,UAER;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;AAEA,SAASA,aAAY,SAAiC;AACpD,MAAI,OAAO,YAAY,SAAU,QAAO;AACxC,MAAI,MAAM,QAAQ,OAAO,GAAG;AAC1B,UAAM,QAAQ,QACX;AAAA,MACC,CAAC,MACC,OAAO,MAAM,YACb,MAAM,QACN,EAAE,SAAS,UACX,OAAO,EAAE,SAAS;AAAA,IACtB,EACC,IAAI,CAAC,MAAM,EAAE,IAAI;AACpB,WAAO,MAAM,SAAS,IAAI,MAAM,KAAK,GAAG,IAAI;AAAA,EAC9C;AACA,SAAO;AACT;;;AChJA,SAAS,oBAAAC,yBAAwB;AACjC,SAAS,WAAAC,UAAS,QAAAC,aAAY;AAC9B,SAAS,mBAAAC,wBAAuB;AAChC,SAAS,WAAAC,gBAAe;AACxB,SAAS,QAAAC,aAAY;AAgBrB,IAAM,qBAAqBA,MAAKD,SAAQ,GAAG,UAAU,UAAU;AAExD,SAAS,eAAwB;AACtC,SAAO;AAAA,IACL,MAAM;AAAA,IACN,OAAO,SAAS,SAAmD;AACjE,aAAO,kBAAkB,oBAAoB,OAAO;AAAA,IACtD;AAAA,EACF;AACF;AAEA,gBAAgB,kBACd,KACA,SACyB;AACzB,MAAI;AACJ,MAAI;AACF,cAAU,MAAMH,SAAQ,GAAG;AAAA,EAC7B,QAAQ;AACN;AAAA,EACF;AAEA,aAAW,SAAS,SAAS;AAC3B,UAAM,WAAWI,MAAK,KAAK,KAAK;AAChC,UAAM,YAAY,MAAMH,MAAK,QAAQ;AAErC,QAAI,UAAU,YAAY,GAAG;AAC3B,aAAO,kBAAkB,UAAU,OAAO;AAAA,IAC5C,WAAW,MAAM,SAAS,QAAQ,GAAG;AACnC,YAAM,UAAU,MAAM,QAAQ,UAAU,EAAE;AAC1C,aAAO,gBAAgB,UAAU,EAAE,SAAS,OAAO,SAAS,MAAM,CAAC;AAAA,IACrE;AAAA,EACF;AACF;AAEA,gBAAgB,gBACd,UACA,SACyB;AACzB,QAAM,KAAKC,iBAAgB;AAAA,IACzB,OAAOH,kBAAiB,UAAU,EAAE,UAAU,QAAQ,CAAC;AAAA,IACvD,WAAW;AAAA,EACb,CAAC;AAED,mBAAiB,QAAQ,IAAI;AAC3B,QAAI,CAAC,KAAK,KAAK,EAAG;AAElB,QAAI;AACF,YAAM,QAAQ,KAAK,MAAM,IAAI;AAG7B,UAAI,MAAM,SAAS,gBAAiB;AAEpC,YAAM,UAAU,MAAM;AACtB,UAAI,CAAC,WAAW,QAAQ,SAAS,OAAQ;AAEzC,YAAM,OAAOM,aAAY,QAAQ,OAAO;AACxC,UAAI,CAAC,KAAM;AAGX,UAAI,KAAK,WAAW,uBAAuB,EAAG;AAE9C,UAAI,KAAK,WAAW,4BAA4B,EAAG;AAEnD,UAAI,QAAQ,SAAS,MAAM,WAAW;AACpC,cAAM,KAAK,IAAI,KAAK,MAAM,SAAS;AACnC,YAAI,KAAK,QAAQ,MAAO;AAAA,MAC1B;AAEA,YAAM;AAAA,QACJ;AAAA,QACA,WAAW,MAAM;AAAA,QACjB,SAAS,QAAQ;AAAA,MACnB;AAAA,IACF,QAAQ;AAAA,IAER;AAAA,EACF;AACF;AAEA,SAASA,aAAY,SAAiC;AACpD,MAAI,CAAC,MAAM,QAAQ,OAAO,EAAG,QAAO;AAEpC,QAAM,QAAQ,QACX;AAAA,IACC,CAAC,MACC,OAAO,MAAM,YACb,MAAM,QACN,EAAE,SAAS,gBACX,OAAO,EAAE,SAAS;AAAA,EACtB,EACC,IAAI,CAAC,MAAM,EAAE,IAAI;AAEpB,SAAO,MAAM,SAAS,IAAI,MAAM,KAAK,GAAG,IAAI;AAC9C;;;AClHA,SAAS,cAAAC,mBAAkB;AAC3B,SAAS,WAAAC,gBAAe;AACxB,SAAS,QAAAC,aAAY;AAkBrB,SAAS,0BAAyC;AAEhD,QAAM,UAAUA;AAAA,IACd,QAAQ,IAAI,eAAe,KAAKA,MAAKD,SAAQ,GAAG,UAAU,OAAO;AAAA,IACjE;AAAA,IACA;AAAA,EACF;AACA,MAAID,YAAW,OAAO,EAAG,QAAO;AAGhC,MAAI,QAAQ,aAAa,UAAU;AACjC,UAAM,UAAUE;AAAA,MACdD,SAAQ;AAAA,MACR;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AACA,QAAID,YAAW,OAAO,EAAG,QAAO;AAAA,EAClC;AAEA,SAAO;AACT;AAEO,SAAS,kBAA2B;AACzC,SAAO;AAAA,IACL,MAAM;AAAA,IACN,OAAO,SAAS,SAAmD;AACjE,YAAM,SAAS,wBAAwB;AACvC,UAAI,CAAC,OAAQ;AAGb,UAAI;AACJ,UAAI;AACF,cAAM,gBAAgB,MAAM,OAAO,gBAAgB;AACnD,cAAM,OAAO,cAAc,WAAW;AACtC,aAAK,IAAK,KAAkF,QAAQ,EAAE,UAAU,KAAK,CAAC;AAAA,MACxH,QAAQ;AACN,gBAAQ;AAAA,UACN;AAAA,QACF;AACA;AAAA,MACF;AAEA,UAAI;AACF,eAAO,kBAAkB,IAAI,OAAO;AAAA,MACtC,UAAE;AACA,WAAG,MAAM;AAAA,MACX;AAAA,IACF;AAAA,EACF;AACF;AAEA,UAAU,kBACR,IACA,SACoB;AAEpB,MAAI,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAWZ,MAAI,SAAS,OAAO;AAClB,UAAM,UAAU,QAAQ,MAAM,QAAQ;AACtC,aAAS,0BAA0B,OAAO;AAAA,EAC5C;AAEA,WAAS;AAET,QAAM,OAAO,GAAG,QAAQ,KAAK,EAAE,IAAI;AAMnC,aAAW,OAAO,MAAM;AACtB,QAAI,CAAC,IAAI,QAAQ,CAAC,IAAI,KAAK,KAAK,EAAG;AAEnC,UAAM;AAAA,MACJ,MAAM,IAAI;AAAA,MACV,WAAW,IAAI,KAAK,IAAI,YAAY,EAAE,YAAY;AAAA,MAClD,SAAS,IAAI;AAAA,IACf;AAAA,EACF;AACF;;;AC/GA,SAAS,WAAAG,UAAS,YAAAC,iBAAgB;AAClC,SAAS,cAAAC,mBAAkB;AAC3B,SAAS,WAAAC,gBAAe;AACxB,SAAS,QAAAC,aAAY;AAoBrB,SAAS,cAAqD;AAC5D,MAAI,QAAQ,aAAa,UAAU;AACjC,UAAMC,QAAOD,MAAKD,SAAQ,GAAG,WAAW,uBAAuB,KAAK;AACpE,WAAO;AAAA,MACL,eAAeC,MAAKC,OAAM,eAAe;AAAA,MACzC,IAAID,MAAKC,OAAM,IAAI;AAAA,IACrB;AAAA,EACF;AAEA,QAAM,OAAOD;AAAA,IACX,QAAQ,IAAI,eAAe,KAAKA,MAAKD,SAAQ,GAAG,UAAU,OAAO;AAAA,IACjE;AAAA,EACF;AACA,SAAO;AAAA,IACL,eAAeC,MAAK,MAAM,eAAe;AAAA,IACzC,IAAIA,MAAK,MAAM,IAAI;AAAA,EACrB;AACF;AAEO,SAAS,aAAsB;AACpC,SAAO;AAAA,IACL,MAAM;AAAA,IACN,OAAO,SAAS,SAAmD;AACjE,YAAM,QAAQ,YAAY;AAG1B,aAAO,iBAAiB,MAAM,eAAe,OAAO;AAGpD,aAAO,kBAAkB,MAAM,IAAI,OAAO;AAAA,IAC5C;AAAA,EACF;AACF;AAEA,gBAAgB,iBACd,KACA,UACyB;AACzB,MAAI,CAACF,YAAW,GAAG,EAAG;AAEtB,MAAI;AACJ,MAAI;AACF,YAAQ,MAAMF,SAAQ,GAAG;AAAA,EAC3B,QAAQ;AACN;AAAA,EACF;AAEA,QAAM,YAAY,MAAM,OAAO,CAAC,MAAM,EAAE,SAAS,OAAO,CAAC;AAEzD,aAAW,QAAQ,WAAW;AAC5B,UAAM,WAAWI,MAAK,KAAK,IAAI;AAC/B,UAAM,UAAU,KAAK,QAAQ,SAAS,EAAE;AAExC,QAAI;AACF,YAAM,MAAM,MAAMH,UAAS,UAAU,OAAO;AAC5C,YAAM,eAAe,KAAK,MAAM,GAAG;AAEnC,UAAI,CAAC,aAAa,YAAY,CAAC,MAAM,QAAQ,aAAa,QAAQ,EAAG;AAErE,iBAAW,OAAO,aAAa,UAAU;AACvC,YAAI,IAAI,SAAS,OAAQ;AAEzB,cAAM,OAAO,OAAO,IAAI,YAAY,WAAW,IAAI,UAAU;AAC7D,YAAI,CAAC,KAAM;AAEX,cAAM;AAAA,UACJ;AAAA,UACA;AAAA,QACF;AAAA,MACF;AAAA,IACF,QAAQ;AAAA,IAER;AAAA,EACF;AACF;AAEA,gBAAgB,kBACd,OACA,UACyB;AAGzB,MAAI,CAACC,YAAW,KAAK,EAAG;AAExB,MAAI;AACJ,MAAI;AACF,UAAM,UAAU,MAAMF,SAAQ,KAAK;AACnC,cAAU,QAAQ,OAAO,CAAC,MAAM,EAAE,SAAS,KAAK,CAAC;AAAA,EACnD,QAAQ;AACN;AAAA,EACF;AAEA,MAAI,QAAQ,WAAW,EAAG;AAE1B,MAAI;AACJ,MAAI;AACF,UAAM,MAAM,MAAM,OAAO,gBAAgB;AACzC,eAAW,IAAI,WAAW;AAAA,EAC5B,QAAQ;AACN;AAAA,EACF;AAEA,aAAW,UAAU,SAAS;AAC5B,UAAM,SAASI,MAAK,OAAO,MAAM;AACjC,QAAI;AAEJ,QAAI;AACF,WAAK,IAAK;AAAA,QACR;AAAA,QACA,EAAE,UAAU,KAAK;AAAA,MACnB;AAAA,IACF,QAAQ;AACN;AAAA,IACF;AAEA,QAAI;AAEF,YAAM,SAAS,GACZ,QAAQ,mDAAmD,EAC3D,IAAI;AACP,YAAM,aAAa,OAAO,IAAI,CAAC,MAAM,EAAE,IAAI;AAG3C,YAAM,WAAW,WAAW;AAAA,QAC1B,CAAC,MAAM,MAAM,cAAc,MAAM,qBAAqB,EAAE,SAAS,SAAS;AAAA,MAC5E;AAEA,UAAI,CAAC,UAAU;AACb,WAAG,MAAM;AACT;AAAA,MACF;AAEA,YAAM,UAAU,GAAG,QAAQ,sBAAsB,QAAQ,IAAI,EAAE,IAAI;AAGnE,YAAM,WAAW,QAAQ,IAAI,CAACE,OAAMA,GAAE,IAAI;AAE1C,YAAM,UAAU,SAAS,SAAS,MAAM;AAExC,UAAI,CAAC,SAAS;AACZ,WAAG,MAAM;AACT;AAAA,MACF;AAEA,YAAM,aAAa,SAAS,SAAS,SAAS,IAC1C,YACA,SAAS,SAAS,MAAM,IACtB,SACA;AAEN,UAAI,QAAQ,WAAW,UAAU,mBAAmB,QAAQ;AAE5D,YAAM,OAAO,GAAG,QAAQ,KAAK,EAAE,IAAI;AACnC,iBAAW,OAAO,MAAM;AACtB,YAAI,CAAC,IAAI,MAAM,KAAK,EAAG;AACvB,cAAM,EAAE,MAAM,IAAI,KAAK;AAAA,MACzB;AAAA,IACF,QAAQ;AAAA,IAER,UAAE;AACA,SAAG,MAAM;AAAA,IACX;AAAA,EACF;AACF;;;AClKA,IAAM,WAA0C;AAAA,EAC9C,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,UAAU;AAAA,EACV,KAAK;AAAA,EACL,OAAO;AAAA,EACP,KAAK;AACP;AAEO,SAAS,cAAc,MAAuB;AACnD,QAAM,UAAU,SAAS,IAAI;AAC7B,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI;AAAA,MACR,oBAAoB,IAAI,gBAAgB,OAAO,KAAK,QAAQ,EAAE,KAAK,IAAI,CAAC;AAAA,IAC1E;AAAA,EACF;AACA,SAAO,QAAQ;AACjB;AAEO,SAAS,cAAyB;AACvC,SAAO,OAAO,OAAO,QAAQ,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC;AAC/C;;;ACfA,IAAM,WAAsB;AAAA;AAAA;AAAA,EAG1B,EAAE,MAAM,QAAQ,UAAU,UAAU,OAAO,OAAO;AAAA,EAClD,EAAE,MAAM,WAAW,UAAU,UAAU,OAAO,OAAO;AAAA,EACrD,EAAE,MAAM,UAAU,UAAU,UAAU,OAAO,OAAO;AAAA,EACpD,EAAE,MAAM,UAAU,UAAU,UAAU,OAAO,OAAO;AAAA,EACpD,EAAE,MAAM,UAAU,UAAU,UAAU,OAAO,OAAO;AAAA,EACpD,EAAE,MAAM,SAAS,UAAU,UAAU,OAAO,OAAO;AAAA;AAAA,EAEnD,EAAE,MAAM,gBAAgB,UAAU,UAAU,OAAO,OAAO;AAAA,EAC1D,EAAE,MAAM,iBAAiB,UAAU,UAAU,OAAO,OAAO;AAAA,EAC3D,EAAE,MAAM,cAAc,UAAU,UAAU,OAAO,OAAO;AAAA,EACxD,EAAE,MAAM,UAAU,UAAU,UAAU,OAAO,OAAO;AAAA,EACpD,EAAE,MAAM,WAAW,UAAU,UAAU,OAAO,OAAO;AAAA,EACrD,EAAE,MAAM,eAAe,UAAU,UAAU,OAAO,OAAO;AAAA,EACzD,EAAE,MAAM,WAAW,UAAU,UAAU,OAAO,OAAO;AAAA,EACrD,EAAE,MAAM,YAAY,UAAU,UAAU,OAAO,OAAO;AAAA,EACtD,EAAE,MAAM,YAAY,UAAU,UAAU,OAAO,OAAO;AAAA,EACtD,EAAE,MAAM,YAAY,UAAU,UAAU,OAAO,OAAO;AAAA;AAAA,EAEtD,EAAE,MAAM,QAAQ,UAAU,UAAU,OAAO,OAAO;AAAA,EAClD,EAAE,MAAM,WAAW,UAAU,UAAU,OAAO,OAAO;AAAA,EACrD,EAAE,MAAM,UAAU,UAAU,UAAU,OAAO,OAAO;AAAA,EACpD,EAAE,MAAM,UAAU,UAAU,UAAU,OAAO,OAAO;AAAA,EACpD,EAAE,MAAM,QAAQ,UAAU,UAAU,OAAO,OAAO;AAAA,EAClD,EAAE,MAAM,WAAW,UAAU,UAAU,OAAO,OAAO;AAAA,EACrD,EAAE,MAAM,UAAU,UAAU,UAAU,OAAO,OAAO;AAAA,EACpD,EAAE,MAAM,OAAO,UAAU,UAAU,OAAO,OAAO;AAAA,EACjD,EAAE,MAAM,UAAU,UAAU,UAAU,OAAO,OAAO;AAAA,EACpD,EAAE,MAAM,SAAS,UAAU,UAAU,OAAO,OAAO;AAAA,EACnD,EAAE,MAAM,SAAS,UAAU,UAAU,OAAO,OAAO;AAAA,EACnD,EAAE,MAAM,QAAQ,UAAU,UAAU,OAAO,OAAO;AAAA,EAClD,EAAE,MAAM,WAAW,UAAU,UAAU,OAAO,OAAO;AAAA;AAAA,EAGrD,EAAE,MAAM,QAAQ,UAAU,UAAU,OAAO,OAAO;AAAA,EAClD,EAAE,MAAM,UAAU,UAAU,UAAU,OAAO,OAAO;AAAA,EACpD,EAAE,MAAM,YAAY,UAAU,UAAU,OAAO,OAAO;AAAA,EACtD,EAAE,MAAM,SAAS,UAAU,UAAU,OAAO,OAAO;AAAA,EACnD,EAAE,MAAM,WAAW,UAAU,UAAU,OAAO,OAAO;AAAA;AAAA,EAErD,EAAE,MAAM,YAAY,UAAU,UAAU,OAAO,OAAO;AAAA,EACtD,EAAE,MAAM,aAAa,UAAU,UAAU,OAAO,OAAO;AAAA,EACvD,EAAE,MAAM,WAAW,UAAU,UAAU,OAAO,OAAO;AAAA,EACrD,EAAE,MAAM,YAAY,UAAU,UAAU,OAAO,OAAO;AAAA,EACtD,EAAE,MAAM,YAAY,UAAU,UAAU,OAAO,OAAO;AAAA,EACtD,EAAE,MAAM,YAAY,UAAU,UAAU,OAAO,OAAO;AAAA,EACtD,EAAE,MAAM,YAAY,UAAU,UAAU,OAAO,OAAO;AAAA,EACtD,EAAE,MAAM,aAAa,UAAU,UAAU,OAAO,OAAO;AAAA,EACvD,EAAE,MAAM,aAAa,UAAU,UAAU,OAAO,OAAO;AAAA,EACvD,EAAE,MAAM,WAAW,UAAU,UAAU,OAAO,OAAO;AAAA;AAAA,EAErD,EAAE,MAAM,QAAQ,UAAU,UAAU,OAAO,OAAO;AAAA,EAClD,EAAE,MAAM,QAAQ,UAAU,UAAU,OAAO,OAAO;AAAA,EAClD,EAAE,MAAM,QAAQ,UAAU,UAAU,OAAO,OAAO;AAAA,EAClD,EAAE,MAAM,QAAQ,UAAU,UAAU,OAAO,OAAO;AAAA,EAClD,EAAE,MAAM,QAAQ,UAAU,UAAU,OAAO,OAAO;AAAA,EAClD,EAAE,MAAM,WAAW,UAAU,UAAU,OAAO,OAAO;AAAA,EACrD,EAAE,MAAM,WAAW,UAAU,UAAU,OAAO,OAAO;AAAA;AAAA,EAGrD,EAAE,MAAM,OAAO,UAAU,YAAY,OAAO,MAAM;AAAA,EAClD,EAAE,MAAM,SAAS,UAAU,YAAY,OAAO,MAAM;AAAA;AAAA,EAEpD,EAAE,MAAM,WAAW,UAAU,UAAU,OAAO,MAAM;AAAA,EACpD,EAAE,MAAM,YAAY,UAAU,UAAU,OAAO,MAAM;AAAA,EACrD,EAAE,MAAM,WAAW,UAAU,UAAU,OAAO,MAAM;AAAA,EACpD,EAAE,MAAM,WAAW,UAAU,UAAU,OAAO,MAAM;AAAA,EACpD,EAAE,MAAM,UAAU,UAAU,YAAY,OAAO,MAAM;AAAA,EACrD,EAAE,MAAM,UAAU,UAAU,UAAU,OAAO,MAAM;AAAA,EACnD,EAAE,MAAM,WAAW,UAAU,UAAU,OAAO,MAAM;AAAA,EACpD,EAAE,MAAM,UAAU,UAAU,QAAQ,OAAO,MAAM;AAAA;AAAA,EAGjD,EAAE,MAAM,QAAQ,UAAU,YAAY,OAAO,OAAO;AAAA,EACpD,EAAE,MAAM,UAAU,UAAU,YAAY,OAAO,OAAO;AAAA,EACtD,EAAE,MAAM,UAAU,UAAU,YAAY,OAAO,OAAO;AAAA,EACtD,EAAE,MAAM,UAAU,UAAU,YAAY,OAAO,OAAO;AAAA,EACtD,EAAE,MAAM,WAAW,UAAU,YAAY,OAAO,OAAO;AAAA,EACvD,EAAE,MAAM,aAAa,UAAU,YAAY,OAAO,OAAO;AAAA,EACzD,EAAE,MAAM,aAAa,UAAU,YAAY,OAAO,OAAO;AAAA;AAAA,EAGzD,EAAE,MAAM,SAAS,UAAU,UAAU,OAAO,QAAQ;AAAA,EACpD,EAAE,MAAM,WAAW,UAAU,UAAU,OAAO,QAAQ;AAAA,EACtD,EAAE,MAAM,YAAY,UAAU,UAAU,OAAO,QAAQ;AAAA,EACvD,EAAE,MAAM,UAAU,UAAU,UAAU,OAAO,QAAQ;AAAA,EACrD,EAAE,MAAM,YAAY,UAAU,UAAU,OAAO,QAAQ;AAAA;AAAA,EAGvD,EAAE,MAAM,WAAW,UAAU,UAAU,OAAO,UAAU;AAAA,EACxD,EAAE,MAAM,YAAY,UAAU,UAAU,OAAO,UAAU;AAAA;AAAA,EAGzD,EAAE,MAAM,QAAQ,UAAU,YAAY,OAAO,OAAO;AAAA,EACpD,EAAE,MAAM,UAAU,UAAU,YAAY,OAAO,OAAO;AAAA,EACtD,EAAE,MAAM,WAAW,UAAU,YAAY,OAAO,OAAO;AAAA,EACvD,EAAE,MAAM,WAAW,UAAU,YAAY,OAAO,OAAO;AAAA;AAAA,EAGvD,EAAE,MAAM,QAAQ,UAAU,YAAY,OAAO,OAAO;AAAA,EACpD,EAAE,MAAM,YAAY,UAAU,UAAU,OAAO,OAAO;AAAA;AAAA,EAGtD,EAAE,MAAM,QAAQ,UAAU,YAAY,OAAO,OAAO;AAAA,EACpD,EAAE,MAAM,UAAU,UAAU,YAAY,OAAO,OAAO;AAAA,EACtD,EAAE,MAAM,YAAY,UAAU,YAAY,OAAO,OAAO;AAAA;AAAA,EAGxD,EAAE,MAAM,QAAQ,UAAU,QAAQ,OAAO,OAAO;AAAA;AAAA,EAGhD,EAAE,MAAM,OAAO,UAAU,QAAQ,OAAO,MAAM;AAAA,EAC9C,EAAE,MAAM,QAAQ,UAAU,QAAQ,OAAO,OAAO;AAAA,EAChD,EAAE,MAAM,SAAS,UAAU,QAAQ,OAAO,QAAQ;AAAA,EAClD,EAAE,MAAM,QAAQ,UAAU,QAAQ,OAAO,OAAO;AAAA;AAAA,EAGhD,EAAE,MAAM,QAAQ,UAAU,UAAU,OAAO,OAAO;AAAA,EAClD,EAAE,MAAM,SAAS,UAAU,UAAU,OAAO,OAAO;AACrD;AAcA,SAAS,gBAAgB,MAAsB;AAC7C,SAAO,KAAK,QAAQ,WAAW,IAAI;AACrC;AAMA,SAAS,aAAa,OAA0B;AAC9C,QAAM,SAAS,CAAC,GAAG,KAAK,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,KAAK,SAAS,EAAE,KAAK,MAAM;AACtE,QAAM,UAAU,OAAO,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,KAAK,GAAG;AAClD,SAAO,IAAI,OAAO,OAAO,OAAO,QAAQ,IAAI;AAC9C;AAEA,IAAM,kBAAkB,aAAa,QAAQ;AAC7C,IAAM,WAAW,IAAI,IAAI,SAAS,IAAI,CAAC,MAAM,CAAC,EAAE,KAAK,YAAY,GAAG,CAAC,CAAC,CAAC;AAShE,SAAS,OAAO,MAA+B;AACpD,QAAM,UAAmB,CAAC;AAC1B,QAAM,OAAO,oBAAI,IAAY;AAG7B,aAAW,MAAM,KAAK,YAAY,GAAG,SAAS,IAAI;AAGlD,QAAM,YAAY,gBAAgB,KAAK,YAAY,CAAC;AACpD,MAAI,cAAc,KAAK,YAAY,GAAG;AACpC,eAAW,MAAM,WAAW,SAAS,IAAI;AAAA,EAC3C;AAEA,SAAO,EAAE,OAAO,QAAQ,QAAQ,QAAQ;AAC1C;AAEA,SAAS,WACP,eACA,YACA,SACA,MACM;AACN,kBAAgB,YAAY;AAE5B,MAAI;AACJ,UAAQ,QAAQ,gBAAgB,KAAK,UAAU,OAAO,MAAM;AAC1D,QAAI,KAAK,IAAI,MAAM,KAAK,EAAG;AAE3B,UAAM,OAAO,MAAM,CAAC,EAAE,YAAY;AAClC,UAAM,QAAQ,SAAS,IAAI,IAAI;AAC/B,QAAI,CAAC,MAAO;AAEZ,SAAK,IAAI,MAAM,KAAK;AACpB,YAAQ,KAAK;AAAA,MACX;AAAA,MACA,OAAO,MAAM;AAAA,MACb,UAAU,MAAM;AAAA,MAChB,OAAO,MAAM;AAAA,IACf,CAAC;AAAA,EACH;AACF;;;ACjOA,IAAM,IAAI;AAAA,EACR,OAAO;AAAA,EACP,MAAM;AAAA,EACN,KAAK;AAAA,EACL,KAAK;AAAA,EACL,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,MAAM;AAAA,EACN,SAAS;AAAA,EACT,MAAM;AAAA,EACN,OAAO;AAAA,EACP,MAAM;AACR;AAEA,IAAM,mBAAmB;AAAA,EACvB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEA,SAAS,gBAAgB;AACvB,MAAI,aAAa;AACjB,MAAI,WAAW;AACf,MAAI,QAA+C;AAEnD,SAAO;AAAA,IACL,QAAQ;AACN,mBAAa,KAAK,MAAM,KAAK,OAAO,IAAI,iBAAiB,MAAM;AAC/D,cAAQ,YAAY,MAAM;AACxB,oBAAY,WAAW,KAAK;AAC5B,cAAM,MAAM,iBAAiB,aAAa,iBAAiB,MAAM;AACjE,cAAM,OAAO,IAAI,OAAO,YAAY,CAAC;AACrC,gBAAQ,OAAO;AAAA,UACb,OAAO,EAAE,GAAG,GAAG,GAAG,GAAG,IAAI,GAAG,EAAE,KAAK;AAAA,QACrC;AAAA,MACF,GAAG,GAAG;AAAA,IACR;AAAA,IACA,SAAS;AACP;AAAA,IACF;AAAA,IACA,OAAO;AACL,UAAI,OAAO;AACT,sBAAc,KAAK;AACnB,gBAAQ;AAAA,MACV;AACA,cAAQ,OAAO,MAAM,OAAO,IAAI,OAAO,EAAE,IAAI,IAAI;AAAA,IACnD;AAAA,EACF;AACF;AAOA,SAAS,UAAU,MAA6B;AAC9C,QAAM,UAAuB,CAAC;AAE9B,WAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,UAAM,MAAM,KAAK,CAAC;AAClB,QAAI,QAAQ,aAAa,QAAQ,MAAM;AACrC,cAAQ,QAAQ,KAAK,EAAE,CAAC;AAAA,IAC1B,WAAW,QAAQ,aAAa,QAAQ,MAAM;AAC5C,YAAM,MAAM,KAAK,EAAE,CAAC;AACpB,UAAI,KAAK;AACP,gBAAQ,QAAQ,IAAI,KAAK,GAAG;AAC5B,YAAI,MAAM,QAAQ,MAAM,QAAQ,CAAC,GAAG;AAClC,kBAAQ,MAAM,iBAAiB,GAAG,EAAE;AACpC,kBAAQ,KAAK,CAAC;AAAA,QAChB;AAAA,MACF;AAAA,IACF,WAAW,QAAQ,YAAY,QAAQ,MAAM;AAC3C,cAAQ,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA,sCAKoB;AAChC,cAAQ,KAAK,CAAC;AAAA,IAChB;AAAA,EACF;AAEA,SAAO;AACT;AAEA,eAAsB,KAAK,MAA+B;AACxD,QAAM,UAAU,UAAU,IAAI;AAE9B,QAAM,WAAW,QAAQ,QACrB,CAAC,cAAc,QAAQ,KAAK,CAAC,IAC7B,YAAY;AAEhB,QAAM,UAAU,cAAc;AAC9B,UAAQ,MAAM;AAEd,QAAM,aAAqC,CAAC;AAC5C,QAAM,eAAuD,CAAC;AAE9D,MAAI,gBAAgB;AACpB,MAAI,cAAc;AAClB,QAAM,WAAiE,CAAC;AAExE,aAAW,WAAW,UAAU;AAC9B,QAAI,gBAAgB;AACpB,QAAI,cAAc;AAClB,YAAQ,OAAO;AAEf,qBAAiB,WAAW,QAAQ,SAAS,EAAE,OAAO,QAAQ,MAAM,CAAC,GAAG;AACtE;AACA;AAEA,YAAM,SAAS,OAAO,QAAQ,IAAI;AAClC,UAAI,OAAO,QAAQ,GAAG;AACpB,uBAAe,OAAO;AACtB,uBAAe,OAAO;AAEtB,mBAAW,SAAS,OAAO,SAAS;AAClC,qBAAW,MAAM,KAAK,KAAK,WAAW,MAAM,KAAK,KAAK,KAAK;AAE3D,gBAAM,WAAY,aAAa,MAAM,KAAK,MAAM,CAAC;AACjD,mBAAS,MAAM,IAAI,KAAK,SAAS,MAAM,IAAI,KAAK,KAAK;AAAA,QACvD;AAAA,MACF;AAAA,IACF;AAEA,QAAI,gBAAgB,GAAG;AACrB,eAAS,QAAQ,IAAI,IAAI,EAAE,UAAU,eAAe,QAAQ,YAAY;AAAA,IAC1E;AAAA,EACF;AAEA,UAAQ,KAAK;AAGb,UAAQ,IAAI,EAAE;AACd,UAAQ,IAAI,KAAK,EAAE,IAAI,GAAG,EAAE,GAAG,UAAU,EAAE,KAAK,IAAI,EAAE,GAAG,SAAS,EAAE,KAAK,EAAE;AAC3E,UAAQ,IAAI,KAAK,EAAE,GAAG,GAAG,SAAI,OAAO,EAAE,CAAC,GAAG,EAAE,KAAK,EAAE;AACnD,UAAQ,IAAI,EAAE;AACd,UAAQ,IAAI,KAAK,EAAE,GAAG,mBAAmB,EAAE,KAAK,KAAK,EAAE,IAAI,GAAG,aAAa,GAAG,EAAE,KAAK,EAAE;AACvF,UAAQ,IAAI,KAAK,EAAE,GAAG,eAAe,EAAE,KAAK,SAAS,EAAE,IAAI,GAAG,EAAE,GAAG,GAAG,WAAW,GAAG,EAAE,KAAK,EAAE;AAE7F,QAAM,eAAe,OAAO,QAAQ,QAAQ;AAC5C,MAAI,aAAa,SAAS,GAAG;AAC3B,YAAQ,IAAI,EAAE;AACd,YAAQ,IAAI,KAAK,EAAE,IAAI,WAAW,EAAE,KAAK,EAAE;AAC3C,eAAW,CAAC,MAAM,KAAK,KAAK,cAAc;AACxC,YAAM,QAAS,MAAM,SAAS,MAAM,WAAY,KAAK,QAAQ,CAAC;AAC9D,cAAQ;AAAA,QACN,OAAO,EAAE,IAAI,GAAG,KAAK,OAAO,EAAE,CAAC,GAAG,EAAE,KAAK,IAAI,EAAE,IAAI,GAAG,OAAO,MAAM,MAAM,EAAE,SAAS,CAAC,CAAC,GAAG,EAAE,KAAK,IAAI,EAAE,GAAG,MAAM,MAAM,QAAQ,cAAc,IAAI,KAAK,EAAE,KAAK;AAAA,MAC7J;AAAA,IACF;AAAA,EACF;AAEA,MAAI,cAAc,GAAG;AACnB,UAAM,SAAS,OAAO,QAAQ,UAAU,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,IAAI,CAAC;AACtE,YAAQ,IAAI,EAAE;AACd,YAAQ,IAAI,KAAK,EAAE,IAAI,YAAY,EAAE,KAAK,EAAE;AAC5C,eAAW,CAAC,OAAO,KAAK,KAAK,OAAO,MAAM,GAAG,EAAE,GAAG;AAChD,YAAM,WAAW,aAAa,KAAK,KAAK,CAAC;AACzC,YAAM,cAAc,OAAO,QAAQ,QAAQ,EACxC,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,IAAI,CAAC,EAC5B,OAAO,CAAC,CAAC,CAAC,MAAM,MAAM,KAAK,EAC3B,MAAM,GAAG,EAAE,EACX,IAAI,CAAC,CAAC,GAAG,GAAG,MAAM,GAAG,EAAE,GAAG,GAAG,CAAC,GAAG,EAAE,KAAK,IAAI,GAAG,EAAE,EACjD,KAAK,GAAG,EAAE,GAAG,IAAI,EAAE,KAAK,GAAG;AAC9B,YAAM,SAAS,cAAc,IAAI,EAAE,GAAG,IAAI,EAAE,KAAK,GAAG,WAAW,GAAG,EAAE,GAAG,IAAI,EAAE,KAAK,KAAK;AACvF,cAAQ;AAAA,QACN,OAAO,EAAE,MAAM,GAAG,MAAM,OAAO,EAAE,CAAC,GAAG,EAAE,KAAK,IAAI,EAAE,IAAI,GAAG,OAAO,KAAK,EAAE,SAAS,CAAC,CAAC,GAAG,EAAE,KAAK,GAAG,MAAM;AAAA,MACvG;AAAA,IACF;AAAA,EACF;AAEA,UAAQ,IAAI,EAAE;AACd,MAAI,gBAAgB,GAAG;AACrB,YAAQ,IAAI,KAAK,EAAE,KAAK,2CAA2C,EAAE,KAAK,EAAE;AAC5E,YAAQ,IAAI,EAAE;AAAA,EAChB;AACF;;;ACzLA,IAAM,WAA8D;AAAA,EAClE;AACF;AAEA,SAAS,QAAc;AACrB,UAAQ,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,kCAeoB;AAClC;AAEA,eAAe,OAAsB;AACnC,QAAM,OAAO,QAAQ,KAAK,MAAM,CAAC;AACjC,QAAM,UAAU,KAAK,CAAC;AAEtB,MAAI,YAAY,YAAY,YAAY,MAAM;AAC5C,UAAM;AACN,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,MAAI,YAAY,aAAa;AAC3B,YAAQ,IAAI,OAAO;AACnB,YAAQ,KAAK,CAAC;AAAA,EAChB;AAGA,QAAM,UAAU,UAAU,SAAS,OAAO,IAAI;AAC9C,MAAI,SAAS;AACX,UAAM,QAAQ,KAAK,MAAM,CAAC,CAAC;AAAA,EAC7B,OAAO;AAEL,UAAM,KAAK,IAAI;AAAA,EACjB;AACF;AAEA,KAAK,EAAE,MAAM,CAAC,QAAiB;AAC7B,UAAQ,MAAM,GAAG;AACjB,UAAQ,KAAK,CAAC;AAChB,CAAC;",
|
|
6
|
+
"names": ["readdir", "homedir", "join", "readdir", "readFile", "stat", "homedir", "join", "extractText", "createReadStream", "readdir", "stat", "createInterface", "homedir", "join", "extractText", "existsSync", "homedir", "join", "readdir", "readFile", "existsSync", "homedir", "join", "base", "c"]
|
|
7
7
|
}
|