@tryglen/cli 0.15.0 → 0.17.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.
- package/README.md +1 -0
- package/dist/_utils/agent-adapter.js +14 -0
- package/dist/_utils/agent-adapter.js.map +1 -1
- package/dist/_utils/collect-import-files.d.ts +4 -0
- package/dist/_utils/collect-import-files.js +55 -0
- package/dist/_utils/collect-import-files.js.map +1 -0
- package/dist/_utils/config.d.ts +2 -0
- package/dist/_utils/config.js +3 -0
- package/dist/_utils/config.js.map +1 -1
- package/dist/_utils/detect-transcript-format.d.ts +2 -0
- package/dist/_utils/detect-transcript-format.js +53 -0
- package/dist/_utils/detect-transcript-format.js.map +1 -0
- package/dist/_utils/parse-claude-transcript.d.ts +3 -0
- package/dist/_utils/parse-claude-transcript.js +124 -0
- package/dist/_utils/parse-claude-transcript.js.map +1 -0
- package/dist/_utils/parse-codex-transcript.d.ts +3 -0
- package/dist/_utils/parse-codex-transcript.js +111 -0
- package/dist/_utils/parse-codex-transcript.js.map +1 -0
- package/dist/_utils/parse-cursor-db.d.ts +5 -0
- package/dist/_utils/parse-cursor-db.js +227 -0
- package/dist/_utils/parse-cursor-db.js.map +1 -0
- package/dist/_utils/transcript-turns.d.ts +19 -0
- package/dist/_utils/transcript-turns.js +41 -0
- package/dist/_utils/transcript-turns.js.map +1 -0
- package/dist/_utils/turn-cache.d.ts +7 -0
- package/dist/_utils/turn-cache.js +63 -0
- package/dist/_utils/turn-cache.js.map +1 -0
- package/dist/bin.js +33 -13
- package/dist/bin.js.map +1 -1
- package/dist/commands/doctor.js +6 -0
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/import.d.ts +7 -0
- package/dist/commands/import.js +236 -0
- package/dist/commands/import.js.map +1 -0
- package/dist/commands/ingest.js +79 -24
- package/dist/commands/ingest.js.map +1 -1
- package/dist/commands/install.js +42 -2
- package/dist/commands/install.js.map +1 -1
- package/dist/commands/onboard.js +1 -1
- package/dist/commands/onboard.js.map +1 -1
- package/dist/commands/pr-link.js +23 -10
- package/dist/commands/pr-link.js.map +1 -1
- package/dist/commands/session-start.d.ts +6 -7
- package/dist/commands/session-start.js +30 -10
- package/dist/commands/session-start.js.map +1 -1
- package/dist/commands/uninstall.js +5 -1
- package/dist/commands/uninstall.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -17,6 +17,7 @@ glen login
|
|
|
17
17
|
| `glen logout` | Sign out and remove credentials + session state. |
|
|
18
18
|
| `glen status` | Show connection status, active org, incognito state, and CLI version. |
|
|
19
19
|
| `glen search "<query>"` | Search the team's shared glen memory. |
|
|
20
|
+
| `glen import <path…> [--dry-run]` | Import old local agent transcripts (Claude Code `~/.claude/projects`, Codex `~/.codex/sessions`, Cursor `state.vscdb`) into glen memory. Idempotent — re-running skips already-imported turns. `--dry-run` previews without writing. |
|
|
20
21
|
| `glen incognito on\|off` | Toggle incognito mode: while on, nothing is recorded (recall keeps working). |
|
|
21
22
|
| `glen org list` | List your organizations; active one is marked with `✓`. |
|
|
22
23
|
| `glen org switch [slug]` | Switch the active organization for this machine (interactive picker without `slug`). |
|
|
@@ -12,6 +12,20 @@ const str = (v) => typeof v === "string" && v ? v : null;
|
|
|
12
12
|
* idempotency key derivation.
|
|
13
13
|
*/
|
|
14
14
|
const adaptAgentEvent = (agent, event, transcriptLines) => {
|
|
15
|
+
if (agent === "cursor") {
|
|
16
|
+
// Cursor hooks carry no usable transcript; priorAssistant comes from the
|
|
17
|
+
// local turn-cache (populated by afterAgentResponse) and is read by
|
|
18
|
+
// ingest.ts, not here. Common payload fields carry the model.
|
|
19
|
+
const fields = {};
|
|
20
|
+
const model = str(event.model);
|
|
21
|
+
if (model)
|
|
22
|
+
fields.model = model;
|
|
23
|
+
return {
|
|
24
|
+
sessionFields: fields,
|
|
25
|
+
priorAssistant: null,
|
|
26
|
+
usesTranscript: false,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
15
29
|
if (agent === "codex") {
|
|
16
30
|
const fields = {};
|
|
17
31
|
const model = str(event.model);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-adapter.js","sourceRoot":"","sources":["../../src/_utils/agent-adapter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAaxD,gDAAgD;AAChD,MAAM,GAAG,GAAG,CAAC,CAAU,EAAiB,EAAE,CACxC,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AAExC;;;;;;;;;GASG;AACH,MAAM,eAAe,GAAG,CACtB,KAAyB,EACzB,KAAgB,EAChB,eAAkC,EACnB,EAAE;IACjB,IAAI,KAAK,KAAK,OAAO,EAAE,CAAC;QACtB,MAAM,MAAM,GAAkB,EAAE,CAAC;QACjC,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QAC/B,IAAI,KAAK;YAAE,MAAM,CAAC,KAAK,GAAG,KAAK,CAAC;QAChC,MAAM,cAAc,GAAG,GAAG,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC;QAClD,IAAI,cAAc;YAAE,MAAM,CAAC,cAAc,GAAG,cAAc,CAAC;QAC3D,MAAM,MAAM,GAAG,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QACjC,IAAI,MAAM;YAAE,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC;QACnC,OAAO;YACL,aAAa,EAAE,MAAM;YACrB,cAAc,EACZ,OAAO,KAAK,CAAC,sBAAsB,KAAK,QAAQ;gBAC9C,CAAC,CAAC,KAAK,CAAC,sBAAsB;gBAC9B,CAAC,CAAC,IAAI;YACV,cAAc,EAAE,KAAK;SACtB,CAAC;IACJ,CAAC;IAED,iFAAiF;IACjF,MAAM,EAAE,cAAc,EAAE,GAAG,eAAe,CAAC,eAAe,CAAC,CAAC;IAC5D,MAAM,MAAM,GAAkB,EAAE,CAAC;IACjC,MAAM,cAAc,GAAG,GAAG,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC;IAClD,IAAI,cAAc;QAAE,MAAM,CAAC,cAAc,GAAG,cAAc,CAAC;IAC3D,MAAM,MAAM,GAAG,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IACjC,IAAI,MAAM;QAAE,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC;IACnC,OAAO;QACL,aAAa,EAAE,MAAM;QACrB,cAAc;QACd,cAAc,EAAE,IAAI;KACrB,CAAC;AACJ,CAAC,CAAC;AAEF,OAAO,EAAE,eAAe,EAAE,CAAC"}
|
|
1
|
+
{"version":3,"file":"agent-adapter.js","sourceRoot":"","sources":["../../src/_utils/agent-adapter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAaxD,gDAAgD;AAChD,MAAM,GAAG,GAAG,CAAC,CAAU,EAAiB,EAAE,CACxC,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AAExC;;;;;;;;;GASG;AACH,MAAM,eAAe,GAAG,CACtB,KAAyB,EACzB,KAAgB,EAChB,eAAkC,EACnB,EAAE;IACjB,IAAI,KAAK,KAAK,QAAQ,EAAE,CAAC;QACvB,yEAAyE;QACzE,oEAAoE;QACpE,8DAA8D;QAC9D,MAAM,MAAM,GAAkB,EAAE,CAAC;QACjC,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QAC/B,IAAI,KAAK;YAAE,MAAM,CAAC,KAAK,GAAG,KAAK,CAAC;QAChC,OAAO;YACL,aAAa,EAAE,MAAM;YACrB,cAAc,EAAE,IAAI;YACpB,cAAc,EAAE,KAAK;SACtB,CAAC;IACJ,CAAC;IAED,IAAI,KAAK,KAAK,OAAO,EAAE,CAAC;QACtB,MAAM,MAAM,GAAkB,EAAE,CAAC;QACjC,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QAC/B,IAAI,KAAK;YAAE,MAAM,CAAC,KAAK,GAAG,KAAK,CAAC;QAChC,MAAM,cAAc,GAAG,GAAG,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC;QAClD,IAAI,cAAc;YAAE,MAAM,CAAC,cAAc,GAAG,cAAc,CAAC;QAC3D,MAAM,MAAM,GAAG,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QACjC,IAAI,MAAM;YAAE,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC;QACnC,OAAO;YACL,aAAa,EAAE,MAAM;YACrB,cAAc,EACZ,OAAO,KAAK,CAAC,sBAAsB,KAAK,QAAQ;gBAC9C,CAAC,CAAC,KAAK,CAAC,sBAAsB;gBAC9B,CAAC,CAAC,IAAI;YACV,cAAc,EAAE,KAAK;SACtB,CAAC;IACJ,CAAC;IAED,iFAAiF;IACjF,MAAM,EAAE,cAAc,EAAE,GAAG,eAAe,CAAC,eAAe,CAAC,CAAC;IAC5D,MAAM,MAAM,GAAkB,EAAE,CAAC;IACjC,MAAM,cAAc,GAAG,GAAG,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC;IAClD,IAAI,cAAc;QAAE,MAAM,CAAC,cAAc,GAAG,cAAc,CAAC;IAC3D,MAAM,MAAM,GAAG,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IACjC,IAAI,MAAM;QAAE,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC;IACnC,OAAO;QACL,aAAa,EAAE,MAAM;QACrB,cAAc;QACd,cAAc,EAAE,IAAI;KACrB,CAAC;AACJ,CAAC,CAAC;AAEF,OAAO,EAAE,eAAe,EAAE,CAAC"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { readdir, stat } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { causeOf, cliErr } from "./cli-error.js";
|
|
4
|
+
import { err, ok } from "./result.js";
|
|
5
|
+
// A file is an import candidate if it looks like a transcript container:
|
|
6
|
+
// Claude Code / Codex session JSONL, or a Cursor SQLite store. Claude Code
|
|
7
|
+
// subagent sidechains (<session>/subagents/agent-*.jsonl) are skipped — they
|
|
8
|
+
// are internal tool chatter, not the user's conversation.
|
|
9
|
+
const isCandidate = (path) => !path.split(/[\\/]/).includes("subagents") &&
|
|
10
|
+
(path.endsWith(".jsonl") || path.endsWith(".vscdb"));
|
|
11
|
+
const walk = async (dir) => {
|
|
12
|
+
const entries = await readdir(dir, { withFileTypes: true });
|
|
13
|
+
const nested = await Promise.all(entries.map(async (entry) => {
|
|
14
|
+
const path = join(dir, entry.name);
|
|
15
|
+
if (entry.isDirectory())
|
|
16
|
+
return walk(path);
|
|
17
|
+
return entry.isFile() && isCandidate(path) ? [path] : [];
|
|
18
|
+
}));
|
|
19
|
+
return nested.flat();
|
|
20
|
+
};
|
|
21
|
+
// Expand the user-supplied paths into concrete transcript files. A directory
|
|
22
|
+
// is scanned recursively for candidates; an explicitly named file is always
|
|
23
|
+
// kept (the user pointed at it — let format detection decide what it is).
|
|
24
|
+
const collectImportFiles = async (paths) => {
|
|
25
|
+
const collected = await Promise.all(paths.map(async (path) => {
|
|
26
|
+
const info = await (async () => {
|
|
27
|
+
try {
|
|
28
|
+
return await stat(path);
|
|
29
|
+
}
|
|
30
|
+
catch (e) {
|
|
31
|
+
return causeOf(e);
|
|
32
|
+
}
|
|
33
|
+
})();
|
|
34
|
+
if (typeof info === "string")
|
|
35
|
+
return err(cliErr({
|
|
36
|
+
what: "path not found",
|
|
37
|
+
why: info,
|
|
38
|
+
path,
|
|
39
|
+
remedy: "pass a transcript file or directory — Claude Code: ~/.claude/projects · Codex: ~/.codex/sessions · Cursor: ~/.config/Cursor/User/globalStorage/state.vscdb (macOS: ~/Library/Application Support/Cursor/…)",
|
|
40
|
+
}));
|
|
41
|
+
if (info.isDirectory())
|
|
42
|
+
return ok(await walk(path));
|
|
43
|
+
return ok([path]);
|
|
44
|
+
}));
|
|
45
|
+
const failed = collected.find((r) => !r.ok);
|
|
46
|
+
if (failed && !failed.ok)
|
|
47
|
+
return failed;
|
|
48
|
+
const files = collected
|
|
49
|
+
.flatMap((r) => (r.ok ? r.value : []))
|
|
50
|
+
.filter((f, i, all) => all.indexOf(f) === i)
|
|
51
|
+
.sort();
|
|
52
|
+
return ok(files);
|
|
53
|
+
};
|
|
54
|
+
export { collectImportFiles };
|
|
55
|
+
//# sourceMappingURL=collect-import-files.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"collect-import-files.js","sourceRoot":"","sources":["../../src/_utils/collect-import-files.ts"],"names":[],"mappings":"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"}
|
package/dist/_utils/config.d.ts
CHANGED
|
@@ -16,11 +16,13 @@ declare const config: {
|
|
|
16
16
|
artifactSearchUrl: string;
|
|
17
17
|
commitAnchorUrl: string;
|
|
18
18
|
codeSearchUrl: string;
|
|
19
|
+
importUrl: string;
|
|
19
20
|
ingestTimeoutMs: number;
|
|
20
21
|
searchTimeoutMs: number;
|
|
21
22
|
forgetTimeoutMs: number;
|
|
22
23
|
listOrgsTimeoutMs: number;
|
|
23
24
|
commitAnchorTimeoutMs: number;
|
|
24
25
|
codeSearchTimeoutMs: number;
|
|
26
|
+
importTimeoutMs: number;
|
|
25
27
|
};
|
|
26
28
|
export { config };
|
package/dist/_utils/config.js
CHANGED
|
@@ -19,6 +19,7 @@ const config = {
|
|
|
19
19
|
artifactSearchUrl: `${baseUrl}/api/mcp/route/artifactSearch`,
|
|
20
20
|
commitAnchorUrl: `${baseUrl}/api/mcp/route/commitAnchor`,
|
|
21
21
|
codeSearchUrl: `${baseUrl}/api/mcp/route/codeSearch`,
|
|
22
|
+
importUrl: `${baseUrl}/api/mcp/route/importTranscript`,
|
|
22
23
|
ingestTimeoutMs: 8000,
|
|
23
24
|
searchTimeoutMs: 15_000,
|
|
24
25
|
forgetTimeoutMs: 15_000,
|
|
@@ -26,6 +27,8 @@ const config = {
|
|
|
26
27
|
commitAnchorTimeoutMs: 3000,
|
|
27
28
|
// Longer than search: the server runs a scoped LLM ranking AND renders transcripts.
|
|
28
29
|
codeSearchTimeoutMs: 30_000,
|
|
30
|
+
// Per-turn write; generous because imported turns can carry near-cap content.
|
|
31
|
+
importTimeoutMs: 15_000,
|
|
29
32
|
};
|
|
30
33
|
export { config };
|
|
31
34
|
//# sourceMappingURL=config.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/_utils/config.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,gEAAgE;AAChE,MAAM,OAAO,GAAG,CACd,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,yBAAyB,CACvD,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;AAEtB,MAAM,MAAM,GAAG;IACb,OAAO;IACP,UAAU,EAAE,GAAG,OAAO,cAAc;IACpC,WAAW,EAAE,GAAG,OAAO,2BAA2B;IAClD,OAAO,EAAE,GAAG,OAAO,qBAAqB;IACxC,SAAS,EAAE,GAAG,OAAO,uBAAuB;IAC5C,SAAS,EAAE,GAAG,OAAO,uBAAuB;IAC5C,SAAS,EAAE,GAAG,OAAO,6BAA6B;IAClD,WAAW,EAAE,GAAG,OAAO,yBAAyB;IAChD,cAAc,EAAE,GAAG,OAAO,4BAA4B;IACtD,WAAW,EAAE,GAAG,OAAO,yBAAyB;IAChD,cAAc,EAAE,GAAG,OAAO,4BAA4B;IACtD,mBAAmB,EAAE,GAAG,OAAO,iCAAiC;IAChE,iBAAiB,EAAE,GAAG,OAAO,+BAA+B;IAC5D,cAAc,EAAE,GAAG,OAAO,4BAA4B;IACtD,iBAAiB,EAAE,GAAG,OAAO,+BAA+B;IAC5D,eAAe,EAAE,GAAG,OAAO,6BAA6B;IACxD,aAAa,EAAE,GAAG,OAAO,2BAA2B;IACpD,eAAe,EAAE,IAAI;IACrB,eAAe,EAAE,MAAM;IACvB,eAAe,EAAE,MAAM;IACvB,iBAAiB,EAAE,MAAM;IACzB,qBAAqB,EAAE,IAAI;IAC3B,oFAAoF;IACpF,mBAAmB,EAAE,MAAM;
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/_utils/config.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,gEAAgE;AAChE,MAAM,OAAO,GAAG,CACd,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,yBAAyB,CACvD,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;AAEtB,MAAM,MAAM,GAAG;IACb,OAAO;IACP,UAAU,EAAE,GAAG,OAAO,cAAc;IACpC,WAAW,EAAE,GAAG,OAAO,2BAA2B;IAClD,OAAO,EAAE,GAAG,OAAO,qBAAqB;IACxC,SAAS,EAAE,GAAG,OAAO,uBAAuB;IAC5C,SAAS,EAAE,GAAG,OAAO,uBAAuB;IAC5C,SAAS,EAAE,GAAG,OAAO,6BAA6B;IAClD,WAAW,EAAE,GAAG,OAAO,yBAAyB;IAChD,cAAc,EAAE,GAAG,OAAO,4BAA4B;IACtD,WAAW,EAAE,GAAG,OAAO,yBAAyB;IAChD,cAAc,EAAE,GAAG,OAAO,4BAA4B;IACtD,mBAAmB,EAAE,GAAG,OAAO,iCAAiC;IAChE,iBAAiB,EAAE,GAAG,OAAO,+BAA+B;IAC5D,cAAc,EAAE,GAAG,OAAO,4BAA4B;IACtD,iBAAiB,EAAE,GAAG,OAAO,+BAA+B;IAC5D,eAAe,EAAE,GAAG,OAAO,6BAA6B;IACxD,aAAa,EAAE,GAAG,OAAO,2BAA2B;IACpD,SAAS,EAAE,GAAG,OAAO,iCAAiC;IACtD,eAAe,EAAE,IAAI;IACrB,eAAe,EAAE,MAAM;IACvB,eAAe,EAAE,MAAM;IACvB,iBAAiB,EAAE,MAAM;IACzB,qBAAqB,EAAE,IAAI;IAC3B,oFAAoF;IACpF,mBAAmB,EAAE,MAAM;IAC3B,8EAA8E;IAC9E,eAAe,EAAE,MAAM;CACxB,CAAC;AAEF,OAAO,EAAE,MAAM,EAAE,CAAC"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
const parseLine = (line) => {
|
|
2
|
+
try {
|
|
3
|
+
const parsed = JSON.parse(line);
|
|
4
|
+
return parsed !== null && typeof parsed === "object"
|
|
5
|
+
? parsed
|
|
6
|
+
: null;
|
|
7
|
+
}
|
|
8
|
+
catch {
|
|
9
|
+
return null;
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
const CODEX_ENVELOPE_TYPES = new Set([
|
|
13
|
+
"session_meta",
|
|
14
|
+
"response_item",
|
|
15
|
+
"event_msg",
|
|
16
|
+
"turn_context",
|
|
17
|
+
"compacted",
|
|
18
|
+
]);
|
|
19
|
+
// Sniff which agent wrote a transcript file. Cursor is identified by its
|
|
20
|
+
// SQLite container; the two JSONL formats are told apart by their envelopes:
|
|
21
|
+
// Claude Code lines carry uuid/parentUuid tree fields, Codex rollout lines a
|
|
22
|
+
// {timestamp, type, payload} wrapper (or, pre-envelope, bare Responses-API
|
|
23
|
+
// message items with input_text/output_text parts).
|
|
24
|
+
const detectTranscriptFormat = (filePath, sampleLines) => {
|
|
25
|
+
if (filePath.endsWith(".vscdb"))
|
|
26
|
+
return "cursor";
|
|
27
|
+
return (sampleLines
|
|
28
|
+
.slice(0, 25)
|
|
29
|
+
.map(parseLine)
|
|
30
|
+
.filter((e) => e !== null)
|
|
31
|
+
.map((e) => {
|
|
32
|
+
if ("parentUuid" in e || "leafUuid" in e)
|
|
33
|
+
return "claude-code";
|
|
34
|
+
if (typeof e.sessionId === "string" &&
|
|
35
|
+
(e.type === "user" || e.type === "assistant" || e.type === "summary"))
|
|
36
|
+
return "claude-code";
|
|
37
|
+
if (typeof e.type === "string" &&
|
|
38
|
+
CODEX_ENVELOPE_TYPES.has(e.type) &&
|
|
39
|
+
"payload" in e)
|
|
40
|
+
return "codex";
|
|
41
|
+
if (e.type === "message" &&
|
|
42
|
+
Array.isArray(e.content) &&
|
|
43
|
+
e.content.some((p) => p !== null &&
|
|
44
|
+
typeof p === "object" &&
|
|
45
|
+
(p.type === "input_text" ||
|
|
46
|
+
p.type === "output_text")))
|
|
47
|
+
return "codex";
|
|
48
|
+
return null;
|
|
49
|
+
})
|
|
50
|
+
.find((f) => f !== null) ?? null);
|
|
51
|
+
};
|
|
52
|
+
export { detectTranscriptFormat };
|
|
53
|
+
//# sourceMappingURL=detect-transcript-format.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"detect-transcript-format.js","sourceRoot":"","sources":["../../src/_utils/detect-transcript-format.ts"],"names":[],"mappings":"AAEA,MAAM,SAAS,GAAG,CAAC,IAAY,EAAgB,EAAE;IAC/C,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAY,CAAC;QAC3C,OAAO,MAAM,KAAK,IAAI,IAAI,OAAO,MAAM,KAAK,QAAQ;YAClD,CAAC,CAAE,MAAgB;YACnB,CAAC,CAAC,IAAI,CAAC;IACX,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC,CAAC;AAEF,MAAM,oBAAoB,GAAG,IAAI,GAAG,CAAC;IACnC,cAAc;IACd,eAAe;IACf,WAAW;IACX,cAAc;IACd,WAAW;CACZ,CAAC,CAAC;AAEH,yEAAyE;AACzE,6EAA6E;AAC7E,6EAA6E;AAC7E,2EAA2E;AAC3E,oDAAoD;AACpD,MAAM,sBAAsB,GAAG,CAC7B,QAAgB,EAChB,WAA8B,EACa,EAAE;IAC7C,IAAI,QAAQ,CAAC,QAAQ,CAAC,QAAQ,CAAC;QAAE,OAAO,QAAQ,CAAC;IACjD,OAAO,CACL,WAAW;SACR,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC;SACZ,GAAG,CAAC,SAAS,CAAC;SACd,MAAM,CAAC,CAAC,CAAC,EAAc,EAAE,CAAC,CAAC,KAAK,IAAI,CAAC;SACrC,GAAG,CAAC,CAAC,CAAC,EAAkC,EAAE;QACzC,IAAI,YAAY,IAAI,CAAC,IAAI,UAAU,IAAI,CAAC;YAAE,OAAO,aAAa,CAAC;QAC/D,IACE,OAAO,CAAC,CAAC,SAAS,KAAK,QAAQ;YAC/B,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,IAAI,CAAC,CAAC,IAAI,KAAK,WAAW,IAAI,CAAC,CAAC,IAAI,KAAK,SAAS,CAAC;YAErE,OAAO,aAAa,CAAC;QACvB,IACE,OAAO,CAAC,CAAC,IAAI,KAAK,QAAQ;YAC1B,oBAAoB,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;YAChC,SAAS,IAAI,CAAC;YAEd,OAAO,OAAO,CAAC;QACjB,IACE,CAAC,CAAC,IAAI,KAAK,SAAS;YACpB,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC;YACxB,CAAC,CAAC,OAAO,CAAC,IAAI,CACZ,CAAC,CAAC,EAAE,EAAE,CACJ,CAAC,KAAK,IAAI;gBACV,OAAO,CAAC,KAAK,QAAQ;gBACrB,CAAE,CAAW,CAAC,IAAI,KAAK,YAAY;oBAChC,CAAW,CAAC,IAAI,KAAK,aAAa,CAAC,CACzC;YAED,OAAO,OAAO,CAAC;QACjB,OAAO,IAAI,CAAC;IACd,CAAC,CAAC;SACD,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,IAAI,CAAC,IAAI,IAAI,CACnC,CAAC;AACJ,CAAC,CAAC;AAEF,OAAO,EAAE,sBAAsB,EAAE,CAAC"}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
const parseLine = (line) => {
|
|
2
|
+
try {
|
|
3
|
+
const parsed = JSON.parse(line);
|
|
4
|
+
return parsed !== null && typeof parsed === "object"
|
|
5
|
+
? parsed
|
|
6
|
+
: null;
|
|
7
|
+
}
|
|
8
|
+
catch {
|
|
9
|
+
return null;
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
const messageOf = (e) => e.message !== null && typeof e.message === "object"
|
|
13
|
+
? e.message
|
|
14
|
+
: null;
|
|
15
|
+
// Text of a Claude message: a plain string (typical human prompt) or the
|
|
16
|
+
// concatenated `text` content blocks (assistant output; thinking/tool_use
|
|
17
|
+
// blocks are not conversation text).
|
|
18
|
+
const textOf = (content) => {
|
|
19
|
+
if (typeof content === "string")
|
|
20
|
+
return content;
|
|
21
|
+
if (!Array.isArray(content))
|
|
22
|
+
return "";
|
|
23
|
+
return content
|
|
24
|
+
.filter((p) => p !== null &&
|
|
25
|
+
typeof p === "object" &&
|
|
26
|
+
p.type === "text" &&
|
|
27
|
+
typeof p.text === "string")
|
|
28
|
+
.map((p) => p.text)
|
|
29
|
+
.join("\n");
|
|
30
|
+
};
|
|
31
|
+
// User-role lines that are tool results, not human prompts: a tool_result
|
|
32
|
+
// content block and/or the top-level toolUseResult sibling.
|
|
33
|
+
const isToolResult = (e) => {
|
|
34
|
+
if (e.toolUseResult !== undefined)
|
|
35
|
+
return true;
|
|
36
|
+
const content = messageOf(e)?.content;
|
|
37
|
+
return (Array.isArray(content) &&
|
|
38
|
+
content.some((p) => p !== null &&
|
|
39
|
+
typeof p === "object" &&
|
|
40
|
+
p.type === "tool_result"));
|
|
41
|
+
};
|
|
42
|
+
// Harness-injected user lines that were never typed by the human.
|
|
43
|
+
const INJECTED_PREFIXES = [
|
|
44
|
+
"<command-name>",
|
|
45
|
+
"<command-message>",
|
|
46
|
+
"<local-command-stdout>",
|
|
47
|
+
"<local-command-stderr>",
|
|
48
|
+
"Caveat:",
|
|
49
|
+
];
|
|
50
|
+
// Claude Code lines form a tree via uuid → parentUuid (edits/retries/resume
|
|
51
|
+
// forks create branches). Follow the chain up from the active leaf — the last
|
|
52
|
+
// line in file order that is nobody's parent — so abandoned branches aren't
|
|
53
|
+
// imported twice. Falls back to file order when the chain is unwalkable
|
|
54
|
+
// (format drift), which matches the active branch in almost all sessions.
|
|
55
|
+
const activeBranch = (entries) => {
|
|
56
|
+
const withUuid = entries.filter((e) => typeof e.uuid === "string");
|
|
57
|
+
const byUuid = new Map(withUuid.map((e) => [e.uuid, e]));
|
|
58
|
+
const parents = new Set(entries
|
|
59
|
+
.map((e) => e.parentUuid)
|
|
60
|
+
.filter((p) => typeof p === "string"));
|
|
61
|
+
const leaf = [...withUuid]
|
|
62
|
+
.reverse()
|
|
63
|
+
.find((e) => !parents.has(e.uuid));
|
|
64
|
+
if (!leaf)
|
|
65
|
+
return entries;
|
|
66
|
+
const walk = (e, acc, seen) => {
|
|
67
|
+
if (!e || typeof e.uuid !== "string" || seen.has(e.uuid))
|
|
68
|
+
return acc;
|
|
69
|
+
return walk(typeof e.parentUuid === "string" ? byUuid.get(e.parentUuid) : undefined, [e, ...acc], new Set([...seen, e.uuid]));
|
|
70
|
+
};
|
|
71
|
+
const chain = walk(leaf, [], new Set());
|
|
72
|
+
return chain.length > 0 ? chain : entries;
|
|
73
|
+
};
|
|
74
|
+
// Parse one Claude Code session file (~/.claude/projects/<munged-cwd>/<uuid>.jsonl)
|
|
75
|
+
// into the normalized transcript shape. Tolerant by design: unknown line types,
|
|
76
|
+
// missing fields, and unparseable lines are skipped, never fatal — the format
|
|
77
|
+
// is undocumented and drifts across versions.
|
|
78
|
+
const parseClaudeTranscript = (lines, fallbackSessionId) => {
|
|
79
|
+
const entries = lines.map(parseLine).filter((e) => e !== null);
|
|
80
|
+
const conversation = activeBranch(entries).filter((e) => {
|
|
81
|
+
if (e.type !== "user" && e.type !== "assistant")
|
|
82
|
+
return false;
|
|
83
|
+
if (e.isSidechain === true)
|
|
84
|
+
return false; // subagent chatter
|
|
85
|
+
if (e.isMeta === true)
|
|
86
|
+
return false; // harness bookkeeping
|
|
87
|
+
if (e.isCompactSummary === true)
|
|
88
|
+
return false; // compaction artifact
|
|
89
|
+
return messageOf(e) !== null;
|
|
90
|
+
});
|
|
91
|
+
const messages = [];
|
|
92
|
+
for (const e of conversation) {
|
|
93
|
+
if (e.type === "user") {
|
|
94
|
+
if (isToolResult(e))
|
|
95
|
+
continue;
|
|
96
|
+
const text = textOf(messageOf(e)?.content);
|
|
97
|
+
if (INJECTED_PREFIXES.some((p) => text.startsWith(p)))
|
|
98
|
+
continue;
|
|
99
|
+
messages.push({ role: "user", text });
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
messages.push({ role: "assistant", text: textOf(messageOf(e)?.content) });
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
if (messages.every((m) => m.text.trim() === ""))
|
|
106
|
+
return null;
|
|
107
|
+
const first = entries.find((e) => typeof e.sessionId === "string");
|
|
108
|
+
const firstCwd = entries.find((e) => typeof e.cwd === "string");
|
|
109
|
+
const firstBranch = entries.find((e) => typeof e.gitBranch === "string" && e.gitBranch !== "");
|
|
110
|
+
const lastModel = [...conversation]
|
|
111
|
+
.reverse()
|
|
112
|
+
.map((e) => messageOf(e)?.model)
|
|
113
|
+
.find((m) => typeof m === "string");
|
|
114
|
+
return {
|
|
115
|
+
sessionId: first?.sessionId ?? fallbackSessionId,
|
|
116
|
+
agent: "claude-code",
|
|
117
|
+
cwd: firstCwd?.cwd,
|
|
118
|
+
branch: firstBranch?.gitBranch,
|
|
119
|
+
model: lastModel,
|
|
120
|
+
messages,
|
|
121
|
+
};
|
|
122
|
+
};
|
|
123
|
+
export { parseClaudeTranscript };
|
|
124
|
+
//# sourceMappingURL=parse-claude-transcript.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse-claude-transcript.js","sourceRoot":"","sources":["../../src/_utils/parse-claude-transcript.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
const parseLine = (line) => {
|
|
2
|
+
try {
|
|
3
|
+
const parsed = JSON.parse(line);
|
|
4
|
+
return parsed !== null && typeof parsed === "object"
|
|
5
|
+
? parsed
|
|
6
|
+
: null;
|
|
7
|
+
}
|
|
8
|
+
catch {
|
|
9
|
+
return null;
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
// User-role message items Codex injects itself (environment context, AGENTS.md
|
|
13
|
+
// instructions, permission notes) — never typed by the human.
|
|
14
|
+
const INJECTED_PREFIXES = [
|
|
15
|
+
"<environment_context>",
|
|
16
|
+
"<user_instructions>",
|
|
17
|
+
"<permissions",
|
|
18
|
+
"<turn_context>",
|
|
19
|
+
"<ide_context>",
|
|
20
|
+
];
|
|
21
|
+
// Text of a Responses-API message item: `input_text` parts (user) and
|
|
22
|
+
// `output_text` parts (assistant); other part kinds (images, refusals) are
|
|
23
|
+
// not conversation text.
|
|
24
|
+
const textOf = (content) => {
|
|
25
|
+
if (!Array.isArray(content))
|
|
26
|
+
return "";
|
|
27
|
+
return content
|
|
28
|
+
.filter((p) => p !== null &&
|
|
29
|
+
typeof p === "object" &&
|
|
30
|
+
(p.type === "input_text" ||
|
|
31
|
+
p.type === "output_text") &&
|
|
32
|
+
typeof p.text === "string")
|
|
33
|
+
.map((p) => p.text)
|
|
34
|
+
.join("\n");
|
|
35
|
+
};
|
|
36
|
+
const messageFrom = (item) => {
|
|
37
|
+
if (item.type !== "message")
|
|
38
|
+
return null;
|
|
39
|
+
const role = item.role;
|
|
40
|
+
if (role !== "user" && role !== "assistant")
|
|
41
|
+
return null; // skip system
|
|
42
|
+
const text = textOf(item.content);
|
|
43
|
+
if (role === "user" && INJECTED_PREFIXES.some((p) => text.startsWith(p)))
|
|
44
|
+
return null;
|
|
45
|
+
return { role, text };
|
|
46
|
+
};
|
|
47
|
+
// Parse one Codex CLI rollout file (~/.codex/sessions/YYYY/MM/DD/
|
|
48
|
+
// rollout-<date>-<uuid>.jsonl) into the normalized transcript shape. Only
|
|
49
|
+
// `session_meta` / `turn_context` / `response_item` lines matter — `event_msg`
|
|
50
|
+
// lines duplicate the same content as a UI stream, so they are skipped to
|
|
51
|
+
// avoid double-importing every message. Pre-envelope rollouts (bare
|
|
52
|
+
// ResponseItem objects without {timestamp,type,payload}) are handled too.
|
|
53
|
+
// Tolerant by design: unknown types and malformed lines are skipped.
|
|
54
|
+
const parseCodexTranscript = (lines, fallbackSessionId) => {
|
|
55
|
+
const parsed = lines.map(parseLine).filter((e) => e !== null);
|
|
56
|
+
const result = {
|
|
57
|
+
sessionId: undefined,
|
|
58
|
+
cwd: undefined,
|
|
59
|
+
branch: undefined,
|
|
60
|
+
model: undefined,
|
|
61
|
+
messages: [],
|
|
62
|
+
};
|
|
63
|
+
for (const line of parsed) {
|
|
64
|
+
const payload = line.payload !== null && typeof line.payload === "object"
|
|
65
|
+
? line.payload
|
|
66
|
+
: null;
|
|
67
|
+
if (line.type === "session_meta" && payload) {
|
|
68
|
+
const git = payload.git !== null && typeof payload.git === "object"
|
|
69
|
+
? payload.git
|
|
70
|
+
: null;
|
|
71
|
+
result.sessionId ??=
|
|
72
|
+
(typeof payload.id === "string" ? payload.id : undefined) ??
|
|
73
|
+
(typeof payload.session_id === "string"
|
|
74
|
+
? payload.session_id
|
|
75
|
+
: undefined);
|
|
76
|
+
result.cwd ??= typeof payload.cwd === "string" ? payload.cwd : undefined;
|
|
77
|
+
result.branch ??=
|
|
78
|
+
git && typeof git.branch === "string" ? git.branch : undefined;
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
if (line.type === "turn_context" && payload) {
|
|
82
|
+
result.cwd ??= typeof payload.cwd === "string" ? payload.cwd : undefined;
|
|
83
|
+
// Latest turn_context wins: the model can change mid-session.
|
|
84
|
+
if (typeof payload.model === "string")
|
|
85
|
+
result.model = payload.model;
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
// Envelope form (current) or a bare pre-envelope ResponseItem (2025-era
|
|
89
|
+
// rollouts wrote items without the {timestamp,type,payload} wrapper).
|
|
90
|
+
const item = line.type === "response_item" && payload
|
|
91
|
+
? payload
|
|
92
|
+
: payload === null && line.type === "message"
|
|
93
|
+
? line
|
|
94
|
+
: null;
|
|
95
|
+
const message = item ? messageFrom(item) : null;
|
|
96
|
+
if (message)
|
|
97
|
+
result.messages.push(message);
|
|
98
|
+
}
|
|
99
|
+
if (result.messages.every((m) => m.text.trim() === ""))
|
|
100
|
+
return null;
|
|
101
|
+
return {
|
|
102
|
+
sessionId: result.sessionId ?? fallbackSessionId,
|
|
103
|
+
agent: "codex",
|
|
104
|
+
cwd: result.cwd,
|
|
105
|
+
branch: result.branch,
|
|
106
|
+
model: result.model,
|
|
107
|
+
messages: result.messages,
|
|
108
|
+
};
|
|
109
|
+
};
|
|
110
|
+
export { parseCodexTranscript };
|
|
111
|
+
//# sourceMappingURL=parse-codex-transcript.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse-codex-transcript.js","sourceRoot":"","sources":["../../src/_utils/parse-codex-transcript.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { type CliError } from "./cli-error.js";
|
|
2
|
+
import { type Result } from "./result.js";
|
|
3
|
+
import type { ParsedTranscript } from "./transcript-turns.js";
|
|
4
|
+
declare const parseCursorDb: (dbPath: string) => Promise<Result<ParsedTranscript[], CliError>>;
|
|
5
|
+
export { parseCursorDb };
|