switchroom 0.21.7 → 0.21.9

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 (59) hide show
  1. package/bin/tmp-reaper.sh +234 -0
  2. package/dist/agent-scheduler/index.js +1 -1
  3. package/dist/auth-broker/index.js +2 -2
  4. package/dist/cli/notion-write-pretool.mjs +1 -1
  5. package/dist/cli/switchroom.js +3520 -2782
  6. package/dist/host-control/main.js +177 -13
  7. package/dist/vault/approvals/kernel-server.js +2 -2
  8. package/dist/vault/broker/server.js +2 -2
  9. package/package.json +6 -5
  10. package/profiles/_base/start.sh.hbs +115 -0
  11. package/profiles/_shared/local-time.md.hbs +6 -0
  12. package/profiles/default/CLAUDE.md.hbs +0 -12
  13. package/skills/switchroom-architecture/telegram.md +12 -10
  14. package/skills/switchroom-cli/SKILL.md +1 -1
  15. package/telegram-plugin/README.md +3 -1
  16. package/telegram-plugin/dist/gateway/gateway.js +1164 -547
  17. package/telegram-plugin/format.ts +12 -4
  18. package/telegram-plugin/gateway/agent-process-liveness.ts +558 -0
  19. package/telegram-plugin/gateway/approval-hold.ts +32 -1
  20. package/telegram-plugin/gateway/approval-outcome-sources.ts +274 -0
  21. package/telegram-plugin/gateway/bridge-dead-watchdog.ts +21 -9
  22. package/telegram-plugin/gateway/callback-query-handlers.ts +87 -15
  23. package/telegram-plugin/gateway/eval-case-proposal-inbound-builders.ts +197 -0
  24. package/telegram-plugin/gateway/gateway.ts +12 -10
  25. package/telegram-plugin/gateway/pending-inbound-buffer.ts +167 -11
  26. package/telegram-plugin/gateway/self-improve-proposal-wiring.test.ts +333 -0
  27. package/telegram-plugin/gateway/self-improve-proposal-wiring.ts +152 -3
  28. package/telegram-plugin/gateway/subagent-handback-marker.ts +19 -0
  29. package/telegram-plugin/package.json +1 -1
  30. package/telegram-plugin/render/code-segments.ts +38 -4
  31. package/telegram-plugin/render/dollar-math-guard.ts +16 -1
  32. package/telegram-plugin/render/ir.ts +53 -3
  33. package/telegram-plugin/render/parse.ts +73 -14
  34. package/telegram-plugin/render/render.ts +53 -15
  35. package/telegram-plugin/render/unsupported-token-guard.ts +45 -80
  36. package/telegram-plugin/rich-send.ts +22 -7
  37. package/telegram-plugin/shared/bot-runtime.ts +3 -2
  38. package/telegram-plugin/telegraph.ts +6 -4
  39. package/telegram-plugin/tests/agent-process-liveness.test.ts +406 -0
  40. package/telegram-plugin/tests/approval-hold-record.test.ts +21 -8
  41. package/telegram-plugin/tests/boot-resume-gateway-only-respawn.test.ts +752 -0
  42. package/telegram-plugin/tests/boot-resume-guard-wiring.test.ts +203 -0
  43. package/telegram-plugin/tests/callback-query-handlers.test.ts +143 -1
  44. package/telegram-plugin/tests/eval-case-proposal-inbound-builders.test.ts +144 -0
  45. package/telegram-plugin/tests/grammy-rich-message-types.test.ts +199 -0
  46. package/telegram-plugin/tests/hermes-messages-paging.test.ts +149 -0
  47. package/telegram-plugin/tests/hermes-session-search.test.ts +146 -0
  48. package/telegram-plugin/tests/pending-inbound-buffer.test.ts +443 -2
  49. package/telegram-plugin/tests/render/dollar-math-guard.test.ts +43 -0
  50. package/telegram-plugin/tests/render/guard-composition.test.ts +102 -0
  51. package/telegram-plugin/tests/render/parse.test.ts +30 -5
  52. package/telegram-plugin/tests/render/render.test.ts +9 -4
  53. package/telegram-plugin/tests/render/rich-render.test.ts +46 -5
  54. package/telegram-plugin/tests/render/tg-entity.test.ts +242 -0
  55. package/telegram-plugin/tests/render/unsupported-token-guard.test.ts +66 -66
  56. package/telegram-plugin/tests/sent-text-capture.test.ts +3 -3
  57. package/telegram-plugin/tests/subagent-handback-marker.test.ts +14 -0
  58. package/telegram-plugin/tests/telegraph.test.ts +1 -1
  59. package/telegram-plugin/uat/scenarios/jtbd-rich-formatting-render-dm.test.ts +17 -8
@@ -66,7 +66,7 @@ var __export = (target, all) => {
66
66
  var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
67
67
  var __require = /* @__PURE__ */ createRequire(import.meta.url);
68
68
 
69
- // ../node_modules/.bun/grammy@1.44.0/node_modules/grammy/out/filter.js
69
+ // ../node_modules/.bun/grammy@1.45.1/node_modules/grammy/out/filter.js
70
70
  var require_filter = __commonJS((exports) => {
71
71
  Object.defineProperty(exports, "__esModule", { value: true });
72
72
  exports.matchFilter = matchFilter;
@@ -357,6 +357,8 @@ var require_filter = __commonJS((exports) => {
357
357
  checklist: { others_can_add_tasks: {}, others_can_mark_tasks_as_done: {} },
358
358
  checklist_tasks_done: {},
359
359
  checklist_tasks_added: {},
360
+ community_chat_added: {},
361
+ community_chat_removed: {},
360
362
  poll_option_added: {},
361
363
  poll_option_deleted: {},
362
364
  suggested_post_info: {},
@@ -411,7 +413,8 @@ var require_filter = __commonJS((exports) => {
411
413
  message_reaction_count: MESSAGE_REACTION_COUNT_UPDATED_KEYS,
412
414
  chat_boost: {},
413
415
  removed_chat_boost: {},
414
- purchased_paid_media: {}
416
+ purchased_paid_media: {},
417
+ subscription: { state: { canceled: {}, active: {}, failed: {} } }
415
418
  };
416
419
  var L1_SHORTCUTS = {
417
420
  "": ["message", "channel_post"],
@@ -435,7 +438,7 @@ var require_filter = __commonJS((exports) => {
435
438
  };
436
439
  });
437
440
 
438
- // ../node_modules/.bun/grammy@1.44.0/node_modules/grammy/out/context.js
441
+ // ../node_modules/.bun/grammy@1.45.1/node_modules/grammy/out/context.js
439
442
  var require_context = __commonJS((exports) => {
440
443
  Object.defineProperty(exports, "__esModule", { value: true });
441
444
  exports.Context = undefined;
@@ -676,6 +679,9 @@ var require_context = __commonJS((exports) => {
676
679
  get purchasedPaidMedia() {
677
680
  return this.update.purchased_paid_media;
678
681
  }
682
+ get subscription() {
683
+ return this.update.subscription;
684
+ }
679
685
  get msg() {
680
686
  var _a, _b, _c, _d, _e, _f, _g, _h;
681
687
  return (_g = (_f = (_e = (_d = (_c = (_b = (_a = this.message) !== null && _a !== undefined ? _a : this.editedMessage) !== null && _b !== undefined ? _b : this.channelPost) !== null && _c !== undefined ? _c : this.editedChannelPost) !== null && _d !== undefined ? _d : this.businessMessage) !== null && _e !== undefined ? _e : this.editedBusinessMessage) !== null && _f !== undefined ? _f : this.guestMessage) !== null && _g !== undefined ? _g : (_h = this.callbackQuery) === null || _h === undefined ? undefined : _h.message;
@@ -689,8 +695,8 @@ var require_context = __commonJS((exports) => {
689
695
  return (_a = this.msg) === null || _a === undefined ? undefined : _a.sender_chat;
690
696
  }
691
697
  get from() {
692
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t;
693
- return (_h = (_g = (_c = (_b = (_a = this.businessConnection) !== null && _a !== undefined ? _a : this.messageReaction) !== null && _b !== undefined ? _b : this.managedBot) !== null && _c !== undefined ? _c : (_f = (_e = (_d = this.chatBoost) === null || _d === undefined ? undefined : _d.boost) !== null && _e !== undefined ? _e : this.removedChatBoost) === null || _f === undefined ? undefined : _f.source) === null || _g === undefined ? undefined : _g.user) !== null && _h !== undefined ? _h : (_t = (_s = (_r = (_q = (_p = (_o = (_m = (_l = (_k = (_j = this.callbackQuery) !== null && _j !== undefined ? _j : this.msg) !== null && _k !== undefined ? _k : this.inlineQuery) !== null && _l !== undefined ? _l : this.chosenInlineResult) !== null && _m !== undefined ? _m : this.shippingQuery) !== null && _o !== undefined ? _o : this.preCheckoutQuery) !== null && _p !== undefined ? _p : this.myChatMember) !== null && _q !== undefined ? _q : this.chatMember) !== null && _r !== undefined ? _r : this.chatJoinRequest) !== null && _s !== undefined ? _s : this.purchasedPaidMedia) === null || _t === undefined ? undefined : _t.from;
698
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u;
699
+ return (_j = (_h = (_g = (_c = (_b = (_a = this.businessConnection) !== null && _a !== undefined ? _a : this.messageReaction) !== null && _b !== undefined ? _b : this.managedBot) !== null && _c !== undefined ? _c : (_f = (_e = (_d = this.chatBoost) === null || _d === undefined ? undefined : _d.boost) !== null && _e !== undefined ? _e : this.removedChatBoost) === null || _f === undefined ? undefined : _f.source) !== null && _g !== undefined ? _g : this.subscription) === null || _h === undefined ? undefined : _h.user) !== null && _j !== undefined ? _j : (_u = (_t = (_s = (_r = (_q = (_p = (_o = (_m = (_l = (_k = this.callbackQuery) !== null && _k !== undefined ? _k : this.msg) !== null && _l !== undefined ? _l : this.inlineQuery) !== null && _m !== undefined ? _m : this.chosenInlineResult) !== null && _o !== undefined ? _o : this.shippingQuery) !== null && _p !== undefined ? _p : this.preCheckoutQuery) !== null && _q !== undefined ? _q : this.myChatMember) !== null && _r !== undefined ? _r : this.chatMember) !== null && _s !== undefined ? _s : this.chatJoinRequest) !== null && _t !== undefined ? _t : this.purchasedPaidMedia) === null || _u === undefined ? undefined : _u.from;
694
700
  }
695
701
  get msgId() {
696
702
  var _a, _b, _c, _d, _e;
@@ -1349,6 +1355,22 @@ var require_context = __commonJS((exports) => {
1349
1355
  var _a, _b, _c, _d, _e;
1350
1356
  return this.api.stopPoll(orThrow(this.chatId, "stopPoll"), orThrow((_d = (_b = (_a = this.msg) === null || _a === undefined ? undefined : _a.message_id) !== null && _b !== undefined ? _b : (_c = this.messageReaction) === null || _c === undefined ? undefined : _c.message_id) !== null && _d !== undefined ? _d : (_e = this.messageReactionCount) === null || _e === undefined ? undefined : _e.message_id, "stopPoll"), { business_connection_id: this.businessConnectionId, ...other }, signal);
1351
1357
  }
1358
+ editEphemeralMessageText(text, other, signal) {
1359
+ const msg = orThrow(this.msg, "editEphemeralMessageText");
1360
+ return this.api.editEphemeralMessageText(msg.chat.id, orThrow(msg.receiver_user, "editEphemeralMessageText").id, orThrow(msg.ephemeral_message_id, "editEphemeralMessageText"), text, other, signal);
1361
+ }
1362
+ editEphemeralMessageMedia(media, other, signal) {
1363
+ const msg = orThrow(this.msg, "editEphemeralMessageMedia");
1364
+ return this.api.editEphemeralMessageMedia(msg.chat.id, orThrow(msg.receiver_user, "editEphemeralMessageMedia").id, orThrow(msg.ephemeral_message_id, "editEphemeralMessageMedia"), media, other, signal);
1365
+ }
1366
+ editEphemeralMessageCaption(caption, other, signal) {
1367
+ const msg = orThrow(this.msg, "editEphemeralMessageCaption");
1368
+ return this.api.editEphemeralMessageCaption(msg.chat.id, orThrow(msg.receiver_user, "editEphemeralMessageCaption").id, orThrow(msg.ephemeral_message_id, "editEphemeralMessageCaption"), caption, other, signal);
1369
+ }
1370
+ editEphemeralMessageReplyMarkup(other, signal) {
1371
+ const msg = orThrow(this.msg, "editEphemeralMessageReplyMarkup");
1372
+ return this.api.editEphemeralMessageReplyMarkup(msg.chat.id, orThrow(msg.receiver_user, "editEphemeralMessageReplyMarkup").id, orThrow(msg.ephemeral_message_id, "editEphemeralMessageReplyMarkup"), other, signal);
1373
+ }
1352
1374
  deleteMessage(signal) {
1353
1375
  var _a, _b, _c, _d, _e;
1354
1376
  return this.api.deleteMessage(orThrow(this.chatId, "deleteMessage"), orThrow((_d = (_b = (_a = this.msg) === null || _a === undefined ? undefined : _a.message_id) !== null && _b !== undefined ? _b : (_c = this.messageReaction) === null || _c === undefined ? undefined : _c.message_id) !== null && _d !== undefined ? _d : (_e = this.messageReactionCount) === null || _e === undefined ? undefined : _e.message_id, "deleteMessage"), signal);
@@ -1356,6 +1378,10 @@ var require_context = __commonJS((exports) => {
1356
1378
  deleteMessages(message_ids, signal) {
1357
1379
  return this.api.deleteMessages(orThrow(this.chatId, "deleteMessages"), message_ids, signal);
1358
1380
  }
1381
+ deleteEphemeralMessage(signal) {
1382
+ const msg = orThrow(this.msg, "deleteEphemeralMessage");
1383
+ return this.api.deleteEphemeralMessage(msg.chat.id, orThrow(msg.receiver_user, "deleteEphemeralMessage").id, orThrow(msg.ephemeral_message_id, "deleteEphemeralMessage"), signal);
1384
+ }
1359
1385
  deleteMessageReaction(other, signal) {
1360
1386
  const reaction = orThrow(this.messageReaction, "deleteMessageReaction");
1361
1387
  if (reaction.user !== undefined) {
@@ -1548,7 +1574,7 @@ var require_context = __commonJS((exports) => {
1548
1574
  }
1549
1575
  });
1550
1576
 
1551
- // ../node_modules/.bun/grammy@1.44.0/node_modules/grammy/out/composer.js
1577
+ // ../node_modules/.bun/grammy@1.45.1/node_modules/grammy/out/composer.js
1552
1578
  var require_composer = __commonJS((exports) => {
1553
1579
  Object.defineProperty(exports, "__esModule", { value: true });
1554
1580
  exports.Composer = exports.BotError = undefined;
@@ -2444,7 +2470,7 @@ var require_src = __commonJS((exports, module) => {
2444
2470
  }
2445
2471
  });
2446
2472
 
2447
- // ../node_modules/.bun/grammy@1.44.0/node_modules/grammy/out/platform.node.js
2473
+ // ../node_modules/.bun/grammy@1.45.1/node_modules/grammy/out/platform.node.js
2448
2474
  var require_platform_node = __commonJS((exports) => {
2449
2475
  Object.defineProperty(exports, "__esModule", { value: true });
2450
2476
  exports.defaultAdapter = exports.itrToStream = exports.debug = undefined;
@@ -2472,19 +2498,21 @@ var require_platform_node = __commonJS((exports) => {
2472
2498
  if (apiRoot.startsWith("https:")) {
2473
2499
  return {
2474
2500
  compress: true,
2475
- agent: getCached(httpsAgents, apiRoot, () => new https_1.Agent({ keepAlive: true }))
2501
+ agent: getCached(httpsAgents, apiRoot, () => new https_1.Agent({ keepAlive: true })),
2502
+ duplex: "half"
2476
2503
  };
2477
2504
  } else if (apiRoot.startsWith("http:")) {
2478
2505
  return {
2479
- agent: getCached(httpAgents, apiRoot, () => new http_1.Agent({ keepAlive: true }))
2506
+ agent: getCached(httpAgents, apiRoot, () => new http_1.Agent({ keepAlive: true })),
2507
+ duplex: "half"
2480
2508
  };
2481
2509
  } else
2482
- return {};
2510
+ return { duplex: "half" };
2483
2511
  }
2484
2512
  exports.defaultAdapter = "express";
2485
2513
  });
2486
2514
 
2487
- // ../node_modules/.bun/grammy@1.44.0/node_modules/grammy/out/core/error.js
2515
+ // ../node_modules/.bun/grammy@1.45.1/node_modules/grammy/out/core/error.js
2488
2516
  var require_error = __commonJS((exports) => {
2489
2517
  Object.defineProperty(exports, "__esModule", { value: true });
2490
2518
  exports.HttpError = exports.GrammyError = undefined;
@@ -2540,10 +2568,10 @@ var require_error = __commonJS((exports) => {
2540
2568
  }
2541
2569
  });
2542
2570
 
2543
- // ../node_modules/.bun/@grammyjs+types@3.28.0/node_modules/@grammyjs/types/mod.js
2571
+ // ../node_modules/.bun/@grammyjs+types@4.0.0/node_modules/@grammyjs/types/mod.js
2544
2572
  var exports_mod = {};
2545
2573
 
2546
- // ../node_modules/.bun/grammy@1.44.0/node_modules/grammy/out/types.node.js
2574
+ // ../node_modules/.bun/grammy@1.45.1/node_modules/grammy/out/types.node.js
2547
2575
  var require_types_node = __commonJS((exports) => {
2548
2576
  var __createBinding = exports && exports.__createBinding || (Object.create ? function(o, m, k, k2) {
2549
2577
  if (k2 === undefined)
@@ -2634,7 +2662,7 @@ var require_types_node = __commonJS((exports) => {
2634
2662
  }
2635
2663
  });
2636
2664
 
2637
- // ../node_modules/.bun/grammy@1.44.0/node_modules/grammy/out/types.js
2665
+ // ../node_modules/.bun/grammy@1.45.1/node_modules/grammy/out/types.js
2638
2666
  var require_types = __commonJS((exports) => {
2639
2667
  var __createBinding = exports && exports.__createBinding || (Object.create ? function(o, m, k, k2) {
2640
2668
  if (k2 === undefined)
@@ -2660,7 +2688,7 @@ var require_types = __commonJS((exports) => {
2660
2688
  __exportStar(require_types_node(), exports);
2661
2689
  });
2662
2690
 
2663
- // ../node_modules/.bun/grammy@1.44.0/node_modules/grammy/out/core/payload.js
2691
+ // ../node_modules/.bun/grammy@1.45.1/node_modules/grammy/out/core/payload.js
2664
2692
  var require_payload = __commonJS((exports) => {
2665
2693
  Object.defineProperty(exports, "__esModule", { value: true });
2666
2694
  exports.requiresFormDataUpload = requiresFormDataUpload;
@@ -3320,7 +3348,7 @@ var require_abort_controller = __commonJS((exports, module) => {
3320
3348
  module.exports.AbortSignal = AbortSignal2;
3321
3349
  });
3322
3350
 
3323
- // ../node_modules/.bun/grammy@1.44.0/node_modules/grammy/out/shim.node.js
3351
+ // ../node_modules/.bun/grammy@1.45.1/node_modules/grammy/out/shim.node.js
3324
3352
  var require_shim_node = __commonJS((exports) => {
3325
3353
  Object.defineProperty(exports, "__esModule", { value: true });
3326
3354
  exports.fetch = exports.AbortController = undefined;
@@ -3334,7 +3362,7 @@ var require_shim_node = __commonJS((exports) => {
3334
3362
  } });
3335
3363
  });
3336
3364
 
3337
- // ../node_modules/.bun/grammy@1.44.0/node_modules/grammy/out/core/client.js
3365
+ // ../node_modules/.bun/grammy@1.45.1/node_modules/grammy/out/core/client.js
3338
3366
  var require_client = __commonJS((exports) => {
3339
3367
  Object.defineProperty(exports, "__esModule", { value: true });
3340
3368
  exports.createRawApi = createRawApi;
@@ -3514,7 +3542,7 @@ If you want to prevent such mistakes in the future, consider using TypeScript. h
3514
3542
  var shim_node_js_1 = require_shim_node();
3515
3543
  });
3516
3544
 
3517
- // ../node_modules/.bun/grammy@1.44.0/node_modules/grammy/out/core/api.js
3545
+ // ../node_modules/.bun/grammy@1.45.1/node_modules/grammy/out/core/api.js
3518
3546
  var require_api = __commonJS((exports) => {
3519
3547
  Object.defineProperty(exports, "__esModule", { value: true });
3520
3548
  exports.Api = undefined;
@@ -3955,12 +3983,39 @@ var require_api = __commonJS((exports) => {
3955
3983
  stopPoll(chat_id, message_id, other, signal) {
3956
3984
  return this.raw.stopPoll({ chat_id, message_id, ...other }, signal);
3957
3985
  }
3986
+ editEphemeralMessageText(chat_id, receiver_user_id, ephemeral_message_id, text, other, signal) {
3987
+ return this.raw.editEphemeralMessageText({ chat_id, receiver_user_id, ephemeral_message_id, text, ...other }, signal);
3988
+ }
3989
+ editEphemeralMessageMedia(chat_id, receiver_user_id, ephemeral_message_id, media, other, signal) {
3990
+ return this.raw.editEphemeralMessageMedia({
3991
+ chat_id,
3992
+ receiver_user_id,
3993
+ ephemeral_message_id,
3994
+ media,
3995
+ ...other
3996
+ }, signal);
3997
+ }
3998
+ editEphemeralMessageCaption(chat_id, receiver_user_id, ephemeral_message_id, caption, other, signal) {
3999
+ return this.raw.editEphemeralMessageCaption({
4000
+ chat_id,
4001
+ receiver_user_id,
4002
+ ephemeral_message_id,
4003
+ caption,
4004
+ ...other
4005
+ }, signal);
4006
+ }
4007
+ editEphemeralMessageReplyMarkup(chat_id, receiver_user_id, ephemeral_message_id, other, signal) {
4008
+ return this.raw.editEphemeralMessageReplyMarkup({ chat_id, receiver_user_id, ephemeral_message_id, ...other }, signal);
4009
+ }
3958
4010
  deleteMessage(chat_id, message_id, signal) {
3959
4011
  return this.raw.deleteMessage({ chat_id, message_id }, signal);
3960
4012
  }
3961
4013
  deleteMessages(chat_id, message_ids, signal) {
3962
4014
  return this.raw.deleteMessages({ chat_id, message_ids }, signal);
3963
4015
  }
4016
+ deleteEphemeralMessage(chat_id, receiver_user_id, ephemeral_message_id, signal) {
4017
+ return this.raw.deleteEphemeralMessage({ chat_id, receiver_user_id, ephemeral_message_id }, signal);
4018
+ }
3964
4019
  deleteMessageReactionUser(chat_id, message_id, user_id, other, signal) {
3965
4020
  return this.raw.deleteMessageReaction({
3966
4021
  chat_id,
@@ -4202,7 +4257,7 @@ var require_api = __commonJS((exports) => {
4202
4257
  exports.Api = Api;
4203
4258
  });
4204
4259
 
4205
- // ../node_modules/.bun/grammy@1.44.0/node_modules/grammy/out/bot.js
4260
+ // ../node_modules/.bun/grammy@1.45.1/node_modules/grammy/out/bot.js
4206
4261
  var require_bot = __commonJS((exports) => {
4207
4262
  Object.defineProperty(exports, "__esModule", { value: true });
4208
4263
  exports.Bot = exports.BotError = exports.DEFAULT_UPDATE_TYPES = undefined;
@@ -4240,7 +4295,8 @@ var require_bot = __commonJS((exports) => {
4240
4295
  "managed_bot",
4241
4296
  "chat_join_request",
4242
4297
  "chat_boost",
4243
- "removed_chat_boost"
4298
+ "removed_chat_boost",
4299
+ "subscription"
4244
4300
  ];
4245
4301
 
4246
4302
  class Bot extends composer_js_1.Composer {
@@ -4532,7 +4588,7 @@ On the other hand, if you actually know what you're doing and you do need to ins
4532
4588
  var shim_node_js_1 = require_shim_node();
4533
4589
  });
4534
4590
 
4535
- // ../node_modules/.bun/grammy@1.44.0/node_modules/grammy/out/convenience/constants.js
4591
+ // ../node_modules/.bun/grammy@1.45.1/node_modules/grammy/out/convenience/constants.js
4536
4592
  var require_constants = __commonJS((exports) => {
4537
4593
  Object.defineProperty(exports, "__esModule", { value: true });
4538
4594
  exports.API_CONSTANTS = undefined;
@@ -4569,7 +4625,7 @@ var require_constants = __commonJS((exports) => {
4569
4625
  Object.freeze(exports.API_CONSTANTS);
4570
4626
  });
4571
4627
 
4572
- // ../node_modules/.bun/grammy@1.44.0/node_modules/grammy/out/convenience/inline_query.js
4628
+ // ../node_modules/.bun/grammy@1.45.1/node_modules/grammy/out/convenience/inline_query.js
4573
4629
  var require_inline_query = __commonJS((exports) => {
4574
4630
  Object.defineProperty(exports, "__esModule", { value: true });
4575
4631
  exports.InlineQueryResultBuilder = undefined;
@@ -4774,7 +4830,7 @@ var require_inline_query = __commonJS((exports) => {
4774
4830
  };
4775
4831
  });
4776
4832
 
4777
- // ../node_modules/.bun/grammy@1.44.0/node_modules/grammy/out/convenience/input_media.js
4833
+ // ../node_modules/.bun/grammy@1.45.1/node_modules/grammy/out/convenience/input_media.js
4778
4834
  var require_input_media = __commonJS((exports) => {
4779
4835
  Object.defineProperty(exports, "__esModule", { value: true });
4780
4836
  exports.InputMediaBuilder = undefined;
@@ -4797,7 +4853,7 @@ var require_input_media = __commonJS((exports) => {
4797
4853
  };
4798
4854
  });
4799
4855
 
4800
- // ../node_modules/.bun/grammy@1.44.0/node_modules/grammy/out/convenience/keyboard.js
4856
+ // ../node_modules/.bun/grammy@1.45.1/node_modules/grammy/out/convenience/keyboard.js
4801
4857
  var require_keyboard = __commonJS((exports) => {
4802
4858
  Object.defineProperty(exports, "__esModule", { value: true });
4803
4859
  exports.InlineKeyboard = exports.Keyboard = undefined;
@@ -5155,7 +5211,7 @@ var require_keyboard = __commonJS((exports) => {
5155
5211
  }
5156
5212
  });
5157
5213
 
5158
- // ../node_modules/.bun/grammy@1.44.0/node_modules/grammy/out/convenience/session.js
5214
+ // ../node_modules/.bun/grammy@1.45.1/node_modules/grammy/out/convenience/session.js
5159
5215
  var require_session = __commonJS((exports) => {
5160
5216
  Object.defineProperty(exports, "__esModule", { value: true });
5161
5217
  exports.MemorySessionStorage = undefined;
@@ -5455,7 +5511,7 @@ var require_session = __commonJS((exports) => {
5455
5511
  }
5456
5512
  });
5457
5513
 
5458
- // ../node_modules/.bun/grammy@1.44.0/node_modules/grammy/out/convenience/frameworks.js
5514
+ // ../node_modules/.bun/grammy@1.45.1/node_modules/grammy/out/convenience/frameworks.js
5459
5515
  var require_frameworks = __commonJS((exports) => {
5460
5516
  Object.defineProperty(exports, "__esModule", { value: true });
5461
5517
  exports.adapters = undefined;
@@ -5827,7 +5883,7 @@ var require_frameworks = __commonJS((exports) => {
5827
5883
  };
5828
5884
  });
5829
5885
 
5830
- // ../node_modules/.bun/grammy@1.44.0/node_modules/grammy/out/convenience/webhook.js
5886
+ // ../node_modules/.bun/grammy@1.45.1/node_modules/grammy/out/convenience/webhook.js
5831
5887
  var require_webhook = __commonJS((exports) => {
5832
5888
  Object.defineProperty(exports, "__esModule", { value: true });
5833
5889
  exports.webhookCallback = webhookCallback;
@@ -5921,7 +5977,7 @@ var require_webhook = __commonJS((exports) => {
5921
5977
  }
5922
5978
  });
5923
5979
 
5924
- // ../node_modules/.bun/grammy@1.44.0/node_modules/grammy/out/mod.js
5980
+ // ../node_modules/.bun/grammy@1.45.1/node_modules/grammy/out/mod.js
5925
5981
  var require_mod = __commonJS((exports) => {
5926
5982
  var __createBinding = exports && exports.__createBinding || (Object.create ? function(o, m, k, k2) {
5927
5983
  if (k2 === undefined)
@@ -5987,7 +6043,7 @@ var require_mod = __commonJS((exports) => {
5987
6043
  } });
5988
6044
  });
5989
6045
 
5990
- // ../node_modules/.bun/@grammyjs+runner@2.0.3+061f65c8e99495c7/node_modules/@grammyjs/runner/out/platform.node.js
6046
+ // ../node_modules/.bun/@grammyjs+runner@2.0.3+a732625cbf2c154c/node_modules/@grammyjs/runner/out/platform.node.js
5991
6047
  var require_platform_node2 = __commonJS((exports) => {
5992
6048
  Object.defineProperty(exports, "__esModule", { value: true });
5993
6049
  exports.parentThread = exports.createThread = undefined;
@@ -6018,7 +6074,7 @@ var require_platform_node2 = __commonJS((exports) => {
6018
6074
  exports.parentThread = parentThread;
6019
6075
  });
6020
6076
 
6021
- // ../node_modules/.bun/@grammyjs+runner@2.0.3+061f65c8e99495c7/node_modules/@grammyjs/runner/out/distribute.js
6077
+ // ../node_modules/.bun/@grammyjs+runner@2.0.3+a732625cbf2c154c/node_modules/@grammyjs/runner/out/distribute.js
6022
6078
  var require_distribute = __commonJS((exports) => {
6023
6079
  Object.defineProperty(exports, "__esModule", { value: true });
6024
6080
  exports.distribute = undefined;
@@ -6063,7 +6119,7 @@ var require_distribute = __commonJS((exports) => {
6063
6119
  exports.distribute = distribute;
6064
6120
  });
6065
6121
 
6066
- // ../node_modules/.bun/@grammyjs+runner@2.0.3+061f65c8e99495c7/node_modules/@grammyjs/runner/out/queue.js
6122
+ // ../node_modules/.bun/@grammyjs+runner@2.0.3+a732625cbf2c154c/node_modules/@grammyjs/runner/out/queue.js
6067
6123
  var require_queue = __commonJS((exports) => {
6068
6124
  Object.defineProperty(exports, "__esModule", { value: true });
6069
6125
  exports.DecayingDeque = undefined;
@@ -6207,7 +6263,7 @@ var require_queue = __commonJS((exports) => {
6207
6263
  exports.DecayingDeque = DecayingDeque;
6208
6264
  });
6209
6265
 
6210
- // ../node_modules/.bun/@grammyjs+runner@2.0.3+061f65c8e99495c7/node_modules/@grammyjs/runner/out/sink.js
6266
+ // ../node_modules/.bun/@grammyjs+runner@2.0.3+a732625cbf2c154c/node_modules/@grammyjs/runner/out/sink.js
6211
6267
  var require_sink = __commonJS((exports) => {
6212
6268
  Object.defineProperty(exports, "__esModule", { value: true });
6213
6269
  exports.createConcurrentSink = exports.createBatchSink = exports.createSequentialSink = undefined;
@@ -6252,7 +6308,7 @@ var require_sink = __commonJS((exports) => {
6252
6308
  exports.createConcurrentSink = createConcurrentSink;
6253
6309
  });
6254
6310
 
6255
- // ../node_modules/.bun/@grammyjs+runner@2.0.3+061f65c8e99495c7/node_modules/@grammyjs/runner/out/node-shim.js
6311
+ // ../node_modules/.bun/@grammyjs+runner@2.0.3+a732625cbf2c154c/node_modules/@grammyjs/runner/out/node-shim.js
6256
6312
  var require_node_shim = __commonJS((exports) => {
6257
6313
  var __createBinding = exports && exports.__createBinding || (Object.create ? function(o, m, k, k2) {
6258
6314
  if (k2 === undefined)
@@ -6278,7 +6334,7 @@ var require_node_shim = __commonJS((exports) => {
6278
6334
  __exportStar(require_abort_controller(), exports);
6279
6335
  });
6280
6336
 
6281
- // ../node_modules/.bun/@grammyjs+runner@2.0.3+061f65c8e99495c7/node_modules/@grammyjs/runner/out/source.js
6337
+ // ../node_modules/.bun/@grammyjs+runner@2.0.3+a732625cbf2c154c/node_modules/@grammyjs/runner/out/source.js
6282
6338
  var require_source = __commonJS((exports) => {
6283
6339
  Object.defineProperty(exports, "__esModule", { value: true });
6284
6340
  exports.createSource = undefined;
@@ -6358,7 +6414,7 @@ var require_source = __commonJS((exports) => {
6358
6414
  var node_shim_js_1 = require_node_shim();
6359
6415
  });
6360
6416
 
6361
- // ../node_modules/.bun/@grammyjs+runner@2.0.3+061f65c8e99495c7/node_modules/@grammyjs/runner/out/runner.js
6417
+ // ../node_modules/.bun/@grammyjs+runner@2.0.3+a732625cbf2c154c/node_modules/@grammyjs/runner/out/runner.js
6362
6418
  var require_runner = __commonJS((exports) => {
6363
6419
  Object.defineProperty(exports, "__esModule", { value: true });
6364
6420
  exports.createRunner = exports.createUpdateFetcher = exports.run = undefined;
@@ -6510,7 +6566,7 @@ var require_runner = __commonJS((exports) => {
6510
6566
  }
6511
6567
  });
6512
6568
 
6513
- // ../node_modules/.bun/@grammyjs+runner@2.0.3+061f65c8e99495c7/node_modules/@grammyjs/runner/out/sequentialize.js
6569
+ // ../node_modules/.bun/@grammyjs+runner@2.0.3+a732625cbf2c154c/node_modules/@grammyjs/runner/out/sequentialize.js
6514
6570
  var require_sequentialize = __commonJS((exports) => {
6515
6571
  Object.defineProperty(exports, "__esModule", { value: true });
6516
6572
  exports.sequentialize = undefined;
@@ -6553,7 +6609,7 @@ var require_sequentialize = __commonJS((exports) => {
6553
6609
  exports.sequentialize = sequentialize;
6554
6610
  });
6555
6611
 
6556
- // ../node_modules/.bun/grammy@1.44.0/node_modules/grammy/out/mod.js
6612
+ // ../node_modules/.bun/grammy@1.45.1/node_modules/grammy/out/mod.js
6557
6613
  var require_mod2 = __commonJS((exports) => {
6558
6614
  var __createBinding = exports && exports.__createBinding || (Object.create ? function(o, m, k, k2) {
6559
6615
  if (k2 === undefined)
@@ -6619,7 +6675,7 @@ var require_mod2 = __commonJS((exports) => {
6619
6675
  } });
6620
6676
  });
6621
6677
 
6622
- // ../node_modules/.bun/@grammyjs+runner@2.0.3+061f65c8e99495c7/node_modules/@grammyjs/runner/out/deps.node.js
6678
+ // ../node_modules/.bun/@grammyjs+runner@2.0.3+a732625cbf2c154c/node_modules/@grammyjs/runner/out/deps.node.js
6623
6679
  var require_deps_node = __commonJS((exports) => {
6624
6680
  Object.defineProperty(exports, "__esModule", { value: true });
6625
6681
  exports.BotError = exports.Bot = undefined;
@@ -6632,7 +6688,7 @@ var require_deps_node = __commonJS((exports) => {
6632
6688
  } });
6633
6689
  });
6634
6690
 
6635
- // ../node_modules/.bun/@grammyjs+runner@2.0.3+061f65c8e99495c7/node_modules/@grammyjs/runner/out/worker.js
6691
+ // ../node_modules/.bun/@grammyjs+runner@2.0.3+a732625cbf2c154c/node_modules/@grammyjs/runner/out/worker.js
6636
6692
  var require_worker = __commonJS((exports) => {
6637
6693
  Object.defineProperty(exports, "__esModule", { value: true });
6638
6694
  exports.BotWorker = undefined;
@@ -6674,7 +6730,7 @@ var require_worker = __commonJS((exports) => {
6674
6730
  exports.BotWorker = BotWorker;
6675
6731
  });
6676
6732
 
6677
- // ../node_modules/.bun/@grammyjs+runner@2.0.3+061f65c8e99495c7/node_modules/@grammyjs/runner/out/mod.js
6733
+ // ../node_modules/.bun/@grammyjs+runner@2.0.3+a732625cbf2c154c/node_modules/@grammyjs/runner/out/mod.js
6678
6734
  var require_mod3 = __commonJS((exports) => {
6679
6735
  var __createBinding = exports && exports.__createBinding || (Object.create ? function(o, m, k, k2) {
6680
6736
  if (k2 === undefined)
@@ -7283,7 +7339,7 @@ var init_format = __esm(() => {
7283
7339
  /\*\*[^*\n]+\*\*/g,
7284
7340
  /__[^_\n]+__/g,
7285
7341
  /(?<![\w*])_[^_\n]+_(?![\w*])/g,
7286
- /\[[^\]\n]*\]\([^)\n]*\)/g,
7342
+ /!?\[[^\]\n]*\]\([^)\n]*\)/g,
7287
7343
  /~~[^~\n]+~~/g,
7288
7344
  /\|\|[^|\n]+\|\|/g
7289
7345
  ];
@@ -13444,6 +13500,15 @@ function splitProseProtected(text) {
13444
13500
  continue;
13445
13501
  }
13446
13502
  }
13503
+ if (ch === "$") {
13504
+ const m = COMPACT_MATH_PAIR.exec(text.slice(i));
13505
+ if (m && !CURRENCY_SHAPED_INNER.test(m[1])) {
13506
+ const end = i + m[0].length;
13507
+ pushProtected(i, end);
13508
+ i = end;
13509
+ continue;
13510
+ }
13511
+ }
13447
13512
  i++;
13448
13513
  }
13449
13514
  if (plainStart < text.length)
@@ -13462,6 +13527,11 @@ function splitProtectedSegments(text) {
13462
13527
  }
13463
13528
  return out;
13464
13529
  }
13530
+ var COMPACT_MATH_PAIR, CURRENCY_SHAPED_INNER;
13531
+ var init_code_segments = __esm(() => {
13532
+ COMPACT_MATH_PAIR = /^\$([^\s$]+)\$/;
13533
+ CURRENCY_SHAPED_INNER = /^[0-9.,+\-kKmMbB]+$/;
13534
+ });
13465
13535
 
13466
13536
  // render/dollar-math-guard.ts
13467
13537
  function guardDollarMath(text) {
@@ -13483,6 +13553,7 @@ function guardDollarMath(text) {
13483
13553
  }
13484
13554
  var ANY_DOLLAR, CURRENCY_SIGNAL, UNESCAPED_DOLLAR;
13485
13555
  var init_dollar_math_guard = __esm(() => {
13556
+ init_code_segments();
13486
13557
  ANY_DOLLAR = /\$/g;
13487
13558
  CURRENCY_SIGNAL = /\$\.?\d|\d\s?\$/;
13488
13559
  UNESCAPED_DOLLAR = /(?<!\\)\$/g;
@@ -13554,6 +13625,7 @@ function guardAccidentalEmphasis(text) {
13554
13625
  }
13555
13626
  var INTRA_WORD_UNDERSCORE, INTRA_WORD_ASTERISK, BOUNDARY_FLANKED_ASTERISK, ANY_UNDERSCORE, ANY_ASTERISK;
13556
13627
  var init_emphasis_guard = __esm(() => {
13628
+ init_code_segments();
13557
13629
  INTRA_WORD_UNDERSCORE = /(?<=[A-Za-z0-9])_(?=[A-Za-z0-9])/g;
13558
13630
  INTRA_WORD_ASTERISK = /(?<=[A-Za-z0-9])\*(?=[A-Za-z0-9])/g;
13559
13631
  BOUNDARY_FLANKED_ASTERISK = /(?<=^|\s)\*(?=\s|$)/g;
@@ -13639,6 +13711,7 @@ function guardAccidentalHeading(text) {
13639
13711
  }
13640
13712
  var ACCIDENTAL_BLOCKQUOTE, ACCIDENTAL_ORDERED_LIST, ACCIDENTAL_HEADING, ACCIDENTAL_HEADING_AFTER_MARKER;
13641
13713
  var init_line_start_guard = __esm(() => {
13714
+ init_code_segments();
13642
13715
  ACCIDENTAL_BLOCKQUOTE = /^>[0-9=]/;
13643
13716
  ACCIDENTAL_ORDERED_LIST = /^(\d{4,})([.)])(\s|$)/;
13644
13717
  ACCIDENTAL_HEADING = /^([ \t]{0,3})(#{1,6})(?=[^\s#])/;
@@ -13683,50 +13756,25 @@ function guardAccidentalInlinePairs(text) {
13683
13756
  }
13684
13757
  var TILDE_APPROX, MARK_OP, SPOILER_OP;
13685
13758
  var init_inline_pairs_guard = __esm(() => {
13759
+ init_code_segments();
13686
13760
  TILDE_APPROX = /(?<!\\)~(?=\$?\.?\d)/g;
13687
13761
  MARK_OP = /(?<=\w)==(?=\w)/g;
13688
13762
  SPOILER_OP = /(?<=\w)\|\|(?=\w)/g;
13689
13763
  });
13690
13764
 
13691
13765
  // render/unsupported-token-guard.ts
13692
- function toExpandableBlockquote(title, body) {
13693
- const lines = [];
13694
- const t = title.trim();
13695
- if (t)
13696
- lines.push(t);
13697
- for (const raw of body.split(`
13698
- `)) {
13699
- const line = raw.trimEnd();
13700
- if (line.trim() === "" && lines.length === 0)
13701
- continue;
13702
- lines.push(line);
13703
- }
13704
- while (lines.length > 0 && lines[lines.length - 1].trim() === "")
13705
- lines.pop();
13706
- if (lines.length === 0)
13707
- return "";
13708
- return lines.map((line, i) => i === 0 ? `**> ${line}` : `> ${line}`).join(`
13709
- `);
13710
- }
13711
13766
  function repairProse(text) {
13712
- let out = text;
13713
- out = out.replace(DETAILS_BLOCK, (_m, summary, body) => toExpandableBlockquote(summary ?? "", body ?? ""));
13714
- out = out.replace(ORPHAN_TAGS, "");
13715
- out = out.replace(CARET_PAIR, (_m, inner) => inner);
13716
- out = out.replace(FOOTNOTE_MARKER, "");
13717
- return out;
13767
+ return text.replace(CARET_PAIR, (_m, inner) => inner);
13718
13768
  }
13719
13769
  function guardUnsupportedTokens(text) {
13720
- if (!/[\^]|<details|<\/details|<summary/i.test(text))
13770
+ if (!text.includes("^"))
13721
13771
  return text;
13722
13772
  return splitProtectedSegments(text).map((seg) => seg.code ? seg.text : repairProse(seg.text)).join("");
13723
13773
  }
13724
- var CARET_PAIR, FOOTNOTE_MARKER, DETAILS_BLOCK, ORPHAN_TAGS;
13774
+ var CARET_PAIR;
13725
13775
  var init_unsupported_token_guard = __esm(() => {
13776
+ init_code_segments();
13726
13777
  CARET_PAIR = /\^([A-Za-z0-9]+)\^/g;
13727
- FOOTNOTE_MARKER = /\[\^[A-Za-z0-9]{1,10}\](?!:)/g;
13728
- DETAILS_BLOCK = /<details[^>]*>\s*(?:<summary[^>]*>([\s\S]*?)<\/summary>)?([\s\S]*?)<\/details>/gi;
13729
- ORPHAN_TAGS = /<\/?(?:details|summary)[^>]*>/gi;
13730
13778
  });
13731
13779
 
13732
13780
  // rich-send.ts
@@ -13767,7 +13815,7 @@ var init_rich_send = __esm(() => {
13767
13815
  import_grammy = __toESM(require_mod2(), 1);
13768
13816
  });
13769
13817
 
13770
- // ../node_modules/.bun/@grammyjs+runner@2.0.3+061f65c8e99495c7/node_modules/@grammyjs/runner/out/mod.js
13818
+ // ../node_modules/.bun/@grammyjs+runner@2.0.3+a732625cbf2c154c/node_modules/@grammyjs/runner/out/mod.js
13771
13819
  var require_mod4 = __commonJS((exports) => {
13772
13820
  var __createBinding = exports && exports.__createBinding || (Object.create ? function(o, m, k, k2) {
13773
13821
  if (k2 === undefined)
@@ -22355,7 +22403,7 @@ var init_schema = __esm(() => {
22355
22403
  repos: exports_external.record(exports_external.string().regex(/^[a-z0-9][a-z0-9-]*$/, "Repo slug must be kebab-case ASCII: start with a lowercase letter or digit, contain only lowercase letters, digits, and hyphens"), exports_external.object({
22356
22404
  url: exports_external.string().min(1).describe("Git remote URL for the repo (e.g. 'git@github.com:org/repo.git' or " + "'https://github.com/org/repo.git'). Used verbatim for git clone."),
22357
22405
  branch_default: exports_external.string().optional().describe("Default branch to track (defaults to the remote's HEAD, typically 'main'). " + "The per-agent branch 'agent/<agentName>/main' fast-forwards to this branch " + "when the worktree is clean on session start.")
22358
- })).optional().describe("Repos this agent operates on. Switchroom provisions a dedicated worktree for each " + "repo at <agentDir>/work/<slug>/ on branch agent/<agentName>/main, backed by a " + "shared bare clone at ~/.switchroom/repos/<slug>.git. The worktree path is injected " + "into the agent's environment as SWITCHROOM_REPO_<SLUG_UPPER>. " + "Agents without this field continue to work unchanged."),
22406
+ })).optional().describe("Repos this agent operates on. Switchroom provisions a dedicated standing tree for " + "each repo at <agentDir>/work/<slug>/ on branch agent/<agentName>/main \u2014 an " + "independent clone (own refs/stash, hardlinked objects) seeded from a shared bare " + "clone at ~/.switchroom/repos/<slug>.git. The tree's path is injected " + "into the agent's environment as SWITCHROOM_REPO_<SLUG_UPPER>. " + "Agents without this field continue to work unchanged."),
22359
22407
  experimental: exports_external.object({
22360
22408
  legacy_pty: exports_external.boolean().optional().describe("Opt out of the default tmux supervisor (#725) and run the agent " + "under the legacy PTY supervisor instead. Default: false."),
22361
22409
  legacy_autoaccept_expect: exports_external.boolean().optional().describe("Opt the autoaccept gateway back into the legacy expect-script " + "behaviour instead of the tmux send-keys path. Default: false.")
@@ -24113,7 +24161,7 @@ var init_approval_card = __esm(() => {
24113
24161
  });
24114
24162
 
24115
24163
  // flood-429-ledger.ts
24116
- import { readFileSync as readFileSync15, writeFileSync as writeFileSync13, mkdirSync as mkdirSync17, chmodSync as chmodSync4, unlinkSync as unlinkSync9 } from "node:fs";
24164
+ import { readFileSync as readFileSync15, writeFileSync as writeFileSync14, mkdirSync as mkdirSync17, chmodSync as chmodSync4, unlinkSync as unlinkSync10 } from "node:fs";
24117
24165
  import { dirname as dirname9, join as join20 } from "node:path";
24118
24166
  function flood429LedgerPathFromFloodState(floodStatePath) {
24119
24167
  return join20(dirname9(floodStatePath), FLOOD_429_LEDGER_FILE);
@@ -24217,7 +24265,7 @@ function writeFlood429Ledger(path2, episodes, log = (l) => process.stderr.write(
24217
24265
  mkdirSync17(dirname9(path2), { recursive: true });
24218
24266
  } catch {}
24219
24267
  try {
24220
- writeFileSync13(path2, payload, { mode: FLOOD_429_LEDGER_MODE });
24268
+ writeFileSync14(path2, payload, { mode: FLOOD_429_LEDGER_MODE });
24221
24269
  try {
24222
24270
  chmodSync4(path2, FLOOD_429_LEDGER_MODE);
24223
24271
  } catch {}
@@ -24230,8 +24278,8 @@ function writeFlood429Ledger(path2, episodes, log = (l) => process.stderr.write(
24230
24278
  return;
24231
24279
  }
24232
24280
  try {
24233
- unlinkSync9(path2);
24234
- writeFileSync13(path2, payload, { mode: FLOOD_429_LEDGER_MODE });
24281
+ unlinkSync10(path2);
24282
+ writeFileSync14(path2, payload, { mode: FLOOD_429_LEDGER_MODE });
24235
24283
  } catch (err2) {
24236
24284
  log(`telegram gateway: 429-ledger: cannot persist the 429 pressure ledger to ${path2} ` + `(${code2}, recreate failed: ${err2?.message ?? String(err2)}). ` + `Flood-pressure history will be missing from \`switchroom doctor\`
24237
24285
  `);
@@ -24253,11 +24301,11 @@ var init_flood_429_ledger = __esm(() => {
24253
24301
  import {
24254
24302
  existsSync as existsSync14,
24255
24303
  readFileSync as readFileSync16,
24256
- writeFileSync as writeFileSync14,
24304
+ writeFileSync as writeFileSync15,
24257
24305
  mkdirSync as mkdirSync18,
24258
24306
  chmodSync as chmodSync5,
24259
- unlinkSync as unlinkSync10,
24260
- renameSync as renameSync10
24307
+ unlinkSync as unlinkSync11,
24308
+ renameSync as renameSync11
24261
24309
  } from "node:fs";
24262
24310
  import { dirname as dirname10, join as join21 } from "node:path";
24263
24311
  function floodStatePath(stateDir) {
@@ -24313,7 +24361,7 @@ function writeFloodState(path2, state, log = (l) => process.stderr.write(l)) {
24313
24361
  mkdirSync18(dirname10(path2), { recursive: true });
24314
24362
  } catch {}
24315
24363
  try {
24316
- writeFileSync14(path2, payload, { mode: FLOOD_STATE_MODE });
24364
+ writeFileSync15(path2, payload, { mode: FLOOD_STATE_MODE });
24317
24365
  try {
24318
24366
  chmodSync5(path2, FLOOD_STATE_MODE);
24319
24367
  } catch {}
@@ -24326,8 +24374,8 @@ function writeFloodState(path2, state, log = (l) => process.stderr.write(l)) {
24326
24374
  return;
24327
24375
  }
24328
24376
  try {
24329
- unlinkSync10(path2);
24330
- writeFileSync14(path2, payload, { mode: FLOOD_STATE_MODE });
24377
+ unlinkSync11(path2);
24378
+ writeFileSync15(path2, payload, { mode: FLOOD_STATE_MODE });
24331
24379
  log(`telegram gateway: flood-breaker: recreated ${path2} \u2014 it was owned by another uid ` + `and could not be updated (${code2}); the breaker was blind (issue #3106)
24332
24380
  `);
24333
24381
  } catch (err2) {
@@ -30636,7 +30684,7 @@ var init_turn_flush_suppression = () => {};
30636
30684
 
30637
30685
  // ../src/agents/generation-stamp.ts
30638
30686
  import { createHash as createHash6 } from "node:crypto";
30639
- import { existsSync as existsSync36, readFileSync as readFileSync35, writeFileSync as writeFileSync30 } from "node:fs";
30687
+ import { existsSync as existsSync36, readFileSync as readFileSync35, writeFileSync as writeFileSync31 } from "node:fs";
30640
30688
  import { join as join44 } from "node:path";
30641
30689
  function sha256Text(s) {
30642
30690
  return createHash6("sha256").update(s, "utf-8").digest("hex");
@@ -36473,7 +36521,7 @@ function renderAuthLine(state7, agentName3, now = Date.now()) {
36473
36521
  }
36474
36522
 
36475
36523
  // gateway/quota-cache.ts
36476
- import { existsSync as existsSync49, readFileSync as readFileSync49, writeFileSync as writeFileSync40, mkdirSync as mkdirSync42 } from "fs";
36524
+ import { existsSync as existsSync49, readFileSync as readFileSync49, writeFileSync as writeFileSync41, mkdirSync as mkdirSync42 } from "fs";
36477
36525
  import { join as join59, dirname as dirname25 } from "path";
36478
36526
  function defaultCachePath() {
36479
36527
  return process.env.SWITCHROOM_QUOTA_CACHE_PATH ?? join59(process.env.HOME ?? "/tmp", ".switchroom", "quota-cache.json");
@@ -36512,7 +36560,7 @@ function writeQuotaCache(result, opts = {}) {
36512
36560
  };
36513
36561
  try {
36514
36562
  mkdirSync42(dirname25(path3), { recursive: true });
36515
- writeFileSync40(path3, JSON.stringify(entry, null, 2), { mode: 384 });
36563
+ writeFileSync41(path3, JSON.stringify(entry, null, 2), { mode: 384 });
36516
36564
  } catch {}
36517
36565
  }
36518
36566
  var DEFAULT_TTL_MS4, RATE_LIMIT_TTL_MS;
@@ -37383,7 +37431,7 @@ var init_boot_probes = __esm(() => {
37383
37431
  });
37384
37432
 
37385
37433
  // gateway/boot-issue-cache.ts
37386
- import { existsSync as existsSync51, readFileSync as readFileSync51, writeFileSync as writeFileSync41, mkdirSync as mkdirSync43, renameSync as renameSync24 } from "fs";
37434
+ import { existsSync as existsSync51, readFileSync as readFileSync51, writeFileSync as writeFileSync42, mkdirSync as mkdirSync43, renameSync as renameSync25 } from "fs";
37387
37435
  import { dirname as dirname26 } from "path";
37388
37436
  function fingerprintProbe(key, r) {
37389
37437
  if (r.status === "ok")
@@ -37476,7 +37524,7 @@ function loadCache(path3, now = Date.now) {
37476
37524
  parsed = JSON.parse(raw);
37477
37525
  } catch {
37478
37526
  try {
37479
- renameSync24(path3, `${path3}.corrupt-${now()}`);
37527
+ renameSync25(path3, `${path3}.corrupt-${now()}`);
37480
37528
  } catch {}
37481
37529
  return { ...EMPTY_CACHE, probes: {} };
37482
37530
  }
@@ -37512,8 +37560,8 @@ function applyAndSave(path3, cache, diff) {
37512
37560
  try {
37513
37561
  mkdirSync43(dirname26(path3), { recursive: true });
37514
37562
  const tmp = `${path3}.tmp`;
37515
- writeFileSync41(tmp, JSON.stringify(next), { mode: 384 });
37516
- renameSync24(tmp, path3);
37563
+ writeFileSync42(tmp, JSON.stringify(next), { mode: 384 });
37564
+ renameSync25(tmp, path3);
37517
37565
  } catch {}
37518
37566
  return next;
37519
37567
  }
@@ -37526,7 +37574,7 @@ var init_boot_issue_cache = __esm(() => {
37526
37574
 
37527
37575
  // gateway/config-snapshot.ts
37528
37576
  import { createHash as createHash7 } from "crypto";
37529
- import { existsSync as existsSync52, readFileSync as readFileSync52, writeFileSync as writeFileSync42, mkdirSync as mkdirSync44, renameSync as renameSync25 } from "fs";
37577
+ import { existsSync as existsSync52, readFileSync as readFileSync52, writeFileSync as writeFileSync43, mkdirSync as mkdirSync44, renameSync as renameSync26 } from "fs";
37530
37578
  import { dirname as dirname27 } from "path";
37531
37579
  function hashStringArray(items) {
37532
37580
  if (!items || items.length === 0)
@@ -37604,7 +37652,7 @@ function loadSnapshot(path3, now = Date.now) {
37604
37652
  parsed = JSON.parse(raw);
37605
37653
  } catch {
37606
37654
  try {
37607
- renameSync25(path3, `${path3}.corrupt-${now()}`);
37655
+ renameSync26(path3, `${path3}.corrupt-${now()}`);
37608
37656
  } catch {}
37609
37657
  return null;
37610
37658
  }
@@ -37627,8 +37675,8 @@ function persistSnapshot(path3, snapshot) {
37627
37675
  try {
37628
37676
  mkdirSync44(dirname27(path3), { recursive: true });
37629
37677
  const tmp = `${path3}.tmp`;
37630
- writeFileSync42(tmp, JSON.stringify(snapshot), { mode: 384 });
37631
- renameSync25(tmp, path3);
37678
+ writeFileSync43(tmp, JSON.stringify(snapshot), { mode: 384 });
37679
+ renameSync26(tmp, path3);
37632
37680
  } catch {}
37633
37681
  }
37634
37682
  var init_config_snapshot = __esm(() => {
@@ -37636,7 +37684,7 @@ var init_config_snapshot = __esm(() => {
37636
37684
  });
37637
37685
 
37638
37686
  // gateway/boot-card-msgid.ts
37639
- import { readFileSync as readFileSync53, writeFileSync as writeFileSync43 } from "node:fs";
37687
+ import { readFileSync as readFileSync53, writeFileSync as writeFileSync44 } from "node:fs";
37640
37688
  function bootCardChatKey(chatId, threadId) {
37641
37689
  return `${chatId}:${threadId ?? ""}`;
37642
37690
  }
@@ -37661,7 +37709,7 @@ function saveBootCardMsgId(path3, chatKey3, messageId) {
37661
37709
  if (store3[chatKey3] === messageId)
37662
37710
  return;
37663
37711
  store3[chatKey3] = messageId;
37664
- writeFileSync43(path3, JSON.stringify(store3), "utf8");
37712
+ writeFileSync44(path3, JSON.stringify(store3), "utf8");
37665
37713
  } catch {}
37666
37714
  }
37667
37715
  var init_boot_card_msgid = () => {};
@@ -38695,7 +38743,7 @@ __export(exports_tmux2, {
38695
38743
  captureAgentPane: () => captureAgentPane2
38696
38744
  });
38697
38745
  import { execFileSync as execFileSync8 } from "node:child_process";
38698
- import { chmodSync as chmodSync13, mkdirSync as mkdirSync49, readdirSync as readdirSync17, statSync as statSync24, unlinkSync as unlinkSync30, writeFileSync as writeFileSync52 } from "node:fs";
38746
+ import { chmodSync as chmodSync13, mkdirSync as mkdirSync49, readdirSync as readdirSync18, statSync as statSync24, unlinkSync as unlinkSync32, writeFileSync as writeFileSync54 } from "node:fs";
38699
38747
  import { resolve as resolve12 } from "node:path";
38700
38748
  function captureAgentPane2(opts) {
38701
38749
  const { agentName: agentName3, agentDir, reason } = opts;
@@ -38746,7 +38794,7 @@ function captureAgentPane2(opts) {
38746
38794
  ` + `
38747
38795
  `;
38748
38796
  try {
38749
- writeFileSync52(outPath, Buffer.concat([Buffer.from(header, "utf8"), body]), {
38797
+ writeFileSync54(outPath, Buffer.concat([Buffer.from(header, "utf8"), body]), {
38750
38798
  mode: 384
38751
38799
  });
38752
38800
  } catch (err) {
@@ -38816,7 +38864,7 @@ function sleepSync3(ms) {
38816
38864
  function pruneOldReports2(dir, retain) {
38817
38865
  let entries;
38818
38866
  try {
38819
- entries = readdirSync17(dir);
38867
+ entries = readdirSync18(dir);
38820
38868
  } catch {
38821
38869
  return;
38822
38870
  }
@@ -38830,7 +38878,7 @@ function pruneOldReports2(dir, retain) {
38830
38878
  }).sort((a, b) => b.mtimeMs - a.mtimeMs);
38831
38879
  for (const stale of files.slice(retain)) {
38832
38880
  try {
38833
- unlinkSync30(stale.full);
38881
+ unlinkSync32(stale.full);
38834
38882
  } catch {}
38835
38883
  }
38836
38884
  }
@@ -39640,7 +39688,7 @@ __export(exports_materialize_bot_token, {
39640
39688
  materializeBotToken: () => materializeBotToken,
39641
39689
  BotTokenMaterializeError: () => BotTokenMaterializeError
39642
39690
  });
39643
- import { existsSync as existsSync63 } from "node:fs";
39691
+ import { existsSync as existsSync64 } from "node:fs";
39644
39692
  function pickConfiguredToken(config, agentName3) {
39645
39693
  if (agentName3) {
39646
39694
  const agent = config.agents?.[agentName3];
@@ -39654,7 +39702,7 @@ function tryDirectVaultRead4(ref, config, passphrase) {
39654
39702
  if (!passphrase)
39655
39703
  return null;
39656
39704
  const vaultPath = resolvePath(config.vault?.path ?? "~/.switchroom/vault.enc");
39657
- if (!existsSync63(vaultPath))
39705
+ if (!existsSync64(vaultPath))
39658
39706
  return null;
39659
39707
  try {
39660
39708
  const secrets = openVault(passphrase, vaultPath);
@@ -39809,19 +39857,19 @@ var import_runner3 = __toESM(require_mod3(), 1);
39809
39857
  import { randomBytes as randomBytes12, createHash as createHash8 } from "crypto";
39810
39858
  import { execFileSync as execFileSync9, execSync as execSync2, spawn as spawn2 } from "child_process";
39811
39859
  import {
39812
- readFileSync as readFileSync66,
39813
- writeFileSync as writeFileSync53,
39860
+ readFileSync as readFileSync67,
39861
+ writeFileSync as writeFileSync55,
39814
39862
  mkdirSync as mkdirSync50,
39815
- readdirSync as readdirSync18,
39863
+ readdirSync as readdirSync19,
39816
39864
  rmSync as rmSync9,
39817
39865
  statSync as statSync25,
39818
- renameSync as renameSync30,
39866
+ renameSync as renameSync32,
39819
39867
  realpathSync as realpathSync6,
39820
39868
  chmodSync as chmodSync14,
39821
39869
  openSync as openSync18,
39822
39870
  closeSync as closeSync18,
39823
- existsSync as existsSync64,
39824
- unlinkSync as unlinkSync31,
39871
+ existsSync as existsSync65,
39872
+ unlinkSync as unlinkSync33,
39825
39873
  appendFileSync as appendFileSync11
39826
39874
  } from "fs";
39827
39875
 
@@ -39839,7 +39887,7 @@ function fsyncPathSync(path) {
39839
39887
 
39840
39888
  // gateway/gateway.ts
39841
39889
  import { homedir as homedir22 } from "os";
39842
- import { join as join76, sep as sep6, basename as basename18 } from "path";
39890
+ import { join as join77, sep as sep6, basename as basename19 } from "path";
39843
39891
 
39844
39892
  // plugin-logger.ts
39845
39893
  import { appendFileSync, mkdirSync, renameSync as renameSync2, statSync, existsSync } from "fs";
@@ -50974,7 +51022,7 @@ function createSweepableCardStore(deps) {
50974
51022
  init_rich_send();
50975
51023
  var import_grammy4 = __toESM(require_mod2(), 1);
50976
51024
  import { execFileSync as execFileSync3 } from "child_process";
50977
- import { mkdirSync as mkdirSync15, writeFileSync as writeFileSync10 } from "fs";
51025
+ import { mkdirSync as mkdirSync15, writeFileSync as writeFileSync11 } from "fs";
50978
51026
  import { dirname as dirname7 } from "path";
50979
51027
  init_client2();
50980
51028
 
@@ -51754,11 +51802,15 @@ import {
51754
51802
  mkdirSync as mkdirSync14,
51755
51803
  openSync as openSync8,
51756
51804
  readFileSync as readFileSync13,
51805
+ renameSync as renameSync10,
51806
+ unlinkSync as unlinkSync6,
51807
+ writeFileSync as writeFileSync10,
51757
51808
  writeSync as writeSync7
51758
51809
  } from "node:fs";
51759
51810
  import { join as join15 } from "node:path";
51760
51811
  import { randomUUID as randomUUID4 } from "node:crypto";
51761
51812
  var EVAL_CASE_PROPOSALS_FILE = "eval-case-proposals.jsonl";
51813
+ var MAX_EVAL_CASE_PROPOSALS = 200;
51762
51814
  function proposalsPath2(stateDir) {
51763
51815
  return join15(stateDir, EVAL_CASE_PROPOSALS_FILE);
51764
51816
  }
@@ -51801,6 +51853,49 @@ function readEvalCaseProposals(stateDir) {
51801
51853
  }
51802
51854
  return [...byId.values()];
51803
51855
  }
51856
+ function withinBound(all, now) {
51857
+ const isLiveRejection = (r) => {
51858
+ if (r.status !== "rejected")
51859
+ return false;
51860
+ const age = now - new Date(r.created_at).getTime();
51861
+ return !Number.isFinite(age) || age <= REJECTION_TTL_MS;
51862
+ };
51863
+ const keepTail = (rows) => rows.length > MAX_EVAL_CASE_PROPOSALS ? rows.slice(rows.length - MAX_EVAL_CASE_PROPOSALS) : rows;
51864
+ const keep = new Set([
51865
+ ...keepTail(all.filter(isLiveRejection)).map((r) => r.id),
51866
+ ...keepTail(all.filter((r) => !isLiveRejection(r))).map((r) => r.id)
51867
+ ]);
51868
+ return all.filter((r) => keep.has(r.id));
51869
+ }
51870
+ function compactIfOversized(stateDir, now) {
51871
+ const path = proposalsPath2(stateDir);
51872
+ let raw;
51873
+ try {
51874
+ raw = readFileSync13(path, "utf-8");
51875
+ } catch {
51876
+ return;
51877
+ }
51878
+ const lines = raw.split(`
51879
+ `).filter((l) => l.trim().length > 0);
51880
+ if (lines.length <= MAX_EVAL_CASE_PROPOSALS * 2)
51881
+ return;
51882
+ const kept = withinBound(readEvalCaseProposals(stateDir), now);
51883
+ if (kept.length >= lines.length)
51884
+ return;
51885
+ const tmp = `${path}.tmp.${process.pid}`;
51886
+ try {
51887
+ writeFileSync10(tmp, kept.map((r) => JSON.stringify(r) + `
51888
+ `).join(""), {
51889
+ encoding: "utf-8",
51890
+ mode: 420
51891
+ });
51892
+ renameSync10(tmp, path);
51893
+ } catch {
51894
+ try {
51895
+ unlinkSync6(tmp);
51896
+ } catch {}
51897
+ }
51898
+ }
51804
51899
  function getEvalCaseProposal(stateDir, id) {
51805
51900
  return readEvalCaseProposals(stateDir).find((p) => p.id === id);
51806
51901
  }
@@ -51814,6 +51909,7 @@ function enqueueEvalCaseProposal(stateDir, input, opts = {}) {
51814
51909
  ...input
51815
51910
  };
51816
51911
  appendLine2(proposalsPath2(stateDir), proposal);
51912
+ compactIfOversized(stateDir, now());
51817
51913
  return proposal;
51818
51914
  }
51819
51915
  function setEvalCaseProposalStatus(stateDir, id, status) {
@@ -51822,8 +51918,94 @@ function setEvalCaseProposalStatus(stateDir, id, status) {
51822
51918
  return;
51823
51919
  const next = { ...cur, status };
51824
51920
  appendLine2(proposalsPath2(stateDir), next);
51921
+ compactIfOversized(stateDir, Date.now());
51825
51922
  return next;
51826
51923
  }
51924
+
51925
+ // gateway/eval-case-proposal-inbound-builders.ts
51926
+ function commonMeta(opts) {
51927
+ return {
51928
+ agent: opts.ctx.agent,
51929
+ ...opts.ctx.threadId != null ? { message_thread_id: String(opts.ctx.threadId) } : {},
51930
+ proposal_id: opts.proposalId,
51931
+ skill_slug: opts.skillSlug,
51932
+ held_out: String(opts.heldOut),
51933
+ operator_id: opts.operatorId
51934
+ };
51935
+ }
51936
+ function buildEvalCaseAppliedInbound(opts) {
51937
+ const ts = opts.nowMs ?? Date.now();
51938
+ const sink2 = opts.heldOut ? "the held-out sink" : `\`${opts.skillSlug}\`'s \`evals.json\``;
51939
+ return {
51940
+ type: "inbound",
51941
+ chatId: opts.ctx.chat_id,
51942
+ ...opts.ctx.threadId != null ? { threadId: opts.ctx.threadId } : {},
51943
+ messageId: ts,
51944
+ user: "self-improve",
51945
+ userId: 0,
51946
+ ts,
51947
+ text: `\u2705 Operator approved your proposed eval case for \`${opts.skillSlug}\` ` + `(proposal ${opts.proposalId}). The case was applied DETERMINISTICALLY by ` + `the gateway and is already written to ${sink2} \u2014 do NOT write it yourself ` + `and do NOT re-propose it. Resume whatever you were doing.`,
51948
+ meta: {
51949
+ source: "eval_case_applied",
51950
+ ...commonMeta({
51951
+ ctx: opts.ctx,
51952
+ proposalId: opts.proposalId,
51953
+ skillSlug: opts.skillSlug,
51954
+ heldOut: opts.heldOut,
51955
+ operatorId: opts.operatorId
51956
+ })
51957
+ }
51958
+ };
51959
+ }
51960
+ function buildEvalCaseRejectedInbound(opts) {
51961
+ const ts = opts.nowMs ?? Date.now();
51962
+ return {
51963
+ type: "inbound",
51964
+ chatId: opts.ctx.chat_id,
51965
+ ...opts.ctx.threadId != null ? { threadId: opts.ctx.threadId } : {},
51966
+ messageId: ts,
51967
+ user: "self-improve",
51968
+ userId: 0,
51969
+ ts,
51970
+ text: `\uD83D\uDEAB Operator dismissed your proposed eval case for \`${opts.skillSlug}\` ` + `(proposal ${opts.proposalId}). NOTHING was written \u2014 no eval case was ` + `added. Carry on with the original task without it. Do NOT re-propose the ` + `same case without first asking the user.`,
51971
+ meta: {
51972
+ source: "eval_case_rejected",
51973
+ ...commonMeta({
51974
+ ctx: opts.ctx,
51975
+ proposalId: opts.proposalId,
51976
+ skillSlug: opts.skillSlug,
51977
+ heldOut: opts.heldOut,
51978
+ operatorId: opts.operatorId
51979
+ })
51980
+ }
51981
+ };
51982
+ }
51983
+ function buildEvalCaseApplyFailedInbound(opts) {
51984
+ const ts = opts.nowMs ?? Date.now();
51985
+ const tail = opts.applyOut.trim().slice(0, 500);
51986
+ return {
51987
+ type: "inbound",
51988
+ chatId: opts.ctx.chat_id,
51989
+ ...opts.ctx.threadId != null ? { threadId: opts.ctx.threadId } : {},
51990
+ messageId: ts,
51991
+ user: "self-improve",
51992
+ userId: 0,
51993
+ ts,
51994
+ text: `\u26a0\ufe0f The operator approved your proposed eval case for \`${opts.skillSlug}\` ` + `(proposal ${opts.proposalId}) but the applier FAILED. The case was NOT ` + `written \u2014 do NOT assume the regression test exists. Applier output:
51995
+ ` + `${tail.length > 0 ? tail : "(no output)"}
51996
+ ` + `Carry on with the original task; report the failure to the operator if it ` + `still matters.`,
51997
+ meta: {
51998
+ source: "eval_case_apply_failed",
51999
+ ...commonMeta({
52000
+ ctx: opts.ctx,
52001
+ proposalId: opts.proposalId,
52002
+ skillSlug: opts.skillSlug,
52003
+ heldOut: opts.heldOut,
52004
+ operatorId: opts.operatorId
52005
+ })
52006
+ }
52007
+ };
52008
+ }
51827
52009
  // gateway/callback-query-handlers.ts
51828
52010
  init_auth_snapshot_format();
51829
52011
 
@@ -52003,13 +52185,14 @@ var AgentSmokeRequestSchema = exports_external.object({
52003
52185
  deep: exports_external.boolean().optional()
52004
52186
  })
52005
52187
  });
52188
+ var CANONICAL_CONFIG_PATH = "/state/config/switchroom.yaml";
52006
52189
  var ConfigProposeEditRequestSchema = exports_external.object({
52007
52190
  ...RequestEnvelope,
52008
52191
  op: exports_external.literal("config_propose_edit"),
52009
52192
  args: exports_external.object({
52010
52193
  unified_diff: exports_external.string().min(1).max(MAX_FRAME_BYTES3 - 1024),
52011
52194
  reason: exports_external.string().min(1).max(500),
52012
- target_path: exports_external.literal("/state/config/switchroom.yaml")
52195
+ target_path: exports_external.literal(CANONICAL_CONFIG_PATH)
52013
52196
  })
52014
52197
  });
52015
52198
  var RequestSchema3 = exports_external.discriminatedUnion("op", [
@@ -52335,6 +52518,20 @@ function createCallbackQueryHandlers(deps) {
52335
52518
  const listViaBroker2 = deps.brokerList ?? listViaBroker;
52336
52519
  const listGrantsViaBroker2 = deps.brokerListGrants ?? listGrantsViaBroker;
52337
52520
  const vaultTokenFilePath2 = deps.brokerVaultTokenFilePath ?? vaultTokenFilePath;
52521
+ const runEvalCaseApply = deps.runEvalCaseApply ?? ((id) => {
52522
+ const cli = process.env.SWITCHROOM_CLI_PATH ?? "switchroom";
52523
+ try {
52524
+ const out = execFileSync3(cli, ["self-improve", "apply-eval-case", "--id", id], { encoding: "utf8", timeout: 15000, env: process.env }).trim();
52525
+ return { ok: true, out };
52526
+ } catch (err) {
52527
+ const e = err;
52528
+ return {
52529
+ ok: false,
52530
+ out: [e.stdout, e.stderr, e.message].filter(Boolean).join(`
52531
+ `).trim()
52532
+ };
52533
+ }
52534
+ });
52338
52535
  async function handleVaultRecentDenialCallback(ctx, data) {
52339
52536
  const senderId = String(ctx.from?.id ?? "");
52340
52537
  const access = loadAccess();
@@ -52375,7 +52572,7 @@ function createCallbackQueryHandlers(deps) {
52375
52572
  const tokenPath = vaultTokenFilePath2(agentName);
52376
52573
  try {
52377
52574
  mkdirSync15(dirname7(tokenPath), { recursive: true });
52378
- writeFileSync10(tokenPath, token, { mode: 384 });
52575
+ writeFileSync11(tokenPath, token, { mode: 384 });
52379
52576
  } catch (err) {
52380
52577
  await switchroomReply(ctx, `**Grant created (${escapeHtmlForTg2(id)}) but token write failed:** ` + `${escapeHtmlForTg2(String(err))}
52381
52578
  ` + `_Recover with: \`switchroom vault grant ${escapeHtmlForTg2(agentName)} ` + `--keys ${escapeHtmlForTg2(keyName)} --duration 30d\` on the host._`, { html: true });
@@ -52527,7 +52724,7 @@ function createCallbackQueryHandlers(deps) {
52527
52724
  const tokenPath = vaultTokenFilePath2(pending.agent);
52528
52725
  try {
52529
52726
  mkdirSync15(dirname7(tokenPath), { recursive: true });
52530
- writeFileSync10(tokenPath, token, { mode: 384 });
52727
+ writeFileSync11(tokenPath, token, { mode: 384 });
52531
52728
  } catch (err) {
52532
52729
  await switchroomReply(ctx, `**Grant created (${escapeHtmlForTg2(id)}) but token write failed:** ` + `${escapeHtmlForTg2(String(err))}
52533
52730
  ` + `_Recover with: \`switchroom vault grant ${escapeHtmlForTg2(pending.agent)} ` + `--keys ${escapeHtmlForTg2(pending.key)} --duration ${Math.round(pending.ttl_seconds / 86400)}d\` on the host._`, { html: true });
@@ -52668,36 +52865,57 @@ _Approver verified by Telegram identity \u2014 broker auto-unlocked at startup._
52668
52865
  }
52669
52866
  return;
52670
52867
  }
52868
+ const cbChatId = String(ctx.chat?.id ?? ctx.from?.id ?? "");
52869
+ const cbThreadId = resolveThreadId(cbChatId, ctx.callbackQuery?.message?.message_thread_id);
52870
+ const inboundCtx = {
52871
+ agent,
52872
+ chat_id: cbChatId,
52873
+ ...cbThreadId != null ? { threadId: cbThreadId } : {}
52874
+ };
52671
52875
  if (parsed.action === "deny") {
52672
52876
  setEvalCaseProposalStatus(stateDir, parsed.id, "rejected");
52877
+ const denied = deliverResumeSyntheticOrBuffer(agent, buildEvalCaseRejectedInbound({
52878
+ ctx: inboundCtx,
52879
+ proposalId: proposal.id,
52880
+ skillSlug: proposal.skill_slug,
52881
+ heldOut: proposal.held_out,
52882
+ operatorId: senderId
52883
+ }));
52673
52884
  await ctx.answerCallbackQuery({ text: "\uD83D\uDEAB Dismissed." }).catch(() => {});
52674
52885
  if (ctx.callbackQuery?.message && "text" in ctx.callbackQuery.message) {
52675
52886
  await ctx.editMessageText(`${escapeHtmlForTg2(ctx.callbackQuery.message.text ?? "")}
52676
52887
 
52677
52888
  \uD83D\uDEAB <i>Dismissed.</i>`, { parse_mode: "HTML", reply_markup: { inline_keyboard: [] } }).catch(() => {});
52678
52889
  }
52890
+ process.stderr.write(`telegram gateway: eval_case_rejected agent=${agent} proposal=${proposal.id} ` + `slug=${proposal.skill_slug} delivered=${denied}
52891
+ `);
52679
52892
  return;
52680
52893
  }
52681
52894
  setEvalCaseProposalStatus(stateDir, parsed.id, "approved");
52682
52895
  await ctx.answerCallbackQuery({ text: "\u2705 Adding the eval case\u2026" }).catch(() => {});
52683
- const cli = process.env.SWITCHROOM_CLI_PATH ?? "switchroom";
52684
- let applyOk = true;
52685
- let applyOut = "";
52686
- try {
52687
- applyOut = execFileSync3(cli, ["self-improve", "apply-eval-case", "--id", parsed.id], { encoding: "utf8", timeout: 15000, env: process.env }).trim();
52688
- } catch (err) {
52689
- applyOk = false;
52690
- const e = err;
52691
- applyOut = [e.stdout, e.stderr, e.message].filter(Boolean).join(`
52692
- `).trim();
52693
- }
52896
+ const { ok: applyOk, out: applyOut } = runEvalCaseApply(parsed.id);
52694
52897
  const footer = applyOk ? "\u2705 <i>Added as a regression test.</i>" : `\u26a0\ufe0f <i>Apply failed:</i> ${escapeHtmlForTg2(applyOut.slice(0, 200))}`;
52695
52898
  if (ctx.callbackQuery?.message && "text" in ctx.callbackQuery.message) {
52696
52899
  await ctx.editMessageText(`${escapeHtmlForTg2(ctx.callbackQuery.message.text ?? "")}
52697
52900
 
52698
52901
  ${footer}`, { parse_mode: "HTML", reply_markup: { inline_keyboard: [] } }).catch(() => {});
52699
52902
  }
52700
- process.stderr.write(`telegram gateway: eval_case_apply agent=${agent} proposal=${proposal.id} ` + `slug=${proposal.skill_slug} ok=${applyOk}
52903
+ const outcomeInbound = applyOk ? buildEvalCaseAppliedInbound({
52904
+ ctx: inboundCtx,
52905
+ proposalId: proposal.id,
52906
+ skillSlug: proposal.skill_slug,
52907
+ heldOut: proposal.held_out,
52908
+ operatorId: senderId
52909
+ }) : buildEvalCaseApplyFailedInbound({
52910
+ ctx: inboundCtx,
52911
+ proposalId: proposal.id,
52912
+ skillSlug: proposal.skill_slug,
52913
+ heldOut: proposal.held_out,
52914
+ operatorId: senderId,
52915
+ applyOut
52916
+ });
52917
+ const delivered = deliverResumeSyntheticOrBuffer(agent, outcomeInbound);
52918
+ process.stderr.write(`telegram gateway: eval_case_apply agent=${agent} proposal=${proposal.id} ` + `slug=${proposal.skill_slug} ok=${applyOk} delivered=${delivered}
52701
52919
  `);
52702
52920
  }
52703
52921
  async function handleMentalModelProposeCallback(ctx, data) {
@@ -53421,7 +53639,7 @@ ${keyList}`,
53421
53639
  const tokenPath = vaultTokenFilePath2(state.agent);
53422
53640
  try {
53423
53641
  mkdirSync15(dirname7(tokenPath), { recursive: true });
53424
- writeFileSync10(tokenPath, token, { mode: 384 });
53642
+ writeFileSync11(tokenPath, token, { mode: 384 });
53425
53643
  } catch (err) {
53426
53644
  await switchroomReply(ctx, `**Grant created but token write failed:** ${escapeHtmlForTg2(String(err))}`, { html: true });
53427
53645
  return;
@@ -54480,7 +54698,7 @@ function hangStalenessMs(env = process.env) {
54480
54698
 
54481
54699
  // gateway/missed-approvals-store.ts
54482
54700
  init_state_owner();
54483
- import { unlinkSync as unlinkSync6 } from "node:fs";
54701
+ import { unlinkSync as unlinkSync7 } from "node:fs";
54484
54702
  import { join as join17 } from "node:path";
54485
54703
  var MAX_PENDING = 50;
54486
54704
  var MAX_DELIVERED = 20;
@@ -54565,7 +54783,7 @@ function createMissedApprovalsStore(stateDir, log = (l) => process.stderr.write(
54565
54783
  },
54566
54784
  clear() {
54567
54785
  try {
54568
- unlinkSync6(filePath);
54786
+ unlinkSync7(filePath);
54569
54787
  } catch {}
54570
54788
  }
54571
54789
  };
@@ -54573,7 +54791,7 @@ function createMissedApprovalsStore(stateDir, log = (l) => process.stderr.write(
54573
54791
 
54574
54792
  // gateway/always-allow-persist-queue.ts
54575
54793
  init_state_owner();
54576
- import { unlinkSync as unlinkSync7 } from "node:fs";
54794
+ import { unlinkSync as unlinkSync8 } from "node:fs";
54577
54795
  import { join as join18 } from "node:path";
54578
54796
  var MAX_ATTEMPTS = 5;
54579
54797
  var MAX_AGE_MS = 24 * 60 * 60 * 1000;
@@ -54710,7 +54928,7 @@ function createAlwaysAllowPersistQueue(stateDir, writeFileSyncFn = atomicWriteSe
54710
54928
  },
54711
54929
  clear() {
54712
54930
  try {
54713
- unlinkSync7(filePath);
54931
+ unlinkSync8(filePath);
54714
54932
  } catch {}
54715
54933
  }
54716
54934
  };
@@ -54873,7 +55091,7 @@ function pickRecoveredPermissionOrigin(recentTurns, now, maxAgeMs) {
54873
55091
  }
54874
55092
 
54875
55093
  // gateway/approval-hold.ts
54876
- import { mkdirSync as mkdirSync16, writeFileSync as writeFileSync12, readFileSync as readFileSync14, unlinkSync as unlinkSync8, chmodSync as chmodSync3, lstatSync as lstatSync2 } from "node:fs";
55094
+ import { mkdirSync as mkdirSync16, writeFileSync as writeFileSync13, readFileSync as readFileSync14, unlinkSync as unlinkSync9, chmodSync as chmodSync3, lstatSync as lstatSync2 } from "node:fs";
54877
55095
  import { join as join19, dirname as dirname8 } from "node:path";
54878
55096
  var BLOCKED_APPROVAL_FILE_MODE = 420;
54879
55097
  var BLOCKED_APPROVAL_DIR_MODE = 1023;
@@ -54902,7 +55120,8 @@ var ACTION_SAFE_WITH_INPUT2 = new Set([
54902
55120
  function safeActionForRecord(naturalAction2, toolName, inputPreview) {
54903
55121
  return ACTION_SAFE_WITH_INPUT2.has(toolName) ? naturalAction2(toolName, inputPreview) : naturalAction2(toolName, undefined);
54904
55122
  }
54905
- function createBlockedApprovalStore(dir, agent, fallbackDir) {
55123
+ function createBlockedApprovalStore(dir, agent, fallbackDir, deps = {}) {
55124
+ const write_ = deps.writeFileSync ?? writeFileSync13;
54906
55125
  const primary = join19(dir, `${agent}.json`);
54907
55126
  const fallback = fallbackDir != null ? join19(fallbackDir, "blocked-approval.json") : null;
54908
55127
  let active = primary;
@@ -54919,7 +55138,7 @@ function createBlockedApprovalStore(dir, agent, fallbackDir) {
54919
55138
  chmodSync3(parent, dirMode);
54920
55139
  } catch {}
54921
55140
  }
54922
- writeFileSync12(target, body, { encoding: "utf-8", mode: BLOCKED_APPROVAL_FILE_MODE });
55141
+ write_(target, body, { encoding: "utf-8", mode: BLOCKED_APPROVAL_FILE_MODE });
54923
55142
  chmodSync3(target, BLOCKED_APPROVAL_FILE_MODE);
54924
55143
  return true;
54925
55144
  } catch {
@@ -54937,7 +55156,7 @@ function createBlockedApprovalStore(dir, agent, fallbackDir) {
54937
55156
  active = primary;
54938
55157
  if (fallback != null) {
54939
55158
  try {
54940
- unlinkSync8(fallback);
55159
+ unlinkSync9(fallback);
54941
55160
  } catch {}
54942
55161
  }
54943
55162
  return;
@@ -54956,7 +55175,7 @@ function createBlockedApprovalStore(dir, agent, fallbackDir) {
54956
55175
  if (p == null)
54957
55176
  continue;
54958
55177
  try {
54959
- unlinkSync8(p);
55178
+ unlinkSync9(p);
54960
55179
  } catch {}
54961
55180
  }
54962
55181
  active = primary;
@@ -64799,6 +65018,11 @@ function slice(source, node2) {
64799
65018
  return source.slice(start, end);
64800
65019
  }
64801
65020
  var EXPANDABLE_MARKER_RE = /^\*\*>/;
65021
+ var TG_INLINE_ENTITY_HREFS = ["tg://emoji", "tg://time"];
65022
+ function isTgInlineEntityHref(href) {
65023
+ const h = href.toLowerCase();
65024
+ return TG_INLINE_ENTITY_HREFS.some((base) => h === base || h.startsWith(`${base}?`));
65025
+ }
64802
65026
  function markExpandableQuotes(markdown) {
64803
65027
  const expandableLineStarts = new Set;
64804
65028
  let out = "";
@@ -64850,6 +65074,14 @@ function foldInline(node2, source) {
64850
65074
  children: foldInlineChildren(node2, source),
64851
65075
  ...pos(node2)
64852
65076
  };
65077
+ case "image": {
65078
+ if (isTgInlineEntityHref(node2.url)) {
65079
+ return { type: "tg-entity", label: node2.alt ?? "", href: node2.url, ...pos(node2) };
65080
+ }
65081
+ return { type: "plain", text: slice(source, node2), ...pos(node2) };
65082
+ }
65083
+ case "footnoteReference":
65084
+ return { type: "raw", text: slice(source, node2), ...pos(node2) };
64853
65085
  default:
64854
65086
  return { type: "plain", text: slice(source, node2), ...pos(node2) };
64855
65087
  }
@@ -64965,6 +65197,12 @@ function foldBlock(node2, source, expandableLineStarts) {
64965
65197
  ...pos(node2)
64966
65198
  };
64967
65199
  }
65200
+ case "footnoteDefinition":
65201
+ return {
65202
+ type: "paragraph",
65203
+ children: [{ type: "raw", text: slice(source, node2), ...pos(node2) }],
65204
+ ...pos(node2)
65205
+ };
64968
65206
  default:
64969
65207
  return {
64970
65208
  type: "paragraph",
@@ -64986,6 +65224,9 @@ function parse2(markdown) {
64986
65224
 
64987
65225
  // render/render.ts
64988
65226
  init_format();
65227
+ function collapseLabelBreaks(label) {
65228
+ return label.replace(/[ \t]*\r?\n[ \t\r\n]*/g, " ");
65229
+ }
64989
65230
  function renderInline(node2, ctx = {}) {
64990
65231
  switch (node2.type) {
64991
65232
  case "plain":
@@ -65008,6 +65249,10 @@ function renderInline(node2, ctx = {}) {
65008
65249
  }
65009
65250
  case "link":
65010
65251
  return `[${renderInlineChildren(node2.children, ctx)}](${escapeLinkHref(node2.href)})`;
65252
+ case "tg-entity":
65253
+ return `![${escapeMarkdown(collapseLabelBreaks(node2.label))}](${escapeLinkHref(node2.href)})`;
65254
+ case "raw":
65255
+ return node2.text;
65011
65256
  default: {
65012
65257
  const _exhaustive = node2;
65013
65258
  return escapeMarkdown(_exhaustive.text ?? "");
@@ -65024,15 +65269,6 @@ function prefixLines(text4, prefix) {
65024
65269
  }
65025
65270
  function renderBlockquote(node2) {
65026
65271
  const inner = renderBlocks3(node2.children);
65027
- if (node2.expandable) {
65028
- const lines = inner.split(`
65029
- `);
65030
- return lines.map((line, i) => {
65031
- const marker = i === 0 ? "**> " : "> ";
65032
- return line.length > 0 ? `${marker}${line}` : marker.trimEnd();
65033
- }).join(`
65034
- `);
65035
- }
65036
65272
  return prefixLines(inner, "> ");
65037
65273
  }
65038
65274
  function renderCodeBlock(node2) {
@@ -67336,11 +67572,11 @@ init_flood_429_ledger();
67336
67572
  import {
67337
67573
  existsSync as existsSync15,
67338
67574
  readFileSync as readFileSync17,
67339
- writeFileSync as writeFileSync15,
67575
+ writeFileSync as writeFileSync16,
67340
67576
  mkdirSync as mkdirSync19,
67341
67577
  chmodSync as chmodSync6,
67342
- unlinkSync as unlinkSync11,
67343
- renameSync as renameSync11
67578
+ unlinkSync as unlinkSync12,
67579
+ renameSync as renameSync12
67344
67580
  } from "node:fs";
67345
67581
  import { dirname as dirname11, join as join22 } from "node:path";
67346
67582
  var FLOOD_STATE_FILE2 = "flood-wait.json";
@@ -67398,7 +67634,7 @@ function writeFloodState2(path2, state, log = (l) => process.stderr.write(l)) {
67398
67634
  mkdirSync19(dirname11(path2), { recursive: true });
67399
67635
  } catch {}
67400
67636
  try {
67401
- writeFileSync15(path2, payload, { mode: FLOOD_STATE_MODE2 });
67637
+ writeFileSync16(path2, payload, { mode: FLOOD_STATE_MODE2 });
67402
67638
  try {
67403
67639
  chmodSync6(path2, FLOOD_STATE_MODE2);
67404
67640
  } catch {}
@@ -67411,8 +67647,8 @@ function writeFloodState2(path2, state, log = (l) => process.stderr.write(l)) {
67411
67647
  return;
67412
67648
  }
67413
67649
  try {
67414
- unlinkSync11(path2);
67415
- writeFileSync15(path2, payload, { mode: FLOOD_STATE_MODE2 });
67650
+ unlinkSync12(path2);
67651
+ writeFileSync16(path2, payload, { mode: FLOOD_STATE_MODE2 });
67416
67652
  log(`telegram gateway: flood-breaker: recreated ${path2} \u2014 it was owned by another uid ` + `and could not be updated (${code2}); the breaker was blind (issue #3106)
67417
67653
  `);
67418
67654
  } catch (err2) {
@@ -67546,8 +67782,8 @@ function writeFloodWindow(path2, record, now) {
67546
67782
  }
67547
67783
  const arr = [...byScope.values()];
67548
67784
  const tmp = `${path2}.tmp-${process.pid}`;
67549
- writeFileSync15(tmp, JSON.stringify(arr), { mode: FLOOD_STATE_MODE2 });
67550
- renameSync11(tmp, path2);
67785
+ writeFileSync16(tmp, JSON.stringify(arr), { mode: FLOOD_STATE_MODE2 });
67786
+ renameSync12(tmp, path2);
67551
67787
  try {
67552
67788
  chmodSync6(path2, FLOOD_STATE_MODE2);
67553
67789
  } catch {}
@@ -72144,7 +72380,7 @@ class PostHog extends PostHogBackendClient {
72144
72380
  }
72145
72381
 
72146
72382
  // analytics-posthog.ts
72147
- import { existsSync as existsSync16, mkdirSync as mkdirSync20, readFileSync as readFileSync18, writeFileSync as writeFileSync16 } from "node:fs";
72383
+ import { existsSync as existsSync16, mkdirSync as mkdirSync20, readFileSync as readFileSync18, writeFileSync as writeFileSync17 } from "node:fs";
72148
72384
  import { dirname as dirname13, join as join24 } from "node:path";
72149
72385
  import { randomUUID as randomUUID5 } from "node:crypto";
72150
72386
  var DEFAULT_KEY = "phc_qKY87cKWZm6ZyCtk7LcRd2cU8Sg42u7Ywhui5stYCegd";
@@ -72185,7 +72421,7 @@ function getDistinctId() {
72185
72421
  cachedDistinctId = id;
72186
72422
  try {
72187
72423
  mkdirSync20(dirname13(fallbackPath), { recursive: true });
72188
- writeFileSync16(fallbackPath, id, "utf-8");
72424
+ writeFileSync17(fallbackPath, id, "utf-8");
72189
72425
  } catch {}
72190
72426
  return id;
72191
72427
  }
@@ -72260,7 +72496,7 @@ import { mkdirSync as mkdirSync22, appendFileSync as appendFileSync4 } from "nod
72260
72496
  import { dirname as dirname15, join as join26 } from "node:path";
72261
72497
 
72262
72498
  // analytics-posthog.ts
72263
- import { existsSync as existsSync17, mkdirSync as mkdirSync21, readFileSync as readFileSync19, writeFileSync as writeFileSync17 } from "node:fs";
72499
+ import { existsSync as existsSync17, mkdirSync as mkdirSync21, readFileSync as readFileSync19, writeFileSync as writeFileSync18 } from "node:fs";
72264
72500
  import { dirname as dirname14, join as join25 } from "node:path";
72265
72501
  import { randomUUID as randomUUID6 } from "node:crypto";
72266
72502
  var DEFAULT_KEY2 = "phc_qKY87cKWZm6ZyCtk7LcRd2cU8Sg42u7Ywhui5stYCegd";
@@ -72300,7 +72536,7 @@ function getDistinctId2() {
72300
72536
  cachedDistinctId2 = id;
72301
72537
  try {
72302
72538
  mkdirSync21(dirname14(fallbackPath), { recursive: true });
72303
- writeFileSync17(fallbackPath, id, "utf-8");
72539
+ writeFileSync18(fallbackPath, id, "utf-8");
72304
72540
  } catch {}
72305
72541
  return id;
72306
72542
  }
@@ -73036,7 +73272,7 @@ function __resetAllForTests3() {
73036
73272
  }
73037
73273
 
73038
73274
  // silent-end.ts
73039
- import { existsSync as existsSync19, readFileSync as readFileSync20, writeFileSync as writeFileSync18, unlinkSync as unlinkSync12, mkdirSync as mkdirSync23 } from "node:fs";
73275
+ import { existsSync as existsSync19, readFileSync as readFileSync20, writeFileSync as writeFileSync19, unlinkSync as unlinkSync13, mkdirSync as mkdirSync23 } from "node:fs";
73040
73276
  import { dirname as dirname16, join as join27 } from "node:path";
73041
73277
  import { homedir as homedir5 } from "node:os";
73042
73278
  var SILENT_END_MAX_RETRIES = 2;
@@ -73081,7 +73317,7 @@ function writeSilentEndState(args, deps) {
73081
73317
  };
73082
73318
  try {
73083
73319
  mkdirSync23(dirname16(statePath), { recursive: true });
73084
- writeFileSync18(statePath, JSON.stringify(state3), "utf8");
73320
+ writeFileSync19(statePath, JSON.stringify(state3), "utf8");
73085
73321
  emitLog(deps, `silent-end: wrote state file turnKey=${args.turnKey} retryCount=${retryCount}
73086
73322
  `);
73087
73323
  } catch (err) {
@@ -73097,7 +73333,7 @@ function clearSilentEndState(turnKey3, deps) {
73097
73333
  const prev = JSON.parse(readFileSync20(statePath, "utf8"));
73098
73334
  if (prev.turnKey != null && prev.turnKey !== turnKey3)
73099
73335
  return;
73100
- unlinkSync12(statePath);
73336
+ unlinkSync13(statePath);
73101
73337
  emitLog(deps, `silent-end: cleared state file turnKey=${turnKey3}
73102
73338
  `);
73103
73339
  } catch {}
@@ -74028,7 +74264,7 @@ async function gatewayStartupRetry(fn, opts = {}) {
74028
74264
  }
74029
74265
 
74030
74266
  // gateway/quarantine.ts
74031
- import { mkdirSync as mkdirSync24, writeFileSync as writeFileSync19 } from "node:fs";
74267
+ import { mkdirSync as mkdirSync24, writeFileSync as writeFileSync20 } from "node:fs";
74032
74268
  import { join as join30 } from "node:path";
74033
74269
  var QUARANTINE_FILENAME = "quarantine.json";
74034
74270
  function writeQuarantineMarker(telegramStateDir, reason, detail, nowFn = Date.now) {
@@ -74039,7 +74275,7 @@ function writeQuarantineMarker(telegramStateDir, reason, detail, nowFn = Date.no
74039
74275
  ts: nowFn(),
74040
74276
  detail
74041
74277
  };
74042
- writeFileSync19(join30(telegramStateDir, QUARANTINE_FILENAME), JSON.stringify(marker) + `
74278
+ writeFileSync20(join30(telegramStateDir, QUARANTINE_FILENAME), JSON.stringify(marker) + `
74043
74279
  `, "utf-8");
74044
74280
  }
74045
74281
 
@@ -75512,7 +75748,7 @@ async function materializeSidecarToken2(opts = {}, logger2 = (line) => process.s
75512
75748
  }
75513
75749
 
75514
75750
  // ../src/setup/host-capabilities.ts
75515
- import { mkdirSync as mkdirSync25, readFileSync as readFileSync22, writeFileSync as writeFileSync20 } from "node:fs";
75751
+ import { mkdirSync as mkdirSync25, readFileSync as readFileSync22, writeFileSync as writeFileSync21 } from "node:fs";
75516
75752
  init_paths();
75517
75753
  function hostCapabilitiesPath() {
75518
75754
  return resolveStatePath("host-capabilities.json");
@@ -75676,7 +75912,7 @@ function resolveExhaustUntil(resetAtMs, now = Date.now()) {
75676
75912
 
75677
75913
  // gateway/auth-add-flow.ts
75678
75914
  import { execFileSync as execFileSync4 } from "node:child_process";
75679
- import { existsSync as existsSync24, mkdirSync as mkdirSync27, readFileSync as readFileSync24, readdirSync as readdirSync7, rmSync as rmSync6, statSync as statSync10, writeFileSync as writeFileSync22 } from "node:fs";
75915
+ import { existsSync as existsSync24, mkdirSync as mkdirSync27, readFileSync as readFileSync24, readdirSync as readdirSync7, rmSync as rmSync6, statSync as statSync10, writeFileSync as writeFileSync23 } from "node:fs";
75680
75916
  import { homedir as homedir8 } from "node:os";
75681
75917
  import { join as join32 } from "node:path";
75682
75918
  import { randomBytes as randomBytes8 } from "node:crypto";
@@ -75686,7 +75922,7 @@ import {
75686
75922
  readFileSync as readFileSync23,
75687
75923
  readdirSync as readdirSync6,
75688
75924
  existsSync as existsSync23,
75689
- writeFileSync as writeFileSync21,
75925
+ writeFileSync as writeFileSync22,
75690
75926
  mkdirSync as mkdirSync26,
75691
75927
  mkdtempSync as mkdtempSync2,
75692
75928
  rmSync as rmSync5,
@@ -75847,7 +76083,7 @@ async function startAccountAuthSession(label, opts = {}) {
75847
76083
  const tmuxSocket = `switchroom-${agentName3}`;
75848
76084
  const tmuxSession = `auth-add-${label}-${hexSuffix}`.slice(0, 64);
75849
76085
  try {
75850
- writeFileSync22(join32(scratchDir, AUTH_TMUX_SESSION_FILE), `${tmuxSocket}
76086
+ writeFileSync23(join32(scratchDir, AUTH_TMUX_SESSION_FILE), `${tmuxSocket}
75851
76087
  ${tmuxSession}`, "utf8");
75852
76088
  } catch {}
75853
76089
  const sessionEnv = {
@@ -78836,7 +79072,7 @@ function startRestartWatchdog(config) {
78836
79072
  }
78837
79073
 
78838
79074
  // gateway/access-store.ts
78839
- import { mkdirSync as mkdirSync28, readFileSync as readFileSync25, renameSync as renameSync12, writeFileSync as writeFileSync23 } from "node:fs";
79075
+ import { mkdirSync as mkdirSync28, readFileSync as readFileSync25, renameSync as renameSync13, writeFileSync as writeFileSync24 } from "node:fs";
78840
79076
 
78841
79077
  // gateway/access-validator.ts
78842
79078
  function validateStringArray(field, value, tag = "gateway") {
@@ -78900,7 +79136,7 @@ function createAccessStore(deps) {
78900
79136
  if (err.code === "ENOENT")
78901
79137
  return defaultAccess();
78902
79138
  try {
78903
- renameSync12(accessFile, `${accessFile}.corrupt-${Date.now()}`);
79139
+ renameSync13(accessFile, `${accessFile}.corrupt-${Date.now()}`);
78904
79140
  } catch {}
78905
79141
  process.stderr.write(`telegram gateway: access.json is corrupt, moved aside. Starting fresh.
78906
79142
  `);
@@ -78945,9 +79181,9 @@ function createAccessStore(deps) {
78945
79181
  return;
78946
79182
  mkdirSync28(stateDir, { recursive: true, mode: 448 });
78947
79183
  const tmp = accessFile + ".tmp";
78948
- writeFileSync23(tmp, JSON.stringify(a, null, 2) + `
79184
+ writeFileSync24(tmp, JSON.stringify(a, null, 2) + `
78949
79185
  `, { mode: 384 });
78950
- renameSync12(tmp, accessFile);
79186
+ renameSync13(tmp, accessFile);
78951
79187
  }
78952
79188
  function pruneExpired(a) {
78953
79189
  const now = Date.now();
@@ -79212,7 +79448,7 @@ var INLINE_SPAN_PATTERNS2 = [
79212
79448
  /\*\*[^*\n]+\*\*/g,
79213
79449
  /__[^_\n]+__/g,
79214
79450
  /(?<![\w*])_[^_\n]+_(?![\w*])/g,
79215
- /\[[^\]\n]*\]\([^)\n]*\)/g,
79451
+ /!?\[[^\]\n]*\]\([^)\n]*\)/g,
79216
79452
  /~~[^~\n]+~~/g,
79217
79453
  /\|\|[^|\n]+\|\|/g
79218
79454
  ];
@@ -79784,10 +80020,10 @@ import {
79784
80020
  mkdirSync as mkdirSync29,
79785
80021
  readFileSync as readFileSync26,
79786
80022
  readdirSync as readdirSync8,
79787
- renameSync as renameSync13,
80023
+ renameSync as renameSync14,
79788
80024
  statSync as statSync11,
79789
- unlinkSync as unlinkSync13,
79790
- writeFileSync as writeFileSync24,
80025
+ unlinkSync as unlinkSync14,
80026
+ writeFileSync as writeFileSync25,
79791
80027
  appendFileSync as appendFileSync5
79792
80028
  } from "node:fs";
79793
80029
  import { join as join34 } from "node:path";
@@ -79891,8 +80127,8 @@ function writeOutboxRecordAtomic(record, stateDir) {
79891
80127
  if (existsSync26(finalPath))
79892
80128
  return true;
79893
80129
  const tmpPath = join34(dir, `.${record.turnNonce}.${process.pid}.tmp`);
79894
- writeFileSync24(tmpPath, JSON.stringify(record), { mode: 384 });
79895
- renameSync13(tmpPath, finalPath);
80130
+ writeFileSync25(tmpPath, JSON.stringify(record), { mode: 384 });
80131
+ renameSync14(tmpPath, finalPath);
79896
80132
  return true;
79897
80133
  } catch {
79898
80134
  return false;
@@ -79919,7 +80155,7 @@ function claimRecord(nonce, stateDir) {
79919
80155
  const from = join34(dir, `${nonce}.json`);
79920
80156
  const to = join34(dir, `${nonce}.sending`);
79921
80157
  try {
79922
- renameSync13(from, to);
80158
+ renameSync14(from, to);
79923
80159
  return to;
79924
80160
  } catch {
79925
80161
  return null;
@@ -79928,12 +80164,12 @@ function claimRecord(nonce, stateDir) {
79928
80164
  function releaseClaim(nonce, stateDir) {
79929
80165
  const dir = resolveOutboxDir(stateDir);
79930
80166
  try {
79931
- renameSync13(join34(dir, `${nonce}.sending`), join34(dir, `${nonce}.json`));
80167
+ renameSync14(join34(dir, `${nonce}.sending`), join34(dir, `${nonce}.json`));
79932
80168
  } catch {}
79933
80169
  }
79934
80170
  function removeClaimed(nonce, stateDir) {
79935
80171
  try {
79936
- unlinkSync13(join34(resolveOutboxDir(stateDir), `${nonce}.sending`));
80172
+ unlinkSync14(join34(resolveOutboxDir(stateDir), `${nonce}.sending`));
79937
80173
  } catch {}
79938
80174
  }
79939
80175
  function reclaimStaleSending(stateDir, now = Date.now()) {
@@ -79948,7 +80184,7 @@ function reclaimStaleSending(stateDir, now = Date.now()) {
79948
80184
  try {
79949
80185
  const st = statSync11(join34(dir, f));
79950
80186
  if (now - st.mtimeMs > OUTBOX_SENDING_TIMEOUT_MS) {
79951
- renameSync13(join34(dir, f), join34(dir, f.replace(/\.sending$/, ".json")));
80187
+ renameSync14(join34(dir, f), join34(dir, f.replace(/\.sending$/, ".json")));
79952
80188
  }
79953
80189
  } catch {}
79954
80190
  }
@@ -80019,17 +80255,17 @@ function compactJournalIfLarge(path2) {
80019
80255
  return;
80020
80256
  const kept = lines.slice(lines.length - JOURNAL_KEEP);
80021
80257
  const tmp = `${path2}.${process.pid}.compact`;
80022
- writeFileSync24(tmp, kept.join(`
80258
+ writeFileSync25(tmp, kept.join(`
80023
80259
  `) + `
80024
80260
  `, { mode: 384 });
80025
- renameSync13(tmp, path2);
80261
+ renameSync14(tmp, path2);
80026
80262
  } catch {}
80027
80263
  }
80028
80264
  function clearOutboxRecord(nonce, stateDir) {
80029
80265
  const dir = resolveOutboxDir(stateDir);
80030
80266
  for (const suffix of [".json", ".sending"]) {
80031
80267
  try {
80032
- unlinkSync13(join34(dir, `${nonce}${suffix}`));
80268
+ unlinkSync14(join34(dir, `${nonce}${suffix}`));
80033
80269
  } catch {}
80034
80270
  }
80035
80271
  }
@@ -80097,8 +80333,8 @@ import {
80097
80333
  existsSync as existsSync27,
80098
80334
  mkdirSync as mkdirSync30,
80099
80335
  readFileSync as readFileSync27,
80100
- renameSync as renameSync14,
80101
- writeFileSync as writeFileSync25,
80336
+ renameSync as renameSync15,
80337
+ writeFileSync as writeFileSync26,
80102
80338
  appendFileSync as appendFileSync6
80103
80339
  } from "node:fs";
80104
80340
  import { join as join35 } from "node:path";
@@ -80227,10 +80463,10 @@ function compactIfLarge(path2) {
80227
80463
  return;
80228
80464
  const kept = lines.slice(lines.length - SHOWN_LEDGER_KEEP);
80229
80465
  const tmp = `${path2}.${process.pid}.compact`;
80230
- writeFileSync25(tmp, kept.join(`
80466
+ writeFileSync26(tmp, kept.join(`
80231
80467
  `) + `
80232
80468
  `, { mode: 384 });
80233
- renameSync14(tmp, path2);
80469
+ renameSync15(tmp, path2);
80234
80470
  } catch {}
80235
80471
  }
80236
80472
 
@@ -80750,6 +80986,10 @@ var INBOUND_SOURCE_CLASSIFICATION = {
80750
80986
  mental_model_proposal_failed: { decoupledCompletion: false },
80751
80987
  webhook: { decoupledCompletion: false },
80752
80988
  linear: { decoupledCompletion: false },
80989
+ eval_case_applied: { decoupledCompletion: false },
80990
+ eval_case_rejected: { decoupledCompletion: false },
80991
+ eval_case_apply_failed: { decoupledCompletion: false },
80992
+ eval_case_suppressed: { decoupledCompletion: false },
80753
80993
  buzz: { decoupledCompletion: false },
80754
80994
  boot_briefing: { decoupledCompletion: false }
80755
80995
  };
@@ -80988,7 +81228,7 @@ function monotonicNowMs2() {
80988
81228
  }
80989
81229
 
80990
81230
  // silent-end.ts
80991
- import { existsSync as existsSync28, readFileSync as readFileSync28, writeFileSync as writeFileSync26, unlinkSync as unlinkSync14, mkdirSync as mkdirSync31 } from "node:fs";
81231
+ import { existsSync as existsSync28, readFileSync as readFileSync28, writeFileSync as writeFileSync27, unlinkSync as unlinkSync15, mkdirSync as mkdirSync31 } from "node:fs";
80992
81232
  import { dirname as dirname17, join as join36 } from "node:path";
80993
81233
  import { homedir as homedir10 } from "node:os";
80994
81234
  var SILENT_END_MAX_RETRIES2 = 2;
@@ -81037,7 +81277,7 @@ function writeSilentEndState2(args, deps) {
81037
81277
  };
81038
81278
  try {
81039
81279
  mkdirSync31(dirname17(statePath), { recursive: true });
81040
- writeFileSync26(statePath, JSON.stringify(state3), "utf8");
81280
+ writeFileSync27(statePath, JSON.stringify(state3), "utf8");
81041
81281
  emitLog2(deps, `silent-end: wrote state file turnKey=${args.turnKey} retryCount=${retryCount}
81042
81282
  `);
81043
81283
  } catch (err) {
@@ -81053,7 +81293,7 @@ function clearSilentEndState2(turnKey3, deps) {
81053
81293
  const prev = JSON.parse(readFileSync28(statePath, "utf8"));
81054
81294
  if (prev.turnKey != null && prev.turnKey !== turnKey3)
81055
81295
  return;
81056
- unlinkSync14(statePath);
81296
+ unlinkSync15(statePath);
81057
81297
  emitLog2(deps, `silent-end: cleared state file turnKey=${turnKey3}
81058
81298
  `);
81059
81299
  } catch {}
@@ -83416,7 +83656,7 @@ import {
83416
83656
  openSync as openSync10,
83417
83657
  readFileSync as readFileSync29,
83418
83658
  statSync as statSync13,
83419
- unlinkSync as unlinkSync15,
83659
+ unlinkSync as unlinkSync16,
83420
83660
  utimesSync
83421
83661
  } from "node:fs";
83422
83662
  import { join as join39 } from "node:path";
@@ -83445,7 +83685,7 @@ function touchTurnActiveMarker(stateDir) {
83445
83685
  }
83446
83686
  function removeTurnActiveMarker(stateDir) {
83447
83687
  try {
83448
- unlinkSync15(join39(stateDir, TURN_ACTIVE_MARKER_FILE));
83688
+ unlinkSync16(join39(stateDir, TURN_ACTIVE_MARKER_FILE));
83449
83689
  } catch {}
83450
83690
  }
83451
83691
  function readTurnActiveMarkerAgeMs(stateDir, now) {
@@ -85770,7 +86010,7 @@ function resolveAgentDirFromEnv() {
85770
86010
  }
85771
86011
 
85772
86012
  // active-reactions.ts
85773
- import { readFileSync as readFileSync30, writeFileSync as writeFileSync27, renameSync as renameSync15, existsSync as existsSync32, unlinkSync as unlinkSync16 } from "node:fs";
86013
+ import { readFileSync as readFileSync30, writeFileSync as writeFileSync28, renameSync as renameSync16, existsSync as existsSync32, unlinkSync as unlinkSync17 } from "node:fs";
85774
86014
  import { join as join40 } from "node:path";
85775
86015
  var ACTIVE_REACTIONS_FILENAME = ".active-reactions.json";
85776
86016
  function reactionsPath(agentDir) {
@@ -85808,15 +86048,15 @@ function writeActiveReactions(agentDir, reactions) {
85808
86048
  const p = reactionsPath(agentDir);
85809
86049
  if (reactions.length === 0) {
85810
86050
  try {
85811
- unlinkSync16(p);
86051
+ unlinkSync17(p);
85812
86052
  } catch {}
85813
86053
  return;
85814
86054
  }
85815
86055
  const tmp = `${p}.tmp-${process.pid}-${Date.now()}`;
85816
86056
  try {
85817
- writeFileSync27(tmp, JSON.stringify(reactions) + `
86057
+ writeFileSync28(tmp, JSON.stringify(reactions) + `
85818
86058
  `, "utf-8");
85819
- renameSync15(tmp, p);
86059
+ renameSync16(tmp, p);
85820
86060
  } catch {}
85821
86061
  }
85822
86062
  function addActiveReaction(agentDir, reaction) {
@@ -85833,12 +86073,12 @@ function removeActiveReaction(agentDir, chatId, messageId) {
85833
86073
  }
85834
86074
  function clearActiveReactions(agentDir) {
85835
86075
  try {
85836
- unlinkSync16(reactionsPath(agentDir));
86076
+ unlinkSync17(reactionsPath(agentDir));
85837
86077
  } catch {}
85838
86078
  }
85839
86079
 
85840
86080
  // active-reactions.ts
85841
- import { readFileSync as readFileSync31, writeFileSync as writeFileSync28, renameSync as renameSync16, existsSync as existsSync33, unlinkSync as unlinkSync17 } from "node:fs";
86081
+ import { readFileSync as readFileSync31, writeFileSync as writeFileSync29, renameSync as renameSync17, existsSync as existsSync33, unlinkSync as unlinkSync18 } from "node:fs";
85842
86082
  import { join as join41 } from "node:path";
85843
86083
  var ACTIVE_REACTIONS_FILENAME2 = ".active-reactions.json";
85844
86084
  function reactionsPath2(agentDir) {
@@ -85874,7 +86114,7 @@ function readActiveReactions2(agentDir) {
85874
86114
  }
85875
86115
  function clearActiveReactions2(agentDir) {
85876
86116
  try {
85877
- unlinkSync17(reactionsPath2(agentDir));
86117
+ unlinkSync18(reactionsPath2(agentDir));
85878
86118
  } catch {}
85879
86119
  }
85880
86120
 
@@ -88116,15 +88356,15 @@ async function menuWithBannerStatic(deps, banner) {
88116
88356
  }
88117
88357
 
88118
88358
  // gateway/session-model-file.ts
88119
- import { readFileSync as readFileSync33, writeFileSync as writeFileSync29, renameSync as renameSync17, rmSync as rmSync7 } from "node:fs";
88359
+ import { readFileSync as readFileSync33, writeFileSync as writeFileSync30, renameSync as renameSync18, rmSync as rmSync7 } from "node:fs";
88120
88360
  import { join as join43 } from "node:path";
88121
88361
  var SESSION_MODEL_FILE = ".session-model";
88122
88362
  var CONFIGURED_DEFAULT_MODEL_FILE = ".configured-default-model";
88123
88363
  var SESSION_MODEL_BOOT_ATTEMPTS_FILE = ".session-model-boot-attempts";
88124
88364
  function atomicWrite(path2, content3) {
88125
88365
  const tmp = `${path2}.tmp-${process.pid}-${Date.now()}`;
88126
- writeFileSync29(tmp, content3, "utf8");
88127
- renameSync17(tmp, path2);
88366
+ writeFileSync30(tmp, content3, "utf8");
88367
+ renameSync18(tmp, path2);
88128
88368
  }
88129
88369
  function serializeSessionModel(rec) {
88130
88370
  return `${JSON.stringify({
@@ -88652,7 +88892,7 @@ var AUDIT_ROOT = join45(homedir11(), ".switchroom", "audit");
88652
88892
 
88653
88893
  // ../src/agents/profiles.ts
88654
88894
  var import_handlebars = __toESM(require_lib(), 1);
88655
- import { readFileSync as readFileSync36, writeFileSync as writeFileSync31, existsSync as existsSync37, readdirSync as readdirSync9, statSync as statSync14, copyFileSync, mkdirSync as mkdirSync33, realpathSync as realpathSync4 } from "node:fs";
88895
+ import { readFileSync as readFileSync36, writeFileSync as writeFileSync32, existsSync as existsSync37, readdirSync as readdirSync9, statSync as statSync14, copyFileSync, mkdirSync as mkdirSync33, realpathSync as realpathSync4 } from "node:fs";
88656
88896
  import { resolve as resolve8, join as join46, sep as pathSep } from "node:path";
88657
88897
  function resolveProfilesRootDetailed() {
88658
88898
  return resolveShippedAsset(PROFILES_ASSET, {
@@ -88670,7 +88910,7 @@ import_handlebars.default.registerHelper("isNumber", (value) => {
88670
88910
  return typeof value === "number" && Number.isFinite(value);
88671
88911
  });
88672
88912
  var SHARED_FRAGMENTS_DIR = resolve8(PROFILES_ROOT, "_shared");
88673
- var SHARED_FRAGMENTS = ["vault-protocol", "agent-self-service", "execution-discipline", "reply-discipline", "dev-protocol"];
88913
+ var SHARED_FRAGMENTS = ["vault-protocol", "agent-self-service", "execution-discipline", "reply-discipline", "dev-protocol", "local-time"];
88674
88914
  for (const name of SHARED_FRAGMENTS) {
88675
88915
  const fragPath = join46(SHARED_FRAGMENTS_DIR, `${name}.md.hbs`);
88676
88916
  if (existsSync37(fragPath)) {
@@ -90623,7 +90863,7 @@ function numField(obj, key) {
90623
90863
  }
90624
90864
 
90625
90865
  // gateway/context-occupancy.ts
90626
- import { mkdirSync as mkdirSync34, writeFileSync as writeFileSync32 } from "node:fs";
90866
+ import { mkdirSync as mkdirSync34, writeFileSync as writeFileSync33 } from "node:fs";
90627
90867
  import { join as join47 } from "node:path";
90628
90868
  var CONTEXT_OCCUPANCY_FILENAME = "context-occupancy.json";
90629
90869
  var TIGHT_FRACTION = 0.8;
@@ -90649,7 +90889,7 @@ function writeContextOccupancySnapshot(stateDir, snapshot, deps) {
90649
90889
  try {
90650
90890
  const path2 = join47(stateDir, CONTEXT_OCCUPANCY_FILENAME);
90651
90891
  (deps?.mkdir ?? ((p, o) => mkdirSync34(p, o)))(stateDir, { recursive: true });
90652
- (deps?.writeFile ?? ((p, d) => writeFileSync32(p, d)))(path2, JSON.stringify(snapshot, null, 2) + `
90892
+ (deps?.writeFile ?? ((p, d) => writeFileSync33(p, d)))(path2, JSON.stringify(snapshot, null, 2) + `
90653
90893
  `);
90654
90894
  } catch {}
90655
90895
  }
@@ -92031,7 +92271,7 @@ import {
92031
92271
  openSync as openSync11,
92032
92272
  readdirSync as readdirSync10,
92033
92273
  statSync as statSync15,
92034
- writeFileSync as writeFileSync33
92274
+ writeFileSync as writeFileSync34
92035
92275
  } from "node:fs";
92036
92276
  import { dirname as dirname21, join as join51, relative as relative2, sep as sep5 } from "node:path";
92037
92277
  var NOFOLLOW2 = constants5.O_NOFOLLOW ?? 0;
@@ -92114,7 +92354,7 @@ function mkdirStateSync2(path2, options = { recursive: true }, log = defaultLog3
92114
92354
  function writeStateFileSync2(path2, data, options, log = defaultLog3) {
92115
92355
  const owner = resolveStateOwner2(dirname21(path2));
92116
92356
  if (!owner) {
92117
- writeFileSync33(path2, data, options);
92357
+ writeFileSync34(path2, data, options);
92118
92358
  return;
92119
92359
  }
92120
92360
  const mode = options?.mode ?? 438;
@@ -92122,7 +92362,7 @@ function writeStateFileSync2(path2, data, options, log = defaultLog3) {
92122
92362
  let fd = null;
92123
92363
  try {
92124
92364
  fd = openSync11(path2, constants5.O_WRONLY | constants5.O_CREAT | constants5.O_TRUNC | NOFOLLOW2, mode);
92125
- writeFileSync33(fd, buf);
92365
+ writeFileSync34(fd, buf);
92126
92366
  try {
92127
92367
  fchownSync4(fd, owner.uid, owner.gid);
92128
92368
  } catch (err) {
@@ -92136,7 +92376,7 @@ function writeStateFileSync2(path2, data, options, log = defaultLog3) {
92136
92376
  fd = null;
92137
92377
  }
92138
92378
  noteFailure2("write", path2, err, log);
92139
- writeFileSync33(path2, data, options);
92379
+ writeFileSync34(path2, data, options);
92140
92380
  return;
92141
92381
  } finally {
92142
92382
  if (fd !== null) {
@@ -92261,7 +92501,7 @@ function adoptAndReport(path2, owner, log) {
92261
92501
 
92262
92502
  // gateway/webhook-ingest-server.ts
92263
92503
  import net4 from "node:net";
92264
- import { chmodSync as chmodSync10, existsSync as existsSync43, unlinkSync as unlinkSync18 } from "node:fs";
92504
+ import { chmodSync as chmodSync10, existsSync as existsSync43, unlinkSync as unlinkSync19 } from "node:fs";
92265
92505
  var MAX_REQUEST_BYTES = 1024 * 1024;
92266
92506
  function fdOf(conn) {
92267
92507
  const handle = conn._handle;
@@ -92274,7 +92514,7 @@ function startWebhookIngestServer(opts) {
92274
92514
  const allowed = new Set(opts.allowedUids);
92275
92515
  try {
92276
92516
  if (existsSync43(opts.socketPath))
92277
- unlinkSync18(opts.socketPath);
92517
+ unlinkSync19(opts.socketPath);
92278
92518
  } catch (err) {
92279
92519
  log(`webhook-ingest-server: could not unlink stale socket: ${err.message}
92280
92520
  `);
@@ -92367,7 +92607,7 @@ function startWebhookIngestServer(opts) {
92367
92607
  } catch {}
92368
92608
  try {
92369
92609
  if (existsSync43(opts.socketPath))
92370
- unlinkSync18(opts.socketPath);
92610
+ unlinkSync19(opts.socketPath);
92371
92611
  } catch {}
92372
92612
  }
92373
92613
  };
@@ -92379,7 +92619,7 @@ import { join as join55 } from "path";
92379
92619
  import { homedir as homedir16 } from "os";
92380
92620
 
92381
92621
  // ../src/web/webhook-handler.ts
92382
- import { appendFileSync as appendFileSync9, existsSync as existsSync45, mkdirSync as mkdirSync38, readFileSync as readFileSync41, writeFileSync as writeFileSync34 } from "fs";
92622
+ import { appendFileSync as appendFileSync9, existsSync as existsSync45, mkdirSync as mkdirSync38, readFileSync as readFileSync41, writeFileSync as writeFileSync35 } from "fs";
92383
92623
  import { join as join53 } from "path";
92384
92624
 
92385
92625
  // ../src/util/log-rotation.ts
@@ -92734,7 +92974,7 @@ function saveDedupFile(path3, deliveries, now) {
92734
92974
  }
92735
92975
  const sorted = Object.entries(pruned).sort((a, b) => b[1] - a[1]).slice(0, DEDUP_MAX);
92736
92976
  const final = Object.fromEntries(sorted);
92737
- writeFileSync34(path3, JSON.stringify({ deliveries: final }), {
92977
+ writeFileSync35(path3, JSON.stringify({ deliveries: final }), {
92738
92978
  mode: 384
92739
92979
  });
92740
92980
  }
@@ -92764,7 +93004,7 @@ var tokenBuckets = new Map;
92764
93004
  var throttleIssueWindow = new Map;
92765
93005
 
92766
93006
  // ../src/web/webhook-dispatch.ts
92767
- import { existsSync as existsSync46, mkdirSync as mkdirSync39, readFileSync as readFileSync42, writeFileSync as writeFileSync35 } from "fs";
93007
+ import { existsSync as existsSync46, mkdirSync as mkdirSync39, readFileSync as readFileSync42, writeFileSync as writeFileSync36 } from "fs";
92768
93008
  import { join as join54 } from "path";
92769
93009
  import { homedir as homedir15 } from "os";
92770
93010
 
@@ -93074,7 +93314,7 @@ function loadCooldownFile(path3) {
93074
93314
  }
93075
93315
  function saveCooldownFile(path3, dispatches) {
93076
93316
  try {
93077
- writeFileSync35(path3, JSON.stringify({ dispatches }), {
93317
+ writeFileSync36(path3, JSON.stringify({ dispatches }), {
93078
93318
  mode: 384
93079
93319
  });
93080
93320
  } catch {}
@@ -93420,7 +93660,7 @@ function recordWebhookEvent(rec, deps = {}) {
93420
93660
 
93421
93661
  // gateway/ipc-server.ts
93422
93662
  init_format();
93423
- import { renameSync as renameSync19, unlinkSync as unlinkSync20, chmodSync as chmodSync11 } from "fs";
93663
+ import { renameSync as renameSync20, unlinkSync as unlinkSync21, chmodSync as chmodSync11 } from "fs";
93424
93664
  var MAX_BUFFER_SIZE = 1024 * 1024;
93425
93665
  var VALID_OPERATOR_KINDS = new Set(OPERATOR_EVENT_KINDS);
93426
93666
  var AGENT_NAME_RE3 = /^[a-z0-9][a-z0-9_-]{0,50}$/;
@@ -93674,10 +93914,10 @@ function createIpcServer(options) {
93674
93914
  return false;
93675
93915
  };
93676
93916
  try {
93677
- renameSync19(socketPath, socketPath + ".bak");
93917
+ renameSync20(socketPath, socketPath + ".bak");
93678
93918
  } catch {}
93679
93919
  try {
93680
- unlinkSync20(socketPath + ".bak");
93920
+ unlinkSync21(socketPath + ".bak");
93681
93921
  } catch {}
93682
93922
  const clients = new Set;
93683
93923
  const agentIndex = new Map;
@@ -94131,7 +94371,7 @@ function createIpcServer(options) {
94131
94371
  clientBySocketId.clear();
94132
94372
  server.stop(true);
94133
94373
  try {
94134
- renameSync19(socketPath, socketPath + ".bak");
94374
+ renameSync20(socketPath, socketPath + ".bak");
94135
94375
  } catch {}
94136
94376
  }
94137
94377
  };
@@ -94705,8 +94945,132 @@ function buildDiffPreviewCard(input) {
94705
94945
  return { text: text4, reply_markup: kb };
94706
94946
  }
94707
94947
 
94948
+ // gateway/approval-outcome-sources.ts
94949
+ var APPROVAL_OUTCOME_SOURCES = Object.freeze(new Set([
94950
+ "vault_grant_approved",
94951
+ "vault_grant_denied",
94952
+ "vault_grant_timeout",
94953
+ "vault_save_completed",
94954
+ "vault_save_discarded",
94955
+ "vault_save_failed",
94956
+ "vault_save_timeout",
94957
+ "secret_provided",
94958
+ "secret_declined",
94959
+ "secret_provide_failed",
94960
+ "secret_request_timeout",
94961
+ "mental_model_proposal_applied",
94962
+ "mental_model_proposal_denied",
94963
+ "mental_model_proposal_failed",
94964
+ "mental_model_propose_timeout",
94965
+ "skill_proposal_apply",
94966
+ "eval_case_applied",
94967
+ "eval_case_rejected",
94968
+ "eval_case_apply_failed",
94969
+ "eval_case_suppressed"
94970
+ ]));
94971
+ var APPROVAL_OUTCOME_DROPPED_SOURCE = "approval_outcome_dropped";
94972
+ function isApprovalOutcome(msg) {
94973
+ const meta = msg.meta;
94974
+ if (meta == null)
94975
+ return false;
94976
+ if (meta.source != null && APPROVAL_OUTCOME_SOURCES.has(meta.source))
94977
+ return true;
94978
+ return meta.button_callback === "true";
94979
+ }
94980
+ function approvalOutcomeLabel(msg) {
94981
+ const src = msg.meta?.source;
94982
+ if (src != null && src !== "")
94983
+ return src;
94984
+ if (msg.meta?.button_callback === "true")
94985
+ return "button_callback";
94986
+ return "-";
94987
+ }
94988
+ function buildApprovalOutcomeDroppedInbound(opts) {
94989
+ const ts = opts.nowMs ?? Date.now();
94990
+ const list2 = opts.sources.length > 0 ? opts.sources.join(", ") : "unknown";
94991
+ const plural = opts.sources.length === 1 ? "an approval outcome" : "approval outcomes";
94992
+ const msg = {
94993
+ type: "inbound",
94994
+ chatId: opts.chatId,
94995
+ ...opts.threadId != null ? { threadId: opts.threadId } : {},
94996
+ messageId: ts,
94997
+ user: "gateway",
94998
+ userId: 0,
94999
+ ts,
95000
+ text: `\u26a0\ufe0f Your inbound buffer overflowed while every queued message was ${plural}, ` + `so the oldest had to be dropped: ${list2}. Do NOT keep waiting on it \u2014 ` + `re-check the underlying state directly (e.g. retry the vault read to see ` + `whether the grant exists) and tell the operator plainly what was lost.`,
95001
+ meta: {
95002
+ source: APPROVAL_OUTCOME_DROPPED_SOURCE,
95003
+ agent: opts.agent,
95004
+ ...opts.threadId != null ? { message_thread_id: String(opts.threadId) } : {},
95005
+ dropped_sources: list2,
95006
+ dropped_count: String(opts.sources.length)
95007
+ }
95008
+ };
95009
+ return msg;
95010
+ }
95011
+ var APPROVAL_OUTCOME_NOTICE_HOPS = 2;
95012
+ function createApprovalOutcomeDropNotifier(opts) {
95013
+ const log = opts.log ?? ((line) => process.stderr.write(line));
95014
+ const defer = opts.defer ?? ((fn) => queueMicrotask(fn));
95015
+ const hops = opts.hops ?? APPROVAL_OUTCOME_NOTICE_HOPS;
95016
+ const pending = new Map;
95017
+ const scheduled = new Set;
95018
+ return (agent, evicted) => {
95019
+ const label = approvalOutcomeLabel(evicted);
95020
+ log(`telegram gateway: APPROVAL-OUTCOME-DROPPED agent=${agent} source=${label} ` + `chat=${evicted.chatId} ts=${evicted.ts}
95021
+ `);
95022
+ const list2 = pending.get(agent) ?? [];
95023
+ list2.push(label);
95024
+ pending.set(agent, list2);
95025
+ if (scheduled.has(agent))
95026
+ return;
95027
+ scheduled.add(agent);
95028
+ const chatId = evicted.chatId;
95029
+ const threadId = evicted.threadId;
95030
+ const flush = (budget) => {
95031
+ const sources = [...pending.get(agent) ?? []];
95032
+ const before = sources.length;
95033
+ try {
95034
+ opts.push(agent, buildApprovalOutcomeDroppedInbound({
95035
+ agent,
95036
+ chatId,
95037
+ ...threadId != null ? { threadId } : {},
95038
+ sources,
95039
+ ...opts.nowMs != null ? { nowMs: opts.nowMs() } : {}
95040
+ }));
95041
+ } catch (e) {
95042
+ log(`telegram gateway: APPROVAL-OUTCOME-DROPPED notice push failed: ${String(e)}
95043
+ `);
95044
+ } finally {
95045
+ scheduled.delete(agent);
95046
+ }
95047
+ if (budget > 0 && (pending.get(agent)?.length ?? 0) > before) {
95048
+ scheduled.add(agent);
95049
+ defer(() => flush(budget - 1));
95050
+ } else {
95051
+ pending.delete(agent);
95052
+ }
95053
+ };
95054
+ defer(() => flush(hops));
95055
+ };
95056
+ }
95057
+
94708
95058
  // gateway/pending-inbound-buffer.ts
94709
95059
  var DEFAULT_PENDING_INBOUND_CAP = 32;
95060
+ var APPROVAL_OUTCOME_PROTECTION_MS = 15 * 60 * 1000;
95061
+ function selectEvictionVictim(q, nowMs3, protectMaxAgeMs = APPROVAL_OUTCOME_PROTECTION_MS) {
95062
+ for (let i = 0;i < q.length; i++) {
95063
+ if (!isApprovalOutcome(q[i]))
95064
+ return { index: i, reason: "non-outcome" };
95065
+ }
95066
+ for (let i = 0;i < q.length; i++) {
95067
+ const ts = q[i].ts;
95068
+ if (typeof ts === "number" && Number.isFinite(ts) && nowMs3 - ts >= protectMaxAgeMs) {
95069
+ return { index: i, reason: "stale-outcome" };
95070
+ }
95071
+ }
95072
+ return { index: 0, reason: "all-outcomes" };
95073
+ }
94710
95074
  function redeliverBufferedInbound(buffer, agent, send, spool, onDelivered) {
94711
95075
  const pending = buffer.drain(agent);
94712
95076
  let redelivered = 0;
@@ -94815,8 +95179,10 @@ function createPendingInboundBuffer(opts = {}) {
94815
95179
  const cap = opts.capPerAgent ?? DEFAULT_PENDING_INBOUND_CAP;
94816
95180
  const log = opts.log ?? ((line) => process.stderr.write(line));
94817
95181
  const spool = opts.spool;
95182
+ const now = opts.now ?? (() => Date.now());
95183
+ const protectionMs = opts.approvalOutcomeProtectionMs ?? APPROVAL_OUTCOME_PROTECTION_MS;
94818
95184
  const queues = new Map;
94819
- return {
95185
+ const buffer = {
94820
95186
  push(agent, msg) {
94821
95187
  let q = queues.get(agent);
94822
95188
  if (q == null) {
@@ -94825,14 +95191,19 @@ function createPendingInboundBuffer(opts = {}) {
94825
95191
  }
94826
95192
  let evicted = false;
94827
95193
  if (q.length >= cap) {
94828
- const dropped = q.shift();
95194
+ const { index: index2, reason } = selectEvictionVictim(q, now(), protectionMs);
95195
+ const dropped = q.splice(index2, 1)[0];
94829
95196
  evicted = true;
94830
- log(`pending-inbound-buffer: agent=${agent} cap=${cap} reached \u2014 ` + `dropped oldest entry source=${dropped?.meta?.source ?? "-"} ts=${dropped?.ts ?? "-"}
95197
+ log(`pending-inbound-buffer: agent=${agent} cap=${cap} reached \u2014 ` + `dropped entry idx=${index2} reason=${reason} ` + `source=${dropped?.meta?.source ?? "-"} ts=${dropped?.ts ?? "-"}
94831
95198
  `);
94832
- if (dropped != null && opts.onEvict != null) {
94833
- try {
94834
- opts.onEvict(agent, dropped);
94835
- } catch {}
95199
+ if (dropped != null) {
95200
+ const critical = reason !== "non-outcome";
95201
+ const cb = critical ? onEvictCritical : opts.onEvict;
95202
+ if (cb != null) {
95203
+ try {
95204
+ cb(agent, dropped);
95205
+ } catch {}
95206
+ }
94836
95207
  }
94837
95208
  }
94838
95209
  q.push(msg);
@@ -94866,6 +95237,13 @@ function createPendingInboundBuffer(opts = {}) {
94866
95237
  },
94867
95238
  beforeRedeliver: opts.beforeRedeliver
94868
95239
  };
95240
+ const onEvictCritical = opts.onEvictCritical ?? createApprovalOutcomeDropNotifier({
95241
+ push: (a, m) => {
95242
+ buffer.push(a, m);
95243
+ },
95244
+ log
95245
+ });
95246
+ return buffer;
94869
95247
  }
94870
95248
 
94871
95249
  // gateway/represent-guard.ts
@@ -94928,6 +95306,7 @@ function makeSessionBusyDrainDeferral(boundMs, staleGapMs = DEFAULT_DRAIN_DEFER_
94928
95306
  }
94929
95307
 
94930
95308
  // gateway/pending-inbound-buffer.ts
95309
+ var APPROVAL_OUTCOME_PROTECTION_MS2 = 15 * 60 * 1000;
94931
95310
  function redeliverBufferedInbound2(buffer, agent, send, spool, onDelivered) {
94932
95311
  const pending = buffer.drain(agent);
94933
95312
  let redelivered = 0;
@@ -97832,7 +98211,7 @@ function purgeStaleTurnsForChat(chatId, keys, purger, isStale = () => true) {
97832
98211
  }
97833
98212
 
97834
98213
  // gateway/compaction-marker.ts
97835
- import { statSync as statSync17, unlinkSync as unlinkSync21 } from "node:fs";
98214
+ import { statSync as statSync17, unlinkSync as unlinkSync22 } from "node:fs";
97836
98215
  import { homedir as homedir17 } from "node:os";
97837
98216
  import { join as join56 } from "node:path";
97838
98217
  var COMPACTION_MARKER_FILE = "compaction-in-flight.json";
@@ -97849,7 +98228,7 @@ function readCompactionMarkerAgeMs(stateDir, now) {
97849
98228
  }
97850
98229
  function removeCompactionMarker(stateDir) {
97851
98230
  try {
97852
- unlinkSync21(join56(stateDir, COMPACTION_MARKER_FILE));
98231
+ unlinkSync22(join56(stateDir, COMPACTION_MARKER_FILE));
97853
98232
  } catch {}
97854
98233
  }
97855
98234
 
@@ -98609,6 +98988,26 @@ function maybeFireWarmup(ctx) {
98609
98988
  }
98610
98989
 
98611
98990
  // gateway/self-improve-proposal-wiring.ts
98991
+ function buildEvalCaseSuppressedInbound(opts) {
98992
+ const ts = opts.nowMs ?? Date.now();
98993
+ return {
98994
+ type: "inbound",
98995
+ chatId: opts.chatId,
98996
+ ...opts.threadId != null ? { threadId: opts.threadId } : {},
98997
+ messageId: ts,
98998
+ user: "self-improve",
98999
+ userId: 0,
99000
+ ts,
99001
+ text: `\u2139\ufe0f Your proposed eval case for \`${opts.skillSlug}\` was NOT posted as a ` + `card: the operator already dismissed this exact case, and the dismissal ` + `is still in effect. This is EXPECTED and is not an error or a failure on ` + `your part \u2014 nothing was written and no card is pending, so do NOT wait ` + `for an approval tap. Do NOT re-propose this case. Carry on with the ` + `original task without it.`,
99002
+ meta: {
99003
+ source: "eval_case_suppressed",
99004
+ agent: opts.agent,
99005
+ ...opts.threadId != null ? { message_thread_id: String(opts.threadId) } : {},
99006
+ skill_slug: opts.skillSlug,
99007
+ fingerprint: opts.fingerprint
99008
+ }
99009
+ };
99010
+ }
98612
99011
  function handlePostSkillProposal(msg, deps) {
98613
99012
  const { bot, assertAllowedChat, swallowingApiCall } = deps;
98614
99013
  const self = process.env.SWITCHROOM_AGENT_NAME;
@@ -98665,8 +99064,28 @@ function handlePostSkillProposal(msg, deps) {
98665
99064
  process.stderr.write(`telegram gateway: post_skill_proposal agent=${msg.agentName} chat=${msg.chatId} ` + `proposal=${proposal.id} slug=${proposal.skill_slug} new=${proposal.is_new}
98666
99065
  `);
98667
99066
  }
99067
+ function isEvalCaseProposalSuppressed(stateDir, candidate, opts = {}) {
99068
+ if (typeof candidate.fingerprint !== "string" || candidate.fingerprint.length === 0) {
99069
+ return false;
99070
+ }
99071
+ const now = (opts.now ?? Date.now)();
99072
+ const ttl = opts.ttlMs ?? REJECTION_TTL_MS;
99073
+ for (const p of readEvalCaseProposals(stateDir)) {
99074
+ if (p.status !== "rejected")
99075
+ continue;
99076
+ if (p.skill_slug !== candidate.skillSlug)
99077
+ continue;
99078
+ if (p.fingerprint !== candidate.fingerprint)
99079
+ continue;
99080
+ const age = now - new Date(p.created_at).getTime();
99081
+ if (!Number.isFinite(age) || age > ttl)
99082
+ continue;
99083
+ return true;
99084
+ }
99085
+ return false;
99086
+ }
98668
99087
  function handlePostEvalCaseProposal(msg, deps) {
98669
- const { bot, assertAllowedChat, swallowingApiCall } = deps;
99088
+ const { bot, assertAllowedChat, swallowingApiCall, deliverResumeSyntheticOrBuffer } = deps;
98670
99089
  const self = process.env.SWITCHROOM_AGENT_NAME;
98671
99090
  if (self && msg.agentName !== self) {
98672
99091
  process.stderr.write(`telegram gateway: post_eval_case_proposal rejected \u2014 agent mismatch (${msg.agentName} != ${self})
@@ -98683,6 +99102,21 @@ function handlePostEvalCaseProposal(msg, deps) {
98683
99102
  const stateDir = process.env.TELEGRAM_STATE_DIR;
98684
99103
  if (stateDir == null || stateDir.length === 0) {
98685
99104
  process.stderr.write(`telegram gateway: post_eval_case_proposal: TELEGRAM_STATE_DIR unset, skipping
99105
+ `);
99106
+ return;
99107
+ }
99108
+ if (isEvalCaseProposalSuppressed(stateDir, {
99109
+ skillSlug: msg.skillSlug,
99110
+ fingerprint: msg.fingerprint
99111
+ })) {
99112
+ const delivered = deliverResumeSyntheticOrBuffer(msg.agentName, buildEvalCaseSuppressedInbound({
99113
+ agent: msg.agentName,
99114
+ chatId: msg.chatId,
99115
+ ...msg.threadId != null ? { threadId: msg.threadId } : {},
99116
+ skillSlug: msg.skillSlug,
99117
+ fingerprint: msg.fingerprint
99118
+ }));
99119
+ process.stderr.write(`telegram gateway: post_eval_case_proposal suppressed (dismissed before) ` + `slug=${msg.skillSlug} fp=${msg.fingerprint} delivered=${delivered}
98686
99120
  `);
98687
99121
  return;
98688
99122
  }
@@ -99214,15 +99648,15 @@ function escapeBody2(s) {
99214
99648
  }
99215
99649
 
99216
99650
  // gateway/pid-file.ts
99217
- import { writeFileSync as writeFileSync36, readFileSync as readFileSync43, unlinkSync as unlinkSync22, renameSync as renameSync20 } from "node:fs";
99651
+ import { writeFileSync as writeFileSync37, readFileSync as readFileSync43, unlinkSync as unlinkSync23, renameSync as renameSync21 } from "node:fs";
99218
99652
  function writePidFile(path3, record) {
99219
99653
  const tmp = `${path3}.tmp-${process.pid}-${Date.now()}`;
99220
- writeFileSync36(tmp, JSON.stringify(record), "utf-8");
99221
- renameSync20(tmp, path3);
99654
+ writeFileSync37(tmp, JSON.stringify(record), "utf-8");
99655
+ renameSync21(tmp, path3);
99222
99656
  }
99223
99657
  function clearPidFile(path3) {
99224
99658
  try {
99225
- unlinkSync22(path3);
99659
+ unlinkSync23(path3);
99226
99660
  } catch {}
99227
99661
  }
99228
99662
 
@@ -99439,11 +99873,11 @@ function safeCount(fn) {
99439
99873
  }
99440
99874
 
99441
99875
  // gateway/session-marker.ts
99442
- import { writeFileSync as writeFileSync37, readFileSync as readFileSync45, renameSync as renameSync21, unlinkSync as unlinkSync23 } from "node:fs";
99876
+ import { writeFileSync as writeFileSync38, readFileSync as readFileSync45, renameSync as renameSync22, unlinkSync as unlinkSync24 } from "node:fs";
99443
99877
  function writeSessionMarker(path3, marker) {
99444
99878
  const tmp = `${path3}.tmp-${process.pid}-${Date.now()}`;
99445
- writeFileSync37(tmp, JSON.stringify(marker), "utf-8");
99446
- renameSync21(tmp, path3);
99879
+ writeFileSync38(tmp, JSON.stringify(marker), "utf-8");
99880
+ renameSync22(tmp, path3);
99447
99881
  }
99448
99882
  function readSessionMarker(path3) {
99449
99883
  try {
@@ -99469,12 +99903,12 @@ function shouldFireRestartBanner(input) {
99469
99903
  }
99470
99904
 
99471
99905
  // gateway/clean-shutdown-marker.ts
99472
- import { writeFileSync as writeFileSync38, readFileSync as readFileSync46, renameSync as renameSync22, unlinkSync as unlinkSync24 } from "node:fs";
99906
+ import { writeFileSync as writeFileSync39, readFileSync as readFileSync46, renameSync as renameSync23, unlinkSync as unlinkSync25 } from "node:fs";
99473
99907
  var DEFAULT_MAX_AGE_MS = 60000;
99474
99908
  function writeCleanShutdownMarker(path3, marker) {
99475
99909
  const tmp = `${path3}.tmp-${process.pid}-${Date.now()}`;
99476
- writeFileSync38(tmp, JSON.stringify(marker), "utf-8");
99477
- renameSync22(tmp, path3);
99910
+ writeFileSync39(tmp, JSON.stringify(marker), "utf-8");
99911
+ renameSync23(tmp, path3);
99478
99912
  }
99479
99913
  function readCleanShutdownMarker(path3) {
99480
99914
  try {
@@ -99493,7 +99927,7 @@ function readCleanShutdownMarker(path3) {
99493
99927
  }
99494
99928
  function clearCleanShutdownMarker(path3) {
99495
99929
  try {
99496
- unlinkSync24(path3);
99930
+ unlinkSync25(path3);
99497
99931
  } catch {}
99498
99932
  }
99499
99933
  function shouldSuppressRecoveryBanner(marker, now, maxAgeMs = DEFAULT_MAX_AGE_MS) {
@@ -101409,31 +101843,31 @@ function startSubagentWatcher(config) {
101409
101843
  // ../src/worktree/registry.ts
101410
101844
  import {
101411
101845
  mkdirSync as mkdirSync41,
101412
- writeFileSync as writeFileSync39,
101846
+ writeFileSync as writeFileSync40,
101413
101847
  readFileSync as readFileSync48,
101414
101848
  readdirSync as readdirSync13,
101415
- unlinkSync as unlinkSync25,
101849
+ unlinkSync as unlinkSync26,
101416
101850
  existsSync as existsSync48,
101417
- renameSync as renameSync23
101851
+ renameSync as renameSync24
101418
101852
  } from "node:fs";
101419
101853
  import { join as join58, resolve as resolve10 } from "node:path";
101420
101854
  import { homedir as homedir18 } from "node:os";
101421
- function registryDir() {
101855
+ function registryDir2() {
101422
101856
  return resolve10(process.env.SWITCHROOM_WORKTREE_DIR ?? join58(homedir18(), ".switchroom", "worktrees"));
101423
101857
  }
101424
101858
  function recordPath(id) {
101425
- return join58(registryDir(), `${id}.json`);
101859
+ return join58(registryDir2(), `${id}.json`);
101426
101860
  }
101427
101861
  function ensureDir4() {
101428
- mkdirSync41(registryDir(), { recursive: true });
101862
+ mkdirSync41(registryDir2(), { recursive: true });
101429
101863
  }
101430
- function writeRecord(record) {
101864
+ function writeRecord2(record) {
101431
101865
  ensureDir4();
101432
101866
  const target = recordPath(record.id);
101433
101867
  const tmp = `${target}.tmp${process.pid}`;
101434
- writeFileSync39(tmp, JSON.stringify(record, null, 2) + `
101868
+ writeFileSync40(tmp, JSON.stringify(record, null, 2) + `
101435
101869
  `, { mode: 384 });
101436
- renameSync23(tmp, target);
101870
+ renameSync24(tmp, target);
101437
101871
  }
101438
101872
  function readRecord(id) {
101439
101873
  const path3 = recordPath(id);
@@ -101446,7 +101880,7 @@ function readRecord(id) {
101446
101880
  }
101447
101881
  function listRecords() {
101448
101882
  ensureDir4();
101449
- const dir = registryDir();
101883
+ const dir = registryDir2();
101450
101884
  const records = [];
101451
101885
  for (const entry of readdirSync13(dir)) {
101452
101886
  if (!entry.endsWith(".json"))
@@ -101465,7 +101899,7 @@ function touchHeartbeat(id, onAfterRead) {
101465
101899
  onAfterRead?.();
101466
101900
  if (!recordExists(id))
101467
101901
  return;
101468
- writeRecord({ ...rec, heartbeatAt: new Date().toISOString() });
101902
+ writeRecord2({ ...rec, heartbeatAt: new Date().toISOString() });
101469
101903
  }
101470
101904
  function recordExists(id) {
101471
101905
  return existsSync48(recordPath(id));
@@ -101845,7 +102279,7 @@ function maybeRenderUpdateAnnouncement(opts = {}) {
101845
102279
 
101846
102280
  // issues-card.ts
101847
102281
  init_card_format();
101848
- import { readFileSync as readFileSync56, writeFileSync as writeFileSync44 } from "node:fs";
102282
+ import { readFileSync as readFileSync56, writeFileSync as writeFileSync45 } from "node:fs";
101849
102283
  var SEVERITY_EMOJI = {
101850
102284
  info: "\u2139\ufe0f",
101851
102285
  warn: "\u26a0\ufe0f",
@@ -101953,7 +102387,7 @@ function readPersistedMessageId(path3, log) {
101953
102387
  }
101954
102388
  function writePersistedMessageId(path3, messageId, log) {
101955
102389
  try {
101956
- writeFileSync44(path3, JSON.stringify({ messageId }) + `
102390
+ writeFileSync45(path3, JSON.stringify({ messageId }) + `
101957
102391
  `, { mode: 384 });
101958
102392
  } catch (err) {
101959
102393
  log(`issues-card: persist write failed (${err.message})`);
@@ -102057,10 +102491,10 @@ import {
102057
102491
  openSync as openSync15,
102058
102492
  readdirSync as readdirSync15,
102059
102493
  readFileSync as readFileSync57,
102060
- renameSync as renameSync26,
102494
+ renameSync as renameSync27,
102061
102495
  statSync as statSync20,
102062
- unlinkSync as unlinkSync26,
102063
- writeFileSync as writeFileSync45,
102496
+ unlinkSync as unlinkSync27,
102497
+ writeFileSync as writeFileSync46,
102064
102498
  writeSync as writeSync8
102065
102499
  } from "node:fs";
102066
102500
  import { join as join64 } from "node:path";
@@ -102143,8 +102577,8 @@ function writeAll(stateDir, events) {
102143
102577
  const body = events.length === 0 ? "" : events.map((e) => JSON.stringify(e)).join(`
102144
102578
  `) + `
102145
102579
  `;
102146
- writeFileSync45(tmp, body, "utf-8");
102147
- renameSync26(tmp, path3);
102580
+ writeFileSync46(tmp, body, "utf-8");
102581
+ renameSync27(tmp, path3);
102148
102582
  }
102149
102583
  var ORPHAN_TMP_TTL_MS = 60000;
102150
102584
  var TMP_PREFIX = `${ISSUES_FILE}.tmp-`;
@@ -102163,7 +102597,7 @@ function sweepOrphanTmpFiles(stateDir) {
102163
102597
  try {
102164
102598
  const stat = statSync20(tmpPath2);
102165
102599
  if (stat.mtimeMs < cutoff) {
102166
- unlinkSync26(tmpPath2);
102600
+ unlinkSync27(tmpPath2);
102167
102601
  }
102168
102602
  } catch {}
102169
102603
  }
@@ -102199,7 +102633,7 @@ function withLock(stateDir, fn) {
102199
102633
  closeSync15(fd);
102200
102634
  } catch {}
102201
102635
  try {
102202
- unlinkSync26(lockPath);
102636
+ unlinkSync27(lockPath);
102203
102637
  } catch {}
102204
102638
  }
102205
102639
  }
@@ -102213,13 +102647,13 @@ function tryStealStaleLock(lockPath) {
102213
102647
  const pid = Number(pidStr);
102214
102648
  if (!Number.isFinite(pid) || pid <= 0) {
102215
102649
  try {
102216
- unlinkSync26(lockPath);
102650
+ unlinkSync27(lockPath);
102217
102651
  } catch {}
102218
102652
  return true;
102219
102653
  }
102220
102654
  if (pid === process.pid) {
102221
102655
  try {
102222
- unlinkSync26(lockPath);
102656
+ unlinkSync27(lockPath);
102223
102657
  } catch {}
102224
102658
  return true;
102225
102659
  }
@@ -102234,7 +102668,7 @@ function tryStealStaleLock(lockPath) {
102234
102668
  return false;
102235
102669
  }
102236
102670
  try {
102237
- unlinkSync26(lockPath);
102671
+ unlinkSync27(lockPath);
102238
102672
  } catch {}
102239
102673
  return true;
102240
102674
  }
@@ -103436,7 +103870,7 @@ function isDiffPreApproved(agentName3, unifiedDiff, deps) {
103436
103870
 
103437
103871
  // credits-watch.ts
103438
103872
  init_card_format();
103439
- import { readFileSync as readFileSync58, writeFileSync as writeFileSync46, existsSync as existsSync56, mkdirSync as mkdirSync47 } from "fs";
103873
+ import { readFileSync as readFileSync58, writeFileSync as writeFileSync47, existsSync as existsSync56, mkdirSync as mkdirSync47 } from "fs";
103440
103874
  import { join as join67 } from "path";
103441
103875
  var STATE_FILE = "credits-watch.json";
103442
103876
  var DEFAULT_CREDIT_FATAL_REASONS = new Set;
@@ -103560,14 +103994,14 @@ function loadCreditState(stateDir) {
103560
103994
  function saveCreditState(stateDir, state7) {
103561
103995
  mkdirSync47(stateDir, { recursive: true });
103562
103996
  const path3 = join67(stateDir, STATE_FILE);
103563
- writeFileSync46(path3, JSON.stringify(state7, null, 2) + `
103997
+ writeFileSync47(path3, JSON.stringify(state7, null, 2) + `
103564
103998
  `, { mode: 384 });
103565
103999
  }
103566
104000
 
103567
104001
  // quota-watch.ts
103568
104002
  init_auth_snapshot_format();
103569
104003
  init_card_format();
103570
- import { readFileSync as readFileSync59, writeFileSync as writeFileSync47, existsSync as existsSync57, mkdirSync as mkdirSync48 } from "fs";
104004
+ import { readFileSync as readFileSync59, writeFileSync as writeFileSync48, existsSync as existsSync57, mkdirSync as mkdirSync48 } from "fs";
103571
104005
  import { join as join68 } from "path";
103572
104006
  var STATE_FILE2 = "quota-watch.json";
103573
104007
  function emptyQuotaWatchState() {
@@ -103829,7 +104263,7 @@ function loadQuotaWatchState(stateDir) {
103829
104263
  function saveQuotaWatchState(stateDir, state7) {
103830
104264
  mkdirSync48(stateDir, { recursive: true });
103831
104265
  const path3 = join68(stateDir, STATE_FILE2);
103832
- writeFileSync47(path3, JSON.stringify(state7, null, 2) + `
104266
+ writeFileSync48(path3, JSON.stringify(state7, null, 2) + `
103833
104267
  `, { mode: 384 });
103834
104268
  }
103835
104269
  function patchQuotaWatchState(current, accountLabel, accountState) {
@@ -103882,7 +104316,7 @@ import {
103882
104316
  openSync as openSync16,
103883
104317
  readFileSync as readFileSync60,
103884
104318
  statSync as statSync22,
103885
- unlinkSync as unlinkSync27,
104319
+ unlinkSync as unlinkSync28,
103886
104320
  utimesSync as utimesSync2
103887
104321
  } from "node:fs";
103888
104322
  import { join as join69 } from "node:path";
@@ -103891,7 +104325,7 @@ var TURN_ACTIVE_HARD_TTL_MS2 = 10 * 60000;
103891
104325
  var TURN_ACTIVE_IDLE_SWEEP_MS = 60000;
103892
104326
  function removeTurnActiveMarker2(stateDir) {
103893
104327
  try {
103894
- unlinkSync27(join69(stateDir, TURN_ACTIVE_MARKER_FILE2));
104328
+ unlinkSync28(join69(stateDir, TURN_ACTIVE_MARKER_FILE2));
103895
104329
  } catch {}
103896
104330
  }
103897
104331
  function sweepStaleTurnActiveMarker(stateDir, opts) {
@@ -103910,7 +104344,7 @@ function sweepStaleTurnActiveMarker(stateDir, opts) {
103910
104344
  try {
103911
104345
  payload = readFileSync60(path3, "utf8");
103912
104346
  } catch {}
103913
- unlinkSync27(path3);
104347
+ unlinkSync28(path3);
103914
104348
  if (opts.onRemove) {
103915
104349
  try {
103916
104350
  opts.onRemove({
@@ -103972,9 +104406,9 @@ import {
103972
104406
  fsyncSync as fsyncSync6,
103973
104407
  openSync as openSync17,
103974
104408
  readFileSync as readFileSync61,
103975
- renameSync as renameSync27,
103976
- unlinkSync as unlinkSync28,
103977
- writeFileSync as writeFileSync48
104409
+ renameSync as renameSync28,
104410
+ unlinkSync as unlinkSync29,
104411
+ writeFileSync as writeFileSync49
103978
104412
  } from "node:fs";
103979
104413
  import { join as join71 } from "node:path";
103980
104414
  var BOOT_BEACON_FILE = "gateway-beacon.json";
@@ -104081,12 +104515,12 @@ function writeBootBeaconFile(stateDir, beacon) {
104081
104515
  try {
104082
104516
  mkdirStateSync(stateDir, { recursive: true, mode: 448 });
104083
104517
  fd = openSync17(tmp, "w", 384);
104084
- writeFileSync48(fd, serializeBootBeacon(beacon));
104518
+ writeFileSync49(fd, serializeBootBeacon(beacon));
104085
104519
  adoptStateOwnershipFd(fd, stateDir);
104086
104520
  fsyncSync6(fd);
104087
104521
  closeSync17(fd);
104088
104522
  fd = undefined;
104089
- renameSync27(tmp, path3);
104523
+ renameSync28(tmp, path3);
104090
104524
  return true;
104091
104525
  } catch {
104092
104526
  if (fd !== undefined) {
@@ -104095,7 +104529,7 @@ function writeBootBeaconFile(stateDir, beacon) {
104095
104529
  } catch {}
104096
104530
  }
104097
104531
  try {
104098
- unlinkSync28(tmp);
104532
+ unlinkSync29(tmp);
104099
104533
  } catch {}
104100
104534
  return false;
104101
104535
  }
@@ -104467,10 +104901,10 @@ function startOutboxSweep(deps) {
104467
104901
  }
104468
104902
 
104469
104903
  // ../src/build-info.ts
104470
- var VERSION2 = "0.21.7";
104471
- var COMMIT_SHA = "e4e50f84";
104472
- var COMMIT_DATE = "2026-08-11T23:08:27Z";
104473
- var LATEST_PR = 4613;
104904
+ var VERSION2 = "0.21.9";
104905
+ var COMMIT_SHA = "08262924";
104906
+ var COMMIT_DATE = "2026-08-13T12:13:46Z";
104907
+ var LATEST_PR = 4686;
104474
104908
  var COMMITS_AHEAD_OF_TAG = 0;
104475
104909
 
104476
104910
  // gateway/boot-version.ts
@@ -105852,7 +106286,7 @@ function selectResumeBuilder(endedVia, opts) {
105852
106286
  }
105853
106287
 
105854
106288
  // gateway/boot-briefing-wiring.ts
105855
- import { existsSync as existsSync60, readFileSync as readFileSync63, writeFileSync as writeFileSync49 } from "node:fs";
106289
+ import { existsSync as existsSync60, readFileSync as readFileSync63, writeFileSync as writeFileSync50 } from "node:fs";
105856
106290
  import { join as join74 } from "node:path";
105857
106291
  init_history();
105858
106292
 
@@ -106208,7 +106642,7 @@ async function maybeQueueBootBriefing(opts) {
106208
106642
  if (!bootId)
106209
106643
  return;
106210
106644
  try {
106211
- writeFileSync49(genMarkerPath, `${bootId}
106645
+ writeFileSync50(genMarkerPath, `${bootId}
106212
106646
  `);
106213
106647
  } catch {}
106214
106648
  };
@@ -106282,7 +106716,7 @@ async function maybeQueueBootBriefing(opts) {
106282
106716
  }
106283
106717
 
106284
106718
  // gateway/pending-turn-env.ts
106285
- import { existsSync as existsSync61, renameSync as renameSync28, rmSync as rmSync8, writeFileSync as writeFileSync50 } from "node:fs";
106719
+ import { existsSync as existsSync61, renameSync as renameSync29, rmSync as rmSync8, writeFileSync as writeFileSync51 } from "node:fs";
106286
106720
  import { join as join75 } from "node:path";
106287
106721
  function writePendingTurnEnv(agentDir, pending, log = (l) => process.stderr.write(l)) {
106288
106722
  const pendingEnvPath = join75(agentDir, ".pending-turn.env");
@@ -106299,10 +106733,10 @@ function writePendingTurnEnv(agentDir, pending, log = (l) => process.stderr.writ
106299
106733
  pending.interrupt_reason != null ? `SWITCHROOM_PENDING_INTERRUPT_REASON=${pending.interrupt_reason}` : `SWITCHROOM_PENDING_INTERRUPT_REASON=`
106300
106734
  ];
106301
106735
  const pendingEnvTmp = `${pendingEnvPath}.tmp-${process.pid}`;
106302
- writeFileSync50(pendingEnvTmp, lines.join(`
106736
+ writeFileSync51(pendingEnvTmp, lines.join(`
106303
106737
  `) + `
106304
106738
  `, { mode: 384 });
106305
- renameSync28(pendingEnvTmp, pendingEnvPath);
106739
+ renameSync29(pendingEnvTmp, pendingEnvPath);
106306
106740
  log(`telegram gateway: pending-turn env written to ${pendingEnvPath} ` + `turnKey=${pending.turn_key} endedVia=${pending.ended_via ?? "open"}
106307
106741
  `);
106308
106742
  } else if (existsSync61(pendingEnvPath)) {
@@ -106316,8 +106750,184 @@ function writePendingTurnEnv(agentDir, pending, log = (l) => process.stderr.writ
106316
106750
  }
106317
106751
  }
106318
106752
 
106753
+ // gateway/agent-process-liveness.ts
106754
+ import { existsSync as existsSync62, readFileSync as readFileSync64, writeFileSync as writeFileSync52, renameSync as renameSync30, unlinkSync as unlinkSync30, readdirSync as readdirSync16 } from "node:fs";
106755
+ import { join as join76, dirname as dirname28, basename as basename18 } from "node:path";
106756
+ var AGENT_PROCESS_RECORD_FILE = "agent-process.json";
106757
+ var BOOT_RESUME_DONE_FILE = ".boot-resume-done";
106758
+ function parseProcStat(raw) {
106759
+ const close = raw.lastIndexOf(") ");
106760
+ const open = raw.indexOf(" (");
106761
+ if (close < 0 || open < 0 || close < open)
106762
+ return null;
106763
+ const comm = raw.slice(open + 2, close);
106764
+ const rest = raw.slice(close + 2).trim().split(/\s+/);
106765
+ const state7 = rest[0];
106766
+ const starttime = rest[19];
106767
+ if (state7 == null || state7.length === 0)
106768
+ return null;
106769
+ if (starttime == null || !/^\d+$/.test(starttime))
106770
+ return null;
106771
+ return { comm, state: state7, starttime };
106772
+ }
106773
+ function readProcIdentity(pid, procRoot = "/proc") {
106774
+ if (!Number.isInteger(pid) || pid <= 0)
106775
+ return null;
106776
+ let identity;
106777
+ try {
106778
+ identity = parseProcStat(readFileSync64(join76(procRoot, String(pid), "stat"), "utf8"));
106779
+ } catch {
106780
+ return null;
106781
+ }
106782
+ if (identity != null && identity.state === "Z")
106783
+ return null;
106784
+ return identity;
106785
+ }
106786
+ function readAgentProcessRecord(path3) {
106787
+ let parsed;
106788
+ try {
106789
+ parsed = JSON.parse(readFileSync64(path3, "utf8"));
106790
+ } catch {
106791
+ return null;
106792
+ }
106793
+ if (parsed == null || typeof parsed !== "object")
106794
+ return null;
106795
+ const o = parsed;
106796
+ const pid = typeof o.pid === "number" ? o.pid : Number(o.pid);
106797
+ const starttime = typeof o.starttime === "string" ? o.starttime : String(o.starttime ?? "");
106798
+ if (!Number.isInteger(pid) || pid <= 0)
106799
+ return null;
106800
+ if (!/^\d+$/.test(starttime))
106801
+ return null;
106802
+ const rec = { pid, starttime };
106803
+ if (typeof o.comm === "string" && o.comm.length > 0)
106804
+ rec.comm = o.comm;
106805
+ if (typeof o.boot_at === "number" && Number.isFinite(o.boot_at))
106806
+ rec.boot_at = o.boot_at;
106807
+ return rec;
106808
+ }
106809
+ function bootResumeDonePath(stateDir) {
106810
+ return join76(stateDir, BOOT_RESUME_DONE_FILE);
106811
+ }
106812
+ function containerBootIdentity(procRoot = "/proc") {
106813
+ return readProcIdentity(1, procRoot)?.starttime ?? null;
106814
+ }
106815
+ function readBootResumeSentinel(path3, opts = {}) {
106816
+ let raw;
106817
+ try {
106818
+ if (!existsSync62(path3))
106819
+ return { present: false, stale: false };
106820
+ raw = readFileSync64(path3, "utf8");
106821
+ } catch {
106822
+ return { present: false, stale: false };
106823
+ }
106824
+ let stamped = null;
106825
+ try {
106826
+ const parsed = JSON.parse(raw);
106827
+ if (parsed != null && typeof parsed === "object" && typeof parsed.boot === "string" && parsed.boot.length > 0) {
106828
+ stamped = parsed.boot;
106829
+ }
106830
+ } catch {}
106831
+ const live = containerBootIdentity(opts.procRoot);
106832
+ if (stamped != null && live != null && stamped !== live)
106833
+ return { present: true, stale: true };
106834
+ return { present: true, stale: false };
106835
+ }
106836
+ function sweepStrayTmps(path3) {
106837
+ const prefix = `${basename18(path3)}.tmp.`;
106838
+ try {
106839
+ for (const name of readdirSync16(dirname28(path3))) {
106840
+ if (!name.startsWith(prefix))
106841
+ continue;
106842
+ try {
106843
+ unlinkSync30(join76(dirname28(path3), name));
106844
+ } catch {}
106845
+ }
106846
+ } catch {}
106847
+ }
106848
+ function markBootResumeComplete(stateDir, opts = {}) {
106849
+ const path3 = opts.path ?? bootResumeDonePath(stateDir);
106850
+ const tmp = `${path3}.tmp.${process.pid}`;
106851
+ const boot = containerBootIdentity(opts.procRoot);
106852
+ try {
106853
+ const token = { pid: process.pid, at: opts.now ?? Date.now() };
106854
+ if (boot != null)
106855
+ token.boot = boot;
106856
+ writeFileSync52(tmp, JSON.stringify(token) + `
106857
+ `);
106858
+ renameSync30(tmp, path3);
106859
+ sweepStrayTmps(path3);
106860
+ } catch (err) {
106861
+ try {
106862
+ unlinkSync30(tmp);
106863
+ } catch {}
106864
+ const log = opts.log ?? ((s) => process.stderr.write(s));
106865
+ log(`telegram gateway: boot: could not stamp ${BOOT_RESUME_DONE_FILE} ` + `(${err.message}) \u2014 a gateway respawn may repeat the boot resume (#4641)
106866
+ `);
106867
+ }
106868
+ }
106869
+ function decideGatewayOnlyRespawn(input) {
106870
+ const { sentinelPresent, sentinelStale, record: record2, live } = input;
106871
+ if (!sentinelPresent) {
106872
+ return { gatewayOnly: false, reason: "no-boot-resume-sentinel", pid: record2?.pid ?? null };
106873
+ }
106874
+ if (sentinelStale === true) {
106875
+ return { gatewayOnly: false, reason: "stale-boot-token", pid: record2?.pid ?? null };
106876
+ }
106877
+ if (record2 == null) {
106878
+ return { gatewayOnly: true, reason: "gateway-only-respawn-no-record", pid: null };
106879
+ }
106880
+ if (live == null)
106881
+ return { gatewayOnly: false, reason: "agent-process-dead", pid: record2.pid };
106882
+ if (live.starttime !== record2.starttime) {
106883
+ return { gatewayOnly: false, reason: "starttime-mismatch", pid: record2.pid };
106884
+ }
106885
+ if (record2.comm != null && record2.comm !== live.comm) {
106886
+ return { gatewayOnly: false, reason: "comm-mismatch", pid: record2.pid };
106887
+ }
106888
+ return { gatewayOnly: true, reason: "gateway-only-respawn", pid: record2.pid };
106889
+ }
106890
+ function detectGatewayOnlyRespawn(opts) {
106891
+ if (opts.enabled === false)
106892
+ return { gatewayOnly: false, reason: "guard-disabled", pid: null };
106893
+ const procRoot = opts.procRoot ?? "/proc";
106894
+ const sentinel = readBootResumeSentinel(opts.sentinelPath ?? bootResumeDonePath(opts.stateDir), { procRoot });
106895
+ const recordPath2 = opts.recordPath ?? join76(opts.stateDir, AGENT_PROCESS_RECORD_FILE);
106896
+ const record2 = readAgentProcessRecord(recordPath2);
106897
+ const live = record2 == null ? null : readProcIdentity(record2.pid, procRoot);
106898
+ return decideGatewayOnlyRespawn({
106899
+ sentinelPresent: sentinel.present,
106900
+ sentinelStale: sentinel.stale,
106901
+ record: record2,
106902
+ live
106903
+ });
106904
+ }
106905
+ function shouldSkipBootResumeForGatewayOnlyRespawn(stateDir, opts = {}) {
106906
+ const log = opts.log ?? ((s) => process.stderr.write(s));
106907
+ let decision;
106908
+ try {
106909
+ decision = detectGatewayOnlyRespawn({
106910
+ ...opts,
106911
+ stateDir,
106912
+ enabled: opts.enabled ?? process.env.SWITCHROOM_GATEWAY_RESPAWN_GUARD !== "0"
106913
+ });
106914
+ } catch (err) {
106915
+ log(`telegram gateway: boot: agent-liveness probe failed (${err.message}) \u2014 assuming agent restart
106916
+ `);
106917
+ return false;
106918
+ }
106919
+ if (decision.gatewayOnly) {
106920
+ log(`telegram gateway: boot: GATEWAY-ONLY respawn \u2014 this container generation's boot resume is already ` + `done (${BOOT_RESUME_DONE_FILE} present, reason=${decision.reason}, agent pid=${decision.pid ?? "unrecorded"}). ` + `Skipping the orphan-turn reaper, the bridge-dead marker, the resume synthetic, crash-redelivery capture ` + `and .pending-turn.env (#4641): the claude session, its in-flight turn and its sub-agents were never interrupted.
106921
+ `);
106922
+ return true;
106923
+ }
106924
+ log(`telegram gateway: boot: agent-liveness probe \u2192 treating as agent restart (reason=${decision.reason})
106925
+ `);
106926
+ return false;
106927
+ }
106928
+
106319
106929
  // gateway/bridge-dead-watchdog.ts
106320
- import { readFileSync as readFileSync64, writeFileSync as writeFileSync51, renameSync as renameSync29, unlinkSync as unlinkSync29 } from "node:fs";
106930
+ import { readFileSync as readFileSync65, writeFileSync as writeFileSync53, renameSync as renameSync31, unlinkSync as unlinkSync31 } from "node:fs";
106321
106931
 
106322
106932
  // gateway/cron-session.ts
106323
106933
  var CRON_IDENTITY_SUFFIX2 = "-cron";
@@ -106350,7 +106960,7 @@ function readFreshCrashLogTail(path3, opts = {}) {
106350
106960
  const nowMs3 = opts.nowMs ?? Date.now();
106351
106961
  const freshWindowMs = opts.freshWindowMs ?? CRASH_LOG_FRESH_WINDOW_MS;
106352
106962
  const maxLines = opts.maxLines ?? CRASH_LOG_TAIL_LINES;
106353
- const readFile = opts.readFile ?? ((p) => readFileSync64(p, "utf8"));
106963
+ const readFile = opts.readFile ?? ((p) => readFileSync65(p, "utf8"));
106354
106964
  let raw;
106355
106965
  try {
106356
106966
  raw = readFile(path3);
@@ -106371,13 +106981,13 @@ function readFreshCrashLogTail(path3, opts = {}) {
106371
106981
  }
106372
106982
  function writeBridgeDeadEscalationMarker(path3, marker) {
106373
106983
  const tmp = `${path3}.tmp-${process.pid}-${Date.now()}`;
106374
- writeFileSync51(tmp, JSON.stringify(marker), "utf8");
106375
- renameSync29(tmp, path3);
106984
+ writeFileSync53(tmp, JSON.stringify(marker), "utf8");
106985
+ renameSync31(tmp, path3);
106376
106986
  }
106377
106987
  function consumeBridgeDeadEscalationMarker(path3, nowMs3 = Date.now(), maxAgeMs = ESCALATION_MARKER_MAX_AGE_MS) {
106378
106988
  let marker = null;
106379
106989
  try {
106380
- const parsed = JSON.parse(readFileSync64(path3, "utf8"));
106990
+ const parsed = JSON.parse(readFileSync65(path3, "utf8"));
106381
106991
  if (typeof parsed.ts === "number" && Number.isFinite(parsed.ts) && typeof parsed.reason === "string") {
106382
106992
  const age = nowMs3 - parsed.ts;
106383
106993
  if (age >= 0 && age < maxAgeMs) {
@@ -106389,7 +106999,7 @@ function consumeBridgeDeadEscalationMarker(path3, nowMs3 = Date.now(), maxAgeMs
106389
106999
  }
106390
107000
  } catch {}
106391
107001
  try {
106392
- unlinkSync29(path3);
107002
+ unlinkSync31(path3);
106393
107003
  } catch {}
106394
107004
  return marker;
106395
107005
  }
@@ -106530,7 +107140,7 @@ function createBridgeDeadWatchdog(opts) {
106530
107140
  }
106531
107141
 
106532
107142
  // gateway/boot-probes.ts
106533
- import { readFileSync as readFileSync65, readdirSync as readdirSync16, existsSync as existsSync62 } from "fs";
107143
+ import { readFileSync as readFileSync66, readdirSync as readdirSync17, existsSync as existsSync63 } from "fs";
106534
107144
  init_quota_cache();
106535
107145
  init_generation_stamp();
106536
107146
  init_quota_check();
@@ -106538,8 +107148,8 @@ import { execFile as execFileCb2 } from "child_process";
106538
107148
  import { promisify as promisify2 } from "util";
106539
107149
  var execFile2 = promisify2(execFileCb2);
106540
107150
  var realProcFs2 = {
106541
- readdir: (p) => readdirSync16(p),
106542
- readFile: (p) => readFileSync65(p, "utf-8")
107151
+ readdir: (p) => readdirSync17(p),
107152
+ readFile: (p) => readFileSync66(p, "utf-8")
106543
107153
  };
106544
107154
  function findAgentProcessInContainer2(fs4 = realProcFs2) {
106545
107155
  let entries;
@@ -106840,7 +107450,7 @@ if (isGatewayMain) {
106840
107450
  shutdownAnalytics();
106841
107451
  });
106842
107452
  }
106843
- var STATE_DIR = process.env.TELEGRAM_STATE_DIR ?? join76(homedir22(), ".claude", "channels", "telegram");
107453
+ var STATE_DIR = process.env.TELEGRAM_STATE_DIR ?? join77(homedir22(), ".claude", "channels", "telegram");
106844
107454
  var permCardStore = createPermissionCardStore(STATE_DIR);
106845
107455
  var BLOCKED_APPROVALS_DIR = process.env.SWITCHROOM_BLOCKED_APPROVALS_DIR ?? "/state/blocked-approvals";
106846
107456
  var AGENT_NAME = process.env.SWITCHROOM_AGENT_NAME ?? "agent";
@@ -106879,7 +107489,7 @@ function alwaysAllowDrainDeps() {
106879
107489
  return {
106880
107490
  readConfigText: () => {
106881
107491
  const cfgPath = process.env.SWITCHROOM_CONFIG ?? SWITCHROOM_CONFIG ?? findConfigFile2();
106882
- return readFileSync66(cfgPath, "utf8");
107492
+ return readFileSync67(cfgPath, "utf8");
106883
107493
  },
106884
107494
  resolveAllowList: (_configText, agentName3) => {
106885
107495
  const cfg = loadConfig2();
@@ -106940,11 +107550,11 @@ function scheduleAlwaysAllowPersistDrain() {
106940
107550
  }, ALWAYS_ALLOW_DRAIN_INTERVAL_MS);
106941
107551
  timer3.unref?.();
106942
107552
  }
106943
- var ACCESS_FILE = join76(STATE_DIR, "access.json");
106944
- var APPROVED_DIR = join76(STATE_DIR, "approved");
106945
- var ENV_FILE = join76(STATE_DIR, ".env");
106946
- var INBOX_DIR = join76(STATE_DIR, "inbox");
106947
- var PEOPLE_FILE = join76(STATE_DIR, "people.json");
107553
+ var ACCESS_FILE = join77(STATE_DIR, "access.json");
107554
+ var APPROVED_DIR = join77(STATE_DIR, "approved");
107555
+ var ENV_FILE = join77(STATE_DIR, ".env");
107556
+ var INBOX_DIR = join77(STATE_DIR, "inbox");
107557
+ var PEOPLE_FILE = join77(STATE_DIR, "people.json");
106948
107558
  function triggerSelfRestart(targetAgent, reason, delayMs = 300) {
106949
107559
  const isDocker = process.env.SWITCHROOM_RUNTIME === "docker";
106950
107560
  const selfAgent = process.env.SWITCHROOM_AGENT_NAME;
@@ -107009,7 +107619,7 @@ function formatBootVersion() {
107009
107619
  }
107010
107620
  try {
107011
107621
  chmodSync14(ENV_FILE, 384);
107012
- for (const line of readFileSync66(ENV_FILE, "utf8").split(`
107622
+ for (const line of readFileSync67(ENV_FILE, "utf8").split(`
107013
107623
  `)) {
107014
107624
  const m = line.match(/^(\w+)=(.*)$/);
107015
107625
  if (m && process.env[m[1]] === undefined)
@@ -107030,7 +107640,7 @@ var bot;
107030
107640
  var lastGetUpdatesHeartbeatMs = Date.now();
107031
107641
  var GRAMMY_VERSION = (() => {
107032
107642
  try {
107033
- const raw = readFileSync66(new URL("../../node_modules/grammy/package.json", import.meta.url), "utf8");
107643
+ const raw = readFileSync67(new URL("../../node_modules/grammy/package.json", import.meta.url), "utf8");
107034
107644
  return JSON.parse(raw).version ?? "unknown";
107035
107645
  } catch {
107036
107646
  return "unknown";
@@ -107071,7 +107681,7 @@ function assertSendable(f) {
107071
107681
  } catch {
107072
107682
  throw new Error(`refusing to send file \u2014 cannot resolve real path: ${f}`);
107073
107683
  }
107074
- const inbox = join76(stateReal, "inbox");
107684
+ const inbox = join77(stateReal, "inbox");
107075
107685
  if (real.startsWith(stateReal + sep6) && !real.startsWith(inbox + sep6)) {
107076
107686
  throw new Error(`refusing to send channel state: ${f}`);
107077
107687
  }
@@ -107100,7 +107710,7 @@ var HISTORY_ENABLED = HISTORY_ACCESS.historyEnabled !== false;
107100
107710
  if (isGatewayMain && HISTORY_ENABLED) {
107101
107711
  try {
107102
107712
  initHistory(STATE_DIR, HISTORY_ACCESS.historyRetentionDays ?? 30);
107103
- process.stderr.write(`telegram gateway: history capture enabled at ${join76(STATE_DIR, "history.db")}
107713
+ process.stderr.write(`telegram gateway: history capture enabled at ${join77(STATE_DIR, "history.db")}
107104
107714
  `);
107105
107715
  } catch (err) {
107106
107716
  process.stderr.write(`telegram gateway: history init failed (${err.message}) \u2014 capture disabled
@@ -107111,174 +107721,179 @@ var turnsDb = null;
107111
107721
  var bootResumeInbound = null;
107112
107722
  var pendingRedelivery = null;
107113
107723
  var bridgeDeadPriorStreak = 0;
107114
- if (isGatewayMain)
107115
- try {
107116
- const agentDir = STATE_DIR.endsWith("/telegram") ? STATE_DIR.slice(0, -"/telegram".length) : STATE_DIR;
107117
- turnsDb = openTurnsDb(agentDir);
107118
- applySubagentsSchema(turnsDb);
107119
- let markerTurnKey = null;
107120
- let markerAgeMs = null;
107724
+ var bootResumeThrew = false;
107725
+ bootResumeInit:
107726
+ if (isGatewayMain)
107121
107727
  try {
107122
- const markerPath = join76(STATE_DIR, TURN_ACTIVE_MARKER_FILE2);
107123
- if (existsSync64(markerPath)) {
107124
- const st = statSync25(markerPath);
107125
- markerAgeMs = Date.now() - st.mtimeMs;
107126
- try {
107127
- const payload = JSON.parse(readFileSync66(markerPath, "utf8"));
107128
- if (typeof payload.turnKey === "string" && payload.turnKey.length > 0) {
107129
- markerTurnKey = payload.turnKey;
107130
- }
107131
- } catch {}
107132
- }
107133
- } catch {}
107134
- const hangSecs = Number(process.env.TURN_HANG_SECS);
107135
- const hangThresholdMs = (Number.isFinite(hangSecs) && hangSecs > 0 ? hangSecs : 300) * 1000;
107136
- const reasonSnapshot = markerAgeMs != null ? JSON.stringify({ idleMs: Math.round(markerAgeMs) }) : null;
107137
- const { reaped, timeoutTurnKey } = markOrphanedWithTimeoutClassification(turnsDb, {
107138
- markerTurnKey,
107139
- markerAgeMs,
107140
- hangThresholdMs,
107141
- reasonSnapshot
107142
- });
107143
- if (reaped > 0) {
107144
- process.stderr.write(`telegram gateway: turn-registry boot-reaper stamped ${reaped} orphaned turn(s)` + `${timeoutTurnKey ? ` (turnKey=${timeoutTurnKey} as 'timeout', markerAgeMs=${markerAgeMs})` : " as 'restart'"}
107145
- `);
107146
- } else {
107147
- process.stderr.write(`telegram gateway: turn-registry initialized at ${join76(agentDir, "telegram", "registry.db")}
107148
- `);
107149
- }
107150
- const bridgeDeadMarker = consumeBridgeDeadEscalationMarker(join76(STATE_DIR, "bridge-dead-escalation.json"));
107151
- if (bridgeDeadMarker != null) {
107152
- bridgeDeadPriorStreak = bridgeDeadMarker.count ?? 1;
107153
- process.stderr.write(`telegram gateway: boot: prior restart was a bridge-dead escalation (reason=${bridgeDeadMarker.reason}` + `, consecutive=${bridgeDeadPriorStreak}` + `${bridgeDeadMarker.crashTail ? `, crashTail=${bridgeDeadMarker.crashTail}` : ""})
107154
- `);
107155
- }
107156
- const bridgeDeadRestartCause = bridgeDeadMarker != null ? {
107157
- reason: bridgeDeadMarker.reason,
107158
- note: "The framework itself triggered this restart: your Telegram MCP bridge process had died " + "(chat tools were unavailable \u2014 you could not send replies), so the container was bounced " + "to restore the chat surface. This was NOT an operator-initiated restart and NOT a hang-watchdog kill."
107159
- } : undefined;
107160
- const pending2 = findLatestTurnIfInterrupted(turnsDb);
107161
- const selfAgent = process.env.SWITCHROOM_AGENT_NAME ?? "";
107162
- if (pending2 != null && selfAgent) {
107163
- const bootResumeMarkerPath = process.env.SWITCHROOM_GATEWAY_CLEAN_SHUTDOWN_MARKER ?? join76(STATE_DIR, "clean-shutdown.json");
107164
- const bootResumeCleanMarker = readCleanShutdownMarker(bootResumeMarkerPath);
107165
- const bootResumeForceAlways = process.env.SWITCHROOM_BOOT_RESUME_ALWAYS === "1";
107166
- const bootResumeMode = parseBootResumeMode(process.env.SWITCHROOM_BOOT_RESUME);
107167
- const bootResumeSuppressed = shouldSuppressBootResume(bootResumeCleanMarker, Date.now(), {
107168
- forceAlways: bootResumeForceAlways,
107169
- mode: bootResumeMode
107170
- });
107171
- const RESUME_MAX_AGE_MS = (() => {
107172
- const v = Number(process.env.SWITCHROOM_RESUME_MAX_AGE_MS);
107173
- return Number.isFinite(v) && v > 0 ? v : 10800000;
107174
- })();
107175
- const bootResumeKind = decideBootResumeKind({
107176
- pending: pending2,
107177
- suppressed: bootResumeSuppressed,
107178
- ageMs: Math.max(0, Date.now() - pending2.started_at),
107179
- maxAgeMs: RESUME_MAX_AGE_MS
107180
- });
107181
- const redeliverCapture = decideRedeliverCapture({
107182
- willBeResumed: bootResumeKind === "resume",
107183
- hasSessionId: Boolean(pending2.session_id)
107728
+ const agentDir = STATE_DIR.endsWith("/telegram") ? STATE_DIR.slice(0, -"/telegram".length) : STATE_DIR;
107729
+ turnsDb = openTurnsDb(agentDir);
107730
+ applySubagentsSchema(turnsDb);
107731
+ if (shouldSkipBootResumeForGatewayOnlyRespawn(STATE_DIR))
107732
+ break bootResumeInit;
107733
+ let markerTurnKey = null;
107734
+ let markerAgeMs = null;
107735
+ try {
107736
+ const markerPath = join77(STATE_DIR, TURN_ACTIVE_MARKER_FILE2);
107737
+ if (existsSync65(markerPath)) {
107738
+ const st = statSync25(markerPath);
107739
+ markerAgeMs = Date.now() - st.mtimeMs;
107740
+ try {
107741
+ const payload = JSON.parse(readFileSync67(markerPath, "utf8"));
107742
+ if (typeof payload.turnKey === "string" && payload.turnKey.length > 0) {
107743
+ markerTurnKey = payload.turnKey;
107744
+ }
107745
+ } catch {}
107746
+ }
107747
+ } catch {}
107748
+ const hangSecs = Number(process.env.TURN_HANG_SECS);
107749
+ const hangThresholdMs = (Number.isFinite(hangSecs) && hangSecs > 0 ? hangSecs : 300) * 1000;
107750
+ const reasonSnapshot = markerAgeMs != null ? JSON.stringify({ idleMs: Math.round(markerAgeMs) }) : null;
107751
+ const { reaped, timeoutTurnKey } = markOrphanedWithTimeoutClassification(turnsDb, {
107752
+ markerTurnKey,
107753
+ markerAgeMs,
107754
+ hangThresholdMs,
107755
+ reasonSnapshot
107184
107756
  });
107185
- if (redeliverCapture.capture) {
107186
- pendingRedelivery = { turn: pending2, maxAgeMs: RESUME_MAX_AGE_MS };
107187
- } else if (redeliverCapture.skipReason === "will-be-resumed") {
107188
- process.stderr.write(`telegram gateway: crash-redelivery suppressed \u2014 interrupted turnKey=${pending2.turn_key} will be ` + `RESUMED (bootResumeKind=resume); the fresh re-answer supersedes the recovered draft (no double-send)
107757
+ if (reaped > 0) {
107758
+ process.stderr.write(`telegram gateway: turn-registry boot-reaper stamped ${reaped} orphaned turn(s)` + `${timeoutTurnKey ? ` (turnKey=${timeoutTurnKey} as 'timeout', markerAgeMs=${markerAgeMs})` : " as 'restart'"}
107189
107759
  `);
107190
107760
  } else {
107191
- process.stderr.write(`telegram gateway: crash-redelivery skipped \u2014 interrupted turnKey=${pending2.turn_key} has no ` + `pinned session_id (pre-feature turn or no session event seen); cannot resolve exact transcript
107761
+ process.stderr.write(`telegram gateway: turn-registry initialized at ${join77(agentDir, "telegram", "registry.db")}
107192
107762
  `);
107193
107763
  }
107194
- let interruptedSubagents = [];
107195
- try {
107196
- interruptedSubagents = listNonTerminalSubagentsForTurn(turnsDb, pending2.turn_key).map((s) => ({ agentType: s.agent_type, description: s.description, status: s.status }));
107197
- } catch (err) {
107198
- process.stderr.write(`telegram gateway: boot-resume subagent lookup failed (${err.message}) \u2014 continuing without worker list
107764
+ const bridgeDeadMarker = consumeBridgeDeadEscalationMarker(join77(STATE_DIR, "bridge-dead-escalation.json"));
107765
+ if (bridgeDeadMarker != null) {
107766
+ bridgeDeadPriorStreak = bridgeDeadMarker.count ?? 1;
107767
+ process.stderr.write(`telegram gateway: boot: prior restart was a bridge-dead escalation (reason=${bridgeDeadMarker.reason}` + `, consecutive=${bridgeDeadPriorStreak}` + `${bridgeDeadMarker.crashTail ? `, crashTail=${bridgeDeadMarker.crashTail}` : ""})
107199
107768
  `);
107200
107769
  }
107201
- if (bootResumeKind === "resume") {
107202
- bootResumeInbound = {
107203
- agent: selfAgent,
107204
- msg: buildResumeInterruptedInbound({
107205
- turn: pending2,
107206
- subagents: interruptedSubagents,
107207
- restartCause: bridgeDeadRestartCause
107208
- })
107209
- };
107210
- } else if (bootResumeKind === "report") {
107211
- let idleMs = pending2.turn_key === timeoutTurnKey && markerAgeMs != null ? markerAgeMs : null;
107212
- if (idleMs == null && pending2.interrupt_reason) {
107213
- try {
107214
- const parsed = JSON.parse(pending2.interrupt_reason);
107215
- if (typeof parsed.idleMs === "number" && Number.isFinite(parsed.idleMs))
107216
- idleMs = parsed.idleMs;
107217
- } catch {}
107770
+ const bridgeDeadRestartCause = bridgeDeadMarker != null ? {
107771
+ reason: bridgeDeadMarker.reason,
107772
+ note: "The framework itself triggered this restart: your Telegram MCP bridge process had died " + "(chat tools were unavailable \u2014 you could not send replies), so the container was bounced " + "to restore the chat surface. This was NOT an operator-initiated restart and NOT a hang-watchdog kill."
107773
+ } : undefined;
107774
+ const pending2 = findLatestTurnIfInterrupted(turnsDb);
107775
+ const selfAgent = process.env.SWITCHROOM_AGENT_NAME ?? "";
107776
+ if (pending2 != null && selfAgent) {
107777
+ const bootResumeMarkerPath = process.env.SWITCHROOM_GATEWAY_CLEAN_SHUTDOWN_MARKER ?? join77(STATE_DIR, "clean-shutdown.json");
107778
+ const bootResumeCleanMarker = readCleanShutdownMarker(bootResumeMarkerPath);
107779
+ const bootResumeForceAlways = process.env.SWITCHROOM_BOOT_RESUME_ALWAYS === "1";
107780
+ const bootResumeMode = parseBootResumeMode(process.env.SWITCHROOM_BOOT_RESUME);
107781
+ const bootResumeSuppressed = shouldSuppressBootResume(bootResumeCleanMarker, Date.now(), {
107782
+ forceAlways: bootResumeForceAlways,
107783
+ mode: bootResumeMode
107784
+ });
107785
+ const RESUME_MAX_AGE_MS = (() => {
107786
+ const v = Number(process.env.SWITCHROOM_RESUME_MAX_AGE_MS);
107787
+ return Number.isFinite(v) && v > 0 ? v : 10800000;
107788
+ })();
107789
+ const bootResumeKind = decideBootResumeKind({
107790
+ pending: pending2,
107791
+ suppressed: bootResumeSuppressed,
107792
+ ageMs: Math.max(0, Date.now() - pending2.started_at),
107793
+ maxAgeMs: RESUME_MAX_AGE_MS
107794
+ });
107795
+ const redeliverCapture = decideRedeliverCapture({
107796
+ willBeResumed: bootResumeKind === "resume",
107797
+ hasSessionId: Boolean(pending2.session_id)
107798
+ });
107799
+ if (redeliverCapture.capture) {
107800
+ pendingRedelivery = { turn: pending2, maxAgeMs: RESUME_MAX_AGE_MS };
107801
+ } else if (redeliverCapture.skipReason === "will-be-resumed") {
107802
+ process.stderr.write(`telegram gateway: crash-redelivery suppressed \u2014 interrupted turnKey=${pending2.turn_key} will be ` + `RESUMED (bootResumeKind=resume); the fresh re-answer supersedes the recovered draft (no double-send)
107803
+ `);
107804
+ } else {
107805
+ process.stderr.write(`telegram gateway: crash-redelivery skipped \u2014 interrupted turnKey=${pending2.turn_key} has no ` + `pinned session_id (pre-feature turn or no session event seen); cannot resolve exact transcript
107806
+ `);
107218
107807
  }
107219
- if (idleMs == null)
107220
- idleMs = Math.max(0, Date.now() - pending2.started_at);
107221
- bootResumeInbound = {
107222
- agent: selfAgent,
107223
- msg: buildResumeWatchdogReportInbound({
107224
- turn: pending2,
107225
- idleMs,
107226
- subagents: interruptedSubagents,
107227
- restartCause: bridgeDeadRestartCause
107228
- })
107229
- };
107230
- } else if (bootResumeKind === "defer-loop" || bootResumeKind === "defer-suppressed") {
107231
- bootResumeInbound = {
107232
- agent: selfAgent,
107233
- msg: buildResumeDeferredReportInbound({
107234
- turn: pending2,
107235
- reason: bootResumeKind === "defer-loop" ? "loop-guard" : "clean-restart-suppressed",
107236
- subagents: interruptedSubagents,
107237
- restartCause: bridgeDeadRestartCause
107238
- })
107239
- };
107240
- }
107241
- if (bootResumeKind === "defer-suppressed") {
107242
- process.stderr.write(`telegram gateway: boot-resume suppressed (clean shutdown` + `${bootResumeCleanMarker?.reason ? ` reason=${JSON.stringify(bootResumeCleanMarker.reason)}` : ""}` + `, mode=${bootResumeMode}) \u2014 passive report delivered for turnKey=${pending2.turn_key}
107808
+ let interruptedSubagents = [];
107809
+ try {
107810
+ interruptedSubagents = listNonTerminalSubagentsForTurn(turnsDb, pending2.turn_key).map((s) => ({ agentType: s.agent_type, description: s.description, status: s.status }));
107811
+ } catch (err) {
107812
+ process.stderr.write(`telegram gateway: boot-resume subagent lookup failed (${err.message}) \u2014 continuing without worker list
107243
107813
  `);
107244
- } else if (bootResumeKind === "defer-loop") {
107245
- process.stderr.write(`telegram gateway: boot-resume loop-guard tripped (interrupted turn was itself a resume) ` + `\u2014 passive report delivered instead of re-resuming turnKey=${pending2.turn_key}
107814
+ }
107815
+ if (bootResumeKind === "resume") {
107816
+ bootResumeInbound = {
107817
+ agent: selfAgent,
107818
+ msg: buildResumeInterruptedInbound({
107819
+ turn: pending2,
107820
+ subagents: interruptedSubagents,
107821
+ restartCause: bridgeDeadRestartCause
107822
+ })
107823
+ };
107824
+ } else if (bootResumeKind === "report") {
107825
+ let idleMs = pending2.turn_key === timeoutTurnKey && markerAgeMs != null ? markerAgeMs : null;
107826
+ if (idleMs == null && pending2.interrupt_reason) {
107827
+ try {
107828
+ const parsed = JSON.parse(pending2.interrupt_reason);
107829
+ if (typeof parsed.idleMs === "number" && Number.isFinite(parsed.idleMs))
107830
+ idleMs = parsed.idleMs;
107831
+ } catch {}
107832
+ }
107833
+ if (idleMs == null)
107834
+ idleMs = Math.max(0, Date.now() - pending2.started_at);
107835
+ bootResumeInbound = {
107836
+ agent: selfAgent,
107837
+ msg: buildResumeWatchdogReportInbound({
107838
+ turn: pending2,
107839
+ idleMs,
107840
+ subagents: interruptedSubagents,
107841
+ restartCause: bridgeDeadRestartCause
107842
+ })
107843
+ };
107844
+ } else if (bootResumeKind === "defer-loop" || bootResumeKind === "defer-suppressed") {
107845
+ bootResumeInbound = {
107846
+ agent: selfAgent,
107847
+ msg: buildResumeDeferredReportInbound({
107848
+ turn: pending2,
107849
+ reason: bootResumeKind === "defer-loop" ? "loop-guard" : "clean-restart-suppressed",
107850
+ subagents: interruptedSubagents,
107851
+ restartCause: bridgeDeadRestartCause
107852
+ })
107853
+ };
107854
+ }
107855
+ if (bootResumeKind === "defer-suppressed") {
107856
+ process.stderr.write(`telegram gateway: boot-resume suppressed (clean shutdown` + `${bootResumeCleanMarker?.reason ? ` reason=${JSON.stringify(bootResumeCleanMarker.reason)}` : ""}` + `, mode=${bootResumeMode}) \u2014 passive report delivered for turnKey=${pending2.turn_key}
107246
107857
  `);
107247
- }
107248
- if (bootResumeInbound != null) {
107249
- process.stderr.write(`telegram gateway: boot-resume queued kind=${bootResumeKind} mode=${bootResumeMode} ` + `turnKey=${pending2.turn_key} endedVia=${pending2.ended_via ?? "open"} chat=${pending2.chat_id}
107858
+ } else if (bootResumeKind === "defer-loop") {
107859
+ process.stderr.write(`telegram gateway: boot-resume loop-guard tripped (interrupted turn was itself a resume) ` + `\u2014 passive report delivered instead of re-resuming turnKey=${pending2.turn_key}
107250
107860
  `);
107251
- }
107252
- }
107253
- if (bridgeDeadMarker != null && bootResumeInbound == null && selfAgent) {
107254
- const idleNoticeChat = (() => {
107255
- try {
107256
- return loadAccess().allowFrom[0] ?? null;
107257
- } catch {
107258
- return null;
107259
107861
  }
107260
- })();
107261
- if (idleNoticeChat != null) {
107262
- bootResumeInbound = {
107263
- agent: selfAgent,
107264
- msg: buildBridgeDeadIdleNoticeInbound({
107265
- chatId: String(idleNoticeChat),
107266
- marker: bridgeDeadMarker
107267
- })
107268
- };
107269
- process.stderr.write(`telegram gateway: boot: bridge-dead idle notice queued chat=${idleNoticeChat} (no turn was in flight)
107862
+ if (bootResumeInbound != null) {
107863
+ process.stderr.write(`telegram gateway: boot-resume queued kind=${bootResumeKind} mode=${bootResumeMode} ` + `turnKey=${pending2.turn_key} endedVia=${pending2.ended_via ?? "open"} chat=${pending2.chat_id}
107270
107864
  `);
107271
- } else {
107272
- process.stderr.write(`telegram gateway: boot: bridge-dead idle notice skipped \u2014 no allowFrom chat to surface it in
107865
+ }
107866
+ }
107867
+ if (bridgeDeadMarker != null && bootResumeInbound == null && selfAgent) {
107868
+ const idleNoticeChat = (() => {
107869
+ try {
107870
+ return loadAccess().allowFrom[0] ?? null;
107871
+ } catch {
107872
+ return null;
107873
+ }
107874
+ })();
107875
+ if (idleNoticeChat != null) {
107876
+ bootResumeInbound = {
107877
+ agent: selfAgent,
107878
+ msg: buildBridgeDeadIdleNoticeInbound({
107879
+ chatId: String(idleNoticeChat),
107880
+ marker: bridgeDeadMarker
107881
+ })
107882
+ };
107883
+ process.stderr.write(`telegram gateway: boot: bridge-dead idle notice queued chat=${idleNoticeChat} (no turn was in flight)
107884
+ `);
107885
+ } else {
107886
+ process.stderr.write(`telegram gateway: boot: bridge-dead idle notice skipped \u2014 no allowFrom chat to surface it in
107273
107887
  `);
107888
+ }
107274
107889
  }
107275
- }
107276
- writePendingTurnEnv(agentDir, pending2);
107277
- } catch (err) {
107278
- process.stderr.write(`telegram gateway: turn-registry init failed (${err.message}) \u2014 turn tracking disabled
107890
+ writePendingTurnEnv(agentDir, pending2);
107891
+ } catch (err) {
107892
+ process.stderr.write(`telegram gateway: turn-registry init failed (${err.message}) \u2014 turn tracking disabled
107279
107893
  `);
107280
- turnsDb = null;
107281
- }
107894
+ turnsDb = null;
107895
+ bootResumeThrew = true;
107896
+ }
107282
107897
  function resolveSubagentOriginChat(agentId) {
107283
107898
  if (turnsDb == null)
107284
107899
  return null;
@@ -107361,12 +107976,12 @@ if (isGatewayMain && !STATIC)
107361
107976
  function checkApprovals() {
107362
107977
  let files;
107363
107978
  try {
107364
- files = readdirSync18(APPROVED_DIR);
107979
+ files = readdirSync19(APPROVED_DIR);
107365
107980
  } catch {
107366
107981
  return;
107367
107982
  }
107368
107983
  for (const senderId of files) {
107369
- const file = join76(APPROVED_DIR, senderId);
107984
+ const file = join77(APPROVED_DIR, senderId);
107370
107985
  bot.api.sendMessage(senderId, "Paired! Say hi to Claude.").then(() => rmSync9(file, { force: true }), (err) => {
107371
107986
  process.stderr.write(`telegram gateway: failed to send approval confirm: ${err}
107372
107987
  `);
@@ -107544,15 +108159,15 @@ function noteAgentOutputAt(key, ts) {
107544
108159
  lastAgentOutputAt.delete(oldest);
107545
108160
  }
107546
108161
  }
107547
- var OBLIGATION_STORE_PATH = join76(STATE_DIR, "obligations.json");
108162
+ var OBLIGATION_STORE_PATH = join77(STATE_DIR, "obligations.json");
107548
108163
  var obligationStoreFs = {
107549
- readFileSync: (p) => readFileSync66(p, "utf8"),
108164
+ readFileSync: (p) => readFileSync67(p, "utf8"),
107550
108165
  writeFileSync: (p, d) => writeStateFileSync2(p, d),
107551
- renameSync: (a, b) => renameSync30(a, b),
107552
- existsSync: (p) => existsSync64(p),
108166
+ renameSync: (a, b) => renameSync32(a, b),
108167
+ existsSync: (p) => existsSync65(p),
107553
108168
  fsyncFileSync: fsyncPathSync,
107554
108169
  fsyncDirSync: fsyncPathSync,
107555
- unlinkSync: unlinkSync31
108170
+ unlinkSync: unlinkSync33
107556
108171
  };
107557
108172
  var obligationLedger = new ObligationLedger(OBLIGATION_REPRESENT_MAX, {
107558
108173
  onChange: STATIC || !OBLIGATION_LEDGER_ENABLED ? undefined : (snapshot) => persistObligations(OBLIGATION_STORE_PATH, obligationStoreFs, snapshot)
@@ -108311,7 +108926,7 @@ function emitTurnRecord(turn, endedAt) {
108311
108926
  return;
108312
108927
  }
108313
108928
  },
108314
- rename: (from, to) => renameSync30(from, to)
108929
+ rename: (from, to) => renameSync32(from, to)
108315
108930
  });
108316
108931
  appendFileSync11(turnsPath, rec);
108317
108932
  } catch {}
@@ -109882,28 +110497,28 @@ var PIN_STATUS_WHILE_WORKING = (() => {
109882
110497
  })();
109883
110498
  var statusPinClaims = new Map;
109884
110499
  var statusPinRightsCache = new PinRightsCache2;
109885
- var STATUS_PIN_STORE_PATH = join76(STATE_DIR, "status-pins.json");
110500
+ var STATUS_PIN_STORE_PATH = join77(STATE_DIR, "status-pins.json");
109886
110501
  var statusPinStoreFs = {
109887
- readFileSync: (p) => readFileSync66(p, "utf8"),
110502
+ readFileSync: (p) => readFileSync67(p, "utf8"),
109888
110503
  writeFileSync: (p, d) => writeStateFileSync2(p, d),
109889
- renameSync: (a, b) => renameSync30(a, b),
109890
- existsSync: (p) => existsSync64(p)
110504
+ renameSync: (a, b) => renameSync32(a, b),
110505
+ existsSync: (p) => existsSync65(p)
109891
110506
  };
109892
110507
  var statusPinPersistEnabled = !STATIC && PIN_STATUS_WHILE_WORKING;
109893
- var ACTIVITY_CARD_STORE_PATH = join76(STATE_DIR, "activity-cards-pending.json");
110508
+ var ACTIVITY_CARD_STORE_PATH = join77(STATE_DIR, "activity-cards-pending.json");
109894
110509
  var activityCardStoreFs = {
109895
- readFileSync: (p) => readFileSync66(p, "utf8"),
110510
+ readFileSync: (p) => readFileSync67(p, "utf8"),
109896
110511
  writeFileSync: (p, d) => writeStateFileSync2(p, d),
109897
- renameSync: (a, b) => renameSync30(a, b),
109898
- existsSync: (p) => existsSync64(p)
110512
+ renameSync: (a, b) => renameSync32(a, b),
110513
+ existsSync: (p) => existsSync65(p)
109899
110514
  };
109900
110515
  var activityCardPersistEnabled = !STATIC;
109901
- var QUEUED_CARD_STORE_PATH = join76(STATE_DIR, "queued-cards-pending.json");
110516
+ var QUEUED_CARD_STORE_PATH = join77(STATE_DIR, "queued-cards-pending.json");
109902
110517
  var queuedCardStoreFs = {
109903
- readFileSync: (p) => readFileSync66(p, "utf8"),
110518
+ readFileSync: (p) => readFileSync67(p, "utf8"),
109904
110519
  writeFileSync: (p, d) => writeStateFileSync2(p, d),
109905
- renameSync: (a, b) => renameSync30(a, b),
109906
- existsSync: (p) => existsSync64(p)
110520
+ renameSync: (a, b) => renameSync32(a, b),
110521
+ existsSync: (p) => existsSync65(p)
109907
110522
  };
109908
110523
  var queuedCardPersistEnabled = !STATIC;
109909
110524
  function persistQueuedCard(key, chatId, threadId, messageId) {
@@ -110186,11 +110801,11 @@ async function unpinAllStatusPins() {
110186
110801
  }
110187
110802
  }
110188
110803
  var stalePinSweepEligible = false;
110189
- var STALE_PIN_SWEEP_STORE_PATH = join76(STATE_DIR, "stale-pin-sweep.json");
110804
+ var STALE_PIN_SWEEP_STORE_PATH = join77(STATE_DIR, "stale-pin-sweep.json");
110190
110805
  var sweepStoreFs = {
110191
- readFileSync: (p) => readFileSync66(p, "utf-8"),
110806
+ readFileSync: (p) => readFileSync67(p, "utf-8"),
110192
110807
  writeFileSync: (p, data) => atomicWriteStateFileSync2(p, data, 384),
110193
- existsSync: (p) => existsSync64(p)
110808
+ existsSync: (p) => existsSync65(p)
110194
110809
  };
110195
110810
  var stalePinSweeper = createGatewayStalePinSweeper({
110196
110811
  telegram: { handle: () => lockedBot, call: robustApiCall },
@@ -110227,12 +110842,12 @@ var getPinnedProgressCardMessageId = null;
110227
110842
  var completeProgressCardTurn = null;
110228
110843
  var subagentWatcher = null;
110229
110844
  var workerActivityFeed = null;
110230
- var SOCKET_PATH = process.env.SWITCHROOM_GATEWAY_SOCKET ?? join76(STATE_DIR, "gateway.sock");
110845
+ var SOCKET_PATH = process.env.SWITCHROOM_GATEWAY_SOCKET ?? join77(STATE_DIR, "gateway.sock");
110231
110846
  if (isGatewayMain)
110232
110847
  mkdirStateSync2(STATE_DIR, { recursive: true, mode: 448 });
110233
- var GATEWAY_PID_PATH = process.env.SWITCHROOM_GATEWAY_PID_FILE ?? join76(STATE_DIR, "gateway.pid.json");
110234
- var GATEWAY_SESSION_MARKER_PATH = process.env.SWITCHROOM_GATEWAY_SESSION_MARKER ?? join76(STATE_DIR, "gateway-session.json");
110235
- var GATEWAY_CLEAN_SHUTDOWN_MARKER_PATH = process.env.SWITCHROOM_GATEWAY_CLEAN_SHUTDOWN_MARKER ?? join76(STATE_DIR, "clean-shutdown.json");
110848
+ var GATEWAY_PID_PATH = process.env.SWITCHROOM_GATEWAY_PID_FILE ?? join77(STATE_DIR, "gateway.pid.json");
110849
+ var GATEWAY_SESSION_MARKER_PATH = process.env.SWITCHROOM_GATEWAY_SESSION_MARKER ?? join77(STATE_DIR, "gateway-session.json");
110850
+ var GATEWAY_CLEAN_SHUTDOWN_MARKER_PATH = process.env.SWITCHROOM_GATEWAY_CLEAN_SHUTDOWN_MARKER ?? join77(STATE_DIR, "clean-shutdown.json");
110236
110851
  var GATEWAY_STARTED_AT_MS = Date.now();
110237
110852
  var BOOT_CARD_ENABLED = process.env.SWITCHROOM_BOOT_CARD !== "false";
110238
110853
  var activeBootCard = null;
@@ -110262,7 +110877,7 @@ function ensureIssuesCard(chatId, threadId) {
110262
110877
  bot: botApi,
110263
110878
  log: (msg) => process.stderr.write(`telegram gateway: ${msg}
110264
110879
  `),
110265
- persistPath: join76(stateDir, "issues-card.json")
110880
+ persistPath: join77(stateDir, "issues-card.json")
110266
110881
  });
110267
110882
  activeIssuesWatcher = startIssuesWatcher({
110268
110883
  stateDir,
@@ -110467,13 +111082,13 @@ if (isGatewayMain)
110467
111082
  var inboundSpool;
110468
111083
  if (isGatewayMain)
110469
111084
  inboundSpool = STATIC ? undefined : createInboundSpool({
110470
- path: join76(STATE_DIR, "inbound-spool.jsonl"),
111085
+ path: join77(STATE_DIR, "inbound-spool.jsonl"),
110471
111086
  fs: {
110472
111087
  appendFileSync: (p, d) => appendStateFileSync(p, d),
110473
- readFileSync: (p) => readFileSync66(p, "utf8"),
111088
+ readFileSync: (p) => readFileSync67(p, "utf8"),
110474
111089
  writeFileSync: (p, d) => writeStateFileSync2(p, d),
110475
- renameSync: (a, b) => renameSync30(a, b),
110476
- existsSync: (p) => existsSync64(p),
111090
+ renameSync: (a, b) => renameSync32(a, b),
111091
+ existsSync: (p) => existsSync65(p),
110477
111092
  statSizeSync: (p) => statSync25(p).size,
110478
111093
  fsyncFileSync: fsyncPathSync,
110479
111094
  fsyncDirSync: fsyncPathSync
@@ -110538,13 +111153,13 @@ async function maybeRedeliverUndeliveredAnswer() {
110538
111153
  let transcriptText;
110539
111154
  try {
110540
111155
  const projectsDir = getProjectsDirForCwd();
110541
- const path3 = join76(projectsDir, `${sessionId}.jsonl`);
110542
- if (!existsSync64(path3)) {
111156
+ const path3 = join77(projectsDir, `${sessionId}.jsonl`);
111157
+ if (!existsSync65(path3)) {
110543
111158
  process.stderr.write(`telegram gateway: crash-redelivery \u2014 transcript not found for turnKey=${turn.turn_key} session=${sessionId} (${path3}); skipping
110544
111159
  `);
110545
111160
  return;
110546
111161
  }
110547
- transcriptText = readFileSync66(path3, "utf8");
111162
+ transcriptText = readFileSync67(path3, "utf8");
110548
111163
  } catch (err) {
110549
111164
  process.stderr.write(`telegram gateway: crash-redelivery \u2014 transcript read failed turnKey=${turn.turn_key}: ${err.message}
110550
111165
  `);
@@ -110638,6 +111253,8 @@ if (isGatewayMain && bootResumeInbound != null) {
110638
111253
  }
110639
111254
  }
110640
111255
  }
111256
+ if (isGatewayMain && !bootResumeThrew)
111257
+ markBootResumeComplete(STATE_DIR);
110641
111258
  if (isGatewayMain && inboundSpool != null) {
110642
111259
  const replay = inboundSpool.liveEntries();
110643
111260
  for (const e of replay)
@@ -110711,8 +111328,8 @@ var bridgeDeadWatchdog = createBridgeDeadWatchdog({
110711
111328
  isSessionAlive: () => findAgentProcessInContainer2()?.comm === "claude",
110712
111329
  isShuttingDown: () => shuttingDown,
110713
111330
  escalate: (reason) => triggerSelfRestart(process.env.SWITCHROOM_AGENT_NAME ?? "", reason, 1500),
110714
- crashLogPath: join76(STATE_DIR, "bridge-crash.log"),
110715
- markerPath: join76(STATE_DIR, "bridge-dead-escalation.json"),
111331
+ crashLogPath: join77(STATE_DIR, "bridge-crash.log"),
111332
+ markerPath: join77(STATE_DIR, "bridge-dead-escalation.json"),
110716
111333
  log: (line) => process.stderr.write(`${line}
110717
111334
  `),
110718
111335
  priorStreak: bridgeDeadPriorStreak,
@@ -110819,8 +111436,8 @@ if (isGatewayMain)
110819
111436
  probeQuotaViaBroker: (t) => probeQuotaForBootCard(agentSlug, t),
110820
111437
  tmuxSupervisor: process.env.SWITCHROOM_TMUX_SUPERVISOR === "1",
110821
111438
  dockerMode: process.env.SWITCHROOM_RUNTIME === "docker",
110822
- configSnapshotPath: join76(resolvedAgentDirForCard, ".config-snapshot.json"),
110823
- bootCardStatePath: join76(resolvedAgentDirForCard, ".boot-card-msgid.json"),
111439
+ configSnapshotPath: join77(resolvedAgentDirForCard, ".config-snapshot.json"),
111440
+ bootCardStatePath: join77(resolvedAgentDirForCard, ".boot-card-msgid.json"),
110824
111441
  floodStatePath: FLOOD_STATE_PATH,
110825
111442
  ...updateOutcomeLine ? { updateOutcomeLine } : {}
110826
111443
  }, ackMsgId).then((handle) => {
@@ -110920,7 +111537,7 @@ if (isGatewayMain)
110920
111537
  if (turnsDb != null && msg.activeFile != null) {
110921
111538
  const stampKey = currentTurn?.registryKey ?? null;
110922
111539
  if (stampKey != null && stampKey !== lastSessionStampedTurnKey) {
110923
- const sessionId = basename18(msg.activeFile).replace(/\.jsonl$/, "");
111540
+ const sessionId = basename19(msg.activeFile).replace(/\.jsonl$/, "");
110924
111541
  if (sessionId) {
110925
111542
  try {
110926
111543
  stampTurnSessionId(turnsDb, stampKey, sessionId);
@@ -111418,10 +112035,10 @@ if (isGatewayMain)
111418
112035
  }
111419
112036
  },
111420
112037
  onPostSkillProposal(_client, msg) {
111421
- handlePostSkillProposal(msg, { bot, assertAllowedChat, swallowingApiCall });
112038
+ handlePostSkillProposal(msg, { bot, assertAllowedChat, swallowingApiCall, deliverResumeSyntheticOrBuffer });
111422
112039
  },
111423
112040
  onPostEvalCaseProposal(_client, msg) {
111424
- handlePostEvalCaseProposal(msg, { bot, assertAllowedChat, swallowingApiCall });
112041
+ handlePostEvalCaseProposal(msg, { bot, assertAllowedChat, swallowingApiCall, deliverResumeSyntheticOrBuffer });
111425
112042
  },
111426
112043
  onBuzzPublishResult: (_c, m) => getBuzzMirror()?.onPublishResult(m),
111427
112044
  log: (msg) => process.stderr.write(`telegram gateway: ipc \u2014 ${msg}
@@ -111454,7 +112071,7 @@ if (isGatewayMain)
111454
112071
  const receiverUid = receiverUidRaw ? Number(receiverUidRaw) : NaN;
111455
112072
  if (Number.isInteger(receiverUid))
111456
112073
  allowedUids.push(receiverUid);
111457
- const socketPath = join76(STATE_DIR, "webhook.sock");
112074
+ const socketPath = join77(STATE_DIR, "webhook.sock");
111458
112075
  const webhookInject = (agentName3, inbound) => {
111459
112076
  const msg = inbound;
111460
112077
  const delivered = ipcServer.sendToAgent(agentName3, msg);
@@ -111706,9 +112323,9 @@ function redactOutboundText(text5, site) {
111706
112323
  var VOICE_OUT_DEFAULT_CHUNK_CHARS = 600;
111707
112324
  var VOICE_OUT_HARD_CHUNK_CAP = 4096;
111708
112325
  var voiceOnDemandCache = new VoiceOnDemandCache({
111709
- persistPath: join76(STATE_DIR, "voice-ondemand.json")
112326
+ persistPath: join77(STATE_DIR, "voice-ondemand.json")
111710
112327
  });
111711
- var VOICE_CACHE_DIR = join76(STATE_DIR, "voice-cache");
112328
+ var VOICE_CACHE_DIR = join77(STATE_DIR, "voice-cache");
111712
112329
  var voicePreSynthQueue = new PreSynthQueue({
111713
112330
  runJob: async (job) => {
111714
112331
  const sidecarToken = await materializeSidecarToken2();
@@ -112116,11 +112733,11 @@ async function executeSendGif(rawArgs) {
112116
112733
  };
112117
112734
  }
112118
112735
  async function publishToTelegraph(text5, shortName, authorName) {
112119
- const accountPath = join76(STATE_DIR, "telegraph-account.json");
112736
+ const accountPath = join77(STATE_DIR, "telegraph-account.json");
112120
112737
  let account = null;
112121
112738
  try {
112122
- if (existsSync64(accountPath)) {
112123
- const raw = readFileSync66(accountPath, "utf-8");
112739
+ if (existsSync65(accountPath)) {
112740
+ const raw = readFileSync67(accountPath, "utf-8");
112124
112741
  const parsed = JSON.parse(raw);
112125
112742
  if (parsed.shortName && parsed.accessToken) {
112126
112743
  account = parsed;
@@ -112140,7 +112757,7 @@ async function publishToTelegraph(text5, shortName, authorName) {
112140
112757
  account = created.value;
112141
112758
  try {
112142
112759
  mkdirStateSync2(STATE_DIR, { recursive: true, mode: 448 });
112143
- writeFileSync53(accountPath, JSON.stringify(account, null, 2), { mode: 384 });
112760
+ writeFileSync55(accountPath, JSON.stringify(account, null, 2), { mode: 384 });
112144
112761
  } catch (err) {
112145
112762
  process.stderr.write(`telegram gateway: telegraph cache write failed: ${err.message}
112146
112763
  `);
@@ -112256,7 +112873,7 @@ _The secret was NOT saved. The agent can re-request with \`request_secret\`._`,
112256
112873
  }
112257
112874
  function readLiveSwitchroomConfigText() {
112258
112875
  const cfgPath = process.env.SWITCHROOM_CONFIG ?? findConfigFile2();
112259
- return readFileSync66(cfgPath, "utf8");
112876
+ return readFileSync67(cfgPath, "utf8");
112260
112877
  }
112261
112878
  async function executeReact(args) {
112262
112879
  if (!args.chat_id)
@@ -112297,7 +112914,7 @@ async function executeDownloadAttachment(args) {
112297
112914
  });
112298
112915
  mkdirSync50(INBOX_DIR, { recursive: true, mode: 448 });
112299
112916
  assertInsideInbox2(INBOX_DIR, dlPath);
112300
- writeFileSync53(dlPath, buf, { mode: 384 });
112917
+ writeFileSync55(dlPath, buf, { mode: 384 });
112301
112918
  return { content: [{ type: "text", text: dlPath }] };
112302
112919
  }
112303
112920
  async function executeEditMessage(args) {
@@ -113653,7 +114270,7 @@ function getMyAgentName() {
113653
114270
  const fromEnv = process.env.SWITCHROOM_AGENT_NAME;
113654
114271
  if (fromEnv && fromEnv.trim().length > 0)
113655
114272
  return fromEnv.trim();
113656
- return basename18(process.cwd());
114273
+ return basename19(process.cwd());
113657
114274
  }
113658
114275
  function isSelfTargetingCommand(name) {
113659
114276
  if (name === "all")
@@ -113666,14 +114283,14 @@ function restartMarkerPath() {
113666
114283
  const agentDir = resolveAgentDirFromEnv();
113667
114284
  if (!agentDir)
113668
114285
  return null;
113669
- return join76(agentDir, "restart-pending.json");
114286
+ return join77(agentDir, "restart-pending.json");
113670
114287
  }
113671
114288
  function writeRestartMarker(marker) {
113672
114289
  const p = restartMarkerPath();
113673
114290
  if (!p)
113674
114291
  return;
113675
114292
  try {
113676
- writeFileSync53(p, JSON.stringify(marker));
114293
+ writeFileSync55(p, JSON.stringify(marker));
113677
114294
  lastPlannedRestartAt = Date.now();
113678
114295
  process.stderr.write(`telegram gateway: restart-marker: write chat_id=${marker.chat_id} thread_id=${marker.thread_id ?? "-"} ack=${marker.ack_message_id ?? "-"} path=${p}
113679
114296
  `);
@@ -113692,7 +114309,7 @@ function readRestartMarker() {
113692
114309
  if (!p)
113693
114310
  return null;
113694
114311
  try {
113695
- return JSON.parse(readFileSync66(p, "utf8"));
114312
+ return JSON.parse(readFileSync67(p, "utf8"));
113696
114313
  } catch {
113697
114314
  return null;
113698
114315
  }
@@ -113841,7 +114458,7 @@ var _dockerReachable;
113841
114458
  function isDockerReachable() {
113842
114459
  if (_dockerReachable !== undefined)
113843
114460
  return _dockerReachable;
113844
- if (!existsSync64("/var/run/docker.sock")) {
114461
+ if (!existsSync65("/var/run/docker.sock")) {
113845
114462
  _dockerReachable = false;
113846
114463
  return _dockerReachable;
113847
114464
  }
@@ -113858,12 +114475,12 @@ function _resetDockerReachableCache() {
113858
114475
  }
113859
114476
  function spawnSwitchroomDetached(args, onFailure) {
113860
114477
  const fullArgs = SWITCHROOM_CONFIG ? ["--config", SWITCHROOM_CONFIG, ...args] : args;
113861
- const logPath = join76(STATE_DIR, "detached-spawn.log");
114478
+ const logPath = join77(STATE_DIR, "detached-spawn.log");
113862
114479
  let outFd = null;
113863
114480
  try {
113864
114481
  mkdirStateSync2(STATE_DIR, { recursive: true });
113865
114482
  outFd = openSync18(logPath, "a");
113866
- writeFileSync53(logPath, `
114483
+ writeFileSync55(logPath, `
113867
114484
  [${new Date().toISOString()}] spawn ${SWITCHROOM_CLI} ${fullArgs.join(" ")}
113868
114485
  `, { flag: "a" });
113869
114486
  } catch {}
@@ -113889,7 +114506,7 @@ function spawnSwitchroomDetached(args, onFailure) {
113889
114506
  return;
113890
114507
  let tail = "";
113891
114508
  try {
113892
- const full = readFileSync66(logPath, "utf8");
114509
+ const full = readFileSync67(logPath, "utf8");
113893
114510
  tail = full.split(`
113894
114511
  `).slice(-30).join(`
113895
114512
  `).trim();
@@ -114151,10 +114768,10 @@ ${preBlock(formatSwitchroomOutput(detail))}`, { html: true });
114151
114768
  }
114152
114769
  function readRecentDenialsForAgent(agentName3, windowMs, limit) {
114153
114770
  try {
114154
- const auditPath = join76(homedir22(), ".switchroom", "vault-audit.log");
114155
- if (!existsSync64(auditPath))
114771
+ const auditPath = join77(homedir22(), ".switchroom", "vault-audit.log");
114772
+ if (!existsSync65(auditPath))
114156
114773
  return [];
114157
- const raw = readFileSync66(auditPath, "utf8");
114774
+ const raw = readFileSync67(auditPath, "utf8");
114158
114775
  return recentDenialsFromAuditLog(raw, { agentName: agentName3, windowMs, limit });
114159
114776
  } catch {
114160
114777
  return [];
@@ -114205,7 +114822,7 @@ async function buildAgentMetadata(agentName3) {
114205
114822
  try {
114206
114823
  const agentDir = resolveAgentDirFromEnv();
114207
114824
  if (agentDir) {
114208
- const raw = readFileSync66(join76(agentDir, ".claude", ".claude.json"), "utf8");
114825
+ const raw = readFileSync67(join77(agentDir, ".claude", ".claude.json"), "utf8");
114209
114826
  claudeJson = JSON.parse(raw);
114210
114827
  }
114211
114828
  } catch {}
@@ -114334,7 +114951,7 @@ function buildModelDeps(restartCtx) {
114334
114951
  try {
114335
114952
  const agentDir = resolveAgentDirFromEnv();
114336
114953
  if (agentDir) {
114337
- const local = await fetchQuota2({ claudeConfigDir: join76(agentDir, ".claude") });
114954
+ const local = await fetchQuota2({ claudeConfigDir: join77(agentDir, ".claude") });
114338
114955
  if (local.ok)
114339
114956
  return formatQuotaLine2(local.data);
114340
114957
  }
@@ -114581,10 +115198,10 @@ function effortMenuReplyMarkup(reply) {
114581
115198
  function flushAgentHandoff(agentDir) {
114582
115199
  let removed = 0;
114583
115200
  for (const fname of [".handoff.md", ".handoff-topic"]) {
114584
- const p = join76(agentDir, fname);
115201
+ const p = join77(agentDir, fname);
114585
115202
  try {
114586
- if (existsSync64(p)) {
114587
- unlinkSync31(p);
115203
+ if (existsSync65(p)) {
115204
+ unlinkSync33(p);
114588
115205
  removed++;
114589
115206
  }
114590
115207
  } catch (err) {
@@ -114639,7 +115256,7 @@ async function handleNewCommand(ctx) {
114639
115256
  writeRestartMarker({ chat_id: chatId, thread_id: threadId ?? null, ack_message_id: ackId, ts: Date.now() });
114640
115257
  if (agentDir != null) {
114641
115258
  try {
114642
- writeFileSync53(join76(agentDir, ".force-fresh-session"), `${kind} at ${new Date().toISOString()}
115259
+ writeFileSync55(join77(agentDir, ".force-fresh-session"), `${kind} at ${new Date().toISOString()}
114643
115260
  `, "utf8");
114644
115261
  } catch (err) {
114645
115262
  process.stderr.write(`telegram gateway: failed to write force-fresh marker: ${err}
@@ -114752,16 +115369,16 @@ function buildFolderPickerDeps() {
114752
115369
  };
114753
115370
  }
114754
115371
  var lockoutOps = {
114755
- readFileSync: (p, enc) => readFileSync66(p, enc),
115372
+ readFileSync: (p, enc) => readFileSync67(p, enc),
114756
115373
  writeFileSync: (p, data, opts) => writeStateFileSync2(p, data, opts),
114757
- existsSync: (p) => existsSync64(p),
115374
+ existsSync: (p) => existsSync65(p),
114758
115375
  mkdirSync: (p, opts) => mkdirStateSync2(p, opts),
114759
- joinPath: (...parts) => join76(...parts)
115376
+ joinPath: (...parts) => join77(...parts)
114760
115377
  };
114761
115378
  var FLEET_FALLBACK_DEDUP_MS = 30000;
114762
115379
  function isAuthBrokerSocketReachable() {
114763
115380
  try {
114764
- return existsSync64(resolveAuthBrokerSocketPath2());
115381
+ return existsSync65(resolveAuthBrokerSocketPath2());
114765
115382
  } catch {
114766
115383
  return false;
114767
115384
  }
@@ -115017,7 +115634,7 @@ async function runCreditWatch() {
115017
115634
  if (!agentDir)
115018
115635
  return;
115019
115636
  const agentName3 = getMyAgentName();
115020
- const claudeConfigDir = join76(agentDir, ".claude");
115637
+ const claudeConfigDir = join77(agentDir, ".claude");
115021
115638
  const stateDir = STATE_DIR;
115022
115639
  const reason = readClaudeJsonOverage(claudeConfigDir);
115023
115640
  const prev = loadCreditState(stateDir);
@@ -116787,7 +117404,7 @@ Send \`/auth ${parsed.provider} cancel\` to abort.`, { html: true });
116787
117404
  await switchroomReply(ctx, "**/usage:** cannot resolve agent dir.", { html: true });
116788
117405
  return;
116789
117406
  }
116790
- const result = await fetchQuota2({ claudeConfigDir: join76(agentDir, ".claude") });
117407
+ const result = await fetchQuota2({ claudeConfigDir: join77(agentDir, ".claude") });
116791
117408
  if (!result.ok) {
116792
117409
  await switchroomReply(ctx, `**/usage:** ${escapeHtmlForTg2(result.reason)}`, { html: true });
116793
117410
  return;
@@ -117178,7 +117795,7 @@ ${interimLabel}` : interimLabel
117178
117795
  const unifiedDiff = (() => {
117179
117796
  try {
117180
117797
  const cfgPath = process.env.SWITCHROOM_CONFIG ?? SWITCHROOM_CONFIG ?? findConfigFile2();
117181
- const raw = readFileSync66(cfgPath, "utf8");
117798
+ const raw = readFileSync67(cfgPath, "utf8");
117182
117799
  return synthesizeAllowRuleDiff({ agentName: agentName3, rule: chosen.rule, configText: raw });
117183
117800
  } catch (err) {
117184
117801
  process.stderr.write(`telegram gateway: always-allow diff synth failed: ${err.message}
@@ -118053,7 +118670,7 @@ async function startGateway() {
118053
118670
  return;
118054
118671
  }
118055
118672
  })();
118056
- const resolvedAgentDirForBootCard = agentDir ?? join76(homedir22(), ".switchroom", "agents", agentSlug);
118673
+ const resolvedAgentDirForBootCard = agentDir ?? join77(homedir22(), ".switchroom", "agents", agentSlug);
118057
118674
  const handle = await startBootCard(chatId, threadId, botApiForCard, {
118058
118675
  agentName: agentDisplayName,
118059
118676
  agentSlug,
@@ -118067,8 +118684,8 @@ async function startGateway() {
118067
118684
  probeQuotaViaBroker: (t) => probeQuotaForBootCard(agentSlug, t),
118068
118685
  tmuxSupervisor: process.env.SWITCHROOM_TMUX_SUPERVISOR === "1",
118069
118686
  dockerMode: process.env.SWITCHROOM_RUNTIME === "docker",
118070
- configSnapshotPath: join76(resolvedAgentDirForBootCard, ".config-snapshot.json"),
118071
- bootCardStatePath: join76(resolvedAgentDirForBootCard, ".boot-card-msgid.json"),
118687
+ configSnapshotPath: join77(resolvedAgentDirForBootCard, ".config-snapshot.json"),
118688
+ bootCardStatePath: join77(resolvedAgentDirForBootCard, ".boot-card-msgid.json"),
118072
118689
  floodStatePath: FLOOD_STATE_PATH,
118073
118690
  ...updateOutcomeLine ? { updateOutcomeLine } : {}
118074
118691
  }, ackMsgId);
@@ -118101,7 +118718,7 @@ async function startGateway() {
118101
118718
  if (smAgentDir) {
118102
118719
  const resolutionTimeoutMs = resolveSessionModelResolutionTimeoutMs(process.env.SWITCHROOM_SESSION_MODEL_RESOLUTION_TIMEOUT_MS);
118103
118720
  const resolved = await waitForSessionModelResolution({
118104
- barrierExists: () => existsSync64(join76(smAgentDir, ".session-model-resolved")),
118721
+ barrierExists: () => existsSync65(join77(smAgentDir, ".session-model-resolved")),
118105
118722
  timeoutMs: resolutionTimeoutMs
118106
118723
  });
118107
118724
  if (!resolved) {
@@ -118109,10 +118726,10 @@ async function startGateway() {
118109
118726
  process.stderr.write(`telegram gateway: gw /model relaunch UNRESOLVED agent=${getMyAgentName()} target=${target} (barrier timeout after ${resolutionTimeoutMs}ms)
118110
118727
  `);
118111
118728
  } else {
118112
- const activePath = join76(smAgentDir, ".active-session-model");
118113
- if (existsSync64(activePath)) {
118729
+ const activePath = join77(smAgentDir, ".active-session-model");
118730
+ if (existsSync65(activePath)) {
118114
118731
  try {
118115
- const launched = readFileSync66(activePath, "utf8").trim();
118732
+ const launched = readFileSync67(activePath, "utf8").trim();
118116
118733
  const configured = (() => {
118117
118734
  const d = switchroomExecJson(["agent", "list"]);
118118
118735
  const raw = d?.agents?.find((a) => a.name === getMyAgentName())?.model ?? null;
@@ -118145,29 +118762,29 @@ async function startGateway() {
118145
118762
  deliverModelSwitchBootNotice({
118146
118763
  ...modelBootCardDeps,
118147
118764
  confirmation,
118148
- hasSessionModelAlert: existsSync64(join76(smAgentDir, ".session-model-alert"))
118765
+ hasSessionModelAlert: existsSync65(join77(smAgentDir, ".session-model-alert"))
118149
118766
  });
118150
118767
  }
118151
118768
  } catch {}
118152
118769
  }
118153
- const activeEffortPath = join76(smAgentDir, ".active-session-effort");
118154
- if (existsSync64(activeEffortPath)) {
118770
+ const activeEffortPath = join77(smAgentDir, ".active-session-effort");
118771
+ if (existsSync65(activeEffortPath)) {
118155
118772
  try {
118156
- const launchedEffort = readFileSync66(activeEffortPath, "utf8").trim();
118773
+ const launchedEffort = readFileSync67(activeEffortPath, "utf8").trim();
118157
118774
  const configuredEffort = getConfiguredEffortForPersist();
118158
118775
  sessionEffortOverride = launchedEffort.length > 0 && launchedEffort !== configuredEffort ? launchedEffort : null;
118159
118776
  } catch {}
118160
118777
  }
118161
- const alertPath = join76(smAgentDir, ".session-model-alert");
118162
- if (existsSync64(alertPath)) {
118778
+ const alertPath = join77(smAgentDir, ".session-model-alert");
118779
+ if (existsSync65(alertPath)) {
118163
118780
  let alertText = null;
118164
118781
  try {
118165
- alertText = readFileSync66(alertPath, "utf8").trim();
118782
+ alertText = readFileSync67(alertPath, "utf8").trim();
118166
118783
  } catch {
118167
118784
  alertText = null;
118168
118785
  }
118169
118786
  try {
118170
- unlinkSync31(alertPath);
118787
+ unlinkSync33(alertPath);
118171
118788
  } catch {}
118172
118789
  if (alertText && alertText.length > 0) {
118173
118790
  const operators = loadAccess().allowFrom;