@herdingchats/friday 0.1.688 → 0.1.701

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 CHANGED
@@ -18,7 +18,7 @@ var __export = (target, all) => {
18
18
  var define_HERD_PACKAGE_default;
19
19
  var init_define_HERD_PACKAGE = __esm({
20
20
  "<define:HERD_PACKAGE>"() {
21
- define_HERD_PACKAGE_default = { version: "0.1.688", gitHead: "a284c931b34fdaa76115c8d2c91da8b2903d19ff" };
21
+ define_HERD_PACKAGE_default = { version: "0.1.701", gitHead: "dee83b97beed4102f6d56d692f1c1e306b62dbb6" };
22
22
  }
23
23
  });
24
24
 
@@ -508,7 +508,13 @@ var init_terminals = __esm({
508
508
  rows: z6.number().int().min(5).max(1e3)
509
509
  };
510
510
  terminalFrameSchema = z6.discriminatedUnion("type", [
511
- z6.object({ type: z6.literal("snapshot"), data: z6.string() }),
511
+ // The screen, and its size, which a watcher draws it at. Hosts from before sizes don't say.
512
+ z6.object({
513
+ type: z6.literal("snapshot"),
514
+ data: z6.string(),
515
+ cols: size.cols.optional(),
516
+ rows: size.rows.optional()
517
+ }),
512
518
  z6.object({ type: z6.literal("data"), data: z6.string() }),
513
519
  z6.object({ type: z6.literal("exit"), exitCode: z6.number().int().nullable() }),
514
520
  z6.object({ type: z6.literal("mode"), mode: terminalModeSchema }),
@@ -1507,7 +1513,10 @@ var init_events = __esm({
1507
1513
  kind: z13.literal("bound"),
1508
1514
  machine: z13.object({ name: nonEmpty6, online: z13.boolean() }),
1509
1515
  // The worker's name, such as `mac-mini/claude`, and never its configuration or capabilities.
1510
- worker: nonEmpty6.optional()
1516
+ worker: nonEmpty6.optional(),
1517
+ // Only for the machine's owner, while it's online: what they may do with its terminal from
1518
+ // the web. Absent for anyone else, and where the machine allows nothing or can't.
1519
+ terminal: z13.enum(["drive", "watch"]).optional()
1511
1520
  }),
1512
1521
  z13.object({ kind: z13.literal("waiting_for_machine") }),
1513
1522
  z13.object({ kind: z13.literal("author_not_linked") })
@@ -5496,6 +5505,25 @@ var Activator = class {
5496
5505
  }
5497
5506
  this.request([{ name: agent, version }]);
5498
5507
  }
5508
+ /**
5509
+ * The terminal an agent's activation runs in, for its owner to sign in from the web. One that
5510
+ * isn't running is started, and its terminal named once it's open. Null if it didn't open.
5511
+ */
5512
+ async terminalFor(agent, version, { waitMs = 6e4, pollMs = 200 } = {}) {
5513
+ if (this.current?.agent !== agent) this.request([{ name: agent, version }], { force: true });
5514
+ const until = Date.now() + waitMs;
5515
+ while (Date.now() < until && !this.stopped) {
5516
+ const current = this.current;
5517
+ if (current?.agent === agent) {
5518
+ const open = (await this.options.terminals.list().catch(() => [])).some(
5519
+ (t) => t.name === current.terminal && !t.exited
5520
+ );
5521
+ if (open) return current.terminal;
5522
+ }
5523
+ await new Promise((resolve8) => setTimeout(resolve8, pollMs));
5524
+ }
5525
+ return null;
5526
+ }
5499
5527
  /** Resolves once nothing is queued or running, as tests wait for. */
5500
5528
  async settled() {
5501
5529
  while (this.running) await this.running;
@@ -5596,7 +5624,8 @@ var Activator = class {
5596
5624
  async waitForCheckIn(version, driver, current, folder, wasSignedOut) {
5597
5625
  const { terminals } = this.options;
5598
5626
  const { agent } = current;
5599
- const deadline = Date.now() + (this.options.deadlineMs ?? ACTIVATION_DEADLINE_MS);
5627
+ const deadlineMs = this.options.deadlineMs ?? ACTIVATION_DEADLINE_MS;
5628
+ let deadline = Date.now() + deadlineMs;
5600
5629
  const restartMs = this.options.signInRestartMs ?? SIGN_IN_RESTART_MS;
5601
5630
  const checkInMs = this.options.checkInMs ?? CHECK_IN_MS;
5602
5631
  const pollMs = this.options.pollMs ?? ACTIVATION_POLL_MS;
@@ -5632,6 +5661,8 @@ var Activator = class {
5632
5661
  };
5633
5662
  await start();
5634
5663
  while (!current.checkedIn && Date.now() < deadline && !this.stopped) {
5664
+ const lookers = lookingAt((await terminals.list()).find((t) => t.name === current.terminal));
5665
+ if (lookers > 0) deadline = Math.max(deadline, Date.now() + deadlineMs);
5635
5666
  const reading = await driver.read(current.terminal).catch(() => null);
5636
5667
  if (reading?.state === "signed_out" && Date.now() - startedAt >= checkInMs) {
5637
5668
  seen = "signed_out";
@@ -11068,9 +11099,13 @@ var Session = class {
11068
11099
  });
11069
11100
  }
11070
11101
  fromHost(message) {
11071
- if (message.type === "snapshot") {
11102
+ const size2 = typeof message.cols === "number" && typeof message.rows === "number" ? { cols: message.cols, rows: message.rows } : null;
11103
+ if (message.type === "resize" && size2) {
11104
+ this.flush();
11105
+ this.send({ type: "resize", ...size2 });
11106
+ } else if (message.type === "snapshot") {
11072
11107
  this.pending = "";
11073
- this.send({ type: "snapshot", data: message.data ?? "" });
11108
+ this.send({ type: "snapshot", data: message.data ?? "", ...size2 ?? {} });
11074
11109
  } else if (message.type === "data") {
11075
11110
  if (this.behind) return;
11076
11111
  this.pending += message.data ?? "";
@@ -14254,8 +14289,12 @@ async function runDaemon(args) {
14254
14289
  }),
14255
14290
  access: () => daemon?.configuration().config?.terminals?.remote ?? "drive",
14256
14291
  resolve: async (target) => {
14257
- if (target.kind !== "conversation") {
14258
- return { refused: "This machine can't open an agent's sign-in terminal from the web yet." };
14292
+ if (target.kind === "activation") {
14293
+ const cli = clis.find((candidate) => candidate.name === target.agent);
14294
+ if (!cli || !activator) return { refused: "This machine doesn't run that agent." };
14295
+ const terminal = await activator.terminalFor(cli.name, cli.version);
14296
+ if (!terminal) return { refused: "The agent's sign-in didn't start on this machine." };
14297
+ return { terminal, socketPath: await terminals.pathOf(terminal) };
14259
14298
  }
14260
14299
  const workspace = workspaces.get(target.conversationId);
14261
14300
  if (!workspace) return { refused: "This machine doesn't hold that conversation." };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@herdingchats/friday",
3
- "version": "0.1.688",
3
+ "version": "0.1.701",
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": "a284c931b34fdaa76115c8d2c91da8b2903d19ff"
25
+ "gitHead": "dee83b97beed4102f6d56d692f1c1e306b62dbb6"
26
26
  }
package/terminal-host.mjs CHANGED
@@ -230,6 +230,16 @@ var TerminalHost = class {
230
230
  if (held.info.exited) return;
231
231
  held.pty.resize(cols, rows);
232
232
  held.term.resize(cols, rows);
233
+ for (const socket of held.watchers) {
234
+ socket.write(`${JSON.stringify({ type: "resize", cols, rows })}
235
+ `);
236
+ }
237
+ }
238
+ /** The screen as `attach` and `watch` send it first: its contents, and its size. */
239
+ async sized(name) {
240
+ const held = this.get(name);
241
+ const data = await this.snapshot(name);
242
+ return { type: "snapshot", data, cols: held.term.cols, rows: held.term.rows };
233
243
  }
234
244
  subscribe(name, socket) {
235
245
  const held = this.get(name);
@@ -253,7 +263,7 @@ var TerminalHost = class {
253
263
  return;
254
264
  }
255
265
  if (size.cols && size.rows) this.resize(name, size.cols, size.rows);
256
- socket.write(`${JSON.stringify({ type: "snapshot", data: await this.snapshot(name) })}
266
+ socket.write(`${JSON.stringify(await this.sized(name))}
257
267
  `);
258
268
  held.viewers.add(socket);
259
269
  held.drivenAt = Date.now();
@@ -294,7 +304,7 @@ var TerminalHost = class {
294
304
  `);
295
305
  return;
296
306
  }
297
- socket.write(`${JSON.stringify({ type: "snapshot", data: await this.snapshot(name) })}
307
+ socket.write(`${JSON.stringify(await this.sized(name))}
298
308
  `);
299
309
  held.watchers.add(socket);
300
310
  held.subscribers.add(socket);