@coreplane/switchboard 1.258.0 → 1.259.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.
@@ -164,7 +164,7 @@ defaults:
164
164
  # addressSeverity: minor # blocking | major | minor (default) | nit
165
165
  # readingDiff:
166
166
  # provider: git # git (default) | meat | off
167
- # meatModel: claude-opus-5 # meat's -model; Opus-class is the floor that actually abridges
167
+ # meatModel: claude-opus-5 # meat's -model; required with provider: meat (no built-in model) — Opus-class is the floor that actually abridges
168
168
  # meatTimeoutS: 240 # meat's own budget on the host; past it the abridging fails by name
169
169
 
170
170
  # Static per-channel defaults (channel ID -> scope). Runtime overrides set via
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "switchboard",
3
- "version": "1.258.0",
3
+ "version": "1.259.0",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "switchboard",
9
- "version": "1.258.0",
9
+ "version": "1.259.0",
10
10
  "license": "Apache-2.0",
11
11
  "workspaces": [
12
12
  "web",
@@ -20445,7 +20445,7 @@
20445
20445
  },
20446
20446
  "packages/switchboard": {
20447
20447
  "name": "@coreplane/switchboard",
20448
- "version": "1.258.0",
20448
+ "version": "1.259.0",
20449
20449
  "license": "Apache-2.0",
20450
20450
  "dependencies": {
20451
20451
  "@earendil-works/pi-ai": "0.85.1",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "switchboard",
3
- "version": "1.258.0",
3
+ "version": "1.259.0",
4
4
  "private": true,
5
5
  "description": "Mention it in Slack and an agent reviews the PR, ships the fix, or answers the question — on the model you choose, with its tools running where you decide.",
6
6
  "license": "Apache-2.0",
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.258.0",
3
- "commit": "05d8b84a387c7b7c15ed8dd2dc30f08a5982a981",
4
- "builtAt": "2026-09-20T17:05:48.184Z"
2
+ "version": "1.259.0",
3
+ "commit": "0b28f0fb4925d069547233cbae61f1d3187972d8",
4
+ "builtAt": "2026-09-21T02:10:55.399Z"
5
5
  }
@@ -187,7 +187,7 @@ export interface VendorRef {
187
187
  /** The one vendor parse (record 0052): `parseModelRef` is the only other parser of a
188
188
  * ref. A block that declares a vendor name uses it; a block that declares
189
189
  * `vendor: model`, or a model id that carries its own vendor prefix
190
- * (`openrouter/anthropic/claude-sonnet-5`), reads the vendor off the id's
190
+ * (`openrouter/<vendor>/<model>`), reads the vendor off the id's
191
191
  * first segment; otherwise the block's own name is the vendor. `catalog`
192
192
  * never enters: a block named unlike its catalog still serves the vendor the
193
193
  * declaration or the id names. */
@@ -272,11 +272,11 @@ export function billerHarnessProvider(biller: string | undefined): BillerHarness
272
272
  /** The env var Anthropic's own SDK reads when an `anthropic` provider block names none. */
273
273
  export const ANTHROPIC_API_KEY_ENV = "ANTHROPIC_API_KEY";
274
274
 
275
- /** "anthropic/claude-opus-5" -> { provider: "anthropic", model: "claude-opus-5" } */
275
+ /** "<provider>/<model>" -> { provider, model }: the split at the ref's first slash. */
276
276
  export function parseModelRef(ref: string): { provider: string; model: string } {
277
277
  const i = ref.indexOf("/");
278
278
  if (i === -1) {
279
- throw new Error(`Model "${ref}" must be qualified as "<provider>/<model>", e.g. "anthropic/claude-opus-5"`);
279
+ throw new Error(`Model "${ref}" must be qualified as "<provider>/<model>"`);
280
280
  }
281
281
  return { provider: ref.slice(0, i), model: ref.slice(i + 1) };
282
282
  }
@@ -162,7 +162,7 @@ export type StatusActivity = { kind: "command"; tool: string; command: string }
162
162
 
163
163
  /** A structured progress frame; adapters decide how to render it. */
164
164
  export interface StatusUpdate {
165
- /** one-line headline, e.g. "⚡ review on anthropic/claude-fable-5 · 42s" */
165
+ /** one-line headline, e.g. "⚡ review on <provider>/<model> · 42s" */
166
166
  title: string;
167
167
  /** the agent's checklist and any lead lines, one per line */
168
168
  detail?: string;
package/dist/cli.js CHANGED
@@ -2846,7 +2846,7 @@ function billerHarnessProvider(biller) {
2846
2846
  function parseModelRef(ref) {
2847
2847
  const i = ref.indexOf("/");
2848
2848
  if (i === -1) {
2849
- throw new Error(`Model "${ref}" must be qualified as "<provider>/<model>", e.g. "anthropic/claude-opus-5"`);
2849
+ throw new Error(`Model "${ref}" must be qualified as "<provider>/<model>"`);
2850
2850
  }
2851
2851
  return { provider: ref.slice(0, i), model: ref.slice(i + 1) };
2852
2852
  }
@@ -7566,6 +7566,12 @@ function addressSeverityProblem(path, value) {
7566
7566
  function validateReview(review) {
7567
7567
  const problem = addressSeverityProblem("review.addressSeverity", review.addressSeverity);
7568
7568
  if (problem) throw new Error(`config.yaml: ${problem}`);
7569
+ const readingDiff = review.readingDiff;
7570
+ if (readingDiff?.provider === "meat" && !readingDiff.meatModel) {
7571
+ throw new Error(
7572
+ 'config.yaml: review.readingDiff.provider is "meat" but review.readingDiff.meatModel is not set \u2014 name the model meat abridges with'
7573
+ );
7574
+ }
7569
7575
  }
7570
7576
  function githubBindingProblem(path, raw) {
7571
7577
  const loginProblem = (login) => {
@@ -13480,9 +13486,13 @@ function resolveReadingDiff(cfg, env) {
13480
13486
  const choice = envChoice ?? cfg?.provider ?? "git";
13481
13487
  if (choice === "off") return null;
13482
13488
  const timeout = typeof cfg?.meatTimeoutS === "number" && cfg.meatTimeoutS > 0 ? Math.floor(cfg.meatTimeoutS) : MEAT_TIMEOUT_S_DEFAULT;
13483
- const meatModel = cfg?.meatModel || (choice === "meat" ? MEAT_MODEL_DEFAULT : void 0);
13489
+ const meatModel = cfg?.meatModel || void 0;
13484
13490
  return { provider: choice, meatTimeoutS: timeout, ...meatModel ? { meatModel } : {} };
13485
13491
  }
13492
+ function readingDiffStartupWarning(cfg, env) {
13493
+ const resolved = resolveReadingDiff(cfg, env);
13494
+ return resolved?.provider === "meat" && !resolved.meatModel ? `[reading-diff] ${MEAT_MODEL_MISSING}` : void 0;
13495
+ }
13486
13496
  function readingDiffCommand(baseRef) {
13487
13497
  const range = shellQuote(`origin/${baseRef ?? "HEAD"}...HEAD`);
13488
13498
  return `git diff --no-color --end-of-options ${range}`;
@@ -13555,7 +13565,7 @@ async function produceReadingDiff(executor, opts, span) {
13555
13565
  return null;
13556
13566
  }
13557
13567
  }
13558
- var MEAT_TIMEOUT_S_DEFAULT, MEAT_MODEL_DEFAULT, READING_DIFF_CAP;
13568
+ var MEAT_TIMEOUT_S_DEFAULT, MEAT_MODEL_MISSING, READING_DIFF_CAP;
13559
13569
  var init_readingDiff = __esm({
13560
13570
  "../../src/core/readingDiff.ts"() {
13561
13571
  "use strict";
@@ -13563,7 +13573,7 @@ var init_readingDiff = __esm({
13563
13573
  init_runEvents();
13564
13574
  init_clock();
13565
13575
  MEAT_TIMEOUT_S_DEFAULT = 240;
13566
- MEAT_MODEL_DEFAULT = "claude-opus-5";
13576
+ MEAT_MODEL_MISSING = "review.readingDiff.meatModel is not set \u2014 name the model meat abridges with in config.yaml";
13567
13577
  READING_DIFF_CAP = 12e4;
13568
13578
  }
13569
13579
  });
@@ -25274,7 +25284,7 @@ var init_help = __esm({
25274
25284
  init_docsLink();
25275
25285
  defineCommand10 = commandDefiner();
25276
25286
  COMMANDS_REFERENCE_URL = `${PROJECT_DOCS_URL}/reference/slack-commands`;
25277
- 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 \u2014 narrows this run's wall clock, never widens it; a budget too short for a turn plus the write-up is refused by name)";
25287
+ DIRECTIVES_HELP = "`agent:review model:<provider>/<model> effort:low budget:20 look at PR 42` (effort: low | medium | high \u2014 lower = faster turns; budget: whole minutes \u2014 narrows this run's wall clock, never widens it; a budget too short for a turn plus the write-up is refused by name)";
25278
25288
  helpShow = defineCommand10({
25279
25289
  id: "help.show",
25280
25290
  action: "help:read",
@@ -30131,7 +30141,11 @@ function reviewAbridgerFromConfig(config, store, secrets, env, dataDir, warn) {
30131
30141
  cacheDir: resolve9(dataDir, "meat-cache"),
30132
30142
  hostEnv: { PATH: env.PATH, HOME: env.HOME }
30133
30143
  }),
30134
- defaultModel: () => resolved().meatModel ?? MEAT_MODEL_DEFAULT,
30144
+ defaultModel: () => {
30145
+ const model = resolved().meatModel;
30146
+ if (!model) throw new Error(MEAT_MODEL_MISSING);
30147
+ return model;
30148
+ },
30135
30149
  timeoutMs: () => resolved().meatTimeoutS * 1e3,
30136
30150
  clock: systemClock,
30137
30151
  warn
@@ -31600,7 +31614,7 @@ var init_review = __esm({
31600
31614
  enabledWhen: (caps) => caps.runHistory && caps.readingDiffAbridge,
31601
31615
  args: [{ name: "id", schema: runId, describe: "run id of a finished PR review" }],
31602
31616
  options: z21.object({
31603
- model: z21.string().min(1).optional().describe("meat's model (default review.readingDiff.meatModel, else claude-opus-5)"),
31617
+ model: z21.string().min(1).optional().describe("meat's model (default review.readingDiff.meatModel; without either the abridge fails naming the key)"),
31604
31618
  force: flag.optional().describe("recompute even when an abridged diff is already stored, or retry a failed one"),
31605
31619
  wait: flag.optional().describe("block until the abridging finishes and answer the outcome instead of `running`")
31606
31620
  }),
@@ -38464,7 +38478,7 @@ var init_runs2 = __esm({
38464
38478
  }
38465
38479
  if (input.model !== void 0) {
38466
38480
  const model = String(input.model).trim();
38467
- if (!/^\S+\/\S+$/.test(model)) return "error: model takes a `<provider>/<model>` ref, e.g. `anthropic/claude-x`";
38481
+ if (!/^\S+\/\S+$/.test(model)) return "error: model takes a `<provider>/<model>` ref";
38468
38482
  request2.model = model;
38469
38483
  }
38470
38484
  if (input.effort !== void 0) {
@@ -66862,9 +66876,9 @@ function installationSettings(config, caps) {
66862
66876
  row(
66863
66877
  "review.readingDiff.meatModel",
66864
66878
  readingDiff?.meatModel,
66865
- MEAT_MODEL_DEFAULT,
66879
+ void 0,
66866
66880
  "config",
66867
- "the model meat abridges with"
66881
+ "the model meat abridges with \u2014 required with provider: meat, no built-in model"
66868
66882
  ),
66869
66883
  row(
66870
66884
  "review.readingDiff.meatTimeoutS",
@@ -70842,6 +70856,8 @@ async function runBot() {
70842
70856
  () => config.config.review?.readingDiff,
70843
70857
  publicEnv()
70844
70858
  );
70859
+ const readingDiffWarning = readingDiffStartupWarning(config.config.review?.readingDiff, publicEnv());
70860
+ if (readingDiffWarning) console.warn(readingDiffWarning);
70845
70861
  const runHistoryWriter = capabilities.runHistory ? createRunHistoryWriter({
70846
70862
  store: runStore,
70847
70863
  warn: (m) => console.warn(m),
@@ -71881,6 +71897,7 @@ var init_index = __esm({
71881
71897
  init_runsService();
71882
71898
  init_planeService();
71883
71899
  init_runHistoryWriter();
71900
+ init_readingDiff();
71884
71901
  init_reviewAbridge();
71885
71902
  init_meatProcess();
71886
71903
  init_runLedgerWorker();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@coreplane/switchboard",
3
- "version": "1.258.0",
3
+ "version": "1.259.0",
4
4
  "description": "Mention it in Slack and an agent reviews the PR, ships the fix, or answers the question — on the model you choose, with its tools running where you decide.",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://openswitchboard.dev",