switchroom 0.19.48 → 0.20.0
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 +18 -1
- package/dist/auth-broker/index.js +19 -2
- package/dist/buzz-gateway/index.js +9207 -0
- package/dist/cli/notion-write-pretool.mjs +18 -1
- package/dist/cli/switchroom.js +63 -4
- package/dist/host-control/main.js +20 -3
- package/dist/vault/approvals/kernel-server.js +19 -2
- package/dist/vault/broker/server.js +19 -2
- package/package.json +4 -3
- package/profiles/_base/start.sh.hbs +78 -1
- package/profiles/default/CLAUDE.md.hbs +1 -1
- package/skills/dev-protocol/SKILL.md +30 -1
- package/skills/switchroom-architecture/SKILL.md +5 -0
- package/skills/switchroom-cli/SKILL.md +1 -1
- package/telegram-plugin/dist/bridge/bridge.js +7 -4
- package/telegram-plugin/dist/gateway/gateway.js +1149 -247
- package/telegram-plugin/dist/server.js +7 -4
- package/telegram-plugin/gateway/boot-briefing-builder.ts +458 -0
- package/telegram-plugin/gateway/boot-briefing-wiring.ts +170 -0
- package/telegram-plugin/gateway/buzz-mirror.ts +329 -0
- package/telegram-plugin/gateway/buzz-type-guards.ts +34 -0
- package/telegram-plugin/gateway/channel-route.ts +272 -0
- package/telegram-plugin/gateway/gateway.ts +73 -81
- package/telegram-plugin/gateway/inbound-spool.ts +33 -1
- package/telegram-plugin/gateway/ipc-protocol.ts +81 -2
- package/telegram-plugin/gateway/ipc-server.ts +197 -2
- package/telegram-plugin/gateway/outbound-send-path.ts +37 -1
- package/telegram-plugin/gateway/pending-turn-env.ts +61 -0
- package/telegram-plugin/gateway/stream-render.ts +21 -0
- package/telegram-plugin/gateway/subagent-handback-marker.ts +12 -0
- package/telegram-plugin/gateway/user-failure-notices.ts +172 -0
- package/telegram-plugin/history.ts +15 -0
- package/telegram-plugin/llm-error-present.ts +9 -4
- package/telegram-plugin/model-unavailable.ts +4 -0
- package/telegram-plugin/operator-events.fixtures.json +12 -12
- package/telegram-plugin/operator-events.ts +81 -9
- package/telegram-plugin/session-tail.ts +7 -1
- package/telegram-plugin/tests/boot-briefing-builder.test.ts +604 -0
- package/telegram-plugin/tests/buzz-mirror.test.ts +242 -0
- package/telegram-plugin/tests/buzz-origin-stamp-gate.test.ts +159 -0
- package/telegram-plugin/tests/channel-route.test.ts +306 -0
- package/telegram-plugin/tests/inbound-spool.test.ts +47 -0
- package/telegram-plugin/tests/ipc-server-buzz-dedup.test.ts +124 -0
- package/telegram-plugin/tests/ipc-server-buzz-peer.test.ts +269 -0
- package/telegram-plugin/tests/operator-events-session-tail.test.ts +63 -0
- package/telegram-plugin/tests/operator-events.test.ts +71 -7
- package/telegram-plugin/tests/user-failure-notices.test.ts +165 -0
- package/telegram-plugin/voice-normalize-text.ts +5 -0
- package/vendor/hindsight-memory/scripts/directive_verify.py +4 -0
- package/vendor/hindsight-memory/scripts/recall.py +7 -2
|
@@ -11591,7 +11591,7 @@ __export(exports_client, {
|
|
|
11591
11591
|
});
|
|
11592
11592
|
import * as net from "node:net";
|
|
11593
11593
|
import { homedir as homedir2 } from "node:os";
|
|
11594
|
-
import { randomUUID } from "node:crypto";
|
|
11594
|
+
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
11595
11595
|
import { join as join3 } from "node:path";
|
|
11596
11596
|
function reviveDate(v) {
|
|
11597
11597
|
if (v == null)
|
|
@@ -11649,7 +11649,7 @@ class AuthBrokerClient {
|
|
|
11649
11649
|
async getCredentials(provider, account) {
|
|
11650
11650
|
const base = {
|
|
11651
11651
|
v: PROTOCOL_VERSION,
|
|
11652
|
-
id:
|
|
11652
|
+
id: randomUUID2(),
|
|
11653
11653
|
op: "get-credentials"
|
|
11654
11654
|
};
|
|
11655
11655
|
let req = base;
|
|
@@ -11663,7 +11663,7 @@ class AuthBrokerClient {
|
|
|
11663
11663
|
async listState() {
|
|
11664
11664
|
const data = await this.send({
|
|
11665
11665
|
v: PROTOCOL_VERSION,
|
|
11666
|
-
id:
|
|
11666
|
+
id: randomUUID2(),
|
|
11667
11667
|
op: "list-state"
|
|
11668
11668
|
});
|
|
11669
11669
|
return data;
|
|
@@ -11671,7 +11671,7 @@ class AuthBrokerClient {
|
|
|
11671
11671
|
async listGoogleAccounts() {
|
|
11672
11672
|
const data = await this.send({
|
|
11673
11673
|
v: PROTOCOL_VERSION,
|
|
11674
|
-
id:
|
|
11674
|
+
id: randomUUID2(),
|
|
11675
11675
|
op: "list-google-accounts"
|
|
11676
11676
|
});
|
|
11677
11677
|
return data;
|
|
@@ -11679,7 +11679,7 @@ class AuthBrokerClient {
|
|
|
11679
11679
|
async listMicrosoftAccounts() {
|
|
11680
11680
|
const data = await this.send({
|
|
11681
11681
|
v: PROTOCOL_VERSION,
|
|
11682
|
-
id:
|
|
11682
|
+
id: randomUUID2(),
|
|
11683
11683
|
op: "list-microsoft-accounts"
|
|
11684
11684
|
});
|
|
11685
11685
|
return data;
|
|
@@ -11687,7 +11687,7 @@ class AuthBrokerClient {
|
|
|
11687
11687
|
async probeQuota(accounts, timeoutMs, forceLive) {
|
|
11688
11688
|
const data = await this.send({
|
|
11689
11689
|
v: PROTOCOL_VERSION,
|
|
11690
|
-
id:
|
|
11690
|
+
id: randomUUID2(),
|
|
11691
11691
|
op: "probe-quota",
|
|
11692
11692
|
accounts: [...accounts],
|
|
11693
11693
|
...timeoutMs !== undefined ? { timeoutMs } : {},
|
|
@@ -11705,7 +11705,7 @@ class AuthBrokerClient {
|
|
|
11705
11705
|
async getExternalSpend(forceLive) {
|
|
11706
11706
|
const data = await this.send({
|
|
11707
11707
|
v: PROTOCOL_VERSION,
|
|
11708
|
-
id:
|
|
11708
|
+
id: randomUUID2(),
|
|
11709
11709
|
op: "get-external-spend",
|
|
11710
11710
|
...forceLive ? { forceLive: true } : {}
|
|
11711
11711
|
});
|
|
@@ -11714,21 +11714,21 @@ class AuthBrokerClient {
|
|
|
11714
11714
|
async setActive(account) {
|
|
11715
11715
|
const data = await this.send({
|
|
11716
11716
|
v: PROTOCOL_VERSION,
|
|
11717
|
-
id:
|
|
11717
|
+
id: randomUUID2(),
|
|
11718
11718
|
op: "set-active",
|
|
11719
11719
|
account
|
|
11720
11720
|
});
|
|
11721
11721
|
return data;
|
|
11722
11722
|
}
|
|
11723
11723
|
async markExhausted(until) {
|
|
11724
|
-
const req = until !== undefined ? { v: PROTOCOL_VERSION, id:
|
|
11724
|
+
const req = until !== undefined ? { v: PROTOCOL_VERSION, id: randomUUID2(), op: "mark-exhausted", until } : { v: PROTOCOL_VERSION, id: randomUUID2(), op: "mark-exhausted" };
|
|
11725
11725
|
const data = await this.send(req);
|
|
11726
11726
|
return data;
|
|
11727
11727
|
}
|
|
11728
11728
|
async markThrottled(until) {
|
|
11729
11729
|
const data = await this.send({
|
|
11730
11730
|
v: PROTOCOL_VERSION,
|
|
11731
|
-
id:
|
|
11731
|
+
id: randomUUID2(),
|
|
11732
11732
|
op: "mark-throttled",
|
|
11733
11733
|
until
|
|
11734
11734
|
});
|
|
@@ -11737,7 +11737,7 @@ class AuthBrokerClient {
|
|
|
11737
11737
|
async claimNotification(key, windowMs) {
|
|
11738
11738
|
const data = await this.send({
|
|
11739
11739
|
v: PROTOCOL_VERSION,
|
|
11740
|
-
id:
|
|
11740
|
+
id: randomUUID2(),
|
|
11741
11741
|
op: "claim-notification",
|
|
11742
11742
|
key,
|
|
11743
11743
|
windowMs
|
|
@@ -11747,7 +11747,7 @@ class AuthBrokerClient {
|
|
|
11747
11747
|
async refreshAccount(account) {
|
|
11748
11748
|
const data = await this.send({
|
|
11749
11749
|
v: PROTOCOL_VERSION,
|
|
11750
|
-
id:
|
|
11750
|
+
id: randomUUID2(),
|
|
11751
11751
|
op: "refresh-account",
|
|
11752
11752
|
account
|
|
11753
11753
|
});
|
|
@@ -11756,7 +11756,7 @@ class AuthBrokerClient {
|
|
|
11756
11756
|
async addAccount(label, credentials, replace, provider) {
|
|
11757
11757
|
const base = {
|
|
11758
11758
|
v: PROTOCOL_VERSION,
|
|
11759
|
-
id:
|
|
11759
|
+
id: randomUUID2(),
|
|
11760
11760
|
op: "add-account",
|
|
11761
11761
|
label,
|
|
11762
11762
|
credentials
|
|
@@ -11769,7 +11769,7 @@ class AuthBrokerClient {
|
|
|
11769
11769
|
async rmAccount(label, provider) {
|
|
11770
11770
|
const base = {
|
|
11771
11771
|
v: PROTOCOL_VERSION,
|
|
11772
|
-
id:
|
|
11772
|
+
id: randomUUID2(),
|
|
11773
11773
|
op: "rm-account",
|
|
11774
11774
|
label
|
|
11775
11775
|
};
|
|
@@ -11780,7 +11780,7 @@ class AuthBrokerClient {
|
|
|
11780
11780
|
async setOverride(agent, account) {
|
|
11781
11781
|
const data = await this.send({
|
|
11782
11782
|
v: PROTOCOL_VERSION,
|
|
11783
|
-
id:
|
|
11783
|
+
id: randomUUID2(),
|
|
11784
11784
|
op: "set-override",
|
|
11785
11785
|
agent,
|
|
11786
11786
|
account
|
|
@@ -21547,7 +21547,7 @@ var init_observation_scopes = __esm(() => {
|
|
|
21547
21547
|
});
|
|
21548
21548
|
|
|
21549
21549
|
// ../src/config/schema.ts
|
|
21550
|
-
var CodeRepoEntrySchema, AgentBindMountSchema, HttpDiffPollSchema, PollSpecSchema, TelegramMessageActionSchema, WebhookActionSchema, ActionSpecSchema, ScheduleEntrySchema, AgentSoulSchema, AgentToolsSchema, ObservationScopesSchema, ObservationScopeStrategySchema, AntiConfabulationDirectiveSchema, AgentMemorySchema, HookEntrySchema, AgentHooksSchema, SubagentSchema, SessionSchema, SessionContinuitySchema, webhookDispatchRule, TelegramChannelSchema, ChannelsSchema, TIMEZONE_REGEX, ApproverIdSchema, GoogleWorkspaceTierSchema, GoogleServiceTokenSchema, 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;
|
|
21550
|
+
var CodeRepoEntrySchema, AgentBindMountSchema, HttpDiffPollSchema, PollSpecSchema, TelegramMessageActionSchema, WebhookActionSchema, ActionSpecSchema, ScheduleEntrySchema, AgentSoulSchema, AgentToolsSchema, ObservationScopesSchema, ObservationScopeStrategySchema, AntiConfabulationDirectiveSchema, AgentMemorySchema, HookEntrySchema, AgentHooksSchema, SubagentSchema, SessionSchema, SessionContinuitySchema, webhookDispatchRule, TelegramChannelSchema, BuzzChannelSchema, ChannelsSchema, TIMEZONE_REGEX, ApproverIdSchema, GoogleWorkspaceTierSchema, GoogleServiceTokenSchema, 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;
|
|
21551
21551
|
var init_schema = __esm(() => {
|
|
21552
21552
|
init_zod();
|
|
21553
21553
|
init_observation_scopes();
|
|
@@ -21794,6 +21794,7 @@ var init_schema = __esm(() => {
|
|
|
21794
21794
|
max_turns_in_briefing: exports_external.number().int().positive().optional().describe("Cap on recent user/assistant turn pairs fed to the summarizer."),
|
|
21795
21795
|
resume_mode: exports_external.enum(["auto", "continue", "handoff", "none"]).optional().describe("How to resume the next session. 'handoff' (default as of #362) " + "never passes --continue; a fresh Claude starts each restart and " + "reads a briefing assembled from recent Telegram messages, Hindsight " + "recall, and today's daily memory file. 'auto' uses --continue when " + "the latest JSONL is smaller than resume_max_bytes, else falls back " + "to the handoff briefing. 'continue' always passes --continue. " + "'none' starts completely fresh every time."),
|
|
21796
21796
|
resume_max_bytes: exports_external.number().int().positive().optional().describe("Byte threshold above which 'auto' mode falls back to handoff " + "instead of --continue. Default 2_000_000 (~2MB). Large transcripts " + "can blow out the context window even with prefix caching, and " + "--continue replay is known-fragile at scale."),
|
|
21797
|
+
briefing: exports_external.enum(["gateway", "legacy"]).optional().describe("Which mechanism assembles the fresh-session reorientation briefing " + "(default 'legacy'). 'legacy' keeps today's behaviour: the Stop-hook " + ".handoff.md and/or bin/handoff-briefing.sh, injected via " + "--append-system-prompt. 'gateway' moves it to a gateway boot-time " + "builder sourced from the durable history.db (crash-independent, " + "surface-scoped, token-budgeted) and injects it as a synthetic " + '<channel source="boot_briefing"> inbound over the durable spool \u2014 ' + "keeping the system-prompt prefix stable for cross-session prompt " + "caching. Suppressed automatically when resume_mode is " + "'continue'/'auto' (the transcript may be replayed) and on a /reset " + "force-fresh boot. Threaded to the gateway as " + "SWITCHROOM_SESSION_BRIEFING."),
|
|
21797
21798
|
boot_resume: exports_external.enum(["always", "in-flight", "never"]).optional().describe("How the gateway auto-resumes a turn that was IN FLIGHT when the " + "agent restarted. 'in-flight' (default) resumes genuinely " + "interrupted work even after a deliberate/operator restart \u2014 a " + "sanctioned restart landing mid-turn no longer silently drops the " + "work. 'always' forces resume unconditionally (same as the " + "SWITCHROOM_BOOT_RESUME_ALWAYS=1 escape hatch). 'never' is the " + "quota-saving posture: don't auto-replay work across a clean " + "restart \u2014 but the user is STILL sent a passive notice of what was " + "in flight (silence is never used). Independent of the at-most-once " + "resume ledger and the bounded resume-chain loop-guard, which always " + "apply. Threaded to the gateway as SWITCHROOM_BOOT_RESUME."),
|
|
21798
21799
|
session_retention_max_count: exports_external.number().int().nonnegative().optional().describe("Session-JSONL retention (issue #2792): keep at most this many " + "newest session transcripts under .claude/projects; older ones " + "past both this count and the age bound are pruned by the Stop " + "hook. The newest sessions (and the handoff source) are always " + "kept. Default 20; set 0 to disable the count bound."),
|
|
21799
21800
|
session_retention_max_age_days: exports_external.number().int().nonnegative().optional().describe("Session-JSONL retention (issue #2792): prune session transcripts " + "older than this many days (a file is deleted only when it is BOTH " + "over the count bound and older than this). Default 30; set 0 to " + "disable the age bound.")
|
|
@@ -21926,8 +21927,24 @@ var init_schema = __esm(() => {
|
|
|
21926
21927
|
}
|
|
21927
21928
|
return tg;
|
|
21928
21929
|
});
|
|
21930
|
+
BuzzChannelSchema = exports_external.object({
|
|
21931
|
+
enabled: exports_external.boolean().default(false).describe("Master switch for the per-agent Buzz sidecar. Default false \u2014 the " + "channel ships dark; start.sh forks the sidecar only when true."),
|
|
21932
|
+
relay_url: exports_external.string().regex(/^wss?:\/\//, "relay_url must be a ws:// or wss:// URL").describe("CANONICAL WebSocket URL of the closed Buzz relay \u2014 the exact string " + "the relay expects in the NIP-42 `relay` auth tag (e.g. " + "'ws://127.0.0.1:3000'). A live probe proved the relay validates this " + "tag as an exact string match against its own URL BEFORE the " + "membership check, so it is the relay's advertised identity, NOT " + "necessarily the address the sidecar dials. Set relay_dial_url when " + "the reachable address differs (a docker-network IP)."),
|
|
21933
|
+
relay_dial_url: exports_external.string().regex(/^wss?:\/\//, "relay_dial_url must be a ws:// or wss:// URL").optional().describe("Reachable ws:// / wss:// address the sidecar DIALS when it differs " + "from the canonical relay_url (e.g. a docker-network IP the relay's " + "own 127.0.0.1 can't stand in for). The NIP-42 auth tag still uses " + "relay_url. Defaults to relay_url when unset."),
|
|
21934
|
+
relay_host: exports_external.string().regex(/^(\[[0-9a-fA-F:]+\]|[^\s/?#:@]+)(:\d+)?$/, "relay_host must be a bare host[:port] authority \u2014 no scheme, path, or userinfo (e.g. '127.0.0.1:3000')").describe("REQUIRED HTTP Host header authority sent verbatim on the WS upgrade " + "(e.g. '127.0.0.1:3000', port included). The relay resolves its " + "community from this header before the upgrade and returns HTTP 404 if " + "it is missing/wrong, so it must match the relay's configured " + "authority and is deployment config, never derived from the dial URL."),
|
|
21935
|
+
nsec_vault_key: exports_external.string().default("buzz/{agent}-nsec").describe("Vault KEY NAME for the agent's Nostr secret key. Broker-fetched " + "in-process at sidecar boot; NEVER resolved into env or logged. " + "'{agent}' is substituted with the agent name."),
|
|
21936
|
+
operator_pubkey: exports_external.string().regex(/^(npub1[02-9ac-hj-np-z]{58}|[0-9a-f]{64})$/, "operator_pubkey must be a bech32 npub or 64-char hex pubkey").describe("The operator's Nostr pubkey (npub or hex). Always in the effective " + "inbound allowlist \u2014 the fail-closed default is operator-only."),
|
|
21937
|
+
authorized_pubkeys: exports_external.array(exports_external.string()).default([]).describe("Additional pubkeys (npub or hex) whose signed events may become " + "turns. Effective allowlist = this \u222a {operator_pubkey}. Empty by " + "default (operator-only)."),
|
|
21938
|
+
mirror: exports_external.enum(["both", "origin", "off"]).default("both").describe("Cross-surface mirror mode. 'both' answers on the origin channel AND " + "mirrors a copy to the other; 'off' is a true kill-switch that disables " + "the channel in BOTH directions (the inbound sidecar exits idle). " + "Phase 2b (S2): 'origin' is DEFERRED \u2014 the hub's mirror hook lives only " + "in sendReply, so 'origin' cannot be honored soundly; a configured " + "'origin' is degraded to 'off' (dark) at runtime by both the sidecar " + "config loader and the hub (channel-route.ts parseConfiguredMirrorMode). " + "Only 'both' and 'off' ship live in 2b."),
|
|
21939
|
+
chat_id: exports_external.string().min(1, "chat_id must be a non-empty Telegram chat id").describe("Telegram chat id an injected Buzz turn is routed to. Phase 1 is " + "inbound-only, so the agent's reply lands here on Telegram (the " + "authoritative surface); in later phases this is the chat the Buzz " + "turn's Telegram copy maps to. Required \u2014 the sidecar refuses to run " + "live without it (BUZZ_CHAT_ID)."),
|
|
21940
|
+
default_channel_id: exports_external.string().describe("Relay-minted group UUID (the NIP-29 `h` tag) the sidecar subscribes " + "to and stamps on injected turns."),
|
|
21941
|
+
channel_map: exports_external.record(exports_external.string(), exports_external.string()).default({}).describe("Optional map of extra group UUIDs \u2192 friendly labels."),
|
|
21942
|
+
pubkey_names: exports_external.record(exports_external.string(), exports_external.string()).default({}).describe("Optional petnames: hex/npub pubkey \u2192 display name, used to label " + "the sender on injected turns."),
|
|
21943
|
+
pinned_relay_digest: exports_external.string().optional().describe("Pinned relay image digest (M4). The compat-check warns on mismatch; " + "advisory in Phase 1.")
|
|
21944
|
+
}).strict();
|
|
21929
21945
|
ChannelsSchema = exports_external.object({
|
|
21930
|
-
telegram: TelegramChannelSchema
|
|
21946
|
+
telegram: TelegramChannelSchema,
|
|
21947
|
+
buzz: BuzzChannelSchema.optional()
|
|
21931
21948
|
}).optional();
|
|
21932
21949
|
TIMEZONE_REGEX = /^UTC$|^[A-Z][A-Za-z0-9_+-]+(\/[A-Z][A-Za-z0-9_+-]+){1,2}$/;
|
|
21933
21950
|
ApproverIdSchema = exports_external.union([exports_external.number(), exports_external.string().regex(/^\d+$/)]);
|
|
@@ -29758,6 +29775,7 @@ __export(exports_history, {
|
|
|
29758
29775
|
hasOutboundDeliveredSince: () => hasOutboundDeliveredSince2,
|
|
29759
29776
|
getRecentOutboundCount: () => getRecentOutboundCount,
|
|
29760
29777
|
getLatestInboundMessageId: () => getLatestInboundMessageId2,
|
|
29778
|
+
getHistoryDbForBriefing: () => getHistoryDbForBriefing,
|
|
29761
29779
|
deliveryTextMatch: () => deliveryTextMatch2,
|
|
29762
29780
|
deleteFromHistory: () => deleteFromHistory2,
|
|
29763
29781
|
checkpointWal: () => checkpointWal2,
|
|
@@ -29901,6 +29919,9 @@ function verifyHistoryWritable2() {
|
|
|
29901
29919
|
} catch {}
|
|
29902
29920
|
}
|
|
29903
29921
|
}
|
|
29922
|
+
function getHistoryDbForBriefing() {
|
|
29923
|
+
return db2;
|
|
29924
|
+
}
|
|
29904
29925
|
function _resetForTests() {
|
|
29905
29926
|
if (db2 != null) {
|
|
29906
29927
|
db2.close();
|
|
@@ -38221,7 +38242,7 @@ __export(exports_tmux2, {
|
|
|
38221
38242
|
captureAgentPane: () => captureAgentPane2
|
|
38222
38243
|
});
|
|
38223
38244
|
import { execFileSync as execFileSync8 } from "node:child_process";
|
|
38224
|
-
import { chmodSync as chmodSync13, mkdirSync as mkdirSync50, readdirSync as readdirSync15, statSync as statSync22, unlinkSync as unlinkSync30, writeFileSync as
|
|
38245
|
+
import { chmodSync as chmodSync13, mkdirSync as mkdirSync50, readdirSync as readdirSync15, statSync as statSync22, unlinkSync as unlinkSync30, writeFileSync as writeFileSync51 } from "node:fs";
|
|
38225
38246
|
import { resolve as resolve12 } from "node:path";
|
|
38226
38247
|
function captureAgentPane2(opts) {
|
|
38227
38248
|
const { agentName: agentName3, agentDir, reason } = opts;
|
|
@@ -38272,7 +38293,7 @@ function captureAgentPane2(opts) {
|
|
|
38272
38293
|
` + `
|
|
38273
38294
|
`;
|
|
38274
38295
|
try {
|
|
38275
|
-
|
|
38296
|
+
writeFileSync51(outPath, Buffer.concat([Buffer.from(header, "utf8"), body]), {
|
|
38276
38297
|
mode: 384
|
|
38277
38298
|
});
|
|
38278
38299
|
} catch (err) {
|
|
@@ -39156,7 +39177,7 @@ __export(exports_materialize_bot_token, {
|
|
|
39156
39177
|
materializeBotToken: () => materializeBotToken,
|
|
39157
39178
|
BotTokenMaterializeError: () => BotTokenMaterializeError
|
|
39158
39179
|
});
|
|
39159
|
-
import { existsSync as
|
|
39180
|
+
import { existsSync as existsSync59 } from "node:fs";
|
|
39160
39181
|
function pickConfiguredToken(config, agentName3) {
|
|
39161
39182
|
if (agentName3) {
|
|
39162
39183
|
const agent = config.agents?.[agentName3];
|
|
@@ -39170,7 +39191,7 @@ function tryDirectVaultRead4(ref, config, passphrase) {
|
|
|
39170
39191
|
if (!passphrase)
|
|
39171
39192
|
return null;
|
|
39172
39193
|
const vaultPath = resolvePath(config.vault?.path ?? "~/.switchroom/vault.enc");
|
|
39173
|
-
if (!
|
|
39194
|
+
if (!existsSync59(vaultPath))
|
|
39174
39195
|
return null;
|
|
39175
39196
|
try {
|
|
39176
39197
|
const secrets = openVault(passphrase, vaultPath);
|
|
@@ -39325,18 +39346,18 @@ var import_runner3 = __toESM(require_mod3(), 1);
|
|
|
39325
39346
|
import { randomBytes as randomBytes13, createHash as createHash8 } from "crypto";
|
|
39326
39347
|
import { execFileSync as execFileSync9, execSync as execSync2, spawn as spawn2 } from "child_process";
|
|
39327
39348
|
import {
|
|
39328
|
-
readFileSync as
|
|
39329
|
-
writeFileSync as
|
|
39349
|
+
readFileSync as readFileSync62,
|
|
39350
|
+
writeFileSync as writeFileSync52,
|
|
39330
39351
|
mkdirSync as mkdirSync51,
|
|
39331
39352
|
readdirSync as readdirSync16,
|
|
39332
|
-
rmSync as
|
|
39353
|
+
rmSync as rmSync9,
|
|
39333
39354
|
statSync as statSync23,
|
|
39334
|
-
renameSync as
|
|
39355
|
+
renameSync as renameSync28,
|
|
39335
39356
|
realpathSync as realpathSync5,
|
|
39336
39357
|
chmodSync as chmodSync14,
|
|
39337
39358
|
openSync as openSync15,
|
|
39338
39359
|
closeSync as closeSync15,
|
|
39339
|
-
existsSync as
|
|
39360
|
+
existsSync as existsSync60,
|
|
39340
39361
|
unlinkSync as unlinkSync31,
|
|
39341
39362
|
appendFileSync as appendFileSync9
|
|
39342
39363
|
} from "fs";
|
|
@@ -39392,7 +39413,7 @@ function fsyncPathSync(path) {
|
|
|
39392
39413
|
|
|
39393
39414
|
// gateway/gateway.ts
|
|
39394
39415
|
import { homedir as homedir20 } from "os";
|
|
39395
|
-
import { join as
|
|
39416
|
+
import { join as join70, sep as sep4, basename as basename17 } from "path";
|
|
39396
39417
|
|
|
39397
39418
|
// plugin-logger.ts
|
|
39398
39419
|
import { appendFileSync, mkdirSync, renameSync as renameSync2, statSync, existsSync } from "fs";
|
|
@@ -42279,6 +42300,225 @@ function resolveReplyOwnerTurnWith(lookups, liveTurn, chatId, args) {
|
|
|
42279
42300
|
return { turn: winnerId != null ? byId.get(winnerId) ?? null : null, tier, candidates };
|
|
42280
42301
|
}
|
|
42281
42302
|
|
|
42303
|
+
// gateway/buzz-mirror.ts
|
|
42304
|
+
import { randomUUID } from "crypto";
|
|
42305
|
+
|
|
42306
|
+
// gateway/channel-route.ts
|
|
42307
|
+
var TELEGRAM_ONLY = Object.freeze({ originChannel: "telegram" });
|
|
42308
|
+
var OUTER_LAST_SOURCE = /<channel[^>]*\bsource="([^"]+)"/;
|
|
42309
|
+
var OUTER_OPEN_TAG = /<channel[^>]*>/;
|
|
42310
|
+
function unescapeXmlAttr(s) {
|
|
42311
|
+
return s.replace(/"/g, '"').replace(/</g, "<").replace(/>/g, ">").replace(/&/g, "&");
|
|
42312
|
+
}
|
|
42313
|
+
function readAttr(openTag, name) {
|
|
42314
|
+
const m = openTag.match(new RegExp(`\\b${name}="([^"]*)"`));
|
|
42315
|
+
if (m == null)
|
|
42316
|
+
return null;
|
|
42317
|
+
const value = unescapeXmlAttr(m[1]);
|
|
42318
|
+
return value.length > 0 ? value : null;
|
|
42319
|
+
}
|
|
42320
|
+
function parseChannelOrigin(rawContent) {
|
|
42321
|
+
if (typeof rawContent !== "string")
|
|
42322
|
+
return TELEGRAM_ONLY;
|
|
42323
|
+
const sourceMatch = rawContent.match(OUTER_LAST_SOURCE);
|
|
42324
|
+
if (sourceMatch == null || sourceMatch[1] !== "buzz")
|
|
42325
|
+
return TELEGRAM_ONLY;
|
|
42326
|
+
const openMatch = rawContent.match(OUTER_OPEN_TAG);
|
|
42327
|
+
if (openMatch == null)
|
|
42328
|
+
return TELEGRAM_ONLY;
|
|
42329
|
+
const openTag = openMatch[0];
|
|
42330
|
+
const channelId = readAttr(openTag, "buzz_channel_id");
|
|
42331
|
+
const eventId = readAttr(openTag, "buzz_event_id");
|
|
42332
|
+
const threadRoot = readAttr(openTag, "buzz_thread_root");
|
|
42333
|
+
if (channelId == null || eventId == null || threadRoot == null) {
|
|
42334
|
+
process.stderr.write("telegram gateway: buzz-origin turn missing coordinate " + `(channel_id=${channelId != null} event_id=${eventId != null} ` + `thread_root=${threadRoot != null}) \u2014 routing as telegram
|
|
42335
|
+
`);
|
|
42336
|
+
return TELEGRAM_ONLY;
|
|
42337
|
+
}
|
|
42338
|
+
return { originChannel: "buzz", buzzCoords: { channelId, eventId, threadRoot } };
|
|
42339
|
+
}
|
|
42340
|
+
function resolveRoute(originChannel, mode, buzzEnabled) {
|
|
42341
|
+
const buzzLive = buzzEnabled && mode !== "off";
|
|
42342
|
+
const primary = originChannel === "buzz" && buzzLive ? "buzz" : "telegram";
|
|
42343
|
+
let mirrors = [];
|
|
42344
|
+
if (buzzLive && mode === "both") {
|
|
42345
|
+
mirrors = originChannel === "telegram" ? ["buzz"] : ["telegram"];
|
|
42346
|
+
}
|
|
42347
|
+
return { primary, mirrors };
|
|
42348
|
+
}
|
|
42349
|
+
function parseConfiguredMirrorMode(raw) {
|
|
42350
|
+
if (raw === undefined)
|
|
42351
|
+
return "both";
|
|
42352
|
+
if (raw === "both")
|
|
42353
|
+
return "both";
|
|
42354
|
+
return "off";
|
|
42355
|
+
}
|
|
42356
|
+
function isBuzzThreadedPublishSafe(input) {
|
|
42357
|
+
return input.ownerEchoed || !input.hasRecentDifferentOriginTurn;
|
|
42358
|
+
}
|
|
42359
|
+
function isBuzzTurnRoutingEnabled(env = process.env) {
|
|
42360
|
+
return env.SWITCHROOM_BUZZ_TURN_ROUTING !== "0";
|
|
42361
|
+
}
|
|
42362
|
+
|
|
42363
|
+
// gateway/buzz-mirror.ts
|
|
42364
|
+
var CORRECTION_DEBOUNCE_MS = 30000;
|
|
42365
|
+
var MAX_TRACKED = 4096;
|
|
42366
|
+
|
|
42367
|
+
class BuzzMirror {
|
|
42368
|
+
cfg;
|
|
42369
|
+
log;
|
|
42370
|
+
sender = null;
|
|
42371
|
+
pending = new Map;
|
|
42372
|
+
pendingOrder = [];
|
|
42373
|
+
msgToBuzz = new Map;
|
|
42374
|
+
msgOrder = [];
|
|
42375
|
+
correctionTimers = new Map;
|
|
42376
|
+
constructor(cfg) {
|
|
42377
|
+
this.cfg = cfg;
|
|
42378
|
+
this.log = cfg.log ?? (() => {});
|
|
42379
|
+
}
|
|
42380
|
+
attachSender(sender) {
|
|
42381
|
+
this.sender = sender;
|
|
42382
|
+
}
|
|
42383
|
+
evict(map, order) {
|
|
42384
|
+
while (order.length > MAX_TRACKED) {
|
|
42385
|
+
const k = order.shift();
|
|
42386
|
+
if (k !== undefined)
|
|
42387
|
+
map.delete(k);
|
|
42388
|
+
}
|
|
42389
|
+
}
|
|
42390
|
+
mirrorReplyDelivered(input) {
|
|
42391
|
+
try {
|
|
42392
|
+
const route = resolveRoute(input.ownerOriginChannel, this.cfg.mode, true);
|
|
42393
|
+
const buzzInRoute = route.primary === "buzz" || route.mirrors.includes("buzz");
|
|
42394
|
+
if (!buzzInRoute)
|
|
42395
|
+
return;
|
|
42396
|
+
let channelId;
|
|
42397
|
+
let replyToEventId;
|
|
42398
|
+
let threadRootId;
|
|
42399
|
+
if (input.ownerOriginChannel === "buzz" && input.ownerBuzzCoords) {
|
|
42400
|
+
if (!isBuzzThreadedPublishSafe({
|
|
42401
|
+
ownerEchoed: input.ownerEchoed,
|
|
42402
|
+
hasRecentDifferentOriginTurn: input.hasRecentDifferentOriginTurn
|
|
42403
|
+
})) {
|
|
42404
|
+
this.log("buzz-mirror: S1 guard blocked a threaded publish on an ambiguous " + "owner binding (un-echoed reply + a recent different-origin turn) " + "\u2014 delivered Telegram-only");
|
|
42405
|
+
return;
|
|
42406
|
+
}
|
|
42407
|
+
channelId = input.ownerBuzzCoords.channelId;
|
|
42408
|
+
replyToEventId = input.ownerBuzzCoords.eventId;
|
|
42409
|
+
threadRootId = input.ownerBuzzCoords.threadRoot;
|
|
42410
|
+
} else {
|
|
42411
|
+
if (!this.cfg.defaultChannelId)
|
|
42412
|
+
return;
|
|
42413
|
+
channelId = this.cfg.defaultChannelId;
|
|
42414
|
+
}
|
|
42415
|
+
this.publish({
|
|
42416
|
+
channelId,
|
|
42417
|
+
replyToEventId,
|
|
42418
|
+
threadRootId,
|
|
42419
|
+
payload: { kind: "message", text: input.scrubbedText }
|
|
42420
|
+
}, input.telegramMessageKeys);
|
|
42421
|
+
} catch (err) {
|
|
42422
|
+
this.log(`buzz-mirror: mirrorReplyDelivered threw (ignored): ${String(err)}`);
|
|
42423
|
+
}
|
|
42424
|
+
}
|
|
42425
|
+
mirrorCorrection(input) {
|
|
42426
|
+
try {
|
|
42427
|
+
const target = this.msgToBuzz.get(input.telegramMessageKey);
|
|
42428
|
+
if (!target)
|
|
42429
|
+
return;
|
|
42430
|
+
const existing = this.correctionTimers.get(input.telegramMessageKey);
|
|
42431
|
+
if (existing)
|
|
42432
|
+
clearTimeout(existing);
|
|
42433
|
+
const timer = setTimeout(() => {
|
|
42434
|
+
this.correctionTimers.delete(input.telegramMessageKey);
|
|
42435
|
+
const t = this.msgToBuzz.get(input.telegramMessageKey);
|
|
42436
|
+
if (!t)
|
|
42437
|
+
return;
|
|
42438
|
+
this.publish({
|
|
42439
|
+
channelId: t.channelId,
|
|
42440
|
+
replyToEventId: t.eventId,
|
|
42441
|
+
threadRootId: t.eventId,
|
|
42442
|
+
payload: {
|
|
42443
|
+
kind: "correction",
|
|
42444
|
+
text: input.scrubbedText,
|
|
42445
|
+
targetEventId: t.eventId
|
|
42446
|
+
}
|
|
42447
|
+
}, []);
|
|
42448
|
+
}, CORRECTION_DEBOUNCE_MS);
|
|
42449
|
+
if (typeof timer.unref === "function") {
|
|
42450
|
+
timer.unref();
|
|
42451
|
+
}
|
|
42452
|
+
this.correctionTimers.set(input.telegramMessageKey, timer);
|
|
42453
|
+
} catch (err) {
|
|
42454
|
+
this.log(`buzz-mirror: mirrorCorrection threw (ignored): ${String(err)}`);
|
|
42455
|
+
}
|
|
42456
|
+
}
|
|
42457
|
+
onPublishResult(msg) {
|
|
42458
|
+
const p = this.pending.get(msg.correlationId);
|
|
42459
|
+
this.pending.delete(msg.correlationId);
|
|
42460
|
+
if (!p)
|
|
42461
|
+
return;
|
|
42462
|
+
if (!msg.ok || !msg.eventId) {
|
|
42463
|
+
this.log(`buzz-mirror: publish failed (correlationId=${msg.correlationId.slice(0, 8)}` + `${msg.error ? ` error=${msg.error}` : ""}) \u2014 Telegram copy already delivered`);
|
|
42464
|
+
return;
|
|
42465
|
+
}
|
|
42466
|
+
for (const key of p.telegramMessageKeys) {
|
|
42467
|
+
this.msgToBuzz.set(key, { eventId: msg.eventId, channelId: p.channelId });
|
|
42468
|
+
this.msgOrder.push(key);
|
|
42469
|
+
}
|
|
42470
|
+
this.evict(this.msgToBuzz, this.msgOrder);
|
|
42471
|
+
}
|
|
42472
|
+
publish(fields, telegramMessageKeys) {
|
|
42473
|
+
if (!this.sender) {
|
|
42474
|
+
this.log("buzz-mirror: no Buzz peer connected \u2014 mirror dropped (Telegram copy delivered)");
|
|
42475
|
+
return;
|
|
42476
|
+
}
|
|
42477
|
+
const correlationId = randomUUID();
|
|
42478
|
+
const msg = {
|
|
42479
|
+
type: "outbound_to_buzz",
|
|
42480
|
+
correlationId,
|
|
42481
|
+
agentName: this.cfg.agentName,
|
|
42482
|
+
...fields
|
|
42483
|
+
};
|
|
42484
|
+
const sent = this.sender(msg);
|
|
42485
|
+
if (!sent) {
|
|
42486
|
+
this.log("buzz-mirror: Buzz peer send returned false \u2014 mirror dropped (Telegram copy delivered)");
|
|
42487
|
+
return;
|
|
42488
|
+
}
|
|
42489
|
+
this.pending.set(correlationId, {
|
|
42490
|
+
channelId: fields.channelId,
|
|
42491
|
+
telegramMessageKeys
|
|
42492
|
+
});
|
|
42493
|
+
this.pendingOrder.push(correlationId);
|
|
42494
|
+
this.evict(this.pending, this.pendingOrder);
|
|
42495
|
+
}
|
|
42496
|
+
}
|
|
42497
|
+
var singleton = null;
|
|
42498
|
+
function initBuzzMirror(cfg) {
|
|
42499
|
+
singleton = new BuzzMirror(cfg);
|
|
42500
|
+
return singleton;
|
|
42501
|
+
}
|
|
42502
|
+
function getBuzzMirror() {
|
|
42503
|
+
return singleton;
|
|
42504
|
+
}
|
|
42505
|
+
function maybeBootBuzzMirror(sender, env = process.env) {
|
|
42506
|
+
if (env.BUZZ_ENABLED !== "1" && env.BUZZ_ENABLED !== "true")
|
|
42507
|
+
return null;
|
|
42508
|
+
const mode = parseConfiguredMirrorMode(env.BUZZ_MIRROR);
|
|
42509
|
+
if (mode !== "both")
|
|
42510
|
+
return null;
|
|
42511
|
+
const bm = initBuzzMirror({
|
|
42512
|
+
mode,
|
|
42513
|
+
agentName: env.SWITCHROOM_AGENT_NAME?.trim() ?? "",
|
|
42514
|
+
defaultChannelId: env.BUZZ_CHANNEL_IDS?.trim() ?? "",
|
|
42515
|
+
log: (m) => process.stderr.write(`telegram gateway: buzz-mirror \u2014 ${m}
|
|
42516
|
+
`)
|
|
42517
|
+
});
|
|
42518
|
+
bm.attachSender(sender);
|
|
42519
|
+
return bm;
|
|
42520
|
+
}
|
|
42521
|
+
|
|
42282
42522
|
// gateway/subagent-reply-authority.ts
|
|
42283
42523
|
var SUB_AGENT_KIND_PREFIX = "sub_agent_";
|
|
42284
42524
|
|
|
@@ -70710,7 +70950,7 @@ class PostHog extends PostHogBackendClient {
|
|
|
70710
70950
|
// analytics-posthog.ts
|
|
70711
70951
|
import { existsSync as existsSync13, mkdirSync as mkdirSync17, readFileSync as readFileSync16, writeFileSync as writeFileSync14 } from "node:fs";
|
|
70712
70952
|
import { dirname as dirname11, join as join21 } from "node:path";
|
|
70713
|
-
import { randomUUID as
|
|
70953
|
+
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
70714
70954
|
var DEFAULT_KEY = "phc_qKY87cKWZm6ZyCtk7LcRd2cU8Sg42u7Ywhui5stYCegd";
|
|
70715
70955
|
var DEFAULT_HOST = "https://us.i.posthog.com";
|
|
70716
70956
|
var client = null;
|
|
@@ -70745,7 +70985,7 @@ function getDistinctId() {
|
|
|
70745
70985
|
}
|
|
70746
70986
|
}
|
|
70747
70987
|
} catch {}
|
|
70748
|
-
const id =
|
|
70988
|
+
const id = randomUUID3();
|
|
70749
70989
|
cachedDistinctId = id;
|
|
70750
70990
|
try {
|
|
70751
70991
|
mkdirSync17(dirname11(fallbackPath), { recursive: true });
|
|
@@ -70826,7 +71066,7 @@ import { dirname as dirname13, join as join23 } from "node:path";
|
|
|
70826
71066
|
// analytics-posthog.ts
|
|
70827
71067
|
import { existsSync as existsSync14, mkdirSync as mkdirSync18, readFileSync as readFileSync17, writeFileSync as writeFileSync15 } from "node:fs";
|
|
70828
71068
|
import { dirname as dirname12, join as join22 } from "node:path";
|
|
70829
|
-
import { randomUUID as
|
|
71069
|
+
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
70830
71070
|
var DEFAULT_KEY2 = "phc_qKY87cKWZm6ZyCtk7LcRd2cU8Sg42u7Ywhui5stYCegd";
|
|
70831
71071
|
var DEFAULT_HOST2 = "https://us.i.posthog.com";
|
|
70832
71072
|
var client2 = null;
|
|
@@ -70860,7 +71100,7 @@ function getDistinctId2() {
|
|
|
70860
71100
|
}
|
|
70861
71101
|
}
|
|
70862
71102
|
} catch {}
|
|
70863
|
-
const id =
|
|
71103
|
+
const id = randomUUID4();
|
|
70864
71104
|
cachedDistinctId2 = id;
|
|
70865
71105
|
try {
|
|
70866
71106
|
mkdirSync18(dirname12(fallbackPath), { recursive: true });
|
|
@@ -71913,6 +72153,8 @@ function detectModelUnavailable(stderr) {
|
|
|
71913
72153
|
"socket hang up",
|
|
71914
72154
|
"request timed out",
|
|
71915
72155
|
"connection refused",
|
|
72156
|
+
"connection closed",
|
|
72157
|
+
"mid-response",
|
|
71916
72158
|
"getaddrinfo"
|
|
71917
72159
|
];
|
|
71918
72160
|
if (networkSignals.some((s) => lower.includes(s))) {
|
|
@@ -72143,6 +72385,7 @@ var OPERATOR_EVENT_KINDS = [
|
|
|
72143
72385
|
"mcp-dependency-blocked",
|
|
72144
72386
|
"quota-exhausted",
|
|
72145
72387
|
"rate-limited",
|
|
72388
|
+
"transport-transient",
|
|
72146
72389
|
"agent-crashed",
|
|
72147
72390
|
"agent-restarted-unexpectedly",
|
|
72148
72391
|
"unknown-4xx",
|
|
@@ -72155,12 +72398,12 @@ function classifyClaudeError(raw) {
|
|
|
72155
72398
|
try {
|
|
72156
72399
|
return classifyInner(raw);
|
|
72157
72400
|
} catch {
|
|
72158
|
-
return "unknown-
|
|
72401
|
+
return "unknown-5xx";
|
|
72159
72402
|
}
|
|
72160
72403
|
}
|
|
72161
72404
|
function classifyInner(raw) {
|
|
72162
72405
|
if (raw == null)
|
|
72163
|
-
return "unknown-
|
|
72406
|
+
return "unknown-5xx";
|
|
72164
72407
|
const obj = typeof raw === "object" ? raw : {};
|
|
72165
72408
|
const errorType = extractString(obj, "error_type") ?? extractString(obj, "type") ?? extractString(getNestedObj(obj, "error"), "type") ?? "";
|
|
72166
72409
|
const errorCode = extractString(obj, "code") ?? extractString(getNestedObj(obj, "error"), "code") ?? "";
|
|
@@ -72205,13 +72448,16 @@ ${message}`;
|
|
|
72205
72448
|
if (errorType === "agent-restarted-unexpectedly" || errorCode === "agent-restarted-unexpectedly") {
|
|
72206
72449
|
return "agent-restarted-unexpectedly";
|
|
72207
72450
|
}
|
|
72451
|
+
if ((status == null || status >= 500) && (errorType === "server_error" || errorCode === "server_error" || sdkCode === "server_error" || errorType === "api_error" || errorCode === "api_error" || sdkCode === "api_error")) {
|
|
72452
|
+
return "transport-transient";
|
|
72453
|
+
}
|
|
72208
72454
|
if (status != null) {
|
|
72209
72455
|
if (status >= 400 && status < 500)
|
|
72210
72456
|
return "unknown-4xx";
|
|
72211
72457
|
if (status >= 500 && status < 600)
|
|
72212
72458
|
return "unknown-5xx";
|
|
72213
72459
|
}
|
|
72214
|
-
return "unknown-
|
|
72460
|
+
return "unknown-5xx";
|
|
72215
72461
|
}
|
|
72216
72462
|
function extractString(obj, key) {
|
|
72217
72463
|
const v = obj[key];
|
|
@@ -73597,7 +73843,7 @@ function defaultAddAccount(label, credentials, opts) {
|
|
|
73597
73843
|
init_protocol();
|
|
73598
73844
|
import * as net3 from "node:net";
|
|
73599
73845
|
import { homedir as homedir7 } from "node:os";
|
|
73600
|
-
import { randomUUID as
|
|
73846
|
+
import { randomUUID as randomUUID5 } from "node:crypto";
|
|
73601
73847
|
import { join as join28 } from "node:path";
|
|
73602
73848
|
var DEFAULT_TIMEOUT_MS3 = 5000;
|
|
73603
73849
|
function reviveDate2(v) {
|
|
@@ -73671,7 +73917,7 @@ class AuthBrokerClient2 {
|
|
|
73671
73917
|
async getCredentials(provider, account) {
|
|
73672
73918
|
const base = {
|
|
73673
73919
|
v: PROTOCOL_VERSION,
|
|
73674
|
-
id:
|
|
73920
|
+
id: randomUUID5(),
|
|
73675
73921
|
op: "get-credentials"
|
|
73676
73922
|
};
|
|
73677
73923
|
let req = base;
|
|
@@ -73685,7 +73931,7 @@ class AuthBrokerClient2 {
|
|
|
73685
73931
|
async listState() {
|
|
73686
73932
|
const data = await this.send({
|
|
73687
73933
|
v: PROTOCOL_VERSION,
|
|
73688
|
-
id:
|
|
73934
|
+
id: randomUUID5(),
|
|
73689
73935
|
op: "list-state"
|
|
73690
73936
|
});
|
|
73691
73937
|
return data;
|
|
@@ -73693,7 +73939,7 @@ class AuthBrokerClient2 {
|
|
|
73693
73939
|
async listGoogleAccounts() {
|
|
73694
73940
|
const data = await this.send({
|
|
73695
73941
|
v: PROTOCOL_VERSION,
|
|
73696
|
-
id:
|
|
73942
|
+
id: randomUUID5(),
|
|
73697
73943
|
op: "list-google-accounts"
|
|
73698
73944
|
});
|
|
73699
73945
|
return data;
|
|
@@ -73701,7 +73947,7 @@ class AuthBrokerClient2 {
|
|
|
73701
73947
|
async listMicrosoftAccounts() {
|
|
73702
73948
|
const data = await this.send({
|
|
73703
73949
|
v: PROTOCOL_VERSION,
|
|
73704
|
-
id:
|
|
73950
|
+
id: randomUUID5(),
|
|
73705
73951
|
op: "list-microsoft-accounts"
|
|
73706
73952
|
});
|
|
73707
73953
|
return data;
|
|
@@ -73709,7 +73955,7 @@ class AuthBrokerClient2 {
|
|
|
73709
73955
|
async probeQuota(accounts, timeoutMs, forceLive) {
|
|
73710
73956
|
const data = await this.send({
|
|
73711
73957
|
v: PROTOCOL_VERSION,
|
|
73712
|
-
id:
|
|
73958
|
+
id: randomUUID5(),
|
|
73713
73959
|
op: "probe-quota",
|
|
73714
73960
|
accounts: [...accounts],
|
|
73715
73961
|
...timeoutMs !== undefined ? { timeoutMs } : {},
|
|
@@ -73727,7 +73973,7 @@ class AuthBrokerClient2 {
|
|
|
73727
73973
|
async getExternalSpend(forceLive) {
|
|
73728
73974
|
const data = await this.send({
|
|
73729
73975
|
v: PROTOCOL_VERSION,
|
|
73730
|
-
id:
|
|
73976
|
+
id: randomUUID5(),
|
|
73731
73977
|
op: "get-external-spend",
|
|
73732
73978
|
...forceLive ? { forceLive: true } : {}
|
|
73733
73979
|
});
|
|
@@ -73736,21 +73982,21 @@ class AuthBrokerClient2 {
|
|
|
73736
73982
|
async setActive(account) {
|
|
73737
73983
|
const data = await this.send({
|
|
73738
73984
|
v: PROTOCOL_VERSION,
|
|
73739
|
-
id:
|
|
73985
|
+
id: randomUUID5(),
|
|
73740
73986
|
op: "set-active",
|
|
73741
73987
|
account
|
|
73742
73988
|
});
|
|
73743
73989
|
return data;
|
|
73744
73990
|
}
|
|
73745
73991
|
async markExhausted(until) {
|
|
73746
|
-
const req = until !== undefined ? { v: PROTOCOL_VERSION, id:
|
|
73992
|
+
const req = until !== undefined ? { v: PROTOCOL_VERSION, id: randomUUID5(), op: "mark-exhausted", until } : { v: PROTOCOL_VERSION, id: randomUUID5(), op: "mark-exhausted" };
|
|
73747
73993
|
const data = await this.send(req);
|
|
73748
73994
|
return data;
|
|
73749
73995
|
}
|
|
73750
73996
|
async markThrottled(until) {
|
|
73751
73997
|
const data = await this.send({
|
|
73752
73998
|
v: PROTOCOL_VERSION,
|
|
73753
|
-
id:
|
|
73999
|
+
id: randomUUID5(),
|
|
73754
74000
|
op: "mark-throttled",
|
|
73755
74001
|
until
|
|
73756
74002
|
});
|
|
@@ -73759,7 +74005,7 @@ class AuthBrokerClient2 {
|
|
|
73759
74005
|
async claimNotification(key, windowMs) {
|
|
73760
74006
|
const data = await this.send({
|
|
73761
74007
|
v: PROTOCOL_VERSION,
|
|
73762
|
-
id:
|
|
74008
|
+
id: randomUUID5(),
|
|
73763
74009
|
op: "claim-notification",
|
|
73764
74010
|
key,
|
|
73765
74011
|
windowMs
|
|
@@ -73769,7 +74015,7 @@ class AuthBrokerClient2 {
|
|
|
73769
74015
|
async refreshAccount(account) {
|
|
73770
74016
|
const data = await this.send({
|
|
73771
74017
|
v: PROTOCOL_VERSION,
|
|
73772
|
-
id:
|
|
74018
|
+
id: randomUUID5(),
|
|
73773
74019
|
op: "refresh-account",
|
|
73774
74020
|
account
|
|
73775
74021
|
});
|
|
@@ -73778,7 +74024,7 @@ class AuthBrokerClient2 {
|
|
|
73778
74024
|
async addAccount(label, credentials, replace2, provider) {
|
|
73779
74025
|
const base = {
|
|
73780
74026
|
v: PROTOCOL_VERSION,
|
|
73781
|
-
id:
|
|
74027
|
+
id: randomUUID5(),
|
|
73782
74028
|
op: "add-account",
|
|
73783
74029
|
label,
|
|
73784
74030
|
credentials
|
|
@@ -73791,7 +74037,7 @@ class AuthBrokerClient2 {
|
|
|
73791
74037
|
async rmAccount(label, provider) {
|
|
73792
74038
|
const base = {
|
|
73793
74039
|
v: PROTOCOL_VERSION,
|
|
73794
|
-
id:
|
|
74040
|
+
id: randomUUID5(),
|
|
73795
74041
|
op: "rm-account",
|
|
73796
74042
|
label
|
|
73797
74043
|
};
|
|
@@ -73802,7 +74048,7 @@ class AuthBrokerClient2 {
|
|
|
73802
74048
|
async setOverride(agent, account) {
|
|
73803
74049
|
const data = await this.send({
|
|
73804
74050
|
v: PROTOCOL_VERSION,
|
|
73805
|
-
id:
|
|
74051
|
+
id: randomUUID5(),
|
|
73806
74052
|
op: "set-override",
|
|
73807
74053
|
agent,
|
|
73808
74054
|
account
|
|
@@ -75361,10 +75607,21 @@ function renderOperatorEvent(ev) {
|
|
|
75361
75607
|
`),
|
|
75362
75608
|
keyboard: {
|
|
75363
75609
|
inline_keyboard: [
|
|
75364
|
-
[
|
|
75365
|
-
|
|
75366
|
-
|
|
75367
|
-
|
|
75610
|
+
[{ text: "\u274c Dismiss", callback_data: `op:dismiss:${encodeURIComponent(ev.agent)}` }]
|
|
75611
|
+
]
|
|
75612
|
+
}
|
|
75613
|
+
};
|
|
75614
|
+
case "transport-transient":
|
|
75615
|
+
return {
|
|
75616
|
+
text: [
|
|
75617
|
+
`\uD83D\uDD0C **Transient transport error** for **${agent}**.`,
|
|
75618
|
+
detail ? `\`${detail}\`` : "",
|
|
75619
|
+
`A mid-response stream to Anthropic dropped. Will retry automatically.`
|
|
75620
|
+
].filter(Boolean).join(`
|
|
75621
|
+
`),
|
|
75622
|
+
keyboard: {
|
|
75623
|
+
inline_keyboard: [
|
|
75624
|
+
[{ text: "\u274c Dismiss", callback_data: `op:dismiss:${encodeURIComponent(ev.agent)}` }]
|
|
75368
75625
|
]
|
|
75369
75626
|
}
|
|
75370
75627
|
};
|
|
@@ -75762,6 +76019,69 @@ function recordOperatorEvent(event, now = Date.now()) {
|
|
|
75762
76019
|
store2.set(event.agent, { event, storedAt: now });
|
|
75763
76020
|
}
|
|
75764
76021
|
|
|
76022
|
+
// gateway/user-failure-notices.ts
|
|
76023
|
+
init_format();
|
|
76024
|
+
var ESCALATION_WINDOW_MS = 10 * 60000;
|
|
76025
|
+
var ESCALATION_THRESHOLD = 3;
|
|
76026
|
+
var transportEscalation = new Map;
|
|
76027
|
+
function noteTransportTransientAndShouldEscalate(agent, now, opts) {
|
|
76028
|
+
const windowMs = opts?.windowMs ?? ESCALATION_WINDOW_MS;
|
|
76029
|
+
const threshold = opts?.threshold ?? ESCALATION_THRESHOLD;
|
|
76030
|
+
const recent = (transportEscalation.get(agent) ?? []).filter((t) => now - t < windowMs);
|
|
76031
|
+
recent.push(now);
|
|
76032
|
+
if (recent.length >= threshold) {
|
|
76033
|
+
transportEscalation.set(agent, []);
|
|
76034
|
+
return true;
|
|
76035
|
+
}
|
|
76036
|
+
transportEscalation.set(agent, recent);
|
|
76037
|
+
return false;
|
|
76038
|
+
}
|
|
76039
|
+
function renderTransportEscalationCard(agent) {
|
|
76040
|
+
const a = escapeMarkdown(agent);
|
|
76041
|
+
return {
|
|
76042
|
+
text: [
|
|
76043
|
+
`\uD83D\uDD0C **Repeated stream failures** reaching Anthropic for **${a}**.`,
|
|
76044
|
+
`3+ mid-response aborts within ~10 min. Turns retry automatically; if this persists, Anthropic's API may be degraded.`
|
|
76045
|
+
].join(`
|
|
76046
|
+
`),
|
|
76047
|
+
keyboard: {
|
|
76048
|
+
inline_keyboard: [
|
|
76049
|
+
[{ text: "\u274c Dismiss", callback_data: `op:dismiss:${encodeURIComponent(agent)}` }]
|
|
76050
|
+
]
|
|
76051
|
+
}
|
|
76052
|
+
};
|
|
76053
|
+
}
|
|
76054
|
+
function emitTransportTransientEvent(event, deps) {
|
|
76055
|
+
const now = deps.now();
|
|
76056
|
+
deps.record(event);
|
|
76057
|
+
const escalate = noteTransportTransientAndShouldEscalate(event.agent, now);
|
|
76058
|
+
deps.log(`transport-transient agent=${event.agent} escalate=${escalate} ` + `(no broadcast card; user-notice deferred to turn-end)`);
|
|
76059
|
+
const allowFrom = deps.allowFrom();
|
|
76060
|
+
if (allowFrom.length === 0)
|
|
76061
|
+
return;
|
|
76062
|
+
deps.scheduleUserNotice({
|
|
76063
|
+
chatIds: [...allowFrom],
|
|
76064
|
+
agent: event.agent,
|
|
76065
|
+
kind: event.kind,
|
|
76066
|
+
key: deps.liveTurnKey(),
|
|
76067
|
+
atMs: now
|
|
76068
|
+
});
|
|
76069
|
+
if (escalate) {
|
|
76070
|
+
const card = renderTransportEscalationCard(event.agent);
|
|
76071
|
+
deps.send(allowFrom[0], card.text, card.keyboard);
|
|
76072
|
+
}
|
|
76073
|
+
}
|
|
76074
|
+
function flushDeferredUserNotices(turnDeliveredReply, turnKey3, deps) {
|
|
76075
|
+
const notices = deps.resolveNotices(turnDeliveredReply, turnKey3);
|
|
76076
|
+
if (notices.length === 0)
|
|
76077
|
+
return;
|
|
76078
|
+
for (const notice of notices) {
|
|
76079
|
+
deps.log(`user-notice flush (turn died reply-less) agent=${notice.agent} ` + `kind=${notice.kind} chats=${notice.chatIds.length}`);
|
|
76080
|
+
for (const chatId of notice.chatIds)
|
|
76081
|
+
deps.send(chatId, notice.text);
|
|
76082
|
+
}
|
|
76083
|
+
}
|
|
76084
|
+
|
|
75765
76085
|
// throttle-tier.ts
|
|
75766
76086
|
init_card_format();
|
|
75767
76087
|
init_quota_check();
|
|
@@ -75906,9 +76226,6 @@ function classifyKindAndSource(text4) {
|
|
|
75906
76226
|
if (claudeKind === "rate-limited") {
|
|
75907
76227
|
return { kind: "rate_limit", source: "anthropic" };
|
|
75908
76228
|
}
|
|
75909
|
-
if (claudeKind === "unknown-5xx") {
|
|
75910
|
-
return { kind: "overload_529", source: "anthropic" };
|
|
75911
|
-
}
|
|
75912
76229
|
return { kind: "unknown", source: "anthropic" };
|
|
75913
76230
|
}
|
|
75914
76231
|
function providerById(id) {
|
|
@@ -76181,6 +76498,8 @@ function detectModelUnavailable2(stderr) {
|
|
|
76181
76498
|
"socket hang up",
|
|
76182
76499
|
"request timed out",
|
|
76183
76500
|
"connection refused",
|
|
76501
|
+
"connection closed",
|
|
76502
|
+
"mid-response",
|
|
76184
76503
|
"getaddrinfo"
|
|
76185
76504
|
];
|
|
76186
76505
|
if (networkSignals.some((s) => lower.includes(s))) {
|
|
@@ -78298,6 +78617,146 @@ function resolveChatIdFallback(rawChatId, access, turnSessionChatId, lastKnownCh
|
|
|
78298
78617
|
}
|
|
78299
78618
|
return { chatId: rawChatId, tier: "raw" };
|
|
78300
78619
|
}
|
|
78620
|
+
|
|
78621
|
+
// gateway/buzz-mirror.ts
|
|
78622
|
+
import { randomUUID as randomUUID6 } from "crypto";
|
|
78623
|
+
var CORRECTION_DEBOUNCE_MS2 = 30000;
|
|
78624
|
+
var MAX_TRACKED2 = 4096;
|
|
78625
|
+
|
|
78626
|
+
class BuzzMirror2 {
|
|
78627
|
+
cfg;
|
|
78628
|
+
log;
|
|
78629
|
+
sender = null;
|
|
78630
|
+
pending = new Map;
|
|
78631
|
+
pendingOrder = [];
|
|
78632
|
+
msgToBuzz = new Map;
|
|
78633
|
+
msgOrder = [];
|
|
78634
|
+
correctionTimers = new Map;
|
|
78635
|
+
constructor(cfg) {
|
|
78636
|
+
this.cfg = cfg;
|
|
78637
|
+
this.log = cfg.log ?? (() => {});
|
|
78638
|
+
}
|
|
78639
|
+
attachSender(sender) {
|
|
78640
|
+
this.sender = sender;
|
|
78641
|
+
}
|
|
78642
|
+
evict(map, order) {
|
|
78643
|
+
while (order.length > MAX_TRACKED2) {
|
|
78644
|
+
const k = order.shift();
|
|
78645
|
+
if (k !== undefined)
|
|
78646
|
+
map.delete(k);
|
|
78647
|
+
}
|
|
78648
|
+
}
|
|
78649
|
+
mirrorReplyDelivered(input) {
|
|
78650
|
+
try {
|
|
78651
|
+
const route = resolveRoute(input.ownerOriginChannel, this.cfg.mode, true);
|
|
78652
|
+
const buzzInRoute = route.primary === "buzz" || route.mirrors.includes("buzz");
|
|
78653
|
+
if (!buzzInRoute)
|
|
78654
|
+
return;
|
|
78655
|
+
let channelId;
|
|
78656
|
+
let replyToEventId;
|
|
78657
|
+
let threadRootId;
|
|
78658
|
+
if (input.ownerOriginChannel === "buzz" && input.ownerBuzzCoords) {
|
|
78659
|
+
if (!isBuzzThreadedPublishSafe({
|
|
78660
|
+
ownerEchoed: input.ownerEchoed,
|
|
78661
|
+
hasRecentDifferentOriginTurn: input.hasRecentDifferentOriginTurn
|
|
78662
|
+
})) {
|
|
78663
|
+
this.log("buzz-mirror: S1 guard blocked a threaded publish on an ambiguous " + "owner binding (un-echoed reply + a recent different-origin turn) " + "\u2014 delivered Telegram-only");
|
|
78664
|
+
return;
|
|
78665
|
+
}
|
|
78666
|
+
channelId = input.ownerBuzzCoords.channelId;
|
|
78667
|
+
replyToEventId = input.ownerBuzzCoords.eventId;
|
|
78668
|
+
threadRootId = input.ownerBuzzCoords.threadRoot;
|
|
78669
|
+
} else {
|
|
78670
|
+
if (!this.cfg.defaultChannelId)
|
|
78671
|
+
return;
|
|
78672
|
+
channelId = this.cfg.defaultChannelId;
|
|
78673
|
+
}
|
|
78674
|
+
this.publish({
|
|
78675
|
+
channelId,
|
|
78676
|
+
replyToEventId,
|
|
78677
|
+
threadRootId,
|
|
78678
|
+
payload: { kind: "message", text: input.scrubbedText }
|
|
78679
|
+
}, input.telegramMessageKeys);
|
|
78680
|
+
} catch (err) {
|
|
78681
|
+
this.log(`buzz-mirror: mirrorReplyDelivered threw (ignored): ${String(err)}`);
|
|
78682
|
+
}
|
|
78683
|
+
}
|
|
78684
|
+
mirrorCorrection(input) {
|
|
78685
|
+
try {
|
|
78686
|
+
const target = this.msgToBuzz.get(input.telegramMessageKey);
|
|
78687
|
+
if (!target)
|
|
78688
|
+
return;
|
|
78689
|
+
const existing = this.correctionTimers.get(input.telegramMessageKey);
|
|
78690
|
+
if (existing)
|
|
78691
|
+
clearTimeout(existing);
|
|
78692
|
+
const timer3 = setTimeout(() => {
|
|
78693
|
+
this.correctionTimers.delete(input.telegramMessageKey);
|
|
78694
|
+
const t = this.msgToBuzz.get(input.telegramMessageKey);
|
|
78695
|
+
if (!t)
|
|
78696
|
+
return;
|
|
78697
|
+
this.publish({
|
|
78698
|
+
channelId: t.channelId,
|
|
78699
|
+
replyToEventId: t.eventId,
|
|
78700
|
+
threadRootId: t.eventId,
|
|
78701
|
+
payload: {
|
|
78702
|
+
kind: "correction",
|
|
78703
|
+
text: input.scrubbedText,
|
|
78704
|
+
targetEventId: t.eventId
|
|
78705
|
+
}
|
|
78706
|
+
}, []);
|
|
78707
|
+
}, CORRECTION_DEBOUNCE_MS2);
|
|
78708
|
+
if (typeof timer3.unref === "function") {
|
|
78709
|
+
timer3.unref();
|
|
78710
|
+
}
|
|
78711
|
+
this.correctionTimers.set(input.telegramMessageKey, timer3);
|
|
78712
|
+
} catch (err) {
|
|
78713
|
+
this.log(`buzz-mirror: mirrorCorrection threw (ignored): ${String(err)}`);
|
|
78714
|
+
}
|
|
78715
|
+
}
|
|
78716
|
+
onPublishResult(msg) {
|
|
78717
|
+
const p = this.pending.get(msg.correlationId);
|
|
78718
|
+
this.pending.delete(msg.correlationId);
|
|
78719
|
+
if (!p)
|
|
78720
|
+
return;
|
|
78721
|
+
if (!msg.ok || !msg.eventId) {
|
|
78722
|
+
this.log(`buzz-mirror: publish failed (correlationId=${msg.correlationId.slice(0, 8)}` + `${msg.error ? ` error=${msg.error}` : ""}) \u2014 Telegram copy already delivered`);
|
|
78723
|
+
return;
|
|
78724
|
+
}
|
|
78725
|
+
for (const key of p.telegramMessageKeys) {
|
|
78726
|
+
this.msgToBuzz.set(key, { eventId: msg.eventId, channelId: p.channelId });
|
|
78727
|
+
this.msgOrder.push(key);
|
|
78728
|
+
}
|
|
78729
|
+
this.evict(this.msgToBuzz, this.msgOrder);
|
|
78730
|
+
}
|
|
78731
|
+
publish(fields, telegramMessageKeys) {
|
|
78732
|
+
if (!this.sender) {
|
|
78733
|
+
this.log("buzz-mirror: no Buzz peer connected \u2014 mirror dropped (Telegram copy delivered)");
|
|
78734
|
+
return;
|
|
78735
|
+
}
|
|
78736
|
+
const correlationId = randomUUID6();
|
|
78737
|
+
const msg = {
|
|
78738
|
+
type: "outbound_to_buzz",
|
|
78739
|
+
correlationId,
|
|
78740
|
+
agentName: this.cfg.agentName,
|
|
78741
|
+
...fields
|
|
78742
|
+
};
|
|
78743
|
+
const sent = this.sender(msg);
|
|
78744
|
+
if (!sent) {
|
|
78745
|
+
this.log("buzz-mirror: Buzz peer send returned false \u2014 mirror dropped (Telegram copy delivered)");
|
|
78746
|
+
return;
|
|
78747
|
+
}
|
|
78748
|
+
this.pending.set(correlationId, {
|
|
78749
|
+
channelId: fields.channelId,
|
|
78750
|
+
telegramMessageKeys
|
|
78751
|
+
});
|
|
78752
|
+
this.pendingOrder.push(correlationId);
|
|
78753
|
+
this.evict(this.pending, this.pendingOrder);
|
|
78754
|
+
}
|
|
78755
|
+
}
|
|
78756
|
+
var singleton2 = null;
|
|
78757
|
+
function getBuzzMirror2() {
|
|
78758
|
+
return singleton2;
|
|
78759
|
+
}
|
|
78301
78760
|
// over-ping-safety-net.ts
|
|
78302
78761
|
function decideOverPing(input) {
|
|
78303
78762
|
const substantive = input.substantive === true;
|
|
@@ -78393,7 +78852,9 @@ var INBOUND_SOURCE_CLASSIFICATION = {
|
|
|
78393
78852
|
mental_model_proposal_denied: { decoupledCompletion: false },
|
|
78394
78853
|
mental_model_proposal_failed: { decoupledCompletion: false },
|
|
78395
78854
|
webhook: { decoupledCompletion: false },
|
|
78396
|
-
linear: { decoupledCompletion: false }
|
|
78855
|
+
linear: { decoupledCompletion: false },
|
|
78856
|
+
buzz: { decoupledCompletion: false },
|
|
78857
|
+
boot_briefing: { decoupledCompletion: false }
|
|
78397
78858
|
};
|
|
78398
78859
|
function stampsHandbackMarker(source) {
|
|
78399
78860
|
if (source == null)
|
|
@@ -79003,6 +79464,7 @@ async function sendReply(deps, req) {
|
|
|
79003
79464
|
resolveReplyOwnerTurn,
|
|
79004
79465
|
findTurnByOriginId,
|
|
79005
79466
|
findTurnByQuotedMessageId,
|
|
79467
|
+
findLatestTurnForChat,
|
|
79006
79468
|
resolveAnswerThreadWithLog,
|
|
79007
79469
|
resolveThreadId,
|
|
79008
79470
|
getLatestInboundMessageId: getLatestInboundMessageId2,
|
|
@@ -79736,6 +80198,23 @@ ${url}`;
|
|
|
79736
80198
|
if (shouldJournalReplySiteDelivery({ text: rawText, disableNotification: modelDisableNotification })) {
|
|
79737
80199
|
journalExternalDelivery({ turnNonce: t?.turnId ?? null, text: text4, tgMessageId: sentIds[sentIds.length - 1], replyAlreadyDeliveredThisTurn: true });
|
|
79738
80200
|
}
|
|
80201
|
+
const buzzMirror = getBuzzMirror2();
|
|
80202
|
+
if (buzzMirror !== null) {
|
|
80203
|
+
const { turn: mOwnerTurn, tier: mOwnerTier } = resolveReplyOwnerTurn(turn, chat_id, args);
|
|
80204
|
+
const ownerOrigin = mOwnerTurn?.originChannel ?? "telegram";
|
|
80205
|
+
const ownerTurnId = mOwnerTurn?.turnId ?? null;
|
|
80206
|
+
const ownerEchoed = mOwnerTier === "origin";
|
|
80207
|
+
const latestEnded = findLatestTurnForChat(chat_id, { endedOnly: true });
|
|
80208
|
+
const hasRecentDifferentOriginTurn = [turn, latestEnded].some((c) => c != null && c.turnId !== ownerTurnId && c.originChannel !== ownerOrigin);
|
|
80209
|
+
buzzMirror.mirrorReplyDelivered({
|
|
80210
|
+
scrubbedText: text4,
|
|
80211
|
+
ownerOriginChannel: ownerOrigin,
|
|
80212
|
+
ownerBuzzCoords: mOwnerTurn?.buzzCoords,
|
|
80213
|
+
ownerEchoed,
|
|
80214
|
+
hasRecentDifferentOriginTurn,
|
|
80215
|
+
telegramMessageKeys: sentIds.map((id) => `${chat_id}:${id}`)
|
|
80216
|
+
});
|
|
80217
|
+
}
|
|
79739
80218
|
}
|
|
79740
80219
|
return { content: [{ type: "text", text: result }] };
|
|
79741
80220
|
}
|
|
@@ -81127,6 +81606,8 @@ var QUEUED_CARD_ENABLED = process.env.SWITCHROOM_QUEUED_CARD !== "0";
|
|
|
81127
81606
|
var QUEUED_CARD_HTML = "\u23f3 Queued \u2014 waiting for the current task to finish\u2026";
|
|
81128
81607
|
var QUEUED_CARD_FOLDED_HTML = "\u2705 Folded into the current task.";
|
|
81129
81608
|
var QUEUED_CARD_EXPIRED_HTML = "\u26a0\ufe0f This queued message timed out before it could start.";
|
|
81609
|
+
var BUZZ_ENABLED = process.env.BUZZ_ENABLED === "1" || process.env.BUZZ_ENABLED === "true";
|
|
81610
|
+
var BUZZ_ORIGIN_STAMP_ACTIVE = BUZZ_ENABLED && isBuzzTurnRoutingEnabled();
|
|
81130
81611
|
var parkedTurnStarts = [];
|
|
81131
81612
|
function pruneParkedTurnStarts(now, onDrop) {
|
|
81132
81613
|
for (let i = parkedTurnStarts.length - 1;i >= 0; i--) {
|
|
@@ -81295,6 +81776,7 @@ function beginTurn(deps, ev) {
|
|
|
81295
81776
|
startedAt,
|
|
81296
81777
|
gatewayReceiveAt: startedAt,
|
|
81297
81778
|
role: deriveTurnRole(ev.rawContent),
|
|
81779
|
+
...BUZZ_ORIGIN_STAMP_ACTIVE ? parseChannelOrigin(ev.rawContent) : { originChannel: "telegram" },
|
|
81298
81780
|
...consumedCrossTurnGate != null ? { crossTurnGate: consumedCrossTurnGate } : {},
|
|
81299
81781
|
replyCalled: false,
|
|
81300
81782
|
finalAnswerDelivered: false,
|
|
@@ -90529,6 +91011,20 @@ function validateClientMessage(msg) {
|
|
|
90529
91011
|
return false;
|
|
90530
91012
|
return true;
|
|
90531
91013
|
}
|
|
91014
|
+
case "hello_buzz_peer": {
|
|
91015
|
+
return typeof m.agentName === "string" && AGENT_NAME_RE3.test(m.agentName);
|
|
91016
|
+
}
|
|
91017
|
+
case "buzz_publish_result": {
|
|
91018
|
+
if (typeof m.correlationId !== "string" || m.correlationId.length === 0 || m.correlationId.length > 64)
|
|
91019
|
+
return false;
|
|
91020
|
+
if (typeof m.ok !== "boolean")
|
|
91021
|
+
return false;
|
|
91022
|
+
if (m.eventId !== undefined && (typeof m.eventId !== "string" || m.eventId.length > 128))
|
|
91023
|
+
return false;
|
|
91024
|
+
if (m.error !== undefined && (typeof m.error !== "string" || m.error.length > 500))
|
|
91025
|
+
return false;
|
|
91026
|
+
return true;
|
|
91027
|
+
}
|
|
90532
91028
|
default:
|
|
90533
91029
|
return false;
|
|
90534
91030
|
}
|
|
@@ -90557,9 +91053,26 @@ function createIpcServer(options) {
|
|
|
90557
91053
|
onRequestConfigFinalize,
|
|
90558
91054
|
onRolloutStatusPost,
|
|
90559
91055
|
onRolloutStatusEdit,
|
|
91056
|
+
onBuzzPublishResult,
|
|
90560
91057
|
log = () => {},
|
|
90561
91058
|
heartbeatTimeoutMs = 30000
|
|
90562
91059
|
} = options;
|
|
91060
|
+
let buzzPeerClient = null;
|
|
91061
|
+
const BUZZ_INJECT_RING_MAX = 1024;
|
|
91062
|
+
const buzzInjectSeen = new Set;
|
|
91063
|
+
const buzzInjectOrder = [];
|
|
91064
|
+
const buzzInjectIsDuplicate = (eventId) => {
|
|
91065
|
+
if (buzzInjectSeen.has(eventId))
|
|
91066
|
+
return true;
|
|
91067
|
+
buzzInjectSeen.add(eventId);
|
|
91068
|
+
buzzInjectOrder.push(eventId);
|
|
91069
|
+
if (buzzInjectOrder.length > BUZZ_INJECT_RING_MAX) {
|
|
91070
|
+
const evicted = buzzInjectOrder.shift();
|
|
91071
|
+
if (evicted !== undefined)
|
|
91072
|
+
buzzInjectSeen.delete(evicted);
|
|
91073
|
+
}
|
|
91074
|
+
return false;
|
|
91075
|
+
};
|
|
90563
91076
|
try {
|
|
90564
91077
|
renameSync17(socketPath, socketPath + ".bak");
|
|
90565
91078
|
} catch {}
|
|
@@ -90578,6 +91091,8 @@ function createIpcServer(options) {
|
|
|
90578
91091
|
if (client3.topicId != null && topicIndex.get(client3.topicId) === client3) {
|
|
90579
91092
|
topicIndex.delete(client3.topicId);
|
|
90580
91093
|
}
|
|
91094
|
+
if (buzzPeerClient === client3)
|
|
91095
|
+
buzzPeerClient = null;
|
|
90581
91096
|
loggedLegacyUpdatePlaceholder.delete(client3.id);
|
|
90582
91097
|
onClientDisconnected(client3);
|
|
90583
91098
|
log(`client disconnected: ${client3.id} (agent=${client3.agentName})`);
|
|
@@ -90633,10 +91148,19 @@ function createIpcServer(options) {
|
|
|
90633
91148
|
if (onPtyPartial)
|
|
90634
91149
|
onPtyPartial(client3, msg);
|
|
90635
91150
|
break;
|
|
90636
|
-
case "inject_inbound":
|
|
91151
|
+
case "inject_inbound": {
|
|
91152
|
+
const injectMsg = msg;
|
|
91153
|
+
const injMeta = injectMsg.inbound?.meta;
|
|
91154
|
+
if (injMeta && injMeta.source === "buzz" && typeof injMeta.buzz_event_id === "string") {
|
|
91155
|
+
if (buzzInjectIsDuplicate(injMeta.buzz_event_id)) {
|
|
91156
|
+
log(`inject_inbound: dropped duplicate buzz event ${injMeta.buzz_event_id.slice(0, 12)} (hub dedup ring)`);
|
|
91157
|
+
break;
|
|
91158
|
+
}
|
|
91159
|
+
}
|
|
90637
91160
|
if (onInjectInbound)
|
|
90638
|
-
onInjectInbound(client3,
|
|
91161
|
+
onInjectInbound(client3, injectMsg);
|
|
90639
91162
|
break;
|
|
91163
|
+
}
|
|
90640
91164
|
case "send_outbound":
|
|
90641
91165
|
if (onSendOutbound)
|
|
90642
91166
|
onSendOutbound(client3, msg);
|
|
@@ -90780,6 +91304,17 @@ function createIpcServer(options) {
|
|
|
90780
91304
|
}
|
|
90781
91305
|
}
|
|
90782
91306
|
break;
|
|
91307
|
+
case "hello_buzz_peer":
|
|
91308
|
+
handleHelloBuzzPeer(client3, msg);
|
|
91309
|
+
break;
|
|
91310
|
+
case "buzz_publish_result":
|
|
91311
|
+
if (!client3.isBuzzPeer) {
|
|
91312
|
+
log(`SECURITY: rejecting buzz_publish_result from non-peer connection ` + `(agent=${client3.agentName ?? "anonymous"} id=${client3.id}) \u2014 only the ` + `registered Buzz publish peer may report publish outcomes; dropped`);
|
|
91313
|
+
break;
|
|
91314
|
+
}
|
|
91315
|
+
if (onBuzzPublishResult)
|
|
91316
|
+
onBuzzPublishResult(client3, msg);
|
|
91317
|
+
break;
|
|
90783
91318
|
case "update_placeholder":
|
|
90784
91319
|
if (!loggedLegacyUpdatePlaceholder.has(client3.id)) {
|
|
90785
91320
|
loggedLegacyUpdatePlaceholder.add(client3.id);
|
|
@@ -90790,7 +91325,39 @@ function createIpcServer(options) {
|
|
|
90790
91325
|
log(`unknown IPC message type from client ${client3.id}: ${msg.type}`);
|
|
90791
91326
|
}
|
|
90792
91327
|
}
|
|
91328
|
+
function handleHelloBuzzPeer(client3, msg) {
|
|
91329
|
+
if (client3.agentName !== null || client3.isBuzzPeer) {
|
|
91330
|
+
log(`rejecting hello_buzz_peer: connection already has a role ` + `(agent=${client3.agentName ?? "none"} isBuzzPeer=${client3.isBuzzPeer}) \u2014 close+drop client=${client3.id}`);
|
|
91331
|
+
try {
|
|
91332
|
+
client3.close();
|
|
91333
|
+
} catch {}
|
|
91334
|
+
return;
|
|
91335
|
+
}
|
|
91336
|
+
if (buzzPeerClient && buzzPeerClient !== client3 && buzzPeerClient.isAlive()) {
|
|
91337
|
+
log(`SECURITY: rejecting hello_buzz_peer \u2014 a LIVE Buzz peer is already ` + `connected (live_id=${buzzPeerClient.id} rejected_id=${client3.id}); ` + `refusing displacement, close+drop`);
|
|
91338
|
+
try {
|
|
91339
|
+
client3.close();
|
|
91340
|
+
} catch {}
|
|
91341
|
+
return;
|
|
91342
|
+
}
|
|
91343
|
+
if (buzzPeerClient && buzzPeerClient !== client3) {
|
|
91344
|
+
log(`hello_buzz_peer: replacing prior (dead) buzz peer (prior_id=${buzzPeerClient.id} new_id=${client3.id})`);
|
|
91345
|
+
try {
|
|
91346
|
+
buzzPeerClient.close();
|
|
91347
|
+
} catch {}
|
|
91348
|
+
}
|
|
91349
|
+
client3.isBuzzPeer = true;
|
|
91350
|
+
buzzPeerClient = client3;
|
|
91351
|
+
log(`registered buzz publish peer for agent=${msg.agentName} id=${client3.id}`);
|
|
91352
|
+
}
|
|
90793
91353
|
function handleRegister(client3, msg) {
|
|
91354
|
+
if (client3.isBuzzPeer) {
|
|
91355
|
+
log(`rejecting register: connection is the Buzz publish peer, not an agent bridge ` + `(close+drop client=${client3.id})`);
|
|
91356
|
+
try {
|
|
91357
|
+
client3.close();
|
|
91358
|
+
} catch {}
|
|
91359
|
+
return;
|
|
91360
|
+
}
|
|
90794
91361
|
if (msg.agentName === "default") {
|
|
90795
91362
|
log(`rejecting register: agentName="default" \u2014 anonymous bridges are not allowed (close+drop client=${client3.id})`);
|
|
90796
91363
|
try {
|
|
@@ -90830,6 +91397,7 @@ function createIpcServer(options) {
|
|
|
90830
91397
|
id;
|
|
90831
91398
|
agentName = null;
|
|
90832
91399
|
topicId = null;
|
|
91400
|
+
isBuzzPeer = false;
|
|
90833
91401
|
lastHeartbeat = Date.now();
|
|
90834
91402
|
_socket;
|
|
90835
91403
|
_closed = false;
|
|
@@ -90939,6 +91507,12 @@ function createIpcServer(options) {
|
|
|
90939
91507
|
clientCount() {
|
|
90940
91508
|
return clients.size;
|
|
90941
91509
|
},
|
|
91510
|
+
sendToBuzzPeer(msg) {
|
|
91511
|
+
if (!buzzPeerClient || !buzzPeerClient.isAlive())
|
|
91512
|
+
return false;
|
|
91513
|
+
buzzPeerClient.send(msg);
|
|
91514
|
+
return true;
|
|
91515
|
+
},
|
|
90942
91516
|
async close() {
|
|
90943
91517
|
if (watchdogTimer !== null) {
|
|
90944
91518
|
clearInterval(watchdogTimer);
|
|
@@ -92400,6 +92974,9 @@ function spoolId(msg) {
|
|
|
92400
92974
|
if ((msg.meta?.source === "resume_interrupted" || msg.meta?.source === "resume_watchdog_timeout" || msg.meta?.source === "resume_deferred") && typeof msg.meta?.resume_turn_key === "string" && msg.meta.resume_turn_key.length > 0) {
|
|
92401
92975
|
return `s:resume:${msg.meta.resume_turn_key}`;
|
|
92402
92976
|
}
|
|
92977
|
+
if (msg.meta?.source === "boot_briefing") {
|
|
92978
|
+
return `s:boot-briefing:${msg.chatId}`;
|
|
92979
|
+
}
|
|
92403
92980
|
if (msg.meta?.source === "cron" && typeof msg.meta?.replay_fire_ms === "string" && msg.meta.replay_fire_ms.length > 0) {
|
|
92404
92981
|
const idx = typeof msg.meta?.schedule_index === "string" && msg.meta.schedule_index.length > 0 ? msg.meta.schedule_index : "-";
|
|
92405
92982
|
return `s:cron-replay:${msg.chatId}:${idx}:${msg.meta.replay_fire_ms}`;
|
|
@@ -92572,8 +93149,17 @@ function createInboundSpool(opts) {
|
|
|
92572
93149
|
return {
|
|
92573
93150
|
put(agent, msg) {
|
|
92574
93151
|
const id = spoolId(msg);
|
|
92575
|
-
|
|
93152
|
+
const existing = live.get(id);
|
|
93153
|
+
if (existing != null) {
|
|
93154
|
+
if (msg.meta?.source === "boot_briefing") {
|
|
93155
|
+
existing.agent = agent;
|
|
93156
|
+
existing.msg = msg;
|
|
93157
|
+
appendRecord({ t: "put", id, agent, msg, firstAt: existing.firstAt });
|
|
93158
|
+
maybeCompact();
|
|
93159
|
+
return true;
|
|
93160
|
+
}
|
|
92576
93161
|
return false;
|
|
93162
|
+
}
|
|
92577
93163
|
const firstAt = now();
|
|
92578
93164
|
live.set(id, { agent, msg, firstAt });
|
|
92579
93165
|
appendRecord({ t: "put", id, agent, msg, firstAt });
|
|
@@ -95290,7 +95876,7 @@ import {
|
|
|
95290
95876
|
writeSync as writeSync6
|
|
95291
95877
|
} from "node:fs";
|
|
95292
95878
|
import { join as join50 } from "node:path";
|
|
95293
|
-
import { randomUUID as
|
|
95879
|
+
import { randomUUID as randomUUID7 } from "node:crypto";
|
|
95294
95880
|
var PROPOSALS_FILE2 = "skill-proposals.jsonl";
|
|
95295
95881
|
var REJECTED_FILE2 = "skill-proposals-rejected.jsonl";
|
|
95296
95882
|
var REJECTION_TTL_MS2 = 90 * 24 * 60 * 60 * 1000;
|
|
@@ -95393,7 +95979,7 @@ function enqueueProposal(stateDir, input, opts = {}) {
|
|
|
95393
95979
|
const now = opts.now ?? Date.now;
|
|
95394
95980
|
ensureDir3(stateDir);
|
|
95395
95981
|
const proposal = {
|
|
95396
|
-
id:
|
|
95982
|
+
id: randomUUID7(),
|
|
95397
95983
|
created_at: new Date(now()).toISOString(),
|
|
95398
95984
|
status: "pending",
|
|
95399
95985
|
...input
|
|
@@ -96782,7 +97368,7 @@ ${errStr}`) ? "rate-limited" : "quota-exhausted" : classifyClaudeError({ type: e
|
|
|
96782
97368
|
const raw = embeddedError ?? obj;
|
|
96783
97369
|
const kind = classifyClaudeError(embeddedError ?? obj);
|
|
96784
97370
|
const detail = extractDetailMessage(embeddedError) ?? extractDetailMessage(obj) ?? String(type ?? "");
|
|
96785
|
-
const transient = kind === "rate-limited";
|
|
97371
|
+
const transient = kind === "rate-limited" || kind === "transport-transient";
|
|
96786
97372
|
const retry = extractRetryState(obj);
|
|
96787
97373
|
const terminal = !transient ? true : retry.retryAttempt != null && retry.maxRetries != null ? retry.retryAttempt >= retry.maxRetries : isErrorLine;
|
|
96788
97374
|
return { kind, raw, detail, transient, terminal };
|
|
@@ -100660,7 +101246,7 @@ function startGatewayHeartbeat(stateDir, intervalMs = GATEWAY_HEARTBEAT_INTERVAL
|
|
|
100660
101246
|
}
|
|
100661
101247
|
|
|
100662
101248
|
// gateway/boot-beacon.ts
|
|
100663
|
-
import { randomUUID as
|
|
101249
|
+
import { randomUUID as randomUUID8 } from "node:crypto";
|
|
100664
101250
|
import {
|
|
100665
101251
|
closeSync as closeSync14,
|
|
100666
101252
|
fsyncSync as fsyncSync5,
|
|
@@ -100794,7 +101380,7 @@ function writeBootBeaconFile(stateDir, beacon) {
|
|
|
100794
101380
|
return false;
|
|
100795
101381
|
}
|
|
100796
101382
|
}
|
|
100797
|
-
var GATEWAY_BOOT_ID =
|
|
101383
|
+
var GATEWAY_BOOT_ID = randomUUID8();
|
|
100798
101384
|
function tickBootBeacon(stateDir, bootId = GATEWAY_BOOT_ID) {
|
|
100799
101385
|
try {
|
|
100800
101386
|
return writeBootBeaconFile(stateDir, buildBootBeacon({
|
|
@@ -101147,10 +101733,10 @@ function startOutboxSweep(deps) {
|
|
|
101147
101733
|
}
|
|
101148
101734
|
|
|
101149
101735
|
// ../src/build-info.ts
|
|
101150
|
-
var VERSION2 = "0.
|
|
101151
|
-
var COMMIT_SHA = "
|
|
101152
|
-
var COMMIT_DATE = "2026-08-
|
|
101153
|
-
var LATEST_PR =
|
|
101736
|
+
var VERSION2 = "0.20.0";
|
|
101737
|
+
var COMMIT_SHA = "86eaf06d";
|
|
101738
|
+
var COMMIT_DATE = "2026-08-03T03:02:51Z";
|
|
101739
|
+
var LATEST_PR = 4259;
|
|
101154
101740
|
var COMMITS_AHEAD_OF_TAG = 0;
|
|
101155
101741
|
|
|
101156
101742
|
// gateway/boot-version.ts
|
|
@@ -102533,8 +103119,338 @@ function selectResumeBuilder(endedVia, opts) {
|
|
|
102533
103119
|
return kind;
|
|
102534
103120
|
}
|
|
102535
103121
|
|
|
103122
|
+
// gateway/boot-briefing-wiring.ts
|
|
103123
|
+
init_history();
|
|
103124
|
+
import { existsSync as existsSync56, readFileSync as readFileSync59, writeFileSync as writeFileSync48 } from "node:fs";
|
|
103125
|
+
import { join as join68 } from "node:path";
|
|
103126
|
+
|
|
103127
|
+
// gateway/resume-inbound-builder.ts
|
|
103128
|
+
function humanizeElapsed2(ms) {
|
|
103129
|
+
if (!Number.isFinite(ms) || ms < 0)
|
|
103130
|
+
return "an unknown amount of time";
|
|
103131
|
+
const sec = Math.round(ms / 1000);
|
|
103132
|
+
if (sec < 45)
|
|
103133
|
+
return "moments";
|
|
103134
|
+
const min = Math.round(sec / 60);
|
|
103135
|
+
if (min < 60)
|
|
103136
|
+
return `~${min} min`;
|
|
103137
|
+
const hr = Math.round(min / 60);
|
|
103138
|
+
if (hr < 24)
|
|
103139
|
+
return `~${hr}h`;
|
|
103140
|
+
const days = Math.round(hr / 24);
|
|
103141
|
+
return `~${days} day${days === 1 ? "" : "s"}`;
|
|
103142
|
+
}
|
|
103143
|
+
var RESUME_SYNTHETIC_PROMPT_PREFIX2 = "You just restarted.";
|
|
103144
|
+
|
|
103145
|
+
// gateway/boot-briefing-builder.ts
|
|
103146
|
+
var BOOT_BRIEFING_SOURCE = "boot_briefing";
|
|
103147
|
+
var BRIEFING_CHAR_BUDGET = 7000;
|
|
103148
|
+
var BRIEFING_PER_MESSAGE_MAX_CHARS = 400;
|
|
103149
|
+
var BRIEFING_PRIMARY_DEPTH = 15;
|
|
103150
|
+
var BRIEFING_ACTIVE_WINDOW_MS = 48 * 60 * 60 * 1000;
|
|
103151
|
+
var BRIEFING_MAX_SURFACES = 8;
|
|
103152
|
+
var BRIEFING_TTL_MS = 60 * 60 * 1000;
|
|
103153
|
+
var HISTORY_SELFCHECK_CHAT = "__history_selfcheck__";
|
|
103154
|
+
function excludeWindowFromResumeInbound(msg) {
|
|
103155
|
+
if (msg == null)
|
|
103156
|
+
return null;
|
|
103157
|
+
const chatId = msg.meta?.chat_id;
|
|
103158
|
+
const startedAt = Number(msg.meta?.started_at);
|
|
103159
|
+
if (typeof chatId !== "string" || chatId.length === 0)
|
|
103160
|
+
return null;
|
|
103161
|
+
if (!Number.isFinite(startedAt) || startedAt <= 0)
|
|
103162
|
+
return null;
|
|
103163
|
+
const threadRaw = msg.meta?.message_thread_id;
|
|
103164
|
+
const threadNum = threadRaw != null && threadRaw !== "" ? Number(threadRaw) : null;
|
|
103165
|
+
return {
|
|
103166
|
+
chatId,
|
|
103167
|
+
threadId: threadNum != null && Number.isFinite(threadNum) ? threadNum : null,
|
|
103168
|
+
sinceMs: startedAt
|
|
103169
|
+
};
|
|
103170
|
+
}
|
|
103171
|
+
function sameSurface(a, b) {
|
|
103172
|
+
return a.chatId === b.chatId && (a.threadId ?? null) === (b.threadId ?? null);
|
|
103173
|
+
}
|
|
103174
|
+
function collectBriefingSurfaces(db3, opts) {
|
|
103175
|
+
const activeWindowMs = opts.activeWindowMs ?? BRIEFING_ACTIVE_WINDOW_MS;
|
|
103176
|
+
const primaryDepth = opts.primaryDepth ?? BRIEFING_PRIMARY_DEPTH;
|
|
103177
|
+
const maxSurfaces = opts.maxSurfaces ?? BRIEFING_MAX_SURFACES;
|
|
103178
|
+
const cutoffSec = Math.floor((opts.nowMs - activeWindowMs) / 1000);
|
|
103179
|
+
try {
|
|
103180
|
+
const surfaceRows = db3.prepare(`SELECT chat_id, thread_id, MAX(ts) AS last_ts
|
|
103181
|
+
FROM messages
|
|
103182
|
+
WHERE role IN ('user','assistant')
|
|
103183
|
+
AND ts >= ?
|
|
103184
|
+
AND chat_id <> ?
|
|
103185
|
+
GROUP BY chat_id, thread_id
|
|
103186
|
+
ORDER BY last_ts DESC
|
|
103187
|
+
LIMIT ?`).all(cutoffSec, HISTORY_SELFCHECK_CHAT, maxSurfaces);
|
|
103188
|
+
const out = [];
|
|
103189
|
+
for (let i = 0;i < surfaceRows.length; i++) {
|
|
103190
|
+
const s = surfaceRows[i];
|
|
103191
|
+
const depth = i === 0 ? primaryDepth : 1;
|
|
103192
|
+
const threadClause = s.thread_id == null ? "thread_id IS NULL" : "thread_id = ?";
|
|
103193
|
+
const params = [s.chat_id];
|
|
103194
|
+
if (s.thread_id != null)
|
|
103195
|
+
params.push(s.thread_id);
|
|
103196
|
+
params.push(depth);
|
|
103197
|
+
const msgRows = db3.prepare(`SELECT role, user, ts, text
|
|
103198
|
+
FROM messages
|
|
103199
|
+
WHERE chat_id = ? AND ${threadClause}
|
|
103200
|
+
AND role IN ('user','assistant')
|
|
103201
|
+
ORDER BY ts DESC, message_id DESC
|
|
103202
|
+
LIMIT ?`).all(...params);
|
|
103203
|
+
msgRows.reverse();
|
|
103204
|
+
let messages = msgRows.map((r) => ({
|
|
103205
|
+
role: r.role,
|
|
103206
|
+
user: r.user ?? null,
|
|
103207
|
+
ts: r.ts,
|
|
103208
|
+
text: r.text ?? ""
|
|
103209
|
+
}));
|
|
103210
|
+
const ex = opts.exclude;
|
|
103211
|
+
if (ex != null && sameSurface({ chatId: s.chat_id, threadId: s.thread_id ?? null }, ex)) {
|
|
103212
|
+
const sinceSec = Math.floor(ex.sinceMs / 1000);
|
|
103213
|
+
messages = messages.filter((m) => m.ts < sinceSec);
|
|
103214
|
+
}
|
|
103215
|
+
if (messages.length === 0)
|
|
103216
|
+
continue;
|
|
103217
|
+
out.push({
|
|
103218
|
+
chatId: s.chat_id,
|
|
103219
|
+
threadId: s.thread_id ?? null,
|
|
103220
|
+
lastTs: s.last_ts,
|
|
103221
|
+
messages
|
|
103222
|
+
});
|
|
103223
|
+
}
|
|
103224
|
+
return out;
|
|
103225
|
+
} catch {
|
|
103226
|
+
return [];
|
|
103227
|
+
}
|
|
103228
|
+
}
|
|
103229
|
+
function truncateOneLine(s, max) {
|
|
103230
|
+
const t = s.replace(/\s+/g, " ").trim();
|
|
103231
|
+
if (t.length <= max)
|
|
103232
|
+
return t;
|
|
103233
|
+
const points = Array.from(t);
|
|
103234
|
+
if (points.length <= max)
|
|
103235
|
+
return t;
|
|
103236
|
+
return points.slice(0, max - 1).join("").trimEnd() + "\u2026";
|
|
103237
|
+
}
|
|
103238
|
+
function surfaceLabel(s) {
|
|
103239
|
+
return s.threadId != null ? `chat ${s.chatId}, topic ${s.threadId}` : `chat ${s.chatId}`;
|
|
103240
|
+
}
|
|
103241
|
+
function renderMessageLine(m, nowMs3, perMessageMax) {
|
|
103242
|
+
const label = m.role === "user" ? m.user && m.user.trim() ? m.user.trim() : "user" : "you";
|
|
103243
|
+
const age = humanizeElapsed2(Math.max(0, nowMs3 - m.ts * 1000));
|
|
103244
|
+
return `- [${age} ago] ${label}: ${truncateOneLine(m.text, perMessageMax)}`;
|
|
103245
|
+
}
|
|
103246
|
+
function renderBootBriefing(surfaces, opts) {
|
|
103247
|
+
if (surfaces.length === 0)
|
|
103248
|
+
return "";
|
|
103249
|
+
const charBudget = opts.charBudget ?? BRIEFING_CHAR_BUDGET;
|
|
103250
|
+
const perMessageMax = opts.perMessageMax ?? BRIEFING_PER_MESSAGE_MAX_CHARS;
|
|
103251
|
+
const reasonClause = opts.restartReason && opts.restartReason.trim() ? ` The previous session ended via: ${truncateOneLine(opts.restartReason, 120)}.` : "";
|
|
103252
|
+
const header = `${RESUME_SYNTHETIC_PROMPT_PREFIX2} This is an automatic boot briefing assembled ` + `from your durable message history \u2014 context to reorient you, NOT a new user ` + `request.${reasonClause} Read it, then: if nothing in it is unfinished or owed, ` + `do NOT message the user (end the turn with NO_REPLY); if something was clearly ` + `left unfinished or owed, briefly pick it up. The full history is available via ` + `get_recent_messages.`;
|
|
103253
|
+
const primary = surfaces[0];
|
|
103254
|
+
const primaryTitle = `## Active conversation \u2014 ${surfaceLabel(primary)} ` + `(last active ${humanizeElapsed2(Math.max(0, opts.nowMs - primary.lastTs * 1000))} ago)`;
|
|
103255
|
+
const primaryLines = primary.messages.map((m) => renderMessageLine(m, opts.nowMs, perMessageMax));
|
|
103256
|
+
const assemble = (lines, secondaries2) => {
|
|
103257
|
+
const parts = [header, "", primaryTitle, ...lines];
|
|
103258
|
+
if (secondaries2.length > 0) {
|
|
103259
|
+
parts.push("", "## Other recent surfaces (active in the last 48h)", ...secondaries2);
|
|
103260
|
+
}
|
|
103261
|
+
return parts.join(`
|
|
103262
|
+
`);
|
|
103263
|
+
};
|
|
103264
|
+
const kept = [...primaryLines];
|
|
103265
|
+
while (kept.length > 1 && assemble(kept, []).length > charBudget) {
|
|
103266
|
+
kept.shift();
|
|
103267
|
+
}
|
|
103268
|
+
if (assemble(kept, []).length > charBudget) {
|
|
103269
|
+
return assemble(kept, []).slice(0, charBudget);
|
|
103270
|
+
}
|
|
103271
|
+
const secondaries = [];
|
|
103272
|
+
for (const s of surfaces.slice(1)) {
|
|
103273
|
+
const last = s.messages[s.messages.length - 1];
|
|
103274
|
+
const block = `- ${surfaceLabel(s)} \u2014 last active ` + `${humanizeElapsed2(Math.max(0, opts.nowMs - s.lastTs * 1000))} ago:
|
|
103275
|
+
` + ` ${renderMessageLine(last, opts.nowMs, perMessageMax).slice(2)}`;
|
|
103276
|
+
if (assemble(kept, [...secondaries, block]).length > charBudget)
|
|
103277
|
+
break;
|
|
103278
|
+
secondaries.push(block);
|
|
103279
|
+
}
|
|
103280
|
+
return assemble(kept, secondaries);
|
|
103281
|
+
}
|
|
103282
|
+
function readRestartBreadcrumb(opts) {
|
|
103283
|
+
let reason = null;
|
|
103284
|
+
if (opts.restartReasonPath) {
|
|
103285
|
+
try {
|
|
103286
|
+
const raw = opts.readFile(opts.restartReasonPath);
|
|
103287
|
+
const first = raw.split(`
|
|
103288
|
+
`)[0]?.replace(/\r/g, "").trim();
|
|
103289
|
+
if (first)
|
|
103290
|
+
reason = first;
|
|
103291
|
+
} catch {}
|
|
103292
|
+
}
|
|
103293
|
+
const envVia = opts.env.SWITCHROOM_PENDING_ENDED_VIA;
|
|
103294
|
+
if (typeof envVia === "string" && envVia.trim().length > 0)
|
|
103295
|
+
reason = envVia.trim();
|
|
103296
|
+
return reason;
|
|
103297
|
+
}
|
|
103298
|
+
function decideBootBriefing(opts) {
|
|
103299
|
+
if (opts.briefingMode !== "gateway")
|
|
103300
|
+
return { build: false, reason: "flag-legacy" };
|
|
103301
|
+
if (opts.forceFreshMarker)
|
|
103302
|
+
return { build: false, reason: "force-fresh" };
|
|
103303
|
+
if (opts.resumeMode === "continue" || opts.resumeMode === "auto") {
|
|
103304
|
+
return { build: false, reason: "transcript-replay-possible" };
|
|
103305
|
+
}
|
|
103306
|
+
return { build: true, reason: "ok" };
|
|
103307
|
+
}
|
|
103308
|
+
function buildBootBriefingInbound(args) {
|
|
103309
|
+
const ts = args.nowMs ?? Date.now();
|
|
103310
|
+
const ttlMs = args.ttlMs ?? BRIEFING_TTL_MS;
|
|
103311
|
+
const meta = {
|
|
103312
|
+
source: BOOT_BRIEFING_SOURCE,
|
|
103313
|
+
chat_id: args.chatId,
|
|
103314
|
+
...args.threadId != null ? { message_thread_id: String(args.threadId) } : {},
|
|
103315
|
+
message_id: String(ts),
|
|
103316
|
+
expiresAt: String(ts + ttlMs)
|
|
103317
|
+
};
|
|
103318
|
+
return {
|
|
103319
|
+
type: "inbound",
|
|
103320
|
+
chatId: args.chatId,
|
|
103321
|
+
...args.threadId != null ? { threadId: args.threadId } : {},
|
|
103322
|
+
messageId: ts,
|
|
103323
|
+
user: "switchroom",
|
|
103324
|
+
userId: 0,
|
|
103325
|
+
ts,
|
|
103326
|
+
text: args.text,
|
|
103327
|
+
meta
|
|
103328
|
+
};
|
|
103329
|
+
}
|
|
103330
|
+
|
|
103331
|
+
// gateway/boot-briefing-wiring.ts
|
|
103332
|
+
function maybeQueueBootBriefing(opts) {
|
|
103333
|
+
const log = opts.log ?? ((l) => process.stderr.write(l));
|
|
103334
|
+
try {
|
|
103335
|
+
const agentDir = opts.stateDir.endsWith("/telegram") ? opts.stateDir.slice(0, -"/telegram".length) : opts.stateDir;
|
|
103336
|
+
const bootId = opts.env.SWITCHROOM_GATEWAY_BOOT_ID;
|
|
103337
|
+
const genMarkerPath = join68(agentDir, ".boot-briefing-generation");
|
|
103338
|
+
if (bootId) {
|
|
103339
|
+
let prevGen = null;
|
|
103340
|
+
try {
|
|
103341
|
+
prevGen = readFileSync59(genMarkerPath, "utf8").trim();
|
|
103342
|
+
} catch {
|
|
103343
|
+
prevGen = null;
|
|
103344
|
+
}
|
|
103345
|
+
if (prevGen === bootId) {
|
|
103346
|
+
log(`telegram gateway: boot-briefing suppressed (supervisor respawn \u2014 this boot generation already briefed)
|
|
103347
|
+
`);
|
|
103348
|
+
return null;
|
|
103349
|
+
}
|
|
103350
|
+
}
|
|
103351
|
+
const markGeneration = () => {
|
|
103352
|
+
if (!bootId)
|
|
103353
|
+
return;
|
|
103354
|
+
try {
|
|
103355
|
+
writeFileSync48(genMarkerPath, `${bootId}
|
|
103356
|
+
`);
|
|
103357
|
+
} catch {}
|
|
103358
|
+
};
|
|
103359
|
+
const forceFresh = opts.env.SWITCHROOM_FORCE_FRESH === "1" || existsSync56(join68(agentDir, ".force-fresh-session"));
|
|
103360
|
+
const decision = decideBootBriefing({
|
|
103361
|
+
briefingMode: opts.env.SWITCHROOM_SESSION_BRIEFING,
|
|
103362
|
+
resumeMode: opts.env.SWITCHROOM_RESUME_MODE,
|
|
103363
|
+
forceFreshMarker: forceFresh
|
|
103364
|
+
});
|
|
103365
|
+
if (!decision.build) {
|
|
103366
|
+
if (decision.reason !== "flag-legacy") {
|
|
103367
|
+
log(`telegram gateway: boot-briefing suppressed (${decision.reason})
|
|
103368
|
+
`);
|
|
103369
|
+
}
|
|
103370
|
+
return null;
|
|
103371
|
+
}
|
|
103372
|
+
const selfAgent = opts.env.SWITCHROOM_AGENT_NAME ?? "";
|
|
103373
|
+
if (!selfAgent)
|
|
103374
|
+
return null;
|
|
103375
|
+
const db3 = getHistoryDbForBriefing();
|
|
103376
|
+
if (db3 == null) {
|
|
103377
|
+
log(`telegram gateway: boot-briefing skipped \u2014 history DB unavailable
|
|
103378
|
+
`);
|
|
103379
|
+
return null;
|
|
103380
|
+
}
|
|
103381
|
+
const nowMs3 = opts.nowMs ?? Date.now();
|
|
103382
|
+
const surfaces = collectBriefingSurfaces(db3, {
|
|
103383
|
+
nowMs: nowMs3,
|
|
103384
|
+
exclude: excludeWindowFromResumeInbound(opts.resumeMsg)
|
|
103385
|
+
});
|
|
103386
|
+
const restartReason = readRestartBreadcrumb({
|
|
103387
|
+
restartReasonPath: join68(agentDir, ".restart-reason"),
|
|
103388
|
+
env: opts.env,
|
|
103389
|
+
readFile: (p) => readFileSync59(p, "utf8")
|
|
103390
|
+
});
|
|
103391
|
+
const text5 = renderBootBriefing(surfaces, { nowMs: nowMs3, restartReason });
|
|
103392
|
+
if (!text5) {
|
|
103393
|
+
markGeneration();
|
|
103394
|
+
log(`telegram gateway: boot-briefing empty (no recent surfaces) \u2014 nothing queued
|
|
103395
|
+
`);
|
|
103396
|
+
return null;
|
|
103397
|
+
}
|
|
103398
|
+
const primary = surfaces[0];
|
|
103399
|
+
const msg = buildBootBriefingInbound({
|
|
103400
|
+
chatId: primary.chatId,
|
|
103401
|
+
threadId: primary.threadId,
|
|
103402
|
+
text: text5,
|
|
103403
|
+
nowMs: nowMs3
|
|
103404
|
+
});
|
|
103405
|
+
opts.put(selfAgent, msg);
|
|
103406
|
+
markGeneration();
|
|
103407
|
+
log(`telegram gateway: boot-briefing queued chat=${primary.chatId}` + `${primary.threadId != null ? ` thread=${primary.threadId}` : ""} ` + `surfaces=${surfaces.length} chars=${text5.length}
|
|
103408
|
+
`);
|
|
103409
|
+
return msg;
|
|
103410
|
+
} catch (err) {
|
|
103411
|
+
log(`telegram gateway: boot-briefing failed (${err.message}) \u2014 continuing without briefing
|
|
103412
|
+
`);
|
|
103413
|
+
return null;
|
|
103414
|
+
}
|
|
103415
|
+
}
|
|
103416
|
+
|
|
103417
|
+
// gateway/pending-turn-env.ts
|
|
103418
|
+
import { existsSync as existsSync57, renameSync as renameSync26, rmSync as rmSync8, writeFileSync as writeFileSync49 } from "node:fs";
|
|
103419
|
+
import { join as join69 } from "node:path";
|
|
103420
|
+
function writePendingTurnEnv(agentDir, pending, log = (l) => process.stderr.write(l)) {
|
|
103421
|
+
const pendingEnvPath = join69(agentDir, ".pending-turn.env");
|
|
103422
|
+
try {
|
|
103423
|
+
if (pending != null) {
|
|
103424
|
+
const lines = [
|
|
103425
|
+
`SWITCHROOM_PENDING_TURN=true`,
|
|
103426
|
+
`SWITCHROOM_PENDING_TURN_KEY=${pending.turn_key}`,
|
|
103427
|
+
`SWITCHROOM_PENDING_CHAT_ID=${pending.chat_id}`,
|
|
103428
|
+
pending.thread_id != null ? `SWITCHROOM_PENDING_THREAD_ID=${pending.thread_id}` : `SWITCHROOM_PENDING_THREAD_ID=`,
|
|
103429
|
+
pending.last_user_msg_id != null ? `SWITCHROOM_PENDING_USER_MSG_ID=${pending.last_user_msg_id}` : `SWITCHROOM_PENDING_USER_MSG_ID=`,
|
|
103430
|
+
`SWITCHROOM_PENDING_ENDED_VIA=${pending.ended_via ?? "unknown"}`,
|
|
103431
|
+
`SWITCHROOM_PENDING_STARTED_AT=${pending.started_at}`,
|
|
103432
|
+
pending.interrupt_reason != null ? `SWITCHROOM_PENDING_INTERRUPT_REASON=${pending.interrupt_reason}` : `SWITCHROOM_PENDING_INTERRUPT_REASON=`
|
|
103433
|
+
];
|
|
103434
|
+
const pendingEnvTmp = `${pendingEnvPath}.tmp-${process.pid}`;
|
|
103435
|
+
writeFileSync49(pendingEnvTmp, lines.join(`
|
|
103436
|
+
`) + `
|
|
103437
|
+
`, { mode: 384 });
|
|
103438
|
+
renameSync26(pendingEnvTmp, pendingEnvPath);
|
|
103439
|
+
log(`telegram gateway: pending-turn env written to ${pendingEnvPath} ` + `turnKey=${pending.turn_key} endedVia=${pending.ended_via ?? "open"}
|
|
103440
|
+
`);
|
|
103441
|
+
} else if (existsSync57(pendingEnvPath)) {
|
|
103442
|
+
rmSync8(pendingEnvPath, { force: true });
|
|
103443
|
+
log(`telegram gateway: pending-turn env cleared (clean previous shutdown)
|
|
103444
|
+
`);
|
|
103445
|
+
}
|
|
103446
|
+
} catch (err) {
|
|
103447
|
+
log(`telegram gateway: pending-turn env write failed (${err.message})
|
|
103448
|
+
`);
|
|
103449
|
+
}
|
|
103450
|
+
}
|
|
103451
|
+
|
|
102536
103452
|
// gateway/bridge-dead-watchdog.ts
|
|
102537
|
-
import { readFileSync as
|
|
103453
|
+
import { readFileSync as readFileSync60, writeFileSync as writeFileSync50, renameSync as renameSync27, unlinkSync as unlinkSync29 } from "node:fs";
|
|
102538
103454
|
|
|
102539
103455
|
// gateway/cron-session.ts
|
|
102540
103456
|
var CRON_IDENTITY_SUFFIX2 = "-cron";
|
|
@@ -102567,7 +103483,7 @@ function readFreshCrashLogTail(path3, opts = {}) {
|
|
|
102567
103483
|
const nowMs3 = opts.nowMs ?? Date.now();
|
|
102568
103484
|
const freshWindowMs = opts.freshWindowMs ?? CRASH_LOG_FRESH_WINDOW_MS;
|
|
102569
103485
|
const maxLines = opts.maxLines ?? CRASH_LOG_TAIL_LINES;
|
|
102570
|
-
const readFile = opts.readFile ?? ((p) =>
|
|
103486
|
+
const readFile = opts.readFile ?? ((p) => readFileSync60(p, "utf8"));
|
|
102571
103487
|
let raw;
|
|
102572
103488
|
try {
|
|
102573
103489
|
raw = readFile(path3);
|
|
@@ -102588,13 +103504,13 @@ function readFreshCrashLogTail(path3, opts = {}) {
|
|
|
102588
103504
|
}
|
|
102589
103505
|
function writeBridgeDeadEscalationMarker(path3, marker) {
|
|
102590
103506
|
const tmp = `${path3}.tmp-${process.pid}-${Date.now()}`;
|
|
102591
|
-
|
|
102592
|
-
|
|
103507
|
+
writeFileSync50(tmp, JSON.stringify(marker), "utf8");
|
|
103508
|
+
renameSync27(tmp, path3);
|
|
102593
103509
|
}
|
|
102594
103510
|
function consumeBridgeDeadEscalationMarker(path3, nowMs3 = Date.now(), maxAgeMs = ESCALATION_MARKER_MAX_AGE_MS) {
|
|
102595
103511
|
let marker = null;
|
|
102596
103512
|
try {
|
|
102597
|
-
const parsed = JSON.parse(
|
|
103513
|
+
const parsed = JSON.parse(readFileSync60(path3, "utf8"));
|
|
102598
103514
|
if (typeof parsed.ts === "number" && Number.isFinite(parsed.ts) && typeof parsed.reason === "string") {
|
|
102599
103515
|
const age = nowMs3 - parsed.ts;
|
|
102600
103516
|
if (age >= 0 && age < maxAgeMs) {
|
|
@@ -102747,7 +103663,7 @@ function createBridgeDeadWatchdog(opts) {
|
|
|
102747
103663
|
}
|
|
102748
103664
|
|
|
102749
103665
|
// gateway/boot-probes.ts
|
|
102750
|
-
import { readFileSync as
|
|
103666
|
+
import { readFileSync as readFileSync61, readdirSync as readdirSync14, existsSync as existsSync58 } from "fs";
|
|
102751
103667
|
init_quota_cache();
|
|
102752
103668
|
init_generation_stamp();
|
|
102753
103669
|
init_quota_check();
|
|
@@ -102756,7 +103672,7 @@ import { promisify as promisify2 } from "util";
|
|
|
102756
103672
|
var execFile2 = promisify2(execFileCb2);
|
|
102757
103673
|
var realProcFs2 = {
|
|
102758
103674
|
readdir: (p) => readdirSync14(p),
|
|
102759
|
-
readFile: (p) =>
|
|
103675
|
+
readFile: (p) => readFileSync61(p, "utf-8")
|
|
102760
103676
|
};
|
|
102761
103677
|
function findAgentProcessInContainer2(fs4 = realProcFs2) {
|
|
102762
103678
|
let entries;
|
|
@@ -103006,7 +103922,7 @@ if (isGatewayMain) {
|
|
|
103006
103922
|
shutdownAnalytics();
|
|
103007
103923
|
});
|
|
103008
103924
|
}
|
|
103009
|
-
var STATE_DIR = process.env.TELEGRAM_STATE_DIR ??
|
|
103925
|
+
var STATE_DIR = process.env.TELEGRAM_STATE_DIR ?? join70(homedir20(), ".claude", "channels", "telegram");
|
|
103010
103926
|
var permCardStore = createPermissionCardStore(STATE_DIR);
|
|
103011
103927
|
var BLOCKED_APPROVALS_DIR = process.env.SWITCHROOM_BLOCKED_APPROVALS_DIR ?? "/state/blocked-approvals";
|
|
103012
103928
|
var AGENT_NAME = process.env.SWITCHROOM_AGENT_NAME ?? "agent";
|
|
@@ -103045,7 +103961,7 @@ function alwaysAllowDrainDeps() {
|
|
|
103045
103961
|
return {
|
|
103046
103962
|
readConfigText: () => {
|
|
103047
103963
|
const cfgPath = process.env.SWITCHROOM_CONFIG ?? SWITCHROOM_CONFIG ?? findConfigFile2();
|
|
103048
|
-
return
|
|
103964
|
+
return readFileSync62(cfgPath, "utf8");
|
|
103049
103965
|
},
|
|
103050
103966
|
resolveAllowList: (_configText, agentName3) => {
|
|
103051
103967
|
const cfg = loadConfig2();
|
|
@@ -103106,11 +104022,11 @@ function scheduleAlwaysAllowPersistDrain() {
|
|
|
103106
104022
|
}, ALWAYS_ALLOW_DRAIN_INTERVAL_MS);
|
|
103107
104023
|
timer3.unref?.();
|
|
103108
104024
|
}
|
|
103109
|
-
var ACCESS_FILE =
|
|
103110
|
-
var APPROVED_DIR =
|
|
103111
|
-
var ENV_FILE =
|
|
103112
|
-
var INBOX_DIR =
|
|
103113
|
-
var PEOPLE_FILE =
|
|
104025
|
+
var ACCESS_FILE = join70(STATE_DIR, "access.json");
|
|
104026
|
+
var APPROVED_DIR = join70(STATE_DIR, "approved");
|
|
104027
|
+
var ENV_FILE = join70(STATE_DIR, ".env");
|
|
104028
|
+
var INBOX_DIR = join70(STATE_DIR, "inbox");
|
|
104029
|
+
var PEOPLE_FILE = join70(STATE_DIR, "people.json");
|
|
103114
104030
|
function triggerSelfRestart(targetAgent, reason, delayMs = 300) {
|
|
103115
104031
|
const isDocker = process.env.SWITCHROOM_RUNTIME === "docker";
|
|
103116
104032
|
const selfAgent = process.env.SWITCHROOM_AGENT_NAME;
|
|
@@ -103175,7 +104091,7 @@ function formatBootVersion() {
|
|
|
103175
104091
|
}
|
|
103176
104092
|
try {
|
|
103177
104093
|
chmodSync14(ENV_FILE, 384);
|
|
103178
|
-
for (const line of
|
|
104094
|
+
for (const line of readFileSync62(ENV_FILE, "utf8").split(`
|
|
103179
104095
|
`)) {
|
|
103180
104096
|
const m = line.match(/^(\w+)=(.*)$/);
|
|
103181
104097
|
if (m && process.env[m[1]] === undefined)
|
|
@@ -103196,7 +104112,7 @@ var bot;
|
|
|
103196
104112
|
var lastGetUpdatesHeartbeatMs = Date.now();
|
|
103197
104113
|
var GRAMMY_VERSION = (() => {
|
|
103198
104114
|
try {
|
|
103199
|
-
const raw =
|
|
104115
|
+
const raw = readFileSync62(new URL("../../node_modules/grammy/package.json", import.meta.url), "utf8");
|
|
103200
104116
|
return JSON.parse(raw).version ?? "unknown";
|
|
103201
104117
|
} catch {
|
|
103202
104118
|
return "unknown";
|
|
@@ -103240,7 +104156,7 @@ function assertSendable(f) {
|
|
|
103240
104156
|
} catch {
|
|
103241
104157
|
throw new Error(`refusing to send file \u2014 cannot resolve real path: ${f}`);
|
|
103242
104158
|
}
|
|
103243
|
-
const inbox =
|
|
104159
|
+
const inbox = join70(stateReal, "inbox");
|
|
103244
104160
|
if (real.startsWith(stateReal + sep4) && !real.startsWith(inbox + sep4)) {
|
|
103245
104161
|
throw new Error(`refusing to send channel state: ${f}`);
|
|
103246
104162
|
}
|
|
@@ -103259,7 +104175,7 @@ function assertSendable(f) {
|
|
|
103259
104175
|
}
|
|
103260
104176
|
function readAccessFile() {
|
|
103261
104177
|
try {
|
|
103262
|
-
const raw =
|
|
104178
|
+
const raw = readFileSync62(ACCESS_FILE, "utf8");
|
|
103263
104179
|
const parsed = JSON.parse(raw);
|
|
103264
104180
|
const allowFrom = validateStringArray("allowFrom", parsed.allowFrom ?? []);
|
|
103265
104181
|
const groups = {};
|
|
@@ -103299,7 +104215,7 @@ function readAccessFile() {
|
|
|
103299
104215
|
if (err.code === "ENOENT")
|
|
103300
104216
|
return defaultAccess();
|
|
103301
104217
|
try {
|
|
103302
|
-
|
|
104218
|
+
renameSync28(ACCESS_FILE, `${ACCESS_FILE}.corrupt-${Date.now()}`);
|
|
103303
104219
|
} catch {}
|
|
103304
104220
|
process.stderr.write(`telegram gateway: access.json is corrupt, moved aside. Starting fresh.
|
|
103305
104221
|
`);
|
|
@@ -103321,7 +104237,7 @@ function loadAccess() {
|
|
|
103321
104237
|
}
|
|
103322
104238
|
function readPeopleFile() {
|
|
103323
104239
|
try {
|
|
103324
|
-
const raw =
|
|
104240
|
+
const raw = readFileSync62(PEOPLE_FILE, "utf8");
|
|
103325
104241
|
const parsed = JSON.parse(raw);
|
|
103326
104242
|
if (!Array.isArray(parsed.entries))
|
|
103327
104243
|
return [];
|
|
@@ -103345,9 +104261,9 @@ function saveAccess(a) {
|
|
|
103345
104261
|
return;
|
|
103346
104262
|
mkdirSync51(STATE_DIR, { recursive: true, mode: 448 });
|
|
103347
104263
|
const tmp = ACCESS_FILE + ".tmp";
|
|
103348
|
-
|
|
104264
|
+
writeFileSync52(tmp, JSON.stringify(a, null, 2) + `
|
|
103349
104265
|
`, { mode: 384 });
|
|
103350
|
-
|
|
104266
|
+
renameSync28(tmp, ACCESS_FILE);
|
|
103351
104267
|
}
|
|
103352
104268
|
function pruneExpired(a) {
|
|
103353
104269
|
const now = Date.now();
|
|
@@ -103365,7 +104281,7 @@ var HISTORY_ENABLED = HISTORY_ACCESS.historyEnabled !== false;
|
|
|
103365
104281
|
if (isGatewayMain && HISTORY_ENABLED) {
|
|
103366
104282
|
try {
|
|
103367
104283
|
initHistory(STATE_DIR, HISTORY_ACCESS.historyRetentionDays ?? 30);
|
|
103368
|
-
process.stderr.write(`telegram gateway: history capture enabled at ${
|
|
104284
|
+
process.stderr.write(`telegram gateway: history capture enabled at ${join70(STATE_DIR, "history.db")}
|
|
103369
104285
|
`);
|
|
103370
104286
|
} catch (err) {
|
|
103371
104287
|
process.stderr.write(`telegram gateway: history init failed (${err.message}) \u2014 capture disabled
|
|
@@ -103384,12 +104300,12 @@ if (isGatewayMain)
|
|
|
103384
104300
|
let markerTurnKey = null;
|
|
103385
104301
|
let markerAgeMs = null;
|
|
103386
104302
|
try {
|
|
103387
|
-
const markerPath =
|
|
103388
|
-
if (
|
|
104303
|
+
const markerPath = join70(STATE_DIR, TURN_ACTIVE_MARKER_FILE2);
|
|
104304
|
+
if (existsSync60(markerPath)) {
|
|
103389
104305
|
const st = statSync23(markerPath);
|
|
103390
104306
|
markerAgeMs = Date.now() - st.mtimeMs;
|
|
103391
104307
|
try {
|
|
103392
|
-
const payload = JSON.parse(
|
|
104308
|
+
const payload = JSON.parse(readFileSync62(markerPath, "utf8"));
|
|
103393
104309
|
if (typeof payload.turnKey === "string" && payload.turnKey.length > 0) {
|
|
103394
104310
|
markerTurnKey = payload.turnKey;
|
|
103395
104311
|
}
|
|
@@ -103409,10 +104325,10 @@ if (isGatewayMain)
|
|
|
103409
104325
|
process.stderr.write(`telegram gateway: turn-registry boot-reaper stamped ${reaped} orphaned turn(s)` + `${timeoutTurnKey ? ` (turnKey=${timeoutTurnKey} as 'timeout', markerAgeMs=${markerAgeMs})` : " as 'restart'"}
|
|
103410
104326
|
`);
|
|
103411
104327
|
} else {
|
|
103412
|
-
process.stderr.write(`telegram gateway: turn-registry initialized at ${
|
|
104328
|
+
process.stderr.write(`telegram gateway: turn-registry initialized at ${join70(agentDir, "telegram", "registry.db")}
|
|
103413
104329
|
`);
|
|
103414
104330
|
}
|
|
103415
|
-
const bridgeDeadMarker = consumeBridgeDeadEscalationMarker(
|
|
104331
|
+
const bridgeDeadMarker = consumeBridgeDeadEscalationMarker(join70(STATE_DIR, "bridge-dead-escalation.json"));
|
|
103416
104332
|
if (bridgeDeadMarker != null) {
|
|
103417
104333
|
bridgeDeadPriorStreak = bridgeDeadMarker.count ?? 1;
|
|
103418
104334
|
process.stderr.write(`telegram gateway: boot: prior restart was a bridge-dead escalation (reason=${bridgeDeadMarker.reason}` + `, consecutive=${bridgeDeadPriorStreak}` + `${bridgeDeadMarker.crashTail ? `, crashTail=${bridgeDeadMarker.crashTail}` : ""})
|
|
@@ -103425,7 +104341,7 @@ if (isGatewayMain)
|
|
|
103425
104341
|
const pending2 = findLatestTurnIfInterrupted(turnsDb);
|
|
103426
104342
|
const selfAgent = process.env.SWITCHROOM_AGENT_NAME ?? "";
|
|
103427
104343
|
if (pending2 != null && selfAgent) {
|
|
103428
|
-
const bootResumeMarkerPath = process.env.SWITCHROOM_GATEWAY_CLEAN_SHUTDOWN_MARKER ??
|
|
104344
|
+
const bootResumeMarkerPath = process.env.SWITCHROOM_GATEWAY_CLEAN_SHUTDOWN_MARKER ?? join70(STATE_DIR, "clean-shutdown.json");
|
|
103429
104345
|
const bootResumeCleanMarker = readCleanShutdownMarker(bootResumeMarkerPath);
|
|
103430
104346
|
const bootResumeForceAlways = process.env.SWITCHROOM_BOOT_RESUME_ALWAYS === "1";
|
|
103431
104347
|
const bootResumeMode = parseBootResumeMode(process.env.SWITCHROOM_BOOT_RESUME);
|
|
@@ -103538,35 +104454,7 @@ if (isGatewayMain)
|
|
|
103538
104454
|
`);
|
|
103539
104455
|
}
|
|
103540
104456
|
}
|
|
103541
|
-
|
|
103542
|
-
try {
|
|
103543
|
-
if (pending2 != null) {
|
|
103544
|
-
const lines = [
|
|
103545
|
-
`SWITCHROOM_PENDING_TURN=true`,
|
|
103546
|
-
`SWITCHROOM_PENDING_TURN_KEY=${pending2.turn_key}`,
|
|
103547
|
-
`SWITCHROOM_PENDING_CHAT_ID=${pending2.chat_id}`,
|
|
103548
|
-
pending2.thread_id != null ? `SWITCHROOM_PENDING_THREAD_ID=${pending2.thread_id}` : `SWITCHROOM_PENDING_THREAD_ID=`,
|
|
103549
|
-
pending2.last_user_msg_id != null ? `SWITCHROOM_PENDING_USER_MSG_ID=${pending2.last_user_msg_id}` : `SWITCHROOM_PENDING_USER_MSG_ID=`,
|
|
103550
|
-
`SWITCHROOM_PENDING_ENDED_VIA=${pending2.ended_via ?? "unknown"}`,
|
|
103551
|
-
`SWITCHROOM_PENDING_STARTED_AT=${pending2.started_at}`,
|
|
103552
|
-
pending2.interrupt_reason != null ? `SWITCHROOM_PENDING_INTERRUPT_REASON=${pending2.interrupt_reason}` : `SWITCHROOM_PENDING_INTERRUPT_REASON=`
|
|
103553
|
-
];
|
|
103554
|
-
const pendingEnvTmp = `${pendingEnvPath}.tmp-${process.pid}`;
|
|
103555
|
-
writeFileSync50(pendingEnvTmp, lines.join(`
|
|
103556
|
-
`) + `
|
|
103557
|
-
`, { mode: 384 });
|
|
103558
|
-
renameSync27(pendingEnvTmp, pendingEnvPath);
|
|
103559
|
-
process.stderr.write(`telegram gateway: pending-turn env written to ${pendingEnvPath} turnKey=${pending2.turn_key} endedVia=${pending2.ended_via ?? "open"}
|
|
103560
|
-
`);
|
|
103561
|
-
} else if (existsSync58(pendingEnvPath)) {
|
|
103562
|
-
rmSync8(pendingEnvPath, { force: true });
|
|
103563
|
-
process.stderr.write(`telegram gateway: pending-turn env cleared (clean previous shutdown)
|
|
103564
|
-
`);
|
|
103565
|
-
}
|
|
103566
|
-
} catch (err) {
|
|
103567
|
-
process.stderr.write(`telegram gateway: pending-turn env write failed (${err.message})
|
|
103568
|
-
`);
|
|
103569
|
-
}
|
|
104457
|
+
writePendingTurnEnv(agentDir, pending2);
|
|
103570
104458
|
} catch (err) {
|
|
103571
104459
|
process.stderr.write(`telegram gateway: turn-registry init failed (${err.message}) \u2014 turn tracking disabled
|
|
103572
104460
|
`);
|
|
@@ -103666,11 +104554,11 @@ function checkApprovals() {
|
|
|
103666
104554
|
return;
|
|
103667
104555
|
}
|
|
103668
104556
|
for (const senderId of files) {
|
|
103669
|
-
const file =
|
|
103670
|
-
bot.api.sendMessage(senderId, "Paired! Say hi to Claude.").then(() =>
|
|
104557
|
+
const file = join70(APPROVED_DIR, senderId);
|
|
104558
|
+
bot.api.sendMessage(senderId, "Paired! Say hi to Claude.").then(() => rmSync9(file, { force: true }), (err) => {
|
|
103671
104559
|
process.stderr.write(`telegram gateway: failed to send approval confirm: ${err}
|
|
103672
104560
|
`);
|
|
103673
|
-
|
|
104561
|
+
rmSync9(file, { force: true });
|
|
103674
104562
|
});
|
|
103675
104563
|
}
|
|
103676
104564
|
}
|
|
@@ -103844,12 +104732,12 @@ function noteAgentOutputAt(key, ts) {
|
|
|
103844
104732
|
lastAgentOutputAt.delete(oldest);
|
|
103845
104733
|
}
|
|
103846
104734
|
}
|
|
103847
|
-
var OBLIGATION_STORE_PATH =
|
|
104735
|
+
var OBLIGATION_STORE_PATH = join70(STATE_DIR, "obligations.json");
|
|
103848
104736
|
var obligationStoreFs = {
|
|
103849
|
-
readFileSync: (p) =>
|
|
103850
|
-
writeFileSync: (p, d) =>
|
|
103851
|
-
renameSync: (a, b) =>
|
|
103852
|
-
existsSync: (p) =>
|
|
104737
|
+
readFileSync: (p) => readFileSync62(p, "utf8"),
|
|
104738
|
+
writeFileSync: (p, d) => writeFileSync52(p, d),
|
|
104739
|
+
renameSync: (a, b) => renameSync28(a, b),
|
|
104740
|
+
existsSync: (p) => existsSync60(p),
|
|
103853
104741
|
fsyncFileSync: fsyncPathSync,
|
|
103854
104742
|
fsyncDirSync: fsyncPathSync,
|
|
103855
104743
|
unlinkSync: unlinkSync31
|
|
@@ -104610,7 +105498,7 @@ function emitTurnRecord(turn, endedAt) {
|
|
|
104610
105498
|
return;
|
|
104611
105499
|
}
|
|
104612
105500
|
},
|
|
104613
|
-
rename: (from, to) =>
|
|
105501
|
+
rename: (from, to) => renameSync28(from, to)
|
|
104614
105502
|
});
|
|
104615
105503
|
appendFileSync9(turnsPath, rec);
|
|
104616
105504
|
} catch {}
|
|
@@ -105930,6 +106818,10 @@ var inboundCoalescer = createInboundCoalescer({
|
|
|
105930
106818
|
function emitGatewayOperatorEvent(event) {
|
|
105931
106819
|
const { agent, kind } = event;
|
|
105932
106820
|
event = { ...event, detail: redactOutboundText(event.detail, "operator_event") };
|
|
106821
|
+
if (kind === "transport-transient") {
|
|
106822
|
+
emitTransportTransientEvent(event, userFailureNoticeDeps());
|
|
106823
|
+
return;
|
|
106824
|
+
}
|
|
105933
106825
|
let throttleEscalation = null;
|
|
105934
106826
|
let escalationFired = false;
|
|
105935
106827
|
let rateLimitedCooldownConsulted = false;
|
|
@@ -106084,40 +106976,37 @@ function emitGatewayOperatorEvent(event) {
|
|
|
106084
106976
|
});
|
|
106085
106977
|
}
|
|
106086
106978
|
if (userNoticeChats.length > 0) {
|
|
106087
|
-
const
|
|
106088
|
-
const noticeKey =
|
|
106089
|
-
|
|
106090
|
-
chatIds: userNoticeChats,
|
|
106091
|
-
text: renderUserFacingFailureNotice(),
|
|
106092
|
-
agent,
|
|
106093
|
-
kind,
|
|
106094
|
-
atMs: Date.now(),
|
|
106095
|
-
key: noticeKey
|
|
106096
|
-
});
|
|
106979
|
+
const noticeDeps = userFailureNoticeDeps();
|
|
106980
|
+
const noticeKey = noticeDeps.liveTurnKey();
|
|
106981
|
+
noticeDeps.scheduleUserNotice({ chatIds: userNoticeChats, agent, kind, key: noticeKey, atMs: Date.now() });
|
|
106097
106982
|
process.stderr.write(`telegram gateway: operator-event user-notice deferred to turn-end agent=${agent} kind=${kind} chats=${userNoticeChats.length} topic=${noticeKey ?? "-"}
|
|
106098
106983
|
`);
|
|
106099
106984
|
}
|
|
106100
106985
|
}
|
|
106986
|
+
function userFailureNoticeDeps() {
|
|
106987
|
+
return {
|
|
106988
|
+
now: () => Date.now(),
|
|
106989
|
+
allowFrom: () => loadAccess().allowFrom,
|
|
106990
|
+
liveTurnKey: () => currentTurn != null ? statusKey(currentTurn.sessionChatId, currentTurn.sessionThreadId) : undefined,
|
|
106991
|
+
record: (e) => {
|
|
106992
|
+
try {
|
|
106993
|
+
recordOperatorEvent(e);
|
|
106994
|
+
} catch {}
|
|
106995
|
+
},
|
|
106996
|
+
scheduleUserNotice: (i) => pendingUserNoticeGate.schedule({ ...i, text: renderUserFacingFailureNotice() }),
|
|
106997
|
+
resolveNotices: (delivered, key) => pendingUserNoticeGate.resolveTurnEnd(key, delivered),
|
|
106998
|
+
send: (chat_id, text5, keyboard) => {
|
|
106999
|
+
const thread = topicForRecipient({ recipientChatId: chat_id, resolvedTopic: resolveAgentOutboundTopic({ kind: "compact-watchdog" }), supergroupChatId: resolveAgentSupergroupChatId() });
|
|
107000
|
+
const opts = { ...keyboard ? { reply_markup: keyboard } : {}, ...thread != null ? { message_thread_id: thread } : {} };
|
|
107001
|
+
bot.api.sendRichMessage(chat_id, richMessage2(text5), opts).catch((e) => process.stderr.write(`telegram gateway: user-failure-notice send to ${chat_id} failed: ${e}
|
|
107002
|
+
`));
|
|
107003
|
+
},
|
|
107004
|
+
log: (m) => process.stderr.write(`telegram gateway: ${m}
|
|
107005
|
+
`)
|
|
107006
|
+
};
|
|
107007
|
+
}
|
|
106101
107008
|
function flushPendingUserFailureNotices(turnDeliveredReply, turnKey3) {
|
|
106102
|
-
|
|
106103
|
-
if (notices.length === 0)
|
|
106104
|
-
return;
|
|
106105
|
-
const noticeTopic = resolveAgentOutboundTopic({ kind: "compact-watchdog" });
|
|
106106
|
-
const noticeSupergroup = resolveAgentSupergroupChatId();
|
|
106107
|
-
for (const notice of notices) {
|
|
106108
|
-
process.stderr.write(`telegram gateway: user-notice flush (turn died reply-less) agent=${notice.agent} kind=${notice.kind} chats=${notice.chatIds.length}
|
|
106109
|
-
`);
|
|
106110
|
-
for (const chat_id of notice.chatIds) {
|
|
106111
|
-
const thread = topicForRecipient({ recipientChatId: chat_id, resolvedTopic: noticeTopic, supergroupChatId: noticeSupergroup });
|
|
106112
|
-
const opts = {
|
|
106113
|
-
...thread != null ? { message_thread_id: thread } : {}
|
|
106114
|
-
};
|
|
106115
|
-
bot.api.sendRichMessage(chat_id, richMessage2(notice.text), opts).catch((e) => {
|
|
106116
|
-
process.stderr.write(`telegram gateway: user-notice send to ${chat_id} failed agent=${notice.agent} kind=${notice.kind}: ${e}
|
|
106117
|
-
`);
|
|
106118
|
-
});
|
|
106119
|
-
}
|
|
106120
|
-
}
|
|
107009
|
+
flushDeferredUserNotices(turnDeliveredReply, turnKey3, userFailureNoticeDeps());
|
|
106121
107010
|
}
|
|
106122
107011
|
function postLegacyBanner(chatId, threadId, ackMessageId, ageSec, site) {
|
|
106123
107012
|
const text5 = `\uD83C\uDF9B\uFE0F Switchroom restarted \u2014 ready. (took ~${ageSec}s)`;
|
|
@@ -106173,28 +107062,28 @@ var PIN_STATUS_WHILE_WORKING = (() => {
|
|
|
106173
107062
|
})();
|
|
106174
107063
|
var statusPinClaims = new Map;
|
|
106175
107064
|
var statusPinRightsCache = new PinRightsCache2;
|
|
106176
|
-
var STATUS_PIN_STORE_PATH =
|
|
107065
|
+
var STATUS_PIN_STORE_PATH = join70(STATE_DIR, "status-pins.json");
|
|
106177
107066
|
var statusPinStoreFs = {
|
|
106178
|
-
readFileSync: (p) =>
|
|
106179
|
-
writeFileSync: (p, d) =>
|
|
106180
|
-
renameSync: (a, b) =>
|
|
106181
|
-
existsSync: (p) =>
|
|
107067
|
+
readFileSync: (p) => readFileSync62(p, "utf8"),
|
|
107068
|
+
writeFileSync: (p, d) => writeFileSync52(p, d),
|
|
107069
|
+
renameSync: (a, b) => renameSync28(a, b),
|
|
107070
|
+
existsSync: (p) => existsSync60(p)
|
|
106182
107071
|
};
|
|
106183
107072
|
var statusPinPersistEnabled = !STATIC && PIN_STATUS_WHILE_WORKING;
|
|
106184
|
-
var ACTIVITY_CARD_STORE_PATH =
|
|
107073
|
+
var ACTIVITY_CARD_STORE_PATH = join70(STATE_DIR, "activity-cards-pending.json");
|
|
106185
107074
|
var activityCardStoreFs = {
|
|
106186
|
-
readFileSync: (p) =>
|
|
106187
|
-
writeFileSync: (p, d) =>
|
|
106188
|
-
renameSync: (a, b) =>
|
|
106189
|
-
existsSync: (p) =>
|
|
107075
|
+
readFileSync: (p) => readFileSync62(p, "utf8"),
|
|
107076
|
+
writeFileSync: (p, d) => writeFileSync52(p, d),
|
|
107077
|
+
renameSync: (a, b) => renameSync28(a, b),
|
|
107078
|
+
existsSync: (p) => existsSync60(p)
|
|
106190
107079
|
};
|
|
106191
107080
|
var activityCardPersistEnabled = !STATIC;
|
|
106192
|
-
var QUEUED_CARD_STORE_PATH =
|
|
107081
|
+
var QUEUED_CARD_STORE_PATH = join70(STATE_DIR, "queued-cards-pending.json");
|
|
106193
107082
|
var queuedCardStoreFs = {
|
|
106194
|
-
readFileSync: (p) =>
|
|
106195
|
-
writeFileSync: (p, d) =>
|
|
106196
|
-
renameSync: (a, b) =>
|
|
106197
|
-
existsSync: (p) =>
|
|
107083
|
+
readFileSync: (p) => readFileSync62(p, "utf8"),
|
|
107084
|
+
writeFileSync: (p, d) => writeFileSync52(p, d),
|
|
107085
|
+
renameSync: (a, b) => renameSync28(a, b),
|
|
107086
|
+
existsSync: (p) => existsSync60(p)
|
|
106198
107087
|
};
|
|
106199
107088
|
var queuedCardPersistEnabled = !STATIC;
|
|
106200
107089
|
function persistQueuedCard(key, chatId, threadId, messageId) {
|
|
@@ -106481,7 +107370,7 @@ async function unpinAllStatusPins() {
|
|
|
106481
107370
|
}
|
|
106482
107371
|
}
|
|
106483
107372
|
var stalePinSweepEligible = false;
|
|
106484
|
-
var STALE_PIN_SWEEP_STORE_PATH =
|
|
107373
|
+
var STALE_PIN_SWEEP_STORE_PATH = join70(STATE_DIR, "stale-pin-sweep.json");
|
|
106485
107374
|
var stalePinSweeper = createGatewayStalePinSweeper({
|
|
106486
107375
|
telegram: { handle: () => lockedBot, call: robustApiCall },
|
|
106487
107376
|
claims: () => statusPinClaims.values(),
|
|
@@ -106490,9 +107379,9 @@ var stalePinSweeper = createGatewayStalePinSweeper({
|
|
|
106490
107379
|
store: {
|
|
106491
107380
|
path: STALE_PIN_SWEEP_STORE_PATH,
|
|
106492
107381
|
fs: {
|
|
106493
|
-
readFileSync: (p) =>
|
|
107382
|
+
readFileSync: (p) => readFileSync62(p, "utf-8"),
|
|
106494
107383
|
writeFileSync: (p, data) => atomicWriteFileSync(p, data, 384),
|
|
106495
|
-
existsSync: (p) =>
|
|
107384
|
+
existsSync: (p) => existsSync60(p)
|
|
106496
107385
|
}
|
|
106497
107386
|
},
|
|
106498
107387
|
allowUnpinAllForumTopic: process.env.SWITCHROOM_PIN_SWEEP_UNPIN_ALL_TOPIC == null ? undefined : process.env.SWITCHROOM_PIN_SWEEP_UNPIN_ALL_TOPIC === "1"
|
|
@@ -106522,12 +107411,12 @@ var getPinnedProgressCardMessageId = null;
|
|
|
106522
107411
|
var completeProgressCardTurn = null;
|
|
106523
107412
|
var subagentWatcher = null;
|
|
106524
107413
|
var workerActivityFeed = null;
|
|
106525
|
-
var SOCKET_PATH = process.env.SWITCHROOM_GATEWAY_SOCKET ??
|
|
107414
|
+
var SOCKET_PATH = process.env.SWITCHROOM_GATEWAY_SOCKET ?? join70(STATE_DIR, "gateway.sock");
|
|
106526
107415
|
if (isGatewayMain)
|
|
106527
107416
|
mkdirSync51(STATE_DIR, { recursive: true, mode: 448 });
|
|
106528
|
-
var GATEWAY_PID_PATH = process.env.SWITCHROOM_GATEWAY_PID_FILE ??
|
|
106529
|
-
var GATEWAY_SESSION_MARKER_PATH = process.env.SWITCHROOM_GATEWAY_SESSION_MARKER ??
|
|
106530
|
-
var GATEWAY_CLEAN_SHUTDOWN_MARKER_PATH = process.env.SWITCHROOM_GATEWAY_CLEAN_SHUTDOWN_MARKER ??
|
|
107417
|
+
var GATEWAY_PID_PATH = process.env.SWITCHROOM_GATEWAY_PID_FILE ?? join70(STATE_DIR, "gateway.pid.json");
|
|
107418
|
+
var GATEWAY_SESSION_MARKER_PATH = process.env.SWITCHROOM_GATEWAY_SESSION_MARKER ?? join70(STATE_DIR, "gateway-session.json");
|
|
107419
|
+
var GATEWAY_CLEAN_SHUTDOWN_MARKER_PATH = process.env.SWITCHROOM_GATEWAY_CLEAN_SHUTDOWN_MARKER ?? join70(STATE_DIR, "clean-shutdown.json");
|
|
106531
107420
|
var GATEWAY_STARTED_AT_MS = Date.now();
|
|
106532
107421
|
var BOOT_CARD_ENABLED = process.env.SWITCHROOM_BOOT_CARD !== "false";
|
|
106533
107422
|
var activeBootCard = null;
|
|
@@ -106556,7 +107445,7 @@ function ensureIssuesCard(chatId, threadId) {
|
|
|
106556
107445
|
bot: botApi,
|
|
106557
107446
|
log: (msg) => process.stderr.write(`telegram gateway: ${msg}
|
|
106558
107447
|
`),
|
|
106559
|
-
persistPath:
|
|
107448
|
+
persistPath: join70(stateDir, "issues-card.json")
|
|
106560
107449
|
});
|
|
106561
107450
|
activeIssuesWatcher = startIssuesWatcher({
|
|
106562
107451
|
stateDir,
|
|
@@ -106761,13 +107650,13 @@ if (isGatewayMain)
|
|
|
106761
107650
|
var inboundSpool;
|
|
106762
107651
|
if (isGatewayMain)
|
|
106763
107652
|
inboundSpool = STATIC ? undefined : createInboundSpool({
|
|
106764
|
-
path:
|
|
107653
|
+
path: join70(STATE_DIR, "inbound-spool.jsonl"),
|
|
106765
107654
|
fs: {
|
|
106766
107655
|
appendFileSync: (p, d) => appendFileSync9(p, d),
|
|
106767
|
-
readFileSync: (p) =>
|
|
106768
|
-
writeFileSync: (p, d) =>
|
|
106769
|
-
renameSync: (a, b) =>
|
|
106770
|
-
existsSync: (p) =>
|
|
107656
|
+
readFileSync: (p) => readFileSync62(p, "utf8"),
|
|
107657
|
+
writeFileSync: (p, d) => writeFileSync52(p, d),
|
|
107658
|
+
renameSync: (a, b) => renameSync28(a, b),
|
|
107659
|
+
existsSync: (p) => existsSync60(p),
|
|
106771
107660
|
statSizeSync: (p) => statSync23(p).size,
|
|
106772
107661
|
fsyncFileSync: fsyncPathSync,
|
|
106773
107662
|
fsyncDirSync: fsyncPathSync
|
|
@@ -106831,13 +107720,13 @@ async function maybeRedeliverUndeliveredAnswer() {
|
|
|
106831
107720
|
let transcriptText;
|
|
106832
107721
|
try {
|
|
106833
107722
|
const projectsDir = getProjectsDirForCwd();
|
|
106834
|
-
const path3 =
|
|
106835
|
-
if (!
|
|
107723
|
+
const path3 = join70(projectsDir, `${sessionId}.jsonl`);
|
|
107724
|
+
if (!existsSync60(path3)) {
|
|
106836
107725
|
process.stderr.write(`telegram gateway: crash-redelivery \u2014 transcript not found for turnKey=${turn.turn_key} session=${sessionId} (${path3}); skipping
|
|
106837
107726
|
`);
|
|
106838
107727
|
return;
|
|
106839
107728
|
}
|
|
106840
|
-
transcriptText =
|
|
107729
|
+
transcriptText = readFileSync62(path3, "utf8");
|
|
106841
107730
|
} catch (err) {
|
|
106842
107731
|
process.stderr.write(`telegram gateway: crash-redelivery \u2014 transcript read failed turnKey=${turn.turn_key}: ${err.message}
|
|
106843
107732
|
`);
|
|
@@ -106907,6 +107796,14 @@ function obligationSweep() {
|
|
|
106907
107796
|
if (isGatewayMain && !STATIC && OBLIGATION_LEDGER_ENABLED) {
|
|
106908
107797
|
setInterval(obligationSweep, OBLIGATION_SWEEP_MS).unref();
|
|
106909
107798
|
}
|
|
107799
|
+
if (isGatewayMain && HISTORY_ENABLED) {
|
|
107800
|
+
maybeQueueBootBriefing({
|
|
107801
|
+
env: process.env,
|
|
107802
|
+
stateDir: STATE_DIR,
|
|
107803
|
+
resumeMsg: bootResumeInbound?.msg ?? null,
|
|
107804
|
+
put: (agent, msg) => inboundSpool != null ? inboundSpool.put(agent, msg) : pendingInboundBuffer.push(agent, msg)
|
|
107805
|
+
});
|
|
107806
|
+
}
|
|
106910
107807
|
if (isGatewayMain && bootResumeInbound != null) {
|
|
106911
107808
|
if (inboundSpool != null) {
|
|
106912
107809
|
inboundSpool.put(bootResumeInbound.agent, bootResumeInbound.msg);
|
|
@@ -106996,8 +107893,8 @@ var bridgeDeadWatchdog = createBridgeDeadWatchdog({
|
|
|
106996
107893
|
isSessionAlive: () => findAgentProcessInContainer2()?.comm === "claude",
|
|
106997
107894
|
isShuttingDown: () => shuttingDown,
|
|
106998
107895
|
escalate: (reason) => triggerSelfRestart(process.env.SWITCHROOM_AGENT_NAME ?? "", reason, 1500),
|
|
106999
|
-
crashLogPath:
|
|
107000
|
-
markerPath:
|
|
107896
|
+
crashLogPath: join70(STATE_DIR, "bridge-crash.log"),
|
|
107897
|
+
markerPath: join70(STATE_DIR, "bridge-dead-escalation.json"),
|
|
107001
107898
|
log: (line) => process.stderr.write(`${line}
|
|
107002
107899
|
`),
|
|
107003
107900
|
priorStreak: bridgeDeadPriorStreak,
|
|
@@ -107103,8 +108000,8 @@ if (isGatewayMain)
|
|
|
107103
108000
|
probeQuotaViaBroker: (t) => probeQuotaForBootCard(agentSlug, t),
|
|
107104
108001
|
tmuxSupervisor: process.env.SWITCHROOM_TMUX_SUPERVISOR === "1",
|
|
107105
108002
|
dockerMode: process.env.SWITCHROOM_RUNTIME === "docker",
|
|
107106
|
-
configSnapshotPath:
|
|
107107
|
-
bootCardStatePath:
|
|
108003
|
+
configSnapshotPath: join70(resolvedAgentDirForCard, ".config-snapshot.json"),
|
|
108004
|
+
bootCardStatePath: join70(resolvedAgentDirForCard, ".boot-card-msgid.json"),
|
|
107108
108005
|
floodStatePath: FLOOD_STATE_PATH,
|
|
107109
108006
|
...updateOutcomeLine ? { updateOutcomeLine } : {}
|
|
107110
108007
|
}, ackMsgId).then((handle) => {
|
|
@@ -107753,9 +108650,12 @@ if (isGatewayMain)
|
|
|
107753
108650
|
process.stderr.write(`telegram gateway: post_skill_proposal agent=${msg.agentName} chat=${msg.chatId} proposal=${proposal.id} slug=${proposal.skill_slug} new=${proposal.is_new}
|
|
107754
108651
|
`);
|
|
107755
108652
|
},
|
|
108653
|
+
onBuzzPublishResult: (_c, m) => getBuzzMirror()?.onPublishResult(m),
|
|
107756
108654
|
log: (msg) => process.stderr.write(`telegram gateway: ipc \u2014 ${msg}
|
|
107757
108655
|
`)
|
|
107758
108656
|
});
|
|
108657
|
+
if (isGatewayMain)
|
|
108658
|
+
maybeBootBuzzMirror((msg) => ipcServer.sendToBuzzPeer(msg));
|
|
107759
108659
|
if (isGatewayMain)
|
|
107760
108660
|
(() => {
|
|
107761
108661
|
try {
|
|
@@ -107781,7 +108681,7 @@ if (isGatewayMain)
|
|
|
107781
108681
|
const receiverUid = receiverUidRaw ? Number(receiverUidRaw) : NaN;
|
|
107782
108682
|
if (Number.isInteger(receiverUid))
|
|
107783
108683
|
allowedUids.push(receiverUid);
|
|
107784
|
-
const socketPath =
|
|
108684
|
+
const socketPath = join70(STATE_DIR, "webhook.sock");
|
|
107785
108685
|
const webhookInject = (agentName3, inbound) => {
|
|
107786
108686
|
const msg = inbound;
|
|
107787
108687
|
const delivered = ipcServer.sendToAgent(agentName3, msg);
|
|
@@ -108032,9 +108932,9 @@ function redactOutboundText(text5, site) {
|
|
|
108032
108932
|
var VOICE_OUT_DEFAULT_CHUNK_CHARS = 600;
|
|
108033
108933
|
var VOICE_OUT_HARD_CHUNK_CAP = 4096;
|
|
108034
108934
|
var voiceOnDemandCache = new VoiceOnDemandCache({
|
|
108035
|
-
persistPath:
|
|
108935
|
+
persistPath: join70(STATE_DIR, "voice-ondemand.json")
|
|
108036
108936
|
});
|
|
108037
|
-
var VOICE_CACHE_DIR =
|
|
108937
|
+
var VOICE_CACHE_DIR = join70(STATE_DIR, "voice-cache");
|
|
108038
108938
|
var voicePreSynthQueue = new PreSynthQueue({
|
|
108039
108939
|
runJob: async (job) => {
|
|
108040
108940
|
const sidecarToken = await materializeSidecarToken2();
|
|
@@ -108190,6 +109090,7 @@ function gatewaySendReplyDeps() {
|
|
|
108190
109090
|
resolveReplyOwnerTurn,
|
|
108191
109091
|
findTurnByOriginId,
|
|
108192
109092
|
findTurnByQuotedMessageId,
|
|
109093
|
+
findLatestTurnForChat,
|
|
108193
109094
|
resolveAnswerThreadWithLog,
|
|
108194
109095
|
resolveThreadId,
|
|
108195
109096
|
getLatestInboundMessageId,
|
|
@@ -108441,11 +109342,11 @@ async function executeSendGif(rawArgs) {
|
|
|
108441
109342
|
};
|
|
108442
109343
|
}
|
|
108443
109344
|
async function publishToTelegraph(text5, shortName, authorName) {
|
|
108444
|
-
const accountPath =
|
|
109345
|
+
const accountPath = join70(STATE_DIR, "telegraph-account.json");
|
|
108445
109346
|
let account = null;
|
|
108446
109347
|
try {
|
|
108447
|
-
if (
|
|
108448
|
-
const raw =
|
|
109348
|
+
if (existsSync60(accountPath)) {
|
|
109349
|
+
const raw = readFileSync62(accountPath, "utf-8");
|
|
108449
109350
|
const parsed = JSON.parse(raw);
|
|
108450
109351
|
if (parsed.shortName && parsed.accessToken) {
|
|
108451
109352
|
account = parsed;
|
|
@@ -108465,7 +109366,7 @@ async function publishToTelegraph(text5, shortName, authorName) {
|
|
|
108465
109366
|
account = created.value;
|
|
108466
109367
|
try {
|
|
108467
109368
|
mkdirSync51(STATE_DIR, { recursive: true, mode: 448 });
|
|
108468
|
-
|
|
109369
|
+
writeFileSync52(accountPath, JSON.stringify(account, null, 2), { mode: 384 });
|
|
108469
109370
|
} catch (err) {
|
|
108470
109371
|
process.stderr.write(`telegram gateway: telegraph cache write failed: ${err.message}
|
|
108471
109372
|
`);
|
|
@@ -108581,7 +109482,7 @@ _The secret was NOT saved. The agent can re-request with \`request_secret\`._`,
|
|
|
108581
109482
|
}
|
|
108582
109483
|
function readLiveSwitchroomConfigText() {
|
|
108583
109484
|
const cfgPath = process.env.SWITCHROOM_CONFIG ?? findConfigFile2();
|
|
108584
|
-
return
|
|
109485
|
+
return readFileSync62(cfgPath, "utf8");
|
|
108585
109486
|
}
|
|
108586
109487
|
async function executeReact(args) {
|
|
108587
109488
|
if (!args.chat_id)
|
|
@@ -108622,7 +109523,7 @@ async function executeDownloadAttachment(args) {
|
|
|
108622
109523
|
});
|
|
108623
109524
|
mkdirSync51(INBOX_DIR, { recursive: true, mode: 448 });
|
|
108624
109525
|
assertInsideInbox2(INBOX_DIR, dlPath);
|
|
108625
|
-
|
|
109526
|
+
writeFileSync52(dlPath, buf, { mode: 384 });
|
|
108626
109527
|
return { content: [{ type: "text", text: dlPath }] };
|
|
108627
109528
|
}
|
|
108628
109529
|
async function executeEditMessage(args) {
|
|
@@ -108661,6 +109562,7 @@ async function executeEditMessage(args) {
|
|
|
108661
109562
|
`);
|
|
108662
109563
|
}
|
|
108663
109564
|
}
|
|
109565
|
+
getBuzzMirror()?.mirrorCorrection({ telegramMessageKey: `${String(args.chat_id ?? "")}:${Number(args.message_id)}`, scrubbedText: editRawText });
|
|
108664
109566
|
return { content: [{ type: "text", text: `edited (id: ${id})` }] };
|
|
108665
109567
|
}
|
|
108666
109568
|
async function executeSendTyping(args) {
|
|
@@ -109996,14 +110898,14 @@ function restartMarkerPath() {
|
|
|
109996
110898
|
const agentDir = resolveAgentDirFromEnv();
|
|
109997
110899
|
if (!agentDir)
|
|
109998
110900
|
return null;
|
|
109999
|
-
return
|
|
110901
|
+
return join70(agentDir, "restart-pending.json");
|
|
110000
110902
|
}
|
|
110001
110903
|
function writeRestartMarker(marker) {
|
|
110002
110904
|
const p = restartMarkerPath();
|
|
110003
110905
|
if (!p)
|
|
110004
110906
|
return;
|
|
110005
110907
|
try {
|
|
110006
|
-
|
|
110908
|
+
writeFileSync52(p, JSON.stringify(marker));
|
|
110007
110909
|
lastPlannedRestartAt = Date.now();
|
|
110008
110910
|
process.stderr.write(`telegram gateway: restart-marker: write chat_id=${marker.chat_id} thread_id=${marker.thread_id ?? "-"} ack=${marker.ack_message_id ?? "-"} path=${p}
|
|
110009
110911
|
`);
|
|
@@ -110022,7 +110924,7 @@ function readRestartMarker() {
|
|
|
110022
110924
|
if (!p)
|
|
110023
110925
|
return null;
|
|
110024
110926
|
try {
|
|
110025
|
-
return JSON.parse(
|
|
110927
|
+
return JSON.parse(readFileSync62(p, "utf8"));
|
|
110026
110928
|
} catch {
|
|
110027
110929
|
return null;
|
|
110028
110930
|
}
|
|
@@ -110032,7 +110934,7 @@ function clearRestartMarker() {
|
|
|
110032
110934
|
if (!p)
|
|
110033
110935
|
return;
|
|
110034
110936
|
try {
|
|
110035
|
-
|
|
110937
|
+
rmSync9(p, { force: true });
|
|
110036
110938
|
process.stderr.write(`telegram gateway: restart-marker: cleared path=${p}
|
|
110037
110939
|
`);
|
|
110038
110940
|
} catch {}
|
|
@@ -110171,7 +111073,7 @@ var _dockerReachable;
|
|
|
110171
111073
|
function isDockerReachable() {
|
|
110172
111074
|
if (_dockerReachable !== undefined)
|
|
110173
111075
|
return _dockerReachable;
|
|
110174
|
-
if (!
|
|
111076
|
+
if (!existsSync60("/var/run/docker.sock")) {
|
|
110175
111077
|
_dockerReachable = false;
|
|
110176
111078
|
return _dockerReachable;
|
|
110177
111079
|
}
|
|
@@ -110188,12 +111090,12 @@ function _resetDockerReachableCache() {
|
|
|
110188
111090
|
}
|
|
110189
111091
|
function spawnSwitchroomDetached(args, onFailure) {
|
|
110190
111092
|
const fullArgs = SWITCHROOM_CONFIG ? ["--config", SWITCHROOM_CONFIG, ...args] : args;
|
|
110191
|
-
const logPath =
|
|
111093
|
+
const logPath = join70(STATE_DIR, "detached-spawn.log");
|
|
110192
111094
|
let outFd = null;
|
|
110193
111095
|
try {
|
|
110194
111096
|
mkdirSync51(STATE_DIR, { recursive: true });
|
|
110195
111097
|
outFd = openSync15(logPath, "a");
|
|
110196
|
-
|
|
111098
|
+
writeFileSync52(logPath, `
|
|
110197
111099
|
[${new Date().toISOString()}] spawn ${SWITCHROOM_CLI} ${fullArgs.join(" ")}
|
|
110198
111100
|
`, { flag: "a" });
|
|
110199
111101
|
} catch {}
|
|
@@ -110219,7 +111121,7 @@ function spawnSwitchroomDetached(args, onFailure) {
|
|
|
110219
111121
|
return;
|
|
110220
111122
|
let tail = "";
|
|
110221
111123
|
try {
|
|
110222
|
-
const full =
|
|
111124
|
+
const full = readFileSync62(logPath, "utf8");
|
|
110223
111125
|
tail = full.split(`
|
|
110224
111126
|
`).slice(-30).join(`
|
|
110225
111127
|
`).trim();
|
|
@@ -110481,10 +111383,10 @@ ${preBlock(formatSwitchroomOutput(detail))}`, { html: true });
|
|
|
110481
111383
|
}
|
|
110482
111384
|
function readRecentDenialsForAgent(agentName3, windowMs, limit) {
|
|
110483
111385
|
try {
|
|
110484
|
-
const auditPath =
|
|
110485
|
-
if (!
|
|
111386
|
+
const auditPath = join70(homedir20(), ".switchroom", "vault-audit.log");
|
|
111387
|
+
if (!existsSync60(auditPath))
|
|
110486
111388
|
return [];
|
|
110487
|
-
const raw =
|
|
111389
|
+
const raw = readFileSync62(auditPath, "utf8");
|
|
110488
111390
|
return recentDenialsFromAuditLog(raw, { agentName: agentName3, windowMs, limit });
|
|
110489
111391
|
} catch {
|
|
110490
111392
|
return [];
|
|
@@ -110535,7 +111437,7 @@ async function buildAgentMetadata(agentName3) {
|
|
|
110535
111437
|
try {
|
|
110536
111438
|
const agentDir = resolveAgentDirFromEnv();
|
|
110537
111439
|
if (agentDir) {
|
|
110538
|
-
const raw =
|
|
111440
|
+
const raw = readFileSync62(join70(agentDir, ".claude", ".claude.json"), "utf8");
|
|
110539
111441
|
claudeJson = JSON.parse(raw);
|
|
110540
111442
|
}
|
|
110541
111443
|
} catch {}
|
|
@@ -110664,7 +111566,7 @@ function buildModelDeps(restartCtx) {
|
|
|
110664
111566
|
try {
|
|
110665
111567
|
const agentDir = resolveAgentDirFromEnv();
|
|
110666
111568
|
if (agentDir) {
|
|
110667
|
-
const local = await fetchQuota2({ claudeConfigDir:
|
|
111569
|
+
const local = await fetchQuota2({ claudeConfigDir: join70(agentDir, ".claude") });
|
|
110668
111570
|
if (local.ok)
|
|
110669
111571
|
return formatQuotaLine2(local.data);
|
|
110670
111572
|
}
|
|
@@ -110911,9 +111813,9 @@ function effortMenuReplyMarkup(reply) {
|
|
|
110911
111813
|
function flushAgentHandoff(agentDir) {
|
|
110912
111814
|
let removed = 0;
|
|
110913
111815
|
for (const fname of [".handoff.md", ".handoff-topic"]) {
|
|
110914
|
-
const p =
|
|
111816
|
+
const p = join70(agentDir, fname);
|
|
110915
111817
|
try {
|
|
110916
|
-
if (
|
|
111818
|
+
if (existsSync60(p)) {
|
|
110917
111819
|
unlinkSync31(p);
|
|
110918
111820
|
removed++;
|
|
110919
111821
|
}
|
|
@@ -110969,7 +111871,7 @@ async function handleNewCommand(ctx) {
|
|
|
110969
111871
|
writeRestartMarker({ chat_id: chatId, thread_id: threadId ?? null, ack_message_id: ackId, ts: Date.now() });
|
|
110970
111872
|
if (agentDir != null) {
|
|
110971
111873
|
try {
|
|
110972
|
-
|
|
111874
|
+
writeFileSync52(join70(agentDir, ".force-fresh-session"), `${kind} at ${new Date().toISOString()}
|
|
110973
111875
|
`, "utf8");
|
|
110974
111876
|
} catch (err) {
|
|
110975
111877
|
process.stderr.write(`telegram gateway: failed to write force-fresh marker: ${err}
|
|
@@ -111082,16 +111984,16 @@ function buildFolderPickerDeps() {
|
|
|
111082
111984
|
};
|
|
111083
111985
|
}
|
|
111084
111986
|
var lockoutOps = {
|
|
111085
|
-
readFileSync: (p, enc) =>
|
|
111086
|
-
writeFileSync: (p, data, opts) =>
|
|
111087
|
-
existsSync: (p) =>
|
|
111987
|
+
readFileSync: (p, enc) => readFileSync62(p, enc),
|
|
111988
|
+
writeFileSync: (p, data, opts) => writeFileSync52(p, data, opts),
|
|
111989
|
+
existsSync: (p) => existsSync60(p),
|
|
111088
111990
|
mkdirSync: (p, opts) => mkdirSync51(p, opts),
|
|
111089
|
-
joinPath: (...parts) =>
|
|
111991
|
+
joinPath: (...parts) => join70(...parts)
|
|
111090
111992
|
};
|
|
111091
111993
|
var FLEET_FALLBACK_DEDUP_MS = 30000;
|
|
111092
111994
|
function isAuthBrokerSocketReachable() {
|
|
111093
111995
|
try {
|
|
111094
|
-
return
|
|
111996
|
+
return existsSync60(resolveAuthBrokerSocketPath2());
|
|
111095
111997
|
} catch {
|
|
111096
111998
|
return false;
|
|
111097
111999
|
}
|
|
@@ -111346,7 +112248,7 @@ async function runCreditWatch() {
|
|
|
111346
112248
|
if (!agentDir)
|
|
111347
112249
|
return;
|
|
111348
112250
|
const agentName3 = getMyAgentName();
|
|
111349
|
-
const claudeConfigDir =
|
|
112251
|
+
const claudeConfigDir = join70(agentDir, ".claude");
|
|
111350
112252
|
const stateDir = STATE_DIR;
|
|
111351
112253
|
const reason = readClaudeJsonOverage(claudeConfigDir);
|
|
111352
112254
|
const prev = loadCreditState(stateDir);
|
|
@@ -113102,7 +114004,7 @@ Send \`/auth ${parsed.provider} cancel\` to abort.`, { html: true });
|
|
|
113102
114004
|
await switchroomReply(ctx, "**/usage:** cannot resolve agent dir.", { html: true });
|
|
113103
114005
|
return;
|
|
113104
114006
|
}
|
|
113105
|
-
const result = await fetchQuota2({ claudeConfigDir:
|
|
114007
|
+
const result = await fetchQuota2({ claudeConfigDir: join70(agentDir, ".claude") });
|
|
113106
114008
|
if (!result.ok) {
|
|
113107
114009
|
await switchroomReply(ctx, `**/usage:** ${escapeHtmlForTg2(result.reason)}`, { html: true });
|
|
113108
114010
|
return;
|
|
@@ -113489,7 +114391,7 @@ ${interimLabel}` : interimLabel
|
|
|
113489
114391
|
const unifiedDiff = (() => {
|
|
113490
114392
|
try {
|
|
113491
114393
|
const cfgPath = process.env.SWITCHROOM_CONFIG ?? SWITCHROOM_CONFIG ?? findConfigFile2();
|
|
113492
|
-
const raw =
|
|
114394
|
+
const raw = readFileSync62(cfgPath, "utf8");
|
|
113493
114395
|
return synthesizeAllowRuleDiff({ agentName: agentName3, rule: chosen.rule, configText: raw });
|
|
113494
114396
|
} catch (err) {
|
|
113495
114397
|
process.stderr.write(`telegram gateway: always-allow diff synth failed: ${err.message}
|
|
@@ -114358,7 +115260,7 @@ async function startGateway() {
|
|
|
114358
115260
|
return;
|
|
114359
115261
|
}
|
|
114360
115262
|
})();
|
|
114361
|
-
const resolvedAgentDirForBootCard = agentDir ??
|
|
115263
|
+
const resolvedAgentDirForBootCard = agentDir ?? join70(homedir20(), ".switchroom", "agents", agentSlug);
|
|
114362
115264
|
const handle = await startBootCard(chatId, threadId, botApiForCard, {
|
|
114363
115265
|
agentName: agentDisplayName,
|
|
114364
115266
|
agentSlug,
|
|
@@ -114372,8 +115274,8 @@ async function startGateway() {
|
|
|
114372
115274
|
probeQuotaViaBroker: (t) => probeQuotaForBootCard(agentSlug, t),
|
|
114373
115275
|
tmuxSupervisor: process.env.SWITCHROOM_TMUX_SUPERVISOR === "1",
|
|
114374
115276
|
dockerMode: process.env.SWITCHROOM_RUNTIME === "docker",
|
|
114375
|
-
configSnapshotPath:
|
|
114376
|
-
bootCardStatePath:
|
|
115277
|
+
configSnapshotPath: join70(resolvedAgentDirForBootCard, ".config-snapshot.json"),
|
|
115278
|
+
bootCardStatePath: join70(resolvedAgentDirForBootCard, ".boot-card-msgid.json"),
|
|
114377
115279
|
floodStatePath: FLOOD_STATE_PATH,
|
|
114378
115280
|
...updateOutcomeLine ? { updateOutcomeLine } : {}
|
|
114379
115281
|
}, ackMsgId);
|
|
@@ -114406,7 +115308,7 @@ async function startGateway() {
|
|
|
114406
115308
|
if (smAgentDir) {
|
|
114407
115309
|
const resolutionTimeoutMs = resolveSessionModelResolutionTimeoutMs(process.env.SWITCHROOM_SESSION_MODEL_RESOLUTION_TIMEOUT_MS);
|
|
114408
115310
|
const resolved = await waitForSessionModelResolution({
|
|
114409
|
-
barrierExists: () =>
|
|
115311
|
+
barrierExists: () => existsSync60(join70(smAgentDir, ".session-model-resolved")),
|
|
114410
115312
|
timeoutMs: resolutionTimeoutMs
|
|
114411
115313
|
});
|
|
114412
115314
|
if (!resolved) {
|
|
@@ -114414,10 +115316,10 @@ async function startGateway() {
|
|
|
114414
115316
|
process.stderr.write(`telegram gateway: gw /model relaunch UNRESOLVED agent=${getMyAgentName()} target=${target} (barrier timeout after ${resolutionTimeoutMs}ms)
|
|
114415
115317
|
`);
|
|
114416
115318
|
} else {
|
|
114417
|
-
const activePath =
|
|
114418
|
-
if (
|
|
115319
|
+
const activePath = join70(smAgentDir, ".active-session-model");
|
|
115320
|
+
if (existsSync60(activePath)) {
|
|
114419
115321
|
try {
|
|
114420
|
-
const launched =
|
|
115322
|
+
const launched = readFileSync62(activePath, "utf8").trim();
|
|
114421
115323
|
const configured = (() => {
|
|
114422
115324
|
const d = switchroomExecJson(["agent", "list"]);
|
|
114423
115325
|
const raw = d?.agents?.find((a) => a.name === getMyAgentName())?.model ?? null;
|
|
@@ -114450,24 +115352,24 @@ async function startGateway() {
|
|
|
114450
115352
|
deliverModelSwitchBootNotice({
|
|
114451
115353
|
...modelBootCardDeps,
|
|
114452
115354
|
confirmation,
|
|
114453
|
-
hasSessionModelAlert:
|
|
115355
|
+
hasSessionModelAlert: existsSync60(join70(smAgentDir, ".session-model-alert"))
|
|
114454
115356
|
});
|
|
114455
115357
|
}
|
|
114456
115358
|
} catch {}
|
|
114457
115359
|
}
|
|
114458
|
-
const activeEffortPath =
|
|
114459
|
-
if (
|
|
115360
|
+
const activeEffortPath = join70(smAgentDir, ".active-session-effort");
|
|
115361
|
+
if (existsSync60(activeEffortPath)) {
|
|
114460
115362
|
try {
|
|
114461
|
-
const launchedEffort =
|
|
115363
|
+
const launchedEffort = readFileSync62(activeEffortPath, "utf8").trim();
|
|
114462
115364
|
const configuredEffort = getConfiguredEffortForPersist();
|
|
114463
115365
|
sessionEffortOverride = launchedEffort.length > 0 && launchedEffort !== configuredEffort ? launchedEffort : null;
|
|
114464
115366
|
} catch {}
|
|
114465
115367
|
}
|
|
114466
|
-
const alertPath =
|
|
114467
|
-
if (
|
|
115368
|
+
const alertPath = join70(smAgentDir, ".session-model-alert");
|
|
115369
|
+
if (existsSync60(alertPath)) {
|
|
114468
115370
|
let alertText = null;
|
|
114469
115371
|
try {
|
|
114470
|
-
alertText =
|
|
115372
|
+
alertText = readFileSync62(alertPath, "utf8").trim();
|
|
114471
115373
|
} catch {
|
|
114472
115374
|
alertText = null;
|
|
114473
115375
|
}
|