@herdingchats/friday 0.1.651 → 0.1.660
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/herd.mjs +510 -492
- package/package.json +2 -2
- package/terminal-host.mjs +37 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@herdingchats/friday",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.660",
|
|
4
4
|
"description": "Friday, HerdingChats' agent daemon, and the herd command it runs agents with.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -22,5 +22,5 @@
|
|
|
22
22
|
"satori": "0.32.0",
|
|
23
23
|
"zod": "4.6.7"
|
|
24
24
|
},
|
|
25
|
-
"gitHead": "
|
|
25
|
+
"gitHead": "21101252ff98a4dc317139a36c286b347f5f5933"
|
|
26
26
|
}
|
package/terminal-host.mjs
CHANGED
|
@@ -58,6 +58,9 @@ var hostRequestSchema = z.discriminatedUnion("op", [
|
|
|
58
58
|
cols: z.number().int().min(10).max(1e3).optional(),
|
|
59
59
|
rows: z.number().int().min(5).max(1e3).optional()
|
|
60
60
|
}),
|
|
61
|
+
// Like `attach`, but output only: its input and resizes are ignored, and it never sizes the
|
|
62
|
+
// terminal, so watching from a small window reflows nothing for anyone else.
|
|
63
|
+
z.object({ op: z.literal("watch"), name: z.string() }),
|
|
61
64
|
z.object({ op: z.literal("kill"), name: z.string() })
|
|
62
65
|
]);
|
|
63
66
|
var viewerMessageSchema = z.discriminatedUnion("type", [
|
|
@@ -139,6 +142,8 @@ var TerminalHost = class {
|
|
|
139
142
|
serialize,
|
|
140
143
|
subscribers: /* @__PURE__ */ new Set(),
|
|
141
144
|
viewers: /* @__PURE__ */ new Set(),
|
|
145
|
+
watchers: /* @__PURE__ */ new Set(),
|
|
146
|
+
drivenAt: null,
|
|
142
147
|
typing: Promise.resolve()
|
|
143
148
|
};
|
|
144
149
|
pty.onData((data) => {
|
|
@@ -162,7 +167,9 @@ var TerminalHost = class {
|
|
|
162
167
|
list() {
|
|
163
168
|
return [...this.terminals.values()].map((held) => ({
|
|
164
169
|
...held.info,
|
|
165
|
-
viewers: held.viewers.size
|
|
170
|
+
viewers: held.viewers.size,
|
|
171
|
+
watchers: held.watchers.size,
|
|
172
|
+
drivenAt: held.viewers.size > 0 ? held.drivenAt : null
|
|
166
173
|
}));
|
|
167
174
|
}
|
|
168
175
|
get(name) {
|
|
@@ -249,6 +256,7 @@ var TerminalHost = class {
|
|
|
249
256
|
socket.write(`${JSON.stringify({ type: "snapshot", data: await this.snapshot(name) })}
|
|
250
257
|
`);
|
|
251
258
|
held.viewers.add(socket);
|
|
259
|
+
held.drivenAt = Date.now();
|
|
252
260
|
held.subscribers.add(socket);
|
|
253
261
|
let buffer = "";
|
|
254
262
|
socket.on("data", (chunk) => {
|
|
@@ -266,8 +274,10 @@ var TerminalHost = class {
|
|
|
266
274
|
}
|
|
267
275
|
const message = viewerMessageSchema.safeParse(parsed);
|
|
268
276
|
if (!message.success || held.info.exited) continue;
|
|
269
|
-
if (message.data.type === "input")
|
|
270
|
-
|
|
277
|
+
if (message.data.type === "input") {
|
|
278
|
+
held.drivenAt = Date.now();
|
|
279
|
+
held.pty.write(message.data.data);
|
|
280
|
+
} else this.resize(name, message.data.cols, message.data.rows);
|
|
271
281
|
}
|
|
272
282
|
});
|
|
273
283
|
socket.on("close", () => {
|
|
@@ -276,6 +286,25 @@ var TerminalHost = class {
|
|
|
276
286
|
if (held.viewers.size === 0) this.resize(name, DEFAULT_COLS, DEFAULT_ROWS);
|
|
277
287
|
});
|
|
278
288
|
}
|
|
289
|
+
/** Attaches a watcher: the current screen, then live output, and nothing it sends is taken. */
|
|
290
|
+
async watch(name, socket) {
|
|
291
|
+
const held = this.get(name);
|
|
292
|
+
if (held.info.exited) {
|
|
293
|
+
socket.end(`${JSON.stringify({ type: "exit", exitCode: held.info.exitCode })}
|
|
294
|
+
`);
|
|
295
|
+
return;
|
|
296
|
+
}
|
|
297
|
+
socket.write(`${JSON.stringify({ type: "snapshot", data: await this.snapshot(name) })}
|
|
298
|
+
`);
|
|
299
|
+
held.watchers.add(socket);
|
|
300
|
+
held.subscribers.add(socket);
|
|
301
|
+
socket.on("data", () => {
|
|
302
|
+
});
|
|
303
|
+
socket.on("close", () => {
|
|
304
|
+
held.watchers.delete(socket);
|
|
305
|
+
held.subscribers.delete(socket);
|
|
306
|
+
});
|
|
307
|
+
}
|
|
279
308
|
kill(name) {
|
|
280
309
|
const held = this.get(name);
|
|
281
310
|
if (!held.info.exited) held.pty.kill();
|
|
@@ -384,6 +413,11 @@ async function answer(served, request, socket) {
|
|
|
384
413
|
`);
|
|
385
414
|
await host.attach(request.name, socket, request);
|
|
386
415
|
return void 0;
|
|
416
|
+
case "watch":
|
|
417
|
+
socket.write(`${JSON.stringify({ ok: true })}
|
|
418
|
+
`);
|
|
419
|
+
await host.watch(request.name, socket);
|
|
420
|
+
return void 0;
|
|
387
421
|
case "kill":
|
|
388
422
|
host.kill(request.name);
|
|
389
423
|
return {};
|