privateboard 0.1.22 → 0.1.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -700,6 +700,22 @@ CREATE INDEX IF NOT EXISTS idx_qd_archive_room_cell
700
700
  }
701
701
  });
702
702
 
703
+ // src/storage/migrations/039_remap_removed_models.sql
704
+ var remap_removed_models_default;
705
+ var init_remap_removed_models = __esm({
706
+ "src/storage/migrations/039_remap_removed_models.sql"() {
707
+ remap_removed_models_default = "-- 039_remap_removed_models.sql\n--\n-- Remap stored modelV strings for the six modelVs deleted from the\n-- registry on 2026-05-17 (B.AI catalog reconcile + xAI removal):\n--\n-- opus-4-6 \u2192 opus-4-7 (Anthropic flagship peer)\n-- gpt-5-5-pro \u2192 gpt-5-5 (drop the -pro suffix; same family)\n-- kimi-2-6 \u2192 kimi-k2-6 (current Kimi model \xB7 OR slug `moonshotai/kimi-k2.6`)\n-- grok-4-3 \u2192 sonnet-4-6 (no Grok in registry; safe default)\n-- grok-4-1-fast \u2192 haiku-4-5 (fast-tier peer)\n-- grok-4-20 \u2192 opus-4-7 (long-context peer; was 2M ctx)\n--\n-- Two live tables hold modelV: agents.model_v (every agent record) and\n-- prefs.default_model_v (the user's default-model choice). Historical\n-- snapshot tables (room_summaries.model_v, retired_token_usage.model_v,\n-- usage_daily.model_v) are NOT touched \u2014 they record what actually ran\n-- at the time and rewriting them would lie about history.\n--\n-- Idempotent \xB7 `WHERE model_v = '<old>'` is a no-op on second run.\n\nUPDATE agents SET model_v = 'opus-4-7' WHERE model_v = 'opus-4-6';\nUPDATE agents SET model_v = 'gpt-5-5' WHERE model_v = 'gpt-5-5-pro';\nUPDATE agents SET model_v = 'kimi-k2-6' WHERE model_v = 'kimi-2-6';\nUPDATE agents SET model_v = 'sonnet-4-6' WHERE model_v = 'grok-4-3';\nUPDATE agents SET model_v = 'haiku-4-5' WHERE model_v = 'grok-4-1-fast';\nUPDATE agents SET model_v = 'opus-4-7' WHERE model_v = 'grok-4-20';\n\nUPDATE prefs SET default_model_v = 'opus-4-7' WHERE default_model_v = 'opus-4-6';\nUPDATE prefs SET default_model_v = 'gpt-5-5' WHERE default_model_v = 'gpt-5-5-pro';\nUPDATE prefs SET default_model_v = 'kimi-k2-6' WHERE default_model_v = 'kimi-2-6';\nUPDATE prefs SET default_model_v = 'sonnet-4-6' WHERE default_model_v = 'grok-4-3';\nUPDATE prefs SET default_model_v = 'haiku-4-5' WHERE default_model_v = 'grok-4-1-fast';\nUPDATE prefs SET default_model_v = 'opus-4-7' WHERE default_model_v = 'grok-4-20';\n";
708
+ }
709
+ });
710
+
711
+ // src/storage/migrations/040_remap_kimi_k2_5_to_k2_6.sql
712
+ var remap_kimi_k2_5_to_k2_6_default;
713
+ var init_remap_kimi_k2_5_to_k2_6 = __esm({
714
+ "src/storage/migrations/040_remap_kimi_k2_5_to_k2_6.sql"() {
715
+ remap_kimi_k2_5_to_k2_6_default = "-- 040_remap_kimi_k2_5_to_k2_6.sql\n--\n-- Bump stored `kimi-k2-5` rows to `kimi-k2-6` after the Kimi registry\n-- entry was renamed (OpenRouter exposes the slug as\n-- `moonshotai/kimi-k2.6`; the prior `moonshotai/kimi-k2.5` slug 404s).\n--\n-- This complements 039_remap_removed_models.sql: 039 was edited to\n-- land users directly on `kimi-k2-6` for first-time runs, but any DB\n-- that already ran the previous 039 (which mapped to `kimi-k2-5`) is\n-- left holding the now-unknown `kimi-k2-5` string. This migration\n-- fixes those. Idempotent \xB7 WHERE clause is a no-op on second run.\n--\n-- Live tables only (`agents.model_v`, `prefs.default_model_v`).\n-- Historical snapshot tables are not touched \u2014 they record what\n-- actually ran at the time.\n\nUPDATE agents SET model_v = 'kimi-k2-6' WHERE model_v = 'kimi-k2-5';\nUPDATE prefs SET default_model_v = 'kimi-k2-6' WHERE default_model_v = 'kimi-k2-5';\n";
716
+ }
717
+ });
718
+
703
719
  // src/storage/db.ts
704
720
  var db_exports = {};
705
721
  __export(db_exports, {
@@ -795,6 +811,8 @@ var init_db = __esm({
795
811
  init_negative_space();
796
812
  init_topic_branches();
797
813
  init_qd_archive();
814
+ init_remap_removed_models();
815
+ init_remap_kimi_k2_5_to_k2_6();
798
816
  MIGRATIONS = [
799
817
  { name: "001_init.sql", sql: init_default },
800
818
  { name: "002_default_opus.sql", sql: default_opus_default },
@@ -833,7 +851,9 @@ var init_db = __esm({
833
851
  { name: "035_topic_rec_tag.sql", sql: topic_rec_tag_default },
834
852
  { name: "036_negative_space.sql", sql: negative_space_default },
835
853
  { name: "037_topic_branches.sql", sql: topic_branches_default },
836
- { name: "038_qd_archive.sql", sql: qd_archive_default }
854
+ { name: "038_qd_archive.sql", sql: qd_archive_default },
855
+ { name: "039_remap_removed_models.sql", sql: remap_removed_models_default },
856
+ { name: "040_remap_kimi_k2_5_to_k2_6.sql", sql: remap_kimi_k2_5_to_k2_6_default }
837
857
  ];
838
858
  _db = null;
839
859
  }
@@ -2274,16 +2294,6 @@ var MODELS = {
2274
2294
  contextBudget: 2e5,
2275
2295
  deck: "balanced \xB7 default"
2276
2296
  },
2277
- "opus-4-6": {
2278
- v: "opus-4-6",
2279
- provider: "anthropic",
2280
- directApiId: "claude-opus-4-6",
2281
- openrouterId: "anthropic/claude-opus-4.6",
2282
- baiId: "claude-opus-4.6",
2283
- displayName: "Opus 4.6",
2284
- contextBudget: 1e6,
2285
- deck: "deep reasoning \xB7 1M ctx"
2286
- },
2287
2297
  "opus-4-7": {
2288
2298
  v: "opus-4-7",
2289
2299
  provider: "anthropic",
@@ -2348,26 +2358,12 @@ var MODELS = {
2348
2358
  provider: "openai",
2349
2359
  directApiId: "gpt-5.4-mini",
2350
2360
  openrouterId: "openai/gpt-5.4-mini",
2351
- // No baiId · B.AI's catalog reports "No available channel for
2352
- // model gpt-5-4-mini" on the OneAPI distributor — the mini
2353
- // variant isn't routed there. The full `gpt-5-4` IS available on
2354
- // B.AI; pick that or use direct / OR for the mini tier.
2361
+ baiId: "gpt-5.4-mini",
2355
2362
  displayName: "GPT-5.4 Mini",
2356
2363
  contextBudget: 4e5,
2357
2364
  deck: "fast \xB7 400k ctx"
2358
2365
  },
2359
- // ── OpenAI · OR-only previews (Pro / Codex) ──
2360
- "gpt-5-5-pro": {
2361
- v: "gpt-5-5-pro",
2362
- provider: "openai",
2363
- directApiId: "gpt-5.5-pro",
2364
- openrouterId: "openai/gpt-5.5-pro",
2365
- baiId: "gpt-5.5-pro",
2366
- displayName: "GPT-5.5 Pro",
2367
- contextBudget: 1e6,
2368
- deck: "deep reasoning \xB7 1M ctx",
2369
- viaUniversalOnly: true
2370
- },
2366
+ // ── OpenAI · OR-only previews (Codex) ──
2371
2367
  "codex-5-4": {
2372
2368
  v: "codex-5-4",
2373
2369
  provider: "openai",
@@ -2419,42 +2415,13 @@ var MODELS = {
2419
2415
  contextBudget: 1e6,
2420
2416
  deck: "fast \xB7 1M ctx"
2421
2417
  },
2422
- // ── xAI · current frontier (4.3 / 4.1 Fast direct + 4.20 big-ctx OR) ──
2423
- // Replaced the legacy grok-4 / grok-4-mini entries 4.3 is xAI's
2424
- // current "most intelligent and fastest" model per their docs; 4.1
2425
- // Fast is the new cheap tier. 4.20 stays OR-only since it's a 2M-ctx
2426
- // preview that the direct SDK hasn't acknowledged yet.
2427
- "grok-4-3": {
2428
- v: "grok-4-3",
2429
- provider: "xai",
2430
- directApiId: "grok-4.3",
2431
- openrouterId: "x-ai/grok-4.3",
2432
- baiId: "grok-4.3",
2433
- displayName: "Grok 4.3",
2434
- contextBudget: 1e6,
2435
- deck: "flagship \xB7 1M ctx"
2436
- },
2437
- "grok-4-1-fast": {
2438
- v: "grok-4-1-fast",
2439
- provider: "xai",
2440
- directApiId: "grok-4.1-fast",
2441
- openrouterId: "x-ai/grok-4.1-fast",
2442
- baiId: "grok-4.1-fast",
2443
- displayName: "Grok 4.1 Fast",
2444
- contextBudget: 256e3,
2445
- deck: "fast \xB7 256k ctx"
2446
- },
2447
- "grok-4-20": {
2448
- v: "grok-4-20",
2449
- provider: "xai",
2450
- directApiId: "grok-4.20",
2451
- openrouterId: "x-ai/grok-4.20",
2452
- baiId: "grok-4.20",
2453
- displayName: "Grok 4.20",
2454
- contextBudget: 2e6,
2455
- deck: "2M ctx \xB7 big context",
2456
- viaUniversalOnly: true
2457
- },
2418
+ // ── xAI · all Grok entries removed (2026-05-17) ──
2419
+ // B.AI's catalog lists no Grok models, the user base on B.AI saw
2420
+ // every grok-* call 503 with "no available channel". Direct xAI key
2421
+ // route and OpenRouter route still exist in the adapter (the `xai`
2422
+ // Provider type is retained), but no modelV currently maps to them.
2423
+ // Re-add a `grok-*` entry here if/when B.AI begins routing xAI again
2424
+ // or if the product re-introduces direct xAI as a first-class path.
2458
2425
  // ── DeepSeek (OR-only · no @ai-sdk/deepseek shipped) ──
2459
2426
  "deepseek-v4-pro": {
2460
2427
  v: "deepseek-v4-pro",
@@ -2494,20 +2461,49 @@ var MODELS = {
2494
2461
  deck: "Zhipu flagship \xB7 200k ctx",
2495
2462
  viaUniversalOnly: true
2496
2463
  },
2497
- // ── Moonshot · Kimi family · OR + B.AI only ──
2498
- // OpenRouter catalog convention: `moonshotai/kimi-…`. B.AI uses
2499
- // hyphenated lowercase: `kimi-2-6`. No direct @ai-sdk client ·
2464
+ // ── Moonshot · Kimi family · OR + B.AI ──
2465
+ // OpenRouter catalog convention: `moonshotai/kimi-k2.6` (the leading
2466
+ // `k` is part of the slug — `moonshotai/kimi-2.6` 404s). B.AI's
2467
+ // siliconflow distributor still ships the older `kimi-k2.5` channel
2468
+ // (per 2026-05-17 catalog snapshot), so the B.AI route serves K2.5
2469
+ // until B.AI picks up the newer build. No direct @ai-sdk client ·
2500
2470
  // viaUniversalOnly skips the direct path.
2501
- "kimi-2-6": {
2502
- v: "kimi-2-6",
2471
+ "kimi-k2-6": {
2472
+ v: "kimi-k2-6",
2503
2473
  provider: "moonshot",
2504
- directApiId: "kimi-2.6",
2505
- openrouterId: "moonshotai/kimi-2.6",
2506
- baiId: "kimi-2.6",
2507
- displayName: "Kimi 2.6",
2474
+ directApiId: "kimi-k2.6",
2475
+ openrouterId: "moonshotai/kimi-k2.6",
2476
+ baiId: "kimi-k2.5",
2477
+ displayName: "Kimi K2.6",
2508
2478
  contextBudget: 256e3,
2509
2479
  deck: "Moonshot \xB7 long-context",
2510
2480
  viaUniversalOnly: true
2481
+ },
2482
+ // ── MiniMax · M-series · OR + B.AI ──
2483
+ // No direct @ai-sdk client · viaUniversalOnly skips the direct path.
2484
+ // OpenRouter catalog slug: `minimax/minimax-mX.Y`. B.AI uses bare
2485
+ // model id: `minimax-mX.Y` (siliconflow / paratera distributors).
2486
+ "minimax-m2-7": {
2487
+ v: "minimax-m2-7",
2488
+ provider: "minimax",
2489
+ directApiId: "minimax-m2.7",
2490
+ openrouterId: "minimax/minimax-m2.7",
2491
+ baiId: "minimax-m2.7",
2492
+ displayName: "MiniMax M2.7",
2493
+ contextBudget: 245e3,
2494
+ deck: "MiniMax flagship \xB7 long-context",
2495
+ viaUniversalOnly: true
2496
+ },
2497
+ "minimax-m2-5": {
2498
+ v: "minimax-m2-5",
2499
+ provider: "minimax",
2500
+ directApiId: "minimax-m2.5",
2501
+ openrouterId: "minimax/minimax-m2.5",
2502
+ baiId: "minimax-m2.5",
2503
+ displayName: "MiniMax M2.5",
2504
+ contextBudget: 245e3,
2505
+ deck: "MiniMax prior \xB7 long-context",
2506
+ viaUniversalOnly: true
2511
2507
  }
2512
2508
  };
2513
2509
  function getModel(v) {
@@ -2766,7 +2762,6 @@ function parseAbility2(raw) {
2766
2762
  }
2767
2763
  var ALLOWED_MODELS = /* @__PURE__ */ new Set([
2768
2764
  "sonnet-4-6",
2769
- "opus-4-6",
2770
2765
  "opus-4-7",
2771
2766
  "haiku-4-5",
2772
2767
  "gpt-5-5",
@@ -2775,10 +2770,12 @@ var ALLOWED_MODELS = /* @__PURE__ */ new Set([
2775
2770
  "gemini-3-1",
2776
2771
  "gemini-3-flash",
2777
2772
  "gemini-3-1-flash",
2778
- "grok-4-3",
2779
- "grok-4-1-fast",
2780
2773
  "deepseek-v4-pro",
2781
- "deepseek-v4-flash"
2774
+ "deepseek-v4-flash",
2775
+ "glm-5-1",
2776
+ "kimi-k2-6",
2777
+ "minimax-m2-7",
2778
+ "minimax-m2-5"
2782
2779
  ]);
2783
2780
  function clamp(s, max) {
2784
2781
  if (s.length <= max) return s;
@@ -4038,8 +4035,9 @@ var PRIMARY_BY_CARRIER = {
4038
4035
  bai: "haiku-4-5",
4039
4036
  anthropic: "haiku-4-5",
4040
4037
  openai: "gpt-5-4-mini",
4041
- google: "gemini-3-1-flash",
4042
- xai: "grok-4-1-fast"
4038
+ google: "gemini-3-1-flash"
4039
+ // xai · no primary (no LLM modelV in registry as of 2026-05-17). The
4040
+ // adapter / availability layer skip xai when this key is absent.
4043
4041
  };
4044
4042
  var CARRIER_PRIORITY = ["openrouter", "bai", "anthropic", "openai", "google", "xai"];
4045
4043
  function reachableModelVs() {
@@ -4181,14 +4179,22 @@ var PROVIDER_FLAGSHIP = {
4181
4179
  anthropic: "opus-4-7",
4182
4180
  openai: "gpt-5-5",
4183
4181
  google: "gemini-3-flash",
4184
- xai: "grok-4-3",
4182
+ // xai · no LLM modelV currently in the registry (all grok-* entries
4183
+ // removed 2026-05-17 when B.AI dropped xAI). Keep the key so the
4184
+ // Record type stays exhaustive; the resolver naturally skips it.
4185
+ xai: null,
4185
4186
  deepseek: "deepseek-v4-pro",
4186
4187
  zhipu: "glm-5-1",
4187
- moonshot: "kimi-2-6",
4188
+ moonshot: "kimi-k2-6",
4188
4189
  openrouter: "opus-4-7",
4189
4190
  bai: "opus-4-7",
4190
4191
  brave: null,
4191
4192
  tavily: null,
4193
+ // minimax has LLM models now (minimax-m2-7 / m2-5) but no direct
4194
+ // @ai-sdk path · only the B.AI route works. The Provider Record here
4195
+ // refers to *direct* providers, so `null` is correct: a user with
4196
+ // only a minimax voice key shouldn't try to use it as their LLM
4197
+ // flagship. B.AI carrier still picks up the MiniMax LLMs naturally.
4192
4198
  minimax: null,
4193
4199
  elevenlabs: null
4194
4200
  };
@@ -4196,13 +4202,14 @@ var PROVIDER_FAST = {
4196
4202
  anthropic: "haiku-4-5",
4197
4203
  openai: "gpt-5-4-mini",
4198
4204
  google: "gemini-3-1-flash",
4199
- xai: "grok-4-1-fast",
4205
+ // xai · no LLM modelV in the registry (see PROVIDER_FLAGSHIP note).
4206
+ xai: null,
4200
4207
  deepseek: "deepseek-v4-flash",
4201
4208
  // GLM / Kimi · no separate fast/flash tier in our registry yet, so
4202
4209
  // both providers' "fast pick" falls back to the same flagship that
4203
4210
  // PROVIDER_FLAGSHIP names. Reachability-via-OR/B.AI carries it.
4204
4211
  zhipu: "glm-5-1",
4205
- moonshot: "kimi-2-6",
4212
+ moonshot: "kimi-k2-6",
4206
4213
  openrouter: "opus-4-6-fast",
4207
4214
  bai: "haiku-4-5",
4208
4215
  brave: null,
@@ -4217,28 +4224,26 @@ var FAST_POOL_BY_CARRIER = {
4217
4224
  "gpt-5-4-mini",
4218
4225
  "gemini-3-flash",
4219
4226
  "gemini-3-1-flash",
4220
- "grok-4-1-fast",
4221
4227
  "deepseek-v4-flash"
4222
4228
  ],
4223
- // B.AI carries the same brand-spanning fast catalog as OpenRouter ·
4224
- // identical pool gives a B.AI-only user the same visibly-mixed
4225
- // director cast (different brand badges per seat) that the OpenRouter
4226
- // path produces. Members are filtered against reachability inside
4227
- // `pickRandomFastModel`, so models without a baiId fall out naturally
4228
- // if B.AI ends up not carrying one of them in practice.
4229
+ // B.AI carries the same brand-spanning fast catalog as OpenRouter
4230
+ // (minus Grok · B.AI dropped xAI 2026-05) · identical pool gives a
4231
+ // B.AI-only user the same visibly-mixed director cast (different
4232
+ // brand badges per seat) that the OpenRouter path produces. Members
4233
+ // are filtered against reachability inside `pickRandomFastModel`, so
4234
+ // models without a baiId fall out naturally if B.AI ends up not
4235
+ // carrying one of them in practice.
4229
4236
  bai: [
4230
- "opus-4-6-fast",
4231
4237
  "haiku-4-5",
4232
4238
  "gpt-5-4-mini",
4233
4239
  "gemini-3-flash",
4234
4240
  "gemini-3-1-flash",
4235
- "grok-4-1-fast",
4236
4241
  "deepseek-v4-flash"
4237
4242
  ],
4238
4243
  anthropic: ["opus-4-6-fast", "haiku-4-5"],
4239
4244
  openai: ["gpt-5-4-mini"],
4240
- google: ["gemini-3-flash", "gemini-3-1-flash"],
4241
- xai: ["grok-4-1-fast"]
4245
+ google: ["gemini-3-flash", "gemini-3-1-flash"]
4246
+ // xai · no fast pool (no LLM modelV in registry).
4242
4247
  };
4243
4248
  function pickRandomFastModel(carrier) {
4244
4249
  if (!carrier) return null;
@@ -4259,13 +4264,13 @@ var FLAGSHIP_TIER = /* @__PURE__ */ new Set([
4259
4264
  // Google
4260
4265
  "gemini-3-1",
4261
4266
  "gemini-3-flash",
4262
- // xAI
4263
- "grok-4-3",
4267
+ // xAI · no flagship in registry currently.
4264
4268
  // DeepSeek
4265
4269
  "deepseek-v4-pro",
4266
- // Zhipu · Moonshot · single flagship each (both OR + B.AI routed).
4270
+ // Zhipu · Moonshot · MiniMax · single flagship each (B.AI routed).
4267
4271
  "glm-5-1",
4268
- "kimi-2-6"
4272
+ "kimi-k2-6",
4273
+ "minimax-m2-7"
4269
4274
  ]);
4270
4275
  function effectiveDefaultModel() {
4271
4276
  const prefs = getPrefs();
@@ -4318,17 +4323,15 @@ var CHEAP_BY_CARRIER = {
4318
4323
  anthropic: "sonnet-4-6",
4319
4324
  // only direct-routable Claude
4320
4325
  openai: "gpt-5-4-mini",
4321
- google: "gemini-3-1-flash",
4326
+ google: "gemini-3-1-flash"
4322
4327
  // 3.1 Flash Lite · cheapest direct-routable Gemini
4323
- xai: "grok-4-1-fast"
4324
- // 4.1 Fast · cheapest direct-routable Grok
4328
+ // xai · no cheap tier (no LLM modelV in registry).
4325
4329
  };
4326
4330
  var UTILITY_PREFERENCE = [
4327
4331
  "haiku-4-5",
4328
4332
  "gpt-5-4-mini",
4329
4333
  "gemini-3-1-flash",
4330
- "gemini-3-flash",
4331
- "grok-4-1-fast"
4334
+ "gemini-3-flash"
4332
4335
  ];
4333
4336
  function utilityModelFor(fallback = null) {
4334
4337
  const reachable = new Set(reachableModels().map((m) => m.modelV));
@@ -16591,6 +16594,19 @@ function setKeyPointVote(id, vote) {
16591
16594
  function pickRouterModel() {
16592
16595
  return utilityModelFor();
16593
16596
  }
16597
+ function authorLabel(m, cast) {
16598
+ if (m.authorKind === "user") return "USER";
16599
+ if (m.authorKind === "system") return "system";
16600
+ if (!m.authorId) return m.authorKind === "agent" ? "director" : m.authorKind;
16601
+ const fromCast = cast?.find((a2) => a2.id === m.authorId);
16602
+ if (fromCast) return `${fromCast.name} (${fromCast.handle})`;
16603
+ const a = getAgent(m.authorId);
16604
+ if (a) {
16605
+ const kindTag = a.roleKind === "moderator" ? "chair" : "director";
16606
+ return `${a.name} (${a.handle}, ${kindTag})`;
16607
+ }
16608
+ return m.authorKind === "agent" ? "director" : m.authorKind;
16609
+ }
16594
16610
  var MAX_PICKS = 2;
16595
16611
  async function pickChairClarifyDecision(opts) {
16596
16612
  const prompt = latestUserPrompt(opts.history);
@@ -16668,10 +16684,7 @@ async function pickRoundWrap(opts) {
16668
16684
  if (meta?.kind === "tool-use" || meta?.kind === "tool-preamble") return false;
16669
16685
  if (meta?.kind === "round-open" || meta?.kind === "round-prompt") return false;
16670
16686
  return true;
16671
- }).map((m) => {
16672
- const who = m.authorKind === "user" ? "USER" : m.authorId || "agent";
16673
- return `[${who}] ${m.body.trim().slice(0, 600)}`;
16674
- }).join("\n\n");
16687
+ }).map((m) => `[${authorLabel(m)}] ${m.body.trim().slice(0, 600)}`).join("\n\n");
16675
16688
  const sys = {
16676
16689
  role: "system",
16677
16690
  content: [
@@ -16775,10 +16788,7 @@ ${extras.join("\n")}` : baseRow;
16775
16788
  if (meta?.kind === "tool-use" || meta?.kind === "tool-preamble") return false;
16776
16789
  if (meta?.kind === "round-open" || meta?.kind === "round-prompt") return false;
16777
16790
  return true;
16778
- }).map((m) => {
16779
- const who = m.authorKind === "user" ? "USER" : m.authorId || "agent";
16780
- return `[${who}] ${m.body.trim().slice(0, 600)}`;
16781
- }).join("\n\n");
16791
+ }).map((m) => `[${authorLabel(m, candidates)}] ${m.body.trim().slice(0, 600)}`).join("\n\n");
16782
16792
  const decision1Block = mode === "dissent-gap" ? [
16783
16793
  "DECISION 1 \xB7 Next speaker (DISSENT-GAP MODE).",
16784
16794
  "The room is converging on a single frame \u2014 for THIS pick, the chair",
@@ -16840,6 +16850,13 @@ ${extras.join("\n")}` : baseRow;
16840
16850
  "the SPECIFIC pattern + the load-bearing piece worth pinning down.",
16841
16851
  "No greeting, no signature.",
16842
16852
  "",
16853
+ "NAMING \xB7 When `intervention` or `rationale` references a director,",
16854
+ "use their DISPLAY NAME (the part before the parenthesis in the",
16855
+ 'roster \u2014 e.g. "Maya", not "fk7wvt1bep62"). The opaque id is for',
16856
+ "the `agent_id` JSON field ONLY; it must NEVER appear inside any",
16857
+ "user-facing prose text. The transcript above labels speakers by",
16858
+ "name already; mirror that format.",
16859
+ "",
16843
16860
  "LANGUAGE \xB7 the chair note must follow the room's DOMINANT",
16844
16861
  "language detected from the recent transcript (most recent",
16845
16862
  "messages weight highest). If most directors and the user are",
@@ -16913,16 +16930,26 @@ ${extras.join("\n")}` : baseRow;
16913
16930
  const obj = parsed;
16914
16931
  const validIds = new Set(candidates.map((c) => c.id));
16915
16932
  const id = typeof obj.agent_id === "string" && validIds.has(obj.agent_id) ? obj.agent_id : null;
16916
- const rationale = typeof obj.rationale === "string" ? obj.rationale.trim().slice(0, 200) : "";
16933
+ const rationale = typeof obj.rationale === "string" ? replaceLeakedIds(obj.rationale.trim(), candidates).slice(0, 200) : "";
16917
16934
  let intervention = null;
16918
16935
  if (typeof obj.intervention === "string") {
16919
- const t = obj.intervention.trim();
16936
+ const t = replaceLeakedIds(obj.intervention.trim(), candidates);
16920
16937
  if (t.length > 0 && t.toLowerCase() !== "null" && t.toLowerCase() !== "none") {
16921
16938
  intervention = t.slice(0, 280);
16922
16939
  }
16923
16940
  }
16924
16941
  return { agentId: id, rationale, intervention };
16925
16942
  }
16943
+ function replaceLeakedIds(text, candidates) {
16944
+ if (!text) return text;
16945
+ return text.replace(/(?<![A-Za-z0-9])[0-9a-hjkmnpqrstvwxyz]{12}(?![A-Za-z0-9])/g, (id) => {
16946
+ const fromCast = candidates.find((c) => c.id === id);
16947
+ if (fromCast) return fromCast.name;
16948
+ const a = getAgent(id);
16949
+ if (a) return a.name;
16950
+ return id;
16951
+ });
16952
+ }
16926
16953
  async function pickChairWebSearch(opts) {
16927
16954
  const prompt = latestUserPrompt(opts.history);
16928
16955
  if (!prompt) return null;
@@ -23548,7 +23575,7 @@ function voicesRouter() {
23548
23575
  init_paths();
23549
23576
 
23550
23577
  // src/version.ts
23551
- var VERSION = "0.1.22";
23578
+ var VERSION = "0.1.23";
23552
23579
 
23553
23580
  // src/server.ts
23554
23581
  function createApp() {