@herdingchats/friday 0.1.600 → 0.1.609

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 (2) hide show
  1. package/herd.mjs +162 -81
  2. package/package.json +2 -2
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.600", gitHead: "258e3577331c639de77e7ab7f0cdccc48b275a89" };
21
+ define_HERD_PACKAGE_default = { version: "0.1.609", gitHead: "cfba1790271c8df777ce206f2e53c6b987e94520" };
22
22
  }
23
23
  });
24
24
 
@@ -3205,7 +3205,7 @@ import { fileURLToPath as fileURLToPath3 } from "node:url";
3205
3205
  // src/friday/main.ts
3206
3206
  init_define_HERD_PACKAGE();
3207
3207
  init_src();
3208
- import { spawn as spawn6 } from "node:child_process";
3208
+ import { spawn as spawn7 } from "node:child_process";
3209
3209
  import { existsSync as existsSync11, readFileSync as readFileSync10 } from "node:fs";
3210
3210
  import { homedir as homedir4 } from "node:os";
3211
3211
  import { dirname as dirname10, join as join14 } from "node:path";
@@ -3438,7 +3438,7 @@ var HERD_FLAGS = {
3438
3438
  persona: []
3439
3439
  };
3440
3440
  var FRIDAY_FLAGS = {
3441
- start: ["--agents", "--config"],
3441
+ start: ["--agents", "--config", "--verbose"],
3442
3442
  stop: [],
3443
3443
  status: [],
3444
3444
  logs: ["--follow", "-f", "-n"]
@@ -3517,17 +3517,64 @@ async function runLogout() {
3517
3517
 
3518
3518
  // src/config.ts
3519
3519
  init_define_HERD_PACKAGE();
3520
- import { execFileSync as execFileSync3 } from "node:child_process";
3520
+ import { execFileSync as execFileSync4 } from "node:child_process";
3521
3521
  import { randomUUID } from "node:crypto";
3522
3522
  import { existsSync as existsSync3, mkdirSync as mkdirSync4, readFileSync as readFileSync4, realpathSync as realpathSync2, writeFileSync as writeFileSync3 } from "node:fs";
3523
3523
  import { homedir as homedir3, hostname } from "node:os";
3524
3524
  import { basename, dirname as dirname4, join as join6, resolve } from "node:path";
3525
3525
  import { z as z18 } from "zod";
3526
3526
 
3527
+ // src/login-shell.ts
3528
+ init_define_HERD_PACKAGE();
3529
+ import { execFileSync, spawn as spawn2 } from "node:child_process";
3530
+ var AWAY_FROM_TERMINAL = { detached: true, killSignal: "SIGKILL" };
3531
+ function verbose(line2) {
3532
+ if (process.env.HERD_VERBOSE) process.stderr.write(`[friday] ${line2}
3533
+ `);
3534
+ }
3535
+ function loginShellSync(shell, args, { env, timeoutMs }) {
3536
+ verbose(`running ${shell} ${args.join(" ")}, detached from the terminal`);
3537
+ try {
3538
+ return execFileSync(shell, args, {
3539
+ encoding: "utf8",
3540
+ stdio: ["ignore", "pipe", "ignore"],
3541
+ env,
3542
+ timeout: timeoutMs,
3543
+ ...AWAY_FROM_TERMINAL
3544
+ });
3545
+ } catch (error) {
3546
+ verbose(`${shell} ${args.join(" ")} failed: ${error.message.split("\n")[0]}`);
3547
+ return null;
3548
+ }
3549
+ }
3550
+ function loginShell(shell, args, { env, timeoutMs }) {
3551
+ verbose(`running ${shell} ${args.join(" ")}, detached from the terminal`);
3552
+ return new Promise((resolve7) => {
3553
+ let output2 = "";
3554
+ let child;
3555
+ try {
3556
+ child = spawn2(shell, args, { env, stdio: ["ignore", "pipe", "ignore"], detached: true });
3557
+ } catch {
3558
+ resolve7("");
3559
+ return;
3560
+ }
3561
+ const timer = setTimeout(() => child.kill("SIGKILL"), timeoutMs);
3562
+ child.stdout?.on("data", (chunk) => {
3563
+ output2 += chunk.toString("utf8");
3564
+ });
3565
+ const done = () => {
3566
+ clearTimeout(timer);
3567
+ resolve7(output2);
3568
+ };
3569
+ child.on("error", done);
3570
+ child.on("close", done);
3571
+ });
3572
+ }
3573
+
3527
3574
  // src/machine-facts.ts
3528
3575
  init_define_HERD_PACKAGE();
3529
3576
  init_src();
3530
- import { execFileSync } from "node:child_process";
3577
+ import { execFileSync as execFileSync2 } from "node:child_process";
3531
3578
  import { createHash as createHash2 } from "node:crypto";
3532
3579
  import { readFileSync as readFileSync2, rmSync as rmSync2, statSync as statSync2, writeFileSync as writeFileSync2 } from "node:fs";
3533
3580
  import { dirname, join as join3 } from "node:path";
@@ -3709,7 +3756,7 @@ var USAGE_TAIL_BYTES = 256 * 1024;
3709
3756
  function latestCodexUsage(home = codexHome()) {
3710
3757
  const newest = newestRollout(join2(home, "sessions"));
3711
3758
  if (!newest) return null;
3712
- let tail2;
3759
+ let tail3;
3713
3760
  try {
3714
3761
  const size = statSync(newest).size;
3715
3762
  const start = Math.max(0, size - USAGE_TAIL_BYTES);
@@ -3720,11 +3767,11 @@ function latestCodexUsage(home = codexHome()) {
3720
3767
  } finally {
3721
3768
  closeSync(fd);
3722
3769
  }
3723
- tail2 = buffer.toString("utf8");
3770
+ tail3 = buffer.toString("utf8");
3724
3771
  } catch {
3725
3772
  return null;
3726
3773
  }
3727
- const lines = tail2.split("\n");
3774
+ const lines = tail3.split("\n");
3728
3775
  for (let index = lines.length - 1; index >= 0; index -= 1) {
3729
3776
  const line2 = lines[index];
3730
3777
  const event2 = parseRecord(line2);
@@ -3770,7 +3817,7 @@ function chosenClis(clis, config) {
3770
3817
  }
3771
3818
  var runCommand = (command, args) => {
3772
3819
  try {
3773
- return execFileSync(command, args, {
3820
+ return execFileSync2(command, args, {
3774
3821
  encoding: "utf8",
3775
3822
  stdio: ["ignore", "pipe", "ignore"],
3776
3823
  timeout: 1e4
@@ -3825,7 +3872,7 @@ async function loadHerdConfig(path = herdConfigPath()) {
3825
3872
  // src/repo-store.ts
3826
3873
  init_define_HERD_PACKAGE();
3827
3874
  init_src();
3828
- import { execFile, execFileSync as execFileSync2 } from "node:child_process";
3875
+ import { execFile, execFileSync as execFileSync3 } from "node:child_process";
3829
3876
  import { randomBytes as randomBytes2 } from "node:crypto";
3830
3877
  import {
3831
3878
  existsSync as existsSync2,
@@ -3843,7 +3890,7 @@ import { promisify } from "node:util";
3843
3890
 
3844
3891
  // src/local-files.ts
3845
3892
  init_define_HERD_PACKAGE();
3846
- import { spawn as spawn2 } from "node:child_process";
3893
+ import { spawn as spawn3 } from "node:child_process";
3847
3894
  import { constants, copyFileSync, existsSync, lstatSync, mkdirSync as mkdirSync2 } from "node:fs";
3848
3895
  import { dirname as dirname2, join as join4 } from "node:path";
3849
3896
  var INCLUDE_FILE = ".worktreeinclude";
@@ -3861,7 +3908,7 @@ var HEAVY_FOLDERS = /* @__PURE__ */ new Set([
3861
3908
  var MAX_COPIED = 500;
3862
3909
  function gitOut(env, cwd, args, input = "") {
3863
3910
  return new Promise((resolve7) => {
3864
- const child = spawn2("git", ["-C", cwd, ...args], {
3911
+ const child = spawn3("git", ["-C", cwd, ...args], {
3865
3912
  env: { ...env ?? process.env, GIT_TERMINAL_PROMPT: "0" },
3866
3913
  stdio: ["pipe", "pipe", "ignore"]
3867
3914
  });
@@ -3872,6 +3919,8 @@ function gitOut(env, cwd, args, input = "") {
3872
3919
  });
3873
3920
  child.on("error", () => resolve7(""));
3874
3921
  child.on("close", () => resolve7(out));
3922
+ child.stdin.on("error", () => {
3923
+ });
3875
3924
  child.stdin.end(input);
3876
3925
  });
3877
3926
  }
@@ -3936,7 +3985,7 @@ async function git(env, cwd, ...args) {
3936
3985
  throw new StoreError(gitError(error));
3937
3986
  }
3938
3987
  }
3939
- var gitSync = (cwd, ...args) => execFileSync2("git", ["-C", cwd, ...args], {
3988
+ var gitSync = (cwd, ...args) => execFileSync3("git", ["-C", cwd, ...args], {
3940
3989
  encoding: "utf8",
3941
3990
  stdio: ["ignore", "pipe", "pipe"],
3942
3991
  env: quiet(void 0)
@@ -4289,7 +4338,7 @@ function workTreeOf(folder) {
4289
4338
  let dir = resolve(folder);
4290
4339
  while (!existsSync3(dir) && dirname4(dir) !== dir) dir = dirname4(dir);
4291
4340
  try {
4292
- const top = execFileSync3("git", ["-C", dir, "rev-parse", "--show-toplevel"], {
4341
+ const top = execFileSync4("git", ["-C", dir, "rev-parse", "--show-toplevel"], {
4293
4342
  encoding: "utf8",
4294
4343
  stdio: ["ignore", "pipe", "ignore"]
4295
4344
  }).trim();
@@ -4318,7 +4367,7 @@ function convosHome(root = machineRoot()) {
4318
4367
  var chooseConvos = (root, preferred, inWorkTree) => inWorkTree(preferred) ? join6(root, ".friday_convos") : preferred;
4319
4368
  function describeRepo(path) {
4320
4369
  const full = resolve(path);
4321
- const git4 = (...args) => execFileSync3("git", ["-C", full, ...args], {
4370
+ const git4 = (...args) => execFileSync4("git", ["-C", full, ...args], {
4322
4371
  encoding: "utf8",
4323
4372
  stdio: ["ignore", "pipe", "pipe"]
4324
4373
  }).trim();
@@ -4391,7 +4440,7 @@ function describeCli(name, version) {
4391
4440
  function findClis() {
4392
4441
  let version;
4393
4442
  try {
4394
- const output2 = execFileSync3("claude", ["--version"], {
4443
+ const output2 = execFileSync4("claude", ["--version"], {
4395
4444
  encoding: "utf8",
4396
4445
  stdio: ["ignore", "pipe", "ignore"],
4397
4446
  env: terminalEnv({}),
@@ -4430,16 +4479,7 @@ function findVersion(command, pattern, run4, shell) {
4430
4479
  return pattern.exec(output2)?.[1] ?? null;
4431
4480
  }
4432
4481
  function runQuietly(command, args) {
4433
- try {
4434
- return execFileSync3(command, args, {
4435
- encoding: "utf8",
4436
- stdio: ["ignore", "pipe", "ignore"],
4437
- env: terminalEnv({}),
4438
- timeout: 15e3
4439
- });
4440
- } catch {
4441
- return null;
4442
- }
4482
+ return loginShellSync(command, args, { env: terminalEnv({}), timeoutMs: 15e3 });
4443
4483
  }
4444
4484
  function terminalEnv(extra) {
4445
4485
  const env = {};
@@ -5529,7 +5569,7 @@ function pickInTerminal(choices, input = process.stdin, output2 = process.stdout
5529
5569
 
5530
5570
  // src/friday/service.ts
5531
5571
  init_define_HERD_PACKAGE();
5532
- import { spawn as spawn3 } from "node:child_process";
5572
+ import { spawn as spawn4 } from "node:child_process";
5533
5573
  import { existsSync as existsSync7, mkdirSync as mkdirSync8, openSync as openSync3, readFileSync as readFileSync7, rmSync as rmSync7, writeFileSync as writeFileSync7 } from "node:fs";
5534
5574
  import { userInfo } from "node:os";
5535
5575
  import { dirname as dirname8, join as join10, win32 } from "node:path";
@@ -5679,7 +5719,7 @@ function spawnInBackground(command, env, log) {
5679
5719
  mkdirSync8(dirname8(log), { recursive: true });
5680
5720
  const out = openSync3(log, "a");
5681
5721
  const [program = process.execPath, ...args] = command;
5682
- spawn3(program, args, {
5722
+ spawn4(program, args, {
5683
5723
  detached: true,
5684
5724
  // On Windows, a detached process otherwise opens a console window of its own.
5685
5725
  windowsHide: true,
@@ -5771,9 +5811,35 @@ async function retireOldDaemon(paths, { home, run: run4 }) {
5771
5811
  return removed;
5772
5812
  }
5773
5813
 
5814
+ // src/friday/verbose.ts
5815
+ init_define_HERD_PACKAGE();
5816
+ var VERBOSE_ENV = "HERD_VERBOSE";
5817
+ var began = Date.now();
5818
+ function verbose2(line2) {
5819
+ if (!process.env[VERBOSE_ENV]) return;
5820
+ const seconds = ((Date.now() - began) / 1e3).toFixed(1);
5821
+ process.stderr.write(`[friday +${seconds}s] ${line2}
5822
+ `);
5823
+ }
5824
+ var tail = (text4) => text4.trim().split("\n").slice(-3).join(" | ");
5825
+ function verboseExec(run4) {
5826
+ return async (command, args, options) => {
5827
+ if (!process.env[VERBOSE_ENV]) return run4(command, args, options);
5828
+ const shown = [command, ...args].join(" ");
5829
+ verbose2(`running ${shown}`);
5830
+ const started = Date.now();
5831
+ const ran = await run4(command, args, options);
5832
+ const took = `${Date.now() - started}ms`;
5833
+ verbose2(
5834
+ ran.status === 0 ? `ran ${shown} (${took})` : `${shown} exited ${ran.status} (${took})${ran.stderr.trim() ? `: ${tail(ran.stderr)}` : ""}`
5835
+ );
5836
+ return ran;
5837
+ };
5838
+ }
5839
+
5774
5840
  // src/friday/versions.ts
5775
5841
  init_define_HERD_PACKAGE();
5776
- import { spawn as spawn4 } from "node:child_process";
5842
+ import { spawn as spawn5 } from "node:child_process";
5777
5843
  import {
5778
5844
  existsSync as existsSync9,
5779
5845
  mkdirSync as mkdirSync9,
@@ -5790,7 +5856,7 @@ import { basename as basename2, dirname as dirname9, join as join12 } from "node
5790
5856
  var exec = (command, args, options = {}) => new Promise((resolve7) => {
5791
5857
  let stdout = "";
5792
5858
  let stderr = "";
5793
- const child = spawn4(command, args, {
5859
+ const child = spawn5(command, args, {
5794
5860
  cwd: options.cwd,
5795
5861
  env: options.env ?? process.env,
5796
5862
  stdio: ["ignore", "pipe", "pipe"]
@@ -5991,6 +6057,9 @@ async function runStart(options) {
5991
6057
  const existing = readRoot2(paths);
5992
6058
  const wanted = chooseRoot(options.cwd, options.home);
5993
6059
  const running = runningSupervisor(paths);
6060
+ verbose2(
6061
+ `root is ${existing ?? "not set"}, this folder makes it ${wanted}, ${running ? `supervisor running at version ${running.version}` : "no supervisor running"}, service ${options.serviceKind}`
6062
+ );
5994
6063
  let moving = false;
5995
6064
  if (existing && real(existing) !== real(wanted)) {
5996
6065
  print(`This machine's root is ${existing}, which holds the repos Friday works on.`);
@@ -6024,6 +6093,7 @@ async function runStart(options) {
6024
6093
  );
6025
6094
  }
6026
6095
  if ((options.platform ?? process.platform) === "linux") {
6096
+ verbose2("checking the build tools node-pty needs");
6027
6097
  const missing = await missingBuildTools(run4);
6028
6098
  if (missing.length > 0) {
6029
6099
  throw new StartError(
@@ -6034,8 +6104,10 @@ async function runStart(options) {
6034
6104
  if (!options.signedIn()) {
6035
6105
  print("Signing in through your browser.");
6036
6106
  await options.signIn();
6037
- }
6107
+ verbose2("signed in");
6108
+ } else verbose2("already signed in");
6038
6109
  const asked = await chooseAndAsk(options, print);
6110
+ verbose2("looking for a daemon set up the old way");
6039
6111
  const retired = await retireOldDaemon(paths, { home: options.home, run: run4 });
6040
6112
  if (retired.length > 0)
6041
6113
  print(
@@ -6052,7 +6124,9 @@ async function runStart(options) {
6052
6124
  }
6053
6125
  mkdirSync10(root, { recursive: true });
6054
6126
  writeRoot(paths, root);
6127
+ verbose2(`installing the ${service.kind} service`);
6055
6128
  const changed = await service.install();
6129
+ verbose2(`${changed ? "service changed" : "service unchanged"}, starting it`);
6056
6130
  await service.start(changed || moving);
6057
6131
  print(
6058
6132
  `Friday is running from ${root}, version ${currentVersion(paths)}, ${service.kind === "launchd" ? "and starts whenever you log in" : service.kind === "systemd" ? "and starts whenever you log in, as a systemd user service" : "in the background"}.`
@@ -6077,13 +6151,18 @@ async function stopped(options) {
6077
6151
  }
6078
6152
  async function chooseAndAsk(options, print) {
6079
6153
  if (!options.agents) return null;
6154
+ verbose2(
6155
+ options.agents.ask ? "asking which agents this machine runs" : "reading the saved agents"
6156
+ );
6080
6157
  const chosen = await chooseAgents(options.agents, print);
6158
+ verbose2(`agents: ${chosen ? chosen.join(", ") || "none" : "unchanged"}`);
6081
6159
  if (!chosen) return null;
6082
6160
  if (!options.agents.ask && !options.agents.given) return null;
6083
6161
  return { chosen, since: askToActivate(options.paths.herdHome) };
6084
6162
  }
6085
6163
  async function waitForAgents(options, asked, print) {
6086
6164
  if (!options.agents || !asked || asked.chosen.length === 0) return;
6165
+ verbose2(`waiting for ${asked.chosen.join(", ")} to activate`);
6087
6166
  await awaitActivations(
6088
6167
  { ...options.agents, herdHome: options.paths.herdHome },
6089
6168
  asked.chosen,
@@ -6095,6 +6174,7 @@ var machineDone = (status2) => !status2.steps.some((step) => step.id === "machin
6095
6174
  async function printSetup(options, print, { waitForMachine = false } = {}) {
6096
6175
  const read = options.setup;
6097
6176
  if (!read) return;
6177
+ verbose2("reading the setup checklist");
6098
6178
  const pollMs = options.setupPollMs ?? SETUP_POLL_MS;
6099
6179
  const deadline = Date.now() + (waitForMachine ? options.setupWaitMs ?? SETUP_WAIT_MS : 0);
6100
6180
  let last = null;
@@ -6121,6 +6201,7 @@ function defaultService(options) {
6121
6201
  async function ensureInstalled(options, print) {
6122
6202
  const { paths, version } = options;
6123
6203
  const current = currentVersion(paths);
6204
+ verbose2(`installed version is ${current ?? "none"}`);
6124
6205
  if (current && !await versionRuns(paths.current, current, options.run)) return;
6125
6206
  if (version === "dev" && !options.install?.spec) {
6126
6207
  throw new StartError(
@@ -6137,7 +6218,7 @@ async function ensureInstalled(options, print) {
6137
6218
  // src/friday/supervisor.ts
6138
6219
  init_define_HERD_PACKAGE();
6139
6220
  init_src();
6140
- import { spawn as spawn5 } from "node:child_process";
6221
+ import { spawn as spawn6 } from "node:child_process";
6141
6222
  import {
6142
6223
  closeSync as closeSync3,
6143
6224
  existsSync as existsSync10,
@@ -6232,7 +6313,7 @@ var Supervisor = class {
6232
6313
  const out = openSync4(daemonLog, "a");
6233
6314
  const [program = process.execPath, ...args] = this.daemonCommand();
6234
6315
  const startedAt = Date.now();
6235
- const child = spawn5(program, args, { stdio: ["ignore", out, out], env: process.env });
6316
+ const child = spawn6(program, args, { stdio: ["ignore", out, out], env: process.env });
6236
6317
  closeSync3(out);
6237
6318
  this.daemon = child;
6238
6319
  this.status.daemonPid = child.pid ?? null;
@@ -6370,7 +6451,7 @@ Usage: ${FRIDAY_COMMAND} <command>
6370
6451
  again. Run in another folder, it offers to move the root there. --config asks
6371
6452
  about the agents again, and --agents claude=lot,codex=little sets their shares
6372
6453
  without asking: off, little, some or lot, where a bare name is some and one
6373
- left out off
6454
+ left out off. --verbose says each step and command on stderr as it goes
6374
6455
  stop Stop the daemon until you log in again, or run start again
6375
6456
  status Whether the daemon is running, which version, and its root
6376
6457
  logs [-f] Show the daemon's latest log lines. -f keeps following them
@@ -6430,16 +6511,20 @@ async function friday(args, deps = defaults()) {
6430
6511
  deps.print(HERD_VERSION);
6431
6512
  return 0;
6432
6513
  case "start": {
6514
+ if (rest.includes("--verbose")) process.env[VERBOSE_ENV] = "1";
6433
6515
  const given = agentsFlag(rest);
6516
+ verbose2(
6517
+ `friday ${HERD_VERSION} on Node ${process.version}, ${process.platform}, in ${deps.cwd}, with ${process.stdin.isTTY && process.stdout.isTTY ? "a terminal" : "no terminal"}`
6518
+ );
6434
6519
  return await runStart({
6435
6520
  paths: deps.paths,
6436
6521
  cwd: deps.cwd,
6437
6522
  home: deps.home,
6438
6523
  version: HERD_VERSION,
6439
- run: deps.run,
6524
+ run: verboseExec(deps.run),
6440
6525
  signedIn: () => isLocal(apiUrl()) || readCredentials() !== null,
6441
6526
  signIn: () => login(openBrowser),
6442
- serviceKind: deps.serviceKind ?? await detectService(deps.run),
6527
+ serviceKind: deps.serviceKind ?? await detectService(verboseExec(deps.run)),
6443
6528
  env: passedEnv(),
6444
6529
  print: deps.print,
6445
6530
  setup: fetchSetup,
@@ -6449,7 +6534,12 @@ async function friday(args, deps = defaults()) {
6449
6534
  // The choice lives in herd.config.ts, so it's asked for only before there is one, or
6450
6535
  // with --config.
6451
6536
  ask: rest.includes("--config") || !existsSync11(herdConfigIn(deps.paths.herdHome)),
6452
- installed: async () => installedAgents(),
6537
+ installed: async () => {
6538
+ verbose2("looking for installed agents");
6539
+ const found = installedAgents();
6540
+ verbose2(`found ${found.length > 0 ? found.join(", ") : "no agents"}`);
6541
+ return found;
6542
+ },
6453
6543
  load: () => loadHerdConfig(herdConfigIn(deps.paths.herdHome)),
6454
6544
  configPath: herdConfigIn(deps.paths.herdHome),
6455
6545
  pick: (choices) => pickInTerminal(choices),
@@ -6503,7 +6593,7 @@ function agentsFlag(args) {
6503
6593
  }
6504
6594
  function attachTo(paths, terminal) {
6505
6595
  const herd = existsSync11(binOf(paths.current, "herd")) ? binOf(paths.current, "herd") : join14(dirname10(process.argv[1] ?? ""), "herd.mjs");
6506
- const child = spawn6(process.execPath, [herd, "attach", terminal], {
6596
+ const child = spawn7(process.execPath, [herd, "attach", terminal], {
6507
6597
  stdio: "inherit",
6508
6598
  env: { ...process.env, HERD_HOME: paths.herdHome }
6509
6599
  });
@@ -6572,7 +6662,7 @@ function readMissingFolder(herdHome2) {
6572
6662
  return null;
6573
6663
  }
6574
6664
  }
6575
- function tail(path, count) {
6665
+ function tail2(path, count) {
6576
6666
  if (!existsSync11(path)) return [];
6577
6667
  const lines = readFileSync10(path, "utf8").split("\n");
6578
6668
  if (lines.at(-1) === "") lines.pop();
@@ -6587,12 +6677,12 @@ async function runLogs(args, deps) {
6587
6677
  return 0;
6588
6678
  }
6589
6679
  if (follow) {
6590
- const child = spawn6("tail", ["-n", "50", "-F", ...files], { stdio: "inherit" });
6680
+ const child = spawn7("tail", ["-n", "50", "-F", ...files], { stdio: "inherit" });
6591
6681
  return await new Promise((resolve7) => child.on("close", (code) => resolve7(code ?? 0)));
6592
6682
  }
6593
6683
  for (const file of files) {
6594
6684
  print(`==> ${file} <==`);
6595
- for (const line2 of tail(file, 50)) print(line2);
6685
+ for (const line2 of tail2(file, 50)) print(line2);
6596
6686
  }
6597
6687
  return 0;
6598
6688
  }
@@ -6629,7 +6719,7 @@ init_define_HERD_PACKAGE();
6629
6719
 
6630
6720
  // src/build-sandbox.ts
6631
6721
  init_define_HERD_PACKAGE();
6632
- import { spawn as spawn7 } from "node:child_process";
6722
+ import { spawn as spawn8 } from "node:child_process";
6633
6723
  import { appendFileSync, readFileSync as readFileSync11 } from "node:fs";
6634
6724
  import { dirname as dirname11, join as join15 } from "node:path";
6635
6725
  var DEPLOY_HOSTS = ["api.cloudflare.com", "api.github.com", "registry.npmjs.org"];
@@ -6691,7 +6781,7 @@ async function runSandboxed(args) {
6691
6781
  }
6692
6782
  });
6693
6783
  const wrapped = await SandboxManager.wrapWithSandbox(shellQuote(command));
6694
- const child = spawn7(wrapped, { shell: true, stdio: "inherit" });
6784
+ const child = spawn8(wrapped, { shell: true, stdio: "inherit" });
6695
6785
  const forward = (signal2) => () => child.kill(signal2);
6696
6786
  process.once("SIGTERM", forward("SIGTERM"));
6697
6787
  process.once("SIGINT", forward("SIGINT"));
@@ -8367,7 +8457,7 @@ var BuildConnection = class {
8367
8457
 
8368
8458
  // src/builds.ts
8369
8459
  init_define_HERD_PACKAGE();
8370
- import { execFile as execFile2, execFileSync as execFileSync4, spawn as spawn8 } from "node:child_process";
8460
+ import { execFile as execFile2, execFileSync as execFileSync5, spawn as spawn9 } from "node:child_process";
8371
8461
  import { createHash as createHash3, randomUUID as randomUUID4 } from "node:crypto";
8372
8462
  import {
8373
8463
  existsSync as existsSync15,
@@ -8444,7 +8534,7 @@ function readSandboxStatus() {
8444
8534
  }
8445
8535
  var HERD_BIN = herdBin;
8446
8536
  var insideBuildSandbox = (env = process.env) => env.SANDBOX_RUNTIME === "1" && Boolean(env.HERD_BUILD_ID);
8447
- var git2 = (cwd, ...args) => execFileSync4("git", args, { cwd, stdio: ["ignore", "pipe", "pipe"] }).toString().trim();
8537
+ var git2 = (cwd, ...args) => execFileSync5("git", args, { cwd, stdio: ["ignore", "pipe", "pipe"] }).toString().trim();
8448
8538
  var run2 = promisify2(execFile2);
8449
8539
  async function storeGit(env, store, ...args) {
8450
8540
  try {
@@ -8473,7 +8563,7 @@ function worktreeOf(dir, store) {
8473
8563
  }
8474
8564
  function cloneFolder(from, to) {
8475
8565
  const args = process.platform === "darwin" ? ["-c", "-R"] : ["-R", "--reflink=auto"];
8476
- execFileSync4("cp", [...args, from, to]);
8566
+ execFileSync5("cp", [...args, from, to]);
8477
8567
  }
8478
8568
  function moduleFolders(dir) {
8479
8569
  const found = existsSync15(join22(dir, "node_modules")) ? ["node_modules"] : [];
@@ -8492,7 +8582,7 @@ function lockHash(dir) {
8492
8582
  }
8493
8583
  var npmCi = (dir) => new Promise((resolve7, reject) => {
8494
8584
  const network = insideBuildSandbox() ? ["--offline"] : ["--prefer-offline"];
8495
- const child = spawn8(
8585
+ const child = spawn9(
8496
8586
  "npm",
8497
8587
  ["ci", ...network, "--no-audit", "--no-fund", "--no-update-notifier"],
8498
8588
  {
@@ -8599,7 +8689,7 @@ var BuildRunner = class _BuildRunner {
8599
8689
  writeFileSync13(join22(staging, ".complete"), folders.join("\n"));
8600
8690
  mkdirSync17(join22(this.home(), "node_modules"), { recursive: true });
8601
8691
  rmSync13(cache, { recursive: true, force: true });
8602
- execFileSync4("mv", [staging, cache]);
8692
+ execFileSync5("mv", [staging, cache]);
8603
8693
  }
8604
8694
  mkdirSync17(join22(dir, "node_modules"), { recursive: true });
8605
8695
  writeFileSync13(marker, wanted);
@@ -8670,7 +8760,7 @@ var BuildRunner = class _BuildRunner {
8670
8760
  env.HERD_BUILD_SANDBOX = insideBuildSandbox() ? "Inside the sandbox of the build that started this one." : "";
8671
8761
  }
8672
8762
  const [executable, ...args] = command;
8673
- const child = spawn8(executable, args, { cwd: dir, env, stdio: "ignore", detached: true });
8763
+ const child = spawn9(executable, args, { cwd: dir, env, stdio: "ignore", detached: true });
8674
8764
  const done = new Promise((resolve7) => {
8675
8765
  child.on("error", () => resolve7(1));
8676
8766
  child.on("close", (code) => resolve7(code ?? 1));
@@ -8749,7 +8839,7 @@ var BuildRunner = class _BuildRunner {
8749
8839
  `try { fs.readFileSync(${JSON.stringify(secret)}); process.exit(10); } catch {}`,
8750
8840
  `fs.writeFileSync(${JSON.stringify(join22(dir, "home", "ok"))}, "ok");`
8751
8841
  ].join(" ");
8752
- const child = spawn8(
8842
+ const child = spawn9(
8753
8843
  process.execPath,
8754
8844
  [HERD_BIN, "build-sandbox", policyPath, "--", process.execPath, "-e", script],
8755
8845
  {
@@ -8820,7 +8910,7 @@ function listFromProc() {
8820
8910
  function listFromPs() {
8821
8911
  let listing = "";
8822
8912
  try {
8823
- listing = execFileSync4("ps", ["-axwwE", "-o", "pid=,command="], {
8913
+ listing = execFileSync5("ps", ["-axwwE", "-o", "pid=,command="], {
8824
8914
  maxBuffer: 64 * 1024 * 1024
8825
8915
  }).toString();
8826
8916
  } catch {
@@ -8871,16 +8961,12 @@ function listClaudeAgents(timeoutMs = 1e4, command = "claude") {
8871
8961
  });
8872
8962
  }
8873
8963
  function findClaude(shell = process.env.SHELL || "/bin/sh", timeoutMs = 1e4) {
8874
- return new Promise((resolve7) => {
8875
- execFile3(
8876
- shell,
8877
- ["-ilc", "command -v claude"],
8878
- { env: terminalEnv({}), timeout: timeoutMs },
8879
- (_error, stdout) => {
8880
- const found = String(stdout ?? "").split("\n").map((line2) => line2.trim()).reverse().find((line2) => line2.startsWith("/"));
8881
- resolve7(found ?? null);
8882
- }
8883
- );
8964
+ return loginShell(shell, ["-ilc", "command -v claude"], {
8965
+ env: terminalEnv({}),
8966
+ timeoutMs
8967
+ }).then((stdout) => {
8968
+ const found = stdout.split("\n").map((line2) => line2.trim()).reverse().find((line2) => line2.startsWith("/"));
8969
+ return found ?? null;
8884
8970
  });
8885
8971
  }
8886
8972
  function claudeAgentsLister(find = () => findClaude(), retryMs = 5 * 60 * 1e3) {
@@ -9534,7 +9620,7 @@ var FolderWatch = class {
9534
9620
  // src/gh.ts
9535
9621
  init_define_HERD_PACKAGE();
9536
9622
  init_src();
9537
- import { execFile as execFile4, spawn as spawn9 } from "node:child_process";
9623
+ import { execFile as execFile4, spawn as spawn10 } from "node:child_process";
9538
9624
  import { promisify as promisify3 } from "node:util";
9539
9625
  var GH_CHECK_MS = 10 * 60 * 1e3;
9540
9626
  var GH_CODE_WAIT_MS = 30 * 1e3;
@@ -9605,7 +9691,7 @@ function readDeviceCode(output2) {
9605
9691
  return code && url === GITHUB_DEVICE_URL ? { code, url: GITHUB_DEVICE_URL } : null;
9606
9692
  }
9607
9693
  async function signInGh(options) {
9608
- const spawnGh = options.spawnGh ?? ((args) => spawn9("gh", args, {
9694
+ const spawnGh = options.spawnGh ?? ((args) => spawn10("gh", args, {
9609
9695
  env: options.env?.() ?? process.env,
9610
9696
  stdio: ["ignore", "pipe", "pipe"]
9611
9697
  }));
@@ -9651,11 +9737,10 @@ async function signInGh(options) {
9651
9737
 
9652
9738
  // src/login-env.ts
9653
9739
  init_define_HERD_PACKAGE();
9654
- import { execFileSync as execFileSync6 } from "node:child_process";
9655
9740
 
9656
9741
  // src/worktree-settings.ts
9657
9742
  init_define_HERD_PACKAGE();
9658
- import { execFileSync as execFileSync5 } from "node:child_process";
9743
+ import { execFileSync as execFileSync6 } from "node:child_process";
9659
9744
  import {
9660
9745
  appendFileSync as appendFileSync2,
9661
9746
  existsSync as existsSync17,
@@ -9666,7 +9751,7 @@ import {
9666
9751
  } from "node:fs";
9667
9752
  import { isAbsolute as isAbsolute3, join as join24 } from "node:path";
9668
9753
  var LOCAL_SETTINGS = join24(".claude", "settings.local.json");
9669
- var git3 = (cwd, ...args) => execFileSync5("git", ["-C", cwd, ...args], {
9754
+ var git3 = (cwd, ...args) => execFileSync6("git", ["-C", cwd, ...args], {
9670
9755
  encoding: "utf8",
9671
9756
  stdio: ["ignore", "pipe", "pipe"]
9672
9757
  }).trim();
@@ -9752,17 +9837,13 @@ function loginShellEnv() {
9752
9837
  }
9753
9838
  const shell = process.env.SHELL || "/bin/sh";
9754
9839
  const script = `process.stdout.write(${JSON.stringify(MARKER)} + JSON.stringify(process.env))`;
9755
- try {
9756
- const output2 = execFileSync6(
9757
- shell,
9758
- ["-ilc", `${shellQuote2(process.execPath)} -e ${shellQuote2(script)}`],
9759
- { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"], env: own, timeout: 15e3 }
9760
- );
9761
- const env = parseCapturedEnv(output2);
9762
- captured = env ? { ...own, ...env } : own;
9763
- } catch {
9764
- captured = own;
9765
- }
9840
+ const output2 = loginShellSync(
9841
+ shell,
9842
+ ["-ilc", `${shellQuote2(process.execPath)} -e ${shellQuote2(script)}`],
9843
+ { env: own, timeoutMs: 15e3 }
9844
+ );
9845
+ const env = output2 === null ? null : parseCapturedEnv(output2);
9846
+ captured = env ? { ...own, ...env } : own;
9766
9847
  return captured;
9767
9848
  }
9768
9849
 
@@ -9863,7 +9944,7 @@ var MachineChecks = class {
9863
9944
 
9864
9945
  // src/terminals.ts
9865
9946
  init_define_HERD_PACKAGE();
9866
- import { spawn as spawn10 } from "node:child_process";
9947
+ import { spawn as spawn11 } from "node:child_process";
9867
9948
  import { mkdirSync as mkdirSync19, readdirSync as readdirSync8, rmSync as rmSync16 } from "node:fs";
9868
9949
  import { connect as connect2 } from "node:net";
9869
9950
  import { join as join25 } from "node:path";
@@ -9959,7 +10040,7 @@ var HostTerminals = class {
9959
10040
  if (this.current()) return;
9960
10041
  const path = currentHostSocketPath(this.version);
9961
10042
  mkdirSync19(hostsDir(), { recursive: true, mode: 448 });
9962
- const child = spawn10(process.execPath, [herdBin, "terminal-host", "--socket", path], {
10043
+ const child = spawn11(process.execPath, [herdBin, "terminal-host", "--socket", path], {
9963
10044
  detached: true,
9964
10045
  stdio: "ignore",
9965
10046
  env: { ...process.env, HERD_HOME: herdHome() }
@@ -13273,7 +13354,7 @@ async function runAgyHook(event2, stdin, env, options = {}) {
13273
13354
 
13274
13355
  // src/statusline.ts
13275
13356
  init_define_HERD_PACKAGE();
13276
- import { spawn as spawn11 } from "node:child_process";
13357
+ import { spawn as spawn12 } from "node:child_process";
13277
13358
  import { readFileSync as readFileSync21 } from "node:fs";
13278
13359
  import { connect as connect3 } from "node:net";
13279
13360
  import { homedir as homedir7 } from "node:os";
@@ -13341,7 +13422,7 @@ function runOwnCommand(command, input, cwd, timeoutMs = OWN_COMMAND_TIMEOUT_MS)
13341
13422
  let output2 = "";
13342
13423
  let child;
13343
13424
  try {
13344
- child = spawn11("sh", ["-c", command], {
13425
+ child = spawn12("sh", ["-c", command], {
13345
13426
  cwd,
13346
13427
  detached: true,
13347
13428
  stdio: ["pipe", "pipe", "ignore"]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@herdingchats/friday",
3
- "version": "0.1.600",
3
+ "version": "0.1.609",
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": "258e3577331c639de77e7ab7f0cdccc48b275a89"
25
+ "gitHead": "cfba1790271c8df777ce206f2e53c6b987e94520"
26
26
  }