@agentproto/runtime 1.1.0 → 2.0.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 +3 -1
- package/dist/catalog-models.d.ts +255 -0
- package/dist/catalog-models.mjs +386 -0
- package/dist/catalog-models.mjs.map +1 -0
- package/dist/config.d.ts +378 -1
- package/dist/config.mjs.map +1 -1
- package/dist/context-continuity-B9n0t0v-.d.ts +53 -0
- package/dist/index.d.ts +6002 -2816
- package/dist/index.mjs +21719 -11296
- package/dist/index.mjs.map +1 -1
- package/dist/pr-provenance.d.ts +140 -0
- package/dist/pr-provenance.mjs +106 -0
- package/dist/pr-provenance.mjs.map +1 -0
- package/dist/resume-strategies.d.ts +39 -2
- package/dist/resume-strategies.mjs +765 -28
- package/dist/resume-strategies.mjs.map +1 -1
- package/dist/session-config-DIf6wYYP.d.ts +192 -0
- package/dist/session-story-panel.d.ts +26 -0
- package/dist/session-story-panel.mjs +970 -0
- package/dist/session-story-panel.mjs.map +1 -0
- package/dist/session-story.d.ts +12 -2
- package/dist/spawn-defaults-7uHRnYH1.d.ts +414 -0
- package/dist/telegram-proxy.d.ts +35 -0
- package/dist/telegram-proxy.mjs +115 -0
- package/dist/telegram-proxy.mjs.map +1 -0
- package/dist/user-presets.d.ts +91 -0
- package/dist/user-presets.mjs +84 -0
- package/dist/user-presets.mjs.map +1 -0
- package/package.json +48 -23
- package/dist/config-BRKy_SAF.d.ts +0 -569
|
@@ -93,6 +93,12 @@ var init_tool_presenter = __esm({
|
|
|
93
93
|
};
|
|
94
94
|
}
|
|
95
95
|
});
|
|
96
|
+
|
|
97
|
+
// src/tool-call-record.ts
|
|
98
|
+
var init_tool_call_record = __esm({
|
|
99
|
+
"src/tool-call-record.ts"() {
|
|
100
|
+
}
|
|
101
|
+
});
|
|
96
102
|
function sessionTranscriptDir(sessionId, baseDir) {
|
|
97
103
|
return join(join(homedir(), ".agentproto", "sessions"), sessionId);
|
|
98
104
|
}
|
|
@@ -101,6 +107,7 @@ function sessionEventsPath(sessionId, baseDir) {
|
|
|
101
107
|
}
|
|
102
108
|
var init_transcript_writer = __esm({
|
|
103
109
|
"src/transcript-writer.ts"() {
|
|
110
|
+
init_tool_call_record();
|
|
104
111
|
}
|
|
105
112
|
});
|
|
106
113
|
|
|
@@ -108,10 +115,19 @@ var init_transcript_writer = __esm({
|
|
|
108
115
|
var transcript_export_exports = {};
|
|
109
116
|
__export(transcript_export_exports, {
|
|
110
117
|
crossValidateHermesExport: () => crossValidateHermesExport,
|
|
118
|
+
discoverCodexSessions: () => discoverCodexSessions,
|
|
111
119
|
discoverHermesSessions: () => discoverHermesSessions,
|
|
120
|
+
discoverMastracodeInprocessSessions: () => discoverMastracodeInprocessSessions,
|
|
121
|
+
discoverOpenCodeSessions: () => discoverOpenCodeSessions,
|
|
122
|
+
discoverPiSessions: () => discoverPiSessions,
|
|
112
123
|
exportAgentSession: () => exportAgentSession,
|
|
113
124
|
exportClaudeCodeSession: () => exportClaudeCodeSession,
|
|
125
|
+
exportCodexSession: () => exportCodexSession,
|
|
126
|
+
exportDaemonEventsSession: () => exportDaemonEventsSession,
|
|
114
127
|
exportHermesSession: () => exportHermesSession,
|
|
128
|
+
exportMastracodeInprocessSession: () => exportMastracodeInprocessSession,
|
|
129
|
+
exportOpenCodeSession: () => exportOpenCodeSession,
|
|
130
|
+
exportPiSession: () => exportPiSession,
|
|
115
131
|
renderJson: () => renderJson,
|
|
116
132
|
renderMarkdown: () => renderMarkdown
|
|
117
133
|
});
|
|
@@ -127,7 +143,9 @@ function renderMarkdown(session, opts = {}) {
|
|
|
127
143
|
out.push(`# ${meta.title ?? "(untitled)"}`);
|
|
128
144
|
out.push("");
|
|
129
145
|
const sourceNote = meta.source ? ` \xB7 source \`${meta.source}\`` : "";
|
|
130
|
-
|
|
146
|
+
const originNote = meta.origin ? ` \xB7 origin \`${meta.origin}\`` : "";
|
|
147
|
+
const callerNote = meta.callerSessionId ? ` \xB7 caller \`${meta.callerSessionId}\`` : "";
|
|
148
|
+
out.push(`> Session${sourceNote}${originNote}${callerNote}`);
|
|
131
149
|
out.push("");
|
|
132
150
|
out.push("| | |");
|
|
133
151
|
out.push("|---|---|");
|
|
@@ -338,6 +356,27 @@ function withRetryOnBusy(fn) {
|
|
|
338
356
|
throw err;
|
|
339
357
|
}
|
|
340
358
|
}
|
|
359
|
+
async function openReadonlySqlite(dbPath, label) {
|
|
360
|
+
let DatabaseSync;
|
|
361
|
+
try {
|
|
362
|
+
const sqlite = await import('sqlite');
|
|
363
|
+
DatabaseSync = sqlite.DatabaseSync;
|
|
364
|
+
} catch {
|
|
365
|
+
throw new Error(`${label}: node:sqlite unavailable. Requires Node.js \u226522.5.0.`);
|
|
366
|
+
}
|
|
367
|
+
try {
|
|
368
|
+
return new DatabaseSync(dbPath, { readOnly: true });
|
|
369
|
+
} catch (err) {
|
|
370
|
+
const msg = String(err);
|
|
371
|
+
if (err.code === "ENOENT" || msg.includes("unable to open database file")) {
|
|
372
|
+
throw new Error(`${label}: database not found at ${dbPath}. Has ${label} been run at least once?`);
|
|
373
|
+
}
|
|
374
|
+
if (msg.includes("SQLITE_BUSY") || msg.includes("database is locked")) {
|
|
375
|
+
throw new Error(`${label}: database is locked (SQLITE_BUSY). It may be writing. Try again in a moment.`);
|
|
376
|
+
}
|
|
377
|
+
throw err;
|
|
378
|
+
}
|
|
379
|
+
}
|
|
341
380
|
async function exportHermesSession(adapterSessionId) {
|
|
342
381
|
const dbPath = join(homedir(), ".hermes", "state.db");
|
|
343
382
|
const db = await openHermesDb(dbPath);
|
|
@@ -620,6 +659,10 @@ Either the session never drove an agent-cli turn, or it predates this feature.`
|
|
|
620
659
|
case "turn-end":
|
|
621
660
|
flushAssistant();
|
|
622
661
|
break;
|
|
662
|
+
case "notice":
|
|
663
|
+
flushAssistant();
|
|
664
|
+
messages.push({ role: "system", text: rec.text ?? "" });
|
|
665
|
+
break;
|
|
623
666
|
}
|
|
624
667
|
}
|
|
625
668
|
flushAssistant();
|
|
@@ -628,6 +671,8 @@ Either the session never drove an agent-cli turn, or it predates this feature.`
|
|
|
628
671
|
if (desc?.model) meta.model = desc.model;
|
|
629
672
|
if (desc?.startedAt) meta.startedAt = desc.startedAt;
|
|
630
673
|
if (desc?.endedAt) meta.endedAt = desc.endedAt;
|
|
674
|
+
if (desc?.origin) meta.origin = desc.origin;
|
|
675
|
+
if (desc?.callerSessionId) meta.callerSessionId = desc.callerSessionId;
|
|
631
676
|
meta.messageCount = messages.length;
|
|
632
677
|
meta.toolCallCount = toolCallCount;
|
|
633
678
|
if (desc?.costUsd !== void 0) meta.costUsd = desc.costUsd;
|
|
@@ -640,6 +685,629 @@ Either the session never drove an agent-cli turn, or it predates this feature.`
|
|
|
640
685
|
}
|
|
641
686
|
return { meta, messages };
|
|
642
687
|
}
|
|
688
|
+
async function readFirstJsonLine(path) {
|
|
689
|
+
const stream = createReadStream(path, { encoding: "utf8" });
|
|
690
|
+
const rl = createInterface({ input: stream, crlfDelay: Infinity });
|
|
691
|
+
try {
|
|
692
|
+
for await (const line of rl) {
|
|
693
|
+
const t = line.trim();
|
|
694
|
+
if (t) return t;
|
|
695
|
+
}
|
|
696
|
+
return void 0;
|
|
697
|
+
} finally {
|
|
698
|
+
rl.close();
|
|
699
|
+
stream.destroy();
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
function codexHome() {
|
|
703
|
+
return process.env.CODEX_HOME ?? join(homedir(), ".codex");
|
|
704
|
+
}
|
|
705
|
+
function codexSessionsDir() {
|
|
706
|
+
return join(codexHome(), "sessions");
|
|
707
|
+
}
|
|
708
|
+
async function walkCodexRollouts(dir) {
|
|
709
|
+
let entries;
|
|
710
|
+
try {
|
|
711
|
+
entries = await promises.readdir(dir, { withFileTypes: true });
|
|
712
|
+
} catch {
|
|
713
|
+
return [];
|
|
714
|
+
}
|
|
715
|
+
const out = [];
|
|
716
|
+
for (const e of entries) {
|
|
717
|
+
const p = join(dir, e.name);
|
|
718
|
+
if (e.isDirectory()) {
|
|
719
|
+
out.push(...await walkCodexRollouts(p));
|
|
720
|
+
} else if (e.isFile() && e.name.startsWith("rollout-") && e.name.endsWith(".jsonl")) {
|
|
721
|
+
out.push(p);
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
return out;
|
|
725
|
+
}
|
|
726
|
+
function codexBlocksText(content) {
|
|
727
|
+
if (typeof content === "string") return content;
|
|
728
|
+
if (!Array.isArray(content)) return "";
|
|
729
|
+
let acc = "";
|
|
730
|
+
for (const c of content) {
|
|
731
|
+
if (c && typeof c === "object") {
|
|
732
|
+
const b = c;
|
|
733
|
+
if (typeof b.text === "string" && (b.type === "input_text" || b.type === "output_text" || b.type === "text")) {
|
|
734
|
+
acc += b.text;
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
return acc;
|
|
739
|
+
}
|
|
740
|
+
async function findCodexRolloutFile(conversationId) {
|
|
741
|
+
const files = await walkCodexRollouts(codexSessionsDir());
|
|
742
|
+
const byName = files.find((f) => f.endsWith(`-${conversationId}.jsonl`));
|
|
743
|
+
if (byName) return byName;
|
|
744
|
+
for (const f of files) {
|
|
745
|
+
const first = await readFirstJsonLine(f);
|
|
746
|
+
if (!first) continue;
|
|
747
|
+
let meta;
|
|
748
|
+
try {
|
|
749
|
+
meta = JSON.parse(first);
|
|
750
|
+
} catch {
|
|
751
|
+
continue;
|
|
752
|
+
}
|
|
753
|
+
const p = meta.payload;
|
|
754
|
+
if (p && (p.id === conversationId || p.session_id === conversationId)) return f;
|
|
755
|
+
}
|
|
756
|
+
return void 0;
|
|
757
|
+
}
|
|
758
|
+
async function exportCodexSession(conversationId) {
|
|
759
|
+
const file = await findCodexRolloutFile(conversationId);
|
|
760
|
+
if (!file) {
|
|
761
|
+
throw new Error(
|
|
762
|
+
`codex: no rollout file for conversation "${conversationId}" under ${codexSessionsDir()}.
|
|
763
|
+
The session may predate persistence, or CODEX_HOME points elsewhere.`
|
|
764
|
+
);
|
|
765
|
+
}
|
|
766
|
+
const stream = createReadStream(file, { encoding: "utf8" });
|
|
767
|
+
const rl = createInterface({ input: stream, crlfDelay: Infinity });
|
|
768
|
+
const messages = [];
|
|
769
|
+
const toolNameByCall = /* @__PURE__ */ new Map();
|
|
770
|
+
let toolCallCount = 0;
|
|
771
|
+
let startedAt;
|
|
772
|
+
let model;
|
|
773
|
+
for await (const line of rl) {
|
|
774
|
+
const trimmed = line.trim();
|
|
775
|
+
if (!trimmed) continue;
|
|
776
|
+
let entry;
|
|
777
|
+
try {
|
|
778
|
+
entry = JSON.parse(trimmed);
|
|
779
|
+
} catch {
|
|
780
|
+
continue;
|
|
781
|
+
}
|
|
782
|
+
const p = entry.payload ?? {};
|
|
783
|
+
if (entry.type === "session_meta") {
|
|
784
|
+
startedAt = p.timestamp ?? entry.timestamp;
|
|
785
|
+
if (typeof p.model === "string") model = p.model;
|
|
786
|
+
continue;
|
|
787
|
+
}
|
|
788
|
+
if (entry.type === "turn_context") {
|
|
789
|
+
if (!model && typeof p.model === "string") model = p.model;
|
|
790
|
+
continue;
|
|
791
|
+
}
|
|
792
|
+
if (entry.type !== "response_item") continue;
|
|
793
|
+
switch (p.type) {
|
|
794
|
+
case "message": {
|
|
795
|
+
const text = codexBlocksText(p.content).trim();
|
|
796
|
+
if (!text) break;
|
|
797
|
+
const role = p.role === "assistant" ? "assistant" : p.role === "user" ? "user" : "system";
|
|
798
|
+
messages.push({ role, text });
|
|
799
|
+
break;
|
|
800
|
+
}
|
|
801
|
+
case "reasoning": {
|
|
802
|
+
const r = (p.summary ?? []).map((s) => s.text ?? "").join("\n").trim();
|
|
803
|
+
if (r) messages.push({ role: "assistant", reasoning: r });
|
|
804
|
+
break;
|
|
805
|
+
}
|
|
806
|
+
case "function_call":
|
|
807
|
+
case "custom_tool_call": {
|
|
808
|
+
const name = p.name ?? "tool";
|
|
809
|
+
if (typeof p.call_id === "string") toolNameByCall.set(p.call_id, name);
|
|
810
|
+
const raw = p.type === "custom_tool_call" ? p.input : p.arguments;
|
|
811
|
+
const args = typeof raw === "string" ? raw : JSON.stringify(raw ?? {});
|
|
812
|
+
messages.push({ role: "assistant", toolCalls: [{ name, args }] });
|
|
813
|
+
toolCallCount += 1;
|
|
814
|
+
break;
|
|
815
|
+
}
|
|
816
|
+
case "function_call_output":
|
|
817
|
+
case "custom_tool_call_output": {
|
|
818
|
+
const name = typeof p.call_id === "string" ? toolNameByCall.get(p.call_id) : void 0;
|
|
819
|
+
const out = codexBlocksText(p.output) || (typeof p.output === "string" ? p.output : "");
|
|
820
|
+
messages.push({ role: "tool", text: out, ...name ? { toolName: name } : {} });
|
|
821
|
+
break;
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
}
|
|
825
|
+
const meta = { source: "codex" };
|
|
826
|
+
if (startedAt) meta.startedAt = startedAt;
|
|
827
|
+
if (model) meta.model = model;
|
|
828
|
+
meta.messageCount = messages.length;
|
|
829
|
+
meta.toolCallCount = toolCallCount;
|
|
830
|
+
return { meta, messages };
|
|
831
|
+
}
|
|
832
|
+
async function discoverCodexSessions(cwd, since, until, expectedId) {
|
|
833
|
+
const files = await walkCodexRollouts(codexSessionsDir());
|
|
834
|
+
const sinceMs = since ? Date.parse(since) : NaN;
|
|
835
|
+
const untilMs = until ? Date.parse(until) : NaN;
|
|
836
|
+
const scored = [];
|
|
837
|
+
for (const f of files) {
|
|
838
|
+
let mtimeMs;
|
|
839
|
+
try {
|
|
840
|
+
mtimeMs = (await promises.stat(f)).mtimeMs;
|
|
841
|
+
} catch {
|
|
842
|
+
continue;
|
|
843
|
+
}
|
|
844
|
+
if (Number.isFinite(sinceMs) && mtimeMs < sinceMs - 1e3) continue;
|
|
845
|
+
const first = await readFirstJsonLine(f);
|
|
846
|
+
if (!first) continue;
|
|
847
|
+
let meta;
|
|
848
|
+
try {
|
|
849
|
+
meta = JSON.parse(first);
|
|
850
|
+
} catch {
|
|
851
|
+
continue;
|
|
852
|
+
}
|
|
853
|
+
if (meta.type !== "session_meta") continue;
|
|
854
|
+
const p = meta.payload ?? {};
|
|
855
|
+
const id = p.id ?? p.session_id;
|
|
856
|
+
if (!id) continue;
|
|
857
|
+
if (expectedId) {
|
|
858
|
+
if (id !== expectedId) continue;
|
|
859
|
+
} else if (p.cwd !== cwd) {
|
|
860
|
+
continue;
|
|
861
|
+
}
|
|
862
|
+
const startedAt = p.timestamp;
|
|
863
|
+
if (Number.isFinite(untilMs) && startedAt) {
|
|
864
|
+
const startedMs = Date.parse(startedAt);
|
|
865
|
+
if (Number.isFinite(startedMs) && startedMs > untilMs) continue;
|
|
866
|
+
}
|
|
867
|
+
scored.push({
|
|
868
|
+
candidate: {
|
|
869
|
+
conversationId: id,
|
|
870
|
+
...startedAt ? { startedAt } : {},
|
|
871
|
+
lastActivityAt: new Date(mtimeMs).toISOString()
|
|
872
|
+
},
|
|
873
|
+
mtimeMs
|
|
874
|
+
});
|
|
875
|
+
}
|
|
876
|
+
scored.sort((a, b) => b.mtimeMs - a.mtimeMs);
|
|
877
|
+
return scored.map((s) => s.candidate);
|
|
878
|
+
}
|
|
879
|
+
function openCodeDbPath() {
|
|
880
|
+
const dataHome = process.env.XDG_DATA_HOME ?? join(homedir(), ".local", "share");
|
|
881
|
+
return join(dataHome, "opencode", "opencode.db");
|
|
882
|
+
}
|
|
883
|
+
function openCodeModelLabel(raw) {
|
|
884
|
+
if (!raw) return void 0;
|
|
885
|
+
try {
|
|
886
|
+
const m = JSON.parse(raw);
|
|
887
|
+
const id = m.modelID ?? m.id;
|
|
888
|
+
if (!id) return void 0;
|
|
889
|
+
return m.providerID ? `${m.providerID}/${id}` : id;
|
|
890
|
+
} catch {
|
|
891
|
+
return void 0;
|
|
892
|
+
}
|
|
893
|
+
}
|
|
894
|
+
async function exportOpenCodeSession(conversationId) {
|
|
895
|
+
const dbPath = openCodeDbPath();
|
|
896
|
+
const db = await openReadonlySqlite(dbPath, "opencode");
|
|
897
|
+
try {
|
|
898
|
+
const session = withRetryOnBusy(
|
|
899
|
+
() => db.prepare("SELECT * FROM session WHERE id = ?").get(conversationId)
|
|
900
|
+
);
|
|
901
|
+
if (!session) {
|
|
902
|
+
throw new Error(
|
|
903
|
+
`opencode: session "${conversationId}" not found in ${dbPath}. Sessions are keyed by the ACP session id (ses_\u2026) recorded as adapterSessionId.`
|
|
904
|
+
);
|
|
905
|
+
}
|
|
906
|
+
const msgRows = withRetryOnBusy(
|
|
907
|
+
() => db.prepare("SELECT id, data, time_created FROM message WHERE session_id = ? ORDER BY time_created ASC, id ASC").all(conversationId)
|
|
908
|
+
);
|
|
909
|
+
const partRows = withRetryOnBusy(
|
|
910
|
+
() => db.prepare("SELECT message_id, data, time_created FROM part WHERE session_id = ? ORDER BY time_created ASC, id ASC").all(conversationId)
|
|
911
|
+
);
|
|
912
|
+
const partsByMsg = /* @__PURE__ */ new Map();
|
|
913
|
+
for (const r of partRows) {
|
|
914
|
+
const list = partsByMsg.get(r.message_id) ?? [];
|
|
915
|
+
list.push(r);
|
|
916
|
+
partsByMsg.set(r.message_id, list);
|
|
917
|
+
}
|
|
918
|
+
const messages = [];
|
|
919
|
+
let toolCallCount = 0;
|
|
920
|
+
for (const m of msgRows) {
|
|
921
|
+
let mdata;
|
|
922
|
+
try {
|
|
923
|
+
mdata = JSON.parse(m.data);
|
|
924
|
+
} catch {
|
|
925
|
+
continue;
|
|
926
|
+
}
|
|
927
|
+
const role = mdata.role === "assistant" ? "assistant" : "user";
|
|
928
|
+
let text = "";
|
|
929
|
+
let reasoning = "";
|
|
930
|
+
const toolCalls = [];
|
|
931
|
+
const toolResults = [];
|
|
932
|
+
for (const pr of partsByMsg.get(m.id) ?? []) {
|
|
933
|
+
let part;
|
|
934
|
+
try {
|
|
935
|
+
part = JSON.parse(pr.data);
|
|
936
|
+
} catch {
|
|
937
|
+
continue;
|
|
938
|
+
}
|
|
939
|
+
switch (part.type) {
|
|
940
|
+
case "text":
|
|
941
|
+
if (part.text) text += part.text;
|
|
942
|
+
break;
|
|
943
|
+
case "reasoning":
|
|
944
|
+
if (part.text) reasoning += part.text;
|
|
945
|
+
break;
|
|
946
|
+
case "tool": {
|
|
947
|
+
const name = part.tool ?? "tool";
|
|
948
|
+
toolCalls.push({ name, args: JSON.stringify(part.state?.input ?? {}) });
|
|
949
|
+
toolCallCount += 1;
|
|
950
|
+
const output = part.state?.output;
|
|
951
|
+
if (output !== void 0 && output !== null && output !== "") {
|
|
952
|
+
toolResults.push({ name, text: typeof output === "string" ? output : JSON.stringify(output) });
|
|
953
|
+
}
|
|
954
|
+
break;
|
|
955
|
+
}
|
|
956
|
+
}
|
|
957
|
+
}
|
|
958
|
+
if (text.trim() || reasoning.trim() || toolCalls.length) {
|
|
959
|
+
const em = { role };
|
|
960
|
+
if (text.trim()) em.text = text.trim();
|
|
961
|
+
if (reasoning.trim()) em.reasoning = reasoning.trim();
|
|
962
|
+
if (toolCalls.length) em.toolCalls = toolCalls;
|
|
963
|
+
em.ts = m.time_created;
|
|
964
|
+
messages.push(em);
|
|
965
|
+
}
|
|
966
|
+
for (const tr of toolResults) {
|
|
967
|
+
messages.push({ role: "tool", text: tr.text, ...tr.name ? { toolName: tr.name } : {} });
|
|
968
|
+
}
|
|
969
|
+
}
|
|
970
|
+
const meta = { source: "opencode" };
|
|
971
|
+
if (session.title) meta.title = session.title;
|
|
972
|
+
const model = openCodeModelLabel(session.model);
|
|
973
|
+
if (model) meta.model = model;
|
|
974
|
+
if (session.time_created) meta.startedAt = new Date(session.time_created).toISOString();
|
|
975
|
+
if (session.time_updated) meta.endedAt = new Date(session.time_updated).toISOString();
|
|
976
|
+
meta.messageCount = messages.length;
|
|
977
|
+
meta.toolCallCount = toolCallCount;
|
|
978
|
+
if (session.cost != null) meta.costUsd = Number(session.cost);
|
|
979
|
+
const tk = {
|
|
980
|
+
...session.tokens_input != null ? { input: session.tokens_input } : {},
|
|
981
|
+
...session.tokens_output != null ? { output: session.tokens_output } : {},
|
|
982
|
+
...session.tokens_cache_read != null ? { cacheRead: session.tokens_cache_read } : {},
|
|
983
|
+
...session.tokens_cache_write != null ? { cacheWrite: session.tokens_cache_write } : {},
|
|
984
|
+
...session.tokens_reasoning != null ? { reasoning: session.tokens_reasoning } : {}
|
|
985
|
+
};
|
|
986
|
+
if (Object.keys(tk).length) meta.tokens = tk;
|
|
987
|
+
return { meta, messages };
|
|
988
|
+
} finally {
|
|
989
|
+
db.close();
|
|
990
|
+
}
|
|
991
|
+
}
|
|
992
|
+
async function discoverOpenCodeSessions(cwd, since, expectedId) {
|
|
993
|
+
const dbPath = openCodeDbPath();
|
|
994
|
+
let db;
|
|
995
|
+
try {
|
|
996
|
+
db = await openReadonlySqlite(dbPath, "opencode");
|
|
997
|
+
} catch (err) {
|
|
998
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
999
|
+
if (msg.includes("database not found")) return [];
|
|
1000
|
+
throw err;
|
|
1001
|
+
}
|
|
1002
|
+
try {
|
|
1003
|
+
if (expectedId) {
|
|
1004
|
+
const row = withRetryOnBusy(
|
|
1005
|
+
() => db.prepare("SELECT * FROM session WHERE id = ?").get(expectedId)
|
|
1006
|
+
);
|
|
1007
|
+
return row ? [openCodeRowToCandidate(row)] : [];
|
|
1008
|
+
}
|
|
1009
|
+
const rows = withRetryOnBusy(
|
|
1010
|
+
() => db.prepare("SELECT * FROM session WHERE directory = ?").all(cwd)
|
|
1011
|
+
);
|
|
1012
|
+
const sinceMs = since ? Date.parse(since) : NaN;
|
|
1013
|
+
return rows.filter((r) => {
|
|
1014
|
+
if (!Number.isFinite(sinceMs)) return true;
|
|
1015
|
+
const last = r.time_updated ?? r.time_created;
|
|
1016
|
+
return last === void 0 || last >= sinceMs - 1e3;
|
|
1017
|
+
}).map(openCodeRowToCandidate);
|
|
1018
|
+
} finally {
|
|
1019
|
+
db.close();
|
|
1020
|
+
}
|
|
1021
|
+
}
|
|
1022
|
+
function openCodeRowToCandidate(row) {
|
|
1023
|
+
return {
|
|
1024
|
+
conversationId: row.id,
|
|
1025
|
+
...row.time_created ? { startedAt: new Date(row.time_created).toISOString() } : {},
|
|
1026
|
+
...row.time_updated ? { lastActivityAt: new Date(row.time_updated).toISOString() } : {},
|
|
1027
|
+
...row.title ? { preview: row.title } : {}
|
|
1028
|
+
};
|
|
1029
|
+
}
|
|
1030
|
+
function mastracodeInprocessDbPath() {
|
|
1031
|
+
const home = process.env.AGENTPROTO_HOME ?? join(homedir(), ".agentproto");
|
|
1032
|
+
return join(home, "mastracode-inprocess", "storage.db");
|
|
1033
|
+
}
|
|
1034
|
+
function mastraThreadId(conversationId) {
|
|
1035
|
+
const idx = conversationId.indexOf(":");
|
|
1036
|
+
return idx > 0 ? conversationId.slice(idx + 1) : conversationId;
|
|
1037
|
+
}
|
|
1038
|
+
function mastraContentToMessage(role, content) {
|
|
1039
|
+
const toolResults = [];
|
|
1040
|
+
let parsed;
|
|
1041
|
+
try {
|
|
1042
|
+
parsed = JSON.parse(content);
|
|
1043
|
+
} catch {
|
|
1044
|
+
return { message: void 0, toolResults, toolCalls: 0 };
|
|
1045
|
+
}
|
|
1046
|
+
let text = "";
|
|
1047
|
+
let reasoning = "";
|
|
1048
|
+
const toolCalls = [];
|
|
1049
|
+
for (const raw of parsed.parts ?? []) {
|
|
1050
|
+
if (!raw || typeof raw !== "object") continue;
|
|
1051
|
+
const part = raw;
|
|
1052
|
+
if (part.type === "text" && part.text) text += part.text;
|
|
1053
|
+
else if (part.type === "reasoning" && part.reasoning) reasoning += part.reasoning;
|
|
1054
|
+
else if (part.type === "tool-invocation" && part.toolInvocation) {
|
|
1055
|
+
const inv = part.toolInvocation;
|
|
1056
|
+
const name = inv.toolName ?? "tool";
|
|
1057
|
+
toolCalls.push({ name, args: JSON.stringify(inv.args ?? {}) });
|
|
1058
|
+
if (inv.result !== void 0) {
|
|
1059
|
+
const r = inv.result;
|
|
1060
|
+
const rtext = Array.isArray(r?.content) ? r.content.filter((c) => c?.type === "text").map((c) => c.text ?? "").join("") : typeof inv.result === "string" ? inv.result : JSON.stringify(inv.result);
|
|
1061
|
+
toolResults.push({ name, text: rtext });
|
|
1062
|
+
}
|
|
1063
|
+
}
|
|
1064
|
+
}
|
|
1065
|
+
let message;
|
|
1066
|
+
if (text.trim() || reasoning.trim() || toolCalls.length) {
|
|
1067
|
+
message = { role };
|
|
1068
|
+
if (text.trim()) message.text = text.trim();
|
|
1069
|
+
if (reasoning.trim()) message.reasoning = reasoning.trim();
|
|
1070
|
+
if (toolCalls.length) message.toolCalls = toolCalls;
|
|
1071
|
+
}
|
|
1072
|
+
return { message, toolResults, toolCalls: toolCalls.length };
|
|
1073
|
+
}
|
|
1074
|
+
async function exportMastracodeInprocessSession(conversationId) {
|
|
1075
|
+
const threadId = mastraThreadId(conversationId);
|
|
1076
|
+
const dbPath = mastracodeInprocessDbPath();
|
|
1077
|
+
const db = await openReadonlySqlite(dbPath, "mastracode-inprocess");
|
|
1078
|
+
try {
|
|
1079
|
+
const thread = withRetryOnBusy(
|
|
1080
|
+
() => db.prepare("SELECT * FROM mastra_threads WHERE id = ?").get(threadId)
|
|
1081
|
+
);
|
|
1082
|
+
if (!thread) {
|
|
1083
|
+
throw new Error(
|
|
1084
|
+
`mastracode-inprocess: thread "${threadId}" not found in ${dbPath}. The sessionId is "<resourceId>:<threadId>"; only the threadId is looked up.`
|
|
1085
|
+
);
|
|
1086
|
+
}
|
|
1087
|
+
const rows = withRetryOnBusy(
|
|
1088
|
+
() => db.prepare('SELECT role, content, createdAt FROM mastra_messages WHERE thread_id = ? ORDER BY "createdAt" ASC').all(threadId)
|
|
1089
|
+
);
|
|
1090
|
+
const messages = [];
|
|
1091
|
+
let toolCallCount = 0;
|
|
1092
|
+
for (const r of rows) {
|
|
1093
|
+
const role = r.role === "assistant" ? "assistant" : "user";
|
|
1094
|
+
const { message, toolResults, toolCalls } = mastraContentToMessage(role, r.content);
|
|
1095
|
+
if (message) messages.push(message);
|
|
1096
|
+
toolCallCount += toolCalls;
|
|
1097
|
+
for (const tr of toolResults) {
|
|
1098
|
+
messages.push({ role: "tool", text: tr.text, ...tr.name ? { toolName: tr.name } : {} });
|
|
1099
|
+
}
|
|
1100
|
+
}
|
|
1101
|
+
const meta = { source: "mastracode-inprocess" };
|
|
1102
|
+
if (thread.title) meta.title = thread.title;
|
|
1103
|
+
if (thread.createdAt) meta.startedAt = thread.createdAt;
|
|
1104
|
+
if (thread.updatedAt) meta.endedAt = thread.updatedAt;
|
|
1105
|
+
meta.messageCount = messages.length;
|
|
1106
|
+
meta.toolCallCount = toolCallCount;
|
|
1107
|
+
return { meta, messages };
|
|
1108
|
+
} finally {
|
|
1109
|
+
db.close();
|
|
1110
|
+
}
|
|
1111
|
+
}
|
|
1112
|
+
async function discoverMastracodeInprocessSessions(_cwd, since, expectedId) {
|
|
1113
|
+
const dbPath = mastracodeInprocessDbPath();
|
|
1114
|
+
let db;
|
|
1115
|
+
try {
|
|
1116
|
+
db = await openReadonlySqlite(dbPath, "mastracode-inprocess");
|
|
1117
|
+
} catch (err) {
|
|
1118
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
1119
|
+
if (msg.includes("database not found")) return [];
|
|
1120
|
+
throw err;
|
|
1121
|
+
}
|
|
1122
|
+
try {
|
|
1123
|
+
if (!expectedId) return [];
|
|
1124
|
+
const threadId = mastraThreadId(expectedId);
|
|
1125
|
+
const thread = withRetryOnBusy(
|
|
1126
|
+
() => db.prepare("SELECT * FROM mastra_threads WHERE id = ?").get(threadId)
|
|
1127
|
+
);
|
|
1128
|
+
if (!thread) return [];
|
|
1129
|
+
const sinceMs = since ? Date.parse(since) : NaN;
|
|
1130
|
+
if (Number.isFinite(sinceMs) && thread.updatedAt) {
|
|
1131
|
+
const upd = Date.parse(thread.updatedAt);
|
|
1132
|
+
if (Number.isFinite(upd) && upd < sinceMs - 1e3) return [];
|
|
1133
|
+
}
|
|
1134
|
+
return [
|
|
1135
|
+
{
|
|
1136
|
+
// Echo back the full composite id so callers/read() round-trip it.
|
|
1137
|
+
conversationId: expectedId,
|
|
1138
|
+
...thread.createdAt ? { startedAt: thread.createdAt } : {},
|
|
1139
|
+
...thread.updatedAt ? { lastActivityAt: thread.updatedAt } : {},
|
|
1140
|
+
...thread.title ? { preview: thread.title } : {}
|
|
1141
|
+
}
|
|
1142
|
+
];
|
|
1143
|
+
} finally {
|
|
1144
|
+
db.close();
|
|
1145
|
+
}
|
|
1146
|
+
}
|
|
1147
|
+
function piSessionsDir() {
|
|
1148
|
+
return join(homedir(), ".pi", "agent", "sessions");
|
|
1149
|
+
}
|
|
1150
|
+
function piBlocksText(content) {
|
|
1151
|
+
if (typeof content === "string") return content;
|
|
1152
|
+
if (!Array.isArray(content)) return "";
|
|
1153
|
+
let acc = "";
|
|
1154
|
+
for (const c of content) {
|
|
1155
|
+
if (c && typeof c === "object") {
|
|
1156
|
+
const b = c;
|
|
1157
|
+
if (b.type === "text" && typeof b.text === "string") acc += b.text;
|
|
1158
|
+
}
|
|
1159
|
+
}
|
|
1160
|
+
return acc;
|
|
1161
|
+
}
|
|
1162
|
+
async function walkPiSessionFiles(dir) {
|
|
1163
|
+
let entries;
|
|
1164
|
+
try {
|
|
1165
|
+
entries = await promises.readdir(dir, { withFileTypes: true });
|
|
1166
|
+
} catch {
|
|
1167
|
+
return [];
|
|
1168
|
+
}
|
|
1169
|
+
const out = [];
|
|
1170
|
+
for (const e of entries) {
|
|
1171
|
+
const p = join(dir, e.name);
|
|
1172
|
+
if (e.isDirectory()) out.push(...await walkPiSessionFiles(p));
|
|
1173
|
+
else if (e.isFile() && e.name.endsWith(".jsonl")) out.push(p);
|
|
1174
|
+
}
|
|
1175
|
+
return out;
|
|
1176
|
+
}
|
|
1177
|
+
async function findPiSessionFile(conversationId) {
|
|
1178
|
+
const files = await walkPiSessionFiles(piSessionsDir());
|
|
1179
|
+
const byName = files.find((f) => f.endsWith(`_${conversationId}.jsonl`));
|
|
1180
|
+
if (byName) return byName;
|
|
1181
|
+
for (const f of files) {
|
|
1182
|
+
const first = await readFirstJsonLine(f);
|
|
1183
|
+
if (!first) continue;
|
|
1184
|
+
try {
|
|
1185
|
+
const meta = JSON.parse(first);
|
|
1186
|
+
if (meta.type === "session" && meta.id === conversationId) return f;
|
|
1187
|
+
} catch {
|
|
1188
|
+
}
|
|
1189
|
+
}
|
|
1190
|
+
return void 0;
|
|
1191
|
+
}
|
|
1192
|
+
async function exportPiSession(conversationId) {
|
|
1193
|
+
const file = await findPiSessionFile(conversationId);
|
|
1194
|
+
if (!file) {
|
|
1195
|
+
throw new Error(
|
|
1196
|
+
`pi: no session file for conversation "${conversationId}" under ${piSessionsDir()}.`
|
|
1197
|
+
);
|
|
1198
|
+
}
|
|
1199
|
+
const stream = createReadStream(file, { encoding: "utf8" });
|
|
1200
|
+
const rl = createInterface({ input: stream, crlfDelay: Infinity });
|
|
1201
|
+
const messages = [];
|
|
1202
|
+
let toolCallCount = 0;
|
|
1203
|
+
let startedAt;
|
|
1204
|
+
let model;
|
|
1205
|
+
for await (const line of rl) {
|
|
1206
|
+
const trimmed = line.trim();
|
|
1207
|
+
if (!trimmed) continue;
|
|
1208
|
+
let entry;
|
|
1209
|
+
try {
|
|
1210
|
+
entry = JSON.parse(trimmed);
|
|
1211
|
+
} catch {
|
|
1212
|
+
continue;
|
|
1213
|
+
}
|
|
1214
|
+
if (entry.type === "session") {
|
|
1215
|
+
startedAt = entry.timestamp;
|
|
1216
|
+
continue;
|
|
1217
|
+
}
|
|
1218
|
+
if (entry.type === "model_change") {
|
|
1219
|
+
model = entry.provider ? `${entry.provider}/${entry.modelId ?? ""}` : entry.modelId;
|
|
1220
|
+
continue;
|
|
1221
|
+
}
|
|
1222
|
+
if (entry.type !== "message" || !entry.message) continue;
|
|
1223
|
+
const m = entry.message;
|
|
1224
|
+
const content = m.content;
|
|
1225
|
+
if (m.role === "toolResult") {
|
|
1226
|
+
const text2 = piBlocksText(content);
|
|
1227
|
+
messages.push({
|
|
1228
|
+
role: "tool",
|
|
1229
|
+
text: m.isError ? `[error] ${text2}` : text2,
|
|
1230
|
+
...m.toolName ? { toolName: m.toolName } : {}
|
|
1231
|
+
});
|
|
1232
|
+
continue;
|
|
1233
|
+
}
|
|
1234
|
+
const role = m.role === "assistant" ? "assistant" : "user";
|
|
1235
|
+
let text = "";
|
|
1236
|
+
let reasoning = "";
|
|
1237
|
+
const toolCalls = [];
|
|
1238
|
+
if (typeof content === "string") {
|
|
1239
|
+
text = content;
|
|
1240
|
+
} else if (Array.isArray(content)) {
|
|
1241
|
+
for (const raw of content) {
|
|
1242
|
+
if (!raw || typeof raw !== "object") continue;
|
|
1243
|
+
const part = raw;
|
|
1244
|
+
if (part.type === "text" && part.text) text += part.text;
|
|
1245
|
+
else if (part.type === "thinking" && part.thinking) reasoning += part.thinking;
|
|
1246
|
+
else if (part.type === "toolCall") {
|
|
1247
|
+
toolCalls.push({ name: part.name ?? "tool", args: JSON.stringify(part.arguments ?? {}) });
|
|
1248
|
+
toolCallCount += 1;
|
|
1249
|
+
}
|
|
1250
|
+
}
|
|
1251
|
+
}
|
|
1252
|
+
if (text.trim() || reasoning.trim() || toolCalls.length) {
|
|
1253
|
+
const em = { role };
|
|
1254
|
+
if (text.trim()) em.text = text.trim();
|
|
1255
|
+
if (reasoning.trim()) em.reasoning = reasoning.trim();
|
|
1256
|
+
if (toolCalls.length) em.toolCalls = toolCalls;
|
|
1257
|
+
messages.push(em);
|
|
1258
|
+
}
|
|
1259
|
+
}
|
|
1260
|
+
const meta = { source: "pi" };
|
|
1261
|
+
if (startedAt) meta.startedAt = startedAt;
|
|
1262
|
+
if (model) meta.model = model;
|
|
1263
|
+
meta.messageCount = messages.length;
|
|
1264
|
+
meta.toolCallCount = toolCallCount;
|
|
1265
|
+
return { meta, messages };
|
|
1266
|
+
}
|
|
1267
|
+
async function discoverPiSessions(cwd, since, until, expectedId) {
|
|
1268
|
+
const files = await walkPiSessionFiles(piSessionsDir());
|
|
1269
|
+
const sinceMs = since ? Date.parse(since) : NaN;
|
|
1270
|
+
const untilMs = until ? Date.parse(until) : NaN;
|
|
1271
|
+
const scored = [];
|
|
1272
|
+
for (const f of files) {
|
|
1273
|
+
let mtimeMs;
|
|
1274
|
+
try {
|
|
1275
|
+
mtimeMs = (await promises.stat(f)).mtimeMs;
|
|
1276
|
+
} catch {
|
|
1277
|
+
continue;
|
|
1278
|
+
}
|
|
1279
|
+
if (Number.isFinite(sinceMs) && mtimeMs < sinceMs - 1e3) continue;
|
|
1280
|
+
const first = await readFirstJsonLine(f);
|
|
1281
|
+
if (!first) continue;
|
|
1282
|
+
let meta;
|
|
1283
|
+
try {
|
|
1284
|
+
meta = JSON.parse(first);
|
|
1285
|
+
} catch {
|
|
1286
|
+
continue;
|
|
1287
|
+
}
|
|
1288
|
+
if (meta.type !== "session" || !meta.id) continue;
|
|
1289
|
+
if (expectedId) {
|
|
1290
|
+
if (meta.id !== expectedId) continue;
|
|
1291
|
+
} else if (meta.cwd !== cwd) {
|
|
1292
|
+
continue;
|
|
1293
|
+
}
|
|
1294
|
+
const startedAt = meta.timestamp;
|
|
1295
|
+
if (Number.isFinite(untilMs) && startedAt) {
|
|
1296
|
+
const s = Date.parse(startedAt);
|
|
1297
|
+
if (Number.isFinite(s) && s > untilMs) continue;
|
|
1298
|
+
}
|
|
1299
|
+
scored.push({
|
|
1300
|
+
candidate: {
|
|
1301
|
+
conversationId: meta.id,
|
|
1302
|
+
...startedAt ? { startedAt } : {},
|
|
1303
|
+
lastActivityAt: new Date(mtimeMs).toISOString()
|
|
1304
|
+
},
|
|
1305
|
+
mtimeMs
|
|
1306
|
+
});
|
|
1307
|
+
}
|
|
1308
|
+
scored.sort((a, b) => b.mtimeMs - a.mtimeMs);
|
|
1309
|
+
return scored.map((s) => s.candidate);
|
|
1310
|
+
}
|
|
643
1311
|
async function exportAgentSession(input) {
|
|
644
1312
|
const { sessionId, registry, format = "markdown", maxToolChars = 1200 } = input;
|
|
645
1313
|
const source = input.source ?? "auto";
|
|
@@ -735,6 +1403,18 @@ var init_transcript_export = __esm({
|
|
|
735
1403
|
},
|
|
736
1404
|
hermes: {
|
|
737
1405
|
exportSession: (id) => exportHermesSession(id)
|
|
1406
|
+
},
|
|
1407
|
+
codex: {
|
|
1408
|
+
exportSession: (id) => exportCodexSession(id)
|
|
1409
|
+
},
|
|
1410
|
+
opencode: {
|
|
1411
|
+
exportSession: (id) => exportOpenCodeSession(id)
|
|
1412
|
+
},
|
|
1413
|
+
"mastracode-inprocess": {
|
|
1414
|
+
exportSession: (id) => exportMastracodeInprocessSession(id)
|
|
1415
|
+
},
|
|
1416
|
+
pi: {
|
|
1417
|
+
exportSession: (id) => exportPiSession(id)
|
|
738
1418
|
}
|
|
739
1419
|
};
|
|
740
1420
|
}
|
|
@@ -862,6 +1542,38 @@ async function readHermes(conversationId) {
|
|
|
862
1542
|
const { exportHermesSession: exportHermesSession2 } = await Promise.resolve().then(() => (init_transcript_export(), transcript_export_exports));
|
|
863
1543
|
return exportHermesSession2(conversationId);
|
|
864
1544
|
}
|
|
1545
|
+
async function discoverCodex(input) {
|
|
1546
|
+
const { discoverCodexSessions: discoverCodexSessions2 } = await Promise.resolve().then(() => (init_transcript_export(), transcript_export_exports));
|
|
1547
|
+
return discoverCodexSessions2(input.cwd, input.since, input.until, input.expectedId);
|
|
1548
|
+
}
|
|
1549
|
+
async function readCodex(conversationId) {
|
|
1550
|
+
const { exportCodexSession: exportCodexSession2 } = await Promise.resolve().then(() => (init_transcript_export(), transcript_export_exports));
|
|
1551
|
+
return exportCodexSession2(conversationId);
|
|
1552
|
+
}
|
|
1553
|
+
async function discoverOpenCode(input) {
|
|
1554
|
+
const { discoverOpenCodeSessions: discoverOpenCodeSessions2 } = await Promise.resolve().then(() => (init_transcript_export(), transcript_export_exports));
|
|
1555
|
+
return discoverOpenCodeSessions2(input.cwd, input.since, input.expectedId);
|
|
1556
|
+
}
|
|
1557
|
+
async function readOpenCode(conversationId) {
|
|
1558
|
+
const { exportOpenCodeSession: exportOpenCodeSession2 } = await Promise.resolve().then(() => (init_transcript_export(), transcript_export_exports));
|
|
1559
|
+
return exportOpenCodeSession2(conversationId);
|
|
1560
|
+
}
|
|
1561
|
+
async function discoverMastracodeInprocess(input) {
|
|
1562
|
+
const { discoverMastracodeInprocessSessions: discoverMastracodeInprocessSessions2 } = await Promise.resolve().then(() => (init_transcript_export(), transcript_export_exports));
|
|
1563
|
+
return discoverMastracodeInprocessSessions2(input.cwd, input.since, input.expectedId);
|
|
1564
|
+
}
|
|
1565
|
+
async function readMastracodeInprocess(conversationId) {
|
|
1566
|
+
const { exportMastracodeInprocessSession: exportMastracodeInprocessSession2 } = await Promise.resolve().then(() => (init_transcript_export(), transcript_export_exports));
|
|
1567
|
+
return exportMastracodeInprocessSession2(conversationId);
|
|
1568
|
+
}
|
|
1569
|
+
async function discoverPi(input) {
|
|
1570
|
+
const { discoverPiSessions: discoverPiSessions2 } = await Promise.resolve().then(() => (init_transcript_export(), transcript_export_exports));
|
|
1571
|
+
return discoverPiSessions2(input.cwd, input.since, input.until, input.expectedId);
|
|
1572
|
+
}
|
|
1573
|
+
async function readPi(conversationId) {
|
|
1574
|
+
const { exportPiSession: exportPiSession2 } = await Promise.resolve().then(() => (init_transcript_export(), transcript_export_exports));
|
|
1575
|
+
return exportPiSession2(conversationId);
|
|
1576
|
+
}
|
|
865
1577
|
var CONVERSATION_STORES;
|
|
866
1578
|
var init_conversation_store = __esm({
|
|
867
1579
|
"src/conversation-store.ts"() {
|
|
@@ -885,6 +1597,28 @@ var init_conversation_store = __esm({
|
|
|
885
1597
|
attachArgv: (conversationId) => ["hermes", "--resume", conversationId, "--tui"],
|
|
886
1598
|
discover: discoverHermes,
|
|
887
1599
|
read: readHermes
|
|
1600
|
+
},
|
|
1601
|
+
// codex-acp writes no resume flag we sniff, and there's no native PTY
|
|
1602
|
+
// reattach argv to declare — export/read only, so no outputHint/attachArgv.
|
|
1603
|
+
codex: {
|
|
1604
|
+
storeAs: "codexResumeId",
|
|
1605
|
+
discover: discoverCodex,
|
|
1606
|
+
read: readCodex
|
|
1607
|
+
},
|
|
1608
|
+
opencode: {
|
|
1609
|
+
storeAs: "openCodeResumeId",
|
|
1610
|
+
discover: discoverOpenCode,
|
|
1611
|
+
read: readOpenCode
|
|
1612
|
+
},
|
|
1613
|
+
"mastracode-inprocess": {
|
|
1614
|
+
storeAs: "mastracodeInprocessResumeId",
|
|
1615
|
+
discover: discoverMastracodeInprocess,
|
|
1616
|
+
read: readMastracodeInprocess
|
|
1617
|
+
},
|
|
1618
|
+
pi: {
|
|
1619
|
+
storeAs: "piResumeId",
|
|
1620
|
+
discover: discoverPi,
|
|
1621
|
+
read: readPi
|
|
888
1622
|
}
|
|
889
1623
|
};
|
|
890
1624
|
}
|
|
@@ -892,37 +1626,34 @@ var init_conversation_store = __esm({
|
|
|
892
1626
|
|
|
893
1627
|
// src/resume-strategies.ts
|
|
894
1628
|
init_conversation_store();
|
|
895
|
-
var
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
// openclaw: { storeAs: "openClawResumeId", ... }
|
|
917
|
-
// opencode: { storeAs: "openCodeResumeId", ... }
|
|
918
|
-
};
|
|
1629
|
+
var RESUME_STRATEGIES = Object.fromEntries(
|
|
1630
|
+
Object.entries(CONVERSATION_STORES).filter(([, store]) => typeof store.attachArgv === "function").map(([slug, store]) => {
|
|
1631
|
+
const s = store;
|
|
1632
|
+
return [
|
|
1633
|
+
slug,
|
|
1634
|
+
{
|
|
1635
|
+
outputHint: store.outputHint,
|
|
1636
|
+
storeAs: store.storeAs,
|
|
1637
|
+
fsProbe: async (cwd, prevStartedAt, expectedId) => {
|
|
1638
|
+
const candidates = await s.discover({
|
|
1639
|
+
cwd,
|
|
1640
|
+
since: prevStartedAt,
|
|
1641
|
+
expectedId
|
|
1642
|
+
});
|
|
1643
|
+
return candidates[0]?.conversationId ?? null;
|
|
1644
|
+
},
|
|
1645
|
+
spawnArgs: s.attachArgv
|
|
1646
|
+
}
|
|
1647
|
+
];
|
|
1648
|
+
})
|
|
1649
|
+
);
|
|
919
1650
|
function hasResumeStrategy(adapterSlug) {
|
|
920
1651
|
if (!adapterSlug) return false;
|
|
921
1652
|
const s = RESUME_STRATEGIES[adapterSlug];
|
|
922
1653
|
return !!(s && (s.outputHint || s.fsProbe || s.spawnArgs));
|
|
923
1654
|
}
|
|
924
1655
|
function decideRestartStrategy(prev) {
|
|
925
|
-
if (prev.adapterSlug) {
|
|
1656
|
+
if (prev.adapterSlug && prev.nativeTerminalResume === true) {
|
|
926
1657
|
const strategy = RESUME_STRATEGIES[prev.adapterSlug];
|
|
927
1658
|
const id = strategy?.storeAs ? prev.resumeMetadata?.[strategy.storeAs] : void 0;
|
|
928
1659
|
if (strategy?.spawnArgs && id) {
|
|
@@ -933,9 +1664,11 @@ function decideRestartStrategy(prev) {
|
|
|
933
1664
|
return { kind: "pty-plain" };
|
|
934
1665
|
}
|
|
935
1666
|
if (prev.adapterSlug) {
|
|
1667
|
+
const canResumeAtAcpLevel = prev.resumable !== false;
|
|
936
1668
|
return {
|
|
937
1669
|
kind: "agent",
|
|
938
|
-
...prev.adapterSessionId ? { resumeSessionId: prev.adapterSessionId } : {}
|
|
1670
|
+
...prev.adapterSessionId && canResumeAtAcpLevel ? { resumeSessionId: prev.adapterSessionId } : {},
|
|
1671
|
+
...prev.adapterSessionId && !canResumeAtAcpLevel ? { resumeFallback: true } : {}
|
|
939
1672
|
};
|
|
940
1673
|
}
|
|
941
1674
|
return {
|
|
@@ -943,6 +1676,7 @@ function decideRestartStrategy(prev) {
|
|
|
943
1676
|
reason: "generic command session \u2014 restart only supports pty + agent-cli"
|
|
944
1677
|
};
|
|
945
1678
|
}
|
|
1679
|
+
var RESUME_ID_REJECTED_RE = /not found|does not support|not supported|unsupported/i;
|
|
946
1680
|
async function augmentWithFsResume(prev) {
|
|
947
1681
|
const slug = prev.adapterSlug;
|
|
948
1682
|
if (!slug) return prev;
|
|
@@ -973,6 +1707,9 @@ function describeResumePath(prev) {
|
|
|
973
1707
|
}
|
|
974
1708
|
}
|
|
975
1709
|
if (prev.adapterSlug && prev.adapterSessionId) {
|
|
1710
|
+
if (prev.resumable === false) {
|
|
1711
|
+
return `fresh \u2014 resume not supported by ${prev.adapterSlug}`;
|
|
1712
|
+
}
|
|
976
1713
|
return "resumed via ACP";
|
|
977
1714
|
}
|
|
978
1715
|
return "";
|
|
@@ -1005,6 +1742,6 @@ function tokenizeCommand(s) {
|
|
|
1005
1742
|
return out;
|
|
1006
1743
|
}
|
|
1007
1744
|
|
|
1008
|
-
export { RESUME_STRATEGIES, augmentWithFsResume, decideRestartStrategy, describeResumePath, hasResumeStrategy, tokenizeCommand };
|
|
1745
|
+
export { RESUME_ID_REJECTED_RE, RESUME_STRATEGIES, augmentWithFsResume, decideRestartStrategy, describeResumePath, hasResumeStrategy, tokenizeCommand };
|
|
1009
1746
|
//# sourceMappingURL=resume-strategies.mjs.map
|
|
1010
1747
|
//# sourceMappingURL=resume-strategies.mjs.map
|