switchroom 0.19.39 → 0.19.41

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 (37) hide show
  1. package/dist/agent-scheduler/index.js +10 -1
  2. package/dist/auth-broker/index.js +12 -3
  3. package/dist/cli/notion-write-pretool.mjs +10 -1
  4. package/dist/cli/switchroom.js +562 -196
  5. package/dist/host-control/main.js +287 -20
  6. package/dist/vault/approvals/kernel-server.js +12 -3
  7. package/dist/vault/broker/server.js +12 -3
  8. package/package.json +1 -1
  9. package/profiles/_base/start.sh.hbs +10 -0
  10. package/telegram-plugin/bridge/bridge.ts +2 -2
  11. package/telegram-plugin/dist/bridge/bridge.js +10 -2
  12. package/telegram-plugin/dist/gateway/gateway.js +549 -232
  13. package/telegram-plugin/dist/server.js +10 -2
  14. package/telegram-plugin/gateway/backstop-delivery.ts +48 -0
  15. package/telegram-plugin/gateway/checklist-fallback.ts +370 -0
  16. package/telegram-plugin/gateway/compaction-marker.ts +84 -0
  17. package/telegram-plugin/gateway/gateway.ts +72 -72
  18. package/telegram-plugin/gateway/liveness-wiring.ts +15 -0
  19. package/telegram-plugin/gateway/outbound-send-path.ts +20 -0
  20. package/telegram-plugin/gateway/outbox-sweep.ts +116 -18
  21. package/telegram-plugin/gateway/silence-poke-session-event.ts +13 -0
  22. package/telegram-plugin/gateway/stream-render.ts +39 -1
  23. package/telegram-plugin/gateway/turn-record-status.ts +80 -0
  24. package/telegram-plugin/hooks/compaction-marker-precompact.mjs +70 -0
  25. package/telegram-plugin/hooks/hooks.json +11 -0
  26. package/telegram-plugin/session-tail.ts +20 -0
  27. package/telegram-plugin/silence-poke.ts +28 -0
  28. package/telegram-plugin/tests/checklist-fallback.test.ts +317 -0
  29. package/telegram-plugin/tests/gateway-outbound-redact.test.ts +10 -6
  30. package/telegram-plugin/tests/outbox-delivery.test.ts +38 -1
  31. package/telegram-plugin/tests/outbox-flush-ack-claim-race.test.ts +213 -0
  32. package/telegram-plugin/tests/outbox-reply-then-recap-e2e.test.ts +1 -1
  33. package/telegram-plugin/tests/outbox-sweep-flood-breaker.test.ts +4 -4
  34. package/telegram-plugin/tests/outbox-sweep-listen-button.test.ts +71 -8
  35. package/telegram-plugin/tests/send-reply-golden.test.ts +47 -0
  36. package/telegram-plugin/tests/silence-poke-compaction.test.ts +222 -0
  37. package/telegram-plugin/tests/turn-record-status.test.ts +62 -0
@@ -21726,7 +21726,7 @@ var require_dist = __commonJS((exports) => {
21726
21726
  });
21727
21727
 
21728
21728
  // ../src/memory/observation-scopes.ts
21729
- var OBSERVATION_SCOPES;
21729
+ var OBSERVATION_SCOPES, OBSERVATION_SCOPE_STRATEGIES;
21730
21730
  var init_observation_scopes = __esm(() => {
21731
21731
  OBSERVATION_SCOPES = [
21732
21732
  "per_tag",
@@ -21734,10 +21734,16 @@ var init_observation_scopes = __esm(() => {
21734
21734
  "all_combinations",
21735
21735
  "shared"
21736
21736
  ];
21737
+ OBSERVATION_SCOPE_STRATEGIES = [
21738
+ "curated",
21739
+ "shared",
21740
+ "combined",
21741
+ "off"
21742
+ ];
21737
21743
  });
21738
21744
 
21739
21745
  // ../src/config/schema.ts
21740
- var CodeRepoEntrySchema, AgentBindMountSchema, HttpDiffPollSchema, PollSpecSchema, TelegramMessageActionSchema, WebhookActionSchema, ActionSpecSchema, ScheduleEntrySchema, AgentSoulSchema, AgentToolsSchema, ObservationScopesSchema, AgentMemorySchema, HookEntrySchema, AgentHooksSchema, SubagentSchema, SessionSchema, SessionContinuitySchema, webhookDispatchRule, TelegramChannelSchema, ChannelsSchema, TIMEZONE_REGEX, ApproverIdSchema, GoogleWorkspaceTierSchema, GoogleWorkspaceConfigSchema, LiteLLMConfigSchema, HindsightPerOpLlmSchema, HindsightConfigSchema, MicrosoftWorkspaceConfigSchema, NotionWorkspaceConfigSchema, AgentGoogleWorkspaceConfigSchema, MicrosoftAccountEmailSchema, MicrosoftToolTokenSchema, MicrosoftAccountBindingSchema, AgentMicrosoftWorkspaceConfigSchema, AgentNotionWorkspaceConfigSchema, ReactionsSchema, ReactionDispatchSchema, releaseBlockFields, ReleaseBlock, RootReleaseBlock, NetworkIsolationSchema, servesField, knowsField, profileFields, ProfileSchema, _omitExtends, defaultsFields, AgentDefaultsSchema, AgentSchema, TelegramConfigSchema, MemoryBackendConfigSchema, VaultConfigSchema, QuotaConfigSchema, AutoReleaseCheckSchema, HostControlConfigSchema, WebServiceConfigSchema, FleetHealthConfigSchema, HostdConfigSchema, CronEgressSchema, CronConfigSchema, UserSchema, SwitchroomConfigSchema;
21746
+ var CodeRepoEntrySchema, AgentBindMountSchema, HttpDiffPollSchema, PollSpecSchema, TelegramMessageActionSchema, WebhookActionSchema, ActionSpecSchema, ScheduleEntrySchema, AgentSoulSchema, AgentToolsSchema, ObservationScopesSchema, ObservationScopeStrategySchema, AgentMemorySchema, HookEntrySchema, AgentHooksSchema, SubagentSchema, SessionSchema, SessionContinuitySchema, webhookDispatchRule, TelegramChannelSchema, ChannelsSchema, TIMEZONE_REGEX, ApproverIdSchema, GoogleWorkspaceTierSchema, GoogleWorkspaceConfigSchema, LiteLLMConfigSchema, HindsightPerOpLlmSchema, HindsightConfigSchema, MicrosoftWorkspaceConfigSchema, NotionWorkspaceConfigSchema, AgentGoogleWorkspaceConfigSchema, MicrosoftAccountEmailSchema, MicrosoftToolTokenSchema, MicrosoftAccountBindingSchema, AgentMicrosoftWorkspaceConfigSchema, AgentNotionWorkspaceConfigSchema, ReactionsSchema, ReactionDispatchSchema, releaseBlockFields, ReleaseBlock, RootReleaseBlock, NetworkIsolationSchema, servesField, knowsField, profileFields, ProfileSchema, _omitExtends, defaultsFields, AgentDefaultsSchema, AgentSchema, TelegramConfigSchema, MemoryBackendConfigSchema, VaultConfigSchema, QuotaConfigSchema, AutoReleaseCheckSchema, HostControlConfigSchema, WebServiceConfigSchema, FleetHealthConfigSchema, HostdConfigSchema, CronEgressSchema, CronConfigSchema, UserSchema, SwitchroomConfigSchema;
21741
21747
  var init_schema = __esm(() => {
21742
21748
  init_zod();
21743
21749
  init_observation_scopes();
@@ -21852,7 +21858,8 @@ var init_schema = __esm(() => {
21852
21858
  allow: exports_external.array(exports_external.string()).default([]).describe("Allowed tools (use ['all'] for unrestricted)"),
21853
21859
  deny: exports_external.array(exports_external.string()).default([]).describe("Denied tools (overrides allow)")
21854
21860
  }).optional();
21855
- ObservationScopesSchema = exports_external.enum(OBSERVATION_SCOPES).optional().describe("Per-row observation scope stamped on every memory this agent " + `retains. "shared" makes Hindsight's consolidation write the ` + "resulting observations into ONE global untagged scope instead of a " + "scope per tag \u2014 what several agents pooling one bank need so their " + "observations actually merge rather than sitting in parallel " + "per-tag silos. OMITTED BY DEFAULT: unset means the field never goes " + "on the wire and the engine's own default stands, which is the " + "shipped behaviour. Applies to every retain path (Stop hook, " + "sidechain, boot reconcile, queue drain, backfill, session-handoff " + "mirror) and is carried on the queued payload, so a retain that fails " + "now and drains later still lands in this scope. Accepted values: " + `${OBSERVATION_SCOPES.join(", ")}. ` + "Cascade: override (per-agent wins over default).");
21861
+ ObservationScopesSchema = exports_external.enum(OBSERVATION_SCOPES).optional().describe("Operator PIN for the per-row observation scope, overriding the " + 'default `curated` strategy (see docs/configuration.md). "shared" ' + "forces Hindsight's consolidation to write EVERY observation into ONE " + "global untagged scope \u2014 what several agents pooling one bank want so " + "their observations merge rather than sitting in parallel silos. " + '"combined" is the pin form of opting out (restores the pre-#4035 ' + "engine default). UNSET does NOT mean 'nothing on the wire': the " + "`curated` strategy still computes a scope per retain. Applies to " + "every retain path (Stop hook, " + "sidechain, boot reconcile, queue drain, backfill, session-handoff " + "mirror) and is carried on the queued payload, so a retain that fails " + "now and drains later still lands in this scope. Accepted values: " + `${OBSERVATION_SCOPES.join(", ")}. ` + "Cascade: override (per-agent wins over default).");
21862
+ ObservationScopeStrategySchema = exports_external.enum(OBSERVATION_SCOPE_STRATEGIES).optional().describe("Per-retain strategy that decides how the observation scope is " + 'computed when no `observation_scopes` pin is set. "curated" ' + "(the default since #4035) strips volatile per-session provenance " + "tags from each retain's consolidation scope \u2014 keeping the stable " + "semantic ones on the source fact \u2014 so an agent's observations dedup " + "and merge across sessions instead of pocketing one-per-session. " + '"shared" sends every retain to the one global untagged scope. ' + '"combined" / "off" opt OUT: no per-row scope goes on the wire, ' + "restoring the pre-feature engine default (byte-identical to an " + "unconfigured client). OMITTED BY DEFAULT: unset leaves the plugin's " + "own default (`curated`) in force. A manual `observation_scopes` pin " + "wins over this strategy. Accepted values: " + `${OBSERVATION_SCOPE_STRATEGIES.join(", ")}. ` + "Cascade: override (per-agent wins over default).");
21856
21863
  AgentMemorySchema = exports_external.object({
21857
21864
  collection: exports_external.string().describe("Hindsight collection name for this agent"),
21858
21865
  auto_recall: exports_external.boolean().default(true).describe("Auto-search memories before each response"),
@@ -21888,6 +21895,7 @@ var init_schema = __esm(() => {
21888
21895
  }).optional().describe("Personality traits (1-5 each) steering how this bank frames recall, " + "reflect, and observation synthesis \u2014 a coach leans empathy-high, a " + "lawyer/analyst leans skepticism/literalism-high. Maps to the engine's " + "flat `disposition_skepticism`/`_literalism`/`_empathy` fields. " + "Cascade: per-key merge (an agent overrides individual traits and " + "inherits the rest, matching `recall`)."),
21889
21896
  directive_capture_nudge: exports_external.boolean().optional().describe("Deterministic directive-capture nudge (issue #2848 Stage B). When " + "on (switchroom default true \u2014 Stage A measured a ~55% miss rate on " + "durable corrections), the auto-recall hook regex-detects correction " + '/ standing-rule-shaped inbound ("always/never \u2026", "from now on \u2026", ' + `"stop doing \u2026", a stated preference, "that's wrong, it's \u2026") and ` + "appends a terse advisory to the turn's context telling the model to " + "persist the rule with mcp__hindsight__create_directive if it IS " + "durable. Detection is pure regex \u2014 the model does the judgment " + "in-session and calls create_directive itself (no model callsite, no " + "silent hook-side write). Set false to disable per-agent. " + "Cascade: override (per-agent wins over default)."),
21890
21897
  observation_scopes: ObservationScopesSchema,
21898
+ observation_scope_strategy: ObservationScopeStrategySchema,
21891
21899
  recall: exports_external.object({
21892
21900
  max_memories: exports_external.number().int().min(0).optional().describe("Cap on the number of memories injected into the prompt by " + "auto-recall, regardless of token budget. Plugin default is 12. " + "0 disables the cap (all memories Hindsight returns are injected)."),
21893
21901
  cache_ttl_secs: exports_external.number().int().min(0).optional().describe("Per-session recall cache TTL in seconds. When > 0, identical " + "(prompt, bank) within the same session reuse the cached recall " + "result instead of round-tripping to Hindsight. 0 disables. " + "Default is 600 (10 min) for switchroom-managed agents."),
@@ -22288,6 +22296,7 @@ var init_schema = __esm(() => {
22288
22296
  isolation: exports_external.enum(["default", "strict"]).optional(),
22289
22297
  directive_capture_nudge: exports_external.boolean().optional(),
22290
22298
  observation_scopes: ObservationScopesSchema,
22299
+ observation_scope_strategy: ObservationScopeStrategySchema,
22291
22300
  recall: exports_external.object({
22292
22301
  max_memories: exports_external.number().int().min(0).optional(),
22293
22302
  cache_ttl_secs: exports_external.number().int().min(0).optional(),
@@ -35875,9 +35884,9 @@ function renderAuthLine(state7, agentName3, now = Date.now()) {
35875
35884
 
35876
35885
  // gateway/quota-cache.ts
35877
35886
  import { existsSync as existsSync44, readFileSync as readFileSync44, writeFileSync as writeFileSync37, mkdirSync as mkdirSync39 } from "fs";
35878
- import { join as join53, dirname as dirname22 } from "path";
35887
+ import { join as join54, dirname as dirname22 } from "path";
35879
35888
  function defaultCachePath() {
35880
- return process.env.SWITCHROOM_QUOTA_CACHE_PATH ?? join53(process.env.HOME ?? "/tmp", ".switchroom", "quota-cache.json");
35889
+ return process.env.SWITCHROOM_QUOTA_CACHE_PATH ?? join54(process.env.HOME ?? "/tmp", ".switchroom", "quota-cache.json");
35881
35890
  }
35882
35891
  function readQuotaCache(opts = {}) {
35883
35892
  const path3 = opts.path ?? defaultCachePath();
@@ -35924,7 +35933,7 @@ var init_quota_cache = __esm(() => {
35924
35933
 
35925
35934
  // gateway/boot-probes.ts
35926
35935
  import { readFileSync as readFileSync45, readdirSync as readdirSync12, existsSync as existsSync45 } from "fs";
35927
- import { join as join54 } from "path";
35936
+ import { join as join55 } from "path";
35928
35937
  import { execFile as execFileCb } from "child_process";
35929
35938
  import { promisify } from "util";
35930
35939
  async function withTimeout(label, p, timeoutMs = PROBE_TIMEOUT_MS) {
@@ -35966,8 +35975,8 @@ function mapPlan(billingType, hasExtra) {
35966
35975
  }
35967
35976
  async function probeAccount(agentDir) {
35968
35977
  return withTimeout("Account", (async () => {
35969
- const claudeDir = join54(agentDir, ".claude");
35970
- const claudeJsonPath = join54(claudeDir, ".claude.json");
35978
+ const claudeDir = join55(agentDir, ".claude");
35979
+ const claudeJsonPath = join55(claudeDir, ".claude.json");
35971
35980
  let cfg = {};
35972
35981
  try {
35973
35982
  const raw = readFileSync45(claudeJsonPath, "utf8");
@@ -35988,8 +35997,8 @@ async function probeAccount(agentDir) {
35988
35997
  let tokenStr = "";
35989
35998
  let status = "ok";
35990
35999
  for (const candidate of [
35991
- join54(claudeDir, ".oauth-token.meta.json"),
35992
- join54(claudeDir, "accounts", "default", ".oauth-token.meta.json")
36000
+ join55(claudeDir, ".oauth-token.meta.json"),
36001
+ join55(claudeDir, "accounts", "default", ".oauth-token.meta.json")
35993
36002
  ]) {
35994
36003
  if (existsSync45(candidate)) {
35995
36004
  try {
@@ -36375,9 +36384,9 @@ async function probeQuota(claudeConfigDir, _agentDir, fetchImpl = fetch, opts =
36375
36384
  let claudeDirForProbe = null;
36376
36385
  for (const candidate of [
36377
36386
  claudeConfigDir,
36378
- join54(claudeConfigDir, "accounts", "default")
36387
+ join55(claudeConfigDir, "accounts", "default")
36379
36388
  ]) {
36380
- if (existsSync45(join54(candidate, ".oauth-token"))) {
36389
+ if (existsSync45(join55(candidate, ".oauth-token"))) {
36381
36390
  claudeDirForProbe = candidate;
36382
36391
  break;
36383
36392
  }
@@ -36612,7 +36621,7 @@ async function probeSkills(agentDir, opts = {}) {
36612
36621
  return withTimeout("Skills", (async () => {
36613
36622
  const fs3 = opts.fs ?? realSkillsFs;
36614
36623
  const max = opts.maxNamesShown ?? 3;
36615
- const skillsDir = join54(agentDir, ".claude", "skills");
36624
+ const skillsDir = join55(agentDir, ".claude", "skills");
36616
36625
  if (!fs3.exists(skillsDir)) {
36617
36626
  return { status: "ok", label: "Skills", detail: "no skills dir" };
36618
36627
  }
@@ -36627,17 +36636,17 @@ async function probeSkills(agentDir, opts = {}) {
36627
36636
  }
36628
36637
  const dangling = [];
36629
36638
  for (const name of entries) {
36630
- const skillPath = join54(skillsDir, name);
36639
+ const skillPath = join55(skillsDir, name);
36631
36640
  if (!fs3.exists(skillPath)) {
36632
36641
  dangling.push(name);
36633
36642
  continue;
36634
36643
  }
36635
- const skillMd = join54(skillPath, "SKILL.md");
36644
+ const skillMd = join55(skillPath, "SKILL.md");
36636
36645
  if (!fs3.exists(skillMd) && !fs3.exists(skillPath + ".md")) {
36637
36646
  continue;
36638
36647
  }
36639
36648
  }
36640
- const overlayDir = opts.overlaySkillsDir ?? join54(agentDir, "skills.d");
36649
+ const overlayDir = opts.overlaySkillsDir ?? join55(agentDir, "skills.d");
36641
36650
  const overlaySlugs = new Set;
36642
36651
  if (fs3.exists(overlayDir)) {
36643
36652
  let overlayEntries = [];
@@ -36679,7 +36688,7 @@ function renderBucketedSkills(switchroom, agent) {
36679
36688
  }
36680
36689
  async function probeConnections(agentDir, opts = {}) {
36681
36690
  return withTimeout("Connections", (async () => {
36682
- const path3 = join54(agentDir, ".claude", "connection-health.json");
36691
+ const path3 = join55(agentDir, ".claude", "connection-health.json");
36683
36692
  const read = opts.readFileImpl ?? ((p) => readFileSync45(p, "utf8"));
36684
36693
  let issues = [];
36685
36694
  try {
@@ -36720,7 +36729,7 @@ async function probeDrift(agentDir, opts = {}) {
36720
36729
  }
36721
36730
  } catch {}
36722
36731
  try {
36723
- const raw = readFileSync45(join54(agentDir, ".switchroom-drift.json"), "utf8");
36732
+ const raw = readFileSync45(join55(agentDir, ".switchroom-drift.json"), "utf8");
36724
36733
  const report = JSON.parse(raw);
36725
36734
  if (report?.version === 1 && Array.isArray(report.findings)) {
36726
36735
  const gen = report.generatedAt ? Date.parse(report.generatedAt) : NaN;
@@ -36772,8 +36781,8 @@ var init_boot_probes = __esm(() => {
36772
36781
  realSchedulerFs = {
36773
36782
  readFile: (p) => readFileSync45(p, "utf-8"),
36774
36783
  mtimeMs: (p) => {
36775
- const { statSync: statSync16 } = __require("fs");
36776
- return statSync16(p).mtimeMs;
36784
+ const { statSync: statSync17 } = __require("fs");
36785
+ return statSync17(p).mtimeMs;
36777
36786
  },
36778
36787
  exists: (p) => existsSync45(p)
36779
36788
  };
@@ -37080,8 +37089,8 @@ __export(exports_boot_card, {
37080
37089
  readRoutingMode: () => readRoutingMode,
37081
37090
  containerBootStartMs: () => containerBootStartMs
37082
37091
  });
37083
- import { join as join55 } from "path";
37084
- import { readFileSync as readFileSync49, statSync as statSync16 } from "fs";
37092
+ import { join as join56 } from "path";
37093
+ import { readFileSync as readFileSync49, statSync as statSync17 } from "fs";
37085
37094
  function resolvePersonaName(slug, loadConfig3) {
37086
37095
  try {
37087
37096
  const config = loadConfig3 ? loadConfig3() : loadConfig();
@@ -37124,8 +37133,8 @@ function containerBootStartMs(fsImpl = { readFileSync: readFileSync49 }) {
37124
37133
  return null;
37125
37134
  }
37126
37135
  }
37127
- function readRoutingMode(agentDir, bootStartMs, fsImpl = { readFileSync: readFileSync49, statSync: statSync16 }) {
37128
- const path3 = join55(agentDir, ".routing-mode");
37136
+ function readRoutingMode(agentDir, bootStartMs, fsImpl = { readFileSync: readFileSync49, statSync: statSync17 }) {
37137
+ const path3 = join56(agentDir, ".routing-mode");
37129
37138
  try {
37130
37139
  const raw = fsImpl.readFileSync(path3, "utf-8");
37131
37140
  const line = raw.split(`
@@ -37232,7 +37241,7 @@ function renderBootCard(opts) {
37232
37241
  return stackCardLines(flatLines);
37233
37242
  }
37234
37243
  async function runAllProbes(opts) {
37235
- const claudeDir = join55(opts.agentDir, ".claude");
37244
+ const claudeDir = join56(opts.agentDir, ".claude");
37236
37245
  const probes = {};
37237
37246
  const slug = opts.agentSlug ?? opts.agentName;
37238
37247
  await Promise.allSettled([
@@ -38094,7 +38103,7 @@ __export(exports_tmux2, {
38094
38103
  captureAgentPane: () => captureAgentPane2
38095
38104
  });
38096
38105
  import { execFileSync as execFileSync8 } from "node:child_process";
38097
- import { chmodSync as chmodSync13, mkdirSync as mkdirSync50, readdirSync as readdirSync15, statSync as statSync21, unlinkSync as unlinkSync29, writeFileSync as writeFileSync49 } from "node:fs";
38106
+ import { chmodSync as chmodSync13, mkdirSync as mkdirSync50, readdirSync as readdirSync15, statSync as statSync22, unlinkSync as unlinkSync30, writeFileSync as writeFileSync49 } from "node:fs";
38098
38107
  import { resolve as resolve12 } from "node:path";
38099
38108
  function captureAgentPane2(opts) {
38100
38109
  const { agentName: agentName3, agentDir, reason } = opts;
@@ -38223,13 +38232,13 @@ function pruneOldReports2(dir, retain) {
38223
38232
  const full = resolve12(dir, n);
38224
38233
  let mtimeMs = 0;
38225
38234
  try {
38226
- mtimeMs = statSync21(full).mtimeMs;
38235
+ mtimeMs = statSync22(full).mtimeMs;
38227
38236
  } catch {}
38228
38237
  return { full, mtimeMs };
38229
38238
  }).sort((a, b) => b.mtimeMs - a.mtimeMs);
38230
38239
  for (const stale of files.slice(retain)) {
38231
38240
  try {
38232
- unlinkSync29(stale.full);
38241
+ unlinkSync30(stale.full);
38233
38242
  } catch {}
38234
38243
  }
38235
38244
  }
@@ -39203,14 +39212,14 @@ import {
39203
39212
  mkdirSync as mkdirSync51,
39204
39213
  readdirSync as readdirSync16,
39205
39214
  rmSync as rmSync8,
39206
- statSync as statSync22,
39215
+ statSync as statSync23,
39207
39216
  renameSync as renameSync27,
39208
39217
  realpathSync as realpathSync4,
39209
39218
  chmodSync as chmodSync14,
39210
39219
  openSync as openSync15,
39211
39220
  closeSync as closeSync15,
39212
39221
  existsSync as existsSync57,
39213
- unlinkSync as unlinkSync30,
39222
+ unlinkSync as unlinkSync31,
39214
39223
  appendFileSync as appendFileSync9
39215
39224
  } from "fs";
39216
39225
 
@@ -39264,8 +39273,8 @@ function fsyncPathSync(path) {
39264
39273
  }
39265
39274
 
39266
39275
  // gateway/gateway.ts
39267
- import { homedir as homedir19 } from "os";
39268
- import { join as join68, sep as sep4, basename as basename17 } from "path";
39276
+ import { homedir as homedir20 } from "os";
39277
+ import { join as join69, sep as sep4, basename as basename17 } from "path";
39269
39278
 
39270
39279
  // plugin-logger.ts
39271
39280
  import { appendFileSync, mkdirSync, renameSync as renameSync2, statSync, existsSync } from "fs";
@@ -39495,6 +39504,178 @@ function redactChecklistFields(title, tasks, redact) {
39495
39504
  };
39496
39505
  }
39497
39506
 
39507
+ // gateway/checklist-fallback.ts
39508
+ var CHECKLIST_MAX_TASKS = 30;
39509
+ function buildChecklistTasks(tasks) {
39510
+ if (tasks.length > CHECKLIST_MAX_TASKS) {
39511
+ throw new Error(`checklist exceeds ${CHECKLIST_MAX_TASKS}-task limit (got ${tasks.length})`);
39512
+ }
39513
+ return tasks.map((t, i) => ({ id: i + 1, text: t.text, done: t.done === true }));
39514
+ }
39515
+ function renderChecklistText(cl, opts) {
39516
+ const header = opts?.literal ? cl.title : `**${cl.title}**`;
39517
+ const lines = cl.tasks.map((t) => `${t.done ? "\u2705" : "\u2b1c"} ${t.text}`);
39518
+ return [header, ...lines].join(`
39519
+ `);
39520
+ }
39521
+ function applyChecklistPatch(cl, patch) {
39522
+ const tasks = cl.tasks.map((t) => ({ ...t }));
39523
+ for (const p of patch.tasks ?? []) {
39524
+ const pid = p.id != null ? Number(p.id) : undefined;
39525
+ const existing = pid != null ? tasks.find((t) => t.id === pid) : undefined;
39526
+ if (existing) {
39527
+ if (p.text != null)
39528
+ existing.text = p.text;
39529
+ if (p.done != null)
39530
+ existing.done = p.done;
39531
+ } else {
39532
+ const nextId = pid != null && Number.isFinite(pid) ? pid : tasks.reduce((m, t) => Math.max(m, t.id), 0) + 1;
39533
+ tasks.push({ id: nextId, text: p.text ?? "", done: p.done === true });
39534
+ }
39535
+ }
39536
+ if (tasks.length > CHECKLIST_MAX_TASKS) {
39537
+ throw new Error(`checklist exceeds ${CHECKLIST_MAX_TASKS}-task limit (got ${tasks.length})`);
39538
+ }
39539
+ return { title: patch.title ?? cl.title, tasks };
39540
+ }
39541
+ function buildNativeChecklistPayload(p) {
39542
+ return {
39543
+ business_connection_id: p.businessConnectionId,
39544
+ chat_id: p.chatId,
39545
+ checklist: {
39546
+ title: p.title,
39547
+ tasks: p.tasks.map((t) => ({ id: t.id, text: t.text }))
39548
+ },
39549
+ ...p.replyToMessageId != null ? { reply_parameters: { message_id: p.replyToMessageId } } : {},
39550
+ ...p.protectContent === true ? { protect_content: true } : {}
39551
+ };
39552
+ }
39553
+ function buildNativeEditChecklistPayload(p) {
39554
+ return {
39555
+ business_connection_id: p.businessConnectionId,
39556
+ chat_id: p.chatId,
39557
+ message_id: p.messageId,
39558
+ checklist: {
39559
+ title: p.title,
39560
+ tasks: p.tasks.map((t) => ({ id: t.id, text: t.text }))
39561
+ }
39562
+ };
39563
+ }
39564
+ function createChecklistStore(cap = 500) {
39565
+ const map = new Map;
39566
+ return {
39567
+ get: (key) => map.get(key),
39568
+ set: (key, state) => {
39569
+ if (map.has(key))
39570
+ map.delete(key);
39571
+ map.set(key, state);
39572
+ while (map.size > cap) {
39573
+ const oldest = map.keys().next().value;
39574
+ if (oldest == null)
39575
+ break;
39576
+ map.delete(oldest);
39577
+ }
39578
+ }
39579
+ };
39580
+ }
39581
+ function checklistStoreKey(chatId, messageId) {
39582
+ return `${chatId}:${messageId}`;
39583
+ }
39584
+ async function performSendChecklist(deps, args) {
39585
+ const tasks = buildChecklistTasks(args.tasks);
39586
+ if (deps.nativeAvailable && deps.businessConnectionId) {
39587
+ try {
39588
+ const sent2 = await deps.sendNative(buildNativeChecklistPayload({
39589
+ businessConnectionId: deps.businessConnectionId,
39590
+ chatId: args.chatId,
39591
+ title: args.title,
39592
+ tasks,
39593
+ replyToMessageId: args.replyToMessageId,
39594
+ protectContent: args.protectContent
39595
+ }));
39596
+ return {
39597
+ message_id: sent2.message_id,
39598
+ mode: "native",
39599
+ state: { title: args.title, tasks, mode: "native" }
39600
+ };
39601
+ } catch (err) {
39602
+ deps.log(`native sendChecklist failed \u2014 falling back to text render: ${err}
39603
+ `);
39604
+ }
39605
+ }
39606
+ const text = renderChecklistText({ title: args.title, tasks }, { literal: deps.literalText });
39607
+ const sent = await deps.sendText(text);
39608
+ return {
39609
+ message_id: sent.message_id,
39610
+ mode: "text",
39611
+ state: { title: args.title, tasks, mode: "text" }
39612
+ };
39613
+ }
39614
+ function sendChecklistToolText(r) {
39615
+ return JSON.stringify(r.mode === "native" ? { ok: true, message_id: r.message_id, mode: "native" } : {
39616
+ ok: true,
39617
+ message_id: r.message_id,
39618
+ mode: "text",
39619
+ degraded: "text",
39620
+ note: "rendered as a formatted text message (native Telegram checklists require a Business connection) \u2014 tasks are not tappable; use update_checklist with task ids 1..N to tick them"
39621
+ });
39622
+ }
39623
+ async function performUpdateChecklist(deps, patch) {
39624
+ let base = deps.state;
39625
+ if (!base) {
39626
+ const fullReplacement = patch.title != null && (patch.tasks?.length ?? 0) > 0 && (patch.tasks ?? []).every((t) => t.text != null);
39627
+ if (!fullReplacement) {
39628
+ return {
39629
+ ok: false,
39630
+ reason: "unknown_checklist",
39631
+ hint: "no stored state for this checklist (gateway restarted?). Re-send it with send_checklist, or pass a full replacement (title + every task's text) to update_checklist."
39632
+ };
39633
+ }
39634
+ base = { title: patch.title, tasks: [], mode: "text" };
39635
+ }
39636
+ let next;
39637
+ try {
39638
+ next = applyChecklistPatch(base, patch);
39639
+ } catch (err) {
39640
+ return { ok: false, reason: "edit_failed", hint: String(err) };
39641
+ }
39642
+ const state = { title: next.title, tasks: next.tasks, mode: base.mode };
39643
+ if (base.mode === "native") {
39644
+ if (!deps.nativeAvailable || !deps.businessConnectionId) {
39645
+ return {
39646
+ ok: false,
39647
+ reason: "edit_failed",
39648
+ hint: "this checklist was sent natively but the business connection / checklist API is no longer available."
39649
+ };
39650
+ }
39651
+ try {
39652
+ await deps.editNative(buildNativeEditChecklistPayload({
39653
+ businessConnectionId: deps.businessConnectionId,
39654
+ chatId: deps.chatId,
39655
+ messageId: deps.messageId,
39656
+ title: state.title,
39657
+ tasks: state.tasks
39658
+ }));
39659
+ return { ok: true, mode: "native", state };
39660
+ } catch (err) {
39661
+ deps.log(`native editMessageChecklist failed: ${err}
39662
+ `);
39663
+ return { ok: false, reason: "edit_failed", hint: String(err) };
39664
+ }
39665
+ }
39666
+ try {
39667
+ await deps.editText(renderChecklistText(state, { literal: deps.literalText }));
39668
+ return { ok: true, mode: "text", state };
39669
+ } catch (err) {
39670
+ deps.log(`checklist text edit failed: ${err}
39671
+ `);
39672
+ return { ok: false, reason: "edit_failed", hint: String(err) };
39673
+ }
39674
+ }
39675
+ function updateChecklistToolText(r, messageId) {
39676
+ return JSON.stringify(r.ok ? { ok: true, message_id: messageId, mode: r.mode, ...r.mode === "text" ? { degraded: "text" } : {} } : { ok: false, reason: r.reason, hint: r.hint });
39677
+ }
39678
+
39498
39679
  // interrupt-marker.ts
39499
39680
  function parseInterruptMarker(text) {
39500
39681
  const trimmed = text.trimStart();
@@ -70372,6 +70553,8 @@ function tick(now) {
70372
70553
  const ceiling = thresholds.fallbackHardCeiling ?? Number.POSITIVE_INFINITY;
70373
70554
  const underCeiling = silence < ceiling;
70374
70555
  if (underCeiling) {
70556
+ if (activeDeps.isCompactionInFlight?.(key) === true)
70557
+ continue;
70375
70558
  const forceDisable = process.env.SWITCHROOM_SILENCE_DEFER_INFLIGHT_TOOLS === "0";
70376
70559
  if (!forceDisable && activeDeps.isLegitimatelyWorking != null) {
70377
70560
  if (activeDeps.isLegitimatelyWorking(key))
@@ -71596,6 +71779,14 @@ function projectTranscriptLine(line) {
71596
71779
  { kind: "turn_end", durationMs: obj.durationMs ?? 0 }
71597
71780
  ];
71598
71781
  }
71782
+ if (type === "system" && obj.subtype === "compact_boundary") {
71783
+ const meta = obj.compactMetadata;
71784
+ return [{
71785
+ kind: "compact_boundary",
71786
+ trigger: typeof meta?.trigger === "string" ? meta.trigger : null,
71787
+ compactDurationMs: typeof meta?.durationMs === "number" ? meta.durationMs : null
71788
+ }];
71789
+ }
71599
71790
  return [];
71600
71791
  }
71601
71792
 
@@ -77127,6 +77318,10 @@ function compactIfLarge(path2) {
77127
77318
  } catch {}
77128
77319
  }
77129
77320
 
77321
+ // gateway/outbox-sweep.ts
77322
+ init_rich_send();
77323
+ init_format();
77324
+
77130
77325
  // registry/subagents-schema.ts
77131
77326
  function countRunningBackgroundSubagents(db2) {
77132
77327
  const row = db2.prepare("SELECT count(*) AS n FROM subagents WHERE background = 1 AND status = 'running'").get();
@@ -78928,13 +79123,28 @@ async function deliverCapturedProse(deps, args) {
78928
79123
  const plainChunks = splitMarkdownChunks(plain, RICH_MESSAGE_MAX_CHARS);
78929
79124
  try {
78930
79125
  let liveThreadId = threadId;
79126
+ const plainSentIds = [];
79127
+ const plainSentTexts = [];
78931
79128
  for (const c of plainChunks) {
78932
79129
  const sent = await retryWithThreadFallback(robustApiCall, (tid) => bot.api.sendMessage(chatId, c, tid != null ? { message_thread_id: tid } : {}), { threadId: liveThreadId, chat_id: chatId, verb: "captured-prose-plain-fallback.sendMessage" });
79130
+ const sentId = sent.message_id;
79131
+ if (sentId != null) {
79132
+ plainSentIds.push(sentId);
79133
+ plainSentTexts.push(c);
79134
+ }
78933
79135
  if (liveThreadId != null && sent.message_thread_id == null) {
78934
79136
  liveThreadId = undefined;
78935
79137
  }
78936
79138
  }
78937
79139
  outboundDedup.record(chatId, threadId, text4, Date.now(), registryKey);
79140
+ if (HISTORY_ENABLED && plainSentIds.length > 0) {
79141
+ try {
79142
+ recordOutbound2({ chat_id: chatId, thread_id: threadId ?? null, message_ids: plainSentIds, texts: plainSentTexts });
79143
+ } catch (histErr) {
79144
+ process.stderr.write(`telegram gateway: history recordOutbound (captured-prose plain fallback) failed: ${histErr instanceof Error ? histErr.message : String(histErr)}
79145
+ `);
79146
+ }
79147
+ }
78938
79148
  process.stderr.write(`telegram gateway: captured-prose recovered via plain-text fallback ` + `(chat=${chatId} origin=${originTurnId})
78939
79149
  `);
78940
79150
  } catch (plainErr) {
@@ -81016,6 +81226,7 @@ function handleSessionEvent(deps, ev) {
81016
81226
  let sentIds = [];
81017
81227
  let chunkCount = 0;
81018
81228
  let delivered = false;
81229
+ let earlyJournaled = false;
81019
81230
  try {
81020
81231
  const delivery = await deliverAnswer({
81021
81232
  chatId: backstopChatId,
@@ -81023,7 +81234,21 @@ function handleSessionEvent(deps, ev) {
81023
81234
  text: capturedText,
81024
81235
  turnId: turn.turnId,
81025
81236
  cardMessageId: backstopCardMessageId,
81026
- replyToMessageId: turn.sourceMessageId
81237
+ replyToMessageId: turn.sourceMessageId,
81238
+ onAckClaim: (ackIds) => {
81239
+ try {
81240
+ journalExternalDelivery({
81241
+ turnNonce: turn.turnId,
81242
+ text: capturedText,
81243
+ tgMessageId: ackIds.length > 0 ? ackIds[0] : undefined,
81244
+ deliverySource: "flush"
81245
+ }, STATE_DIR);
81246
+ earlyJournaled = true;
81247
+ } catch (err) {
81248
+ process.stderr.write(`telegram gateway: turn-flush send-ack journal write failed (non-fatal): ${err.message}
81249
+ `);
81250
+ }
81251
+ }
81027
81252
  });
81028
81253
  sentIds = delivery.sentIds;
81029
81254
  chunkCount = delivery.chunkCount;
@@ -81069,7 +81294,7 @@ function handleSessionEvent(deps, ev) {
81069
81294
  chunkCount,
81070
81295
  cardMessageId: backstopCardMessageId
81071
81296
  });
81072
- if (delivered) {
81297
+ if (delivered && !earlyJournaled) {
81073
81298
  try {
81074
81299
  journalExternalDelivery({
81075
81300
  turnNonce: turn.turnId,
@@ -91719,6 +91944,18 @@ function computeTurnStatus(turn) {
91719
91944
  return turn.finalAnswerDelivered ? "complete" : "no_reply";
91720
91945
  }
91721
91946
  }
91947
+ function computeTurnRoute(turn) {
91948
+ switch (turn.deliveryOutcome) {
91949
+ case "failed":
91950
+ return "none";
91951
+ case "delivered":
91952
+ return "flush";
91953
+ case "suppressed":
91954
+ return "reply";
91955
+ default:
91956
+ return turn.finalAnswerDelivered ? turn.replyCalled ? "reply" : "stream" : "none";
91957
+ }
91958
+ }
91722
91959
  function buildTurnRecord(turn, endedAt) {
91723
91960
  return {
91724
91961
  ts: Math.floor(endedAt / 1000),
@@ -91727,6 +91964,11 @@ function buildTurnRecord(turn, endedAt) {
91727
91964
  tools: turn.toolCallCount ?? 0,
91728
91965
  status: computeTurnStatus(turn),
91729
91966
  turn_id: turn.turnId,
91967
+ route: computeTurnRoute({
91968
+ finalAnswerDelivered: turn.finalAnswerDelivered,
91969
+ replyCalled: turn.replyCalled ?? false,
91970
+ deliveryOutcome: turn.deliveryOutcome
91971
+ }),
91730
91972
  ...turn.landedUnconfirmed != null && turn.landedUnconfirmed > 0 ? { landed_unconfirmed: turn.landedUnconfirmed } : {}
91731
91973
  };
91732
91974
  }
@@ -91852,6 +92094,7 @@ async function runBackstopDelivery(ledger, turnId, chunks, cardMessageId, deps,
91852
92094
  const stderr = deps.stderr ?? (() => {});
91853
92095
  const chunkCount = chunks.length;
91854
92096
  let attempts = 0;
92097
+ let ackClaimed = false;
91855
92098
  for (let attempt = 1;attempt <= Math.max(1, maxAttempts); attempt++) {
91856
92099
  attempts = attempt;
91857
92100
  const resume = ledger.unsentIndices(turnId, chunkCount);
@@ -91875,6 +92118,18 @@ async function runBackstopDelivery(ledger, turnId, chunks, cardMessageId, deps,
91875
92118
  `);
91876
92119
  }
91877
92120
  }
92121
+ if (!ackClaimed && deps.onAckClaim != null) {
92122
+ const allLandedNow = chunkCount > 0 && ledger.unsentIndices(turnId, chunkCount).length === 0;
92123
+ if (allLandedNow && backstopReceiptIds(ledger.sentIds(turnId), cardMessageId).length > 0) {
92124
+ ackClaimed = true;
92125
+ try {
92126
+ deps.onAckClaim(ledger.sentIds(turnId));
92127
+ } catch (err) {
92128
+ stderr(`telegram gateway: backstop send-ack claim callback threw for turn ${turnId} ` + `(non-fatal): ${err instanceof Error ? err.message : String(err)}
92129
+ `);
92130
+ }
92131
+ }
92132
+ }
91878
92133
  let demotedAny = false;
91879
92134
  for (const i of ledger.landedUnconfirmedIndices(turnId, chunkCount)) {
91880
92135
  if (deps.readBack == null) {
@@ -93239,6 +93494,28 @@ function purgeStaleTurnsForChat(chatId, keys, purger, isStale = () => true) {
93239
93494
  return { purged };
93240
93495
  }
93241
93496
 
93497
+ // gateway/compaction-marker.ts
93498
+ import { statSync as statSync15, unlinkSync as unlinkSync21 } from "node:fs";
93499
+ import { homedir as homedir15 } from "node:os";
93500
+ import { join as join50 } from "node:path";
93501
+ var COMPACTION_MARKER_FILE = "compaction-in-flight.json";
93502
+ function resolveTelegramStateDir() {
93503
+ return process.env.TELEGRAM_STATE_DIR ?? join50(homedir15(), ".claude", "channels", "telegram");
93504
+ }
93505
+ function readCompactionMarkerAgeMs(stateDir, now) {
93506
+ try {
93507
+ const st = statSync15(join50(stateDir, COMPACTION_MARKER_FILE));
93508
+ return (now ?? Date.now()) - st.mtimeMs;
93509
+ } catch {
93510
+ return null;
93511
+ }
93512
+ }
93513
+ function removeCompactionMarker(stateDir) {
93514
+ try {
93515
+ unlinkSync21(join50(stateDir, COMPACTION_MARKER_FILE));
93516
+ } catch {}
93517
+ }
93518
+
93242
93519
  // gateway/hang-restart-decision.ts
93243
93520
  var HUMAN_WAIT_TOOLS2 = new Set(["ask_user"]);
93244
93521
  var BACKGROUND_TOOLS2 = new Set(["Task", "Agent"]);
@@ -93346,6 +93623,10 @@ function buildSilencePokeOptions(deps) {
93346
93623
  thresholdsMs: { fallback: SILENCE_FALLBACK_MS, fallbackHardCeiling: SILENCE_FALLBACK_HARD_MS, floor: SILENCE_FLOOR_MS },
93347
93624
  deferFallbackWhileToolInFlight: SILENCE_DEFER_INFLIGHT_TOOLS,
93348
93625
  isLegitimatelyWorking: (key) => isLegitimatelyWorking(key),
93626
+ isCompactionInFlight: () => {
93627
+ const ageMs = readCompactionMarkerAgeMs(STATE_DIR);
93628
+ return ageMs != null && ageMs >= 0 && ageMs < SILENCE_FALLBACK_HARD_MS;
93629
+ },
93349
93630
  isTurnLive: (key) => !(activeTurnStartedAt.get(key) == null && getCurrentTurnForKey(key) == null),
93350
93631
  emitMetric: (event) => {
93351
93632
  emitRuntimeMetric2(event);
@@ -93769,6 +94050,9 @@ function applySilencePokeSessionEvent(silencePoke, pendingProgress, key, ev) {
93769
94050
  if (ev.toolUseId != null && ev.toolUseId.length > 0) {
93770
94051
  silencePoke.noteToolEnd(key, ev.toolUseId, Date.now());
93771
94052
  }
94053
+ } else if (ev.kind === "compact_boundary") {
94054
+ removeCompactionMarker(resolveTelegramStateDir());
94055
+ silencePoke.noteProduction(key, Date.now());
93772
94056
  }
93773
94057
  applyBackgroundShellLiveness(silencePoke, key, ev);
93774
94058
  }
@@ -94054,17 +94338,17 @@ import {
94054
94338
  readFileSync as readFileSync37,
94055
94339
  writeSync as writeSync6
94056
94340
  } from "node:fs";
94057
- import { join as join50 } from "node:path";
94341
+ import { join as join51 } from "node:path";
94058
94342
  import { randomUUID as randomUUID5 } from "node:crypto";
94059
94343
  var PROPOSALS_FILE2 = "skill-proposals.jsonl";
94060
94344
  var REJECTED_FILE2 = "skill-proposals-rejected.jsonl";
94061
94345
  var REJECTION_TTL_MS2 = 90 * 24 * 60 * 60 * 1000;
94062
94346
  var PROPOSAL_SIM_THRESHOLD = 0.5;
94063
94347
  function proposalsPath2(stateDir) {
94064
- return join50(stateDir, PROPOSALS_FILE2);
94348
+ return join51(stateDir, PROPOSALS_FILE2);
94065
94349
  }
94066
94350
  function rejectedPath2(stateDir) {
94067
- return join50(stateDir, REJECTED_FILE2);
94351
+ return join51(stateDir, REJECTED_FILE2);
94068
94352
  }
94069
94353
  function ensureDir3(stateDir) {
94070
94354
  if (!existsSync41(stateDir)) {
@@ -94682,7 +94966,7 @@ function escapeBody2(s) {
94682
94966
  }
94683
94967
 
94684
94968
  // gateway/pid-file.ts
94685
- import { writeFileSync as writeFileSync33, readFileSync as readFileSync38, unlinkSync as unlinkSync21, renameSync as renameSync18 } from "node:fs";
94969
+ import { writeFileSync as writeFileSync33, readFileSync as readFileSync38, unlinkSync as unlinkSync22, renameSync as renameSync18 } from "node:fs";
94686
94970
  function writePidFile(path3, record) {
94687
94971
  const tmp = `${path3}.tmp-${process.pid}-${Date.now()}`;
94688
94972
  writeFileSync33(tmp, JSON.stringify(record), "utf-8");
@@ -94690,7 +94974,7 @@ function writePidFile(path3, record) {
94690
94974
  }
94691
94975
  function clearPidFile(path3) {
94692
94976
  try {
94693
- unlinkSync21(path3);
94977
+ unlinkSync22(path3);
94694
94978
  } catch {}
94695
94979
  }
94696
94980
 
@@ -94907,7 +95191,7 @@ function safeCount(fn) {
94907
95191
  }
94908
95192
 
94909
95193
  // gateway/session-marker.ts
94910
- import { writeFileSync as writeFileSync34, readFileSync as readFileSync40, renameSync as renameSync19, unlinkSync as unlinkSync22 } from "node:fs";
95194
+ import { writeFileSync as writeFileSync34, readFileSync as readFileSync40, renameSync as renameSync19, unlinkSync as unlinkSync23 } from "node:fs";
94911
95195
  function writeSessionMarker(path3, marker) {
94912
95196
  const tmp = `${path3}.tmp-${process.pid}-${Date.now()}`;
94913
95197
  writeFileSync34(tmp, JSON.stringify(marker), "utf-8");
@@ -94937,7 +95221,7 @@ function shouldFireRestartBanner(input) {
94937
95221
  }
94938
95222
 
94939
95223
  // gateway/clean-shutdown-marker.ts
94940
- import { writeFileSync as writeFileSync35, readFileSync as readFileSync41, renameSync as renameSync20, unlinkSync as unlinkSync23 } from "node:fs";
95224
+ import { writeFileSync as writeFileSync35, readFileSync as readFileSync41, renameSync as renameSync20, unlinkSync as unlinkSync24 } from "node:fs";
94941
95225
  var DEFAULT_MAX_AGE_MS = 60000;
94942
95226
  function writeCleanShutdownMarker(path3, marker) {
94943
95227
  const tmp = `${path3}.tmp-${process.pid}-${Date.now()}`;
@@ -94961,7 +95245,7 @@ function readCleanShutdownMarker(path3) {
94961
95245
  }
94962
95246
  function clearCleanShutdownMarker(path3) {
94963
95247
  try {
94964
- unlinkSync23(path3);
95248
+ unlinkSync24(path3);
94965
95249
  } catch {}
94966
95250
  }
94967
95251
  function shouldSuppressRecoveryBanner(marker, now, maxAgeMs = DEFAULT_MAX_AGE_MS) {
@@ -95321,13 +95605,13 @@ import {
95321
95605
  existsSync as existsSync42,
95322
95606
  openSync as openSync10,
95323
95607
  readSync as readSync2,
95324
- statSync as statSync15,
95608
+ statSync as statSync16,
95325
95609
  closeSync as closeSync10,
95326
95610
  watch,
95327
95611
  readdirSync as readdirSync10,
95328
95612
  readFileSync as readFileSync42
95329
95613
  } from "fs";
95330
- import { join as join51 } from "path";
95614
+ import { join as join52 } from "path";
95331
95615
 
95332
95616
  // session-tail.ts
95333
95617
  function sanitizeCwdToProjectName2(cwd) {
@@ -96134,7 +96418,7 @@ function startSubagentWatcher(config) {
96134
96418
  const fs3 = config.fs ?? {
96135
96419
  existsSync: existsSync42,
96136
96420
  readdirSync: readdirSync10,
96137
- statSync: statSync15,
96421
+ statSync: statSync16,
96138
96422
  openSync: openSync10,
96139
96423
  closeSync: closeSync10,
96140
96424
  readSync: readSync2,
@@ -96650,8 +96934,8 @@ function startSubagentWatcher(config) {
96650
96934
  if (stopped)
96651
96935
  return;
96652
96936
  pruneVanishedDirWatchers();
96653
- const claudeHome = join51(agentDir, ".claude");
96654
- const projectsRoot = join51(claudeHome, "projects");
96937
+ const claudeHome = join52(agentDir, ".claude");
96938
+ const projectsRoot = join52(claudeHome, "projects");
96655
96939
  if (!fs3.existsSync(projectsRoot))
96656
96940
  return;
96657
96941
  let projectDirs;
@@ -96685,7 +96969,7 @@ function startSubagentWatcher(config) {
96685
96969
  continue;
96686
96970
  }
96687
96971
  warnedForeignSlugs.delete(pDir);
96688
- const projectPath = join51(projectsRoot, pDir);
96972
+ const projectPath = join52(projectsRoot, pDir);
96689
96973
  let sessionDirs;
96690
96974
  try {
96691
96975
  sessionDirs = fs3.readdirSync(projectPath);
@@ -96695,7 +96979,7 @@ function startSubagentWatcher(config) {
96695
96979
  for (const sDir of sessionDirs) {
96696
96980
  if (sDir.endsWith(".jsonl"))
96697
96981
  continue;
96698
- const subagentsPath = join51(projectPath, sDir, "subagents");
96982
+ const subagentsPath = join52(projectPath, sDir, "subagents");
96699
96983
  if (!fs3.existsSync(subagentsPath))
96700
96984
  continue;
96701
96985
  const watchAndScan = (dirPath) => {
@@ -96704,7 +96988,7 @@ function startSubagentWatcher(config) {
96704
96988
  const w = fs3.watch(dirPath, (_event, filename) => {
96705
96989
  if (!filename || !filename.toString().startsWith("agent-") || !filename.toString().endsWith(".jsonl"))
96706
96990
  return;
96707
- const filePath = join51(dirPath, filename.toString());
96991
+ const filePath = join52(dirPath, filename.toString());
96708
96992
  if (!knownFiles.has(filePath)) {
96709
96993
  scanSubagentsDir(dirPath);
96710
96994
  }
@@ -96718,7 +97002,7 @@ function startSubagentWatcher(config) {
96718
97002
  scanSubagentsDir(dirPath);
96719
97003
  };
96720
97004
  watchAndScan(subagentsPath);
96721
- const workflowsPath = join51(subagentsPath, "workflows");
97005
+ const workflowsPath = join52(subagentsPath, "workflows");
96722
97006
  if (fs3.existsSync(workflowsPath)) {
96723
97007
  let wfDirs;
96724
97008
  try {
@@ -96728,7 +97012,7 @@ function startSubagentWatcher(config) {
96728
97012
  }
96729
97013
  for (const wfDir of wfDirs) {
96730
97014
  try {
96731
- const wfPath = join51(workflowsPath, wfDir);
97015
+ const wfPath = join52(workflowsPath, wfDir);
96732
97016
  if (!fs3.statSync(wfPath).isDirectory())
96733
97017
  continue;
96734
97018
  watchAndScan(wfPath);
@@ -96748,7 +97032,7 @@ function startSubagentWatcher(config) {
96748
97032
  for (const e of entries) {
96749
97033
  if (!e.startsWith("agent-") || !e.endsWith(".jsonl"))
96750
97034
  continue;
96751
- const filePath = join51(subagentsPath, e);
97035
+ const filePath = join52(subagentsPath, e);
96752
97036
  if (knownFiles.has(filePath))
96753
97037
  continue;
96754
97038
  const agentId = e.slice("agent-".length, -".jsonl".length);
@@ -96880,17 +97164,17 @@ import {
96880
97164
  writeFileSync as writeFileSync36,
96881
97165
  readFileSync as readFileSync43,
96882
97166
  readdirSync as readdirSync11,
96883
- unlinkSync as unlinkSync24,
97167
+ unlinkSync as unlinkSync25,
96884
97168
  existsSync as existsSync43,
96885
97169
  renameSync as renameSync21
96886
97170
  } from "node:fs";
96887
- import { join as join52, resolve as resolve10 } from "node:path";
96888
- import { homedir as homedir15 } from "node:os";
97171
+ import { join as join53, resolve as resolve10 } from "node:path";
97172
+ import { homedir as homedir16 } from "node:os";
96889
97173
  function registryDir() {
96890
- return resolve10(process.env.SWITCHROOM_WORKTREE_DIR ?? join52(homedir15(), ".switchroom", "worktrees"));
97174
+ return resolve10(process.env.SWITCHROOM_WORKTREE_DIR ?? join53(homedir16(), ".switchroom", "worktrees"));
96891
97175
  }
96892
97176
  function recordPath(id) {
96893
- return join52(registryDir(), `${id}.json`);
97177
+ return join53(registryDir(), `${id}.json`);
96894
97178
  }
96895
97179
  function ensureDir4() {
96896
97180
  mkdirSync38(registryDir(), { recursive: true });
@@ -97066,19 +97350,19 @@ function determineRestartReason(opts) {
97066
97350
 
97067
97351
  // gateway/update-announce.ts
97068
97352
  import { existsSync as existsSync48, mkdirSync as mkdirSync42, openSync as openSync11, closeSync as closeSync11, readFileSync as readFileSync50 } from "node:fs";
97069
- import { join as join57 } from "node:path";
97070
- import { homedir as homedir17 } from "node:os";
97353
+ import { join as join58 } from "node:path";
97354
+ import { homedir as homedir18 } from "node:os";
97071
97355
 
97072
97356
  // ../src/host-control/audit-reader.ts
97073
- import { homedir as homedir16 } from "node:os";
97074
- import { join as join56 } from "node:path";
97357
+ import { homedir as homedir17 } from "node:os";
97358
+ import { join as join57 } from "node:path";
97075
97359
 
97076
97360
  // ../src/host-control/audit-rotation-config.ts
97077
97361
  var DEFAULT_HOSTD_AUDIT_MAX_BYTES = 32 * 1024 * 1024;
97078
97362
 
97079
97363
  // ../src/host-control/audit-reader.ts
97080
- function defaultAuditLogPath(home2 = homedir16()) {
97081
- return join56(home2, ".switchroom", "host-control-audit.log");
97364
+ function defaultAuditLogPath(home2 = homedir17()) {
97365
+ return join57(home2, ".switchroom", "host-control-audit.log");
97082
97366
  }
97083
97367
  var AUDIT_READ_WINDOW_BYTES = 4 * 1024 * 1024;
97084
97368
  function parseAuditLine(line) {
@@ -97273,15 +97557,15 @@ function renderUpdateOutcomeLine(entry) {
97273
97557
  `);
97274
97558
  }
97275
97559
  function claimUpdateAnnouncement(requestId, opts = {}) {
97276
- const stateDir = opts.stateDir ?? process.env.TELEGRAM_STATE_DIR ?? join57(homedir17(), ".switchroom");
97277
- const dir = join57(stateDir, "update-announced");
97560
+ const stateDir = opts.stateDir ?? process.env.TELEGRAM_STATE_DIR ?? join58(homedir18(), ".switchroom");
97561
+ const dir = join58(stateDir, "update-announced");
97278
97562
  try {
97279
97563
  mkdirSync42(dir, { recursive: true });
97280
97564
  } catch {
97281
97565
  return false;
97282
97566
  }
97283
97567
  const safeId = requestId.replace(/[^A-Za-z0-9_.-]/g, "_").slice(0, 200);
97284
- const path3 = join57(dir, safeId);
97568
+ const path3 = join58(dir, safeId);
97285
97569
  try {
97286
97570
  const fd = openSync11(path3, "wx");
97287
97571
  closeSync11(fd);
@@ -97502,8 +97786,8 @@ function createIssuesCardHandle(opts) {
97502
97786
  }
97503
97787
 
97504
97788
  // issues-watcher.ts
97505
- import { existsSync as existsSync50, statSync as statSync18 } from "node:fs";
97506
- import { join as join59 } from "node:path";
97789
+ import { existsSync as existsSync50, statSync as statSync19 } from "node:fs";
97790
+ import { join as join60 } from "node:path";
97507
97791
 
97508
97792
  // ../src/issues/store.ts
97509
97793
  import {
@@ -97514,12 +97798,12 @@ import {
97514
97798
  readdirSync as readdirSync13,
97515
97799
  readFileSync as readFileSync52,
97516
97800
  renameSync as renameSync24,
97517
- statSync as statSync17,
97518
- unlinkSync as unlinkSync25,
97801
+ statSync as statSync18,
97802
+ unlinkSync as unlinkSync26,
97519
97803
  writeFileSync as writeFileSync42,
97520
97804
  writeSync as writeSync7
97521
97805
  } from "node:fs";
97522
- import { join as join58 } from "node:path";
97806
+ import { join as join59 } from "node:path";
97523
97807
  import { randomBytes as randomBytes11 } from "node:crypto";
97524
97808
  import { execSync } from "node:child_process";
97525
97809
 
@@ -97538,7 +97822,7 @@ init_redact();
97538
97822
  var ISSUES_FILE = "issues.jsonl";
97539
97823
  var ISSUES_LOCK = "issues.lock";
97540
97824
  function readAll(stateDir) {
97541
- const path3 = join58(stateDir, ISSUES_FILE);
97825
+ const path3 = join59(stateDir, ISSUES_FILE);
97542
97826
  if (!existsSync49(path3))
97543
97827
  return [];
97544
97828
  let raw;
@@ -97575,7 +97859,7 @@ function list2(stateDir, opts = {}) {
97575
97859
  });
97576
97860
  }
97577
97861
  function resolve11(stateDir, fingerprint, nowFn = Date.now) {
97578
- if (!existsSync49(join58(stateDir, ISSUES_FILE)))
97862
+ if (!existsSync49(join59(stateDir, ISSUES_FILE)))
97579
97863
  return 0;
97580
97864
  return withLock(stateDir, () => {
97581
97865
  const all2 = readAll(stateDir);
@@ -97593,7 +97877,7 @@ function resolve11(stateDir, fingerprint, nowFn = Date.now) {
97593
97877
  });
97594
97878
  }
97595
97879
  function writeAll(stateDir, events) {
97596
- const path3 = join58(stateDir, ISSUES_FILE);
97880
+ const path3 = join59(stateDir, ISSUES_FILE);
97597
97881
  sweepOrphanTmpFiles(stateDir);
97598
97882
  const tmp = `${path3}.tmp-${process.pid}-${randomBytes11(4).toString("hex")}`;
97599
97883
  const body = events.length === 0 ? "" : events.map((e) => JSON.stringify(e)).join(`
@@ -97615,11 +97899,11 @@ function sweepOrphanTmpFiles(stateDir) {
97615
97899
  for (const entry of entries) {
97616
97900
  if (!entry.startsWith(TMP_PREFIX))
97617
97901
  continue;
97618
- const tmpPath2 = join58(stateDir, entry);
97902
+ const tmpPath2 = join59(stateDir, entry);
97619
97903
  try {
97620
- const stat = statSync17(tmpPath2);
97904
+ const stat = statSync18(tmpPath2);
97621
97905
  if (stat.mtimeMs < cutoff) {
97622
- unlinkSync25(tmpPath2);
97906
+ unlinkSync26(tmpPath2);
97623
97907
  }
97624
97908
  } catch {}
97625
97909
  }
@@ -97627,7 +97911,7 @@ function sweepOrphanTmpFiles(stateDir) {
97627
97911
  var LOCK_RETRY_MS = 25;
97628
97912
  var LOCK_TIMEOUT_MS = 1e4;
97629
97913
  function withLock(stateDir, fn) {
97630
- const lockPath = join58(stateDir, ISSUES_LOCK);
97914
+ const lockPath = join59(stateDir, ISSUES_LOCK);
97631
97915
  const startedAt = Date.now();
97632
97916
  let fd = null;
97633
97917
  while (fd === null) {
@@ -97655,7 +97939,7 @@ function withLock(stateDir, fn) {
97655
97939
  closeSync12(fd);
97656
97940
  } catch {}
97657
97941
  try {
97658
- unlinkSync25(lockPath);
97942
+ unlinkSync26(lockPath);
97659
97943
  } catch {}
97660
97944
  }
97661
97945
  }
@@ -97669,13 +97953,13 @@ function tryStealStaleLock(lockPath) {
97669
97953
  const pid = Number(pidStr);
97670
97954
  if (!Number.isFinite(pid) || pid <= 0) {
97671
97955
  try {
97672
- unlinkSync25(lockPath);
97956
+ unlinkSync26(lockPath);
97673
97957
  } catch {}
97674
97958
  return true;
97675
97959
  }
97676
97960
  if (pid === process.pid) {
97677
97961
  try {
97678
- unlinkSync25(lockPath);
97962
+ unlinkSync26(lockPath);
97679
97963
  } catch {}
97680
97964
  return true;
97681
97965
  }
@@ -97690,7 +97974,7 @@ function tryStealStaleLock(lockPath) {
97690
97974
  return false;
97691
97975
  }
97692
97976
  try {
97693
- unlinkSync25(lockPath);
97977
+ unlinkSync26(lockPath);
97694
97978
  } catch {}
97695
97979
  return true;
97696
97980
  }
@@ -97712,7 +97996,7 @@ function isIssueEvent(v) {
97712
97996
  // issues-watcher.ts
97713
97997
  var DEFAULT_POLL_INTERVAL_MS2 = 2000;
97714
97998
  function startIssuesWatcher(opts) {
97715
- const path3 = join59(opts.stateDir, ISSUES_FILE);
97999
+ const path3 = join60(opts.stateDir, ISSUES_FILE);
97716
98000
  const log = opts.log ?? (() => {});
97717
98001
  const intervalMs = opts.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS2;
97718
98002
  const setIntervalFn = opts.setInterval ?? setInterval;
@@ -97763,7 +98047,7 @@ function defaultSignatureProvider(path3) {
97763
98047
  if (!existsSync50(path3))
97764
98048
  return null;
97765
98049
  try {
97766
- const stat = statSync18(path3);
98050
+ const stat = statSync19(path3);
97767
98051
  return `${stat.mtimeMs}:${stat.size}`;
97768
98052
  } catch {
97769
98053
  return null;
@@ -98472,7 +98756,7 @@ function readBashCommand(inputPreview) {
98472
98756
 
98473
98757
  // gateway/scoped-grant-store.ts
98474
98758
  init_atomic();
98475
- import { join as join60 } from "node:path";
98759
+ import { join as join61 } from "node:path";
98476
98760
 
98477
98761
  // scoped-approval.ts
98478
98762
  var SCOPED_APPROVAL_DEFAULT_TTL_MS2 = 30 * 60 * 1000;
@@ -98514,7 +98798,7 @@ function scopedGrantPersistEnabled(env = process.env) {
98514
98798
  return env.SWITCHROOM_SCOPED_GRANT_PERSIST !== "0";
98515
98799
  }
98516
98800
  function createScopedGrantStore(stateDir, env = process.env, log = (l) => process.stderr.write(l)) {
98517
- const filePath = join60(stateDir, "scoped-grants.json");
98801
+ const filePath = join61(stateDir, "scoped-grants.json");
98518
98802
  const enabled7 = scopedGrantPersistEnabled(env);
98519
98803
  let unreadable = false;
98520
98804
  function read() {
@@ -98893,7 +99177,7 @@ function isDiffPreApproved(agentName3, unifiedDiff, deps) {
98893
99177
  // credits-watch.ts
98894
99178
  init_card_format();
98895
99179
  import { readFileSync as readFileSync53, writeFileSync as writeFileSync43, existsSync as existsSync51, mkdirSync as mkdirSync44 } from "fs";
98896
- import { join as join61 } from "path";
99180
+ import { join as join62 } from "path";
98897
99181
  var STATE_FILE = "credits-watch.json";
98898
99182
  var DEFAULT_CREDIT_FATAL_REASONS = new Set;
98899
99183
  var KNOWN_CREDIT_REASONS = [
@@ -98915,7 +99199,7 @@ function emptyCreditState() {
98915
99199
  return { lastNotifiedReason: null, lastNotifiedAt: 0 };
98916
99200
  }
98917
99201
  function readClaudeJsonOverage(claudeConfigDir) {
98918
- const path3 = join61(claudeConfigDir, ".claude.json");
99202
+ const path3 = join62(claudeConfigDir, ".claude.json");
98919
99203
  if (!existsSync51(path3))
98920
99204
  return null;
98921
99205
  let raw;
@@ -98998,7 +99282,7 @@ function humanizeReason(reason) {
98998
99282
  }
98999
99283
  }
99000
99284
  function loadCreditState(stateDir) {
99001
- const path3 = join61(stateDir, STATE_FILE);
99285
+ const path3 = join62(stateDir, STATE_FILE);
99002
99286
  if (!existsSync51(path3))
99003
99287
  return emptyCreditState();
99004
99288
  try {
@@ -99015,7 +99299,7 @@ function loadCreditState(stateDir) {
99015
99299
  }
99016
99300
  function saveCreditState(stateDir, state7) {
99017
99301
  mkdirSync44(stateDir, { recursive: true });
99018
- const path3 = join61(stateDir, STATE_FILE);
99302
+ const path3 = join62(stateDir, STATE_FILE);
99019
99303
  writeFileSync43(path3, JSON.stringify(state7, null, 2) + `
99020
99304
  `, { mode: 384 });
99021
99305
  }
@@ -99024,7 +99308,7 @@ function saveCreditState(stateDir, state7) {
99024
99308
  init_auth_snapshot_format();
99025
99309
  init_card_format();
99026
99310
  import { readFileSync as readFileSync54, writeFileSync as writeFileSync44, existsSync as existsSync52, mkdirSync as mkdirSync45 } from "fs";
99027
- import { join as join62 } from "path";
99311
+ import { join as join63 } from "path";
99028
99312
  var STATE_FILE2 = "quota-watch.json";
99029
99313
  function emptyQuotaWatchState() {
99030
99314
  return {};
@@ -99262,7 +99546,7 @@ function buildRecoveryMessage(agentName3, snap) {
99262
99546
  `);
99263
99547
  }
99264
99548
  function loadQuotaWatchState(stateDir) {
99265
- const path3 = join62(stateDir, STATE_FILE2);
99549
+ const path3 = join63(stateDir, STATE_FILE2);
99266
99550
  if (!existsSync52(path3))
99267
99551
  return emptyQuotaWatchState();
99268
99552
  try {
@@ -99284,7 +99568,7 @@ function loadQuotaWatchState(stateDir) {
99284
99568
  }
99285
99569
  function saveQuotaWatchState(stateDir, state7) {
99286
99570
  mkdirSync45(stateDir, { recursive: true });
99287
- const path3 = join62(stateDir, STATE_FILE2);
99571
+ const path3 = join63(stateDir, STATE_FILE2);
99288
99572
  writeFileSync44(path3, JSON.stringify(state7, null, 2) + `
99289
99573
  `, { mode: 384 });
99290
99574
  }
@@ -99337,27 +99621,27 @@ import {
99337
99621
  mkdirSync as mkdirSync46,
99338
99622
  openSync as openSync13,
99339
99623
  readFileSync as readFileSync55,
99340
- statSync as statSync19,
99341
- unlinkSync as unlinkSync26,
99624
+ statSync as statSync20,
99625
+ unlinkSync as unlinkSync27,
99342
99626
  utimesSync as utimesSync2,
99343
99627
  writeFileSync as writeFileSync45
99344
99628
  } from "node:fs";
99345
- import { join as join63 } from "node:path";
99629
+ import { join as join64 } from "node:path";
99346
99630
  var TURN_ACTIVE_MARKER_FILE2 = "turn-active.json";
99347
99631
  var TURN_ACTIVE_HARD_TTL_MS2 = 10 * 60000;
99348
99632
  var TURN_ACTIVE_IDLE_SWEEP_MS = 60000;
99349
99633
  function removeTurnActiveMarker2(stateDir) {
99350
99634
  try {
99351
- unlinkSync26(join63(stateDir, TURN_ACTIVE_MARKER_FILE2));
99635
+ unlinkSync27(join64(stateDir, TURN_ACTIVE_MARKER_FILE2));
99352
99636
  } catch {}
99353
99637
  }
99354
99638
  function sweepStaleTurnActiveMarker(stateDir, opts) {
99355
- const path3 = join63(stateDir, TURN_ACTIVE_MARKER_FILE2);
99639
+ const path3 = join64(stateDir, TURN_ACTIVE_MARKER_FILE2);
99356
99640
  if (!existsSync53(path3))
99357
99641
  return false;
99358
99642
  const now = opts.now ?? Date.now();
99359
99643
  try {
99360
- const st = statSync19(path3);
99644
+ const st = statSync20(path3);
99361
99645
  const ageMs = now - st.mtimeMs;
99362
99646
  const hardExpired = ageMs > opts.hardTtlMs;
99363
99647
  const idleExpired = !opts.turnInFlight && ageMs > opts.idleSweepMs;
@@ -99367,7 +99651,7 @@ function sweepStaleTurnActiveMarker(stateDir, opts) {
99367
99651
  try {
99368
99652
  payload = readFileSync55(path3, "utf8");
99369
99653
  } catch {}
99370
- unlinkSync26(path3);
99654
+ unlinkSync27(path3);
99371
99655
  if (opts.onRemove) {
99372
99656
  try {
99373
99657
  opts.onRemove({
@@ -99383,9 +99667,9 @@ function sweepStaleTurnActiveMarker(stateDir, opts) {
99383
99667
  }
99384
99668
  }
99385
99669
  function readTurnActiveMarkerAgeMs2(stateDir, now) {
99386
- const path3 = join63(stateDir, TURN_ACTIVE_MARKER_FILE2);
99670
+ const path3 = join64(stateDir, TURN_ACTIVE_MARKER_FILE2);
99387
99671
  try {
99388
- const st = statSync19(path3);
99672
+ const st = statSync20(path3);
99389
99673
  return (now ?? Date.now()) - st.mtimeMs;
99390
99674
  } catch {
99391
99675
  return null;
@@ -99397,11 +99681,11 @@ function effectiveTurnAgeMs(markerAgeMs, turnStartedAt, now) {
99397
99681
 
99398
99682
  // gateway/gateway-heartbeat.ts
99399
99683
  import { mkdirSync as mkdirSync47, utimesSync as utimesSync3, writeFileSync as writeFileSync46 } from "node:fs";
99400
- import { join as join64 } from "node:path";
99684
+ import { join as join65 } from "node:path";
99401
99685
  var GATEWAY_HEARTBEAT_FILE = "gateway-heartbeat";
99402
99686
  var GATEWAY_HEARTBEAT_INTERVAL_MS = 15000;
99403
99687
  function touchGatewayHeartbeat(stateDir) {
99404
- const path3 = join64(stateDir, GATEWAY_HEARTBEAT_FILE);
99688
+ const path3 = join65(stateDir, GATEWAY_HEARTBEAT_FILE);
99405
99689
  const now = new Date;
99406
99690
  try {
99407
99691
  utimesSync3(path3, now, now);
@@ -99429,10 +99713,10 @@ import {
99429
99713
  openSync as openSync14,
99430
99714
  readFileSync as readFileSync56,
99431
99715
  renameSync as renameSync25,
99432
- unlinkSync as unlinkSync27,
99716
+ unlinkSync as unlinkSync28,
99433
99717
  writeFileSync as writeFileSync47
99434
99718
  } from "node:fs";
99435
- import { join as join65 } from "node:path";
99719
+ import { join as join66 } from "node:path";
99436
99720
  var BOOT_BEACON_FILE = "gateway-beacon.json";
99437
99721
  var HOST_BOOT_ID_PATH = "/proc/sys/kernel/random/boot_id";
99438
99722
  var CGROUP_MEMORY_EVENTS_PATH = "/sys/fs/cgroup/memory.events";
@@ -99531,7 +99815,7 @@ function sampleBeaconHost(paths = {}) {
99531
99815
  return sample3;
99532
99816
  }
99533
99817
  function writeBootBeaconFile(stateDir, beacon) {
99534
- const path3 = join65(stateDir, BOOT_BEACON_FILE);
99818
+ const path3 = join66(stateDir, BOOT_BEACON_FILE);
99535
99819
  const tmp = `${path3}.tmp-${process.pid}`;
99536
99820
  let fd;
99537
99821
  try {
@@ -99550,7 +99834,7 @@ function writeBootBeaconFile(stateDir, beacon) {
99550
99834
  } catch {}
99551
99835
  }
99552
99836
  try {
99553
- unlinkSync27(tmp);
99837
+ unlinkSync28(tmp);
99554
99838
  } catch {}
99555
99839
  return false;
99556
99840
  }
@@ -99578,6 +99862,8 @@ function attachBootBeacon(stateDir, next) {
99578
99862
  }
99579
99863
 
99580
99864
  // gateway/outbox-sweep.ts
99865
+ init_rich_send();
99866
+ init_format();
99581
99867
  init_flood_circuit_breaker();
99582
99868
  async function sweepOutbox(deps) {
99583
99869
  const now = deps.now?.() ?? Date.now();
@@ -99650,15 +99936,20 @@ async function sweepOutbox(deps) {
99650
99936
  }
99651
99937
  const resolvedChat = resolved;
99652
99938
  try {
99653
- const messageId = await deps.send(resolvedChat.chatId, resolvedChat.threadId, decision.text ?? record2.text);
99939
+ const sendResult = await deps.send(resolvedChat.chatId, resolvedChat.threadId, decision.text ?? record2.text);
99654
99940
  appendDelivered({
99655
99941
  turnNonce: record2.turnNonce,
99656
99942
  textSha256: record2.textSha256,
99657
- tgMessageId: messageId,
99943
+ tgMessageId: sendResult.messageId,
99658
99944
  ts: now,
99659
99945
  deliverySource: "sweep",
99660
99946
  replyAlreadyDeliveredThisTurn: record2.replyAlreadyDeliveredThisTurn === true
99661
99947
  }, deps.stateDir);
99948
+ if (deps.recordOutbound != null && sendResult.chunks.length > 0) {
99949
+ try {
99950
+ deps.recordOutbound(resolvedChat.chatId, resolvedChat.threadId, sendResult.chunks.map((c) => c.messageId), sendResult.chunks.map((c) => c.text));
99951
+ } catch {}
99952
+ }
99662
99953
  removeClaimed(record2.turnNonce, deps.stateDir);
99663
99954
  summary.delivered++;
99664
99955
  log(`outbox-sweep: delivered nonce=${record2.turnNonce} via=${resolvedChat.via} ` + `source=${record2.source} chars=${record2.text.length}${decision.action === "send-delayed" ? " (delayed)" : ""}
@@ -99713,27 +100004,42 @@ function createSweepBackoff(cfg = {}) {
99713
100004
  failures: () => failures
99714
100005
  };
99715
100006
  }
100007
+ async function sendChunkRich(bot, chatId, chunk2, opts) {
100008
+ try {
100009
+ return await bot.api.sendRichMessage(chatId, richMessage(chunk2), opts);
100010
+ } catch (err) {
100011
+ if (isParseEntitiesError(err)) {
100012
+ return await bot.api.sendMessage(chatId, chunk2, opts);
100013
+ }
100014
+ throw err;
100015
+ }
100016
+ }
99716
100017
  function createOutboxSend(deps) {
99717
100018
  return async (chatId, threadId, text4) => {
99718
100019
  const bot = deps.getBot();
99719
100020
  if (bot == null)
99720
100021
  throw new Error("outbox-sweep: bot unavailable");
99721
100022
  if (text4.length === 0)
99722
- return;
100023
+ return { messageId: undefined, chunks: [] };
99723
100024
  const replyMarkup = deps.resolveReplyMarkup?.(chatId, threadId, text4);
99724
- let lastId;
99725
- const chunkCount = Math.ceil(text4.length / 4000);
99726
- for (let i = 0, idx = 0;i < text4.length; i += 4000, idx++) {
99727
- const chunk2 = text4.slice(i, i + 4000);
99728
- const isLast = idx === chunkCount - 1;
100025
+ const landed = [];
100026
+ const chunks = splitMarkdownChunks(text4);
100027
+ for (let idx = 0;idx < chunks.length; idx++) {
100028
+ const chunk2 = chunks[idx];
100029
+ const isLast = idx === chunks.length - 1;
99729
100030
  const res = await retryWithThreadFallback(deps.retry, (tid) => {
99730
100031
  const base = tid != null ? { message_thread_id: tid } : {};
99731
100032
  const opts = isLast && replyMarkup != null ? { ...base, reply_markup: replyMarkup } : base;
99732
- return bot.api.sendMessage(chatId, chunk2, opts);
100033
+ return sendChunkRich(bot, chatId, chunk2, opts);
99733
100034
  }, { threadId: threadId ?? undefined, chat_id: chatId, verb: "outbox-sweep.sendMessage" });
99734
- lastId = res?.message_id;
100035
+ const id = res?.message_id;
100036
+ if (id != null)
100037
+ landed.push({ messageId: id, text: chunk2 });
99735
100038
  }
99736
- return lastId;
100039
+ return {
100040
+ messageId: landed.length > 0 ? landed[landed.length - 1].messageId : undefined,
100041
+ chunks: landed
100042
+ };
99737
100043
  };
99738
100044
  }
99739
100045
  function startOutboxSweep(deps) {
@@ -99764,6 +100070,7 @@ function startOutboxSweep(deps) {
99764
100070
  stateDir: deps.stateDir,
99765
100071
  log: deps.log,
99766
100072
  send,
100073
+ ...deps.recordOutbound != null ? { recordOutbound: deps.recordOutbound } : {},
99767
100074
  floodWaitRemainingMs: floodProbe,
99768
100075
  textAlreadyDelivered: (chatId, threadId, text4) => deps.dedupCheck(chatId, threadId ?? undefined, text4),
99769
100076
  registryChainLookup: (taskId) => {
@@ -99799,10 +100106,10 @@ function startOutboxSweep(deps) {
99799
100106
  }
99800
100107
 
99801
100108
  // ../src/build-info.ts
99802
- var VERSION2 = "0.19.39";
99803
- var COMMIT_SHA = "4aff2bdd";
99804
- var COMMIT_DATE = "2026-07-31T00:54:36Z";
99805
- var LATEST_PR = 4041;
100109
+ var VERSION2 = "0.19.41";
100110
+ var COMMIT_SHA = "e77ee9c0";
100111
+ var COMMIT_DATE = "2026-07-31T09:46:10Z";
100112
+ var LATEST_PR = 4066;
99806
100113
  var COMMITS_AHEAD_OF_TAG = 0;
99807
100114
 
99808
100115
  // gateway/boot-version.ts
@@ -99879,12 +100186,12 @@ init_protocol2();
99879
100186
  init_peercred();
99880
100187
  import * as net5 from "node:net";
99881
100188
  import * as fs3 from "node:fs";
99882
- import { homedir as homedir18 } from "node:os";
99883
- import { join as join66 } from "node:path";
100189
+ import { homedir as homedir19 } from "node:os";
100190
+ import { join as join67 } from "node:path";
99884
100191
  var DEFAULT_TIMEOUT_MS4 = 2000;
99885
100192
  var UNLOCK_TIMEOUT_MS = 30000;
99886
- var LEGACY_SOCKET_PATH2 = join66(homedir18(), ".switchroom", "vault-broker.sock");
99887
- var OPERATOR_SOCKET_PATH2 = join66(homedir18(), ".switchroom", "broker-operator", "sock");
100193
+ var LEGACY_SOCKET_PATH2 = join67(homedir19(), ".switchroom", "vault-broker.sock");
100194
+ var OPERATOR_SOCKET_PATH2 = join67(homedir19(), ".switchroom", "broker-operator", "sock");
99888
100195
  function defaultBrokerSocketPath2() {
99889
100196
  if (fs3.existsSync(OPERATOR_SOCKET_PATH2))
99890
100197
  return OPERATOR_SOCKET_PATH2;
@@ -100767,7 +101074,7 @@ function resolveVaultApprovalPosture(broker) {
100767
101074
 
100768
101075
  // registry/turns-schema.ts
100769
101076
  import { chmodSync as chmodSync12, mkdirSync as mkdirSync49 } from "fs";
100770
- import { join as join67 } from "path";
101077
+ import { join as join68 } from "path";
100771
101078
  var DatabaseClass3 = null;
100772
101079
  function loadDatabaseClass3() {
100773
101080
  if (DatabaseClass3 != null)
@@ -100839,9 +101146,9 @@ function applySchema(db3) {
100839
101146
  }
100840
101147
  function openTurnsDb(agentDir) {
100841
101148
  const Database = loadDatabaseClass3();
100842
- const dir = join67(agentDir, "telegram");
101149
+ const dir = join68(agentDir, "telegram");
100843
101150
  mkdirSync49(dir, { recursive: true, mode: 448 });
100844
- const path3 = join67(dir, "registry.db");
101151
+ const path3 = join68(dir, "registry.db");
100845
101152
  const db3 = new Database(path3, { create: true });
100846
101153
  applySchema(db3);
100847
101154
  try {
@@ -101186,7 +101493,7 @@ function selectResumeBuilder(endedVia, opts) {
101186
101493
  }
101187
101494
 
101188
101495
  // gateway/bridge-dead-watchdog.ts
101189
- import { readFileSync as readFileSync58, writeFileSync as writeFileSync48, renameSync as renameSync26, unlinkSync as unlinkSync28 } from "node:fs";
101496
+ import { readFileSync as readFileSync58, writeFileSync as writeFileSync48, renameSync as renameSync26, unlinkSync as unlinkSync29 } from "node:fs";
101190
101497
 
101191
101498
  // gateway/cron-session.ts
101192
101499
  var CRON_IDENTITY_SUFFIX2 = "-cron";
@@ -101258,7 +101565,7 @@ function consumeBridgeDeadEscalationMarker(path3, nowMs3 = Date.now(), maxAgeMs
101258
101565
  }
101259
101566
  } catch {}
101260
101567
  try {
101261
- unlinkSync28(path3);
101568
+ unlinkSync29(path3);
101262
101569
  } catch {}
101263
101570
  return marker;
101264
101571
  }
@@ -101658,7 +101965,7 @@ if (isGatewayMain) {
101658
101965
  shutdownAnalytics();
101659
101966
  });
101660
101967
  }
101661
- var STATE_DIR = process.env.TELEGRAM_STATE_DIR ?? join68(homedir19(), ".claude", "channels", "telegram");
101968
+ var STATE_DIR = process.env.TELEGRAM_STATE_DIR ?? join69(homedir20(), ".claude", "channels", "telegram");
101662
101969
  var permCardStore = createPermissionCardStore(STATE_DIR);
101663
101970
  var BLOCKED_APPROVALS_DIR = process.env.SWITCHROOM_BLOCKED_APPROVALS_DIR ?? "/state/blocked-approvals";
101664
101971
  var AGENT_NAME = process.env.SWITCHROOM_AGENT_NAME ?? "agent";
@@ -101758,11 +102065,11 @@ function scheduleAlwaysAllowPersistDrain() {
101758
102065
  }, ALWAYS_ALLOW_DRAIN_INTERVAL_MS);
101759
102066
  timer3.unref?.();
101760
102067
  }
101761
- var ACCESS_FILE = join68(STATE_DIR, "access.json");
101762
- var APPROVED_DIR = join68(STATE_DIR, "approved");
101763
- var ENV_FILE = join68(STATE_DIR, ".env");
101764
- var INBOX_DIR = join68(STATE_DIR, "inbox");
101765
- var PEOPLE_FILE = join68(STATE_DIR, "people.json");
102068
+ var ACCESS_FILE = join69(STATE_DIR, "access.json");
102069
+ var APPROVED_DIR = join69(STATE_DIR, "approved");
102070
+ var ENV_FILE = join69(STATE_DIR, ".env");
102071
+ var INBOX_DIR = join69(STATE_DIR, "inbox");
102072
+ var PEOPLE_FILE = join69(STATE_DIR, "people.json");
101766
102073
  function triggerSelfRestart(targetAgent, reason, delayMs = 300) {
101767
102074
  const isDocker = process.env.SWITCHROOM_RUNTIME === "docker";
101768
102075
  const selfAgent = process.env.SWITCHROOM_AGENT_NAME;
@@ -101857,40 +102164,21 @@ var GRAMMY_VERSION = (() => {
101857
102164
  var _rawSendChecklist;
101858
102165
  var _rawEditMessageChecklist;
101859
102166
  var CHECKLIST_API_AVAILABLE = false;
101860
- async function rawSendChecklist(args) {
101861
- if (!CHECKLIST_API_AVAILABLE) {
102167
+ async function rawSendChecklist(payload) {
102168
+ if (!CHECKLIST_API_AVAILABLE)
101862
102169
  throw new Error("sendChecklist is not available in this grammY/Telegram Bot API version");
101863
- }
101864
- const MAX_TASKS = 30;
101865
- if (args.tasks.length > MAX_TASKS) {
101866
- throw new Error(`checklist exceeds ${MAX_TASKS}-task limit (got ${args.tasks.length})`);
101867
- }
101868
- const result = await _rawSendChecklist({
101869
- chat_id: Number(args.chat_id),
101870
- title: args.title,
101871
- tasks: args.tasks.map((t) => ({ text: t.text, ...t.done != null ? { is_completed: t.done } : {} })),
101872
- ...args.message_thread_id != null ? { message_thread_id: args.message_thread_id } : {},
101873
- ...args.reply_to_message_id != null ? { reply_to_message_id: args.reply_to_message_id } : {},
101874
- ...args.protect_content === true ? { protect_content: true } : {}
101875
- });
102170
+ const result = await _rawSendChecklist(payload);
101876
102171
  return { message_id: result.message_id };
101877
102172
  }
101878
- async function rawEditMessageChecklist(args) {
101879
- if (!CHECKLIST_API_AVAILABLE) {
102173
+ async function rawEditMessageChecklist(payload) {
102174
+ if (!CHECKLIST_API_AVAILABLE)
101880
102175
  throw new Error("editMessageChecklist is not available in this grammY/Telegram Bot API version");
101881
- }
101882
- await _rawEditMessageChecklist({
101883
- chat_id: Number(args.chat_id),
101884
- message_id: Number(args.message_id),
101885
- ...args.title != null ? { title: args.title } : {},
101886
- ...args.tasks != null ? {
101887
- tasks: args.tasks.map((t) => ({
101888
- ...t.id != null ? { id: Number(t.id) } : {},
101889
- ...t.text != null ? { text: t.text } : {},
101890
- ...t.done != null ? { is_completed: t.done } : {}
101891
- }))
101892
- } : {}
101893
- });
102176
+ await _rawEditMessageChecklist(payload);
102177
+ }
102178
+ var checklistStore = createChecklistStore();
102179
+ function resolveBusinessConnectionId() {
102180
+ const v = process.env.SWITCHROOM_TELEGRAM_BUSINESS_CONNECTION_ID?.trim();
102181
+ return v ? v : undefined;
101894
102182
  }
101895
102183
  var chatLock = createChatLock();
101896
102184
  var lockedBot;
@@ -101911,7 +102199,7 @@ function assertSendable(f) {
101911
102199
  } catch {
101912
102200
  throw new Error(`refusing to send file \u2014 cannot resolve real path: ${f}`);
101913
102201
  }
101914
- const inbox = join68(stateReal, "inbox");
102202
+ const inbox = join69(stateReal, "inbox");
101915
102203
  if (real.startsWith(stateReal + sep4) && !real.startsWith(inbox + sep4)) {
101916
102204
  throw new Error(`refusing to send channel state: ${f}`);
101917
102205
  }
@@ -102036,7 +102324,7 @@ var HISTORY_ENABLED = HISTORY_ACCESS.historyEnabled !== false;
102036
102324
  if (isGatewayMain && HISTORY_ENABLED) {
102037
102325
  try {
102038
102326
  initHistory(STATE_DIR, HISTORY_ACCESS.historyRetentionDays ?? 30);
102039
- process.stderr.write(`telegram gateway: history capture enabled at ${join68(STATE_DIR, "history.db")}
102327
+ process.stderr.write(`telegram gateway: history capture enabled at ${join69(STATE_DIR, "history.db")}
102040
102328
  `);
102041
102329
  } catch (err) {
102042
102330
  process.stderr.write(`telegram gateway: history init failed (${err.message}) \u2014 capture disabled
@@ -102055,9 +102343,9 @@ if (isGatewayMain)
102055
102343
  let markerTurnKey = null;
102056
102344
  let markerAgeMs = null;
102057
102345
  try {
102058
- const markerPath = join68(STATE_DIR, TURN_ACTIVE_MARKER_FILE2);
102346
+ const markerPath = join69(STATE_DIR, TURN_ACTIVE_MARKER_FILE2);
102059
102347
  if (existsSync57(markerPath)) {
102060
- const st = statSync22(markerPath);
102348
+ const st = statSync23(markerPath);
102061
102349
  markerAgeMs = Date.now() - st.mtimeMs;
102062
102350
  try {
102063
102351
  const payload = JSON.parse(readFileSync60(markerPath, "utf8"));
@@ -102080,10 +102368,10 @@ if (isGatewayMain)
102080
102368
  process.stderr.write(`telegram gateway: turn-registry boot-reaper stamped ${reaped} orphaned turn(s)` + `${timeoutTurnKey ? ` (turnKey=${timeoutTurnKey} as 'timeout', markerAgeMs=${markerAgeMs})` : " as 'restart'"}
102081
102369
  `);
102082
102370
  } else {
102083
- process.stderr.write(`telegram gateway: turn-registry initialized at ${join68(agentDir, "telegram", "registry.db")}
102371
+ process.stderr.write(`telegram gateway: turn-registry initialized at ${join69(agentDir, "telegram", "registry.db")}
102084
102372
  `);
102085
102373
  }
102086
- const bridgeDeadMarker = consumeBridgeDeadEscalationMarker(join68(STATE_DIR, "bridge-dead-escalation.json"));
102374
+ const bridgeDeadMarker = consumeBridgeDeadEscalationMarker(join69(STATE_DIR, "bridge-dead-escalation.json"));
102087
102375
  if (bridgeDeadMarker != null) {
102088
102376
  bridgeDeadPriorStreak = bridgeDeadMarker.count ?? 1;
102089
102377
  process.stderr.write(`telegram gateway: boot: prior restart was a bridge-dead escalation (reason=${bridgeDeadMarker.reason}` + `, consecutive=${bridgeDeadPriorStreak}` + `${bridgeDeadMarker.crashTail ? `, crashTail=${bridgeDeadMarker.crashTail}` : ""})
@@ -102096,7 +102384,7 @@ if (isGatewayMain)
102096
102384
  const pending2 = findLatestTurnIfInterrupted(turnsDb);
102097
102385
  const selfAgent = process.env.SWITCHROOM_AGENT_NAME ?? "";
102098
102386
  if (pending2 != null && selfAgent) {
102099
- const bootResumeMarkerPath = process.env.SWITCHROOM_GATEWAY_CLEAN_SHUTDOWN_MARKER ?? join68(STATE_DIR, "clean-shutdown.json");
102387
+ const bootResumeMarkerPath = process.env.SWITCHROOM_GATEWAY_CLEAN_SHUTDOWN_MARKER ?? join69(STATE_DIR, "clean-shutdown.json");
102100
102388
  const bootResumeCleanMarker = readCleanShutdownMarker(bootResumeMarkerPath);
102101
102389
  const bootResumeForceAlways = process.env.SWITCHROOM_BOOT_RESUME_ALWAYS === "1";
102102
102390
  const bootResumeMode = parseBootResumeMode(process.env.SWITCHROOM_BOOT_RESUME);
@@ -102209,7 +102497,7 @@ if (isGatewayMain)
102209
102497
  `);
102210
102498
  }
102211
102499
  }
102212
- const pendingEnvPath = join68(agentDir, ".pending-turn.env");
102500
+ const pendingEnvPath = join69(agentDir, ".pending-turn.env");
102213
102501
  try {
102214
102502
  if (pending2 != null) {
102215
102503
  const lines = [
@@ -102337,7 +102625,7 @@ function checkApprovals() {
102337
102625
  return;
102338
102626
  }
102339
102627
  for (const senderId of files) {
102340
- const file = join68(APPROVED_DIR, senderId);
102628
+ const file = join69(APPROVED_DIR, senderId);
102341
102629
  bot.api.sendMessage(senderId, "Paired! Say hi to Claude.").then(() => rmSync8(file, { force: true }), (err) => {
102342
102630
  process.stderr.write(`telegram gateway: failed to send approval confirm: ${err}
102343
102631
  `);
@@ -102423,6 +102711,7 @@ async function deliverAnswer(args) {
102423
102711
  const result = await runBackstopDelivery(backstopDeliveryLedger, turnId, chunks, args.resume ? null : args.cardMessageId, {
102424
102712
  sendChunk,
102425
102713
  readBack,
102714
+ onAckClaim: args.onAckClaim,
102426
102715
  recordOutbound: HISTORY_ENABLED ? (messageIds, texts) => {
102427
102716
  try {
102428
102717
  recordOutbound({
@@ -102511,7 +102800,7 @@ function noteAgentOutputAt(key, ts) {
102511
102800
  lastAgentOutputAt.delete(oldest);
102512
102801
  }
102513
102802
  }
102514
- var OBLIGATION_STORE_PATH = join68(STATE_DIR, "obligations.json");
102803
+ var OBLIGATION_STORE_PATH = join69(STATE_DIR, "obligations.json");
102515
102804
  var obligationStoreFs = {
102516
102805
  readFileSync: (p) => readFileSync60(p, "utf8"),
102517
102806
  writeFileSync: (p, d) => writeFileSync50(p, d),
@@ -103280,6 +103569,7 @@ function emitTurnRecord(turn, endedAt) {
103280
103569
  toolCallCount: turn.toolCallCount ?? 0,
103281
103570
  turnId: turn.turnId,
103282
103571
  finalAnswerDelivered: turn.finalAnswerDelivered,
103572
+ replyCalled: turn.replyCalled,
103283
103573
  deliveryOutcome: turn.deliveryOutcome,
103284
103574
  landedUnconfirmed: turn.landedUnconfirmed
103285
103575
  }, endedAt)) + `
@@ -103288,7 +103578,7 @@ function emitTurnRecord(turn, endedAt) {
103288
103578
  maybeRotate(turnsPath, {
103289
103579
  statSize: (p) => {
103290
103580
  try {
103291
- return statSync22(p).size;
103581
+ return statSync23(p).size;
103292
103582
  } catch {
103293
103583
  return;
103294
103584
  }
@@ -104856,7 +105146,7 @@ var PIN_STATUS_WHILE_WORKING = (() => {
104856
105146
  })();
104857
105147
  var statusPinClaims = new Map;
104858
105148
  var statusPinRightsCache = new PinRightsCache2;
104859
- var STATUS_PIN_STORE_PATH = join68(STATE_DIR, "status-pins.json");
105149
+ var STATUS_PIN_STORE_PATH = join69(STATE_DIR, "status-pins.json");
104860
105150
  var statusPinStoreFs = {
104861
105151
  readFileSync: (p) => readFileSync60(p, "utf8"),
104862
105152
  writeFileSync: (p, d) => writeFileSync50(p, d),
@@ -104864,7 +105154,7 @@ var statusPinStoreFs = {
104864
105154
  existsSync: (p) => existsSync57(p)
104865
105155
  };
104866
105156
  var statusPinPersistEnabled = !STATIC && PIN_STATUS_WHILE_WORKING;
104867
- var ACTIVITY_CARD_STORE_PATH = join68(STATE_DIR, "activity-cards-pending.json");
105157
+ var ACTIVITY_CARD_STORE_PATH = join69(STATE_DIR, "activity-cards-pending.json");
104868
105158
  var activityCardStoreFs = {
104869
105159
  readFileSync: (p) => readFileSync60(p, "utf8"),
104870
105160
  writeFileSync: (p, d) => writeFileSync50(p, d),
@@ -104872,7 +105162,7 @@ var activityCardStoreFs = {
104872
105162
  existsSync: (p) => existsSync57(p)
104873
105163
  };
104874
105164
  var activityCardPersistEnabled = !STATIC;
104875
- var QUEUED_CARD_STORE_PATH = join68(STATE_DIR, "queued-cards-pending.json");
105165
+ var QUEUED_CARD_STORE_PATH = join69(STATE_DIR, "queued-cards-pending.json");
104876
105166
  var queuedCardStoreFs = {
104877
105167
  readFileSync: (p) => readFileSync60(p, "utf8"),
104878
105168
  writeFileSync: (p, d) => writeFileSync50(p, d),
@@ -105164,7 +105454,7 @@ async function unpinAllStatusPins() {
105164
105454
  }
105165
105455
  }
105166
105456
  var stalePinSweepEligible = false;
105167
- var STALE_PIN_SWEEP_STORE_PATH = join68(STATE_DIR, "stale-pin-sweep.json");
105457
+ var STALE_PIN_SWEEP_STORE_PATH = join69(STATE_DIR, "stale-pin-sweep.json");
105168
105458
  var stalePinSweeper = createGatewayStalePinSweeper({
105169
105459
  telegram: { handle: () => lockedBot, call: robustApiCall },
105170
105460
  claims: () => statusPinClaims.values(),
@@ -105205,12 +105495,12 @@ var getPinnedProgressCardMessageId = null;
105205
105495
  var completeProgressCardTurn = null;
105206
105496
  var subagentWatcher = null;
105207
105497
  var workerActivityFeed = null;
105208
- var SOCKET_PATH = process.env.SWITCHROOM_GATEWAY_SOCKET ?? join68(STATE_DIR, "gateway.sock");
105498
+ var SOCKET_PATH = process.env.SWITCHROOM_GATEWAY_SOCKET ?? join69(STATE_DIR, "gateway.sock");
105209
105499
  if (isGatewayMain)
105210
105500
  mkdirSync51(STATE_DIR, { recursive: true, mode: 448 });
105211
- var GATEWAY_PID_PATH = process.env.SWITCHROOM_GATEWAY_PID_FILE ?? join68(STATE_DIR, "gateway.pid.json");
105212
- var GATEWAY_SESSION_MARKER_PATH = process.env.SWITCHROOM_GATEWAY_SESSION_MARKER ?? join68(STATE_DIR, "gateway-session.json");
105213
- var GATEWAY_CLEAN_SHUTDOWN_MARKER_PATH = process.env.SWITCHROOM_GATEWAY_CLEAN_SHUTDOWN_MARKER ?? join68(STATE_DIR, "clean-shutdown.json");
105501
+ var GATEWAY_PID_PATH = process.env.SWITCHROOM_GATEWAY_PID_FILE ?? join69(STATE_DIR, "gateway.pid.json");
105502
+ var GATEWAY_SESSION_MARKER_PATH = process.env.SWITCHROOM_GATEWAY_SESSION_MARKER ?? join69(STATE_DIR, "gateway-session.json");
105503
+ var GATEWAY_CLEAN_SHUTDOWN_MARKER_PATH = process.env.SWITCHROOM_GATEWAY_CLEAN_SHUTDOWN_MARKER ?? join69(STATE_DIR, "clean-shutdown.json");
105214
105504
  var GATEWAY_STARTED_AT_MS = Date.now();
105215
105505
  var BOOT_CARD_ENABLED = process.env.SWITCHROOM_BOOT_CARD !== "false";
105216
105506
  var activeBootCard = null;
@@ -105239,7 +105529,7 @@ function ensureIssuesCard(chatId, threadId) {
105239
105529
  bot: botApi,
105240
105530
  log: (msg) => process.stderr.write(`telegram gateway: ${msg}
105241
105531
  `),
105242
- persistPath: join68(stateDir, "issues-card.json")
105532
+ persistPath: join69(stateDir, "issues-card.json")
105243
105533
  });
105244
105534
  activeIssuesWatcher = startIssuesWatcher({
105245
105535
  stateDir,
@@ -105417,7 +105707,11 @@ function runDeliveryConfirmSweep() {
105417
105707
  }
105418
105708
  var _deliveryConfirmSweep = isGatewayMain ? setInterval(runDeliveryConfirmSweep, DELIVERY_CONFIRM_SWEEP_MS) : undefined;
105419
105709
  _deliveryConfirmSweep?.unref?.();
105420
- startOutboxSweep({ isGatewayMain, stateDir: STATE_DIR, getBot: () => bot, getTurnsDb: () => turnsDb, dedupCheck: (c, t, x) => outboundDedup.check(c, t, x, Date.now()) != null, resolveReplyMarkup: makeOutboxListenMarkupResolver({ resolveVoiceOutPlan: (t) => resolveVoiceOutPlan(loadAccess().voice_out, t), cachePut: (token, payload) => voiceOnDemandCache.put(token, payload), eagerVoiceEnabled, enqueuePreSynth: (j) => voicePreSynthQueue.enqueue(j) }), log: (l) => process.stderr.write(l) });
105710
+ startOutboxSweep({ isGatewayMain, stateDir: STATE_DIR, getBot: () => bot, getTurnsDb: () => turnsDb, dedupCheck: (c, t, x) => outboundDedup.check(c, t, x, Date.now()) != null, recordOutbound: HISTORY_ENABLED ? (chatId, threadId, message_ids, texts) => {
105711
+ try {
105712
+ recordOutbound({ chat_id: chatId, thread_id: threadId, message_ids, texts });
105713
+ } catch {}
105714
+ } : undefined, resolveReplyMarkup: makeOutboxListenMarkupResolver({ resolveVoiceOutPlan: (t) => resolveVoiceOutPlan(loadAccess().voice_out, t), cachePut: (token, payload) => voiceOnDemandCache.put(token, payload), eagerVoiceEnabled, enqueuePreSynth: (j) => voicePreSynthQueue.enqueue(j) }), log: (l) => process.stderr.write(l) });
105421
105715
  if (isGatewayMain)
105422
105716
  startTimer2({
105423
105717
  editMessage: async (ctx) => {
@@ -105439,14 +105733,14 @@ if (isGatewayMain)
105439
105733
  var inboundSpool;
105440
105734
  if (isGatewayMain)
105441
105735
  inboundSpool = STATIC ? undefined : createInboundSpool({
105442
- path: join68(STATE_DIR, "inbound-spool.jsonl"),
105736
+ path: join69(STATE_DIR, "inbound-spool.jsonl"),
105443
105737
  fs: {
105444
105738
  appendFileSync: (p, d) => appendFileSync9(p, d),
105445
105739
  readFileSync: (p) => readFileSync60(p, "utf8"),
105446
105740
  writeFileSync: (p, d) => writeFileSync50(p, d),
105447
105741
  renameSync: (a, b) => renameSync27(a, b),
105448
105742
  existsSync: (p) => existsSync57(p),
105449
- statSizeSync: (p) => statSync22(p).size,
105743
+ statSizeSync: (p) => statSync23(p).size,
105450
105744
  fsyncFileSync: fsyncPathSync,
105451
105745
  fsyncDirSync: fsyncPathSync
105452
105746
  },
@@ -105509,7 +105803,7 @@ async function maybeRedeliverUndeliveredAnswer() {
105509
105803
  let transcriptText;
105510
105804
  try {
105511
105805
  const projectsDir = getProjectsDirForCwd();
105512
- const path3 = join68(projectsDir, `${sessionId}.jsonl`);
105806
+ const path3 = join69(projectsDir, `${sessionId}.jsonl`);
105513
105807
  if (!existsSync57(path3)) {
105514
105808
  process.stderr.write(`telegram gateway: crash-redelivery \u2014 transcript not found for turnKey=${turn.turn_key} session=${sessionId} (${path3}); skipping
105515
105809
  `);
@@ -105674,8 +105968,8 @@ var bridgeDeadWatchdog = createBridgeDeadWatchdog({
105674
105968
  isSessionAlive: () => findAgentProcessInContainer2()?.comm === "claude",
105675
105969
  isShuttingDown: () => shuttingDown,
105676
105970
  escalate: (reason) => triggerSelfRestart(process.env.SWITCHROOM_AGENT_NAME ?? "", reason, 1500),
105677
- crashLogPath: join68(STATE_DIR, "bridge-crash.log"),
105678
- markerPath: join68(STATE_DIR, "bridge-dead-escalation.json"),
105971
+ crashLogPath: join69(STATE_DIR, "bridge-crash.log"),
105972
+ markerPath: join69(STATE_DIR, "bridge-dead-escalation.json"),
105679
105973
  log: (line) => process.stderr.write(`${line}
105680
105974
  `),
105681
105975
  priorStreak: bridgeDeadPriorStreak,
@@ -105781,8 +106075,8 @@ if (isGatewayMain)
105781
106075
  probeQuotaViaBroker: (t) => probeQuotaForBootCard(agentSlug, t),
105782
106076
  tmuxSupervisor: process.env.SWITCHROOM_TMUX_SUPERVISOR === "1",
105783
106077
  dockerMode: process.env.SWITCHROOM_RUNTIME === "docker",
105784
- configSnapshotPath: join68(resolvedAgentDirForCard, ".config-snapshot.json"),
105785
- bootCardStatePath: join68(resolvedAgentDirForCard, ".boot-card-msgid.json"),
106078
+ configSnapshotPath: join69(resolvedAgentDirForCard, ".config-snapshot.json"),
106079
+ bootCardStatePath: join69(resolvedAgentDirForCard, ".boot-card-msgid.json"),
105786
106080
  floodStatePath: FLOOD_STATE_PATH,
105787
106081
  ...updateOutcomeLine ? { updateOutcomeLine } : {}
105788
106082
  }, ackMsgId).then((handle) => {
@@ -106450,7 +106744,7 @@ if (isGatewayMain)
106450
106744
  const receiverUid = receiverUidRaw ? Number(receiverUidRaw) : NaN;
106451
106745
  if (Number.isInteger(receiverUid))
106452
106746
  allowedUids.push(receiverUid);
106453
- const socketPath = join68(STATE_DIR, "webhook.sock");
106747
+ const socketPath = join69(STATE_DIR, "webhook.sock");
106454
106748
  const webhookInject = (agentName3, inbound) => {
106455
106749
  const msg = inbound;
106456
106750
  const delivered = ipcServer.sendToAgent(agentName3, msg);
@@ -106600,17 +106894,24 @@ async function executeSendChecklist(args) {
106600
106894
  const protectContent = args.protect_content === true;
106601
106895
  assertAllowedChat(chat_id);
106602
106896
  const { title: redactedTitle, tasks: redactedTasks } = redactChecklistFields(title, tasks, (t) => redactOutboundText(t, "send_checklist"));
106603
- const sent = await rawSendChecklist({
106604
- chat_id,
106605
- title: redactedTitle,
106606
- tasks: redactedTasks,
106897
+ const literal = (loadAccess().parseMode ?? "html") === "text";
106898
+ const sendOpts = {
106607
106899
  ...threadId != null ? { message_thread_id: threadId } : {},
106608
- ...replyTo != null ? { reply_to_message_id: replyTo } : {},
106900
+ ...replyTo != null ? { reply_parameters: { message_id: replyTo } } : {},
106609
106901
  ...protectContent ? { protect_content: true } : {}
106610
- });
106611
- process.stderr.write(`telegram gateway: send_checklist: sent chatId=${chat_id} messageId=${sent.message_id} tasks=${tasks.length}
106902
+ };
106903
+ const result = await performSendChecklist({
106904
+ businessConnectionId: resolveBusinessConnectionId(),
106905
+ nativeAvailable: CHECKLIST_API_AVAILABLE,
106906
+ sendNative: rawSendChecklist,
106907
+ sendText: (text5) => robustApiCall(() => literal ? lockedBot.api.sendMessage(chat_id, text5, sendOpts) : lockedBot.api.sendRichMessage(chat_id, richMessage2(text5), sendOpts), { verb: "sendMessage", chat_id, threadId }),
106908
+ literalText: literal,
106909
+ log: (l) => process.stderr.write(`telegram gateway: ${l}`)
106910
+ }, { title: redactedTitle, tasks: redactedTasks, chatId: Number(chat_id), replyToMessageId: replyTo, protectContent });
106911
+ checklistStore.set(checklistStoreKey(chat_id, result.message_id), result.state);
106912
+ process.stderr.write(`telegram gateway: send_checklist: sent chatId=${chat_id} messageId=${result.message_id} tasks=${tasks.length} mode=${result.mode}
106612
106913
  `);
106613
- return { content: [{ type: "text", text: `checklist sent (id: ${sent.message_id})` }] };
106914
+ return { content: [{ type: "text", text: sendChecklistToolText(result) }] };
106614
106915
  }
106615
106916
  var linearAuthAlertLast = new Map;
106616
106917
  var LINEAR_AUTH_ALERT_COOLDOWN_MS = 21600000;
@@ -106662,10 +106963,26 @@ async function executeUpdateChecklist(args) {
106662
106963
  const tasks = args.tasks;
106663
106964
  assertAllowedChat(chat_id);
106664
106965
  const { title: redactedTitle, tasks: redactedTasks } = redactChecklistFields(title, tasks, (t) => redactOutboundText(t, "update_checklist"));
106665
- await rawEditMessageChecklist({ chat_id, message_id, title: redactedTitle, tasks: redactedTasks });
106666
- process.stderr.write(`telegram gateway: update_checklist: updated chatId=${chat_id} messageId=${message_id}
106966
+ const literal = (loadAccess().parseMode ?? "html") === "text";
106967
+ const key = checklistStoreKey(chat_id, message_id);
106968
+ const result = await performUpdateChecklist({
106969
+ state: checklistStore.get(key),
106970
+ businessConnectionId: resolveBusinessConnectionId(),
106971
+ nativeAvailable: CHECKLIST_API_AVAILABLE,
106972
+ editNative: rawEditMessageChecklist,
106973
+ editText: async (text5) => {
106974
+ await robustApiCall(() => lockedBot.api.editMessageText(chat_id, Number(message_id), literal ? text5 : richMessage2(text5)));
106975
+ },
106976
+ literalText: literal,
106977
+ log: (l) => process.stderr.write(`telegram gateway: ${l}`),
106978
+ chatId: Number(chat_id),
106979
+ messageId: Number(message_id)
106980
+ }, { title: redactedTitle, tasks: redactedTasks });
106981
+ if (result.ok)
106982
+ checklistStore.set(key, result.state);
106983
+ process.stderr.write(`telegram gateway: update_checklist: ${result.ok ? `updated mode=${result.mode}` : `failed reason=${result.reason}`} chatId=${chat_id} messageId=${message_id}
106667
106984
  `);
106668
- return { content: [{ type: "text", text: `checklist updated (id: ${message_id})` }] };
106985
+ return { content: [{ type: "text", text: updateChecklistToolText(result, Number(message_id)) }] };
106669
106986
  }
106670
106987
  function redactOutboundText(text5, site) {
106671
106988
  const masked = redact2(text5);
@@ -106678,9 +106995,9 @@ function redactOutboundText(text5, site) {
106678
106995
  var VOICE_OUT_DEFAULT_CHUNK_CHARS = 600;
106679
106996
  var VOICE_OUT_HARD_CHUNK_CAP = 4096;
106680
106997
  var voiceOnDemandCache = new VoiceOnDemandCache({
106681
- persistPath: join68(STATE_DIR, "voice-ondemand.json")
106998
+ persistPath: join69(STATE_DIR, "voice-ondemand.json")
106682
106999
  });
106683
- var VOICE_CACHE_DIR = join68(STATE_DIR, "voice-cache");
107000
+ var VOICE_CACHE_DIR = join69(STATE_DIR, "voice-cache");
106684
107001
  var voicePreSynthQueue = new PreSynthQueue({
106685
107002
  runJob: async (job) => {
106686
107003
  const sidecarToken = await materializeSidecarToken2();
@@ -107082,7 +107399,7 @@ async function executeSendGif(rawArgs) {
107082
107399
  };
107083
107400
  }
107084
107401
  async function publishToTelegraph(text5, shortName, authorName) {
107085
- const accountPath = join68(STATE_DIR, "telegraph-account.json");
107402
+ const accountPath = join69(STATE_DIR, "telegraph-account.json");
107086
107403
  let account = null;
107087
107404
  try {
107088
107405
  if (existsSync57(accountPath)) {
@@ -108637,7 +108954,7 @@ function restartMarkerPath() {
108637
108954
  const agentDir = resolveAgentDirFromEnv();
108638
108955
  if (!agentDir)
108639
108956
  return null;
108640
- return join68(agentDir, "restart-pending.json");
108957
+ return join69(agentDir, "restart-pending.json");
108641
108958
  }
108642
108959
  function writeRestartMarker(marker) {
108643
108960
  const p = restartMarkerPath();
@@ -108829,7 +109146,7 @@ function _resetDockerReachableCache() {
108829
109146
  }
108830
109147
  function spawnSwitchroomDetached(args, onFailure) {
108831
109148
  const fullArgs = SWITCHROOM_CONFIG ? ["--config", SWITCHROOM_CONFIG, ...args] : args;
108832
- const logPath = join68(STATE_DIR, "detached-spawn.log");
109149
+ const logPath = join69(STATE_DIR, "detached-spawn.log");
108833
109150
  let outFd = null;
108834
109151
  try {
108835
109152
  mkdirSync51(STATE_DIR, { recursive: true });
@@ -109122,7 +109439,7 @@ ${preBlock(formatSwitchroomOutput(detail))}`, { html: true });
109122
109439
  }
109123
109440
  function readRecentDenialsForAgent(agentName3, windowMs, limit) {
109124
109441
  try {
109125
- const auditPath = join68(homedir19(), ".switchroom", "vault-audit.log");
109442
+ const auditPath = join69(homedir20(), ".switchroom", "vault-audit.log");
109126
109443
  if (!existsSync57(auditPath))
109127
109444
  return [];
109128
109445
  const raw = readFileSync60(auditPath, "utf8");
@@ -109176,7 +109493,7 @@ async function buildAgentMetadata(agentName3) {
109176
109493
  try {
109177
109494
  const agentDir = resolveAgentDirFromEnv();
109178
109495
  if (agentDir) {
109179
- const raw = readFileSync60(join68(agentDir, ".claude", ".claude.json"), "utf8");
109496
+ const raw = readFileSync60(join69(agentDir, ".claude", ".claude.json"), "utf8");
109180
109497
  claudeJson = JSON.parse(raw);
109181
109498
  }
109182
109499
  } catch {}
@@ -109305,7 +109622,7 @@ function buildModelDeps(restartCtx) {
109305
109622
  try {
109306
109623
  const agentDir = resolveAgentDirFromEnv();
109307
109624
  if (agentDir) {
109308
- const local = await fetchQuota2({ claudeConfigDir: join68(agentDir, ".claude") });
109625
+ const local = await fetchQuota2({ claudeConfigDir: join69(agentDir, ".claude") });
109309
109626
  if (local.ok)
109310
109627
  return formatQuotaLine2(local.data);
109311
109628
  }
@@ -109552,10 +109869,10 @@ function effortMenuReplyMarkup(reply) {
109552
109869
  function flushAgentHandoff(agentDir) {
109553
109870
  let removed = 0;
109554
109871
  for (const fname of [".handoff.md", ".handoff-topic"]) {
109555
- const p = join68(agentDir, fname);
109872
+ const p = join69(agentDir, fname);
109556
109873
  try {
109557
109874
  if (existsSync57(p)) {
109558
- unlinkSync30(p);
109875
+ unlinkSync31(p);
109559
109876
  removed++;
109560
109877
  }
109561
109878
  } catch (err) {
@@ -109610,7 +109927,7 @@ async function handleNewCommand(ctx) {
109610
109927
  writeRestartMarker({ chat_id: chatId, thread_id: threadId ?? null, ack_message_id: ackId, ts: Date.now() });
109611
109928
  if (agentDir != null) {
109612
109929
  try {
109613
- writeFileSync50(join68(agentDir, ".force-fresh-session"), `${kind} at ${new Date().toISOString()}
109930
+ writeFileSync50(join69(agentDir, ".force-fresh-session"), `${kind} at ${new Date().toISOString()}
109614
109931
  `, "utf8");
109615
109932
  } catch (err) {
109616
109933
  process.stderr.write(`telegram gateway: failed to write force-fresh marker: ${err}
@@ -109727,7 +110044,7 @@ var lockoutOps = {
109727
110044
  writeFileSync: (p, data, opts) => writeFileSync50(p, data, opts),
109728
110045
  existsSync: (p) => existsSync57(p),
109729
110046
  mkdirSync: (p, opts) => mkdirSync51(p, opts),
109730
- joinPath: (...parts) => join68(...parts)
110047
+ joinPath: (...parts) => join69(...parts)
109731
110048
  };
109732
110049
  var FLEET_FALLBACK_DEDUP_MS = 30000;
109733
110050
  function isAuthBrokerSocketReachable() {
@@ -109987,7 +110304,7 @@ async function runCreditWatch() {
109987
110304
  if (!agentDir)
109988
110305
  return;
109989
110306
  const agentName3 = getMyAgentName();
109990
- const claudeConfigDir = join68(agentDir, ".claude");
110307
+ const claudeConfigDir = join69(agentDir, ".claude");
109991
110308
  const stateDir = STATE_DIR;
109992
110309
  const reason = readClaudeJsonOverage(claudeConfigDir);
109993
110310
  const prev = loadCreditState(stateDir);
@@ -111743,7 +112060,7 @@ Send \`/auth ${parsed.provider} cancel\` to abort.`, { html: true });
111743
112060
  await switchroomReply(ctx, "**/usage:** cannot resolve agent dir.", { html: true });
111744
112061
  return;
111745
112062
  }
111746
- const result = await fetchQuota2({ claudeConfigDir: join68(agentDir, ".claude") });
112063
+ const result = await fetchQuota2({ claudeConfigDir: join69(agentDir, ".claude") });
111747
112064
  if (!result.ok) {
111748
112065
  await switchroomReply(ctx, `**/usage:** ${escapeHtmlForTg2(result.reason)}`, { html: true });
111749
112066
  return;
@@ -112999,7 +113316,7 @@ async function startGateway() {
112999
113316
  return;
113000
113317
  }
113001
113318
  })();
113002
- const resolvedAgentDirForBootCard = agentDir ?? join68(homedir19(), ".switchroom", "agents", agentSlug);
113319
+ const resolvedAgentDirForBootCard = agentDir ?? join69(homedir20(), ".switchroom", "agents", agentSlug);
113003
113320
  const handle = await startBootCard(chatId, threadId, botApiForCard, {
113004
113321
  agentName: agentDisplayName,
113005
113322
  agentSlug,
@@ -113013,8 +113330,8 @@ async function startGateway() {
113013
113330
  probeQuotaViaBroker: (t) => probeQuotaForBootCard(agentSlug, t),
113014
113331
  tmuxSupervisor: process.env.SWITCHROOM_TMUX_SUPERVISOR === "1",
113015
113332
  dockerMode: process.env.SWITCHROOM_RUNTIME === "docker",
113016
- configSnapshotPath: join68(resolvedAgentDirForBootCard, ".config-snapshot.json"),
113017
- bootCardStatePath: join68(resolvedAgentDirForBootCard, ".boot-card-msgid.json"),
113333
+ configSnapshotPath: join69(resolvedAgentDirForBootCard, ".config-snapshot.json"),
113334
+ bootCardStatePath: join69(resolvedAgentDirForBootCard, ".boot-card-msgid.json"),
113018
113335
  floodStatePath: FLOOD_STATE_PATH,
113019
113336
  ...updateOutcomeLine ? { updateOutcomeLine } : {}
113020
113337
  }, ackMsgId);
@@ -113047,7 +113364,7 @@ async function startGateway() {
113047
113364
  if (smAgentDir) {
113048
113365
  const resolutionTimeoutMs = resolveSessionModelResolutionTimeoutMs(process.env.SWITCHROOM_SESSION_MODEL_RESOLUTION_TIMEOUT_MS);
113049
113366
  const resolved = await waitForSessionModelResolution({
113050
- barrierExists: () => existsSync57(join68(smAgentDir, ".session-model-resolved")),
113367
+ barrierExists: () => existsSync57(join69(smAgentDir, ".session-model-resolved")),
113051
113368
  timeoutMs: resolutionTimeoutMs
113052
113369
  });
113053
113370
  if (!resolved) {
@@ -113055,7 +113372,7 @@ async function startGateway() {
113055
113372
  process.stderr.write(`telegram gateway: gw /model relaunch UNRESOLVED agent=${getMyAgentName()} target=${target} (barrier timeout after ${resolutionTimeoutMs}ms)
113056
113373
  `);
113057
113374
  } else {
113058
- const activePath = join68(smAgentDir, ".active-session-model");
113375
+ const activePath = join69(smAgentDir, ".active-session-model");
113059
113376
  if (existsSync57(activePath)) {
113060
113377
  try {
113061
113378
  const launched = readFileSync60(activePath, "utf8").trim();
@@ -113091,12 +113408,12 @@ async function startGateway() {
113091
113408
  deliverModelSwitchBootNotice({
113092
113409
  ...modelBootCardDeps,
113093
113410
  confirmation,
113094
- hasSessionModelAlert: existsSync57(join68(smAgentDir, ".session-model-alert"))
113411
+ hasSessionModelAlert: existsSync57(join69(smAgentDir, ".session-model-alert"))
113095
113412
  });
113096
113413
  }
113097
113414
  } catch {}
113098
113415
  }
113099
- const activeEffortPath = join68(smAgentDir, ".active-session-effort");
113416
+ const activeEffortPath = join69(smAgentDir, ".active-session-effort");
113100
113417
  if (existsSync57(activeEffortPath)) {
113101
113418
  try {
113102
113419
  const launchedEffort = readFileSync60(activeEffortPath, "utf8").trim();
@@ -113104,7 +113421,7 @@ async function startGateway() {
113104
113421
  sessionEffortOverride = launchedEffort.length > 0 && launchedEffort !== configuredEffort ? launchedEffort : null;
113105
113422
  } catch {}
113106
113423
  }
113107
- const alertPath = join68(smAgentDir, ".session-model-alert");
113424
+ const alertPath = join69(smAgentDir, ".session-model-alert");
113108
113425
  if (existsSync57(alertPath)) {
113109
113426
  let alertText = null;
113110
113427
  try {
@@ -113113,7 +113430,7 @@ async function startGateway() {
113113
113430
  alertText = null;
113114
113431
  }
113115
113432
  try {
113116
- unlinkSync30(alertPath);
113433
+ unlinkSync31(alertPath);
113117
113434
  } catch {}
113118
113435
  if (alertText && alertText.length > 0) {
113119
113436
  const operators = loadAccess().allowFrom;