switchroom 0.8.1 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +54 -61
- package/bin/timezone-hook.sh +9 -7
- package/dist/agent-scheduler/index.js +285 -45
- package/dist/auth-broker/index.js +13932 -0
- package/dist/cli/drive-write-pretool.mjs +5418 -0
- package/dist/cli/switchroom.js +8890 -5560
- package/dist/host-control/main.js +582 -43
- package/dist/vault/approvals/kernel-server.js +276 -47
- package/dist/vault/broker/server.js +333 -69
- package/examples/minimal.yaml +63 -0
- package/examples/personal-google-workspace-mcp/.env.example +34 -0
- package/examples/personal-google-workspace-mcp/README.md +194 -0
- package/examples/personal-google-workspace-mcp/compose.yaml +66 -0
- package/examples/switchroom.yaml +220 -0
- package/package.json +6 -4
- package/profiles/_base/start.sh.hbs +3 -3
- package/profiles/_shared/agent-self-service.md.hbs +126 -0
- package/profiles/default/CLAUDE.md +10 -0
- package/profiles/default/CLAUDE.md.hbs +16 -0
- package/skills/buildkite-agent-infrastructure/SKILL.md +30 -11
- package/skills/buildkite-agent-runtime/SKILL.md +44 -11
- package/skills/buildkite-api/SKILL.md +31 -8
- package/skills/buildkite-cli/SKILL.md +27 -9
- package/skills/buildkite-migration/SKILL.md +22 -9
- package/skills/buildkite-pipelines/SKILL.md +26 -9
- package/skills/buildkite-secure-delivery/SKILL.md +23 -9
- package/skills/buildkite-test-engine/SKILL.md +25 -8
- package/skills/docx/SKILL.md +1 -1
- package/skills/file-bug/SKILL.md +34 -6
- package/skills/humanizer/SKILL.md +15 -0
- package/skills/humanizer-calibrate/SKILL.md +7 -1
- package/skills/mcp-builder/SKILL.md +1 -1
- package/skills/pdf/SKILL.md +1 -1
- package/skills/pptx/SKILL.md +1 -1
- package/skills/skill-creator/SKILL.md +21 -1
- package/skills/skill-creator/scripts/__pycache__/__init__.cpython-313.pyc +0 -0
- package/skills/skill-creator/scripts/__pycache__/generate_report.cpython-313.pyc +0 -0
- package/skills/skill-creator/scripts/__pycache__/improve_description.cpython-313.pyc +0 -0
- package/skills/skill-creator/scripts/__pycache__/run_eval.cpython-313.pyc +0 -0
- package/skills/skill-creator/scripts/__pycache__/run_loop.cpython-313.pyc +0 -0
- package/skills/skill-creator/scripts/__pycache__/utils.cpython-313.pyc +0 -0
- package/skills/switchroom-cli/SKILL.md +63 -64
- package/skills/switchroom-health/SKILL.md +23 -10
- package/skills/switchroom-install/SKILL.md +3 -3
- package/skills/switchroom-manage/SKILL.md +26 -19
- package/skills/switchroom-runtime/SKILL.md +67 -15
- package/skills/switchroom-status/SKILL.md +26 -1
- package/skills/telegram-test-harness/SKILL.md +3 -0
- package/skills/webapp-testing/SKILL.md +31 -1
- package/skills/xlsx/SKILL.md +1 -1
- package/telegram-plugin/admin-commands/dispatch.test.ts +1 -1
- package/telegram-plugin/admin-commands/index.ts +9 -5
- package/telegram-plugin/auth-snapshot-format.ts +612 -0
- package/telegram-plugin/auto-fallback-fleet.ts +215 -0
- package/telegram-plugin/auto-fallback.ts +28 -301
- package/telegram-plugin/dist/gateway/gateway.js +17453 -15100
- package/telegram-plugin/fleet-fallback-gate.ts +105 -0
- package/telegram-plugin/gateway/approval-callback.test.ts +104 -0
- package/telegram-plugin/gateway/approval-callback.ts +31 -3
- package/telegram-plugin/gateway/auth-add-flow.ts +326 -0
- package/telegram-plugin/gateway/auth-broker-client.ts +75 -0
- package/telegram-plugin/gateway/auth-command.ts +905 -0
- package/telegram-plugin/gateway/auth-line.ts +123 -0
- package/telegram-plugin/gateway/auth-status-adapter.ts +101 -0
- package/telegram-plugin/gateway/boot-card.ts +23 -37
- package/telegram-plugin/gateway/boot-probes.ts +9 -12
- package/telegram-plugin/gateway/diff-preview-card.test.ts +192 -0
- package/telegram-plugin/gateway/diff-preview-card.ts +170 -0
- package/telegram-plugin/gateway/drive-write-approval.test.ts +312 -0
- package/telegram-plugin/gateway/drive-write-approval.ts +243 -0
- package/telegram-plugin/gateway/folder-picker-handler.test.ts +314 -0
- package/telegram-plugin/gateway/folder-picker-handler.ts +348 -0
- package/telegram-plugin/gateway/gateway.ts +1156 -938
- package/telegram-plugin/gateway/hostd-dispatch.ts +244 -0
- package/telegram-plugin/gateway/ipc-protocol.ts +83 -2
- package/telegram-plugin/gateway/ipc-server.ts +69 -0
- package/telegram-plugin/hooks/sandbox-hint-posttool.mjs +103 -12
- package/telegram-plugin/hooks/tool-label-pretool.mjs +11 -0
- package/telegram-plugin/hooks/wedge-detect-posttool.mjs +303 -0
- package/telegram-plugin/model-unavailable.ts +28 -12
- package/telegram-plugin/permission-title.ts +56 -0
- package/telegram-plugin/quota-check.ts +19 -41
- package/telegram-plugin/scripts/build.mjs +0 -1
- package/telegram-plugin/shared/bot-runtime.ts +5 -4
- package/telegram-plugin/silence-poke.ts +153 -1
- package/telegram-plugin/tests/auth-add-flow.test.ts +559 -0
- package/telegram-plugin/tests/auth-code-redact.test.ts +8 -4
- package/telegram-plugin/tests/auth-command-format2.test.ts +156 -0
- package/telegram-plugin/tests/auth-command-vernacular.test.ts +531 -0
- package/telegram-plugin/tests/auth-snapshot-format.test.ts +429 -0
- package/telegram-plugin/tests/auth-status-adapter.test.ts +129 -0
- package/telegram-plugin/tests/auto-fallback-fleet.test.ts +211 -0
- package/telegram-plugin/tests/auto-fallback.test.ts +60 -358
- package/telegram-plugin/tests/boot-probes.test.ts +27 -22
- package/telegram-plugin/tests/fleet-fallback-gate.test.ts +197 -0
- package/telegram-plugin/tests/model-unavailable.test.ts +30 -5
- package/telegram-plugin/tests/permission-title.test.ts +31 -0
- package/telegram-plugin/tests/quota-check.test.ts +5 -35
- package/telegram-plugin/tests/sandbox-hint-posttool.test.ts +212 -2
- package/telegram-plugin/tests/silence-poke.test.ts +237 -0
- package/telegram-plugin/tests/turn-flush-safety.test.ts +112 -0
- package/telegram-plugin/turn-flush-safety.ts +55 -1
- package/telegram-plugin/uat/SETUP.md +35 -1
- package/telegram-plugin/uat/runners/agent-self-sufficiency.ts +457 -0
- package/telegram-plugin/uat/runners/paraphrases.ts +231 -0
- package/telegram-plugin/uat/runners/report.ts +150 -0
- package/telegram-plugin/uat/runners/run-agent-self-sufficiency.sh +50 -0
- package/telegram-plugin/uat/runners/scorer.test.ts +196 -0
- package/telegram-plugin/uat/runners/scorer.ts +106 -0
- package/telegram-plugin/uat/runners/skill-coverage.test.ts +100 -0
- package/telegram-plugin/uat/runners/skill-coverage.ts +620 -0
- package/telegram-plugin/uat/scenarios/jtbd-interrupt-marker-dm.test.ts +7 -1
- package/telegram-plugin/uat/scenarios/jtbd-rapid-followup-dm.test.ts +7 -1
- package/telegram-plugin/auth-dashboard.ts +0 -1104
- package/telegram-plugin/auth-slot-parser.ts +0 -497
- package/telegram-plugin/auto-fallback-dispatcher.ts +0 -68
- package/telegram-plugin/dist/foreman/foreman.js +0 -31358
- package/telegram-plugin/foreman/foreman-create-flow.ts +0 -202
- package/telegram-plugin/foreman/foreman-handlers.ts +0 -493
- package/telegram-plugin/foreman/foreman.ts +0 -1165
- package/telegram-plugin/foreman/setup-flow.ts +0 -345
- package/telegram-plugin/foreman/setup-state.ts +0 -239
- package/telegram-plugin/foreman/state.ts +0 -203
- package/telegram-plugin/tests/auth-account-identity-surface.test.ts +0 -118
- package/telegram-plugin/tests/auth-dashboard-edge-cases.test.ts +0 -260
- package/telegram-plugin/tests/auth-dashboard-restart-flow.test.ts +0 -140
- package/telegram-plugin/tests/auth-dashboard-v3b.test.ts +0 -559
- package/telegram-plugin/tests/auth-dashboard.test.ts +0 -1045
- package/telegram-plugin/tests/auth-slot-commands.test.ts +0 -640
- package/telegram-plugin/tests/auto-fallback-dispatcher.e2e.test.ts +0 -183
- package/telegram-plugin/tests/boot-card-account-quota.test.ts +0 -137
- package/telegram-plugin/tests/foreman-create-flow.test.ts +0 -359
- package/telegram-plugin/tests/foreman-handlers.test.ts +0 -347
- package/telegram-plugin/tests/foreman-state.test.ts +0 -164
- package/telegram-plugin/tests/foreman-write-ops.test.ts +0 -214
- package/telegram-plugin/tests/setup-flow.test.ts +0 -510
- package/telegram-plugin/tests/setup-state.test.ts +0 -146
|
@@ -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.
|
|
3
|
+
"version": "0.11.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,14 +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/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/
|
|
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-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/
|
|
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 && bash scripts/check-bot-api-wrapping.sh",
|
|
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",
|
|
30
31
|
"lint:bot-api-wrapping": "bash scripts/check-bot-api-wrapping.sh",
|
|
32
|
+
"lint:bun-test-imports": "node scripts/check-bun-test-imports.mjs",
|
|
31
33
|
"prepublishOnly": "npm run build && npm run lint && npm test"
|
|
32
34
|
},
|
|
33
35
|
"dependencies": {
|
|
@@ -149,10 +149,10 @@ export PATH="$HOME/.bun/bin:$PATH"
|
|
|
149
149
|
# /state/agent bind mount (HOME=/state/agent/home).
|
|
150
150
|
export PATH="$HOME/.local/bin:$HOME/bin:$HOME/.npm-global/bin:$PATH"
|
|
151
151
|
export CLAUDE_CONFIG_DIR="{{agentDir}}/.claude"
|
|
152
|
+
# CLAUDE_CODE_OAUTH_TOKEN injection was removed with RFC H (auth-broker).
|
|
153
|
+
# Claude reads .credentials.json directly; the broker is the sole writer
|
|
154
|
+
# of that file and updates it before claude's own refresh window opens.
|
|
152
155
|
unset CLAUDE_CODE_OAUTH_TOKEN
|
|
153
|
-
if [ -f "$CLAUDE_CONFIG_DIR/.oauth-token" ]; then
|
|
154
|
-
export CLAUDE_CODE_OAUTH_TOKEN="$(tr -d '\r\n' < "$CLAUDE_CONFIG_DIR/.oauth-token")"
|
|
155
|
-
fi
|
|
156
156
|
export TELEGRAM_STATE_DIR="{{agentDir}}/telegram"
|
|
157
157
|
# SWITCHROOM_AGENT_NAME is the canonical "which agent am I" identifier the
|
|
158
158
|
# telegram-plugin reads to detect self-restart commands. We can't rely on
|