@zerone-agent/open-agent-sdk 0.5.9 → 0.6.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.
Files changed (42) hide show
  1. package/dist/agent.d.ts.map +1 -1
  2. package/dist/agent.js +6 -0
  3. package/dist/agent.js.map +1 -1
  4. package/dist/engine.d.ts +19 -1
  5. package/dist/engine.d.ts.map +1 -1
  6. package/dist/engine.js +88 -2
  7. package/dist/engine.js.map +1 -1
  8. package/dist/index.d.ts +9 -2
  9. package/dist/index.d.ts.map +1 -1
  10. package/dist/index.js +11 -1
  11. package/dist/index.js.map +1 -1
  12. package/dist/providers/types.d.ts +7 -0
  13. package/dist/providers/types.d.ts.map +1 -1
  14. package/dist/revert/index.d.ts +63 -0
  15. package/dist/revert/index.d.ts.map +1 -0
  16. package/dist/revert/index.js +125 -0
  17. package/dist/revert/index.js.map +1 -0
  18. package/dist/session.d.ts +20 -1
  19. package/dist/session.d.ts.map +1 -1
  20. package/dist/session.js +40 -6
  21. package/dist/session.js.map +1 -1
  22. package/dist/snapshot/git-detector.d.ts +9 -0
  23. package/dist/snapshot/git-detector.d.ts.map +1 -0
  24. package/dist/snapshot/git-detector.js +26 -0
  25. package/dist/snapshot/git-detector.js.map +1 -0
  26. package/dist/snapshot/index.d.ts +76 -0
  27. package/dist/snapshot/index.d.ts.map +1 -0
  28. package/dist/snapshot/index.js +288 -0
  29. package/dist/snapshot/index.js.map +1 -0
  30. package/dist/snapshot/semaphore.d.ts +11 -0
  31. package/dist/snapshot/semaphore.d.ts.map +1 -0
  32. package/dist/snapshot/semaphore.js +27 -0
  33. package/dist/snapshot/semaphore.js.map +1 -0
  34. package/dist/types.d.ts +15 -0
  35. package/dist/types.d.ts.map +1 -1
  36. package/dist/utils/compact.d.ts +5 -0
  37. package/dist/utils/compact.d.ts.map +1 -1
  38. package/dist/utils/compact.js +30 -0
  39. package/dist/utils/compact.js.map +1 -1
  40. package/dist/utils/messages.js +2 -2
  41. package/dist/utils/messages.js.map +1 -1
  42. package/package.json +1 -1
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Revert Service
3
+ *
4
+ * Orchestrates conversation + file rollback using SnapshotEngine
5
+ * and QueryEngine snapshot/restore.
6
+ *
7
+ * Two modes:
8
+ * - Mode A (snapshotEngine provided): reverts files + conversation
9
+ * - Mode B (no snapshotEngine): reverts conversation only
10
+ */
11
+ import type { NormalizedMessageParam } from '../providers/types.js';
12
+ import type { EngineSnapshot } from '../types.js';
13
+ import type { SnapshotEngine } from '../snapshot/index.js';
14
+ export interface RevertServiceOptions {
15
+ engine: {
16
+ messages: NormalizedMessageParam[];
17
+ snapshot: () => EngineSnapshot;
18
+ restore: (snap: EngineSnapshot) => void;
19
+ isRunning: boolean;
20
+ compactBoundaryId?: string;
21
+ };
22
+ snapshotEngine?: SnapshotEngine;
23
+ /** Snapshot of engine state taken before the current run (for restore) */
24
+ engineSnapshot: EngineSnapshot;
25
+ }
26
+ export interface RevertResult {
27
+ messageId: string;
28
+ changedFiles: string[];
29
+ diff?: string;
30
+ }
31
+ export declare class RevertService {
32
+ private engine;
33
+ private snapshotEngine?;
34
+ private engineSnapshot;
35
+ private revertSnapshot?;
36
+ private revertState?;
37
+ constructor(opts: RevertServiceOptions);
38
+ /**
39
+ * Revert conversation and files to the state before the given message.
40
+ */
41
+ revert(messageId: string): Promise<RevertResult>;
42
+ /**
43
+ * Undo a revert — restore files and conversation to pre-revert state.
44
+ */
45
+ unrevert(): Promise<void>;
46
+ /**
47
+ * Permanently commit a revert — cleaned-up messages are gone forever.
48
+ */
49
+ cleanup(): void;
50
+ /**
51
+ * Get current revert state (for persistence).
52
+ */
53
+ getState(): {
54
+ messageId: string;
55
+ snapshotHash?: string;
56
+ } | null;
57
+ /**
58
+ * Whether a revert is currently active.
59
+ */
60
+ isReverted(): boolean;
61
+ private assertNotBusy;
62
+ }
63
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/revert/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAA;AACnE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AACjD,OAAO,KAAK,EAAE,cAAc,EAAe,MAAM,sBAAsB,CAAA;AAEvE,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE;QACN,QAAQ,EAAE,sBAAsB,EAAE,CAAA;QAClC,QAAQ,EAAE,MAAM,cAAc,CAAA;QAC9B,OAAO,EAAE,CAAC,IAAI,EAAE,cAAc,KAAK,IAAI,CAAA;QACvC,SAAS,EAAE,OAAO,CAAA;QAClB,iBAAiB,CAAC,EAAE,MAAM,CAAA;KAC3B,CAAA;IACD,cAAc,CAAC,EAAE,cAAc,CAAA;IAC/B,0EAA0E;IAC1E,cAAc,EAAE,cAAc,CAAA;CAC/B;AAED,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,MAAM,CAAA;IACjB,YAAY,EAAE,MAAM,EAAE,CAAA;IACtB,IAAI,CAAC,EAAE,MAAM,CAAA;CACd;AAED,qBAAa,aAAa;IACxB,OAAO,CAAC,MAAM,CAAgC;IAC9C,OAAO,CAAC,cAAc,CAAC,CAAgB;IACvC,OAAO,CAAC,cAAc,CAAgB;IACtC,OAAO,CAAC,cAAc,CAAC,CAAgB;IACvC,OAAO,CAAC,WAAW,CAAC,CAA8C;gBAEtD,IAAI,EAAE,oBAAoB;IAMtC;;OAEG;IACG,MAAM,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAsEtD;;OAEG;IACG,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAmB/B;;OAEG;IACH,OAAO,IAAI,IAAI;IAKf;;OAEG;IACH,QAAQ,IAAI;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,YAAY,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI;IAI/D;;OAEG;IACH,UAAU,IAAI,OAAO;IAIrB,OAAO,CAAC,aAAa;CAKtB"}
@@ -0,0 +1,125 @@
1
+ /**
2
+ * Revert Service
3
+ *
4
+ * Orchestrates conversation + file rollback using SnapshotEngine
5
+ * and QueryEngine snapshot/restore.
6
+ *
7
+ * Two modes:
8
+ * - Mode A (snapshotEngine provided): reverts files + conversation
9
+ * - Mode B (no snapshotEngine): reverts conversation only
10
+ */
11
+ export class RevertService {
12
+ engine;
13
+ snapshotEngine;
14
+ engineSnapshot;
15
+ revertSnapshot;
16
+ revertState;
17
+ constructor(opts) {
18
+ this.engine = opts.engine;
19
+ this.snapshotEngine = opts.snapshotEngine;
20
+ this.engineSnapshot = opts.engineSnapshot;
21
+ }
22
+ /**
23
+ * Revert conversation and files to the state before the given message.
24
+ */
25
+ async revert(messageId) {
26
+ this.assertNotBusy();
27
+ const anchorIdx = this.engine.messages.findIndex((m) => m.id === messageId);
28
+ if (anchorIdx === -1) {
29
+ // Check if it was compacted away
30
+ const boundary = this.engine.compactBoundaryId;
31
+ if (boundary) {
32
+ throw new Error(`Cannot revert to message ${messageId} — it was summarized by auto-compaction. ` +
33
+ `Earliest available message: ${boundary}`);
34
+ }
35
+ throw new Error(`Message not found: ${messageId}`);
36
+ }
37
+ // Collect file changes from messages at or after the anchor.
38
+ // For each file, use the FIRST occurrence's beforeHash (the state before
39
+ // the file was first changed in this range). Later occurrences are skipped
40
+ // to avoid overwriting with newer states.
41
+ const entries = [];
42
+ const changedFiles = new Set();
43
+ const seenFiles = new Set();
44
+ for (let i = anchorIdx; i < this.engine.messages.length; i++) {
45
+ const msg = this.engine.messages[i];
46
+ if (msg._snapshot) {
47
+ for (const file of msg._snapshot.changedFiles) {
48
+ changedFiles.add(file);
49
+ if (!seenFiles.has(file)) {
50
+ seenFiles.add(file);
51
+ entries.push({ hash: msg._snapshot.beforeHash, path: file });
52
+ }
53
+ }
54
+ }
55
+ }
56
+ // Mode A: revert files
57
+ let diff;
58
+ if (this.snapshotEngine && entries.length > 0) {
59
+ if (!this.revertState?.snapshotHash) {
60
+ const snapshotHash = await this.snapshotEngine.track();
61
+ this.revertState = { messageId, snapshotHash };
62
+ this.revertSnapshot = this.engineSnapshot;
63
+ }
64
+ else {
65
+ await this.snapshotEngine.restore(this.revertState.snapshotHash);
66
+ }
67
+ await this.snapshotEngine.revert(entries);
68
+ diff = await this.snapshotEngine.diff(this.revertState.snapshotHash);
69
+ }
70
+ // Revert conversation state
71
+ this.engine.restore(this.engineSnapshot);
72
+ this.engine.messages.length = anchorIdx;
73
+ this.revertState = {
74
+ messageId,
75
+ snapshotHash: this.revertState?.snapshotHash,
76
+ };
77
+ return {
78
+ messageId,
79
+ changedFiles: Array.from(changedFiles),
80
+ diff,
81
+ };
82
+ }
83
+ /**
84
+ * Undo a revert — restore files and conversation to pre-revert state.
85
+ */
86
+ async unrevert() {
87
+ this.assertNotBusy();
88
+ if (!this.revertState?.snapshotHash) {
89
+ throw new Error('No active revert to undo');
90
+ }
91
+ if (this.snapshotEngine) {
92
+ await this.snapshotEngine.restore(this.revertState.snapshotHash);
93
+ }
94
+ if (this.revertSnapshot) {
95
+ this.engine.restore(this.revertSnapshot);
96
+ }
97
+ this.revertState = undefined;
98
+ this.revertSnapshot = undefined;
99
+ }
100
+ /**
101
+ * Permanently commit a revert — cleaned-up messages are gone forever.
102
+ */
103
+ cleanup() {
104
+ this.revertState = undefined;
105
+ this.revertSnapshot = undefined;
106
+ }
107
+ /**
108
+ * Get current revert state (for persistence).
109
+ */
110
+ getState() {
111
+ return this.revertState ?? null;
112
+ }
113
+ /**
114
+ * Whether a revert is currently active.
115
+ */
116
+ isReverted() {
117
+ return this.revertState !== undefined;
118
+ }
119
+ assertNotBusy() {
120
+ if (this.engine.isRunning) {
121
+ throw new Error('Cannot revert while engine is running');
122
+ }
123
+ }
124
+ }
125
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/revert/index.ts"],"names":[],"mappings":"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"}
package/dist/session.d.ts CHANGED
@@ -19,6 +19,13 @@ export interface SessionMetadata {
19
19
  summary?: string;
20
20
  lastInputTokens?: number;
21
21
  lastOutputTokens?: number;
22
+ /** Revert state — present when conversation is rolled back */
23
+ revert?: RevertState;
24
+ }
25
+ export interface RevertState {
26
+ messageId: string;
27
+ snapshotHash?: string;
28
+ diff?: string;
22
29
  }
23
30
  /**
24
31
  * Session data on disk.
@@ -39,10 +46,22 @@ export declare function loadSession(sessionId: string): Promise<SessionData | nu
39
46
  * List all sessions.
40
47
  */
41
48
  export declare function listSessions(): Promise<SessionMetadata[]>;
49
+ /**
50
+ * Fork source specification — which session and message to fork from.
51
+ */
52
+ export interface ForkSource {
53
+ sessionId: string;
54
+ /** Fork point: only messages up to and including this one are copied. */
55
+ messageId?: string;
56
+ }
42
57
  /**
43
58
  * Fork a session (create a copy with a new ID).
59
+ *
60
+ * Without messageId: full copy of all messages.
61
+ * With messageId: only messages up to and including that message are copied,
62
+ * and all message IDs are regenerated.
44
63
  */
45
- export declare function forkSession(sourceSessionId: string, newSessionId?: string): Promise<string | null>;
64
+ export declare function forkSession(source: ForkSource | string, newSessionId?: string): Promise<string | null>;
46
65
  /**
47
66
  * Get session messages.
48
67
  */
@@ -1 +1 @@
1
- {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAA;AAElE;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAA;IACV,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,MAAM,CAAA;IACjB,YAAY,EAAE,MAAM,CAAA;IACpB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,gBAAgB,CAAC,EAAE,MAAM,CAAA;CAC1B;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,eAAe,CAAA;IACzB,QAAQ,EAAE,sBAAsB,EAAE,CAAA;CACnC;AAiBD;;GAEG;AACH,wBAAsB,WAAW,CAC/B,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,sBAAsB,EAAE,EAClC,QAAQ,EAAE,OAAO,CAAC,eAAe,CAAC,GACjC,OAAO,CAAC,IAAI,CAAC,CAyBf;AAED;;GAEG;AACH,wBAAsB,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAQhF;AAED;;GAEG;AACH,wBAAsB,YAAY,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC,CAwB/D;AAED;;GAEG;AACH,wBAAsB,WAAW,CAC/B,eAAe,EAAE,MAAM,EACvB,YAAY,CAAC,EAAE,MAAM,GACpB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAcxB;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CACtC,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,sBAAsB,EAAE,CAAC,CAGnC;AAED;;GAEG;AACH,wBAAsB,eAAe,CACnC,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,sBAAsB,GAC9B,OAAO,CAAC,IAAI,CAAC,CASf;AAED;;GAEG;AACH,wBAAsB,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAQvE;AAED;;GAEG;AACH,wBAAsB,cAAc,CAClC,SAAS,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GACzB,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CAGjC;AAED;;GAEG;AACH,wBAAsB,aAAa,CACjC,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,EACb,OAAO,CAAC,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GACzB,OAAO,CAAC,IAAI,CAAC,CAQf;AAED;;GAEG;AACH,wBAAsB,UAAU,CAC9B,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,MAAM,GAAG,IAAI,EAClB,OAAO,CAAC,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GACzB,OAAO,CAAC,IAAI,CAAC,CAQf"}
1
+ {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAA;AAYlE;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAA;IACV,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,MAAM,CAAA;IACjB,YAAY,EAAE,MAAM,CAAA;IACpB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,8DAA8D;IAC9D,MAAM,CAAC,EAAE,WAAW,CAAA;CACrB;AAED,MAAM,WAAW,WAAW;IAC1B,SAAS,EAAE,MAAM,CAAA;IACjB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,IAAI,CAAC,EAAE,MAAM,CAAA;CACd;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,eAAe,CAAA;IACzB,QAAQ,EAAE,sBAAsB,EAAE,CAAA;CACnC;AAiBD;;GAEG;AACH,wBAAsB,WAAW,CAC/B,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,sBAAsB,EAAE,EAClC,QAAQ,EAAE,OAAO,CAAC,eAAe,CAAC,GACjC,OAAO,CAAC,IAAI,CAAC,CA2Bf;AAED;;GAEG;AACH,wBAAsB,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAUhF;AAED;;GAEG;AACH,wBAAsB,YAAY,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC,CAwB/D;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,SAAS,EAAE,MAAM,CAAA;IACjB,yEAAyE;IACzE,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED;;;;;;GAMG;AACH,wBAAsB,WAAW,CAC/B,MAAM,EAAE,UAAU,GAAG,MAAM,EAC3B,YAAY,CAAC,EAAE,MAAM,GACpB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAmCxB;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CACtC,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,sBAAsB,EAAE,CAAC,CAGnC;AAED;;GAEG;AACH,wBAAsB,eAAe,CACnC,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,sBAAsB,GAC9B,OAAO,CAAC,IAAI,CAAC,CASf;AAED;;GAEG;AACH,wBAAsB,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAQvE;AAED;;GAEG;AACH,wBAAsB,cAAc,CAClC,SAAS,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GACzB,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CAGjC;AAED;;GAEG;AACH,wBAAsB,aAAa,CACjC,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,EACb,OAAO,CAAC,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GACzB,OAAO,CAAC,IAAI,CAAC,CAQf;AAED;;GAEG;AACH,wBAAsB,UAAU,CAC9B,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,MAAM,GAAG,IAAI,EAClB,OAAO,CAAC,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GACzB,OAAO,CAAC,IAAI,CAAC,CAQf"}
package/dist/session.js CHANGED
@@ -6,6 +6,16 @@
6
6
  */
7
7
  import { readFile, writeFile, mkdir, readdir } from 'fs/promises';
8
8
  import { join } from 'path';
9
+ /**
10
+ * Ensure every message has a stable id.
11
+ */
12
+ function ensureMessageIds(messages) {
13
+ for (const msg of messages) {
14
+ if (!msg.id)
15
+ msg.id = crypto.randomUUID();
16
+ }
17
+ return messages;
18
+ }
9
19
  /**
10
20
  * Get the sessions directory path.
11
21
  */
@@ -25,6 +35,7 @@ function getSessionPath(sessionId) {
25
35
  export async function saveSession(sessionId, messages, metadata) {
26
36
  const dir = getSessionPath(sessionId);
27
37
  await mkdir(dir, { recursive: true });
38
+ const messagesWithIds = ensureMessageIds(messages);
28
39
  const data = {
29
40
  metadata: {
30
41
  id: sessionId,
@@ -33,12 +44,12 @@ export async function saveSession(sessionId, messages, metadata) {
33
44
  provider: metadata.provider,
34
45
  createdAt: metadata.createdAt || new Date().toISOString(),
35
46
  updatedAt: new Date().toISOString(),
36
- messageCount: messages.length,
47
+ messageCount: messagesWithIds.length,
37
48
  summary: metadata.summary,
38
49
  lastInputTokens: metadata.lastInputTokens,
39
50
  lastOutputTokens: metadata.lastOutputTokens,
40
51
  },
41
- messages,
52
+ messages: messagesWithIds,
42
53
  };
43
54
  await writeFile(join(dir, 'transcript.json'), JSON.stringify(data, null, 2), 'utf-8');
44
55
  }
@@ -49,7 +60,9 @@ export async function loadSession(sessionId) {
49
60
  try {
50
61
  const filePath = join(getSessionPath(sessionId), 'transcript.json');
51
62
  const content = await readFile(filePath, 'utf-8');
52
- return JSON.parse(content);
63
+ const data = JSON.parse(content);
64
+ data.messages = ensureMessageIds(data.messages);
65
+ return data;
53
66
  }
54
67
  catch {
55
68
  return null;
@@ -84,13 +97,34 @@ export async function listSessions() {
84
97
  }
85
98
  /**
86
99
  * Fork a session (create a copy with a new ID).
100
+ *
101
+ * Without messageId: full copy of all messages.
102
+ * With messageId: only messages up to and including that message are copied,
103
+ * and all message IDs are regenerated.
87
104
  */
88
- export async function forkSession(sourceSessionId, newSessionId) {
105
+ export async function forkSession(source, newSessionId) {
106
+ // Accept both old signature (string) and new ({ sessionId, messageId? })
107
+ const sourceSessionId = typeof source === 'string' ? source : source.sessionId;
108
+ const forkMessageId = typeof source === 'string' ? undefined : source.messageId;
89
109
  const data = await loadSession(sourceSessionId);
90
110
  if (!data)
91
111
  return null;
112
+ let messages = data.messages;
113
+ if (forkMessageId) {
114
+ const idx = messages.findIndex((m) => m.id === forkMessageId);
115
+ if (idx === -1) {
116
+ throw new Error(`Message not found: ${forkMessageId}`);
117
+ }
118
+ messages = messages.slice(0, idx + 1);
119
+ }
120
+ // Always regenerate IDs and strip snapshot metadata — fork starts clean
121
+ messages = messages.map((m) => ({
122
+ ...m,
123
+ id: crypto.randomUUID(),
124
+ _snapshot: undefined,
125
+ }));
92
126
  const forkId = newSessionId || crypto.randomUUID();
93
- await saveSession(forkId, data.messages, {
127
+ await saveSession(forkId, messages, {
94
128
  ...data.metadata,
95
129
  id: forkId,
96
130
  createdAt: new Date().toISOString(),
@@ -112,7 +146,7 @@ export async function appendToSession(sessionId, message) {
112
146
  const data = await loadSession(sessionId);
113
147
  if (!data)
114
148
  return;
115
- data.messages.push(message);
149
+ data.messages.push(message.id ? message : { ...message, id: crypto.randomUUID() });
116
150
  data.metadata.updatedAt = new Date().toISOString();
117
151
  data.metadata.messageCount = data.messages.length;
118
152
  await saveSession(sessionId, data.messages, data.metadata);
@@ -1 +1 @@
1
- {"version":3,"file":"session.js","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAA;AACjE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AA2B3B;;GAEG;AACH,SAAS,cAAc;IACrB,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,MAAM,CAAA;IAClE,OAAO,IAAI,CAAC,IAAI,EAAE,YAAY,EAAE,UAAU,CAAC,CAAA;AAC7C,CAAC;AAED;;GAEG;AACH,SAAS,cAAc,CAAC,SAAiB;IACvC,OAAO,IAAI,CAAC,cAAc,EAAE,EAAE,SAAS,CAAC,CAAA;AAC1C,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,SAAiB,EACjB,QAAkC,EAClC,QAAkC;IAElC,MAAM,GAAG,GAAG,cAAc,CAAC,SAAS,CAAC,CAAA;IACrC,MAAM,KAAK,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IAErC,MAAM,IAAI,GAAgB;QACxB,QAAQ,EAAE;YACR,EAAE,EAAE,SAAS;YACb,GAAG,EAAE,QAAQ,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,EAAE;YAClC,KAAK,EAAE,QAAQ,CAAC,KAAK,IAAI,mBAAmB;YAC5C,QAAQ,EAAE,QAAQ,CAAC,QAAQ;YAC3B,SAAS,EAAE,QAAQ,CAAC,SAAS,IAAI,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACzD,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACnC,YAAY,EAAE,QAAQ,CAAC,MAAM;YAC7B,OAAO,EAAE,QAAQ,CAAC,OAAO;YACzB,eAAe,EAAE,QAAQ,CAAC,eAAe;YACzC,gBAAgB,EAAE,QAAQ,CAAC,gBAAgB;SAC5C;QACD,QAAQ;KACT,CAAA;IAED,MAAM,SAAS,CACb,IAAI,CAAC,GAAG,EAAE,iBAAiB,CAAC,EAC5B,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAC7B,OAAO,CACR,CAAA;AACH,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,SAAiB;IACjD,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,IAAI,CAAC,cAAc,CAAC,SAAS,CAAC,EAAE,iBAAiB,CAAC,CAAA;QACnE,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAA;QACjD,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAgB,CAAA;IAC3C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAA;IACb,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY;IAChC,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,cAAc,EAAE,CAAA;QAC5B,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,CAAA;QAClC,MAAM,QAAQ,GAAsB,EAAE,CAAA;QAEtC,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;YAC5B,IAAI,CAAC;gBACH,MAAM,IAAI,GAAG,MAAM,WAAW,CAAC,KAAK,CAAC,CAAA;gBACrC,IAAI,IAAI,EAAE,QAAQ,EAAE,CAAC;oBACnB,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;gBAC9B,CAAC;YACH,CAAC;YAAC,MAAM,CAAC;gBACP,wBAAwB;YAC1B,CAAC;QACH,CAAC;QAED,+BAA+B;QAC/B,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAA;QAE/D,OAAO,QAAQ,CAAA;IACjB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAA;IACX,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,eAAuB,EACvB,YAAqB;IAErB,MAAM,IAAI,GAAG,MAAM,WAAW,CAAC,eAAe,CAAC,CAAA;IAC/C,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAA;IAEtB,MAAM,MAAM,GAAG,YAAY,IAAI,MAAM,CAAC,UAAU,EAAE,CAAA;IAElD,MAAM,WAAW,CAAC,MAAM,EAAE,IAAI,CAAC,QAAQ,EAAE;QACvC,GAAG,IAAI,CAAC,QAAQ;QAChB,EAAE,EAAE,MAAM;QACV,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACnC,OAAO,EAAE,uBAAuB,eAAe,EAAE;KAClD,CAAC,CAAA;IAEF,OAAO,MAAM,CAAA;AACf,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,SAAiB;IAEjB,MAAM,IAAI,GAAG,MAAM,WAAW,CAAC,SAAS,CAAC,CAAA;IACzC,OAAO,IAAI,EAAE,QAAQ,IAAI,EAAE,CAAA;AAC7B,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,SAAiB,EACjB,OAA+B;IAE/B,MAAM,IAAI,GAAG,MAAM,WAAW,CAAC,SAAS,CAAC,CAAA;IACzC,IAAI,CAAC,IAAI;QAAE,OAAM;IAEjB,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;IAC3B,IAAI,CAAC,QAAQ,CAAC,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAA;IAClD,IAAI,CAAC,QAAQ,CAAC,YAAY,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAA;IAEjD,MAAM,WAAW,CAAC,SAAS,EAAE,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAA;AAC5D,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,SAAiB;IACnD,IAAI,CAAC;QACH,MAAM,EAAE,EAAE,EAAE,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,CAAA;QAC1C,MAAM,EAAE,CAAC,cAAc,CAAC,SAAS,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAA;QACrE,OAAO,IAAI,CAAA;IACb,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAA;IACd,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,SAAiB,EACjB,OAA0B;IAE1B,MAAM,IAAI,GAAG,MAAM,WAAW,CAAC,SAAS,CAAC,CAAA;IACzC,OAAO,IAAI,EAAE,QAAQ,IAAI,IAAI,CAAA;AAC/B,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,SAAiB,EACjB,KAAa,EACb,OAA0B;IAE1B,MAAM,IAAI,GAAG,MAAM,WAAW,CAAC,SAAS,CAAC,CAAA;IACzC,IAAI,CAAC,IAAI;QAAE,OAAM;IAEjB,IAAI,CAAC,QAAQ,CAAC,OAAO,GAAG,KAAK,CAAA;IAC7B,IAAI,CAAC,QAAQ,CAAC,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAA;IAElD,MAAM,WAAW,CAAC,SAAS,EAAE,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAA;AAC5D,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,SAAiB,EACjB,GAAkB,EAClB,OAA0B;IAE1B,MAAM,IAAI,GAAG,MAAM,WAAW,CAAC,SAAS,CAAC,CAAA;IACzC,IAAI,CAAC,IAAI;QAAE,OAEV;IAAC,IAAI,CAAC,QAAgB,CAAC,GAAG,GAAG,GAAG,CAAA;IACjC,IAAI,CAAC,QAAQ,CAAC,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAA;IAElD,MAAM,WAAW,CAAC,SAAS,EAAE,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAA;AAC5D,CAAC"}
1
+ {"version":3,"file":"session.js","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Detect if git CLI is available. Result is cached.
3
+ */
4
+ export declare function isGitAvailable(): Promise<boolean>;
5
+ /**
6
+ * Reset the cache (for testing).
7
+ */
8
+ export declare function resetGitCache(): void;
9
+ //# sourceMappingURL=git-detector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git-detector.d.ts","sourceRoot":"","sources":["../../src/snapshot/git-detector.ts"],"names":[],"mappings":"AAOA;;GAEG;AACH,wBAAsB,cAAc,IAAI,OAAO,CAAC,OAAO,CAAC,CASvD;AAED;;GAEG;AACH,wBAAgB,aAAa,IAAI,IAAI,CAEpC"}
@@ -0,0 +1,26 @@
1
+ import { execFile } from 'child_process';
2
+ import { promisify } from 'util';
3
+ const execFileAsync = promisify(execFile);
4
+ let cached = null;
5
+ /**
6
+ * Detect if git CLI is available. Result is cached.
7
+ */
8
+ export async function isGitAvailable() {
9
+ if (cached !== null)
10
+ return cached;
11
+ try {
12
+ await execFileAsync('git', ['--version']);
13
+ cached = true;
14
+ }
15
+ catch {
16
+ cached = false;
17
+ }
18
+ return cached;
19
+ }
20
+ /**
21
+ * Reset the cache (for testing).
22
+ */
23
+ export function resetGitCache() {
24
+ cached = null;
25
+ }
26
+ //# sourceMappingURL=git-detector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git-detector.js","sourceRoot":"","sources":["../../src/snapshot/git-detector.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AACxC,OAAO,EAAE,SAAS,EAAE,MAAM,MAAM,CAAA;AAEhC,MAAM,aAAa,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAA;AAEzC,IAAI,MAAM,GAAmB,IAAI,CAAA;AAEjC;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc;IAClC,IAAI,MAAM,KAAK,IAAI;QAAE,OAAO,MAAM,CAAA;IAClC,IAAI,CAAC;QACH,MAAM,aAAa,CAAC,KAAK,EAAE,CAAC,WAAW,CAAC,CAAC,CAAA;QACzC,MAAM,GAAG,IAAI,CAAA;IACf,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,GAAG,KAAK,CAAA;IAChB,CAAC;IACD,OAAO,MAAM,CAAA;AACf,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,aAAa;IAC3B,MAAM,GAAG,IAAI,CAAA;AACf,CAAC"}
@@ -0,0 +1,76 @@
1
+ export interface SnapshotEngineOptions {
2
+ worktree: string;
3
+ /** Snapshot repo directory. Defaults to ~/.openagent/snapshot/<project-hash>/<worktree-hash>/ */
4
+ snapshotDir?: string;
5
+ }
6
+ export interface RevertEntry {
7
+ hash: string;
8
+ path: string;
9
+ }
10
+ export declare class SnapshotEngine {
11
+ private worktree;
12
+ private _gitDir?;
13
+ private lock;
14
+ private gcTimer?;
15
+ private gcInterval?;
16
+ constructor(opts: SnapshotEngineOptions);
17
+ /** Snapshot repo path. Available after init(). */
18
+ private get gitDir();
19
+ /**
20
+ * Initialize the snapshot git repo.
21
+ * Creates a bare repo and syncs ignore rules from the source repo.
22
+ */
23
+ init(): Promise<void>;
24
+ /**
25
+ * Run a git command with GIT_DIR and GIT_WORK_TREE set.
26
+ */
27
+ private exec;
28
+ /**
29
+ * Run a git command without GIT_DIR/GIT_WORK_TREE (for init).
30
+ */
31
+ private execRaw;
32
+ /**
33
+ * Sync ignore rules from the source repo's .git/info/exclude.
34
+ */
35
+ private syncIgnoreRules;
36
+ /**
37
+ * Snapshot the current workspace state.
38
+ * Returns a tree hash that can be used to restore or revert later.
39
+ */
40
+ track(): Promise<string>;
41
+ /**
42
+ * Remove large untracked files from the index and add them to exclude.
43
+ */
44
+ private filterLargeUntracked;
45
+ /**
46
+ * Restore the entire workspace to a snapshot state.
47
+ */
48
+ restore(hash: string): Promise<void>;
49
+ /**
50
+ * List files changed since the given snapshot hash.
51
+ */
52
+ patchList(fromHash: string): Promise<string[]>;
53
+ /**
54
+ * Generate a unified diff between a snapshot and the current workspace.
55
+ */
56
+ diff(fromHash: string): Promise<string>;
57
+ /**
58
+ * Revert specific files to their state at a given snapshot.
59
+ * Files that did not exist in the snapshot are deleted.
60
+ */
61
+ revert(entries: RevertEntry[]): Promise<void>;
62
+ /**
63
+ * Run git gc to prune unreachable objects older than 7 days.
64
+ */
65
+ gc(): Promise<void>;
66
+ /**
67
+ * Start periodic background gc.
68
+ * First run after 1 minute, then every hour.
69
+ */
70
+ startGc(): void;
71
+ /**
72
+ * Stop background gc. Call on engine shutdown or in test cleanup.
73
+ */
74
+ stopGc(): void;
75
+ }
76
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/snapshot/index.ts"],"names":[],"mappings":"AAYA,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE,MAAM,CAAA;IAChB,iGAAiG;IACjG,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB;AAyCD,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;CACb;AAED,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAQ;IACxB,OAAO,CAAC,OAAO,CAAC,CAAQ;IACxB,OAAO,CAAC,IAAI,CAAkB;IAC9B,OAAO,CAAC,OAAO,CAAC,CAA+B;IAC/C,OAAO,CAAC,UAAU,CAAC,CAAgC;gBAEvC,IAAI,EAAE,qBAAqB;IAKvC,kDAAkD;IAClD,OAAO,KAAK,MAAM,GAGjB;IAED;;;OAGG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAiB3B;;OAEG;YACW,IAAI;IAWlB;;OAEG;YACW,OAAO;IAQrB;;OAEG;YACW,eAAe;IAY7B;;;OAGG;IACG,KAAK,IAAI,OAAO,CAAC,MAAM,CAAC;IAY9B;;OAEG;YACW,oBAAoB;IAoClC;;OAEG;IACG,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAU1C;;OAEG;IACG,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAYpD;;OAEG;IACG,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAY7C;;;OAGG;IACG,MAAM,CAAC,OAAO,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAqBnD;;OAEG;IACG,EAAE,IAAI,OAAO,CAAC,IAAI,CAAC;IAWzB;;;OAGG;IACH,OAAO,IAAI,IAAI;IASf;;OAEG;IACH,MAAM,IAAI,IAAI;CAUf"}