@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/cli/index.js
CHANGED
|
@@ -67884,6 +67884,162 @@ var init_bootstrap = __esm({
|
|
|
67884
67884
|
}
|
|
67885
67885
|
});
|
|
67886
67886
|
|
|
67887
|
+
// packages/core/src/sessions/snapshot.ts
|
|
67888
|
+
async function serializeSession(projectRoot, options = {}, accessor) {
|
|
67889
|
+
const acc = accessor ?? await getAccessor(projectRoot);
|
|
67890
|
+
const maxObs = options.maxObservations ?? 10;
|
|
67891
|
+
const maxDescLen = options.maxDescriptionLength ?? 500;
|
|
67892
|
+
const sessions2 = await acc.loadSessions();
|
|
67893
|
+
let session;
|
|
67894
|
+
if (options.sessionId) {
|
|
67895
|
+
session = sessions2.find((s) => s.id === options.sessionId);
|
|
67896
|
+
} else {
|
|
67897
|
+
session = sessions2.filter((s) => s.status === "active").sort((a, b) => new Date(b.startedAt).getTime() - new Date(a.startedAt).getTime())[0];
|
|
67898
|
+
}
|
|
67899
|
+
if (!session) {
|
|
67900
|
+
throw new CleoError(
|
|
67901
|
+
31 /* SESSION_NOT_FOUND */,
|
|
67902
|
+
options.sessionId ? `Session '${options.sessionId}' not found` : "No active session to serialize",
|
|
67903
|
+
{ fix: "Use 'cleo session list' to see available sessions" }
|
|
67904
|
+
);
|
|
67905
|
+
}
|
|
67906
|
+
const handoff = await computeHandoff(projectRoot, { sessionId: session.id });
|
|
67907
|
+
const decisionLog = await getDecisionLog(projectRoot, { sessionId: session.id });
|
|
67908
|
+
const decisions = decisionLog.map((d) => ({
|
|
67909
|
+
decision: d.decision,
|
|
67910
|
+
rationale: d.rationale,
|
|
67911
|
+
taskId: d.taskId,
|
|
67912
|
+
recordedAt: d.timestamp ?? (/* @__PURE__ */ new Date()).toISOString()
|
|
67913
|
+
}));
|
|
67914
|
+
let observations = [];
|
|
67915
|
+
try {
|
|
67916
|
+
const { searchBrainCompact: searchBrainCompact2 } = await Promise.resolve().then(() => (init_brain_retrieval(), brain_retrieval_exports));
|
|
67917
|
+
const results = await searchBrainCompact2(projectRoot, {
|
|
67918
|
+
query: session.id,
|
|
67919
|
+
limit: maxObs,
|
|
67920
|
+
tables: ["observations"]
|
|
67921
|
+
});
|
|
67922
|
+
if (Array.isArray(results)) {
|
|
67923
|
+
observations = results.map(
|
|
67924
|
+
(r) => ({
|
|
67925
|
+
id: r.id,
|
|
67926
|
+
text: r.text ?? "",
|
|
67927
|
+
type: r.type ?? "discovery",
|
|
67928
|
+
createdAt: r.createdAt ?? ""
|
|
67929
|
+
})
|
|
67930
|
+
);
|
|
67931
|
+
}
|
|
67932
|
+
} catch {
|
|
67933
|
+
}
|
|
67934
|
+
let activeTask = null;
|
|
67935
|
+
if (session.taskWork?.taskId) {
|
|
67936
|
+
try {
|
|
67937
|
+
const { tasks: tasks2 } = await acc.queryTasks({});
|
|
67938
|
+
const task = tasks2.find((t) => t.id === session.taskWork?.taskId);
|
|
67939
|
+
if (task) {
|
|
67940
|
+
const desc7 = task.description ?? "";
|
|
67941
|
+
activeTask = {
|
|
67942
|
+
taskId: task.id,
|
|
67943
|
+
title: task.title,
|
|
67944
|
+
status: task.status,
|
|
67945
|
+
priority: task.priority ?? "medium",
|
|
67946
|
+
description: desc7.length > maxDescLen ? desc7.slice(0, maxDescLen) + "..." : desc7,
|
|
67947
|
+
acceptance: Array.isArray(task.acceptance) ? task.acceptance.join("\n") : task.acceptance ?? void 0
|
|
67948
|
+
};
|
|
67949
|
+
}
|
|
67950
|
+
} catch {
|
|
67951
|
+
}
|
|
67952
|
+
}
|
|
67953
|
+
const startTime = new Date(session.startedAt).getTime();
|
|
67954
|
+
const now2 = Date.now();
|
|
67955
|
+
const durationMinutes = Math.round((now2 - startTime) / 6e4);
|
|
67956
|
+
return {
|
|
67957
|
+
version: SNAPSHOT_VERSION,
|
|
67958
|
+
capturedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
67959
|
+
session,
|
|
67960
|
+
handoff,
|
|
67961
|
+
decisions,
|
|
67962
|
+
observations,
|
|
67963
|
+
activeTask,
|
|
67964
|
+
durationMinutes
|
|
67965
|
+
};
|
|
67966
|
+
}
|
|
67967
|
+
async function restoreSession(projectRoot, snapshot, options = {}, accessor) {
|
|
67968
|
+
if (snapshot.version > SNAPSHOT_VERSION) {
|
|
67969
|
+
throw new CleoError(
|
|
67970
|
+
6 /* VALIDATION_ERROR */,
|
|
67971
|
+
`Snapshot version ${snapshot.version} is newer than supported version ${SNAPSHOT_VERSION}`,
|
|
67972
|
+
{ fix: "Upgrade @cleocode/core to a newer version that supports this snapshot format" }
|
|
67973
|
+
);
|
|
67974
|
+
}
|
|
67975
|
+
const acc = accessor ?? await getAccessor(projectRoot);
|
|
67976
|
+
const activate = options.activate ?? true;
|
|
67977
|
+
if (activate) {
|
|
67978
|
+
const sessions2 = await acc.loadSessions();
|
|
67979
|
+
const scope = snapshot.session.scope;
|
|
67980
|
+
const activeConflict = sessions2.find(
|
|
67981
|
+
(s) => s.status === "active" && s.scope.type === scope.type && s.scope.epicId === scope.epicId && s.id !== snapshot.session.id
|
|
67982
|
+
);
|
|
67983
|
+
if (activeConflict) {
|
|
67984
|
+
throw new CleoError(
|
|
67985
|
+
32 /* SCOPE_CONFLICT */,
|
|
67986
|
+
`Active session '${activeConflict.id}' already exists for scope ${scope.type}${scope.epicId ? ":" + scope.epicId : ""}`,
|
|
67987
|
+
{
|
|
67988
|
+
fix: `End the active session first with 'cleo session end' or restore without activating`,
|
|
67989
|
+
alternatives: [
|
|
67990
|
+
{ action: "End conflicting session", command: "cleo session end" },
|
|
67991
|
+
{ action: "Restore without activating", command: "Restore with activate: false" }
|
|
67992
|
+
]
|
|
67993
|
+
}
|
|
67994
|
+
);
|
|
67995
|
+
}
|
|
67996
|
+
}
|
|
67997
|
+
const restoredSession = {
|
|
67998
|
+
...snapshot.session,
|
|
67999
|
+
status: activate ? "active" : snapshot.session.status,
|
|
68000
|
+
notes: [
|
|
68001
|
+
...snapshot.session.notes ?? [],
|
|
68002
|
+
`Restored from snapshot at ${(/* @__PURE__ */ new Date()).toISOString()} (captured ${snapshot.capturedAt}, duration ${snapshot.durationMinutes}m)`
|
|
68003
|
+
],
|
|
68004
|
+
resumeCount: (snapshot.session.resumeCount ?? 0) + 1
|
|
68005
|
+
};
|
|
68006
|
+
if (options.agent) {
|
|
68007
|
+
restoredSession.agent = options.agent;
|
|
68008
|
+
restoredSession.notes = [
|
|
68009
|
+
...restoredSession.notes ?? [],
|
|
68010
|
+
`Agent handoff: ${snapshot.session.agent ?? "unknown"} \u2192 ${options.agent}`
|
|
68011
|
+
];
|
|
68012
|
+
}
|
|
68013
|
+
restoredSession.handoffJson = JSON.stringify(snapshot.handoff);
|
|
68014
|
+
await acc.upsertSingleSession(restoredSession);
|
|
68015
|
+
try {
|
|
68016
|
+
const { hooks: hooks2 } = await Promise.resolve().then(() => (init_registry(), registry_exports));
|
|
68017
|
+
await hooks2.dispatch("onSessionStart", projectRoot, {
|
|
68018
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
68019
|
+
sessionId: restoredSession.id,
|
|
68020
|
+
name: restoredSession.name,
|
|
68021
|
+
scope: restoredSession.scope,
|
|
68022
|
+
agent: restoredSession.agent,
|
|
68023
|
+
restored: true,
|
|
68024
|
+
snapshotCapturedAt: snapshot.capturedAt
|
|
68025
|
+
});
|
|
68026
|
+
} catch {
|
|
68027
|
+
}
|
|
68028
|
+
return restoredSession;
|
|
68029
|
+
}
|
|
68030
|
+
var SNAPSHOT_VERSION;
|
|
68031
|
+
var init_snapshot2 = __esm({
|
|
68032
|
+
"packages/core/src/sessions/snapshot.ts"() {
|
|
68033
|
+
"use strict";
|
|
68034
|
+
init_src();
|
|
68035
|
+
init_errors3();
|
|
68036
|
+
init_data_accessor();
|
|
68037
|
+
init_decisions();
|
|
68038
|
+
init_handoff();
|
|
68039
|
+
SNAPSHOT_VERSION = 1;
|
|
68040
|
+
}
|
|
68041
|
+
});
|
|
68042
|
+
|
|
67887
68043
|
// packages/core/src/cleo.ts
|
|
67888
68044
|
import path from "node:path";
|
|
67889
68045
|
var Cleo;
|
|
@@ -67906,6 +68062,7 @@ var init_cleo = __esm({
|
|
|
67906
68062
|
init_link_store();
|
|
67907
68063
|
init_release2();
|
|
67908
68064
|
init_sessions();
|
|
68065
|
+
init_snapshot2();
|
|
67909
68066
|
init_sticky();
|
|
67910
68067
|
init_data_accessor();
|
|
67911
68068
|
init_task_work();
|
|
@@ -68015,7 +68172,15 @@ var init_cleo = __esm({
|
|
|
68015
68172
|
recordAssumption: (p) => recordAssumption(root, p),
|
|
68016
68173
|
contextDrift: (p) => getContextDrift(root, p),
|
|
68017
68174
|
decisionLog: (p) => getDecisionLog(root, { sessionId: p?.sessionId, taskId: p?.taskId }),
|
|
68018
|
-
lastHandoff: (scope) => getLastHandoff(root, scope)
|
|
68175
|
+
lastHandoff: (scope) => getLastHandoff(root, scope),
|
|
68176
|
+
serialize: (p) => serializeSession(root, {
|
|
68177
|
+
sessionId: p?.sessionId,
|
|
68178
|
+
maxObservations: p?.maxObservations
|
|
68179
|
+
}),
|
|
68180
|
+
restore: (snapshot, p) => restoreSession(root, snapshot, {
|
|
68181
|
+
agent: p?.agent,
|
|
68182
|
+
activate: p?.activate
|
|
68183
|
+
})
|
|
68019
68184
|
};
|
|
68020
68185
|
}
|
|
68021
68186
|
// === Memory ===
|
|
@@ -68371,6 +68536,7 @@ __export(src_exports, {
|
|
|
68371
68536
|
remote: () => remote_exports,
|
|
68372
68537
|
research: () => research_exports,
|
|
68373
68538
|
resolveProjectPath: () => resolveProjectPath,
|
|
68539
|
+
restoreSession: () => restoreSession,
|
|
68374
68540
|
resumeSession: () => resumeSession,
|
|
68375
68541
|
roadmap: () => roadmap_exports,
|
|
68376
68542
|
routing: () => routing_exports,
|
|
@@ -68387,6 +68553,7 @@ __export(src_exports, {
|
|
|
68387
68553
|
selectSessionSchema: () => selectSessionSchema,
|
|
68388
68554
|
selectTaskSchema: () => selectTaskSchema,
|
|
68389
68555
|
sequence: () => sequence_exports,
|
|
68556
|
+
serializeSession: () => serializeSession,
|
|
68390
68557
|
sessionStatus: () => sessionStatus,
|
|
68391
68558
|
sessionStatusSchema: () => sessionStatusSchema,
|
|
68392
68559
|
sessions: () => sessions_exports,
|
|
@@ -68497,6 +68664,7 @@ var init_src2 = __esm({
|
|
|
68497
68664
|
init_migration();
|
|
68498
68665
|
init_reconciliation();
|
|
68499
68666
|
init_sessions();
|
|
68667
|
+
init_snapshot2();
|
|
68500
68668
|
init_migrate();
|
|
68501
68669
|
init_storage_preflight();
|
|
68502
68670
|
init_task_work();
|
|
@@ -79745,6 +79913,7 @@ __export(internal_exports, {
|
|
|
79745
79913
|
resolveTask: () => resolveTask,
|
|
79746
79914
|
restoreBackup: () => restoreBackup,
|
|
79747
79915
|
restoreFromBackup: () => restoreFromBackup,
|
|
79916
|
+
restoreSession: () => restoreSession,
|
|
79748
79917
|
resumeSession: () => resumeSession,
|
|
79749
79918
|
roadmap: () => roadmap_exports,
|
|
79750
79919
|
rollbackRelease: () => rollbackRelease,
|
|
@@ -79772,6 +79941,7 @@ __export(internal_exports, {
|
|
|
79772
79941
|
selectSessionSchema: () => selectSessionSchema,
|
|
79773
79942
|
selectTaskSchema: () => selectTaskSchema,
|
|
79774
79943
|
sequence: () => sequence_exports,
|
|
79944
|
+
serializeSession: () => serializeSession,
|
|
79775
79945
|
sessionStatus: () => sessionStatus,
|
|
79776
79946
|
sessionStatusSchema: () => sessionStatusSchema,
|
|
79777
79947
|
sessions: () => sessions_exports,
|