@herdingchats/friday 0.1.653 → 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.
Files changed (3) hide show
  1. package/herd.mjs +510 -492
  2. package/package.json +2 -2
  3. 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.653",
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": "66b195d50009a6d5e3e3f7c256873c5b63fb1271"
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") held.pty.write(message.data.data);
270
- else this.resize(name, message.data.cols, message.data.rows);
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 {};