mirror of
https://github.com/anomalyco/opencode.git
synced 2026-04-24 06:45:22 +00:00
Compare commits
15 Commits
v0.3.115
...
v0.0.0-202
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ff7cd909d0 | ||
|
|
564ef93066 | ||
|
|
263b266476 | ||
|
|
06830327e7 | ||
|
|
4b204fee58 | ||
|
|
99d3a0bb24 | ||
|
|
0930f6ac55 | ||
|
|
24515162fa | ||
|
|
53aa899e45 | ||
|
|
7e763e1c06 | ||
|
|
b0f2cc0c22 | ||
|
|
f90aa62784 | ||
|
|
852191f6cb | ||
|
|
c5e9dc081c | ||
|
|
49c8889228 |
13
.github/workflows/publish.yml
vendored
13
.github/workflows/publish.yml
vendored
@@ -39,6 +39,15 @@ jobs:
|
||||
with:
|
||||
bun-version: 1.2.19
|
||||
|
||||
- name: Cache ~/.bun
|
||||
id: cache-bun
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ~/.bun
|
||||
key: ${{ runner.os }}-bun-${{ hashFiles('bun.lock') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-bun-
|
||||
|
||||
- name: Install makepkg
|
||||
run: |
|
||||
sudo apt-get update
|
||||
@@ -53,9 +62,11 @@ jobs:
|
||||
git config --global user.email "opencode@sst.dev"
|
||||
git config --global user.name "opencode"
|
||||
|
||||
- name: Install dependencies
|
||||
run: bun install
|
||||
|
||||
- name: Publish
|
||||
run: |
|
||||
bun install
|
||||
OPENCODE_VERSION=${{ inputs.version }} ./script/publish.ts
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.SST_GITHUB_TOKEN }}
|
||||
|
||||
1
STATS.md
1
STATS.md
@@ -36,3 +36,4 @@
|
||||
| 2025-07-31 | 118,339 (+4,795) | 143,344 (+3,027) | 261,683 (+7,822) |
|
||||
| 2025-08-01 | 123,539 (+5,200) | 146,680 (+3,336) | 270,219 (+8,536) |
|
||||
| 2025-08-02 | 127,864 (+4,325) | 149,236 (+2,556) | 277,100 (+6,881) |
|
||||
| 2025-08-03 | 131,397 (+3,533) | 150,451 (+1,215) | 281,848 (+4,748) |
|
||||
|
||||
10
bun.lock
10
bun.lock
@@ -10,7 +10,7 @@
|
||||
},
|
||||
"packages/function": {
|
||||
"name": "@opencode/function",
|
||||
"version": "0.3.113",
|
||||
"version": "0.3.120",
|
||||
"dependencies": {
|
||||
"@octokit/auth-app": "8.0.1",
|
||||
"@octokit/rest": "22.0.0",
|
||||
@@ -25,7 +25,7 @@
|
||||
},
|
||||
"packages/opencode": {
|
||||
"name": "opencode",
|
||||
"version": "0.3.113",
|
||||
"version": "0.3.120",
|
||||
"bin": {
|
||||
"opencode": "./bin/opencode",
|
||||
},
|
||||
@@ -78,7 +78,7 @@
|
||||
},
|
||||
"packages/plugin": {
|
||||
"name": "@opencode-ai/plugin",
|
||||
"version": "0.3.113",
|
||||
"version": "0.3.120",
|
||||
"devDependencies": {
|
||||
"@hey-api/openapi-ts": "0.80.1",
|
||||
"@opencode-ai/sdk": "workspace:*",
|
||||
@@ -88,7 +88,7 @@
|
||||
},
|
||||
"packages/sdk/js": {
|
||||
"name": "@opencode-ai/sdk",
|
||||
"version": "0.3.113",
|
||||
"version": "0.3.120",
|
||||
"devDependencies": {
|
||||
"@hey-api/openapi-ts": "0.80.1",
|
||||
"@tsconfig/node22": "catalog:",
|
||||
@@ -97,7 +97,7 @@
|
||||
},
|
||||
"packages/web": {
|
||||
"name": "@opencode/web",
|
||||
"version": "0.3.113",
|
||||
"version": "0.3.120",
|
||||
"dependencies": {
|
||||
"@astrojs/cloudflare": "^12.5.4",
|
||||
"@astrojs/markdown-remark": "6.3.1",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@opencode/function",
|
||||
"version": "0.3.113",
|
||||
"version": "0.3.122",
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"version": "0.3.113",
|
||||
"version": "0.3.122",
|
||||
"name": "opencode",
|
||||
"type": "module",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"typecheck": "tsc --noEmit",
|
||||
"dev": "bun run ./src/index.ts"
|
||||
"dev": "bun run --conditions=development ./src/index.ts"
|
||||
},
|
||||
"bin": {
|
||||
"opencode": "./bin/opencode"
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Log } from "../util/log"
|
||||
import path from "path"
|
||||
import os from "os"
|
||||
import { z } from "zod"
|
||||
import { App } from "../app/app"
|
||||
import { Filesystem } from "../util/filesystem"
|
||||
@@ -403,7 +404,10 @@ export namespace Config {
|
||||
if (lineIndex !== -1 && lines[lineIndex].trim().startsWith("//")) {
|
||||
continue // Skip if line is commented
|
||||
}
|
||||
const filePath = match.replace(/^\{file:/, "").replace(/\}$/, "")
|
||||
let filePath = match.replace(/^\{file:/, "").replace(/\}$/, "")
|
||||
if (filePath.startsWith("~/")) {
|
||||
filePath = path.join(os.homedir(), filePath.slice(2))
|
||||
}
|
||||
const resolvedPath = path.isAbsolute(filePath) ? filePath : path.resolve(configDir, filePath)
|
||||
const fileContent = (await Bun.file(resolvedPath).text()).trim()
|
||||
// escape newlines/quotes, strip outer quotes
|
||||
|
||||
@@ -735,7 +735,6 @@ export namespace Session {
|
||||
args,
|
||||
},
|
||||
)
|
||||
await processor.track(options.toolCallId)
|
||||
const result = await item.execute(args, {
|
||||
sessionID: input.sessionID,
|
||||
abort: abort.signal,
|
||||
@@ -784,7 +783,6 @@ export namespace Session {
|
||||
const execute = item.execute
|
||||
if (!execute) continue
|
||||
item.execute = async (args, opts) => {
|
||||
await processor.track(opts.toolCallId)
|
||||
const result = await execute(args, opts)
|
||||
const output = result.content
|
||||
.filter((x: any) => x.type === "text")
|
||||
@@ -920,15 +918,11 @@ export namespace Session {
|
||||
}
|
||||
|
||||
function createProcessor(assistantMsg: MessageV2.Assistant, model: ModelsDev.Model) {
|
||||
const toolCalls: Record<string, MessageV2.ToolPart> = {}
|
||||
const snapshots: Record<string, string> = {}
|
||||
const toolcalls: Record<string, MessageV2.ToolPart> = {}
|
||||
let snapshot: string | undefined
|
||||
return {
|
||||
async track(toolCallID: string) {
|
||||
const hash = await Snapshot.track()
|
||||
if (hash) snapshots[toolCallID] = hash
|
||||
},
|
||||
partFromToolCall(toolCallID: string) {
|
||||
return toolCalls[toolCallID]
|
||||
return toolcalls[toolCallID]
|
||||
},
|
||||
async process(stream: StreamTextResult<Record<string, AITool>, never>) {
|
||||
try {
|
||||
@@ -944,7 +938,7 @@ export namespace Session {
|
||||
|
||||
case "tool-input-start":
|
||||
const part = await updatePart({
|
||||
id: toolCalls[value.id]?.id ?? Identifier.ascending("part"),
|
||||
id: toolcalls[value.id]?.id ?? Identifier.ascending("part"),
|
||||
messageID: assistantMsg.id,
|
||||
sessionID: assistantMsg.sessionID,
|
||||
type: "tool",
|
||||
@@ -954,7 +948,7 @@ export namespace Session {
|
||||
status: "pending",
|
||||
},
|
||||
})
|
||||
toolCalls[value.id] = part as MessageV2.ToolPart
|
||||
toolcalls[value.id] = part as MessageV2.ToolPart
|
||||
break
|
||||
|
||||
case "tool-input-delta":
|
||||
@@ -964,7 +958,7 @@ export namespace Session {
|
||||
break
|
||||
|
||||
case "tool-call": {
|
||||
const match = toolCalls[value.toolCallId]
|
||||
const match = toolcalls[value.toolCallId]
|
||||
if (match) {
|
||||
const part = await updatePart({
|
||||
...match,
|
||||
@@ -976,12 +970,12 @@ export namespace Session {
|
||||
},
|
||||
},
|
||||
})
|
||||
toolCalls[value.toolCallId] = part as MessageV2.ToolPart
|
||||
toolcalls[value.toolCallId] = part as MessageV2.ToolPart
|
||||
}
|
||||
break
|
||||
}
|
||||
case "tool-result": {
|
||||
const match = toolCalls[value.toolCallId]
|
||||
const match = toolcalls[value.toolCallId]
|
||||
if (match && match.state.status === "running") {
|
||||
await updatePart({
|
||||
...match,
|
||||
@@ -997,27 +991,13 @@ export namespace Session {
|
||||
},
|
||||
},
|
||||
})
|
||||
delete toolCalls[value.toolCallId]
|
||||
const snapshot = snapshots[value.toolCallId]
|
||||
if (snapshot) {
|
||||
const patch = await Snapshot.patch(snapshot)
|
||||
if (patch.files.length) {
|
||||
await updatePart({
|
||||
id: Identifier.ascending("part"),
|
||||
messageID: assistantMsg.id,
|
||||
sessionID: assistantMsg.sessionID,
|
||||
type: "patch",
|
||||
hash: patch.hash,
|
||||
files: patch.files,
|
||||
})
|
||||
}
|
||||
}
|
||||
delete toolcalls[value.toolCallId]
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
case "tool-error": {
|
||||
const match = toolCalls[value.toolCallId]
|
||||
const match = toolcalls[value.toolCallId]
|
||||
if (match && match.state.status === "running") {
|
||||
await updatePart({
|
||||
...match,
|
||||
@@ -1031,19 +1011,7 @@ export namespace Session {
|
||||
},
|
||||
},
|
||||
})
|
||||
delete toolCalls[value.toolCallId]
|
||||
const snapshot = snapshots[value.toolCallId]
|
||||
if (snapshot) {
|
||||
const patch = await Snapshot.patch(snapshot)
|
||||
await updatePart({
|
||||
id: Identifier.ascending("part"),
|
||||
messageID: assistantMsg.id,
|
||||
sessionID: assistantMsg.sessionID,
|
||||
type: "patch",
|
||||
hash: patch.hash,
|
||||
files: patch.files,
|
||||
})
|
||||
}
|
||||
delete toolcalls[value.toolCallId]
|
||||
}
|
||||
break
|
||||
}
|
||||
@@ -1058,6 +1026,7 @@ export namespace Session {
|
||||
sessionID: assistantMsg.sessionID,
|
||||
type: "step-start",
|
||||
})
|
||||
snapshot = await Snapshot.track()
|
||||
break
|
||||
|
||||
case "finish-step":
|
||||
@@ -1073,6 +1042,20 @@ export namespace Session {
|
||||
cost: usage.cost,
|
||||
})
|
||||
await updateMessage(assistantMsg)
|
||||
if (snapshot) {
|
||||
const patch = await Snapshot.patch(snapshot)
|
||||
if (patch.files.length) {
|
||||
await updatePart({
|
||||
id: Identifier.ascending("part"),
|
||||
messageID: assistantMsg.id,
|
||||
sessionID: assistantMsg.sessionID,
|
||||
type: "patch",
|
||||
hash: patch.hash,
|
||||
files: patch.files,
|
||||
})
|
||||
}
|
||||
snapshot = undefined
|
||||
}
|
||||
break
|
||||
|
||||
case "text-start":
|
||||
|
||||
@@ -39,7 +39,7 @@ export namespace Snapshot {
|
||||
log.info("initialized")
|
||||
}
|
||||
await $`git --git-dir ${git} add .`.quiet().cwd(app.path.cwd).nothrow()
|
||||
const hash = await $`git --git-dir ${git} write-tree`.quiet().cwd(app.path.cwd).text()
|
||||
const hash = await $`git --git-dir ${git} write-tree`.quiet().cwd(app.path.cwd).nothrow().text()
|
||||
return hash.trim()
|
||||
}
|
||||
|
||||
|
||||
@@ -75,9 +75,13 @@ 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("-") || (command[0] === "chmod" && arg.startsWith("+"))) continue
|
||||
const resolved = await $`realpath ${arg}`.text().then((x) => x.trim())
|
||||
const resolved = await $`realpath ${arg}`
|
||||
.quiet()
|
||||
.nothrow()
|
||||
.text()
|
||||
.then((x) => x.trim())
|
||||
log.info("resolved path", { arg, resolved })
|
||||
if (!Filesystem.contains(app.path.cwd, resolved)) {
|
||||
if (resolved && !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.`,
|
||||
)
|
||||
@@ -118,6 +122,7 @@ export const BashTool = Tool.define("bash", {
|
||||
maxBuffer: MAX_OUTPUT_LENGTH,
|
||||
signal: ctx.abort,
|
||||
timeout: timeout,
|
||||
stdin: "pipe",
|
||||
stdout: "pipe",
|
||||
stderr: "pipe",
|
||||
})
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"name": "@opencode-ai/plugin",
|
||||
"version": "0.3.113",
|
||||
"version": "0.3.122",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"typecheck": "tsc --noEmit"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"name": "@opencode-ai/sdk",
|
||||
"version": "0.3.113",
|
||||
"version": "0.3.122",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"typecheck": "tsc --noEmit"
|
||||
|
||||
@@ -4,7 +4,6 @@ const dir = new URL("..", import.meta.url).pathname
|
||||
process.chdir(dir)
|
||||
|
||||
import { $ } from "bun"
|
||||
import fs from "fs/promises"
|
||||
import path from "path"
|
||||
|
||||
console.log("=== Generating JS SDK ===")
|
||||
@@ -12,8 +11,7 @@ console.log()
|
||||
|
||||
import { createClient } from "@hey-api/openapi-ts"
|
||||
|
||||
await fs.rm(path.join(dir, "src/gen"), { recursive: true, force: true })
|
||||
await $`bun run ../../opencode/src/index.ts generate > openapi.json`
|
||||
await $`bun dev generate > ${dir}/openapi.json`.cwd(path.resolve(dir, "../../opencode"))
|
||||
|
||||
await createClient({
|
||||
input: "./openapi.json",
|
||||
@@ -37,6 +35,3 @@ await createClient({
|
||||
],
|
||||
})
|
||||
await $`bun prettier --write src/gen`
|
||||
|
||||
await $`rm -rf dist`
|
||||
await $`bun tsc`
|
||||
|
||||
@@ -6,6 +6,8 @@ process.chdir(dir)
|
||||
import { $ } from "bun"
|
||||
|
||||
await import("./generate")
|
||||
await $`rm -rf dist`
|
||||
await $`bun tsc`
|
||||
|
||||
const snapshot = process.env["OPENCODE_SNAPSHOT"] === "true"
|
||||
|
||||
|
||||
@@ -10,6 +10,9 @@
|
||||
"es2022",
|
||||
"dom",
|
||||
"dom.iterable"
|
||||
],
|
||||
"customConditions": [
|
||||
"development"
|
||||
]
|
||||
},
|
||||
"include": [
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@opencode/web",
|
||||
"type": "module",
|
||||
"version": "0.3.113",
|
||||
"version": "0.3.122",
|
||||
"scripts": {
|
||||
"dev": "astro dev",
|
||||
"dev:remote": "sst shell --stage=dev --target=Web astro dev",
|
||||
|
||||
@@ -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.
|
||||
|
||||
The `disabled_providers` option accepts an array of provider IDs. When a provider is disabled:
|
||||
|
||||
- It won't be loaded even if environment variables are set
|
||||
- It won't be loaded even if API keys are configured through `opencode auth login`
|
||||
- The provider's models won't appear in the model selection list
|
||||
|
||||
---
|
||||
|
||||
### Formatters
|
||||
@@ -243,12 +249,6 @@ You can configure code formatters through the `formatter` option. See [Formatter
|
||||
}
|
||||
```
|
||||
|
||||
The `disabled_providers` option accepts an array of provider IDs. When a provider is disabled:
|
||||
|
||||
- It won't be loaded even if environment variables are set
|
||||
- It won't be loaded even if API keys are configured through `opencode auth login`
|
||||
- The provider's models won't appear in the model selection list
|
||||
|
||||
---
|
||||
|
||||
### Permissions
|
||||
|
||||
@@ -15,14 +15,13 @@ const pkgjsons = await Array.fromAsync(
|
||||
new Bun.Glob("**/package.json").scan({
|
||||
absolute: true,
|
||||
}),
|
||||
)
|
||||
).then((arr) => arr.filter((x) => !x.includes("node_modules") && !x.includes("dist")))
|
||||
|
||||
const tree = await $`git add . && git write-tree`.text().then((x) => x.trim())
|
||||
for await (const file of new Bun.Glob("**/package.json").scan({
|
||||
absolute: true,
|
||||
})) {
|
||||
for (const file of pkgjsons) {
|
||||
let pkg = await Bun.file(file).text()
|
||||
pkg = pkg.replaceAll(/"version": "[^"]+"/g, `"version": "${version}"`)
|
||||
console.log("versioned", file, version)
|
||||
await Bun.file(file).write(pkg)
|
||||
}
|
||||
|
||||
@@ -43,9 +42,7 @@ if (snapshot) {
|
||||
await $`git push origin v${version} --no-verify`
|
||||
await $`git checkout dev`
|
||||
await $`git branch -D snapshot-${version}`
|
||||
for await (const file of new Bun.Glob("**/package.json").scan({
|
||||
absolute: true,
|
||||
})) {
|
||||
$`await git checkout ${tree} ${file}`
|
||||
for (const file of pkgjsons) {
|
||||
await $`git checkout ${tree} ${file}`
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"name": "opencode",
|
||||
"displayName": "opencode",
|
||||
"description": "opencode for VS Code",
|
||||
"version": "0.3.113",
|
||||
"version": "0.3.122",
|
||||
"publisher": "sst-dev",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
Reference in New Issue
Block a user