switchroom 0.18.9 → 0.18.11
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 +1 -0
- package/dist/auth-broker/index.js +198 -13
- package/dist/cli/notion-write-pretool.mjs +1 -0
- package/dist/cli/switchroom.js +214 -83
- package/dist/cli/ui/apple-touch-icon.png +0 -0
- package/dist/cli/ui/favicon-32.png +0 -0
- package/dist/cli/ui/favicon.ico +0 -0
- package/dist/host-control/main.js +760 -257
- package/dist/vault/approvals/kernel-server.js +3 -1
- package/dist/vault/broker/server.js +3 -1
- package/package.json +1 -1
- package/profiles/_base/start.sh.hbs +119 -37
- package/profiles/_shared/dev-protocol.md.hbs +42 -0
- package/skills/dev-protocol/SKILL.md +131 -0
- package/telegram-plugin/README.md +2 -1
- package/telegram-plugin/admin-commands/dispatch.test.ts +40 -2
- package/telegram-plugin/admin-commands/index.ts +6 -1
- package/telegram-plugin/bridge/bridge.ts +23 -1
- package/telegram-plugin/bridge/crash-breadcrumb.ts +42 -0
- package/telegram-plugin/chat-lock.ts +13 -0
- package/telegram-plugin/dist/bridge/bridge.js +24 -1
- package/telegram-plugin/dist/gateway/gateway.js +1832 -263
- package/telegram-plugin/dist/server.js +29 -2
- package/telegram-plugin/fallback-card-collapse.ts +131 -0
- package/telegram-plugin/gateway/bridge-dead-watchdog.ts +546 -0
- package/telegram-plugin/gateway/effort-command.ts +47 -3
- package/telegram-plugin/gateway/gateway.ts +1435 -211
- package/telegram-plugin/gateway/model-command.ts +94 -8
- package/telegram-plugin/gateway/pending-session-command.ts +365 -0
- package/telegram-plugin/gateway/permission-timeout.ts +25 -0
- package/telegram-plugin/gateway/resume-inbound-builder.ts +23 -3
- package/telegram-plugin/gateway/session-model-file.ts +166 -23
- package/telegram-plugin/gateway/stop-command.ts +56 -0
- package/telegram-plugin/photo-precheck.ts +201 -0
- package/telegram-plugin/quota-watch.ts +141 -2
- package/telegram-plugin/registry/subagents-schema.ts +26 -3
- package/telegram-plugin/registry/subagents.test.ts +67 -0
- package/telegram-plugin/retry-api-call.ts +31 -0
- package/telegram-plugin/subagent-watcher.ts +392 -1
- package/telegram-plugin/tests/bridge-dead-watchdog.test.ts +576 -0
- package/telegram-plugin/tests/buffer-gate-broadened.test.ts +11 -5
- package/telegram-plugin/tests/chat-lock-unhandled-rejection.test.ts +101 -0
- package/telegram-plugin/tests/crash-breadcrumb.test.ts +57 -0
- package/telegram-plugin/tests/effort-command.test.ts +59 -2
- package/telegram-plugin/tests/fallback-card-collapse.test.ts +104 -0
- package/telegram-plugin/tests/gateway-pending-command-wiring.test.ts +124 -0
- package/telegram-plugin/tests/gateway-secret-detect.test.ts +7 -1
- package/telegram-plugin/tests/gateway-session-model-relaunch.test.ts +19 -11
- package/telegram-plugin/tests/model-command.test.ts +46 -3
- package/telegram-plugin/tests/pending-session-command.test.ts +322 -0
- package/telegram-plugin/tests/permission-timeout.test.ts +26 -0
- package/telegram-plugin/tests/permission-verdict-resume-guard.test.ts +16 -0
- package/telegram-plugin/tests/photo-dimension-fallback.test.ts +129 -0
- package/telegram-plugin/tests/photo-precheck.test.ts +240 -0
- package/telegram-plugin/tests/photo-reroute-wiring.test.ts +85 -0
- package/telegram-plugin/tests/quota-watch.test.ts +225 -0
- package/telegram-plugin/tests/session-model-file.test.ts +101 -2
- package/telegram-plugin/tests/stop-command.test.ts +234 -0
- package/telegram-plugin/tests/subagent-watcher-env-thresholds.test.ts +27 -9
- package/telegram-plugin/tests/subagent-watcher-resurrection.test.ts +398 -0
- package/telegram-plugin/tests/subagent-watcher-stall-terminal.test.ts +172 -0
- package/telegram-plugin/tests/worker-activity-feed.test.ts +37 -0
- package/telegram-plugin/tests/worker-visibility-prose-silent-harness.test.ts +18 -4
- package/telegram-plugin/welcome-text.ts +4 -3
- package/telegram-plugin/worker-activity-feed.ts +27 -0
|
@@ -158,6 +158,7 @@ function makeHarness() {
|
|
|
158
158
|
stallThresholdMs: 60_000, // tight active-loop threshold
|
|
159
159
|
silentSynthesisStallThresholdMs: 300_000, // widened window (also long-runner window)
|
|
160
160
|
silentStallTerminalMs: 300_000, // post-stall terminal-synthesis window (unchanged)
|
|
161
|
+
inflightTerminalCapMs: 900_000, // died-mid-tool cap (15 min, compressed from the 45-min default)
|
|
161
162
|
rescanMs: 500,
|
|
162
163
|
now: () => currentTime,
|
|
163
164
|
setInterval: sharedSetInterval,
|
|
@@ -278,10 +279,23 @@ describe('prose-silent background worker — end-to-end visibility harness (PR 2
|
|
|
278
279
|
expect(h.stallCalls[0].agentId).toBe(h.agentId)
|
|
279
280
|
expect(h.stallTerminalCalls).toHaveLength(0)
|
|
280
281
|
|
|
281
|
-
// (d)
|
|
282
|
-
//
|
|
283
|
-
//
|
|
284
|
-
|
|
282
|
+
// (d) IN-FLIGHT DEFERRAL: 300s past the stall the OLD contract
|
|
283
|
+
// (#2777/#2782) synthesised terminal here. But this worker's transcript
|
|
284
|
+
// ends in a Bash tool_use with NO tool_result — it may still be inside
|
|
285
|
+
// the tool call (incident 2026-07-10: exactly this shape finalised a
|
|
286
|
+
// LIVE worker's card mid-Bash). Synthesis is now deferred while the
|
|
287
|
+
// tool call is in flight...
|
|
288
|
+
h.advance(310_000) // total idle ~672s — past silentStallTerminalMs, under the 900s cap
|
|
289
|
+
await h.flush()
|
|
290
|
+
expect(h.stallTerminalCalls).toHaveLength(0)
|
|
291
|
+
expect(h.finishCalls).toHaveLength(0)
|
|
292
|
+
|
|
293
|
+
// (e) TERMINAL GATE RELEASE AT THE CAP: ...but not forever. A worker
|
|
294
|
+
// that died mid-tool (JSONL frozen, tool_result never coming) must not
|
|
295
|
+
// wedge — past inflightTerminalCapMs of total idle the synthesis
|
|
296
|
+
// proceeds and the completion gate releases. The load-bearing release
|
|
297
|
+
// from #2777/#2782 survives, bounded instead of at the raw synth window.
|
|
298
|
+
h.advance(300_000) // total idle ~972s ≥ 900s cap
|
|
285
299
|
await h.flush()
|
|
286
300
|
expect(h.stallTerminalCalls).toHaveLength(1)
|
|
287
301
|
expect(h.finishCalls).toHaveLength(1)
|
|
@@ -279,9 +279,9 @@ export function statusUnpairedText(): string {
|
|
|
279
279
|
*/
|
|
280
280
|
export const switchroomHelpCommandNames = [
|
|
281
281
|
// Session & approvals
|
|
282
|
-
"new", "compact", "clear", "approve", "deny", "pending", "interrupt",
|
|
282
|
+
"new", "compact", "clear", "approve", "deny", "pending", "interrupt", "stop",
|
|
283
283
|
// Agents
|
|
284
|
-
"agents", "agentstart", "
|
|
284
|
+
"agents", "agentstart", "agentstop", "restart", "logs", "memory",
|
|
285
285
|
// Auth & config — consolidated onto the `/auth` dashboard.
|
|
286
286
|
"auth", "model",
|
|
287
287
|
"topics", "update", "version", "whoami",
|
|
@@ -380,11 +380,12 @@ export function switchroomHelpText(agentName: string): string {
|
|
|
380
380
|
`\`/deny [id]\` — deny pending tool permission`,
|
|
381
381
|
`\`/pending\` — list pending permission prompts`,
|
|
382
382
|
`\`/interrupt [name]\` — interrupt an agent turn`,
|
|
383
|
+
`\`/stop\` — cancel my in-flight turn (bare "stop" works too)`,
|
|
383
384
|
``,
|
|
384
385
|
`**Agents**`,
|
|
385
386
|
`\`/agents\` — list all agents`,
|
|
386
387
|
`\`/agentstart [name]\` — start an agent`,
|
|
387
|
-
`\`/
|
|
388
|
+
`\`/agentstop [name]\` — stop an agent's container`,
|
|
388
389
|
`\`/logs [name] [lines]\` — show agent logs`,
|
|
389
390
|
`\`/memory <query>\` — search agent memory`,
|
|
390
391
|
``,
|
|
@@ -342,6 +342,16 @@ export interface WorkerActivityFeed {
|
|
|
342
342
|
finish(agentId: string, view: WorkerActivityView): Promise<void>
|
|
343
343
|
/** Forget a worker's state without editing (e.g. error path). */
|
|
344
344
|
drop(agentId: string): void
|
|
345
|
+
/**
|
|
346
|
+
* Issue #3023 (card resurrection). Undo a finalization: clear the durable
|
|
347
|
+
* `finalized` gate (and any lingering per-handle `finished` latch) so a
|
|
348
|
+
* worker whose card was FALSELY finalized can be painted/edited again. The
|
|
349
|
+
* watcher calls this (via the gateway's `onResurrect` wiring) when a
|
|
350
|
+
* falsely-finalized worker's JSONL resumes growing. A fresh `running` cue
|
|
351
|
+
* after this repaints a live card — the operator invariant that active work
|
|
352
|
+
* stays visible. Idempotent; a no-op if the worker was never finalized.
|
|
353
|
+
*/
|
|
354
|
+
resurrect(agentId: string): void
|
|
345
355
|
/** Clear the heartbeat interval (gateway shutdown). Idempotent. */
|
|
346
356
|
stop(): void
|
|
347
357
|
/** Manually fire one heartbeat tick (test hook). */
|
|
@@ -777,6 +787,23 @@ export function createWorkerActivityFeed(opts: WorkerActivityFeedOpts): WorkerAc
|
|
|
777
787
|
markFinalized(agentId)
|
|
778
788
|
handles.delete(agentId)
|
|
779
789
|
},
|
|
790
|
+
resurrect(agentId) {
|
|
791
|
+
// Issue #3023: the worker's card was falsely finalized and its JSONL has
|
|
792
|
+
// resumed. Re-open the paint path: drop the durable finalized gate so a
|
|
793
|
+
// fresh `running` cue creates a new handle and first-paints a live card
|
|
794
|
+
// again, and un-latch any surviving handle (finish deleted it in the
|
|
795
|
+
// common case, but a staged pendingFinish could keep it alive). The next
|
|
796
|
+
// `update` tick from the watcher's replayed progress does the repaint.
|
|
797
|
+
const wasFinalized = finalized.delete(agentId)
|
|
798
|
+
const h = handles.get(agentId)
|
|
799
|
+
if (h != null) {
|
|
800
|
+
h.finished = false
|
|
801
|
+
h.pendingFinish = null
|
|
802
|
+
}
|
|
803
|
+
if (wasFinalized || h != null) {
|
|
804
|
+
log(`worker-feed: resurrect agent=${agentId} — cleared finalized gate; card will repaint on next running cue`)
|
|
805
|
+
}
|
|
806
|
+
},
|
|
780
807
|
heartbeatTick,
|
|
781
808
|
stop() {
|
|
782
809
|
if (heartbeatTimer != null) {
|