Skip to content

feat(widget): add Sandbox Status widget#481

Open
CorticalCode wants to merge 1 commit into
sirmalloc:mainfrom
CorticalCode:feat/sandbox-status
Open

feat(widget): add Sandbox Status widget#481
CorticalCode wants to merge 1 commit into
sirmalloc:mainfrom
CorticalCode:feat/sandbox-status

Conversation

@CorticalCode

@CorticalCode CorticalCode commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

What

Adds a Sandbox Status widget that shows whether Claude Code's bash sandbox mode is currently enabled. Implements the request in #104.

Why it reads settings (not the status JSON)

Sandbox state isn't in the status-line JSON, and there's no environment variable for it — it's a runtime property of the Bash tool. The one durable source is sandbox.enabled in Claude Code's settings, and /sandbox persists its toggle to <cwd>/.claude/settings.local.json. So reading the effective setting on each refresh tracks the live state, not just a static default.

The widget reads sandbox.enabled across the same layered config the Voice widget already uses (project-local → project → user-local → user, honoring CLAUDE_CONFIG_DIR) — it deliberately mirrors getVoiceConfig.

Display & config

  • Formats (cycle f): SB: ●/○ (default), SB: ON/OFF, Sandbox: ON/OFF, and bare ●/○. Optional Nerd Font lock/unlock glyphs (n).
  • Standard per-widget color; raw value on/off for composition.

Defaults (calling these out so they're easy to change)

  • Default format is the compact SB: ●/○.
  • Default color is green.
  • When sandbox is off it renders the off state rather than hiding; it returns null (hides) only if Claude Code was never initialized (no settings file anywhere) — matching the Voice widget.

Implementation notes

  • getSandboxConfig lives in claude-settings.ts next to getVoiceConfig; the widget (src/widgets/SandboxStatus.ts) mirrors VoiceStatus.ts.
  • I renamed the private path helper getVoiceConfigCandidatePathsByPrioritygetLayeredSettingsCandidatePathsByPriority so voice and sandbox share it. getVoiceConfig's behavior is unchanged (its existing tests still pass). The per-layer read (tryReadSandboxLayer) is kept parallel to the voice one rather than fully generalized.

Tests

Widget tests (every format, nerd font, raw, preview, null-hide, cwd resolution) and getSandboxConfig layering tests (precedence, malformed/absent handling, CLAUDE_CONFIG_DIR). Full suite green, lint clean.

Possible follow-up (not in this PR)

Letting the color encode state — green when on, red when off, chosen through the existing picker — would be a general "per-state / conditional color" capability that belongs in the shared color system rather than this one widget, so it's deliberately out of scope here.

Shows whether Claude Code's bash sandbox mode is enabled, read from the effective sandbox.enabled setting across the layered Claude config (project-local -> project -> user-local -> user). Because /sandbox persists its toggle to .claude/settings.local.json, the widget reflects runtime toggles on each status refresh, not just the configured default.

Display modes (cycle 'f'): glyph 'SB: dot' (default), text 'SB: ON/OFF', word 'Sandbox: ON/OFF', bare glyph-only; optional Nerd Font lock glyphs ('n'). Standard per-widget color picker; raw value on/off for composition.

Reuses the layered-settings candidate-path reader shared with getVoiceConfig.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant