@herdingchats/friday 0.1.1 → 0.1.522
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 +168 -105
- 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.522", gitHead: "3dab37264f9426b4af9a912efcddadf9fb04cdcc" };
|
|
22
22
|
}
|
|
23
23
|
});
|
|
24
24
|
|
|
@@ -513,6 +513,9 @@ import { z as z8 } from "zod";
|
|
|
513
513
|
function agentShortName(cli) {
|
|
514
514
|
return AGENTS[cli]?.short ?? cli;
|
|
515
515
|
}
|
|
516
|
+
function shareOf(harness) {
|
|
517
|
+
return harness?.share ?? (harness?.enabled === false ? "off" : "some");
|
|
518
|
+
}
|
|
516
519
|
function runnerCapacity(setting) {
|
|
517
520
|
if (setting === void 0 || setting === true) return 1;
|
|
518
521
|
return setting.max;
|
|
@@ -528,7 +531,7 @@ function workerKey(machineId, cli) {
|
|
|
528
531
|
function machineShortName(name) {
|
|
529
532
|
return name.trim().toLowerCase().replace(/\.local$/, "").replace(/\s+/g, "-");
|
|
530
533
|
}
|
|
531
|
-
var CAPABILITIES, capabilitySchema, PLATFORMS, platformSchema, TOOLS, toolSchema, CAPABILITY_WORDING, AGENTS, PHRASE_MAX, PHRASES_MAX, ABOUT_MAX, phrase, phrases, harnessConfigSchema, BUILDS_MAX, buildsSettingSchema, CONFIG_REPOS_MAX, configRepoSchema, herdConfigSchema, HERD_CONFIG_TYPE, PROFILE_LEVELS, profileEntrySchema, workerSchema;
|
|
534
|
+
var CAPABILITIES, capabilitySchema, PLATFORMS, platformSchema, TOOLS, toolSchema, CAPABILITY_WORDING, AGENTS, PHRASE_MAX, PHRASES_MAX, ABOUT_MAX, phrase, phrases, SHARES, shareSchema, SHARE_LABELS, harnessConfigSchema, BUILDS_MAX, buildsSettingSchema, CONFIG_REPOS_MAX, configRepoSchema, herdConfigSchema, HERD_CONFIG_TYPE, PROFILE_LEVELS, profileEntrySchema, workerSchema;
|
|
532
535
|
var init_workers = __esm({
|
|
533
536
|
"../common-chat/src/workers.ts"() {
|
|
534
537
|
"use strict";
|
|
@@ -566,7 +569,17 @@ var init_workers = __esm({
|
|
|
566
569
|
ABOUT_MAX = 500;
|
|
567
570
|
phrase = z8.string().trim().min(1).max(PHRASE_MAX, `at most ${PHRASE_MAX} characters`);
|
|
568
571
|
phrases = z8.array(phrase).max(PHRASES_MAX, `at most ${PHRASES_MAX} phrases`);
|
|
572
|
+
SHARES = ["off", "little", "some", "lot"];
|
|
573
|
+
shareSchema = z8.enum(SHARES);
|
|
574
|
+
SHARE_LABELS = {
|
|
575
|
+
off: "off",
|
|
576
|
+
little: "a little",
|
|
577
|
+
some: "some",
|
|
578
|
+
lot: "a lot"
|
|
579
|
+
};
|
|
569
580
|
harnessConfigSchema = z8.object({
|
|
581
|
+
share: shareSchema.optional(),
|
|
582
|
+
/** Read as `share: "off"` when false, from files written before shares. */
|
|
570
583
|
enabled: z8.boolean().optional(),
|
|
571
584
|
only: phrases.optional(),
|
|
572
585
|
great: phrases.optional(),
|
|
@@ -619,10 +632,12 @@ var init_workers = __esm({
|
|
|
619
632
|
/** Each harness by its short name, such as claude, codex or gemini. */
|
|
620
633
|
harnesses?: Record<string, {
|
|
621
634
|
/**
|
|
622
|
-
*
|
|
623
|
-
*
|
|
635
|
+
* How much of this agent its owner has, as chosen in \`friday start\`: "off", "little", "some"
|
|
636
|
+
* or "lot". Routing gives each its share of the work several agents suit equally, weighted
|
|
637
|
+
* 1, 2 and 4. "off" means it's no worker here. Without a configuration file, every installed
|
|
638
|
+
* agent is at "some".
|
|
624
639
|
*/
|
|
625
|
-
|
|
640
|
+
share?: "off" | "little" | "some" | "lot";
|
|
626
641
|
/** It takes only work about one of these, however good it is at other work. */
|
|
627
642
|
only?: string[];
|
|
628
643
|
/**
|
|
@@ -664,6 +679,8 @@ export default {
|
|
|
664
679
|
/** What it's great, good and okay at, and can't do: its agent's defaults with its owner's word. */
|
|
665
680
|
profile: z8.array(profileEntrySchema),
|
|
666
681
|
priority: z8.number().int(),
|
|
682
|
+
/** How much of its agent its owner has. Servers from before shares send none, which is "some". */
|
|
683
|
+
share: shareSchema.default("some"),
|
|
667
684
|
enabled: z8.boolean(),
|
|
668
685
|
/** Whether its agent checked in from herd's terminal on this version, so it's offered work. */
|
|
669
686
|
activated: z8.boolean(),
|
|
@@ -1002,6 +1019,7 @@ var init_events = __esm({
|
|
|
1002
1019
|
init_prompts();
|
|
1003
1020
|
init_usage();
|
|
1004
1021
|
init_work_objects();
|
|
1022
|
+
init_workers();
|
|
1005
1023
|
routeSchema = z13.enum(["direct", "mention", "joined"]);
|
|
1006
1024
|
deliveryModeSchema = z13.enum(["interrupt", "defer"]);
|
|
1007
1025
|
eventSourceSchema = z13.enum(["slack", "discord", "web", "api", "cli", "mcp", "system"]);
|
|
@@ -1056,7 +1074,18 @@ var init_events = __esm({
|
|
|
1056
1074
|
// The repos the work hinted, and the workers whose machine had cloned every one, which go first
|
|
1057
1075
|
// among workers that tie on fit and priority.
|
|
1058
1076
|
hints: z13.array(nonEmpty6).optional(),
|
|
1059
|
-
warm: z13.array(nonEmpty6).optional()
|
|
1077
|
+
warm: z13.array(nonEmpty6).optional(),
|
|
1078
|
+
// Each ordered worker's share, how its weekly usage is pacing, and the weight that gives it. The
|
|
1079
|
+
// first worker was drawn by weight from those in `drawn`, which suited the work equally.
|
|
1080
|
+
shares: z13.array(
|
|
1081
|
+
z13.object({
|
|
1082
|
+
key: nonEmpty6,
|
|
1083
|
+
share: shareSchema,
|
|
1084
|
+
pacing: z13.enum(["ahead", "even", "under", "unknown"]),
|
|
1085
|
+
weight: z13.number().nonnegative()
|
|
1086
|
+
})
|
|
1087
|
+
).optional(),
|
|
1088
|
+
drawn: z13.array(nonEmpty6).optional()
|
|
1060
1089
|
});
|
|
1061
1090
|
conversationEventSchema = z13.discriminatedUnion("type", [
|
|
1062
1091
|
event("message.created", {
|
|
@@ -3171,9 +3200,9 @@ import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
|
3171
3200
|
// src/friday/main.ts
|
|
3172
3201
|
init_define_HERD_PACKAGE();
|
|
3173
3202
|
import { spawn as spawn5 } from "node:child_process";
|
|
3174
|
-
import { existsSync as
|
|
3203
|
+
import { existsSync as existsSync10, readFileSync as readFileSync10 } from "node:fs";
|
|
3175
3204
|
import { homedir as homedir4 } from "node:os";
|
|
3176
|
-
import { dirname as
|
|
3205
|
+
import { dirname as dirname9, join as join13 } from "node:path";
|
|
3177
3206
|
import { z as z22 } from "zod";
|
|
3178
3207
|
|
|
3179
3208
|
// src/auth.ts
|
|
@@ -3402,9 +3431,9 @@ async function runLogout() {
|
|
|
3402
3431
|
init_define_HERD_PACKAGE();
|
|
3403
3432
|
import { execFileSync as execFileSync3 } from "node:child_process";
|
|
3404
3433
|
import { randomUUID } from "node:crypto";
|
|
3405
|
-
import { mkdirSync as mkdirSync3, readFileSync as readFileSync4, writeFileSync as writeFileSync3 } from "node:fs";
|
|
3434
|
+
import { existsSync as existsSync2, mkdirSync as mkdirSync3, readFileSync as readFileSync4, writeFileSync as writeFileSync3 } from "node:fs";
|
|
3406
3435
|
import { homedir as homedir3, hostname } from "node:os";
|
|
3407
|
-
import { basename, join as join5, resolve } from "node:path";
|
|
3436
|
+
import { basename, dirname as dirname3, join as join5, resolve } from "node:path";
|
|
3408
3437
|
import { z as z18 } from "zod";
|
|
3409
3438
|
|
|
3410
3439
|
// src/machine-facts.ts
|
|
@@ -3649,7 +3678,7 @@ var ADAPTERS = [
|
|
|
3649
3678
|
{ cli: "agy", capabilities: ["image_generation"] }
|
|
3650
3679
|
];
|
|
3651
3680
|
function chosenClis(clis, config) {
|
|
3652
|
-
return clis.filter((cli) => config?.harnesses?.[agentShortName(cli.name)]
|
|
3681
|
+
return clis.filter((cli) => shareOf(config?.harnesses?.[agentShortName(cli.name)]) !== "off");
|
|
3653
3682
|
}
|
|
3654
3683
|
var runCommand = (command, args) => {
|
|
3655
3684
|
try {
|
|
@@ -4111,6 +4140,20 @@ function readRoot() {
|
|
|
4111
4140
|
function setRoot(path) {
|
|
4112
4141
|
return save({ ...loadConfig(), root: resolve(path) });
|
|
4113
4142
|
}
|
|
4143
|
+
async function waitForRoot(root, {
|
|
4144
|
+
pollMs = 2e3,
|
|
4145
|
+
exists = existsSync2,
|
|
4146
|
+
sleep: sleep8 = (ms) => new Promise((done) => setTimeout(done, ms)),
|
|
4147
|
+
log = (line2) => console.log(line2)
|
|
4148
|
+
} = {}) {
|
|
4149
|
+
const parent = dirname3(root);
|
|
4150
|
+
if (exists(parent)) return;
|
|
4151
|
+
log(
|
|
4152
|
+
`Waiting for ${parent}, which holds this machine's root, to be there, as when its drive mounts.`
|
|
4153
|
+
);
|
|
4154
|
+
while (!exists(parent)) await sleep8(pollMs);
|
|
4155
|
+
log(`${parent} is there.`);
|
|
4156
|
+
}
|
|
4114
4157
|
var machineRoot = () => readRoot() ?? defaultRoot();
|
|
4115
4158
|
function describeRepo(path) {
|
|
4116
4159
|
const full = resolve(path);
|
|
@@ -4267,15 +4310,15 @@ async function readSetup(fetch2, init) {
|
|
|
4267
4310
|
// src/friday/agents.ts
|
|
4268
4311
|
init_define_HERD_PACKAGE();
|
|
4269
4312
|
init_src();
|
|
4270
|
-
import { existsSync as
|
|
4271
|
-
import { dirname as
|
|
4313
|
+
import { existsSync as existsSync4, mkdirSync as mkdirSync5, writeFileSync as writeFileSync5 } from "node:fs";
|
|
4314
|
+
import { dirname as dirname5, join as join7 } from "node:path";
|
|
4272
4315
|
|
|
4273
4316
|
// src/activation.ts
|
|
4274
4317
|
init_define_HERD_PACKAGE();
|
|
4275
4318
|
init_src();
|
|
4276
4319
|
import { randomBytes as randomBytes4, randomUUID as randomUUID3 } from "node:crypto";
|
|
4277
4320
|
import { mkdirSync as mkdirSync4, readFileSync as readFileSync5, renameSync as renameSync2, rmSync as rmSync5, statSync as statSync4, writeFileSync as writeFileSync4 } from "node:fs";
|
|
4278
|
-
import { dirname as
|
|
4321
|
+
import { dirname as dirname4, join as join6 } from "node:path";
|
|
4279
4322
|
import { z as z21 } from "zod";
|
|
4280
4323
|
|
|
4281
4324
|
// src/permissions.ts
|
|
@@ -4287,7 +4330,7 @@ import { z as z20 } from "zod";
|
|
|
4287
4330
|
// src/local-socket.ts
|
|
4288
4331
|
init_define_HERD_PACKAGE();
|
|
4289
4332
|
import { randomBytes as randomBytes3 } from "node:crypto";
|
|
4290
|
-
import { chmodSync as chmodSync2, existsSync as
|
|
4333
|
+
import { chmodSync as chmodSync2, existsSync as existsSync3, rmSync as rmSync4 } from "node:fs";
|
|
4291
4334
|
import { connect, createServer as createServer2 } from "node:net";
|
|
4292
4335
|
import { z as z19 } from "zod";
|
|
4293
4336
|
var localRequestSchema = z19.object({
|
|
@@ -4423,7 +4466,7 @@ var LocalSocket = class {
|
|
|
4423
4466
|
}
|
|
4424
4467
|
}
|
|
4425
4468
|
async listen() {
|
|
4426
|
-
if (
|
|
4469
|
+
if (existsSync3(this.path)) rmSync4(this.path);
|
|
4427
4470
|
this.server = createServer2((socket) => this.serve(socket));
|
|
4428
4471
|
await new Promise((resolve6, reject) => {
|
|
4429
4472
|
this.server?.once("error", reject);
|
|
@@ -4505,7 +4548,7 @@ function askDaemon(path, request) {
|
|
|
4505
4548
|
}
|
|
4506
4549
|
function isAnswering(path) {
|
|
4507
4550
|
return new Promise((resolve6) => {
|
|
4508
|
-
if (!
|
|
4551
|
+
if (!existsSync3(path)) return resolve6(false);
|
|
4509
4552
|
const socket = connect(path);
|
|
4510
4553
|
socket.on("connect", () => {
|
|
4511
4554
|
socket.destroy();
|
|
@@ -4744,7 +4787,7 @@ var Activator = class {
|
|
|
4744
4787
|
}
|
|
4745
4788
|
record(agent, record) {
|
|
4746
4789
|
const agents = { ...readActivations(this.path), [agent]: record };
|
|
4747
|
-
mkdirSync4(
|
|
4790
|
+
mkdirSync4(dirname4(this.path), { recursive: true, mode: 448 });
|
|
4748
4791
|
const temporary = `${this.path}.${process.pid}`;
|
|
4749
4792
|
writeFileSync4(temporary, JSON.stringify({ agents }, null, 2), { mode: 384 });
|
|
4750
4793
|
renameSync2(temporary, this.path);
|
|
@@ -4956,36 +4999,42 @@ var ACTIVATION_READ_MS = 500;
|
|
|
4956
4999
|
var label2 = (cli) => AGENTS[cli]?.label ?? cli;
|
|
4957
5000
|
function agentChoices(installed, saved) {
|
|
4958
5001
|
const harnesses = saved?.harnesses ?? {};
|
|
4959
|
-
const chosenBefore = Object.values(harnesses).some(
|
|
5002
|
+
const chosenBefore = Object.values(harnesses).some(
|
|
5003
|
+
(harness) => harness.enabled !== void 0 || harness.share !== void 0
|
|
5004
|
+
);
|
|
4960
5005
|
return ADAPTERS.map(({ cli }) => {
|
|
4961
5006
|
const isInstalled = installed.includes(cli);
|
|
4962
|
-
const
|
|
5007
|
+
const harness = harnesses[agentShortName(cli)];
|
|
5008
|
+
const before = harness?.share ?? (harness?.enabled ? "some" : "off");
|
|
4963
5009
|
return {
|
|
4964
5010
|
cli,
|
|
4965
5011
|
label: label2(cli),
|
|
4966
5012
|
installed: isInstalled,
|
|
4967
|
-
|
|
5013
|
+
share: chosenBefore ? before : isInstalled ? "some" : "off"
|
|
4968
5014
|
};
|
|
4969
5015
|
});
|
|
4970
5016
|
}
|
|
4971
5017
|
function parseAgents(value) {
|
|
4972
|
-
const
|
|
4973
|
-
const
|
|
5018
|
+
const parts = value.split(",").map((part) => part.trim().toLowerCase()).filter(Boolean);
|
|
5019
|
+
const shares = Object.fromEntries(ADAPTERS.map(({ cli }) => [cli, "off"]));
|
|
4974
5020
|
const unknown = [];
|
|
4975
|
-
for (const
|
|
5021
|
+
for (const part of parts) {
|
|
5022
|
+
const [name = "", share = "some"] = part.split("=", 2).map((piece) => piece.trim());
|
|
4976
5023
|
const adapter = ADAPTERS.find(
|
|
4977
5024
|
({ cli }) => cli === name || agentShortName(cli) === name || label2(cli).toLowerCase() === name
|
|
4978
5025
|
);
|
|
4979
|
-
if (adapter
|
|
4980
|
-
|
|
5026
|
+
if (adapter && SHARES.includes(share)) {
|
|
5027
|
+
shares[adapter.cli] = share;
|
|
5028
|
+
} else unknown.push(part);
|
|
4981
5029
|
}
|
|
4982
|
-
return unknown.length > 0 ? { unknown } : {
|
|
5030
|
+
return unknown.length > 0 ? { unknown } : { shares };
|
|
4983
5031
|
}
|
|
4984
|
-
function withChoice(config,
|
|
5032
|
+
function withChoice(config, shares) {
|
|
4985
5033
|
const harnesses = { ...config?.harnesses ?? {} };
|
|
4986
5034
|
for (const { cli } of ADAPTERS) {
|
|
4987
5035
|
const short = agentShortName(cli);
|
|
4988
|
-
|
|
5036
|
+
const { enabled: _, ...rest } = harnesses[short] ?? {};
|
|
5037
|
+
harnesses[short] = { ...rest, share: shares[cli] ?? "off" };
|
|
4989
5038
|
}
|
|
4990
5039
|
return { ...config, harnesses };
|
|
4991
5040
|
}
|
|
@@ -4994,9 +5043,10 @@ function configSource(config) {
|
|
|
4994
5043
|
export default ${JSON.stringify(config, null, 2)};
|
|
4995
5044
|
`;
|
|
4996
5045
|
}
|
|
4997
|
-
var sameChoice = (config,
|
|
4998
|
-
|
|
4999
|
-
);
|
|
5046
|
+
var sameChoice = (config, shares) => ADAPTERS.every(({ cli }) => {
|
|
5047
|
+
const harness = config?.harnesses?.[agentShortName(cli)];
|
|
5048
|
+
return harness?.enabled === void 0 && harness?.share === (shares[cli] ?? "off");
|
|
5049
|
+
});
|
|
5000
5050
|
async function chooseAgents(options, print) {
|
|
5001
5051
|
const [installed, loaded] = await Promise.all([options.installed(), options.load()]);
|
|
5002
5052
|
if (loaded.status === "error") {
|
|
@@ -5006,14 +5056,15 @@ async function chooseAgents(options, print) {
|
|
|
5006
5056
|
const saved = loaded.status === "ok" ? loaded.config : void 0;
|
|
5007
5057
|
const choices = agentChoices(installed, saved);
|
|
5008
5058
|
const asked = options.given ? null : await (options.pick?.(choices) ?? Promise.resolve(null));
|
|
5009
|
-
const
|
|
5010
|
-
choices.
|
|
5011
|
-
if (!sameChoice(saved,
|
|
5012
|
-
mkdirSync5(
|
|
5013
|
-
writeFileSync5(options.configPath, configSource(withChoice(saved,
|
|
5059
|
+
const shares = options.given ?? asked ?? // No terminal: what was chosen before, or what's installed.
|
|
5060
|
+
Object.fromEntries(choices.map((choice) => [choice.cli, choice.share]));
|
|
5061
|
+
if (!sameChoice(saved, shares) || !existsSync4(options.configPath)) {
|
|
5062
|
+
mkdirSync5(dirname5(options.configPath), { recursive: true, mode: 448 });
|
|
5063
|
+
writeFileSync5(options.configPath, configSource(withChoice(saved, shares)), { mode: 384 });
|
|
5014
5064
|
}
|
|
5065
|
+
const chosen = ADAPTERS.map(({ cli }) => cli).filter((cli) => (shares[cli] ?? "off") !== "off");
|
|
5015
5066
|
print(
|
|
5016
|
-
chosen.length > 0 ? `This machine runs ${chosen.map(label2).join(", ")}.` : "This machine runs no agents, so it takes no work. Run this again to choose some."
|
|
5067
|
+
chosen.length > 0 ? `This machine runs ${chosen.map((cli) => `${label2(cli)} (${SHARE_LABELS[shares[cli]]})`).join(", ")}.` : "This machine runs no agents, so it takes no work. Run this again to choose some."
|
|
5017
5068
|
);
|
|
5018
5069
|
return chosen;
|
|
5019
5070
|
}
|
|
@@ -5081,7 +5132,7 @@ init_define_HERD_PACKAGE();
|
|
|
5081
5132
|
import { spawnSync } from "node:child_process";
|
|
5082
5133
|
import {
|
|
5083
5134
|
closeSync as closeSync2,
|
|
5084
|
-
existsSync as
|
|
5135
|
+
existsSync as existsSync5,
|
|
5085
5136
|
mkdirSync as mkdirSync6,
|
|
5086
5137
|
openSync as openSync2,
|
|
5087
5138
|
readFileSync as readFileSync6,
|
|
@@ -5089,7 +5140,7 @@ import {
|
|
|
5089
5140
|
statSync as statSync5,
|
|
5090
5141
|
writeFileSync as writeFileSync6
|
|
5091
5142
|
} from "node:fs";
|
|
5092
|
-
import { dirname as
|
|
5143
|
+
import { dirname as dirname6, join as join8, resolve as resolve2 } from "node:path";
|
|
5093
5144
|
var PACKAGE_NAME = "@herdingchats/friday";
|
|
5094
5145
|
function fridayPaths(herdHome2) {
|
|
5095
5146
|
const logs = join8(herdHome2, "logs");
|
|
@@ -5118,8 +5169,8 @@ function alive2(pid) {
|
|
|
5118
5169
|
}
|
|
5119
5170
|
}
|
|
5120
5171
|
function takeLock(path, staleMs = 10 * 6e4) {
|
|
5121
|
-
mkdirSync6(
|
|
5122
|
-
if (
|
|
5172
|
+
mkdirSync6(dirname6(path), { recursive: true });
|
|
5173
|
+
if (existsSync5(path)) {
|
|
5123
5174
|
const holder2 = Number(readFileSync6(path, "utf8").trim());
|
|
5124
5175
|
const old = Date.now() - statSync5(path).mtimeMs > staleMs;
|
|
5125
5176
|
if (old || !alive2(holder2)) rmSync6(path, { force: true });
|
|
@@ -5169,7 +5220,7 @@ function writeRoot(paths, root) {
|
|
|
5169
5220
|
}
|
|
5170
5221
|
function insideWorkTree(folder) {
|
|
5171
5222
|
let dir = resolve2(folder);
|
|
5172
|
-
while (!
|
|
5223
|
+
while (!existsSync5(dir) && dirname6(dir) !== dir) dir = dirname6(dir);
|
|
5173
5224
|
const result = spawnSync("git", ["-C", dir, "rev-parse", "--show-toplevel"], {
|
|
5174
5225
|
encoding: "utf8",
|
|
5175
5226
|
stdio: ["ignore", "pipe", "ignore"]
|
|
@@ -5189,6 +5240,9 @@ var VERSION = /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/;
|
|
|
5189
5240
|
|
|
5190
5241
|
// src/friday/picker.ts
|
|
5191
5242
|
init_define_HERD_PACKAGE();
|
|
5243
|
+
init_src();
|
|
5244
|
+
var LESS = /* @__PURE__ */ new Set(["-", "_", "\x1B[D"]);
|
|
5245
|
+
var MORE = /* @__PURE__ */ new Set(["+", "=", "\x1B[C"]);
|
|
5192
5246
|
function pickerKey(state, key) {
|
|
5193
5247
|
const { choices, cursor } = state;
|
|
5194
5248
|
if (key === "" || key === "\x1B") return null;
|
|
@@ -5197,22 +5251,28 @@ function pickerKey(state, key) {
|
|
|
5197
5251
|
return { ...state, cursor: (cursor + choices.length - 1) % choices.length };
|
|
5198
5252
|
}
|
|
5199
5253
|
if (key === "\x1B[B" || key === "j") return { ...state, cursor: (cursor + 1) % choices.length };
|
|
5200
|
-
|
|
5201
|
-
|
|
5202
|
-
|
|
5203
|
-
|
|
5204
|
-
|
|
5205
|
-
)
|
|
5206
|
-
|
|
5207
|
-
|
|
5208
|
-
|
|
5254
|
+
const step = LESS.has(key) ? -1 : MORE.has(key) ? 1 : 0;
|
|
5255
|
+
if (step === 0) return state;
|
|
5256
|
+
return {
|
|
5257
|
+
...state,
|
|
5258
|
+
choices: choices.map((choice, at) => {
|
|
5259
|
+
if (at !== cursor) return choice;
|
|
5260
|
+
const next = Math.min(SHARES.length - 1, Math.max(0, SHARES.indexOf(choice.share) + step));
|
|
5261
|
+
return { ...choice, share: SHARES[next] ?? choice.share };
|
|
5262
|
+
})
|
|
5263
|
+
};
|
|
5209
5264
|
}
|
|
5210
5265
|
function pickerLines(state) {
|
|
5266
|
+
const width = Math.max(...state.choices.map((choice) => choice.label.length));
|
|
5267
|
+
const cells = SHARES.length - 1;
|
|
5211
5268
|
return [
|
|
5212
|
-
"
|
|
5213
|
-
...state.choices.map(
|
|
5214
|
-
|
|
5215
|
-
|
|
5269
|
+
"How much of each agent do you have on this computer? (\u2191/\u2193 to move, -/+ to change, Enter to accept)",
|
|
5270
|
+
...state.choices.map((choice, at) => {
|
|
5271
|
+
const filled = SHARES.indexOf(choice.share);
|
|
5272
|
+
const bar = "\u25A0".repeat(filled) + "\u25A1".repeat(cells - filled);
|
|
5273
|
+
const missing = choice.installed ? "" : " (not installed here)";
|
|
5274
|
+
return `${at === state.cursor ? "\u276F" : " "} ${choice.label.padEnd(width)} ${bar} ${SHARE_LABELS[choice.share]}${missing}`;
|
|
5275
|
+
})
|
|
5216
5276
|
];
|
|
5217
5277
|
}
|
|
5218
5278
|
function pickInTerminal(choices, input = process.stdin, output2 = process.stdout) {
|
|
@@ -5229,18 +5289,18 @@ function pickInTerminal(choices, input = process.stdin, output2 = process.stdout
|
|
|
5229
5289
|
input.setRawMode(true);
|
|
5230
5290
|
input.resume();
|
|
5231
5291
|
draw(true);
|
|
5232
|
-
const finish = (
|
|
5292
|
+
const finish = (shares) => {
|
|
5233
5293
|
input.off("data", onData);
|
|
5234
5294
|
input.setRawMode(wasRaw);
|
|
5235
5295
|
input.pause();
|
|
5236
|
-
resolve6(
|
|
5296
|
+
resolve6(shares);
|
|
5237
5297
|
};
|
|
5238
5298
|
const onData = (data) => {
|
|
5239
5299
|
const next = pickerKey(state, data.toString("utf8"));
|
|
5240
5300
|
if (!next) return finish(null);
|
|
5241
5301
|
state = next;
|
|
5242
5302
|
draw(false);
|
|
5243
|
-
if (state.done) finish(state.choices.
|
|
5303
|
+
if (state.done) finish(Object.fromEntries(state.choices.map((c) => [c.cli, c.share])));
|
|
5244
5304
|
};
|
|
5245
5305
|
input.on("data", onData);
|
|
5246
5306
|
});
|
|
@@ -5249,9 +5309,9 @@ function pickInTerminal(choices, input = process.stdin, output2 = process.stdout
|
|
|
5249
5309
|
// src/friday/service.ts
|
|
5250
5310
|
init_define_HERD_PACKAGE();
|
|
5251
5311
|
import { spawn as spawn2 } from "node:child_process";
|
|
5252
|
-
import { existsSync as
|
|
5312
|
+
import { existsSync as existsSync6, mkdirSync as mkdirSync7, openSync as openSync3, readFileSync as readFileSync7, rmSync as rmSync7, writeFileSync as writeFileSync7 } from "node:fs";
|
|
5253
5313
|
import { userInfo } from "node:os";
|
|
5254
|
-
import { dirname as
|
|
5314
|
+
import { dirname as dirname7, join as join9 } from "node:path";
|
|
5255
5315
|
var LAUNCH_AGENT = "com.herdingchats.friday";
|
|
5256
5316
|
var SYSTEMD_UNIT = "herdingchats-friday.service";
|
|
5257
5317
|
async function detectService(run4, platform2 = process.platform, override = process.env.HERD_SERVICE) {
|
|
@@ -5266,7 +5326,7 @@ async function detectService(run4, platform2 = process.platform, override = proc
|
|
|
5266
5326
|
}
|
|
5267
5327
|
function servicePath(node) {
|
|
5268
5328
|
return [
|
|
5269
|
-
|
|
5329
|
+
dirname7(node),
|
|
5270
5330
|
"/opt/homebrew/bin",
|
|
5271
5331
|
"/usr/local/bin",
|
|
5272
5332
|
"/usr/bin",
|
|
@@ -5337,8 +5397,8 @@ WantedBy=default.target
|
|
|
5337
5397
|
`;
|
|
5338
5398
|
}
|
|
5339
5399
|
function writeIfChanged(path, text4) {
|
|
5340
|
-
if (
|
|
5341
|
-
mkdirSync7(
|
|
5400
|
+
if (existsSync6(path) && readFileSync7(path, "utf8") === text4) return false;
|
|
5401
|
+
mkdirSync7(dirname7(path), { recursive: true });
|
|
5342
5402
|
writeFileSync7(path, text4);
|
|
5343
5403
|
return true;
|
|
5344
5404
|
}
|
|
@@ -5393,7 +5453,7 @@ function systemd(context2) {
|
|
|
5393
5453
|
};
|
|
5394
5454
|
}
|
|
5395
5455
|
function spawnInBackground(command, env, log) {
|
|
5396
|
-
mkdirSync7(
|
|
5456
|
+
mkdirSync7(dirname7(log), { recursive: true });
|
|
5397
5457
|
const out = openSync3(log, "a");
|
|
5398
5458
|
const [program = process.execPath, ...args] = command;
|
|
5399
5459
|
spawn2(program, args, {
|
|
@@ -5442,20 +5502,20 @@ import { join as join12, resolve as resolve3 } from "node:path";
|
|
|
5442
5502
|
|
|
5443
5503
|
// src/friday/legacy.ts
|
|
5444
5504
|
init_define_HERD_PACKAGE();
|
|
5445
|
-
import { existsSync as
|
|
5505
|
+
import { existsSync as existsSync7, readdirSync as readdirSync3, rmSync as rmSync8 } from "node:fs";
|
|
5446
5506
|
import { userInfo as userInfo2 } from "node:os";
|
|
5447
5507
|
import { join as join10 } from "node:path";
|
|
5448
5508
|
var OLD_LAUNCH_AGENT = "com.herdingchats.herd";
|
|
5449
5509
|
var OLD_APPS = ["herd-daemon", "herd-updater"];
|
|
5450
5510
|
function oldPm2s(paths) {
|
|
5451
5511
|
const dir = join10(paths.herdHome, "daemon");
|
|
5452
|
-
if (!
|
|
5453
|
-
return readdirSync3(dir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => join10(dir, entry.name, "node_modules", "pm2", "bin", "pm2")).filter((pm2) =>
|
|
5512
|
+
if (!existsSync7(dir)) return [];
|
|
5513
|
+
return readdirSync3(dir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => join10(dir, entry.name, "node_modules", "pm2", "bin", "pm2")).filter((pm2) => existsSync7(pm2));
|
|
5454
5514
|
}
|
|
5455
5515
|
async function retireOldDaemon(paths, { home, run: run4 }) {
|
|
5456
5516
|
const removed = [];
|
|
5457
5517
|
const plist = join10(home, "Library", "LaunchAgents", `${OLD_LAUNCH_AGENT}.plist`);
|
|
5458
|
-
if (
|
|
5518
|
+
if (existsSync7(plist)) {
|
|
5459
5519
|
await run4("launchctl", ["bootout", `gui/${userInfo2().uid}/${OLD_LAUNCH_AGENT}`]);
|
|
5460
5520
|
rmSync8(plist, { force: true });
|
|
5461
5521
|
removed.push(`the login item ${OLD_LAUNCH_AGENT}`);
|
|
@@ -5481,7 +5541,7 @@ async function retireOldDaemon(paths, { home, run: run4 }) {
|
|
|
5481
5541
|
init_define_HERD_PACKAGE();
|
|
5482
5542
|
import { spawn as spawn3 } from "node:child_process";
|
|
5483
5543
|
import {
|
|
5484
|
-
existsSync as
|
|
5544
|
+
existsSync as existsSync8,
|
|
5485
5545
|
mkdirSync as mkdirSync8,
|
|
5486
5546
|
readdirSync as readdirSync4,
|
|
5487
5547
|
readFileSync as readFileSync8,
|
|
@@ -5492,7 +5552,7 @@ import {
|
|
|
5492
5552
|
symlinkSync,
|
|
5493
5553
|
writeFileSync as writeFileSync8
|
|
5494
5554
|
} from "node:fs";
|
|
5495
|
-
import { basename as basename2, dirname as
|
|
5555
|
+
import { basename as basename2, dirname as dirname8, join as join11 } from "node:path";
|
|
5496
5556
|
var exec = (command, args, options = {}) => new Promise((resolve6) => {
|
|
5497
5557
|
let stdout = "";
|
|
5498
5558
|
let stderr = "";
|
|
@@ -5514,8 +5574,8 @@ var exec = (command, args, options = {}) => new Promise((resolve6) => {
|
|
|
5514
5574
|
});
|
|
5515
5575
|
});
|
|
5516
5576
|
function npmCommand() {
|
|
5517
|
-
const beside = join11(
|
|
5518
|
-
return
|
|
5577
|
+
const beside = join11(dirname8(process.execPath), "npm");
|
|
5578
|
+
return existsSync8(beside) ? beside : "npm";
|
|
5519
5579
|
}
|
|
5520
5580
|
function currentVersion(paths) {
|
|
5521
5581
|
try {
|
|
@@ -5525,7 +5585,7 @@ function currentVersion(paths) {
|
|
|
5525
5585
|
}
|
|
5526
5586
|
}
|
|
5527
5587
|
function installedVersions(paths) {
|
|
5528
|
-
if (!
|
|
5588
|
+
if (!existsSync8(paths.versions)) return [];
|
|
5529
5589
|
return readdirSync4(paths.versions).filter((name) => VERSION.test(name)).sort(compareVersions);
|
|
5530
5590
|
}
|
|
5531
5591
|
var binOf = (versionDir, bin) => join11(packageDir(versionDir), `${bin}.mjs`);
|
|
@@ -5556,7 +5616,7 @@ async function installVersion(paths, version, { spec, integrity, run: run4 = exe
|
|
|
5556
5616
|
} } = {}) {
|
|
5557
5617
|
if (!VERSION.test(version)) return { ok: false, reason: `${version} isn't a version.` };
|
|
5558
5618
|
const dir = join11(paths.versions, version);
|
|
5559
|
-
if (
|
|
5619
|
+
if (existsSync8(dir)) {
|
|
5560
5620
|
const installed2 = recordedIntegrity(dir);
|
|
5561
5621
|
if (integrity && installed2 !== integrity)
|
|
5562
5622
|
return { ok: false, reason: `the installed ${version} doesn't have the integrity named.` };
|
|
@@ -5609,7 +5669,7 @@ async function installVersion(paths, version, { spec, integrity, run: run4 = exe
|
|
|
5609
5669
|
return { ok: true, dir };
|
|
5610
5670
|
}
|
|
5611
5671
|
function sweepStaging(paths) {
|
|
5612
|
-
if (!
|
|
5672
|
+
if (!existsSync8(paths.versions)) return;
|
|
5613
5673
|
for (const name of readdirSync4(paths.versions)) {
|
|
5614
5674
|
const match = /^\.staging-.+-(\d+)$/.exec(name);
|
|
5615
5675
|
if (match && !alive2(Number(match[1])))
|
|
@@ -5815,7 +5875,7 @@ init_define_HERD_PACKAGE();
|
|
|
5815
5875
|
import { spawn as spawn4 } from "node:child_process";
|
|
5816
5876
|
import {
|
|
5817
5877
|
closeSync as closeSync3,
|
|
5818
|
-
existsSync as
|
|
5878
|
+
existsSync as existsSync9,
|
|
5819
5879
|
mkdirSync as mkdirSync10,
|
|
5820
5880
|
openSync as openSync4,
|
|
5821
5881
|
readFileSync as readFileSync9,
|
|
@@ -5900,7 +5960,7 @@ var Supervisor = class {
|
|
|
5900
5960
|
const { daemonLog, logs } = this.options.paths;
|
|
5901
5961
|
mkdirSync10(logs, { recursive: true });
|
|
5902
5962
|
try {
|
|
5903
|
-
if (
|
|
5963
|
+
if (existsSync9(daemonLog) && statSync6(daemonLog).size > MAX_LOG_BYTES2)
|
|
5904
5964
|
renameSync4(daemonLog, `${daemonLog}.1`);
|
|
5905
5965
|
} catch {
|
|
5906
5966
|
}
|
|
@@ -6034,9 +6094,10 @@ Usage: friday <command>
|
|
|
6034
6094
|
|
|
6035
6095
|
start Make this computer a machine, with the folder this runs in as its root, where
|
|
6036
6096
|
Friday keeps its repos and conversations. Signs in through your browser when
|
|
6037
|
-
needed, asks
|
|
6038
|
-
in, waits for each agent to check in, then shows what's left to set up.
|
|
6039
|
-
run again. --agents claude,codex
|
|
6097
|
+
needed, asks how much of each agent you have, starts the daemon now and whenever
|
|
6098
|
+
you log in, waits for each agent to check in, then shows what's left to set up.
|
|
6099
|
+
Safe to run again. --agents claude=lot,codex=little sets the shares without
|
|
6100
|
+
asking: off, little, some or lot, where a bare name is some and one left out off
|
|
6040
6101
|
stop Stop the daemon until you log in again, or run friday start
|
|
6041
6102
|
status Whether the daemon is running, which version, and its root
|
|
6042
6103
|
logs [-f] Show the daemon's latest log lines. -f keeps following them
|
|
@@ -6138,13 +6199,13 @@ function agentsFlag(args) {
|
|
|
6138
6199
|
const parsed = parseAgents(value ?? "");
|
|
6139
6200
|
if ("unknown" in parsed) {
|
|
6140
6201
|
throw new StartError(
|
|
6141
|
-
`friday start doesn't
|
|
6202
|
+
`friday start doesn't understand ${parsed.unknown.join(", ")}. Name claude, codex or agy, each with =off, =little, =some or =lot if you like.`
|
|
6142
6203
|
);
|
|
6143
6204
|
}
|
|
6144
|
-
return parsed.
|
|
6205
|
+
return parsed.shares;
|
|
6145
6206
|
}
|
|
6146
6207
|
function attachTo(paths, terminal) {
|
|
6147
|
-
const herd =
|
|
6208
|
+
const herd = existsSync10(binOf(paths.current, "herd")) ? binOf(paths.current, "herd") : join13(dirname9(process.argv[1] ?? ""), "herd.mjs");
|
|
6148
6209
|
const child = spawn5(process.execPath, [herd, "attach", terminal], {
|
|
6149
6210
|
stdio: "inherit",
|
|
6150
6211
|
env: { ...process.env, HERD_HOME: paths.herdHome }
|
|
@@ -6200,7 +6261,7 @@ function runStatus(deps) {
|
|
|
6200
6261
|
return running ? 0 : 1;
|
|
6201
6262
|
}
|
|
6202
6263
|
function tail(path, count) {
|
|
6203
|
-
if (!
|
|
6264
|
+
if (!existsSync10(path)) return [];
|
|
6204
6265
|
const lines = readFileSync10(path, "utf8").split("\n");
|
|
6205
6266
|
if (lines.at(-1) === "") lines.pop();
|
|
6206
6267
|
return lines.slice(-count);
|
|
@@ -6208,7 +6269,7 @@ function tail(path, count) {
|
|
|
6208
6269
|
async function runLogs(args, deps) {
|
|
6209
6270
|
const { paths, print } = deps;
|
|
6210
6271
|
const follow = args.includes("-f") || args.includes("--follow");
|
|
6211
|
-
const files = [paths.supervisorLog, paths.daemonLog].filter((file) =>
|
|
6272
|
+
const files = [paths.supervisorLog, paths.daemonLog].filter((file) => existsSync10(file));
|
|
6212
6273
|
if (files.length === 0) {
|
|
6213
6274
|
print(`There are no logs in ${paths.logs} yet.`);
|
|
6214
6275
|
return 0;
|
|
@@ -6258,7 +6319,7 @@ init_define_HERD_PACKAGE();
|
|
|
6258
6319
|
init_define_HERD_PACKAGE();
|
|
6259
6320
|
import { spawn as spawn6 } from "node:child_process";
|
|
6260
6321
|
import { appendFileSync, readFileSync as readFileSync11 } from "node:fs";
|
|
6261
|
-
import { dirname as
|
|
6322
|
+
import { dirname as dirname10, join as join14 } from "node:path";
|
|
6262
6323
|
var DEPLOY_HOSTS = ["api.cloudflare.com", "api.github.com", "registry.npmjs.org"];
|
|
6263
6324
|
function buildPolicy(input) {
|
|
6264
6325
|
const platform2 = input.platform ?? process.platform;
|
|
@@ -6288,7 +6349,7 @@ function describePolicy(policy, platform2 = process.platform) {
|
|
|
6288
6349
|
const hosts = policy.network.allowedDomains.join(", ");
|
|
6289
6350
|
return `Sandboxed with ${kind}: the owner's home is unreadable, writes go only to the worktree and the build's home, and the only hosts it reaches are ${hosts}.`;
|
|
6290
6351
|
}
|
|
6291
|
-
var nodePrefix = (execPath = process.execPath) =>
|
|
6352
|
+
var nodePrefix = (execPath = process.execPath) => dirname10(dirname10(execPath));
|
|
6292
6353
|
var shellQuote = (args) => args.map((arg) => `'${arg.replace(/'/g, "'\\''")}'`).join(" ");
|
|
6293
6354
|
var BLOCKED_LOG = "blocked.log";
|
|
6294
6355
|
async function runSandboxed(args) {
|
|
@@ -6779,7 +6840,7 @@ init_define_HERD_PACKAGE();
|
|
|
6779
6840
|
// src/build-runner-key.ts
|
|
6780
6841
|
init_define_HERD_PACKAGE();
|
|
6781
6842
|
init_src();
|
|
6782
|
-
import { chmodSync as chmodSync3, existsSync as
|
|
6843
|
+
import { chmodSync as chmodSync3, existsSync as existsSync11, mkdirSync as mkdirSync11, readFileSync as readFileSync13, writeFileSync as writeFileSync9 } from "node:fs";
|
|
6783
6844
|
import { join as join15 } from "node:path";
|
|
6784
6845
|
import { z as z24 } from "zod";
|
|
6785
6846
|
var BUILDS_URL = "https://builds.herdingchats.com";
|
|
@@ -6791,7 +6852,7 @@ var runnerKeySchema = z24.object({
|
|
|
6791
6852
|
var runnerKeyPath = () => join15(herdHome(), "build-runner.json");
|
|
6792
6853
|
function readRunnerKey() {
|
|
6793
6854
|
const path = runnerKeyPath();
|
|
6794
|
-
if (!
|
|
6855
|
+
if (!existsSync11(path)) return null;
|
|
6795
6856
|
try {
|
|
6796
6857
|
return runnerKeySchema.parse(JSON.parse(readFileSync13(path, "utf8")));
|
|
6797
6858
|
} catch {
|
|
@@ -7765,7 +7826,7 @@ init_define_HERD_PACKAGE();
|
|
|
7765
7826
|
import { execFile as execFile2, execFileSync as execFileSync4, spawn as spawn7 } from "node:child_process";
|
|
7766
7827
|
import { createHash as createHash3, randomUUID as randomUUID4 } from "node:crypto";
|
|
7767
7828
|
import {
|
|
7768
|
-
existsSync as
|
|
7829
|
+
existsSync as existsSync12,
|
|
7769
7830
|
mkdirSync as mkdirSync15,
|
|
7770
7831
|
mkdtempSync,
|
|
7771
7832
|
readdirSync as readdirSync6,
|
|
@@ -7859,7 +7920,7 @@ var real2 = (path) => {
|
|
|
7859
7920
|
}
|
|
7860
7921
|
};
|
|
7861
7922
|
function worktreeOf(dir, store) {
|
|
7862
|
-
if (!
|
|
7923
|
+
if (!existsSync12(join20(dir, ".git"))) return false;
|
|
7863
7924
|
try {
|
|
7864
7925
|
return real2(git2(dir, "rev-parse", "--path-format=absolute", "--git-common-dir")) === real2(store);
|
|
7865
7926
|
} catch {
|
|
@@ -7871,10 +7932,10 @@ function cloneFolder(from, to) {
|
|
|
7871
7932
|
execFileSync4("cp", [...args, from, to]);
|
|
7872
7933
|
}
|
|
7873
7934
|
function moduleFolders(dir) {
|
|
7874
|
-
const found =
|
|
7935
|
+
const found = existsSync12(join20(dir, "node_modules")) ? ["node_modules"] : [];
|
|
7875
7936
|
for (const entry of readdirSync6(dir, { withFileTypes: true })) {
|
|
7876
7937
|
if (entry.isDirectory() && !entry.name.startsWith(".") && entry.name !== "node_modules") {
|
|
7877
|
-
if (
|
|
7938
|
+
if (existsSync12(join20(dir, entry.name, "node_modules")))
|
|
7878
7939
|
found.push(join20(entry.name, "node_modules"));
|
|
7879
7940
|
}
|
|
7880
7941
|
}
|
|
@@ -7970,11 +8031,11 @@ var BuildRunner = class _BuildRunner {
|
|
|
7970
8031
|
async ensureModules(dir) {
|
|
7971
8032
|
const wanted = lockHash(dir);
|
|
7972
8033
|
const marker = join20(dir, "node_modules", ".herd-lock");
|
|
7973
|
-
if (
|
|
8034
|
+
if (existsSync12(marker) && readFileSync16(marker, "utf8") === wanted) return;
|
|
7974
8035
|
const cache = join20(this.home(), "node_modules", wanted);
|
|
7975
8036
|
for (const folder of moduleFolders(dir))
|
|
7976
8037
|
rmSync12(join20(dir, folder), { recursive: true, force: true });
|
|
7977
|
-
if (
|
|
8038
|
+
if (existsSync12(join20(cache, ".complete"))) {
|
|
7978
8039
|
for (const folder of readFileSync16(join20(cache, ".complete"), "utf8").split("\n").filter(Boolean)) {
|
|
7979
8040
|
cloneFolder(join20(cache, folder), join20(dir, folder));
|
|
7980
8041
|
}
|
|
@@ -8156,7 +8217,7 @@ var BuildRunner = class _BuildRunner {
|
|
|
8156
8217
|
clearTimeout(timer);
|
|
8157
8218
|
if (status2 === 10)
|
|
8158
8219
|
return { ok: false, reason: "the sandbox let a build read the owner's files" };
|
|
8159
|
-
if (status2 !== 0 || !
|
|
8220
|
+
if (status2 !== 0 || !existsSync12(join20(dir, "home", "ok"))) {
|
|
8160
8221
|
const why = stderr.trim().split("\n").at(-1) || `the probe exited with ${status2}`;
|
|
8161
8222
|
return { ok: false, reason: why.slice(0, 300) };
|
|
8162
8223
|
}
|
|
@@ -8929,7 +8990,7 @@ init_define_HERD_PACKAGE();
|
|
|
8929
8990
|
import { execFileSync as execFileSync5 } from "node:child_process";
|
|
8930
8991
|
import {
|
|
8931
8992
|
appendFileSync as appendFileSync2,
|
|
8932
|
-
existsSync as
|
|
8993
|
+
existsSync as existsSync13,
|
|
8933
8994
|
mkdirSync as mkdirSync16,
|
|
8934
8995
|
readFileSync as readFileSync17,
|
|
8935
8996
|
renameSync as renameSync5,
|
|
@@ -8945,7 +9006,7 @@ var shellQuote2 = (value) => `'${value.replace(/'/g, `'\\''`)}'`;
|
|
|
8945
9006
|
function writeWorktreeSettings(worktree, settings2, ownCommand) {
|
|
8946
9007
|
const path = join22(worktree, LOCAL_SETTINGS);
|
|
8947
9008
|
let current = {};
|
|
8948
|
-
if (
|
|
9009
|
+
if (existsSync13(path)) {
|
|
8949
9010
|
try {
|
|
8950
9011
|
const parsed = JSON.parse(readFileSync17(path, "utf8"));
|
|
8951
9012
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return false;
|
|
@@ -8990,7 +9051,7 @@ function ignoreLocalSettings(worktree) {
|
|
|
8990
9051
|
const info = join22(isAbsolute3(common) ? common : join22(worktree, common), "info");
|
|
8991
9052
|
const exclude = join22(info, "exclude");
|
|
8992
9053
|
const line2 = "/.claude/settings.local.json";
|
|
8993
|
-
const existing =
|
|
9054
|
+
const existing = existsSync13(exclude) ? readFileSync17(exclude, "utf8") : "";
|
|
8994
9055
|
if (existing.split("\n").includes(line2)) return;
|
|
8995
9056
|
mkdirSync16(info, { recursive: true });
|
|
8996
9057
|
appendFileSync2(exclude, `${existing && !existing.endsWith("\n") ? "\n" : ""}${line2}
|
|
@@ -9039,7 +9100,7 @@ function loginShellEnv() {
|
|
|
9039
9100
|
|
|
9040
9101
|
// src/machine-checks.ts
|
|
9041
9102
|
init_define_HERD_PACKAGE();
|
|
9042
|
-
import { existsSync as
|
|
9103
|
+
import { existsSync as existsSync14, rmSync as rmSync13 } from "node:fs";
|
|
9043
9104
|
var REQUEST_POLL_MS = 2e3;
|
|
9044
9105
|
var MachineChecks = class {
|
|
9045
9106
|
constructor(options) {
|
|
@@ -9085,7 +9146,7 @@ var MachineChecks = class {
|
|
|
9085
9146
|
/** `friday start` asked for every agent to be activated again. */
|
|
9086
9147
|
takeRequest() {
|
|
9087
9148
|
const path = activationRequestPath(this.options.herdHome);
|
|
9088
|
-
if (!
|
|
9149
|
+
if (!existsSync14(path)) return;
|
|
9089
9150
|
rmSync13(path, { force: true });
|
|
9090
9151
|
this.activateChosen(true);
|
|
9091
9152
|
}
|
|
@@ -10623,7 +10684,7 @@ import {
|
|
|
10623
10684
|
statSync as statSync8,
|
|
10624
10685
|
writeFileSync as writeFileSync16
|
|
10625
10686
|
} from "node:fs";
|
|
10626
|
-
import { dirname as
|
|
10687
|
+
import { dirname as dirname11, join as join29, sep as sep2 } from "node:path";
|
|
10627
10688
|
import { Readable } from "node:stream";
|
|
10628
10689
|
import { pipeline } from "node:stream/promises";
|
|
10629
10690
|
|
|
@@ -10811,6 +10872,7 @@ function describe(worker, current) {
|
|
|
10811
10872
|
);
|
|
10812
10873
|
lines.push(` ${label3}: ${listed.join(", ")}`);
|
|
10813
10874
|
}
|
|
10875
|
+
lines.push(` share: ${SHARE_LABELS[worker.share]}`);
|
|
10814
10876
|
if (worker.priority !== 0) lines.push(` priority: ${worker.priority}`);
|
|
10815
10877
|
const repos = worker.repos.map(
|
|
10816
10878
|
(repo) => `${normalizeRemote(repo.remote) ?? repo.name} (${isCloned(repo) ? "cloned" : "not cloned"})`
|
|
@@ -11673,8 +11735,8 @@ async function download(ws, workspace, file) {
|
|
|
11673
11735
|
if (lstatSync2(herd, { throwIfNoEntry: false })?.isSymbolicLink()) {
|
|
11674
11736
|
throw new Error("its folder leads outside the worktree");
|
|
11675
11737
|
}
|
|
11676
|
-
mkdirSync20(
|
|
11677
|
-
if (!realpathSync8(
|
|
11738
|
+
mkdirSync20(dirname11(target), { recursive: true });
|
|
11739
|
+
if (!realpathSync8(dirname11(target)).startsWith(realpathSync8(workspace.folder) + sep2)) {
|
|
11678
11740
|
throw new Error("its folder leads outside the worktree");
|
|
11679
11741
|
}
|
|
11680
11742
|
writeFileSync16(join29(herd, ".gitignore"), "*\n");
|
|
@@ -12187,6 +12249,7 @@ async function runDaemon(args) {
|
|
|
12187
12249
|
const root = setRoot(defaultRoot()).root;
|
|
12188
12250
|
console.log(`No root folder is set for this machine, so it works from ${root}.`);
|
|
12189
12251
|
}
|
|
12252
|
+
await waitForRoot(machineRoot(), { pollMs: Number(process.env.HERD_ROOT_POLL_MS) || 2e3 });
|
|
12190
12253
|
const api = apiUrl();
|
|
12191
12254
|
const terminals = new HostTerminals({ log: (line2) => console.log(line2) });
|
|
12192
12255
|
await terminals.ensureHost();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@herdingchats/friday",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.522",
|
|
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": "3dab37264f9426b4af9a912efcddadf9fb04cdcc"
|
|
26
26
|
}
|