@koda-sl/baker-bridge 0.143.0-dev.d167daeeb → 0.143.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 +13 -12
- package/dist/hono/agent.d.ts.map +1 -1
- package/dist/hono/agent.js +0 -3
- package/dist/hono/agent.js.map +1 -1
- package/dist/hono/bridge-job.d.ts +0 -16
- package/dist/hono/bridge-job.d.ts.map +1 -1
- package/dist/hono/bridge-job.js +20 -65
- package/dist/hono/bridge-job.js.map +1 -1
- package/dist/hono/bridge-job.test.js +63 -31
- package/dist/hono/bridge-job.test.js.map +1 -1
- package/dist/hono/publish-handoff.d.ts +5 -53
- package/dist/hono/publish-handoff.d.ts.map +1 -1
- package/dist/hono/publish-handoff.js +21 -194
- package/dist/hono/publish-handoff.js.map +1 -1
- package/dist/hono/publish-handoff.test.js +21 -54
- package/dist/hono/publish-handoff.test.js.map +1 -1
- package/dist/hono/runtime-files.d.ts +0 -1
- package/dist/hono/runtime-files.d.ts.map +1 -1
- package/dist/hono/runtime-files.js +0 -1
- package/dist/hono/runtime-files.js.map +1 -1
- package/dist/hono/turn-events.d.ts +1 -1
- package/dist/hono/turn-events.d.ts.map +1 -1
- package/dist/hono/turn-events.js.map +1 -1
- package/dist/hono/types.d.ts +2 -0
- package/dist/hono/types.d.ts.map +1 -1
- package/dist/review/evidence-block.d.ts.map +1 -1
- package/dist/review/evidence-block.js +3 -1
- package/dist/review/evidence-block.js.map +1 -1
- package/dist/review/evidence-block.test.js +33 -1
- package/dist/review/evidence-block.test.js.map +1 -1
- package/dist/review/evidence.d.ts +3 -0
- package/dist/review/evidence.d.ts.map +1 -1
- package/dist/review/evidence.js +27 -11
- package/dist/review/evidence.js.map +1 -1
- package/dist/review/evidence.test.d.ts +2 -0
- package/dist/review/evidence.test.d.ts.map +1 -0
- package/dist/review/evidence.test.js +94 -0
- package/dist/review/evidence.test.js.map +1 -0
- package/dist/review/transcripts.d.ts +29 -6
- package/dist/review/transcripts.d.ts.map +1 -1
- package/dist/review/transcripts.js +100 -18
- package/dist/review/transcripts.js.map +1 -1
- package/dist/review/transcripts.test.js +37 -0
- package/dist/review/transcripts.test.js.map +1 -1
- package/package.json +1 -1
|
@@ -9,6 +9,7 @@ function report(overrides = {}) {
|
|
|
9
9
|
{
|
|
10
10
|
threadId: "thread-1",
|
|
11
11
|
sessionIds: ["sess-1"],
|
|
12
|
+
sessionIdsWithoutTranscript: [],
|
|
12
13
|
files: ["/home/u/.claude/projects/p/sess-1.jsonl"],
|
|
13
14
|
subagentFiles: ["/home/u/.claude/projects/p/sess-1/subagents/a.jsonl"],
|
|
14
15
|
},
|
|
@@ -56,7 +57,16 @@ describe("renderEvidenceBlock", () => {
|
|
|
56
57
|
digestDir: "/tmp/d",
|
|
57
58
|
paths,
|
|
58
59
|
evidence: report({
|
|
59
|
-
threads: [
|
|
60
|
+
threads: [
|
|
61
|
+
{
|
|
62
|
+
threadId: "t2",
|
|
63
|
+
sessionIds: [],
|
|
64
|
+
sessionIdsWithoutTranscript: [],
|
|
65
|
+
files: [],
|
|
66
|
+
subagentFiles: [],
|
|
67
|
+
missing: "no_session_file",
|
|
68
|
+
},
|
|
69
|
+
],
|
|
60
70
|
transcriptsFound: 0,
|
|
61
71
|
transcriptsMissing: 1,
|
|
62
72
|
}),
|
|
@@ -66,6 +76,28 @@ describe("renderEvidenceBlock", () => {
|
|
|
66
76
|
expect(block).toContain("t2: **missing**");
|
|
67
77
|
expect(block).toContain("no session file");
|
|
68
78
|
});
|
|
79
|
+
it("names a session the thread ran under whose transcript is gone, beside the ones it read", () => {
|
|
80
|
+
const block = renderEvidenceBlock({
|
|
81
|
+
digestDir: "/tmp/d",
|
|
82
|
+
paths,
|
|
83
|
+
evidence: report({
|
|
84
|
+
threads: [
|
|
85
|
+
{
|
|
86
|
+
threadId: "thread-1",
|
|
87
|
+
sessionIds: ["sess-0", "sess-1"],
|
|
88
|
+
sessionIdsWithoutTranscript: ["sess-0"],
|
|
89
|
+
files: ["/home/u/.claude/projects/p/sess-1.jsonl"],
|
|
90
|
+
subagentFiles: [],
|
|
91
|
+
},
|
|
92
|
+
],
|
|
93
|
+
transcriptsMissing: 1,
|
|
94
|
+
}),
|
|
95
|
+
chatId: "chat_1",
|
|
96
|
+
threadIds: ["thread-1"],
|
|
97
|
+
});
|
|
98
|
+
expect(block).toContain("/home/u/.claude/projects/p/sess-1.jsonl");
|
|
99
|
+
expect(block).toContain("no transcript for session sess-0");
|
|
100
|
+
});
|
|
69
101
|
it("puts the digest before the raw transcript in the reading order", () => {
|
|
70
102
|
// Starting on the JSONL spends the whole context arriving at numbers the
|
|
71
103
|
// digest already has — and getting them wrong on the way.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"evidence-block.test.js","sourceRoot":"","sources":["../../src/review/evidence-block.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAE9C,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAE1D,MAAM,KAAK,GAAG,WAAW,CAAC,YAAY,CAAC,CAAC;AAExC,SAAS,MAAM,CAAC,SAAS,GAA4B,EAAE;IACrD,OAAO;QACL,WAAW,EAAE,0BAA0B;QACvC,OAAO,EAAE;YACP;gBACE,QAAQ,EAAE,UAAU;gBACpB,UAAU,EAAE,CAAC,QAAQ,CAAC;gBACtB,KAAK,EAAE,CAAC,yCAAyC,CAAC;gBAClD,aAAa,EAAE,CAAC,qDAAqD,CAAC;aACvE;SACF;QACD,gBAAgB,EAAE,CAAC;QACnB,kBAAkB,EAAE,CAAC;QACrB,eAAe,EAAE,IAAI;QACrB,iBAAiB,EAAE,IAAI;QACvB,kBAAkB,EAAE,IAAI;QACxB,mBAAmB,EAAE,IAAI;QACzB,oBAAoB,EAAE,IAAI;QAC1B,aAAa,EAAE,IAAI;QACnB,cAAc,EAAE,EAAE;QAClB,GAAG,SAAS;KACb,CAAC;AACJ,CAAC;AAED,QAAQ,CAAC,qBAAqB,EAAE,GAAG,EAAE;IACnC,EAAE,CAAC,+CAA+C,EAAE,GAAG,EAAE;QACvD,MAAM,KAAK,GAAG,mBAAmB,CAAC;YAChC,SAAS,EAAE,0BAA0B;YACrC,KAAK;YACL,QAAQ,EAAE,MAAM,EAAE;YAClB,MAAM,EAAE,QAAQ;YAChB,SAAS,EAAE,CAAC,UAAU,CAAC;SACxB,CAAC,CAAC;QACH,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,yCAAyC,CAAC,CAAC;QACnE,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,yBAAyB,CAAC,CAAC;IACrD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4EAA4E,EAAE,GAAG,EAAE;QACpF,2EAA2E;QAC3E,+DAA+D;QAC/D,MAAM,KAAK,GAAG,mBAAmB,CAAC;YAChC,SAAS,EAAE,QAAQ;YACnB,KAAK;YACL,QAAQ,EAAE,MAAM,CAAC,EAAE,eAAe,EAAE,KAAK,EAAE,oBAAoB,EAAE,KAAK,EAAE,CAAC;YACzE,MAAM,EAAE,QAAQ;YAChB,SAAS,EAAE,CAAC,UAAU,CAAC;SACxB,CAAC,CAAC;QACH,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,6BAA6B,CAAC,CAAC;QACvD,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,yBAAyB,CAAC,CAAC;QACnD,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,mBAAmB,CAAC,CAAC;IAC/C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gFAAgF,EAAE,GAAG,EAAE;QACxF,MAAM,KAAK,GAAG,mBAAmB,CAAC;YAChC,SAAS,EAAE,QAAQ;YACnB,KAAK;YACL,QAAQ,EAAE,MAAM,CAAC;gBACf,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"evidence-block.test.js","sourceRoot":"","sources":["../../src/review/evidence-block.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAE9C,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAE1D,MAAM,KAAK,GAAG,WAAW,CAAC,YAAY,CAAC,CAAC;AAExC,SAAS,MAAM,CAAC,SAAS,GAA4B,EAAE;IACrD,OAAO;QACL,WAAW,EAAE,0BAA0B;QACvC,OAAO,EAAE;YACP;gBACE,QAAQ,EAAE,UAAU;gBACpB,UAAU,EAAE,CAAC,QAAQ,CAAC;gBACtB,2BAA2B,EAAE,EAAE;gBAC/B,KAAK,EAAE,CAAC,yCAAyC,CAAC;gBAClD,aAAa,EAAE,CAAC,qDAAqD,CAAC;aACvE;SACF;QACD,gBAAgB,EAAE,CAAC;QACnB,kBAAkB,EAAE,CAAC;QACrB,eAAe,EAAE,IAAI;QACrB,iBAAiB,EAAE,IAAI;QACvB,kBAAkB,EAAE,IAAI;QACxB,mBAAmB,EAAE,IAAI;QACzB,oBAAoB,EAAE,IAAI;QAC1B,aAAa,EAAE,IAAI;QACnB,cAAc,EAAE,EAAE;QAClB,GAAG,SAAS;KACb,CAAC;AACJ,CAAC;AAED,QAAQ,CAAC,qBAAqB,EAAE,GAAG,EAAE;IACnC,EAAE,CAAC,+CAA+C,EAAE,GAAG,EAAE;QACvD,MAAM,KAAK,GAAG,mBAAmB,CAAC;YAChC,SAAS,EAAE,0BAA0B;YACrC,KAAK;YACL,QAAQ,EAAE,MAAM,EAAE;YAClB,MAAM,EAAE,QAAQ;YAChB,SAAS,EAAE,CAAC,UAAU,CAAC;SACxB,CAAC,CAAC;QACH,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,yCAAyC,CAAC,CAAC;QACnE,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,yBAAyB,CAAC,CAAC;IACrD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4EAA4E,EAAE,GAAG,EAAE;QACpF,2EAA2E;QAC3E,+DAA+D;QAC/D,MAAM,KAAK,GAAG,mBAAmB,CAAC;YAChC,SAAS,EAAE,QAAQ;YACnB,KAAK;YACL,QAAQ,EAAE,MAAM,CAAC,EAAE,eAAe,EAAE,KAAK,EAAE,oBAAoB,EAAE,KAAK,EAAE,CAAC;YACzE,MAAM,EAAE,QAAQ;YAChB,SAAS,EAAE,CAAC,UAAU,CAAC;SACxB,CAAC,CAAC;QACH,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,6BAA6B,CAAC,CAAC;QACvD,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,yBAAyB,CAAC,CAAC;QACnD,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,mBAAmB,CAAC,CAAC;IAC/C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gFAAgF,EAAE,GAAG,EAAE;QACxF,MAAM,KAAK,GAAG,mBAAmB,CAAC;YAChC,SAAS,EAAE,QAAQ;YACnB,KAAK;YACL,QAAQ,EAAE,MAAM,CAAC;gBACf,OAAO,EAAE;oBACP;wBACE,QAAQ,EAAE,IAAI;wBACd,UAAU,EAAE,EAAE;wBACd,2BAA2B,EAAE,EAAE;wBAC/B,KAAK,EAAE,EAAE;wBACT,aAAa,EAAE,EAAE;wBACjB,OAAO,EAAE,iBAAiB;qBAC3B;iBACF;gBACD,gBAAgB,EAAE,CAAC;gBACnB,kBAAkB,EAAE,CAAC;aACtB,CAAC;YACF,MAAM,EAAE,QAAQ;YAChB,SAAS,EAAE,CAAC,IAAI,CAAC;SAClB,CAAC,CAAC;QACH,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,iBAAiB,CAAC,CAAC;QAC3C,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,iBAAiB,CAAC,CAAC;IAC7C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wFAAwF,EAAE,GAAG,EAAE;QAChG,MAAM,KAAK,GAAG,mBAAmB,CAAC;YAChC,SAAS,EAAE,QAAQ;YACnB,KAAK;YACL,QAAQ,EAAE,MAAM,CAAC;gBACf,OAAO,EAAE;oBACP;wBACE,QAAQ,EAAE,UAAU;wBACpB,UAAU,EAAE,CAAC,QAAQ,EAAE,QAAQ,CAAC;wBAChC,2BAA2B,EAAE,CAAC,QAAQ,CAAC;wBACvC,KAAK,EAAE,CAAC,yCAAyC,CAAC;wBAClD,aAAa,EAAE,EAAE;qBAClB;iBACF;gBACD,kBAAkB,EAAE,CAAC;aACtB,CAAC;YACF,MAAM,EAAE,QAAQ;YAChB,SAAS,EAAE,CAAC,UAAU,CAAC;SACxB,CAAC,CAAC;QACH,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,yCAAyC,CAAC,CAAC;QACnE,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,kCAAkC,CAAC,CAAC;IAC9D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gEAAgE,EAAE,GAAG,EAAE;QACxE,yEAAyE;QACzE,0DAA0D;QAC1D,MAAM,KAAK,GAAG,mBAAmB,CAAC;YAChC,SAAS,EAAE,QAAQ;YACnB,KAAK;YACL,QAAQ,EAAE,MAAM,EAAE;YAClB,MAAM,EAAE,QAAQ;YAChB,SAAS,EAAE,CAAC,UAAU,CAAC;SACxB,CAAC,CAAC;QACH,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC,CAAC,YAAY,CAAC,KAAK,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC,CAAC;IACxF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oEAAoE,EAAE,GAAG,EAAE;QAC5E,4EAA4E;QAC5E,4EAA4E;QAC5E,MAAM,KAAK,GAAG,mBAAmB,CAAC;YAChC,SAAS,EAAE,QAAQ;YACnB,KAAK;YACL,QAAQ,EAAE,MAAM,EAAE;YAClB,MAAM,EAAE,QAAQ;YAChB,SAAS,EAAE,CAAC,UAAU,CAAC;SACxB,CAAC,CAAC;QACH,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,wBAAwB,CAAC,CAAC;QAClD,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,kBAAkB,CAAC,CAAC;IAC9C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0EAA0E,EAAE,GAAG,EAAE;QAClF,iEAAiE;QACjE,0EAA0E;QAC1E,uDAAuD;QACvD,MAAM,KAAK,GAAG,mBAAmB,CAAC;YAChC,SAAS,EAAE,QAAQ;YACnB,KAAK;YACL,QAAQ,EAAE,MAAM,EAAE;YAClB,MAAM,EAAE,QAAQ;YAChB,SAAS,EAAE,CAAC,UAAU,CAAC;SACxB,CAAC,CAAC;QACH,MAAM,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,gBAAgB,CAAC,CAAC;IAChD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -16,12 +16,15 @@ export type EvidenceReport = {
|
|
|
16
16
|
threads: {
|
|
17
17
|
threadId: string;
|
|
18
18
|
sessionIds: string[];
|
|
19
|
+
/** Session ids the thread ran under whose transcript is not on disk. */
|
|
20
|
+
sessionIdsWithoutTranscript: string[];
|
|
19
21
|
files: string[];
|
|
20
22
|
subagentFiles: string[];
|
|
21
23
|
/** Present when this thread's transcript could not be read, and why. */
|
|
22
24
|
missing?: string;
|
|
23
25
|
}[];
|
|
24
26
|
transcriptsFound: number;
|
|
27
|
+
/** Threads with no transcript at all, plus every session a thread ran under whose transcript is gone. */
|
|
25
28
|
transcriptsMissing: number;
|
|
26
29
|
debugLogPresent: boolean;
|
|
27
30
|
turnEventsPresent: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"evidence.d.ts","sourceRoot":"","sources":["../../src/review/evidence.ts"],"names":[],"mappings":"AAIA,OAAO,EAGL,KAAK,aAAa,EAalB,KAAK,gBAAgB,EAErB,KAAK,aAAa,EAEnB,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAGxD;;;;;;;;;GASG;AAEH,eAAO,MAAM,UAAU,6BAA6B,CAAC;AAKrD,MAAM,MAAM,cAAc,GAAG;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE;QACP,QAAQ,EAAE,MAAM,CAAC;QACjB,UAAU,EAAE,MAAM,EAAE,CAAC;QACrB,KAAK,EAAE,MAAM,EAAE,CAAC;QAChB,aAAa,EAAE,MAAM,EAAE,CAAC;QACxB,wEAAwE;QACxE,OAAO,CAAC,EAAE,MAAM,CAAC;KAClB,EAAE,CAAC;IACJ,gBAAgB,EAAE,MAAM,CAAC;IACzB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,eAAe,EAAE,OAAO,CAAC;IACzB,iBAAiB,EAAE,OAAO,CAAC;IAC3B,kBAAkB,EAAE,OAAO,CAAC;IAC5B,mBAAmB,EAAE,OAAO,CAAC;IAC7B,oBAAoB,EAAE,OAAO,CAAC;IAC9B,aAAa,EAAE,OAAO,CAAC;IACvB,qDAAqD;IACrD,cAAc,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CACnD,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,gBAAgB,CAAC;IACzB,GAAG,EAAE,aAAa,EAAE,CAAC;IACrB,MAAM,EAAE,aAAa,GAAG,IAAI,CAAC;IAC7B,QAAQ,EAAE,cAAc,CAAC;IACzB,kEAAkE;IAClE,QAAQ,EAAE,aAAa,EAAE,CAAC;CAC3B,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE;IACpC,MAAM,EAAE,gBAAgB,CAAC;IACzB,GAAG,EAAE,aAAa,EAAE,CAAC;IACrB,MAAM,EAAE,aAAa,GAAG,IAAI,CAAC;IAC7B,QAAQ,EAAE,cAAc,CAAC;CAC1B,GAAG,aAAa,EAAE,CAiBlB;AAkBD,MAAM,MAAM,WAAW,GAAG;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,wBAAgB,WAAW,CAAC,WAAW,EAAE,MAAM,GAAG,WAAW,CAU5D;AA+
|
|
1
|
+
{"version":3,"file":"evidence.d.ts","sourceRoot":"","sources":["../../src/review/evidence.ts"],"names":[],"mappings":"AAIA,OAAO,EAGL,KAAK,aAAa,EAalB,KAAK,gBAAgB,EAErB,KAAK,aAAa,EAEnB,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAGxD;;;;;;;;;GASG;AAEH,eAAO,MAAM,UAAU,6BAA6B,CAAC;AAKrD,MAAM,MAAM,cAAc,GAAG;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE;QACP,QAAQ,EAAE,MAAM,CAAC;QACjB,UAAU,EAAE,MAAM,EAAE,CAAC;QACrB,wEAAwE;QACxE,2BAA2B,EAAE,MAAM,EAAE,CAAC;QACtC,KAAK,EAAE,MAAM,EAAE,CAAC;QAChB,aAAa,EAAE,MAAM,EAAE,CAAC;QACxB,wEAAwE;QACxE,OAAO,CAAC,EAAE,MAAM,CAAC;KAClB,EAAE,CAAC;IACJ,gBAAgB,EAAE,MAAM,CAAC;IACzB,yGAAyG;IACzG,kBAAkB,EAAE,MAAM,CAAC;IAC3B,eAAe,EAAE,OAAO,CAAC;IACzB,iBAAiB,EAAE,OAAO,CAAC;IAC3B,kBAAkB,EAAE,OAAO,CAAC;IAC5B,mBAAmB,EAAE,OAAO,CAAC;IAC7B,oBAAoB,EAAE,OAAO,CAAC;IAC9B,aAAa,EAAE,OAAO,CAAC;IACvB,qDAAqD;IACrD,cAAc,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CACnD,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,gBAAgB,CAAC;IACzB,GAAG,EAAE,aAAa,EAAE,CAAC;IACrB,MAAM,EAAE,aAAa,GAAG,IAAI,CAAC;IAC7B,QAAQ,EAAE,cAAc,CAAC;IACzB,kEAAkE;IAClE,QAAQ,EAAE,aAAa,EAAE,CAAC;CAC3B,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE;IACpC,MAAM,EAAE,gBAAgB,CAAC;IACzB,GAAG,EAAE,aAAa,EAAE,CAAC;IACrB,MAAM,EAAE,aAAa,GAAG,IAAI,CAAC;IAC7B,QAAQ,EAAE,cAAc,CAAC;CAC1B,GAAG,aAAa,EAAE,CAiBlB;AAkBD,MAAM,MAAM,WAAW,GAAG;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,wBAAgB,WAAW,CAAC,WAAW,EAAE,MAAM,GAAG,WAAW,CAU5D;AA+ED;;;;;;GAMG;AACH,wBAAsB,iBAAiB,CACrC,SAAS,EAAE,SAAS,MAAM,EAAE,EAC5B,OAAO,GAAE;IAAE,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAO,GACnD,OAAO,CAAC,YAAY,CAAC,CA8CvB"}
|
package/dist/review/evidence.js
CHANGED
|
@@ -85,25 +85,32 @@ async function readTranscriptLines(transcripts) {
|
|
|
85
85
|
const skippedForSize = [];
|
|
86
86
|
const lines = [];
|
|
87
87
|
for (const thread of transcripts) {
|
|
88
|
+
const seenUuids = new Set();
|
|
88
89
|
// Grouped by thread rather than interleaved by clock: two threads are two
|
|
89
90
|
// conversations, and a turn stream that alternates between them reads as
|
|
90
91
|
// one conversation nobody had. Each line is stamped instead, so a finding
|
|
91
92
|
// can name the thread it happened in.
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
//
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
93
|
+
//
|
|
94
|
+
// Within a thread, session by session, each followed by the subagents spawned in it: the
|
|
95
|
+
// digest charges a line to the turn open when it is read, so a subagent read
|
|
96
|
+
// after every session would be charged to the thread's last turn.
|
|
97
|
+
for (const session of thread.sessions) {
|
|
98
|
+
if (session.file !== null) {
|
|
99
|
+
await absorbFile(session.file, { threadId: thread.threadId }, lines, skippedForSize, seenUuids);
|
|
100
|
+
}
|
|
101
|
+
// A subagent's own file records its prompt as an ordinary `user` line — the
|
|
102
|
+
// `isSidechain` flag lives only in the parent's copy. Taken at face value
|
|
103
|
+
// every fan-out opens a turn the marketer never took, and every per-turn
|
|
104
|
+
// number is then divided by a turn count that is wrong.
|
|
105
|
+
for (const file of session.subagentFiles) {
|
|
106
|
+
await absorbFile(file, { threadId: thread.threadId, isSubagent: true }, lines, skippedForSize, seenUuids);
|
|
107
|
+
}
|
|
101
108
|
}
|
|
102
109
|
}
|
|
103
110
|
return { lines, skippedForSize };
|
|
104
111
|
}
|
|
105
112
|
/** Read one transcript, stamp every line with where it came from, or record why not. */
|
|
106
|
-
async function absorbFile(file, stamp, into, skippedForSize) {
|
|
113
|
+
async function absorbFile(file, stamp, into, skippedForSize, seenUuids) {
|
|
107
114
|
const bytes = await byteSize(file);
|
|
108
115
|
if (bytes !== null && bytes > MAX_TRANSCRIPT_BYTES) {
|
|
109
116
|
skippedForSize.push({ path: file, bytes });
|
|
@@ -114,6 +121,14 @@ async function absorbFile(file, stamp, into, skippedForSize) {
|
|
|
114
121
|
return;
|
|
115
122
|
}
|
|
116
123
|
for (const line of parseTranscript(body)) {
|
|
124
|
+
// A fork starts with a copy of the conversation it forked from, under the
|
|
125
|
+
// same uuids: the first file to carry a line is the one that counts it.
|
|
126
|
+
if (line.uuid !== undefined) {
|
|
127
|
+
if (seenUuids.has(line.uuid)) {
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
130
|
+
seenUuids.add(line.uuid);
|
|
131
|
+
}
|
|
117
132
|
into.push({ ...line, ...stamp });
|
|
118
133
|
}
|
|
119
134
|
}
|
|
@@ -149,12 +164,13 @@ export async function buildReviewDigest(threadIds, options = {}) {
|
|
|
149
164
|
threads: transcripts.map((thread) => ({
|
|
150
165
|
threadId: thread.threadId,
|
|
151
166
|
sessionIds: thread.sessionIds,
|
|
167
|
+
sessionIdsWithoutTranscript: thread.sessionIdsWithoutTranscript,
|
|
152
168
|
files: thread.files,
|
|
153
169
|
subagentFiles: thread.subagentFiles,
|
|
154
170
|
...(thread.missing === undefined ? {} : { missing: thread.missing }),
|
|
155
171
|
})),
|
|
156
172
|
transcriptsFound: transcripts.filter((thread) => thread.files.length > 0).length,
|
|
157
|
-
transcriptsMissing: transcripts.
|
|
173
|
+
transcriptsMissing: transcripts.reduce((missing, thread) => missing + (thread.missing === "no_session_file" ? 1 : thread.sessionIdsWithoutTranscript.length), 0),
|
|
158
174
|
debugLogPresent: debugBody !== null,
|
|
159
175
|
turnEventsPresent: (await readIfPresent(paths.turnEvents)) !== null,
|
|
160
176
|
relayErrorsPresent: (await readIfPresent(paths.relayErrors)) !== null,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"evidence.js","sourceRoot":"","sources":["../../src/review/evidence.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACpE,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAC9D,OAAO,EACL,cAAc,EACd,qBAAqB,EAGrB,UAAU,EACV,eAAe,EACf,SAAS,EACT,cAAc,EACd,YAAY,EACZ,WAAW,EACX,WAAW,EACX,WAAW,EACX,gBAAgB,EAChB,YAAY,EACZ,eAAe,GAKhB,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,wBAAwB,EAA0B,MAAM,kBAAkB,CAAC;AAEpF;;;;;;;;;GASG;AAEH,MAAM,CAAC,MAAM,UAAU,GAAG,0BAA0B,CAAC;AAErD,uEAAuE;AACvE,MAAM,oBAAoB,GAAG,GAAG,GAAG,IAAI,GAAG,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"evidence.js","sourceRoot":"","sources":["../../src/review/evidence.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACpE,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAC9D,OAAO,EACL,cAAc,EACd,qBAAqB,EAGrB,UAAU,EACV,eAAe,EACf,SAAS,EACT,cAAc,EACd,YAAY,EACZ,WAAW,EACX,WAAW,EACX,WAAW,EACX,gBAAgB,EAChB,YAAY,EACZ,eAAe,GAKhB,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,wBAAwB,EAA0B,MAAM,kBAAkB,CAAC;AAEpF;;;;;;;;;GASG;AAEH,MAAM,CAAC,MAAM,UAAU,GAAG,0BAA0B,CAAC;AAErD,uEAAuE;AACvE,MAAM,oBAAoB,GAAG,GAAG,GAAG,IAAI,GAAG,IAAI,CAAC;AAqC/C;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,cAAc,CAAC,KAK9B;IACC,OAAO;QACL,EAAE,IAAI,EAAE,aAAa,EAAE,OAAO,EAAE,cAAc,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE;QAC9D,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,WAAW,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE;QACxD,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,WAAW,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE;QACxD,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,YAAY,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE;QAC1D,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,WAAW,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE;QACxD,EAAE,IAAI,EAAE,gBAAgB,EAAE,OAAO,EAAE,gBAAgB,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE;QACnE,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE;QACjD,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,YAAY,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE;QAC1D,EAAE,IAAI,EAAE,eAAe,EAAE,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE;QAC3E;YACE,IAAI,EAAE,YAAY;YAClB,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,QAAQ,EAAE,KAAK,CAAC,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;SACnG;QACD,EAAE,IAAI,EAAE,YAAY,EAAE,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,MAAM,CAAC,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE;KACjF,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,aAAa,CAAC,IAAY;IACvC,IAAI,CAAC;QACH,OAAO,MAAM,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IACvC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,KAAK,UAAU,QAAQ,CAAC,IAAY;IAClC,IAAI,CAAC;QACH,OAAO,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;IACjC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAWD,MAAM,UAAU,WAAW,CAAC,WAAmB;IAC7C,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,QAAQ,CAAC,CAAC;IAC5C,OAAO;QACL,QAAQ,EAAE,4BAA4B;QACtC,UAAU,EAAE,IAAI,CAAC,SAAS,EAAE,mBAAmB,CAAC;QAChD,WAAW,EAAE,IAAI,CAAC,SAAS,EAAE,oBAAoB,CAAC;QAClD,YAAY,EAAE,IAAI,CAAC,WAAW,EAAE,mCAAmC,CAAC;QACpE,aAAa,EAAE,IAAI,CAAC,WAAW,EAAE,qCAAqC,CAAC;QACvE,MAAM,EAAE,IAAI,CAAC,WAAW,EAAE,0BAA0B,CAAC;KACtD,CAAC;AACJ,CAAC;AAED;;;;;;GAMG;AACH,KAAK,UAAU,mBAAmB,CAChC,WAAyC;IAEzC,MAAM,cAAc,GAAqC,EAAE,CAAC;IAC5D,MAAM,KAAK,GAAqB,EAAE,CAAC;IACnC,KAAK,MAAM,MAAM,IAAI,WAAW,EAAE,CAAC;QACjC,MAAM,SAAS,GAAG,IAAI,GAAG,EAAU,CAAC;QACpC,0EAA0E;QAC1E,yEAAyE;QACzE,0EAA0E;QAC1E,sCAAsC;QACtC,EAAE;QACF,yFAAyF;QACzF,6EAA6E;QAC7E,kEAAkE;QAClE,KAAK,MAAM,OAAO,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;YACtC,IAAI,OAAO,CAAC,IAAI,KAAK,IAAI,EAAE,CAAC;gBAC1B,MAAM,UAAU,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,EAAE,KAAK,EAAE,cAAc,EAAE,SAAS,CAAC,CAAC;YAClG,CAAC;YACD,4EAA4E;YAC5E,0EAA0E;YAC1E,yEAAyE;YACzE,wDAAwD;YACxD,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,aAAa,EAAE,CAAC;gBACzC,MAAM,UAAU,CAAC,IAAI,EAAE,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,UAAU,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,cAAc,EAAE,SAAS,CAAC,CAAC;YAC5G,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,cAAc,EAAE,CAAC;AACnC,CAAC;AAED,wFAAwF;AACxF,KAAK,UAAU,UAAU,CACvB,IAAY,EACZ,KAAiD,EACjD,IAAsB,EACtB,cAAgD,EAChD,SAAsB;IAEtB,MAAM,KAAK,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,CAAC;IACnC,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,GAAG,oBAAoB,EAAE,CAAC;QACnD,cAAc,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;QAC3C,OAAO;IACT,CAAC;IACD,MAAM,IAAI,GAAG,MAAM,aAAa,CAAC,IAAI,CAAC,CAAC;IACvC,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,OAAO;IACT,CAAC;IACD,KAAK,MAAM,IAAI,IAAI,eAAe,CAAC,IAAI,CAAC,EAAE,CAAC;QACzC,0EAA0E;QAC1E,wEAAwE;QACxE,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;YAC5B,IAAI,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC7B,SAAS;YACX,CAAC;YACD,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC3B,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,EAAE,GAAG,IAAI,EAAE,GAAG,KAAK,EAAE,CAAC,CAAC;IACnC,CAAC;AACH,CAAC;AAED,2FAA2F;AAC3F,SAAS,iBAAiB,CAAC,IAAY;IACrC,IAAI,CAAC;QACH,OAAO,eAAe,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAkB,CAAC,CAAC;IAC5D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,SAA4B,EAC5B,OAAO,GAA2C,EAAE;IAEpD,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,IAAI,kBAAkB,CAAC,WAAW,EAAE,CAAC;IAC5E,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,UAAU,CAAC;IACtC,MAAM,KAAK,GAAG,WAAW,CAAC,WAAW,CAAC,CAAC;IAEvC,MAAM,WAAW,GAAG,MAAM,wBAAwB,CAAC,SAAS,EAAE,EAAE,WAAW,EAAE,CAAC,CAAC;IAC/E,MAAM,EAAE,KAAK,EAAE,cAAc,EAAE,GAAG,MAAM,mBAAmB,CAAC,WAAW,CAAC,CAAC;IACzE,MAAM,MAAM,GAAG,qBAAqB,CAAC,KAAK,CAAC,CAAC;IAE5C,MAAM,SAAS,GAAG,MAAM,aAAa,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IACtD,MAAM,GAAG,GAAG,SAAS,CAAC,CAAC,CAAC,cAAc,CAAC,UAAU,CAAe,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAEjF,MAAM,WAAW,GAAG,MAAM,aAAa,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;IAC7D,MAAM,MAAM,GAAG,WAAW,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,iBAAiB,CAAC,WAAW,CAAC,CAAC;IAE5E,MAAM,QAAQ,GAAmB;QAC/B,WAAW,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACrC,OAAO,EAAE,WAAW,CAAC,GAAG,CAAC,CAAC,MAAyB,EAAE,EAAE,CAAC,CAAC;YACvD,QAAQ,EAAE,MAAM,CAAC,QAAQ;YACzB,UAAU,EAAE,MAAM,CAAC,UAAU;YAC7B,2BAA2B,EAAE,MAAM,CAAC,2BAA2B;YAC/D,KAAK,EAAE,MAAM,CAAC,KAAK;YACnB,aAAa,EAAE,MAAM,CAAC,aAAa;YACnC,GAAG,CAAC,MAAM,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC;SACrE,CAAC,CAAC;QACH,gBAAgB,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,MAAM;QAChF,kBAAkB,EAAE,WAAW,CAAC,MAAM,CACpC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,CAClB,OAAO,GAAG,CAAC,MAAM,CAAC,OAAO,KAAK,iBAAiB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,2BAA2B,CAAC,MAAM,CAAC,EAClG,CAAC,CACF;QACD,eAAe,EAAE,SAAS,KAAK,IAAI;QACnC,iBAAiB,EAAE,CAAC,MAAM,aAAa,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,KAAK,IAAI;QACnE,kBAAkB,EAAE,CAAC,MAAM,aAAa,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,KAAK,IAAI;QACrE,mBAAmB,EAAE,CAAC,MAAM,aAAa,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,KAAK,IAAI;QACvE,oBAAoB,EAAE,WAAW,KAAK,IAAI;QAC1C,aAAa,EAAE,CAAC,MAAM,aAAa,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,KAAK,IAAI;QAC3D,cAAc;KACf,CAAC;IAEF,MAAM,QAAQ,GAAG,cAAc,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC;IAEnE,MAAM,KAAK,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACtC,MAAM,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,EAAE,OAAO,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;IAE3G,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC;AAC1D,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"evidence.test.d.ts","sourceRoot":"","sources":["../../src/review/evidence.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { mkdirSync, rmSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { afterAll, describe, expect, it, vi } from "vitest";
|
|
4
|
+
import { buildReviewDigest } from "./evidence.js";
|
|
5
|
+
import { projectSlug } from "./transcripts.js";
|
|
6
|
+
// The Session's home is the Runtime's: both the bridge's `~/.baker` and the
|
|
7
|
+
// CLI's `~/.claude/projects` resolve under it.
|
|
8
|
+
const root = vi.hoisted(() => {
|
|
9
|
+
const { mkdtempSync } = require("node:fs");
|
|
10
|
+
const { tmpdir } = require("node:os");
|
|
11
|
+
const { join } = require("node:path");
|
|
12
|
+
return mkdtempSync(join(tmpdir(), "review-evidence-"));
|
|
13
|
+
});
|
|
14
|
+
const bakerHome = join(root, ".baker");
|
|
15
|
+
const projectsRoot = join(root, ".claude", "projects");
|
|
16
|
+
vi.mock("node:os", async () => {
|
|
17
|
+
const actual = await vi.importActual("node:os");
|
|
18
|
+
return { ...actual, homedir: () => root };
|
|
19
|
+
});
|
|
20
|
+
afterAll(() => {
|
|
21
|
+
rmSync(root, { recursive: true, force: true });
|
|
22
|
+
});
|
|
23
|
+
function jsonl(lines) {
|
|
24
|
+
return lines.map((line) => `${JSON.stringify(line)}\n`).join("");
|
|
25
|
+
}
|
|
26
|
+
function userLine(uuid, text) {
|
|
27
|
+
return { type: "user", uuid, message: { role: "user", content: text } };
|
|
28
|
+
}
|
|
29
|
+
function callLine(uuid, id, command) {
|
|
30
|
+
return {
|
|
31
|
+
type: "assistant",
|
|
32
|
+
uuid,
|
|
33
|
+
message: { role: "assistant", content: [{ type: "tool_use", id, name: "Bash", input: { command } }] },
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
function resultLine(uuid, id, content, isError = false) {
|
|
37
|
+
return {
|
|
38
|
+
type: "user",
|
|
39
|
+
uuid,
|
|
40
|
+
message: { role: "user", content: [{ type: "tool_result", tool_use_id: id, content, is_error: isError }] },
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
describe("buildReviewDigest", () => {
|
|
44
|
+
// The shape every chat has: each message forks the session (the fork copies the
|
|
45
|
+
// conversation so far under the same line uuids), `/publish` runs in a session
|
|
46
|
+
// the thread never adopts, and a subagent lives under the id it was spawned in.
|
|
47
|
+
it("reads every session a thread ran under once, publish and earlier subagents included", async () => {
|
|
48
|
+
const projectRoot = join(root, "repo");
|
|
49
|
+
const dir = join(projectsRoot, projectSlug(projectRoot));
|
|
50
|
+
mkdirSync(join(dir, "s-turn1", "subagents"), { recursive: true });
|
|
51
|
+
const turn1 = [
|
|
52
|
+
userLine("u1", "Build the landing"),
|
|
53
|
+
callLine("a1", "b1", "pnpm build"),
|
|
54
|
+
resultLine("r1", "b1", "built"),
|
|
55
|
+
];
|
|
56
|
+
writeFileSync(join(dir, "s-turn1.jsonl"), jsonl(turn1));
|
|
57
|
+
writeFileSync(join(dir, "s-turn1", "subagents", "agent-visual.jsonl"), jsonl([
|
|
58
|
+
userLine("v0", "Check the hero at 390px"),
|
|
59
|
+
callLine("v1", "vb1", "agent-browser help"),
|
|
60
|
+
resultLine("v2", "vb1", "Blocked by guard-agent-browser: use the wrapper", true),
|
|
61
|
+
]));
|
|
62
|
+
writeFileSync(join(dir, "s-publish.jsonl"), jsonl([
|
|
63
|
+
userLine("p0", "/publish"),
|
|
64
|
+
callLine("p1", "pb1", "pnpm verify"),
|
|
65
|
+
resultLine("p2", "pb1", "verify failed", true),
|
|
66
|
+
]));
|
|
67
|
+
writeFileSync(join(dir, "s-turn3.jsonl"), jsonl([...turn1, userLine("u3", "Make the hero blue"), callLine("a3", "b3", "pnpm build")]));
|
|
68
|
+
mkdirSync(join(bakerHome, "sessions"), { recursive: true });
|
|
69
|
+
writeFileSync(join(bakerHome, "sessions", "thread-1.json"), JSON.stringify({ version: 2, sessionId: "s-turn3", updatedAtMs: 3 }));
|
|
70
|
+
writeFileSync(join(bakerHome, "turn-events.jsonl"), jsonl(["s-turn1", "s-publish", "s-turn3", "s-reaped"].map((sessionId, index) => ({
|
|
71
|
+
threadId: "thread-1",
|
|
72
|
+
turnId: `turn-${index}`,
|
|
73
|
+
event: "session",
|
|
74
|
+
detail: { sessionId },
|
|
75
|
+
}))));
|
|
76
|
+
const result = await buildReviewDigest(["thread-1"], { projectRoot, dir: join(root, "digest") });
|
|
77
|
+
expect(result.digest.totals.turns).toBe(3);
|
|
78
|
+
expect(result.digest.toolCalls.map((call) => call.toolUseId).sort()).toEqual(["b1", "b3", "pb1", "vb1"]);
|
|
79
|
+
expect(result.digest.guards.map((guard) => guard.message)).toEqual([
|
|
80
|
+
expect.stringContaining("guard-agent-browser"),
|
|
81
|
+
"verify failed",
|
|
82
|
+
]);
|
|
83
|
+
// A subagent counts toward the turn that spawned it, not the thread's last turn.
|
|
84
|
+
const turnOf = (id) => result.digest.toolCalls.find((call) => call.toolUseId === id)?.turn;
|
|
85
|
+
expect(turnOf("vb1")).toBe(turnOf("b1"));
|
|
86
|
+
expect(result.evidence.threads[0]?.subagentFiles).toEqual([
|
|
87
|
+
join(dir, "s-turn1", "subagents", "agent-visual.jsonl"),
|
|
88
|
+
]);
|
|
89
|
+
// A session the thread ran under whose transcript is gone is missing evidence, said out loud.
|
|
90
|
+
expect(result.evidence.threads[0]?.sessionIdsWithoutTranscript).toEqual(["s-reaped"]);
|
|
91
|
+
expect(result.evidence.transcriptsMissing).toBe(1);
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
//# sourceMappingURL=evidence.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"evidence.test.js","sourceRoot":"","sources":["../../src/review/evidence.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -6,18 +6,41 @@
|
|
|
6
6
|
* this sandbox. That file is append-only, so it survives compaction: a
|
|
7
7
|
* compaction adds a summary line, it never removes one.
|
|
8
8
|
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
9
|
+
* A thread is not one SDK session. Every message resumes the last one as a
|
|
10
|
+
* fork, a stall or a restart forks again, and `/publish` runs in a session of
|
|
11
|
+
* its own the thread never adopts. The bridge records each id a turn runs under
|
|
12
|
+
* as a `session` line in `~/.baker/turn-events.jsonl`; the thread's session file
|
|
13
|
+
* (`~/.baker/sessions/<threadId>.json`) names only the latest. Both are read,
|
|
14
|
+
* and each id maps to `~/.claude/projects/<cwd-slug>/<sessionId>.jsonl` plus the
|
|
15
|
+
* subagent directory beside it — a subagent lives under the id it was spawned
|
|
16
|
+
* in, so reading the latest alone drops every earlier turn's fan-out.
|
|
17
|
+
*
|
|
18
|
+
* A fork copies the conversation so far into its new file under the same line
|
|
19
|
+
* uuids, so the files overlap; the reader dedupes by uuid.
|
|
20
|
+
*
|
|
21
|
+
* Whatever cannot be read is reported rather than skipped: "we could not read
|
|
22
|
+
* this" and "this had no tool calls" must never look the same to the reviewer.
|
|
14
23
|
*/
|
|
15
24
|
/** Claude Code names a project directory after its cwd, with every separator folded to `-`. */
|
|
16
25
|
export declare function projectSlug(cwd: string): string;
|
|
26
|
+
/** One session a thread ran under: its own transcript and the subagents spawned in it. */
|
|
27
|
+
export type SessionTranscripts = {
|
|
28
|
+
sessionId: string;
|
|
29
|
+
/** The session's transcript, or null when it is not on disk. */
|
|
30
|
+
file: string | null;
|
|
31
|
+
subagentFiles: string[];
|
|
32
|
+
};
|
|
17
33
|
export type ThreadTranscripts = {
|
|
18
34
|
threadId: string;
|
|
19
|
-
/**
|
|
35
|
+
/**
|
|
36
|
+
* Per session, in run order. Read in this order so a subagent follows the turn
|
|
37
|
+
* that spawned it, not the thread's last turn.
|
|
38
|
+
*/
|
|
39
|
+
sessions: SessionTranscripts[];
|
|
40
|
+
/** Every session id this thread ran under, in the order it first ran under each. */
|
|
20
41
|
sessionIds: string[];
|
|
42
|
+
/** Session ids the thread ran under whose transcript file is not on disk. */
|
|
43
|
+
sessionIdsWithoutTranscript: string[];
|
|
21
44
|
/** Transcript files that exist on disk. */
|
|
22
45
|
files: string[];
|
|
23
46
|
/** Subagent transcript files, one per fan-out task. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transcripts.d.ts","sourceRoot":"","sources":["../../src/review/transcripts.ts"],"names":[],"mappings":"AAKA
|
|
1
|
+
{"version":3,"file":"transcripts.d.ts","sourceRoot":"","sources":["../../src/review/transcripts.ts"],"names":[],"mappings":"AAKA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,+FAA+F;AAC/F,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAE/C;AAED,0FAA0F;AAC1F,MAAM,MAAM,kBAAkB,GAAG;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,gEAAgE;IAChE,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,aAAa,EAAE,MAAM,EAAE,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB;;;OAGG;IACH,QAAQ,EAAE,kBAAkB,EAAE,CAAC;IAC/B,oFAAoF;IACpF,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,6EAA6E;IAC7E,2BAA2B,EAAE,MAAM,EAAE,CAAC;IACtC,2CAA2C;IAC3C,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,uDAAuD;IACvD,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,gFAAgF;IAChF,OAAO,CAAC,EAAE,iBAAiB,GAAG,eAAe,CAAC;CAC/C,CAAC;AA6EF,MAAM,MAAM,uBAAuB,GAAG;IACpC,8EAA8E;IAC9E,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,+DAA+D;IAC/D,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF;;;;;;GAMG;AACH,wBAAsB,wBAAwB,CAC5C,SAAS,EAAE,SAAS,MAAM,EAAE,EAC5B,OAAO,GAAE,uBAA4B,GACpC,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAkB9B"}
|
|
@@ -10,11 +10,20 @@ import { bridgeRuntimeFiles, runtimeFileStore } from "../hono/runtime-files.js";
|
|
|
10
10
|
* this sandbox. That file is append-only, so it survives compaction: a
|
|
11
11
|
* compaction adds a summary line, it never removes one.
|
|
12
12
|
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
13
|
+
* A thread is not one SDK session. Every message resumes the last one as a
|
|
14
|
+
* fork, a stall or a restart forks again, and `/publish` runs in a session of
|
|
15
|
+
* its own the thread never adopts. The bridge records each id a turn runs under
|
|
16
|
+
* as a `session` line in `~/.baker/turn-events.jsonl`; the thread's session file
|
|
17
|
+
* (`~/.baker/sessions/<threadId>.json`) names only the latest. Both are read,
|
|
18
|
+
* and each id maps to `~/.claude/projects/<cwd-slug>/<sessionId>.jsonl` plus the
|
|
19
|
+
* subagent directory beside it — a subagent lives under the id it was spawned
|
|
20
|
+
* in, so reading the latest alone drops every earlier turn's fan-out.
|
|
21
|
+
*
|
|
22
|
+
* A fork copies the conversation so far into its new file under the same line
|
|
23
|
+
* uuids, so the files overlap; the reader dedupes by uuid.
|
|
24
|
+
*
|
|
25
|
+
* Whatever cannot be read is reported rather than skipped: "we could not read
|
|
26
|
+
* this" and "this had no tool calls" must never look the same to the reviewer.
|
|
18
27
|
*/
|
|
19
28
|
/** Claude Code names a project directory after its cwd, with every separator folded to `-`. */
|
|
20
29
|
export function projectSlug(cwd) {
|
|
@@ -36,6 +45,53 @@ async function readSessionId(threadId) {
|
|
|
36
45
|
return undefined;
|
|
37
46
|
}
|
|
38
47
|
}
|
|
48
|
+
/**
|
|
49
|
+
* Session ids per thread, in the order the bridge first saw each one.
|
|
50
|
+
*
|
|
51
|
+
* Absent or unreadable is an empty map: a Runtime whose bridge predates the
|
|
52
|
+
* `session` event still has the session file, which is what it had before.
|
|
53
|
+
*/
|
|
54
|
+
async function readTurnSessionIds() {
|
|
55
|
+
const byThread = new Map();
|
|
56
|
+
const result = await runtimeFileStore.readText(bridgeRuntimeFiles.turnEventsFile());
|
|
57
|
+
if (!result.ok) {
|
|
58
|
+
return byThread;
|
|
59
|
+
}
|
|
60
|
+
for (const line of result.value.split("\n")) {
|
|
61
|
+
const sessionId = sessionEventId(line);
|
|
62
|
+
if (!sessionId) {
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
const ids = byThread.get(sessionId.threadId) ?? [];
|
|
66
|
+
if (!ids.includes(sessionId.sessionId)) {
|
|
67
|
+
ids.push(sessionId.sessionId);
|
|
68
|
+
}
|
|
69
|
+
byThread.set(sessionId.threadId, ids);
|
|
70
|
+
}
|
|
71
|
+
return byThread;
|
|
72
|
+
}
|
|
73
|
+
function sessionEventId(line) {
|
|
74
|
+
if (line.trim().length === 0) {
|
|
75
|
+
return undefined;
|
|
76
|
+
}
|
|
77
|
+
let parsed;
|
|
78
|
+
try {
|
|
79
|
+
parsed = JSON.parse(line);
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
// A truncated final line is normal on a file still being appended to.
|
|
83
|
+
return undefined;
|
|
84
|
+
}
|
|
85
|
+
if (typeof parsed !== "object" || parsed === null) {
|
|
86
|
+
return undefined;
|
|
87
|
+
}
|
|
88
|
+
const event = parsed;
|
|
89
|
+
if (event.event !== "session" || typeof event.threadId !== "string") {
|
|
90
|
+
return undefined;
|
|
91
|
+
}
|
|
92
|
+
const sessionId = event.detail?.sessionId;
|
|
93
|
+
return typeof sessionId === "string" && sessionId.length > 0 ? { threadId: event.threadId, sessionId } : undefined;
|
|
94
|
+
}
|
|
39
95
|
async function listJsonl(dir) {
|
|
40
96
|
try {
|
|
41
97
|
const entries = await readdir(dir);
|
|
@@ -57,24 +113,50 @@ export async function resolveThreadTranscripts(threadIds, options = {}) {
|
|
|
57
113
|
const projectsRoot = options.projectsRoot ?? join(homedir(), ".claude", "projects");
|
|
58
114
|
const projectDir = join(projectsRoot, projectSlug(projectRoot));
|
|
59
115
|
const onDisk = new Set(await listJsonl(projectDir));
|
|
116
|
+
const turnSessionIds = await readTurnSessionIds();
|
|
60
117
|
const out = [];
|
|
61
118
|
for (const threadId of threadIds) {
|
|
62
|
-
const
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
119
|
+
const sessionIds = [...(turnSessionIds.get(threadId) ?? [])];
|
|
120
|
+
const latest = await readSessionId(threadId);
|
|
121
|
+
if (latest && !sessionIds.includes(latest)) {
|
|
122
|
+
sessionIds.push(latest);
|
|
66
123
|
}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
124
|
+
out.push(await threadTranscripts(threadId, sessionIds, projectDir, onDisk));
|
|
125
|
+
}
|
|
126
|
+
return out;
|
|
127
|
+
}
|
|
128
|
+
async function threadTranscripts(threadId, sessionIds, projectDir, onDisk) {
|
|
129
|
+
if (sessionIds.length === 0) {
|
|
130
|
+
return {
|
|
71
131
|
threadId,
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
132
|
+
sessions: [],
|
|
133
|
+
sessionIds: [],
|
|
134
|
+
sessionIdsWithoutTranscript: [],
|
|
135
|
+
files: [],
|
|
136
|
+
subagentFiles: [],
|
|
137
|
+
missing: "no_session_file",
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
const sessions = [];
|
|
141
|
+
for (const sessionId of sessionIds) {
|
|
142
|
+
const file = join(projectDir, `${sessionId}.jsonl`);
|
|
143
|
+
sessions.push({
|
|
144
|
+
sessionId,
|
|
145
|
+
file: onDisk.has(file) ? file : null,
|
|
146
|
+
subagentFiles: await listJsonl(join(projectDir, sessionId, "subagents")),
|
|
76
147
|
});
|
|
77
148
|
}
|
|
78
|
-
|
|
149
|
+
const files = sessions.flatMap((session) => (session.file === null ? [] : [session.file]));
|
|
150
|
+
return {
|
|
151
|
+
threadId,
|
|
152
|
+
sessions,
|
|
153
|
+
sessionIds,
|
|
154
|
+
sessionIdsWithoutTranscript: sessions
|
|
155
|
+
.filter((session) => session.file === null)
|
|
156
|
+
.map((session) => session.sessionId),
|
|
157
|
+
subagentFiles: sessions.flatMap((session) => session.subagentFiles),
|
|
158
|
+
files,
|
|
159
|
+
...(files.length === 0 ? { missing: "no_transcript" } : {}),
|
|
160
|
+
};
|
|
79
161
|
}
|
|
80
162
|
//# sourceMappingURL=transcripts.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transcripts.js","sourceRoot":"","sources":["../../src/review/transcripts.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAC3C,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAEhF
|
|
1
|
+
{"version":3,"file":"transcripts.js","sourceRoot":"","sources":["../../src/review/transcripts.ts"],"names":[],"mappings":"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"}
|
|
@@ -10,6 +10,7 @@ vi.mock("../hono/runtime-files.ts", async () => {
|
|
|
10
10
|
bridgeRuntimeFiles: {
|
|
11
11
|
...actual.bridgeRuntimeFiles,
|
|
12
12
|
sessionFile: (threadId) => join(bakerHome, "sessions", `${threadId}.json`),
|
|
13
|
+
turnEventsFile: () => join(bakerHome, "turn-events.jsonl"),
|
|
13
14
|
},
|
|
14
15
|
};
|
|
15
16
|
});
|
|
@@ -25,6 +26,9 @@ function writeSession(threadId, body) {
|
|
|
25
26
|
mkdirSync(join(bakerHome, "sessions"), { recursive: true });
|
|
26
27
|
writeFileSync(join(bakerHome, "sessions", `${threadId}.json`), body);
|
|
27
28
|
}
|
|
29
|
+
function writeTurnEvents(events) {
|
|
30
|
+
writeFileSync(join(bakerHome, "turn-events.jsonl"), events.map((event) => `${JSON.stringify(event)}\n`).join(""));
|
|
31
|
+
}
|
|
28
32
|
describe("projectSlug", () => {
|
|
29
33
|
it("folds every path separator and dot, the way Claude Code names its project directory", () => {
|
|
30
34
|
expect(projectSlug("/home/user/my.repo")).toBe("-home-user-my-repo");
|
|
@@ -78,5 +82,38 @@ describe("resolveThreadTranscripts", () => {
|
|
|
78
82
|
const result = await resolveThreadTranscripts(["thread-reaped"], { projectRoot, projectsRoot });
|
|
79
83
|
expect(result[0]?.missing).toBe("no_transcript");
|
|
80
84
|
});
|
|
85
|
+
it("joins every session a resumed thread ran under, with each one's subagents", async () => {
|
|
86
|
+
// Every message forks the SDK session: the thread's session file names only
|
|
87
|
+
// the last id, while the visual checks of turn 2 sit under the id turn 2 ran in.
|
|
88
|
+
const projectsRoot = mkdtempSync(join(tmpdir(), "projects-"));
|
|
89
|
+
created.push(projectsRoot);
|
|
90
|
+
const projectRoot = "/work/resumed";
|
|
91
|
+
const dir = join(projectsRoot, projectSlug(projectRoot));
|
|
92
|
+
mkdirSync(dir, { recursive: true });
|
|
93
|
+
for (const sessionId of ["s-turn1", "s-turn2", "s-turn3"]) {
|
|
94
|
+
writeFileSync(join(dir, `${sessionId}.jsonl`), "{}\n");
|
|
95
|
+
}
|
|
96
|
+
mkdirSync(join(dir, "s-turn2", "subagents"), { recursive: true });
|
|
97
|
+
writeFileSync(join(dir, "s-turn2", "subagents", "agent-v4.jsonl"), "{}\n");
|
|
98
|
+
writeFileSync(join(dir, "s-turn2", "subagents", "agent-v1.jsonl"), "{}\n");
|
|
99
|
+
mkdirSync(join(dir, "s-turn3", "subagents"), { recursive: true });
|
|
100
|
+
writeFileSync(join(dir, "s-turn3", "subagents", "agent-last.jsonl"), "{}\n");
|
|
101
|
+
writeSession("thread-resumed", JSON.stringify({ version: 2, sessionId: "s-turn3", updatedAtMs: 3 }));
|
|
102
|
+
writeTurnEvents([
|
|
103
|
+
{ threadId: "thread-resumed", turnId: "t1", event: "session", detail: { sessionId: "s-turn1" } },
|
|
104
|
+
{ threadId: "thread-other", turnId: "o1", event: "session", detail: { sessionId: "s-other" } },
|
|
105
|
+
{ threadId: "thread-resumed", turnId: "t2", event: "session", detail: { sessionId: "s-turn2" } },
|
|
106
|
+
{ threadId: "thread-resumed", turnId: "t2", event: "turn_end" },
|
|
107
|
+
{ threadId: "thread-resumed", turnId: "t3", event: "session", detail: { sessionId: "s-turn3" } },
|
|
108
|
+
]);
|
|
109
|
+
const [thread] = await resolveThreadTranscripts(["thread-resumed"], { projectRoot, projectsRoot });
|
|
110
|
+
expect(thread?.sessionIds).toEqual(["s-turn1", "s-turn2", "s-turn3"]);
|
|
111
|
+
expect(thread?.files).toEqual(["s-turn1", "s-turn2", "s-turn3"].map((id) => join(dir, `${id}.jsonl`)));
|
|
112
|
+
expect([...(thread?.subagentFiles ?? [])].sort()).toEqual([
|
|
113
|
+
join(dir, "s-turn2", "subagents", "agent-v1.jsonl"),
|
|
114
|
+
join(dir, "s-turn2", "subagents", "agent-v4.jsonl"),
|
|
115
|
+
join(dir, "s-turn3", "subagents", "agent-last.jsonl"),
|
|
116
|
+
].sort());
|
|
117
|
+
});
|
|
81
118
|
});
|
|
82
119
|
//# sourceMappingURL=transcripts.test.js.map
|