@mariozechner/pi-coding-agent 0.25.2 → 0.25.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +20 -0
- package/README.md +4 -1
- package/dist/cli/args.d.ts +1 -0
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +5 -0
- package/dist/cli/args.js.map +1 -1
- package/dist/core/agent-session.d.ts +4 -1
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +5 -0
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/compaction.d.ts.map +1 -1
- package/dist/core/compaction.js +1 -1
- package/dist/core/compaction.js.map +1 -1
- package/dist/core/export-html.d.ts.map +1 -1
- package/dist/core/export-html.js +1 -1
- package/dist/core/export-html.js.map +1 -1
- package/dist/core/messages.d.ts.map +1 -1
- package/dist/core/messages.js +1 -1
- package/dist/core/messages.js.map +1 -1
- package/dist/core/model-config.d.ts.map +1 -1
- package/dist/core/model-config.js.map +1 -1
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +10 -10
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/settings-manager.d.ts +9 -0
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +13 -0
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/skills.d.ts +2 -1
- package/dist/core/skills.d.ts.map +1 -1
- package/dist/core/skills.js +41 -14
- package/dist/core/skills.js.map +1 -1
- package/dist/core/slash-commands.d.ts.map +1 -1
- package/dist/core/slash-commands.js +2 -2
- package/dist/core/slash-commands.js.map +1 -1
- package/dist/core/system-prompt.d.ts +2 -1
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js +5 -5
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/core/tools/grep.d.ts.map +1 -1
- package/dist/core/tools/grep.js +1 -1
- package/dist/core/tools/grep.js.map +1 -1
- package/dist/core/tools/read.d.ts.map +1 -1
- package/dist/core/tools/read.js +0 -1
- package/dist/core/tools/read.js.map +1 -1
- package/dist/core/tools/truncate.d.ts.map +1 -1
- package/dist/core/tools/truncate.js +1 -1
- package/dist/core/tools/truncate.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +9 -2
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/components/armin.d.ts.map +1 -1
- package/dist/modes/interactive/components/armin.js +2 -2
- package/dist/modes/interactive/components/armin.js.map +1 -1
- package/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/bash-execution.js +3 -3
- package/dist/modes/interactive/components/bash-execution.js.map +1 -1
- package/dist/modes/interactive/components/custom-editor.d.ts +2 -0
- package/dist/modes/interactive/components/custom-editor.d.ts.map +1 -1
- package/dist/modes/interactive/components/custom-editor.js +13 -1
- package/dist/modes/interactive/components/custom-editor.js.map +1 -1
- package/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/dist/modes/interactive/components/footer.js +6 -6
- package/dist/modes/interactive/components/footer.js.map +1 -1
- package/dist/modes/interactive/components/hook-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/hook-selector.js +1 -1
- package/dist/modes/interactive/components/hook-selector.js.map +1 -1
- package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/model-selector.js +2 -2
- package/dist/modes/interactive/components/model-selector.js.map +1 -1
- package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/tool-execution.js +14 -14
- package/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +2 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +80 -16
- 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 -6
- package/dist/modes/interactive/theme/theme.js.map +1 -1
- package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-client.js +1 -1
- package/dist/modes/rpc/rpc-client.js.map +1 -1
- package/dist/utils/shell.d.ts.map +1 -1
- package/dist/utils/shell.js +1 -1
- package/dist/utils/shell.js.map +1 -1
- package/docs/skills.md +53 -0
- package/package.json +4 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-manager.d.ts","sourceRoot":"","sources":["../../src/core/session-manager.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AgentState, AppMessage } from \"@mariozechner/pi-agent-core\";\nimport { randomBytes } from \"crypto\";\nimport { appendFileSync, existsSync, mkdirSync, readdirSync, readFileSync, statSync } from \"fs\";\nimport { join, resolve } from \"path\";\nimport { getAgentDir } from \"../config.js\";\n\nfunction uuidv4(): string {\n\tconst bytes = randomBytes(16);\n\tbytes[6] = (bytes[6] & 0x0f) | 0x40;\n\tbytes[8] = (bytes[8] & 0x3f) | 0x80;\n\tconst hex = bytes.toString(\"hex\");\n\treturn `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20, 32)}`;\n}\n\n// ============================================================================\n// Session entry types\n// ============================================================================\n\nexport interface SessionHeader {\n\ttype: \"session\";\n\tid: string;\n\ttimestamp: string;\n\tcwd: string;\n\tprovider: string;\n\tmodelId: string;\n\tthinkingLevel: string;\n\tbranchedFrom?: string;\n}\n\nexport interface SessionMessageEntry {\n\ttype: \"message\";\n\ttimestamp: string;\n\tmessage: AppMessage;\n}\n\nexport interface ThinkingLevelChangeEntry {\n\ttype: \"thinking_level_change\";\n\ttimestamp: string;\n\tthinkingLevel: string;\n}\n\nexport interface ModelChangeEntry {\n\ttype: \"model_change\";\n\ttimestamp: string;\n\tprovider: string;\n\tmodelId: string;\n}\n\nexport interface CompactionEntry {\n\ttype: \"compaction\";\n\ttimestamp: string;\n\tsummary: string;\n\tfirstKeptEntryIndex: number; // Index into session entries where we start keeping\n\ttokensBefore: number;\n}\n\n/** Union of all session entry types */\nexport type SessionEntry =\n\t| SessionHeader\n\t| SessionMessageEntry\n\t| ThinkingLevelChangeEntry\n\t| ModelChangeEntry\n\t| CompactionEntry;\n\n// ============================================================================\n// Session loading with compaction support\n// ============================================================================\n\nexport interface LoadedSession {\n\tmessages: AppMessage[];\n\tthinkingLevel: string;\n\tmodel: { provider: string; modelId: string } | null;\n}\n\nexport const SUMMARY_PREFIX = `The conversation history before this point was compacted into the following summary:\n\n<summary>\n`;\n\nexport const SUMMARY_SUFFIX = `\n</summary>`;\n\n/**\n * Create a user message containing the summary with the standard prefix.\n */\nexport function createSummaryMessage(summary: string): AppMessage {\n\treturn {\n\t\trole: \"user\",\n\t\tcontent: SUMMARY_PREFIX + summary + SUMMARY_SUFFIX,\n\t\ttimestamp: Date.now(),\n\t};\n}\n\n/**\n * Parse session file content into entries.\n */\nexport function parseSessionEntries(content: string): SessionEntry[] {\n\tconst entries: SessionEntry[] = [];\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 SessionEntry;\n\t\t\tentries.push(entry);\n\t\t} catch {\n\t\t\t// Skip malformed lines\n\t\t}\n\t}\n\n\treturn entries;\n}\n\n/**\n * Load session from entries, handling compaction events.\n *\n * Algorithm:\n * 1. Find latest compaction event (if any)\n * 2. Keep all entries from firstKeptEntryIndex onwards (extracting messages)\n * 3. Prepend summary as user message\n */\n/**\n * Get the latest compaction entry from session entries, if any.\n */\nexport function getLatestCompactionEntry(entries: SessionEntry[]): CompactionEntry | null {\n\tfor (let i = entries.length - 1; i >= 0; i--) {\n\t\tif (entries[i].type === \"compaction\") {\n\t\t\treturn entries[i] as CompactionEntry;\n\t\t}\n\t}\n\treturn null;\n}\n\nexport function loadSessionFromEntries(entries: SessionEntry[]): LoadedSession {\n\t// Find model and thinking level (always scan all entries)\n\tlet thinkingLevel = \"off\";\n\tlet model: { provider: string; modelId: string } | null = null;\n\n\tfor (const entry of entries) {\n\t\tif (entry.type === \"session\") {\n\t\t\tthinkingLevel = entry.thinkingLevel;\n\t\t\tmodel = { provider: entry.provider, modelId: entry.modelId };\n\t\t} else if (entry.type === \"thinking_level_change\") {\n\t\t\tthinkingLevel = entry.thinkingLevel;\n\t\t} else if (entry.type === \"model_change\") {\n\t\t\tmodel = { provider: entry.provider, modelId: entry.modelId };\n\t\t}\n\t}\n\n\t// Find latest compaction event\n\tlet latestCompactionIndex = -1;\n\tfor (let i = entries.length - 1; i >= 0; i--) {\n\t\tif (entries[i].type === \"compaction\") {\n\t\t\tlatestCompactionIndex = i;\n\t\t\tbreak;\n\t\t}\n\t}\n\n\t// No compaction: return all messages\n\tif (latestCompactionIndex === -1) {\n\t\tconst messages: AppMessage[] = [];\n\t\tfor (const entry of entries) {\n\t\t\tif (entry.type === \"message\") {\n\t\t\t\tmessages.push(entry.message);\n\t\t\t}\n\t\t}\n\t\treturn { messages, thinkingLevel, model };\n\t}\n\n\tconst compactionEvent = entries[latestCompactionIndex] as CompactionEntry;\n\n\t// Extract messages from firstKeptEntryIndex to end (skipping compaction entries)\n\tconst keptMessages: AppMessage[] = [];\n\tfor (let i = compactionEvent.firstKeptEntryIndex; i < entries.length; i++) {\n\t\tconst entry = entries[i];\n\t\tif (entry.type === \"message\") {\n\t\t\tkeptMessages.push(entry.message);\n\t\t}\n\t}\n\n\t// Build final messages: summary + kept messages\n\tconst messages: AppMessage[] = [];\n\tmessages.push(createSummaryMessage(compactionEvent.summary));\n\tmessages.push(...keptMessages);\n\n\treturn { messages, thinkingLevel, model };\n}\n\nexport class SessionManager {\n\tprivate sessionId!: string;\n\tprivate sessionFile!: string;\n\tprivate sessionDir: string;\n\tprivate enabled: boolean = true;\n\tprivate sessionInitialized: boolean = false;\n\tprivate pendingEntries: SessionEntry[] = [];\n\t// In-memory entries for --no-session mode (when enabled=false)\n\tprivate inMemoryEntries: SessionEntry[] = [];\n\n\tconstructor(continueSession: boolean = false, customSessionPath?: string) {\n\t\tthis.sessionDir = this.getSessionDirectory();\n\n\t\tif (customSessionPath) {\n\t\t\t// Use custom session file path\n\t\t\tthis.sessionFile = resolve(customSessionPath);\n\t\t\tthis.loadSessionId();\n\t\t\t// If file doesn't exist, loadSessionId() won't set sessionId, so generate one\n\t\t\tif (!this.sessionId) {\n\t\t\t\tthis.sessionId = uuidv4();\n\t\t\t}\n\t\t\t// Mark as initialized since we're loading an existing session\n\t\t\tthis.sessionInitialized = existsSync(this.sessionFile);\n\t\t\t// Load entries into memory\n\t\t\tif (this.sessionInitialized) {\n\t\t\t\tthis.inMemoryEntries = this.loadEntriesFromFile();\n\t\t\t}\n\t\t} else if (continueSession) {\n\t\t\tconst mostRecent = this.findMostRecentlyModifiedSession();\n\t\t\tif (mostRecent) {\n\t\t\t\tthis.sessionFile = mostRecent;\n\t\t\t\tthis.loadSessionId();\n\t\t\t\t// Mark as initialized since we're loading an existing session\n\t\t\t\tthis.sessionInitialized = true;\n\t\t\t\t// Load entries into memory\n\t\t\t\tthis.inMemoryEntries = this.loadEntriesFromFile();\n\t\t\t} else {\n\t\t\t\tthis.initNewSession();\n\t\t\t}\n\t\t} else {\n\t\t\tthis.initNewSession();\n\t\t}\n\t}\n\n\t/** Disable session saving (for --no-session mode) */\n\tdisable() {\n\t\tthis.enabled = false;\n\t}\n\n\t/** Check if session persistence is enabled */\n\tisEnabled(): boolean {\n\t\treturn this.enabled;\n\t}\n\n\tprivate getSessionDirectory(): string {\n\t\tconst cwd = process.cwd();\n\t\t// Replace all path separators and colons (for Windows drive letters) with dashes\n\t\tconst safePath = \"--\" + cwd.replace(/^[/\\\\]/, \"\").replace(/[/\\\\:]/g, \"-\") + \"--\";\n\n\t\tconst configDir = getAgentDir();\n\t\tconst sessionDir = join(configDir, \"sessions\", safePath);\n\t\tif (!existsSync(sessionDir)) {\n\t\t\tmkdirSync(sessionDir, { recursive: true });\n\t\t}\n\t\treturn sessionDir;\n\t}\n\n\tprivate initNewSession(): void {\n\t\tthis.sessionId = uuidv4();\n\t\tconst timestamp = new Date().toISOString().replace(/[:.]/g, \"-\");\n\t\tthis.sessionFile = join(this.sessionDir, `${timestamp}_${this.sessionId}.jsonl`);\n\t}\n\n\t/** Reset to a fresh session. Clears pending entries and starts a new session file. */\n\treset(): void {\n\t\tthis.pendingEntries = [];\n\t\tthis.inMemoryEntries = [];\n\t\tthis.sessionInitialized = false;\n\t\tthis.initNewSession();\n\t}\n\n\tprivate findMostRecentlyModifiedSession(): string | null {\n\t\ttry {\n\t\t\tconst files = readdirSync(this.sessionDir)\n\t\t\t\t.filter((f) => f.endsWith(\".jsonl\"))\n\t\t\t\t.map((f) => ({\n\t\t\t\t\tname: f,\n\t\t\t\t\tpath: join(this.sessionDir, f),\n\t\t\t\t\tmtime: statSync(join(this.sessionDir, f)).mtime,\n\t\t\t\t}))\n\t\t\t\t.sort((a, b) => b.mtime.getTime() - a.mtime.getTime());\n\n\t\t\treturn files[0]?.path || null;\n\t\t} catch {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\tprivate loadSessionId(): void {\n\t\tif (!existsSync(this.sessionFile)) return;\n\n\t\tconst lines = readFileSync(this.sessionFile, \"utf8\").trim().split(\"\\n\");\n\t\tfor (const line of lines) {\n\t\t\ttry {\n\t\t\t\tconst entry = JSON.parse(line);\n\t\t\t\tif (entry.type === \"session\") {\n\t\t\t\t\tthis.sessionId = entry.id;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\t// Skip malformed lines\n\t\t\t}\n\t\t}\n\t\tthis.sessionId = uuidv4();\n\t}\n\n\tstartSession(state: AgentState): void {\n\t\tif (this.sessionInitialized) return;\n\t\tthis.sessionInitialized = true;\n\n\t\tconst entry: SessionHeader = {\n\t\t\ttype: \"session\",\n\t\t\tid: this.sessionId,\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tcwd: process.cwd(),\n\t\t\tprovider: state.model.provider,\n\t\t\tmodelId: state.model.id,\n\t\t\tthinkingLevel: state.thinkingLevel,\n\t\t};\n\n\t\t// Always track in memory\n\t\tthis.inMemoryEntries.push(entry);\n\t\tfor (const pending of this.pendingEntries) {\n\t\t\tthis.inMemoryEntries.push(pending);\n\t\t}\n\t\tthis.pendingEntries = [];\n\n\t\t// Write to file only if enabled\n\t\tif (this.enabled) {\n\t\t\tappendFileSync(this.sessionFile, JSON.stringify(entry) + \"\\n\");\n\t\t\tfor (const memEntry of this.inMemoryEntries.slice(1)) {\n\t\t\t\tappendFileSync(this.sessionFile, JSON.stringify(memEntry) + \"\\n\");\n\t\t\t}\n\t\t}\n\t}\n\n\tsaveMessage(message: any): void {\n\t\tconst entry: SessionMessageEntry = {\n\t\t\ttype: \"message\",\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tmessage,\n\t\t};\n\n\t\tif (!this.sessionInitialized) {\n\t\t\tthis.pendingEntries.push(entry);\n\t\t} else {\n\t\t\t// Always track in memory\n\t\t\tthis.inMemoryEntries.push(entry);\n\t\t\t// Write to file only if enabled\n\t\t\tif (this.enabled) {\n\t\t\t\tappendFileSync(this.sessionFile, JSON.stringify(entry) + \"\\n\");\n\t\t\t}\n\t\t}\n\t}\n\n\tsaveThinkingLevelChange(thinkingLevel: string): void {\n\t\tconst entry: ThinkingLevelChangeEntry = {\n\t\t\ttype: \"thinking_level_change\",\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tthinkingLevel,\n\t\t};\n\n\t\tif (!this.sessionInitialized) {\n\t\t\tthis.pendingEntries.push(entry);\n\t\t} else {\n\t\t\t// Always track in memory\n\t\t\tthis.inMemoryEntries.push(entry);\n\t\t\t// Write to file only if enabled\n\t\t\tif (this.enabled) {\n\t\t\t\tappendFileSync(this.sessionFile, JSON.stringify(entry) + \"\\n\");\n\t\t\t}\n\t\t}\n\t}\n\n\tsaveModelChange(provider: string, modelId: string): void {\n\t\tconst entry: ModelChangeEntry = {\n\t\t\ttype: \"model_change\",\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tprovider,\n\t\t\tmodelId,\n\t\t};\n\n\t\tif (!this.sessionInitialized) {\n\t\t\tthis.pendingEntries.push(entry);\n\t\t} else {\n\t\t\t// Always track in memory\n\t\t\tthis.inMemoryEntries.push(entry);\n\t\t\t// Write to file only if enabled\n\t\t\tif (this.enabled) {\n\t\t\t\tappendFileSync(this.sessionFile, JSON.stringify(entry) + \"\\n\");\n\t\t\t}\n\t\t}\n\t}\n\n\tsaveCompaction(entry: CompactionEntry): void {\n\t\t// Always track in memory\n\t\tthis.inMemoryEntries.push(entry);\n\t\t// Write to file only if enabled\n\t\tif (this.enabled) {\n\t\t\tappendFileSync(this.sessionFile, JSON.stringify(entry) + \"\\n\");\n\t\t}\n\t}\n\n\t/**\n\t * Load session data (messages, model, thinking level) with compaction support.\n\t */\n\tloadSession(): LoadedSession {\n\t\tconst entries = this.loadEntries();\n\t\treturn loadSessionFromEntries(entries);\n\t}\n\n\t/**\n\t * @deprecated Use loadSession().messages instead\n\t */\n\tloadMessages(): AppMessage[] {\n\t\treturn this.loadSession().messages;\n\t}\n\n\t/**\n\t * @deprecated Use loadSession().thinkingLevel instead\n\t */\n\tloadThinkingLevel(): string {\n\t\treturn this.loadSession().thinkingLevel;\n\t}\n\n\t/**\n\t * @deprecated Use loadSession().model instead\n\t */\n\tloadModel(): { provider: string; modelId: string } | null {\n\t\treturn this.loadSession().model;\n\t}\n\n\tgetSessionId(): string {\n\t\treturn this.sessionId;\n\t}\n\n\tgetSessionFile(): string {\n\t\treturn this.sessionFile;\n\t}\n\n\t/**\n\t * Load entries directly from the session file (internal helper).\n\t */\n\tprivate loadEntriesFromFile(): SessionEntry[] {\n\t\tif (!existsSync(this.sessionFile)) return [];\n\n\t\tconst content = readFileSync(this.sessionFile, \"utf8\");\n\t\tconst entries: SessionEntry[] = [];\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\tconst entry = JSON.parse(line) as SessionEntry;\n\t\t\t\tentries.push(entry);\n\t\t\t} catch {\n\t\t\t\t// Skip malformed lines\n\t\t\t}\n\t\t}\n\n\t\treturn entries;\n\t}\n\n\t/**\n\t * Load all entries from the session file or in-memory store.\n\t * When file persistence is enabled, reads from file (source of truth for resumed sessions).\n\t * When disabled (--no-session), returns in-memory entries.\n\t */\n\tloadEntries(): SessionEntry[] {\n\t\t// If file persistence is enabled and file exists, read from file\n\t\tif (this.enabled && existsSync(this.sessionFile)) {\n\t\t\treturn this.loadEntriesFromFile();\n\t\t}\n\n\t\t// Otherwise return in-memory entries (for --no-session mode)\n\t\treturn [...this.inMemoryEntries];\n\t}\n\n\t/**\n\t * Load all sessions for the current directory with metadata\n\t */\n\tloadAllSessions(): Array<{\n\t\tpath: string;\n\t\tid: string;\n\t\tcreated: Date;\n\t\tmodified: Date;\n\t\tmessageCount: number;\n\t\tfirstMessage: string;\n\t\tallMessagesText: string;\n\t}> {\n\t\tconst sessions: Array<{\n\t\t\tpath: string;\n\t\t\tid: string;\n\t\t\tcreated: Date;\n\t\t\tmodified: Date;\n\t\t\tmessageCount: number;\n\t\t\tfirstMessage: string;\n\t\t\tallMessagesText: string;\n\t\t}> = [];\n\n\t\ttry {\n\t\t\tconst files = readdirSync(this.sessionDir)\n\t\t\t\t.filter((f) => f.endsWith(\".jsonl\"))\n\t\t\t\t.map((f) => join(this.sessionDir, f));\n\n\t\t\tfor (const file of files) {\n\t\t\t\ttry {\n\t\t\t\t\tconst stats = statSync(file);\n\t\t\t\t\tconst content = readFileSync(file, \"utf8\");\n\t\t\t\t\tconst lines = content.trim().split(\"\\n\");\n\n\t\t\t\t\tlet sessionId = \"\";\n\t\t\t\t\tlet created = stats.birthtime;\n\t\t\t\t\tlet messageCount = 0;\n\t\t\t\t\tlet firstMessage = \"\";\n\t\t\t\t\tconst allMessages: string[] = [];\n\n\t\t\t\t\tfor (const line of lines) {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst entry = JSON.parse(line);\n\n\t\t\t\t\t\t\t// Extract session ID from first session entry\n\t\t\t\t\t\t\tif (entry.type === \"session\" && !sessionId) {\n\t\t\t\t\t\t\t\tsessionId = entry.id;\n\t\t\t\t\t\t\t\tcreated = new Date(entry.timestamp);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// Count messages and collect all text\n\t\t\t\t\t\t\tif (entry.type === \"message\") {\n\t\t\t\t\t\t\t\tmessageCount++;\n\n\t\t\t\t\t\t\t\t// Extract text from user and assistant messages\n\t\t\t\t\t\t\t\tif (entry.message.role === \"user\" || entry.message.role === \"assistant\") {\n\t\t\t\t\t\t\t\t\tconst textContent = entry.message.content\n\t\t\t\t\t\t\t\t\t\t.filter((c: any) => c.type === \"text\")\n\t\t\t\t\t\t\t\t\t\t.map((c: any) => c.text)\n\t\t\t\t\t\t\t\t\t\t.join(\" \");\n\n\t\t\t\t\t\t\t\t\tif (textContent) {\n\t\t\t\t\t\t\t\t\t\tallMessages.push(textContent);\n\n\t\t\t\t\t\t\t\t\t\t// Get first user message for display\n\t\t\t\t\t\t\t\t\t\tif (!firstMessage && entry.message.role === \"user\") {\n\t\t\t\t\t\t\t\t\t\t\tfirstMessage = textContent;\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t// Skip malformed lines\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tsessions.push({\n\t\t\t\t\t\tpath: file,\n\t\t\t\t\t\tid: sessionId || \"unknown\",\n\t\t\t\t\t\tcreated,\n\t\t\t\t\t\tmodified: stats.mtime,\n\t\t\t\t\t\tmessageCount,\n\t\t\t\t\t\tfirstMessage: firstMessage || \"(no messages)\",\n\t\t\t\t\t\tallMessagesText: allMessages.join(\" \"),\n\t\t\t\t\t});\n\t\t\t\t} catch (error) {\n\t\t\t\t\t// Skip files that can't be read\n\t\t\t\t\tconsole.error(`Failed to read session file ${file}:`, error);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Sort by modified date (most recent first)\n\t\t\tsessions.sort((a, b) => b.modified.getTime() - a.modified.getTime());\n\t\t} catch (error) {\n\t\t\tconsole.error(\"Failed to load sessions:\", error);\n\t\t}\n\n\t\treturn sessions;\n\t}\n\n\t/**\n\t * Set the session file to an existing session\n\t */\n\tsetSessionFile(path: string): void {\n\t\tthis.sessionFile = path;\n\t\tthis.loadSessionId();\n\t\t// Mark as initialized since we're loading an existing session\n\t\tthis.sessionInitialized = existsSync(path);\n\t\t// Load entries into memory for consistency\n\t\tif (this.sessionInitialized) {\n\t\t\tthis.inMemoryEntries = this.loadEntriesFromFile();\n\t\t} else {\n\t\t\tthis.inMemoryEntries = [];\n\t\t}\n\t\tthis.pendingEntries = [];\n\t}\n\n\t/**\n\t * Check if we should initialize the session based on message history.\n\t * Session is initialized when we have at least 1 user message and 1 assistant message.\n\t */\n\tshouldInitializeSession(messages: any[]): boolean {\n\t\tif (this.sessionInitialized) return false;\n\n\t\tconst userMessages = messages.filter((m) => m.role === \"user\");\n\t\tconst assistantMessages = messages.filter((m) => m.role === \"assistant\");\n\n\t\treturn userMessages.length >= 1 && assistantMessages.length >= 1;\n\t}\n\n\t/**\n\t * Create a branched session from a specific message index.\n\t * If branchFromIndex is -1, creates an empty session.\n\t * Returns the new session file path.\n\t */\n\tcreateBranchedSession(state: any, branchFromIndex: number): string {\n\t\t// Create a new session ID for the branch\n\t\tconst newSessionId = uuidv4();\n\t\tconst timestamp = new Date().toISOString().replace(/[:.]/g, \"-\");\n\t\tconst newSessionFile = join(this.sessionDir, `${timestamp}_${newSessionId}.jsonl`);\n\n\t\t// Write session header\n\t\tconst entry: SessionHeader = {\n\t\t\ttype: \"session\",\n\t\t\tid: newSessionId,\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tcwd: process.cwd(),\n\t\t\tprovider: state.model.provider,\n\t\t\tmodelId: state.model.id,\n\t\t\tthinkingLevel: state.thinkingLevel,\n\t\t\tbranchedFrom: this.sessionFile,\n\t\t};\n\t\tappendFileSync(newSessionFile, JSON.stringify(entry) + \"\\n\");\n\n\t\t// Write messages up to and including the branch point (if >= 0)\n\t\tif (branchFromIndex >= 0) {\n\t\t\tconst messagesToWrite = state.messages.slice(0, branchFromIndex + 1);\n\t\t\tfor (const message of messagesToWrite) {\n\t\t\t\tconst messageEntry: SessionMessageEntry = {\n\t\t\t\t\ttype: \"message\",\n\t\t\t\t\ttimestamp: new Date().toISOString(),\n\t\t\t\t\tmessage,\n\t\t\t\t};\n\t\t\t\tappendFileSync(newSessionFile, JSON.stringify(messageEntry) + \"\\n\");\n\t\t\t}\n\t\t}\n\n\t\treturn newSessionFile;\n\t}\n\n\t/**\n\t * Create a branched session from session entries up to (but not including) a specific entry index.\n\t * This preserves compaction events and all entry types.\n\t * Returns the new session file path, or null if in --no-session mode (in-memory only).\n\t */\n\tcreateBranchedSessionFromEntries(entries: SessionEntry[], branchBeforeIndex: number): string | null {\n\t\tconst newSessionId = uuidv4();\n\t\tconst timestamp = new Date().toISOString().replace(/[:.]/g, \"-\");\n\t\tconst newSessionFile = join(this.sessionDir, `${timestamp}_${newSessionId}.jsonl`);\n\n\t\t// Build new entries list (up to but not including branch point)\n\t\tconst newEntries: SessionEntry[] = [];\n\t\tfor (let i = 0; i < branchBeforeIndex; i++) {\n\t\t\tconst entry = entries[i];\n\n\t\t\tif (entry.type === \"session\") {\n\t\t\t\t// Rewrite session header with new ID and branchedFrom\n\t\t\t\tnewEntries.push({\n\t\t\t\t\t...entry,\n\t\t\t\t\tid: newSessionId,\n\t\t\t\t\ttimestamp: new Date().toISOString(),\n\t\t\t\t\tbranchedFrom: this.enabled ? this.sessionFile : undefined,\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\t// Copy other entries as-is\n\t\t\t\tnewEntries.push(entry);\n\t\t\t}\n\t\t}\n\n\t\tif (this.enabled) {\n\t\t\t// Write to file\n\t\t\tfor (const entry of newEntries) {\n\t\t\t\tappendFileSync(newSessionFile, JSON.stringify(entry) + \"\\n\");\n\t\t\t}\n\t\t\treturn newSessionFile;\n\t\t} else {\n\t\t\t// In-memory mode: replace inMemoryEntries, no file created\n\t\t\tthis.inMemoryEntries = newEntries;\n\t\t\tthis.sessionId = newSessionId;\n\t\t\treturn null;\n\t\t}\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"session-manager.d.ts","sourceRoot":"","sources":["../../src/core/session-manager.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AgentState, AppMessage } from \"@mariozechner/pi-agent-core\";\nimport { randomBytes } from \"crypto\";\nimport { appendFileSync, existsSync, mkdirSync, readdirSync, readFileSync, statSync } from \"fs\";\nimport { join, resolve } from \"path\";\nimport { getAgentDir } from \"../config.js\";\n\nfunction uuidv4(): string {\n\tconst bytes = randomBytes(16);\n\tbytes[6] = (bytes[6] & 0x0f) | 0x40;\n\tbytes[8] = (bytes[8] & 0x3f) | 0x80;\n\tconst hex = bytes.toString(\"hex\");\n\treturn `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20, 32)}`;\n}\n\n// ============================================================================\n// Session entry types\n// ============================================================================\n\nexport interface SessionHeader {\n\ttype: \"session\";\n\tid: string;\n\ttimestamp: string;\n\tcwd: string;\n\tprovider: string;\n\tmodelId: string;\n\tthinkingLevel: string;\n\tbranchedFrom?: string;\n}\n\nexport interface SessionMessageEntry {\n\ttype: \"message\";\n\ttimestamp: string;\n\tmessage: AppMessage;\n}\n\nexport interface ThinkingLevelChangeEntry {\n\ttype: \"thinking_level_change\";\n\ttimestamp: string;\n\tthinkingLevel: string;\n}\n\nexport interface ModelChangeEntry {\n\ttype: \"model_change\";\n\ttimestamp: string;\n\tprovider: string;\n\tmodelId: string;\n}\n\nexport interface CompactionEntry {\n\ttype: \"compaction\";\n\ttimestamp: string;\n\tsummary: string;\n\tfirstKeptEntryIndex: number; // Index into session entries where we start keeping\n\ttokensBefore: number;\n}\n\n/** Union of all session entry types */\nexport type SessionEntry =\n\t| SessionHeader\n\t| SessionMessageEntry\n\t| ThinkingLevelChangeEntry\n\t| ModelChangeEntry\n\t| CompactionEntry;\n\n// ============================================================================\n// Session loading with compaction support\n// ============================================================================\n\nexport interface LoadedSession {\n\tmessages: AppMessage[];\n\tthinkingLevel: string;\n\tmodel: { provider: string; modelId: string } | null;\n}\n\nexport const SUMMARY_PREFIX = `The conversation history before this point was compacted into the following summary:\n\n<summary>\n`;\n\nexport const SUMMARY_SUFFIX = `\n</summary>`;\n\n/**\n * Create a user message containing the summary with the standard prefix.\n */\nexport function createSummaryMessage(summary: string): AppMessage {\n\treturn {\n\t\trole: \"user\",\n\t\tcontent: SUMMARY_PREFIX + summary + SUMMARY_SUFFIX,\n\t\ttimestamp: Date.now(),\n\t};\n}\n\n/**\n * Parse session file content into entries.\n */\nexport function parseSessionEntries(content: string): SessionEntry[] {\n\tconst entries: SessionEntry[] = [];\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 SessionEntry;\n\t\t\tentries.push(entry);\n\t\t} catch {\n\t\t\t// Skip malformed lines\n\t\t}\n\t}\n\n\treturn entries;\n}\n\n/**\n * Load session from entries, handling compaction events.\n *\n * Algorithm:\n * 1. Find latest compaction event (if any)\n * 2. Keep all entries from firstKeptEntryIndex onwards (extracting messages)\n * 3. Prepend summary as user message\n */\n/**\n * Get the latest compaction entry from session entries, if any.\n */\nexport function getLatestCompactionEntry(entries: SessionEntry[]): CompactionEntry | null {\n\tfor (let i = entries.length - 1; i >= 0; i--) {\n\t\tif (entries[i].type === \"compaction\") {\n\t\t\treturn entries[i] as CompactionEntry;\n\t\t}\n\t}\n\treturn null;\n}\n\nexport function loadSessionFromEntries(entries: SessionEntry[]): LoadedSession {\n\t// Find model and thinking level (always scan all entries)\n\tlet thinkingLevel = \"off\";\n\tlet model: { provider: string; modelId: string } | null = null;\n\n\tfor (const entry of entries) {\n\t\tif (entry.type === \"session\") {\n\t\t\tthinkingLevel = entry.thinkingLevel;\n\t\t\tmodel = { provider: entry.provider, modelId: entry.modelId };\n\t\t} else if (entry.type === \"thinking_level_change\") {\n\t\t\tthinkingLevel = entry.thinkingLevel;\n\t\t} else if (entry.type === \"model_change\") {\n\t\t\tmodel = { provider: entry.provider, modelId: entry.modelId };\n\t\t}\n\t}\n\n\t// Find latest compaction event\n\tlet latestCompactionIndex = -1;\n\tfor (let i = entries.length - 1; i >= 0; i--) {\n\t\tif (entries[i].type === \"compaction\") {\n\t\t\tlatestCompactionIndex = i;\n\t\t\tbreak;\n\t\t}\n\t}\n\n\t// No compaction: return all messages\n\tif (latestCompactionIndex === -1) {\n\t\tconst messages: AppMessage[] = [];\n\t\tfor (const entry of entries) {\n\t\t\tif (entry.type === \"message\") {\n\t\t\t\tmessages.push(entry.message);\n\t\t\t}\n\t\t}\n\t\treturn { messages, thinkingLevel, model };\n\t}\n\n\tconst compactionEvent = entries[latestCompactionIndex] as CompactionEntry;\n\n\t// Extract messages from firstKeptEntryIndex to end (skipping compaction entries)\n\tconst keptMessages: AppMessage[] = [];\n\tfor (let i = compactionEvent.firstKeptEntryIndex; i < entries.length; i++) {\n\t\tconst entry = entries[i];\n\t\tif (entry.type === \"message\") {\n\t\t\tkeptMessages.push(entry.message);\n\t\t}\n\t}\n\n\t// Build final messages: summary + kept messages\n\tconst messages: AppMessage[] = [];\n\tmessages.push(createSummaryMessage(compactionEvent.summary));\n\tmessages.push(...keptMessages);\n\n\treturn { messages, thinkingLevel, model };\n}\n\nexport class SessionManager {\n\tprivate sessionId!: string;\n\tprivate sessionFile!: string;\n\tprivate sessionDir: string;\n\tprivate enabled: boolean = true;\n\tprivate sessionInitialized: boolean = false;\n\tprivate pendingEntries: SessionEntry[] = [];\n\t// In-memory entries for --no-session mode (when enabled=false)\n\tprivate inMemoryEntries: SessionEntry[] = [];\n\n\tconstructor(continueSession: boolean = false, customSessionPath?: string) {\n\t\tthis.sessionDir = this.getSessionDirectory();\n\n\t\tif (customSessionPath) {\n\t\t\t// Use custom session file path\n\t\t\tthis.sessionFile = resolve(customSessionPath);\n\t\t\tthis.loadSessionId();\n\t\t\t// If file doesn't exist, loadSessionId() won't set sessionId, so generate one\n\t\t\tif (!this.sessionId) {\n\t\t\t\tthis.sessionId = uuidv4();\n\t\t\t}\n\t\t\t// Mark as initialized since we're loading an existing session\n\t\t\tthis.sessionInitialized = existsSync(this.sessionFile);\n\t\t\t// Load entries into memory\n\t\t\tif (this.sessionInitialized) {\n\t\t\t\tthis.inMemoryEntries = this.loadEntriesFromFile();\n\t\t\t}\n\t\t} else if (continueSession) {\n\t\t\tconst mostRecent = this.findMostRecentlyModifiedSession();\n\t\t\tif (mostRecent) {\n\t\t\t\tthis.sessionFile = mostRecent;\n\t\t\t\tthis.loadSessionId();\n\t\t\t\t// Mark as initialized since we're loading an existing session\n\t\t\t\tthis.sessionInitialized = true;\n\t\t\t\t// Load entries into memory\n\t\t\t\tthis.inMemoryEntries = this.loadEntriesFromFile();\n\t\t\t} else {\n\t\t\t\tthis.initNewSession();\n\t\t\t}\n\t\t} else {\n\t\t\tthis.initNewSession();\n\t\t}\n\t}\n\n\t/** Disable session saving (for --no-session mode) */\n\tdisable() {\n\t\tthis.enabled = false;\n\t}\n\n\t/** Check if session persistence is enabled */\n\tisEnabled(): boolean {\n\t\treturn this.enabled;\n\t}\n\n\tprivate getSessionDirectory(): string {\n\t\tconst cwd = process.cwd();\n\t\t// Replace all path separators and colons (for Windows drive letters) with dashes\n\t\tconst safePath = `--${cwd.replace(/^[/\\\\]/, \"\").replace(/[/\\\\:]/g, \"-\")}--`;\n\n\t\tconst configDir = getAgentDir();\n\t\tconst sessionDir = join(configDir, \"sessions\", safePath);\n\t\tif (!existsSync(sessionDir)) {\n\t\t\tmkdirSync(sessionDir, { recursive: true });\n\t\t}\n\t\treturn sessionDir;\n\t}\n\n\tprivate initNewSession(): void {\n\t\tthis.sessionId = uuidv4();\n\t\tconst timestamp = new Date().toISOString().replace(/[:.]/g, \"-\");\n\t\tthis.sessionFile = join(this.sessionDir, `${timestamp}_${this.sessionId}.jsonl`);\n\t}\n\n\t/** Reset to a fresh session. Clears pending entries and starts a new session file. */\n\treset(): void {\n\t\tthis.pendingEntries = [];\n\t\tthis.inMemoryEntries = [];\n\t\tthis.sessionInitialized = false;\n\t\tthis.initNewSession();\n\t}\n\n\tprivate findMostRecentlyModifiedSession(): string | null {\n\t\ttry {\n\t\t\tconst files = readdirSync(this.sessionDir)\n\t\t\t\t.filter((f) => f.endsWith(\".jsonl\"))\n\t\t\t\t.map((f) => ({\n\t\t\t\t\tname: f,\n\t\t\t\t\tpath: join(this.sessionDir, f),\n\t\t\t\t\tmtime: statSync(join(this.sessionDir, f)).mtime,\n\t\t\t\t}))\n\t\t\t\t.sort((a, b) => b.mtime.getTime() - a.mtime.getTime());\n\n\t\t\treturn files[0]?.path || null;\n\t\t} catch {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\tprivate loadSessionId(): void {\n\t\tif (!existsSync(this.sessionFile)) return;\n\n\t\tconst lines = readFileSync(this.sessionFile, \"utf8\").trim().split(\"\\n\");\n\t\tfor (const line of lines) {\n\t\t\ttry {\n\t\t\t\tconst entry = JSON.parse(line);\n\t\t\t\tif (entry.type === \"session\") {\n\t\t\t\t\tthis.sessionId = entry.id;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\t// Skip malformed lines\n\t\t\t}\n\t\t}\n\t\tthis.sessionId = uuidv4();\n\t}\n\n\tstartSession(state: AgentState): void {\n\t\tif (this.sessionInitialized) return;\n\t\tthis.sessionInitialized = true;\n\n\t\tconst entry: SessionHeader = {\n\t\t\ttype: \"session\",\n\t\t\tid: this.sessionId,\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tcwd: process.cwd(),\n\t\t\tprovider: state.model.provider,\n\t\t\tmodelId: state.model.id,\n\t\t\tthinkingLevel: state.thinkingLevel,\n\t\t};\n\n\t\t// Always track in memory\n\t\tthis.inMemoryEntries.push(entry);\n\t\tfor (const pending of this.pendingEntries) {\n\t\t\tthis.inMemoryEntries.push(pending);\n\t\t}\n\t\tthis.pendingEntries = [];\n\n\t\t// Write to file only if enabled\n\t\tif (this.enabled) {\n\t\t\tappendFileSync(this.sessionFile, `${JSON.stringify(entry)}\\n`);\n\t\t\tfor (const memEntry of this.inMemoryEntries.slice(1)) {\n\t\t\t\tappendFileSync(this.sessionFile, `${JSON.stringify(memEntry)}\\n`);\n\t\t\t}\n\t\t}\n\t}\n\n\tsaveMessage(message: any): void {\n\t\tconst entry: SessionMessageEntry = {\n\t\t\ttype: \"message\",\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tmessage,\n\t\t};\n\n\t\tif (!this.sessionInitialized) {\n\t\t\tthis.pendingEntries.push(entry);\n\t\t} else {\n\t\t\t// Always track in memory\n\t\t\tthis.inMemoryEntries.push(entry);\n\t\t\t// Write to file only if enabled\n\t\t\tif (this.enabled) {\n\t\t\t\tappendFileSync(this.sessionFile, `${JSON.stringify(entry)}\\n`);\n\t\t\t}\n\t\t}\n\t}\n\n\tsaveThinkingLevelChange(thinkingLevel: string): void {\n\t\tconst entry: ThinkingLevelChangeEntry = {\n\t\t\ttype: \"thinking_level_change\",\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tthinkingLevel,\n\t\t};\n\n\t\tif (!this.sessionInitialized) {\n\t\t\tthis.pendingEntries.push(entry);\n\t\t} else {\n\t\t\t// Always track in memory\n\t\t\tthis.inMemoryEntries.push(entry);\n\t\t\t// Write to file only if enabled\n\t\t\tif (this.enabled) {\n\t\t\t\tappendFileSync(this.sessionFile, `${JSON.stringify(entry)}\\n`);\n\t\t\t}\n\t\t}\n\t}\n\n\tsaveModelChange(provider: string, modelId: string): void {\n\t\tconst entry: ModelChangeEntry = {\n\t\t\ttype: \"model_change\",\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tprovider,\n\t\t\tmodelId,\n\t\t};\n\n\t\tif (!this.sessionInitialized) {\n\t\t\tthis.pendingEntries.push(entry);\n\t\t} else {\n\t\t\t// Always track in memory\n\t\t\tthis.inMemoryEntries.push(entry);\n\t\t\t// Write to file only if enabled\n\t\t\tif (this.enabled) {\n\t\t\t\tappendFileSync(this.sessionFile, `${JSON.stringify(entry)}\\n`);\n\t\t\t}\n\t\t}\n\t}\n\n\tsaveCompaction(entry: CompactionEntry): void {\n\t\t// Always track in memory\n\t\tthis.inMemoryEntries.push(entry);\n\t\t// Write to file only if enabled\n\t\tif (this.enabled) {\n\t\t\tappendFileSync(this.sessionFile, `${JSON.stringify(entry)}\\n`);\n\t\t}\n\t}\n\n\t/**\n\t * Load session data (messages, model, thinking level) with compaction support.\n\t */\n\tloadSession(): LoadedSession {\n\t\tconst entries = this.loadEntries();\n\t\treturn loadSessionFromEntries(entries);\n\t}\n\n\t/**\n\t * @deprecated Use loadSession().messages instead\n\t */\n\tloadMessages(): AppMessage[] {\n\t\treturn this.loadSession().messages;\n\t}\n\n\t/**\n\t * @deprecated Use loadSession().thinkingLevel instead\n\t */\n\tloadThinkingLevel(): string {\n\t\treturn this.loadSession().thinkingLevel;\n\t}\n\n\t/**\n\t * @deprecated Use loadSession().model instead\n\t */\n\tloadModel(): { provider: string; modelId: string } | null {\n\t\treturn this.loadSession().model;\n\t}\n\n\tgetSessionId(): string {\n\t\treturn this.sessionId;\n\t}\n\n\tgetSessionFile(): string {\n\t\treturn this.sessionFile;\n\t}\n\n\t/**\n\t * Load entries directly from the session file (internal helper).\n\t */\n\tprivate loadEntriesFromFile(): SessionEntry[] {\n\t\tif (!existsSync(this.sessionFile)) return [];\n\n\t\tconst content = readFileSync(this.sessionFile, \"utf8\");\n\t\tconst entries: SessionEntry[] = [];\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\tconst entry = JSON.parse(line) as SessionEntry;\n\t\t\t\tentries.push(entry);\n\t\t\t} catch {\n\t\t\t\t// Skip malformed lines\n\t\t\t}\n\t\t}\n\n\t\treturn entries;\n\t}\n\n\t/**\n\t * Load all entries from the session file or in-memory store.\n\t * When file persistence is enabled, reads from file (source of truth for resumed sessions).\n\t * When disabled (--no-session), returns in-memory entries.\n\t */\n\tloadEntries(): SessionEntry[] {\n\t\t// If file persistence is enabled and file exists, read from file\n\t\tif (this.enabled && existsSync(this.sessionFile)) {\n\t\t\treturn this.loadEntriesFromFile();\n\t\t}\n\n\t\t// Otherwise return in-memory entries (for --no-session mode)\n\t\treturn [...this.inMemoryEntries];\n\t}\n\n\t/**\n\t * Load all sessions for the current directory with metadata\n\t */\n\tloadAllSessions(): Array<{\n\t\tpath: string;\n\t\tid: string;\n\t\tcreated: Date;\n\t\tmodified: Date;\n\t\tmessageCount: number;\n\t\tfirstMessage: string;\n\t\tallMessagesText: string;\n\t}> {\n\t\tconst sessions: Array<{\n\t\t\tpath: string;\n\t\t\tid: string;\n\t\t\tcreated: Date;\n\t\t\tmodified: Date;\n\t\t\tmessageCount: number;\n\t\t\tfirstMessage: string;\n\t\t\tallMessagesText: string;\n\t\t}> = [];\n\n\t\ttry {\n\t\t\tconst files = readdirSync(this.sessionDir)\n\t\t\t\t.filter((f) => f.endsWith(\".jsonl\"))\n\t\t\t\t.map((f) => join(this.sessionDir, f));\n\n\t\t\tfor (const file of files) {\n\t\t\t\ttry {\n\t\t\t\t\tconst stats = statSync(file);\n\t\t\t\t\tconst content = readFileSync(file, \"utf8\");\n\t\t\t\t\tconst lines = content.trim().split(\"\\n\");\n\n\t\t\t\t\tlet sessionId = \"\";\n\t\t\t\t\tlet created = stats.birthtime;\n\t\t\t\t\tlet messageCount = 0;\n\t\t\t\t\tlet firstMessage = \"\";\n\t\t\t\t\tconst allMessages: string[] = [];\n\n\t\t\t\t\tfor (const line of lines) {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst entry = JSON.parse(line);\n\n\t\t\t\t\t\t\t// Extract session ID from first session entry\n\t\t\t\t\t\t\tif (entry.type === \"session\" && !sessionId) {\n\t\t\t\t\t\t\t\tsessionId = entry.id;\n\t\t\t\t\t\t\t\tcreated = new Date(entry.timestamp);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// Count messages and collect all text\n\t\t\t\t\t\t\tif (entry.type === \"message\") {\n\t\t\t\t\t\t\t\tmessageCount++;\n\n\t\t\t\t\t\t\t\t// Extract text from user and assistant messages\n\t\t\t\t\t\t\t\tif (entry.message.role === \"user\" || entry.message.role === \"assistant\") {\n\t\t\t\t\t\t\t\t\tconst textContent = entry.message.content\n\t\t\t\t\t\t\t\t\t\t.filter((c: any) => c.type === \"text\")\n\t\t\t\t\t\t\t\t\t\t.map((c: any) => c.text)\n\t\t\t\t\t\t\t\t\t\t.join(\" \");\n\n\t\t\t\t\t\t\t\t\tif (textContent) {\n\t\t\t\t\t\t\t\t\t\tallMessages.push(textContent);\n\n\t\t\t\t\t\t\t\t\t\t// Get first user message for display\n\t\t\t\t\t\t\t\t\t\tif (!firstMessage && entry.message.role === \"user\") {\n\t\t\t\t\t\t\t\t\t\t\tfirstMessage = textContent;\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t// Skip malformed lines\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tsessions.push({\n\t\t\t\t\t\tpath: file,\n\t\t\t\t\t\tid: sessionId || \"unknown\",\n\t\t\t\t\t\tcreated,\n\t\t\t\t\t\tmodified: stats.mtime,\n\t\t\t\t\t\tmessageCount,\n\t\t\t\t\t\tfirstMessage: firstMessage || \"(no messages)\",\n\t\t\t\t\t\tallMessagesText: allMessages.join(\" \"),\n\t\t\t\t\t});\n\t\t\t\t} catch (error) {\n\t\t\t\t\t// Skip files that can't be read\n\t\t\t\t\tconsole.error(`Failed to read session file ${file}:`, error);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Sort by modified date (most recent first)\n\t\t\tsessions.sort((a, b) => b.modified.getTime() - a.modified.getTime());\n\t\t} catch (error) {\n\t\t\tconsole.error(\"Failed to load sessions:\", error);\n\t\t}\n\n\t\treturn sessions;\n\t}\n\n\t/**\n\t * Set the session file to an existing session\n\t */\n\tsetSessionFile(path: string): void {\n\t\tthis.sessionFile = path;\n\t\tthis.loadSessionId();\n\t\t// Mark as initialized since we're loading an existing session\n\t\tthis.sessionInitialized = existsSync(path);\n\t\t// Load entries into memory for consistency\n\t\tif (this.sessionInitialized) {\n\t\t\tthis.inMemoryEntries = this.loadEntriesFromFile();\n\t\t} else {\n\t\t\tthis.inMemoryEntries = [];\n\t\t}\n\t\tthis.pendingEntries = [];\n\t}\n\n\t/**\n\t * Check if we should initialize the session based on message history.\n\t * Session is initialized when we have at least 1 user message and 1 assistant message.\n\t */\n\tshouldInitializeSession(messages: any[]): boolean {\n\t\tif (this.sessionInitialized) return false;\n\n\t\tconst userMessages = messages.filter((m) => m.role === \"user\");\n\t\tconst assistantMessages = messages.filter((m) => m.role === \"assistant\");\n\n\t\treturn userMessages.length >= 1 && assistantMessages.length >= 1;\n\t}\n\n\t/**\n\t * Create a branched session from a specific message index.\n\t * If branchFromIndex is -1, creates an empty session.\n\t * Returns the new session file path.\n\t */\n\tcreateBranchedSession(state: any, branchFromIndex: number): string {\n\t\t// Create a new session ID for the branch\n\t\tconst newSessionId = uuidv4();\n\t\tconst timestamp = new Date().toISOString().replace(/[:.]/g, \"-\");\n\t\tconst newSessionFile = join(this.sessionDir, `${timestamp}_${newSessionId}.jsonl`);\n\n\t\t// Write session header\n\t\tconst entry: SessionHeader = {\n\t\t\ttype: \"session\",\n\t\t\tid: newSessionId,\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tcwd: process.cwd(),\n\t\t\tprovider: state.model.provider,\n\t\t\tmodelId: state.model.id,\n\t\t\tthinkingLevel: state.thinkingLevel,\n\t\t\tbranchedFrom: this.sessionFile,\n\t\t};\n\t\tappendFileSync(newSessionFile, `${JSON.stringify(entry)}\\n`);\n\n\t\t// Write messages up to and including the branch point (if >= 0)\n\t\tif (branchFromIndex >= 0) {\n\t\t\tconst messagesToWrite = state.messages.slice(0, branchFromIndex + 1);\n\t\t\tfor (const message of messagesToWrite) {\n\t\t\t\tconst messageEntry: SessionMessageEntry = {\n\t\t\t\t\ttype: \"message\",\n\t\t\t\t\ttimestamp: new Date().toISOString(),\n\t\t\t\t\tmessage,\n\t\t\t\t};\n\t\t\t\tappendFileSync(newSessionFile, `${JSON.stringify(messageEntry)}\\n`);\n\t\t\t}\n\t\t}\n\n\t\treturn newSessionFile;\n\t}\n\n\t/**\n\t * Create a branched session from session entries up to (but not including) a specific entry index.\n\t * This preserves compaction events and all entry types.\n\t * Returns the new session file path, or null if in --no-session mode (in-memory only).\n\t */\n\tcreateBranchedSessionFromEntries(entries: SessionEntry[], branchBeforeIndex: number): string | null {\n\t\tconst newSessionId = uuidv4();\n\t\tconst timestamp = new Date().toISOString().replace(/[:.]/g, \"-\");\n\t\tconst newSessionFile = join(this.sessionDir, `${timestamp}_${newSessionId}.jsonl`);\n\n\t\t// Build new entries list (up to but not including branch point)\n\t\tconst newEntries: SessionEntry[] = [];\n\t\tfor (let i = 0; i < branchBeforeIndex; i++) {\n\t\t\tconst entry = entries[i];\n\n\t\t\tif (entry.type === \"session\") {\n\t\t\t\t// Rewrite session header with new ID and branchedFrom\n\t\t\t\tnewEntries.push({\n\t\t\t\t\t...entry,\n\t\t\t\t\tid: newSessionId,\n\t\t\t\t\ttimestamp: new Date().toISOString(),\n\t\t\t\t\tbranchedFrom: this.enabled ? this.sessionFile : undefined,\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\t// Copy other entries as-is\n\t\t\t\tnewEntries.push(entry);\n\t\t\t}\n\t\t}\n\n\t\tif (this.enabled) {\n\t\t\t// Write to file\n\t\t\tfor (const entry of newEntries) {\n\t\t\t\tappendFileSync(newSessionFile, `${JSON.stringify(entry)}\\n`);\n\t\t\t}\n\t\t\treturn newSessionFile;\n\t\t} else {\n\t\t\t// In-memory mode: replace inMemoryEntries, no file created\n\t\t\tthis.inMemoryEntries = newEntries;\n\t\t\tthis.sessionId = newSessionId;\n\t\t\treturn null;\n\t\t}\n\t}\n}\n"]}
|
|
@@ -167,7 +167,7 @@ export class SessionManager {
|
|
|
167
167
|
getSessionDirectory() {
|
|
168
168
|
const cwd = process.cwd();
|
|
169
169
|
// Replace all path separators and colons (for Windows drive letters) with dashes
|
|
170
|
-
const safePath =
|
|
170
|
+
const safePath = `--${cwd.replace(/^[/\\]/, "").replace(/[/\\:]/g, "-")}--`;
|
|
171
171
|
const configDir = getAgentDir();
|
|
172
172
|
const sessionDir = join(configDir, "sessions", safePath);
|
|
173
173
|
if (!existsSync(sessionDir)) {
|
|
@@ -242,9 +242,9 @@ export class SessionManager {
|
|
|
242
242
|
this.pendingEntries = [];
|
|
243
243
|
// Write to file only if enabled
|
|
244
244
|
if (this.enabled) {
|
|
245
|
-
appendFileSync(this.sessionFile, JSON.stringify(entry)
|
|
245
|
+
appendFileSync(this.sessionFile, `${JSON.stringify(entry)}\n`);
|
|
246
246
|
for (const memEntry of this.inMemoryEntries.slice(1)) {
|
|
247
|
-
appendFileSync(this.sessionFile, JSON.stringify(memEntry)
|
|
247
|
+
appendFileSync(this.sessionFile, `${JSON.stringify(memEntry)}\n`);
|
|
248
248
|
}
|
|
249
249
|
}
|
|
250
250
|
}
|
|
@@ -262,7 +262,7 @@ export class SessionManager {
|
|
|
262
262
|
this.inMemoryEntries.push(entry);
|
|
263
263
|
// Write to file only if enabled
|
|
264
264
|
if (this.enabled) {
|
|
265
|
-
appendFileSync(this.sessionFile, JSON.stringify(entry)
|
|
265
|
+
appendFileSync(this.sessionFile, `${JSON.stringify(entry)}\n`);
|
|
266
266
|
}
|
|
267
267
|
}
|
|
268
268
|
}
|
|
@@ -280,7 +280,7 @@ export class SessionManager {
|
|
|
280
280
|
this.inMemoryEntries.push(entry);
|
|
281
281
|
// Write to file only if enabled
|
|
282
282
|
if (this.enabled) {
|
|
283
|
-
appendFileSync(this.sessionFile, JSON.stringify(entry)
|
|
283
|
+
appendFileSync(this.sessionFile, `${JSON.stringify(entry)}\n`);
|
|
284
284
|
}
|
|
285
285
|
}
|
|
286
286
|
}
|
|
@@ -299,7 +299,7 @@ export class SessionManager {
|
|
|
299
299
|
this.inMemoryEntries.push(entry);
|
|
300
300
|
// Write to file only if enabled
|
|
301
301
|
if (this.enabled) {
|
|
302
|
-
appendFileSync(this.sessionFile, JSON.stringify(entry)
|
|
302
|
+
appendFileSync(this.sessionFile, `${JSON.stringify(entry)}\n`);
|
|
303
303
|
}
|
|
304
304
|
}
|
|
305
305
|
}
|
|
@@ -308,7 +308,7 @@ export class SessionManager {
|
|
|
308
308
|
this.inMemoryEntries.push(entry);
|
|
309
309
|
// Write to file only if enabled
|
|
310
310
|
if (this.enabled) {
|
|
311
|
-
appendFileSync(this.sessionFile, JSON.stringify(entry)
|
|
311
|
+
appendFileSync(this.sessionFile, `${JSON.stringify(entry)}\n`);
|
|
312
312
|
}
|
|
313
313
|
}
|
|
314
314
|
/**
|
|
@@ -499,7 +499,7 @@ export class SessionManager {
|
|
|
499
499
|
thinkingLevel: state.thinkingLevel,
|
|
500
500
|
branchedFrom: this.sessionFile,
|
|
501
501
|
};
|
|
502
|
-
appendFileSync(newSessionFile, JSON.stringify(entry)
|
|
502
|
+
appendFileSync(newSessionFile, `${JSON.stringify(entry)}\n`);
|
|
503
503
|
// Write messages up to and including the branch point (if >= 0)
|
|
504
504
|
if (branchFromIndex >= 0) {
|
|
505
505
|
const messagesToWrite = state.messages.slice(0, branchFromIndex + 1);
|
|
@@ -509,7 +509,7 @@ export class SessionManager {
|
|
|
509
509
|
timestamp: new Date().toISOString(),
|
|
510
510
|
message,
|
|
511
511
|
};
|
|
512
|
-
appendFileSync(newSessionFile, JSON.stringify(messageEntry)
|
|
512
|
+
appendFileSync(newSessionFile, `${JSON.stringify(messageEntry)}\n`);
|
|
513
513
|
}
|
|
514
514
|
}
|
|
515
515
|
return newSessionFile;
|
|
@@ -544,7 +544,7 @@ export class SessionManager {
|
|
|
544
544
|
if (this.enabled) {
|
|
545
545
|
// Write to file
|
|
546
546
|
for (const entry of newEntries) {
|
|
547
|
-
appendFileSync(newSessionFile, JSON.stringify(entry)
|
|
547
|
+
appendFileSync(newSessionFile, `${JSON.stringify(entry)}\n`);
|
|
548
548
|
}
|
|
549
549
|
return newSessionFile;
|
|
550
550
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-manager.js","sourceRoot":"","sources":["../../src/core/session-manager.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AgentState, AppMessage } from \"@mariozechner/pi-agent-core\";\nimport { randomBytes } from \"crypto\";\nimport { appendFileSync, existsSync, mkdirSync, readdirSync, readFileSync, statSync } from \"fs\";\nimport { join, resolve } from \"path\";\nimport { getAgentDir } from \"../config.js\";\n\nfunction uuidv4(): string {\n\tconst bytes = randomBytes(16);\n\tbytes[6] = (bytes[6] & 0x0f) | 0x40;\n\tbytes[8] = (bytes[8] & 0x3f) | 0x80;\n\tconst hex = bytes.toString(\"hex\");\n\treturn `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20, 32)}`;\n}\n\n// ============================================================================\n// Session entry types\n// ============================================================================\n\nexport interface SessionHeader {\n\ttype: \"session\";\n\tid: string;\n\ttimestamp: string;\n\tcwd: string;\n\tprovider: string;\n\tmodelId: string;\n\tthinkingLevel: string;\n\tbranchedFrom?: string;\n}\n\nexport interface SessionMessageEntry {\n\ttype: \"message\";\n\ttimestamp: string;\n\tmessage: AppMessage;\n}\n\nexport interface ThinkingLevelChangeEntry {\n\ttype: \"thinking_level_change\";\n\ttimestamp: string;\n\tthinkingLevel: string;\n}\n\nexport interface ModelChangeEntry {\n\ttype: \"model_change\";\n\ttimestamp: string;\n\tprovider: string;\n\tmodelId: string;\n}\n\nexport interface CompactionEntry {\n\ttype: \"compaction\";\n\ttimestamp: string;\n\tsummary: string;\n\tfirstKeptEntryIndex: number; // Index into session entries where we start keeping\n\ttokensBefore: number;\n}\n\n/** Union of all session entry types */\nexport type SessionEntry =\n\t| SessionHeader\n\t| SessionMessageEntry\n\t| ThinkingLevelChangeEntry\n\t| ModelChangeEntry\n\t| CompactionEntry;\n\n// ============================================================================\n// Session loading with compaction support\n// ============================================================================\n\nexport interface LoadedSession {\n\tmessages: AppMessage[];\n\tthinkingLevel: string;\n\tmodel: { provider: string; modelId: string } | null;\n}\n\nexport const SUMMARY_PREFIX = `The conversation history before this point was compacted into the following summary:\n\n<summary>\n`;\n\nexport const SUMMARY_SUFFIX = `\n</summary>`;\n\n/**\n * Create a user message containing the summary with the standard prefix.\n */\nexport function createSummaryMessage(summary: string): AppMessage {\n\treturn {\n\t\trole: \"user\",\n\t\tcontent: SUMMARY_PREFIX + summary + SUMMARY_SUFFIX,\n\t\ttimestamp: Date.now(),\n\t};\n}\n\n/**\n * Parse session file content into entries.\n */\nexport function parseSessionEntries(content: string): SessionEntry[] {\n\tconst entries: SessionEntry[] = [];\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 SessionEntry;\n\t\t\tentries.push(entry);\n\t\t} catch {\n\t\t\t// Skip malformed lines\n\t\t}\n\t}\n\n\treturn entries;\n}\n\n/**\n * Load session from entries, handling compaction events.\n *\n * Algorithm:\n * 1. Find latest compaction event (if any)\n * 2. Keep all entries from firstKeptEntryIndex onwards (extracting messages)\n * 3. Prepend summary as user message\n */\n/**\n * Get the latest compaction entry from session entries, if any.\n */\nexport function getLatestCompactionEntry(entries: SessionEntry[]): CompactionEntry | null {\n\tfor (let i = entries.length - 1; i >= 0; i--) {\n\t\tif (entries[i].type === \"compaction\") {\n\t\t\treturn entries[i] as CompactionEntry;\n\t\t}\n\t}\n\treturn null;\n}\n\nexport function loadSessionFromEntries(entries: SessionEntry[]): LoadedSession {\n\t// Find model and thinking level (always scan all entries)\n\tlet thinkingLevel = \"off\";\n\tlet model: { provider: string; modelId: string } | null = null;\n\n\tfor (const entry of entries) {\n\t\tif (entry.type === \"session\") {\n\t\t\tthinkingLevel = entry.thinkingLevel;\n\t\t\tmodel = { provider: entry.provider, modelId: entry.modelId };\n\t\t} else if (entry.type === \"thinking_level_change\") {\n\t\t\tthinkingLevel = entry.thinkingLevel;\n\t\t} else if (entry.type === \"model_change\") {\n\t\t\tmodel = { provider: entry.provider, modelId: entry.modelId };\n\t\t}\n\t}\n\n\t// Find latest compaction event\n\tlet latestCompactionIndex = -1;\n\tfor (let i = entries.length - 1; i >= 0; i--) {\n\t\tif (entries[i].type === \"compaction\") {\n\t\t\tlatestCompactionIndex = i;\n\t\t\tbreak;\n\t\t}\n\t}\n\n\t// No compaction: return all messages\n\tif (latestCompactionIndex === -1) {\n\t\tconst messages: AppMessage[] = [];\n\t\tfor (const entry of entries) {\n\t\t\tif (entry.type === \"message\") {\n\t\t\t\tmessages.push(entry.message);\n\t\t\t}\n\t\t}\n\t\treturn { messages, thinkingLevel, model };\n\t}\n\n\tconst compactionEvent = entries[latestCompactionIndex] as CompactionEntry;\n\n\t// Extract messages from firstKeptEntryIndex to end (skipping compaction entries)\n\tconst keptMessages: AppMessage[] = [];\n\tfor (let i = compactionEvent.firstKeptEntryIndex; i < entries.length; i++) {\n\t\tconst entry = entries[i];\n\t\tif (entry.type === \"message\") {\n\t\t\tkeptMessages.push(entry.message);\n\t\t}\n\t}\n\n\t// Build final messages: summary + kept messages\n\tconst messages: AppMessage[] = [];\n\tmessages.push(createSummaryMessage(compactionEvent.summary));\n\tmessages.push(...keptMessages);\n\n\treturn { messages, thinkingLevel, model };\n}\n\nexport class SessionManager {\n\tprivate sessionId!: string;\n\tprivate sessionFile!: string;\n\tprivate sessionDir: string;\n\tprivate enabled: boolean = true;\n\tprivate sessionInitialized: boolean = false;\n\tprivate pendingEntries: SessionEntry[] = [];\n\t// In-memory entries for --no-session mode (when enabled=false)\n\tprivate inMemoryEntries: SessionEntry[] = [];\n\n\tconstructor(continueSession: boolean = false, customSessionPath?: string) {\n\t\tthis.sessionDir = this.getSessionDirectory();\n\n\t\tif (customSessionPath) {\n\t\t\t// Use custom session file path\n\t\t\tthis.sessionFile = resolve(customSessionPath);\n\t\t\tthis.loadSessionId();\n\t\t\t// If file doesn't exist, loadSessionId() won't set sessionId, so generate one\n\t\t\tif (!this.sessionId) {\n\t\t\t\tthis.sessionId = uuidv4();\n\t\t\t}\n\t\t\t// Mark as initialized since we're loading an existing session\n\t\t\tthis.sessionInitialized = existsSync(this.sessionFile);\n\t\t\t// Load entries into memory\n\t\t\tif (this.sessionInitialized) {\n\t\t\t\tthis.inMemoryEntries = this.loadEntriesFromFile();\n\t\t\t}\n\t\t} else if (continueSession) {\n\t\t\tconst mostRecent = this.findMostRecentlyModifiedSession();\n\t\t\tif (mostRecent) {\n\t\t\t\tthis.sessionFile = mostRecent;\n\t\t\t\tthis.loadSessionId();\n\t\t\t\t// Mark as initialized since we're loading an existing session\n\t\t\t\tthis.sessionInitialized = true;\n\t\t\t\t// Load entries into memory\n\t\t\t\tthis.inMemoryEntries = this.loadEntriesFromFile();\n\t\t\t} else {\n\t\t\t\tthis.initNewSession();\n\t\t\t}\n\t\t} else {\n\t\t\tthis.initNewSession();\n\t\t}\n\t}\n\n\t/** Disable session saving (for --no-session mode) */\n\tdisable() {\n\t\tthis.enabled = false;\n\t}\n\n\t/** Check if session persistence is enabled */\n\tisEnabled(): boolean {\n\t\treturn this.enabled;\n\t}\n\n\tprivate getSessionDirectory(): string {\n\t\tconst cwd = process.cwd();\n\t\t// Replace all path separators and colons (for Windows drive letters) with dashes\n\t\tconst safePath = \"--\" + cwd.replace(/^[/\\\\]/, \"\").replace(/[/\\\\:]/g, \"-\") + \"--\";\n\n\t\tconst configDir = getAgentDir();\n\t\tconst sessionDir = join(configDir, \"sessions\", safePath);\n\t\tif (!existsSync(sessionDir)) {\n\t\t\tmkdirSync(sessionDir, { recursive: true });\n\t\t}\n\t\treturn sessionDir;\n\t}\n\n\tprivate initNewSession(): void {\n\t\tthis.sessionId = uuidv4();\n\t\tconst timestamp = new Date().toISOString().replace(/[:.]/g, \"-\");\n\t\tthis.sessionFile = join(this.sessionDir, `${timestamp}_${this.sessionId}.jsonl`);\n\t}\n\n\t/** Reset to a fresh session. Clears pending entries and starts a new session file. */\n\treset(): void {\n\t\tthis.pendingEntries = [];\n\t\tthis.inMemoryEntries = [];\n\t\tthis.sessionInitialized = false;\n\t\tthis.initNewSession();\n\t}\n\n\tprivate findMostRecentlyModifiedSession(): string | null {\n\t\ttry {\n\t\t\tconst files = readdirSync(this.sessionDir)\n\t\t\t\t.filter((f) => f.endsWith(\".jsonl\"))\n\t\t\t\t.map((f) => ({\n\t\t\t\t\tname: f,\n\t\t\t\t\tpath: join(this.sessionDir, f),\n\t\t\t\t\tmtime: statSync(join(this.sessionDir, f)).mtime,\n\t\t\t\t}))\n\t\t\t\t.sort((a, b) => b.mtime.getTime() - a.mtime.getTime());\n\n\t\t\treturn files[0]?.path || null;\n\t\t} catch {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\tprivate loadSessionId(): void {\n\t\tif (!existsSync(this.sessionFile)) return;\n\n\t\tconst lines = readFileSync(this.sessionFile, \"utf8\").trim().split(\"\\n\");\n\t\tfor (const line of lines) {\n\t\t\ttry {\n\t\t\t\tconst entry = JSON.parse(line);\n\t\t\t\tif (entry.type === \"session\") {\n\t\t\t\t\tthis.sessionId = entry.id;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\t// Skip malformed lines\n\t\t\t}\n\t\t}\n\t\tthis.sessionId = uuidv4();\n\t}\n\n\tstartSession(state: AgentState): void {\n\t\tif (this.sessionInitialized) return;\n\t\tthis.sessionInitialized = true;\n\n\t\tconst entry: SessionHeader = {\n\t\t\ttype: \"session\",\n\t\t\tid: this.sessionId,\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tcwd: process.cwd(),\n\t\t\tprovider: state.model.provider,\n\t\t\tmodelId: state.model.id,\n\t\t\tthinkingLevel: state.thinkingLevel,\n\t\t};\n\n\t\t// Always track in memory\n\t\tthis.inMemoryEntries.push(entry);\n\t\tfor (const pending of this.pendingEntries) {\n\t\t\tthis.inMemoryEntries.push(pending);\n\t\t}\n\t\tthis.pendingEntries = [];\n\n\t\t// Write to file only if enabled\n\t\tif (this.enabled) {\n\t\t\tappendFileSync(this.sessionFile, JSON.stringify(entry) + \"\\n\");\n\t\t\tfor (const memEntry of this.inMemoryEntries.slice(1)) {\n\t\t\t\tappendFileSync(this.sessionFile, JSON.stringify(memEntry) + \"\\n\");\n\t\t\t}\n\t\t}\n\t}\n\n\tsaveMessage(message: any): void {\n\t\tconst entry: SessionMessageEntry = {\n\t\t\ttype: \"message\",\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tmessage,\n\t\t};\n\n\t\tif (!this.sessionInitialized) {\n\t\t\tthis.pendingEntries.push(entry);\n\t\t} else {\n\t\t\t// Always track in memory\n\t\t\tthis.inMemoryEntries.push(entry);\n\t\t\t// Write to file only if enabled\n\t\t\tif (this.enabled) {\n\t\t\t\tappendFileSync(this.sessionFile, JSON.stringify(entry) + \"\\n\");\n\t\t\t}\n\t\t}\n\t}\n\n\tsaveThinkingLevelChange(thinkingLevel: string): void {\n\t\tconst entry: ThinkingLevelChangeEntry = {\n\t\t\ttype: \"thinking_level_change\",\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tthinkingLevel,\n\t\t};\n\n\t\tif (!this.sessionInitialized) {\n\t\t\tthis.pendingEntries.push(entry);\n\t\t} else {\n\t\t\t// Always track in memory\n\t\t\tthis.inMemoryEntries.push(entry);\n\t\t\t// Write to file only if enabled\n\t\t\tif (this.enabled) {\n\t\t\t\tappendFileSync(this.sessionFile, JSON.stringify(entry) + \"\\n\");\n\t\t\t}\n\t\t}\n\t}\n\n\tsaveModelChange(provider: string, modelId: string): void {\n\t\tconst entry: ModelChangeEntry = {\n\t\t\ttype: \"model_change\",\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tprovider,\n\t\t\tmodelId,\n\t\t};\n\n\t\tif (!this.sessionInitialized) {\n\t\t\tthis.pendingEntries.push(entry);\n\t\t} else {\n\t\t\t// Always track in memory\n\t\t\tthis.inMemoryEntries.push(entry);\n\t\t\t// Write to file only if enabled\n\t\t\tif (this.enabled) {\n\t\t\t\tappendFileSync(this.sessionFile, JSON.stringify(entry) + \"\\n\");\n\t\t\t}\n\t\t}\n\t}\n\n\tsaveCompaction(entry: CompactionEntry): void {\n\t\t// Always track in memory\n\t\tthis.inMemoryEntries.push(entry);\n\t\t// Write to file only if enabled\n\t\tif (this.enabled) {\n\t\t\tappendFileSync(this.sessionFile, JSON.stringify(entry) + \"\\n\");\n\t\t}\n\t}\n\n\t/**\n\t * Load session data (messages, model, thinking level) with compaction support.\n\t */\n\tloadSession(): LoadedSession {\n\t\tconst entries = this.loadEntries();\n\t\treturn loadSessionFromEntries(entries);\n\t}\n\n\t/**\n\t * @deprecated Use loadSession().messages instead\n\t */\n\tloadMessages(): AppMessage[] {\n\t\treturn this.loadSession().messages;\n\t}\n\n\t/**\n\t * @deprecated Use loadSession().thinkingLevel instead\n\t */\n\tloadThinkingLevel(): string {\n\t\treturn this.loadSession().thinkingLevel;\n\t}\n\n\t/**\n\t * @deprecated Use loadSession().model instead\n\t */\n\tloadModel(): { provider: string; modelId: string } | null {\n\t\treturn this.loadSession().model;\n\t}\n\n\tgetSessionId(): string {\n\t\treturn this.sessionId;\n\t}\n\n\tgetSessionFile(): string {\n\t\treturn this.sessionFile;\n\t}\n\n\t/**\n\t * Load entries directly from the session file (internal helper).\n\t */\n\tprivate loadEntriesFromFile(): SessionEntry[] {\n\t\tif (!existsSync(this.sessionFile)) return [];\n\n\t\tconst content = readFileSync(this.sessionFile, \"utf8\");\n\t\tconst entries: SessionEntry[] = [];\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\tconst entry = JSON.parse(line) as SessionEntry;\n\t\t\t\tentries.push(entry);\n\t\t\t} catch {\n\t\t\t\t// Skip malformed lines\n\t\t\t}\n\t\t}\n\n\t\treturn entries;\n\t}\n\n\t/**\n\t * Load all entries from the session file or in-memory store.\n\t * When file persistence is enabled, reads from file (source of truth for resumed sessions).\n\t * When disabled (--no-session), returns in-memory entries.\n\t */\n\tloadEntries(): SessionEntry[] {\n\t\t// If file persistence is enabled and file exists, read from file\n\t\tif (this.enabled && existsSync(this.sessionFile)) {\n\t\t\treturn this.loadEntriesFromFile();\n\t\t}\n\n\t\t// Otherwise return in-memory entries (for --no-session mode)\n\t\treturn [...this.inMemoryEntries];\n\t}\n\n\t/**\n\t * Load all sessions for the current directory with metadata\n\t */\n\tloadAllSessions(): Array<{\n\t\tpath: string;\n\t\tid: string;\n\t\tcreated: Date;\n\t\tmodified: Date;\n\t\tmessageCount: number;\n\t\tfirstMessage: string;\n\t\tallMessagesText: string;\n\t}> {\n\t\tconst sessions: Array<{\n\t\t\tpath: string;\n\t\t\tid: string;\n\t\t\tcreated: Date;\n\t\t\tmodified: Date;\n\t\t\tmessageCount: number;\n\t\t\tfirstMessage: string;\n\t\t\tallMessagesText: string;\n\t\t}> = [];\n\n\t\ttry {\n\t\t\tconst files = readdirSync(this.sessionDir)\n\t\t\t\t.filter((f) => f.endsWith(\".jsonl\"))\n\t\t\t\t.map((f) => join(this.sessionDir, f));\n\n\t\t\tfor (const file of files) {\n\t\t\t\ttry {\n\t\t\t\t\tconst stats = statSync(file);\n\t\t\t\t\tconst content = readFileSync(file, \"utf8\");\n\t\t\t\t\tconst lines = content.trim().split(\"\\n\");\n\n\t\t\t\t\tlet sessionId = \"\";\n\t\t\t\t\tlet created = stats.birthtime;\n\t\t\t\t\tlet messageCount = 0;\n\t\t\t\t\tlet firstMessage = \"\";\n\t\t\t\t\tconst allMessages: string[] = [];\n\n\t\t\t\t\tfor (const line of lines) {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst entry = JSON.parse(line);\n\n\t\t\t\t\t\t\t// Extract session ID from first session entry\n\t\t\t\t\t\t\tif (entry.type === \"session\" && !sessionId) {\n\t\t\t\t\t\t\t\tsessionId = entry.id;\n\t\t\t\t\t\t\t\tcreated = new Date(entry.timestamp);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// Count messages and collect all text\n\t\t\t\t\t\t\tif (entry.type === \"message\") {\n\t\t\t\t\t\t\t\tmessageCount++;\n\n\t\t\t\t\t\t\t\t// Extract text from user and assistant messages\n\t\t\t\t\t\t\t\tif (entry.message.role === \"user\" || entry.message.role === \"assistant\") {\n\t\t\t\t\t\t\t\t\tconst textContent = entry.message.content\n\t\t\t\t\t\t\t\t\t\t.filter((c: any) => c.type === \"text\")\n\t\t\t\t\t\t\t\t\t\t.map((c: any) => c.text)\n\t\t\t\t\t\t\t\t\t\t.join(\" \");\n\n\t\t\t\t\t\t\t\t\tif (textContent) {\n\t\t\t\t\t\t\t\t\t\tallMessages.push(textContent);\n\n\t\t\t\t\t\t\t\t\t\t// Get first user message for display\n\t\t\t\t\t\t\t\t\t\tif (!firstMessage && entry.message.role === \"user\") {\n\t\t\t\t\t\t\t\t\t\t\tfirstMessage = textContent;\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t// Skip malformed lines\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tsessions.push({\n\t\t\t\t\t\tpath: file,\n\t\t\t\t\t\tid: sessionId || \"unknown\",\n\t\t\t\t\t\tcreated,\n\t\t\t\t\t\tmodified: stats.mtime,\n\t\t\t\t\t\tmessageCount,\n\t\t\t\t\t\tfirstMessage: firstMessage || \"(no messages)\",\n\t\t\t\t\t\tallMessagesText: allMessages.join(\" \"),\n\t\t\t\t\t});\n\t\t\t\t} catch (error) {\n\t\t\t\t\t// Skip files that can't be read\n\t\t\t\t\tconsole.error(`Failed to read session file ${file}:`, error);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Sort by modified date (most recent first)\n\t\t\tsessions.sort((a, b) => b.modified.getTime() - a.modified.getTime());\n\t\t} catch (error) {\n\t\t\tconsole.error(\"Failed to load sessions:\", error);\n\t\t}\n\n\t\treturn sessions;\n\t}\n\n\t/**\n\t * Set the session file to an existing session\n\t */\n\tsetSessionFile(path: string): void {\n\t\tthis.sessionFile = path;\n\t\tthis.loadSessionId();\n\t\t// Mark as initialized since we're loading an existing session\n\t\tthis.sessionInitialized = existsSync(path);\n\t\t// Load entries into memory for consistency\n\t\tif (this.sessionInitialized) {\n\t\t\tthis.inMemoryEntries = this.loadEntriesFromFile();\n\t\t} else {\n\t\t\tthis.inMemoryEntries = [];\n\t\t}\n\t\tthis.pendingEntries = [];\n\t}\n\n\t/**\n\t * Check if we should initialize the session based on message history.\n\t * Session is initialized when we have at least 1 user message and 1 assistant message.\n\t */\n\tshouldInitializeSession(messages: any[]): boolean {\n\t\tif (this.sessionInitialized) return false;\n\n\t\tconst userMessages = messages.filter((m) => m.role === \"user\");\n\t\tconst assistantMessages = messages.filter((m) => m.role === \"assistant\");\n\n\t\treturn userMessages.length >= 1 && assistantMessages.length >= 1;\n\t}\n\n\t/**\n\t * Create a branched session from a specific message index.\n\t * If branchFromIndex is -1, creates an empty session.\n\t * Returns the new session file path.\n\t */\n\tcreateBranchedSession(state: any, branchFromIndex: number): string {\n\t\t// Create a new session ID for the branch\n\t\tconst newSessionId = uuidv4();\n\t\tconst timestamp = new Date().toISOString().replace(/[:.]/g, \"-\");\n\t\tconst newSessionFile = join(this.sessionDir, `${timestamp}_${newSessionId}.jsonl`);\n\n\t\t// Write session header\n\t\tconst entry: SessionHeader = {\n\t\t\ttype: \"session\",\n\t\t\tid: newSessionId,\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tcwd: process.cwd(),\n\t\t\tprovider: state.model.provider,\n\t\t\tmodelId: state.model.id,\n\t\t\tthinkingLevel: state.thinkingLevel,\n\t\t\tbranchedFrom: this.sessionFile,\n\t\t};\n\t\tappendFileSync(newSessionFile, JSON.stringify(entry) + \"\\n\");\n\n\t\t// Write messages up to and including the branch point (if >= 0)\n\t\tif (branchFromIndex >= 0) {\n\t\t\tconst messagesToWrite = state.messages.slice(0, branchFromIndex + 1);\n\t\t\tfor (const message of messagesToWrite) {\n\t\t\t\tconst messageEntry: SessionMessageEntry = {\n\t\t\t\t\ttype: \"message\",\n\t\t\t\t\ttimestamp: new Date().toISOString(),\n\t\t\t\t\tmessage,\n\t\t\t\t};\n\t\t\t\tappendFileSync(newSessionFile, JSON.stringify(messageEntry) + \"\\n\");\n\t\t\t}\n\t\t}\n\n\t\treturn newSessionFile;\n\t}\n\n\t/**\n\t * Create a branched session from session entries up to (but not including) a specific entry index.\n\t * This preserves compaction events and all entry types.\n\t * Returns the new session file path, or null if in --no-session mode (in-memory only).\n\t */\n\tcreateBranchedSessionFromEntries(entries: SessionEntry[], branchBeforeIndex: number): string | null {\n\t\tconst newSessionId = uuidv4();\n\t\tconst timestamp = new Date().toISOString().replace(/[:.]/g, \"-\");\n\t\tconst newSessionFile = join(this.sessionDir, `${timestamp}_${newSessionId}.jsonl`);\n\n\t\t// Build new entries list (up to but not including branch point)\n\t\tconst newEntries: SessionEntry[] = [];\n\t\tfor (let i = 0; i < branchBeforeIndex; i++) {\n\t\t\tconst entry = entries[i];\n\n\t\t\tif (entry.type === \"session\") {\n\t\t\t\t// Rewrite session header with new ID and branchedFrom\n\t\t\t\tnewEntries.push({\n\t\t\t\t\t...entry,\n\t\t\t\t\tid: newSessionId,\n\t\t\t\t\ttimestamp: new Date().toISOString(),\n\t\t\t\t\tbranchedFrom: this.enabled ? this.sessionFile : undefined,\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\t// Copy other entries as-is\n\t\t\t\tnewEntries.push(entry);\n\t\t\t}\n\t\t}\n\n\t\tif (this.enabled) {\n\t\t\t// Write to file\n\t\t\tfor (const entry of newEntries) {\n\t\t\t\tappendFileSync(newSessionFile, JSON.stringify(entry) + \"\\n\");\n\t\t\t}\n\t\t\treturn newSessionFile;\n\t\t} else {\n\t\t\t// In-memory mode: replace inMemoryEntries, no file created\n\t\t\tthis.inMemoryEntries = newEntries;\n\t\t\tthis.sessionId = newSessionId;\n\t\t\treturn null;\n\t\t}\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"session-manager.js","sourceRoot":"","sources":["../../src/core/session-manager.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AgentState, AppMessage } from \"@mariozechner/pi-agent-core\";\nimport { randomBytes } from \"crypto\";\nimport { appendFileSync, existsSync, mkdirSync, readdirSync, readFileSync, statSync } from \"fs\";\nimport { join, resolve } from \"path\";\nimport { getAgentDir } from \"../config.js\";\n\nfunction uuidv4(): string {\n\tconst bytes = randomBytes(16);\n\tbytes[6] = (bytes[6] & 0x0f) | 0x40;\n\tbytes[8] = (bytes[8] & 0x3f) | 0x80;\n\tconst hex = bytes.toString(\"hex\");\n\treturn `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20, 32)}`;\n}\n\n// ============================================================================\n// Session entry types\n// ============================================================================\n\nexport interface SessionHeader {\n\ttype: \"session\";\n\tid: string;\n\ttimestamp: string;\n\tcwd: string;\n\tprovider: string;\n\tmodelId: string;\n\tthinkingLevel: string;\n\tbranchedFrom?: string;\n}\n\nexport interface SessionMessageEntry {\n\ttype: \"message\";\n\ttimestamp: string;\n\tmessage: AppMessage;\n}\n\nexport interface ThinkingLevelChangeEntry {\n\ttype: \"thinking_level_change\";\n\ttimestamp: string;\n\tthinkingLevel: string;\n}\n\nexport interface ModelChangeEntry {\n\ttype: \"model_change\";\n\ttimestamp: string;\n\tprovider: string;\n\tmodelId: string;\n}\n\nexport interface CompactionEntry {\n\ttype: \"compaction\";\n\ttimestamp: string;\n\tsummary: string;\n\tfirstKeptEntryIndex: number; // Index into session entries where we start keeping\n\ttokensBefore: number;\n}\n\n/** Union of all session entry types */\nexport type SessionEntry =\n\t| SessionHeader\n\t| SessionMessageEntry\n\t| ThinkingLevelChangeEntry\n\t| ModelChangeEntry\n\t| CompactionEntry;\n\n// ============================================================================\n// Session loading with compaction support\n// ============================================================================\n\nexport interface LoadedSession {\n\tmessages: AppMessage[];\n\tthinkingLevel: string;\n\tmodel: { provider: string; modelId: string } | null;\n}\n\nexport const SUMMARY_PREFIX = `The conversation history before this point was compacted into the following summary:\n\n<summary>\n`;\n\nexport const SUMMARY_SUFFIX = `\n</summary>`;\n\n/**\n * Create a user message containing the summary with the standard prefix.\n */\nexport function createSummaryMessage(summary: string): AppMessage {\n\treturn {\n\t\trole: \"user\",\n\t\tcontent: SUMMARY_PREFIX + summary + SUMMARY_SUFFIX,\n\t\ttimestamp: Date.now(),\n\t};\n}\n\n/**\n * Parse session file content into entries.\n */\nexport function parseSessionEntries(content: string): SessionEntry[] {\n\tconst entries: SessionEntry[] = [];\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 SessionEntry;\n\t\t\tentries.push(entry);\n\t\t} catch {\n\t\t\t// Skip malformed lines\n\t\t}\n\t}\n\n\treturn entries;\n}\n\n/**\n * Load session from entries, handling compaction events.\n *\n * Algorithm:\n * 1. Find latest compaction event (if any)\n * 2. Keep all entries from firstKeptEntryIndex onwards (extracting messages)\n * 3. Prepend summary as user message\n */\n/**\n * Get the latest compaction entry from session entries, if any.\n */\nexport function getLatestCompactionEntry(entries: SessionEntry[]): CompactionEntry | null {\n\tfor (let i = entries.length - 1; i >= 0; i--) {\n\t\tif (entries[i].type === \"compaction\") {\n\t\t\treturn entries[i] as CompactionEntry;\n\t\t}\n\t}\n\treturn null;\n}\n\nexport function loadSessionFromEntries(entries: SessionEntry[]): LoadedSession {\n\t// Find model and thinking level (always scan all entries)\n\tlet thinkingLevel = \"off\";\n\tlet model: { provider: string; modelId: string } | null = null;\n\n\tfor (const entry of entries) {\n\t\tif (entry.type === \"session\") {\n\t\t\tthinkingLevel = entry.thinkingLevel;\n\t\t\tmodel = { provider: entry.provider, modelId: entry.modelId };\n\t\t} else if (entry.type === \"thinking_level_change\") {\n\t\t\tthinkingLevel = entry.thinkingLevel;\n\t\t} else if (entry.type === \"model_change\") {\n\t\t\tmodel = { provider: entry.provider, modelId: entry.modelId };\n\t\t}\n\t}\n\n\t// Find latest compaction event\n\tlet latestCompactionIndex = -1;\n\tfor (let i = entries.length - 1; i >= 0; i--) {\n\t\tif (entries[i].type === \"compaction\") {\n\t\t\tlatestCompactionIndex = i;\n\t\t\tbreak;\n\t\t}\n\t}\n\n\t// No compaction: return all messages\n\tif (latestCompactionIndex === -1) {\n\t\tconst messages: AppMessage[] = [];\n\t\tfor (const entry of entries) {\n\t\t\tif (entry.type === \"message\") {\n\t\t\t\tmessages.push(entry.message);\n\t\t\t}\n\t\t}\n\t\treturn { messages, thinkingLevel, model };\n\t}\n\n\tconst compactionEvent = entries[latestCompactionIndex] as CompactionEntry;\n\n\t// Extract messages from firstKeptEntryIndex to end (skipping compaction entries)\n\tconst keptMessages: AppMessage[] = [];\n\tfor (let i = compactionEvent.firstKeptEntryIndex; i < entries.length; i++) {\n\t\tconst entry = entries[i];\n\t\tif (entry.type === \"message\") {\n\t\t\tkeptMessages.push(entry.message);\n\t\t}\n\t}\n\n\t// Build final messages: summary + kept messages\n\tconst messages: AppMessage[] = [];\n\tmessages.push(createSummaryMessage(compactionEvent.summary));\n\tmessages.push(...keptMessages);\n\n\treturn { messages, thinkingLevel, model };\n}\n\nexport class SessionManager {\n\tprivate sessionId!: string;\n\tprivate sessionFile!: string;\n\tprivate sessionDir: string;\n\tprivate enabled: boolean = true;\n\tprivate sessionInitialized: boolean = false;\n\tprivate pendingEntries: SessionEntry[] = [];\n\t// In-memory entries for --no-session mode (when enabled=false)\n\tprivate inMemoryEntries: SessionEntry[] = [];\n\n\tconstructor(continueSession: boolean = false, customSessionPath?: string) {\n\t\tthis.sessionDir = this.getSessionDirectory();\n\n\t\tif (customSessionPath) {\n\t\t\t// Use custom session file path\n\t\t\tthis.sessionFile = resolve(customSessionPath);\n\t\t\tthis.loadSessionId();\n\t\t\t// If file doesn't exist, loadSessionId() won't set sessionId, so generate one\n\t\t\tif (!this.sessionId) {\n\t\t\t\tthis.sessionId = uuidv4();\n\t\t\t}\n\t\t\t// Mark as initialized since we're loading an existing session\n\t\t\tthis.sessionInitialized = existsSync(this.sessionFile);\n\t\t\t// Load entries into memory\n\t\t\tif (this.sessionInitialized) {\n\t\t\t\tthis.inMemoryEntries = this.loadEntriesFromFile();\n\t\t\t}\n\t\t} else if (continueSession) {\n\t\t\tconst mostRecent = this.findMostRecentlyModifiedSession();\n\t\t\tif (mostRecent) {\n\t\t\t\tthis.sessionFile = mostRecent;\n\t\t\t\tthis.loadSessionId();\n\t\t\t\t// Mark as initialized since we're loading an existing session\n\t\t\t\tthis.sessionInitialized = true;\n\t\t\t\t// Load entries into memory\n\t\t\t\tthis.inMemoryEntries = this.loadEntriesFromFile();\n\t\t\t} else {\n\t\t\t\tthis.initNewSession();\n\t\t\t}\n\t\t} else {\n\t\t\tthis.initNewSession();\n\t\t}\n\t}\n\n\t/** Disable session saving (for --no-session mode) */\n\tdisable() {\n\t\tthis.enabled = false;\n\t}\n\n\t/** Check if session persistence is enabled */\n\tisEnabled(): boolean {\n\t\treturn this.enabled;\n\t}\n\n\tprivate getSessionDirectory(): string {\n\t\tconst cwd = process.cwd();\n\t\t// Replace all path separators and colons (for Windows drive letters) with dashes\n\t\tconst safePath = `--${cwd.replace(/^[/\\\\]/, \"\").replace(/[/\\\\:]/g, \"-\")}--`;\n\n\t\tconst configDir = getAgentDir();\n\t\tconst sessionDir = join(configDir, \"sessions\", safePath);\n\t\tif (!existsSync(sessionDir)) {\n\t\t\tmkdirSync(sessionDir, { recursive: true });\n\t\t}\n\t\treturn sessionDir;\n\t}\n\n\tprivate initNewSession(): void {\n\t\tthis.sessionId = uuidv4();\n\t\tconst timestamp = new Date().toISOString().replace(/[:.]/g, \"-\");\n\t\tthis.sessionFile = join(this.sessionDir, `${timestamp}_${this.sessionId}.jsonl`);\n\t}\n\n\t/** Reset to a fresh session. Clears pending entries and starts a new session file. */\n\treset(): void {\n\t\tthis.pendingEntries = [];\n\t\tthis.inMemoryEntries = [];\n\t\tthis.sessionInitialized = false;\n\t\tthis.initNewSession();\n\t}\n\n\tprivate findMostRecentlyModifiedSession(): string | null {\n\t\ttry {\n\t\t\tconst files = readdirSync(this.sessionDir)\n\t\t\t\t.filter((f) => f.endsWith(\".jsonl\"))\n\t\t\t\t.map((f) => ({\n\t\t\t\t\tname: f,\n\t\t\t\t\tpath: join(this.sessionDir, f),\n\t\t\t\t\tmtime: statSync(join(this.sessionDir, f)).mtime,\n\t\t\t\t}))\n\t\t\t\t.sort((a, b) => b.mtime.getTime() - a.mtime.getTime());\n\n\t\t\treturn files[0]?.path || null;\n\t\t} catch {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\tprivate loadSessionId(): void {\n\t\tif (!existsSync(this.sessionFile)) return;\n\n\t\tconst lines = readFileSync(this.sessionFile, \"utf8\").trim().split(\"\\n\");\n\t\tfor (const line of lines) {\n\t\t\ttry {\n\t\t\t\tconst entry = JSON.parse(line);\n\t\t\t\tif (entry.type === \"session\") {\n\t\t\t\t\tthis.sessionId = entry.id;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\t// Skip malformed lines\n\t\t\t}\n\t\t}\n\t\tthis.sessionId = uuidv4();\n\t}\n\n\tstartSession(state: AgentState): void {\n\t\tif (this.sessionInitialized) return;\n\t\tthis.sessionInitialized = true;\n\n\t\tconst entry: SessionHeader = {\n\t\t\ttype: \"session\",\n\t\t\tid: this.sessionId,\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tcwd: process.cwd(),\n\t\t\tprovider: state.model.provider,\n\t\t\tmodelId: state.model.id,\n\t\t\tthinkingLevel: state.thinkingLevel,\n\t\t};\n\n\t\t// Always track in memory\n\t\tthis.inMemoryEntries.push(entry);\n\t\tfor (const pending of this.pendingEntries) {\n\t\t\tthis.inMemoryEntries.push(pending);\n\t\t}\n\t\tthis.pendingEntries = [];\n\n\t\t// Write to file only if enabled\n\t\tif (this.enabled) {\n\t\t\tappendFileSync(this.sessionFile, `${JSON.stringify(entry)}\\n`);\n\t\t\tfor (const memEntry of this.inMemoryEntries.slice(1)) {\n\t\t\t\tappendFileSync(this.sessionFile, `${JSON.stringify(memEntry)}\\n`);\n\t\t\t}\n\t\t}\n\t}\n\n\tsaveMessage(message: any): void {\n\t\tconst entry: SessionMessageEntry = {\n\t\t\ttype: \"message\",\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tmessage,\n\t\t};\n\n\t\tif (!this.sessionInitialized) {\n\t\t\tthis.pendingEntries.push(entry);\n\t\t} else {\n\t\t\t// Always track in memory\n\t\t\tthis.inMemoryEntries.push(entry);\n\t\t\t// Write to file only if enabled\n\t\t\tif (this.enabled) {\n\t\t\t\tappendFileSync(this.sessionFile, `${JSON.stringify(entry)}\\n`);\n\t\t\t}\n\t\t}\n\t}\n\n\tsaveThinkingLevelChange(thinkingLevel: string): void {\n\t\tconst entry: ThinkingLevelChangeEntry = {\n\t\t\ttype: \"thinking_level_change\",\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tthinkingLevel,\n\t\t};\n\n\t\tif (!this.sessionInitialized) {\n\t\t\tthis.pendingEntries.push(entry);\n\t\t} else {\n\t\t\t// Always track in memory\n\t\t\tthis.inMemoryEntries.push(entry);\n\t\t\t// Write to file only if enabled\n\t\t\tif (this.enabled) {\n\t\t\t\tappendFileSync(this.sessionFile, `${JSON.stringify(entry)}\\n`);\n\t\t\t}\n\t\t}\n\t}\n\n\tsaveModelChange(provider: string, modelId: string): void {\n\t\tconst entry: ModelChangeEntry = {\n\t\t\ttype: \"model_change\",\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tprovider,\n\t\t\tmodelId,\n\t\t};\n\n\t\tif (!this.sessionInitialized) {\n\t\t\tthis.pendingEntries.push(entry);\n\t\t} else {\n\t\t\t// Always track in memory\n\t\t\tthis.inMemoryEntries.push(entry);\n\t\t\t// Write to file only if enabled\n\t\t\tif (this.enabled) {\n\t\t\t\tappendFileSync(this.sessionFile, `${JSON.stringify(entry)}\\n`);\n\t\t\t}\n\t\t}\n\t}\n\n\tsaveCompaction(entry: CompactionEntry): void {\n\t\t// Always track in memory\n\t\tthis.inMemoryEntries.push(entry);\n\t\t// Write to file only if enabled\n\t\tif (this.enabled) {\n\t\t\tappendFileSync(this.sessionFile, `${JSON.stringify(entry)}\\n`);\n\t\t}\n\t}\n\n\t/**\n\t * Load session data (messages, model, thinking level) with compaction support.\n\t */\n\tloadSession(): LoadedSession {\n\t\tconst entries = this.loadEntries();\n\t\treturn loadSessionFromEntries(entries);\n\t}\n\n\t/**\n\t * @deprecated Use loadSession().messages instead\n\t */\n\tloadMessages(): AppMessage[] {\n\t\treturn this.loadSession().messages;\n\t}\n\n\t/**\n\t * @deprecated Use loadSession().thinkingLevel instead\n\t */\n\tloadThinkingLevel(): string {\n\t\treturn this.loadSession().thinkingLevel;\n\t}\n\n\t/**\n\t * @deprecated Use loadSession().model instead\n\t */\n\tloadModel(): { provider: string; modelId: string } | null {\n\t\treturn this.loadSession().model;\n\t}\n\n\tgetSessionId(): string {\n\t\treturn this.sessionId;\n\t}\n\n\tgetSessionFile(): string {\n\t\treturn this.sessionFile;\n\t}\n\n\t/**\n\t * Load entries directly from the session file (internal helper).\n\t */\n\tprivate loadEntriesFromFile(): SessionEntry[] {\n\t\tif (!existsSync(this.sessionFile)) return [];\n\n\t\tconst content = readFileSync(this.sessionFile, \"utf8\");\n\t\tconst entries: SessionEntry[] = [];\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\tconst entry = JSON.parse(line) as SessionEntry;\n\t\t\t\tentries.push(entry);\n\t\t\t} catch {\n\t\t\t\t// Skip malformed lines\n\t\t\t}\n\t\t}\n\n\t\treturn entries;\n\t}\n\n\t/**\n\t * Load all entries from the session file or in-memory store.\n\t * When file persistence is enabled, reads from file (source of truth for resumed sessions).\n\t * When disabled (--no-session), returns in-memory entries.\n\t */\n\tloadEntries(): SessionEntry[] {\n\t\t// If file persistence is enabled and file exists, read from file\n\t\tif (this.enabled && existsSync(this.sessionFile)) {\n\t\t\treturn this.loadEntriesFromFile();\n\t\t}\n\n\t\t// Otherwise return in-memory entries (for --no-session mode)\n\t\treturn [...this.inMemoryEntries];\n\t}\n\n\t/**\n\t * Load all sessions for the current directory with metadata\n\t */\n\tloadAllSessions(): Array<{\n\t\tpath: string;\n\t\tid: string;\n\t\tcreated: Date;\n\t\tmodified: Date;\n\t\tmessageCount: number;\n\t\tfirstMessage: string;\n\t\tallMessagesText: string;\n\t}> {\n\t\tconst sessions: Array<{\n\t\t\tpath: string;\n\t\t\tid: string;\n\t\t\tcreated: Date;\n\t\t\tmodified: Date;\n\t\t\tmessageCount: number;\n\t\t\tfirstMessage: string;\n\t\t\tallMessagesText: string;\n\t\t}> = [];\n\n\t\ttry {\n\t\t\tconst files = readdirSync(this.sessionDir)\n\t\t\t\t.filter((f) => f.endsWith(\".jsonl\"))\n\t\t\t\t.map((f) => join(this.sessionDir, f));\n\n\t\t\tfor (const file of files) {\n\t\t\t\ttry {\n\t\t\t\t\tconst stats = statSync(file);\n\t\t\t\t\tconst content = readFileSync(file, \"utf8\");\n\t\t\t\t\tconst lines = content.trim().split(\"\\n\");\n\n\t\t\t\t\tlet sessionId = \"\";\n\t\t\t\t\tlet created = stats.birthtime;\n\t\t\t\t\tlet messageCount = 0;\n\t\t\t\t\tlet firstMessage = \"\";\n\t\t\t\t\tconst allMessages: string[] = [];\n\n\t\t\t\t\tfor (const line of lines) {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst entry = JSON.parse(line);\n\n\t\t\t\t\t\t\t// Extract session ID from first session entry\n\t\t\t\t\t\t\tif (entry.type === \"session\" && !sessionId) {\n\t\t\t\t\t\t\t\tsessionId = entry.id;\n\t\t\t\t\t\t\t\tcreated = new Date(entry.timestamp);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// Count messages and collect all text\n\t\t\t\t\t\t\tif (entry.type === \"message\") {\n\t\t\t\t\t\t\t\tmessageCount++;\n\n\t\t\t\t\t\t\t\t// Extract text from user and assistant messages\n\t\t\t\t\t\t\t\tif (entry.message.role === \"user\" || entry.message.role === \"assistant\") {\n\t\t\t\t\t\t\t\t\tconst textContent = entry.message.content\n\t\t\t\t\t\t\t\t\t\t.filter((c: any) => c.type === \"text\")\n\t\t\t\t\t\t\t\t\t\t.map((c: any) => c.text)\n\t\t\t\t\t\t\t\t\t\t.join(\" \");\n\n\t\t\t\t\t\t\t\t\tif (textContent) {\n\t\t\t\t\t\t\t\t\t\tallMessages.push(textContent);\n\n\t\t\t\t\t\t\t\t\t\t// Get first user message for display\n\t\t\t\t\t\t\t\t\t\tif (!firstMessage && entry.message.role === \"user\") {\n\t\t\t\t\t\t\t\t\t\t\tfirstMessage = textContent;\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t// Skip malformed lines\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tsessions.push({\n\t\t\t\t\t\tpath: file,\n\t\t\t\t\t\tid: sessionId || \"unknown\",\n\t\t\t\t\t\tcreated,\n\t\t\t\t\t\tmodified: stats.mtime,\n\t\t\t\t\t\tmessageCount,\n\t\t\t\t\t\tfirstMessage: firstMessage || \"(no messages)\",\n\t\t\t\t\t\tallMessagesText: allMessages.join(\" \"),\n\t\t\t\t\t});\n\t\t\t\t} catch (error) {\n\t\t\t\t\t// Skip files that can't be read\n\t\t\t\t\tconsole.error(`Failed to read session file ${file}:`, error);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Sort by modified date (most recent first)\n\t\t\tsessions.sort((a, b) => b.modified.getTime() - a.modified.getTime());\n\t\t} catch (error) {\n\t\t\tconsole.error(\"Failed to load sessions:\", error);\n\t\t}\n\n\t\treturn sessions;\n\t}\n\n\t/**\n\t * Set the session file to an existing session\n\t */\n\tsetSessionFile(path: string): void {\n\t\tthis.sessionFile = path;\n\t\tthis.loadSessionId();\n\t\t// Mark as initialized since we're loading an existing session\n\t\tthis.sessionInitialized = existsSync(path);\n\t\t// Load entries into memory for consistency\n\t\tif (this.sessionInitialized) {\n\t\t\tthis.inMemoryEntries = this.loadEntriesFromFile();\n\t\t} else {\n\t\t\tthis.inMemoryEntries = [];\n\t\t}\n\t\tthis.pendingEntries = [];\n\t}\n\n\t/**\n\t * Check if we should initialize the session based on message history.\n\t * Session is initialized when we have at least 1 user message and 1 assistant message.\n\t */\n\tshouldInitializeSession(messages: any[]): boolean {\n\t\tif (this.sessionInitialized) return false;\n\n\t\tconst userMessages = messages.filter((m) => m.role === \"user\");\n\t\tconst assistantMessages = messages.filter((m) => m.role === \"assistant\");\n\n\t\treturn userMessages.length >= 1 && assistantMessages.length >= 1;\n\t}\n\n\t/**\n\t * Create a branched session from a specific message index.\n\t * If branchFromIndex is -1, creates an empty session.\n\t * Returns the new session file path.\n\t */\n\tcreateBranchedSession(state: any, branchFromIndex: number): string {\n\t\t// Create a new session ID for the branch\n\t\tconst newSessionId = uuidv4();\n\t\tconst timestamp = new Date().toISOString().replace(/[:.]/g, \"-\");\n\t\tconst newSessionFile = join(this.sessionDir, `${timestamp}_${newSessionId}.jsonl`);\n\n\t\t// Write session header\n\t\tconst entry: SessionHeader = {\n\t\t\ttype: \"session\",\n\t\t\tid: newSessionId,\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tcwd: process.cwd(),\n\t\t\tprovider: state.model.provider,\n\t\t\tmodelId: state.model.id,\n\t\t\tthinkingLevel: state.thinkingLevel,\n\t\t\tbranchedFrom: this.sessionFile,\n\t\t};\n\t\tappendFileSync(newSessionFile, `${JSON.stringify(entry)}\\n`);\n\n\t\t// Write messages up to and including the branch point (if >= 0)\n\t\tif (branchFromIndex >= 0) {\n\t\t\tconst messagesToWrite = state.messages.slice(0, branchFromIndex + 1);\n\t\t\tfor (const message of messagesToWrite) {\n\t\t\t\tconst messageEntry: SessionMessageEntry = {\n\t\t\t\t\ttype: \"message\",\n\t\t\t\t\ttimestamp: new Date().toISOString(),\n\t\t\t\t\tmessage,\n\t\t\t\t};\n\t\t\t\tappendFileSync(newSessionFile, `${JSON.stringify(messageEntry)}\\n`);\n\t\t\t}\n\t\t}\n\n\t\treturn newSessionFile;\n\t}\n\n\t/**\n\t * Create a branched session from session entries up to (but not including) a specific entry index.\n\t * This preserves compaction events and all entry types.\n\t * Returns the new session file path, or null if in --no-session mode (in-memory only).\n\t */\n\tcreateBranchedSessionFromEntries(entries: SessionEntry[], branchBeforeIndex: number): string | null {\n\t\tconst newSessionId = uuidv4();\n\t\tconst timestamp = new Date().toISOString().replace(/[:.]/g, \"-\");\n\t\tconst newSessionFile = join(this.sessionDir, `${timestamp}_${newSessionId}.jsonl`);\n\n\t\t// Build new entries list (up to but not including branch point)\n\t\tconst newEntries: SessionEntry[] = [];\n\t\tfor (let i = 0; i < branchBeforeIndex; i++) {\n\t\t\tconst entry = entries[i];\n\n\t\t\tif (entry.type === \"session\") {\n\t\t\t\t// Rewrite session header with new ID and branchedFrom\n\t\t\t\tnewEntries.push({\n\t\t\t\t\t...entry,\n\t\t\t\t\tid: newSessionId,\n\t\t\t\t\ttimestamp: new Date().toISOString(),\n\t\t\t\t\tbranchedFrom: this.enabled ? this.sessionFile : undefined,\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\t// Copy other entries as-is\n\t\t\t\tnewEntries.push(entry);\n\t\t\t}\n\t\t}\n\n\t\tif (this.enabled) {\n\t\t\t// Write to file\n\t\t\tfor (const entry of newEntries) {\n\t\t\t\tappendFileSync(newSessionFile, `${JSON.stringify(entry)}\\n`);\n\t\t\t}\n\t\t\treturn newSessionFile;\n\t\t} else {\n\t\t\t// In-memory mode: replace inMemoryEntries, no file created\n\t\t\tthis.inMemoryEntries = newEntries;\n\t\t\tthis.sessionId = newSessionId;\n\t\t\treturn null;\n\t\t}\n\t}\n}\n"]}
|
|
@@ -10,6 +10,14 @@ export interface RetrySettings {
|
|
|
10
10
|
}
|
|
11
11
|
export interface SkillsSettings {
|
|
12
12
|
enabled?: boolean;
|
|
13
|
+
enableCodexUser?: boolean;
|
|
14
|
+
enableClaudeUser?: boolean;
|
|
15
|
+
enableClaudeProject?: boolean;
|
|
16
|
+
enablePiUser?: boolean;
|
|
17
|
+
enablePiProject?: boolean;
|
|
18
|
+
customDirectories?: string[];
|
|
19
|
+
ignoredSkills?: string[];
|
|
20
|
+
includeSkills?: string[];
|
|
13
21
|
}
|
|
14
22
|
export interface TerminalSettings {
|
|
15
23
|
showImages?: boolean;
|
|
@@ -81,6 +89,7 @@ export declare class SettingsManager {
|
|
|
81
89
|
setCustomToolPaths(paths: string[]): void;
|
|
82
90
|
getSkillsEnabled(): boolean;
|
|
83
91
|
setSkillsEnabled(enabled: boolean): void;
|
|
92
|
+
getSkillsSettings(): Required<SkillsSettings>;
|
|
84
93
|
getShowImages(): boolean;
|
|
85
94
|
setShowImages(show: boolean): void;
|
|
86
95
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"settings-manager.d.ts","sourceRoot":"","sources":["../../src/core/settings-manager.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,kBAAkB;IAClC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,aAAa;IAC7B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,cAAc;IAC9B,OAAO,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,gBAAgB;IAChC,UAAU,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,QAAQ;IACxB,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,oBAAoB,CAAC,EAAE,KAAK,GAAG,SAAS,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,CAAC;IAC/E,SAAS,CAAC,EAAE,KAAK,GAAG,eAAe,CAAC;IACpC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,kBAAkB,CAAC;IAChC,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,MAAM,CAAC,EAAE,cAAc,CAAC;IACxB,QAAQ,CAAC,EAAE,gBAAgB,CAAC;CAC5B;AAED,qBAAa,eAAe;IAC3B,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,QAAQ,CAAW;IAE3B,YAAY,OAAO,CAAC,EAAE,MAAM,EAI3B;IAED,OAAO,CAAC,IAAI;IAcZ,OAAO,CAAC,IAAI;IAcZ,uBAAuB,IAAI,MAAM,GAAG,SAAS,CAE5C;IAED,uBAAuB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAG7C;IAED,kBAAkB,IAAI,MAAM,GAAG,SAAS,CAEvC;IAED,eAAe,IAAI,MAAM,GAAG,SAAS,CAEpC;IAED,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAGzC;IAED,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAGrC;IAED,0BAA0B,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAIlE;IAED,YAAY,IAAI,KAAK,GAAG,eAAe,CAEtC;IAED,YAAY,CAAC,IAAI,EAAE,KAAK,GAAG,eAAe,GAAG,IAAI,CAGhD;IAED,QAAQ,IAAI,MAAM,GAAG,SAAS,CAE7B;IAED,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAG5B;IAED,uBAAuB,IAAI,KAAK,GAAG,SAAS,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,CAE7F;IAED,uBAAuB,CAAC,KAAK,EAAE,KAAK,GAAG,SAAS,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,CAG5F;IAED,oBAAoB,IAAI,OAAO,CAE9B;IAED,oBAAoB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAM3C;IAED,0BAA0B,IAAI,MAAM,CAEnC;IAED,6BAA6B,IAAI,MAAM,CAEtC;IAED,qBAAqB,IAAI;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,aAAa,EAAE,MAAM,CAAC;QAAC,gBAAgB,EAAE,MAAM,CAAA;KAAE,CAM7F;IAED,eAAe,IAAI,OAAO,CAEzB;IAED,eAAe,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAMtC;IAED,gBAAgB,IAAI;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAMhF;IAED,oBAAoB,IAAI,OAAO,CAE9B;IAED,oBAAoB,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CAGxC;IAED,YAAY,IAAI,MAAM,GAAG,SAAS,CAEjC;IAED,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAG3C;IAED,oBAAoB,IAAI,OAAO,CAE9B;IAED,oBAAoB,CAAC,QAAQ,EAAE,OAAO,GAAG,IAAI,CAG5C;IAED,YAAY,IAAI,MAAM,EAAE,CAEvB;IAED,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,CAGlC;IAED,cAAc,IAAI,MAAM,CAEvB;IAED,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAGpC;IAED,kBAAkB,IAAI,MAAM,EAAE,CAE7B;IAED,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,CAGxC;IAED,gBAAgB,IAAI,OAAO,CAE1B;IAED,gBAAgB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAMvC;IAED,aAAa,IAAI,OAAO,CAEvB;IAED,aAAa,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CAMjC;CACD","sourcesContent":["import { existsSync, mkdirSync, readFileSync, writeFileSync } from \"fs\";\nimport { dirname, join } from \"path\";\nimport { getAgentDir } from \"../config.js\";\n\nexport interface CompactionSettings {\n\tenabled?: boolean; // default: true\n\treserveTokens?: number; // default: 16384\n\tkeepRecentTokens?: number; // default: 20000\n}\n\nexport interface RetrySettings {\n\tenabled?: boolean; // default: true\n\tmaxRetries?: number; // default: 3\n\tbaseDelayMs?: number; // default: 2000 (exponential backoff: 2s, 4s, 8s)\n}\n\nexport interface SkillsSettings {\n\tenabled?: boolean; // default: true\n}\n\nexport interface TerminalSettings {\n\tshowImages?: boolean; // default: true (only relevant if terminal supports images)\n}\n\nexport interface Settings {\n\tlastChangelogVersion?: string;\n\tdefaultProvider?: string;\n\tdefaultModel?: string;\n\tdefaultThinkingLevel?: \"off\" | \"minimal\" | \"low\" | \"medium\" | \"high\" | \"xhigh\";\n\tqueueMode?: \"all\" | \"one-at-a-time\";\n\ttheme?: string;\n\tcompaction?: CompactionSettings;\n\tretry?: RetrySettings;\n\thideThinkingBlock?: boolean;\n\tshellPath?: string; // Custom shell path (e.g., for Cygwin users on Windows)\n\tcollapseChangelog?: boolean; // Show condensed changelog after update (use /changelog for full)\n\thooks?: string[]; // Array of hook file paths\n\thookTimeout?: number; // Timeout for hook execution in ms (default: 30000)\n\tcustomTools?: string[]; // Array of custom tool file paths\n\tskills?: SkillsSettings;\n\tterminal?: TerminalSettings;\n}\n\nexport class SettingsManager {\n\tprivate settingsPath: string;\n\tprivate settings: Settings;\n\n\tconstructor(baseDir?: string) {\n\t\tconst dir = baseDir || getAgentDir();\n\t\tthis.settingsPath = join(dir, \"settings.json\");\n\t\tthis.settings = this.load();\n\t}\n\n\tprivate load(): Settings {\n\t\tif (!existsSync(this.settingsPath)) {\n\t\t\treturn {};\n\t\t}\n\n\t\ttry {\n\t\t\tconst content = readFileSync(this.settingsPath, \"utf-8\");\n\t\t\treturn JSON.parse(content);\n\t\t} catch (error) {\n\t\t\tconsole.error(`Warning: Could not read settings file: ${error}`);\n\t\t\treturn {};\n\t\t}\n\t}\n\n\tprivate save(): void {\n\t\ttry {\n\t\t\t// Ensure directory exists\n\t\t\tconst dir = dirname(this.settingsPath);\n\t\t\tif (!existsSync(dir)) {\n\t\t\t\tmkdirSync(dir, { recursive: true });\n\t\t\t}\n\n\t\t\twriteFileSync(this.settingsPath, JSON.stringify(this.settings, null, 2), \"utf-8\");\n\t\t} catch (error) {\n\t\t\tconsole.error(`Warning: Could not save settings file: ${error}`);\n\t\t}\n\t}\n\n\tgetLastChangelogVersion(): string | undefined {\n\t\treturn this.settings.lastChangelogVersion;\n\t}\n\n\tsetLastChangelogVersion(version: string): void {\n\t\tthis.settings.lastChangelogVersion = version;\n\t\tthis.save();\n\t}\n\n\tgetDefaultProvider(): string | undefined {\n\t\treturn this.settings.defaultProvider;\n\t}\n\n\tgetDefaultModel(): string | undefined {\n\t\treturn this.settings.defaultModel;\n\t}\n\n\tsetDefaultProvider(provider: string): void {\n\t\tthis.settings.defaultProvider = provider;\n\t\tthis.save();\n\t}\n\n\tsetDefaultModel(modelId: string): void {\n\t\tthis.settings.defaultModel = modelId;\n\t\tthis.save();\n\t}\n\n\tsetDefaultModelAndProvider(provider: string, modelId: string): void {\n\t\tthis.settings.defaultProvider = provider;\n\t\tthis.settings.defaultModel = modelId;\n\t\tthis.save();\n\t}\n\n\tgetQueueMode(): \"all\" | \"one-at-a-time\" {\n\t\treturn this.settings.queueMode || \"one-at-a-time\";\n\t}\n\n\tsetQueueMode(mode: \"all\" | \"one-at-a-time\"): void {\n\t\tthis.settings.queueMode = mode;\n\t\tthis.save();\n\t}\n\n\tgetTheme(): string | undefined {\n\t\treturn this.settings.theme;\n\t}\n\n\tsetTheme(theme: string): void {\n\t\tthis.settings.theme = theme;\n\t\tthis.save();\n\t}\n\n\tgetDefaultThinkingLevel(): \"off\" | \"minimal\" | \"low\" | \"medium\" | \"high\" | \"xhigh\" | undefined {\n\t\treturn this.settings.defaultThinkingLevel;\n\t}\n\n\tsetDefaultThinkingLevel(level: \"off\" | \"minimal\" | \"low\" | \"medium\" | \"high\" | \"xhigh\"): void {\n\t\tthis.settings.defaultThinkingLevel = level;\n\t\tthis.save();\n\t}\n\n\tgetCompactionEnabled(): boolean {\n\t\treturn this.settings.compaction?.enabled ?? true;\n\t}\n\n\tsetCompactionEnabled(enabled: boolean): void {\n\t\tif (!this.settings.compaction) {\n\t\t\tthis.settings.compaction = {};\n\t\t}\n\t\tthis.settings.compaction.enabled = enabled;\n\t\tthis.save();\n\t}\n\n\tgetCompactionReserveTokens(): number {\n\t\treturn this.settings.compaction?.reserveTokens ?? 16384;\n\t}\n\n\tgetCompactionKeepRecentTokens(): number {\n\t\treturn this.settings.compaction?.keepRecentTokens ?? 20000;\n\t}\n\n\tgetCompactionSettings(): { enabled: boolean; reserveTokens: number; keepRecentTokens: number } {\n\t\treturn {\n\t\t\tenabled: this.getCompactionEnabled(),\n\t\t\treserveTokens: this.getCompactionReserveTokens(),\n\t\t\tkeepRecentTokens: this.getCompactionKeepRecentTokens(),\n\t\t};\n\t}\n\n\tgetRetryEnabled(): boolean {\n\t\treturn this.settings.retry?.enabled ?? true;\n\t}\n\n\tsetRetryEnabled(enabled: boolean): void {\n\t\tif (!this.settings.retry) {\n\t\t\tthis.settings.retry = {};\n\t\t}\n\t\tthis.settings.retry.enabled = enabled;\n\t\tthis.save();\n\t}\n\n\tgetRetrySettings(): { enabled: boolean; maxRetries: number; baseDelayMs: number } {\n\t\treturn {\n\t\t\tenabled: this.getRetryEnabled(),\n\t\t\tmaxRetries: this.settings.retry?.maxRetries ?? 3,\n\t\t\tbaseDelayMs: this.settings.retry?.baseDelayMs ?? 2000,\n\t\t};\n\t}\n\n\tgetHideThinkingBlock(): boolean {\n\t\treturn this.settings.hideThinkingBlock ?? false;\n\t}\n\n\tsetHideThinkingBlock(hide: boolean): void {\n\t\tthis.settings.hideThinkingBlock = hide;\n\t\tthis.save();\n\t}\n\n\tgetShellPath(): string | undefined {\n\t\treturn this.settings.shellPath;\n\t}\n\n\tsetShellPath(path: string | undefined): void {\n\t\tthis.settings.shellPath = path;\n\t\tthis.save();\n\t}\n\n\tgetCollapseChangelog(): boolean {\n\t\treturn this.settings.collapseChangelog ?? false;\n\t}\n\n\tsetCollapseChangelog(collapse: boolean): void {\n\t\tthis.settings.collapseChangelog = collapse;\n\t\tthis.save();\n\t}\n\n\tgetHookPaths(): string[] {\n\t\treturn this.settings.hooks ?? [];\n\t}\n\n\tsetHookPaths(paths: string[]): void {\n\t\tthis.settings.hooks = paths;\n\t\tthis.save();\n\t}\n\n\tgetHookTimeout(): number {\n\t\treturn this.settings.hookTimeout ?? 30000;\n\t}\n\n\tsetHookTimeout(timeout: number): void {\n\t\tthis.settings.hookTimeout = timeout;\n\t\tthis.save();\n\t}\n\n\tgetCustomToolPaths(): string[] {\n\t\treturn this.settings.customTools ?? [];\n\t}\n\n\tsetCustomToolPaths(paths: string[]): void {\n\t\tthis.settings.customTools = paths;\n\t\tthis.save();\n\t}\n\n\tgetSkillsEnabled(): boolean {\n\t\treturn this.settings.skills?.enabled ?? true;\n\t}\n\n\tsetSkillsEnabled(enabled: boolean): void {\n\t\tif (!this.settings.skills) {\n\t\t\tthis.settings.skills = {};\n\t\t}\n\t\tthis.settings.skills.enabled = enabled;\n\t\tthis.save();\n\t}\n\n\tgetShowImages(): boolean {\n\t\treturn this.settings.terminal?.showImages ?? true;\n\t}\n\n\tsetShowImages(show: boolean): void {\n\t\tif (!this.settings.terminal) {\n\t\t\tthis.settings.terminal = {};\n\t\t}\n\t\tthis.settings.terminal.showImages = show;\n\t\tthis.save();\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"settings-manager.d.ts","sourceRoot":"","sources":["../../src/core/settings-manager.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync, mkdirSync, readFileSync, writeFileSync } from \"fs\";\nimport { dirname, join } from \"path\";\nimport { getAgentDir } from \"../config.js\";\n\nexport interface CompactionSettings {\n\tenabled?: boolean; // default: true\n\treserveTokens?: number; // default: 16384\n\tkeepRecentTokens?: number; // default: 20000\n}\n\nexport interface RetrySettings {\n\tenabled?: boolean; // default: true\n\tmaxRetries?: number; // default: 3\n\tbaseDelayMs?: number; // default: 2000 (exponential backoff: 2s, 4s, 8s)\n}\n\nexport interface SkillsSettings {\n\tenabled?: boolean; // default: true\n\tenableCodexUser?: boolean; // default: true\n\tenableClaudeUser?: boolean; // default: true\n\tenableClaudeProject?: boolean; // default: true\n\tenablePiUser?: boolean; // default: true\n\tenablePiProject?: boolean; // default: true\n\tcustomDirectories?: string[]; // default: []\n\tignoredSkills?: string[]; // default: [] (glob patterns to exclude; takes precedence over includeSkills)\n\tincludeSkills?: string[]; // default: [] (empty = include all; glob patterns to filter)\n}\n\nexport interface TerminalSettings {\n\tshowImages?: boolean; // default: true (only relevant if terminal supports images)\n}\n\nexport interface Settings {\n\tlastChangelogVersion?: string;\n\tdefaultProvider?: string;\n\tdefaultModel?: string;\n\tdefaultThinkingLevel?: \"off\" | \"minimal\" | \"low\" | \"medium\" | \"high\" | \"xhigh\";\n\tqueueMode?: \"all\" | \"one-at-a-time\";\n\ttheme?: string;\n\tcompaction?: CompactionSettings;\n\tretry?: RetrySettings;\n\thideThinkingBlock?: boolean;\n\tshellPath?: string; // Custom shell path (e.g., for Cygwin users on Windows)\n\tcollapseChangelog?: boolean; // Show condensed changelog after update (use /changelog for full)\n\thooks?: string[]; // Array of hook file paths\n\thookTimeout?: number; // Timeout for hook execution in ms (default: 30000)\n\tcustomTools?: string[]; // Array of custom tool file paths\n\tskills?: SkillsSettings;\n\tterminal?: TerminalSettings;\n}\n\nexport class SettingsManager {\n\tprivate settingsPath: string;\n\tprivate settings: Settings;\n\n\tconstructor(baseDir?: string) {\n\t\tconst dir = baseDir || getAgentDir();\n\t\tthis.settingsPath = join(dir, \"settings.json\");\n\t\tthis.settings = this.load();\n\t}\n\n\tprivate load(): Settings {\n\t\tif (!existsSync(this.settingsPath)) {\n\t\t\treturn {};\n\t\t}\n\n\t\ttry {\n\t\t\tconst content = readFileSync(this.settingsPath, \"utf-8\");\n\t\t\treturn JSON.parse(content);\n\t\t} catch (error) {\n\t\t\tconsole.error(`Warning: Could not read settings file: ${error}`);\n\t\t\treturn {};\n\t\t}\n\t}\n\n\tprivate save(): void {\n\t\ttry {\n\t\t\t// Ensure directory exists\n\t\t\tconst dir = dirname(this.settingsPath);\n\t\t\tif (!existsSync(dir)) {\n\t\t\t\tmkdirSync(dir, { recursive: true });\n\t\t\t}\n\n\t\t\twriteFileSync(this.settingsPath, JSON.stringify(this.settings, null, 2), \"utf-8\");\n\t\t} catch (error) {\n\t\t\tconsole.error(`Warning: Could not save settings file: ${error}`);\n\t\t}\n\t}\n\n\tgetLastChangelogVersion(): string | undefined {\n\t\treturn this.settings.lastChangelogVersion;\n\t}\n\n\tsetLastChangelogVersion(version: string): void {\n\t\tthis.settings.lastChangelogVersion = version;\n\t\tthis.save();\n\t}\n\n\tgetDefaultProvider(): string | undefined {\n\t\treturn this.settings.defaultProvider;\n\t}\n\n\tgetDefaultModel(): string | undefined {\n\t\treturn this.settings.defaultModel;\n\t}\n\n\tsetDefaultProvider(provider: string): void {\n\t\tthis.settings.defaultProvider = provider;\n\t\tthis.save();\n\t}\n\n\tsetDefaultModel(modelId: string): void {\n\t\tthis.settings.defaultModel = modelId;\n\t\tthis.save();\n\t}\n\n\tsetDefaultModelAndProvider(provider: string, modelId: string): void {\n\t\tthis.settings.defaultProvider = provider;\n\t\tthis.settings.defaultModel = modelId;\n\t\tthis.save();\n\t}\n\n\tgetQueueMode(): \"all\" | \"one-at-a-time\" {\n\t\treturn this.settings.queueMode || \"one-at-a-time\";\n\t}\n\n\tsetQueueMode(mode: \"all\" | \"one-at-a-time\"): void {\n\t\tthis.settings.queueMode = mode;\n\t\tthis.save();\n\t}\n\n\tgetTheme(): string | undefined {\n\t\treturn this.settings.theme;\n\t}\n\n\tsetTheme(theme: string): void {\n\t\tthis.settings.theme = theme;\n\t\tthis.save();\n\t}\n\n\tgetDefaultThinkingLevel(): \"off\" | \"minimal\" | \"low\" | \"medium\" | \"high\" | \"xhigh\" | undefined {\n\t\treturn this.settings.defaultThinkingLevel;\n\t}\n\n\tsetDefaultThinkingLevel(level: \"off\" | \"minimal\" | \"low\" | \"medium\" | \"high\" | \"xhigh\"): void {\n\t\tthis.settings.defaultThinkingLevel = level;\n\t\tthis.save();\n\t}\n\n\tgetCompactionEnabled(): boolean {\n\t\treturn this.settings.compaction?.enabled ?? true;\n\t}\n\n\tsetCompactionEnabled(enabled: boolean): void {\n\t\tif (!this.settings.compaction) {\n\t\t\tthis.settings.compaction = {};\n\t\t}\n\t\tthis.settings.compaction.enabled = enabled;\n\t\tthis.save();\n\t}\n\n\tgetCompactionReserveTokens(): number {\n\t\treturn this.settings.compaction?.reserveTokens ?? 16384;\n\t}\n\n\tgetCompactionKeepRecentTokens(): number {\n\t\treturn this.settings.compaction?.keepRecentTokens ?? 20000;\n\t}\n\n\tgetCompactionSettings(): { enabled: boolean; reserveTokens: number; keepRecentTokens: number } {\n\t\treturn {\n\t\t\tenabled: this.getCompactionEnabled(),\n\t\t\treserveTokens: this.getCompactionReserveTokens(),\n\t\t\tkeepRecentTokens: this.getCompactionKeepRecentTokens(),\n\t\t};\n\t}\n\n\tgetRetryEnabled(): boolean {\n\t\treturn this.settings.retry?.enabled ?? true;\n\t}\n\n\tsetRetryEnabled(enabled: boolean): void {\n\t\tif (!this.settings.retry) {\n\t\t\tthis.settings.retry = {};\n\t\t}\n\t\tthis.settings.retry.enabled = enabled;\n\t\tthis.save();\n\t}\n\n\tgetRetrySettings(): { enabled: boolean; maxRetries: number; baseDelayMs: number } {\n\t\treturn {\n\t\t\tenabled: this.getRetryEnabled(),\n\t\t\tmaxRetries: this.settings.retry?.maxRetries ?? 3,\n\t\t\tbaseDelayMs: this.settings.retry?.baseDelayMs ?? 2000,\n\t\t};\n\t}\n\n\tgetHideThinkingBlock(): boolean {\n\t\treturn this.settings.hideThinkingBlock ?? false;\n\t}\n\n\tsetHideThinkingBlock(hide: boolean): void {\n\t\tthis.settings.hideThinkingBlock = hide;\n\t\tthis.save();\n\t}\n\n\tgetShellPath(): string | undefined {\n\t\treturn this.settings.shellPath;\n\t}\n\n\tsetShellPath(path: string | undefined): void {\n\t\tthis.settings.shellPath = path;\n\t\tthis.save();\n\t}\n\n\tgetCollapseChangelog(): boolean {\n\t\treturn this.settings.collapseChangelog ?? false;\n\t}\n\n\tsetCollapseChangelog(collapse: boolean): void {\n\t\tthis.settings.collapseChangelog = collapse;\n\t\tthis.save();\n\t}\n\n\tgetHookPaths(): string[] {\n\t\treturn this.settings.hooks ?? [];\n\t}\n\n\tsetHookPaths(paths: string[]): void {\n\t\tthis.settings.hooks = paths;\n\t\tthis.save();\n\t}\n\n\tgetHookTimeout(): number {\n\t\treturn this.settings.hookTimeout ?? 30000;\n\t}\n\n\tsetHookTimeout(timeout: number): void {\n\t\tthis.settings.hookTimeout = timeout;\n\t\tthis.save();\n\t}\n\n\tgetCustomToolPaths(): string[] {\n\t\treturn this.settings.customTools ?? [];\n\t}\n\n\tsetCustomToolPaths(paths: string[]): void {\n\t\tthis.settings.customTools = paths;\n\t\tthis.save();\n\t}\n\n\tgetSkillsEnabled(): boolean {\n\t\treturn this.settings.skills?.enabled ?? true;\n\t}\n\n\tsetSkillsEnabled(enabled: boolean): void {\n\t\tif (!this.settings.skills) {\n\t\t\tthis.settings.skills = {};\n\t\t}\n\t\tthis.settings.skills.enabled = enabled;\n\t\tthis.save();\n\t}\n\n\tgetSkillsSettings(): Required<SkillsSettings> {\n\t\treturn {\n\t\t\tenabled: this.settings.skills?.enabled ?? true,\n\t\t\tenableCodexUser: this.settings.skills?.enableCodexUser ?? true,\n\t\t\tenableClaudeUser: this.settings.skills?.enableClaudeUser ?? true,\n\t\t\tenableClaudeProject: this.settings.skills?.enableClaudeProject ?? true,\n\t\t\tenablePiUser: this.settings.skills?.enablePiUser ?? true,\n\t\t\tenablePiProject: this.settings.skills?.enablePiProject ?? true,\n\t\t\tcustomDirectories: this.settings.skills?.customDirectories ?? [],\n\t\t\tignoredSkills: this.settings.skills?.ignoredSkills ?? [],\n\t\t\tincludeSkills: this.settings.skills?.includeSkills ?? [],\n\t\t};\n\t}\n\n\tgetShowImages(): boolean {\n\t\treturn this.settings.terminal?.showImages ?? true;\n\t}\n\n\tsetShowImages(show: boolean): void {\n\t\tif (!this.settings.terminal) {\n\t\t\tthis.settings.terminal = {};\n\t\t}\n\t\tthis.settings.terminal.showImages = show;\n\t\tthis.save();\n\t}\n}\n"]}
|
|
@@ -174,6 +174,19 @@ export class SettingsManager {
|
|
|
174
174
|
this.settings.skills.enabled = enabled;
|
|
175
175
|
this.save();
|
|
176
176
|
}
|
|
177
|
+
getSkillsSettings() {
|
|
178
|
+
return {
|
|
179
|
+
enabled: this.settings.skills?.enabled ?? true,
|
|
180
|
+
enableCodexUser: this.settings.skills?.enableCodexUser ?? true,
|
|
181
|
+
enableClaudeUser: this.settings.skills?.enableClaudeUser ?? true,
|
|
182
|
+
enableClaudeProject: this.settings.skills?.enableClaudeProject ?? true,
|
|
183
|
+
enablePiUser: this.settings.skills?.enablePiUser ?? true,
|
|
184
|
+
enablePiProject: this.settings.skills?.enablePiProject ?? true,
|
|
185
|
+
customDirectories: this.settings.skills?.customDirectories ?? [],
|
|
186
|
+
ignoredSkills: this.settings.skills?.ignoredSkills ?? [],
|
|
187
|
+
includeSkills: this.settings.skills?.includeSkills ?? [],
|
|
188
|
+
};
|
|
189
|
+
}
|
|
177
190
|
getShowImages() {
|
|
178
191
|
return this.settings.terminal?.showImages ?? true;
|
|
179
192
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"settings-manager.js","sourceRoot":"","sources":["../../src/core/settings-manager.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync, mkdirSync, readFileSync, writeFileSync } from \"fs\";\nimport { dirname, join } from \"path\";\nimport { getAgentDir } from \"../config.js\";\n\nexport interface CompactionSettings {\n\tenabled?: boolean; // default: true\n\treserveTokens?: number; // default: 16384\n\tkeepRecentTokens?: number; // default: 20000\n}\n\nexport interface RetrySettings {\n\tenabled?: boolean; // default: true\n\tmaxRetries?: number; // default: 3\n\tbaseDelayMs?: number; // default: 2000 (exponential backoff: 2s, 4s, 8s)\n}\n\nexport interface SkillsSettings {\n\tenabled?: boolean; // default: true\n}\n\nexport interface TerminalSettings {\n\tshowImages?: boolean; // default: true (only relevant if terminal supports images)\n}\n\nexport interface Settings {\n\tlastChangelogVersion?: string;\n\tdefaultProvider?: string;\n\tdefaultModel?: string;\n\tdefaultThinkingLevel?: \"off\" | \"minimal\" | \"low\" | \"medium\" | \"high\" | \"xhigh\";\n\tqueueMode?: \"all\" | \"one-at-a-time\";\n\ttheme?: string;\n\tcompaction?: CompactionSettings;\n\tretry?: RetrySettings;\n\thideThinkingBlock?: boolean;\n\tshellPath?: string; // Custom shell path (e.g., for Cygwin users on Windows)\n\tcollapseChangelog?: boolean; // Show condensed changelog after update (use /changelog for full)\n\thooks?: string[]; // Array of hook file paths\n\thookTimeout?: number; // Timeout for hook execution in ms (default: 30000)\n\tcustomTools?: string[]; // Array of custom tool file paths\n\tskills?: SkillsSettings;\n\tterminal?: TerminalSettings;\n}\n\nexport class SettingsManager {\n\tprivate settingsPath: string;\n\tprivate settings: Settings;\n\n\tconstructor(baseDir?: string) {\n\t\tconst dir = baseDir || getAgentDir();\n\t\tthis.settingsPath = join(dir, \"settings.json\");\n\t\tthis.settings = this.load();\n\t}\n\n\tprivate load(): Settings {\n\t\tif (!existsSync(this.settingsPath)) {\n\t\t\treturn {};\n\t\t}\n\n\t\ttry {\n\t\t\tconst content = readFileSync(this.settingsPath, \"utf-8\");\n\t\t\treturn JSON.parse(content);\n\t\t} catch (error) {\n\t\t\tconsole.error(`Warning: Could not read settings file: ${error}`);\n\t\t\treturn {};\n\t\t}\n\t}\n\n\tprivate save(): void {\n\t\ttry {\n\t\t\t// Ensure directory exists\n\t\t\tconst dir = dirname(this.settingsPath);\n\t\t\tif (!existsSync(dir)) {\n\t\t\t\tmkdirSync(dir, { recursive: true });\n\t\t\t}\n\n\t\t\twriteFileSync(this.settingsPath, JSON.stringify(this.settings, null, 2), \"utf-8\");\n\t\t} catch (error) {\n\t\t\tconsole.error(`Warning: Could not save settings file: ${error}`);\n\t\t}\n\t}\n\n\tgetLastChangelogVersion(): string | undefined {\n\t\treturn this.settings.lastChangelogVersion;\n\t}\n\n\tsetLastChangelogVersion(version: string): void {\n\t\tthis.settings.lastChangelogVersion = version;\n\t\tthis.save();\n\t}\n\n\tgetDefaultProvider(): string | undefined {\n\t\treturn this.settings.defaultProvider;\n\t}\n\n\tgetDefaultModel(): string | undefined {\n\t\treturn this.settings.defaultModel;\n\t}\n\n\tsetDefaultProvider(provider: string): void {\n\t\tthis.settings.defaultProvider = provider;\n\t\tthis.save();\n\t}\n\n\tsetDefaultModel(modelId: string): void {\n\t\tthis.settings.defaultModel = modelId;\n\t\tthis.save();\n\t}\n\n\tsetDefaultModelAndProvider(provider: string, modelId: string): void {\n\t\tthis.settings.defaultProvider = provider;\n\t\tthis.settings.defaultModel = modelId;\n\t\tthis.save();\n\t}\n\n\tgetQueueMode(): \"all\" | \"one-at-a-time\" {\n\t\treturn this.settings.queueMode || \"one-at-a-time\";\n\t}\n\n\tsetQueueMode(mode: \"all\" | \"one-at-a-time\"): void {\n\t\tthis.settings.queueMode = mode;\n\t\tthis.save();\n\t}\n\n\tgetTheme(): string | undefined {\n\t\treturn this.settings.theme;\n\t}\n\n\tsetTheme(theme: string): void {\n\t\tthis.settings.theme = theme;\n\t\tthis.save();\n\t}\n\n\tgetDefaultThinkingLevel(): \"off\" | \"minimal\" | \"low\" | \"medium\" | \"high\" | \"xhigh\" | undefined {\n\t\treturn this.settings.defaultThinkingLevel;\n\t}\n\n\tsetDefaultThinkingLevel(level: \"off\" | \"minimal\" | \"low\" | \"medium\" | \"high\" | \"xhigh\"): void {\n\t\tthis.settings.defaultThinkingLevel = level;\n\t\tthis.save();\n\t}\n\n\tgetCompactionEnabled(): boolean {\n\t\treturn this.settings.compaction?.enabled ?? true;\n\t}\n\n\tsetCompactionEnabled(enabled: boolean): void {\n\t\tif (!this.settings.compaction) {\n\t\t\tthis.settings.compaction = {};\n\t\t}\n\t\tthis.settings.compaction.enabled = enabled;\n\t\tthis.save();\n\t}\n\n\tgetCompactionReserveTokens(): number {\n\t\treturn this.settings.compaction?.reserveTokens ?? 16384;\n\t}\n\n\tgetCompactionKeepRecentTokens(): number {\n\t\treturn this.settings.compaction?.keepRecentTokens ?? 20000;\n\t}\n\n\tgetCompactionSettings(): { enabled: boolean; reserveTokens: number; keepRecentTokens: number } {\n\t\treturn {\n\t\t\tenabled: this.getCompactionEnabled(),\n\t\t\treserveTokens: this.getCompactionReserveTokens(),\n\t\t\tkeepRecentTokens: this.getCompactionKeepRecentTokens(),\n\t\t};\n\t}\n\n\tgetRetryEnabled(): boolean {\n\t\treturn this.settings.retry?.enabled ?? true;\n\t}\n\n\tsetRetryEnabled(enabled: boolean): void {\n\t\tif (!this.settings.retry) {\n\t\t\tthis.settings.retry = {};\n\t\t}\n\t\tthis.settings.retry.enabled = enabled;\n\t\tthis.save();\n\t}\n\n\tgetRetrySettings(): { enabled: boolean; maxRetries: number; baseDelayMs: number } {\n\t\treturn {\n\t\t\tenabled: this.getRetryEnabled(),\n\t\t\tmaxRetries: this.settings.retry?.maxRetries ?? 3,\n\t\t\tbaseDelayMs: this.settings.retry?.baseDelayMs ?? 2000,\n\t\t};\n\t}\n\n\tgetHideThinkingBlock(): boolean {\n\t\treturn this.settings.hideThinkingBlock ?? false;\n\t}\n\n\tsetHideThinkingBlock(hide: boolean): void {\n\t\tthis.settings.hideThinkingBlock = hide;\n\t\tthis.save();\n\t}\n\n\tgetShellPath(): string | undefined {\n\t\treturn this.settings.shellPath;\n\t}\n\n\tsetShellPath(path: string | undefined): void {\n\t\tthis.settings.shellPath = path;\n\t\tthis.save();\n\t}\n\n\tgetCollapseChangelog(): boolean {\n\t\treturn this.settings.collapseChangelog ?? false;\n\t}\n\n\tsetCollapseChangelog(collapse: boolean): void {\n\t\tthis.settings.collapseChangelog = collapse;\n\t\tthis.save();\n\t}\n\n\tgetHookPaths(): string[] {\n\t\treturn this.settings.hooks ?? [];\n\t}\n\n\tsetHookPaths(paths: string[]): void {\n\t\tthis.settings.hooks = paths;\n\t\tthis.save();\n\t}\n\n\tgetHookTimeout(): number {\n\t\treturn this.settings.hookTimeout ?? 30000;\n\t}\n\n\tsetHookTimeout(timeout: number): void {\n\t\tthis.settings.hookTimeout = timeout;\n\t\tthis.save();\n\t}\n\n\tgetCustomToolPaths(): string[] {\n\t\treturn this.settings.customTools ?? [];\n\t}\n\n\tsetCustomToolPaths(paths: string[]): void {\n\t\tthis.settings.customTools = paths;\n\t\tthis.save();\n\t}\n\n\tgetSkillsEnabled(): boolean {\n\t\treturn this.settings.skills?.enabled ?? true;\n\t}\n\n\tsetSkillsEnabled(enabled: boolean): void {\n\t\tif (!this.settings.skills) {\n\t\t\tthis.settings.skills = {};\n\t\t}\n\t\tthis.settings.skills.enabled = enabled;\n\t\tthis.save();\n\t}\n\n\tgetShowImages(): boolean {\n\t\treturn this.settings.terminal?.showImages ?? true;\n\t}\n\n\tsetShowImages(show: boolean): void {\n\t\tif (!this.settings.terminal) {\n\t\t\tthis.settings.terminal = {};\n\t\t}\n\t\tthis.settings.terminal.showImages = show;\n\t\tthis.save();\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"settings-manager.js","sourceRoot":"","sources":["../../src/core/settings-manager.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync, mkdirSync, readFileSync, writeFileSync } from \"fs\";\nimport { dirname, join } from \"path\";\nimport { getAgentDir } from \"../config.js\";\n\nexport interface CompactionSettings {\n\tenabled?: boolean; // default: true\n\treserveTokens?: number; // default: 16384\n\tkeepRecentTokens?: number; // default: 20000\n}\n\nexport interface RetrySettings {\n\tenabled?: boolean; // default: true\n\tmaxRetries?: number; // default: 3\n\tbaseDelayMs?: number; // default: 2000 (exponential backoff: 2s, 4s, 8s)\n}\n\nexport interface SkillsSettings {\n\tenabled?: boolean; // default: true\n\tenableCodexUser?: boolean; // default: true\n\tenableClaudeUser?: boolean; // default: true\n\tenableClaudeProject?: boolean; // default: true\n\tenablePiUser?: boolean; // default: true\n\tenablePiProject?: boolean; // default: true\n\tcustomDirectories?: string[]; // default: []\n\tignoredSkills?: string[]; // default: [] (glob patterns to exclude; takes precedence over includeSkills)\n\tincludeSkills?: string[]; // default: [] (empty = include all; glob patterns to filter)\n}\n\nexport interface TerminalSettings {\n\tshowImages?: boolean; // default: true (only relevant if terminal supports images)\n}\n\nexport interface Settings {\n\tlastChangelogVersion?: string;\n\tdefaultProvider?: string;\n\tdefaultModel?: string;\n\tdefaultThinkingLevel?: \"off\" | \"minimal\" | \"low\" | \"medium\" | \"high\" | \"xhigh\";\n\tqueueMode?: \"all\" | \"one-at-a-time\";\n\ttheme?: string;\n\tcompaction?: CompactionSettings;\n\tretry?: RetrySettings;\n\thideThinkingBlock?: boolean;\n\tshellPath?: string; // Custom shell path (e.g., for Cygwin users on Windows)\n\tcollapseChangelog?: boolean; // Show condensed changelog after update (use /changelog for full)\n\thooks?: string[]; // Array of hook file paths\n\thookTimeout?: number; // Timeout for hook execution in ms (default: 30000)\n\tcustomTools?: string[]; // Array of custom tool file paths\n\tskills?: SkillsSettings;\n\tterminal?: TerminalSettings;\n}\n\nexport class SettingsManager {\n\tprivate settingsPath: string;\n\tprivate settings: Settings;\n\n\tconstructor(baseDir?: string) {\n\t\tconst dir = baseDir || getAgentDir();\n\t\tthis.settingsPath = join(dir, \"settings.json\");\n\t\tthis.settings = this.load();\n\t}\n\n\tprivate load(): Settings {\n\t\tif (!existsSync(this.settingsPath)) {\n\t\t\treturn {};\n\t\t}\n\n\t\ttry {\n\t\t\tconst content = readFileSync(this.settingsPath, \"utf-8\");\n\t\t\treturn JSON.parse(content);\n\t\t} catch (error) {\n\t\t\tconsole.error(`Warning: Could not read settings file: ${error}`);\n\t\t\treturn {};\n\t\t}\n\t}\n\n\tprivate save(): void {\n\t\ttry {\n\t\t\t// Ensure directory exists\n\t\t\tconst dir = dirname(this.settingsPath);\n\t\t\tif (!existsSync(dir)) {\n\t\t\t\tmkdirSync(dir, { recursive: true });\n\t\t\t}\n\n\t\t\twriteFileSync(this.settingsPath, JSON.stringify(this.settings, null, 2), \"utf-8\");\n\t\t} catch (error) {\n\t\t\tconsole.error(`Warning: Could not save settings file: ${error}`);\n\t\t}\n\t}\n\n\tgetLastChangelogVersion(): string | undefined {\n\t\treturn this.settings.lastChangelogVersion;\n\t}\n\n\tsetLastChangelogVersion(version: string): void {\n\t\tthis.settings.lastChangelogVersion = version;\n\t\tthis.save();\n\t}\n\n\tgetDefaultProvider(): string | undefined {\n\t\treturn this.settings.defaultProvider;\n\t}\n\n\tgetDefaultModel(): string | undefined {\n\t\treturn this.settings.defaultModel;\n\t}\n\n\tsetDefaultProvider(provider: string): void {\n\t\tthis.settings.defaultProvider = provider;\n\t\tthis.save();\n\t}\n\n\tsetDefaultModel(modelId: string): void {\n\t\tthis.settings.defaultModel = modelId;\n\t\tthis.save();\n\t}\n\n\tsetDefaultModelAndProvider(provider: string, modelId: string): void {\n\t\tthis.settings.defaultProvider = provider;\n\t\tthis.settings.defaultModel = modelId;\n\t\tthis.save();\n\t}\n\n\tgetQueueMode(): \"all\" | \"one-at-a-time\" {\n\t\treturn this.settings.queueMode || \"one-at-a-time\";\n\t}\n\n\tsetQueueMode(mode: \"all\" | \"one-at-a-time\"): void {\n\t\tthis.settings.queueMode = mode;\n\t\tthis.save();\n\t}\n\n\tgetTheme(): string | undefined {\n\t\treturn this.settings.theme;\n\t}\n\n\tsetTheme(theme: string): void {\n\t\tthis.settings.theme = theme;\n\t\tthis.save();\n\t}\n\n\tgetDefaultThinkingLevel(): \"off\" | \"minimal\" | \"low\" | \"medium\" | \"high\" | \"xhigh\" | undefined {\n\t\treturn this.settings.defaultThinkingLevel;\n\t}\n\n\tsetDefaultThinkingLevel(level: \"off\" | \"minimal\" | \"low\" | \"medium\" | \"high\" | \"xhigh\"): void {\n\t\tthis.settings.defaultThinkingLevel = level;\n\t\tthis.save();\n\t}\n\n\tgetCompactionEnabled(): boolean {\n\t\treturn this.settings.compaction?.enabled ?? true;\n\t}\n\n\tsetCompactionEnabled(enabled: boolean): void {\n\t\tif (!this.settings.compaction) {\n\t\t\tthis.settings.compaction = {};\n\t\t}\n\t\tthis.settings.compaction.enabled = enabled;\n\t\tthis.save();\n\t}\n\n\tgetCompactionReserveTokens(): number {\n\t\treturn this.settings.compaction?.reserveTokens ?? 16384;\n\t}\n\n\tgetCompactionKeepRecentTokens(): number {\n\t\treturn this.settings.compaction?.keepRecentTokens ?? 20000;\n\t}\n\n\tgetCompactionSettings(): { enabled: boolean; reserveTokens: number; keepRecentTokens: number } {\n\t\treturn {\n\t\t\tenabled: this.getCompactionEnabled(),\n\t\t\treserveTokens: this.getCompactionReserveTokens(),\n\t\t\tkeepRecentTokens: this.getCompactionKeepRecentTokens(),\n\t\t};\n\t}\n\n\tgetRetryEnabled(): boolean {\n\t\treturn this.settings.retry?.enabled ?? true;\n\t}\n\n\tsetRetryEnabled(enabled: boolean): void {\n\t\tif (!this.settings.retry) {\n\t\t\tthis.settings.retry = {};\n\t\t}\n\t\tthis.settings.retry.enabled = enabled;\n\t\tthis.save();\n\t}\n\n\tgetRetrySettings(): { enabled: boolean; maxRetries: number; baseDelayMs: number } {\n\t\treturn {\n\t\t\tenabled: this.getRetryEnabled(),\n\t\t\tmaxRetries: this.settings.retry?.maxRetries ?? 3,\n\t\t\tbaseDelayMs: this.settings.retry?.baseDelayMs ?? 2000,\n\t\t};\n\t}\n\n\tgetHideThinkingBlock(): boolean {\n\t\treturn this.settings.hideThinkingBlock ?? false;\n\t}\n\n\tsetHideThinkingBlock(hide: boolean): void {\n\t\tthis.settings.hideThinkingBlock = hide;\n\t\tthis.save();\n\t}\n\n\tgetShellPath(): string | undefined {\n\t\treturn this.settings.shellPath;\n\t}\n\n\tsetShellPath(path: string | undefined): void {\n\t\tthis.settings.shellPath = path;\n\t\tthis.save();\n\t}\n\n\tgetCollapseChangelog(): boolean {\n\t\treturn this.settings.collapseChangelog ?? false;\n\t}\n\n\tsetCollapseChangelog(collapse: boolean): void {\n\t\tthis.settings.collapseChangelog = collapse;\n\t\tthis.save();\n\t}\n\n\tgetHookPaths(): string[] {\n\t\treturn this.settings.hooks ?? [];\n\t}\n\n\tsetHookPaths(paths: string[]): void {\n\t\tthis.settings.hooks = paths;\n\t\tthis.save();\n\t}\n\n\tgetHookTimeout(): number {\n\t\treturn this.settings.hookTimeout ?? 30000;\n\t}\n\n\tsetHookTimeout(timeout: number): void {\n\t\tthis.settings.hookTimeout = timeout;\n\t\tthis.save();\n\t}\n\n\tgetCustomToolPaths(): string[] {\n\t\treturn this.settings.customTools ?? [];\n\t}\n\n\tsetCustomToolPaths(paths: string[]): void {\n\t\tthis.settings.customTools = paths;\n\t\tthis.save();\n\t}\n\n\tgetSkillsEnabled(): boolean {\n\t\treturn this.settings.skills?.enabled ?? true;\n\t}\n\n\tsetSkillsEnabled(enabled: boolean): void {\n\t\tif (!this.settings.skills) {\n\t\t\tthis.settings.skills = {};\n\t\t}\n\t\tthis.settings.skills.enabled = enabled;\n\t\tthis.save();\n\t}\n\n\tgetSkillsSettings(): Required<SkillsSettings> {\n\t\treturn {\n\t\t\tenabled: this.settings.skills?.enabled ?? true,\n\t\t\tenableCodexUser: this.settings.skills?.enableCodexUser ?? true,\n\t\t\tenableClaudeUser: this.settings.skills?.enableClaudeUser ?? true,\n\t\t\tenableClaudeProject: this.settings.skills?.enableClaudeProject ?? true,\n\t\t\tenablePiUser: this.settings.skills?.enablePiUser ?? true,\n\t\t\tenablePiProject: this.settings.skills?.enablePiProject ?? true,\n\t\t\tcustomDirectories: this.settings.skills?.customDirectories ?? [],\n\t\t\tignoredSkills: this.settings.skills?.ignoredSkills ?? [],\n\t\t\tincludeSkills: this.settings.skills?.includeSkills ?? [],\n\t\t};\n\t}\n\n\tgetShowImages(): boolean {\n\t\treturn this.settings.terminal?.showImages ?? true;\n\t}\n\n\tsetShowImages(show: boolean): void {\n\t\tif (!this.settings.terminal) {\n\t\t\tthis.settings.terminal = {};\n\t\t}\n\t\tthis.settings.terminal.showImages = show;\n\t\tthis.save();\n\t}\n}\n"]}
|
package/dist/core/skills.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { SkillsSettings } from "./settings-manager.js";
|
|
1
2
|
export interface SkillFrontmatter {
|
|
2
3
|
name?: string;
|
|
3
4
|
description?: string;
|
|
@@ -39,5 +40,5 @@ export declare function formatSkillsForPrompt(skills: Skill[]): string;
|
|
|
39
40
|
* Load skills from all configured locations.
|
|
40
41
|
* Returns skills and any validation warnings.
|
|
41
42
|
*/
|
|
42
|
-
export declare function loadSkills(): LoadSkillsResult;
|
|
43
|
+
export declare function loadSkills(options?: SkillsSettings): LoadSkillsResult;
|
|
43
44
|
//# sourceMappingURL=skills.d.ts.map
|