switchroom 0.18.17 → 0.18.19
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 +13 -0
- package/dist/auth-broker/index.js +13 -0
- package/dist/cli/notion-write-pretool.mjs +13 -0
- package/dist/cli/switchroom.js +605 -479
- package/dist/host-control/main.js +17 -1
- package/dist/vault/approvals/kernel-server.js +13 -0
- package/dist/vault/broker/server.js +13 -0
- package/package.json +1 -1
- package/telegram-plugin/bridge/bridge.ts +7 -1
- package/telegram-plugin/dist/bridge/bridge.js +26 -1
- package/telegram-plugin/dist/gateway/gateway.js +1544 -619
- package/telegram-plugin/dist/server.js +32 -1
- package/telegram-plugin/fleet-fallback-resume.ts +26 -3
- package/telegram-plugin/format.ts +137 -213
- package/telegram-plugin/gateway/approval-hold.ts +49 -0
- package/telegram-plugin/gateway/bridge-dead-watchdog.ts +61 -18
- package/telegram-plugin/gateway/gateway.ts +399 -85
- package/telegram-plugin/gateway/linear-activity.ts +20 -4
- package/telegram-plugin/gateway/outbound-send-path.ts +9 -7
- package/telegram-plugin/gateway/premium-recovery-wiring.ts +122 -0
- package/telegram-plugin/gateway/session-model-file.ts +103 -0
- package/telegram-plugin/gateway/tier-downgrade-wiring.ts +121 -0
- package/telegram-plugin/gateway/unhandled-rejection-policy.ts +14 -1
- package/telegram-plugin/llm-error-present.ts +474 -0
- package/telegram-plugin/operator-events.ts +7 -1
- package/telegram-plugin/permission-title.ts +172 -10
- package/telegram-plugin/premium-recovery.ts +101 -0
- package/telegram-plugin/raw-error-scrub.ts +73 -0
- package/telegram-plugin/retry-api-call.ts +8 -2
- package/telegram-plugin/send-gate-degraded.test.ts +152 -1
- package/telegram-plugin/send-gate-observability.test.ts +140 -0
- package/telegram-plugin/send-gate-observability.ts +65 -20
- package/telegram-plugin/send-gate.test.ts +143 -1
- package/telegram-plugin/send-gate.ts +212 -19
- package/telegram-plugin/session-tail.ts +16 -0
- package/telegram-plugin/shared/local-time.ts +69 -0
- package/telegram-plugin/stream-reply-handler.ts +5 -14
- package/telegram-plugin/tests/approval-hold-harness.ts +6 -6
- package/telegram-plugin/tests/approval-hold-outcome.test.ts +10 -2
- package/telegram-plugin/tests/bridge-dead-watchdog.test.ts +61 -0
- package/telegram-plugin/tests/fleet-fallback-resume.test.ts +39 -0
- package/telegram-plugin/tests/flood-windows-persistence.test.ts +3 -2
- package/telegram-plugin/tests/format-consistency.test.ts +68 -53
- package/telegram-plugin/tests/formatting-parse-regression.test.ts +5 -6
- package/telegram-plugin/tests/formatting-torture-set.ts +1 -1
- package/telegram-plugin/tests/gateway-outbound-redact.test.ts +26 -0
- package/telegram-plugin/tests/linear-create-issue.test.ts +30 -2
- package/telegram-plugin/tests/llm-error-present.test.ts +481 -0
- package/telegram-plugin/tests/outbound-send-path.test.ts +4 -3
- package/telegram-plugin/tests/paragraph-normalizer.test.ts +42 -100
- package/telegram-plugin/tests/permission-title.test.ts +167 -4
- package/telegram-plugin/tests/premium-recovery-wiring.test.ts +150 -0
- package/telegram-plugin/tests/premium-recovery.test.ts +165 -0
- package/telegram-plugin/tests/reaction-gate-routing.test.ts +6 -1
- package/telegram-plugin/tests/retry-api-call.test.ts +21 -0
- package/telegram-plugin/tests/stream-reply-handler.test.ts +9 -12
- package/telegram-plugin/tests/telegram-format.test.ts +86 -31
- package/telegram-plugin/tests/tier-downgrade-wiring.test.ts +165 -0
- package/telegram-plugin/tests/tier-downgrade.test.ts +141 -0
- package/telegram-plugin/tests/turn-flush-safety.test.ts +17 -21
- package/telegram-plugin/tests/unhandled-rejection-policy.test.ts +27 -1
- package/telegram-plugin/tests/worker-activity-feed.test.ts +5 -2
- package/telegram-plugin/tests/worker-feed-coalesce.test.ts +492 -0
- package/telegram-plugin/tier-downgrade.ts +198 -0
- package/telegram-plugin/tool-activity-summary.ts +99 -0
- package/telegram-plugin/turn-flush-safety.ts +4 -3
- package/telegram-plugin/worker-activity-feed.ts +509 -409
|
@@ -32,11 +32,15 @@
|
|
|
32
32
|
* claude itself down — where a bounce is either premature or
|
|
33
33
|
* futile); the timer re-arms so a slow-booting claude gets the full
|
|
34
34
|
* grace window again once it appears;
|
|
35
|
-
* - cron-session bridges (`<agent>-cron`)
|
|
36
|
-
* (recall.py one-shots, pre-handshake connects)
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
35
|
+
* - cron-session bridges (`<agent>-cron`), anonymous IPC clients
|
|
36
|
+
* (recall.py one-shots, pre-handshake connects), AND secondary/relay
|
|
37
|
+
* clients that register a DIFFERENT agent name than this gateway serves
|
|
38
|
+
* (e.g. an `overlord-relay` connecting into another agent's gateway
|
|
39
|
+
* socket — #3086) neither satisfy nor re-arm the watchdog: only the
|
|
40
|
+
* gateway's OWN primary bridge (agentName === $SWITCHROOM_AGENT_NAME)
|
|
41
|
+
* counts. The gating lives INSIDE noteBridge* so a gateway handler
|
|
42
|
+
* refactor can't silently reintroduce the bounce-after-cron-fire or the
|
|
43
|
+
* bounce-after-relay-disconnect false positive;
|
|
40
44
|
* - loud, structured escalation log line including a fresh
|
|
41
45
|
* bridge-crash.log tail (PR #3037 breadcrumbs) so the operator sees
|
|
42
46
|
* WHY from the supervisor log alone.
|
|
@@ -352,6 +356,16 @@ export interface BridgeDeadWatchdogOpts {
|
|
|
352
356
|
* unref (the watchdog must never keep the gateway process alive). */
|
|
353
357
|
setTimer?: (fn: () => void, ms: number) => unknown
|
|
354
358
|
clearTimer?: (handle: unknown) => void
|
|
359
|
+
/** The agent identity THIS gateway serves ($SWITCHROOM_AGENT_NAME).
|
|
360
|
+
* Only a bridge client registering under this exact name is the
|
|
361
|
+
* primary bridge whose presence/absence drives the watchdog. Secondary
|
|
362
|
+
* or relay clients (a different named identity connecting into this
|
|
363
|
+
* gateway's socket — e.g. `overlord-relay`, #3086) are ignored on both
|
|
364
|
+
* the register and disconnect paths. When unset/empty (a misconfigured
|
|
365
|
+
* gateway with no agent name), the watchdog falls back to the pre-#3086
|
|
366
|
+
* test — any named non-cron client counts — so a genuine bridge death is
|
|
367
|
+
* still caught rather than silently un-guarded. */
|
|
368
|
+
selfAgentName?: string
|
|
355
369
|
/** Injectable clock (marker ts + crash-log freshness). */
|
|
356
370
|
nowMs?: () => number
|
|
357
371
|
/** Injectable marker writer (tests avoid real fs). */
|
|
@@ -365,15 +379,18 @@ export interface BridgeDeadWatchdog {
|
|
|
365
379
|
* when the cross-boot streak cap is already reached (stands down with
|
|
366
380
|
* an audit line instead). */
|
|
367
381
|
arm: () => void
|
|
368
|
-
/** A bridge client registered. Only
|
|
369
|
-
*
|
|
370
|
-
* anonymous clients (agentName null)
|
|
371
|
-
*
|
|
382
|
+
/** A bridge client registered. Only THIS gateway's OWN primary bridge
|
|
383
|
+
* (agentName === selfAgentName, named, non-cron) satisfies the watchdog
|
|
384
|
+
* — cron sessions (`<agent>-cron`), anonymous clients (agentName null),
|
|
385
|
+
* and secondary/relay clients registering a different name (#3086) are
|
|
386
|
+
* ignored HERE so a gateway handler refactor can't reorder the gating
|
|
387
|
+
* away (review finding 5). */
|
|
372
388
|
noteBridgeRegistered: (agentName: string | null | undefined) => void
|
|
373
|
-
/** A bridge client disconnected. Re-arms the grace window only for
|
|
374
|
-
*
|
|
375
|
-
* and never reconnects also escalates
|
|
376
|
-
*
|
|
389
|
+
/** A bridge client disconnected. Re-arms the grace window only for THIS
|
|
390
|
+
* gateway's own primary bridge (same internal gating), so a bridge that
|
|
391
|
+
* dies AFTER boot and never reconnects also escalates — while a
|
|
392
|
+
* transient relay/secondary client's disconnect (#3086) is a no-op.
|
|
393
|
+
* Still capped by the once-per-boot fuse. */
|
|
377
394
|
noteBridgeDisconnected: (agentName: string | null | undefined) => void
|
|
378
395
|
/** Evaluate now (the timer body — exposed for tests). Returns the
|
|
379
396
|
* decision taken. */
|
|
@@ -384,9 +401,34 @@ export interface BridgeDeadWatchdog {
|
|
|
384
401
|
hasEscalated: () => boolean
|
|
385
402
|
}
|
|
386
403
|
|
|
387
|
-
/**
|
|
388
|
-
|
|
389
|
-
|
|
404
|
+
/**
|
|
405
|
+
* Is this client identity THIS gateway's OWN primary main-agent bridge?
|
|
406
|
+
*
|
|
407
|
+
* A named, non-cron client whose name matches the gateway's own agent
|
|
408
|
+
* identity (`selfAgentName` = $SWITCHROOM_AGENT_NAME). A switchroom gateway
|
|
409
|
+
* serves exactly one agent, and its real bridge registers under exactly that
|
|
410
|
+
* name (see bridge/bridge.ts — `agentName: AGENT_NAME`). Secondary or relay
|
|
411
|
+
* clients (e.g. an `overlord-relay` that connects into another agent's
|
|
412
|
+
* gateway socket, #3086) register a DIFFERENT name; they are named and
|
|
413
|
+
* non-cron but are NOT this gateway's primary bridge, so their register /
|
|
414
|
+
* disconnect must neither satisfy nor re-arm the watchdog — otherwise a
|
|
415
|
+
* transient relay disconnect marks the (still-alive) primary bridge dead and
|
|
416
|
+
* bounces a healthy container.
|
|
417
|
+
*
|
|
418
|
+
* When `selfAgentName` is unset/empty (misconfigured gateway) we cannot
|
|
419
|
+
* identity-match, so fall back to the pre-#3086 test — any named non-cron
|
|
420
|
+
* client counts — keeping the watchdog protective rather than un-guarded.
|
|
421
|
+
*/
|
|
422
|
+
function isRealBridgeIdentity(
|
|
423
|
+
agentName: string | null | undefined,
|
|
424
|
+
selfAgentName: string | null | undefined,
|
|
425
|
+
): boolean {
|
|
426
|
+
if (agentName == null || agentName.length === 0) return false
|
|
427
|
+
if (isCronIdentity(agentName)) return false
|
|
428
|
+
if (selfAgentName != null && selfAgentName.length > 0) {
|
|
429
|
+
return agentName === selfAgentName
|
|
430
|
+
}
|
|
431
|
+
return true
|
|
390
432
|
}
|
|
391
433
|
|
|
392
434
|
export function createBridgeDeadWatchdog(opts: BridgeDeadWatchdogOpts): BridgeDeadWatchdog {
|
|
@@ -404,6 +446,7 @@ export function createBridgeDeadWatchdog(opts: BridgeDeadWatchdogOpts): BridgeDe
|
|
|
404
446
|
opts.readCrashTail ?? ((p: string, t: number) => readFreshCrashLogTail(p, { nowMs: t }))
|
|
405
447
|
const priorStreak = opts.priorStreak ?? 0
|
|
406
448
|
const maxConsecutive = opts.maxConsecutive ?? MAX_CONSECUTIVE_ESCALATIONS
|
|
449
|
+
const selfAgentName = opts.selfAgentName
|
|
407
450
|
|
|
408
451
|
let timer: unknown = null
|
|
409
452
|
let bridgeRegistered = false
|
|
@@ -528,13 +571,13 @@ export function createBridgeDeadWatchdog(opts: BridgeDeadWatchdogOpts): BridgeDe
|
|
|
528
571
|
return {
|
|
529
572
|
arm: armInternal,
|
|
530
573
|
noteBridgeRegistered: (agentName) => {
|
|
531
|
-
if (!isRealBridgeIdentity(agentName)) return
|
|
574
|
+
if (!isRealBridgeIdentity(agentName, selfAgentName)) return
|
|
532
575
|
bridgeRegistered = true
|
|
533
576
|
bridgeEverRegistered = true
|
|
534
577
|
cancel()
|
|
535
578
|
},
|
|
536
579
|
noteBridgeDisconnected: (agentName) => {
|
|
537
|
-
if (!isRealBridgeIdentity(agentName)) return
|
|
580
|
+
if (!isRealBridgeIdentity(agentName, selfAgentName)) return
|
|
538
581
|
bridgeRegistered = false
|
|
539
582
|
armInternal()
|
|
540
583
|
},
|