switchroom 0.11.1 → 0.12.1

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.
Files changed (77) hide show
  1. package/README.md +32 -16
  2. package/dist/agent-scheduler/index.js +216 -97
  3. package/dist/auth-broker/index.js +176 -97
  4. package/dist/cli/drive-write-pretool.mjs +26 -11
  5. package/dist/cli/skill-validate-pretool.mjs +7209 -0
  6. package/dist/cli/switchroom.js +45571 -42642
  7. package/dist/cli/ui/index.html +1281 -0
  8. package/dist/host-control/main.js +3628 -309
  9. package/dist/vault/approvals/kernel-server.js +207 -98
  10. package/dist/vault/broker/server.js +249 -119
  11. package/examples/personal-google-workspace-mcp/README.md +8 -3
  12. package/examples/switchroom.yaml +91 -42
  13. package/package.json +4 -3
  14. package/profiles/_base/start.sh.hbs +76 -36
  15. package/profiles/_shared/agent-self-service.md.hbs +1 -1
  16. package/profiles/default/CLAUDE.md.hbs +4 -2
  17. package/skills/file-bug/SKILL.md +6 -4
  18. package/skills/skill-creator/SKILL.md +52 -0
  19. package/skills/switchroom-cli/SKILL.md +20 -4
  20. package/skills/switchroom-install/SKILL.md +3 -3
  21. package/telegram-plugin/auth-snapshot-format.ts +9 -9
  22. package/telegram-plugin/card-format.ts +3 -3
  23. package/telegram-plugin/dist/bridge/bridge.js +112 -112
  24. package/telegram-plugin/dist/gateway/gateway.js +853 -414
  25. package/telegram-plugin/dist/server.js +162 -161
  26. package/telegram-plugin/format.ts +71 -0
  27. package/telegram-plugin/gateway/access-validator.test.ts +8 -8
  28. package/telegram-plugin/gateway/access-validator.ts +1 -1
  29. package/telegram-plugin/gateway/approval-card.test.ts +18 -18
  30. package/telegram-plugin/gateway/approval-card.ts +1 -1
  31. package/telegram-plugin/gateway/auth-command.ts +2 -2
  32. package/telegram-plugin/gateway/boot-card.ts +40 -3
  33. package/telegram-plugin/gateway/boot-probes.ts +114 -30
  34. package/telegram-plugin/gateway/diff-preview-card.test.ts +15 -15
  35. package/telegram-plugin/gateway/diff-preview-card.ts +1 -1
  36. package/telegram-plugin/gateway/drive-write-approval.test.ts +2 -2
  37. package/telegram-plugin/gateway/gateway.ts +265 -22
  38. package/telegram-plugin/gateway/update-announce.ts +167 -0
  39. package/telegram-plugin/quota-check.ts +0 -195
  40. package/telegram-plugin/recent-outbound-dedup.ts +1 -1
  41. package/telegram-plugin/registry/turns-schema.ts +1 -1
  42. package/telegram-plugin/retry-api-call.ts +24 -0
  43. package/telegram-plugin/server.ts +8 -5
  44. package/telegram-plugin/tests/auth-add-flow.test.ts +32 -3
  45. package/telegram-plugin/tests/auth-command-format2.test.ts +4 -4
  46. package/telegram-plugin/tests/auth-snapshot-format.test.ts +17 -17
  47. package/telegram-plugin/tests/auto-fallback-fleet.test.ts +10 -10
  48. package/telegram-plugin/tests/boot-probes.test.ts +90 -2
  49. package/telegram-plugin/tests/bot-runtime.test.ts +23 -1
  50. package/telegram-plugin/tests/fixtures/service-log-current-claude-code.bin +1 -1
  51. package/telegram-plugin/tests/fleet-state.test.ts +3 -2
  52. package/telegram-plugin/tests/quota-check.test.ts +0 -409
  53. package/telegram-plugin/tests/retry-api-call.test.ts +76 -0
  54. package/telegram-plugin/tests/secret-detect-audit.test.ts +1 -1
  55. package/telegram-plugin/tests/secret-detect-pipeline.test.ts +7 -6
  56. package/telegram-plugin/tests/secret-detect-suppressor-no-silent-allow.test.ts +6 -5
  57. package/telegram-plugin/tests/secret-detect.test.ts +8 -8
  58. package/telegram-plugin/tests/telegram-format.test.ts +84 -1
  59. package/telegram-plugin/tests/update-announce.test.ts +154 -0
  60. package/telegram-plugin/tests/vault-grant-inbound-builders.test.ts +8 -8
  61. package/telegram-plugin/tests/vault-request-access-tool.test.ts +51 -0
  62. package/telegram-plugin/welcome-text.ts +1 -8
  63. package/profiles/default/CLAUDE.md +0 -192
  64. package/skills/docx/scripts/office/validators/__pycache__/__init__.cpython-313.pyc +0 -0
  65. package/skills/docx/scripts/office/validators/__pycache__/base.cpython-313.pyc +0 -0
  66. package/skills/skill-creator/scripts/__pycache__/__init__.cpython-313.pyc +0 -0
  67. package/skills/skill-creator/scripts/__pycache__/generate_report.cpython-313.pyc +0 -0
  68. package/skills/skill-creator/scripts/__pycache__/improve_description.cpython-313.pyc +0 -0
  69. package/skills/skill-creator/scripts/__pycache__/run_eval.cpython-313.pyc +0 -0
  70. package/skills/skill-creator/scripts/__pycache__/run_loop.cpython-313.pyc +0 -0
  71. package/skills/skill-creator/scripts/__pycache__/utils.cpython-313.pyc +0 -0
  72. package/telegram-plugin/first-paint.ts +0 -225
  73. package/telegram-plugin/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +0 -1
  74. package/telegram-plugin/server.js +0 -41795
  75. package/telegram-plugin/tests/html-balanced.ts +0 -63
  76. package/telegram-plugin/tests/snapshot-serializer.ts +0 -79
  77. package/telegram-plugin/tool-error-filter.ts +0 -89
package/README.md CHANGED
@@ -22,7 +22,7 @@ Every time an agent starts work, a **progress card** pins into its Telegram topi
22
22
 
23
23
  No silent gaps. No ghosts. No squinting into a black box.
24
24
 
25
- <p align="center"><img src="docs/diagrams/progress-card-anatomy.jpg" width="700" alt="Annotated progress card: pin badge, user quote, last 5 steps, collapsed older, in-flight pulse, elapsed timer, sub-agent indent"></p>
25
+ <p align="center"><img src="docs/diagrams/progress-card-anatomy.svg" width="700" alt="Annotated progress card: pin badge, user quote, last 5 steps, collapsed older, in-flight pulse, elapsed timer, sub-agent indent"></p>
26
26
 
27
27
  ```
28
28
  ⚙️ Working… · ⏱ 12s
@@ -87,9 +87,12 @@ You (Telegram)
87
87
  ├─ Progress cards ├─ Approval kernel ◄─────┤ settings.json (tools, hooks, MCP)
88
88
  ├─ Pin / unpin lifecycle │ (allow/deny broker) ├─ Hindsight plugin (memory)
89
89
  ├─ SQLite history ├─ Vault broker ◄────────┤ Drive MCP, Playwright MCP, …
90
- ├─ Card-events.jsonl audit │ (cron secrets, IPC) └─ scheduled tasks across reboots
91
- ├─ Emoji reactions │
92
- └─ Format conversion └─ Docker Compose restart (unless-stopped)
90
+ ├─ Card-events.jsonl audit ├─ Auth broker ◄─────────┤ in-agent scheduler sidecar
91
+ ├─ Emoji reactions │ (OAuth refresh, └─ (cron, fires across reboots)
92
+ └─ Format conversion │ sole creds writer)
93
+ ├─ hostd (host-control:
94
+ │ /restart, /update apply)
95
+ └─ Docker Compose restart (unless-stopped)
93
96
  ```
94
97
 
95
98
  See [`docs/architecture.md`](docs/architecture.md) for the process model, IPC layout, supervisor choice, and how each layer maps to the `claude` CLI.
@@ -98,7 +101,7 @@ See [`docs/architecture.md`](docs/architecture.md) for the process model, IPC la
98
101
 
99
102
  Tools that touch the world — Bash, Edit, Write, anything not on an agent's pre-approved allowlist — pause for explicit approval. Switchroom's **approval kernel** (shipped in v0.5.1) routes every gated tool call through an inline Telegram card with the actual diff or command shown. Tap Allow and the tool resumes. Tap Deny and the agent gets a clean refusal it can recover from.
100
103
 
101
- <p align="center"><img src="docs/diagrams/approval-grant-flow.jpg" width="700" alt="Approval grant flow: agent tool call pauses at the kernel, broker writes pending grant to sqlite, user taps Allow on the Telegram card, broker releases the gate, tool resumes"></p>
104
+ <p align="center"><img src="docs/diagrams/approval-grant-flow.svg" width="700" alt="Approval grant flow: agent tool call pauses at the kernel, broker writes pending grant to sqlite, user taps Allow on the Telegram card, broker releases the gate, tool resumes"></p>
102
105
 
103
106
  - **Inline cards.** Allow / Deny / Allow once / Allow for 1h. No leaving Telegram.
104
107
  - **TTL'd grants.** "Allow Bash for 1h" expires automatically. No silent permanent escalation.
@@ -115,7 +118,7 @@ Switchroom never intercepts auth, never proxies inference, never patches the CLI
115
118
 
116
119
  Each agent is a long-running service. They survive reboots, network drops, and your laptop closing. But "always on" isn't enough on its own. Things still die. The product has to handle that gracefully or the illusion breaks.
117
120
 
118
- <p align="center"><img src="docs/diagrams/wake-audit-lifecycle.jpg" width="700" alt="Wake-audit lifecycle: kill, crash-pane snapshot, auto-restart, agent boots with SWITCHROOM_PENDING_TURN, acks with three options"></p>
121
+ <p align="center"><img src="docs/diagrams/wake-audit-lifecycle.svg" width="700" alt="Wake-audit lifecycle: kill, crash-pane snapshot, auto-restart, agent boots with SWITCHROOM_PENDING_TURN, acks with three options"></p>
119
122
 
120
123
  - **Auto-restart.** Agent containers come up with `restart: unless-stopped`, and each service has a healthcheck — a crashed or wedged agent is brought back automatically. No silent dropped work.
121
124
  - **Resume protocol.** When an agent reboots mid-turn, `start.sh` exports `SWITCHROOM_PENDING_TURN=true` plus the original chat / message ids. The agent's first action on boot is to acknowledge the gap and ask the user how to proceed (start over, summarise and continue, or drop it).
@@ -157,12 +160,13 @@ Then log out and back in so the docker group takes effect, and:
157
160
 
158
161
  ```bash
159
162
  switchroom setup # interactive: Telegram + vault + first agent
160
- switchroom auth add me --from-oauth # OAuth into your Claude Pro or Max account (one flow, fleet-wide)
161
- switchroom apply # write ~/.switchroom/compose/docker-compose.yml
162
- docker compose -p switchroom -f ~/.switchroom/compose/docker-compose.yml up -d
163
+ switchroom apply # regenerate ~/.switchroom/compose/docker-compose.yml
164
+ docker compose -p switchroom -f ~/.switchroom/compose/docker-compose.yml up -d # bring the fleet up
165
+ switchroom auth add default --via-claude # OAuth your Claude Pro/Max account — run AFTER the fleet is up
166
+ switchroom auth use default # make it the fleet-wide active account
163
167
  ```
164
168
 
165
- After the last command you talk to the agent from Telegram. You don't touch the server again.
169
+ Auth comes *after* the fleet is up on purpose: the `switchroom-auth-broker` is the sole writer of credentials and doesn't exist until the compose stack is running (`switchroom auth …` beforehand just prints a "fleet not up" hint). After this you talk to the agent from Telegram and don't touch the server again. To catch a running host up later — pull images, refresh scaffolds, recreate — use **`switchroom update`**, not a raw `docker compose up` (a bare compose-up on a live fleet skips the operator restart-marker, so the boot cards render as crashes).
166
170
 
167
171
  ### Already have Docker + Node ≥ 20.11
168
172
 
@@ -187,7 +191,7 @@ If you already use Claude Code, this is the shortest path. Inside any session:
187
191
 
188
192
  ### Static binary (planned, not yet shipped)
189
193
 
190
- Pre-built single-binary releases (no Node or Bun required on the host) are scaffolded in [`install.sh`](install.sh) and referenced from the GitHub Releases page, but **the release workflow that publishes those binaries does not yet exist**. Until v0.9, use the one-script or npm paths above. Tracking work: switching the release pipeline to actually upload `switchroom-linux-{amd64,arm64}` and `switchroom-macos-{amd64,arm64}` on every tag.
194
+ Pre-built single-binary releases (no Node or Bun required on the host) are scaffolded in [`install.sh`](install.sh) and referenced from the GitHub Releases page, but **the release workflow that publishes those binaries still does not exist as of v0.12.0**. Use the one-script or npm paths above. Tracking work: switching the release pipeline to actually upload `switchroom-linux-{amd64,arm64}` and `switchroom-macos-{amd64,arm64}` on every tag.
191
195
 
192
196
  ### One-shot happy path (no wizard)
193
197
 
@@ -292,7 +296,8 @@ Disable with `switchroom vault broker disable-auto-unlock`.
292
296
  ```bash
293
297
  switchroom setup # Interactive wizard
294
298
  switchroom doctor # Health check
295
- switchroom apply # Reconcile + (re)write docker-compose.yml; bring fleet up via `docker compose ... up -d`
299
+ switchroom apply # Reconcile + regenerate docker-compose.yml (self-elevates via sudo for scaffolds). Does NOT run docker prints the `up` command
300
+ switchroom update [--check|--status|--rebuild] # Operator catch-up: pull images + apply + recreate fleet + doctor
296
301
  switchroom restart [agent] [--force] # Bounce agent(s); drains in-flight turn by default
297
302
  switchroom version # Show versions + running agent health summary
298
303
 
@@ -304,15 +309,23 @@ switchroom agent bootstrap <name> --profile <p> --bot-token <t> # One-shot scaf
304
309
  switchroom agent reconcile <name|all> # Re-apply switchroom.yaml (without pulling/building)
305
310
  switchroom agent start|stop|restart <name> # Lifecycle (with preflight)
306
311
  switchroom agent interrupt <name> # Cancel in-flight turn without restarting
312
+ switchroom agent unquarantine <name> # Clear a crash-quarantine and resume supervision
307
313
  switchroom agent rename <old> <new> # Rename an agent slug (#168)
308
314
  switchroom agent destroy <name> # Remove from compose + scaffold dir
309
315
  switchroom agent attach <name> # Interactive tmux session
316
+ switchroom agent send <name> <slash-cmd> # Inject a slash command into the agent's tmux pane
310
317
  switchroom agent logs <name> [-f] # View logs
311
318
  switchroom agent grant <name> <tool> # Grant a tool permission
312
319
  switchroom agent permissions <name> # Show allow/deny list
313
320
  switchroom agent dangerous <name> [off] # Toggle full tool access
321
+
322
+ switchroom soul path|show|reset <name> # Manage the agent's user-owned SOUL.md (persona)
323
+ switchroom hostd install|status|uninstall|audit # Host-control daemon (/restart, /update apply, …)
324
+ switchroom drive connect|disconnect <agent> # Per-agent Google Drive OAuth
314
325
  ```
315
326
 
327
+ `switchroom --help` lists every verb (also `deps`, `issues`, `migrate`).
328
+
316
329
  Profiles live in `profiles/` at the repo root. Bundled ones for `--profile`: `coding`, `default`, `executive-assistant`, `health-coach` (the `_base/` dir is framework-internal render templates and is not a user-selectable profile).
317
330
 
318
331
  `switchroom agent create <name> --profile <profile>` does two things in one step:
@@ -329,10 +342,11 @@ Model aliases: the bare names `opus`, `sonnet`, `haiku` are accepted alongside t
329
342
  The **Anthropic account is the unit of authentication.** One OAuth flow per account, then every agent in the fleet inherits the fleet-wide active account. The `switchroom-auth-broker` daemon owns the refresh loop and is the sole writer of every `credentials.json`. Per-account quota state fans out across the fleet in seconds. See [`docs/auth.md`](docs/auth.md) for the full operator guide.
330
343
 
331
344
  ```bash
332
- switchroom auth add <label> --from-oauth # New account via OAuth (one flow per Anthropic account)
345
+ switchroom auth add <label> --via-claude # New account, broader scope recommended for first-time
346
+ switchroom auth add <label> --from-oauth # Narrow scope=user:inference (rejected by agents in server: mode)
333
347
  switchroom auth add <label> --from-agent <name> # Seed from an existing agent's creds
334
348
  switchroom auth add <label> --from-credentials <path> # Import a credentials.json
335
- switchroom auth add <label> --from-oauth --replace # Re-auth an existing label (drift recovery)
349
+ switchroom auth add <label> --via-claude --replace # Re-auth an existing label (drift recovery)
336
350
 
337
351
  switchroom auth list # Accounts + health + which one is fleet-active
338
352
  switchroom auth show [agent] # Full snapshot (fleet + agents + consumers), or one agent
@@ -350,7 +364,9 @@ The same surface is reachable from Telegram in any agent's chat: `/auth show` (r
350
364
 
351
365
  ### Workspace (agent bootstrap layer)
352
366
 
353
- Each agent has a workspace directory (`~/.switchroom/agents/<name>/workspace/`) with editable stable files (`AGENTS.md`, `SOUL.md`, `USER.md`, `IDENTITY.md`, `TOOLS.md`) and dynamic files (`MEMORY.md`, `memory/YYYY-MM-DD.md`, `HEARTBEAT.md`) that are injected into the model's context at turn time.
367
+ Each agent has a workspace directory (`~/.switchroom/agents/<name>/workspace/`) with editable stable files (`AGENTS.md`, `USER.md`, `IDENTITY.md`, `TOOLS.md`) and dynamic files (`MEMORY.md`, `memory/YYYY-MM-DD.md`, `HEARTBEAT.md`) injected into the model's context at turn time.
368
+
369
+ `SOUL.md` (the persona) is a special case since v0.12.0: it's **user-owned and seeded once** — switchroom writes it at first scaffold (from the setup wizard's persona prompts or the profile default) and then *never overwrites it*, the deliberate inverse of the switchroom-managed `CLAUDE.md`. Edit it freely; `switchroom update` won't touch it. Use `switchroom soul reset <agent>` to re-seed from the profile (it backs the old one up first). See [docs/configuration.md § Persona & SOUL.md ownership](docs/configuration.md#persona--soulmd-ownership).
354
370
 
355
371
  ```bash
356
372
  switchroom workspace path <agent> # Print the workspace dir
@@ -414,7 +430,7 @@ Overlay entries win on collision with built-in defaults. Unknown files that appe
414
430
  | **[Vault](docs/vault.md)** | Architecture, per-cron secrets, ACL, audit log, threat model |
415
431
  | **[Telegram Plugin](docs/telegram-plugin.md)** | Progress cards, 15 MCP tools, native checklists, sticker aliases, voice-in |
416
432
  | **[Sub-Agents](docs/sub-agents.md)** | Model routing, delegation patterns, frontmatter spec |
417
- | **[Scheduling](docs/scheduling.md)** | Cron tasks (per-agent scheduler container), model selection |
433
+ | **[Scheduling](docs/scheduling.md)** | Cron tasks (in-agent scheduler sidecar), model selection |
418
434
  | **[Session Management](docs/session-optimization.md)** | Continuity, compaction, freshness policy |
419
435
  | **[OpenClaw alternative](docs/vs-openclaw.md)** | Switchroom vs OpenClaw |
420
436
  | **[NanoClaw alternative](docs/vs-nanoclaw.md)** | Switchroom vs NanoClaw |