From b3050cbffdd8d6948f8ece35e778bd015320366b Mon Sep 17 00:00:00 2001 From: marius-kilocode Date: Mon, 22 Jun 2026 17:06:51 +0200 Subject: [PATCH] feat(cli): add macOS file-level sandbox for agent tools Add an OS-level sandbox that confines agent writes to the project and Kilo state directories. Currently macOS-only (via sandbox-exec/seatbelt), with Linux, Windows, network isolation, and worktree isolation deferred to follow-up issues (#11538, #11540, #11542, #11544, #11546, #11547). Two enforcement layers: - Bash tool: kernel-level seatbelt confinement via sandbox-exec - File tools (write/edit/apply_patch): TS-level AppFileSystem layer wrapper Both share the same configurable scope, which respects existing permission config (external_directory allows, project sandboxes). Opt-in via experimental.sandbox config toggle or the lock button in the prompt input. --- .../src/components/chat/PromptInput.tsx | 31 +++- .../components/settings/ExperimentalTab.tsx | 15 +- .../kilo-vscode/webview-ui/src/i18n/en.ts | 7 + .../webview-ui/src/styles/prompt-input.css | 24 +++ .../webview-ui/src/types/messages/config.ts | 1 + packages/opencode/src/config/config.ts | 5 + packages/opencode/src/effect/app-runtime.ts | 7 +- .../opencode/src/kilocode/sandbox/fs-layer.ts | 93 ++++++++++++ .../opencode/src/kilocode/sandbox/guard.ts | 78 ++++++++++ .../opencode/src/kilocode/sandbox/index.ts | 6 + .../opencode/src/kilocode/sandbox/scope.ts | 81 ++++++++++ .../src/kilocode/sandbox/seatbelt-base.ts | 114 ++++++++++++++ .../opencode/src/kilocode/sandbox/seatbelt.ts | 84 +++++++++++ .../opencode/src/kilocode/sandbox/spawn.ts | 17 +++ packages/opencode/src/tool/shell.ts | 49 +++++- .../test/kilocode/sandbox/seatbelt.test.ts | 139 ++++++++++++++++++ packages/sdk/js/src/v2/gen/types.gen.ts | 1 + packages/ui/src/components/icon.tsx | 1 + 18 files changed, 749 insertions(+), 4 deletions(-) create mode 100644 packages/opencode/src/kilocode/sandbox/fs-layer.ts create mode 100644 packages/opencode/src/kilocode/sandbox/guard.ts create mode 100644 packages/opencode/src/kilocode/sandbox/index.ts create mode 100644 packages/opencode/src/kilocode/sandbox/scope.ts create mode 100644 packages/opencode/src/kilocode/sandbox/seatbelt-base.ts create mode 100644 packages/opencode/src/kilocode/sandbox/seatbelt.ts create mode 100644 packages/opencode/src/kilocode/sandbox/spawn.ts create mode 100644 packages/opencode/test/kilocode/sandbox/seatbelt.test.ts diff --git a/packages/kilo-vscode/webview-ui/src/components/chat/PromptInput.tsx b/packages/kilo-vscode/webview-ui/src/components/chat/PromptInput.tsx index 71b87c08ce..f9585b3d8a 100644 --- a/packages/kilo-vscode/webview-ui/src/components/chat/PromptInput.tsx +++ b/packages/kilo-vscode/webview-ui/src/components/chat/PromptInput.tsx @@ -78,7 +78,7 @@ export const PromptInput: Component = (props) => { const session = useSession() const server = useServer() const indexing = useIndexing() - const { config, features } = useConfig() + const { config, features, updateConfig, saveConfig } = useConfig() const provider = useProvider() const language = useLanguage() const vscode = useVSCode() @@ -142,6 +142,7 @@ export const PromptInput: Component = (props) => { const [reviewComments, setReviewComments] = createSignal([]) const [enhancing, setEnhancing] = createSignal(false) const [autoApprove, setAutoApprove] = createSignal(false) + const sandbox = () => config().experimental?.sandbox ?? false let enhanceCounter = 0 let preEnhanceText: string | null = null @@ -1064,6 +1065,34 @@ export const PromptInput: Component = (props) => { + + +