@herdingchats/friday 0.1.598 → 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.
- package/herd.mjs +162 -81
- 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.
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
3770
|
+
tail3 = buffer.toString("utf8");
|
|
3724
3771
|
} catch {
|
|
3725
3772
|
return null;
|
|
3726
3773
|
}
|
|
3727
|
-
const lines =
|
|
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
|
|
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
|
|
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
|
|
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 =
|
|
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) =>
|
|
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 =
|
|
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) =>
|
|
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 =
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
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 =
|
|
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
|
|
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 =
|
|
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 () =>
|
|
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 =
|
|
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
|
|
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 =
|
|
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
|
|
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
|
|
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 =
|
|
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
|
|
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) =>
|
|
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
|
-
|
|
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 =
|
|
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
|
-
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
|
8875
|
-
|
|
8876
|
-
|
|
8877
|
-
|
|
8878
|
-
|
|
8879
|
-
|
|
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
|
|
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) =>
|
|
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
|
|
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) =>
|
|
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
|
-
|
|
9756
|
-
|
|
9757
|
-
|
|
9758
|
-
|
|
9759
|
-
|
|
9760
|
-
|
|
9761
|
-
|
|
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
|
|
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 =
|
|
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
|
|
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 =
|
|
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.
|
|
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": "
|
|
25
|
+
"gitHead": "cfba1790271c8df777ce206f2e53c6b987e94520"
|
|
26
26
|
}
|