@ai-devkit/agent-manager 0.33.0 → 0.34.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/AgentManager.d.ts +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__/capacity/codex.test.js +2 -1
- package/dist/__tests__/capacity/codex.test.js.map +1 -1
- package/dist/__tests__/capacity/index.test.js +6 -3
- package/dist/__tests__/capacity/index.test.js.map +1 -1
- package/dist/__tests__/capacity/zai.test.js +213 -0
- package/dist/__tests__/capacity/zai.test.js.map +1 -0
- 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__/providers/opencode/OpenCodeAdapter.test.js +189 -0
- package/dist/__tests__/providers/opencode/OpenCodeAdapter.test.js.map +1 -0
- package/dist/__tests__/providers/opencode/OpenCodeAgentMapper.test.js +89 -0
- package/dist/__tests__/providers/opencode/OpenCodeAgentMapper.test.js.map +1 -0
- package/dist/__tests__/providers/opencode/OpenCodeSessionLocator.test.js +94 -0
- package/dist/__tests__/providers/opencode/OpenCodeSessionLocator.test.js.map +1 -0
- package/dist/__tests__/providers/opencode/OpenCodeSessionParser.test.js +147 -0
- package/dist/__tests__/providers/opencode/OpenCodeSessionParser.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/index.d.ts +3 -3
- package/dist/adapters/index.d.ts.map +1 -1
- package/dist/adapters/index.js +3 -3
- package/dist/adapters/index.js.map +1 -1
- package/dist/capacity/codex.d.ts +1 -0
- package/dist/capacity/codex.d.ts.map +1 -1
- package/dist/capacity/codex.js +9 -4
- package/dist/capacity/codex.js.map +1 -1
- package/dist/capacity/index.d.ts +8 -0
- package/dist/capacity/index.d.ts.map +1 -1
- package/dist/capacity/index.js +10 -9
- package/dist/capacity/index.js.map +1 -1
- package/dist/capacity/types.d.ts +8 -0
- package/dist/capacity/types.d.ts.map +1 -1
- package/dist/capacity/types.js.map +1 -1
- package/dist/capacity/zai.d.ts +14 -0
- package/dist/capacity/zai.d.ts.map +1 -0
- package/dist/capacity/zai.js +203 -0
- package/dist/capacity/zai.js.map +1 -0
- package/dist/index.d.ts +8 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -4
- 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/{adapters → providers/opencode}/OpenCodeAdapter.d.ts +6 -12
- package/dist/providers/opencode/OpenCodeAdapter.d.ts.map +1 -0
- package/dist/providers/opencode/OpenCodeAdapter.js +86 -0
- package/dist/providers/opencode/OpenCodeAdapter.js.map +1 -0
- package/dist/providers/opencode/OpenCodeAgentMapper.d.ts +11 -0
- package/dist/providers/opencode/OpenCodeAgentMapper.d.ts.map +1 -0
- package/dist/providers/opencode/OpenCodeAgentMapper.js +50 -0
- package/dist/providers/opencode/OpenCodeAgentMapper.js.map +1 -0
- package/dist/providers/opencode/OpenCodeSessionLocator.d.ts +21 -0
- package/dist/providers/opencode/OpenCodeSessionLocator.d.ts.map +1 -0
- package/dist/providers/opencode/OpenCodeSessionLocator.js +99 -0
- package/dist/providers/opencode/OpenCodeSessionLocator.js.map +1 -0
- package/dist/providers/opencode/OpenCodeSessionParser.d.ts +18 -0
- package/dist/providers/opencode/OpenCodeSessionParser.d.ts.map +1 -0
- package/dist/providers/opencode/OpenCodeSessionParser.js +104 -0
- package/dist/providers/opencode/OpenCodeSessionParser.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__/capacity/codex.test.ts +94 -26
- package/src/__tests__/capacity/fixtures/zai-auth.json +6 -0
- package/src/__tests__/capacity/fixtures/zai-quota-invalid.json +7 -0
- package/src/__tests__/capacity/fixtures/zai-quota.json +38 -0
- package/src/__tests__/capacity/index.test.ts +10 -3
- package/src/__tests__/capacity/zai.test.ts +186 -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__/providers/opencode/OpenCodeAdapter.test.ts +197 -0
- package/src/__tests__/providers/opencode/OpenCodeAgentMapper.test.ts +83 -0
- package/src/__tests__/providers/opencode/OpenCodeSessionLocator.test.ts +84 -0
- package/src/__tests__/providers/opencode/OpenCodeSessionParser.test.ts +148 -0
- 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/index.ts +3 -3
- package/src/capacity/codex.ts +96 -28
- package/src/capacity/index.ts +29 -11
- package/src/capacity/types.ts +8 -0
- package/src/capacity/zai.ts +237 -0
- package/src/index.ts +18 -6
- 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/providers/opencode/OpenCodeAdapter.ts +112 -0
- package/src/providers/opencode/OpenCodeAgentMapper.ts +61 -0
- package/src/providers/opencode/OpenCodeSessionLocator.ts +123 -0
- package/src/providers/opencode/OpenCodeSessionParser.ts +145 -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/__tests__/adapters/OpenCodeAdapter.test.js +0 -635
- package/dist/__tests__/adapters/OpenCodeAdapter.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/dist/adapters/OpenCodeAdapter.d.ts.map +0 -1
- package/dist/adapters/OpenCodeAdapter.js +0 -286
- package/dist/adapters/OpenCodeAdapter.js.map +0 -1
- package/src/__tests__/adapters/OpenCodeAdapter.test.ts +0 -543
- package/src/adapters/CopilotAdapter.ts +0 -483
- package/src/adapters/GeminiCliAdapter.ts +0 -699
- package/src/adapters/OpenCodeAdapter.ts +0 -369
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import { HerdrCliClient } from "./HerdrCliClient.js";
|
|
2
|
+
export async function fetchHerdrAgentPanes(runner) {
|
|
3
|
+
const client = new HerdrCliClient(runner);
|
|
4
|
+
const response = await client.runJson([
|
|
5
|
+
"pane",
|
|
6
|
+
"list"
|
|
7
|
+
]);
|
|
8
|
+
return enrichHerdrAgentPanes(client, extractHerdrAgentPanes(response));
|
|
9
|
+
}
|
|
10
|
+
export function extractHerdrAgentPanes(value) {
|
|
11
|
+
const snapshot = getObject(value, [
|
|
12
|
+
"result",
|
|
13
|
+
"snapshot"
|
|
14
|
+
]);
|
|
15
|
+
const rawPanes = getArray(value, [
|
|
16
|
+
"result",
|
|
17
|
+
"panes"
|
|
18
|
+
]) ?? snapshot?.agents;
|
|
19
|
+
if (!Array.isArray(rawPanes)) return [];
|
|
20
|
+
const panes = [];
|
|
21
|
+
for (const rawPane of rawPanes){
|
|
22
|
+
if (!rawPane || typeof rawPane !== "object" || Array.isArray(rawPane)) continue;
|
|
23
|
+
const pane = rawPane;
|
|
24
|
+
const agent = nonEmptyString(pane.agent);
|
|
25
|
+
const paneId = nonEmptyString(pane.pane_id);
|
|
26
|
+
if (!agent || !paneId) continue;
|
|
27
|
+
const session = getObject(pane, [
|
|
28
|
+
"agent_session"
|
|
29
|
+
]);
|
|
30
|
+
const agentSessionId = nonEmptyString(session?.value);
|
|
31
|
+
const cwd = nonEmptyString(pane.cwd);
|
|
32
|
+
const workspaceId = nonEmptyString(pane.workspace_id);
|
|
33
|
+
const tabId = nonEmptyString(pane.tab_id);
|
|
34
|
+
panes.push({
|
|
35
|
+
agent,
|
|
36
|
+
paneId,
|
|
37
|
+
...agentSessionId ? {
|
|
38
|
+
agentSessionId
|
|
39
|
+
} : {},
|
|
40
|
+
...cwd ? {
|
|
41
|
+
cwd
|
|
42
|
+
} : {},
|
|
43
|
+
...workspaceId ? {
|
|
44
|
+
workspaceId
|
|
45
|
+
} : {},
|
|
46
|
+
...tabId ? {
|
|
47
|
+
tabId
|
|
48
|
+
} : {}
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
return panes;
|
|
52
|
+
}
|
|
53
|
+
export function findMatchingHerdrPane(agent, panes) {
|
|
54
|
+
if (agent.sessionId) {
|
|
55
|
+
const sessionMatches = panes.filter((pane)=>pane.agentSessionId === agent.sessionId);
|
|
56
|
+
if (sessionMatches.length === 1) return sessionMatches[0];
|
|
57
|
+
if (sessionMatches.length > 1) return null;
|
|
58
|
+
}
|
|
59
|
+
const foregroundPidMatches = panes.filter((pane)=>pane.foregroundPids?.includes(agent.pid));
|
|
60
|
+
if (foregroundPidMatches.length === 1) return foregroundPidMatches[0];
|
|
61
|
+
if (foregroundPidMatches.length > 1) return null;
|
|
62
|
+
const shellPidMatches = panes.filter((pane)=>pane.shellPid === agent.pid);
|
|
63
|
+
if (shellPidMatches.length === 1) return shellPidMatches[0];
|
|
64
|
+
if (shellPidMatches.length > 1) return null;
|
|
65
|
+
const cwdMatches = panes.filter((pane)=>pane.cwd === agent.projectPath && herdrAgentMatchesType(pane.agent, agent.type));
|
|
66
|
+
return cwdMatches.length === 1 ? cwdMatches[0] : null;
|
|
67
|
+
}
|
|
68
|
+
export function herdrPaneToRuntimeRef(pane, agentName) {
|
|
69
|
+
return {
|
|
70
|
+
session: "default",
|
|
71
|
+
paneId: pane.paneId,
|
|
72
|
+
agentName,
|
|
73
|
+
...pane.workspaceId ? {
|
|
74
|
+
workspaceId: pane.workspaceId
|
|
75
|
+
} : {},
|
|
76
|
+
...pane.tabId ? {
|
|
77
|
+
tabId: pane.tabId
|
|
78
|
+
} : {}
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
function herdrAgentMatchesType(herdrAgent, agentType) {
|
|
82
|
+
const normalized = herdrAgent.toLowerCase();
|
|
83
|
+
const candidates = {
|
|
84
|
+
claude: [
|
|
85
|
+
"claude"
|
|
86
|
+
],
|
|
87
|
+
codex: [
|
|
88
|
+
"codex"
|
|
89
|
+
],
|
|
90
|
+
copilot: [
|
|
91
|
+
"copilot"
|
|
92
|
+
],
|
|
93
|
+
gemini_cli: [
|
|
94
|
+
"gemini",
|
|
95
|
+
"gemini_cli"
|
|
96
|
+
],
|
|
97
|
+
grok_cli: [
|
|
98
|
+
"grok",
|
|
99
|
+
"grok_cli"
|
|
100
|
+
],
|
|
101
|
+
opencode: [
|
|
102
|
+
"opencode"
|
|
103
|
+
],
|
|
104
|
+
pi: [
|
|
105
|
+
"pi"
|
|
106
|
+
],
|
|
107
|
+
other: [
|
|
108
|
+
"other"
|
|
109
|
+
]
|
|
110
|
+
};
|
|
111
|
+
return candidates[agentType]?.includes(normalized) ?? false;
|
|
112
|
+
}
|
|
113
|
+
async function enrichHerdrAgentPanes(client, panes) {
|
|
114
|
+
return Promise.all(panes.map(async (pane)=>{
|
|
115
|
+
try {
|
|
116
|
+
const response = await client.runJson([
|
|
117
|
+
"pane",
|
|
118
|
+
"process-info",
|
|
119
|
+
"--pane",
|
|
120
|
+
pane.paneId
|
|
121
|
+
]);
|
|
122
|
+
return {
|
|
123
|
+
...pane,
|
|
124
|
+
...extractPaneProcessIds(response)
|
|
125
|
+
};
|
|
126
|
+
} catch {
|
|
127
|
+
return pane;
|
|
128
|
+
}
|
|
129
|
+
}));
|
|
130
|
+
}
|
|
131
|
+
function extractPaneProcessIds(value) {
|
|
132
|
+
const processInfo = getObject(value, [
|
|
133
|
+
"result",
|
|
134
|
+
"process_info"
|
|
135
|
+
]);
|
|
136
|
+
if (!processInfo) return {};
|
|
137
|
+
const foregroundProcesses = processInfo.foreground_processes;
|
|
138
|
+
const foregroundPids = [];
|
|
139
|
+
if (Array.isArray(foregroundProcesses)) {
|
|
140
|
+
for (const foregroundProcess of foregroundProcesses){
|
|
141
|
+
if (!foregroundProcess || typeof foregroundProcess !== "object" || Array.isArray(foregroundProcess)) continue;
|
|
142
|
+
const pid = positiveIntegerOrNull(foregroundProcess.pid);
|
|
143
|
+
if (pid !== null) foregroundPids.push(pid);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
const shellPid = positiveIntegerOrNull(processInfo.shell_pid);
|
|
147
|
+
return {
|
|
148
|
+
...foregroundPids.length > 0 ? {
|
|
149
|
+
foregroundPids
|
|
150
|
+
} : {},
|
|
151
|
+
...shellPid !== null ? {
|
|
152
|
+
shellPid
|
|
153
|
+
} : {}
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
function getArray(value, path) {
|
|
157
|
+
let current = value;
|
|
158
|
+
for (const part of path){
|
|
159
|
+
if (!current || typeof current !== "object" || Array.isArray(current) || !(part in current)) {
|
|
160
|
+
return null;
|
|
161
|
+
}
|
|
162
|
+
current = current[part];
|
|
163
|
+
}
|
|
164
|
+
return Array.isArray(current) ? current : null;
|
|
165
|
+
}
|
|
166
|
+
function getObject(value, path) {
|
|
167
|
+
let current = value;
|
|
168
|
+
for (const part of path){
|
|
169
|
+
if (!current || typeof current !== "object" || Array.isArray(current) || !(part in current)) {
|
|
170
|
+
return null;
|
|
171
|
+
}
|
|
172
|
+
current = current[part];
|
|
173
|
+
}
|
|
174
|
+
return current && typeof current === "object" && !Array.isArray(current) ? current : null;
|
|
175
|
+
}
|
|
176
|
+
function nonEmptyString(value) {
|
|
177
|
+
return typeof value === "string" && value.trim() ? value : undefined;
|
|
178
|
+
}
|
|
179
|
+
function positiveIntegerOrNull(value) {
|
|
180
|
+
return typeof value === "number" && Number.isInteger(value) && value > 0 ? value : null;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
//# sourceMappingURL=HerdrAgentDiscovery.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/runtime/herdr/HerdrAgentDiscovery.ts"],"sourcesContent":["import type { AgentInfo, AgentType } from \"../../adapters/AgentAdapter.js\";\nimport { HerdrCliClient, type HerdrCommandRunner } from \"./HerdrCliClient.js\";\nimport type { HerdrRuntimeRef } from \"./HerdrRuntimeRef.js\";\n\nexport interface HerdrAgentPane {\n agent: string;\n agentSessionId?: string;\n cwd?: string;\n paneId: string;\n workspaceId?: string;\n tabId?: string;\n foregroundPids?: number[];\n shellPid?: number;\n}\n\nexport async function fetchHerdrAgentPanes(runner?: HerdrCommandRunner): Promise<HerdrAgentPane[]> {\n const client = new HerdrCliClient(runner);\n const response = await client.runJson([\"pane\", \"list\"]);\n return enrichHerdrAgentPanes(client, extractHerdrAgentPanes(response));\n}\n\nexport function extractHerdrAgentPanes(value: unknown): HerdrAgentPane[] {\n const snapshot = getObject(value, [\"result\", \"snapshot\"]);\n const rawPanes = getArray(value, [\"result\", \"panes\"]) ?? snapshot?.agents;\n if (!Array.isArray(rawPanes)) return [];\n\n const panes: HerdrAgentPane[] = [];\n for (const rawPane of rawPanes) {\n if (!rawPane || typeof rawPane !== \"object\" || Array.isArray(rawPane)) continue;\n const pane = rawPane as Record<string, unknown>;\n const agent = nonEmptyString(pane.agent);\n const paneId = nonEmptyString(pane.pane_id);\n if (!agent || !paneId) continue;\n\n const session = getObject(pane, [\"agent_session\"]);\n const agentSessionId = nonEmptyString(session?.value);\n const cwd = nonEmptyString(pane.cwd);\n const workspaceId = nonEmptyString(pane.workspace_id);\n const tabId = nonEmptyString(pane.tab_id);\n\n panes.push({\n agent,\n paneId,\n ...(agentSessionId ? { agentSessionId } : {}),\n ...(cwd ? { cwd } : {}),\n ...(workspaceId ? { workspaceId } : {}),\n ...(tabId ? { tabId } : {}),\n });\n }\n\n return panes;\n}\n\nexport function findMatchingHerdrPane(\n agent: Pick<AgentInfo, \"type\" | \"projectPath\" | \"sessionId\" | \"pid\">,\n panes: readonly HerdrAgentPane[],\n): HerdrAgentPane | null {\n if (agent.sessionId) {\n const sessionMatches = panes.filter((pane) => pane.agentSessionId === agent.sessionId);\n if (sessionMatches.length === 1) return sessionMatches[0]!;\n if (sessionMatches.length > 1) return null;\n }\n\n const foregroundPidMatches = panes.filter((pane) => pane.foregroundPids?.includes(agent.pid));\n if (foregroundPidMatches.length === 1) return foregroundPidMatches[0]!;\n if (foregroundPidMatches.length > 1) return null;\n\n const shellPidMatches = panes.filter((pane) => pane.shellPid === agent.pid);\n if (shellPidMatches.length === 1) return shellPidMatches[0]!;\n if (shellPidMatches.length > 1) return null;\n\n const cwdMatches = panes.filter(\n (pane) => pane.cwd === agent.projectPath && herdrAgentMatchesType(pane.agent, agent.type),\n );\n return cwdMatches.length === 1 ? cwdMatches[0]! : null;\n}\n\nexport function herdrPaneToRuntimeRef(pane: HerdrAgentPane, agentName: string): HerdrRuntimeRef {\n return {\n session: \"default\",\n paneId: pane.paneId,\n agentName,\n ...(pane.workspaceId ? { workspaceId: pane.workspaceId } : {}),\n ...(pane.tabId ? { tabId: pane.tabId } : {}),\n };\n}\n\nfunction herdrAgentMatchesType(herdrAgent: string, agentType: AgentType): boolean {\n const normalized = herdrAgent.toLowerCase();\n const candidates: Record<AgentType, readonly string[]> = {\n claude: [\"claude\"],\n codex: [\"codex\"],\n copilot: [\"copilot\"],\n gemini_cli: [\"gemini\", \"gemini_cli\"],\n grok_cli: [\"grok\", \"grok_cli\"],\n opencode: [\"opencode\"],\n pi: [\"pi\"],\n other: [\"other\"],\n };\n return candidates[agentType]?.includes(normalized) ?? false;\n}\n\nasync function enrichHerdrAgentPanes(\n client: HerdrCliClient,\n panes: HerdrAgentPane[],\n): Promise<HerdrAgentPane[]> {\n return Promise.all(\n panes.map(async (pane) => {\n try {\n const response = await client.runJson([\"pane\", \"process-info\", \"--pane\", pane.paneId]);\n return {\n ...pane,\n ...extractPaneProcessIds(response),\n };\n } catch {\n return pane;\n }\n }),\n );\n}\n\nfunction extractPaneProcessIds(value: unknown): Pick<HerdrAgentPane, \"foregroundPids\" | \"shellPid\"> {\n const processInfo = getObject(value, [\"result\", \"process_info\"]);\n if (!processInfo) return {};\n\n const foregroundProcesses = processInfo.foreground_processes;\n const foregroundPids: number[] = [];\n if (Array.isArray(foregroundProcesses)) {\n for (const foregroundProcess of foregroundProcesses) {\n if (\n !foregroundProcess ||\n typeof foregroundProcess !== \"object\" ||\n Array.isArray(foregroundProcess)\n )\n continue;\n const pid = positiveIntegerOrNull((foregroundProcess as { pid?: unknown }).pid);\n if (pid !== null) foregroundPids.push(pid);\n }\n }\n const shellPid = positiveIntegerOrNull(processInfo.shell_pid);\n\n return {\n ...(foregroundPids.length > 0 ? { foregroundPids } : {}),\n ...(shellPid !== null ? { shellPid } : {}),\n };\n}\n\nfunction getArray(value: unknown, path: string[]): unknown[] | null {\n let current = value;\n for (const part of path) {\n if (!current || typeof current !== \"object\" || Array.isArray(current) || !(part in current)) {\n return null;\n }\n current = (current as Record<string, unknown>)[part];\n }\n return Array.isArray(current) ? current : null;\n}\n\nfunction getObject(value: unknown, path: string[]): Record<string, unknown> | null {\n let current = value;\n for (const part of path) {\n if (!current || typeof current !== \"object\" || Array.isArray(current) || !(part in current)) {\n return null;\n }\n current = (current as Record<string, unknown>)[part];\n }\n return current && typeof current === \"object\" && !Array.isArray(current)\n ? (current as Record<string, unknown>)\n : null;\n}\n\nfunction nonEmptyString(value: unknown): string | undefined {\n return typeof value === \"string\" && value.trim() ? value : undefined;\n}\n\nfunction positiveIntegerOrNull(value: unknown): number | null {\n return typeof value === \"number\" && Number.isInteger(value) && value > 0 ? value : null;\n}\n"],"names":["HerdrCliClient","fetchHerdrAgentPanes","runner","client","response","runJson","enrichHerdrAgentPanes","extractHerdrAgentPanes","value","snapshot","getObject","rawPanes","getArray","agents","Array","isArray","panes","rawPane","pane","agent","nonEmptyString","paneId","pane_id","session","agentSessionId","cwd","workspaceId","workspace_id","tabId","tab_id","push","findMatchingHerdrPane","sessionId","sessionMatches","filter","length","foregroundPidMatches","foregroundPids","includes","pid","shellPidMatches","shellPid","cwdMatches","projectPath","herdrAgentMatchesType","type","herdrPaneToRuntimeRef","agentName","herdrAgent","agentType","normalized","toLowerCase","candidates","claude","codex","copilot","gemini_cli","grok_cli","opencode","pi","other","Promise","all","map","extractPaneProcessIds","processInfo","foregroundProcesses","foreground_processes","foregroundProcess","positiveIntegerOrNull","shell_pid","path","current","part","trim","undefined","Number","isInteger"],"mappings":"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"}
|
|
@@ -5,6 +5,8 @@ export interface HerdrRuntimeOptions {
|
|
|
5
5
|
env?: NodeJS.ProcessEnv;
|
|
6
6
|
agentStartBusyRetryMs?: number;
|
|
7
7
|
agentStartBusyRetryIntervalMs?: number;
|
|
8
|
+
processInfoPollMs?: number;
|
|
9
|
+
processInfoPollIntervalMs?: number;
|
|
8
10
|
}
|
|
9
11
|
export declare class HerdrAgentRuntime implements InteractiveAgentRuntime {
|
|
10
12
|
readonly provider: "herdr";
|
|
@@ -12,6 +14,8 @@ export declare class HerdrAgentRuntime implements InteractiveAgentRuntime {
|
|
|
12
14
|
private readonly env;
|
|
13
15
|
private readonly agentStartBusyRetryMs;
|
|
14
16
|
private readonly agentStartBusyRetryIntervalMs;
|
|
17
|
+
private readonly processInfoPollMs;
|
|
18
|
+
private readonly processInfoPollIntervalMs;
|
|
15
19
|
constructor(options?: HerdrRuntimeOptions);
|
|
16
20
|
isAvailable(): Promise<AgentRuntimeAvailability>;
|
|
17
21
|
startAgent(input: RuntimeStartInput): Promise<RuntimeStartResult>;
|
|
@@ -27,5 +31,6 @@ export declare class HerdrAgentRuntime implements InteractiveAgentRuntime {
|
|
|
27
31
|
focus(input: RuntimeFocusInput): Promise<boolean>;
|
|
28
32
|
stop(input: RuntimeStopInput): Promise<void>;
|
|
29
33
|
private runAgentStartJson;
|
|
34
|
+
private readStartedAgentPid;
|
|
30
35
|
}
|
|
31
36
|
//# sourceMappingURL=HerdrAgentRuntime.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HerdrAgentRuntime.d.ts","sourceRoot":"","sources":["../../../src/runtime/herdr/HerdrAgentRuntime.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoC,KAAK,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"HerdrAgentRuntime.d.ts","sourceRoot":"","sources":["../../../src/runtime/herdr/HerdrAgentRuntime.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoC,KAAK,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAShG,OAAO,KAAK,EACV,wBAAwB,EACxB,uBAAuB,EACvB,iBAAiB,EACjB,gBAAgB,EAChB,iBAAiB,EACjB,kBAAkB,EAClB,gBAAgB,EACjB,MAAM,aAAa,CAAC;AAOrB,MAAM,WAAW,mBAAmB;IAClC,MAAM,CAAC,EAAE,kBAAkB,CAAC;IAC5B,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,6BAA6B,CAAC,EAAE,MAAM,CAAC;IACvC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,yBAAyB,CAAC,EAAE,MAAM,CAAC;CACpC;AAED,qBAAa,iBAAkB,YAAW,uBAAuB;IAC/D,QAAQ,CAAC,QAAQ,EAAG,OAAO,CAAU;IAErC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAiB;IACxC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAoB;IACxC,OAAO,CAAC,QAAQ,CAAC,qBAAqB,CAAS;IAC/C,OAAO,CAAC,QAAQ,CAAC,6BAA6B,CAAS;IACvD,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAS;IAC3C,OAAO,CAAC,QAAQ,CAAC,yBAAyB,CAAS;gBAEvC,OAAO,GAAE,mBAAwB;IAWvC,WAAW,IAAI,OAAO,CAAC,wBAAwB,CAAC;IAoChD,UAAU,CAAC,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAAC,kBAAkB,CAAC;IA6BjE,IAAI,CAAC,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IAK5C,IAAI,CAAC,KAAK,EAAE;QAAE,UAAU,EAAE,OAAO,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAetE,UAAU,CAAC,KAAK,EAAE;QAAE,UAAU,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,MAAM,CAAC;IAc3E,KAAK,CAAC,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAAC,OAAO,CAAC;IAMjD,IAAI,CAAC,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;YAKpC,iBAAiB;YAqBjB,mBAAmB;CAqBlC"}
|
|
@@ -1,20 +1,26 @@
|
|
|
1
1
|
import { HerdrCliClient, isCommandMissing } from "./HerdrCliClient.js";
|
|
2
2
|
import { HerdrRuntimeError } from "./HerdrErrors.js";
|
|
3
3
|
import { parseHerdrRuntimeRef } from "./HerdrRuntimeRef.js";
|
|
4
|
-
import { extractAgentRuntimeRef, extractProcessInfoPid, extractWorkspaceStart } from "./HerdrResponseParsers.js";
|
|
4
|
+
import { extractAgentRuntimeRef, extractForegroundProcessInfoPid, extractProcessInfoPid, extractWorkspaceStart } from "./HerdrResponseParsers.js";
|
|
5
5
|
const AGENT_START_BUSY_RETRY_MS = 5000;
|
|
6
6
|
const AGENT_START_BUSY_RETRY_INTERVAL_MS = 100;
|
|
7
|
+
const PROCESS_INFO_POLL_MS = 3000;
|
|
8
|
+
const PROCESS_INFO_POLL_INTERVAL_MS = 100;
|
|
7
9
|
export class HerdrAgentRuntime {
|
|
8
10
|
provider = "herdr";
|
|
9
11
|
client;
|
|
10
12
|
env;
|
|
11
13
|
agentStartBusyRetryMs;
|
|
12
14
|
agentStartBusyRetryIntervalMs;
|
|
15
|
+
processInfoPollMs;
|
|
16
|
+
processInfoPollIntervalMs;
|
|
13
17
|
constructor(options = {}){
|
|
14
18
|
this.client = new HerdrCliClient(options.runner);
|
|
15
19
|
this.env = options.env ?? process.env;
|
|
16
20
|
this.agentStartBusyRetryMs = options.agentStartBusyRetryMs ?? AGENT_START_BUSY_RETRY_MS;
|
|
17
21
|
this.agentStartBusyRetryIntervalMs = options.agentStartBusyRetryIntervalMs ?? AGENT_START_BUSY_RETRY_INTERVAL_MS;
|
|
22
|
+
this.processInfoPollMs = options.processInfoPollMs ?? PROCESS_INFO_POLL_MS;
|
|
23
|
+
this.processInfoPollIntervalMs = options.processInfoPollIntervalMs ?? PROCESS_INFO_POLL_INTERVAL_MS;
|
|
18
24
|
}
|
|
19
25
|
async isAvailable() {
|
|
20
26
|
try {
|
|
@@ -87,13 +93,7 @@ export class HerdrAgentRuntime {
|
|
|
87
93
|
paneId: workspace.paneId,
|
|
88
94
|
workspaceId: workspace.workspaceId
|
|
89
95
|
});
|
|
90
|
-
const
|
|
91
|
-
"pane",
|
|
92
|
-
"process-info",
|
|
93
|
-
"--pane",
|
|
94
|
-
runtimeRef.paneId
|
|
95
|
-
]);
|
|
96
|
-
const pid = extractProcessInfoPid(processInfoResponse);
|
|
96
|
+
const pid = await this.readStartedAgentPid(runtimeRef.paneId);
|
|
97
97
|
if (pid === null) {
|
|
98
98
|
throw new HerdrRuntimeError("Herdr pane process-info response did not include process pid.");
|
|
99
99
|
}
|
|
@@ -172,6 +172,24 @@ export class HerdrAgentRuntime {
|
|
|
172
172
|
code: "agent_pane_busy"
|
|
173
173
|
});
|
|
174
174
|
}
|
|
175
|
+
async readStartedAgentPid(paneId) {
|
|
176
|
+
const deadline = Date.now() + this.processInfoPollMs;
|
|
177
|
+
let fallbackPid = null;
|
|
178
|
+
do {
|
|
179
|
+
const processInfoResponse = await this.client.runJson([
|
|
180
|
+
"pane",
|
|
181
|
+
"process-info",
|
|
182
|
+
"--pane",
|
|
183
|
+
paneId
|
|
184
|
+
]);
|
|
185
|
+
const foregroundPid = extractForegroundProcessInfoPid(processInfoResponse);
|
|
186
|
+
if (foregroundPid !== null) return foregroundPid;
|
|
187
|
+
fallbackPid ??= extractProcessInfoPid(processInfoResponse);
|
|
188
|
+
if (Date.now() >= deadline) break;
|
|
189
|
+
await sleep(this.processInfoPollIntervalMs);
|
|
190
|
+
}while (Date.now() < deadline)
|
|
191
|
+
return fallbackPid;
|
|
192
|
+
}
|
|
175
193
|
}
|
|
176
194
|
function sleep(ms) {
|
|
177
195
|
if (ms <= 0) return Promise.resolve();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/runtime/herdr/HerdrAgentRuntime.ts"],"sourcesContent":["import { HerdrCliClient, isCommandMissing, type HerdrCommandRunner } from \"./HerdrCliClient.js\";\nimport { HerdrRuntimeError } from \"./HerdrErrors.js\";\nimport { parseHerdrRuntimeRef } from \"./HerdrRuntimeRef.js\";\nimport {\n extractAgentRuntimeRef,\n extractProcessInfoPid,\n extractWorkspaceStart,\n} from \"./HerdrResponseParsers.js\";\nimport type {\n AgentRuntimeAvailability,\n InteractiveAgentRuntime,\n RuntimeFocusInput,\n RuntimeSendInput,\n RuntimeStartInput,\n RuntimeStartResult,\n RuntimeStopInput,\n} from \"../types.js\";\n\nconst AGENT_START_BUSY_RETRY_MS = 5000;\nconst AGENT_START_BUSY_RETRY_INTERVAL_MS = 100;\n\nexport interface HerdrRuntimeOptions {\n runner?: HerdrCommandRunner;\n env?: NodeJS.ProcessEnv;\n agentStartBusyRetryMs?: number;\n agentStartBusyRetryIntervalMs?: number;\n}\n\nexport class HerdrAgentRuntime implements InteractiveAgentRuntime {\n readonly provider = \"herdr\" as const;\n\n private readonly client: HerdrCliClient;\n private readonly env: NodeJS.ProcessEnv;\n private readonly agentStartBusyRetryMs: number;\n private readonly agentStartBusyRetryIntervalMs: number;\n\n constructor(options: HerdrRuntimeOptions = {}) {\n this.client = new HerdrCliClient(options.runner);\n this.env = options.env ?? process.env;\n this.agentStartBusyRetryMs = options.agentStartBusyRetryMs ?? AGENT_START_BUSY_RETRY_MS;\n this.agentStartBusyRetryIntervalMs =\n options.agentStartBusyRetryIntervalMs ?? AGENT_START_BUSY_RETRY_INTERVAL_MS;\n }\n\n async isAvailable(): Promise<AgentRuntimeAvailability> {\n try {\n await this.client.run([\"--version\"]);\n } catch (error) {\n if (isCommandMissing(error)) {\n return {\n ok: false,\n reason: \"binary-missing\",\n detail: \"herdr command was not found in PATH.\",\n };\n }\n return {\n ok: false,\n reason: \"backend-unreachable\",\n detail: (error as Error).message,\n };\n }\n\n try {\n await this.client.run([\"api\", \"snapshot\"]);\n } catch (error) {\n return {\n ok: false,\n reason: \"backend-unreachable\",\n detail: (error as Error).message,\n };\n }\n\n const currentPaneId = nonEmptyString(this.env.HERDR_PANE_ID);\n return {\n ok: true,\n insideRuntime: this.env.HERDR_ENV === \"1\",\n ...(currentPaneId ? { currentPaneId } : {}),\n };\n }\n\n async startAgent(input: RuntimeStartInput): Promise<RuntimeStartResult> {\n const workspace = extractWorkspaceStart(\n await this.client.runJson([\"workspace\", \"create\", \"--cwd\", input.cwd, \"--label\", input.name]),\n );\n\n const agentResponse = await this.runAgentStartJson([\n \"agent\",\n \"start\",\n input.name,\n \"--kind\",\n input.kind,\n \"--pane\",\n workspace.paneId,\n ...(input.timeoutMs ? [\"--timeout\", String(input.timeoutMs)] : []),\n ...(input.args?.length ? [\"--\", ...input.args] : []),\n ]);\n const runtimeRef = extractAgentRuntimeRef(agentResponse, {\n name: input.name,\n paneId: workspace.paneId,\n workspaceId: workspace.workspaceId,\n });\n const processInfoResponse = await this.client.runJson([\n \"pane\",\n \"process-info\",\n \"--pane\",\n runtimeRef.paneId,\n ]);\n const pid = extractProcessInfoPid(processInfoResponse);\n if (pid === null) {\n throw new HerdrRuntimeError(\"Herdr pane process-info response did not include process pid.\");\n }\n\n return { pid, runtimeRef };\n }\n\n async send(input: RuntimeSendInput): Promise<void> {\n const ref = parseHerdrRuntimeRef(input.runtimeRef);\n await this.client.run([\"agent\", \"prompt\", ref.paneId, input.prompt]);\n }\n\n async wait(input: { runtimeRef: unknown; timeoutMs: number }): Promise<void> {\n const ref = parseHerdrRuntimeRef(input.runtimeRef);\n await this.client.run([\n \"agent\",\n \"wait\",\n ref.paneId,\n \"--until\",\n \"done\",\n \"--until\",\n \"blocked\",\n \"--timeout\",\n String(input.timeoutMs),\n ]);\n }\n\n async readOutput(input: { runtimeRef: unknown; lines?: number }): Promise<string> {\n const ref = parseHerdrRuntimeRef(input.runtimeRef);\n const { stdout } = await this.client.run([\n \"agent\",\n \"read\",\n ref.paneId,\n \"--source\",\n \"recent-unwrapped\",\n \"--lines\",\n String(input.lines ?? 120),\n ]);\n return stdout;\n }\n\n async focus(input: RuntimeFocusInput): Promise<boolean> {\n const ref = parseHerdrRuntimeRef(input.runtimeRef);\n await this.client.run([\"agent\", \"focus\", ref.paneId]);\n return true;\n }\n\n async stop(input: RuntimeStopInput): Promise<void> {\n const ref = parseHerdrRuntimeRef(input.runtimeRef);\n await this.client.run([\"pane\", \"close\", ref.paneId]);\n }\n\n private async runAgentStartJson(args: string[]): Promise<unknown> {\n const deadline = Date.now() + this.agentStartBusyRetryMs;\n let lastBusyError: HerdrRuntimeError | null = null;\n do {\n try {\n return await this.client.runJson(args);\n } catch (error) {\n if (!(error instanceof HerdrRuntimeError) || error.code !== \"agent_pane_busy\") throw error;\n lastBusyError = error;\n if (Date.now() >= deadline) break;\n await sleep(this.agentStartBusyRetryIntervalMs);\n }\n } while (Date.now() < deadline);\n throw (\n lastBusyError ??\n new HerdrRuntimeError(\"Herdr agent start failed because the target pane stayed busy.\", {\n code: \"agent_pane_busy\",\n })\n );\n }\n}\n\nfunction sleep(ms: number): Promise<void> {\n if (ms <= 0) return Promise.resolve();\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nfunction nonEmptyString(value: unknown): string | undefined {\n return typeof value === \"string\" && value.trim() ? value : undefined;\n}\n"],"names":["HerdrCliClient","isCommandMissing","HerdrRuntimeError","parseHerdrRuntimeRef","extractAgentRuntimeRef","extractProcessInfoPid","extractWorkspaceStart","AGENT_START_BUSY_RETRY_MS","AGENT_START_BUSY_RETRY_INTERVAL_MS","HerdrAgentRuntime","provider","client","env","agentStartBusyRetryMs","agentStartBusyRetryIntervalMs","options","runner","process","isAvailable","run","error","ok","reason","detail","message","currentPaneId","nonEmptyString","HERDR_PANE_ID","insideRuntime","HERDR_ENV","startAgent","input","workspace","runJson","cwd","name","agentResponse","runAgentStartJson","kind","paneId","timeoutMs","String","args","length","runtimeRef","workspaceId","processInfoResponse","pid","send","ref","prompt","wait","readOutput","stdout","lines","focus","stop","deadline","Date","now","lastBusyError","code","sleep","ms","Promise","resolve","setTimeout","value","trim","undefined"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../src/runtime/herdr/HerdrAgentRuntime.ts"],"sourcesContent":["import { HerdrCliClient, isCommandMissing, type HerdrCommandRunner } from \"./HerdrCliClient.js\";\nimport { HerdrRuntimeError } from \"./HerdrErrors.js\";\nimport { parseHerdrRuntimeRef } from \"./HerdrRuntimeRef.js\";\nimport {\n extractAgentRuntimeRef,\n extractForegroundProcessInfoPid,\n extractProcessInfoPid,\n extractWorkspaceStart,\n} from \"./HerdrResponseParsers.js\";\nimport type {\n AgentRuntimeAvailability,\n InteractiveAgentRuntime,\n RuntimeFocusInput,\n RuntimeSendInput,\n RuntimeStartInput,\n RuntimeStartResult,\n RuntimeStopInput,\n} from \"../types.js\";\n\nconst AGENT_START_BUSY_RETRY_MS = 5000;\nconst AGENT_START_BUSY_RETRY_INTERVAL_MS = 100;\nconst PROCESS_INFO_POLL_MS = 3000;\nconst PROCESS_INFO_POLL_INTERVAL_MS = 100;\n\nexport interface HerdrRuntimeOptions {\n runner?: HerdrCommandRunner;\n env?: NodeJS.ProcessEnv;\n agentStartBusyRetryMs?: number;\n agentStartBusyRetryIntervalMs?: number;\n processInfoPollMs?: number;\n processInfoPollIntervalMs?: number;\n}\n\nexport class HerdrAgentRuntime implements InteractiveAgentRuntime {\n readonly provider = \"herdr\" as const;\n\n private readonly client: HerdrCliClient;\n private readonly env: NodeJS.ProcessEnv;\n private readonly agentStartBusyRetryMs: number;\n private readonly agentStartBusyRetryIntervalMs: number;\n private readonly processInfoPollMs: number;\n private readonly processInfoPollIntervalMs: number;\n\n constructor(options: HerdrRuntimeOptions = {}) {\n this.client = new HerdrCliClient(options.runner);\n this.env = options.env ?? process.env;\n this.agentStartBusyRetryMs = options.agentStartBusyRetryMs ?? AGENT_START_BUSY_RETRY_MS;\n this.agentStartBusyRetryIntervalMs =\n options.agentStartBusyRetryIntervalMs ?? AGENT_START_BUSY_RETRY_INTERVAL_MS;\n this.processInfoPollMs = options.processInfoPollMs ?? PROCESS_INFO_POLL_MS;\n this.processInfoPollIntervalMs =\n options.processInfoPollIntervalMs ?? PROCESS_INFO_POLL_INTERVAL_MS;\n }\n\n async isAvailable(): Promise<AgentRuntimeAvailability> {\n try {\n await this.client.run([\"--version\"]);\n } catch (error) {\n if (isCommandMissing(error)) {\n return {\n ok: false,\n reason: \"binary-missing\",\n detail: \"herdr command was not found in PATH.\",\n };\n }\n return {\n ok: false,\n reason: \"backend-unreachable\",\n detail: (error as Error).message,\n };\n }\n\n try {\n await this.client.run([\"api\", \"snapshot\"]);\n } catch (error) {\n return {\n ok: false,\n reason: \"backend-unreachable\",\n detail: (error as Error).message,\n };\n }\n\n const currentPaneId = nonEmptyString(this.env.HERDR_PANE_ID);\n return {\n ok: true,\n insideRuntime: this.env.HERDR_ENV === \"1\",\n ...(currentPaneId ? { currentPaneId } : {}),\n };\n }\n\n async startAgent(input: RuntimeStartInput): Promise<RuntimeStartResult> {\n const workspace = extractWorkspaceStart(\n await this.client.runJson([\"workspace\", \"create\", \"--cwd\", input.cwd, \"--label\", input.name]),\n );\n\n const agentResponse = await this.runAgentStartJson([\n \"agent\",\n \"start\",\n input.name,\n \"--kind\",\n input.kind,\n \"--pane\",\n workspace.paneId,\n ...(input.timeoutMs ? [\"--timeout\", String(input.timeoutMs)] : []),\n ...(input.args?.length ? [\"--\", ...input.args] : []),\n ]);\n const runtimeRef = extractAgentRuntimeRef(agentResponse, {\n name: input.name,\n paneId: workspace.paneId,\n workspaceId: workspace.workspaceId,\n });\n const pid = await this.readStartedAgentPid(runtimeRef.paneId);\n if (pid === null) {\n throw new HerdrRuntimeError(\"Herdr pane process-info response did not include process pid.\");\n }\n\n return { pid, runtimeRef };\n }\n\n async send(input: RuntimeSendInput): Promise<void> {\n const ref = parseHerdrRuntimeRef(input.runtimeRef);\n await this.client.run([\"agent\", \"prompt\", ref.paneId, input.prompt]);\n }\n\n async wait(input: { runtimeRef: unknown; timeoutMs: number }): Promise<void> {\n const ref = parseHerdrRuntimeRef(input.runtimeRef);\n await this.client.run([\n \"agent\",\n \"wait\",\n ref.paneId,\n \"--until\",\n \"done\",\n \"--until\",\n \"blocked\",\n \"--timeout\",\n String(input.timeoutMs),\n ]);\n }\n\n async readOutput(input: { runtimeRef: unknown; lines?: number }): Promise<string> {\n const ref = parseHerdrRuntimeRef(input.runtimeRef);\n const { stdout } = await this.client.run([\n \"agent\",\n \"read\",\n ref.paneId,\n \"--source\",\n \"recent-unwrapped\",\n \"--lines\",\n String(input.lines ?? 120),\n ]);\n return stdout;\n }\n\n async focus(input: RuntimeFocusInput): Promise<boolean> {\n const ref = parseHerdrRuntimeRef(input.runtimeRef);\n await this.client.run([\"agent\", \"focus\", ref.paneId]);\n return true;\n }\n\n async stop(input: RuntimeStopInput): Promise<void> {\n const ref = parseHerdrRuntimeRef(input.runtimeRef);\n await this.client.run([\"pane\", \"close\", ref.paneId]);\n }\n\n private async runAgentStartJson(args: string[]): Promise<unknown> {\n const deadline = Date.now() + this.agentStartBusyRetryMs;\n let lastBusyError: HerdrRuntimeError | null = null;\n do {\n try {\n return await this.client.runJson(args);\n } catch (error) {\n if (!(error instanceof HerdrRuntimeError) || error.code !== \"agent_pane_busy\") throw error;\n lastBusyError = error;\n if (Date.now() >= deadline) break;\n await sleep(this.agentStartBusyRetryIntervalMs);\n }\n } while (Date.now() < deadline);\n throw (\n lastBusyError ??\n new HerdrRuntimeError(\"Herdr agent start failed because the target pane stayed busy.\", {\n code: \"agent_pane_busy\",\n })\n );\n }\n\n private async readStartedAgentPid(paneId: string): Promise<number | null> {\n const deadline = Date.now() + this.processInfoPollMs;\n let fallbackPid: number | null = null;\n\n do {\n const processInfoResponse = await this.client.runJson([\n \"pane\",\n \"process-info\",\n \"--pane\",\n paneId,\n ]);\n const foregroundPid = extractForegroundProcessInfoPid(processInfoResponse);\n if (foregroundPid !== null) return foregroundPid;\n fallbackPid ??= extractProcessInfoPid(processInfoResponse);\n\n if (Date.now() >= deadline) break;\n await sleep(this.processInfoPollIntervalMs);\n } while (Date.now() < deadline);\n\n return fallbackPid;\n }\n}\n\nfunction sleep(ms: number): Promise<void> {\n if (ms <= 0) return Promise.resolve();\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nfunction nonEmptyString(value: unknown): string | undefined {\n return typeof value === \"string\" && value.trim() ? value : undefined;\n}\n"],"names":["HerdrCliClient","isCommandMissing","HerdrRuntimeError","parseHerdrRuntimeRef","extractAgentRuntimeRef","extractForegroundProcessInfoPid","extractProcessInfoPid","extractWorkspaceStart","AGENT_START_BUSY_RETRY_MS","AGENT_START_BUSY_RETRY_INTERVAL_MS","PROCESS_INFO_POLL_MS","PROCESS_INFO_POLL_INTERVAL_MS","HerdrAgentRuntime","provider","client","env","agentStartBusyRetryMs","agentStartBusyRetryIntervalMs","processInfoPollMs","processInfoPollIntervalMs","options","runner","process","isAvailable","run","error","ok","reason","detail","message","currentPaneId","nonEmptyString","HERDR_PANE_ID","insideRuntime","HERDR_ENV","startAgent","input","workspace","runJson","cwd","name","agentResponse","runAgentStartJson","kind","paneId","timeoutMs","String","args","length","runtimeRef","workspaceId","pid","readStartedAgentPid","send","ref","prompt","wait","readOutput","stdout","lines","focus","stop","deadline","Date","now","lastBusyError","code","sleep","fallbackPid","processInfoResponse","foregroundPid","ms","Promise","resolve","setTimeout","value","trim","undefined"],"mappings":"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"}
|
|
@@ -10,5 +10,7 @@ export declare function extractAgentRuntimeRef(value: unknown, fallback: {
|
|
|
10
10
|
workspaceId?: string;
|
|
11
11
|
}): HerdrRuntimeRef;
|
|
12
12
|
export declare function extractProcessInfoPid(value: unknown): number | null;
|
|
13
|
+
export declare function extractForegroundProcessInfoPid(value: unknown): number | null;
|
|
14
|
+
export declare function extractShellPid(value: unknown): number | null;
|
|
13
15
|
export declare function herdrErrorFromResponse(value: unknown): HerdrRuntimeError | null;
|
|
14
16
|
//# sourceMappingURL=HerdrResponseParsers.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HerdrResponseParsers.d.ts","sourceRoot":"","sources":["../../../src/runtime/herdr/HerdrResponseParsers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAE5D,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG;IAAE,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAU9F;AAED,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,OAAO,EACd,QAAQ,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,GAC/D,eAAe,CAWjB;AAED,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,
|
|
1
|
+
{"version":3,"file":"HerdrResponseParsers.d.ts","sourceRoot":"","sources":["../../../src/runtime/herdr/HerdrResponseParsers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAE5D,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG;IAAE,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAU9F;AAED,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,OAAO,EACd,QAAQ,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,GAC/D,eAAe,CAWjB;AAED,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAEnE;AAED,wBAAgB,+BAA+B,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAW7E;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAI7D;AAED,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,OAAO,GAAG,iBAAiB,GAAG,IAAI,CAM/E"}
|
|
@@ -49,18 +49,29 @@ export function extractAgentRuntimeRef(value, fallback) {
|
|
|
49
49
|
};
|
|
50
50
|
}
|
|
51
51
|
export function extractProcessInfoPid(value) {
|
|
52
|
+
return extractForegroundProcessInfoPid(value) ?? extractShellPid(value);
|
|
53
|
+
}
|
|
54
|
+
export function extractForegroundProcessInfoPid(value) {
|
|
52
55
|
const processInfo = getObject(value, [
|
|
53
56
|
"result",
|
|
54
57
|
"process_info"
|
|
55
58
|
]);
|
|
56
59
|
if (!processInfo) return null;
|
|
57
60
|
const processes = processInfo.foreground_processes;
|
|
58
|
-
if (!Array.isArray(processes)) return
|
|
61
|
+
if (!Array.isArray(processes)) return null;
|
|
59
62
|
for (const processInfo of processes){
|
|
60
63
|
if (!processInfo || typeof processInfo !== "object") continue;
|
|
61
64
|
const pid = numberOrNull(processInfo.pid);
|
|
62
65
|
if (pid !== null) return pid;
|
|
63
66
|
}
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
export function extractShellPid(value) {
|
|
70
|
+
const processInfo = getObject(value, [
|
|
71
|
+
"result",
|
|
72
|
+
"process_info"
|
|
73
|
+
]);
|
|
74
|
+
if (!processInfo) return null;
|
|
64
75
|
return numberOrNull(processInfo.shell_pid);
|
|
65
76
|
}
|
|
66
77
|
export function herdrErrorFromResponse(value) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/runtime/herdr/HerdrResponseParsers.ts"],"sourcesContent":["import { HerdrRuntimeError } from \"./HerdrErrors.js\";\nimport type { HerdrRuntimeRef } from \"./HerdrRuntimeRef.js\";\n\nexport function extractWorkspaceStart(value: unknown): { workspaceId?: string; paneId: string } {\n const workspaceId = getString(value, [\"result\", \"workspace\", \"workspace_id\"]);\n const paneId = getString(value, [\"result\", \"root_pane\", \"pane_id\"]);\n if (!paneId) {\n throw new HerdrRuntimeError(\"Herdr workspace create response did not include root pane id.\");\n }\n return {\n ...(workspaceId ? { workspaceId } : {}),\n paneId,\n };\n}\n\nexport function extractAgentRuntimeRef(\n value: unknown,\n fallback: { paneId: string; name: string; workspaceId?: string },\n): HerdrRuntimeRef {\n const agentPaneId = getString(value, [\"result\", \"agent\", \"pane_id\"]) ?? fallback.paneId;\n const agentName = getString(value, [\"result\", \"agent\", \"name\"]) ?? fallback.name;\n const tabId = getString(value, [\"result\", \"agent\", \"tab_id\"]);\n return {\n session: \"default\",\n ...(fallback.workspaceId ? { workspaceId: fallback.workspaceId } : {}),\n ...(tabId ? { tabId } : {}),\n paneId: agentPaneId,\n agentName,\n };\n}\n\nexport function extractProcessInfoPid(value: unknown): number | null {\n const processInfo = getObject(value, [\"result\", \"process_info\"]);\n if (!processInfo) return null;\n const processes = processInfo.foreground_processes;\n if (!Array.isArray(processes)) return
|
|
1
|
+
{"version":3,"sources":["../../../src/runtime/herdr/HerdrResponseParsers.ts"],"sourcesContent":["import { HerdrRuntimeError } from \"./HerdrErrors.js\";\nimport type { HerdrRuntimeRef } from \"./HerdrRuntimeRef.js\";\n\nexport function extractWorkspaceStart(value: unknown): { workspaceId?: string; paneId: string } {\n const workspaceId = getString(value, [\"result\", \"workspace\", \"workspace_id\"]);\n const paneId = getString(value, [\"result\", \"root_pane\", \"pane_id\"]);\n if (!paneId) {\n throw new HerdrRuntimeError(\"Herdr workspace create response did not include root pane id.\");\n }\n return {\n ...(workspaceId ? { workspaceId } : {}),\n paneId,\n };\n}\n\nexport function extractAgentRuntimeRef(\n value: unknown,\n fallback: { paneId: string; name: string; workspaceId?: string },\n): HerdrRuntimeRef {\n const agentPaneId = getString(value, [\"result\", \"agent\", \"pane_id\"]) ?? fallback.paneId;\n const agentName = getString(value, [\"result\", \"agent\", \"name\"]) ?? fallback.name;\n const tabId = getString(value, [\"result\", \"agent\", \"tab_id\"]);\n return {\n session: \"default\",\n ...(fallback.workspaceId ? { workspaceId: fallback.workspaceId } : {}),\n ...(tabId ? { tabId } : {}),\n paneId: agentPaneId,\n agentName,\n };\n}\n\nexport function extractProcessInfoPid(value: unknown): number | null {\n return extractForegroundProcessInfoPid(value) ?? extractShellPid(value);\n}\n\nexport function extractForegroundProcessInfoPid(value: unknown): number | null {\n const processInfo = getObject(value, [\"result\", \"process_info\"]);\n if (!processInfo) return null;\n const processes = processInfo.foreground_processes;\n if (!Array.isArray(processes)) return null;\n for (const processInfo of processes) {\n if (!processInfo || typeof processInfo !== \"object\") continue;\n const pid = numberOrNull((processInfo as { pid?: unknown }).pid);\n if (pid !== null) return pid;\n }\n return null;\n}\n\nexport function extractShellPid(value: unknown): number | null {\n const processInfo = getObject(value, [\"result\", \"process_info\"]);\n if (!processInfo) return null;\n return numberOrNull(processInfo.shell_pid);\n}\n\nexport function herdrErrorFromResponse(value: unknown): HerdrRuntimeError | null {\n const error = getObject(value, [\"error\"]);\n if (!error) return null;\n const message = nonEmptyString(error.message) ?? \"Herdr command failed.\";\n const code = nonEmptyString(error.code);\n return new HerdrRuntimeError(message, code ? { code } : {});\n}\n\nfunction getObject(value: unknown, path: string[]): Record<string, unknown> | null {\n let current = value;\n for (const part of path) {\n if (!current || typeof current !== \"object\" || Array.isArray(current) || !(part in current))\n return null;\n current = (current as Record<string, unknown>)[part];\n }\n return current && typeof current === \"object\" && !Array.isArray(current)\n ? (current as Record<string, unknown>)\n : null;\n}\n\nfunction getString(value: unknown, path: string[]): string | undefined {\n const parent = getObject(value, path.slice(0, -1));\n return parent ? nonEmptyString(parent[path[path.length - 1]!]) : undefined;\n}\n\nfunction nonEmptyString(value: unknown): string | undefined {\n return typeof value === \"string\" && value.trim() ? value : undefined;\n}\n\nfunction numberOrNull(value: unknown): number | null {\n return typeof value === \"number\" && Number.isInteger(value) && value > 0 ? value : null;\n}\n"],"names":["HerdrRuntimeError","extractWorkspaceStart","value","workspaceId","getString","paneId","extractAgentRuntimeRef","fallback","agentPaneId","agentName","name","tabId","session","extractProcessInfoPid","extractForegroundProcessInfoPid","extractShellPid","processInfo","getObject","processes","foreground_processes","Array","isArray","pid","numberOrNull","shell_pid","herdrErrorFromResponse","error","message","nonEmptyString","code","path","current","part","parent","slice","length","undefined","trim","Number","isInteger"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AgentRegistry.d.ts","sourceRoot":"","sources":["../../src/utils/AgentRegistry.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AAE7D,OAAO,EAAE,mBAAmB,EAAE,KAAK,cAAc,EAAE,MAAM,mCAAmC,CAAC;AAE7F,qBAAa,mBAAoB,SAAQ,KAAK;IACzB,SAAS,EAAE,MAAM;gBAAjB,SAAS,EAAE,MAAM;CAIrC;AAED,qBAAa,mBAAoB,SAAQ,KAAK;IACzB,SAAS,EAAE,MAAM;gBAAjB,SAAS,EAAE,MAAM;CAIrC;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,SAAS,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,oBAAoB,CAAC;IAC9B,UAAU,EAAE,OAAO,GAAG,IAAI,CAAC;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,MAAM,CAAC;IACxB,MAAM,EAAE,OAAO,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAiBD,eAAO,MAAM,uBAAuB,4BAA6B,CAAC;AAClE,MAAM,MAAM,oBAAoB,GAAG,CAAC,OAAO,uBAAuB,CAAC,CAAC,MAAM,CAAC,CAAC;AAO5E,MAAM,WAAW,oBAAoB;IACnC,GAAG,CAAC,EAAE,MAAM,IAAI,CAAC;IACjB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,mBAAmB,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5C,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,qBAAa,aAAa;IACxB,OAAO,CAAC,EAAE,CAAqB;IAC/B,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAa;IACjC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAS;IACzC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAU;IACnC,OAAO,CAAC,YAAY,CAAqB;gBAE7B,QAAQ,GAAE,MAA8B,EAAE,OAAO,GAAE,oBAAyB;IAWxF,MAAM,CAAC,OAAO,IAAI,aAAa;IAO/B,OAAO,CAAC,UAAU;IAiBlB,OAAO,CAAC,YAAY;IAIpB,OAAO,CAAC,eAAe;IAoBvB,OAAO,CAAC,UAAU;
|
|
1
|
+
{"version":3,"file":"AgentRegistry.d.ts","sourceRoot":"","sources":["../../src/utils/AgentRegistry.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AAE7D,OAAO,EAAE,mBAAmB,EAAE,KAAK,cAAc,EAAE,MAAM,mCAAmC,CAAC;AAE7F,qBAAa,mBAAoB,SAAQ,KAAK;IACzB,SAAS,EAAE,MAAM;gBAAjB,SAAS,EAAE,MAAM;CAIrC;AAED,qBAAa,mBAAoB,SAAQ,KAAK;IACzB,SAAS,EAAE,MAAM;gBAAjB,SAAS,EAAE,MAAM;CAIrC;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,SAAS,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,oBAAoB,CAAC;IAC9B,UAAU,EAAE,OAAO,GAAG,IAAI,CAAC;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,MAAM,CAAC;IACxB,MAAM,EAAE,OAAO,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAiBD,eAAO,MAAM,uBAAuB,4BAA6B,CAAC;AAClE,MAAM,MAAM,oBAAoB,GAAG,CAAC,OAAO,uBAAuB,CAAC,CAAC,MAAM,CAAC,CAAC;AAO5E,MAAM,WAAW,oBAAoB;IACnC,GAAG,CAAC,EAAE,MAAM,IAAI,CAAC;IACjB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,mBAAmB,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5C,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,qBAAa,aAAa;IACxB,OAAO,CAAC,EAAE,CAAqB;IAC/B,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAa;IACjC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAS;IACzC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAU;IACnC,OAAO,CAAC,YAAY,CAAqB;gBAE7B,QAAQ,GAAE,MAA8B,EAAE,OAAO,GAAE,oBAAyB;IAWxF,MAAM,CAAC,OAAO,IAAI,aAAa;IAO/B,OAAO,CAAC,UAAU;IAiBlB,OAAO,CAAC,YAAY;IAIpB,OAAO,CAAC,eAAe;IAoBvB,OAAO,CAAC,UAAU;IAkBlB,OAAO,CAAC,cAAc;IAQtB,OAAO,CAAC,UAAU;IAKlB,OAAO,CAAC,gBAAgB;IAMxB,OAAO,CAAC,YAAY;IAcpB,OAAO,CAAC,kBAAkB;IAY1B,OAAO,CAAC,cAAc;IA8BtB,OAAO,CAAC,UAAU;IAUlB,OAAO,CAAC,IAAI;IAkBZ,OAAO,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO;IAUtC,OAAO,CAAC,OAAO;IAaf,KAAK,IAAI,IAAI;IAIb,UAAU,IAAI,IAAI;IAOlB,QAAQ,CAAC,KAAK,EAAE,aAAa,GAAG,IAAI;IAIpC,aAAa,CAAC,OAAO,EAAE,aAAa,EAAE,GAAG,IAAI;IAU7C,MAAM,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI;IA0BlD,SAAS,CAAC,IAAI,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI;IAYvD,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI;IAI1C,IAAI,IAAI,aAAa,EAAE;CAMxB;AAED,OAAO,EAAE,mBAAmB,EAAE,CAAC;AAC/B,YAAY,EAAE,cAAc,EAAE,CAAC"}
|
|
@@ -81,13 +81,13 @@ export class AgentRegistry {
|
|
|
81
81
|
}
|
|
82
82
|
mergeEntry(incoming, existing) {
|
|
83
83
|
if (!existing) return incoming;
|
|
84
|
-
const
|
|
84
|
+
const keepExistingRuntime = existing.runtime === "herdr" || Boolean(parseTmuxRuntimeRef(existing.runtimeRef)) || incoming.runtime !== "herdr";
|
|
85
85
|
return {
|
|
86
86
|
...existing,
|
|
87
|
-
name:
|
|
88
|
-
runtime:
|
|
89
|
-
runtimeRef:
|
|
90
|
-
cwd:
|
|
87
|
+
name: existing.name,
|
|
88
|
+
runtime: keepExistingRuntime ? existing.runtime : incoming.runtime,
|
|
89
|
+
runtimeRef: keepExistingRuntime ? existing.runtimeRef : incoming.runtimeRef,
|
|
90
|
+
cwd: existing.cwd || incoming.cwd,
|
|
91
91
|
startedAt: existing.startedAt || incoming.startedAt,
|
|
92
92
|
sessionId: incoming.sessionId || existing.sessionId,
|
|
93
93
|
sessionFilePath: incoming.sessionFilePath || existing.sessionFilePath
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/utils/AgentRegistry.ts"],"sourcesContent":["import os from \"os\";\nimport path from \"path\";\nimport type { AgentType } from \"../adapters/AgentAdapter.js\";\nimport { DatabaseConnection, resolveAgentRegistryDbPath } from \"../database/index.js\";\nimport { parseTmuxRuntimeRef, type TmuxRuntimeRef } from \"../runtime/tmux/TmuxRuntimeRef.js\";\n\nexport class RenameNotFoundError extends Error {\n constructor(public agentName: string) {\n super(`Agent \"${agentName}\" not found in registry.`);\n this.name = \"RenameNotFoundError\";\n }\n}\n\nexport class RenameConflictError extends Error {\n constructor(public agentName: string) {\n super(`Agent \"${agentName}\" is already in use.`);\n this.name = \"RenameConflictError\";\n }\n}\n\nexport interface RegistryEntry {\n name: string;\n type: AgentType;\n pid: number;\n runtime: AgentRuntimeProvider;\n runtimeRef: unknown | null;\n cwd: string;\n startedAt: string; // ISO 8601\n sessionId: string;\n sessionFilePath: string;\n pinned: boolean;\n updatedAt?: string;\n}\n\ninterface RegistryRow {\n name: string;\n type: AgentType;\n pid: number;\n tmux_session: string;\n runtime?: string;\n runtime_ref?: string;\n cwd: string;\n started_at: string;\n session_id: string;\n session_file_path: string;\n updated_at: string;\n pinned: number;\n}\n\nexport const AGENT_RUNTIME_PROVIDERS = [\"tmux\", \"herdr\"] as const;\nexport type AgentRuntimeProvider = (typeof AGENT_RUNTIME_PROVIDERS)[number];\n\nconst DEFAULT_REGISTRY_PATH = path.join(os.homedir(), \".ai-devkit\", \"agents.json\");\nconst DEFAULT_PRUNE_INTERVAL_MS = 30_000;\n\nlet defaultInstance: AgentRegistry | null = null;\n\nexport interface AgentRegistryOptions {\n now?: () => Date;\n pruneIntervalMs?: number;\n onDatabaseOperation?: (sql: string) => void;\n readonly?: boolean;\n}\n\nexport class AgentRegistry {\n private db: DatabaseConnection;\n private readonly now: () => Date;\n private readonly pruneIntervalMs: number;\n private readonly readonly: boolean;\n private lastPrunedAt: number | undefined;\n\n constructor(filePath: string = DEFAULT_REGISTRY_PATH, options: AgentRegistryOptions = {}) {\n this.now = options.now ?? (() => new Date());\n this.pruneIntervalMs = options.pruneIntervalMs ?? DEFAULT_PRUNE_INTERVAL_MS;\n this.readonly = options.readonly ?? false;\n this.db = new DatabaseConnection({\n dbPath: resolveAgentRegistryDbPath(filePath),\n verbose: options.onDatabaseOperation,\n readonly: this.readonly,\n });\n }\n\n static default(): AgentRegistry {\n if (!defaultInstance) {\n defaultInstance = new AgentRegistry();\n }\n return defaultInstance;\n }\n\n private rowToEntry(row: RegistryRow): RegistryEntry {\n const runtime = this.parseRuntime(row.runtime);\n return {\n name: row.name,\n type: row.type,\n pid: row.pid,\n runtime,\n runtimeRef: this.parseRuntimeRef(runtime, row.runtime_ref, row.tmux_session),\n cwd: row.cwd,\n startedAt: row.started_at,\n sessionId: row.session_id,\n sessionFilePath: row.session_file_path,\n pinned: row.pinned !== 0,\n updatedAt: row.updated_at,\n };\n }\n\n private parseRuntime(value: string | undefined): AgentRuntimeProvider {\n return value === \"herdr\" ? \"herdr\" : \"tmux\";\n }\n\n private parseRuntimeRef(\n runtime: AgentRuntimeProvider,\n raw: string | undefined,\n legacyTmuxSession: string,\n ): unknown | null {\n if (raw) {\n try {\n return JSON.parse(raw) as unknown;\n } catch {\n return null;\n }\n }\n\n if (runtime === \"tmux\" && legacyTmuxSession) {\n return { session: legacyTmuxSession };\n }\n\n return null;\n }\n\n private mergeEntry(incoming: RegistryEntry, existing: RegistryEntry | undefined): RegistryEntry {\n if (!existing) return incoming;\n const incomingIsManaged =\n incoming.runtime === \"herdr\" || Boolean(parseTmuxRuntimeRef(incoming.runtimeRef));\n return {\n ...existing,\n name: incomingIsManaged ? incoming.name : existing.name,\n runtime: incoming.runtime ?? existing.runtime,\n runtimeRef: incoming.runtimeRef ?? existing.runtimeRef,\n cwd: incoming.cwd || existing.cwd,\n startedAt: existing.startedAt || incoming.startedAt,\n sessionId: incoming.sessionId || existing.sessionId,\n sessionFilePath: incoming.sessionFilePath || existing.sessionFilePath,\n };\n }\n\n private findByIdentity(type: AgentType, pid: number): RegistryEntry | undefined {\n const row = this.db.queryOne<RegistryRow>(\"SELECT * FROM agents WHERE type = ? AND pid = ?\", [\n type,\n pid,\n ]);\n return row ? this.rowToEntry(row) : undefined;\n }\n\n private findByName(name: string): RegistryEntry | undefined {\n const row = this.db.queryOne<RegistryRow>(\"SELECT * FROM agents WHERE name = ?\", [name]);\n return row ? this.rowToEntry(row) : undefined;\n }\n\n private findPidConflicts(type: AgentType, pid: number): RegistryEntry[] {\n return this.db\n .query<RegistryRow>(\"SELECT * FROM agents WHERE pid = ? AND type <> ?\", [pid, type])\n .map((row) => this.rowToEntry(row));\n }\n\n private entriesEqual(left: RegistryEntry, right: RegistryEntry): boolean {\n return (\n left.name === right.name &&\n left.type === right.type &&\n left.pid === right.pid &&\n left.runtime === right.runtime &&\n JSON.stringify(left.runtimeRef ?? null) === JSON.stringify(right.runtimeRef ?? null) &&\n left.cwd === right.cwd &&\n left.startedAt === right.startedAt &&\n left.sessionId === right.sessionId &&\n left.sessionFilePath === right.sessionFilePath\n );\n }\n\n private deleteNameConflict(name: string, type: AgentType, pid: number): void {\n const conflict = this.findByName(name);\n if (!conflict) return;\n if (conflict.type === type && conflict.pid === pid) return;\n if (!this.isAlive(conflict)) {\n this.db.execute(\"DELETE FROM agents WHERE type = ? AND pid = ?\", [\n conflict.type,\n conflict.pid,\n ]);\n }\n }\n\n private insertOrUpdate(entry: RegistryEntry): void {\n this.db.instance\n .prepare(`\n INSERT INTO agents (\n type, pid, name, tmux_session, cwd, started_at, session_id, session_file_path, updated_at\n , runtime, runtime_ref\n )\n VALUES (\n @type, @pid, @name, @legacyTmuxSession, @cwd, @startedAt, @sessionId, @sessionFilePath, @updatedAt\n , @runtime, @runtimeRefJson\n )\n ON CONFLICT(type, pid) DO UPDATE SET\n name = excluded.name,\n tmux_session = excluded.tmux_session,\n runtime = excluded.runtime,\n runtime_ref = excluded.runtime_ref,\n cwd = excluded.cwd,\n started_at = agents.started_at,\n session_id = excluded.session_id,\n session_file_path = excluded.session_file_path,\n updated_at = excluded.updated_at\n `)\n .run({\n ...entry,\n legacyTmuxSession: parseTmuxRuntimeRef(entry.runtimeRef)?.session ?? \"\",\n runtimeRefJson: JSON.stringify(entry.runtimeRef ?? null),\n updatedAt: this.now().toISOString(),\n });\n }\n\n private needsWrite(incoming: RegistryEntry): boolean {\n const existing = this.findByIdentity(incoming.type, incoming.pid);\n const merged = this.mergeEntry(incoming, existing);\n return (\n !existing ||\n !this.entriesEqual(merged, existing) ||\n this.findPidConflicts(incoming.type, incoming.pid).length > 0\n );\n }\n\n private save(incoming: RegistryEntry): void {\n const existing = this.findByIdentity(incoming.type, incoming.pid);\n const merged = this.mergeEntry(incoming, existing);\n const pidConflicts = this.findPidConflicts(incoming.type, incoming.pid);\n if (existing && this.entriesEqual(merged, existing) && pidConflicts.length === 0) return;\n\n for (const conflict of pidConflicts) {\n this.db.execute(\"DELETE FROM agents WHERE type = ? AND pid = ?\", [\n conflict.type,\n conflict.pid,\n ]);\n }\n if (existing && this.entriesEqual(merged, existing)) return;\n\n this.deleteNameConflict(merged.name, merged.type, merged.pid);\n this.insertOrUpdate(merged);\n }\n\n isAlive(entry: RegistryEntry): boolean {\n try {\n process.kill(entry.pid, 0);\n return true;\n } catch (error) {\n const code = error && typeof error === \"object\" && \"code\" in error ? error.code : undefined;\n return code !== \"ESRCH\";\n }\n }\n\n private pruneAt(nowMs: number): void {\n const entries = this.list();\n const stale = entries.filter((e) => !this.isAlive(e));\n if (stale.length > 0) {\n this.db.transaction(() => {\n for (const entry of stale) {\n this.db.execute(\"DELETE FROM agents WHERE type = ? AND pid = ?\", [entry.type, entry.pid]);\n }\n });\n }\n this.lastPrunedAt = nowMs;\n }\n\n prune(): void {\n this.pruneAt(this.now().getTime());\n }\n\n pruneIfDue(): void {\n const nowMs = this.now().getTime();\n const elapsed = this.lastPrunedAt === undefined ? undefined : nowMs - this.lastPrunedAt;\n if (elapsed !== undefined && elapsed >= 0 && elapsed < this.pruneIntervalMs) return;\n this.pruneAt(nowMs);\n }\n\n register(entry: RegistryEntry): void {\n this.registerBatch([entry]);\n }\n\n registerBatch(entries: RegistryEntry[]): void {\n if (entries.length === 0) return;\n if (!entries.some((entry) => this.needsWrite(entry))) return;\n this.db.transaction(() => {\n for (const incoming of entries) {\n this.save(incoming);\n }\n });\n }\n\n rename(currentName: string, newName: string): void {\n const existing = this.findByName(currentName);\n if (!existing) {\n throw new RenameNotFoundError(currentName);\n }\n const conflict = this.findByName(newName);\n if (conflict && this.isAlive(conflict)) {\n throw new RenameConflictError(newName);\n }\n\n this.db.transaction(() => {\n if (conflict) {\n this.db.execute(\"DELETE FROM agents WHERE type = ? AND pid = ?\", [\n conflict.type,\n conflict.pid,\n ]);\n }\n this.db.execute(\"UPDATE agents SET name = ?, updated_at = ? WHERE type = ? AND pid = ?\", [\n newName,\n this.now().toISOString(),\n existing.type,\n existing.pid,\n ]);\n });\n }\n\n togglePin(type: AgentType, pid: number): boolean | null {\n if (this.readonly) {\n throw new Error(\"Agent registry is readonly; cannot toggle pin.\");\n }\n const result = this.db.execute(\n \"UPDATE agents SET pinned = NOT pinned, updated_at = ? WHERE type = ? AND pid = ?\",\n [this.now().toISOString(), type, pid],\n );\n if (result.changes === 0) return null;\n return this.findByIdentity(type, pid)?.pinned ?? null;\n }\n\n lookup(name: string): RegistryEntry | null {\n return this.findByName(name) ?? null;\n }\n\n list(): RegistryEntry[] {\n const rows = this.db.query<RegistryRow>(\n \"SELECT * FROM agents ORDER BY started_at ASC, name ASC\",\n );\n return rows.map((row) => this.rowToEntry(row));\n }\n}\n\nexport { parseTmuxRuntimeRef };\nexport type { TmuxRuntimeRef };\n"],"names":["os","path","DatabaseConnection","resolveAgentRegistryDbPath","parseTmuxRuntimeRef","RenameNotFoundError","Error","agentName","name","RenameConflictError","AGENT_RUNTIME_PROVIDERS","DEFAULT_REGISTRY_PATH","join","homedir","DEFAULT_PRUNE_INTERVAL_MS","defaultInstance","AgentRegistry","db","now","pruneIntervalMs","readonly","lastPrunedAt","filePath","options","Date","dbPath","verbose","onDatabaseOperation","default","rowToEntry","row","runtime","parseRuntime","type","pid","runtimeRef","parseRuntimeRef","runtime_ref","tmux_session","cwd","startedAt","started_at","sessionId","session_id","sessionFilePath","session_file_path","pinned","updatedAt","updated_at","value","raw","legacyTmuxSession","JSON","parse","session","mergeEntry","incoming","existing","incomingIsManaged","Boolean","findByIdentity","queryOne","undefined","findByName","findPidConflicts","query","map","entriesEqual","left","right","stringify","deleteNameConflict","conflict","isAlive","execute","insertOrUpdate","entry","instance","prepare","run","runtimeRefJson","toISOString","needsWrite","merged","length","save","pidConflicts","process","kill","error","code","pruneAt","nowMs","entries","list","stale","filter","e","transaction","prune","getTime","pruneIfDue","elapsed","register","registerBatch","some","rename","currentName","newName","togglePin","result","changes","lookup","rows"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../src/utils/AgentRegistry.ts"],"sourcesContent":["import os from \"os\";\nimport path from \"path\";\nimport type { AgentType } from \"../adapters/AgentAdapter.js\";\nimport { DatabaseConnection, resolveAgentRegistryDbPath } from \"../database/index.js\";\nimport { parseTmuxRuntimeRef, type TmuxRuntimeRef } from \"../runtime/tmux/TmuxRuntimeRef.js\";\n\nexport class RenameNotFoundError extends Error {\n constructor(public agentName: string) {\n super(`Agent \"${agentName}\" not found in registry.`);\n this.name = \"RenameNotFoundError\";\n }\n}\n\nexport class RenameConflictError extends Error {\n constructor(public agentName: string) {\n super(`Agent \"${agentName}\" is already in use.`);\n this.name = \"RenameConflictError\";\n }\n}\n\nexport interface RegistryEntry {\n name: string;\n type: AgentType;\n pid: number;\n runtime: AgentRuntimeProvider;\n runtimeRef: unknown | null;\n cwd: string;\n startedAt: string; // ISO 8601\n sessionId: string;\n sessionFilePath: string;\n pinned: boolean;\n updatedAt?: string;\n}\n\ninterface RegistryRow {\n name: string;\n type: AgentType;\n pid: number;\n tmux_session: string;\n runtime?: string;\n runtime_ref?: string;\n cwd: string;\n started_at: string;\n session_id: string;\n session_file_path: string;\n updated_at: string;\n pinned: number;\n}\n\nexport const AGENT_RUNTIME_PROVIDERS = [\"tmux\", \"herdr\"] as const;\nexport type AgentRuntimeProvider = (typeof AGENT_RUNTIME_PROVIDERS)[number];\n\nconst DEFAULT_REGISTRY_PATH = path.join(os.homedir(), \".ai-devkit\", \"agents.json\");\nconst DEFAULT_PRUNE_INTERVAL_MS = 30_000;\n\nlet defaultInstance: AgentRegistry | null = null;\n\nexport interface AgentRegistryOptions {\n now?: () => Date;\n pruneIntervalMs?: number;\n onDatabaseOperation?: (sql: string) => void;\n readonly?: boolean;\n}\n\nexport class AgentRegistry {\n private db: DatabaseConnection;\n private readonly now: () => Date;\n private readonly pruneIntervalMs: number;\n private readonly readonly: boolean;\n private lastPrunedAt: number | undefined;\n\n constructor(filePath: string = DEFAULT_REGISTRY_PATH, options: AgentRegistryOptions = {}) {\n this.now = options.now ?? (() => new Date());\n this.pruneIntervalMs = options.pruneIntervalMs ?? DEFAULT_PRUNE_INTERVAL_MS;\n this.readonly = options.readonly ?? false;\n this.db = new DatabaseConnection({\n dbPath: resolveAgentRegistryDbPath(filePath),\n verbose: options.onDatabaseOperation,\n readonly: this.readonly,\n });\n }\n\n static default(): AgentRegistry {\n if (!defaultInstance) {\n defaultInstance = new AgentRegistry();\n }\n return defaultInstance;\n }\n\n private rowToEntry(row: RegistryRow): RegistryEntry {\n const runtime = this.parseRuntime(row.runtime);\n return {\n name: row.name,\n type: row.type,\n pid: row.pid,\n runtime,\n runtimeRef: this.parseRuntimeRef(runtime, row.runtime_ref, row.tmux_session),\n cwd: row.cwd,\n startedAt: row.started_at,\n sessionId: row.session_id,\n sessionFilePath: row.session_file_path,\n pinned: row.pinned !== 0,\n updatedAt: row.updated_at,\n };\n }\n\n private parseRuntime(value: string | undefined): AgentRuntimeProvider {\n return value === \"herdr\" ? \"herdr\" : \"tmux\";\n }\n\n private parseRuntimeRef(\n runtime: AgentRuntimeProvider,\n raw: string | undefined,\n legacyTmuxSession: string,\n ): unknown | null {\n if (raw) {\n try {\n return JSON.parse(raw) as unknown;\n } catch {\n return null;\n }\n }\n\n if (runtime === \"tmux\" && legacyTmuxSession) {\n return { session: legacyTmuxSession };\n }\n\n return null;\n }\n\n private mergeEntry(incoming: RegistryEntry, existing: RegistryEntry | undefined): RegistryEntry {\n if (!existing) return incoming;\n const keepExistingRuntime =\n existing.runtime === \"herdr\" ||\n Boolean(parseTmuxRuntimeRef(existing.runtimeRef)) ||\n incoming.runtime !== \"herdr\";\n return {\n ...existing,\n name: existing.name,\n runtime: keepExistingRuntime ? existing.runtime : incoming.runtime,\n runtimeRef: keepExistingRuntime ? existing.runtimeRef : incoming.runtimeRef,\n cwd: existing.cwd || incoming.cwd,\n startedAt: existing.startedAt || incoming.startedAt,\n sessionId: incoming.sessionId || existing.sessionId,\n sessionFilePath: incoming.sessionFilePath || existing.sessionFilePath,\n };\n }\n\n private findByIdentity(type: AgentType, pid: number): RegistryEntry | undefined {\n const row = this.db.queryOne<RegistryRow>(\"SELECT * FROM agents WHERE type = ? AND pid = ?\", [\n type,\n pid,\n ]);\n return row ? this.rowToEntry(row) : undefined;\n }\n\n private findByName(name: string): RegistryEntry | undefined {\n const row = this.db.queryOne<RegistryRow>(\"SELECT * FROM agents WHERE name = ?\", [name]);\n return row ? this.rowToEntry(row) : undefined;\n }\n\n private findPidConflicts(type: AgentType, pid: number): RegistryEntry[] {\n return this.db\n .query<RegistryRow>(\"SELECT * FROM agents WHERE pid = ? AND type <> ?\", [pid, type])\n .map((row) => this.rowToEntry(row));\n }\n\n private entriesEqual(left: RegistryEntry, right: RegistryEntry): boolean {\n return (\n left.name === right.name &&\n left.type === right.type &&\n left.pid === right.pid &&\n left.runtime === right.runtime &&\n JSON.stringify(left.runtimeRef ?? null) === JSON.stringify(right.runtimeRef ?? null) &&\n left.cwd === right.cwd &&\n left.startedAt === right.startedAt &&\n left.sessionId === right.sessionId &&\n left.sessionFilePath === right.sessionFilePath\n );\n }\n\n private deleteNameConflict(name: string, type: AgentType, pid: number): void {\n const conflict = this.findByName(name);\n if (!conflict) return;\n if (conflict.type === type && conflict.pid === pid) return;\n if (!this.isAlive(conflict)) {\n this.db.execute(\"DELETE FROM agents WHERE type = ? AND pid = ?\", [\n conflict.type,\n conflict.pid,\n ]);\n }\n }\n\n private insertOrUpdate(entry: RegistryEntry): void {\n this.db.instance\n .prepare(`\n INSERT INTO agents (\n type, pid, name, tmux_session, cwd, started_at, session_id, session_file_path, updated_at\n , runtime, runtime_ref\n )\n VALUES (\n @type, @pid, @name, @legacyTmuxSession, @cwd, @startedAt, @sessionId, @sessionFilePath, @updatedAt\n , @runtime, @runtimeRefJson\n )\n ON CONFLICT(type, pid) DO UPDATE SET\n name = excluded.name,\n tmux_session = excluded.tmux_session,\n runtime = excluded.runtime,\n runtime_ref = excluded.runtime_ref,\n cwd = excluded.cwd,\n started_at = agents.started_at,\n session_id = excluded.session_id,\n session_file_path = excluded.session_file_path,\n updated_at = excluded.updated_at\n `)\n .run({\n ...entry,\n legacyTmuxSession: parseTmuxRuntimeRef(entry.runtimeRef)?.session ?? \"\",\n runtimeRefJson: JSON.stringify(entry.runtimeRef ?? null),\n updatedAt: this.now().toISOString(),\n });\n }\n\n private needsWrite(incoming: RegistryEntry): boolean {\n const existing = this.findByIdentity(incoming.type, incoming.pid);\n const merged = this.mergeEntry(incoming, existing);\n return (\n !existing ||\n !this.entriesEqual(merged, existing) ||\n this.findPidConflicts(incoming.type, incoming.pid).length > 0\n );\n }\n\n private save(incoming: RegistryEntry): void {\n const existing = this.findByIdentity(incoming.type, incoming.pid);\n const merged = this.mergeEntry(incoming, existing);\n const pidConflicts = this.findPidConflicts(incoming.type, incoming.pid);\n if (existing && this.entriesEqual(merged, existing) && pidConflicts.length === 0) return;\n\n for (const conflict of pidConflicts) {\n this.db.execute(\"DELETE FROM agents WHERE type = ? AND pid = ?\", [\n conflict.type,\n conflict.pid,\n ]);\n }\n if (existing && this.entriesEqual(merged, existing)) return;\n\n this.deleteNameConflict(merged.name, merged.type, merged.pid);\n this.insertOrUpdate(merged);\n }\n\n isAlive(entry: RegistryEntry): boolean {\n try {\n process.kill(entry.pid, 0);\n return true;\n } catch (error) {\n const code = error && typeof error === \"object\" && \"code\" in error ? error.code : undefined;\n return code !== \"ESRCH\";\n }\n }\n\n private pruneAt(nowMs: number): void {\n const entries = this.list();\n const stale = entries.filter((e) => !this.isAlive(e));\n if (stale.length > 0) {\n this.db.transaction(() => {\n for (const entry of stale) {\n this.db.execute(\"DELETE FROM agents WHERE type = ? AND pid = ?\", [entry.type, entry.pid]);\n }\n });\n }\n this.lastPrunedAt = nowMs;\n }\n\n prune(): void {\n this.pruneAt(this.now().getTime());\n }\n\n pruneIfDue(): void {\n const nowMs = this.now().getTime();\n const elapsed = this.lastPrunedAt === undefined ? undefined : nowMs - this.lastPrunedAt;\n if (elapsed !== undefined && elapsed >= 0 && elapsed < this.pruneIntervalMs) return;\n this.pruneAt(nowMs);\n }\n\n register(entry: RegistryEntry): void {\n this.registerBatch([entry]);\n }\n\n registerBatch(entries: RegistryEntry[]): void {\n if (entries.length === 0) return;\n if (!entries.some((entry) => this.needsWrite(entry))) return;\n this.db.transaction(() => {\n for (const incoming of entries) {\n this.save(incoming);\n }\n });\n }\n\n rename(currentName: string, newName: string): void {\n const existing = this.findByName(currentName);\n if (!existing) {\n throw new RenameNotFoundError(currentName);\n }\n const conflict = this.findByName(newName);\n if (conflict && this.isAlive(conflict)) {\n throw new RenameConflictError(newName);\n }\n\n this.db.transaction(() => {\n if (conflict) {\n this.db.execute(\"DELETE FROM agents WHERE type = ? AND pid = ?\", [\n conflict.type,\n conflict.pid,\n ]);\n }\n this.db.execute(\"UPDATE agents SET name = ?, updated_at = ? WHERE type = ? AND pid = ?\", [\n newName,\n this.now().toISOString(),\n existing.type,\n existing.pid,\n ]);\n });\n }\n\n togglePin(type: AgentType, pid: number): boolean | null {\n if (this.readonly) {\n throw new Error(\"Agent registry is readonly; cannot toggle pin.\");\n }\n const result = this.db.execute(\n \"UPDATE agents SET pinned = NOT pinned, updated_at = ? WHERE type = ? AND pid = ?\",\n [this.now().toISOString(), type, pid],\n );\n if (result.changes === 0) return null;\n return this.findByIdentity(type, pid)?.pinned ?? null;\n }\n\n lookup(name: string): RegistryEntry | null {\n return this.findByName(name) ?? null;\n }\n\n list(): RegistryEntry[] {\n const rows = this.db.query<RegistryRow>(\n \"SELECT * FROM agents ORDER BY started_at ASC, name ASC\",\n );\n return rows.map((row) => this.rowToEntry(row));\n }\n}\n\nexport { parseTmuxRuntimeRef };\nexport type { TmuxRuntimeRef };\n"],"names":["os","path","DatabaseConnection","resolveAgentRegistryDbPath","parseTmuxRuntimeRef","RenameNotFoundError","Error","agentName","name","RenameConflictError","AGENT_RUNTIME_PROVIDERS","DEFAULT_REGISTRY_PATH","join","homedir","DEFAULT_PRUNE_INTERVAL_MS","defaultInstance","AgentRegistry","db","now","pruneIntervalMs","readonly","lastPrunedAt","filePath","options","Date","dbPath","verbose","onDatabaseOperation","default","rowToEntry","row","runtime","parseRuntime","type","pid","runtimeRef","parseRuntimeRef","runtime_ref","tmux_session","cwd","startedAt","started_at","sessionId","session_id","sessionFilePath","session_file_path","pinned","updatedAt","updated_at","value","raw","legacyTmuxSession","JSON","parse","session","mergeEntry","incoming","existing","keepExistingRuntime","Boolean","findByIdentity","queryOne","undefined","findByName","findPidConflicts","query","map","entriesEqual","left","right","stringify","deleteNameConflict","conflict","isAlive","execute","insertOrUpdate","entry","instance","prepare","run","runtimeRefJson","toISOString","needsWrite","merged","length","save","pidConflicts","process","kill","error","code","pruneAt","nowMs","entries","list","stale","filter","e","transaction","prune","getTime","pruneIfDue","elapsed","register","registerBatch","some","rename","currentName","newName","togglePin","result","changes","lookup","rows"],"mappings":"AAAA,OAAOA,QAAQ,KAAK;AACpB,OAAOC,UAAU,OAAO;AAExB,SAASC,kBAAkB,EAAEC,0BAA0B,QAAQ,uBAAuB;AACtF,SAASC,mBAAmB,QAA6B,oCAAoC;AAE7F,OAAO,MAAMC,4BAA4BC;;IACvC,YAAY,AAAOC,SAAiB,CAAE;QACpC,KAAK,CAAC,CAAC,OAAO,EAAEA,UAAU,wBAAwB,CAAC,QADlCA,YAAAA;QAEjB,IAAI,CAACC,IAAI,GAAG;IACd;AACF;AAEA,OAAO,MAAMC,4BAA4BH;;IACvC,YAAY,AAAOC,SAAiB,CAAE;QACpC,KAAK,CAAC,CAAC,OAAO,EAAEA,UAAU,oBAAoB,CAAC,QAD9BA,YAAAA;QAEjB,IAAI,CAACC,IAAI,GAAG;IACd;AACF;AA+BA,OAAO,MAAME,0BAA0B;IAAC;IAAQ;CAAQ,CAAU;AAGlE,MAAMC,wBAAwBV,KAAKW,IAAI,CAACZ,GAAGa,OAAO,IAAI,cAAc;AACpE,MAAMC,4BAA4B;AAElC,IAAIC,kBAAwC;AAS5C,OAAO,MAAMC;IACHC,GAAuB;IACdC,IAAgB;IAChBC,gBAAwB;IACxBC,SAAkB;IAC3BC,aAAiC;IAEzC,YAAYC,WAAmBX,qBAAqB,EAAEY,UAAgC,CAAC,CAAC,CAAE;QACxF,IAAI,CAACL,GAAG,GAAGK,QAAQL,GAAG,IAAK,CAAA,IAAM,IAAIM,MAAK;QAC1C,IAAI,CAACL,eAAe,GAAGI,QAAQJ,eAAe,IAAIL;QAClD,IAAI,CAACM,QAAQ,GAAGG,QAAQH,QAAQ,IAAI;QACpC,IAAI,CAACH,EAAE,GAAG,IAAIf,mBAAmB;YAC/BuB,QAAQtB,2BAA2BmB;YACnCI,SAASH,QAAQI,mBAAmB;YACpCP,UAAU,IAAI,CAACA,QAAQ;QACzB;IACF;IAEA,OAAOQ,UAAyB;QAC9B,IAAI,CAACb,iBAAiB;YACpBA,kBAAkB,IAAIC;QACxB;QACA,OAAOD;IACT;IAEQc,WAAWC,GAAgB,EAAiB;QAClD,MAAMC,UAAU,IAAI,CAACC,YAAY,CAACF,IAAIC,OAAO;QAC7C,OAAO;YACLvB,MAAMsB,IAAItB,IAAI;YACdyB,MAAMH,IAAIG,IAAI;YACdC,KAAKJ,IAAII,GAAG;YACZH;YACAI,YAAY,IAAI,CAACC,eAAe,CAACL,SAASD,IAAIO,WAAW,EAAEP,IAAIQ,YAAY;YAC3EC,KAAKT,IAAIS,GAAG;YACZC,WAAWV,IAAIW,UAAU;YACzBC,WAAWZ,IAAIa,UAAU;YACzBC,iBAAiBd,IAAIe,iBAAiB;YACtCC,QAAQhB,IAAIgB,MAAM,KAAK;YACvBC,WAAWjB,IAAIkB,UAAU;QAC3B;IACF;IAEQhB,aAAaiB,KAAyB,EAAwB;QACpE,OAAOA,UAAU,UAAU,UAAU;IACvC;IAEQb,gBACNL,OAA6B,EAC7BmB,GAAuB,EACvBC,iBAAyB,EACT;QAChB,IAAID,KAAK;YACP,IAAI;gBACF,OAAOE,KAAKC,KAAK,CAACH;YACpB,EAAE,OAAM;gBACN,OAAO;YACT;QACF;QAEA,IAAInB,YAAY,UAAUoB,mBAAmB;YAC3C,OAAO;gBAAEG,SAASH;YAAkB;QACtC;QAEA,OAAO;IACT;IAEQI,WAAWC,QAAuB,EAAEC,QAAmC,EAAiB;QAC9F,IAAI,CAACA,UAAU,OAAOD;QACtB,MAAME,sBACJD,SAAS1B,OAAO,KAAK,WACrB4B,QAAQvD,oBAAoBqD,SAAStB,UAAU,MAC/CqB,SAASzB,OAAO,KAAK;QACvB,OAAO;YACL,GAAG0B,QAAQ;YACXjD,MAAMiD,SAASjD,IAAI;YACnBuB,SAAS2B,sBAAsBD,SAAS1B,OAAO,GAAGyB,SAASzB,OAAO;YAClEI,YAAYuB,sBAAsBD,SAAStB,UAAU,GAAGqB,SAASrB,UAAU;YAC3EI,KAAKkB,SAASlB,GAAG,IAAIiB,SAASjB,GAAG;YACjCC,WAAWiB,SAASjB,SAAS,IAAIgB,SAAShB,SAAS;YACnDE,WAAWc,SAASd,SAAS,IAAIe,SAASf,SAAS;YACnDE,iBAAiBY,SAASZ,eAAe,IAAIa,SAASb,eAAe;QACvE;IACF;IAEQgB,eAAe3B,IAAe,EAAEC,GAAW,EAA6B;QAC9E,MAAMJ,MAAM,IAAI,CAACb,EAAE,CAAC4C,QAAQ,CAAc,mDAAmD;YAC3F5B;YACAC;SACD;QACD,OAAOJ,MAAM,IAAI,CAACD,UAAU,CAACC,OAAOgC;IACtC;IAEQC,WAAWvD,IAAY,EAA6B;QAC1D,MAAMsB,MAAM,IAAI,CAACb,EAAE,CAAC4C,QAAQ,CAAc,uCAAuC;YAACrD;SAAK;QACvF,OAAOsB,MAAM,IAAI,CAACD,UAAU,CAACC,OAAOgC;IACtC;IAEQE,iBAAiB/B,IAAe,EAAEC,GAAW,EAAmB;QACtE,OAAO,IAAI,CAACjB,EAAE,CACXgD,KAAK,CAAc,oDAAoD;YAAC/B;YAAKD;SAAK,EAClFiC,GAAG,CAAC,CAACpC,MAAQ,IAAI,CAACD,UAAU,CAACC;IAClC;IAEQqC,aAAaC,IAAmB,EAAEC,KAAoB,EAAW;QACvE,OACED,KAAK5D,IAAI,KAAK6D,MAAM7D,IAAI,IACxB4D,KAAKnC,IAAI,KAAKoC,MAAMpC,IAAI,IACxBmC,KAAKlC,GAAG,KAAKmC,MAAMnC,GAAG,IACtBkC,KAAKrC,OAAO,KAAKsC,MAAMtC,OAAO,IAC9BqB,KAAKkB,SAAS,CAACF,KAAKjC,UAAU,IAAI,UAAUiB,KAAKkB,SAAS,CAACD,MAAMlC,UAAU,IAAI,SAC/EiC,KAAK7B,GAAG,KAAK8B,MAAM9B,GAAG,IACtB6B,KAAK5B,SAAS,KAAK6B,MAAM7B,SAAS,IAClC4B,KAAK1B,SAAS,KAAK2B,MAAM3B,SAAS,IAClC0B,KAAKxB,eAAe,KAAKyB,MAAMzB,eAAe;IAElD;IAEQ2B,mBAAmB/D,IAAY,EAAEyB,IAAe,EAAEC,GAAW,EAAQ;QAC3E,MAAMsC,WAAW,IAAI,CAACT,UAAU,CAACvD;QACjC,IAAI,CAACgE,UAAU;QACf,IAAIA,SAASvC,IAAI,KAAKA,QAAQuC,SAAStC,GAAG,KAAKA,KAAK;QACpD,IAAI,CAAC,IAAI,CAACuC,OAAO,CAACD,WAAW;YAC3B,IAAI,CAACvD,EAAE,CAACyD,OAAO,CAAC,iDAAiD;gBAC/DF,SAASvC,IAAI;gBACbuC,SAAStC,GAAG;aACb;QACH;IACF;IAEQyC,eAAeC,KAAoB,EAAQ;QACjD,IAAI,CAAC3D,EAAE,CAAC4D,QAAQ,CACbC,OAAO,CAAC,CAAC;;;;;;;;;;;;;;;;;;;QAmBR,CAAC,EACFC,GAAG,CAAC;YACH,GAAGH,KAAK;YACRzB,mBAAmB/C,oBAAoBwE,MAAMzC,UAAU,GAAGmB,WAAW;YACrE0B,gBAAgB5B,KAAKkB,SAAS,CAACM,MAAMzC,UAAU,IAAI;YACnDY,WAAW,IAAI,CAAC7B,GAAG,GAAG+D,WAAW;QACnC;IACJ;IAEQC,WAAW1B,QAAuB,EAAW;QACnD,MAAMC,WAAW,IAAI,CAACG,cAAc,CAACJ,SAASvB,IAAI,EAAEuB,SAAStB,GAAG;QAChE,MAAMiD,SAAS,IAAI,CAAC5B,UAAU,CAACC,UAAUC;QACzC,OACE,CAACA,YACD,CAAC,IAAI,CAACU,YAAY,CAACgB,QAAQ1B,aAC3B,IAAI,CAACO,gBAAgB,CAACR,SAASvB,IAAI,EAAEuB,SAAStB,GAAG,EAAEkD,MAAM,GAAG;IAEhE;IAEQC,KAAK7B,QAAuB,EAAQ;QAC1C,MAAMC,WAAW,IAAI,CAACG,cAAc,CAACJ,SAASvB,IAAI,EAAEuB,SAAStB,GAAG;QAChE,MAAMiD,SAAS,IAAI,CAAC5B,UAAU,CAACC,UAAUC;QACzC,MAAM6B,eAAe,IAAI,CAACtB,gBAAgB,CAACR,SAASvB,IAAI,EAAEuB,SAAStB,GAAG;QACtE,IAAIuB,YAAY,IAAI,CAACU,YAAY,CAACgB,QAAQ1B,aAAa6B,aAAaF,MAAM,KAAK,GAAG;QAElF,KAAK,MAAMZ,YAAYc,aAAc;YACnC,IAAI,CAACrE,EAAE,CAACyD,OAAO,CAAC,iDAAiD;gBAC/DF,SAASvC,IAAI;gBACbuC,SAAStC,GAAG;aACb;QACH;QACA,IAAIuB,YAAY,IAAI,CAACU,YAAY,CAACgB,QAAQ1B,WAAW;QAErD,IAAI,CAACc,kBAAkB,CAACY,OAAO3E,IAAI,EAAE2E,OAAOlD,IAAI,EAAEkD,OAAOjD,GAAG;QAC5D,IAAI,CAACyC,cAAc,CAACQ;IACtB;IAEAV,QAAQG,KAAoB,EAAW;QACrC,IAAI;YACFW,QAAQC,IAAI,CAACZ,MAAM1C,GAAG,EAAE;YACxB,OAAO;QACT,EAAE,OAAOuD,OAAO;YACd,MAAMC,OAAOD,SAAS,OAAOA,UAAU,YAAY,UAAUA,QAAQA,MAAMC,IAAI,GAAG5B;YAClF,OAAO4B,SAAS;QAClB;IACF;IAEQC,QAAQC,KAAa,EAAQ;QACnC,MAAMC,UAAU,IAAI,CAACC,IAAI;QACzB,MAAMC,QAAQF,QAAQG,MAAM,CAAC,CAACC,IAAM,CAAC,IAAI,CAACxB,OAAO,CAACwB;QAClD,IAAIF,MAAMX,MAAM,GAAG,GAAG;YACpB,IAAI,CAACnE,EAAE,CAACiF,WAAW,CAAC;gBAClB,KAAK,MAAMtB,SAASmB,MAAO;oBACzB,IAAI,CAAC9E,EAAE,CAACyD,OAAO,CAAC,iDAAiD;wBAACE,MAAM3C,IAAI;wBAAE2C,MAAM1C,GAAG;qBAAC;gBAC1F;YACF;QACF;QACA,IAAI,CAACb,YAAY,GAAGuE;IACtB;IAEAO,QAAc;QACZ,IAAI,CAACR,OAAO,CAAC,IAAI,CAACzE,GAAG,GAAGkF,OAAO;IACjC;IAEAC,aAAmB;QACjB,MAAMT,QAAQ,IAAI,CAAC1E,GAAG,GAAGkF,OAAO;QAChC,MAAME,UAAU,IAAI,CAACjF,YAAY,KAAKyC,YAAYA,YAAY8B,QAAQ,IAAI,CAACvE,YAAY;QACvF,IAAIiF,YAAYxC,aAAawC,WAAW,KAAKA,UAAU,IAAI,CAACnF,eAAe,EAAE;QAC7E,IAAI,CAACwE,OAAO,CAACC;IACf;IAEAW,SAAS3B,KAAoB,EAAQ;QACnC,IAAI,CAAC4B,aAAa,CAAC;YAAC5B;SAAM;IAC5B;IAEA4B,cAAcX,OAAwB,EAAQ;QAC5C,IAAIA,QAAQT,MAAM,KAAK,GAAG;QAC1B,IAAI,CAACS,QAAQY,IAAI,CAAC,CAAC7B,QAAU,IAAI,CAACM,UAAU,CAACN,SAAS;QACtD,IAAI,CAAC3D,EAAE,CAACiF,WAAW,CAAC;YAClB,KAAK,MAAM1C,YAAYqC,QAAS;gBAC9B,IAAI,CAACR,IAAI,CAAC7B;YACZ;QACF;IACF;IAEAkD,OAAOC,WAAmB,EAAEC,OAAe,EAAQ;QACjD,MAAMnD,WAAW,IAAI,CAACM,UAAU,CAAC4C;QACjC,IAAI,CAAClD,UAAU;YACb,MAAM,IAAIpD,oBAAoBsG;QAChC;QACA,MAAMnC,WAAW,IAAI,CAACT,UAAU,CAAC6C;QACjC,IAAIpC,YAAY,IAAI,CAACC,OAAO,CAACD,WAAW;YACtC,MAAM,IAAI/D,oBAAoBmG;QAChC;QAEA,IAAI,CAAC3F,EAAE,CAACiF,WAAW,CAAC;YAClB,IAAI1B,UAAU;gBACZ,IAAI,CAACvD,EAAE,CAACyD,OAAO,CAAC,iDAAiD;oBAC/DF,SAASvC,IAAI;oBACbuC,SAAStC,GAAG;iBACb;YACH;YACA,IAAI,CAACjB,EAAE,CAACyD,OAAO,CAAC,yEAAyE;gBACvFkC;gBACA,IAAI,CAAC1F,GAAG,GAAG+D,WAAW;gBACtBxB,SAASxB,IAAI;gBACbwB,SAASvB,GAAG;aACb;QACH;IACF;IAEA2E,UAAU5E,IAAe,EAAEC,GAAW,EAAkB;QACtD,IAAI,IAAI,CAACd,QAAQ,EAAE;YACjB,MAAM,IAAId,MAAM;QAClB;QACA,MAAMwG,SAAS,IAAI,CAAC7F,EAAE,CAACyD,OAAO,CAC5B,oFACA;YAAC,IAAI,CAACxD,GAAG,GAAG+D,WAAW;YAAIhD;YAAMC;SAAI;QAEvC,IAAI4E,OAAOC,OAAO,KAAK,GAAG,OAAO;QACjC,OAAO,IAAI,CAACnD,cAAc,CAAC3B,MAAMC,MAAMY,UAAU;IACnD;IAEAkE,OAAOxG,IAAY,EAAwB;QACzC,OAAO,IAAI,CAACuD,UAAU,CAACvD,SAAS;IAClC;IAEAsF,OAAwB;QACtB,MAAMmB,OAAO,IAAI,CAAChG,EAAE,CAACgD,KAAK,CACxB;QAEF,OAAOgD,KAAK/C,GAAG,CAAC,CAACpC,MAAQ,IAAI,CAACD,UAAU,CAACC;IAC3C;AACF;AAEA,SAAS1B,mBAAmB,GAAG"}
|