supernaturalist 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/README.md +85 -0
  2. package/dist/cli.js +1097 -0
  3. package/dist/cli.js.map +7 -0
  4. package/dist/lib/adapters/amp.d.ts +3 -0
  5. package/dist/lib/adapters/amp.d.ts.map +1 -0
  6. package/dist/lib/adapters/amp.js +79 -0
  7. package/dist/lib/adapters/amp.js.map +1 -0
  8. package/dist/lib/adapters/claude.d.ts +3 -0
  9. package/dist/lib/adapters/claude.d.ts.map +1 -0
  10. package/dist/lib/adapters/claude.js +147 -0
  11. package/dist/lib/adapters/claude.js.map +1 -0
  12. package/dist/lib/adapters/cline.d.ts +3 -0
  13. package/dist/lib/adapters/cline.d.ts.map +1 -0
  14. package/dist/lib/adapters/cline.js +125 -0
  15. package/dist/lib/adapters/cline.js.map +1 -0
  16. package/dist/lib/adapters/codex.d.ts +3 -0
  17. package/dist/lib/adapters/codex.d.ts.map +1 -0
  18. package/dist/lib/adapters/codex.js +96 -0
  19. package/dist/lib/adapters/codex.js.map +1 -0
  20. package/dist/lib/adapters/index.d.ts +17 -0
  21. package/dist/lib/adapters/index.d.ts.map +1 -0
  22. package/dist/lib/adapters/index.js +27 -0
  23. package/dist/lib/adapters/index.js.map +1 -0
  24. package/dist/lib/adapters/opencode.d.ts +3 -0
  25. package/dist/lib/adapters/opencode.d.ts.map +1 -0
  26. package/dist/lib/adapters/opencode.js +86 -0
  27. package/dist/lib/adapters/opencode.js.map +1 -0
  28. package/dist/lib/adapters/pi.d.ts +3 -0
  29. package/dist/lib/adapters/pi.d.ts.map +1 -0
  30. package/dist/lib/adapters/pi.js +118 -0
  31. package/dist/lib/adapters/pi.js.map +1 -0
  32. package/dist/lib/adapters/zed.d.ts +3 -0
  33. package/dist/lib/adapters/zed.d.ts.map +1 -0
  34. package/dist/lib/adapters/zed.js +156 -0
  35. package/dist/lib/adapters/zed.js.map +1 -0
  36. package/dist/lib/detector/index.d.ts +32 -0
  37. package/dist/lib/detector/index.d.ts.map +1 -0
  38. package/dist/lib/detector/index.js +234 -0
  39. package/dist/lib/detector/index.js.map +1 -0
  40. package/dist/lib/index.d.ts +3 -0
  41. package/dist/lib/index.d.ts.map +1 -0
  42. package/dist/lib/index.js +3 -0
  43. package/dist/lib/index.js.map +1 -0
  44. package/package.json +39 -0
@@ -0,0 +1,96 @@
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": "assistant", "content": [...] } }
12
+ *
13
+ * Assistant messages have payload.role === "assistant" and content is usually
14
+ * an array of { "type": "output_text", "text": "..." } parts.
15
+ */
16
+ const CODEX_SESSIONS_DIR = join(homedir(), ".codex", "sessions");
17
+ export function codexAdapter() {
18
+ return {
19
+ name: "codex",
20
+ async *messages(options) {
21
+ yield* walkCodexSessions(CODEX_SESSIONS_DIR, options);
22
+ },
23
+ };
24
+ }
25
+ async function* walkCodexSessions(dir, options) {
26
+ let entries;
27
+ try {
28
+ entries = await readdir(dir);
29
+ }
30
+ catch {
31
+ return; // Codex not installed or no sessions
32
+ }
33
+ for (const entry of entries) {
34
+ const fullPath = join(dir, entry);
35
+ const entryStat = await stat(fullPath);
36
+ if (entryStat.isDirectory()) {
37
+ yield* walkCodexSessions(fullPath, options);
38
+ }
39
+ else if (entry.endsWith(".jsonl")) {
40
+ const session = entry.replace(".jsonl", "");
41
+ const context = options?.since ? { session, since: options.since } : { session };
42
+ yield* parseCodexJsonl(fullPath, context);
43
+ }
44
+ }
45
+ }
46
+ async function* parseCodexJsonl(filePath, context) {
47
+ const rl = createInterface({
48
+ input: createReadStream(filePath, { encoding: "utf-8" }),
49
+ crlfDelay: Infinity,
50
+ });
51
+ for await (const line of rl) {
52
+ if (!line.trim()) {
53
+ continue;
54
+ }
55
+ try {
56
+ const entry = JSON.parse(line);
57
+ if (entry.type !== "response_item") {
58
+ continue;
59
+ }
60
+ const payload = entry.payload;
61
+ if (!payload || payload.role !== "assistant") {
62
+ continue;
63
+ }
64
+ const text = extractText(payload.content);
65
+ if (!text) {
66
+ continue;
67
+ }
68
+ if (context.since && entry.timestamp) {
69
+ const ts = new Date(entry.timestamp);
70
+ if (ts < context.since) {
71
+ continue;
72
+ }
73
+ }
74
+ const message = entry.timestamp
75
+ ? { text, timestamp: entry.timestamp, session: context.session }
76
+ : { text, session: context.session };
77
+ yield message;
78
+ }
79
+ catch {
80
+ // Skip malformed lines
81
+ }
82
+ }
83
+ }
84
+ function extractText(content) {
85
+ if (!Array.isArray(content)) {
86
+ return null;
87
+ }
88
+ const parts = content
89
+ .filter((p) => typeof p === "object" &&
90
+ p !== null &&
91
+ (p.type === "output_text" || p.type === "text") &&
92
+ typeof p.text === "string")
93
+ .map((p) => p.text);
94
+ return parts.length > 0 ? parts.join(" ") : null;
95
+ }
96
+ //# 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 assistant/agent 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,6EAA6E;IAC7E,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;AAuChE,wBAAgB,eAAe,IAAI,OAAO,CA4BzC"}
@@ -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 assistant's message" }
14
+ *
15
+ * Assistant messages have role="assistant" in message.data. The actual text content is in
16
+ * the associated part rows where part.data.type === "text".
17
+ */
18
+ function getOpencodeDatabasePath() {
19
+ const xdgPath = join(process.env["XDG_DATA_HOME"] ?? join(homedir(), ".local", "share"), "opencode", "opencode.db");
20
+ if (existsSync(xdgPath)) {
21
+ return xdgPath;
22
+ }
23
+ if (process.platform === "darwin") {
24
+ const macPath = join(homedir(), "Library", "Application Support", "opencode", "opencode.db");
25
+ if (existsSync(macPath)) {
26
+ return macPath;
27
+ }
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
+ }
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("supernaturalist: better-sqlite3 not available, skipping OpenCode sessions");
47
+ return;
48
+ }
49
+ try {
50
+ yield* queryAssistantMessages(db, options);
51
+ }
52
+ finally {
53
+ db.close();
54
+ }
55
+ },
56
+ };
57
+ }
58
+ function* queryAssistantMessages(db, options) {
59
+ let query = `
60
+ SELECT
61
+ m.session_id,
62
+ m.time_created,
63
+ json_extract(p.data, '$.text') as text
64
+ FROM message m
65
+ JOIN part p ON p.message_id = m.id
66
+ WHERE json_extract(m.data, '$.role') = 'assistant'
67
+ AND json_extract(p.data, '$.type') = 'text'
68
+ `;
69
+ if (options?.since) {
70
+ const sinceMs = options.since.getTime();
71
+ query += ` AND m.time_created >= ${sinceMs}`;
72
+ }
73
+ query += ` ORDER BY m.time_created ASC`;
74
+ const rows = db.prepare(query).all();
75
+ for (const row of rows) {
76
+ if (!row.text || !row.text.trim()) {
77
+ continue;
78
+ }
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,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,EAAE,CAAC;QAAA,OAAO,OAAO,CAAC;IAAA,CAAC;IAE1C,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,EAAE,CAAC;YAAA,OAAO,OAAO,CAAC;QAAA,CAAC;IAC5C,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,EAAE,CAAC;gBAAA,OAAO;YAAA,CAAC;YAEtB,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,IAE6B,CAAC,MAAM,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;YACtE,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,CAAC,IAAI,CACV,2EAA2E,CAC5E,CAAC;gBACF,OAAO;YACT,CAAC;YAED,IAAI,CAAC;gBACH,KAAK,CAAC,CAAC,sBAAsB,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;YAC7C,CAAC;oBAAS,CAAC;gBACT,EAAE,CAAC,KAAK,EAAE,CAAC;YACb,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC;AAED,QAAQ,CAAC,CAAC,sBAAsB,CAC9B,EAAqC,EACrC,OAAwB;IAExB,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,EAAE,CAAC;YAAA,SAAS;QAAA,CAAC;QAE9C,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;AAehE,wBAAgB,SAAS,IAAI,OAAO,CAOnC"}
@@ -0,0 +1,118 @@
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 Agent stores sessions as JSONL files at:
8
+ * ~/.pi/agent/sessions/<project>/<session-id>.jsonl
9
+ *
10
+ * Each line is a JSON object:
11
+ * { "type": "session", "cwd": "/path/to/project" } — session metadata
12
+ * { "type": "message", "timestamp": "...", "message": { "role": "assistant", "content": "..." } }
13
+ *
14
+ * Content can be a string or array of { type: "text", text: "..." } parts.
15
+ */
16
+ const PI_SESSIONS_DIR = join(homedir(), ".pi", "agent", "sessions");
17
+ export function piAdapter() {
18
+ return {
19
+ name: "pi",
20
+ async *messages(options) {
21
+ yield* walkPiSessions(PI_SESSIONS_DIR, options);
22
+ },
23
+ };
24
+ }
25
+ async function* walkPiSessions(dir, options, project) {
26
+ let entries;
27
+ try {
28
+ entries = await readdir(dir);
29
+ }
30
+ catch {
31
+ return;
32
+ }
33
+ for (const entry of entries) {
34
+ const fullPath = join(dir, entry);
35
+ const entryStat = await stat(fullPath).catch(() => null);
36
+ if (!entryStat) {
37
+ continue;
38
+ }
39
+ if (entryStat.isDirectory()) {
40
+ yield* walkPiSessions(fullPath, options, project ?? entry);
41
+ }
42
+ else if (entry.endsWith(".jsonl")) {
43
+ const session = entry.replace(".jsonl", "");
44
+ const context = options?.since
45
+ ? { session, project, since: options.since }
46
+ : { session, project };
47
+ yield* parsePiJsonl(fullPath, context);
48
+ }
49
+ }
50
+ }
51
+ async function* parsePiJsonl(filePath, context) {
52
+ const rl = createInterface({
53
+ input: createReadStream(filePath, { encoding: "utf-8" }),
54
+ crlfDelay: Infinity,
55
+ });
56
+ let project = context.project;
57
+ for await (const line of rl) {
58
+ if (!line.trim()) {
59
+ continue;
60
+ }
61
+ try {
62
+ const entry = JSON.parse(line);
63
+ if (entry.type === "session") {
64
+ project = entry.cwd ?? project;
65
+ continue;
66
+ }
67
+ if (entry.type !== "message") {
68
+ continue;
69
+ }
70
+ const message = entry.message;
71
+ if (!message || message.role !== "assistant") {
72
+ continue;
73
+ }
74
+ const text = contentToString(message.content);
75
+ if (!text) {
76
+ continue;
77
+ }
78
+ const timestamp = typeof entry.timestamp === "string"
79
+ ? entry.timestamp
80
+ : typeof message.timestamp === "number"
81
+ ? new Date(message.timestamp).toISOString()
82
+ : undefined;
83
+ if (context.since && timestamp) {
84
+ const ts = new Date(timestamp);
85
+ if (ts < context.since) {
86
+ continue;
87
+ }
88
+ }
89
+ const record = timestamp
90
+ ? project
91
+ ? { text, timestamp, session: context.session, project }
92
+ : { text, timestamp, session: context.session }
93
+ : project
94
+ ? { text, session: context.session, project }
95
+ : { text, session: context.session };
96
+ yield record;
97
+ }
98
+ catch {
99
+ // Skip malformed lines
100
+ }
101
+ }
102
+ }
103
+ function contentToString(content) {
104
+ if (typeof content === "string") {
105
+ return content;
106
+ }
107
+ if (Array.isArray(content)) {
108
+ const parts = content
109
+ .filter((p) => typeof p === "object" &&
110
+ p !== null &&
111
+ p.type === "text" &&
112
+ typeof p.text === "string")
113
+ .map((p) => p.text);
114
+ return parts.length > 0 ? parts.join(" ") : null;
115
+ }
116
+ return null;
117
+ }
118
+ //# 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;AAqChE,wBAAgB,UAAU,IAAI,OAAO,CAUpC"}
@@ -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
+ const base = join(process.env["XDG_DATA_HOME"] ?? join(homedir(), ".local", "share"), "zed");
30
+ return {
31
+ conversations: join(base, "conversations"),
32
+ db: join(base, "db"),
33
+ };
34
+ }
35
+ export function zedAdapter() {
36
+ return {
37
+ name: "zed",
38
+ async *messages(options) {
39
+ const paths = getZedPaths();
40
+ yield* parseTextThreads(paths.conversations, options);
41
+ yield* parseAgentThreads(paths.db, options);
42
+ },
43
+ };
44
+ }
45
+ async function* parseTextThreads(dir, _options) {
46
+ if (!existsSync(dir)) {
47
+ return;
48
+ }
49
+ let files;
50
+ try {
51
+ files = await readdir(dir);
52
+ }
53
+ catch {
54
+ return;
55
+ }
56
+ const jsonFiles = files.filter((f) => f.endsWith(".json"));
57
+ for (const file of jsonFiles) {
58
+ const filePath = join(dir, file);
59
+ const session = file.replace(".json", "");
60
+ try {
61
+ const raw = await readFile(filePath, "utf-8");
62
+ const conversation = JSON.parse(raw);
63
+ if (!conversation.messages || !Array.isArray(conversation.messages)) {
64
+ continue;
65
+ }
66
+ for (const msg of conversation.messages) {
67
+ if (msg.role !== "assistant") {
68
+ continue;
69
+ }
70
+ const text = typeof msg.content === "string" ? msg.content : null;
71
+ if (!text) {
72
+ continue;
73
+ }
74
+ yield {
75
+ text,
76
+ session,
77
+ };
78
+ }
79
+ }
80
+ catch {
81
+ // Skip malformed files
82
+ }
83
+ }
84
+ }
85
+ async function* parseAgentThreads(dbDir, _options) {
86
+ if (!existsSync(dbDir)) {
87
+ return;
88
+ }
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
+ }
100
+ let Database;
101
+ try {
102
+ const mod = await import("better-sqlite3");
103
+ Database = mod.default ?? mod;
104
+ }
105
+ catch {
106
+ return;
107
+ }
108
+ for (const dbFile of dbFiles) {
109
+ const dbPath = join(dbDir, dbFile);
110
+ let db;
111
+ try {
112
+ db = new Database(dbPath, { readonly: true });
113
+ }
114
+ catch {
115
+ continue;
116
+ }
117
+ try {
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
+ const msgTable = tableNames.find((t) => t === "messages" || t === "thread_messages" || t.includes("message"));
123
+ if (!msgTable) {
124
+ db.close();
125
+ continue;
126
+ }
127
+ const columns = db.prepare(`PRAGMA table_info("${msgTable}")`).all();
128
+ const colNames = columns.map((c) => c.name);
129
+ const hasRole = colNames.includes("role");
130
+ if (!hasRole) {
131
+ db.close();
132
+ continue;
133
+ }
134
+ const contentCol = colNames.includes("content")
135
+ ? "content"
136
+ : colNames.includes("body")
137
+ ? "body"
138
+ : "text";
139
+ const query = `SELECT "${contentCol}" as text FROM "${msgTable}" WHERE role = 'assistant'`;
140
+ const rows = db.prepare(query).all();
141
+ for (const row of rows) {
142
+ if (!row.text?.trim()) {
143
+ continue;
144
+ }
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 supernatural terms 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
+ intensity: Intensity;
11
+ group: string;
12
+ }
13
+ export type Intensity = "subtle" | "vivid" | "ominous";
14
+ interface WordDef {
15
+ word: string;
16
+ intensity: Intensity;
17
+ group: string;
18
+ }
19
+ /**
20
+ * Detect supernatural terms 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 ghooost, haauunted, 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,iDAAiD;IACjD,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,SAAS,EAAE,SAAS,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,MAAM,SAAS,GAAG,QAAQ,GAAG,OAAO,GAAG,SAAS,CAAC;AAEvD,UAAU,OAAO;IACf,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,SAAS,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;CACf;AAqLD;;;;;;GAMG;AACH,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe,CAYpD;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"}