@cleocode/cleo 2026.3.71 → 2026.3.72
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/index.js +171 -1
- package/dist/cli/index.js.map +4 -4
- package/dist/mcp/index.js +169 -1
- package/dist/mcp/index.js.map +4 -4
- package/package.json +3 -3
package/dist/mcp/index.js
CHANGED
|
@@ -67855,6 +67855,162 @@ var init_bootstrap = __esm({
|
|
|
67855
67855
|
}
|
|
67856
67856
|
});
|
|
67857
67857
|
|
|
67858
|
+
// packages/core/src/sessions/snapshot.ts
|
|
67859
|
+
async function serializeSession(projectRoot, options = {}, accessor) {
|
|
67860
|
+
const acc = accessor ?? await getAccessor(projectRoot);
|
|
67861
|
+
const maxObs = options.maxObservations ?? 10;
|
|
67862
|
+
const maxDescLen = options.maxDescriptionLength ?? 500;
|
|
67863
|
+
const sessions2 = await acc.loadSessions();
|
|
67864
|
+
let session;
|
|
67865
|
+
if (options.sessionId) {
|
|
67866
|
+
session = sessions2.find((s) => s.id === options.sessionId);
|
|
67867
|
+
} else {
|
|
67868
|
+
session = sessions2.filter((s) => s.status === "active").sort((a, b) => new Date(b.startedAt).getTime() - new Date(a.startedAt).getTime())[0];
|
|
67869
|
+
}
|
|
67870
|
+
if (!session) {
|
|
67871
|
+
throw new CleoError(
|
|
67872
|
+
31 /* SESSION_NOT_FOUND */,
|
|
67873
|
+
options.sessionId ? `Session '${options.sessionId}' not found` : "No active session to serialize",
|
|
67874
|
+
{ fix: "Use 'cleo session list' to see available sessions" }
|
|
67875
|
+
);
|
|
67876
|
+
}
|
|
67877
|
+
const handoff = await computeHandoff(projectRoot, { sessionId: session.id });
|
|
67878
|
+
const decisionLog = await getDecisionLog(projectRoot, { sessionId: session.id });
|
|
67879
|
+
const decisions = decisionLog.map((d) => ({
|
|
67880
|
+
decision: d.decision,
|
|
67881
|
+
rationale: d.rationale,
|
|
67882
|
+
taskId: d.taskId,
|
|
67883
|
+
recordedAt: d.timestamp ?? (/* @__PURE__ */ new Date()).toISOString()
|
|
67884
|
+
}));
|
|
67885
|
+
let observations = [];
|
|
67886
|
+
try {
|
|
67887
|
+
const { searchBrainCompact: searchBrainCompact2 } = await Promise.resolve().then(() => (init_brain_retrieval(), brain_retrieval_exports));
|
|
67888
|
+
const results = await searchBrainCompact2(projectRoot, {
|
|
67889
|
+
query: session.id,
|
|
67890
|
+
limit: maxObs,
|
|
67891
|
+
tables: ["observations"]
|
|
67892
|
+
});
|
|
67893
|
+
if (Array.isArray(results)) {
|
|
67894
|
+
observations = results.map(
|
|
67895
|
+
(r) => ({
|
|
67896
|
+
id: r.id,
|
|
67897
|
+
text: r.text ?? "",
|
|
67898
|
+
type: r.type ?? "discovery",
|
|
67899
|
+
createdAt: r.createdAt ?? ""
|
|
67900
|
+
})
|
|
67901
|
+
);
|
|
67902
|
+
}
|
|
67903
|
+
} catch {
|
|
67904
|
+
}
|
|
67905
|
+
let activeTask = null;
|
|
67906
|
+
if (session.taskWork?.taskId) {
|
|
67907
|
+
try {
|
|
67908
|
+
const { tasks: tasks2 } = await acc.queryTasks({});
|
|
67909
|
+
const task = tasks2.find((t) => t.id === session.taskWork?.taskId);
|
|
67910
|
+
if (task) {
|
|
67911
|
+
const desc7 = task.description ?? "";
|
|
67912
|
+
activeTask = {
|
|
67913
|
+
taskId: task.id,
|
|
67914
|
+
title: task.title,
|
|
67915
|
+
status: task.status,
|
|
67916
|
+
priority: task.priority ?? "medium",
|
|
67917
|
+
description: desc7.length > maxDescLen ? desc7.slice(0, maxDescLen) + "..." : desc7,
|
|
67918
|
+
acceptance: Array.isArray(task.acceptance) ? task.acceptance.join("\n") : task.acceptance ?? void 0
|
|
67919
|
+
};
|
|
67920
|
+
}
|
|
67921
|
+
} catch {
|
|
67922
|
+
}
|
|
67923
|
+
}
|
|
67924
|
+
const startTime = new Date(session.startedAt).getTime();
|
|
67925
|
+
const now2 = Date.now();
|
|
67926
|
+
const durationMinutes = Math.round((now2 - startTime) / 6e4);
|
|
67927
|
+
return {
|
|
67928
|
+
version: SNAPSHOT_VERSION,
|
|
67929
|
+
capturedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
67930
|
+
session,
|
|
67931
|
+
handoff,
|
|
67932
|
+
decisions,
|
|
67933
|
+
observations,
|
|
67934
|
+
activeTask,
|
|
67935
|
+
durationMinutes
|
|
67936
|
+
};
|
|
67937
|
+
}
|
|
67938
|
+
async function restoreSession(projectRoot, snapshot, options = {}, accessor) {
|
|
67939
|
+
if (snapshot.version > SNAPSHOT_VERSION) {
|
|
67940
|
+
throw new CleoError(
|
|
67941
|
+
6 /* VALIDATION_ERROR */,
|
|
67942
|
+
`Snapshot version ${snapshot.version} is newer than supported version ${SNAPSHOT_VERSION}`,
|
|
67943
|
+
{ fix: "Upgrade @cleocode/core to a newer version that supports this snapshot format" }
|
|
67944
|
+
);
|
|
67945
|
+
}
|
|
67946
|
+
const acc = accessor ?? await getAccessor(projectRoot);
|
|
67947
|
+
const activate = options.activate ?? true;
|
|
67948
|
+
if (activate) {
|
|
67949
|
+
const sessions2 = await acc.loadSessions();
|
|
67950
|
+
const scope = snapshot.session.scope;
|
|
67951
|
+
const activeConflict = sessions2.find(
|
|
67952
|
+
(s) => s.status === "active" && s.scope.type === scope.type && s.scope.epicId === scope.epicId && s.id !== snapshot.session.id
|
|
67953
|
+
);
|
|
67954
|
+
if (activeConflict) {
|
|
67955
|
+
throw new CleoError(
|
|
67956
|
+
32 /* SCOPE_CONFLICT */,
|
|
67957
|
+
`Active session '${activeConflict.id}' already exists for scope ${scope.type}${scope.epicId ? ":" + scope.epicId : ""}`,
|
|
67958
|
+
{
|
|
67959
|
+
fix: `End the active session first with 'cleo session end' or restore without activating`,
|
|
67960
|
+
alternatives: [
|
|
67961
|
+
{ action: "End conflicting session", command: "cleo session end" },
|
|
67962
|
+
{ action: "Restore without activating", command: "Restore with activate: false" }
|
|
67963
|
+
]
|
|
67964
|
+
}
|
|
67965
|
+
);
|
|
67966
|
+
}
|
|
67967
|
+
}
|
|
67968
|
+
const restoredSession = {
|
|
67969
|
+
...snapshot.session,
|
|
67970
|
+
status: activate ? "active" : snapshot.session.status,
|
|
67971
|
+
notes: [
|
|
67972
|
+
...snapshot.session.notes ?? [],
|
|
67973
|
+
`Restored from snapshot at ${(/* @__PURE__ */ new Date()).toISOString()} (captured ${snapshot.capturedAt}, duration ${snapshot.durationMinutes}m)`
|
|
67974
|
+
],
|
|
67975
|
+
resumeCount: (snapshot.session.resumeCount ?? 0) + 1
|
|
67976
|
+
};
|
|
67977
|
+
if (options.agent) {
|
|
67978
|
+
restoredSession.agent = options.agent;
|
|
67979
|
+
restoredSession.notes = [
|
|
67980
|
+
...restoredSession.notes ?? [],
|
|
67981
|
+
`Agent handoff: ${snapshot.session.agent ?? "unknown"} \u2192 ${options.agent}`
|
|
67982
|
+
];
|
|
67983
|
+
}
|
|
67984
|
+
restoredSession.handoffJson = JSON.stringify(snapshot.handoff);
|
|
67985
|
+
await acc.upsertSingleSession(restoredSession);
|
|
67986
|
+
try {
|
|
67987
|
+
const { hooks: hooks2 } = await Promise.resolve().then(() => (init_registry(), registry_exports));
|
|
67988
|
+
await hooks2.dispatch("onSessionStart", projectRoot, {
|
|
67989
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
67990
|
+
sessionId: restoredSession.id,
|
|
67991
|
+
name: restoredSession.name,
|
|
67992
|
+
scope: restoredSession.scope,
|
|
67993
|
+
agent: restoredSession.agent,
|
|
67994
|
+
restored: true,
|
|
67995
|
+
snapshotCapturedAt: snapshot.capturedAt
|
|
67996
|
+
});
|
|
67997
|
+
} catch {
|
|
67998
|
+
}
|
|
67999
|
+
return restoredSession;
|
|
68000
|
+
}
|
|
68001
|
+
var SNAPSHOT_VERSION;
|
|
68002
|
+
var init_snapshot2 = __esm({
|
|
68003
|
+
"packages/core/src/sessions/snapshot.ts"() {
|
|
68004
|
+
"use strict";
|
|
68005
|
+
init_src();
|
|
68006
|
+
init_errors3();
|
|
68007
|
+
init_data_accessor();
|
|
68008
|
+
init_decisions();
|
|
68009
|
+
init_handoff();
|
|
68010
|
+
SNAPSHOT_VERSION = 1;
|
|
68011
|
+
}
|
|
68012
|
+
});
|
|
68013
|
+
|
|
67858
68014
|
// packages/core/src/cleo.ts
|
|
67859
68015
|
import path from "node:path";
|
|
67860
68016
|
var Cleo;
|
|
@@ -67877,6 +68033,7 @@ var init_cleo = __esm({
|
|
|
67877
68033
|
init_link_store();
|
|
67878
68034
|
init_release2();
|
|
67879
68035
|
init_sessions();
|
|
68036
|
+
init_snapshot2();
|
|
67880
68037
|
init_sticky();
|
|
67881
68038
|
init_data_accessor();
|
|
67882
68039
|
init_task_work();
|
|
@@ -67986,7 +68143,15 @@ var init_cleo = __esm({
|
|
|
67986
68143
|
recordAssumption: (p) => recordAssumption(root, p),
|
|
67987
68144
|
contextDrift: (p) => getContextDrift(root, p),
|
|
67988
68145
|
decisionLog: (p) => getDecisionLog(root, { sessionId: p?.sessionId, taskId: p?.taskId }),
|
|
67989
|
-
lastHandoff: (scope) => getLastHandoff(root, scope)
|
|
68146
|
+
lastHandoff: (scope) => getLastHandoff(root, scope),
|
|
68147
|
+
serialize: (p) => serializeSession(root, {
|
|
68148
|
+
sessionId: p?.sessionId,
|
|
68149
|
+
maxObservations: p?.maxObservations
|
|
68150
|
+
}),
|
|
68151
|
+
restore: (snapshot, p) => restoreSession(root, snapshot, {
|
|
68152
|
+
agent: p?.agent,
|
|
68153
|
+
activate: p?.activate
|
|
68154
|
+
})
|
|
67990
68155
|
};
|
|
67991
68156
|
}
|
|
67992
68157
|
// === Memory ===
|
|
@@ -68235,6 +68400,7 @@ var init_src2 = __esm({
|
|
|
68235
68400
|
init_migration();
|
|
68236
68401
|
init_reconciliation();
|
|
68237
68402
|
init_sessions();
|
|
68403
|
+
init_snapshot2();
|
|
68238
68404
|
init_migrate();
|
|
68239
68405
|
init_storage_preflight();
|
|
68240
68406
|
init_task_work();
|
|
@@ -79483,6 +79649,7 @@ __export(internal_exports, {
|
|
|
79483
79649
|
resolveTask: () => resolveTask,
|
|
79484
79650
|
restoreBackup: () => restoreBackup,
|
|
79485
79651
|
restoreFromBackup: () => restoreFromBackup,
|
|
79652
|
+
restoreSession: () => restoreSession,
|
|
79486
79653
|
resumeSession: () => resumeSession,
|
|
79487
79654
|
roadmap: () => roadmap_exports,
|
|
79488
79655
|
rollbackRelease: () => rollbackRelease,
|
|
@@ -79510,6 +79677,7 @@ __export(internal_exports, {
|
|
|
79510
79677
|
selectSessionSchema: () => selectSessionSchema,
|
|
79511
79678
|
selectTaskSchema: () => selectTaskSchema,
|
|
79512
79679
|
sequence: () => sequence_exports,
|
|
79680
|
+
serializeSession: () => serializeSession,
|
|
79513
79681
|
sessionStatus: () => sessionStatus,
|
|
79514
79682
|
sessionStatusSchema: () => sessionStatusSchema,
|
|
79515
79683
|
sessions: () => sessions_exports,
|