@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__/utils/AgentRegistry.test.ts"],"sourcesContent":["import fs from 'fs';\nimport os from 'os';\nimport path from 'path';\nimport Database from 'better-sqlite3';\nimport { AgentRegistry, RenameNotFoundError, RenameConflictError, type RegistryEntry } from '../../utils/AgentRegistry.js';\n\nfunction makeEntry(over: Partial<RegistryEntry> = {}): RegistryEntry {\n return {\n name: 'agent1',\n type: 'claude',\n pid: process.pid,\n tmuxSession: 'agent1',\n cwd: '/tmp',\n startedAt: '2026-05-30T00:00:00.000Z',\n sessionId: 'sid-1',\n sessionFilePath: '/tmp/session.jsonl',\n pinned: false,\n ...over,\n };\n}\n\ndescribe('AgentRegistry', () => {\n let tmpDir: string;\n let regPath: string;\n let registry: AgentRegistry;\n\n beforeEach(() => {\n tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'agent-registry-'));\n regPath = path.join(tmpDir, 'nested', 'agents.json');\n registry = new AgentRegistry(regPath);\n });\n\n afterEach(() => {\n vi.restoreAllMocks();\n fs.rmSync(tmpDir, { recursive: true, force: true });\n });\n\n describe('register', () => {\n it('creates the SQLite database and parent directory if missing', () => {\n registry.register(makeEntry());\n expect(fs.existsSync(regPath.replace(/\\.json$/, '.db'))).toBe(true);\n expect(registry.list()[0].name).toBe('agent1');\n });\n\n it('appends a new entry when name is unique', () => {\n registry.register(makeEntry({ name: 'a' }));\n registry.register(makeEntry({ name: 'b', pid: process.ppid }));\n expect(registry.list()).toHaveLength(2);\n });\n\n it('upserts in place when type and pid already exist', () => {\n registry.register(makeEntry({ name: 'a', pid: process.pid }));\n registry.register(makeEntry({ name: 'fallback', pid: process.pid, tmuxSession: '' }));\n const all = registry.list();\n expect(all).toHaveLength(1);\n expect(all[0].pid).toBe(process.pid);\n expect(all[0].name).toBe('a');\n });\n\n it('does not write through the legacy fixed .tmp path', () => {\n registry.register(makeEntry());\n expect(fs.existsSync(`${regPath}.tmp`)).toBe(false);\n });\n\n it('persists session fields', () => {\n registry.register(makeEntry({ sessionId: 'sid-xyz', sessionFilePath: '/foo/bar.jsonl' }));\n const saved = registry.list()[0];\n expect(saved.sessionId).toBe('sid-xyz');\n expect(saved.sessionFilePath).toBe('/foo/bar.jsonl');\n });\n\n it('preserves existing tmuxSession when incoming is empty string', () => {\n registry.register(makeEntry({ name: 'a', tmuxSession: 'pinned' }));\n registry.register(makeEntry({ name: 'fallback', tmuxSession: '', pid: process.pid }));\n const saved = registry.lookup('a');\n expect(saved?.tmuxSession).toBe('pinned');\n expect(saved?.pid).toBe(process.pid);\n });\n\n it('lets a managed start entry replace a generated fallback for the same pid', () => {\n registry.register(makeEntry({ name: `ai-devkit-${process.pid}`, tmuxSession: '' }));\n registry.register(makeEntry({ name: 'custom-name', tmuxSession: 'custom-name' }));\n expect(registry.lookup('custom-name')?.tmuxSession).toBe('custom-name');\n expect(registry.lookup(`ai-devkit-${process.pid}`)).toBeNull();\n expect(registry.list()).toHaveLength(1);\n });\n\n it('preserves an existing name conflict when its probe fails with EPERM', () => {\n registry.register(makeEntry({ name: 'claimed-name', pid: process.pid }));\n vi.spyOn(process, 'kill').mockImplementation(() => {\n throw Object.assign(new Error('operation not permitted'), { code: 'EPERM' });\n });\n\n expect(() => registry.register(makeEntry({\n name: 'claimed-name',\n pid: process.pid + 1,\n }))).toThrow();\n expect(registry.lookup('claimed-name')?.pid).toBe(process.pid);\n });\n });\n\n describe('registerBatch', () => {\n it('is a no-op on empty array', () => {\n registry.registerBatch([]);\n expect(fs.existsSync(regPath)).toBe(false);\n });\n\n it('upserts multiple entries in a single batch', () => {\n registry.registerBatch([\n makeEntry({ name: 'a' }),\n makeEntry({ name: 'b', pid: process.pid + 1 }),\n makeEntry({ name: 'c', pid: process.pid + 2 }),\n ]);\n expect(registry.list()).toHaveLength(3);\n });\n\n it('applies the tmuxSession merge per entry', () => {\n registry.register(makeEntry({ name: 'a', tmuxSession: 'pinned' }));\n registry.registerBatch([\n makeEntry({ name: 'fallback', tmuxSession: '', pid: process.pid }),\n makeEntry({ name: 'b', tmuxSession: '', pid: process.pid + 1 }),\n ]);\n expect(registry.lookup('a')?.tmuxSession).toBe('pinned');\n expect(registry.lookup('a')?.pid).toBe(process.pid);\n expect(registry.lookup('b')?.tmuxSession).toBe('');\n });\n\n it('handles concurrent registry instances without duplicate pid rows', () => {\n const other = new AgentRegistry(regPath);\n registry.register(makeEntry({ name: `ai-devkit-${process.pid}`, tmuxSession: '' }));\n other.register(makeEntry({ name: 'custom-name', tmuxSession: 'custom-name' }));\n registry.register(makeEntry({ name: `ai-devkit-${process.pid}`, tmuxSession: '' }));\n\n expect(registry.list()).toHaveLength(1);\n expect(registry.lookup('custom-name')?.pid).toBe(process.pid);\n });\n\n it('cleans up a cross-type row when its pid has been reused', () => {\n registry.register(makeEntry({ name: 'old-claude', type: 'claude', pid: process.pid }));\n\n registry.register(makeEntry({\n name: 'new-codex',\n type: 'codex',\n pid: process.pid,\n tmuxSession: '',\n }));\n\n expect(registry.lookup('old-claude')).toBeNull();\n expect(registry.lookup('new-codex')).toMatchObject({ type: 'codex', pid: process.pid });\n expect(registry.list()).toHaveLength(1);\n });\n\n it('rolls back the whole batch when a live name conflict rejects one entry', () => {\n registry.register(makeEntry({ name: 'taken', pid: process.pid }));\n\n expect(() => registry.registerBatch([\n makeEntry({ name: 'fresh', pid: 999998 }),\n makeEntry({ name: 'taken', type: 'codex', pid: 999997 }),\n ])).toThrow(/UNIQUE constraint failed/);\n\n expect(registry.lookup('fresh')).toBeNull();\n expect(registry.lookup('taken')?.pid).toBe(process.pid);\n });\n });\n\n describe('lookup', () => {\n it('returns null when name not found', () => {\n expect(registry.lookup('missing')).toBeNull();\n });\n\n it('returns the entry when name matches', () => {\n registry.register(makeEntry({ name: 'a' }));\n expect(registry.lookup('a')?.name).toBe('a');\n });\n });\n\n describe('pinning', () => {\n it('defaults new rows to unpinned and toggles the persisted state', () => {\n registry.register(makeEntry());\n\n expect(registry.lookup('agent1')?.pinned).toBe(false);\n expect(registry.togglePin('claude', process.pid)).toBe(true);\n expect(registry.lookup('agent1')?.pinned).toBe(true);\n expect(registry.togglePin('claude', process.pid)).toBe(false);\n expect(registry.lookup('agent1')?.pinned).toBe(false);\n });\n\n it('updates existing recency when toggled', () => {\n let now = new Date('2026-08-16T10:00:00.000Z');\n const clocked = new AgentRegistry(regPath, { now: () => now });\n clocked.register(makeEntry());\n now = new Date('2026-08-16T10:01:00.000Z');\n\n clocked.togglePin('claude', process.pid);\n\n expect(clocked.lookup('agent1')?.updatedAt).toBe(now.toISOString());\n const db = new Database(regPath.replace(/\\.json$/, '.db'), { readonly: true });\n const row = db.prepare('SELECT updated_at FROM agents WHERE type = ? AND pid = ?')\n .get('claude', process.pid) as { updated_at: string };\n db.close();\n expect(row.updated_at).toBe(now.toISOString());\n });\n\n it('returns null when the process row has disappeared', () => {\n expect(registry.togglePin('claude', 999999)).toBeNull();\n });\n\n it('preserves a pin when poll registration updates the row', () => {\n registry.register(makeEntry({ sessionId: 'before' }));\n registry.togglePin('claude', process.pid);\n\n registry.register(makeEntry({ sessionId: 'after' }));\n\n expect(registry.lookup('agent1')).toMatchObject({ sessionId: 'after', pinned: true });\n });\n\n it('preserves a pin through rename', () => {\n registry.register(makeEntry({ name: 'before' }));\n registry.togglePin('claude', process.pid);\n\n registry.rename('before', 'after');\n\n expect(registry.lookup('after')?.pinned).toBe(true);\n });\n\n it('removes the pin with a pruned process row', () => {\n registry.register(makeEntry({ pid: 999999 }));\n registry.togglePin('claude', 999999);\n\n registry.prune();\n\n expect(registry.lookup('agent1')).toBeNull();\n });\n\n it('reports a clear error when a readonly registry toggles a pin', () => {\n registry.register(makeEntry());\n const readonlyRegistry = new AgentRegistry(regPath, { readonly: true });\n\n expect(() => readonlyRegistry.togglePin('claude', process.pid)).toThrow(/readonly/i);\n });\n });\n\n describe('list', () => {\n it('returns empty array when database does not contain entries', () => {\n expect(registry.list()).toEqual([]);\n });\n\n it('ignores existing legacy agents.json entries', () => {\n const legacyEntry = makeEntry({ name: 'legacy', tmuxSession: 'legacy' });\n fs.mkdirSync(path.dirname(regPath), { recursive: true });\n fs.writeFileSync(regPath, JSON.stringify({ entries: [legacyEntry] }), 'utf8');\n\n const legacyRegistry = new AgentRegistry(regPath);\n\n expect(legacyRegistry.lookup('legacy')).toBeNull();\n expect(legacyRegistry.list()).toEqual([]);\n expect(fs.existsSync(regPath.replace(/\\.json$/, '.db'))).toBe(true);\n });\n });\n\n describe('isAlive', () => {\n it('returns true for the current process', () => {\n expect(registry.isAlive(makeEntry({ pid: process.pid }))).toBe(true);\n });\n\n it('returns false for a PID that does not exist', () => {\n expect(registry.isAlive(makeEntry({ pid: 999999 }))).toBe(false);\n });\n\n it('returns true when the process probe is forbidden with EPERM', () => {\n vi.spyOn(process, 'kill').mockImplementation(() => {\n throw Object.assign(new Error('operation not permitted'), { code: 'EPERM' });\n });\n\n expect(registry.isAlive(makeEntry())).toBe(true);\n });\n\n it('returns false when the process probe reports ESRCH', () => {\n vi.spyOn(process, 'kill').mockImplementation(() => {\n throw Object.assign(new Error('no such process'), { code: 'ESRCH' });\n });\n\n expect(registry.isAlive(makeEntry())).toBe(false);\n });\n\n it('returns true when the process probe fails without a definitive error code', () => {\n vi.spyOn(process, 'kill').mockImplementation(() => {\n throw new Error('indeterminate probe failure');\n });\n\n expect(registry.isAlive(makeEntry())).toBe(true);\n });\n });\n\n describe('prune', () => {\n it('removes entries whose PIDs are dead', () => {\n registry.register(makeEntry({ name: 'alive', pid: process.pid }));\n registry.register(makeEntry({ name: 'dead', pid: 999999 }));\n registry.prune();\n const remaining = registry.list();\n expect(remaining).toHaveLength(1);\n expect(remaining[0].name).toBe('alive');\n });\n\n it('is a no-op when all entries are alive', () => {\n registry.register(makeEntry({ pid: process.pid }));\n const before = registry.list();\n registry.prune();\n const after = registry.list();\n expect(after).toEqual(before);\n });\n\n it('preserves entries when liveness probing fails with EPERM', () => {\n registry.register(makeEntry({ name: 'custom-name', tmuxSession: 'tmux-custom' }));\n vi.spyOn(process, 'kill').mockImplementation(() => {\n throw Object.assign(new Error('operation not permitted'), { code: 'EPERM' });\n });\n\n registry.prune();\n\n expect(registry.lookup('custom-name')).toMatchObject({\n name: 'custom-name',\n tmuxSession: 'tmux-custom',\n });\n });\n\n it('removes entries when liveness probing fails with ESRCH', () => {\n registry.register(makeEntry({ name: 'dead' }));\n vi.spyOn(process, 'kill').mockImplementation(() => {\n throw Object.assign(new Error('no such process'), { code: 'ESRCH' });\n });\n\n registry.prune();\n\n expect(registry.lookup('dead')).toBeNull();\n });\n\n it('does nothing when file is missing', () => {\n expect(() => registry.prune()).not.toThrow();\n });\n\n it('keeps forced prune available before the passive cadence is due', () => {\n let nowMs = Date.parse('2026-08-14T10:00:00.000Z');\n const clocked = new AgentRegistry(regPath, {\n now: () => new Date(nowMs),\n pruneIntervalMs: 30_000,\n });\n clocked.register(makeEntry({ name: 'forced', pid: process.pid }));\n const alive = vi.spyOn(clocked, 'isAlive').mockReturnValue(true);\n clocked.pruneIfDue();\n alive.mockReturnValue(false);\n nowMs += 1;\n\n clocked.prune();\n\n expect(alive).toHaveBeenCalledTimes(2);\n expect(clocked.lookup('forced')).toBeNull();\n });\n });\n\n describe('default()', () => {\n it('returns a singleton instance', () => {\n expect(AgentRegistry.default()).toBe(AgentRegistry.default());\n });\n });\n\n describe('rename', () => {\n it('updates the name of an existing entry', () => {\n registry.register(makeEntry({ name: 'old-name', pid: process.pid }));\n registry.rename('old-name', 'new-name');\n expect(registry.lookup('new-name')?.name).toBe('new-name');\n expect(registry.lookup('old-name')).toBeNull();\n });\n\n it('preserves all other fields on the renamed entry', () => {\n registry.register(makeEntry({ name: 'old-name', pid: process.pid, tmuxSession: 'old-name', cwd: '/my/cwd' }));\n registry.rename('old-name', 'new-name');\n const entry = registry.lookup('new-name');\n expect(entry?.tmuxSession).toBe('old-name');\n expect(entry?.cwd).toBe('/my/cwd');\n expect(entry?.pid).toBe(process.pid);\n });\n\n it('throws RenameNotFoundError when current name does not exist', () => {\n expect(() => registry.rename('ghost', 'new-name')).toThrow(RenameNotFoundError);\n });\n\n it('throws RenameConflictError when new name is already in use by a live entry', () => {\n registry.register(makeEntry({ name: 'agent-a', pid: process.pid }));\n registry.register(makeEntry({ name: 'agent-b', pid: process.ppid }));\n expect(() => registry.rename('agent-a', 'agent-b')).toThrow(RenameConflictError);\n });\n\n it('throws RenameConflictError when the conflicting entry probe fails with EPERM', () => {\n registry.register(makeEntry({ name: 'agent-a', pid: process.pid }));\n registry.register(makeEntry({ name: 'agent-b', pid: process.ppid }));\n vi.spyOn(process, 'kill').mockImplementation(() => {\n throw Object.assign(new Error('operation not permitted'), { code: 'EPERM' });\n });\n\n expect(() => registry.rename('agent-a', 'agent-b')).toThrow(RenameConflictError);\n expect(registry.lookup('agent-b')?.pid).toBe(process.ppid);\n });\n\n it('succeeds when new name exists only as a stale (dead) entry', () => {\n registry.register(makeEntry({ name: 'agent-a', pid: process.pid }));\n registry.register(makeEntry({ name: 'agent-b', pid: 999999 }));\n expect(() => registry.rename('agent-a', 'agent-b')).not.toThrow();\n expect(registry.lookup('agent-b')?.pid).toBe(process.pid);\n });\n\n it('does not create the legacy fixed .tmp path on rename', () => {\n registry.register(makeEntry({ name: 'old-name', pid: process.pid }));\n registry.rename('old-name', 'new-name');\n expect(fs.existsSync(`${regPath}.tmp`)).toBe(false);\n });\n });\n});\n"],"names":["fs","os","path","Database","AgentRegistry","RenameNotFoundError","RenameConflictError","makeEntry","over","name","type","pid","process","tmuxSession","cwd","startedAt","sessionId","sessionFilePath","pinned","describe","tmpDir","regPath","registry","beforeEach","mkdtempSync","join","tmpdir","afterEach","vi","restoreAllMocks","rmSync","recursive","force","it","register","expect","existsSync","replace","toBe","list","ppid","toHaveLength","all","saved","lookup","toBeNull","spyOn","mockImplementation","Object","assign","Error","code","toThrow","registerBatch","other","toMatchObject","togglePin","now","Date","clocked","updatedAt","toISOString","db","readonly","row","prepare","get","close","updated_at","rename","prune","readonlyRegistry","toEqual","legacyEntry","mkdirSync","dirname","writeFileSync","JSON","stringify","entries","legacyRegistry","isAlive","remaining","before","after","not","nowMs","parse","pruneIntervalMs","alive","mockReturnValue","pruneIfDue","toHaveBeenCalledTimes","default","entry"],"mappings":"AAAA,OAAOA,QAAQ,KAAK;AACpB,OAAOC,QAAQ,KAAK;AACpB,OAAOC,UAAU,OAAO;AACxB,OAAOC,cAAc,iBAAiB;AACtC,SAASC,aAAa,EAAEC,mBAAmB,EAAEC,mBAAmB,QAA4B,+BAA+B;AAE3H,SAASC,UAAUC,OAA+B,CAAC,CAAC;IAChD,OAAO;QACHC,MAAM;QACNC,MAAM;QACNC,KAAKC,QAAQD,GAAG;QAChBE,aAAa;QACbC,KAAK;QACLC,WAAW;QACXC,WAAW;QACXC,iBAAiB;QACjBC,QAAQ;QACR,GAAGV,IAAI;IACX;AACJ;AAEAW,SAAS,iBAAiB;IACtB,IAAIC;IACJ,IAAIC;IACJ,IAAIC;IAEJC,WAAW;QACPH,SAASpB,GAAGwB,WAAW,CAACtB,KAAKuB,IAAI,CAACxB,GAAGyB,MAAM,IAAI;QAC/CL,UAAUnB,KAAKuB,IAAI,CAACL,QAAQ,UAAU;QACtCE,WAAW,IAAIlB,cAAciB;IACjC;IAEAM,UAAU;QACNC,GAAGC,eAAe;QAClB7B,GAAG8B,MAAM,CAACV,QAAQ;YAAEW,WAAW;YAAMC,OAAO;QAAK;IACrD;IAEAb,SAAS,YAAY;QACjBc,GAAG,+DAA+D;YAC9DX,SAASY,QAAQ,CAAC3B;YAClB4B,OAAOnC,GAAGoC,UAAU,CAACf,QAAQgB,OAAO,CAAC,WAAW,SAASC,IAAI,CAAC;YAC9DH,OAAOb,SAASiB,IAAI,EAAE,CAAC,EAAE,CAAC9B,IAAI,EAAE6B,IAAI,CAAC;QACzC;QAEAL,GAAG,2CAA2C;YAC1CX,SAASY,QAAQ,CAAC3B,UAAU;gBAAEE,MAAM;YAAI;YACxCa,SAASY,QAAQ,CAAC3B,UAAU;gBAAEE,MAAM;gBAAKE,KAAKC,QAAQ4B,IAAI;YAAC;YAC3DL,OAAOb,SAASiB,IAAI,IAAIE,YAAY,CAAC;QACzC;QAEAR,GAAG,oDAAoD;YACnDX,SAASY,QAAQ,CAAC3B,UAAU;gBAAEE,MAAM;gBAAKE,KAAKC,QAAQD,GAAG;YAAC;YAC1DW,SAASY,QAAQ,CAAC3B,UAAU;gBAAEE,MAAM;gBAAYE,KAAKC,QAAQD,GAAG;gBAAEE,aAAa;YAAG;YAClF,MAAM6B,MAAMpB,SAASiB,IAAI;YACzBJ,OAAOO,KAAKD,YAAY,CAAC;YACzBN,OAAOO,GAAG,CAAC,EAAE,CAAC/B,GAAG,EAAE2B,IAAI,CAAC1B,QAAQD,GAAG;YACnCwB,OAAOO,GAAG,CAAC,EAAE,CAACjC,IAAI,EAAE6B,IAAI,CAAC;QAC7B;QAEAL,GAAG,qDAAqD;YACpDX,SAASY,QAAQ,CAAC3B;YAClB4B,OAAOnC,GAAGoC,UAAU,CAAC,GAAGf,QAAQ,IAAI,CAAC,GAAGiB,IAAI,CAAC;QACjD;QAEAL,GAAG,2BAA2B;YAC1BX,SAASY,QAAQ,CAAC3B,UAAU;gBAAES,WAAW;gBAAWC,iBAAiB;YAAiB;YACtF,MAAM0B,QAAQrB,SAASiB,IAAI,EAAE,CAAC,EAAE;YAChCJ,OAAOQ,MAAM3B,SAAS,EAAEsB,IAAI,CAAC;YAC7BH,OAAOQ,MAAM1B,eAAe,EAAEqB,IAAI,CAAC;QACvC;QAEAL,GAAG,gEAAgE;YAC/DX,SAASY,QAAQ,CAAC3B,UAAU;gBAAEE,MAAM;gBAAKI,aAAa;YAAS;YAC/DS,SAASY,QAAQ,CAAC3B,UAAU;gBAAEE,MAAM;gBAAYI,aAAa;gBAAIF,KAAKC,QAAQD,GAAG;YAAC;YAClF,MAAMgC,QAAQrB,SAASsB,MAAM,CAAC;YAC9BT,OAAOQ,OAAO9B,aAAayB,IAAI,CAAC;YAChCH,OAAOQ,OAAOhC,KAAK2B,IAAI,CAAC1B,QAAQD,GAAG;QACvC;QAEAsB,GAAG,4EAA4E;YAC3EX,SAASY,QAAQ,CAAC3B,UAAU;gBAAEE,MAAM,CAAC,UAAU,EAAEG,QAAQD,GAAG,EAAE;gBAAEE,aAAa;YAAG;YAChFS,SAASY,QAAQ,CAAC3B,UAAU;gBAAEE,MAAM;gBAAeI,aAAa;YAAc;YAC9EsB,OAAOb,SAASsB,MAAM,CAAC,gBAAgB/B,aAAayB,IAAI,CAAC;YACzDH,OAAOb,SAASsB,MAAM,CAAC,CAAC,UAAU,EAAEhC,QAAQD,GAAG,EAAE,GAAGkC,QAAQ;YAC5DV,OAAOb,SAASiB,IAAI,IAAIE,YAAY,CAAC;QACzC;QAEAR,GAAG,uEAAuE;YACtEX,SAASY,QAAQ,CAAC3B,UAAU;gBAAEE,MAAM;gBAAgBE,KAAKC,QAAQD,GAAG;YAAC;YACrEiB,GAAGkB,KAAK,CAAClC,SAAS,QAAQmC,kBAAkB,CAAC;gBACzC,MAAMC,OAAOC,MAAM,CAAC,IAAIC,MAAM,4BAA4B;oBAAEC,MAAM;gBAAQ;YAC9E;YAEAhB,OAAO,IAAMb,SAASY,QAAQ,CAAC3B,UAAU;oBACrCE,MAAM;oBACNE,KAAKC,QAAQD,GAAG,GAAG;gBACvB,KAAKyC,OAAO;YACZjB,OAAOb,SAASsB,MAAM,CAAC,iBAAiBjC,KAAK2B,IAAI,CAAC1B,QAAQD,GAAG;QACjE;IACJ;IAEAQ,SAAS,iBAAiB;QACtBc,GAAG,6BAA6B;YAC5BX,SAAS+B,aAAa,CAAC,EAAE;YACzBlB,OAAOnC,GAAGoC,UAAU,CAACf,UAAUiB,IAAI,CAAC;QACxC;QAEAL,GAAG,8CAA8C;YAC7CX,SAAS+B,aAAa,CAAC;gBACnB9C,UAAU;oBAAEE,MAAM;gBAAI;gBACtBF,UAAU;oBAAEE,MAAM;oBAAKE,KAAKC,QAAQD,GAAG,GAAG;gBAAE;gBAC5CJ,UAAU;oBAAEE,MAAM;oBAAKE,KAAKC,QAAQD,GAAG,GAAG;gBAAE;aAC/C;YACDwB,OAAOb,SAASiB,IAAI,IAAIE,YAAY,CAAC;QACzC;QAEAR,GAAG,2CAA2C;YAC1CX,SAASY,QAAQ,CAAC3B,UAAU;gBAAEE,MAAM;gBAAKI,aAAa;YAAS;YAC/DS,SAAS+B,aAAa,CAAC;gBACnB9C,UAAU;oBAAEE,MAAM;oBAAYI,aAAa;oBAAIF,KAAKC,QAAQD,GAAG;gBAAC;gBAChEJ,UAAU;oBAAEE,MAAM;oBAAKI,aAAa;oBAAIF,KAAKC,QAAQD,GAAG,GAAG;gBAAE;aAChE;YACDwB,OAAOb,SAASsB,MAAM,CAAC,MAAM/B,aAAayB,IAAI,CAAC;YAC/CH,OAAOb,SAASsB,MAAM,CAAC,MAAMjC,KAAK2B,IAAI,CAAC1B,QAAQD,GAAG;YAClDwB,OAAOb,SAASsB,MAAM,CAAC,MAAM/B,aAAayB,IAAI,CAAC;QACnD;QAEAL,GAAG,oEAAoE;YACnE,MAAMqB,QAAQ,IAAIlD,cAAciB;YAChCC,SAASY,QAAQ,CAAC3B,UAAU;gBAAEE,MAAM,CAAC,UAAU,EAAEG,QAAQD,GAAG,EAAE;gBAAEE,aAAa;YAAG;YAChFyC,MAAMpB,QAAQ,CAAC3B,UAAU;gBAAEE,MAAM;gBAAeI,aAAa;YAAc;YAC3ES,SAASY,QAAQ,CAAC3B,UAAU;gBAAEE,MAAM,CAAC,UAAU,EAAEG,QAAQD,GAAG,EAAE;gBAAEE,aAAa;YAAG;YAEhFsB,OAAOb,SAASiB,IAAI,IAAIE,YAAY,CAAC;YACrCN,OAAOb,SAASsB,MAAM,CAAC,gBAAgBjC,KAAK2B,IAAI,CAAC1B,QAAQD,GAAG;QAChE;QAEAsB,GAAG,2DAA2D;YAC1DX,SAASY,QAAQ,CAAC3B,UAAU;gBAAEE,MAAM;gBAAcC,MAAM;gBAAUC,KAAKC,QAAQD,GAAG;YAAC;YAEnFW,SAASY,QAAQ,CAAC3B,UAAU;gBACxBE,MAAM;gBACNC,MAAM;gBACNC,KAAKC,QAAQD,GAAG;gBAChBE,aAAa;YACjB;YAEAsB,OAAOb,SAASsB,MAAM,CAAC,eAAeC,QAAQ;YAC9CV,OAAOb,SAASsB,MAAM,CAAC,cAAcW,aAAa,CAAC;gBAAE7C,MAAM;gBAASC,KAAKC,QAAQD,GAAG;YAAC;YACrFwB,OAAOb,SAASiB,IAAI,IAAIE,YAAY,CAAC;QACzC;QAEAR,GAAG,0EAA0E;YACzEX,SAASY,QAAQ,CAAC3B,UAAU;gBAAEE,MAAM;gBAASE,KAAKC,QAAQD,GAAG;YAAC;YAE9DwB,OAAO,IAAMb,SAAS+B,aAAa,CAAC;oBAChC9C,UAAU;wBAAEE,MAAM;wBAASE,KAAK;oBAAO;oBACvCJ,UAAU;wBAAEE,MAAM;wBAASC,MAAM;wBAASC,KAAK;oBAAO;iBACzD,GAAGyC,OAAO,CAAC;YAEZjB,OAAOb,SAASsB,MAAM,CAAC,UAAUC,QAAQ;YACzCV,OAAOb,SAASsB,MAAM,CAAC,UAAUjC,KAAK2B,IAAI,CAAC1B,QAAQD,GAAG;QAC1D;IACJ;IAEAQ,SAAS,UAAU;QACfc,GAAG,oCAAoC;YACnCE,OAAOb,SAASsB,MAAM,CAAC,YAAYC,QAAQ;QAC/C;QAEAZ,GAAG,uCAAuC;YACtCX,SAASY,QAAQ,CAAC3B,UAAU;gBAAEE,MAAM;YAAI;YACxC0B,OAAOb,SAASsB,MAAM,CAAC,MAAMnC,MAAM6B,IAAI,CAAC;QAC5C;IACJ;IAEAnB,SAAS,WAAW;QAChBc,GAAG,iEAAiE;YAChEX,SAASY,QAAQ,CAAC3B;YAElB4B,OAAOb,SAASsB,MAAM,CAAC,WAAW1B,QAAQoB,IAAI,CAAC;YAC/CH,OAAOb,SAASkC,SAAS,CAAC,UAAU5C,QAAQD,GAAG,GAAG2B,IAAI,CAAC;YACvDH,OAAOb,SAASsB,MAAM,CAAC,WAAW1B,QAAQoB,IAAI,CAAC;YAC/CH,OAAOb,SAASkC,SAAS,CAAC,UAAU5C,QAAQD,GAAG,GAAG2B,IAAI,CAAC;YACvDH,OAAOb,SAASsB,MAAM,CAAC,WAAW1B,QAAQoB,IAAI,CAAC;QACnD;QAEAL,GAAG,yCAAyC;YACxC,IAAIwB,MAAM,IAAIC,KAAK;YACnB,MAAMC,UAAU,IAAIvD,cAAciB,SAAS;gBAAEoC,KAAK,IAAMA;YAAI;YAC5DE,QAAQzB,QAAQ,CAAC3B;YACjBkD,MAAM,IAAIC,KAAK;YAEfC,QAAQH,SAAS,CAAC,UAAU5C,QAAQD,GAAG;YAEvCwB,OAAOwB,QAAQf,MAAM,CAAC,WAAWgB,WAAWtB,IAAI,CAACmB,IAAII,WAAW;YAChE,MAAMC,KAAK,IAAI3D,SAASkB,QAAQgB,OAAO,CAAC,WAAW,QAAQ;gBAAE0B,UAAU;YAAK;YAC5E,MAAMC,MAAMF,GAAGG,OAAO,CAAC,4DAClBC,GAAG,CAAC,UAAUtD,QAAQD,GAAG;YAC9BmD,GAAGK,KAAK;YACRhC,OAAO6B,IAAII,UAAU,EAAE9B,IAAI,CAACmB,IAAII,WAAW;QAC/C;QAEA5B,GAAG,qDAAqD;YACpDE,OAAOb,SAASkC,SAAS,CAAC,UAAU,SAASX,QAAQ;QACzD;QAEAZ,GAAG,0DAA0D;YACzDX,SAASY,QAAQ,CAAC3B,UAAU;gBAAES,WAAW;YAAS;YAClDM,SAASkC,SAAS,CAAC,UAAU5C,QAAQD,GAAG;YAExCW,SAASY,QAAQ,CAAC3B,UAAU;gBAAES,WAAW;YAAQ;YAEjDmB,OAAOb,SAASsB,MAAM,CAAC,WAAWW,aAAa,CAAC;gBAAEvC,WAAW;gBAASE,QAAQ;YAAK;QACvF;QAEAe,GAAG,kCAAkC;YACjCX,SAASY,QAAQ,CAAC3B,UAAU;gBAAEE,MAAM;YAAS;YAC7Ca,SAASkC,SAAS,CAAC,UAAU5C,QAAQD,GAAG;YAExCW,SAAS+C,MAAM,CAAC,UAAU;YAE1BlC,OAAOb,SAASsB,MAAM,CAAC,UAAU1B,QAAQoB,IAAI,CAAC;QAClD;QAEAL,GAAG,6CAA6C;YAC5CX,SAASY,QAAQ,CAAC3B,UAAU;gBAAEI,KAAK;YAAO;YAC1CW,SAASkC,SAAS,CAAC,UAAU;YAE7BlC,SAASgD,KAAK;YAEdnC,OAAOb,SAASsB,MAAM,CAAC,WAAWC,QAAQ;QAC9C;QAEAZ,GAAG,gEAAgE;YAC/DX,SAASY,QAAQ,CAAC3B;YAClB,MAAMgE,mBAAmB,IAAInE,cAAciB,SAAS;gBAAE0C,UAAU;YAAK;YAErE5B,OAAO,IAAMoC,iBAAiBf,SAAS,CAAC,UAAU5C,QAAQD,GAAG,GAAGyC,OAAO,CAAC;QAC5E;IACJ;IAEAjC,SAAS,QAAQ;QACbc,GAAG,8DAA8D;YAC7DE,OAAOb,SAASiB,IAAI,IAAIiC,OAAO,CAAC,EAAE;QACtC;QAEAvC,GAAG,+CAA+C;YAC9C,MAAMwC,cAAclE,UAAU;gBAAEE,MAAM;gBAAUI,aAAa;YAAS;YACtEb,GAAG0E,SAAS,CAACxE,KAAKyE,OAAO,CAACtD,UAAU;gBAAEU,WAAW;YAAK;YACtD/B,GAAG4E,aAAa,CAACvD,SAASwD,KAAKC,SAAS,CAAC;gBAAEC,SAAS;oBAACN;iBAAY;YAAC,IAAI;YAEtE,MAAMO,iBAAiB,IAAI5E,cAAciB;YAEzCc,OAAO6C,eAAepC,MAAM,CAAC,WAAWC,QAAQ;YAChDV,OAAO6C,eAAezC,IAAI,IAAIiC,OAAO,CAAC,EAAE;YACxCrC,OAAOnC,GAAGoC,UAAU,CAACf,QAAQgB,OAAO,CAAC,WAAW,SAASC,IAAI,CAAC;QAClE;IACJ;IAEAnB,SAAS,WAAW;QAChBc,GAAG,wCAAwC;YACvCE,OAAOb,SAAS2D,OAAO,CAAC1E,UAAU;gBAAEI,KAAKC,QAAQD,GAAG;YAAC,KAAK2B,IAAI,CAAC;QACnE;QAEAL,GAAG,+CAA+C;YAC9CE,OAAOb,SAAS2D,OAAO,CAAC1E,UAAU;gBAAEI,KAAK;YAAO,KAAK2B,IAAI,CAAC;QAC9D;QAEAL,GAAG,+DAA+D;YAC9DL,GAAGkB,KAAK,CAAClC,SAAS,QAAQmC,kBAAkB,CAAC;gBACzC,MAAMC,OAAOC,MAAM,CAAC,IAAIC,MAAM,4BAA4B;oBAAEC,MAAM;gBAAQ;YAC9E;YAEAhB,OAAOb,SAAS2D,OAAO,CAAC1E,cAAc+B,IAAI,CAAC;QAC/C;QAEAL,GAAG,sDAAsD;YACrDL,GAAGkB,KAAK,CAAClC,SAAS,QAAQmC,kBAAkB,CAAC;gBACzC,MAAMC,OAAOC,MAAM,CAAC,IAAIC,MAAM,oBAAoB;oBAAEC,MAAM;gBAAQ;YACtE;YAEAhB,OAAOb,SAAS2D,OAAO,CAAC1E,cAAc+B,IAAI,CAAC;QAC/C;QAEAL,GAAG,6EAA6E;YAC5EL,GAAGkB,KAAK,CAAClC,SAAS,QAAQmC,kBAAkB,CAAC;gBACzC,MAAM,IAAIG,MAAM;YACpB;YAEAf,OAAOb,SAAS2D,OAAO,CAAC1E,cAAc+B,IAAI,CAAC;QAC/C;IACJ;IAEAnB,SAAS,SAAS;QACdc,GAAG,uCAAuC;YACtCX,SAASY,QAAQ,CAAC3B,UAAU;gBAAEE,MAAM;gBAASE,KAAKC,QAAQD,GAAG;YAAC;YAC9DW,SAASY,QAAQ,CAAC3B,UAAU;gBAAEE,MAAM;gBAAQE,KAAK;YAAO;YACxDW,SAASgD,KAAK;YACd,MAAMY,YAAY5D,SAASiB,IAAI;YAC/BJ,OAAO+C,WAAWzC,YAAY,CAAC;YAC/BN,OAAO+C,SAAS,CAAC,EAAE,CAACzE,IAAI,EAAE6B,IAAI,CAAC;QACnC;QAEAL,GAAG,yCAAyC;YACxCX,SAASY,QAAQ,CAAC3B,UAAU;gBAAEI,KAAKC,QAAQD,GAAG;YAAC;YAC/C,MAAMwE,SAAS7D,SAASiB,IAAI;YAC5BjB,SAASgD,KAAK;YACd,MAAMc,QAAQ9D,SAASiB,IAAI;YAC3BJ,OAAOiD,OAAOZ,OAAO,CAACW;QAC1B;QAEAlD,GAAG,4DAA4D;YAC3DX,SAASY,QAAQ,CAAC3B,UAAU;gBAAEE,MAAM;gBAAeI,aAAa;YAAc;YAC9Ee,GAAGkB,KAAK,CAAClC,SAAS,QAAQmC,kBAAkB,CAAC;gBACzC,MAAMC,OAAOC,MAAM,CAAC,IAAIC,MAAM,4BAA4B;oBAAEC,MAAM;gBAAQ;YAC9E;YAEA7B,SAASgD,KAAK;YAEdnC,OAAOb,SAASsB,MAAM,CAAC,gBAAgBW,aAAa,CAAC;gBACjD9C,MAAM;gBACNI,aAAa;YACjB;QACJ;QAEAoB,GAAG,0DAA0D;YACzDX,SAASY,QAAQ,CAAC3B,UAAU;gBAAEE,MAAM;YAAO;YAC3CmB,GAAGkB,KAAK,CAAClC,SAAS,QAAQmC,kBAAkB,CAAC;gBACzC,MAAMC,OAAOC,MAAM,CAAC,IAAIC,MAAM,oBAAoB;oBAAEC,MAAM;gBAAQ;YACtE;YAEA7B,SAASgD,KAAK;YAEdnC,OAAOb,SAASsB,MAAM,CAAC,SAASC,QAAQ;QAC5C;QAEAZ,GAAG,qCAAqC;YACpCE,OAAO,IAAMb,SAASgD,KAAK,IAAIe,GAAG,CAACjC,OAAO;QAC9C;QAEAnB,GAAG,kEAAkE;YACjE,IAAIqD,QAAQ5B,KAAK6B,KAAK,CAAC;YACvB,MAAM5B,UAAU,IAAIvD,cAAciB,SAAS;gBACvCoC,KAAK,IAAM,IAAIC,KAAK4B;gBACpBE,iBAAiB;YACrB;YACA7B,QAAQzB,QAAQ,CAAC3B,UAAU;gBAAEE,MAAM;gBAAUE,KAAKC,QAAQD,GAAG;YAAC;YAC9D,MAAM8E,QAAQ7D,GAAGkB,KAAK,CAACa,SAAS,WAAW+B,eAAe,CAAC;YAC3D/B,QAAQgC,UAAU;YAClBF,MAAMC,eAAe,CAAC;YACtBJ,SAAS;YAET3B,QAAQW,KAAK;YAEbnC,OAAOsD,OAAOG,qBAAqB,CAAC;YACpCzD,OAAOwB,QAAQf,MAAM,CAAC,WAAWC,QAAQ;QAC7C;IACJ;IAEA1B,SAAS,aAAa;QAClBc,GAAG,gCAAgC;YAC/BE,OAAO/B,cAAcyF,OAAO,IAAIvD,IAAI,CAAClC,cAAcyF,OAAO;QAC9D;IACJ;IAEA1E,SAAS,UAAU;QACfc,GAAG,yCAAyC;YACxCX,SAASY,QAAQ,CAAC3B,UAAU;gBAAEE,MAAM;gBAAYE,KAAKC,QAAQD,GAAG;YAAC;YACjEW,SAAS+C,MAAM,CAAC,YAAY;YAC5BlC,OAAOb,SAASsB,MAAM,CAAC,aAAanC,MAAM6B,IAAI,CAAC;YAC/CH,OAAOb,SAASsB,MAAM,CAAC,aAAaC,QAAQ;QAChD;QAEAZ,GAAG,mDAAmD;YAClDX,SAASY,QAAQ,CAAC3B,UAAU;gBAAEE,MAAM;gBAAYE,KAAKC,QAAQD,GAAG;gBAAEE,aAAa;gBAAYC,KAAK;YAAU;YAC1GQ,SAAS+C,MAAM,CAAC,YAAY;YAC5B,MAAMyB,QAAQxE,SAASsB,MAAM,CAAC;YAC9BT,OAAO2D,OAAOjF,aAAayB,IAAI,CAAC;YAChCH,OAAO2D,OAAOhF,KAAKwB,IAAI,CAAC;YACxBH,OAAO2D,OAAOnF,KAAK2B,IAAI,CAAC1B,QAAQD,GAAG;QACvC;QAEAsB,GAAG,+DAA+D;YAC9DE,OAAO,IAAMb,SAAS+C,MAAM,CAAC,SAAS,aAAajB,OAAO,CAAC/C;QAC/D;QAEA4B,GAAG,8EAA8E;YAC7EX,SAASY,QAAQ,CAAC3B,UAAU;gBAAEE,MAAM;gBAAWE,KAAKC,QAAQD,GAAG;YAAC;YAChEW,SAASY,QAAQ,CAAC3B,UAAU;gBAAEE,MAAM;gBAAWE,KAAKC,QAAQ4B,IAAI;YAAC;YACjEL,OAAO,IAAMb,SAAS+C,MAAM,CAAC,WAAW,YAAYjB,OAAO,CAAC9C;QAChE;QAEA2B,GAAG,gFAAgF;YAC/EX,SAASY,QAAQ,CAAC3B,UAAU;gBAAEE,MAAM;gBAAWE,KAAKC,QAAQD,GAAG;YAAC;YAChEW,SAASY,QAAQ,CAAC3B,UAAU;gBAAEE,MAAM;gBAAWE,KAAKC,QAAQ4B,IAAI;YAAC;YACjEZ,GAAGkB,KAAK,CAAClC,SAAS,QAAQmC,kBAAkB,CAAC;gBACzC,MAAMC,OAAOC,MAAM,CAAC,IAAIC,MAAM,4BAA4B;oBAAEC,MAAM;gBAAQ;YAC9E;YAEAhB,OAAO,IAAMb,SAAS+C,MAAM,CAAC,WAAW,YAAYjB,OAAO,CAAC9C;YAC5D6B,OAAOb,SAASsB,MAAM,CAAC,YAAYjC,KAAK2B,IAAI,CAAC1B,QAAQ4B,IAAI;QAC7D;QAEAP,GAAG,8DAA8D;YAC7DX,SAASY,QAAQ,CAAC3B,UAAU;gBAAEE,MAAM;gBAAWE,KAAKC,QAAQD,GAAG;YAAC;YAChEW,SAASY,QAAQ,CAAC3B,UAAU;gBAAEE,MAAM;gBAAWE,KAAK;YAAO;YAC3DwB,OAAO,IAAMb,SAAS+C,MAAM,CAAC,WAAW,YAAYgB,GAAG,CAACjC,OAAO;YAC/DjB,OAAOb,SAASsB,MAAM,CAAC,YAAYjC,KAAK2B,IAAI,CAAC1B,QAAQD,GAAG;QAC5D;QAEAsB,GAAG,wDAAwD;YACvDX,SAASY,QAAQ,CAAC3B,UAAU;gBAAEE,MAAM;gBAAYE,KAAKC,QAAQD,GAAG;YAAC;YACjEW,SAAS+C,MAAM,CAAC,YAAY;YAC5BlC,OAAOnC,GAAGoC,UAAU,CAAC,GAAGf,QAAQ,IAAI,CAAC,GAAGiB,IAAI,CAAC;QACjD;IACJ;AACJ"}
|
|
1
|
+
{"version":3,"sources":["../../../src/__tests__/utils/AgentRegistry.test.ts"],"sourcesContent":["import fs from \"fs\";\nimport os from \"os\";\nimport path from \"path\";\nimport Database from \"better-sqlite3\";\nimport {\n AgentRegistry,\n RenameNotFoundError,\n RenameConflictError,\n type RegistryEntry,\n} from \"../../utils/AgentRegistry.js\";\n\nfunction makeEntry(over: Partial<RegistryEntry> = {}): RegistryEntry {\n return {\n name: \"agent1\",\n type: \"claude\",\n pid: process.pid,\n cwd: \"/tmp\",\n startedAt: \"2026-05-30T00:00:00.000Z\",\n sessionId: \"sid-1\",\n sessionFilePath: \"/tmp/session.jsonl\",\n pinned: false,\n runtime: \"tmux\",\n runtimeRef: { session: \"agent1\" },\n ...over,\n };\n}\n\ndescribe(\"AgentRegistry\", () => {\n let tmpDir: string;\n let regPath: string;\n let registry: AgentRegistry;\n\n beforeEach(() => {\n tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), \"agent-registry-\"));\n regPath = path.join(tmpDir, \"nested\", \"agents.json\");\n registry = new AgentRegistry(regPath);\n });\n\n afterEach(() => {\n vi.restoreAllMocks();\n fs.rmSync(tmpDir, { recursive: true, force: true });\n });\n\n describe(\"register\", () => {\n it(\"creates the SQLite database and parent directory if missing\", () => {\n registry.register(makeEntry());\n expect(fs.existsSync(regPath.replace(/\\.json$/, \".db\"))).toBe(true);\n expect(registry.list()[0].name).toBe(\"agent1\");\n });\n\n it(\"appends a new entry when name is unique\", () => {\n registry.register(makeEntry({ name: \"a\" }));\n registry.register(makeEntry({ name: \"b\", pid: process.ppid }));\n expect(registry.list()).toHaveLength(2);\n });\n\n it(\"upserts in place when type and pid already exist\", () => {\n registry.register(makeEntry({ name: \"a\", pid: process.pid }));\n registry.register(makeEntry({ name: \"fallback\", pid: process.pid, runtimeRef: null }));\n const all = registry.list();\n expect(all).toHaveLength(1);\n expect(all[0].pid).toBe(process.pid);\n expect(all[0].name).toBe(\"a\");\n });\n\n it(\"does not write through the legacy fixed .tmp path\", () => {\n registry.register(makeEntry());\n expect(fs.existsSync(`${regPath}.tmp`)).toBe(false);\n });\n\n it(\"persists session fields\", () => {\n registry.register(makeEntry({ sessionId: \"sid-xyz\", sessionFilePath: \"/foo/bar.jsonl\" }));\n const saved = registry.list()[0];\n expect(saved.sessionId).toBe(\"sid-xyz\");\n expect(saved.sessionFilePath).toBe(\"/foo/bar.jsonl\");\n });\n\n it(\"persists runtime metadata for Herdr-backed entries\", () => {\n const runtimeRef = { session: \"default\", paneId: \"w1:p2\", agentName: \"reviewer\" };\n\n registry.register(\n makeEntry({\n name: \"reviewer\",\n runtime: \"herdr\",\n runtimeRef,\n }),\n );\n\n expect(registry.lookup(\"reviewer\")).toMatchObject({\n runtime: \"herdr\",\n runtimeRef,\n });\n });\n\n it(\"lets a Herdr managed start replace an existing same-pid name\", () => {\n const runtimeRef = { session: \"default\", paneId: \"w1:p2\", agentName: \"requested-name\" };\n\n registry.register(makeEntry({ name: \"old-name\", pid: process.pid }));\n registry.register(\n makeEntry({\n name: \"requested-name\",\n pid: process.pid,\n runtime: \"herdr\",\n runtimeRef,\n }),\n );\n\n expect(registry.lookup(\"old-name\")).toBeNull();\n expect(registry.lookup(\"requested-name\")).toMatchObject({\n pid: process.pid,\n runtime: \"herdr\",\n runtimeRef,\n });\n });\n\n it(\"preserves existing runtime ref when incoming runtime ref is empty\", () => {\n registry.register(makeEntry({ name: \"a\", runtimeRef: { session: \"pinned\" } }));\n registry.register(makeEntry({ name: \"fallback\", runtimeRef: null, pid: process.pid }));\n const saved = registry.lookup(\"a\");\n expect(saved?.runtimeRef).toEqual({ session: \"pinned\" });\n expect(saved?.pid).toBe(process.pid);\n });\n\n it(\"defaults an empty tmux runtime ref from the tmux session\", () => {\n registry.register(makeEntry({ name: \"a\", runtimeRef: null }));\n\n expect(registry.lookup(\"a\")?.runtimeRef).toBeNull();\n });\n\n it(\"lets a managed start entry replace a generated fallback for the same pid\", () => {\n registry.register(makeEntry({ name: `ai-devkit-${process.pid}`, runtimeRef: null }));\n registry.register(makeEntry({ name: \"custom-name\", runtimeRef: { session: \"custom-name\" } }));\n expect(registry.lookup(\"custom-name\")?.runtimeRef).toEqual({ session: \"custom-name\" });\n expect(registry.lookup(`ai-devkit-${process.pid}`)).toBeNull();\n expect(registry.list()).toHaveLength(1);\n });\n\n it(\"preserves an existing name conflict when its probe fails with EPERM\", () => {\n registry.register(makeEntry({ name: \"claimed-name\", pid: process.pid }));\n vi.spyOn(process, \"kill\").mockImplementation(() => {\n throw Object.assign(new Error(\"operation not permitted\"), { code: \"EPERM\" });\n });\n\n expect(() =>\n registry.register(\n makeEntry({\n name: \"claimed-name\",\n pid: process.pid + 1,\n }),\n ),\n ).toThrow();\n expect(registry.lookup(\"claimed-name\")?.pid).toBe(process.pid);\n });\n });\n\n describe(\"registerBatch\", () => {\n it(\"is a no-op on empty array\", () => {\n registry.registerBatch([]);\n expect(fs.existsSync(regPath)).toBe(false);\n });\n\n it(\"upserts multiple entries in a single batch\", () => {\n registry.registerBatch([\n makeEntry({ name: \"a\" }),\n makeEntry({ name: \"b\", pid: process.pid + 1 }),\n makeEntry({ name: \"c\", pid: process.pid + 2 }),\n ]);\n expect(registry.list()).toHaveLength(3);\n });\n\n it(\"applies the tmux runtime ref merge per entry\", () => {\n registry.register(makeEntry({ name: \"a\", runtimeRef: { session: \"pinned\" } }));\n registry.registerBatch([\n makeEntry({ name: \"fallback\", runtimeRef: null, pid: process.pid }),\n makeEntry({ name: \"b\", runtimeRef: null, pid: process.pid + 1 }),\n ]);\n expect(registry.lookup(\"a\")?.runtimeRef).toEqual({ session: \"pinned\" });\n expect(registry.lookup(\"a\")?.pid).toBe(process.pid);\n expect(registry.lookup(\"b\")?.runtimeRef).toBeNull();\n });\n\n it(\"handles concurrent registry instances without duplicate pid rows\", () => {\n const other = new AgentRegistry(regPath);\n registry.register(makeEntry({ name: `ai-devkit-${process.pid}`, runtimeRef: null }));\n other.register(makeEntry({ name: \"custom-name\", runtimeRef: { session: \"custom-name\" } }));\n registry.register(makeEntry({ name: `ai-devkit-${process.pid}`, runtimeRef: null }));\n\n expect(registry.list()).toHaveLength(1);\n expect(registry.lookup(\"custom-name\")?.pid).toBe(process.pid);\n });\n\n it(\"cleans up a cross-type row when its pid has been reused\", () => {\n registry.register(makeEntry({ name: \"old-claude\", type: \"claude\", pid: process.pid }));\n\n registry.register(\n makeEntry({\n name: \"new-codex\",\n type: \"codex\",\n pid: process.pid,\n runtimeRef: null,\n }),\n );\n\n expect(registry.lookup(\"old-claude\")).toBeNull();\n expect(registry.lookup(\"new-codex\")).toMatchObject({ type: \"codex\", pid: process.pid });\n expect(registry.list()).toHaveLength(1);\n });\n\n it(\"rolls back the whole batch when a live name conflict rejects one entry\", () => {\n registry.register(makeEntry({ name: \"taken\", pid: process.pid }));\n\n expect(() =>\n registry.registerBatch([\n makeEntry({ name: \"fresh\", pid: 999998 }),\n makeEntry({ name: \"taken\", type: \"codex\", pid: 999997 }),\n ]),\n ).toThrow(/UNIQUE constraint failed/);\n\n expect(registry.lookup(\"fresh\")).toBeNull();\n expect(registry.lookup(\"taken\")?.pid).toBe(process.pid);\n });\n });\n\n describe(\"lookup\", () => {\n it(\"returns null when name not found\", () => {\n expect(registry.lookup(\"missing\")).toBeNull();\n });\n\n it(\"returns the entry when name matches\", () => {\n registry.register(makeEntry({ name: \"a\" }));\n expect(registry.lookup(\"a\")?.name).toBe(\"a\");\n });\n });\n\n describe(\"pinning\", () => {\n it(\"defaults new rows to unpinned and toggles the persisted state\", () => {\n registry.register(makeEntry());\n\n expect(registry.lookup(\"agent1\")?.pinned).toBe(false);\n expect(registry.togglePin(\"claude\", process.pid)).toBe(true);\n expect(registry.lookup(\"agent1\")?.pinned).toBe(true);\n expect(registry.togglePin(\"claude\", process.pid)).toBe(false);\n expect(registry.lookup(\"agent1\")?.pinned).toBe(false);\n });\n\n it(\"updates existing recency when toggled\", () => {\n let now = new Date(\"2026-08-16T10:00:00.000Z\");\n const clocked = new AgentRegistry(regPath, { now: () => now });\n clocked.register(makeEntry());\n now = new Date(\"2026-08-16T10:01:00.000Z\");\n\n clocked.togglePin(\"claude\", process.pid);\n\n expect(clocked.lookup(\"agent1\")?.updatedAt).toBe(now.toISOString());\n const db = new Database(regPath.replace(/\\.json$/, \".db\"), { readonly: true });\n const row = db\n .prepare(\"SELECT updated_at FROM agents WHERE type = ? AND pid = ?\")\n .get(\"claude\", process.pid) as { updated_at: string };\n db.close();\n expect(row.updated_at).toBe(now.toISOString());\n });\n\n it(\"returns null when the process row has disappeared\", () => {\n expect(registry.togglePin(\"claude\", 999999)).toBeNull();\n });\n\n it(\"preserves a pin when poll registration updates the row\", () => {\n registry.register(makeEntry({ sessionId: \"before\" }));\n registry.togglePin(\"claude\", process.pid);\n\n registry.register(makeEntry({ sessionId: \"after\" }));\n\n expect(registry.lookup(\"agent1\")).toMatchObject({ sessionId: \"after\", pinned: true });\n });\n\n it(\"preserves a pin through rename\", () => {\n registry.register(makeEntry({ name: \"before\" }));\n registry.togglePin(\"claude\", process.pid);\n\n registry.rename(\"before\", \"after\");\n\n expect(registry.lookup(\"after\")?.pinned).toBe(true);\n });\n\n it(\"removes the pin with a pruned process row\", () => {\n registry.register(makeEntry({ pid: 999999 }));\n registry.togglePin(\"claude\", 999999);\n\n registry.prune();\n\n expect(registry.lookup(\"agent1\")).toBeNull();\n });\n\n it(\"reports a clear error when a readonly registry toggles a pin\", () => {\n registry.register(makeEntry());\n const readonlyRegistry = new AgentRegistry(regPath, { readonly: true });\n\n expect(() => readonlyRegistry.togglePin(\"claude\", process.pid)).toThrow(/readonly/i);\n });\n });\n\n describe(\"list\", () => {\n it(\"returns empty array when database does not contain entries\", () => {\n expect(registry.list()).toEqual([]);\n });\n\n it(\"ignores existing legacy agents.json entries\", () => {\n const legacyEntry = makeEntry({ name: \"legacy\", runtimeRef: { session: \"legacy\" } });\n fs.mkdirSync(path.dirname(regPath), { recursive: true });\n fs.writeFileSync(regPath, JSON.stringify({ entries: [legacyEntry] }), \"utf8\");\n\n const legacyRegistry = new AgentRegistry(regPath);\n\n expect(legacyRegistry.lookup(\"legacy\")).toBeNull();\n expect(legacyRegistry.list()).toEqual([]);\n expect(fs.existsSync(regPath.replace(/\\.json$/, \".db\"))).toBe(true);\n });\n\n it(\"reads pre-runtime SQLite rows as tmux-backed records\", () => {\n const dbPath = regPath.replace(/\\.json$/, \".db\");\n fs.mkdirSync(path.dirname(dbPath), { recursive: true });\n fs.rmSync(dbPath, { force: true });\n fs.rmSync(`${dbPath}-wal`, { force: true });\n fs.rmSync(`${dbPath}-shm`, { force: true });\n const db = new Database(dbPath);\n db.exec(`\n CREATE TABLE agents (\n type TEXT NOT NULL,\n pid INTEGER NOT NULL,\n name TEXT NOT NULL UNIQUE,\n tmux_session TEXT NOT NULL DEFAULT '',\n cwd TEXT NOT NULL DEFAULT '',\n started_at TEXT NOT NULL,\n session_id TEXT NOT NULL DEFAULT '',\n session_file_path TEXT NOT NULL DEFAULT '',\n updated_at TEXT NOT NULL,\n PRIMARY KEY (type, pid)\n );\n INSERT INTO agents (\n type, pid, name, tmux_session, cwd, started_at, session_id, session_file_path, updated_at\n ) VALUES (\n 'claude', ${process.pid}, 'legacy-sqlite', 'legacy-sqlite', '/tmp',\n '2026-05-30T00:00:00.000Z', 'sid-1', '/tmp/session.jsonl', '2026-05-30T00:00:00.000Z'\n );\n PRAGMA user_version = 1;\n `);\n db.close();\n\n const migratedRegistry = new AgentRegistry(regPath);\n\n expect(migratedRegistry.lookup(\"legacy-sqlite\")).toMatchObject({\n runtime: \"tmux\",\n runtimeRef: { session: \"legacy-sqlite\" },\n });\n });\n });\n\n describe(\"isAlive\", () => {\n it(\"returns true for the current process\", () => {\n expect(registry.isAlive(makeEntry({ pid: process.pid }))).toBe(true);\n });\n\n it(\"returns false for a PID that does not exist\", () => {\n expect(registry.isAlive(makeEntry({ pid: 999999 }))).toBe(false);\n });\n\n it(\"returns true when the process probe is forbidden with EPERM\", () => {\n vi.spyOn(process, \"kill\").mockImplementation(() => {\n throw Object.assign(new Error(\"operation not permitted\"), { code: \"EPERM\" });\n });\n\n expect(registry.isAlive(makeEntry())).toBe(true);\n });\n\n it(\"returns false when the process probe reports ESRCH\", () => {\n vi.spyOn(process, \"kill\").mockImplementation(() => {\n throw Object.assign(new Error(\"no such process\"), { code: \"ESRCH\" });\n });\n\n expect(registry.isAlive(makeEntry())).toBe(false);\n });\n\n it(\"returns true when the process probe fails without a definitive error code\", () => {\n vi.spyOn(process, \"kill\").mockImplementation(() => {\n throw new Error(\"indeterminate probe failure\");\n });\n\n expect(registry.isAlive(makeEntry())).toBe(true);\n });\n });\n\n describe(\"prune\", () => {\n it(\"removes entries whose PIDs are dead\", () => {\n registry.register(makeEntry({ name: \"alive\", pid: process.pid }));\n registry.register(makeEntry({ name: \"dead\", pid: 999999 }));\n registry.prune();\n const remaining = registry.list();\n expect(remaining).toHaveLength(1);\n expect(remaining[0].name).toBe(\"alive\");\n });\n\n it(\"is a no-op when all entries are alive\", () => {\n registry.register(makeEntry({ pid: process.pid }));\n const before = registry.list();\n registry.prune();\n const after = registry.list();\n expect(after).toEqual(before);\n });\n\n it(\"preserves entries when liveness probing fails with EPERM\", () => {\n registry.register(makeEntry({ name: \"custom-name\", runtimeRef: { session: \"tmux-custom\" } }));\n vi.spyOn(process, \"kill\").mockImplementation(() => {\n throw Object.assign(new Error(\"operation not permitted\"), { code: \"EPERM\" });\n });\n\n registry.prune();\n\n expect(registry.lookup(\"custom-name\")).toMatchObject({\n name: \"custom-name\",\n runtimeRef: { session: \"tmux-custom\" },\n });\n });\n\n it(\"removes entries when liveness probing fails with ESRCH\", () => {\n registry.register(makeEntry({ name: \"dead\" }));\n vi.spyOn(process, \"kill\").mockImplementation(() => {\n throw Object.assign(new Error(\"no such process\"), { code: \"ESRCH\" });\n });\n\n registry.prune();\n\n expect(registry.lookup(\"dead\")).toBeNull();\n });\n\n it(\"does nothing when file is missing\", () => {\n expect(() => registry.prune()).not.toThrow();\n });\n\n it(\"keeps forced prune available before the passive cadence is due\", () => {\n let nowMs = Date.parse(\"2026-08-14T10:00:00.000Z\");\n const clocked = new AgentRegistry(regPath, {\n now: () => new Date(nowMs),\n pruneIntervalMs: 30_000,\n });\n clocked.register(makeEntry({ name: \"forced\", pid: process.pid }));\n const alive = vi.spyOn(clocked, \"isAlive\").mockReturnValue(true);\n clocked.pruneIfDue();\n alive.mockReturnValue(false);\n nowMs += 1;\n\n clocked.prune();\n\n expect(alive).toHaveBeenCalledTimes(2);\n expect(clocked.lookup(\"forced\")).toBeNull();\n });\n });\n\n describe(\"default()\", () => {\n it(\"returns a singleton instance\", () => {\n expect(AgentRegistry.default()).toBe(AgentRegistry.default());\n });\n });\n\n describe(\"rename\", () => {\n it(\"updates the name of an existing entry\", () => {\n registry.register(makeEntry({ name: \"old-name\", pid: process.pid }));\n registry.rename(\"old-name\", \"new-name\");\n expect(registry.lookup(\"new-name\")?.name).toBe(\"new-name\");\n expect(registry.lookup(\"old-name\")).toBeNull();\n });\n\n it(\"preserves all other fields on the renamed entry\", () => {\n registry.register(\n makeEntry({\n name: \"old-name\",\n pid: process.pid,\n runtimeRef: { session: \"old-name\" },\n cwd: \"/my/cwd\",\n }),\n );\n registry.rename(\"old-name\", \"new-name\");\n const entry = registry.lookup(\"new-name\");\n expect(entry?.runtimeRef).toEqual({ session: \"old-name\" });\n expect(entry?.cwd).toBe(\"/my/cwd\");\n expect(entry?.pid).toBe(process.pid);\n });\n\n it(\"throws RenameNotFoundError when current name does not exist\", () => {\n expect(() => registry.rename(\"ghost\", \"new-name\")).toThrow(RenameNotFoundError);\n });\n\n it(\"throws RenameConflictError when new name is already in use by a live entry\", () => {\n registry.register(makeEntry({ name: \"agent-a\", pid: process.pid }));\n registry.register(makeEntry({ name: \"agent-b\", pid: process.ppid }));\n expect(() => registry.rename(\"agent-a\", \"agent-b\")).toThrow(RenameConflictError);\n });\n\n it(\"throws RenameConflictError when the conflicting entry probe fails with EPERM\", () => {\n registry.register(makeEntry({ name: \"agent-a\", pid: process.pid }));\n registry.register(makeEntry({ name: \"agent-b\", pid: process.ppid }));\n vi.spyOn(process, \"kill\").mockImplementation(() => {\n throw Object.assign(new Error(\"operation not permitted\"), { code: \"EPERM\" });\n });\n\n expect(() => registry.rename(\"agent-a\", \"agent-b\")).toThrow(RenameConflictError);\n expect(registry.lookup(\"agent-b\")?.pid).toBe(process.ppid);\n });\n\n it(\"succeeds when new name exists only as a stale (dead) entry\", () => {\n registry.register(makeEntry({ name: \"agent-a\", pid: process.pid }));\n registry.register(makeEntry({ name: \"agent-b\", pid: 999999 }));\n expect(() => registry.rename(\"agent-a\", \"agent-b\")).not.toThrow();\n expect(registry.lookup(\"agent-b\")?.pid).toBe(process.pid);\n });\n\n it(\"does not create the legacy fixed .tmp path on rename\", () => {\n registry.register(makeEntry({ name: \"old-name\", pid: process.pid }));\n registry.rename(\"old-name\", \"new-name\");\n expect(fs.existsSync(`${regPath}.tmp`)).toBe(false);\n });\n });\n});\n"],"names":["fs","os","path","Database","AgentRegistry","RenameNotFoundError","RenameConflictError","makeEntry","over","name","type","pid","process","cwd","startedAt","sessionId","sessionFilePath","pinned","runtime","runtimeRef","session","describe","tmpDir","regPath","registry","beforeEach","mkdtempSync","join","tmpdir","afterEach","vi","restoreAllMocks","rmSync","recursive","force","it","register","expect","existsSync","replace","toBe","list","ppid","toHaveLength","all","saved","paneId","agentName","lookup","toMatchObject","toBeNull","toEqual","spyOn","mockImplementation","Object","assign","Error","code","toThrow","registerBatch","other","togglePin","now","Date","clocked","updatedAt","toISOString","db","readonly","row","prepare","get","close","updated_at","rename","prune","readonlyRegistry","legacyEntry","mkdirSync","dirname","writeFileSync","JSON","stringify","entries","legacyRegistry","dbPath","exec","migratedRegistry","isAlive","remaining","before","after","not","nowMs","parse","pruneIntervalMs","alive","mockReturnValue","pruneIfDue","toHaveBeenCalledTimes","default","entry"],"mappings":"AAAA,OAAOA,QAAQ,KAAK;AACpB,OAAOC,QAAQ,KAAK;AACpB,OAAOC,UAAU,OAAO;AACxB,OAAOC,cAAc,iBAAiB;AACtC,SACEC,aAAa,EACbC,mBAAmB,EACnBC,mBAAmB,QAEd,+BAA+B;AAEtC,SAASC,UAAUC,OAA+B,CAAC,CAAC;IAClD,OAAO;QACLC,MAAM;QACNC,MAAM;QACNC,KAAKC,QAAQD,GAAG;QAChBE,KAAK;QACLC,WAAW;QACXC,WAAW;QACXC,iBAAiB;QACjBC,QAAQ;QACRC,SAAS;QACTC,YAAY;YAAEC,SAAS;QAAS;QAChC,GAAGZ,IAAI;IACT;AACF;AAEAa,SAAS,iBAAiB;IACxB,IAAIC;IACJ,IAAIC;IACJ,IAAIC;IAEJC,WAAW;QACTH,SAAStB,GAAG0B,WAAW,CAACxB,KAAKyB,IAAI,CAAC1B,GAAG2B,MAAM,IAAI;QAC/CL,UAAUrB,KAAKyB,IAAI,CAACL,QAAQ,UAAU;QACtCE,WAAW,IAAIpB,cAAcmB;IAC/B;IAEAM,UAAU;QACRC,GAAGC,eAAe;QAClB/B,GAAGgC,MAAM,CAACV,QAAQ;YAAEW,WAAW;YAAMC,OAAO;QAAK;IACnD;IAEAb,SAAS,YAAY;QACnBc,GAAG,+DAA+D;YAChEX,SAASY,QAAQ,CAAC7B;YAClB8B,OAAOrC,GAAGsC,UAAU,CAACf,QAAQgB,OAAO,CAAC,WAAW,SAASC,IAAI,CAAC;YAC9DH,OAAOb,SAASiB,IAAI,EAAE,CAAC,EAAE,CAAChC,IAAI,EAAE+B,IAAI,CAAC;QACvC;QAEAL,GAAG,2CAA2C;YAC5CX,SAASY,QAAQ,CAAC7B,UAAU;gBAAEE,MAAM;YAAI;YACxCe,SAASY,QAAQ,CAAC7B,UAAU;gBAAEE,MAAM;gBAAKE,KAAKC,QAAQ8B,IAAI;YAAC;YAC3DL,OAAOb,SAASiB,IAAI,IAAIE,YAAY,CAAC;QACvC;QAEAR,GAAG,oDAAoD;YACrDX,SAASY,QAAQ,CAAC7B,UAAU;gBAAEE,MAAM;gBAAKE,KAAKC,QAAQD,GAAG;YAAC;YAC1Da,SAASY,QAAQ,CAAC7B,UAAU;gBAAEE,MAAM;gBAAYE,KAAKC,QAAQD,GAAG;gBAAEQ,YAAY;YAAK;YACnF,MAAMyB,MAAMpB,SAASiB,IAAI;YACzBJ,OAAOO,KAAKD,YAAY,CAAC;YACzBN,OAAOO,GAAG,CAAC,EAAE,CAACjC,GAAG,EAAE6B,IAAI,CAAC5B,QAAQD,GAAG;YACnC0B,OAAOO,GAAG,CAAC,EAAE,CAACnC,IAAI,EAAE+B,IAAI,CAAC;QAC3B;QAEAL,GAAG,qDAAqD;YACtDX,SAASY,QAAQ,CAAC7B;YAClB8B,OAAOrC,GAAGsC,UAAU,CAAC,GAAGf,QAAQ,IAAI,CAAC,GAAGiB,IAAI,CAAC;QAC/C;QAEAL,GAAG,2BAA2B;YAC5BX,SAASY,QAAQ,CAAC7B,UAAU;gBAAEQ,WAAW;gBAAWC,iBAAiB;YAAiB;YACtF,MAAM6B,QAAQrB,SAASiB,IAAI,EAAE,CAAC,EAAE;YAChCJ,OAAOQ,MAAM9B,SAAS,EAAEyB,IAAI,CAAC;YAC7BH,OAAOQ,MAAM7B,eAAe,EAAEwB,IAAI,CAAC;QACrC;QAEAL,GAAG,sDAAsD;YACvD,MAAMhB,aAAa;gBAAEC,SAAS;gBAAW0B,QAAQ;gBAASC,WAAW;YAAW;YAEhFvB,SAASY,QAAQ,CACf7B,UAAU;gBACRE,MAAM;gBACNS,SAAS;gBACTC;YACF;YAGFkB,OAAOb,SAASwB,MAAM,CAAC,aAAaC,aAAa,CAAC;gBAChD/B,SAAS;gBACTC;YACF;QACF;QAEAgB,GAAG,gEAAgE;YACjE,MAAMhB,aAAa;gBAAEC,SAAS;gBAAW0B,QAAQ;gBAASC,WAAW;YAAiB;YAEtFvB,SAASY,QAAQ,CAAC7B,UAAU;gBAAEE,MAAM;gBAAYE,KAAKC,QAAQD,GAAG;YAAC;YACjEa,SAASY,QAAQ,CACf7B,UAAU;gBACRE,MAAM;gBACNE,KAAKC,QAAQD,GAAG;gBAChBO,SAAS;gBACTC;YACF;YAGFkB,OAAOb,SAASwB,MAAM,CAAC,aAAaE,QAAQ;YAC5Cb,OAAOb,SAASwB,MAAM,CAAC,mBAAmBC,aAAa,CAAC;gBACtDtC,KAAKC,QAAQD,GAAG;gBAChBO,SAAS;gBACTC;YACF;QACF;QAEAgB,GAAG,qEAAqE;YACtEX,SAASY,QAAQ,CAAC7B,UAAU;gBAAEE,MAAM;gBAAKU,YAAY;oBAAEC,SAAS;gBAAS;YAAE;YAC3EI,SAASY,QAAQ,CAAC7B,UAAU;gBAAEE,MAAM;gBAAYU,YAAY;gBAAMR,KAAKC,QAAQD,GAAG;YAAC;YACnF,MAAMkC,QAAQrB,SAASwB,MAAM,CAAC;YAC9BX,OAAOQ,OAAO1B,YAAYgC,OAAO,CAAC;gBAAE/B,SAAS;YAAS;YACtDiB,OAAOQ,OAAOlC,KAAK6B,IAAI,CAAC5B,QAAQD,GAAG;QACrC;QAEAwB,GAAG,4DAA4D;YAC7DX,SAASY,QAAQ,CAAC7B,UAAU;gBAAEE,MAAM;gBAAKU,YAAY;YAAK;YAE1DkB,OAAOb,SAASwB,MAAM,CAAC,MAAM7B,YAAY+B,QAAQ;QACnD;QAEAf,GAAG,4EAA4E;YAC7EX,SAASY,QAAQ,CAAC7B,UAAU;gBAAEE,MAAM,CAAC,UAAU,EAAEG,QAAQD,GAAG,EAAE;gBAAEQ,YAAY;YAAK;YACjFK,SAASY,QAAQ,CAAC7B,UAAU;gBAAEE,MAAM;gBAAeU,YAAY;oBAAEC,SAAS;gBAAc;YAAE;YAC1FiB,OAAOb,SAASwB,MAAM,CAAC,gBAAgB7B,YAAYgC,OAAO,CAAC;gBAAE/B,SAAS;YAAc;YACpFiB,OAAOb,SAASwB,MAAM,CAAC,CAAC,UAAU,EAAEpC,QAAQD,GAAG,EAAE,GAAGuC,QAAQ;YAC5Db,OAAOb,SAASiB,IAAI,IAAIE,YAAY,CAAC;QACvC;QAEAR,GAAG,uEAAuE;YACxEX,SAASY,QAAQ,CAAC7B,UAAU;gBAAEE,MAAM;gBAAgBE,KAAKC,QAAQD,GAAG;YAAC;YACrEmB,GAAGsB,KAAK,CAACxC,SAAS,QAAQyC,kBAAkB,CAAC;gBAC3C,MAAMC,OAAOC,MAAM,CAAC,IAAIC,MAAM,4BAA4B;oBAAEC,MAAM;gBAAQ;YAC5E;YAEApB,OAAO,IACLb,SAASY,QAAQ,CACf7B,UAAU;oBACRE,MAAM;oBACNE,KAAKC,QAAQD,GAAG,GAAG;gBACrB,KAEF+C,OAAO;YACTrB,OAAOb,SAASwB,MAAM,CAAC,iBAAiBrC,KAAK6B,IAAI,CAAC5B,QAAQD,GAAG;QAC/D;IACF;IAEAU,SAAS,iBAAiB;QACxBc,GAAG,6BAA6B;YAC9BX,SAASmC,aAAa,CAAC,EAAE;YACzBtB,OAAOrC,GAAGsC,UAAU,CAACf,UAAUiB,IAAI,CAAC;QACtC;QAEAL,GAAG,8CAA8C;YAC/CX,SAASmC,aAAa,CAAC;gBACrBpD,UAAU;oBAAEE,MAAM;gBAAI;gBACtBF,UAAU;oBAAEE,MAAM;oBAAKE,KAAKC,QAAQD,GAAG,GAAG;gBAAE;gBAC5CJ,UAAU;oBAAEE,MAAM;oBAAKE,KAAKC,QAAQD,GAAG,GAAG;gBAAE;aAC7C;YACD0B,OAAOb,SAASiB,IAAI,IAAIE,YAAY,CAAC;QACvC;QAEAR,GAAG,gDAAgD;YACjDX,SAASY,QAAQ,CAAC7B,UAAU;gBAAEE,MAAM;gBAAKU,YAAY;oBAAEC,SAAS;gBAAS;YAAE;YAC3EI,SAASmC,aAAa,CAAC;gBACrBpD,UAAU;oBAAEE,MAAM;oBAAYU,YAAY;oBAAMR,KAAKC,QAAQD,GAAG;gBAAC;gBACjEJ,UAAU;oBAAEE,MAAM;oBAAKU,YAAY;oBAAMR,KAAKC,QAAQD,GAAG,GAAG;gBAAE;aAC/D;YACD0B,OAAOb,SAASwB,MAAM,CAAC,MAAM7B,YAAYgC,OAAO,CAAC;gBAAE/B,SAAS;YAAS;YACrEiB,OAAOb,SAASwB,MAAM,CAAC,MAAMrC,KAAK6B,IAAI,CAAC5B,QAAQD,GAAG;YAClD0B,OAAOb,SAASwB,MAAM,CAAC,MAAM7B,YAAY+B,QAAQ;QACnD;QAEAf,GAAG,oEAAoE;YACrE,MAAMyB,QAAQ,IAAIxD,cAAcmB;YAChCC,SAASY,QAAQ,CAAC7B,UAAU;gBAAEE,MAAM,CAAC,UAAU,EAAEG,QAAQD,GAAG,EAAE;gBAAEQ,YAAY;YAAK;YACjFyC,MAAMxB,QAAQ,CAAC7B,UAAU;gBAAEE,MAAM;gBAAeU,YAAY;oBAAEC,SAAS;gBAAc;YAAE;YACvFI,SAASY,QAAQ,CAAC7B,UAAU;gBAAEE,MAAM,CAAC,UAAU,EAAEG,QAAQD,GAAG,EAAE;gBAAEQ,YAAY;YAAK;YAEjFkB,OAAOb,SAASiB,IAAI,IAAIE,YAAY,CAAC;YACrCN,OAAOb,SAASwB,MAAM,CAAC,gBAAgBrC,KAAK6B,IAAI,CAAC5B,QAAQD,GAAG;QAC9D;QAEAwB,GAAG,2DAA2D;YAC5DX,SAASY,QAAQ,CAAC7B,UAAU;gBAAEE,MAAM;gBAAcC,MAAM;gBAAUC,KAAKC,QAAQD,GAAG;YAAC;YAEnFa,SAASY,QAAQ,CACf7B,UAAU;gBACRE,MAAM;gBACNC,MAAM;gBACNC,KAAKC,QAAQD,GAAG;gBAChBQ,YAAY;YACd;YAGFkB,OAAOb,SAASwB,MAAM,CAAC,eAAeE,QAAQ;YAC9Cb,OAAOb,SAASwB,MAAM,CAAC,cAAcC,aAAa,CAAC;gBAAEvC,MAAM;gBAASC,KAAKC,QAAQD,GAAG;YAAC;YACrF0B,OAAOb,SAASiB,IAAI,IAAIE,YAAY,CAAC;QACvC;QAEAR,GAAG,0EAA0E;YAC3EX,SAASY,QAAQ,CAAC7B,UAAU;gBAAEE,MAAM;gBAASE,KAAKC,QAAQD,GAAG;YAAC;YAE9D0B,OAAO,IACLb,SAASmC,aAAa,CAAC;oBACrBpD,UAAU;wBAAEE,MAAM;wBAASE,KAAK;oBAAO;oBACvCJ,UAAU;wBAAEE,MAAM;wBAASC,MAAM;wBAASC,KAAK;oBAAO;iBACvD,GACD+C,OAAO,CAAC;YAEVrB,OAAOb,SAASwB,MAAM,CAAC,UAAUE,QAAQ;YACzCb,OAAOb,SAASwB,MAAM,CAAC,UAAUrC,KAAK6B,IAAI,CAAC5B,QAAQD,GAAG;QACxD;IACF;IAEAU,SAAS,UAAU;QACjBc,GAAG,oCAAoC;YACrCE,OAAOb,SAASwB,MAAM,CAAC,YAAYE,QAAQ;QAC7C;QAEAf,GAAG,uCAAuC;YACxCX,SAASY,QAAQ,CAAC7B,UAAU;gBAAEE,MAAM;YAAI;YACxC4B,OAAOb,SAASwB,MAAM,CAAC,MAAMvC,MAAM+B,IAAI,CAAC;QAC1C;IACF;IAEAnB,SAAS,WAAW;QAClBc,GAAG,iEAAiE;YAClEX,SAASY,QAAQ,CAAC7B;YAElB8B,OAAOb,SAASwB,MAAM,CAAC,WAAW/B,QAAQuB,IAAI,CAAC;YAC/CH,OAAOb,SAASqC,SAAS,CAAC,UAAUjD,QAAQD,GAAG,GAAG6B,IAAI,CAAC;YACvDH,OAAOb,SAASwB,MAAM,CAAC,WAAW/B,QAAQuB,IAAI,CAAC;YAC/CH,OAAOb,SAASqC,SAAS,CAAC,UAAUjD,QAAQD,GAAG,GAAG6B,IAAI,CAAC;YACvDH,OAAOb,SAASwB,MAAM,CAAC,WAAW/B,QAAQuB,IAAI,CAAC;QACjD;QAEAL,GAAG,yCAAyC;YAC1C,IAAI2B,MAAM,IAAIC,KAAK;YACnB,MAAMC,UAAU,IAAI5D,cAAcmB,SAAS;gBAAEuC,KAAK,IAAMA;YAAI;YAC5DE,QAAQ5B,QAAQ,CAAC7B;YACjBuD,MAAM,IAAIC,KAAK;YAEfC,QAAQH,SAAS,CAAC,UAAUjD,QAAQD,GAAG;YAEvC0B,OAAO2B,QAAQhB,MAAM,CAAC,WAAWiB,WAAWzB,IAAI,CAACsB,IAAII,WAAW;YAChE,MAAMC,KAAK,IAAIhE,SAASoB,QAAQgB,OAAO,CAAC,WAAW,QAAQ;gBAAE6B,UAAU;YAAK;YAC5E,MAAMC,MAAMF,GACTG,OAAO,CAAC,4DACRC,GAAG,CAAC,UAAU3D,QAAQD,GAAG;YAC5BwD,GAAGK,KAAK;YACRnC,OAAOgC,IAAII,UAAU,EAAEjC,IAAI,CAACsB,IAAII,WAAW;QAC7C;QAEA/B,GAAG,qDAAqD;YACtDE,OAAOb,SAASqC,SAAS,CAAC,UAAU,SAASX,QAAQ;QACvD;QAEAf,GAAG,0DAA0D;YAC3DX,SAASY,QAAQ,CAAC7B,UAAU;gBAAEQ,WAAW;YAAS;YAClDS,SAASqC,SAAS,CAAC,UAAUjD,QAAQD,GAAG;YAExCa,SAASY,QAAQ,CAAC7B,UAAU;gBAAEQ,WAAW;YAAQ;YAEjDsB,OAAOb,SAASwB,MAAM,CAAC,WAAWC,aAAa,CAAC;gBAAElC,WAAW;gBAASE,QAAQ;YAAK;QACrF;QAEAkB,GAAG,kCAAkC;YACnCX,SAASY,QAAQ,CAAC7B,UAAU;gBAAEE,MAAM;YAAS;YAC7Ce,SAASqC,SAAS,CAAC,UAAUjD,QAAQD,GAAG;YAExCa,SAASkD,MAAM,CAAC,UAAU;YAE1BrC,OAAOb,SAASwB,MAAM,CAAC,UAAU/B,QAAQuB,IAAI,CAAC;QAChD;QAEAL,GAAG,6CAA6C;YAC9CX,SAASY,QAAQ,CAAC7B,UAAU;gBAAEI,KAAK;YAAO;YAC1Ca,SAASqC,SAAS,CAAC,UAAU;YAE7BrC,SAASmD,KAAK;YAEdtC,OAAOb,SAASwB,MAAM,CAAC,WAAWE,QAAQ;QAC5C;QAEAf,GAAG,gEAAgE;YACjEX,SAASY,QAAQ,CAAC7B;YAClB,MAAMqE,mBAAmB,IAAIxE,cAAcmB,SAAS;gBAAE6C,UAAU;YAAK;YAErE/B,OAAO,IAAMuC,iBAAiBf,SAAS,CAAC,UAAUjD,QAAQD,GAAG,GAAG+C,OAAO,CAAC;QAC1E;IACF;IAEArC,SAAS,QAAQ;QACfc,GAAG,8DAA8D;YAC/DE,OAAOb,SAASiB,IAAI,IAAIU,OAAO,CAAC,EAAE;QACpC;QAEAhB,GAAG,+CAA+C;YAChD,MAAM0C,cAActE,UAAU;gBAAEE,MAAM;gBAAUU,YAAY;oBAAEC,SAAS;gBAAS;YAAE;YAClFpB,GAAG8E,SAAS,CAAC5E,KAAK6E,OAAO,CAACxD,UAAU;gBAAEU,WAAW;YAAK;YACtDjC,GAAGgF,aAAa,CAACzD,SAAS0D,KAAKC,SAAS,CAAC;gBAAEC,SAAS;oBAACN;iBAAY;YAAC,IAAI;YAEtE,MAAMO,iBAAiB,IAAIhF,cAAcmB;YAEzCc,OAAO+C,eAAepC,MAAM,CAAC,WAAWE,QAAQ;YAChDb,OAAO+C,eAAe3C,IAAI,IAAIU,OAAO,CAAC,EAAE;YACxCd,OAAOrC,GAAGsC,UAAU,CAACf,QAAQgB,OAAO,CAAC,WAAW,SAASC,IAAI,CAAC;QAChE;QAEAL,GAAG,wDAAwD;YACzD,MAAMkD,SAAS9D,QAAQgB,OAAO,CAAC,WAAW;YAC1CvC,GAAG8E,SAAS,CAAC5E,KAAK6E,OAAO,CAACM,SAAS;gBAAEpD,WAAW;YAAK;YACrDjC,GAAGgC,MAAM,CAACqD,QAAQ;gBAAEnD,OAAO;YAAK;YAChClC,GAAGgC,MAAM,CAAC,GAAGqD,OAAO,IAAI,CAAC,EAAE;gBAAEnD,OAAO;YAAK;YACzClC,GAAGgC,MAAM,CAAC,GAAGqD,OAAO,IAAI,CAAC,EAAE;gBAAEnD,OAAO;YAAK;YACzC,MAAMiC,KAAK,IAAIhE,SAASkF;YACxBlB,GAAGmB,IAAI,CAAC,CAAC;;;;;;;;;;;;;;;;8BAgBe,EAAE1E,QAAQD,GAAG,CAAC;;;;YAIhC,CAAC;YACPwD,GAAGK,KAAK;YAER,MAAMe,mBAAmB,IAAInF,cAAcmB;YAE3Cc,OAAOkD,iBAAiBvC,MAAM,CAAC,kBAAkBC,aAAa,CAAC;gBAC7D/B,SAAS;gBACTC,YAAY;oBAAEC,SAAS;gBAAgB;YACzC;QACF;IACF;IAEAC,SAAS,WAAW;QAClBc,GAAG,wCAAwC;YACzCE,OAAOb,SAASgE,OAAO,CAACjF,UAAU;gBAAEI,KAAKC,QAAQD,GAAG;YAAC,KAAK6B,IAAI,CAAC;QACjE;QAEAL,GAAG,+CAA+C;YAChDE,OAAOb,SAASgE,OAAO,CAACjF,UAAU;gBAAEI,KAAK;YAAO,KAAK6B,IAAI,CAAC;QAC5D;QAEAL,GAAG,+DAA+D;YAChEL,GAAGsB,KAAK,CAACxC,SAAS,QAAQyC,kBAAkB,CAAC;gBAC3C,MAAMC,OAAOC,MAAM,CAAC,IAAIC,MAAM,4BAA4B;oBAAEC,MAAM;gBAAQ;YAC5E;YAEApB,OAAOb,SAASgE,OAAO,CAACjF,cAAciC,IAAI,CAAC;QAC7C;QAEAL,GAAG,sDAAsD;YACvDL,GAAGsB,KAAK,CAACxC,SAAS,QAAQyC,kBAAkB,CAAC;gBAC3C,MAAMC,OAAOC,MAAM,CAAC,IAAIC,MAAM,oBAAoB;oBAAEC,MAAM;gBAAQ;YACpE;YAEApB,OAAOb,SAASgE,OAAO,CAACjF,cAAciC,IAAI,CAAC;QAC7C;QAEAL,GAAG,6EAA6E;YAC9EL,GAAGsB,KAAK,CAACxC,SAAS,QAAQyC,kBAAkB,CAAC;gBAC3C,MAAM,IAAIG,MAAM;YAClB;YAEAnB,OAAOb,SAASgE,OAAO,CAACjF,cAAciC,IAAI,CAAC;QAC7C;IACF;IAEAnB,SAAS,SAAS;QAChBc,GAAG,uCAAuC;YACxCX,SAASY,QAAQ,CAAC7B,UAAU;gBAAEE,MAAM;gBAASE,KAAKC,QAAQD,GAAG;YAAC;YAC9Da,SAASY,QAAQ,CAAC7B,UAAU;gBAAEE,MAAM;gBAAQE,KAAK;YAAO;YACxDa,SAASmD,KAAK;YACd,MAAMc,YAAYjE,SAASiB,IAAI;YAC/BJ,OAAOoD,WAAW9C,YAAY,CAAC;YAC/BN,OAAOoD,SAAS,CAAC,EAAE,CAAChF,IAAI,EAAE+B,IAAI,CAAC;QACjC;QAEAL,GAAG,yCAAyC;YAC1CX,SAASY,QAAQ,CAAC7B,UAAU;gBAAEI,KAAKC,QAAQD,GAAG;YAAC;YAC/C,MAAM+E,SAASlE,SAASiB,IAAI;YAC5BjB,SAASmD,KAAK;YACd,MAAMgB,QAAQnE,SAASiB,IAAI;YAC3BJ,OAAOsD,OAAOxC,OAAO,CAACuC;QACxB;QAEAvD,GAAG,4DAA4D;YAC7DX,SAASY,QAAQ,CAAC7B,UAAU;gBAAEE,MAAM;gBAAeU,YAAY;oBAAEC,SAAS;gBAAc;YAAE;YAC1FU,GAAGsB,KAAK,CAACxC,SAAS,QAAQyC,kBAAkB,CAAC;gBAC3C,MAAMC,OAAOC,MAAM,CAAC,IAAIC,MAAM,4BAA4B;oBAAEC,MAAM;gBAAQ;YAC5E;YAEAjC,SAASmD,KAAK;YAEdtC,OAAOb,SAASwB,MAAM,CAAC,gBAAgBC,aAAa,CAAC;gBACnDxC,MAAM;gBACNU,YAAY;oBAAEC,SAAS;gBAAc;YACvC;QACF;QAEAe,GAAG,0DAA0D;YAC3DX,SAASY,QAAQ,CAAC7B,UAAU;gBAAEE,MAAM;YAAO;YAC3CqB,GAAGsB,KAAK,CAACxC,SAAS,QAAQyC,kBAAkB,CAAC;gBAC3C,MAAMC,OAAOC,MAAM,CAAC,IAAIC,MAAM,oBAAoB;oBAAEC,MAAM;gBAAQ;YACpE;YAEAjC,SAASmD,KAAK;YAEdtC,OAAOb,SAASwB,MAAM,CAAC,SAASE,QAAQ;QAC1C;QAEAf,GAAG,qCAAqC;YACtCE,OAAO,IAAMb,SAASmD,KAAK,IAAIiB,GAAG,CAAClC,OAAO;QAC5C;QAEAvB,GAAG,kEAAkE;YACnE,IAAI0D,QAAQ9B,KAAK+B,KAAK,CAAC;YACvB,MAAM9B,UAAU,IAAI5D,cAAcmB,SAAS;gBACzCuC,KAAK,IAAM,IAAIC,KAAK8B;gBACpBE,iBAAiB;YACnB;YACA/B,QAAQ5B,QAAQ,CAAC7B,UAAU;gBAAEE,MAAM;gBAAUE,KAAKC,QAAQD,GAAG;YAAC;YAC9D,MAAMqF,QAAQlE,GAAGsB,KAAK,CAACY,SAAS,WAAWiC,eAAe,CAAC;YAC3DjC,QAAQkC,UAAU;YAClBF,MAAMC,eAAe,CAAC;YACtBJ,SAAS;YAET7B,QAAQW,KAAK;YAEbtC,OAAO2D,OAAOG,qBAAqB,CAAC;YACpC9D,OAAO2B,QAAQhB,MAAM,CAAC,WAAWE,QAAQ;QAC3C;IACF;IAEA7B,SAAS,aAAa;QACpBc,GAAG,gCAAgC;YACjCE,OAAOjC,cAAcgG,OAAO,IAAI5D,IAAI,CAACpC,cAAcgG,OAAO;QAC5D;IACF;IAEA/E,SAAS,UAAU;QACjBc,GAAG,yCAAyC;YAC1CX,SAASY,QAAQ,CAAC7B,UAAU;gBAAEE,MAAM;gBAAYE,KAAKC,QAAQD,GAAG;YAAC;YACjEa,SAASkD,MAAM,CAAC,YAAY;YAC5BrC,OAAOb,SAASwB,MAAM,CAAC,aAAavC,MAAM+B,IAAI,CAAC;YAC/CH,OAAOb,SAASwB,MAAM,CAAC,aAAaE,QAAQ;QAC9C;QAEAf,GAAG,mDAAmD;YACpDX,SAASY,QAAQ,CACf7B,UAAU;gBACRE,MAAM;gBACNE,KAAKC,QAAQD,GAAG;gBAChBQ,YAAY;oBAAEC,SAAS;gBAAW;gBAClCP,KAAK;YACP;YAEFW,SAASkD,MAAM,CAAC,YAAY;YAC5B,MAAM2B,QAAQ7E,SAASwB,MAAM,CAAC;YAC9BX,OAAOgE,OAAOlF,YAAYgC,OAAO,CAAC;gBAAE/B,SAAS;YAAW;YACxDiB,OAAOgE,OAAOxF,KAAK2B,IAAI,CAAC;YACxBH,OAAOgE,OAAO1F,KAAK6B,IAAI,CAAC5B,QAAQD,GAAG;QACrC;QAEAwB,GAAG,+DAA+D;YAChEE,OAAO,IAAMb,SAASkD,MAAM,CAAC,SAAS,aAAahB,OAAO,CAACrD;QAC7D;QAEA8B,GAAG,8EAA8E;YAC/EX,SAASY,QAAQ,CAAC7B,UAAU;gBAAEE,MAAM;gBAAWE,KAAKC,QAAQD,GAAG;YAAC;YAChEa,SAASY,QAAQ,CAAC7B,UAAU;gBAAEE,MAAM;gBAAWE,KAAKC,QAAQ8B,IAAI;YAAC;YACjEL,OAAO,IAAMb,SAASkD,MAAM,CAAC,WAAW,YAAYhB,OAAO,CAACpD;QAC9D;QAEA6B,GAAG,gFAAgF;YACjFX,SAASY,QAAQ,CAAC7B,UAAU;gBAAEE,MAAM;gBAAWE,KAAKC,QAAQD,GAAG;YAAC;YAChEa,SAASY,QAAQ,CAAC7B,UAAU;gBAAEE,MAAM;gBAAWE,KAAKC,QAAQ8B,IAAI;YAAC;YACjEZ,GAAGsB,KAAK,CAACxC,SAAS,QAAQyC,kBAAkB,CAAC;gBAC3C,MAAMC,OAAOC,MAAM,CAAC,IAAIC,MAAM,4BAA4B;oBAAEC,MAAM;gBAAQ;YAC5E;YAEApB,OAAO,IAAMb,SAASkD,MAAM,CAAC,WAAW,YAAYhB,OAAO,CAACpD;YAC5D+B,OAAOb,SAASwB,MAAM,CAAC,YAAYrC,KAAK6B,IAAI,CAAC5B,QAAQ8B,IAAI;QAC3D;QAEAP,GAAG,8DAA8D;YAC/DX,SAASY,QAAQ,CAAC7B,UAAU;gBAAEE,MAAM;gBAAWE,KAAKC,QAAQD,GAAG;YAAC;YAChEa,SAASY,QAAQ,CAAC7B,UAAU;gBAAEE,MAAM;gBAAWE,KAAK;YAAO;YAC3D0B,OAAO,IAAMb,SAASkD,MAAM,CAAC,WAAW,YAAYkB,GAAG,CAAClC,OAAO;YAC/DrB,OAAOb,SAASwB,MAAM,CAAC,YAAYrC,KAAK6B,IAAI,CAAC5B,QAAQD,GAAG;QAC1D;QAEAwB,GAAG,wDAAwD;YACzDX,SAASY,QAAQ,CAAC7B,UAAU;gBAAEE,MAAM;gBAAYE,KAAKC,QAAQD,GAAG;YAAC;YACjEa,SAASkD,MAAM,CAAC,YAAY;YAC5BrC,OAAOrC,GAAGsC,UAAU,CAAC,GAAGf,QAAQ,IAAI,CAAC,GAAGiB,IAAI,CAAC;QAC/C;IACF;AACF"}
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Tests for providers/claude/ClaudeSessionParser.ts — focused on stripping
|
|
3
3
|
* harness-injected XML tags from conversation content.
|
|
4
|
-
*/ import * as fs from
|
|
5
|
-
import * as os from
|
|
6
|
-
import * as path from
|
|
7
|
-
import { ClaudeSessionParser } from
|
|
4
|
+
*/ import * as fs from "fs";
|
|
5
|
+
import * as os from "os";
|
|
6
|
+
import * as path from "path";
|
|
7
|
+
import { ClaudeSessionParser } from "../../providers/claude/ClaudeSessionParser.js";
|
|
8
8
|
function writeSession(entries) {
|
|
9
|
-
const dir = fs.mkdtempSync(path.join(os.tmpdir(),
|
|
10
|
-
const filePath = path.join(dir,
|
|
11
|
-
fs.writeFileSync(filePath, entries.map((e)=>JSON.stringify(e)).join(
|
|
9
|
+
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "parser-test-"));
|
|
10
|
+
const filePath = path.join(dir, "session.jsonl");
|
|
11
|
+
fs.writeFileSync(filePath, entries.map((e)=>JSON.stringify(e)).join("\n"));
|
|
12
12
|
return filePath;
|
|
13
13
|
}
|
|
14
|
-
describe(
|
|
14
|
+
describe("ClaudeSessionParser.getConversation — harness tag stripping", ()=>{
|
|
15
15
|
let parser;
|
|
16
16
|
const tempFiles = [];
|
|
17
17
|
beforeEach(()=>{
|
|
@@ -24,7 +24,8 @@ describe('ClaudeSessionParser.getConversation — harness tag stripping', ()=>{
|
|
|
24
24
|
recursive: true,
|
|
25
25
|
force: true
|
|
26
26
|
});
|
|
27
|
-
} catch {
|
|
27
|
+
} catch {
|
|
28
|
+
/* best effort */ }
|
|
28
29
|
}
|
|
29
30
|
tempFiles.length = 0;
|
|
30
31
|
});
|
|
@@ -33,15 +34,15 @@ describe('ClaudeSessionParser.getConversation — harness tag stripping', ()=>{
|
|
|
33
34
|
tempFiles.push(f);
|
|
34
35
|
return f;
|
|
35
36
|
}
|
|
36
|
-
it(
|
|
37
|
+
it("strips <system-reminder> blocks from text content", ()=>{
|
|
37
38
|
const file = makeSession([
|
|
38
39
|
{
|
|
39
|
-
type:
|
|
40
|
+
type: "assistant",
|
|
40
41
|
message: {
|
|
41
42
|
content: [
|
|
42
43
|
{
|
|
43
|
-
type:
|
|
44
|
-
text:
|
|
44
|
+
type: "text",
|
|
45
|
+
text: "Real response here.\n<system-reminder>\nDo not mention this reminder.\n</system-reminder>\nMore response."
|
|
45
46
|
}
|
|
46
47
|
]
|
|
47
48
|
}
|
|
@@ -49,124 +50,124 @@ describe('ClaudeSessionParser.getConversation — harness tag stripping', ()=>{
|
|
|
49
50
|
]);
|
|
50
51
|
const conv = parser.getConversation(file);
|
|
51
52
|
expect(conv).toHaveLength(1);
|
|
52
|
-
expect(conv[0].content).toBe(
|
|
53
|
+
expect(conv[0].content).toBe("Real response here.\n\nMore response.");
|
|
53
54
|
});
|
|
54
|
-
it(
|
|
55
|
+
it("strips <local-command-stdout> blocks", ()=>{
|
|
55
56
|
const file = makeSession([
|
|
56
57
|
{
|
|
57
|
-
type:
|
|
58
|
+
type: "system",
|
|
58
59
|
message: {
|
|
59
|
-
content:
|
|
60
|
+
content: "before <local-command-stdout>\nRunning...\nDone\n</local-command-stdout> after"
|
|
60
61
|
}
|
|
61
62
|
}
|
|
62
63
|
]);
|
|
63
64
|
const conv = parser.getConversation(file);
|
|
64
|
-
expect(conv[0].content).toBe(
|
|
65
|
+
expect(conv[0].content).toBe("before after");
|
|
65
66
|
});
|
|
66
|
-
it(
|
|
67
|
+
it("strips <user-prompt-submit-hook> blocks", ()=>{
|
|
67
68
|
const file = makeSession([
|
|
68
69
|
{
|
|
69
|
-
type:
|
|
70
|
+
type: "user",
|
|
70
71
|
message: {
|
|
71
|
-
content:
|
|
72
|
+
content: "<user-prompt-submit-hook>hook output</user-prompt-submit-hook>\nactual question"
|
|
72
73
|
}
|
|
73
74
|
}
|
|
74
75
|
]);
|
|
75
76
|
const conv = parser.getConversation(file);
|
|
76
|
-
expect(conv[0].content).toBe(
|
|
77
|
+
expect(conv[0].content).toBe("actual question");
|
|
77
78
|
});
|
|
78
|
-
it(
|
|
79
|
+
it("strips bash and command stdout/stderr blocks", ()=>{
|
|
79
80
|
const file = makeSession([
|
|
80
81
|
{
|
|
81
|
-
type:
|
|
82
|
+
type: "assistant",
|
|
82
83
|
message: {
|
|
83
84
|
content: [
|
|
84
85
|
{
|
|
85
|
-
type:
|
|
86
|
-
text:
|
|
86
|
+
type: "text",
|
|
87
|
+
text: "Output:\n<bash-input>ls</bash-input>\n<bash-stdout>file.txt</bash-stdout>\n<bash-stderr></bash-stderr>\n<command-stdout>x</command-stdout>\n<command-stderr>y</command-stderr>\nEnd."
|
|
87
88
|
}
|
|
88
89
|
]
|
|
89
90
|
}
|
|
90
91
|
}
|
|
91
92
|
]);
|
|
92
93
|
const conv = parser.getConversation(file);
|
|
93
|
-
expect(conv[0].content).toBe(
|
|
94
|
+
expect(conv[0].content).toBe("Output:\n\n\n\n\n\nEnd.".replace(/\n{3,}/g, "\n\n"));
|
|
94
95
|
expect(conv[0].content).not.toMatch(/<bash-/);
|
|
95
96
|
expect(conv[0].content).not.toMatch(/<command-stdout>|<command-stderr>/);
|
|
96
97
|
});
|
|
97
98
|
it('collapses <command-name>/<command-args> into "/name args" shorthand', ()=>{
|
|
98
99
|
const file = makeSession([
|
|
99
100
|
{
|
|
100
|
-
type:
|
|
101
|
+
type: "user",
|
|
101
102
|
message: {
|
|
102
|
-
content:
|
|
103
|
+
content: "<command-message>debug</command-message>\n<command-name>/debug</command-name>\n<command-args>fix the bug</command-args>"
|
|
103
104
|
}
|
|
104
105
|
}
|
|
105
106
|
]);
|
|
106
107
|
const conv = parser.getConversation(file);
|
|
107
|
-
expect(conv[0].content).toBe(
|
|
108
|
+
expect(conv[0].content).toBe("/debug fix the bug");
|
|
108
109
|
});
|
|
109
|
-
it(
|
|
110
|
+
it("handles <command-name> without <command-args>", ()=>{
|
|
110
111
|
const file = makeSession([
|
|
111
112
|
{
|
|
112
|
-
type:
|
|
113
|
+
type: "user",
|
|
113
114
|
message: {
|
|
114
|
-
content:
|
|
115
|
+
content: "<command-message>clear</command-message>\n<command-name>/clear</command-name>"
|
|
115
116
|
}
|
|
116
117
|
}
|
|
117
118
|
]);
|
|
118
119
|
const conv = parser.getConversation(file);
|
|
119
|
-
expect(conv[0].content).toBe(
|
|
120
|
+
expect(conv[0].content).toBe("/clear");
|
|
120
121
|
});
|
|
121
|
-
it(
|
|
122
|
+
it("handles multiple harness tags mixed together", ()=>{
|
|
122
123
|
const file = makeSession([
|
|
123
124
|
{
|
|
124
|
-
type:
|
|
125
|
+
type: "user",
|
|
125
126
|
message: {
|
|
126
127
|
content: [
|
|
127
128
|
{
|
|
128
|
-
type:
|
|
129
|
-
text:
|
|
129
|
+
type: "text",
|
|
130
|
+
text: "<system-reminder>ignore me</system-reminder>\n<command-message>build</command-message>\n<command-name>/build</command-name>\n<command-args>--watch</command-args>\n<local-command-stdout>build output here</local-command-stdout>"
|
|
130
131
|
}
|
|
131
132
|
]
|
|
132
133
|
}
|
|
133
134
|
}
|
|
134
135
|
]);
|
|
135
136
|
const conv = parser.getConversation(file);
|
|
136
|
-
expect(conv[0].content).toBe(
|
|
137
|
+
expect(conv[0].content).toBe("/build --watch");
|
|
137
138
|
});
|
|
138
|
-
it(
|
|
139
|
+
it("leaves text without harness tags unchanged", ()=>{
|
|
139
140
|
const file = makeSession([
|
|
140
141
|
{
|
|
141
|
-
type:
|
|
142
|
+
type: "assistant",
|
|
142
143
|
message: {
|
|
143
144
|
content: [
|
|
144
145
|
{
|
|
145
|
-
type:
|
|
146
|
-
text:
|
|
146
|
+
type: "text",
|
|
147
|
+
text: "Hello, world!"
|
|
147
148
|
}
|
|
148
149
|
]
|
|
149
150
|
}
|
|
150
151
|
}
|
|
151
152
|
]);
|
|
152
153
|
const conv = parser.getConversation(file);
|
|
153
|
-
expect(conv[0].content).toBe(
|
|
154
|
+
expect(conv[0].content).toBe("Hello, world!");
|
|
154
155
|
});
|
|
155
|
-
it(
|
|
156
|
+
it("drops a message that becomes empty after stripping", ()=>{
|
|
156
157
|
const file = makeSession([
|
|
157
158
|
{
|
|
158
|
-
type:
|
|
159
|
+
type: "system",
|
|
159
160
|
message: {
|
|
160
|
-
content:
|
|
161
|
+
content: "<system-reminder>only this</system-reminder>"
|
|
161
162
|
}
|
|
162
163
|
},
|
|
163
164
|
{
|
|
164
|
-
type:
|
|
165
|
+
type: "assistant",
|
|
165
166
|
message: {
|
|
166
167
|
content: [
|
|
167
168
|
{
|
|
168
|
-
type:
|
|
169
|
-
text:
|
|
169
|
+
type: "text",
|
|
170
|
+
text: "kept"
|
|
170
171
|
}
|
|
171
172
|
]
|
|
172
173
|
}
|
|
@@ -174,17 +175,17 @@ describe('ClaudeSessionParser.getConversation — harness tag stripping', ()=>{
|
|
|
174
175
|
]);
|
|
175
176
|
const conv = parser.getConversation(file);
|
|
176
177
|
expect(conv).toHaveLength(1);
|
|
177
|
-
expect(conv[0].content).toBe(
|
|
178
|
+
expect(conv[0].content).toBe("kept");
|
|
178
179
|
});
|
|
179
|
-
it(
|
|
180
|
-
const multilineReminder =
|
|
180
|
+
it("strips tags spanning multiple lines", ()=>{
|
|
181
|
+
const multilineReminder = "<system-reminder>\nLine 1\nLine 2\nLine 3\n</system-reminder>";
|
|
181
182
|
const file = makeSession([
|
|
182
183
|
{
|
|
183
|
-
type:
|
|
184
|
+
type: "assistant",
|
|
184
185
|
message: {
|
|
185
186
|
content: [
|
|
186
187
|
{
|
|
187
|
-
type:
|
|
188
|
+
type: "text",
|
|
188
189
|
text: `before\n${multilineReminder}\nafter`
|
|
189
190
|
}
|
|
190
191
|
]
|
|
@@ -192,10 +193,10 @@ describe('ClaudeSessionParser.getConversation — harness tag stripping', ()=>{
|
|
|
192
193
|
}
|
|
193
194
|
]);
|
|
194
195
|
const conv = parser.getConversation(file);
|
|
195
|
-
expect(conv[0].content).toBe(
|
|
196
|
+
expect(conv[0].content).toBe("before\n\nafter");
|
|
196
197
|
});
|
|
197
198
|
});
|
|
198
|
-
describe(
|
|
199
|
+
describe("ClaudeSessionParser.readSession — UI-state entries ignored for status", ()=>{
|
|
199
200
|
let parser;
|
|
200
201
|
const tempFiles = [];
|
|
201
202
|
beforeEach(()=>{
|
|
@@ -208,104 +209,105 @@ describe('ClaudeSessionParser.readSession — UI-state entries ignored for statu
|
|
|
208
209
|
recursive: true,
|
|
209
210
|
force: true
|
|
210
211
|
});
|
|
211
|
-
} catch {
|
|
212
|
+
} catch {
|
|
213
|
+
/* best effort */ }
|
|
212
214
|
}
|
|
213
215
|
tempFiles.length = 0;
|
|
214
216
|
});
|
|
215
217
|
function writeRawSession(lines) {
|
|
216
|
-
const dir = fs.mkdtempSync(path.join(os.tmpdir(),
|
|
217
|
-
const filePath = path.join(dir,
|
|
218
|
-
fs.writeFileSync(filePath, lines.map((l)=>JSON.stringify(l)).join(
|
|
218
|
+
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "parser-status-"));
|
|
219
|
+
const filePath = path.join(dir, "session.jsonl");
|
|
220
|
+
fs.writeFileSync(filePath, lines.map((l)=>JSON.stringify(l)).join("\n"));
|
|
219
221
|
tempFiles.push(filePath);
|
|
220
222
|
return filePath;
|
|
221
223
|
}
|
|
222
224
|
const uiStateTypes = [
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
225
|
+
"attachment",
|
|
226
|
+
"permission-mode",
|
|
227
|
+
"ai-title",
|
|
228
|
+
"queued_command",
|
|
229
|
+
"tools_changed",
|
|
230
|
+
"model_changed",
|
|
231
|
+
"hook_progress"
|
|
230
232
|
];
|
|
231
233
|
for (const uiType of uiStateTypes){
|
|
232
234
|
it(`keeps lastEntryType from previous conversation turn when trailing entry is ${uiType}`, ()=>{
|
|
233
235
|
const file = writeRawSession([
|
|
234
236
|
{
|
|
235
|
-
type:
|
|
236
|
-
timestamp:
|
|
237
|
+
type: "user",
|
|
238
|
+
timestamp: "2026-05-30T06:17:57.189Z",
|
|
237
239
|
message: {
|
|
238
|
-
content:
|
|
240
|
+
content: "hello"
|
|
239
241
|
}
|
|
240
242
|
},
|
|
241
243
|
{
|
|
242
244
|
type: uiType,
|
|
243
|
-
timestamp:
|
|
245
|
+
timestamp: "2026-05-30T06:17:57.201Z"
|
|
244
246
|
}
|
|
245
247
|
]);
|
|
246
|
-
const session = parser.readSession(file,
|
|
247
|
-
expect(session?.lastEntryType).toBe(
|
|
248
|
+
const session = parser.readSession(file, "/test");
|
|
249
|
+
expect(session?.lastEntryType).toBe("user");
|
|
248
250
|
});
|
|
249
251
|
}
|
|
250
|
-
it(
|
|
252
|
+
it("keeps lastEntryType from a user turn even with multiple trailing UI-state entries", ()=>{
|
|
251
253
|
const file = writeRawSession([
|
|
252
254
|
{
|
|
253
|
-
type:
|
|
254
|
-
timestamp:
|
|
255
|
+
type: "user",
|
|
256
|
+
timestamp: "2026-05-30T06:17:57.189Z",
|
|
255
257
|
message: {
|
|
256
|
-
content:
|
|
258
|
+
content: "hello"
|
|
257
259
|
}
|
|
258
260
|
},
|
|
259
261
|
{
|
|
260
|
-
type:
|
|
261
|
-
timestamp:
|
|
262
|
+
type: "attachment",
|
|
263
|
+
timestamp: "2026-05-30T06:17:57.200Z",
|
|
262
264
|
attachment: {
|
|
263
|
-
type:
|
|
265
|
+
type: "task_reminder",
|
|
264
266
|
content: []
|
|
265
267
|
}
|
|
266
268
|
},
|
|
267
269
|
{
|
|
268
|
-
type:
|
|
269
|
-
timestamp:
|
|
270
|
-
permissionMode:
|
|
270
|
+
type: "permission-mode",
|
|
271
|
+
timestamp: "2026-05-30T06:17:57.210Z",
|
|
272
|
+
permissionMode: "default"
|
|
271
273
|
},
|
|
272
274
|
{
|
|
273
|
-
type:
|
|
274
|
-
timestamp:
|
|
275
|
+
type: "ai-title",
|
|
276
|
+
timestamp: "2026-05-30T06:17:57.220Z"
|
|
275
277
|
}
|
|
276
278
|
]);
|
|
277
|
-
const session = parser.readSession(file,
|
|
278
|
-
expect(session?.lastEntryType).toBe(
|
|
279
|
+
const session = parser.readSession(file, "/test");
|
|
280
|
+
expect(session?.lastEntryType).toBe("user");
|
|
279
281
|
});
|
|
280
|
-
it(
|
|
282
|
+
it("keeps lastEntryType from assistant turn when followed by UI-state events", ()=>{
|
|
281
283
|
const file = writeRawSession([
|
|
282
284
|
{
|
|
283
|
-
type:
|
|
284
|
-
timestamp:
|
|
285
|
+
type: "user",
|
|
286
|
+
timestamp: "2026-05-30T06:17:00.000Z",
|
|
285
287
|
message: {
|
|
286
|
-
content:
|
|
288
|
+
content: "go"
|
|
287
289
|
}
|
|
288
290
|
},
|
|
289
291
|
{
|
|
290
|
-
type:
|
|
291
|
-
timestamp:
|
|
292
|
+
type: "assistant",
|
|
293
|
+
timestamp: "2026-05-30T06:17:01.000Z",
|
|
292
294
|
message: {
|
|
293
295
|
content: [
|
|
294
296
|
{
|
|
295
|
-
type:
|
|
296
|
-
text:
|
|
297
|
+
type: "text",
|
|
298
|
+
text: "done"
|
|
297
299
|
}
|
|
298
300
|
]
|
|
299
301
|
}
|
|
300
302
|
},
|
|
301
303
|
{
|
|
302
|
-
type:
|
|
303
|
-
timestamp:
|
|
304
|
-
permissionMode:
|
|
304
|
+
type: "permission-mode",
|
|
305
|
+
timestamp: "2026-05-30T06:17:02.000Z",
|
|
306
|
+
permissionMode: "default"
|
|
305
307
|
}
|
|
306
308
|
]);
|
|
307
|
-
const session = parser.readSession(file,
|
|
308
|
-
expect(session?.lastEntryType).toBe(
|
|
309
|
+
const session = parser.readSession(file, "/test");
|
|
310
|
+
expect(session?.lastEntryType).toBe("assistant");
|
|
309
311
|
});
|
|
310
312
|
});
|
|
311
313
|
|