Compare commits

..

10 Commits

Author SHA1 Message Date
Aiden Cline e6a3be31de merge dev 2025-11-21 01:44:45 -06:00
Ian Maurer 715265de4b Update .gitignore to remove '*.bun-build'
Remove '*.bun-build' from the .gitignore file
2025-11-12 11:33:59 -05:00
Ian Maurer 2048f32491 Merge branch 'dev' into fix/cli-clean-exit-on-model-errors 2025-11-12 11:30:36 -05:00
GitHub Action 2d7ba43a21 chore: format code 2025-11-12 16:14:12 +00:00
Ian Maurer bd198d8550 fix(cli): robust suggestions for unknown provider and model-only input; ignore bun build artifacts 2025-11-12 11:13:34 -05:00
GitHub Action cbffbcdd3d chore: format code 2025-11-12 15:43:30 +00:00
Ian Maurer 2be8b2269f feat(cli): suggest closest provider/model on not found ("Did you mean…")\n\nSummary\n- Add fuzzy suggestions to ProviderModelNotFoundError with up to 3 candidates\n- Normalize punctuation (e.g., 4.5 vs 4-5) and case to better match common typos\n- Support model-only input (no provider) by searching across all providers\n- Enhance CLI error formatter to display suggestions when present\n\nImplementation\n- provider.ts: use fuzzysort; add normalization by stripping non-alphanumerics; search by key for robust matches\n- provider.ts: when provider is unknown and model is empty, treat token as unqualified model and search across all providers' models; otherwise suggest provider matches\n- error.ts: print "Did you mean: <provider/model>, …" when suggestions exist\n\nExamples\n1) Typo in model ID\n $ bun run ./src/index.ts run --model anthropic/claude-haiu-4-5 "hi"\n Error: Model not found: anthropic/claude-haiu-4-5\n Did you mean: anthropic/claude-haiku-4-5, anthropic/claude-haiku-4-5-20251001\n Try: zai-coding-plan/glm-4.5-flash
zai-coding-plan/glm-4.5
zai-coding-plan/glm-4.5-air
zai-coding-plan/glm-4.5v
zai-coding-plan/glm-4.6
opencode/big-pickle
opencode/grok-code
anthropic/claude-opus-4-0
anthropic/claude-3-5-sonnet-20241022
anthropic/claude-opus-4-1
anthropic/claude-haiku-4-5
anthropic/claude-3-5-sonnet-20240620
anthropic/claude-3-5-haiku-latest
anthropic/claude-3-opus-20240229
anthropic/claude-sonnet-4-5
anthropic/claude-sonnet-4-5-20250929
anthropic/claude-sonnet-4-20250514
anthropic/claude-opus-4-20250514
anthropic/claude-3-5-haiku-20241022
anthropic/claude-3-haiku-20240307
anthropic/claude-3-7-sonnet-20250219
anthropic/claude-3-7-sonnet-latest
anthropic/claude-sonnet-4-0
anthropic/claude-opus-4-1-20250805
anthropic/claude-3-sonnet-20240229
anthropic/claude-haiku-4-5-20251001
openai/gpt-4.1-nano
openai/text-embedding-3-small
openai/gpt-4
openai/o1-pro
openai/gpt-4o-2024-05-13
openai/gpt-4o-2024-08-06
openai/gpt-4.1-mini
openai/o3-deep-research
openai/gpt-3.5-turbo
openai/text-embedding-3-large
openai/gpt-4-turbo
openai/o1-preview
openai/o3-mini
openai/codex-mini-latest
openai/gpt-5-nano
openai/gpt-5-codex
openai/gpt-4o
openai/gpt-4.1
openai/o4-mini
openai/o1
openai/gpt-5-mini
openai/o1-mini
openai/text-embedding-ada-002
openai/o3-pro
openai/gpt-4o-2024-11-20
openai/o3
openai/o4-mini-deep-research
openai/gpt-4o-mini
openai/gpt-5
openai/gpt-5-pro to list available models\n   Or check your config (opencode.json) provider/model names\n\n2) Dot vs dash (punctuation normalization)\n   $ bun run ./src/index.ts run --model anthropic/claude-haiku-4.5 "hi"\n   Error: Model not found: anthropic/claude-haiku-4.5\n   Did you mean: anthropic/claude-haiku-4-5, anthropic/claude-haiku-4-5-20251001\n   Try: zai-coding-plan/glm-4.5-flash
zai-coding-plan/glm-4.5
zai-coding-plan/glm-4.5-air
zai-coding-plan/glm-4.5v
zai-coding-plan/glm-4.6
opencode/big-pickle
opencode/grok-code
anthropic/claude-opus-4-0
anthropic/claude-3-5-sonnet-20241022
anthropic/claude-opus-4-1
anthropic/claude-haiku-4-5
anthropic/claude-3-5-sonnet-20240620
anthropic/claude-3-5-haiku-latest
anthropic/claude-3-opus-20240229
anthropic/claude-sonnet-4-5
anthropic/claude-sonnet-4-5-20250929
anthropic/claude-sonnet-4-20250514
anthropic/claude-opus-4-20250514
anthropic/claude-3-5-haiku-20241022
anthropic/claude-3-haiku-20240307
anthropic/claude-3-7-sonnet-20250219
anthropic/claude-3-7-sonnet-latest
anthropic/claude-sonnet-4-0
anthropic/claude-opus-4-1-20250805
anthropic/claude-3-sonnet-20240229
anthropic/claude-haiku-4-5-20251001
openai/gpt-4.1-nano
openai/text-embedding-3-small
openai/gpt-4
openai/o1-pro
openai/gpt-4o-2024-05-13
openai/gpt-4o-2024-08-06
openai/gpt-4.1-mini
openai/o3-deep-research
openai/gpt-3.5-turbo
openai/text-embedding-3-large
openai/gpt-4-turbo
openai/o1-preview
openai/o3-mini
openai/codex-mini-latest
openai/gpt-5-nano
openai/gpt-5-codex
openai/gpt-4o
openai/gpt-4.1
openai/o4-mini
openai/o1
openai/gpt-5-mini
openai/o1-mini
openai/text-embedding-ada-002
openai/o3-pro
openai/gpt-4o-2024-11-20
openai/o3
openai/o4-mini-deep-research
openai/gpt-4o-mini
openai/gpt-5
openai/gpt-5-pro to list available models\n   Or check your config (opencode.json) provider/model names\n\n3) Missing provider (model-only input)\n   $ bun run ./src/index.ts run --model big-pickle "hi"\n   Error: Model not found: big-pickle/\n   Did you mean: opencode/big-pickle\n\n4) Correct model after suggestion\n   $ bun run ./src/index.ts run --model opencode/big-pickle "hi"\n   Hi! How can I help you with your opencode project today?\n\nNotes\n- Suggestions are hints only; behavior is unchanged (no auto-selection).\n- This runs locally as part of the CLI error path; performance impact is negligible (small in-memory scans).
2025-11-12 10:42:18 -05:00
Ian Maurer c1fa257a92 Merge branch 'dev' into fix/cli-clean-exit-on-model-errors 2025-11-11 17:18:23 -05:00
Ian Maurer 7fd81dd93e chore(cli): resolve merge conflict with dev in bootstrap; keep try/finally with explicit return 2025-11-11 17:16:47 -05:00
Ian Maurer d554e7aaef fix(cli): always dispose instance on error to prevent hanging; add friendly ProviderModelNotFoundError/InitError messages\n\n- Wrap bootstrap callback in try/finally to guarantee Instance.dispose()\n- Format provider/model errors into actionable guidance (opencode models, config)\n\nRepro: running opencode run --model typo/claude-haiku-4-5 prints stack and hangs until SIGINT due to lingering watchers.\nFix: disposing Instance tears down watchers/subscriptions, allowing process to exit.\n\nNotes: Prior attempt (#3083) explicitly exited; this approach addresses root cause without forcing exit and improves UX for common misconfigurations. 2025-11-11 17:13:55 -05:00
35 changed files with 140 additions and 280 deletions
-1
View File
@@ -146,4 +146,3 @@
| 2025-11-18 | 791,563 (+11,402) | 732,544 (+9,205) | 1,524,107 (+20,607) |
| 2025-11-19 | 804,409 (+12,846) | 747,624 (+15,080) | 1,552,033 (+27,926) |
| 2025-11-20 | 814,620 (+10,211) | 757,907 (+10,283) | 1,572,527 (+20,494) |
| 2025-11-21 | 826,309 (+11,689) | 769,307 (+11,400) | 1,595,616 (+23,089) |
+12 -12
View File
@@ -41,7 +41,7 @@
},
"packages/console/core": {
"name": "@opencode-ai/console-core",
"version": "1.0.86",
"version": "1.0.85",
"dependencies": {
"@aws-sdk/client-sts": "3.782.0",
"@jsx-email/render": "1.1.1",
@@ -68,7 +68,7 @@
},
"packages/console/function": {
"name": "@opencode-ai/console-function",
"version": "1.0.86",
"version": "1.0.85",
"dependencies": {
"@ai-sdk/anthropic": "2.0.0",
"@ai-sdk/openai": "2.0.2",
@@ -92,7 +92,7 @@
},
"packages/console/mail": {
"name": "@opencode-ai/console-mail",
"version": "1.0.86",
"version": "1.0.85",
"dependencies": {
"@jsx-email/all": "2.2.3",
"@jsx-email/cli": "1.4.3",
@@ -116,7 +116,7 @@
},
"packages/desktop": {
"name": "@opencode-ai/desktop",
"version": "1.0.86",
"version": "1.0.85",
"dependencies": {
"@kobalte/core": "catalog:",
"@opencode-ai/sdk": "workspace:*",
@@ -156,7 +156,7 @@
},
"packages/function": {
"name": "@opencode-ai/function",
"version": "1.0.86",
"version": "1.0.85",
"dependencies": {
"@octokit/auth-app": "8.0.1",
"@octokit/rest": "22.0.0",
@@ -172,7 +172,7 @@
},
"packages/opencode": {
"name": "opencode",
"version": "1.0.86",
"version": "1.0.85",
"bin": {
"opencode": "./bin/opencode",
},
@@ -251,7 +251,7 @@
},
"packages/plugin": {
"name": "@opencode-ai/plugin",
"version": "1.0.86",
"version": "1.0.85",
"dependencies": {
"@opencode-ai/sdk": "workspace:*",
"zod": "catalog:",
@@ -271,7 +271,7 @@
},
"packages/sdk/js": {
"name": "@opencode-ai/sdk",
"version": "1.0.86",
"version": "1.0.85",
"devDependencies": {
"@hey-api/openapi-ts": "0.81.0",
"@tsconfig/node22": "catalog:",
@@ -282,7 +282,7 @@
},
"packages/slack": {
"name": "@opencode-ai/slack",
"version": "1.0.86",
"version": "1.0.85",
"dependencies": {
"@opencode-ai/sdk": "workspace:*",
"@slack/bolt": "^3.17.1",
@@ -295,7 +295,7 @@
},
"packages/ui": {
"name": "@opencode-ai/ui",
"version": "1.0.86",
"version": "1.0.85",
"dependencies": {
"@kobalte/core": "catalog:",
"@opencode-ai/sdk": "workspace:*",
@@ -325,7 +325,7 @@
},
"packages/util": {
"name": "@opencode-ai/util",
"version": "1.0.86",
"version": "1.0.85",
"dependencies": {
"zod": "catalog:",
},
@@ -335,7 +335,7 @@
},
"packages/web": {
"name": "@opencode-ai/web",
"version": "1.0.86",
"version": "1.0.85",
"dependencies": {
"@astrojs/cloudflare": "12.6.3",
"@astrojs/markdown-remark": "6.3.1",
+4 -7
View File
@@ -97,12 +97,8 @@ export const stripeWebhook = new stripe.WebhookEndpoint("StripeWebhookEndpoint",
],
})
const ZEN_MODELS = [
new sst.Secret("ZEN_MODELS1"),
new sst.Secret("ZEN_MODELS2"),
new sst.Secret("ZEN_MODELS3"),
new sst.Secret("ZEN_MODELS4"),
]
const ZEN_MODELS1 = new sst.Secret("ZEN_MODELS1")
const ZEN_MODELS2 = new sst.Secret("ZEN_MODELS2")
const STRIPE_SECRET_KEY = new sst.Secret("STRIPE_SECRET_KEY")
const AUTH_API_URL = new sst.Linkable("AUTH_API_URL", {
properties: { value: auth.url.apply((url) => url!) },
@@ -136,10 +132,11 @@ new sst.cloudflare.x.SolidStart("Console", {
AUTH_API_URL,
STRIPE_WEBHOOK_SECRET,
STRIPE_SECRET_KEY,
ZEN_MODELS1,
ZEN_MODELS2,
EMAILOCTOPUS_API_KEY,
AWS_SES_ACCESS_KEY_ID,
AWS_SES_SECRET_ACCESS_KEY,
...ZEN_MODELS,
...($dev
? [
new sst.Secret("CLOUDFLARE_DEFAULT_ACCOUNT_ID", process.env.CLOUDFLARE_DEFAULT_ACCOUNT_ID!),
+9 -125
View File
@@ -2,8 +2,9 @@
set -euo pipefail
APP=opencode
MUTED='\033[0;2m'
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
ORANGE='\033[38;2;255;140;0m'
NC='\033[0m' # No Color
@@ -44,11 +45,6 @@ case "$filename" in
;;
esac
if ! command -v unzip >/dev/null 2>&1; then
echo -e "${RED}Error: 'unzip' is required but not installed.${NC}"
exit 1
fi
INSTALL_DIR=$HOME/.opencode/bin
mkdir -p "$INSTALL_DIR"
@@ -71,8 +67,8 @@ print_message() {
local color=""
case $level in
info) color="${NC}" ;;
warning) color="${NC}" ;;
info) color="${GREEN}" ;;
warning) color="${YELLOW}" ;;
error) color="${RED}" ;;
esac
@@ -90,113 +86,18 @@ check_version() {
installed_version=$(echo $installed_version | awk '{print $2}')
if [[ "$installed_version" != "$specific_version" ]]; then
print_message info "${MUTED}Installed version: ${NC}$installed_version."
print_message info "Installed version: ${YELLOW}$installed_version."
else
print_message info "${MUTED}Version ${NC}$specific_version${MUTED} already installed"
print_message info "Version ${YELLOW}$specific_version${GREEN} already installed"
exit 0
fi
fi
}
unbuffered_sed() {
if echo | sed -u -e "" >/dev/null 2>&1; then
sed -nu "$@"
elif echo | sed -l -e "" >/dev/null 2>&1; then
sed -nl "$@"
else
local pad="$(printf "\n%512s" "")"
sed -ne "s/$/\\${pad}/" "$@"
fi
}
print_progress() {
local bytes="$1"
local length="$2"
[ "$length" -gt 0 ] || return 0
local width=50
local percent=$(( bytes * 100 / length ))
[ "$percent" -gt 100 ] && percent=100
local on=$(( percent * width / 100 ))
local off=$(( width - on ))
local filled=$(printf "%*s" "$on" "")
filled=${filled// /■}
local empty=$(printf "%*s" "$off" "")
empty=${empty// /・}
printf "\r${ORANGE}%s%s %3d%%${NC}" "$filled" "$empty" "$percent" >&4
}
download_with_progress() {
local url="$1"
local output="$2"
if [ -t 2 ]; then
exec 4>&2
else
exec 4>/dev/null
fi
local tmp_dir=${TMPDIR:-/tmp}
local basename="${tmp_dir}/opencode_install_$$"
local tracefile="${basename}.trace"
rm -f "$tracefile"
mkfifo "$tracefile"
# Hide cursor
printf "\033[?25l" >&4
trap "trap - RETURN; rm -f \"$tracefile\"; printf '\033[?25h' >&4; exec 4>&-" RETURN
(
curl --trace-ascii "$tracefile" -s -L -o "$output" "$url"
) &
local curl_pid=$!
unbuffered_sed \
-e 'y/ACDEGHLNORTV/acdeghlnortv/' \
-e '/^0000: content-length:/p' \
-e '/^<= recv data/p' \
"$tracefile" | \
{
local length=0
local bytes=0
while IFS=" " read -r -a line; do
[ "${#line[@]}" -lt 2 ] && continue
local tag="${line[0]} ${line[1]}"
if [ "$tag" = "0000: content-length:" ]; then
length="${line[2]}"
length=$(echo "$length" | tr -d '\r')
bytes=0
elif [ "$tag" = "<= recv" ]; then
local size="${line[3]}"
bytes=$(( bytes + size ))
if [ "$length" -gt 0 ]; then
print_progress "$bytes" "$length"
fi
fi
done
}
wait $curl_pid
local ret=$?
echo "" >&4
return $ret
}
download_and_install() {
print_message info "\n${MUTED}Installing ${NC}opencode ${MUTED}version: ${NC}$specific_version"
print_message info "Downloading ${ORANGE}opencode ${GREEN}version: ${YELLOW}$specific_version ${GREEN}..."
mkdir -p opencodetmp && cd opencodetmp
if [[ "$os" == "windows" ]] || ! download_with_progress "$url" "$filename"; then
# Fallback to standard curl on Windows or if custom progress fails
curl -# -L -o "$filename" "$url"
fi
curl -# -L -o "$filename" "$url"
unzip -q "$filename"
mv opencode "$INSTALL_DIR"
chmod 755 "${INSTALL_DIR}/opencode"
@@ -216,7 +117,7 @@ add_to_path() {
elif [[ -w $config_file ]]; then
echo -e "\n# opencode" >> "$config_file"
echo "$command" >> "$config_file"
print_message info "${MUTED}Successfully added ${NC}opencode ${MUTED}to \$PATH in ${NC}$config_file"
print_message info "Successfully added ${ORANGE}opencode ${GREEN}to \$PATH in $config_file"
else
print_message warning "Manually add the directory to $config_file (or similar):"
print_message info " $command"
@@ -290,20 +191,3 @@ if [ -n "${GITHUB_ACTIONS-}" ] && [ "${GITHUB_ACTIONS}" == "true" ]; then
echo "$INSTALL_DIR" >> $GITHUB_PATH
print_message info "Added $INSTALL_DIR to \$GITHUB_PATH"
fi
echo -e ""
echo -e "${MUTED}  ${NC} ▄ "
echo -e "${MUTED}█▀▀█ █▀▀█ █▀▀█ █▀▀▄ ${NC}█▀▀▀ █▀▀█ █▀▀█ █▀▀█"
echo -e "${MUTED}█░░█ █░░█ █▀▀▀ █░░█ ${NC}█░░░ █░░█ █░░█ █▀▀▀"
echo -e "${MUTED}▀▀▀▀ █▀▀▀ ▀▀▀▀ ▀ ▀ ${NC}▀▀▀▀ ▀▀▀▀ ▀▀▀▀ ▀▀▀▀"
echo -e ""
echo -e ""
echo -e "${MUTED}To get started, navigate to a project and run:${NC}"
echo -e "opencode ${MUTED}Use free models${NC}"
echo -e "opencode auth login ${MUTED}Add paid provider API keys${NC}"
echo -e "opencode help ${MUTED}List commands and options${NC}"
echo -e ""
echo -e "${MUTED}For more information visit ${NC}https://opencode.ai/docs"
echo -e ""
echo -e ""
+1 -1
View File
@@ -4,7 +4,7 @@
"description": "AI-powered development tool",
"private": true,
"type": "module",
"packageManager": "bun@1.3.3",
"packageManager": "bun@1.3.2",
"scripts": {
"dev": "bun run --cwd packages/opencode --conditions=browser src/index.ts",
"typecheck": "bun turbo typecheck",
+1 -1
View File
@@ -7,7 +7,7 @@
"dev:remote": "VITE_AUTH_URL=https://auth.dev.opencode.ai bun sst shell --stage=dev bun dev",
"build": "./script/generate-sitemap.ts && vinxi build && ../../opencode/script/schema.ts ./.output/public/config.json",
"start": "vinxi start",
"version": "1.0.86"
"version": "1.0.85"
},
"dependencies": {
"@ibm/plex": "6.4.1",
+1 -1
View File
@@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "@opencode-ai/console-core",
"version": "1.0.86",
"version": "1.0.85",
"private": true,
"type": "module",
"dependencies": {
+9 -10
View File
@@ -11,21 +11,20 @@ const root = path.resolve(process.cwd(), "..", "..", "..")
// read the secret
const ret = await $`bun sst secret list`.cwd(root).text()
const lines = ret.split("\n")
const value1 = lines.find((line) => line.startsWith("ZEN_MODELS1"))?.split("=")[1]
const value2 = lines.find((line) => line.startsWith("ZEN_MODELS2"))?.split("=")[1]
const value3 = lines.find((line) => line.startsWith("ZEN_MODELS3"))?.split("=")[1]
const value4 = lines.find((line) => line.startsWith("ZEN_MODELS4"))?.split("=")[1]
const value1 = ret
.split("\n")
.find((line) => line.startsWith("ZEN_MODELS1"))
?.split("=")[1]
const value2 = ret
.split("\n")
.find((line) => line.startsWith("ZEN_MODELS2"))
?.split("=")[1]
if (!value1) throw new Error("ZEN_MODELS1 not found")
if (!value2) throw new Error("ZEN_MODELS2 not found")
if (!value3) throw new Error("ZEN_MODELS3 not found")
if (!value4) throw new Error("ZEN_MODELS4 not found")
// validate value
ZenData.validate(JSON.parse(value1 + value2 + value3 + value4))
ZenData.validate(JSON.parse(value1 + value2))
// update the secret
await $`bun sst secret set ZEN_MODELS1 ${value1} --stage ${stage}`
await $`bun sst secret set ZEN_MODELS2 ${value2} --stage ${stage}`
await $`bun sst secret set ZEN_MODELS3 ${value3} --stage ${stage}`
await $`bun sst secret set ZEN_MODELS4 ${value4} --stage ${stage}`
+12 -17
View File
@@ -9,20 +9,21 @@ const root = path.resolve(process.cwd(), "..", "..", "..")
const models = await $`bun sst secret list`.cwd(root).text()
// read the line starting with "ZEN_MODELS"
const lines = models.split("\n")
const oldValue1 = lines.find((line) => line.startsWith("ZEN_MODELS1"))?.split("=")[1]
const oldValue2 = lines.find((line) => line.startsWith("ZEN_MODELS2"))?.split("=")[1]
const oldValue3 = lines.find((line) => line.startsWith("ZEN_MODELS3"))?.split("=")[1]
const oldValue4 = lines.find((line) => line.startsWith("ZEN_MODELS4"))?.split("=")[1]
const oldValue1 = models
.split("\n")
.find((line) => line.startsWith("ZEN_MODELS1"))
?.split("=")[1]
const oldValue2 = models
.split("\n")
.find((line) => line.startsWith("ZEN_MODELS2"))
?.split("=")[1]
if (!oldValue1) throw new Error("ZEN_MODELS1 not found")
if (!oldValue2) throw new Error("ZEN_MODELS2 not found")
if (!oldValue3) throw new Error("ZEN_MODELS3 not found")
if (!oldValue4) throw new Error("ZEN_MODELS4 not found")
// store the prettified json to a temp file
const filename = `models-${Date.now()}.json`
const tempFile = Bun.file(path.join(os.tmpdir(), filename))
await tempFile.write(JSON.stringify(JSON.parse(oldValue1 + oldValue2 + oldValue3 + oldValue4), null, 2))
await tempFile.write(JSON.stringify(JSON.parse(oldValue1 + oldValue2), null, 2))
console.log("tempFile", tempFile.name)
// open temp file in vim and read the file on close
@@ -31,12 +32,6 @@ const newValue = JSON.stringify(JSON.parse(await tempFile.text()))
ZenData.validate(JSON.parse(newValue))
// update the secret
const chunk = Math.ceil(newValue.length / 4)
const newValue1 = newValue.slice(0, chunk)
const newValue2 = newValue.slice(chunk, chunk * 2)
const newValue3 = newValue.slice(chunk * 2, chunk * 3)
const newValue4 = newValue.slice(chunk * 3)
await $`bun sst secret set ZEN_MODELS1 ${newValue1}`
await $`bun sst secret set ZEN_MODELS2 ${newValue2}`
await $`bun sst secret set ZEN_MODELS3 ${newValue3}`
await $`bun sst secret set ZEN_MODELS4 ${newValue4}`
const mid = Math.floor(newValue.length / 2)
await $`bun sst secret set ZEN_MODELS1 ${newValue.slice(0, mid)}`
await $`bun sst secret set ZEN_MODELS2 ${newValue.slice(mid)}`
+1 -3
View File
@@ -53,9 +53,7 @@ export namespace ZenData {
})
export const list = fn(z.void(), () => {
const json = JSON.parse(
Resource.ZEN_MODELS1.value + Resource.ZEN_MODELS2.value + Resource.ZEN_MODELS3.value + Resource.ZEN_MODELS4.value,
)
const json = JSON.parse(Resource.ZEN_MODELS1.value + Resource.ZEN_MODELS2.value)
return ModelsSchema.parse(json)
})
}
-8
View File
@@ -94,14 +94,6 @@ declare module "sst" {
type: "sst.sst.Secret"
value: string
}
ZEN_MODELS3: {
type: "sst.sst.Secret"
value: string
}
ZEN_MODELS4: {
type: "sst.sst.Secret"
value: string
}
}
}
// cloudflare
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/console-function",
"version": "1.0.86",
"version": "1.0.85",
"$schema": "https://json.schemastore.org/package.json",
"private": true,
"type": "module",
-8
View File
@@ -94,14 +94,6 @@ declare module "sst" {
type: "sst.sst.Secret"
value: string
}
ZEN_MODELS3: {
type: "sst.sst.Secret"
value: string
}
ZEN_MODELS4: {
type: "sst.sst.Secret"
value: string
}
}
}
// cloudflare
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/console-mail",
"version": "1.0.86",
"version": "1.0.85",
"dependencies": {
"@jsx-email/all": "2.2.3",
"@jsx-email/cli": "1.4.3",
-8
View File
@@ -94,14 +94,6 @@ declare module "sst" {
type: "sst.sst.Secret"
value: string
}
ZEN_MODELS3: {
type: "sst.sst.Secret"
value: string
}
ZEN_MODELS4: {
type: "sst.sst.Secret"
value: string
}
}
}
// cloudflare
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/desktop",
"version": "1.0.86",
"version": "1.0.85",
"description": "",
"type": "module",
"scripts": {
+6 -6
View File
@@ -1,7 +1,7 @@
id = "opencode"
name = "OpenCode"
description = "The AI coding agent built for the terminal"
version = "1.0.86"
version = "1.0.85"
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.86/opencode-darwin-arm64.zip"
archive = "https://github.com/sst/opencode/releases/download/v1.0.85/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.86/opencode-darwin-x64.zip"
archive = "https://github.com/sst/opencode/releases/download/v1.0.85/opencode-darwin-x64.zip"
cmd = "./opencode"
args = ["acp"]
[agent_servers.opencode.targets.linux-aarch64]
archive = "https://github.com/sst/opencode/releases/download/v1.0.86/opencode-linux-arm64.zip"
archive = "https://github.com/sst/opencode/releases/download/v1.0.85/opencode-linux-arm64.zip"
cmd = "./opencode"
args = ["acp"]
[agent_servers.opencode.targets.linux-x86_64]
archive = "https://github.com/sst/opencode/releases/download/v1.0.86/opencode-linux-x64.zip"
archive = "https://github.com/sst/opencode/releases/download/v1.0.85/opencode-linux-x64.zip"
cmd = "./opencode"
args = ["acp"]
[agent_servers.opencode.targets.windows-x86_64]
archive = "https://github.com/sst/opencode/releases/download/v1.0.86/opencode-windows-x64.zip"
archive = "https://github.com/sst/opencode/releases/download/v1.0.85/opencode-windows-x64.zip"
cmd = "./opencode.exe"
args = ["acp"]
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/function",
"version": "1.0.86",
"version": "1.0.85",
"$schema": "https://json.schemastore.org/package.json",
"private": true,
"type": "module",
-8
View File
@@ -94,14 +94,6 @@ declare module "sst" {
type: "sst.sst.Secret"
value: string
}
ZEN_MODELS3: {
type: "sst.sst.Secret"
value: string
}
ZEN_MODELS4: {
type: "sst.sst.Secret"
value: string
}
}
}
// cloudflare
+1 -1
View File
@@ -1,6 +1,6 @@
{
"$schema": "https://json.schemastore.org/package.json",
"version": "1.0.86",
"version": "1.0.85",
"name": "opencode",
"type": "module",
"private": true,
+65 -8
View File
@@ -599,20 +599,77 @@ export namespace Provider {
const provider = s.providers[providerID]
if (!provider) {
const availableProviders = Object.keys(s.providers)
const matches = fuzzysort.go(providerID, availableProviders, { limit: 3, threshold: -10000 })
const suggestions = matches.map((m) => m.target)
let suggestions: string[] = []
const normalize = (str: string) => str.toLowerCase().replace(/[^a-z0-9]/g, "")
const levenshtein = (a: string, b: string) => {
const m = a.length,
n = b.length
const dp = Array.from({ length: m + 1 }, () => new Array<number>(n + 1).fill(0))
for (let i = 0; i <= m; i++) dp[i][0] = i
for (let j = 0; j <= n; j++) dp[0][j] = j
for (let i = 1; i <= m; i++) {
for (let j = 1; j <= n; j++) {
const cost = a[i - 1] === b[j - 1] ? 0 : 1
dp[i][j] = Math.min(dp[i - 1][j] + 1, dp[i][j - 1] + 1, dp[i - 1][j - 1] + cost)
}
}
return dp[m][n]
}
if (!modelID || modelID.trim() === "") {
// Treat single-token input as an unqualified model; search across all providers' models.
const q = normalize(providerID)
const entries: { combo: string; norm: string }[] = []
for (const [pid, prov] of Object.entries(s.providers)) {
for (const mid of Object.keys(prov.info.models)) {
entries.push({ combo: pid + "/" + mid, norm: normalize(mid) })
}
}
const byNorm = fuzzysort.go(q, entries as any, { limit: 5, key: "norm" }).map((r: any) => r.obj.combo)
const combos = entries.map((e) => e.combo)
const byRaw = fuzzysort.go(providerID, combos, { limit: 5 }).map((r) => r.target)
let merged = Array.from(new Set([...byNorm, ...byRaw]))
if (merged.length === 0) {
// fallback to edit distance on normalized mid
const scored = entries
.map((e) => ({ combo: e.combo, d: levenshtein(q, e.norm) }))
.sort((a, b) => a.d - b.d)
.slice(0, 3)
.map((x) => x.combo)
merged = scored
}
suggestions = merged.slice(0, 3)
} else {
const pcands = Object.keys(s.providers)
const corpus = pcands.map((raw) => ({ raw, norm: normalize(raw) }))
const q = normalize(providerID)
const hits = fuzzysort.go(q, corpus as any, { limit: 5, key: "norm" })
let ranked = hits.map((r: any) => r.obj.raw)
if (ranked.length === 0) {
ranked = pcands
.map((p) => ({ p, d: levenshtein(q, normalize(p)) }))
.sort((a, b) => a.d - b.d)
.slice(0, 3)
.map((x) => x.p)
}
const providerSuggestions = ranked.map((r) => r + "/" + modelID)
suggestions = providerSuggestions
}
throw new ModelNotFoundError({ providerID, modelID, suggestions })
}
const info = provider.info.models[modelID]
if (!info) {
const availableModels = Object.keys(provider.info.models)
const matches = fuzzysort.go(modelID, availableModels, { limit: 3, threshold: -10000 })
const suggestions = matches.map((m) => m.target)
const candidates = Object.keys(provider.info.models)
// Normalize punctuation differences like '-' vs '.' by stripping non-alphanumerics
const normalize = (s: string) => s.toLowerCase().replace(/[^a-z0-9]/g, "")
const corpus = candidates.map((raw) => ({ raw, norm: normalize(raw) }))
const query = normalize(modelID)
const results = fuzzysort.go(query, corpus as any, { limit: 5, key: "norm" })
const ranked = results.map((r) => ("obj" in r ? (r as any).obj.raw : (r as any).target)) as string[]
const fallback = fuzzysort.go(modelID, candidates, { limit: 5 }).map((r) => r.target)
const merged = Array.from(new Set([...ranked, ...fallback]))
const suggestions = merged.slice(0, 3).map((m) => providerID + "/" + m)
throw new ModelNotFoundError({ providerID, modelID, suggestions })
}
const sdk = await getSDK(provider.info, info)
try {
+2 -2
View File
@@ -147,7 +147,7 @@ export namespace ProviderTransform {
result["promptCacheKey"] = sessionID
}
if (providerID === "google" || (providerID.startsWith("opencode") && modelID.includes("gemini-3"))) {
if (providerID === "google" || (providerID === "opencode" && modelID.includes("gemini-3"))) {
result["thinkingConfig"] = {
includeThoughts: true,
}
@@ -166,7 +166,7 @@ export namespace ProviderTransform {
result["textVerbosity"] = "low"
}
if (providerID.startsWith("opencode")) {
if (providerID === "opencode") {
result["promptCacheKey"] = sessionID
result["include"] = ["reasoning.encrypted_content"]
result["reasoningSummary"] = "auto"
-10
View File
@@ -813,18 +813,8 @@ export namespace Server {
async (c) => {
const id = c.req.valid("param").id
const body = c.req.valid("json")
const msgs = await Session.messages({ sessionID: id })
let currentAgent = "build"
for (let i = msgs.length - 1; i >= 0; i--) {
const info = msgs[i].info
if (info.role === "user") {
currentAgent = info.agent || "build"
break
}
}
await SessionCompaction.create({
sessionID: id,
agent: currentAgent,
model: {
providerID: body.providerID,
modelID: body.modelID,
+3 -5
View File
@@ -92,7 +92,6 @@ export namespace SessionCompaction {
providerID: string
modelID: string
}
agent: string
abort: AbortSignal
}) {
const model = await Provider.getModel(input.model.providerID, input.model.modelID)
@@ -102,7 +101,7 @@ export namespace SessionCompaction {
role: "assistant",
parentID: input.parentID,
sessionID: input.sessionID,
mode: input.agent,
mode: "build",
summary: true,
path: {
cwd: Instance.directory,
@@ -200,7 +199,7 @@ export namespace SessionCompaction {
time: {
created: Date.now(),
},
agent: input.agent,
agent: "build",
model: input.model,
})
await Session.updatePart({
@@ -223,7 +222,6 @@ export namespace SessionCompaction {
export const create = fn(
z.object({
sessionID: Identifier.schema("session"),
agent: z.string(),
model: z.object({
providerID: z.string(),
modelID: z.string(),
@@ -235,7 +233,7 @@ export namespace SessionCompaction {
role: "user",
model: input.model,
sessionID: input.sessionID,
agent: input.agent,
agent: "build",
time: {
created: Date.now(),
},
-2
View File
@@ -398,7 +398,6 @@ export namespace SessionPrompt {
messages: msgs,
parentID: lastUser.id,
abort,
agent: lastUser.agent,
model: {
providerID: model.providerID,
modelID: model.modelID,
@@ -417,7 +416,6 @@ export namespace SessionPrompt {
) {
await SessionCompaction.create({
sessionID,
agent: lastUser.agent,
model: lastUser.model,
})
continue
+2 -2
View File
@@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "@opencode-ai/plugin",
"version": "1.0.86",
"version": "1.0.85",
"type": "module",
"scripts": {
"typecheck": "tsgo --noEmit",
@@ -24,4 +24,4 @@
"typescript": "catalog:",
"@typescript/native-preview": "catalog:"
}
}
}
+2 -2
View File
@@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "@opencode-ai/sdk",
"version": "1.0.86",
"version": "1.0.85",
"type": "module",
"scripts": {
"typecheck": "tsgo --noEmit",
@@ -26,4 +26,4 @@
"publishConfig": {
"directory": "dist"
}
}
}
-6
View File
@@ -90,10 +90,4 @@ class Resource:
class ZEN_MODELS2:
type: str
value: str
class ZEN_MODELS3:
type: str
value: str
class ZEN_MODELS4:
type: str
value: str
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/slack",
"version": "1.0.86",
"version": "1.0.85",
"type": "module",
"scripts": {
"dev": "bun run src/index.ts",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/ui",
"version": "1.0.86",
"version": "1.0.85",
"type": "module",
"exports": {
".": "./src/components/index.ts",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/util",
"version": "1.0.86",
"version": "1.0.85",
"private": true,
"type": "module",
"exports": {
-9
View File
@@ -1,9 +0,0 @@
/* This file is auto-generated by SST. Do not edit. */
/* tslint:disable */
/* eslint-disable */
/* deno-fmt-ignore-file */
/// <reference path="../../sst-env.d.ts" />
import "sst"
export {}
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@opencode-ai/web",
"type": "module",
"version": "1.0.86",
"version": "1.0.85",
"scripts": {
"dev": "astro dev",
"dev:remote": "VITE_API_URL=https://api.opencode.ai astro dev",
+1 -1
View File
@@ -2,7 +2,7 @@
"name": "opencode",
"displayName": "opencode",
"description": "opencode for VS Code",
"version": "1.0.86",
"version": "1.0.85",
"publisher": "sst-dev",
"repository": {
"type": "git",
-8
View File
@@ -116,14 +116,6 @@ declare module "sst" {
type: "sst.sst.Secret"
value: string
}
ZEN_MODELS3: {
type: "sst.sst.Secret"
value: string
}
ZEN_MODELS4: {
type: "sst.sst.Secret"
value: string
}
}
}
/// <reference path="sst-env.d.ts" />