@ai-devkit/agent-manager 0.33.0 → 0.33.1
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 +11 -2
- package/dist/AgentManager.d.ts.map +1 -1
- package/dist/AgentManager.js +37 -6
- package/dist/AgentManager.js.map +1 -1
- package/dist/__tests__/AgentManager.test.js +212 -5
- package/dist/__tests__/AgentManager.test.js.map +1 -1
- package/dist/__tests__/adapters/OpenCodeAdapter.test.js +1 -0
- package/dist/__tests__/adapters/OpenCodeAdapter.test.js.map +1 -1
- package/dist/__tests__/{adapters → providers/copilot}/CopilotAdapter.test.js +19 -14
- package/dist/__tests__/providers/copilot/CopilotAdapter.test.js.map +1 -0
- package/dist/__tests__/{adapters → providers/gemini}/GeminiCliAdapter.test.js +37 -29
- package/dist/__tests__/providers/gemini/GeminiCliAdapter.test.js.map +1 -0
- package/dist/__tests__/runtime/HerdrAgentDiscovery.test.js +164 -0
- package/dist/__tests__/runtime/HerdrAgentDiscovery.test.js.map +1 -0
- package/dist/__tests__/runtime/HerdrAgentRuntime.test.js +37 -1
- package/dist/__tests__/runtime/HerdrAgentRuntime.test.js.map +1 -1
- package/dist/__tests__/utils/AgentRegistry.test.js +20 -13
- package/dist/__tests__/utils/AgentRegistry.test.js.map +1 -1
- package/dist/adapters/OpenCodeAdapter.d.ts +1 -0
- package/dist/adapters/OpenCodeAdapter.d.ts.map +1 -1
- package/dist/adapters/OpenCodeAdapter.js +7 -4
- package/dist/adapters/OpenCodeAdapter.js.map +1 -1
- package/dist/adapters/index.d.ts +2 -2
- package/dist/adapters/index.d.ts.map +1 -1
- package/dist/adapters/index.js +2 -2
- package/dist/adapters/index.js.map +1 -1
- package/dist/index.d.ts +5 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/dist/{adapters → providers/copilot}/CopilotAdapter.d.ts +11 -25
- package/dist/providers/copilot/CopilotAdapter.d.ts.map +1 -0
- package/dist/providers/copilot/CopilotAdapter.js +108 -0
- package/dist/providers/copilot/CopilotAdapter.js.map +1 -0
- package/dist/providers/copilot/CopilotAgentMapper.d.ts +9 -0
- package/dist/providers/copilot/CopilotAgentMapper.d.ts.map +1 -0
- package/dist/providers/copilot/CopilotAgentMapper.js +37 -0
- package/dist/providers/copilot/CopilotAgentMapper.js.map +1 -0
- package/dist/providers/copilot/CopilotSessionLocator.d.ts +19 -0
- package/dist/providers/copilot/CopilotSessionLocator.d.ts.map +1 -0
- package/dist/providers/copilot/CopilotSessionLocator.js +41 -0
- package/dist/providers/copilot/CopilotSessionLocator.js.map +1 -0
- package/dist/providers/copilot/CopilotSessionParser.d.ts +30 -0
- package/dist/providers/copilot/CopilotSessionParser.d.ts.map +1 -0
- package/dist/providers/copilot/CopilotSessionParser.js +181 -0
- package/dist/providers/copilot/CopilotSessionParser.js.map +1 -0
- package/dist/providers/gemini/GeminiAgentMapper.d.ts +9 -0
- package/dist/providers/gemini/GeminiAgentMapper.d.ts.map +1 -0
- package/dist/providers/gemini/GeminiAgentMapper.js +37 -0
- package/dist/providers/gemini/GeminiAgentMapper.js.map +1 -0
- package/dist/providers/gemini/GeminiCliAdapter.d.ts +52 -0
- package/dist/providers/gemini/GeminiCliAdapter.d.ts.map +1 -0
- package/dist/providers/gemini/GeminiCliAdapter.js +188 -0
- package/dist/providers/gemini/GeminiCliAdapter.js.map +1 -0
- package/dist/providers/gemini/GeminiSessionLocator.d.ts +30 -0
- package/dist/providers/gemini/GeminiSessionLocator.d.ts.map +1 -0
- package/dist/providers/gemini/GeminiSessionLocator.js +142 -0
- package/dist/providers/gemini/GeminiSessionLocator.js.map +1 -0
- package/dist/providers/gemini/GeminiSessionParser.d.ts +94 -0
- package/dist/providers/gemini/GeminiSessionParser.d.ts.map +1 -0
- package/dist/providers/gemini/GeminiSessionParser.js +166 -0
- package/dist/providers/gemini/GeminiSessionParser.js.map +1 -0
- package/dist/runtime/herdr/HerdrAgentDiscovery.d.ts +18 -0
- package/dist/runtime/herdr/HerdrAgentDiscovery.d.ts.map +1 -0
- package/dist/runtime/herdr/HerdrAgentDiscovery.js +183 -0
- package/dist/runtime/herdr/HerdrAgentDiscovery.js.map +1 -0
- package/dist/runtime/herdr/HerdrAgentRuntime.d.ts +5 -0
- package/dist/runtime/herdr/HerdrAgentRuntime.d.ts.map +1 -1
- package/dist/runtime/herdr/HerdrAgentRuntime.js +26 -8
- package/dist/runtime/herdr/HerdrAgentRuntime.js.map +1 -1
- package/dist/runtime/herdr/HerdrResponseParsers.d.ts +2 -0
- package/dist/runtime/herdr/HerdrResponseParsers.d.ts.map +1 -1
- package/dist/runtime/herdr/HerdrResponseParsers.js +12 -1
- package/dist/runtime/herdr/HerdrResponseParsers.js.map +1 -1
- package/dist/utils/AgentRegistry.d.ts.map +1 -1
- package/dist/utils/AgentRegistry.js +5 -5
- package/dist/utils/AgentRegistry.js.map +1 -1
- package/package.json +1 -1
- package/src/AgentManager.ts +67 -5
- package/src/__tests__/AgentManager.test.ts +231 -5
- package/src/__tests__/adapters/OpenCodeAdapter.test.ts +1 -0
- package/src/__tests__/{adapters → providers/copilot}/CopilotAdapter.test.ts +13 -16
- package/src/__tests__/{adapters → providers/gemini}/GeminiCliAdapter.test.ts +39 -31
- package/src/__tests__/runtime/HerdrAgentDiscovery.test.ts +131 -0
- package/src/__tests__/runtime/HerdrAgentRuntime.test.ts +20 -1
- package/src/__tests__/utils/AgentRegistry.test.ts +20 -10
- package/src/adapters/OpenCodeAdapter.ts +8 -4
- package/src/adapters/index.ts +2 -2
- package/src/index.ts +10 -3
- package/src/providers/copilot/CopilotAdapter.ts +145 -0
- package/src/providers/copilot/CopilotAgentMapper.ts +36 -0
- package/src/providers/copilot/CopilotSessionLocator.ts +57 -0
- package/src/providers/copilot/CopilotSessionParser.ts +289 -0
- package/src/providers/gemini/GeminiAgentMapper.ts +36 -0
- package/src/providers/gemini/GeminiCliAdapter.ts +266 -0
- package/src/providers/gemini/GeminiSessionLocator.ts +183 -0
- package/src/providers/gemini/GeminiSessionParser.ts +271 -0
- package/src/runtime/herdr/HerdrAgentDiscovery.ts +178 -0
- package/src/runtime/herdr/HerdrAgentRuntime.ts +33 -7
- package/src/runtime/herdr/HerdrResponseParsers.ts +11 -1
- package/src/utils/AgentRegistry.ts +8 -6
- package/dist/__tests__/adapters/CopilotAdapter.test.js.map +0 -1
- package/dist/__tests__/adapters/GeminiCliAdapter.test.js.map +0 -1
- package/dist/adapters/CopilotAdapter.d.ts.map +0 -1
- package/dist/adapters/CopilotAdapter.js +0 -329
- package/dist/adapters/CopilotAdapter.js.map +0 -1
- package/dist/adapters/GeminiCliAdapter.d.ts +0 -98
- package/dist/adapters/GeminiCliAdapter.d.ts.map +0 -1
- package/dist/adapters/GeminiCliAdapter.js +0 -513
- package/dist/adapters/GeminiCliAdapter.js.map +0 -1
- package/src/adapters/CopilotAdapter.ts +0 -483
- package/src/adapters/GeminiCliAdapter.ts +0 -699
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import { extractHerdrAgentPanes, fetchHerdrAgentPanes, findMatchingHerdrPane } from "../../runtime/herdr/HerdrAgentDiscovery.js";
|
|
2
|
+
function jsonResponse(value) {
|
|
3
|
+
return {
|
|
4
|
+
stdout: JSON.stringify(value),
|
|
5
|
+
stderr: ""
|
|
6
|
+
};
|
|
7
|
+
}
|
|
8
|
+
describe("HerdrAgentDiscovery", ()=>{
|
|
9
|
+
it("extracts agent panes from pane list responses", ()=>{
|
|
10
|
+
const panes = extractHerdrAgentPanes({
|
|
11
|
+
result: {
|
|
12
|
+
panes: [
|
|
13
|
+
{
|
|
14
|
+
agent: "codex",
|
|
15
|
+
agent_session: {
|
|
16
|
+
value: "session-1"
|
|
17
|
+
},
|
|
18
|
+
cwd: "/repo",
|
|
19
|
+
pane_id: "w32:p1",
|
|
20
|
+
workspace_id: "w32",
|
|
21
|
+
tab_id: "w32:t1"
|
|
22
|
+
}
|
|
23
|
+
]
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
expect(panes).toEqual([
|
|
27
|
+
{
|
|
28
|
+
agent: "codex",
|
|
29
|
+
agentSessionId: "session-1",
|
|
30
|
+
cwd: "/repo",
|
|
31
|
+
paneId: "w32:p1",
|
|
32
|
+
workspaceId: "w32",
|
|
33
|
+
tabId: "w32:t1"
|
|
34
|
+
}
|
|
35
|
+
]);
|
|
36
|
+
});
|
|
37
|
+
it("matches by foreground PID before falling back to ambiguous cwd and type", ()=>{
|
|
38
|
+
const pane = findMatchingHerdrPane({
|
|
39
|
+
type: "codex",
|
|
40
|
+
projectPath: "/repo",
|
|
41
|
+
sessionId: "pid-64904",
|
|
42
|
+
pid: 64904
|
|
43
|
+
}, [
|
|
44
|
+
{
|
|
45
|
+
agent: "codex",
|
|
46
|
+
cwd: "/repo",
|
|
47
|
+
paneId: "w31:p1",
|
|
48
|
+
foregroundPids: [
|
|
49
|
+
44290
|
|
50
|
+
]
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
agent: "codex",
|
|
54
|
+
cwd: "/repo",
|
|
55
|
+
paneId: "w32:p1",
|
|
56
|
+
foregroundPids: [
|
|
57
|
+
64904
|
|
58
|
+
]
|
|
59
|
+
}
|
|
60
|
+
]);
|
|
61
|
+
expect(pane?.paneId).toBe("w32:p1");
|
|
62
|
+
});
|
|
63
|
+
it("prefers a foreground PID match over a shell PID match", ()=>{
|
|
64
|
+
const pane = findMatchingHerdrPane({
|
|
65
|
+
type: "codex",
|
|
66
|
+
projectPath: "/repo",
|
|
67
|
+
sessionId: "pid-64904",
|
|
68
|
+
pid: 64904
|
|
69
|
+
}, [
|
|
70
|
+
{
|
|
71
|
+
agent: "codex",
|
|
72
|
+
cwd: "/repo",
|
|
73
|
+
paneId: "w31:p1",
|
|
74
|
+
shellPid: 64904
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
agent: "codex",
|
|
78
|
+
cwd: "/repo",
|
|
79
|
+
paneId: "w32:p1",
|
|
80
|
+
foregroundPids: [
|
|
81
|
+
64904
|
|
82
|
+
]
|
|
83
|
+
}
|
|
84
|
+
]);
|
|
85
|
+
expect(pane?.paneId).toBe("w32:p1");
|
|
86
|
+
});
|
|
87
|
+
it("enriches pane list output with foreground process IDs", async ()=>{
|
|
88
|
+
const runner = vi.fn().mockResolvedValueOnce(jsonResponse({
|
|
89
|
+
result: {
|
|
90
|
+
panes: [
|
|
91
|
+
{
|
|
92
|
+
agent: "codex",
|
|
93
|
+
cwd: "/repo",
|
|
94
|
+
pane_id: "w31:p1"
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
agent: "codex",
|
|
98
|
+
cwd: "/repo",
|
|
99
|
+
pane_id: "w32:p1"
|
|
100
|
+
}
|
|
101
|
+
]
|
|
102
|
+
}
|
|
103
|
+
})).mockResolvedValueOnce(jsonResponse({
|
|
104
|
+
result: {
|
|
105
|
+
process_info: {
|
|
106
|
+
pane_id: "w31:p1",
|
|
107
|
+
shell_pid: 111,
|
|
108
|
+
foreground_processes: [
|
|
109
|
+
{
|
|
110
|
+
pid: 44290
|
|
111
|
+
}
|
|
112
|
+
]
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
})).mockResolvedValueOnce(jsonResponse({
|
|
116
|
+
result: {
|
|
117
|
+
process_info: {
|
|
118
|
+
pane_id: "w32:p1",
|
|
119
|
+
shell_pid: 222,
|
|
120
|
+
foreground_processes: [
|
|
121
|
+
{
|
|
122
|
+
pid: 64904
|
|
123
|
+
}
|
|
124
|
+
]
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}));
|
|
128
|
+
const panes = await fetchHerdrAgentPanes(runner);
|
|
129
|
+
expect(runner).toHaveBeenNthCalledWith(1, "herdr", [
|
|
130
|
+
"pane",
|
|
131
|
+
"list"
|
|
132
|
+
]);
|
|
133
|
+
expect(runner).toHaveBeenNthCalledWith(2, "herdr", [
|
|
134
|
+
"pane",
|
|
135
|
+
"process-info",
|
|
136
|
+
"--pane",
|
|
137
|
+
"w31:p1"
|
|
138
|
+
]);
|
|
139
|
+
expect(runner).toHaveBeenNthCalledWith(3, "herdr", [
|
|
140
|
+
"pane",
|
|
141
|
+
"process-info",
|
|
142
|
+
"--pane",
|
|
143
|
+
"w32:p1"
|
|
144
|
+
]);
|
|
145
|
+
expect(panes).toMatchObject([
|
|
146
|
+
{
|
|
147
|
+
paneId: "w31:p1",
|
|
148
|
+
foregroundPids: [
|
|
149
|
+
44290
|
|
150
|
+
],
|
|
151
|
+
shellPid: 111
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
paneId: "w32:p1",
|
|
155
|
+
foregroundPids: [
|
|
156
|
+
64904
|
|
157
|
+
],
|
|
158
|
+
shellPid: 222
|
|
159
|
+
}
|
|
160
|
+
]);
|
|
161
|
+
});
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
//# sourceMappingURL=HerdrAgentDiscovery.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/__tests__/runtime/HerdrAgentDiscovery.test.ts"],"sourcesContent":["import {\n extractHerdrAgentPanes,\n fetchHerdrAgentPanes,\n findMatchingHerdrPane,\n} from \"../../runtime/herdr/HerdrAgentDiscovery.js\";\nimport type { HerdrCommandRunner } from \"../../runtime/herdr/HerdrCliClient.js\";\n\nfunction jsonResponse(value: unknown): { stdout: string; stderr: string } {\n return { stdout: JSON.stringify(value), stderr: \"\" };\n}\n\ndescribe(\"HerdrAgentDiscovery\", () => {\n it(\"extracts agent panes from pane list responses\", () => {\n const panes = extractHerdrAgentPanes({\n result: {\n panes: [\n {\n agent: \"codex\",\n agent_session: { value: \"session-1\" },\n cwd: \"/repo\",\n pane_id: \"w32:p1\",\n workspace_id: \"w32\",\n tab_id: \"w32:t1\",\n },\n ],\n },\n });\n\n expect(panes).toEqual([\n {\n agent: \"codex\",\n agentSessionId: \"session-1\",\n cwd: \"/repo\",\n paneId: \"w32:p1\",\n workspaceId: \"w32\",\n tabId: \"w32:t1\",\n },\n ]);\n });\n\n it(\"matches by foreground PID before falling back to ambiguous cwd and type\", () => {\n const pane = findMatchingHerdrPane(\n {\n type: \"codex\",\n projectPath: \"/repo\",\n sessionId: \"pid-64904\",\n pid: 64904,\n },\n [\n { agent: \"codex\", cwd: \"/repo\", paneId: \"w31:p1\", foregroundPids: [44290] },\n { agent: \"codex\", cwd: \"/repo\", paneId: \"w32:p1\", foregroundPids: [64904] },\n ],\n );\n\n expect(pane?.paneId).toBe(\"w32:p1\");\n });\n\n it(\"prefers a foreground PID match over a shell PID match\", () => {\n const pane = findMatchingHerdrPane(\n {\n type: \"codex\",\n projectPath: \"/repo\",\n sessionId: \"pid-64904\",\n pid: 64904,\n },\n [\n { agent: \"codex\", cwd: \"/repo\", paneId: \"w31:p1\", shellPid: 64904 },\n { agent: \"codex\", cwd: \"/repo\", paneId: \"w32:p1\", foregroundPids: [64904] },\n ],\n );\n\n expect(pane?.paneId).toBe(\"w32:p1\");\n });\n\n it(\"enriches pane list output with foreground process IDs\", async () => {\n const runner = vi\n .fn<HerdrCommandRunner>()\n .mockResolvedValueOnce(\n jsonResponse({\n result: {\n panes: [\n { agent: \"codex\", cwd: \"/repo\", pane_id: \"w31:p1\" },\n { agent: \"codex\", cwd: \"/repo\", pane_id: \"w32:p1\" },\n ],\n },\n }),\n )\n .mockResolvedValueOnce(\n jsonResponse({\n result: {\n process_info: {\n pane_id: \"w31:p1\",\n shell_pid: 111,\n foreground_processes: [{ pid: 44290 }],\n },\n },\n }),\n )\n .mockResolvedValueOnce(\n jsonResponse({\n result: {\n process_info: {\n pane_id: \"w32:p1\",\n shell_pid: 222,\n foreground_processes: [{ pid: 64904 }],\n },\n },\n }),\n );\n\n const panes = await fetchHerdrAgentPanes(runner);\n\n expect(runner).toHaveBeenNthCalledWith(1, \"herdr\", [\"pane\", \"list\"]);\n expect(runner).toHaveBeenNthCalledWith(2, \"herdr\", [\n \"pane\",\n \"process-info\",\n \"--pane\",\n \"w31:p1\",\n ]);\n expect(runner).toHaveBeenNthCalledWith(3, \"herdr\", [\n \"pane\",\n \"process-info\",\n \"--pane\",\n \"w32:p1\",\n ]);\n expect(panes).toMatchObject([\n { paneId: \"w31:p1\", foregroundPids: [44290], shellPid: 111 },\n { paneId: \"w32:p1\", foregroundPids: [64904], shellPid: 222 },\n ]);\n });\n});\n"],"names":["extractHerdrAgentPanes","fetchHerdrAgentPanes","findMatchingHerdrPane","jsonResponse","value","stdout","JSON","stringify","stderr","describe","it","panes","result","agent","agent_session","cwd","pane_id","workspace_id","tab_id","expect","toEqual","agentSessionId","paneId","workspaceId","tabId","pane","type","projectPath","sessionId","pid","foregroundPids","toBe","shellPid","runner","vi","fn","mockResolvedValueOnce","process_info","shell_pid","foreground_processes","toHaveBeenNthCalledWith","toMatchObject"],"mappings":"AAAA,SACEA,sBAAsB,EACtBC,oBAAoB,EACpBC,qBAAqB,QAChB,6CAA6C;AAGpD,SAASC,aAAaC,KAAc;IAClC,OAAO;QAAEC,QAAQC,KAAKC,SAAS,CAACH;QAAQI,QAAQ;IAAG;AACrD;AAEAC,SAAS,uBAAuB;IAC9BC,GAAG,iDAAiD;QAClD,MAAMC,QAAQX,uBAAuB;YACnCY,QAAQ;gBACND,OAAO;oBACL;wBACEE,OAAO;wBACPC,eAAe;4BAAEV,OAAO;wBAAY;wBACpCW,KAAK;wBACLC,SAAS;wBACTC,cAAc;wBACdC,QAAQ;oBACV;iBACD;YACH;QACF;QAEAC,OAAOR,OAAOS,OAAO,CAAC;YACpB;gBACEP,OAAO;gBACPQ,gBAAgB;gBAChBN,KAAK;gBACLO,QAAQ;gBACRC,aAAa;gBACbC,OAAO;YACT;SACD;IACH;IAEAd,GAAG,2EAA2E;QAC5E,MAAMe,OAAOvB,sBACX;YACEwB,MAAM;YACNC,aAAa;YACbC,WAAW;YACXC,KAAK;QACP,GACA;YACE;gBAAEhB,OAAO;gBAASE,KAAK;gBAASO,QAAQ;gBAAUQ,gBAAgB;oBAAC;iBAAM;YAAC;YAC1E;gBAAEjB,OAAO;gBAASE,KAAK;gBAASO,QAAQ;gBAAUQ,gBAAgB;oBAAC;iBAAM;YAAC;SAC3E;QAGHX,OAAOM,MAAMH,QAAQS,IAAI,CAAC;IAC5B;IAEArB,GAAG,yDAAyD;QAC1D,MAAMe,OAAOvB,sBACX;YACEwB,MAAM;YACNC,aAAa;YACbC,WAAW;YACXC,KAAK;QACP,GACA;YACE;gBAAEhB,OAAO;gBAASE,KAAK;gBAASO,QAAQ;gBAAUU,UAAU;YAAM;YAClE;gBAAEnB,OAAO;gBAASE,KAAK;gBAASO,QAAQ;gBAAUQ,gBAAgB;oBAAC;iBAAM;YAAC;SAC3E;QAGHX,OAAOM,MAAMH,QAAQS,IAAI,CAAC;IAC5B;IAEArB,GAAG,yDAAyD;QAC1D,MAAMuB,SAASC,GACZC,EAAE,GACFC,qBAAqB,CACpBjC,aAAa;YACXS,QAAQ;gBACND,OAAO;oBACL;wBAAEE,OAAO;wBAASE,KAAK;wBAASC,SAAS;oBAAS;oBAClD;wBAAEH,OAAO;wBAASE,KAAK;wBAASC,SAAS;oBAAS;iBACnD;YACH;QACF,IAEDoB,qBAAqB,CACpBjC,aAAa;YACXS,QAAQ;gBACNyB,cAAc;oBACZrB,SAAS;oBACTsB,WAAW;oBACXC,sBAAsB;wBAAC;4BAAEV,KAAK;wBAAM;qBAAE;gBACxC;YACF;QACF,IAEDO,qBAAqB,CACpBjC,aAAa;YACXS,QAAQ;gBACNyB,cAAc;oBACZrB,SAAS;oBACTsB,WAAW;oBACXC,sBAAsB;wBAAC;4BAAEV,KAAK;wBAAM;qBAAE;gBACxC;YACF;QACF;QAGJ,MAAMlB,QAAQ,MAAMV,qBAAqBgC;QAEzCd,OAAOc,QAAQO,uBAAuB,CAAC,GAAG,SAAS;YAAC;YAAQ;SAAO;QACnErB,OAAOc,QAAQO,uBAAuB,CAAC,GAAG,SAAS;YACjD;YACA;YACA;YACA;SACD;QACDrB,OAAOc,QAAQO,uBAAuB,CAAC,GAAG,SAAS;YACjD;YACA;YACA;YACA;SACD;QACDrB,OAAOR,OAAO8B,aAAa,CAAC;YAC1B;gBAAEnB,QAAQ;gBAAUQ,gBAAgB;oBAAC;iBAAM;gBAAEE,UAAU;YAAI;YAC3D;gBAAEV,QAAQ;gBAAUQ,gBAAgB;oBAAC;iBAAM;gBAAEE,UAAU;YAAI;SAC5D;IACH;AACF"}
|
|
@@ -222,12 +222,48 @@ describe("HerdrAgentRuntime", ()=>{
|
|
|
222
222
|
]);
|
|
223
223
|
const runtime = new HerdrAgentRuntime({
|
|
224
224
|
runner,
|
|
225
|
-
env: {}
|
|
225
|
+
env: {},
|
|
226
|
+
processInfoPollMs: 0
|
|
226
227
|
});
|
|
227
228
|
await expect(runtime.startAgent(startInput)).resolves.toMatchObject({
|
|
228
229
|
pid: 12000
|
|
229
230
|
});
|
|
230
231
|
});
|
|
232
|
+
it("waits for a foreground process pid before falling back to the pane shell pid", async ()=>{
|
|
233
|
+
const runner = createRunner([
|
|
234
|
+
workspaceResponse(),
|
|
235
|
+
agentResponse(),
|
|
236
|
+
processInfoResponse({
|
|
237
|
+
shellPid: 12000
|
|
238
|
+
}),
|
|
239
|
+
processInfoResponse({
|
|
240
|
+
shellPid: 12000,
|
|
241
|
+
pid: 12345,
|
|
242
|
+
processName: "node"
|
|
243
|
+
})
|
|
244
|
+
]);
|
|
245
|
+
const runtime = new HerdrAgentRuntime({
|
|
246
|
+
runner,
|
|
247
|
+
env: {},
|
|
248
|
+
processInfoPollMs: 100,
|
|
249
|
+
processInfoPollIntervalMs: 0
|
|
250
|
+
});
|
|
251
|
+
await expect(runtime.startAgent(startInput)).resolves.toMatchObject({
|
|
252
|
+
pid: 12345
|
|
253
|
+
});
|
|
254
|
+
expect(runner).toHaveBeenNthCalledWith(3, "herdr", [
|
|
255
|
+
"pane",
|
|
256
|
+
"process-info",
|
|
257
|
+
"--pane",
|
|
258
|
+
"w1:p1"
|
|
259
|
+
]);
|
|
260
|
+
expect(runner).toHaveBeenNthCalledWith(4, "herdr", [
|
|
261
|
+
"pane",
|
|
262
|
+
"process-info",
|
|
263
|
+
"--pane",
|
|
264
|
+
"w1:p1"
|
|
265
|
+
]);
|
|
266
|
+
});
|
|
231
267
|
it("passes only explicit extra agent args after the Herdr start separator", async ()=>{
|
|
232
268
|
const runner = createRunner([
|
|
233
269
|
workspaceResponse(),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/__tests__/runtime/HerdrAgentRuntime.test.ts"],"sourcesContent":["import { HerdrAgentRuntime } from \"../../runtime/herdr/HerdrAgentRuntime.js\";\nimport { HerdrRuntimeError } from \"../../runtime/herdr/HerdrErrors.js\";\nimport type { HerdrCommandRunner } from \"../../runtime/herdr/HerdrCliClient.js\";\n\nfunction createRunner(\n responses: Array<{ stdout?: string; stderr?: string; reject?: Error }> = [],\n): HerdrCommandRunner {\n const runner = vi.fn(async () => {\n const response = responses.shift();\n if (!response) return { stdout: \"{}\", stderr: \"\" };\n if (response.reject) throw response.reject;\n return { stdout: response.stdout ?? \"\", stderr: response.stderr ?? \"\" };\n });\n return runner;\n}\n\nfunction herdrCliError(response: unknown): Error {\n return Object.assign(new Error(\"herdr command failed\"), {\n stdout: JSON.stringify(response),\n stderr: \"\",\n code: 1,\n });\n}\n\nfunction jsonResponse(value: unknown): { stdout: string } {\n return { stdout: JSON.stringify(value) };\n}\n\nfunction workspaceResponse(workspaceId = \"w1\", paneId = \"w1:p1\"): { stdout: string } {\n return jsonResponse({\n result: {\n type: \"workspace_info\",\n workspace: { workspace_id: workspaceId },\n root_pane: { pane_id: paneId },\n },\n });\n}\n\nfunction agentResponse({\n name = \"reviewer\",\n paneId = \"w1:p1\",\n workspaceId,\n tabId,\n}: {\n name?: string;\n paneId?: string;\n workspaceId?: string;\n tabId?: string;\n} = {}): { stdout: string } {\n return jsonResponse({\n result: {\n type: \"agent_info\",\n agent: {\n name,\n agent: \"codex\",\n pane_id: paneId,\n ...(workspaceId ? { workspace_id: workspaceId } : {}),\n ...(tabId ? { tab_id: tabId } : {}),\n },\n },\n });\n}\n\nfunction processInfoResponse({\n paneId = \"w1:p1\",\n pid,\n shellPid,\n processName,\n}: {\n paneId?: string;\n pid?: number;\n shellPid?: number;\n processName?: string;\n} = {}): { stdout: string } {\n return jsonResponse({\n result: {\n type: \"pane_process_info\",\n process_info: {\n pane_id: paneId,\n ...(shellPid ? { shell_pid: shellPid } : {}),\n foreground_processes: pid ? [{ pid, ...(processName ? { name: processName } : {}) }] : [],\n },\n },\n });\n}\n\nconst startInput = {\n name: \"reviewer\",\n cwd: \"/repo\",\n kind: \"codex\",\n args: [],\n timeoutMs: 15000,\n};\n\ndescribe(\"HerdrAgentRuntime\", () => {\n it(\"reports unavailable when the herdr binary is missing\", async () => {\n const runner = createRunner([\n { reject: Object.assign(new Error(\"not found\"), { code: \"ENOENT\" }) },\n ]);\n const runtime = new HerdrAgentRuntime({ runner, env: {} });\n\n await expect(runtime.isAvailable()).resolves.toEqual({\n ok: false,\n reason: \"binary-missing\",\n detail: \"herdr command was not found in PATH.\",\n });\n });\n\n it(\"reports available outside Herdr when binary and snapshot work\", async () => {\n const runner = createRunner([\n { stdout: \"herdr 0.8.2\\n\" },\n jsonResponse({ id: \"cli:api:snapshot\", result: { type: \"session_snapshot\" } }),\n ]);\n const runtime = new HerdrAgentRuntime({ runner, env: {} });\n\n await expect(runtime.isAvailable()).resolves.toEqual({\n ok: true,\n insideRuntime: false,\n });\n expect(runner).toHaveBeenNthCalledWith(1, \"herdr\", [\"--version\"]);\n expect(runner).toHaveBeenNthCalledWith(2, \"herdr\", [\"api\", \"snapshot\"]);\n });\n\n it(\"includes Herdr environment context when present\", async () => {\n const runner = createRunner([\n { stdout: \"herdr 0.8.2\\n\" },\n jsonResponse({ id: \"cli:api:snapshot\", result: { type: \"session_snapshot\" } }),\n ]);\n const runtime = new HerdrAgentRuntime({\n runner,\n env: { HERDR_ENV: \"1\", HERDR_PANE_ID: \"w1:p1\" },\n });\n\n await expect(runtime.isAvailable()).resolves.toEqual({\n ok: true,\n insideRuntime: true,\n currentPaneId: \"w1:p1\",\n });\n });\n\n it(\"creates a workspace, starts the named agent, and returns an opaque Herdr ref\", async () => {\n const runner = createRunner([\n workspaceResponse(),\n agentResponse({ workspaceId: \"w1\", tabId: \"w1:t1\" }),\n processInfoResponse({ shellPid: 12000, pid: 12345, processName: \"codex\" }),\n ]);\n const runtime = new HerdrAgentRuntime({ runner, env: {} });\n\n const result = await runtime.startAgent(startInput);\n\n expect(runner).toHaveBeenNthCalledWith(1, \"herdr\", [\n \"workspace\",\n \"create\",\n \"--cwd\",\n \"/repo\",\n \"--label\",\n \"reviewer\",\n ]);\n expect(runner).toHaveBeenNthCalledWith(2, \"herdr\", [\n \"agent\",\n \"start\",\n \"reviewer\",\n \"--kind\",\n \"codex\",\n \"--pane\",\n \"w1:p1\",\n \"--timeout\",\n \"15000\",\n ]);\n expect(runner).toHaveBeenNthCalledWith(3, \"herdr\", [\"pane\", \"process-info\", \"--pane\", \"w1:p1\"]);\n expect(result).toEqual({\n pid: 12345,\n runtimeRef: {\n session: \"default\",\n workspaceId: \"w1\",\n tabId: \"w1:t1\",\n paneId: \"w1:p1\",\n agentName: \"reviewer\",\n },\n });\n });\n\n it(\"falls back to the pane shell pid when no foreground process pid is reported\", async () => {\n const runner = createRunner([\n workspaceResponse(),\n agentResponse(),\n processInfoResponse({ shellPid: 12000 }),\n ]);\n const runtime = new HerdrAgentRuntime({ runner, env: {} });\n\n await expect(runtime.startAgent(startInput)).resolves.toMatchObject({ pid: 12000 });\n });\n\n it(\"passes only explicit extra agent args after the Herdr start separator\", async () => {\n const runner = createRunner([\n workspaceResponse(),\n agentResponse(),\n processInfoResponse({ pid: 12345 }),\n ]);\n const runtime = new HerdrAgentRuntime({ runner, env: {} });\n\n await runtime.startAgent({\n ...startInput,\n args: [\"--model\", \"gpt-5-codex\"],\n });\n\n expect(runner).toHaveBeenNthCalledWith(2, \"herdr\", [\n \"agent\",\n \"start\",\n \"reviewer\",\n \"--kind\",\n \"codex\",\n \"--pane\",\n \"w1:p1\",\n \"--timeout\",\n \"15000\",\n \"--\",\n \"--model\",\n \"gpt-5-codex\",\n ]);\n });\n\n it(\"retries agent start when a freshly-created Herdr pane is temporarily busy\", async () => {\n const runner = createRunner([\n workspaceResponse(\"w15\", \"w15:p1\"),\n {\n reject: herdrCliError({\n error: {\n code: \"agent_pane_busy\",\n message: \"agent target pane w15:p1 is not an available shell\",\n },\n id: \"cli:agent:start\",\n }),\n },\n agentResponse({ paneId: \"w15:p1\", workspaceId: \"w15\", tabId: \"w15:t1\" }),\n processInfoResponse({ paneId: \"w15:p1\", pid: 12345 }),\n ]);\n const runtime = new HerdrAgentRuntime({\n runner,\n env: {},\n agentStartBusyRetryMs: 100,\n agentStartBusyRetryIntervalMs: 0,\n });\n\n await expect(runtime.startAgent(startInput)).resolves.toMatchObject({\n runtimeRef: {\n workspaceId: \"w15\",\n paneId: \"w15:p1\",\n },\n });\n\n expect(runner).toHaveBeenNthCalledWith(2, \"herdr\", [\n \"agent\",\n \"start\",\n \"reviewer\",\n \"--kind\",\n \"codex\",\n \"--pane\",\n \"w15:p1\",\n \"--timeout\",\n \"15000\",\n ]);\n expect(runner).toHaveBeenNthCalledWith(3, \"herdr\", [\n \"agent\",\n \"start\",\n \"reviewer\",\n \"--kind\",\n \"codex\",\n \"--pane\",\n \"w15:p1\",\n \"--timeout\",\n \"15000\",\n ]);\n });\n\n it(\"surfaces non-retryable Herdr agent start errors without retrying\", async () => {\n const runner = createRunner([\n workspaceResponse(),\n {\n reject: herdrCliError({\n error: {\n code: \"duplicate_agent_name\",\n message: \"agent name reviewer already exists\",\n },\n id: \"cli:agent:start\",\n }),\n },\n ]);\n const runtime = new HerdrAgentRuntime({ runner, env: {} });\n\n await expect(runtime.startAgent(startInput)).rejects.toMatchObject({\n code: \"duplicate_agent_name\",\n message: \"agent name reviewer already exists\",\n });\n\n expect(runner).toHaveBeenCalledTimes(2);\n });\n\n it(\"rejects start responses when Herdr process info does not include a pid\", async () => {\n const runner = createRunner([workspaceResponse(), agentResponse(), processInfoResponse()]);\n const runtime = new HerdrAgentRuntime({ runner, env: {} });\n\n await expect(runtime.startAgent(startInput)).rejects.toThrow(\n new HerdrRuntimeError(\"Herdr pane process-info response did not include process pid.\"),\n );\n });\n\n it(\"rejects start responses that do not include a pane id\", async () => {\n const runner = createRunner([{ stdout: '{\"result\":{\"workspace\":{\"workspace_id\":\"w1\"}}}' }]);\n const runtime = new HerdrAgentRuntime({ runner, env: {} });\n\n await expect(runtime.startAgent(startInput)).rejects.toThrow(\n new HerdrRuntimeError(\"Herdr workspace create response did not include root pane id.\"),\n );\n });\n\n it(\"sends, waits, reads, focuses, and stops by Herdr pane ref\", async () => {\n const runner = createRunner([\n { stdout: \"{}\" },\n { stdout: '{\"result\":{\"agent\":{\"agent_status\":\"done\"}}}' },\n { stdout: \"done\\n\" },\n { stdout: \"{}\" },\n { stdout: \"{}\" },\n ]);\n const runtime = new HerdrAgentRuntime({ runner, env: {} });\n const runtimeRef = { paneId: \"w1:p2\", agentName: \"reviewer\" };\n\n await runtime.send({ runtimeRef, prompt: \"continue\" });\n await runtime.wait({ runtimeRef, timeoutMs: 2000 });\n await expect(runtime.readOutput({ runtimeRef, lines: 80 })).resolves.toBe(\"done\\n\");\n await expect(runtime.focus({ runtimeRef })).resolves.toBe(true);\n await runtime.stop({ runtimeRef });\n\n expect(runner).toHaveBeenNthCalledWith(1, \"herdr\", [\"agent\", \"prompt\", \"w1:p2\", \"continue\"]);\n expect(runner).toHaveBeenNthCalledWith(2, \"herdr\", [\n \"agent\",\n \"wait\",\n \"w1:p2\",\n \"--until\",\n \"done\",\n \"--until\",\n \"blocked\",\n \"--timeout\",\n \"2000\",\n ]);\n expect(runner).toHaveBeenNthCalledWith(3, \"herdr\", [\n \"agent\",\n \"read\",\n \"w1:p2\",\n \"--source\",\n \"recent-unwrapped\",\n \"--lines\",\n \"80\",\n ]);\n expect(runner).toHaveBeenNthCalledWith(4, \"herdr\", [\"agent\", \"focus\", \"w1:p2\"]);\n expect(runner).toHaveBeenNthCalledWith(5, \"herdr\", [\"pane\", \"close\", \"w1:p2\"]);\n });\n});\n"],"names":["HerdrAgentRuntime","HerdrRuntimeError","createRunner","responses","runner","vi","fn","response","shift","stdout","stderr","reject","herdrCliError","Object","assign","Error","JSON","stringify","code","jsonResponse","value","workspaceResponse","workspaceId","paneId","result","type","workspace","workspace_id","root_pane","pane_id","agentResponse","name","tabId","agent","tab_id","processInfoResponse","pid","shellPid","processName","process_info","shell_pid","foreground_processes","startInput","cwd","kind","args","timeoutMs","describe","it","runtime","env","expect","isAvailable","resolves","toEqual","ok","reason","detail","id","insideRuntime","toHaveBeenNthCalledWith","HERDR_ENV","HERDR_PANE_ID","currentPaneId","startAgent","runtimeRef","session","agentName","toMatchObject","error","message","agentStartBusyRetryMs","agentStartBusyRetryIntervalMs","rejects","toHaveBeenCalledTimes","toThrow","send","prompt","wait","readOutput","lines","toBe","focus","stop"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../src/__tests__/runtime/HerdrAgentRuntime.test.ts"],"sourcesContent":["import { HerdrAgentRuntime } from \"../../runtime/herdr/HerdrAgentRuntime.js\";\nimport { HerdrRuntimeError } from \"../../runtime/herdr/HerdrErrors.js\";\nimport type { HerdrCommandRunner } from \"../../runtime/herdr/HerdrCliClient.js\";\n\nfunction createRunner(\n responses: Array<{ stdout?: string; stderr?: string; reject?: Error }> = [],\n): HerdrCommandRunner {\n const runner = vi.fn(async () => {\n const response = responses.shift();\n if (!response) return { stdout: \"{}\", stderr: \"\" };\n if (response.reject) throw response.reject;\n return { stdout: response.stdout ?? \"\", stderr: response.stderr ?? \"\" };\n });\n return runner;\n}\n\nfunction herdrCliError(response: unknown): Error {\n return Object.assign(new Error(\"herdr command failed\"), {\n stdout: JSON.stringify(response),\n stderr: \"\",\n code: 1,\n });\n}\n\nfunction jsonResponse(value: unknown): { stdout: string } {\n return { stdout: JSON.stringify(value) };\n}\n\nfunction workspaceResponse(workspaceId = \"w1\", paneId = \"w1:p1\"): { stdout: string } {\n return jsonResponse({\n result: {\n type: \"workspace_info\",\n workspace: { workspace_id: workspaceId },\n root_pane: { pane_id: paneId },\n },\n });\n}\n\nfunction agentResponse({\n name = \"reviewer\",\n paneId = \"w1:p1\",\n workspaceId,\n tabId,\n}: {\n name?: string;\n paneId?: string;\n workspaceId?: string;\n tabId?: string;\n} = {}): { stdout: string } {\n return jsonResponse({\n result: {\n type: \"agent_info\",\n agent: {\n name,\n agent: \"codex\",\n pane_id: paneId,\n ...(workspaceId ? { workspace_id: workspaceId } : {}),\n ...(tabId ? { tab_id: tabId } : {}),\n },\n },\n });\n}\n\nfunction processInfoResponse({\n paneId = \"w1:p1\",\n pid,\n shellPid,\n processName,\n}: {\n paneId?: string;\n pid?: number;\n shellPid?: number;\n processName?: string;\n} = {}): { stdout: string } {\n return jsonResponse({\n result: {\n type: \"pane_process_info\",\n process_info: {\n pane_id: paneId,\n ...(shellPid ? { shell_pid: shellPid } : {}),\n foreground_processes: pid ? [{ pid, ...(processName ? { name: processName } : {}) }] : [],\n },\n },\n });\n}\n\nconst startInput = {\n name: \"reviewer\",\n cwd: \"/repo\",\n kind: \"codex\",\n args: [],\n timeoutMs: 15000,\n};\n\ndescribe(\"HerdrAgentRuntime\", () => {\n it(\"reports unavailable when the herdr binary is missing\", async () => {\n const runner = createRunner([\n { reject: Object.assign(new Error(\"not found\"), { code: \"ENOENT\" }) },\n ]);\n const runtime = new HerdrAgentRuntime({ runner, env: {} });\n\n await expect(runtime.isAvailable()).resolves.toEqual({\n ok: false,\n reason: \"binary-missing\",\n detail: \"herdr command was not found in PATH.\",\n });\n });\n\n it(\"reports available outside Herdr when binary and snapshot work\", async () => {\n const runner = createRunner([\n { stdout: \"herdr 0.8.2\\n\" },\n jsonResponse({ id: \"cli:api:snapshot\", result: { type: \"session_snapshot\" } }),\n ]);\n const runtime = new HerdrAgentRuntime({ runner, env: {} });\n\n await expect(runtime.isAvailable()).resolves.toEqual({\n ok: true,\n insideRuntime: false,\n });\n expect(runner).toHaveBeenNthCalledWith(1, \"herdr\", [\"--version\"]);\n expect(runner).toHaveBeenNthCalledWith(2, \"herdr\", [\"api\", \"snapshot\"]);\n });\n\n it(\"includes Herdr environment context when present\", async () => {\n const runner = createRunner([\n { stdout: \"herdr 0.8.2\\n\" },\n jsonResponse({ id: \"cli:api:snapshot\", result: { type: \"session_snapshot\" } }),\n ]);\n const runtime = new HerdrAgentRuntime({\n runner,\n env: { HERDR_ENV: \"1\", HERDR_PANE_ID: \"w1:p1\" },\n });\n\n await expect(runtime.isAvailable()).resolves.toEqual({\n ok: true,\n insideRuntime: true,\n currentPaneId: \"w1:p1\",\n });\n });\n\n it(\"creates a workspace, starts the named agent, and returns an opaque Herdr ref\", async () => {\n const runner = createRunner([\n workspaceResponse(),\n agentResponse({ workspaceId: \"w1\", tabId: \"w1:t1\" }),\n processInfoResponse({ shellPid: 12000, pid: 12345, processName: \"codex\" }),\n ]);\n const runtime = new HerdrAgentRuntime({ runner, env: {} });\n\n const result = await runtime.startAgent(startInput);\n\n expect(runner).toHaveBeenNthCalledWith(1, \"herdr\", [\n \"workspace\",\n \"create\",\n \"--cwd\",\n \"/repo\",\n \"--label\",\n \"reviewer\",\n ]);\n expect(runner).toHaveBeenNthCalledWith(2, \"herdr\", [\n \"agent\",\n \"start\",\n \"reviewer\",\n \"--kind\",\n \"codex\",\n \"--pane\",\n \"w1:p1\",\n \"--timeout\",\n \"15000\",\n ]);\n expect(runner).toHaveBeenNthCalledWith(3, \"herdr\", [\"pane\", \"process-info\", \"--pane\", \"w1:p1\"]);\n expect(result).toEqual({\n pid: 12345,\n runtimeRef: {\n session: \"default\",\n workspaceId: \"w1\",\n tabId: \"w1:t1\",\n paneId: \"w1:p1\",\n agentName: \"reviewer\",\n },\n });\n });\n\n it(\"falls back to the pane shell pid when no foreground process pid is reported\", async () => {\n const runner = createRunner([\n workspaceResponse(),\n agentResponse(),\n processInfoResponse({ shellPid: 12000 }),\n ]);\n const runtime = new HerdrAgentRuntime({ runner, env: {}, processInfoPollMs: 0 });\n\n await expect(runtime.startAgent(startInput)).resolves.toMatchObject({ pid: 12000 });\n });\n\n it(\"waits for a foreground process pid before falling back to the pane shell pid\", async () => {\n const runner = createRunner([\n workspaceResponse(),\n agentResponse(),\n processInfoResponse({ shellPid: 12000 }),\n processInfoResponse({ shellPid: 12000, pid: 12345, processName: \"node\" }),\n ]);\n const runtime = new HerdrAgentRuntime({\n runner,\n env: {},\n processInfoPollMs: 100,\n processInfoPollIntervalMs: 0,\n });\n\n await expect(runtime.startAgent(startInput)).resolves.toMatchObject({ pid: 12345 });\n expect(runner).toHaveBeenNthCalledWith(3, \"herdr\", [\"pane\", \"process-info\", \"--pane\", \"w1:p1\"]);\n expect(runner).toHaveBeenNthCalledWith(4, \"herdr\", [\"pane\", \"process-info\", \"--pane\", \"w1:p1\"]);\n });\n\n it(\"passes only explicit extra agent args after the Herdr start separator\", async () => {\n const runner = createRunner([\n workspaceResponse(),\n agentResponse(),\n processInfoResponse({ pid: 12345 }),\n ]);\n const runtime = new HerdrAgentRuntime({ runner, env: {} });\n\n await runtime.startAgent({\n ...startInput,\n args: [\"--model\", \"gpt-5-codex\"],\n });\n\n expect(runner).toHaveBeenNthCalledWith(2, \"herdr\", [\n \"agent\",\n \"start\",\n \"reviewer\",\n \"--kind\",\n \"codex\",\n \"--pane\",\n \"w1:p1\",\n \"--timeout\",\n \"15000\",\n \"--\",\n \"--model\",\n \"gpt-5-codex\",\n ]);\n });\n\n it(\"retries agent start when a freshly-created Herdr pane is temporarily busy\", async () => {\n const runner = createRunner([\n workspaceResponse(\"w15\", \"w15:p1\"),\n {\n reject: herdrCliError({\n error: {\n code: \"agent_pane_busy\",\n message: \"agent target pane w15:p1 is not an available shell\",\n },\n id: \"cli:agent:start\",\n }),\n },\n agentResponse({ paneId: \"w15:p1\", workspaceId: \"w15\", tabId: \"w15:t1\" }),\n processInfoResponse({ paneId: \"w15:p1\", pid: 12345 }),\n ]);\n const runtime = new HerdrAgentRuntime({\n runner,\n env: {},\n agentStartBusyRetryMs: 100,\n agentStartBusyRetryIntervalMs: 0,\n });\n\n await expect(runtime.startAgent(startInput)).resolves.toMatchObject({\n runtimeRef: {\n workspaceId: \"w15\",\n paneId: \"w15:p1\",\n },\n });\n\n expect(runner).toHaveBeenNthCalledWith(2, \"herdr\", [\n \"agent\",\n \"start\",\n \"reviewer\",\n \"--kind\",\n \"codex\",\n \"--pane\",\n \"w15:p1\",\n \"--timeout\",\n \"15000\",\n ]);\n expect(runner).toHaveBeenNthCalledWith(3, \"herdr\", [\n \"agent\",\n \"start\",\n \"reviewer\",\n \"--kind\",\n \"codex\",\n \"--pane\",\n \"w15:p1\",\n \"--timeout\",\n \"15000\",\n ]);\n });\n\n it(\"surfaces non-retryable Herdr agent start errors without retrying\", async () => {\n const runner = createRunner([\n workspaceResponse(),\n {\n reject: herdrCliError({\n error: {\n code: \"duplicate_agent_name\",\n message: \"agent name reviewer already exists\",\n },\n id: \"cli:agent:start\",\n }),\n },\n ]);\n const runtime = new HerdrAgentRuntime({ runner, env: {} });\n\n await expect(runtime.startAgent(startInput)).rejects.toMatchObject({\n code: \"duplicate_agent_name\",\n message: \"agent name reviewer already exists\",\n });\n\n expect(runner).toHaveBeenCalledTimes(2);\n });\n\n it(\"rejects start responses when Herdr process info does not include a pid\", async () => {\n const runner = createRunner([workspaceResponse(), agentResponse(), processInfoResponse()]);\n const runtime = new HerdrAgentRuntime({ runner, env: {} });\n\n await expect(runtime.startAgent(startInput)).rejects.toThrow(\n new HerdrRuntimeError(\"Herdr pane process-info response did not include process pid.\"),\n );\n });\n\n it(\"rejects start responses that do not include a pane id\", async () => {\n const runner = createRunner([{ stdout: '{\"result\":{\"workspace\":{\"workspace_id\":\"w1\"}}}' }]);\n const runtime = new HerdrAgentRuntime({ runner, env: {} });\n\n await expect(runtime.startAgent(startInput)).rejects.toThrow(\n new HerdrRuntimeError(\"Herdr workspace create response did not include root pane id.\"),\n );\n });\n\n it(\"sends, waits, reads, focuses, and stops by Herdr pane ref\", async () => {\n const runner = createRunner([\n { stdout: \"{}\" },\n { stdout: '{\"result\":{\"agent\":{\"agent_status\":\"done\"}}}' },\n { stdout: \"done\\n\" },\n { stdout: \"{}\" },\n { stdout: \"{}\" },\n ]);\n const runtime = new HerdrAgentRuntime({ runner, env: {} });\n const runtimeRef = { paneId: \"w1:p2\", agentName: \"reviewer\" };\n\n await runtime.send({ runtimeRef, prompt: \"continue\" });\n await runtime.wait({ runtimeRef, timeoutMs: 2000 });\n await expect(runtime.readOutput({ runtimeRef, lines: 80 })).resolves.toBe(\"done\\n\");\n await expect(runtime.focus({ runtimeRef })).resolves.toBe(true);\n await runtime.stop({ runtimeRef });\n\n expect(runner).toHaveBeenNthCalledWith(1, \"herdr\", [\"agent\", \"prompt\", \"w1:p2\", \"continue\"]);\n expect(runner).toHaveBeenNthCalledWith(2, \"herdr\", [\n \"agent\",\n \"wait\",\n \"w1:p2\",\n \"--until\",\n \"done\",\n \"--until\",\n \"blocked\",\n \"--timeout\",\n \"2000\",\n ]);\n expect(runner).toHaveBeenNthCalledWith(3, \"herdr\", [\n \"agent\",\n \"read\",\n \"w1:p2\",\n \"--source\",\n \"recent-unwrapped\",\n \"--lines\",\n \"80\",\n ]);\n expect(runner).toHaveBeenNthCalledWith(4, \"herdr\", [\"agent\", \"focus\", \"w1:p2\"]);\n expect(runner).toHaveBeenNthCalledWith(5, \"herdr\", [\"pane\", \"close\", \"w1:p2\"]);\n });\n});\n"],"names":["HerdrAgentRuntime","HerdrRuntimeError","createRunner","responses","runner","vi","fn","response","shift","stdout","stderr","reject","herdrCliError","Object","assign","Error","JSON","stringify","code","jsonResponse","value","workspaceResponse","workspaceId","paneId","result","type","workspace","workspace_id","root_pane","pane_id","agentResponse","name","tabId","agent","tab_id","processInfoResponse","pid","shellPid","processName","process_info","shell_pid","foreground_processes","startInput","cwd","kind","args","timeoutMs","describe","it","runtime","env","expect","isAvailable","resolves","toEqual","ok","reason","detail","id","insideRuntime","toHaveBeenNthCalledWith","HERDR_ENV","HERDR_PANE_ID","currentPaneId","startAgent","runtimeRef","session","agentName","processInfoPollMs","toMatchObject","processInfoPollIntervalMs","error","message","agentStartBusyRetryMs","agentStartBusyRetryIntervalMs","rejects","toHaveBeenCalledTimes","toThrow","send","prompt","wait","readOutput","lines","toBe","focus","stop"],"mappings":"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"}
|
|
@@ -96,7 +96,7 @@ describe("AgentRegistry", ()=>{
|
|
|
96
96
|
runtimeRef
|
|
97
97
|
});
|
|
98
98
|
});
|
|
99
|
-
it("
|
|
99
|
+
it("preserves existing identity and routing fields for same-pid refreshes", ()=>{
|
|
100
100
|
const runtimeRef = {
|
|
101
101
|
session: "default",
|
|
102
102
|
paneId: "w1:p2",
|
|
@@ -104,19 +104,28 @@ describe("AgentRegistry", ()=>{
|
|
|
104
104
|
};
|
|
105
105
|
registry.register(makeEntry({
|
|
106
106
|
name: "old-name",
|
|
107
|
-
pid: process.pid
|
|
107
|
+
pid: process.pid,
|
|
108
|
+
runtime: "tmux",
|
|
109
|
+
runtimeRef: {
|
|
110
|
+
session: "old-name"
|
|
111
|
+
},
|
|
112
|
+
cwd: "/original"
|
|
108
113
|
}));
|
|
109
114
|
registry.register(makeEntry({
|
|
110
115
|
name: "requested-name",
|
|
111
116
|
pid: process.pid,
|
|
112
117
|
runtime: "herdr",
|
|
113
|
-
runtimeRef
|
|
118
|
+
runtimeRef,
|
|
119
|
+
cwd: "/incoming"
|
|
114
120
|
}));
|
|
115
|
-
expect(registry.lookup("
|
|
116
|
-
expect(registry.lookup("
|
|
121
|
+
expect(registry.lookup("requested-name")).toBeNull();
|
|
122
|
+
expect(registry.lookup("old-name")).toMatchObject({
|
|
117
123
|
pid: process.pid,
|
|
118
|
-
runtime: "
|
|
119
|
-
runtimeRef
|
|
124
|
+
runtime: "tmux",
|
|
125
|
+
runtimeRef: {
|
|
126
|
+
session: "old-name"
|
|
127
|
+
},
|
|
128
|
+
cwd: "/original"
|
|
120
129
|
});
|
|
121
130
|
});
|
|
122
131
|
it("preserves existing runtime ref when incoming runtime ref is empty", ()=>{
|
|
@@ -144,7 +153,7 @@ describe("AgentRegistry", ()=>{
|
|
|
144
153
|
}));
|
|
145
154
|
expect(registry.lookup("a")?.runtimeRef).toBeNull();
|
|
146
155
|
});
|
|
147
|
-
it("
|
|
156
|
+
it("preserves an existing generated fallback for the same pid", ()=>{
|
|
148
157
|
registry.register(makeEntry({
|
|
149
158
|
name: `ai-devkit-${process.pid}`,
|
|
150
159
|
runtimeRef: null
|
|
@@ -155,10 +164,8 @@ describe("AgentRegistry", ()=>{
|
|
|
155
164
|
session: "custom-name"
|
|
156
165
|
}
|
|
157
166
|
}));
|
|
158
|
-
expect(registry.lookup("custom-name")
|
|
159
|
-
|
|
160
|
-
});
|
|
161
|
-
expect(registry.lookup(`ai-devkit-${process.pid}`)).toBeNull();
|
|
167
|
+
expect(registry.lookup("custom-name")).toBeNull();
|
|
168
|
+
expect(registry.lookup(`ai-devkit-${process.pid}`)?.runtimeRef).toBeNull();
|
|
162
169
|
expect(registry.list()).toHaveLength(1);
|
|
163
170
|
});
|
|
164
171
|
it("preserves an existing name conflict when its probe fails with EPERM", ()=>{
|
|
@@ -241,7 +248,7 @@ describe("AgentRegistry", ()=>{
|
|
|
241
248
|
runtimeRef: null
|
|
242
249
|
}));
|
|
243
250
|
expect(registry.list()).toHaveLength(1);
|
|
244
|
-
expect(registry.lookup(
|
|
251
|
+
expect(registry.lookup(`ai-devkit-${process.pid}`)?.pid).toBe(process.pid);
|
|
245
252
|
});
|
|
246
253
|
it("cleans up a cross-type row when its pid has been reused", ()=>{
|
|
247
254
|
registry.register(makeEntry({
|
|
@@ -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 {\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":"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"}
|
|
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(\"preserves existing identity and routing fields for same-pid refreshes\", () => {\n const runtimeRef = { session: \"default\", paneId: \"w1:p2\", agentName: \"requested-name\" };\n\n registry.register(\n makeEntry({\n name: \"old-name\",\n pid: process.pid,\n runtime: \"tmux\",\n runtimeRef: { session: \"old-name\" },\n cwd: \"/original\",\n }),\n );\n registry.register(\n makeEntry({\n name: \"requested-name\",\n pid: process.pid,\n runtime: \"herdr\",\n runtimeRef,\n cwd: \"/incoming\",\n }),\n );\n\n expect(registry.lookup(\"requested-name\")).toBeNull();\n expect(registry.lookup(\"old-name\")).toMatchObject({\n pid: process.pid,\n runtime: \"tmux\",\n runtimeRef: { session: \"old-name\" },\n cwd: \"/original\",\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(\"preserves an existing 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\")).toBeNull();\n expect(registry.lookup(`ai-devkit-${process.pid}`)?.runtimeRef).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(`ai-devkit-${process.pid}`)?.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,yEAAyE;YAC1E,MAAMhB,aAAa;gBAAEC,SAAS;gBAAW0B,QAAQ;gBAASC,WAAW;YAAiB;YAEtFvB,SAASY,QAAQ,CACf7B,UAAU;gBACRE,MAAM;gBACNE,KAAKC,QAAQD,GAAG;gBAChBO,SAAS;gBACTC,YAAY;oBAAEC,SAAS;gBAAW;gBAClCP,KAAK;YACP;YAEFW,SAASY,QAAQ,CACf7B,UAAU;gBACRE,MAAM;gBACNE,KAAKC,QAAQD,GAAG;gBAChBO,SAAS;gBACTC;gBACAN,KAAK;YACP;YAGFwB,OAAOb,SAASwB,MAAM,CAAC,mBAAmBE,QAAQ;YAClDb,OAAOb,SAASwB,MAAM,CAAC,aAAaC,aAAa,CAAC;gBAChDtC,KAAKC,QAAQD,GAAG;gBAChBO,SAAS;gBACTC,YAAY;oBAAEC,SAAS;gBAAW;gBAClCP,KAAK;YACP;QACF;QAEAsB,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,6DAA6D;YAC9DX,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,gBAAgBE,QAAQ;YAC/Cb,OAAOb,SAASwB,MAAM,CAAC,CAAC,UAAU,EAAEpC,QAAQD,GAAG,EAAE,GAAGQ,YAAY+B,QAAQ;YACxEb,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,CAAC,UAAU,EAAEpC,QAAQD,GAAG,EAAE,GAAGA,KAAK6B,IAAI,CAAC5B,QAAQD,GAAG;QAC3E;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"}
|
|
@@ -16,6 +16,7 @@ export declare class OpenCodeAdapter implements AgentAdapter {
|
|
|
16
16
|
readonly processNames: readonly ["opencode"];
|
|
17
17
|
private static readonly IDLE_THRESHOLD_MINUTES;
|
|
18
18
|
private readonly dbPath;
|
|
19
|
+
private readonly cleanup;
|
|
19
20
|
private db;
|
|
20
21
|
constructor();
|
|
21
22
|
close(): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OpenCodeAdapter.d.ts","sourceRoot":"","sources":["../../src/adapters/OpenCodeAdapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAKH,OAAO,KAAK,EACV,YAAY,EACZ,SAAS,EACT,WAAW,EACX,mBAAmB,EACnB,cAAc,EACd,mBAAmB,EACnB,qBAAqB,EACtB,MAAM,mBAAmB,CAAC;AAoC3B,qBAAa,eAAgB,YAAW,YAAY;IAClD,QAAQ,CAAC,IAAI,EAAG,UAAU,CAAU;IACpC,QAAQ,CAAC,YAAY,wBAAyB;IAE9C,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,sBAAsB,CAAK;IAEnD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,EAAE,CAAkC;;
|
|
1
|
+
{"version":3,"file":"OpenCodeAdapter.d.ts","sourceRoot":"","sources":["../../src/adapters/OpenCodeAdapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAKH,OAAO,KAAK,EACV,YAAY,EACZ,SAAS,EACT,WAAW,EACX,mBAAmB,EACnB,cAAc,EACd,mBAAmB,EACnB,qBAAqB,EACtB,MAAM,mBAAmB,CAAC;AAoC3B,qBAAa,eAAgB,YAAW,YAAY;IAClD,QAAQ,CAAC,IAAI,EAAG,UAAU,CAAU;IACpC,QAAQ,CAAC,YAAY,wBAAyB;IAE9C,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,sBAAsB,CAAK;IAEnD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA4B;IACpD,OAAO,CAAC,EAAE,CAAkC;;IAS5C,KAAK,IAAI,IAAI;IAeb,OAAO,CAAC,MAAM,CAAC,aAAa;IAO5B,SAAS,CAAC,WAAW,EAAE,WAAW,GAAG,OAAO;IAKtC,YAAY,CAAC,OAAO,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;IA6BzE,eAAe,CAAC,eAAe,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,mBAAmB,EAAE;IAmD1F,YAAY,CAAC,IAAI,CAAC,EAAE,mBAAmB,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC;IAyCzE,OAAO,CAAC,uBAAuB;IAsB/B,OAAO,CAAC,eAAe;IAwEvB,OAAO,CAAC,iBAAiB;IAqBzB,OAAO,CAAC,mBAAmB;IAa3B,OAAO,CAAC,eAAe;IASvB,OAAO,CAAC,MAAM;CAUf"}
|
|
@@ -34,15 +34,18 @@ export class OpenCodeAdapter {
|
|
|
34
34
|
];
|
|
35
35
|
static IDLE_THRESHOLD_MINUTES = 5;
|
|
36
36
|
dbPath;
|
|
37
|
+
cleanup = ()=>this.close();
|
|
37
38
|
db = null;
|
|
38
39
|
constructor(){
|
|
39
40
|
this.dbPath = OpenCodeAdapter.resolveDbPath();
|
|
40
|
-
|
|
41
|
-
process.once("
|
|
42
|
-
process.once("
|
|
43
|
-
process.once("SIGTERM", cleanup);
|
|
41
|
+
process.once("exit", this.cleanup);
|
|
42
|
+
process.once("SIGINT", this.cleanup);
|
|
43
|
+
process.once("SIGTERM", this.cleanup);
|
|
44
44
|
}
|
|
45
45
|
close() {
|
|
46
|
+
process.off("exit", this.cleanup);
|
|
47
|
+
process.off("SIGINT", this.cleanup);
|
|
48
|
+
process.off("SIGTERM", this.cleanup);
|
|
46
49
|
if (this.db) {
|
|
47
50
|
try {
|
|
48
51
|
this.db.close();
|