@cydm/pie 1.0.36 → 1.0.37
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +346 -60
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -46565,6 +46565,165 @@ function parseModelsCommandArgs(args) {
|
|
|
46565
46565
|
|
|
46566
46566
|
// src/commands/sessions.ts
|
|
46567
46567
|
import fs6 from "node:fs";
|
|
46568
|
+
|
|
46569
|
+
// src/session-control.ts
|
|
46570
|
+
var SessionControlError = class extends Error {
|
|
46571
|
+
constructor(code, message, recoverable = sessionControlErrorRecoverable(code)) {
|
|
46572
|
+
super(message);
|
|
46573
|
+
this.code = code;
|
|
46574
|
+
this.recoverable = recoverable;
|
|
46575
|
+
this.name = "SessionControlError";
|
|
46576
|
+
}
|
|
46577
|
+
code;
|
|
46578
|
+
recoverable;
|
|
46579
|
+
};
|
|
46580
|
+
function sessionControlErrorRecoverable(code) {
|
|
46581
|
+
return code !== "session_unrecoverable" && code !== "session_mismatch";
|
|
46582
|
+
}
|
|
46583
|
+
async function loadRequiredSession(store, sessionId) {
|
|
46584
|
+
const exists = await store.exists(sessionId);
|
|
46585
|
+
const data = await store.load(sessionId);
|
|
46586
|
+
if (data) return data;
|
|
46587
|
+
throw new SessionControlError(
|
|
46588
|
+
exists ? "session_unrecoverable" : "session_not_found",
|
|
46589
|
+
exists ? `Session could not be recovered: ${sessionId}` : `Session not found: ${sessionId}`
|
|
46590
|
+
);
|
|
46591
|
+
}
|
|
46592
|
+
async function rewindStoredSession(params) {
|
|
46593
|
+
const data = await loadRequiredSession(params.store, params.sessionId);
|
|
46594
|
+
if (!data.entries.some((entry) => entry.id === params.entryId)) {
|
|
46595
|
+
throw new SessionControlError("checkpoint_not_found", `Entry not found: ${params.entryId}`);
|
|
46596
|
+
}
|
|
46597
|
+
try {
|
|
46598
|
+
await params.store.save(params.sessionId, data.entries, {
|
|
46599
|
+
...data.metadata,
|
|
46600
|
+
activeEntryId: params.entryId,
|
|
46601
|
+
updatedAt: params.now ?? Date.now()
|
|
46602
|
+
});
|
|
46603
|
+
const metadata = await params.store.getMetadata(params.sessionId);
|
|
46604
|
+
if (!metadata) {
|
|
46605
|
+
throw new SessionControlError("session_unrecoverable", `Session could not be recovered after rewind: ${params.sessionId}`, false);
|
|
46606
|
+
}
|
|
46607
|
+
return {
|
|
46608
|
+
sessionId: params.sessionId,
|
|
46609
|
+
entryId: params.entryId,
|
|
46610
|
+
checkpointId: params.entryId,
|
|
46611
|
+
activeEntryId: params.entryId,
|
|
46612
|
+
headEntryId: params.entryId,
|
|
46613
|
+
metadata
|
|
46614
|
+
};
|
|
46615
|
+
} catch (error) {
|
|
46616
|
+
if (error instanceof SessionControlError) throw error;
|
|
46617
|
+
throw new SessionControlError("session_io_error", error instanceof Error ? error.message : String(error));
|
|
46618
|
+
}
|
|
46619
|
+
}
|
|
46620
|
+
async function forkStoredSession(params) {
|
|
46621
|
+
try {
|
|
46622
|
+
const existingTarget = await maybeLoadExistingForkTarget(params);
|
|
46623
|
+
if (existingTarget) return existingTarget;
|
|
46624
|
+
const source = await loadRequiredSession(params.store, params.sourceSessionId);
|
|
46625
|
+
const pathEntries = pathToEntry(source, params.sourceEntryId);
|
|
46626
|
+
if (pathEntries.length === 0 || pathEntries[pathEntries.length - 1]?.id !== params.sourceEntryId) {
|
|
46627
|
+
throw new SessionControlError("checkpoint_not_found", `Entry not found: ${params.sourceEntryId}`);
|
|
46628
|
+
}
|
|
46629
|
+
const now = params.now ?? Date.now();
|
|
46630
|
+
const idMap = /* @__PURE__ */ new Map();
|
|
46631
|
+
for (const entry of pathEntries) idMap.set(entry.id, generateEntryId());
|
|
46632
|
+
const forkedEntries = pathEntries.map((entry) => {
|
|
46633
|
+
const nextId = idMap.get(entry.id);
|
|
46634
|
+
if (!nextId) throw new SessionControlError("session_io_error", `Failed to map entry: ${entry.id}`);
|
|
46635
|
+
const parentId = entry.parentId ? idMap.get(entry.parentId) ?? null : null;
|
|
46636
|
+
return {
|
|
46637
|
+
...cloneJson(entry),
|
|
46638
|
+
id: nextId,
|
|
46639
|
+
parentId,
|
|
46640
|
+
timestamp: entry.timestamp
|
|
46641
|
+
};
|
|
46642
|
+
});
|
|
46643
|
+
const activeEntryId = idMap.get(params.sourceEntryId);
|
|
46644
|
+
if (!activeEntryId) {
|
|
46645
|
+
throw new SessionControlError("session_io_error", `Failed to map active entry: ${params.sourceEntryId}`);
|
|
46646
|
+
}
|
|
46647
|
+
await params.store.save(params.targetSessionId, forkedEntries, {
|
|
46648
|
+
name: params.name,
|
|
46649
|
+
createdAt: now,
|
|
46650
|
+
updatedAt: now,
|
|
46651
|
+
activeEntryId,
|
|
46652
|
+
cwd: params.cwd ?? source.metadata.cwd,
|
|
46653
|
+
sourceSessionId: params.sourceSessionId,
|
|
46654
|
+
sourceEntryId: params.sourceEntryId,
|
|
46655
|
+
sourceActiveEntryId: source.metadata.activeEntryId ?? void 0,
|
|
46656
|
+
forkBaseEntryId: activeEntryId,
|
|
46657
|
+
...params.requestId ? { sessionControlRequestId: params.requestId } : {}
|
|
46658
|
+
});
|
|
46659
|
+
const metadata = await params.store.getMetadata(params.targetSessionId);
|
|
46660
|
+
if (!metadata) {
|
|
46661
|
+
throw new SessionControlError("session_unrecoverable", `Session could not be recovered after fork: ${params.targetSessionId}`, false);
|
|
46662
|
+
}
|
|
46663
|
+
return buildForkResult({
|
|
46664
|
+
metadata,
|
|
46665
|
+
sourceSessionId: params.sourceSessionId,
|
|
46666
|
+
sourceEntryId: params.sourceEntryId,
|
|
46667
|
+
sourceActiveEntryId: source.metadata.activeEntryId ?? null
|
|
46668
|
+
});
|
|
46669
|
+
} catch (error) {
|
|
46670
|
+
if (error instanceof SessionControlError) throw error;
|
|
46671
|
+
throw new SessionControlError("session_io_error", error instanceof Error ? error.message : String(error));
|
|
46672
|
+
}
|
|
46673
|
+
}
|
|
46674
|
+
async function maybeLoadExistingForkTarget(params) {
|
|
46675
|
+
if (!await params.store.exists(params.targetSessionId)) return null;
|
|
46676
|
+
const target = await params.store.load(params.targetSessionId);
|
|
46677
|
+
if (!target) {
|
|
46678
|
+
throw new SessionControlError("session_unrecoverable", `Session could not be recovered: ${params.targetSessionId}`, false);
|
|
46679
|
+
}
|
|
46680
|
+
const metadata = target.metadata;
|
|
46681
|
+
if (params.requestId && metadata.sessionControlRequestId === params.requestId && metadata.sourceSessionId === params.sourceSessionId && metadata.sourceEntryId === params.sourceEntryId && typeof metadata.forkBaseEntryId === "string" && metadata.activeEntryId === metadata.forkBaseEntryId) {
|
|
46682
|
+
return buildForkResult({
|
|
46683
|
+
metadata,
|
|
46684
|
+
sourceSessionId: params.sourceSessionId,
|
|
46685
|
+
sourceEntryId: params.sourceEntryId,
|
|
46686
|
+
sourceActiveEntryId: typeof metadata.sourceActiveEntryId === "string" ? metadata.sourceActiveEntryId : null
|
|
46687
|
+
});
|
|
46688
|
+
}
|
|
46689
|
+
throw new SessionControlError("target_exists", `Target session already exists: ${params.targetSessionId}`);
|
|
46690
|
+
}
|
|
46691
|
+
function buildForkResult(params) {
|
|
46692
|
+
const targetActiveEntryId = params.metadata.activeEntryId;
|
|
46693
|
+
if (!targetActiveEntryId) {
|
|
46694
|
+
throw new SessionControlError("session_unrecoverable", `Fork target has no active entry: ${params.metadata.id}`, false);
|
|
46695
|
+
}
|
|
46696
|
+
const forkBaseEntryId = typeof params.metadata.forkBaseEntryId === "string" ? params.metadata.forkBaseEntryId : targetActiveEntryId;
|
|
46697
|
+
return {
|
|
46698
|
+
sourceSessionId: params.sourceSessionId,
|
|
46699
|
+
sourceEntryId: params.sourceEntryId,
|
|
46700
|
+
sourceCheckpointId: params.sourceEntryId,
|
|
46701
|
+
targetSessionId: params.metadata.id,
|
|
46702
|
+
targetActiveEntryId,
|
|
46703
|
+
targetHeadEntryId: targetActiveEntryId,
|
|
46704
|
+
headEntryId: targetActiveEntryId,
|
|
46705
|
+
sourceActiveEntryId: params.sourceActiveEntryId,
|
|
46706
|
+
forkBaseEntryId,
|
|
46707
|
+
metadata: params.metadata
|
|
46708
|
+
};
|
|
46709
|
+
}
|
|
46710
|
+
function pathToEntry(data, entryId) {
|
|
46711
|
+
const byId = new Map(data.entries.map((entry) => [entry.id, entry]));
|
|
46712
|
+
const path31 = [];
|
|
46713
|
+
let current = entryId;
|
|
46714
|
+
while (current) {
|
|
46715
|
+
const entry = byId.get(current);
|
|
46716
|
+
if (!entry) return [];
|
|
46717
|
+
path31.unshift(entry);
|
|
46718
|
+
current = entry.parentId;
|
|
46719
|
+
}
|
|
46720
|
+
return path31;
|
|
46721
|
+
}
|
|
46722
|
+
function cloneJson(value) {
|
|
46723
|
+
return JSON.parse(JSON.stringify(value));
|
|
46724
|
+
}
|
|
46725
|
+
|
|
46726
|
+
// src/commands/sessions.ts
|
|
46568
46727
|
async function runSessionsCommand(args) {
|
|
46569
46728
|
const command = args[0] || "help";
|
|
46570
46729
|
const rest = args.slice(1);
|
|
@@ -46691,17 +46850,12 @@ async function rewindSession(args) {
|
|
|
46691
46850
|
const entryId = stringFlag(args, "--to");
|
|
46692
46851
|
if (!sessionId || !entryId) throw new Error("Usage: pie sessions rewind <sessionId> --to <entryId> [--json]");
|
|
46693
46852
|
const store = new FileSessionStore(getSessionsDir());
|
|
46694
|
-
const
|
|
46695
|
-
if (!data) throw new Error(`Session not found: ${sessionId}`);
|
|
46696
|
-
if (!data.entries.some((entry) => entry.id === entryId)) throw new Error(`Entry not found: ${entryId}`);
|
|
46697
|
-
await store.save(sessionId, data.entries, { ...data.metadata, activeEntryId: entryId, updatedAt: Date.now() });
|
|
46698
|
-
const updated = await store.getMetadata(sessionId);
|
|
46699
|
-
if (!updated) throw new Error(`Session not found after rewind: ${sessionId}`);
|
|
46853
|
+
const result = await rewindStoredSession({ store, sessionId, entryId });
|
|
46700
46854
|
const response = {
|
|
46701
46855
|
ok: true,
|
|
46702
|
-
session: sessionSummary(
|
|
46703
|
-
activeEntryId:
|
|
46704
|
-
currentHead:
|
|
46856
|
+
session: sessionSummary(result.metadata),
|
|
46857
|
+
activeEntryId: result.activeEntryId,
|
|
46858
|
+
currentHead: result.headEntryId
|
|
46705
46859
|
};
|
|
46706
46860
|
if (json) {
|
|
46707
46861
|
console.log(JSON.stringify(response, null, 2));
|
|
@@ -46720,50 +46874,23 @@ async function forkSession(args) {
|
|
|
46720
46874
|
throw new Error("Usage: pie sessions fork <sessionId> --from <entryId> --target <newSessionId> --name <name> [--cwd <path>] [--json]");
|
|
46721
46875
|
}
|
|
46722
46876
|
const store = new FileSessionStore(getSessionsDir());
|
|
46723
|
-
const
|
|
46724
|
-
|
|
46725
|
-
if (await store.exists(targetSessionId)) throw new Error(`Target session already exists: ${targetSessionId}`);
|
|
46726
|
-
const pathEntries = pathToEntry(source, sourceEntryId);
|
|
46727
|
-
if (pathEntries.length === 0 || pathEntries[pathEntries.length - 1]?.id !== sourceEntryId) {
|
|
46728
|
-
throw new Error(`Entry not found: ${sourceEntryId}`);
|
|
46729
|
-
}
|
|
46730
|
-
const now = Date.now();
|
|
46731
|
-
const idMap = /* @__PURE__ */ new Map();
|
|
46732
|
-
for (const entry of pathEntries) idMap.set(entry.id, generateEntryId());
|
|
46733
|
-
const forkedEntries = pathEntries.map((entry) => {
|
|
46734
|
-
const nextId = idMap.get(entry.id);
|
|
46735
|
-
if (!nextId) throw new Error(`Failed to map entry: ${entry.id}`);
|
|
46736
|
-
const parentId = entry.parentId ? idMap.get(entry.parentId) ?? null : null;
|
|
46737
|
-
return {
|
|
46738
|
-
...cloneJson(entry),
|
|
46739
|
-
id: nextId,
|
|
46740
|
-
parentId,
|
|
46741
|
-
timestamp: entry.timestamp
|
|
46742
|
-
};
|
|
46743
|
-
});
|
|
46744
|
-
const activeEntryId = idMap.get(sourceEntryId) ?? null;
|
|
46745
|
-
await store.save(targetSessionId, forkedEntries, {
|
|
46746
|
-
name,
|
|
46747
|
-
createdAt: now,
|
|
46748
|
-
updatedAt: now,
|
|
46749
|
-
activeEntryId,
|
|
46750
|
-
cwd: cwd ?? source.metadata.cwd,
|
|
46877
|
+
const result = await forkStoredSession({
|
|
46878
|
+
store,
|
|
46751
46879
|
sourceSessionId,
|
|
46752
46880
|
sourceEntryId,
|
|
46753
|
-
|
|
46754
|
-
|
|
46881
|
+
targetSessionId,
|
|
46882
|
+
name,
|
|
46883
|
+
cwd
|
|
46755
46884
|
});
|
|
46756
|
-
const updated = await store.getMetadata(targetSessionId);
|
|
46757
|
-
if (!updated) throw new Error(`Session not found after fork: ${targetSessionId}`);
|
|
46758
46885
|
const response = {
|
|
46759
46886
|
ok: true,
|
|
46760
|
-
session: sessionSummary(
|
|
46887
|
+
session: sessionSummary(result.metadata),
|
|
46761
46888
|
sourceSessionId,
|
|
46762
46889
|
sourceEntryId,
|
|
46763
|
-
sourceActiveEntryId:
|
|
46764
|
-
forkBaseEntryId:
|
|
46765
|
-
activeEntryId,
|
|
46766
|
-
currentHead:
|
|
46890
|
+
sourceActiveEntryId: result.sourceActiveEntryId,
|
|
46891
|
+
forkBaseEntryId: result.forkBaseEntryId,
|
|
46892
|
+
activeEntryId: result.targetActiveEntryId,
|
|
46893
|
+
currentHead: result.targetHeadEntryId
|
|
46767
46894
|
};
|
|
46768
46895
|
if (json) {
|
|
46769
46896
|
console.log(JSON.stringify(response, null, 2));
|
|
@@ -46856,7 +46983,7 @@ function activeTranscriptEvents(entries) {
|
|
|
46856
46983
|
role,
|
|
46857
46984
|
turnId,
|
|
46858
46985
|
content: textFromMessage(entry.message),
|
|
46859
|
-
message: entry.message ?
|
|
46986
|
+
message: entry.message ? cloneJson2(entry.message) : void 0
|
|
46860
46987
|
};
|
|
46861
46988
|
});
|
|
46862
46989
|
}
|
|
@@ -46879,18 +47006,6 @@ function activePathEntries(data) {
|
|
|
46879
47006
|
if (!activeEntryId) return [];
|
|
46880
47007
|
return pathToEntry(data, activeEntryId);
|
|
46881
47008
|
}
|
|
46882
|
-
function pathToEntry(data, entryId) {
|
|
46883
|
-
const byId = new Map(data.entries.map((entry) => [entry.id, entry]));
|
|
46884
|
-
const path31 = [];
|
|
46885
|
-
let current = entryId;
|
|
46886
|
-
while (current) {
|
|
46887
|
-
const entry = byId.get(current);
|
|
46888
|
-
if (!entry) return [];
|
|
46889
|
-
path31.unshift(entry);
|
|
46890
|
-
current = entry.parentId;
|
|
46891
|
-
}
|
|
46892
|
-
return path31;
|
|
46893
|
-
}
|
|
46894
47009
|
function resolveBeforeCursor(events, cursor) {
|
|
46895
47010
|
if (!cursor) return events.length;
|
|
46896
47011
|
const numeric = Number(cursor);
|
|
@@ -46900,7 +47015,7 @@ function resolveBeforeCursor(events, cursor) {
|
|
|
46900
47015
|
const index = events.findIndex((event) => event.entryId === cursor || event.checkpointId === cursor);
|
|
46901
47016
|
return index >= 0 ? index : events.length;
|
|
46902
47017
|
}
|
|
46903
|
-
function
|
|
47018
|
+
function cloneJson2(value) {
|
|
46904
47019
|
return JSON.parse(JSON.stringify(value));
|
|
46905
47020
|
}
|
|
46906
47021
|
function listCursorQueryKey(input) {
|
|
@@ -70224,6 +70339,26 @@ function parseInput(line) {
|
|
|
70224
70339
|
reason: typeof parsed.reason === "string" ? parsed.reason : void 0
|
|
70225
70340
|
};
|
|
70226
70341
|
}
|
|
70342
|
+
if (parsed.type === "session.rewind") {
|
|
70343
|
+
return {
|
|
70344
|
+
type: "session.rewind",
|
|
70345
|
+
sessionId: typeof parsed.sessionId === "string" ? parsed.sessionId : void 0,
|
|
70346
|
+
requestId: typeof parsed.requestId === "string" ? parsed.requestId : void 0,
|
|
70347
|
+
entryId: typeof parsed.entryId === "string" ? parsed.entryId : void 0,
|
|
70348
|
+
checkpointId: typeof parsed.checkpointId === "string" ? parsed.checkpointId : void 0
|
|
70349
|
+
};
|
|
70350
|
+
}
|
|
70351
|
+
if (parsed.type === "session.fork") {
|
|
70352
|
+
return {
|
|
70353
|
+
type: "session.fork",
|
|
70354
|
+
sessionId: typeof parsed.sessionId === "string" ? parsed.sessionId : void 0,
|
|
70355
|
+
requestId: typeof parsed.requestId === "string" ? parsed.requestId : void 0,
|
|
70356
|
+
fromEntryId: typeof parsed.fromEntryId === "string" ? parsed.fromEntryId : void 0,
|
|
70357
|
+
targetSessionId: typeof parsed.targetSessionId === "string" ? parsed.targetSessionId : void 0,
|
|
70358
|
+
name: typeof parsed.name === "string" ? parsed.name : void 0,
|
|
70359
|
+
cwd: typeof parsed.cwd === "string" ? parsed.cwd : void 0
|
|
70360
|
+
};
|
|
70361
|
+
}
|
|
70227
70362
|
if ((parsed.type === "turn.request" || parsed.type === "turn.input") && typeof parsed.turnId === "string" && typeof parsed.prompt === "string") {
|
|
70228
70363
|
const streamingBehavior = parsed.streamingBehavior;
|
|
70229
70364
|
if (streamingBehavior !== void 0 && streamingBehavior !== "steer" && streamingBehavior !== "followUp") {
|
|
@@ -70386,6 +70521,7 @@ async function runJsonEventsMode(params) {
|
|
|
70386
70521
|
let thinkingLevel = "off";
|
|
70387
70522
|
let defaultRuntime;
|
|
70388
70523
|
let defaultModelState;
|
|
70524
|
+
const completedSessionControlRequests = /* @__PURE__ */ new Map();
|
|
70389
70525
|
const noProgressTimeoutMs = Number(process.env.PIE_JSON_EVENTS_NO_PROGRESS_MS || 6e5);
|
|
70390
70526
|
const mockResponseDelayMs = Number(process.env.PIE_TEST_MOCK_RESPONSE_DELAY_MS || 0);
|
|
70391
70527
|
writeEvent({ type: "agent.ready", sessionId });
|
|
@@ -70534,6 +70670,148 @@ async function runJsonEventsMode(params) {
|
|
|
70534
70670
|
}
|
|
70535
70671
|
return error instanceof Error ? error.message : String(error);
|
|
70536
70672
|
}
|
|
70673
|
+
function sessionControlStore() {
|
|
70674
|
+
return new FileSessionStore(runtime?.paths.sessionsDir ?? getSessionsDir());
|
|
70675
|
+
}
|
|
70676
|
+
function invalidSessionControl(message) {
|
|
70677
|
+
return new SessionControlError("invalid_request", message);
|
|
70678
|
+
}
|
|
70679
|
+
function requireSessionControlString(value, field) {
|
|
70680
|
+
const normalized = value?.trim();
|
|
70681
|
+
if (!normalized) {
|
|
70682
|
+
throw invalidSessionControl(`${field} is required`);
|
|
70683
|
+
}
|
|
70684
|
+
return normalized;
|
|
70685
|
+
}
|
|
70686
|
+
function requireSessionControlBase(message) {
|
|
70687
|
+
const requestedSessionId = requireSessionControlString(message.sessionId, "sessionId");
|
|
70688
|
+
const requestId = requireSessionControlString(message.requestId, "requestId");
|
|
70689
|
+
if (requestedSessionId !== sessionId) {
|
|
70690
|
+
throw new SessionControlError("session_mismatch", sessionMismatchError(requestedSessionId), false);
|
|
70691
|
+
}
|
|
70692
|
+
if (activeTurn && !activeTurn.finalized) {
|
|
70693
|
+
throw new SessionControlError("session_busy", `Cannot ${message.type.slice("session.".length)} session while a turn is active`);
|
|
70694
|
+
}
|
|
70695
|
+
return { sessionId: requestedSessionId, requestId };
|
|
70696
|
+
}
|
|
70697
|
+
function resolveRewindEntryId(message) {
|
|
70698
|
+
const entryId = message.entryId?.trim();
|
|
70699
|
+
const checkpointId = message.checkpointId?.trim();
|
|
70700
|
+
if (entryId && checkpointId && entryId !== checkpointId) {
|
|
70701
|
+
throw invalidSessionControl("entryId and checkpointId must match when both are provided");
|
|
70702
|
+
}
|
|
70703
|
+
const resolved = entryId || checkpointId;
|
|
70704
|
+
if (!resolved) {
|
|
70705
|
+
throw invalidSessionControl("entryId or checkpointId is required");
|
|
70706
|
+
}
|
|
70707
|
+
return resolved;
|
|
70708
|
+
}
|
|
70709
|
+
function writeSessionControlFailure(message, operation, error) {
|
|
70710
|
+
const detail = error instanceof SessionControlError ? error : new SessionControlError("session_io_error", error instanceof Error ? error.message : String(error));
|
|
70711
|
+
writeEvent({
|
|
70712
|
+
type: "session.failed",
|
|
70713
|
+
sessionId: message.sessionId || sessionId,
|
|
70714
|
+
requestId: message.requestId,
|
|
70715
|
+
operation,
|
|
70716
|
+
error: detail.message,
|
|
70717
|
+
code: detail.code,
|
|
70718
|
+
recoverable: detail.recoverable
|
|
70719
|
+
});
|
|
70720
|
+
}
|
|
70721
|
+
async function saveRuntimeSessionForControl() {
|
|
70722
|
+
if (!runtime?.sessionManager.getActiveSession()) return;
|
|
70723
|
+
try {
|
|
70724
|
+
await runtime.sessionManager.save();
|
|
70725
|
+
} catch (error) {
|
|
70726
|
+
throw new SessionControlError("session_io_error", error instanceof Error ? error.message : String(error));
|
|
70727
|
+
}
|
|
70728
|
+
}
|
|
70729
|
+
async function syncRuntimeAfterRewind(controlSessionId) {
|
|
70730
|
+
if (params.mockResponse !== void 0) return;
|
|
70731
|
+
if (runtime?.sessionManager.getActiveSessionId() !== controlSessionId) return;
|
|
70732
|
+
const loaded = await runtime.sessionManager.loadSession(controlSessionId, { warnIfMissing: false });
|
|
70733
|
+
if (!loaded) {
|
|
70734
|
+
const exists = await runtime.sessionManager.hasSession(controlSessionId);
|
|
70735
|
+
throw new SessionControlError(
|
|
70736
|
+
exists ? "session_unrecoverable" : "session_not_found",
|
|
70737
|
+
exists ? `Session could not be recovered: ${controlSessionId}` : `Session not found: ${controlSessionId}`,
|
|
70738
|
+
!exists
|
|
70739
|
+
);
|
|
70740
|
+
}
|
|
70741
|
+
controller?.syncFromActiveSession();
|
|
70742
|
+
}
|
|
70743
|
+
async function handleSessionRewind(message) {
|
|
70744
|
+
try {
|
|
70745
|
+
const { sessionId: controlSessionId, requestId } = requireSessionControlBase(message);
|
|
70746
|
+
const cached = completedSessionControlRequests.get(requestId);
|
|
70747
|
+
if (cached) {
|
|
70748
|
+
writeEvent(cached);
|
|
70749
|
+
return;
|
|
70750
|
+
}
|
|
70751
|
+
const entryId = resolveRewindEntryId(message);
|
|
70752
|
+
await saveRuntimeSessionForControl();
|
|
70753
|
+
const result = await rewindStoredSession({
|
|
70754
|
+
store: sessionControlStore(),
|
|
70755
|
+
sessionId: controlSessionId,
|
|
70756
|
+
entryId
|
|
70757
|
+
});
|
|
70758
|
+
await syncRuntimeAfterRewind(controlSessionId);
|
|
70759
|
+
mockActiveEntryId = result.headEntryId;
|
|
70760
|
+
const event = {
|
|
70761
|
+
type: "session.rewound",
|
|
70762
|
+
sessionId: controlSessionId,
|
|
70763
|
+
requestId,
|
|
70764
|
+
entryId: result.entryId,
|
|
70765
|
+
checkpointId: result.checkpointId,
|
|
70766
|
+
headEntryId: result.headEntryId,
|
|
70767
|
+
activeEntryId: result.activeEntryId
|
|
70768
|
+
};
|
|
70769
|
+
completedSessionControlRequests.set(requestId, event);
|
|
70770
|
+
writeEvent(event);
|
|
70771
|
+
} catch (error) {
|
|
70772
|
+
writeSessionControlFailure(message, "rewind", error);
|
|
70773
|
+
}
|
|
70774
|
+
}
|
|
70775
|
+
async function handleSessionFork(message) {
|
|
70776
|
+
try {
|
|
70777
|
+
const { sessionId: controlSessionId, requestId } = requireSessionControlBase(message);
|
|
70778
|
+
const sourceEntryId = requireSessionControlString(message.fromEntryId, "fromEntryId");
|
|
70779
|
+
const targetSessionId = requireSessionControlString(message.targetSessionId, "targetSessionId");
|
|
70780
|
+
const name = requireSessionControlString(message.name, "name");
|
|
70781
|
+
const forkCwd = message.cwd?.trim() || void 0;
|
|
70782
|
+
const cached = completedSessionControlRequests.get(requestId);
|
|
70783
|
+
if (cached) {
|
|
70784
|
+
writeEvent(cached);
|
|
70785
|
+
return;
|
|
70786
|
+
}
|
|
70787
|
+
await saveRuntimeSessionForControl();
|
|
70788
|
+
const result = await forkStoredSession({
|
|
70789
|
+
store: sessionControlStore(),
|
|
70790
|
+
sourceSessionId: controlSessionId,
|
|
70791
|
+
sourceEntryId,
|
|
70792
|
+
targetSessionId,
|
|
70793
|
+
name,
|
|
70794
|
+
cwd: forkCwd,
|
|
70795
|
+
requestId
|
|
70796
|
+
});
|
|
70797
|
+
const event = {
|
|
70798
|
+
type: "session.forked",
|
|
70799
|
+
sessionId: controlSessionId,
|
|
70800
|
+
requestId,
|
|
70801
|
+
sourceSessionId: result.sourceSessionId,
|
|
70802
|
+
sourceEntryId: result.sourceEntryId,
|
|
70803
|
+
sourceCheckpointId: result.sourceCheckpointId,
|
|
70804
|
+
targetSessionId: result.targetSessionId,
|
|
70805
|
+
targetHeadEntryId: result.targetHeadEntryId,
|
|
70806
|
+
targetActiveEntryId: result.targetActiveEntryId,
|
|
70807
|
+
headEntryId: result.headEntryId
|
|
70808
|
+
};
|
|
70809
|
+
completedSessionControlRequests.set(requestId, event);
|
|
70810
|
+
writeEvent(event);
|
|
70811
|
+
} catch (error) {
|
|
70812
|
+
writeSessionControlFailure(message, "fork", error);
|
|
70813
|
+
}
|
|
70814
|
+
}
|
|
70537
70815
|
function finalize(kind, detail) {
|
|
70538
70816
|
const turn = activeTurn;
|
|
70539
70817
|
if (!turn || turn.finalized) return;
|
|
@@ -71169,6 +71447,14 @@ async function runJsonEventsMode(params) {
|
|
|
71169
71447
|
await interrupt(message);
|
|
71170
71448
|
continue;
|
|
71171
71449
|
}
|
|
71450
|
+
if (message.type === "session.rewind") {
|
|
71451
|
+
await handleSessionRewind(message);
|
|
71452
|
+
continue;
|
|
71453
|
+
}
|
|
71454
|
+
if (message.type === "session.fork") {
|
|
71455
|
+
await handleSessionFork(message);
|
|
71456
|
+
continue;
|
|
71457
|
+
}
|
|
71172
71458
|
const shouldTrackTurn = !activeTurn || activeTurn.finalized;
|
|
71173
71459
|
const turnPromise = runTurn(message).catch((error) => {
|
|
71174
71460
|
writeEvent({
|