@coreplane/switchboard 1.216.1 → 1.217.0

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 (24) hide show
  1. package/dist/assets/deploy/cloudflare/package.json +1 -1
  2. package/dist/assets/deploy/cloudflare-docs/package.json +1 -1
  3. package/dist/assets/deploy/cloudflare-memory/package.json +1 -1
  4. package/dist/assets/deploy/cloudflare-resident/package.json +1 -1
  5. package/dist/assets/deploy/cloudflare-sandbox/package.json +1 -1
  6. package/dist/assets/package-lock.json +5676 -7966
  7. package/dist/assets/package.json +2 -2
  8. package/dist/assets/source.json +3 -3
  9. package/dist/assets/src/core/runEvents.ts +7 -0
  10. package/dist/assets/src/core/runLedger/types.ts +13 -0
  11. package/dist/assets/src/core/runRecord.ts +4 -2
  12. package/dist/assets/web/dist/.vite/manifest.json +18 -18
  13. package/dist/assets/web/dist/assets/{ResidentDetailPage-CvwjhjlG.js → ResidentDetailPage-CWyEd5fq.js} +1 -1
  14. package/dist/assets/web/dist/assets/{ResidentsIndexPage-DoN6XuNx.js → ResidentsIndexPage-DqFqRTWb.js} +1 -1
  15. package/dist/assets/web/dist/assets/{RunRoutePage-FzLNexjF.js → RunRoutePage-CghwVr_X.js} +3 -3
  16. package/dist/assets/web/dist/assets/{RunsIndexPage-DhSUbF9k.js → RunsIndexPage-BcYehvW5.js} +1 -1
  17. package/dist/assets/web/dist/assets/{ScheduledPage-Bq0Yg4nT.js → ScheduledPage-mKa20Qdd.js} +1 -1
  18. package/dist/assets/web/dist/assets/{StatusDot-D8Wwt1KC.js → StatusDot-QMofJG-E.js} +1 -1
  19. package/dist/assets/web/dist/assets/{Tooltip-DpDK7jWZ.js → Tooltip-D-zVPexc.js} +1 -1
  20. package/dist/assets/web/dist/assets/dist-D43zKxNV.js +1542 -0
  21. package/dist/assets/web/dist/assets/{main-BFkEOy3K.js → main-ClTMtz8n.js} +2 -2
  22. package/dist/cli.js +771 -283
  23. package/package.json +1 -1
  24. package/dist/assets/web/dist/assets/dist-B7BVkB7x.js +0 -1547
package/dist/cli.js CHANGED
@@ -2167,8 +2167,8 @@ var init_effort = __esm({
2167
2167
  });
2168
2168
 
2169
2169
  // ../../src/core/dashboardAuthConfig.ts
2170
- function resolveDashboardAuthMode(configured2, accessConfigured) {
2171
- if (configured2 !== void 0) return configured2;
2170
+ function resolveDashboardAuthMode(configured3, accessConfigured) {
2171
+ if (configured3 !== void 0) return configured3;
2172
2172
  return accessConfigured ? "access" : "none";
2173
2173
  }
2174
2174
  function tokenSubjectOf(actor) {
@@ -7582,6 +7582,159 @@ var init_imagesHost = __esm({
7582
7582
  }
7583
7583
  });
7584
7584
 
7585
+ // ../../src/deploy/artifactsBucket.ts
7586
+ function lifecycleRulesFor(retentionDays) {
7587
+ if (!Number.isInteger(retentionDays) || retentionDays < 1) {
7588
+ throw new Error(`retentionDays must be an integer >= 1, got ${String(retentionDays)}`);
7589
+ }
7590
+ return [
7591
+ {
7592
+ id: EXPIRE_RULE_ID,
7593
+ enabled: true,
7594
+ conditions: { prefix: "" },
7595
+ deleteObjectsTransition: { condition: { type: "Age", maxAge: retentionDays * DAY_SECONDS } }
7596
+ },
7597
+ {
7598
+ id: ABORT_RULE_ID,
7599
+ enabled: true,
7600
+ conditions: { prefix: "" },
7601
+ abortMultipartUploadsTransition: { condition: { type: "Age", maxAge: ABORT_MULTIPART_AFTER_DAYS * DAY_SECONDS } }
7602
+ }
7603
+ ];
7604
+ }
7605
+ function describeRules(rules) {
7606
+ return rules.map((r) => {
7607
+ const days = (s) => `${s / DAY_SECONDS} day${s === DAY_SECONDS ? "" : "s"}`;
7608
+ if (r.deleteObjectsTransition)
7609
+ return `${r.id}: delete every object ${days(r.deleteObjectsTransition.condition.maxAge)} after it was written`;
7610
+ if (r.abortMultipartUploadsTransition)
7611
+ return `${r.id}: abort an incomplete multipart upload after ${days(r.abortMultipartUploadsTransition.condition.maxAge)}`;
7612
+ return `${r.id}: (no transition)`;
7613
+ });
7614
+ }
7615
+ function rulesMatch(readBack, wanted) {
7616
+ const rules = Array.isArray(readBack?.rules) ? readBack.rules : null;
7617
+ if (!rules) return { ok: false, problem: "the read-back carries no `rules` array" };
7618
+ const problems = [];
7619
+ for (const want of wanted) {
7620
+ const got = rules.find((r) => r?.id === want.id);
7621
+ if (!got) {
7622
+ problems.push(`rule ${want.id} is missing`);
7623
+ continue;
7624
+ }
7625
+ if (got.enabled !== true) problems.push(`rule ${want.id} is not enabled`);
7626
+ const wantAge = want.deleteObjectsTransition?.condition.maxAge ?? want.abortMultipartUploadsTransition?.condition.maxAge;
7627
+ const gotAge = got.deleteObjectsTransition?.condition?.maxAge ?? got.abortMultipartUploadsTransition?.condition?.maxAge;
7628
+ if (gotAge !== wantAge) problems.push(`rule ${want.id} has maxAge ${String(gotAge)}, not ${String(wantAge)}`);
7629
+ }
7630
+ return problems.length === 0 ? { ok: true } : { ok: false, problem: problems.join("; ") };
7631
+ }
7632
+ function privacyOf(managed, custom) {
7633
+ const open = [];
7634
+ if (managed.enabled) open.push(`the managed r2.dev domain ${managed.domain} is enabled`);
7635
+ for (const d of custom) if (d.enabled) open.push(`the custom domain ${d.domain} is enabled`);
7636
+ return open.length === 0 ? { private: true, open: [] } : { private: false, open };
7637
+ }
7638
+ function bucketTokenMissingProblem() {
7639
+ return `${API_TOKEN_ENV} is not set \u2014 the bucket's lifecycle rules and domain settings are read and written with a Cloudflare API token holding Workers R2 Storage: Edit (Read suffices for \`artifacts check\`); the bot's ARTIFACTS_R2_* token cannot do this and is never used here`;
7640
+ }
7641
+ function bucketCallProblem(method, url, status3, text) {
7642
+ const words = text.trim().slice(0, 300);
7643
+ const permission = status3 === 401 || status3 === 403 ? ` \u2014 the token lacks the permission (Workers R2 Storage: ${method === "GET" ? "Read" : "Edit"} on this account)` : "";
7644
+ return `${method} ${url} answered HTTP ${status3}${permission}${words ? `: ${words}` : ""}`;
7645
+ }
7646
+ function artifactsBucketHost(options = {}) {
7647
+ const env = options.env ?? process.env;
7648
+ const fetchImpl = options.fetch ?? fetch;
7649
+ const call2 = async (method, path, body) => {
7650
+ const token2 = env[API_TOKEN_ENV]?.trim();
7651
+ if (!token2) return { ok: false, problem: bucketTokenMissingProblem() };
7652
+ const url = `${API}${path}`;
7653
+ let res;
7654
+ try {
7655
+ res = await fetchImpl(url, {
7656
+ method,
7657
+ headers: {
7658
+ authorization: `Bearer ${token2}`,
7659
+ ...body !== void 0 ? { "content-type": "application/json" } : {}
7660
+ },
7661
+ ...body !== void 0 ? { body: JSON.stringify(body) } : {}
7662
+ });
7663
+ } catch (err2) {
7664
+ return { ok: false, problem: `${method} ${url} failed \u2014 ${err2 instanceof Error ? err2.message : String(err2)}` };
7665
+ }
7666
+ const text = await res.text().catch(() => "");
7667
+ if (!res.ok) return { ok: false, problem: bucketCallProblem(method, url, res.status, text) };
7668
+ let envelope;
7669
+ try {
7670
+ envelope = JSON.parse(text);
7671
+ } catch {
7672
+ return { ok: false, problem: `${method} ${url} answered HTTP ${res.status} with a body that is not JSON` };
7673
+ }
7674
+ if (envelope.success !== true) {
7675
+ const errors = Array.isArray(envelope.errors) ? envelope.errors.map((e) => e?.message ?? JSON.stringify(e)).join("; ") : "no error given";
7676
+ return { ok: false, problem: `${method} ${url} answered success: false \u2014 ${errors}` };
7677
+ }
7678
+ return { ok: true, value: envelope.result };
7679
+ };
7680
+ const bucketPath = (account2, bucket, tail) => `/accounts/${encodeURIComponent(account2)}/r2/buckets/${encodeURIComponent(bucket)}/${tail}`;
7681
+ return {
7682
+ async putLifecycle(account2, bucket, rules) {
7683
+ const r = await call2("PUT", bucketPath(account2, bucket, "lifecycle"), { rules });
7684
+ return r.ok ? { ok: true, value: void 0 } : r;
7685
+ },
7686
+ getLifecycle(account2, bucket) {
7687
+ return call2("GET", bucketPath(account2, bucket, "lifecycle"));
7688
+ },
7689
+ async managedDomain(account2, bucket) {
7690
+ const r = await call2("GET", bucketPath(account2, bucket, "domains/managed"));
7691
+ if (!r.ok) return r;
7692
+ const v = r.value;
7693
+ if (!v || typeof v.domain !== "string" || typeof v.enabled !== "boolean") {
7694
+ return {
7695
+ ok: false,
7696
+ problem: `the managed-domain answer has no domain/enabled: ${JSON.stringify(r.value).slice(0, 200)}`
7697
+ };
7698
+ }
7699
+ return { ok: true, value: { domain: v.domain, enabled: v.enabled } };
7700
+ },
7701
+ async customDomains(account2, bucket) {
7702
+ const r = await call2("GET", bucketPath(account2, bucket, "domains/custom"));
7703
+ if (!r.ok) return r;
7704
+ const list = r.value?.domains;
7705
+ if (!Array.isArray(list)) {
7706
+ return {
7707
+ ok: false,
7708
+ problem: `the custom-domains answer has no domains array: ${JSON.stringify(r.value).slice(0, 200)}`
7709
+ };
7710
+ }
7711
+ const domains = [];
7712
+ for (const d of list) {
7713
+ if (typeof d?.domain !== "string" || typeof d.enabled !== "boolean") {
7714
+ return {
7715
+ ok: false,
7716
+ problem: `a custom domain entry has no domain/enabled: ${JSON.stringify(d).slice(0, 200)}`
7717
+ };
7718
+ }
7719
+ domains.push({ domain: d.domain, enabled: d.enabled });
7720
+ }
7721
+ return { ok: true, value: domains };
7722
+ }
7723
+ };
7724
+ }
7725
+ var ABORT_MULTIPART_AFTER_DAYS, DAY_SECONDS, EXPIRE_RULE_ID, ABORT_RULE_ID, API;
7726
+ var init_artifactsBucket = __esm({
7727
+ "../../src/deploy/artifactsBucket.ts"() {
7728
+ "use strict";
7729
+ init_imagesHost();
7730
+ ABORT_MULTIPART_AFTER_DAYS = 1;
7731
+ DAY_SECONDS = 86400;
7732
+ EXPIRE_RULE_ID = "switchboard-artifacts-expire";
7733
+ ABORT_RULE_ID = "switchboard-artifacts-abort-multipart";
7734
+ API = "https://api.cloudflare.com/client/v4";
7735
+ }
7736
+ });
7737
+
7585
7738
  // ../../src/deploy/secrets.ts
7586
7739
  import { z as z3 } from "zod";
7587
7740
  function isOptionalOn(secret2, worker) {
@@ -7842,6 +7995,7 @@ var init_runEvents = __esm({
7842
7995
  "mcp_unavailable",
7843
7996
  "follow_up",
7844
7997
  "resumed",
7998
+ "seed",
7845
7999
  "description_turn",
7846
8000
  "cold_sandbox",
7847
8001
  "pr_not_opened",
@@ -9290,6 +9444,7 @@ var init_resident = __esm({
9290
9444
  ref: data.ref,
9291
9445
  sha: data.sha,
9292
9446
  ...typeof data.workspace === "string" && data.workspace ? { workspace: data.workspace } : {},
9447
+ ...typeof data.user === "string" && data.user ? { user: data.user } : {},
9293
9448
  ...trace.length > 0 ? { trace } : {},
9294
9449
  ...typeof data.attachMs === "number" && Number.isFinite(data.attachMs) ? { attachMs: data.attachMs } : {}
9295
9450
  };
@@ -11996,8 +12151,110 @@ var init_commandRegistry = __esm({
11996
12151
  }
11997
12152
  });
11998
12153
 
11999
- // ../../src/core/commands/config.ts
12154
+ // ../../src/core/commands/artifacts.ts
12000
12155
  import { z as z5 } from "zod";
12156
+ async function configured2(deps) {
12157
+ const cfg = await deps.artifacts.config();
12158
+ if (!cfg) {
12159
+ throw new CommandError(
12160
+ "unavailable",
12161
+ "artifacts: is not configured \u2014 name the bucket under `artifacts.r2` in config.yaml before managing it (docs/how-to/store-run-artifacts.md)"
12162
+ );
12163
+ }
12164
+ return cfg;
12165
+ }
12166
+ function registerArtifactsCommands(registry) {
12167
+ for (const cmd of artifactsCommands) registry.register(cmd);
12168
+ }
12169
+ var defineCommand2, lifecycleOptions, artifactsLifecycle, artifactsCheck, artifactsCommands;
12170
+ var init_artifacts = __esm({
12171
+ "../../src/core/commands/artifacts.ts"() {
12172
+ "use strict";
12173
+ init_config();
12174
+ init_artifactsBucket();
12175
+ init_commandRegistry();
12176
+ defineCommand2 = commandDefiner();
12177
+ lifecycleOptions = z5.object({
12178
+ dryRun: flag.optional().describe("print the rules that would be applied and touch nothing")
12179
+ });
12180
+ artifactsLifecycle = defineCommand2({
12181
+ id: "artifacts.lifecycle",
12182
+ options: lifecycleOptions,
12183
+ action: "deploy:write",
12184
+ effect: "write",
12185
+ surfaces: { chat: false, mcp: false, http: false },
12186
+ describe: "Apply the artifacts bucket's lifecycle rules from config.yaml \u2014 objects expire after `artifacts.retentionDays` (default 30), incomplete multipart uploads abort after one day \u2014 and read them back; `--dry-run` prints the rules and touches nothing. Operator-side: CLOUDFLARE_API_TOKEN with Workers R2 Storage: Edit, never the bot's token.",
12187
+ render: (output) => {
12188
+ const o = output;
12189
+ const lines = describeRules(o.rules).map((l) => ` - ${l}`);
12190
+ const head = o.applied ? `applied ${o.rules.length} lifecycle rule(s) to ${o.bucket} (account ${o.account}) and read them back equal:` : `dry run \u2014 would apply ${o.rules.length} lifecycle rule(s) to ${o.bucket} (account ${o.account}); nothing touched:`;
12191
+ return [head, ...lines].join("\n");
12192
+ },
12193
+ handler: async ({ options, deps }) => {
12194
+ const cfg = await configured2(deps);
12195
+ const retentionDays = cfg.retentionDays ?? ARTIFACT_DEFAULTS.retentionDays;
12196
+ const rules = lifecycleRulesFor(retentionDays);
12197
+ const { accountId: account2, bucket } = cfg.r2;
12198
+ const out = { account: account2, bucket, retentionDays, rules, applied: false, readBack: false };
12199
+ if (options.dryRun) return out;
12200
+ const put = await deps.artifacts.bucket.putLifecycle(account2, bucket, rules);
12201
+ if (!put.ok)
12202
+ throw new CommandError("unavailable", `applying the lifecycle rules to ${bucket} failed \u2014 ${put.problem}`);
12203
+ const read = await deps.artifacts.bucket.getLifecycle(account2, bucket);
12204
+ if (!read.ok)
12205
+ throw new CommandError(
12206
+ "unavailable",
12207
+ `the rules were applied to ${bucket} but reading them back failed \u2014 ${read.problem}; run \`artifacts lifecycle\` again to confirm`
12208
+ );
12209
+ const match = rulesMatch(read.value, rules);
12210
+ if (!match.ok)
12211
+ throw new CommandError(
12212
+ "unavailable",
12213
+ `the rules were applied to ${bucket} but the read-back differs \u2014 ${match.problem}; the bucket's configuration is not what config.yaml says`
12214
+ );
12215
+ return { ...out, applied: true, readBack: true };
12216
+ }
12217
+ });
12218
+ artifactsCheck = defineCommand2({
12219
+ id: "artifacts.check",
12220
+ action: "deploy:write",
12221
+ effect: "read",
12222
+ surfaces: { chat: false, mcp: false, http: false },
12223
+ describe: "Report whether the artifacts bucket is private: its managed r2.dev domain must be disabled and no custom domain enabled \u2014 the two ways R2 serves a bucket without a signature. Operator-side: CLOUDFLARE_API_TOKEN with Workers R2 Storage: Read, never the bot's token.",
12224
+ render: (output) => {
12225
+ const o = output;
12226
+ if (o.private) {
12227
+ return `${o.bucket} (account ${o.account}) is private: the managed domain ${o.managedDomain.domain} is disabled and ${o.customDomains.length === 0 ? "no custom domain is attached" : `none of its ${o.customDomains.length} custom domain(s) is enabled`}`;
12228
+ }
12229
+ return [`${o.bucket} (account ${o.account}) is NOT private:`, ...o.open.map((l) => ` - ${l}`)].join("\n");
12230
+ },
12231
+ handler: async ({ deps }) => {
12232
+ const cfg = await configured2(deps);
12233
+ const { accountId: account2, bucket } = cfg.r2;
12234
+ const managed = await deps.artifacts.bucket.managedDomain(account2, bucket);
12235
+ if (!managed.ok)
12236
+ throw new CommandError("unavailable", `reading ${bucket}'s managed domain failed \u2014 ${managed.problem}`);
12237
+ const custom = await deps.artifacts.bucket.customDomains(account2, bucket);
12238
+ if (!custom.ok)
12239
+ throw new CommandError("unavailable", `reading ${bucket}'s custom domains failed \u2014 ${custom.problem}`);
12240
+ const verdict = privacyOf(managed.value, custom.value);
12241
+ const out = {
12242
+ account: account2,
12243
+ bucket,
12244
+ private: verdict.private,
12245
+ open: [...verdict.open],
12246
+ managedDomain: managed.value,
12247
+ customDomains: custom.value
12248
+ };
12249
+ return out;
12250
+ }
12251
+ });
12252
+ artifactsCommands = [artifactsLifecycle, artifactsCheck];
12253
+ }
12254
+ });
12255
+
12256
+ // ../../src/core/commands/config.ts
12257
+ import { z as z6 } from "zod";
12001
12258
  function targetChannel(caller, channel) {
12002
12259
  const target = channel ?? caller.origin?.channelId;
12003
12260
  if (!target) throw new CommandError("invalid_input", "channel: required on this surface \u2014 pass --channel <id>");
@@ -12017,7 +12274,7 @@ function summarizeScope(s) {
12017
12274
  function registerConfigCommands(registry) {
12018
12275
  for (const cmd of configCommands) registry.register(cmd);
12019
12276
  }
12020
- var defineCommand2, scopeArg, channelOption, effort, effortLevels, modelRef, boundaryOption, who, configShow, configSet, configClear, quote, configInstructions, configCommands;
12277
+ var defineCommand3, scopeArg, channelOption, effort, effortLevels, modelRef, boundaryOption, who, configShow, configSet, configClear, quote, configInstructions, configCommands;
12021
12278
  var init_config4 = __esm({
12022
12279
  "../../src/core/commands/config.ts"() {
12023
12280
  "use strict";
@@ -12027,25 +12284,25 @@ var init_config4 = __esm({
12027
12284
  init_effort();
12028
12285
  init_authorize();
12029
12286
  init_commandRegistry();
12030
- defineCommand2 = commandDefiner();
12287
+ defineCommand3 = commandDefiner();
12031
12288
  scopeArg = {
12032
12289
  name: "scope",
12033
- schema: z5.enum(["channel", "me"]),
12290
+ schema: z6.enum(["channel", "me"]),
12034
12291
  describe: "`channel` (everyone here) or `me` (your own runs)"
12035
12292
  };
12036
- channelOption = z5.string().optional().describe("target channel (default: the channel you are speaking in)");
12037
- effort = z5.enum(EFFORT_LEVELS);
12293
+ channelOption = z6.string().optional().describe("target channel (default: the channel you are speaking in)");
12294
+ effort = z6.enum(EFFORT_LEVELS);
12038
12295
  effortLevels = `<${EFFORT_LEVELS.join("|")}>`;
12039
- modelRef = z5.string().min(1);
12040
- boundaryOption = z5.object({
12041
- maxMinutes: z5.coerce.number().int().min(MIN_BOUNDARY_MINUTES).optional().describe(`cap the wall-clock budget of every run in this scope (minutes, >= ${MIN_BOUNDARY_MINUTES})`),
12042
- maxIdentity: z5.enum(IDENTITIES).optional().describe(`cap the identity runs may act as <${IDENTITIES.join("|")}> \u2014 a preset above it is refused`),
12043
- machines: z5.string().optional().describe(`the machine classes runs may execute on, comma-separated from ${MACHINE_CLASSES.join(", ")}`)
12296
+ modelRef = z6.string().min(1);
12297
+ boundaryOption = z6.object({
12298
+ maxMinutes: z6.coerce.number().int().min(MIN_BOUNDARY_MINUTES).optional().describe(`cap the wall-clock budget of every run in this scope (minutes, >= ${MIN_BOUNDARY_MINUTES})`),
12299
+ maxIdentity: z6.enum(IDENTITIES).optional().describe(`cap the identity runs may act as <${IDENTITIES.join("|")}> \u2014 a preset above it is refused`),
12300
+ machines: z6.string().optional().describe(`the machine classes runs may execute on, comma-separated from ${MACHINE_CLASSES.join(", ")}`)
12044
12301
  }).optional();
12045
12302
  who = (scope) => scope === "channel" ? "channel" : "your";
12046
- configShow = defineCommand2({
12303
+ configShow = defineCommand3({
12047
12304
  id: "config.show",
12048
- options: z5.object({ channel: channelOption }),
12305
+ options: z6.object({ channel: channelOption }),
12049
12306
  action: "config:read",
12050
12307
  effect: "read",
12051
12308
  describe: "The effective agent/model/effort for you in this channel, the defaults, both scopes, and what is restricted.",
@@ -12059,15 +12316,15 @@ var init_config4 = __esm({
12059
12316
  return description;
12060
12317
  }
12061
12318
  });
12062
- configSet = defineCommand2({
12319
+ configSet = defineCommand3({
12063
12320
  id: "config.set",
12064
12321
  args: [scopeArg],
12065
- options: z5.object({
12066
- agent: z5.string().min(1).optional().describe("force which agent handles requests in this scope"),
12322
+ options: z6.object({
12323
+ agent: z6.string().min(1).optional().describe("force which agent handles requests in this scope"),
12067
12324
  model: modelRef.optional().describe("force a model (provider/model) regardless of agent"),
12068
- models: z5.record(z5.string(), modelRef).optional().describe("per-agent model: --models.<agent> provider/model"),
12325
+ models: z6.record(z6.string(), modelRef).optional().describe("per-agent model: --models.<agent> provider/model"),
12069
12326
  effort: effort.optional().describe(`force a model effort ${effortLevels}`),
12070
- efforts: z5.record(z5.string(), effort).optional().describe(`per-agent effort: --efforts.<agent> ${effortLevels}`),
12327
+ efforts: z6.record(z6.string(), effort).optional().describe(`per-agent effort: --efforts.<agent> ${effortLevels}`),
12071
12328
  boundary: boundaryOption,
12072
12329
  channel: channelOption
12073
12330
  }),
@@ -12134,10 +12391,10 @@ var init_config4 = __esm({
12134
12391
  return { scope: args.scope, effective: summarizeScope(effective) };
12135
12392
  }
12136
12393
  });
12137
- configClear = defineCommand2({
12394
+ configClear = defineCommand3({
12138
12395
  id: "config.clear",
12139
12396
  args: [scopeArg],
12140
- options: z5.object({ channel: channelOption }),
12397
+ options: z6.object({ channel: channelOption }),
12141
12398
  action: "config:write",
12142
12399
  effect: "write",
12143
12400
  describe: "Drop every runtime override of a channel (gated) or of yourself; static config.yaml values show through again.",
@@ -12154,18 +12411,18 @@ var init_config4 = __esm({
12154
12411
  }
12155
12412
  });
12156
12413
  quote = (text) => `> ${text.replace(/\n/g, "\n> ")}`;
12157
- configInstructions = defineCommand2({
12414
+ configInstructions = defineCommand3({
12158
12415
  id: "config.instructions",
12159
12416
  args: [
12160
12417
  scopeArg,
12161
12418
  {
12162
12419
  name: "text",
12163
- schema: z5.string().optional(),
12420
+ schema: z6.string().optional(),
12164
12421
  describe: 'the instructions; omit to show the current text, pass "" to clear',
12165
12422
  rest: true
12166
12423
  }
12167
12424
  ],
12168
- options: z5.object({ channel: channelOption }),
12425
+ options: z6.object({ channel: channelOption }),
12169
12426
  action: "config:write",
12170
12427
  effect: "write",
12171
12428
  describe: "Custom instructions for a channel (gated) or for yourself \u2014 advisory prompt content that never changes agent, model, or permissions.",
@@ -12226,7 +12483,7 @@ ${quote(current ?? "")}`;
12226
12483
 
12227
12484
  // ../../src/core/commands/contract.ts
12228
12485
  import { basename, dirname as dirname8, join as join10 } from "node:path";
12229
- import { z as z6 } from "zod";
12486
+ import { z as z7 } from "zod";
12230
12487
  function repoRootOfPlan(planPath) {
12231
12488
  const plans = dirname8(planPath);
12232
12489
  const docs = dirname8(plans);
@@ -12244,24 +12501,24 @@ function renderOutput(output) {
12244
12501
  function registerContractCommands(registry) {
12245
12502
  for (const cmd of contractCommands) registry.register(cmd);
12246
12503
  }
12247
- var defineCommand3, SPECS_DIR, RULES_FILES, contractRender, contractCommands;
12504
+ var defineCommand4, SPECS_DIR, RULES_FILES, contractRender, contractCommands;
12248
12505
  var init_contract2 = __esm({
12249
12506
  "../../src/core/commands/contract.ts"() {
12250
12507
  "use strict";
12251
12508
  init_commandRegistry();
12252
12509
  init_contract();
12253
- defineCommand3 = commandDefiner();
12510
+ defineCommand4 = commandDefiner();
12254
12511
  SPECS_DIR = join10("docs", "reference", "specs");
12255
12512
  RULES_FILES = ["AGENTS.md", "CLAUDE.md"];
12256
- contractRender = defineCommand3({
12513
+ contractRender = defineCommand4({
12257
12514
  id: "contract.render",
12258
- options: z6.object({
12259
- plan: z6.string().min(1).describe("path of the plan record (docs/plans/<file>.md)"),
12260
- unit: z6.string().regex(/^U\d+$/, "expected a unit id like U<n>").describe("the unit to render, as its heading spells it (U<n>)"),
12261
- root: z6.string().min(1).optional().describe("the repository root the specs and rules are read under (default: the root the plan path implies)"),
12262
- branch: z6.string().min(1).optional().describe("the unit's branch, named in the first instruction"),
12263
- onto: z6.string().min(1).optional().describe("the merged parent the branch is rebased onto"),
12264
- maxChars: z6.coerce.number().int().positive().optional().describe(`the rendered block's budget in characters (default ${DEFAULT_CONTRACT_MAX_CHARS})`)
12515
+ options: z7.object({
12516
+ plan: z7.string().min(1).describe("path of the plan record (docs/plans/<file>.md)"),
12517
+ unit: z7.string().regex(/^U\d+$/, "expected a unit id like U<n>").describe("the unit to render, as its heading spells it (U<n>)"),
12518
+ root: z7.string().min(1).optional().describe("the repository root the specs and rules are read under (default: the root the plan path implies)"),
12519
+ branch: z7.string().min(1).optional().describe("the unit's branch, named in the first instruction"),
12520
+ onto: z7.string().min(1).optional().describe("the merged parent the branch is rebased onto"),
12521
+ maxChars: z7.coerce.number().int().positive().optional().describe(`the rendered block's budget in characters (default ${DEFAULT_CONTRACT_MAX_CHARS})`)
12265
12522
  }),
12266
12523
  action: "contract:read",
12267
12524
  effect: "read",
@@ -13908,7 +14165,7 @@ var init_runRecord = __esm({
13908
14165
  RUN_STATUSES = ["completed", "stopped_soft", "stopped_hard", "failed", "interrupted"];
13909
14166
  RUN_ID_PATTERN = /^[A-Za-z0-9_-]{1,64}$/;
13910
14167
  REVIEW_HEAD_PATTERN = /^[0-9a-f]{7,40}$/;
13911
- RUN_SEEDS = ["channel", "parent"];
14168
+ RUN_SEEDS = ["channel", "parent", "session"];
13912
14169
  SESSION_KEY_PATTERN = /^[A-Za-z0-9_.:@+/-]{1,512}$/;
13913
14170
  isIndex = (v) => typeof v === "number" && Number.isInteger(v) && v >= 0;
13914
14171
  MACHINE_CLASSES_IN_RECORD = {
@@ -13953,11 +14210,11 @@ var init_runRecord = __esm({
13953
14210
  });
13954
14211
 
13955
14212
  // ../../src/core/commands/delivery.ts
13956
- import { z as z7 } from "zod";
14213
+ import { z as z8 } from "zod";
13957
14214
  function registerDeliveryCommands(registry) {
13958
14215
  for (const cmd of deliveryCommands) registry.register(cmd);
13959
14216
  }
13960
- var defineCommand4, REPO_SLUG3, ISO_DAY3, asJson, deliveryReport, deliveryCommands;
14217
+ var defineCommand5, REPO_SLUG3, ISO_DAY3, asJson, deliveryReport, deliveryCommands;
13961
14218
  var init_delivery2 = __esm({
13962
14219
  "../../src/core/commands/delivery.ts"() {
13963
14220
  "use strict";
@@ -13965,16 +14222,16 @@ var init_delivery2 = __esm({
13965
14222
  init_commandRegistry();
13966
14223
  init_delivery();
13967
14224
  init_runRecord();
13968
- defineCommand4 = commandDefiner();
14225
+ defineCommand5 = commandDefiner();
13969
14226
  REPO_SLUG3 = /^(?!\.+\/)[\w.-]+\/(?!\.+$)[\w.-]+$/;
13970
14227
  ISO_DAY3 = /^\d{4}-\d{2}-\d{2}$/;
13971
14228
  asJson = (v) => v;
13972
- deliveryReport = defineCommand4({
14229
+ deliveryReport = defineCommand5({
13973
14230
  id: "delivery.report",
13974
- options: z7.object({
13975
- repo: z7.string().regex(REPO_SLUG3).optional().describe("the repository (`owner/name`); default: the first under `delivery.repos`"),
13976
- since: z7.string().regex(ISO_DAY3).optional().describe("the first day of the range (`YYYY-MM-DD`, UTC); the range ends today"),
13977
- weeks: z7.coerce.number().int().min(1).max(MAX_WEEKS).optional().describe(
14231
+ options: z8.object({
14232
+ repo: z8.string().regex(REPO_SLUG3).optional().describe("the repository (`owner/name`); default: the first under `delivery.repos`"),
14233
+ since: z8.string().regex(ISO_DAY3).optional().describe("the first day of the range (`YYYY-MM-DD`, UTC); the range ends today"),
14234
+ weeks: z8.coerce.number().int().min(1).max(MAX_WEEKS).optional().describe(
13978
14235
  `Monday-start weeks back from this one (default 4, at most ${MAX_WEEKS}); --since, when given, decides instead`
13979
14236
  ),
13980
14237
  fresh: flag.optional().describe("read GitHub now instead of the repository's snapshot, and refresh the snapshot")
@@ -14019,7 +14276,7 @@ var init_delivery2 = __esm({
14019
14276
  });
14020
14277
 
14021
14278
  // ../../src/core/commands/deploy.ts
14022
- import { z as z8 } from "zod";
14279
+ import { z as z9 } from "zod";
14023
14280
  function toOptions(o, dryRun, affected) {
14024
14281
  return {
14025
14282
  only: o.only,
@@ -14129,7 +14386,7 @@ async function copyImages(copies, account2, deps) {
14129
14386
  function registerDeployCommands(registry) {
14130
14387
  for (const cmd of deployCommands) registry.register(cmd);
14131
14388
  }
14132
- var defineCommand5, workerList, positiveInt, gitRef, deployOptions, planJson, deployPlan, allOptions, copiedImage, listCopies, deployAll, restartOptions, deployRestart, initOptions, deployInit, configOptions, deployConfig, secretNames, secretsOptions, deploySecrets, imagesOptions, deployImages, deployCommands;
14389
+ var defineCommand6, workerList, positiveInt, gitRef, deployOptions, planJson, deployPlan, allOptions, copiedImage, listCopies, deployAll, restartOptions, deployRestart, initOptions, deployInit, configOptions, deployConfig, secretNames, secretsOptions, deploySecrets, imagesOptions, deployImages, deployCommands;
14133
14390
  var init_deploy = __esm({
14134
14391
  "../../src/core/commands/deploy.ts"() {
14135
14392
  "use strict";
@@ -14142,16 +14399,16 @@ var init_deploy = __esm({
14142
14399
  init_wranglerTemplate();
14143
14400
  init_secrets();
14144
14401
  init_commandRegistry();
14145
- defineCommand5 = commandDefiner();
14146
- workerList = z8.string().transform(
14402
+ defineCommand6 = commandDefiner();
14403
+ workerList = z9.string().transform(
14147
14404
  (s) => s.split(",").map((x) => x.trim()).filter(Boolean)
14148
14405
  ).refine(
14149
14406
  (names) => names.every((n2) => DEPLOY_ORDER.includes(n2)),
14150
14407
  `expected a comma list of Workers (${DEPLOY_ORDER.join(", ")})`
14151
14408
  ).transform((names) => [...new Set(names)]);
14152
- positiveInt = z8.coerce.number().int().positive();
14153
- gitRef = z8.string().regex(/^[A-Za-z0-9_./^~@{}][A-Za-z0-9_./^~@{}-]{0,199}$/, "expected a git revision (a sha, tag, branch, or HEAD^)");
14154
- deployOptions = z8.object({
14409
+ positiveInt = z9.coerce.number().int().positive();
14410
+ gitRef = z9.string().regex(/^[A-Za-z0-9_./^~@{}][A-Za-z0-9_./^~@{}-]{0,199}$/, "expected a git revision (a sha, tag, branch, or HEAD^)");
14411
+ deployOptions = z9.object({
14155
14412
  only: workerList.optional().describe(
14156
14413
  `deploy only these Workers (comma list of ${DEPLOY_ORDER.join(", ")}); with --affected, only those of them that are affected`
14157
14414
  ),
@@ -14170,7 +14427,7 @@ var init_deploy = __esm({
14170
14427
  poll: positiveInt.optional().describe("seconds between preflight retries (default 60)")
14171
14428
  });
14172
14429
  planJson = (plan3) => plan3;
14173
- deployPlan = defineCommand5({
14430
+ deployPlan = defineCommand6({
14174
14431
  id: "deploy.plan",
14175
14432
  options: deployOptions,
14176
14433
  action: "deploy:read",
@@ -14186,7 +14443,7 @@ var init_deploy = __esm({
14186
14443
  });
14187
14444
  copiedImage = (c) => ({ kind: c.kind, source: c.source, target: c.target });
14188
14445
  listCopies = (copies) => copies.map((c) => `${c.kind} \u2190 ${c.source}`).join(", ");
14189
- deployAll = defineCommand5({
14446
+ deployAll = defineCommand6({
14190
14447
  id: "deploy.all",
14191
14448
  options: allOptions,
14192
14449
  action: "deploy:write",
@@ -14237,15 +14494,15 @@ ${formatDeployResults(result.results, result.notAttempted)}`
14237
14494
  return output(result.results, copies, []);
14238
14495
  }
14239
14496
  });
14240
- restartOptions = z8.object({
14241
- only: z8.enum(["bot"]).optional().describe("the Worker to restart \u2014 only `bot` has a long-lived container (default bot)"),
14497
+ restartOptions = z9.object({
14498
+ only: z9.enum(["bot"]).optional().describe("the Worker to restart \u2014 only `bot` has a long-lived container (default bot)"),
14242
14499
  force: flag.optional().describe(
14243
14500
  "restart even when the bot cannot be consulted (no JSON on /healthz) \u2014 the fail-closed cases; runs in flight never refuse, they hand off"
14244
14501
  ),
14245
14502
  waitMax: positiveInt.optional().describe("minutes to wait out a refusal (the bot not answering with JSON) before giving up (default 10)"),
14246
14503
  poll: positiveInt.optional().describe("seconds between retries while refused (default 60)")
14247
14504
  });
14248
- deployRestart = defineCommand5({
14505
+ deployRestart = defineCommand6({
14249
14506
  id: "deploy.restart",
14250
14507
  options: restartOptions,
14251
14508
  action: "deploy:write",
@@ -14286,12 +14543,12 @@ ${formatDeployResults(result.results, result.notAttempted)}`
14286
14543
  };
14287
14544
  }
14288
14545
  });
14289
- initOptions = z8.object({
14546
+ initOptions = z9.object({
14290
14547
  check: flag.optional().describe(
14291
14548
  "compare only: report each rendered file that differs from the one on disk and fail when any does (the `deploy:check` gate); nothing is written"
14292
14549
  )
14293
14550
  });
14294
- deployInit = defineCommand5({
14551
+ deployInit = defineCommand6({
14295
14552
  id: "deploy.init",
14296
14553
  options: initOptions,
14297
14554
  action: "deploy:write",
@@ -14338,12 +14595,12 @@ ${formatDeployResults(result.results, result.notAttempted)}`
14338
14595
  return output;
14339
14596
  }
14340
14597
  });
14341
- configOptions = z8.object({
14342
- source: z8.string().min(1).optional().describe(
14598
+ configOptions = z9.object({
14599
+ source: z9.string().min(1).optional().describe(
14343
14600
  "read the config from this source instead of the profile's configSource (a path, github://owner/repo/path@ref, or op://Vault/Item/field)"
14344
14601
  )
14345
14602
  });
14346
- deployConfig = defineCommand5({
14603
+ deployConfig = defineCommand6({
14347
14604
  id: "deploy.config",
14348
14605
  options: configOptions,
14349
14606
  action: "deploy:write",
@@ -14378,21 +14635,21 @@ the bot reads it on its next start: \`deploy restart\``;
14378
14635
  return output;
14379
14636
  }
14380
14637
  });
14381
- secretNames = z8.string().transform(
14638
+ secretNames = z9.string().transform(
14382
14639
  (s) => s.split(",").map((x) => x.trim()).filter(Boolean)
14383
14640
  ).refine(
14384
14641
  (names) => names.length > 0 && names.every((n2) => /^[A-Z][A-Z0-9_]*$/.test(n2)),
14385
14642
  "expected a comma list of secret names (SCREAMING_SNAKE)"
14386
14643
  ).transform((names) => [...new Set(names)]);
14387
- secretsOptions = z8.object({
14644
+ secretsOptions = z9.object({
14388
14645
  only: secretNames.optional().describe("put only these secrets (comma list of names from deploy/secrets.manifest.json)")
14389
14646
  });
14390
- deploySecrets = defineCommand5({
14647
+ deploySecrets = defineCommand6({
14391
14648
  id: "deploy.secrets",
14392
14649
  args: [
14393
14650
  {
14394
14651
  name: "worker",
14395
- schema: z8.enum(DEPLOY_ORDER),
14652
+ schema: z9.enum(DEPLOY_ORDER),
14396
14653
  describe: `the Worker to provision (${DEPLOY_ORDER.join(", ")})`
14397
14654
  }
14398
14655
  ],
@@ -14454,12 +14711,12 @@ the bot reads it on its next start: \`deploy restart\``;
14454
14711
  return output;
14455
14712
  }
14456
14713
  });
14457
- imagesOptions = z8.object({
14714
+ imagesOptions = z9.object({
14458
14715
  dryRun: flag.optional().describe(
14459
14716
  "say which images the account registry already holds at the version and which would be copied; nothing is copied"
14460
14717
  )
14461
14718
  });
14462
- deployImages = defineCommand5({
14719
+ deployImages = defineCommand6({
14463
14720
  id: "deploy.images",
14464
14721
  options: imagesOptions,
14465
14722
  action: "deploy:write",
@@ -14510,25 +14767,25 @@ the bot reads it on its next start: \`deploy restart\``;
14510
14767
  });
14511
14768
 
14512
14769
  // ../../src/core/commands/env.ts
14513
- import { z as z9 } from "zod";
14770
+ import { z as z10 } from "zod";
14514
14771
  function registerEnvCommands(registry) {
14515
14772
  for (const cmd of envCommands) registry.register(cmd);
14516
14773
  }
14517
- var defineCommand6, envBootstrap, envCommands;
14774
+ var defineCommand7, envBootstrap, envCommands;
14518
14775
  var init_env = __esm({
14519
14776
  "../../src/core/commands/env.ts"() {
14520
14777
  "use strict";
14521
14778
  init_bootstrap();
14522
14779
  init_commandRegistry();
14523
- defineCommand6 = commandDefiner();
14524
- envBootstrap = defineCommand6({
14780
+ defineCommand7 = commandDefiner();
14781
+ envBootstrap = defineCommand7({
14525
14782
  id: "env.bootstrap",
14526
- options: z9.object({
14527
- env: z9.string().min(1).describe("environment to materialize (UAT only; anything else is refused)"),
14528
- service: z9.string().min(1).describe("which downstream service's toolchain env to fill"),
14783
+ options: z10.object({
14784
+ env: z10.string().min(1).describe("environment to materialize (UAT only; anything else is refused)"),
14785
+ service: z10.string().min(1).describe("which downstream service's toolchain env to fill"),
14529
14786
  apply: flag.optional().describe("resolve the refs and WRITE the chmod-600 env file (default: dry-run)"),
14530
- out: z9.string().min(1).optional().describe("env-file path (default .agent-env/<service>.<env>.env)"),
14531
- manifest: z9.string().min(1).optional().describe(`manifest path (default ${DEFAULT_MANIFEST_PATH})`)
14787
+ out: z10.string().min(1).optional().describe("env-file path (default .agent-env/<service>.<env>.env)"),
14788
+ manifest: z10.string().min(1).optional().describe(`manifest path (default ${DEFAULT_MANIFEST_PATH})`)
14532
14789
  }),
14533
14790
  action: "env:write",
14534
14791
  effect: "write",
@@ -15262,7 +15519,7 @@ var init_selfImprovement = __esm({
15262
15519
  });
15263
15520
 
15264
15521
  // ../../src/core/commands/friction.ts
15265
- import { z as z10 } from "zod";
15522
+ import { z as z11 } from "zod";
15266
15523
  async function ledgerOf(deps) {
15267
15524
  let ledger;
15268
15525
  try {
@@ -15290,7 +15547,7 @@ function inProgressHint(diagnosis, finished) {
15290
15547
  function registerFrictionCommands(registry) {
15291
15548
  for (const cmd of frictionCommands) registry.register(cmd);
15292
15549
  }
15293
- var defineCommand7, positiveInt2, repoSlug, NO_LEDGER_MESSAGE, NO_REPO_MESSAGE, asJson2, render, visibleRuns, frictionReport, frictionPropose, frictionAnalyze, frictionCommands;
15550
+ var defineCommand8, positiveInt2, repoSlug, NO_LEDGER_MESSAGE, NO_REPO_MESSAGE, asJson2, render, visibleRuns, frictionReport, frictionPropose, frictionAnalyze, frictionCommands;
15294
15551
  var init_friction = __esm({
15295
15552
  "../../src/core/commands/friction.ts"() {
15296
15553
  "use strict";
@@ -15301,19 +15558,19 @@ var init_friction = __esm({
15301
15558
  init_runEventLines();
15302
15559
  init_runFriction();
15303
15560
  init_selfImprovement();
15304
- defineCommand7 = commandDefiner();
15305
- positiveInt2 = z10.coerce.number().int().positive();
15306
- repoSlug = z10.string().refine((s) => /^[\w.-]+\/[\w.-]+$/.test(s), "expected an owner/name slug");
15561
+ defineCommand8 = commandDefiner();
15562
+ positiveInt2 = z11.coerce.number().int().positive();
15563
+ repoSlug = z11.string().refine((s) => /^[\w.-]+\/[\w.-]+$/.test(s), "expected an owner/name slug");
15307
15564
  NO_LEDGER_MESSAGE = "Run history is not configured in this deployment (`runHistory`), so there are no recent runs to analyze.";
15308
15565
  NO_REPO_MESSAGE = "Set `selfImprovement.repo` (an `owner/name`) in config.yaml to tell `friction propose` where to file issues.";
15309
15566
  asJson2 = (r) => r;
15310
15567
  render = (output) => formatSelfImprovementReport(output);
15311
15568
  visibleRuns = (caller) => predicateFor(caller.actor, "runs:read", "run");
15312
- frictionReport = defineCommand7({
15569
+ frictionReport = defineCommand8({
15313
15570
  id: "friction.report",
15314
15571
  enabledWhen: (caps) => caps.runHistory,
15315
- options: z10.object({
15316
- sinceMs: z10.coerce.number().int().nonnegative().optional().describe("only runs finished at or after this epoch ms"),
15572
+ options: z11.object({
15573
+ sinceMs: z11.coerce.number().int().nonnegative().optional().describe("only runs finished at or after this epoch ms"),
15317
15574
  limit: positiveInt2.optional().describe("newest n runs (default: the ledger's retained window)"),
15318
15575
  minRuns: positiveInt2.optional().describe("distinct runs a pattern must recur in (default selfImprovement.minRuns, else 2)")
15319
15576
  }),
@@ -15339,10 +15596,10 @@ var init_friction = __esm({
15339
15596
  });
15340
15597
  }
15341
15598
  });
15342
- frictionPropose = defineCommand7({
15599
+ frictionPropose = defineCommand8({
15343
15600
  id: "friction.propose",
15344
15601
  enabledWhen: (caps) => caps.runHistory,
15345
- options: z10.object({
15602
+ options: z11.object({
15346
15603
  dryRun: flag.optional().describe("compute and report everything, file nothing"),
15347
15604
  top: positiveInt2.optional().describe("proposals filed per pass (default selfImprovement.top, else 3)"),
15348
15605
  minRuns: positiveInt2.optional().describe("distinct runs a pattern must recur in (default selfImprovement.minRuns, else 2)"),
@@ -15374,17 +15631,17 @@ var init_friction = __esm({
15374
15631
  }
15375
15632
  }
15376
15633
  });
15377
- frictionAnalyze = defineCommand7({
15634
+ frictionAnalyze = defineCommand8({
15378
15635
  id: "friction.analyze",
15379
15636
  args: [
15380
15637
  {
15381
15638
  name: "source",
15382
- schema: z10.string().optional(),
15639
+ schema: z11.string().optional(),
15383
15640
  describe: "a saved run stream: JSON lines of run events or a curl'ed /runs/:id/events SSE capture (default: stdin)"
15384
15641
  }
15385
15642
  ],
15386
- options: z10.object({
15387
- slowMs: z10.coerce.number().nonnegative().optional().describe("a tool call slower than this many ms is a slow-tool finding"),
15643
+ options: z11.object({
15644
+ slowMs: z11.coerce.number().nonnegative().optional().describe("a tool call slower than this many ms is a slow-tool finding"),
15388
15645
  inProgress: flag.optional().describe("the capture was taken mid-run: a trailing call without a result is still executing, not a dead run")
15389
15646
  }),
15390
15647
  action: "friction:read",
@@ -15437,7 +15694,7 @@ var init_friction = __esm({
15437
15694
  });
15438
15695
 
15439
15696
  // ../../src/core/commandSurface.ts
15440
- import { z as z11 } from "zod";
15697
+ import { z as z12 } from "zod";
15441
15698
  function camelToKebab(s) {
15442
15699
  return s.replace(/[A-Z]/g, (c) => `-${c.toLowerCase()}`);
15443
15700
  }
@@ -15509,7 +15766,7 @@ function isBooleanSchema(schema) {
15509
15766
  return false;
15510
15767
  }
15511
15768
  function jsonSchemaOf(schema) {
15512
- const out = z11.toJSONSchema(unwrap(schema), { io: "input" });
15769
+ const out = z12.toJSONSchema(unwrap(schema), { io: "input" });
15513
15770
  delete out.$schema;
15514
15771
  return out;
15515
15772
  }
@@ -15521,7 +15778,7 @@ function jsonSchemaFor(cmd) {
15521
15778
  if (!acceptsUndefined(arg.schema)) required.push(arg.name);
15522
15779
  }
15523
15780
  if (cmd.options) {
15524
- const opts = z11.toJSONSchema(cmd.options, { io: "input" });
15781
+ const opts = z12.toJSONSchema(cmd.options, { io: "input" });
15525
15782
  Object.assign(properties, opts.properties ?? {});
15526
15783
  required.push(...opts.required ?? []);
15527
15784
  }
@@ -15761,17 +16018,17 @@ function chatCommandList(commands) {
15761
16018
  function registerHelpCommands(registry) {
15762
16019
  for (const cmd of helpCommands) registry.register(cmd);
15763
16020
  }
15764
- var defineCommand8, COMMANDS_REFERENCE_URL, DIRECTIVES_HELP, helpShow, helpCommandsList, helpCommands;
16021
+ var defineCommand9, COMMANDS_REFERENCE_URL, DIRECTIVES_HELP, helpShow, helpCommandsList, helpCommands;
15765
16022
  var init_help = __esm({
15766
16023
  "../../src/core/commands/help.ts"() {
15767
16024
  "use strict";
15768
16025
  init_commandRegistry();
15769
16026
  init_commandSurface();
15770
16027
  init_docsLink();
15771
- defineCommand8 = commandDefiner();
16028
+ defineCommand9 = commandDefiner();
15772
16029
  COMMANDS_REFERENCE_URL = `${PROJECT_DOCS_URL}/reference/slack-commands`;
15773
16030
  DIRECTIVES_HELP = "`agent:review model:anthropic/claude-opus-5 effort:low budget:20 look at PR 42` (effort: low | medium | high \u2014 lower = faster turns; budget: whole minutes, at least 2 \u2014 narrows this run's wall clock, never widens it)";
15774
- helpShow = defineCommand8({
16031
+ helpShow = defineCommand9({
15775
16032
  id: "help.show",
15776
16033
  action: "help:read",
15777
16034
  effect: "read",
@@ -15782,7 +16039,7 @@ var init_help = __esm({
15782
16039
  commandsReference: COMMANDS_REFERENCE_URL
15783
16040
  })
15784
16041
  });
15785
- helpCommandsList = defineCommand8({
16042
+ helpCommandsList = defineCommand9({
15786
16043
  id: "help.commands",
15787
16044
  action: "help:read",
15788
16045
  effect: "read",
@@ -17519,7 +17776,7 @@ var init_service = __esm({
17519
17776
  });
17520
17777
 
17521
17778
  // ../../src/core/commands/mcp.ts
17522
- import { z as z12 } from "zod";
17779
+ import { z as z13 } from "zod";
17523
17780
  async function serviceOf(deps) {
17524
17781
  const svc = await deps.mcp.service();
17525
17782
  if ("unavailable" in svc) throw new CommandError("unavailable", svc.unavailable);
@@ -17613,7 +17870,7 @@ function renderShow(output) {
17613
17870
  function registerMcpCommands(registry) {
17614
17871
  for (const cmd of MCP_COMMANDS) registry.register(cmd);
17615
17872
  }
17616
- var defineCommand9, serverName, serverUrl, scopeOption, channelOption2, nameArg, mcpList, mcpAdd, mcpConnect, mcpShow, mcpRemove, MCP_COMMANDS;
17873
+ var defineCommand10, serverName, serverUrl, scopeOption, channelOption2, nameArg, mcpList, mcpAdd, mcpConnect, mcpShow, mcpRemove, MCP_COMMANDS;
17617
17874
  var init_mcp = __esm({
17618
17875
  "../../src/core/commands/mcp.ts"() {
17619
17876
  "use strict";
@@ -17621,18 +17878,18 @@ var init_mcp = __esm({
17621
17878
  init_service();
17622
17879
  init_authorize();
17623
17880
  init_commandRegistry();
17624
- defineCommand9 = commandDefiner();
17625
- serverName = z12.string().refine((s) => MCP_SERVER_NAME_PATTERN.test(s), "expected a slug: lowercase letters, digits, dashes (\u2264 32 chars)");
17626
- serverUrl = z12.string().refine((s) => /^https?:\/\/\S+$/.test(s), "expected an http(s) URL");
17627
- scopeOption = z12.enum(["me", "channel", "org"]).optional().describe(
17881
+ defineCommand10 = commandDefiner();
17882
+ serverName = z13.string().refine((s) => MCP_SERVER_NAME_PATTERN.test(s), "expected a slug: lowercase letters, digits, dashes (\u2264 32 chars)");
17883
+ serverUrl = z13.string().refine((s) => /^https?:\/\/\S+$/.test(s), "expected an http(s) URL");
17884
+ scopeOption = z13.enum(["me", "channel", "org"]).optional().describe(
17628
17885
  "whose server: yours (`me`, default), this channel's (`channel`, channel-config rights), or org-wide (`org`, admins)"
17629
17886
  );
17630
- channelOption2 = z12.string().optional().describe("target channel for `--scope channel` and for `list` (default: the channel you are speaking in)");
17887
+ channelOption2 = z13.string().optional().describe("target channel for `--scope channel` and for `list` (default: the channel you are speaking in)");
17631
17888
  nameArg = { name: "name", schema: serverName, describe: "the server's name (see `mcp list`)" };
17632
- mcpList = defineCommand9({
17889
+ mcpList = defineCommand10({
17633
17890
  id: "mcp.list",
17634
17891
  enabledWhen: (caps) => caps.mcp,
17635
- options: z12.object({ channel: channelOption2 }),
17892
+ options: z13.object({ channel: channelOption2 }),
17636
17893
  action: "mcp:read",
17637
17894
  effect: "read",
17638
17895
  describe: "External MCP servers your runs in this channel can use \u2014 org-wide, this channel's, and your own \u2014 with state and agents; never a credential.",
@@ -17644,7 +17901,7 @@ var init_mcp = __esm({
17644
17901
  return { servers };
17645
17902
  }
17646
17903
  });
17647
- mcpAdd = defineCommand9({
17904
+ mcpAdd = defineCommand10({
17648
17905
  id: "mcp.add",
17649
17906
  enabledWhen: (caps) => caps.mcp,
17650
17907
  args: [
@@ -17654,15 +17911,15 @@ var init_mcp = __esm({
17654
17911
  describe: "a short slug for the server (becomes the tool prefix mcp__<name>__)"
17655
17912
  }
17656
17913
  ],
17657
- options: z12.object({
17914
+ options: z13.object({
17658
17915
  url: serverUrl.describe("the server's Streamable-HTTP endpoint (https://\u2026/mcp)"),
17659
17916
  scope: scopeOption,
17660
- agents: z12.string().transform(
17917
+ agents: z13.string().transform(
17661
17918
  (s) => s.split(",").map((a) => a.trim()).filter(Boolean)
17662
17919
  ).optional().describe(
17663
17920
  "comma-separated agents that may use it (default general,research; only org servers may name coding/review/ship)"
17664
17921
  ),
17665
- auth: z12.enum(["oauth", "bearer", "none"]).optional().describe(
17922
+ auth: z13.enum(["oauth", "bearer", "none"]).optional().describe(
17666
17923
  "how the server authenticates: `oauth` (you sign in on a one-time link), `bearer` (you paste a token on a one-time link), or `none`; omit to detect it from the server"
17667
17924
  ),
17668
17925
  channel: channelOption2
@@ -17687,11 +17944,11 @@ var init_mcp = __esm({
17687
17944
  );
17688
17945
  }
17689
17946
  });
17690
- mcpConnect = defineCommand9({
17947
+ mcpConnect = defineCommand10({
17691
17948
  id: "mcp.connect",
17692
17949
  enabledWhen: (caps) => caps.mcp,
17693
17950
  args: [nameArg],
17694
- options: z12.object({ scope: scopeOption, channel: channelOption2 }),
17951
+ options: z13.object({ scope: scopeOption, channel: channelOption2 }),
17695
17952
  action: "mcp:write",
17696
17953
  effect: "write",
17697
17954
  describe: "A fresh one-time link to sign in to an OAuth server or enter (or replace) a bearer server's token \u2014 only you can complete it; it expires in 10 minutes.",
@@ -17705,11 +17962,11 @@ var init_mcp = __esm({
17705
17962
  return await via(() => svc.connect(actor, target, args.name));
17706
17963
  }
17707
17964
  });
17708
- mcpShow = defineCommand9({
17965
+ mcpShow = defineCommand10({
17709
17966
  id: "mcp.show",
17710
17967
  enabledWhen: (caps) => caps.mcp,
17711
17968
  args: [nameArg],
17712
- options: z12.object({ scope: scopeOption, channel: channelOption2 }),
17969
+ options: z13.object({ scope: scopeOption, channel: channelOption2 }),
17713
17970
  action: "mcp:read",
17714
17971
  effect: "read",
17715
17972
  describe: "One MCP server's entry plus a live probe of the tools it offers (names, read-only flags); never a credential.",
@@ -17725,11 +17982,11 @@ var init_mcp = __esm({
17725
17982
  return await via(() => svc.show(actor, target, args.name));
17726
17983
  }
17727
17984
  });
17728
- mcpRemove = defineCommand9({
17985
+ mcpRemove = defineCommand10({
17729
17986
  id: "mcp.remove",
17730
17987
  enabledWhen: (caps) => caps.mcp,
17731
17988
  args: [nameArg],
17732
- options: z12.object({ scope: scopeOption, channel: channelOption2 }),
17989
+ options: z13.object({ scope: scopeOption, channel: channelOption2 }),
17733
17990
  action: "mcp:write",
17734
17991
  effect: "write",
17735
17992
  describe: "Remove an MCP server you added and its stored credential (yours freely; channel ones need channel-config rights, org-wide ones admin rights).",
@@ -18167,7 +18424,7 @@ var init_llmOutput = __esm({
18167
18424
  });
18168
18425
 
18169
18426
  // ../../src/core/memory/reflection.ts
18170
- import { z as z13 } from "zod";
18427
+ import { z as z14 } from "zod";
18171
18428
  function shouldReflect(input) {
18172
18429
  if (input.agentName !== void 0 && NO_REFLECT_AGENTS.has(input.agentName)) return false;
18173
18430
  return input.toolCalls > 0 || input.historyTurns >= REFLECT_MIN_TURNS;
@@ -18386,7 +18643,7 @@ var init_reflection = __esm({
18386
18643
  "Output raw JSON with no code fence and no prose."
18387
18644
  ].join("\n");
18388
18645
  SUMMARY_INHERITANCE = ["user", "repo", "channel"];
18389
- REFLECTION_ENVELOPE = jsonOutput(z13.object({ facts: z13.array(z13.unknown()), summary: z13.unknown().optional() }), {
18646
+ REFLECTION_ENVELOPE = jsonOutput(z14.object({ facts: z14.array(z14.unknown()), summary: z14.unknown().optional() }), {
18390
18647
  name: "reflection-envelope"
18391
18648
  });
18392
18649
  SCOPE_KINDS = ["org", "user", "repo", "channel"];
@@ -18506,11 +18763,11 @@ var init_workerStore = __esm({
18506
18763
  });
18507
18764
 
18508
18765
  // ../../src/core/memory/buildStore.ts
18509
- function resolveScopeCap(configured2, warn) {
18510
- if (configured2 === void 0) return DEFAULT_SCOPE_CAP;
18511
- if (Number.isInteger(configured2) && configured2 >= 1 && configured2 <= MAX_SCOPE_CAP) return configured2;
18766
+ function resolveScopeCap(configured3, warn) {
18767
+ if (configured3 === void 0) return DEFAULT_SCOPE_CAP;
18768
+ if (Number.isInteger(configured3) && configured3 >= 1 && configured3 <= MAX_SCOPE_CAP) return configured3;
18512
18769
  warn(
18513
- `memory.maxRecordsPerScope must be an integer between 1 and ${MAX_SCOPE_CAP} (got ${String(configured2)}) \u2014 using the default ${DEFAULT_SCOPE_CAP}.`
18770
+ `memory.maxRecordsPerScope must be an integer between 1 and ${MAX_SCOPE_CAP} (got ${String(configured3)}) \u2014 using the default ${DEFAULT_SCOPE_CAP}.`
18514
18771
  );
18515
18772
  return DEFAULT_SCOPE_CAP;
18516
18773
  }
@@ -18618,7 +18875,7 @@ var init_memory = __esm({
18618
18875
  });
18619
18876
 
18620
18877
  // ../../src/core/commands/memory.ts
18621
- import { z as z14 } from "zod";
18878
+ import { z as z15 } from "zod";
18622
18879
  function scopeKeyOfMemoryId(id) {
18623
18880
  const m = /^mem:(.+):\d+$/.exec(id);
18624
18881
  return m ? m[1] : void 0;
@@ -18672,18 +18929,18 @@ _(limit ${limit} reached \u2014 there may be more; narrow with words or raise \`
18672
18929
  function registerMemoryCommands(registry) {
18673
18930
  for (const cmd of memoryCommands) registry.register(cmd);
18674
18931
  }
18675
- var defineCommand10, MEMORY_LIST_LIMIT, MEMORY_LIST_MAX_LIMIT, MEMORY_OFF_MESSAGE, memoryId, repoScopeKey, channelScopeKey, isSharedScope, LIST_SCOPES, memoryList, memoryForget, memoryCommands;
18932
+ var defineCommand11, MEMORY_LIST_LIMIT, MEMORY_LIST_MAX_LIMIT, MEMORY_OFF_MESSAGE, memoryId, repoScopeKey, channelScopeKey, isSharedScope, LIST_SCOPES, memoryList, memoryForget, memoryCommands;
18676
18933
  var init_memory2 = __esm({
18677
18934
  "../../src/core/commands/memory.ts"() {
18678
18935
  "use strict";
18679
18936
  init_authorize();
18680
18937
  init_commandRegistry();
18681
18938
  init_memory();
18682
- defineCommand10 = commandDefiner();
18939
+ defineCommand11 = commandDefiner();
18683
18940
  MEMORY_LIST_LIMIT = 20;
18684
18941
  MEMORY_LIST_MAX_LIMIT = 50;
18685
18942
  MEMORY_OFF_MESSAGE = "Memory is off in this deployment (`memory.enabled` is not set), so there is nothing to list or forget.";
18686
- memoryId = z14.string().refine(
18943
+ memoryId = z15.string().refine(
18687
18944
  (id) => scopeKeyOfMemoryId(id) !== void 0,
18688
18945
  "expected a memory id like mem:<scope>:<n> (see `memory list`)"
18689
18946
  );
@@ -18691,21 +18948,21 @@ var init_memory2 = __esm({
18691
18948
  channelScopeKey = (channelId) => deriveScopeKey("channel", { channelId });
18692
18949
  isSharedScope = (key, keys) => key === keys.org || key.startsWith("repo:") || key.startsWith("channel:");
18693
18950
  LIST_SCOPES = ["me", "org", "repo", "channel", "all"];
18694
- memoryList = defineCommand10({
18951
+ memoryList = defineCommand11({
18695
18952
  id: "memory.list",
18696
18953
  enabledWhen: (caps) => caps.memory,
18697
18954
  args: [
18698
18955
  {
18699
18956
  name: "query",
18700
- schema: z14.string().optional(),
18957
+ schema: z15.string().optional(),
18701
18958
  describe: "words a record must mention (whole-token match)",
18702
18959
  rest: true
18703
18960
  }
18704
18961
  ],
18705
- options: z14.object({
18706
- scope: z14.enum(LIST_SCOPES).optional().describe("which scopes to list (default all: yours, this repo's, this channel's, and the shared org scope)"),
18707
- limit: z14.coerce.number().int().min(1).max(MEMORY_LIST_MAX_LIMIT).optional().describe(`records per scope (default ${MEMORY_LIST_LIMIT}, max ${MEMORY_LIST_MAX_LIMIT})`),
18708
- repo: z14.string().refine((s) => /^[\w.-]+\/[\w.-]+$/.test(s), "expected an owner/name slug").optional().describe("the repo whose scope to list (default: the repo this thread is bound to)")
18962
+ options: z15.object({
18963
+ scope: z15.enum(LIST_SCOPES).optional().describe("which scopes to list (default all: yours, this repo's, this channel's, and the shared org scope)"),
18964
+ limit: z15.coerce.number().int().min(1).max(MEMORY_LIST_MAX_LIMIT).optional().describe(`records per scope (default ${MEMORY_LIST_LIMIT}, max ${MEMORY_LIST_MAX_LIMIT})`),
18965
+ repo: z15.string().refine((s) => /^[\w.-]+\/[\w.-]+$/.test(s), "expected an owner/name slug").optional().describe("the repo whose scope to list (default: the repo this thread is bound to)")
18709
18966
  }),
18710
18967
  action: "memory:read",
18711
18968
  effect: "read",
@@ -18759,7 +19016,7 @@ var init_memory2 = __esm({
18759
19016
  };
18760
19017
  }
18761
19018
  });
18762
- memoryForget = defineCommand10({
19019
+ memoryForget = defineCommand11({
18763
19020
  id: "memory.forget",
18764
19021
  enabledWhen: (caps) => caps.memory,
18765
19022
  args: [{ name: "id", schema: memoryId, describe: "the record id (`mem:<scope>:<n>`, from `memory list`)" }],
@@ -18894,7 +19151,7 @@ var init_residentDiskBudget = __esm({
18894
19151
  });
18895
19152
 
18896
19153
  // ../../src/core/commands/repo.ts
18897
- import { z as z15 } from "zod";
19154
+ import { z as z16 } from "zod";
18898
19155
  async function adminOf(deps, span) {
18899
19156
  const api = await deps.repo.admin();
18900
19157
  if ("unavailable" in api) throw new CommandError("unavailable", api.unavailable);
@@ -19002,7 +19259,7 @@ ${clipOpOutput(text)}
19002
19259
  \`\`\`` : `${icon} ${str4(o.summary)}`;
19003
19260
  }
19004
19261
  function defineOp(op) {
19005
- return defineCommand11({
19262
+ return defineCommand12({
19006
19263
  id: `repo.${op}`,
19007
19264
  // The op needs a backend: the resident service, or the local workspace (`defaultOperations`).
19008
19265
  enabledWhen: (caps) => caps.residents || caps.execution === "local",
@@ -19060,7 +19317,7 @@ function defineOp(op) {
19060
19317
  function registerRepoCommands(registry) {
19061
19318
  for (const cmd of repoCommands) registry.register(cmd);
19062
19319
  }
19063
- var defineCommand11, DEFAULT_COMMANDS, DEFAULT_REF, SETTLE_POLL_MS, SETTLE_MAX_MS, repoSlug2, gitRef2, command, slugArg, n, obj, str4, repoList, repoOnboard, COMMAND_KEYS, dryRunOptions, repoOffboard, repoRebuild, repoReconfigure, NO_OPS_BACKEND_MESSAGE, repoTest, repoBuild, repoCommands;
19320
+ var defineCommand12, DEFAULT_COMMANDS, DEFAULT_REF, SETTLE_POLL_MS, SETTLE_MAX_MS, repoSlug2, gitRef2, command, slugArg, n, obj, str4, repoList, repoOnboard, COMMAND_KEYS, dryRunOptions, repoOffboard, repoRebuild, repoReconfigure, NO_OPS_BACKEND_MESSAGE, repoTest, repoBuild, repoCommands;
19064
19321
  var init_repo = __esm({
19065
19322
  "../../src/core/commands/repo.ts"() {
19066
19323
  "use strict";
@@ -19068,19 +19325,19 @@ var init_repo = __esm({
19068
19325
  init_residentAdmin();
19069
19326
  init_repoToolchain();
19070
19327
  init_residentDiskBudget();
19071
- defineCommand11 = commandDefiner();
19328
+ defineCommand12 = commandDefiner();
19072
19329
  DEFAULT_COMMANDS = NPM_FALLBACK_COMMANDS;
19073
19330
  DEFAULT_REF = "main";
19074
19331
  SETTLE_POLL_MS = 1e4;
19075
19332
  SETTLE_MAX_MS = 12 * 6e4;
19076
- repoSlug2 = z15.string().refine((s) => parseSlug(s) !== void 0, "expected a GitHub owner/name slug").transform((s) => parseSlug(s));
19077
- gitRef2 = z15.string().refine((s) => validRef(s) !== void 0, "expected a plausible git branch ref (e.g. main)");
19078
- command = z15.string().min(1);
19333
+ repoSlug2 = z16.string().refine((s) => parseSlug(s) !== void 0, "expected a GitHub owner/name slug").transform((s) => parseSlug(s));
19334
+ gitRef2 = z16.string().refine((s) => validRef(s) !== void 0, "expected a plausible git branch ref (e.g. main)");
19335
+ command = z16.string().min(1);
19079
19336
  slugArg = { name: "slug", schema: repoSlug2, describe: "GitHub owner/name of the repo" };
19080
19337
  n = (v) => String(typeof v === "number" ? v : v ?? "?");
19081
19338
  obj = (v) => typeof v === "object" && v !== null && !Array.isArray(v) ? v : {};
19082
19339
  str4 = (v) => typeof v === "string" ? v : String(v ?? "?");
19083
- repoList = defineCommand11({
19340
+ repoList = defineCommand12({
19084
19341
  id: "repo.list",
19085
19342
  enabledWhen: (caps) => caps.residents,
19086
19343
  action: "repo:read",
@@ -19097,11 +19354,11 @@ var init_repo = __esm({
19097
19354
  return res.data;
19098
19355
  }
19099
19356
  });
19100
- repoOnboard = defineCommand11({
19357
+ repoOnboard = defineCommand12({
19101
19358
  id: "repo.onboard",
19102
19359
  enabledWhen: (caps) => caps.residents,
19103
19360
  args: [slugArg],
19104
- options: z15.object({
19361
+ options: z16.object({
19105
19362
  ref: gitRef2.optional().describe(`default branch to keep warm (default ${DEFAULT_REF})`),
19106
19363
  test: command.optional().describe(
19107
19364
  "the repo's test command (default: detected from the repo root \u2014 `<pm> test`, or a no-op without a test script)"
@@ -19188,10 +19445,10 @@ var init_repo = __esm({
19188
19445
  settle: (output, { deps }) => settleProvisioning(deps, str4(output.slug))
19189
19446
  });
19190
19447
  COMMAND_KEYS = ["install", "build", "test"];
19191
- dryRunOptions = z15.object({
19448
+ dryRunOptions = z16.object({
19192
19449
  dryRun: flag.optional().describe("compute and return the itemized plan without executing")
19193
19450
  });
19194
- repoOffboard = defineCommand11({
19451
+ repoOffboard = defineCommand12({
19195
19452
  id: "repo.offboard",
19196
19453
  enabledWhen: (caps) => caps.residents,
19197
19454
  args: [slugArg],
@@ -19225,7 +19482,7 @@ var init_repo = __esm({
19225
19482
  return { ...r.data, slug: args.slug, dryRun };
19226
19483
  }
19227
19484
  });
19228
- repoRebuild = defineCommand11({
19485
+ repoRebuild = defineCommand12({
19229
19486
  id: "repo.rebuild",
19230
19487
  enabledWhen: (caps) => caps.residents,
19231
19488
  args: [slugArg],
@@ -19264,11 +19521,11 @@ var init_repo = __esm({
19264
19521
  return { ...r.data, slug: args.slug, dryRun };
19265
19522
  }
19266
19523
  });
19267
- repoReconfigure = defineCommand11({
19524
+ repoReconfigure = defineCommand12({
19268
19525
  id: "repo.reconfigure",
19269
19526
  enabledWhen: (caps) => caps.residents,
19270
19527
  args: [slugArg],
19271
- options: z15.object({
19528
+ options: z16.object({
19272
19529
  ref: gitRef2.optional().describe("new default branch"),
19273
19530
  test: command.optional().describe("new test command"),
19274
19531
  build: command.optional().describe("new build command"),
@@ -20238,7 +20495,7 @@ var init_runsService = __esm({
20238
20495
  });
20239
20496
 
20240
20497
  // ../../src/core/commands/review.ts
20241
- import { z as z16 } from "zod";
20498
+ import { z as z17 } from "zod";
20242
20499
  function artifactJson(a) {
20243
20500
  return {
20244
20501
  ...a.model !== void 0 ? { model: a.model } : {},
@@ -20307,7 +20564,7 @@ function refused2(err2) {
20307
20564
  function registerReviewCommands(registry) {
20308
20565
  for (const cmd of reviewCommands) registry.register(cmd);
20309
20566
  }
20310
- var defineCommand12, runId, ABRIDGE_OFF_MESSAGE, reviewAbridge, reviewCommands;
20567
+ var defineCommand13, runId, ABRIDGE_OFF_MESSAGE, reviewAbridge, reviewCommands;
20311
20568
  var init_review = __esm({
20312
20569
  "../../src/core/commands/review.ts"() {
20313
20570
  "use strict";
@@ -20316,17 +20573,17 @@ var init_review = __esm({
20316
20573
  init_reviewAbridge();
20317
20574
  init_runRecord();
20318
20575
  init_runsService();
20319
- defineCommand12 = commandDefiner();
20320
- runId = z16.string().regex(RUN_ID_PATTERN);
20576
+ defineCommand13 = commandDefiner();
20577
+ runId = z17.string().regex(RUN_ID_PATTERN);
20321
20578
  ABRIDGE_OFF_MESSAGE = "The abridged reading diff is off in this deployment: it needs the `meat` binary on the bot host, the Anthropic provider's credential, `review.readingDiff.provider` not `off`, and run history to store it.";
20322
- reviewAbridge = defineCommand12({
20579
+ reviewAbridge = defineCommand13({
20323
20580
  id: "review.abridge",
20324
20581
  // Hidden unless the abridging can happen here (the binary, the credential,
20325
20582
  // the switch) AND there is a record to append to.
20326
20583
  enabledWhen: (caps) => caps.runHistory && caps.readingDiffAbridge,
20327
20584
  args: [{ name: "id", schema: runId, describe: "run id of a finished PR review" }],
20328
- options: z16.object({
20329
- model: z16.string().min(1).optional().describe("meat's model (default review.readingDiff.meatModel, else claude-opus-5)"),
20585
+ options: z17.object({
20586
+ model: z17.string().min(1).optional().describe("meat's model (default review.readingDiff.meatModel, else claude-opus-5)"),
20330
20587
  force: flag.optional().describe("recompute even when an abridged diff is already stored, or retry a failed one"),
20331
20588
  wait: flag.optional().describe("block until the abridging finishes and answer the outcome instead of `running`")
20332
20589
  }),
@@ -20358,7 +20615,7 @@ var init_review = __esm({
20358
20615
  });
20359
20616
 
20360
20617
  // ../../src/core/commands/runs.ts
20361
- import { z as z17 } from "zod";
20618
+ import { z as z18 } from "zod";
20362
20619
  function unwrap2(res) {
20363
20620
  if (res.ok) return res.value;
20364
20621
  throw new CommandError(res.error, res.error === "not_found" ? "run not found" : "run already finished");
@@ -20399,7 +20656,7 @@ function wrapEvent(e) {
20399
20656
  function registerRunsCommands(registry) {
20400
20657
  for (const cmd of runsCommands) registry.register(cmd);
20401
20658
  }
20402
- var defineCommand13, runId2, positiveInt3, idArg, logDenied, asJson3, runsList, runsGet, runsEvents, runsFriction, runsStop, runsCommands;
20659
+ var defineCommand14, runId2, positiveInt3, idArg, logDenied, asJson3, runsList, runsGet, runsEvents, runsFriction, runsStop, runsCommands;
20403
20660
  var init_runs = __esm({
20404
20661
  "../../src/core/commands/runs.ts"() {
20405
20662
  "use strict";
@@ -20408,21 +20665,24 @@ var init_runs = __esm({
20408
20665
  init_commandRegistry();
20409
20666
  init_runRecord();
20410
20667
  init_runsService();
20411
- defineCommand13 = commandDefiner();
20412
- runId2 = z17.string().regex(RUN_ID_PATTERN);
20413
- positiveInt3 = z17.coerce.number().int().positive();
20668
+ defineCommand14 = commandDefiner();
20669
+ runId2 = z18.string().regex(RUN_ID_PATTERN);
20670
+ positiveInt3 = z18.coerce.number().int().positive();
20414
20671
  idArg = { name: "id", schema: runId2, describe: "run id" };
20415
20672
  logDenied = (entry) => console.log(JSON.stringify({ audit: "authz", ...entry }));
20416
20673
  asJson3 = (v) => v;
20417
- runsList = defineCommand13({
20674
+ runsList = defineCommand14({
20418
20675
  id: "runs.list",
20419
- options: z17.object({
20420
- status: z17.enum(["active", "finished", "all"]).default("active").describe("which runs: live (default), persisted, or both"),
20421
- agent: z17.string().min(1).optional().describe("only runs of this agent"),
20422
- channel: z17.string().min(1).optional().describe("only runs in this platform-namespaced channel (`slack:C0123`, `http:ops`)"),
20423
- sinceMs: z17.coerce.number().int().nonnegative().optional().describe("only runs started at or after this epoch ms"),
20676
+ options: z18.object({
20677
+ status: z18.enum(["active", "finished", "all"]).default("active").describe("which runs: live (default), persisted, or both"),
20678
+ agent: z18.string().min(1).optional().describe("only runs of this agent"),
20679
+ channel: z18.string().min(1).optional().describe("only runs in this platform-namespaced channel (`slack:C0123`, `http:ops`)"),
20680
+ thread: z18.string().min(1).optional().describe(
20681
+ "only runs in this thread, newest first (`slack:C0123:1712.34` \u2014 a thread's story, its sessions' runs)"
20682
+ ),
20683
+ sinceMs: z18.coerce.number().int().nonnegative().optional().describe("only runs started at or after this epoch ms"),
20424
20684
  limit: positiveInt3.max(RUN_LIST_MAX_LIMIT).optional().describe(`page size (max ${RUN_LIST_MAX_LIMIT})`),
20425
- before: z17.coerce.number().int().nonnegative().optional().describe("page cursor: runs finished before this epoch ms"),
20685
+ before: z18.coerce.number().int().nonnegative().optional().describe("page cursor: runs finished before this epoch ms"),
20426
20686
  beforeId: runId2.optional().describe("page cursor tie-breaker: the last id of the previous page")
20427
20687
  }),
20428
20688
  action: "runs:read",
@@ -20430,14 +20690,17 @@ var init_runs = __esm({
20430
20690
  describe: "List runs (live and persisted, newest first) \u2014 metadata only, never message text.",
20431
20691
  handler: async ({ options, caller, deps }) => {
20432
20692
  const visibleTo = predicateFor(caller.actor, "runs:read", "run");
20433
- return asJson3(await (await deps.runs()).listRuns({ ...options, visibleTo }));
20693
+ const { thread, ...rest } = options;
20694
+ return asJson3(
20695
+ await (await deps.runs()).listRuns({ ...rest, ...thread !== void 0 ? { threadKey: thread } : {}, visibleTo })
20696
+ );
20434
20697
  }
20435
20698
  });
20436
- runsGet = defineCommand13({
20699
+ runsGet = defineCommand14({
20437
20700
  id: "runs.get",
20438
20701
  args: [idArg],
20439
- options: z17.object({
20440
- include: z17.enum(["messages"]).optional().describe("add the run's events, free text wrapped as untrusted content")
20702
+ options: z18.object({
20703
+ include: z18.enum(["messages"]).optional().describe("add the run's events, free text wrapped as untrusted content")
20441
20704
  }),
20442
20705
  action: "runs:read",
20443
20706
  effect: "read",
@@ -20457,11 +20720,11 @@ var init_runs = __esm({
20457
20720
  return asJson3(view);
20458
20721
  }
20459
20722
  });
20460
- runsEvents = defineCommand13({
20723
+ runsEvents = defineCommand14({
20461
20724
  id: "runs.events",
20462
20725
  args: [idArg],
20463
- options: z17.object({
20464
- afterSeq: z17.coerce.number().int().nonnegative().optional().describe("events with seq greater than this"),
20726
+ options: z18.object({
20727
+ afterSeq: z18.coerce.number().int().nonnegative().optional().describe("events with seq greater than this"),
20465
20728
  limit: positiveInt3.max(MAX_EVENTS_PAGE).optional().describe(`page size (max ${MAX_EVENTS_PAGE})`)
20466
20729
  }),
20467
20730
  action: "runs:read",
@@ -20475,7 +20738,7 @@ var init_runs = __esm({
20475
20738
  return asJson3({ ...page2, events: page2.events.map(wrapEvent) });
20476
20739
  }
20477
20740
  });
20478
- runsFriction = defineCommand13({
20741
+ runsFriction = defineCommand14({
20479
20742
  id: "runs.friction",
20480
20743
  args: [idArg],
20481
20744
  action: "runs:read",
@@ -20488,10 +20751,10 @@ var init_runs = __esm({
20488
20751
  return asJson3(unwrap2(await runs.getRunFriction(args.id)));
20489
20752
  }
20490
20753
  });
20491
- runsStop = defineCommand13({
20754
+ runsStop = defineCommand14({
20492
20755
  id: "runs.stop",
20493
20756
  args: [idArg],
20494
- options: z17.object({ mode: z17.enum(["soft", "hard"]).describe("soft = finish the current step; hard = abort now") }),
20757
+ options: z18.object({ mode: z18.enum(["soft", "hard"]).describe("soft = finish the current step; hard = abort now") }),
20495
20758
  action: "runs:write",
20496
20759
  effect: "write",
20497
20760
  describe: "Request a live run to stop (`--mode soft` = finish the current step; `hard` = abort now). Records the caller as the actor.",
@@ -20515,16 +20778,16 @@ var init_runs = __esm({
20515
20778
  function registerScheduleCommands(registry) {
20516
20779
  for (const cmd of scheduleCommands) registry.register(cmd);
20517
20780
  }
20518
- var defineCommand14, ACTION_LABEL, utc, scheduleList, scheduleCommands;
20781
+ var defineCommand15, ACTION_LABEL, utc, scheduleList, scheduleCommands;
20519
20782
  var init_schedule = __esm({
20520
20783
  "../../src/core/commands/schedule.ts"() {
20521
20784
  "use strict";
20522
20785
  init_commandRegistry();
20523
20786
  init_schedules();
20524
- defineCommand14 = commandDefiner();
20787
+ defineCommand15 = commandDefiner();
20525
20788
  ACTION_LABEL = { healthz: "keep-alive", watchdog: "resident watchdog" };
20526
20789
  utc = (ms) => `${new Date(ms).toISOString().slice(0, 16).replace("T", " ")} UTC`;
20527
- scheduleList = defineCommand14({
20790
+ scheduleList = defineCommand15({
20528
20791
  id: "schedule.list",
20529
20792
  enabledWhen: (caps) => caps.schedules,
20530
20793
  action: "schedule:read",
@@ -20788,7 +21051,7 @@ var init_plan2 = __esm({
20788
21051
  });
20789
21052
 
20790
21053
  // ../../src/core/commands/setup.ts
20791
- import { z as z18 } from "zod";
21054
+ import { z as z19 } from "zod";
20792
21055
  async function gatherAnswers(o, setup) {
20793
21056
  const ask = setup.prompt;
20794
21057
  const given = (v) => v !== void 0;
@@ -20858,33 +21121,33 @@ function capabilityLine(c) {
20858
21121
  function registerSetupCommands(registry) {
20859
21122
  for (const cmd of setupCommands) registry.register(cmd);
20860
21123
  }
20861
- var defineCommand15, secret, digits, workerName, hostname2, httpUrl, account, initOptions2, DEFAULT_NAME, setupInit, ASK, setupCommands;
21124
+ var defineCommand16, secret, digits, workerName, hostname2, httpUrl, account, initOptions2, DEFAULT_NAME, setupInit, ASK, setupCommands;
20862
21125
  var init_setup = __esm({
20863
21126
  "../../src/core/commands/setup.ts"() {
20864
21127
  "use strict";
20865
21128
  init_plan2();
20866
21129
  init_commandRegistry();
20867
21130
  init_deploy();
20868
- defineCommand15 = commandDefiner();
20869
- secret = z18.string().min(1);
20870
- digits = z18.string().regex(/^\d+$/, "expected a number");
20871
- workerName = z18.string().regex(/^[a-z0-9]([a-z0-9-]*[a-z0-9])?$/, "expected a Worker name: lowercase letters, digits, hyphens");
20872
- hostname2 = z18.string().regex(/^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)+$/, "expected a bare DNS name (example.com)");
20873
- httpUrl = z18.string().regex(/^https?:\/\/\S+$/, "expected an http(s) URL");
20874
- account = z18.string().regex(/^[0-9a-f]{32}$/, "expected a Cloudflare account id: 32 hex characters");
20875
- initOptions2 = z18.object({
20876
- organization: z18.string().min(1).optional().describe("the GitHub organization (or user) this installation serves \u2014 config.yaml's `organization`"),
21131
+ defineCommand16 = commandDefiner();
21132
+ secret = z19.string().min(1);
21133
+ digits = z19.string().regex(/^\d+$/, "expected a number");
21134
+ workerName = z19.string().regex(/^[a-z0-9]([a-z0-9-]*[a-z0-9])?$/, "expected a Worker name: lowercase letters, digits, hyphens");
21135
+ hostname2 = z19.string().regex(/^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)+$/, "expected a bare DNS name (example.com)");
21136
+ httpUrl = z19.string().regex(/^https?:\/\/\S+$/, "expected an http(s) URL");
21137
+ account = z19.string().regex(/^[0-9a-f]{32}$/, "expected a Cloudflare account id: 32 hex characters");
21138
+ initOptions2 = z19.object({
21139
+ organization: z19.string().min(1).optional().describe("the GitHub organization (or user) this installation serves \u2014 config.yaml's `organization`"),
20877
21140
  anthropicKey: secret.optional().describe("an Anthropic API key \u2192 ANTHROPIC_API_KEY and the `anthropic` provider"),
20878
21141
  openaiCompatible: httpUrl.optional().describe(
20879
21142
  "an OpenAI-compatible endpoint's base URL (https://api.openai.com/v1, http://localhost:11434/v1) \u2192 the `openai` provider"
20880
21143
  ),
20881
- model: z18.string().min(1).optional().describe("with --openai-compatible: the model every agent runs on at that endpoint (openai/<model>)"),
21144
+ model: z19.string().min(1).optional().describe("with --openai-compatible: the model every agent runs on at that endpoint (openai/<model>)"),
20882
21145
  modelKey: secret.optional().describe("with --openai-compatible: the endpoint's key \u2192 OPENAI_API_KEY (a local endpoint needs none)"),
20883
21146
  slackAppToken: secret.optional().describe("the Slack app-level token (xapp-\u2026) \u2192 SLACK_APP_TOKEN"),
20884
21147
  slackBotToken: secret.optional().describe("the Slack bot token (xoxb-\u2026) \u2192 SLACK_BOT_TOKEN"),
20885
21148
  githubAppId: digits.optional().describe("the GitHub App's id \u2192 GITHUB_APP_ID"),
20886
21149
  githubInstallationId: digits.optional().describe("the GitHub App's installation id \u2192 GITHUB_APP_INSTALLATION_ID"),
20887
- githubPrivateKeyFile: z18.string().min(1).optional().describe("path to the GitHub App's private key (PEM) \u2192 GITHUB_APP_PRIVATE_KEY, one quoted line"),
21150
+ githubPrivateKeyFile: z19.string().min(1).optional().describe("path to the GitHub App's private key (PEM) \u2192 GITHUB_APP_PRIVATE_KEY, one quoted line"),
20888
21151
  cloudflare: account.optional().describe(
20889
21152
  "a Cloudflare account id: also write deploy/profile.json and render the Worker configs (needs --zone; from a checkout's root, or anywhere when this CLI is the published package)"
20890
21153
  ),
@@ -20894,7 +21157,7 @@ var init_setup = __esm({
20894
21157
  dryRun: flag.optional().describe("write nothing; print each file as it would be written, secrets masked")
20895
21158
  });
20896
21159
  DEFAULT_NAME = "switchboard";
20897
- setupInit = defineCommand15({
21160
+ setupInit = defineCommand16({
20898
21161
  id: "setup.init",
20899
21162
  options: initOptions2,
20900
21163
  action: "setup:write",
@@ -20994,13 +21257,13 @@ function renderStatus(output) {
20994
21257
  function registerStatusCommands(registry) {
20995
21258
  for (const cmd of statusCommands) registry.register(cmd);
20996
21259
  }
20997
- var defineCommand16, statusShow, statusCommands;
21260
+ var defineCommand17, statusShow, statusCommands;
20998
21261
  var init_status = __esm({
20999
21262
  "../../src/core/commands/status.ts"() {
21000
21263
  "use strict";
21001
21264
  init_commandRegistry();
21002
- defineCommand16 = commandDefiner();
21003
- statusShow = defineCommand16({
21265
+ defineCommand17 = commandDefiner();
21266
+ statusShow = defineCommand17({
21004
21267
  id: "status.show",
21005
21268
  action: "status:read",
21006
21269
  effect: "read",
@@ -21039,6 +21302,7 @@ function registerCoreCommands(registry) {
21039
21302
  registerSetupCommands(registry);
21040
21303
  registerContractCommands(registry);
21041
21304
  registerDeliveryCommands(registry);
21305
+ registerArtifactsCommands(registry);
21042
21306
  }
21043
21307
  function coreCommandGroups() {
21044
21308
  const registry = new CommandRegistry({ audit: () => {
@@ -21050,6 +21314,7 @@ var init_all = __esm({
21050
21314
  "../../src/core/commands/all.ts"() {
21051
21315
  "use strict";
21052
21316
  init_commandRegistry();
21317
+ init_artifacts();
21053
21318
  init_config4();
21054
21319
  init_contract2();
21055
21320
  init_delivery2();
@@ -21333,6 +21598,11 @@ function buildCoreCommands(config, store, wiring) {
21333
21598
  images: imagesHostIO({ log: (l) => console.log(l), now: wiring.now ?? systemClock }),
21334
21599
  cliVersion: cliVersionOnHost
21335
21600
  },
21601
+ // `artifacts lifecycle` / `artifacts check`: the config's section and the operator's Cloudflare calls.
21602
+ artifacts: {
21603
+ config: async () => (await cfg()).config.artifacts,
21604
+ bucket: artifactsBucketHost()
21605
+ },
21336
21606
  env: { bootstrap: bootstrapOnHost },
21337
21607
  status: { snapshot: () => (wiring.status ?? unstampedStatus)() },
21338
21608
  // `setup init` writes the operator's working directory — the one the CLI runs in.
@@ -21366,6 +21636,7 @@ var init_commandCatalogue = __esm({
21366
21636
  init_clock();
21367
21637
  init_run();
21368
21638
  init_imagesHost();
21639
+ init_artifactsBucket();
21369
21640
  init_secretsHost();
21370
21641
  init_host3();
21371
21642
  init_executor();
@@ -21584,6 +21855,12 @@ function runPageLink(id) {
21584
21855
  if (!base) return void 0;
21585
21856
  return `${base.replace(/\/+$/, "")}/runs/${encodeURIComponent(id)}`;
21586
21857
  }
21858
+ function artifactLink(id, key, token2) {
21859
+ const page2 = runPageLink(id);
21860
+ if (!page2) return void 0;
21861
+ const path = key.split("/").map(encodeURIComponent).join("/");
21862
+ return `${page2}/artifacts/${path}${token2 ? `?t=${encodeURIComponent(token2)}` : ""}`;
21863
+ }
21587
21864
  function stripPlatformPrefix(id) {
21588
21865
  const i = id.indexOf(":");
21589
21866
  return i === -1 ? id : id.slice(i + 1);
@@ -24256,7 +24533,8 @@ async function readRequest(ctx) {
24256
24533
  }
24257
24534
  function resolveRun(deps, ctx) {
24258
24535
  const { msg, directives, history } = ctx;
24259
- const sticky = lastThreadDirectives(history);
24536
+ const fromTurns = lastThreadDirectives(history);
24537
+ const sticky = ctx.stickyAgent !== void 0 ? { ...fromTurns, agent: ctx.stickyAgent } : fromTurns;
24260
24538
  const resolved = deps.config.resolve({
24261
24539
  channelId: msg.channelId,
24262
24540
  userId: msg.userId,
@@ -24916,9 +25194,24 @@ function providerRouteModel(provider, model, opts = {}) {
24916
25194
  return result.content.filter((p) => p.type === "text").map((p) => p.text).join("");
24917
25195
  };
24918
25196
  }
25197
+ function resolveRouted(deps, msg, directives, sticky, preset) {
25198
+ return deps.config.resolve({
25199
+ channelId: msg.channelId,
25200
+ userId: msg.userId,
25201
+ request: {
25202
+ agent: preset,
25203
+ model: directives.model ?? sticky.model,
25204
+ effort: directives.effort ?? sticky.effort
25205
+ }
25206
+ });
25207
+ }
24919
25208
  async function routeRequest(deps, ctx) {
24920
- const { msg, directives, sticky, agentSource, threadLive, root } = ctx;
25209
+ const { msg, directives, sticky, agentSource, threadLive, root, carried } = ctx;
24921
25210
  const cfg = deps.config.config;
25211
+ if (carried) {
25212
+ console.log(`[route] ${msg.threadKey} routed to ${carried.preset} as before the restart: ${carried.reason}`);
25213
+ return { kind: "routed", resolved: resolveRouted(deps, msg, directives, sticky, carried.preset), route: carried };
25214
+ }
24922
25215
  if (!routingOn(cfg) || agentSource !== "default" || threadLive) return { kind: "unrouted" };
24923
25216
  const modelRef2 = cfg.routing?.model ?? cfg.defaults.models["general"];
24924
25217
  if (!modelRef2) {
@@ -24959,15 +25252,7 @@ async function routeRequest(deps, ctx) {
24959
25252
  console.log(`[route] ${msg.threadKey} not routed (${decision.reason}) \u2014 running ${cfg.defaults.agent}`);
24960
25253
  return decision.compoundRejected ? { kind: "unrouted", rejected: { preset: cfg.defaults.agent, reason: decision.reason, model: modelRef2 } } : { kind: "unrouted" };
24961
25254
  }
24962
- const resolved = deps.config.resolve({
24963
- channelId: msg.channelId,
24964
- userId: msg.userId,
24965
- request: {
24966
- agent: decision.preset,
24967
- model: directives.model ?? sticky.model,
24968
- effort: directives.effort ?? sticky.effort
24969
- }
24970
- });
25255
+ const resolved = resolveRouted(deps, msg, directives, sticky, decision.preset);
24971
25256
  const { parts, collapsed } = decision;
24972
25257
  console.log(
24973
25258
  `[route] ${msg.threadKey} routed to ${decision.preset} on ${modelRef2}${parts ? ` (${parts.length} parts)` : ""}${collapsed ? ` (compound collapsed: ${collapsed.presets.join("+")})` : ""}: ${decision.reason}`
@@ -25074,7 +25359,7 @@ var init_tracingExecutor = __esm({
25074
25359
  });
25075
25360
 
25076
25361
  // ../../src/core/prDescription.ts
25077
- import { z as z19 } from "zod";
25362
+ import { z as z20 } from "zod";
25078
25363
  function parsePrDescription(input) {
25079
25364
  return PrDescriptionSchema.parse(input);
25080
25365
  }
@@ -25362,34 +25647,34 @@ var init_prDescription = __esm({
25362
25647
  "../../src/core/prDescription.ts"() {
25363
25648
  "use strict";
25364
25649
  init_redact();
25365
- line2 = z19.string().trim().min(1).refine((s) => !/[\r\n]/.test(s), "must be a single line (no embedded newlines)");
25366
- prose = z19.string().trim().min(1);
25367
- TourAnchorSchema = z19.object({
25650
+ line2 = z20.string().trim().min(1).refine((s) => !/[\r\n]/.test(s), "must be a single line (no embedded newlines)");
25651
+ prose = z20.string().trim().min(1);
25652
+ TourAnchorSchema = z20.object({
25368
25653
  // Repo-relative: no leading `/`, no `..` SEGMENT (a filename like `a..b.ts` is fine).
25369
- path: z19.string().trim().min(1).refine((p) => !p.startsWith("/") && !p.split("/").includes(".."), "path must be repo-relative"),
25370
- from: z19.number().int().positive(),
25371
- to: z19.number().int().positive()
25654
+ path: z20.string().trim().min(1).refine((p) => !p.startsWith("/") && !p.split("/").includes(".."), "path must be repo-relative"),
25655
+ from: z20.number().int().positive(),
25656
+ to: z20.number().int().positive()
25372
25657
  }).refine((a) => a.to >= a.from, "to must be >= from");
25373
- TourStepSchema = z19.object({
25658
+ TourStepSchema = z20.object({
25374
25659
  title: line2,
25375
25660
  description: prose,
25376
25661
  lookFor: prose.optional(),
25377
25662
  anchor: TourAnchorSchema
25378
25663
  });
25379
- PrDescriptionSchema = z19.object({
25664
+ PrDescriptionSchema = z20.object({
25380
25665
  /** The PR title's single source. Metadata for the PR's own title field —
25381
25666
  * never rendered into the body (GitHub shows the title itself). */
25382
25667
  title: line2,
25383
25668
  tldr: prose,
25384
25669
  whatWhy: prose,
25385
- tour: z19.array(TourStepSchema).min(1),
25670
+ tour: z20.array(TourStepSchema).min(1),
25386
25671
  /** Every touched file the Tour steps did not cover, one line each. */
25387
- remaining: z19.array(z19.object({ path: line2, note: prose })),
25388
- decisions: z19.array(z19.object({ title: line2, rationale: prose })).min(1),
25672
+ remaining: z20.array(z20.object({ path: line2, note: prose })),
25673
+ decisions: z20.array(z20.object({ title: line2, rationale: prose })).min(1),
25389
25674
  risks: prose,
25390
- validation: z19.object({
25675
+ validation: z20.object({
25391
25676
  summary: prose.optional(),
25392
- criteria: z19.array(z19.object({ criterion: prose, proof: prose })).min(1)
25677
+ criteria: z20.array(z20.object({ criterion: prose, proof: prose })).min(1)
25393
25678
  })
25394
25679
  });
25395
25680
  REPO_RE = /^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/;
@@ -26161,10 +26446,11 @@ async function attachThroughStore(path, name, lead, artifacts, ctx) {
26161
26446
  }
26162
26447
  ctx.publish?.({ type: "artifact", direction: "out", key, name, size, contentType });
26163
26448
  if (!ctx.uploadTicket) {
26164
- const where = artifacts.runUrl ? ` \u2014 ${artifacts.runUrl}` : "";
26449
+ const link = artifacts.artifactUrl?.(key);
26450
+ const where = link ? ` \u2014 ${link}` : ` is on the run page as ${key}`;
26165
26451
  await artifacts.reply(`${lead}
26166
- \u{1F4CE} ${name} (${size} bytes) is on the run page${where}`);
26167
- return `attached ${name} (${size} bytes) to the run page; this conversation's channel takes no file uploads, so the lead and the page's link were posted instead`;
26452
+ \u{1F4CE} ${name} (${size} bytes)${where}`);
26453
+ return `attached ${name} (${size} bytes) to the run page as ${key}; this conversation's channel takes no file uploads, so the lead and the file's link were posted instead`;
26168
26454
  }
26169
26455
  const kept = "the file is kept on the run page";
26170
26456
  let ticket;
@@ -26631,7 +26917,7 @@ var init_runs2 = __esm({
26631
26917
  });
26632
26918
 
26633
26919
  // ../../src/tools/workspace.ts
26634
- import { z as z20 } from "zod";
26920
+ import { z as z21 } from "zod";
26635
26921
  var bashTool, readFileTool, writeFileTool, NAME_STATUS_MARK, NAME_STATUS_MARK_LINE, OUTPUT_CUT_RE, diffDigestTool, submitVerdictTool, submitDispositionsTool, submitPrDescriptionTool, handoffEntry, submitHandoffTool, updateStatusTool, TOOLSETS;
26636
26922
  var init_workspace = __esm({
26637
26923
  "../../src/tools/workspace.ts"() {
@@ -26930,7 +27216,7 @@ ${raw.trim()}`;
26930
27216
  try {
26931
27217
  desc = parsePrDescription(input);
26932
27218
  } catch (err2) {
26933
- const detail = err2 instanceof z20.ZodError ? err2.issues.map((i) => `${i.path.join(".") || "(root)"}: ${i.message}`).join("; ") : String(err2);
27219
+ const detail = err2 instanceof z21.ZodError ? err2.issues.map((i) => `${i.path.join(".") || "(root)"}: ${i.message}`).join("; ") : String(err2);
26934
27220
  return `error: invalid PR description \u2014 ${detail}`;
26935
27221
  }
26936
27222
  ctx.onPrDescription?.(desc);
@@ -29213,7 +29499,8 @@ async function reserveRun(deps, ctx) {
29213
29499
  root,
29214
29500
  parentRunId,
29215
29501
  coordinator,
29216
- seed
29502
+ seed,
29503
+ route: route3
29217
29504
  } = ctx;
29218
29505
  if (!resume && !restart) {
29219
29506
  const requestRow = durableInboxMessage(msg, msg.text, receivedAt);
@@ -29242,6 +29529,7 @@ async function reserveRun(deps, ctx) {
29242
29529
  ...parentRunId !== void 0 ? { parentRunId } : {},
29243
29530
  ...coordinatorFields(coordinator),
29244
29531
  ...seed !== void 0 ? { seed } : {},
29532
+ ...route3 !== void 0 ? { route: route3 } : {},
29245
29533
  request: requestRow
29246
29534
  },
29247
29535
  card: card.handle ?? null,
@@ -29472,7 +29760,9 @@ async function claimRun(deps, ctx) {
29472
29760
  root,
29473
29761
  parentRunId,
29474
29762
  coordinator,
29475
- seed
29763
+ seed,
29764
+ route: route3,
29765
+ seedLog
29476
29766
  } = ctx;
29477
29767
  const { resident, binding } = selection;
29478
29768
  let ledgerRun = ctx.ledgerRun;
@@ -29503,6 +29793,7 @@ async function claimRun(deps, ctx) {
29503
29793
  ...parentRunId !== void 0 ? { parentRunId } : {},
29504
29794
  ...coordinatorFields(coordinator),
29505
29795
  ...seed !== void 0 ? { seed } : {},
29796
+ ...route3 !== void 0 ? { route: route3 } : {},
29506
29797
  selection: resident === true ? "resident" : "sandbox",
29507
29798
  ...binding?.workspace !== void 0 ? { workspace: binding.workspace } : {},
29508
29799
  ...requestRow !== void 0 ? { request: requestRow } : {}
@@ -29516,8 +29807,9 @@ async function claimRun(deps, ctx) {
29516
29807
  ({ name, description, inputSchema }) => ({ name, description, inputSchema })
29517
29808
  ),
29518
29809
  // The seed carries the EFFECTIVE budget, so a resume runs on what
29519
- // this run was admitted with, not on the preset's own number.
29520
- seed: { messages, budgetMs: profile.minutes * 6e4 },
29810
+ // this run was admitted with, not on the preset's own number — and,
29811
+ // for a seed read from the log, the rows it reuses (session-log item 9).
29812
+ seed: { messages, budgetMs: profile.minutes * 6e4, ...seedLog ? { log: seedLog } : {} },
29521
29813
  // A stop asked of another container (`/runs/stop` there) reaches this
29522
29814
  // run through its heartbeat and is honored like a local one; a fence
29523
29815
  // (another generation took the run) is a hard stop — nothing more may
@@ -29587,7 +29879,7 @@ function writeFileScripts(path, content) {
29587
29879
  chunks.push(content.slice(i, i + WRITE_CHUNK_CHARS));
29588
29880
  const dir = path.slice(0, path.lastIndexOf("/")) || ".";
29589
29881
  return chunks.map(
29590
- (chunk, i) => i === 0 ? `mkdir -p ${shellQuote(dir)} && umask 077 && printf '%s' ${shellQuote(chunk)} > ${shellQuote(path)}` : `printf '%s' ${shellQuote(chunk)} >> ${shellQuote(path)}`
29882
+ (chunk, i) => i === 0 ? `umask 077 && mkdir -p ${shellQuote(dir)} && printf '%s' ${shellQuote(chunk)} > ${shellQuote(path)}` : `printf '%s' ${shellQuote(chunk)} >> ${shellQuote(path)}`
29591
29883
  );
29592
29884
  }
29593
29885
  function startScript(start3) {
@@ -29598,7 +29890,7 @@ function startScript(start3) {
29598
29890
  `pi ${args.map(shellQuote).join(" ")} <&3 2>>${shellQuote(paths.errLog)} | ${LOG_FILTER} >> ${shellQuote(paths.log)}`
29599
29891
  ].join("; ");
29600
29892
  return [
29601
- `mkdir -p ${shellQuote(paths.dir)} ${shellQuote(paths.sessionDir)} ${shellQuote(paths.commandDir)}`,
29893
+ `(umask 077 && mkdir -p ${shellQuote(paths.dir)} ${shellQuote(paths.sessionDir)} ${shellQuote(paths.commandDir)})`,
29602
29894
  `rm -f ${shellQuote(paths.fifo)}`,
29603
29895
  `mkfifo -m 600 ${shellQuote(paths.fifo)}`,
29604
29896
  `: > ${shellQuote(paths.log)}`,
@@ -29626,6 +29918,9 @@ function killScript(pid) {
29626
29918
  function tailScript(path, bytes) {
29627
29919
  return `tail -c ${bytes} ${shellQuote(path)} 2>/dev/null || true`;
29628
29920
  }
29921
+ function removeScript(dir) {
29922
+ return `rm -rf ${shellQuote(dir)}`;
29923
+ }
29629
29924
  function stdoutOf(operation, out) {
29630
29925
  const exit = parseExitPrefix(out);
29631
29926
  if (exit.failed) throw new PiContainerError(operation, out);
@@ -29694,6 +29989,9 @@ var init_container = __esm({
29694
29989
  return "";
29695
29990
  }
29696
29991
  }
29992
+ async remove(paths) {
29993
+ stdoutOf("remove", await this.exec(removeScript(paths.dir)));
29994
+ }
29697
29995
  exec(script, env) {
29698
29996
  return this.executor.exec(script, { timeoutMs: OP_TIMEOUT_MS, ...env ? { env } : {} });
29699
29997
  }
@@ -30370,8 +30668,8 @@ function piBuiltinToolsFor(identity2) {
30370
30668
  function piThinkingLevel(effort2) {
30371
30669
  return effort2;
30372
30670
  }
30373
- function piRunPaths(runId3, root = "/tmp/switchboard-pi") {
30374
- const dir = `${root}/${runId3}`;
30671
+ function piRunPaths(runId3) {
30672
+ const dir = `/tmp/switchboard-pi-${runId3}`;
30375
30673
  return {
30376
30674
  dir,
30377
30675
  agentDir: `${dir}/agent`,
@@ -30618,7 +30916,7 @@ async function runPiHarness(deps, run2) {
30618
30916
  emit({ type: "run_note", kind, summary, ...mode ? { mode } : {} });
30619
30917
  };
30620
30918
  const bridge = new PiBridge({ emit, onProgress: run2.onProgress, agentSpan, clock: clock3 });
30621
- const paths = piRunPaths(run2.runId, deps.root);
30919
+ const paths = piRunPaths(run2.runId);
30622
30920
  const remainingMs = run2.resume?.remainingMs ?? run2.agent.maxMinutes * 6e4;
30623
30921
  const deadline = now() + remainingMs;
30624
30922
  const warnAt = deadline - Math.min(3 * 6e4, run2.agent.maxMinutes * 15e3);
@@ -30890,6 +31188,8 @@ async function runPiHarness(deps, run2) {
30890
31188
  forget();
30891
31189
  if (pid !== void 0) await container.kill(pid).catch(() => {
30892
31190
  });
31191
+ await container.remove(paths).catch(() => {
31192
+ });
30893
31193
  agentSpan?.end(hardStopped || bypass ? "error" : "ok");
30894
31194
  }
30895
31195
  }
@@ -31564,12 +31864,11 @@ async function runLoop2(deps, ctx) {
31564
31864
  const uploadTicket = io.uploadTicket?.bind(io);
31565
31865
  const nextStagedIndex = ctx.stagingIndex ?? stagingIndex();
31566
31866
  let artifactSeq = 0;
31567
- const runUrl = runPageLink(run2.id);
31568
31867
  const artifacts = deps.artifacts ? {
31569
31868
  store: deps.artifacts,
31570
31869
  runId: run2.id,
31571
31870
  nextSeq: () => ++artifactSeq,
31572
- ...runUrl ? { runUrl } : {},
31871
+ artifactUrl: (key) => artifactLink(run2.id, key, run2.token),
31573
31872
  reply: (text) => io.reply(text)
31574
31873
  } : void 0;
31575
31874
  const toolContext = {
@@ -33309,15 +33608,7 @@ var init_settle = __esm({
33309
33608
  });
33310
33609
 
33311
33610
  // ../../src/core/dispatch/lineage.ts
33312
- async function threadLineage(service, threadKey) {
33313
- let newest;
33314
- try {
33315
- const page2 = await service.listRuns({ status: "all", visibleTo: { kind: "all" }, threadKey, limit: 1 });
33316
- newest = page2.runs[0];
33317
- } catch (err2) {
33318
- console.warn(`[lineage] ${threadKey}: thread read failed \u2014 ${err2 instanceof Error ? err2.message : String(err2)}`);
33319
- return void 0;
33320
- }
33611
+ function lineageOf(newest) {
33321
33612
  if (newest === void 0 || newest.parentRunId === void 0) return void 0;
33322
33613
  return {
33323
33614
  parentRunId: newest.parentRunId,
@@ -33374,6 +33665,161 @@ var init_lineage = __esm({
33374
33665
  }
33375
33666
  });
33376
33667
 
33668
+ // ../../src/core/runLedger/sessionLog.ts
33669
+ function sessionKey(threadKey, agent) {
33670
+ return `${threadKey}:${agent ?? "-"}`;
33671
+ }
33672
+ function requestIndex(seed) {
33673
+ for (let i = seed.length - 1; i >= 0; i--) if (seed[i].role === "user") return i;
33674
+ return 0;
33675
+ }
33676
+ var DEFAULT_SESSION_LOG_MAX_BYTES;
33677
+ var init_sessionLog = __esm({
33678
+ "../../src/core/runLedger/sessionLog.ts"() {
33679
+ "use strict";
33680
+ init_runRecord();
33681
+ init_runRecord();
33682
+ DEFAULT_SESSION_LOG_MAX_BYTES = DEFAULT_RETENTION_POLICY.sessionLogMaxBytes;
33683
+ }
33684
+ });
33685
+
33686
+ // ../../src/core/dispatch/thread.ts
33687
+ async function readThread(service, threadKey) {
33688
+ try {
33689
+ const page2 = await service.listRuns({
33690
+ status: "all",
33691
+ visibleTo: { kind: "all" },
33692
+ threadKey,
33693
+ limit: THREAD_READ_LIMIT
33694
+ });
33695
+ return page2.runs;
33696
+ } catch (err2) {
33697
+ console.warn(`[thread] ${threadKey}: thread read failed \u2014 ${err2 instanceof Error ? err2.message : String(err2)}`);
33698
+ return void 0;
33699
+ }
33700
+ }
33701
+ function continuable(run2) {
33702
+ return run2.finished && run2.session !== void 0 && run2.agent !== void 0;
33703
+ }
33704
+ function stickyAgentOf(runs, onPi) {
33705
+ const newest = runs[0];
33706
+ if (newest === void 0 || !continuable(newest) || !onPi(newest.agent)) return void 0;
33707
+ return newest.agent;
33708
+ }
33709
+ function previousRunOf(runs, agent) {
33710
+ const run2 = runs.find((r) => r.agent === agent && continuable(r));
33711
+ if (run2 === void 0) return void 0;
33712
+ return {
33713
+ ...run2.finishedAt !== void 0 ? { finishedAt: run2.finishedAt } : {},
33714
+ broken: run2.session.range === "broken"
33715
+ };
33716
+ }
33717
+ var THREAD_READ_LIMIT;
33718
+ var init_thread = __esm({
33719
+ "../../src/core/dispatch/thread.ts"() {
33720
+ "use strict";
33721
+ THREAD_READ_LIMIT = 8;
33722
+ }
33723
+ });
33724
+
33725
+ // ../../src/core/dispatch/seed.ts
33726
+ function sessionSeed(input) {
33727
+ const { tail, previous, history, request } = input;
33728
+ const { from, transcript } = tail;
33729
+ if (from === 0 && transcript.turns === 0) return void 0;
33730
+ const notes = [];
33731
+ const messages = [];
33732
+ const compactions = transcript.compactions;
33733
+ const afterCompaction = compactions.reduce((n2, c) => Math.max(n2, c.before), 0);
33734
+ let start3 = -1;
33735
+ for (let i = afterCompaction; i < transcript.messages.length; i++) {
33736
+ const m = transcript.messages[i];
33737
+ if (m.role === "user" && m.content.some((p) => p.type === "text")) {
33738
+ start3 = i;
33739
+ break;
33740
+ }
33741
+ }
33742
+ const summary = compactions.length ? compactions[compactions.length - 1].entry.summary : void 0;
33743
+ const logFrom = start3 < 0 ? from + transcript.turns : from + start3 + compactions.length;
33744
+ const kept = start3 < 0 ? [] : transcript.messages.slice(start3).map(withoutThinking);
33745
+ if (kept.length === 0) {
33746
+ notes.push(
33747
+ transcript.turns === 0 ? "session seed: the log's newest turn alone is over the seed budget \u2014 the run starts from the request" : "session seed: no user text turn in the tail within the seed budget \u2014 the run starts from the request"
33748
+ );
33749
+ }
33750
+ messages.push(...kept);
33751
+ const last = kept[kept.length - 1];
33752
+ if (last?.role === "assistant") {
33753
+ const calls = last.content.filter((p) => p.type === "tool_use");
33754
+ if (calls.length > 0) {
33755
+ messages.push({
33756
+ role: "user",
33757
+ content: calls.map((c) => ({
33758
+ type: "tool_result",
33759
+ toolUseId: c.id,
33760
+ content: settledResult(c.name),
33761
+ isError: true
33762
+ }))
33763
+ });
33764
+ }
33765
+ }
33766
+ if (previous?.broken) messages.push({ role: "user", content: [{ type: "text", text: GAP_MARKER }] });
33767
+ if (previous?.finishedAt === void 0) {
33768
+ notes.push(
33769
+ "session seed: the previous run's end is unknown, so the lines written since could not be told apart \u2014 only the request follows the tail"
33770
+ );
33771
+ } else {
33772
+ const end = previous.finishedAt;
33773
+ for (const h of history) {
33774
+ if (h.role !== "user" || h.at === void 0 || h.at <= end) continue;
33775
+ messages.push({ role: "user", content: turnContent(h.text, h.images, h.documents) });
33776
+ }
33777
+ }
33778
+ messages.push({ role: "user", content: turnContent(request.text, request.images, request.documents) });
33779
+ return {
33780
+ messages,
33781
+ log: { from: logFrom, turns: kept.length },
33782
+ ...summary !== void 0 ? { summary } : {},
33783
+ notes
33784
+ };
33785
+ }
33786
+ async function sessionSeedFor(input) {
33787
+ const key = sessionKey(input.threadKey, input.agent);
33788
+ let tail;
33789
+ try {
33790
+ tail = await input.ledger.readSessionTail(key, SEED_BUDGET_BYTES);
33791
+ } catch (err2) {
33792
+ const why = err2 instanceof Error ? err2.message : String(err2);
33793
+ return { notes: [`session seed: the log ${key} could not be read (${why}) \u2014 the run seeds from the channel`] };
33794
+ }
33795
+ const seed = sessionSeed({
33796
+ tail,
33797
+ previous: previousRunOf(input.thread, input.agent),
33798
+ history: input.history,
33799
+ request: input.request
33800
+ });
33801
+ return seed ? { seed, notes: seed.notes } : { notes: [] };
33802
+ }
33803
+ function withoutThinking(message2) {
33804
+ if (message2.role !== "assistant") return message2;
33805
+ const content = message2.content.filter((p) => p.type !== "thinking" && p.type !== "redacted_thinking");
33806
+ if (content.length === message2.content.length) return message2;
33807
+ return { ...message2, content: content.length ? content : [{ type: "text", text: "(reasoning omitted)" }] };
33808
+ }
33809
+ var SEED_BUDGET_TOKENS, SEED_BUDGET_BYTES, GAP_MARKER, settledResult;
33810
+ var init_seed = __esm({
33811
+ "../../src/core/dispatch/seed.ts"() {
33812
+ "use strict";
33813
+ init_sessionLog();
33814
+ init_messages();
33815
+ init_thread();
33816
+ SEED_BUDGET_TOKENS = 6e4;
33817
+ SEED_BUDGET_BYTES = SEED_BUDGET_TOKENS * 4;
33818
+ GAP_MARKER = "[The log of this conversation ends short of what the previous run saw: its connection to the ledger broke, so its later turns and its final reply are not here.]";
33819
+ settledResult = (toolName) => `The run that made this call ended before this ${toolName} call's result was recorded; its effects are unknown \u2014 re-check them before repeating it.`;
33820
+ }
33821
+ });
33822
+
33377
33823
  // ../../src/core/runEnding.ts
33378
33824
  function createRunEnding(deps) {
33379
33825
  const log = deps.log ?? console.error;
@@ -33511,7 +33957,8 @@ async function dispatch(deps, msg, io, opts = {}) {
33511
33957
  const { directives, history } = await readRequest({ msg, io, root });
33512
33958
  if (await answerOperation(deps, { msg, io, ending, trace, directives, history })) return ended;
33513
33959
  const runsService = deps.runs ?? createRunsService({ registry, store: deps.runStore });
33514
- const lineage = opts.parent || opts.coordinator || resume || restart ? void 0 : await threadLineage(runsService, msg.threadKey);
33960
+ const thread = opts.parent || opts.coordinator || resume || restart || history.length === 0 ? void 0 : await readThread(runsService, msg.threadKey);
33961
+ const lineage = lineageOf(thread?.[0]);
33515
33962
  const parent = opts.parent ?? (lineage ? lineageParent(lineage) : void 0);
33516
33963
  const tellLineage = async (heard) => {
33517
33964
  if (!lineage) return;
@@ -33522,18 +33969,40 @@ async function dispatch(deps, msg, io, opts = {}) {
33522
33969
  heard
33523
33970
  );
33524
33971
  };
33525
- const settled = resolveRun(deps, { msg, directives, history });
33972
+ const harnessBlock = deps.config.config.harness;
33973
+ const onPi = (name) => {
33974
+ const def = AGENTS[name];
33975
+ return def !== void 0 && effectiveHarness(def, harnessBlock) === "pi";
33976
+ };
33977
+ const stickyAgent = thread ? stickyAgentOf(thread, onPi) : void 0;
33978
+ const settled = resolveRun(deps, {
33979
+ msg,
33980
+ directives,
33981
+ history,
33982
+ ...stickyAgent !== void 0 ? { stickyAgent } : {}
33983
+ });
33526
33984
  const { sticky } = settled;
33527
33985
  let { resolved, agentSource } = settled;
33528
33986
  let route3;
33529
33987
  const threadLive = admission.get(msg.threadKey) !== void 0 || !resume && !restart && deps.threadsElsewhere.get(msg.threadKey) !== void 0;
33530
- const routing = await routeRequest(deps, { msg, directives, sticky, agentSource, threadLive, root });
33988
+ const routing = await routeRequest(deps, {
33989
+ msg,
33990
+ directives,
33991
+ sticky,
33992
+ agentSource,
33993
+ threadLive,
33994
+ root,
33995
+ // A restart is the same run under the same card: the row's decision
33996
+ // (run-history item 35) is the route, re-resolved, never re-asked.
33997
+ ...restart?.row.meta.route ? { carried: restart.row.meta.route } : {}
33998
+ });
33531
33999
  if (routing.kind === "routed") {
33532
34000
  resolved = routing.resolved;
33533
34001
  route3 = routing.route;
33534
34002
  agentSource = "route";
33535
34003
  }
33536
34004
  const routeEvent = routing.kind === "routed" ? routing.route : routing.rejected;
34005
+ if (resume?.row.meta.route) route3 = resume.row.meta.route;
33537
34006
  if ((await authorizeAgent(deps, { msg, io, refuse: refuse3, agentName: resolved.agentName })).kind === "refused")
33538
34007
  return ended;
33539
34008
  const agent = resolved.agentName === "ship" ? shipPresetFor(deps.config.config.ship) : getAgent(resolved.agentName);
@@ -33649,8 +34118,23 @@ async function dispatch(deps, msg, io, opts = {}) {
33649
34118
  }
33650
34119
  const contractBlock = opts.contract ? renderContract(opts.contract, { maxChars: DEFAULT_CONTRACT_MAX_CHARS }).text : void 0;
33651
34120
  const requestText = route3?.parts ? compoundBrief(directives.text, route3.parts) : directives.text;
33652
- const seed = opts.seed ? "parent" : "channel";
33653
- const built = buildMessages(opts.seed ?? history, requestText, msg.images, msg.documents);
34121
+ const fromSession = !resume && !opts.seed && thread && effectiveHarness(agent, harnessBlock) === "pi" ? await sessionSeedFor({
34122
+ ledger: deps.runLedger,
34123
+ threadKey: msg.threadKey,
34124
+ agent: agent.name,
34125
+ thread,
34126
+ history,
34127
+ request: {
34128
+ text: requestText,
34129
+ ...msg.images ? { images: msg.images } : {},
34130
+ ...msg.documents ? { documents: msg.documents } : {}
34131
+ }
34132
+ }) : void 0;
34133
+ const session = fromSession?.seed;
34134
+ const seedNotes = fromSession?.notes ?? [];
34135
+ const seed = opts.seed ? "parent" : session ? "session" : "channel";
34136
+ const seedTurns = opts.seed ?? (session ? textTurnsOf(session.messages.slice(0, -1)) : void 0);
34137
+ const built = session ? session.messages : buildMessages(opts.seed ?? history, requestText, msg.images, msg.documents);
33654
34138
  const messages = resume ? resume.plan.messages : contractBlock !== void 0 && agent.name !== "review" ? withContractInFirstUserTurn(built, contractBlock) : built;
33655
34139
  const headPreflight = await authorizePrHead({
33656
34140
  msg,
@@ -33688,12 +34172,14 @@ async function dispatch(deps, msg, io, opts = {}) {
33688
34172
  parentRunId,
33689
34173
  coordinator,
33690
34174
  seed,
33691
- ...opts.seed ? { seedTurns: opts.seed } : {},
34175
+ ...seedTurns ? { seedTurns } : {},
33692
34176
  agentSource,
33693
34177
  ...routeEvent ? { route: routeEvent } : {}
33694
34178
  });
33695
34179
  const { run: run2, runId: runId3, channelVisibility, liveUrl, publishText, publishMeta } = registration;
33696
34180
  registered = run2;
34181
+ for (const summary of seedNotes)
34182
+ registry.publish(run2.id, { type: "run_note", kind: "seed", summary: oneLine(summary), at: clock3() });
33697
34183
  await tellLineage({ kind: "started", runId: runId3 });
33698
34184
  const staged = !resume && deps.artifacts && msg.staged && msg.staged.length > 0 ? msg.staged : [];
33699
34185
  const nextStagedIndex = stagingIndex();
@@ -33717,6 +34203,7 @@ async function dispatch(deps, msg, io, opts = {}) {
33717
34203
  restart,
33718
34204
  card,
33719
34205
  hooks: reservationHooks,
34206
+ route: route3,
33720
34207
  admitted,
33721
34208
  root,
33722
34209
  parentRunId,
@@ -33852,11 +34339,13 @@ async function dispatch(deps, msg, io, opts = {}) {
33852
34339
  resume,
33853
34340
  ledgerRun,
33854
34341
  card,
34342
+ route: route3,
33855
34343
  clock: clock3,
33856
34344
  root,
33857
34345
  parentRunId,
33858
34346
  coordinator,
33859
- seed
34347
+ seed,
34348
+ ...session ? { seedLog: session.log } : {}
33860
34349
  });
33861
34350
  const { spawn: spawn7, runs, steer, wait } = runToolCapabilities(
33862
34351
  { core: deps, dispatch, registry, clock: clock3 },
@@ -34037,6 +34526,9 @@ var init_dispatcher = __esm({
34037
34526
  init_codingChild();
34038
34527
  init_settle();
34039
34528
  init_lineage();
34529
+ init_seed();
34530
+ init_thread();
34531
+ init_select();
34040
34532
  init_spawn();
34041
34533
  init_runsService();
34042
34534
  init_runRegistry();
@@ -34438,24 +34930,6 @@ var init_flusher = __esm({
34438
34930
  }
34439
34931
  });
34440
34932
 
34441
- // ../../src/core/runLedger/sessionLog.ts
34442
- function sessionKey(threadKey, agent) {
34443
- return `${threadKey}:${agent ?? "-"}`;
34444
- }
34445
- function requestIndex(seed) {
34446
- for (let i = seed.length - 1; i >= 0; i--) if (seed[i].role === "user") return i;
34447
- return 0;
34448
- }
34449
- var DEFAULT_SESSION_LOG_MAX_BYTES;
34450
- var init_sessionLog = __esm({
34451
- "../../src/core/runLedger/sessionLog.ts"() {
34452
- "use strict";
34453
- init_runRecord();
34454
- init_runRecord();
34455
- DEFAULT_SESSION_LOG_MAX_BYTES = DEFAULT_RETENTION_POLICY.sessionLogMaxBytes;
34456
- }
34457
- });
34458
-
34459
34933
  // ../../src/core/runLedger/types.ts
34460
34934
  var LEASE_MS, HEARTBEAT_MS, APPEND_FLUSH_MS, APPEND_FLUSH_EVENTS, TRANSCRIPT_REQUEST_BYTES, TRANSCRIPT_PART_BYTES, ATTACHMENT_REF_BYTES, GEN_PATTERN;
34461
34935
  var init_types5 = __esm({
@@ -34508,7 +34982,15 @@ function createLedgerWriteThrough(opts) {
34508
34982
  if (opts2.seed) {
34509
34983
  const key = sessionKey(req.threadKey, req.meta.agent);
34510
34984
  const next = await ledger.sessionTail(key);
34511
- session = { key, seedFrom: next, request: next + requestIndex(opts2.seed), range: { from: next } };
34985
+ let seedFrom = next;
34986
+ if (opts2.log) {
34987
+ if (opts2.log.from + opts2.log.turns === next) seedFrom = opts2.log.from;
34988
+ else
34989
+ warn(
34990
+ `[ledger] ${req.threadKey} run ${req.runId}: the seed names log rows ${opts2.log.from}..${opts2.log.from + opts2.log.turns - 1} but the log's tail is ${next} \u2014 the whole seed is written as new rows`
34991
+ );
34992
+ }
34993
+ session = { key, seedFrom, request: seedFrom + requestIndex(opts2.seed), range: { from: next } };
34512
34994
  }
34513
34995
  const result = await ledger.claim({
34514
34996
  runId: req.runId,
@@ -34669,7 +35151,8 @@ function createLedgerWriteThrough(opts) {
34669
35151
  * closes `interrupted`. */
34670
35152
  async seed(messages, budgetMs) {
34671
35153
  const base = this.session?.seedFrom ?? 0;
34672
- const turns = messages.map((message2, i) => ({ idx: base + i, message: message2 }));
35154
+ const reused = this.session && this.session.range !== "broken" ? this.session.range.from - this.session.seedFrom : 0;
35155
+ const turns = messages.slice(reused).map((message2, i) => ({ idx: base + reused + i, message: message2 }));
34673
35156
  try {
34674
35157
  const seeded = await ledger.seed(this.runId, gen, turns, this.session?.key);
34675
35158
  if (!seeded.ok) {
@@ -34839,7 +35322,7 @@ function createLedgerWriteThrough(opts) {
34839
35322
  const seed = req.seed?.messages;
34840
35323
  if (reserved instanceof TrackedRun) {
34841
35324
  if (!reserved.tracked()) return void 0;
34842
- const claimed3 = await claim(req, seed ? { seed } : {});
35325
+ const claimed3 = await claim(req, seed ? { seed, ...req.seed?.log ? { log: req.seed.log } : {} } : {});
34843
35326
  if (claimed3.outcome === "fenced") {
34844
35327
  reserved.detach("promotion refused (fenced)");
34845
35328
  return void 0;
@@ -34853,7 +35336,7 @@ function createLedgerWriteThrough(opts) {
34853
35336
  if (req.seed) await reserved.seed(req.seed.messages, req.seed.budgetMs);
34854
35337
  return reserved;
34855
35338
  }
34856
- const claimed2 = await claim(req, seed ? { seed } : {});
35339
+ const claimed2 = await claim(req, seed ? { seed, ...req.seed?.log ? { log: req.seed.log } : {} } : {});
34857
35340
  if (claimed2.outcome === "fenced") {
34858
35341
  warn(`[ledger] ${req.threadKey} not tracked: run ${req.runId} is live under another generation`);
34859
35342
  return void 0;
@@ -34902,6 +35385,7 @@ function createLedgerWriteThrough(opts) {
34902
35385
  return [];
34903
35386
  }
34904
35387
  },
35388
+ readSessionTail: (key, maxBytes) => ledger.readSessionTail(key, maxBytes),
34905
35389
  async handoff() {
34906
35390
  const candidates = [...live].filter((r) => r.resumable && r.tracked() && !r.handedOff);
34907
35391
  if (candidates.length === 0) return { marked: [] };
@@ -34952,6 +35436,9 @@ var init_writeThrough = __esm({
34952
35436
  async readInbox(_runId, _afterSeq) {
34953
35437
  return [];
34954
35438
  }
35439
+ async readSessionTail(_key, _maxBytes) {
35440
+ return { from: 0, transcript: { complete: true, turns: 0, messages: [], compactions: [] } };
35441
+ }
34955
35442
  async handoff() {
34956
35443
  return { marked: [] };
34957
35444
  }
@@ -36865,7 +37352,8 @@ ${file.text}`));
36865
37352
  if (STATUS_PREFIXES.some((p) => text.startsWith(p))) continue;
36866
37353
  const files = mm.bot_id ? void 0 : mm.files;
36867
37354
  if (!text && !files?.length) continue;
36868
- kept.push({ role: mm.bot_id ? "assistant" : "user", text, files });
37355
+ const at = mm.ts !== void 0 && Number.isFinite(Number(mm.ts)) ? Math.round(Number(mm.ts) * 1e3) : void 0;
37356
+ kept.push({ role: mm.bot_id ? "assistant" : "user", text, ...at !== void 0 ? { at } : {}, files });
36869
37357
  }
36870
37358
  const imagesByIndex = [];
36871
37359
  const documentsByIndex = [];
@@ -36892,11 +37380,11 @@ ${file.text}`));
36892
37380
  }
36893
37381
  }
36894
37382
  for (let i = 0; i < kept.length; i++) {
36895
- const { role, text } = kept[i];
37383
+ const { role, text, at } = kept[i];
36896
37384
  const images = imagesByIndex[i];
36897
37385
  const documents = documentsByIndex[i];
36898
37386
  if (!text && !images && !documents) continue;
36899
- items.push({ role, text, images, documents });
37387
+ items.push({ role, text, ...at !== void 0 ? { at } : {}, images, documents });
36900
37388
  }
36901
37389
  } catch {
36902
37390
  }
@@ -39724,8 +40212,8 @@ function prUrlOf(events) {
39724
40212
  for (const e of events) if (e.type === "pr_opened" && typeof e.url === "string") url = e.url;
39725
40213
  return url;
39726
40214
  }
39727
- function routedOf(events) {
39728
- return events.some((e) => e.type === "run_meta" && e.agentSource === "route");
40215
+ function routedOf(meta, events) {
40216
+ return meta.route !== void 0 || events.some((e) => e.type === "run_meta" && e.agentSource === "route");
39729
40217
  }
39730
40218
  async function reclaimRuns(opts) {
39731
40219
  const { ledger, gen } = opts;
@@ -39801,7 +40289,7 @@ async function reclaimRuns(opts) {
39801
40289
  events: events.length,
39802
40290
  ...row.meta.agent !== void 0 ? { agent: row.meta.agent } : {},
39803
40291
  ...prUrl2 !== void 0 ? { prUrl: prUrl2 } : {},
39804
- ...routedOf(events) ? { routed: true } : {},
40292
+ ...routedOf(row.meta, events) ? { routed: true } : {},
39805
40293
  ...status3 === "interrupted" ? { note: closureNote(row.meta.agent, prUrl2) } : {}
39806
40294
  });
39807
40295
  log(