@fleetagent/pi-coding-agent 0.0.5 → 0.0.7
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 +49 -0
- package/README.md +28 -5
- package/dist/cli/args.d.ts +2 -0
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +9 -0
- package/dist/cli/args.js.map +1 -1
- package/dist/cli/file-processor.d.ts.map +1 -1
- package/dist/cli/file-processor.js +2 -3
- package/dist/cli/file-processor.js.map +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +15 -2
- package/dist/config.js.map +1 -1
- package/dist/core/agent-session.d.ts +13 -3
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +130 -23
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/diagnostics.d.ts +1 -1
- package/dist/core/diagnostics.d.ts.map +1 -1
- package/dist/core/diagnostics.js.map +1 -1
- package/dist/core/export-html/template.js +6 -3
- package/dist/core/extensions/runner.d.ts +5 -1
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +13 -3
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/types.d.ts +6 -3
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/model-registry.d.ts.map +1 -1
- package/dist/core/model-registry.js +65 -13
- package/dist/core/model-registry.js.map +1 -1
- package/dist/core/output-guard.d.ts +1 -0
- package/dist/core/output-guard.d.ts.map +1 -1
- package/dist/core/output-guard.js +52 -22
- package/dist/core/output-guard.js.map +1 -1
- package/dist/core/package-manager.d.ts +1 -0
- package/dist/core/package-manager.d.ts.map +1 -1
- package/dist/core/package-manager.js +161 -24
- package/dist/core/package-manager.js.map +1 -1
- package/dist/core/pi-agent.d.ts.map +1 -1
- package/dist/core/pi-agent.js +12 -3
- package/dist/core/pi-agent.js.map +1 -1
- package/dist/core/resolve-config-value.d.ts +9 -1
- package/dist/core/resolve-config-value.d.ts.map +1 -1
- package/dist/core/resolve-config-value.js +134 -11
- package/dist/core/resolve-config-value.js.map +1 -1
- package/dist/core/resource-loader.d.ts +30 -0
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +94 -0
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/rules.d.ts +57 -0
- package/dist/core/rules.d.ts.map +1 -0
- package/dist/core/rules.js +384 -0
- package/dist/core/rules.js.map +1 -0
- package/dist/core/session/jsonl-helpers.d.ts +2 -1
- package/dist/core/session/jsonl-helpers.d.ts.map +1 -1
- package/dist/core/session/jsonl-helpers.js +6 -3
- package/dist/core/session/jsonl-helpers.js.map +1 -1
- package/dist/core/session/local-session-manager.d.ts +1 -0
- package/dist/core/session/local-session-manager.d.ts.map +1 -1
- package/dist/core/session/local-session-manager.js +12 -4
- package/dist/core/session/local-session-manager.js.map +1 -1
- package/dist/core/session/session-manager.d.ts +1 -0
- package/dist/core/session/session-manager.d.ts.map +1 -1
- package/dist/core/session/session-manager.js.map +1 -1
- package/dist/core/session/stores/jsonl-session-store.d.ts +2 -1
- package/dist/core/session/stores/jsonl-session-store.d.ts.map +1 -1
- package/dist/core/session/stores/jsonl-session-store.js +105 -78
- package/dist/core/session/stores/jsonl-session-store.js.map +1 -1
- package/dist/core/settings-manager.d.ts +7 -0
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +28 -9
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/slash-commands.d.ts +1 -1
- package/dist/core/slash-commands.d.ts.map +1 -1
- package/dist/core/slash-commands.js +1 -1
- package/dist/core/slash-commands.js.map +1 -1
- package/dist/core/system-prompt.d.ts +3 -0
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js +11 -3
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +73 -63
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/edit.d.ts.map +1 -1
- package/dist/core/tools/edit.js +45 -76
- package/dist/core/tools/edit.js.map +1 -1
- package/dist/core/tools/file-mutation-queue.d.ts.map +1 -1
- package/dist/core/tools/file-mutation-queue.js +27 -12
- package/dist/core/tools/file-mutation-queue.js.map +1 -1
- package/dist/core/tools/find.d.ts.map +1 -1
- package/dist/core/tools/find.js +11 -2
- package/dist/core/tools/find.js.map +1 -1
- package/dist/core/tools/grep.d.ts.map +1 -1
- package/dist/core/tools/grep.js +3 -3
- package/dist/core/tools/grep.js.map +1 -1
- package/dist/core/tools/ls.d.ts.map +1 -1
- package/dist/core/tools/ls.js +13 -4
- package/dist/core/tools/ls.js.map +1 -1
- package/dist/core/tools/path-utils.d.ts +1 -0
- package/dist/core/tools/path-utils.d.ts.map +1 -1
- package/dist/core/tools/path-utils.js +37 -0
- package/dist/core/tools/path-utils.js.map +1 -1
- package/dist/core/tools/read.d.ts.map +1 -1
- package/dist/core/tools/read.js +13 -8
- package/dist/core/tools/read.js.map +1 -1
- package/dist/core/tools/write.d.ts.map +1 -1
- package/dist/core/tools/write.js +24 -32
- package/dist/core/tools/write.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +6 -2
- package/dist/main.js.map +1 -1
- package/dist/migrations.d.ts.map +1 -1
- package/dist/migrations.js +118 -1
- package/dist/migrations.js.map +1 -1
- package/dist/modes/interactive/components/config-selector.d.ts +1 -1
- package/dist/modes/interactive/components/config-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/config-selector.js +12 -3
- package/dist/modes/interactive/components/config-selector.js.map +1 -1
- package/dist/modes/interactive/components/footer.d.ts +1 -0
- package/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/dist/modes/interactive/components/footer.js +14 -5
- package/dist/modes/interactive/components/footer.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js +1 -1
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/modes/interactive/components/user-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/user-message.js +1 -1
- package/dist/modes/interactive/components/user-message.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +1 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +64 -9
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/dist/modes/interactive/theme/theme.js +10 -0
- package/dist/modes/interactive/theme/theme.js.map +1 -1
- package/dist/modes/rpc/rpc-client.d.ts +5 -0
- package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-client.js +91 -18
- package/dist/modes/rpc/rpc-client.js.map +1 -1
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-mode.js +23 -3
- package/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-types.d.ts +1 -1
- package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-types.js.map +1 -1
- package/dist/utils/clipboard-native.d.ts +3 -1
- package/dist/utils/clipboard-native.d.ts.map +1 -1
- package/dist/utils/clipboard-native.js +14 -8
- package/dist/utils/clipboard-native.js.map +1 -1
- package/dist/utils/deprecation.d.ts +4 -0
- package/dist/utils/deprecation.d.ts.map +1 -0
- package/dist/utils/deprecation.js +13 -0
- package/dist/utils/deprecation.js.map +1 -0
- package/dist/utils/image-resize-core.d.ts +30 -0
- package/dist/utils/image-resize-core.d.ts.map +1 -0
- package/dist/utils/image-resize-core.js +124 -0
- package/dist/utils/image-resize-core.js.map +1 -0
- package/dist/utils/image-resize-worker.d.ts +2 -0
- package/dist/utils/image-resize-worker.d.ts.map +1 -0
- package/dist/utils/image-resize-worker.js +31 -0
- package/dist/utils/image-resize-worker.js.map +1 -0
- package/dist/utils/image-resize.d.ts +6 -27
- package/dist/utils/image-resize.d.ts.map +1 -1
- package/dist/utils/image-resize.js +60 -116
- package/dist/utils/image-resize.js.map +1 -1
- package/dist/utils/json.d.ts +3 -0
- package/dist/utils/json.d.ts.map +1 -0
- package/dist/utils/json.js +7 -0
- package/dist/utils/json.js.map +1 -0
- package/docs/custom-provider.md +22 -9
- package/docs/extensions.md +13 -11
- package/docs/index.md +3 -2
- package/docs/models.md +34 -12
- package/docs/packages.md +11 -8
- package/docs/providers.md +13 -5
- package/docs/quickstart.md +1 -1
- package/docs/rpc.md +4 -2
- package/docs/rules.md +102 -0
- package/docs/sdk.md +57 -1
- package/docs/settings.md +6 -3
- package/docs/terminal-setup.md +6 -0
- package/docs/usage.md +6 -4
- package/examples/extensions/README.md +2 -1
- package/examples/extensions/custom-provider-anthropic/index.ts +1 -1
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/index.ts +54 -3
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/dynamic-resources/RULES.md +8 -0
- package/examples/extensions/dynamic-resources/index.ts +1 -0
- package/examples/extensions/git-merge-and-resolve.ts +115 -0
- package/examples/extensions/reload-runtime.ts +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/with-deps/package.json +1 -1
- package/examples/sdk/12-full-control.ts +1 -0
- package/examples/sdk/README.md +1 -1
- package/npm-shrinkwrap.json +13 -12
- package/package.json +5 -5
|
@@ -1 +1 @@
|
|
|
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
|
+
{"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 {\n\tfindMostRecentSession,\n\tgetDefaultSessionDir,\n\tgetDefaultSessionDirPath,\n\tloadEntriesFromFile,\n} 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 filterCwd = this.sessionDir !== undefined && dir !== getDefaultSessionDirPath(this.cwd);\n\t\tconst mostRecent = findMostRecentSession(dir, filterCwd ? this.cwd : undefined);\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\tusesDefaultSessionDir(): boolean {\n\t\treturn (this.sessionDir ?? getDefaultSessionDir(this.cwd)) === getDefaultSessionDirPath(this.cwd);\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 filterCwd = this.sessionDir !== undefined && dir !== getDefaultSessionDirPath(this.cwd);\n\t\tconst resolvedCwd = resolve(this.cwd);\n\t\tconst sessions = (await listJsonlSessions(dir, onProgress)).filter(\n\t\t\t(session) => !filterCwd || (session.cwd !== undefined && resolve(session.cwd) === resolvedCwd),\n\t\t);\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 = this.sessionDir\n\t\t\t? await listJsonlSessions(this.sessionDir, onProgress)\n\t\t\t: await listAllJsonlSessions(getSessionsRoot(), onProgress);\n\t\tsessions.sort((a, b) => b.modified.getTime() - a.modified.getTime());\n\t\treturn sessions;\n\t}\n}\n"]}
|
|
@@ -13,5 +13,6 @@ export interface SessionManager {
|
|
|
13
13
|
importJsonl(inputPath: string, options?: OpenSessionOptions): SessionResult;
|
|
14
14
|
list(onProgress?: SessionListProgress): Promise<SessionInfo[]>;
|
|
15
15
|
listAll(onProgress?: SessionListProgress): Promise<SessionInfo[]>;
|
|
16
|
+
usesDefaultSessionDir?(): boolean;
|
|
16
17
|
}
|
|
17
18
|
//# sourceMappingURL=session-manager.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-manager.d.ts","sourceRoot":"","sources":["../../../src/core/session/session-manager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,KAAK,EAAE,iBAAiB,EAAE,WAAW,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAEtF,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;AAEvD,MAAM,WAAW,kBAAkB;IAClC,WAAW,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,cAAc;IAC9B,MAAM,CAAC,OAAO,CAAC,EAAE,iBAAiB,GAAG,aAAa,CAAC;IACnD,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,kBAAkB,GAAG,aAAa,CAAC;IAC9E,cAAc,IAAI,aAAa,CAAC;IAChC,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,aAAa,CAAC;IAC3C,WAAW,CAAC,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,GAAG,IAAI,GAAG,aAAa,CAAC;IACzE,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,kBAAkB,GAAG,aAAa,CAAC;IAC5E,IAAI,CAAC,UAAU,CAAC,EAAE,mBAAmB,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;IAC/D,OAAO,CAAC,UAAU,CAAC,EAAE,mBAAmB,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"session-manager.d.ts","sourceRoot":"","sources":["../../../src/core/session/session-manager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,KAAK,EAAE,iBAAiB,EAAE,WAAW,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAEtF,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;AAEvD,MAAM,WAAW,kBAAkB;IAClC,WAAW,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,cAAc;IAC9B,MAAM,CAAC,OAAO,CAAC,EAAE,iBAAiB,GAAG,aAAa,CAAC;IACnD,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,kBAAkB,GAAG,aAAa,CAAC;IAC9E,cAAc,IAAI,aAAa,CAAC;IAChC,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,aAAa,CAAC;IAC3C,WAAW,CAAC,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,GAAG,IAAI,GAAG,aAAa,CAAC;IACzE,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,kBAAkB,GAAG,aAAa,CAAC;IAC5E,IAAI,CAAC,UAAU,CAAC,EAAE,mBAAmB,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;IAC/D,OAAO,CAAC,UAAU,CAAC,EAAE,mBAAmB,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;IAClE,qBAAqB,CAAC,IAAI,OAAO,CAAC;CAClC","sourcesContent":["import type { Session } from \"./session.ts\";\nimport type { NewSessionOptions, SessionInfo, SessionListProgress } from \"./types.ts\";\n\nexport type SessionResult = Session | Promise<Session>;\n\nexport interface OpenSessionOptions {\n\tcwdOverride?: string;\n}\n\nexport interface SessionManager {\n\tcreate(options?: NewSessionOptions): SessionResult;\n\topenReference(reference: string, options?: OpenSessionOptions): SessionResult;\n\tcontinueRecent(): SessionResult;\n\tforkFrom(reference: string): SessionResult;\n\tforkSession(source: Session, targetLeafId: string | null): SessionResult;\n\timportJsonl(inputPath: string, options?: OpenSessionOptions): SessionResult;\n\tlist(onProgress?: SessionListProgress): Promise<SessionInfo[]>;\n\tlistAll(onProgress?: SessionListProgress): Promise<SessionInfo[]>;\n\tusesDefaultSessionDir?(): boolean;\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-manager.js","sourceRoot":"","sources":["../../../src/core/session/session-manager.ts"],"names":[],"mappings":"","sourcesContent":["import type { Session } from \"./session.ts\";\nimport type { NewSessionOptions, SessionInfo, SessionListProgress } from \"./types.ts\";\n\nexport type SessionResult = Session | Promise<Session>;\n\nexport interface OpenSessionOptions {\n\tcwdOverride?: string;\n}\n\nexport interface SessionManager {\n\tcreate(options?: NewSessionOptions): SessionResult;\n\topenReference(reference: string, options?: OpenSessionOptions): SessionResult;\n\tcontinueRecent(): SessionResult;\n\tforkFrom(reference: string): SessionResult;\n\tforkSession(source: Session, targetLeafId: string | null): SessionResult;\n\timportJsonl(inputPath: string, options?: OpenSessionOptions): SessionResult;\n\tlist(onProgress?: SessionListProgress): Promise<SessionInfo[]>;\n\tlistAll(onProgress?: SessionListProgress): Promise<SessionInfo[]>;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"session-manager.js","sourceRoot":"","sources":["../../../src/core/session/session-manager.ts"],"names":[],"mappings":"","sourcesContent":["import type { Session } from \"./session.ts\";\nimport type { NewSessionOptions, SessionInfo, SessionListProgress } from \"./types.ts\";\n\nexport type SessionResult = Session | Promise<Session>;\n\nexport interface OpenSessionOptions {\n\tcwdOverride?: string;\n}\n\nexport interface SessionManager {\n\tcreate(options?: NewSessionOptions): SessionResult;\n\topenReference(reference: string, options?: OpenSessionOptions): SessionResult;\n\tcontinueRecent(): SessionResult;\n\tforkFrom(reference: string): SessionResult;\n\tforkSession(source: Session, targetLeafId: string | null): SessionResult;\n\timportJsonl(inputPath: string, options?: OpenSessionOptions): SessionResult;\n\tlist(onProgress?: SessionListProgress): Promise<SessionInfo[]>;\n\tlistAll(onProgress?: SessionListProgress): Promise<SessionInfo[]>;\n\tusesDefaultSessionDir?(): boolean;\n}\n"]}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { FileEntry, SessionEntry, SessionHeader, SessionInfo, SessionListProgress } from "../types.ts";
|
|
2
2
|
import { InMemorySessionStore } from "./in-memory-session-store.ts";
|
|
3
3
|
export declare function getSessionDirForReference(reference: string): string;
|
|
4
|
+
export declare function getDefaultSessionDirPath(cwd: string, agentDir?: string): string;
|
|
4
5
|
export declare function getDefaultSessionDir(cwd: string, agentDir?: string): string;
|
|
5
6
|
export declare function getSessionsRoot(): string;
|
|
6
7
|
export declare function prepareSessionReference(sessionDir: string, sessionId: string, timestamp: string): string;
|
|
@@ -10,7 +11,7 @@ export declare function load(filePath: string): FileEntry[];
|
|
|
10
11
|
export declare function append(filePath: string, entry: FileEntry): void;
|
|
11
12
|
export declare function rewrite(filePath: string, entries: FileEntry[]): void;
|
|
12
13
|
export declare function forkSession(sessionDir: string, header: SessionHeader, sourceEntries: FileEntry[]): string;
|
|
13
|
-
export declare function findMostRecent(sessionDir: string): string | null;
|
|
14
|
+
export declare function findMostRecent(sessionDir: string, cwd?: string): string | null;
|
|
14
15
|
export declare function list(dir: string, onProgress?: SessionListProgress): Promise<SessionInfo[]>;
|
|
15
16
|
export declare function listAll(sessionsDir: string, onProgress?: SessionListProgress): Promise<SessionInfo[]>;
|
|
16
17
|
export declare class JsonlSessionStore extends InMemorySessionStore {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"jsonl-session-store.d.ts","sourceRoot":"","sources":["../../../../src/core/session/stores/jsonl-session-store.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EACX,SAAS,EACT,YAAY,EAEZ,aAAa,EACb,WAAW,EAEX,mBAAmB,EAEnB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AA8IpE,wBAAgB,yBAAyB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAEnE;AAED,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,GAAE,MAA6B,GAAG,MAAM,CAKjG;AAED,wBAAgB,eAAe,IAAI,MAAM,CAExC;AAED,wBAAgB,uBAAuB,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAGxG;AAED,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAE5C;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAI5C;AAED,wBAAgB,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,EAAE,CAwBlD;AAED,wBAAgB,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,GAAG,IAAI,CAE/D;AAED,wBAAgB,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,GAAG,IAAI,CAGpE;AAED,wBAAgB,WAAW,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE,aAAa,EAAE,SAAS,EAAE,GAAG,MAAM,CASzG;AAED,wBAAgB,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAahE;AAED,wBAAsB,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,mBAAmB,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CAwBhG;AAED,wBAAsB,OAAO,CAAC,WAAW,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,mBAAmB,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CAsC3G;AA0CD,qBAAa,iBAAkB,SAAQ,oBAAoB;IAC1D,OAAO,CAAC,SAAS,CAAqB;IACtC,OAAO,CAAC,OAAO,CAAS;IAExB,WAAW,IAAI,OAAO,CAErB;IAED,mBAAmB,IAAI,MAAM,GAAG,SAAS,CAExC;IAED,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAG3C;IAED,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAE5B;IAED,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAE5B;IAED,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,EAAE,CAIlC;IAED,WAAW,CAAC,KAAK,EAAE,YAAY,GAAG,IAAI,CAGrC;IAED,OAAO,CAAC,oBAAoB;IAkB5B,YAAY,IAAI,IAAI,CAInB;IAED,cAAc,IAAI,IAAI,CAMrB;CACD","sourcesContent":["import type { AgentMessage } from \"@fleetagent/pi-agent-core\";\nimport type { Message, TextContent } from \"@fleetagent/pi-ai\";\nimport {\n\tappendFileSync,\n\tcloseSync,\n\texistsSync,\n\tmkdirSync,\n\topenSync,\n\treaddirSync,\n\treadFileSync,\n\treadSync,\n\tstatSync,\n\twriteFileSync,\n} from \"fs\";\nimport { readdir, readFile, stat } from \"fs/promises\";\nimport { join, resolve } from \"path\";\nimport { getAgentDir as getDefaultAgentDir, getSessionsDir } from \"../../../config.ts\";\nimport type {\n\tFileEntry,\n\tSessionEntry,\n\tSessionEntryBase,\n\tSessionHeader,\n\tSessionInfo,\n\tSessionInfoEntry,\n\tSessionListProgress,\n\tSessionMessageEntry,\n} from \"../types.ts\";\nimport { InMemorySessionStore } from \"./in-memory-session-store.ts\";\n\nfunction isMessageWithContent(message: AgentMessage): message is Message {\n\treturn typeof (message as Message).role === \"string\" && \"content\" in message;\n}\n\nfunction extractTextContent(message: Message): string {\n\tconst content = message.content;\n\tif (typeof content === \"string\") {\n\t\treturn content;\n\t}\n\treturn content\n\t\t.filter((block): block is TextContent => block.type === \"text\")\n\t\t.map((block) => block.text)\n\t\t.join(\" \");\n}\n\nfunction getLastActivityTime(entries: FileEntry[]): number | undefined {\n\tlet lastActivityTime: number | undefined;\n\n\tfor (const entry of entries) {\n\t\tif (entry.type !== \"message\") continue;\n\n\t\tconst message = (entry as SessionMessageEntry).message;\n\t\tif (!isMessageWithContent(message)) continue;\n\t\tif (message.role !== \"user\" && message.role !== \"assistant\") continue;\n\n\t\tconst msgTimestamp = (message as { timestamp?: number }).timestamp;\n\t\tif (typeof msgTimestamp === \"number\") {\n\t\t\tlastActivityTime = Math.max(lastActivityTime ?? 0, msgTimestamp);\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst entryTimestamp = (entry as SessionEntryBase).timestamp;\n\t\tif (typeof entryTimestamp === \"string\") {\n\t\t\tconst t = new Date(entryTimestamp).getTime();\n\t\t\tif (!Number.isNaN(t)) {\n\t\t\t\tlastActivityTime = Math.max(lastActivityTime ?? 0, t);\n\t\t\t}\n\t\t}\n\t}\n\n\treturn lastActivityTime;\n}\n\nfunction getSessionModifiedDate(entries: FileEntry[], header: SessionHeader, statsMtime: Date): Date {\n\tconst lastActivityTime = getLastActivityTime(entries);\n\tif (typeof lastActivityTime === \"number\" && lastActivityTime > 0) {\n\t\treturn new Date(lastActivityTime);\n\t}\n\n\tconst headerTime = typeof header.timestamp === \"string\" ? new Date(header.timestamp).getTime() : NaN;\n\treturn !Number.isNaN(headerTime) ? new Date(headerTime) : statsMtime;\n}\n\nfunction isValidSessionFile(filePath: string): boolean {\n\ttry {\n\t\tconst fd = openSync(filePath, \"r\");\n\t\tconst buffer = Buffer.alloc(512);\n\t\tconst bytesRead = readSync(fd, buffer, 0, 512, 0);\n\t\tcloseSync(fd);\n\t\tconst firstLine = buffer.toString(\"utf8\", 0, bytesRead).split(\"\\n\")[0];\n\t\tif (!firstLine) return false;\n\t\tconst header = JSON.parse(firstLine) as Partial<SessionHeader>;\n\t\treturn header.type === \"session\" && typeof header.id === \"string\";\n\t} catch {\n\t\treturn false;\n\t}\n}\n\nasync function buildSessionInfo(filePath: string): Promise<SessionInfo | null> {\n\ttry {\n\t\tconst content = await readFile(filePath, \"utf8\");\n\t\tconst entries: FileEntry[] = [];\n\t\tconst lines = content.trim().split(\"\\n\");\n\n\t\tfor (const line of lines) {\n\t\t\tif (!line.trim()) continue;\n\t\t\ttry {\n\t\t\t\tentries.push(JSON.parse(line) as FileEntry);\n\t\t\t} catch {\n\t\t\t\t// Skip malformed lines\n\t\t\t}\n\t\t}\n\n\t\tif (entries.length === 0) return null;\n\t\tconst header = entries[0];\n\t\tif (header.type !== \"session\") return null;\n\n\t\tconst stats = await stat(filePath);\n\t\tlet messageCount = 0;\n\t\tlet firstMessage = \"\";\n\t\tconst allMessages: string[] = [];\n\t\tlet name: string | undefined;\n\n\t\tfor (const entry of entries) {\n\t\t\tif (entry.type === \"session_info\") {\n\t\t\t\tconst infoEntry = entry as SessionInfoEntry;\n\t\t\t\tname = infoEntry.name?.trim() || undefined;\n\t\t\t}\n\n\t\t\tif (entry.type !== \"message\") continue;\n\t\t\tmessageCount++;\n\n\t\t\tconst message = (entry as SessionMessageEntry).message;\n\t\t\tif (!isMessageWithContent(message)) continue;\n\t\t\tif (message.role !== \"user\" && message.role !== \"assistant\") continue;\n\n\t\t\tconst textContent = extractTextContent(message);\n\t\t\tif (!textContent) continue;\n\n\t\t\tallMessages.push(textContent);\n\t\t\tif (!firstMessage && message.role === \"user\") {\n\t\t\t\tfirstMessage = textContent;\n\t\t\t}\n\t\t}\n\n\t\tconst sessionHeader = header as SessionHeader;\n\t\tconst cwd = typeof sessionHeader.cwd === \"string\" ? sessionHeader.cwd : \"\";\n\t\tconst parentSessionPath = sessionHeader.parentSession;\n\t\tconst modified = getSessionModifiedDate(entries, sessionHeader, stats.mtime);\n\n\t\treturn {\n\t\t\treference: filePath,\n\t\t\tpath: filePath,\n\t\t\tid: sessionHeader.id,\n\t\t\tcwd,\n\t\t\tname,\n\t\t\tparentSessionPath,\n\t\t\tcreated: new Date(sessionHeader.timestamp),\n\t\t\tmodified,\n\t\t\tmessageCount,\n\t\t\tfirstMessage: firstMessage || \"(no messages)\",\n\t\t\tallMessagesText: allMessages.join(\" \"),\n\t\t};\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nconst MAX_CONCURRENT_SESSION_INFO_LOADS = 10;\n\nexport function getSessionDirForReference(reference: string): string {\n\treturn resolve(reference, \"..\");\n}\n\nexport function getDefaultSessionDir(cwd: string, agentDir: string = getDefaultAgentDir()): string {\n\tconst safePath = `--${cwd.replace(/^[/\\\\]/, \"\").replace(/[/\\\\:]/g, \"-\")}--`;\n\tconst sessionDir = join(agentDir, \"sessions\", safePath);\n\tensureDir(sessionDir);\n\treturn sessionDir;\n}\n\nexport function getSessionsRoot(): string {\n\treturn getSessionsDir();\n}\n\nexport function prepareSessionReference(sessionDir: string, sessionId: string, timestamp: string): string {\n\tconst fileTimestamp = timestamp.replace(/[:.]/g, \"-\");\n\treturn join(sessionDir, `${fileTimestamp}_${sessionId}.jsonl`);\n}\n\nexport function exists(path: string): boolean {\n\treturn existsSync(path);\n}\n\nexport function ensureDir(path: string): void {\n\tif (!existsSync(path)) {\n\t\tmkdirSync(path, { recursive: true });\n\t}\n}\n\nexport function load(filePath: string): FileEntry[] {\n\tif (!existsSync(filePath)) return [];\n\n\tconst content = readFileSync(filePath, \"utf8\");\n\tconst entries: FileEntry[] = [];\n\tconst lines = content.trim().split(\"\\n\");\n\n\tfor (const line of lines) {\n\t\tif (!line.trim()) continue;\n\t\ttry {\n\t\t\tconst entry = JSON.parse(line) as FileEntry;\n\t\t\tentries.push(entry);\n\t\t} catch {\n\t\t\t// Skip malformed lines\n\t\t}\n\t}\n\n\tif (entries.length === 0) return entries;\n\tconst header = entries[0];\n\tif (header.type !== \"session\" || typeof (header as Partial<SessionHeader>).id !== \"string\") {\n\t\treturn [];\n\t}\n\n\treturn entries;\n}\n\nexport function append(filePath: string, entry: FileEntry): void {\n\tappendFileSync(filePath, `${JSON.stringify(entry)}\\n`);\n}\n\nexport function rewrite(filePath: string, entries: FileEntry[]): void {\n\tconst content = `${entries.map((entry) => JSON.stringify(entry)).join(\"\\n\")}\\n`;\n\twriteFileSync(filePath, content);\n}\n\nexport function forkSession(sessionDir: string, header: SessionHeader, sourceEntries: FileEntry[]): string {\n\tconst reference = prepareSessionReference(sessionDir, header.id, header.timestamp);\n\tappend(reference, header);\n\tfor (const entry of sourceEntries) {\n\t\tif (entry.type !== \"session\") {\n\t\t\tappend(reference, entry);\n\t\t}\n\t}\n\treturn reference;\n}\n\nexport function findMostRecent(sessionDir: string): string | null {\n\ttry {\n\t\tconst files = readdirSync(sessionDir)\n\t\t\t.filter((file) => file.endsWith(\".jsonl\"))\n\t\t\t.map((file) => join(sessionDir, file))\n\t\t\t.filter(isValidSessionFile)\n\t\t\t.map((path) => ({ path, mtime: statSync(path).mtime }))\n\t\t\t.sort((a, b) => b.mtime.getTime() - a.mtime.getTime());\n\n\t\treturn files[0]?.path || null;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nexport async function list(dir: string, onProgress?: SessionListProgress): Promise<SessionInfo[]> {\n\tconst sessions: SessionInfo[] = [];\n\tif (!existsSync(dir)) {\n\t\treturn sessions;\n\t}\n\n\ttry {\n\t\tconst dirEntries = await readdir(dir);\n\t\tconst files = dirEntries.filter((file) => file.endsWith(\".jsonl\")).map((file) => join(dir, file));\n\t\tlet loaded = 0;\n\t\tconst results = await buildSessionInfosWithConcurrency(files, () => {\n\t\t\tloaded++;\n\t\t\tonProgress?.(loaded, files.length);\n\t\t});\n\t\tfor (const info of results) {\n\t\t\tif (info) {\n\t\t\t\tsessions.push(info);\n\t\t\t}\n\t\t}\n\t} catch {\n\t\t// Return empty list on error\n\t}\n\n\treturn sessions;\n}\n\nexport async function listAll(sessionsDir: string, onProgress?: SessionListProgress): Promise<SessionInfo[]> {\n\ttry {\n\t\tif (!existsSync(sessionsDir)) {\n\t\t\treturn [];\n\t\t}\n\t\tconst entries = await readdir(sessionsDir, { withFileTypes: true });\n\t\tconst dirs = entries.filter((entry) => entry.isDirectory()).map((entry) => join(sessionsDir, entry.name));\n\n\t\tlet totalFiles = 0;\n\t\tconst dirFiles: string[][] = [];\n\t\tfor (const dir of dirs) {\n\t\t\ttry {\n\t\t\t\tconst files = (await readdir(dir)).filter((file) => file.endsWith(\".jsonl\"));\n\t\t\t\tdirFiles.push(files.map((file) => join(dir, file)));\n\t\t\t\ttotalFiles += files.length;\n\t\t\t} catch {\n\t\t\t\tdirFiles.push([]);\n\t\t\t}\n\t\t}\n\n\t\tlet loaded = 0;\n\t\tconst sessions: SessionInfo[] = [];\n\t\tconst allFiles = dirFiles.flat();\n\t\tconst results = await buildSessionInfosWithConcurrency(allFiles, () => {\n\t\t\tloaded++;\n\t\t\tonProgress?.(loaded, totalFiles);\n\t\t});\n\n\t\tfor (const info of results) {\n\t\t\tif (info) {\n\t\t\t\tsessions.push(info);\n\t\t\t}\n\t\t}\n\n\t\treturn sessions;\n\t} catch {\n\t\treturn [];\n\t}\n}\n\nasync function buildSessionInfosWithConcurrency(\n\tfiles: string[],\n\tonLoaded: () => void,\n): Promise<(SessionInfo | null)[]> {\n\tconst results: (SessionInfo | null)[] = new Array(files.length).fill(null);\n\tconst inFlight = new Set<Promise<void>>();\n\tlet nextIndex = 0;\n\n\tconst startNext = (): void => {\n\t\tconst index = nextIndex++;\n\t\tconst file = files[index];\n\t\tif (!file) return;\n\n\t\tlet task: Promise<void>;\n\t\ttask = buildSessionInfo(file)\n\t\t\t.then((info) => {\n\t\t\t\tresults[index] = info;\n\t\t\t})\n\t\t\t.catch(() => {\n\t\t\t\tresults[index] = null;\n\t\t\t})\n\t\t\t.finally(() => {\n\t\t\t\tinFlight.delete(task);\n\t\t\t\tonLoaded();\n\t\t\t});\n\t\tinFlight.add(task);\n\t};\n\n\twhile (nextIndex < files.length || inFlight.size > 0) {\n\t\twhile (nextIndex < files.length && inFlight.size < MAX_CONCURRENT_SESSION_INFO_LOADS) {\n\t\t\tstartNext();\n\t\t}\n\t\tif (inFlight.size > 0) {\n\t\t\tawait Promise.race(inFlight);\n\t\t}\n\t}\n\n\treturn results;\n}\n\nexport class JsonlSessionStore extends InMemorySessionStore {\n\tprivate reference: string | undefined;\n\tprivate flushed = false;\n\n\tisPersisted(): boolean {\n\t\treturn true;\n\t}\n\n\tgetSessionReference(): string | undefined {\n\t\treturn this.reference;\n\t}\n\n\tsetSessionReference(reference: string): void {\n\t\tthis.reference = resolve(reference);\n\t\tthis.flushed = false;\n\t}\n\n\texists(path: string): boolean {\n\t\treturn exists(path);\n\t}\n\n\tensureDir(path: string): void {\n\t\tensureDir(path);\n\t}\n\n\tload(filePath: string): FileEntry[] {\n\t\tif (!exists(filePath)) return [];\n\t\tthis.flushed = true;\n\t\treturn load(filePath);\n\t}\n\n\tappendEntry(entry: SessionEntry): void {\n\t\tsuper.appendEntry(entry);\n\t\tthis.persistAppendedEntry(entry);\n\t}\n\n\tprivate persistAppendedEntry(entry: SessionEntry): void {\n\t\tif (!this.reference) return;\n\n\t\tif (!this.hasAssistantMessage()) {\n\t\t\tthis.flushed = false;\n\t\t\treturn;\n\t\t}\n\n\t\tif (!this.flushed) {\n\t\t\tfor (const fileEntry of this.getFileEntries()) {\n\t\t\t\tappend(this.reference, fileEntry);\n\t\t\t}\n\t\t\tthis.flushed = true;\n\t\t} else {\n\t\t\tappend(this.reference, entry);\n\t\t}\n\t}\n\n\tsaveSnapshot(): void {\n\t\tif (!this.reference) return;\n\t\trewrite(this.reference, this.getFileEntries());\n\t\tthis.flushed = true;\n\t}\n\n\tcommitSnapshot(): void {\n\t\tif (!this.hasAssistantMessage()) {\n\t\t\tthis.flushed = false;\n\t\t\treturn;\n\t\t}\n\t\tthis.saveSnapshot();\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"jsonl-session-store.d.ts","sourceRoot":"","sources":["../../../../src/core/session/stores/jsonl-session-store.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EACX,SAAS,EACT,YAAY,EACZ,aAAa,EACb,WAAW,EACX,mBAAmB,EAEnB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AAgJpE,wBAAgB,yBAAyB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAEnE;AAED,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,GAAE,MAA6B,GAAG,MAAM,CAIrG;AAED,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,GAAE,MAA6B,GAAG,MAAM,CAIjG;AAED,wBAAgB,eAAe,IAAI,MAAM,CAExC;AAED,wBAAgB,uBAAuB,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAGxG;AAED,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAE5C;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAI5C;AAID,wBAAgB,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,EAAE,CAwClD;AAED,wBAAgB,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,GAAG,IAAI,CAE/D;AAED,wBAAgB,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,GAAG,IAAI,CAGpE;AAED,wBAAgB,WAAW,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE,aAAa,EAAE,SAAS,EAAE,GAAG,MAAM,CASzG;AAED,wBAAgB,cAAc,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAkB9E;AAED,wBAAsB,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,mBAAmB,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CAwBhG;AAED,wBAAsB,OAAO,CAAC,WAAW,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,mBAAmB,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CAsC3G;AA0CD,qBAAa,iBAAkB,SAAQ,oBAAoB;IAC1D,OAAO,CAAC,SAAS,CAAqB;IACtC,OAAO,CAAC,OAAO,CAAS;IAExB,WAAW,IAAI,OAAO,CAErB;IAED,mBAAmB,IAAI,MAAM,GAAG,SAAS,CAExC;IAED,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAG3C;IAED,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAE5B;IAED,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAE5B;IAED,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,EAAE,CAIlC;IAED,WAAW,CAAC,KAAK,EAAE,YAAY,GAAG,IAAI,CAGrC;IAED,OAAO,CAAC,oBAAoB;IAkB5B,YAAY,IAAI,IAAI,CAInB;IAED,cAAc,IAAI,IAAI,CAMrB;CACD","sourcesContent":["import type { AgentMessage } from \"@fleetagent/pi-agent-core\";\nimport type { Message, TextContent } from \"@fleetagent/pi-ai\";\nimport {\n\tappendFileSync,\n\tcloseSync,\n\tcreateReadStream,\n\texistsSync,\n\tmkdirSync,\n\topenSync,\n\treaddirSync,\n\treadSync,\n\tstatSync,\n\twriteFileSync,\n} from \"fs\";\nimport { readdir, stat } from \"fs/promises\";\nimport { join, resolve } from \"path\";\nimport { createInterface } from \"readline\";\nimport { StringDecoder } from \"string_decoder\";\nimport { getAgentDir as getDefaultAgentDir, getSessionsDir } from \"../../../config.ts\";\nimport type {\n\tFileEntry,\n\tSessionEntry,\n\tSessionHeader,\n\tSessionInfo,\n\tSessionListProgress,\n\tSessionMessageEntry,\n} from \"../types.ts\";\nimport { InMemorySessionStore } from \"./in-memory-session-store.ts\";\n\nfunction isMessageWithContent(message: AgentMessage): message is Message {\n\treturn typeof (message as Message).role === \"string\" && \"content\" in message;\n}\n\nfunction extractTextContent(message: Message): string {\n\tconst content = message.content;\n\tif (typeof content === \"string\") {\n\t\treturn content;\n\t}\n\treturn content\n\t\t.filter((block): block is TextContent => block.type === \"text\")\n\t\t.map((block) => block.text)\n\t\t.join(\" \");\n}\n\nfunction getMessageActivityTime(entry: SessionMessageEntry): number | undefined {\n\tconst message = entry.message;\n\tif (!isMessageWithContent(message)) return undefined;\n\tif (message.role !== \"user\" && message.role !== \"assistant\") return undefined;\n\n\tconst msgTimestamp = (message as { timestamp?: number }).timestamp;\n\tif (typeof msgTimestamp === \"number\") {\n\t\treturn msgTimestamp;\n\t}\n\n\tconst t = new Date(entry.timestamp).getTime();\n\treturn Number.isNaN(t) ? undefined : t;\n}\n\nfunction parseSessionEntryLine(line: string): FileEntry | null {\n\tif (!line.trim()) return null;\n\ttry {\n\t\treturn JSON.parse(line) as FileEntry;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nfunction readSessionHeader(filePath: string): SessionHeader | null {\n\ttry {\n\t\tconst fd = openSync(filePath, \"r\");\n\t\tconst buffer = Buffer.alloc(512);\n\t\tconst bytesRead = readSync(fd, buffer, 0, 512, 0);\n\t\tcloseSync(fd);\n\t\tconst firstLine = buffer.toString(\"utf8\", 0, bytesRead).split(\"\\n\")[0];\n\t\tif (!firstLine) return null;\n\t\tconst header = JSON.parse(firstLine) as Partial<SessionHeader>;\n\t\tif (header.type !== \"session\" || typeof header.id !== \"string\") {\n\t\t\treturn null;\n\t\t}\n\t\treturn header as SessionHeader;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nfunction sessionCwdMatches(cwd: string | undefined, resolvedCwd: string): boolean {\n\treturn cwd !== undefined && cwd !== \"\" && resolve(cwd) === resolvedCwd;\n}\n\nasync function buildSessionInfo(filePath: string): Promise<SessionInfo | null> {\n\ttry {\n\t\tconst stats = await stat(filePath);\n\t\tlet header: SessionHeader | null = null;\n\t\tlet messageCount = 0;\n\t\tlet firstMessage = \"\";\n\t\tconst allMessages: string[] = [];\n\t\tlet name: string | undefined;\n\t\tlet lastActivityTime: number | undefined;\n\n\t\tconst rl = createInterface({\n\t\t\tinput: createReadStream(filePath, { encoding: \"utf8\" }),\n\t\t\tcrlfDelay: Infinity,\n\t\t});\n\n\t\tfor await (const line of rl) {\n\t\t\tconst entry = parseSessionEntryLine(line);\n\t\t\tif (!entry) continue;\n\n\t\t\tif (!header) {\n\t\t\t\tif (entry.type !== \"session\") return null;\n\t\t\t\theader = entry;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (entry.type === \"session_info\") {\n\t\t\t\tname = entry.name?.trim() || undefined;\n\t\t\t}\n\n\t\t\tif (entry.type !== \"message\") continue;\n\t\t\tmessageCount++;\n\n\t\t\tconst activityTime = getMessageActivityTime(entry);\n\t\t\tif (typeof activityTime === \"number\") {\n\t\t\t\tlastActivityTime = Math.max(lastActivityTime ?? 0, activityTime);\n\t\t\t}\n\n\t\t\tconst message = entry.message;\n\t\t\tif (!isMessageWithContent(message)) continue;\n\t\t\tif (message.role !== \"user\" && message.role !== \"assistant\") continue;\n\n\t\t\tconst textContent = extractTextContent(message);\n\t\t\tif (!textContent) continue;\n\n\t\t\tallMessages.push(textContent);\n\t\t\tif (!firstMessage && message.role === \"user\") {\n\t\t\t\tfirstMessage = textContent;\n\t\t\t}\n\t\t}\n\n\t\tif (!header) return null;\n\n\t\tconst cwd = typeof header.cwd === \"string\" ? header.cwd : \"\";\n\t\tconst parentSessionPath = header.parentSession;\n\t\tconst headerTime = typeof header.timestamp === \"string\" ? new Date(header.timestamp).getTime() : NaN;\n\t\tconst modified =\n\t\t\ttypeof lastActivityTime === \"number\" && lastActivityTime > 0\n\t\t\t\t? new Date(lastActivityTime)\n\t\t\t\t: !Number.isNaN(headerTime)\n\t\t\t\t\t? new Date(headerTime)\n\t\t\t\t\t: stats.mtime;\n\n\t\treturn {\n\t\t\treference: filePath,\n\t\t\tpath: filePath,\n\t\t\tid: header.id,\n\t\t\tcwd,\n\t\t\tname,\n\t\t\tparentSessionPath,\n\t\t\tcreated: new Date(header.timestamp),\n\t\t\tmodified,\n\t\t\tmessageCount,\n\t\t\tfirstMessage: firstMessage || \"(no messages)\",\n\t\t\tallMessagesText: allMessages.join(\" \"),\n\t\t};\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nconst MAX_CONCURRENT_SESSION_INFO_LOADS = 10;\n\nexport function getSessionDirForReference(reference: string): string {\n\treturn resolve(reference, \"..\");\n}\n\nexport function getDefaultSessionDirPath(cwd: string, agentDir: string = getDefaultAgentDir()): string {\n\tconst resolvedCwd = resolve(cwd);\n\tconst safePath = `--${resolvedCwd.replace(/^[/\\\\]/, \"\").replace(/[/\\\\:]/g, \"-\")}--`;\n\treturn join(resolve(agentDir), \"sessions\", safePath);\n}\n\nexport function getDefaultSessionDir(cwd: string, agentDir: string = getDefaultAgentDir()): string {\n\tconst sessionDir = getDefaultSessionDirPath(cwd, agentDir);\n\tensureDir(sessionDir);\n\treturn sessionDir;\n}\n\nexport function getSessionsRoot(): string {\n\treturn getSessionsDir();\n}\n\nexport function prepareSessionReference(sessionDir: string, sessionId: string, timestamp: string): string {\n\tconst fileTimestamp = timestamp.replace(/[:.]/g, \"-\");\n\treturn join(sessionDir, `${fileTimestamp}_${sessionId}.jsonl`);\n}\n\nexport function exists(path: string): boolean {\n\treturn existsSync(path);\n}\n\nexport function ensureDir(path: string): void {\n\tif (!existsSync(path)) {\n\t\tmkdirSync(path, { recursive: true });\n\t}\n}\n\nconst SESSION_READ_BUFFER_SIZE = 1024 * 1024;\n\nexport function load(filePath: string): FileEntry[] {\n\tif (!existsSync(filePath)) return [];\n\n\tconst entries: FileEntry[] = [];\n\tconst fd = openSync(filePath, \"r\");\n\ttry {\n\t\tconst decoder = new StringDecoder(\"utf8\");\n\t\tconst buffer = Buffer.allocUnsafe(SESSION_READ_BUFFER_SIZE);\n\t\tlet pending = \"\";\n\n\t\twhile (true) {\n\t\t\tconst bytesRead = readSync(fd, buffer, 0, buffer.length, null);\n\t\t\tif (bytesRead === 0) break;\n\n\t\t\tpending += decoder.write(buffer.subarray(0, bytesRead));\n\t\t\tlet lineStart = 0;\n\t\t\tlet newlineIndex = pending.indexOf(\"\\n\", lineStart);\n\t\t\twhile (newlineIndex !== -1) {\n\t\t\t\tconst entry = parseSessionEntryLine(pending.slice(lineStart, newlineIndex));\n\t\t\t\tif (entry) entries.push(entry);\n\t\t\t\tlineStart = newlineIndex + 1;\n\t\t\t\tnewlineIndex = pending.indexOf(\"\\n\", lineStart);\n\t\t\t}\n\t\t\tpending = pending.slice(lineStart);\n\t\t}\n\n\t\tpending += decoder.end();\n\t\tconst finalEntry = parseSessionEntryLine(pending);\n\t\tif (finalEntry) entries.push(finalEntry);\n\t} finally {\n\t\tcloseSync(fd);\n\t}\n\n\tif (entries.length === 0) return entries;\n\tconst header = entries[0];\n\tif (header.type !== \"session\" || typeof (header as Partial<SessionHeader>).id !== \"string\") {\n\t\treturn [];\n\t}\n\n\treturn entries;\n}\n\nexport function append(filePath: string, entry: FileEntry): void {\n\tappendFileSync(filePath, `${JSON.stringify(entry)}\\n`);\n}\n\nexport function rewrite(filePath: string, entries: FileEntry[]): void {\n\tconst content = `${entries.map((entry) => JSON.stringify(entry)).join(\"\\n\")}\\n`;\n\twriteFileSync(filePath, content);\n}\n\nexport function forkSession(sessionDir: string, header: SessionHeader, sourceEntries: FileEntry[]): string {\n\tconst reference = prepareSessionReference(sessionDir, header.id, header.timestamp);\n\tappend(reference, header);\n\tfor (const entry of sourceEntries) {\n\t\tif (entry.type !== \"session\") {\n\t\t\tappend(reference, entry);\n\t\t}\n\t}\n\treturn reference;\n}\n\nexport function findMostRecent(sessionDir: string, cwd?: string): string | null {\n\tconst resolvedCwd = cwd ? resolve(cwd) : undefined;\n\ttry {\n\t\tconst files = readdirSync(sessionDir)\n\t\t\t.filter((file) => file.endsWith(\".jsonl\"))\n\t\t\t.map((file) => join(sessionDir, file))\n\t\t\t.map((path) => ({ path, header: readSessionHeader(path) }))\n\t\t\t.filter(\n\t\t\t\t(file): file is { path: string; header: SessionHeader } =>\n\t\t\t\t\tfile.header !== null && (!resolvedCwd || sessionCwdMatches(file.header.cwd, resolvedCwd)),\n\t\t\t)\n\t\t\t.map(({ path }) => ({ path, mtime: statSync(path).mtime }))\n\t\t\t.sort((a, b) => b.mtime.getTime() - a.mtime.getTime());\n\n\t\treturn files[0]?.path || null;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nexport async function list(dir: string, onProgress?: SessionListProgress): Promise<SessionInfo[]> {\n\tconst sessions: SessionInfo[] = [];\n\tif (!existsSync(dir)) {\n\t\treturn sessions;\n\t}\n\n\ttry {\n\t\tconst dirEntries = await readdir(dir);\n\t\tconst files = dirEntries.filter((file) => file.endsWith(\".jsonl\")).map((file) => join(dir, file));\n\t\tlet loaded = 0;\n\t\tconst results = await buildSessionInfosWithConcurrency(files, () => {\n\t\t\tloaded++;\n\t\t\tonProgress?.(loaded, files.length);\n\t\t});\n\t\tfor (const info of results) {\n\t\t\tif (info) {\n\t\t\t\tsessions.push(info);\n\t\t\t}\n\t\t}\n\t} catch {\n\t\t// Return empty list on error\n\t}\n\n\treturn sessions;\n}\n\nexport async function listAll(sessionsDir: string, onProgress?: SessionListProgress): Promise<SessionInfo[]> {\n\ttry {\n\t\tif (!existsSync(sessionsDir)) {\n\t\t\treturn [];\n\t\t}\n\t\tconst entries = await readdir(sessionsDir, { withFileTypes: true });\n\t\tconst dirs = entries.filter((entry) => entry.isDirectory()).map((entry) => join(sessionsDir, entry.name));\n\n\t\tlet totalFiles = 0;\n\t\tconst dirFiles: string[][] = [];\n\t\tfor (const dir of dirs) {\n\t\t\ttry {\n\t\t\t\tconst files = (await readdir(dir)).filter((file) => file.endsWith(\".jsonl\"));\n\t\t\t\tdirFiles.push(files.map((file) => join(dir, file)));\n\t\t\t\ttotalFiles += files.length;\n\t\t\t} catch {\n\t\t\t\tdirFiles.push([]);\n\t\t\t}\n\t\t}\n\n\t\tlet loaded = 0;\n\t\tconst sessions: SessionInfo[] = [];\n\t\tconst allFiles = dirFiles.flat();\n\t\tconst results = await buildSessionInfosWithConcurrency(allFiles, () => {\n\t\t\tloaded++;\n\t\t\tonProgress?.(loaded, totalFiles);\n\t\t});\n\n\t\tfor (const info of results) {\n\t\t\tif (info) {\n\t\t\t\tsessions.push(info);\n\t\t\t}\n\t\t}\n\n\t\treturn sessions;\n\t} catch {\n\t\treturn [];\n\t}\n}\n\nasync function buildSessionInfosWithConcurrency(\n\tfiles: string[],\n\tonLoaded: () => void,\n): Promise<(SessionInfo | null)[]> {\n\tconst results: (SessionInfo | null)[] = new Array(files.length).fill(null);\n\tconst inFlight = new Set<Promise<void>>();\n\tlet nextIndex = 0;\n\n\tconst startNext = (): void => {\n\t\tconst index = nextIndex++;\n\t\tconst file = files[index];\n\t\tif (!file) return;\n\n\t\tlet task: Promise<void>;\n\t\ttask = buildSessionInfo(file)\n\t\t\t.then((info) => {\n\t\t\t\tresults[index] = info;\n\t\t\t})\n\t\t\t.catch(() => {\n\t\t\t\tresults[index] = null;\n\t\t\t})\n\t\t\t.finally(() => {\n\t\t\t\tinFlight.delete(task);\n\t\t\t\tonLoaded();\n\t\t\t});\n\t\tinFlight.add(task);\n\t};\n\n\twhile (nextIndex < files.length || inFlight.size > 0) {\n\t\twhile (nextIndex < files.length && inFlight.size < MAX_CONCURRENT_SESSION_INFO_LOADS) {\n\t\t\tstartNext();\n\t\t}\n\t\tif (inFlight.size > 0) {\n\t\t\tawait Promise.race(inFlight);\n\t\t}\n\t}\n\n\treturn results;\n}\n\nexport class JsonlSessionStore extends InMemorySessionStore {\n\tprivate reference: string | undefined;\n\tprivate flushed = false;\n\n\tisPersisted(): boolean {\n\t\treturn true;\n\t}\n\n\tgetSessionReference(): string | undefined {\n\t\treturn this.reference;\n\t}\n\n\tsetSessionReference(reference: string): void {\n\t\tthis.reference = resolve(reference);\n\t\tthis.flushed = false;\n\t}\n\n\texists(path: string): boolean {\n\t\treturn exists(path);\n\t}\n\n\tensureDir(path: string): void {\n\t\tensureDir(path);\n\t}\n\n\tload(filePath: string): FileEntry[] {\n\t\tif (!exists(filePath)) return [];\n\t\tthis.flushed = true;\n\t\treturn load(filePath);\n\t}\n\n\tappendEntry(entry: SessionEntry): void {\n\t\tsuper.appendEntry(entry);\n\t\tthis.persistAppendedEntry(entry);\n\t}\n\n\tprivate persistAppendedEntry(entry: SessionEntry): void {\n\t\tif (!this.reference) return;\n\n\t\tif (!this.hasAssistantMessage()) {\n\t\t\tthis.flushed = false;\n\t\t\treturn;\n\t\t}\n\n\t\tif (!this.flushed) {\n\t\t\tfor (const fileEntry of this.getFileEntries()) {\n\t\t\t\tappend(this.reference, fileEntry);\n\t\t\t}\n\t\t\tthis.flushed = true;\n\t\t} else {\n\t\t\tappend(this.reference, entry);\n\t\t}\n\t}\n\n\tsaveSnapshot(): void {\n\t\tif (!this.reference) return;\n\t\trewrite(this.reference, this.getFileEntries());\n\t\tthis.flushed = true;\n\t}\n\n\tcommitSnapshot(): void {\n\t\tif (!this.hasAssistantMessage()) {\n\t\t\tthis.flushed = false;\n\t\t\treturn;\n\t\t}\n\t\tthis.saveSnapshot();\n\t}\n}\n"]}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import { appendFileSync, closeSync, existsSync, mkdirSync, openSync, readdirSync,
|
|
2
|
-
import { readdir,
|
|
1
|
+
import { appendFileSync, closeSync, createReadStream, existsSync, mkdirSync, openSync, readdirSync, readSync, statSync, writeFileSync, } from "fs";
|
|
2
|
+
import { readdir, stat } from "fs/promises";
|
|
3
3
|
import { join, resolve } from "path";
|
|
4
|
+
import { createInterface } from "readline";
|
|
5
|
+
import { StringDecoder } from "string_decoder";
|
|
4
6
|
import { getAgentDir as getDefaultAgentDir, getSessionsDir } from "../../../config.js";
|
|
5
7
|
import { InMemorySessionStore } from "./in-memory-session-store.js";
|
|
6
8
|
function isMessageWithContent(message) {
|
|
@@ -16,40 +18,30 @@ function extractTextContent(message) {
|
|
|
16
18
|
.map((block) => block.text)
|
|
17
19
|
.join(" ");
|
|
18
20
|
}
|
|
19
|
-
function
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
continue;
|
|
29
|
-
const msgTimestamp = message.timestamp;
|
|
30
|
-
if (typeof msgTimestamp === "number") {
|
|
31
|
-
lastActivityTime = Math.max(lastActivityTime ?? 0, msgTimestamp);
|
|
32
|
-
continue;
|
|
33
|
-
}
|
|
34
|
-
const entryTimestamp = entry.timestamp;
|
|
35
|
-
if (typeof entryTimestamp === "string") {
|
|
36
|
-
const t = new Date(entryTimestamp).getTime();
|
|
37
|
-
if (!Number.isNaN(t)) {
|
|
38
|
-
lastActivityTime = Math.max(lastActivityTime ?? 0, t);
|
|
39
|
-
}
|
|
40
|
-
}
|
|
21
|
+
function getMessageActivityTime(entry) {
|
|
22
|
+
const message = entry.message;
|
|
23
|
+
if (!isMessageWithContent(message))
|
|
24
|
+
return undefined;
|
|
25
|
+
if (message.role !== "user" && message.role !== "assistant")
|
|
26
|
+
return undefined;
|
|
27
|
+
const msgTimestamp = message.timestamp;
|
|
28
|
+
if (typeof msgTimestamp === "number") {
|
|
29
|
+
return msgTimestamp;
|
|
41
30
|
}
|
|
42
|
-
|
|
31
|
+
const t = new Date(entry.timestamp).getTime();
|
|
32
|
+
return Number.isNaN(t) ? undefined : t;
|
|
43
33
|
}
|
|
44
|
-
function
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
34
|
+
function parseSessionEntryLine(line) {
|
|
35
|
+
if (!line.trim())
|
|
36
|
+
return null;
|
|
37
|
+
try {
|
|
38
|
+
return JSON.parse(line);
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
return null;
|
|
48
42
|
}
|
|
49
|
-
const headerTime = typeof header.timestamp === "string" ? new Date(header.timestamp).getTime() : NaN;
|
|
50
|
-
return !Number.isNaN(headerTime) ? new Date(headerTime) : statsMtime;
|
|
51
43
|
}
|
|
52
|
-
function
|
|
44
|
+
function readSessionHeader(filePath) {
|
|
53
45
|
try {
|
|
54
46
|
const fd = openSync(filePath, "r");
|
|
55
47
|
const buffer = Buffer.alloc(512);
|
|
@@ -57,47 +49,53 @@ function isValidSessionFile(filePath) {
|
|
|
57
49
|
closeSync(fd);
|
|
58
50
|
const firstLine = buffer.toString("utf8", 0, bytesRead).split("\n")[0];
|
|
59
51
|
if (!firstLine)
|
|
60
|
-
return
|
|
52
|
+
return null;
|
|
61
53
|
const header = JSON.parse(firstLine);
|
|
62
|
-
|
|
54
|
+
if (header.type !== "session" || typeof header.id !== "string") {
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
return header;
|
|
63
58
|
}
|
|
64
59
|
catch {
|
|
65
|
-
return
|
|
60
|
+
return null;
|
|
66
61
|
}
|
|
67
62
|
}
|
|
63
|
+
function sessionCwdMatches(cwd, resolvedCwd) {
|
|
64
|
+
return cwd !== undefined && cwd !== "" && resolve(cwd) === resolvedCwd;
|
|
65
|
+
}
|
|
68
66
|
async function buildSessionInfo(filePath) {
|
|
69
67
|
try {
|
|
70
|
-
const content = await readFile(filePath, "utf8");
|
|
71
|
-
const entries = [];
|
|
72
|
-
const lines = content.trim().split("\n");
|
|
73
|
-
for (const line of lines) {
|
|
74
|
-
if (!line.trim())
|
|
75
|
-
continue;
|
|
76
|
-
try {
|
|
77
|
-
entries.push(JSON.parse(line));
|
|
78
|
-
}
|
|
79
|
-
catch {
|
|
80
|
-
// Skip malformed lines
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
if (entries.length === 0)
|
|
84
|
-
return null;
|
|
85
|
-
const header = entries[0];
|
|
86
|
-
if (header.type !== "session")
|
|
87
|
-
return null;
|
|
88
68
|
const stats = await stat(filePath);
|
|
69
|
+
let header = null;
|
|
89
70
|
let messageCount = 0;
|
|
90
71
|
let firstMessage = "";
|
|
91
72
|
const allMessages = [];
|
|
92
73
|
let name;
|
|
93
|
-
|
|
74
|
+
let lastActivityTime;
|
|
75
|
+
const rl = createInterface({
|
|
76
|
+
input: createReadStream(filePath, { encoding: "utf8" }),
|
|
77
|
+
crlfDelay: Infinity,
|
|
78
|
+
});
|
|
79
|
+
for await (const line of rl) {
|
|
80
|
+
const entry = parseSessionEntryLine(line);
|
|
81
|
+
if (!entry)
|
|
82
|
+
continue;
|
|
83
|
+
if (!header) {
|
|
84
|
+
if (entry.type !== "session")
|
|
85
|
+
return null;
|
|
86
|
+
header = entry;
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
94
89
|
if (entry.type === "session_info") {
|
|
95
|
-
|
|
96
|
-
name = infoEntry.name?.trim() || undefined;
|
|
90
|
+
name = entry.name?.trim() || undefined;
|
|
97
91
|
}
|
|
98
92
|
if (entry.type !== "message")
|
|
99
93
|
continue;
|
|
100
94
|
messageCount++;
|
|
95
|
+
const activityTime = getMessageActivityTime(entry);
|
|
96
|
+
if (typeof activityTime === "number") {
|
|
97
|
+
lastActivityTime = Math.max(lastActivityTime ?? 0, activityTime);
|
|
98
|
+
}
|
|
101
99
|
const message = entry.message;
|
|
102
100
|
if (!isMessageWithContent(message))
|
|
103
101
|
continue;
|
|
@@ -111,18 +109,24 @@ async function buildSessionInfo(filePath) {
|
|
|
111
109
|
firstMessage = textContent;
|
|
112
110
|
}
|
|
113
111
|
}
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
const
|
|
117
|
-
const
|
|
112
|
+
if (!header)
|
|
113
|
+
return null;
|
|
114
|
+
const cwd = typeof header.cwd === "string" ? header.cwd : "";
|
|
115
|
+
const parentSessionPath = header.parentSession;
|
|
116
|
+
const headerTime = typeof header.timestamp === "string" ? new Date(header.timestamp).getTime() : NaN;
|
|
117
|
+
const modified = typeof lastActivityTime === "number" && lastActivityTime > 0
|
|
118
|
+
? new Date(lastActivityTime)
|
|
119
|
+
: !Number.isNaN(headerTime)
|
|
120
|
+
? new Date(headerTime)
|
|
121
|
+
: stats.mtime;
|
|
118
122
|
return {
|
|
119
123
|
reference: filePath,
|
|
120
124
|
path: filePath,
|
|
121
|
-
id:
|
|
125
|
+
id: header.id,
|
|
122
126
|
cwd,
|
|
123
127
|
name,
|
|
124
128
|
parentSessionPath,
|
|
125
|
-
created: new Date(
|
|
129
|
+
created: new Date(header.timestamp),
|
|
126
130
|
modified,
|
|
127
131
|
messageCount,
|
|
128
132
|
firstMessage: firstMessage || "(no messages)",
|
|
@@ -137,9 +141,13 @@ const MAX_CONCURRENT_SESSION_INFO_LOADS = 10;
|
|
|
137
141
|
export function getSessionDirForReference(reference) {
|
|
138
142
|
return resolve(reference, "..");
|
|
139
143
|
}
|
|
144
|
+
export function getDefaultSessionDirPath(cwd, agentDir = getDefaultAgentDir()) {
|
|
145
|
+
const resolvedCwd = resolve(cwd);
|
|
146
|
+
const safePath = `--${resolvedCwd.replace(/^[/\\]/, "").replace(/[/\\:]/g, "-")}--`;
|
|
147
|
+
return join(resolve(agentDir), "sessions", safePath);
|
|
148
|
+
}
|
|
140
149
|
export function getDefaultSessionDir(cwd, agentDir = getDefaultAgentDir()) {
|
|
141
|
-
const
|
|
142
|
-
const sessionDir = join(agentDir, "sessions", safePath);
|
|
150
|
+
const sessionDir = getDefaultSessionDirPath(cwd, agentDir);
|
|
143
151
|
ensureDir(sessionDir);
|
|
144
152
|
return sessionDir;
|
|
145
153
|
}
|
|
@@ -158,22 +166,39 @@ export function ensureDir(path) {
|
|
|
158
166
|
mkdirSync(path, { recursive: true });
|
|
159
167
|
}
|
|
160
168
|
}
|
|
169
|
+
const SESSION_READ_BUFFER_SIZE = 1024 * 1024;
|
|
161
170
|
export function load(filePath) {
|
|
162
171
|
if (!existsSync(filePath))
|
|
163
172
|
return [];
|
|
164
|
-
const content = readFileSync(filePath, "utf8");
|
|
165
173
|
const entries = [];
|
|
166
|
-
const
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
174
|
+
const fd = openSync(filePath, "r");
|
|
175
|
+
try {
|
|
176
|
+
const decoder = new StringDecoder("utf8");
|
|
177
|
+
const buffer = Buffer.allocUnsafe(SESSION_READ_BUFFER_SIZE);
|
|
178
|
+
let pending = "";
|
|
179
|
+
while (true) {
|
|
180
|
+
const bytesRead = readSync(fd, buffer, 0, buffer.length, null);
|
|
181
|
+
if (bytesRead === 0)
|
|
182
|
+
break;
|
|
183
|
+
pending += decoder.write(buffer.subarray(0, bytesRead));
|
|
184
|
+
let lineStart = 0;
|
|
185
|
+
let newlineIndex = pending.indexOf("\n", lineStart);
|
|
186
|
+
while (newlineIndex !== -1) {
|
|
187
|
+
const entry = parseSessionEntryLine(pending.slice(lineStart, newlineIndex));
|
|
188
|
+
if (entry)
|
|
189
|
+
entries.push(entry);
|
|
190
|
+
lineStart = newlineIndex + 1;
|
|
191
|
+
newlineIndex = pending.indexOf("\n", lineStart);
|
|
192
|
+
}
|
|
193
|
+
pending = pending.slice(lineStart);
|
|
176
194
|
}
|
|
195
|
+
pending += decoder.end();
|
|
196
|
+
const finalEntry = parseSessionEntryLine(pending);
|
|
197
|
+
if (finalEntry)
|
|
198
|
+
entries.push(finalEntry);
|
|
199
|
+
}
|
|
200
|
+
finally {
|
|
201
|
+
closeSync(fd);
|
|
177
202
|
}
|
|
178
203
|
if (entries.length === 0)
|
|
179
204
|
return entries;
|
|
@@ -200,13 +225,15 @@ export function forkSession(sessionDir, header, sourceEntries) {
|
|
|
200
225
|
}
|
|
201
226
|
return reference;
|
|
202
227
|
}
|
|
203
|
-
export function findMostRecent(sessionDir) {
|
|
228
|
+
export function findMostRecent(sessionDir, cwd) {
|
|
229
|
+
const resolvedCwd = cwd ? resolve(cwd) : undefined;
|
|
204
230
|
try {
|
|
205
231
|
const files = readdirSync(sessionDir)
|
|
206
232
|
.filter((file) => file.endsWith(".jsonl"))
|
|
207
233
|
.map((file) => join(sessionDir, file))
|
|
208
|
-
.
|
|
209
|
-
.
|
|
234
|
+
.map((path) => ({ path, header: readSessionHeader(path) }))
|
|
235
|
+
.filter((file) => file.header !== null && (!resolvedCwd || sessionCwdMatches(file.header.cwd, resolvedCwd)))
|
|
236
|
+
.map(({ path }) => ({ path, mtime: statSync(path).mtime }))
|
|
210
237
|
.sort((a, b) => b.mtime.getTime() - a.mtime.getTime());
|
|
211
238
|
return files[0]?.path || null;
|
|
212
239
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"jsonl-session-store.js","sourceRoot":"","sources":["../../../../src/core/session/stores/jsonl-session-store.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AgentMessage } from \"@fleetagent/pi-agent-core\";\nimport type { Message, TextContent } from \"@fleetagent/pi-ai\";\nimport {\n\tappendFileSync,\n\tcloseSync,\n\texistsSync,\n\tmkdirSync,\n\topenSync,\n\treaddirSync,\n\treadFileSync,\n\treadSync,\n\tstatSync,\n\twriteFileSync,\n} from \"fs\";\nimport { readdir, readFile, stat } from \"fs/promises\";\nimport { join, resolve } from \"path\";\nimport { getAgentDir as getDefaultAgentDir, getSessionsDir } from \"../../../config.ts\";\nimport type {\n\tFileEntry,\n\tSessionEntry,\n\tSessionEntryBase,\n\tSessionHeader,\n\tSessionInfo,\n\tSessionInfoEntry,\n\tSessionListProgress,\n\tSessionMessageEntry,\n} from \"../types.ts\";\nimport { InMemorySessionStore } from \"./in-memory-session-store.ts\";\n\nfunction isMessageWithContent(message: AgentMessage): message is Message {\n\treturn typeof (message as Message).role === \"string\" && \"content\" in message;\n}\n\nfunction extractTextContent(message: Message): string {\n\tconst content = message.content;\n\tif (typeof content === \"string\") {\n\t\treturn content;\n\t}\n\treturn content\n\t\t.filter((block): block is TextContent => block.type === \"text\")\n\t\t.map((block) => block.text)\n\t\t.join(\" \");\n}\n\nfunction getLastActivityTime(entries: FileEntry[]): number | undefined {\n\tlet lastActivityTime: number | undefined;\n\n\tfor (const entry of entries) {\n\t\tif (entry.type !== \"message\") continue;\n\n\t\tconst message = (entry as SessionMessageEntry).message;\n\t\tif (!isMessageWithContent(message)) continue;\n\t\tif (message.role !== \"user\" && message.role !== \"assistant\") continue;\n\n\t\tconst msgTimestamp = (message as { timestamp?: number }).timestamp;\n\t\tif (typeof msgTimestamp === \"number\") {\n\t\t\tlastActivityTime = Math.max(lastActivityTime ?? 0, msgTimestamp);\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst entryTimestamp = (entry as SessionEntryBase).timestamp;\n\t\tif (typeof entryTimestamp === \"string\") {\n\t\t\tconst t = new Date(entryTimestamp).getTime();\n\t\t\tif (!Number.isNaN(t)) {\n\t\t\t\tlastActivityTime = Math.max(lastActivityTime ?? 0, t);\n\t\t\t}\n\t\t}\n\t}\n\n\treturn lastActivityTime;\n}\n\nfunction getSessionModifiedDate(entries: FileEntry[], header: SessionHeader, statsMtime: Date): Date {\n\tconst lastActivityTime = getLastActivityTime(entries);\n\tif (typeof lastActivityTime === \"number\" && lastActivityTime > 0) {\n\t\treturn new Date(lastActivityTime);\n\t}\n\n\tconst headerTime = typeof header.timestamp === \"string\" ? new Date(header.timestamp).getTime() : NaN;\n\treturn !Number.isNaN(headerTime) ? new Date(headerTime) : statsMtime;\n}\n\nfunction isValidSessionFile(filePath: string): boolean {\n\ttry {\n\t\tconst fd = openSync(filePath, \"r\");\n\t\tconst buffer = Buffer.alloc(512);\n\t\tconst bytesRead = readSync(fd, buffer, 0, 512, 0);\n\t\tcloseSync(fd);\n\t\tconst firstLine = buffer.toString(\"utf8\", 0, bytesRead).split(\"\\n\")[0];\n\t\tif (!firstLine) return false;\n\t\tconst header = JSON.parse(firstLine) as Partial<SessionHeader>;\n\t\treturn header.type === \"session\" && typeof header.id === \"string\";\n\t} catch {\n\t\treturn false;\n\t}\n}\n\nasync function buildSessionInfo(filePath: string): Promise<SessionInfo | null> {\n\ttry {\n\t\tconst content = await readFile(filePath, \"utf8\");\n\t\tconst entries: FileEntry[] = [];\n\t\tconst lines = content.trim().split(\"\\n\");\n\n\t\tfor (const line of lines) {\n\t\t\tif (!line.trim()) continue;\n\t\t\ttry {\n\t\t\t\tentries.push(JSON.parse(line) as FileEntry);\n\t\t\t} catch {\n\t\t\t\t// Skip malformed lines\n\t\t\t}\n\t\t}\n\n\t\tif (entries.length === 0) return null;\n\t\tconst header = entries[0];\n\t\tif (header.type !== \"session\") return null;\n\n\t\tconst stats = await stat(filePath);\n\t\tlet messageCount = 0;\n\t\tlet firstMessage = \"\";\n\t\tconst allMessages: string[] = [];\n\t\tlet name: string | undefined;\n\n\t\tfor (const entry of entries) {\n\t\t\tif (entry.type === \"session_info\") {\n\t\t\t\tconst infoEntry = entry as SessionInfoEntry;\n\t\t\t\tname = infoEntry.name?.trim() || undefined;\n\t\t\t}\n\n\t\t\tif (entry.type !== \"message\") continue;\n\t\t\tmessageCount++;\n\n\t\t\tconst message = (entry as SessionMessageEntry).message;\n\t\t\tif (!isMessageWithContent(message)) continue;\n\t\t\tif (message.role !== \"user\" && message.role !== \"assistant\") continue;\n\n\t\t\tconst textContent = extractTextContent(message);\n\t\t\tif (!textContent) continue;\n\n\t\t\tallMessages.push(textContent);\n\t\t\tif (!firstMessage && message.role === \"user\") {\n\t\t\t\tfirstMessage = textContent;\n\t\t\t}\n\t\t}\n\n\t\tconst sessionHeader = header as SessionHeader;\n\t\tconst cwd = typeof sessionHeader.cwd === \"string\" ? sessionHeader.cwd : \"\";\n\t\tconst parentSessionPath = sessionHeader.parentSession;\n\t\tconst modified = getSessionModifiedDate(entries, sessionHeader, stats.mtime);\n\n\t\treturn {\n\t\t\treference: filePath,\n\t\t\tpath: filePath,\n\t\t\tid: sessionHeader.id,\n\t\t\tcwd,\n\t\t\tname,\n\t\t\tparentSessionPath,\n\t\t\tcreated: new Date(sessionHeader.timestamp),\n\t\t\tmodified,\n\t\t\tmessageCount,\n\t\t\tfirstMessage: firstMessage || \"(no messages)\",\n\t\t\tallMessagesText: allMessages.join(\" \"),\n\t\t};\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nconst MAX_CONCURRENT_SESSION_INFO_LOADS = 10;\n\nexport function getSessionDirForReference(reference: string): string {\n\treturn resolve(reference, \"..\");\n}\n\nexport function getDefaultSessionDir(cwd: string, agentDir: string = getDefaultAgentDir()): string {\n\tconst safePath = `--${cwd.replace(/^[/\\\\]/, \"\").replace(/[/\\\\:]/g, \"-\")}--`;\n\tconst sessionDir = join(agentDir, \"sessions\", safePath);\n\tensureDir(sessionDir);\n\treturn sessionDir;\n}\n\nexport function getSessionsRoot(): string {\n\treturn getSessionsDir();\n}\n\nexport function prepareSessionReference(sessionDir: string, sessionId: string, timestamp: string): string {\n\tconst fileTimestamp = timestamp.replace(/[:.]/g, \"-\");\n\treturn join(sessionDir, `${fileTimestamp}_${sessionId}.jsonl`);\n}\n\nexport function exists(path: string): boolean {\n\treturn existsSync(path);\n}\n\nexport function ensureDir(path: string): void {\n\tif (!existsSync(path)) {\n\t\tmkdirSync(path, { recursive: true });\n\t}\n}\n\nexport function load(filePath: string): FileEntry[] {\n\tif (!existsSync(filePath)) return [];\n\n\tconst content = readFileSync(filePath, \"utf8\");\n\tconst entries: FileEntry[] = [];\n\tconst lines = content.trim().split(\"\\n\");\n\n\tfor (const line of lines) {\n\t\tif (!line.trim()) continue;\n\t\ttry {\n\t\t\tconst entry = JSON.parse(line) as FileEntry;\n\t\t\tentries.push(entry);\n\t\t} catch {\n\t\t\t// Skip malformed lines\n\t\t}\n\t}\n\n\tif (entries.length === 0) return entries;\n\tconst header = entries[0];\n\tif (header.type !== \"session\" || typeof (header as Partial<SessionHeader>).id !== \"string\") {\n\t\treturn [];\n\t}\n\n\treturn entries;\n}\n\nexport function append(filePath: string, entry: FileEntry): void {\n\tappendFileSync(filePath, `${JSON.stringify(entry)}\\n`);\n}\n\nexport function rewrite(filePath: string, entries: FileEntry[]): void {\n\tconst content = `${entries.map((entry) => JSON.stringify(entry)).join(\"\\n\")}\\n`;\n\twriteFileSync(filePath, content);\n}\n\nexport function forkSession(sessionDir: string, header: SessionHeader, sourceEntries: FileEntry[]): string {\n\tconst reference = prepareSessionReference(sessionDir, header.id, header.timestamp);\n\tappend(reference, header);\n\tfor (const entry of sourceEntries) {\n\t\tif (entry.type !== \"session\") {\n\t\t\tappend(reference, entry);\n\t\t}\n\t}\n\treturn reference;\n}\n\nexport function findMostRecent(sessionDir: string): string | null {\n\ttry {\n\t\tconst files = readdirSync(sessionDir)\n\t\t\t.filter((file) => file.endsWith(\".jsonl\"))\n\t\t\t.map((file) => join(sessionDir, file))\n\t\t\t.filter(isValidSessionFile)\n\t\t\t.map((path) => ({ path, mtime: statSync(path).mtime }))\n\t\t\t.sort((a, b) => b.mtime.getTime() - a.mtime.getTime());\n\n\t\treturn files[0]?.path || null;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nexport async function list(dir: string, onProgress?: SessionListProgress): Promise<SessionInfo[]> {\n\tconst sessions: SessionInfo[] = [];\n\tif (!existsSync(dir)) {\n\t\treturn sessions;\n\t}\n\n\ttry {\n\t\tconst dirEntries = await readdir(dir);\n\t\tconst files = dirEntries.filter((file) => file.endsWith(\".jsonl\")).map((file) => join(dir, file));\n\t\tlet loaded = 0;\n\t\tconst results = await buildSessionInfosWithConcurrency(files, () => {\n\t\t\tloaded++;\n\t\t\tonProgress?.(loaded, files.length);\n\t\t});\n\t\tfor (const info of results) {\n\t\t\tif (info) {\n\t\t\t\tsessions.push(info);\n\t\t\t}\n\t\t}\n\t} catch {\n\t\t// Return empty list on error\n\t}\n\n\treturn sessions;\n}\n\nexport async function listAll(sessionsDir: string, onProgress?: SessionListProgress): Promise<SessionInfo[]> {\n\ttry {\n\t\tif (!existsSync(sessionsDir)) {\n\t\t\treturn [];\n\t\t}\n\t\tconst entries = await readdir(sessionsDir, { withFileTypes: true });\n\t\tconst dirs = entries.filter((entry) => entry.isDirectory()).map((entry) => join(sessionsDir, entry.name));\n\n\t\tlet totalFiles = 0;\n\t\tconst dirFiles: string[][] = [];\n\t\tfor (const dir of dirs) {\n\t\t\ttry {\n\t\t\t\tconst files = (await readdir(dir)).filter((file) => file.endsWith(\".jsonl\"));\n\t\t\t\tdirFiles.push(files.map((file) => join(dir, file)));\n\t\t\t\ttotalFiles += files.length;\n\t\t\t} catch {\n\t\t\t\tdirFiles.push([]);\n\t\t\t}\n\t\t}\n\n\t\tlet loaded = 0;\n\t\tconst sessions: SessionInfo[] = [];\n\t\tconst allFiles = dirFiles.flat();\n\t\tconst results = await buildSessionInfosWithConcurrency(allFiles, () => {\n\t\t\tloaded++;\n\t\t\tonProgress?.(loaded, totalFiles);\n\t\t});\n\n\t\tfor (const info of results) {\n\t\t\tif (info) {\n\t\t\t\tsessions.push(info);\n\t\t\t}\n\t\t}\n\n\t\treturn sessions;\n\t} catch {\n\t\treturn [];\n\t}\n}\n\nasync function buildSessionInfosWithConcurrency(\n\tfiles: string[],\n\tonLoaded: () => void,\n): Promise<(SessionInfo | null)[]> {\n\tconst results: (SessionInfo | null)[] = new Array(files.length).fill(null);\n\tconst inFlight = new Set<Promise<void>>();\n\tlet nextIndex = 0;\n\n\tconst startNext = (): void => {\n\t\tconst index = nextIndex++;\n\t\tconst file = files[index];\n\t\tif (!file) return;\n\n\t\tlet task: Promise<void>;\n\t\ttask = buildSessionInfo(file)\n\t\t\t.then((info) => {\n\t\t\t\tresults[index] = info;\n\t\t\t})\n\t\t\t.catch(() => {\n\t\t\t\tresults[index] = null;\n\t\t\t})\n\t\t\t.finally(() => {\n\t\t\t\tinFlight.delete(task);\n\t\t\t\tonLoaded();\n\t\t\t});\n\t\tinFlight.add(task);\n\t};\n\n\twhile (nextIndex < files.length || inFlight.size > 0) {\n\t\twhile (nextIndex < files.length && inFlight.size < MAX_CONCURRENT_SESSION_INFO_LOADS) {\n\t\t\tstartNext();\n\t\t}\n\t\tif (inFlight.size > 0) {\n\t\t\tawait Promise.race(inFlight);\n\t\t}\n\t}\n\n\treturn results;\n}\n\nexport class JsonlSessionStore extends InMemorySessionStore {\n\tprivate reference: string | undefined;\n\tprivate flushed = false;\n\n\tisPersisted(): boolean {\n\t\treturn true;\n\t}\n\n\tgetSessionReference(): string | undefined {\n\t\treturn this.reference;\n\t}\n\n\tsetSessionReference(reference: string): void {\n\t\tthis.reference = resolve(reference);\n\t\tthis.flushed = false;\n\t}\n\n\texists(path: string): boolean {\n\t\treturn exists(path);\n\t}\n\n\tensureDir(path: string): void {\n\t\tensureDir(path);\n\t}\n\n\tload(filePath: string): FileEntry[] {\n\t\tif (!exists(filePath)) return [];\n\t\tthis.flushed = true;\n\t\treturn load(filePath);\n\t}\n\n\tappendEntry(entry: SessionEntry): void {\n\t\tsuper.appendEntry(entry);\n\t\tthis.persistAppendedEntry(entry);\n\t}\n\n\tprivate persistAppendedEntry(entry: SessionEntry): void {\n\t\tif (!this.reference) return;\n\n\t\tif (!this.hasAssistantMessage()) {\n\t\t\tthis.flushed = false;\n\t\t\treturn;\n\t\t}\n\n\t\tif (!this.flushed) {\n\t\t\tfor (const fileEntry of this.getFileEntries()) {\n\t\t\t\tappend(this.reference, fileEntry);\n\t\t\t}\n\t\t\tthis.flushed = true;\n\t\t} else {\n\t\t\tappend(this.reference, entry);\n\t\t}\n\t}\n\n\tsaveSnapshot(): void {\n\t\tif (!this.reference) return;\n\t\trewrite(this.reference, this.getFileEntries());\n\t\tthis.flushed = true;\n\t}\n\n\tcommitSnapshot(): void {\n\t\tif (!this.hasAssistantMessage()) {\n\t\t\tthis.flushed = false;\n\t\t\treturn;\n\t\t}\n\t\tthis.saveSnapshot();\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"jsonl-session-store.js","sourceRoot":"","sources":["../../../../src/core/session/stores/jsonl-session-store.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AgentMessage } from \"@fleetagent/pi-agent-core\";\nimport type { Message, TextContent } from \"@fleetagent/pi-ai\";\nimport {\n\tappendFileSync,\n\tcloseSync,\n\tcreateReadStream,\n\texistsSync,\n\tmkdirSync,\n\topenSync,\n\treaddirSync,\n\treadSync,\n\tstatSync,\n\twriteFileSync,\n} from \"fs\";\nimport { readdir, stat } from \"fs/promises\";\nimport { join, resolve } from \"path\";\nimport { createInterface } from \"readline\";\nimport { StringDecoder } from \"string_decoder\";\nimport { getAgentDir as getDefaultAgentDir, getSessionsDir } from \"../../../config.ts\";\nimport type {\n\tFileEntry,\n\tSessionEntry,\n\tSessionHeader,\n\tSessionInfo,\n\tSessionListProgress,\n\tSessionMessageEntry,\n} from \"../types.ts\";\nimport { InMemorySessionStore } from \"./in-memory-session-store.ts\";\n\nfunction isMessageWithContent(message: AgentMessage): message is Message {\n\treturn typeof (message as Message).role === \"string\" && \"content\" in message;\n}\n\nfunction extractTextContent(message: Message): string {\n\tconst content = message.content;\n\tif (typeof content === \"string\") {\n\t\treturn content;\n\t}\n\treturn content\n\t\t.filter((block): block is TextContent => block.type === \"text\")\n\t\t.map((block) => block.text)\n\t\t.join(\" \");\n}\n\nfunction getMessageActivityTime(entry: SessionMessageEntry): number | undefined {\n\tconst message = entry.message;\n\tif (!isMessageWithContent(message)) return undefined;\n\tif (message.role !== \"user\" && message.role !== \"assistant\") return undefined;\n\n\tconst msgTimestamp = (message as { timestamp?: number }).timestamp;\n\tif (typeof msgTimestamp === \"number\") {\n\t\treturn msgTimestamp;\n\t}\n\n\tconst t = new Date(entry.timestamp).getTime();\n\treturn Number.isNaN(t) ? undefined : t;\n}\n\nfunction parseSessionEntryLine(line: string): FileEntry | null {\n\tif (!line.trim()) return null;\n\ttry {\n\t\treturn JSON.parse(line) as FileEntry;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nfunction readSessionHeader(filePath: string): SessionHeader | null {\n\ttry {\n\t\tconst fd = openSync(filePath, \"r\");\n\t\tconst buffer = Buffer.alloc(512);\n\t\tconst bytesRead = readSync(fd, buffer, 0, 512, 0);\n\t\tcloseSync(fd);\n\t\tconst firstLine = buffer.toString(\"utf8\", 0, bytesRead).split(\"\\n\")[0];\n\t\tif (!firstLine) return null;\n\t\tconst header = JSON.parse(firstLine) as Partial<SessionHeader>;\n\t\tif (header.type !== \"session\" || typeof header.id !== \"string\") {\n\t\t\treturn null;\n\t\t}\n\t\treturn header as SessionHeader;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nfunction sessionCwdMatches(cwd: string | undefined, resolvedCwd: string): boolean {\n\treturn cwd !== undefined && cwd !== \"\" && resolve(cwd) === resolvedCwd;\n}\n\nasync function buildSessionInfo(filePath: string): Promise<SessionInfo | null> {\n\ttry {\n\t\tconst stats = await stat(filePath);\n\t\tlet header: SessionHeader | null = null;\n\t\tlet messageCount = 0;\n\t\tlet firstMessage = \"\";\n\t\tconst allMessages: string[] = [];\n\t\tlet name: string | undefined;\n\t\tlet lastActivityTime: number | undefined;\n\n\t\tconst rl = createInterface({\n\t\t\tinput: createReadStream(filePath, { encoding: \"utf8\" }),\n\t\t\tcrlfDelay: Infinity,\n\t\t});\n\n\t\tfor await (const line of rl) {\n\t\t\tconst entry = parseSessionEntryLine(line);\n\t\t\tif (!entry) continue;\n\n\t\t\tif (!header) {\n\t\t\t\tif (entry.type !== \"session\") return null;\n\t\t\t\theader = entry;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (entry.type === \"session_info\") {\n\t\t\t\tname = entry.name?.trim() || undefined;\n\t\t\t}\n\n\t\t\tif (entry.type !== \"message\") continue;\n\t\t\tmessageCount++;\n\n\t\t\tconst activityTime = getMessageActivityTime(entry);\n\t\t\tif (typeof activityTime === \"number\") {\n\t\t\t\tlastActivityTime = Math.max(lastActivityTime ?? 0, activityTime);\n\t\t\t}\n\n\t\t\tconst message = entry.message;\n\t\t\tif (!isMessageWithContent(message)) continue;\n\t\t\tif (message.role !== \"user\" && message.role !== \"assistant\") continue;\n\n\t\t\tconst textContent = extractTextContent(message);\n\t\t\tif (!textContent) continue;\n\n\t\t\tallMessages.push(textContent);\n\t\t\tif (!firstMessage && message.role === \"user\") {\n\t\t\t\tfirstMessage = textContent;\n\t\t\t}\n\t\t}\n\n\t\tif (!header) return null;\n\n\t\tconst cwd = typeof header.cwd === \"string\" ? header.cwd : \"\";\n\t\tconst parentSessionPath = header.parentSession;\n\t\tconst headerTime = typeof header.timestamp === \"string\" ? new Date(header.timestamp).getTime() : NaN;\n\t\tconst modified =\n\t\t\ttypeof lastActivityTime === \"number\" && lastActivityTime > 0\n\t\t\t\t? new Date(lastActivityTime)\n\t\t\t\t: !Number.isNaN(headerTime)\n\t\t\t\t\t? new Date(headerTime)\n\t\t\t\t\t: stats.mtime;\n\n\t\treturn {\n\t\t\treference: filePath,\n\t\t\tpath: filePath,\n\t\t\tid: header.id,\n\t\t\tcwd,\n\t\t\tname,\n\t\t\tparentSessionPath,\n\t\t\tcreated: new Date(header.timestamp),\n\t\t\tmodified,\n\t\t\tmessageCount,\n\t\t\tfirstMessage: firstMessage || \"(no messages)\",\n\t\t\tallMessagesText: allMessages.join(\" \"),\n\t\t};\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nconst MAX_CONCURRENT_SESSION_INFO_LOADS = 10;\n\nexport function getSessionDirForReference(reference: string): string {\n\treturn resolve(reference, \"..\");\n}\n\nexport function getDefaultSessionDirPath(cwd: string, agentDir: string = getDefaultAgentDir()): string {\n\tconst resolvedCwd = resolve(cwd);\n\tconst safePath = `--${resolvedCwd.replace(/^[/\\\\]/, \"\").replace(/[/\\\\:]/g, \"-\")}--`;\n\treturn join(resolve(agentDir), \"sessions\", safePath);\n}\n\nexport function getDefaultSessionDir(cwd: string, agentDir: string = getDefaultAgentDir()): string {\n\tconst sessionDir = getDefaultSessionDirPath(cwd, agentDir);\n\tensureDir(sessionDir);\n\treturn sessionDir;\n}\n\nexport function getSessionsRoot(): string {\n\treturn getSessionsDir();\n}\n\nexport function prepareSessionReference(sessionDir: string, sessionId: string, timestamp: string): string {\n\tconst fileTimestamp = timestamp.replace(/[:.]/g, \"-\");\n\treturn join(sessionDir, `${fileTimestamp}_${sessionId}.jsonl`);\n}\n\nexport function exists(path: string): boolean {\n\treturn existsSync(path);\n}\n\nexport function ensureDir(path: string): void {\n\tif (!existsSync(path)) {\n\t\tmkdirSync(path, { recursive: true });\n\t}\n}\n\nconst SESSION_READ_BUFFER_SIZE = 1024 * 1024;\n\nexport function load(filePath: string): FileEntry[] {\n\tif (!existsSync(filePath)) return [];\n\n\tconst entries: FileEntry[] = [];\n\tconst fd = openSync(filePath, \"r\");\n\ttry {\n\t\tconst decoder = new StringDecoder(\"utf8\");\n\t\tconst buffer = Buffer.allocUnsafe(SESSION_READ_BUFFER_SIZE);\n\t\tlet pending = \"\";\n\n\t\twhile (true) {\n\t\t\tconst bytesRead = readSync(fd, buffer, 0, buffer.length, null);\n\t\t\tif (bytesRead === 0) break;\n\n\t\t\tpending += decoder.write(buffer.subarray(0, bytesRead));\n\t\t\tlet lineStart = 0;\n\t\t\tlet newlineIndex = pending.indexOf(\"\\n\", lineStart);\n\t\t\twhile (newlineIndex !== -1) {\n\t\t\t\tconst entry = parseSessionEntryLine(pending.slice(lineStart, newlineIndex));\n\t\t\t\tif (entry) entries.push(entry);\n\t\t\t\tlineStart = newlineIndex + 1;\n\t\t\t\tnewlineIndex = pending.indexOf(\"\\n\", lineStart);\n\t\t\t}\n\t\t\tpending = pending.slice(lineStart);\n\t\t}\n\n\t\tpending += decoder.end();\n\t\tconst finalEntry = parseSessionEntryLine(pending);\n\t\tif (finalEntry) entries.push(finalEntry);\n\t} finally {\n\t\tcloseSync(fd);\n\t}\n\n\tif (entries.length === 0) return entries;\n\tconst header = entries[0];\n\tif (header.type !== \"session\" || typeof (header as Partial<SessionHeader>).id !== \"string\") {\n\t\treturn [];\n\t}\n\n\treturn entries;\n}\n\nexport function append(filePath: string, entry: FileEntry): void {\n\tappendFileSync(filePath, `${JSON.stringify(entry)}\\n`);\n}\n\nexport function rewrite(filePath: string, entries: FileEntry[]): void {\n\tconst content = `${entries.map((entry) => JSON.stringify(entry)).join(\"\\n\")}\\n`;\n\twriteFileSync(filePath, content);\n}\n\nexport function forkSession(sessionDir: string, header: SessionHeader, sourceEntries: FileEntry[]): string {\n\tconst reference = prepareSessionReference(sessionDir, header.id, header.timestamp);\n\tappend(reference, header);\n\tfor (const entry of sourceEntries) {\n\t\tif (entry.type !== \"session\") {\n\t\t\tappend(reference, entry);\n\t\t}\n\t}\n\treturn reference;\n}\n\nexport function findMostRecent(sessionDir: string, cwd?: string): string | null {\n\tconst resolvedCwd = cwd ? resolve(cwd) : undefined;\n\ttry {\n\t\tconst files = readdirSync(sessionDir)\n\t\t\t.filter((file) => file.endsWith(\".jsonl\"))\n\t\t\t.map((file) => join(sessionDir, file))\n\t\t\t.map((path) => ({ path, header: readSessionHeader(path) }))\n\t\t\t.filter(\n\t\t\t\t(file): file is { path: string; header: SessionHeader } =>\n\t\t\t\t\tfile.header !== null && (!resolvedCwd || sessionCwdMatches(file.header.cwd, resolvedCwd)),\n\t\t\t)\n\t\t\t.map(({ path }) => ({ path, mtime: statSync(path).mtime }))\n\t\t\t.sort((a, b) => b.mtime.getTime() - a.mtime.getTime());\n\n\t\treturn files[0]?.path || null;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nexport async function list(dir: string, onProgress?: SessionListProgress): Promise<SessionInfo[]> {\n\tconst sessions: SessionInfo[] = [];\n\tif (!existsSync(dir)) {\n\t\treturn sessions;\n\t}\n\n\ttry {\n\t\tconst dirEntries = await readdir(dir);\n\t\tconst files = dirEntries.filter((file) => file.endsWith(\".jsonl\")).map((file) => join(dir, file));\n\t\tlet loaded = 0;\n\t\tconst results = await buildSessionInfosWithConcurrency(files, () => {\n\t\t\tloaded++;\n\t\t\tonProgress?.(loaded, files.length);\n\t\t});\n\t\tfor (const info of results) {\n\t\t\tif (info) {\n\t\t\t\tsessions.push(info);\n\t\t\t}\n\t\t}\n\t} catch {\n\t\t// Return empty list on error\n\t}\n\n\treturn sessions;\n}\n\nexport async function listAll(sessionsDir: string, onProgress?: SessionListProgress): Promise<SessionInfo[]> {\n\ttry {\n\t\tif (!existsSync(sessionsDir)) {\n\t\t\treturn [];\n\t\t}\n\t\tconst entries = await readdir(sessionsDir, { withFileTypes: true });\n\t\tconst dirs = entries.filter((entry) => entry.isDirectory()).map((entry) => join(sessionsDir, entry.name));\n\n\t\tlet totalFiles = 0;\n\t\tconst dirFiles: string[][] = [];\n\t\tfor (const dir of dirs) {\n\t\t\ttry {\n\t\t\t\tconst files = (await readdir(dir)).filter((file) => file.endsWith(\".jsonl\"));\n\t\t\t\tdirFiles.push(files.map((file) => join(dir, file)));\n\t\t\t\ttotalFiles += files.length;\n\t\t\t} catch {\n\t\t\t\tdirFiles.push([]);\n\t\t\t}\n\t\t}\n\n\t\tlet loaded = 0;\n\t\tconst sessions: SessionInfo[] = [];\n\t\tconst allFiles = dirFiles.flat();\n\t\tconst results = await buildSessionInfosWithConcurrency(allFiles, () => {\n\t\t\tloaded++;\n\t\t\tonProgress?.(loaded, totalFiles);\n\t\t});\n\n\t\tfor (const info of results) {\n\t\t\tif (info) {\n\t\t\t\tsessions.push(info);\n\t\t\t}\n\t\t}\n\n\t\treturn sessions;\n\t} catch {\n\t\treturn [];\n\t}\n}\n\nasync function buildSessionInfosWithConcurrency(\n\tfiles: string[],\n\tonLoaded: () => void,\n): Promise<(SessionInfo | null)[]> {\n\tconst results: (SessionInfo | null)[] = new Array(files.length).fill(null);\n\tconst inFlight = new Set<Promise<void>>();\n\tlet nextIndex = 0;\n\n\tconst startNext = (): void => {\n\t\tconst index = nextIndex++;\n\t\tconst file = files[index];\n\t\tif (!file) return;\n\n\t\tlet task: Promise<void>;\n\t\ttask = buildSessionInfo(file)\n\t\t\t.then((info) => {\n\t\t\t\tresults[index] = info;\n\t\t\t})\n\t\t\t.catch(() => {\n\t\t\t\tresults[index] = null;\n\t\t\t})\n\t\t\t.finally(() => {\n\t\t\t\tinFlight.delete(task);\n\t\t\t\tonLoaded();\n\t\t\t});\n\t\tinFlight.add(task);\n\t};\n\n\twhile (nextIndex < files.length || inFlight.size > 0) {\n\t\twhile (nextIndex < files.length && inFlight.size < MAX_CONCURRENT_SESSION_INFO_LOADS) {\n\t\t\tstartNext();\n\t\t}\n\t\tif (inFlight.size > 0) {\n\t\t\tawait Promise.race(inFlight);\n\t\t}\n\t}\n\n\treturn results;\n}\n\nexport class JsonlSessionStore extends InMemorySessionStore {\n\tprivate reference: string | undefined;\n\tprivate flushed = false;\n\n\tisPersisted(): boolean {\n\t\treturn true;\n\t}\n\n\tgetSessionReference(): string | undefined {\n\t\treturn this.reference;\n\t}\n\n\tsetSessionReference(reference: string): void {\n\t\tthis.reference = resolve(reference);\n\t\tthis.flushed = false;\n\t}\n\n\texists(path: string): boolean {\n\t\treturn exists(path);\n\t}\n\n\tensureDir(path: string): void {\n\t\tensureDir(path);\n\t}\n\n\tload(filePath: string): FileEntry[] {\n\t\tif (!exists(filePath)) return [];\n\t\tthis.flushed = true;\n\t\treturn load(filePath);\n\t}\n\n\tappendEntry(entry: SessionEntry): void {\n\t\tsuper.appendEntry(entry);\n\t\tthis.persistAppendedEntry(entry);\n\t}\n\n\tprivate persistAppendedEntry(entry: SessionEntry): void {\n\t\tif (!this.reference) return;\n\n\t\tif (!this.hasAssistantMessage()) {\n\t\t\tthis.flushed = false;\n\t\t\treturn;\n\t\t}\n\n\t\tif (!this.flushed) {\n\t\t\tfor (const fileEntry of this.getFileEntries()) {\n\t\t\t\tappend(this.reference, fileEntry);\n\t\t\t}\n\t\t\tthis.flushed = true;\n\t\t} else {\n\t\t\tappend(this.reference, entry);\n\t\t}\n\t}\n\n\tsaveSnapshot(): void {\n\t\tif (!this.reference) return;\n\t\trewrite(this.reference, this.getFileEntries());\n\t\tthis.flushed = true;\n\t}\n\n\tcommitSnapshot(): void {\n\t\tif (!this.hasAssistantMessage()) {\n\t\t\tthis.flushed = false;\n\t\t\treturn;\n\t\t}\n\t\tthis.saveSnapshot();\n\t}\n}\n"]}
|
|
@@ -51,6 +51,7 @@ export type PackageSource = string | {
|
|
|
51
51
|
source: string;
|
|
52
52
|
extensions?: string[];
|
|
53
53
|
skills?: string[];
|
|
54
|
+
rules?: string[];
|
|
54
55
|
prompts?: string[];
|
|
55
56
|
themes?: string[];
|
|
56
57
|
};
|
|
@@ -76,6 +77,7 @@ export interface Settings {
|
|
|
76
77
|
packages?: PackageSource[];
|
|
77
78
|
extensions?: string[];
|
|
78
79
|
skills?: string[];
|
|
80
|
+
rules?: string[];
|
|
79
81
|
prompts?: string[];
|
|
80
82
|
themes?: string[];
|
|
81
83
|
enableSkillCommands?: boolean;
|
|
@@ -92,6 +94,7 @@ export interface Settings {
|
|
|
92
94
|
warnings?: WarningSettings;
|
|
93
95
|
sessionDir?: string;
|
|
94
96
|
httpIdleTimeoutMs?: number;
|
|
97
|
+
websocketConnectTimeoutMs?: number;
|
|
95
98
|
}
|
|
96
99
|
export type SettingsScope = "global" | "project";
|
|
97
100
|
export interface SettingsStorage {
|
|
@@ -196,6 +199,7 @@ export declare class SettingsManager {
|
|
|
196
199
|
};
|
|
197
200
|
getHttpIdleTimeoutMs(): number;
|
|
198
201
|
setHttpIdleTimeoutMs(timeoutMs: number): void;
|
|
202
|
+
getWebSocketConnectTimeoutMs(): number | undefined;
|
|
199
203
|
getProviderRetrySettings(): {
|
|
200
204
|
timeoutMs?: number;
|
|
201
205
|
maxRetries?: number;
|
|
@@ -224,6 +228,9 @@ export declare class SettingsManager {
|
|
|
224
228
|
getSkillPaths(): string[];
|
|
225
229
|
setSkillPaths(paths: string[]): void;
|
|
226
230
|
setProjectSkillPaths(paths: string[]): void;
|
|
231
|
+
getRulePaths(): string[];
|
|
232
|
+
setRulePaths(paths: string[]): void;
|
|
233
|
+
setProjectRulePaths(paths: string[]): void;
|
|
227
234
|
getPromptTemplatePaths(): string[];
|
|
228
235
|
setPromptTemplatePaths(paths: string[]): void;
|
|
229
236
|
setProjectPromptTemplatePaths(paths: string[]): void;
|