Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions packages/opencode/src/session/system.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -58,6 +58,12 @@ export const layer = Layer.effect(
` Platform: ${process.platform}`,
` Today's date: ${new Date().toDateString()}`,
`</env>`,
``,
`## System Safety (Critical)`,
``,
`- **NEVER** run commands that kill all Node.js processes (e.g., \`taskkill /F /IM node.exe\`, \`killall node\`, \`pkill node\`, \`Get-Process node | Stop-Process\`, etc.).`,
`- OpenCode is built on Node.js (\`node.exe\`). Killing all Node processes will immediately crash the AI assistant and terminate the current session.`,
`- If you need to stop a specific process, target it by PID or use process-manager commands scoped to the project (e.g., \`npm stop\`, \`pm2 stop <name>\`).`,
].join("\n"),
]
}),
Expand Down
17 changes: 17 additions & 0 deletions packages/opencode/src/tool/shell.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -28,6 +28,18 @@ export { Parameters } from "./shell/prompt"
const MAX_METADATA_LENGTH = 30_000
const DEFAULT_TIMEOUT = Flag.OPENCODE_EXPERIMENTAL_BASH_DEFAULT_TIMEOUT_MS || 2 * 60 * 1000
const CWD = new Set(["cd", "chdir", "popd", "pushd", "push-location", "set-location"])

const DANGEROUS_COMMAND_PATTERNS = [
/taskkill\s+.*\/?[Ff]\s+.*\/?[Ii][Mm]\s+node\.?exe/i,
/taskkill\s+.*\/?[Ii][Mm]\s+node\.?exe/i,
/killall\s+node/i,
/pkill\s+node/i,
/Get-Process\s+.*node\s*\|\s*Stop-Process/i,
]

function isDangerousCommand(command: string): boolean {
return DANGEROUS_COMMAND_PATTERNS.some((pattern) => pattern.test(command))
}
const FILES = new Set([
...CWD,
"rm",
Expand DownExpand Up@@ -601,6 +613,11 @@ export const ShellTool = Tool.define(
throw new Error(`Invalid timeout value: ${params.timeout}. Timeout must be a positive number.`)
}
const timeout = params.timeout ?? DEFAULT_TIMEOUT
if (isDangerousCommand(params.command)) {
throw new Error(
`Command blocked for system safety: "${params.command}". This command would kill all Node.js processes, which crashes OpenCode because it is built on Node.js (node.exe). If you need to stop a specific process, target it by PID or use project-scoped commands like "npm stop" or "pm2 stop <name>".`,
)
}
const ps = Shell.ps(shell)
yield* Effect.scoped(
Effect.gen(function* () {
Expand Down
6 changes: 6 additions & 0 deletions packages/opencode/src/tool/shell/shell.txt
Original file line numberDiff line numberDiff line change
Expand Up@@ -8,6 +8,12 @@ Use `${tmp}` for temporary work outside the workspace. This directory has alread

IMPORTANT: This tool is for terminal operations like git, npm, docker, etc. DO NOT use it for file operations (reading, writing, editing, searching, finding files) - use the specialized tools for this instead.

## System Safety (Critical)

- **NEVER** run commands that kill all Node.js processes (e.g., `taskkill /F /IM node.exe`, `killall node`, `pkill node`, `Get-Process node | Stop-Process`, etc.).
- OpenCode is built on Node.js (`node.exe`). Killing all Node processes will immediately crash the AI assistant and terminate the current session.
- If you need to stop a specific process, target it by PID or use process-manager commands scoped to the project (e.g., `npm stop`, `pm2 stop <name>`).

${commandSection}

# Committing changes with git
Expand Down
Loading