Compare commits

...

66 Commits

Author SHA1 Message Date
opencode-agent[bot] e7859f8c5c Apply PR #37927: fix(app): navigate tabs by selection history
publish / version (push) Waiting to run
publish / build-cli (push) Blocked by required conditions
publish / sign-cli-windows (push) Blocked by required conditions
publish / build-electron (map[bun_install_flags:--os=darwin --cpu=arm64 host:macos-26 platform_flag:--mac --arm64 target:aarch64-apple-darwin]) (push) Blocked by required conditions
publish / build-electron (map[bun_install_flags:--os=darwin --cpu=x64 host:macos-26-intel platform_flag:--mac --x64 target:x86_64-apple-darwin]) (push) Blocked by required conditions
publish / build-electron (map[host:blacksmith-4vcpu-ubuntu-2404 platform_flag:--linux target:x86_64-unknown-linux-gnu]) (push) Blocked by required conditions
publish / build-electron (map[host:blacksmith-4vcpu-ubuntu-2404-arm platform_flag:--linux --arm64 target:aarch64-unknown-linux-gnu]) (push) Blocked by required conditions
publish / build-electron (map[host:blacksmith-4vcpu-windows-2025 platform_flag:--win target:x86_64-pc-windows-msvc]) (push) Blocked by required conditions
publish / build-electron (map[host:windows-2025 platform_flag:--win --arm64 target:aarch64-pc-windows-msvc]) (push) Blocked by required conditions
publish / publish (push) Blocked by required conditions
2026-07-22 05:10:21 +00:00
opencode-agent[bot] d0697f9991 Apply PR #29948: fix(tui): keep command palette available in questions 2026-07-22 05:10:21 +00:00
Jack 0a601cf334 fix(docs): correct Kimi K2.7 Code request limits (#38248)
docs-locale-sync / sync-locales (push) Waiting to run
generate / generate (push) Waiting to run
nix-eval / nix-eval (push) Waiting to run
publish / version (push) Waiting to run
publish / build-cli (push) Blocked by required conditions
publish / sign-cli-windows (push) Blocked by required conditions
publish / build-electron (map[bun_install_flags:--os=darwin --cpu=arm64 host:macos-26 platform_flag:--mac --arm64 target:aarch64-apple-darwin]) (push) Blocked by required conditions
publish / build-electron (map[bun_install_flags:--os=darwin --cpu=x64 host:macos-26-intel platform_flag:--mac --x64 target:x86_64-apple-darwin]) (push) Blocked by required conditions
publish / build-electron (map[host:blacksmith-4vcpu-ubuntu-2404 platform_flag:--linux target:x86_64-unknown-linux-gnu]) (push) Blocked by required conditions
publish / build-electron (map[host:blacksmith-4vcpu-ubuntu-2404-arm platform_flag:--linux --arm64 target:aarch64-unknown-linux-gnu]) (push) Blocked by required conditions
publish / build-electron (map[host:blacksmith-4vcpu-windows-2025 platform_flag:--win target:x86_64-pc-windows-msvc]) (push) Blocked by required conditions
publish / build-electron (map[host:windows-2025 platform_flag:--win --arm64 target:aarch64-pc-windows-msvc]) (push) Blocked by required conditions
publish / publish (push) Blocked by required conditions
storybook / storybook build (push) Waiting to run
typecheck / typecheck (push) Waiting to run
deploy / deploy (push) Waiting to run
2026-07-22 12:42:44 +08:00
opencode-agent[bot] c9db6e9a1f fix(app): show running shell command (#38080)
Co-authored-by: Luke Parker <10430890+Hona@users.noreply.github.com>
2026-07-22 11:47:42 +10:00
opencode-agent[bot] 130038eb63 fix(app): defer unavailable notification state (#38186)
Co-authored-by: Luke Parker <10430890+Hona@users.noreply.github.com>
2026-07-22 11:16:51 +10:00
Frank 4438f69aac zen: add security check 2026-07-21 14:51:43 -04:00
opencode-agent[bot] 76ced5418f chore: generate 2026-07-21 18:43:01 +00:00
Frank c40e3e74a7 zen: add security check 2026-07-21 14:34:00 -04:00
Frank 0317531906 zen: add laguna-2-2.1 2026-07-21 12:59:49 -04:00
opencode-agent[bot] 5f241f1cc1 chore: generate 2026-07-21 15:19:02 +00:00
Daniel Polito b513fafe83 fix(app): support nested slash command autocomplete (#38097) 2026-07-21 23:08:23 +08:00
Daniel Polito 21c4c93770 fix(ui): improve progress circle contrast (#38101) 2026-07-21 23:08:09 +08:00
Frank abc4b83f58 Zen: gemini 3.6 flash and 3.5 flash lite 2026-07-21 10:59:30 -04:00
opencode-agent[bot] cb562b2c62 chore: generate 2026-07-21 09:58:21 +00:00
Aarav Sareen 2d2339d37d feat(app): draggable project rows (#38055) 2026-07-21 17:56:42 +08:00
Aiden Cline 849c2598ab docs: generalize session title model description (#37986)
docs-locale-sync / sync-locales (push) Waiting to run
generate / generate (push) Waiting to run
nix-hashes / compute-hash (blacksmith-4vcpu-ubuntu-2404, x86_64-linux) (push) Waiting to run
nix-hashes / compute-hash (blacksmith-4vcpu-ubuntu-2404-arm, aarch64-linux) (push) Waiting to run
nix-hashes / compute-hash (macos-15-intel, x86_64-darwin) (push) Waiting to run
nix-hashes / compute-hash (macos-latest, aarch64-darwin) (push) Waiting to run
nix-hashes / update-hashes (push) Blocked by required conditions
typecheck / typecheck (push) Waiting to run
deploy / deploy (push) Has been cancelled
nix-eval / nix-eval (push) Has been cancelled
publish / version (push) Has been cancelled
publish / build-cli (push) Has been cancelled
publish / sign-cli-windows (push) Has been cancelled
publish / build-electron (map[bun_install_flags:--os=darwin --cpu=arm64 host:macos-26 platform_flag:--mac --arm64 target:aarch64-apple-darwin]) (push) Has been cancelled
publish / build-electron (map[bun_install_flags:--os=darwin --cpu=x64 host:macos-26-intel platform_flag:--mac --x64 target:x86_64-apple-darwin]) (push) Has been cancelled
publish / build-electron (map[host:blacksmith-4vcpu-ubuntu-2404 platform_flag:--linux target:x86_64-unknown-linux-gnu]) (push) Has been cancelled
publish / build-electron (map[host:blacksmith-4vcpu-ubuntu-2404-arm platform_flag:--linux --arm64 target:aarch64-unknown-linux-gnu]) (push) Has been cancelled
publish / build-electron (map[host:blacksmith-4vcpu-windows-2025 platform_flag:--win target:x86_64-pc-windows-msvc]) (push) Has been cancelled
publish / build-electron (map[host:windows-2025 platform_flag:--win --arm64 target:aarch64-pc-windows-msvc]) (push) Has been cancelled
publish / publish (push) Has been cancelled
storybook / storybook build (push) Has been cancelled
2026-07-20 14:20:13 -05:00
Aiden Cline 3033afba51 fix(provider): normalize Mistral family tool call IDs (#37982)
Co-authored-by: tobwen <1864057+tobwen@users.noreply.github.com>
2026-07-20 13:58:49 -05:00
Matthias Reso 5a8ee27254 fix(provider): update muse-spark reasoning default and system prompt (#37562)
Co-authored-by: Aiden Cline <aidenpcline@gmail.com>
2026-07-20 13:15:42 -05:00
OpeOginni 4cc022481c fix(opencode): display proper session import errors (#36258) 2026-07-20 11:43:27 -05:00
opencode d36a2d8981 sync release versions for v1.18.4
deploy / deploy (push) Has been cancelled
2026-07-20 15:28:16 +00:00
opencode-agent[bot] 96ff82a11f fix(console): remove desktop promo overlay
Requested by: @thdxr (dax via Slack)
2026-07-20 15:28:00 +00:00
opencode-agent[bot] 4872c48c23 fix(app): complete mentions at cursor (#37941)
Co-authored-by: Brendan Allan <14191578+Brendonovich@users.noreply.github.com>
2026-07-20 22:53:10 +08:00
opencode-agent[bot] 47fc6f2991 fix(app): preserve mentions during paste (#37940)
Co-authored-by: Brendan Allan <14191578+Brendonovich@users.noreply.github.com>
2026-07-20 22:52:14 +08:00
opencode-agent[bot] da312b009c fix(app): preserve command menu drafts (#37942)
Co-authored-by: Brendan Allan <14191578+Brendonovich@users.noreply.github.com>
2026-07-20 22:49:39 +08:00
opencode-agent[bot] 70535a1bad chore: update nix node_modules hashes 2026-07-20 14:35:56 +00:00
Luke Parker 43e472bba7 feat(app): sync embedded terminal theme (#37931) 2026-07-20 14:22:26 +00:00
opencode-agent[bot] b67fda133a chore: update nix node_modules hashes 2026-07-20 13:24:20 +00:00
LukeParkerDev 985ee1e2ec fix(app): navigate tabs by selection history 2026-07-20 23:15:53 +10:00
Luke Parker e2531dff0f chore(app): bump ghostty-web (#37923)
Includes the physical-pixel rendering and native Ghostty sprite work from anomalyco/ghostty-web#3.
2026-07-20 13:09:46 +00:00
opencode-agent[bot] cc3615b535 fix(app): tolerate missing message parents (#37918)
Co-authored-by: Luke Parker <10430890+Hona@users.noreply.github.com>
2026-07-20 12:20:41 +00:00
Luke Parker 5542415b64 fix(app): shrink Windows drawer close button (#37909) 2026-07-20 11:21:22 +00:00
Luke Parker 8bec40a816 fix(app): align Windows upgrade drawer (#37895) 2026-07-20 10:32:38 +00:00
opencode-agent[bot] 4a81e8392b fix(app): gate notification server selection (#37890)
Co-authored-by: Luke Parker <10430890+Hona@users.noreply.github.com>
2026-07-20 09:22:18 +00:00
opencode-agent[bot] a19b52e85b fix(app): omit empty prompt text parts (#37577)
Co-authored-by: Jay <53023+jayair@users.noreply.github.com>
2026-07-20 17:09:06 +10:00
opencode-agent[bot] 9105f35966 chore: generate
deploy / deploy (push) Has been cancelled
nix-eval / nix-eval (push) Has been cancelled
publish / version (push) Has been cancelled
publish / build-cli (push) Has been cancelled
publish / sign-cli-windows (push) Has been cancelled
publish / build-electron (map[bun_install_flags:--os=darwin --cpu=arm64 host:macos-26 platform_flag:--mac --arm64 target:aarch64-apple-darwin]) (push) Has been cancelled
publish / build-electron (map[bun_install_flags:--os=darwin --cpu=x64 host:macos-26-intel platform_flag:--mac --x64 target:x86_64-apple-darwin]) (push) Has been cancelled
publish / build-electron (map[host:blacksmith-4vcpu-ubuntu-2404 platform_flag:--linux target:x86_64-unknown-linux-gnu]) (push) Has been cancelled
publish / build-electron (map[host:blacksmith-4vcpu-ubuntu-2404-arm platform_flag:--linux --arm64 target:aarch64-unknown-linux-gnu]) (push) Has been cancelled
publish / build-electron (map[host:blacksmith-4vcpu-windows-2025 platform_flag:--win target:x86_64-pc-windows-msvc]) (push) Has been cancelled
publish / build-electron (map[host:windows-2025 platform_flag:--win --arm64 target:aarch64-pc-windows-msvc]) (push) Has been cancelled
publish / publish (push) Has been cancelled
storybook / storybook build (push) Has been cancelled
docs-locale-sync / sync-locales (push) Has been cancelled
generate / generate (push) Has been cancelled
typecheck / typecheck (push) Has been cancelled
2026-07-20 06:50:36 +00:00
Aarav Sareen 3ba3954aa0 feat(app): review panel improvements (#36716)
Co-authored-by: LukeParkerDev <10430890+Hona@users.noreply.github.com>
2026-07-20 06:49:23 +00:00
Aarav Sareen 3fc5af6dd1 feat(app): update settings description line height (#37759) 2026-07-20 15:57:11 +10:00
opencode-agent[bot] 5586f9675e fix(app): restore model variant accessibility (#37857)
Co-authored-by: Aiden Cline <rekram1-node@users.noreply.github.com>
2026-07-20 05:20:56 +00:00
opencode-agent[bot] 3b719aba48 chore: generate 2026-07-20 04:55:12 +00:00
Qiping Li 20a3a2138e feat(opencode): use adaptive thinking effort for kimi family on anthr… (#37696)
Co-authored-by: liqiping <liqiping@msh.team>
Co-authored-by: Aiden Cline <aidenpcline@gmail.com>
2026-07-19 23:54:00 -05:00
Frank cd46f22d51 sync 2026-07-19 23:55:16 -04:00
Frank cfa134f042 Merge branch 'dev' of github.com:anomalyco/opencode into dev
deploy / deploy (push) Has been cancelled
2026-07-19 23:30:38 -04:00
Frank 61653a20a5 sync 2026-07-19 23:30:36 -04:00
opencode-agent[bot] 2a097f3af7 fix(llm): expand context overflow patterns (#37840)
Co-authored-by: Aiden Cline <rekram1-node@users.noreply.github.com>
2026-07-19 22:15:21 -05:00
David Hill ba4b8e21f4 feat(app): toggle debug tools from dev badge (#36689)
Co-authored-by: LukeParkerDev <10430890+Hona@users.noreply.github.com>
2026-07-20 12:22:48 +10:00
Rahul A Mistry 7985c2066a fix(app): show keybind tooltips on prompt input controls (#37824) 2026-07-20 10:22:38 +10:00
opencode-agent[bot] 67caf894e0 fix(opencode): increase OpenAI header timeout (#37770)
Co-authored-by: Aiden Cline <rekram1-node@users.noreply.github.com>
2026-07-19 10:41:48 -05:00
opencode-agent[bot] 78587c141b fix(app): restore question pager segments (#37575)
Co-authored-by: Jay <53023+jayair@users.noreply.github.com>
2026-07-19 13:00:57 +00:00
opencode-agent[bot] f5573281ca chore: generate 2026-07-19 07:46:36 +00:00
opencode-agent[bot] 4817228f96 docs(go): update Kimi K3 request estimates (#37725)
Co-authored-by: Frank <frank@anoma.ly>
2026-07-19 03:45:27 -04:00
Frank 5a5117b36c Merge branch 'dev' of github.com:anomalyco/opencode into dev
nix-eval / nix-eval (push) Has been cancelled
publish / version (push) Has been cancelled
publish / build-cli (push) Has been cancelled
publish / sign-cli-windows (push) Has been cancelled
publish / build-electron (map[bun_install_flags:--os=darwin --cpu=arm64 host:macos-26 platform_flag:--mac --arm64 target:aarch64-apple-darwin]) (push) Has been cancelled
publish / build-electron (map[bun_install_flags:--os=darwin --cpu=x64 host:macos-26-intel platform_flag:--mac --x64 target:x86_64-apple-darwin]) (push) Has been cancelled
publish / build-electron (map[host:blacksmith-4vcpu-ubuntu-2404 platform_flag:--linux target:x86_64-unknown-linux-gnu]) (push) Has been cancelled
publish / build-electron (map[host:blacksmith-4vcpu-ubuntu-2404-arm platform_flag:--linux --arm64 target:aarch64-unknown-linux-gnu]) (push) Has been cancelled
publish / build-electron (map[host:blacksmith-4vcpu-windows-2025 platform_flag:--win target:x86_64-pc-windows-msvc]) (push) Has been cancelled
publish / build-electron (map[host:windows-2025 platform_flag:--win --arm64 target:aarch64-pc-windows-msvc]) (push) Has been cancelled
publish / publish (push) Has been cancelled
storybook / storybook build (push) Has been cancelled
deploy / deploy (push) Has been cancelled
containers / build (push) Has been cancelled
docs-locale-sync / sync-locales (push) Has been cancelled
generate / generate (push) Has been cancelled
nix-hashes / compute-hash (blacksmith-4vcpu-ubuntu-2404, x86_64-linux) (push) Has been cancelled
nix-hashes / compute-hash (blacksmith-4vcpu-ubuntu-2404-arm, aarch64-linux) (push) Has been cancelled
nix-hashes / compute-hash (macos-15-intel, x86_64-darwin) (push) Has been cancelled
nix-hashes / compute-hash (macos-latest, aarch64-darwin) (push) Has been cancelled
typecheck / typecheck (push) Has been cancelled
nix-hashes / update-hashes (push) Has been cancelled
2026-07-19 02:50:38 -04:00
Frank 6a288426b8 go: support openai route 2026-07-19 02:50:36 -04:00
usrnk1 573ac85983 feat(desktop): align new session project picker (#37461)
Co-authored-by: Brendan Allan <14191578+Brendonovich@users.noreply.github.com>
Co-authored-by: LukeParkerDev <10430890+Hona@users.noreply.github.com>
2026-07-19 16:15:54 +10:00
Frank 1221bbbe14 Merge branch 'dev' of github.com:anomalyco/opencode into dev 2026-07-19 02:08:19 -04:00
Frank 6bea0f4fa4 zen: grok 4.5 adjusted price 2026-07-19 02:08:05 -04:00
usrnk1 cc34084dfe feat(desktop): prevent overlapping composer borders (#37490) 2026-07-19 16:01:16 +10:00
opencode-agent[bot] b8142c7aa8 chore: update nix node_modules hashes 2026-07-18 17:54:17 +00:00
Simon Klee ba3f966ed0 build: bump opentui to 0.4.5 (#37616) 2026-07-18 19:40:12 +02:00
Jérôme Benoit b95fe7b2d7 fix(nix): restore desktop integration (#37197)
Co-authored-by: Test User <test@test.com>
2026-07-18 10:41:44 -05:00
Jérôme Benoit 9da9ed9de6 fix(nix): relax Bun version check for desktop build (#36767)
Co-authored-by: Test User <test@test.com>
2026-07-18 10:41:15 -05:00
opencode-agent[bot] fab2133129 chore: configure trust center domain (#36910)
deploy / deploy (push) Has been cancelled
nix-eval / nix-eval (push) Has been cancelled
nix-hashes / compute-hash (blacksmith-4vcpu-ubuntu-2404, x86_64-linux) (push) Has been cancelled
nix-hashes / compute-hash (blacksmith-4vcpu-ubuntu-2404-arm, aarch64-linux) (push) Has been cancelled
nix-hashes / compute-hash (macos-15-intel, x86_64-darwin) (push) Has been cancelled
nix-hashes / compute-hash (macos-latest, aarch64-darwin) (push) Has been cancelled
nix-hashes / update-hashes (push) Has been cancelled
publish / version (push) Has been cancelled
publish / build-cli (push) Has been cancelled
publish / sign-cli-windows (push) Has been cancelled
publish / build-electron (map[bun_install_flags:--os=darwin --cpu=arm64 host:macos-26 platform_flag:--mac --arm64 target:aarch64-apple-darwin]) (push) Has been cancelled
publish / build-electron (map[bun_install_flags:--os=darwin --cpu=x64 host:macos-26-intel platform_flag:--mac --x64 target:x86_64-apple-darwin]) (push) Has been cancelled
publish / build-electron (map[host:blacksmith-4vcpu-ubuntu-2404 platform_flag:--linux target:x86_64-unknown-linux-gnu]) (push) Has been cancelled
publish / build-electron (map[host:blacksmith-4vcpu-ubuntu-2404-arm platform_flag:--linux --arm64 target:aarch64-unknown-linux-gnu]) (push) Has been cancelled
publish / build-electron (map[host:blacksmith-4vcpu-windows-2025 platform_flag:--win target:x86_64-pc-windows-msvc]) (push) Has been cancelled
publish / build-electron (map[host:windows-2025 platform_flag:--win --arm64 target:aarch64-pc-windows-msvc]) (push) Has been cancelled
publish / publish (push) Has been cancelled
storybook / storybook build (push) Has been cancelled
docs-locale-sync / sync-locales (push) Has been cancelled
generate / generate (push) Has been cancelled
typecheck / typecheck (push) Has been cancelled
Co-authored-by: opencode-agent[bot] <opencode-agent[bot]@users.noreply.github.com>
2026-07-18 02:51:31 -04:00
opencode-agent[bot] 901c9e7329 fix(app): disable unavailable file navigation (#37595)
Co-authored-by: opencode-agent[bot] <opencode-agent[bot]@users.noreply.github.com>
2026-07-18 15:39:15 +10:00
opencode-agent[bot] 3476e6baa5 chore: update nix node_modules hashes 2026-07-18 03:05:17 +00:00
opencode-agent[bot] 86e04d4174 revert(tui): downgrade opentui to 0.4.3 (#37582)
Co-authored-by: Aiden Cline <rekram1-node@users.noreply.github.com>
2026-07-17 21:51:48 -05:00
Test 83bee1e776 Merge remote-tracking branch 'origin/dev' into beta-sync-29948
# Conflicts:
#	packages/tui/test/keymap.test.tsx
2026-06-25 07:02:20 +00:00
opencode-agent[bot] 124714ca3a fix(tui): keep command palette available in questions 2026-05-29 23:19:01 +00:00
173 changed files with 5955 additions and 1629 deletions
+30 -30
View File
@@ -29,7 +29,7 @@
},
"packages/app": {
"name": "@opencode-ai/app",
"version": "1.18.3",
"version": "1.18.4",
"dependencies": {
"@corvu/drawer": "catalog:",
"@dnd-kit/abstract": "0.5.0",
@@ -65,7 +65,7 @@
"diff": "catalog:",
"effect": "catalog:",
"fuzzysort": "catalog:",
"ghostty-web": "github:anomalyco/ghostty-web#513463a6f1190253057e8a3f0dac8f6ee8393553",
"ghostty-web": "github:anomalyco/ghostty-web#83c0a07b8628b748aed073b232cb4b52a6ca11c1",
"luxon": "catalog:",
"marked": "catalog:",
"marked-shiki": "catalog:",
@@ -95,7 +95,7 @@
},
"packages/cli": {
"name": "@opencode-ai/cli",
"version": "1.18.3",
"version": "1.18.4",
"bin": {
"lildax": "./bin/lildax.cjs",
},
@@ -143,7 +143,7 @@
},
"packages/codemode": {
"name": "@opencode-ai/codemode",
"version": "1.18.3",
"version": "1.18.4",
"dependencies": {
"acorn": "8.15.0",
"effect": "catalog:",
@@ -157,7 +157,7 @@
},
"packages/console/app": {
"name": "@opencode-ai/console-app",
"version": "1.18.3",
"version": "1.18.4",
"dependencies": {
"@cloudflare/vite-plugin": "1.15.2",
"@ibm/plex": "6.4.1",
@@ -193,7 +193,7 @@
},
"packages/console/core": {
"name": "@opencode-ai/console-core",
"version": "1.18.3",
"version": "1.18.4",
"dependencies": {
"@aws-sdk/client-sts": "3.782.0",
"@jsx-email/render": "1.1.1",
@@ -220,7 +220,7 @@
},
"packages/console/function": {
"name": "@opencode-ai/console-function",
"version": "1.18.3",
"version": "1.18.4",
"dependencies": {
"@ai-sdk/anthropic": "3.0.82",
"@ai-sdk/openai": "3.0.48",
@@ -242,7 +242,7 @@
},
"packages/console/mail": {
"name": "@opencode-ai/console-mail",
"version": "1.18.3",
"version": "1.18.4",
"dependencies": {
"@jsx-email/all": "2.2.3",
"@jsx-email/cli": "1.4.3",
@@ -266,7 +266,7 @@
},
"packages/console/support": {
"name": "@opencode-ai/console-support",
"version": "1.18.3",
"version": "1.18.4",
"dependencies": {
"@cloudflare/vite-plugin": "1.15.2",
"@opencode-ai/console-core": "workspace:*",
@@ -286,7 +286,7 @@
},
"packages/core": {
"name": "@opencode-ai/core",
"version": "1.18.3",
"version": "1.18.4",
"bin": {
"opencode": "./bin/opencode",
},
@@ -380,7 +380,7 @@
},
"packages/desktop": {
"name": "@opencode-ai/desktop",
"version": "1.18.3",
"version": "1.18.4",
"dependencies": {
"@zip.js/zip.js": "2.7.62",
"effect": "catalog:",
@@ -434,7 +434,7 @@
},
"packages/effect-drizzle-sqlite": {
"name": "@opencode-ai/effect-drizzle-sqlite",
"version": "1.18.3",
"version": "1.18.4",
"dependencies": {
"drizzle-orm": "catalog:",
"effect": "catalog:",
@@ -448,7 +448,7 @@
},
"packages/effect-sqlite-node": {
"name": "@opencode-ai/effect-sqlite-node",
"version": "1.18.3",
"version": "1.18.4",
"dependencies": {
"effect": "catalog:",
},
@@ -460,7 +460,7 @@
},
"packages/enterprise": {
"name": "@opencode-ai/enterprise",
"version": "1.18.3",
"version": "1.18.4",
"dependencies": {
"@hono/standard-validator": "catalog:",
"@opencode-ai/core": "workspace:*",
@@ -492,7 +492,7 @@
},
"packages/function": {
"name": "@opencode-ai/function",
"version": "1.18.3",
"version": "1.18.4",
"dependencies": {
"@octokit/auth-app": "8.0.1",
"@octokit/rest": "catalog:",
@@ -508,7 +508,7 @@
},
"packages/http-recorder": {
"name": "@opencode-ai/http-recorder",
"version": "1.18.3",
"version": "1.18.4",
"dependencies": {
"@effect/platform-node": "4.0.0-beta.83",
"@effect/platform-node-shared": "4.0.0-beta.83",
@@ -539,7 +539,7 @@
},
"packages/llm": {
"name": "@opencode-ai/llm",
"version": "1.18.3",
"version": "1.18.4",
"dependencies": {
"@opencode-ai/schema": "workspace:*",
"@smithy/eventstream-codec": "4.2.14",
@@ -558,7 +558,7 @@
},
"packages/opencode": {
"name": "opencode",
"version": "1.18.3",
"version": "1.18.4",
"bin": {
"opencode": "./bin/opencode",
},
@@ -689,7 +689,7 @@
},
"packages/plugin": {
"name": "@opencode-ai/plugin",
"version": "1.18.3",
"version": "1.18.4",
"dependencies": {
"@ai-sdk/provider": "3.0.8",
"@opencode-ai/sdk": "workspace:*",
@@ -765,7 +765,7 @@
},
"packages/sdk/js": {
"name": "@opencode-ai/sdk",
"version": "1.18.3",
"version": "1.18.4",
"dependencies": {
"cross-spawn": "catalog:",
},
@@ -780,7 +780,7 @@
},
"packages/server": {
"name": "@opencode-ai/server",
"version": "1.18.3",
"version": "1.18.4",
"dependencies": {
"@opencode-ai/core": "workspace:*",
"@opencode-ai/protocol": "workspace:*",
@@ -795,7 +795,7 @@
},
"packages/session-ui": {
"name": "@opencode-ai/session-ui",
"version": "1.18.3",
"version": "1.18.4",
"dependencies": {
"@kobalte/core": "catalog:",
"@opencode-ai/core": "workspace:*",
@@ -839,7 +839,7 @@
},
"packages/slack": {
"name": "@opencode-ai/slack",
"version": "1.18.3",
"version": "1.18.4",
"dependencies": {
"@opencode-ai/sdk": "workspace:*",
"@slack/bolt": "^3.17.1",
@@ -852,7 +852,7 @@
},
"packages/stats/app": {
"name": "@opencode-ai/stats-app",
"version": "1.18.3",
"version": "1.18.4",
"dependencies": {
"@ibm/plex": "6.4.1",
"@kobalte/core": "catalog:",
@@ -886,7 +886,7 @@
},
"packages/stats/core": {
"name": "@opencode-ai/stats-core",
"version": "1.18.3",
"version": "1.18.4",
"dependencies": {
"@aws-sdk/client-athena": "3.933.0",
"@planetscale/database": "1.19.0",
@@ -905,7 +905,7 @@
},
"packages/stats/server": {
"name": "@opencode-ai/stats-server",
"version": "1.18.3",
"version": "1.18.4",
"dependencies": {
"@aws-sdk/client-firehose": "3.933.0",
"@effect/platform-node": "catalog:",
@@ -947,7 +947,7 @@
},
"packages/tui": {
"name": "@opencode-ai/tui",
"version": "1.18.3",
"version": "1.18.4",
"dependencies": {
"@opencode-ai/core": "workspace:*",
"@opencode-ai/plugin": "workspace:*",
@@ -974,7 +974,7 @@
},
"packages/ui": {
"name": "@opencode-ai/ui",
"version": "1.18.3",
"version": "1.18.4",
"dependencies": {
"@kobalte/core": "catalog:",
"@pierre/diffs": "catalog:",
@@ -1025,7 +1025,7 @@
},
"packages/web": {
"name": "@opencode-ai/web",
"version": "1.18.3",
"version": "1.18.4",
"dependencies": {
"@astrojs/cloudflare": "12.6.3",
"@astrojs/markdown-remark": "6.3.1",
@@ -3845,7 +3845,7 @@
"get-tsconfig": ["get-tsconfig@4.14.0", "", { "dependencies": { "resolve-pkg-maps": "^1.0.0" } }, "sha512-yTb+8DXzDREzgvYmh6s9vHsSVCHeC0G3PI5bEXNBHtmshPnO+S5O7qgLEOn0I5QvMy6kpZN8K1NKGyilLb93wA=="],
"ghostty-web": ["ghostty-web@github:anomalyco/ghostty-web#513463a", {}, "anomalyco-ghostty-web-513463a", "sha512-GZR8LSmgGzViWnBJrqRI8MpAZRCJxhcr1Hi9Tyeh7YRooHZQjK9J97FQRD3tbBaM2wjq05gzGY2UEsG+JtZeBw=="],
"ghostty-web": ["ghostty-web@github:anomalyco/ghostty-web#83c0a07", {}, "anomalyco-ghostty-web-83c0a07", "sha512-Lf2v1agHkVUpMpHBWWuCZrhOEmcwwin5/Hboc9rZwQ7/CKkIh5rU1r1CvfLlhkMoFv+ed8z52RZ8hkzGZZj3MQ=="],
"giget": ["giget@2.0.0", "", { "dependencies": { "citty": "^0.1.6", "consola": "^3.4.0", "defu": "^6.1.4", "node-fetch-native": "^1.6.6", "nypm": "^0.6.0", "pathe": "^2.0.3" }, "bin": { "giget": "dist/cli.mjs" } }, "sha512-L5bGsVkxJbJgdnwyuheIunkGatUF/zssUoxxjACCseZYAVbaqdh9Tsmmlkl8vYan09H7sbvKt4pS8GqKLBrEzA=="],
+19
View File
@@ -8,6 +8,25 @@ export const zoneID = "430ba34c138cfb5360826c4909f99be8"
export const awsStage = $app.stage === "production" ? "production" : "dev"
export const deployAws = $app.stage === awsStage
if ($app.stage === "production") {
new cloudflare.DnsRecord("TrustCenter", {
zoneId: zoneID,
name: "trust.opencode.ai",
type: "CNAME",
content: "3a69a5bb27875189.vercel-dns-016.com",
proxied: false,
ttl: 60,
})
new cloudflare.DnsRecord("TrustCenterVerification", {
zoneId: zoneID,
name: "opencode.ai",
type: "TXT",
content: "compai-domain-verification=org_6993a99c6200a2d642bb115d",
ttl: 60,
})
}
new cloudflare.RegionalHostname("RegionalHostname", {
hostname: domain,
regionKey: "us",
+66 -33
View File
@@ -8,6 +8,8 @@
makeWrapper,
writableTmpDirAsHomeHook,
autoPatchelfHook,
copyDesktopItems,
makeDesktopItem,
opencode,
}:
let
@@ -27,9 +29,12 @@ stdenv.mkDerivation (finalAttrs: {
nodejs
makeWrapper
writableTmpDirAsHomeHook
] ++ lib.optionals stdenv.hostPlatform.isLinux [
]
++ lib.optionals stdenv.hostPlatform.isLinux [
autoPatchelfHook
] ++ lib.optionals stdenv.hostPlatform.isDarwin [
copyDesktopItems
]
++ lib.optionals stdenv.hostPlatform.isDarwin [
# Ad-hoc sign the .app: --config.mac.identity=null below skips signing.
darwin.autoSignDarwinBinariesHook
];
@@ -38,20 +43,37 @@ stdenv.mkDerivation (finalAttrs: {
(lib.getLib stdenv.cc.cc)
];
desktopItems = lib.optional stdenv.hostPlatform.isLinux (makeDesktopItem {
name = "ai.opencode.desktop";
desktopName = "OpenCode";
exec = "opencode-desktop %U";
icon = "ai.opencode.desktop";
# Electron 41 derives X11 WM_CLASS from app.name.
startupWMClass = "OpenCode";
categories = [ "Development" ];
});
env = opencode.env // {
ELECTRON_SKIP_BINARY_DOWNLOAD = "1";
};
# https://github.com/electron/electron/issues/31121
# mac builds use a .app bundle which doesnt have this issue
postPatch = lib.optionalString stdenv.isLinux ''
BASE_PATH=packages/desktop
FILES=(src/main/windows.ts)
for file in "''${FILES[@]}"; do
substituteInPlace $BASE_PATH/$file \
--replace-fail "process.resourcesPath" "'$out/opt/opencode-desktop/resources'"
done
'';
postPatch =
# NOTE: Relax Bun version check to be a warning instead of an error
''
substituteInPlace packages/script/src/index.ts \
--replace-fail 'throw new Error(`This script requires bun@''${expectedBunVersionRange}' \
'console.warn(`Warning: This script requires bun@''${expectedBunVersionRange}'
''
# https://github.com/electron/electron/issues/31121
# mac builds use a .app bundle which doesnt have this issue
+ lib.optionalString stdenv.isLinux ''
BASE_PATH=packages/desktop
FILES=(src/main/windows.ts)
for file in "''${FILES[@]}"; do
substituteInPlace $BASE_PATH/$file \
--replace-fail "process.resourcesPath" "'$out/opt/opencode-desktop/resources'"
done
'';
preBuild = ''
cp -r "${electron.dist}" $HOME/.electron-dist
@@ -76,27 +98,38 @@ stdenv.mkDerivation (finalAttrs: {
runHook postBuild
'';
installPhase =
''
runHook preInstall
''
+ lib.optionalString stdenv.hostPlatform.isDarwin ''
mkdir -p $out/Applications
mv dist/mac*/*.app $out/Applications
makeWrapper "$out/Applications/OpenCode.app/Contents/MacOS/OpenCode" $out/bin/opencode-desktop
''
+ lib.optionalString stdenv.hostPlatform.isLinux ''
mkdir -p $out/opt/opencode-desktop
cp -r dist/linux*-unpacked/{resources,LICENSE*} $out/opt/opencode-desktop
makeWrapper ${lib.getExe electron} $out/bin/opencode-desktop \
--inherit-argv0 \
--set ELECTRON_FORCE_IS_PACKAGED 1 \
--add-flags $out/opt/opencode-desktop/resources/app.asar \
--add-flags "\''${NIXOS_OZONE_WL:+\''${WAYLAND_DISPLAY:+--ozone-platform-hint=auto --enable-features=WaylandWindowDecorations --enable-wayland-ime=true}}"
''
+ ''
runHook postInstall
'';
installPhase = ''
runHook preInstall
''
+ lib.optionalString stdenv.hostPlatform.isDarwin ''
mkdir -p $out/Applications
mv dist/mac*/*.app $out/Applications
makeWrapper "$out/Applications/OpenCode.app/Contents/MacOS/OpenCode" $out/bin/opencode-desktop
''
+ lib.optionalString stdenv.hostPlatform.isLinux ''
mkdir -p $out/opt/opencode-desktop
cp -r dist/linux*-unpacked/{resources,LICENSE*} $out/opt/opencode-desktop
install -Dm644 resources/icons/32x32.png \
"$out/share/icons/hicolor/32x32/apps/ai.opencode.desktop.png"
install -Dm644 resources/icons/64x64.png \
"$out/share/icons/hicolor/64x64/apps/ai.opencode.desktop.png"
install -Dm644 resources/icons/128x128.png \
"$out/share/icons/hicolor/128x128/apps/ai.opencode.desktop.png"
install -Dm644 resources/icons/128x128@2x.png \
"$out/share/icons/hicolor/256x256/apps/ai.opencode.desktop.png"
install -Dm644 resources/icons/icon.png \
"$out/share/icons/hicolor/512x512/apps/ai.opencode.desktop.png"
install -Dm644 resources/ai.opencode.desktop.metainfo.xml \
"$out/share/metainfo/ai.opencode.desktop.metainfo.xml"
makeWrapper ${lib.getExe electron} $out/bin/opencode-desktop \
--inherit-argv0 \
--set ELECTRON_FORCE_IS_PACKAGED 1 \
--add-flags $out/opt/opencode-desktop/resources/app.asar \
--add-flags "\''${NIXOS_OZONE_WL:+\''${WAYLAND_DISPLAY:+--ozone-platform-hint=auto --enable-features=WaylandWindowDecorations --enable-wayland-ime=true}}"
''
+ ''
runHook postInstall
'';
autoPatchelfIgnoreMissingDeps = [
"libc.musl-x86_64.so.1"
+4 -4
View File
@@ -1,8 +1,8 @@
{
"nodeModules": {
"x86_64-linux": "sha256-zAftZieWR0hWQQVkhEa826iueHaRnKxtyRodhNb+Apc=",
"aarch64-linux": "sha256-cTG+gB7CuiFgaYHSFbzXaXUI1C2kiugV3B9rUDRUwlg=",
"aarch64-darwin": "sha256-ap4Xv5ZliourkI4mcD0ktbzSI88jb4oVBv5mMK3WdUs=",
"x86_64-darwin": "sha256-NGRJMMnaMNrf3FkcYwr5PcfVm5thhlNLGIeMmAK0MeE="
"x86_64-linux": "sha256-qt11SKmOjq0KU542QFbs+u7YyJicn4drCcwCdg325yk=",
"aarch64-linux": "sha256-z68doReXTrWS7HeiAjc0btIjAsvzeZZ7hXAlHr0c77Q=",
"aarch64-darwin": "sha256-PILYH1Pi8XBvSkuZ+1sNnUTao5kba+m5Z8iJKx6YXPo=",
"x86_64-darwin": "sha256-KpcJzP4m0SUavu/WaSffgzOxrHq8ljdy0GOzs9p16lo="
}
}
@@ -0,0 +1,50 @@
import { expect, test } from "@playwright/test"
import { base64Encode } from "@opencode-ai/core/util/encode"
import { mockOpenCodeServer } from "../utils/mock-server"
import { expectAppVisible } from "../utils/waits"
const directory = "C:/OpenCode/PromptInputV2Editing"
const projectID = "proj_prompt_input_v2_editing"
const sessionID = "ses_prompt_input_v2_editing"
test("preserves the draft when a populated command menu triggers a built-in", async ({ page }) => {
await mockOpenCodeServer(page, {
directory,
project: {
id: projectID,
worktree: directory,
vcs: "git",
name: "prompt-input-v2-editing",
time: { created: 1700000000000, updated: 1700000000000 },
sandboxes: [],
},
provider: { all: [], connected: [], default: {} },
sessions: [
{
id: sessionID,
slug: "prompt-input-v2-editing",
projectID,
directory,
title: "Prompt input V2 editing",
version: "dev",
time: { created: 1700000000000, updated: 1700000000000 },
},
],
pageMessages: () => ({ items: [] }),
})
await page.addInitScript(() => {
localStorage.setItem("settings.v3", JSON.stringify({ general: { newLayoutDesigns: true } }))
})
await page.goto(`/${base64Encode(directory)}/session/${sessionID}`)
const composer = page.locator('[data-component="prompt-input-v2"]')
const input = composer.locator('[data-component="prompt-input"]')
await expectAppVisible(composer)
await input.fill("keep me")
await composer.getByRole("button", { name: "Add images and files" }).click()
await page.getByRole("menuitem", { name: "Commands" }).click()
await page.locator('[data-suggestion-id="model.choose"]').click()
await expect(input).toHaveText("keep me")
})
@@ -56,7 +56,7 @@ test("shows the V2 thinking level control while relevant", async ({ page }) => {
await page.goto(`/${base64Encode(directory)}/session/${sessionID}`)
const composer = page.locator('[data-component="prompt-input-v2"]')
const input = composer.locator('[data-component="prompt-input"]')
const control = composer.locator('button[title="Choose model variant"]')
const control = composer.getByRole("button", { name: "Choose model variant" })
await expectAppVisible(composer)
await idleComposer(page)
@@ -32,6 +32,23 @@ for (const expanded of [false, true]) {
})
}
test("shows and expands a running shell command without shimmering it", async ({ page }) => {
const id = "prt_shell_running_command"
const command = "sleep 10 && echo done"
await setupTimeline(page, {
messages: [userMessage(), assistantMessage([shell(id, "running", "still running", command)], { completed: false })],
settings: { shellToolPartsExpanded: false },
})
const tool = page.locator(`[data-timeline-part-id="${id}"]`)
await expect(tool.locator('[data-component="text-shimmer"]')).toHaveAttribute("data-active", "true")
await expect(tool.locator('[data-component="shell-submessage"]')).toHaveText(command)
await expect(tool.locator('[data-component="shell-submessage"] [data-component="text-shimmer"]')).toHaveCount(0)
await tool.locator('[data-slot="collapsible-trigger"]').click()
await expect(tool.locator('[data-slot="collapsible-trigger"]')).toHaveAttribute("aria-expanded", "true")
await expect(tool.locator('[data-slot="bash-pre"]')).toContainText("still running")
})
test("transitions thinking and hidden reasoning through busy to idle", async ({ page }) => {
const reasoningID = "prt_reasoning_hidden"
const assistant = assistantMessage([reasoningPart(reasoningID, "## Inspecting stability")], { completed: false })
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/app",
"version": "1.18.3",
"version": "1.18.4",
"description": "",
"type": "module",
"exports": {
@@ -81,7 +81,7 @@
"diff": "catalog:",
"effect": "catalog:",
"fuzzysort": "catalog:",
"ghostty-web": "github:anomalyco/ghostty-web#513463a6f1190253057e8a3f0dac8f6ee8393553",
"ghostty-web": "github:anomalyco/ghostty-web#83c0a07b8628b748aed073b232cb4b52a6ca11c1",
"luxon": "catalog:",
"marked": "catalog:",
"marked-shiki": "catalog:",
@@ -37,6 +37,14 @@ function writeAndWait(term: Terminal, data: string): Promise<void> {
}
describe("SerializeAddon", () => {
test("preserves color scheme reporting mode", async () => {
const { term, addon } = createTerminal()
await writeAndWait(term, "\x1b[?2031h")
expect(addon.serialize().startsWith("\x1b[?2031h")).toBe(true)
expect(addon.serialize({ excludeModes: true }).startsWith("\x1b[?2031h")).toBe(false)
})
describe("ANSI color preservation", () => {
test("should preserve text attributes (bold, italic, underline)", async () => {
const { term, addon } = createTerminal()
+9 -1
View File
@@ -89,6 +89,13 @@ const getTerminalBuffers = (value: ITerminalCore): TerminalBuffers | undefined =
return { active, normal, alternate }
}
const getTerminalMode = (value: ITerminalCore, mode: number) => {
if (!isRecord(value)) return false
const terminal = value.wasmTerm
if (!isRecord(terminal) || typeof terminal.getMode !== "function") return false
return terminal.getMode(mode) === true
}
// ============================================================================
// Types
// ============================================================================
@@ -544,7 +551,8 @@ export class SerializeAddon implements ITerminalAddon {
return ""
}
let content = options?.range
let content = !options?.excludeModes && getTerminalMode(this._terminal, 2031) ? "\u001b[?2031h" : ""
content += options?.range
? this._serializeBufferByRange(normalBuffer, options.range, true)
: this._serializeBufferByScrollback(normalBuffer, options?.scrollback)
+32 -3
View File
@@ -16,6 +16,7 @@ export function TabsInfoPopup() {
const settings = useSettings()
const platform = usePlatform()
const [drawerOpen, setDrawerOpen] = createSignal(false)
const windows = () => platform.platform === "desktop" && platform.os === "windows"
return (
<Drawer open={drawerOpen()} onOpenChange={setDrawerOpen} side="right">
@@ -70,12 +71,40 @@ export function TabsInfoPopup() {
</button>
</div>
</Show>
<DrawerContent>
<div class="flex h-[52px] w-full shrink-0 items-center gap-4 self-stretch border-b border-v2-border-border-muted p-4">
<DrawerContent
style={
windows()
? {
inset: "0 0 0 auto",
"max-height": "100vh",
"max-width": "100vw",
"border-radius": "0",
}
: undefined
}
>
<Show when={windows()}>
<DrawerClose
as={IconButtonV2}
type="button"
size="small"
variant="neutral"
aria-label="Close"
icon={<IconV2 name="xmark-small" />}
class="absolute top-[10px] left-[-36px]"
/>
</Show>
<div
class="flex w-full shrink-0 items-center gap-4 self-stretch border-b border-v2-border-border-muted"
classList={{
"h-[40px] px-4": windows(),
"h-[52px] p-4": !windows(),
}}
>
<p class="min-h-0 min-w-0 flex-1 text-[13px] font-[530] leading-5 tracking-[-0.04px] tabular-nums text-v2-text-text-muted">
July 14
</p>
<Show when={platform.platform !== "desktop" || platform.os !== "windows"}>
<Show when={!windows()}>
<DrawerClose
as={IconButtonV2}
type="button"
@@ -36,6 +36,7 @@ import {
export type PromptInputV2ComposerProps = {
class?: string
controller: PromptInputV2ComposerController
borderUnderlay?: boolean
edit?: PromptInputProps["edit"]
onEditLoaded?: PromptInputProps["onEditLoaded"]
}
@@ -57,7 +58,10 @@ export function PromptInputV2Composer(props: PromptInputV2ComposerProps) {
<div class="flex flex-col gap-3">
<PromptInputV2
controller={props.controller}
borderUnderlay={props.borderUnderlay}
class={props.class}
attachKeybind={command.keybindParts("file.attach")}
attachShortcut={command.keybind("file.attach")}
modelControl={
<PromptInputV2ModelControl
loading={props.controller.model.loading}
@@ -449,12 +453,14 @@ export function usePromptInputV2Controller(props: PromptInputV2ControllerProps):
options: () => props.controls.agents.options.map((name) => ({ id: name, label: name })),
current: () => props.controls.agents.current,
onSelect: props.controls.agents.select,
keybind: () => command.keybindParts("agent.cycle"),
}
: undefined,
variant: {
options: () => variants().map((value) => ({ id: value, label: value })),
current: () => props.controls.model.selection.variant.current() ?? "default",
onSelect: (value) => props.controls.model.selection.variant.set(value === "default" ? undefined : value),
keybind: () => command.keybindParts("model.variant.cycle"),
},
submit: {
stopping,
+1 -1
View File
@@ -1460,10 +1460,10 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
t={(key) => language.t(key as Parameters<typeof language.t>[0])}
/>
<DockShellForm
data-dock-border-underlay="legacy"
onSubmit={handleSubmit}
classList={{
"group/prompt-input": true,
"focus-within:shadow-xs-border": true,
"border-icon-info-active border-dashed": store.draggingType !== null,
[props.class ?? ""]: !!props.class,
}}
@@ -89,13 +89,15 @@ const toOptimisticPart = (part: PromptRequestPart, sessionID: string, messageID:
}
export function buildRequestParts(input: BuildRequestPartsInput) {
const requestParts: PromptRequestPart[] = [
{
id: Identifier.ascending("part"),
type: "text",
text: input.text,
},
]
const requestParts: PromptRequestPart[] = input.text.trim()
? [
{
id: Identifier.ascending("part"),
type: "text",
text: input.text,
},
]
: []
const files = input.prompt.filter(isFileAttachment).map((attachment) => {
const path = absolute(input.sessionDirectory, attachment.path)
@@ -93,24 +93,36 @@ export function PromptWorkspaceSelector(props: {
</MenuV2.Content>
</MenuV2.Portal>
</MenuV2>
<Show when={props.branch}>
{(branch) => (
<>
<span class="hidden select-none opacity-50 sm:inline mx-1">/</span>
<TooltipV2
placement="top"
value={branch()}
class="min-w-0 max-w-[220px]"
contentClass="max-w-[calc(100vw-32px)] break-all"
>
<div class="flex h-7 min-w-0 max-w-[220px] items-center gap-1.5 px-2 text-[13px] font-[440] leading-5 tracking-[-0.04px]">
<Icon name="branch" size="small" class="shrink-0 text-v2-icon-icon-muted" />
<span class="min-w-0 truncate">{branch()}</span>
</div>
</TooltipV2>
</>
)}
</Show>
<PromptGitStatus branch={props.branch} />
</>
)
}
export function PromptGitStatus(props: { branch?: string; noGit?: boolean }) {
const language = useLanguage()
const label = () => {
if (props.noGit) return language.t("session.new.git.none")
return props.branch
}
return (
<Show when={label()}>
{(value) => (
<>
<span class="hidden select-none opacity-50 sm:inline mx-1">/</span>
<TooltipV2
placement="top"
value={value()}
class="min-w-0 max-w-[220px]"
contentClass="max-w-[calc(100vw-32px)] break-all"
>
<div class="flex h-7 min-w-0 max-w-[220px] items-center gap-1.5 px-2 text-[13px] font-[440] leading-5 tracking-[-0.04px]">
<Icon name="branch" size="small" class="shrink-0 text-v2-icon-icon-muted" />
<span class="min-w-0 truncate">{value()}</span>
</div>
</TooltipV2>
</>
)}
</Show>
)
}
@@ -133,9 +133,10 @@
}
[data-slot="settings-v2-row-description"] {
margin-block: -3.5px;
font-size: 13px;
font-weight: 440;
line-height: 1;
line-height: 20px;
color: var(--v2-text-text-muted);
}
@@ -270,10 +271,10 @@
}
.settings-v2-provider-description {
margin: 0;
margin-block: -3.5px;
font-size: 13px;
font-weight: 440;
line-height: 1;
line-height: 20px;
color: var(--v2-text-text-muted);
}
+10 -1
View File
@@ -292,7 +292,12 @@ export const Terminal = (props: TerminalProps) => {
const scheduleSize = (cols: number, rows: number) => {
if (disposed) return
if (lastSize?.cols === cols && lastSize?.rows === rows) return
if (lastSize?.cols === cols && lastSize?.rows === rows) {
pendingSize = undefined
if (sizeTimer !== undefined) clearTimeout(sizeTimer)
sizeTimer = undefined
return
}
pendingSize = { cols, rows }
@@ -317,8 +322,10 @@ export const Terminal = (props: TerminalProps) => {
createEffect(() => {
const colors = terminalColors()
const mode = theme.mode() === "dark" ? "dark" : "light"
if (!term) return
setOptionIfSupported(term, "theme", colors)
setOptionIfSupported(term, "colorScheme", mode)
})
createEffect(() => {
@@ -396,6 +403,7 @@ export const Terminal = (props: TerminalProps) => {
}
_ghostty = g
term = t
setOptionIfSupported(t, "colorScheme", theme.mode() === "dark" ? "dark" : "light")
output = terminalWriter((data, done) =>
t.write(data, () => {
done?.()
@@ -595,6 +603,7 @@ export const Terminal = (props: TerminalProps) => {
tries = 0
local.onConnect?.()
scheduleSize(t.cols, t.rows)
if (t.getMode(2031)) t.write("\x1b[?996n")
}
const handleMessage = (event: MessageEvent) => {
+23 -26
View File
@@ -67,7 +67,7 @@ export function useTitlebarRightMount() {
return mount
}
export function Titlebar(props: { update?: TitlebarUpdate }) {
export function Titlebar(props: { update?: TitlebarUpdate; debugTools?: { visible: boolean; toggle: () => void } }) {
const layout = useLayout()
const platform = usePlatform()
const command = useCommand()
@@ -419,16 +419,7 @@ export function Titlebar(props: { update?: TitlebarUpdate }) {
title: "",
keybind: `mod+option+ArrowLeft,ctrl+shift+tab`,
hidden: true,
onSelect: () => {
let index = tabsStore.findIndex((tab) => tab === currentTab())
if (index === -1) return
index -= 1
if (index === -1) index = tabsStore.length - 1
const next = tabsStore[index]
if (next) tabs.select(next)
},
onSelect: tabs.previous,
},
{
id: `tab.next`,
@@ -436,16 +427,7 @@ export function Titlebar(props: { update?: TitlebarUpdate }) {
title: "",
keybind: `mod+option+ArrowRight,ctrl+tab`,
hidden: true,
onSelect: () => {
let index = tabsStore.findIndex((tab) => tab === currentTab())
if (index === -1) return
index += 1
if (index === tabsStore.length) index = 0
const next = tabsStore[index]
if (next) tabs.select(next)
},
onSelect: tabs.next,
},
].filter((v) => v !== undefined)
})
@@ -462,7 +444,7 @@ export function Titlebar(props: { update?: TitlebarUpdate }) {
"md:pl-4": !mac(),
}}
>
<ChannelIndicator />
<ChannelIndicator debugTools={props.debugTools} />
<Show when={windows() || linux()}>
<WindowsAppMenu command={command} platform={platform} variant="v2" />
</Show>
@@ -660,9 +642,9 @@ export function Titlebar(props: { update?: TitlebarUpdate }) {
</div>
</Show>
<div id="opencode-titlebar-left" class="flex items-center gap-3 min-w-0 px-2" />
<ChannelIndicator />
</div>
</div>
<ChannelIndicator debugTools={props.debugTools} />
</div>
</div>
@@ -747,12 +729,27 @@ function TitlebarUpdateIconButton(props: { state: TitlebarUpdatePillState }) {
)
}
function ChannelIndicator() {
function ChannelIndicator(props: { debugTools?: { visible: boolean; toggle: () => void } }) {
const channel = import.meta.env.VITE_OPENCODE_CHANNEL
if (channel === "dev" && props.debugTools) {
return (
<button
type="button"
class="bg-icon-interactive-base text-[#FFF] font-medium px-2 rounded-sm uppercase font-mono cursor-pointer"
onClick={props.debugTools.toggle}
aria-label="Toggle debug tools"
aria-pressed={props.debugTools.visible}
>
DEV
</button>
)
}
return (
<>
{["beta", "dev"].includes(import.meta.env.VITE_OPENCODE_CHANNEL) && (
{["beta", "dev"].includes(channel) && (
<div class="bg-icon-interactive-base text-[#FFF] font-medium px-2 rounded-sm uppercase font-mono">
{import.meta.env.VITE_OPENCODE_CHANNEL.toUpperCase()}
{channel.toUpperCase()}
</div>
)}
</>
+8 -1
View File
@@ -176,7 +176,14 @@ export const { use: useNotification, provider: NotificationProvider } = createSi
onCleanup(() => states.forEach((value) => value.dispose()))
const selected = () => ensure(activeServer())
const selected = () => {
const list = global.servers.list()
const key = activeServer()
if (list.some((conn) => ServerConnection.key(conn) === key)) return ensure(key)
const conn = list.find((conn) => ServerConnection.key(conn) === server.key) ?? list[0]
if (!conn) throw new Error("Notification server not found")
return ensure(ServerConnection.key(conn))
}
return {
ready: () => selected().ready(),
@@ -200,6 +200,49 @@ describe("server session", () => {
expect(store.history.more("child")).toBe(true)
})
test("keeps assistant history when its deleted parent cannot be backfilled", async () => {
const missing = Promise.withResolvers<SingleMessageResponse>()
const assistant = assistantMessage("message-2", "message-missing")
const client = rootMessageClient([response([{ info: assistant, parts: [] }], "older")], [missing.promise])
const store = createServerSession(client)
const loading = store.sync("child")
await client.rootRequested(1)
missing.reject(new Error("Message not found: message-missing", { cause: { status: 404 } }))
await loading
expect(client.rootRequests).toEqual([{ sessionID: "child", messageID: "message-missing" }])
expect(store.data.message.child).toEqual([assistant])
expect(store.history.more("child")).toBe(true)
})
test("drops a cached parent when a forced refresh confirms it was deleted", async () => {
const missing = Promise.withResolvers<SingleMessageResponse>()
const parent = userMessage("message-1")
const part = textPart(parent.id)
const assistant = assistantMessage("message-2", parent.id)
const client = rootMessageClient(
[
response([
{ info: parent, parts: [part] },
{ info: assistant, parts: [] },
]),
response([{ info: assistant, parts: [] }], "older"),
],
[missing.promise],
)
const store = createServerSession(client)
await store.sync("child")
const loading = store.sync("child", { force: true })
await client.rootRequested(1)
missing.reject(new Error(`Message not found: ${parent.id}`, { cause: { status: 404 } }))
await loading
expect(store.data.message.child).toEqual([assistant])
expect(store.data.part[parent.id]).toBeUndefined()
})
test("does not let an optimistic user suppress initial root backfill", async () => {
const user = userMessage("message-1")
const part = textPart(user.id)
+12 -1
View File
@@ -110,6 +110,7 @@ function reconcileFetched<T extends { id: string }>(
options: {
touched?: ReadonlySet<string>
retained?: ReadonlySet<string>
removed?: ReadonlySet<string>
preserveUnfetched?: boolean | ((item: T) => boolean)
} = {},
) {
@@ -132,6 +133,7 @@ function reconcileFetched<T extends { id: string }>(
if (item) result.set(id, item)
if (!item) result.delete(id)
}
for (const id of options.removed ?? emptyIDs) result.delete(id)
return [...result.values()].sort((a, b) => cmp(a.id, b.id))
}
@@ -577,6 +579,7 @@ export function createServerSession(client: OpencodeClient, options?: { retry?:
const messages = reconcileFetched(merged.session, data.message[sessionID] ?? [], {
touched: touchedMessages,
retained: load?.retainedMessages,
removed: load?.removedMessages,
preserveUnfetched,
})
batch(() => {
@@ -645,7 +648,15 @@ export function createServerSession(client: OpencodeClient, options?: { retry?:
if (generations.get(sessionID) !== active) break
const parent = await fetchMessage(sessionID, parentID, () =>
resetMessageLoad(sessionID, load, messageLoadBaseline(load, parentID)),
)
).catch((error) => {
const cause = error instanceof Error && typeof error.cause === "object" ? error.cause : undefined
if (cause && "status" in cause && cause.status === 404) {
load.removedMessages.add(parentID)
return
}
throw error
})
if (!parent) continue
if (parent.message.role !== "user") throw new Error(`Assistant parent is not a user message: ${parentID}`)
parents.push(parent)
}
@@ -0,0 +1,43 @@
import { describe, expect, test } from "bun:test"
import { nextTab, previousTab, rememberTab, type TabHistory } from "./tab-history"
function history(): TabHistory {
return { stack: [], index: -1 }
}
describe("tab history", () => {
test("moves backward and forward through selected tabs", () => {
const selected = ["a", "b", "c"].reduce(rememberTab, history())
const available = new Set(selected.stack)
const previous = previousTab(selected, available)
expect(previous?.key).toBe("b")
const first = previousTab(previous!.state, available)
expect(first?.key).toBe("a")
const next = nextTab(first!.state, available)
expect(next?.key).toBe("b")
})
test("replaces forward history after a new selection", () => {
const selected = ["a", "b", "c"].reduce(rememberTab, history())
const previous = previousTab(selected, new Set(selected.stack))
const next = rememberTab(previous!.state, "d")
expect(next).toEqual({ stack: ["a", "b", "d"], index: 2 })
expect(nextTab(next, new Set(next.stack))).toBeUndefined()
})
test("skips tabs that are no longer open", () => {
const selected = ["a", "b", "c"].reduce(rememberTab, history())
expect(previousTab(selected, new Set(["a", "c"]))?.key).toBe("a")
})
test("skips a repeated current tab after closing the previous selection", () => {
const selected = ["a", "b", "c", "b"].reduce(rememberTab, history())
expect(previousTab(selected, new Set(["a", "b"]))?.key).toBe("a")
})
})
+28
View File
@@ -0,0 +1,28 @@
const MAX_TAB_HISTORY = 100
export type TabHistory = {
stack: string[]
index: number
}
export function rememberTab(state: TabHistory, key: string): TabHistory {
if (state.stack[state.index] === key) return state
const stack = state.stack.slice(0, state.index + 1).concat(key).slice(-MAX_TAB_HISTORY)
return { stack, index: stack.length - 1 }
}
export function previousTab(state: TabHistory, available: Set<string>) {
return move(state, -1, available)
}
export function nextTab(state: TabHistory, available: Set<string>) {
return move(state, 1, available)
}
function move(state: TabHistory, offset: -1 | 1, available: Set<string>) {
const current = state.stack[state.index]
for (let index = state.index + offset; index >= 0 && index < state.stack.length; index += offset) {
const key = state.stack[index]
if (key && key !== current && available.has(key)) return { state: { ...state, index }, key }
}
}
+16
View File
@@ -12,6 +12,7 @@ import { sessionHref } from "@/utils/session-route"
import { createTabMemory } from "./tab-memory"
import { nextTabAfterClose, pushClosedTab, removeClosedTabs, takeClosedTab, type ClosedTab } from "./closed-tabs"
import { createDraftPromptSession, type PromptModel } from "./prompt-state"
import { nextTab, previousTab, rememberTab, type TabHistory } from "./tab-history"
export type SessionTab = {
type: "session"
@@ -79,6 +80,7 @@ export const { use: useTabs, provider: TabsProvider } = createSimpleContext({
const memory = createTabMemory(getOwner())
const closing = new Set<string>()
let history: TabHistory = { stack: [], index: -1 }
let recentWrite = 0
let recentValue: string | undefined
@@ -150,10 +152,21 @@ export const { use: useTabs, provider: TabsProvider } = createSimpleContext({
const navigateTab = (tab: Tab) => {
const href = tabHref(tab)
history = rememberTab(history, tabKey(tab))
setRecentKey(tabKey(tab))
navigate(href)
}
const moveHistory = (direction: "previous" | "next") => {
const available = new Set(store.map(tabKey))
const result = direction === "previous" ? previousTab(history, available) : nextTab(history, available)
if (!result) return
const tab = store.find((item) => tabKey(item) === result.key)
if (!tab) return
history = result.state
navigateTab(tab)
}
const removeTab = (index: number) => {
const tab = store[index]
if (!tab) return
@@ -359,8 +372,11 @@ export const { use: useTabs, provider: TabsProvider } = createSimpleContext({
select: navigateTab,
remember(tab: Tab) {
const key = tabKey(tab)
history = rememberTab(history, key)
if (recentKey() !== key) setRecentKey(key)
},
previous: () => moveHistory("previous"),
next: () => moveHistory("next"),
toggleHome(input: { home: boolean; current?: Tab }) {
if (input.home) {
const tab = store.find((tab) => tabKey(tab) === recentKey())
+11
View File
@@ -2,6 +2,17 @@ import { describe, expect, test } from "bun:test"
import { DESKTOP_MENU } from "./desktop-menu"
describe("desktop menu", () => {
test("navigates between tabs", () => {
const items = DESKTOP_MENU.flatMap((menu) => menu.items ?? []).filter(
(item) => item.type === "item" && (item.label === "Previous Tab" || item.label === "Next Tab"),
)
expect(items).toEqual([
{ type: "item", label: "Previous Tab", command: "tab.prev", accelerator: { macos: "Option+Up" } },
{ type: "item", label: "Next Tab", command: "tab.next", accelerator: { macos: "Option+Down" } },
])
})
test("exports logs through the desktop command registry", () => {
const items = DESKTOP_MENU.flatMap((menu) => menu.items ?? []).filter(
(item) => item.type === "item" && item.label === "Export Logs...",
+2 -2
View File
@@ -168,8 +168,8 @@ export const DESKTOP_MENU: DesktopMenu[] = [
{ type: "item", label: "Back", command: "common.goBack", accelerator: { macos: "Cmd+[" } },
{ type: "item", label: "Forward", command: "common.goForward", accelerator: { macos: "Cmd+]" } },
{ type: "separator" },
{ type: "item", label: "Previous Session", command: "session.previous", accelerator: { macos: "Option+Up" } },
{ type: "item", label: "Next Session", command: "session.next", accelerator: { macos: "Option+Down" } },
{ type: "item", label: "Previous Tab", command: "tab.prev", accelerator: { macos: "Option+Up" } },
{ type: "item", label: "Next Tab", command: "tab.next", accelerator: { macos: "Option+Down" } },
{ type: "separator" },
{
type: "item",
+1
View File
@@ -613,6 +613,7 @@ export const dict = {
"session.new.workspace.triggerLocal": "محلي",
"session.new.workspace.local": "المستودع المحلي",
"session.new.workspace.existing": "مساحة عمل…",
"session.new.git.none": "لا يوجد Git",
"session.new.lastModified": "آخر تعديل",
"session.header.search.placeholder": "بحث {{project}}",
"session.header.searchFiles": "بحث عن الملفات",
+1
View File
@@ -619,6 +619,7 @@ export const dict = {
"session.new.workspace.triggerLocal": "Local",
"session.new.workspace.local": "Repositório local",
"session.new.workspace.existing": "Espaço de trabalho…",
"session.new.git.none": "Sem Git",
"session.new.lastModified": "Última modificação",
"session.header.search.placeholder": "Buscar {{project}}",
"session.header.searchFiles": "Buscar arquivos",
+1
View File
@@ -675,6 +675,7 @@ export const dict = {
"session.new.workspace.triggerLocal": "Lokalno",
"session.new.workspace.local": "Lokalni repozitorij",
"session.new.workspace.existing": "Radni prostor…",
"session.new.git.none": "Nema Gita",
"session.new.lastModified": "Posljednja izmjena",
"session.header.search.placeholder": "Pretraži {{project}}",
+1
View File
@@ -670,6 +670,7 @@ export const dict = {
"session.new.workspace.triggerLocal": "Lokal",
"session.new.workspace.local": "Lokalt repository",
"session.new.workspace.existing": "Arbejdsområde…",
"session.new.git.none": "Ingen Git",
"session.new.lastModified": "Sidst ændret",
"session.header.search.placeholder": "Søg {{project}}",
+1
View File
@@ -628,6 +628,7 @@ export const dict = {
"session.new.workspace.triggerLocal": "Lokal",
"session.new.workspace.local": "Lokales Repository",
"session.new.workspace.existing": "Arbeitsbereich…",
"session.new.git.none": "Kein Git",
"session.new.lastModified": "Zuletzt geändert",
"session.header.search.placeholder": "{{project}} durchsuchen",
"session.header.searchFiles": "Dateien suchen",
+1
View File
@@ -700,6 +700,7 @@ export const dict = {
"session.new.workspace.triggerLocal": "Local",
"session.new.workspace.local": "Local repository",
"session.new.workspace.existing": "Workspace…",
"session.new.git.none": "No Git",
"session.new.lastModified": "Last modified",
"session.header.search.placeholder": "Search {{project}}",
+1
View File
@@ -676,6 +676,7 @@ export const dict = {
"session.new.workspace.triggerLocal": "Local",
"session.new.workspace.local": "Repositorio local",
"session.new.workspace.existing": "Espacio de trabajo…",
"session.new.git.none": "Sin Git",
"session.new.lastModified": "Última modificación",
"session.header.search.placeholder": "Buscar {{project}}",
+1
View File
@@ -624,6 +624,7 @@ export const dict = {
"session.new.workspace.triggerLocal": "Local",
"session.new.workspace.local": "Dépôt local",
"session.new.workspace.existing": "Espace de travail…",
"session.new.git.none": "Pas de Git",
"session.new.lastModified": "Dernière modification",
"session.header.search.placeholder": "Rechercher {{project}}",
"session.header.searchFiles": "Rechercher des fichiers",
+1
View File
@@ -615,6 +615,7 @@ export const dict = {
"session.new.workspace.triggerLocal": "ローカル",
"session.new.workspace.local": "ローカルリポジトリ",
"session.new.workspace.existing": "ワークスペース…",
"session.new.git.none": "Git なし",
"session.new.lastModified": "最終更新",
"session.header.search.placeholder": "{{project}}を検索",
"session.header.searchFiles": "ファイルを検索",
+1
View File
@@ -976,6 +976,7 @@ export const dict = {
"session.new.workspace.triggerLocal": "로컬",
"session.new.workspace.local": "로컬 저장소",
"session.new.workspace.existing": "작업 공간…",
"session.new.git.none": "Git 없음",
"sidebar.empty.title": "열린 프로젝트 없음",
"sidebar.empty.description": "프로젝트를 열어 시작하세요",
+1
View File
@@ -1070,6 +1070,7 @@ export const dict = {
"session.new.workspace.triggerLocal": "Lokalt",
"session.new.workspace.local": "Lokalt depot",
"session.new.workspace.existing": "Arbeidsområde…",
"session.new.git.none": "Ingen Git",
"sidebar.empty.title": "Ingen åpne prosjekter",
"sidebar.empty.description": "Åpne et prosjekt for å komme i gang",
+1
View File
@@ -619,6 +619,7 @@ export const dict = {
"session.new.workspace.triggerLocal": "Lokalnie",
"session.new.workspace.local": "Lokalne repozytorium",
"session.new.workspace.existing": "Przestrzeń robocza…",
"session.new.git.none": "Brak Git",
"session.new.lastModified": "Ostatnio zmodyfikowano",
"session.header.search.placeholder": "Szukaj {{project}}",
"session.header.searchFiles": "Szukaj plików",
+1
View File
@@ -673,6 +673,7 @@ export const dict = {
"session.new.workspace.triggerLocal": "Локально",
"session.new.workspace.local": "Локальный репозиторий",
"session.new.workspace.existing": "Рабочее пространство…",
"session.new.git.none": "Нет Git",
"session.new.lastModified": "Последнее изменение",
"session.header.search.placeholder": "Поиск {{project}}",
+1
View File
@@ -669,6 +669,7 @@ export const dict = {
"session.new.workspace.triggerLocal": "ในเครื่อง",
"session.new.workspace.local": "รีโพซิทอรีในเครื่อง",
"session.new.workspace.existing": "พื้นที่ทำงาน…",
"session.new.git.none": "ไม่มี Git",
"session.new.lastModified": "แก้ไขล่าสุด",
"session.header.search.placeholder": "ค้นหา {{project}}",
+1
View File
@@ -679,6 +679,7 @@ export const dict = {
"session.new.workspace.triggerLocal": "Yerel",
"session.new.workspace.local": "Yerel depo",
"session.new.workspace.existing": "Çalışma alanı…",
"session.new.git.none": "Git yok",
"session.new.lastModified": "Son değişiklik",
"session.header.search.placeholder": "{{project}} ara",
+1
View File
@@ -703,6 +703,7 @@ export const dict = {
"session.new.workspace.triggerLocal": "Локально",
"session.new.workspace.local": "Локальний репозиторій",
"session.new.workspace.existing": "Робоча область…",
"session.new.git.none": "Немає Git",
"session.new.lastModified": "Востаннє змінено",
"session.header.search.placeholder": "Пошук {{project}}",
+1
View File
@@ -666,6 +666,7 @@ export const dict = {
"session.new.workspace.triggerLocal": "本地",
"session.new.workspace.local": "本地仓库",
"session.new.workspace.existing": "工作区…",
"session.new.git.none": "无 Git",
"session.new.lastModified": "最后修改",
"session.header.search.placeholder": "搜索 {{project}}",
"session.header.searchFiles": "搜索文件",
+1
View File
@@ -663,6 +663,7 @@ export const dict = {
"session.new.workspace.triggerLocal": "本機",
"session.new.workspace.local": "本機儲存庫",
"session.new.workspace.existing": "工作區…",
"session.new.git.none": "無 Git",
"session.new.lastModified": "最後修改",
"session.header.search.placeholder": "搜尋 {{project}}",
+128 -25
View File
@@ -17,6 +17,11 @@ import {
} from "solid-js"
import { makeEventListener } from "@solid-primitives/event-listener"
import { createStore, produce } from "solid-js/store"
import { DragDropProvider, PointerSensor } from "@dnd-kit/solid"
import { isSortable, useSortable } from "@dnd-kit/solid/sortable"
import { AutoScroller, Feedback, PointerActivationConstraints } from "@dnd-kit/dom"
import { RestrictToVerticalAxis } from "@dnd-kit/abstract/modifiers"
import { RestrictToElement } from "@dnd-kit/dom/modifiers"
import { useQuery } from "@tanstack/solid-query"
import { Button } from "@opencode-ai/ui/button"
import { Logo } from "@opencode-ai/ui/logo"
@@ -1037,7 +1042,7 @@ function HomeServerRow(props: {
)
}
function HomeProjectList(props: {
type HomeProjectListProps = {
server: ServerConnection.Any
projects: LocalProject[]
selected: HomeProjectSelection
@@ -1048,29 +1053,82 @@ function HomeProjectList(props: {
clearNotifications: (server: ServerConnection.Any, project: LocalProject) => void
unseenCount: (server: ServerConnection.Any, project: LocalProject) => number
language: ReturnType<typeof useLanguage>
}) {
}
function HomeProjectList(props: HomeProjectListProps) {
const global = useGlobal()
let listRef!: HTMLDivElement
const projects = () => global.ensureServerCtx(props.server).projects
return (
<div class="flex min-w-0 flex-col gap-1">
<For each={props.projects}>
{(project) => (
<HomeProjectRow
project={project}
server={props.server}
selected={
props.selected.server === ServerConnection.key(props.server) &&
props.selected.directory === project.worktree
}
unseenCount={props.unseenCount(props.server, project)}
selectProject={props.selectProject}
openNewSession={props.openNewSession}
editProject={props.editProject}
closeProject={props.closeProject}
clearNotifications={props.clearNotifications}
language={props.language}
/>
)}
</For>
</div>
<DragDropProvider
sensors={(defaults) => [
...defaults.filter((sensor) => sensor !== PointerSensor),
PointerSensor.configure({
activationConstraints: (event) =>
event.pointerType === "touch"
? [new PointerActivationConstraints.Delay({ value: 250, tolerance: 5 })]
: [new PointerActivationConstraints.Distance({ value: 4 })],
preventActivation: (event) => event.target instanceof Element && !!event.target.closest("[data-action]"),
}),
]}
modifiers={[RestrictToVerticalAxis, RestrictToElement.configure({ element: () => listRef })]}
plugins={(defaults) => [
...defaults.filter((plugin) => plugin !== AutoScroller && plugin !== Feedback),
AutoScroller.configure({ acceleration: 8, threshold: { x: 0, y: 0.05 } }),
Feedback.configure({ dropAnimation: null }),
]}
onDragEnd={(event) => {
const source = event.operation.source
if (event.canceled || !isSortable(source)) return
if (source.initialIndex !== source.index) projects().move(source.id.toString(), source.index)
if (props.selected.server !== ServerConnection.key(props.server))
props.selectProject(props.server, source.id.toString())
}}
>
<div class="flex min-w-0 flex-col gap-1" ref={listRef}>
{/* Keyed on worktree strings: the enriched project objects are
recreated on every store or sync update, so iterating them directly
remounts all rows killing any in-flight drag activation (the
row's sortable unregisters on unmount) and discarding animations.
String keys keep row elements alive and move them on reorder. */}
<For each={props.projects.map((project) => project.worktree)}>
{(worktree, index) => <HomeProjectSlot {...props} worktree={worktree} index={index} />}
</For>
</div>
</DragDropProvider>
)
}
function HomeProjectSlot(
props: HomeProjectListProps & {
worktree: string
index: () => number
},
) {
const project = createMemo(() => props.projects.find((item) => item.worktree === props.worktree))
return (
<Show when={project()}>
{(item) => (
<HomeProjectRow
project={item()}
server={props.server}
index={props.index}
serverSelected={props.selected.server === ServerConnection.key(props.server)}
selected={
props.selected.server === ServerConnection.key(props.server) && props.selected.directory === props.worktree
}
unseenCount={props.unseenCount(props.server, item())}
selectProject={props.selectProject}
openNewSession={props.openNewSession}
editProject={props.editProject}
closeProject={props.closeProject}
clearNotifications={props.clearNotifications}
language={props.language}
/>
)}
</Show>
)
}
@@ -1150,6 +1208,8 @@ function HomeRecentlyClosedRow(props: {
function HomeProjectRow(props: {
project: LocalProject
server: ServerConnection.Any
index: () => number
serverSelected: boolean
selected: boolean
unseenCount: number
selectProject: (server: ServerConnection.Any, directory: string) => void
@@ -1163,6 +1223,15 @@ function HomeProjectRow(props: {
const platform = usePlatform()
const serverUnreachable = () => global.servers.health[ServerConnection.key(props.server)]?.healthy === false
const [state, setState] = createStore({ menuOpen: false })
const sortable = useSortable({
get id() {
return props.project.worktree
},
get index() {
return props.index()
},
})
let pointerDownSelected: boolean | undefined
const canRevealInFileManager = () =>
platform.platform === "desktop" && !!platform.openPath && ServerConnection.local(props.server)
const fileManagerActionLabel = () =>
@@ -1179,15 +1248,49 @@ function HomeProjectRow(props: {
)
}
return (
<div class="group/project relative flex h-7 min-w-0 items-center rounded-[6px]">
<div
ref={sortable.ref}
class="group/project relative flex h-7 min-w-0 items-center rounded-[6px]"
classList={{ "z-10": sortable.isDragSource() }}
>
<button
type="button"
data-component="home-project-row"
class={`${HOME_PROJECT_NAV_ROW} pr-16 disabled:opacity-60`}
classList={{
"bg-v2-background-bg-layer-01 text-v2-text-text-base [box-shadow:inset_0_0_0_0.5px_var(--v2-border-border-muted)]":
sortable.isDragSource(),
}}
data-selected={props.selected ? "" : undefined}
aria-current={props.selected ? "page" : undefined}
disabled={serverUnreachable()}
onClick={() => props.selectProject(props.server, props.project.worktree)}
onPointerDown={(event) => {
// Same-server mouse selection happens on pointerdown (like tabs),
// but only ever selects; selectProject toggles, and deselecting here
// would fire on every drag before the threshold is met. Cross-server
// selection waits for click so reordering a remote server's projects
// does not focus that server and load its session index. Touch is
// excluded so flick-scrolling the list cannot select rows.
pointerDownSelected = undefined
if (event.button !== 0 || event.pointerType === "touch") return
if (!props.serverSelected) return
pointerDownSelected = props.selected
if (!props.selected) props.selectProject(props.server, props.project.worktree)
}}
onClick={(event) => {
// The drag sensor calls preventDefault on post-drag clicks; never
// toggle selection as part of a reorder.
if (event.defaultPrevented) return
// Keyboard activation and touch taps keep the original toggle.
if (event.detail === 0 || pointerDownSelected === undefined) {
props.selectProject(props.server, props.project.worktree)
return
}
// Mouse: pointerdown already selected unselected rows; a plain click
// on an already-selected row toggles it off.
if (pointerDownSelected) props.selectProject(props.server, props.project.worktree)
pointerDownSelected = undefined
}}
>
<HomeProjectAvatar project={props.project} />
<span class={HOME_PROJECT_NAV_LABEL}>{displayName(props.project)}</span>
+11 -2
View File
@@ -1,4 +1,5 @@
import { createEffect, Suspense, type ParentProps } from "solid-js"
import { createStore } from "solid-js/store"
import { useNavigate } from "@solidjs/router"
import { DebugBar } from "@/components/debug-bar"
import { TabsInfoPopup } from "@/components/help-button"
@@ -11,6 +12,7 @@ export default function NewLayout(props: ParentProps) {
const platform = usePlatform()
const navigate = useNavigate()
setNavigate(navigate)
const [state, setState] = createStore({ debugTools: true })
createEffect(() => setV2Toast(true))
@@ -32,11 +34,18 @@ export default function NewLayout(props: ParentProps) {
"padding-bottom": "env(safe-area-inset-bottom, 0px)",
}}
>
<Titlebar update={update} />
<Titlebar
update={update}
debugTools={
import.meta.env.DEV
? { visible: state.debugTools, toggle: () => setState("debugTools", (value) => !value) }
: undefined
}
/>
<main class="flex-1 min-h-0 min-w-0 overflow-x-hidden flex flex-col items-start contain-strict">
<Suspense>{props.children}</Suspense>
</main>
{import.meta.env.DEV && <DebugBar inline />}
{import.meta.env.DEV && state.debugTools && <DebugBar inline />}
<TabsInfoPopup />
<ToastRegion v2 />
</div>
+10 -2
View File
@@ -156,6 +156,7 @@ export default function LegacyLayout(props: ParentProps) {
sizing: false,
peek: undefined as string | undefined,
peeked: false,
debugTools: true,
})
const updateVersion = () => {
@@ -2248,7 +2249,14 @@ export default function LegacyLayout(props: ParentProps) {
return (
<div class="relative bg-background-base flex-1 min-h-0 min-w-0 flex flex-col select-none [&_input]:select-text [&_textarea]:select-text [&_[contenteditable]]:select-text">
{autoselecting() ?? ""}
<Titlebar update={titlebarUpdate} />
<Titlebar
update={titlebarUpdate}
debugTools={
import.meta.env.DEV && import.meta.env.VITE_DISABLE_DEBUG_BAR !== "1"
? { visible: state.debugTools, toggle: () => setState("debugTools", (value) => !value) }
: undefined
}
/>
<Show when={updateVersion() !== undefined}>
<UpdateAvailableToast version={updateVersion() ?? ""} install={installUpdate} language={language} />
</Show>
@@ -2393,7 +2401,7 @@ export default function LegacyLayout(props: ParentProps) {
</div>
</div>
</div>
{import.meta.env.DEV && import.meta.env.VITE_DISABLE_DEBUG_BAR !== "1" && <DebugBar />}
{import.meta.env.DEV && import.meta.env.VITE_DISABLE_DEBUG_BAR !== "1" && state.debugTools && <DebugBar />}
</div>
<TabsInfoPopup />
<ToastRegion v2={false} />
@@ -13,7 +13,6 @@ export function useSessionTabAvatarState(
const global = useGlobal()
const notification = useNotification()
const permission = usePermission()
const permissionState = createMemo(() => permission.ensureServerState(server()))
const connection = createMemo(() => global.servers.list().find((item) => ServerConnection.key(item) === server()))
const sync = createMemo(() => {
const conn = connection()
@@ -22,9 +21,10 @@ export function useSessionTabAvatarState(
const hasPermissions = createMemo(() => {
const serverSync = sync()
if (!serverSync) return false
const permissionState = permission.ensureServerState(server())
const [store] = serverSync.child(directory(), { bootstrap: false })
return !!sessionPermissionRequest(store.session, serverSync.session.data.permission, sessionId(), (item) => {
return !permissionState().autoResponds(item, directory())
return !permissionState.autoResponds(item, directory())
})
})
const hasQuestions = createMemo(() => {
@@ -34,9 +34,11 @@ export function useSessionTabAvatarState(
return !!sessionQuestionRequest(store.session, serverSync.session.data.question, sessionId())
})
const needsAttention = createMemo(() => hasPermissions() || hasQuestions())
const unread = createMemo(
() => needsAttention() || notification.ensureServerState(server()).session.unseenCount(sessionId()) > 0,
)
const notificationState = createMemo(() => {
if (!connection()) return
return notification.ensureServerState(server())
})
const unread = createMemo(() => needsAttention() || (notificationState()?.session.unseenCount(sessionId()) ?? 0) > 0)
const loading = createMemo(() => {
const serverSync = sync()
if (!serverSync) return false
+8 -14
View File
@@ -25,7 +25,7 @@ import { createPromptInputController, createPromptProjectControls } from "@/page
import { useSessionKey } from "@/pages/session/session-layout"
import { useComposerCommands } from "@/pages/session/use-composer-commands"
import { NEW_SESSION_CONTENT_WIDTH } from "@/pages/session/new-session-layout"
import { PromptWorkspaceSelector } from "@/components/prompt-workspace-selector"
import { PromptGitStatus, PromptWorkspaceSelector } from "@/components/prompt-workspace-selector"
import { useTitlebarRightMount } from "@/components/titlebar"
import { useCommand } from "@/context/command"
import { useProviders } from "@/hooks/use-providers"
@@ -168,24 +168,18 @@ export default function NewSessionPage() {
<div class="flex-1 min-h-0 overflow-hidden rounded-[10px]">
<NewSessionDesignView>
<div class={NEW_SESSION_CONTENT_WIDTH}>
<div class="flex flex-col" classList={{ "gap-8": showWorkspaceBar(), "gap-3": !showWorkspaceBar() }}>
<div class="flex flex-col gap-8">
<PromptInputV2Composer controller={promptInputV2Controller} />
<Show when={projectController.empty()}>
<PromptProjectAddButton controller={projectController} />
</Show>
<Show when={projectController.selected()}>
<div
class="flex min-h-7 min-w-0 items-center gap-0 text-v2-text-text-faint"
classList={{
"flex-col justify-center sm:flex-row": showWorkspaceBar(),
"justify-start": !showWorkspaceBar(),
}}
>
<PromptProjectSelector
controller={projectController}
placement={showWorkspaceBar() ? "bottom" : "bottom-start"}
/>
<Show when={showWorkspaceBar()}>
<div class="flex min-h-7 min-w-0 flex-col items-center justify-center gap-0 text-v2-text-text-faint sm:flex-row">
<PromptProjectSelector controller={projectController} placement="bottom" />
<Show
when={showWorkspaceBar()}
fallback={<PromptGitStatus branch={selectedBranch()} noGit={sync().project?.vcs !== "git"} />}
>
<PromptWorkspaceSelector
value={newSessionWorktree()}
projectRoot={projectRoot()}
+6 -1
View File
@@ -668,7 +668,8 @@ export default function Page() {
const mobileChanges = createMemo(() => !isDesktop() && store.mobileTab === "changes")
const wantsReview = createMemo(() =>
isDesktop()
? desktopFileTreeOpen() || (desktopReviewOpen() && activeTab() === "review")
? desktopFileTreeOpen() ||
(desktopReviewOpen() && (activeTab() === "review" || (newSessionDesign() && !!activeFileTab())))
: store.mobileTab === "changes",
)
const vcsMode = createMemo<VcsMode | undefined>(() => {
@@ -2265,6 +2266,7 @@ export default function Page() {
return (
<PromptInputV2Composer
controller={controller}
borderUnderlay
edit={editingFollowup()}
onEditLoaded={clearFollowupEdit}
/>
@@ -2365,6 +2367,9 @@ export default function Page() {
reviewHasFocusableContent={() => hasReview() || reviewV2State.sidebarOpened()}
reviewCount={reviewCount}
reviewPanel={reviewPanelV2}
diffVersion={vcsQuery.dataUpdatedAt}
loadDiff={loadReviewDiff}
expandUnchanged={reviewV2State.expandMode() === "expand"}
reviewSidebarToggle={(disabled) => (
<SessionReviewV2SidebarToggle
opened={reviewV2State.sidebarOpened()}
@@ -1,5 +1,6 @@
import { For } from "solid-js"
import { createStore } from "solid-js/store"
import { DockShell } from "@opencode-ai/ui/dock-surface"
import { SessionRevertDock } from "@/pages/session/composer/session-revert-dock"
import { SettingsProvider, useSettings } from "@/context/settings"
@@ -78,12 +79,17 @@ function Stage(props: { count: number }) {
{/* Reproduce the real composer stack: dock + card overlapping the dock's bottom by lift() = 18px */}
<div style={{ display: "flex", "flex-direction": "column" }}>
<SessionRevertDock items={store.items} onRestore={restore} />
<div
<DockShell
data-dock-border-underlay={v2() ? "v2" : "legacy"}
style={{ position: "relative", "z-index": 70, "margin-top": "-18px" }}
class="min-h-24 w-full rounded-[12px] border border-v2-border-border-base bg-v2-background-bg-base px-4 py-3 text-[13px] text-v2-text-text-faint"
classList={{
"min-h-24 w-full rounded-[12px] px-4 py-3 text-[13px]": true,
"bg-v2-background-bg-base text-v2-text-text-faint": v2(),
"text-text-weak": !v2(),
}}
>
Ask anything...
</div>
</DockShell>
</div>
<div class="text-[12px] text-v2-text-text-faint">
@@ -8,8 +8,10 @@ import { TextReveal } from "@opencode-ai/ui/text-reveal"
import { TextStrikethrough } from "@opencode-ai/ui/text-strikethrough"
import { createResizeObserver } from "@solid-primitives/resize-observer"
import { Index, createEffect, createMemo } from "solid-js"
import { Dynamic } from "solid-js/web"
import { createStore } from "solid-js/store"
import { useLanguage } from "@/context/language"
import { useSettings } from "@/context/settings"
const doneToken = "\u0000done\u0000"
const totalToken = "\u0000total\u0000"
@@ -48,6 +50,7 @@ export function SessionTodoDock(props: {
dockProgress: number
}) {
const language = useLanguage()
const settings = useSettings()
const [store, setStore] = createStore({
height: 78,
})
@@ -91,8 +94,13 @@ export function SessionTodoDock(props: {
})
return (
<DockTray
<Dynamic
component={settings.general.newLayoutDesigns() ? "div" : DockTray}
data-component="session-todo-dock"
classList={{
"w-full overflow-hidden rounded-xl border-[0.5px] border-v2-border-border-base bg-v2-background-bg-layer-01":
settings.general.newLayoutDesigns(),
}}
style={{
"overflow-x": "visible",
"overflow-y": "hidden",
@@ -102,7 +110,11 @@ export function SessionTodoDock(props: {
<div ref={contentRef}>
<div
data-action="session-todo-toggle"
class="pl-3 pr-2 py-2 flex items-center gap-2 overflow-visible"
classList={{
"flex items-center gap-2 overflow-visible": true,
"h-[42px] pl-4 pr-2": settings.general.newLayoutDesigns(),
"pl-3 pr-2 py-2": !settings.general.newLayoutDesigns(),
}}
role="button"
tabIndex={0}
onClick={props.onToggle}
@@ -113,7 +125,12 @@ export function SessionTodoDock(props: {
}}
>
<span
class="text-14-regular text-text-strong cursor-default inline-flex items-baseline shrink-0 overflow-visible"
classList={{
"cursor-default inline-flex items-baseline shrink-0 overflow-visible": true,
"font-[440] text-[13px] leading-5 tracking-[-0.04px] text-v2-text-text-muted":
settings.general.newLayoutDesigns(),
"text-14-regular text-text-strong": !settings.general.newLayoutDesigns(),
}}
aria-label={label()}
style={{
"--tool-motion-odometer-ms": "600ms",
@@ -145,7 +162,11 @@ export function SessionTodoDock(props: {
}}
>
<TextReveal
class="text-14-regular text-text-base cursor-default"
class={
settings.general.newLayoutDesigns()
? "cursor-default text-[13px] font-[440] leading-5 tracking-[-0.04px] text-v2-text-text-faint"
: "text-14-regular text-text-base cursor-default"
}
text={props.collapsed ? preview() : undefined}
duration={600}
travel={25}
@@ -191,7 +212,7 @@ export function SessionTodoDock(props: {
<TodoList todos={props.todos} />
</div>
</div>
</DockTray>
</Dynamic>
)
}
+62 -16
View File
@@ -1,4 +1,4 @@
import { createEffect, createMemo, createSignal, Match, on, onCleanup, Show, Switch } from "solid-js"
import { createEffect, createMemo, createResource, createSignal, Match, on, onCleanup, Show, Switch } from "solid-js"
import { createStore } from "solid-js/store"
import { Dynamic } from "solid-js/web"
import { makeEventListener } from "@solid-primitives/event-listener"
@@ -8,6 +8,7 @@ import { cloneSelectedLineRange, previewSelectedLines } from "@opencode-ai/sessi
import { createLineCommentController } from "@opencode-ai/session-ui/line-comment-annotations"
import { createLineCommentControllerV2 } from "@opencode-ai/session-ui/v2/line-comment-annotations-v2"
import { sampledChecksum } from "@opencode-ai/core/util/encode"
import { normalize, text } from "@opencode-ai/session-ui/session-diff"
import { DropdownMenu } from "@opencode-ai/ui/dropdown-menu"
import { IconButton } from "@opencode-ai/ui/icon-button"
import { LineCommentV2OverflowIcon } from "@opencode-ai/ui/v2/line-comment-v2"
@@ -18,11 +19,23 @@ import { showToast } from "@/utils/toast"
import { selectionFromLines, useFile, type FileSelection, type SelectedLineRange } from "@/context/file"
import { useComments } from "@/context/comments"
import { useLanguage } from "@/context/language"
import { useLayout } from "@/context/layout"
import { usePrompt } from "@/context/prompt"
import { useSettings } from "@/context/settings"
import { getSessionHandoff } from "@/pages/session/handoff"
import { useSessionLayout } from "@/pages/session/session-layout"
import { createSessionTabs } from "@/pages/session/helpers"
import { reviewDiffNeedsLoad, type RenderDiff } from "@/pages/session/v2/review-diff-kinds"
type SessionFileViewProps = {
tab: string
diff?: RenderDiff
diffVersion?: number
loadDiff?: (path: string, version?: number) => Promise<RenderDiff | undefined>
expandUnchanged?: boolean
}
const selectionSide = (range: SelectedLineRange) => range.endSide ?? range.side ?? "additions"
function FileCommentMenu(props: {
moreLabel: string
@@ -207,11 +220,27 @@ export function FileTabContent(props: { tab: string }) {
)
}
export function SessionFileView(props: { tab: string }) {
export function SessionFileView(props: SessionFileViewProps) {
const settings = useSettings()
const detailSource = createMemo(() => {
if (!props.diff || !props.loadDiff || !reviewDiffNeedsLoad(props.diff)) return
return { diff: props.diff, load: props.loadDiff, version: props.diffVersion }
})
const [loadedDiff] = createResource(detailSource, async ({ diff, load, version }) => {
const value = await load(diff.file, version)
if (value?.file !== diff.file) return
return { source: diff, version, value }
})
const diff = createMemo(() => {
const source = props.diff
if (!source) return
const loaded = loadedDiff()
return normalize(loaded?.source === source && loaded.version === props.diffVersion ? loaded.value : source)
})
return (
<Show when={settings.general.newLayoutDesigns()} fallback={<SessionFileViewV1 tab={props.tab} />}>
<SessionFileViewV2 tab={props.tab} />
<SessionFileViewV2 tab={props.tab} diff={diff()} expandUnchanged={props.expandUnchanged} />
</Show>
)
}
@@ -501,11 +530,12 @@ function SessionFileViewV1(props: { tab: string }) {
return content()
}
function SessionFileViewV2(props: { tab: string }) {
function SessionFileViewV2(props: { tab: string; diff?: ReturnType<typeof normalize>; expandUnchanged?: boolean }) {
const file = useFile()
const comments = useComments()
const language = useLanguage()
const prompt = usePrompt()
const layout = useLayout()
const fileComponent = useFileComponent()
const { sessionKey, tabs, view } = useSessionLayout()
const activeFileTab = createSessionTabs({
@@ -548,10 +578,15 @@ function SessionFileViewV2(props: { tab: string }) {
})
}
const buildPreview = (filePath: string, selection: FileSelection) => {
const source = filePath === path() ? contents() : file.get(filePath)?.content?.content
const buildPreview = (filePath: string, lines: SelectedLineRange) => {
const source =
filePath === path()
? props.diff
? text(props.diff, selectionSide(lines))
: contents()
: file.get(filePath)?.content?.content
if (!source) return undefined
return selectionPreview(source, selection)
return selectionPreview(source, selectionFromLines(lines))
}
const addCommentToContext = (input: {
@@ -562,7 +597,7 @@ function SessionFileViewV2(props: { tab: string }) {
origin?: "review" | "file"
}) => {
const selection = selectionFromLines(input.selection)
const preview = input.preview ?? buildPreview(input.file, selection)
const preview = input.preview ?? buildPreview(input.file, input.selection)
const saved = comments.add({
file: input.file,
@@ -587,7 +622,7 @@ function SessionFileViewV2(props: { tab: string }) {
comment: string
}) => {
comments.update(input.file, input.id, input.comment)
const preview = input.file === path() ? buildPreview(input.file, selectionFromLines(input.selection)) : undefined
const preview = input.file === path() ? buildPreview(input.file, input.selection) : undefined
prompt.context.updateComment(input.file, input.id, {
comment: input.comment,
...(preview ? { preview } : {}),
@@ -628,7 +663,7 @@ function SessionFileViewV2(props: { tab: string }) {
mention: {
items: file.searchFilesAndDirectories,
},
getSide: (range) => range.endSide ?? range.side ?? "additions",
getSide: selectionSide,
state: {
opened: () => note.openedComment,
setOpened: (id) => setNote("openedComment", id),
@@ -726,12 +761,21 @@ function SessionFileViewV2(props: { tab: string }) {
<div class="relative overflow-hidden pb-40">
<Dynamic
component={fileComponent}
mode="text"
file={{
name: path() ?? "",
contents: source,
cacheKey: cacheKey(),
}}
{...(props.diff
? {
mode: "diff" as const,
fileDiff: props.diff.fileDiff,
diffStyle: layout.review.diffStyle(),
expandUnchanged: props.expandUnchanged,
}
: {
mode: "text" as const,
file: {
name: path() ?? "",
contents: source,
cacheKey: cacheKey(),
},
})}
enableLineSelection
enableGutterUtility
selectedLines={activeSelection()}
@@ -761,6 +805,7 @@ function SessionFileViewV2(props: { tab: string }) {
media={{
mode: "auto",
path: path(),
deleted: props.diff?.status === "deleted",
current: state()?.content,
onLoad: scrollSync.queueRestore,
onError: (args: { kind: "image" | "audio" | "svg" }) => {
@@ -779,6 +824,7 @@ function SessionFileViewV2(props: { tab: string }) {
<div class="mt-3 relative h-full min-h-0">
<ScrollView class="h-full" viewportRef={scrollSync.setViewport} onScroll={scrollSync.handleScroll as any}>
<Switch>
<Match when={props.diff}>{renderFile(contents())}</Match>
<Match when={state()?.loaded}>{renderFile(contents())}</Match>
<Match when={state()?.loading}>
<div class="px-6 py-4 text-text-weak">{language.t("common.loading")}...</div>
@@ -71,6 +71,9 @@ export function SessionSidePanel(props: {
reviewHasFocusableContent: () => boolean
reviewCount: () => number
reviewPanel: () => JSX.Element
diffVersion?: number
loadDiff?: (path: string, version?: number) => Promise<RenderDiff | undefined>
expandUnchanged?: boolean
reviewSidebarToggle?: (disabled: boolean) => JSX.Element
fileBrowserState?: SessionFileBrowserState
activeDiff?: string
@@ -88,6 +91,11 @@ export function SessionSidePanel(props: {
const sdk = useSDK()
const { sessionKey, tabs, view, params } = useSessionLayout()
const projectDirectory = createMemo(() => sdk().directory)
const diffForTab = (tab: string) => {
const path = file.pathFromTab(tab)
if (!path) return
return props.diffs().find((diff): diff is RenderDiff => renderDiff(diff) && diff.file === path)
}
const isDesktop = createMediaQuery("(min-width: 768px)")
const shown = settings.visibility.fileTree
@@ -739,6 +747,10 @@ export function SessionSidePanel(props: {
active={file.pathFromTab(browserTab() ?? activeFileTab() ?? "")}
kinds={kinds()}
state={props.fileBrowserState!}
diff={diffForTab(browserTab() ?? activeFileTab() ?? "")}
diffVersion={props.diffVersion}
loadDiff={props.loadDiff}
expandUnchanged={props.expandUnchanged}
onSelect={(path) => previewTab(file.tab(path))}
onSelectPermanent={(path) => openTab(file.tab(path))}
filterRef={(element) => (fileFilter = element)}
@@ -11,6 +11,7 @@ import { useSDK } from "@/context/sdk"
import { displayName } from "@/pages/layout/helpers"
import { useSessionLayout } from "@/pages/session/session-layout"
import { SessionFileView } from "@/pages/session/file-tabs"
import type { RenderDiff } from "@/pages/session/v2/review-diff-kinds"
import { applyFileListKeyDown, SessionFileListV2 } from "@/pages/session/v2/session-file-list-v2"
import { pathKey } from "@/utils/path-key"
@@ -30,6 +31,10 @@ export function SessionFileBrowserTab(props: {
active?: string
kinds: ReadonlyMap<string, Kind>
state: SessionFileBrowserState
diff?: RenderDiff
diffVersion?: number
loadDiff?: (path: string, version?: number) => Promise<RenderDiff | undefined>
expandUnchanged?: boolean
onSelect: (path: string) => void
onSelectPermanent: (path: string) => void
filterRef?: (element: HTMLInputElement) => void
@@ -172,7 +177,15 @@ export function SessionFileBrowserTab(props: {
>
<div class="min-h-0 flex-1">
<Show when={props.tab} keyed>
{(tab) => <SessionFileView tab={tab} />}
{(tab) => (
<SessionFileView
tab={tab}
diff={props.diff}
diffVersion={props.diffVersion}
loadDiff={props.loadDiff}
expandUnchanged={props.expandUnchanged}
/>
)}
</Show>
</div>
</Show>
+1 -1
View File
@@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "@opencode-ai/cli",
"version": "1.18.3",
"version": "1.18.4",
"type": "module",
"license": "MIT",
"bin": {
+1 -10
View File
@@ -1,7 +1,6 @@
#!/usr/bin/env bun
import { $ } from "bun"
import fs from "fs"
import { rm } from "fs/promises"
import path from "path"
import { Script } from "@opencode-ai/script"
@@ -51,10 +50,6 @@ const targets = singleFlag
if (!skipInstall) await $`bun install --os="*" --cpu="*" @opentui/core@${pkg.dependencies["@opentui/core"]}`
const localParserWorker = path.resolve(dir, "node_modules/@opentui/core/parser.worker.js")
const rootParserWorker = path.resolve(dir, "../../node_modules/@opentui/core/parser.worker.js")
const parserWorker = fs.realpathSync(fs.existsSync(localParserWorker) ? localParserWorker : rootParserWorker)
for (const item of targets) {
const target = [
binary,
@@ -68,7 +63,7 @@ for (const item of targets) {
const name = target.replace(binary, "cli")
console.log(`building ${name}`)
const result = await Bun.build({
entrypoints: ["./src/index.ts", parserWorker],
entrypoints: ["./src/index.ts"],
tsconfig: "./tsconfig.json",
plugins: [plugin],
external: ["node-gyp"],
@@ -94,10 +89,6 @@ for (const item of targets) {
OPENCODE_LIBC: item.os === "linux" ? `'${item.abi ?? "glibc"}'` : "undefined",
// FFF_LIBC selects the fff native lib variant: "musl" or "gnu".
FFF_LIBC: item.os === "linux" ? `'${item.abi ?? "gnu"}'` : "undefined",
OTUI_TREE_SITTER_WORKER_PATH:
(item.os === "win32" ? '"B:/~BUN/root/' : '"/$bunfs/root/') +
path.relative(dir, parserWorker).replaceAll("\\", "/") +
'"',
...(item.os === "linux" ? { "process.env.OPENTUI_LIBC": JSON.stringify(item.abi ?? "glibc") } : {}),
},
})
+1 -1
View File
@@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "@opencode-ai/codemode",
"version": "1.18.3",
"version": "1.18.4",
"description": "Effect-native confined code execution over schema-described tools",
"private": true,
"type": "module",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/console-app",
"version": "1.18.3",
"version": "1.18.4",
"type": "module",
"license": "MIT",
"scripts": {
-2
View File
@@ -9,7 +9,6 @@ import "./app.css"
import { LanguageProvider } from "~/context/language"
import { I18nProvider, useI18n } from "~/context/i18n"
import { strip } from "~/lib/language"
import { DesktopPromo } from "~/component/desktop-promo"
function AppMeta() {
const i18n = useI18n()
@@ -34,7 +33,6 @@ export default function App() {
<MetaProvider>
<AppMeta />
<Suspense>{props.children}</Suspense>
<DesktopPromo />
</MetaProvider>
</I18nProvider>
</LanguageProvider>
+1
View File
@@ -358,6 +358,7 @@ export const dict = {
"zen.api.error.providerNotSupported": "المزود {{provider}} غير مدعوم",
"zen.api.error.missingApiKey": "مفتاح API مفقود.",
"zen.api.error.invalidApiKey": "مفتاح API غير صالح.",
"zen.api.error.requestBlockedByUpstreamProvider": "حظر المزود الخارجي الطلب.",
"zen.api.error.subscriptionQuotaExceeded": "تم تجاوز حصة الاشتراك. أعد المحاولة خلال {{retryIn}}.",
"zen.api.error.goSubscriptionRollingLimitExceeded":
"تم الوصول إلى حد الاستخدام لمدة 5 ساعات. تتم إعادة التعيين خلال {{retryIn}}. لمواصلة استخدام هذا النموذج الآن، فعّل الاستخدام من رصيدك المتاح: {{consoleGoUrl}}",
+1
View File
@@ -366,6 +366,7 @@ export const dict = {
"zen.api.error.providerNotSupported": "Provedor {{provider}} não suportado",
"zen.api.error.missingApiKey": "Chave de API ausente.",
"zen.api.error.invalidApiKey": "Chave de API inválida.",
"zen.api.error.requestBlockedByUpstreamProvider": "Solicitação bloqueada pelo provedor upstream.",
"zen.api.error.subscriptionQuotaExceeded": "Cota de assinatura excedida. Tente novamente em {{retryIn}}.",
"zen.api.error.goSubscriptionRollingLimitExceeded":
"Limite de uso de 5 horas atingido. Será reiniciado em {{retryIn}}. Para continuar usando este modelo agora, habilite o uso a partir do seu saldo disponível: {{consoleGoUrl}}",
+1
View File
@@ -362,6 +362,7 @@ export const dict = {
"zen.api.error.providerNotSupported": "Udbyder {{provider}} understøttes ikke",
"zen.api.error.missingApiKey": "Manglende API-nøgle.",
"zen.api.error.invalidApiKey": "Ugyldig API-nøgle.",
"zen.api.error.requestBlockedByUpstreamProvider": "Anmodningen blev blokeret af upstream-udbyderen.",
"zen.api.error.subscriptionQuotaExceeded": "Abonnementskvote overskredet. Prøv igen om {{retryIn}}.",
"zen.api.error.goSubscriptionRollingLimitExceeded":
"Forbrugsgrænsen for 5 timer er nået. Nulstilles om {{retryIn}}. For at fortsætte med at bruge denne model nu, aktivér forbrug fra din tilgængelige saldo: {{consoleGoUrl}}",
+1
View File
@@ -365,6 +365,7 @@ export const dict = {
"zen.api.error.providerNotSupported": "Anbieter {{provider}} wird nicht unterstützt",
"zen.api.error.missingApiKey": "Fehlender API-Key.",
"zen.api.error.invalidApiKey": "Ungültiger API-Key.",
"zen.api.error.requestBlockedByUpstreamProvider": "Anfrage vom vorgelagerten Anbieter blockiert.",
"zen.api.error.subscriptionQuotaExceeded": "Abonnement-Quote überschritten. Erneuter Versuch in {{retryIn}}.",
"zen.api.error.goSubscriptionRollingLimitExceeded":
"5-Stunden-Nutzungslimit erreicht. Wird in {{retryIn}} zurückgesetzt. Um dieses Modell jetzt weiter zu nutzen, aktiviere die Nutzung über dein verfügbares Guthaben: {{consoleGoUrl}}",
+5
View File
@@ -360,6 +360,7 @@ export const dict = {
"zen.api.error.providerNotSupported": "Provider {{provider}} not supported",
"zen.api.error.missingApiKey": "Missing API key.",
"zen.api.error.invalidApiKey": "Invalid API key.",
"zen.api.error.requestBlockedByUpstreamProvider": "Request blocked by upstream provider.",
"zen.api.error.subscriptionQuotaExceeded": "Subscription quota exceeded. Retry in {{retryIn}}.",
"zen.api.error.goSubscriptionRollingLimitExceeded":
"5-hour usage limit reached. Resets in {{retryIn}}. To continue using this model now, enable usage from your available balance: {{consoleGoUrl}}",
@@ -777,6 +778,10 @@ export const dict = {
"enterprise.faq.q4": "Is my data secure with OpenCode Enterprise?",
"enterprise.faq.a4":
"Yes. OpenCode does not store your code or context data. All processing happens locally or through direct API calls to your AI provider. With central config and SSO integration, your data remains secure within your organization's infrastructure.",
"enterprise.faq.q5": "Where can I find your security and compliance documentation?",
"enterprise.faq.a5.before":
"Our Trust Center has everything: SOC 2 Type 2 report, security policies, subprocessor list, and answers to common security questions. Visit",
"enterprise.faq.a5.after": "to review or request documents under NDA.",
"brand.title": "OpenCode | Brand",
"brand.meta.description": "OpenCode brand guidelines",
+1
View File
@@ -366,6 +366,7 @@ export const dict = {
"zen.api.error.providerNotSupported": "Proveedor {{provider}} no soportado",
"zen.api.error.missingApiKey": "Falta la clave API.",
"zen.api.error.invalidApiKey": "Clave API inválida.",
"zen.api.error.requestBlockedByUpstreamProvider": "El proveedor externo bloqueó la solicitud.",
"zen.api.error.subscriptionQuotaExceeded": "Cuota de suscripción excedida. Reintenta en {{retryIn}}.",
"zen.api.error.goSubscriptionRollingLimitExceeded":
"Límite de uso de 5 horas alcanzado. Se restablece en {{retryIn}}. Para seguir usando este modelo ahora, habilita el uso desde tu saldo disponible: {{consoleGoUrl}}",
+1
View File
@@ -366,6 +366,7 @@ export const dict = {
"zen.api.error.providerNotSupported": "Fournisseur {{provider}} non pris en charge",
"zen.api.error.missingApiKey": "Clé API manquante.",
"zen.api.error.invalidApiKey": "Clé API invalide.",
"zen.api.error.requestBlockedByUpstreamProvider": "Requête bloquée par le fournisseur en amont.",
"zen.api.error.subscriptionQuotaExceeded": "Quota d'abonnement dépassé. Réessayez dans {{retryIn}}.",
"zen.api.error.goSubscriptionRollingLimitExceeded":
"Limite d'utilisation sur 5 heures atteinte. Réinitialisation dans {{retryIn}}. Pour continuer à utiliser ce modèle dès maintenant, activez l'utilisation depuis votre solde disponible : {{consoleGoUrl}}",
+1
View File
@@ -362,6 +362,7 @@ export const dict = {
"zen.api.error.providerNotSupported": "Provider {{provider}} non supportato",
"zen.api.error.missingApiKey": "Chiave API mancante.",
"zen.api.error.invalidApiKey": "Chiave API non valida.",
"zen.api.error.requestBlockedByUpstreamProvider": "Richiesta bloccata dal provider upstream.",
"zen.api.error.subscriptionQuotaExceeded": "Quota dell'abbonamento superata. Riprova tra {{retryIn}}.",
"zen.api.error.goSubscriptionRollingLimitExceeded":
"Limite di utilizzo di 5 ore raggiunto. Si reimposta tra {{retryIn}}. Per continuare a usare questo modello ora, abilita l'utilizzo dal tuo saldo disponibile: {{consoleGoUrl}}",
+1
View File
@@ -362,6 +362,7 @@ export const dict = {
"zen.api.error.providerNotSupported": "プロバイダー {{provider}} はサポートされていません",
"zen.api.error.missingApiKey": "APIキーがありません。",
"zen.api.error.invalidApiKey": "無効なAPIキーです。",
"zen.api.error.requestBlockedByUpstreamProvider": "上流プロバイダーによりリクエストがブロックされました。",
"zen.api.error.subscriptionQuotaExceeded":
"サブスクリプションの制限を超えました。{{retryIn}} 後に再試行してください。",
"zen.api.error.goSubscriptionRollingLimitExceeded":
+1
View File
@@ -357,6 +357,7 @@ export const dict = {
"zen.api.error.providerNotSupported": "{{provider}} 제공자는 지원되지 않습니다",
"zen.api.error.missingApiKey": "API 키가 누락되었습니다.",
"zen.api.error.invalidApiKey": "유효하지 않은 API 키입니다.",
"zen.api.error.requestBlockedByUpstreamProvider": "상위 제공자가 요청을 차단했습니다.",
"zen.api.error.subscriptionQuotaExceeded": "구독 할당량을 초과했습니다. {{retryIn}} 후 다시 시도해 주세요.",
"zen.api.error.goSubscriptionRollingLimitExceeded":
"5시간 사용 한도에 도달했습니다. {{retryIn}} 후 초기화됩니다. 이 모델을 지금 계속 사용하려면 사용 가능한 잔액에서 사용을 활성화하세요: {{consoleGoUrl}}",
+1
View File
@@ -363,6 +363,7 @@ export const dict = {
"zen.api.error.providerNotSupported": "Leverandør {{provider}} støttes ikke",
"zen.api.error.missingApiKey": "Mangler API-nøkkel.",
"zen.api.error.invalidApiKey": "Ugyldig API-nøkkel.",
"zen.api.error.requestBlockedByUpstreamProvider": "Forespørselen ble blokkert av leverandøren.",
"zen.api.error.subscriptionQuotaExceeded": "Abonnementskvote overskredet. Prøv igjen om {{retryIn}}.",
"zen.api.error.goSubscriptionRollingLimitExceeded":
"5-timers bruksgrense nådd. Tilbakestilles om {{retryIn}}. For å fortsette å bruke denne modellen nå, aktiver bruk fra din tilgjengelige saldo: {{consoleGoUrl}}",
+1
View File
@@ -364,6 +364,7 @@ export const dict = {
"zen.api.error.providerNotSupported": "Dostawca {{provider}} nie jest obsługiwany",
"zen.api.error.missingApiKey": "Brak klucza API.",
"zen.api.error.invalidApiKey": "Nieprawidłowy klucz API.",
"zen.api.error.requestBlockedByUpstreamProvider": "Żądanie zablokowane przez dostawcę zewnętrznego.",
"zen.api.error.subscriptionQuotaExceeded": "Przekroczono limit subskrypcji. Spróbuj ponownie za {{retryIn}}.",
"zen.api.error.goSubscriptionRollingLimitExceeded":
"Osiągnięto 5-godzinny limit użycia. Resetuje się za {{retryIn}}. Aby nadal korzystać z tego modelu, włącz użycie z dostępnego salda: {{consoleGoUrl}}",
+1
View File
@@ -368,6 +368,7 @@ export const dict = {
"zen.api.error.providerNotSupported": "Провайдер {{provider}} не поддерживается",
"zen.api.error.missingApiKey": "Отсутствует API ключ.",
"zen.api.error.invalidApiKey": "Неверный API ключ.",
"zen.api.error.requestBlockedByUpstreamProvider": "Запрос заблокирован вышестоящим провайдером.",
"zen.api.error.subscriptionQuotaExceeded": "Квота подписки превышена. Повторите попытку через {{retryIn}}.",
"zen.api.error.goSubscriptionRollingLimitExceeded":
"Достигнут лимит использования за 5 часов. Сбросится через {{retryIn}}. Чтобы продолжить использовать эту модель сейчас, включите оплату с доступного баланса: {{consoleGoUrl}}",
+1
View File
@@ -359,6 +359,7 @@ export const dict = {
"zen.api.error.providerNotSupported": "ไม่รองรับผู้ให้บริการ {{provider}}",
"zen.api.error.missingApiKey": "ไม่มี API key",
"zen.api.error.invalidApiKey": "API key ไม่ถูกต้อง",
"zen.api.error.requestBlockedByUpstreamProvider": "คำขอถูกบล็อกโดยผู้ให้บริการต้นทาง",
"zen.api.error.subscriptionQuotaExceeded": "โควต้าการสมัครสมาชิกเกินขีดจำกัด ลองใหม่ในอีก {{retryIn}}",
"zen.api.error.goSubscriptionRollingLimitExceeded":
"ถึงขีดจำกัดการใช้งานในรอบ 5 ชั่วโมงแล้ว จะรีเซ็ตในอีก {{retryIn}} หากต้องการใช้โมเดลนี้ต่อทันที ให้เปิดใช้งานจากยอดเงินคงเหลือของคุณ: {{consoleGoUrl}}",
+1
View File
@@ -366,6 +366,7 @@ export const dict = {
"zen.api.error.providerNotSupported": "{{provider}} sağlayıcısı desteklenmiyor",
"zen.api.error.missingApiKey": "API anahtarı eksik.",
"zen.api.error.invalidApiKey": "Geçersiz API anahtarı.",
"zen.api.error.requestBlockedByUpstreamProvider": "İstek üst sağlayıcı tarafından engellendi.",
"zen.api.error.subscriptionQuotaExceeded": "Abonelik kotası aşıldı. {{retryIn}} içinde tekrar deneyin.",
"zen.api.error.goSubscriptionRollingLimitExceeded":
"5 saatlik kullanım limitine ulaşıldı. {{retryIn}} içinde sıfırlanır. Bu modeli şimdi kullanmaya devam etmek için kullanılabilir bakiyenizden kullanımı etkinleştirin: {{consoleGoUrl}}",
+1
View File
@@ -363,6 +363,7 @@ export const dict = {
"zen.api.error.providerNotSupported": "Провайдер {{provider}} не підтримується",
"zen.api.error.missingApiKey": "Відсутній ключ API.",
"zen.api.error.invalidApiKey": "Недійсний ключ API.",
"zen.api.error.requestBlockedByUpstreamProvider": "Запит заблоковано зовнішнім провайдером.",
"zen.api.error.subscriptionQuotaExceeded": "Перевищено квоту підписки. Повторіть через {{retryIn}}.",
"zen.api.error.goSubscriptionRollingLimitExceeded":
"Досягнуто 5-годинного ліміту використання. Скидається через {{retryIn}}. Щоб продовжити, увімкніть використання з доступного балансу: {{consoleGoUrl}}",
+1
View File
@@ -346,6 +346,7 @@ export const dict = {
"zen.api.error.providerNotSupported": "不支持提供商 {{provider}}",
"zen.api.error.missingApiKey": "缺少 API 密钥。",
"zen.api.error.invalidApiKey": "无效的 API 密钥。",
"zen.api.error.requestBlockedByUpstreamProvider": "请求被上游提供商阻止。",
"zen.api.error.subscriptionQuotaExceeded": "超出订阅配额。请在 {{retryIn}} 后重试。",
"zen.api.error.goSubscriptionRollingLimitExceeded":
"已达到 5 小时使用限额。将在 {{retryIn}} 后重置。如需立即继续使用该模型,请启用从可用余额扣费:{{consoleGoUrl}}",
+1
View File
@@ -346,6 +346,7 @@ export const dict = {
"zen.api.error.providerNotSupported": "不支援供應商 {{provider}}",
"zen.api.error.missingApiKey": "缺少 API 金鑰。",
"zen.api.error.invalidApiKey": "無效的 API 金鑰。",
"zen.api.error.requestBlockedByUpstreamProvider": "請求遭上游供應商封鎖。",
"zen.api.error.subscriptionQuotaExceeded": "超出訂閱配額。請在 {{retryIn}} 後重試。",
"zen.api.error.goSubscriptionRollingLimitExceeded":
"已達 5 小時使用上限,將在 {{retryIn}} 後重置。若要立即繼續使用此模型,請從可用餘額啟用使用量:{{consoleGoUrl}}",
@@ -273,6 +273,12 @@ export default function Enterprise() {
<li>
<Faq question={i18n.t("enterprise.faq.q4")}>{i18n.t("enterprise.faq.a4")}</Faq>
</li>
<li>
<Faq question={i18n.t("enterprise.faq.q5")}>
{i18n.t("enterprise.faq.a5.before")} <a href="https://trust.opencode.ai">trust.opencode.ai</a>{" "}
{i18n.t("enterprise.faq.a5.after")}
</Faq>
</li>
</ul>
</section>
</div>
+2 -2
View File
@@ -63,8 +63,8 @@ function LimitsGraph(props: { href: string }) {
const baseline = 100
const graph = [
{ id: "grok-4.5", name: "Grok 4.5", req: 80, d: "50ms" },
{ id: "kimi-k3", name: "Kimi K3 (2x usage)", req: 280, baseReq: 140, d: "75ms" },
{ id: "grok-4.5", name: "Grok 4.5", req: 120, d: "50ms" },
{ id: "kimi-k3", name: "Kimi K3 (2x usage)", req: 220, baseReq: 110, d: "75ms" },
{ id: "glm-5.2", name: "GLM-5.2", req: 880, d: "100ms" },
{ id: "qwen3.7-max", name: "Qwen3.7 Max", req: 950, d: "110ms" },
{ id: "kimi-k2.7-code", name: "Kimi K2.7 Code", req: 1150, d: "150ms" },
@@ -0,0 +1,14 @@
import type { APIEvent } from "@solidjs/start/server"
import { handler } from "~/routes/zen/util/handler"
import { parseOpenAiVariant } from "~/routes/zen/util/variant"
export function POST(input: APIEvent) {
return handler(input, {
format: "openai",
modelList: "lite",
parseApiKey: (headers: Headers) => headers.get("authorization")?.split(" ")[1],
parseModel: (url: string, body: any) => body.model,
parseVariant: (url: string, body: any) => parseOpenAiVariant(body),
parseIsStream: (url: string, body: any) => !!body.stream,
})
}
@@ -697,6 +697,9 @@ export async function handler(
workspace: {
id: WorkspaceTable.id,
region: WorkspaceTable.region,
isBlocked: WorkspaceTable.is_blocked,
isFlaggedByAnthropic: WorkspaceTable.is_flagged_by_anthropic,
isFlaggedByOpenAI: WorkspaceTable.is_flagged_by_openai,
},
billing: {
balance: BillingTable.balance,
@@ -772,6 +775,12 @@ export async function handler(
)
if (!data) throw new AuthError(t("zen.api.error.invalidApiKey"))
if (
data.workspace.isBlocked ||
(data.workspace.isFlaggedByAnthropic && modelInfo.id.startsWith("claude-")) ||
(data.workspace.isFlaggedByOpenAI && modelInfo.id.startsWith("gpt-"))
)
throw new AuthError(t("zen.api.error.requestBlockedByUpstreamProvider"))
if (
modelInfo.id.startsWith("alpha-") &&
Resource.App.stage === "production" &&
@@ -0,0 +1,3 @@
ALTER TABLE `workspace` ADD `is_blocked` boolean;--> statement-breakpoint
ALTER TABLE `workspace` ADD `is_flagged_by_anthropic` boolean;--> statement-breakpoint
ALTER TABLE `workspace` ADD `is_flagged_by_openai` boolean;
@@ -0,0 +1,3135 @@
{
"version": "6",
"dialect": "mysql",
"id": "c143f6ef-07b8-401f-8281-462bf49b6501",
"prevIds": ["d78d7057-b247-4572-9150-2532149169db"],
"ddl": [
{
"name": "account",
"entityType": "tables"
},
{
"name": "auth",
"entityType": "tables"
},
{
"name": "benchmark",
"entityType": "tables"
},
{
"name": "billing",
"entityType": "tables"
},
{
"name": "coupon",
"entityType": "tables"
},
{
"name": "lite",
"entityType": "tables"
},
{
"name": "payment",
"entityType": "tables"
},
{
"name": "subscription",
"entityType": "tables"
},
{
"name": "usage",
"entityType": "tables"
},
{
"name": "ip_rate_limit",
"entityType": "tables"
},
{
"name": "ip",
"entityType": "tables"
},
{
"name": "key_rate_limit",
"entityType": "tables"
},
{
"name": "model_sticky_provider",
"entityType": "tables"
},
{
"name": "model_tpm_rate_limit",
"entityType": "tables"
},
{
"name": "model_tps_rate_limit",
"entityType": "tables"
},
{
"name": "key",
"entityType": "tables"
},
{
"name": "model",
"entityType": "tables"
},
{
"name": "provider",
"entityType": "tables"
},
{
"name": "referral_code",
"entityType": "tables"
},
{
"name": "referral_reward",
"entityType": "tables"
},
{
"name": "referral",
"entityType": "tables"
},
{
"name": "user",
"entityType": "tables"
},
{
"name": "workspace",
"entityType": "tables"
},
{
"type": "varchar(30)",
"notNull": true,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "id",
"entityType": "columns",
"table": "account"
},
{
"type": "timestamp(3)",
"notNull": true,
"autoIncrement": false,
"default": "(now())",
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "time_created",
"entityType": "columns",
"table": "account"
},
{
"type": "timestamp(3)",
"notNull": true,
"autoIncrement": false,
"default": "(CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3))",
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "time_updated",
"entityType": "columns",
"table": "account"
},
{
"type": "timestamp(3)",
"notNull": false,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "time_deleted",
"entityType": "columns",
"table": "account"
},
{
"type": "varchar(30)",
"notNull": true,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "id",
"entityType": "columns",
"table": "auth"
},
{
"type": "timestamp(3)",
"notNull": true,
"autoIncrement": false,
"default": "(now())",
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "time_created",
"entityType": "columns",
"table": "auth"
},
{
"type": "timestamp(3)",
"notNull": true,
"autoIncrement": false,
"default": "(CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3))",
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "time_updated",
"entityType": "columns",
"table": "auth"
},
{
"type": "timestamp(3)",
"notNull": false,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "time_deleted",
"entityType": "columns",
"table": "auth"
},
{
"type": "enum('email','github','google')",
"notNull": true,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "provider",
"entityType": "columns",
"table": "auth"
},
{
"type": "varchar(255)",
"notNull": true,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "subject",
"entityType": "columns",
"table": "auth"
},
{
"type": "varchar(30)",
"notNull": true,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "account_id",
"entityType": "columns",
"table": "auth"
},
{
"type": "varchar(30)",
"notNull": true,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "id",
"entityType": "columns",
"table": "benchmark"
},
{
"type": "timestamp(3)",
"notNull": true,
"autoIncrement": false,
"default": "(now())",
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "time_created",
"entityType": "columns",
"table": "benchmark"
},
{
"type": "timestamp(3)",
"notNull": true,
"autoIncrement": false,
"default": "(CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3))",
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "time_updated",
"entityType": "columns",
"table": "benchmark"
},
{
"type": "timestamp(3)",
"notNull": false,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "time_deleted",
"entityType": "columns",
"table": "benchmark"
},
{
"type": "varchar(64)",
"notNull": true,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "model",
"entityType": "columns",
"table": "benchmark"
},
{
"type": "varchar(64)",
"notNull": true,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "agent",
"entityType": "columns",
"table": "benchmark"
},
{
"type": "mediumtext",
"notNull": true,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "result",
"entityType": "columns",
"table": "benchmark"
},
{
"type": "varchar(30)",
"notNull": true,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "id",
"entityType": "columns",
"table": "billing"
},
{
"type": "varchar(30)",
"notNull": true,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "workspace_id",
"entityType": "columns",
"table": "billing"
},
{
"type": "timestamp(3)",
"notNull": true,
"autoIncrement": false,
"default": "(now())",
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "time_created",
"entityType": "columns",
"table": "billing"
},
{
"type": "timestamp(3)",
"notNull": true,
"autoIncrement": false,
"default": "(CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3))",
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "time_updated",
"entityType": "columns",
"table": "billing"
},
{
"type": "timestamp(3)",
"notNull": false,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "time_deleted",
"entityType": "columns",
"table": "billing"
},
{
"type": "varchar(255)",
"notNull": false,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "customer_id",
"entityType": "columns",
"table": "billing"
},
{
"type": "varchar(255)",
"notNull": false,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "payment_method_id",
"entityType": "columns",
"table": "billing"
},
{
"type": "varchar(32)",
"notNull": false,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "payment_method_type",
"entityType": "columns",
"table": "billing"
},
{
"type": "varchar(4)",
"notNull": false,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "payment_method_last4",
"entityType": "columns",
"table": "billing"
},
{
"type": "bigint",
"notNull": true,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "balance",
"entityType": "columns",
"table": "billing"
},
{
"type": "int",
"notNull": false,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "monthly_limit",
"entityType": "columns",
"table": "billing"
},
{
"type": "bigint",
"notNull": false,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "monthly_usage",
"entityType": "columns",
"table": "billing"
},
{
"type": "timestamp(3)",
"notNull": false,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "time_monthly_usage_updated",
"entityType": "columns",
"table": "billing"
},
{
"type": "boolean",
"notNull": false,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "reload",
"entityType": "columns",
"table": "billing"
},
{
"type": "int",
"notNull": false,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "reload_trigger",
"entityType": "columns",
"table": "billing"
},
{
"type": "int",
"notNull": false,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "reload_amount",
"entityType": "columns",
"table": "billing"
},
{
"type": "varchar(255)",
"notNull": false,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "reload_error",
"entityType": "columns",
"table": "billing"
},
{
"type": "timestamp(3)",
"notNull": false,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "time_reload_error",
"entityType": "columns",
"table": "billing"
},
{
"type": "timestamp(3)",
"notNull": false,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "time_reload_locked_till",
"entityType": "columns",
"table": "billing"
},
{
"type": "json",
"notNull": false,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "subscription",
"entityType": "columns",
"table": "billing"
},
{
"type": "varchar(28)",
"notNull": false,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "subscription_id",
"entityType": "columns",
"table": "billing"
},
{
"type": "enum('20','100','200')",
"notNull": false,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "subscription_plan",
"entityType": "columns",
"table": "billing"
},
{
"type": "timestamp(3)",
"notNull": false,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "time_subscription_booked",
"entityType": "columns",
"table": "billing"
},
{
"type": "timestamp(3)",
"notNull": false,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "time_subscription_selected",
"entityType": "columns",
"table": "billing"
},
{
"type": "varchar(28)",
"notNull": false,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "lite_subscription_id",
"entityType": "columns",
"table": "billing"
},
{
"type": "json",
"notNull": false,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "lite",
"entityType": "columns",
"table": "billing"
},
{
"type": "varchar(255)",
"notNull": false,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "email",
"entityType": "columns",
"table": "coupon"
},
{
"type": "enum('BUILDATHON','GO1MONTH50','GOFREEMONTH','GO3MONTHS100','GO6MONTHS100','GO12MONTHS100')",
"notNull": true,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "type",
"entityType": "columns",
"table": "coupon"
},
{
"type": "timestamp(3)",
"notNull": false,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "time_redeemed",
"entityType": "columns",
"table": "coupon"
},
{
"type": "varchar(30)",
"notNull": true,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "id",
"entityType": "columns",
"table": "lite"
},
{
"type": "varchar(30)",
"notNull": true,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "workspace_id",
"entityType": "columns",
"table": "lite"
},
{
"type": "timestamp(3)",
"notNull": true,
"autoIncrement": false,
"default": "(now())",
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "time_created",
"entityType": "columns",
"table": "lite"
},
{
"type": "timestamp(3)",
"notNull": true,
"autoIncrement": false,
"default": "(CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3))",
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "time_updated",
"entityType": "columns",
"table": "lite"
},
{
"type": "timestamp(3)",
"notNull": false,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "time_deleted",
"entityType": "columns",
"table": "lite"
},
{
"type": "varchar(30)",
"notNull": true,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "user_id",
"entityType": "columns",
"table": "lite"
},
{
"type": "bigint",
"notNull": false,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "rolling_usage",
"entityType": "columns",
"table": "lite"
},
{
"type": "bigint",
"notNull": false,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "weekly_usage",
"entityType": "columns",
"table": "lite"
},
{
"type": "bigint",
"notNull": false,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "monthly_usage",
"entityType": "columns",
"table": "lite"
},
{
"type": "timestamp(3)",
"notNull": false,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "time_rolling_updated",
"entityType": "columns",
"table": "lite"
},
{
"type": "timestamp(3)",
"notNull": false,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "time_weekly_updated",
"entityType": "columns",
"table": "lite"
},
{
"type": "timestamp(3)",
"notNull": false,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "time_monthly_updated",
"entityType": "columns",
"table": "lite"
},
{
"type": "varchar(30)",
"notNull": true,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "id",
"entityType": "columns",
"table": "payment"
},
{
"type": "varchar(30)",
"notNull": true,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "workspace_id",
"entityType": "columns",
"table": "payment"
},
{
"type": "timestamp(3)",
"notNull": true,
"autoIncrement": false,
"default": "(now())",
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "time_created",
"entityType": "columns",
"table": "payment"
},
{
"type": "timestamp(3)",
"notNull": true,
"autoIncrement": false,
"default": "(CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3))",
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "time_updated",
"entityType": "columns",
"table": "payment"
},
{
"type": "timestamp(3)",
"notNull": false,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "time_deleted",
"entityType": "columns",
"table": "payment"
},
{
"type": "varchar(255)",
"notNull": false,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "customer_id",
"entityType": "columns",
"table": "payment"
},
{
"type": "varchar(255)",
"notNull": false,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "invoice_id",
"entityType": "columns",
"table": "payment"
},
{
"type": "varchar(255)",
"notNull": false,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "payment_id",
"entityType": "columns",
"table": "payment"
},
{
"type": "bigint",
"notNull": true,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "amount",
"entityType": "columns",
"table": "payment"
},
{
"type": "timestamp(3)",
"notNull": false,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "time_refunded",
"entityType": "columns",
"table": "payment"
},
{
"type": "json",
"notNull": false,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "enrichment",
"entityType": "columns",
"table": "payment"
},
{
"type": "varchar(30)",
"notNull": true,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "id",
"entityType": "columns",
"table": "subscription"
},
{
"type": "varchar(30)",
"notNull": true,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "workspace_id",
"entityType": "columns",
"table": "subscription"
},
{
"type": "timestamp(3)",
"notNull": true,
"autoIncrement": false,
"default": "(now())",
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "time_created",
"entityType": "columns",
"table": "subscription"
},
{
"type": "timestamp(3)",
"notNull": true,
"autoIncrement": false,
"default": "(CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3))",
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "time_updated",
"entityType": "columns",
"table": "subscription"
},
{
"type": "timestamp(3)",
"notNull": false,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "time_deleted",
"entityType": "columns",
"table": "subscription"
},
{
"type": "varchar(30)",
"notNull": true,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "user_id",
"entityType": "columns",
"table": "subscription"
},
{
"type": "bigint",
"notNull": false,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "rolling_usage",
"entityType": "columns",
"table": "subscription"
},
{
"type": "bigint",
"notNull": false,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "fixed_usage",
"entityType": "columns",
"table": "subscription"
},
{
"type": "timestamp(3)",
"notNull": false,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "time_rolling_updated",
"entityType": "columns",
"table": "subscription"
},
{
"type": "timestamp(3)",
"notNull": false,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "time_fixed_updated",
"entityType": "columns",
"table": "subscription"
},
{
"type": "varchar(30)",
"notNull": true,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "id",
"entityType": "columns",
"table": "usage"
},
{
"type": "varchar(30)",
"notNull": true,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "workspace_id",
"entityType": "columns",
"table": "usage"
},
{
"type": "timestamp(3)",
"notNull": true,
"autoIncrement": false,
"default": "(now())",
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "time_created",
"entityType": "columns",
"table": "usage"
},
{
"type": "timestamp(3)",
"notNull": true,
"autoIncrement": false,
"default": "(CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3))",
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "time_updated",
"entityType": "columns",
"table": "usage"
},
{
"type": "timestamp(3)",
"notNull": false,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "time_deleted",
"entityType": "columns",
"table": "usage"
},
{
"type": "varchar(255)",
"notNull": true,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "model",
"entityType": "columns",
"table": "usage"
},
{
"type": "varchar(255)",
"notNull": true,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "provider",
"entityType": "columns",
"table": "usage"
},
{
"type": "int",
"notNull": true,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "input_tokens",
"entityType": "columns",
"table": "usage"
},
{
"type": "int",
"notNull": true,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "output_tokens",
"entityType": "columns",
"table": "usage"
},
{
"type": "int",
"notNull": false,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "reasoning_tokens",
"entityType": "columns",
"table": "usage"
},
{
"type": "int",
"notNull": false,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "cache_read_tokens",
"entityType": "columns",
"table": "usage"
},
{
"type": "int",
"notNull": false,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "cache_write_5m_tokens",
"entityType": "columns",
"table": "usage"
},
{
"type": "int",
"notNull": false,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "cache_write_1h_tokens",
"entityType": "columns",
"table": "usage"
},
{
"type": "bigint",
"notNull": true,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "cost",
"entityType": "columns",
"table": "usage"
},
{
"type": "varchar(30)",
"notNull": false,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "key_id",
"entityType": "columns",
"table": "usage"
},
{
"type": "varchar(30)",
"notNull": false,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "session_id",
"entityType": "columns",
"table": "usage"
},
{
"type": "json",
"notNull": false,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "enrichment",
"entityType": "columns",
"table": "usage"
},
{
"type": "varchar(45)",
"notNull": true,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "ip",
"entityType": "columns",
"table": "ip_rate_limit"
},
{
"type": "varchar(10)",
"notNull": true,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "interval",
"entityType": "columns",
"table": "ip_rate_limit"
},
{
"type": "int",
"notNull": true,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "count",
"entityType": "columns",
"table": "ip_rate_limit"
},
{
"type": "varchar(45)",
"notNull": true,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "ip",
"entityType": "columns",
"table": "ip"
},
{
"type": "timestamp(3)",
"notNull": true,
"autoIncrement": false,
"default": "(now())",
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "time_created",
"entityType": "columns",
"table": "ip"
},
{
"type": "timestamp(3)",
"notNull": true,
"autoIncrement": false,
"default": "(CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3))",
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "time_updated",
"entityType": "columns",
"table": "ip"
},
{
"type": "timestamp(3)",
"notNull": false,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "time_deleted",
"entityType": "columns",
"table": "ip"
},
{
"type": "int",
"notNull": false,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "usage",
"entityType": "columns",
"table": "ip"
},
{
"type": "varchar(255)",
"notNull": true,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "key",
"entityType": "columns",
"table": "key_rate_limit"
},
{
"type": "varchar(40)",
"notNull": true,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "interval",
"entityType": "columns",
"table": "key_rate_limit"
},
{
"type": "int",
"notNull": true,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "count",
"entityType": "columns",
"table": "key_rate_limit"
},
{
"type": "varchar(255)",
"notNull": true,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "id",
"entityType": "columns",
"table": "model_sticky_provider"
},
{
"type": "timestamp(3)",
"notNull": true,
"autoIncrement": false,
"default": "(now())",
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "time_created",
"entityType": "columns",
"table": "model_sticky_provider"
},
{
"type": "timestamp(3)",
"notNull": true,
"autoIncrement": false,
"default": "(CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3))",
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "time_updated",
"entityType": "columns",
"table": "model_sticky_provider"
},
{
"type": "timestamp(3)",
"notNull": false,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "time_deleted",
"entityType": "columns",
"table": "model_sticky_provider"
},
{
"type": "varchar(255)",
"notNull": true,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "provider_id",
"entityType": "columns",
"table": "model_sticky_provider"
},
{
"type": "varchar(255)",
"notNull": true,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "id",
"entityType": "columns",
"table": "model_tpm_rate_limit"
},
{
"type": "bigint",
"notNull": true,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "interval",
"entityType": "columns",
"table": "model_tpm_rate_limit"
},
{
"type": "int",
"notNull": true,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "count",
"entityType": "columns",
"table": "model_tpm_rate_limit"
},
{
"type": "varchar(255)",
"notNull": true,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "id",
"entityType": "columns",
"table": "model_tps_rate_limit"
},
{
"type": "bigint",
"notNull": true,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "interval",
"entityType": "columns",
"table": "model_tps_rate_limit"
},
{
"type": "int",
"notNull": true,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "qualify",
"entityType": "columns",
"table": "model_tps_rate_limit"
},
{
"type": "int",
"notNull": true,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "unqualify",
"entityType": "columns",
"table": "model_tps_rate_limit"
},
{
"type": "varchar(30)",
"notNull": true,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "id",
"entityType": "columns",
"table": "key"
},
{
"type": "varchar(30)",
"notNull": true,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "workspace_id",
"entityType": "columns",
"table": "key"
},
{
"type": "timestamp(3)",
"notNull": true,
"autoIncrement": false,
"default": "(now())",
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "time_created",
"entityType": "columns",
"table": "key"
},
{
"type": "timestamp(3)",
"notNull": true,
"autoIncrement": false,
"default": "(CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3))",
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "time_updated",
"entityType": "columns",
"table": "key"
},
{
"type": "timestamp(3)",
"notNull": false,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "time_deleted",
"entityType": "columns",
"table": "key"
},
{
"type": "varchar(255)",
"notNull": true,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "name",
"entityType": "columns",
"table": "key"
},
{
"type": "varchar(255)",
"notNull": true,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "key",
"entityType": "columns",
"table": "key"
},
{
"type": "varchar(30)",
"notNull": true,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "user_id",
"entityType": "columns",
"table": "key"
},
{
"type": "timestamp(3)",
"notNull": false,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "time_used",
"entityType": "columns",
"table": "key"
},
{
"type": "varchar(30)",
"notNull": true,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "id",
"entityType": "columns",
"table": "model"
},
{
"type": "varchar(30)",
"notNull": true,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "workspace_id",
"entityType": "columns",
"table": "model"
},
{
"type": "timestamp(3)",
"notNull": true,
"autoIncrement": false,
"default": "(now())",
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "time_created",
"entityType": "columns",
"table": "model"
},
{
"type": "timestamp(3)",
"notNull": true,
"autoIncrement": false,
"default": "(CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3))",
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "time_updated",
"entityType": "columns",
"table": "model"
},
{
"type": "timestamp(3)",
"notNull": false,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "time_deleted",
"entityType": "columns",
"table": "model"
},
{
"type": "varchar(64)",
"notNull": true,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "model",
"entityType": "columns",
"table": "model"
},
{
"type": "varchar(30)",
"notNull": true,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "id",
"entityType": "columns",
"table": "provider"
},
{
"type": "varchar(30)",
"notNull": true,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "workspace_id",
"entityType": "columns",
"table": "provider"
},
{
"type": "timestamp(3)",
"notNull": true,
"autoIncrement": false,
"default": "(now())",
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "time_created",
"entityType": "columns",
"table": "provider"
},
{
"type": "timestamp(3)",
"notNull": true,
"autoIncrement": false,
"default": "(CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3))",
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "time_updated",
"entityType": "columns",
"table": "provider"
},
{
"type": "timestamp(3)",
"notNull": false,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "time_deleted",
"entityType": "columns",
"table": "provider"
},
{
"type": "varchar(64)",
"notNull": true,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "provider",
"entityType": "columns",
"table": "provider"
},
{
"type": "text",
"notNull": true,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "credentials",
"entityType": "columns",
"table": "provider"
},
{
"type": "varchar(30)",
"notNull": true,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "workspace_id",
"entityType": "columns",
"table": "referral_code"
},
{
"type": "varchar(10)",
"notNull": true,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "code",
"entityType": "columns",
"table": "referral_code"
},
{
"type": "timestamp(3)",
"notNull": true,
"autoIncrement": false,
"default": "(now())",
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "time_created",
"entityType": "columns",
"table": "referral_code"
},
{
"type": "timestamp(3)",
"notNull": true,
"autoIncrement": false,
"default": "(CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3))",
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "time_updated",
"entityType": "columns",
"table": "referral_code"
},
{
"type": "timestamp(3)",
"notNull": false,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "time_deleted",
"entityType": "columns",
"table": "referral_code"
},
{
"type": "varchar(30)",
"notNull": true,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "workspace_id",
"entityType": "columns",
"table": "referral_reward"
},
{
"type": "varchar(30)",
"notNull": true,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "referral_id",
"entityType": "columns",
"table": "referral_reward"
},
{
"type": "timestamp(3)",
"notNull": true,
"autoIncrement": false,
"default": "(now())",
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "time_created",
"entityType": "columns",
"table": "referral_reward"
},
{
"type": "timestamp(3)",
"notNull": true,
"autoIncrement": false,
"default": "(CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3))",
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "time_updated",
"entityType": "columns",
"table": "referral_reward"
},
{
"type": "timestamp(3)",
"notNull": false,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "time_deleted",
"entityType": "columns",
"table": "referral_reward"
},
{
"type": "bigint",
"notNull": true,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "amount",
"entityType": "columns",
"table": "referral_reward"
},
{
"type": "timestamp(3)",
"notNull": false,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "time_applied",
"entityType": "columns",
"table": "referral_reward"
},
{
"type": "varchar(30)",
"notNull": true,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "id",
"entityType": "columns",
"table": "referral"
},
{
"type": "varchar(30)",
"notNull": true,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "workspace_id",
"entityType": "columns",
"table": "referral"
},
{
"type": "timestamp(3)",
"notNull": true,
"autoIncrement": false,
"default": "(now())",
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "time_created",
"entityType": "columns",
"table": "referral"
},
{
"type": "timestamp(3)",
"notNull": true,
"autoIncrement": false,
"default": "(CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3))",
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "time_updated",
"entityType": "columns",
"table": "referral"
},
{
"type": "timestamp(3)",
"notNull": false,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "time_deleted",
"entityType": "columns",
"table": "referral"
},
{
"type": "varchar(30)",
"notNull": true,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "invitee_account_id",
"entityType": "columns",
"table": "referral"
},
{
"type": "varchar(30)",
"notNull": true,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "id",
"entityType": "columns",
"table": "user"
},
{
"type": "varchar(30)",
"notNull": true,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "workspace_id",
"entityType": "columns",
"table": "user"
},
{
"type": "timestamp(3)",
"notNull": true,
"autoIncrement": false,
"default": "(now())",
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "time_created",
"entityType": "columns",
"table": "user"
},
{
"type": "timestamp(3)",
"notNull": true,
"autoIncrement": false,
"default": "(CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3))",
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "time_updated",
"entityType": "columns",
"table": "user"
},
{
"type": "timestamp(3)",
"notNull": false,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "time_deleted",
"entityType": "columns",
"table": "user"
},
{
"type": "varchar(30)",
"notNull": false,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "account_id",
"entityType": "columns",
"table": "user"
},
{
"type": "varchar(255)",
"notNull": false,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "email",
"entityType": "columns",
"table": "user"
},
{
"type": "varchar(255)",
"notNull": true,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "name",
"entityType": "columns",
"table": "user"
},
{
"type": "timestamp(3)",
"notNull": false,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "time_seen",
"entityType": "columns",
"table": "user"
},
{
"type": "int",
"notNull": false,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "color",
"entityType": "columns",
"table": "user"
},
{
"type": "enum('admin','member')",
"notNull": true,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "role",
"entityType": "columns",
"table": "user"
},
{
"type": "int",
"notNull": false,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "monthly_limit",
"entityType": "columns",
"table": "user"
},
{
"type": "bigint",
"notNull": false,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "monthly_usage",
"entityType": "columns",
"table": "user"
},
{
"type": "timestamp(3)",
"notNull": false,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "time_monthly_usage_updated",
"entityType": "columns",
"table": "user"
},
{
"type": "varchar(30)",
"notNull": true,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "id",
"entityType": "columns",
"table": "workspace"
},
{
"type": "varchar(255)",
"notNull": false,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "slug",
"entityType": "columns",
"table": "workspace"
},
{
"type": "varchar(255)",
"notNull": true,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "name",
"entityType": "columns",
"table": "workspace"
},
{
"type": "json",
"notNull": false,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "region",
"entityType": "columns",
"table": "workspace"
},
{
"type": "boolean",
"notNull": false,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "is_blocked",
"entityType": "columns",
"table": "workspace"
},
{
"type": "boolean",
"notNull": false,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "is_flagged_by_anthropic",
"entityType": "columns",
"table": "workspace"
},
{
"type": "boolean",
"notNull": false,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "is_flagged_by_openai",
"entityType": "columns",
"table": "workspace"
},
{
"type": "timestamp(3)",
"notNull": true,
"autoIncrement": false,
"default": "(now())",
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "time_created",
"entityType": "columns",
"table": "workspace"
},
{
"type": "timestamp(3)",
"notNull": true,
"autoIncrement": false,
"default": "(CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3))",
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "time_updated",
"entityType": "columns",
"table": "workspace"
},
{
"type": "timestamp(3)",
"notNull": false,
"autoIncrement": false,
"default": null,
"onUpdateNow": false,
"onUpdateNowFsp": null,
"charSet": null,
"collation": null,
"generated": null,
"name": "time_deleted",
"entityType": "columns",
"table": "workspace"
},
{
"columns": ["id"],
"name": "PRIMARY",
"table": "account",
"entityType": "pks"
},
{
"columns": ["id"],
"name": "PRIMARY",
"table": "auth",
"entityType": "pks"
},
{
"columns": ["id"],
"name": "PRIMARY",
"table": "benchmark",
"entityType": "pks"
},
{
"columns": ["workspace_id", "id"],
"name": "PRIMARY",
"table": "billing",
"entityType": "pks"
},
{
"columns": ["email", "type"],
"name": "PRIMARY",
"table": "coupon",
"entityType": "pks"
},
{
"columns": ["workspace_id", "id"],
"name": "PRIMARY",
"table": "lite",
"entityType": "pks"
},
{
"columns": ["workspace_id", "id"],
"name": "PRIMARY",
"table": "payment",
"entityType": "pks"
},
{
"columns": ["workspace_id", "id"],
"name": "PRIMARY",
"table": "subscription",
"entityType": "pks"
},
{
"columns": ["workspace_id", "id"],
"name": "PRIMARY",
"table": "usage",
"entityType": "pks"
},
{
"columns": ["ip", "interval"],
"name": "PRIMARY",
"table": "ip_rate_limit",
"entityType": "pks"
},
{
"columns": ["ip"],
"name": "PRIMARY",
"table": "ip",
"entityType": "pks"
},
{
"columns": ["key", "interval"],
"name": "PRIMARY",
"table": "key_rate_limit",
"entityType": "pks"
},
{
"columns": ["id"],
"name": "PRIMARY",
"table": "model_sticky_provider",
"entityType": "pks"
},
{
"columns": ["id", "interval"],
"name": "PRIMARY",
"table": "model_tpm_rate_limit",
"entityType": "pks"
},
{
"columns": ["id", "interval"],
"name": "PRIMARY",
"table": "model_tps_rate_limit",
"entityType": "pks"
},
{
"columns": ["workspace_id", "id"],
"name": "PRIMARY",
"table": "key",
"entityType": "pks"
},
{
"columns": ["workspace_id", "id"],
"name": "PRIMARY",
"table": "model",
"entityType": "pks"
},
{
"columns": ["workspace_id", "id"],
"name": "PRIMARY",
"table": "provider",
"entityType": "pks"
},
{
"columns": ["workspace_id"],
"name": "PRIMARY",
"table": "referral_code",
"entityType": "pks"
},
{
"columns": ["workspace_id", "referral_id"],
"name": "PRIMARY",
"table": "referral_reward",
"entityType": "pks"
},
{
"columns": ["workspace_id", "id"],
"name": "PRIMARY",
"table": "referral",
"entityType": "pks"
},
{
"columns": ["workspace_id", "id"],
"name": "PRIMARY",
"table": "user",
"entityType": "pks"
},
{
"columns": ["id"],
"name": "PRIMARY",
"table": "workspace",
"entityType": "pks"
},
{
"columns": [
{
"value": "provider",
"isExpression": false
},
{
"value": "subject",
"isExpression": false
}
],
"isUnique": true,
"using": null,
"algorithm": null,
"lock": null,
"nameExplicit": true,
"name": "provider",
"entityType": "indexes",
"table": "auth"
},
{
"columns": [
{
"value": "account_id",
"isExpression": false
}
],
"isUnique": false,
"using": null,
"algorithm": null,
"lock": null,
"nameExplicit": true,
"name": "account_id",
"entityType": "indexes",
"table": "auth"
},
{
"columns": [
{
"value": "time_created",
"isExpression": false
}
],
"isUnique": false,
"using": null,
"algorithm": null,
"lock": null,
"nameExplicit": true,
"name": "time_created",
"entityType": "indexes",
"table": "benchmark"
},
{
"columns": [
{
"value": "customer_id",
"isExpression": false
}
],
"isUnique": true,
"using": null,
"algorithm": null,
"lock": null,
"nameExplicit": true,
"name": "global_customer_id",
"entityType": "indexes",
"table": "billing"
},
{
"columns": [
{
"value": "subscription_id",
"isExpression": false
}
],
"isUnique": true,
"using": null,
"algorithm": null,
"lock": null,
"nameExplicit": true,
"name": "global_subscription_id",
"entityType": "indexes",
"table": "billing"
},
{
"columns": [
{
"value": "workspace_id",
"isExpression": false
},
{
"value": "user_id",
"isExpression": false
}
],
"isUnique": true,
"using": null,
"algorithm": null,
"lock": null,
"nameExplicit": true,
"name": "workspace_user_id",
"entityType": "indexes",
"table": "lite"
},
{
"columns": [
{
"value": "workspace_id",
"isExpression": false
},
{
"value": "user_id",
"isExpression": false
}
],
"isUnique": true,
"using": null,
"algorithm": null,
"lock": null,
"nameExplicit": true,
"name": "workspace_user_id",
"entityType": "indexes",
"table": "subscription"
},
{
"columns": [
{
"value": "workspace_id",
"isExpression": false
},
{
"value": "time_created",
"isExpression": false
}
],
"isUnique": false,
"using": null,
"algorithm": null,
"lock": null,
"nameExplicit": true,
"name": "usage_time_created",
"entityType": "indexes",
"table": "usage"
},
{
"columns": [
{
"value": "key",
"isExpression": false
}
],
"isUnique": true,
"using": null,
"algorithm": null,
"lock": null,
"nameExplicit": true,
"name": "global_key",
"entityType": "indexes",
"table": "key"
},
{
"columns": [
{
"value": "workspace_id",
"isExpression": false
},
{
"value": "model",
"isExpression": false
}
],
"isUnique": true,
"using": null,
"algorithm": null,
"lock": null,
"nameExplicit": true,
"name": "model_workspace_model",
"entityType": "indexes",
"table": "model"
},
{
"columns": [
{
"value": "workspace_id",
"isExpression": false
},
{
"value": "provider",
"isExpression": false
}
],
"isUnique": true,
"using": null,
"algorithm": null,
"lock": null,
"nameExplicit": true,
"name": "workspace_provider",
"entityType": "indexes",
"table": "provider"
},
{
"columns": [
{
"value": "code",
"isExpression": false
}
],
"isUnique": true,
"using": null,
"algorithm": null,
"lock": null,
"nameExplicit": true,
"name": "code",
"entityType": "indexes",
"table": "referral_code"
},
{
"columns": [
{
"value": "invitee_account_id",
"isExpression": false
}
],
"isUnique": true,
"using": null,
"algorithm": null,
"lock": null,
"nameExplicit": true,
"name": "invitee_account_id",
"entityType": "indexes",
"table": "referral"
},
{
"columns": [
{
"value": "workspace_id",
"isExpression": false
},
{
"value": "account_id",
"isExpression": false
}
],
"isUnique": true,
"using": null,
"algorithm": null,
"lock": null,
"nameExplicit": true,
"name": "user_account_id",
"entityType": "indexes",
"table": "user"
},
{
"columns": [
{
"value": "workspace_id",
"isExpression": false
},
{
"value": "email",
"isExpression": false
}
],
"isUnique": true,
"using": null,
"algorithm": null,
"lock": null,
"nameExplicit": true,
"name": "user_email",
"entityType": "indexes",
"table": "user"
},
{
"columns": [
{
"value": "account_id",
"isExpression": false
}
],
"isUnique": false,
"using": null,
"algorithm": null,
"lock": null,
"nameExplicit": true,
"name": "global_account_id",
"entityType": "indexes",
"table": "user"
},
{
"columns": [
{
"value": "email",
"isExpression": false
}
],
"isUnique": false,
"using": null,
"algorithm": null,
"lock": null,
"nameExplicit": true,
"name": "global_email",
"entityType": "indexes",
"table": "user"
},
{
"columns": [
{
"value": "slug",
"isExpression": false
}
],
"isUnique": true,
"using": null,
"algorithm": null,
"lock": null,
"nameExplicit": true,
"name": "slug",
"entityType": "indexes",
"table": "workspace"
}
],
"renames": []
}
+1 -1
View File
@@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "@opencode-ai/console-core",
"version": "1.18.3",
"version": "1.18.4",
"private": true,
"type": "module",
"license": "MIT",
@@ -1,4 +1,4 @@
import { json, primaryKey, mysqlTable, uniqueIndex, varchar } from "drizzle-orm/mysql-core"
import { boolean, json, primaryKey, mysqlTable, uniqueIndex, varchar } from "drizzle-orm/mysql-core"
import { timestamps, ulid } from "../drizzle/types"
export const WorkspaceTable = mysqlTable(
@@ -8,6 +8,9 @@ export const WorkspaceTable = mysqlTable(
slug: varchar("slug", { length: 255 }),
name: varchar("name", { length: 255 }).notNull(),
region: json("region").$type<("us" | "eu" | "sg" | "cn")[]>(),
is_blocked: boolean(),
is_flagged_by_anthropic: boolean(),
is_flagged_by_openai: boolean(),
...timestamps,
},
(table) => [uniqueIndex("slug").on(table.slug)],
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/console-function",
"version": "1.18.3",
"version": "1.18.4",
"$schema": "https://json.schemastore.org/package.json",
"private": true,
"type": "module",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/console-mail",
"version": "1.18.3",
"version": "1.18.4",
"dependencies": {
"@jsx-email/all": "2.2.3",
"@jsx-email/cli": "1.4.3",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/console-support",
"version": "1.18.3",
"version": "1.18.4",
"type": "module",
"license": "MIT",
"scripts": {
+1 -1
View File
@@ -1,6 +1,6 @@
{
"$schema": "https://json.schemastore.org/package.json",
"version": "1.18.3",
"version": "1.18.4",
"name": "@opencode-ai/core",
"type": "module",
"license": "MIT",
+4 -1
View File
@@ -4,7 +4,10 @@ import type { Opts, Proc } from "./pty"
export type { Disp, Exit, Opts, Proc } from "./pty"
export function spawn(file: string, args: string[], opts: Opts): Proc {
const proc = pty.spawn(file, args, opts)
const proc = pty.spawn(file, args, {
...opts,
...(process.platform === "win32" ? { useConptyDll: true } : {}),
})
return {
pid: proc.pid,
onData(listener) {
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@opencode-ai/desktop",
"private": true,
"version": "1.18.3",
"version": "1.18.4",
"type": "module",
"license": "MIT",
"homepage": "https://opencode.ai",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"$schema": "https://json.schemastore.org/package.json",
"version": "1.18.3",
"version": "1.18.4",
"name": "@opencode-ai/effect-drizzle-sqlite",
"type": "module",
"license": "MIT",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"$schema": "https://json.schemastore.org/package.json",
"version": "1.18.3",
"version": "1.18.4",
"name": "@opencode-ai/effect-sqlite-node",
"type": "module",
"license": "MIT",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/enterprise",
"version": "1.18.3",
"version": "1.18.4",
"private": true,
"type": "module",
"license": "MIT",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/function",
"version": "1.18.3",
"version": "1.18.4",
"$schema": "https://json.schemastore.org/package.json",
"private": true,
"type": "module",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"$schema": "https://json.schemastore.org/package.json",
"version": "1.18.3",
"version": "1.18.4",
"name": "@opencode-ai/http-recorder",
"description": "Record and replay Effect HTTP client traffic with deterministic cassettes",
"type": "module",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"$schema": "https://json.schemastore.org/package.json",
"version": "1.18.3",
"version": "1.18.4",
"name": "@opencode-ai/llm",
"type": "module",
"license": "MIT",
+11 -1
View File
@@ -3,13 +3,17 @@ import { LLMError, ProviderErrorEvent } from "./schema"
const patterns = [
/prompt is too long/i,
/request_too_large/i,
/input is too long for requested model/i,
/exceeds the context window/i,
/exceeds (?:the )?(?:model'?s )?maximum context length(?: of [\d,]+ tokens?|\s*\([\d,]+\))/i,
/input token count.*exceeds the maximum/i,
/tokens in request more than max tokens allowed/i,
/maximum prompt length is \d+/i,
/reduce the length of the messages/i,
/maximum context length is \d+ tokens/i,
/exceeds (?:the )?maximum allowed input length of [\d,]+ tokens?/i,
/input \(\d+ tokens\) is longer than the model'?s context length \(\d+ tokens\)/i,
/exceeds the limit of \d+/i,
/exceeds the available context size/i,
/greater than the context length/i,
@@ -21,11 +25,17 @@ const patterns = [
/input length.*exceeds.*context length/i,
/prompt too long; exceeded (?:max )?context length/i,
/too large for model with \d+ maximum context length/i,
/prompt has [\d,]+ tokens?, but the configured context size is [\d,]+ tokens?/i,
/model_context_window_exceeded/i,
/too many tokens/i,
/token limit exceeded/i,
]
const exclusions = [/^(throttling error|service unavailable):/i, /rate limit/i, /too many requests/i]
export const isContextOverflow = (message: string) =>
patterns.some((pattern) => pattern.test(message)) || /^4(00|13)\s*(status code)?\s*\(no body\)/i.test(message)
!exclusions.some((pattern) => pattern.test(message)) &&
(patterns.some((pattern) => pattern.test(message)) || /^4(00|13)\s*(status code)?\s*\(no body\)/i.test(message))
export const isContextOverflowFailure = (failure: unknown) =>
failure instanceof LLMError
+24 -2
View File
@@ -2,7 +2,29 @@ import { describe, expect, test } from "bun:test"
import { isContextOverflow } from "../src"
describe("provider error classification", () => {
test("classifies Z.AI GLM token limit messages as context overflow", () => {
expect(isContextOverflow("tokens in request more than max tokens allowed")).toBe(true)
test("classifies provider token limit messages as context overflow", () => {
const messages = [
"tokens in request more than max tokens allowed",
'{"error":{"type":"request_too_large","message":"Request exceeds the maximum size"}}',
"Requested token count exceeds the model's maximum context length of 131072 tokens.",
"Input length (265330) exceeds model's maximum context length (262144).",
"Input length 131393 exceeds the maximum allowed input length of 131040 tokens.",
"The input (516368 tokens) is longer than the model's context length (262144 tokens).",
"Prompt has 5,958,968 tokens, but the configured context size is 256,000 tokens",
"Too many tokens",
"Token limit exceeded",
]
expect(messages.every(isContextOverflow)).toBe(true)
})
test("does not classify rate limits as context overflow", () => {
const messages = [
"Throttling error: Too many tokens, please wait before trying again.",
"Rate limit exceeded, please retry after 30 seconds.",
"Too many requests. Please slow down.",
]
expect(messages.some(isContextOverflow)).toBe(false)
})
})

Some files were not shown because too many files have changed in this diff Show More