@ai-devkit/agent-manager 0.31.0 → 0.33.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 +3 -3
- package/dist/AgentManager.d.ts.map +1 -1
- package/dist/AgentManager.js +80 -79
- package/dist/AgentManager.js.map +1 -1
- package/dist/__tests__/AgentManager.test.js +413 -388
- package/dist/__tests__/AgentManager.test.js.map +1 -1
- package/dist/__tests__/adapters/ClaudeCodeAdapter.test.js +642 -642
- package/dist/__tests__/adapters/ClaudeCodeAdapter.test.js.map +1 -1
- package/dist/__tests__/adapters/CodexAdapter.test.js +322 -2321
- package/dist/__tests__/adapters/CodexAdapter.test.js.map +1 -1
- package/dist/__tests__/adapters/CopilotAdapter.test.js +254 -248
- package/dist/__tests__/adapters/CopilotAdapter.test.js.map +1 -1
- package/dist/__tests__/adapters/GeminiCliAdapter.test.js +564 -558
- package/dist/__tests__/adapters/GeminiCliAdapter.test.js.map +1 -1
- package/dist/__tests__/adapters/GrokCliAdapter.test.js +114 -114
- package/dist/__tests__/adapters/GrokCliAdapter.test.js.map +1 -1
- package/dist/__tests__/adapters/OpenCodeAdapter.test.js +169 -169
- package/dist/__tests__/adapters/OpenCodeAdapter.test.js.map +1 -1
- package/dist/__tests__/capacity/codex.test.js +93 -93
- package/dist/__tests__/capacity/codex.test.js.map +1 -1
- package/dist/__tests__/capacity/index.test.js +17 -17
- package/dist/__tests__/capacity/index.test.js.map +1 -1
- package/dist/__tests__/durable/CodexCliProbe.test.js +60 -60
- package/dist/__tests__/durable/CodexCliProbe.test.js.map +1 -1
- package/dist/__tests__/durable/CodexDurableAgentRepository.test.js +28 -28
- package/dist/__tests__/durable/CodexDurableAgentRepository.test.js.map +1 -1
- package/dist/__tests__/durable/CodexPrintAgent.integration.test.js +30 -30
- package/dist/__tests__/durable/CodexPrintAgent.integration.test.js.map +1 -1
- package/dist/__tests__/durable/CodexPrintAgentService.test.js +71 -71
- package/dist/__tests__/durable/CodexPrintAgentService.test.js.map +1 -1
- package/dist/__tests__/durable/CodexPrintRunner.test.js +125 -125
- package/dist/__tests__/durable/CodexPrintRunner.test.js.map +1 -1
- package/dist/__tests__/print/ClaudeCliProbe.test.js +20 -20
- package/dist/__tests__/print/ClaudeCliProbe.test.js.map +1 -1
- package/dist/__tests__/print/ClaudePrintAgent.integration.test.js +20 -20
- package/dist/__tests__/print/ClaudePrintAgent.integration.test.js.map +1 -1
- package/dist/__tests__/print/ClaudePrintAgentService.test.js +58 -58
- package/dist/__tests__/print/ClaudePrintAgentService.test.js.map +1 -1
- package/dist/__tests__/print/ClaudePrintRunner.test.js +55 -55
- package/dist/__tests__/print/ClaudePrintRunner.test.js.map +1 -1
- package/dist/__tests__/print/DurableAgent.test.js +9 -9
- package/dist/__tests__/print/DurableAgent.test.js.map +1 -1
- package/dist/__tests__/print/DurableAgentRepository.sqlite.test.js +40 -40
- package/dist/__tests__/print/DurableAgentRepository.sqlite.test.js.map +1 -1
- package/dist/__tests__/print/DurableAgentRepository.test.js +66 -66
- package/dist/__tests__/print/DurableAgentRepository.test.js.map +1 -1
- package/dist/__tests__/providers/claude/ClaudeAgentMapper.test.js +34 -34
- package/dist/__tests__/providers/claude/ClaudeAgentMapper.test.js.map +1 -1
- package/dist/__tests__/providers/claude/ClaudeSessionLocator.test.js +132 -132
- package/dist/__tests__/providers/claude/ClaudeSessionLocator.test.js.map +1 -1
- package/dist/__tests__/providers/codex/CodexSessionLocator.test.js +194 -0
- package/dist/__tests__/providers/codex/CodexSessionLocator.test.js.map +1 -0
- package/dist/__tests__/providers/codex/CodexSessionMapping.test.js +86 -0
- package/dist/__tests__/providers/codex/CodexSessionMapping.test.js.map +1 -0
- package/dist/__tests__/providers/codex/CodexSessionParser.test.js +254 -0
- package/dist/__tests__/providers/codex/CodexSessionParser.test.js.map +1 -0
- package/dist/__tests__/providers/pi/PiAdapter.test.js +337 -0
- package/dist/__tests__/providers/pi/PiAdapter.test.js.map +1 -0
- package/dist/__tests__/providers/pi/PiSessionParser.test.js +246 -0
- package/dist/__tests__/providers/pi/PiSessionParser.test.js.map +1 -0
- package/dist/__tests__/providers/pi/PiSessionTracker.test.js +108 -0
- package/dist/__tests__/providers/pi/PiSessionTracker.test.js.map +1 -0
- package/dist/__tests__/providers/pi/durable/PiCliProbe.test.js +33 -33
- package/dist/__tests__/providers/pi/durable/PiCliProbe.test.js.map +1 -1
- package/dist/__tests__/providers/pi/durable/PiDurableAgentRepository.test.js +16 -16
- package/dist/__tests__/providers/pi/durable/PiDurableAgentRepository.test.js.map +1 -1
- package/dist/__tests__/providers/pi/durable/PiPrintAgentService.test.js +52 -52
- package/dist/__tests__/providers/pi/durable/PiPrintAgentService.test.js.map +1 -1
- package/dist/__tests__/providers/pi/durable/PiPrintProtocol.test.js +44 -44
- package/dist/__tests__/providers/pi/durable/PiPrintProtocol.test.js.map +1 -1
- package/dist/__tests__/providers/pi/durable/PiPrintRunner.test.js +126 -126
- package/dist/__tests__/providers/pi/durable/PiPrintRunner.test.js.map +1 -1
- package/dist/__tests__/providers/pi/durable/PiStreamParser.test.js +14 -14
- package/dist/__tests__/providers/pi/durable/PiStreamParser.test.js.map +1 -1
- package/dist/__tests__/readiness/AgentReadiness.test.js +301 -0
- package/dist/__tests__/readiness/AgentReadiness.test.js.map +1 -0
- package/dist/__tests__/runtime/AgentRuntime.test.js +13 -0
- package/dist/__tests__/runtime/AgentRuntime.test.js.map +1 -0
- package/dist/__tests__/runtime/HerdrAgentRuntime.test.js +452 -0
- package/dist/__tests__/runtime/HerdrAgentRuntime.test.js.map +1 -0
- package/dist/__tests__/runtime/ManagedAgentRuntime.test.js +588 -0
- package/dist/__tests__/runtime/ManagedAgentRuntime.test.js.map +1 -0
- package/dist/__tests__/terminal/TerminalFocusManager.test.js +100 -100
- package/dist/__tests__/terminal/TerminalFocusManager.test.js.map +1 -1
- package/dist/__tests__/terminal/TmuxManager.test.js +101 -101
- package/dist/__tests__/terminal/TmuxManager.test.js.map +1 -1
- package/dist/__tests__/terminal/TtyWriter.test.js +185 -185
- package/dist/__tests__/terminal/TtyWriter.test.js.map +1 -1
- package/dist/__tests__/utils/AgentRegistry.test.js +335 -217
- package/dist/__tests__/utils/AgentRegistry.test.js.map +1 -1
- package/dist/__tests__/utils/ClaudeSessionParser.test.js +103 -101
- package/dist/__tests__/utils/ClaudeSessionParser.test.js.map +1 -1
- package/dist/__tests__/utils/agent-requests.test.js +43 -43
- package/dist/__tests__/utils/agent-requests.test.js.map +1 -1
- package/dist/__tests__/utils/agents.test.js +17 -17
- package/dist/__tests__/utils/agents.test.js.map +1 -1
- package/dist/__tests__/utils/matching.test.js +92 -92
- package/dist/__tests__/utils/matching.test.js.map +1 -1
- package/dist/__tests__/utils/process.test.js +108 -108
- package/dist/__tests__/utils/process.test.js.map +1 -1
- package/dist/__tests__/utils/session.test.js +53 -53
- package/dist/__tests__/utils/session.test.js.map +1 -1
- package/dist/adapters/AgentAdapter.d.ts +2 -2
- package/dist/adapters/AgentAdapter.d.ts.map +1 -1
- package/dist/adapters/AgentAdapter.js +1 -1
- package/dist/adapters/AgentAdapter.js.map +1 -1
- package/dist/adapters/CopilotAdapter.d.ts +2 -2
- package/dist/adapters/CopilotAdapter.d.ts.map +1 -1
- package/dist/adapters/CopilotAdapter.js +51 -51
- package/dist/adapters/CopilotAdapter.js.map +1 -1
- package/dist/adapters/GeminiCliAdapter.d.ts +2 -2
- package/dist/adapters/GeminiCliAdapter.d.ts.map +1 -1
- package/dist/adapters/GeminiCliAdapter.js +86 -86
- package/dist/adapters/GeminiCliAdapter.js.map +1 -1
- package/dist/adapters/GrokCliAdapter.d.ts +1 -1
- package/dist/adapters/GrokCliAdapter.d.ts.map +1 -1
- package/dist/adapters/GrokCliAdapter.js +80 -80
- package/dist/adapters/GrokCliAdapter.js.map +1 -1
- package/dist/adapters/OpenCodeAdapter.d.ts +1 -1
- package/dist/adapters/OpenCodeAdapter.d.ts.map +1 -1
- package/dist/adapters/OpenCodeAdapter.js +37 -36
- package/dist/adapters/OpenCodeAdapter.js.map +1 -1
- package/dist/adapters/index.d.ts +9 -9
- package/dist/adapters/index.d.ts.map +1 -1
- package/dist/adapters/index.js +8 -8
- package/dist/adapters/index.js.map +1 -1
- package/dist/capacity/codex.d.ts +3 -3
- package/dist/capacity/codex.d.ts.map +1 -1
- package/dist/capacity/codex.js +57 -57
- package/dist/capacity/codex.js.map +1 -1
- package/dist/capacity/index.d.ts +3 -3
- package/dist/capacity/index.d.ts.map +1 -1
- package/dist/capacity/index.js +8 -8
- package/dist/capacity/index.js.map +1 -1
- package/dist/capacity/types.d.ts +1 -1
- package/dist/capacity/types.js.map +1 -1
- package/dist/database/connection.d.ts +1 -1
- package/dist/database/connection.d.ts.map +1 -1
- package/dist/database/connection.js +15 -15
- package/dist/database/connection.js.map +1 -1
- package/dist/database/index.d.ts +3 -3
- package/dist/database/index.d.ts.map +1 -1
- package/dist/database/index.js +2 -2
- package/dist/database/index.js.map +1 -1
- package/dist/database/migrations/005_agent_runtime.sql +2 -0
- package/dist/database/schema.d.ts +1 -1
- package/dist/database/schema.d.ts.map +1 -1
- package/dist/database/schema.js +7 -7
- package/dist/database/schema.js.map +1 -1
- package/dist/durable/DurableAgent.d.ts +9 -9
- package/dist/durable/DurableAgent.d.ts.map +1 -1
- package/dist/durable/DurableAgent.js +16 -16
- package/dist/durable/DurableAgent.js.map +1 -1
- package/dist/durable/DurableAgentRepository.d.ts +4 -4
- package/dist/durable/DurableAgentRepository.d.ts.map +1 -1
- package/dist/durable/DurableAgentRepository.js +49 -48
- package/dist/durable/DurableAgentRepository.js.map +1 -1
- package/dist/durable/process.d.ts +1 -1
- package/dist/durable/process.d.ts.map +1 -1
- package/dist/durable/process.js +14 -14
- package/dist/durable/process.js.map +1 -1
- package/dist/durable/run.d.ts +2 -2
- package/dist/durable/run.d.ts.map +1 -1
- package/dist/durable/run.js +6 -6
- package/dist/durable/run.js.map +1 -1
- package/dist/durable/utils.d.ts +1 -1
- package/dist/durable/utils.d.ts.map +1 -1
- package/dist/durable/utils.js +4 -4
- package/dist/durable/utils.js.map +1 -1
- package/dist/index.d.ts +46 -41
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +27 -25
- package/dist/index.js.map +1 -1
- package/dist/providers/claude/ClaudeAgentMapper.d.ts +4 -4
- package/dist/providers/claude/ClaudeAgentMapper.d.ts.map +1 -1
- package/dist/providers/claude/ClaudeAgentMapper.js +10 -10
- package/dist/providers/claude/ClaudeAgentMapper.js.map +1 -1
- package/dist/providers/claude/ClaudeCodeAdapter.d.ts +1 -1
- package/dist/providers/claude/ClaudeCodeAdapter.d.ts.map +1 -1
- package/dist/providers/claude/ClaudeCodeAdapter.js +14 -14
- package/dist/providers/claude/ClaudeCodeAdapter.js.map +1 -1
- package/dist/providers/claude/ClaudeSessionLocator.d.ts +4 -4
- package/dist/providers/claude/ClaudeSessionLocator.d.ts.map +1 -1
- package/dist/providers/claude/ClaudeSessionLocator.js +79 -79
- package/dist/providers/claude/ClaudeSessionLocator.js.map +1 -1
- package/dist/providers/claude/ClaudeSessionParser.d.ts +2 -2
- package/dist/providers/claude/ClaudeSessionParser.d.ts.map +1 -1
- package/dist/providers/claude/ClaudeSessionParser.js +99 -99
- package/dist/providers/claude/ClaudeSessionParser.js.map +1 -1
- package/dist/providers/claude/durable/ClaudeCliProbe.d.ts.map +1 -1
- package/dist/providers/claude/durable/ClaudeCliProbe.js +16 -16
- package/dist/providers/claude/durable/ClaudeCliProbe.js.map +1 -1
- package/dist/providers/claude/durable/ClaudePrintAgentService.d.ts +5 -5
- package/dist/providers/claude/durable/ClaudePrintAgentService.d.ts.map +1 -1
- package/dist/providers/claude/durable/ClaudePrintAgentService.js +10 -10
- package/dist/providers/claude/durable/ClaudePrintAgentService.js.map +1 -1
- package/dist/providers/claude/durable/ClaudePrintRunner.d.ts +4 -4
- package/dist/providers/claude/durable/ClaudePrintRunner.d.ts.map +1 -1
- package/dist/providers/claude/durable/ClaudePrintRunner.js +18 -18
- package/dist/providers/claude/durable/ClaudePrintRunner.js.map +1 -1
- package/dist/providers/claude/durable/ClaudeStreamParser.d.ts +2 -2
- package/dist/providers/claude/durable/ClaudeStreamParser.d.ts.map +1 -1
- package/dist/providers/claude/durable/ClaudeStreamParser.js +17 -17
- package/dist/providers/claude/durable/ClaudeStreamParser.js.map +1 -1
- package/dist/providers/codex/CodexAdapter.d.ts +27 -0
- package/dist/providers/codex/CodexAdapter.d.ts.map +1 -0
- package/dist/providers/codex/CodexAdapter.js +162 -0
- package/dist/providers/codex/CodexAdapter.js.map +1 -0
- package/dist/providers/codex/CodexAgentMapper.d.ts +9 -0
- package/dist/providers/codex/CodexAgentMapper.d.ts.map +1 -0
- package/dist/providers/codex/CodexAgentMapper.js +35 -0
- package/dist/providers/codex/CodexAgentMapper.js.map +1 -0
- package/dist/providers/codex/CodexSessionLocator.d.ts +44 -0
- package/dist/providers/codex/CodexSessionLocator.d.ts.map +1 -0
- package/dist/providers/codex/CodexSessionLocator.js +207 -0
- package/dist/providers/codex/CodexSessionLocator.js.map +1 -0
- package/dist/providers/codex/CodexSessionMapping.d.ts +23 -0
- package/dist/providers/codex/CodexSessionMapping.d.ts.map +1 -0
- package/dist/providers/codex/CodexSessionMapping.js +68 -0
- package/dist/providers/codex/CodexSessionMapping.js.map +1 -0
- package/dist/providers/codex/CodexSessionParser.d.ts +58 -0
- package/dist/providers/codex/CodexSessionParser.d.ts.map +1 -0
- package/dist/providers/codex/CodexSessionParser.js +262 -0
- package/dist/providers/codex/CodexSessionParser.js.map +1 -0
- package/dist/providers/codex/durable/CodexCliProbe.d.ts.map +1 -1
- package/dist/providers/codex/durable/CodexCliProbe.js +22 -22
- package/dist/providers/codex/durable/CodexCliProbe.js.map +1 -1
- package/dist/providers/codex/durable/CodexPrintAgentService.d.ts +6 -6
- package/dist/providers/codex/durable/CodexPrintAgentService.d.ts.map +1 -1
- package/dist/providers/codex/durable/CodexPrintAgentService.js +10 -10
- package/dist/providers/codex/durable/CodexPrintAgentService.js.map +1 -1
- package/dist/providers/codex/durable/CodexPrintRunner.d.ts +4 -4
- package/dist/providers/codex/durable/CodexPrintRunner.d.ts.map +1 -1
- package/dist/providers/codex/durable/CodexPrintRunner.js +20 -20
- package/dist/providers/codex/durable/CodexPrintRunner.js.map +1 -1
- package/dist/providers/codex/durable/CodexStreamParser.d.ts +2 -2
- package/dist/providers/codex/durable/CodexStreamParser.d.ts.map +1 -1
- package/dist/providers/codex/durable/CodexStreamParser.js +21 -21
- package/dist/providers/codex/durable/CodexStreamParser.js.map +1 -1
- package/dist/providers/pi/PiAdapter.d.ts +28 -0
- package/dist/providers/pi/PiAdapter.d.ts.map +1 -0
- package/dist/providers/pi/PiAdapter.js +153 -0
- package/dist/providers/pi/PiAdapter.js.map +1 -0
- package/dist/providers/pi/PiAgentMapper.d.ts +9 -0
- package/dist/providers/pi/PiAgentMapper.d.ts.map +1 -0
- package/dist/providers/pi/PiAgentMapper.js +37 -0
- package/dist/providers/pi/PiAgentMapper.js.map +1 -0
- package/dist/providers/pi/PiSessionLocator.d.ts +23 -0
- package/dist/providers/pi/PiSessionLocator.d.ts.map +1 -0
- package/dist/providers/pi/PiSessionLocator.js +79 -0
- package/dist/providers/pi/PiSessionLocator.js.map +1 -0
- package/dist/providers/pi/PiSessionParser.d.ts +36 -0
- package/dist/providers/pi/PiSessionParser.d.ts.map +1 -0
- package/dist/providers/pi/PiSessionParser.js +191 -0
- package/dist/providers/pi/PiSessionParser.js.map +1 -0
- package/dist/providers/pi/PiSessionTracker.d.ts +23 -0
- package/dist/providers/pi/PiSessionTracker.d.ts.map +1 -0
- package/dist/providers/pi/PiSessionTracker.js +69 -0
- package/dist/providers/pi/PiSessionTracker.js.map +1 -0
- package/dist/providers/pi/durable/PiCliProbe.d.ts.map +1 -1
- package/dist/providers/pi/durable/PiCliProbe.js +15 -15
- package/dist/providers/pi/durable/PiCliProbe.js.map +1 -1
- package/dist/providers/pi/durable/PiPrintAgentService.d.ts +6 -6
- package/dist/providers/pi/durable/PiPrintAgentService.d.ts.map +1 -1
- package/dist/providers/pi/durable/PiPrintAgentService.js +10 -10
- package/dist/providers/pi/durable/PiPrintAgentService.js.map +1 -1
- package/dist/providers/pi/durable/PiPrintProtocol.d.ts.map +1 -1
- package/dist/providers/pi/durable/PiPrintProtocol.js +18 -18
- package/dist/providers/pi/durable/PiPrintProtocol.js.map +1 -1
- package/dist/providers/pi/durable/PiPrintRunner.d.ts +4 -4
- package/dist/providers/pi/durable/PiPrintRunner.d.ts.map +1 -1
- package/dist/providers/pi/durable/PiPrintRunner.js +15 -15
- package/dist/providers/pi/durable/PiPrintRunner.js.map +1 -1
- package/dist/providers/pi/durable/PiStreamParser.d.ts +1 -1
- package/dist/providers/pi/durable/PiStreamParser.d.ts.map +1 -1
- package/dist/providers/pi/durable/PiStreamParser.js +16 -16
- package/dist/providers/pi/durable/PiStreamParser.js.map +1 -1
- package/dist/readiness/AgentReadiness.d.ts +67 -0
- package/dist/readiness/AgentReadiness.d.ts.map +1 -0
- package/dist/readiness/AgentReadiness.js +614 -0
- package/dist/readiness/AgentReadiness.js.map +1 -0
- package/dist/runtime/ManagedAgentRuntime.d.ts +69 -0
- package/dist/runtime/ManagedAgentRuntime.d.ts.map +1 -0
- package/dist/runtime/ManagedAgentRuntime.js +156 -0
- package/dist/runtime/ManagedAgentRuntime.js.map +1 -0
- package/dist/runtime/RuntimeFactory.d.ts +4 -0
- package/dist/runtime/RuntimeFactory.d.ts.map +1 -0
- package/dist/runtime/RuntimeFactory.js +11 -0
- package/dist/runtime/RuntimeFactory.js.map +1 -0
- package/dist/runtime/errors.d.ts +27 -0
- package/dist/runtime/errors.d.ts.map +1 -0
- package/dist/runtime/errors.js +42 -0
- package/dist/runtime/errors.js.map +1 -0
- package/dist/runtime/herdr/HerdrAgentRuntime.d.ts +31 -0
- package/dist/runtime/herdr/HerdrAgentRuntime.d.ts.map +1 -0
- package/dist/runtime/herdr/HerdrAgentRuntime.js +184 -0
- package/dist/runtime/herdr/HerdrAgentRuntime.js.map +1 -0
- package/dist/runtime/herdr/HerdrCliClient.d.ts +13 -0
- package/dist/runtime/herdr/HerdrCliClient.d.ts.map +1 -0
- package/dist/runtime/herdr/HerdrCliClient.js +60 -0
- package/dist/runtime/herdr/HerdrCliClient.js.map +1 -0
- package/dist/runtime/herdr/HerdrErrors.d.ts +7 -0
- package/dist/runtime/herdr/HerdrErrors.d.ts.map +1 -0
- package/dist/runtime/herdr/HerdrErrors.js +10 -0
- package/dist/runtime/herdr/HerdrErrors.js.map +1 -0
- package/dist/runtime/herdr/HerdrResponseParsers.d.ts +14 -0
- package/dist/runtime/herdr/HerdrResponseParsers.d.ts.map +1 -0
- package/dist/runtime/herdr/HerdrResponseParsers.js +96 -0
- package/dist/runtime/herdr/HerdrResponseParsers.js.map +1 -0
- package/dist/runtime/herdr/HerdrRuntimeRef.d.ts +9 -0
- package/dist/runtime/herdr/HerdrRuntimeRef.d.ts.map +1 -0
- package/dist/runtime/herdr/HerdrRuntimeRef.js +33 -0
- package/dist/runtime/herdr/HerdrRuntimeRef.js.map +1 -0
- package/dist/runtime/tmux/PidPolling.d.ts +5 -0
- package/dist/runtime/tmux/PidPolling.d.ts.map +1 -0
- package/dist/runtime/tmux/PidPolling.js +24 -0
- package/dist/runtime/tmux/PidPolling.js.map +1 -0
- package/dist/runtime/tmux/TmuxAgentRuntime.d.ts +17 -0
- package/dist/runtime/tmux/TmuxAgentRuntime.d.ts.map +1 -0
- package/dist/runtime/tmux/TmuxAgentRuntime.js +80 -0
- package/dist/runtime/tmux/TmuxAgentRuntime.js.map +1 -0
- package/dist/runtime/tmux/TmuxRuntimeRef.d.ts +5 -0
- package/dist/runtime/tmux/TmuxRuntimeRef.d.ts.map +1 -0
- package/dist/runtime/tmux/TmuxRuntimeRef.js +9 -0
- package/dist/runtime/tmux/TmuxRuntimeRef.js.map +1 -0
- package/dist/runtime/types.d.ts +54 -0
- package/dist/runtime/types.d.ts.map +1 -0
- package/dist/runtime/types.js +3 -0
- package/dist/runtime/types.js.map +1 -0
- package/dist/terminal/TerminalFocusManager.d.ts.map +1 -1
- package/dist/terminal/TerminalFocusManager.js +50 -50
- package/dist/terminal/TerminalFocusManager.js.map +1 -1
- package/dist/terminal/TmuxManager.d.ts.map +1 -1
- package/dist/terminal/TmuxManager.js +47 -47
- package/dist/terminal/TmuxManager.js.map +1 -1
- package/dist/terminal/TtyWriter.d.ts +1 -1
- package/dist/terminal/TtyWriter.d.ts.map +1 -1
- package/dist/terminal/TtyWriter.js +89 -89
- package/dist/terminal/TtyWriter.js.map +1 -1
- package/dist/terminal/index.d.ts +4 -4
- package/dist/terminal/index.js +3 -3
- package/dist/terminal/index.js.map +1 -1
- package/dist/utils/AgentRegistry.d.ts +10 -2
- package/dist/utils/AgentRegistry.d.ts.map +1 -1
- package/dist/utils/AgentRegistry.js +57 -24
- package/dist/utils/AgentRegistry.js.map +1 -1
- package/dist/utils/agent-requests.d.ts.map +1 -1
- package/dist/utils/agent-requests.js +5 -5
- package/dist/utils/agent-requests.js.map +1 -1
- package/dist/utils/agents.d.ts +2 -2
- package/dist/utils/agents.d.ts.map +1 -1
- package/dist/utils/agents.js +15 -15
- package/dist/utils/agents.js.map +1 -1
- package/dist/utils/applescript.js +1 -1
- package/dist/utils/applescript.js.map +1 -1
- package/dist/utils/index.d.ts +6 -6
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +4 -4
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/matching.d.ts +2 -2
- package/dist/utils/matching.d.ts.map +1 -1
- package/dist/utils/matching.js +4 -4
- package/dist/utils/matching.js.map +1 -1
- package/dist/utils/process.d.ts +1 -1
- package/dist/utils/process.d.ts.map +1 -1
- package/dist/utils/process.js +74 -74
- package/dist/utils/process.js.map +1 -1
- package/dist/utils/session.d.ts +1 -1
- package/dist/utils/session.d.ts.map +1 -1
- package/dist/utils/session.js +7 -7
- package/dist/utils/session.js.map +1 -1
- package/dist/utils/sortAgents.d.ts +2 -2
- package/dist/utils/sortAgents.d.ts.map +1 -1
- package/dist/utils/sortAgents.js +5 -5
- package/dist/utils/sortAgents.js.map +1 -1
- package/package.json +18 -19
- package/src/AgentManager.ts +283 -281
- package/src/__tests__/AgentManager.test.ts +917 -907
- package/src/__tests__/adapters/ClaudeCodeAdapter.test.ts +1657 -1368
- package/src/__tests__/adapters/CodexAdapter.test.ts +365 -1698
- package/src/__tests__/adapters/CopilotAdapter.test.ts +576 -481
- package/src/__tests__/adapters/GeminiCliAdapter.test.ts +1189 -1157
- package/src/__tests__/adapters/GrokCliAdapter.test.ts +325 -272
- package/src/__tests__/adapters/OpenCodeAdapter.test.ts +510 -455
- package/src/__tests__/capacity/codex.test.ts +178 -91
- package/src/__tests__/capacity/index.test.ts +27 -18
- package/src/__tests__/durable/CodexCliProbe.test.ts +75 -53
- package/src/__tests__/durable/CodexDurableAgentRepository.test.ts +51 -40
- package/src/__tests__/durable/CodexPrintAgent.integration.test.ts +89 -64
- package/src/__tests__/durable/CodexPrintAgentService.test.ts +196 -118
- package/src/__tests__/durable/CodexPrintRunner.test.ts +282 -162
- package/src/__tests__/fixtures/fake-claude.cjs +20 -13
- package/src/__tests__/fixtures/fake-codex.cjs +41 -30
- package/src/__tests__/print/ClaudeCliProbe.test.ts +27 -21
- package/src/__tests__/print/ClaudePrintAgent.integration.test.ts +48 -40
- package/src/__tests__/print/ClaudePrintAgentService.test.ts +118 -67
- package/src/__tests__/print/ClaudePrintRunner.test.ts +136 -83
- package/src/__tests__/print/DurableAgent.test.ts +19 -16
- package/src/__tests__/print/DurableAgentRepository.sqlite.test.ts +109 -86
- package/src/__tests__/print/DurableAgentRepository.test.ts +170 -137
- package/src/__tests__/providers/claude/ClaudeAgentMapper.test.ts +65 -65
- package/src/__tests__/providers/claude/ClaudeSessionLocator.test.ts +400 -377
- package/src/__tests__/providers/codex/CodexSessionLocator.test.ts +182 -0
- package/src/__tests__/providers/codex/CodexSessionMapping.test.ts +63 -0
- package/src/__tests__/providers/codex/CodexSessionParser.test.ts +192 -0
- package/src/__tests__/providers/pi/PiAdapter.test.ts +310 -0
- package/src/__tests__/providers/pi/PiSessionParser.test.ts +190 -0
- package/src/__tests__/providers/pi/PiSessionTracker.test.ts +79 -0
- package/src/__tests__/providers/pi/durable/PiCliProbe.test.ts +48 -32
- package/src/__tests__/providers/pi/durable/PiDurableAgentRepository.test.ts +24 -23
- package/src/__tests__/providers/pi/durable/PiPrintAgentService.test.ts +131 -59
- package/src/__tests__/providers/pi/durable/PiPrintProtocol.test.ts +66 -28
- package/src/__tests__/providers/pi/durable/PiPrintRunner.test.ts +236 -90
- package/src/__tests__/providers/pi/durable/PiStreamParser.test.ts +20 -18
- package/src/__tests__/readiness/AgentReadiness.test.ts +242 -0
- package/src/__tests__/runtime/AgentRuntime.test.ts +8 -0
- package/src/__tests__/runtime/HerdrAgentRuntime.test.ts +358 -0
- package/src/__tests__/runtime/ManagedAgentRuntime.test.ts +555 -0
- package/src/__tests__/terminal/TerminalFocusManager.test.ts +254 -253
- package/src/__tests__/terminal/TmuxManager.test.ts +157 -157
- package/src/__tests__/terminal/TtyWriter.test.ts +423 -419
- package/src/__tests__/utils/AgentRegistry.test.ts +506 -402
- package/src/__tests__/utils/ClaudeSessionParser.test.ts +276 -242
- package/src/__tests__/utils/agent-requests.test.ts +76 -56
- package/src/__tests__/utils/agents.test.ts +20 -20
- package/src/__tests__/utils/matching.test.ts +206 -171
- package/src/__tests__/utils/process.test.ts +276 -262
- package/src/__tests__/utils/session.test.ts +133 -139
- package/src/adapters/AgentAdapter.ts +134 -126
- package/src/adapters/CopilotAdapter.ts +405 -395
- package/src/adapters/GeminiCliAdapter.ts +598 -600
- package/src/adapters/GrokCliAdapter.ts +353 -342
- package/src/adapters/OpenCodeAdapter.ts +285 -259
- package/src/adapters/index.ts +15 -9
- package/src/capacity/codex.ts +137 -84
- package/src/capacity/index.ts +18 -13
- package/src/capacity/types.ts +1 -1
- package/src/database/connection.ts +73 -68
- package/src/database/index.ts +6 -6
- package/src/database/migrations/005_agent_runtime.sql +2 -0
- package/src/database/schema.ts +40 -38
- package/src/durable/DurableAgent.ts +85 -85
- package/src/durable/DurableAgentRepository.ts +409 -260
- package/src/durable/process.ts +22 -21
- package/src/durable/run.ts +61 -51
- package/src/durable/utils.ts +46 -41
- package/src/index.ts +145 -86
- package/src/providers/claude/ClaudeAgentMapper.ts +51 -50
- package/src/providers/claude/ClaudeCodeAdapter.ts +144 -136
- package/src/providers/claude/ClaudeSessionLocator.ts +291 -293
- package/src/providers/claude/ClaudeSessionParser.ts +322 -338
- package/src/providers/claude/durable/ClaudeCliProbe.ts +42 -37
- package/src/providers/claude/durable/ClaudePrintAgentService.ts +63 -50
- package/src/providers/claude/durable/ClaudePrintRunner.ts +79 -69
- package/src/providers/claude/durable/ClaudeStreamParser.ts +91 -62
- package/src/providers/codex/CodexAdapter.ts +205 -0
- package/src/providers/codex/CodexAgentMapper.ts +35 -0
- package/src/providers/codex/CodexSessionLocator.ts +279 -0
- package/src/providers/codex/CodexSessionMapping.ts +89 -0
- package/src/providers/codex/CodexSessionParser.ts +385 -0
- package/src/providers/codex/durable/CodexCliProbe.ts +50 -42
- package/src/providers/codex/durable/CodexPrintAgentService.ts +63 -49
- package/src/providers/codex/durable/CodexPrintRunner.ts +79 -69
- package/src/providers/codex/durable/CodexStreamParser.ts +97 -84
- package/src/providers/pi/PiAdapter.ts +183 -0
- package/src/providers/pi/PiAgentMapper.ts +36 -0
- package/src/providers/pi/PiSessionLocator.ts +95 -0
- package/src/providers/pi/PiSessionParser.ts +284 -0
- package/src/providers/pi/PiSessionTracker.ts +87 -0
- package/src/providers/pi/durable/PiCliProbe.ts +42 -34
- package/src/providers/pi/durable/PiPrintAgentService.ts +61 -53
- package/src/providers/pi/durable/PiPrintProtocol.ts +31 -29
- package/src/providers/pi/durable/PiPrintRunner.ts +75 -68
- package/src/providers/pi/durable/PiStreamParser.ts +82 -72
- package/src/readiness/AgentReadiness.ts +727 -0
- package/src/runtime/ManagedAgentRuntime.ts +266 -0
- package/src/runtime/RuntimeFactory.ts +13 -0
- package/src/runtime/errors.ts +50 -0
- package/src/runtime/herdr/HerdrAgentRuntime.ts +190 -0
- package/src/runtime/herdr/HerdrCliClient.ts +78 -0
- package/src/runtime/herdr/HerdrErrors.ts +9 -0
- package/src/runtime/herdr/HerdrResponseParsers.ts +76 -0
- package/src/runtime/herdr/HerdrRuntimeRef.ts +41 -0
- package/src/runtime/tmux/PidPolling.ts +34 -0
- package/src/runtime/tmux/TmuxAgentRuntime.ts +113 -0
- package/src/runtime/tmux/TmuxRuntimeRef.ts +9 -0
- package/src/runtime/types.ts +56 -0
- package/src/terminal/TerminalFocusManager.ts +215 -212
- package/src/terminal/TmuxManager.ts +99 -92
- package/src/terminal/TtyWriter.ts +203 -194
- package/src/terminal/index.ts +4 -4
- package/src/utils/AgentRegistry.ts +299 -238
- package/src/utils/agent-requests.ts +16 -16
- package/src/utils/agents.ts +41 -38
- package/src/utils/applescript.ts +4 -4
- package/src/utils/index.ts +12 -6
- package/src/utils/matching.ts +43 -43
- package/src/utils/process.ts +261 -258
- package/src/utils/session.ts +66 -66
- package/src/utils/sortAgents.ts +35 -33
- package/tsconfig.json +2 -8
- package/vitest.config.ts +16 -16
- package/.eslintrc.json +0 -31
- package/dist/__tests__/adapters/PiAdapter.test.js +0 -618
- package/dist/__tests__/adapters/PiAdapter.test.js.map +0 -1
- package/dist/__tests__/database/DurableAgentsDatabase.test.js +0 -128
- package/dist/__tests__/database/DurableAgentsDatabase.test.js.map +0 -1
- package/dist/adapters/CodexAdapter.d.ts +0 -109
- package/dist/adapters/CodexAdapter.d.ts.map +0 -1
- package/dist/adapters/CodexAdapter.js +0 -710
- package/dist/adapters/CodexAdapter.js.map +0 -1
- package/dist/adapters/PiAdapter.d.ts +0 -63
- package/dist/adapters/PiAdapter.d.ts.map +0 -1
- package/dist/adapters/PiAdapter.js +0 -453
- package/dist/adapters/PiAdapter.js.map +0 -1
- package/src/__tests__/adapters/PiAdapter.test.ts +0 -458
- package/src/__tests__/database/DurableAgentsDatabase.test.ts +0 -102
- package/src/adapters/CodexAdapter.ts +0 -923
- package/src/adapters/PiAdapter.ts +0 -598
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/__tests__/providers/claude/ClaudeSessionLocator.test.ts"],"sourcesContent":["import type { MockedFunction } from 'vitest';\nimport * as fs from 'fs';\nimport * as os from 'os';\nimport * as path from 'path';\nimport { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport { AgentStatus, type ProcessInfo } from '../../../adapters/AgentAdapter.js';\nimport { ClaudeSessionLocator } from '../../../providers/claude/ClaudeSessionLocator.js';\nimport { batchGetSessionFileBirthtimes } from '../../../utils/session.js';\nimport type { SessionFile } from '../../../utils/session.js';\n\nvi.mock('../../../utils/session.js', async (importOriginal) => {\n const actual = await importOriginal() as typeof import('../../../utils/session.js');\n return {\n ...actual,\n batchGetSessionFileBirthtimes: vi.fn(),\n };\n});\n\nconst mockedBatchGetSessionFileBirthtimes =\n batchGetSessionFileBirthtimes as MockedFunction<typeof batchGetSessionFileBirthtimes>;\n\nconst tmpDirs: string[] = [];\n\nfunction makeTmpDir(): string {\n const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'claude-locator-test-'));\n tmpDirs.push(dir);\n return dir;\n}\n\nfunction makeProcess(overrides: Partial<ProcessInfo> = {}): ProcessInfo {\n return {\n pid: 123,\n command: 'claude',\n cwd: '/repo/my-app',\n tty: 'ttys001',\n startTime: new Date('2026-08-23T10:00:00.000Z'),\n ...overrides,\n };\n}\n\ntype PidFileMatching = (processes: ProcessInfo[]) => {\n direct: Array<{ process: ProcessInfo; sessionFile: SessionFile }>;\n fallback: ProcessInfo[];\n};\n\n/** `tryPidFileMatching` is private; tests drive it directly like the sibling adapter suites do. */\nfunction bindPidFileMatching(locator: ClaudeSessionLocator): PidFileMatching {\n return (locator as unknown as { tryPidFileMatching: PidFileMatching })\n .tryPidFileMatching.bind(locator) as PidFileMatching;\n}\n\n/** `getProjectDir` is private; bound here so the encoding tests read cleanly. */\nfunction bindProjectDir(locator: ClaudeSessionLocator): (cwd: string) => string {\n return (locator as unknown as { getProjectDir: (cwd: string) => string })\n .getProjectDir.bind(locator);\n}\n\ndescribe('ClaudeSessionLocator', () => {\n beforeEach(() => {\n mockedBatchGetSessionFileBirthtimes.mockReset();\n });\n\n afterEach(() => {\n for (const dir of tmpDirs.splice(0)) {\n fs.rmSync(dir, { recursive: true, force: true });\n }\n });\n\n it('matches resumed sessions directly and carries live PID status metadata', () => {\n const root = makeTmpDir();\n const projectsDir = path.join(root, 'projects');\n const sessionsDir = path.join(root, 'sessions');\n const cwd = '/repo/my-app';\n const sessionId = '12345678-1234-1234-1234-123456789abc';\n const projectDir = path.join(projectsDir, '-repo-my-app');\n const sessionFile = path.join(projectDir, `${sessionId}.jsonl`);\n fs.mkdirSync(projectDir, { recursive: true });\n fs.mkdirSync(sessionsDir, { recursive: true });\n fs.writeFileSync(sessionFile, '{}\\n');\n fs.writeFileSync(path.join(sessionsDir, '123.json'), JSON.stringify({\n pid: 123,\n sessionId,\n cwd,\n startedAt: new Date('2026-08-23T10:00:00.000Z').getTime(),\n kind: 'interactive',\n entrypoint: 'cli',\n status: 'waiting',\n waitingFor: 'approve Read',\n }));\n\n const locator = new ClaudeSessionLocator({ projectsDir, sessionsDir });\n const matches = locator.matchRunningProcesses([\n makeProcess({ command: `claude --resume ${sessionId}`, cwd }),\n ]);\n\n expect(matches.direct).toHaveLength(1);\n expect(matches.legacyMatches).toEqual([]);\n expect(matches.direct[0]).toMatchObject({\n pidStatus: AgentStatus.WAITING,\n waitingFor: 'approve Read',\n sessionFile: {\n sessionId,\n filePath: sessionFile,\n projectDir,\n resolvedCwd: cwd,\n },\n });\n });\n describe('discoverLiveSessions', () => {\n let tmpDir: string;\n let projectsDir: string;\n let locator: ClaudeSessionLocator;\n\n beforeEach(() => {\n tmpDir = makeTmpDir();\n projectsDir = path.join(tmpDir, 'projects');\n locator = new ClaudeSessionLocator({\n projectsDir,\n sessionsDir: path.join(tmpDir, 'sessions'),\n });\n });\n\n it('should return empty when projects dir does not exist', () => {\n const missing = new ClaudeSessionLocator({\n projectsDir: path.join(tmpDir, 'nonexistent'),\n sessionsDir: path.join(tmpDir, 'sessions'),\n });\n\n const result = missing.discoverLiveSessions([\n { pid: 1, command: 'claude', cwd: '/test', tty: '' },\n ]);\n expect(result).toEqual([]);\n });\n\n it('should scan only directories matching process CWDs', () => {\n // /my/project → -my-project (encoded dir)\n const encodedDir = path.join(projectsDir, '-my-project');\n fs.mkdirSync(encodedDir, { recursive: true });\n\n // Also create another dir that should NOT be scanned\n const otherDir = path.join(projectsDir, '-other-project');\n fs.mkdirSync(otherDir, { recursive: true });\n\n const mockFiles: SessionFile[] = [\n {\n sessionId: 's1',\n filePath: path.join(encodedDir, 's1.jsonl'),\n projectDir: encodedDir,\n birthtimeMs: 1710800324000,\n resolvedCwd: '',\n },\n ];\n mockedBatchGetSessionFileBirthtimes.mockReturnValue(mockFiles);\n\n const processes = [\n { pid: 1, command: 'claude', cwd: '/my/project', tty: '' },\n ];\n\n const result = locator.discoverLiveSessions(processes);\n expect(result).toHaveLength(1);\n expect(result[0].resolvedCwd).toBe('/my/project');\n // batchGetSessionFileBirthtimes called once with all dirs\n expect(mockedBatchGetSessionFileBirthtimes).toHaveBeenCalledTimes(1);\n expect(mockedBatchGetSessionFileBirthtimes).toHaveBeenCalledWith([encodedDir]);\n });\n\n it('should return empty when encoded dir does not exist', () => {\n fs.mkdirSync(projectsDir, { recursive: true });\n\n // Process CWD /test encodes to -test, but that dir doesn't exist\n const result = locator.discoverLiveSessions([\n { pid: 1, command: 'claude', cwd: '/test', tty: '' },\n ]);\n expect(result).toEqual([]);\n expect(mockedBatchGetSessionFileBirthtimes).not.toHaveBeenCalled();\n });\n\n it('should deduplicate when multiple processes share same CWD', () => {\n const encodedDir = path.join(projectsDir, '-my-project');\n fs.mkdirSync(encodedDir, { recursive: true });\n\n mockedBatchGetSessionFileBirthtimes.mockReturnValue([\n { sessionId: 's1', filePath: path.join(encodedDir, 's1.jsonl'), projectDir: encodedDir, birthtimeMs: 1710800324000, resolvedCwd: '' },\n ]);\n\n const processes = [\n { pid: 1, command: 'claude', cwd: '/my/project', tty: '' },\n { pid: 2, command: 'claude', cwd: '/my/project', tty: '' },\n ];\n\n const result = locator.discoverLiveSessions(processes);\n // Should only call batch once with deduplicated dir\n expect(mockedBatchGetSessionFileBirthtimes).toHaveBeenCalledTimes(1);\n expect(mockedBatchGetSessionFileBirthtimes).toHaveBeenCalledWith([encodedDir]);\n expect(result).toHaveLength(1);\n });\n\n it('should skip processes with empty cwd', () => {\n fs.mkdirSync(projectsDir, { recursive: true });\n\n const result = locator.discoverLiveSessions([\n { pid: 1, command: 'claude', cwd: '', tty: '' },\n ]);\n expect(result).toEqual([]);\n });\n });\n\n describe('tryPidFileMatching', () => {\n let tmpDir: string;\n let sessionsDir: string;\n let projectsDir: string;\n let tryMatch: (processes: ProcessInfo[]) => {\n direct: Array<{ process: ProcessInfo; sessionFile: SessionFile }>;\n fallback: ProcessInfo[];\n };\n\n beforeEach(() => {\n tmpDir = makeTmpDir();\n sessionsDir = path.join(tmpDir, 'sessions');\n projectsDir = path.join(tmpDir, 'projects');\n fs.mkdirSync(sessionsDir, { recursive: true });\n tryMatch = bindPidFileMatching(new ClaudeSessionLocator({ projectsDir, sessionsDir }));\n });\n\n const makeProc = (pid: number, cwd = '/project/test', startTime?: Date): ProcessInfo => ({\n pid, command: 'claude', cwd, tty: 'ttys001', startTime,\n });\n\n const writePidFile = (pid: number, sessionId: string, cwd: string, startedAt: number) => {\n fs.writeFileSync(\n path.join(sessionsDir, `${pid}.json`),\n JSON.stringify({ pid, sessionId, cwd, startedAt, kind: 'interactive', entrypoint: 'cli' }),\n );\n };\n\n const writeJsonl = (cwd: string, sessionId: string) => {\n const encoded = cwd.replace(/[^a-zA-Z0-9]/g, '-');\n const projDir = path.join(projectsDir, encoded);\n fs.mkdirSync(projDir, { recursive: true });\n const filePath = path.join(projDir, `${sessionId}.jsonl`);\n fs.writeFileSync(filePath, JSON.stringify({ type: 'assistant', timestamp: new Date().toISOString() }));\n return filePath;\n };\n\n it('should return direct match when PID file and JSONL both exist within time tolerance', () => {\n const startTime = new Date();\n const proc = makeProc(1001, '/project/test', startTime);\n writePidFile(1001, 'session-abc', '/project/test', startTime.getTime());\n writeJsonl('/project/test', 'session-abc');\n\n const { direct, fallback } = tryMatch([proc]);\n\n expect(direct).toHaveLength(1);\n expect(fallback).toHaveLength(0);\n expect(direct[0].sessionFile.sessionId).toBe('session-abc');\n expect(direct[0].sessionFile.resolvedCwd).toBe('/project/test');\n expect(direct[0].process.pid).toBe(1001);\n });\n\n it('should fall back when PID file exists but JSONL is missing', () => {\n const startTime = new Date();\n const proc = makeProc(1002, '/project/test', startTime);\n writePidFile(1002, 'nonexistent-session', '/project/test', startTime.getTime());\n // No JSONL file written\n\n const { direct, fallback } = tryMatch([proc]);\n\n expect(direct).toHaveLength(0);\n expect(fallback).toHaveLength(1);\n expect(fallback[0].pid).toBe(1002);\n });\n\n it('should fall back when startedAt is stale (>60s from proc.startTime)', () => {\n const startTime = new Date();\n const staleTime = startTime.getTime() - 90_000; // 90 seconds earlier\n const proc = makeProc(1003, '/project/test', startTime);\n writePidFile(1003, 'stale-session', '/project/test', staleTime);\n writeJsonl('/project/test', 'stale-session');\n\n const { direct, fallback } = tryMatch([proc]);\n\n expect(direct).toHaveLength(0);\n expect(fallback).toHaveLength(1);\n });\n\n it('should accept PID file when startedAt is within 60s tolerance', () => {\n const startTime = new Date();\n const closeTime = startTime.getTime() - 30_000; // 30 seconds earlier — within tolerance\n const proc = makeProc(1004, '/project/test', startTime);\n writePidFile(1004, 'close-session', '/project/test', closeTime);\n writeJsonl('/project/test', 'close-session');\n\n const { direct, fallback } = tryMatch([proc]);\n\n expect(direct).toHaveLength(1);\n expect(fallback).toHaveLength(0);\n });\n\n it('should fall back when PID file is absent', () => {\n const proc = makeProc(1005, '/project/test', new Date());\n // No PID file written\n\n const { direct, fallback } = tryMatch([proc]);\n\n expect(direct).toHaveLength(0);\n expect(fallback).toHaveLength(1);\n });\n\n it('should fall back when PID file contains malformed JSON', () => {\n const proc = makeProc(1006, '/project/test', new Date());\n fs.writeFileSync(path.join(sessionsDir, '1006.json'), 'not valid json {{{');\n\n expect(() => {\n const { direct, fallback } = tryMatch([proc]);\n expect(direct).toHaveLength(0);\n expect(fallback).toHaveLength(1);\n }).not.toThrow();\n });\n\n it('should fall back for all processes when sessions dir does not exist', () => {\n const missingSessions = bindPidFileMatching(new ClaudeSessionLocator({\n projectsDir,\n sessionsDir: path.join(tmpDir, 'nonexistent-sessions'),\n }));\n const processes = [makeProc(2001, '/a', new Date()), makeProc(2002, '/b', new Date())];\n\n const { direct, fallback } = missingSessions(processes);\n\n expect(direct).toHaveLength(0);\n expect(fallback).toHaveLength(2);\n });\n\n it('should correctly split mixed processes (some with PID files, some without)', () => {\n const startTime = new Date();\n const proc1 = makeProc(3001, '/project/one', startTime);\n const proc2 = makeProc(3002, '/project/two', startTime);\n const proc3 = makeProc(3003, '/project/three', startTime);\n\n writePidFile(3001, 'session-one', '/project/one', startTime.getTime());\n writeJsonl('/project/one', 'session-one');\n writePidFile(3003, 'session-three', '/project/three', startTime.getTime());\n writeJsonl('/project/three', 'session-three');\n // proc2 has no PID file\n\n const { direct, fallback } = tryMatch([proc1, proc2, proc3]);\n\n expect(direct).toHaveLength(2);\n expect(fallback).toHaveLength(1);\n expect(direct.map((d) => d.process.pid).sort()).toEqual([3001, 3003]);\n expect(fallback[0].pid).toBe(3002);\n });\n\n it('should skip stale-file check when proc.startTime is undefined', () => {\n const proc = makeProc(4001, '/project/test', undefined); // no startTime\n writePidFile(4001, 'no-time-session', '/project/test', Date.now() - 999_999);\n writeJsonl('/project/test', 'no-time-session');\n\n const { direct, fallback } = tryMatch([proc]);\n\n // startTime undefined → stale check skipped → direct match\n expect(direct).toHaveLength(1);\n expect(fallback).toHaveLength(0);\n });\n });\n\n describe('getProjectDir', () => {\n let tmpDir: string;\n let projectsDir: string;\n let encode: (cwd: string) => string;\n\n beforeEach(() => {\n tmpDir = makeTmpDir();\n projectsDir = path.join(tmpDir, 'projects');\n encode = bindProjectDir(new ClaudeSessionLocator({\n projectsDir,\n sessionsDir: path.join(tmpDir, 'sessions'),\n }));\n });\n\n it('should replace path separators with hyphens', () => {\n expect(encode('/Users/foo/bar')).toBe(path.join(projectsDir, '-Users-foo-bar'));\n });\n\n it('should encode underscores as hyphens (matches Claude Code CLI)', () => {\n expect(encode('/Users/foo/my_project')).toBe(path.join(projectsDir, '-Users-foo-my-project'));\n });\n\n it('should encode dots as hyphens', () => {\n expect(encode('/Users/foo/.worktrees/x')).toBe(path.join(projectsDir, '-Users-foo--worktrees-x'));\n });\n\n it('should collide paths that differ only in non-alphanumeric chars', () => {\n // The encoding is intentionally lossy — callers must\n // disambiguate via session JSONL contents, not dir name.\n expect(encode('/a/b_c')).toBe(encode('/a/b-c'));\n expect(encode('/a/b_c')).toBe(encode('/a/b.c'));\n });\n\n it('should resolve to a real session dir when cwd contains underscores', () => {\n const cwd = '/Users/foo/my_project';\n const expectedDir = path.join(projectsDir, '-Users-foo-my-project');\n fs.mkdirSync(expectedDir, { recursive: true });\n const sessionFile = path.join(expectedDir, 'session-underscore.jsonl');\n fs.writeFileSync(sessionFile, '');\n\n expect(encode(cwd)).toBe(expectedDir);\n expect(fs.existsSync(path.join(encode(cwd), 'session-underscore.jsonl'))).toBe(true);\n });\n });\n});\n"],"names":["fs","os","path","afterEach","beforeEach","describe","expect","it","vi","AgentStatus","ClaudeSessionLocator","batchGetSessionFileBirthtimes","mock","importOriginal","actual","fn","mockedBatchGetSessionFileBirthtimes","tmpDirs","makeTmpDir","dir","mkdtempSync","join","tmpdir","push","makeProcess","overrides","pid","command","cwd","tty","startTime","Date","bindPidFileMatching","locator","tryPidFileMatching","bind","bindProjectDir","getProjectDir","mockReset","splice","rmSync","recursive","force","root","projectsDir","sessionsDir","sessionId","projectDir","sessionFile","mkdirSync","writeFileSync","JSON","stringify","startedAt","getTime","kind","entrypoint","status","waitingFor","matches","matchRunningProcesses","direct","toHaveLength","legacyMatches","toEqual","toMatchObject","pidStatus","WAITING","filePath","resolvedCwd","tmpDir","missing","result","discoverLiveSessions","encodedDir","otherDir","mockFiles","birthtimeMs","mockReturnValue","processes","toBe","toHaveBeenCalledTimes","toHaveBeenCalledWith","not","toHaveBeenCalled","tryMatch","makeProc","writePidFile","writeJsonl","encoded","replace","projDir","type","timestamp","toISOString","proc","fallback","process","staleTime","closeTime","toThrow","missingSessions","proc1","proc2","proc3","map","d","sort","undefined","now","encode","expectedDir","existsSync"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../src/__tests__/providers/claude/ClaudeSessionLocator.test.ts"],"sourcesContent":["import type { MockedFunction } from \"vitest\";\nimport * as fs from \"fs\";\nimport * as os from \"os\";\nimport * as path from \"path\";\nimport { afterEach, beforeEach, describe, expect, it, vi } from \"vitest\";\n\nimport { AgentStatus, type ProcessInfo } from \"../../../adapters/AgentAdapter.js\";\nimport { ClaudeSessionLocator } from \"../../../providers/claude/ClaudeSessionLocator.js\";\nimport { batchGetSessionFileBirthtimes } from \"../../../utils/session.js\";\nimport type { SessionFile } from \"../../../utils/session.js\";\n\nvi.mock(\"../../../utils/session.js\", async (importOriginal) => {\n const actual = (await importOriginal()) as typeof import(\"../../../utils/session.js\");\n return {\n ...actual,\n batchGetSessionFileBirthtimes: vi.fn(),\n };\n});\n\nconst mockedBatchGetSessionFileBirthtimes = batchGetSessionFileBirthtimes as MockedFunction<\n typeof batchGetSessionFileBirthtimes\n>;\n\nconst tmpDirs: string[] = [];\n\nfunction makeTmpDir(): string {\n const dir = fs.mkdtempSync(path.join(os.tmpdir(), \"claude-locator-test-\"));\n tmpDirs.push(dir);\n return dir;\n}\n\nfunction makeProcess(overrides: Partial<ProcessInfo> = {}): ProcessInfo {\n return {\n pid: 123,\n command: \"claude\",\n cwd: \"/repo/my-app\",\n tty: \"ttys001\",\n startTime: new Date(\"2026-08-23T10:00:00.000Z\"),\n ...overrides,\n };\n}\n\ntype PidFileMatching = (processes: ProcessInfo[]) => {\n direct: Array<{ process: ProcessInfo; sessionFile: SessionFile }>;\n fallback: ProcessInfo[];\n};\n\n/** `tryPidFileMatching` is private; tests drive it directly like the sibling adapter suites do. */\nfunction bindPidFileMatching(locator: ClaudeSessionLocator): PidFileMatching {\n return (locator as unknown as { tryPidFileMatching: PidFileMatching }).tryPidFileMatching.bind(\n locator,\n ) as PidFileMatching;\n}\n\n/** `getProjectDir` is private; bound here so the encoding tests read cleanly. */\nfunction bindProjectDir(locator: ClaudeSessionLocator): (cwd: string) => string {\n return (locator as unknown as { getProjectDir: (cwd: string) => string }).getProjectDir.bind(\n locator,\n );\n}\n\ndescribe(\"ClaudeSessionLocator\", () => {\n beforeEach(() => {\n mockedBatchGetSessionFileBirthtimes.mockReset();\n });\n\n afterEach(() => {\n for (const dir of tmpDirs.splice(0)) {\n fs.rmSync(dir, { recursive: true, force: true });\n }\n });\n\n it(\"matches resumed sessions directly and carries live PID status metadata\", () => {\n const root = makeTmpDir();\n const projectsDir = path.join(root, \"projects\");\n const sessionsDir = path.join(root, \"sessions\");\n const cwd = \"/repo/my-app\";\n const sessionId = \"12345678-1234-1234-1234-123456789abc\";\n const projectDir = path.join(projectsDir, \"-repo-my-app\");\n const sessionFile = path.join(projectDir, `${sessionId}.jsonl`);\n fs.mkdirSync(projectDir, { recursive: true });\n fs.mkdirSync(sessionsDir, { recursive: true });\n fs.writeFileSync(sessionFile, \"{}\\n\");\n fs.writeFileSync(\n path.join(sessionsDir, \"123.json\"),\n JSON.stringify({\n pid: 123,\n sessionId,\n cwd,\n startedAt: new Date(\"2026-08-23T10:00:00.000Z\").getTime(),\n kind: \"interactive\",\n entrypoint: \"cli\",\n status: \"waiting\",\n waitingFor: \"approve Read\",\n }),\n );\n\n const locator = new ClaudeSessionLocator({ projectsDir, sessionsDir });\n const matches = locator.matchRunningProcesses([\n makeProcess({ command: `claude --resume ${sessionId}`, cwd }),\n ]);\n\n expect(matches.direct).toHaveLength(1);\n expect(matches.legacyMatches).toEqual([]);\n expect(matches.direct[0]).toMatchObject({\n pidStatus: AgentStatus.WAITING,\n waitingFor: \"approve Read\",\n sessionFile: {\n sessionId,\n filePath: sessionFile,\n projectDir,\n resolvedCwd: cwd,\n },\n });\n });\n describe(\"discoverLiveSessions\", () => {\n let tmpDir: string;\n let projectsDir: string;\n let locator: ClaudeSessionLocator;\n\n beforeEach(() => {\n tmpDir = makeTmpDir();\n projectsDir = path.join(tmpDir, \"projects\");\n locator = new ClaudeSessionLocator({\n projectsDir,\n sessionsDir: path.join(tmpDir, \"sessions\"),\n });\n });\n\n it(\"should return empty when projects dir does not exist\", () => {\n const missing = new ClaudeSessionLocator({\n projectsDir: path.join(tmpDir, \"nonexistent\"),\n sessionsDir: path.join(tmpDir, \"sessions\"),\n });\n\n const result = missing.discoverLiveSessions([\n { pid: 1, command: \"claude\", cwd: \"/test\", tty: \"\" },\n ]);\n expect(result).toEqual([]);\n });\n\n it(\"should scan only directories matching process CWDs\", () => {\n // /my/project → -my-project (encoded dir)\n const encodedDir = path.join(projectsDir, \"-my-project\");\n fs.mkdirSync(encodedDir, { recursive: true });\n\n // Also create another dir that should NOT be scanned\n const otherDir = path.join(projectsDir, \"-other-project\");\n fs.mkdirSync(otherDir, { recursive: true });\n\n const mockFiles: SessionFile[] = [\n {\n sessionId: \"s1\",\n filePath: path.join(encodedDir, \"s1.jsonl\"),\n projectDir: encodedDir,\n birthtimeMs: 1710800324000,\n resolvedCwd: \"\",\n },\n ];\n mockedBatchGetSessionFileBirthtimes.mockReturnValue(mockFiles);\n\n const processes = [{ pid: 1, command: \"claude\", cwd: \"/my/project\", tty: \"\" }];\n\n const result = locator.discoverLiveSessions(processes);\n expect(result).toHaveLength(1);\n expect(result[0].resolvedCwd).toBe(\"/my/project\");\n // batchGetSessionFileBirthtimes called once with all dirs\n expect(mockedBatchGetSessionFileBirthtimes).toHaveBeenCalledTimes(1);\n expect(mockedBatchGetSessionFileBirthtimes).toHaveBeenCalledWith([encodedDir]);\n });\n\n it(\"should return empty when encoded dir does not exist\", () => {\n fs.mkdirSync(projectsDir, { recursive: true });\n\n // Process CWD /test encodes to -test, but that dir doesn't exist\n const result = locator.discoverLiveSessions([\n { pid: 1, command: \"claude\", cwd: \"/test\", tty: \"\" },\n ]);\n expect(result).toEqual([]);\n expect(mockedBatchGetSessionFileBirthtimes).not.toHaveBeenCalled();\n });\n\n it(\"should deduplicate when multiple processes share same CWD\", () => {\n const encodedDir = path.join(projectsDir, \"-my-project\");\n fs.mkdirSync(encodedDir, { recursive: true });\n\n mockedBatchGetSessionFileBirthtimes.mockReturnValue([\n {\n sessionId: \"s1\",\n filePath: path.join(encodedDir, \"s1.jsonl\"),\n projectDir: encodedDir,\n birthtimeMs: 1710800324000,\n resolvedCwd: \"\",\n },\n ]);\n\n const processes = [\n { pid: 1, command: \"claude\", cwd: \"/my/project\", tty: \"\" },\n { pid: 2, command: \"claude\", cwd: \"/my/project\", tty: \"\" },\n ];\n\n const result = locator.discoverLiveSessions(processes);\n // Should only call batch once with deduplicated dir\n expect(mockedBatchGetSessionFileBirthtimes).toHaveBeenCalledTimes(1);\n expect(mockedBatchGetSessionFileBirthtimes).toHaveBeenCalledWith([encodedDir]);\n expect(result).toHaveLength(1);\n });\n\n it(\"should skip processes with empty cwd\", () => {\n fs.mkdirSync(projectsDir, { recursive: true });\n\n const result = locator.discoverLiveSessions([\n { pid: 1, command: \"claude\", cwd: \"\", tty: \"\" },\n ]);\n expect(result).toEqual([]);\n });\n });\n\n describe(\"tryPidFileMatching\", () => {\n let tmpDir: string;\n let sessionsDir: string;\n let projectsDir: string;\n let tryMatch: (processes: ProcessInfo[]) => {\n direct: Array<{ process: ProcessInfo; sessionFile: SessionFile }>;\n fallback: ProcessInfo[];\n };\n\n beforeEach(() => {\n tmpDir = makeTmpDir();\n sessionsDir = path.join(tmpDir, \"sessions\");\n projectsDir = path.join(tmpDir, \"projects\");\n fs.mkdirSync(sessionsDir, { recursive: true });\n tryMatch = bindPidFileMatching(new ClaudeSessionLocator({ projectsDir, sessionsDir }));\n });\n\n const makeProc = (pid: number, cwd = \"/project/test\", startTime?: Date): ProcessInfo => ({\n pid,\n command: \"claude\",\n cwd,\n tty: \"ttys001\",\n startTime,\n });\n\n const writePidFile = (pid: number, sessionId: string, cwd: string, startedAt: number) => {\n fs.writeFileSync(\n path.join(sessionsDir, `${pid}.json`),\n JSON.stringify({ pid, sessionId, cwd, startedAt, kind: \"interactive\", entrypoint: \"cli\" }),\n );\n };\n\n const writeJsonl = (cwd: string, sessionId: string) => {\n const encoded = cwd.replace(/[^a-zA-Z0-9]/g, \"-\");\n const projDir = path.join(projectsDir, encoded);\n fs.mkdirSync(projDir, { recursive: true });\n const filePath = path.join(projDir, `${sessionId}.jsonl`);\n fs.writeFileSync(\n filePath,\n JSON.stringify({ type: \"assistant\", timestamp: new Date().toISOString() }),\n );\n return filePath;\n };\n\n it(\"should return direct match when PID file and JSONL both exist within time tolerance\", () => {\n const startTime = new Date();\n const proc = makeProc(1001, \"/project/test\", startTime);\n writePidFile(1001, \"session-abc\", \"/project/test\", startTime.getTime());\n writeJsonl(\"/project/test\", \"session-abc\");\n\n const { direct, fallback } = tryMatch([proc]);\n\n expect(direct).toHaveLength(1);\n expect(fallback).toHaveLength(0);\n expect(direct[0].sessionFile.sessionId).toBe(\"session-abc\");\n expect(direct[0].sessionFile.resolvedCwd).toBe(\"/project/test\");\n expect(direct[0].process.pid).toBe(1001);\n });\n\n it(\"should fall back when PID file exists but JSONL is missing\", () => {\n const startTime = new Date();\n const proc = makeProc(1002, \"/project/test\", startTime);\n writePidFile(1002, \"nonexistent-session\", \"/project/test\", startTime.getTime());\n // No JSONL file written\n\n const { direct, fallback } = tryMatch([proc]);\n\n expect(direct).toHaveLength(0);\n expect(fallback).toHaveLength(1);\n expect(fallback[0].pid).toBe(1002);\n });\n\n it(\"should fall back when startedAt is stale (>60s from proc.startTime)\", () => {\n const startTime = new Date();\n const staleTime = startTime.getTime() - 90_000; // 90 seconds earlier\n const proc = makeProc(1003, \"/project/test\", startTime);\n writePidFile(1003, \"stale-session\", \"/project/test\", staleTime);\n writeJsonl(\"/project/test\", \"stale-session\");\n\n const { direct, fallback } = tryMatch([proc]);\n\n expect(direct).toHaveLength(0);\n expect(fallback).toHaveLength(1);\n });\n\n it(\"should accept PID file when startedAt is within 60s tolerance\", () => {\n const startTime = new Date();\n const closeTime = startTime.getTime() - 30_000; // 30 seconds earlier — within tolerance\n const proc = makeProc(1004, \"/project/test\", startTime);\n writePidFile(1004, \"close-session\", \"/project/test\", closeTime);\n writeJsonl(\"/project/test\", \"close-session\");\n\n const { direct, fallback } = tryMatch([proc]);\n\n expect(direct).toHaveLength(1);\n expect(fallback).toHaveLength(0);\n });\n\n it(\"should fall back when PID file is absent\", () => {\n const proc = makeProc(1005, \"/project/test\", new Date());\n // No PID file written\n\n const { direct, fallback } = tryMatch([proc]);\n\n expect(direct).toHaveLength(0);\n expect(fallback).toHaveLength(1);\n });\n\n it(\"should fall back when PID file contains malformed JSON\", () => {\n const proc = makeProc(1006, \"/project/test\", new Date());\n fs.writeFileSync(path.join(sessionsDir, \"1006.json\"), \"not valid json {{{\");\n\n expect(() => {\n const { direct, fallback } = tryMatch([proc]);\n expect(direct).toHaveLength(0);\n expect(fallback).toHaveLength(1);\n }).not.toThrow();\n });\n\n it(\"should fall back for all processes when sessions dir does not exist\", () => {\n const missingSessions = bindPidFileMatching(\n new ClaudeSessionLocator({\n projectsDir,\n sessionsDir: path.join(tmpDir, \"nonexistent-sessions\"),\n }),\n );\n const processes = [makeProc(2001, \"/a\", new Date()), makeProc(2002, \"/b\", new Date())];\n\n const { direct, fallback } = missingSessions(processes);\n\n expect(direct).toHaveLength(0);\n expect(fallback).toHaveLength(2);\n });\n\n it(\"should correctly split mixed processes (some with PID files, some without)\", () => {\n const startTime = new Date();\n const proc1 = makeProc(3001, \"/project/one\", startTime);\n const proc2 = makeProc(3002, \"/project/two\", startTime);\n const proc3 = makeProc(3003, \"/project/three\", startTime);\n\n writePidFile(3001, \"session-one\", \"/project/one\", startTime.getTime());\n writeJsonl(\"/project/one\", \"session-one\");\n writePidFile(3003, \"session-three\", \"/project/three\", startTime.getTime());\n writeJsonl(\"/project/three\", \"session-three\");\n // proc2 has no PID file\n\n const { direct, fallback } = tryMatch([proc1, proc2, proc3]);\n\n expect(direct).toHaveLength(2);\n expect(fallback).toHaveLength(1);\n expect(direct.map((d) => d.process.pid).sort()).toEqual([3001, 3003]);\n expect(fallback[0].pid).toBe(3002);\n });\n\n it(\"should skip stale-file check when proc.startTime is undefined\", () => {\n const proc = makeProc(4001, \"/project/test\", undefined); // no startTime\n writePidFile(4001, \"no-time-session\", \"/project/test\", Date.now() - 999_999);\n writeJsonl(\"/project/test\", \"no-time-session\");\n\n const { direct, fallback } = tryMatch([proc]);\n\n // startTime undefined → stale check skipped → direct match\n expect(direct).toHaveLength(1);\n expect(fallback).toHaveLength(0);\n });\n });\n\n describe(\"getProjectDir\", () => {\n let tmpDir: string;\n let projectsDir: string;\n let encode: (cwd: string) => string;\n\n beforeEach(() => {\n tmpDir = makeTmpDir();\n projectsDir = path.join(tmpDir, \"projects\");\n encode = bindProjectDir(\n new ClaudeSessionLocator({\n projectsDir,\n sessionsDir: path.join(tmpDir, \"sessions\"),\n }),\n );\n });\n\n it(\"should replace path separators with hyphens\", () => {\n expect(encode(\"/Users/foo/bar\")).toBe(path.join(projectsDir, \"-Users-foo-bar\"));\n });\n\n it(\"should encode underscores as hyphens (matches Claude Code CLI)\", () => {\n expect(encode(\"/Users/foo/my_project\")).toBe(path.join(projectsDir, \"-Users-foo-my-project\"));\n });\n\n it(\"should encode dots as hyphens\", () => {\n expect(encode(\"/Users/foo/.worktrees/x\")).toBe(\n path.join(projectsDir, \"-Users-foo--worktrees-x\"),\n );\n });\n\n it(\"should collide paths that differ only in non-alphanumeric chars\", () => {\n // The encoding is intentionally lossy — callers must\n // disambiguate via session JSONL contents, not dir name.\n expect(encode(\"/a/b_c\")).toBe(encode(\"/a/b-c\"));\n expect(encode(\"/a/b_c\")).toBe(encode(\"/a/b.c\"));\n });\n\n it(\"should resolve to a real session dir when cwd contains underscores\", () => {\n const cwd = \"/Users/foo/my_project\";\n const expectedDir = path.join(projectsDir, \"-Users-foo-my-project\");\n fs.mkdirSync(expectedDir, { recursive: true });\n const sessionFile = path.join(expectedDir, \"session-underscore.jsonl\");\n fs.writeFileSync(sessionFile, \"\");\n\n expect(encode(cwd)).toBe(expectedDir);\n expect(fs.existsSync(path.join(encode(cwd), \"session-underscore.jsonl\"))).toBe(true);\n });\n });\n});\n"],"names":["fs","os","path","afterEach","beforeEach","describe","expect","it","vi","AgentStatus","ClaudeSessionLocator","batchGetSessionFileBirthtimes","mock","importOriginal","actual","fn","mockedBatchGetSessionFileBirthtimes","tmpDirs","makeTmpDir","dir","mkdtempSync","join","tmpdir","push","makeProcess","overrides","pid","command","cwd","tty","startTime","Date","bindPidFileMatching","locator","tryPidFileMatching","bind","bindProjectDir","getProjectDir","mockReset","splice","rmSync","recursive","force","root","projectsDir","sessionsDir","sessionId","projectDir","sessionFile","mkdirSync","writeFileSync","JSON","stringify","startedAt","getTime","kind","entrypoint","status","waitingFor","matches","matchRunningProcesses","direct","toHaveLength","legacyMatches","toEqual","toMatchObject","pidStatus","WAITING","filePath","resolvedCwd","tmpDir","missing","result","discoverLiveSessions","encodedDir","otherDir","mockFiles","birthtimeMs","mockReturnValue","processes","toBe","toHaveBeenCalledTimes","toHaveBeenCalledWith","not","toHaveBeenCalled","tryMatch","makeProc","writePidFile","writeJsonl","encoded","replace","projDir","type","timestamp","toISOString","proc","fallback","process","staleTime","closeTime","toThrow","missingSessions","proc1","proc2","proc3","map","d","sort","undefined","now","encode","expectedDir","existsSync"],"mappings":"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"}
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import * as fs from "fs";
|
|
2
|
+
import * as os from "os";
|
|
3
|
+
import * as path from "path";
|
|
4
|
+
import { CodexSessionLocator } from "../../../providers/codex/CodexSessionLocator.js";
|
|
5
|
+
import { batchGetSessionFileBirthtimes } from "../../../utils/session.js";
|
|
6
|
+
import { matchProcessesToSessions } from "../../../utils/matching.js";
|
|
7
|
+
vi.mock("../../../utils/session.js", async ()=>{
|
|
8
|
+
const actual = await vi.importActual("../../../utils/session");
|
|
9
|
+
return {
|
|
10
|
+
...actual,
|
|
11
|
+
batchGetSessionFileBirthtimes: vi.fn()
|
|
12
|
+
};
|
|
13
|
+
});
|
|
14
|
+
vi.mock("../../../utils/matching.js", async ()=>{
|
|
15
|
+
const actual = await vi.importActual("../../../utils/matching");
|
|
16
|
+
return {
|
|
17
|
+
...actual,
|
|
18
|
+
matchProcessesToSessions: vi.fn()
|
|
19
|
+
};
|
|
20
|
+
});
|
|
21
|
+
const mockedBatchGetSessionFileBirthtimes = batchGetSessionFileBirthtimes;
|
|
22
|
+
const mockedMatchProcessesToSessions = matchProcessesToSessions;
|
|
23
|
+
describe("CodexSessionLocator", ()=>{
|
|
24
|
+
let tmpDir;
|
|
25
|
+
let sessionsDir;
|
|
26
|
+
let locator;
|
|
27
|
+
beforeEach(()=>{
|
|
28
|
+
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "codex-locator-"));
|
|
29
|
+
sessionsDir = path.join(tmpDir, "sessions");
|
|
30
|
+
locator = new CodexSessionLocator({
|
|
31
|
+
sessionsDir
|
|
32
|
+
});
|
|
33
|
+
mockedBatchGetSessionFileBirthtimes.mockReset();
|
|
34
|
+
mockedMatchProcessesToSessions.mockReset();
|
|
35
|
+
});
|
|
36
|
+
afterEach(()=>{
|
|
37
|
+
fs.rmSync(tmpDir, {
|
|
38
|
+
recursive: true,
|
|
39
|
+
force: true
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
it("discovers live sessions from the process start day window and applies session_meta cwd and timestamp", ()=>{
|
|
43
|
+
const dateDir = path.join(sessionsDir, "2026", "03", "18");
|
|
44
|
+
fs.mkdirSync(dateDir, {
|
|
45
|
+
recursive: true
|
|
46
|
+
});
|
|
47
|
+
const sessionFile = path.join(dateDir, "sess-meta-time.jsonl");
|
|
48
|
+
fs.writeFileSync(sessionFile, JSON.stringify({
|
|
49
|
+
type: "session_meta",
|
|
50
|
+
payload: {
|
|
51
|
+
id: "sess-meta-time",
|
|
52
|
+
timestamp: "2026-03-18T15:00:05.000Z",
|
|
53
|
+
cwd: "/repo-a"
|
|
54
|
+
}
|
|
55
|
+
}));
|
|
56
|
+
mockedBatchGetSessionFileBirthtimes.mockReturnValue([
|
|
57
|
+
{
|
|
58
|
+
sessionId: "sess-meta-time",
|
|
59
|
+
filePath: sessionFile,
|
|
60
|
+
projectDir: dateDir,
|
|
61
|
+
birthtimeMs: new Date("2026-03-18T15:05:30.000Z").getTime(),
|
|
62
|
+
resolvedCwd: ""
|
|
63
|
+
}
|
|
64
|
+
]);
|
|
65
|
+
const { sessions, contentCache } = locator.discoverLiveSessions([
|
|
66
|
+
{
|
|
67
|
+
pid: 1,
|
|
68
|
+
command: "codex",
|
|
69
|
+
cwd: "/repo-a",
|
|
70
|
+
tty: "",
|
|
71
|
+
startTime: new Date("2026-03-18T15:00:00Z")
|
|
72
|
+
}
|
|
73
|
+
]);
|
|
74
|
+
expect(sessions).toHaveLength(1);
|
|
75
|
+
expect(sessions[0]).toMatchObject({
|
|
76
|
+
resolvedCwd: "/repo-a",
|
|
77
|
+
birthtimeMs: new Date("2026-03-18T15:00:05.000Z").getTime()
|
|
78
|
+
});
|
|
79
|
+
expect(contentCache.has(sessionFile)).toBe(true);
|
|
80
|
+
expect(mockedBatchGetSessionFileBirthtimes.mock.calls[0][0]).toEqual([
|
|
81
|
+
dateDir
|
|
82
|
+
]);
|
|
83
|
+
});
|
|
84
|
+
it("matches resumed UUIDv7 sessions directly without legacy matching", ()=>{
|
|
85
|
+
const sessionId = "019eabed-4079-7071-9531-b853ddd9914e";
|
|
86
|
+
const sessionFile = writeSession(sessionId, "2026/06/09");
|
|
87
|
+
const processInfo = {
|
|
88
|
+
pid: 88018,
|
|
89
|
+
command: `codex resume ${sessionId}`,
|
|
90
|
+
cwd: "/repo-a",
|
|
91
|
+
tty: "ttys001",
|
|
92
|
+
startTime: new Date("2026-06-10T12:00:00.000Z")
|
|
93
|
+
};
|
|
94
|
+
const result = locator.matchRunningProcesses([
|
|
95
|
+
processInfo
|
|
96
|
+
]);
|
|
97
|
+
expect(result.direct).toHaveLength(1);
|
|
98
|
+
expect(result.direct[0]).toMatchObject({
|
|
99
|
+
process: processInfo,
|
|
100
|
+
sessionFile: {
|
|
101
|
+
sessionId,
|
|
102
|
+
filePath: sessionFile,
|
|
103
|
+
resolvedCwd: "/repo-a"
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
expect(result.fallback).toEqual([]);
|
|
107
|
+
expect(mockedBatchGetSessionFileBirthtimes).not.toHaveBeenCalled();
|
|
108
|
+
expect(mockedMatchProcessesToSessions).not.toHaveBeenCalled();
|
|
109
|
+
});
|
|
110
|
+
it("falls back to walking all session files for non-time-sortable resume ids", ()=>{
|
|
111
|
+
const sessionId = "aaaaaaaa-bbbb-4ccc-dddd-eeeeeeeeeeee";
|
|
112
|
+
const sessionFile = writeSession(sessionId, "2026/01/02");
|
|
113
|
+
const result = locator.matchRunningProcesses([
|
|
114
|
+
{
|
|
115
|
+
pid: 42,
|
|
116
|
+
command: `codex resume ${sessionId}`,
|
|
117
|
+
cwd: "/repo-a",
|
|
118
|
+
tty: "ttys001"
|
|
119
|
+
}
|
|
120
|
+
]);
|
|
121
|
+
expect(result.direct[0].sessionFile.filePath).toBe(sessionFile);
|
|
122
|
+
});
|
|
123
|
+
it("passes unmatched processes and discovered sessions to legacy matching", ()=>{
|
|
124
|
+
const dateDir = path.join(sessionsDir, "2026", "03", "18");
|
|
125
|
+
fs.mkdirSync(dateDir, {
|
|
126
|
+
recursive: true
|
|
127
|
+
});
|
|
128
|
+
const candidate = {
|
|
129
|
+
sessionId: "sess",
|
|
130
|
+
filePath: path.join(dateDir, "sess.jsonl"),
|
|
131
|
+
projectDir: dateDir,
|
|
132
|
+
birthtimeMs: new Date("2026-03-18T15:00:05Z").getTime(),
|
|
133
|
+
resolvedCwd: ""
|
|
134
|
+
};
|
|
135
|
+
fs.writeFileSync(candidate.filePath, JSON.stringify({
|
|
136
|
+
type: "session_meta",
|
|
137
|
+
payload: {
|
|
138
|
+
id: "sess",
|
|
139
|
+
cwd: "/repo-a",
|
|
140
|
+
timestamp: "2026-03-18T15:00:05Z"
|
|
141
|
+
}
|
|
142
|
+
}));
|
|
143
|
+
const processInfo = {
|
|
144
|
+
pid: 100,
|
|
145
|
+
command: "codex",
|
|
146
|
+
cwd: "/repo-a",
|
|
147
|
+
tty: "ttys001",
|
|
148
|
+
startTime: new Date("2026-03-18T15:00:00Z")
|
|
149
|
+
};
|
|
150
|
+
const legacyMatch = {
|
|
151
|
+
process: processInfo,
|
|
152
|
+
session: {
|
|
153
|
+
...candidate,
|
|
154
|
+
resolvedCwd: "/repo-a"
|
|
155
|
+
},
|
|
156
|
+
deltaMs: 5000
|
|
157
|
+
};
|
|
158
|
+
mockedBatchGetSessionFileBirthtimes.mockReturnValue([
|
|
159
|
+
candidate
|
|
160
|
+
]);
|
|
161
|
+
mockedMatchProcessesToSessions.mockReturnValue([
|
|
162
|
+
legacyMatch
|
|
163
|
+
]);
|
|
164
|
+
const result = locator.matchRunningProcesses([
|
|
165
|
+
processInfo
|
|
166
|
+
]);
|
|
167
|
+
expect(result.direct).toEqual([]);
|
|
168
|
+
expect(result.fallback).toEqual([
|
|
169
|
+
processInfo
|
|
170
|
+
]);
|
|
171
|
+
expect(result.legacyMatches).toEqual([
|
|
172
|
+
legacyMatch
|
|
173
|
+
]);
|
|
174
|
+
expect(result.contentCache.has(candidate.filePath)).toBe(true);
|
|
175
|
+
});
|
|
176
|
+
function writeSession(sessionId, day) {
|
|
177
|
+
const dateDir = path.join(sessionsDir, ...day.split("/"));
|
|
178
|
+
fs.mkdirSync(dateDir, {
|
|
179
|
+
recursive: true
|
|
180
|
+
});
|
|
181
|
+
const sessionFile = path.join(dateDir, `${sessionId}.jsonl`);
|
|
182
|
+
fs.writeFileSync(sessionFile, JSON.stringify({
|
|
183
|
+
type: "session_meta",
|
|
184
|
+
payload: {
|
|
185
|
+
id: sessionId,
|
|
186
|
+
timestamp: "2026-03-18T15:00:05.000Z",
|
|
187
|
+
cwd: "/repo-a"
|
|
188
|
+
}
|
|
189
|
+
}));
|
|
190
|
+
return sessionFile;
|
|
191
|
+
}
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
//# sourceMappingURL=CodexSessionLocator.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../src/__tests__/providers/codex/CodexSessionLocator.test.ts"],"sourcesContent":["import type { MockedFunction } from \"vitest\";\nimport * as fs from \"fs\";\nimport * as os from \"os\";\nimport * as path from \"path\";\nimport type { ProcessInfo } from \"../../../adapters/AgentAdapter.js\";\nimport { CodexSessionLocator } from \"../../../providers/codex/CodexSessionLocator.js\";\nimport { batchGetSessionFileBirthtimes, type SessionFile } from \"../../../utils/session.js\";\nimport { matchProcessesToSessions, type MatchResult } from \"../../../utils/matching.js\";\n\nvi.mock(\"../../../utils/session.js\", async () => {\n const actual = (await vi.importActual(\n \"../../../utils/session\",\n )) as typeof import(\"../../../utils/session\");\n return {\n ...actual,\n batchGetSessionFileBirthtimes: vi.fn(),\n };\n});\n\nvi.mock(\"../../../utils/matching.js\", async () => {\n const actual = (await vi.importActual(\n \"../../../utils/matching\",\n )) as typeof import(\"../../../utils/matching\");\n return {\n ...actual,\n matchProcessesToSessions: vi.fn(),\n };\n});\n\nconst mockedBatchGetSessionFileBirthtimes = batchGetSessionFileBirthtimes as MockedFunction<\n typeof batchGetSessionFileBirthtimes\n>;\nconst mockedMatchProcessesToSessions = matchProcessesToSessions as MockedFunction<\n typeof matchProcessesToSessions\n>;\n\ndescribe(\"CodexSessionLocator\", () => {\n let tmpDir: string;\n let sessionsDir: string;\n let locator: CodexSessionLocator;\n\n beforeEach(() => {\n tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), \"codex-locator-\"));\n sessionsDir = path.join(tmpDir, \"sessions\");\n locator = new CodexSessionLocator({ sessionsDir });\n mockedBatchGetSessionFileBirthtimes.mockReset();\n mockedMatchProcessesToSessions.mockReset();\n });\n\n afterEach(() => {\n fs.rmSync(tmpDir, { recursive: true, force: true });\n });\n\n it(\"discovers live sessions from the process start day window and applies session_meta cwd and timestamp\", () => {\n const dateDir = path.join(sessionsDir, \"2026\", \"03\", \"18\");\n fs.mkdirSync(dateDir, { recursive: true });\n const sessionFile = path.join(dateDir, \"sess-meta-time.jsonl\");\n fs.writeFileSync(\n sessionFile,\n JSON.stringify({\n type: \"session_meta\",\n payload: { id: \"sess-meta-time\", timestamp: \"2026-03-18T15:00:05.000Z\", cwd: \"/repo-a\" },\n }),\n );\n mockedBatchGetSessionFileBirthtimes.mockReturnValue([\n {\n sessionId: \"sess-meta-time\",\n filePath: sessionFile,\n projectDir: dateDir,\n birthtimeMs: new Date(\"2026-03-18T15:05:30.000Z\").getTime(),\n resolvedCwd: \"\",\n },\n ]);\n\n const { sessions, contentCache } = locator.discoverLiveSessions([\n {\n pid: 1,\n command: \"codex\",\n cwd: \"/repo-a\",\n tty: \"\",\n startTime: new Date(\"2026-03-18T15:00:00Z\"),\n },\n ]);\n\n expect(sessions).toHaveLength(1);\n expect(sessions[0]).toMatchObject({\n resolvedCwd: \"/repo-a\",\n birthtimeMs: new Date(\"2026-03-18T15:00:05.000Z\").getTime(),\n });\n expect(contentCache.has(sessionFile)).toBe(true);\n expect(mockedBatchGetSessionFileBirthtimes.mock.calls[0][0]).toEqual([dateDir]);\n });\n\n it(\"matches resumed UUIDv7 sessions directly without legacy matching\", () => {\n const sessionId = \"019eabed-4079-7071-9531-b853ddd9914e\";\n const sessionFile = writeSession(sessionId, \"2026/06/09\");\n const processInfo: ProcessInfo = {\n pid: 88018,\n command: `codex resume ${sessionId}`,\n cwd: \"/repo-a\",\n tty: \"ttys001\",\n startTime: new Date(\"2026-06-10T12:00:00.000Z\"),\n };\n\n const result = locator.matchRunningProcesses([processInfo]);\n\n expect(result.direct).toHaveLength(1);\n expect(result.direct[0]).toMatchObject({\n process: processInfo,\n sessionFile: { sessionId, filePath: sessionFile, resolvedCwd: \"/repo-a\" },\n });\n expect(result.fallback).toEqual([]);\n expect(mockedBatchGetSessionFileBirthtimes).not.toHaveBeenCalled();\n expect(mockedMatchProcessesToSessions).not.toHaveBeenCalled();\n });\n\n it(\"falls back to walking all session files for non-time-sortable resume ids\", () => {\n const sessionId = \"aaaaaaaa-bbbb-4ccc-dddd-eeeeeeeeeeee\";\n const sessionFile = writeSession(sessionId, \"2026/01/02\");\n\n const result = locator.matchRunningProcesses([\n { pid: 42, command: `codex resume ${sessionId}`, cwd: \"/repo-a\", tty: \"ttys001\" },\n ]);\n\n expect(result.direct[0].sessionFile.filePath).toBe(sessionFile);\n });\n\n it(\"passes unmatched processes and discovered sessions to legacy matching\", () => {\n const dateDir = path.join(sessionsDir, \"2026\", \"03\", \"18\");\n fs.mkdirSync(dateDir, { recursive: true });\n const candidate: SessionFile = {\n sessionId: \"sess\",\n filePath: path.join(dateDir, \"sess.jsonl\"),\n projectDir: dateDir,\n birthtimeMs: new Date(\"2026-03-18T15:00:05Z\").getTime(),\n resolvedCwd: \"\",\n };\n fs.writeFileSync(\n candidate.filePath,\n JSON.stringify({\n type: \"session_meta\",\n payload: { id: \"sess\", cwd: \"/repo-a\", timestamp: \"2026-03-18T15:00:05Z\" },\n }),\n );\n const processInfo: ProcessInfo = {\n pid: 100,\n command: \"codex\",\n cwd: \"/repo-a\",\n tty: \"ttys001\",\n startTime: new Date(\"2026-03-18T15:00:00Z\"),\n };\n const legacyMatch: MatchResult = {\n process: processInfo,\n session: { ...candidate, resolvedCwd: \"/repo-a\" },\n deltaMs: 5000,\n };\n\n mockedBatchGetSessionFileBirthtimes.mockReturnValue([candidate]);\n mockedMatchProcessesToSessions.mockReturnValue([legacyMatch]);\n\n const result = locator.matchRunningProcesses([processInfo]);\n\n expect(result.direct).toEqual([]);\n expect(result.fallback).toEqual([processInfo]);\n expect(result.legacyMatches).toEqual([legacyMatch]);\n expect(result.contentCache.has(candidate.filePath)).toBe(true);\n });\n\n function writeSession(sessionId: string, day: string): string {\n const dateDir = path.join(sessionsDir, ...day.split(\"/\"));\n fs.mkdirSync(dateDir, { recursive: true });\n const sessionFile = path.join(dateDir, `${sessionId}.jsonl`);\n fs.writeFileSync(\n sessionFile,\n JSON.stringify({\n type: \"session_meta\",\n payload: { id: sessionId, timestamp: \"2026-03-18T15:00:05.000Z\", cwd: \"/repo-a\" },\n }),\n );\n return sessionFile;\n }\n});\n"],"names":["fs","os","path","CodexSessionLocator","batchGetSessionFileBirthtimes","matchProcessesToSessions","vi","mock","actual","importActual","fn","mockedBatchGetSessionFileBirthtimes","mockedMatchProcessesToSessions","describe","tmpDir","sessionsDir","locator","beforeEach","mkdtempSync","join","tmpdir","mockReset","afterEach","rmSync","recursive","force","it","dateDir","mkdirSync","sessionFile","writeFileSync","JSON","stringify","type","payload","id","timestamp","cwd","mockReturnValue","sessionId","filePath","projectDir","birthtimeMs","Date","getTime","resolvedCwd","sessions","contentCache","discoverLiveSessions","pid","command","tty","startTime","expect","toHaveLength","toMatchObject","has","toBe","calls","toEqual","writeSession","processInfo","result","matchRunningProcesses","direct","process","fallback","not","toHaveBeenCalled","candidate","legacyMatch","session","deltaMs","legacyMatches","day","split"],"mappings":"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"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import * as fs from "fs";
|
|
2
|
+
import * as os from "os";
|
|
3
|
+
import * as path from "path";
|
|
4
|
+
import { CodexSessionMapping } from "../../../providers/codex/CodexSessionMapping.js";
|
|
5
|
+
describe("CodexSessionMapping", ()=>{
|
|
6
|
+
let tmpDir;
|
|
7
|
+
let sessionsDir;
|
|
8
|
+
let mappingPath;
|
|
9
|
+
let processInfo;
|
|
10
|
+
beforeEach(()=>{
|
|
11
|
+
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "codex-mapping-"));
|
|
12
|
+
sessionsDir = path.join(tmpDir, ".codex", "sessions");
|
|
13
|
+
mappingPath = path.join(tmpDir, ".codex", "ai-devkit", "sessions.json");
|
|
14
|
+
processInfo = {
|
|
15
|
+
pid: 5151,
|
|
16
|
+
command: "codex",
|
|
17
|
+
cwd: "/repo",
|
|
18
|
+
tty: "ttys001"
|
|
19
|
+
};
|
|
20
|
+
});
|
|
21
|
+
afterEach(()=>{
|
|
22
|
+
fs.rmSync(tmpDir, {
|
|
23
|
+
recursive: true,
|
|
24
|
+
force: true
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
it("matches a process to an existing trusted session file", ()=>{
|
|
28
|
+
const sessionFile = path.join(sessionsDir, "2026", "06", "26", "session.jsonl");
|
|
29
|
+
fs.mkdirSync(path.dirname(sessionFile), {
|
|
30
|
+
recursive: true
|
|
31
|
+
});
|
|
32
|
+
fs.mkdirSync(path.dirname(mappingPath), {
|
|
33
|
+
recursive: true
|
|
34
|
+
});
|
|
35
|
+
fs.writeFileSync(sessionFile, "");
|
|
36
|
+
fs.writeFileSync(mappingPath, JSON.stringify({
|
|
37
|
+
5151: sessionFile
|
|
38
|
+
}));
|
|
39
|
+
expect(createMapping().match([
|
|
40
|
+
processInfo
|
|
41
|
+
])).toEqual({
|
|
42
|
+
matches: [
|
|
43
|
+
{
|
|
44
|
+
process: processInfo,
|
|
45
|
+
filePath: sessionFile
|
|
46
|
+
}
|
|
47
|
+
],
|
|
48
|
+
fallback: []
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
it("falls back for malformed mappings, missing files, invalid pids, and untrusted paths", ()=>{
|
|
52
|
+
fs.mkdirSync(path.dirname(mappingPath), {
|
|
53
|
+
recursive: true
|
|
54
|
+
});
|
|
55
|
+
fs.writeFileSync(mappingPath, JSON.stringify({
|
|
56
|
+
invalid: path.join(sessionsDir, "ignored.jsonl"),
|
|
57
|
+
5151: path.join(tmpDir, "outside.jsonl"),
|
|
58
|
+
9999: path.join(sessionsDir, "missing.jsonl")
|
|
59
|
+
}));
|
|
60
|
+
expect(createMapping().match([
|
|
61
|
+
processInfo
|
|
62
|
+
])).toEqual({
|
|
63
|
+
matches: [],
|
|
64
|
+
fallback: [
|
|
65
|
+
processInfo
|
|
66
|
+
]
|
|
67
|
+
});
|
|
68
|
+
fs.writeFileSync(mappingPath, "{not-json");
|
|
69
|
+
expect(createMapping().match([
|
|
70
|
+
processInfo
|
|
71
|
+
])).toEqual({
|
|
72
|
+
matches: [],
|
|
73
|
+
fallback: [
|
|
74
|
+
processInfo
|
|
75
|
+
]
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
function createMapping() {
|
|
79
|
+
return new CodexSessionMapping({
|
|
80
|
+
mappingPath,
|
|
81
|
+
sessionsDir
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
//# sourceMappingURL=CodexSessionMapping.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../src/__tests__/providers/codex/CodexSessionMapping.test.ts"],"sourcesContent":["import * as fs from \"fs\";\nimport * as os from \"os\";\nimport * as path from \"path\";\nimport type { ProcessInfo } from \"../../../adapters/AgentAdapter.js\";\nimport { CodexSessionMapping } from \"../../../providers/codex/CodexSessionMapping.js\";\n\ndescribe(\"CodexSessionMapping\", () => {\n let tmpDir: string;\n let sessionsDir: string;\n let mappingPath: string;\n let processInfo: ProcessInfo;\n\n beforeEach(() => {\n tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), \"codex-mapping-\"));\n sessionsDir = path.join(tmpDir, \".codex\", \"sessions\");\n mappingPath = path.join(tmpDir, \".codex\", \"ai-devkit\", \"sessions.json\");\n processInfo = { pid: 5151, command: \"codex\", cwd: \"/repo\", tty: \"ttys001\" };\n });\n\n afterEach(() => {\n fs.rmSync(tmpDir, { recursive: true, force: true });\n });\n\n it(\"matches a process to an existing trusted session file\", () => {\n const sessionFile = path.join(sessionsDir, \"2026\", \"06\", \"26\", \"session.jsonl\");\n fs.mkdirSync(path.dirname(sessionFile), { recursive: true });\n fs.mkdirSync(path.dirname(mappingPath), { recursive: true });\n fs.writeFileSync(sessionFile, \"\");\n fs.writeFileSync(mappingPath, JSON.stringify({ 5151: sessionFile }));\n\n expect(createMapping().match([processInfo])).toEqual({\n matches: [{ process: processInfo, filePath: sessionFile }],\n fallback: [],\n });\n });\n\n it(\"falls back for malformed mappings, missing files, invalid pids, and untrusted paths\", () => {\n fs.mkdirSync(path.dirname(mappingPath), { recursive: true });\n fs.writeFileSync(\n mappingPath,\n JSON.stringify({\n invalid: path.join(sessionsDir, \"ignored.jsonl\"),\n 5151: path.join(tmpDir, \"outside.jsonl\"),\n 9999: path.join(sessionsDir, \"missing.jsonl\"),\n }),\n );\n\n expect(createMapping().match([processInfo])).toEqual({\n matches: [],\n fallback: [processInfo],\n });\n\n fs.writeFileSync(mappingPath, \"{not-json\");\n expect(createMapping().match([processInfo])).toEqual({\n matches: [],\n fallback: [processInfo],\n });\n });\n\n function createMapping(): CodexSessionMapping {\n return new CodexSessionMapping({ mappingPath, sessionsDir });\n }\n});\n"],"names":["fs","os","path","CodexSessionMapping","describe","tmpDir","sessionsDir","mappingPath","processInfo","beforeEach","mkdtempSync","join","tmpdir","pid","command","cwd","tty","afterEach","rmSync","recursive","force","it","sessionFile","mkdirSync","dirname","writeFileSync","JSON","stringify","expect","createMapping","match","toEqual","matches","process","filePath","fallback","invalid"],"mappings":"AAAA,YAAYA,QAAQ,KAAK;AACzB,YAAYC,QAAQ,KAAK;AACzB,YAAYC,UAAU,OAAO;AAE7B,SAASC,mBAAmB,QAAQ,kDAAkD;AAEtFC,SAAS,uBAAuB;IAC9B,IAAIC;IACJ,IAAIC;IACJ,IAAIC;IACJ,IAAIC;IAEJC,WAAW;QACTJ,SAASL,GAAGU,WAAW,CAACR,KAAKS,IAAI,CAACV,GAAGW,MAAM,IAAI;QAC/CN,cAAcJ,KAAKS,IAAI,CAACN,QAAQ,UAAU;QAC1CE,cAAcL,KAAKS,IAAI,CAACN,QAAQ,UAAU,aAAa;QACvDG,cAAc;YAAEK,KAAK;YAAMC,SAAS;YAASC,KAAK;YAASC,KAAK;QAAU;IAC5E;IAEAC,UAAU;QACRjB,GAAGkB,MAAM,CAACb,QAAQ;YAAEc,WAAW;YAAMC,OAAO;QAAK;IACnD;IAEAC,GAAG,yDAAyD;QAC1D,MAAMC,cAAcpB,KAAKS,IAAI,CAACL,aAAa,QAAQ,MAAM,MAAM;QAC/DN,GAAGuB,SAAS,CAACrB,KAAKsB,OAAO,CAACF,cAAc;YAAEH,WAAW;QAAK;QAC1DnB,GAAGuB,SAAS,CAACrB,KAAKsB,OAAO,CAACjB,cAAc;YAAEY,WAAW;QAAK;QAC1DnB,GAAGyB,aAAa,CAACH,aAAa;QAC9BtB,GAAGyB,aAAa,CAAClB,aAAamB,KAAKC,SAAS,CAAC;YAAE,MAAML;QAAY;QAEjEM,OAAOC,gBAAgBC,KAAK,CAAC;YAACtB;SAAY,GAAGuB,OAAO,CAAC;YACnDC,SAAS;gBAAC;oBAAEC,SAASzB;oBAAa0B,UAAUZ;gBAAY;aAAE;YAC1Da,UAAU,EAAE;QACd;IACF;IAEAd,GAAG,uFAAuF;QACxFrB,GAAGuB,SAAS,CAACrB,KAAKsB,OAAO,CAACjB,cAAc;YAAEY,WAAW;QAAK;QAC1DnB,GAAGyB,aAAa,CACdlB,aACAmB,KAAKC,SAAS,CAAC;YACbS,SAASlC,KAAKS,IAAI,CAACL,aAAa;YAChC,MAAMJ,KAAKS,IAAI,CAACN,QAAQ;YACxB,MAAMH,KAAKS,IAAI,CAACL,aAAa;QAC/B;QAGFsB,OAAOC,gBAAgBC,KAAK,CAAC;YAACtB;SAAY,GAAGuB,OAAO,CAAC;YACnDC,SAAS,EAAE;YACXG,UAAU;gBAAC3B;aAAY;QACzB;QAEAR,GAAGyB,aAAa,CAAClB,aAAa;QAC9BqB,OAAOC,gBAAgBC,KAAK,CAAC;YAACtB;SAAY,GAAGuB,OAAO,CAAC;YACnDC,SAAS,EAAE;YACXG,UAAU;gBAAC3B;aAAY;QACzB;IACF;IAEA,SAASqB;QACP,OAAO,IAAI1B,oBAAoB;YAAEI;YAAaD;QAAY;IAC5D;AACF"}
|