switchroom 0.18.13 → 0.18.15

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 (47) hide show
  1. package/dist/agent-scheduler/index.js +49 -9
  2. package/dist/auth-broker/index.js +152 -46
  3. package/dist/cli/autoaccept-poll.js +23 -0
  4. package/dist/cli/drive-write-pretool.mjs +24 -1
  5. package/dist/cli/foreground-hog-pretool.mjs +264 -0
  6. package/dist/cli/notion-write-pretool.mjs +0 -1
  7. package/dist/cli/switchroom.js +1185 -1072
  8. package/dist/host-control/main.js +53 -52
  9. package/dist/vault/approvals/kernel-server.js +16 -13
  10. package/dist/vault/broker/server.js +672 -669
  11. package/package.json +1 -1
  12. package/profiles/coding/CLAUDE.md.hbs +2 -0
  13. package/profiles/default/CLAUDE.md.hbs +2 -0
  14. package/skills/switchroom-architecture/telegram.md +0 -1
  15. package/telegram-plugin/auth-snapshot-format.ts +37 -5
  16. package/telegram-plugin/auto-fallback-fleet.ts +29 -1
  17. package/telegram-plugin/bridge/bridge.ts +2 -0
  18. package/telegram-plugin/dist/bridge/bridge.js +23 -0
  19. package/telegram-plugin/dist/gateway/gateway.js +765 -67
  20. package/telegram-plugin/dist/server.js +24 -1
  21. package/telegram-plugin/gateway/auth-broker-client.ts +1 -0
  22. package/telegram-plugin/gateway/auth-command.ts +14 -0
  23. package/telegram-plugin/gateway/forward-origin.ts +235 -0
  24. package/telegram-plugin/gateway/gateway.ts +270 -10
  25. package/telegram-plugin/gateway/throttle-tier-wiring.ts +268 -0
  26. package/telegram-plugin/history.ts +55 -6
  27. package/telegram-plugin/model-unavailable.ts +234 -2
  28. package/telegram-plugin/render/rich-render.ts +40 -32
  29. package/telegram-plugin/runtime-metrics.ts +31 -0
  30. package/telegram-plugin/session-tail.ts +14 -2
  31. package/telegram-plugin/stream-controller.ts +3 -2
  32. package/telegram-plugin/tests/auto-fallback-fleet.test.ts +72 -0
  33. package/telegram-plugin/tests/forward-origin.test.ts +309 -0
  34. package/telegram-plugin/tests/history.test.ts +157 -0
  35. package/telegram-plugin/tests/model-unavailable.test.ts +187 -0
  36. package/telegram-plugin/tests/operator-events-session-tail.test.ts +55 -0
  37. package/telegram-plugin/tests/render/render-outbound-chunks.test.ts +6 -4
  38. package/telegram-plugin/tests/render/rich-render.test.ts +41 -22
  39. package/telegram-plugin/tests/runtime-metrics.test.ts +24 -0
  40. package/telegram-plugin/tests/single-mode-stream-reply.test.ts +5 -3
  41. package/telegram-plugin/tests/status-accent.test.ts +5 -3
  42. package/telegram-plugin/tests/stream-controller-chunk-cap.test.ts +20 -20
  43. package/telegram-plugin/tests/stream-reply-handler.test.ts +5 -2
  44. package/telegram-plugin/tests/throttle-tier-wiring.test.ts +290 -0
  45. package/telegram-plugin/tests/throttle-tier.test.ts +454 -0
  46. package/telegram-plugin/throttle-tier.ts +323 -0
  47. package/telegram-plugin/uat/scenarios/jtbd-rich-formatting-render-dm.test.ts +8 -7
@@ -18824,7 +18824,6 @@ var TelegramChannelSchema = exports_external.object({
18824
18824
  enabled: exports_external.boolean().default(true).describe("Master switch for the per-agent Telegram gateway sidecar. " + "When false, start.sh skips the gateway supervise loop and the " + "agent boots without bot-token requirements (smoke-test + " + "offline-dev use case)."),
18825
18825
  plugin: exports_external.enum(["switchroom", "official"]).optional().describe("Which Telegram MCP plugin to load. Default is 'switchroom' — the " + "enhanced fork with streaming edits, reactions, history, and " + "access control. Set to 'official' for the upstream marketplace " + "plugin (basic send/receive only)."),
18826
18826
  format: exports_external.enum(["html", "markdownv2", "text"]).optional().describe("Default reply format passed to the plugin"),
18827
- rate_limit_ms: exports_external.number().optional().describe("Minimum delay between outgoing messages in ms"),
18828
18827
  stream_mode: exports_external.enum(["pty", "checklist"]).optional().describe("How live progress is streamed to Telegram during a turn. " + "'pty' (default) surfaces text snapshots of Claude Code's TUI — " + "compatible but can flicker as Ink re-renders. 'checklist' drives " + "a structured progress card from session-tail events — stable " + "order, per-tool status emojis, fires only on semantic transitions."),
18829
18828
  stream_throttle_ms: exports_external.number().int().nonnegative().optional().describe("Throttle window in ms between successive in-place stream edits " + "during a turn. Lower = more responsive stream, higher = fewer API " + "calls. Floored at 250 by draft-stream itself. Default 400 ms for DMs " + "and 1000 ms for groups/forums (respects Telegram's ~1 edit/sec/message " + "practical ceiling). Override per-agent if a particular agent needs " + "snappier or quieter streaming."),
18830
18829
  clear_status_on_completion: exports_external.boolean().optional().describe("When true, the live activity/status feed (the in-place 'what it's " + "doing' message — Reading X, Searching the web for Y, …) is DELETED " + "when the turn's final answer lands, so only the reply remains. " + "Default false: the status message is left in the chat as a record " + "(its last step marked done) — no post-then-delete. Per-agent " + "override; cascades defaults → profile → agent (per-key)."),
@@ -20497,13 +20496,62 @@ async function waitForConfigRecovery(opts) {
20497
20496
  return config;
20498
20497
  }
20499
20498
 
20500
- // src/agents/compose.ts
20501
- import { createHash } from "node:crypto";
20502
-
20503
20499
  // src/agents/scaffold.ts
20504
20500
  import { join as join5, resolve as resolve5 } from "node:path";
20505
20501
  init_atomic();
20506
20502
 
20503
+ // src/agents/agent-uid.ts
20504
+ import { createHash } from "node:crypto";
20505
+
20506
+ // src/broker-common/peercred-path.ts
20507
+ function matchSocketName(socketPath, patterns, maxNameLen) {
20508
+ if (typeof socketPath !== "string" || socketPath.length === 0)
20509
+ return null;
20510
+ let name = null;
20511
+ for (const re of patterns) {
20512
+ const m = socketPath.match(re);
20513
+ if (m && typeof m[1] === "string") {
20514
+ name = m[1];
20515
+ break;
20516
+ }
20517
+ }
20518
+ if (name === null || name.length === 0)
20519
+ return null;
20520
+ if (maxNameLen !== undefined && name.length > maxNameLen)
20521
+ return null;
20522
+ return name;
20523
+ }
20524
+ function parseSocketIdentity(socketPath, spec) {
20525
+ const name = matchSocketName(socketPath, spec.patterns, spec.maxNameLen);
20526
+ if (name === null)
20527
+ return null;
20528
+ const operatorName = spec.operatorName ?? "operator";
20529
+ if (name === operatorName)
20530
+ return { kind: "operator" };
20531
+ if (spec.reservedNames.has(name))
20532
+ return null;
20533
+ return { kind: "agent", name };
20534
+ }
20535
+
20536
+ // src/vault/broker/peercred.ts
20537
+ var RESERVED_AGENT_NAMES = new Set(["operator", "hostd"]);
20538
+ function isReservedAgentName(name) {
20539
+ return RESERVED_AGENT_NAMES.has(name);
20540
+ }
20541
+
20542
+ // src/agents/agent-uid.ts
20543
+ var AGENT_UID_MIN = 10001;
20544
+ var AGENT_UID_MAX = 10999;
20545
+ function allocateAgentUid(name) {
20546
+ if (isReservedAgentName(name)) {
20547
+ throw new Error(`agent name '${name}' is reserved by switchroom for another identity kind ` + `(see vault/broker/peercred.ts:RESERVED_AGENT_NAMES). Pick a different name.`);
20548
+ }
20549
+ const hash = createHash("sha256").update(name).digest();
20550
+ const u32 = hash.readUInt32BE(0);
20551
+ const range = AGENT_UID_MAX - AGENT_UID_MIN + 1;
20552
+ return AGENT_UID_MIN + u32 % range;
20553
+ }
20554
+
20507
20555
  // src/config/timezone.ts
20508
20556
  var CONTAINER_DEFAULT_UTC_ZONES = new Set([
20509
20557
  "UTC",
@@ -20649,42 +20697,6 @@ import * as fs from "node:fs";
20649
20697
  import { homedir as homedir3 } from "node:os";
20650
20698
  import { join as join4 } from "node:path";
20651
20699
 
20652
- // src/broker-common/peercred-path.ts
20653
- function matchSocketName(socketPath, patterns, maxNameLen) {
20654
- if (typeof socketPath !== "string" || socketPath.length === 0)
20655
- return null;
20656
- let name = null;
20657
- for (const re of patterns) {
20658
- const m = socketPath.match(re);
20659
- if (m && typeof m[1] === "string") {
20660
- name = m[1];
20661
- break;
20662
- }
20663
- }
20664
- if (name === null || name.length === 0)
20665
- return null;
20666
- if (maxNameLen !== undefined && name.length > maxNameLen)
20667
- return null;
20668
- return name;
20669
- }
20670
- function parseSocketIdentity(socketPath, spec) {
20671
- const name = matchSocketName(socketPath, spec.patterns, spec.maxNameLen);
20672
- if (name === null)
20673
- return null;
20674
- const operatorName = spec.operatorName ?? "operator";
20675
- if (name === operatorName)
20676
- return { kind: "operator" };
20677
- if (spec.reservedNames.has(name))
20678
- return null;
20679
- return { kind: "agent", name };
20680
- }
20681
-
20682
- // src/vault/broker/peercred.ts
20683
- var RESERVED_AGENT_NAMES = new Set(["operator", "hostd"]);
20684
- function isReservedAgentName(name) {
20685
- return RESERVED_AGENT_NAMES.has(name);
20686
- }
20687
-
20688
20700
  // src/vault/broker/protocol.ts
20689
20701
  var MAX_FRAME_BYTES = 64 * 1024;
20690
20702
  var AgentNameSchema = exports_external.string().min(1).max(64, "agent name max 64 chars").regex(/^[a-zA-Z0-9][a-zA-Z0-9_-]*$/, "agent name must be kebab-case ASCII (alnum + _- only, first char alnum)").refine((s) => !isReservedAgentName(s), {
@@ -21132,17 +21144,6 @@ var DOCKER_TELEGRAM_PLUGIN_PATH = "/opt/switchroom/telegram-plugin";
21132
21144
  var DOCKER_HOOKS_PATH = `${DOCKER_TELEGRAM_PLUGIN_PATH}/hooks`;
21133
21145
 
21134
21146
  // src/agents/compose.ts
21135
- var AGENT_UID_MIN = 10001;
21136
- var AGENT_UID_MAX = 10999;
21137
- function allocateAgentUid(name) {
21138
- if (isReservedAgentName(name)) {
21139
- throw new Error(`agent name '${name}' is reserved by switchroom for another identity kind ` + `(see vault/broker/peercred.ts:RESERVED_AGENT_NAMES). Pick a different name.`);
21140
- }
21141
- const hash = createHash("sha256").update(name).digest();
21142
- const u32 = hash.readUInt32BE(0);
21143
- const range = AGENT_UID_MAX - AGENT_UID_MIN + 1;
21144
- return AGENT_UID_MIN + u32 % range;
21145
- }
21146
21147
  var BIND_MOUNT_EXACT_SOURCE_DENY = new Set(["/var/run/docker.sock"]);
21147
21148
 
21148
21149
  // src/host-control/server.ts
@@ -26588,7 +26589,7 @@ import { existsSync as existsSync9, readFileSync as readFileSync7 } from "node:f
26588
26589
  import { dirname as dirname4, join as join7 } from "node:path";
26589
26590
 
26590
26591
  // src/build-info.ts
26591
- var VERSION = "0.18.13";
26592
+ var VERSION = "0.18.15";
26592
26593
 
26593
26594
  // src/cli/resolve-version.ts
26594
26595
  function readPackageVersion() {
@@ -4244,7 +4244,6 @@ var init_schema = __esm(() => {
4244
4244
  enabled: exports_external.boolean().default(true).describe("Master switch for the per-agent Telegram gateway sidecar. " + "When false, start.sh skips the gateway supervise loop and the " + "agent boots without bot-token requirements (smoke-test + " + "offline-dev use case)."),
4245
4245
  plugin: exports_external.enum(["switchroom", "official"]).optional().describe("Which Telegram MCP plugin to load. Default is 'switchroom' — the " + "enhanced fork with streaming edits, reactions, history, and " + "access control. Set to 'official' for the upstream marketplace " + "plugin (basic send/receive only)."),
4246
4246
  format: exports_external.enum(["html", "markdownv2", "text"]).optional().describe("Default reply format passed to the plugin"),
4247
- rate_limit_ms: exports_external.number().optional().describe("Minimum delay between outgoing messages in ms"),
4248
4247
  stream_mode: exports_external.enum(["pty", "checklist"]).optional().describe("How live progress is streamed to Telegram during a turn. " + "'pty' (default) surfaces text snapshots of Claude Code's TUI — " + "compatible but can flicker as Ink re-renders. 'checklist' drives " + "a structured progress card from session-tail events — stable " + "order, per-tool status emojis, fires only on semantic transitions."),
4249
4248
  stream_throttle_ms: exports_external.number().int().nonnegative().optional().describe("Throttle window in ms between successive in-place stream edits " + "during a turn. Lower = more responsive stream, higher = fewer API " + "calls. Floored at 250 by draft-stream itself. Default 400 ms for DMs " + "and 1000 ms for groups/forums (respects Telegram's ~1 edit/sec/message " + "practical ceiling). Override per-agent if a particular agent needs " + "snappier or quieter streaming."),
4250
4249
  clear_status_on_completion: exports_external.boolean().optional().describe("When true, the live activity/status feed (the in-place 'what it's " + "doing' message — Reading X, Searching the web for Y, …) is DELETED " + "when the turn's final answer lands, so only the reply remains. " + "Default false: the status message is left in the chat as a record " + "(its last step marked done) — no post-then-delete. Per-agent " + "override; cascades defaults → profile → agent (per-key)."),
@@ -18894,12 +18893,27 @@ function getNonce(db, request_id) {
18894
18893
  }
18895
18894
 
18896
18895
  // src/agents/compose.ts
18897
- import { createHash } from "node:crypto";
18898
18896
  init_schema();
18899
18897
 
18900
18898
  // src/agents/scaffold.ts
18901
18899
  import { join as join4, resolve as resolve5 } from "node:path";
18902
18900
  init_atomic();
18901
+
18902
+ // src/agents/agent-uid.ts
18903
+ import { createHash } from "node:crypto";
18904
+ var AGENT_UID_MIN = 10001;
18905
+ var AGENT_UID_MAX = 10999;
18906
+ function allocateAgentUid(name) {
18907
+ if (isReservedAgentName(name)) {
18908
+ throw new Error(`agent name '${name}' is reserved by switchroom for another identity kind ` + `(see vault/broker/peercred.ts:RESERVED_AGENT_NAMES). Pick a different name.`);
18909
+ }
18910
+ const hash = createHash("sha256").update(name).digest();
18911
+ const u32 = hash.readUInt32BE(0);
18912
+ const range = AGENT_UID_MAX - AGENT_UID_MIN + 1;
18913
+ return AGENT_UID_MIN + u32 % range;
18914
+ }
18915
+
18916
+ // src/agents/scaffold.ts
18903
18917
  init_schema();
18904
18918
 
18905
18919
  // src/config/users.ts
@@ -19101,17 +19115,6 @@ init_merge();
19101
19115
  init_paths();
19102
19116
 
19103
19117
  // src/agents/compose.ts
19104
- var AGENT_UID_MIN = 10001;
19105
- var AGENT_UID_MAX = 10999;
19106
- function allocateAgentUid(name) {
19107
- if (isReservedAgentName(name)) {
19108
- throw new Error(`agent name '${name}' is reserved by switchroom for another identity kind ` + `(see vault/broker/peercred.ts:RESERVED_AGENT_NAMES). Pick a different name.`);
19109
- }
19110
- const hash = createHash("sha256").update(name).digest();
19111
- const u32 = hash.readUInt32BE(0);
19112
- const range = AGENT_UID_MAX - AGENT_UID_MIN + 1;
19113
- return AGENT_UID_MIN + u32 % range;
19114
- }
19115
19118
  var BIND_MOUNT_EXACT_SOURCE_DENY = new Set(["/var/run/docker.sock"]);
19116
19119
 
19117
19120
  // src/vault/approvals/acl.ts