@cotal-ai/herdr 0.0.0 → 0.19.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/LICENSE +202 -0
- package/README.md +95 -8
- package/dist/driver.d.ts +140 -0
- package/dist/driver.d.ts.map +1 -0
- package/dist/driver.js +543 -0
- package/dist/driver.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -0
- package/dist/runtime.d.ts +30 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/runtime.js +230 -0
- package/dist/runtime.js.map +1 -0
- package/package.json +29 -7
package/dist/driver.js
ADDED
|
@@ -0,0 +1,543 @@
|
|
|
1
|
+
import { execFileSync, spawn } from "node:child_process";
|
|
2
|
+
import { closeSync, mkdtempSync, openSync, readFileSync, rmSync } from "node:fs";
|
|
3
|
+
import { tmpdir } from "node:os";
|
|
4
|
+
import { basename, join } from "node:path";
|
|
5
|
+
const EXIT_WAIT_MS = 8_000;
|
|
6
|
+
const EXIT_POLL_MS = 100;
|
|
7
|
+
const PROBE_MS = 2_000;
|
|
8
|
+
const RUN_TIMEOUT_MS = 10_000;
|
|
9
|
+
const SERVER_START_WAIT_MS = 5_000;
|
|
10
|
+
const SERVER_START_POLL_MS = 100;
|
|
11
|
+
const RUN_START_WAIT_MS = 5_000;
|
|
12
|
+
const RUN_START_POLL_MS = 50;
|
|
13
|
+
/** A structured error from the herdr CLI/socket API (e.g. `pane_not_found`). */
|
|
14
|
+
export class HerdrCliError extends Error {
|
|
15
|
+
code;
|
|
16
|
+
constructor(code, message) {
|
|
17
|
+
super(`herdr: ${code}: ${message}`);
|
|
18
|
+
this.code = code;
|
|
19
|
+
this.name = "HerdrCliError";
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
/** Oldest herdr whose CLI contract this driver speaks: `workspace create` + `pane run`, and
|
|
23
|
+
* `pane send-text`. 0.7.x exposed `agent start --cwd -- argv` and `agent send` instead, which
|
|
24
|
+
* 0.8.0 removed outright — there is no shared subset, so an older herdr is refused rather than
|
|
25
|
+
* silently half-supported. */
|
|
26
|
+
export const MIN_HERDR = [0, 8, 0];
|
|
27
|
+
/** `herdr --version` prints e.g. `herdr 0.8.0`. Returns the numeric triple, or undefined when the
|
|
28
|
+
* output does not carry a parseable version (a fork, a wrapper, a future format change). */
|
|
29
|
+
export function parseVersion(out) {
|
|
30
|
+
const m = /(\d+)\.(\d+)\.(\d+)/.exec(out);
|
|
31
|
+
return m ? [Number(m[1]), Number(m[2]), Number(m[3])] : undefined;
|
|
32
|
+
}
|
|
33
|
+
function atLeast(v, min) {
|
|
34
|
+
for (let i = 0; i < 3; i++) {
|
|
35
|
+
if (v[i] > min[i])
|
|
36
|
+
return true;
|
|
37
|
+
if (v[i] < min[i])
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
return true;
|
|
41
|
+
}
|
|
42
|
+
/** True if a herdr this driver can actually drive is on PATH. Deliberately checks the VERSION and
|
|
43
|
+
* not merely that the binary executes: a bare `--version` probe reports 0.7.x as available, so the
|
|
44
|
+
* CLI advertises the runtime as ready and every spawn then dies on `unknown option: --cwd`. An
|
|
45
|
+
* unparseable version reads as unavailable — uncertainty must not advertise readiness. The session
|
|
46
|
+
* server is provisioned separately ({@link ensureServer}), like tmux's auto-created sessions. */
|
|
47
|
+
export function available() {
|
|
48
|
+
let out;
|
|
49
|
+
try {
|
|
50
|
+
out = execFileSync("herdr", ["--version"], {
|
|
51
|
+
encoding: "utf8",
|
|
52
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
53
|
+
timeout: PROBE_MS,
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
const version = parseVersion(out);
|
|
60
|
+
return version !== undefined && atLeast(version, MIN_HERDR);
|
|
61
|
+
}
|
|
62
|
+
/** The installed herdr version as text, for error messages. Empty when it cannot be determined. */
|
|
63
|
+
export function versionText() {
|
|
64
|
+
try {
|
|
65
|
+
return execFileSync("herdr", ["--version"], {
|
|
66
|
+
encoding: "utf8",
|
|
67
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
68
|
+
timeout: PROBE_MS,
|
|
69
|
+
}).trim();
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
return "";
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
function parseAgent(record) {
|
|
76
|
+
const terminalId = record.terminal_id;
|
|
77
|
+
const paneId = record.pane_id;
|
|
78
|
+
const workspaceId = record.workspace_id;
|
|
79
|
+
if (typeof terminalId !== "string" || typeof paneId !== "string" || typeof workspaceId !== "string")
|
|
80
|
+
throw new Error(`herdr: malformed agent record (${JSON.stringify(record)})`);
|
|
81
|
+
return { terminalId, paneId, workspaceId };
|
|
82
|
+
}
|
|
83
|
+
/** Run one herdr CLI command scoped to `session` and return the parsed JSON `result`.
|
|
84
|
+
* Every invocation carries `--session` explicitly so no call can ever hit the ambient/default
|
|
85
|
+
* Herdr session. A JSON `{error}` becomes a {@link HerdrCliError}; missing/non-JSON output
|
|
86
|
+
* throws — except for `void: true` commands (send-keys, report-metadata), which herdr
|
|
87
|
+
* acknowledges with a bare exit 0 and no output. */
|
|
88
|
+
export function run(session, args, opts = {}) {
|
|
89
|
+
let out;
|
|
90
|
+
try {
|
|
91
|
+
out = execFileSync("herdr", ["--session", session, ...args], {
|
|
92
|
+
encoding: "utf8",
|
|
93
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
94
|
+
timeout: RUN_TIMEOUT_MS,
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
catch (err) {
|
|
98
|
+
// A JSON error rides stderr (sometimes stdout) with a nonzero exit; surface its code.
|
|
99
|
+
// Anything else (socket down, timeout, kill) is not a protocol error — rethrow with context.
|
|
100
|
+
const e = err;
|
|
101
|
+
const structured = parseError(`${String(e.stdout ?? "")}\n${String(e.stderr ?? "")}`);
|
|
102
|
+
if (structured)
|
|
103
|
+
throw structured;
|
|
104
|
+
throw new Error(`herdr --session ${session} ${args.join(" ")} failed: ${String(e.stderr ?? "").trim() || String(e.message ?? err)}`, { cause: err });
|
|
105
|
+
}
|
|
106
|
+
// A response that carries a RESULT succeeded, whatever else it printed — so look for the result
|
|
107
|
+
// first. Scanning for an error first meant any JSON line with a top-level `error` key (a
|
|
108
|
+
// deprecation notice, an informational warning) failed a command that actually worked, because
|
|
109
|
+
// parseError scans every line and the result line was never reached.
|
|
110
|
+
const result = findResult(out);
|
|
111
|
+
if (result)
|
|
112
|
+
return result;
|
|
113
|
+
const structured = parseError(out);
|
|
114
|
+
if (structured)
|
|
115
|
+
throw structured;
|
|
116
|
+
if (opts.void)
|
|
117
|
+
return {};
|
|
118
|
+
throw new Error(`herdr --session ${session} ${args.join(" ")}: no JSON result in output (${JSON.stringify(out)})`);
|
|
119
|
+
}
|
|
120
|
+
function parseError(out) {
|
|
121
|
+
for (const line of out.split("\n")) {
|
|
122
|
+
const trimmed = line.trim();
|
|
123
|
+
if (!trimmed.startsWith("{"))
|
|
124
|
+
continue;
|
|
125
|
+
try {
|
|
126
|
+
const parsed = JSON.parse(trimmed);
|
|
127
|
+
if (parsed.error)
|
|
128
|
+
return new HerdrCliError(String(parsed.error.code ?? "unknown"), String(parsed.error.message ?? trimmed));
|
|
129
|
+
}
|
|
130
|
+
catch {
|
|
131
|
+
/* not JSON — keep scanning */
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return undefined;
|
|
135
|
+
}
|
|
136
|
+
/** The `result` payload from the first JSON line that carries one, or undefined. Non-throwing so
|
|
137
|
+
* {@link run} can decide precedence between a result and an error in the same output. */
|
|
138
|
+
function findResult(out) {
|
|
139
|
+
for (const line of out.split("\n")) {
|
|
140
|
+
const trimmed = line.trim();
|
|
141
|
+
if (!trimmed.startsWith("{"))
|
|
142
|
+
continue;
|
|
143
|
+
try {
|
|
144
|
+
const parsed = JSON.parse(trimmed);
|
|
145
|
+
if (parsed.result && typeof parsed.result === "object")
|
|
146
|
+
return parsed.result;
|
|
147
|
+
}
|
|
148
|
+
catch {
|
|
149
|
+
/* not JSON — keep scanning */
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
return undefined;
|
|
153
|
+
}
|
|
154
|
+
/** True if the session's server answers on its socket. `herdr status server` exits 0 either
|
|
155
|
+
* way, so the answer is in the text. */
|
|
156
|
+
export function serverRunning(session) {
|
|
157
|
+
const out = execFileSync("herdr", ["--session", session, "status", "server"], {
|
|
158
|
+
encoding: "utf8",
|
|
159
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
160
|
+
timeout: PROBE_MS,
|
|
161
|
+
});
|
|
162
|
+
return /^\s*status:\s*running\s*$/m.test(out);
|
|
163
|
+
}
|
|
164
|
+
/** Portable synchronous sleep — {@link Runtime.spawn} is a synchronous contract, so server
|
|
165
|
+
* provisioning below cannot await. */
|
|
166
|
+
function sleepSync(ms) {
|
|
167
|
+
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
|
|
168
|
+
}
|
|
169
|
+
/** Whether the spawned server child is PROVABLY dead. The provisioning wait blocks the event
|
|
170
|
+
* loop, so Node cannot reap the child yet and a dead child lingers as a zombie — which
|
|
171
|
+
* `kill(pid, 0)` still counts as alive; `ps`'s state column sees through that synchronously.
|
|
172
|
+
* Death is only ever proven by `ps` actually running: a nonzero `ps` exit (it ran, the pid
|
|
173
|
+
* does not exist) or a zombie/empty state. A `ps` that cannot run at all (Windows, a ps-less
|
|
174
|
+
* container) proves nothing and reads as "still alive" — early-death detection is a POSIX
|
|
175
|
+
* fast path; everywhere else the bounded startup window still fails loud with the captured
|
|
176
|
+
* stderr, never a false "dead" for a healthy starting child. */
|
|
177
|
+
function childDead(pid) {
|
|
178
|
+
if (pid === undefined)
|
|
179
|
+
return true; // spawn itself failed (error event is pending)
|
|
180
|
+
let state;
|
|
181
|
+
try {
|
|
182
|
+
state = execFileSync("ps", ["-o", "state=", "-p", String(pid)], {
|
|
183
|
+
encoding: "utf8",
|
|
184
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
185
|
+
timeout: PROBE_MS,
|
|
186
|
+
}).trim();
|
|
187
|
+
}
|
|
188
|
+
catch (err) {
|
|
189
|
+
// exitCode set → ps ran and found no such pid: proof of death. Anything else (ENOENT,
|
|
190
|
+
// spawn failure, timeout) means ps itself failed: no proof, treat as alive.
|
|
191
|
+
const status = err.status;
|
|
192
|
+
return typeof status === "number" && status !== 0;
|
|
193
|
+
}
|
|
194
|
+
return state === "" || state.startsWith("Z");
|
|
195
|
+
}
|
|
196
|
+
/** Ensure the named session's headless server is up, starting one when absent (the herdr
|
|
197
|
+
* analog of tmux's auto-created detached session). Fails loud if it doesn't come up — a dead
|
|
198
|
+
* or wedged start throws WITH the server's own stderr, and the swallowed `error` event means
|
|
199
|
+
* a spawn failure can never surface as an uncaught exception in the caller later. */
|
|
200
|
+
export function ensureServer(session) {
|
|
201
|
+
if (serverRunning(session))
|
|
202
|
+
return;
|
|
203
|
+
const dir = mkdtempSync(join(tmpdir(), "cotal-herdr-srv-"));
|
|
204
|
+
const logPath = join(dir, "server.log");
|
|
205
|
+
const logFd = openSync(logPath, "a");
|
|
206
|
+
const child = spawn("herdr", ["--session", session, "server"], {
|
|
207
|
+
detached: true,
|
|
208
|
+
stdio: ["ignore", "ignore", logFd],
|
|
209
|
+
});
|
|
210
|
+
// A spawn failure (e.g. ENOENT) is delivered as an async "error" event once the event loop
|
|
211
|
+
// resumes — after this function has already thrown via childDead. Swallow it here so it can
|
|
212
|
+
// never crash the manager as an unhandled ChildProcess error.
|
|
213
|
+
child.on("error", () => { });
|
|
214
|
+
const finish = () => {
|
|
215
|
+
try {
|
|
216
|
+
closeSync(logFd);
|
|
217
|
+
}
|
|
218
|
+
catch {
|
|
219
|
+
/* already closed */
|
|
220
|
+
}
|
|
221
|
+
try {
|
|
222
|
+
rmSync(dir, { recursive: true, force: true });
|
|
223
|
+
}
|
|
224
|
+
catch {
|
|
225
|
+
/* the child holds its own fd; unlinking is safe regardless */
|
|
226
|
+
}
|
|
227
|
+
};
|
|
228
|
+
const fail = (why) => {
|
|
229
|
+
let log = "";
|
|
230
|
+
try {
|
|
231
|
+
log = readFileSync(logPath, "utf8").trim();
|
|
232
|
+
}
|
|
233
|
+
catch {
|
|
234
|
+
/* no log captured */
|
|
235
|
+
}
|
|
236
|
+
finish();
|
|
237
|
+
throw new Error(`herdr: server for session "${session}" ${why}` +
|
|
238
|
+
(log ? ` - server said: ${log.split("\n").slice(-5).join(" | ")}` : "") +
|
|
239
|
+
` - check \`herdr --session ${session} status\``);
|
|
240
|
+
};
|
|
241
|
+
// Every exit from the poll below — success, timeout, or a THROW out of serverRunning (which
|
|
242
|
+
// wraps execFileSync with no catch, so a probe timeout or nonzero exit propagates) — must leave
|
|
243
|
+
// the fd closed, the scratch dir gone, and no detached child behind. Without this the throwing
|
|
244
|
+
// path leaked all three AND kept the manager alive on the unreffed child handle.
|
|
245
|
+
let adopted = false; // the server is up and now owns itself
|
|
246
|
+
try {
|
|
247
|
+
const deadline = Date.now() + SERVER_START_WAIT_MS;
|
|
248
|
+
while (Date.now() < deadline) {
|
|
249
|
+
sleepSync(SERVER_START_POLL_MS);
|
|
250
|
+
if (serverRunning(session)) {
|
|
251
|
+
adopted = true;
|
|
252
|
+
child.unref();
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
if (childDead(child.pid))
|
|
256
|
+
fail("failed to start");
|
|
257
|
+
}
|
|
258
|
+
fail(`did not come up within ${SERVER_START_WAIT_MS}ms`);
|
|
259
|
+
}
|
|
260
|
+
finally {
|
|
261
|
+
if (!adopted) {
|
|
262
|
+
// A wedged half-start (or one abandoned by a throw) must not linger: kill it so the next
|
|
263
|
+
// attempt provisions fresh, and so this process is not held open by its handle.
|
|
264
|
+
try {
|
|
265
|
+
child.kill();
|
|
266
|
+
}
|
|
267
|
+
catch {
|
|
268
|
+
/* already gone */
|
|
269
|
+
}
|
|
270
|
+
child.unref();
|
|
271
|
+
}
|
|
272
|
+
finish();
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
/** POSIX single-quote escaping. `pane run` hands its argument to the pane's interactive SHELL, so
|
|
276
|
+
* unlike every other call in this driver the command is not argv — each word must be quoted or a
|
|
277
|
+
* path containing a space, quote, or `$` becomes multiple words or a substitution. */
|
|
278
|
+
export function shellQuote(word) {
|
|
279
|
+
return `'${word.replaceAll("'", `'\\''`)}'`;
|
|
280
|
+
}
|
|
281
|
+
/** The names one foreground-process record can be matched by, most authoritative first.
|
|
282
|
+
*
|
|
283
|
+
* herdr's `pane process-info` shape is PLATFORM-DEPENDENT, which is not documented anywhere and
|
|
284
|
+
* is the whole reason this helper exists:
|
|
285
|
+
*
|
|
286
|
+
* macOS {"argv0":"node","argv":["/usr/local/bin/node","x.mjs"],"name":"node",…}
|
|
287
|
+
* Linux { "argv":["sleep","30"], "name":"sleep",…}
|
|
288
|
+
*
|
|
289
|
+
* Linux omits `argv0` entirely. Reading it alone matched on macOS and NEVER on Linux, so no
|
|
290
|
+
* agent could start there at all — the readiness poll below simply timed out on every spawn.
|
|
291
|
+
*
|
|
292
|
+
* `name` is deliberately NOT consulted: it is the kernel's comm string, truncated to 15 bytes on
|
|
293
|
+
* Linux and version-suffixed on macOS ("python3.13"), so matching it would trade a false negative
|
|
294
|
+
* for a false positive — and a readiness probe that lies green is worse than one that lies red. */
|
|
295
|
+
export function processNames(proc) {
|
|
296
|
+
if (!proc || typeof proc !== "object")
|
|
297
|
+
return [];
|
|
298
|
+
const p = proc;
|
|
299
|
+
const names = [];
|
|
300
|
+
if (typeof p.argv0 === "string")
|
|
301
|
+
names.push(p.argv0);
|
|
302
|
+
if (Array.isArray(p.argv) && typeof p.argv[0] === "string")
|
|
303
|
+
names.push(p.argv[0]);
|
|
304
|
+
return names;
|
|
305
|
+
}
|
|
306
|
+
/** True when `proc` was invoked as `command`, compared by BASENAME: herdr reports either a bare
|
|
307
|
+
* name (`node`) or an absolute path depending on platform and field, while the caller passes an
|
|
308
|
+
* absolute interpreter path (`process.execPath`). A literal comparison matches neither reliably. */
|
|
309
|
+
export function processIsCommand(proc, command) {
|
|
310
|
+
const want = basename(command);
|
|
311
|
+
return processNames(proc).some((n) => basename(n) === want);
|
|
312
|
+
}
|
|
313
|
+
/** The pane's foreground processes as herdr reports them, or `[]` when it cannot say. */
|
|
314
|
+
export function foregroundProcesses(session, paneId) {
|
|
315
|
+
let result;
|
|
316
|
+
try {
|
|
317
|
+
result = run(session, ["pane", "process-info", "--pane", paneId]);
|
|
318
|
+
}
|
|
319
|
+
catch {
|
|
320
|
+
return []; // pane may not have settled yet; the caller's deadline decides
|
|
321
|
+
}
|
|
322
|
+
const info = result.process_info;
|
|
323
|
+
const procs = info?.foreground_processes;
|
|
324
|
+
return Array.isArray(procs) ? procs : [];
|
|
325
|
+
}
|
|
326
|
+
/** The pid of the pane's foreground process running `command`, or undefined when it is not there. */
|
|
327
|
+
export function foregroundPid(session, paneId, command) {
|
|
328
|
+
const proc = foregroundProcesses(session, paneId).find((p) => processIsCommand(p, command));
|
|
329
|
+
const pid = proc?.pid;
|
|
330
|
+
return typeof pid === "number" ? pid : undefined;
|
|
331
|
+
}
|
|
332
|
+
/** True when the pane's foreground process is the command we asked for. The readiness signal for
|
|
333
|
+
* {@link agentStart}: `pane run` types into a shell, so a successful CLI call proves the keystrokes
|
|
334
|
+
* were delivered, NOT that the process started. Polling the real process table is the only proof. */
|
|
335
|
+
function paneRunning(session, paneId, command) {
|
|
336
|
+
return foregroundProcesses(session, paneId).some((p) => processIsCommand(p, command));
|
|
337
|
+
}
|
|
338
|
+
/** Start `argv` in its own workspace of `session` and return its stable refs.
|
|
339
|
+
*
|
|
340
|
+
* herdr 0.8.0 has no "create a pane running this command" primitive: `agent start` attaches a
|
|
341
|
+
* RECOGNIZED agent kind to an existing pane, `pane split` needs a pane to split from, and a fresh
|
|
342
|
+
* headless server has no workspace, tab or pane at all. So the bootstrap is `workspace create`
|
|
343
|
+
* (which yields a workspace + tab + root pane in one call, honouring --cwd) followed by `pane run`
|
|
344
|
+
* into that root pane. One workspace per agent also gives the name-labeled-tab layout for free.
|
|
345
|
+
*
|
|
346
|
+
* The command is `exec`'d deliberately: a plain `pane run` leaves the pane's shell alive after the
|
|
347
|
+
* command exits, so the pane would outlive the agent and {@link terminalState} could never prove an
|
|
348
|
+
* exit. `exec` replaces the shell, so herdr closes the pane exactly when the agent exits — which is
|
|
349
|
+
* the property the whole lifecycle design rests on.
|
|
350
|
+
*
|
|
351
|
+
* Fails loud and leaves nothing behind: if the process does not appear within the readiness window
|
|
352
|
+
* the half-built workspace is torn down before throwing. */
|
|
353
|
+
export function agentStart(session, name, cwd, argv) {
|
|
354
|
+
const created = run(session, ["workspace", "create", "--cwd", cwd, "--label", name, "--no-focus"]);
|
|
355
|
+
const rootPane = created.root_pane;
|
|
356
|
+
if (!rootPane || typeof rootPane !== "object")
|
|
357
|
+
throw new Error(`herdr: workspace create returned no root pane (${JSON.stringify(created)})`);
|
|
358
|
+
const agent = parseAgent(rootPane);
|
|
359
|
+
try {
|
|
360
|
+
// `workspace create --label` names the WORKSPACE; the tab it creates is labeled positionally
|
|
361
|
+
// ("1", "2", …). The tab strip is what an operator actually reads, so name the tab too —
|
|
362
|
+
// otherwise every agent shows up as a number.
|
|
363
|
+
const tabId = rootPane.tab_id;
|
|
364
|
+
if (typeof tabId === "string")
|
|
365
|
+
run(session, ["tab", "rename", tabId, name], { void: true });
|
|
366
|
+
run(session, ["pane", "run", agent.paneId, `exec ${argv.map(shellQuote).join(" ")}`], { void: true });
|
|
367
|
+
const argv0 = argv[0] ?? "";
|
|
368
|
+
const deadline = Date.now() + RUN_START_WAIT_MS;
|
|
369
|
+
let started = false;
|
|
370
|
+
while (Date.now() < deadline) {
|
|
371
|
+
if (paneRunning(session, agent.paneId, argv0)) {
|
|
372
|
+
started = true;
|
|
373
|
+
break;
|
|
374
|
+
}
|
|
375
|
+
// The pane closing before the process ever appeared means the command died instantly
|
|
376
|
+
// (bad interpreter, exec failure) — stop waiting out the window for a corpse.
|
|
377
|
+
if (terminalState(session, agent.terminalId) === "exited")
|
|
378
|
+
throw new Error(`herdr: agent "${name}" exited immediately; its command never started (${argv0})`);
|
|
379
|
+
sleepSync(RUN_START_POLL_MS);
|
|
380
|
+
}
|
|
381
|
+
if (!started)
|
|
382
|
+
throw new Error(`herdr: agent "${name}" did not start ${argv0} within ${RUN_START_WAIT_MS}ms - ` +
|
|
383
|
+
`check \`herdr --session ${session} pane read ${agent.paneId}\``);
|
|
384
|
+
}
|
|
385
|
+
catch (err) {
|
|
386
|
+
try {
|
|
387
|
+
closePane(session, agent.paneId);
|
|
388
|
+
}
|
|
389
|
+
catch {
|
|
390
|
+
/* best-effort teardown of the half-built workspace */
|
|
391
|
+
}
|
|
392
|
+
throw err;
|
|
393
|
+
}
|
|
394
|
+
return agent;
|
|
395
|
+
}
|
|
396
|
+
/** The CURRENT record for a terminal id, or undefined when it is gone.
|
|
397
|
+
*
|
|
398
|
+
* Resolved off the pane inventory rather than `agent get`: in herdr 0.8.0 an "agent" is a
|
|
399
|
+
* RECOGNIZED KIND (pi, claude, codex, …) attached to a pane, so a pane we started with
|
|
400
|
+
* {@link agentStart} never appears in the agent registry and `agent get` reports it as gone. The
|
|
401
|
+
* pane inventory is the only view that sees it, and it is session-wide (`--workspace` merely
|
|
402
|
+
* narrows), so a pane that moved workspaces is still found.
|
|
403
|
+
*
|
|
404
|
+
* A failed inventory THROWS rather than reporting undefined — uncertainty must never read as gone,
|
|
405
|
+
* or a live agent gets torn down as a corpse. */
|
|
406
|
+
export function agentInfo(session, terminalId) {
|
|
407
|
+
const result = run(session, ["pane", "list"]);
|
|
408
|
+
const panes = result.panes;
|
|
409
|
+
if (!Array.isArray(panes))
|
|
410
|
+
throw new Error(`herdr: malformed pane list (${JSON.stringify(result)})`);
|
|
411
|
+
for (const pane of panes) {
|
|
412
|
+
if (pane && typeof pane === "object" && pane.terminal_id === terminalId)
|
|
413
|
+
return parseAgent(pane);
|
|
414
|
+
}
|
|
415
|
+
return undefined;
|
|
416
|
+
}
|
|
417
|
+
/** Authoritative liveness for a terminal id: ONLY a successful full pane inventory that no
|
|
418
|
+
* longer contains it proves exit (herdr closes a pane when its command exits). Every failed
|
|
419
|
+
* inventory — including an absent/refused session socket, which may be a transient server
|
|
420
|
+
* restart or a permission problem — throws rather than report a false exit. */
|
|
421
|
+
export function terminalState(session, terminalId) {
|
|
422
|
+
let result;
|
|
423
|
+
try {
|
|
424
|
+
result = run(session, ["pane", "list"]);
|
|
425
|
+
}
|
|
426
|
+
catch (err) {
|
|
427
|
+
if (err instanceof HerdrCliError)
|
|
428
|
+
throw err;
|
|
429
|
+
throw new Error(`herdr: couldn't prove terminal ${terminalId} exited: ${err.message}`, { cause: err });
|
|
430
|
+
}
|
|
431
|
+
const panes = result.panes;
|
|
432
|
+
if (!Array.isArray(panes))
|
|
433
|
+
throw new Error(`herdr: malformed pane list (${JSON.stringify(result)})`);
|
|
434
|
+
for (const pane of panes) {
|
|
435
|
+
if (pane && typeof pane === "object" && pane.terminal_id === terminalId)
|
|
436
|
+
return "running";
|
|
437
|
+
}
|
|
438
|
+
return "exited";
|
|
439
|
+
}
|
|
440
|
+
/** Bounded polling over the authoritative pane inventory. */
|
|
441
|
+
export async function waitForTerminalExit(session, terminalId, opts = {}) {
|
|
442
|
+
const timeoutMs = opts.timeoutMs ?? EXIT_WAIT_MS;
|
|
443
|
+
const pollMs = opts.pollMs ?? EXIT_POLL_MS;
|
|
444
|
+
const deadline = Date.now() + timeoutMs;
|
|
445
|
+
while (true) {
|
|
446
|
+
if (terminalState(session, terminalId) === "exited")
|
|
447
|
+
return;
|
|
448
|
+
const remaining = deadline - Date.now();
|
|
449
|
+
if (remaining <= 0)
|
|
450
|
+
throw new Error(`herdr: terminal ${terminalId} did not exit within ${timeoutMs}ms`);
|
|
451
|
+
await new Promise((resolve) => setTimeout(resolve, Math.min(pollMs, remaining)));
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
/** Type literal text into a pane. Pane-scoped: the caller must pass a freshly re-resolved pane id
|
|
455
|
+
* ({@link agentInfo}), never a cached one. (herdr 0.8.0 removed `agent send`; `pane send-text` is
|
|
456
|
+
* the replacement, and it is addressed by pane rather than terminal.) */
|
|
457
|
+
export function sendText(session, paneId, text) {
|
|
458
|
+
run(session, ["pane", "send-text", paneId, text], { void: true });
|
|
459
|
+
}
|
|
460
|
+
/** Send a named key (e.g. `enter`, `ctrl+c`) to a pane. Pane-scoped: the caller must pass a
|
|
461
|
+
* freshly re-resolved pane id ({@link agentInfo}), never a cached one. */
|
|
462
|
+
export function sendKeys(session, paneId, key) {
|
|
463
|
+
run(session, ["pane", "send-keys", paneId, key], { void: true });
|
|
464
|
+
}
|
|
465
|
+
/** Close a pane. Idempotent for an already-gone pane only; every other error propagates. */
|
|
466
|
+
export function closePane(session, paneId) {
|
|
467
|
+
try {
|
|
468
|
+
run(session, ["pane", "close", paneId]);
|
|
469
|
+
}
|
|
470
|
+
catch (err) {
|
|
471
|
+
if (err instanceof HerdrCliError && err.code === "pane_not_found")
|
|
472
|
+
return;
|
|
473
|
+
throw err;
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
/** Every tab in the session, newest last. Used to find a tab to share under the `split` layout. */
|
|
477
|
+
export function tabIds(session) {
|
|
478
|
+
const result = run(session, ["tab", "list"]);
|
|
479
|
+
const tabs = result.tabs;
|
|
480
|
+
if (!Array.isArray(tabs))
|
|
481
|
+
throw new Error(`herdr: malformed tab list (${JSON.stringify(result)})`);
|
|
482
|
+
return tabs
|
|
483
|
+
.map((t) => (t && typeof t === "object" ? t.tab_id : undefined))
|
|
484
|
+
.filter((id) => typeof id === "string");
|
|
485
|
+
}
|
|
486
|
+
/** Move a pane into an EXISTING tab, splitting it, and return the pane's updated record — the
|
|
487
|
+
* public pane id changes. `terminalId` pins the response: a malformed or wrong-terminal record is
|
|
488
|
+
* rejected so a bad reply can never make later metadata/cleanup target a different terminal.
|
|
489
|
+
* Used only by the opt-in `split` layout; the default one-workspace-per-agent layout needs no move
|
|
490
|
+
* at all, because {@link agentStart} already lands each agent in its own name-labeled tab. */
|
|
491
|
+
export function paneMoveIntoTab(session, paneId, tabId, terminalId) {
|
|
492
|
+
const result = run(session, ["pane", "move", paneId, "--tab", tabId, "--split", "down", "--no-focus"]);
|
|
493
|
+
const moved = result.move_result?.pane;
|
|
494
|
+
if (!moved || typeof moved !== "object")
|
|
495
|
+
throw new Error(`herdr: pane move returned no pane (${JSON.stringify(result)})`);
|
|
496
|
+
const agent = parseAgent(moved);
|
|
497
|
+
if (agent.terminalId !== terminalId)
|
|
498
|
+
throw new Error(`herdr: pane move returned a different terminal (${agent.terminalId}, expected ${terminalId})`);
|
|
499
|
+
return agent;
|
|
500
|
+
}
|
|
501
|
+
/** Attach Cotal identity to a pane as display metadata tokens (visible in herdr's pane/agent
|
|
502
|
+
* UI). Values ride argv — never a shell — so no quoting/injection surface. */
|
|
503
|
+
export function reportMetadata(session, paneId, source, tokens) {
|
|
504
|
+
const args = ["pane", "report-metadata", paneId, "--source", source];
|
|
505
|
+
for (const [key, value] of Object.entries(tokens)) {
|
|
506
|
+
if (!/^[A-Za-z_][A-Za-z0-9_.-]*$/.test(key))
|
|
507
|
+
throw new Error(`herdr: refusing to render unsafe metadata token name ${JSON.stringify(key)}`);
|
|
508
|
+
args.push("--token", `${key}=${value}`);
|
|
509
|
+
}
|
|
510
|
+
run(session, args, { void: true });
|
|
511
|
+
}
|
|
512
|
+
/** Stop the named session's server (used by teardown/smoke; production sessions stay up —
|
|
513
|
+
* that persistence is the point of the runtime).
|
|
514
|
+
*
|
|
515
|
+
* `session stop` takes a POSITIONAL name, not `--session`, so it cannot go through {@link run}.
|
|
516
|
+
* Only "it was not running" is absorbed, matched on herdr's exact `session_stop_failed` code —
|
|
517
|
+
* which it reports on stdout with exit 0, so the output has to be read rather than ignored. Every
|
|
518
|
+
* other structured error (permission, protocol) propagates: a teardown that cannot say it failed
|
|
519
|
+
* is worse than no teardown, because it reports success either way. */
|
|
520
|
+
export function stopSession(session) {
|
|
521
|
+
let out;
|
|
522
|
+
try {
|
|
523
|
+
out = execFileSync("herdr", ["session", "stop", session], {
|
|
524
|
+
encoding: "utf8",
|
|
525
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
526
|
+
timeout: PROBE_MS,
|
|
527
|
+
});
|
|
528
|
+
}
|
|
529
|
+
catch (err) {
|
|
530
|
+
const e = err;
|
|
531
|
+
const structured = parseError(`${String(e.stdout ?? "")}\n${String(e.stderr ?? "")}`);
|
|
532
|
+
if (structured) {
|
|
533
|
+
if (structured.code === "session_stop_failed")
|
|
534
|
+
return; // not running: the desired end state
|
|
535
|
+
throw structured;
|
|
536
|
+
}
|
|
537
|
+
throw new Error(`herdr session stop ${session} failed: ${String(e.stderr ?? "").trim() || String(e.message ?? err)}`, { cause: err });
|
|
538
|
+
}
|
|
539
|
+
const structured = parseError(out);
|
|
540
|
+
if (structured && structured.code !== "session_stop_failed")
|
|
541
|
+
throw structured;
|
|
542
|
+
}
|
|
543
|
+
//# sourceMappingURL=driver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"driver.js","sourceRoot":"","sources":["../src/driver.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/** @cotal-ai/herdr — the Herdr integration: a thin driver over the herdr CLI plus a
|
|
2
|
+
* self-registering `herdr` Runtime provider. Importing the package registers the provider
|
|
3
|
+
* with the core Registry (like a connector), so the manager can spawn agents into panes of
|
|
4
|
+
* a dedicated Herdr session without depending on this package. The driver itself stays
|
|
5
|
+
* mesh-free; launch scripts import `./driver.js` directly to avoid the registration
|
|
6
|
+
* side effect. */
|
|
7
|
+
export * as herdr from "./driver.js";
|
|
8
|
+
export { HerdrRuntime, herdrRuntimeProvider, privateLauncher } from "./runtime.js";
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;mBAKmB;AACnB,OAAO,KAAK,KAAK,MAAM,aAAa,CAAC;AAErC,OAAO,EAAE,YAAY,EAAE,oBAAoB,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/** @cotal-ai/herdr — the Herdr integration: a thin driver over the herdr CLI plus a
|
|
2
|
+
* self-registering `herdr` Runtime provider. Importing the package registers the provider
|
|
3
|
+
* with the core Registry (like a connector), so the manager can spawn agents into panes of
|
|
4
|
+
* a dedicated Herdr session without depending on this package. The driver itself stays
|
|
5
|
+
* mesh-free; launch scripts import `./driver.js` directly to avoid the registration
|
|
6
|
+
* side effect. */
|
|
7
|
+
export * as herdr from "./driver.js";
|
|
8
|
+
// importing registers the herdr runtime provider
|
|
9
|
+
export { HerdrRuntime, herdrRuntimeProvider, privateLauncher } from "./runtime.js";
|
|
10
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;mBAKmB;AACnB,OAAO,KAAK,KAAK,MAAM,aAAa,CAAC;AACrC,iDAAiD;AACjD,OAAO,EAAE,YAAY,EAAE,oBAAoB,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { type AgentHandle, type LaunchSpec, type Runtime, type RuntimeProvider } from "@cotal-ai/core";
|
|
2
|
+
export interface PrivateLauncher {
|
|
3
|
+
argv: string[];
|
|
4
|
+
dir: string;
|
|
5
|
+
script: string;
|
|
6
|
+
}
|
|
7
|
+
/** The connector-declared env (identity, creds, control token) must never appear on herdr's
|
|
8
|
+
* command line or in the server's pane records, so it rides an owner-only (0o600) launcher
|
|
9
|
+
* script in a private temp dir; herdr only ever sees `node <script>`. The script removes its
|
|
10
|
+
* own directory as soon as it has loaded. */
|
|
11
|
+
export declare function privateLauncher(spec: LaunchSpec, cwd: string): PrivateLauncher;
|
|
12
|
+
/**
|
|
13
|
+
* Spawns each managed agent into a pane of a DEDICATED named herdr session (`cotal-<space>`,
|
|
14
|
+
* from the manager) with its own server and socket — never the operator's default session, so
|
|
15
|
+
* no Cotal operation can inspect or kill unrelated panes. Panes are owned by the herdr server,
|
|
16
|
+
* so agents survive the manager's terminal going away; watch them with
|
|
17
|
+
* `herdr session attach <session>`. Lifecycle is keyed off the globally-unique `terminal_id`;
|
|
18
|
+
* the workspace-scoped public `pane_id` is re-resolved before every pane-scoped call (a pane
|
|
19
|
+
* move changes it) and never trusted from cache.
|
|
20
|
+
*/
|
|
21
|
+
export declare class HerdrRuntime implements Runtime {
|
|
22
|
+
private readonly session;
|
|
23
|
+
readonly kind: "herdr";
|
|
24
|
+
constructor(session: string);
|
|
25
|
+
spawn(name: string, spec: LaunchSpec, cwd: string): AgentHandle;
|
|
26
|
+
}
|
|
27
|
+
/** Self-registering runtime provider — `import "@cotal-ai/herdr"` makes the manager's `herdr`
|
|
28
|
+
* runtime available without the manager depending on this package. */
|
|
29
|
+
export declare const herdrRuntimeProvider: RuntimeProvider;
|
|
30
|
+
//# sourceMappingURL=runtime.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"AAGA,OAAO,EAIL,KAAK,WAAW,EAChB,KAAK,UAAU,EACf,KAAK,OAAO,EACZ,KAAK,eAAe,EACrB,MAAM,gBAAgB,CAAC;AAcxB,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;CAChB;AAiBD;;;8CAG8C;AAC9C,wBAAgB,eAAe,CAAC,IAAI,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM,GAAG,eAAe,CAS9E;AA6BD;;;;;;;;GAQG;AACH,qBAAa,YAAa,YAAW,OAAO;IAG9B,OAAO,CAAC,QAAQ,CAAC,OAAO;IAFpC,QAAQ,CAAC,IAAI,EAAG,OAAO,CAAU;gBAEJ,OAAO,EAAE,MAAM;IAE5C,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM,GAAG,WAAW;CAwIhE;AAED;uEACuE;AACvE,eAAO,MAAM,oBAAoB,EAAE,eAKlC,CAAC"}
|