switchroom 0.7.15 → 0.10.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.
Files changed (301) hide show
  1. package/README.md +51 -59
  2. package/bin/run-hook.sh +27 -11
  3. package/bin/timezone-hook.sh +9 -7
  4. package/dist/agent-scheduler/index.js +410 -133
  5. package/dist/auth-broker/index.js +13932 -0
  6. package/dist/cli/switchroom.js +26937 -5601
  7. package/dist/host-control/main.js +12702 -0
  8. package/dist/vault/approvals/kernel-server.js +467 -184
  9. package/dist/vault/broker/server.js +1430 -724
  10. package/examples/minimal.yaml +63 -0
  11. package/examples/personal-google-workspace-mcp/.env.example +34 -0
  12. package/examples/personal-google-workspace-mcp/README.md +194 -0
  13. package/examples/personal-google-workspace-mcp/compose.yaml +66 -0
  14. package/examples/switchroom.yaml +220 -0
  15. package/package.json +7 -4
  16. package/profiles/_base/settings.json.hbs +20 -5
  17. package/profiles/_base/start.sh.hbs +16 -3
  18. package/profiles/_shared/agent-self-service.md.hbs +126 -0
  19. package/profiles/_shared/telegram-style.md.hbs +20 -90
  20. package/profiles/_shared/vault-protocol.md.hbs +68 -0
  21. package/profiles/default/CLAUDE.md +50 -96
  22. package/profiles/default/CLAUDE.md.hbs +36 -6
  23. package/profiles/default/workspace/SOUL.md.hbs +12 -5
  24. package/skills/buildkite-agent-infrastructure/SKILL.md +30 -11
  25. package/skills/buildkite-agent-runtime/SKILL.md +44 -11
  26. package/skills/buildkite-api/SKILL.md +31 -8
  27. package/skills/buildkite-cli/SKILL.md +27 -9
  28. package/skills/buildkite-migration/SKILL.md +22 -9
  29. package/skills/buildkite-pipelines/SKILL.md +26 -9
  30. package/skills/buildkite-secure-delivery/SKILL.md +23 -9
  31. package/skills/buildkite-test-engine/SKILL.md +25 -8
  32. package/skills/docx/SKILL.md +1 -1
  33. package/skills/docx/scripts/office/validators/__pycache__/__init__.cpython-313.pyc +0 -0
  34. package/skills/docx/scripts/office/validators/__pycache__/base.cpython-313.pyc +0 -0
  35. package/skills/file-bug/SKILL.md +34 -6
  36. package/skills/humanizer/SKILL.md +15 -0
  37. package/skills/humanizer-calibrate/SKILL.md +7 -1
  38. package/skills/mcp-builder/SKILL.md +1 -1
  39. package/skills/pdf/SKILL.md +1 -1
  40. package/skills/pptx/SKILL.md +1 -1
  41. package/skills/skill-creator/SKILL.md +21 -1
  42. package/skills/skill-creator/scripts/__pycache__/__init__.cpython-313.pyc +0 -0
  43. package/skills/skill-creator/scripts/__pycache__/generate_report.cpython-313.pyc +0 -0
  44. package/skills/skill-creator/scripts/__pycache__/improve_description.cpython-313.pyc +0 -0
  45. package/skills/skill-creator/scripts/__pycache__/run_eval.cpython-313.pyc +0 -0
  46. package/skills/skill-creator/scripts/__pycache__/run_loop.cpython-313.pyc +0 -0
  47. package/skills/skill-creator/scripts/__pycache__/utils.cpython-313.pyc +0 -0
  48. package/skills/switchroom-cli/SKILL.md +63 -64
  49. package/skills/switchroom-health/SKILL.md +23 -10
  50. package/skills/switchroom-install/SKILL.md +3 -3
  51. package/skills/switchroom-manage/SKILL.md +26 -19
  52. package/skills/switchroom-runtime/SKILL.md +191 -0
  53. package/skills/switchroom-status/SKILL.md +27 -2
  54. package/skills/telegram-test-harness/SKILL.md +3 -0
  55. package/skills/token-helpers/SKILL.md +24 -1
  56. package/skills/webapp-testing/SKILL.md +31 -1
  57. package/skills/xlsx/SKILL.md +1 -1
  58. package/telegram-plugin/admin-commands/index.ts +7 -5
  59. package/telegram-plugin/analytics-posthog.ts +191 -0
  60. package/telegram-plugin/bridge/bridge.ts +69 -0
  61. package/telegram-plugin/bridge/ipc-client.ts +4 -1
  62. package/telegram-plugin/dist/bridge/bridge.js +194 -119
  63. package/telegram-plugin/dist/gateway/gateway.js +23611 -19671
  64. package/telegram-plugin/dist/server.js +245 -189
  65. package/telegram-plugin/first-paint.ts +3 -24
  66. package/telegram-plugin/gateway/auth-add-flow.ts +326 -0
  67. package/telegram-plugin/gateway/auth-broker-client.ts +75 -0
  68. package/telegram-plugin/gateway/auth-command.ts +794 -0
  69. package/telegram-plugin/gateway/auth-line.ts +123 -0
  70. package/telegram-plugin/gateway/boot-card.ts +169 -40
  71. package/telegram-plugin/gateway/boot-issue-cache.ts +308 -0
  72. package/telegram-plugin/gateway/boot-probes.ts +166 -123
  73. package/telegram-plugin/gateway/boot-reason.ts +41 -7
  74. package/telegram-plugin/gateway/boot-version.ts +66 -0
  75. package/telegram-plugin/gateway/gateway.ts +3499 -1885
  76. package/telegram-plugin/gateway/hostd-dispatch.ts +117 -0
  77. package/telegram-plugin/gateway/ipc-protocol.ts +18 -0
  78. package/telegram-plugin/gateway/pending-inbound-buffer.ts +106 -0
  79. package/telegram-plugin/gateway/quarantine.ts +69 -0
  80. package/telegram-plugin/gateway/quota-cache.ts +9 -4
  81. package/telegram-plugin/gateway/reaction-trigger.ts +401 -0
  82. package/telegram-plugin/gateway/recent-denials.test.ts +103 -0
  83. package/telegram-plugin/gateway/recent-denials.ts +77 -0
  84. package/telegram-plugin/gateway/startup-network-retry.ts +109 -31
  85. package/telegram-plugin/gateway/vault-grant-inbound-builders.ts +125 -0
  86. package/telegram-plugin/history.ts +91 -0
  87. package/telegram-plugin/hooks/hooks.json +10 -0
  88. package/telegram-plugin/hooks/sandbox-hint-posttool.mjs +130 -0
  89. package/telegram-plugin/hooks/subagent-tracker-posttool.mjs +19 -2
  90. package/telegram-plugin/hooks/subagent-tracker-pretool.mjs +22 -2
  91. package/telegram-plugin/hooks/tool-label-pretool.mjs +11 -0
  92. package/telegram-plugin/hooks/wedge-detect-posttool.mjs +303 -0
  93. package/telegram-plugin/inbound-classifier.ts +50 -0
  94. package/telegram-plugin/inline-keyboard-callbacks.ts +136 -0
  95. package/telegram-plugin/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -0
  96. package/telegram-plugin/package.json +4 -2
  97. package/telegram-plugin/permission-rule.ts +51 -0
  98. package/telegram-plugin/permission-title.ts +56 -0
  99. package/telegram-plugin/quota-check.ts +19 -41
  100. package/telegram-plugin/registry/reaper.ts +223 -0
  101. package/telegram-plugin/retry-api-call.ts +80 -0
  102. package/telegram-plugin/runtime-metrics.ts +177 -0
  103. package/telegram-plugin/scripts/build.mjs +0 -1
  104. package/telegram-plugin/secret-detect/index.ts +24 -0
  105. package/telegram-plugin/secret-detect/vault-error.test.ts +64 -12
  106. package/telegram-plugin/secret-detect/vault-error.ts +78 -11
  107. package/telegram-plugin/secret-detect/vault-write.ts +14 -2
  108. package/telegram-plugin/server.js +41795 -0
  109. package/telegram-plugin/session-tail.ts +6 -1
  110. package/telegram-plugin/shared/bot-runtime.ts +5 -4
  111. package/telegram-plugin/silence-poke.ts +420 -0
  112. package/telegram-plugin/silent-end.ts +174 -0
  113. package/telegram-plugin/stream-controller.ts +13 -0
  114. package/telegram-plugin/stream-reply-handler.ts +7 -0
  115. package/telegram-plugin/subagent-watcher.ts +213 -4
  116. package/telegram-plugin/tests/auth-add-flow.test.ts +559 -0
  117. package/telegram-plugin/tests/auth-code-redact.test.ts +8 -4
  118. package/telegram-plugin/tests/auth-command-vernacular.test.ts +531 -0
  119. package/telegram-plugin/tests/boot-card-issue-dedup.test.ts +247 -0
  120. package/telegram-plugin/tests/boot-card-reason-to-render.test.ts +182 -0
  121. package/telegram-plugin/tests/boot-card-reason.test.ts +65 -2
  122. package/telegram-plugin/tests/boot-card-render.test.ts +146 -0
  123. package/telegram-plugin/tests/boot-card-silent-on-operator.test.ts +103 -0
  124. package/telegram-plugin/tests/boot-probes.test.ts +216 -10
  125. package/telegram-plugin/tests/boot-version-string.test.ts +0 -0
  126. package/telegram-plugin/tests/finalize-callback.test.ts +190 -0
  127. package/telegram-plugin/tests/gateway-message-validator.test.ts +26 -0
  128. package/telegram-plugin/tests/gateway-secret-detect.test.ts +12 -3
  129. package/telegram-plugin/tests/gateway-startup-network-retry.test.ts +104 -0
  130. package/telegram-plugin/tests/history-reaper.test.ts +378 -0
  131. package/telegram-plugin/tests/hostd-dispatch.test.ts +129 -0
  132. package/telegram-plugin/tests/inbound-classifier.test.ts +76 -0
  133. package/telegram-plugin/tests/inbound-message-types.test.ts +267 -0
  134. package/telegram-plugin/tests/issues-card.test.ts +49 -0
  135. package/telegram-plugin/tests/pending-inbound-buffer.test.ts +132 -0
  136. package/telegram-plugin/tests/permission-rule.test.ts +80 -1
  137. package/telegram-plugin/tests/permission-title.test.ts +31 -0
  138. package/telegram-plugin/tests/quota-check.test.ts +5 -35
  139. package/telegram-plugin/tests/races.test.ts +179 -0
  140. package/telegram-plugin/tests/reaction-trigger-flow.test.ts +353 -0
  141. package/telegram-plugin/tests/reaction-trigger.test.ts +397 -0
  142. package/telegram-plugin/tests/retry-api-call.test.ts +152 -1
  143. package/telegram-plugin/tests/runtime-metrics.test.ts +145 -0
  144. package/telegram-plugin/tests/sandbox-hint-posttool.test.ts +155 -0
  145. package/telegram-plugin/tests/secret-detect-delete-must-surface-failures.test.ts +133 -0
  146. package/telegram-plugin/tests/secret-detect-false-positives.test.ts +137 -0
  147. package/telegram-plugin/tests/silence-poke.test.ts +493 -0
  148. package/telegram-plugin/tests/silent-end.test.ts +206 -0
  149. package/telegram-plugin/tests/subagent-tracker-hooks.test.ts +107 -0
  150. package/telegram-plugin/tests/subagent-watcher-env-thresholds.test.ts +224 -0
  151. package/telegram-plugin/tests/subagent-watcher-stall-terminal.test.ts +316 -0
  152. package/telegram-plugin/tests/subagent-watcher.test.ts +263 -0
  153. package/telegram-plugin/tests/turn-signal-tracker.test.ts +81 -0
  154. package/telegram-plugin/tests/vault-approval-posture.test.ts +256 -0
  155. package/telegram-plugin/tests/vault-grant-auto-resume.test.ts +73 -0
  156. package/telegram-plugin/tests/vault-grant-inbound-builders.test.ts +226 -0
  157. package/telegram-plugin/tests/vault-grant-union.test.ts +130 -0
  158. package/telegram-plugin/tests/vault-key-regex-allows-slash.test.ts +140 -0
  159. package/telegram-plugin/tests/vault-posture-quarantine.test.ts +104 -0
  160. package/telegram-plugin/tests/vault-request-access-tool.test.ts +114 -0
  161. package/telegram-plugin/tests/vault-request-access-unlock-resume.test.ts +106 -0
  162. package/telegram-plugin/turn-signal-tracker.ts +100 -24
  163. package/telegram-plugin/uat/SETUP.md +210 -35
  164. package/telegram-plugin/uat/assertions.ts +264 -37
  165. package/telegram-plugin/uat/driver-info.ts +57 -0
  166. package/telegram-plugin/uat/driver.ts +590 -51
  167. package/telegram-plugin/uat/harness.ts +140 -94
  168. package/telegram-plugin/uat/load-env.test.ts +72 -0
  169. package/telegram-plugin/uat/load-env.ts +48 -0
  170. package/telegram-plugin/uat/login.ts +96 -53
  171. package/telegram-plugin/uat/runners/agent-self-sufficiency.ts +457 -0
  172. package/telegram-plugin/uat/runners/paraphrases.ts +231 -0
  173. package/telegram-plugin/uat/runners/report.ts +150 -0
  174. package/telegram-plugin/uat/runners/run-agent-self-sufficiency.sh +50 -0
  175. package/telegram-plugin/uat/runners/scorer.test.ts +196 -0
  176. package/telegram-plugin/uat/runners/scorer.ts +106 -0
  177. package/telegram-plugin/uat/runners/skill-coverage.test.ts +100 -0
  178. package/telegram-plugin/uat/runners/skill-coverage.ts +620 -0
  179. package/telegram-plugin/uat/scenarios/ask-user-button-tap-dm.test.ts +141 -0
  180. package/telegram-plugin/uat/scenarios/bg-sub-agent-dispatch-dm.test.ts +191 -0
  181. package/telegram-plugin/uat/scenarios/fuzz-extended-dm.test.ts +255 -0
  182. package/telegram-plugin/uat/scenarios/fuzz-human-style-dm.test.ts +275 -0
  183. package/telegram-plugin/uat/scenarios/fuzz-random-prompts-dm.test.ts +146 -0
  184. package/telegram-plugin/uat/scenarios/fuzz-status-ask-dm.test.ts +486 -0
  185. package/telegram-plugin/uat/scenarios/jtbd-interrupt-marker-dm.test.ts +67 -0
  186. package/telegram-plugin/uat/scenarios/jtbd-rapid-followup-dm.test.ts +100 -0
  187. package/telegram-plugin/uat/scenarios/jtbd-soft-commit-dm.test.ts +67 -0
  188. package/telegram-plugin/uat/scenarios/jtbd-status-query-dm.test.ts +49 -0
  189. package/telegram-plugin/uat/scenarios/location-inbound-dm.test.ts +65 -0
  190. package/telegram-plugin/uat/scenarios/midturn-silent-dm.test.ts +175 -0
  191. package/telegram-plugin/uat/scenarios/reactions-dm.test.ts +142 -0
  192. package/telegram-plugin/uat/scenarios/reactions-trigger-turn-dm.test.ts +96 -0
  193. package/telegram-plugin/uat/scenarios/secret-redaction-deletes-original-dm.test.ts +123 -0
  194. package/telegram-plugin/uat/scenarios/secret-redaction-no-false-positive-dm.test.ts +87 -0
  195. package/telegram-plugin/uat/scenarios/silence-poke-soft-dm.test.ts +155 -0
  196. package/telegram-plugin/uat/scenarios/silent-end-recovery-dm.test.ts +95 -0
  197. package/telegram-plugin/uat/scenarios/smoke-dm-reply.test.ts +57 -0
  198. package/telegram-plugin/uat/scenarios/subagent-watcher-no-rerun-dm.test.ts +135 -0
  199. package/telegram-plugin/uat/scenarios/vault-approval-posture-telegram-id-dm.test.ts +191 -0
  200. package/telegram-plugin/uat/scenarios/vault-audit-allow-dm.test.ts +108 -0
  201. package/telegram-plugin/uat/scenarios/vault-grant-auto-resume-dm.test.ts +121 -0
  202. package/telegram-plugin/uat/scenarios/vault-request-access-concurrent-dm.test.ts +161 -0
  203. package/telegram-plugin/uat/scenarios/vault-request-access-end-to-end-dm.test.ts +158 -0
  204. package/telegram-plugin/uat/scenarios/voice-inbound-dm.test.ts +65 -0
  205. package/telegram-plugin/vault-approval-posture.ts +42 -0
  206. package/telegram-plugin/welcome-text.ts +1 -0
  207. package/telegram-plugin/active-pins-sweep.ts +0 -204
  208. package/telegram-plugin/active-pins.ts +0 -146
  209. package/telegram-plugin/auth-dashboard.ts +0 -1104
  210. package/telegram-plugin/auth-slot-parser.ts +0 -497
  211. package/telegram-plugin/card-event-log.ts +0 -138
  212. package/telegram-plugin/dist/foreman/foreman.js +0 -31106
  213. package/telegram-plugin/docs/multi-agent-card-design.md +0 -847
  214. package/telegram-plugin/docs/pinned-progress-card-reliability.md +0 -144
  215. package/telegram-plugin/foreman/foreman-create-flow.ts +0 -202
  216. package/telegram-plugin/foreman/foreman-handlers.ts +0 -493
  217. package/telegram-plugin/foreman/foreman.ts +0 -1165
  218. package/telegram-plugin/foreman/setup-flow.ts +0 -345
  219. package/telegram-plugin/foreman/setup-state.ts +0 -239
  220. package/telegram-plugin/foreman/state.ts +0 -203
  221. package/telegram-plugin/pin-event-log.ts +0 -76
  222. package/telegram-plugin/progress-card-driver.ts +0 -2886
  223. package/telegram-plugin/progress-card-pin-manager.ts +0 -589
  224. package/telegram-plugin/progress-card-pin-watchdog.ts +0 -98
  225. package/telegram-plugin/progress-card.ts +0 -1409
  226. package/telegram-plugin/tests/HARNESS.md +0 -340
  227. package/telegram-plugin/tests/_progress-card-harness.ts +0 -109
  228. package/telegram-plugin/tests/active-pins-boot-reaper.test.ts +0 -211
  229. package/telegram-plugin/tests/active-pins-sweep.test.ts +0 -309
  230. package/telegram-plugin/tests/active-pins.test.ts +0 -187
  231. package/telegram-plugin/tests/auth-account-identity-surface.test.ts +0 -118
  232. package/telegram-plugin/tests/auth-dashboard-edge-cases.test.ts +0 -260
  233. package/telegram-plugin/tests/auth-dashboard-restart-flow.test.ts +0 -140
  234. package/telegram-plugin/tests/auth-dashboard-v3b.test.ts +0 -559
  235. package/telegram-plugin/tests/auth-dashboard.test.ts +0 -1045
  236. package/telegram-plugin/tests/auth-slot-commands.test.ts +0 -640
  237. package/telegram-plugin/tests/bg-agent-progress-card-757.test.ts +0 -201
  238. package/telegram-plugin/tests/boot-card-account-quota.test.ts +0 -137
  239. package/telegram-plugin/tests/card-event-log.test.ts +0 -145
  240. package/telegram-plugin/tests/first-paint.test.ts +0 -257
  241. package/telegram-plugin/tests/foreman-create-flow.test.ts +0 -359
  242. package/telegram-plugin/tests/foreman-handlers.test.ts +0 -347
  243. package/telegram-plugin/tests/foreman-state.test.ts +0 -164
  244. package/telegram-plugin/tests/foreman-write-ops.test.ts +0 -214
  245. package/telegram-plugin/tests/harness-ordering-invariants.test.ts +0 -243
  246. package/telegram-plugin/tests/pin-event-log.test.ts +0 -124
  247. package/telegram-plugin/tests/progress-card-api-failure-during-deferred.test.ts +0 -73
  248. package/telegram-plugin/tests/progress-card-close-paths-converge.test.ts +0 -272
  249. package/telegram-plugin/tests/progress-card-cross-turn.test.ts +0 -258
  250. package/telegram-plugin/tests/progress-card-delay-842.test.ts +0 -160
  251. package/telegram-plugin/tests/progress-card-dispose-preservepending.test.ts +0 -81
  252. package/telegram-plugin/tests/progress-card-draft-flag.test.ts +0 -80
  253. package/telegram-plugin/tests/progress-card-driver-eviction.test.ts +0 -215
  254. package/telegram-plugin/tests/progress-card-driver-fleet-shadow.test.ts +0 -123
  255. package/telegram-plugin/tests/progress-card-driver-force-complete-parent-done.test.ts +0 -76
  256. package/telegram-plugin/tests/progress-card-edit-timestamps-budget.test.ts +0 -62
  257. package/telegram-plugin/tests/progress-card-memory-bounds.test.ts +0 -84
  258. package/telegram-plugin/tests/progress-card-pin-failure-paths.test.ts +0 -139
  259. package/telegram-plugin/tests/progress-card-pin-manager.test.ts +0 -773
  260. package/telegram-plugin/tests/progress-card-pin-race-fast-turn.test.ts +0 -66
  261. package/telegram-plugin/tests/progress-card-pin-sidecar-partial-write.test.ts +0 -64
  262. package/telegram-plugin/tests/progress-card-pin-watchdog.test.ts +0 -190
  263. package/telegram-plugin/tests/progress-card-sigterm-pin-flush.test.ts +0 -146
  264. package/telegram-plugin/tests/real-gateway-f1-ladder-integrity.test.ts +0 -123
  265. package/telegram-plugin/tests/real-gateway-f2-instant-draft.test.ts +0 -82
  266. package/telegram-plugin/tests/real-gateway-f3-late-card.test.ts +0 -114
  267. package/telegram-plugin/tests/real-gateway-harness.ts +0 -699
  268. package/telegram-plugin/tests/real-gateway-i6-turn-flush-replay-dedup.test.ts +0 -313
  269. package/telegram-plugin/tests/real-gateway-ipc-lifecycle.test.ts +0 -299
  270. package/telegram-plugin/tests/real-gateway-spec.test.ts +0 -487
  271. package/telegram-plugin/tests/real-gateway.smoke.test.ts +0 -101
  272. package/telegram-plugin/tests/setup-flow.test.ts +0 -510
  273. package/telegram-plugin/tests/setup-state.test.ts +0 -146
  274. package/telegram-plugin/tests/sync-chat-running-subagents.test.ts +0 -116
  275. package/telegram-plugin/tests/turn-end-regressions.test.ts +0 -489
  276. package/telegram-plugin/tests/turn-flush-card-takeover.test.ts +0 -218
  277. package/telegram-plugin/tests/turn-flush-prose-recovery.test.ts +0 -78
  278. package/telegram-plugin/tests/two-zone-bg-carry-full-lifecycle.test.ts +0 -131
  279. package/telegram-plugin/tests/two-zone-bg-detection.test.ts +0 -120
  280. package/telegram-plugin/tests/two-zone-bg-done-when-all-terminal.test.ts +0 -116
  281. package/telegram-plugin/tests/two-zone-bg-early-turn-end.test.ts +0 -87
  282. package/telegram-plugin/tests/two-zone-bg-survives-next-turn.test.ts +0 -211
  283. package/telegram-plugin/tests/two-zone-card-cap.test.ts +0 -62
  284. package/telegram-plugin/tests/two-zone-card-fleet-row.test.ts +0 -101
  285. package/telegram-plugin/tests/two-zone-card-header-phases.test.ts +0 -78
  286. package/telegram-plugin/tests/two-zone-card-html-balance.test.ts +0 -110
  287. package/telegram-plugin/tests/two-zone-card-lifecycle.test.ts +0 -128
  288. package/telegram-plugin/tests/two-zone-card-sanitise.test.ts +0 -58
  289. package/telegram-plugin/tests/two-zone-card-snapshot.test.ts +0 -133
  290. package/telegram-plugin/tests/two-zone-concurrent-turns-isolation.test.ts +0 -155
  291. package/telegram-plugin/tests/two-zone-phasefor-precedence.test.ts +0 -117
  292. package/telegram-plugin/tests/two-zone-snapshot-extras.test.ts +0 -187
  293. package/telegram-plugin/tests/two-zone-stuck-edit-throttle.test.ts +0 -149
  294. package/telegram-plugin/tests/two-zone-stuck-header-escalation.test.ts +0 -101
  295. package/telegram-plugin/tests/two-zone-stuck-per-member.test.ts +0 -114
  296. package/telegram-plugin/tests/two-zone-stuck-recovery.test.ts +0 -105
  297. package/telegram-plugin/tests/waiting-ux-harness.ts +0 -381
  298. package/telegram-plugin/tests/waiting-ux.e2e.test.ts +0 -233
  299. package/telegram-plugin/turn-flush-prose-recovery.ts +0 -40
  300. package/telegram-plugin/two-zone-card.ts +0 -269
  301. package/telegram-plugin/uat/scenarios/smoke-clerk-reply.test.ts +0 -61
@@ -0,0 +1,63 @@
1
+ # switchroom.yaml — Minimal single-agent setup.
2
+ # One bot, one agent, DM-only (no forum/topic routing).
3
+ #
4
+ # `vault:telegram-bot-token` is the canonical way to reference the bot
5
+ # token — `switchroom setup` stores your BotFather token in the vault
6
+ # under that key and the runtime resolves it via the vault broker.
7
+ # (For bootstrap before the vault exists, the wizard also accepts
8
+ # TELEGRAM_BOT_TOKEN as an env-var fallback.)
9
+ #
10
+ # `forum_chat_id: "0"` is the DM-only sentinel used by v0.7+ — kept in
11
+ # the schema for backwards compat with legacy forum-mode installs.
12
+
13
+ switchroom:
14
+ version: 1
15
+
16
+ telegram:
17
+ bot_token: "vault:telegram-bot-token"
18
+ forum_chat_id: "0"
19
+
20
+ memory:
21
+ backend: hindsight
22
+ shared_collection: shared
23
+
24
+ defaults:
25
+ model: claude-sonnet-4-6
26
+ tools:
27
+ allow: [all]
28
+ subagents:
29
+ worker:
30
+ description: "Handles implementation tasks: writing, editing, building, testing. Use for any task that takes more than a few seconds."
31
+ model: sonnet
32
+ background: true
33
+ isolation: worktree
34
+ maxTurns: 50
35
+ color: blue
36
+ prompt: |
37
+ You are a worker sub-agent. Implement the task described in your
38
+ prompt precisely and completely. Commit your work when done.
39
+ If requirements are ambiguous, state your assumptions rather
40
+ than guessing. Return a concise summary of what you did.
41
+ researcher:
42
+ description: "Explores codebases, reads documentation, searches for information. Use for any research or investigation task."
43
+ model: haiku
44
+ background: true
45
+ color: green
46
+ prompt: |
47
+ You are a research sub-agent. Investigate the topic described
48
+ in your prompt thoroughly. Return structured findings — not
49
+ raw file contents. Keep your report under 500 words unless
50
+ the parent explicitly asks for more detail.
51
+ reviewer:
52
+ description: "Reviews code, plans, documents for quality, correctness, and completeness. Use after a worker finishes or before shipping."
53
+ model: sonnet
54
+ color: purple
55
+ prompt: |
56
+ You are a review sub-agent. Examine the work described in
57
+ your prompt for correctness, completeness, security, and
58
+ quality. Report findings as a punch list: what's good, what
59
+ needs fixing, what's missing. Be rigorous but concise.
60
+
61
+ agents:
62
+ assistant:
63
+ topic_name: "General"
@@ -0,0 +1,34 @@
1
+ # Personal Google Workspace MCP — environment configuration.
2
+ #
3
+ # Copy to `.env` and fill in:
4
+ # GOOGLE_OAUTH_CLIENT_ID — from your Google Cloud Console OAuth client (Desktop app type)
5
+ # FASTMCP_SERVER_AUTH_GOOGLE_JWT_SIGNING_KEY — generate via: openssl rand -hex 32
6
+ #
7
+ # OAuth 2.1 PKCE flow — no client_secret needed (Desktop clients are
8
+ # public clients per OAuth 2.0 spec; PKCE replaces the secret's role).
9
+
10
+ # Required by upstream MCP for OAuth 2.1 mode.
11
+ MCP_ENABLE_OAUTH21=true
12
+
13
+ # Your OAuth client ID from Google Cloud Console.
14
+ # Create: APIs & Services → Credentials → Create OAuth client ID → Desktop app.
15
+ # Format: "12345678-abc...xyz.apps.googleusercontent.com"
16
+ GOOGLE_OAUTH_CLIENT_ID=REPLACE_WITH_YOUR_CLIENT_ID
17
+
18
+ # Port the MCP server listens on (must match compose.yaml's port mapping
19
+ # AND the URL in your .mcp.json). 8217 is arbitrary; pick anything free.
20
+ WORKSPACE_MCP_PORT=8217
21
+
22
+ # OAuth callback URL — must match WORKSPACE_MCP_PORT exactly.
23
+ # Loopback `localhost` is implicitly allowed for Desktop OAuth clients,
24
+ # no GCP-side redirect URI registration needed.
25
+ GOOGLE_OAUTH_REDIRECT_URI=http://localhost:8217/oauth2callback
26
+
27
+ # Required for the loopback OAuth flow over plain HTTP. Safe in this
28
+ # context — the OAuth handshake never leaves localhost.
29
+ OAUTHLIB_INSECURE_TRANSPORT=1
30
+
31
+ # JWT signing key for the MCP's session tokens. Generate ONCE per
32
+ # install: openssl rand -hex 32
33
+ # DO NOT commit the real value to source control.
34
+ FASTMCP_SERVER_AUTH_GOOGLE_JWT_SIGNING_KEY=REPLACE_WITH_HEX_FROM_OPENSSL_RAND
@@ -0,0 +1,194 @@
1
+ # Personal Google Workspace MCP
2
+
3
+ This example sets up [taylorwilsdon/google_workspace_mcp][upstream] as a
4
+ docker-compose service exposing Google Drive + Docs + Sheets + Calendar
5
+ tools to **your own Claude Code session on the host** (not to switchroom
6
+ agents).
7
+
8
+ It is intentionally **separate from the agent-side feature.** Agents get
9
+ Workspace access via `switchroom auth google connect <agent>` (RFC G
10
+ §4.5, available after Phase 3 lands). This example is for the
11
+ operator's pair-design loop with their own host-side `claude`.
12
+
13
+ > **Why two paths?** Agents run inside switchroom containers with
14
+ > approval-kernel-mediated tool access; the per-agent OAuth posture is
15
+ > load-bearing for the approval semantics (RFC D §2 + RFC G §4.4).
16
+ > Your own host-side Claude Code is a single-identity surface — none of
17
+ > that machinery applies. A shared HTTP MCP server is the right shape
18
+ > for the operator case and the wrong shape for the fleet.
19
+
20
+ [upstream]: https://github.com/taylorwilsdon/google_workspace_mcp
21
+
22
+ ## What you get
23
+
24
+ - A long-running docker container (`google-workspace-mcp`) listening on
25
+ loopback port 8217.
26
+ - 16 Workspace tools available to any Claude Code session that points
27
+ its `.mcp.json` at `http://127.0.0.1:8217/mcp`.
28
+ - OAuth 2.1 PKCE flow — no client_secret to manage.
29
+ - Refresh tokens persist in `./credentials/` so you re-auth only on
30
+ Google password change or 7-day Testing-mode expiry (see §5).
31
+
32
+ ## What you don't get
33
+
34
+ - Tools in unrelated Claude Code sessions. The `.mcp.json` is
35
+ project-scoped — Drive surface only appears when you `cd` to a
36
+ directory that has it.
37
+ - Any effect on switchroom agents.
38
+ - HTTPS or LAN reachability. Loopback only by design.
39
+
40
+ ## 1. GCP Console setup (~5 minutes, you do this)
41
+
42
+ 1. Go to <https://console.cloud.google.com> and create (or pick) a
43
+ project — name it `claude-workspace-mcp`.
44
+ 2. **APIs & Services → Library** — enable each of these (one at a time;
45
+ wait for "API enabled" before moving on):
46
+ - Google Drive API
47
+ - Google Docs API
48
+ - Google Sheets API
49
+ - Google Calendar API
50
+ 3. **APIs & Services → OAuth consent screen** → User Type **External**.
51
+ - Fill App name (`claude-workspace-mcp`), your email, dev contact email.
52
+ - Save and continue past the Scopes page (the server requests scopes
53
+ at runtime — don't add any here).
54
+ - **Add yourself as a Test User** under "Audience" (your gmail
55
+ address).
56
+ - Decide whether to **Publish app** — see §5 for the trade-off.
57
+ 4. **APIs & Services → Credentials → Create Credentials → OAuth client
58
+ ID** → Application type **Desktop app** → name it `claude-code-local`.
59
+ 5. Copy the Client ID from the modal (looks like
60
+ `12345-abc...xyz.apps.googleusercontent.com`). You can ignore the
61
+ client secret — PKCE doesn't use it.
62
+
63
+ ## 2. Set up this directory
64
+
65
+ ```sh
66
+ cd examples/personal-google-workspace-mcp/
67
+ cp .env.example .env
68
+
69
+ # Edit .env:
70
+ # GOOGLE_OAUTH_CLIENT_ID ← paste from step 5 above
71
+ # FASTMCP_SERVER_AUTH_GOOGLE_JWT_SIGNING_KEY ← generate via:
72
+
73
+ # (GNU sed — Linux)
74
+ sed -i "s|REPLACE_WITH_HEX_FROM_OPENSSL_RAND|$(openssl rand -hex 32)|" .env
75
+
76
+ # (BSD sed — macOS — use this instead)
77
+ # sed -i '' "s|REPLACE_WITH_HEX_FROM_OPENSSL_RAND|$(openssl rand -hex 32)|" .env
78
+
79
+ chmod 600 .env
80
+ ```
81
+
82
+ ## 3. Bring it up
83
+
84
+ ```sh
85
+ docker compose up -d
86
+ docker compose ps # should show "healthy" within ~30s
87
+ docker compose logs -f # ctrl-c when you see "Uvicorn running on http://0.0.0.0:8217"
88
+ ```
89
+
90
+ ## 4. Wire it into Claude Code
91
+
92
+ Choose where the MCP server should be reachable:
93
+
94
+ **Project-scoped (recommended)** — the Workspace tools only appear when
95
+ you start Claude Code in this specific project directory:
96
+
97
+ ```sh
98
+ cat > /path/to/your/project/.mcp.json <<'JSON'
99
+ {
100
+ "mcpServers": {
101
+ "google-workspace": {
102
+ "type": "http",
103
+ "url": "http://127.0.0.1:8217/mcp"
104
+ }
105
+ }
106
+ }
107
+ JSON
108
+ ```
109
+
110
+ Restart Claude Code in that directory. On first start it'll prompt to
111
+ approve the new MCP server — say yes.
112
+
113
+ **User-scoped** (every Claude Code session sees Workspace tools): use
114
+ `claude mcp add` instead per upstream README — but think hard before you
115
+ do this, because you're then carrying Workspace authorization into every
116
+ unrelated codebase.
117
+
118
+ ## 5. OAuth consent — Testing vs Production trade-off
119
+
120
+ When you set up the consent screen in §1.3, you chose between leaving
121
+ the app in **Testing** or clicking **Publish app**.
122
+
123
+ - **Testing** (default): refresh tokens expire **every 7 days** for
124
+ Google's "unverified app + sensitive scopes" policy. You re-auth
125
+ weekly via the inline OAuth prompt.
126
+ - **Production**: no 7-day expiry. The "Publish app" button prompts
127
+ scary copy ("your app will be available to any user with a Google
128
+ Account") but for a personal Desktop OAuth client with you as the
129
+ only user, this is effectively a no-op — there's nothing to find or
130
+ use without your specific Client ID.
131
+
132
+ Pick whichever your nerve allows.
133
+
134
+ ## 6. Tier choice
135
+
136
+ `compose.yaml` defaults to `--tool-tier core` (~16 tools). Change to:
137
+
138
+ - `extended` (~40 tools) — adds Slides, Forms, Tasks, Chat. Re-consent
139
+ needed (broader OAuth scopes). Procedure:
140
+ 1. Edit `compose.yaml` to bump `--tool-tier core` → `--tool-tier extended`.
141
+ 2. **Delete the existing token** so the upgraded scopes get requested
142
+ on the next OAuth flow: `rm -rf ./credentials/`.
143
+ 3. `docker compose up -d --force-recreate`.
144
+ 4. Trigger a tool call from Claude Code — the OAuth URL will appear
145
+ inline; tap to consent at the new scopes.
146
+ - `complete` (~60+ tools) — adds Gmail. **Not recommended yet** — Gmail's
147
+ per-thread approval shape is unsuitable for the broad OAuth scopes
148
+ this tier requests. Wait for a dedicated Gmail spec.
149
+
150
+ ## 7. Maintenance
151
+
152
+ - **Logs**: `docker compose logs -f workspace-mcp`
153
+ - **Restart**: `docker compose restart workspace-mcp`
154
+ - **Re-auth** (Google password change or weekly Testing expiry): the
155
+ next failed tool call surfaces a fresh OAuth URL inline; tap to
156
+ consent, done.
157
+ - **Upgrade**: bump the `workspace-mcp==X.Y.Z` pin in `compose.yaml`,
158
+ then `docker compose up -d --force-recreate`.
159
+ - **Tear down**: `docker compose down` (keeps credentials);
160
+ `docker compose down -v` (deletes credentials, forces fresh OAuth).
161
+ - **Inspect tokens**: `ls -la ./credentials/` — one JSON file per
162
+ authenticated Google account.
163
+
164
+ ## 8. Troubleshooting
165
+
166
+ - **Container "unhealthy" forever**: check `docker compose logs` for
167
+ Python tracebacks. Most common cause: `GOOGLE_OAUTH_CLIENT_ID` or
168
+ `FASTMCP_SERVER_AUTH_GOOGLE_JWT_SIGNING_KEY` still has the
169
+ `REPLACE_WITH_*` placeholder.
170
+ - **Port 8217 collision**: bump the port in `.env`
171
+ (`WORKSPACE_MCP_PORT` + `GOOGLE_OAUTH_REDIRECT_URI`), in
172
+ `compose.yaml` (the `ports:` mapping AND the healthcheck script),
173
+ and in your `.mcp.json` URL.
174
+ - **OAuth flow fails with `redirect_uri_mismatch`**: make sure
175
+ `GOOGLE_OAUTH_REDIRECT_URI` in `.env` exactly matches
176
+ `WORKSPACE_MCP_PORT`. Loopback URIs don't need GCP-side registration
177
+ for Desktop clients, but they do need to match what the server
178
+ presents.
179
+ - **Claude Code doesn't show the new MCP server after `cd` to project**:
180
+ exit and re-launch Claude Code (`/exit`, then `claude -c` to keep
181
+ the conversation). `.mcp.json` is loaded at startup, not hot-reloaded.
182
+
183
+ ## 9. Security notes
184
+
185
+ - `.env` is mode 600 — don't commit, don't share, don't snapshot.
186
+ - `./credentials/` directory holds refresh tokens — same restrictions.
187
+ Add to disk-encryption scope if your host has any.
188
+ - The Workspace MCP sends data to Google APIs only, on your behalf,
189
+ using your OAuth client. No telemetry, no third-party endpoints
190
+ (verified per upstream's `pyproject.toml` dependency tree).
191
+ - The OAuth client_secret in your `gcp-oauth.keys.json` (if Google
192
+ Cloud Console gave you one) is **not used** in PKCE flow. Treat it
193
+ as cosmetic; you can ignore it. If it's worried you, regenerate it
194
+ in GCP Console — won't break anything.
@@ -0,0 +1,66 @@
1
+ # Personal Google Workspace MCP — operator-host Claude Code surface.
2
+ #
3
+ # This is the docker-compose pattern for an operator who wants their own
4
+ # Claude Code on the host to have Drive + Docs + Sheets + Calendar tools.
5
+ # It does NOT affect switchroom agents — they get Workspace via
6
+ # `switchroom auth google connect <agent>` (RFC G §4.5, post-Phase-3).
7
+ #
8
+ # Setup walkthrough: see README.md.
9
+ #
10
+ # Compose project name (`name:`) is deliberately distinct from the
11
+ # `switchroom` project so `switchroom apply` / `switchroom update` /
12
+ # `docker compose -p switchroom down -v` won't touch this container.
13
+ # Same isolation pattern as the hostd compose project.
14
+
15
+ name: google-workspace-mcp
16
+
17
+ services:
18
+ workspace-mcp:
19
+ image: ghcr.io/astral-sh/uv:python3.12-bookworm-slim
20
+ container_name: google-workspace-mcp
21
+ restart: unless-stopped
22
+ env_file: .env
23
+ environment:
24
+ WORKSPACE_MCP_CREDENTIALS_DIR: /credentials
25
+ ports:
26
+ # Loopback only — never expose Workspace MCP to the LAN.
27
+ # Bump the host-side port if 8217 collides with something else
28
+ # (also update WORKSPACE_MCP_PORT + GOOGLE_OAUTH_REDIRECT_URI in .env
29
+ # and the URL in your .mcp.json).
30
+ - "127.0.0.1:8217:8217"
31
+ volumes:
32
+ # Refresh tokens persist here (chmod 700-equivalent inside the
33
+ # container). Survives container recreate; lost on `docker compose
34
+ # down -v`.
35
+ - ./credentials:/credentials
36
+ command:
37
+ - uvx
38
+ # Pinned: bumping is a deliberate operator decision, not a silent
39
+ # surprise. Bump in lockstep with retesting the OAuth flow.
40
+ - --from
41
+ - workspace-mcp==1.20.4
42
+ - workspace-mcp
43
+ # streamable-http (not stdio) is required for OAuth 2.1 PKCE per
44
+ # upstream README.
45
+ - --transport
46
+ - streamable-http
47
+ # Tier knob — see README §4 for tier choice. `core` = ~16 tools
48
+ # (Drive + Docs + Sheets + Calendar, the validated default).
49
+ - --tool-tier
50
+ - core
51
+ # Restrict to only the four core services; omits Gmail (which is
52
+ # in `complete` tier and warrants its own approval shape).
53
+ - --tools
54
+ - drive
55
+ - docs
56
+ - sheets
57
+ - calendar
58
+ healthcheck:
59
+ # TCP-connect probe — the server returns 401 on `/mcp` until OAuth
60
+ # completes, which would fail an HTTP healthcheck. TCP-connect just
61
+ # verifies the listener is bound.
62
+ test: ["CMD-SHELL", "python -c \"import socket; s=socket.socket(); s.settimeout(2); s.connect(('127.0.0.1',8217)); s.close()\""]
63
+ interval: 30s
64
+ timeout: 5s
65
+ retries: 3
66
+ start_period: 20s
@@ -0,0 +1,220 @@
1
+ # switchroom.yaml — Full example configuration
2
+ #
3
+ # Switchroom uses a three-layer cascade for agent config:
4
+ # 1. defaults: → global baseline for every agent
5
+ # 2. profiles: → named presets agents opt into via `extends:`
6
+ # 3. agents: → per-agent overrides (only express differences)
7
+ #
8
+ # Each agent gets its own Telegram topic in a forum group.
9
+ # Create bots via @BotFather: /newbot for each agent.
10
+
11
+ switchroom:
12
+ version: 1
13
+ agents_dir: ~/.switchroom/agents
14
+ skills_dir: ~/.switchroom/skills # shared skill pool (symlinked per agent)
15
+
16
+ telegram:
17
+ bot_token: "vault:telegram-bot-token"
18
+ # DM-only sentinel; v0.7+ defaults to per-agent DM-pair topology.
19
+ # Legacy forum-mode installs keep a real chat id here.
20
+ forum_chat_id: "0"
21
+
22
+ memory:
23
+ backend: hindsight
24
+ shared_collection: shared
25
+ config:
26
+ provider: ollama
27
+ model: nomic-embed-text
28
+
29
+ vault:
30
+ # v0.7.12+ canonical path is the parent-dir layout. v0.7.x installs
31
+ # auto-migrate from the legacy ~/.switchroom/vault.enc on `switchroom
32
+ # apply`; the legacy path becomes a symlink that's removed in v0.7.14.
33
+ # See docs/vault.md for the migration story.
34
+ path: ~/.switchroom/vault/vault.enc
35
+
36
+ # --- Global defaults (implicit bottom-of-cascade profile) ---
37
+ # Every agent inherits this. Per-agent fields win on conflict.
38
+ # tools/skills/schedule are unioned; scalars are overridden.
39
+ defaults:
40
+ model: claude-sonnet-4-6
41
+ # The switchroom-telegram fork is the default. Uncomment to fall back to
42
+ # the upstream marketplace plugin: channels.telegram.plugin: official
43
+ channels:
44
+ telegram:
45
+ format: html
46
+ tools:
47
+ allow: [all]
48
+ env:
49
+ SWITCHROOM_AUDIT_URL: "https://audit.example"
50
+ hooks:
51
+ PreToolUse:
52
+ - command: "/opt/switchroom-audit.sh"
53
+ timeout: 5
54
+ # Bundled skills that ship with switchroom. `humanizer` removes AI-writing
55
+ # patterns from agent replies before they reach Telegram (29 patterns from
56
+ # Wikipedia's "Signs of AI writing" guide). `humanizer-calibrate` is its
57
+ # companion that builds a personal voice template from your message history.
58
+ # Remove from this list to disable. Per-agent `skills:` is unioned with
59
+ # this default — don't repeat shared skills in each agent.
60
+ skills: [humanizer, humanizer-calibrate]
61
+ # Optional: point the humanizer at a voice template generated by
62
+ # `/humanizer-calibrate`. Without this, falls back to generic rules.
63
+ # humanizer_voice_file: ~/.switchroom/voice.md
64
+ system_prompt_append: |
65
+ Always respond concisely.
66
+
67
+ # --- Default sub-agents ---
68
+ # Every agent gets these workers. They run on cheaper/faster models
69
+ # in the background so the main agent stays available for new requests.
70
+ # Override per-agent or per-profile by redefining the same name.
71
+ subagents:
72
+ worker:
73
+ description: "Handles implementation tasks: writing, editing, building, testing. Use for any task that takes more than a few seconds."
74
+ model: sonnet
75
+ background: true
76
+ # NOTE: `isolation: worktree` used to live here as a global default
77
+ # but moved to the `coding` profile in switchroom 0.6.6 (#682). It
78
+ # hard-failed for any agent whose cwd was not a git repo — i.e. the
79
+ # majority of switchroom agents, which run from
80
+ # `~/.switchroom/agents/<name>` with no git init. Worktree isolation
81
+ # is opt-in via `extends: coding` now. See CHANGELOG and #682.
82
+ # 100 turns is a comfortable budget for most worker tasks; if a
83
+ # worker exhausts this mid-flow, it'll be reported as #423-style
84
+ # ceiling. Bump to 200 for genuinely long PR-shipping flows or
85
+ # remove the line entirely to inherit Claude Code's default.
86
+ # Origin: this used to be 50 and was the literal cause of #423
87
+ # ("worker sub-agents hit ~50 tool-use ceiling mid-flow before
88
+ # finishing"). Don't shrink it without good reason.
89
+ maxTurns: 100
90
+ color: blue
91
+ disallowedTools:
92
+ - "mcp__switchroom-telegram__*"
93
+ prompt: |
94
+ You are a worker sub-agent. Implement the task described in your
95
+ prompt precisely and completely. Commit your work when done.
96
+ If requirements are ambiguous, state your assumptions rather
97
+ than guessing. Return a concise summary of what you did.
98
+ researcher:
99
+ description: "Explores codebases, reads documentation, searches for information. Use for any research or investigation task."
100
+ model: haiku
101
+ background: true
102
+ color: green
103
+ disallowedTools:
104
+ - "mcp__switchroom-telegram__*"
105
+ prompt: |
106
+ You are a research sub-agent. Investigate the topic described
107
+ in your prompt thoroughly. Return structured findings — not
108
+ raw file contents. Keep your report under 500 words unless
109
+ the parent explicitly asks for more detail.
110
+ reviewer:
111
+ description: "Reviews code, plans, documents for quality, correctness, and completeness. Use after a worker finishes or before shipping."
112
+ model: sonnet
113
+ color: purple
114
+ disallowedTools:
115
+ - "mcp__switchroom-telegram__*"
116
+ prompt: |
117
+ You are a review sub-agent. Examine the work described in
118
+ your prompt for correctness, completeness, security, and
119
+ quality. Report findings as a punch list: what's good, what
120
+ needs fixing, what's missing. Be rigorous but concise.
121
+
122
+ # --- Named profiles (opt-in presets) ---
123
+ # Agents inherit from a profile via `extends: <name>`.
124
+ # Inline profiles here take priority over filesystem profiles/<name>/
125
+ # (which can additionally bundle CLAUDE.md.hbs + skills/).
126
+ profiles:
127
+ # The `coding` profile pairs with `profiles/coding/` on disk (which
128
+ # ships the CLAUDE.md template and skills). Its inline counterpart
129
+ # here carries the YAML-level defaults that the filesystem assets
130
+ # advertise — worktree-isolated workers chief among them. Agents
131
+ # whose cwd IS a git checkout (a real code repo) should
132
+ # `extends: coding` to pick this up. Agents whose cwd is the default
133
+ # `~/.switchroom/agents/<name>` (no git) should NOT — Claude Code
134
+ # cannot create a worktree off a non-repo and the worker will fail.
135
+ coding:
136
+ subagents:
137
+ worker:
138
+ isolation: worktree
139
+
140
+ coder:
141
+ tools:
142
+ allow: [Bash, Read, Write, Edit, Grep, Glob]
143
+ system_prompt_append: |
144
+ You write production-quality TypeScript. Prefer explicit types.
145
+ skills: [code-review, architecture]
146
+
147
+ advisor:
148
+ tools:
149
+ deny: [Bash, Edit, Write]
150
+ soul:
151
+ style: warm, empathetic, non-prescriptive
152
+ boundaries: not a licensed professional — always recommend consulting a qualified expert
153
+ system_prompt_append: |
154
+ Prioritize listening and asking clarifying questions.
155
+
156
+ # --- Agents ---
157
+ # Minimal per-agent declarations. Everything else inherited.
158
+ agents:
159
+ coach:
160
+ topic_name: "Fitness"
161
+ topic_emoji: "🏋️"
162
+ extends: advisor # inherits from inline profile above
163
+ soul:
164
+ name: Coach
165
+ style: motivational, direct # overrides advisor.soul.style
166
+ memory:
167
+ collection: fitness
168
+ schedule:
169
+ - cron: "0 8 * * *"
170
+ prompt: "Good morning check-in: ask about sleep, energy, and plans for today"
171
+ - cron: "0 20 * * 0"
172
+ prompt: "Weekly review: summarize this week's activity and progress"
173
+
174
+ dev:
175
+ topic_name: "Code"
176
+ topic_emoji: "💻"
177
+ extends: coder # inherits from inline profile above
178
+ model: claude-opus-4-7 # override defaults.model for this agent
179
+ memory:
180
+ collection: coding
181
+ cli_args: ["--effort", "high"] # escape hatch: extra exec claude flags
182
+
183
+ assistant:
184
+ topic_name: "General"
185
+ topic_emoji: "💬"
186
+ memory:
187
+ collection: general
188
+ # No `extends:` → uses the "default" filesystem profile (profiles/default/)
189
+ # No tool/model overrides → inherits everything from defaults:
190
+
191
+ exec:
192
+ topic_name: "Executive"
193
+ topic_emoji: "📋"
194
+ extends: advisor
195
+ soul:
196
+ name: Friday
197
+ style: efficient, proactive, anticipates needs
198
+ skills: [daily-briefing, meeting-prep]
199
+ memory:
200
+ collection: executive
201
+ schedule:
202
+ - cron: "0 7 * * 1-5"
203
+ prompt: "Daily briefing: summarize today's calendar, pending tasks, and priorities"
204
+
205
+ # Example admin agent — its gateway intercepts fleet-management slash
206
+ # commands (/agents, /restart, /update, /logs, etc.) and runs them
207
+ # locally via the switchroom CLI instead of forwarding to Claude. Per-
208
+ # agent commands like /auth list, /auth reauth, /interrupt, /new work
209
+ # on every agent regardless of admin status. See the three-tier
210
+ # command model in docs/architecture.md.
211
+ #
212
+ # Uncomment after creating a second BotFather bot and adding its
213
+ # token to the vault (`switchroom vault set telegram-admin-bot-token`).
214
+ # admin:
215
+ # topic_name: "Admin"
216
+ # topic_emoji: "🛠️"
217
+ # bot_token: "vault:telegram-admin-bot-token"
218
+ # admin: true
219
+ # system_prompt_append: |
220
+ # You are the fleet admin agent. Always respond concisely.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "switchroom",
3
- "version": "0.7.15",
3
+ "version": "0.10.0",
4
4
  "description": "Run Claude Code 24/7 on your Claude Pro/Max subscription over Telegram. Open-source alternative to OpenClaw and NanoClaw — no API keys.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -9,6 +9,7 @@
9
9
  "main": "./dist/cli/switchroom.js",
10
10
  "files": [
11
11
  "dist",
12
+ "examples",
12
13
  "profiles",
13
14
  "skills",
14
15
  "telegram-plugin",
@@ -20,13 +21,15 @@
20
21
  "dev": "bun bin/switchroom.ts",
21
22
  "build": "node scripts/build.mjs",
22
23
  "build:cli": "node scripts/build.mjs && bun build --compile --target=bun-linux-x64 --minify bin/switchroom.ts --outfile switchroom-linux-amd64",
23
- "test": "vitest run && bun test telegram-plugin/tests/history.test.ts telegram-plugin/tests/ipc-server-client.test.ts telegram-plugin/tests/ipc-server-race.test.ts telegram-plugin/tests/gateway-bridge.test.ts telegram-plugin/tests/gateway-startup-mutex.test.ts telegram-plugin/tests/gateway-clean-shutdown-marker.test.ts telegram-plugin/tests/foreman-state.test.ts telegram-plugin/tests/boot-card-dedupe.test.ts telegram-plugin/tests/boot-card-reason.test.ts telegram-plugin/tests/progress-update.test.ts telegram-plugin/tests/quota-cache.test.ts telegram-plugin/tests/silent-reply-guard.test.ts telegram-plugin/tests/unhandled-rejection-policy.test.ts telegram-plugin/tests/registry-turns.test.ts telegram-plugin/registry/subagents.test.ts telegram-plugin/tests/turns-writer.test.ts telegram-plugin/registry/api-registry.test.ts telegram-plugin/registry/turns-schema.test.ts telegram-plugin/tests/idle-footer-wiring.test.ts telegram-plugin/tests/subagent-tracker-hooks.test.ts telegram-plugin/tests/resolve-calling-subagent.test.ts telegram-plugin/tests/gateway-update-placeholder-dispatch.test.ts",
24
+ "test": "vitest run && bun test telegram-plugin/tests/history.test.ts telegram-plugin/tests/history-reaper.test.ts telegram-plugin/tests/ipc-server-client.test.ts telegram-plugin/tests/ipc-server-race.test.ts telegram-plugin/tests/gateway-bridge.test.ts telegram-plugin/tests/gateway-startup-mutex.test.ts telegram-plugin/tests/gateway-clean-shutdown-marker.test.ts telegram-plugin/tests/boot-card-dedupe.test.ts telegram-plugin/tests/boot-card-reason.test.ts telegram-plugin/tests/progress-update.test.ts telegram-plugin/tests/quota-cache.test.ts telegram-plugin/tests/silent-reply-guard.test.ts telegram-plugin/tests/unhandled-rejection-policy.test.ts telegram-plugin/tests/registry-turns.test.ts telegram-plugin/registry/subagents.test.ts telegram-plugin/tests/turns-writer.test.ts telegram-plugin/registry/api-registry.test.ts telegram-plugin/registry/turns-schema.test.ts telegram-plugin/tests/idle-footer-wiring.test.ts telegram-plugin/tests/subagent-tracker-hooks.test.ts telegram-plugin/tests/resolve-calling-subagent.test.ts telegram-plugin/tests/gateway-update-placeholder-dispatch.test.ts telegram-plugin/tests/reaction-trigger.test.ts telegram-plugin/tests/reaction-trigger-flow.test.ts",
24
25
  "test:vitest": "vitest run",
25
- "test:bun": "bun test src/watchdog/state.test.ts src/watchdog/policy.test.ts src/vault/grants.test.ts src/vault/write-grants.test.ts src/vault/broker/server-grants.test.ts src/vault/broker/server-write-grants.test.ts src/vault/broker/server-passphrase-attest.test.ts src/vault/broker/client-token.test.ts src/vault/broker/server-unlock.test.ts src/vault/broker/auto-unlock.test.ts src/vault/broker/drift-detection.test.ts tests/vault-broker-passphrase.test.ts src/cli/vault-get-broker.test.ts src/vault/resolver-via-broker.test.ts src/vault/broker/scope.test.ts src/vault/broker/server.test.ts src/drive/disconnect.test.ts src/drive/grants.test.ts src/drive/oauth.test.ts src/drive/onboarding.test.ts src/drive/reconciler.test.ts src/drive/vault-slots.test.ts src/drive/wrapper.test.ts src/vault/approvals/kernel.test.ts src/vault/broker/server-approvals.test.ts telegram-plugin/tests/boot-probes.test.ts telegram-plugin/tests/setup-state.test.ts telegram-plugin/tests/history.test.ts telegram-plugin/tests/ipc-server-client.test.ts telegram-plugin/tests/ipc-server-race.test.ts telegram-plugin/tests/gateway-bridge.test.ts telegram-plugin/tests/gateway-startup-mutex.test.ts telegram-plugin/tests/gateway-clean-shutdown-marker.test.ts telegram-plugin/tests/foreman-state.test.ts telegram-plugin/tests/boot-card-dedupe.test.ts telegram-plugin/tests/boot-card-reason.test.ts telegram-plugin/tests/progress-update.test.ts telegram-plugin/tests/quota-cache.test.ts telegram-plugin/tests/silent-reply-guard.test.ts telegram-plugin/tests/unhandled-rejection-policy.test.ts telegram-plugin/tests/registry-turns.test.ts telegram-plugin/registry/subagents.test.ts telegram-plugin/tests/turns-writer.test.ts telegram-plugin/tests/resolve-calling-subagent.test.ts telegram-plugin/tests/gateway-update-placeholder-dispatch.test.ts",
26
+ "test:bun": "bun test src/watchdog/state.test.ts src/watchdog/policy.test.ts src/vault/grants.test.ts src/vault/write-grants.test.ts src/vault/broker/server-grants.test.ts src/vault/broker/server-write-grants.test.ts src/vault/broker/server-mint-grant-passphrase-attest.test.ts src/vault/broker/server-passphrase-attest.test.ts src/vault/broker/server-mint-grant-posture-attest.test.ts src/vault/broker/client-token.test.ts src/vault/broker/server-unlock.test.ts src/vault/broker/auto-unlock.test.ts src/vault/broker/drift-detection.test.ts tests/vault-broker-passphrase.test.ts src/cli/vault-get-broker.test.ts src/vault/resolver-via-broker.test.ts src/vault/broker/scope.test.ts src/vault/broker/server.test.ts src/drive/disconnect.test.ts src/drive/grants.test.ts src/drive/oauth.test.ts src/drive/onboarding.test.ts src/drive/reconciler.test.ts src/drive/vault-slots.test.ts src/drive/wrapper.test.ts src/vault/approvals/kernel.test.ts src/vault/approvals/schema-idempotent.test.ts src/vault/broker/server-approvals.test.ts telegram-plugin/tests/boot-probes.test.ts telegram-plugin/tests/boot-version-string.test.ts telegram-plugin/tests/history.test.ts telegram-plugin/tests/history-reaper.test.ts telegram-plugin/tests/ipc-server-client.test.ts telegram-plugin/tests/ipc-server-race.test.ts telegram-plugin/tests/gateway-bridge.test.ts telegram-plugin/tests/gateway-startup-mutex.test.ts telegram-plugin/tests/gateway-clean-shutdown-marker.test.ts telegram-plugin/tests/boot-card-dedupe.test.ts telegram-plugin/tests/boot-card-reason.test.ts telegram-plugin/tests/progress-update.test.ts telegram-plugin/tests/quota-cache.test.ts telegram-plugin/tests/silent-reply-guard.test.ts telegram-plugin/tests/unhandled-rejection-policy.test.ts telegram-plugin/tests/registry-turns.test.ts telegram-plugin/registry/subagents.test.ts telegram-plugin/tests/turns-writer.test.ts telegram-plugin/tests/resolve-calling-subagent.test.ts telegram-plugin/tests/gateway-update-placeholder-dispatch.test.ts telegram-plugin/tests/reaction-trigger.test.ts telegram-plugin/tests/reaction-trigger-flow.test.ts telegram-plugin/uat/load-env.test.ts",
26
27
  "test:watch": "vitest",
27
- "lint": "tsc --noEmit && node scripts/check-plugin-references.mjs",
28
+ "lint": "tsc --noEmit && node scripts/check-plugin-references.mjs && bash scripts/check-bot-api-wrapping.sh && node scripts/check-bun-test-imports.mjs",
28
29
  "lint:tsc": "tsc --noEmit",
29
30
  "lint:plugin-references": "node scripts/check-plugin-references.mjs",
31
+ "lint:bot-api-wrapping": "bash scripts/check-bot-api-wrapping.sh",
32
+ "lint:bun-test-imports": "node scripts/check-bun-test-imports.mjs",
30
33
  "prepublishOnly": "npm run build && npm run lint && npm test"
31
34
  },
32
35
  "dependencies": {
@@ -1,15 +1,30 @@
1
+ {{!--
2
+ Two keys deliberately omitted from this template (do not re-add):
3
+
4
+ * `skipDangerousModePermissionPrompt` — real key, but Claude Code IGNORES it
5
+ in project-level .claude/settings.json as a security measure (only user
6
+ or local scope is honored). It also belongs under `permissions.`, not
7
+ top-level. autoaccept (src/agents/autoaccept.ts) handles the prompt instead.
8
+ See https://code.claude.com/docs/en/settings (permissions section).
9
+
10
+ * `enabledPlugins` — REDUNDANT, not nonfunctional. Plugin selection is
11
+ driven at the CLI by profiles/_base/start.sh.hbs (`--channels
12
+ plugin:telegram@claude-plugins-official` in vanilla mode, or
13
+ `--dangerously-load-development-channels server:switchroom-telegram` in
14
+ vendored-plugin mode). Re-adding an `enabledPlugins` block here would
15
+ work but duplicate state with the CLI flag and risk drift.
16
+
17
+ A `settings_raw` block in switchroom.yaml CAN still inject either key via
18
+ the deep-merge escape hatch (src/config/merge.ts) — that's intentional
19
+ power-user territory, not a regression.
20
+ --}}
1
21
  {
2
22
  "permissions": {
3
23
  "allow": {{{json permissionAllow}}},
4
24
  "deny": {{{json toolsDeny}}}{{#if defaultModeAcceptEdits}},
5
25
  "defaultMode": "acceptEdits"{{/if}}
6
- },
7
- "enabledPlugins": {
8
- "telegram@claude-plugins-official": {{#if useSwitchroomPlugin}}false{{else}}true{{/if}}
9
26
  }{{#if hindsightEnabled}},
10
27
  "autoMemoryEnabled": false{{/if}}{{#if mcpServers}},
11
28
  "mcpServers": {{{json mcpServers}}}
12
- {{/if}}{{#if skipPermissionPrompt}},
13
- "skipDangerousModePermissionPrompt": true
14
29
  {{/if}}
15
30
  }