Compare commits

..

13 Commits

Author SHA1 Message Date
Aiden Cline
d2311bbf81 core: ephemerally wrap queued user messages with reminder to stay on track 2026-01-02 22:40:05 -06:00
Dax Raad
0cf0294787 anomalyco/opencode 2026-01-02 16:09:06 -05:00
Dax
3c41e4e8f1 chore: rename repo references from sst/opencode to anomalyco/opencode (#6687)
Co-authored-by: Github Action <action@github.com>
2026-01-02 16:02:52 -05:00
Matt Silverlock
66bc046503 fix: merge instructions arrays across config files (#6663) 2026-01-02 13:55:40 -06:00
Matt Silverlock
6e68ea034c fix: handle actions/checkout v6 credential storage change (#6667) 2026-01-02 13:54:43 -06:00
Adam
c51fa7cb24 feat: add /compact session command 2026-01-02 12:40:37 -06:00
Adam
a4c67515c9 fix(desktop): tweak window drag region layout 2026-01-02 12:40:36 -06:00
Adam
1d2d710fce fix: relax request timeouts 2026-01-02 12:40:36 -06:00
Aiden Cline
2fd97377f6 test: fix transform test 2026-01-02 12:38:44 -06:00
Aiden Cline
47ebb2973f test: add message-v2 test 2026-01-02 12:28:40 -06:00
Aiden Cline
49d7ccd1db fix: variant for minimal 2026-01-02 12:28:40 -06:00
Aiden Cline
c996f3d847 chore: ensure empty message isnt sent 2026-01-02 12:28:40 -06:00
Mike English
70881b2937 fix: cloudflare-ai-gateway sdk.chat undefined error (#6407) 2026-01-02 11:24:13 -06:00
53 changed files with 810 additions and 108 deletions

View File

@@ -26,7 +26,7 @@ jobs:
- uses: ./.github/actions/setup-bun
- name: Run opencode
uses: sst/opencode/github@latest
uses: anomalyco/opencode/github@latest
env:
OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }}
OPENCODE_PERMISSION: '{"bash": "deny"}'

View File

@@ -14,10 +14,10 @@ However, any UI or core product feature must go through a design review with the
If you are unsure if a PR would be accepted, feel free to ask a maintainer or look for issues with any of the following labels:
- [`help wanted`](https://github.com/sst/opencode/issues?q=is%3Aissue%20state%3Aopen%20label%3Ahelp-wanted)
- [`good first issue`](https://github.com/sst/opencode/issues?q=is%3Aissue%20state%3Aopen%20label%3A%22good%20first%20issue%22)
- [`bug`](https://github.com/sst/opencode/issues?q=is%3Aissue%20state%3Aopen%20label%3Abug)
- [`perf`](https://github.com/sst/opencode/issues?q=is%3Aopen%20is%3Aissue%20label%3A%22perf%22)
- [`help wanted`](https://github.com/anomalyco/opencode/issues?q=is%3Aissue%20state%3Aopen%20label%3Ahelp-wanted)
- [`good first issue`](https://github.com/anomalyco/opencode/issues?q=is%3Aissue%20state%3Aopen%20label%3A%22good%20first%20issue%22)
- [`bug`](https://github.com/anomalyco/opencode/issues?q=is%3Aissue%20state%3Aopen%20label%3Abug)
- [`perf`](https://github.com/anomalyco/opencode/issues?q=is%3Aopen%20is%3Aissue%20label%3A%22perf%22)
> [!NOTE]
> PRs that ignore these guardrails will likely be closed.

View File

@@ -11,7 +11,7 @@
<p align="center">
<a href="https://opencode.ai/discord"><img alt="Discord" src="https://img.shields.io/discord/1391832426048651334?style=flat-square&label=discord" /></a>
<a href="https://www.npmjs.com/package/opencode-ai"><img alt="npm" src="https://img.shields.io/npm/v/opencode-ai?style=flat-square" /></a>
<a href="https://github.com/sst/opencode/actions/workflows/publish.yml"><img alt="Build status" src="https://img.shields.io/github/actions/workflow/status/sst/opencode/publish.yml?style=flat-square&branch=dev" /></a>
<a href="https://github.com/anomalyco/opencode/actions/workflows/publish.yml"><img alt="Build status" src="https://img.shields.io/github/actions/workflow/status/anomalyco/opencode/publish.yml?style=flat-square&branch=dev" /></a>
</p>
[![OpenCode Terminal UI](packages/web/src/assets/lander/screenshot.png)](https://opencode.ai)
@@ -31,7 +31,7 @@ choco install opencode # Windows
brew install opencode # macOS and Linux
paru -S opencode-bin # Arch Linux
mise use -g opencode # Any OS
nix run nixpkgs#opencode # or github:sst/opencode for latest dev branch
nix run nixpkgs#opencode # or github:anomalyco/opencode for latest dev branch
```
> [!TIP]
@@ -39,7 +39,7 @@ nix run nixpkgs#opencode # or github:sst/opencode for latest dev branc
### Desktop App (BETA)
OpenCode is also available as a desktop application. Download directly from the [releases page](https://github.com/sst/opencode/releases) or [opencode.ai/download](https://opencode.ai/download).
OpenCode is also available as a desktop application. Download directly from the [releases page](https://github.com/anomalyco/opencode/releases) or [opencode.ai/download](https://opencode.ai/download).
| Platform | Download |
| --------------------- | ------------------------------------- |

View File

@@ -11,7 +11,7 @@
<p align="center">
<a href="https://opencode.ai/discord"><img alt="Discord" src="https://img.shields.io/discord/1391832426048651334?style=flat-square&label=discord" /></a>
<a href="https://www.npmjs.com/package/opencode-ai"><img alt="npm" src="https://img.shields.io/npm/v/opencode-ai?style=flat-square" /></a>
<a href="https://github.com/sst/opencode/actions/workflows/publish.yml"><img alt="Build status" src="https://img.shields.io/github/actions/workflow/status/sst/opencode/publish.yml?style=flat-square&branch=dev" /></a>
<a href="https://github.com/anomalyco/opencode/actions/workflows/publish.yml"><img alt="Build status" src="https://img.shields.io/github/actions/workflow/status/anomalyco/opencode/publish.yml?style=flat-square&branch=dev" /></a>
</p>
[![OpenCode Terminal UI](packages/web/src/assets/lander/screenshot.png)](https://opencode.ai)
@@ -30,8 +30,8 @@ scoop bucket add extras; scoop install extras/opencode # Windows
choco install opencode # Windows
brew install opencode # macOS 與 Linux
paru -S opencode-bin # Arch Linux
mise use -g github:sst/opencode # 任何作業系統
nix run nixpkgs#opencode # 或使用 github:sst/opencode 以取得最新開發分支
mise use -g github:anomalyco/opencode # 任何作業系統
nix run nixpkgs#opencode # 或使用 github:anomalyco/opencode 以取得最新開發分支
```
> [!TIP]
@@ -39,7 +39,7 @@ nix run nixpkgs#opencode # 或使用 github:sst/opencode 以取得最
### 桌面應用程式 (BETA)
OpenCode 也提供桌面版應用程式。您可以直接從 [發佈頁面 (releases page)](https://github.com/sst/opencode/releases) 或 [opencode.ai/download](https://opencode.ai/download) 下載。
OpenCode 也提供桌面版應用程式。您可以直接從 [發佈頁面 (releases page)](https://github.com/anomalyco/opencode/releases) 或 [opencode.ai/download](https://opencode.ai/download) 下載。
| 平台 | 下載連結 |
| --------------------- | ------------------------------------- |

6
flake.lock generated
View File

@@ -2,11 +2,11 @@
"nodes": {
"nixpkgs": {
"locked": {
"lastModified": 1767242400,
"narHash": "sha256-knFaYjeg7swqG1dljj1hOxfg39zrIy8pfGuicjm9s+o=",
"lastModified": 1767273430,
"narHash": "sha256-kDpoFwQ8GLrPiS3KL+sAwreXrph2KhdXuJzo5+vSLoo=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "c04833a1e584401bb63c1a63ddc51a71e6aa457a",
"rev": "76eec3925eb9bbe193934987d3285473dbcfad50",
"type": "github"
},
"original": {

View File

@@ -87,7 +87,7 @@ This will walk you through installing the GitHub app, creating the workflow, and
fetch-depth: 1
- name: Run opencode
uses: sst/opencode/github@latest
uses: anomalyco/opencode/github@latest
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
with:
@@ -98,7 +98,7 @@ This will walk you through installing the GitHub app, creating the workflow, and
## Support
This is an early release. If you encounter issues or have feedback, please create an issue at https://github.com/sst/opencode/issues.
This is an early release. If you encounter issues or have feedback, please create an issue at https://github.com/anomalyco/opencode/issues.
## Development

View File

@@ -41,7 +41,7 @@ runs:
id: version
shell: bash
run: |
VERSION=$(curl -sf https://api.github.com/repos/sst/opencode/releases/latest | grep -o '"tag_name": *"[^"]*"' | cut -d'"' -f4)
VERSION=$(curl -sf https://api.github.com/repos/anomalyco/opencode/releases/latest | grep -o '"tag_name": *"[^"]*"' | cut -d'"' -f4)
echo "version=${VERSION:-latest}" >> $GITHUB_OUTPUT
- name: Cache opencode

10
install
View File

@@ -147,8 +147,8 @@ INSTALL_DIR=$HOME/.opencode/bin
mkdir -p "$INSTALL_DIR"
if [ -z "$requested_version" ]; then
url="https://github.com/sst/opencode/releases/latest/download/$filename"
specific_version=$(curl -s https://api.github.com/repos/sst/opencode/releases/latest | sed -n 's/.*"tag_name": *"v\([^"]*\)".*/\1/p')
url="https://github.com/anomalyco/opencode/releases/latest/download/$filename"
specific_version=$(curl -s https://api.github.com/repos/anomalyco/opencode/releases/latest | sed -n 's/.*"tag_name": *"v\([^"]*\)".*/\1/p')
if [[ $? -ne 0 || -z "$specific_version" ]]; then
echo -e "${RED}Failed to fetch version information${NC}"
@@ -157,14 +157,14 @@ if [ -z "$requested_version" ]; then
else
# Strip leading 'v' if present
requested_version="${requested_version#v}"
url="https://github.com/sst/opencode/releases/download/v${requested_version}/$filename"
url="https://github.com/anomalyco/opencode/releases/download/v${requested_version}/$filename"
specific_version=$requested_version
# Verify the release exists before downloading
http_status=$(curl -sI -o /dev/null -w "%{http_code}" "https://github.com/sst/opencode/releases/tag/v${requested_version}")
http_status=$(curl -sI -o /dev/null -w "%{http_code}" "https://github.com/anomalyco/opencode/releases/tag/v${requested_version}")
if [ "$http_status" = "404" ]; then
echo -e "${RED}Error: Release v${requested_version} not found${NC}"
echo -e "${MUTED}Available releases: https://github.com/sst/opencode/releases${NC}"
echo -e "${MUTED}Available releases: https://github.com/anomalyco/opencode/releases${NC}"
exit 1
fi
fi

View File

@@ -125,7 +125,7 @@ stdenvNoCC.mkDerivation (finalAttrs: {
It combines a TypeScript/JavaScript core with a Go-based TUI
to provide an interactive AI coding experience.
'';
homepage = "https://github.com/sst/opencode";
homepage = "https://github.com/anomalyco/opencode";
license = lib.licenses.mit;
platforms = [
"aarch64-linux"

View File

@@ -76,7 +76,7 @@
},
"repository": {
"type": "git",
"url": "https://github.com/sst/opencode"
"url": "https://github.com/anomalyco/opencode"
},
"license": "MIT",
"prettier": {

View File

@@ -31,7 +31,6 @@ export const { use: useGlobalSDK, provider: GlobalSDKProvider } = createSimpleCo
const platform = usePlatform()
const sdk = createOpencodeClient({
baseUrl: server.url,
signal: AbortSignal.timeout(1000 * 60 * 10),
fetch: platform.fetch,
throwOnError: true,
})

View File

@@ -11,7 +11,6 @@ export const { use: useSDK, provider: SDKProvider } = createSimpleContext({
const globalSDK = useGlobalSDK()
const sdk = createOpencodeClient({
baseUrl: globalSDK.url,
signal: AbortSignal.timeout(1000 * 60 * 10),
fetch: platform.fetch,
directory: props.directory,
throwOnError: true,

View File

@@ -100,7 +100,7 @@ export const { use: useServer, provider: ServerProvider } = createSimpleContext(
const sdk = createOpencodeClient({
baseUrl: url,
fetch: platform.fetch,
signal: AbortSignal.timeout(2000),
signal: AbortSignal.timeout(3000),
})
return sdk.global
.health()

View File

@@ -555,6 +555,31 @@ export default function Page() {
setActiveMessage(priorMsg)
},
},
{
id: "session.compact",
title: "Compact session",
description: "Summarize the session to reduce context size",
category: "Session",
slash: "compact",
disabled: !params.id || visibleUserMessages().length === 0,
onSelect: async () => {
const sessionID = params.id
if (!sessionID) return
const model = local.model.current()
if (!model) {
showToast({
title: "No model selected",
description: "Connect a provider to summarize this session",
})
return
}
await sdk.client.session.summarize({
sessionID,
modelID: model.id,
providerID: model.provider.id,
})
},
},
])
const handleKeyDown = (event: KeyboardEvent) => {

View File

@@ -7,7 +7,7 @@ export const config = {
// GitHub
github: {
repoUrl: "https://github.com/sst/opencode",
repoUrl: "https://github.com/anomalyco/opencode",
starsFormatted: {
compact: "45K",
full: "45,000",

View File

@@ -26,7 +26,7 @@ export default function NotFound() {
<a href="/docs">Docs</a>
</div>
<div data-slot="action">
<a href="https://github.com/sst/opencode">GitHub</a>
<a href="https://github.com/anomalyco/opencode">GitHub</a>
</div>
<div data-slot="action">
<a href="/discord">Discord</a>

View File

@@ -21,7 +21,7 @@ export async function GET({ params: { platform } }: APIEvent) {
const assetName = assetNames[platform]
if (!assetName) return new Response("Not Found", { status: 404 })
const resp = await fetch(`https://github.com/sst/opencode/releases/latest/download/${assetName}`, {
const resp = await fetch(`https://github.com/anomalyco/opencode/releases/latest/download/${assetName}`, {
cf: {
// in case gh releases has rate limits
cacheTtl: 60 * 60 * 24,

View File

@@ -1,6 +1,6 @@
export async function GET() {
const response = await fetch(
"https://raw.githubusercontent.com/sst/opencode/refs/heads/dev/packages/sdk/openapi.json",
"https://raw.githubusercontent.com/anomalyco/opencode/refs/heads/dev/packages/sdk/openapi.json",
)
const json = await response.json()
return json

View File

@@ -151,7 +151,7 @@ export default function Home() {
<a href="https://x.com/opencode">X.com</a>
</div>
<div data-slot="cell">
<a href="https://github.com/sst/opencode">GitHub</a>
<a href="https://github.com/anomalyco/opencode">GitHub</a>
</div>
<div data-slot="cell">
<a href="https://opencode.ai/discord">Discord</a>

View File

@@ -13,7 +13,6 @@
<meta name="theme-color" content="#131010" media="(prefers-color-scheme: dark)" />
<meta property="og:image" content="/social-share.png" />
<meta property="twitter:image" content="/social-share.png" />
<!-- Theme preload script - applies cached theme to avoid FOUC -->
<script id="oc-theme-preload-script">
;(function () {
var themeId = localStorage.getItem("opencode-theme-id")

View File

@@ -20,7 +20,7 @@
"plugins": {
"updater": {
"pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IEYwMDM5Nzg5OUMzOUExMDQKUldRRW9UbWNpWmNEOENYT01CV0lhOXR1UFhpaXJsK1Z3aU9lZnNtNzE0TDROWVMwVW9XQnFOelkK",
"endpoints": ["https://github.com/sst/opencode/releases/latest/download/latest.json"]
"endpoints": ["https://github.com/anomalyco/opencode/releases/latest/download/latest.json"]
}
}
}

View File

@@ -198,7 +198,7 @@ render(() => {
return (
<PlatformProvider value={platform}>
{ostype() === "macos" && (
<div class="bg-background-base border-b border-border-weak-base h-8" data-tauri-drag-region />
<div class="mx-px bg-background-base border-b border-border-weak-base h-8" data-tauri-drag-region />
)}
<App />
</PlatformProvider>

View File

@@ -328,7 +328,7 @@ export default function () {
<div class="flex gap-3 items-center">
<IconButton
as={"a"}
href="https://github.com/sst/opencode"
href="https://github.com/anomalyco/opencode"
target="_blank"
icon="github"
variant="ghost"

View File

@@ -4,33 +4,33 @@ description = "The open source coding agent."
version = "1.0.224"
schema_version = 1
authors = ["Anomaly"]
repository = "https://github.com/sst/opencode"
repository = "https://github.com/anomalyco/opencode"
[agent_servers.opencode]
name = "OpenCode"
icon = "./icons/opencode.svg"
[agent_servers.opencode.targets.darwin-aarch64]
archive = "https://github.com/sst/opencode/releases/download/v1.0.224/opencode-darwin-arm64.zip"
archive = "https://github.com/anomalyco/opencode/releases/download/v1.0.224/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.224/opencode-darwin-x64.zip"
archive = "https://github.com/anomalyco/opencode/releases/download/v1.0.224/opencode-darwin-x64.zip"
cmd = "./opencode"
args = ["acp"]
[agent_servers.opencode.targets.linux-aarch64]
archive = "https://github.com/sst/opencode/releases/download/v1.0.224/opencode-linux-arm64.tar.gz"
archive = "https://github.com/anomalyco/opencode/releases/download/v1.0.224/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.224/opencode-linux-x64.tar.gz"
archive = "https://github.com/anomalyco/opencode/releases/download/v1.0.224/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.224/opencode-windows-x64.zip"
archive = "https://github.com/anomalyco/opencode/releases/download/v1.0.224/opencode-windows-x64.zip"
cmd = "./opencode.exe"
args = ["acp"]

View File

@@ -22,17 +22,17 @@ if (!Script.preview) {
"options=('!debug' '!strip')",
"pkgrel=1",
"pkgdesc='The AI coding agent built for the terminal.'",
"url='https://github.com/sst/opencode'",
"url='https://github.com/anomalyco/opencode'",
"arch=('aarch64' 'x86_64')",
"license=('MIT')",
"provides=('opencode')",
"conflicts=('opencode')",
"depends=('ripgrep')",
"",
`source_aarch64=("\${pkgname}_\${pkgver}_aarch64.tar.gz::https://github.com/sst/opencode/releases/download/v\${pkgver}\${_subver}/opencode-linux-arm64.tar.gz")`,
`source_aarch64=("\${pkgname}_\${pkgver}_aarch64.tar.gz::https://github.com/anomalyco/opencode/releases/download/v\${pkgver}\${_subver}/opencode-linux-arm64.tar.gz")`,
`sha256sums_aarch64=('${arm64Sha}')`,
`source_x86_64=("\${pkgname}_\${pkgver}_x86_64.tar.gz::https://github.com/sst/opencode/releases/download/v\${pkgver}\${_subver}/opencode-linux-x64.tar.gz")`,
`source_x86_64=("\${pkgname}_\${pkgver}_x86_64.tar.gz::https://github.com/anomalyco/opencode/releases/download/v\${pkgver}\${_subver}/opencode-linux-x64.tar.gz")`,
`sha256sums_x86_64=('${x64Sha}')`,
"",
"package() {",
@@ -52,7 +52,7 @@ if (!Script.preview) {
"options=('!debug' '!strip')",
"pkgrel=1",
"pkgdesc='The AI coding agent built for the terminal.'",
"url='https://github.com/sst/opencode'",
"url='https://github.com/anomalyco/opencode'",
"arch=('aarch64' 'x86_64')",
"license=('MIT')",
"provides=('opencode')",
@@ -60,7 +60,7 @@ if (!Script.preview) {
"depends=('ripgrep')",
"makedepends=('git' 'bun' 'go')",
"",
`source=("opencode-\${pkgver}.tar.gz::https://github.com/sst/opencode/archive/v\${pkgver}\${_subver}.tar.gz")`,
`source=("opencode-\${pkgver}.tar.gz::https://github.com/anomalyco/opencode/archive/v\${pkgver}\${_subver}.tar.gz")`,
`sha256sums=('SKIP')`,
"",
"build() {",
@@ -133,14 +133,14 @@ if (!Script.preview) {
"# This file was generated by GoReleaser. DO NOT EDIT.",
"class Opencode < Formula",
` desc "The AI coding agent built for the terminal."`,
` homepage "https://github.com/sst/opencode"`,
` homepage "https://github.com/anomalyco/opencode"`,
` version "${Script.version.split("-")[0]}"`,
"",
` depends_on "ripgrep"`,
"",
" on_macos do",
" if Hardware::CPU.intel?",
` url "https://github.com/sst/opencode/releases/download/v${Script.version}/opencode-darwin-x64.zip"`,
` url "https://github.com/anomalyco/opencode/releases/download/v${Script.version}/opencode-darwin-x64.zip"`,
` sha256 "${macX64Sha}"`,
"",
" def install",
@@ -148,7 +148,7 @@ if (!Script.preview) {
" end",
" end",
" if Hardware::CPU.arm?",
` url "https://github.com/sst/opencode/releases/download/v${Script.version}/opencode-darwin-arm64.zip"`,
` url "https://github.com/anomalyco/opencode/releases/download/v${Script.version}/opencode-darwin-arm64.zip"`,
` sha256 "${macArm64Sha}"`,
"",
" def install",
@@ -159,14 +159,14 @@ if (!Script.preview) {
"",
" on_linux do",
" if Hardware::CPU.intel? and Hardware::CPU.is_64_bit?",
` url "https://github.com/sst/opencode/releases/download/v${Script.version}/opencode-linux-x64.tar.gz"`,
` url "https://github.com/anomalyco/opencode/releases/download/v${Script.version}/opencode-linux-x64.tar.gz"`,
` sha256 "${x64Sha}"`,
" def install",
' bin.install "opencode"',
" end",
" end",
" if Hardware::CPU.arm? and Hardware::CPU.is_64_bit?",
` url "https://github.com/sst/opencode/releases/download/v${Script.version}/opencode-linux-arm64.tar.gz"`,
` url "https://github.com/anomalyco/opencode/releases/download/v${Script.version}/opencode-linux-arm64.tar.gz"`,
` sha256 "${arm64Sha}"`,
" def install",
' bin.install "opencode"',

View File

@@ -62,7 +62,7 @@ if (!Script.preview) {
}
}
const image = "ghcr.io/sst/opencode"
const image = "ghcr.io/anomalyco/opencode"
const platforms = "linux/amd64,linux/arm64"
const tags = [`${image}:${Script.version}`, `${image}:latest`]
const tagFlags = tags.flatMap((t) => ["-t", t])

View File

@@ -396,7 +396,7 @@ jobs:
uses: actions/checkout@v4
- name: Run opencode
uses: sst/opencode/github@latest${envStr}
uses: anomalyco/opencode/github@latest${envStr}
with:
model: ${provider}/${model}`,
)
@@ -994,12 +994,16 @@ export const GithubRunCommand = cmd({
console.log("Configuring git...")
const config = "http.https://github.com/.extraheader"
const ret = await $`git config --local --get ${config}`
gitConfig = ret.stdout.toString().trim()
// actions/checkout@v6 no longer stores credentials in .git/config,
// so this may not exist - use nothrow() to handle gracefully
const ret = await $`git config --local --get ${config}`.nothrow()
if (ret.exitCode === 0) {
gitConfig = ret.stdout.toString().trim()
await $`git config --local --unset-all ${config}`
}
const newCredentials = Buffer.from(`x-access-token:${appToken}`, "utf8").toString("base64")
await $`git config --local --unset-all ${config}`
await $`git config --local ${config} "AUTHORIZATION: basic ${newCredentials}"`
await $`git config --global user.name "${AGENT_USERNAME}"`
await $`git config --global user.email "${AGENT_USERNAME}@users.noreply.github.com"`

View File

@@ -648,7 +648,7 @@ function ErrorComponent(props: {
})
const [copied, setCopied] = createSignal(false)
const issueURL = new URL("https://github.com/sst/opencode/issues/new?template=bug-report.yml")
const issueURL = new URL("https://github.com/anomalyco/opencode/issues/new?template=bug-report.yml")
// Choose safe fallback colors per mode since theme context may not be available
const isLight = props.mode === "light"

View File

@@ -92,7 +92,7 @@ export const TIPS = [
"Press {highlight}Ctrl+X S{/highlight} or {highlight}/status{/highlight} to see system status info.",
"Enable {highlight}tui.scroll_acceleration{/highlight} for smooth macOS-style scrolling.",
"Toggle username display in chat via command palette ({highlight}Ctrl+P{/highlight}).",
"Run {highlight}docker run -it --rm ghcr.io/sst/opencode{/highlight} for containerized use.",
"Run {highlight}docker run -it --rm ghcr.io/anomalyco/opencode{/highlight} for containerized use.",
"Use {highlight}/connect{/highlight} with OpenCode Zen for curated, tested models.",
"Commit your project's {highlight}AGENTS.md{/highlight} file to Git for team sharing.",
"Use {highlight}/review{/highlight} to review uncommitted changes, branches, or PRs.",

View File

@@ -22,13 +22,14 @@ import { ConfigMarkdown } from "./markdown"
export namespace Config {
const log = Log.create({ service: "config" })
// Custom merge function that concatenates plugin arrays instead of replacing them
function mergeConfigWithPlugins(target: Info, source: Info): Info {
// Custom merge function that concatenates array fields instead of replacing them
function mergeConfigConcatArrays(target: Info, source: Info): Info {
const merged = mergeDeep(target, source)
// If both configs have plugin arrays, concatenate them instead of replacing
if (target.plugin && source.plugin) {
const pluginSet = new Set([...target.plugin, ...source.plugin])
merged.plugin = Array.from(pluginSet)
merged.plugin = Array.from(new Set([...target.plugin, ...source.plugin]))
}
if (target.instructions && source.instructions) {
merged.instructions = Array.from(new Set([...target.instructions, ...source.instructions]))
}
return merged
}
@@ -39,19 +40,19 @@ export namespace Config {
// Override with custom config if provided
if (Flag.OPENCODE_CONFIG) {
result = mergeConfigWithPlugins(result, await loadFile(Flag.OPENCODE_CONFIG))
result = mergeConfigConcatArrays(result, await loadFile(Flag.OPENCODE_CONFIG))
log.debug("loaded custom config", { path: Flag.OPENCODE_CONFIG })
}
for (const file of ["opencode.jsonc", "opencode.json"]) {
const found = await Filesystem.findUp(file, Instance.directory, Instance.worktree)
for (const resolved of found.toReversed()) {
result = mergeConfigWithPlugins(result, await loadFile(resolved))
result = mergeConfigConcatArrays(result, await loadFile(resolved))
}
}
if (Flag.OPENCODE_CONFIG_CONTENT) {
result = mergeConfigWithPlugins(result, JSON.parse(Flag.OPENCODE_CONFIG_CONTENT))
result = mergeConfigConcatArrays(result, JSON.parse(Flag.OPENCODE_CONFIG_CONTENT))
log.debug("loaded custom config from OPENCODE_CONFIG_CONTENT")
}
@@ -59,7 +60,7 @@ export namespace Config {
if (value.type === "wellknown") {
process.env[value.key] = value.token
const wellknown = (await fetch(`${key}/.well-known/opencode`).then((x) => x.json())) as any
result = mergeConfigWithPlugins(result, await load(JSON.stringify(wellknown.config ?? {}), process.cwd()))
result = mergeConfigConcatArrays(result, await load(JSON.stringify(wellknown.config ?? {}), process.cwd()))
}
}
@@ -94,7 +95,7 @@ export namespace Config {
if (dir.endsWith(".opencode") || dir === Flag.OPENCODE_CONFIG_DIR) {
for (const file of ["opencode.jsonc", "opencode.json"]) {
log.debug(`loading config from ${path.join(dir, file)}`)
result = mergeConfigWithPlugins(result, await loadFile(path.join(dir, file)))
result = mergeConfigConcatArrays(result, await loadFile(path.join(dir, file)))
// to satisfy the type checker
result.agent ??= {}
result.mode ??= {}

View File

@@ -195,7 +195,7 @@ export namespace Installation {
.then((data: any) => data.version)
}
return fetch("https://api.github.com/repos/sst/opencode/releases/latest")
return fetch("https://api.github.com/repos/anomalyco/opencode/releases/latest")
.then((res) => {
if (!res.ok) throw new Error(res.statusText)
return res.json()

View File

@@ -374,7 +374,7 @@ export namespace Provider {
return {
autoload: true,
async getModel(sdk: any, modelID: string, _options?: Record<string, any>) {
return sdk.chat(modelID)
return sdk.languageModel(modelID)
},
options: {
baseURL: `https://gateway.ai.cloudflare.com/v1/${accountId}/${gateway}/compat`,

View File

@@ -279,7 +279,7 @@ export namespace ProviderTransform {
// https://v5.ai-sdk.dev/providers/ai-sdk-providers/azure
if (id === "o1-mini") return {}
const azureEfforts = ["low", "medium", "high"]
if (id.includes("gpt-5")) {
if (id.includes("gpt-5-") || id === "gpt-5") {
azureEfforts.unshift("minimal")
}
return Object.fromEntries(
@@ -296,8 +296,11 @@ export namespace ProviderTransform {
// https://v5.ai-sdk.dev/providers/ai-sdk-providers/openai
if (id === "gpt-5-pro") return {}
const openaiEfforts = iife(() => {
if (model.id.includes("codex")) return WIDELY_SUPPORTED_EFFORTS
const arr = ["minimal", ...WIDELY_SUPPORTED_EFFORTS]
if (id.includes("codex")) return WIDELY_SUPPORTED_EFFORTS
const arr = [...WIDELY_SUPPORTED_EFFORTS]
if (id.includes("gpt-5-") || id === "gpt-5") {
arr.unshift("minimal")
}
if (model.release_date >= "2025-11-13") {
arr.unshift("none")
}

View File

@@ -476,7 +476,6 @@ export namespace MessageV2 {
role: "assistant",
parts: [],
}
result.push(assistantMessage)
for (const part of msg.parts) {
if (part.type === "text")
assistantMessage.parts.push({
@@ -535,6 +534,9 @@ export namespace MessageV2 {
})
}
}
if (assistantMessage.parts.length > 0) {
result.push(assistantMessage)
}
}
}

View File

@@ -560,6 +560,25 @@ export namespace SessionPrompt {
const sessionMessages = clone(msgs)
// Ephemerally wrap queued user messages with a reminder to stay on track
if (step > 1 && lastFinished) {
for (const msg of sessionMessages) {
if (msg.info.role !== "user" || msg.info.id <= lastFinished.id) continue
for (const part of msg.parts) {
if (part.type !== "text" || part.ignored || part.synthetic) continue
if (!part.text.trim()) continue
part.text = [
"<system-reminder>",
"The user sent the following message:",
part.text,
"",
"Please address this message and continue with your tasks.",
"</system-reminder>",
].join("\n")
}
}
}
await Plugin.trigger("experimental.chat.messages.transform", {}, { messages: sessionMessages })
const result = await processor.process({

View File

@@ -140,7 +140,7 @@ The user will primarily request you perform software engineering tasks. This inc
Here is useful information about the environment you are running in:
<env>
Working directory: /home/thdxr/dev/projects/sst/opencode/packages/opencode
Working directory: /home/thdxr/dev/projects/anomalyco/opencode/packages/opencode
Is directory a git repo: Yes
Platform: linux
OS Version: Linux 6.12.4-arch1-1

View File

@@ -7,7 +7,7 @@ IMPORTANT: You must NEVER generate or guess URLs for the user unless you are con
If the user asks for help or wants to give feedback inform them of the following:
- ctrl+p to list available actions
- To give feedback, users should report the issue at
https://github.com/sst/opencode
https://github.com/anomalyco/opencode
When the user directly asks about OpenCode (eg. "can OpenCode do...", "does OpenCode have..."), or asks in second person (eg. "are you able...", "can you do..."), or asks how to use a specific OpenCode feature (eg. implement a hook, write a slash command, or install an MCP server), use the WebFetch tool to gather information to answer the question from OpenCode docs. The list of available docs is available at https://opencode.ai/docs

View File

@@ -6,7 +6,7 @@ IMPORTANT: You must NEVER generate or guess URLs for the user unless you are con
If the user asks for help or wants to give feedback inform them of the following:
- /help: Get help with using opencode
- To give feedback, users should report the issue at https://github.com/sst/opencode/issues
- To give feedback, users should report the issue at https://github.com/anomalyco/opencode/issues
When the user directly asks about opencode (eg 'can opencode do...', 'does opencode have...') or asks in second person (eg 'are you able...', 'can you do...'), first use the WebFetch tool to gather information to answer the question from opencode docs at https://opencode.ai

View File

@@ -488,6 +488,87 @@ Helper subagent prompt`,
})
})
test("merges instructions arrays from global and local configs", async () => {
await using tmp = await tmpdir({
init: async (dir) => {
const projectDir = path.join(dir, "project")
const opencodeDir = path.join(projectDir, ".opencode")
await fs.mkdir(opencodeDir, { recursive: true })
await Bun.write(
path.join(dir, "opencode.json"),
JSON.stringify({
$schema: "https://opencode.ai/config.json",
instructions: ["global-instructions.md", "shared-rules.md"],
}),
)
await Bun.write(
path.join(opencodeDir, "opencode.json"),
JSON.stringify({
$schema: "https://opencode.ai/config.json",
instructions: ["local-instructions.md"],
}),
)
},
})
await Instance.provide({
directory: path.join(tmp.path, "project"),
fn: async () => {
const config = await Config.get()
const instructions = config.instructions ?? []
expect(instructions).toContain("global-instructions.md")
expect(instructions).toContain("shared-rules.md")
expect(instructions).toContain("local-instructions.md")
expect(instructions.length).toBe(3)
},
})
})
test("deduplicates duplicate instructions from global and local configs", async () => {
await using tmp = await tmpdir({
init: async (dir) => {
const projectDir = path.join(dir, "project")
const opencodeDir = path.join(projectDir, ".opencode")
await fs.mkdir(opencodeDir, { recursive: true })
await Bun.write(
path.join(dir, "opencode.json"),
JSON.stringify({
$schema: "https://opencode.ai/config.json",
instructions: ["duplicate.md", "global-only.md"],
}),
)
await Bun.write(
path.join(opencodeDir, "opencode.json"),
JSON.stringify({
$schema: "https://opencode.ai/config.json",
instructions: ["duplicate.md", "local-only.md"],
}),
)
},
})
await Instance.provide({
directory: path.join(tmp.path, "project"),
fn: async () => {
const config = await Config.get()
const instructions = config.instructions ?? []
expect(instructions).toContain("global-only.md")
expect(instructions).toContain("local-only.md")
expect(instructions).toContain("duplicate.md")
const duplicates = instructions.filter((i) => i === "duplicate.md")
expect(duplicates.length).toBe(1)
expect(instructions.length).toBe(3)
},
})
})
test("deduplicates duplicate plugins from global and local configs", async () => {
await using tmp = await tmpdir({
init: async (dir) => {

View File

@@ -694,10 +694,10 @@ describe("ProviderTransform.variants", () => {
test("standard azure models return custom efforts with reasoningSummary", () => {
const model = createMockModel({
id: "azure/gpt-4o",
id: "o1",
providerID: "azure",
api: {
id: "gpt-4o",
id: "o1",
url: "https://azure.com",
npm: "@ai-sdk/azure",
},
@@ -713,7 +713,7 @@ describe("ProviderTransform.variants", () => {
test("gpt-5 adds minimal effort", () => {
const model = createMockModel({
id: "azure/gpt-5",
id: "gpt-5",
providerID: "azure",
api: {
id: "gpt-5",
@@ -743,10 +743,10 @@ describe("ProviderTransform.variants", () => {
test("standard openai models return custom efforts with reasoningSummary", () => {
const model = createMockModel({
id: "openai/gpt-4o",
id: "gpt-5",
providerID: "openai",
api: {
id: "gpt-4o",
id: "gpt-5",
url: "https://api.openai.com",
npm: "@ai-sdk/openai",
},
@@ -763,10 +763,10 @@ describe("ProviderTransform.variants", () => {
test("models after 2025-11-13 include 'none' effort", () => {
const model = createMockModel({
id: "openai/gpt-4.5",
id: "gpt-5-nano",
providerID: "openai",
api: {
id: "gpt-4.5",
id: "gpt-5-nano",
url: "https://api.openai.com",
npm: "@ai-sdk/openai",
},

View File

@@ -0,0 +1,570 @@
import { describe, expect, test } from "bun:test"
import { MessageV2 } from "../../src/session/message-v2"
const sessionID = "session"
function userInfo(id: string): MessageV2.User {
return {
id,
sessionID,
role: "user",
time: { created: 0 },
agent: "user",
model: { providerID: "test", modelID: "test" },
tools: {},
mode: "",
} as unknown as MessageV2.User
}
function assistantInfo(id: string, parentID: string, error?: MessageV2.Assistant["error"]): MessageV2.Assistant {
return {
id,
sessionID,
role: "assistant",
time: { created: 0 },
error,
parentID,
modelID: "model",
providerID: "provider",
mode: "",
agent: "agent",
path: { cwd: "/", root: "/" },
cost: 0,
tokens: {
input: 0,
output: 0,
reasoning: 0,
cache: { read: 0, write: 0 },
},
} as unknown as MessageV2.Assistant
}
function basePart(messageID: string, id: string) {
return {
id,
sessionID,
messageID,
}
}
describe("session.message-v2.toModelMessage", () => {
test("filters out messages with no parts", () => {
const input: MessageV2.WithParts[] = [
{
info: userInfo("m-empty"),
parts: [],
},
{
info: userInfo("m-user"),
parts: [
{
...basePart("m-user", "p1"),
type: "text",
text: "hello",
},
] as MessageV2.Part[],
},
]
expect(MessageV2.toModelMessage(input)).toStrictEqual([
{
role: "user",
content: [{ type: "text", text: "hello" }],
},
])
})
test("filters out messages with only ignored parts", () => {
const messageID = "m-user"
const input: MessageV2.WithParts[] = [
{
info: userInfo(messageID),
parts: [
{
...basePart(messageID, "p1"),
type: "text",
text: "ignored",
ignored: true,
},
] as MessageV2.Part[],
},
]
expect(MessageV2.toModelMessage(input)).toStrictEqual([])
})
test("includes synthetic text parts", () => {
const messageID = "m-user"
const input: MessageV2.WithParts[] = [
{
info: userInfo(messageID),
parts: [
{
...basePart(messageID, "p1"),
type: "text",
text: "hello",
synthetic: true,
},
] as MessageV2.Part[],
},
{
info: assistantInfo("m-assistant", messageID),
parts: [
{
...basePart("m-assistant", "a1"),
type: "text",
text: "assistant",
synthetic: true,
},
] as MessageV2.Part[],
},
]
expect(MessageV2.toModelMessage(input)).toStrictEqual([
{
role: "user",
content: [{ type: "text", text: "hello" }],
},
{
role: "assistant",
content: [{ type: "text", text: "assistant" }],
},
])
})
test("converts user text/file parts and injects compaction/subtask prompts", () => {
const messageID = "m-user"
const input: MessageV2.WithParts[] = [
{
info: userInfo(messageID),
parts: [
{
...basePart(messageID, "p1"),
type: "text",
text: "hello",
},
{
...basePart(messageID, "p2"),
type: "text",
text: "ignored",
ignored: true,
},
{
...basePart(messageID, "p3"),
type: "file",
mime: "image/png",
filename: "img.png",
url: "https://example.com/img.png",
},
{
...basePart(messageID, "p4"),
type: "file",
mime: "text/plain",
filename: "note.txt",
url: "https://example.com/note.txt",
},
{
...basePart(messageID, "p5"),
type: "file",
mime: "application/x-directory",
filename: "dir",
url: "https://example.com/dir",
},
{
...basePart(messageID, "p6"),
type: "compaction",
auto: true,
},
{
...basePart(messageID, "p7"),
type: "subtask",
prompt: "prompt",
description: "desc",
agent: "agent",
},
] as MessageV2.Part[],
},
]
expect(MessageV2.toModelMessage(input)).toStrictEqual([
{
role: "user",
content: [
{ type: "text", text: "hello" },
{
type: "file",
mediaType: "image/png",
filename: "img.png",
data: "https://example.com/img.png",
},
{ type: "text", text: "What did we do so far?" },
{ type: "text", text: "The following tool was executed by the user" },
],
},
])
})
test("converts assistant tool completion into tool-call + tool-result messages and emits attachment message", () => {
const userID = "m-user"
const assistantID = "m-assistant"
const input: MessageV2.WithParts[] = [
{
info: userInfo(userID),
parts: [
{
...basePart(userID, "u1"),
type: "text",
text: "run tool",
},
] as MessageV2.Part[],
},
{
info: assistantInfo(assistantID, userID),
parts: [
{
...basePart(assistantID, "a1"),
type: "text",
text: "done",
metadata: { openai: { assistant: "meta" } },
},
{
...basePart(assistantID, "a2"),
type: "tool",
callID: "call-1",
tool: "bash",
state: {
status: "completed",
input: { cmd: "ls" },
output: "ok",
title: "Bash",
metadata: {},
time: { start: 0, end: 1 },
attachments: [
{
...basePart(assistantID, "file-1"),
type: "file",
mime: "image/png",
filename: "attachment.png",
url: "https://example.com/attachment.png",
},
],
},
metadata: { openai: { tool: "meta" } },
},
] as MessageV2.Part[],
},
]
expect(MessageV2.toModelMessage(input)).toStrictEqual([
{
role: "user",
content: [{ type: "text", text: "run tool" }],
},
{
role: "user",
content: [
{ type: "text", text: "Tool bash returned an attachment:" },
{
type: "file",
mediaType: "image/png",
filename: "attachment.png",
data: "https://example.com/attachment.png",
},
],
},
{
role: "assistant",
content: [
{ type: "text", text: "done", providerOptions: { openai: { assistant: "meta" } } },
{
type: "tool-call",
toolCallId: "call-1",
toolName: "bash",
input: { cmd: "ls" },
providerExecuted: undefined,
providerOptions: { openai: { tool: "meta" } },
},
],
},
{
role: "tool",
content: [
{
type: "tool-result",
toolCallId: "call-1",
toolName: "bash",
output: { type: "text", value: "ok" },
},
],
},
])
})
test("replaces compacted tool output with placeholder", () => {
const userID = "m-user"
const assistantID = "m-assistant"
const input: MessageV2.WithParts[] = [
{
info: userInfo(userID),
parts: [
{
...basePart(userID, "u1"),
type: "text",
text: "run tool",
},
] as MessageV2.Part[],
},
{
info: assistantInfo(assistantID, userID),
parts: [
{
...basePart(assistantID, "a1"),
type: "tool",
callID: "call-1",
tool: "bash",
state: {
status: "completed",
input: { cmd: "ls" },
output: "this should be cleared",
title: "Bash",
metadata: {},
time: { start: 0, end: 1, compacted: 1 },
},
},
] as MessageV2.Part[],
},
]
expect(MessageV2.toModelMessage(input)).toStrictEqual([
{
role: "user",
content: [{ type: "text", text: "run tool" }],
},
{
role: "assistant",
content: [
{
type: "tool-call",
toolCallId: "call-1",
toolName: "bash",
input: { cmd: "ls" },
providerExecuted: undefined,
},
],
},
{
role: "tool",
content: [
{
type: "tool-result",
toolCallId: "call-1",
toolName: "bash",
output: { type: "text", value: "[Old tool result content cleared]" },
},
],
},
])
})
test("converts assistant tool error into error-text tool result", () => {
const userID = "m-user"
const assistantID = "m-assistant"
const input: MessageV2.WithParts[] = [
{
info: userInfo(userID),
parts: [
{
...basePart(userID, "u1"),
type: "text",
text: "run tool",
},
] as MessageV2.Part[],
},
{
info: assistantInfo(assistantID, userID),
parts: [
{
...basePart(assistantID, "a1"),
type: "tool",
callID: "call-1",
tool: "bash",
state: {
status: "error",
input: { cmd: "ls" },
error: "nope",
time: { start: 0, end: 1 },
metadata: {},
},
metadata: { openai: { tool: "meta" } },
},
] as MessageV2.Part[],
},
]
expect(MessageV2.toModelMessage(input)).toStrictEqual([
{
role: "user",
content: [{ type: "text", text: "run tool" }],
},
{
role: "assistant",
content: [
{
type: "tool-call",
toolCallId: "call-1",
toolName: "bash",
input: { cmd: "ls" },
providerExecuted: undefined,
providerOptions: { openai: { tool: "meta" } },
},
],
},
{
role: "tool",
content: [
{
type: "tool-result",
toolCallId: "call-1",
toolName: "bash",
output: { type: "error-text", value: "nope" },
},
],
},
])
})
test("filters assistant messages with non-abort errors", () => {
const assistantID = "m-assistant"
const input: MessageV2.WithParts[] = [
{
info: assistantInfo(
assistantID,
"m-parent",
new MessageV2.APIError({ message: "boom", isRetryable: true }).toObject() as MessageV2.APIError,
),
parts: [
{
...basePart(assistantID, "a1"),
type: "text",
text: "should not render",
},
] as MessageV2.Part[],
},
]
expect(MessageV2.toModelMessage(input)).toStrictEqual([])
})
test("includes aborted assistant messages only when they have non-step-start/reasoning content", () => {
const assistantID1 = "m-assistant-1"
const assistantID2 = "m-assistant-2"
const aborted = new MessageV2.AbortedError({ message: "aborted" }).toObject() as MessageV2.Assistant["error"]
const input: MessageV2.WithParts[] = [
{
info: assistantInfo(assistantID1, "m-parent", aborted),
parts: [
{
...basePart(assistantID1, "a1"),
type: "reasoning",
text: "thinking",
time: { start: 0 },
},
{
...basePart(assistantID1, "a2"),
type: "text",
text: "partial answer",
},
] as MessageV2.Part[],
},
{
info: assistantInfo(assistantID2, "m-parent", aborted),
parts: [
{
...basePart(assistantID2, "b1"),
type: "step-start",
},
{
...basePart(assistantID2, "b2"),
type: "reasoning",
text: "thinking",
time: { start: 0 },
},
] as MessageV2.Part[],
},
]
expect(MessageV2.toModelMessage(input)).toStrictEqual([
{
role: "assistant",
content: [
{ type: "reasoning", text: "thinking", providerOptions: undefined },
{ type: "text", text: "partial answer" },
],
},
])
})
test("splits assistant messages on step-start boundaries", () => {
const assistantID = "m-assistant"
const input: MessageV2.WithParts[] = [
{
info: assistantInfo(assistantID, "m-parent"),
parts: [
{
...basePart(assistantID, "p1"),
type: "text",
text: "first",
},
{
...basePart(assistantID, "p2"),
type: "step-start",
},
{
...basePart(assistantID, "p3"),
type: "text",
text: "second",
},
] as MessageV2.Part[],
},
]
expect(MessageV2.toModelMessage(input)).toStrictEqual([
{
role: "assistant",
content: [{ type: "text", text: "first" }],
},
{
role: "assistant",
content: [{ type: "text", text: "second" }],
},
])
})
test("drops messages that only contain step-start parts", () => {
const assistantID = "m-assistant"
const input: MessageV2.WithParts[] = [
{
info: assistantInfo(assistantID, "m-parent"),
parts: [
{
...basePart(assistantID, "p1"),
type: "step-start",
},
] as MessageV2.Part[],
},
]
expect(MessageV2.toModelMessage(input)).toStrictEqual([])
})
})

View File

@@ -5,7 +5,7 @@ export default {
console: stage === "production" ? "https://opencode.ai/auth" : `https://${stage}.opencode.ai/auth`,
email: "contact@anoma.ly",
socialCard: "https://social-cards.sst.dev",
github: "https://github.com/sst/opencode",
github: "https://github.com/anomalyco/opencode",
discord: "https://opencode.ai/discord",
headerLinks: [
{ name: "Home", url: "/" },

View File

@@ -133,9 +133,9 @@ if (image) {
</div>
<div class="col4">
<h3>Mise</h3>
<button class="command" data-command="mise use -g github:sst/opencode">
<button class="command" data-command="mise use -g github:anomalyco/opencode">
<code>
<span>mise use -g</span> <span class="highlight">github:sst/opencode</span>
<span>mise use -g</span> <span class="highlight">github:anomalyco/opencode</span>
</code>
<span class="copy">
<CopyIcon />

View File

@@ -572,7 +572,7 @@ Here are some common use cases for different agents.
Here are some examples agents you might find useful.
:::tip
Do you have an agent you'd like to share? [Submit a PR](https://github.com/sst/opencode).
Do you have an agent you'd like to share? [Submit a PR](https://github.com/anomalyco/opencode).
:::
---

View File

@@ -63,7 +63,7 @@ Or you can set it up manually.
fetch-depth: 1
- name: Run OpenCode
uses: sst/opencode/github@latest
uses: anomalyco/opencode/github@latest
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
with:
@@ -137,7 +137,7 @@ jobs:
uses: actions/checkout@v4
- name: Run OpenCode
uses: sst/opencode/github@latest
uses: anomalyco/opencode/github@latest
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
with:
@@ -172,7 +172,7 @@ jobs:
issues: read
steps:
- uses: actions/checkout@v4
- uses: sst/opencode/github@latest
- uses: anomalyco/opencode/github@latest
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
with:
@@ -224,7 +224,7 @@ jobs:
- uses: actions/checkout@v4
if: steps.check.outputs.result == 'true'
- uses: sst/opencode/github@latest
- uses: anomalyco/opencode/github@latest
if: steps.check.outputs.result == 'true'
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
@@ -246,7 +246,7 @@ For `issues` events, the `prompt` input is **required** since there's no comment
Override the default prompt to customize OpenCode's behavior for your workflow.
```yaml title=".github/workflows/opencode.yml"
- uses: sst/opencode/github@latest
- uses: anomalyco/opencode/github@latest
with:
model: anthropic/claude-sonnet-4-5
prompt: |

View File

@@ -109,18 +109,18 @@ You can also install it with the following commands:
- **Using Mise**
```bash
mise use -g github:sst/opencode
mise use -g github:anomalyco/opencode
```
- **Using Docker**
```bash
docker run -it --rm ghcr.io/sst/opencode
docker run -it --rm ghcr.io/anomalyco/opencode
```
Support for installing OpenCode on Windows using Bun is currently in progress.
You can also grab the binary from the [Releases](https://github.com/sst/opencode/releases).
You can also grab the binary from the [Releases](https://github.com/anomalyco/opencode/releases).
---

View File

@@ -46,7 +46,7 @@ If you're experiencing issues with OpenCode:
The best way to report bugs or request features is through our GitHub repository:
[**github.com/sst/opencode/issues**](https://github.com/sst/opencode/issues)
[**github.com/anomalyco/opencode/issues**](https://github.com/anomalyco/opencode/issues)
Before creating a new issue, search existing issues to see if your problem has already been reported.

View File

@@ -18,7 +18,7 @@ export const team = [
]
export async function getLatestRelease() {
return fetch("https://api.github.com/repos/sst/opencode/releases/latest")
return fetch("https://api.github.com/repos/anomalyco/opencode/releases/latest")
.then((res) => {
if (!res.ok) throw new Error(res.statusText)
return res.json()
@@ -39,7 +39,7 @@ export async function getCommits(from: string, to: string): Promise<Commit[]> {
// Get commit data with GitHub usernames from the API
const compare =
await $`gh api "/repos/sst/opencode/compare/${fromRef}...${toRef}" --jq '.commits[] | {sha: .sha, login: .author.login, message: .commit.message}'`.text()
await $`gh api "/repos/anomalyco/opencode/compare/${fromRef}...${toRef}" --jq '.commits[] | {sha: .sha, login: .author.login, message: .commit.message}'`.text()
const commitData = new Map<string, { login: string | null; message: string }>()
for (const line of compare.split("\n").filter(Boolean)) {
@@ -195,7 +195,7 @@ export async function getContributors(from: string, to: string) {
const fromRef = from.startsWith("v") ? from : `v${from}`
const toRef = to === "HEAD" ? to : to.startsWith("v") ? to : `v${to}`
const compare =
await $`gh api "/repos/sst/opencode/compare/${fromRef}...${toRef}" --jq '.commits[] | {login: .author.login, message: .commit.message}'`.text()
await $`gh api "/repos/anomalyco/opencode/compare/${fromRef}...${toRef}" --jq '.commits[] | {login: .author.login, message: .commit.message}'`.text()
const contributors = new Map<string, string[]>()
for (const line of compare.split("\n").filter(Boolean)) {

View File

@@ -73,7 +73,7 @@ async function fetchReleases(): Promise<Release[]> {
const per = 100
while (true) {
const url = `https://api.github.com/repos/sst/opencode/releases?page=${page}&per_page=${per}`
const url = `https://api.github.com/repos/anomalyco/opencode/releases?page=${page}&per_page=${per}`
const response = await fetch(url)
if (!response.ok) {
@@ -188,7 +188,7 @@ async function save(githubTotal: number, npmDownloads: number) {
)
}
console.log("Fetching GitHub releases for sst/opencode...\n")
console.log("Fetching GitHub releases for anomalyco/opencode...\n")
const releases = await fetchReleases()
console.log(`\nFetched ${releases.length} releases total\n`)

View File

@@ -6,7 +6,7 @@
set -euo pipefail
REPO="sst/opencode"
REPO="anomalyco/opencode"
GITHUB_API="https://api.github.com/repos"
FOUR_WEEKS_AGO=$(date -u -v-28d '+%Y-%m-%dT00:00:00Z' 2>/dev/null || date -u -d '4 weeks ago' '+%Y-%m-%dT00:00:00Z')

View File

@@ -6,7 +6,7 @@
set -euo pipefail
REPO="sst/opencode"
REPO="anomalyco/opencode"
GITHUB_API="https://api.github.com/repos"
# Start from Dec 15

View File

@@ -15,7 +15,7 @@ This extension requires the [opencode CLI](https://opencode.ai) to be installed
## Support
This is an early release. If you encounter issues or have feedback, please create an issue at https://github.com/sst/opencode/issues.
This is an early release. If you encounter issues or have feedback, please create an issue at https://github.com/anomalyco/opencode/issues.
## Development

View File

@@ -6,7 +6,7 @@
"publisher": "sst-dev",
"repository": {
"type": "git",
"url": "https://github.com/sst/opencode"
"url": "https://github.com/anomalyco/opencode"
},
"license": "MIT",
"icon": "images/icon.png",