privateboard 0.1.22 → 0.1.24

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/boot.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
  }
@@ -2270,16 +2290,6 @@ var MODELS = {
2270
2290
  contextBudget: 2e5,
2271
2291
  deck: "balanced \xB7 default"
2272
2292
  },
2273
- "opus-4-6": {
2274
- v: "opus-4-6",
2275
- provider: "anthropic",
2276
- directApiId: "claude-opus-4-6",
2277
- openrouterId: "anthropic/claude-opus-4.6",
2278
- baiId: "claude-opus-4.6",
2279
- displayName: "Opus 4.6",
2280
- contextBudget: 1e6,
2281
- deck: "deep reasoning \xB7 1M ctx"
2282
- },
2283
2293
  "opus-4-7": {
2284
2294
  v: "opus-4-7",
2285
2295
  provider: "anthropic",
@@ -2344,26 +2354,12 @@ var MODELS = {
2344
2354
  provider: "openai",
2345
2355
  directApiId: "gpt-5.4-mini",
2346
2356
  openrouterId: "openai/gpt-5.4-mini",
2347
- // No baiId · B.AI's catalog reports "No available channel for
2348
- // model gpt-5-4-mini" on the OneAPI distributor — the mini
2349
- // variant isn't routed there. The full `gpt-5-4` IS available on
2350
- // B.AI; pick that or use direct / OR for the mini tier.
2357
+ baiId: "gpt-5.4-mini",
2351
2358
  displayName: "GPT-5.4 Mini",
2352
2359
  contextBudget: 4e5,
2353
2360
  deck: "fast \xB7 400k ctx"
2354
2361
  },
2355
- // ── OpenAI · OR-only previews (Pro / Codex) ──
2356
- "gpt-5-5-pro": {
2357
- v: "gpt-5-5-pro",
2358
- provider: "openai",
2359
- directApiId: "gpt-5.5-pro",
2360
- openrouterId: "openai/gpt-5.5-pro",
2361
- baiId: "gpt-5.5-pro",
2362
- displayName: "GPT-5.5 Pro",
2363
- contextBudget: 1e6,
2364
- deck: "deep reasoning \xB7 1M ctx",
2365
- viaUniversalOnly: true
2366
- },
2362
+ // ── OpenAI · OR-only previews (Codex) ──
2367
2363
  "codex-5-4": {
2368
2364
  v: "codex-5-4",
2369
2365
  provider: "openai",
@@ -2415,42 +2411,13 @@ var MODELS = {
2415
2411
  contextBudget: 1e6,
2416
2412
  deck: "fast \xB7 1M ctx"
2417
2413
  },
2418
- // ── xAI · current frontier (4.3 / 4.1 Fast direct + 4.20 big-ctx OR) ──
2419
- // Replaced the legacy grok-4 / grok-4-mini entries 4.3 is xAI's
2420
- // current "most intelligent and fastest" model per their docs; 4.1
2421
- // Fast is the new cheap tier. 4.20 stays OR-only since it's a 2M-ctx
2422
- // preview that the direct SDK hasn't acknowledged yet.
2423
- "grok-4-3": {
2424
- v: "grok-4-3",
2425
- provider: "xai",
2426
- directApiId: "grok-4.3",
2427
- openrouterId: "x-ai/grok-4.3",
2428
- baiId: "grok-4.3",
2429
- displayName: "Grok 4.3",
2430
- contextBudget: 1e6,
2431
- deck: "flagship \xB7 1M ctx"
2432
- },
2433
- "grok-4-1-fast": {
2434
- v: "grok-4-1-fast",
2435
- provider: "xai",
2436
- directApiId: "grok-4.1-fast",
2437
- openrouterId: "x-ai/grok-4.1-fast",
2438
- baiId: "grok-4.1-fast",
2439
- displayName: "Grok 4.1 Fast",
2440
- contextBudget: 256e3,
2441
- deck: "fast \xB7 256k ctx"
2442
- },
2443
- "grok-4-20": {
2444
- v: "grok-4-20",
2445
- provider: "xai",
2446
- directApiId: "grok-4.20",
2447
- openrouterId: "x-ai/grok-4.20",
2448
- baiId: "grok-4.20",
2449
- displayName: "Grok 4.20",
2450
- contextBudget: 2e6,
2451
- deck: "2M ctx \xB7 big context",
2452
- viaUniversalOnly: true
2453
- },
2414
+ // ── xAI · all Grok entries removed (2026-05-17) ──
2415
+ // B.AI's catalog lists no Grok models, the user base on B.AI saw
2416
+ // every grok-* call 503 with "no available channel". Direct xAI key
2417
+ // route and OpenRouter route still exist in the adapter (the `xai`
2418
+ // Provider type is retained), but no modelV currently maps to them.
2419
+ // Re-add a `grok-*` entry here if/when B.AI begins routing xAI again
2420
+ // or if the product re-introduces direct xAI as a first-class path.
2454
2421
  // ── DeepSeek (OR-only · no @ai-sdk/deepseek shipped) ──
2455
2422
  "deepseek-v4-pro": {
2456
2423
  v: "deepseek-v4-pro",
@@ -2490,20 +2457,49 @@ var MODELS = {
2490
2457
  deck: "Zhipu flagship \xB7 200k ctx",
2491
2458
  viaUniversalOnly: true
2492
2459
  },
2493
- // ── Moonshot · Kimi family · OR + B.AI only ──
2494
- // OpenRouter catalog convention: `moonshotai/kimi-…`. B.AI uses
2495
- // hyphenated lowercase: `kimi-2-6`. No direct @ai-sdk client ·
2460
+ // ── Moonshot · Kimi family · OR + B.AI ──
2461
+ // OpenRouter catalog convention: `moonshotai/kimi-k2.6` (the leading
2462
+ // `k` is part of the slug — `moonshotai/kimi-2.6` 404s). B.AI's
2463
+ // siliconflow distributor still ships the older `kimi-k2.5` channel
2464
+ // (per 2026-05-17 catalog snapshot), so the B.AI route serves K2.5
2465
+ // until B.AI picks up the newer build. No direct @ai-sdk client ·
2496
2466
  // viaUniversalOnly skips the direct path.
2497
- "kimi-2-6": {
2498
- v: "kimi-2-6",
2467
+ "kimi-k2-6": {
2468
+ v: "kimi-k2-6",
2499
2469
  provider: "moonshot",
2500
- directApiId: "kimi-2.6",
2501
- openrouterId: "moonshotai/kimi-2.6",
2502
- baiId: "kimi-2.6",
2503
- displayName: "Kimi 2.6",
2470
+ directApiId: "kimi-k2.6",
2471
+ openrouterId: "moonshotai/kimi-k2.6",
2472
+ baiId: "kimi-k2.5",
2473
+ displayName: "Kimi K2.6",
2504
2474
  contextBudget: 256e3,
2505
2475
  deck: "Moonshot \xB7 long-context",
2506
2476
  viaUniversalOnly: true
2477
+ },
2478
+ // ── MiniMax · M-series · OR + B.AI ──
2479
+ // No direct @ai-sdk client · viaUniversalOnly skips the direct path.
2480
+ // OpenRouter catalog slug: `minimax/minimax-mX.Y`. B.AI uses bare
2481
+ // model id: `minimax-mX.Y` (siliconflow / paratera distributors).
2482
+ "minimax-m2-7": {
2483
+ v: "minimax-m2-7",
2484
+ provider: "minimax",
2485
+ directApiId: "minimax-m2.7",
2486
+ openrouterId: "minimax/minimax-m2.7",
2487
+ baiId: "minimax-m2.7",
2488
+ displayName: "MiniMax M2.7",
2489
+ contextBudget: 245e3,
2490
+ deck: "MiniMax flagship \xB7 long-context",
2491
+ viaUniversalOnly: true
2492
+ },
2493
+ "minimax-m2-5": {
2494
+ v: "minimax-m2-5",
2495
+ provider: "minimax",
2496
+ directApiId: "minimax-m2.5",
2497
+ openrouterId: "minimax/minimax-m2.5",
2498
+ baiId: "minimax-m2.5",
2499
+ displayName: "MiniMax M2.5",
2500
+ contextBudget: 245e3,
2501
+ deck: "MiniMax prior \xB7 long-context",
2502
+ viaUniversalOnly: true
2507
2503
  }
2508
2504
  };
2509
2505
  function getModel(v) {
@@ -2762,7 +2758,6 @@ function parseAbility2(raw) {
2762
2758
  }
2763
2759
  var ALLOWED_MODELS = /* @__PURE__ */ new Set([
2764
2760
  "sonnet-4-6",
2765
- "opus-4-6",
2766
2761
  "opus-4-7",
2767
2762
  "haiku-4-5",
2768
2763
  "gpt-5-5",
@@ -2771,10 +2766,12 @@ var ALLOWED_MODELS = /* @__PURE__ */ new Set([
2771
2766
  "gemini-3-1",
2772
2767
  "gemini-3-flash",
2773
2768
  "gemini-3-1-flash",
2774
- "grok-4-3",
2775
- "grok-4-1-fast",
2776
2769
  "deepseek-v4-pro",
2777
- "deepseek-v4-flash"
2770
+ "deepseek-v4-flash",
2771
+ "glm-5-1",
2772
+ "kimi-k2-6",
2773
+ "minimax-m2-7",
2774
+ "minimax-m2-5"
2778
2775
  ]);
2779
2776
  function clamp(s, max) {
2780
2777
  if (s.length <= max) return s;
@@ -4034,8 +4031,9 @@ var PRIMARY_BY_CARRIER = {
4034
4031
  bai: "haiku-4-5",
4035
4032
  anthropic: "haiku-4-5",
4036
4033
  openai: "gpt-5-4-mini",
4037
- google: "gemini-3-1-flash",
4038
- xai: "grok-4-1-fast"
4034
+ google: "gemini-3-1-flash"
4035
+ // xai · no primary (no LLM modelV in registry as of 2026-05-17). The
4036
+ // adapter / availability layer skip xai when this key is absent.
4039
4037
  };
4040
4038
  var CARRIER_PRIORITY = ["openrouter", "bai", "anthropic", "openai", "google", "xai"];
4041
4039
  function reachableModelVs() {
@@ -4177,14 +4175,22 @@ var PROVIDER_FLAGSHIP = {
4177
4175
  anthropic: "opus-4-7",
4178
4176
  openai: "gpt-5-5",
4179
4177
  google: "gemini-3-flash",
4180
- xai: "grok-4-3",
4178
+ // xai · no LLM modelV currently in the registry (all grok-* entries
4179
+ // removed 2026-05-17 when B.AI dropped xAI). Keep the key so the
4180
+ // Record type stays exhaustive; the resolver naturally skips it.
4181
+ xai: null,
4181
4182
  deepseek: "deepseek-v4-pro",
4182
4183
  zhipu: "glm-5-1",
4183
- moonshot: "kimi-2-6",
4184
+ moonshot: "kimi-k2-6",
4184
4185
  openrouter: "opus-4-7",
4185
4186
  bai: "opus-4-7",
4186
4187
  brave: null,
4187
4188
  tavily: null,
4189
+ // minimax has LLM models now (minimax-m2-7 / m2-5) but no direct
4190
+ // @ai-sdk path · only the B.AI route works. The Provider Record here
4191
+ // refers to *direct* providers, so `null` is correct: a user with
4192
+ // only a minimax voice key shouldn't try to use it as their LLM
4193
+ // flagship. B.AI carrier still picks up the MiniMax LLMs naturally.
4188
4194
  minimax: null,
4189
4195
  elevenlabs: null
4190
4196
  };
@@ -4192,13 +4198,14 @@ var PROVIDER_FAST = {
4192
4198
  anthropic: "haiku-4-5",
4193
4199
  openai: "gpt-5-4-mini",
4194
4200
  google: "gemini-3-1-flash",
4195
- xai: "grok-4-1-fast",
4201
+ // xai · no LLM modelV in the registry (see PROVIDER_FLAGSHIP note).
4202
+ xai: null,
4196
4203
  deepseek: "deepseek-v4-flash",
4197
4204
  // GLM / Kimi · no separate fast/flash tier in our registry yet, so
4198
4205
  // both providers' "fast pick" falls back to the same flagship that
4199
4206
  // PROVIDER_FLAGSHIP names. Reachability-via-OR/B.AI carries it.
4200
4207
  zhipu: "glm-5-1",
4201
- moonshot: "kimi-2-6",
4208
+ moonshot: "kimi-k2-6",
4202
4209
  openrouter: "opus-4-6-fast",
4203
4210
  bai: "haiku-4-5",
4204
4211
  brave: null,
@@ -4213,28 +4220,26 @@ var FAST_POOL_BY_CARRIER = {
4213
4220
  "gpt-5-4-mini",
4214
4221
  "gemini-3-flash",
4215
4222
  "gemini-3-1-flash",
4216
- "grok-4-1-fast",
4217
4223
  "deepseek-v4-flash"
4218
4224
  ],
4219
- // B.AI carries the same brand-spanning fast catalog as OpenRouter ·
4220
- // identical pool gives a B.AI-only user the same visibly-mixed
4221
- // director cast (different brand badges per seat) that the OpenRouter
4222
- // path produces. Members are filtered against reachability inside
4223
- // `pickRandomFastModel`, so models without a baiId fall out naturally
4224
- // if B.AI ends up not carrying one of them in practice.
4225
+ // B.AI carries the same brand-spanning fast catalog as OpenRouter
4226
+ // (minus Grok · B.AI dropped xAI 2026-05) · identical pool gives a
4227
+ // B.AI-only user the same visibly-mixed director cast (different
4228
+ // brand badges per seat) that the OpenRouter path produces. Members
4229
+ // are filtered against reachability inside `pickRandomFastModel`, so
4230
+ // models without a baiId fall out naturally if B.AI ends up not
4231
+ // carrying one of them in practice.
4225
4232
  bai: [
4226
- "opus-4-6-fast",
4227
4233
  "haiku-4-5",
4228
4234
  "gpt-5-4-mini",
4229
4235
  "gemini-3-flash",
4230
4236
  "gemini-3-1-flash",
4231
- "grok-4-1-fast",
4232
4237
  "deepseek-v4-flash"
4233
4238
  ],
4234
4239
  anthropic: ["opus-4-6-fast", "haiku-4-5"],
4235
4240
  openai: ["gpt-5-4-mini"],
4236
- google: ["gemini-3-flash", "gemini-3-1-flash"],
4237
- xai: ["grok-4-1-fast"]
4241
+ google: ["gemini-3-flash", "gemini-3-1-flash"]
4242
+ // xai · no fast pool (no LLM modelV in registry).
4238
4243
  };
4239
4244
  function pickRandomFastModel(carrier) {
4240
4245
  if (!carrier) return null;
@@ -4255,13 +4260,13 @@ var FLAGSHIP_TIER = /* @__PURE__ */ new Set([
4255
4260
  // Google
4256
4261
  "gemini-3-1",
4257
4262
  "gemini-3-flash",
4258
- // xAI
4259
- "grok-4-3",
4263
+ // xAI · no flagship in registry currently.
4260
4264
  // DeepSeek
4261
4265
  "deepseek-v4-pro",
4262
- // Zhipu · Moonshot · single flagship each (both OR + B.AI routed).
4266
+ // Zhipu · Moonshot · MiniMax · single flagship each (B.AI routed).
4263
4267
  "glm-5-1",
4264
- "kimi-2-6"
4268
+ "kimi-k2-6",
4269
+ "minimax-m2-7"
4265
4270
  ]);
4266
4271
  function effectiveDefaultModel() {
4267
4272
  const prefs = getPrefs();
@@ -4314,17 +4319,15 @@ var CHEAP_BY_CARRIER = {
4314
4319
  anthropic: "sonnet-4-6",
4315
4320
  // only direct-routable Claude
4316
4321
  openai: "gpt-5-4-mini",
4317
- google: "gemini-3-1-flash",
4322
+ google: "gemini-3-1-flash"
4318
4323
  // 3.1 Flash Lite · cheapest direct-routable Gemini
4319
- xai: "grok-4-1-fast"
4320
- // 4.1 Fast · cheapest direct-routable Grok
4324
+ // xai · no cheap tier (no LLM modelV in registry).
4321
4325
  };
4322
4326
  var UTILITY_PREFERENCE = [
4323
4327
  "haiku-4-5",
4324
4328
  "gpt-5-4-mini",
4325
4329
  "gemini-3-1-flash",
4326
- "gemini-3-flash",
4327
- "grok-4-1-fast"
4330
+ "gemini-3-flash"
4328
4331
  ];
4329
4332
  function utilityModelFor(fallback = null) {
4330
4333
  const reachable = new Set(reachableModels().map((m) => m.modelV));
@@ -16587,6 +16590,19 @@ function setKeyPointVote(id, vote) {
16587
16590
  function pickRouterModel() {
16588
16591
  return utilityModelFor();
16589
16592
  }
16593
+ function authorLabel(m, cast) {
16594
+ if (m.authorKind === "user") return "USER";
16595
+ if (m.authorKind === "system") return "system";
16596
+ if (!m.authorId) return m.authorKind === "agent" ? "director" : m.authorKind;
16597
+ const fromCast = cast?.find((a2) => a2.id === m.authorId);
16598
+ if (fromCast) return `${fromCast.name} (${fromCast.handle})`;
16599
+ const a = getAgent(m.authorId);
16600
+ if (a) {
16601
+ const kindTag = a.roleKind === "moderator" ? "chair" : "director";
16602
+ return `${a.name} (${a.handle}, ${kindTag})`;
16603
+ }
16604
+ return m.authorKind === "agent" ? "director" : m.authorKind;
16605
+ }
16590
16606
  var MAX_PICKS = 2;
16591
16607
  async function pickChairClarifyDecision(opts) {
16592
16608
  const prompt = latestUserPrompt(opts.history);
@@ -16664,10 +16680,7 @@ async function pickRoundWrap(opts) {
16664
16680
  if (meta?.kind === "tool-use" || meta?.kind === "tool-preamble") return false;
16665
16681
  if (meta?.kind === "round-open" || meta?.kind === "round-prompt") return false;
16666
16682
  return true;
16667
- }).map((m) => {
16668
- const who = m.authorKind === "user" ? "USER" : m.authorId || "agent";
16669
- return `[${who}] ${m.body.trim().slice(0, 600)}`;
16670
- }).join("\n\n");
16683
+ }).map((m) => `[${authorLabel(m)}] ${m.body.trim().slice(0, 600)}`).join("\n\n");
16671
16684
  const sys = {
16672
16685
  role: "system",
16673
16686
  content: [
@@ -16771,10 +16784,7 @@ ${extras.join("\n")}` : baseRow;
16771
16784
  if (meta?.kind === "tool-use" || meta?.kind === "tool-preamble") return false;
16772
16785
  if (meta?.kind === "round-open" || meta?.kind === "round-prompt") return false;
16773
16786
  return true;
16774
- }).map((m) => {
16775
- const who = m.authorKind === "user" ? "USER" : m.authorId || "agent";
16776
- return `[${who}] ${m.body.trim().slice(0, 600)}`;
16777
- }).join("\n\n");
16787
+ }).map((m) => `[${authorLabel(m, candidates)}] ${m.body.trim().slice(0, 600)}`).join("\n\n");
16778
16788
  const decision1Block = mode === "dissent-gap" ? [
16779
16789
  "DECISION 1 \xB7 Next speaker (DISSENT-GAP MODE).",
16780
16790
  "The room is converging on a single frame \u2014 for THIS pick, the chair",
@@ -16836,6 +16846,13 @@ ${extras.join("\n")}` : baseRow;
16836
16846
  "the SPECIFIC pattern + the load-bearing piece worth pinning down.",
16837
16847
  "No greeting, no signature.",
16838
16848
  "",
16849
+ "NAMING \xB7 When `intervention` or `rationale` references a director,",
16850
+ "use their DISPLAY NAME (the part before the parenthesis in the",
16851
+ 'roster \u2014 e.g. "Maya", not "fk7wvt1bep62"). The opaque id is for',
16852
+ "the `agent_id` JSON field ONLY; it must NEVER appear inside any",
16853
+ "user-facing prose text. The transcript above labels speakers by",
16854
+ "name already; mirror that format.",
16855
+ "",
16839
16856
  "LANGUAGE \xB7 the chair note must follow the room's DOMINANT",
16840
16857
  "language detected from the recent transcript (most recent",
16841
16858
  "messages weight highest). If most directors and the user are",
@@ -16909,16 +16926,26 @@ ${extras.join("\n")}` : baseRow;
16909
16926
  const obj = parsed;
16910
16927
  const validIds = new Set(candidates.map((c) => c.id));
16911
16928
  const id = typeof obj.agent_id === "string" && validIds.has(obj.agent_id) ? obj.agent_id : null;
16912
- const rationale = typeof obj.rationale === "string" ? obj.rationale.trim().slice(0, 200) : "";
16929
+ const rationale = typeof obj.rationale === "string" ? replaceLeakedIds(obj.rationale.trim(), candidates).slice(0, 200) : "";
16913
16930
  let intervention = null;
16914
16931
  if (typeof obj.intervention === "string") {
16915
- const t = obj.intervention.trim();
16932
+ const t = replaceLeakedIds(obj.intervention.trim(), candidates);
16916
16933
  if (t.length > 0 && t.toLowerCase() !== "null" && t.toLowerCase() !== "none") {
16917
16934
  intervention = t.slice(0, 280);
16918
16935
  }
16919
16936
  }
16920
16937
  return { agentId: id, rationale, intervention };
16921
16938
  }
16939
+ function replaceLeakedIds(text, candidates) {
16940
+ if (!text) return text;
16941
+ return text.replace(/(?<![A-Za-z0-9])[0-9a-hjkmnpqrstvwxyz]{12}(?![A-Za-z0-9])/g, (id) => {
16942
+ const fromCast = candidates.find((c) => c.id === id);
16943
+ if (fromCast) return fromCast.name;
16944
+ const a = getAgent(id);
16945
+ if (a) return a.name;
16946
+ return id;
16947
+ });
16948
+ }
16922
16949
  async function pickChairWebSearch(opts) {
16923
16950
  const prompt = latestUserPrompt(opts.history);
16924
16951
  if (!prompt) return null;
@@ -23544,7 +23571,7 @@ function voicesRouter() {
23544
23571
  init_paths();
23545
23572
 
23546
23573
  // src/version.ts
23547
- var VERSION = "0.1.22";
23574
+ var VERSION = "0.1.24";
23548
23575
 
23549
23576
  // src/server.ts
23550
23577
  function createApp() {