@fleetagent/pi-coding-agent 0.0.1 → 0.0.4
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/CHANGELOG.md +32 -0
- package/dist/core/agent-session.d.ts +32 -7
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +225 -12
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/compaction/branch-summarization.d.ts +2 -2
- package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
- package/dist/core/compaction/branch-summarization.js.map +1 -1
- package/dist/core/compaction/compaction.d.ts +2 -2
- package/dist/core/compaction/compaction.d.ts.map +1 -1
- package/dist/core/compaction/compaction.js +1 -1
- package/dist/core/compaction/compaction.js.map +1 -1
- package/dist/core/extensions/runner.d.ts +3 -3
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +5 -5
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/types.d.ts +15 -8
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/footer-data-provider.d.ts +1 -1
- package/dist/core/footer-data-provider.d.ts.map +1 -1
- package/dist/core/footer-data-provider.js +1 -1
- package/dist/core/footer-data-provider.js.map +1 -1
- package/dist/core/messages.d.ts +1 -0
- package/dist/core/messages.d.ts.map +1 -1
- package/dist/core/messages.js +4 -0
- package/dist/core/messages.js.map +1 -1
- package/dist/core/pi-agent.d.ts +5 -3
- package/dist/core/pi-agent.d.ts.map +1 -1
- package/dist/core/pi-agent.js +64 -18
- package/dist/core/pi-agent.js.map +1 -1
- package/dist/core/session/in-memory-session-manager.d.ts.map +1 -1
- package/dist/core/session/in-memory-session-manager.js +5 -7
- package/dist/core/session/in-memory-session-manager.js.map +1 -1
- package/dist/core/session/in-memory-session.d.ts +3 -1
- package/dist/core/session/in-memory-session.d.ts.map +1 -1
- package/dist/core/session/in-memory-session.js +5 -2
- package/dist/core/session/in-memory-session.js.map +1 -1
- package/dist/core/session/index.d.ts +2 -2
- package/dist/core/session/index.d.ts.map +1 -1
- package/dist/core/session/index.js.map +1 -1
- package/dist/core/session/jsonl-helpers.d.ts.map +1 -1
- package/dist/core/session/jsonl-helpers.js +4 -4
- package/dist/core/session/jsonl-helpers.js.map +1 -1
- package/dist/core/session/local-session-manager.d.ts.map +1 -1
- package/dist/core/session/local-session-manager.js +12 -11
- package/dist/core/session/local-session-manager.js.map +1 -1
- package/dist/core/session/local-session.d.ts +3 -1
- package/dist/core/session/local-session.d.ts.map +1 -1
- package/dist/core/session/local-session.js +7 -2
- package/dist/core/session/local-session.js.map +1 -1
- package/dist/core/session/remote-session-client.d.ts +6 -1
- package/dist/core/session/remote-session-client.d.ts.map +1 -1
- package/dist/core/session/remote-session-client.js.map +1 -1
- package/dist/core/session/remote-session-manager.d.ts.map +1 -1
- package/dist/core/session/remote-session-manager.js +28 -7
- package/dist/core/session/remote-session-manager.js.map +1 -1
- package/dist/core/session/remote-session.d.ts +3 -0
- package/dist/core/session/remote-session.d.ts.map +1 -1
- package/dist/core/session/remote-session.js +4 -1
- package/dist/core/session/remote-session.js.map +1 -1
- package/dist/core/session/session.d.ts +9 -3
- package/dist/core/session/session.d.ts.map +1 -1
- package/dist/core/session/session.js +64 -10
- package/dist/core/session/session.js.map +1 -1
- package/dist/core/session/stores/in-memory-session-store.d.ts +6 -14
- package/dist/core/session/stores/in-memory-session-store.d.ts.map +1 -1
- package/dist/core/session/stores/in-memory-session-store.js +8 -34
- package/dist/core/session/stores/in-memory-session-store.js.map +1 -1
- package/dist/core/session/stores/jsonl-session-store.d.ts +14 -14
- package/dist/core/session/stores/jsonl-session-store.d.ts.map +1 -1
- package/dist/core/session/stores/jsonl-session-store.js +153 -162
- package/dist/core/session/stores/jsonl-session-store.js.map +1 -1
- package/dist/core/session/stores/remote-session-store.d.ts +4 -6
- package/dist/core/session/stores/remote-session-store.d.ts.map +1 -1
- package/dist/core/session/stores/remote-session-store.js +18 -30
- package/dist/core/session/stores/remote-session-store.js.map +1 -1
- package/dist/core/session/stores/session-store.d.ts +1 -15
- package/dist/core/session/stores/session-store.d.ts.map +1 -1
- package/dist/core/session/stores/session-store.js.map +1 -1
- package/dist/core/session-cwd.d.ts +2 -2
- package/dist/core/session-cwd.d.ts.map +1 -1
- package/dist/core/session-cwd.js +5 -5
- package/dist/core/session-cwd.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +39 -37
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/docs/extensions.md +35 -32
- package/docs/index.md +1 -1
- package/docs/sdk.md +2 -0
- package/docs/session-format.md +21 -21
- package/docs/sessions.md +2 -2
- package/docs/tui.md +1 -1
- package/examples/README.md +3 -0
- package/examples/extensions/README.md +1 -1
- package/examples/extensions/auto-commit-on-exit.ts +1 -1
- package/examples/extensions/bookmark.ts +3 -3
- package/examples/extensions/confirm-destructive.ts +1 -1
- package/examples/extensions/custom-compaction.ts +1 -1
- package/examples/extensions/custom-footer.ts +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/git-checkpoint.ts +1 -1
- package/examples/extensions/handoff.ts +2 -2
- package/examples/extensions/plan-mode/index.ts +1 -1
- package/examples/extensions/preset.ts +1 -1
- package/examples/extensions/qna.ts +1 -1
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/snake.ts +1 -1
- package/examples/extensions/space-invaders.ts +1 -1
- package/examples/extensions/summarize.ts +1 -1
- package/examples/extensions/tic-tac-toe.ts +1 -1
- package/examples/extensions/todo.ts +1 -1
- package/examples/extensions/tools.ts +1 -1
- package/examples/extensions/with-deps/package.json +1 -1
- package/examples/remote-session-server/README.md +66 -0
- package/examples/remote-session-server/server.ts +359 -0
- package/examples/sdk/11-sessions.ts +3 -3
- package/examples/sdk/13-session-runtime.ts +6 -6
- package/npm-shrinkwrap.json +12 -12
- package/package.json +4 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"local-session-manager.js","sourceRoot":"","sources":["../../../src/core/session/local-session-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAC9D,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpD,OAAO,EAAE,uBAAuB,EAAE,MAAM,gBAAgB,CAAC;AACzD,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAC3C,OAAO,
|
|
1
|
+
{"version":3,"file":"local-session-manager.js","sourceRoot":"","sources":["../../../src/core/session/local-session-manager.ts"],"names":[],"mappings":"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","sourcesContent":["import { copyFileSync, existsSync, mkdirSync } from \"node:fs\";\nimport { basename, join, resolve } from \"node:path\";\nimport { CURRENT_SESSION_VERSION } from \"./constants.ts\";\nimport { createSessionId } from \"./ids.ts\";\nimport { findMostRecentSession, getDefaultSessionDir, loadEntriesFromFile } from \"./jsonl-helpers.ts\";\nimport { LocalSession } from \"./local-session.ts\";\nimport type { Session } from \"./session.ts\";\nimport type { OpenSessionOptions, SessionManager } from \"./session-manager.ts\";\nimport {\n\tensureDir,\n\tforkSession as forkJsonlSession,\n\tgetSessionDirForReference,\n\tgetSessionsRoot,\n\tlistAll as listAllJsonlSessions,\n\tlist as listJsonlSessions,\n} from \"./stores/jsonl-session-store.ts\";\nimport type { NewSessionOptions, SessionHeader, SessionInfo, SessionListProgress } from \"./types.ts\";\n\nexport interface LocalSessionManagerOptions {\n\tcwd: string;\n\tsessionDir?: string;\n}\n\nexport class LocalSessionManager implements SessionManager {\n\tprivate readonly cwd: string;\n\tprivate readonly sessionDir?: string;\n\n\tconstructor(options: LocalSessionManagerOptions) {\n\t\tthis.cwd = options.cwd;\n\t\tthis.sessionDir = options.sessionDir;\n\t}\n\n\tcreate(options?: NewSessionOptions): LocalSession {\n\t\tconst dir = this.sessionDir ?? getDefaultSessionDir(this.cwd);\n\t\tconst session = new LocalSession(this.cwd, dir, undefined, this);\n\t\tif (options?.id || options?.parentSession) {\n\t\t\tsession.newSession(options);\n\t\t}\n\t\treturn session;\n\t}\n\n\topenReference(reference: string, options?: OpenSessionOptions): LocalSession {\n\t\tconst entries = loadEntriesFromFile(reference);\n\t\tconst header = entries.find((entry) => entry.type === \"session\") as SessionHeader | undefined;\n\t\tconst cwd = options?.cwdOverride ?? header?.cwd ?? this.cwd;\n\t\tconst dir = this.sessionDir ?? getSessionDirForReference(reference);\n\t\treturn new LocalSession(cwd, dir, reference, this);\n\t}\n\n\tcontinueRecent(): LocalSession {\n\t\tconst dir = this.sessionDir ?? getDefaultSessionDir(this.cwd);\n\t\tconst mostRecent = findMostRecentSession(dir);\n\t\tif (mostRecent) {\n\t\t\treturn new LocalSession(this.cwd, dir, mostRecent, this);\n\t\t}\n\t\treturn new LocalSession(this.cwd, dir, undefined, this);\n\t}\n\n\tforkFrom(reference: string): LocalSession {\n\t\tconst sourceEntries = loadEntriesFromFile(reference);\n\t\tif (sourceEntries.length === 0) {\n\t\t\tthrow new Error(`Cannot fork: source session is empty or invalid: ${reference}`);\n\t\t}\n\n\t\tconst sourceHeader = sourceEntries.find((entry) => entry.type === \"session\") as SessionHeader | undefined;\n\t\tif (!sourceHeader) {\n\t\t\tthrow new Error(`Cannot fork: source session has no header: ${reference}`);\n\t\t}\n\n\t\tconst dir = this.sessionDir ?? getDefaultSessionDir(this.cwd);\n\t\tensureDir(dir);\n\n\t\tconst newSessionId = createSessionId();\n\t\tconst timestamp = new Date().toISOString();\n\t\tconst newHeader: SessionHeader = {\n\t\t\ttype: \"session\",\n\t\t\tversion: CURRENT_SESSION_VERSION,\n\t\t\tid: newSessionId,\n\t\t\ttimestamp,\n\t\t\tcwd: this.cwd,\n\t\t\tparentSession: reference,\n\t\t};\n\t\tconst newSessionReference = forkJsonlSession(dir, newHeader, sourceEntries);\n\n\t\treturn new LocalSession(this.cwd, dir, newSessionReference, this);\n\t}\n\n\tforkSession(source: Session, targetLeafId: string | null): LocalSession {\n\t\tconst parentSession = source.getSessionReference();\n\t\tif (!targetLeafId) {\n\t\t\tconst session = this.create();\n\t\t\tsession.newSession({ parentSession });\n\t\t\treturn session;\n\t\t}\n\n\t\tconst branchSource = parentSession ? this.openReference(parentSession) : source;\n\t\tconst forkedReference = branchSource.createBranchedSession(targetLeafId);\n\t\tif (!forkedReference) {\n\t\t\tthrow new Error(\"Failed to create forked session\");\n\t\t}\n\t\treturn this.openReference(forkedReference);\n\t}\n\n\timportJsonl(inputPath: string, options?: OpenSessionOptions): LocalSession {\n\t\tconst resolvedPath = resolve(inputPath);\n\t\tif (!existsSync(resolvedPath)) {\n\t\t\tthrow new Error(`File not found: ${resolvedPath}`);\n\t\t}\n\n\t\tconst dir = this.sessionDir ?? getDefaultSessionDir(this.cwd);\n\t\tif (!existsSync(dir)) {\n\t\t\tmkdirSync(dir, { recursive: true });\n\t\t}\n\n\t\tconst destinationPath = join(dir, basename(resolvedPath));\n\t\tif (resolve(destinationPath) !== resolvedPath) {\n\t\t\tcopyFileSync(resolvedPath, destinationPath);\n\t\t}\n\t\treturn this.openReference(destinationPath, options);\n\t}\n\n\tasync list(onProgress?: SessionListProgress): Promise<SessionInfo[]> {\n\t\tconst dir = this.sessionDir ?? getDefaultSessionDir(this.cwd);\n\t\tconst sessions = await listJsonlSessions(dir, onProgress);\n\t\tsessions.sort((a, b) => b.modified.getTime() - a.modified.getTime());\n\t\treturn sessions;\n\t}\n\n\tasync listAll(onProgress?: SessionListProgress): Promise<SessionInfo[]> {\n\t\tconst sessions = await listAllJsonlSessions(getSessionsRoot(), onProgress);\n\t\tsessions.sort((a, b) => b.modified.getTime() - a.modified.getTime());\n\t\treturn sessions;\n\t}\n}\n"]}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { Session } from "./session.ts";
|
|
2
|
+
import type { SessionManager } from "./session-manager.ts";
|
|
2
3
|
export declare class LocalSession extends Session {
|
|
3
|
-
constructor(cwd: string, sessionDir: string, sessionReference: string | undefined);
|
|
4
|
+
constructor(cwd: string, sessionDir: string, sessionReference: string | undefined, sessionManager?: SessionManager);
|
|
5
|
+
protected prepareNewSessionReference(sessionDir: string, sessionId: string, timestamp: string): string | undefined;
|
|
4
6
|
}
|
|
5
7
|
//# sourceMappingURL=local-session.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"local-session.d.ts","sourceRoot":"","sources":["../../../src/core/session/local-session.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"local-session.d.ts","sourceRoot":"","sources":["../../../src/core/session/local-session.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAG3D,qBAAa,YAAa,SAAQ,OAAO;IACxC,YAAY,GAAG,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,GAAG,SAAS,EAAE,cAAc,CAAC,EAAE,cAAc,EAEjH;IAED,SAAS,CAAC,0BAA0B,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAGjH;CACD","sourcesContent":["import { join } from \"node:path\";\nimport { Session } from \"./session.ts\";\nimport type { SessionManager } from \"./session-manager.ts\";\nimport { JsonlSessionStore } from \"./stores/jsonl-session-store.ts\";\n\nexport class LocalSession extends Session {\n\tconstructor(cwd: string, sessionDir: string, sessionReference: string | undefined, sessionManager?: SessionManager) {\n\t\tsuper(cwd, sessionDir, sessionReference, new JsonlSessionStore(), sessionManager);\n\t}\n\n\tprotected prepareNewSessionReference(sessionDir: string, sessionId: string, timestamp: string): string | undefined {\n\t\tconst fileTimestamp = timestamp.replace(/[:.]/g, \"-\");\n\t\treturn join(sessionDir, `${fileTimestamp}_${sessionId}.jsonl`);\n\t}\n}\n"]}
|
|
@@ -1,8 +1,13 @@
|
|
|
1
|
+
import { join } from "node:path";
|
|
1
2
|
import { Session } from "./session.js";
|
|
2
3
|
import { JsonlSessionStore } from "./stores/jsonl-session-store.js";
|
|
3
4
|
export class LocalSession extends Session {
|
|
4
|
-
constructor(cwd, sessionDir, sessionReference) {
|
|
5
|
-
super(cwd, sessionDir, sessionReference, new JsonlSessionStore());
|
|
5
|
+
constructor(cwd, sessionDir, sessionReference, sessionManager) {
|
|
6
|
+
super(cwd, sessionDir, sessionReference, new JsonlSessionStore(), sessionManager);
|
|
7
|
+
}
|
|
8
|
+
prepareNewSessionReference(sessionDir, sessionId, timestamp) {
|
|
9
|
+
const fileTimestamp = timestamp.replace(/[:.]/g, "-");
|
|
10
|
+
return join(sessionDir, `${fileTimestamp}_${sessionId}.jsonl`);
|
|
6
11
|
}
|
|
7
12
|
}
|
|
8
13
|
//# sourceMappingURL=local-session.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"local-session.js","sourceRoot":"","sources":["../../../src/core/session/local-session.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"local-session.js","sourceRoot":"","sources":["../../../src/core/session/local-session.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC,OAAO,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AAEpE,MAAM,OAAO,YAAa,SAAQ,OAAO;IACxC,YAAY,GAAW,EAAE,UAAkB,EAAE,gBAAoC,EAAE,cAA+B,EAAE;QACnH,KAAK,CAAC,GAAG,EAAE,UAAU,EAAE,gBAAgB,EAAE,IAAI,iBAAiB,EAAE,EAAE,cAAc,CAAC,CAAC;IAAA,CAClF;IAES,0BAA0B,CAAC,UAAkB,EAAE,SAAiB,EAAE,SAAiB,EAAsB;QAClH,MAAM,aAAa,GAAG,SAAS,CAAC,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;QACtD,OAAO,IAAI,CAAC,UAAU,EAAE,GAAG,aAAa,IAAI,SAAS,QAAQ,CAAC,CAAC;IAAA,CAC/D;CACD","sourcesContent":["import { join } from \"node:path\";\nimport { Session } from \"./session.ts\";\nimport type { SessionManager } from \"./session-manager.ts\";\nimport { JsonlSessionStore } from \"./stores/jsonl-session-store.ts\";\n\nexport class LocalSession extends Session {\n\tconstructor(cwd: string, sessionDir: string, sessionReference: string | undefined, sessionManager?: SessionManager) {\n\t\tsuper(cwd, sessionDir, sessionReference, new JsonlSessionStore(), sessionManager);\n\t}\n\n\tprotected prepareNewSessionReference(sessionDir: string, sessionId: string, timestamp: string): string | undefined {\n\t\tconst fileTimestamp = timestamp.replace(/[:.]/g, \"-\");\n\t\treturn join(sessionDir, `${fileTimestamp}_${sessionId}.jsonl`);\n\t}\n}\n"]}
|
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
import type { FileEntry, SessionInfo } from "./types.ts";
|
|
2
|
+
export type RemoteSessionInfo = Omit<SessionInfo, "path" | "created" | "modified"> & {
|
|
3
|
+
path?: string;
|
|
4
|
+
created: Date | string;
|
|
5
|
+
modified: Date | string;
|
|
6
|
+
};
|
|
2
7
|
export interface RemoteSessionClientOptions {
|
|
3
8
|
baseUrl: string;
|
|
4
9
|
token: string;
|
|
@@ -46,7 +51,7 @@ export interface ImportRemoteSessionJsonlRequest {
|
|
|
46
51
|
metadata?: Record<string, unknown>;
|
|
47
52
|
}
|
|
48
53
|
export interface ListRemoteSessionsResponse {
|
|
49
|
-
sessions:
|
|
54
|
+
sessions: RemoteSessionInfo[];
|
|
50
55
|
}
|
|
51
56
|
export declare class RemoteSessionClientError extends Error {
|
|
52
57
|
readonly status: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"remote-session-client.d.ts","sourceRoot":"","sources":["../../../src/core/session/remote-session-client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEzD,MAAM,WAAW,0BAA0B;IAC1C,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;CACrB;AAED,MAAM,WAAW,qBAAqB;IACrC,SAAS,EAAE,MAAM,CAAC;IAClB,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,SAAS,EAAE,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,0BAA0B;IAC1C,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC;AAED,MAAM,WAAW,iCAAiC;IACjD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,SAAS,EAAE,CAAC;CACrB;AAED,MAAM,WAAW,kCAAkC;IAClD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,mCAAmC;IACnD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,SAAS,EAAE,CAAC;CACrB;AAED,MAAM,WAAW,oCAAoC;IACpD,IAAI,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,wBAAwB;IACxC,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,+BAA+B;IAC/C,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,SAAS,EAAE,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC;AAED,MAAM,WAAW,0BAA0B;IAC1C,QAAQ,EAAE,
|
|
1
|
+
{"version":3,"file":"remote-session-client.d.ts","sourceRoot":"","sources":["../../../src/core/session/remote-session-client.ts"],"names":[],"mappings":"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","sourcesContent":["import type { FileEntry, SessionInfo } from \"./types.ts\";\n\nexport type RemoteSessionInfo = Omit<SessionInfo, \"path\" | \"created\" | \"modified\"> & {\n\tpath?: string;\n\tcreated: Date | string;\n\tmodified: Date | string;\n};\n\nexport interface RemoteSessionClientOptions {\n\tbaseUrl: string;\n\ttoken: string;\n\tfetch?: typeof fetch;\n}\n\nexport interface RemoteSessionSnapshot {\n\treference: string;\n\tid: string;\n\tversion?: number;\n\tentries: FileEntry[];\n\tetag?: string;\n}\n\nexport interface CreateRemoteSessionRequest {\n\tid?: string;\n\tcwd: string;\n\tprojectId?: string;\n\tparentSession?: string;\n\tmetadata?: Record<string, unknown>;\n}\n\nexport interface AppendRemoteSessionEntriesRequest {\n\tbaseEtag?: string;\n\tentries: FileEntry[];\n}\n\nexport interface AppendRemoteSessionEntriesResponse {\n\tetag?: string;\n\taccepted: number;\n}\n\nexport interface ReplaceRemoteSessionSnapshotRequest {\n\tbaseEtag?: string;\n\tentries: FileEntry[];\n}\n\nexport interface ReplaceRemoteSessionSnapshotResponse {\n\tetag?: string;\n}\n\nexport interface ForkRemoteSessionRequest {\n\tcwd: string;\n\tprojectId?: string;\n\tleafId?: string;\n}\n\nexport interface ImportRemoteSessionJsonlRequest {\n\tcwd: string;\n\tprojectId?: string;\n\tsourceName?: string;\n\tentries: FileEntry[];\n\tmetadata?: Record<string, unknown>;\n}\n\nexport interface ListRemoteSessionsResponse {\n\tsessions: RemoteSessionInfo[];\n}\n\nexport class RemoteSessionClientError extends Error {\n\treadonly status: number;\n\treadonly responseText: string;\n\n\tconstructor(status: number, responseText: string) {\n\t\tsuper(`Remote session request failed with status ${status}: ${responseText}`);\n\t\tthis.name = \"RemoteSessionClientError\";\n\t\tthis.status = status;\n\t\tthis.responseText = responseText;\n\t}\n}\n\nexport class RemoteSessionClient {\n\tprivate readonly baseUrl: string;\n\tprivate readonly token: string;\n\tprivate readonly fetchImpl: typeof fetch;\n\n\tconstructor(options: RemoteSessionClientOptions) {\n\t\tthis.baseUrl = options.baseUrl.replace(/\\/+$/, \"\");\n\t\tthis.token = options.token;\n\t\tthis.fetchImpl = options.fetch ?? fetch;\n\t}\n\n\tcreateSession(request: CreateRemoteSessionRequest): Promise<RemoteSessionSnapshot> {\n\t\treturn this.request(\"POST\", \"/v1/sessions\", request);\n\t}\n\n\topenSession(sessionIdOrReference: string): Promise<RemoteSessionSnapshot> {\n\t\treturn this.request(\"GET\", `/v1/sessions/${encodeURIComponent(parseRemoteSessionId(sessionIdOrReference))}`);\n\t}\n\n\tappendEntries(\n\t\tsessionIdOrReference: string,\n\t\trequest: AppendRemoteSessionEntriesRequest,\n\t): Promise<AppendRemoteSessionEntriesResponse> {\n\t\treturn this.request(\n\t\t\t\"POST\",\n\t\t\t`/v1/sessions/${encodeURIComponent(parseRemoteSessionId(sessionIdOrReference))}/entries`,\n\t\t\trequest,\n\t\t);\n\t}\n\n\treplaceSnapshot(\n\t\tsessionIdOrReference: string,\n\t\trequest: ReplaceRemoteSessionSnapshotRequest,\n\t): Promise<ReplaceRemoteSessionSnapshotResponse> {\n\t\treturn this.request(\n\t\t\t\"PUT\",\n\t\t\t`/v1/sessions/${encodeURIComponent(parseRemoteSessionId(sessionIdOrReference))}/snapshot`,\n\t\t\trequest,\n\t\t);\n\t}\n\n\tlistSessions(): Promise<ListRemoteSessionsResponse> {\n\t\treturn this.request(\"GET\", \"/v1/sessions\");\n\t}\n\n\tgetRecentSession(): Promise<RemoteSessionSnapshot> {\n\t\treturn this.request(\"GET\", \"/v1/sessions/recent\");\n\t}\n\n\tforkSession(sessionIdOrReference: string, request: ForkRemoteSessionRequest): Promise<RemoteSessionSnapshot> {\n\t\treturn this.request(\n\t\t\t\"POST\",\n\t\t\t`/v1/sessions/${encodeURIComponent(parseRemoteSessionId(sessionIdOrReference))}/fork`,\n\t\t\trequest,\n\t\t);\n\t}\n\n\timportJsonl(request: ImportRemoteSessionJsonlRequest): Promise<RemoteSessionSnapshot> {\n\t\treturn this.request(\"POST\", \"/v1/sessions/import-jsonl\", request);\n\t}\n\n\tprivate async request<T>(method: string, path: string, body?: unknown): Promise<T> {\n\t\tconst response = await this.fetchImpl(`${this.baseUrl}${path}`, {\n\t\t\tmethod,\n\t\t\theaders: {\n\t\t\t\tAuthorization: `Bearer ${this.token}`,\n\t\t\t\tAccept: \"application/json\",\n\t\t\t\t...(body === undefined ? {} : { \"Content-Type\": \"application/json\" }),\n\t\t\t},\n\t\t\tbody: body === undefined ? undefined : JSON.stringify(body),\n\t\t});\n\n\t\tif (!response.ok) {\n\t\t\tthrow new RemoteSessionClientError(response.status, await response.text());\n\t\t}\n\n\t\tif (response.status === 204) {\n\t\t\treturn undefined as T;\n\t\t}\n\n\t\treturn (await response.json()) as T;\n\t}\n}\n\nexport function parseRemoteSessionId(reference: string): string {\n\treturn reference.startsWith(\"remote:\") ? reference.slice(\"remote:\".length) : reference;\n}\n\nexport function formatRemoteSessionReference(sessionId: string): string {\n\treturn sessionId.startsWith(\"remote:\") ? sessionId : `remote:${sessionId}`;\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"remote-session-client.js","sourceRoot":"","sources":["../../../src/core/session/remote-session-client.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"remote-session-client.js","sourceRoot":"","sources":["../../../src/core/session/remote-session-client.ts"],"names":[],"mappings":"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","sourcesContent":["import type { FileEntry, SessionInfo } from \"./types.ts\";\n\nexport type RemoteSessionInfo = Omit<SessionInfo, \"path\" | \"created\" | \"modified\"> & {\n\tpath?: string;\n\tcreated: Date | string;\n\tmodified: Date | string;\n};\n\nexport interface RemoteSessionClientOptions {\n\tbaseUrl: string;\n\ttoken: string;\n\tfetch?: typeof fetch;\n}\n\nexport interface RemoteSessionSnapshot {\n\treference: string;\n\tid: string;\n\tversion?: number;\n\tentries: FileEntry[];\n\tetag?: string;\n}\n\nexport interface CreateRemoteSessionRequest {\n\tid?: string;\n\tcwd: string;\n\tprojectId?: string;\n\tparentSession?: string;\n\tmetadata?: Record<string, unknown>;\n}\n\nexport interface AppendRemoteSessionEntriesRequest {\n\tbaseEtag?: string;\n\tentries: FileEntry[];\n}\n\nexport interface AppendRemoteSessionEntriesResponse {\n\tetag?: string;\n\taccepted: number;\n}\n\nexport interface ReplaceRemoteSessionSnapshotRequest {\n\tbaseEtag?: string;\n\tentries: FileEntry[];\n}\n\nexport interface ReplaceRemoteSessionSnapshotResponse {\n\tetag?: string;\n}\n\nexport interface ForkRemoteSessionRequest {\n\tcwd: string;\n\tprojectId?: string;\n\tleafId?: string;\n}\n\nexport interface ImportRemoteSessionJsonlRequest {\n\tcwd: string;\n\tprojectId?: string;\n\tsourceName?: string;\n\tentries: FileEntry[];\n\tmetadata?: Record<string, unknown>;\n}\n\nexport interface ListRemoteSessionsResponse {\n\tsessions: RemoteSessionInfo[];\n}\n\nexport class RemoteSessionClientError extends Error {\n\treadonly status: number;\n\treadonly responseText: string;\n\n\tconstructor(status: number, responseText: string) {\n\t\tsuper(`Remote session request failed with status ${status}: ${responseText}`);\n\t\tthis.name = \"RemoteSessionClientError\";\n\t\tthis.status = status;\n\t\tthis.responseText = responseText;\n\t}\n}\n\nexport class RemoteSessionClient {\n\tprivate readonly baseUrl: string;\n\tprivate readonly token: string;\n\tprivate readonly fetchImpl: typeof fetch;\n\n\tconstructor(options: RemoteSessionClientOptions) {\n\t\tthis.baseUrl = options.baseUrl.replace(/\\/+$/, \"\");\n\t\tthis.token = options.token;\n\t\tthis.fetchImpl = options.fetch ?? fetch;\n\t}\n\n\tcreateSession(request: CreateRemoteSessionRequest): Promise<RemoteSessionSnapshot> {\n\t\treturn this.request(\"POST\", \"/v1/sessions\", request);\n\t}\n\n\topenSession(sessionIdOrReference: string): Promise<RemoteSessionSnapshot> {\n\t\treturn this.request(\"GET\", `/v1/sessions/${encodeURIComponent(parseRemoteSessionId(sessionIdOrReference))}`);\n\t}\n\n\tappendEntries(\n\t\tsessionIdOrReference: string,\n\t\trequest: AppendRemoteSessionEntriesRequest,\n\t): Promise<AppendRemoteSessionEntriesResponse> {\n\t\treturn this.request(\n\t\t\t\"POST\",\n\t\t\t`/v1/sessions/${encodeURIComponent(parseRemoteSessionId(sessionIdOrReference))}/entries`,\n\t\t\trequest,\n\t\t);\n\t}\n\n\treplaceSnapshot(\n\t\tsessionIdOrReference: string,\n\t\trequest: ReplaceRemoteSessionSnapshotRequest,\n\t): Promise<ReplaceRemoteSessionSnapshotResponse> {\n\t\treturn this.request(\n\t\t\t\"PUT\",\n\t\t\t`/v1/sessions/${encodeURIComponent(parseRemoteSessionId(sessionIdOrReference))}/snapshot`,\n\t\t\trequest,\n\t\t);\n\t}\n\n\tlistSessions(): Promise<ListRemoteSessionsResponse> {\n\t\treturn this.request(\"GET\", \"/v1/sessions\");\n\t}\n\n\tgetRecentSession(): Promise<RemoteSessionSnapshot> {\n\t\treturn this.request(\"GET\", \"/v1/sessions/recent\");\n\t}\n\n\tforkSession(sessionIdOrReference: string, request: ForkRemoteSessionRequest): Promise<RemoteSessionSnapshot> {\n\t\treturn this.request(\n\t\t\t\"POST\",\n\t\t\t`/v1/sessions/${encodeURIComponent(parseRemoteSessionId(sessionIdOrReference))}/fork`,\n\t\t\trequest,\n\t\t);\n\t}\n\n\timportJsonl(request: ImportRemoteSessionJsonlRequest): Promise<RemoteSessionSnapshot> {\n\t\treturn this.request(\"POST\", \"/v1/sessions/import-jsonl\", request);\n\t}\n\n\tprivate async request<T>(method: string, path: string, body?: unknown): Promise<T> {\n\t\tconst response = await this.fetchImpl(`${this.baseUrl}${path}`, {\n\t\t\tmethod,\n\t\t\theaders: {\n\t\t\t\tAuthorization: `Bearer ${this.token}`,\n\t\t\t\tAccept: \"application/json\",\n\t\t\t\t...(body === undefined ? {} : { \"Content-Type\": \"application/json\" }),\n\t\t\t},\n\t\t\tbody: body === undefined ? undefined : JSON.stringify(body),\n\t\t});\n\n\t\tif (!response.ok) {\n\t\t\tthrow new RemoteSessionClientError(response.status, await response.text());\n\t\t}\n\n\t\tif (response.status === 204) {\n\t\t\treturn undefined as T;\n\t\t}\n\n\t\treturn (await response.json()) as T;\n\t}\n}\n\nexport function parseRemoteSessionId(reference: string): string {\n\treturn reference.startsWith(\"remote:\") ? reference.slice(\"remote:\".length) : reference;\n}\n\nexport function formatRemoteSessionReference(sessionId: string): string {\n\treturn sessionId.startsWith(\"remote:\") ? sessionId : `remote:${sessionId}`;\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"remote-session-manager.d.ts","sourceRoot":"","sources":["../../../src/core/session/remote-session-manager.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAGpD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,KAAK,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC/E,OAAO,KAAK,EAAE,iBAAiB,EAAiB,WAAW,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAErG,MAAM,WAAW,2BAA2B;IAC3C,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;CACrB;
|
|
1
|
+
{"version":3,"file":"remote-session-manager.d.ts","sourceRoot":"","sources":["../../../src/core/session/remote-session-manager.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAGpD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,KAAK,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC/E,OAAO,KAAK,EAAE,iBAAiB,EAAiB,WAAW,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAErG,MAAM,WAAW,2BAA2B;IAC3C,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;CACrB;AAkBD;;;;;GAKG;AACH,qBAAa,oBAAqB,YAAW,cAAc;IAC1D,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAsB;IAC7C,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAS;IAC7B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAqB;IAE/C,YAAY,OAAO,EAAE,2BAA2B,EAI/C;IAEK,MAAM,CAAC,OAAO,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,aAAa,CAAC,CAQhE;IAEK,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,aAAa,CAAC,CAQ3F;IAEK,cAAc,IAAI,OAAO,CAAC,aAAa,CAAC,CAQ7C;IAEK,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAGxD;IAEK,WAAW,CAAC,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,aAAa,CAAC,CAWtF;IAEK,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,aAAa,CAAC,CAyBzF;IAEK,IAAI,CAAC,WAAW,CAAC,EAAE,mBAAmB,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CAGpE;IAEK,OAAO,CAAC,WAAW,CAAC,EAAE,mBAAmB,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CAGvE;CACD","sourcesContent":["import { existsSync } from \"node:fs\";\nimport { basename, resolve } from \"node:path\";\nimport { loadEntriesFromFile } from \"./jsonl-helpers.ts\";\nimport { migrateToCurrentVersion } from \"./migrations.ts\";\nimport { RemoteSession } from \"./remote-session.ts\";\nimport type { RemoteSessionInfo, RemoteSessionSnapshot } from \"./remote-session-client.ts\";\nimport { RemoteSessionClient } from \"./remote-session-client.ts\";\nimport type { Session } from \"./session.ts\";\nimport type { OpenSessionOptions, SessionManager } from \"./session-manager.ts\";\nimport type { NewSessionOptions, SessionHeader, SessionInfo, SessionListProgress } from \"./types.ts\";\n\nexport interface RemoteSessionManagerOptions {\n\tbaseUrl: string;\n\ttoken: string;\n\tcwd: string;\n\tprojectId?: string;\n\tfetch?: typeof fetch;\n}\n\nfunction getSnapshotCwd(snapshot: RemoteSessionSnapshot, fallback: string): string {\n\tconst header = snapshot.entries.find((entry) => entry.type === \"session\") as SessionHeader | undefined;\n\treturn header?.cwd ?? fallback;\n}\n\nfunction normalizeRemoteSessionInfo(session: RemoteSessionInfo): SessionInfo {\n\tconst reference = session.reference ?? session.path;\n\treturn {\n\t\t...session,\n\t\treference,\n\t\tpath: session.path ?? reference ?? session.id,\n\t\tcreated: session.created instanceof Date ? session.created : new Date(session.created),\n\t\tmodified: session.modified instanceof Date ? session.modified : new Date(session.modified),\n\t};\n}\n\n/**\n * Remote session manager skeleton.\n *\n * Lifecycle methods are async-compatible through SessionManager so this backend\n * can fetch/create snapshots before returning an active Session.\n */\nexport class RemoteSessionManager implements SessionManager {\n\tprivate readonly client: RemoteSessionClient;\n\tprivate readonly cwd: string;\n\tprivate readonly projectId: string | undefined;\n\n\tconstructor(options: RemoteSessionManagerOptions) {\n\t\tthis.client = new RemoteSessionClient({ baseUrl: options.baseUrl, token: options.token, fetch: options.fetch });\n\t\tthis.cwd = options.cwd;\n\t\tthis.projectId = options.projectId;\n\t}\n\n\tasync create(options?: NewSessionOptions): Promise<RemoteSession> {\n\t\tconst snapshot = await this.client.createSession({\n\t\t\tid: options?.id,\n\t\t\tcwd: this.cwd,\n\t\t\tprojectId: this.projectId,\n\t\t\tparentSession: options?.parentSession,\n\t\t});\n\t\treturn new RemoteSession({ client: this.client, cwd: this.cwd, snapshot, sessionManager: this });\n\t}\n\n\tasync openReference(reference: string, options?: OpenSessionOptions): Promise<RemoteSession> {\n\t\tconst snapshot = await this.client.openSession(reference);\n\t\treturn new RemoteSession({\n\t\t\tclient: this.client,\n\t\t\tcwd: options?.cwdOverride ?? getSnapshotCwd(snapshot, this.cwd),\n\t\t\tsnapshot,\n\t\t\tsessionManager: this,\n\t\t});\n\t}\n\n\tasync continueRecent(): Promise<RemoteSession> {\n\t\tconst snapshot = await this.client.getRecentSession();\n\t\treturn new RemoteSession({\n\t\t\tclient: this.client,\n\t\t\tcwd: getSnapshotCwd(snapshot, this.cwd),\n\t\t\tsnapshot,\n\t\t\tsessionManager: this,\n\t\t});\n\t}\n\n\tasync forkFrom(reference: string): Promise<RemoteSession> {\n\t\tconst snapshot = await this.client.forkSession(reference, { cwd: this.cwd, projectId: this.projectId });\n\t\treturn new RemoteSession({ client: this.client, cwd: this.cwd, snapshot, sessionManager: this });\n\t}\n\n\tasync forkSession(source: Session, targetLeafId: string | null): Promise<RemoteSession> {\n\t\tconst reference = source.getSessionReference();\n\t\tif (!reference) {\n\t\t\tthrow new Error(\"Cannot fork a remote session without a session reference\");\n\t\t}\n\t\tconst snapshot = await this.client.forkSession(reference, {\n\t\t\tcwd: this.cwd,\n\t\t\tprojectId: this.projectId,\n\t\t\tleafId: targetLeafId ?? undefined,\n\t\t});\n\t\treturn new RemoteSession({ client: this.client, cwd: this.cwd, snapshot, sessionManager: this });\n\t}\n\n\tasync importJsonl(inputPath: string, options?: OpenSessionOptions): Promise<RemoteSession> {\n\t\tconst resolvedPath = resolve(inputPath);\n\t\tif (!existsSync(resolvedPath)) {\n\t\t\tthrow new Error(`File not found: ${resolvedPath}`);\n\t\t}\n\n\t\tconst entries = loadEntriesFromFile(resolvedPath);\n\t\tif (entries.length === 0) {\n\t\t\tthrow new Error(`Cannot import empty or invalid session JSONL: ${resolvedPath}`);\n\t\t}\n\t\tmigrateToCurrentVersion(entries);\n\n\t\tconst cwd = options?.cwdOverride ?? getSnapshotCwd({ id: \"\", reference: \"\", entries }, this.cwd);\n\t\tconst snapshot = await this.client.importJsonl({\n\t\t\tcwd,\n\t\t\tprojectId: this.projectId,\n\t\t\tsourceName: basename(resolvedPath),\n\t\t\tentries,\n\t\t});\n\t\treturn new RemoteSession({\n\t\t\tclient: this.client,\n\t\t\tcwd: getSnapshotCwd(snapshot, cwd),\n\t\t\tsnapshot,\n\t\t\tsessionManager: this,\n\t\t});\n\t}\n\n\tasync list(_onProgress?: SessionListProgress): Promise<SessionInfo[]> {\n\t\tconst response = await this.client.listSessions();\n\t\treturn response.sessions.map((session) => normalizeRemoteSessionInfo(session));\n\t}\n\n\tasync listAll(_onProgress?: SessionListProgress): Promise<SessionInfo[]> {\n\t\tconst response = await this.client.listSessions();\n\t\treturn response.sessions.map((session) => normalizeRemoteSessionInfo(session));\n\t}\n}\n"]}
|
|
@@ -8,6 +8,16 @@ function getSnapshotCwd(snapshot, fallback) {
|
|
|
8
8
|
const header = snapshot.entries.find((entry) => entry.type === "session");
|
|
9
9
|
return header?.cwd ?? fallback;
|
|
10
10
|
}
|
|
11
|
+
function normalizeRemoteSessionInfo(session) {
|
|
12
|
+
const reference = session.reference ?? session.path;
|
|
13
|
+
return {
|
|
14
|
+
...session,
|
|
15
|
+
reference,
|
|
16
|
+
path: session.path ?? reference ?? session.id,
|
|
17
|
+
created: session.created instanceof Date ? session.created : new Date(session.created),
|
|
18
|
+
modified: session.modified instanceof Date ? session.modified : new Date(session.modified),
|
|
19
|
+
};
|
|
20
|
+
}
|
|
11
21
|
/**
|
|
12
22
|
* Remote session manager skeleton.
|
|
13
23
|
*
|
|
@@ -30,7 +40,7 @@ export class RemoteSessionManager {
|
|
|
30
40
|
projectId: this.projectId,
|
|
31
41
|
parentSession: options?.parentSession,
|
|
32
42
|
});
|
|
33
|
-
return new RemoteSession({ client: this.client, cwd: this.cwd, snapshot });
|
|
43
|
+
return new RemoteSession({ client: this.client, cwd: this.cwd, snapshot, sessionManager: this });
|
|
34
44
|
}
|
|
35
45
|
async openReference(reference, options) {
|
|
36
46
|
const snapshot = await this.client.openSession(reference);
|
|
@@ -38,15 +48,21 @@ export class RemoteSessionManager {
|
|
|
38
48
|
client: this.client,
|
|
39
49
|
cwd: options?.cwdOverride ?? getSnapshotCwd(snapshot, this.cwd),
|
|
40
50
|
snapshot,
|
|
51
|
+
sessionManager: this,
|
|
41
52
|
});
|
|
42
53
|
}
|
|
43
54
|
async continueRecent() {
|
|
44
55
|
const snapshot = await this.client.getRecentSession();
|
|
45
|
-
return new RemoteSession({
|
|
56
|
+
return new RemoteSession({
|
|
57
|
+
client: this.client,
|
|
58
|
+
cwd: getSnapshotCwd(snapshot, this.cwd),
|
|
59
|
+
snapshot,
|
|
60
|
+
sessionManager: this,
|
|
61
|
+
});
|
|
46
62
|
}
|
|
47
63
|
async forkFrom(reference) {
|
|
48
64
|
const snapshot = await this.client.forkSession(reference, { cwd: this.cwd, projectId: this.projectId });
|
|
49
|
-
return new RemoteSession({ client: this.client, cwd: this.cwd, snapshot });
|
|
65
|
+
return new RemoteSession({ client: this.client, cwd: this.cwd, snapshot, sessionManager: this });
|
|
50
66
|
}
|
|
51
67
|
async forkSession(source, targetLeafId) {
|
|
52
68
|
const reference = source.getSessionReference();
|
|
@@ -58,7 +74,7 @@ export class RemoteSessionManager {
|
|
|
58
74
|
projectId: this.projectId,
|
|
59
75
|
leafId: targetLeafId ?? undefined,
|
|
60
76
|
});
|
|
61
|
-
return new RemoteSession({ client: this.client, cwd: this.cwd, snapshot });
|
|
77
|
+
return new RemoteSession({ client: this.client, cwd: this.cwd, snapshot, sessionManager: this });
|
|
62
78
|
}
|
|
63
79
|
async importJsonl(inputPath, options) {
|
|
64
80
|
const resolvedPath = resolve(inputPath);
|
|
@@ -77,15 +93,20 @@ export class RemoteSessionManager {
|
|
|
77
93
|
sourceName: basename(resolvedPath),
|
|
78
94
|
entries,
|
|
79
95
|
});
|
|
80
|
-
return new RemoteSession({
|
|
96
|
+
return new RemoteSession({
|
|
97
|
+
client: this.client,
|
|
98
|
+
cwd: getSnapshotCwd(snapshot, cwd),
|
|
99
|
+
snapshot,
|
|
100
|
+
sessionManager: this,
|
|
101
|
+
});
|
|
81
102
|
}
|
|
82
103
|
async list(_onProgress) {
|
|
83
104
|
const response = await this.client.listSessions();
|
|
84
|
-
return response.sessions;
|
|
105
|
+
return response.sessions.map((session) => normalizeRemoteSessionInfo(session));
|
|
85
106
|
}
|
|
86
107
|
async listAll(_onProgress) {
|
|
87
108
|
const response = await this.client.listSessions();
|
|
88
|
-
return response.sessions;
|
|
109
|
+
return response.sessions.map((session) => normalizeRemoteSessionInfo(session));
|
|
89
110
|
}
|
|
90
111
|
}
|
|
91
112
|
//# sourceMappingURL=remote-session-manager.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"remote-session-manager.js","sourceRoot":"","sources":["../../../src/core/session/remote-session-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEpD,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AAajE,SAAS,cAAc,CAAC,QAA+B,EAAE,QAAgB,EAAU;IAClF,MAAM,MAAM,GAAG,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,SAAS,CAA8B,CAAC;IACvG,OAAO,MAAM,EAAE,GAAG,IAAI,QAAQ,CAAC;AAAA,CAC/B;AAED;;;;;GAKG;AACH,MAAM,OAAO,oBAAoB;IACf,MAAM,CAAsB;IAC5B,GAAG,CAAS;IACZ,SAAS,CAAqB;IAE/C,YAAY,OAAoC,EAAE;QACjD,IAAI,CAAC,MAAM,GAAG,IAAI,mBAAmB,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC;QAChH,IAAI,CAAC,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC;QACvB,IAAI,CAAC,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC;IAAA,CACnC;IAED,KAAK,CAAC,MAAM,CAAC,OAA2B,EAA0B;QACjE,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC;YAChD,EAAE,EAAE,OAAO,EAAE,EAAE;YACf,GAAG,EAAE,IAAI,CAAC,GAAG;YACb,SAAS,EAAE,IAAI,CAAC,SAAS;YACzB,aAAa,EAAE,OAAO,EAAE,aAAa;SACrC,CAAC,CAAC;QACH,OAAO,IAAI,aAAa,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,QAAQ,EAAE,CAAC,CAAC;IAAA,
|
|
1
|
+
{"version":3,"file":"remote-session-manager.js","sourceRoot":"","sources":["../../../src/core/session/remote-session-manager.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync } from \"node:fs\";\nimport { basename, resolve } from \"node:path\";\nimport { loadEntriesFromFile } from \"./jsonl-helpers.ts\";\nimport { migrateToCurrentVersion } from \"./migrations.ts\";\nimport { RemoteSession } from \"./remote-session.ts\";\nimport type { RemoteSessionInfo, RemoteSessionSnapshot } from \"./remote-session-client.ts\";\nimport { RemoteSessionClient } from \"./remote-session-client.ts\";\nimport type { Session } from \"./session.ts\";\nimport type { OpenSessionOptions, SessionManager } from \"./session-manager.ts\";\nimport type { NewSessionOptions, SessionHeader, SessionInfo, SessionListProgress } from \"./types.ts\";\n\nexport interface RemoteSessionManagerOptions {\n\tbaseUrl: string;\n\ttoken: string;\n\tcwd: string;\n\tprojectId?: string;\n\tfetch?: typeof fetch;\n}\n\nfunction getSnapshotCwd(snapshot: RemoteSessionSnapshot, fallback: string): string {\n\tconst header = snapshot.entries.find((entry) => entry.type === \"session\") as SessionHeader | undefined;\n\treturn header?.cwd ?? fallback;\n}\n\nfunction normalizeRemoteSessionInfo(session: RemoteSessionInfo): SessionInfo {\n\tconst reference = session.reference ?? session.path;\n\treturn {\n\t\t...session,\n\t\treference,\n\t\tpath: session.path ?? reference ?? session.id,\n\t\tcreated: session.created instanceof Date ? session.created : new Date(session.created),\n\t\tmodified: session.modified instanceof Date ? session.modified : new Date(session.modified),\n\t};\n}\n\n/**\n * Remote session manager skeleton.\n *\n * Lifecycle methods are async-compatible through SessionManager so this backend\n * can fetch/create snapshots before returning an active Session.\n */\nexport class RemoteSessionManager implements SessionManager {\n\tprivate readonly client: RemoteSessionClient;\n\tprivate readonly cwd: string;\n\tprivate readonly projectId: string | undefined;\n\n\tconstructor(options: RemoteSessionManagerOptions) {\n\t\tthis.client = new RemoteSessionClient({ baseUrl: options.baseUrl, token: options.token, fetch: options.fetch });\n\t\tthis.cwd = options.cwd;\n\t\tthis.projectId = options.projectId;\n\t}\n\n\tasync create(options?: NewSessionOptions): Promise<RemoteSession> {\n\t\tconst snapshot = await this.client.createSession({\n\t\t\tid: options?.id,\n\t\t\tcwd: this.cwd,\n\t\t\tprojectId: this.projectId,\n\t\t\tparentSession: options?.parentSession,\n\t\t});\n\t\treturn new RemoteSession({ client: this.client, cwd: this.cwd, snapshot, sessionManager: this });\n\t}\n\n\tasync openReference(reference: string, options?: OpenSessionOptions): Promise<RemoteSession> {\n\t\tconst snapshot = await this.client.openSession(reference);\n\t\treturn new RemoteSession({\n\t\t\tclient: this.client,\n\t\t\tcwd: options?.cwdOverride ?? getSnapshotCwd(snapshot, this.cwd),\n\t\t\tsnapshot,\n\t\t\tsessionManager: this,\n\t\t});\n\t}\n\n\tasync continueRecent(): Promise<RemoteSession> {\n\t\tconst snapshot = await this.client.getRecentSession();\n\t\treturn new RemoteSession({\n\t\t\tclient: this.client,\n\t\t\tcwd: getSnapshotCwd(snapshot, this.cwd),\n\t\t\tsnapshot,\n\t\t\tsessionManager: this,\n\t\t});\n\t}\n\n\tasync forkFrom(reference: string): Promise<RemoteSession> {\n\t\tconst snapshot = await this.client.forkSession(reference, { cwd: this.cwd, projectId: this.projectId });\n\t\treturn new RemoteSession({ client: this.client, cwd: this.cwd, snapshot, sessionManager: this });\n\t}\n\n\tasync forkSession(source: Session, targetLeafId: string | null): Promise<RemoteSession> {\n\t\tconst reference = source.getSessionReference();\n\t\tif (!reference) {\n\t\t\tthrow new Error(\"Cannot fork a remote session without a session reference\");\n\t\t}\n\t\tconst snapshot = await this.client.forkSession(reference, {\n\t\t\tcwd: this.cwd,\n\t\t\tprojectId: this.projectId,\n\t\t\tleafId: targetLeafId ?? undefined,\n\t\t});\n\t\treturn new RemoteSession({ client: this.client, cwd: this.cwd, snapshot, sessionManager: this });\n\t}\n\n\tasync importJsonl(inputPath: string, options?: OpenSessionOptions): Promise<RemoteSession> {\n\t\tconst resolvedPath = resolve(inputPath);\n\t\tif (!existsSync(resolvedPath)) {\n\t\t\tthrow new Error(`File not found: ${resolvedPath}`);\n\t\t}\n\n\t\tconst entries = loadEntriesFromFile(resolvedPath);\n\t\tif (entries.length === 0) {\n\t\t\tthrow new Error(`Cannot import empty or invalid session JSONL: ${resolvedPath}`);\n\t\t}\n\t\tmigrateToCurrentVersion(entries);\n\n\t\tconst cwd = options?.cwdOverride ?? getSnapshotCwd({ id: \"\", reference: \"\", entries }, this.cwd);\n\t\tconst snapshot = await this.client.importJsonl({\n\t\t\tcwd,\n\t\t\tprojectId: this.projectId,\n\t\t\tsourceName: basename(resolvedPath),\n\t\t\tentries,\n\t\t});\n\t\treturn new RemoteSession({\n\t\t\tclient: this.client,\n\t\t\tcwd: getSnapshotCwd(snapshot, cwd),\n\t\t\tsnapshot,\n\t\t\tsessionManager: this,\n\t\t});\n\t}\n\n\tasync list(_onProgress?: SessionListProgress): Promise<SessionInfo[]> {\n\t\tconst response = await this.client.listSessions();\n\t\treturn response.sessions.map((session) => normalizeRemoteSessionInfo(session));\n\t}\n\n\tasync listAll(_onProgress?: SessionListProgress): Promise<SessionInfo[]> {\n\t\tconst response = await this.client.listSessions();\n\t\treturn response.sessions.map((session) => normalizeRemoteSessionInfo(session));\n\t}\n}\n"]}
|
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
import type { RemoteSessionClient, RemoteSessionSnapshot } from "./remote-session-client.ts";
|
|
2
2
|
import { Session } from "./session.ts";
|
|
3
|
+
import type { SessionManager } from "./session-manager.ts";
|
|
3
4
|
import type { NewSessionOptions } from "./types.ts";
|
|
4
5
|
export interface RemoteSessionOptions {
|
|
5
6
|
client: RemoteSessionClient;
|
|
6
7
|
cwd: string;
|
|
7
8
|
reference?: string;
|
|
8
9
|
snapshot?: RemoteSessionSnapshot;
|
|
10
|
+
sessionManager?: SessionManager;
|
|
9
11
|
}
|
|
10
12
|
export declare class RemoteSession extends Session {
|
|
11
13
|
private remoteStore;
|
|
12
14
|
constructor(options: RemoteSessionOptions);
|
|
15
|
+
protected prepareNewSessionReference(_sessionDir: string, sessionId: string, _timestamp: string): string | undefined;
|
|
13
16
|
newSession(options?: NewSessionOptions): string | undefined;
|
|
14
17
|
flushPendingSync(): Promise<void>;
|
|
15
18
|
getLastSyncError(): unknown;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"remote-session.d.ts","sourceRoot":"","sources":["../../../src/core/session/remote-session.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AAE7F,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"remote-session.d.ts","sourceRoot":"","sources":["../../../src/core/session/remote-session.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AAE7F,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAE3D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAEpD,MAAM,WAAW,oBAAoB;IACpC,MAAM,EAAE,mBAAmB,CAAC;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,qBAAqB,CAAC;IACjC,cAAc,CAAC,EAAE,cAAc,CAAC;CAChC;AAED,qBAAa,aAAc,SAAQ,OAAO;IACzC,OAAO,CAAC,WAAW,CAAiC;IAEpD,YAAY,OAAO,EAAE,oBAAoB,EAYxC;IAED,SAAS,CAAC,0BAA0B,CACnC,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,GAChB,MAAM,GAAG,SAAS,CAEpB;IAEQ,UAAU,CAAC,OAAO,CAAC,EAAE,iBAAiB,GAAG,MAAM,GAAG,SAAS,CAInE;IAED,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC,CAEhC;IAED,gBAAgB,IAAI,OAAO,CAE1B;CACD","sourcesContent":["import type { RemoteSessionClient, RemoteSessionSnapshot } from \"./remote-session-client.ts\";\nimport { formatRemoteSessionReference } from \"./remote-session-client.ts\";\nimport { Session } from \"./session.ts\";\nimport type { SessionManager } from \"./session-manager.ts\";\nimport { RemoteSessionStore } from \"./stores/remote-session-store.ts\";\nimport type { NewSessionOptions } from \"./types.ts\";\n\nexport interface RemoteSessionOptions {\n\tclient: RemoteSessionClient;\n\tcwd: string;\n\treference?: string;\n\tsnapshot?: RemoteSessionSnapshot;\n\tsessionManager?: SessionManager;\n}\n\nexport class RemoteSession extends Session {\n\tprivate remoteStore: RemoteSessionStore | undefined;\n\n\tconstructor(options: RemoteSessionOptions) {\n\t\tconst reference =\n\t\t\toptions.reference ??\n\t\t\toptions.snapshot?.reference ??\n\t\t\t(options.snapshot ? formatRemoteSessionReference(options.snapshot.id) : undefined);\n\t\tconst store = new RemoteSessionStore({\n\t\t\tclient: options.client,\n\t\t\treference,\n\t\t\tsnapshot: options.snapshot,\n\t\t});\n\t\tsuper(options.cwd, \"\", reference, store, options.sessionManager);\n\t\tthis.remoteStore = store;\n\t}\n\n\tprotected prepareNewSessionReference(\n\t\t_sessionDir: string,\n\t\tsessionId: string,\n\t\t_timestamp: string,\n\t): string | undefined {\n\t\treturn this.getSessionReference() ?? formatRemoteSessionReference(sessionId);\n\t}\n\n\toverride newSession(options?: NewSessionOptions): string | undefined {\n\t\tconst reference = super.newSession(options);\n\t\tthis.remoteStore?.saveSnapshot();\n\t\treturn reference;\n\t}\n\n\tflushPendingSync(): Promise<void> {\n\t\treturn this.remoteStore?.flushPendingSync() ?? Promise.resolve();\n\t}\n\n\tgetLastSyncError(): unknown {\n\t\treturn this.remoteStore?.getLastSyncError();\n\t}\n}\n"]}
|
|
@@ -12,9 +12,12 @@ export class RemoteSession extends Session {
|
|
|
12
12
|
reference,
|
|
13
13
|
snapshot: options.snapshot,
|
|
14
14
|
});
|
|
15
|
-
super(options.cwd, "", reference, store);
|
|
15
|
+
super(options.cwd, "", reference, store, options.sessionManager);
|
|
16
16
|
this.remoteStore = store;
|
|
17
17
|
}
|
|
18
|
+
prepareNewSessionReference(_sessionDir, sessionId, _timestamp) {
|
|
19
|
+
return this.getSessionReference() ?? formatRemoteSessionReference(sessionId);
|
|
20
|
+
}
|
|
18
21
|
newSession(options) {
|
|
19
22
|
const reference = super.newSession(options);
|
|
20
23
|
this.remoteStore?.saveSnapshot();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"remote-session.js","sourceRoot":"","sources":["../../../src/core/session/remote-session.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,4BAA4B,EAAE,MAAM,4BAA4B,CAAC;AAC1E,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"remote-session.js","sourceRoot":"","sources":["../../../src/core/session/remote-session.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,4BAA4B,EAAE,MAAM,4BAA4B,CAAC;AAC1E,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC,OAAO,EAAE,kBAAkB,EAAE,MAAM,kCAAkC,CAAC;AAWtE,MAAM,OAAO,aAAc,SAAQ,OAAO;IACjC,WAAW,CAAiC;IAEpD,YAAY,OAA6B,EAAE;QAC1C,MAAM,SAAS,GACd,OAAO,CAAC,SAAS;YACjB,OAAO,CAAC,QAAQ,EAAE,SAAS;YAC3B,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,4BAA4B,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;QACpF,MAAM,KAAK,GAAG,IAAI,kBAAkB,CAAC;YACpC,MAAM,EAAE,OAAO,CAAC,MAAM;YACtB,SAAS;YACT,QAAQ,EAAE,OAAO,CAAC,QAAQ;SAC1B,CAAC,CAAC;QACH,KAAK,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,OAAO,CAAC,cAAc,CAAC,CAAC;QACjE,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC;IAAA,CACzB;IAES,0BAA0B,CACnC,WAAmB,EACnB,SAAiB,EACjB,UAAkB,EACG;QACrB,OAAO,IAAI,CAAC,mBAAmB,EAAE,IAAI,4BAA4B,CAAC,SAAS,CAAC,CAAC;IAAA,CAC7E;IAEQ,UAAU,CAAC,OAA2B,EAAsB;QACpE,MAAM,SAAS,GAAG,KAAK,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;QAC5C,IAAI,CAAC,WAAW,EAAE,YAAY,EAAE,CAAC;QACjC,OAAO,SAAS,CAAC;IAAA,CACjB;IAED,gBAAgB,GAAkB;QACjC,OAAO,IAAI,CAAC,WAAW,EAAE,gBAAgB,EAAE,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;IAAA,CACjE;IAED,gBAAgB,GAAY;QAC3B,OAAO,IAAI,CAAC,WAAW,EAAE,gBAAgB,EAAE,CAAC;IAAA,CAC5C;CACD","sourcesContent":["import type { RemoteSessionClient, RemoteSessionSnapshot } from \"./remote-session-client.ts\";\nimport { formatRemoteSessionReference } from \"./remote-session-client.ts\";\nimport { Session } from \"./session.ts\";\nimport type { SessionManager } from \"./session-manager.ts\";\nimport { RemoteSessionStore } from \"./stores/remote-session-store.ts\";\nimport type { NewSessionOptions } from \"./types.ts\";\n\nexport interface RemoteSessionOptions {\n\tclient: RemoteSessionClient;\n\tcwd: string;\n\treference?: string;\n\tsnapshot?: RemoteSessionSnapshot;\n\tsessionManager?: SessionManager;\n}\n\nexport class RemoteSession extends Session {\n\tprivate remoteStore: RemoteSessionStore | undefined;\n\n\tconstructor(options: RemoteSessionOptions) {\n\t\tconst reference =\n\t\t\toptions.reference ??\n\t\t\toptions.snapshot?.reference ??\n\t\t\t(options.snapshot ? formatRemoteSessionReference(options.snapshot.id) : undefined);\n\t\tconst store = new RemoteSessionStore({\n\t\t\tclient: options.client,\n\t\t\treference,\n\t\t\tsnapshot: options.snapshot,\n\t\t});\n\t\tsuper(options.cwd, \"\", reference, store, options.sessionManager);\n\t\tthis.remoteStore = store;\n\t}\n\n\tprotected prepareNewSessionReference(\n\t\t_sessionDir: string,\n\t\tsessionId: string,\n\t\t_timestamp: string,\n\t): string | undefined {\n\t\treturn this.getSessionReference() ?? formatRemoteSessionReference(sessionId);\n\t}\n\n\toverride newSession(options?: NewSessionOptions): string | undefined {\n\t\tconst reference = super.newSession(options);\n\t\tthis.remoteStore?.saveSnapshot();\n\t\treturn reference;\n\t}\n\n\tflushPendingSync(): Promise<void> {\n\t\treturn this.remoteStore?.flushPendingSync() ?? Promise.resolve();\n\t}\n\n\tgetLastSyncError(): unknown {\n\t\treturn this.remoteStore?.getLastSyncError();\n\t}\n}\n"]}
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
import type { ImageContent, Message, TextContent } from "@fleetagent/pi-ai";
|
|
2
2
|
import type { BashExecutionMessage, CustomMessage } from "../messages.ts";
|
|
3
|
+
import type { SessionManager, SessionResult } from "./session-manager.ts";
|
|
3
4
|
import type { SessionStore } from "./stores/session-store.ts";
|
|
4
5
|
import type { NewSessionOptions, SessionContext, SessionEntry, SessionHeader, SessionTreeNode } from "./types.ts";
|
|
5
6
|
export { CURRENT_SESSION_VERSION } from "./constants.ts";
|
|
6
7
|
export { buildSessionContext, getLatestCompactionEntry } from "./context.ts";
|
|
7
8
|
export { migrateSessionEntries, parseSessionEntries } from "./migrations.ts";
|
|
8
9
|
export type { BranchSummaryEntry, CompactionEntry, CustomEntry, CustomMessageEntry, FileEntry, LabelEntry, ModelChangeEntry, NewSessionOptions, SessionContext, SessionEntry, SessionEntryBase, SessionHeader, SessionInfo, SessionInfoEntry, SessionListProgress, SessionMessageEntry, SessionTreeNode, ThinkingLevelChangeEntry, } from "./types.ts";
|
|
9
|
-
export type
|
|
10
|
+
export type ReadonlySession = Pick<Session, "getCwd" | "getSessionDir" | "getSessionId" | "getSessionReference" | "getLeafId" | "getLeafEntry" | "getEntry" | "getLabel" | "getBranch" | "getHeader" | "getEntries" | "getTree" | "getSessionName">;
|
|
10
11
|
export { findMostRecentSession, getDefaultSessionDir, loadEntriesFromFile } from "./jsonl-helpers.ts";
|
|
11
12
|
/**
|
|
12
|
-
*
|
|
13
|
+
* Represents one active conversation session as an append-only tree.
|
|
13
14
|
*
|
|
14
15
|
* Each session entry has an id and parentId forming a tree structure. The "leaf"
|
|
15
16
|
* pointer tracks the current position. Appending creates a child of the current leaf.
|
|
@@ -24,7 +25,9 @@ export declare abstract class Session {
|
|
|
24
25
|
private sessionDir;
|
|
25
26
|
private cwd;
|
|
26
27
|
private store;
|
|
27
|
-
|
|
28
|
+
private sessionManager;
|
|
29
|
+
protected constructor(cwd: string, sessionDir: string, sessionReference: string | undefined, store: SessionStore, sessionManager?: SessionManager);
|
|
30
|
+
protected abstract prepareNewSessionReference(sessionDir: string, sessionId: string, timestamp: string): string | undefined;
|
|
28
31
|
/** Switch to a different session reference (used for resume and branching). */
|
|
29
32
|
setSessionReference(sessionReference: string): void;
|
|
30
33
|
newSession(options?: NewSessionOptions): string | undefined;
|
|
@@ -131,5 +134,8 @@ export declare abstract class Session {
|
|
|
131
134
|
* Returns the new session reference, or undefined if the store does not expose one.
|
|
132
135
|
*/
|
|
133
136
|
createBranchedSession(leafId: string): string | undefined;
|
|
137
|
+
copyBranchFrom(source: Session, leafId: string, parentSession?: string): void;
|
|
138
|
+
createSubSession(options?: NewSessionOptions): SessionResult;
|
|
139
|
+
forkSubSession(targetLeafId: string | null): SessionResult;
|
|
134
140
|
}
|
|
135
141
|
//# sourceMappingURL=session.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../../src/core/session/session.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ImageContent, Message, TextContent } from \"@fleetagent/pi-ai\";\nimport type { BashExecutionMessage, CustomMessage } from \"../messages.ts\";\nimport { CURRENT_SESSION_VERSION } from \"./constants.ts\";\nimport { buildSessionContext } from \"./context.ts\";\nimport { createSessionId, generateId } from \"./ids.ts\";\nimport { migrateToCurrentVersion } from \"./migrations.ts\";\nimport type { SessionStore } from \"./stores/session-store.ts\";\nimport type {\n\tBranchSummaryEntry,\n\tCompactionEntry,\n\tCustomEntry,\n\tCustomMessageEntry,\n\tLabelEntry,\n\tModelChangeEntry,\n\tNewSessionOptions,\n\tSessionContext,\n\tSessionEntry,\n\tSessionHeader,\n\tSessionInfoEntry,\n\tSessionMessageEntry,\n\tSessionTreeNode,\n\tThinkingLevelChangeEntry,\n} from \"./types.ts\";\n\nexport { CURRENT_SESSION_VERSION } from \"./constants.ts\";\nexport { buildSessionContext, getLatestCompactionEntry } from \"./context.ts\";\nexport { migrateSessionEntries, parseSessionEntries } from \"./migrations.ts\";\n\nexport type {\n\tBranchSummaryEntry,\n\tCompactionEntry,\n\tCustomEntry,\n\tCustomMessageEntry,\n\tFileEntry,\n\tLabelEntry,\n\tModelChangeEntry,\n\tNewSessionOptions,\n\tSessionContext,\n\tSessionEntry,\n\tSessionEntryBase,\n\tSessionHeader,\n\tSessionInfo,\n\tSessionInfoEntry,\n\tSessionListProgress,\n\tSessionMessageEntry,\n\tSessionTreeNode,\n\tThinkingLevelChangeEntry,\n} from \"./types.ts\";\n\nexport type ReadonlySessionManager = Pick<\n\tSession,\n\t| \"getCwd\"\n\t| \"getSessionDir\"\n\t| \"getSessionId\"\n\t| \"getSessionReference\"\n\t| \"getLeafId\"\n\t| \"getLeafEntry\"\n\t| \"getEntry\"\n\t| \"getLabel\"\n\t| \"getBranch\"\n\t| \"getHeader\"\n\t| \"getEntries\"\n\t| \"getTree\"\n\t| \"getSessionName\"\n>;\n\nexport { findMostRecentSession, getDefaultSessionDir, loadEntriesFromFile } from \"./jsonl-helpers.ts\";\n\n/**\n * Manages conversation sessions as append-only trees stored in JSONL files.\n *\n * Each session entry has an id and parentId forming a tree structure. The \"leaf\"\n * pointer tracks the current position. Appending creates a child of the current leaf.\n * Branching moves the leaf to an earlier entry, allowing new branches without\n * modifying history.\n *\n * Use buildSessionContext() to get the resolved message list for the LLM, which\n * handles compaction summaries and follows the path from root to current leaf.\n */\nexport abstract class Session {\n\tprivate sessionId: string = \"\";\n\tprivate sessionDir: string;\n\tprivate cwd: string;\n\tprivate store: SessionStore;\n\n\tprotected constructor(cwd: string, sessionDir: string, sessionReference: string | undefined, store: SessionStore) {\n\t\tthis.cwd = cwd;\n\t\tthis.sessionDir = sessionDir;\n\t\tthis.store = store;\n\t\tif (sessionDir) {\n\t\t\tthis.store.ensureDir(sessionDir);\n\t\t}\n\n\t\tif (sessionReference) {\n\t\t\tthis.setSessionReference(sessionReference);\n\t\t} else {\n\t\t\tthis.newSession();\n\t\t}\n\t}\n\n\t/** Switch to a different session reference (used for resume and branching). */\n\tsetSessionReference(sessionReference: string): void {\n\t\tconst opened = this.store.openSession(sessionReference);\n\t\tif (opened.exists) {\n\t\t\tthis.store.setEntries(opened.entries);\n\n\t\t\t// If the opened session has no valid header, start fresh to avoid\n\t\t\t// appending messages without a session header.\n\t\t\tif (this.store.getFileEntries().length === 0) {\n\t\t\t\tthis.newSession();\n\t\t\t\tthis.store.setSessionReference(opened.reference);\n\t\t\t\tthis.store.saveSnapshot();\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst header = this.store.getHeader();\n\t\t\tthis.sessionId = header?.id ?? createSessionId();\n\n\t\t\tif (migrateToCurrentVersion(this.store.getFileEntries())) {\n\t\t\t\tthis.store.setEntries(this.store.getFileEntries());\n\t\t\t\tthis.store.saveSnapshot();\n\t\t\t}\n\t\t} else {\n\t\t\tthis.newSession();\n\t\t\tthis.store.setSessionReference(opened.reference); // preserve explicit path from --session flag\n\t\t}\n\t}\n\n\tnewSession(options?: NewSessionOptions): string | undefined {\n\t\tthis.sessionId = options?.id ?? createSessionId();\n\t\tconst timestamp = new Date().toISOString();\n\t\tconst header: SessionHeader = {\n\t\t\ttype: \"session\",\n\t\t\tversion: CURRENT_SESSION_VERSION,\n\t\t\tid: this.sessionId,\n\t\t\ttimestamp,\n\t\t\tcwd: this.cwd,\n\t\t\tparentSession: options?.parentSession,\n\t\t};\n\t\tthis.store.setEntries([header]);\n\t\treturn this.store.prepareSessionReference(this.getSessionDir(), this.sessionId, timestamp);\n\t}\n\n\tisPersisted(): boolean {\n\t\treturn this.store.isPersisted();\n\t}\n\n\tgetCwd(): string {\n\t\treturn this.cwd;\n\t}\n\n\tgetSessionDir(): string {\n\t\treturn this.sessionDir;\n\t}\n\n\tgetSessionId(): string {\n\t\treturn this.sessionId;\n\t}\n\n\tgetSessionReference(): string | undefined {\n\t\treturn this.store.getSessionReference();\n\t}\n\n\tprivate _appendEntry(entry: SessionEntry): void {\n\t\tthis.store.appendEntry(entry);\n\t}\n\n\t/** Append a message as child of current leaf, then advance leaf. Returns entry id.\n\t * Does not allow writing CompactionSummaryMessage and BranchSummaryMessage directly.\n\t * Reason: we want these to be top-level entries in the session, not message session entries,\n\t * so it is easier to find them.\n\t * These need to be appended via appendCompaction() and appendBranchSummary() methods.\n\t */\n\tappendMessage(message: Message | CustomMessage | BashExecutionMessage): string {\n\t\tconst entry: SessionMessageEntry = {\n\t\t\ttype: \"message\",\n\t\t\tid: generateId(this.store),\n\t\t\tparentId: this.store.getLeafId(),\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tmessage,\n\t\t};\n\t\tthis._appendEntry(entry);\n\t\treturn entry.id;\n\t}\n\n\t/** Append a thinking level change as child of current leaf, then advance leaf. Returns entry id. */\n\tappendThinkingLevelChange(thinkingLevel: string): string {\n\t\tconst entry: ThinkingLevelChangeEntry = {\n\t\t\ttype: \"thinking_level_change\",\n\t\t\tid: generateId(this.store),\n\t\t\tparentId: this.store.getLeafId(),\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tthinkingLevel,\n\t\t};\n\t\tthis._appendEntry(entry);\n\t\treturn entry.id;\n\t}\n\n\t/** Append a model change as child of current leaf, then advance leaf. Returns entry id. */\n\tappendModelChange(provider: string, modelId: string): string {\n\t\tconst entry: ModelChangeEntry = {\n\t\t\ttype: \"model_change\",\n\t\t\tid: generateId(this.store),\n\t\t\tparentId: this.store.getLeafId(),\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tprovider,\n\t\t\tmodelId,\n\t\t};\n\t\tthis._appendEntry(entry);\n\t\treturn entry.id;\n\t}\n\n\t/** Append a compaction summary as child of current leaf, then advance leaf. Returns entry id. */\n\tappendCompaction<T = unknown>(\n\t\tsummary: string,\n\t\tfirstKeptEntryId: string,\n\t\ttokensBefore: number,\n\t\tdetails?: T,\n\t\tfromHook?: boolean,\n\t): string {\n\t\tconst entry: CompactionEntry<T> = {\n\t\t\ttype: \"compaction\",\n\t\t\tid: generateId(this.store),\n\t\t\tparentId: this.store.getLeafId(),\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tsummary,\n\t\t\tfirstKeptEntryId,\n\t\t\ttokensBefore,\n\t\t\tdetails,\n\t\t\tfromHook,\n\t\t};\n\t\tthis._appendEntry(entry);\n\t\treturn entry.id;\n\t}\n\n\t/** Append a custom entry (for extensions) as child of current leaf, then advance leaf. Returns entry id. */\n\tappendCustomEntry(customType: string, data?: unknown): string {\n\t\tconst entry: CustomEntry = {\n\t\t\ttype: \"custom\",\n\t\t\tcustomType,\n\t\t\tdata,\n\t\t\tid: generateId(this.store),\n\t\t\tparentId: this.store.getLeafId(),\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t};\n\t\tthis._appendEntry(entry);\n\t\treturn entry.id;\n\t}\n\n\t/** Append a session info entry (e.g., display name). Returns entry id. */\n\tappendSessionInfo(name: string): string {\n\t\tconst entry: SessionInfoEntry = {\n\t\t\ttype: \"session_info\",\n\t\t\tid: generateId(this.store),\n\t\t\tparentId: this.store.getLeafId(),\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tname: name.trim(),\n\t\t};\n\t\tthis._appendEntry(entry);\n\t\treturn entry.id;\n\t}\n\n\t/** Get the current session name from the latest session_info entry, if any. */\n\tgetSessionName(): string | undefined {\n\t\treturn this.store.getSessionName();\n\t}\n\n\t/**\n\t * Append a custom message entry (for extensions) that participates in LLM context.\n\t * @param customType Extension identifier for filtering on reload\n\t * @param content Message content (string or TextContent/ImageContent array)\n\t * @param display Whether to show in TUI (true = styled display, false = hidden)\n\t * @param details Optional extension-specific metadata (not sent to LLM)\n\t * @returns Entry id\n\t */\n\tappendCustomMessageEntry<T = unknown>(\n\t\tcustomType: string,\n\t\tcontent: string | (TextContent | ImageContent)[],\n\t\tdisplay: boolean,\n\t\tdetails?: T,\n\t): string {\n\t\tconst entry: CustomMessageEntry<T> = {\n\t\t\ttype: \"custom_message\",\n\t\t\tcustomType,\n\t\t\tcontent,\n\t\t\tdisplay,\n\t\t\tdetails,\n\t\t\tid: generateId(this.store),\n\t\t\tparentId: this.store.getLeafId(),\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t};\n\t\tthis._appendEntry(entry);\n\t\treturn entry.id;\n\t}\n\n\t// =========================================================================\n\t// Tree Traversal\n\t// =========================================================================\n\n\tgetLeafId(): string | null {\n\t\treturn this.store.getLeafId();\n\t}\n\n\tgetLeafEntry(): SessionEntry | undefined {\n\t\treturn this.store.getLeafEntry();\n\t}\n\n\tgetEntry(id: string): SessionEntry | undefined {\n\t\treturn this.store.getEntry(id);\n\t}\n\n\t/**\n\t * Get all direct children of an entry.\n\t */\n\tgetChildren(parentId: string): SessionEntry[] {\n\t\treturn this.store.getChildren(parentId);\n\t}\n\n\t/**\n\t * Get the label for an entry, if any.\n\t */\n\tgetLabel(id: string): string | undefined {\n\t\treturn this.store.getLabel(id);\n\t}\n\n\t/**\n\t * Set or clear a label on an entry.\n\t * Labels are user-defined markers for bookmarking/navigation.\n\t * Pass undefined or empty string to clear the label.\n\t */\n\tappendLabelChange(targetId: string, label: string | undefined): string {\n\t\tif (!this.store.has(targetId)) {\n\t\t\tthrow new Error(`Entry ${targetId} not found`);\n\t\t}\n\t\tconst entry: LabelEntry = {\n\t\t\ttype: \"label\",\n\t\t\tid: generateId(this.store),\n\t\t\tparentId: this.store.getLeafId(),\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\ttargetId,\n\t\t\tlabel,\n\t\t};\n\t\tthis._appendEntry(entry);\n\t\treturn entry.id;\n\t}\n\n\t/**\n\t * Walk from entry to root, returning all entries in path order.\n\t * Includes all entry types (messages, compaction, model changes, etc.).\n\t * Use buildSessionContext() to get the resolved messages for the LLM.\n\t */\n\tgetBranch(fromId?: string): SessionEntry[] {\n\t\treturn this.store.getBranch(fromId);\n\t}\n\n\t/**\n\t * Build the session context (what gets sent to the LLM).\n\t * Uses tree traversal from current leaf.\n\t */\n\tbuildSessionContext(): SessionContext {\n\t\treturn buildSessionContext(this.getEntries(), this.store.getLeafId(), this.store.getEntryIndex());\n\t}\n\n\t/**\n\t * Get session header.\n\t */\n\tgetHeader(): SessionHeader | null {\n\t\treturn this.store.getHeader();\n\t}\n\n\t/**\n\t * Get all session entries (excludes header). Returns a shallow copy.\n\t * The session is append-only: use appendXXX() to add entries, branch() to\n\t * change the leaf pointer. Entries cannot be modified or deleted.\n\t */\n\tgetEntries(): SessionEntry[] {\n\t\treturn this.store.getEntries();\n\t}\n\n\t/**\n\t * Get the session as a tree structure. Returns a shallow defensive copy of all entries.\n\t * A well-formed session has exactly one root (first entry with parentId === null).\n\t * Orphaned entries (broken parent chain) are also returned as roots.\n\t */\n\tgetTree(): SessionTreeNode[] {\n\t\treturn this.store.getTree();\n\t}\n\n\t// =========================================================================\n\t// Branching\n\t// =========================================================================\n\n\t/**\n\t * Start a new branch from an earlier entry.\n\t * Moves the leaf pointer to the specified entry. The next appendXXX() call\n\t * will create a child of that entry, forming a new branch. Existing entries\n\t * are not modified or deleted.\n\t */\n\tbranch(branchFromId: string): void {\n\t\tif (!this.store.has(branchFromId)) {\n\t\t\tthrow new Error(`Entry ${branchFromId} not found`);\n\t\t}\n\t\tthis.store.setLeafId(branchFromId);\n\t}\n\n\t/**\n\t * Reset the leaf pointer to null (before any entries).\n\t * The next appendXXX() call will create a new root entry (parentId = null).\n\t * Use this when navigating to re-edit the first user message.\n\t */\n\tresetLeaf(): void {\n\t\tthis.store.setLeafId(null);\n\t}\n\n\t/**\n\t * Start a new branch with a summary of the abandoned path.\n\t * Same as branch(), but also appends a branch_summary entry that captures\n\t * context from the abandoned conversation path.\n\t */\n\tbranchWithSummary(branchFromId: string | null, summary: string, details?: unknown, fromHook?: boolean): string {\n\t\tif (branchFromId !== null && !this.store.has(branchFromId)) {\n\t\t\tthrow new Error(`Entry ${branchFromId} not found`);\n\t\t}\n\t\tthis.store.setLeafId(branchFromId);\n\t\tconst entry: BranchSummaryEntry = {\n\t\t\ttype: \"branch_summary\",\n\t\t\tid: generateId(this.store),\n\t\t\tparentId: branchFromId,\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tfromId: branchFromId ?? \"root\",\n\t\t\tsummary,\n\t\t\tdetails,\n\t\t\tfromHook,\n\t\t};\n\t\tthis._appendEntry(entry);\n\t\treturn entry.id;\n\t}\n\n\t/**\n\t * Create a new session reference containing only the path from root to the specified leaf.\n\t * Useful for extracting a single conversation path from a branched session.\n\t * Returns the new session reference, or undefined if the store does not expose one.\n\t */\n\tcreateBranchedSession(leafId: string): string | undefined {\n\t\tconst parentSession = this.store.getParentSessionReference();\n\t\tconst path = this.getBranch(leafId);\n\t\tif (path.length === 0) {\n\t\t\tthrow new Error(`Entry ${leafId} not found`);\n\t\t}\n\n\t\t// Filter out LabelEntry from path - we'll recreate them from the resolved map\n\t\tconst pathWithoutLabels = path.filter((e) => e.type !== \"label\");\n\n\t\tconst newSessionId = createSessionId();\n\t\tconst timestamp = new Date().toISOString();\n\t\tconst newSessionReference = this.store.prepareSessionReference(this.getSessionDir(), newSessionId, timestamp);\n\n\t\tconst header: SessionHeader = {\n\t\t\ttype: \"session\",\n\t\t\tversion: CURRENT_SESSION_VERSION,\n\t\t\tid: newSessionId,\n\t\t\ttimestamp,\n\t\t\tcwd: this.cwd,\n\t\t\tparentSession,\n\t\t};\n\n\t\t// Collect labels for entries in the path\n\t\tconst pathEntryIds = new Set(pathWithoutLabels.map((e) => e.id));\n\t\tconst labelsToWrite = this.store.getLabelsForEntryIds(pathEntryIds);\n\n\t\tconst labelEntries: LabelEntry[] = [];\n\t\tlet parentId = pathWithoutLabels[pathWithoutLabels.length - 1]?.id || null;\n\t\tfor (const { targetId, label, timestamp: labelTimestamp } of labelsToWrite) {\n\t\t\tconst labelEntry: LabelEntry = {\n\t\t\t\ttype: \"label\",\n\t\t\t\tid: generateId(new Set([...pathEntryIds, ...labelEntries.map((e) => e.id)])),\n\t\t\t\tparentId,\n\t\t\t\ttimestamp: labelTimestamp,\n\t\t\t\ttargetId,\n\t\t\t\tlabel,\n\t\t\t};\n\t\t\tpathEntryIds.add(labelEntry.id);\n\t\t\tlabelEntries.push(labelEntry);\n\t\t\tparentId = labelEntry.id;\n\t\t}\n\t\tthis.store.setEntries([header, ...pathWithoutLabels, ...labelEntries]);\n\t\tthis.sessionId = newSessionId;\n\t\tthis.store.commitSnapshot();\n\t\treturn newSessionReference;\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../../src/core/session/session.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ImageContent, Message, TextContent } from \"@fleetagent/pi-ai\";\nimport type { BashExecutionMessage, CustomMessage } from \"../messages.ts\";\nimport { CURRENT_SESSION_VERSION } from \"./constants.ts\";\nimport { buildSessionContext } from \"./context.ts\";\nimport { createSessionId, generateId } from \"./ids.ts\";\nimport { migrateToCurrentVersion } from \"./migrations.ts\";\nimport type { SessionManager, SessionResult } from \"./session-manager.ts\";\nimport type { SessionStore } from \"./stores/session-store.ts\";\nimport type {\n\tBranchSummaryEntry,\n\tCompactionEntry,\n\tCustomEntry,\n\tCustomMessageEntry,\n\tLabelEntry,\n\tModelChangeEntry,\n\tNewSessionOptions,\n\tSessionContext,\n\tSessionEntry,\n\tSessionHeader,\n\tSessionInfoEntry,\n\tSessionMessageEntry,\n\tSessionTreeNode,\n\tThinkingLevelChangeEntry,\n} from \"./types.ts\";\n\nexport { CURRENT_SESSION_VERSION } from \"./constants.ts\";\nexport { buildSessionContext, getLatestCompactionEntry } from \"./context.ts\";\nexport { migrateSessionEntries, parseSessionEntries } from \"./migrations.ts\";\n\nexport type {\n\tBranchSummaryEntry,\n\tCompactionEntry,\n\tCustomEntry,\n\tCustomMessageEntry,\n\tFileEntry,\n\tLabelEntry,\n\tModelChangeEntry,\n\tNewSessionOptions,\n\tSessionContext,\n\tSessionEntry,\n\tSessionEntryBase,\n\tSessionHeader,\n\tSessionInfo,\n\tSessionInfoEntry,\n\tSessionListProgress,\n\tSessionMessageEntry,\n\tSessionTreeNode,\n\tThinkingLevelChangeEntry,\n} from \"./types.ts\";\n\nexport type ReadonlySession = Pick<\n\tSession,\n\t| \"getCwd\"\n\t| \"getSessionDir\"\n\t| \"getSessionId\"\n\t| \"getSessionReference\"\n\t| \"getLeafId\"\n\t| \"getLeafEntry\"\n\t| \"getEntry\"\n\t| \"getLabel\"\n\t| \"getBranch\"\n\t| \"getHeader\"\n\t| \"getEntries\"\n\t| \"getTree\"\n\t| \"getSessionName\"\n>;\n\nexport { findMostRecentSession, getDefaultSessionDir, loadEntriesFromFile } from \"./jsonl-helpers.ts\";\n\n/**\n * Represents one active conversation session as an append-only tree.\n *\n * Each session entry has an id and parentId forming a tree structure. The \"leaf\"\n * pointer tracks the current position. Appending creates a child of the current leaf.\n * Branching moves the leaf to an earlier entry, allowing new branches without\n * modifying history.\n *\n * Use buildSessionContext() to get the resolved message list for the LLM, which\n * handles compaction summaries and follows the path from root to current leaf.\n */\nexport abstract class Session {\n\tprivate sessionId: string = \"\";\n\tprivate sessionDir: string;\n\tprivate cwd: string;\n\tprivate store: SessionStore;\n\tprivate sessionManager: SessionManager | undefined;\n\n\tprotected constructor(\n\t\tcwd: string,\n\t\tsessionDir: string,\n\t\tsessionReference: string | undefined,\n\t\tstore: SessionStore,\n\t\tsessionManager?: SessionManager,\n\t) {\n\t\tthis.cwd = cwd;\n\t\tthis.sessionDir = sessionDir;\n\t\tthis.store = store;\n\t\tthis.sessionManager = sessionManager;\n\t\tif (sessionDir) {\n\t\t\tthis.store.ensureDir(sessionDir);\n\t\t}\n\n\t\tif (sessionReference) {\n\t\t\tthis.setSessionReference(sessionReference);\n\t\t} else {\n\t\t\tthis.newSession();\n\t\t}\n\t}\n\n\tprotected abstract prepareNewSessionReference(\n\t\tsessionDir: string,\n\t\tsessionId: string,\n\t\ttimestamp: string,\n\t): string | undefined;\n\n\t/** Switch to a different session reference (used for resume and branching). */\n\tsetSessionReference(sessionReference: string): void {\n\t\tthis.store.setSessionReference(sessionReference);\n\t\tif (this.store.exists(sessionReference)) {\n\t\t\tthis.store.setEntries(this.store.load(sessionReference));\n\n\t\t\t// If the opened session has no valid header, start fresh to avoid\n\t\t\t// appending messages without a session header.\n\t\t\tif (this.store.getFileEntries().length === 0) {\n\t\t\t\tthis.newSession();\n\t\t\t\tthis.store.setSessionReference(sessionReference);\n\t\t\t\tthis.store.saveSnapshot();\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst header = this.store.getHeader();\n\t\t\tthis.sessionId = header?.id ?? createSessionId();\n\n\t\t\tif (migrateToCurrentVersion(this.store.getFileEntries())) {\n\t\t\t\tthis.store.setEntries(this.store.getFileEntries());\n\t\t\t\tthis.store.saveSnapshot();\n\t\t\t}\n\t\t} else {\n\t\t\tthis.newSession();\n\t\t\tthis.store.setSessionReference(sessionReference); // preserve explicit reference from --session flag\n\t\t}\n\t}\n\n\tnewSession(options?: NewSessionOptions): string | undefined {\n\t\tthis.sessionId = options?.id ?? createSessionId();\n\t\tconst timestamp = new Date().toISOString();\n\t\tconst header: SessionHeader = {\n\t\t\ttype: \"session\",\n\t\t\tversion: CURRENT_SESSION_VERSION,\n\t\t\tid: this.sessionId,\n\t\t\ttimestamp,\n\t\t\tcwd: this.cwd,\n\t\t\tparentSession: options?.parentSession,\n\t\t};\n\t\tconst sessionReference = this.prepareNewSessionReference(this.getSessionDir(), this.sessionId, timestamp);\n\t\tif (sessionReference) {\n\t\t\tthis.store.setSessionReference(sessionReference);\n\t\t}\n\t\tthis.store.setEntries([header]);\n\t\treturn sessionReference;\n\t}\n\n\tisPersisted(): boolean {\n\t\treturn this.store.isPersisted();\n\t}\n\n\tgetCwd(): string {\n\t\treturn this.cwd;\n\t}\n\n\tgetSessionDir(): string {\n\t\treturn this.sessionDir;\n\t}\n\n\tgetSessionId(): string {\n\t\treturn this.sessionId;\n\t}\n\n\tgetSessionReference(): string | undefined {\n\t\treturn this.store.getSessionReference();\n\t}\n\n\tprivate _appendEntry(entry: SessionEntry): void {\n\t\tthis.store.appendEntry(entry);\n\t}\n\n\t/** Append a message as child of current leaf, then advance leaf. Returns entry id.\n\t * Does not allow writing CompactionSummaryMessage and BranchSummaryMessage directly.\n\t * Reason: we want these to be top-level entries in the session, not message session entries,\n\t * so it is easier to find them.\n\t * These need to be appended via appendCompaction() and appendBranchSummary() methods.\n\t */\n\tappendMessage(message: Message | CustomMessage | BashExecutionMessage): string {\n\t\tconst entry: SessionMessageEntry = {\n\t\t\ttype: \"message\",\n\t\t\tid: generateId(this.store),\n\t\t\tparentId: this.store.getLeafId(),\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tmessage,\n\t\t};\n\t\tthis._appendEntry(entry);\n\t\treturn entry.id;\n\t}\n\n\t/** Append a thinking level change as child of current leaf, then advance leaf. Returns entry id. */\n\tappendThinkingLevelChange(thinkingLevel: string): string {\n\t\tconst entry: ThinkingLevelChangeEntry = {\n\t\t\ttype: \"thinking_level_change\",\n\t\t\tid: generateId(this.store),\n\t\t\tparentId: this.store.getLeafId(),\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tthinkingLevel,\n\t\t};\n\t\tthis._appendEntry(entry);\n\t\treturn entry.id;\n\t}\n\n\t/** Append a model change as child of current leaf, then advance leaf. Returns entry id. */\n\tappendModelChange(provider: string, modelId: string): string {\n\t\tconst entry: ModelChangeEntry = {\n\t\t\ttype: \"model_change\",\n\t\t\tid: generateId(this.store),\n\t\t\tparentId: this.store.getLeafId(),\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tprovider,\n\t\t\tmodelId,\n\t\t};\n\t\tthis._appendEntry(entry);\n\t\treturn entry.id;\n\t}\n\n\t/** Append a compaction summary as child of current leaf, then advance leaf. Returns entry id. */\n\tappendCompaction<T = unknown>(\n\t\tsummary: string,\n\t\tfirstKeptEntryId: string,\n\t\ttokensBefore: number,\n\t\tdetails?: T,\n\t\tfromHook?: boolean,\n\t): string {\n\t\tconst entry: CompactionEntry<T> = {\n\t\t\ttype: \"compaction\",\n\t\t\tid: generateId(this.store),\n\t\t\tparentId: this.store.getLeafId(),\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tsummary,\n\t\t\tfirstKeptEntryId,\n\t\t\ttokensBefore,\n\t\t\tdetails,\n\t\t\tfromHook,\n\t\t};\n\t\tthis._appendEntry(entry);\n\t\treturn entry.id;\n\t}\n\n\t/** Append a custom entry (for extensions) as child of current leaf, then advance leaf. Returns entry id. */\n\tappendCustomEntry(customType: string, data?: unknown): string {\n\t\tconst entry: CustomEntry = {\n\t\t\ttype: \"custom\",\n\t\t\tcustomType,\n\t\t\tdata,\n\t\t\tid: generateId(this.store),\n\t\t\tparentId: this.store.getLeafId(),\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t};\n\t\tthis._appendEntry(entry);\n\t\treturn entry.id;\n\t}\n\n\t/** Append a session info entry (e.g., display name). Returns entry id. */\n\tappendSessionInfo(name: string): string {\n\t\tconst entry: SessionInfoEntry = {\n\t\t\ttype: \"session_info\",\n\t\t\tid: generateId(this.store),\n\t\t\tparentId: this.store.getLeafId(),\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tname: name.trim(),\n\t\t};\n\t\tthis._appendEntry(entry);\n\t\treturn entry.id;\n\t}\n\n\t/** Get the current session name from the latest session_info entry, if any. */\n\tgetSessionName(): string | undefined {\n\t\treturn this.store.getSessionName();\n\t}\n\n\t/**\n\t * Append a custom message entry (for extensions) that participates in LLM context.\n\t * @param customType Extension identifier for filtering on reload\n\t * @param content Message content (string or TextContent/ImageContent array)\n\t * @param display Whether to show in TUI (true = styled display, false = hidden)\n\t * @param details Optional extension-specific metadata (not sent to LLM)\n\t * @returns Entry id\n\t */\n\tappendCustomMessageEntry<T = unknown>(\n\t\tcustomType: string,\n\t\tcontent: string | (TextContent | ImageContent)[],\n\t\tdisplay: boolean,\n\t\tdetails?: T,\n\t): string {\n\t\tconst entry: CustomMessageEntry<T> = {\n\t\t\ttype: \"custom_message\",\n\t\t\tcustomType,\n\t\t\tcontent,\n\t\t\tdisplay,\n\t\t\tdetails,\n\t\t\tid: generateId(this.store),\n\t\t\tparentId: this.store.getLeafId(),\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t};\n\t\tthis._appendEntry(entry);\n\t\treturn entry.id;\n\t}\n\n\t// =========================================================================\n\t// Tree Traversal\n\t// =========================================================================\n\n\tgetLeafId(): string | null {\n\t\treturn this.store.getLeafId();\n\t}\n\n\tgetLeafEntry(): SessionEntry | undefined {\n\t\treturn this.store.getLeafEntry();\n\t}\n\n\tgetEntry(id: string): SessionEntry | undefined {\n\t\treturn this.store.getEntry(id);\n\t}\n\n\t/**\n\t * Get all direct children of an entry.\n\t */\n\tgetChildren(parentId: string): SessionEntry[] {\n\t\treturn this.store.getChildren(parentId);\n\t}\n\n\t/**\n\t * Get the label for an entry, if any.\n\t */\n\tgetLabel(id: string): string | undefined {\n\t\treturn this.store.getLabel(id);\n\t}\n\n\t/**\n\t * Set or clear a label on an entry.\n\t * Labels are user-defined markers for bookmarking/navigation.\n\t * Pass undefined or empty string to clear the label.\n\t */\n\tappendLabelChange(targetId: string, label: string | undefined): string {\n\t\tif (!this.store.has(targetId)) {\n\t\t\tthrow new Error(`Entry ${targetId} not found`);\n\t\t}\n\t\tconst entry: LabelEntry = {\n\t\t\ttype: \"label\",\n\t\t\tid: generateId(this.store),\n\t\t\tparentId: this.store.getLeafId(),\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\ttargetId,\n\t\t\tlabel,\n\t\t};\n\t\tthis._appendEntry(entry);\n\t\treturn entry.id;\n\t}\n\n\t/**\n\t * Walk from entry to root, returning all entries in path order.\n\t * Includes all entry types (messages, compaction, model changes, etc.).\n\t * Use buildSessionContext() to get the resolved messages for the LLM.\n\t */\n\tgetBranch(fromId?: string): SessionEntry[] {\n\t\treturn this.store.getBranch(fromId);\n\t}\n\n\t/**\n\t * Build the session context (what gets sent to the LLM).\n\t * Uses tree traversal from current leaf.\n\t */\n\tbuildSessionContext(): SessionContext {\n\t\treturn buildSessionContext(this.getEntries(), this.store.getLeafId(), this.store.getEntryIndex());\n\t}\n\n\t/**\n\t * Get session header.\n\t */\n\tgetHeader(): SessionHeader | null {\n\t\treturn this.store.getHeader();\n\t}\n\n\t/**\n\t * Get all session entries (excludes header). Returns a shallow copy.\n\t * The session is append-only: use appendXXX() to add entries, branch() to\n\t * change the leaf pointer. Entries cannot be modified or deleted.\n\t */\n\tgetEntries(): SessionEntry[] {\n\t\treturn this.store.getEntries();\n\t}\n\n\t/**\n\t * Get the session as a tree structure. Returns a shallow defensive copy of all entries.\n\t * A well-formed session has exactly one root (first entry with parentId === null).\n\t * Orphaned entries (broken parent chain) are also returned as roots.\n\t */\n\tgetTree(): SessionTreeNode[] {\n\t\treturn this.store.getTree();\n\t}\n\n\t// =========================================================================\n\t// Branching\n\t// =========================================================================\n\n\t/**\n\t * Start a new branch from an earlier entry.\n\t * Moves the leaf pointer to the specified entry. The next appendXXX() call\n\t * will create a child of that entry, forming a new branch. Existing entries\n\t * are not modified or deleted.\n\t */\n\tbranch(branchFromId: string): void {\n\t\tif (!this.store.has(branchFromId)) {\n\t\t\tthrow new Error(`Entry ${branchFromId} not found`);\n\t\t}\n\t\tthis.store.setLeafId(branchFromId);\n\t}\n\n\t/**\n\t * Reset the leaf pointer to null (before any entries).\n\t * The next appendXXX() call will create a new root entry (parentId = null).\n\t * Use this when navigating to re-edit the first user message.\n\t */\n\tresetLeaf(): void {\n\t\tthis.store.setLeafId(null);\n\t}\n\n\t/**\n\t * Start a new branch with a summary of the abandoned path.\n\t * Same as branch(), but also appends a branch_summary entry that captures\n\t * context from the abandoned conversation path.\n\t */\n\tbranchWithSummary(branchFromId: string | null, summary: string, details?: unknown, fromHook?: boolean): string {\n\t\tif (branchFromId !== null && !this.store.has(branchFromId)) {\n\t\t\tthrow new Error(`Entry ${branchFromId} not found`);\n\t\t}\n\t\tthis.store.setLeafId(branchFromId);\n\t\tconst entry: BranchSummaryEntry = {\n\t\t\ttype: \"branch_summary\",\n\t\t\tid: generateId(this.store),\n\t\t\tparentId: branchFromId,\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tfromId: branchFromId ?? \"root\",\n\t\t\tsummary,\n\t\t\tdetails,\n\t\t\tfromHook,\n\t\t};\n\t\tthis._appendEntry(entry);\n\t\treturn entry.id;\n\t}\n\n\t/**\n\t * Create a new session reference containing only the path from root to the specified leaf.\n\t * Useful for extracting a single conversation path from a branched session.\n\t * Returns the new session reference, or undefined if the store does not expose one.\n\t */\n\tcreateBranchedSession(leafId: string): string | undefined {\n\t\tconst parentSession = this.getSessionReference();\n\t\tconst path = this.getBranch(leafId);\n\t\tif (path.length === 0) {\n\t\t\tthrow new Error(`Entry ${leafId} not found`);\n\t\t}\n\n\t\t// Filter out LabelEntry from path - we'll recreate them from the resolved map\n\t\tconst pathWithoutLabels = path.filter((e) => e.type !== \"label\");\n\n\t\tconst newSessionId = createSessionId();\n\t\tconst timestamp = new Date().toISOString();\n\t\tconst newSessionReference = this.prepareNewSessionReference(this.getSessionDir(), newSessionId, timestamp);\n\t\tif (newSessionReference) {\n\t\t\tthis.store.setSessionReference(newSessionReference);\n\t\t}\n\n\t\tconst header: SessionHeader = {\n\t\t\ttype: \"session\",\n\t\t\tversion: CURRENT_SESSION_VERSION,\n\t\t\tid: newSessionId,\n\t\t\ttimestamp,\n\t\t\tcwd: this.cwd,\n\t\t\tparentSession,\n\t\t};\n\n\t\t// Collect labels for entries in the path\n\t\tconst pathEntryIds = new Set(pathWithoutLabels.map((e) => e.id));\n\t\tconst labelsToWrite = this.store.getLabelsForEntryIds(pathEntryIds);\n\n\t\tconst labelEntries: LabelEntry[] = [];\n\t\tlet parentId = pathWithoutLabels[pathWithoutLabels.length - 1]?.id || null;\n\t\tfor (const { targetId, label, timestamp: labelTimestamp } of labelsToWrite) {\n\t\t\tconst labelEntry: LabelEntry = {\n\t\t\t\ttype: \"label\",\n\t\t\t\tid: generateId(new Set([...pathEntryIds, ...labelEntries.map((e) => e.id)])),\n\t\t\t\tparentId,\n\t\t\t\ttimestamp: labelTimestamp,\n\t\t\t\ttargetId,\n\t\t\t\tlabel,\n\t\t\t};\n\t\t\tpathEntryIds.add(labelEntry.id);\n\t\t\tlabelEntries.push(labelEntry);\n\t\t\tparentId = labelEntry.id;\n\t\t}\n\t\tthis.store.setEntries([header, ...pathWithoutLabels, ...labelEntries]);\n\t\tthis.sessionId = newSessionId;\n\t\tthis.store.commitSnapshot();\n\t\treturn newSessionReference;\n\t}\n\n\tcopyBranchFrom(source: Session, leafId: string, parentSession?: string): void {\n\t\tconst path = source.getBranch(leafId);\n\t\tif (path.length === 0) {\n\t\t\tthrow new Error(`Entry ${leafId} not found`);\n\t\t}\n\n\t\tconst header = this.getHeader();\n\t\tif (!header) {\n\t\t\tthrow new Error(\"Target session has no header\");\n\t\t}\n\n\t\tconst pathWithoutLabels = structuredClone(path.filter((entry) => entry.type !== \"label\"));\n\t\tconst pathEntryIds = new Set(pathWithoutLabels.map((entry) => entry.id));\n\t\tconst labelsToWrite = source.store.getLabelsForEntryIds(pathEntryIds);\n\t\tconst labelEntries: LabelEntry[] = [];\n\t\tlet nextParentId = pathWithoutLabels[pathWithoutLabels.length - 1]?.id ?? null;\n\t\tfor (const { targetId, label, timestamp } of labelsToWrite) {\n\t\t\tconst labelEntry: LabelEntry = {\n\t\t\t\ttype: \"label\",\n\t\t\t\tid: generateId(new Set([...pathEntryIds, ...labelEntries.map((entry) => entry.id)])),\n\t\t\t\tparentId: nextParentId,\n\t\t\t\ttimestamp,\n\t\t\t\ttargetId,\n\t\t\t\tlabel,\n\t\t\t};\n\t\t\tpathEntryIds.add(labelEntry.id);\n\t\t\tlabelEntries.push(labelEntry);\n\t\t\tnextParentId = labelEntry.id;\n\t\t}\n\n\t\tthis.store.setEntries([{ ...header, parentSession }, ...pathWithoutLabels, ...labelEntries]);\n\t\tthis.store.commitSnapshot();\n\t}\n\n\tcreateSubSession(options?: NewSessionOptions): SessionResult {\n\t\tif (!this.sessionManager) {\n\t\t\tthrow new Error(\"Session manager unavailable\");\n\t\t}\n\t\treturn this.sessionManager.create({\n\t\t\t...options,\n\t\t\tparentSession: options?.parentSession ?? this.getSessionReference(),\n\t\t});\n\t}\n\n\tforkSubSession(targetLeafId: string | null): SessionResult {\n\t\tif (!this.sessionManager) {\n\t\t\tthrow new Error(\"Session manager unavailable\");\n\t\t}\n\t\treturn this.sessionManager.forkSession(this, targetLeafId);\n\t}\n}\n"]}
|