switchroom 0.14.7 → 0.14.9

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.
@@ -28477,6 +28477,30 @@ var init_doctor_status = __esm(() => {
28477
28477
  init_source();
28478
28478
  });
28479
28479
 
28480
+ // src/config/thinking-effort-risk.ts
28481
+ function isAdaptiveThinkingOpus(model) {
28482
+ if (!model)
28483
+ return false;
28484
+ const m = model.trim().toLowerCase();
28485
+ return m === "opus" || m.startsWith("claude-opus-4");
28486
+ }
28487
+ function assessThinkingEffortRisk(model, effort) {
28488
+ if (!effort)
28489
+ return { risky: false };
28490
+ if (!RISKY_EFFORTS.has(effort.trim().toLowerCase()))
28491
+ return { risky: false };
28492
+ if (!isAdaptiveThinkingOpus(model))
28493
+ return { risky: false };
28494
+ return {
28495
+ risky: true,
28496
+ reason: `thinking_effort '${effort}' on adaptive-thinking model '${model}' can trigger ` + `'400 thinking/redacted_thinking blocks cannot be modified' errors when work runs ` + `through concurrent sub-agents (issue #1978). Pin 'thinking_effort: low' (the safe ` + `floor) unless the bundled claude CLI includes the concurrent-agent thinking-block ` + `merge fix.`
28497
+ };
28498
+ }
28499
+ var RISKY_EFFORTS;
28500
+ var init_thinking_effort_risk = __esm(() => {
28501
+ RISKY_EFFORTS = new Set(["medium", "high", "xhigh", "max"]);
28502
+ });
28503
+
28480
28504
  // src/manifest.ts
28481
28505
  import {
28482
28506
  existsSync as existsSync48,
@@ -31399,6 +31423,19 @@ function checkConfig(config, configPath) {
31399
31423
  detail: foundSubagents.length > 0 ? foundSubagents.join(", ") : "no default subagents \u2014 main agent handles all work inline",
31400
31424
  fix: foundSubagents.length > 0 ? undefined : "Add defaults.subagents to switchroom.yaml to enable Sonnet/Haiku delegation. See docs/sub-agents.md for the worker/researcher/reviewer pattern."
31401
31425
  });
31426
+ const effortRisks = [];
31427
+ for (const [name, agentConfig] of Object.entries(config.agents)) {
31428
+ const resolved = resolveAgentConfig(config.defaults, config.profiles, agentConfig);
31429
+ if (assessThinkingEffortRisk(resolved.model, resolved.thinking_effort).risky) {
31430
+ effortRisks.push(name);
31431
+ }
31432
+ }
31433
+ results.push({
31434
+ name: "thinking_effort \u00d7 adaptive model",
31435
+ status: effortRisks.length > 0 ? "warn" : "ok",
31436
+ detail: effortRisks.length > 0 ? `${effortRisks.length} agent(s) on Opus 4.x with thinking_effort > low: ${effortRisks.join(", ")}` : "no risky model/effort combos",
31437
+ fix: effortRisks.length > 0 ? "Pin `thinking_effort: low` for Opus 4.x agents \u2014 medium+ can 400 on 'thinking blocks cannot be modified' with concurrent sub-agents (issue #1978). Removing the field is NOT a fix (Opus 4.8 defaults effort=high when unset)." : undefined
31438
+ });
31402
31439
  return results;
31403
31440
  }
31404
31441
  function checkUserDeclaredMcps(name, agentConfig, config, renderedMcpServers) {
@@ -32833,6 +32870,7 @@ var init_doctor = __esm(() => {
32833
32870
  init_vault();
32834
32871
  init_loader();
32835
32872
  init_merge();
32873
+ init_thinking_effort_risk();
32836
32874
  init_paths();
32837
32875
  init_helpers();
32838
32876
  init_lifecycle();
@@ -49366,8 +49404,8 @@ var {
49366
49404
  } = import__.default;
49367
49405
 
49368
49406
  // src/build-info.ts
49369
- var VERSION = "0.14.7";
49370
- var COMMIT_SHA = "0f782e65";
49407
+ var VERSION = "0.14.9";
49408
+ var COMMIT_SHA = "fd8ed8ed";
49371
49409
 
49372
49410
  // src/cli/agent.ts
49373
49411
  init_source();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "switchroom",
3
- "version": "0.14.7",
3
+ "version": "0.14.9",
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": {
@@ -183,6 +183,29 @@ export PATH="$HOME/.bun/bin:$PATH"
183
183
  # all land in these paths; survival across container restart is via the
184
184
  # /state/agent bind mount (HOME=/state/agent/home).
185
185
  export PATH="$HOME/.local/bin:$HOME/bin:$HOME/.npm-global/bin:$PATH"
186
+ # claude is delivered ONLY by the agent image (/usr/local, root-owned,
187
+ # version-pinned, rebuilt deliberately via `switchroom update`). The
188
+ # persistent-HOME dirs above precede /usr/local/bin on PATH so agents
189
+ # can install their own npm/pip tools — but that same precedence means
190
+ # a stray `claude` in the writable, state-persisted npm prefix would
191
+ # silently SHADOW the image's, surviving every restart and drifting the
192
+ # fleet off the tested binary (this bit test-harness with a months-old
193
+ # self-installed 2.1.139). DISABLE_AUTOUPDATER=1 stops claude's own
194
+ # self-update, but can't undo a pre-existing or manual drop. So prune
195
+ # any user-local claude at boot — narrowly, by name, leaving every
196
+ # other user-installed package intact — guaranteeing `claude` always
197
+ # resolves to the image binary. Idempotent; no-op when clean.
198
+ for _stray_claude in \
199
+ "$HOME/.npm-global/bin/claude" \
200
+ "$HOME/.local/bin/claude" \
201
+ "$HOME/bin/claude"; do
202
+ if [ -e "$_stray_claude" ] || [ -L "$_stray_claude" ]; then
203
+ echo "start.sh: pruning user-local claude shadow at $_stray_claude (image binary is authoritative)" >&2
204
+ rm -f "$_stray_claude"
205
+ fi
206
+ done
207
+ rm -rf "$HOME/.npm-global/lib/node_modules/@anthropic-ai/claude-code" 2>/dev/null || true
208
+ unset _stray_claude
186
209
  export CLAUDE_CONFIG_DIR="{{agentDir}}/.claude"
187
210
  # CLAUDE_CODE_OAUTH_TOKEN injection was removed with RFC H (auth-broker).
188
211
  # Claude reads .credentials.json directly; the broker is the sole writer