mirror of
https://github.com/anomalyco/opencode.git
synced 2026-08-03 08:46:15 -04:00
Compare commits
37 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 33d8bfc937 | |||
| f2343a6794 | |||
| bab000eeb5 | |||
| 8e674ae053 | |||
| 6a4f4009d5 | |||
| 5e79b95927 | |||
| a7a2bbb497 | |||
| 6e93d14bdb | |||
| f29f284b3e | |||
| b1b8f6cf71 | |||
| 4c3336bbe7 | |||
| 354ac0b493 | |||
| 1d159c6858 | |||
| d70639b256 | |||
| e4a92f0084 | |||
| fdf5a70a27 | |||
| f71da42520 | |||
| f6bdeb9e3a | |||
| 2400354bab | |||
| db348c46cc | |||
| 49567fe61a | |||
| e5b3f796e4 | |||
| a9700c8773 | |||
| 26cf5e003e | |||
| 742cf10dee | |||
| 7664453f94 | |||
| 460672aa93 | |||
| b4e4fd9807 | |||
| 34bdfd0937 | |||
| 84591ca8ad | |||
| fd4d0c5c0b | |||
| 9f5db46911 | |||
| 755ddbb223 | |||
| 701d470d01 | |||
| 1d9058d26b | |||
| 39e2a5f595 | |||
| f862ab6722 |
@@ -80,8 +80,9 @@ jobs:
|
||||
GITHUB_TOKEN: ${{ secrets.SST_GITHUB_TOKEN }}
|
||||
NPM_CONFIG_PROVENANCE: false
|
||||
outputs:
|
||||
releaseId: ${{ steps.publish.outputs.releaseId }}
|
||||
tagName: ${{ steps.publish.outputs.tagName }}
|
||||
release: ${{ steps.publish.outputs.release }}
|
||||
tag: ${{ steps.publish.outputs.tag }}
|
||||
version: ${{ steps.publish.outputs.version }}
|
||||
|
||||
publish-tauri:
|
||||
needs: publish
|
||||
@@ -103,7 +104,7 @@ jobs:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
ref: ${{ needs.publish.outputs.tagName }}
|
||||
ref: ${{ needs.publish.outputs.tag }}
|
||||
|
||||
- uses: apple-actions/import-codesign-certs@v2
|
||||
if: ${{ runner.os == 'macOS' }}
|
||||
@@ -146,20 +147,18 @@ jobs:
|
||||
shared-key: ${{ matrix.settings.target }}
|
||||
|
||||
- name: Prepare
|
||||
if: inputs.bump || inputs.version
|
||||
run: |
|
||||
cd packages/tauri
|
||||
bun ./scripts/prepare.ts
|
||||
env:
|
||||
OPENCODE_BUMP: ${{ inputs.bump }}
|
||||
OPENCODE_VERSION: ${{ inputs.version }}
|
||||
OPENCODE_CHANNEL: latest
|
||||
OPENCODE_VERSION: ${{ needs.publish.outputs.version }}
|
||||
NPM_CONFIG_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
GITHUB_TOKEN: ${{ secrets.SST_GITHUB_TOKEN }}
|
||||
AUR_KEY: ${{ secrets.AUR_KEY }}
|
||||
OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }}
|
||||
RUST_TARGET: ${{ matrix.settings.target }}
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
OPENCODE_RELEASE_TAG: ${{ needs.publish.outputs.tagName }}
|
||||
|
||||
# Fixes AppImage build issues, can be removed when https://github.com/tauri-apps/tauri/pull/12491 is released
|
||||
- name: Install tauri-cli from portable appimage branch
|
||||
@@ -189,8 +188,8 @@ jobs:
|
||||
tauriScript: ${{ (contains(matrix.settings.host, 'ubuntu') && 'cargo tauri') || '' }}
|
||||
args: --target ${{ matrix.settings.target }} --config src-tauri/tauri.prod.conf.json
|
||||
updaterJsonPreferNsis: true
|
||||
releaseId: ${{ needs.publish.outputs.releaseId }}
|
||||
tagName: ${{ needs.publish.outputs.tagName }}
|
||||
releaseId: ${{ needs.publish.outputs.release }}
|
||||
tagName: ${{ needs.publish.outputs.tag }}
|
||||
releaseAssetNamePattern: opencode-desktop-[platform]-[arch][ext]
|
||||
releaseDraft: true
|
||||
|
||||
@@ -198,13 +197,13 @@ jobs:
|
||||
needs:
|
||||
- publish
|
||||
- publish-tauri
|
||||
if: needs.publish.outputs.tagName
|
||||
if: needs.publish.outputs.tag
|
||||
runs-on: blacksmith-4vcpu-ubuntu-2404
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
ref: ${{ needs.publish.outputs.tagName }}
|
||||
ref: ${{ needs.publish.outputs.tag }}
|
||||
|
||||
- uses: ./.github/actions/setup-bun
|
||||
|
||||
@@ -221,8 +220,6 @@ jobs:
|
||||
|
||||
- run: ./script/publish-complete.ts
|
||||
env:
|
||||
OPENCODE_BUMP: ${{ inputs.bump }}
|
||||
OPENCODE_VERSION: ${{ inputs.version }}
|
||||
OPENCODE_VERSION: ${{ needs.publish.outputs.version }}
|
||||
AUR_KEY: ${{ secrets.AUR_KEY }}
|
||||
GITHUB_TOKEN: ${{ secrets.SST_GITHUB_TOKEN }}
|
||||
OPENCODE_RELEASE_TAG: ${{ needs.publish.outputs.tagName }}
|
||||
|
||||
@@ -175,3 +175,4 @@
|
||||
| 2025-12-17 | 1,151,067 (+30,590) | 1,097,661 (+19,639) | 2,248,728 (+50,229) |
|
||||
| 2025-12-18 | 1,178,658 (+27,591) | 1,113,418 (+15,757) | 2,292,076 (+43,348) |
|
||||
| 2025-12-19 | 1,203,485 (+24,827) | 1,129,698 (+16,280) | 2,333,183 (+41,107) |
|
||||
| 2025-12-20 | 1,223,000 (+19,515) | 1,146,258 (+16,560) | 2,369,258 (+36,075) |
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
},
|
||||
"packages/console/app": {
|
||||
"name": "@opencode-ai/console-app",
|
||||
"version": "1.0.170",
|
||||
"version": "1.0.179",
|
||||
"dependencies": {
|
||||
"@cloudflare/vite-plugin": "1.15.2",
|
||||
"@ibm/plex": "6.4.1",
|
||||
@@ -48,7 +48,7 @@
|
||||
},
|
||||
"packages/console/core": {
|
||||
"name": "@opencode-ai/console-core",
|
||||
"version": "1.0.170",
|
||||
"version": "1.0.179",
|
||||
"dependencies": {
|
||||
"@aws-sdk/client-sts": "3.782.0",
|
||||
"@jsx-email/render": "1.1.1",
|
||||
@@ -75,7 +75,7 @@
|
||||
},
|
||||
"packages/console/function": {
|
||||
"name": "@opencode-ai/console-function",
|
||||
"version": "1.0.170",
|
||||
"version": "1.0.179",
|
||||
"dependencies": {
|
||||
"@ai-sdk/anthropic": "2.0.0",
|
||||
"@ai-sdk/openai": "2.0.2",
|
||||
@@ -99,7 +99,7 @@
|
||||
},
|
||||
"packages/console/mail": {
|
||||
"name": "@opencode-ai/console-mail",
|
||||
"version": "1.0.170",
|
||||
"version": "1.0.179",
|
||||
"dependencies": {
|
||||
"@jsx-email/all": "2.2.3",
|
||||
"@jsx-email/cli": "1.4.3",
|
||||
@@ -123,7 +123,7 @@
|
||||
},
|
||||
"packages/desktop": {
|
||||
"name": "@opencode-ai/desktop",
|
||||
"version": "1.0.170",
|
||||
"version": "1.0.179",
|
||||
"dependencies": {
|
||||
"@kobalte/core": "catalog:",
|
||||
"@opencode-ai/sdk": "workspace:*",
|
||||
@@ -171,7 +171,7 @@
|
||||
},
|
||||
"packages/enterprise": {
|
||||
"name": "@opencode-ai/enterprise",
|
||||
"version": "1.0.170",
|
||||
"version": "1.0.179",
|
||||
"dependencies": {
|
||||
"@opencode-ai/ui": "workspace:*",
|
||||
"@opencode-ai/util": "workspace:*",
|
||||
@@ -200,7 +200,7 @@
|
||||
},
|
||||
"packages/function": {
|
||||
"name": "@opencode-ai/function",
|
||||
"version": "1.0.170",
|
||||
"version": "1.0.179",
|
||||
"dependencies": {
|
||||
"@octokit/auth-app": "8.0.1",
|
||||
"@octokit/rest": "catalog:",
|
||||
@@ -216,7 +216,7 @@
|
||||
},
|
||||
"packages/opencode": {
|
||||
"name": "opencode",
|
||||
"version": "1.0.170",
|
||||
"version": "1.0.179",
|
||||
"bin": {
|
||||
"opencode": "./bin/opencode",
|
||||
},
|
||||
@@ -308,7 +308,7 @@
|
||||
},
|
||||
"packages/plugin": {
|
||||
"name": "@opencode-ai/plugin",
|
||||
"version": "1.0.170",
|
||||
"version": "1.0.179",
|
||||
"dependencies": {
|
||||
"@opencode-ai/sdk": "workspace:*",
|
||||
"zod": "catalog:",
|
||||
@@ -328,7 +328,7 @@
|
||||
},
|
||||
"packages/sdk/js": {
|
||||
"name": "@opencode-ai/sdk",
|
||||
"version": "1.0.170",
|
||||
"version": "1.0.179",
|
||||
"devDependencies": {
|
||||
"@hey-api/openapi-ts": "0.88.1",
|
||||
"@tsconfig/node22": "catalog:",
|
||||
@@ -339,7 +339,7 @@
|
||||
},
|
||||
"packages/slack": {
|
||||
"name": "@opencode-ai/slack",
|
||||
"version": "1.0.170",
|
||||
"version": "1.0.179",
|
||||
"dependencies": {
|
||||
"@opencode-ai/sdk": "workspace:*",
|
||||
"@slack/bolt": "^3.17.1",
|
||||
@@ -352,7 +352,7 @@
|
||||
},
|
||||
"packages/tauri": {
|
||||
"name": "@opencode-ai/tauri",
|
||||
"version": "1.0.170",
|
||||
"version": "1.0.179",
|
||||
"dependencies": {
|
||||
"@opencode-ai/desktop": "workspace:*",
|
||||
"@solid-primitives/storage": "catalog:",
|
||||
@@ -379,7 +379,7 @@
|
||||
},
|
||||
"packages/ui": {
|
||||
"name": "@opencode-ai/ui",
|
||||
"version": "1.0.170",
|
||||
"version": "1.0.179",
|
||||
"dependencies": {
|
||||
"@kobalte/core": "catalog:",
|
||||
"@opencode-ai/sdk": "workspace:*",
|
||||
@@ -414,7 +414,7 @@
|
||||
},
|
||||
"packages/util": {
|
||||
"name": "@opencode-ai/util",
|
||||
"version": "1.0.170",
|
||||
"version": "1.0.179",
|
||||
"dependencies": {
|
||||
"zod": "catalog:",
|
||||
},
|
||||
@@ -425,7 +425,7 @@
|
||||
},
|
||||
"packages/web": {
|
||||
"name": "@opencode-ai/web",
|
||||
"version": "1.0.170",
|
||||
"version": "1.0.179",
|
||||
"dependencies": {
|
||||
"@astrojs/cloudflare": "12.6.3",
|
||||
"@astrojs/markdown-remark": "6.3.1",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@opencode-ai/console-app",
|
||||
"version": "1.0.170",
|
||||
"version": "1.0.179",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"typecheck": "tsgo --noEmit",
|
||||
|
||||
@@ -202,6 +202,14 @@ export function IconZai(props: JSX.SvgSVGAttributes<SVGSVGElement>) {
|
||||
)
|
||||
}
|
||||
|
||||
export function IconMiniMax(props: JSX.SvgSVGAttributes<SVGSVGElement>) {
|
||||
return (
|
||||
<svg {...props} fill="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M16.278 2c1.156 0 2.093.927 2.093 2.07v12.501a.74.74 0 00.744.709.74.74 0 00.743-.709V9.099a2.06 2.06 0 012.071-2.049A2.06 2.06 0 0124 9.1v6.561a.649.649 0 01-.652.645.649.649 0 01-.653-.645V9.1a.762.762 0 00-.766-.758.762.762 0 00-.766.758v7.472a2.037 2.037 0 01-2.048 2.026 2.037 2.037 0 01-2.048-2.026v-12.5a.785.785 0 00-.788-.753.785.785 0 00-.789.752l-.001 15.904A2.037 2.037 0 0113.441 22a2.037 2.037 0 01-2.048-2.026V18.04c0-.356.292-.645.652-.645.36 0 .652.289.652.645v1.934c0 .263.142.506.372.638.23.131.514.131.744 0a.734.734 0 00.372-.638V4.07c0-1.143.937-2.07 2.093-2.07zm-5.674 0c1.156 0 2.093.927 2.093 2.07v11.523a.648.648 0 01-.652.645.648.648 0 01-.652-.645V4.07a.785.785 0 00-.789-.78.785.785 0 00-.789.78v14.013a2.06 2.06 0 01-2.07 2.048 2.06 2.06 0 01-2.071-2.048V9.1a.762.762 0 00-.766-.758.762.762 0 00-.766.758v3.8a2.06 2.06 0 01-2.071 2.049A2.06 2.06 0 010 12.9v-1.378c0-.357.292-.646.652-.646.36 0 .653.29.653.646V12.9c0 .418.343.757.766.757s.766-.339.766-.757V9.099a2.06 2.06 0 012.07-2.048 2.06 2.06 0 012.071 2.048v8.984c0 .419.343.758.767.758.423 0 .766-.339.766-.758V4.07c0-1.143.937-2.07 2.093-2.07z" />
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export function IconGemini(props: JSX.SvgSVGAttributes<SVGSVGElement>) {
|
||||
return (
|
||||
<svg {...props} viewBox="0 0 50 50" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
IconAlibaba,
|
||||
IconAnthropic,
|
||||
IconGemini,
|
||||
IconMiniMax,
|
||||
IconMoonshotAI,
|
||||
IconOpenAI,
|
||||
IconStealth,
|
||||
@@ -23,6 +24,7 @@ const getModelLab = (modelId: string) => {
|
||||
if (modelId.startsWith("kimi")) return "Moonshot AI"
|
||||
if (modelId.startsWith("glm")) return "Z.ai"
|
||||
if (modelId.startsWith("qwen")) return "Alibaba"
|
||||
if (modelId.startsWith("minimax")) return "MiniMax"
|
||||
if (modelId.startsWith("grok")) return "xAI"
|
||||
return "Stealth"
|
||||
}
|
||||
@@ -35,7 +37,7 @@ const getModelsInfo = query(async (workspaceID: string) => {
|
||||
.filter(([id, _model]) => !["claude-3-5-haiku"].includes(id))
|
||||
.filter(([id, _model]) => !id.startsWith("alpha-"))
|
||||
.sort(([idA, modelA], [idB, modelB]) => {
|
||||
const priority = ["big-pickle", "grok", "claude", "gpt", "gemini"]
|
||||
const priority = ["big-pickle", "minimax", "grok", "claude", "gpt", "gemini"]
|
||||
const getPriority = (id: string) => {
|
||||
const index = priority.findIndex((p) => id.startsWith(p))
|
||||
return index === -1 ? Infinity : index
|
||||
@@ -129,6 +131,8 @@ export function ModelSection() {
|
||||
return <IconAlibaba width={16} height={16} />
|
||||
case "xAI":
|
||||
return <IconXai width={16} height={16} />
|
||||
case "MiniMax":
|
||||
return <IconMiniMax width={16} height={16} />
|
||||
default:
|
||||
return <IconStealth width={16} height={16} />
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"name": "@opencode-ai/console-core",
|
||||
"version": "1.0.170",
|
||||
"version": "1.0.179",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@opencode-ai/console-function",
|
||||
"version": "1.0.170",
|
||||
"version": "1.0.179",
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@opencode-ai/console-mail",
|
||||
"version": "1.0.170",
|
||||
"version": "1.0.179",
|
||||
"dependencies": {
|
||||
"@jsx-email/all": "2.2.3",
|
||||
"@jsx-email/cli": "1.4.3",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@opencode-ai/desktop",
|
||||
"version": "1.0.170",
|
||||
"version": "1.0.179",
|
||||
"description": "",
|
||||
"type": "module",
|
||||
"exports": {
|
||||
|
||||
@@ -8,8 +8,7 @@ export const { use: useGlobalSDK, provider: GlobalSDKProvider } = createSimpleCo
|
||||
init: (props: { url: string }) => {
|
||||
const eventSdk = createOpencodeClient({
|
||||
baseUrl: props.url,
|
||||
signal: AbortSignal.timeout(1000 * 60 * 10),
|
||||
throwOnError: true,
|
||||
// signal: AbortSignal.timeout(1000 * 60 * 10),
|
||||
})
|
||||
const emitter = createGlobalEmitter<{
|
||||
[key: string]: Event
|
||||
|
||||
@@ -18,6 +18,7 @@ import {
|
||||
} from "@opencode-ai/sdk/v2/client"
|
||||
import { createStore, produce, reconcile } from "solid-js/store"
|
||||
import { Binary } from "@opencode-ai/util/binary"
|
||||
import { retry } from "@opencode-ai/util/retry"
|
||||
import { useGlobalSDK } from "./global-sdk"
|
||||
import { ErrorPage, type InitError } from "../pages/error"
|
||||
import { createContext, useContext, onMount, type ParentProps, Switch, Match } from "solid-js"
|
||||
@@ -145,7 +146,7 @@ function createGlobalSync() {
|
||||
changes: () => sdk.file.status().then((x) => setStore("changes", x.data!)),
|
||||
node: () => sdk.file.list({ path: "/" }).then((x) => setStore("node", x.data!)),
|
||||
}
|
||||
await Promise.all(Object.values(load).map((p) => p().catch((e) => setGlobalStore("error", e))))
|
||||
await Promise.all(Object.values(load).map((p) => retry(p).catch((e) => setGlobalStore("error", e))))
|
||||
.then(() => setStore("ready", true))
|
||||
.catch((e) => setGlobalStore("error", e))
|
||||
}
|
||||
@@ -295,21 +296,29 @@ function createGlobalSync() {
|
||||
|
||||
async function bootstrap() {
|
||||
return Promise.all([
|
||||
globalSDK.client.path.get().then((x) => {
|
||||
setGlobalStore("path", x.data!)
|
||||
}),
|
||||
globalSDK.client.project.list().then(async (x) => {
|
||||
setGlobalStore(
|
||||
"project",
|
||||
x.data!.filter((p) => !p.worktree.includes("opencode-test")).sort((a, b) => a.id.localeCompare(b.id)),
|
||||
)
|
||||
}),
|
||||
globalSDK.client.provider.list().then((x) => {
|
||||
setGlobalStore("provider", x.data ?? {})
|
||||
}),
|
||||
globalSDK.client.provider.auth().then((x) => {
|
||||
setGlobalStore("provider_auth", x.data ?? {})
|
||||
}),
|
||||
retry(() =>
|
||||
globalSDK.client.path.get().then((x) => {
|
||||
setGlobalStore("path", x.data!)
|
||||
}),
|
||||
),
|
||||
retry(() =>
|
||||
globalSDK.client.project.list().then(async (x) => {
|
||||
setGlobalStore(
|
||||
"project",
|
||||
x.data!.filter((p) => !p.worktree.includes("opencode-test")).sort((a, b) => a.id.localeCompare(b.id)),
|
||||
)
|
||||
}),
|
||||
),
|
||||
retry(() =>
|
||||
globalSDK.client.provider.list().then((x) => {
|
||||
setGlobalStore("provider", x.data ?? {})
|
||||
}),
|
||||
),
|
||||
retry(() =>
|
||||
globalSDK.client.provider.auth().then((x) => {
|
||||
setGlobalStore("provider_auth", x.data ?? {})
|
||||
}),
|
||||
),
|
||||
])
|
||||
.then(() => setGlobalStore("ready", true))
|
||||
.catch((e) => setGlobalStore("error", e))
|
||||
|
||||
@@ -27,6 +27,8 @@ type SessionTabs = {
|
||||
all: string[]
|
||||
}
|
||||
|
||||
export type LocalProject = Partial<Project> & { worktree: string; expanded: boolean }
|
||||
|
||||
export const { use: useLayout, provider: LayoutProvider } = createSimpleContext({
|
||||
name: "Layout",
|
||||
init: () => {
|
||||
@@ -61,21 +63,22 @@ export const { use: useLayout, provider: LayoutProvider } = createSimpleContext(
|
||||
|
||||
function enrich(project: { worktree: string; expanded: boolean }) {
|
||||
const metadata = globalSync.data.project.find((x) => x.worktree === project.worktree)
|
||||
if (!metadata) return []
|
||||
return [
|
||||
{
|
||||
...project,
|
||||
...metadata,
|
||||
...(metadata ?? {}),
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
function colorize(project: Project & { expanded: boolean }) {
|
||||
function colorize(project: LocalProject) {
|
||||
if (project.icon?.color) return project
|
||||
const color = pickAvailableColor()
|
||||
usedColors.add(color)
|
||||
project.icon = { ...project.icon, color }
|
||||
globalSdk.client.project.update({ projectID: project.id, icon: { color } })
|
||||
if (project.id) {
|
||||
globalSdk.client.project.update({ projectID: project.id, icon: { color } })
|
||||
}
|
||||
return project
|
||||
}
|
||||
|
||||
@@ -95,7 +98,9 @@ export const { use: useLayout, provider: LayoutProvider } = createSimpleContext(
|
||||
projects: {
|
||||
list,
|
||||
open(directory: string) {
|
||||
if (store.projects.find((x) => x.worktree === directory)) return
|
||||
if (store.projects.find((x) => x.worktree === directory)) {
|
||||
return
|
||||
}
|
||||
globalSync.project.loadSessions(directory)
|
||||
setStore("projects", (x) => [{ worktree: directory, expanded: true }, ...x])
|
||||
},
|
||||
|
||||
@@ -337,6 +337,7 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({
|
||||
const load = async (path: string) => {
|
||||
const relativePath = relative(path)
|
||||
await sdk.client.file.read({ path: relativePath }).then((x) => {
|
||||
if (!store.node[relativePath]) return
|
||||
setStore(
|
||||
"node",
|
||||
relativePath,
|
||||
@@ -425,7 +426,7 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({
|
||||
init,
|
||||
expand(path: string) {
|
||||
setStore("node", path, "expanded", true)
|
||||
if (store.node[path].loaded) return
|
||||
if (store.node[path]?.loaded) return
|
||||
setStore("node", path, "loaded", true)
|
||||
list(path)
|
||||
},
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { produce } from "solid-js/store"
|
||||
import { createMemo } from "solid-js"
|
||||
import { Binary } from "@opencode-ai/util/binary"
|
||||
import { retry } from "@opencode-ai/util/retry"
|
||||
import { createSimpleContext } from "@opencode-ai/ui/context"
|
||||
import { useGlobalSync } from "./global-sync"
|
||||
import { useSDK } from "./sdk"
|
||||
@@ -61,10 +62,10 @@ export const { use: useSync, provider: SyncProvider } = createSimpleContext({
|
||||
},
|
||||
async sync(sessionID: string, _isRetry = false) {
|
||||
const [session, messages, todo, diff] = await Promise.all([
|
||||
sdk.client.session.get({ sessionID }, { throwOnError: true }),
|
||||
sdk.client.session.messages({ sessionID, limit: 100 }),
|
||||
sdk.client.session.todo({ sessionID }),
|
||||
sdk.client.session.diff({ sessionID }),
|
||||
retry(() => sdk.client.session.get({ sessionID })),
|
||||
retry(() => sdk.client.session.messages({ sessionID, limit: 100 })),
|
||||
retry(() => sdk.client.session.todo({ sessionID })),
|
||||
retry(() => sdk.client.session.diff({ sessionID })),
|
||||
])
|
||||
setStore(
|
||||
produce((draft) => {
|
||||
|
||||
@@ -1,18 +1,7 @@
|
||||
import {
|
||||
createEffect,
|
||||
createMemo,
|
||||
createSignal,
|
||||
For,
|
||||
Match,
|
||||
onMount,
|
||||
ParentProps,
|
||||
Show,
|
||||
Switch,
|
||||
type JSX,
|
||||
} from "solid-js"
|
||||
import { createEffect, createMemo, For, Match, onMount, ParentProps, Show, Switch, type JSX } from "solid-js"
|
||||
import { DateTime } from "luxon"
|
||||
import { A, useNavigate, useParams } from "@solidjs/router"
|
||||
import { useLayout, getAvatarColors } from "@/context/layout"
|
||||
import { useLayout, getAvatarColors, LocalProject } from "@/context/layout"
|
||||
import { useGlobalSync } from "@/context/global-sync"
|
||||
import { base64Decode, base64Encode } from "@opencode-ai/util/encode"
|
||||
import { Avatar } from "@opencode-ai/ui/avatar"
|
||||
@@ -26,7 +15,7 @@ import { DiffChanges } from "@opencode-ai/ui/diff-changes"
|
||||
import { Spinner } from "@opencode-ai/ui/spinner"
|
||||
import { getFilename } from "@opencode-ai/util/path"
|
||||
import { DropdownMenu } from "@opencode-ai/ui/dropdown-menu"
|
||||
import { Session, Project } from "@opencode-ai/sdk/v2/client"
|
||||
import { Session } from "@opencode-ai/sdk/v2/client"
|
||||
import { usePlatform } from "@/context/platform"
|
||||
import { createStore, produce } from "solid-js/store"
|
||||
import {
|
||||
@@ -348,7 +337,7 @@ export default function Layout(props: ParentProps) {
|
||||
}
|
||||
|
||||
const ProjectAvatar = (props: {
|
||||
project: Project
|
||||
project: LocalProject
|
||||
class?: string
|
||||
expandable?: boolean
|
||||
notify?: boolean
|
||||
@@ -391,7 +380,7 @@ export default function Layout(props: ParentProps) {
|
||||
)
|
||||
}
|
||||
|
||||
const ProjectVisual = (props: { project: Project & { expanded: boolean }; class?: string }): JSX.Element => {
|
||||
const ProjectVisual = (props: { project: LocalProject; class?: string }): JSX.Element => {
|
||||
const name = createMemo(() => getFilename(props.project.worktree))
|
||||
const current = createMemo(() => base64Decode(params.dir ?? ""))
|
||||
return (
|
||||
@@ -427,7 +416,7 @@ export default function Layout(props: ParentProps) {
|
||||
const SessionItem = (props: {
|
||||
session: Session
|
||||
slug: string
|
||||
project: Project
|
||||
project: LocalProject
|
||||
depth?: number
|
||||
childrenMap: Map<string, Session[]>
|
||||
}): JSX.Element => {
|
||||
@@ -517,7 +506,7 @@ export default function Layout(props: ParentProps) {
|
||||
)
|
||||
}
|
||||
|
||||
const SortableProject = (props: { project: Project & { expanded: boolean } }): JSX.Element => {
|
||||
const SortableProject = (props: { project: LocalProject }): JSX.Element => {
|
||||
const sortable = createSortable(props.project.worktree)
|
||||
const slug = createMemo(() => base64Encode(props.project.worktree))
|
||||
const name = createMemo(() => getFilename(props.project.worktree))
|
||||
@@ -542,13 +531,21 @@ export default function Layout(props: ParentProps) {
|
||||
setProjectStore("limit", (limit) => limit + 5)
|
||||
await globalSync.project.loadSessions(props.project.worktree)
|
||||
}
|
||||
const [expanded, setExpanded] = createSignal(true)
|
||||
const handleOpenChange = (open: boolean) => {
|
||||
if (open) layout.projects.expand(props.project.worktree)
|
||||
else layout.projects.collapse(props.project.worktree)
|
||||
}
|
||||
return (
|
||||
// @ts-ignore
|
||||
<div use:sortable classList={{ "opacity-30": sortable.isActiveDraggable }}>
|
||||
<Switch>
|
||||
<Match when={layout.sidebar.opened()}>
|
||||
<Collapsible variant="ghost" defaultOpen class="gap-2 shrink-0" onOpenChange={setExpanded}>
|
||||
<Collapsible
|
||||
variant="ghost"
|
||||
open={props.project.expanded}
|
||||
class="gap-2 shrink-0"
|
||||
onOpenChange={handleOpenChange}
|
||||
>
|
||||
<Button
|
||||
as={"div"}
|
||||
variant="ghost"
|
||||
@@ -559,7 +556,7 @@ export default function Layout(props: ParentProps) {
|
||||
project={props.project}
|
||||
class="group-hover/session:hidden"
|
||||
expandable
|
||||
notify={!expanded()}
|
||||
notify={!props.project.expanded}
|
||||
/>
|
||||
<span class="truncate text-14-medium text-text-strong">{name()}</span>
|
||||
</Collapsible.Trigger>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@opencode-ai/enterprise",
|
||||
"version": "1.0.170",
|
||||
"version": "1.0.179",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
id = "opencode"
|
||||
name = "OpenCode"
|
||||
description = "The open source coding agent."
|
||||
version = "1.0.170"
|
||||
version = "1.0.179"
|
||||
schema_version = 1
|
||||
authors = ["Anomaly"]
|
||||
repository = "https://github.com/sst/opencode"
|
||||
@@ -11,26 +11,26 @@ name = "OpenCode"
|
||||
icon = "./icons/opencode.svg"
|
||||
|
||||
[agent_servers.opencode.targets.darwin-aarch64]
|
||||
archive = "https://github.com/sst/opencode/releases/download/v1.0.170/opencode-darwin-arm64.zip"
|
||||
archive = "https://github.com/sst/opencode/releases/download/v1.0.179/opencode-darwin-arm64.zip"
|
||||
cmd = "./opencode"
|
||||
args = ["acp"]
|
||||
|
||||
[agent_servers.opencode.targets.darwin-x86_64]
|
||||
archive = "https://github.com/sst/opencode/releases/download/v1.0.170/opencode-darwin-x64.zip"
|
||||
archive = "https://github.com/sst/opencode/releases/download/v1.0.179/opencode-darwin-x64.zip"
|
||||
cmd = "./opencode"
|
||||
args = ["acp"]
|
||||
|
||||
[agent_servers.opencode.targets.linux-aarch64]
|
||||
archive = "https://github.com/sst/opencode/releases/download/v1.0.170/opencode-linux-arm64.tar.gz"
|
||||
archive = "https://github.com/sst/opencode/releases/download/v1.0.179/opencode-linux-arm64.tar.gz"
|
||||
cmd = "./opencode"
|
||||
args = ["acp"]
|
||||
|
||||
[agent_servers.opencode.targets.linux-x86_64]
|
||||
archive = "https://github.com/sst/opencode/releases/download/v1.0.170/opencode-linux-x64.tar.gz"
|
||||
archive = "https://github.com/sst/opencode/releases/download/v1.0.179/opencode-linux-x64.tar.gz"
|
||||
cmd = "./opencode"
|
||||
args = ["acp"]
|
||||
|
||||
[agent_servers.opencode.targets.windows-x86_64]
|
||||
archive = "https://github.com/sst/opencode/releases/download/v1.0.170/opencode-windows-x64.zip"
|
||||
archive = "https://github.com/sst/opencode/releases/download/v1.0.179/opencode-windows-x64.zip"
|
||||
cmd = "./opencode.exe"
|
||||
args = ["acp"]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@opencode-ai/function",
|
||||
"version": "1.0.170",
|
||||
"version": "1.0.179",
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"version": "1.0.170",
|
||||
"version": "1.0.179",
|
||||
"name": "opencode",
|
||||
"type": "module",
|
||||
"private": true,
|
||||
|
||||
@@ -53,6 +53,15 @@ for (const tag of tags) {
|
||||
}
|
||||
|
||||
if (!Script.preview) {
|
||||
// Create archives for GitHub release
|
||||
for (const key of Object.keys(binaries)) {
|
||||
if (key.includes("linux")) {
|
||||
await $`tar -czf ../../${key}.tar.gz *`.cwd(`dist/${key}/bin`)
|
||||
} else {
|
||||
await $`zip -r ../../${key}.zip *`.cwd(`dist/${key}/bin`)
|
||||
}
|
||||
}
|
||||
|
||||
const image = "ghcr.io/sst/opencode"
|
||||
const platforms = "linux/amd64,linux/arm64"
|
||||
const tags = [`${image}:${Script.version}`, `${image}:latest`]
|
||||
|
||||
@@ -10,6 +10,7 @@ export type HomeRoute = {
|
||||
export type SessionRoute = {
|
||||
type: "session"
|
||||
sessionID: string
|
||||
initialPrompt?: PromptInfo
|
||||
}
|
||||
|
||||
export type Route = HomeRoute | SessionRoute
|
||||
|
||||
@@ -6,6 +6,7 @@ import { Locale } from "@/util/locale"
|
||||
import { useSDK } from "@tui/context/sdk"
|
||||
import { useRoute } from "@tui/context/route"
|
||||
import { useDialog } from "../../ui/dialog"
|
||||
import type { PromptInfo } from "@tui/component/prompt/history"
|
||||
|
||||
export function DialogForkFromTimeline(props: { sessionID: string; onMove: (messageID: string) => void }) {
|
||||
const sync = useSync()
|
||||
@@ -35,9 +36,21 @@ export function DialogForkFromTimeline(props: { sessionID: string; onMove: (mess
|
||||
sessionID: props.sessionID,
|
||||
messageID: message.id,
|
||||
})
|
||||
const parts = sync.data.part[message.id] ?? []
|
||||
const initialPrompt = parts.reduce(
|
||||
(agg, part) => {
|
||||
if (part.type === "text") {
|
||||
if (!part.synthetic) agg.input += part.text
|
||||
}
|
||||
if (part.type === "file") agg.parts.push(part)
|
||||
return agg
|
||||
},
|
||||
{ input: "", parts: [] as PromptInfo["parts"] },
|
||||
)
|
||||
route.navigate({
|
||||
sessionID: forked.data!.id,
|
||||
type: "session",
|
||||
initialPrompt,
|
||||
})
|
||||
dialog.clear()
|
||||
},
|
||||
|
||||
@@ -80,9 +80,25 @@ export function DialogMessage(props: {
|
||||
sessionID: props.sessionID,
|
||||
messageID: props.messageID,
|
||||
})
|
||||
const initialPrompt = (() => {
|
||||
const msg = message()
|
||||
if (!msg) return undefined
|
||||
const parts = sync.data.part[msg.id]
|
||||
return parts.reduce(
|
||||
(agg, part) => {
|
||||
if (part.type === "text") {
|
||||
if (!part.synthetic) agg.input += part.text
|
||||
}
|
||||
if (part.type === "file") agg.parts.push(part)
|
||||
return agg
|
||||
},
|
||||
{ input: "", parts: [] as PromptInfo["parts"] },
|
||||
)
|
||||
})()
|
||||
route.navigate({
|
||||
sessionID: result.data!.id,
|
||||
type: "session",
|
||||
initialPrompt,
|
||||
})
|
||||
dialog.clear()
|
||||
},
|
||||
|
||||
@@ -168,6 +168,13 @@ export function Session() {
|
||||
const toast = useToast()
|
||||
const sdk = useSDK()
|
||||
|
||||
// Handle initial prompt from fork
|
||||
createEffect(() => {
|
||||
if (route.initialPrompt && prompt) {
|
||||
prompt.set(route.initialPrompt)
|
||||
}
|
||||
})
|
||||
|
||||
// Auto-navigate to whichever session currently needs permission input
|
||||
createEffect(() => {
|
||||
const currentSession = session()
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { BusEvent } from "@/bus/bus-event"
|
||||
import { Bus } from "@/bus"
|
||||
import z from "zod"
|
||||
import { $ } from "bun"
|
||||
import type { BunFile } from "bun"
|
||||
@@ -74,6 +73,7 @@ export namespace File {
|
||||
|
||||
async function shouldEncode(file: BunFile): Promise<boolean> {
|
||||
const type = file.type?.toLowerCase()
|
||||
log.info("shouldEncode", { type })
|
||||
if (!type) return false
|
||||
|
||||
if (type.startsWith("text/")) return false
|
||||
@@ -93,7 +93,6 @@ export namespace File {
|
||||
"bzip",
|
||||
"compressed",
|
||||
"binary",
|
||||
"stream",
|
||||
"pdf",
|
||||
"msword",
|
||||
"powerpoint",
|
||||
@@ -290,9 +289,11 @@ export namespace File {
|
||||
}
|
||||
const resolved = dir ? path.join(Instance.directory, dir) : Instance.directory
|
||||
const nodes: Node[] = []
|
||||
for (const entry of await fs.promises.readdir(resolved, {
|
||||
withFileTypes: true,
|
||||
})) {
|
||||
for (const entry of await fs.promises
|
||||
.readdir(resolved, {
|
||||
withFileTypes: true,
|
||||
})
|
||||
.catch(() => [])) {
|
||||
if (exclude.includes(entry.name)) continue
|
||||
const fullPath = path.join(resolved, entry.name)
|
||||
const relativePath = path.relative(Instance.directory, fullPath)
|
||||
|
||||
@@ -1188,6 +1188,79 @@ export namespace Server {
|
||||
return c.json(message)
|
||||
},
|
||||
)
|
||||
.delete(
|
||||
"/session/:sessionID/message/:messageID/part/:partID",
|
||||
describeRoute({
|
||||
description: "Delete a part from a message",
|
||||
operationId: "part.delete",
|
||||
responses: {
|
||||
200: {
|
||||
description: "Successfully deleted part",
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: resolver(z.boolean()),
|
||||
},
|
||||
},
|
||||
},
|
||||
...errors(400, 404),
|
||||
},
|
||||
}),
|
||||
validator(
|
||||
"param",
|
||||
z.object({
|
||||
sessionID: z.string().meta({ description: "Session ID" }),
|
||||
messageID: z.string().meta({ description: "Message ID" }),
|
||||
partID: z.string().meta({ description: "Part ID" }),
|
||||
}),
|
||||
),
|
||||
async (c) => {
|
||||
const params = c.req.valid("param")
|
||||
await Session.removePart({
|
||||
sessionID: params.sessionID,
|
||||
messageID: params.messageID,
|
||||
partID: params.partID,
|
||||
})
|
||||
return c.json(true)
|
||||
},
|
||||
)
|
||||
.patch(
|
||||
"/session/:sessionID/message/:messageID/part/:partID",
|
||||
describeRoute({
|
||||
description: "Update a part in a message",
|
||||
operationId: "part.update",
|
||||
responses: {
|
||||
200: {
|
||||
description: "Successfully updated part",
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: resolver(MessageV2.Part),
|
||||
},
|
||||
},
|
||||
},
|
||||
...errors(400, 404),
|
||||
},
|
||||
}),
|
||||
validator(
|
||||
"param",
|
||||
z.object({
|
||||
sessionID: z.string().meta({ description: "Session ID" }),
|
||||
messageID: z.string().meta({ description: "Message ID" }),
|
||||
partID: z.string().meta({ description: "Part ID" }),
|
||||
}),
|
||||
),
|
||||
validator("json", MessageV2.Part),
|
||||
async (c) => {
|
||||
const params = c.req.valid("param")
|
||||
const body = c.req.valid("json")
|
||||
if (body.id !== params.partID || body.messageID !== params.messageID || body.sessionID !== params.sessionID) {
|
||||
throw new Error(
|
||||
`Part mismatch: body.id='${body.id}' vs partID='${params.partID}', body.messageID='${body.messageID}' vs messageID='${params.messageID}', body.sessionID='${body.sessionID}' vs sessionID='${params.sessionID}'`,
|
||||
)
|
||||
}
|
||||
const part = await Session.updatePart(body)
|
||||
return c.json(part)
|
||||
},
|
||||
)
|
||||
.post(
|
||||
"/session/:sessionID/message",
|
||||
describeRoute({
|
||||
|
||||
@@ -339,6 +339,23 @@ export namespace Session {
|
||||
},
|
||||
)
|
||||
|
||||
export const removePart = fn(
|
||||
z.object({
|
||||
sessionID: Identifier.schema("session"),
|
||||
messageID: Identifier.schema("message"),
|
||||
partID: Identifier.schema("part"),
|
||||
}),
|
||||
async (input) => {
|
||||
await Storage.remove(["part", input.messageID, input.partID])
|
||||
Bus.publish(MessageV2.Event.PartRemoved, {
|
||||
sessionID: input.sessionID,
|
||||
messageID: input.messageID,
|
||||
partID: input.partID,
|
||||
})
|
||||
return input.partID
|
||||
},
|
||||
)
|
||||
|
||||
const UpdatePartInput = z.union([
|
||||
MessageV2.Part,
|
||||
z.object({
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"name": "@opencode-ai/plugin",
|
||||
"version": "1.0.170",
|
||||
"version": "1.0.179",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"typecheck": "tsgo --noEmit",
|
||||
@@ -24,4 +24,4 @@
|
||||
"typescript": "catalog:",
|
||||
"@typescript/native-preview": "catalog:"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"name": "@opencode-ai/sdk",
|
||||
"version": "1.0.170",
|
||||
"version": "1.0.179",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"typecheck": "tsgo --noEmit",
|
||||
@@ -29,4 +29,4 @@
|
||||
"publishConfig": {
|
||||
"directory": "dist"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -47,6 +47,11 @@ import type {
|
||||
McpLocalConfig,
|
||||
McpRemoteConfig,
|
||||
McpStatusResponses,
|
||||
Part as Part2,
|
||||
PartDeleteErrors,
|
||||
PartDeleteResponses,
|
||||
PartUpdateErrors,
|
||||
PartUpdateResponses,
|
||||
PathGetResponses,
|
||||
PermissionRespondErrors,
|
||||
PermissionRespondResponses,
|
||||
@@ -1486,6 +1491,79 @@ export class Session extends HeyApiClient {
|
||||
}
|
||||
}
|
||||
|
||||
export class Part extends HeyApiClient {
|
||||
/**
|
||||
* Delete a part from a message
|
||||
*/
|
||||
public delete<ThrowOnError extends boolean = false>(
|
||||
parameters: {
|
||||
sessionID: string
|
||||
messageID: string
|
||||
partID: string
|
||||
directory?: string
|
||||
},
|
||||
options?: Options<never, ThrowOnError>,
|
||||
) {
|
||||
const params = buildClientParams(
|
||||
[parameters],
|
||||
[
|
||||
{
|
||||
args: [
|
||||
{ in: "path", key: "sessionID" },
|
||||
{ in: "path", key: "messageID" },
|
||||
{ in: "path", key: "partID" },
|
||||
{ in: "query", key: "directory" },
|
||||
],
|
||||
},
|
||||
],
|
||||
)
|
||||
return (options?.client ?? this.client).delete<PartDeleteResponses, PartDeleteErrors, ThrowOnError>({
|
||||
url: "/session/{sessionID}/message/{messageID}/part/{partID}",
|
||||
...options,
|
||||
...params,
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a part in a message
|
||||
*/
|
||||
public update<ThrowOnError extends boolean = false>(
|
||||
parameters: {
|
||||
sessionID: string
|
||||
messageID: string
|
||||
partID: string
|
||||
directory?: string
|
||||
part?: Part2
|
||||
},
|
||||
options?: Options<never, ThrowOnError>,
|
||||
) {
|
||||
const params = buildClientParams(
|
||||
[parameters],
|
||||
[
|
||||
{
|
||||
args: [
|
||||
{ in: "path", key: "sessionID" },
|
||||
{ in: "path", key: "messageID" },
|
||||
{ in: "path", key: "partID" },
|
||||
{ in: "query", key: "directory" },
|
||||
{ key: "part", map: "body" },
|
||||
],
|
||||
},
|
||||
],
|
||||
)
|
||||
return (options?.client ?? this.client).patch<PartUpdateResponses, PartUpdateErrors, ThrowOnError>({
|
||||
url: "/session/{sessionID}/message/{messageID}/part/{partID}",
|
||||
...options,
|
||||
...params,
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
...options?.headers,
|
||||
...params.headers,
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export class Permission extends HeyApiClient {
|
||||
/**
|
||||
* Respond to permission
|
||||
@@ -2588,6 +2666,8 @@ export class OpencodeClient extends HeyApiClient {
|
||||
|
||||
session = new Session({ client: this.client })
|
||||
|
||||
part = new Part({ client: this.client })
|
||||
|
||||
permission = new Permission({ client: this.client })
|
||||
|
||||
command = new Command({ client: this.client })
|
||||
|
||||
@@ -2915,6 +2915,94 @@ export type SessionMessageResponses = {
|
||||
|
||||
export type SessionMessageResponse = SessionMessageResponses[keyof SessionMessageResponses]
|
||||
|
||||
export type PartDeleteData = {
|
||||
body?: never
|
||||
path: {
|
||||
/**
|
||||
* Session ID
|
||||
*/
|
||||
sessionID: string
|
||||
/**
|
||||
* Message ID
|
||||
*/
|
||||
messageID: string
|
||||
/**
|
||||
* Part ID
|
||||
*/
|
||||
partID: string
|
||||
}
|
||||
query?: {
|
||||
directory?: string
|
||||
}
|
||||
url: "/session/{sessionID}/message/{messageID}/part/{partID}"
|
||||
}
|
||||
|
||||
export type PartDeleteErrors = {
|
||||
/**
|
||||
* Bad request
|
||||
*/
|
||||
400: BadRequestError
|
||||
/**
|
||||
* Not found
|
||||
*/
|
||||
404: NotFoundError
|
||||
}
|
||||
|
||||
export type PartDeleteError = PartDeleteErrors[keyof PartDeleteErrors]
|
||||
|
||||
export type PartDeleteResponses = {
|
||||
/**
|
||||
* Successfully deleted part
|
||||
*/
|
||||
200: boolean
|
||||
}
|
||||
|
||||
export type PartDeleteResponse = PartDeleteResponses[keyof PartDeleteResponses]
|
||||
|
||||
export type PartUpdateData = {
|
||||
body?: Part
|
||||
path: {
|
||||
/**
|
||||
* Session ID
|
||||
*/
|
||||
sessionID: string
|
||||
/**
|
||||
* Message ID
|
||||
*/
|
||||
messageID: string
|
||||
/**
|
||||
* Part ID
|
||||
*/
|
||||
partID: string
|
||||
}
|
||||
query?: {
|
||||
directory?: string
|
||||
}
|
||||
url: "/session/{sessionID}/message/{messageID}/part/{partID}"
|
||||
}
|
||||
|
||||
export type PartUpdateErrors = {
|
||||
/**
|
||||
* Bad request
|
||||
*/
|
||||
400: BadRequestError
|
||||
/**
|
||||
* Not found
|
||||
*/
|
||||
404: NotFoundError
|
||||
}
|
||||
|
||||
export type PartUpdateError = PartUpdateErrors[keyof PartUpdateErrors]
|
||||
|
||||
export type PartUpdateResponses = {
|
||||
/**
|
||||
* Successfully updated part
|
||||
*/
|
||||
200: Part
|
||||
}
|
||||
|
||||
export type PartUpdateResponse = PartUpdateResponses[keyof PartUpdateResponses]
|
||||
|
||||
export type SessionPromptAsyncData = {
|
||||
body?: {
|
||||
messageID?: string
|
||||
|
||||
@@ -2126,6 +2126,173 @@
|
||||
]
|
||||
}
|
||||
},
|
||||
"/session/{sessionID}/message/{messageID}/part/{partID}": {
|
||||
"delete": {
|
||||
"operationId": "part.delete",
|
||||
"parameters": [
|
||||
{
|
||||
"in": "query",
|
||||
"name": "directory",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
{
|
||||
"in": "path",
|
||||
"name": "sessionID",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
},
|
||||
"required": true,
|
||||
"description": "Session ID"
|
||||
},
|
||||
{
|
||||
"in": "path",
|
||||
"name": "messageID",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
},
|
||||
"required": true,
|
||||
"description": "Message ID"
|
||||
},
|
||||
{
|
||||
"in": "path",
|
||||
"name": "partID",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
},
|
||||
"required": true,
|
||||
"description": "Part ID"
|
||||
}
|
||||
],
|
||||
"description": "Delete a part from a message",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Successfully deleted part",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad request",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/BadRequestError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "Not found",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/NotFoundError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"x-codeSamples": [
|
||||
{
|
||||
"lang": "js",
|
||||
"source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.part.delete({\n ...\n})"
|
||||
}
|
||||
]
|
||||
},
|
||||
"patch": {
|
||||
"operationId": "part.update",
|
||||
"parameters": [
|
||||
{
|
||||
"in": "query",
|
||||
"name": "directory",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
{
|
||||
"in": "path",
|
||||
"name": "sessionID",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
},
|
||||
"required": true,
|
||||
"description": "Session ID"
|
||||
},
|
||||
{
|
||||
"in": "path",
|
||||
"name": "messageID",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
},
|
||||
"required": true,
|
||||
"description": "Message ID"
|
||||
},
|
||||
{
|
||||
"in": "path",
|
||||
"name": "partID",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
},
|
||||
"required": true,
|
||||
"description": "Part ID"
|
||||
}
|
||||
],
|
||||
"description": "Update a part in a message",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Successfully updated part",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/Part"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad request",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/BadRequestError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "Not found",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/NotFoundError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/Part"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"x-codeSamples": [
|
||||
{
|
||||
"lang": "js",
|
||||
"source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.part.update({\n ...\n})"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"/session/{sessionID}/prompt_async": {
|
||||
"post": {
|
||||
"operationId": "session.prompt_async",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@opencode-ai/slack",
|
||||
"version": "1.0.170",
|
||||
"version": "1.0.179",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "bun run src/index.ts",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@opencode-ai/tauri",
|
||||
"private": true,
|
||||
"version": "1.0.170",
|
||||
"version": "1.0.179",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"typecheck": "tsgo -b",
|
||||
|
||||
@@ -3,13 +3,14 @@
|
||||
import { $ } from "bun"
|
||||
|
||||
import { copyBinaryToSidecarFolder, getCurrentSidecar } from "./utils"
|
||||
import { Script } from "@opencode-ai/script"
|
||||
|
||||
const sidecarConfig = getCurrentSidecar()
|
||||
|
||||
const dir = "src-tauri/target/opencode-binaries"
|
||||
|
||||
await $`mkdir -p ${dir}`
|
||||
await $`gh release download ${Bun.env.OPENCODE_RELEASE_TAG} --pattern ${sidecarConfig.ocBinary}.${sidecarConfig.assetExt} --repo sst/opencode --skip-existing --dir ${dir}`
|
||||
await $`gh release download v${Script.version} --pattern ${sidecarConfig.ocBinary}.${sidecarConfig.assetExt} --repo sst/opencode --skip-existing --dir ${dir}`
|
||||
|
||||
if (sidecarConfig.assetExt === "tar.gz") {
|
||||
await $`tar -xvzf ${dir}/${sidecarConfig.ocBinary}.${sidecarConfig.assetExt} -C ${dir}`
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@opencode-ai/ui",
|
||||
"version": "1.0.170",
|
||||
"version": "1.0.179",
|
||||
"type": "module",
|
||||
"exports": {
|
||||
"./*": "./src/components/*.tsx",
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
[data-component="tool-trigger"] {
|
||||
content-visibility: auto;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { children, For, Match, Show, Switch, type JSX } from "solid-js"
|
||||
import { For, Match, Show, Switch, type JSX } from "solid-js"
|
||||
import { Collapsible } from "./collapsible"
|
||||
import { Icon, IconProps } from "./icon"
|
||||
|
||||
@@ -27,7 +27,6 @@ export interface BasicToolProps {
|
||||
}
|
||||
|
||||
export function BasicTool(props: BasicToolProps) {
|
||||
const resolved = children(() => props.children)
|
||||
return (
|
||||
<Collapsible defaultOpen={props.defaultOpen}>
|
||||
<Collapsible.Trigger>
|
||||
@@ -81,13 +80,13 @@ export function BasicTool(props: BasicToolProps) {
|
||||
</Switch>
|
||||
</div>
|
||||
</div>
|
||||
<Show when={resolved() && !props.hideDetails}>
|
||||
<Show when={props.children && !props.hideDetails}>
|
||||
<Collapsible.Arrow />
|
||||
</Show>
|
||||
</div>
|
||||
</Collapsible.Trigger>
|
||||
<Show when={resolved() && !props.hideDetails}>
|
||||
<Collapsible.Content>{resolved()}</Collapsible.Content>
|
||||
<Show when={props.children && !props.hideDetails}>
|
||||
<Collapsible.Content>{props.children}</Collapsible.Content>
|
||||
</Show>
|
||||
</Collapsible>
|
||||
)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Checkbox as Kobalte } from "@kobalte/core/checkbox"
|
||||
import { children, Show, splitProps } from "solid-js"
|
||||
import { Show, splitProps } from "solid-js"
|
||||
import type { ComponentProps, JSX, ParentProps } from "solid-js"
|
||||
|
||||
export interface CheckboxProps extends ParentProps<ComponentProps<typeof Kobalte>> {
|
||||
@@ -10,7 +10,6 @@ export interface CheckboxProps extends ParentProps<ComponentProps<typeof Kobalte
|
||||
|
||||
export function Checkbox(props: CheckboxProps) {
|
||||
const [local, others] = splitProps(props, ["children", "class", "label", "hideLabel", "description", "icon"])
|
||||
const resolved = children(() => local.children)
|
||||
return (
|
||||
<Kobalte {...others} data-component="checkbox">
|
||||
<Kobalte.Input data-slot="checkbox-checkbox-input" />
|
||||
@@ -29,9 +28,9 @@ export function Checkbox(props: CheckboxProps) {
|
||||
</Kobalte.Indicator>
|
||||
</Kobalte.Control>
|
||||
<div data-slot="checkbox-checkbox-content">
|
||||
<Show when={resolved()}>
|
||||
<Show when={props.children}>
|
||||
<Kobalte.Label data-slot="checkbox-checkbox-label" classList={{ "sr-only": local.hideLabel }}>
|
||||
{resolved()}
|
||||
{props.children}
|
||||
</Kobalte.Label>
|
||||
</Show>
|
||||
<Show when={local.description}>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
[data-component="code"] {
|
||||
content-visibility: auto;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
[data-component="diff"] {
|
||||
contain: content;
|
||||
content-visibility: auto;
|
||||
|
||||
[data-slot="diff-hunk-separator-line-number"] {
|
||||
position: sticky;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
[data-component="assistant-message"] {
|
||||
content-visibility: auto;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
@@ -463,13 +463,13 @@ ToolRegistry.register({
|
||||
subtitle: props.input.description,
|
||||
}}
|
||||
>
|
||||
<Show when={props.output}>
|
||||
{(output) => (
|
||||
<div data-component="tool-output" data-scrollable>
|
||||
<Markdown text={output()} />
|
||||
</div>
|
||||
)}
|
||||
</Show>
|
||||
{/* <Show when={false && props.output}> */}
|
||||
{/* {(output) => ( */}
|
||||
{/* <div data-component="tool-output" data-scrollable> */}
|
||||
{/* <Markdown text={output()} /> */}
|
||||
{/* </div> */}
|
||||
{/* )} */}
|
||||
{/* </Show> */}
|
||||
</BasicTool>
|
||||
)
|
||||
},
|
||||
|
||||
@@ -25,7 +25,7 @@ export interface SessionReviewProps {
|
||||
export const SessionReview = (props: SessionReviewProps) => {
|
||||
const diffComponent = useDiffComponent()
|
||||
const [store, setStore] = createStore({
|
||||
open: props.diffs.map((d) => d.file),
|
||||
open: props.diffs.length > 10 ? [] : props.diffs.map((d) => d.file),
|
||||
})
|
||||
|
||||
const handleChange = (open: string[]) => {
|
||||
@@ -78,7 +78,7 @@ export const SessionReview = (props: SessionReviewProps) => {
|
||||
<Accordion multiple value={store.open} onChange={handleChange}>
|
||||
<For each={props.diffs}>
|
||||
{(diff) => (
|
||||
<Accordion.Item forceMount value={diff.file} data-slot="session-review-accordion-item">
|
||||
<Accordion.Item value={diff.file} data-slot="session-review-accordion-item">
|
||||
<StickyAccordionHeader>
|
||||
<Accordion.Trigger>
|
||||
<div data-slot="session-review-trigger-content">
|
||||
|
||||
@@ -499,7 +499,7 @@ export function SessionTurn(
|
||||
)
|
||||
return (
|
||||
<Switch>
|
||||
<Match when={response() && lastTextPart()?.id === last()?.id}>
|
||||
<Match when={!summary() && response() && lastTextPart()?.id === last()?.id}>
|
||||
<Message
|
||||
message={assistantMessage}
|
||||
parts={parts().filter((p) => p?.id !== last()?.id)}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Switch as Kobalte } from "@kobalte/core/switch"
|
||||
import { children, Show, splitProps } from "solid-js"
|
||||
import { Show, splitProps } from "solid-js"
|
||||
import type { ComponentProps, ParentProps } from "solid-js"
|
||||
|
||||
export interface SwitchProps extends ParentProps<ComponentProps<typeof Kobalte>> {
|
||||
@@ -9,13 +9,12 @@ export interface SwitchProps extends ParentProps<ComponentProps<typeof Kobalte>>
|
||||
|
||||
export function Switch(props: SwitchProps) {
|
||||
const [local, others] = splitProps(props, ["children", "class", "hideLabel", "description"])
|
||||
const resolved = children(() => local.children)
|
||||
return (
|
||||
<Kobalte {...others} data-component="switch">
|
||||
<Kobalte.Input data-slot="switch-input" />
|
||||
<Show when={resolved()}>
|
||||
<Show when={local.children}>
|
||||
<Kobalte.Label data-slot="switch-label" classList={{ "sr-only": local.hideLabel }}>
|
||||
{resolved()}
|
||||
{local.children}
|
||||
</Kobalte.Label>
|
||||
</Show>
|
||||
<Show when={local.description}>
|
||||
|
||||
@@ -24,6 +24,13 @@ type Data = {
|
||||
export const { use: useData, provider: DataProvider } = createSimpleContext({
|
||||
name: "Data",
|
||||
init: (props: { data: Data; directory: string }) => {
|
||||
return { store: props.data, directory: props.directory }
|
||||
return {
|
||||
get store() {
|
||||
return props.data
|
||||
},
|
||||
get directory() {
|
||||
return props.directory
|
||||
},
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@opencode-ai/util",
|
||||
"version": "1.0.170",
|
||||
"version": "1.0.179",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"exports": {
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
export interface RetryOptions {
|
||||
attempts?: number
|
||||
delay?: number
|
||||
factor?: number
|
||||
maxDelay?: number
|
||||
retryIf?: (error: unknown) => boolean
|
||||
}
|
||||
|
||||
const TRANSIENT_MESSAGES = [
|
||||
"load failed",
|
||||
"network connection was lost",
|
||||
"network request failed",
|
||||
"failed to fetch",
|
||||
"econnreset",
|
||||
"econnrefused",
|
||||
"etimedout",
|
||||
"socket hang up",
|
||||
]
|
||||
|
||||
function isTransientError(error: unknown): boolean {
|
||||
if (!error) return false
|
||||
const message = String(error instanceof Error ? error.message : error).toLowerCase()
|
||||
return TRANSIENT_MESSAGES.some((m) => message.includes(m))
|
||||
}
|
||||
|
||||
export async function retry<T>(fn: () => Promise<T>, options: RetryOptions = {}): Promise<T> {
|
||||
const { attempts = 3, delay = 500, factor = 2, maxDelay = 10000, retryIf = isTransientError } = options
|
||||
|
||||
let lastError: unknown
|
||||
for (let attempt = 0; attempt < attempts; attempt++) {
|
||||
try {
|
||||
return await fn()
|
||||
} catch (error) {
|
||||
lastError = error
|
||||
if (attempt === attempts - 1 || !retryIf(error)) throw error
|
||||
const wait = Math.min(delay * Math.pow(factor, attempt), maxDelay)
|
||||
await new Promise((resolve) => setTimeout(resolve, wait))
|
||||
}
|
||||
}
|
||||
throw lastError
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@opencode-ai/web",
|
||||
"type": "module",
|
||||
"version": "1.0.170",
|
||||
"version": "1.0.179",
|
||||
"scripts": {
|
||||
"dev": "astro dev",
|
||||
"dev:remote": "VITE_API_URL=https://api.opencode.ai astro dev",
|
||||
|
||||
@@ -77,6 +77,7 @@ You can also access our models through the following API endpoints.
|
||||
| Claude Haiku 3.5 | claude-3-5-haiku | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` |
|
||||
| Claude Opus 4.5 | claude-opus-4-5 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` |
|
||||
| Claude Opus 4.1 | claude-opus-4-1 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` |
|
||||
| MiniMax M2.1 | minimax-m2.1 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` |
|
||||
| Gemini 3 Pro | gemini-3-pro | `https://opencode.ai/zen/v1/models/gemini-3-pro` | `@ai-sdk/google` |
|
||||
| Gemini 3 Flash | gemini-3-flash | `https://opencode.ai/zen/v1/models/gemini-3-flash` | `@ai-sdk/google` |
|
||||
| GLM 4.6 | glm-4.6 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` |
|
||||
@@ -109,6 +110,7 @@ We support a pay-as-you-go model. Below are the prices **per 1M tokens**.
|
||||
| Model | Input | Output | Cached Read | Cached Write |
|
||||
| --------------------------------- | ------ | ------ | ----------- | ------------ |
|
||||
| Big Pickle | Free | Free | Free | - |
|
||||
| MiniMax M2.1 | Free | Free | Free | - |
|
||||
| Grok Code Fast 1 | Free | Free | Free | - |
|
||||
| GLM 4.6 | $0.60 | $2.20 | $0.10 | - |
|
||||
| Kimi K2 | $0.40 | $2.50 | - | - |
|
||||
@@ -142,6 +144,7 @@ Credit card fees are passed along at cost; we don't charge anything beyond that.
|
||||
The free models:
|
||||
|
||||
- Grok Code Fast 1 is currently free on OpenCode for a limited time. The xAI team is using this time to collect feedback and improve Grok Code.
|
||||
- MiniMax M2.1 is currently free on OpenCode for a limited time. The MiniMax team is using this time to collect feedback and improve M2.1.
|
||||
- Big Pickle is a stealth model that's free on OpenCode for a limited time. The team is using this time to collect feedback and improve the model.
|
||||
|
||||
<a href={email}>Contact us</a> if you have any questions.
|
||||
@@ -153,6 +156,7 @@ The free models:
|
||||
All our models are hosted in the US. Our providers follow a zero-retention policy and do not use your data for model training, with the following exceptions:
|
||||
|
||||
- Grok Code Fast 1: During its free period, collected data may be used to improve Grok Code.
|
||||
- MiniMax M2.1: During its free period, collected data may be used to improve M2.1.
|
||||
- Big Pickle: During its free period, collected data may be used to improve the model.
|
||||
- OpenAI APIs: Requests are retained for 30 days in accordance with [OpenAI's Data Policies](https://platform.openai.com/docs/guides/your-data).
|
||||
- Anthropic APIs: Requests are retained for 30 days in accordance with [Anthropic's Data Policies](https://docs.anthropic.com/en/docs/claude-code/data-usage).
|
||||
|
||||
Regular → Executable
+1
-1
@@ -4,7 +4,7 @@ import { Script } from "@opencode-ai/script"
|
||||
import { $ } from "bun"
|
||||
|
||||
if (!Script.preview) {
|
||||
await $`gh release edit ${process.env.OPENCODE_RELEASE_TAG} --draft=false`
|
||||
await $`gh release edit v${Script.version} --draft=false`
|
||||
}
|
||||
|
||||
await $`bun install`
|
||||
|
||||
+22
-16
@@ -27,6 +27,20 @@ if (!Script.preview) {
|
||||
const opencode = await createOpencode()
|
||||
const session = await opencode.client.session.create()
|
||||
console.log("generating changelog since " + previous)
|
||||
|
||||
const team = [
|
||||
"actions-user",
|
||||
"opencode",
|
||||
"rekram1-node",
|
||||
"thdxr",
|
||||
"kommander",
|
||||
"jayair",
|
||||
"fwang",
|
||||
"adamdotdevin",
|
||||
"iamdavidhill",
|
||||
"opencode-agent[bot]",
|
||||
]
|
||||
|
||||
const raw = await opencode.client.session
|
||||
.prompt({
|
||||
path: {
|
||||
@@ -106,19 +120,6 @@ if (!Script.preview) {
|
||||
console.log("-----------------------------")
|
||||
opencode.server.close()
|
||||
|
||||
// Get contributors
|
||||
const team = [
|
||||
"actions-user",
|
||||
"opencode",
|
||||
"rekram1-node",
|
||||
"thdxr",
|
||||
"kommander",
|
||||
"jayair",
|
||||
"fwang",
|
||||
"adamdotdevin",
|
||||
"iamdavidhill",
|
||||
"opencode-agent[bot]",
|
||||
]
|
||||
const compare =
|
||||
await $`gh api "/repos/sst/opencode/compare/v${previous}...HEAD" --jq '.commits[] | {login: .author.login, message: .commit.message}'`.text()
|
||||
const contributors = new Map<string, string[]>()
|
||||
@@ -180,6 +181,8 @@ await import(`../packages/plugin/script/publish.ts`)
|
||||
const dir = new URL("..", import.meta.url).pathname
|
||||
process.chdir(dir)
|
||||
|
||||
let output = `version=${Script.version}\n`
|
||||
|
||||
if (!Script.preview) {
|
||||
await $`git commit -am "release: v${Script.version}"`
|
||||
await $`git tag v${Script.version}`
|
||||
@@ -189,7 +192,10 @@ if (!Script.preview) {
|
||||
await new Promise((resolve) => setTimeout(resolve, 5_000))
|
||||
await $`gh release create v${Script.version} -d --title "v${Script.version}" --notes ${notes.join("\n") || "No notable changes"} ./packages/opencode/dist/*.zip ./packages/opencode/dist/*.tar.gz`
|
||||
const release = await $`gh release view v${Script.version} --json id,tagName`.json()
|
||||
if (process.env.GITHUB_OUTPUT) {
|
||||
await Bun.write(process.env.GITHUB_OUTPUT, `releaseId=${release.id}\ntagName=${release.tagName}\n`)
|
||||
}
|
||||
output += `release=${release.id}`
|
||||
output += `tag=${release.tagName}`
|
||||
}
|
||||
|
||||
if (process.env.GITHUB_OUTPUT) {
|
||||
await Bun.write(process.env.GITHUB_OUTPUT, output)
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"name": "opencode",
|
||||
"displayName": "opencode",
|
||||
"description": "opencode for VS Code",
|
||||
"version": "1.0.170",
|
||||
"version": "1.0.179",
|
||||
"publisher": "sst-dev",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
Reference in New Issue
Block a user