@ai-devkit/agent-manager 0.35.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/claude.test.js +485 -0
- package/dist/__tests__/capacity/claude.test.js.map +1 -0
- package/dist/__tests__/capacity/openai.test.js +670 -0
- package/dist/__tests__/capacity/openai.test.js.map +1 -0
- package/dist/__tests__/capacity/wham.test.js +144 -0
- package/dist/__tests__/capacity/wham.test.js.map +1 -0
- 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__/harnesses/antigravity/AntigravityCliAdapter.test.js +462 -0
- 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__/harnesses/kiro/KiroAdapter.test.js +662 -0
- 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 +72 -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/claude.d.ts +17 -0
- package/dist/capacity/claude.d.ts.map +1 -0
- package/dist/capacity/claude.js +271 -0
- package/dist/capacity/claude.js.map +1 -0
- package/dist/capacity/codex.d.ts +1 -2
- package/dist/capacity/codex.d.ts.map +1 -1
- package/dist/capacity/codex.js +5 -47
- package/dist/capacity/codex.js.map +1 -1
- package/dist/capacity/index.d.ts +11 -0
- package/dist/capacity/index.d.ts.map +1 -1
- package/dist/capacity/index.js +17 -0
- package/dist/capacity/index.js.map +1 -1
- package/dist/capacity/openai.d.ts +47 -0
- package/dist/capacity/openai.d.ts.map +1 -0
- package/dist/capacity/openai.js +307 -0
- package/dist/capacity/openai.js.map +1 -0
- package/dist/capacity/wham.d.ts +16 -0
- package/dist/capacity/wham.d.ts.map +1 -0
- package/dist/capacity/wham.js +66 -0
- package/dist/capacity/wham.js.map +1 -0
- 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 +28 -25
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +19 -16
- package/dist/index.js.map +1 -1
- package/dist/readiness/AgentReadiness.d.ts +1 -1
- package/dist/readiness/AgentReadiness.d.ts.map +1 -1
- package/dist/readiness/AgentReadiness.js.map +1 -1
- package/dist/runtime/ManagedAgentRuntime.js +3 -1
- package/dist/runtime/ManagedAgentRuntime.js.map +1 -1
- package/dist/runtime/herdr/HerdrAgentDiscovery.js +10 -0
- package/dist/runtime/herdr/HerdrAgentDiscovery.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 +61 -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/claude.test.ts +467 -0
- package/src/__tests__/capacity/fixtures/claude-credentials.json +7 -0
- package/src/__tests__/capacity/fixtures/claude-usage-malformed.json +1 -0
- package/src/__tests__/capacity/fixtures/claude-usage-partial.json +15 -0
- package/src/__tests__/capacity/fixtures/claude-usage.json +63 -0
- package/src/__tests__/capacity/fixtures/openai-auth.json +6 -0
- package/src/__tests__/capacity/fixtures/openai-codex-auth.json +9 -0
- package/src/__tests__/capacity/fixtures/openai-usage-completions.json +67 -0
- package/src/__tests__/capacity/fixtures/openai-usage-responses.json +20 -0
- package/src/__tests__/capacity/fixtures/wham-usage.json +32 -0
- package/src/__tests__/capacity/openai.test.ts +560 -0
- package/src/__tests__/capacity/wham.test.ts +104 -0
- 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__/harnesses/antigravity/AntigravityCliAdapter.test.ts +396 -0
- 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__/harnesses/kiro/KiroAdapter.test.ts +552 -0
- 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 +83 -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 -12
- package/src/capacity/claude.ts +313 -0
- package/src/capacity/codex.ts +25 -134
- package/src/capacity/index.ts +33 -4
- package/src/capacity/openai.ts +355 -0
- package/src/capacity/wham.ts +84 -0
- 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 +34 -23
- package/src/readiness/AgentReadiness.ts +4 -1
- package/src/runtime/ManagedAgentRuntime.ts +2 -0
- package/src/runtime/herdr/HerdrAgentDiscovery.ts +5 -1
- package/src/utils/IncrementalJsonlSummary.ts +306 -0
- package/src/utils/agents.ts +62 -20
- 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/ClaudeCodeAdapter.test.js.map +0 -1
- package/dist/__tests__/adapters/CodexAdapter.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/index.d.ts +0 -10
- package/dist/adapters/index.d.ts.map +0 -1
- package/dist/adapters/index.js +0 -10
- 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/index.ts +0 -15
- 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
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { AgentStatus } from "../../adapters/AgentAdapter.js";
|
|
2
1
|
import { generateAgentName } from "../../utils/matching.js";
|
|
3
2
|
import { GeminiSessionParser } from "./GeminiSessionParser.js";
|
|
3
|
+
import { processOnlyAgent } from "../shared.js";
|
|
4
4
|
export class GeminiAgentMapper {
|
|
5
5
|
parser;
|
|
6
6
|
constructor(parser = new GeminiSessionParser()){
|
|
@@ -21,16 +21,9 @@ export class GeminiAgentMapper {
|
|
|
21
21
|
};
|
|
22
22
|
}
|
|
23
23
|
mapProcessOnlyAgent(processInfo) {
|
|
24
|
-
return {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
status: AgentStatus.RUNNING,
|
|
28
|
-
summary: "Gemini CLI process running",
|
|
29
|
-
pid: processInfo.pid,
|
|
30
|
-
projectPath: processInfo.cwd || "",
|
|
31
|
-
sessionId: `pid-${processInfo.pid}`,
|
|
32
|
-
lastActive: new Date()
|
|
33
|
-
};
|
|
24
|
+
return processOnlyAgent("gemini_cli", processInfo, {
|
|
25
|
+
summary: "Gemini CLI process running"
|
|
26
|
+
});
|
|
34
27
|
}
|
|
35
28
|
}
|
|
36
29
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/harnesses/gemini/GeminiAgentMapper.ts"],"sourcesContent":["import type { AgentInfo, ProcessInfo } from \"../../adapters/AgentAdapter.js\";\nimport { generateAgentName } from \"../../utils/matching.js\";\nimport { GeminiSessionParser, type GeminiSession } from \"./GeminiSessionParser.js\";\nimport { processOnlyAgent } from \"../shared.js\";\n\nexport class GeminiAgentMapper {\n constructor(private readonly parser: GeminiSessionParser = new GeminiSessionParser()) {}\n\n mapSessionToAgent(session: GeminiSession, processInfo: ProcessInfo, filePath: string): AgentInfo {\n const projectPath = session.projectPath || processInfo.cwd || \"\";\n return {\n name: generateAgentName(projectPath, processInfo.pid),\n type: \"gemini_cli\",\n status: this.parser.determineStatus(session),\n summary: session.summary || \"Gemini CLI session active\",\n pid: processInfo.pid,\n projectPath,\n sessionId: session.sessionId,\n lastActive: session.lastActive,\n sessionFilePath: filePath,\n };\n }\n\n mapProcessOnlyAgent(processInfo: ProcessInfo): AgentInfo {\n return processOnlyAgent(\"gemini_cli\", processInfo, { summary: \"Gemini CLI process running\" });\n }\n}\n"],"names":["generateAgentName","GeminiSessionParser","processOnlyAgent","GeminiAgentMapper","parser","mapSessionToAgent","session","processInfo","filePath","projectPath","cwd","name","pid","type","status","determineStatus","summary","sessionId","lastActive","sessionFilePath","mapProcessOnlyAgent"],"mappings":"AACA,SAASA,iBAAiB,QAAQ,0BAA0B;AAC5D,SAASC,mBAAmB,QAA4B,2BAA2B;AACnF,SAASC,gBAAgB,QAAQ,eAAe;AAEhD,OAAO,MAAMC;;IACX,YAAY,AAAiBC,SAA8B,IAAIH,qBAAqB,CAAE;aAAzDG,SAAAA;IAA0D;IAEvFC,kBAAkBC,OAAsB,EAAEC,WAAwB,EAAEC,QAAgB,EAAa;QAC/F,MAAMC,cAAcH,QAAQG,WAAW,IAAIF,YAAYG,GAAG,IAAI;QAC9D,OAAO;YACLC,MAAMX,kBAAkBS,aAAaF,YAAYK,GAAG;YACpDC,MAAM;YACNC,QAAQ,IAAI,CAACV,MAAM,CAACW,eAAe,CAACT;YACpCU,SAASV,QAAQU,OAAO,IAAI;YAC5BJ,KAAKL,YAAYK,GAAG;YACpBH;YACAQ,WAAWX,QAAQW,SAAS;YAC5BC,YAAYZ,QAAQY,UAAU;YAC9BC,iBAAiBX;QACnB;IACF;IAEAY,oBAAoBb,WAAwB,EAAa;QACvD,OAAOL,iBAAiB,cAAcK,aAAa;YAAES,SAAS;QAA6B;IAC7F;AACF"}
|
|
@@ -4,12 +4,13 @@
|
|
|
4
4
|
* Detects running Gemini CLI agents by:
|
|
5
5
|
* 1. Filtering Gemini Node processes from a shared asynchronous process snapshot
|
|
6
6
|
* 2. Using snapshot CWD and start-time enrichment
|
|
7
|
-
* 3. Discovering session files from ~/.gemini/tmp/<shortId>/chats/session-*.
|
|
7
|
+
* 3. Discovering session files from ~/.gemini/tmp/<shortId>/chats/session-*.jsonl
|
|
8
|
+
* (Gemini CLI 0.46+ append-only logs) or legacy session-*.json documents
|
|
8
9
|
* 4. Matching sessions to processes via shared matchProcessesToSessions()
|
|
9
10
|
* using sha256(cwd) === session.projectHash as the resolvedCwd source
|
|
10
11
|
* 5. Extracting summary from the most recent user message in the session JSON
|
|
11
12
|
*/
|
|
12
|
-
import type { AgentAdapter, AgentInfo, ProcessInfo, ConversationMessage, SessionSummary, ListSessionsOptions, AgentDetectionContext } from "../../adapters/AgentAdapter.js";
|
|
13
|
+
import type { AgentAdapter, AgentInfo, ProcessInfo, ConversationMessage, ConversationOptions, SessionSummary, ListSessionsOptions, AgentDetectionContext } from "../../adapters/AgentAdapter.js";
|
|
13
14
|
import { AgentRegistry } from "../../utils/AgentRegistry.js";
|
|
14
15
|
export interface GeminiCliAdapterOptions {
|
|
15
16
|
geminiTmpDir?: string;
|
|
@@ -36,9 +37,7 @@ export declare class GeminiCliAdapter implements AgentAdapter {
|
|
|
36
37
|
* executable or script via isGeminiExecutable().
|
|
37
38
|
*/
|
|
38
39
|
detectAgents(context?: AgentDetectionContext): Promise<AgentInfo[]>;
|
|
39
|
-
getConversation(sessionFilePath: string, options?:
|
|
40
|
-
verbose?: boolean;
|
|
41
|
-
}): ConversationMessage[];
|
|
40
|
+
getConversation(sessionFilePath: string, options?: ConversationOptions): ConversationMessage[];
|
|
42
41
|
listSessions(opts?: ListSessionsOptions): Promise<SessionSummary[]>;
|
|
43
42
|
findSessionsById(sessionId: string): Promise<SessionSummary[]>;
|
|
44
43
|
private getGeminiProcesses;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GeminiCliAdapter.d.ts","sourceRoot":"","sources":["../../../src/harnesses/gemini/GeminiCliAdapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EACV,YAAY,EACZ,SAAS,EACT,WAAW,EACX,mBAAmB,EACnB,mBAAmB,EACnB,cAAc,EACd,mBAAmB,EACnB,qBAAqB,EACtB,MAAM,gCAAgC,CAAC;AAOxC,OAAO,EAAE,aAAa,EAAsB,MAAM,8BAA8B,CAAC;AAMjF,MAAM,WAAW,uBAAuB;IACtC,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,qBAAa,gBAAiB,YAAW,YAAY;IACnD,QAAQ,CAAC,IAAI,EAAG,YAAY,CAAU;IACtC,QAAQ,CAAC,YAAY,oBAAqB;IAE1C,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAgB;IACzC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAsB;IAC7C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAoB;IAC3C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAuB;gBAG7C,QAAQ,GAAE,aAAuC,EACjD,OAAO,GAAE,uBAA4B;IAQvC,SAAS,CAAC,WAAW,EAAE,WAAW,GAAG,OAAO;IAI5C;;;;;;;;;;;OAWG;IACG,YAAY,CAAC,OAAO,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;IAoBzE,eAAe,CAAC,eAAe,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,mBAAmB,GAAG,mBAAmB,EAAE;IAIxF,YAAY,CAAC,IAAI,CAAC,EAAE,mBAAmB,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC;IAanE,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC;YAQtD,kBAAkB;IAIhC,OAAO,CAAC,mBAAmB;IAuC3B,OAAO,CAAC,oBAAoB;IAY5B,OAAO,CAAC,wBAAwB;IAahC,OAAO,CAAC,wBAAwB;IA4BhC,OAAO,CAAC,uBAAuB;IAQ/B,OAAO,CAAC,gBAAgB;IAmCxB,OAAO,CAAC,kBAAkB;CAa3B"}
|
|
@@ -4,16 +4,18 @@
|
|
|
4
4
|
* Detects running Gemini CLI agents by:
|
|
5
5
|
* 1. Filtering Gemini Node processes from a shared asynchronous process snapshot
|
|
6
6
|
* 2. Using snapshot CWD and start-time enrichment
|
|
7
|
-
* 3. Discovering session files from ~/.gemini/tmp/<shortId>/chats/session-*.
|
|
7
|
+
* 3. Discovering session files from ~/.gemini/tmp/<shortId>/chats/session-*.jsonl
|
|
8
|
+
* (Gemini CLI 0.46+ append-only logs) or legacy session-*.json documents
|
|
8
9
|
* 4. Matching sessions to processes via shared matchProcessesToSessions()
|
|
9
10
|
* using sha256(cwd) === session.projectHash as the resolvedCwd source
|
|
10
11
|
* 5. Extracting summary from the most recent user message in the session JSON
|
|
11
|
-
*/ import {
|
|
12
|
+
*/ import { executableBasename, findWrapperProcess, findWrapperProcessPids } from "../../utils/process.js";
|
|
12
13
|
import { matchProcessesToSessions } from "../../utils/matching.js";
|
|
13
14
|
import { AgentRegistry } from "../../utils/AgentRegistry.js";
|
|
14
15
|
import { GeminiAgentMapper } from "./GeminiAgentMapper.js";
|
|
15
16
|
import { GeminiSessionLocator } from "./GeminiSessionLocator.js";
|
|
16
17
|
import { GeminiSessionParser } from "./GeminiSessionParser.js";
|
|
18
|
+
import { findHarnessProcesses } from "../shared.js";
|
|
17
19
|
export class GeminiCliAdapter {
|
|
18
20
|
type = "gemini_cli";
|
|
19
21
|
processNames = [
|
|
@@ -84,9 +86,7 @@ export class GeminiCliAdapter {
|
|
|
84
86
|
return [];
|
|
85
87
|
}
|
|
86
88
|
async getGeminiProcesses(context) {
|
|
87
|
-
|
|
88
|
-
const relevant = filterByProcessNames(snapshot, this.processNames);
|
|
89
|
-
return relevant.filter((process)=>this.canHandle(process));
|
|
89
|
+
return (await findHarnessProcesses(this, context)).processes;
|
|
90
90
|
}
|
|
91
91
|
mapSessionDiscovery(discovery, candidateProcesses, allProcesses, registryEntriesByPid) {
|
|
92
92
|
const matches = matchProcessesToSessions(candidateProcesses, discovery.sessions);
|
|
@@ -94,8 +94,7 @@ export class GeminiCliAdapter {
|
|
|
94
94
|
const matchedProcesses = [];
|
|
95
95
|
const agents = [];
|
|
96
96
|
for (const match of matches){
|
|
97
|
-
const
|
|
98
|
-
const sessionData = this.parser.parseSession(cachedContent, match.session.filePath);
|
|
97
|
+
const sessionData = this.parser.parseSession(undefined, match.session.filePath);
|
|
99
98
|
if (!sessionData) {
|
|
100
99
|
matchedPids.delete(match.process.pid);
|
|
101
100
|
continue;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/harnesses/gemini/GeminiCliAdapter.ts"],"sourcesContent":["/**\n * Gemini CLI Adapter\n *\n * Detects running Gemini CLI agents by:\n * 1. Filtering Gemini Node processes from a shared asynchronous process snapshot\n * 2. Using snapshot CWD and start-time enrichment\n * 3. Discovering session files from ~/.gemini/tmp/<shortId>/chats/session-*.jsonl\n * (Gemini CLI 0.46+ append-only logs) or legacy session-*.json documents\n * 4. Matching sessions to processes via shared matchProcessesToSessions()\n * using sha256(cwd) === session.projectHash as the resolvedCwd source\n * 5. Extracting summary from the most recent user message in the session JSON\n */\n\nimport type {\n AgentAdapter,\n AgentInfo,\n ProcessInfo,\n ConversationMessage,\n ConversationOptions,\n SessionSummary,\n ListSessionsOptions,\n AgentDetectionContext,\n} from \"../../adapters/AgentAdapter.js\";\nimport {\n executableBasename,\n findWrapperProcess,\n findWrapperProcessPids,\n} from \"../../utils/process.js\";\nimport { matchProcessesToSessions } from \"../../utils/matching.js\";\nimport { AgentRegistry, type RegistryEntry } from \"../../utils/AgentRegistry.js\";\nimport { GeminiAgentMapper } from \"./GeminiAgentMapper.js\";\nimport { GeminiSessionLocator, type GeminiSessionDiscovery } from \"./GeminiSessionLocator.js\";\nimport { GeminiSessionParser } from \"./GeminiSessionParser.js\";\nimport { findHarnessProcesses } from \"../shared.js\";\n\nexport interface GeminiCliAdapterOptions {\n geminiTmpDir?: string;\n}\n\nexport class GeminiCliAdapter implements AgentAdapter {\n readonly type = \"gemini_cli\" as const;\n readonly processNames = [\"node\"] as const;\n\n private readonly registry: AgentRegistry;\n private readonly parser: GeminiSessionParser;\n private readonly mapper: GeminiAgentMapper;\n private readonly locator: GeminiSessionLocator;\n\n constructor(\n registry: AgentRegistry = AgentRegistry.default(),\n options: GeminiCliAdapterOptions = {},\n ) {\n this.registry = registry;\n this.parser = new GeminiSessionParser();\n this.mapper = new GeminiAgentMapper(this.parser);\n this.locator = new GeminiSessionLocator(options);\n }\n\n canHandle(processInfo: ProcessInfo): boolean {\n return this.isGeminiExecutable(processInfo.command);\n }\n\n /**\n * Detect running Gemini CLI agents.\n *\n * Gemini CLI ships as a Node script (`bundle/gemini.js` with shebang\n * `#!/usr/bin/env node`) — unlike Claude Code (native binary per\n * platform) or Codex CLI (Node wrapper that execs a native Rust\n * binary). The primary running process is therefore the Node runtime\n * itself, and `ps aux` lists it as `node /path/to/gemini ...` with\n * argv[0] = `node`. We scan the Node process pool via the shared\n * snapshot and keep only those whose command line references the gemini\n * executable or script via isGeminiExecutable().\n */\n async detectAgents(context?: AgentDetectionContext): Promise<AgentInfo[]> {\n const processes = await this.getGeminiProcesses(context);\n if (processes.length === 0) return [];\n\n const wrapperPids = findWrapperProcessPids(processes);\n const { cachedAgents, remaining } = this.tryRegistryCache(processes, wrapperPids);\n if (remaining.length === 0) return this.deduplicateSessionAgents(cachedAgents);\n\n const candidateProcesses = remaining.filter((proc) => !wrapperPids.has(proc.pid));\n const registryEntriesByPid = new Map(this.registry.list().map((entry) => [entry.pid, entry]));\n const discovery = this.locator.discoverSessions(candidateProcesses);\n\n const agents =\n discovery.sessions.length === 0\n ? this.mapProcessOnlyAgents(candidateProcesses, processes, registryEntriesByPid)\n : this.mapSessionDiscovery(discovery, candidateProcesses, processes, registryEntriesByPid);\n\n return this.deduplicateSessionAgents([...cachedAgents, ...agents]);\n }\n\n getConversation(sessionFilePath: string, options?: ConversationOptions): ConversationMessage[] {\n return this.parser.getConversation(sessionFilePath, options);\n }\n\n async listSessions(opts?: ListSessionsOptions): Promise<SessionSummary[]> {\n const summaries: SessionSummary[] = [];\n\n for (const filePath of this.locator.discoverHistoricalSessionFiles()) {\n const summary = this.parser.fileToSessionSummary(filePath);\n if (!summary) continue;\n if (opts?.cwd !== undefined && summary.cwd !== opts.cwd) continue;\n summaries.push(summary);\n }\n\n return summaries;\n }\n\n async findSessionsById(sessionId: string): Promise<SessionSummary[]> {\n for (const filePath of this.locator.discoverHistoricalSessionFiles()) {\n const summary = this.parser.fileToSessionSummary(filePath);\n if (summary?.sessionId === sessionId) return [summary];\n }\n return [];\n }\n\n private async getGeminiProcesses(context?: AgentDetectionContext): Promise<ProcessInfo[]> {\n return (await findHarnessProcesses(this, context)).processes;\n }\n\n private mapSessionDiscovery(\n discovery: GeminiSessionDiscovery,\n candidateProcesses: ProcessInfo[],\n allProcesses: ProcessInfo[],\n registryEntriesByPid: Map<number, RegistryEntry>,\n ): AgentInfo[] {\n const matches = matchProcessesToSessions(candidateProcesses, discovery.sessions);\n const matchedPids = new Set(matches.map((m) => m.process.pid));\n const matchedProcesses: ProcessInfo[] = [];\n const agents: AgentInfo[] = [];\n\n for (const match of matches) {\n const sessionData = this.parser.parseSession(undefined, match.session.filePath);\n if (!sessionData) {\n matchedPids.delete(match.process.pid);\n continue;\n }\n\n const agent = this.mapper.mapSessionToAgent(\n sessionData,\n match.process,\n match.session.filePath,\n );\n this.applyWrapperRegistryName(agent, match.process, allProcesses, registryEntriesByPid);\n agents.push(agent);\n matchedProcesses.push(match.process);\n }\n\n const matchedWrapperPids = findWrapperProcessPids(candidateProcesses, matchedProcesses);\n const unmatchedProcesses = candidateProcesses.filter(\n (process) => !matchedPids.has(process.pid) && !matchedWrapperPids.has(process.pid),\n );\n\n agents.push(\n ...this.mapProcessOnlyAgents(unmatchedProcesses, allProcesses, registryEntriesByPid),\n );\n return agents;\n }\n\n private mapProcessOnlyAgents(\n processes: ProcessInfo[],\n allProcesses: ProcessInfo[],\n registryEntriesByPid: Map<number, RegistryEntry>,\n ): AgentInfo[] {\n return processes.map((processInfo) => {\n const agent = this.mapper.mapProcessOnlyAgent(processInfo);\n this.applyWrapperRegistryName(agent, processInfo, allProcesses, registryEntriesByPid);\n return agent;\n });\n }\n\n private applyWrapperRegistryName(\n agent: AgentInfo,\n processInfo: ProcessInfo,\n processes: ProcessInfo[],\n registryEntriesByPid: Map<number, RegistryEntry>,\n ): void {\n const wrapper = findWrapperProcess(processes, processInfo);\n const wrapperEntry = wrapper ? registryEntriesByPid.get(wrapper.pid) : undefined;\n if (wrapperEntry?.type === this.type) {\n agent.name = wrapperEntry.name;\n }\n }\n\n private deduplicateSessionAgents(agents: AgentInfo[]): AgentInfo[] {\n const bySession = new Map<string, AgentInfo>();\n const result: AgentInfo[] = [];\n\n for (const agent of agents) {\n const sessionKey = this.sessionDeduplicationKey(agent);\n if (!sessionKey) {\n result.push(agent);\n continue;\n }\n\n const existing = bySession.get(sessionKey);\n if (!existing) {\n bySession.set(sessionKey, agent);\n result.push(agent);\n continue;\n }\n\n if (agent.pid > existing.pid) {\n bySession.set(sessionKey, agent);\n const index = result.indexOf(existing);\n if (index >= 0) result[index] = agent;\n }\n }\n\n return result;\n }\n\n private sessionDeduplicationKey(agent: AgentInfo): string | null {\n if (agent.sessionFilePath) return `file:${agent.sessionFilePath}`;\n if (agent.sessionId && !agent.sessionId.startsWith(\"pid-\")) {\n return `session:${agent.sessionId}`;\n }\n return null;\n }\n\n private tryRegistryCache(\n processes: ProcessInfo[],\n wrapperPids: Set<number>,\n ): {\n cachedAgents: AgentInfo[];\n remaining: ProcessInfo[];\n } {\n const cachedAgents: AgentInfo[] = [];\n const remaining: ProcessInfo[] = [];\n const byPid = new Map(this.registry.list().map((e) => [e.pid, e]));\n\n for (const proc of processes) {\n const entry = byPid.get(proc.pid);\n if (\n wrapperPids.has(proc.pid) ||\n !entry ||\n entry.type !== this.type ||\n !entry.sessionFilePath\n ) {\n remaining.push(proc);\n continue;\n }\n\n const sessionData = this.parser.parseSession(undefined, entry.sessionFilePath);\n if (!sessionData) {\n remaining.push(proc);\n continue;\n }\n\n cachedAgents.push(this.mapper.mapSessionToAgent(sessionData, proc, entry.sessionFilePath));\n }\n\n return { cachedAgents, remaining };\n }\n\n private isGeminiExecutable(command: string): boolean {\n // Accept any token in the command line whose basename matches a\n // known gemini entrypoint. This is intentionally broader than the\n // other adapters' argv[0]-only check because the Node-script\n // distribution puts the real gemini path in argv[1..], not argv[0].\n for (const token of command.trim().split(/\\s+/)) {\n const base = executableBasename(token);\n if (base === \"gemini\" || base === \"gemini.exe\" || base === \"gemini.js\") {\n return true;\n }\n }\n return false;\n }\n}\n"],"names":["executableBasename","findWrapperProcess","findWrapperProcessPids","matchProcessesToSessions","AgentRegistry","GeminiAgentMapper","GeminiSessionLocator","GeminiSessionParser","findHarnessProcesses","GeminiCliAdapter","type","processNames","registry","parser","mapper","locator","default","options","canHandle","processInfo","isGeminiExecutable","command","detectAgents","context","processes","getGeminiProcesses","length","wrapperPids","cachedAgents","remaining","tryRegistryCache","deduplicateSessionAgents","candidateProcesses","filter","proc","has","pid","registryEntriesByPid","Map","list","map","entry","discovery","discoverSessions","agents","sessions","mapProcessOnlyAgents","mapSessionDiscovery","getConversation","sessionFilePath","listSessions","opts","summaries","filePath","discoverHistoricalSessionFiles","summary","fileToSessionSummary","cwd","undefined","push","findSessionsById","sessionId","allProcesses","matches","matchedPids","Set","m","process","matchedProcesses","match","sessionData","parseSession","session","delete","agent","mapSessionToAgent","applyWrapperRegistryName","matchedWrapperPids","unmatchedProcesses","mapProcessOnlyAgent","wrapper","wrapperEntry","get","name","bySession","result","sessionKey","sessionDeduplicationKey","existing","set","index","indexOf","startsWith","byPid","e","token","trim","split","base"],"mappings":"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"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import type { ProcessInfo } from "../../adapters/AgentAdapter.js";
|
|
2
|
+
import type { SessionFile } from "../../utils/session.js";
|
|
3
|
+
export interface GeminiSessionDiscovery {
|
|
4
|
+
sessions: SessionFile[];
|
|
5
|
+
}
|
|
6
|
+
export interface GeminiSessionLocatorOptions {
|
|
7
|
+
geminiTmpDir?: string;
|
|
8
|
+
}
|
|
9
|
+
export declare class GeminiSessionLocator {
|
|
10
|
+
private readonly geminiTmpDir;
|
|
11
|
+
private metadataCache;
|
|
12
|
+
private markerCache;
|
|
13
|
+
constructor(options?: GeminiSessionLocatorOptions);
|
|
14
|
+
/**
|
|
15
|
+
* Discover session files for the given processes.
|
|
16
|
+
*
|
|
17
|
+
* Gemini CLI writes sessions to ~/.gemini/tmp/<shortId>/chats/session-*.jsonl
|
|
18
|
+
* (0.46+; older versions wrote session-*.json) where <shortId> is either sha256(projectRoot) (legacy) or a slug whose
|
|
19
|
+
* owner is recorded in <shortId>/.project_root. Each session's projectHash
|
|
20
|
+
* is matched against sha256 of every candidate project root of a process.
|
|
21
|
+
*
|
|
22
|
+
* To keep each refresh cheap:
|
|
23
|
+
* - project dirs whose name or marker can't belong to a candidate root are
|
|
24
|
+
* skipped without listing or opening their chats;
|
|
25
|
+
* - chat files last modified before the earliest candidate process start
|
|
26
|
+
* (minus the matching tolerance) are skipped after a stat;
|
|
27
|
+
* - sessionId/projectHash come from a bounded head read, cached by
|
|
28
|
+
* inode+size+mtime, so unchanged files are never re-read.
|
|
29
|
+
*/
|
|
30
|
+
discoverSessions(processes: ProcessInfo[]): GeminiSessionDiscovery;
|
|
31
|
+
discoverHistoricalSessionFiles(): string[];
|
|
32
|
+
private readCandidateSession;
|
|
33
|
+
private readSessionMetadata;
|
|
34
|
+
/**
|
|
35
|
+
* Read sessionId/projectHash from the first METADATA_HEAD_BYTES. Files that
|
|
36
|
+
* fit in the head are parsed as JSON exactly; larger files are scanned for
|
|
37
|
+
* the leading keys and only fully parsed when the head lacks them.
|
|
38
|
+
*/
|
|
39
|
+
private extractSessionMetadata;
|
|
40
|
+
/**
|
|
41
|
+
* A `.jsonl` log's metadata is its first line. Never fall back to reading
|
|
42
|
+
* the whole log: it only grows, and a log whose first record is not
|
|
43
|
+
* metadata cannot be attributed from its head anyway.
|
|
44
|
+
*/
|
|
45
|
+
private extractLogMetadata;
|
|
46
|
+
private readHead;
|
|
47
|
+
private matchStringField;
|
|
48
|
+
private pickMetadata;
|
|
49
|
+
/**
|
|
50
|
+
* Decide from the directory name or its `.project_root` marker whether a
|
|
51
|
+
* project temp dir can hold sessions for a candidate root. Dirs with no
|
|
52
|
+
* recognisable ownership are scanned conservatively.
|
|
53
|
+
*/
|
|
54
|
+
private mayBelongToCandidates;
|
|
55
|
+
private readProjectMarker;
|
|
56
|
+
private earliestMatchableMtime;
|
|
57
|
+
private buildCandidateProjects;
|
|
58
|
+
/** Match Gemini CLI's project registry normalization (lower-cased on Windows). */
|
|
59
|
+
private normalizeRoot;
|
|
60
|
+
private candidateProjectRoots;
|
|
61
|
+
private hashProjectRoot;
|
|
62
|
+
/**
|
|
63
|
+
* Session files in a chats dir, in both formats. Resuming a legacy session
|
|
64
|
+
* makes Gemini CLI continue it in `<name>.jsonl` next to the stale
|
|
65
|
+
* `<name>.json`, so a `.json` with a `.jsonl` sibling is skipped.
|
|
66
|
+
*/
|
|
67
|
+
private listSessionFileNames;
|
|
68
|
+
private toSessionLogName;
|
|
69
|
+
private isSessionFile;
|
|
70
|
+
private parseSessionMetadata;
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=GeminiSessionLocator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GeminiSessionLocator.d.ts","sourceRoot":"","sources":["../../../src/harnesses/gemini/GeminiSessionLocator.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gCAAgC,CAAC;AAElE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAM1D,MAAM,WAAW,sBAAsB;IACrC,QAAQ,EAAE,WAAW,EAAE,CAAC;CACzB;AAED,MAAM,WAAW,2BAA2B;IAC1C,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAyCD,qBAAa,oBAAoB;IAC/B,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;IACtC,OAAO,CAAC,aAAa,CAA4C;IACjE,OAAO,CAAC,WAAW,CAA0C;gBAEjD,OAAO,GAAE,2BAAgC;IAIrD;;;;;;;;;;;;;;;OAeG;IACH,gBAAgB,CAAC,SAAS,EAAE,WAAW,EAAE,GAAG,sBAAsB;IA4ClE,8BAA8B,IAAI,MAAM,EAAE;IAgB1C,OAAO,CAAC,oBAAoB;IA4B5B,OAAO,CAAC,mBAAmB;IAQ3B;;;;OAIG;IACH,OAAO,CAAC,sBAAsB;IAiB9B;;;;OAIG;IACH,OAAO,CAAC,kBAAkB;IAa1B,OAAO,CAAC,QAAQ;IA6BhB,OAAO,CAAC,gBAAgB;IAUxB,OAAO,CAAC,YAAY;IAKpB;;;;OAIG;IACH,OAAO,CAAC,qBAAqB;IAa7B,OAAO,CAAC,iBAAiB;IAkBzB,OAAO,CAAC,sBAAsB;IAc9B,OAAO,CAAC,sBAAsB;IAuB9B,kFAAkF;IAClF,OAAO,CAAC,aAAa;IAKrB,OAAO,CAAC,qBAAqB;IAa7B,OAAO,CAAC,eAAe;IAIvB;;;;OAIG;IACH,OAAO,CAAC,oBAAoB;IAU5B,OAAO,CAAC,gBAAgB;IAKxB,OAAO,CAAC,aAAa;IAOrB,OAAO,CAAC,oBAAoB;CAO7B"}
|
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
import * as crypto from "crypto";
|
|
2
|
+
import * as fs from "fs";
|
|
3
|
+
import * as path from "path";
|
|
4
|
+
import { MATCH_TOLERANCE_MS } from "../../utils/matchingConstants.js";
|
|
5
|
+
import { isDirectory, safeReadFile, safeReaddir, safeStat } from "../../utils/session.js";
|
|
6
|
+
import { fileSignature } from "./fileSignature.js";
|
|
7
|
+
import { isSessionLogPath } from "./GeminiSessionParser.js";
|
|
8
|
+
import { homeDir } from "../shared.js";
|
|
9
|
+
const SESSION_FILE_PREFIX = "session-";
|
|
10
|
+
/** Legacy single-document sessions. */ const SESSION_DOCUMENT_EXTENSION = ".json";
|
|
11
|
+
/** Gemini CLI 0.46+ append-only session logs; line 1 is the metadata record. */ const SESSION_LOG_EXTENSION = ".jsonl";
|
|
12
|
+
const CHATS_DIR_NAME = "chats";
|
|
13
|
+
/** Ownership marker Gemini CLI writes into slug-named project temp dirs. */ const PROJECT_ROOT_MARKER = ".project_root";
|
|
14
|
+
/** Legacy Gemini CLI temp dirs are named sha256(projectRoot). */ const LEGACY_HASH_DIR_PATTERN = /^[0-9a-f]{64}$/;
|
|
15
|
+
/** Slack for coarse filesystem timestamp granularity. */ const MTIME_SLACK_MS = 2 * 1000;
|
|
16
|
+
/**
|
|
17
|
+
* Both formats start with sessionId/projectHash (a legacy document's leading
|
|
18
|
+
* keys, a log's line-1 metadata record); a small head is enough.
|
|
19
|
+
*/ const METADATA_HEAD_BYTES = 8 * 1024;
|
|
20
|
+
export class GeminiSessionLocator {
|
|
21
|
+
geminiTmpDir;
|
|
22
|
+
metadataCache = new Map();
|
|
23
|
+
markerCache = new Map();
|
|
24
|
+
constructor(options = {}){
|
|
25
|
+
this.geminiTmpDir = options.geminiTmpDir ?? path.join(homeDir(), ".gemini", "tmp");
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Discover session files for the given processes.
|
|
29
|
+
*
|
|
30
|
+
* Gemini CLI writes sessions to ~/.gemini/tmp/<shortId>/chats/session-*.jsonl
|
|
31
|
+
* (0.46+; older versions wrote session-*.json) where <shortId> is either sha256(projectRoot) (legacy) or a slug whose
|
|
32
|
+
* owner is recorded in <shortId>/.project_root. Each session's projectHash
|
|
33
|
+
* is matched against sha256 of every candidate project root of a process.
|
|
34
|
+
*
|
|
35
|
+
* To keep each refresh cheap:
|
|
36
|
+
* - project dirs whose name or marker can't belong to a candidate root are
|
|
37
|
+
* skipped without listing or opening their chats;
|
|
38
|
+
* - chat files last modified before the earliest candidate process start
|
|
39
|
+
* (minus the matching tolerance) are skipped after a stat;
|
|
40
|
+
* - sessionId/projectHash come from a bounded head read, cached by
|
|
41
|
+
* inode+size+mtime, so unchanged files are never re-read.
|
|
42
|
+
*/ discoverSessions(processes) {
|
|
43
|
+
const empty = {
|
|
44
|
+
sessions: []
|
|
45
|
+
};
|
|
46
|
+
if (!fs.existsSync(this.geminiTmpDir)) return empty;
|
|
47
|
+
const candidates = this.buildCandidateProjects(processes);
|
|
48
|
+
if (candidates.cwdByHash.size === 0) return empty;
|
|
49
|
+
let shortIdEntries;
|
|
50
|
+
try {
|
|
51
|
+
shortIdEntries = fs.readdirSync(this.geminiTmpDir);
|
|
52
|
+
} catch {
|
|
53
|
+
return empty;
|
|
54
|
+
}
|
|
55
|
+
const minMtimeMs = this.earliestMatchableMtime(processes);
|
|
56
|
+
const nextMetadataCache = new Map();
|
|
57
|
+
const nextMarkerCache = new Map();
|
|
58
|
+
const sessions = [];
|
|
59
|
+
for (const shortId of shortIdEntries){
|
|
60
|
+
const projectDir = path.join(this.geminiTmpDir, shortId);
|
|
61
|
+
if (!this.mayBelongToCandidates(projectDir, shortId, candidates, nextMarkerCache)) continue;
|
|
62
|
+
const chatsDir = path.join(projectDir, CHATS_DIR_NAME);
|
|
63
|
+
if (!isDirectory(chatsDir)) continue;
|
|
64
|
+
for (const fileName of this.listSessionFileNames(chatsDir)){
|
|
65
|
+
const session = this.readCandidateSession(chatsDir, fileName, candidates.cwdByHash, minMtimeMs, nextMetadataCache);
|
|
66
|
+
if (session) sessions.push(session);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
// Keep metadata only for files still in scope so the caches stay bounded.
|
|
70
|
+
this.metadataCache = nextMetadataCache;
|
|
71
|
+
this.markerCache = nextMarkerCache;
|
|
72
|
+
return {
|
|
73
|
+
sessions
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
discoverHistoricalSessionFiles() {
|
|
77
|
+
if (!isDirectory(this.geminiTmpDir)) return [];
|
|
78
|
+
const files = [];
|
|
79
|
+
for (const shortId of safeReaddir(this.geminiTmpDir)){
|
|
80
|
+
const chatsDir = path.join(this.geminiTmpDir, shortId, CHATS_DIR_NAME);
|
|
81
|
+
if (!isDirectory(chatsDir)) continue;
|
|
82
|
+
for (const fileName of this.listSessionFileNames(chatsDir)){
|
|
83
|
+
files.push(path.join(chatsDir, fileName));
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return files;
|
|
87
|
+
}
|
|
88
|
+
readCandidateSession(chatsDir, fileName, cwdByHash, minMtimeMs, nextMetadataCache) {
|
|
89
|
+
const filePath = path.join(chatsDir, fileName);
|
|
90
|
+
const stat = safeStat(filePath);
|
|
91
|
+
if (!stat || stat.mtimeMs < minMtimeMs) return null;
|
|
92
|
+
const metadata = this.readSessionMetadata(filePath, stat);
|
|
93
|
+
nextMetadataCache.set(filePath, metadata);
|
|
94
|
+
if (!metadata.projectHash) return null;
|
|
95
|
+
const resolvedCwd = cwdByHash.get(metadata.projectHash);
|
|
96
|
+
if (!resolvedCwd) return null;
|
|
97
|
+
return {
|
|
98
|
+
sessionId: metadata.sessionId || fileName.replace(/\.jsonl?$/, ""),
|
|
99
|
+
filePath,
|
|
100
|
+
projectDir: chatsDir,
|
|
101
|
+
birthtimeMs: stat.birthtimeMs,
|
|
102
|
+
resolvedCwd
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
readSessionMetadata(filePath, stat) {
|
|
106
|
+
const signature = fileSignature(stat);
|
|
107
|
+
const cached = this.metadataCache.get(filePath);
|
|
108
|
+
if (cached?.signature === signature) return cached;
|
|
109
|
+
return {
|
|
110
|
+
signature,
|
|
111
|
+
...this.extractSessionMetadata(filePath)
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Read sessionId/projectHash from the first METADATA_HEAD_BYTES. Files that
|
|
116
|
+
* fit in the head are parsed as JSON exactly; larger files are scanned for
|
|
117
|
+
* the leading keys and only fully parsed when the head lacks them.
|
|
118
|
+
*/ extractSessionMetadata(filePath) {
|
|
119
|
+
const head = this.readHead(filePath);
|
|
120
|
+
if (head === null) return {};
|
|
121
|
+
if (isSessionLogPath(filePath)) return this.extractLogMetadata(head);
|
|
122
|
+
if (head.complete) return this.pickMetadata(this.parseSessionMetadata(head.text));
|
|
123
|
+
const sessionId = this.matchStringField(head.text, "sessionId");
|
|
124
|
+
const projectHash = this.matchStringField(head.text, "projectHash");
|
|
125
|
+
if (sessionId !== undefined && projectHash !== undefined) {
|
|
126
|
+
return {
|
|
127
|
+
sessionId,
|
|
128
|
+
projectHash
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
const content = safeReadFile(filePath);
|
|
132
|
+
if (content === undefined) return {};
|
|
133
|
+
return this.pickMetadata(this.parseSessionMetadata(content));
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* A `.jsonl` log's metadata is its first line. Never fall back to reading
|
|
137
|
+
* the whole log: it only grows, and a log whose first record is not
|
|
138
|
+
* metadata cannot be attributed from its head anyway.
|
|
139
|
+
*/ extractLogMetadata(head) {
|
|
140
|
+
const newline = head.text.indexOf("\n");
|
|
141
|
+
if (newline !== -1 || head.complete) {
|
|
142
|
+
const firstLine = newline === -1 ? head.text : head.text.slice(0, newline);
|
|
143
|
+
return this.pickMetadata(this.parseSessionMetadata(firstLine));
|
|
144
|
+
}
|
|
145
|
+
// First line longer than the head: pick the leading keys from its prefix.
|
|
146
|
+
return {
|
|
147
|
+
sessionId: this.matchStringField(head.text, "sessionId"),
|
|
148
|
+
projectHash: this.matchStringField(head.text, "projectHash")
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
readHead(filePath) {
|
|
152
|
+
let fd;
|
|
153
|
+
try {
|
|
154
|
+
fd = fs.openSync(filePath, "r");
|
|
155
|
+
// One extra byte tells "exactly METADATA_HEAD_BYTES long" from "longer".
|
|
156
|
+
const buffer = Buffer.alloc(METADATA_HEAD_BYTES + 1);
|
|
157
|
+
let length = 0;
|
|
158
|
+
while(length < buffer.length){
|
|
159
|
+
const bytesRead = fs.readSync(fd, buffer, length, buffer.length - length, length);
|
|
160
|
+
if (bytesRead === 0) break;
|
|
161
|
+
length += bytesRead;
|
|
162
|
+
}
|
|
163
|
+
return {
|
|
164
|
+
text: buffer.toString("utf-8", 0, Math.min(length, METADATA_HEAD_BYTES)),
|
|
165
|
+
complete: length <= METADATA_HEAD_BYTES
|
|
166
|
+
};
|
|
167
|
+
} catch {
|
|
168
|
+
return null;
|
|
169
|
+
} finally{
|
|
170
|
+
if (fd !== undefined) {
|
|
171
|
+
try {
|
|
172
|
+
fs.closeSync(fd);
|
|
173
|
+
} catch {
|
|
174
|
+
// Nothing useful to do if closing a read-only descriptor fails.
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
matchStringField(text, key) {
|
|
180
|
+
const match = new RegExp(`"${key}"\\s*:\\s*"((?:[^"\\\\]|\\\\.)*)"`).exec(text);
|
|
181
|
+
if (!match) return undefined;
|
|
182
|
+
try {
|
|
183
|
+
return JSON.parse(`"${match[1]}"`);
|
|
184
|
+
} catch {
|
|
185
|
+
return undefined;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
pickMetadata(parsed) {
|
|
189
|
+
if (!parsed || typeof parsed !== "object") return {};
|
|
190
|
+
return {
|
|
191
|
+
sessionId: parsed.sessionId,
|
|
192
|
+
projectHash: parsed.projectHash
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Decide from the directory name or its `.project_root` marker whether a
|
|
197
|
+
* project temp dir can hold sessions for a candidate root. Dirs with no
|
|
198
|
+
* recognisable ownership are scanned conservatively.
|
|
199
|
+
*/ mayBelongToCandidates(projectDir, shortId, candidates, nextMarkerCache) {
|
|
200
|
+
if (LEGACY_HASH_DIR_PATTERN.test(shortId)) return candidates.cwdByHash.has(shortId);
|
|
201
|
+
const projectRoot = this.readProjectMarker(projectDir, nextMarkerCache);
|
|
202
|
+
if (projectRoot === undefined) return true;
|
|
203
|
+
return candidates.roots.has(this.normalizeRoot(projectRoot));
|
|
204
|
+
}
|
|
205
|
+
readProjectMarker(projectDir, nextMarkerCache) {
|
|
206
|
+
const markerPath = path.join(projectDir, PROJECT_ROOT_MARKER);
|
|
207
|
+
const stat = safeStat(markerPath);
|
|
208
|
+
if (!stat?.isFile()) return undefined;
|
|
209
|
+
const signature = fileSignature(stat);
|
|
210
|
+
const cached = this.markerCache.get(markerPath);
|
|
211
|
+
const projectRoot = cached?.signature === signature ? cached.projectRoot : safeReadFile(markerPath)?.trim();
|
|
212
|
+
if (!projectRoot) return undefined;
|
|
213
|
+
nextMarkerCache.set(markerPath, {
|
|
214
|
+
signature,
|
|
215
|
+
projectRoot
|
|
216
|
+
});
|
|
217
|
+
return projectRoot;
|
|
218
|
+
}
|
|
219
|
+
earliestMatchableMtime(processes) {
|
|
220
|
+
let earliestStartMs = Number.POSITIVE_INFINITY;
|
|
221
|
+
for (const proc of processes){
|
|
222
|
+
if (!proc.cwd || !proc.startTime) continue;
|
|
223
|
+
const startMs = proc.startTime.getTime();
|
|
224
|
+
if (Number.isFinite(startMs)) earliestStartMs = Math.min(earliestStartMs, startMs);
|
|
225
|
+
}
|
|
226
|
+
// No start times: nothing can be windowed safely, so scan every file.
|
|
227
|
+
if (!Number.isFinite(earliestStartMs)) return Number.NEGATIVE_INFINITY;
|
|
228
|
+
// A file last modified before (earliest start - matcher tolerance) was also
|
|
229
|
+
// born before it, so it can never be matched to any candidate process.
|
|
230
|
+
return earliestStartMs - MATCH_TOLERANCE_MS - MTIME_SLACK_MS;
|
|
231
|
+
}
|
|
232
|
+
buildCandidateProjects(processes) {
|
|
233
|
+
const cwdByHash = new Map();
|
|
234
|
+
const roots = new Set();
|
|
235
|
+
for (const proc of processes){
|
|
236
|
+
if (!proc.cwd) continue;
|
|
237
|
+
// Gemini CLI resolves its project root by walking up from the
|
|
238
|
+
// startup directory looking for a `.git` boundary marker. A
|
|
239
|
+
// session's projectHash therefore tracks that ancestor rather
|
|
240
|
+
// than the process' actual CWD. Enumerate every ancestor as a
|
|
241
|
+
// candidate so subdirectory invocations still line up with the
|
|
242
|
+
// session the Gemini process wrote.
|
|
243
|
+
for (const candidate of this.candidateProjectRoots(proc.cwd)){
|
|
244
|
+
roots.add(this.normalizeRoot(candidate));
|
|
245
|
+
const hash = this.hashProjectRoot(candidate);
|
|
246
|
+
if (!cwdByHash.has(hash)) {
|
|
247
|
+
cwdByHash.set(hash, proc.cwd);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
return {
|
|
252
|
+
cwdByHash,
|
|
253
|
+
roots
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
/** Match Gemini CLI's project registry normalization (lower-cased on Windows). */ normalizeRoot(projectRoot) {
|
|
257
|
+
const resolved = path.resolve(projectRoot);
|
|
258
|
+
return process.platform === "win32" ? resolved.toLowerCase() : resolved;
|
|
259
|
+
}
|
|
260
|
+
candidateProjectRoots(cwd) {
|
|
261
|
+
const roots = [];
|
|
262
|
+
let current = path.resolve(cwd);
|
|
263
|
+
let parent = path.dirname(current);
|
|
264
|
+
while(parent !== current){
|
|
265
|
+
roots.push(current);
|
|
266
|
+
current = parent;
|
|
267
|
+
parent = path.dirname(current);
|
|
268
|
+
}
|
|
269
|
+
roots.push(current);
|
|
270
|
+
return roots;
|
|
271
|
+
}
|
|
272
|
+
hashProjectRoot(projectRoot) {
|
|
273
|
+
return crypto.createHash("sha256").update(projectRoot).digest("hex");
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Session files in a chats dir, in both formats. Resuming a legacy session
|
|
277
|
+
* makes Gemini CLI continue it in `<name>.jsonl` next to the stale
|
|
278
|
+
* `<name>.json`, so a `.json` with a `.jsonl` sibling is skipped.
|
|
279
|
+
*/ listSessionFileNames(chatsDir) {
|
|
280
|
+
const sessionFiles = safeReaddir(chatsDir).filter((fileName)=>this.isSessionFile(fileName));
|
|
281
|
+
const names = new Set(sessionFiles);
|
|
282
|
+
return sessionFiles.filter((fileName)=>!fileName.endsWith(SESSION_DOCUMENT_EXTENSION) || !names.has(this.toSessionLogName(fileName)));
|
|
283
|
+
}
|
|
284
|
+
toSessionLogName(documentFileName) {
|
|
285
|
+
const baseName = documentFileName.slice(0, -SESSION_DOCUMENT_EXTENSION.length);
|
|
286
|
+
return `${baseName}${SESSION_LOG_EXTENSION}`;
|
|
287
|
+
}
|
|
288
|
+
isSessionFile(fileName) {
|
|
289
|
+
return fileName.startsWith(SESSION_FILE_PREFIX) && (fileName.endsWith(SESSION_DOCUMENT_EXTENSION) || fileName.endsWith(SESSION_LOG_EXTENSION));
|
|
290
|
+
}
|
|
291
|
+
parseSessionMetadata(content) {
|
|
292
|
+
try {
|
|
293
|
+
return JSON.parse(content);
|
|
294
|
+
} catch {
|
|
295
|
+
return null;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
//# sourceMappingURL=GeminiSessionLocator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/harnesses/gemini/GeminiSessionLocator.ts"],"sourcesContent":["import * as crypto from \"crypto\";\nimport * as fs from \"fs\";\nimport * as path from \"path\";\nimport type { ProcessInfo } from \"../../adapters/AgentAdapter.js\";\nimport { MATCH_TOLERANCE_MS } from \"../../utils/matchingConstants.js\";\nimport type { SessionFile } from \"../../utils/session.js\";\nimport { isDirectory, safeReadFile, safeReaddir, safeStat } from \"../../utils/session.js\";\nimport { fileSignature } from \"./fileSignature.js\";\nimport { isSessionLogPath } from \"./GeminiSessionParser.js\";\nimport { homeDir } from \"../shared.js\";\n\nexport interface GeminiSessionDiscovery {\n sessions: SessionFile[];\n}\n\nexport interface GeminiSessionLocatorOptions {\n geminiTmpDir?: string;\n}\n\ninterface GeminiSessionMetadata {\n sessionId?: string;\n projectHash?: string;\n}\n\ninterface CachedSessionMetadata extends GeminiSessionMetadata {\n signature: string;\n}\n\ninterface CachedProjectMarker {\n signature: string;\n projectRoot: string;\n}\n\ninterface CandidateProjects {\n /** sha256(projectRoot) -> process CWD that may own sessions for that root. */\n cwdByHash: Map<string, string>;\n /** Normalized candidate project roots, compared against `.project_root` markers. */\n roots: Set<string>;\n}\n\nconst SESSION_FILE_PREFIX = \"session-\";\n/** Legacy single-document sessions. */\nconst SESSION_DOCUMENT_EXTENSION = \".json\";\n/** Gemini CLI 0.46+ append-only session logs; line 1 is the metadata record. */\nconst SESSION_LOG_EXTENSION = \".jsonl\";\nconst CHATS_DIR_NAME = \"chats\";\n/** Ownership marker Gemini CLI writes into slug-named project temp dirs. */\nconst PROJECT_ROOT_MARKER = \".project_root\";\n/** Legacy Gemini CLI temp dirs are named sha256(projectRoot). */\nconst LEGACY_HASH_DIR_PATTERN = /^[0-9a-f]{64}$/;\n/** Slack for coarse filesystem timestamp granularity. */\nconst MTIME_SLACK_MS = 2 * 1000;\n/**\n * Both formats start with sessionId/projectHash (a legacy document's leading\n * keys, a log's line-1 metadata record); a small head is enough.\n */\nconst METADATA_HEAD_BYTES = 8 * 1024;\n\nexport class GeminiSessionLocator {\n private readonly geminiTmpDir: string;\n private metadataCache = new Map<string, CachedSessionMetadata>();\n private markerCache = new Map<string, CachedProjectMarker>();\n\n constructor(options: GeminiSessionLocatorOptions = {}) {\n this.geminiTmpDir = options.geminiTmpDir ?? path.join(homeDir(), \".gemini\", \"tmp\");\n }\n\n /**\n * Discover session files for the given processes.\n *\n * Gemini CLI writes sessions to ~/.gemini/tmp/<shortId>/chats/session-*.jsonl\n * (0.46+; older versions wrote session-*.json) where <shortId> is either sha256(projectRoot) (legacy) or a slug whose\n * owner is recorded in <shortId>/.project_root. Each session's projectHash\n * is matched against sha256 of every candidate project root of a process.\n *\n * To keep each refresh cheap:\n * - project dirs whose name or marker can't belong to a candidate root are\n * skipped without listing or opening their chats;\n * - chat files last modified before the earliest candidate process start\n * (minus the matching tolerance) are skipped after a stat;\n * - sessionId/projectHash come from a bounded head read, cached by\n * inode+size+mtime, so unchanged files are never re-read.\n */\n discoverSessions(processes: ProcessInfo[]): GeminiSessionDiscovery {\n const empty: GeminiSessionDiscovery = { sessions: [] };\n if (!fs.existsSync(this.geminiTmpDir)) return empty;\n\n const candidates = this.buildCandidateProjects(processes);\n if (candidates.cwdByHash.size === 0) return empty;\n\n let shortIdEntries: string[];\n try {\n shortIdEntries = fs.readdirSync(this.geminiTmpDir);\n } catch {\n return empty;\n }\n\n const minMtimeMs = this.earliestMatchableMtime(processes);\n const nextMetadataCache = new Map<string, CachedSessionMetadata>();\n const nextMarkerCache = new Map<string, CachedProjectMarker>();\n const sessions: SessionFile[] = [];\n\n for (const shortId of shortIdEntries) {\n const projectDir = path.join(this.geminiTmpDir, shortId);\n if (!this.mayBelongToCandidates(projectDir, shortId, candidates, nextMarkerCache)) continue;\n\n const chatsDir = path.join(projectDir, CHATS_DIR_NAME);\n if (!isDirectory(chatsDir)) continue;\n\n for (const fileName of this.listSessionFileNames(chatsDir)) {\n const session = this.readCandidateSession(\n chatsDir,\n fileName,\n candidates.cwdByHash,\n minMtimeMs,\n nextMetadataCache,\n );\n if (session) sessions.push(session);\n }\n }\n\n // Keep metadata only for files still in scope so the caches stay bounded.\n this.metadataCache = nextMetadataCache;\n this.markerCache = nextMarkerCache;\n return { sessions };\n }\n\n discoverHistoricalSessionFiles(): string[] {\n if (!isDirectory(this.geminiTmpDir)) return [];\n\n const files: string[] = [];\n for (const shortId of safeReaddir(this.geminiTmpDir)) {\n const chatsDir = path.join(this.geminiTmpDir, shortId, CHATS_DIR_NAME);\n if (!isDirectory(chatsDir)) continue;\n\n for (const fileName of this.listSessionFileNames(chatsDir)) {\n files.push(path.join(chatsDir, fileName));\n }\n }\n\n return files;\n }\n\n private readCandidateSession(\n chatsDir: string,\n fileName: string,\n cwdByHash: Map<string, string>,\n minMtimeMs: number,\n nextMetadataCache: Map<string, CachedSessionMetadata>,\n ): SessionFile | null {\n const filePath = path.join(chatsDir, fileName);\n\n const stat = safeStat(filePath);\n if (!stat || stat.mtimeMs < minMtimeMs) return null;\n\n const metadata = this.readSessionMetadata(filePath, stat);\n nextMetadataCache.set(filePath, metadata);\n if (!metadata.projectHash) return null;\n\n const resolvedCwd = cwdByHash.get(metadata.projectHash);\n if (!resolvedCwd) return null;\n\n return {\n sessionId: metadata.sessionId || fileName.replace(/\\.jsonl?$/, \"\"),\n filePath,\n projectDir: chatsDir,\n birthtimeMs: stat.birthtimeMs,\n resolvedCwd,\n };\n }\n\n private readSessionMetadata(filePath: string, stat: fs.Stats): CachedSessionMetadata {\n const signature = fileSignature(stat);\n const cached = this.metadataCache.get(filePath);\n if (cached?.signature === signature) return cached;\n\n return { signature, ...this.extractSessionMetadata(filePath) };\n }\n\n /**\n * Read sessionId/projectHash from the first METADATA_HEAD_BYTES. Files that\n * fit in the head are parsed as JSON exactly; larger files are scanned for\n * the leading keys and only fully parsed when the head lacks them.\n */\n private extractSessionMetadata(filePath: string): GeminiSessionMetadata {\n const head = this.readHead(filePath);\n if (head === null) return {};\n if (isSessionLogPath(filePath)) return this.extractLogMetadata(head);\n if (head.complete) return this.pickMetadata(this.parseSessionMetadata(head.text));\n\n const sessionId = this.matchStringField(head.text, \"sessionId\");\n const projectHash = this.matchStringField(head.text, \"projectHash\");\n if (sessionId !== undefined && projectHash !== undefined) {\n return { sessionId, projectHash };\n }\n\n const content = safeReadFile(filePath);\n if (content === undefined) return {};\n return this.pickMetadata(this.parseSessionMetadata(content));\n }\n\n /**\n * A `.jsonl` log's metadata is its first line. Never fall back to reading\n * the whole log: it only grows, and a log whose first record is not\n * metadata cannot be attributed from its head anyway.\n */\n private extractLogMetadata(head: { text: string; complete: boolean }): GeminiSessionMetadata {\n const newline = head.text.indexOf(\"\\n\");\n if (newline !== -1 || head.complete) {\n const firstLine = newline === -1 ? head.text : head.text.slice(0, newline);\n return this.pickMetadata(this.parseSessionMetadata(firstLine));\n }\n // First line longer than the head: pick the leading keys from its prefix.\n return {\n sessionId: this.matchStringField(head.text, \"sessionId\"),\n projectHash: this.matchStringField(head.text, \"projectHash\"),\n };\n }\n\n private readHead(filePath: string): { text: string; complete: boolean } | null {\n let fd: number | undefined;\n try {\n fd = fs.openSync(filePath, \"r\");\n // One extra byte tells \"exactly METADATA_HEAD_BYTES long\" from \"longer\".\n const buffer = Buffer.alloc(METADATA_HEAD_BYTES + 1);\n let length = 0;\n while (length < buffer.length) {\n const bytesRead = fs.readSync(fd, buffer, length, buffer.length - length, length);\n if (bytesRead === 0) break;\n length += bytesRead;\n }\n return {\n text: buffer.toString(\"utf-8\", 0, Math.min(length, METADATA_HEAD_BYTES)),\n complete: length <= METADATA_HEAD_BYTES,\n };\n } catch {\n return null;\n } finally {\n if (fd !== undefined) {\n try {\n fs.closeSync(fd);\n } catch {\n // Nothing useful to do if closing a read-only descriptor fails.\n }\n }\n }\n }\n\n private matchStringField(text: string, key: string): string | undefined {\n const match = new RegExp(`\"${key}\"\\\\s*:\\\\s*\"((?:[^\"\\\\\\\\]|\\\\\\\\.)*)\"`).exec(text);\n if (!match) return undefined;\n try {\n return JSON.parse(`\"${match[1]}\"`) as string;\n } catch {\n return undefined;\n }\n }\n\n private pickMetadata(parsed: GeminiSessionMetadata | null): GeminiSessionMetadata {\n if (!parsed || typeof parsed !== \"object\") return {};\n return { sessionId: parsed.sessionId, projectHash: parsed.projectHash };\n }\n\n /**\n * Decide from the directory name or its `.project_root` marker whether a\n * project temp dir can hold sessions for a candidate root. Dirs with no\n * recognisable ownership are scanned conservatively.\n */\n private mayBelongToCandidates(\n projectDir: string,\n shortId: string,\n candidates: CandidateProjects,\n nextMarkerCache: Map<string, CachedProjectMarker>,\n ): boolean {\n if (LEGACY_HASH_DIR_PATTERN.test(shortId)) return candidates.cwdByHash.has(shortId);\n\n const projectRoot = this.readProjectMarker(projectDir, nextMarkerCache);\n if (projectRoot === undefined) return true;\n return candidates.roots.has(this.normalizeRoot(projectRoot));\n }\n\n private readProjectMarker(\n projectDir: string,\n nextMarkerCache: Map<string, CachedProjectMarker>,\n ): string | undefined {\n const markerPath = path.join(projectDir, PROJECT_ROOT_MARKER);\n const stat = safeStat(markerPath);\n if (!stat?.isFile()) return undefined;\n\n const signature = fileSignature(stat);\n const cached = this.markerCache.get(markerPath);\n const projectRoot =\n cached?.signature === signature ? cached.projectRoot : safeReadFile(markerPath)?.trim();\n if (!projectRoot) return undefined;\n\n nextMarkerCache.set(markerPath, { signature, projectRoot });\n return projectRoot;\n }\n\n private earliestMatchableMtime(processes: ProcessInfo[]): number {\n let earliestStartMs = Number.POSITIVE_INFINITY;\n for (const proc of processes) {\n if (!proc.cwd || !proc.startTime) continue;\n const startMs = proc.startTime.getTime();\n if (Number.isFinite(startMs)) earliestStartMs = Math.min(earliestStartMs, startMs);\n }\n // No start times: nothing can be windowed safely, so scan every file.\n if (!Number.isFinite(earliestStartMs)) return Number.NEGATIVE_INFINITY;\n // A file last modified before (earliest start - matcher tolerance) was also\n // born before it, so it can never be matched to any candidate process.\n return earliestStartMs - MATCH_TOLERANCE_MS - MTIME_SLACK_MS;\n }\n\n private buildCandidateProjects(processes: ProcessInfo[]): CandidateProjects {\n const cwdByHash = new Map<string, string>();\n const roots = new Set<string>();\n for (const proc of processes) {\n if (!proc.cwd) continue;\n\n // Gemini CLI resolves its project root by walking up from the\n // startup directory looking for a `.git` boundary marker. A\n // session's projectHash therefore tracks that ancestor rather\n // than the process' actual CWD. Enumerate every ancestor as a\n // candidate so subdirectory invocations still line up with the\n // session the Gemini process wrote.\n for (const candidate of this.candidateProjectRoots(proc.cwd)) {\n roots.add(this.normalizeRoot(candidate));\n const hash = this.hashProjectRoot(candidate);\n if (!cwdByHash.has(hash)) {\n cwdByHash.set(hash, proc.cwd);\n }\n }\n }\n return { cwdByHash, roots };\n }\n\n /** Match Gemini CLI's project registry normalization (lower-cased on Windows). */\n private normalizeRoot(projectRoot: string): string {\n const resolved = path.resolve(projectRoot);\n return process.platform === \"win32\" ? resolved.toLowerCase() : resolved;\n }\n\n private candidateProjectRoots(cwd: string): string[] {\n const roots: string[] = [];\n let current = path.resolve(cwd);\n let parent = path.dirname(current);\n while (parent !== current) {\n roots.push(current);\n current = parent;\n parent = path.dirname(current);\n }\n roots.push(current);\n return roots;\n }\n\n private hashProjectRoot(projectRoot: string): string {\n return crypto.createHash(\"sha256\").update(projectRoot).digest(\"hex\");\n }\n\n /**\n * Session files in a chats dir, in both formats. Resuming a legacy session\n * makes Gemini CLI continue it in `<name>.jsonl` next to the stale\n * `<name>.json`, so a `.json` with a `.jsonl` sibling is skipped.\n */\n private listSessionFileNames(chatsDir: string): string[] {\n const sessionFiles = safeReaddir(chatsDir).filter((fileName) => this.isSessionFile(fileName));\n const names = new Set(sessionFiles);\n return sessionFiles.filter(\n (fileName) =>\n !fileName.endsWith(SESSION_DOCUMENT_EXTENSION) ||\n !names.has(this.toSessionLogName(fileName)),\n );\n }\n\n private toSessionLogName(documentFileName: string): string {\n const baseName = documentFileName.slice(0, -SESSION_DOCUMENT_EXTENSION.length);\n return `${baseName}${SESSION_LOG_EXTENSION}`;\n }\n\n private isSessionFile(fileName: string): boolean {\n return (\n fileName.startsWith(SESSION_FILE_PREFIX) &&\n (fileName.endsWith(SESSION_DOCUMENT_EXTENSION) || fileName.endsWith(SESSION_LOG_EXTENSION))\n );\n }\n\n private parseSessionMetadata(content: string): GeminiSessionMetadata | null {\n try {\n return JSON.parse(content) as GeminiSessionMetadata;\n } catch {\n return null;\n }\n }\n}\n"],"names":["crypto","fs","path","MATCH_TOLERANCE_MS","isDirectory","safeReadFile","safeReaddir","safeStat","fileSignature","isSessionLogPath","homeDir","SESSION_FILE_PREFIX","SESSION_DOCUMENT_EXTENSION","SESSION_LOG_EXTENSION","CHATS_DIR_NAME","PROJECT_ROOT_MARKER","LEGACY_HASH_DIR_PATTERN","MTIME_SLACK_MS","METADATA_HEAD_BYTES","GeminiSessionLocator","geminiTmpDir","metadataCache","Map","markerCache","options","join","discoverSessions","processes","empty","sessions","existsSync","candidates","buildCandidateProjects","cwdByHash","size","shortIdEntries","readdirSync","minMtimeMs","earliestMatchableMtime","nextMetadataCache","nextMarkerCache","shortId","projectDir","mayBelongToCandidates","chatsDir","fileName","listSessionFileNames","session","readCandidateSession","push","discoverHistoricalSessionFiles","files","filePath","stat","mtimeMs","metadata","readSessionMetadata","set","projectHash","resolvedCwd","get","sessionId","replace","birthtimeMs","signature","cached","extractSessionMetadata","head","readHead","extractLogMetadata","complete","pickMetadata","parseSessionMetadata","text","matchStringField","undefined","content","newline","indexOf","firstLine","slice","fd","openSync","buffer","Buffer","alloc","length","bytesRead","readSync","toString","Math","min","closeSync","key","match","RegExp","exec","JSON","parse","parsed","test","has","projectRoot","readProjectMarker","roots","normalizeRoot","markerPath","isFile","trim","earliestStartMs","Number","POSITIVE_INFINITY","proc","cwd","startTime","startMs","getTime","isFinite","NEGATIVE_INFINITY","Set","candidate","candidateProjectRoots","add","hash","hashProjectRoot","resolved","resolve","process","platform","toLowerCase","current","parent","dirname","createHash","update","digest","sessionFiles","filter","isSessionFile","names","endsWith","toSessionLogName","documentFileName","baseName","startsWith"],"mappings":"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"}
|