@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,29 +1,32 @@
|
|
|
1
|
-
import fs from
|
|
2
|
-
import os from
|
|
3
|
-
import path from
|
|
4
|
-
import Database from
|
|
5
|
-
import { AgentRegistry, RenameNotFoundError, RenameConflictError } from
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import os from "os";
|
|
3
|
+
import path from "path";
|
|
4
|
+
import Database from "better-sqlite3";
|
|
5
|
+
import { AgentRegistry, RenameNotFoundError, RenameConflictError } from "../../utils/AgentRegistry.js";
|
|
6
6
|
function makeEntry(over = {}) {
|
|
7
7
|
return {
|
|
8
|
-
name:
|
|
9
|
-
type:
|
|
8
|
+
name: "agent1",
|
|
9
|
+
type: "claude",
|
|
10
10
|
pid: process.pid,
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
sessionFilePath: '/tmp/session.jsonl',
|
|
11
|
+
cwd: "/tmp",
|
|
12
|
+
startedAt: "2026-05-30T00:00:00.000Z",
|
|
13
|
+
sessionId: "sid-1",
|
|
14
|
+
sessionFilePath: "/tmp/session.jsonl",
|
|
16
15
|
pinned: false,
|
|
16
|
+
runtime: "tmux",
|
|
17
|
+
runtimeRef: {
|
|
18
|
+
session: "agent1"
|
|
19
|
+
},
|
|
17
20
|
...over
|
|
18
21
|
};
|
|
19
22
|
}
|
|
20
|
-
describe(
|
|
23
|
+
describe("AgentRegistry", ()=>{
|
|
21
24
|
let tmpDir;
|
|
22
25
|
let regPath;
|
|
23
26
|
let registry;
|
|
24
27
|
beforeEach(()=>{
|
|
25
|
-
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(),
|
|
26
|
-
regPath = path.join(tmpDir,
|
|
28
|
+
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "agent-registry-"));
|
|
29
|
+
regPath = path.join(tmpDir, "nested", "agents.json");
|
|
27
30
|
registry = new AgentRegistry(regPath);
|
|
28
31
|
});
|
|
29
32
|
afterEach(()=>{
|
|
@@ -33,276 +36,338 @@ describe('AgentRegistry', ()=>{
|
|
|
33
36
|
force: true
|
|
34
37
|
});
|
|
35
38
|
});
|
|
36
|
-
describe(
|
|
37
|
-
it(
|
|
39
|
+
describe("register", ()=>{
|
|
40
|
+
it("creates the SQLite database and parent directory if missing", ()=>{
|
|
38
41
|
registry.register(makeEntry());
|
|
39
|
-
expect(fs.existsSync(regPath.replace(/\.json$/,
|
|
40
|
-
expect(registry.list()[0].name).toBe(
|
|
42
|
+
expect(fs.existsSync(regPath.replace(/\.json$/, ".db"))).toBe(true);
|
|
43
|
+
expect(registry.list()[0].name).toBe("agent1");
|
|
41
44
|
});
|
|
42
|
-
it(
|
|
45
|
+
it("appends a new entry when name is unique", ()=>{
|
|
43
46
|
registry.register(makeEntry({
|
|
44
|
-
name:
|
|
47
|
+
name: "a"
|
|
45
48
|
}));
|
|
46
49
|
registry.register(makeEntry({
|
|
47
|
-
name:
|
|
50
|
+
name: "b",
|
|
48
51
|
pid: process.ppid
|
|
49
52
|
}));
|
|
50
53
|
expect(registry.list()).toHaveLength(2);
|
|
51
54
|
});
|
|
52
|
-
it(
|
|
55
|
+
it("upserts in place when type and pid already exist", ()=>{
|
|
53
56
|
registry.register(makeEntry({
|
|
54
|
-
name:
|
|
57
|
+
name: "a",
|
|
55
58
|
pid: process.pid
|
|
56
59
|
}));
|
|
57
60
|
registry.register(makeEntry({
|
|
58
|
-
name:
|
|
61
|
+
name: "fallback",
|
|
59
62
|
pid: process.pid,
|
|
60
|
-
|
|
63
|
+
runtimeRef: null
|
|
61
64
|
}));
|
|
62
65
|
const all = registry.list();
|
|
63
66
|
expect(all).toHaveLength(1);
|
|
64
67
|
expect(all[0].pid).toBe(process.pid);
|
|
65
|
-
expect(all[0].name).toBe(
|
|
68
|
+
expect(all[0].name).toBe("a");
|
|
66
69
|
});
|
|
67
|
-
it(
|
|
70
|
+
it("does not write through the legacy fixed .tmp path", ()=>{
|
|
68
71
|
registry.register(makeEntry());
|
|
69
72
|
expect(fs.existsSync(`${regPath}.tmp`)).toBe(false);
|
|
70
73
|
});
|
|
71
|
-
it(
|
|
74
|
+
it("persists session fields", ()=>{
|
|
72
75
|
registry.register(makeEntry({
|
|
73
|
-
sessionId:
|
|
74
|
-
sessionFilePath:
|
|
76
|
+
sessionId: "sid-xyz",
|
|
77
|
+
sessionFilePath: "/foo/bar.jsonl"
|
|
75
78
|
}));
|
|
76
79
|
const saved = registry.list()[0];
|
|
77
|
-
expect(saved.sessionId).toBe(
|
|
78
|
-
expect(saved.sessionFilePath).toBe(
|
|
80
|
+
expect(saved.sessionId).toBe("sid-xyz");
|
|
81
|
+
expect(saved.sessionFilePath).toBe("/foo/bar.jsonl");
|
|
82
|
+
});
|
|
83
|
+
it("persists runtime metadata for Herdr-backed entries", ()=>{
|
|
84
|
+
const runtimeRef = {
|
|
85
|
+
session: "default",
|
|
86
|
+
paneId: "w1:p2",
|
|
87
|
+
agentName: "reviewer"
|
|
88
|
+
};
|
|
89
|
+
registry.register(makeEntry({
|
|
90
|
+
name: "reviewer",
|
|
91
|
+
runtime: "herdr",
|
|
92
|
+
runtimeRef
|
|
93
|
+
}));
|
|
94
|
+
expect(registry.lookup("reviewer")).toMatchObject({
|
|
95
|
+
runtime: "herdr",
|
|
96
|
+
runtimeRef
|
|
97
|
+
});
|
|
79
98
|
});
|
|
80
|
-
it(
|
|
99
|
+
it("lets a Herdr managed start replace an existing same-pid name", ()=>{
|
|
100
|
+
const runtimeRef = {
|
|
101
|
+
session: "default",
|
|
102
|
+
paneId: "w1:p2",
|
|
103
|
+
agentName: "requested-name"
|
|
104
|
+
};
|
|
81
105
|
registry.register(makeEntry({
|
|
82
|
-
name:
|
|
83
|
-
|
|
106
|
+
name: "old-name",
|
|
107
|
+
pid: process.pid
|
|
84
108
|
}));
|
|
85
109
|
registry.register(makeEntry({
|
|
86
|
-
name:
|
|
87
|
-
|
|
110
|
+
name: "requested-name",
|
|
111
|
+
pid: process.pid,
|
|
112
|
+
runtime: "herdr",
|
|
113
|
+
runtimeRef
|
|
114
|
+
}));
|
|
115
|
+
expect(registry.lookup("old-name")).toBeNull();
|
|
116
|
+
expect(registry.lookup("requested-name")).toMatchObject({
|
|
117
|
+
pid: process.pid,
|
|
118
|
+
runtime: "herdr",
|
|
119
|
+
runtimeRef
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
it("preserves existing runtime ref when incoming runtime ref is empty", ()=>{
|
|
123
|
+
registry.register(makeEntry({
|
|
124
|
+
name: "a",
|
|
125
|
+
runtimeRef: {
|
|
126
|
+
session: "pinned"
|
|
127
|
+
}
|
|
128
|
+
}));
|
|
129
|
+
registry.register(makeEntry({
|
|
130
|
+
name: "fallback",
|
|
131
|
+
runtimeRef: null,
|
|
88
132
|
pid: process.pid
|
|
89
133
|
}));
|
|
90
|
-
const saved = registry.lookup(
|
|
91
|
-
expect(saved?.
|
|
134
|
+
const saved = registry.lookup("a");
|
|
135
|
+
expect(saved?.runtimeRef).toEqual({
|
|
136
|
+
session: "pinned"
|
|
137
|
+
});
|
|
92
138
|
expect(saved?.pid).toBe(process.pid);
|
|
93
139
|
});
|
|
94
|
-
it(
|
|
140
|
+
it("defaults an empty tmux runtime ref from the tmux session", ()=>{
|
|
141
|
+
registry.register(makeEntry({
|
|
142
|
+
name: "a",
|
|
143
|
+
runtimeRef: null
|
|
144
|
+
}));
|
|
145
|
+
expect(registry.lookup("a")?.runtimeRef).toBeNull();
|
|
146
|
+
});
|
|
147
|
+
it("lets a managed start entry replace a generated fallback for the same pid", ()=>{
|
|
95
148
|
registry.register(makeEntry({
|
|
96
149
|
name: `ai-devkit-${process.pid}`,
|
|
97
|
-
|
|
150
|
+
runtimeRef: null
|
|
98
151
|
}));
|
|
99
152
|
registry.register(makeEntry({
|
|
100
|
-
name:
|
|
101
|
-
|
|
153
|
+
name: "custom-name",
|
|
154
|
+
runtimeRef: {
|
|
155
|
+
session: "custom-name"
|
|
156
|
+
}
|
|
102
157
|
}));
|
|
103
|
-
expect(registry.lookup(
|
|
158
|
+
expect(registry.lookup("custom-name")?.runtimeRef).toEqual({
|
|
159
|
+
session: "custom-name"
|
|
160
|
+
});
|
|
104
161
|
expect(registry.lookup(`ai-devkit-${process.pid}`)).toBeNull();
|
|
105
162
|
expect(registry.list()).toHaveLength(1);
|
|
106
163
|
});
|
|
107
|
-
it(
|
|
164
|
+
it("preserves an existing name conflict when its probe fails with EPERM", ()=>{
|
|
108
165
|
registry.register(makeEntry({
|
|
109
|
-
name:
|
|
166
|
+
name: "claimed-name",
|
|
110
167
|
pid: process.pid
|
|
111
168
|
}));
|
|
112
|
-
vi.spyOn(process,
|
|
113
|
-
throw Object.assign(new Error(
|
|
114
|
-
code:
|
|
169
|
+
vi.spyOn(process, "kill").mockImplementation(()=>{
|
|
170
|
+
throw Object.assign(new Error("operation not permitted"), {
|
|
171
|
+
code: "EPERM"
|
|
115
172
|
});
|
|
116
173
|
});
|
|
117
174
|
expect(()=>registry.register(makeEntry({
|
|
118
|
-
name:
|
|
175
|
+
name: "claimed-name",
|
|
119
176
|
pid: process.pid + 1
|
|
120
177
|
}))).toThrow();
|
|
121
|
-
expect(registry.lookup(
|
|
178
|
+
expect(registry.lookup("claimed-name")?.pid).toBe(process.pid);
|
|
122
179
|
});
|
|
123
180
|
});
|
|
124
|
-
describe(
|
|
125
|
-
it(
|
|
181
|
+
describe("registerBatch", ()=>{
|
|
182
|
+
it("is a no-op on empty array", ()=>{
|
|
126
183
|
registry.registerBatch([]);
|
|
127
184
|
expect(fs.existsSync(regPath)).toBe(false);
|
|
128
185
|
});
|
|
129
|
-
it(
|
|
186
|
+
it("upserts multiple entries in a single batch", ()=>{
|
|
130
187
|
registry.registerBatch([
|
|
131
188
|
makeEntry({
|
|
132
|
-
name:
|
|
189
|
+
name: "a"
|
|
133
190
|
}),
|
|
134
191
|
makeEntry({
|
|
135
|
-
name:
|
|
192
|
+
name: "b",
|
|
136
193
|
pid: process.pid + 1
|
|
137
194
|
}),
|
|
138
195
|
makeEntry({
|
|
139
|
-
name:
|
|
196
|
+
name: "c",
|
|
140
197
|
pid: process.pid + 2
|
|
141
198
|
})
|
|
142
199
|
]);
|
|
143
200
|
expect(registry.list()).toHaveLength(3);
|
|
144
201
|
});
|
|
145
|
-
it(
|
|
202
|
+
it("applies the tmux runtime ref merge per entry", ()=>{
|
|
146
203
|
registry.register(makeEntry({
|
|
147
|
-
name:
|
|
148
|
-
|
|
204
|
+
name: "a",
|
|
205
|
+
runtimeRef: {
|
|
206
|
+
session: "pinned"
|
|
207
|
+
}
|
|
149
208
|
}));
|
|
150
209
|
registry.registerBatch([
|
|
151
210
|
makeEntry({
|
|
152
|
-
name:
|
|
153
|
-
|
|
211
|
+
name: "fallback",
|
|
212
|
+
runtimeRef: null,
|
|
154
213
|
pid: process.pid
|
|
155
214
|
}),
|
|
156
215
|
makeEntry({
|
|
157
|
-
name:
|
|
158
|
-
|
|
216
|
+
name: "b",
|
|
217
|
+
runtimeRef: null,
|
|
159
218
|
pid: process.pid + 1
|
|
160
219
|
})
|
|
161
220
|
]);
|
|
162
|
-
expect(registry.lookup(
|
|
163
|
-
|
|
164
|
-
|
|
221
|
+
expect(registry.lookup("a")?.runtimeRef).toEqual({
|
|
222
|
+
session: "pinned"
|
|
223
|
+
});
|
|
224
|
+
expect(registry.lookup("a")?.pid).toBe(process.pid);
|
|
225
|
+
expect(registry.lookup("b")?.runtimeRef).toBeNull();
|
|
165
226
|
});
|
|
166
|
-
it(
|
|
227
|
+
it("handles concurrent registry instances without duplicate pid rows", ()=>{
|
|
167
228
|
const other = new AgentRegistry(regPath);
|
|
168
229
|
registry.register(makeEntry({
|
|
169
230
|
name: `ai-devkit-${process.pid}`,
|
|
170
|
-
|
|
231
|
+
runtimeRef: null
|
|
171
232
|
}));
|
|
172
233
|
other.register(makeEntry({
|
|
173
|
-
name:
|
|
174
|
-
|
|
234
|
+
name: "custom-name",
|
|
235
|
+
runtimeRef: {
|
|
236
|
+
session: "custom-name"
|
|
237
|
+
}
|
|
175
238
|
}));
|
|
176
239
|
registry.register(makeEntry({
|
|
177
240
|
name: `ai-devkit-${process.pid}`,
|
|
178
|
-
|
|
241
|
+
runtimeRef: null
|
|
179
242
|
}));
|
|
180
243
|
expect(registry.list()).toHaveLength(1);
|
|
181
|
-
expect(registry.lookup(
|
|
244
|
+
expect(registry.lookup("custom-name")?.pid).toBe(process.pid);
|
|
182
245
|
});
|
|
183
|
-
it(
|
|
246
|
+
it("cleans up a cross-type row when its pid has been reused", ()=>{
|
|
184
247
|
registry.register(makeEntry({
|
|
185
|
-
name:
|
|
186
|
-
type:
|
|
248
|
+
name: "old-claude",
|
|
249
|
+
type: "claude",
|
|
187
250
|
pid: process.pid
|
|
188
251
|
}));
|
|
189
252
|
registry.register(makeEntry({
|
|
190
|
-
name:
|
|
191
|
-
type:
|
|
253
|
+
name: "new-codex",
|
|
254
|
+
type: "codex",
|
|
192
255
|
pid: process.pid,
|
|
193
|
-
|
|
256
|
+
runtimeRef: null
|
|
194
257
|
}));
|
|
195
|
-
expect(registry.lookup(
|
|
196
|
-
expect(registry.lookup(
|
|
197
|
-
type:
|
|
258
|
+
expect(registry.lookup("old-claude")).toBeNull();
|
|
259
|
+
expect(registry.lookup("new-codex")).toMatchObject({
|
|
260
|
+
type: "codex",
|
|
198
261
|
pid: process.pid
|
|
199
262
|
});
|
|
200
263
|
expect(registry.list()).toHaveLength(1);
|
|
201
264
|
});
|
|
202
|
-
it(
|
|
265
|
+
it("rolls back the whole batch when a live name conflict rejects one entry", ()=>{
|
|
203
266
|
registry.register(makeEntry({
|
|
204
|
-
name:
|
|
267
|
+
name: "taken",
|
|
205
268
|
pid: process.pid
|
|
206
269
|
}));
|
|
207
270
|
expect(()=>registry.registerBatch([
|
|
208
271
|
makeEntry({
|
|
209
|
-
name:
|
|
272
|
+
name: "fresh",
|
|
210
273
|
pid: 999998
|
|
211
274
|
}),
|
|
212
275
|
makeEntry({
|
|
213
|
-
name:
|
|
214
|
-
type:
|
|
276
|
+
name: "taken",
|
|
277
|
+
type: "codex",
|
|
215
278
|
pid: 999997
|
|
216
279
|
})
|
|
217
280
|
])).toThrow(/UNIQUE constraint failed/);
|
|
218
|
-
expect(registry.lookup(
|
|
219
|
-
expect(registry.lookup(
|
|
281
|
+
expect(registry.lookup("fresh")).toBeNull();
|
|
282
|
+
expect(registry.lookup("taken")?.pid).toBe(process.pid);
|
|
220
283
|
});
|
|
221
284
|
});
|
|
222
|
-
describe(
|
|
223
|
-
it(
|
|
224
|
-
expect(registry.lookup(
|
|
285
|
+
describe("lookup", ()=>{
|
|
286
|
+
it("returns null when name not found", ()=>{
|
|
287
|
+
expect(registry.lookup("missing")).toBeNull();
|
|
225
288
|
});
|
|
226
|
-
it(
|
|
289
|
+
it("returns the entry when name matches", ()=>{
|
|
227
290
|
registry.register(makeEntry({
|
|
228
|
-
name:
|
|
291
|
+
name: "a"
|
|
229
292
|
}));
|
|
230
|
-
expect(registry.lookup(
|
|
293
|
+
expect(registry.lookup("a")?.name).toBe("a");
|
|
231
294
|
});
|
|
232
295
|
});
|
|
233
|
-
describe(
|
|
234
|
-
it(
|
|
296
|
+
describe("pinning", ()=>{
|
|
297
|
+
it("defaults new rows to unpinned and toggles the persisted state", ()=>{
|
|
235
298
|
registry.register(makeEntry());
|
|
236
|
-
expect(registry.lookup(
|
|
237
|
-
expect(registry.togglePin(
|
|
238
|
-
expect(registry.lookup(
|
|
239
|
-
expect(registry.togglePin(
|
|
240
|
-
expect(registry.lookup(
|
|
241
|
-
});
|
|
242
|
-
it(
|
|
243
|
-
let now = new Date(
|
|
299
|
+
expect(registry.lookup("agent1")?.pinned).toBe(false);
|
|
300
|
+
expect(registry.togglePin("claude", process.pid)).toBe(true);
|
|
301
|
+
expect(registry.lookup("agent1")?.pinned).toBe(true);
|
|
302
|
+
expect(registry.togglePin("claude", process.pid)).toBe(false);
|
|
303
|
+
expect(registry.lookup("agent1")?.pinned).toBe(false);
|
|
304
|
+
});
|
|
305
|
+
it("updates existing recency when toggled", ()=>{
|
|
306
|
+
let now = new Date("2026-08-16T10:00:00.000Z");
|
|
244
307
|
const clocked = new AgentRegistry(regPath, {
|
|
245
308
|
now: ()=>now
|
|
246
309
|
});
|
|
247
310
|
clocked.register(makeEntry());
|
|
248
|
-
now = new Date(
|
|
249
|
-
clocked.togglePin(
|
|
250
|
-
expect(clocked.lookup(
|
|
251
|
-
const db = new Database(regPath.replace(/\.json$/,
|
|
311
|
+
now = new Date("2026-08-16T10:01:00.000Z");
|
|
312
|
+
clocked.togglePin("claude", process.pid);
|
|
313
|
+
expect(clocked.lookup("agent1")?.updatedAt).toBe(now.toISOString());
|
|
314
|
+
const db = new Database(regPath.replace(/\.json$/, ".db"), {
|
|
252
315
|
readonly: true
|
|
253
316
|
});
|
|
254
|
-
const row = db.prepare(
|
|
317
|
+
const row = db.prepare("SELECT updated_at FROM agents WHERE type = ? AND pid = ?").get("claude", process.pid);
|
|
255
318
|
db.close();
|
|
256
319
|
expect(row.updated_at).toBe(now.toISOString());
|
|
257
320
|
});
|
|
258
|
-
it(
|
|
259
|
-
expect(registry.togglePin(
|
|
321
|
+
it("returns null when the process row has disappeared", ()=>{
|
|
322
|
+
expect(registry.togglePin("claude", 999999)).toBeNull();
|
|
260
323
|
});
|
|
261
|
-
it(
|
|
324
|
+
it("preserves a pin when poll registration updates the row", ()=>{
|
|
262
325
|
registry.register(makeEntry({
|
|
263
|
-
sessionId:
|
|
326
|
+
sessionId: "before"
|
|
264
327
|
}));
|
|
265
|
-
registry.togglePin(
|
|
328
|
+
registry.togglePin("claude", process.pid);
|
|
266
329
|
registry.register(makeEntry({
|
|
267
|
-
sessionId:
|
|
330
|
+
sessionId: "after"
|
|
268
331
|
}));
|
|
269
|
-
expect(registry.lookup(
|
|
270
|
-
sessionId:
|
|
332
|
+
expect(registry.lookup("agent1")).toMatchObject({
|
|
333
|
+
sessionId: "after",
|
|
271
334
|
pinned: true
|
|
272
335
|
});
|
|
273
336
|
});
|
|
274
|
-
it(
|
|
337
|
+
it("preserves a pin through rename", ()=>{
|
|
275
338
|
registry.register(makeEntry({
|
|
276
|
-
name:
|
|
339
|
+
name: "before"
|
|
277
340
|
}));
|
|
278
|
-
registry.togglePin(
|
|
279
|
-
registry.rename(
|
|
280
|
-
expect(registry.lookup(
|
|
341
|
+
registry.togglePin("claude", process.pid);
|
|
342
|
+
registry.rename("before", "after");
|
|
343
|
+
expect(registry.lookup("after")?.pinned).toBe(true);
|
|
281
344
|
});
|
|
282
|
-
it(
|
|
345
|
+
it("removes the pin with a pruned process row", ()=>{
|
|
283
346
|
registry.register(makeEntry({
|
|
284
347
|
pid: 999999
|
|
285
348
|
}));
|
|
286
|
-
registry.togglePin(
|
|
349
|
+
registry.togglePin("claude", 999999);
|
|
287
350
|
registry.prune();
|
|
288
|
-
expect(registry.lookup(
|
|
351
|
+
expect(registry.lookup("agent1")).toBeNull();
|
|
289
352
|
});
|
|
290
|
-
it(
|
|
353
|
+
it("reports a clear error when a readonly registry toggles a pin", ()=>{
|
|
291
354
|
registry.register(makeEntry());
|
|
292
355
|
const readonlyRegistry = new AgentRegistry(regPath, {
|
|
293
356
|
readonly: true
|
|
294
357
|
});
|
|
295
|
-
expect(()=>readonlyRegistry.togglePin(
|
|
358
|
+
expect(()=>readonlyRegistry.togglePin("claude", process.pid)).toThrow(/readonly/i);
|
|
296
359
|
});
|
|
297
360
|
});
|
|
298
|
-
describe(
|
|
299
|
-
it(
|
|
361
|
+
describe("list", ()=>{
|
|
362
|
+
it("returns empty array when database does not contain entries", ()=>{
|
|
300
363
|
expect(registry.list()).toEqual([]);
|
|
301
364
|
});
|
|
302
|
-
it(
|
|
365
|
+
it("ignores existing legacy agents.json entries", ()=>{
|
|
303
366
|
const legacyEntry = makeEntry({
|
|
304
|
-
name:
|
|
305
|
-
|
|
367
|
+
name: "legacy",
|
|
368
|
+
runtimeRef: {
|
|
369
|
+
session: "legacy"
|
|
370
|
+
}
|
|
306
371
|
});
|
|
307
372
|
fs.mkdirSync(path.dirname(regPath), {
|
|
308
373
|
recursive: true
|
|
@@ -311,63 +376,108 @@ describe('AgentRegistry', ()=>{
|
|
|
311
376
|
entries: [
|
|
312
377
|
legacyEntry
|
|
313
378
|
]
|
|
314
|
-
}),
|
|
379
|
+
}), "utf8");
|
|
315
380
|
const legacyRegistry = new AgentRegistry(regPath);
|
|
316
|
-
expect(legacyRegistry.lookup(
|
|
381
|
+
expect(legacyRegistry.lookup("legacy")).toBeNull();
|
|
317
382
|
expect(legacyRegistry.list()).toEqual([]);
|
|
318
|
-
expect(fs.existsSync(regPath.replace(/\.json$/,
|
|
383
|
+
expect(fs.existsSync(regPath.replace(/\.json$/, ".db"))).toBe(true);
|
|
384
|
+
});
|
|
385
|
+
it("reads pre-runtime SQLite rows as tmux-backed records", ()=>{
|
|
386
|
+
const dbPath = regPath.replace(/\.json$/, ".db");
|
|
387
|
+
fs.mkdirSync(path.dirname(dbPath), {
|
|
388
|
+
recursive: true
|
|
389
|
+
});
|
|
390
|
+
fs.rmSync(dbPath, {
|
|
391
|
+
force: true
|
|
392
|
+
});
|
|
393
|
+
fs.rmSync(`${dbPath}-wal`, {
|
|
394
|
+
force: true
|
|
395
|
+
});
|
|
396
|
+
fs.rmSync(`${dbPath}-shm`, {
|
|
397
|
+
force: true
|
|
398
|
+
});
|
|
399
|
+
const db = new Database(dbPath);
|
|
400
|
+
db.exec(`
|
|
401
|
+
CREATE TABLE agents (
|
|
402
|
+
type TEXT NOT NULL,
|
|
403
|
+
pid INTEGER NOT NULL,
|
|
404
|
+
name TEXT NOT NULL UNIQUE,
|
|
405
|
+
tmux_session TEXT NOT NULL DEFAULT '',
|
|
406
|
+
cwd TEXT NOT NULL DEFAULT '',
|
|
407
|
+
started_at TEXT NOT NULL,
|
|
408
|
+
session_id TEXT NOT NULL DEFAULT '',
|
|
409
|
+
session_file_path TEXT NOT NULL DEFAULT '',
|
|
410
|
+
updated_at TEXT NOT NULL,
|
|
411
|
+
PRIMARY KEY (type, pid)
|
|
412
|
+
);
|
|
413
|
+
INSERT INTO agents (
|
|
414
|
+
type, pid, name, tmux_session, cwd, started_at, session_id, session_file_path, updated_at
|
|
415
|
+
) VALUES (
|
|
416
|
+
'claude', ${process.pid}, 'legacy-sqlite', 'legacy-sqlite', '/tmp',
|
|
417
|
+
'2026-05-30T00:00:00.000Z', 'sid-1', '/tmp/session.jsonl', '2026-05-30T00:00:00.000Z'
|
|
418
|
+
);
|
|
419
|
+
PRAGMA user_version = 1;
|
|
420
|
+
`);
|
|
421
|
+
db.close();
|
|
422
|
+
const migratedRegistry = new AgentRegistry(regPath);
|
|
423
|
+
expect(migratedRegistry.lookup("legacy-sqlite")).toMatchObject({
|
|
424
|
+
runtime: "tmux",
|
|
425
|
+
runtimeRef: {
|
|
426
|
+
session: "legacy-sqlite"
|
|
427
|
+
}
|
|
428
|
+
});
|
|
319
429
|
});
|
|
320
430
|
});
|
|
321
|
-
describe(
|
|
322
|
-
it(
|
|
431
|
+
describe("isAlive", ()=>{
|
|
432
|
+
it("returns true for the current process", ()=>{
|
|
323
433
|
expect(registry.isAlive(makeEntry({
|
|
324
434
|
pid: process.pid
|
|
325
435
|
}))).toBe(true);
|
|
326
436
|
});
|
|
327
|
-
it(
|
|
437
|
+
it("returns false for a PID that does not exist", ()=>{
|
|
328
438
|
expect(registry.isAlive(makeEntry({
|
|
329
439
|
pid: 999999
|
|
330
440
|
}))).toBe(false);
|
|
331
441
|
});
|
|
332
|
-
it(
|
|
333
|
-
vi.spyOn(process,
|
|
334
|
-
throw Object.assign(new Error(
|
|
335
|
-
code:
|
|
442
|
+
it("returns true when the process probe is forbidden with EPERM", ()=>{
|
|
443
|
+
vi.spyOn(process, "kill").mockImplementation(()=>{
|
|
444
|
+
throw Object.assign(new Error("operation not permitted"), {
|
|
445
|
+
code: "EPERM"
|
|
336
446
|
});
|
|
337
447
|
});
|
|
338
448
|
expect(registry.isAlive(makeEntry())).toBe(true);
|
|
339
449
|
});
|
|
340
|
-
it(
|
|
341
|
-
vi.spyOn(process,
|
|
342
|
-
throw Object.assign(new Error(
|
|
343
|
-
code:
|
|
450
|
+
it("returns false when the process probe reports ESRCH", ()=>{
|
|
451
|
+
vi.spyOn(process, "kill").mockImplementation(()=>{
|
|
452
|
+
throw Object.assign(new Error("no such process"), {
|
|
453
|
+
code: "ESRCH"
|
|
344
454
|
});
|
|
345
455
|
});
|
|
346
456
|
expect(registry.isAlive(makeEntry())).toBe(false);
|
|
347
457
|
});
|
|
348
|
-
it(
|
|
349
|
-
vi.spyOn(process,
|
|
350
|
-
throw new Error(
|
|
458
|
+
it("returns true when the process probe fails without a definitive error code", ()=>{
|
|
459
|
+
vi.spyOn(process, "kill").mockImplementation(()=>{
|
|
460
|
+
throw new Error("indeterminate probe failure");
|
|
351
461
|
});
|
|
352
462
|
expect(registry.isAlive(makeEntry())).toBe(true);
|
|
353
463
|
});
|
|
354
464
|
});
|
|
355
|
-
describe(
|
|
356
|
-
it(
|
|
465
|
+
describe("prune", ()=>{
|
|
466
|
+
it("removes entries whose PIDs are dead", ()=>{
|
|
357
467
|
registry.register(makeEntry({
|
|
358
|
-
name:
|
|
468
|
+
name: "alive",
|
|
359
469
|
pid: process.pid
|
|
360
470
|
}));
|
|
361
471
|
registry.register(makeEntry({
|
|
362
|
-
name:
|
|
472
|
+
name: "dead",
|
|
363
473
|
pid: 999999
|
|
364
474
|
}));
|
|
365
475
|
registry.prune();
|
|
366
476
|
const remaining = registry.list();
|
|
367
477
|
expect(remaining).toHaveLength(1);
|
|
368
|
-
expect(remaining[0].name).toBe(
|
|
478
|
+
expect(remaining[0].name).toBe("alive");
|
|
369
479
|
});
|
|
370
|
-
it(
|
|
480
|
+
it("is a no-op when all entries are alive", ()=>{
|
|
371
481
|
registry.register(makeEntry({
|
|
372
482
|
pid: process.pid
|
|
373
483
|
}));
|
|
@@ -376,133 +486,141 @@ describe('AgentRegistry', ()=>{
|
|
|
376
486
|
const after = registry.list();
|
|
377
487
|
expect(after).toEqual(before);
|
|
378
488
|
});
|
|
379
|
-
it(
|
|
489
|
+
it("preserves entries when liveness probing fails with EPERM", ()=>{
|
|
380
490
|
registry.register(makeEntry({
|
|
381
|
-
name:
|
|
382
|
-
|
|
491
|
+
name: "custom-name",
|
|
492
|
+
runtimeRef: {
|
|
493
|
+
session: "tmux-custom"
|
|
494
|
+
}
|
|
383
495
|
}));
|
|
384
|
-
vi.spyOn(process,
|
|
385
|
-
throw Object.assign(new Error(
|
|
386
|
-
code:
|
|
496
|
+
vi.spyOn(process, "kill").mockImplementation(()=>{
|
|
497
|
+
throw Object.assign(new Error("operation not permitted"), {
|
|
498
|
+
code: "EPERM"
|
|
387
499
|
});
|
|
388
500
|
});
|
|
389
501
|
registry.prune();
|
|
390
|
-
expect(registry.lookup(
|
|
391
|
-
name:
|
|
392
|
-
|
|
502
|
+
expect(registry.lookup("custom-name")).toMatchObject({
|
|
503
|
+
name: "custom-name",
|
|
504
|
+
runtimeRef: {
|
|
505
|
+
session: "tmux-custom"
|
|
506
|
+
}
|
|
393
507
|
});
|
|
394
508
|
});
|
|
395
|
-
it(
|
|
509
|
+
it("removes entries when liveness probing fails with ESRCH", ()=>{
|
|
396
510
|
registry.register(makeEntry({
|
|
397
|
-
name:
|
|
511
|
+
name: "dead"
|
|
398
512
|
}));
|
|
399
|
-
vi.spyOn(process,
|
|
400
|
-
throw Object.assign(new Error(
|
|
401
|
-
code:
|
|
513
|
+
vi.spyOn(process, "kill").mockImplementation(()=>{
|
|
514
|
+
throw Object.assign(new Error("no such process"), {
|
|
515
|
+
code: "ESRCH"
|
|
402
516
|
});
|
|
403
517
|
});
|
|
404
518
|
registry.prune();
|
|
405
|
-
expect(registry.lookup(
|
|
519
|
+
expect(registry.lookup("dead")).toBeNull();
|
|
406
520
|
});
|
|
407
|
-
it(
|
|
521
|
+
it("does nothing when file is missing", ()=>{
|
|
408
522
|
expect(()=>registry.prune()).not.toThrow();
|
|
409
523
|
});
|
|
410
|
-
it(
|
|
411
|
-
let nowMs = Date.parse(
|
|
524
|
+
it("keeps forced prune available before the passive cadence is due", ()=>{
|
|
525
|
+
let nowMs = Date.parse("2026-08-14T10:00:00.000Z");
|
|
412
526
|
const clocked = new AgentRegistry(regPath, {
|
|
413
527
|
now: ()=>new Date(nowMs),
|
|
414
528
|
pruneIntervalMs: 30_000
|
|
415
529
|
});
|
|
416
530
|
clocked.register(makeEntry({
|
|
417
|
-
name:
|
|
531
|
+
name: "forced",
|
|
418
532
|
pid: process.pid
|
|
419
533
|
}));
|
|
420
|
-
const alive = vi.spyOn(clocked,
|
|
534
|
+
const alive = vi.spyOn(clocked, "isAlive").mockReturnValue(true);
|
|
421
535
|
clocked.pruneIfDue();
|
|
422
536
|
alive.mockReturnValue(false);
|
|
423
537
|
nowMs += 1;
|
|
424
538
|
clocked.prune();
|
|
425
539
|
expect(alive).toHaveBeenCalledTimes(2);
|
|
426
|
-
expect(clocked.lookup(
|
|
540
|
+
expect(clocked.lookup("forced")).toBeNull();
|
|
427
541
|
});
|
|
428
542
|
});
|
|
429
|
-
describe(
|
|
430
|
-
it(
|
|
543
|
+
describe("default()", ()=>{
|
|
544
|
+
it("returns a singleton instance", ()=>{
|
|
431
545
|
expect(AgentRegistry.default()).toBe(AgentRegistry.default());
|
|
432
546
|
});
|
|
433
547
|
});
|
|
434
|
-
describe(
|
|
435
|
-
it(
|
|
548
|
+
describe("rename", ()=>{
|
|
549
|
+
it("updates the name of an existing entry", ()=>{
|
|
436
550
|
registry.register(makeEntry({
|
|
437
|
-
name:
|
|
551
|
+
name: "old-name",
|
|
438
552
|
pid: process.pid
|
|
439
553
|
}));
|
|
440
|
-
registry.rename(
|
|
441
|
-
expect(registry.lookup(
|
|
442
|
-
expect(registry.lookup(
|
|
554
|
+
registry.rename("old-name", "new-name");
|
|
555
|
+
expect(registry.lookup("new-name")?.name).toBe("new-name");
|
|
556
|
+
expect(registry.lookup("old-name")).toBeNull();
|
|
443
557
|
});
|
|
444
|
-
it(
|
|
558
|
+
it("preserves all other fields on the renamed entry", ()=>{
|
|
445
559
|
registry.register(makeEntry({
|
|
446
|
-
name:
|
|
560
|
+
name: "old-name",
|
|
447
561
|
pid: process.pid,
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
562
|
+
runtimeRef: {
|
|
563
|
+
session: "old-name"
|
|
564
|
+
},
|
|
565
|
+
cwd: "/my/cwd"
|
|
566
|
+
}));
|
|
567
|
+
registry.rename("old-name", "new-name");
|
|
568
|
+
const entry = registry.lookup("new-name");
|
|
569
|
+
expect(entry?.runtimeRef).toEqual({
|
|
570
|
+
session: "old-name"
|
|
571
|
+
});
|
|
572
|
+
expect(entry?.cwd).toBe("/my/cwd");
|
|
455
573
|
expect(entry?.pid).toBe(process.pid);
|
|
456
574
|
});
|
|
457
|
-
it(
|
|
458
|
-
expect(()=>registry.rename(
|
|
575
|
+
it("throws RenameNotFoundError when current name does not exist", ()=>{
|
|
576
|
+
expect(()=>registry.rename("ghost", "new-name")).toThrow(RenameNotFoundError);
|
|
459
577
|
});
|
|
460
|
-
it(
|
|
578
|
+
it("throws RenameConflictError when new name is already in use by a live entry", ()=>{
|
|
461
579
|
registry.register(makeEntry({
|
|
462
|
-
name:
|
|
580
|
+
name: "agent-a",
|
|
463
581
|
pid: process.pid
|
|
464
582
|
}));
|
|
465
583
|
registry.register(makeEntry({
|
|
466
|
-
name:
|
|
584
|
+
name: "agent-b",
|
|
467
585
|
pid: process.ppid
|
|
468
586
|
}));
|
|
469
|
-
expect(()=>registry.rename(
|
|
587
|
+
expect(()=>registry.rename("agent-a", "agent-b")).toThrow(RenameConflictError);
|
|
470
588
|
});
|
|
471
|
-
it(
|
|
589
|
+
it("throws RenameConflictError when the conflicting entry probe fails with EPERM", ()=>{
|
|
472
590
|
registry.register(makeEntry({
|
|
473
|
-
name:
|
|
591
|
+
name: "agent-a",
|
|
474
592
|
pid: process.pid
|
|
475
593
|
}));
|
|
476
594
|
registry.register(makeEntry({
|
|
477
|
-
name:
|
|
595
|
+
name: "agent-b",
|
|
478
596
|
pid: process.ppid
|
|
479
597
|
}));
|
|
480
|
-
vi.spyOn(process,
|
|
481
|
-
throw Object.assign(new Error(
|
|
482
|
-
code:
|
|
598
|
+
vi.spyOn(process, "kill").mockImplementation(()=>{
|
|
599
|
+
throw Object.assign(new Error("operation not permitted"), {
|
|
600
|
+
code: "EPERM"
|
|
483
601
|
});
|
|
484
602
|
});
|
|
485
|
-
expect(()=>registry.rename(
|
|
486
|
-
expect(registry.lookup(
|
|
603
|
+
expect(()=>registry.rename("agent-a", "agent-b")).toThrow(RenameConflictError);
|
|
604
|
+
expect(registry.lookup("agent-b")?.pid).toBe(process.ppid);
|
|
487
605
|
});
|
|
488
|
-
it(
|
|
606
|
+
it("succeeds when new name exists only as a stale (dead) entry", ()=>{
|
|
489
607
|
registry.register(makeEntry({
|
|
490
|
-
name:
|
|
608
|
+
name: "agent-a",
|
|
491
609
|
pid: process.pid
|
|
492
610
|
}));
|
|
493
611
|
registry.register(makeEntry({
|
|
494
|
-
name:
|
|
612
|
+
name: "agent-b",
|
|
495
613
|
pid: 999999
|
|
496
614
|
}));
|
|
497
|
-
expect(()=>registry.rename(
|
|
498
|
-
expect(registry.lookup(
|
|
615
|
+
expect(()=>registry.rename("agent-a", "agent-b")).not.toThrow();
|
|
616
|
+
expect(registry.lookup("agent-b")?.pid).toBe(process.pid);
|
|
499
617
|
});
|
|
500
|
-
it(
|
|
618
|
+
it("does not create the legacy fixed .tmp path on rename", ()=>{
|
|
501
619
|
registry.register(makeEntry({
|
|
502
|
-
name:
|
|
620
|
+
name: "old-name",
|
|
503
621
|
pid: process.pid
|
|
504
622
|
}));
|
|
505
|
-
registry.rename(
|
|
623
|
+
registry.rename("old-name", "new-name");
|
|
506
624
|
expect(fs.existsSync(`${regPath}.tmp`)).toBe(false);
|
|
507
625
|
});
|
|
508
626
|
});
|