switchroom 0.18.12 → 0.18.14
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 +57 -9
- package/dist/auth-broker/index.js +174 -72
- 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/ms-365-write-pretool.mjs +31 -8
- package/dist/cli/notion-write-pretool.mjs +9 -2
- package/dist/cli/skill-validate-pretool.mjs +144 -2847
- package/dist/cli/switchroom.js +986 -3131
- package/dist/host-control/main.js +216 -2863
- package/dist/vault/approvals/kernel-server.js +67 -1
- package/dist/vault/broker/server.js +98 -45
- 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 +51 -3
- package/telegram-plugin/dist/gateway/gateway.js +1251 -2368
- package/telegram-plugin/dist/server.js +67 -3
- package/telegram-plugin/format.ts +19 -0
- package/telegram-plugin/gateway/approval-hold.ts +21 -2
- package/telegram-plugin/gateway/auth-broker-client.ts +1 -0
- package/telegram-plugin/gateway/auth-command.ts +14 -0
- package/telegram-plugin/gateway/callback-query-handlers.ts +12 -0
- package/telegram-plugin/gateway/forward-origin.ts +235 -0
- package/telegram-plugin/gateway/gateway.ts +445 -83
- package/telegram-plugin/gateway/throttle-tier-wiring.ts +268 -0
- package/telegram-plugin/history.ts +106 -6
- package/telegram-plugin/inline-keyboard-callbacks.ts +94 -0
- package/telegram-plugin/model-unavailable.ts +61 -13
- package/telegram-plugin/outbound-field-redact.ts +69 -0
- package/telegram-plugin/render/render.ts +32 -14
- package/telegram-plugin/render/rich-render.ts +40 -32
- package/telegram-plugin/scoped-approval.ts +11 -2
- package/telegram-plugin/secret-detect/chunker.ts +18 -4
- package/telegram-plugin/secret-detect/index.ts +12 -56
- package/telegram-plugin/send-gate-degraded.test.ts +131 -0
- package/telegram-plugin/send-gate.test.ts +25 -6
- package/telegram-plugin/send-gate.ts +82 -8
- package/telegram-plugin/session-tail.ts +82 -7
- package/telegram-plugin/stream-controller.ts +3 -2
- package/telegram-plugin/subagent-watcher.ts +71 -16
- package/telegram-plugin/tests/approval-hold-outcome.test.ts +36 -5
- package/telegram-plugin/tests/auto-fallback-fleet.test.ts +72 -0
- package/telegram-plugin/tests/callback-query-handlers.test.ts +65 -0
- package/telegram-plugin/tests/forward-origin.test.ts +309 -0
- package/telegram-plugin/tests/gateway-outbound-redact.test.ts +57 -0
- package/telegram-plugin/tests/history.test.ts +272 -0
- package/telegram-plugin/tests/inbound-message-types.test.ts +5 -1
- package/telegram-plugin/tests/inline-keyboard-callbacks.test.ts +164 -0
- package/telegram-plugin/tests/operator-events-session-tail.test.ts +74 -0
- package/telegram-plugin/tests/outbound-field-redact.test.ts +107 -0
- package/telegram-plugin/tests/reaction-gate-routing.test.ts +173 -0
- package/telegram-plugin/tests/render/render-outbound-chunks.test.ts +6 -4
- package/telegram-plugin/tests/render/render.test.ts +88 -0
- package/telegram-plugin/tests/render/rich-render.test.ts +41 -22
- package/telegram-plugin/tests/scoped-approval.test.ts +27 -0
- package/telegram-plugin/tests/secret-detect-chunk-overlap.test.ts +65 -0
- package/telegram-plugin/tests/secret-detect-oauth-code.test.ts +5 -4
- package/telegram-plugin/tests/session-tail-sidecar-reap.test.ts +268 -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/subagent-watcher-fd-leak.test.ts +275 -0
- package/telegram-plugin/tests/throttle-tier-wiring.test.ts +290 -0
- package/telegram-plugin/tests/throttle-tier.test.ts +278 -0
- package/telegram-plugin/tests/worktree-watch-cwds.test.ts +215 -1
- package/telegram-plugin/throttle-tier.ts +226 -0
- package/telegram-plugin/uat/scenarios/jtbd-rich-formatting-render-dm.test.ts +8 -7
- package/telegram-plugin/worktree-watch-cwds.ts +194 -5
- package/telegram-plugin/secret-detect/secretlint-source.ts +0 -95
- package/telegram-plugin/tests/secret-detect-secretlint.test.ts +0 -105
|
@@ -23035,6 +23035,33 @@ function getNestedObj(obj, key) {
|
|
|
23035
23035
|
var DEFAULT_OPERATOR_EVENT_COOLDOWN_MS = 5 * 60000;
|
|
23036
23036
|
var cooldownMap = new Map;
|
|
23037
23037
|
|
|
23038
|
+
// text-voice-scrub.ts
|
|
23039
|
+
var NULL = "\x00";
|
|
23040
|
+
var FENCE_PH = `${NULL}VS_FENCE`;
|
|
23041
|
+
var INLINE_PH = `${NULL}VS_INLINE`;
|
|
23042
|
+
var HTML_CODE_PH = `${NULL}VS_HTMLCODE`;
|
|
23043
|
+
var HTML_PRE_PH = `${NULL}VS_HTMLPRE`;
|
|
23044
|
+
var URL_PH = `${NULL}VS_URL`;
|
|
23045
|
+
|
|
23046
|
+
// model-unavailable.ts
|
|
23047
|
+
var transientUpstreamSignals = [
|
|
23048
|
+
"not your usage limit",
|
|
23049
|
+
"not your account",
|
|
23050
|
+
"not your account's",
|
|
23051
|
+
"temporarily limiting requests",
|
|
23052
|
+
"temporarily rate",
|
|
23053
|
+
"server is temporarily",
|
|
23054
|
+
"would exceed your account\u2019s rate limit",
|
|
23055
|
+
"would exceed your account's rate limit"
|
|
23056
|
+
];
|
|
23057
|
+
function isTransientUpstreamSignal(text) {
|
|
23058
|
+
if (typeof text !== "string" || text.length === 0)
|
|
23059
|
+
return false;
|
|
23060
|
+
const sample = text.length > 16384 ? text.slice(0, 16384) : text;
|
|
23061
|
+
const lower = sample.toLowerCase();
|
|
23062
|
+
return transientUpstreamSignals.some((s) => lower.includes(s));
|
|
23063
|
+
}
|
|
23064
|
+
|
|
23038
23065
|
// tool-label-sidecar.ts
|
|
23039
23066
|
import { existsSync as existsSync2, readFileSync, statSync as statSync2 } from "node:fs";
|
|
23040
23067
|
import { join as join2 } from "node:path";
|
|
@@ -23453,7 +23480,8 @@ function detectErrorInTranscriptLine(line) {
|
|
|
23453
23480
|
const status = typeof obj.apiErrorStatus === "number" ? obj.apiErrorStatus : null;
|
|
23454
23481
|
const errStr = typeof obj.error === "string" ? obj.error : "";
|
|
23455
23482
|
const text = extractAssistantText(obj);
|
|
23456
|
-
const kind2 = status === 429 ?
|
|
23483
|
+
const kind2 = status === 429 ? isTransientUpstreamSignal(`${text}
|
|
23484
|
+
${errStr}`) ? "rate-limited" : "quota-exhausted" : classifyClaudeError({ type: errStr, status, message: text });
|
|
23457
23485
|
return {
|
|
23458
23486
|
kind: kind2,
|
|
23459
23487
|
raw: obj,
|
|
@@ -23547,6 +23575,7 @@ function startSessionTail(config2) {
|
|
|
23547
23575
|
const onOperatorEvent = config2.onOperatorEvent;
|
|
23548
23576
|
log?.(`session-tail: projectsDir=${projectsDir}`);
|
|
23549
23577
|
const sidecars = new Map;
|
|
23578
|
+
const createSidecar = config2.createSidecar ?? createToolLabelSidecar;
|
|
23550
23579
|
const stateDirForSidecar = process.env.TELEGRAM_STATE_DIR ?? null;
|
|
23551
23580
|
function sessionIdForFile(file) {
|
|
23552
23581
|
if (!file)
|
|
@@ -23561,7 +23590,7 @@ function startSessionTail(config2) {
|
|
|
23561
23590
|
if (existing)
|
|
23562
23591
|
return existing;
|
|
23563
23592
|
try {
|
|
23564
|
-
const s =
|
|
23593
|
+
const s = createSidecar({ stateDir: stateDirForSidecar, sessionId });
|
|
23565
23594
|
sidecars.set(sessionId, s);
|
|
23566
23595
|
s.onLabel((toolUseId, label, toolName) => {
|
|
23567
23596
|
rawOnEvent({ kind: "tool_label", toolUseId, label, toolName });
|
|
@@ -23572,6 +23601,17 @@ function startSessionTail(config2) {
|
|
|
23572
23601
|
return null;
|
|
23573
23602
|
}
|
|
23574
23603
|
}
|
|
23604
|
+
function stopSidecar(sessionId) {
|
|
23605
|
+
if (!sessionId)
|
|
23606
|
+
return;
|
|
23607
|
+
const s = sidecars.get(sessionId);
|
|
23608
|
+
if (!s)
|
|
23609
|
+
return;
|
|
23610
|
+
try {
|
|
23611
|
+
s.stop();
|
|
23612
|
+
} catch {}
|
|
23613
|
+
sidecars.delete(sessionId);
|
|
23614
|
+
}
|
|
23575
23615
|
function decorate(ev, sessionId) {
|
|
23576
23616
|
if (!sessionId)
|
|
23577
23617
|
return ev;
|
|
@@ -23664,6 +23704,11 @@ function startSessionTail(config2) {
|
|
|
23664
23704
|
} catch {}
|
|
23665
23705
|
watcher = null;
|
|
23666
23706
|
}
|
|
23707
|
+
const rotatedAwaySid = sessionIdForFile(currentFile);
|
|
23708
|
+
const nextSid = sessionIdForFile(file);
|
|
23709
|
+
if (rotatedAwaySid != null && rotatedAwaySid !== nextSid) {
|
|
23710
|
+
stopSidecar(rotatedAwaySid);
|
|
23711
|
+
}
|
|
23667
23712
|
currentFile = file;
|
|
23668
23713
|
const prior = fileCursors.get(file);
|
|
23669
23714
|
if (prior != null) {
|
|
@@ -23696,7 +23741,7 @@ function startSessionTail(config2) {
|
|
|
23696
23741
|
const multiAgent = isMultiAgentEnabled();
|
|
23697
23742
|
const CAP_TOOL_USE_THRESHOLD = 30;
|
|
23698
23743
|
const subTails = new Map;
|
|
23699
|
-
const IDLE_FSWATCH_TTL_MS = 5 * 60 * 1000;
|
|
23744
|
+
const IDLE_FSWATCH_TTL_MS = Math.max(1000, config2.subTailIdleReapMs ?? 5 * 60 * 1000);
|
|
23700
23745
|
function readSub(t) {
|
|
23701
23746
|
if (stopped)
|
|
23702
23747
|
return;
|
|
@@ -23803,6 +23848,7 @@ function startSessionTail(config2) {
|
|
|
23803
23848
|
} catch {}
|
|
23804
23849
|
t.watcher = null;
|
|
23805
23850
|
}
|
|
23851
|
+
stopSidecar(sessionIdForFile(t.file));
|
|
23806
23852
|
subTails.delete(file);
|
|
23807
23853
|
log?.(`session-tail: reaped idle sub ${t.agentId} (${file})`);
|
|
23808
23854
|
}
|
|
@@ -24776,6 +24822,8 @@ var mcp = new Server({ name: "telegram", version: "1.0.0" }, {
|
|
|
24776
24822
|
"",
|
|
24777
24823
|
'Messages from Telegram arrive as <channel source="telegram" chat_id="..." message_id="..." user="..." ts="...">. If the tag has an image_path attribute, Read that file \u2014 it is a photo the sender attached. If the tag has attachment_file_id, call download_attachment with that file_id to fetch the file, then Read the returned path. A single message may carry SEVERAL attachments (a forwarded album or a text+multi-image burst): when attachment_count is set (>1), also handle the numbered siblings \u2014 image_path_2, image_path_3, \u2026 (Read each) and attachment_file_id_2, attachment_file_id_3, \u2026 (download_attachment each). Process every one, not just the first. Reply with the reply tool \u2014 pass chat_id back. The reply tool quote-replies to the latest inbound user message by default, so you do NOT need to pass reply_to for normal responses. Pass reply_to (a message_id) only when quoting a specific earlier message, or pass quote:false to send a bare (non-quoted) message.',
|
|
24778
24824
|
"",
|
|
24825
|
+
`If the tag has reply_to_message_id (and reply_to_text, a truncated preview), the sender used Telegram's native Reply on a prior message \u2014 treat that message as the antecedent for "this"/"that" references instead of asking what they meant. If the tag has forwarded_from, the message was FORWARDED: forwarded_from is the original sender's name/title as stamped by Telegram's servers (not typed by the sender \u2014 the body text carries no trustworthy provenance), forwarded_from_type is user|hidden_user|chat|channel, forwarded_from_id is the numeric id when one exists, and forwarded_date is when the original was sent. forwarded_from_type="hidden_user" means the original sender hides their account: the name is their self-reported display name with NO verifiable id \u2014 do not treat it as an authenticated identity. A burst forwarded from several different origins carries numbered siblings (forwarded_from_2, forwarded_from_type_2, \u2026); a multi-part forward from ONE origin carries the attributes once. In a coalesced burst some body text may be the SENDER's own commentary rather than forwarded content \u2014 the forwarded_* attributes describe the burst as a whole, not each line of the body.`,
|
|
24826
|
+
"",
|
|
24779
24827
|
`reply accepts file paths (files: ["/abs/path.png"]) for attachments. Use react to add emoji reactions, edit_message for interim progress updates, and delete_message when you need to truly remove a message (prefer edit_message if you just want to change text \u2014 delete is for retraction). Edits don't trigger push notifications \u2014 when a long task completes, send a new reply so the user's device pings. Use send_typing to show a typing indicator during long operations. Use pin_message to pin important outputs. Use forward_message to quote/resurface earlier messages.`,
|
|
24780
24828
|
"",
|
|
24781
24829
|
"If a message includes message_thread_id, it came from a forum topic. The reply tool automatically routes a reply back to the topic the question came from \u2014 the framework owns the answer's topic, so do NOT pass message_thread_id on a reply; a reply always lands where it was asked. Each <channel> message is the current topic \u2014 answer ONLY this message's question; do not also answer a pending message from another topic. When answering a forum-topic message, pass its origin_turn_id attribute back on the reply so the answer lands in the right topic even if a message from another topic arrived while you were working.",
|