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.
- package/dist/agent-scheduler/index.js +49 -9
- package/dist/auth-broker/index.js +152 -46
- package/dist/cli/autoaccept-poll.js +23 -0
- package/dist/cli/drive-write-pretool.mjs +24 -1
- package/dist/cli/foreground-hog-pretool.mjs +264 -0
- package/dist/cli/notion-write-pretool.mjs +0 -1
- package/dist/cli/switchroom.js +1185 -1072
- package/dist/host-control/main.js +53 -52
- package/dist/vault/approvals/kernel-server.js +16 -13
- package/dist/vault/broker/server.js +672 -669
- package/package.json +1 -1
- package/profiles/coding/CLAUDE.md.hbs +2 -0
- package/profiles/default/CLAUDE.md.hbs +2 -0
- package/skills/switchroom-architecture/telegram.md +0 -1
- package/telegram-plugin/auth-snapshot-format.ts +37 -5
- package/telegram-plugin/auto-fallback-fleet.ts +29 -1
- package/telegram-plugin/bridge/bridge.ts +2 -0
- package/telegram-plugin/dist/bridge/bridge.js +23 -0
- package/telegram-plugin/dist/gateway/gateway.js +765 -67
- package/telegram-plugin/dist/server.js +24 -1
- package/telegram-plugin/gateway/auth-broker-client.ts +1 -0
- package/telegram-plugin/gateway/auth-command.ts +14 -0
- package/telegram-plugin/gateway/forward-origin.ts +235 -0
- package/telegram-plugin/gateway/gateway.ts +270 -10
- package/telegram-plugin/gateway/throttle-tier-wiring.ts +268 -0
- package/telegram-plugin/history.ts +55 -6
- package/telegram-plugin/model-unavailable.ts +234 -2
- package/telegram-plugin/render/rich-render.ts +40 -32
- package/telegram-plugin/runtime-metrics.ts +31 -0
- package/telegram-plugin/session-tail.ts +14 -2
- package/telegram-plugin/stream-controller.ts +3 -2
- package/telegram-plugin/tests/auto-fallback-fleet.test.ts +72 -0
- package/telegram-plugin/tests/forward-origin.test.ts +309 -0
- package/telegram-plugin/tests/history.test.ts +157 -0
- package/telegram-plugin/tests/model-unavailable.test.ts +187 -0
- package/telegram-plugin/tests/operator-events-session-tail.test.ts +55 -0
- package/telegram-plugin/tests/render/render-outbound-chunks.test.ts +6 -4
- package/telegram-plugin/tests/render/rich-render.test.ts +41 -22
- package/telegram-plugin/tests/runtime-metrics.test.ts +24 -0
- package/telegram-plugin/tests/single-mode-stream-reply.test.ts +5 -3
- package/telegram-plugin/tests/status-accent.test.ts +5 -3
- package/telegram-plugin/tests/stream-controller-chunk-cap.test.ts +20 -20
- package/telegram-plugin/tests/stream-reply-handler.test.ts +5 -2
- package/telegram-plugin/tests/throttle-tier-wiring.test.ts +290 -0
- package/telegram-plugin/tests/throttle-tier.test.ts +454 -0
- package/telegram-plugin/throttle-tier.ts +323 -0
- 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.
|
|
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
|