2026-08-09 11:35:42 -07:00
import type { Project } from "../../../../lib/types" ;
import Toggle from "../../../ui/Toggle" ;
import { ConfigGroup , SwitchRow } from "../../../ui/Field" ;
import PermissionModeControl , { permissionModePatch } from "../../PermissionModeControl" ;
import ClaudeInstructionsEditor from "../../ClaudeInstructionsEditor" ;
import ClaudeCodeSettingsEditor from "../../ClaudeCodeSettingsEditor" ;
2026-08-23 08:31:39 -07:00
import AuthBridgeRow from "./AuthBridgeRow" ;
2026-08-09 11:35:42 -07:00
interface Props {
project : Project ;
save : ( patch : Partial < Project >) => Promise < boolean >;
disabled : boolean ;
disabledReason? : string ;
}
export default function RuntimeSection ({
project ,
save ,
disabled ,
disabledReason ,
} : Props ) {
return (
<>
< ConfigGroup
title = "Runtime"
description = "How much the sandbox lets Claude do, and what contains it."
>
< div className = "pb-2 border-b border-[var(--border-color)]" >
< PermissionModeControl
project = { project }
onChange = {( mode ) => save ( permissionModePatch ( mode ))}
/>
</ div >
< SwitchRow
label = "Sandbox mode"
hint = "Claude Code's bash sandbox (bubblewrap filesystem and network isolation). Triple-C is the source of truth: toggling this overrides any manual /sandbox configuration in the container's settings.json on next start."
control = {
< Toggle
label = "Sandbox mode"
checked = { project . sandbox_mode_enabled }
disabled = { disabled }
onChange = {( v ) => save ({ sandbox_mode_enabled : v })}
/>
}
/>
< SwitchRow
label = "Allow container spawning"
hint = "Mounts the Docker socket so Claude can build and run Docker containers from inside the sandbox."
control = {
< Toggle
label = "Allow container spawning"
checked = { project . allow_docker_access }
disabled = { disabled }
onChange = {( v ) => save ({ allow_docker_access : v })}
/>
}
/>
2026-08-14 07:52:39 -07:00
< SwitchRow
label = "VPN support"
2026-08-14 08:15:05 -07:00
hint = "Grants NET_ADMIN and the /dev/net/tun device so a VPN client (PIA, WireGuard, OpenVPN) can build a tunnel inside the container. Without it a client installs and runs but its connection hangs until it times out. Anything in the container can then reconfigure the container's own network stack; the host's is untouched. Changing this recreates the container on its next start — the home and .claude volumes are preserved."
2026-08-14 07:52:39 -07:00
control = {
< Toggle
label = "VPN support"
checked = { project . vpn_support_enabled }
disabled = { disabled }
onChange = {( v ) => save ({ vpn_support_enabled : v })}
/>
}
/>
2026-08-23 08:31:39 -07:00
{ /* Not gated on `disabled`: the bridge is host-side and has its own
command, so it can be switched on while a login is hanging — which
is the only moment anyone reaches for it. It owns its state rather
than going through `save`. */ }
< AuthBridgeRow project = { project } />
2026-08-09 11:35:42 -07:00
< SwitchRow
label = "Mission Control"
hint = "A web dashboard for monitoring and managing Claude sessions remotely."
control = {
< Toggle
label = "Mission Control"
checked = { project . mission_control_enabled }
disabled = { disabled }
onChange = {( v ) => save ({ mission_control_enabled : v })}
/>
}
/>
{ disabled && disabledReason && (
< p className = "text-xs text-[var(--text-disabled)]" >{ disabledReason }</ p >
)}
</ ConfigGroup >
< ConfigGroup
title = "Claude instructions"
description = "Written to ~/.claude/CLAUDE.md inside this project's container."
>
< ClaudeInstructionsEditor
instructions = { project . claude_instructions ?? "" }
disabled = { disabled }
disabledReason = { disabledReason }
onSave = {( value ) => save ({ claude_instructions : value || null })}
/>
</ ConfigGroup >
< ConfigGroup
title = "Claude Code settings"
2026-08-23 16:45:20 -07:00
description = {
"Per-project CLI behaviour. Anything left on Global follows Settings; " +
2026-08-23 18:45:11 -07:00
"Off overrides a global On. Changing any of these recreates the container, " +
"which commits a new image layer — so flipping switches repeatedly costs disk. " +
"Turning TUI mode, Effort level, Focus mode or Session recap back to Global " +
"also needs the base image updated first: those four are cleared by removing a " +
"key, and an older image's startup script ignores the instruction to remove it. " +
"Update the base image from Overview. TUI mode, Effort level and Focus mode " +
"visibly refuse to switch off until you do; Session recap just stays off silently."
2026-08-23 16:45:20 -07:00
}
2026-08-09 11:35:42 -07:00
>
< ClaudeCodeSettingsEditor
2026-08-23 09:05:39 -07:00
scope = "project"
2026-08-09 11:35:42 -07:00
settings = { project . claude_code_settings }
disabled = { disabled }
disabledReason = { disabledReason }
onSave = {( settings ) => save ({ claude_code_settings : settings })}
/>
</ ConfigGroup >
</>
);
}