mirror of
https://github.com/anomalyco/opencode.git
synced 2026-07-17 12:56:41 +02:00
Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a0d2e53bde | |||
| 851e900982 | |||
| 3aa6eeb426 | |||
| b6ee8e92f9 | |||
| 44211e1526 | |||
| 12f84f198f | |||
| e6db1cf29d | |||
| f07f04d969 | |||
| 33d613a470 | |||
| 0bbd7ea17b | |||
| 87f3166437 | |||
| 7665bd9439 | |||
| 30e10127f2 | |||
| 5e66fc2318 | |||
| c1c99c7e0f | |||
| 04e3e83db3 |
@@ -11,7 +11,8 @@
|
||||
| 2025-07-05 | 32,524 (+1,916) | 58,371 (+3,613) | 90,895 (+5,529) |
|
||||
| 2025-07-06 | 33,766 (+1,242) | 59,694 (+1,323) | 93,460 (+2,565) |
|
||||
| 2025-07-08 | 38,052 (+4,286) | 64,468 (+4,774) | 102,520 (+9,060) |
|
||||
| 2025-07-10 | 43,796 (+5,744) | 71,402 (+6,934) | 115,198 (+12,678) |
|
||||
| 2025-07-09 | 40,924 (+2,872) | 67,935 (+3,467) | 108,859 (+6,339) |
|
||||
| 2025-07-10 | 43,796 (+2,872) | 71,402 (+3,467) | 115,198 (+6,339) |
|
||||
| 2025-07-11 | 46,982 (+3,186) | 77,462 (+6,060) | 124,444 (+9,246) |
|
||||
| 2025-07-12 | 49,302 (+2,320) | 82,177 (+4,715) | 131,479 (+7,035) |
|
||||
| 2025-07-13 | 50,803 (+1,501) | 86,394 (+4,217) | 137,197 (+5,718) |
|
||||
|
||||
@@ -123,7 +123,7 @@
|
||||
"catalog": {
|
||||
"@tsconfig/node22": "22.0.2",
|
||||
"@types/node": "22.13.9",
|
||||
"ai": "5.0.0-beta.33",
|
||||
"ai": "5.0.0-beta.34",
|
||||
"hono": "4.7.10",
|
||||
"remeda": "2.26.0",
|
||||
"typescript": "5.8.2",
|
||||
@@ -144,11 +144,11 @@
|
||||
|
||||
"@ai-sdk/anthropic": ["@ai-sdk/anthropic@1.2.12", "", { "dependencies": { "@ai-sdk/provider": "1.1.3", "@ai-sdk/provider-utils": "2.2.8" }, "peerDependencies": { "zod": "^3.0.0" } }, "sha512-YSzjlko7JvuiyQFmI9RN1tNZdEiZxc+6xld/0tq/VkJaHpEzGAb1yiNxxvmYVcjvfu/PcvCxAAYXmTYQQ63IHQ=="],
|
||||
|
||||
"@ai-sdk/gateway": ["@ai-sdk/gateway@1.0.0-beta.18", "", { "dependencies": { "@ai-sdk/provider": "2.0.0-beta.2", "@ai-sdk/provider-utils": "3.0.0-beta.9" }, "peerDependencies": { "zod": "^3.25.76 || ^4" } }, "sha512-1K5L7mY04ZwpngkDPLaiBiCivVj1h7gDiCZjAIgXtVp0S2zQ+1efnM/K/o2Pig6rUbt559rDLLalwZUgvn0vig=="],
|
||||
"@ai-sdk/gateway": ["@ai-sdk/gateway@1.0.0-beta.19", "", { "dependencies": { "@ai-sdk/provider": "2.0.0-beta.2", "@ai-sdk/provider-utils": "3.0.0-beta.10" }, "peerDependencies": { "zod": "^3.25.76 || ^4" } }, "sha512-felWPMuECZRGx8xnmvH5dW3jywKTkGnw/tXN8szphGzEDr/BfxywuXijfPBG2WBUS6frPXsvSLDRdCm5W38PXA=="],
|
||||
|
||||
"@ai-sdk/provider": ["@ai-sdk/provider@2.0.0-beta.2", "", { "dependencies": { "json-schema": "^0.4.0" } }, "sha512-vqhtZA7R24q1XnmfmIb1fZSmHMIaJH1BVQ+0kFnNJgqWsc+V8i+yfetZ37gUc4fXATFmBuS/6O7+RPoHsZ2Fqg=="],
|
||||
|
||||
"@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@3.0.0-beta.9", "", { "dependencies": { "@ai-sdk/provider": "2.0.0-beta.2", "@standard-schema/spec": "^1.0.0", "eventsource-parser": "^3.0.3", "zod-to-json-schema": "^3.24.1" }, "peerDependencies": { "zod": "^3.25.76 || ^4" } }, "sha512-RJMeoqFA9mGo1XOE20bpVv4/ikVbZMHo00vmF4RweN7GHS+nEXU3SHFgtcp7NBG3j8W15b9MAitOBycRMYxecg=="],
|
||||
"@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@3.0.0-beta.10", "", { "dependencies": { "@ai-sdk/provider": "2.0.0-beta.2", "@standard-schema/spec": "^1.0.0", "eventsource-parser": "^3.0.3", "zod-to-json-schema": "^3.24.1" }, "peerDependencies": { "zod": "^3.25.76 || ^4" } }, "sha512-e6WSsgM01au04/1L/v5daXHn00eKjPBQXl3jq3BfvQbQ1jo8Rls2pvrdkyVc25jBW4TV4Zm+tw+v6NAh5NPXMA=="],
|
||||
|
||||
"@ampproject/remapping": ["@ampproject/remapping@2.3.0", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw=="],
|
||||
|
||||
@@ -594,7 +594,7 @@
|
||||
|
||||
"acorn-walk": ["acorn-walk@8.3.2", "", {}, "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A=="],
|
||||
|
||||
"ai": ["ai@5.0.0-beta.33", "", { "dependencies": { "@ai-sdk/gateway": "1.0.0-beta.18", "@ai-sdk/provider": "2.0.0-beta.2", "@ai-sdk/provider-utils": "3.0.0-beta.9", "@opentelemetry/api": "1.9.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4" } }, "sha512-TKDOYDRhS6kSmfbTj3lLFmS8kBx8OOHsIfhYKJBKnAPwlbkI3/byZRBty8tfKBrwsUAbSro3GB7rFeSthft37Q=="],
|
||||
"ai": ["ai@5.0.0-beta.34", "", { "dependencies": { "@ai-sdk/gateway": "1.0.0-beta.19", "@ai-sdk/provider": "2.0.0-beta.2", "@ai-sdk/provider-utils": "3.0.0-beta.10", "@opentelemetry/api": "1.9.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4" } }, "sha512-AFJ4p35AxA+1KFtnoouePLaAUpoj0IxIAoq/xgIv88qzYajTg4Sac5KaV4CDHFRLoF0L2cwhlFXt/Ss/zyBKkA=="],
|
||||
|
||||
"ajv": ["ajv@6.12.6", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g=="],
|
||||
|
||||
|
||||
+1
-1
@@ -18,7 +18,7 @@
|
||||
"catalog": {
|
||||
"@types/node": "22.13.9",
|
||||
"@tsconfig/node22": "22.0.2",
|
||||
"ai": "5.0.0-beta.33",
|
||||
"ai": "5.0.0-beta.34",
|
||||
"hono": "4.7.10",
|
||||
"typescript": "5.8.2",
|
||||
"zod": "3.25.49",
|
||||
|
||||
@@ -104,6 +104,7 @@ if (!snapshot) {
|
||||
.filter((x: string) => {
|
||||
const lower = x.toLowerCase()
|
||||
return (
|
||||
!lower.includes("release:") &&
|
||||
!lower.includes("ignore:") &&
|
||||
!lower.includes("chore:") &&
|
||||
!lower.includes("ci:") &&
|
||||
|
||||
@@ -278,6 +278,17 @@ export namespace Config {
|
||||
.optional()
|
||||
.describe("Custom provider configurations and model overrides"),
|
||||
mcp: z.record(z.string(), Mcp).optional().describe("MCP (Model Context Protocol) server configurations"),
|
||||
formatter: z
|
||||
.record(
|
||||
z.string(),
|
||||
z.object({
|
||||
disabled: z.boolean().optional(),
|
||||
command: z.array(z.string()).optional(),
|
||||
environment: z.record(z.string(), z.string()).optional(),
|
||||
extensions: z.array(z.string()).optional(),
|
||||
}),
|
||||
)
|
||||
.optional(),
|
||||
instructions: z.array(z.string()).optional().describe("Additional instruction files or patterns to include"),
|
||||
layout: Layout.optional().describe("@deprecated Always uses stretch layout."),
|
||||
permission: z
|
||||
|
||||
@@ -129,7 +129,9 @@ export const clang: Info = {
|
||||
command: ["clang-format", "-i", "$FILE"],
|
||||
extensions: [".c", ".cc", ".cpp", ".cxx", ".c++", ".h", ".hh", ".hpp", ".hxx", ".h++", ".ino", ".C", ".H"],
|
||||
async enabled() {
|
||||
return Bun.which("clang-format") !== null
|
||||
const app = App.info()
|
||||
const items = await Filesystem.findUp(".clang-format", app.path.cwd, app.path.root)
|
||||
return items.length > 0
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -5,20 +5,40 @@ import { Log } from "../util/log"
|
||||
import path from "path"
|
||||
|
||||
import * as Formatter from "./formatter"
|
||||
import { Config } from "../config/config"
|
||||
import { mergeDeep } from "remeda"
|
||||
|
||||
export namespace Format {
|
||||
const log = Log.create({ service: "format" })
|
||||
|
||||
const state = App.state("format", () => {
|
||||
const state = App.state("format", async () => {
|
||||
const enabled: Record<string, boolean> = {}
|
||||
const cfg = await Config.get()
|
||||
|
||||
const formatters = { ...Formatter } as Record<string, Formatter.Info>
|
||||
for (const [name, item] of Object.entries(cfg.formatter ?? {})) {
|
||||
if (item.disabled) {
|
||||
delete formatters[name]
|
||||
continue
|
||||
}
|
||||
const result: Formatter.Info = mergeDeep(formatters[name] ?? {}, {
|
||||
command: [],
|
||||
extensions: [],
|
||||
...item,
|
||||
})
|
||||
result.enabled = async () => true
|
||||
result.name = name
|
||||
formatters[name] = result
|
||||
}
|
||||
|
||||
return {
|
||||
enabled,
|
||||
formatters,
|
||||
}
|
||||
})
|
||||
|
||||
async function isEnabled(item: Formatter.Info) {
|
||||
const s = state()
|
||||
const s = await state()
|
||||
let status = s.enabled[item.name]
|
||||
if (status === undefined) {
|
||||
status = await item.enabled()
|
||||
@@ -28,8 +48,10 @@ export namespace Format {
|
||||
}
|
||||
|
||||
async function getFormatter(ext: string) {
|
||||
const formatters = await state().then((x) => x.formatters)
|
||||
const result = []
|
||||
for (const item of Object.values(Formatter)) {
|
||||
for (const item of Object.values(formatters)) {
|
||||
log.info("checking", { name: item.name, ext })
|
||||
if (!item.extensions.includes(ext)) continue
|
||||
if (!(await isEnabled(item))) continue
|
||||
result.push(item)
|
||||
|
||||
@@ -50,21 +50,24 @@ export namespace ModelsDev {
|
||||
export type Provider = z.infer<typeof Provider>
|
||||
|
||||
export async function get() {
|
||||
refresh()
|
||||
const file = Bun.file(filepath)
|
||||
const result = await file.json().catch(() => {})
|
||||
if (result) {
|
||||
refresh()
|
||||
return result as Record<string, Provider>
|
||||
}
|
||||
refresh()
|
||||
if (result) return result as Record<string, Provider>
|
||||
const json = await data()
|
||||
return JSON.parse(json) as Record<string, Provider>
|
||||
}
|
||||
|
||||
async function refresh() {
|
||||
export async function refresh() {
|
||||
const file = Bun.file(filepath)
|
||||
log.info("refreshing")
|
||||
const result = await fetch("https://models.dev/api.json").catch(() => {})
|
||||
const result = await fetch("https://models.dev/api.json", {
|
||||
headers: {
|
||||
"User-Agent": "opencode",
|
||||
},
|
||||
}).catch(() => {})
|
||||
if (result && result.ok) await Bun.write(file, result)
|
||||
}
|
||||
}
|
||||
|
||||
setInterval(() => ModelsDev.refresh(), 60 * 1000).unref()
|
||||
|
||||
@@ -1115,7 +1115,7 @@ export namespace Session {
|
||||
}
|
||||
const p = await getParts(assistantMsg.sessionID, assistantMsg.id)
|
||||
for (const part of p) {
|
||||
if (part.type === "tool" && part.state.status !== "completed") {
|
||||
if (part.type === "tool" && part.state.status !== "completed" && part.state.status !== "error") {
|
||||
updatePart({
|
||||
...part,
|
||||
state: {
|
||||
|
||||
@@ -5,14 +5,17 @@ import { App } from "../app/app"
|
||||
import { Permission } from "../permission"
|
||||
import { Config } from "../config/config"
|
||||
import { Filesystem } from "../util/filesystem"
|
||||
import path from "path"
|
||||
import { lazy } from "../util/lazy"
|
||||
import { minimatch } from "minimatch"
|
||||
import { Log } from "../util/log"
|
||||
import { Wildcard } from "../util/wildcard"
|
||||
import { $ } from "bun"
|
||||
|
||||
const MAX_OUTPUT_LENGTH = 30000
|
||||
const DEFAULT_TIMEOUT = 1 * 60 * 1000
|
||||
const MAX_TIMEOUT = 10 * 60 * 1000
|
||||
|
||||
const log = Log.create({ service: "bash-tool" })
|
||||
|
||||
const parser = lazy(async () => {
|
||||
const { default: Parser } = await import("tree-sitter")
|
||||
const Bash = await import("tree-sitter-bash")
|
||||
@@ -72,7 +75,8 @@ export const BashTool = Tool.define("bash", {
|
||||
if (["cd", "rm", "cp", "mv", "mkdir", "touch", "chmod", "chown"].includes(command[0])) {
|
||||
for (const arg of command.slice(1)) {
|
||||
if (arg.startsWith("-")) continue
|
||||
const resolved = path.resolve(app.path.cwd, arg)
|
||||
const resolved = await $`realpath ${arg}`.text().then((x) => x.trim())
|
||||
log.info("resolved path", { arg, resolved })
|
||||
if (!Filesystem.contains(app.path.cwd, resolved)) {
|
||||
throw new Error(
|
||||
`This command references paths outside of ${app.path.cwd} so it is not allowed to be executed.`,
|
||||
@@ -85,9 +89,9 @@ export const BashTool = Tool.define("bash", {
|
||||
if (!needsAsk && command[0] !== "cd") {
|
||||
const ask = (() => {
|
||||
for (const [pattern, value] of Object.entries(permissions)) {
|
||||
if (minimatch(node.text, pattern)) {
|
||||
return value
|
||||
}
|
||||
const match = Wildcard.match(node.text, pattern)
|
||||
log.info("checking", { text: node.text.trim(), pattern, match })
|
||||
if (match) return value
|
||||
}
|
||||
return "ask"
|
||||
})()
|
||||
|
||||
@@ -96,6 +96,7 @@ export const EditTool = Tool.define("edit", {
|
||||
file: filePath,
|
||||
})
|
||||
contentNew = await file.text()
|
||||
diff = trimDiff(createTwoFilesPatch(filePath, filePath, contentOld, contentNew))
|
||||
})()
|
||||
|
||||
FileTime.read(ctx.sessionID, filePath)
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
export namespace Wildcard {
|
||||
export function match(str: string, pattern: string) {
|
||||
const regex = new RegExp(
|
||||
"^" +
|
||||
pattern
|
||||
.replace(/[.+^${}()|[\]\\]/g, "\\$&") // escape special regex chars
|
||||
.replace(/\*/g, ".*") // * becomes .*
|
||||
.replace(/\?/g, ".") + // ? becomes .
|
||||
"$",
|
||||
"s", // s flag enables multiline matching
|
||||
)
|
||||
return regex.test(str)
|
||||
}
|
||||
}
|
||||
@@ -590,6 +590,16 @@ export type Config = {
|
||||
type: 'remote';
|
||||
} & McpRemoteConfig);
|
||||
};
|
||||
formatter?: {
|
||||
[key: string]: {
|
||||
disabled?: boolean;
|
||||
command?: Array<string>;
|
||||
environment?: {
|
||||
[key: string]: string;
|
||||
};
|
||||
extensions?: Array<string>;
|
||||
};
|
||||
};
|
||||
/**
|
||||
* Additional instruction files or patterns to include
|
||||
*/
|
||||
|
||||
@@ -83,6 +83,7 @@ export default defineConfig({
|
||||
"docs/keybinds",
|
||||
"docs/permissions",
|
||||
"docs/mcp-servers",
|
||||
"docs/formatters",
|
||||
],
|
||||
},
|
||||
],
|
||||
|
||||
@@ -230,6 +230,12 @@ You can also define agents using markdown files in `~/.config/opencode/agent/` o
|
||||
|
||||
You can disable providers that are loaded automatically through the `disabled_providers` option. This is useful when you want to prevent certain providers from being loaded even if their credentials are available.
|
||||
|
||||
---
|
||||
|
||||
### Formatters
|
||||
|
||||
You can configure code formatters through the `formatter` option. See [Formatters documentation](/docs/formatters) for more details.
|
||||
|
||||
```json title="opencode.json"
|
||||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
---
|
||||
title: Formatters
|
||||
description: Code formatting with opencode
|
||||
---
|
||||
|
||||
opencode automatically formats code files after they are written or edited using language-specific formatters. This ensures consistent code style across your project without manual intervention.
|
||||
|
||||
## Built-in Formatters
|
||||
|
||||
opencode comes with several built-in formatters for popular languages and frameworks:
|
||||
|
||||
| Formatter | Languages/Extensions | Requirements |
|
||||
| -------------- | -------------------------------------------------------------------------------------------------------- | ------------------------------------- |
|
||||
| gofmt | .go | `gofmt` command available |
|
||||
| mix | .ex, .exs, .eex, .heex, .leex, .neex, .sface | `mix` command available |
|
||||
| prettier | .js, .jsx, .ts, .tsx, .html, .css, .md, .json, .yaml, and [more](https://prettier.io/docs/en/index.html) | `prettier` dependency in package.json |
|
||||
| biome | .js, .jsx, .ts, .tsx, .html, .css, .md, .json, .yaml, and [more](https://biomejs.dev/) | `biome.json` config file |
|
||||
| zig | .zig, .zon | `zig` command available |
|
||||
| clang-format | .c, .cpp, .h, .hpp, .ino, and [more](https://clang.llvm.org/docs/ClangFormat.html) | `.clang-format` config file |
|
||||
| ktlint | .kt, .kts | `ktlint` command available |
|
||||
| ruff | .py, .pyi | `ruff` command available with config |
|
||||
| rubocop | .rb, .rake, .gemspec, .ru | `rubocop` command available |
|
||||
| standardrb | .rb, .rake, .gemspec, .ru | `standardrb` command available |
|
||||
| htmlbeautifier | .erb, .html.erb | `htmlbeautifier` command available |
|
||||
|
||||
Formatters are automatically enabled when their requirements are met in your project environment.
|
||||
|
||||
## Configuration
|
||||
|
||||
You can customize formatters through the `formatter` section in your `opencode.json` configuration file.
|
||||
|
||||
### Disabling Formatters
|
||||
|
||||
To disable a specific formatter, set its `disabled` property to `true`:
|
||||
|
||||
```json title="opencode.json"
|
||||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
"formatter": {
|
||||
"prettier": {
|
||||
"disabled": true
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Custom Formatters
|
||||
|
||||
You can override the default formatters or add new ones by specifying the command, environment variables, and file extensions:
|
||||
|
||||
```json title="opencode.json"
|
||||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
"formatter": {
|
||||
"custom-prettier": {
|
||||
"command": ["npx", "prettier", "--write", "$FILE"],
|
||||
"environment": {
|
||||
"NODE_ENV": "development"
|
||||
},
|
||||
"extensions": [".js", ".ts", ".jsx", ".tsx"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The `$FILE` placeholder in the command will be replaced with the path to the file being formatted.
|
||||
|
||||
### Configuration Options
|
||||
|
||||
Each formatter configuration supports these properties:
|
||||
|
||||
| Property | Type | Description |
|
||||
| ------------- | -------- | ------------------------------------------------------- |
|
||||
| `disabled` | boolean | Set to `true` to disable the formatter |
|
||||
| `command` | string[] | The command to run for formatting |
|
||||
| `environment` | object | Environment variables to set when running the formatter |
|
||||
| `extensions` | string[] | File extensions this formatter should handle |
|
||||
|
||||
## How It Works
|
||||
|
||||
When opencode writes or edits a file, it:
|
||||
|
||||
1. Checks the file extension against all enabled formatters
|
||||
2. Runs the appropriate formatter command on the file
|
||||
3. Applies the formatting changes automatically
|
||||
|
||||
This process happens seamlessly in the background, ensuring your code maintains consistent formatting without requiring manual steps.
|
||||
@@ -18,6 +18,7 @@ Let's get started.
|
||||
To use opencode, you'll need:
|
||||
|
||||
1. A modern terminal emulator like:
|
||||
|
||||
- [WezTerm](https://wezterm.org), cross-platform
|
||||
- [Alacritty](https://alacritty.org), cross-platform
|
||||
- [Ghostty](https://ghostty.org), Linux and macOS
|
||||
@@ -40,26 +41,10 @@ You can also install it with the following:
|
||||
- **Using Node.js**
|
||||
|
||||
<Tabs>
|
||||
<TabItem label="npm">
|
||||
```bash
|
||||
npm install -g opencode-ai
|
||||
```
|
||||
</TabItem>
|
||||
<TabItem label="Bun">
|
||||
```bash
|
||||
bun install -g opencode-ai
|
||||
```
|
||||
</TabItem>
|
||||
<TabItem label="pnpm">
|
||||
```bash
|
||||
pnpm install -g opencode-ai
|
||||
```
|
||||
</TabItem>
|
||||
<TabItem label="Yarn">
|
||||
```bash
|
||||
yarn global add opencode-ai
|
||||
```
|
||||
</TabItem>
|
||||
<TabItem label="npm">```bash npm install -g opencode-ai ```</TabItem>
|
||||
<TabItem label="Bun">```bash bun install -g opencode-ai ```</TabItem>
|
||||
<TabItem label="pnpm">```bash pnpm install -g opencode-ai ```</TabItem>
|
||||
<TabItem label="Yarn">```bash yarn global add opencode-ai ```</TabItem>
|
||||
</Tabs>
|
||||
|
||||
- **Using Homebrew on macOS**
|
||||
@@ -138,7 +123,7 @@ You should commit your project's `AGENTS.md` file to Git.
|
||||
:::
|
||||
|
||||
This helps opencode understand the project structure and the coding patterns
|
||||
used.
|
||||
used.
|
||||
|
||||
---
|
||||
|
||||
@@ -178,22 +163,22 @@ You can ask opencode to add new features to your project. Though we first recomm
|
||||
instead suggest _how_ it'll implement the feature.
|
||||
|
||||
Switch to it using the **Tab** key. You'll see an indicator for this in the lower right corner.
|
||||
|
||||
|
||||
```bash frame="none" title="Switch to Plan mode"
|
||||
<TAB>
|
||||
```
|
||||
|
||||
Now let's describe what we want it to do.
|
||||
|
||||
|
||||
```txt frame="none"
|
||||
When a user deletes a note, we'd like to flag it as deleted in the database.
|
||||
Then create a screen that shows all the recently deleted notes.
|
||||
From this screen, the user can undelete a note or permanently delete it.
|
||||
```
|
||||
|
||||
|
||||
You want to give opencode enough details to understand what you want. It helps
|
||||
to talk to it like you are talking to a junior developer on your team.
|
||||
|
||||
|
||||
:::tip
|
||||
Give opencode plenty of context and examples to help it understand what you
|
||||
want.
|
||||
@@ -202,7 +187,7 @@ You can ask opencode to add new features to your project. Though we first recomm
|
||||
2. **Iterate on the plan**
|
||||
|
||||
Once it gives you a plan, you can give it feedback or add more details.
|
||||
|
||||
|
||||
```txt frame="none"
|
||||
We'd like to design this new screen using a design I've used before.
|
||||
[Image #1] Take a look at this image and use it as a reference.
|
||||
@@ -216,16 +201,16 @@ You can ask opencode to add new features to your project. Though we first recomm
|
||||
do this by dragging and dropping an image into the terminal.
|
||||
|
||||
3. **Build the feature**
|
||||
|
||||
|
||||
Once you feel comfortable with the plan, switch back to _Build mode_ by
|
||||
hitting the **Tab** key again.
|
||||
|
||||
|
||||
```bash frame="none"
|
||||
<TAB>
|
||||
```
|
||||
|
||||
|
||||
And asking it to make the changes.
|
||||
|
||||
|
||||
```bash frame="none"
|
||||
Sounds good! Go ahead and make the changes.
|
||||
```
|
||||
@@ -271,4 +256,4 @@ Here's an [example conversation](https://opencode.ai/s/4XP1fce5) with opencode.
|
||||
|
||||
And that's it! You are now a pro at using opencode.
|
||||
|
||||
To make it your own, we recommend [picking a theme](/docs/themes), [customizing the keybinds](/docs/keybinds), or playing around with the [opencode config](/docs/config).
|
||||
To make it your own, we recommend [picking a theme](/docs/themes), [customizing the keybinds](/docs/keybinds), [configuring code formatters](/docs/formatters), or playing around with the [opencode config](/docs/config).
|
||||
|
||||
@@ -46,6 +46,8 @@ This mode is useful when you want the AI to analyze code, suggest changes, or cr
|
||||
|
||||
You can switch between modes during a session using the _Tab_ key. Or your configured `switch_mode` keybind.
|
||||
|
||||
See also: [Formatters](/docs/formatters) for information about code formatting configuration.
|
||||
|
||||
---
|
||||
|
||||
## Configure
|
||||
@@ -99,6 +101,7 @@ tools:
|
||||
---
|
||||
|
||||
You are in code review mode. Focus on:
|
||||
|
||||
- Code quality and best practices
|
||||
- Potential bugs and edge cases
|
||||
- Performance implications
|
||||
@@ -281,6 +284,7 @@ tools:
|
||||
You are in debug mode. Your primary goal is to help investigate and diagnose issues.
|
||||
|
||||
Focus on:
|
||||
|
||||
- Understanding the problem through careful analysis
|
||||
- Using bash commands to inspect system state
|
||||
- Reading relevant files and logs
|
||||
@@ -304,6 +308,7 @@ tools:
|
||||
You are in refactoring mode. Focus on improving code quality without changing functionality.
|
||||
|
||||
Priorities:
|
||||
|
||||
- Improve code readability and maintainability
|
||||
- Apply consistent naming conventions
|
||||
- Reduce code duplication
|
||||
|
||||
@@ -1,57 +1,74 @@
|
||||
---
|
||||
title: Permissions
|
||||
description: Control what AI agents can do in your codebase.
|
||||
description: Control what agents can do in your codebase.
|
||||
---
|
||||
|
||||
By default, opencode allows all operations without requiring explicit approval. The permissions system provides granular control to restrict what actions AI agents can perform in your codebase, allowing you to configure explicit approval requirements for sensitive operations like file editing, bash commands, and more.
|
||||
By default, opencode **allows all operations** without requiring explicit approval.
|
||||
|
||||
## Configuration
|
||||
The permissions system provides granular control to restrict what actions AI agents can perform in your codebase, allowing you to configure explicit approval requirements for sensitive operations like file editing, bash commands, and more.
|
||||
|
||||
Permissions are configured in your `opencode.json` file under the `permission` key. Here are the available options:
|
||||
---
|
||||
|
||||
### permission.edit
|
||||
## Configure
|
||||
|
||||
Controls whether file editing operations require user approval.
|
||||
Permissions are configured in your `opencode.json` file under the `permission` key. Here are the available options.
|
||||
|
||||
- `"ask"` - Prompt user for approval before editing files
|
||||
---
|
||||
|
||||
### edit
|
||||
|
||||
Use the `permission.edit` key to control whether file editing operations require user approval.
|
||||
|
||||
- `"ask"` - Prompt for approval before editing files
|
||||
- `"allow"` - Allow all file editing operations without approval
|
||||
|
||||
### permission.bash
|
||||
|
||||
Controls whether bash commands require user approval. This can be configured globally or with specific patterns. Setting this to "ask" is the strictest mode, requiring approval for all bash commands.
|
||||
|
||||
## Configuration examples
|
||||
|
||||
### Basic permission configuration
|
||||
|
||||
```json title="opencode.json"
|
||||
```json title="opencode.json" {4}
|
||||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
"permission": {
|
||||
"edit": "ask",
|
||||
"bash": "ask"
|
||||
"edit": "ask"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Advanced bash permission configuration
|
||||
---
|
||||
|
||||
Setting bash permissions to "ask" is the strictest mode. If you want to allow specific commands without approval, you can configure them explicitly. All other commands will require approval by default:
|
||||
### bash
|
||||
|
||||
```json title="opencode.json"
|
||||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
"permission": {
|
||||
"edit": "ask",
|
||||
"bash": {
|
||||
"git status": "allow",
|
||||
"git diff": "allow",
|
||||
"npm run build": "allow",
|
||||
"ls": "allow",
|
||||
"pwd": "allow"
|
||||
Controls whether bash commands require user approval.
|
||||
|
||||
:::tip
|
||||
You can specify which commands you want to have run without approval.
|
||||
:::
|
||||
|
||||
This can be configured globally or with specific patterns. Setting this to `"ask"` is the strictest mode, requiring approval for all bash commands.
|
||||
|
||||
For example.
|
||||
|
||||
- **Ask for approval for all commands**
|
||||
|
||||
```json title="opencode.json"
|
||||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
"permission": {
|
||||
"bash": "ask"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
```
|
||||
|
||||
This permissions system ensures that you maintain control over what AI agents can do in your codebase while providing flexibility for trusted operations.
|
||||
- **Approve specific commands**
|
||||
|
||||
```json title="opencode.json"
|
||||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
"permission": {
|
||||
"bash": {
|
||||
"git status": "allow",
|
||||
"git diff": "allow",
|
||||
"npm run build": "allow",
|
||||
"ls": "allow",
|
||||
"pwd": "allow"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@ await import(`../packages/sdk/js/script/publish.ts`)
|
||||
// await import(`../packages/sdk/stainless/generate.ts`)
|
||||
|
||||
if (!snapshot) {
|
||||
await $`git commit -am "Release v${version}"`
|
||||
await $`git commit -am "release: v${version}"`
|
||||
await $`git tag v${version}`
|
||||
await $`git push origin HEAD --tags`
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user