@ai-devkit/agent-manager 0.36.0 → 0.37.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/AgentManager.d.ts +9 -4
- package/dist/AgentManager.d.ts.map +1 -1
- package/dist/AgentManager.js +21 -2
- package/dist/AgentManager.js.map +1 -1
- package/dist/__tests__/AgentManager.test.js +151 -3
- package/dist/__tests__/AgentManager.test.js.map +1 -1
- package/dist/__tests__/adapters/IncrementalSessionRefresh.test.js +486 -0
- package/dist/__tests__/adapters/IncrementalSessionRefresh.test.js.map +1 -0
- package/dist/__tests__/adapters/adapterProcessImports.test.js +52 -0
- package/dist/__tests__/adapters/adapterProcessImports.test.js.map +1 -0
- package/dist/__tests__/adapters/adapterSnapshotCandidates.test.js +247 -0
- package/dist/__tests__/adapters/adapterSnapshotCandidates.test.js.map +1 -0
- package/dist/__tests__/capacity/openai.test.js +12 -14
- package/dist/__tests__/capacity/openai.test.js.map +1 -1
- package/dist/__tests__/harnesses/BoundedSummarySkip.test.js +568 -0
- package/dist/__tests__/harnesses/BoundedSummarySkip.test.js.map +1 -0
- package/dist/__tests__/harnesses/SessionSummaryEquivalence.test.js +1089 -0
- package/dist/__tests__/harnesses/SessionSummaryEquivalence.test.js.map +1 -0
- package/dist/__tests__/harnesses/antigravity/AntigravityCliAdapter.subprocess.test.js +143 -0
- package/dist/__tests__/harnesses/antigravity/AntigravityCliAdapter.subprocess.test.js.map +1 -0
- package/dist/__tests__/{adapters → harnesses/antigravity}/AntigravityCliAdapter.test.js +103 -22
- package/dist/__tests__/harnesses/antigravity/AntigravityCliAdapter.test.js.map +1 -0
- package/dist/__tests__/harnesses/builtinAdapters.test.js +33 -0
- package/dist/__tests__/harnesses/builtinAdapters.test.js.map +1 -0
- package/dist/__tests__/{providers → harnesses}/claude/ClaudeAgentMapper.test.js +4 -4
- package/dist/__tests__/harnesses/claude/ClaudeAgentMapper.test.js.map +1 -0
- package/dist/__tests__/{adapters → harnesses/claude}/ClaudeCodeAdapter.test.js +47 -19
- package/dist/__tests__/harnesses/claude/ClaudeCodeAdapter.test.js.map +1 -0
- package/dist/__tests__/{providers → harnesses}/claude/ClaudeSessionLocator.test.js +1 -12
- package/dist/__tests__/{providers → harnesses}/claude/ClaudeSessionLocator.test.js.map +1 -1
- package/dist/__tests__/{utils → harnesses/claude}/ClaudeSessionParser.test.js +2 -2
- package/dist/__tests__/harnesses/claude/ClaudeSessionParser.test.js.map +1 -0
- package/dist/__tests__/{print → harnesses/claude/durable}/ClaudeCliProbe.test.js +1 -1
- package/dist/__tests__/harnesses/claude/durable/ClaudeCliProbe.test.js.map +1 -0
- package/dist/__tests__/{print → harnesses/claude/durable}/ClaudePrintAgent.integration.test.js +1 -1
- package/dist/__tests__/harnesses/claude/durable/ClaudePrintAgent.integration.test.js.map +1 -0
- package/dist/__tests__/{print → harnesses/claude/durable}/ClaudePrintAgentService.test.js +4 -4
- package/dist/__tests__/harnesses/claude/durable/ClaudePrintAgentService.test.js.map +1 -0
- package/dist/__tests__/{print → harnesses/claude/durable}/ClaudePrintRunner.test.js +1 -1
- package/dist/__tests__/harnesses/claude/durable/ClaudePrintRunner.test.js.map +1 -0
- package/dist/__tests__/{adapters → harnesses/codex}/CodexAdapter.test.js +304 -10
- package/dist/__tests__/harnesses/codex/CodexAdapter.test.js.map +1 -0
- package/dist/__tests__/harnesses/codex/CodexSessionLocator.test.js +463 -0
- package/dist/__tests__/harnesses/codex/CodexSessionLocator.test.js.map +1 -0
- package/dist/__tests__/{providers → harnesses}/codex/CodexSessionMapping.test.js +1 -1
- package/dist/__tests__/{providers → harnesses}/codex/CodexSessionMapping.test.js.map +1 -1
- package/dist/__tests__/{providers → harnesses}/codex/CodexSessionParser.test.js +1 -1
- package/dist/__tests__/{providers → harnesses}/codex/CodexSessionParser.test.js.map +1 -1
- package/dist/__tests__/{durable → harnesses/codex/durable}/CodexCliProbe.test.js +4 -4
- package/dist/__tests__/harnesses/codex/durable/CodexCliProbe.test.js.map +1 -0
- package/dist/__tests__/{durable → harnesses/codex/durable}/CodexDurableAgentRepository.test.js +1 -1
- package/dist/__tests__/harnesses/codex/durable/CodexDurableAgentRepository.test.js.map +1 -0
- package/dist/__tests__/{durable → harnesses/codex/durable}/CodexPrintAgent.integration.test.js +1 -1
- package/dist/__tests__/harnesses/codex/durable/CodexPrintAgent.integration.test.js.map +1 -0
- package/dist/__tests__/{durable → harnesses/codex/durable}/CodexPrintAgentService.test.js +8 -18
- package/dist/__tests__/harnesses/codex/durable/CodexPrintAgentService.test.js.map +1 -0
- package/dist/__tests__/{durable → harnesses/codex/durable}/CodexPrintRunner.test.js +2 -7
- package/dist/__tests__/harnesses/codex/durable/CodexPrintRunner.test.js.map +1 -0
- package/dist/__tests__/{providers → harnesses}/copilot/CopilotAdapter.test.js +1 -1
- package/dist/__tests__/{providers → harnesses}/copilot/CopilotAdapter.test.js.map +1 -1
- package/dist/__tests__/harnesses/copilot/CopilotRefreshIO.test.js +290 -0
- package/dist/__tests__/harnesses/copilot/CopilotRefreshIO.test.js.map +1 -0
- package/dist/__tests__/{providers → harnesses}/gemini/GeminiCliAdapter.test.js +34 -25
- package/dist/__tests__/harnesses/gemini/GeminiCliAdapter.test.js.map +1 -0
- package/dist/__tests__/harnesses/gemini/GeminiSessionJsonl.test.js +491 -0
- package/dist/__tests__/harnesses/gemini/GeminiSessionJsonl.test.js.map +1 -0
- package/dist/__tests__/harnesses/gemini/GeminiSessionLocator.test.js +399 -0
- package/dist/__tests__/harnesses/gemini/GeminiSessionLocator.test.js.map +1 -0
- package/dist/__tests__/{providers → harnesses}/grok/GrokAgentMapper.test.js +1 -1
- package/dist/__tests__/{providers → harnesses}/grok/GrokAgentMapper.test.js.map +1 -1
- package/dist/__tests__/{providers → harnesses}/grok/GrokCliAdapter.test.js +1 -1
- package/dist/__tests__/{providers → harnesses}/grok/GrokCliAdapter.test.js.map +1 -1
- package/dist/__tests__/harnesses/grok/GrokIncrementalRefresh.test.js +167 -0
- package/dist/__tests__/harnesses/grok/GrokIncrementalRefresh.test.js.map +1 -0
- package/dist/__tests__/{providers → harnesses}/grok/GrokSessionLocator.test.js +1 -1
- package/dist/__tests__/{providers → harnesses}/grok/GrokSessionLocator.test.js.map +1 -1
- package/dist/__tests__/harnesses/grok/GrokSessionParser.test.js +301 -0
- package/dist/__tests__/harnesses/grok/GrokSessionParser.test.js.map +1 -0
- package/dist/__tests__/{adapters → harnesses/kiro}/KiroAdapter.test.js +137 -82
- package/dist/__tests__/harnesses/kiro/KiroAdapter.test.js.map +1 -0
- package/dist/__tests__/{providers → harnesses}/opencode/OpenCodeAdapter.test.js +1 -1
- package/dist/__tests__/{providers → harnesses}/opencode/OpenCodeAdapter.test.js.map +1 -1
- package/dist/__tests__/{providers → harnesses}/opencode/OpenCodeAgentMapper.test.js +1 -1
- package/dist/__tests__/{providers → harnesses}/opencode/OpenCodeAgentMapper.test.js.map +1 -1
- package/dist/__tests__/{providers → harnesses}/opencode/OpenCodeSessionLocator.test.js +2 -2
- package/dist/__tests__/{providers → harnesses}/opencode/OpenCodeSessionLocator.test.js.map +1 -1
- package/dist/__tests__/{providers → harnesses}/opencode/OpenCodeSessionParser.test.js +1 -1
- package/dist/__tests__/{providers → harnesses}/opencode/OpenCodeSessionParser.test.js.map +1 -1
- package/dist/__tests__/{providers → harnesses}/pi/PiAdapter.test.js +1 -1
- package/dist/__tests__/{providers → harnesses}/pi/PiAdapter.test.js.map +1 -1
- package/dist/__tests__/harnesses/pi/PiDiscoveryIO.test.js +382 -0
- package/dist/__tests__/harnesses/pi/PiDiscoveryIO.test.js.map +1 -0
- package/dist/__tests__/{providers → harnesses}/pi/PiSessionParser.test.js +171 -1
- package/dist/__tests__/harnesses/pi/PiSessionParser.test.js.map +1 -0
- package/dist/__tests__/{providers → harnesses}/pi/PiSessionTracker.test.js +1 -1
- package/dist/__tests__/{providers → harnesses}/pi/PiSessionTracker.test.js.map +1 -1
- package/dist/__tests__/{providers → harnesses}/pi/durable/PiCliProbe.test.js.map +1 -1
- package/dist/__tests__/{providers → harnesses}/pi/durable/PiDurableAgentRepository.test.js.map +1 -1
- package/dist/__tests__/{providers → harnesses}/pi/durable/PiPrintAgentService.test.js.map +1 -1
- package/dist/__tests__/{providers → harnesses}/pi/durable/PiPrintProtocol.test.js +1 -1
- package/dist/__tests__/{providers → harnesses}/pi/durable/PiPrintProtocol.test.js.map +1 -1
- package/dist/__tests__/{providers → harnesses}/pi/durable/PiPrintRunner.test.js.map +1 -1
- package/dist/__tests__/{providers → harnesses}/pi/durable/PiStreamParser.test.js +1 -1
- package/dist/__tests__/{providers → harnesses}/pi/durable/PiStreamParser.test.js.map +1 -1
- package/dist/__tests__/readiness/AgentReadiness.test.js +20 -0
- package/dist/__tests__/readiness/AgentReadiness.test.js.map +1 -1
- package/dist/__tests__/runtime/ManagedAgentRuntime.test.js +49 -0
- package/dist/__tests__/runtime/ManagedAgentRuntime.test.js.map +1 -1
- package/dist/__tests__/utils/IncrementalJsonlSummary.test.js +650 -0
- package/dist/__tests__/utils/IncrementalJsonlSummary.test.js.map +1 -0
- package/dist/__tests__/utils/agents.test.js +66 -2
- package/dist/__tests__/utils/agents.test.js.map +1 -1
- package/dist/__tests__/utils/conversationTail.bench.test.js +258 -0
- package/dist/__tests__/utils/conversationTail.bench.test.js.map +1 -0
- package/dist/__tests__/utils/conversationTailParity.test.js +588 -0
- package/dist/__tests__/utils/conversationTailParity.test.js.map +1 -0
- package/dist/__tests__/utils/jsonlTail.test.js +360 -0
- package/dist/__tests__/utils/jsonlTail.test.js.map +1 -0
- package/dist/__tests__/utils/matchingConstants.test.js +35 -0
- package/dist/__tests__/utils/matchingConstants.test.js.map +1 -0
- package/dist/__tests__/utils/process.test.js +436 -2
- package/dist/__tests__/utils/process.test.js.map +1 -1
- package/dist/adapters/AgentAdapter.d.ts +25 -6
- package/dist/adapters/AgentAdapter.d.ts.map +1 -1
- package/dist/adapters/AgentAdapter.js +12 -3
- package/dist/adapters/AgentAdapter.js.map +1 -1
- package/dist/capacity/openai.d.ts +0 -1
- package/dist/capacity/openai.d.ts.map +1 -1
- package/dist/capacity/openai.js +0 -5
- package/dist/capacity/openai.js.map +1 -1
- package/dist/harnesses/antigravity/AntigravityAgentMapper.d.ts +13 -0
- package/dist/harnesses/antigravity/AntigravityAgentMapper.d.ts.map +1 -0
- package/dist/harnesses/antigravity/AntigravityAgentMapper.js +30 -0
- package/dist/harnesses/antigravity/AntigravityAgentMapper.js.map +1 -0
- package/dist/harnesses/antigravity/AntigravityCliAdapter.d.ts +32 -0
- package/dist/harnesses/antigravity/AntigravityCliAdapter.d.ts.map +1 -0
- package/dist/harnesses/antigravity/AntigravityCliAdapter.js +97 -0
- package/dist/harnesses/antigravity/AntigravityCliAdapter.js.map +1 -0
- package/dist/harnesses/antigravity/AntigravitySessionLocator.d.ts +30 -0
- package/dist/harnesses/antigravity/AntigravitySessionLocator.d.ts.map +1 -0
- package/dist/harnesses/antigravity/AntigravitySessionLocator.js +56 -0
- package/dist/harnesses/antigravity/AntigravitySessionLocator.js.map +1 -0
- package/dist/harnesses/antigravity/AntigravitySessionParser.d.ts +75 -0
- package/dist/harnesses/antigravity/AntigravitySessionParser.d.ts.map +1 -0
- package/dist/harnesses/antigravity/AntigravitySessionParser.js +174 -0
- package/dist/harnesses/antigravity/AntigravitySessionParser.js.map +1 -0
- package/dist/{providers → harnesses}/claude/ClaudeAgentMapper.d.ts.map +1 -1
- package/dist/{providers → harnesses}/claude/ClaudeAgentMapper.js +4 -10
- package/dist/harnesses/claude/ClaudeAgentMapper.js.map +1 -0
- package/dist/{providers → harnesses}/claude/ClaudeCodeAdapter.d.ts +5 -6
- package/dist/harnesses/claude/ClaudeCodeAdapter.d.ts.map +1 -0
- package/dist/{providers → harnesses}/claude/ClaudeCodeAdapter.js +17 -15
- package/dist/harnesses/claude/ClaudeCodeAdapter.js.map +1 -0
- package/dist/{providers → harnesses}/claude/ClaudeSessionLocator.d.ts.map +1 -1
- package/dist/{providers → harnesses}/claude/ClaudeSessionLocator.js +3 -3
- package/dist/harnesses/claude/ClaudeSessionLocator.js.map +1 -0
- package/dist/{providers → harnesses}/claude/ClaudeSessionParser.d.ts +40 -6
- package/dist/harnesses/claude/ClaudeSessionParser.d.ts.map +1 -0
- package/dist/{providers → harnesses}/claude/ClaudeSessionParser.js +141 -85
- package/dist/harnesses/claude/ClaudeSessionParser.js.map +1 -0
- package/dist/{providers → harnesses}/claude/durable/ClaudeCliProbe.d.ts.map +1 -1
- package/dist/{providers → harnesses}/claude/durable/ClaudeCliProbe.js.map +1 -1
- package/dist/{providers → harnesses}/claude/durable/ClaudePrintAgentService.d.ts.map +1 -1
- package/dist/{providers → harnesses}/claude/durable/ClaudePrintAgentService.js.map +1 -1
- package/dist/{providers → harnesses}/claude/durable/ClaudePrintRunner.d.ts.map +1 -1
- package/dist/{providers → harnesses}/claude/durable/ClaudePrintRunner.js.map +1 -1
- package/dist/{providers → harnesses}/claude/durable/ClaudeStreamParser.d.ts.map +1 -1
- package/dist/{providers → harnesses}/claude/durable/ClaudeStreamParser.js.map +1 -1
- package/dist/{providers → harnesses}/codex/CodexAdapter.d.ts +5 -4
- package/dist/harnesses/codex/CodexAdapter.d.ts.map +1 -0
- package/dist/{providers → harnesses}/codex/CodexAdapter.js +139 -19
- package/dist/harnesses/codex/CodexAdapter.js.map +1 -0
- package/dist/{providers → harnesses}/codex/CodexAgentMapper.d.ts.map +1 -1
- package/dist/{providers → harnesses}/codex/CodexAgentMapper.js +4 -11
- package/dist/harnesses/codex/CodexAgentMapper.js.map +1 -0
- package/dist/harnesses/codex/CodexSessionLocator.d.ts +74 -0
- package/dist/harnesses/codex/CodexSessionLocator.d.ts.map +1 -0
- package/dist/harnesses/codex/CodexSessionLocator.js +359 -0
- package/dist/harnesses/codex/CodexSessionLocator.js.map +1 -0
- package/dist/{providers → harnesses}/codex/CodexSessionMapping.d.ts.map +1 -1
- package/dist/{providers → harnesses}/codex/CodexSessionMapping.js +3 -3
- package/dist/harnesses/codex/CodexSessionMapping.js.map +1 -0
- package/dist/harnesses/codex/CodexSessionParser.d.ts +89 -0
- package/dist/harnesses/codex/CodexSessionParser.d.ts.map +1 -0
- package/dist/{providers → harnesses}/codex/CodexSessionParser.js +124 -78
- package/dist/harnesses/codex/CodexSessionParser.js.map +1 -0
- package/dist/{providers → harnesses}/codex/durable/CodexCliProbe.d.ts.map +1 -1
- package/dist/{providers → harnesses}/codex/durable/CodexCliProbe.js.map +1 -1
- package/dist/{providers → harnesses}/codex/durable/CodexPrintAgentService.d.ts.map +1 -1
- package/dist/{providers → harnesses}/codex/durable/CodexPrintAgentService.js.map +1 -1
- package/dist/{providers → harnesses}/codex/durable/CodexPrintRunner.d.ts.map +1 -1
- package/dist/{providers → harnesses}/codex/durable/CodexPrintRunner.js.map +1 -1
- package/dist/{providers → harnesses}/codex/durable/CodexStreamParser.d.ts.map +1 -1
- package/dist/{providers → harnesses}/codex/durable/CodexStreamParser.js.map +1 -1
- package/dist/{providers → harnesses}/copilot/CopilotAdapter.d.ts +7 -6
- package/dist/harnesses/copilot/CopilotAdapter.d.ts.map +1 -0
- package/dist/{providers → harnesses}/copilot/CopilotAdapter.js +19 -14
- package/dist/harnesses/copilot/CopilotAdapter.js.map +1 -0
- package/dist/{providers → harnesses}/copilot/CopilotAgentMapper.d.ts.map +1 -1
- package/dist/{providers → harnesses}/copilot/CopilotAgentMapper.js +4 -11
- package/dist/harnesses/copilot/CopilotAgentMapper.js.map +1 -0
- package/dist/harnesses/copilot/CopilotSessionLocator.d.ts +42 -0
- package/dist/harnesses/copilot/CopilotSessionLocator.d.ts.map +1 -0
- package/dist/harnesses/copilot/CopilotSessionLocator.js +126 -0
- package/dist/harnesses/copilot/CopilotSessionLocator.js.map +1 -0
- package/dist/harnesses/copilot/CopilotSessionParser.d.ts +62 -0
- package/dist/harnesses/copilot/CopilotSessionParser.d.ts.map +1 -0
- package/dist/harnesses/copilot/CopilotSessionParser.js +236 -0
- package/dist/harnesses/copilot/CopilotSessionParser.js.map +1 -0
- package/dist/{providers → harnesses}/gemini/GeminiAgentMapper.d.ts.map +1 -1
- package/dist/{providers → harnesses}/gemini/GeminiAgentMapper.js +4 -11
- package/dist/harnesses/gemini/GeminiAgentMapper.js.map +1 -0
- package/dist/{providers → harnesses}/gemini/GeminiCliAdapter.d.ts +4 -5
- package/dist/harnesses/gemini/GeminiCliAdapter.d.ts.map +1 -0
- package/dist/{providers → harnesses}/gemini/GeminiCliAdapter.js +6 -7
- package/dist/harnesses/gemini/GeminiCliAdapter.js.map +1 -0
- package/dist/harnesses/gemini/GeminiSessionLocator.d.ts +72 -0
- package/dist/harnesses/gemini/GeminiSessionLocator.d.ts.map +1 -0
- package/dist/harnesses/gemini/GeminiSessionLocator.js +300 -0
- package/dist/harnesses/gemini/GeminiSessionLocator.js.map +1 -0
- package/dist/{providers → harnesses}/gemini/GeminiSessionParser.d.ts +34 -7
- package/dist/harnesses/gemini/GeminiSessionParser.d.ts.map +1 -0
- package/dist/harnesses/gemini/GeminiSessionParser.js +272 -0
- package/dist/harnesses/gemini/GeminiSessionParser.js.map +1 -0
- package/dist/harnesses/gemini/fileSignature.d.ts +8 -0
- package/dist/harnesses/gemini/fileSignature.d.ts.map +1 -0
- package/dist/harnesses/gemini/fileSignature.js +9 -0
- package/dist/harnesses/gemini/fileSignature.js.map +1 -0
- package/dist/{providers → harnesses}/grok/GrokAgentMapper.d.ts.map +1 -1
- package/dist/{providers → harnesses}/grok/GrokAgentMapper.js +4 -10
- package/dist/harnesses/grok/GrokAgentMapper.js.map +1 -0
- package/dist/{providers → harnesses}/grok/GrokCliAdapter.d.ts +5 -5
- package/dist/harnesses/grok/GrokCliAdapter.d.ts.map +1 -0
- package/dist/{providers → harnesses}/grok/GrokCliAdapter.js +14 -10
- package/dist/harnesses/grok/GrokCliAdapter.js.map +1 -0
- package/dist/{providers → harnesses}/grok/GrokSessionLocator.d.ts.map +1 -1
- package/dist/{providers → harnesses}/grok/GrokSessionLocator.js +2 -2
- package/dist/harnesses/grok/GrokSessionLocator.js.map +1 -0
- package/dist/harnesses/grok/GrokSessionParser.d.ts +87 -0
- package/dist/harnesses/grok/GrokSessionParser.d.ts.map +1 -0
- package/dist/harnesses/grok/GrokSessionParser.js +185 -0
- package/dist/harnesses/grok/GrokSessionParser.js.map +1 -0
- package/dist/harnesses/index.d.ts +7 -0
- package/dist/harnesses/index.d.ts.map +1 -0
- package/dist/harnesses/index.js +27 -0
- package/dist/harnesses/index.js.map +1 -0
- package/dist/harnesses/kiro/KiroAdapter.d.ts +31 -0
- package/dist/harnesses/kiro/KiroAdapter.d.ts.map +1 -0
- package/dist/harnesses/kiro/KiroAdapter.js +125 -0
- package/dist/harnesses/kiro/KiroAdapter.js.map +1 -0
- package/dist/harnesses/kiro/KiroAgentMapper.d.ts +13 -0
- package/dist/harnesses/kiro/KiroAgentMapper.d.ts.map +1 -0
- package/dist/harnesses/kiro/KiroAgentMapper.js +29 -0
- package/dist/harnesses/kiro/KiroAgentMapper.js.map +1 -0
- package/dist/harnesses/kiro/KiroSessionLocator.d.ts +38 -0
- package/dist/harnesses/kiro/KiroSessionLocator.d.ts.map +1 -0
- package/dist/harnesses/kiro/KiroSessionLocator.js +95 -0
- package/dist/harnesses/kiro/KiroSessionLocator.js.map +1 -0
- package/dist/harnesses/kiro/KiroSessionParser.d.ts +81 -0
- package/dist/harnesses/kiro/KiroSessionParser.d.ts.map +1 -0
- package/dist/harnesses/kiro/KiroSessionParser.js +251 -0
- package/dist/harnesses/kiro/KiroSessionParser.js.map +1 -0
- package/dist/{providers → harnesses}/opencode/OpenCodeAdapter.d.ts +2 -4
- package/dist/harnesses/opencode/OpenCodeAdapter.d.ts.map +1 -0
- package/dist/{providers → harnesses}/opencode/OpenCodeAdapter.js +4 -7
- package/dist/harnesses/opencode/OpenCodeAdapter.js.map +1 -0
- package/dist/{providers → harnesses}/opencode/OpenCodeAgentMapper.d.ts.map +1 -1
- package/dist/{providers → harnesses}/opencode/OpenCodeAgentMapper.js +5 -13
- package/dist/harnesses/opencode/OpenCodeAgentMapper.js.map +1 -0
- package/dist/{providers → harnesses}/opencode/OpenCodeSessionLocator.d.ts.map +1 -1
- package/dist/{providers → harnesses}/opencode/OpenCodeSessionLocator.js +2 -2
- package/dist/harnesses/opencode/OpenCodeSessionLocator.js.map +1 -0
- package/dist/{providers → harnesses}/opencode/OpenCodeSessionParser.d.ts +2 -4
- package/dist/harnesses/opencode/OpenCodeSessionParser.d.ts.map +1 -0
- package/dist/{providers → harnesses}/opencode/OpenCodeSessionParser.js +2 -1
- package/dist/harnesses/opencode/OpenCodeSessionParser.js.map +1 -0
- package/dist/{providers → harnesses}/pi/PiAdapter.d.ts +5 -4
- package/dist/harnesses/pi/PiAdapter.d.ts.map +1 -0
- package/dist/{providers → harnesses}/pi/PiAdapter.js +16 -12
- package/dist/harnesses/pi/PiAdapter.js.map +1 -0
- package/dist/{providers → harnesses}/pi/PiAgentMapper.d.ts.map +1 -1
- package/dist/{providers → harnesses}/pi/PiAgentMapper.js +4 -11
- package/dist/harnesses/pi/PiAgentMapper.js.map +1 -0
- package/dist/harnesses/pi/PiSessionLocator.d.ts +61 -0
- package/dist/harnesses/pi/PiSessionLocator.d.ts.map +1 -0
- package/dist/harnesses/pi/PiSessionLocator.js +212 -0
- package/dist/harnesses/pi/PiSessionLocator.js.map +1 -0
- package/dist/harnesses/pi/PiSessionParser.d.ts +88 -0
- package/dist/harnesses/pi/PiSessionParser.d.ts.map +1 -0
- package/dist/harnesses/pi/PiSessionParser.js +318 -0
- package/dist/harnesses/pi/PiSessionParser.js.map +1 -0
- package/dist/{providers → harnesses}/pi/PiSessionTracker.d.ts.map +1 -1
- package/dist/{providers → harnesses}/pi/PiSessionTracker.js +2 -2
- package/dist/harnesses/pi/PiSessionTracker.js.map +1 -0
- package/dist/{providers → harnesses}/pi/durable/PiCliProbe.d.ts.map +1 -1
- package/dist/{providers → harnesses}/pi/durable/PiCliProbe.js.map +1 -1
- package/dist/{providers → harnesses}/pi/durable/PiPrintAgentService.d.ts.map +1 -1
- package/dist/{providers → harnesses}/pi/durable/PiPrintAgentService.js.map +1 -1
- package/dist/{providers → harnesses}/pi/durable/PiPrintProtocol.d.ts.map +1 -1
- package/dist/{providers → harnesses}/pi/durable/PiPrintProtocol.js.map +1 -1
- package/dist/{providers → harnesses}/pi/durable/PiPrintRunner.d.ts.map +1 -1
- package/dist/{providers → harnesses}/pi/durable/PiPrintRunner.js.map +1 -1
- package/dist/{providers → harnesses}/pi/durable/PiStreamParser.d.ts.map +1 -1
- package/dist/{providers → harnesses}/pi/durable/PiStreamParser.js.map +1 -1
- package/dist/harnesses/shared.d.ts +41 -0
- package/dist/harnesses/shared.d.ts.map +1 -0
- package/dist/harnesses/shared.js +71 -0
- package/dist/harnesses/shared.js.map +1 -0
- package/dist/index.d.ts +26 -25
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +18 -17
- package/dist/index.js.map +1 -1
- package/dist/utils/IncrementalJsonlSummary.d.ts +100 -0
- package/dist/utils/IncrementalJsonlSummary.d.ts.map +1 -0
- package/dist/utils/IncrementalJsonlSummary.js +209 -0
- package/dist/utils/IncrementalJsonlSummary.js.map +1 -0
- package/dist/utils/agents.d.ts +3 -2
- package/dist/utils/agents.d.ts.map +1 -1
- package/dist/utils/agents.js +50 -15
- package/dist/utils/agents.js.map +1 -1
- package/dist/utils/index.d.ts +2 -1
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +1 -1
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/jsonlTail.d.ts +73 -0
- package/dist/utils/jsonlTail.d.ts.map +1 -0
- package/dist/utils/jsonlTail.js +238 -0
- package/dist/utils/jsonlTail.js.map +1 -0
- package/dist/utils/matching.d.ts +2 -0
- package/dist/utils/matching.d.ts.map +1 -1
- package/dist/utils/matching.js +3 -2
- package/dist/utils/matching.js.map +1 -1
- package/dist/utils/matchingConstants.d.ts +15 -0
- package/dist/utils/matchingConstants.d.ts.map +1 -0
- package/dist/utils/matchingConstants.js +14 -0
- package/dist/utils/matchingConstants.js.map +1 -0
- package/dist/utils/process.d.ts +38 -2
- package/dist/utils/process.d.ts.map +1 -1
- package/dist/utils/process.js +131 -43
- package/dist/utils/process.js.map +1 -1
- package/package.json +2 -1
- package/scripts/benchmark-cold-start.mjs +350 -0
- package/src/AgentManager.ts +26 -5
- package/src/__tests__/AgentManager.test.ts +141 -3
- package/src/__tests__/adapters/IncrementalSessionRefresh.test.ts +437 -0
- package/src/__tests__/adapters/adapterProcessImports.test.ts +58 -0
- package/src/__tests__/adapters/adapterSnapshotCandidates.test.ts +243 -0
- package/src/__tests__/capacity/openai.test.ts +5 -15
- package/src/__tests__/harnesses/BoundedSummarySkip.test.ts +496 -0
- package/src/__tests__/harnesses/SessionSummaryEquivalence.test.ts +726 -0
- package/src/__tests__/harnesses/antigravity/AntigravityCliAdapter.subprocess.test.ts +133 -0
- package/src/__tests__/{adapters → harnesses/antigravity}/AntigravityCliAdapter.test.ts +97 -25
- package/src/__tests__/harnesses/builtinAdapters.test.ts +33 -0
- package/src/__tests__/{providers → harnesses}/claude/ClaudeAgentMapper.test.ts +5 -5
- package/src/__tests__/{adapters → harnesses/claude}/ClaudeCodeAdapter.test.ts +54 -24
- package/src/__tests__/{providers → harnesses}/claude/ClaudeSessionLocator.test.ts +1 -12
- package/src/__tests__/{utils → harnesses/claude}/ClaudeSessionParser.test.ts +2 -2
- package/src/__tests__/{print → harnesses/claude/durable}/ClaudeCliProbe.test.ts +1 -1
- package/src/__tests__/{print → harnesses/claude/durable}/ClaudePrintAgent.integration.test.ts +1 -1
- package/src/__tests__/{print → harnesses/claude/durable}/ClaudePrintAgentService.test.ts +4 -4
- package/src/__tests__/{print → harnesses/claude/durable}/ClaudePrintRunner.test.ts +2 -2
- package/src/__tests__/{adapters → harnesses/codex}/CodexAdapter.test.ts +277 -12
- package/src/__tests__/harnesses/codex/CodexSessionLocator.test.ts +419 -0
- package/src/__tests__/{providers → harnesses}/codex/CodexSessionMapping.test.ts +1 -1
- package/src/__tests__/{providers → harnesses}/codex/CodexSessionParser.test.ts +1 -1
- package/src/__tests__/{durable → harnesses/codex/durable}/CodexCliProbe.test.ts +4 -4
- package/src/__tests__/{durable → harnesses/codex/durable}/CodexDurableAgentRepository.test.ts +1 -1
- package/src/__tests__/{durable → harnesses/codex/durable}/CodexPrintAgent.integration.test.ts +1 -1
- package/src/__tests__/{durable → harnesses/codex/durable}/CodexPrintAgentService.test.ts +8 -18
- package/src/__tests__/{durable → harnesses/codex/durable}/CodexPrintRunner.test.ts +3 -9
- package/src/__tests__/{providers → harnesses}/copilot/CopilotAdapter.test.ts +1 -1
- package/src/__tests__/harnesses/copilot/CopilotRefreshIO.test.ts +270 -0
- package/src/__tests__/{providers → harnesses}/gemini/GeminiCliAdapter.test.ts +27 -23
- package/src/__tests__/harnesses/gemini/GeminiSessionJsonl.test.ts +402 -0
- package/src/__tests__/harnesses/gemini/GeminiSessionLocator.test.ts +396 -0
- package/src/__tests__/{providers → harnesses}/grok/GrokAgentMapper.test.ts +2 -2
- package/src/__tests__/{providers → harnesses}/grok/GrokCliAdapter.test.ts +1 -1
- package/src/__tests__/harnesses/grok/GrokIncrementalRefresh.test.ts +170 -0
- package/src/__tests__/{providers → harnesses}/grok/GrokSessionLocator.test.ts +1 -1
- package/src/__tests__/harnesses/grok/GrokSessionParser.test.ts +230 -0
- package/src/__tests__/{adapters → harnesses/kiro}/KiroAdapter.test.ts +127 -109
- package/src/__tests__/{providers → harnesses}/opencode/OpenCodeAdapter.test.ts +1 -1
- package/src/__tests__/{providers → harnesses}/opencode/OpenCodeAgentMapper.test.ts +1 -1
- package/src/__tests__/{providers → harnesses}/opencode/OpenCodeSessionLocator.test.ts +2 -2
- package/src/__tests__/{providers → harnesses}/opencode/OpenCodeSessionParser.test.ts +1 -1
- package/src/__tests__/{providers → harnesses}/pi/PiAdapter.test.ts +1 -1
- package/src/__tests__/harnesses/pi/PiDiscoveryIO.test.ts +337 -0
- package/src/__tests__/{providers → harnesses}/pi/PiSessionParser.test.ts +91 -1
- package/src/__tests__/{providers → harnesses}/pi/PiSessionTracker.test.ts +1 -1
- package/src/__tests__/{providers → harnesses}/pi/durable/PiPrintProtocol.test.ts +1 -1
- package/src/__tests__/{providers → harnesses}/pi/durable/PiStreamParser.test.ts +1 -1
- package/src/__tests__/readiness/AgentReadiness.test.ts +16 -0
- package/src/__tests__/runtime/ManagedAgentRuntime.test.ts +30 -0
- package/src/__tests__/utils/IncrementalJsonlSummary.test.ts +414 -0
- package/src/__tests__/utils/agents.test.ts +76 -2
- package/src/__tests__/utils/conversationTail.bench.test.ts +193 -0
- package/src/__tests__/utils/conversationTailParity.test.ts +365 -0
- package/src/__tests__/utils/jsonlTail.test.ts +317 -0
- package/src/__tests__/utils/matchingConstants.test.ts +40 -0
- package/src/__tests__/utils/process.test.ts +254 -0
- package/src/adapters/AgentAdapter.ts +37 -14
- package/src/capacity/openai.ts +0 -6
- package/src/harnesses/antigravity/AntigravityAgentMapper.ts +34 -0
- package/src/harnesses/antigravity/AntigravityCliAdapter.ts +126 -0
- package/src/harnesses/antigravity/AntigravitySessionLocator.ts +75 -0
- package/src/harnesses/antigravity/AntigravitySessionParser.ts +252 -0
- package/src/{providers → harnesses}/claude/ClaudeAgentMapper.ts +2 -10
- package/src/{providers → harnesses}/claude/ClaudeCodeAdapter.ts +22 -20
- package/src/{providers → harnesses}/claude/ClaudeSessionLocator.ts +3 -3
- package/src/{providers → harnesses}/claude/ClaudeSessionParser.ts +189 -97
- package/src/{providers → harnesses}/codex/CodexAdapter.ts +153 -29
- package/src/{providers → harnesses}/codex/CodexAgentMapper.ts +2 -11
- package/src/harnesses/codex/CodexSessionLocator.ts +509 -0
- package/src/{providers → harnesses}/codex/CodexSessionMapping.ts +3 -3
- package/src/{providers → harnesses}/codex/CodexSessionParser.ts +169 -92
- package/src/{providers → harnesses}/copilot/CopilotAdapter.ts +22 -22
- package/src/{providers → harnesses}/copilot/CopilotAgentMapper.ts +2 -11
- package/src/harnesses/copilot/CopilotSessionLocator.ts +161 -0
- package/src/harnesses/copilot/CopilotSessionParser.ts +380 -0
- package/src/{providers → harnesses}/gemini/GeminiAgentMapper.ts +2 -11
- package/src/{providers → harnesses}/gemini/GeminiCliAdapter.ts +7 -9
- package/src/harnesses/gemini/GeminiSessionLocator.ts +394 -0
- package/src/{providers → harnesses}/gemini/GeminiSessionParser.ts +155 -31
- package/src/harnesses/gemini/fileSignature.ts +10 -0
- package/src/{providers → harnesses}/grok/GrokAgentMapper.ts +2 -11
- package/src/{providers → harnesses}/grok/GrokCliAdapter.ts +16 -15
- package/src/{providers → harnesses}/grok/GrokSessionLocator.ts +2 -2
- package/src/harnesses/grok/GrokSessionParser.ts +251 -0
- package/src/harnesses/index.ts +28 -0
- package/src/harnesses/kiro/KiroAdapter.ts +143 -0
- package/src/harnesses/kiro/KiroAgentMapper.ts +34 -0
- package/src/harnesses/kiro/KiroSessionLocator.ts +143 -0
- package/src/harnesses/kiro/KiroSessionParser.ts +376 -0
- package/src/{providers → harnesses}/opencode/OpenCodeAdapter.ts +5 -11
- package/src/{providers → harnesses}/opencode/OpenCodeAgentMapper.ts +3 -13
- package/src/{providers → harnesses}/opencode/OpenCodeSessionLocator.ts +2 -2
- package/src/{providers → harnesses}/opencode/OpenCodeSessionParser.ts +4 -3
- package/src/{providers → harnesses}/pi/PiAdapter.ts +20 -18
- package/src/{providers → harnesses}/pi/PiAgentMapper.ts +2 -11
- package/src/harnesses/pi/PiSessionLocator.ts +288 -0
- package/src/harnesses/pi/PiSessionParser.ts +488 -0
- package/src/{providers → harnesses}/pi/PiSessionTracker.ts +2 -2
- package/src/harnesses/shared.ts +119 -0
- package/src/index.ts +26 -24
- package/src/utils/IncrementalJsonlSummary.ts +306 -0
- package/src/utils/agents.ts +60 -28
- package/src/utils/index.ts +2 -0
- package/src/utils/jsonlTail.ts +349 -0
- package/src/utils/matching.ts +3 -3
- package/src/utils/matchingConstants.ts +15 -0
- package/src/utils/process.ts +189 -45
- package/dist/__tests__/adapters/AntigravityCliAdapter.test.js.map +0 -1
- package/dist/__tests__/adapters/ClaudeCodeAdapter.test.js.map +0 -1
- package/dist/__tests__/adapters/CodexAdapter.test.js.map +0 -1
- package/dist/__tests__/adapters/KiroAdapter.test.js.map +0 -1
- package/dist/__tests__/durable/CodexCliProbe.test.js.map +0 -1
- package/dist/__tests__/durable/CodexDurableAgentRepository.test.js.map +0 -1
- package/dist/__tests__/durable/CodexPrintAgent.integration.test.js.map +0 -1
- package/dist/__tests__/durable/CodexPrintAgentService.test.js.map +0 -1
- package/dist/__tests__/durable/CodexPrintRunner.test.js.map +0 -1
- package/dist/__tests__/print/ClaudeCliProbe.test.js.map +0 -1
- package/dist/__tests__/print/ClaudePrintAgent.integration.test.js.map +0 -1
- package/dist/__tests__/print/ClaudePrintAgentService.test.js.map +0 -1
- package/dist/__tests__/print/ClaudePrintRunner.test.js.map +0 -1
- package/dist/__tests__/providers/claude/ClaudeAgentMapper.test.js.map +0 -1
- package/dist/__tests__/providers/codex/CodexSessionLocator.test.js +0 -194
- package/dist/__tests__/providers/codex/CodexSessionLocator.test.js.map +0 -1
- package/dist/__tests__/providers/gemini/GeminiCliAdapter.test.js.map +0 -1
- package/dist/__tests__/providers/pi/PiSessionParser.test.js.map +0 -1
- package/dist/__tests__/utils/ClaudeSessionParser.test.js.map +0 -1
- package/dist/adapters/AntigravityCliAdapter.d.ts +0 -57
- package/dist/adapters/AntigravityCliAdapter.d.ts.map +0 -1
- package/dist/adapters/AntigravityCliAdapter.js +0 -273
- package/dist/adapters/AntigravityCliAdapter.js.map +0 -1
- package/dist/adapters/KiroAdapter.d.ts +0 -46
- package/dist/adapters/KiroAdapter.d.ts.map +0 -1
- package/dist/adapters/KiroAdapter.js +0 -344
- package/dist/adapters/KiroAdapter.js.map +0 -1
- package/dist/adapters/index.d.ts +0 -12
- package/dist/adapters/index.d.ts.map +0 -1
- package/dist/adapters/index.js +0 -12
- package/dist/adapters/index.js.map +0 -1
- package/dist/providers/claude/ClaudeAgentMapper.js.map +0 -1
- package/dist/providers/claude/ClaudeCodeAdapter.d.ts.map +0 -1
- package/dist/providers/claude/ClaudeCodeAdapter.js.map +0 -1
- package/dist/providers/claude/ClaudeSessionLocator.js.map +0 -1
- package/dist/providers/claude/ClaudeSessionParser.d.ts.map +0 -1
- package/dist/providers/claude/ClaudeSessionParser.js.map +0 -1
- package/dist/providers/codex/CodexAdapter.d.ts.map +0 -1
- package/dist/providers/codex/CodexAdapter.js.map +0 -1
- package/dist/providers/codex/CodexAgentMapper.js.map +0 -1
- package/dist/providers/codex/CodexSessionLocator.d.ts +0 -44
- package/dist/providers/codex/CodexSessionLocator.d.ts.map +0 -1
- package/dist/providers/codex/CodexSessionLocator.js +0 -207
- package/dist/providers/codex/CodexSessionLocator.js.map +0 -1
- package/dist/providers/codex/CodexSessionMapping.js.map +0 -1
- package/dist/providers/codex/CodexSessionParser.d.ts +0 -58
- package/dist/providers/codex/CodexSessionParser.d.ts.map +0 -1
- package/dist/providers/codex/CodexSessionParser.js.map +0 -1
- package/dist/providers/copilot/CopilotAdapter.d.ts.map +0 -1
- package/dist/providers/copilot/CopilotAdapter.js.map +0 -1
- package/dist/providers/copilot/CopilotAgentMapper.js.map +0 -1
- package/dist/providers/copilot/CopilotSessionLocator.d.ts +0 -20
- package/dist/providers/copilot/CopilotSessionLocator.d.ts.map +0 -1
- package/dist/providers/copilot/CopilotSessionLocator.js +0 -49
- package/dist/providers/copilot/CopilotSessionLocator.js.map +0 -1
- package/dist/providers/copilot/CopilotSessionParser.d.ts +0 -30
- package/dist/providers/copilot/CopilotSessionParser.d.ts.map +0 -1
- package/dist/providers/copilot/CopilotSessionParser.js +0 -181
- package/dist/providers/copilot/CopilotSessionParser.js.map +0 -1
- package/dist/providers/gemini/GeminiAgentMapper.js.map +0 -1
- package/dist/providers/gemini/GeminiCliAdapter.d.ts.map +0 -1
- package/dist/providers/gemini/GeminiCliAdapter.js.map +0 -1
- package/dist/providers/gemini/GeminiSessionLocator.d.ts +0 -30
- package/dist/providers/gemini/GeminiSessionLocator.d.ts.map +0 -1
- package/dist/providers/gemini/GeminiSessionLocator.js +0 -142
- package/dist/providers/gemini/GeminiSessionLocator.js.map +0 -1
- package/dist/providers/gemini/GeminiSessionParser.d.ts.map +0 -1
- package/dist/providers/gemini/GeminiSessionParser.js +0 -166
- package/dist/providers/gemini/GeminiSessionParser.js.map +0 -1
- package/dist/providers/grok/GrokAgentMapper.js.map +0 -1
- package/dist/providers/grok/GrokCliAdapter.d.ts.map +0 -1
- package/dist/providers/grok/GrokCliAdapter.js.map +0 -1
- package/dist/providers/grok/GrokSessionLocator.js.map +0 -1
- package/dist/providers/grok/GrokSessionParser.d.ts +0 -54
- package/dist/providers/grok/GrokSessionParser.d.ts.map +0 -1
- package/dist/providers/grok/GrokSessionParser.js +0 -122
- package/dist/providers/grok/GrokSessionParser.js.map +0 -1
- package/dist/providers/opencode/OpenCodeAdapter.d.ts.map +0 -1
- package/dist/providers/opencode/OpenCodeAdapter.js.map +0 -1
- package/dist/providers/opencode/OpenCodeAgentMapper.js.map +0 -1
- package/dist/providers/opencode/OpenCodeSessionLocator.js.map +0 -1
- package/dist/providers/opencode/OpenCodeSessionParser.d.ts.map +0 -1
- package/dist/providers/opencode/OpenCodeSessionParser.js.map +0 -1
- package/dist/providers/pi/PiAdapter.d.ts.map +0 -1
- package/dist/providers/pi/PiAdapter.js.map +0 -1
- package/dist/providers/pi/PiAgentMapper.js.map +0 -1
- package/dist/providers/pi/PiSessionLocator.d.ts +0 -24
- package/dist/providers/pi/PiSessionLocator.d.ts.map +0 -1
- package/dist/providers/pi/PiSessionLocator.js +0 -86
- package/dist/providers/pi/PiSessionLocator.js.map +0 -1
- package/dist/providers/pi/PiSessionParser.d.ts +0 -36
- package/dist/providers/pi/PiSessionParser.d.ts.map +0 -1
- package/dist/providers/pi/PiSessionParser.js +0 -191
- package/dist/providers/pi/PiSessionParser.js.map +0 -1
- package/dist/providers/pi/PiSessionTracker.js.map +0 -1
- package/src/__tests__/fixtures/fake-claude.cjs +0 -31
- package/src/__tests__/fixtures/fake-codex.cjs +0 -56
- package/src/__tests__/providers/codex/CodexSessionLocator.test.ts +0 -182
- package/src/adapters/AntigravityCliAdapter.ts +0 -356
- package/src/adapters/KiroAdapter.ts +0 -456
- package/src/adapters/index.ts +0 -17
- package/src/providers/codex/CodexSessionLocator.ts +0 -279
- package/src/providers/copilot/CopilotSessionLocator.ts +0 -63
- package/src/providers/copilot/CopilotSessionParser.ts +0 -289
- package/src/providers/gemini/GeminiSessionLocator.ts +0 -183
- package/src/providers/grok/GrokSessionParser.ts +0 -166
- package/src/providers/pi/PiSessionLocator.ts +0 -110
- package/src/providers/pi/PiSessionParser.ts +0 -284
- /package/dist/__tests__/{providers → harnesses}/pi/durable/PiCliProbe.test.js +0 -0
- /package/dist/__tests__/{providers → harnesses}/pi/durable/PiDurableAgentRepository.test.js +0 -0
- /package/dist/__tests__/{providers → harnesses}/pi/durable/PiPrintAgentService.test.js +0 -0
- /package/dist/__tests__/{providers → harnesses}/pi/durable/PiPrintRunner.test.js +0 -0
- /package/dist/{providers → harnesses}/claude/ClaudeAgentMapper.d.ts +0 -0
- /package/dist/{providers → harnesses}/claude/ClaudeSessionLocator.d.ts +0 -0
- /package/dist/{providers → harnesses}/claude/durable/ClaudeCliProbe.d.ts +0 -0
- /package/dist/{providers → harnesses}/claude/durable/ClaudeCliProbe.js +0 -0
- /package/dist/{providers → harnesses}/claude/durable/ClaudePrintAgentService.d.ts +0 -0
- /package/dist/{providers → harnesses}/claude/durable/ClaudePrintAgentService.js +0 -0
- /package/dist/{providers → harnesses}/claude/durable/ClaudePrintRunner.d.ts +0 -0
- /package/dist/{providers → harnesses}/claude/durable/ClaudePrintRunner.js +0 -0
- /package/dist/{providers → harnesses}/claude/durable/ClaudeStreamParser.d.ts +0 -0
- /package/dist/{providers → harnesses}/claude/durable/ClaudeStreamParser.js +0 -0
- /package/dist/{providers → harnesses}/codex/CodexAgentMapper.d.ts +0 -0
- /package/dist/{providers → harnesses}/codex/CodexSessionMapping.d.ts +0 -0
- /package/dist/{providers → harnesses}/codex/durable/CodexCliProbe.d.ts +0 -0
- /package/dist/{providers → harnesses}/codex/durable/CodexCliProbe.js +0 -0
- /package/dist/{providers → harnesses}/codex/durable/CodexPrintAgentService.d.ts +0 -0
- /package/dist/{providers → harnesses}/codex/durable/CodexPrintAgentService.js +0 -0
- /package/dist/{providers → harnesses}/codex/durable/CodexPrintRunner.d.ts +0 -0
- /package/dist/{providers → harnesses}/codex/durable/CodexPrintRunner.js +0 -0
- /package/dist/{providers → harnesses}/codex/durable/CodexStreamParser.d.ts +0 -0
- /package/dist/{providers → harnesses}/codex/durable/CodexStreamParser.js +0 -0
- /package/dist/{providers → harnesses}/copilot/CopilotAgentMapper.d.ts +0 -0
- /package/dist/{providers → harnesses}/gemini/GeminiAgentMapper.d.ts +0 -0
- /package/dist/{providers → harnesses}/grok/GrokAgentMapper.d.ts +0 -0
- /package/dist/{providers → harnesses}/grok/GrokSessionLocator.d.ts +0 -0
- /package/dist/{providers → harnesses}/opencode/OpenCodeAgentMapper.d.ts +0 -0
- /package/dist/{providers → harnesses}/opencode/OpenCodeSessionLocator.d.ts +0 -0
- /package/dist/{providers → harnesses}/pi/PiAgentMapper.d.ts +0 -0
- /package/dist/{providers → harnesses}/pi/PiSessionTracker.d.ts +0 -0
- /package/dist/{providers → harnesses}/pi/durable/PiCliProbe.d.ts +0 -0
- /package/dist/{providers → harnesses}/pi/durable/PiCliProbe.js +0 -0
- /package/dist/{providers → harnesses}/pi/durable/PiPrintAgentService.d.ts +0 -0
- /package/dist/{providers → harnesses}/pi/durable/PiPrintAgentService.js +0 -0
- /package/dist/{providers → harnesses}/pi/durable/PiPrintProtocol.d.ts +0 -0
- /package/dist/{providers → harnesses}/pi/durable/PiPrintProtocol.js +0 -0
- /package/dist/{providers → harnesses}/pi/durable/PiPrintRunner.d.ts +0 -0
- /package/dist/{providers → harnesses}/pi/durable/PiPrintRunner.js +0 -0
- /package/dist/{providers → harnesses}/pi/durable/PiStreamParser.d.ts +0 -0
- /package/dist/{providers → harnesses}/pi/durable/PiStreamParser.js +0 -0
- /package/src/__tests__/{providers → harnesses}/pi/durable/PiCliProbe.test.ts +0 -0
- /package/src/__tests__/{providers → harnesses}/pi/durable/PiDurableAgentRepository.test.ts +0 -0
- /package/src/__tests__/{providers → harnesses}/pi/durable/PiPrintAgentService.test.ts +0 -0
- /package/src/__tests__/{providers → harnesses}/pi/durable/PiPrintRunner.test.ts +0 -0
- /package/src/{providers → harnesses}/claude/durable/ClaudeCliProbe.ts +0 -0
- /package/src/{providers → harnesses}/claude/durable/ClaudePrintAgentService.ts +0 -0
- /package/src/{providers → harnesses}/claude/durable/ClaudePrintRunner.ts +0 -0
- /package/src/{providers → harnesses}/claude/durable/ClaudeStreamParser.ts +0 -0
- /package/src/{providers → harnesses}/codex/durable/CodexCliProbe.ts +0 -0
- /package/src/{providers → harnesses}/codex/durable/CodexPrintAgentService.ts +0 -0
- /package/src/{providers → harnesses}/codex/durable/CodexPrintRunner.ts +0 -0
- /package/src/{providers → harnesses}/codex/durable/CodexStreamParser.ts +0 -0
- /package/src/{providers → harnesses}/pi/durable/PiCliProbe.ts +0 -0
- /package/src/{providers → harnesses}/pi/durable/PiPrintAgentService.ts +0 -0
- /package/src/{providers → harnesses}/pi/durable/PiPrintProtocol.ts +0 -0
- /package/src/{providers → harnesses}/pi/durable/PiPrintRunner.ts +0 -0
- /package/src/{providers → harnesses}/pi/durable/PiStreamParser.ts +0 -0
|
@@ -0,0 +1,394 @@
|
|
|
1
|
+
import * as crypto from "crypto";
|
|
2
|
+
import * as fs from "fs";
|
|
3
|
+
import * as path from "path";
|
|
4
|
+
import type { ProcessInfo } from "../../adapters/AgentAdapter.js";
|
|
5
|
+
import { MATCH_TOLERANCE_MS } from "../../utils/matchingConstants.js";
|
|
6
|
+
import type { SessionFile } from "../../utils/session.js";
|
|
7
|
+
import { isDirectory, safeReadFile, safeReaddir, safeStat } from "../../utils/session.js";
|
|
8
|
+
import { fileSignature } from "./fileSignature.js";
|
|
9
|
+
import { isSessionLogPath } from "./GeminiSessionParser.js";
|
|
10
|
+
import { homeDir } from "../shared.js";
|
|
11
|
+
|
|
12
|
+
export interface GeminiSessionDiscovery {
|
|
13
|
+
sessions: SessionFile[];
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface GeminiSessionLocatorOptions {
|
|
17
|
+
geminiTmpDir?: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
interface GeminiSessionMetadata {
|
|
21
|
+
sessionId?: string;
|
|
22
|
+
projectHash?: string;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
interface CachedSessionMetadata extends GeminiSessionMetadata {
|
|
26
|
+
signature: string;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
interface CachedProjectMarker {
|
|
30
|
+
signature: string;
|
|
31
|
+
projectRoot: string;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
interface CandidateProjects {
|
|
35
|
+
/** sha256(projectRoot) -> process CWD that may own sessions for that root. */
|
|
36
|
+
cwdByHash: Map<string, string>;
|
|
37
|
+
/** Normalized candidate project roots, compared against `.project_root` markers. */
|
|
38
|
+
roots: Set<string>;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const SESSION_FILE_PREFIX = "session-";
|
|
42
|
+
/** Legacy single-document sessions. */
|
|
43
|
+
const SESSION_DOCUMENT_EXTENSION = ".json";
|
|
44
|
+
/** Gemini CLI 0.46+ append-only session logs; line 1 is the metadata record. */
|
|
45
|
+
const SESSION_LOG_EXTENSION = ".jsonl";
|
|
46
|
+
const CHATS_DIR_NAME = "chats";
|
|
47
|
+
/** Ownership marker Gemini CLI writes into slug-named project temp dirs. */
|
|
48
|
+
const PROJECT_ROOT_MARKER = ".project_root";
|
|
49
|
+
/** Legacy Gemini CLI temp dirs are named sha256(projectRoot). */
|
|
50
|
+
const LEGACY_HASH_DIR_PATTERN = /^[0-9a-f]{64}$/;
|
|
51
|
+
/** Slack for coarse filesystem timestamp granularity. */
|
|
52
|
+
const MTIME_SLACK_MS = 2 * 1000;
|
|
53
|
+
/**
|
|
54
|
+
* Both formats start with sessionId/projectHash (a legacy document's leading
|
|
55
|
+
* keys, a log's line-1 metadata record); a small head is enough.
|
|
56
|
+
*/
|
|
57
|
+
const METADATA_HEAD_BYTES = 8 * 1024;
|
|
58
|
+
|
|
59
|
+
export class GeminiSessionLocator {
|
|
60
|
+
private readonly geminiTmpDir: string;
|
|
61
|
+
private metadataCache = new Map<string, CachedSessionMetadata>();
|
|
62
|
+
private markerCache = new Map<string, CachedProjectMarker>();
|
|
63
|
+
|
|
64
|
+
constructor(options: GeminiSessionLocatorOptions = {}) {
|
|
65
|
+
this.geminiTmpDir = options.geminiTmpDir ?? path.join(homeDir(), ".gemini", "tmp");
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Discover session files for the given processes.
|
|
70
|
+
*
|
|
71
|
+
* Gemini CLI writes sessions to ~/.gemini/tmp/<shortId>/chats/session-*.jsonl
|
|
72
|
+
* (0.46+; older versions wrote session-*.json) where <shortId> is either sha256(projectRoot) (legacy) or a slug whose
|
|
73
|
+
* owner is recorded in <shortId>/.project_root. Each session's projectHash
|
|
74
|
+
* is matched against sha256 of every candidate project root of a process.
|
|
75
|
+
*
|
|
76
|
+
* To keep each refresh cheap:
|
|
77
|
+
* - project dirs whose name or marker can't belong to a candidate root are
|
|
78
|
+
* skipped without listing or opening their chats;
|
|
79
|
+
* - chat files last modified before the earliest candidate process start
|
|
80
|
+
* (minus the matching tolerance) are skipped after a stat;
|
|
81
|
+
* - sessionId/projectHash come from a bounded head read, cached by
|
|
82
|
+
* inode+size+mtime, so unchanged files are never re-read.
|
|
83
|
+
*/
|
|
84
|
+
discoverSessions(processes: ProcessInfo[]): GeminiSessionDiscovery {
|
|
85
|
+
const empty: GeminiSessionDiscovery = { sessions: [] };
|
|
86
|
+
if (!fs.existsSync(this.geminiTmpDir)) return empty;
|
|
87
|
+
|
|
88
|
+
const candidates = this.buildCandidateProjects(processes);
|
|
89
|
+
if (candidates.cwdByHash.size === 0) return empty;
|
|
90
|
+
|
|
91
|
+
let shortIdEntries: string[];
|
|
92
|
+
try {
|
|
93
|
+
shortIdEntries = fs.readdirSync(this.geminiTmpDir);
|
|
94
|
+
} catch {
|
|
95
|
+
return empty;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const minMtimeMs = this.earliestMatchableMtime(processes);
|
|
99
|
+
const nextMetadataCache = new Map<string, CachedSessionMetadata>();
|
|
100
|
+
const nextMarkerCache = new Map<string, CachedProjectMarker>();
|
|
101
|
+
const sessions: SessionFile[] = [];
|
|
102
|
+
|
|
103
|
+
for (const shortId of shortIdEntries) {
|
|
104
|
+
const projectDir = path.join(this.geminiTmpDir, shortId);
|
|
105
|
+
if (!this.mayBelongToCandidates(projectDir, shortId, candidates, nextMarkerCache)) continue;
|
|
106
|
+
|
|
107
|
+
const chatsDir = path.join(projectDir, CHATS_DIR_NAME);
|
|
108
|
+
if (!isDirectory(chatsDir)) continue;
|
|
109
|
+
|
|
110
|
+
for (const fileName of this.listSessionFileNames(chatsDir)) {
|
|
111
|
+
const session = this.readCandidateSession(
|
|
112
|
+
chatsDir,
|
|
113
|
+
fileName,
|
|
114
|
+
candidates.cwdByHash,
|
|
115
|
+
minMtimeMs,
|
|
116
|
+
nextMetadataCache,
|
|
117
|
+
);
|
|
118
|
+
if (session) sessions.push(session);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Keep metadata only for files still in scope so the caches stay bounded.
|
|
123
|
+
this.metadataCache = nextMetadataCache;
|
|
124
|
+
this.markerCache = nextMarkerCache;
|
|
125
|
+
return { sessions };
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
discoverHistoricalSessionFiles(): string[] {
|
|
129
|
+
if (!isDirectory(this.geminiTmpDir)) return [];
|
|
130
|
+
|
|
131
|
+
const files: string[] = [];
|
|
132
|
+
for (const shortId of safeReaddir(this.geminiTmpDir)) {
|
|
133
|
+
const chatsDir = path.join(this.geminiTmpDir, shortId, CHATS_DIR_NAME);
|
|
134
|
+
if (!isDirectory(chatsDir)) continue;
|
|
135
|
+
|
|
136
|
+
for (const fileName of this.listSessionFileNames(chatsDir)) {
|
|
137
|
+
files.push(path.join(chatsDir, fileName));
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
return files;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
private readCandidateSession(
|
|
145
|
+
chatsDir: string,
|
|
146
|
+
fileName: string,
|
|
147
|
+
cwdByHash: Map<string, string>,
|
|
148
|
+
minMtimeMs: number,
|
|
149
|
+
nextMetadataCache: Map<string, CachedSessionMetadata>,
|
|
150
|
+
): SessionFile | null {
|
|
151
|
+
const filePath = path.join(chatsDir, fileName);
|
|
152
|
+
|
|
153
|
+
const stat = safeStat(filePath);
|
|
154
|
+
if (!stat || stat.mtimeMs < minMtimeMs) return null;
|
|
155
|
+
|
|
156
|
+
const metadata = this.readSessionMetadata(filePath, stat);
|
|
157
|
+
nextMetadataCache.set(filePath, metadata);
|
|
158
|
+
if (!metadata.projectHash) return null;
|
|
159
|
+
|
|
160
|
+
const resolvedCwd = cwdByHash.get(metadata.projectHash);
|
|
161
|
+
if (!resolvedCwd) return null;
|
|
162
|
+
|
|
163
|
+
return {
|
|
164
|
+
sessionId: metadata.sessionId || fileName.replace(/\.jsonl?$/, ""),
|
|
165
|
+
filePath,
|
|
166
|
+
projectDir: chatsDir,
|
|
167
|
+
birthtimeMs: stat.birthtimeMs,
|
|
168
|
+
resolvedCwd,
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
private readSessionMetadata(filePath: string, stat: fs.Stats): CachedSessionMetadata {
|
|
173
|
+
const signature = fileSignature(stat);
|
|
174
|
+
const cached = this.metadataCache.get(filePath);
|
|
175
|
+
if (cached?.signature === signature) return cached;
|
|
176
|
+
|
|
177
|
+
return { signature, ...this.extractSessionMetadata(filePath) };
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Read sessionId/projectHash from the first METADATA_HEAD_BYTES. Files that
|
|
182
|
+
* fit in the head are parsed as JSON exactly; larger files are scanned for
|
|
183
|
+
* the leading keys and only fully parsed when the head lacks them.
|
|
184
|
+
*/
|
|
185
|
+
private extractSessionMetadata(filePath: string): GeminiSessionMetadata {
|
|
186
|
+
const head = this.readHead(filePath);
|
|
187
|
+
if (head === null) return {};
|
|
188
|
+
if (isSessionLogPath(filePath)) return this.extractLogMetadata(head);
|
|
189
|
+
if (head.complete) return this.pickMetadata(this.parseSessionMetadata(head.text));
|
|
190
|
+
|
|
191
|
+
const sessionId = this.matchStringField(head.text, "sessionId");
|
|
192
|
+
const projectHash = this.matchStringField(head.text, "projectHash");
|
|
193
|
+
if (sessionId !== undefined && projectHash !== undefined) {
|
|
194
|
+
return { sessionId, projectHash };
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
const content = safeReadFile(filePath);
|
|
198
|
+
if (content === undefined) return {};
|
|
199
|
+
return this.pickMetadata(this.parseSessionMetadata(content));
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* A `.jsonl` log's metadata is its first line. Never fall back to reading
|
|
204
|
+
* the whole log: it only grows, and a log whose first record is not
|
|
205
|
+
* metadata cannot be attributed from its head anyway.
|
|
206
|
+
*/
|
|
207
|
+
private extractLogMetadata(head: { text: string; complete: boolean }): GeminiSessionMetadata {
|
|
208
|
+
const newline = head.text.indexOf("\n");
|
|
209
|
+
if (newline !== -1 || head.complete) {
|
|
210
|
+
const firstLine = newline === -1 ? head.text : head.text.slice(0, newline);
|
|
211
|
+
return this.pickMetadata(this.parseSessionMetadata(firstLine));
|
|
212
|
+
}
|
|
213
|
+
// First line longer than the head: pick the leading keys from its prefix.
|
|
214
|
+
return {
|
|
215
|
+
sessionId: this.matchStringField(head.text, "sessionId"),
|
|
216
|
+
projectHash: this.matchStringField(head.text, "projectHash"),
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
private readHead(filePath: string): { text: string; complete: boolean } | null {
|
|
221
|
+
let fd: number | undefined;
|
|
222
|
+
try {
|
|
223
|
+
fd = fs.openSync(filePath, "r");
|
|
224
|
+
// One extra byte tells "exactly METADATA_HEAD_BYTES long" from "longer".
|
|
225
|
+
const buffer = Buffer.alloc(METADATA_HEAD_BYTES + 1);
|
|
226
|
+
let length = 0;
|
|
227
|
+
while (length < buffer.length) {
|
|
228
|
+
const bytesRead = fs.readSync(fd, buffer, length, buffer.length - length, length);
|
|
229
|
+
if (bytesRead === 0) break;
|
|
230
|
+
length += bytesRead;
|
|
231
|
+
}
|
|
232
|
+
return {
|
|
233
|
+
text: buffer.toString("utf-8", 0, Math.min(length, METADATA_HEAD_BYTES)),
|
|
234
|
+
complete: length <= METADATA_HEAD_BYTES,
|
|
235
|
+
};
|
|
236
|
+
} catch {
|
|
237
|
+
return null;
|
|
238
|
+
} finally {
|
|
239
|
+
if (fd !== undefined) {
|
|
240
|
+
try {
|
|
241
|
+
fs.closeSync(fd);
|
|
242
|
+
} catch {
|
|
243
|
+
// Nothing useful to do if closing a read-only descriptor fails.
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
private matchStringField(text: string, key: string): string | undefined {
|
|
250
|
+
const match = new RegExp(`"${key}"\\s*:\\s*"((?:[^"\\\\]|\\\\.)*)"`).exec(text);
|
|
251
|
+
if (!match) return undefined;
|
|
252
|
+
try {
|
|
253
|
+
return JSON.parse(`"${match[1]}"`) as string;
|
|
254
|
+
} catch {
|
|
255
|
+
return undefined;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
private pickMetadata(parsed: GeminiSessionMetadata | null): GeminiSessionMetadata {
|
|
260
|
+
if (!parsed || typeof parsed !== "object") return {};
|
|
261
|
+
return { sessionId: parsed.sessionId, projectHash: parsed.projectHash };
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* Decide from the directory name or its `.project_root` marker whether a
|
|
266
|
+
* project temp dir can hold sessions for a candidate root. Dirs with no
|
|
267
|
+
* recognisable ownership are scanned conservatively.
|
|
268
|
+
*/
|
|
269
|
+
private mayBelongToCandidates(
|
|
270
|
+
projectDir: string,
|
|
271
|
+
shortId: string,
|
|
272
|
+
candidates: CandidateProjects,
|
|
273
|
+
nextMarkerCache: Map<string, CachedProjectMarker>,
|
|
274
|
+
): boolean {
|
|
275
|
+
if (LEGACY_HASH_DIR_PATTERN.test(shortId)) return candidates.cwdByHash.has(shortId);
|
|
276
|
+
|
|
277
|
+
const projectRoot = this.readProjectMarker(projectDir, nextMarkerCache);
|
|
278
|
+
if (projectRoot === undefined) return true;
|
|
279
|
+
return candidates.roots.has(this.normalizeRoot(projectRoot));
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
private readProjectMarker(
|
|
283
|
+
projectDir: string,
|
|
284
|
+
nextMarkerCache: Map<string, CachedProjectMarker>,
|
|
285
|
+
): string | undefined {
|
|
286
|
+
const markerPath = path.join(projectDir, PROJECT_ROOT_MARKER);
|
|
287
|
+
const stat = safeStat(markerPath);
|
|
288
|
+
if (!stat?.isFile()) return undefined;
|
|
289
|
+
|
|
290
|
+
const signature = fileSignature(stat);
|
|
291
|
+
const cached = this.markerCache.get(markerPath);
|
|
292
|
+
const projectRoot =
|
|
293
|
+
cached?.signature === signature ? cached.projectRoot : safeReadFile(markerPath)?.trim();
|
|
294
|
+
if (!projectRoot) return undefined;
|
|
295
|
+
|
|
296
|
+
nextMarkerCache.set(markerPath, { signature, projectRoot });
|
|
297
|
+
return projectRoot;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
private earliestMatchableMtime(processes: ProcessInfo[]): number {
|
|
301
|
+
let earliestStartMs = Number.POSITIVE_INFINITY;
|
|
302
|
+
for (const proc of processes) {
|
|
303
|
+
if (!proc.cwd || !proc.startTime) continue;
|
|
304
|
+
const startMs = proc.startTime.getTime();
|
|
305
|
+
if (Number.isFinite(startMs)) earliestStartMs = Math.min(earliestStartMs, startMs);
|
|
306
|
+
}
|
|
307
|
+
// No start times: nothing can be windowed safely, so scan every file.
|
|
308
|
+
if (!Number.isFinite(earliestStartMs)) return Number.NEGATIVE_INFINITY;
|
|
309
|
+
// A file last modified before (earliest start - matcher tolerance) was also
|
|
310
|
+
// born before it, so it can never be matched to any candidate process.
|
|
311
|
+
return earliestStartMs - MATCH_TOLERANCE_MS - MTIME_SLACK_MS;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
private buildCandidateProjects(processes: ProcessInfo[]): CandidateProjects {
|
|
315
|
+
const cwdByHash = new Map<string, string>();
|
|
316
|
+
const roots = new Set<string>();
|
|
317
|
+
for (const proc of processes) {
|
|
318
|
+
if (!proc.cwd) continue;
|
|
319
|
+
|
|
320
|
+
// Gemini CLI resolves its project root by walking up from the
|
|
321
|
+
// startup directory looking for a `.git` boundary marker. A
|
|
322
|
+
// session's projectHash therefore tracks that ancestor rather
|
|
323
|
+
// than the process' actual CWD. Enumerate every ancestor as a
|
|
324
|
+
// candidate so subdirectory invocations still line up with the
|
|
325
|
+
// session the Gemini process wrote.
|
|
326
|
+
for (const candidate of this.candidateProjectRoots(proc.cwd)) {
|
|
327
|
+
roots.add(this.normalizeRoot(candidate));
|
|
328
|
+
const hash = this.hashProjectRoot(candidate);
|
|
329
|
+
if (!cwdByHash.has(hash)) {
|
|
330
|
+
cwdByHash.set(hash, proc.cwd);
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
return { cwdByHash, roots };
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
/** Match Gemini CLI's project registry normalization (lower-cased on Windows). */
|
|
338
|
+
private normalizeRoot(projectRoot: string): string {
|
|
339
|
+
const resolved = path.resolve(projectRoot);
|
|
340
|
+
return process.platform === "win32" ? resolved.toLowerCase() : resolved;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
private candidateProjectRoots(cwd: string): string[] {
|
|
344
|
+
const roots: string[] = [];
|
|
345
|
+
let current = path.resolve(cwd);
|
|
346
|
+
let parent = path.dirname(current);
|
|
347
|
+
while (parent !== current) {
|
|
348
|
+
roots.push(current);
|
|
349
|
+
current = parent;
|
|
350
|
+
parent = path.dirname(current);
|
|
351
|
+
}
|
|
352
|
+
roots.push(current);
|
|
353
|
+
return roots;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
private hashProjectRoot(projectRoot: string): string {
|
|
357
|
+
return crypto.createHash("sha256").update(projectRoot).digest("hex");
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
/**
|
|
361
|
+
* Session files in a chats dir, in both formats. Resuming a legacy session
|
|
362
|
+
* makes Gemini CLI continue it in `<name>.jsonl` next to the stale
|
|
363
|
+
* `<name>.json`, so a `.json` with a `.jsonl` sibling is skipped.
|
|
364
|
+
*/
|
|
365
|
+
private listSessionFileNames(chatsDir: string): string[] {
|
|
366
|
+
const sessionFiles = safeReaddir(chatsDir).filter((fileName) => this.isSessionFile(fileName));
|
|
367
|
+
const names = new Set(sessionFiles);
|
|
368
|
+
return sessionFiles.filter(
|
|
369
|
+
(fileName) =>
|
|
370
|
+
!fileName.endsWith(SESSION_DOCUMENT_EXTENSION) ||
|
|
371
|
+
!names.has(this.toSessionLogName(fileName)),
|
|
372
|
+
);
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
private toSessionLogName(documentFileName: string): string {
|
|
376
|
+
const baseName = documentFileName.slice(0, -SESSION_DOCUMENT_EXTENSION.length);
|
|
377
|
+
return `${baseName}${SESSION_LOG_EXTENSION}`;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
private isSessionFile(fileName: string): boolean {
|
|
381
|
+
return (
|
|
382
|
+
fileName.startsWith(SESSION_FILE_PREFIX) &&
|
|
383
|
+
(fileName.endsWith(SESSION_DOCUMENT_EXTENSION) || fileName.endsWith(SESSION_LOG_EXTENSION))
|
|
384
|
+
);
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
private parseSessionMetadata(content: string): GeminiSessionMetadata | null {
|
|
388
|
+
try {
|
|
389
|
+
return JSON.parse(content) as GeminiSessionMetadata;
|
|
390
|
+
} catch {
|
|
391
|
+
return null;
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
}
|
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
import * as fs from "fs";
|
|
2
|
-
import type {
|
|
2
|
+
import type {
|
|
3
|
+
ConversationMessage,
|
|
4
|
+
ConversationOptions,
|
|
5
|
+
SessionSummary,
|
|
6
|
+
} from "../../adapters/AgentAdapter.js";
|
|
3
7
|
import { AgentStatus } from "../../adapters/AgentAdapter.js";
|
|
8
|
+
import { sliceTail } from "../../utils/jsonlTail.js";
|
|
4
9
|
import { safeReadFile, safeStat } from "../../utils/session.js";
|
|
10
|
+
import { fileSignature } from "./fileSignature.js";
|
|
11
|
+
import { isIdle, parseTimestamp, SUMMARY_MAX_LENGTH, truncate } from "../shared.js";
|
|
5
12
|
|
|
6
13
|
/**
|
|
7
14
|
* A single Gemini CLI message content part. Mirrors the `{text?: string}`
|
|
@@ -54,31 +61,70 @@ export interface GeminiSession {
|
|
|
54
61
|
lastMessageType?: string;
|
|
55
62
|
}
|
|
56
63
|
|
|
57
|
-
|
|
64
|
+
interface CachedParsedSession {
|
|
65
|
+
signature: string;
|
|
66
|
+
session: GeminiSession | null;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const SESSION_LOG_EXTENSION = ".jsonl";
|
|
70
|
+
/** Parsed sessions are small (summary is truncated); cap entries, not bytes. */
|
|
71
|
+
const MAX_CACHED_SESSIONS = 256;
|
|
58
72
|
|
|
59
73
|
export class GeminiSessionParser {
|
|
74
|
+
private readonly sessionCache = new Map<string, CachedParsedSession>();
|
|
75
|
+
|
|
60
76
|
/**
|
|
61
77
|
* Parse session file content into GeminiSession.
|
|
62
|
-
* Uses
|
|
78
|
+
* Uses the given content if available; otherwise reads from disk, reusing
|
|
79
|
+
* the previous result while the file's inode, size and mtime are unchanged.
|
|
63
80
|
*/
|
|
64
81
|
parseSession(cachedContent: string | undefined, filePath: string): GeminiSession | null {
|
|
65
|
-
const
|
|
66
|
-
if (
|
|
82
|
+
const fileStat = safeStat(filePath);
|
|
83
|
+
if (cachedContent !== undefined) return this.buildSession(cachedContent, filePath, fileStat);
|
|
84
|
+
|
|
85
|
+
if (!fileStat) {
|
|
86
|
+
this.sessionCache.delete(filePath);
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const signature = fileSignature(fileStat);
|
|
91
|
+
const cached = this.sessionCache.get(filePath);
|
|
92
|
+
if (cached?.signature === signature) return cached.session;
|
|
93
|
+
|
|
94
|
+
const content = this.readSessionFile(filePath);
|
|
95
|
+
const session = content === null ? null : this.buildSession(content, filePath, fileStat);
|
|
96
|
+
this.rememberSession(filePath, { signature, session });
|
|
97
|
+
return session;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
private rememberSession(filePath: string, entry: CachedParsedSession): void {
|
|
101
|
+
this.sessionCache.delete(filePath);
|
|
102
|
+
this.sessionCache.set(filePath, entry);
|
|
103
|
+
while (this.sessionCache.size > MAX_CACHED_SESSIONS) {
|
|
104
|
+
const oldest = this.sessionCache.keys().next().value;
|
|
105
|
+
if (oldest === undefined) break;
|
|
106
|
+
this.sessionCache.delete(oldest);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
67
109
|
|
|
68
|
-
|
|
110
|
+
private buildSession(
|
|
111
|
+
content: string,
|
|
112
|
+
filePath: string,
|
|
113
|
+
fileStat: fs.Stats | undefined,
|
|
114
|
+
): GeminiSession | null {
|
|
115
|
+
const parsed = this.parseSessionContent(content, filePath);
|
|
69
116
|
if (!parsed?.sessionId) return null;
|
|
70
117
|
|
|
71
118
|
const messages = Array.isArray(parsed.messages) ? parsed.messages : [];
|
|
72
119
|
const lastEntry = messages.length > 0 ? messages[messages.length - 1] : undefined;
|
|
73
|
-
const fileStat = safeStat(filePath);
|
|
74
120
|
|
|
75
121
|
const lastActive =
|
|
76
|
-
|
|
77
|
-
|
|
122
|
+
parseTimestamp(parsed.lastUpdated) ||
|
|
123
|
+
parseTimestamp(lastEntry?.timestamp) ||
|
|
78
124
|
fileStat?.mtime ||
|
|
79
125
|
new Date();
|
|
80
126
|
|
|
81
|
-
const sessionStart =
|
|
127
|
+
const sessionStart = parseTimestamp(parsed.startTime) || lastActive;
|
|
82
128
|
const projectPath =
|
|
83
129
|
Array.isArray(parsed.directories) && parsed.directories.length > 0
|
|
84
130
|
? parsed.directories[0]
|
|
@@ -95,10 +141,7 @@ export class GeminiSessionParser {
|
|
|
95
141
|
}
|
|
96
142
|
|
|
97
143
|
determineStatus(session: GeminiSession): AgentStatus {
|
|
98
|
-
|
|
99
|
-
const diffMinutes = diffMs / 60000;
|
|
100
|
-
|
|
101
|
-
if (diffMinutes > IDLE_THRESHOLD_MINUTES) {
|
|
144
|
+
if (isIdle(session.lastActive)) {
|
|
102
145
|
return AgentStatus.IDLE;
|
|
103
146
|
}
|
|
104
147
|
|
|
@@ -114,13 +157,17 @@ export class GeminiSessionParser {
|
|
|
114
157
|
*
|
|
115
158
|
* Gemini sessions store messages in an array with `type` field — typically
|
|
116
159
|
* 'user' or 'gemini' for visible turns, with tool and system entries mixed in.
|
|
160
|
+
*
|
|
161
|
+
* `tail` only slices the result: the session is a single JSON document, so
|
|
162
|
+
* it cannot be read from the end and is always parsed in full. Callers that
|
|
163
|
+
* poll (the console preview) rely on their mtime cache to skip re-parses.
|
|
117
164
|
*/
|
|
118
|
-
getConversation(sessionFilePath: string, options?:
|
|
165
|
+
getConversation(sessionFilePath: string, options?: ConversationOptions): ConversationMessage[] {
|
|
119
166
|
const verbose = options?.verbose ?? false;
|
|
120
167
|
const content = safeReadFile(sessionFilePath);
|
|
121
168
|
if (content === undefined) return [];
|
|
122
169
|
|
|
123
|
-
const parsed = this.
|
|
170
|
+
const parsed = this.parseSessionContent(content, sessionFilePath);
|
|
124
171
|
if (!Array.isArray(parsed?.messages)) return [];
|
|
125
172
|
|
|
126
173
|
const messages: ConversationMessage[] = [];
|
|
@@ -138,7 +185,7 @@ export class GeminiSessionParser {
|
|
|
138
185
|
});
|
|
139
186
|
}
|
|
140
187
|
|
|
141
|
-
return messages;
|
|
188
|
+
return sliceTail(messages, options?.tail);
|
|
142
189
|
}
|
|
143
190
|
|
|
144
191
|
/**
|
|
@@ -150,7 +197,7 @@ export class GeminiSessionParser {
|
|
|
150
197
|
const content = safeReadFile(filePath);
|
|
151
198
|
if (content === undefined) return null;
|
|
152
199
|
|
|
153
|
-
const parsed = this.
|
|
200
|
+
const parsed = this.parseSessionContent(content, filePath);
|
|
154
201
|
if (!parsed?.sessionId) return null;
|
|
155
202
|
|
|
156
203
|
const messages = Array.isArray(parsed.messages) ? parsed.messages : [];
|
|
@@ -161,13 +208,13 @@ export class GeminiSessionParser {
|
|
|
161
208
|
: "";
|
|
162
209
|
|
|
163
210
|
const stat = safeStat(filePath);
|
|
164
|
-
const lastEntryTimestamp =
|
|
211
|
+
const lastEntryTimestamp = parseTimestamp(
|
|
165
212
|
messages.length > 0 ? messages[messages.length - 1]?.timestamp : undefined,
|
|
166
213
|
);
|
|
167
214
|
const lastActive =
|
|
168
|
-
|
|
215
|
+
parseTimestamp(parsed.lastUpdated) || lastEntryTimestamp || stat?.mtime || new Date();
|
|
169
216
|
const startedAt =
|
|
170
|
-
|
|
217
|
+
parseTimestamp(parsed.startTime) || stat?.birthtime || stat?.mtime || lastActive;
|
|
171
218
|
|
|
172
219
|
return {
|
|
173
220
|
type: "gemini_cli",
|
|
@@ -180,6 +227,85 @@ export class GeminiSessionParser {
|
|
|
180
227
|
};
|
|
181
228
|
}
|
|
182
229
|
|
|
230
|
+
/**
|
|
231
|
+
* Parse either session format into the legacy single-document shape:
|
|
232
|
+
* `session-*.json` is one JSON document, `session-*.jsonl` (Gemini CLI
|
|
233
|
+
* 0.46+) is an append-only log replayed by {@link replaySessionLog}.
|
|
234
|
+
*/
|
|
235
|
+
private parseSessionContent(content: string, filePath: string): GeminiSessionFile | null {
|
|
236
|
+
return isSessionLogPath(filePath)
|
|
237
|
+
? this.replaySessionLog(content)
|
|
238
|
+
: this.parseSessionJson(content);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Rebuild a session document from a `.jsonl` log, mirroring Gemini CLI's
|
|
243
|
+
* own loader (`loadConversationRecord`):
|
|
244
|
+
* - a record with a string `id` is a message, upserted by id in place;
|
|
245
|
+
* - `{"$set": {...}}` merges metadata; a `$set.messages` array replaces
|
|
246
|
+
* every message;
|
|
247
|
+
* - `{"$rewindTo": id}` drops that message and all later ones (all
|
|
248
|
+
* messages when the id is unknown);
|
|
249
|
+
* - a record with `sessionId` and `projectHash` (line 1) merges metadata.
|
|
250
|
+
* Unknown operators, non-object lines and a torn trailing line (a write
|
|
251
|
+
* in progress) are ignored.
|
|
252
|
+
*/
|
|
253
|
+
private replaySessionLog(content: string): GeminiSessionFile | null {
|
|
254
|
+
let metadata: Record<string, unknown> = {};
|
|
255
|
+
const messages = new Map<string, GeminiMessageEntry>();
|
|
256
|
+
const upsertAll = (entries: unknown): void => {
|
|
257
|
+
if (!Array.isArray(entries)) return;
|
|
258
|
+
for (const entry of entries) {
|
|
259
|
+
if (isRecord(entry) && typeof entry.id === "string") messages.set(entry.id, entry);
|
|
260
|
+
}
|
|
261
|
+
};
|
|
262
|
+
|
|
263
|
+
for (const line of content.split("\n")) {
|
|
264
|
+
if (!line.trim()) continue;
|
|
265
|
+
const record = this.parseLogRecord(line);
|
|
266
|
+
if (!record) continue;
|
|
267
|
+
|
|
268
|
+
if (typeof record.$rewindTo === "string") {
|
|
269
|
+
this.rewindMessages(messages, record.$rewindTo);
|
|
270
|
+
} else if (typeof record.id === "string") {
|
|
271
|
+
messages.set(record.id, record);
|
|
272
|
+
} else if (isRecord(record.$set)) {
|
|
273
|
+
if (Array.isArray(record.$set.messages)) {
|
|
274
|
+
messages.clear();
|
|
275
|
+
upsertAll(record.$set.messages);
|
|
276
|
+
}
|
|
277
|
+
metadata = { ...metadata, ...record.$set };
|
|
278
|
+
} else if (typeof record.sessionId === "string" && typeof record.projectHash === "string") {
|
|
279
|
+
metadata = { ...metadata, ...record };
|
|
280
|
+
upsertAll(record.messages);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
if (typeof metadata.sessionId !== "string") return null;
|
|
285
|
+
return { ...(metadata as GeminiSessionFile), messages: Array.from(messages.values()) };
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
private rewindMessages(messages: Map<string, GeminiMessageEntry>, messageId: string): void {
|
|
289
|
+
if (!messages.has(messageId)) {
|
|
290
|
+
messages.clear();
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
293
|
+
let found = false;
|
|
294
|
+
for (const id of Array.from(messages.keys())) {
|
|
295
|
+
if (id === messageId) found = true;
|
|
296
|
+
if (found) messages.delete(id);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
private parseLogRecord(line: string): Record<string, unknown> | null {
|
|
301
|
+
try {
|
|
302
|
+
const record: unknown = JSON.parse(line);
|
|
303
|
+
return isRecord(record) ? record : null;
|
|
304
|
+
} catch {
|
|
305
|
+
return null;
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
|
|
183
309
|
private parseSessionJson(content: string): GeminiSessionFile | null {
|
|
184
310
|
try {
|
|
185
311
|
return JSON.parse(content) as GeminiSessionFile;
|
|
@@ -211,7 +337,7 @@ export class GeminiSessionParser {
|
|
|
211
337
|
const entry = messages[i];
|
|
212
338
|
if (entry?.type !== "user") continue;
|
|
213
339
|
const text = this.messageText(entry).trim();
|
|
214
|
-
if (text) return
|
|
340
|
+
if (text) return truncate(text, SUMMARY_MAX_LENGTH);
|
|
215
341
|
}
|
|
216
342
|
|
|
217
343
|
return "Gemini CLI session active";
|
|
@@ -257,15 +383,13 @@ export class GeminiSessionParser {
|
|
|
257
383
|
}
|
|
258
384
|
return "";
|
|
259
385
|
}
|
|
386
|
+
}
|
|
260
387
|
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
}
|
|
388
|
+
/** Gemini CLI 0.46+ writes sessions as append-only `.jsonl` logs. */
|
|
389
|
+
export function isSessionLogPath(filePath: string): boolean {
|
|
390
|
+
return filePath.endsWith(SESSION_LOG_EXTENSION);
|
|
391
|
+
}
|
|
266
392
|
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
return `${value.slice(0, maxLength - 3)}...`;
|
|
270
|
-
}
|
|
393
|
+
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
394
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
271
395
|
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type * as fs from "fs";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Identity of a file's current contents derived from `stat` alone:
|
|
5
|
+
* inode, size and mtime. Used to reuse metadata and parse results across
|
|
6
|
+
* refreshes without re-reading unchanged Gemini chat files.
|
|
7
|
+
*/
|
|
8
|
+
export function fileSignature(stat: fs.Stats): string {
|
|
9
|
+
return `${stat.ino}:${stat.size}:${stat.mtimeMs}`;
|
|
10
|
+
}
|