devrager 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/dist/cli.js +988 -0
  2. package/dist/cli.js.map +7 -0
  3. package/dist/lib/adapters/amp.d.ts +3 -0
  4. package/dist/lib/adapters/amp.d.ts.map +1 -0
  5. package/dist/lib/adapters/amp.js +74 -0
  6. package/dist/lib/adapters/amp.js.map +1 -0
  7. package/dist/lib/adapters/claude.d.ts +3 -0
  8. package/dist/lib/adapters/claude.d.ts.map +1 -0
  9. package/dist/lib/adapters/claude.js +137 -0
  10. package/dist/lib/adapters/claude.js.map +1 -0
  11. package/dist/lib/adapters/cline.d.ts +3 -0
  12. package/dist/lib/adapters/cline.d.ts.map +1 -0
  13. package/dist/lib/adapters/cline.js +122 -0
  14. package/dist/lib/adapters/cline.js.map +1 -0
  15. package/dist/lib/adapters/codex.d.ts +3 -0
  16. package/dist/lib/adapters/codex.d.ts.map +1 -0
  17. package/dist/lib/adapters/codex.js +99 -0
  18. package/dist/lib/adapters/codex.js.map +1 -0
  19. package/dist/lib/adapters/index.d.ts +17 -0
  20. package/dist/lib/adapters/index.d.ts.map +1 -0
  21. package/dist/lib/adapters/index.js +27 -0
  22. package/dist/lib/adapters/index.js.map +1 -0
  23. package/dist/lib/adapters/opencode.d.ts +3 -0
  24. package/dist/lib/adapters/opencode.d.ts.map +1 -0
  25. package/dist/lib/adapters/opencode.js +86 -0
  26. package/dist/lib/adapters/opencode.js.map +1 -0
  27. package/dist/lib/adapters/pi.d.ts +3 -0
  28. package/dist/lib/adapters/pi.d.ts.map +1 -0
  29. package/dist/lib/adapters/pi.js +112 -0
  30. package/dist/lib/adapters/pi.js.map +1 -0
  31. package/dist/lib/adapters/zed.d.ts +3 -0
  32. package/dist/lib/adapters/zed.d.ts.map +1 -0
  33. package/dist/lib/adapters/zed.js +156 -0
  34. package/dist/lib/adapters/zed.js.map +1 -0
  35. package/dist/lib/detector/index.d.ts +32 -0
  36. package/dist/lib/detector/index.d.ts.map +1 -0
  37. package/dist/lib/detector/index.js +224 -0
  38. package/dist/lib/detector/index.js.map +1 -0
  39. package/dist/lib/index.d.ts +3 -0
  40. package/dist/lib/index.d.ts.map +1 -0
  41. package/dist/lib/index.js +3 -0
  42. package/dist/lib/index.js.map +1 -0
  43. package/package.json +40 -0
@@ -0,0 +1,99 @@
1
+ import { createReadStream } from "node:fs";
2
+ import { readdir, stat } from "node:fs/promises";
3
+ import { createInterface } from "node:readline";
4
+ import { homedir } from "node:os";
5
+ import { join } from "node:path";
6
+ /**
7
+ * Codex stores sessions as JSONL files at:
8
+ * ~/.codex/sessions/YYYY/MM/DD/rollout-*.jsonl
9
+ *
10
+ * Each line is JSON with structure:
11
+ * { "timestamp": "...", "type": "response_item", "payload": { "type": "message", "role": "user", "content": [...] } }
12
+ *
13
+ * User messages have payload.role === "user" and content is an array of
14
+ * { "type": "input_text", "text": "..." }
15
+ *
16
+ * We skip messages that are just environment context injections.
17
+ */
18
+ const CODEX_SESSIONS_DIR = join(homedir(), ".codex", "sessions");
19
+ export function codexAdapter() {
20
+ return {
21
+ name: "codex",
22
+ async *messages(options) {
23
+ yield* walkCodexSessions(CODEX_SESSIONS_DIR, options);
24
+ },
25
+ };
26
+ }
27
+ async function* walkCodexSessions(dir, options) {
28
+ let entries;
29
+ try {
30
+ entries = await readdir(dir);
31
+ }
32
+ catch {
33
+ return; // Codex not installed or no sessions
34
+ }
35
+ for (const entry of entries) {
36
+ const fullPath = join(dir, entry);
37
+ const entryStat = await stat(fullPath);
38
+ if (entryStat.isDirectory()) {
39
+ yield* walkCodexSessions(fullPath, options);
40
+ }
41
+ else if (entry.endsWith(".jsonl")) {
42
+ const session = entry.replace(".jsonl", "");
43
+ yield* parseCodexJsonl(fullPath, { session, since: options?.since });
44
+ }
45
+ }
46
+ }
47
+ async function* parseCodexJsonl(filePath, context) {
48
+ const rl = createInterface({
49
+ input: createReadStream(filePath, { encoding: "utf-8" }),
50
+ crlfDelay: Infinity,
51
+ });
52
+ for await (const line of rl) {
53
+ if (!line.trim())
54
+ continue;
55
+ try {
56
+ const entry = JSON.parse(line);
57
+ // Only care about response_item entries with user messages
58
+ if (entry.type !== "response_item")
59
+ continue;
60
+ const payload = entry.payload;
61
+ if (!payload || payload.role !== "user")
62
+ continue;
63
+ const text = extractText(payload.content);
64
+ if (!text)
65
+ continue;
66
+ // Skip environment context injections (they start with <environment_context>)
67
+ if (text.startsWith("<environment_context>"))
68
+ continue;
69
+ // Skip permission/sandbox instructions
70
+ if (text.startsWith("<permissions instructions>"))
71
+ continue;
72
+ if (context.since && entry.timestamp) {
73
+ const ts = new Date(entry.timestamp);
74
+ if (ts < context.since)
75
+ continue;
76
+ }
77
+ yield {
78
+ text,
79
+ timestamp: entry.timestamp,
80
+ session: context.session,
81
+ };
82
+ }
83
+ catch {
84
+ // Skip malformed lines
85
+ }
86
+ }
87
+ }
88
+ function extractText(content) {
89
+ if (!Array.isArray(content))
90
+ return null;
91
+ const parts = content
92
+ .filter((p) => typeof p === "object" &&
93
+ p !== null &&
94
+ p.type === "input_text" &&
95
+ typeof p.text === "string")
96
+ .map((p) => p.text);
97
+ return parts.length > 0 ? parts.join(" ") : null;
98
+ }
99
+ //# sourceMappingURL=codex.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codex.js","sourceRoot":"","sources":["../../../src/adapters/codex.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ export interface Message {
2
+ text: string;
3
+ timestamp?: string;
4
+ session?: string;
5
+ project?: string;
6
+ }
7
+ export interface Adapter {
8
+ name: string;
9
+ /** Discover and yield all user messages from local session storage */
10
+ messages(options?: AdapterOptions): AsyncGenerator<Message>;
11
+ }
12
+ export interface AdapterOptions {
13
+ since?: Date;
14
+ }
15
+ export declare function createAdapter(name: string): Adapter;
16
+ export declare function allAdapters(): Adapter[];
17
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/adapters/index.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,sEAAsE;IACtE,QAAQ,CAAC,OAAO,CAAC,EAAE,cAAc,GAAG,cAAc,CAAC,OAAO,CAAC,CAAC;CAC7D;AAED,MAAM,WAAW,cAAc;IAC7B,KAAK,CAAC,EAAE,IAAI,CAAC;CACd;AAYD,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAQnD;AAED,wBAAgB,WAAW,IAAI,OAAO,EAAE,CAEvC"}
@@ -0,0 +1,27 @@
1
+ import { ampAdapter } from "./amp";
2
+ import { claudeAdapter } from "./claude";
3
+ import { clineAdapter } from "./cline";
4
+ import { codexAdapter } from "./codex";
5
+ import { opencodeAdapter } from "./opencode";
6
+ import { piAdapter } from "./pi";
7
+ import { zedAdapter } from "./zed";
8
+ const ADAPTERS = {
9
+ claude: claudeAdapter,
10
+ codex: codexAdapter,
11
+ opencode: opencodeAdapter,
12
+ amp: ampAdapter,
13
+ cline: clineAdapter,
14
+ pi: piAdapter,
15
+ zed: zedAdapter,
16
+ };
17
+ export function createAdapter(name) {
18
+ const factory = ADAPTERS[name];
19
+ if (!factory) {
20
+ throw new Error(`unknown adapter: ${name} (available: ${Object.keys(ADAPTERS).join(", ")})`);
21
+ }
22
+ return factory();
23
+ }
24
+ export function allAdapters() {
25
+ return Object.values(ADAPTERS).map((f) => f());
26
+ }
27
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/adapters/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AACnC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,EAAE,SAAS,EAAE,MAAM,MAAM,CAAC;AACjC,OAAO,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AAmBnC,MAAM,QAAQ,GAAkC;IAC9C,MAAM,EAAE,aAAa;IACrB,KAAK,EAAE,YAAY;IACnB,QAAQ,EAAE,eAAe;IACzB,GAAG,EAAE,UAAU;IACf,KAAK,EAAE,YAAY;IACnB,EAAE,EAAE,SAAS;IACb,GAAG,EAAE,UAAU;CAChB,CAAC;AAEF,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;IAC/B,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CACb,oBAAoB,IAAI,gBAAgB,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAC5E,CAAC;IACJ,CAAC;IACD,OAAO,OAAO,EAAE,CAAC;AACnB,CAAC;AAED,MAAM,UAAU,WAAW;IACzB,OAAO,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;AACjD,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { Adapter } from "./index";
2
+ export declare function opencodeAdapter(): Adapter;
3
+ //# sourceMappingURL=opencode.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"opencode.d.ts","sourceRoot":"","sources":["../../../src/adapters/opencode.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAA2B,MAAM,SAAS,CAAC;AAyChE,wBAAgB,eAAe,IAAI,OAAO,CA2BzC"}
@@ -0,0 +1,86 @@
1
+ import { existsSync } from "node:fs";
2
+ import { homedir } from "node:os";
3
+ import { join } from "node:path";
4
+ /**
5
+ * OpenCode stores sessions in a SQLite database at:
6
+ * ~/.local/share/opencode/opencode.db
7
+ *
8
+ * Schema:
9
+ * message: { id, session_id, time_created (epoch ms), time_updated, data (JSON) }
10
+ * part: { id, message_id, session_id, time_created, time_updated, data (JSON) }
11
+ *
12
+ * message.data: { "role": "user"|"assistant", "time": {...}, "agent": "...", ... }
13
+ * part.data: { "type": "text", "text": "the user's message" }
14
+ *
15
+ * User messages have role="user" in message.data. The actual text content is in
16
+ * the associated part rows where part.data.type === "text".
17
+ */
18
+ function getOpencodeDatabasePath() {
19
+ // macOS: ~/.local/share/opencode/opencode.db (despite XDG, this is where it actually lives)
20
+ const xdgPath = join(process.env["XDG_DATA_HOME"] ?? join(homedir(), ".local", "share"), "opencode", "opencode.db");
21
+ if (existsSync(xdgPath))
22
+ return xdgPath;
23
+ // macOS Application Support fallback
24
+ if (process.platform === "darwin") {
25
+ const macPath = join(homedir(), "Library", "Application Support", "opencode", "opencode.db");
26
+ if (existsSync(macPath))
27
+ return macPath;
28
+ }
29
+ return null;
30
+ }
31
+ export function opencodeAdapter() {
32
+ return {
33
+ name: "opencode",
34
+ async *messages(options) {
35
+ const dbPath = getOpencodeDatabasePath();
36
+ if (!dbPath)
37
+ return;
38
+ // Dynamic import so the CLI doesn't crash if better-sqlite3 isn't available
39
+ let db;
40
+ try {
41
+ const BetterSqlite3 = await import("better-sqlite3");
42
+ const Ctor = BetterSqlite3.default ?? BetterSqlite3;
43
+ db = new Ctor(dbPath, { readonly: true });
44
+ }
45
+ catch {
46
+ console.warn("devrage: better-sqlite3 not available, skipping OpenCode sessions");
47
+ return;
48
+ }
49
+ try {
50
+ yield* queryUserMessages(db, options);
51
+ }
52
+ finally {
53
+ db.close();
54
+ }
55
+ },
56
+ };
57
+ }
58
+ function* queryUserMessages(db, options) {
59
+ // Query: join message + part, filter to user role and text parts
60
+ let query = `
61
+ SELECT
62
+ m.session_id,
63
+ m.time_created,
64
+ json_extract(p.data, '$.text') as text
65
+ FROM message m
66
+ JOIN part p ON p.message_id = m.id
67
+ WHERE json_extract(m.data, '$.role') = 'user'
68
+ AND json_extract(p.data, '$.type') = 'text'
69
+ `;
70
+ if (options?.since) {
71
+ const sinceMs = options.since.getTime();
72
+ query += ` AND m.time_created >= ${sinceMs}`;
73
+ }
74
+ query += ` ORDER BY m.time_created ASC`;
75
+ const rows = db.prepare(query).all();
76
+ for (const row of rows) {
77
+ if (!row.text || !row.text.trim())
78
+ continue;
79
+ yield {
80
+ text: row.text,
81
+ timestamp: new Date(row.time_created).toISOString(),
82
+ session: row.session_id,
83
+ };
84
+ }
85
+ }
86
+ //# sourceMappingURL=opencode.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"opencode.js","sourceRoot":"","sources":["../../../src/adapters/opencode.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAGjC;;;;;;;;;;;;;GAaG;AAEH,SAAS,uBAAuB;IAC9B,4FAA4F;IAC5F,MAAM,OAAO,GAAG,IAAI,CAClB,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,QAAQ,EAAE,OAAO,CAAC,EAClE,UAAU,EACV,aAAa,CACd,CAAC;IACF,IAAI,UAAU,CAAC,OAAO,CAAC;QAAE,OAAO,OAAO,CAAC;IAExC,qCAAqC;IACrC,IAAI,OAAO,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAClC,MAAM,OAAO,GAAG,IAAI,CAClB,OAAO,EAAE,EACT,SAAS,EACT,qBAAqB,EACrB,UAAU,EACV,aAAa,CACd,CAAC;QACF,IAAI,UAAU,CAAC,OAAO,CAAC;YAAE,OAAO,OAAO,CAAC;IAC1C,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,UAAU,eAAe;IAC7B,OAAO;QACL,IAAI,EAAE,UAAU;QAChB,KAAK,CAAC,CAAC,QAAQ,CAAC,OAAwB;YACtC,MAAM,MAAM,GAAG,uBAAuB,EAAE,CAAC;YACzC,IAAI,CAAC,MAAM;gBAAE,OAAO;YAEpB,4EAA4E;YAC5E,IAAI,EAAqC,CAAC;YAC1C,IAAI,CAAC;gBACH,MAAM,aAAa,GAAG,MAAM,MAAM,CAAC,gBAAgB,CAAC,CAAC;gBACrD,MAAM,IAAI,GAAG,aAAa,CAAC,OAAO,IAAI,aAAa,CAAC;gBACpD,EAAE,GAAG,IAAK,IAAiF,CAAC,MAAM,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;YAC1H,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,CAAC,IAAI,CACV,mEAAmE,CACpE,CAAC;gBACF,OAAO;YACT,CAAC;YAED,IAAI,CAAC;gBACH,KAAK,CAAC,CAAC,iBAAiB,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;YACxC,CAAC;oBAAS,CAAC;gBACT,EAAE,CAAC,KAAK,EAAE,CAAC;YACb,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC;AAED,QAAQ,CAAC,CAAC,iBAAiB,CACzB,EAAqC,EACrC,OAAwB;IAExB,iEAAiE;IACjE,IAAI,KAAK,GAAG;;;;;;;;;GASX,CAAC;IAEF,IAAI,OAAO,EAAE,KAAK,EAAE,CAAC;QACnB,MAAM,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC;QACxC,KAAK,IAAI,0BAA0B,OAAO,EAAE,CAAC;IAC/C,CAAC;IAED,KAAK,IAAI,8BAA8B,CAAC;IAExC,MAAM,IAAI,GAAG,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,GAAG,EAI/B,CAAC;IAEJ,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,IAAI,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE;YAAE,SAAS;QAE5C,MAAM;YACJ,IAAI,EAAE,GAAG,CAAC,IAAI;YACd,SAAS,EAAE,IAAI,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,WAAW,EAAE;YACnD,OAAO,EAAE,GAAG,CAAC,UAAU;SACxB,CAAC;IACJ,CAAC;AACH,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { Adapter } from "./index";
2
+ export declare function piAdapter(): Adapter;
3
+ //# sourceMappingURL=pi.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pi.d.ts","sourceRoot":"","sources":["../../../src/adapters/pi.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,OAAO,EAA2B,MAAM,SAAS,CAAC;AAkBhE,wBAAgB,SAAS,IAAI,OAAO,CAyCnC"}
@@ -0,0 +1,112 @@
1
+ import { createReadStream } from "node:fs";
2
+ import { readdir, stat } from "node:fs/promises";
3
+ import { createInterface } from "node:readline";
4
+ import { homedir } from "node:os";
5
+ import { join } from "node:path";
6
+ /**
7
+ * pi stores sessions as JSONL files at:
8
+ * ~/.pi/agent/sessions/<project-dir>/<timestamp>_<uuid>.jsonl
9
+ *
10
+ * Project directories are path-encoded (e.g. --Users-justin-twiddle--
11
+ * for /Users/justin/twiddle).
12
+ *
13
+ * Each line is JSON. User messages have:
14
+ * { "type": "message", "timestamp": "...", "message": { "role": "user", "content": [{"type": "text", "text": "..."}] } }
15
+ *
16
+ * The session-starter line has `type: "session"` with `cwd` — we use that
17
+ * as the project name.
18
+ */
19
+ const PI_SESSIONS_DIR = join(homedir(), ".pi", "agent", "sessions");
20
+ export function piAdapter() {
21
+ return {
22
+ name: "pi",
23
+ async *messages(options) {
24
+ let projectDirs;
25
+ try {
26
+ projectDirs = await readdir(PI_SESSIONS_DIR);
27
+ }
28
+ catch {
29
+ return; // pi not installed or no sessions
30
+ }
31
+ for (const dirName of projectDirs) {
32
+ const projectDirPath = join(PI_SESSIONS_DIR, dirName);
33
+ const dirStat = await stat(projectDirPath).catch(() => null);
34
+ if (!dirStat?.isDirectory())
35
+ continue;
36
+ // Skip subagent-artifacts directories
37
+ if (dirName === "subagent-artifacts")
38
+ continue;
39
+ let sessionFiles;
40
+ try {
41
+ sessionFiles = await readdir(projectDirPath);
42
+ }
43
+ catch {
44
+ continue;
45
+ }
46
+ const jsonlFiles = sessionFiles.filter((f) => f.endsWith(".jsonl"));
47
+ for (const file of jsonlFiles) {
48
+ const filePath = join(projectDirPath, file);
49
+ const sessionId = file.replace(".jsonl", "");
50
+ yield* parsePiJsonl(filePath, {
51
+ session: sessionId,
52
+ project: dirName,
53
+ since: options?.since,
54
+ });
55
+ }
56
+ }
57
+ },
58
+ };
59
+ }
60
+ async function* parsePiJsonl(filePath, context) {
61
+ const rl = createInterface({
62
+ input: createReadStream(filePath, { encoding: "utf-8" }),
63
+ crlfDelay: Infinity,
64
+ });
65
+ for await (const line of rl) {
66
+ if (!line.trim())
67
+ continue;
68
+ try {
69
+ const entry = JSON.parse(line);
70
+ // Only process user messages
71
+ if (entry.type !== "message")
72
+ continue;
73
+ const msg = entry.message;
74
+ if (!msg || msg.role !== "user")
75
+ continue;
76
+ const text = extractText(msg.content);
77
+ if (!text)
78
+ continue;
79
+ const timestamp = entry.timestamp
80
+ ?? (msg.timestamp != null ? new Date(msg.timestamp).toISOString() : undefined);
81
+ if (context.since && timestamp) {
82
+ const ts = new Date(timestamp);
83
+ if (ts < context.since)
84
+ continue;
85
+ }
86
+ yield {
87
+ text,
88
+ timestamp,
89
+ session: context.session,
90
+ project: context.project,
91
+ };
92
+ }
93
+ catch {
94
+ // Skip malformed lines
95
+ }
96
+ }
97
+ }
98
+ function extractText(content) {
99
+ if (typeof content === "string")
100
+ return content;
101
+ if (Array.isArray(content)) {
102
+ const parts = content
103
+ .filter((p) => typeof p === "object" &&
104
+ p !== null &&
105
+ p.type === "text" &&
106
+ typeof p.text === "string")
107
+ .map((p) => p.text);
108
+ return parts.length > 0 ? parts.join(" ") : null;
109
+ }
110
+ return null;
111
+ }
112
+ //# sourceMappingURL=pi.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pi.js","sourceRoot":"","sources":["../../../src/adapters/pi.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { Adapter } from "./index";
2
+ export declare function zedAdapter(): Adapter;
3
+ //# sourceMappingURL=zed.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"zed.d.ts","sourceRoot":"","sources":["../../../src/adapters/zed.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,OAAO,EAA2B,MAAM,SAAS,CAAC;AAsChE,wBAAgB,UAAU,IAAI,OAAO,CAapC"}
@@ -0,0 +1,156 @@
1
+ import { readdir, readFile } from "node:fs/promises";
2
+ import { existsSync } from "node:fs";
3
+ import { homedir } from "node:os";
4
+ import { join } from "node:path";
5
+ /**
6
+ * Zed stores AI conversations in two places:
7
+ *
8
+ * 1. Text threads (older assistant panel):
9
+ * ~/.local/share/zed/conversations/*.json (Linux)
10
+ * ~/Library/Application Support/Zed/conversations/*.json (macOS)
11
+ * These are markdown-like JSON with messages.
12
+ *
13
+ * 2. Agent threads (newer):
14
+ * Stored in SQLite at ~/.local/share/zed/db (Linux)
15
+ * or ~/Library/Application Support/Zed/db (macOS)
16
+ * We'd need to query this, but the schema isn't well documented.
17
+ *
18
+ * We support the text thread JSON files for now, and the SQLite agent
19
+ * threads when better-sqlite3 is available.
20
+ */
21
+ function getZedPaths() {
22
+ if (process.platform === "darwin") {
23
+ const base = join(homedir(), "Library", "Application Support", "Zed");
24
+ return {
25
+ conversations: join(base, "conversations"),
26
+ db: join(base, "db"),
27
+ };
28
+ }
29
+ // Linux / others
30
+ const base = join(process.env["XDG_DATA_HOME"] ?? join(homedir(), ".local", "share"), "zed");
31
+ return {
32
+ conversations: join(base, "conversations"),
33
+ db: join(base, "db"),
34
+ };
35
+ }
36
+ export function zedAdapter() {
37
+ return {
38
+ name: "zed",
39
+ async *messages(options) {
40
+ const paths = getZedPaths();
41
+ // 1. Parse text thread JSON conversations
42
+ yield* parseTextThreads(paths.conversations, options);
43
+ // 2. Try SQLite agent threads
44
+ yield* parseAgentThreads(paths.db, options);
45
+ },
46
+ };
47
+ }
48
+ async function* parseTextThreads(dir, _options) {
49
+ if (!existsSync(dir))
50
+ return;
51
+ let files;
52
+ try {
53
+ files = await readdir(dir);
54
+ }
55
+ catch {
56
+ return;
57
+ }
58
+ const jsonFiles = files.filter((f) => f.endsWith(".json"));
59
+ for (const file of jsonFiles) {
60
+ const filePath = join(dir, file);
61
+ const session = file.replace(".json", "");
62
+ try {
63
+ const raw = await readFile(filePath, "utf-8");
64
+ const conversation = JSON.parse(raw);
65
+ if (!conversation.messages || !Array.isArray(conversation.messages))
66
+ continue;
67
+ for (const msg of conversation.messages) {
68
+ if (msg.role !== "user")
69
+ continue;
70
+ const text = typeof msg.content === "string" ? msg.content : null;
71
+ if (!text)
72
+ continue;
73
+ yield {
74
+ text,
75
+ session,
76
+ };
77
+ }
78
+ }
79
+ catch {
80
+ // Skip malformed files
81
+ }
82
+ }
83
+ }
84
+ async function* parseAgentThreads(dbDir, _options) {
85
+ // Zed uses a directory of SQLite databases. The main one is typically
86
+ // a file like 0-dev.db or similar inside the db/ directory.
87
+ if (!existsSync(dbDir))
88
+ return;
89
+ let dbFiles;
90
+ try {
91
+ const entries = await readdir(dbDir);
92
+ dbFiles = entries.filter((f) => f.endsWith(".db"));
93
+ }
94
+ catch {
95
+ return;
96
+ }
97
+ if (dbFiles.length === 0)
98
+ return;
99
+ let Database;
100
+ try {
101
+ const mod = await import("better-sqlite3");
102
+ Database = mod.default ?? mod;
103
+ }
104
+ catch {
105
+ return; // better-sqlite3 not available
106
+ }
107
+ for (const dbFile of dbFiles) {
108
+ const dbPath = join(dbDir, dbFile);
109
+ let db;
110
+ try {
111
+ db = new Database(dbPath, { readonly: true });
112
+ }
113
+ catch {
114
+ continue; // Can't open this DB
115
+ }
116
+ try {
117
+ // Check if this DB has a threads/messages table
118
+ const tables = db
119
+ .prepare("SELECT name FROM sqlite_master WHERE type='table'")
120
+ .all();
121
+ const tableNames = tables.map((t) => t.name);
122
+ // Look for message-like tables (Zed's schema may vary by version)
123
+ const msgTable = tableNames.find((t) => t === "messages" || t === "thread_messages" || t.includes("message"));
124
+ if (!msgTable) {
125
+ db.close();
126
+ continue;
127
+ }
128
+ const columns = db.prepare(`PRAGMA table_info("${msgTable}")`).all();
129
+ const colNames = columns.map((c) => c.name);
130
+ const hasRole = colNames.includes("role");
131
+ if (!hasRole) {
132
+ db.close();
133
+ continue;
134
+ }
135
+ const contentCol = colNames.includes("content")
136
+ ? "content"
137
+ : colNames.includes("body")
138
+ ? "body"
139
+ : "text";
140
+ let query = `SELECT "${contentCol}" as text FROM "${msgTable}" WHERE role = 'user'`;
141
+ const rows = db.prepare(query).all();
142
+ for (const row of rows) {
143
+ if (!row.text?.trim())
144
+ continue;
145
+ yield { text: row.text };
146
+ }
147
+ }
148
+ catch {
149
+ // Schema mismatch or other error
150
+ }
151
+ finally {
152
+ db.close();
153
+ }
154
+ }
155
+ }
156
+ //# sourceMappingURL=zed.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"zed.js","sourceRoot":"","sources":["../../../src/adapters/zed.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ export interface DetectionResult {
2
+ /** Total swear words found in the text */
3
+ count: number;
4
+ /** Individual matches */
5
+ matches: Match[];
6
+ }
7
+ export interface Match {
8
+ word: string;
9
+ index: number;
10
+ severity: Severity;
11
+ group: string;
12
+ }
13
+ export type Severity = "mild" | "moderate" | "strong";
14
+ interface WordDef {
15
+ word: string;
16
+ severity: Severity;
17
+ group: string;
18
+ }
19
+ /**
20
+ * Detect profanity in a string.
21
+ *
22
+ * Runs detection in two passes:
23
+ * 1. Direct match on original text (preserves positions)
24
+ * 2. Match on repeat-collapsed text (catches fuuuuck, shiiiiit, etc.)
25
+ */
26
+ export declare function detect(text: string): DetectionResult;
27
+ /**
28
+ * Create a custom detector with additional words.
29
+ */
30
+ export declare function createDetector(extraWords?: WordDef[]): (text: string) => DetectionResult;
31
+ export type { WordDef as WordEntry };
32
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/detector/index.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,eAAe;IAC9B,0CAA0C;IAC1C,KAAK,EAAE,MAAM,CAAC;IACd,yBAAyB;IACzB,OAAO,EAAE,KAAK,EAAE,CAAC;CAClB;AAED,MAAM,WAAW,KAAK;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,QAAQ,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG,UAAU,GAAG,QAAQ,CAAC;AAEtD,UAAU,OAAO;IACf,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,QAAQ,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;CACf;AAkKD;;;;;;GAMG;AACH,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe,CAcpD;AA4BD;;GAEG;AACH,wBAAgB,cAAc,CAC5B,UAAU,CAAC,EAAE,OAAO,EAAE,GACrB,CAAC,IAAI,EAAE,MAAM,KAAK,eAAe,CAoCnC;AAED,YAAY,EAAE,OAAO,IAAI,SAAS,EAAE,CAAC"}