@herdingchats/friday 0.1.688 → 0.1.707
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 +433 -263
- package/package.json +2 -2
- package/terminal-host.mjs +12 -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.707", gitHead: "092263ddfd4398fa1093a095995b57b617e624d3" };
|
|
22
22
|
}
|
|
23
23
|
});
|
|
24
24
|
|
|
@@ -508,7 +508,13 @@ var init_terminals = __esm({
|
|
|
508
508
|
rows: z6.number().int().min(5).max(1e3)
|
|
509
509
|
};
|
|
510
510
|
terminalFrameSchema = z6.discriminatedUnion("type", [
|
|
511
|
-
|
|
511
|
+
// The screen, and its size, which a watcher draws it at. Hosts from before sizes don't say.
|
|
512
|
+
z6.object({
|
|
513
|
+
type: z6.literal("snapshot"),
|
|
514
|
+
data: z6.string(),
|
|
515
|
+
cols: size.cols.optional(),
|
|
516
|
+
rows: size.rows.optional()
|
|
517
|
+
}),
|
|
512
518
|
z6.object({ type: z6.literal("data"), data: z6.string() }),
|
|
513
519
|
z6.object({ type: z6.literal("exit"), exitCode: z6.number().int().nullable() }),
|
|
514
520
|
z6.object({ type: z6.literal("mode"), mode: terminalModeSchema }),
|
|
@@ -1507,7 +1513,10 @@ var init_events = __esm({
|
|
|
1507
1513
|
kind: z13.literal("bound"),
|
|
1508
1514
|
machine: z13.object({ name: nonEmpty6, online: z13.boolean() }),
|
|
1509
1515
|
// The worker's name, such as `mac-mini/claude`, and never its configuration or capabilities.
|
|
1510
|
-
worker: nonEmpty6.optional()
|
|
1516
|
+
worker: nonEmpty6.optional(),
|
|
1517
|
+
// Only for the machine's owner, while it's online: what they may do with its terminal from
|
|
1518
|
+
// the web. Absent for anyone else, and where the machine allows nothing or can't.
|
|
1519
|
+
terminal: z13.enum(["drive", "watch"]).optional()
|
|
1511
1520
|
}),
|
|
1512
1521
|
z13.object({ kind: z13.literal("waiting_for_machine") }),
|
|
1513
1522
|
z13.object({ kind: z13.literal("author_not_linked") })
|
|
@@ -1962,8 +1971,138 @@ var init_builds = __esm({
|
|
|
1962
1971
|
}
|
|
1963
1972
|
});
|
|
1964
1973
|
|
|
1965
|
-
// ../common-chat/src/
|
|
1974
|
+
// ../common-chat/src/gateway-spend.ts
|
|
1966
1975
|
import { z as z17 } from "zod";
|
|
1976
|
+
var spendLimitDimensionSchema, spendLimitRuleSchema, gatewaySettingsSchema, accountCreditsSchema, gatewayAnalyticsGroupSchema, gatewayAnalyticsResponseSchema, GATEWAY_SPEND_CACHE_MS, GATEWAY_SPEND_KEEP_MS, usd, modelSpendSchema, spendPeriodSchema, spendLimitScopeSchema, spendLimitSchema, creditBalanceSchema, gatewaySpendFiguresSchema, gatewaySpendResponseSchema;
|
|
1977
|
+
var init_gateway_spend = __esm({
|
|
1978
|
+
"../common-chat/src/gateway-spend.ts"() {
|
|
1979
|
+
"use strict";
|
|
1980
|
+
init_define_HERD_PACKAGE();
|
|
1981
|
+
spendLimitDimensionSchema = z17.discriminatedUnion("mode", [
|
|
1982
|
+
z17.object({ mode: z17.literal("partition") }),
|
|
1983
|
+
z17.object({ mode: z17.literal("filter"), values: z17.array(z17.string()) })
|
|
1984
|
+
]);
|
|
1985
|
+
spendLimitRuleSchema = z17.object({
|
|
1986
|
+
id: z17.string().min(1).optional(),
|
|
1987
|
+
enabled: z17.boolean().optional(),
|
|
1988
|
+
limit: z17.number().positive(),
|
|
1989
|
+
limitType: z17.string(),
|
|
1990
|
+
window: z17.number().positive(),
|
|
1991
|
+
technique: z17.enum(["fixed", "sliding"]).optional(),
|
|
1992
|
+
metadata: z17.record(z17.string(), spendLimitDimensionSchema).nullish(),
|
|
1993
|
+
model: spendLimitDimensionSchema.nullish(),
|
|
1994
|
+
provider: spendLimitDimensionSchema.nullish()
|
|
1995
|
+
});
|
|
1996
|
+
gatewaySettingsSchema = z17.object({
|
|
1997
|
+
id: z17.string(),
|
|
1998
|
+
spend_limits: z17.object({
|
|
1999
|
+
enabled: z17.boolean().optional(),
|
|
2000
|
+
rules: z17.array(spendLimitRuleSchema).nullish()
|
|
2001
|
+
}).nullish()
|
|
2002
|
+
});
|
|
2003
|
+
accountCreditsSchema = z17.object({
|
|
2004
|
+
confirmed_balance_cents: z17.number().nullish(),
|
|
2005
|
+
currency: z17.string().nullish(),
|
|
2006
|
+
days_remaining: z17.number().nullish(),
|
|
2007
|
+
eligible: z17.boolean().nullish(),
|
|
2008
|
+
has_record: z17.boolean().nullish(),
|
|
2009
|
+
original_amount_cents: z17.number().nullish(),
|
|
2010
|
+
percent_consumed: z17.number().nullish(),
|
|
2011
|
+
projected_depletion_date: z17.string().nullish(),
|
|
2012
|
+
valid_from: z17.string().nullish(),
|
|
2013
|
+
valid_to: z17.string().nullish()
|
|
2014
|
+
});
|
|
2015
|
+
gatewayAnalyticsGroupSchema = z17.object({
|
|
2016
|
+
count: z17.number().int().nonnegative(),
|
|
2017
|
+
sum: z17.object({ cost: z17.number().nullish() }).nullish(),
|
|
2018
|
+
dimensions: z17.object({ model: z17.string().nullish(), provider: z17.string().nullish() }).nullish()
|
|
2019
|
+
});
|
|
2020
|
+
gatewayAnalyticsResponseSchema = z17.object({
|
|
2021
|
+
data: z17.object({
|
|
2022
|
+
viewer: z17.object({
|
|
2023
|
+
accounts: z17.array(z17.record(z17.string(), z17.array(gatewayAnalyticsGroupSchema)))
|
|
2024
|
+
})
|
|
2025
|
+
}).nullish(),
|
|
2026
|
+
errors: z17.array(z17.object({ message: z17.string() })).nullish()
|
|
2027
|
+
});
|
|
2028
|
+
GATEWAY_SPEND_CACHE_MS = 5 * 60 * 1e3;
|
|
2029
|
+
GATEWAY_SPEND_KEEP_MS = 24 * 60 * 60 * 1e3;
|
|
2030
|
+
usd = z17.number().nonnegative();
|
|
2031
|
+
modelSpendSchema = z17.object({
|
|
2032
|
+
model: z17.string(),
|
|
2033
|
+
provider: z17.string().nullable(),
|
|
2034
|
+
costUsd: usd,
|
|
2035
|
+
requests: z17.number().int().nonnegative()
|
|
2036
|
+
});
|
|
2037
|
+
spendPeriodSchema = z17.object({
|
|
2038
|
+
since: z17.number().int(),
|
|
2039
|
+
costUsd: usd,
|
|
2040
|
+
requests: z17.number().int().nonnegative(),
|
|
2041
|
+
byModel: z17.array(modelSpendSchema)
|
|
2042
|
+
});
|
|
2043
|
+
spendLimitScopeSchema = z17.object({
|
|
2044
|
+
/** Only these models, or any model. */
|
|
2045
|
+
models: z17.array(z17.string()),
|
|
2046
|
+
/** Only these providers, or any provider. */
|
|
2047
|
+
providers: z17.array(z17.string()),
|
|
2048
|
+
/** Dimensions that give each value its own budget, such as `model` or `metadata:cf.user_id`. */
|
|
2049
|
+
splitBy: z17.array(z17.string()),
|
|
2050
|
+
/** Custom metadata keys the rule filters or splits by, such as `cf.user_id`. */
|
|
2051
|
+
metadata: z17.array(z17.string())
|
|
2052
|
+
});
|
|
2053
|
+
spendLimitSchema = z17.object({
|
|
2054
|
+
id: z17.string().nullable(),
|
|
2055
|
+
enabled: z17.boolean(),
|
|
2056
|
+
limitUsd: z17.number().positive(),
|
|
2057
|
+
windowSeconds: z17.number().positive(),
|
|
2058
|
+
/** `fixed` counts from the window's start, and `rolling` over its length up to now. */
|
|
2059
|
+
windowKind: z17.enum(["fixed", "rolling"]),
|
|
2060
|
+
scope: spendLimitScopeSchema,
|
|
2061
|
+
/** When the counted window started, in ms. */
|
|
2062
|
+
windowStart: z17.number().int(),
|
|
2063
|
+
/** When a fixed window starts again, in ms, or null for a rolling one. */
|
|
2064
|
+
resetsAt: z17.number().int().nullable(),
|
|
2065
|
+
/**
|
|
2066
|
+
* The estimated spend counted against it, and that as a share of the limit, which can pass 1.
|
|
2067
|
+
* For a rule split by model or provider, that's its fullest bucket, which `bucket` names. Null
|
|
2068
|
+
* when analytics can't attribute spend to its buckets, as for a rule on custom metadata.
|
|
2069
|
+
*/
|
|
2070
|
+
consumed: z17.object({ costUsd: usd, share: z17.number().nonnegative(), bucket: z17.string().nullable() }).nullable()
|
|
2071
|
+
});
|
|
2072
|
+
creditBalanceSchema = z17.object({ amount: z17.number(), currency: z17.string() });
|
|
2073
|
+
gatewaySpendFiguresSchema = z17.object({
|
|
2074
|
+
gateway: z17.string(),
|
|
2075
|
+
/** When Cloudflare was read, in ms. */
|
|
2076
|
+
readAt: z17.number().int(),
|
|
2077
|
+
today: spendPeriodSchema,
|
|
2078
|
+
month: spendPeriodSchema,
|
|
2079
|
+
/** Whether the gateway enforces its spend limits at all. */
|
|
2080
|
+
limitsEnabled: z17.boolean(),
|
|
2081
|
+
limits: z17.array(spendLimitSchema),
|
|
2082
|
+
credits: creditBalanceSchema.nullable(),
|
|
2083
|
+
/** Why the balance is missing, when it is. */
|
|
2084
|
+
creditsError: z17.string().nullable()
|
|
2085
|
+
});
|
|
2086
|
+
gatewaySpendResponseSchema = z17.discriminatedUnion("configured", [
|
|
2087
|
+
/** Before the read-only token is uploaded: what's missing, by binding name. */
|
|
2088
|
+
z17.object({ configured: z17.literal(false), missing: z17.array(z17.string()).min(1) }),
|
|
2089
|
+
z17.object({
|
|
2090
|
+
configured: z17.literal(true),
|
|
2091
|
+
/** Stand-in figures from `npm run dev`, never Cloudflare's. */
|
|
2092
|
+
local: z17.boolean(),
|
|
2093
|
+
/** Spend is Cloudflare's estimate from token counts and model pricing, not the bill. */
|
|
2094
|
+
estimated: z17.literal(true),
|
|
2095
|
+
/** The latest good figures, or null if no read has succeeded in the last day. */
|
|
2096
|
+
figures: gatewaySpendFiguresSchema.nullable(),
|
|
2097
|
+
/** Why the latest read failed, when it did. The figures are then the last good ones. */
|
|
2098
|
+
error: z17.string().nullable()
|
|
2099
|
+
})
|
|
2100
|
+
]);
|
|
2101
|
+
}
|
|
2102
|
+
});
|
|
2103
|
+
|
|
2104
|
+
// ../common-chat/src/setup.ts
|
|
2105
|
+
import { z as z18 } from "zod";
|
|
1967
2106
|
function actionText(action) {
|
|
1968
2107
|
if (action.kind === "link") return `${action.label}: ${action.url}`;
|
|
1969
2108
|
if (action.kind === "sign_in") {
|
|
@@ -1998,42 +2137,42 @@ var init_setup = __esm({
|
|
|
1998
2137
|
init_activation();
|
|
1999
2138
|
init_bot();
|
|
2000
2139
|
SETUP_STEP_IDS = ["slack", "machine", "github", "repos"];
|
|
2001
|
-
setupActionSchema =
|
|
2140
|
+
setupActionSchema = z18.discriminatedUnion("kind", [
|
|
2002
2141
|
/** A page to open, which signs in to HerdingChats first. */
|
|
2003
|
-
|
|
2142
|
+
z18.object({ kind: z18.literal("link"), url: z18.string(), label: z18.string() }),
|
|
2004
2143
|
/** A command to run on the computer. */
|
|
2005
|
-
|
|
2144
|
+
z18.object({ kind: z18.literal("command"), command: z18.string() }),
|
|
2006
2145
|
/**
|
|
2007
2146
|
* A sign-in herd starts on one of the person's machines, from Slack or the page, whose code
|
|
2008
2147
|
* Friday sends to their direct message.
|
|
2009
2148
|
*/
|
|
2010
|
-
|
|
2011
|
-
kind:
|
|
2012
|
-
machineId:
|
|
2149
|
+
z18.object({
|
|
2150
|
+
kind: z18.literal("sign_in"),
|
|
2151
|
+
machineId: z18.string(),
|
|
2013
2152
|
tool: signInToolSchema,
|
|
2014
|
-
label:
|
|
2153
|
+
label: z18.string()
|
|
2015
2154
|
})
|
|
2016
2155
|
]);
|
|
2017
|
-
setupStepSchema =
|
|
2018
|
-
id:
|
|
2156
|
+
setupStepSchema = z18.object({
|
|
2157
|
+
id: z18.enum(SETUP_STEP_IDS),
|
|
2019
2158
|
/** `unavailable` is a step nobody can take yet, such as GitHub linking before an admin turns it on. */
|
|
2020
|
-
state:
|
|
2021
|
-
optional:
|
|
2022
|
-
title:
|
|
2159
|
+
state: z18.enum(["done", "todo", "unavailable"]),
|
|
2160
|
+
optional: z18.boolean(),
|
|
2161
|
+
title: z18.string(),
|
|
2023
2162
|
/** What was found, such as the machine and whether it's online, or why it can't be done yet. */
|
|
2024
|
-
detail:
|
|
2163
|
+
detail: z18.string().nullable(),
|
|
2025
2164
|
/** What to do next. None once it's done, or while it's unavailable. */
|
|
2026
2165
|
action: setupActionSchema.nullable(),
|
|
2027
2166
|
/**
|
|
2028
2167
|
* More that can be done, which doesn't decide whether the step is done, such as signing in a
|
|
2029
2168
|
* computer's GitHub CLI. Shown whatever the step's state.
|
|
2030
2169
|
*/
|
|
2031
|
-
extra:
|
|
2170
|
+
extra: z18.array(setupActionSchema).optional()
|
|
2032
2171
|
});
|
|
2033
|
-
setupStatusSchema =
|
|
2034
|
-
steps:
|
|
2172
|
+
setupStatusSchema = z18.object({
|
|
2173
|
+
steps: z18.array(setupStepSchema),
|
|
2035
2174
|
/** Whether every step that isn't optional is done, so Friday can take work. */
|
|
2036
|
-
ready:
|
|
2175
|
+
ready: z18.boolean()
|
|
2037
2176
|
});
|
|
2038
2177
|
READY_TEXT = `You're set up: mention @${BOT_NAME} in any channel it's in, or message it directly.`;
|
|
2039
2178
|
READY_SUGGESTIONS_TITLE = "Some things to try:";
|
|
@@ -2068,6 +2207,7 @@ var init_src = __esm({
|
|
|
2068
2207
|
init_content();
|
|
2069
2208
|
init_conversation_state();
|
|
2070
2209
|
init_events();
|
|
2210
|
+
init_gateway_spend();
|
|
2071
2211
|
init_github();
|
|
2072
2212
|
init_github_triggers();
|
|
2073
2213
|
init_machines();
|
|
@@ -2485,7 +2625,7 @@ var init_widget = __esm({
|
|
|
2485
2625
|
});
|
|
2486
2626
|
|
|
2487
2627
|
// ../common-board/src/widgets/conversations.tsx
|
|
2488
|
-
import { z as
|
|
2628
|
+
import { z as z31 } from "zod";
|
|
2489
2629
|
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
2490
2630
|
function badge(item) {
|
|
2491
2631
|
if (pullRequestBadge(item)) {
|
|
@@ -2529,10 +2669,10 @@ var init_conversations = __esm({
|
|
|
2529
2669
|
conversations2 = defineWidget({
|
|
2530
2670
|
kind: "conversations",
|
|
2531
2671
|
describe: "Blocked, working and queued conversations, then the latest done, with what each is doing, where it came from and who holds it",
|
|
2532
|
-
options:
|
|
2533
|
-
states:
|
|
2534
|
-
limit:
|
|
2535
|
-
show:
|
|
2672
|
+
options: z31.object({
|
|
2673
|
+
states: z31.array(conversationStateSchema).min(1).default(["stuck", "working", "waiting", "done"]),
|
|
2674
|
+
limit: z31.number().int().min(1).max(BOARD_ITEMS).default(4),
|
|
2675
|
+
show: z31.array(z31.enum(DETAILS)).default([...DETAILS])
|
|
2536
2676
|
}),
|
|
2537
2677
|
reads: ["items", "machines"],
|
|
2538
2678
|
Component: ({ board, options, theme, now }) => {
|
|
@@ -2576,7 +2716,7 @@ var init_conversations = __esm({
|
|
|
2576
2716
|
});
|
|
2577
2717
|
|
|
2578
2718
|
// ../common-board/src/widgets/counts.tsx
|
|
2579
|
-
import { z as
|
|
2719
|
+
import { z as z32 } from "zod";
|
|
2580
2720
|
import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
2581
2721
|
var COUNTS, LABELS2, counts;
|
|
2582
2722
|
var init_counts = __esm({
|
|
@@ -2596,8 +2736,8 @@ var init_counts = __esm({
|
|
|
2596
2736
|
counts = defineWidget({
|
|
2597
2737
|
kind: "counts",
|
|
2598
2738
|
describe: "How many conversations are stuck, unanswered, waiting and working, and done today",
|
|
2599
|
-
options:
|
|
2600
|
-
show:
|
|
2739
|
+
options: z32.object({
|
|
2740
|
+
show: z32.array(z32.enum(COUNTS)).min(1).max(5).default([...COUNTS])
|
|
2601
2741
|
}),
|
|
2602
2742
|
reads: ["counts", "doneToday"],
|
|
2603
2743
|
Component: ({ board, options, theme }) => {
|
|
@@ -2636,7 +2776,7 @@ var init_counts = __esm({
|
|
|
2636
2776
|
});
|
|
2637
2777
|
|
|
2638
2778
|
// ../common-board/src/widgets/header.tsx
|
|
2639
|
-
import { z as
|
|
2779
|
+
import { z as z33 } from "zod";
|
|
2640
2780
|
import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
2641
2781
|
function summary(board) {
|
|
2642
2782
|
const parts = [
|
|
@@ -2661,9 +2801,9 @@ var init_header = __esm({
|
|
|
2661
2801
|
header = defineWidget({
|
|
2662
2802
|
kind: "header",
|
|
2663
2803
|
describe: "The board's title, a line of how much is open, and when it was drawn",
|
|
2664
|
-
options:
|
|
2665
|
-
title:
|
|
2666
|
-
summary:
|
|
2804
|
+
options: z33.object({
|
|
2805
|
+
title: z33.string().min(1).max(40).default(`@${BOT_NAME}`),
|
|
2806
|
+
summary: z33.boolean().default(true)
|
|
2667
2807
|
}),
|
|
2668
2808
|
reads: ["counts"],
|
|
2669
2809
|
Component: ({ board, options, theme, now }) => {
|
|
@@ -2681,7 +2821,7 @@ var init_header = __esm({
|
|
|
2681
2821
|
});
|
|
2682
2822
|
|
|
2683
2823
|
// ../common-board/src/widgets/machines.tsx
|
|
2684
|
-
import { z as
|
|
2824
|
+
import { z as z34 } from "zod";
|
|
2685
2825
|
import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
2686
2826
|
function usageText(worker) {
|
|
2687
2827
|
const usage = worker.usage;
|
|
@@ -2712,7 +2852,7 @@ var init_machines2 = __esm({
|
|
|
2712
2852
|
machines = defineWidget({
|
|
2713
2853
|
kind: "machines",
|
|
2714
2854
|
describe: "One bubble per agent on an online machine, with its usage, most recently active first",
|
|
2715
|
-
options:
|
|
2855
|
+
options: z34.object({ limit: z34.number().int().min(1).max(8).default(3) }),
|
|
2716
2856
|
reads: ["machines"],
|
|
2717
2857
|
Component: ({ board, options, theme }) => {
|
|
2718
2858
|
const workers2 = board.machines.filter((machine) => machine.online).flatMap((machine) => machine.workers.map((worker) => ({ ...worker, machine: machine.name }))).sort((a, b) => (b.reportedAt ?? 0) - (a.reportedAt ?? 0));
|
|
@@ -2829,9 +2969,9 @@ var init_board2 = __esm({
|
|
|
2829
2969
|
});
|
|
2830
2970
|
|
|
2831
2971
|
// ../common-board/src/composition.ts
|
|
2832
|
-
import { z as
|
|
2972
|
+
import { z as z35 } from "zod";
|
|
2833
2973
|
function readComposition(stored) {
|
|
2834
|
-
const shape =
|
|
2974
|
+
const shape = z35.object({ widgets: z35.array(placedWidgetSchema) }).safeParse(stored);
|
|
2835
2975
|
if (!shape.success) return DEFAULT_COMPOSITION;
|
|
2836
2976
|
const known = shape.data.widgets.filter(
|
|
2837
2977
|
(widget) => WIDGETS[widget.kind]?.options.safeParse(widget.options).success
|
|
@@ -2846,11 +2986,11 @@ var init_composition = __esm({
|
|
|
2846
2986
|
init_registry();
|
|
2847
2987
|
MAX_WIDGETS = 12;
|
|
2848
2988
|
MAX_COMPOSITION_BYTES = 4096;
|
|
2849
|
-
placedWidgetSchema =
|
|
2850
|
-
kind:
|
|
2851
|
-
options:
|
|
2989
|
+
placedWidgetSchema = z35.object({
|
|
2990
|
+
kind: z35.string().min(1),
|
|
2991
|
+
options: z35.record(z35.string(), z35.unknown()).default({})
|
|
2852
2992
|
});
|
|
2853
|
-
compositionSchema =
|
|
2993
|
+
compositionSchema = z35.object({ widgets: z35.array(placedWidgetSchema).max(MAX_WIDGETS) }).superRefine((composition, context2) => {
|
|
2854
2994
|
if (JSON.stringify(composition).length > MAX_COMPOSITION_BYTES) {
|
|
2855
2995
|
context2.addIssue({
|
|
2856
2996
|
code: "custom",
|
|
@@ -3310,7 +3450,7 @@ import { existsSync as existsSync12, readFileSync as readFileSync10 } from "node
|
|
|
3310
3450
|
import { homedir as homedir5 } from "node:os";
|
|
3311
3451
|
import { dirname as dirname10, join as join16 } from "node:path";
|
|
3312
3452
|
import { createInterface as createInterface2 } from "node:readline/promises";
|
|
3313
|
-
import { z as
|
|
3453
|
+
import { z as z24 } from "zod";
|
|
3314
3454
|
|
|
3315
3455
|
// src/auth.ts
|
|
3316
3456
|
init_define_HERD_PACKAGE();
|
|
@@ -3319,21 +3459,21 @@ import { chmodSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:
|
|
|
3319
3459
|
import { createServer } from "node:http";
|
|
3320
3460
|
import { homedir } from "node:os";
|
|
3321
3461
|
import { join } from "node:path";
|
|
3322
|
-
import { z as
|
|
3462
|
+
import { z as z19 } from "zod";
|
|
3323
3463
|
var herdHome = () => process.env.HERD_HOME ?? join(homedir(), ".herd");
|
|
3324
3464
|
var apiUrl = () => (process.env.HERD_API_URL ?? "https://api.herdingchats.com").replace(/\/+$/, "");
|
|
3325
3465
|
var isLocal = (url) => /^http:\/\/localhost:\d+\/?$/.test(url);
|
|
3326
3466
|
var localSignIn = () => process.env.HERD_LOCAL_SLACK ? { "X-Herd-Local-Slack": process.env.HERD_LOCAL_SLACK } : {};
|
|
3327
3467
|
var HerdError = class extends Error {
|
|
3328
3468
|
};
|
|
3329
|
-
var credentialsSchema =
|
|
3330
|
-
api:
|
|
3331
|
-
tokenEndpoint:
|
|
3332
|
-
revocationEndpoint:
|
|
3333
|
-
clientId:
|
|
3334
|
-
accessToken:
|
|
3335
|
-
accessTokenExpiresAt:
|
|
3336
|
-
refreshToken:
|
|
3469
|
+
var credentialsSchema = z19.object({
|
|
3470
|
+
api: z19.string(),
|
|
3471
|
+
tokenEndpoint: z19.string(),
|
|
3472
|
+
revocationEndpoint: z19.string().optional(),
|
|
3473
|
+
clientId: z19.string(),
|
|
3474
|
+
accessToken: z19.string(),
|
|
3475
|
+
accessTokenExpiresAt: z19.number(),
|
|
3476
|
+
refreshToken: z19.string()
|
|
3337
3477
|
});
|
|
3338
3478
|
var credentialsPath = () => join(herdHome(), "credentials.json");
|
|
3339
3479
|
function readCredentials() {
|
|
@@ -3349,16 +3489,16 @@ function writeCredentials(credentials) {
|
|
|
3349
3489
|
writeFileSync(credentialsPath(), JSON.stringify(credentials, null, 2), { mode: 384 });
|
|
3350
3490
|
chmodSync(credentialsPath(), 384);
|
|
3351
3491
|
}
|
|
3352
|
-
var metadataSchema =
|
|
3353
|
-
authorization_endpoint:
|
|
3354
|
-
token_endpoint:
|
|
3355
|
-
registration_endpoint:
|
|
3356
|
-
revocation_endpoint:
|
|
3492
|
+
var metadataSchema = z19.object({
|
|
3493
|
+
authorization_endpoint: z19.string(),
|
|
3494
|
+
token_endpoint: z19.string(),
|
|
3495
|
+
registration_endpoint: z19.string(),
|
|
3496
|
+
revocation_endpoint: z19.string().optional()
|
|
3357
3497
|
});
|
|
3358
|
-
var tokenSchema =
|
|
3359
|
-
access_token:
|
|
3360
|
-
refresh_token:
|
|
3361
|
-
expires_in:
|
|
3498
|
+
var tokenSchema = z19.object({
|
|
3499
|
+
access_token: z19.string().min(1),
|
|
3500
|
+
refresh_token: z19.string().min(1),
|
|
3501
|
+
expires_in: z19.number()
|
|
3362
3502
|
});
|
|
3363
3503
|
var base64url = (bytes) => bytes.toString("base64url");
|
|
3364
3504
|
async function postForm(url, fields) {
|
|
@@ -3467,7 +3607,7 @@ async function login(how, {
|
|
|
3467
3607
|
token_endpoint_auth_method: "none"
|
|
3468
3608
|
})
|
|
3469
3609
|
});
|
|
3470
|
-
const client =
|
|
3610
|
+
const client = z19.object({ client_id: z19.string() }).safeParse(await registration2.json());
|
|
3471
3611
|
if (!registration2.ok || !client.success) {
|
|
3472
3612
|
throw new HerdError("The sign-in server refused to register this tool.");
|
|
3473
3613
|
}
|
|
@@ -3705,7 +3845,7 @@ import { randomUUID } from "node:crypto";
|
|
|
3705
3845
|
import { existsSync as existsSync3, mkdirSync as mkdirSync4, readFileSync as readFileSync4, realpathSync as realpathSync2, writeFileSync as writeFileSync3 } from "node:fs";
|
|
3706
3846
|
import { homedir as homedir3, hostname } from "node:os";
|
|
3707
3847
|
import { basename, dirname as dirname4, join as join6, resolve } from "node:path";
|
|
3708
|
-
import { z as
|
|
3848
|
+
import { z as z20 } from "zod";
|
|
3709
3849
|
|
|
3710
3850
|
// src/login-shell.ts
|
|
3711
3851
|
init_define_HERD_PACKAGE();
|
|
@@ -4484,13 +4624,13 @@ function hasUnpushed(path) {
|
|
|
4484
4624
|
|
|
4485
4625
|
// src/config.ts
|
|
4486
4626
|
init_self();
|
|
4487
|
-
var repoSchema =
|
|
4488
|
-
var configSchema =
|
|
4489
|
-
machineId:
|
|
4490
|
-
machineName:
|
|
4491
|
-
repos:
|
|
4627
|
+
var repoSchema = z20.object({ name: z20.string(), path: z20.string(), remote: z20.string() });
|
|
4628
|
+
var configSchema = z20.object({
|
|
4629
|
+
machineId: z20.string(),
|
|
4630
|
+
machineName: z20.string(),
|
|
4631
|
+
repos: z20.array(repoSchema),
|
|
4492
4632
|
/** The machine's root folder, holding herd's clones and its conversations' folders. */
|
|
4493
|
-
root:
|
|
4633
|
+
root: z20.string().optional()
|
|
4494
4634
|
});
|
|
4495
4635
|
var configPath = () => join6(herdHome(), "config.json");
|
|
4496
4636
|
function save(config) {
|
|
@@ -4708,23 +4848,23 @@ init_src();
|
|
|
4708
4848
|
import { randomBytes as randomBytes4, randomUUID as randomUUID3 } from "node:crypto";
|
|
4709
4849
|
import { mkdirSync as mkdirSync6, readFileSync as readFileSync5, renameSync as renameSync2, rmSync as rmSync6, statSync as statSync4, writeFileSync as writeFileSync4 } from "node:fs";
|
|
4710
4850
|
import { dirname as dirname5, join as join8 } from "node:path";
|
|
4711
|
-
import { z as
|
|
4851
|
+
import { z as z23 } from "zod";
|
|
4712
4852
|
|
|
4713
4853
|
// src/permissions.ts
|
|
4714
4854
|
init_define_HERD_PACKAGE();
|
|
4715
4855
|
init_src();
|
|
4716
4856
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
4717
|
-
import { z as
|
|
4857
|
+
import { z as z22 } from "zod";
|
|
4718
4858
|
|
|
4719
4859
|
// src/local-socket.ts
|
|
4720
4860
|
init_define_HERD_PACKAGE();
|
|
4721
4861
|
import { randomBytes as randomBytes3 } from "node:crypto";
|
|
4722
4862
|
import { chmodSync as chmodSync2, existsSync as existsSync4, rmSync as rmSync4 } from "node:fs";
|
|
4723
4863
|
import { connect, createServer as createServer2 } from "node:net";
|
|
4724
|
-
import { z as
|
|
4725
|
-
var localRequestSchema =
|
|
4726
|
-
secret:
|
|
4727
|
-
op:
|
|
4864
|
+
import { z as z21 } from "zod";
|
|
4865
|
+
var localRequestSchema = z21.object({
|
|
4866
|
+
secret: z21.string().min(1),
|
|
4867
|
+
op: z21.enum([
|
|
4728
4868
|
"inbox",
|
|
4729
4869
|
"send",
|
|
4730
4870
|
"run",
|
|
@@ -4756,32 +4896,32 @@ var localRequestSchema = z20.object({
|
|
|
4756
4896
|
"activate"
|
|
4757
4897
|
]),
|
|
4758
4898
|
// The key of the agent's start, from `HERD_START`, which `herd inbox` proves the start with.
|
|
4759
|
-
start:
|
|
4899
|
+
start: z21.string().min(1).max(100).optional(),
|
|
4760
4900
|
// `herd repo`: the repo it added to the conversation's folder, for the daemon to record.
|
|
4761
|
-
repo:
|
|
4762
|
-
remote:
|
|
4763
|
-
folder:
|
|
4764
|
-
base:
|
|
4765
|
-
fetchFailed:
|
|
4901
|
+
repo: z21.object({
|
|
4902
|
+
remote: z21.string().min(1).max(500),
|
|
4903
|
+
folder: z21.string().min(1).max(100),
|
|
4904
|
+
base: z21.string().min(1).max(300).optional(),
|
|
4905
|
+
fetchFailed: z21.string().max(1e3).optional()
|
|
4766
4906
|
}).optional(),
|
|
4767
4907
|
// `herd repo`: what the agent named and the folder it asked for, for the daemon to add.
|
|
4768
|
-
repoAdd:
|
|
4769
|
-
asked:
|
|
4770
|
-
folder:
|
|
4908
|
+
repoAdd: z21.object({
|
|
4909
|
+
asked: z21.string().min(1).max(500),
|
|
4910
|
+
folder: z21.string().min(1).max(100).optional()
|
|
4771
4911
|
}).optional(),
|
|
4772
4912
|
// `herd delegate --repo`, given once for each repo the delegate works in.
|
|
4773
|
-
repos:
|
|
4913
|
+
repos: z21.array(z21.string().min(1).max(500)).max(10).optional(),
|
|
4774
4914
|
// `herd watch`, `herd unwatch` and `herd watching`: what to do, and the pull request.
|
|
4775
|
-
watch:
|
|
4776
|
-
action:
|
|
4777
|
-
url:
|
|
4915
|
+
watch: z21.object({
|
|
4916
|
+
action: z21.enum(["watch", "unwatch", "list"]),
|
|
4917
|
+
url: z21.string().min(1).max(500).optional()
|
|
4778
4918
|
}).optional(),
|
|
4779
4919
|
// `herd delegate`, `herd tell` and `herd handoff`: the worker or conversation they name.
|
|
4780
|
-
worker:
|
|
4781
|
-
to:
|
|
4920
|
+
worker: z21.string().min(1).max(200).optional(),
|
|
4921
|
+
to: z21.string().min(1).max(200).optional(),
|
|
4782
4922
|
// `herd automations`: what to do, to which automation, and the definition or change it sends.
|
|
4783
|
-
automation:
|
|
4784
|
-
action:
|
|
4923
|
+
automation: z21.object({
|
|
4924
|
+
action: z21.enum([
|
|
4785
4925
|
"list",
|
|
4786
4926
|
"show",
|
|
4787
4927
|
"create",
|
|
@@ -4792,47 +4932,47 @@ var localRequestSchema = z20.object({
|
|
|
4792
4932
|
"test",
|
|
4793
4933
|
"rotate"
|
|
4794
4934
|
]),
|
|
4795
|
-
id:
|
|
4796
|
-
body:
|
|
4797
|
-
waitMs:
|
|
4935
|
+
id: z21.string().min(1).max(100).optional(),
|
|
4936
|
+
body: z21.record(z21.string(), z21.unknown()).optional(),
|
|
4937
|
+
waitMs: z21.number().int().min(0).max(6e5).optional()
|
|
4798
4938
|
}).optional(),
|
|
4799
4939
|
// `herd work`: list, record or remove one, with the change the daemon checks again.
|
|
4800
|
-
work:
|
|
4801
|
-
action:
|
|
4802
|
-
change:
|
|
4803
|
-
url:
|
|
4940
|
+
work: z21.object({
|
|
4941
|
+
action: z21.enum(["list", "record", "remove"]),
|
|
4942
|
+
change: z21.unknown().optional(),
|
|
4943
|
+
url: z21.string().min(1).max(2048).optional()
|
|
4804
4944
|
}).optional(),
|
|
4805
4945
|
// `herd conversations --about <url>`: only the owner's conversations about that URL.
|
|
4806
|
-
about:
|
|
4946
|
+
about: z21.string().min(1).max(2048).optional(),
|
|
4807
4947
|
// `herd investigate screen` or `herd investigate propose`, with the proposal the daemon checks.
|
|
4808
|
-
action:
|
|
4809
|
-
proposal:
|
|
4948
|
+
action: z21.enum(["screen", "propose"]).optional(),
|
|
4949
|
+
proposal: z21.unknown().optional(),
|
|
4810
4950
|
// Commands may name a conversation, but only their own is ever allowed.
|
|
4811
|
-
conversationId:
|
|
4951
|
+
conversationId: z21.string().optional(),
|
|
4812
4952
|
// Where `conversations` is shown, which decides whether private titles are. Only the terminal's
|
|
4813
4953
|
// own conversation is ever allowed, so a terminal can't pick one that shows more.
|
|
4814
|
-
for:
|
|
4815
|
-
text:
|
|
4954
|
+
for: z21.string().optional(),
|
|
4955
|
+
text: z21.string().optional(),
|
|
4816
4956
|
// A whole message, from `herd send --json`, which the daemon checks again.
|
|
4817
|
-
message:
|
|
4818
|
-
idempotencyKey:
|
|
4819
|
-
command:
|
|
4957
|
+
message: z21.unknown().optional(),
|
|
4958
|
+
idempotencyKey: z21.string().optional(),
|
|
4959
|
+
command: z21.array(z21.string()).optional(),
|
|
4820
4960
|
// `status --clear`.
|
|
4821
|
-
clear:
|
|
4961
|
+
clear: z21.boolean().optional(),
|
|
4822
4962
|
// What an agent's status line reported, checked by the daemon.
|
|
4823
|
-
usage:
|
|
4963
|
+
usage: z21.unknown().optional(),
|
|
4824
4964
|
// Which agent and session a status line ran for. Its reports count only from the session herd
|
|
4825
4965
|
// started in the conversation's lead terminal.
|
|
4826
|
-
agent:
|
|
4827
|
-
sessionId:
|
|
4966
|
+
agent: z21.enum(["claude-code", "codex", "agy"]).optional(),
|
|
4967
|
+
sessionId: z21.string().min(1).max(200).optional(),
|
|
4828
4968
|
// What agy's status line says its agent is doing: `working` or `idle`.
|
|
4829
|
-
state:
|
|
4969
|
+
state: z21.enum(["working", "idle"]).optional(),
|
|
4830
4970
|
// A permission request from Claude Code's hook, with the key it keeps across reconnects.
|
|
4831
|
-
key:
|
|
4832
|
-
request:
|
|
4971
|
+
key: z21.string().min(1).max(200).optional(),
|
|
4972
|
+
request: z21.unknown().optional(),
|
|
4833
4973
|
// For one of Claude Code's other hooks: which event, and the JSON Claude Code gave it.
|
|
4834
|
-
event:
|
|
4835
|
-
input:
|
|
4974
|
+
event: z21.string().optional(),
|
|
4975
|
+
input: z21.record(z21.string(), z21.unknown()).optional()
|
|
4836
4976
|
});
|
|
4837
4977
|
var LocalSocket = class {
|
|
4838
4978
|
constructor(path, handle) {
|
|
@@ -4954,10 +5094,10 @@ function isAnswering(path) {
|
|
|
4954
5094
|
}
|
|
4955
5095
|
|
|
4956
5096
|
// src/permissions.ts
|
|
4957
|
-
var hookRequestSchema =
|
|
4958
|
-
tool_name:
|
|
4959
|
-
tool_input:
|
|
4960
|
-
permission_suggestions:
|
|
5097
|
+
var hookRequestSchema = z22.looseObject({
|
|
5098
|
+
tool_name: z22.string().min(1),
|
|
5099
|
+
tool_input: z22.record(z22.string(), z22.unknown()).default({}),
|
|
5100
|
+
permission_suggestions: z22.array(z22.unknown()).optional()
|
|
4961
5101
|
});
|
|
4962
5102
|
var DETAIL_LIMIT = 2800;
|
|
4963
5103
|
var REPLY_MESSAGE_LIMIT = 2e3;
|
|
@@ -5407,9 +5547,9 @@ var activationTerminal = (agent) => `herd-activate-${agentShortName(agent)}`;
|
|
|
5407
5547
|
var activationFolder = (root, agent) => join8(convosHome(root), ".activate", agentShortName(agent));
|
|
5408
5548
|
var recordSchema = agentActivationSchema.extend({
|
|
5409
5549
|
/** While it's waiting: the terminal it runs in, which `friday start` can attach to. */
|
|
5410
|
-
terminal:
|
|
5550
|
+
terminal: z23.string().optional()
|
|
5411
5551
|
});
|
|
5412
|
-
var storeSchema =
|
|
5552
|
+
var storeSchema = z23.object({ agents: z23.record(z23.string(), recordSchema) });
|
|
5413
5553
|
var activationsPath = (home = herdHome()) => join8(home, "activations.json");
|
|
5414
5554
|
var activationRequestPath = (home = herdHome()) => join8(home, "activate-request");
|
|
5415
5555
|
function readActivations(path = activationsPath()) {
|
|
@@ -5496,6 +5636,25 @@ var Activator = class {
|
|
|
5496
5636
|
}
|
|
5497
5637
|
this.request([{ name: agent, version }]);
|
|
5498
5638
|
}
|
|
5639
|
+
/**
|
|
5640
|
+
* The terminal an agent's activation runs in, for its owner to sign in from the web. One that
|
|
5641
|
+
* isn't running is started, and its terminal named once it's open. Null if it didn't open.
|
|
5642
|
+
*/
|
|
5643
|
+
async terminalFor(agent, version, { waitMs = 6e4, pollMs = 200 } = {}) {
|
|
5644
|
+
if (this.current?.agent !== agent) this.request([{ name: agent, version }], { force: true });
|
|
5645
|
+
const until = Date.now() + waitMs;
|
|
5646
|
+
while (Date.now() < until && !this.stopped) {
|
|
5647
|
+
const current = this.current;
|
|
5648
|
+
if (current?.agent === agent) {
|
|
5649
|
+
const open = (await this.options.terminals.list().catch(() => [])).some(
|
|
5650
|
+
(t) => t.name === current.terminal && !t.exited
|
|
5651
|
+
);
|
|
5652
|
+
if (open) return current.terminal;
|
|
5653
|
+
}
|
|
5654
|
+
await new Promise((resolve8) => setTimeout(resolve8, pollMs));
|
|
5655
|
+
}
|
|
5656
|
+
return null;
|
|
5657
|
+
}
|
|
5499
5658
|
/** Resolves once nothing is queued or running, as tests wait for. */
|
|
5500
5659
|
async settled() {
|
|
5501
5660
|
while (this.running) await this.running;
|
|
@@ -5596,7 +5755,8 @@ var Activator = class {
|
|
|
5596
5755
|
async waitForCheckIn(version, driver, current, folder, wasSignedOut) {
|
|
5597
5756
|
const { terminals } = this.options;
|
|
5598
5757
|
const { agent } = current;
|
|
5599
|
-
const
|
|
5758
|
+
const deadlineMs = this.options.deadlineMs ?? ACTIVATION_DEADLINE_MS;
|
|
5759
|
+
let deadline = Date.now() + deadlineMs;
|
|
5600
5760
|
const restartMs = this.options.signInRestartMs ?? SIGN_IN_RESTART_MS;
|
|
5601
5761
|
const checkInMs = this.options.checkInMs ?? CHECK_IN_MS;
|
|
5602
5762
|
const pollMs = this.options.pollMs ?? ACTIVATION_POLL_MS;
|
|
@@ -5632,6 +5792,8 @@ var Activator = class {
|
|
|
5632
5792
|
};
|
|
5633
5793
|
await start();
|
|
5634
5794
|
while (!current.checkedIn && Date.now() < deadline && !this.stopped) {
|
|
5795
|
+
const lookers = lookingAt((await terminals.list()).find((t) => t.name === current.terminal));
|
|
5796
|
+
if (lookers > 0) deadline = Math.max(deadline, Date.now() + deadlineMs);
|
|
5635
5797
|
const reading = await driver.read(current.terminal).catch(() => null);
|
|
5636
5798
|
if (reading?.state === "signed_out" && Date.now() - startedAt >= checkInMs) {
|
|
5637
5799
|
seen = "signed_out";
|
|
@@ -7147,7 +7309,7 @@ function defaults() {
|
|
|
7147
7309
|
print: (line2) => console.log(line2)
|
|
7148
7310
|
};
|
|
7149
7311
|
}
|
|
7150
|
-
var releaseSchema =
|
|
7312
|
+
var releaseSchema = z24.object({ version: z24.string().min(1), integrity: z24.string().min(1) });
|
|
7151
7313
|
async function fetchRelease() {
|
|
7152
7314
|
const response = await apiFetch("/api/daemon/release");
|
|
7153
7315
|
if (response.status === 404) return null;
|
|
@@ -7788,11 +7950,11 @@ init_define_HERD_PACKAGE();
|
|
|
7788
7950
|
// src/investigator.ts
|
|
7789
7951
|
init_define_HERD_PACKAGE();
|
|
7790
7952
|
init_src();
|
|
7791
|
-
import { z as
|
|
7953
|
+
import { z as z25 } from "zod";
|
|
7792
7954
|
var INVESTIGATE_KEYS = ["escape", "up", "down", "enter", "tab"];
|
|
7793
|
-
var proposalSchema =
|
|
7794
|
-
key:
|
|
7795
|
-
reason:
|
|
7955
|
+
var proposalSchema = z25.object({
|
|
7956
|
+
key: z25.enum([...INVESTIGATE_KEYS, "none"]),
|
|
7957
|
+
reason: z25.string().trim().min(1).max(300)
|
|
7796
7958
|
});
|
|
7797
7959
|
var KEY_LABELS = {
|
|
7798
7960
|
escape: "Esc",
|
|
@@ -8202,12 +8364,12 @@ init_define_HERD_PACKAGE();
|
|
|
8202
8364
|
init_src();
|
|
8203
8365
|
import { chmodSync as chmodSync3, existsSync as existsSync14, mkdirSync as mkdirSync14, readFileSync as readFileSync14, writeFileSync as writeFileSync10 } from "node:fs";
|
|
8204
8366
|
import { join as join19 } from "node:path";
|
|
8205
|
-
import { z as
|
|
8367
|
+
import { z as z26 } from "zod";
|
|
8206
8368
|
var BUILDS_URL = "https://builds.herdingchats.com";
|
|
8207
|
-
var runnerKeySchema =
|
|
8208
|
-
runnerId:
|
|
8209
|
-
key:
|
|
8210
|
-
url:
|
|
8369
|
+
var runnerKeySchema = z26.object({
|
|
8370
|
+
runnerId: z26.string().min(1),
|
|
8371
|
+
key: z26.string().min(20),
|
|
8372
|
+
url: z26.string().url()
|
|
8211
8373
|
});
|
|
8212
8374
|
var runnerKeyPath = () => join19(herdHome(), "build-runner.json");
|
|
8213
8375
|
function readRunnerKey() {
|
|
@@ -8276,33 +8438,33 @@ async function registerRunner({
|
|
|
8276
8438
|
|
|
8277
8439
|
// src/build-speed.ts
|
|
8278
8440
|
init_define_HERD_PACKAGE();
|
|
8279
|
-
import { z as
|
|
8280
|
-
var ms =
|
|
8281
|
-
var figuresSchema =
|
|
8282
|
-
var buildTimesSchema =
|
|
8283
|
-
var stepFiguresSchema =
|
|
8284
|
-
ran:
|
|
8285
|
-
remembered:
|
|
8441
|
+
import { z as z27 } from "zod";
|
|
8442
|
+
var ms = z27.number().int().nullable();
|
|
8443
|
+
var figuresSchema = z27.object({ count: z27.number().int(), median: ms, p90: ms });
|
|
8444
|
+
var buildTimesSchema = z27.object({ run: figuresSchema, push: figuresSchema });
|
|
8445
|
+
var stepFiguresSchema = z27.object({
|
|
8446
|
+
ran: z27.number().int(),
|
|
8447
|
+
remembered: z27.number().int(),
|
|
8286
8448
|
median: ms,
|
|
8287
8449
|
p90: ms,
|
|
8288
|
-
overBudget:
|
|
8450
|
+
overBudget: z27.number().int()
|
|
8289
8451
|
});
|
|
8290
|
-
var kindSchema =
|
|
8291
|
-
builds:
|
|
8292
|
-
steps:
|
|
8293
|
-
|
|
8452
|
+
var kindSchema = z27.object({
|
|
8453
|
+
builds: z27.object({ current: buildTimesSchema, previous: buildTimesSchema }),
|
|
8454
|
+
steps: z27.array(
|
|
8455
|
+
z27.object({ label: z27.string(), current: stepFiguresSchema, previous: stepFiguresSchema })
|
|
8294
8456
|
),
|
|
8295
|
-
overBudget:
|
|
8296
|
-
|
|
8457
|
+
overBudget: z27.array(
|
|
8458
|
+
z27.object({ label: z27.string(), current: z27.number().int(), previous: z27.number().int() })
|
|
8297
8459
|
)
|
|
8298
8460
|
});
|
|
8299
|
-
var range =
|
|
8300
|
-
var speedReportSchema =
|
|
8301
|
-
periods:
|
|
8302
|
-
repos:
|
|
8303
|
-
|
|
8304
|
-
repo:
|
|
8305
|
-
capped:
|
|
8461
|
+
var range = z27.object({ from: z27.number(), to: z27.number() });
|
|
8462
|
+
var speedReportSchema = z27.object({
|
|
8463
|
+
periods: z27.object({ current: range, previous: range }),
|
|
8464
|
+
repos: z27.array(
|
|
8465
|
+
z27.object({
|
|
8466
|
+
repo: z27.string(),
|
|
8467
|
+
capped: z27.boolean(),
|
|
8306
8468
|
pullRequests: kindSchema,
|
|
8307
8469
|
main: kindSchema
|
|
8308
8470
|
})
|
|
@@ -11068,9 +11230,13 @@ var Session = class {
|
|
|
11068
11230
|
});
|
|
11069
11231
|
}
|
|
11070
11232
|
fromHost(message) {
|
|
11071
|
-
|
|
11233
|
+
const size2 = typeof message.cols === "number" && typeof message.rows === "number" ? { cols: message.cols, rows: message.rows } : null;
|
|
11234
|
+
if (message.type === "resize" && size2) {
|
|
11235
|
+
this.flush();
|
|
11236
|
+
this.send({ type: "resize", ...size2 });
|
|
11237
|
+
} else if (message.type === "snapshot") {
|
|
11072
11238
|
this.pending = "";
|
|
11073
|
-
this.send({ type: "snapshot", data: message.data ?? "" });
|
|
11239
|
+
this.send({ type: "snapshot", data: message.data ?? "", ...size2 ?? {} });
|
|
11074
11240
|
} else if (message.type === "data") {
|
|
11075
11241
|
if (this.behind) return;
|
|
11076
11242
|
this.pending += message.data ?? "";
|
|
@@ -11240,7 +11406,7 @@ init_define_HERD_PACKAGE();
|
|
|
11240
11406
|
init_src();
|
|
11241
11407
|
init_self();
|
|
11242
11408
|
import { join as join28 } from "node:path";
|
|
11243
|
-
import { z as
|
|
11409
|
+
import { z as z28 } from "zod";
|
|
11244
11410
|
function hasThread(events) {
|
|
11245
11411
|
return events.some(
|
|
11246
11412
|
(event2) => event2.type === "prompt.opened" || event2.type === "message.created" && !(event2.payload.direction === "inbound" && event2.payload.automation) && !event2.payload.quiet && !event2.payload.post
|
|
@@ -11306,16 +11472,16 @@ var WAITING_NOTIFICATIONS = /* @__PURE__ */ new Set([
|
|
|
11306
11472
|
"agent_needs_input",
|
|
11307
11473
|
"elicitation_dialog"
|
|
11308
11474
|
]);
|
|
11309
|
-
var agentMessageSchema =
|
|
11310
|
-
text:
|
|
11311
|
-
files:
|
|
11475
|
+
var agentMessageSchema = z28.object({
|
|
11476
|
+
text: z28.string().trim().min(1).max(12e3),
|
|
11477
|
+
files: z28.array(z28.object({ path: z28.string().min(1), title: z28.string().optional() })).max(10).optional()
|
|
11312
11478
|
});
|
|
11313
|
-
var workspaceRepoSchema =
|
|
11314
|
-
folder:
|
|
11315
|
-
remote:
|
|
11316
|
-
branch:
|
|
11479
|
+
var workspaceRepoSchema = z28.object({
|
|
11480
|
+
folder: z28.string(),
|
|
11481
|
+
remote: z28.string(),
|
|
11482
|
+
branch: z28.string(),
|
|
11317
11483
|
/** For a conversation from before folders: the name of the repo it was allowed as. */
|
|
11318
|
-
name:
|
|
11484
|
+
name: z28.string().optional()
|
|
11319
11485
|
});
|
|
11320
11486
|
function fromBeforeFolders(raw) {
|
|
11321
11487
|
if (!raw || typeof raw !== "object" || "folder" in raw) return raw;
|
|
@@ -11336,106 +11502,106 @@ function fromBeforeFolders(raw) {
|
|
|
11336
11502
|
legacy: true
|
|
11337
11503
|
};
|
|
11338
11504
|
}
|
|
11339
|
-
var workspaceFields =
|
|
11340
|
-
conversationId:
|
|
11505
|
+
var workspaceFields = z28.object({
|
|
11506
|
+
conversationId: z28.string(),
|
|
11341
11507
|
/** The conversation's own folder, where its terminals start. */
|
|
11342
|
-
folder:
|
|
11508
|
+
folder: z28.string(),
|
|
11343
11509
|
/** The repos in it, in the order they were added. */
|
|
11344
|
-
worktrees:
|
|
11510
|
+
worktrees: z28.array(workspaceRepoSchema).default([]),
|
|
11345
11511
|
/** A conversation from before folders, which works in its one repo's worktree. */
|
|
11346
|
-
legacy:
|
|
11347
|
-
lead:
|
|
11348
|
-
secret:
|
|
11349
|
-
readSeq:
|
|
11350
|
-
claimId:
|
|
11351
|
-
claimRenewedAt:
|
|
11352
|
-
started:
|
|
11512
|
+
legacy: z28.boolean().default(false),
|
|
11513
|
+
lead: z28.string(),
|
|
11514
|
+
secret: z28.string(),
|
|
11515
|
+
readSeq: z28.number(),
|
|
11516
|
+
claimId: z28.string().nullable(),
|
|
11517
|
+
claimRenewedAt: z28.number(),
|
|
11518
|
+
started: z28.boolean(),
|
|
11353
11519
|
/** Messages to deliver once the current turn ends. */
|
|
11354
|
-
deferred:
|
|
11520
|
+
deferred: z28.boolean(),
|
|
11355
11521
|
/** A `herd run` command finished, which the agent hears about even with nothing to claim. */
|
|
11356
|
-
terminalNotice:
|
|
11357
|
-
status:
|
|
11522
|
+
terminalNotice: z28.boolean().default(false),
|
|
11523
|
+
status: z28.string().nullable(),
|
|
11358
11524
|
/** Set once the thread has been told the agent is waiting, so it's told once per wait. */
|
|
11359
|
-
toldWaiting:
|
|
11360
|
-
runs:
|
|
11525
|
+
toldWaiting: z28.boolean(),
|
|
11526
|
+
runs: z28.array(z28.object({ name: z28.string(), secret: z28.string(), reported: z28.boolean() })),
|
|
11361
11527
|
/** The subscription usage Claude Code last reported in this worktree. */
|
|
11362
11528
|
usage: usageSchema.nullable().default(null),
|
|
11363
11529
|
/** When that usage was reported, or 0 if it was before this was kept. */
|
|
11364
|
-
usageAt:
|
|
11530
|
+
usageAt: z28.number().default(0),
|
|
11365
11531
|
/** The lead agent's Claude Code session, as its `SessionStart` hook reported it. */
|
|
11366
|
-
sessionId:
|
|
11532
|
+
sessionId: z28.string().nullable().default(null),
|
|
11367
11533
|
/** When the agent's last turn ended with nothing left to do, for shutting it down later. */
|
|
11368
|
-
idleSince:
|
|
11534
|
+
idleSince: z28.number().nullable().default(null),
|
|
11369
11535
|
/** The agent ran `herd exit`, so its session ends after this turn. */
|
|
11370
|
-
exitRequested:
|
|
11536
|
+
exitRequested: z28.boolean().default(false),
|
|
11371
11537
|
/** Whether the agent sent anything with `herd send` this turn. */
|
|
11372
|
-
sentThisTurn:
|
|
11538
|
+
sentThisTurn: z28.boolean().default(false),
|
|
11373
11539
|
/** Whether it's been asked this turn to reply. */
|
|
11374
|
-
askedToReply:
|
|
11540
|
+
askedToReply: z28.boolean().default(false),
|
|
11375
11541
|
/** Whether it ran `herd handled` this turn, which handles the turn's messages with no reply. */
|
|
11376
|
-
handledThisTurn:
|
|
11542
|
+
handledThisTurn: z28.boolean().default(false),
|
|
11377
11543
|
/** The newest waiting message it's been pointed at, so one arrival is pointed out once. */
|
|
11378
|
-
nudgedSeq:
|
|
11544
|
+
nudgedSeq: z28.number().default(0),
|
|
11379
11545
|
/** When a `Stop` hook last ended a turn. */
|
|
11380
|
-
hookIdleAt:
|
|
11546
|
+
hookIdleAt: z28.number().default(0),
|
|
11381
11547
|
/** When a turn last ended with background work still running, which keeps its messages held. */
|
|
11382
|
-
pausedAt:
|
|
11548
|
+
pausedAt: z28.number().nullable().default(null),
|
|
11383
11549
|
/** The version of the terminal host the lead terminal was opened in, if it was recorded. */
|
|
11384
|
-
hostVersion:
|
|
11550
|
+
hostVersion: z28.string().nullable().default(null),
|
|
11385
11551
|
/** When a notice last failed for a reason other than someone's draft, to wait before retrying. */
|
|
11386
|
-
noticeFailedAt:
|
|
11552
|
+
noticeFailedAt: z28.number().nullable().default(null),
|
|
11387
11553
|
/** Why the last notice failed, so the history records each reason once, not every attempt. */
|
|
11388
|
-
noticeFailure:
|
|
11554
|
+
noticeFailure: z28.string().nullable().default(null),
|
|
11389
11555
|
/** A recorded dialog herd pressed its way out of, so a dialog that stays isn't pressed again. */
|
|
11390
|
-
closedDialog:
|
|
11556
|
+
closedDialog: z28.string().nullable().default(null),
|
|
11391
11557
|
/**
|
|
11392
11558
|
* Prompts Claude Code's hooks reported that haven't had their `Stop`. A turn is open while this
|
|
11393
11559
|
* is above zero. It's a count because a prompt queued mid-turn is reported as it's queued, and
|
|
11394
11560
|
* runs as a turn of its own, ending with a second `Stop`.
|
|
11395
11561
|
*/
|
|
11396
|
-
promptsOpen:
|
|
11562
|
+
promptsOpen: z28.number().default(0),
|
|
11397
11563
|
/** The messages the latest claim or addition took, for choosing which notice to type. */
|
|
11398
|
-
claimedSeqs:
|
|
11564
|
+
claimedSeqs: z28.array(z28.number()).default([]),
|
|
11399
11565
|
/** The investigator looking at a screen herd can't read, from opening to the owner's answer. */
|
|
11400
|
-
investigation:
|
|
11401
|
-
terminal:
|
|
11402
|
-
secret:
|
|
11403
|
-
startedAt:
|
|
11566
|
+
investigation: z28.object({
|
|
11567
|
+
terminal: z28.string(),
|
|
11568
|
+
secret: z28.string(),
|
|
11569
|
+
startedAt: z28.number(),
|
|
11404
11570
|
/** The stuck screen when it opened, saved with the key if the owner approves one. */
|
|
11405
|
-
screen:
|
|
11406
|
-
key:
|
|
11407
|
-
promptId:
|
|
11571
|
+
screen: z28.array(z28.string()),
|
|
11572
|
+
key: z28.string().nullable(),
|
|
11573
|
+
promptId: z28.string().nullable()
|
|
11408
11574
|
}).nullable().default(null),
|
|
11409
11575
|
/** The failed notice an investigator was opened for, so each failure gets one. */
|
|
11410
|
-
investigatedFailure:
|
|
11576
|
+
investigatedFailure: z28.number().nullable().default(null),
|
|
11411
11577
|
/** The agent CLI this conversation's worker runs, as its offer named it. */
|
|
11412
|
-
agent:
|
|
11578
|
+
agent: z28.string().default("claude-code"),
|
|
11413
11579
|
/** Whether what the current claim took needs a reply, which other agents' messages don't. */
|
|
11414
|
-
replyWanted:
|
|
11580
|
+
replyWanted: z28.boolean().default(true),
|
|
11415
11581
|
/** For a delegate: the conversation that started it, which its starting prompt names. */
|
|
11416
|
-
parent:
|
|
11582
|
+
parent: z28.string().nullable().default(null),
|
|
11417
11583
|
/** Codex's session file for this worktree, once found, and how far the daemon has read it. */
|
|
11418
|
-
codexFile:
|
|
11419
|
-
codexOffset:
|
|
11584
|
+
codexFile: z28.string().nullable().default(null),
|
|
11585
|
+
codexOffset: z28.number().default(0),
|
|
11420
11586
|
/** When the agent was last started, so Codex's new session file is told from older ones. */
|
|
11421
|
-
agentStartedAt:
|
|
11587
|
+
agentStartedAt: z28.number().default(0),
|
|
11422
11588
|
/**
|
|
11423
11589
|
* The key the agent was last started with, as `HERD_START`. Its `herd inbox` carrying this key
|
|
11424
11590
|
* is what proves the start works: never a hook, a prompt being taken, or the screen.
|
|
11425
11591
|
*/
|
|
11426
|
-
startKey:
|
|
11592
|
+
startKey: z28.string().nullable().default(null),
|
|
11427
11593
|
/** Whether the current start has checked in. One from before keys counts as proven. */
|
|
11428
|
-
startProven:
|
|
11594
|
+
startProven: z28.boolean().default(true),
|
|
11429
11595
|
/** When the check-in window of an unproven start began, or null once it's proven or for none. */
|
|
11430
|
-
checkInFrom:
|
|
11596
|
+
checkInFrom: z28.number().nullable().default(null),
|
|
11431
11597
|
/** Whether this start has been flagged as needing someone at its terminal, so it's said once. */
|
|
11432
|
-
needsAttention:
|
|
11598
|
+
needsAttention: z28.boolean().default(false),
|
|
11433
11599
|
/** What agy's status line last said its agent was doing, and when. */
|
|
11434
|
-
agentState:
|
|
11435
|
-
agentStateAt:
|
|
11600
|
+
agentState: z28.enum(["working", "idle"]).nullable().default(null),
|
|
11601
|
+
agentStateAt: z28.number().default(0)
|
|
11436
11602
|
});
|
|
11437
|
-
var workspaceSchema =
|
|
11438
|
-
var stateSchema =
|
|
11603
|
+
var workspaceSchema = z28.preprocess(fromBeforeFolders, workspaceFields);
|
|
11604
|
+
var stateSchema = z28.object({ workspaces: z28.record(z28.string(), workspaceSchema) });
|
|
11439
11605
|
|
|
11440
11606
|
// src/workspaces/claims.ts
|
|
11441
11607
|
var holder = (ws, workspace) => `${ws.options.machineName()}/${workspace.lead}`;
|
|
@@ -11516,7 +11682,7 @@ import { join as join29 } from "node:path";
|
|
|
11516
11682
|
|
|
11517
11683
|
// src/commands/repo.ts
|
|
11518
11684
|
init_define_HERD_PACKAGE();
|
|
11519
|
-
import { z as
|
|
11685
|
+
import { z as z29 } from "zod";
|
|
11520
11686
|
var REPO_HELP = `Usage: herd repo <url or owner/name> [folder]
|
|
11521
11687
|
|
|
11522
11688
|
Checks a repo out in this conversation's folder, on a branch named for the conversation, started
|
|
@@ -11530,16 +11696,16 @@ var REPOS_HELP = `Usage: herd repos [--json]
|
|
|
11530
11696
|
|
|
11531
11697
|
Lists the repos in this conversation's folder, the repos checked out in this machine's root, and
|
|
11532
11698
|
the repos your owner's herd.config.ts describes, with what each is for. Add one with herd repo.`;
|
|
11533
|
-
var repoContextSchema =
|
|
11534
|
-
folder:
|
|
11535
|
-
root:
|
|
11536
|
-
branch:
|
|
11537
|
-
legacy:
|
|
11538
|
-
legacyReason:
|
|
11539
|
-
recorded:
|
|
11540
|
-
cloned:
|
|
11541
|
-
described:
|
|
11542
|
-
|
|
11699
|
+
var repoContextSchema = z29.object({
|
|
11700
|
+
folder: z29.string(),
|
|
11701
|
+
root: z29.string(),
|
|
11702
|
+
branch: z29.string(),
|
|
11703
|
+
legacy: z29.boolean(),
|
|
11704
|
+
legacyReason: z29.string().optional(),
|
|
11705
|
+
recorded: z29.array(z29.object({ folder: z29.string(), remote: z29.string(), branch: z29.string() })),
|
|
11706
|
+
cloned: z29.array(z29.object({ key: z29.string(), remote: z29.string() })),
|
|
11707
|
+
described: z29.array(
|
|
11708
|
+
z29.object({ remote: z29.string(), key: z29.string().nullable(), about: z29.string().optional() })
|
|
11543
11709
|
)
|
|
11544
11710
|
});
|
|
11545
11711
|
var isUrl = (text4) => /^[a-z][a-z0-9+.-]*:\/\//i.test(text4) || text4.startsWith("/") || /^[^@/\s]+@[^:/\s]+:/.test(text4);
|
|
@@ -11596,7 +11762,7 @@ async function runRepo(rest) {
|
|
|
11596
11762
|
op: "repo-add",
|
|
11597
11763
|
repoAdd: { asked, ...folderName !== void 0 ? { folder: folderName } : {} }
|
|
11598
11764
|
});
|
|
11599
|
-
const lines =
|
|
11765
|
+
const lines = z29.array(z29.string()).safeParse(reply.lines);
|
|
11600
11766
|
if (!lines.success) throw new HerdError("The daemon's answer about this repo wasn't readable.");
|
|
11601
11767
|
console.log(lines.data.join("\n"));
|
|
11602
11768
|
return 0;
|
|
@@ -12775,21 +12941,21 @@ function resolveAttachments(worktree, files) {
|
|
|
12775
12941
|
// src/workers.ts
|
|
12776
12942
|
init_define_HERD_PACKAGE();
|
|
12777
12943
|
init_src();
|
|
12778
|
-
import { z as
|
|
12779
|
-
var workerListingSchema =
|
|
12780
|
-
workers:
|
|
12781
|
-
machines:
|
|
12782
|
-
|
|
12783
|
-
id:
|
|
12784
|
-
name:
|
|
12785
|
-
online:
|
|
12786
|
-
missing:
|
|
12787
|
-
configError:
|
|
12944
|
+
import { z as z30 } from "zod";
|
|
12945
|
+
var workerListingSchema = z30.object({
|
|
12946
|
+
workers: z30.array(workerSchema),
|
|
12947
|
+
machines: z30.array(
|
|
12948
|
+
z30.object({
|
|
12949
|
+
id: z30.string(),
|
|
12950
|
+
name: z30.string(),
|
|
12951
|
+
online: z30.boolean(),
|
|
12952
|
+
missing: z30.array(z30.string()),
|
|
12953
|
+
configError: z30.string().optional(),
|
|
12788
12954
|
// Servers from before versions were reported send none.
|
|
12789
|
-
herdVersion:
|
|
12955
|
+
herdVersion: z30.string().nullable().optional()
|
|
12790
12956
|
})
|
|
12791
12957
|
),
|
|
12792
|
-
configType:
|
|
12958
|
+
configType: z30.string()
|
|
12793
12959
|
});
|
|
12794
12960
|
async function readWorkers(fetch2) {
|
|
12795
12961
|
const response = await fetch2("/api/workers");
|
|
@@ -12857,20 +13023,20 @@ function formatWorkers(listing, current = null) {
|
|
|
12857
13023
|
);
|
|
12858
13024
|
return lines.join("\n");
|
|
12859
13025
|
}
|
|
12860
|
-
var routingCheckSchema =
|
|
12861
|
-
suits:
|
|
12862
|
-
eligible:
|
|
12863
|
-
removed:
|
|
12864
|
-
questions:
|
|
12865
|
-
|
|
13026
|
+
var routingCheckSchema = z30.object({
|
|
13027
|
+
suits: z30.array(z30.object({ key: z30.string(), name: z30.string() })),
|
|
13028
|
+
eligible: z30.array(z30.object({ key: z30.string(), name: z30.string() })),
|
|
13029
|
+
removed: z30.array(z30.object({ key: z30.string(), name: z30.string(), rule: z30.string() })),
|
|
13030
|
+
questions: z30.array(
|
|
13031
|
+
z30.object({ id: z30.string(), question: z30.string(), probability: z30.number().nullable() })
|
|
12866
13032
|
),
|
|
12867
|
-
fallback:
|
|
12868
|
-
fits:
|
|
12869
|
-
|
|
12870
|
-
key:
|
|
12871
|
-
fit:
|
|
12872
|
-
statement:
|
|
12873
|
-
level:
|
|
13033
|
+
fallback: z30.string().optional(),
|
|
13034
|
+
fits: z30.array(
|
|
13035
|
+
z30.object({
|
|
13036
|
+
key: z30.string(),
|
|
13037
|
+
fit: z30.number(),
|
|
13038
|
+
statement: z30.string().optional(),
|
|
13039
|
+
level: z30.string().optional()
|
|
12874
13040
|
})
|
|
12875
13041
|
).optional()
|
|
12876
13042
|
});
|
|
@@ -14254,8 +14420,12 @@ async function runDaemon(args) {
|
|
|
14254
14420
|
}),
|
|
14255
14421
|
access: () => daemon?.configuration().config?.terminals?.remote ?? "drive",
|
|
14256
14422
|
resolve: async (target) => {
|
|
14257
|
-
if (target.kind
|
|
14258
|
-
|
|
14423
|
+
if (target.kind === "activation") {
|
|
14424
|
+
const cli = clis.find((candidate) => candidate.name === target.agent);
|
|
14425
|
+
if (!cli || !activator) return { refused: "This machine doesn't run that agent." };
|
|
14426
|
+
const terminal = await activator.terminalFor(cli.name, cli.version);
|
|
14427
|
+
if (!terminal) return { refused: "The agent's sign-in didn't start on this machine." };
|
|
14428
|
+
return { terminal, socketPath: await terminals.pathOf(terminal) };
|
|
14259
14429
|
}
|
|
14260
14430
|
const workspace = workspaces.get(target.conversationId);
|
|
14261
14431
|
if (!workspace) return { refused: "This machine doesn't hold that conversation." };
|
|
@@ -15321,7 +15491,7 @@ async function runWatch(command, rest) {
|
|
|
15321
15491
|
// src/commands/work.ts
|
|
15322
15492
|
init_define_HERD_PACKAGE();
|
|
15323
15493
|
init_src();
|
|
15324
|
-
import { z as
|
|
15494
|
+
import { z as z36 } from "zod";
|
|
15325
15495
|
var WORK_HELP = `Usage: herd work <url> [--kind <kind>] [--title "<title>"] [--status <status>]
|
|
15326
15496
|
[--detail "<detail>"] [--made] [--phase <phase>]
|
|
15327
15497
|
herd work --remove <url>
|
|
@@ -15413,9 +15583,9 @@ ${WORK_HELP}`
|
|
|
15413
15583
|
};
|
|
15414
15584
|
return { kind: "record", change, json };
|
|
15415
15585
|
}
|
|
15416
|
-
var followSchema =
|
|
15417
|
-
|
|
15418
|
-
|
|
15586
|
+
var followSchema = z36.union([
|
|
15587
|
+
z36.object({ following: z36.literal(true) }),
|
|
15588
|
+
z36.object({ following: z36.literal(false), reason: z36.string() })
|
|
15419
15589
|
]);
|
|
15420
15590
|
function formatFollow(follow) {
|
|
15421
15591
|
return follow.following ? "Following it: its reviews, CI and merge will reach herd inbox." : `Not followed: ${follow.reason}`;
|
|
@@ -15431,7 +15601,7 @@ function formatWork(work, own) {
|
|
|
15431
15601
|
return ` ${parts.join(" \xB7 ")}${work.made ? " made here" : ""}
|
|
15432
15602
|
${work.url}${whose}`;
|
|
15433
15603
|
}
|
|
15434
|
-
var listSchema =
|
|
15604
|
+
var listSchema = z36.array(workObjectSchema);
|
|
15435
15605
|
async function runWork(rest) {
|
|
15436
15606
|
const parsed = parseWork(rest);
|
|
15437
15607
|
if (parsed.kind === "help") {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@herdingchats/friday",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.707",
|
|
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": "092263ddfd4398fa1093a095995b57b617e624d3"
|
|
26
26
|
}
|
package/terminal-host.mjs
CHANGED
|
@@ -230,6 +230,16 @@ var TerminalHost = class {
|
|
|
230
230
|
if (held.info.exited) return;
|
|
231
231
|
held.pty.resize(cols, rows);
|
|
232
232
|
held.term.resize(cols, rows);
|
|
233
|
+
for (const socket of held.watchers) {
|
|
234
|
+
socket.write(`${JSON.stringify({ type: "resize", cols, rows })}
|
|
235
|
+
`);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
/** The screen as `attach` and `watch` send it first: its contents, and its size. */
|
|
239
|
+
async sized(name) {
|
|
240
|
+
const held = this.get(name);
|
|
241
|
+
const data = await this.snapshot(name);
|
|
242
|
+
return { type: "snapshot", data, cols: held.term.cols, rows: held.term.rows };
|
|
233
243
|
}
|
|
234
244
|
subscribe(name, socket) {
|
|
235
245
|
const held = this.get(name);
|
|
@@ -253,7 +263,7 @@ var TerminalHost = class {
|
|
|
253
263
|
return;
|
|
254
264
|
}
|
|
255
265
|
if (size.cols && size.rows) this.resize(name, size.cols, size.rows);
|
|
256
|
-
socket.write(`${JSON.stringify(
|
|
266
|
+
socket.write(`${JSON.stringify(await this.sized(name))}
|
|
257
267
|
`);
|
|
258
268
|
held.viewers.add(socket);
|
|
259
269
|
held.drivenAt = Date.now();
|
|
@@ -294,7 +304,7 @@ var TerminalHost = class {
|
|
|
294
304
|
`);
|
|
295
305
|
return;
|
|
296
306
|
}
|
|
297
|
-
socket.write(`${JSON.stringify(
|
|
307
|
+
socket.write(`${JSON.stringify(await this.sized(name))}
|
|
298
308
|
`);
|
|
299
309
|
held.watchers.add(socket);
|
|
300
310
|
held.subscribers.add(socket);
|