Просмотр исходного кода

fix(opencode): agent create generates permissions field with deny ins… (#24482)

Co-authored-by: Aiden Cline <63023139+rekram1-node@users.noreply.github.com>
Co-authored-by: Aiden Cline <aidenpcline@gmail.com>
21pounder 4 месяцев назад
Родитель
Сommit
0efc6163f1

+ 27 - 23
packages/opencode/src/cli/cmd/agent.ts

@@ -15,7 +15,10 @@ import type { Argv } from "yargs"
 
 type AgentMode = "all" | "primary" | "subagent"
 
-const AVAILABLE_TOOLS = ["bash", "read", "write", "edit", "glob", "grep", "webfetch", "task", "todowrite"]
+// Permission keys (not raw tool names). Multiple tools can map to a single
+// permission — e.g. write/edit/apply_patch all gate on `edit` — so we configure
+// agents at the permission level to match how the runtime actually enforces it.
+const AVAILABLE_PERMISSIONS = ["bash", "read", "edit", "glob", "grep", "webfetch", "task", "todowrite", "websearch", "codesearch", "lsp", "skill"]
 
 const AgentCreateCommand = cmd({
   command: "create",
@@ -35,9 +38,10 @@ const AgentCreateCommand = cmd({
         describe: "agent mode",
         choices: ["all", "primary", "subagent"] as const,
       })
-      .option("tools", {
+      .option("permissions", {
         type: "string",
-        describe: `comma-separated list of tools to enable (default: all). Available: "${AVAILABLE_TOOLS.join(", ")}"`,
+        alias: ["tools"],
+        describe: `comma-separated list of permissions to allow (default: all). Available: "${AVAILABLE_PERMISSIONS.join(", ")}"`,
       })
       .option("model", {
         type: "string",
@@ -51,9 +55,9 @@ const AgentCreateCommand = cmd({
         const cliPath = args.path
         const cliDescription = args.description
         const cliMode = args.mode as AgentMode | undefined
-        const cliTools = args.tools
+        const perms = args.permissions
 
-        const isFullyNonInteractive = cliPath && cliDescription && cliMode && cliTools !== undefined
+        const isFullyNonInteractive = cliPath && cliDescription && cliMode && perms !== undefined
 
         if (!isFullyNonInteractive) {
           UI.empty()
@@ -120,21 +124,21 @@ const AgentCreateCommand = cmd({
         })
         spinner.stop(`Agent ${generated.identifier} generated`)
 
-        // Select tools
-        let selectedTools: string[]
-        if (cliTools !== undefined) {
-          selectedTools = cliTools ? cliTools.split(",").map((t) => t.trim()) : AVAILABLE_TOOLS
+        // Select permissions to allow
+        let selected: string[]
+        if (perms !== undefined) {
+          selected = perms ? perms.split(",").map((t) => t.trim()) : AVAILABLE_PERMISSIONS
         } else {
           const result = await prompts.multiselect({
-            message: "Select tools to enable (Space to toggle)",
-            options: AVAILABLE_TOOLS.map((tool) => ({
-              label: tool,
-              value: tool,
+            message: "Select permissions to allow (Space to toggle)",
+            options: AVAILABLE_PERMISSIONS.map((permission) => ({
+              label: permission,
+              value: permission,
             })),
-            initialValues: AVAILABLE_TOOLS,
+            initialValues: AVAILABLE_PERMISSIONS,
           })
           if (prompts.isCancel(result)) throw new UI.CancelledError()
-          selectedTools = result
+          selected = result
         }
 
         // Get mode
@@ -167,11 +171,11 @@ const AgentCreateCommand = cmd({
           mode = modeResult
         }
 
-        // Build tools config
-        const tools: Record<string, boolean> = {}
-        for (const tool of AVAILABLE_TOOLS) {
-          if (!selectedTools.includes(tool)) {
-            tools[tool] = false
+        // Build permissions config — deny anything not explicitly selected.
+        const permissions: Record<string, "deny"> = {}
+        for (const permission of AVAILABLE_PERMISSIONS) {
+          if (!selected.includes(permission)) {
+            permissions[permission] = "deny"
           }
         }
 
@@ -179,13 +183,13 @@ const AgentCreateCommand = cmd({
         const frontmatter: {
           description: string
           mode: AgentMode
-          tools?: Record<string, boolean>
+          permission?: Record<string, "deny">
         } = {
           description: generated.whenToUse,
           mode,
         }
-        if (Object.keys(tools).length > 0) {
-          frontmatter.tools = tools
+        if (Object.keys(permissions).length > 0) {
+          frontmatter.permission = permissions
         }
 
         // Write file

+ 44 - 22
packages/web/src/content/docs/agents.mdx

@@ -149,19 +149,17 @@ Configure agents in your `opencode.json` config file:
       "mode": "primary",
       "model": "anthropic/claude-sonnet-4-20250514",
       "prompt": "{file:./prompts/build.txt}",
-      "tools": {
-        "write": true,
-        "edit": true,
-        "bash": true
+      "permission": {
+        "edit": "allow",
+        "bash": "allow"
       }
     },
     "plan": {
       "mode": "primary",
       "model": "anthropic/claude-haiku-4-20250514",
-      "tools": {
-        "write": false,
-        "edit": false,
-        "bash": false
+      "permission": {
+        "edit": "deny",
+        "bash": "deny"
       }
     },
     "code-reviewer": {
@@ -169,9 +167,8 @@ Configure agents in your `opencode.json` config file:
       "mode": "subagent",
       "model": "anthropic/claude-sonnet-4-20250514",
       "prompt": "You are a code reviewer. Focus on security, performance, and maintainability.",
-      "tools": {
-        "write": false,
-        "edit": false
+      "permission": {
+        "edit": "deny"
       }
     }
   }
@@ -193,10 +190,9 @@ description: Reviews code for quality and best practices
 mode: subagent
 model: anthropic/claude-sonnet-4-20250514
 temperature: 0.1
-tools:
-  write: false
-  edit: false
-  bash: false
+permission:
+  edit: deny
+  bash: deny
 ---
 
 You are in code review mode. Focus on:
@@ -417,12 +413,39 @@ You can also use wildcards in legacy `tools` entries to control multiple tools a
 
 ### Permissions
 
-You can configure permissions to manage what actions an agent can take. Currently, the permissions for the `edit`, `bash`, and `webfetch` tools can be configured to:
+You can configure permissions to manage what actions an agent can take. Each permission key can be set to:
 
 - `"ask"` — Prompt for approval before running the tool
 - `"allow"` — Allow all operations without approval
 - `"deny"` — Disable the tool
 
+The available permission keys are:
+
+| Key                  | Tools it gates                                                                |
+| -------------------- | ----------------------------------------------------------------------------- |
+| `read`               | `read`                                                                        |
+| `edit`               | `write`, `edit`, `apply_patch`                                                |
+| `glob`               | `glob`                                                                        |
+| `grep`               | `grep`                                                                        |
+| `list`               | `list`                                                                        |
+| `bash`               | `bash`                                                                        |
+| `task`               | `task`                                                                        |
+| `external_directory` | Any tool that reads or writes files outside the project worktree              |
+| `todowrite`          | `todowrite`, `todoread`                                                       |
+| `webfetch`           | `webfetch`                                                                    |
+| `websearch`          | `websearch`                                                                   |
+| `codesearch`         | `codesearch`                                                                  |
+| `lsp`                | `lsp`                                                                         |
+| `skill`              | `skill`                                                                       |
+| `question`           | `question`                                                                    |
+| `doom_loop`          | Recovery prompts when an agent appears stuck                                  |
+
+`read`, `edit`, `glob`, `grep`, `list`, `bash`, `task`, `external_directory`, `lsp`, and `skill` accept either a shorthand action (`"allow" | "ask" | "deny"`) or an object of glob/pattern → action for fine-grained control. The remaining keys accept the shorthand action only.
+
+:::note
+Permission keys are matched as wildcard patterns against the underlying tool name, so the same syntax works for built-ins, custom tools, and MCP tools — for example `"mymcp_*": "deny"` denies every tool from an MCP server, and `"mymcp_search": "ask"` targets a single one.
+:::
+
 ```json title="opencode.json"
 {
   "$schema": "https://opencode.ai/config.json",
@@ -680,7 +703,7 @@ This interactive command will:
 1. Ask where to save the agent; global or project-specific.
 2. Description of what the agent should do.
 3. Generate an appropriate system prompt and identifier.
-4. Let you select which tools the agent can access.
+4. Let you select which permissions the agent should be allowed (anything you don't select is denied).
 5. Finally, create a markdown file with the agent configuration.
 
 ---
@@ -713,8 +736,8 @@ Do you have an agent you'd like to share? [Submit a PR](https://github.com/anoma
 ---
 description: Writes and maintains project documentation
 mode: subagent
-tools:
-  bash: false
+permission:
+  bash: deny
 ---
 
 You are a technical writer. Create clear, comprehensive documentation.
@@ -735,9 +758,8 @@ Focus on:
 ---
 description: Performs security audits and identifies vulnerabilities
 mode: subagent
-tools:
-  write: false
-  edit: false
+permission:
+  edit: deny
 ---
 
 You are a security expert. Focus on identifying potential security issues.

+ 13 - 1
packages/web/src/content/docs/cli.mdx

@@ -93,7 +93,19 @@ Create a new agent with custom configuration.
 opencode agent create
 ```
 
-This command will guide you through creating a new agent with a custom system prompt and tool configuration.
+This command will guide you through creating a new agent with a custom system prompt and permission configuration. Anything you don't allow is denied in the generated agent's frontmatter.
+
+#### Flags
+
+| Flag             | Description                                                                                                |
+| ---------------- | ---------------------------------------------------------------------------------------------------------- |
+| `--path`         | Directory to write the agent file to (defaults to global or `.opencode/agent` based on the prompt)         |
+| `--description`  | What the agent should do                                                                                   |
+| `--mode`         | Agent mode: `all`, `primary`, or `subagent`                                                                |
+| `--permissions`  | Comma-separated list of permissions to allow (default: all). Available: `bash`, `read`, `edit`, `glob`, `grep`, `webfetch`, `task`, `todowrite`, `websearch`, `codesearch`, `lsp`, `skill`. Anything omitted is denied. Alias: `--tools` |
+| `--model`, `-m`  | Model to use, in `provider/model` format                                                                   |
+
+Passing all of `--path`, `--description`, `--mode`, and `--permissions` runs the command non-interactively.
 
 ---