@herdingchats/friday 0.1.701 → 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.
Files changed (2) hide show
  1. package/herd.mjs +387 -256
  2. package/package.json +2 -2
package/herd.mjs CHANGED
@@ -18,7 +18,7 @@ var __export = (target, all) => {
18
18
  var define_HERD_PACKAGE_default;
19
19
  var init_define_HERD_PACKAGE = __esm({
20
20
  "<define:HERD_PACKAGE>"() {
21
- define_HERD_PACKAGE_default = { version: "0.1.701", gitHead: "dee83b97beed4102f6d56d692f1c1e306b62dbb6" };
21
+ define_HERD_PACKAGE_default = { version: "0.1.707", gitHead: "092263ddfd4398fa1093a095995b57b617e624d3" };
22
22
  }
23
23
  });
24
24
 
@@ -1971,8 +1971,138 @@ var init_builds = __esm({
1971
1971
  }
1972
1972
  });
1973
1973
 
1974
- // ../common-chat/src/setup.ts
1974
+ // ../common-chat/src/gateway-spend.ts
1975
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";
1976
2106
  function actionText(action) {
1977
2107
  if (action.kind === "link") return `${action.label}: ${action.url}`;
1978
2108
  if (action.kind === "sign_in") {
@@ -2007,42 +2137,42 @@ var init_setup = __esm({
2007
2137
  init_activation();
2008
2138
  init_bot();
2009
2139
  SETUP_STEP_IDS = ["slack", "machine", "github", "repos"];
2010
- setupActionSchema = z17.discriminatedUnion("kind", [
2140
+ setupActionSchema = z18.discriminatedUnion("kind", [
2011
2141
  /** A page to open, which signs in to HerdingChats first. */
2012
- z17.object({ kind: z17.literal("link"), url: z17.string(), label: z17.string() }),
2142
+ z18.object({ kind: z18.literal("link"), url: z18.string(), label: z18.string() }),
2013
2143
  /** A command to run on the computer. */
2014
- z17.object({ kind: z17.literal("command"), command: z17.string() }),
2144
+ z18.object({ kind: z18.literal("command"), command: z18.string() }),
2015
2145
  /**
2016
2146
  * A sign-in herd starts on one of the person's machines, from Slack or the page, whose code
2017
2147
  * Friday sends to their direct message.
2018
2148
  */
2019
- z17.object({
2020
- kind: z17.literal("sign_in"),
2021
- machineId: z17.string(),
2149
+ z18.object({
2150
+ kind: z18.literal("sign_in"),
2151
+ machineId: z18.string(),
2022
2152
  tool: signInToolSchema,
2023
- label: z17.string()
2153
+ label: z18.string()
2024
2154
  })
2025
2155
  ]);
2026
- setupStepSchema = z17.object({
2027
- id: z17.enum(SETUP_STEP_IDS),
2156
+ setupStepSchema = z18.object({
2157
+ id: z18.enum(SETUP_STEP_IDS),
2028
2158
  /** `unavailable` is a step nobody can take yet, such as GitHub linking before an admin turns it on. */
2029
- state: z17.enum(["done", "todo", "unavailable"]),
2030
- optional: z17.boolean(),
2031
- title: z17.string(),
2159
+ state: z18.enum(["done", "todo", "unavailable"]),
2160
+ optional: z18.boolean(),
2161
+ title: z18.string(),
2032
2162
  /** What was found, such as the machine and whether it's online, or why it can't be done yet. */
2033
- detail: z17.string().nullable(),
2163
+ detail: z18.string().nullable(),
2034
2164
  /** What to do next. None once it's done, or while it's unavailable. */
2035
2165
  action: setupActionSchema.nullable(),
2036
2166
  /**
2037
2167
  * More that can be done, which doesn't decide whether the step is done, such as signing in a
2038
2168
  * computer's GitHub CLI. Shown whatever the step's state.
2039
2169
  */
2040
- extra: z17.array(setupActionSchema).optional()
2170
+ extra: z18.array(setupActionSchema).optional()
2041
2171
  });
2042
- setupStatusSchema = z17.object({
2043
- steps: z17.array(setupStepSchema),
2172
+ setupStatusSchema = z18.object({
2173
+ steps: z18.array(setupStepSchema),
2044
2174
  /** Whether every step that isn't optional is done, so Friday can take work. */
2045
- ready: z17.boolean()
2175
+ ready: z18.boolean()
2046
2176
  });
2047
2177
  READY_TEXT = `You're set up: mention @${BOT_NAME} in any channel it's in, or message it directly.`;
2048
2178
  READY_SUGGESTIONS_TITLE = "Some things to try:";
@@ -2077,6 +2207,7 @@ var init_src = __esm({
2077
2207
  init_content();
2078
2208
  init_conversation_state();
2079
2209
  init_events();
2210
+ init_gateway_spend();
2080
2211
  init_github();
2081
2212
  init_github_triggers();
2082
2213
  init_machines();
@@ -2494,7 +2625,7 @@ var init_widget = __esm({
2494
2625
  });
2495
2626
 
2496
2627
  // ../common-board/src/widgets/conversations.tsx
2497
- import { z as z30 } from "zod";
2628
+ import { z as z31 } from "zod";
2498
2629
  import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
2499
2630
  function badge(item) {
2500
2631
  if (pullRequestBadge(item)) {
@@ -2538,10 +2669,10 @@ var init_conversations = __esm({
2538
2669
  conversations2 = defineWidget({
2539
2670
  kind: "conversations",
2540
2671
  describe: "Blocked, working and queued conversations, then the latest done, with what each is doing, where it came from and who holds it",
2541
- options: z30.object({
2542
- states: z30.array(conversationStateSchema).min(1).default(["stuck", "working", "waiting", "done"]),
2543
- limit: z30.number().int().min(1).max(BOARD_ITEMS).default(4),
2544
- show: z30.array(z30.enum(DETAILS)).default([...DETAILS])
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])
2545
2676
  }),
2546
2677
  reads: ["items", "machines"],
2547
2678
  Component: ({ board, options, theme, now }) => {
@@ -2585,7 +2716,7 @@ var init_conversations = __esm({
2585
2716
  });
2586
2717
 
2587
2718
  // ../common-board/src/widgets/counts.tsx
2588
- import { z as z31 } from "zod";
2719
+ import { z as z32 } from "zod";
2589
2720
  import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
2590
2721
  var COUNTS, LABELS2, counts;
2591
2722
  var init_counts = __esm({
@@ -2605,8 +2736,8 @@ var init_counts = __esm({
2605
2736
  counts = defineWidget({
2606
2737
  kind: "counts",
2607
2738
  describe: "How many conversations are stuck, unanswered, waiting and working, and done today",
2608
- options: z31.object({
2609
- show: z31.array(z31.enum(COUNTS)).min(1).max(5).default([...COUNTS])
2739
+ options: z32.object({
2740
+ show: z32.array(z32.enum(COUNTS)).min(1).max(5).default([...COUNTS])
2610
2741
  }),
2611
2742
  reads: ["counts", "doneToday"],
2612
2743
  Component: ({ board, options, theme }) => {
@@ -2645,7 +2776,7 @@ var init_counts = __esm({
2645
2776
  });
2646
2777
 
2647
2778
  // ../common-board/src/widgets/header.tsx
2648
- import { z as z32 } from "zod";
2779
+ import { z as z33 } from "zod";
2649
2780
  import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
2650
2781
  function summary(board) {
2651
2782
  const parts = [
@@ -2670,9 +2801,9 @@ var init_header = __esm({
2670
2801
  header = defineWidget({
2671
2802
  kind: "header",
2672
2803
  describe: "The board's title, a line of how much is open, and when it was drawn",
2673
- options: z32.object({
2674
- title: z32.string().min(1).max(40).default(`@${BOT_NAME}`),
2675
- summary: z32.boolean().default(true)
2804
+ options: z33.object({
2805
+ title: z33.string().min(1).max(40).default(`@${BOT_NAME}`),
2806
+ summary: z33.boolean().default(true)
2676
2807
  }),
2677
2808
  reads: ["counts"],
2678
2809
  Component: ({ board, options, theme, now }) => {
@@ -2690,7 +2821,7 @@ var init_header = __esm({
2690
2821
  });
2691
2822
 
2692
2823
  // ../common-board/src/widgets/machines.tsx
2693
- import { z as z33 } from "zod";
2824
+ import { z as z34 } from "zod";
2694
2825
  import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
2695
2826
  function usageText(worker) {
2696
2827
  const usage = worker.usage;
@@ -2721,7 +2852,7 @@ var init_machines2 = __esm({
2721
2852
  machines = defineWidget({
2722
2853
  kind: "machines",
2723
2854
  describe: "One bubble per agent on an online machine, with its usage, most recently active first",
2724
- options: z33.object({ limit: z33.number().int().min(1).max(8).default(3) }),
2855
+ options: z34.object({ limit: z34.number().int().min(1).max(8).default(3) }),
2725
2856
  reads: ["machines"],
2726
2857
  Component: ({ board, options, theme }) => {
2727
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));
@@ -2838,9 +2969,9 @@ var init_board2 = __esm({
2838
2969
  });
2839
2970
 
2840
2971
  // ../common-board/src/composition.ts
2841
- import { z as z34 } from "zod";
2972
+ import { z as z35 } from "zod";
2842
2973
  function readComposition(stored) {
2843
- const shape = z34.object({ widgets: z34.array(placedWidgetSchema) }).safeParse(stored);
2974
+ const shape = z35.object({ widgets: z35.array(placedWidgetSchema) }).safeParse(stored);
2844
2975
  if (!shape.success) return DEFAULT_COMPOSITION;
2845
2976
  const known = shape.data.widgets.filter(
2846
2977
  (widget) => WIDGETS[widget.kind]?.options.safeParse(widget.options).success
@@ -2855,11 +2986,11 @@ var init_composition = __esm({
2855
2986
  init_registry();
2856
2987
  MAX_WIDGETS = 12;
2857
2988
  MAX_COMPOSITION_BYTES = 4096;
2858
- placedWidgetSchema = z34.object({
2859
- kind: z34.string().min(1),
2860
- options: z34.record(z34.string(), z34.unknown()).default({})
2989
+ placedWidgetSchema = z35.object({
2990
+ kind: z35.string().min(1),
2991
+ options: z35.record(z35.string(), z35.unknown()).default({})
2861
2992
  });
2862
- compositionSchema = z34.object({ widgets: z34.array(placedWidgetSchema).max(MAX_WIDGETS) }).superRefine((composition, context2) => {
2993
+ compositionSchema = z35.object({ widgets: z35.array(placedWidgetSchema).max(MAX_WIDGETS) }).superRefine((composition, context2) => {
2863
2994
  if (JSON.stringify(composition).length > MAX_COMPOSITION_BYTES) {
2864
2995
  context2.addIssue({
2865
2996
  code: "custom",
@@ -3319,7 +3450,7 @@ import { existsSync as existsSync12, readFileSync as readFileSync10 } from "node
3319
3450
  import { homedir as homedir5 } from "node:os";
3320
3451
  import { dirname as dirname10, join as join16 } from "node:path";
3321
3452
  import { createInterface as createInterface2 } from "node:readline/promises";
3322
- import { z as z23 } from "zod";
3453
+ import { z as z24 } from "zod";
3323
3454
 
3324
3455
  // src/auth.ts
3325
3456
  init_define_HERD_PACKAGE();
@@ -3328,21 +3459,21 @@ import { chmodSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:
3328
3459
  import { createServer } from "node:http";
3329
3460
  import { homedir } from "node:os";
3330
3461
  import { join } from "node:path";
3331
- import { z as z18 } from "zod";
3462
+ import { z as z19 } from "zod";
3332
3463
  var herdHome = () => process.env.HERD_HOME ?? join(homedir(), ".herd");
3333
3464
  var apiUrl = () => (process.env.HERD_API_URL ?? "https://api.herdingchats.com").replace(/\/+$/, "");
3334
3465
  var isLocal = (url) => /^http:\/\/localhost:\d+\/?$/.test(url);
3335
3466
  var localSignIn = () => process.env.HERD_LOCAL_SLACK ? { "X-Herd-Local-Slack": process.env.HERD_LOCAL_SLACK } : {};
3336
3467
  var HerdError = class extends Error {
3337
3468
  };
3338
- var credentialsSchema = z18.object({
3339
- api: z18.string(),
3340
- tokenEndpoint: z18.string(),
3341
- revocationEndpoint: z18.string().optional(),
3342
- clientId: z18.string(),
3343
- accessToken: z18.string(),
3344
- accessTokenExpiresAt: z18.number(),
3345
- refreshToken: z18.string()
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()
3346
3477
  });
3347
3478
  var credentialsPath = () => join(herdHome(), "credentials.json");
3348
3479
  function readCredentials() {
@@ -3358,16 +3489,16 @@ function writeCredentials(credentials) {
3358
3489
  writeFileSync(credentialsPath(), JSON.stringify(credentials, null, 2), { mode: 384 });
3359
3490
  chmodSync(credentialsPath(), 384);
3360
3491
  }
3361
- var metadataSchema = z18.object({
3362
- authorization_endpoint: z18.string(),
3363
- token_endpoint: z18.string(),
3364
- registration_endpoint: z18.string(),
3365
- revocation_endpoint: z18.string().optional()
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()
3366
3497
  });
3367
- var tokenSchema = z18.object({
3368
- access_token: z18.string().min(1),
3369
- refresh_token: z18.string().min(1),
3370
- expires_in: z18.number()
3498
+ var tokenSchema = z19.object({
3499
+ access_token: z19.string().min(1),
3500
+ refresh_token: z19.string().min(1),
3501
+ expires_in: z19.number()
3371
3502
  });
3372
3503
  var base64url = (bytes) => bytes.toString("base64url");
3373
3504
  async function postForm(url, fields) {
@@ -3476,7 +3607,7 @@ async function login(how, {
3476
3607
  token_endpoint_auth_method: "none"
3477
3608
  })
3478
3609
  });
3479
- const client = z18.object({ client_id: z18.string() }).safeParse(await registration2.json());
3610
+ const client = z19.object({ client_id: z19.string() }).safeParse(await registration2.json());
3480
3611
  if (!registration2.ok || !client.success) {
3481
3612
  throw new HerdError("The sign-in server refused to register this tool.");
3482
3613
  }
@@ -3714,7 +3845,7 @@ import { randomUUID } from "node:crypto";
3714
3845
  import { existsSync as existsSync3, mkdirSync as mkdirSync4, readFileSync as readFileSync4, realpathSync as realpathSync2, writeFileSync as writeFileSync3 } from "node:fs";
3715
3846
  import { homedir as homedir3, hostname } from "node:os";
3716
3847
  import { basename, dirname as dirname4, join as join6, resolve } from "node:path";
3717
- import { z as z19 } from "zod";
3848
+ import { z as z20 } from "zod";
3718
3849
 
3719
3850
  // src/login-shell.ts
3720
3851
  init_define_HERD_PACKAGE();
@@ -4493,13 +4624,13 @@ function hasUnpushed(path) {
4493
4624
 
4494
4625
  // src/config.ts
4495
4626
  init_self();
4496
- var repoSchema = z19.object({ name: z19.string(), path: z19.string(), remote: z19.string() });
4497
- var configSchema = z19.object({
4498
- machineId: z19.string(),
4499
- machineName: z19.string(),
4500
- repos: z19.array(repoSchema),
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),
4501
4632
  /** The machine's root folder, holding herd's clones and its conversations' folders. */
4502
- root: z19.string().optional()
4633
+ root: z20.string().optional()
4503
4634
  });
4504
4635
  var configPath = () => join6(herdHome(), "config.json");
4505
4636
  function save(config) {
@@ -4717,23 +4848,23 @@ init_src();
4717
4848
  import { randomBytes as randomBytes4, randomUUID as randomUUID3 } from "node:crypto";
4718
4849
  import { mkdirSync as mkdirSync6, readFileSync as readFileSync5, renameSync as renameSync2, rmSync as rmSync6, statSync as statSync4, writeFileSync as writeFileSync4 } from "node:fs";
4719
4850
  import { dirname as dirname5, join as join8 } from "node:path";
4720
- import { z as z22 } from "zod";
4851
+ import { z as z23 } from "zod";
4721
4852
 
4722
4853
  // src/permissions.ts
4723
4854
  init_define_HERD_PACKAGE();
4724
4855
  init_src();
4725
4856
  import { randomUUID as randomUUID2 } from "node:crypto";
4726
- import { z as z21 } from "zod";
4857
+ import { z as z22 } from "zod";
4727
4858
 
4728
4859
  // src/local-socket.ts
4729
4860
  init_define_HERD_PACKAGE();
4730
4861
  import { randomBytes as randomBytes3 } from "node:crypto";
4731
4862
  import { chmodSync as chmodSync2, existsSync as existsSync4, rmSync as rmSync4 } from "node:fs";
4732
4863
  import { connect, createServer as createServer2 } from "node:net";
4733
- import { z as z20 } from "zod";
4734
- var localRequestSchema = z20.object({
4735
- secret: z20.string().min(1),
4736
- op: z20.enum([
4864
+ import { z as z21 } from "zod";
4865
+ var localRequestSchema = z21.object({
4866
+ secret: z21.string().min(1),
4867
+ op: z21.enum([
4737
4868
  "inbox",
4738
4869
  "send",
4739
4870
  "run",
@@ -4765,32 +4896,32 @@ var localRequestSchema = z20.object({
4765
4896
  "activate"
4766
4897
  ]),
4767
4898
  // The key of the agent's start, from `HERD_START`, which `herd inbox` proves the start with.
4768
- start: z20.string().min(1).max(100).optional(),
4899
+ start: z21.string().min(1).max(100).optional(),
4769
4900
  // `herd repo`: the repo it added to the conversation's folder, for the daemon to record.
4770
- repo: z20.object({
4771
- remote: z20.string().min(1).max(500),
4772
- folder: z20.string().min(1).max(100),
4773
- base: z20.string().min(1).max(300).optional(),
4774
- fetchFailed: z20.string().max(1e3).optional()
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()
4775
4906
  }).optional(),
4776
4907
  // `herd repo`: what the agent named and the folder it asked for, for the daemon to add.
4777
- repoAdd: z20.object({
4778
- asked: z20.string().min(1).max(500),
4779
- folder: z20.string().min(1).max(100).optional()
4908
+ repoAdd: z21.object({
4909
+ asked: z21.string().min(1).max(500),
4910
+ folder: z21.string().min(1).max(100).optional()
4780
4911
  }).optional(),
4781
4912
  // `herd delegate --repo`, given once for each repo the delegate works in.
4782
- repos: z20.array(z20.string().min(1).max(500)).max(10).optional(),
4913
+ repos: z21.array(z21.string().min(1).max(500)).max(10).optional(),
4783
4914
  // `herd watch`, `herd unwatch` and `herd watching`: what to do, and the pull request.
4784
- watch: z20.object({
4785
- action: z20.enum(["watch", "unwatch", "list"]),
4786
- url: z20.string().min(1).max(500).optional()
4915
+ watch: z21.object({
4916
+ action: z21.enum(["watch", "unwatch", "list"]),
4917
+ url: z21.string().min(1).max(500).optional()
4787
4918
  }).optional(),
4788
4919
  // `herd delegate`, `herd tell` and `herd handoff`: the worker or conversation they name.
4789
- worker: z20.string().min(1).max(200).optional(),
4790
- to: z20.string().min(1).max(200).optional(),
4920
+ worker: z21.string().min(1).max(200).optional(),
4921
+ to: z21.string().min(1).max(200).optional(),
4791
4922
  // `herd automations`: what to do, to which automation, and the definition or change it sends.
4792
- automation: z20.object({
4793
- action: z20.enum([
4923
+ automation: z21.object({
4924
+ action: z21.enum([
4794
4925
  "list",
4795
4926
  "show",
4796
4927
  "create",
@@ -4801,47 +4932,47 @@ var localRequestSchema = z20.object({
4801
4932
  "test",
4802
4933
  "rotate"
4803
4934
  ]),
4804
- id: z20.string().min(1).max(100).optional(),
4805
- body: z20.record(z20.string(), z20.unknown()).optional(),
4806
- waitMs: z20.number().int().min(0).max(6e5).optional()
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()
4807
4938
  }).optional(),
4808
4939
  // `herd work`: list, record or remove one, with the change the daemon checks again.
4809
- work: z20.object({
4810
- action: z20.enum(["list", "record", "remove"]),
4811
- change: z20.unknown().optional(),
4812
- url: z20.string().min(1).max(2048).optional()
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()
4813
4944
  }).optional(),
4814
4945
  // `herd conversations --about <url>`: only the owner's conversations about that URL.
4815
- about: z20.string().min(1).max(2048).optional(),
4946
+ about: z21.string().min(1).max(2048).optional(),
4816
4947
  // `herd investigate screen` or `herd investigate propose`, with the proposal the daemon checks.
4817
- action: z20.enum(["screen", "propose"]).optional(),
4818
- proposal: z20.unknown().optional(),
4948
+ action: z21.enum(["screen", "propose"]).optional(),
4949
+ proposal: z21.unknown().optional(),
4819
4950
  // Commands may name a conversation, but only their own is ever allowed.
4820
- conversationId: z20.string().optional(),
4951
+ conversationId: z21.string().optional(),
4821
4952
  // Where `conversations` is shown, which decides whether private titles are. Only the terminal's
4822
4953
  // own conversation is ever allowed, so a terminal can't pick one that shows more.
4823
- for: z20.string().optional(),
4824
- text: z20.string().optional(),
4954
+ for: z21.string().optional(),
4955
+ text: z21.string().optional(),
4825
4956
  // A whole message, from `herd send --json`, which the daemon checks again.
4826
- message: z20.unknown().optional(),
4827
- idempotencyKey: z20.string().optional(),
4828
- command: z20.array(z20.string()).optional(),
4957
+ message: z21.unknown().optional(),
4958
+ idempotencyKey: z21.string().optional(),
4959
+ command: z21.array(z21.string()).optional(),
4829
4960
  // `status --clear`.
4830
- clear: z20.boolean().optional(),
4961
+ clear: z21.boolean().optional(),
4831
4962
  // What an agent's status line reported, checked by the daemon.
4832
- usage: z20.unknown().optional(),
4963
+ usage: z21.unknown().optional(),
4833
4964
  // Which agent and session a status line ran for. Its reports count only from the session herd
4834
4965
  // started in the conversation's lead terminal.
4835
- agent: z20.enum(["claude-code", "codex", "agy"]).optional(),
4836
- sessionId: z20.string().min(1).max(200).optional(),
4966
+ agent: z21.enum(["claude-code", "codex", "agy"]).optional(),
4967
+ sessionId: z21.string().min(1).max(200).optional(),
4837
4968
  // What agy's status line says its agent is doing: `working` or `idle`.
4838
- state: z20.enum(["working", "idle"]).optional(),
4969
+ state: z21.enum(["working", "idle"]).optional(),
4839
4970
  // A permission request from Claude Code's hook, with the key it keeps across reconnects.
4840
- key: z20.string().min(1).max(200).optional(),
4841
- request: z20.unknown().optional(),
4971
+ key: z21.string().min(1).max(200).optional(),
4972
+ request: z21.unknown().optional(),
4842
4973
  // For one of Claude Code's other hooks: which event, and the JSON Claude Code gave it.
4843
- event: z20.string().optional(),
4844
- input: z20.record(z20.string(), z20.unknown()).optional()
4974
+ event: z21.string().optional(),
4975
+ input: z21.record(z21.string(), z21.unknown()).optional()
4845
4976
  });
4846
4977
  var LocalSocket = class {
4847
4978
  constructor(path, handle) {
@@ -4963,10 +5094,10 @@ function isAnswering(path) {
4963
5094
  }
4964
5095
 
4965
5096
  // src/permissions.ts
4966
- var hookRequestSchema = z21.looseObject({
4967
- tool_name: z21.string().min(1),
4968
- tool_input: z21.record(z21.string(), z21.unknown()).default({}),
4969
- permission_suggestions: z21.array(z21.unknown()).optional()
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()
4970
5101
  });
4971
5102
  var DETAIL_LIMIT = 2800;
4972
5103
  var REPLY_MESSAGE_LIMIT = 2e3;
@@ -5416,9 +5547,9 @@ var activationTerminal = (agent) => `herd-activate-${agentShortName(agent)}`;
5416
5547
  var activationFolder = (root, agent) => join8(convosHome(root), ".activate", agentShortName(agent));
5417
5548
  var recordSchema = agentActivationSchema.extend({
5418
5549
  /** While it's waiting: the terminal it runs in, which `friday start` can attach to. */
5419
- terminal: z22.string().optional()
5550
+ terminal: z23.string().optional()
5420
5551
  });
5421
- var storeSchema = z22.object({ agents: z22.record(z22.string(), recordSchema) });
5552
+ var storeSchema = z23.object({ agents: z23.record(z23.string(), recordSchema) });
5422
5553
  var activationsPath = (home = herdHome()) => join8(home, "activations.json");
5423
5554
  var activationRequestPath = (home = herdHome()) => join8(home, "activate-request");
5424
5555
  function readActivations(path = activationsPath()) {
@@ -7178,7 +7309,7 @@ function defaults() {
7178
7309
  print: (line2) => console.log(line2)
7179
7310
  };
7180
7311
  }
7181
- var releaseSchema = z23.object({ version: z23.string().min(1), integrity: z23.string().min(1) });
7312
+ var releaseSchema = z24.object({ version: z24.string().min(1), integrity: z24.string().min(1) });
7182
7313
  async function fetchRelease() {
7183
7314
  const response = await apiFetch("/api/daemon/release");
7184
7315
  if (response.status === 404) return null;
@@ -7819,11 +7950,11 @@ init_define_HERD_PACKAGE();
7819
7950
  // src/investigator.ts
7820
7951
  init_define_HERD_PACKAGE();
7821
7952
  init_src();
7822
- import { z as z24 } from "zod";
7953
+ import { z as z25 } from "zod";
7823
7954
  var INVESTIGATE_KEYS = ["escape", "up", "down", "enter", "tab"];
7824
- var proposalSchema = z24.object({
7825
- key: z24.enum([...INVESTIGATE_KEYS, "none"]),
7826
- reason: z24.string().trim().min(1).max(300)
7955
+ var proposalSchema = z25.object({
7956
+ key: z25.enum([...INVESTIGATE_KEYS, "none"]),
7957
+ reason: z25.string().trim().min(1).max(300)
7827
7958
  });
7828
7959
  var KEY_LABELS = {
7829
7960
  escape: "Esc",
@@ -8233,12 +8364,12 @@ init_define_HERD_PACKAGE();
8233
8364
  init_src();
8234
8365
  import { chmodSync as chmodSync3, existsSync as existsSync14, mkdirSync as mkdirSync14, readFileSync as readFileSync14, writeFileSync as writeFileSync10 } from "node:fs";
8235
8366
  import { join as join19 } from "node:path";
8236
- import { z as z25 } from "zod";
8367
+ import { z as z26 } from "zod";
8237
8368
  var BUILDS_URL = "https://builds.herdingchats.com";
8238
- var runnerKeySchema = z25.object({
8239
- runnerId: z25.string().min(1),
8240
- key: z25.string().min(20),
8241
- url: z25.string().url()
8369
+ var runnerKeySchema = z26.object({
8370
+ runnerId: z26.string().min(1),
8371
+ key: z26.string().min(20),
8372
+ url: z26.string().url()
8242
8373
  });
8243
8374
  var runnerKeyPath = () => join19(herdHome(), "build-runner.json");
8244
8375
  function readRunnerKey() {
@@ -8307,33 +8438,33 @@ async function registerRunner({
8307
8438
 
8308
8439
  // src/build-speed.ts
8309
8440
  init_define_HERD_PACKAGE();
8310
- import { z as z26 } from "zod";
8311
- var ms = z26.number().int().nullable();
8312
- var figuresSchema = z26.object({ count: z26.number().int(), median: ms, p90: ms });
8313
- var buildTimesSchema = z26.object({ run: figuresSchema, push: figuresSchema });
8314
- var stepFiguresSchema = z26.object({
8315
- ran: z26.number().int(),
8316
- remembered: z26.number().int(),
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(),
8317
8448
  median: ms,
8318
8449
  p90: ms,
8319
- overBudget: z26.number().int()
8450
+ overBudget: z27.number().int()
8320
8451
  });
8321
- var kindSchema = z26.object({
8322
- builds: z26.object({ current: buildTimesSchema, previous: buildTimesSchema }),
8323
- steps: z26.array(
8324
- z26.object({ label: z26.string(), current: stepFiguresSchema, previous: stepFiguresSchema })
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 })
8325
8456
  ),
8326
- overBudget: z26.array(
8327
- z26.object({ label: z26.string(), current: z26.number().int(), previous: z26.number().int() })
8457
+ overBudget: z27.array(
8458
+ z27.object({ label: z27.string(), current: z27.number().int(), previous: z27.number().int() })
8328
8459
  )
8329
8460
  });
8330
- var range = z26.object({ from: z26.number(), to: z26.number() });
8331
- var speedReportSchema = z26.object({
8332
- periods: z26.object({ current: range, previous: range }),
8333
- repos: z26.array(
8334
- z26.object({
8335
- repo: z26.string(),
8336
- capped: z26.boolean(),
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(),
8337
8468
  pullRequests: kindSchema,
8338
8469
  main: kindSchema
8339
8470
  })
@@ -11275,7 +11406,7 @@ init_define_HERD_PACKAGE();
11275
11406
  init_src();
11276
11407
  init_self();
11277
11408
  import { join as join28 } from "node:path";
11278
- import { z as z27 } from "zod";
11409
+ import { z as z28 } from "zod";
11279
11410
  function hasThread(events) {
11280
11411
  return events.some(
11281
11412
  (event2) => event2.type === "prompt.opened" || event2.type === "message.created" && !(event2.payload.direction === "inbound" && event2.payload.automation) && !event2.payload.quiet && !event2.payload.post
@@ -11341,16 +11472,16 @@ var WAITING_NOTIFICATIONS = /* @__PURE__ */ new Set([
11341
11472
  "agent_needs_input",
11342
11473
  "elicitation_dialog"
11343
11474
  ]);
11344
- var agentMessageSchema = z27.object({
11345
- text: z27.string().trim().min(1).max(12e3),
11346
- files: z27.array(z27.object({ path: z27.string().min(1), title: z27.string().optional() })).max(10).optional()
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()
11347
11478
  });
11348
- var workspaceRepoSchema = z27.object({
11349
- folder: z27.string(),
11350
- remote: z27.string(),
11351
- branch: z27.string(),
11479
+ var workspaceRepoSchema = z28.object({
11480
+ folder: z28.string(),
11481
+ remote: z28.string(),
11482
+ branch: z28.string(),
11352
11483
  /** For a conversation from before folders: the name of the repo it was allowed as. */
11353
- name: z27.string().optional()
11484
+ name: z28.string().optional()
11354
11485
  });
11355
11486
  function fromBeforeFolders(raw) {
11356
11487
  if (!raw || typeof raw !== "object" || "folder" in raw) return raw;
@@ -11371,106 +11502,106 @@ function fromBeforeFolders(raw) {
11371
11502
  legacy: true
11372
11503
  };
11373
11504
  }
11374
- var workspaceFields = z27.object({
11375
- conversationId: z27.string(),
11505
+ var workspaceFields = z28.object({
11506
+ conversationId: z28.string(),
11376
11507
  /** The conversation's own folder, where its terminals start. */
11377
- folder: z27.string(),
11508
+ folder: z28.string(),
11378
11509
  /** The repos in it, in the order they were added. */
11379
- worktrees: z27.array(workspaceRepoSchema).default([]),
11510
+ worktrees: z28.array(workspaceRepoSchema).default([]),
11380
11511
  /** A conversation from before folders, which works in its one repo's worktree. */
11381
- legacy: z27.boolean().default(false),
11382
- lead: z27.string(),
11383
- secret: z27.string(),
11384
- readSeq: z27.number(),
11385
- claimId: z27.string().nullable(),
11386
- claimRenewedAt: z27.number(),
11387
- started: z27.boolean(),
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(),
11388
11519
  /** Messages to deliver once the current turn ends. */
11389
- deferred: z27.boolean(),
11520
+ deferred: z28.boolean(),
11390
11521
  /** A `herd run` command finished, which the agent hears about even with nothing to claim. */
11391
- terminalNotice: z27.boolean().default(false),
11392
- status: z27.string().nullable(),
11522
+ terminalNotice: z28.boolean().default(false),
11523
+ status: z28.string().nullable(),
11393
11524
  /** Set once the thread has been told the agent is waiting, so it's told once per wait. */
11394
- toldWaiting: z27.boolean(),
11395
- runs: z27.array(z27.object({ name: z27.string(), secret: z27.string(), reported: z27.boolean() })),
11525
+ toldWaiting: z28.boolean(),
11526
+ runs: z28.array(z28.object({ name: z28.string(), secret: z28.string(), reported: z28.boolean() })),
11396
11527
  /** The subscription usage Claude Code last reported in this worktree. */
11397
11528
  usage: usageSchema.nullable().default(null),
11398
11529
  /** When that usage was reported, or 0 if it was before this was kept. */
11399
- usageAt: z27.number().default(0),
11530
+ usageAt: z28.number().default(0),
11400
11531
  /** The lead agent's Claude Code session, as its `SessionStart` hook reported it. */
11401
- sessionId: z27.string().nullable().default(null),
11532
+ sessionId: z28.string().nullable().default(null),
11402
11533
  /** When the agent's last turn ended with nothing left to do, for shutting it down later. */
11403
- idleSince: z27.number().nullable().default(null),
11534
+ idleSince: z28.number().nullable().default(null),
11404
11535
  /** The agent ran `herd exit`, so its session ends after this turn. */
11405
- exitRequested: z27.boolean().default(false),
11536
+ exitRequested: z28.boolean().default(false),
11406
11537
  /** Whether the agent sent anything with `herd send` this turn. */
11407
- sentThisTurn: z27.boolean().default(false),
11538
+ sentThisTurn: z28.boolean().default(false),
11408
11539
  /** Whether it's been asked this turn to reply. */
11409
- askedToReply: z27.boolean().default(false),
11540
+ askedToReply: z28.boolean().default(false),
11410
11541
  /** Whether it ran `herd handled` this turn, which handles the turn's messages with no reply. */
11411
- handledThisTurn: z27.boolean().default(false),
11542
+ handledThisTurn: z28.boolean().default(false),
11412
11543
  /** The newest waiting message it's been pointed at, so one arrival is pointed out once. */
11413
- nudgedSeq: z27.number().default(0),
11544
+ nudgedSeq: z28.number().default(0),
11414
11545
  /** When a `Stop` hook last ended a turn. */
11415
- hookIdleAt: z27.number().default(0),
11546
+ hookIdleAt: z28.number().default(0),
11416
11547
  /** When a turn last ended with background work still running, which keeps its messages held. */
11417
- pausedAt: z27.number().nullable().default(null),
11548
+ pausedAt: z28.number().nullable().default(null),
11418
11549
  /** The version of the terminal host the lead terminal was opened in, if it was recorded. */
11419
- hostVersion: z27.string().nullable().default(null),
11550
+ hostVersion: z28.string().nullable().default(null),
11420
11551
  /** When a notice last failed for a reason other than someone's draft, to wait before retrying. */
11421
- noticeFailedAt: z27.number().nullable().default(null),
11552
+ noticeFailedAt: z28.number().nullable().default(null),
11422
11553
  /** Why the last notice failed, so the history records each reason once, not every attempt. */
11423
- noticeFailure: z27.string().nullable().default(null),
11554
+ noticeFailure: z28.string().nullable().default(null),
11424
11555
  /** A recorded dialog herd pressed its way out of, so a dialog that stays isn't pressed again. */
11425
- closedDialog: z27.string().nullable().default(null),
11556
+ closedDialog: z28.string().nullable().default(null),
11426
11557
  /**
11427
11558
  * Prompts Claude Code's hooks reported that haven't had their `Stop`. A turn is open while this
11428
11559
  * is above zero. It's a count because a prompt queued mid-turn is reported as it's queued, and
11429
11560
  * runs as a turn of its own, ending with a second `Stop`.
11430
11561
  */
11431
- promptsOpen: z27.number().default(0),
11562
+ promptsOpen: z28.number().default(0),
11432
11563
  /** The messages the latest claim or addition took, for choosing which notice to type. */
11433
- claimedSeqs: z27.array(z27.number()).default([]),
11564
+ claimedSeqs: z28.array(z28.number()).default([]),
11434
11565
  /** The investigator looking at a screen herd can't read, from opening to the owner's answer. */
11435
- investigation: z27.object({
11436
- terminal: z27.string(),
11437
- secret: z27.string(),
11438
- startedAt: z27.number(),
11566
+ investigation: z28.object({
11567
+ terminal: z28.string(),
11568
+ secret: z28.string(),
11569
+ startedAt: z28.number(),
11439
11570
  /** The stuck screen when it opened, saved with the key if the owner approves one. */
11440
- screen: z27.array(z27.string()),
11441
- key: z27.string().nullable(),
11442
- promptId: z27.string().nullable()
11571
+ screen: z28.array(z28.string()),
11572
+ key: z28.string().nullable(),
11573
+ promptId: z28.string().nullable()
11443
11574
  }).nullable().default(null),
11444
11575
  /** The failed notice an investigator was opened for, so each failure gets one. */
11445
- investigatedFailure: z27.number().nullable().default(null),
11576
+ investigatedFailure: z28.number().nullable().default(null),
11446
11577
  /** The agent CLI this conversation's worker runs, as its offer named it. */
11447
- agent: z27.string().default("claude-code"),
11578
+ agent: z28.string().default("claude-code"),
11448
11579
  /** Whether what the current claim took needs a reply, which other agents' messages don't. */
11449
- replyWanted: z27.boolean().default(true),
11580
+ replyWanted: z28.boolean().default(true),
11450
11581
  /** For a delegate: the conversation that started it, which its starting prompt names. */
11451
- parent: z27.string().nullable().default(null),
11582
+ parent: z28.string().nullable().default(null),
11452
11583
  /** Codex's session file for this worktree, once found, and how far the daemon has read it. */
11453
- codexFile: z27.string().nullable().default(null),
11454
- codexOffset: z27.number().default(0),
11584
+ codexFile: z28.string().nullable().default(null),
11585
+ codexOffset: z28.number().default(0),
11455
11586
  /** When the agent was last started, so Codex's new session file is told from older ones. */
11456
- agentStartedAt: z27.number().default(0),
11587
+ agentStartedAt: z28.number().default(0),
11457
11588
  /**
11458
11589
  * The key the agent was last started with, as `HERD_START`. Its `herd inbox` carrying this key
11459
11590
  * is what proves the start works: never a hook, a prompt being taken, or the screen.
11460
11591
  */
11461
- startKey: z27.string().nullable().default(null),
11592
+ startKey: z28.string().nullable().default(null),
11462
11593
  /** Whether the current start has checked in. One from before keys counts as proven. */
11463
- startProven: z27.boolean().default(true),
11594
+ startProven: z28.boolean().default(true),
11464
11595
  /** When the check-in window of an unproven start began, or null once it's proven or for none. */
11465
- checkInFrom: z27.number().nullable().default(null),
11596
+ checkInFrom: z28.number().nullable().default(null),
11466
11597
  /** Whether this start has been flagged as needing someone at its terminal, so it's said once. */
11467
- needsAttention: z27.boolean().default(false),
11598
+ needsAttention: z28.boolean().default(false),
11468
11599
  /** What agy's status line last said its agent was doing, and when. */
11469
- agentState: z27.enum(["working", "idle"]).nullable().default(null),
11470
- agentStateAt: z27.number().default(0)
11600
+ agentState: z28.enum(["working", "idle"]).nullable().default(null),
11601
+ agentStateAt: z28.number().default(0)
11471
11602
  });
11472
- var workspaceSchema = z27.preprocess(fromBeforeFolders, workspaceFields);
11473
- var stateSchema = z27.object({ workspaces: z27.record(z27.string(), workspaceSchema) });
11603
+ var workspaceSchema = z28.preprocess(fromBeforeFolders, workspaceFields);
11604
+ var stateSchema = z28.object({ workspaces: z28.record(z28.string(), workspaceSchema) });
11474
11605
 
11475
11606
  // src/workspaces/claims.ts
11476
11607
  var holder = (ws, workspace) => `${ws.options.machineName()}/${workspace.lead}`;
@@ -11551,7 +11682,7 @@ import { join as join29 } from "node:path";
11551
11682
 
11552
11683
  // src/commands/repo.ts
11553
11684
  init_define_HERD_PACKAGE();
11554
- import { z as z28 } from "zod";
11685
+ import { z as z29 } from "zod";
11555
11686
  var REPO_HELP = `Usage: herd repo <url or owner/name> [folder]
11556
11687
 
11557
11688
  Checks a repo out in this conversation's folder, on a branch named for the conversation, started
@@ -11565,16 +11696,16 @@ var REPOS_HELP = `Usage: herd repos [--json]
11565
11696
 
11566
11697
  Lists the repos in this conversation's folder, the repos checked out in this machine's root, and
11567
11698
  the repos your owner's herd.config.ts describes, with what each is for. Add one with herd repo.`;
11568
- var repoContextSchema = z28.object({
11569
- folder: z28.string(),
11570
- root: z28.string(),
11571
- branch: z28.string(),
11572
- legacy: z28.boolean(),
11573
- legacyReason: z28.string().optional(),
11574
- recorded: z28.array(z28.object({ folder: z28.string(), remote: z28.string(), branch: z28.string() })),
11575
- cloned: z28.array(z28.object({ key: z28.string(), remote: z28.string() })),
11576
- described: z28.array(
11577
- z28.object({ remote: z28.string(), key: z28.string().nullable(), about: z28.string().optional() })
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() })
11578
11709
  )
11579
11710
  });
11580
11711
  var isUrl = (text4) => /^[a-z][a-z0-9+.-]*:\/\//i.test(text4) || text4.startsWith("/") || /^[^@/\s]+@[^:/\s]+:/.test(text4);
@@ -11631,7 +11762,7 @@ async function runRepo(rest) {
11631
11762
  op: "repo-add",
11632
11763
  repoAdd: { asked, ...folderName !== void 0 ? { folder: folderName } : {} }
11633
11764
  });
11634
- const lines = z28.array(z28.string()).safeParse(reply.lines);
11765
+ const lines = z29.array(z29.string()).safeParse(reply.lines);
11635
11766
  if (!lines.success) throw new HerdError("The daemon's answer about this repo wasn't readable.");
11636
11767
  console.log(lines.data.join("\n"));
11637
11768
  return 0;
@@ -12810,21 +12941,21 @@ function resolveAttachments(worktree, files) {
12810
12941
  // src/workers.ts
12811
12942
  init_define_HERD_PACKAGE();
12812
12943
  init_src();
12813
- import { z as z29 } from "zod";
12814
- var workerListingSchema = z29.object({
12815
- workers: z29.array(workerSchema),
12816
- machines: z29.array(
12817
- z29.object({
12818
- id: z29.string(),
12819
- name: z29.string(),
12820
- online: z29.boolean(),
12821
- missing: z29.array(z29.string()),
12822
- configError: z29.string().optional(),
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(),
12823
12954
  // Servers from before versions were reported send none.
12824
- herdVersion: z29.string().nullable().optional()
12955
+ herdVersion: z30.string().nullable().optional()
12825
12956
  })
12826
12957
  ),
12827
- configType: z29.string()
12958
+ configType: z30.string()
12828
12959
  });
12829
12960
  async function readWorkers(fetch2) {
12830
12961
  const response = await fetch2("/api/workers");
@@ -12892,20 +13023,20 @@ function formatWorkers(listing, current = null) {
12892
13023
  );
12893
13024
  return lines.join("\n");
12894
13025
  }
12895
- var routingCheckSchema = z29.object({
12896
- suits: z29.array(z29.object({ key: z29.string(), name: z29.string() })),
12897
- eligible: z29.array(z29.object({ key: z29.string(), name: z29.string() })),
12898
- removed: z29.array(z29.object({ key: z29.string(), name: z29.string(), rule: z29.string() })),
12899
- questions: z29.array(
12900
- z29.object({ id: z29.string(), question: z29.string(), probability: z29.number().nullable() })
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() })
12901
13032
  ),
12902
- fallback: z29.string().optional(),
12903
- fits: z29.array(
12904
- z29.object({
12905
- key: z29.string(),
12906
- fit: z29.number(),
12907
- statement: z29.string().optional(),
12908
- level: z29.string().optional()
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()
12909
13040
  })
12910
13041
  ).optional()
12911
13042
  });
@@ -15360,7 +15491,7 @@ async function runWatch(command, rest) {
15360
15491
  // src/commands/work.ts
15361
15492
  init_define_HERD_PACKAGE();
15362
15493
  init_src();
15363
- import { z as z35 } from "zod";
15494
+ import { z as z36 } from "zod";
15364
15495
  var WORK_HELP = `Usage: herd work <url> [--kind <kind>] [--title "<title>"] [--status <status>]
15365
15496
  [--detail "<detail>"] [--made] [--phase <phase>]
15366
15497
  herd work --remove <url>
@@ -15452,9 +15583,9 @@ ${WORK_HELP}`
15452
15583
  };
15453
15584
  return { kind: "record", change, json };
15454
15585
  }
15455
- var followSchema = z35.union([
15456
- z35.object({ following: z35.literal(true) }),
15457
- z35.object({ following: z35.literal(false), reason: z35.string() })
15586
+ var followSchema = z36.union([
15587
+ z36.object({ following: z36.literal(true) }),
15588
+ z36.object({ following: z36.literal(false), reason: z36.string() })
15458
15589
  ]);
15459
15590
  function formatFollow(follow) {
15460
15591
  return follow.following ? "Following it: its reviews, CI and merge will reach herd inbox." : `Not followed: ${follow.reason}`;
@@ -15470,7 +15601,7 @@ function formatWork(work, own) {
15470
15601
  return ` ${parts.join(" \xB7 ")}${work.made ? " made here" : ""}
15471
15602
  ${work.url}${whose}`;
15472
15603
  }
15473
- var listSchema = z35.array(workObjectSchema);
15604
+ var listSchema = z36.array(workObjectSchema);
15474
15605
  async function runWork(rest) {
15475
15606
  const parsed = parseWork(rest);
15476
15607
  if (parsed.kind === "help") {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@herdingchats/friday",
3
- "version": "0.1.701",
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": "dee83b97beed4102f6d56d692f1c1e306b62dbb6"
25
+ "gitHead": "092263ddfd4398fa1093a095995b57b617e624d3"
26
26
  }