Compare commits

..
14 Commits
Author SHA1 Message Date
Dax Raad ee1f55dbe2 token
publish / publish (push) Has been cancelled
2025-06-12 13:17:06 -04:00
Dax Raad 2fa50190e5 skip nil values
publish / publish (push) Has been cancelled
2025-06-12 13:13:34 -04:00
Jay V 662b6b1258 share page handle undefined 2025-06-12 13:11:34 -04:00
Dax Raad f0dbe40522 sync
publish / publish (push) Has been cancelled
2025-06-12 13:04:01 -04:00
Dax Raad 41c54f629c sync
release / goreleaser (push) Has been cancelled
2025-06-12 12:48:38 -04:00
Dax Raad 4503201b15 npm token
release / goreleaser (push) Has been cancelled
2025-06-12 12:09:13 -04:00
Dax Raad 120151ee38 sync 2025-06-12 11:58:41 -04:00
Dax Raad 4d2e556713 sync
release / goreleaser (push) Has been cancelled
2025-06-12 11:57:57 -04:00
Dax Raad 54a5d3a9eb sync
release / goreleaser (push) Has been cancelled
2025-06-12 11:56:52 -04:00
Dax Raad 22dc6b6ec9 sync
release / goreleaser (push) Has been cancelled
2025-06-12 11:56:06 -04:00
Dax Raad b5c6ddcd04 tweak
release / goreleaser (push) Has been cancelled
2025-06-12 11:55:07 -04:00
Dax Raad e03ad6c42e sync
release / goreleaser (push) Has been cancelled
2025-06-12 11:18:17 -04:00
Dax Raad 33457d8472 sync
release / goreleaser (push) Has been cancelled
2025-06-12 11:02:51 -04:00
Dax Raad 888105e60f sync
release / goreleaser (push) Has been cancelled
2025-06-12 11:00:37 -04:00
11 changed files with 242 additions and 106 deletions
@@ -1,4 +1,4 @@
name: release
name: publish
on:
workflow_dispatch:
@@ -13,7 +13,7 @@ permissions:
packages: write
jobs:
goreleaser:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
@@ -24,17 +24,19 @@ jobs:
- uses: actions/setup-go@v5
with:
go-version: ">=1.23.2"
go-version: ">=1.24.0"
cache: true
cache-dependency-path: go.sum
- run: go mod download
- uses: goreleaser/goreleaser-action@v6
- uses: oven-sh/setup-bun@v2
with:
distribution: goreleaser
version: latest
args: release --clean
bun-version: 1.2.16
- run: |
bun install
./script/publish.ts
working-directory: ./packages/opencode
env:
GITHUB_TOKEN: ${{ secrets.SST_GITHUB_TOKEN }}
AUR_KEY: ${{ secrets.AUR_KEY }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
@@ -0,0 +1,23 @@
# Maintainer: dax
# Maintainer: adam
pkgname='opencode-bin'
pkgver={{VERSION}}
pkgrel=1
pkgdesc='The AI coding agent built for the terminal.'
url='https://github.com/sst/opencode'
arch=('aarch64' 'x86_64')
license=('MIT')
provides=('opencode')
conflicts=('opencode')
depends=('fzf' 'ripgrep')
source_aarch64=("${pkgname}_${pkgver}_aarch64.zip::{{ARM64_URL}}")
sha256sums_aarch64=('{{ARM64_SHA}}')
source_x86_64=("${pkgname}_${pkgver}_x86_64.zip::{{X64_URL}}")
sha256sums_x86_64=('{{X64_SHA}}')
package() {
install -Dm755 ./opencode "${pkgdir}/usr/bin/opencode"
}
+161
View File
@@ -0,0 +1,161 @@
#!/usr/bin/env bun
import { $ } from "bun"
import pkg from "../package.json"
const dry = process.argv.includes("--dry")
const snapshot = process.argv.includes("--snapshot")
const version = snapshot
? `0.0.0-${new Date().toISOString().slice(0, 16).replace(/[-:T]/g, "")}`
: await $`git describe --tags --exact-match HEAD`
.text()
.then((x) => x.substring(1).trim())
.catch(() => {
console.error("tag not found")
process.exit(1)
})
console.log(`publishing ${version}`)
const GOARCH: Record<string, string> = {
arm64: "arm64",
x64: "amd64",
}
const targets = [
["linux", "arm64"],
["linux", "x64"],
["darwin", "x64"],
["darwin", "arm64"],
["windows", "x64"],
]
await $`rm -rf dist`
const optionalDependencies: Record<string, string> = {}
const npmTag = snapshot ? "snapshot" : "latest"
for (const [os, arch] of targets) {
console.log(`building ${os}-${arch}`)
const name = `${pkg.name}-${os}-${arch}`
await $`mkdir -p dist/${name}/bin`
await $`GOOS=${os} GOARCH=${GOARCH[arch]} go build -ldflags="-s -w -X main.Version=${version}" -o ../opencode/dist/${name}/bin/tui ../tui/cmd/opencode/main.go`.cwd(
"../tui",
)
await $`bun build --define OPENCODE_VERSION="'${version}'" --compile --minify --target=bun-${os}-${arch} --outfile=dist/${name}/bin/opencode ./src/index.ts ./dist/${name}/bin/tui`
await $`rm -rf ./dist/${name}/bin/tui`
await Bun.file(`dist/${name}/package.json`).write(
JSON.stringify(
{
name,
version,
os: [os === "windows" ? "win32" : os],
cpu: [arch],
},
null,
2,
),
)
if (!dry)
await $`cd dist/${name} && bun publish --access public --tag ${npmTag}`
optionalDependencies[name] = version
}
await $`mkdir -p ./dist/${pkg.name}`
await $`cp -r ./bin ./dist/${pkg.name}/bin`
await $`cp ./script/postinstall.js ./dist/${pkg.name}/postinstall.js`
await Bun.file(`./dist/${pkg.name}/package.json`).write(
JSON.stringify(
{
name: pkg.name + "-ai",
bin: {
[pkg.name]: `./bin/${pkg.name}`,
},
scripts: {
postinstall: "node ./postinstall.js",
},
version,
optionalDependencies,
},
null,
2,
),
)
if (!dry)
await $`cd ./dist/${pkg.name} && bun publish --access public --tag ${npmTag}`
if (!snapshot) {
// Github Release
for (const key of Object.keys(optionalDependencies)) {
await $`cd dist/${key}/bin && zip -r ../../${key}.zip *`
}
const previous = await fetch(
"https://api.github.com/repos/sst/opencode/releases/latest",
)
.then((res) => res.json())
.then((data) => data.tag_name)
const commits = await fetch(
`https://api.github.com/repos/sst/opencode/compare/${previous}...HEAD`,
)
.then((res) => res.json())
.then((data) => data.commits || [])
const notes = commits
.map((commit: any) => `- ${commit.commit.message.split("\n")[0]}`)
.filter((x: string) => {
const lower = x.toLowerCase()
return (
!lower.includes("chore:") &&
!lower.includes("ci:") &&
!lower.includes("docs:")
)
})
.join("\n")
if (!dry)
await $`gh release create v${version} --title "v${version}" --notes ${notes} ./dist/*.zip`
// AUR package
const pkgbuildTemplate = await Bun.file("./script/PKGBUILD.template").text()
const pkgbuild = pkgbuildTemplate
.replace("{{VERSION}}", version.split("-")[0])
.replace(
"{{ARM64_URL}}",
`https://github.com/sst/opencode/releases/download/v${version}/opencode-linux-arm64.zip`,
)
.replace(
"{{ARM64_SHA}}",
await $`sha256sum ./dist/opencode-linux-arm64.zip | cut -d' ' -f1`
.text()
.then((x) => x.trim()),
)
.replace(
"{{X64_URL}}",
`https://github.com/sst/opencode/releases/download/v${version}/opencode-linux-x64.zip`,
)
.replace(
"{{X64_SHA}}",
await $`sha256sum ./dist/opencode-linux-x64.zip | cut -d' ' -f1`
.text()
.then((x) => x.trim()),
)
await $`rm -rf ./dist/aur-opencode-bin`
const gitEnv: Record<string, string> = process.env["AUR_KEY"]
? { GIT_SSH_COMMAND: `ssh -i ${process.env["AUR_KEY"]}` }
: {}
await $`git clone ssh://aur@aur.archlinux.org/opencode-bin.git ./dist/aur-opencode-bin`.env(
gitEnv,
)
await Bun.file("./dist/aur-opencode-bin/PKGBUILD").write(pkgbuild)
await $`cd ./dist/aur-opencode-bin && makepkg --printsrcinfo > .SRCINFO`
await $`cd ./dist/aur-opencode-bin && git add PKGBUILD .SRCINFO`.env(gitEnv)
await $`cd ./dist/aur-opencode-bin && git commit -m "Update to v${version}"`.env(
gitEnv,
)
if (!dry) await $`cd ./dist/aur-opencode-bin && git push`.env(gitEnv)
}
-73
View File
@@ -1,73 +0,0 @@
#!/usr/bin/env bun
import { $ } from "bun"
import pkg from "../package.json"
const dry = process.argv.includes("--dry")
const version = `0.0.0-${new Date().toISOString().slice(0, 16).replace(/[-:T]/g, "")}`
const GOARCH: Record<string, string> = {
arm64: "arm64",
x64: "amd64",
}
const targets = [
["linux", "arm64"],
["linux", "x64"],
["darwin", "x64"],
["darwin", "arm64"],
["windows", "x64"],
]
await $`rm -rf dist`
const optionalDependencies: Record<string, string> = {}
for (const [os, arch] of targets) {
console.log(`building ${os}-${arch}`)
const name = `${pkg.name}-${os}-${arch}`
await $`mkdir -p dist/${name}/bin`
await $`GOOS=${os} GOARCH=${GOARCH[arch]} go build -ldflags="-s -w -X main.Version=${version}" -o ../opencode/dist/${name}/bin/tui ../tui/cmd/opencode/main.go`.cwd(
"../tui",
)
await $`bun build --define OPENCODE_VERSION="'${version}'" --compile --minify --target=bun-${os}-${arch} --outfile=dist/${name}/bin/opencode ./src/index.ts ./dist/${name}/bin/tui`
await $`rm -rf ./dist/${name}/bin/tui`
await Bun.file(`dist/${name}/package.json`).write(
JSON.stringify(
{
name,
version,
os: [os === "windows" ? "win32" : os],
cpu: [arch],
},
null,
2,
),
)
if (!dry) await $`cd dist/${name} && npm publish --access public --tag latest`
optionalDependencies[name] = version
}
await $`mkdir -p ./dist/${pkg.name}`
await $`cp -r ./bin ./dist/${pkg.name}/bin`
await $`cp ./script/postinstall.js ./dist/${pkg.name}/postinstall.js`
await Bun.file(`./dist/${pkg.name}/package.json`).write(
JSON.stringify(
{
name: pkg.name + "-ai",
bin: {
[pkg.name]: `./bin/${pkg.name}`,
},
scripts: {
postinstall: "node ./postinstall.js",
},
version,
optionalDependencies,
},
null,
2,
),
)
if (!dry)
await $`cd ./dist/${pkg.name} && npm publish --access public --tag latest`
+8 -7
View File
@@ -7,17 +7,12 @@ export namespace BunProc {
cmd: string[],
options?: Bun.SpawnOptions.OptionsObject<any, any, any>,
) {
const root =
process.argv0 !== "bun" && false
? path.resolve(process.cwd(), process.argv0)
: "bun"
log.info("running", {
cmd: [root, ...cmd],
cmd: [which(), ...cmd],
options,
})
const result = Bun.spawn([root, ...cmd], {
const result = Bun.spawn([which(), ...cmd], {
...options,
argv0: "bun",
env: {
...process.env,
...options?.env,
@@ -31,4 +26,10 @@ export namespace BunProc {
}
return result
}
export function which() {
return process.argv0 !== "bun"
? path.resolve(process.cwd(), process.argv0)
: "bun"
}
}
+2 -6
View File
@@ -3,6 +3,7 @@ import type { App } from "../app/app"
import path from "path"
import { Global } from "../global"
import { Log } from "../util/log"
import { BunProc } from "../bun"
export namespace LSPServer {
const log = Log.create({ service: "lsp.server" })
@@ -37,15 +38,10 @@ export namespace LSPServer {
app.path.cwd,
).catch(() => {})
if (!tsserver) return
const root =
process.argv0 !== "bun" && false
? path.resolve(process.cwd(), process.argv0)
: "bun"
const proc = spawn(
root,
BunProc.which(),
["x", "typescript-language-server", "--stdio"],
{
argv0: "bun",
env: {
...process.env,
BUN_BE_BUN: "1",
+5 -2
View File
@@ -259,11 +259,14 @@ export namespace Provider {
}
}
const priority = ["claude-sonnet-4", "gemini-2.5-pro-preview", "codex-mini"]
const priority = ["gemini-2.5-pro-preview", "codex-mini", "claude-sonnet-4"]
export function sort(models: Model[]) {
return sortBy(
models,
[(model) => priority.indexOf(model.id), "desc"],
[
(model) => priority.findIndex((filter) => model.id.includes(filter)),
"desc",
],
[(model) => (model.id.includes("latest") ? 0 : 1), "asc"],
[(model) => model.id, "desc"],
)
+1 -1
View File
@@ -283,7 +283,7 @@ export namespace Session {
}
msgs.push(system)
generateText({
maxOutputTokens: 80,
maxOutputTokens: 20,
messages: convertToModelMessages([
{
role: "system",
@@ -484,6 +484,9 @@ func renderArgs(args *map[string]any, titleKey string) string {
title := ""
parts := []string{}
for key, value := range *args {
if value == nil {
continue
}
if key == "filePath" || key == "path" {
value = relative(value.(string))
}
+24 -7
View File
@@ -167,6 +167,8 @@ export function getDiagnostics(
): string[] {
const result: string[] = []
if (diagnosticsByFile === undefined) return result
for (const diags of Object.values(diagnosticsByFile)) {
for (const d of diags) {
// Only keep diagnostics explicitly marked as Error (severity === 1)
@@ -1395,6 +1397,7 @@ export default function Share(props: {
part().toolInvocation.toolCallId
],
)
const hasError = metadata()?.error
const args = part().toolInvocation.args
const filePath = args.filePath
const diagnostics = createMemo(() =>
@@ -1429,13 +1432,27 @@ export default function Share(props: {
<span data-element-label>Edit</span>
<b>{filePath}</b>
</span>
<div data-part-tool-edit>
<DiffView
class={styles["diff-code-block"]}
diff={metadata()?.diff}
lang={getFileType(filePath)}
/>
</div>
<Switch>
<Match when={hasError}>
<div data-part-tool-result>
<TextPart
expand
data-size="sm"
data-color="dimmed"
text={metadata()?.message}
/>
</div>
</Match>
<Match when={false}>
<div data-part-tool-edit>
<DiffView
class={styles["diff-code-block"]}
diff={metadata()?.diff}
lang={getFileType(filePath)}
/>
</div>
</Match>
</Switch>
<Show when={diagnostics().length > 0}>
<TextPart
data-size="sm"
@@ -12,8 +12,11 @@
margin-bottom: 1rem;
}
ul,
ol {
list-style-position: inside;
padding-left: 0.75rem;
}
ul {
padding-left: 1.5rem;
}