devrager 0.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +988 -0
- package/dist/cli.js.map +7 -0
- package/dist/lib/adapters/amp.d.ts +3 -0
- package/dist/lib/adapters/amp.d.ts.map +1 -0
- package/dist/lib/adapters/amp.js +74 -0
- package/dist/lib/adapters/amp.js.map +1 -0
- package/dist/lib/adapters/claude.d.ts +3 -0
- package/dist/lib/adapters/claude.d.ts.map +1 -0
- package/dist/lib/adapters/claude.js +137 -0
- package/dist/lib/adapters/claude.js.map +1 -0
- package/dist/lib/adapters/cline.d.ts +3 -0
- package/dist/lib/adapters/cline.d.ts.map +1 -0
- package/dist/lib/adapters/cline.js +122 -0
- package/dist/lib/adapters/cline.js.map +1 -0
- package/dist/lib/adapters/codex.d.ts +3 -0
- package/dist/lib/adapters/codex.d.ts.map +1 -0
- package/dist/lib/adapters/codex.js +99 -0
- package/dist/lib/adapters/codex.js.map +1 -0
- package/dist/lib/adapters/index.d.ts +17 -0
- package/dist/lib/adapters/index.d.ts.map +1 -0
- package/dist/lib/adapters/index.js +27 -0
- package/dist/lib/adapters/index.js.map +1 -0
- package/dist/lib/adapters/opencode.d.ts +3 -0
- package/dist/lib/adapters/opencode.d.ts.map +1 -0
- package/dist/lib/adapters/opencode.js +86 -0
- package/dist/lib/adapters/opencode.js.map +1 -0
- package/dist/lib/adapters/pi.d.ts +3 -0
- package/dist/lib/adapters/pi.d.ts.map +1 -0
- package/dist/lib/adapters/pi.js +112 -0
- package/dist/lib/adapters/pi.js.map +1 -0
- package/dist/lib/adapters/zed.d.ts +3 -0
- package/dist/lib/adapters/zed.d.ts.map +1 -0
- package/dist/lib/adapters/zed.js +156 -0
- package/dist/lib/adapters/zed.js.map +1 -0
- package/dist/lib/detector/index.d.ts +32 -0
- package/dist/lib/detector/index.d.ts.map +1 -0
- package/dist/lib/detector/index.js +224 -0
- package/dist/lib/detector/index.js.map +1 -0
- package/dist/lib/index.d.ts +3 -0
- package/dist/lib/index.d.ts.map +1 -0
- package/dist/lib/index.js +3 -0
- package/dist/lib/index.js.map +1 -0
- package/package.json +40 -0
|
@@ -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 @@
|
|
|
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 @@
|
|
|
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 @@
|
|
|
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"}
|