Compare commits

..
Author SHA1 Message Date
Kit Langton b60294c696 test(provider): avoid plugin dependency install timeout 2026-04-25 21:55:59 -04:00
Kit Langton 5a4763f560 test(httpapi): skip worktree mutation bridge on windows 2026-04-25 21:46:50 -04:00
Kit Langton 2a600797fb Merge remote-tracking branch 'origin/dev' into kit/httpapi-experimental-tools 2026-04-25 19:32:05 -04:00
Kit Langton 9175c68a77 feat(httpapi): bridge experimental tool routes 2026-04-25 19:32:05 -04:00
opencode-agent[bot] f77277a69e chore: generate 2026-04-25 23:28:25 +00:00
Kit LangtonandGitHub 450128f9be feat(httpapi): bridge mcp oauth endpoints (#24405) 2026-04-25 19:27:11 -04:00
opencode-agent[bot] 3e35c974a4 chore: generate 2026-04-25 23:17:18 +00:00
Kit LangtonandGitHub a14c22d4e9 feat(httpapi): bridge mcp control endpoints (#24403) 2026-04-25 19:16:19 -04:00
Kit LangtonandGitHub 58c65874ba feat(httpapi): bridge project update endpoint (#24398) 2026-04-25 18:55:49 -04:00
opencode-agent[bot] 27b0877714 chore: generate 2026-04-25 22:43:13 +00:00
Kit LangtonandGitHub 5904f599a9 feat(httpapi): bridge project git init endpoint (#24394) 2026-04-25 18:42:02 -04:00
Kit LangtonandGitHub df9e1d9854 feat(httpapi): bridge config update endpoint (#24387) 2026-04-25 17:52:34 -04:00
opencode-agent[bot] 75a22f82bd chore: generate 2026-04-25 19:36:15 +00:00
Kit LangtonandGitHub a369130226 feat(httpapi): bridge worktree mutations (#24371) 2026-04-25 15:35:15 -04:00
opencode-agent[bot] 474024f9e6 chore: generate 2026-04-25 19:25:41 +00:00
Kit LangtonandGitHub b4f4134e81 feat(httpapi): bridge instance dispose endpoint (#24368) 2026-04-25 15:24:07 -04:00
Kit LangtonandGitHub cd64b67038 feat(tui): show /connect tip when user has no models configured (#24014) 2026-04-25 15:01:41 -04:00
opencode-agent[bot] 9af46df535 chore: generate 2026-04-25 18:56:31 +00:00
Kit LangtonandGitHub b749866f0b feat(httpapi): bridge worktree read endpoint (#24366) 2026-04-25 14:55:29 -04:00
opencode-agent[bot] 60fa708f0b chore: update nix node_modules hashes 2026-04-25 18:49:27 +00:00
opencode-agent[bot] 3b74077437 chore: generate 2026-04-25 18:47:06 +00:00
Kit LangtonandGitHub 95d4bb2130 feat(httpapi): bridge experimental read endpoints (#24365) 2026-04-25 14:46:06 -04:00
Dax Raad f5dce6d960 core: move npm service to core package for shared dependency management 2026-04-25 14:36:15 -04:00
Dax Raad 1e98167b0e core: move cross-spawn-spawner to root and remove unused types
The cross-spawn-spawner module has been moved from src/effect/ to src/
to simplify the core package structure. The src/types.d.ts file which
contained unused type declarations has also been removed. All imports
throughout the codebase have been updated to reflect the new location.

This change reduces the package's internal complexity by flattening the
module hierarchy and removing dead code, making future maintenance easier.
2026-04-25 14:30:16 -04:00
Dax Raad 3eee2f6afa core: move cross-spawn-spawner from opencode to core package
Moved the cross-spawn-spawner module from packages/opencode to packages/core
to enable code sharing across the monorepo. This consolidates the process
spawning infrastructure into the core package so other packages can use
cross-platform child process spawning without duplicating the implementation.

Updated all import statements across the codebase to reference the new
location (@opencode-ai/core/effect/cross-spawn-spawner). Removed the
local copy from the opencode package along with its tests.
2026-04-25 14:23:17 -04:00
opencode-agent[bot] ff4b60e1f3 chore: generate 2026-04-25 18:14:26 +00:00
Aiden Cline f91b73b938 ci: fix model name 2026-04-25 14:13:19 -04:00
Kit LangtonandGitHub 05661c60ff feat(httpapi): bridge file search endpoints (#24356) 2026-04-25 14:12:54 -04:00
Kit LangtonandGitHub 625aca49de feat(tui): read Zed editor context from state db (#24352) 2026-04-25 18:10:58 +00:00
opencode-agent[bot] 3bc0c36ace chore: generate 2026-04-25 18:01:35 +00:00
Kit LangtonandGitHub eb0219988b feat(httpapi): bridge catalog read endpoints (#24353) 2026-04-25 14:00:30 -04:00
Dax Raad 705f792e87 core: move Global module to @opencode-ai/core for centralized path management
Move the Global module from packages/opencode/src/global to packages/core/src/global
to provide a unified location for managing XDG directories and application paths.
This eliminates duplicate path definitions across packages and ensures consistent
access to data, config, cache, state, log, and bin directories throughout the codebase.
2026-04-25 13:52:32 -04:00
Aiden ClineandGitHub 716cf74190 ci: adjust review flow (#24355) 2026-04-25 13:52:19 -04:00
opencode-agent[bot] fc8dae2422 chore: update nix node_modules hashes 2026-04-25 17:50:26 +00:00
opencode-agent[bot] 27353df0cc chore: generate 2026-04-25 17:31:57 +00:00
Dax Raad 1a734adb4d core: consolidate shared infrastructure into core package
Moves effect logging, observability, runtime utilities, flags, installation
version info, and process utilities from opencode to core package. This
enables better code sharing across packages and establishes core as the
single source of truth for foundational utilities.

All internal imports updated to use @opencode-ai/core paths for consistency.
2026-04-25 13:30:37 -04:00
Kit LangtonandGitHub a9740b9133 fix(config): preserve permission order with Effect decode (#24308) 2026-04-25 13:30:12 -04:00
opencode-agent[bot] 62651c7114 chore: update nix node_modules hashes 2026-04-25 15:16:42 +00:00
DaxandGitHub 1d728fc627 feat: add startup debug command (#24310) 2026-04-25 15:08:19 +00:00
DaxandGitHub 62ef2a2207 refactor: rename shared package to core (#24309) 2026-04-25 10:59:17 -04:00
DaxandGitHub 37aa8442dc refactor: remove lazy cross-spawn runtime (#24305) 2026-04-25 14:46:16 +00:00
opencode-agent[bot] 5b0e828c10 chore: generate 2026-04-25 14:43:27 +00:00
Kit LangtonandGitHub d5bfaef53d feat(httpapi): bridge instance read endpoints (#24258) 2026-04-25 10:42:31 -04:00
opencode bad732c26a sync release versions for v1.14.25 2026-04-25 14:37:01 +00:00
Dax Raad 1b92c95425 core: permission config schema now provides full IntelliSense for all tool permission keys
The permission configuration previously used a generic record type that didn't offer editor completions. Updated the schema to explicitly list all tool permission keys (read, edit, glob, grep, list, bash, task, external_directory, lsp, skill, todowrite, question, webfetch, websearch, codesearch, doom_loop) with proper types, enabling autocomplete when editing permission files.
2026-04-25 09:48:09 -04:00
Dax Raad d748c71845 ci: centralize opentui dependencies in workspace catalog
Use catalog references for @opentui/core, @opentui/solid, and opentui-spinner
across packages to ensure consistent versions and simplify updates.
2026-04-25 09:41:30 -04:00
opencode-agent[bot] fc88ed1262 chore: generate 2026-04-25 13:19:42 +00:00
DaxandGitHub 66f93035b0 fix permission config order (#24222) 2026-04-25 13:18:42 +00:00
Simon KleeandGitHub 9ff999cc2b tool/lsp: include request details in permission metadata (#24139) 2026-04-25 14:21:35 +02:00
Kit LangtonandGitHub 4877eccc0d Fix shell cwd after login startup (#24215) 2026-04-25 01:14:52 -04:00
Aiden ClineandGitHub f7d527cd28 ci: adjust auto close issue script to use not planned instead of completed (#24253) 2026-04-25 00:47:36 -04:00
opencode-agent[bot] e29058c346 chore: update nix node_modules hashes 2026-04-25 03:04:44 +00:00
Maddison HellstromandGitHub 49894330d9 fix(build): add prettier to devDependencies (#23255) 2026-04-24 22:47:05 -04:00
Luke ParkerandGitHub cdc7d5f2ea chore: group beta PR logs (#24236) 2026-04-25 10:42:33 +10:00
opencode-agent[bot] ec201623fb chore: generate 2026-04-25 00:34:02 +00:00
Luke ParkerandGitHub 386091b79a fix: validate beta before pushing (#24230) 2026-04-25 10:32:41 +10:00
Luke ParkerandGitHub 1e4b7b5451 Add Roslyn support for Razor and C# scripts (#24228) 2026-04-25 10:25:57 +10:00
opencode-agent[bot] 5cd178ba70 chore: generate 2026-04-24 22:05:23 +00:00
Kit LangtonandGitHub 97eb9fdee8 test(httpapi): cover hono bridge middleware (#24216) 2026-04-24 18:03:51 -04:00
Kit LangtonandGitHub 5a04de231e refactor(ripgrep): migrate result schemas to effect (#24213) 2026-04-24 17:42:52 -04:00
Kyle AltendorfGitHubAiden ClineLuke ParkerBrendan Allanopencode-agent[bot] <opencode-agent[bot]@users.noreply.github.com>Shoubhit Dash
bb3509b5ff fix(opencode): clarify git amend condition to require verifying commit landed (#19937)
Co-authored-by: Aiden Cline <63023139+rekram1-node@users.noreply.github.com>
Co-authored-by: Luke Parker <10430890+Hona@users.noreply.github.com>
Co-authored-by: Brendan Allan <14191578+Brendonovich@users.noreply.github.com>
Co-authored-by: opencode-agent[bot] <opencode-agent[bot]@users.noreply.github.com>
Co-authored-by: Shoubhit Dash <shoubhit2005@gmail.com>
2026-04-24 17:42:10 -04:00
Aiden ClineandGitHub 4a67905266 fix: ensure gpt-5.5 compacts at correct context size when using openai oauth (#24212) 2026-04-24 17:39:06 -04:00
opencode-agent[bot] c4e33d3168 chore: generate 2026-04-24 21:38:31 +00:00
Aiden ClineandGitHub 872cdff2ab ignore: denounce ai spammer 2026-04-24 17:37:28 -04:00
Kit LangtonandGitHub 361d7001d0 Clarify HttpApi migration plan (#24211) 2026-04-24 17:36:49 -04:00
opencode-agent[bot] 7a02eee0f4 chore: generate 2026-04-24 21:13:00 +00:00
Kit LangtonandGitHub cf45a8d807 refactor(schema): decode effect schemas directly (#24169) 2026-04-24 17:11:52 -04:00
Kit LangtonandGitHub 435becbea0 Refactor HttpApi auth middleware wiring (#24168) 2026-04-24 17:11:07 -04:00
Frank 0405bc74e9 zen: gpt-5.5 2026-04-24 14:57:23 -04:00
Frank 4dab2a8555 zen: gpt-5.5 2026-04-24 14:43:04 -04:00
Frank 3776d85e15 zen: gpt-5.5 2026-04-24 14:39:24 -04:00
Frank d01ad4c499 zen: gpt-5.5 2026-04-24 14:05:29 -04:00
opencode 28025a0f36 sync release versions for v1.14.24 2026-04-24 15:53:03 +00:00
opencode-agent[bot] 1220f784fe chore: generate 2026-04-24 15:48:08 +00:00
Frank 28f7d31e72 zen: deepseek v4 pro 2026-04-24 11:46:01 -04:00
opencode-agent[bot] 66936b0fff chore: update nix node_modules hashes 2026-04-24 15:45:10 +00:00
SebastianandGitHub 3a5507de95 Use OpenTUI theme detection for initial TUI mode, again (#23846) 2026-04-24 17:28:07 +02:00
Aiden ClineandGitHub 86715fecc4 fix: ensure assistant messages always have reasoning on them for deepseek (#24180) 2026-04-24 11:10:47 -04:00
07akioniandGitHub 3062d3e070 fix: use existingModel as fallback for interleaved field (#24172) 2026-04-24 10:41:41 -04:00
opencode-agent[bot] d89bfc32ac chore: generate 2026-04-24 13:20:23 +00:00
Kit LangtonandGitHub 011c23761b feat(httpapi): bridge mcp status endpoint (#24100) 2026-04-24 09:18:57 -04:00
opencode a8c8d2dd79 sync release versions for v1.14.23 2026-04-24 13:17:13 +00:00
Kit LangtonandGitHub 9f7ecd65e5 feat(httpapi): bridge file read endpoints (#24098) 2026-04-24 09:12:05 -04:00
Aiden ClineandGitHub f8e939d96f fix: support max for deepseek (#24163) 2026-04-24 08:48:52 -04:00
923af96d26 fix: preserve empty reasoning_content for DeepSeek V4 thinking mode (#24146)
Co-authored-by: Simon Klee <hello@simonklee.dk>
2026-04-24 08:42:57 -04:00
Aiden ClineandGitHub a882e958b3 fix: deepseek variants (#24157) 2026-04-24 08:34:48 -04:00
Simon KleeandGitHub 2cda629c8d test(prompt): align shell placeholder expectation (#24147) 2026-04-24 13:00:11 +02:00
Brendan AllanandGitHub f033d2d8fb fix(app): conditionally show model variant selector (#24115) 2026-04-24 15:20:53 +08:00
Frank a4bd88ab97 zen: deepseek v4 pro 2026-04-24 02:09:14 -04:00
Frank f4616c8268 sync 2026-04-24 02:05:22 -04:00
Brendan AllanandGitHub 4712f0f3c1 feat(prompt): add shell mode UI with cancel button, custom icon, and example placeholder (#24105) 2026-04-24 14:04:55 +08:00
opencode-agent[bot] 6c1268f3b1 chore: generate 2026-04-24 05:28:43 +00:00
Brendan AllanandGitHub 2e156b8990 fix(desktop): avoid relaunching without installing updates (#23806) 2026-04-24 13:27:36 +08:00
Brendan AllanandGitHub 3bfe6a1ef6 ci: add platform-specific bun install flags (#23822) 2026-04-24 04:50:34 +00:00
opencode-agent[bot] 5c5069b622 chore: generate 2026-04-23 21:44:44 +00:00
f8c6ddd4cb feat(truncate): allow configuring tool output truncation limits (#23770)
Co-authored-by: rgs_ramp <rgs@ramp.com>
Co-authored-by: Aiden Cline <63023139+rekram1-node@users.noreply.github.com>
2026-04-23 17:43:33 -04:00
Kit LangtonandGitHub e50a688ca3 feat(httpapi): bridge workspace read endpoints (#24062) 2026-04-23 17:32:02 -04:00
Aiden ClineandGitHub 334ab4707c fix: account for additional openai retry case (#24063) 2026-04-23 17:31:43 -04:00
Aiden ClineandGitHub 87321942fe chore: update copilot readme to symlink to an agents md to prevent dumbass agents from touching these files (#24057) 2026-04-23 17:08:46 -04:00
opencode-agent[bot] a771859362 chore: generate 2026-04-23 20:50:19 +00:00
Kit LangtonandGitHub 31d01d404a refactor(control-plane): migrate workspace DTO schemas (#24056) 2026-04-23 16:48:56 -04:00
Kit LangtonandGitHub 814e83ffec docs: update effect schema migration tracker (#24054) 2026-04-23 16:23:45 -04:00
opencode-agent[bot] 4c3e65c877 chore: generate 2026-04-23 20:20:26 +00:00
James LongandGitHub 98ea5b6e7e feat(tui): support builtin protocol for handling context from editors (#24034) 2026-04-23 16:19:19 -04:00
opencode-agent[bot] 3f8c659056 chore: generate 2026-04-23 20:10:56 +00:00
Kit LangtonandGitHub 3910a6e527 refactor(tool): migrate tool framework + all 18 built-in tools to Effect Schema (#23244) 2026-04-23 16:09:34 -04:00
opencode-agent[bot] 24892559ae chore: generate 2026-04-23 19:38:54 +00:00
Kit LangtonandGitHub cd93533b1f refactor(bus): migrate BusEvent to Effect Schema (#24040) 2026-04-23 15:37:44 -04:00
Kit LangtonandGitHub 0590452456 refactor(schema): use Schema.Int and consolidate PositiveInt/NonNegativeInt (#24029) 2026-04-23 13:22:48 -04:00
Kit LangtonandGitHub 93940a1859 refactor(provider): migrate provider domain to Effect Schema (#24027) 2026-04-23 13:17:33 -04:00
Frank 1e439b8226 sync 2026-04-23 13:13:29 -04:00
Kit LangtonandGitHub 8b2f8355b2 docs(schema): mark sync/index.ts migrated with compat-bridge note (#24024) 2026-04-23 12:54:46 -04:00
opencode-agent[bot] aed03078f8 chore: generate 2026-04-23 16:44:32 +00:00
Kit LangtonandGitHub c50d65b4d6 refactor(sync): make session events schema-first (#24019) 2026-04-23 12:43:08 -04:00
opencode-agent[bot] 353532b1c1 chore: generate 2026-04-23 16:00:01 +00:00
Shoubhit DashandGitHub 9df7c78ebe fix(npm): respect npmrc for version lookups (#24016) 2026-04-23 21:28:54 +05:30
opencode eb7555d3c6 sync release versions for v1.14.22 2026-04-23 15:56:49 +00:00
opencode-agent[bot] 2cd89d64e9 chore: generate 2026-04-23 15:31:16 +00:00
Kit LangtonandGitHub 0517ab4695 refactor(session): migrate session domain to Effect Schema (#24005) 2026-04-23 11:30:02 -04:00
James LongandGitHub bbf67d0fff fix(tui): render all non-synthetic text parts of a user message (#24009) 2026-04-23 11:24:40 -04:00
Shoubhit DashandGitHub 38deb0f3ee fix(npm): respect npmrc config (#24001) 2026-04-23 19:54:01 +05:30
Simon KleeandGitHub 9b6db08d21 chore: add to TEAM_MEMBERS (#23975) 2026-04-23 13:02:40 +02:00
opencode-agent[bot] 3ae74cb047 chore: generate 2026-04-23 10:58:14 +00:00
Brendan AllanandGitHub 6002500bc0 feat(project): add icon_url_override field to projects (#23955) 2026-04-23 18:57:04 +08:00
Brendan AllanandGitHub 785f3589ab fix: add keyed prop to Show components for proper reactivity (#23935) 2026-04-23 17:32:01 +08:00
Frank a419f1c50f zen: hy3 preview 2026-04-23 02:56:41 -04:00
opencode 871789ce64 sync release versions for v1.14.21 2026-04-23 05:45:21 +00:00
Brendan AllanandGitHub df27baa00d refactor: remove redundant pending check from working memo (#23929) 2026-04-23 13:15:02 +08:00
Aiden ClineandGitHub 9730008543 tweak: codex model logic (#23925) 2026-04-23 00:29:56 -04:00
Luke ParkerandAiden Cline ac26394fcb fix(beta): PR resolvers/smoke check should typecheck all pacakges (#23913) 2026-04-23 00:25:41 -04:00
Luke ParkerandAiden Cline 6387b35a2d log session sdk errors (#23652) 2026-04-23 00:25:41 -04:00
opencode-agent[bot]andAiden Cline 1cd4c92242 chore: generate 2026-04-23 00:25:40 -04:00
Luke ParkerandAiden Cline e383df4b17 feat: support pull diagnostics in the LSP client (C#, Kotlin, etc) (#23771) 2026-04-23 00:25:40 -04:00
Caleb NortonandAiden Cline 58db41b4b9 chore: update nix bun version (#23881) 2026-04-23 00:25:40 -04:00
opencode-agent[bot]andAiden Cline 5d133f2785 chore: generate 2026-04-23 00:25:39 -04:00
JackandAiden Cline e9b1d3b940 docs: add MiMo V2.5 to Go pages (#23876) 2026-04-23 00:25:39 -04:00
Steven T. CramerandAiden Cline 3a082a0efd fix(project): use git common dir for bare repo project cache (#19054) 2026-04-23 00:25:39 -04:00
opencode-agent[bot]andAiden Cline 504fd1b373 chore: generate 2026-04-23 00:25:39 -04:00
Shoubhit DashandAiden Cline 574b2c2170 fix(session): improve session compaction (#23870) 2026-04-23 00:25:38 -04:00
opencode-agent[bot]andAiden Cline fa8b7bc4d2 chore: generate 2026-04-23 00:25:38 -04:00
Shoubhit DashandAiden Cline 6196b81e0a fix(tui): fail fast on invalid session startup (#23837) 2026-04-23 00:25:38 -04:00
Brendan AllanandAiden Cline d884ab73d5 fix: consolidate project avatar source logic (#23819) 2026-04-23 00:25:37 -04:00
opencode-agent[bot]andAiden Cline 71d196d3cd chore: generate 2026-04-23 00:25:37 -04:00
Luke ParkerandAiden Cline 20756e0ee4 test: fix cross-spawn stderr race on Windows CI (#23808) 2026-04-23 00:25:37 -04:00
opencode-agent[bot]andAiden Cline 894e638914 chore: generate 2026-04-23 00:25:37 -04:00
Luke ParkerandAiden Cline 8113a4360e fix: preserve BOM in text tool round-trips (#23797) 2026-04-23 00:25:36 -04:00
opencode-agent[bot]andAiden Cline c819804638 chore: update nix node_modules hashes 2026-04-23 00:25:36 -04:00
Brendan AllanandAiden Cline 06066dbb7b fix(app): improve icon override handling in project edit dialog (#23768) 2026-04-23 00:25:36 -04:00
Luke ParkerandAiden Cline 69b8ea0d66 chore: bump Bun to 1.3.13 (#23791) 2026-04-23 00:25:36 -04:00
opencode-agent[bot] b0455583aa chore: generate 2026-04-22 03:41:42 +00:00
Kit LangtonandGitHub ed802fd121 refactor(core): migrate MessageV2 errors to Schema-backed named errors (#23764) 2026-04-21 23:40:32 -04:00
Kit LangtonandGitHub 1593c3ed16 refactor(core): migrate MessageV2 internal Cursor to Effect Schema (#23763) 2026-04-21 23:28:33 -04:00
Kit LangtonandGitHub e89543811c refactor(core): migrate MessageV2 message DTOs (User/Assistant/Part/Info/WithParts) to Effect Schema (#23757) 2026-04-21 23:26:12 -04:00
opencode-agent[bot] 1a76799fd8 chore: generate 2026-04-22 03:18:25 +00:00
Kit LangtonandGitHub fa623964a2 refactor(core): migrate MessageV2 part leaves + ToolPart to Effect Schema (#23756) 2026-04-21 23:17:23 -04:00
Frank 628102ad04 zen: handle alibaba format 2026-04-21 23:13:44 -04:00
Kit LangtonandGitHub ad7ae7353f refactor(core): derive all schema.ts leaves' .zod via effect-zod walker (#23754) 2026-04-21 22:51:18 -04:00
NN708andGitHub 8043cfa68d fix(desktop): update desktop file and MetaInfo file (#14933) 2026-04-22 07:19:04 +08:00
opencode-agent[bot] d2181e9273 chore: generate 2026-04-21 22:04:16 +00:00
5e9fb3cc90 feat: replace csharp-ls with roslyn-language-server (#14463)
Co-authored-by: Mathews <Mathews.Bryan@cincpro.com>
2026-04-21 22:03:09 +00:00
Kit LangtonandGitHub 2da6d860e0 refactor(core): derive provider schema .zod via effect-zod walker (#23753) 2026-04-21 17:49:24 -04:00
Kit LangtonandGitHub df0c1f649c refactor(core): migrate MessageV2 tool state schemas to Effect Schema (#23752) 2026-04-21 17:47:50 -04:00
Kit LangtonandGitHub d6dea3f3e0 chore(core): clean up after ConfigPermission Effect Schema migration (#23749) 2026-04-21 17:40:54 -04:00
Kit LangtonandGitHub 0bcf734a67 migrate Snapshot schemas to Effect Schema (#23747) 2026-04-21 17:37:27 -04:00
opencode-agent[bot] b1c3095edd chore: generate 2026-04-21 21:34:17 +00:00
Kit LangtonandGitHub b0f565b74a refactor(core): migrate ConfigPermission.Info to Effect Schema canonical (#23740) 2026-04-21 17:33:13 -04:00
Kit LangtonandGitHub 2ae64f426b refactor(core): migrate MessageV2.Format to Effect Schema (#23744) 2026-04-21 17:30:08 -04:00
Kit LangtonandGitHub 7933657135 migrate LSP data schemas to Effect Schema (#23745) 2026-04-21 17:26:50 -04:00
Frank caaddf0964 zen: ling 2.6 free 2026-04-21 17:06:31 -04:00
Ruben De SmetandGitHub 1a20703469 feat: add Mistral Small reasoning variant support (issue #19479) (#23735) 2026-04-21 16:45:06 -04:00
github-actions[bot] 8751f48a75 Update VOUCHED list
https://github.com/anomalyco/opencode/issues/23735#issuecomment-4291498854
2026-04-21 20:17:13 +00:00
Aiden ClineandGitHub 58232d896e fix: dont show variants for kimi models that dont support them (#23696) 2026-04-21 15:33:35 -04:00
cd6415f332 fix(tui): don't check for version upgrades if it's disabled by the user (#20089)
Co-authored-by: Aiden Cline <63023139+rekram1-node@users.noreply.github.com>
2026-04-21 15:30:15 -04:00
opencode c9fb8d0ce7 sync release versions for v1.14.20 2026-04-21 19:07:36 +00:00
opencode-agent[bot] 1e1a500603 chore: generate 2026-04-21 18:08:04 +00:00
Kit LangtonandGitHub ecc06a3d8f refactor(core): make Config.Info canonical Effect Schema (#23716) 2026-04-21 14:06:47 -04:00
opencode-agent[bot] 3205f122eb chore: update nix node_modules hashes 2026-04-21 16:57:27 +00:00
Aiden ClineandGitHub e95474df05 fix: revert parts of a824064c4 which caused system theme regression (#23714) 2026-04-21 12:08:12 -04:00
Kit LangtonandGitHub 96a534d8c6 feat(core): bridge GET /config through experimental HttpApi (#23712) 2026-04-21 16:05:23 +00:00
Kit LangtonandGitHub 9579429276 test(opencode): consolidate session prompt tests into Effect style (#23710) 2026-04-21 15:54:40 +00:00
Aiden ClineandGitHub 2486621ca1 chore: kill unused tool (#23701) 2026-04-21 11:31:20 -04:00
James LongandGitHub b5acc2203c fix(core): fix permissions routing when using remote workspace (#23593) 2026-04-21 14:42:54 +00:00
Brendan AllanandGitHub 8cc2c81d57 fix(app): prevent prompt input animations from rerunning on every render (#23676) 2026-04-21 19:12:32 +08:00
opencode-agent[bot] 8d2d12d9c6 chore: generate 2026-04-21 11:11:54 +00:00
Brendan AllanandGitHub 811a7e9a8b feat(app): allow disabling progress bar in settings (#23674) 2026-04-21 19:10:50 +08:00
Brendan AllanandGitHub febadc5589 fix(ui): correct diff render condition logic (#23670) 2026-04-21 18:49:04 +08:00
Luke ParkerandGitHub 92c005866b fix(core): use file:// URLs for local dynamic import() on Windows+Node (#23639) 2026-04-21 07:54:53 +00:00
OpeOginniandGitHub 224548d87d fix(desktop): adjust layout properties in DialogSelectServer component (#23589) 2026-04-21 14:38:56 +08:00
Frank 8a7bb7c6a9 zen: tpm routing 2026-04-21 02:36:40 -04:00
Brendan AllanandGitHub 22d33c57af fix(app): properly wrap produce calls in setProjects (#23638) 2026-04-21 14:11:23 +08:00
1e0137f624 go: promote kimi k2.6 usage limits (#23634)
Co-authored-by: Frank <frank@anoma.ly>
2026-04-21 02:01:52 -04:00
Brendan AllanandGitHub 38e2f4cdda fix(desktop-electron): add CORS headers to main window webRequest (#23633) 2026-04-21 13:32:31 +08:00
Frank bd54b68c12 zen: m2.7 & k2.6 2026-04-21 01:15:07 -04:00
opencode-agent[bot] a08aa21cb3 chore: generate 2026-04-21 04:40:02 +00:00
Brendan AllanandGitHub eb9906420f refactor(desktop-electron): enable contextIsolation and sandbox (#23523) 2026-04-21 12:38:59 +08:00
opencode-agent[bot] 4964ce480c chore: generate 2026-04-21 04:37:57 +00:00
Brendan AllanandGitHub e5687d646c electron: use custom oc:// protocol for renderer windows (#23516) 2026-04-21 12:36:56 +08:00
opencode-agent[bot] a38d53fe2f chore: generate 2026-04-21 02:42:45 +00:00
Frank 6278ce51ce zen: tpm routing 2026-04-20 22:41:36 -04:00
opencode-agent[bot] 53b0084ce2 chore: generate 2026-04-21 02:22:12 +00:00
Frank f74a255ca9 zen: tpm routing 2026-04-20 22:21:06 -04:00
Frank 3e8abac625 sync 2026-04-20 17:01:27 -04:00
opencode-agent[bot] 65e99fcc2e chore: generate 2026-04-20 20:06:22 +00:00
Frank bad025eba9 sync 2026-04-20 16:05:04 -04:00
opencode-agent[bot] 06dde3afd3 chore: generate 2026-04-20 19:04:24 +00:00
Frank ad65af28e7 zen: tpm routing 2026-04-20 15:02:54 -04:00
opencode-agent[bot] bd1bdc4f04 chore: generate 2026-04-20 18:29:48 +00:00
James LongandGitHub debcff2b6b feat(core): add debug workspace server (#23590) 2026-04-20 18:27:58 +00:00
opencode-agent[bot] 8b3323708d chore: generate 2026-04-20 17:43:32 +00:00
James MurdzaandGitHub 3406f18746 fix(plugin): add env parameter to WorkspaceAdaptor.create type (#23235) 2026-04-20 13:41:38 -04:00
opencode-agent[bot] 7e576eea41 chore: generate 2026-04-20 15:59:40 +00:00
JackandGitHub d68ebee555 docs(go): add Kimi K2.6 to Go and Zen content (#23558) 2026-04-20 23:58:32 +08:00
Frank ae7a3518f7 zen: tpm based routing 2026-04-20 09:56:26 -04:00
Chris YangandGitHub 16caaa2229 fix(app): fall back to icon.url in sidebar avatar (#18747) 2026-04-20 19:32:54 +08:00
黑墨水鱼andGitHub 91468fe455 fix(ui): use parentID matching instead of positional scan for assistant messages (#23093) 2026-04-20 07:35:06 +00:00
opencode 7c6948cf6f sync release versions for v1.14.19 2026-04-20 07:21:46 +00:00
Luke ParkerandGitHub 7a568a457f fix: defer MessageV2.Assistant.shape access to break circular dep in compiled binary (#23495) 2026-04-20 06:39:13 +00:00
opencode-agent[bot] 3ddc69ec2b chore: update nix node_modules hashes 2026-04-20 06:36:01 +00:00
opencode-agent[bot] f3d5a71620 chore: generate 2026-04-20 06:07:28 +00:00
Aiden ClineandGitHub c6c56ac2cf tweak: rename tail_tokens -> preserve_recent_tokens (#23491) 2026-04-20 01:06:29 -05:00
Aiden ClineandGitHub e539efe2b9 fix: patch arborist to get around bun bug (#23460) 2026-04-20 00:49:46 -05:00
Brendan AllanandGitHub 687b758882 app: better loading (#23489) 2026-04-20 05:17:37 +00:00
opencode-agent[bot] 84e322b0fd chore: generate 2026-04-20 05:15:29 +00:00
Aiden ClineandGitHub 8bc4f91fd9 fix: parallel edits sometimes would override each other (#23483) 2026-04-20 00:14:21 -05:00
Brendan AllanandGitHub 93e633fb7d refactor(app): move QueryProvider to AppInterface (#23484) 2026-04-20 12:51:34 +08:00
opencode-agent[bot] cbe702c09d chore: generate 2026-04-20 04:40:12 +00:00
Luke ParkerandGitHub a7a85c94b8 fix(core): fix Windows managed install and bump ripgrep to 15.1.0 for ARM64 support (#23477) 2026-04-20 14:39:15 +10:00
6e0178655b feat(provider): add NVIDIA to popular providers, docs, and attribution headers (#22927)
Co-authored-by: Kit Langton <kit.langton@gmail.com>
Co-authored-by: Aiden Cline <63023139+rekram1-node@users.noreply.github.com>
2026-04-19 19:57:49 -05:00
Dax Raad e4be557928 ci: skip beta smoke fixes for now 2026-04-19 20:01:30 -04:00
Dax Raad b9640fc7e4 core: fix session compaction test to properly enable prune config option 2026-04-19 19:53:43 -04:00
opencode-agent[bot] 29f05cb1ee chore: generate 2026-04-19 23:48:44 +00:00
Dax Raad 48acab48ad ci: skip Docker builds during preview releases to save time 2026-04-19 19:47:29 -04:00
Dax Raad 5ae74aa881 Merge branch 'nxl/improve-compaction-strategy' into dev 2026-04-19 19:38:46 -04:00
Dax Raad 6eddf08244 flip toolcall prune defaults 2026-04-19 19:34:44 -04:00
opencode-agent[bot] 9c7e52b8a1 chore: update nix node_modules hashes 2026-04-19 22:52:42 +00:00
SebastianandGitHub a824064c4c stabilize TUI theme persistence and KV writes (#23188) 2026-04-20 00:10:31 +02:00
opencode-agent[bot] 33b2795cc8 chore: generate 2026-04-19 09:47:36 +00:00
Luke ParkerandGitHub 10bd044c55 feat: add terminal font settings and built-in Nerd Font (#23391) 2026-04-19 19:46:34 +10:00
opencode c09bcfe531 sync release versions for v1.14.18 2026-04-19 09:36:56 +00:00
Brendan AllanandGitHub 83227be0ca fix(version): remove --target flag from beta release creation (#23403) 2026-04-19 17:05:03 +08:00
opencode-agent[bot] 8ee47a0533 chore: update nix node_modules hashes 2026-04-19 08:29:51 +00:00
Brendan AllanandGitHub a546e88f37 fix(desktop-electron): run JSON migration before spawning sidecar (#23396) 2026-04-19 15:53:47 +08:00
opencode-agent[bot] e998c9e9cb chore: update nix node_modules hashes 2026-04-19 07:35:27 +00:00
889087c966 fix(ripgrep): restore native rg backend (#22773)
Co-authored-by: LukeParkerDev <10430890+Hona@users.noreply.github.com>
2026-04-19 06:58:15 +00:00
opencode-agent[bot] 7f3b64c7c4 chore: update nix node_modules hashes 2026-04-19 06:38:10 +00:00
DaxandGitHub e60a6e3a82 fix: change Free download button text to Download (#23388) 2026-04-19 02:19:40 -04:00
opencode-agent[bot] 135c8f0e99 chore: generate 2026-04-19 05:59:31 +00:00
opencode-agent[bot] f02504bb80 chore: generate 2026-04-19 05:58:31 +00:00
Dax Raad 40834fdf2f core: allow users with credits but no payment method to access zen mode 2026-04-19 01:57:16 -04:00
Aiden ClineandGitHub fc0588954b fix (#23385) 2026-04-19 00:45:44 -05:00
opencode-agent[bot] 75960e3bf3 chore: generate 2026-04-19 04:25:23 +00:00
Ariane EmoryandGitHub f14ac472a3 docs: document --dangerously-skip-permissions CLI flag (#23371) 2026-04-18 23:24:23 -05:00
opencode-agent[bot] 9ed93715ef chore: update nix node_modules hashes 2026-04-19 03:40:53 +00:00
Luke ParkerandGitHub b34ca44abe fix incorrect config directory by lazily loading electron-store (#23373) 2026-04-19 13:06:07 +10:00
opencode 40ba8f3570 sync release versions for v1.14.17 2026-04-19 03:02:14 +00:00
Luke ParkerandGitHub e543acf923 chore: bump electron and fix taskbar icon (#23368) 2026-04-19 02:35:02 +00:00
Dax Raad d183568644 core: ensure executable permissions are set before Docker builds
Fixes an issue where GitHub artifact downloads could strip executable bits
from binaries, causing Docker builds to fail when using unpacked dist files
directly rather than published tarballs. The chmod now runs before the
publish check to guarantee binaries are executable.
2026-04-18 22:32:53 -04:00
Dax Raad f27eb8f09e fix plugins reinstalling too often 2026-04-18 20:02:24 -04:00
Dax Raad ad0545335a ci 2026-04-18 19:29:21 -04:00
Dax Raad cfbbae7323 ci 2026-04-18 18:59:44 -04:00
Dax Raad 940f971ca0 ci: fix 2026-04-18 18:56:14 -04:00
Aiden ClineandGitHub 78ca49a1bc test: fix bedrock test (#23351) 2026-04-18 17:46:15 -05:00
1d54b0e540 Stefan/enterprise forms waitlist (#23158)
Co-authored-by: Ryan Vogel <me@ryan.ceo>
2026-04-18 18:30:28 -04:00
opencode-agent[bot] 7e971d8302 chore: generate 2026-04-18 21:37:45 +00:00
Frank 54b3b3fe05 zen: redeem go 2026-04-18 17:33:28 -04:00
Frank 9d012b0621 zen: redeem credit 2026-04-18 17:33:28 -04:00
opencode-agent[bot] fbb0a93e12 chore: update nix node_modules hashes 2026-04-18 21:32:47 +00:00
Aiden ClineandGitHub e2e7a8d722 fix: ensure display: summarized is sent by default for bedrock (#23343) 2026-04-18 16:04:00 -05:00
Aiden ClineandGitHub ce7923adaf chore: bump @ai-sdk/amazon-bedrock (#23341) 2026-04-18 16:00:46 -05:00
DaxandGitHub a26d53151b tui: allow full-session forks from the session dialog (#23339) 2026-04-18 20:20:23 +00:00
Dax Raad 5eaef6b758 release: avoid package.json drift during publish 2026-04-18 12:32:23 -04:00
opencode-agent[bot] c5c38cad9c chore: generate 2026-04-18 16:00:01 +00:00
Kit LangtonandGitHub 9918f389e7 fix: detect attachment mime from file contents (#23291) 2026-04-18 11:59:08 -04:00
opencode-agent[bot] dd8c424806 chore: generate 2026-04-18 15:21:48 +00:00
Dax Raad 078d8a07cf core: support OTEL_RESOURCE_ATTRIBUTES environment variable for custom telemetry attributes
Users can now pass custom OpenTelemetry resource attributes via the OTEL_RESOURCE_ATTRIBUTES environment variable (comma-separated key=value format). These attributes are automatically included in all telemetry data sent from both the main process and workspace environments, enabling better observability integration with existing monitoring systems that rely on custom resource tags.
2026-04-18 11:20:29 -04:00
Dax Raad 1ee712e549 core: fix early return when node_modules is missing during package install 2026-04-18 10:42:33 -04:00
Dax Raad 55315bdffa tui: fix sync loading indicator to properly show loading state on startup 2026-04-18 10:39:10 -04:00
Dax Raad 882b8e1e75 core: track retry attempts with detailed error context on assistant entries
users can now see when transient failures occur during assistant responses,
such as rate limits or provider overloads, giving visibility into what
issues were encountered and automatically resolved before the final response
2026-04-18 10:38:35 -04:00
opencode-agent[bot] 95edbc0ae6 chore: generate 2026-04-18 05:49:37 +00:00
Dax Raad 11cd4fb639 core: extract session entry stepping logic into dedicated module
Move the step function from session-entry.ts to session-entry-stepper.ts and remove immer dependency. Add static fromEvent factory methods to Synthetic, Assistant, and Compaction classes for cleaner event-to-entry conversion.
2026-04-18 01:48:21 -04:00
Aiden ClineandGitHub 9c16bd1e30 fix: make skills logic more token efficient (#23253) 2026-04-17 23:51:16 -05:00
opencode-agent[bot] 5e9d5c734e chore: generate 2026-04-18 03:52:28 +00:00
Kit LangtonandGitHub b382d1a467 docs(effect): track schema migration progress with concrete file checklists (#23242) 2026-04-18 03:51:30 +00:00
Kit LangtonandGitHub 23f31475e7 refactor(config): migrate config.ts root Info to Effect Schema (#23241) 2026-04-18 03:44:35 +00:00
OpeOginniandGitHub c0eab9e442 fix(desktop): adjust ui tool diff sticky header offset (#23149) 2026-04-18 11:31:38 +08:00
opencode-agent[bot] 8a1e85d0c8 chore: generate 2026-04-18 03:17:28 +00:00
Kit LangtonandGitHub 2793502db2 refactor(config): migrate agent.ts Info to Effect Schema (#23237) 2026-04-18 03:16:24 +00:00
opencode-agent[bot] 9f7bd0246c chore: generate 2026-04-18 03:05:59 +00:00
Kit LangtonandGitHub a6a4350d10 refactor(config): migrate permission.ts Info to Effect Schema (#23231) 2026-04-18 03:05:06 +00:00
Kit LangtonandGitHub 471b9f4dc4 refactor: use InstanceState context in worktree cleanup paths (#23019) 2026-04-17 23:04:16 -04:00
Kit LangtonandGitHub 24fb9b1296 fix: stop rewriting dev during release publish (#22982) 2026-04-18 02:53:19 +00:00
Kit LangtonandGitHub 3573019916 fix(generate): make openapi output deterministic by formatting in-place (#23228) 2026-04-17 22:31:21 -04:00
Kit LangtonandGitHub fc5b353144 refactor(config): migrate keybinds.ts to Effect Schema (#23227) 2026-04-18 02:28:45 +00:00
Kit LangtonandGitHub 1dd257b76a refactor: use instance state in small services (#23022) 2026-04-18 02:16:15 +00:00
Kit LangtonandGitHub 5fa1673341 refactor: use InstanceState context in File service (#23015) 2026-04-17 22:08:57 -04:00
opencode-agent[bot] daaa1c7e26 chore: generate 2026-04-18 02:03:30 +00:00
Kit LangtonandGitHub 1fae784b81 feat(effect-zod): add ZodPreprocess annotation for pre-parse transforms (#23222) 2026-04-18 02:02:37 +00:00
Aiden ClineandGitHub 81b7b58a5e fix: gh copilot issue w/ haiku (eager_input_streaming not supported) (#23223) 2026-04-17 20:57:48 -05:00
opencode-agent[bot] 866188a643 chore: generate 2026-04-18 01:48:50 +00:00
Kit LangtonandGitHub e6fd57165e refactor: remove ambient instance reads from lsp (#23023) 2026-04-17 21:47:59 -04:00
Kit LangtonandGitHub a5d99e7a3c refactor: pass formatter instance context explicitly (#23020) 2026-04-18 01:22:36 +00:00
opencode-agent[bot] a92c75e5f4 chore: generate 2026-04-18 01:21:01 +00:00
Kit LangtonandGitHub 826fd3350c refactor(config): migrate Server + Layout to Effect Schema (#23216) 2026-04-18 01:20:06 +00:00
Kit LangtonandGitHub 23a2d01282 fix(observability): standardize session telemetry attrs (#23213) 2026-04-17 21:14:23 -04:00
Kit LangtonandGitHub 5181f9b4e1 refactor(config): drop ZodOverride from PositiveInt in provider.ts (#23215) 2026-04-18 01:04:40 +00:00
opencode-agent[bot] f52ae28432 chore: generate 2026-04-18 00:56:33 +00:00
Kit LangtonandGitHub 36119ff173 feat(effect-zod): translate Schema.withDecodingDefault into zod .default() (#23207) 2026-04-17 20:55:38 -04:00
Kit LangtonandGitHub bb90f3bbf9 feat(effect-zod): translate well-known filters into native Zod methods (#23209) 2026-04-17 20:50:36 -04:00
Kit Langtonandopencode 05cdb7c107 refactor(v2): tag session unions and exhaustively match events (#23201) 2026-04-18 00:29:26 +00:00
Kit Langtonandopencode b493dabfe6 docs(effect): refresh migration status specs (#23206) 2026-04-18 00:29:26 +00:00
opencode-agent[bot]andopencode c4816f944e chore: generate 2026-04-18 00:29:26 +00:00
Kit Langtonandopencode 211136e3a8 feat(effect-zod): transform support + walk memoization + flattened checks (#23203) 2026-04-18 00:29:26 +00:00
opencode-agent[bot]andopencode cf0a53c501 chore: generate 2026-04-18 00:29:26 +00:00
Kit Langtonandopencode 2899984819 refactor(config): migrate provider (Model + Info) to Effect Schema (#23197) 2026-04-18 00:29:26 +00:00
Kit Langtonandopencode eafbe5c57c refactor(server): align route-span attrs with OTel semantic conventions (#23198) 2026-04-18 00:29:26 +00:00
Kit Langtonandopencode 7b98f544ff feat(effect-zod): add catchall (StructWithRest) support to the walker (#23186) 2026-04-18 00:29:26 +00:00
Kit Langtonandopencode b5aba5807c feat(tui): show session ID in sidebar on non-prod channels (#23185) 2026-04-18 00:29:26 +00:00
Kit Langtonandopencode d5c4c26b4b feat(server): auto-tag route spans with route params (session.id, message.id, …) (#23189) 2026-04-18 00:29:26 +00:00
opencode a35b8a95c2 release: v1.4.11 2026-04-18 00:29:16 +00:00
DaxandGitHub cded68a2e2 refactor(npm): use object-based package spec for install API (#23181) 2026-04-17 17:30:50 -04:00
Aiden ClineandGitHub 0068ccec35 fix: ensure copilot model list filters out disabled models (#23176) 2026-04-17 16:27:32 -05:00
opencode-agent[bot] 89e8994fd1 chore: generate 2026-04-17 21:08:00 +00:00
Kit LangtonandGitHub 5980b0a5ee feat(effect-zod): add tuple support; migrate config/plugin to Effect Schema (#23178) 2026-04-17 21:06:55 +00:00
opencode-agent[bot] 89029a20ef chore: generate 2026-04-17 21:00:20 +00:00
Kit LangtonandGitHub ce69bd97b9 refactor(config): migrate model-id and command to Effect Schema (#23175) 2026-04-17 20:59:24 +00:00
Kit LangtonandGitHub 999d8651aa feat(server): wrap remaining route handlers in request spans (#23169) 2026-04-17 16:52:40 -04:00
opencode-agent[bot] ed0f022502 chore: generate 2026-04-17 20:50:37 +00:00
Kit LangtonandGitHub b1307d5c2a refactor(config): migrate skills, formatter, console-state to Effect Schema (#23162) 2026-04-17 20:49:36 +00:00
opencode-agent[bot] dc16013b4f chore: generate 2026-04-17 20:47:05 +00:00
Kit LangtonandGitHub e7686dbd64 feat(effect-zod): translate Schema.check filters into zod .superRefine + promote LSP refinement to Effect layer (#23173) 2026-04-17 20:46:05 +00:00
James LongandGitHub 47f553f9ba fix(core): more explicit routing to fix workspace instance issue (#23171) 2026-04-17 16:39:34 -04:00
Kit LangtonandGitHub d11268ece7 refactor(config): migrate permission Action/Object/Rule leaves to Effect Schema (#23168) 2026-04-17 20:35:42 +00:00
Kit LangtonandGitHub 650a13a690 refactor(config): migrate lsp schemas to Effect Schema (#23167) 2026-04-17 20:34:47 +00:00
opencode-agent[bot] 54435325b6 chore: generate 2026-04-17 20:26:43 +00:00
Kit LangtonandGitHub 11fa257549 refactor(config): migrate mcp schemas to Effect Schema.Class (#23163) 2026-04-17 20:25:49 +00:00
Kit LangtonandGitHub 6af8ab0df2 docs(http-api): refresh bridge inventory and clarify Schema.Class vs Struct (#23164) 2026-04-17 16:20:57 -04:00
Kit LangtonandGitHub 984f5ed6eb fix(opencode): skip share sync for unshared sessions (#23159) 2026-04-17 20:15:24 +00:00
opencode-agent[bot]andopencode c2061c6bbf chore: generate 2026-04-17 20:13:34 +00:00
Daxandopencode b708e8431e docs(opencode): annotate plugin loader flow (#23160) 2026-04-17 20:13:34 +00:00
opencode 9b6c397171 release: v1.4.10 2026-04-17 20:13:25 +00:00
opencode-agent[bot] 9b0659d4f9 chore: generate 2026-04-17 19:30:28 +00:00
Kit LangtonandGitHub f83cecaaf6 fix(opencode): untrace streaming event hot paths (#23156) 2026-04-17 15:29:32 -04:00
James LongandGitHub aa05b9abe5 fix(core): pass OTEL config to workspace env (#23154) 2026-04-17 15:25:58 -04:00
Kit LangtonandGitHub 68834cfcc3 fix(opencode): normalize provider metadata and tag otel runs (#23140) 2026-04-17 15:22:08 -04:00
James LongandGitHub 5621373bc2 fix(core): move instance middleware after control plane routes (#23150) 2026-04-17 15:20:11 -04:00
opencode-agent[bot] 88582566bf chore: update nix node_modules hashes 2026-04-17 19:18:55 +00:00
opencode-agent[bot] d6e1362fee chore: generate 2026-04-17 19:15:07 +00:00
James LongandGitHub b275b8580d feat(tui): minor UX improvements for workspaces (#23146) 2026-04-17 15:14:05 -04:00
DaxandGitHub 467be08e67 refactor: consolidate npm exports and trace flock acquisition (#23151) 2026-04-17 18:58:37 +00:00
Aiden ClineandGitHub bbb422d125 chore: bump ai to 6.0.168 and @ai-sdk/gateway to 3.0.104 (#23145) 2026-04-17 13:47:22 -05:00
Dax Raad b1f076558c test: align plugin loader npm mocks
- switch plugin loader tests to the effect npm module
- return Option.none() for mocked npm entrypoints
- keep test fixtures aligned with the current Npm.add contract
2026-04-17 14:33:02 -04:00
Dax Raad 992435aaf8 do not flock until reify 2026-04-17 14:18:48 -04:00
Dax Raad 2f73e73e9d trace npm fully 2026-04-17 14:08:45 -04:00
James LongandGitHub 4c30a78cd9 fix: revert sdk generation script change (#23133) 2026-04-17 13:33:11 -04:00
James LongandGitHub a8c78fc005 fix(core): add historical sync on workspace connect (#23121) 2026-04-17 13:30:09 -04:00
opencode-agent[bot] fcb473ff64 chore: update nix node_modules hashes 2026-04-17 17:25:44 +00:00
James LongandGitHub 797953c88d when generating sdk only format sdk, much faster (#23122) 2026-04-17 13:01:22 -04:00
opencode-agent[bot] ce0cfb0ea5 chore: generate 2026-04-17 16:46:34 +00:00
Kit LangtonandGitHub 13dfe569ef tui: fix agent cycling and prompt metadata polish (#23115) 2026-04-17 12:45:29 -04:00
Aiden ClineandGitHub c491161c0c chore: bump @ai-sdk/anthropic to 3.0.71 and dependents (#23120) 2026-04-17 11:40:24 -05:00
fde3d9133b fix(opencode): pass EXA_API_KEY to websearch tool to avoid rate limits (#16362)
Co-authored-by: Dax Raad <d@ironbay.co>
Co-authored-by: Aiden Cline <aidenpcline@gmail.com>
Co-authored-by: Aiden Cline <63023139+rekram1-node@users.noreply.github.com>
2026-04-17 11:28:23 -05:00
Vladimir GlafirovandGitHub 0d582f9d3f chore: bump gitlab-ai-provider to 6.6.0 (#23057) 2026-04-17 11:22:43 -05:00
Dax Raadandopencode 1a59133168 Improve light mode dark mode copy 2026-04-17 16:19:57 +00:00
opencode 803d9eb7ad release: v1.4.9 2026-04-17 16:19:46 +00:00
Dax Raad a27d3c1623 tui: fix session resumption with --session-id flag to navigate after app initialization
Previously when passing a session ID directly, the route was set during initial
render which could cause navigation issues before the router was fully ready.
Now the session navigation happens after initialization completes, ensuring
the TUI properly loads the requested session when users resume with --session-id.
2026-04-17 11:41:24 -04:00
Dax Raad 551216a452 fix incorrect light mode in ghostty 2026-04-17 11:32:17 -04:00
opencode-agent[bot] 38cd3979f2 chore: update nix node_modules hashes 2026-04-17 15:31:50 +00:00
3fe602cda3 feat: add LLM Gateway provider (#7847)
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Aiden Cline <63023139+rekram1-node@users.noreply.github.com>
Co-authored-by: Aiden Cline <aidenpcline@gmail.com>
2026-04-17 10:29:31 -05:00
opencode-agent[bot] 3a4b49095c chore: generate 2026-04-17 15:26:45 +00:00
Jen PersonandGitHub ac5b395c5d docs: adding Mistral to docs as a provider (it is already a provider, just docs update) #23070 (#23072) 2026-04-17 10:25:42 -05:00
OpeOginniandGitHub 8fbbca5f4b fix(opencode): rescrict github copilot opus 4.7 variants to "medium" (#23097) 2026-04-17 10:25:12 -05:00
Brendan AllanandGitHub 2415820ecd fix: conditionally show file tree in beta channel (#23099) 2026-04-17 15:13:59 +00:00
Frank 20103eb97b sync 2026-04-17 10:53:45 -04:00
Dax Raad 10c4ab9a3d roll back opentui 2026-04-17 10:51:02 -04:00
Dax Raad 7e39c9b950 back to opentui 0.1.99 2026-04-17 10:43:17 -04:00
opencode-agent[bot] cc063d4c32 chore: generate 2026-04-17 13:56:17 +00:00
Frank 3707e4a49c zen: routing logic 2026-04-17 09:54:47 -04:00
opencode-agent[bot] cb425ac927 chore: generate 2026-04-17 13:53:11 +00:00
James LongandGitHub 0f80c827ed feat(core): exponential backoff of workspace reconnect (#23083) 2026-04-17 09:52:10 -04:00
Dax Raad fffc496f41 remove log 2026-04-17 09:46:35 -04:00
opencode 06ae43920b release: v1.4.8 2026-04-17 13:37:06 +00:00
opencode-agent[bot] e78d75a003 chore: update nix node_modules hashes 2026-04-17 13:07:11 +00:00
SebastianandGitHub ec3ac0c4b0 upgrade opentui to 0.1.100 (#22928) 2026-04-17 14:29:46 +02:00
opencode-agent[bot] c57c5315c1 chore: generate 2026-04-17 07:27:13 +00:00
Brendan AllanandGitHub a726530735 fix(app): workspace loading and persist ready state (#23046) 2026-04-17 07:26:14 +00:00
DaxandGitHub d9950598d0 core: migrate config loading to Effect framework (#23032) 2026-04-17 06:44:01 +00:00
opencode-agent[bot] 81f0885879 chore: generate 2026-04-17 06:13:42 +00:00
DaxandGitHub 65b2a10e97 fade in prompt metadata transitions (#23037) 2026-04-17 06:12:41 +00:00
James LongandGitHub 7605acff65 refactor(core): move server routes around to clarify workspacing (#23031) 2026-04-17 02:06:20 -04:00
Dax Raad e7f8f7fa3b fix crash on experimental 2026-04-17 01:14:08 -04:00
James LongandGitHub 72d7cb717d remove accidental commit of daytona plugin (#23030) 2026-04-17 00:42:45 -04:00
opencode-agent[bot] f0caeb9b25 chore: generate 2026-04-17 04:32:17 +00:00
Aiden ClineandGitHub 76a141090e chore: delete filetime module (#22999) 2026-04-16 23:31:21 -05:00
DaxandGitHub 4bd5a158a5 fix: preserve prompt input across unmount/remount cycles (#22508) 2026-04-17 04:23:30 +00:00
opencode-agent[bot] dfaae14544 chore: update nix node_modules hashes 2026-04-17 04:14:26 +00:00
Brendan AllanandGitHub 79e9baf55a fix(app): use fetchQuery instead of ensureQueryData in global sync (#23025) 2026-04-17 03:54:19 +00:00
Brendan Allan a4882290aa Merge branch 'dev' into nxl/improve-compaction-strategy 2026-04-17 11:53:17 +08:00
Kit LangtonandGitHub 9ee89f7868 refactor: move project read routes onto HttpApi (#23003) 2026-04-17 03:48:12 +00:00
opencode-agent[bot] 67dbb3cf18 chore: generate 2026-04-17 03:37:21 +00:00
Kit LangtonandGitHub 4260c40efa refactor(tui): inline final Go shimmer settings (#23017) 2026-04-17 03:36:21 +00:00
James LongandGitHub 0bedea52b1 fix(tui): tui resiliency when workspace is dead, disable directory filter in session list (#23013) 2026-04-16 23:35:36 -04:00
fbbab9d6c8 feat(app): hide desktop titlebar tools behind settings (#19029)
Co-authored-by: Brendan Allan <git@brendonovich.dev>
Co-authored-by: Brendan Allan <brendonovich@outlook.com>
2026-04-17 03:31:00 +00:00
Kit LangtonandGitHub cccb907a9b feat(tui): animated GO logo + radial pulse in free-limit upsell dialog (#22976) 2026-04-16 23:19:18 -04:00
Kit LangtonandGitHub ee7339f2c6 refactor: move provider and config provider routes onto HttpApi (#23004) 2026-04-16 23:10:45 -04:00
Kit LangtonandGitHub c51f3e35ca chore: retire namespace migration tooling + document module shape (#23010) 2026-04-17 02:48:40 +00:00
7b3bb9a761 fix: preserve plugin tool metadata in execute result (#22827)
Co-authored-by: jquense <jquense@ramp.com>
Co-authored-by: Aiden Cline <63023139+rekram1-node@users.noreply.github.com>
2026-04-16 21:38:21 -05:00
opencode-agent[bot] dc38f22bd8 chore: generate 2026-04-17 02:34:07 +00:00
DaxandGitHub 220e3e9a2b refactor: make formatter config opt-in (#22997) 2026-04-17 02:33:09 +00:00
Brendan AllanandGitHub f135c0b5ee app: use tanstack query to load session vcs state (#22277) 2026-04-17 02:27:08 +00:00
opencode-agent[bot] ebe6ea580d chore: generate 2026-04-17 02:26:48 +00:00
DaxandGitHub ee708040f6 fix: prefer real undo filenames over /dev/null (#23006) 2026-04-16 22:25:43 -04:00
Kit LangtonandGitHub 61c4815a37 refactor: unwrap FileWatcher namespace + self-reexport (redo) (#23000) 2026-04-17 02:20:43 +00:00
DaxandGitHub 01bb54a94d refactor: split config parsing steps (#22996) 2026-04-17 01:57:43 +00:00
Kit LangtonandGitHub f592c3846b refactor: convert Flag namespace to const object with getters (#22984) 2026-04-17 01:57:21 +00:00
Kit LangtonandGitHub c026e25088 refactor: eliminate account/ barrel, route consumers to sibling files (#22995) 2026-04-17 01:55:50 +00:00
Kit LangtonandGitHub 8ba73bed23 refactor: collapse auth/ barrel — merge auth.ts into index.ts + self-reexport (#22993) 2026-04-17 01:52:19 +00:00
Kit LangtonandGitHub 4f8986aa48 refactor: unwrap Question namespace + fix script to emit "." for index.ts (#22992) 2026-04-17 01:51:02 +00:00
Kit LangtonandGitHub 9c87a144e8 refactor: normalize AccountRepo to canonical Effect service pattern (#22991) 2026-04-17 01:43:57 +00:00
opencode-agent[bot] 5b9fa32255 chore: generate 2026-04-17 01:36:45 +00:00
DaxandGitHub f13778215a perf: speed up skill directory discovery (#22990) 2026-04-17 01:35:47 +00:00
DaxandGitHub 326471a25c refactor: split config lsp and formatter schemas (#22986) 2026-04-17 01:35:26 +00:00
DaxandGitHub 6405e3a7b1 tui: stabilize session dialog ordering (#22987) 2026-04-17 01:32:36 +00:00
Kit LangtonandGitHub 8afb625bab refactor: extract Diagnostic namespace into lsp/diagnostic.ts + self-reexport (#22983) 2026-04-17 01:19:01 +00:00
Kit LangtonandGitHub c59df636cc chore: delete empty v2/session-common + collapse patch barrel (#22981) 2026-04-17 01:02:09 +00:00
Kit LangtonandGitHub 94878d76f8 refactor: unwrap TuiPluginRuntime namespace + self-reexport (#22980) 2026-04-17 01:02:07 +00:00
Kit LangtonandGitHub 5022895e2b refactor: unwrap ExperimentalHttpApiServer namespace + self-reexport (#22979) 2026-04-17 01:01:24 +00:00
Kit LangtonandGitHub 54046e0b98 refactor: unwrap SessionV2 namespace + self-reexport (#22978) 2026-04-17 01:00:30 +00:00
Kit LangtonandGitHub d2cb1613ac refactor: unwrap SessionEntry namespace + self-reexport (#22977) 2026-04-17 00:59:42 +00:00
opencode-agent[bot] 266fb93422 chore: generate 2026-04-17 00:50:44 +00:00
Kit LangtonandGitHub 51d8219c46 refactor: unwrap session/ tier-2 namespaces + self-reexport (#22973) 2026-04-17 00:49:39 +00:00
Dax Raad d6af5a686c tui: convert TuiConfig namespace to ES module exports 2026-04-16 20:46:40 -04:00
Dax Raad 39342b0e75 tui: fix Windows terminal suspend and input undo keybindings
On Windows, native terminals don't support POSIX suspend (ctrl+z), so we now
assign ctrl+z to input undo instead of terminal suspend. Terminal suspend is
disabled on Windows to avoid conflicts with the undo functionality.
2026-04-16 20:37:58 -04:00
Kit LangtonandGitHub 54078c4cae refactor: unwrap Shell namespace + self-reexport (#22964) 2026-04-16 20:11:19 -04:00
Kit LangtonandGitHub c0bfccc15e tooling: add unwrap-and-self-reexport + batch-unwrap-pr scripts (#22929) 2026-04-16 20:11:17 -04:00
opencode-agent[bot] 53dc7b1649 chore: generate 2026-04-17 00:04:01 +00:00
Kit LangtonandGitHub 635970b0a1 refactor: unwrap ConfigSkills namespace + self-reexport (#22950) 2026-04-17 00:02:53 +00:00
Kit LangtonandGitHub 059b32c212 refactor: unwrap Protected namespace + self-reexport (#22938) 2026-04-17 00:02:51 +00:00
Kit LangtonandGitHub 2704ad9110 refactor: unwrap TuiConfig namespace + self-reexport (#22952) 2026-04-17 00:02:24 +00:00
Kit LangtonandGitHub 06d247c709 refactor: unwrap FileIgnore namespace + self-reexport (#22937) 2026-04-17 00:02:08 +00:00
Kit LangtonandGitHub 974fa1b8b1 refactor: unwrap PluginMeta namespace + self-reexport (#22945) 2026-04-17 00:02:05 +00:00
Kit LangtonandGitHub fb02744460 refactor: unwrap Agent namespace + self-reexport (#22935) 2026-04-17 00:01:44 +00:00
Kit LangtonandGitHub 79732ab175 refactor: unwrap UI namespace + self-reexport (#22951) 2026-04-17 00:01:41 +00:00
Kit LangtonandGitHub f6dbb2f3e0 refactor: unwrap Heap namespace + self-reexport (#22931) 2026-04-17 00:01:37 +00:00
Kit LangtonandGitHub fdd5b77bfd refactor: unwrap McpAuth namespace + self-reexport (#22942) 2026-04-17 00:01:12 +00:00
Kit LangtonandGitHub cde105e7a8 refactor: unwrap CopilotModels namespace + self-reexport (#22947) 2026-04-17 00:01:09 +00:00
Kit LangtonandGitHub 1291e82bb4 refactor: unwrap ACP namespace + self-reexport (#22936) 2026-04-17 00:00:50 +00:00
Kit LangtonandGitHub 19d15d9ff7 refactor: unwrap ConfigProvider namespace + self-reexport (#22949) 2026-04-17 00:00:48 +00:00
Kit LangtonandGitHub 4e27804160 refactor: unwrap McpOAuthCallback namespace + self-reexport (#22943) 2026-04-17 00:00:46 +00:00
Kit LangtonandGitHub bae80af1b4 refactor: unwrap Workspace namespace + self-reexport (#22934) 2026-04-17 00:00:15 +00:00
opencode-agent[bot] f9aa3d77cd chore: generate 2026-04-16 23:53:10 +00:00
Kit LangtonandGitHub 5d47ea0918 refactor: unwrap ConfigMCP namespace + self-reexport (#22948) 2026-04-16 19:52:04 -04:00
Kit LangtonandGitHub c03fa36257 refactor: unwrap Server namespace + self-reexport (#22970) 2026-04-16 23:51:01 +00:00
Kit LangtonandGitHub 1089fa0415 refactor: unwrap ServerProxy namespace + self-reexport (#22969) 2026-04-16 23:50:32 +00:00
Kit LangtonandGitHub 715786bbf9 refactor: unwrap FileTime namespace + self-reexport (#22966) 2026-04-16 23:50:15 +00:00
Kit LangtonandGitHub 218eca7c2b refactor: unwrap MDNS namespace + self-reexport (#22968) 2026-04-16 23:50:11 +00:00
Kit LangtonandGitHub 30fc791480 refactor: unwrap Ripgrep namespace + self-reexport (#22965) 2026-04-16 19:49:52 -04:00
Kit LangtonandGitHub e2d161dfdd refactor: unwrap Identifier namespace + self-reexport (#22963) 2026-04-16 23:48:24 +00:00
Kit LangtonandGitHub 23d48a7cf1 refactor: unwrap BusEvent namespace + self-reexport (#22962) 2026-04-16 23:46:49 +00:00
Aiden ClineandGitHub cb18f2ef40 fix: ensure azure sets prompt cache key by default (#22957) 2026-04-16 17:45:35 -05:00
Dax Raad dbe2ff52b2 fix tui otel profiling 2026-04-16 18:40:22 -04:00
Dax Raad 9db40996cc fix build script 2026-04-16 18:01:58 -04:00
opencode 9f201d6370 release: v1.4.7 2026-04-16 21:54:54 +00:00
Kit LangtonandGitHub 0e86466f99 refactor: unwrap Discovery namespace to flat exports + self-reexport (#22878) 2026-04-16 16:59:30 -04:00
Kit LangtonandGitHub 32548bcb4a refactor: unwrap ConfigPlugin namespace to flat exports + self-reexport (#22876) 2026-04-16 16:59:17 -04:00
James LongandGitHub 86c54c5acc fix(tui): minor logging cleanup (#22924) 2026-04-16 16:58:17 -04:00
Aiden ClineandGitHub ae584332b3 fix: uncomment import (#22923) 2026-04-16 15:56:29 -05:00
Kit LangtonandGitHub 1694c5bfe1 refactor: collapse file barrel into file/index.ts (#22901) 2026-04-16 16:56:09 -04:00
Kit LangtonandGitHub cdfbb26c00 refactor: collapse bus barrel into bus/index.ts (#22902) 2026-04-16 16:55:57 -04:00
thakrarsagarGitHubopencode-agent[bot] <opencode-agent[bot]@users.noreply.github.com>rekram1-node
610c036ef1 fix(opencode): use low reasoning effort for GitHub Copilot gpt-5 models (#22824)
Co-authored-by: opencode-agent[bot] <opencode-agent[bot]@users.noreply.github.com>
Co-authored-by: rekram1-node <rekram1-node@users.noreply.github.com>
2026-04-16 15:44:58 -05:00
Kit LangtonandGitHub 2638e2acfa refactor: collapse plugin barrel into plugin/index.ts (#22914) 2026-04-16 20:37:13 +00:00
Kit LangtonandGitHub 49bbea5aed refactor: collapse snapshot barrel into snapshot/index.ts (#22916) 2026-04-16 20:36:45 +00:00
Kit LangtonandGitHub 5fccdc9fc7 refactor: collapse mcp barrel into mcp/index.ts (#22913) 2026-04-16 20:36:23 +00:00
Kit LangtonandGitHub 664b2c36e8 refactor: collapse git barrel into git/index.ts (#22909) 2026-04-16 20:36:07 +00:00
Kit LangtonandGitHub 964474a1b1 refactor: collapse permission barrel into permission/index.ts (#22915) 2026-04-16 20:36:04 +00:00
Kit LangtonandGitHub ab15fc1575 refactor: collapse npm barrel into npm/index.ts (#22911) 2026-04-16 20:36:02 +00:00
Kit LangtonandGitHub 99d392a4fb refactor: collapse skill barrel into skill/index.ts (#22912) 2026-04-16 20:35:43 +00:00
Kit LangtonandGitHub ae9a696607 refactor: collapse installation barrel into installation/index.ts (#22910) 2026-04-16 20:35:28 +00:00
Kit LangtonandGitHub bd51a0d35b refactor: collapse worktree barrel into worktree/index.ts (#22906) 2026-04-16 20:35:26 +00:00
Kit LangtonandGitHub 8c191b10c2 refactor: collapse ide barrel into ide/index.ts (#22904) 2026-04-16 20:35:04 +00:00
Kit LangtonandGitHub cb6a9253fe refactor: collapse sync barrel into sync/index.ts (#22907) 2026-04-16 20:34:33 +00:00
Kit LangtonandGitHub 23f97ac49d refactor: collapse global barrel into global/index.ts (#22905) 2026-04-16 20:33:52 +00:00
opencode-agent[bot] 021ab50fb1 chore: generate 2026-04-16 20:31:50 +00:00
Kit LangtonandGitHub 3fe906f517 refactor: collapse command barrel into command/index.ts (#22903) 2026-04-16 20:30:52 +00:00
James LongandGitHub a8d8a35cd3 feat(core): pass auth data to workspace (#22897) 2026-04-16 16:30:11 -04:00
Kit LangtonandGitHub 9b77430d0d refactor: collapse env barrel into env/index.ts (#22900) 2026-04-16 16:29:54 -04:00
Kit LangtonandGitHub 1045a43603 refactor: collapse format barrel into format/index.ts (#22898) 2026-04-16 16:29:51 -04:00
James LongandGitHub 26af77cd1e fix(core): fix detection of local installation channel (#22899) 2026-04-16 20:26:33 +00:00
Dax Raad 25a9de301a core: eager load config on startup for better traces and refactor npm install for improved error reporting
Config is now loaded eagerly during project bootstrap so users can see config loading in traces during startup. This helps diagnose configuration issues earlier in the initialization flow.

NPM installation logic has been refactored with a unified reify function and improved InstallFailedError that includes both the packages being installed and the target directory. This provides users with complete context when package installations fail, making it easier to identify which dependency or project directory caused the issue.
2026-04-16 16:23:19 -04:00
Kit LangtonandGitHub e0d71f124e tooling: add collapse-barrel.ts for single-namespace barrel migration (#22887) 2026-04-16 16:12:46 -04:00
Kit LangtonandGitHub 1c33b866ba fix: remove 10 more unnecessary as any casts in opencode core (#22882) 2026-04-16 20:11:05 +00:00
5e650fd9e2 fix(opencode): drop max_tokens for OpenAI reasoning models on Cloudflare AI Gateway (#22864)
Co-authored-by: Aiden Cline <63023139+rekram1-node@users.noreply.github.com>
2026-04-16 15:01:21 -05:00
Kit LangtonandGitHub 76275fc3ab refactor: move Pty into pty/index.ts with self-reexport (#22881) 2026-04-16 15:49:21 -04:00
Aiden ClineandGitHub 6c3b28db64 fix: ensure that double pasting doesnt happen after tui perf commit was merged (#22880) 2026-04-16 14:38:39 -05:00
Kit LangtonandGitHub 2fe9d94470 fix: remove 8 more unnecessary as any casts in opencode core (#22877) 2026-04-16 19:27:53 +00:00
Kit LangtonandGitHub 219b473e66 refactor: unwrap BashArity namespace to flat exports + self-reexport (#22874) 2026-04-16 15:24:24 -04:00
opencode-agent[bot] 7c1b30291c chore: update nix node_modules hashes 2026-04-16 19:19:52 +00:00
Aiden ClineandGitHub 47e0e2342c tweak: set display 'summarized' by default for opus 4.7 thorugh messages api (#22873) 2026-04-16 14:12:43 -05:00
Kit LangtonandGitHub bf4c107829 fix: remove 7 unnecessary as any casts in opencode core (#22840) 2026-04-16 15:07:02 -04:00
DaxandGitHub 9afbdc102c fix(test): make plugin loader theme source path separator-safe (#22870) 2026-04-16 14:45:17 -04:00
opencode-agent[bot] 370770122c chore: generate 2026-04-16 18:29:57 +00:00
Aiden ClineandGitHub 143817d44e chore: bump ai sdk deps for opus 4.7 (#22869) 2026-04-16 13:28:20 -05:00
Thomas ButlerandGitHub c60862fc9e fix: add missing glob dependency (#22851) 2026-04-16 13:21:04 -05:00
Dax Raad bee5f919fc core: reorganize ConfigPaths module export for cleaner dependency management 2026-04-16 13:33:54 -04:00
Dax Raad cefa7f04c6 core: reorganize ConfigPaths module export for cleaner dependency management 2026-04-16 13:32:22 -04:00
Dax Raad 03e20e6ac1 core: modularize config parsing to improve maintainability
Extract error handling, parsing logic, and variable substitution into dedicated
modules. This reduces duplication between tui.json and opencode.json parsing
and makes the config system easier to extend for future config formats.
2026-04-16 13:29:03 -04:00
Aiden ClineandGitHub c5deeee8c7 fix: ensure azure has store = true by default (#22764) 2026-04-16 12:19:01 -05:00
Dax Raad 8b1f0e2d90 core: add documentation comments to plugin configuration merge logic
Adds explanatory comments to config.ts and plugin.ts clarifying:

- How plugin specs are stored and normalized during config loading

- Why plugin_origins tracks provenance for location-sensitive decisions

- Why path-like specs are resolved early to prevent reinterpretation during merges

- How plugin deduplication works while keeping origin metadata for writes and diagnostics
2026-04-16 12:55:40 -04:00
Dax Raad 9bf2dfea35 core: refactor config schemas into separate modules for better maintainability 2026-04-16 12:47:09 -04:00
Dax Raad 33bb847a1d config: refactor 2026-04-16 12:40:24 -04:00
Dax Raad bfffc3c2c6 tui: ensure TUI plugins load with proper project context when multiple directories are open
Fixes potential plugin resolution issues when switching between projects by wrapping
plugin loading in Instance.provide(). This ensures each plugin resolves dependencies
relative to its correct project directory instead of inheriting context from whatever
instance happened to be active.

Also reorganizes config loading code into focused modules (command.ts, managed.ts,
plugin.ts) to make the codebase easier to maintain and test.
2026-04-16 12:40:24 -04:00
James LongandGitHub b28956f0db fix(core): better global sync event structure (#22858) 2026-04-16 12:35:37 -04:00
opencode-agent[bot] d82bc3a421 chore: generate 2026-04-16 16:26:12 +00:00
James LongandGitHub 06afd33291 refactor(tui): improve workspace management (#22691) 2026-04-16 12:24:40 -04:00
James LongandGitHub 305460b25f fix: add a few more tests for sync and session restore (#22837) 2026-04-16 12:15:44 -04:00
NacaiGitHubopencode-agent[bot] <opencode-agent[bot]@users.noreply.github.com>rekram1-node
8c0205a84a fix: align stale bot message with actual 60-day threshold (#22842)
Co-authored-by: opencode-agent[bot] <opencode-agent[bot]@users.noreply.github.com>
Co-authored-by: rekram1-node <rekram1-node@users.noreply.github.com>
2026-04-16 11:01:35 -05:00
378c05f202 feat: Add support for claude opus 4.7 xhigh adaptive reasoning effort (#22833)
Co-authored-by: Aiden Cline <63023139+rekram1-node@users.noreply.github.com>
2026-04-16 10:57:36 -05:00
Jérôme BenoitandGitHub cc7acd90ab fix(nix): add shared package to bun install filters (#22665) 2026-04-16 10:43:15 -05:00
Frank a200f6fb8b zen: opus 4.7 2026-04-16 11:32:56 -04:00
Dax Raad 2b1696f1d1 Revert "tui: fix path comparison in theme installer to handle different path formats"
This reverts commit 8ab17f5ce0.
2026-04-16 11:28:19 -04:00
Dax Raad 8ab17f5ce0 tui: fix path comparison in theme installer to handle different path formats 2026-04-16 11:18:44 -04:00
Dax Raad 6ce481e95b move useful scripts to script folder 2026-04-16 10:09:14 -04:00
Shoubhit Dash 42771c1db3 fix(compaction): budget retained tail with media 2026-04-16 17:30:29 +05:30
Shoubhit Dash 2e18a603f0 merge dev 2026-04-16 17:30:14 +05:30
opencode-agent[bot] 7341718f92 chore: generate 2026-04-16 07:15:05 +00:00
DaxandGitHub ef90b93205 fix: restore .gitignore logic for config dirs and migrate to shared Npm service (#22772) 2026-04-16 03:14:06 -04:00
DaxandGitHub 3f7df08be9 perf: make vcs init non-blocking by forking git branch resolution (#22771) 2026-04-16 03:02:19 -04:00
opencode-agent[bot] ef6c26c730 chore: update nix node_modules hashes 2026-04-16 06:59:47 +00:00
opencode-agent[bot] 8b3b608ba9 chore: generate 2026-04-16 06:11:24 +00:00
Brendan AllanandGitHub 97918500d4 app: start migrating bootstrap data fetching to TanStack Query (#22756) 2026-04-16 06:10:23 +00:00
Brendan AllanandGitHub e2c0803962 Fix desktop download asset names for beta channel (#22766) 2026-04-16 06:10:03 +00:00
f418fd5632 beta badge for desktop app (#14471)
Co-authored-by: Brendan Allan <git@brendonovich.dev>
2026-04-16 06:03:41 +00:00
DaxandGitHub 675a46e23e CLI perf: reduce deps (#22652) 2026-04-16 02:03:03 -04:00
opencode-agent[bot] 150ab07a83 chore: generate 2026-04-16 05:03:50 +00:00
Kit LangtonandGitHub 6b20838981 feat: unwrap provider namespaces to flat exports + barrel (#22760) 2026-04-16 05:02:50 +00:00
opencode-agent[bot] c8af8f96ce chore: generate 2026-04-16 03:57:53 +00:00
Kit LangtonandGitHub 5011465c81 feat: unwrap tool namespaces to flat exports + barrel (#22762) 2026-04-16 03:56:54 +00:00
Kit LangtonandGitHub f6cc228684 feat: unwrap cli-tui namespaces to flat exports + barrel (#22759) 2026-04-16 03:56:51 +00:00
Kit LangtonandGitHub 9f4b73b6a3 fix: clean up final 16 no-unused-vars warnings (#22751) 2026-04-16 03:54:21 +00:00
Kit LangtonandGitHub bd29004831 feat: enable type-aware no-misused-spread rule, fix 8 violations (#22749) 2026-04-16 03:50:50 +00:00
Kit LangtonandGitHub 8aa0f9fe95 feat: enable type-aware no-base-to-string rule, fix 56 violations (#22750) 2026-04-16 03:50:47 +00:00
Kit LangtonandGitHub c802695ee9 docs: add circular import rules to namespace treeshake spec (#22754) 2026-04-15 23:44:08 -04:00
opencode-agent[bot] 225a769411 chore: generate 2026-04-16 03:42:25 +00:00
Kit LangtonandGitHub 0e20382396 fix: resolve circular sibling imports causing runtime ReferenceError (#22752) 2026-04-15 23:41:34 -04:00
Kit LangtonandGitHub 509bc11f81 feat: unwrap lsp namespaces to flat exports + barrel (#22748) 2026-04-15 23:30:52 -04:00
Kit LangtonandGitHub f24207844f feat: unwrap storage namespaces to flat exports + barrel (#22747) 2026-04-15 23:30:49 -04:00
Kit LangtonandGitHub 1ca257e356 feat: unwrap config namespaces to flat exports + barrel (#22746) 2026-04-15 23:29:14 -04:00
Kit LangtonandGitHub d4cfbd020d feat: unwrap effect namespaces to flat exports + barrel (#22745) 2026-04-15 23:29:12 -04:00
Kit LangtonandGitHub 581d5208ca feat: unwrap share namespaces to flat exports + barrel (#22744) 2026-04-15 23:28:46 -04:00
Kit LangtonandGitHub a427a28fa9 feat: unwrap project namespaces to flat exports + barrel (#22743) 2026-04-15 23:28:46 -04:00
opencode-agent[bot] 0beaf04df5 chore: generate 2026-04-16 03:28:30 +00:00
Kit LangtonandGitHub 80f1f1b5b8 feat: enable type-aware no-floating-promises rule, fix all 177 violations (#22741)
publish-github-action / publish (push) Has been cancelled
2026-04-15 23:27:32 -04:00
Kit LangtonandGitHub 343a564183 feat: unwrap 11 util namespaces to flat exports + barrel (#22739) 2026-04-15 23:15:58 -04:00
Kit LangtonandGitHub b0eae5e12f feat: bridge permission and provider auth routes behind OPENCODE_EXPERIMENTAL_HTTPAPI (#22736) 2026-04-15 23:02:48 -04:00
Kit LangtonandGitHub 702f741267 feat: enable oxlint suspicious category, fix 24 violations (#22727)
publish-github-action / publish (push) Has been cancelled
2026-04-16 02:53:10 +00:00
Kit LangtonandGitHub 665a843086 feat: unwrap Archive namespace to flat exports + barrel (#22722) 2026-04-16 02:52:34 +00:00
Kit LangtonandGitHub 1508196c0f feat: bridge question routes from Hono to Effect HttpApi (#22718) 2026-04-15 22:50:22 -04:00
opencode-agent[bot] f6243603f8 chore: generate 2026-04-16 02:46:39 +00:00
Kit LangtonandGitHub 379e40d772 feat: unwrap InstanceState + EffectBridge namespaces to flat exports + barrel (#22721) 2026-04-16 02:45:45 +00:00
Kit LangtonandGitHub 6c7e9f6f3a refactor: migrate Effect call sites from Flock to EffectFlock (#22688) 2026-04-16 02:39:59 +00:00
opencode-agent[bot] 48f88af9aa chore: update nix node_modules hashes 2026-04-16 02:39:40 +00:00
Kit LangtonandGitHub 60c927cf4f feat: unwrap Pty namespace to flat exports + barrel (#22719) 2026-04-16 02:21:46 +00:00
opencode-agent[bot] 069cef8a44 chore: generate 2026-04-16 02:18:58 +00:00
Kit LangtonandGitHub cf423d2769 fix: remove 10 unused type-only imports and declarations (#22696) 2026-04-16 02:17:59 +00:00
Kit LangtonandGitHub 62ddb9d3ad feat: unwrap uskill namespace to flat exports + barrel (#22714) 2026-04-16 02:17:19 +00:00
Kit LangtonandGitHub 0b975b01fb feat: unwrap ugit namespace to flat exports + barrel (#22704) 2026-04-16 02:16:42 +00:00
Kit LangtonandGitHub bb90aa6cb2 feat: unwrap uworktree namespace to flat exports + barrel (#22717) 2026-04-16 02:16:17 +00:00
Kit LangtonandGitHub ce4e47a2e3 feat: unwrap uformat namespace to flat exports + barrel (#22703) 2026-04-16 02:16:01 +00:00
Kit LangtonandGitHub e3677c2ba2 feat: unwrap upatch namespace to flat exports + barrel (#22709) 2026-04-16 02:15:58 +00:00
Kit LangtonandGitHub a653a4b887 feat: unwrap usync namespace to flat exports + barrel (#22716) 2026-04-16 02:15:46 +00:00
Kit LangtonandGitHub f7edffc11a feat: unwrap uglobal namespace to flat exports + barrel (#22705) 2026-04-16 02:15:36 +00:00
Kit LangtonandGitHub dc16488bd7 feat: unwrap uide namespace to flat exports + barrel (#22706) 2026-04-16 02:15:21 +00:00
Kit LangtonandGitHub d7a072dd46 feat: unwrap usnapshot namespace to flat exports + barrel (#22715) 2026-04-16 02:15:20 +00:00
Kit LangtonandGitHub 5ae91aa810 feat: unwrap uplugin namespace to flat exports + barrel (#22711) 2026-04-16 02:15:19 +00:00
Kit LangtonandGitHub 18538e359b feat: unwrap usession namespace to flat exports + barrel (#22713) 2026-04-16 02:15:17 +00:00
Kit LangtonandGitHub 47577ae857 feat: unwrap upermission namespace to flat exports + barrel (#22710) 2026-04-16 02:14:59 +00:00
Kit LangtonandGitHub d22b5f026d feat: unwrap unpm namespace to flat exports + barrel (#22708) 2026-04-16 02:14:44 +00:00
Kit LangtonandGitHub 26cdbc20b2 feat: unwrap ufile namespace to flat exports + barrel (#22702) 2026-04-16 02:14:37 +00:00
Kit LangtonandGitHub 360d8dd940 feat: unwrap uinstallation namespace to flat exports + barrel (#22707) 2026-04-16 02:14:34 +00:00
Kit LangtonandGitHub 426815a829 feat: unwrap ucommand namespace to flat exports + barrel (#22700) 2026-04-16 02:14:18 +00:00
Kit LangtonandGitHub c6286d1bb9 feat: unwrap uenv namespace to flat exports + barrel (#22701) 2026-04-16 02:14:14 +00:00
Kit LangtonandGitHub 710c81984a feat: unwrap uauth namespace to flat exports + barrel (#22699) 2026-04-16 02:13:56 +00:00
Kit LangtonandGitHub a1dbfb5967 feat: unwrap uaccount namespace to flat exports + barrel (#22698) 2026-04-16 02:13:33 +00:00
opencode-agent[bot] 64cc4623b5 chore: generate 2026-04-16 02:08:47 +00:00
Kit LangtonandGitHub 5eae926846 add experimental provider auth HttpApi slice (#22389) 2026-04-16 02:07:42 +00:00
Kit LangtonandGitHub cce05c1665 fix: clean up 49 unused variables, catch params, and stale imports (#22695) 2026-04-16 02:01:53 +00:00
Kit LangtonandGitHub 34213d4446 fix: delete 9 dead functions with zero callers (#22697) 2026-04-16 02:01:02 +00:00
opencode-agent[bot] 70aeebf2df chore: generate 2026-04-16 01:57:23 +00:00
Kit LangtonandGitHub d6b14e2467 fix: prefix 32 unused parameters with underscore (#22694) 2026-04-15 21:56:23 -04:00
Kit LangtonandGitHub 6625766350 feat: unwrap MCP namespace to flat exports + barrel (#22693) 2026-04-16 01:56:02 +00:00
opencode-agent[bot] 7baf998752 chore: generate 2026-04-16 01:45:44 +00:00
Kit LangtonandGitHub 1d81335ab5 feat: unwrap Provider namespace + improved automation script (#22690) 2026-04-15 21:44:46 -04:00
Kit LangtonandGitHub f7d4665e40 fix: resolve oxlint warnings — suppress false positives, remove unused imports (#22687)
publish-github-action / publish (push) Has been cancelled
2026-04-15 21:33:54 -04:00
Kit LangtonandGitHub bbdbc107ae feat: unwrap Config namespace to flat exports + barrel (#22689) 2026-04-15 21:26:24 -04:00
Kit LangtonandGitHub 0fb0135e51 refactor: remove makeRuntime facades from File and Ripgrep (#22513) 2026-04-15 21:22:18 -04:00
Kit LangtonandGitHub 02f2cf439e feat: namespace → flat export migration (Bus proof-of-concept) (#22685) 2026-04-16 01:18:36 +00:00
Kit LangtonandGitHub 6d42f97644 fix: revert "core: move plugin initialisation to config layer override" (#22686) 2026-04-15 21:14:39 -04:00
Aiden ClineandGitHub 307251bf3c fix: bash memory usage (#22660) 2026-04-15 20:09:06 -05:00
James LongandGitHub 074ef032ee feat(core): add fence to make all methods strongly consistent when syncing (#22679) 2026-04-15 21:04:37 -04:00
Kit LangtonandGitHub 4ca809ef4e fix(session): retry 5xx server errors even when isRetryable is unset (#22511) 2026-04-16 00:58:48 +00:00
Kit LangtonandGitHub a147ad68e6 feat(shared): add Effect-idiomatic file lock (EffectFlock) (#22681) 2026-04-16 00:55:14 +00:00
opencode-agent[bot] ac2fa668cf chore: generate 2026-04-16 00:46:18 +00:00
Kit LangtonandGitHub 3d6f90cb53 feat: add oxlint with correctness defaults (#22682) 2026-04-15 20:45:19 -04:00
Carlo WoodandGitHub a554fad232 fix(tui): Don't overwrite the agent that was specified on the command line (#20554) 2026-04-15 18:41:35 -05:00
Kit LangtonandGitHub 4dd0d1f67e refactor(opencode): use AppFileSystem path helpers (#22637) 2026-04-15 19:36:30 -04:00
Kit LangtonandGitHub 672ee28635 fix(opencode): avoid org lookup during config startup (#22670) 2026-04-15 19:20:25 -04:00
e16589f8b5 tweak(ui): session spacing (#20839)
Co-authored-by: Adam <2363879+adamdotdevin@users.noreply.github.com>
Co-authored-by: Brendan Allan <brendonovich@outlook.com>
2026-04-15 18:58:05 -04:00
opencode-agent[bot] 83e257b468 chore: generate 2026-04-15 22:45:54 +00:00
Brendan AllanandGitHub 916131be19 core: move plugin intialisation to config layer override (#22620) 2026-04-15 22:44:55 +00:00
Ariane EmoryandGitHub d2ea6700aa fix(core): Remove dead code and documentation related to the obsolete list tool. (#22672) 2026-04-15 17:44:53 -05:00
Kit LangtonandGitHub 6bed7d469d feat(opencode): improve telemetry tracing and request spans (#22653) 2026-04-15 17:32:56 -04:00
opencode-agent[bot] 3b75f16119 chore: generate 2026-04-15 21:29:10 +00:00
Kit LangtonandGitHub 250e30bc7d add experimental permission HttpApi slice (#22385) 2026-04-15 21:28:01 +00:00
Aiden ClineGitHubopencode-agent[bot] <opencode-agent[bot]@users.noreply.github.com>
e83b22159d tweak: ensure auto continuing compaction is tracked as agent initiated for github copilot (#22567)
Co-authored-by: opencode-agent[bot] <opencode-agent[bot]@users.noreply.github.com>
2026-04-15 15:50:33 -05:00
Aiden ClineGitHubopencode-agent[bot] <opencode-agent[bot]@users.noreply.github.com>
348a84969d fix: ensure tool_use is always followed by tool_result (#22646)
Co-authored-by: opencode-agent[bot] <opencode-agent[bot]@users.noreply.github.com>
2026-04-15 14:56:45 -05:00
opencode-agent[bot] 8ba4799b3e chore: update nix node_modules hashes 2026-04-15 17:38:21 +00:00
Kit LangtonandGitHub 9640d889ba fix: register OTel context manager so AI SDK spans thread into Effect traces (#22645) 2026-04-15 16:35:14 +00:00
DaxandGitHub 4ae7c77f8a migrate: move flock and hash utilities to shared package (#22640) 2026-04-15 15:50:24 +00:00
Aiden Cline 9819eb0461 tweak: disable 2026-04-09 23:11:09 -05:00
Shoubhit Dash aa86fb75ad refactor compaction tail selection 2026-04-10 09:36:39 +05:30
Shoubhit Dash 6f5a3d30fd keep recent turns during session compaction 2026-04-10 09:34:01 +05:30
1031 changed files with 77292 additions and 43395 deletions
+1
View File
@@ -13,3 +13,4 @@ R44VC0RP
rekram1-node rekram1-node
RhysSullivan RhysSullivan
thdxr thdxr
simonklee
+2
View File
@@ -27,8 +27,10 @@ r44vc0rp
rekram1-node rekram1-node
-ricardo-m-l -ricardo-m-l
-robinmordasiewicz -robinmordasiewicz
rubdos
shantur shantur
simonklee simonklee
-spider-yamet clawdbot/llm psychosis, spam pinging the team -spider-yamet clawdbot/llm psychosis, spam pinging the team
thdxr thdxr
-toastythebot -toastythebot
-davidbernat looks to be a clawdbot that spams team and sends super weird emails, doesnt appear to be a real person
+7 -2
View File
@@ -1,5 +1,10 @@
name: "Setup Bun" name: "Setup Bun"
description: "Setup Bun with caching and install dependencies" description: "Setup Bun with caching and install dependencies"
inputs:
install-flags:
description: "Additional flags to pass to 'bun install'"
required: false
default: ""
runs: runs:
using: "composite" using: "composite"
steps: steps:
@@ -46,8 +51,8 @@ runs:
# e.g. ./patches/ for standard-openapi # e.g. ./patches/ for standard-openapi
# https://github.com/oven-sh/bun/issues/28147 # https://github.com/oven-sh/bun/issues/28147
if [ "$RUNNER_OS" = "Windows" ]; then if [ "$RUNNER_OS" = "Windows" ]; then
bun install --linker hoisted bun install --linker hoisted ${{ inputs.install-flags }}
else else
bun install bun install ${{ inputs.install-flags }}
fi fi
shell: bash shell: bash
+6 -2
View File
@@ -402,12 +402,14 @@ jobs:
fail-fast: false fail-fast: false
matrix: matrix:
settings: settings:
- host: macos-latest - host: macos-26-intel
target: x86_64-apple-darwin target: x86_64-apple-darwin
platform_flag: --mac --x64 platform_flag: --mac --x64
- host: macos-latest bun_install_flags: --os=darwin --cpu=x64
- host: macos-26
target: aarch64-apple-darwin target: aarch64-apple-darwin
platform_flag: --mac --arm64 platform_flag: --mac --arm64
bun_install_flags: --os=darwin --cpu=arm64
# github-hosted: blacksmith lacks ARM64 MSVC cross-compilation toolchain # github-hosted: blacksmith lacks ARM64 MSVC cross-compilation toolchain
- host: "windows-2025" - host: "windows-2025"
target: aarch64-pc-windows-msvc target: aarch64-pc-windows-msvc
@@ -437,6 +439,8 @@ jobs:
run: echo "${{ secrets.APPLE_API_KEY_PATH }}" > $RUNNER_TEMP/apple-api-key.p8 run: echo "${{ secrets.APPLE_API_KEY_PATH }}" > $RUNNER_TEMP/apple-api-key.p8
- uses: ./.github/actions/setup-bun - uses: ./.github/actions/setup-bun
with:
install-flags: ${{ matrix.settings.bun_install_flags }}
- name: Azure login - name: Azure login
if: runner.os == 'Windows' if: runner.os == 'Windows'
+2 -2
View File
@@ -45,13 +45,13 @@ jobs:
- name: Check PR guidelines compliance - name: Check PR guidelines compliance
env: env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
OPENCODE_PERMISSION: '{ "bash": { "*": "deny", "gh*": "allow", "gh pr review*": "deny" } }' OPENCODE_PERMISSION: '{ "bash": { "*": "deny", "gh*": "allow", "gh pr review*": "deny" } }'
PR_TITLE: ${{ steps.pr-details.outputs.title }} PR_TITLE: ${{ steps.pr-details.outputs.title }}
run: | run: |
PR_BODY=$(jq -r .body pr_data.json) PR_BODY=$(jq -r .body pr_data.json)
opencode run -m anthropic/claude-opus-4-5 "A new pull request has been created: '${PR_TITLE}' opencode run -m opencode/gpt-5.5 --variant medium "A new pull request has been created: '${PR_TITLE}'
<pr-number> <pr-number>
${{ steps.pr-number.outputs.number }} ${{ steps.pr-number.outputs.number }}
-1
View File
@@ -594,7 +594,6 @@ OPENCODE_DISABLE_CLAUDE_CODE
OPENCODE_DISABLE_CLAUDE_CODE_PROMPT OPENCODE_DISABLE_CLAUDE_CODE_PROMPT
OPENCODE_DISABLE_CLAUDE_CODE_SKILLS OPENCODE_DISABLE_CLAUDE_CODE_SKILLS
OPENCODE_DISABLE_DEFAULT_PLUGINS OPENCODE_DISABLE_DEFAULT_PLUGINS
OPENCODE_DISABLE_FILETIME_CHECK
OPENCODE_DISABLE_LSP_DOWNLOAD OPENCODE_DISABLE_LSP_DOWNLOAD
OPENCODE_DISABLE_MODELS_FETCH OPENCODE_DISABLE_MODELS_FETCH
OPENCODE_DISABLE_PRUNE OPENCODE_DISABLE_PRUNE
+1 -5
View File
@@ -1,10 +1,6 @@
{ {
"$schema": "https://opencode.ai/config.json", "$schema": "https://opencode.ai/config.json",
"provider": { "provider": {},
"opencode": {
"options": {},
},
},
"permission": { "permission": {
"edit": { "edit": {
"packages/opencode/migration/*": "deny", "packages/opencode/migration/*": "deny",
@@ -1,25 +0,0 @@
import type { TuiPluginModule } from "@opencode-ai/plugin/tui"
let seen = false
const plugin: TuiPluginModule & { id: string } = {
id: "local.config-once-toast",
async tui(api) {
if (seen) return
const cfg = api.state.config
if (cfg.plugin !== undefined && !Array.isArray(cfg.plugin)) {
throw new Error("Invalid config: plugin must be an array")
}
const mdl = typeof cfg.model === "string" && cfg.model.trim() ? cfg.model : "default"
seen = true
api.ui.toast({
title: "Config check",
message: `This is a 1 time toast, validating ur config (model: ${mdl})`,
variant: "info",
})
},
}
export default plugin
+19 -10
View File
@@ -1,21 +1,30 @@
--- ---
name: effect name: effect
description: Answer questions about the Effect framework description: Work with Effect v4 / effect-smol TypeScript code in this repo
--- ---
# Effect # Effect
This codebase uses Effect, a framework for writing typescript. This codebase uses Effect for typed, composable TypeScript services, schemas, and workflows.
## How to Answer Effect Questions ## Source Of Truth
1. Clone the Effect repository: `https://github.com/Effect-TS/effect-smol` to Use the current Effect v4 / effect-smol source, not memory or older Effect v2/v3 examples.
`.opencode/references/effect-smol` in this project NOT the skill folder.
2. Use the explore agent to search the codebase for answers about Effect patterns, APIs, and concepts 1. If `.opencode/references/effect-smol` is missing, clone `https://github.com/Effect-TS/effect-smol` there. Do this in the project, not in the skill folder.
3. Provide responses based on the actual Effect source code and documentation 2. Search `.opencode/references/effect-smol` for exact APIs, examples, tests, and naming patterns before answering or implementing Effect-specific code.
3. Also inspect existing repo code for local house style before introducing new patterns.
4. Prefer answers and implementations backed by specific source files or nearby repo examples.
## Guidelines ## Guidelines
- Always use the explore agent with the cloned repository when answering Effect-related questions - Prefer current Effect v4 APIs and project-local patterns over old blog posts, examples, or package-memory guesses.
- Reference specific files and patterns found in the Effect codebase - Use `Effect.gen(function* () { ... })` for multi-step workflows.
- Do not answer from memory - always verify against the source - Use `Effect.fn("Name")` or `Effect.fnUntraced(...)` for named effects when adding reusable service methods or important workflows.
- Prefer Effect `Schema` for API and domain data shapes. Use branded schemas for IDs and `Schema.TaggedErrorClass` for typed domain errors when modeling new error surfaces.
- Keep HTTP handlers thin: decode input, read request context, call services, and map transport errors. Put business rules in services.
- In Effect service code, prefer Effect-aware platform abstractions and dependencies over ad hoc promises where the surrounding code already does so.
- Keep layer composition explicit. Avoid broad hidden provisioning that makes missing dependencies hard to see.
- In tests, prefer the repo's existing Effect test helpers and live tests for filesystem, git, child process, locks, or timing behavior.
- Do not introduce `any`, non-null assertions, unchecked casts, or older Effect APIs just to satisfy types.
- Do not answer from memory. Verify against `.opencode/references/effect-smol` or nearby code first.
+1 -1
View File
@@ -7,7 +7,7 @@ async function githubFetch(endpoint: string, options: RequestInit = {}) {
Authorization: `Bearer ${process.env.GITHUB_TOKEN}`, Authorization: `Bearer ${process.env.GITHUB_TOKEN}`,
Accept: "application/vnd.github+json", Accept: "application/vnd.github+json",
"Content-Type": "application/json", "Content-Type": "application/json",
...options.headers, ...(options.headers instanceof Headers ? Object.fromEntries(options.headers.entries()) : options.headers),
}, },
}) })
if (!response.ok) { if (!response.ok) {
+1 -1
View File
@@ -28,7 +28,7 @@ async function githubFetch(endpoint: string, options: RequestInit = {}) {
Authorization: `Bearer ${process.env.GITHUB_TOKEN}`, Authorization: `Bearer ${process.env.GITHUB_TOKEN}`,
Accept: "application/vnd.github+json", Accept: "application/vnd.github+json",
"Content-Type": "application/json", "Content-Type": "application/json",
...options.headers, ...(options.headers instanceof Headers ? Object.fromEntries(options.headers.entries()) : options.headers),
}, },
}) })
if (!response.ok) { if (!response.ok) {
-1
View File
@@ -1,7 +1,6 @@
{ {
"$schema": "https://opencode.ai/tui.json", "$schema": "https://opencode.ai/tui.json",
"plugin": [ "plugin": [
"./plugins/tui-config-once-toast.tsx",
[ [
"./plugins/tui-smoke.tsx", "./plugins/tui-smoke.tsx",
{ {
+51
View File
@@ -0,0 +1,51 @@
{
"$schema": "https://raw.githubusercontent.com/nicolo-ribaudo/oxc-project.github.io/refs/heads/json-schema/src/public/.oxlintrc.schema.json",
"options": {
"typeAware": true
},
"categories": {
"suspicious": "warn"
},
"rules": {
"typescript/no-base-to-string": "warn",
// Effect uses `function*` with Effect.gen/Effect.fnUntraced that don't always yield
"require-yield": "off",
// SolidJS uses `let ref: T | undefined` for JSX ref bindings assigned at runtime
"no-unassigned-vars": "off",
// SolidJS tracks reactive deps by reading properties inside createEffect
"no-unused-expressions": "off",
// Intentional control char matching (ANSI escapes, null byte sanitization)
"no-control-regex": "off",
// SST and plugin tools require triple-slash references
"triple-slash-reference": "off",
// Suspicious category: suppress noisy rules
// Effect's nested function* closures inherently shadow outer scope
"no-shadow": "off",
// Namespace-heavy codebase makes this too noisy
"unicorn/consistent-function-scoping": "off",
// Opinionated — .sort()/.reverse() mutation is fine in this codebase
"unicorn/no-array-sort": "off",
"unicorn/no-array-reverse": "off",
// Not relevant — this isn't a DOM event handler codebase
"unicorn/prefer-add-event-listener": "off",
// Bundler handles module resolution
"unicorn/require-module-specifiers": "off",
// postMessage target origin not relevant for this codebase
"unicorn/require-post-message-target-origin": "off",
// Side-effectful constructors are intentional in some places
"no-new": "off",
// Type-aware: catch unhandled promises
"typescript/no-floating-promises": "warn",
// Warn when spreading non-plain objects (Headers, class instances, etc.)
"typescript/no-misused-spread": "warn"
},
"options": {
"typeAware": true
},
"options": {
"typeAware": true
},
"ignorePatterns": ["**/node_modules", "**/dist", "**/.build", "**/.sst", "**/*.d.ts", "**/sdk.gen.ts"]
}
+1 -26
View File
@@ -11,35 +11,10 @@
- Keep things in one function unless composable or reusable - Keep things in one function unless composable or reusable
- Avoid `try`/`catch` where possible - Avoid `try`/`catch` where possible
- Avoid using the `any` type - Avoid using the `any` type
- Prefer single word variable names where possible
- Use Bun APIs when possible, like `Bun.file()` - Use Bun APIs when possible, like `Bun.file()`
- Rely on type inference when possible; avoid explicit type annotations or interfaces unless necessary for exports or clarity - Rely on type inference when possible; avoid explicit type annotations or interfaces unless necessary for exports or clarity
- Prefer functional array methods (flatMap, filter, map) over for loops; use type guards on filter to maintain type inference downstream - Prefer functional array methods (flatMap, filter, map) over for loops; use type guards on filter to maintain type inference downstream
- In `src/config`, follow the existing self-export pattern at the top of the file (for example `export * as ConfigAgent from "./agent"`) when adding a new config module.
### Naming
Prefer single word names for variables and functions. Only use multiple words if necessary.
### Naming Enforcement (Read This)
THIS RULE IS MANDATORY FOR AGENT WRITTEN CODE.
- Use single word names by default for new locals, params, and helper functions.
- Multi-word names are allowed only when a single word would be unclear or ambiguous.
- Do not introduce new camelCase compounds when a short single-word alternative is clear.
- Before finishing edits, review touched lines and shorten newly introduced identifiers where possible.
- Good short names to prefer: `pid`, `cfg`, `err`, `opts`, `dir`, `root`, `child`, `state`, `timeout`.
- Examples to avoid unless truly required: `inputPID`, `existingClient`, `connectTimeout`, `workerPath`.
```ts
// Good
const foo = 1
function journal(dir: string) {}
// Bad
const fooBar = 1
function prepareJournal(dir: string) {}
```
Reduce total variable count by inlining when a value is only used once. Reduce total variable count by inlining when a value is only used once.
+177 -97
View File
@@ -19,6 +19,8 @@
"@typescript/native-preview": "catalog:", "@typescript/native-preview": "catalog:",
"glob": "13.0.5", "glob": "13.0.5",
"husky": "9.1.7", "husky": "9.1.7",
"oxlint": "1.60.0",
"oxlint-tsgolint": "0.21.0",
"prettier": "3.6.2", "prettier": "3.6.2",
"semver": "^7.6.0", "semver": "^7.6.0",
"sst": "3.18.10", "sst": "3.18.10",
@@ -27,11 +29,11 @@
}, },
"packages/app": { "packages/app": {
"name": "@opencode-ai/app", "name": "@opencode-ai/app",
"version": "1.4.6", "version": "1.14.25",
"dependencies": { "dependencies": {
"@kobalte/core": "catalog:", "@kobalte/core": "catalog:",
"@opencode-ai/core": "workspace:*",
"@opencode-ai/sdk": "workspace:*", "@opencode-ai/sdk": "workspace:*",
"@opencode-ai/shared": "workspace:*",
"@opencode-ai/ui": "workspace:*", "@opencode-ai/ui": "workspace:*",
"@shikijs/transformers": "3.9.2", "@shikijs/transformers": "3.9.2",
"@solid-primitives/active-element": "2.1.3", "@solid-primitives/active-element": "2.1.3",
@@ -81,7 +83,7 @@
}, },
"packages/console/app": { "packages/console/app": {
"name": "@opencode-ai/console-app", "name": "@opencode-ai/console-app",
"version": "1.4.6", "version": "1.14.25",
"dependencies": { "dependencies": {
"@cloudflare/vite-plugin": "1.15.2", "@cloudflare/vite-plugin": "1.15.2",
"@ibm/plex": "6.4.1", "@ibm/plex": "6.4.1",
@@ -115,7 +117,7 @@
}, },
"packages/console/core": { "packages/console/core": {
"name": "@opencode-ai/console-core", "name": "@opencode-ai/console-core",
"version": "1.4.6", "version": "1.14.25",
"dependencies": { "dependencies": {
"@aws-sdk/client-sts": "3.782.0", "@aws-sdk/client-sts": "3.782.0",
"@jsx-email/render": "1.1.1", "@jsx-email/render": "1.1.1",
@@ -142,7 +144,7 @@
}, },
"packages/console/function": { "packages/console/function": {
"name": "@opencode-ai/console-function", "name": "@opencode-ai/console-function",
"version": "1.4.6", "version": "1.14.25",
"dependencies": { "dependencies": {
"@ai-sdk/anthropic": "3.0.64", "@ai-sdk/anthropic": "3.0.64",
"@ai-sdk/openai": "3.0.48", "@ai-sdk/openai": "3.0.48",
@@ -166,7 +168,7 @@
}, },
"packages/console/mail": { "packages/console/mail": {
"name": "@opencode-ai/console-mail", "name": "@opencode-ai/console-mail",
"version": "1.4.6", "version": "1.14.25",
"dependencies": { "dependencies": {
"@jsx-email/all": "2.2.3", "@jsx-email/all": "2.2.3",
"@jsx-email/cli": "1.4.3", "@jsx-email/cli": "1.4.3",
@@ -188,9 +190,43 @@
"cloudflare": "5.2.0", "cloudflare": "5.2.0",
}, },
}, },
"packages/core": {
"name": "@opencode-ai/core",
"version": "1.14.25",
"bin": {
"opencode": "./bin/opencode",
},
"dependencies": {
"@effect/opentelemetry": "catalog:",
"@effect/platform-node": "catalog:",
"@npmcli/arborist": "9.4.0",
"@npmcli/config": "10.8.1",
"@opentelemetry/api": "1.9.0",
"@opentelemetry/context-async-hooks": "2.6.1",
"@opentelemetry/exporter-trace-otlp-http": "0.214.0",
"@opentelemetry/sdk-trace-base": "2.6.1",
"cross-spawn": "catalog:",
"effect": "catalog:",
"glob": "13.0.5",
"mime-types": "3.0.2",
"minimatch": "10.2.5",
"npm-package-arg": "13.0.2",
"semver": "^7.6.3",
"xdg-basedir": "5.1.0",
"zod": "catalog:",
},
"devDependencies": {
"@tsconfig/bun": "catalog:",
"@types/bun": "catalog:",
"@types/cross-spawn": "catalog:",
"@types/npm-package-arg": "6.1.4",
"@types/npmcli__arborist": "6.3.3",
"@types/semver": "catalog:",
},
},
"packages/desktop": { "packages/desktop": {
"name": "@opencode-ai/desktop", "name": "@opencode-ai/desktop",
"version": "1.4.6", "version": "1.14.25",
"dependencies": { "dependencies": {
"@opencode-ai/app": "workspace:*", "@opencode-ai/app": "workspace:*",
"@opencode-ai/ui": "workspace:*", "@opencode-ai/ui": "workspace:*",
@@ -223,8 +259,9 @@
}, },
"packages/desktop-electron": { "packages/desktop-electron": {
"name": "@opencode-ai/desktop-electron", "name": "@opencode-ai/desktop-electron",
"version": "1.4.6", "version": "1.14.25",
"dependencies": { "dependencies": {
"drizzle-orm": "catalog:",
"effect": "catalog:", "effect": "catalog:",
"electron-context-menu": "4.1.2", "electron-context-menu": "4.1.2",
"electron-log": "^5", "electron-log": "^5",
@@ -246,7 +283,7 @@
"@types/node": "catalog:", "@types/node": "catalog:",
"@typescript/native-preview": "catalog:", "@typescript/native-preview": "catalog:",
"@valibot/to-json-schema": "1.6.0", "@valibot/to-json-schema": "1.6.0",
"electron": "40.4.1", "electron": "41.2.1",
"electron-builder": "^26", "electron-builder": "^26",
"electron-vite": "^5", "electron-vite": "^5",
"solid-js": "catalog:", "solid-js": "catalog:",
@@ -266,9 +303,9 @@
}, },
"packages/enterprise": { "packages/enterprise": {
"name": "@opencode-ai/enterprise", "name": "@opencode-ai/enterprise",
"version": "1.4.6", "version": "1.14.25",
"dependencies": { "dependencies": {
"@opencode-ai/shared": "workspace:*", "@opencode-ai/core": "workspace:*",
"@opencode-ai/ui": "workspace:*", "@opencode-ai/ui": "workspace:*",
"@pierre/diffs": "catalog:", "@pierre/diffs": "catalog:",
"@solidjs/meta": "catalog:", "@solidjs/meta": "catalog:",
@@ -295,7 +332,7 @@
}, },
"packages/function": { "packages/function": {
"name": "@opencode-ai/function", "name": "@opencode-ai/function",
"version": "1.4.6", "version": "1.14.25",
"dependencies": { "dependencies": {
"@octokit/auth-app": "8.0.1", "@octokit/auth-app": "8.0.1",
"@octokit/rest": "catalog:", "@octokit/rest": "catalog:",
@@ -311,7 +348,7 @@
}, },
"packages/opencode": { "packages/opencode": {
"name": "opencode", "name": "opencode",
"version": "1.4.6", "version": "1.14.25",
"bin": { "bin": {
"opencode": "./bin/opencode", "opencode": "./bin/opencode",
}, },
@@ -320,15 +357,15 @@
"@actions/github": "6.0.1", "@actions/github": "6.0.1",
"@agentclientprotocol/sdk": "0.16.1", "@agentclientprotocol/sdk": "0.16.1",
"@ai-sdk/alibaba": "1.0.17", "@ai-sdk/alibaba": "1.0.17",
"@ai-sdk/amazon-bedrock": "4.0.93", "@ai-sdk/amazon-bedrock": "4.0.96",
"@ai-sdk/anthropic": "3.0.67", "@ai-sdk/anthropic": "3.0.71",
"@ai-sdk/azure": "3.0.49", "@ai-sdk/azure": "3.0.49",
"@ai-sdk/cerebras": "2.0.41", "@ai-sdk/cerebras": "2.0.41",
"@ai-sdk/cohere": "3.0.27", "@ai-sdk/cohere": "3.0.27",
"@ai-sdk/deepinfra": "2.0.41", "@ai-sdk/deepinfra": "2.0.41",
"@ai-sdk/gateway": "3.0.97", "@ai-sdk/gateway": "3.0.104",
"@ai-sdk/google": "3.0.63", "@ai-sdk/google": "3.0.63",
"@ai-sdk/google-vertex": "4.0.109", "@ai-sdk/google-vertex": "4.0.112",
"@ai-sdk/groq": "3.0.31", "@ai-sdk/groq": "3.0.31",
"@ai-sdk/mistral": "3.0.27", "@ai-sdk/mistral": "3.0.27",
"@ai-sdk/openai": "3.0.53", "@ai-sdk/openai": "3.0.53",
@@ -350,20 +387,20 @@
"@hono/zod-validator": "catalog:", "@hono/zod-validator": "catalog:",
"@lydell/node-pty": "catalog:", "@lydell/node-pty": "catalog:",
"@modelcontextprotocol/sdk": "1.27.1", "@modelcontextprotocol/sdk": "1.27.1",
"@npmcli/arborist": "9.4.0",
"@octokit/graphql": "9.0.2", "@octokit/graphql": "9.0.2",
"@octokit/rest": "catalog:", "@octokit/rest": "catalog:",
"@openauthjs/openauth": "catalog:", "@openauthjs/openauth": "catalog:",
"@opencode-ai/plugin": "workspace:*", "@opencode-ai/plugin": "workspace:*",
"@opencode-ai/script": "workspace:*", "@opencode-ai/script": "workspace:*",
"@opencode-ai/sdk": "workspace:*", "@opencode-ai/sdk": "workspace:*",
"@opencode-ai/server": "workspace:*",
"@openrouter/ai-sdk-provider": "2.5.1", "@openrouter/ai-sdk-provider": "2.5.1",
"@opentelemetry/api": "1.9.0",
"@opentelemetry/context-async-hooks": "2.6.1",
"@opentelemetry/exporter-trace-otlp-http": "0.214.0", "@opentelemetry/exporter-trace-otlp-http": "0.214.0",
"@opentelemetry/sdk-trace-base": "2.6.1", "@opentelemetry/sdk-trace-base": "2.6.1",
"@opentelemetry/sdk-trace-node": "2.6.1", "@opentelemetry/sdk-trace-node": "2.6.1",
"@opentui/core": "0.1.99", "@opentui/core": "catalog:",
"@opentui/solid": "0.1.99", "@opentui/solid": "catalog:",
"@parcel/watcher": "2.5.1", "@parcel/watcher": "2.5.1",
"@pierre/diffs": "catalog:", "@pierre/diffs": "catalog:",
"@solid-primitives/event-bus": "1.1.2", "@solid-primitives/event-bus": "1.1.2",
@@ -383,7 +420,7 @@
"drizzle-orm": "catalog:", "drizzle-orm": "catalog:",
"effect": "catalog:", "effect": "catalog:",
"fuzzysort": "3.1.0", "fuzzysort": "3.1.0",
"gitlab-ai-provider": "6.4.2", "gitlab-ai-provider": "6.6.0",
"glob": "13.0.5", "glob": "13.0.5",
"google-auth-library": "10.5.0", "google-auth-library": "10.5.0",
"gray-matter": "4.0.3", "gray-matter": "4.0.3",
@@ -398,10 +435,9 @@
"open": "10.1.2", "open": "10.1.2",
"opencode-gitlab-auth": "2.0.1", "opencode-gitlab-auth": "2.0.1",
"opencode-poe-auth": "0.0.1", "opencode-poe-auth": "0.0.1",
"opentui-spinner": "0.0.6", "opentui-spinner": "catalog:",
"partial-json": "0.1.7", "partial-json": "0.1.7",
"remeda": "catalog:", "remeda": "catalog:",
"ripgrep": "0.3.1",
"semver": "^7.6.3", "semver": "^7.6.3",
"solid-js": "catalog:", "solid-js": "catalog:",
"strip-ansi": "7.1.2", "strip-ansi": "7.1.2",
@@ -422,8 +458,8 @@
"@babel/core": "7.28.4", "@babel/core": "7.28.4",
"@effect/language-service": "0.84.2", "@effect/language-service": "0.84.2",
"@octokit/webhooks-types": "7.6.1", "@octokit/webhooks-types": "7.6.1",
"@opencode-ai/core": "workspace:*",
"@opencode-ai/script": "workspace:*", "@opencode-ai/script": "workspace:*",
"@opencode-ai/shared": "workspace:*",
"@parcel/watcher-darwin-arm64": "2.5.1", "@parcel/watcher-darwin-arm64": "2.5.1",
"@parcel/watcher-darwin-x64": "2.5.1", "@parcel/watcher-darwin-x64": "2.5.1",
"@parcel/watcher-linux-arm64-glibc": "2.5.1", "@parcel/watcher-linux-arm64-glibc": "2.5.1",
@@ -439,7 +475,6 @@
"@types/cross-spawn": "catalog:", "@types/cross-spawn": "catalog:",
"@types/mime-types": "3.0.1", "@types/mime-types": "3.0.1",
"@types/npm-package-arg": "6.1.4", "@types/npm-package-arg": "6.1.4",
"@types/npmcli__arborist": "6.3.3",
"@types/semver": "^7.5.8", "@types/semver": "^7.5.8",
"@types/turndown": "5.0.5", "@types/turndown": "5.0.5",
"@types/which": "3.0.4", "@types/which": "3.0.4",
@@ -447,6 +482,7 @@
"@typescript/native-preview": "catalog:", "@typescript/native-preview": "catalog:",
"drizzle-kit": "catalog:", "drizzle-kit": "catalog:",
"drizzle-orm": "catalog:", "drizzle-orm": "catalog:",
"prettier": "3.6.2",
"typescript": "catalog:", "typescript": "catalog:",
"vscode-languageserver-types": "3.17.5", "vscode-languageserver-types": "3.17.5",
"why-is-node-running": "3.2.2", "why-is-node-running": "3.2.2",
@@ -455,23 +491,23 @@
}, },
"packages/plugin": { "packages/plugin": {
"name": "@opencode-ai/plugin", "name": "@opencode-ai/plugin",
"version": "1.4.6", "version": "1.14.25",
"dependencies": { "dependencies": {
"@opencode-ai/sdk": "workspace:*", "@opencode-ai/sdk": "workspace:*",
"effect": "catalog:", "effect": "catalog:",
"zod": "catalog:", "zod": "catalog:",
}, },
"devDependencies": { "devDependencies": {
"@opentui/core": "0.1.99", "@opentui/core": "catalog:",
"@opentui/solid": "0.1.99", "@opentui/solid": "catalog:",
"@tsconfig/node22": "catalog:", "@tsconfig/node22": "catalog:",
"@types/node": "catalog:", "@types/node": "catalog:",
"@typescript/native-preview": "catalog:", "@typescript/native-preview": "catalog:",
"typescript": "catalog:", "typescript": "catalog:",
}, },
"peerDependencies": { "peerDependencies": {
"@opentui/core": ">=0.1.99", "@opentui/core": ">=0.1.103",
"@opentui/solid": ">=0.1.99", "@opentui/solid": ">=0.1.103",
}, },
"optionalPeers": [ "optionalPeers": [
"@opentui/core", "@opentui/core",
@@ -490,7 +526,7 @@
}, },
"packages/sdk/js": { "packages/sdk/js": {
"name": "@opencode-ai/sdk", "name": "@opencode-ai/sdk",
"version": "1.4.6", "version": "1.14.25",
"dependencies": { "dependencies": {
"cross-spawn": "catalog:", "cross-spawn": "catalog:",
}, },
@@ -503,39 +539,9 @@
"typescript": "catalog:", "typescript": "catalog:",
}, },
}, },
"packages/server": {
"name": "@opencode-ai/server",
"version": "1.4.6",
"dependencies": {
"effect": "catalog:",
},
"devDependencies": {
"@typescript/native-preview": "catalog:",
"typescript": "catalog:",
},
},
"packages/shared": {
"name": "@opencode-ai/shared",
"version": "1.4.6",
"bin": {
"opencode": "./bin/opencode",
},
"dependencies": {
"@effect/platform-node": "catalog:",
"@npmcli/arborist": "catalog:",
"effect": "catalog:",
"mime-types": "3.0.2",
"minimatch": "10.2.5",
"semver": "catalog:",
"zod": "catalog:",
},
"devDependencies": {
"@types/semver": "catalog:",
},
},
"packages/slack": { "packages/slack": {
"name": "@opencode-ai/slack", "name": "@opencode-ai/slack",
"version": "1.4.6", "version": "1.14.25",
"dependencies": { "dependencies": {
"@opencode-ai/sdk": "workspace:*", "@opencode-ai/sdk": "workspace:*",
"@slack/bolt": "^3.17.1", "@slack/bolt": "^3.17.1",
@@ -570,11 +576,11 @@
}, },
"packages/ui": { "packages/ui": {
"name": "@opencode-ai/ui", "name": "@opencode-ai/ui",
"version": "1.4.6", "version": "1.14.25",
"dependencies": { "dependencies": {
"@kobalte/core": "catalog:", "@kobalte/core": "catalog:",
"@opencode-ai/core": "workspace:*",
"@opencode-ai/sdk": "workspace:*", "@opencode-ai/sdk": "workspace:*",
"@opencode-ai/shared": "workspace:*",
"@pierre/diffs": "catalog:", "@pierre/diffs": "catalog:",
"@shikijs/transformers": "3.9.2", "@shikijs/transformers": "3.9.2",
"@solid-primitives/bounds": "0.1.3", "@solid-primitives/bounds": "0.1.3",
@@ -619,7 +625,7 @@
}, },
"packages/web": { "packages/web": {
"name": "@opencode-ai/web", "name": "@opencode-ai/web",
"version": "1.4.6", "version": "1.14.25",
"dependencies": { "dependencies": {
"@astrojs/cloudflare": "12.6.3", "@astrojs/cloudflare": "12.6.3",
"@astrojs/markdown-remark": "6.3.1", "@astrojs/markdown-remark": "6.3.1",
@@ -663,6 +669,7 @@
"patchedDependencies": { "patchedDependencies": {
"solid-js@1.9.10": "patches/solid-js@1.9.10.patch", "solid-js@1.9.10": "patches/solid-js@1.9.10.patch",
"@standard-community/standard-openapi@0.2.9": "patches/@standard-community%2Fstandard-openapi@0.2.9.patch", "@standard-community/standard-openapi@0.2.9": "patches/@standard-community%2Fstandard-openapi@0.2.9.patch",
"@npmcli/agent@4.0.0": "patches/@npmcli%2Fagent@4.0.0.patch",
}, },
"overrides": { "overrides": {
"@types/bun": "catalog:", "@types/bun": "catalog:",
@@ -678,6 +685,8 @@
"@npmcli/arborist": "9.4.0", "@npmcli/arborist": "9.4.0",
"@octokit/rest": "22.0.0", "@octokit/rest": "22.0.0",
"@openauthjs/openauth": "0.0.0-20250322224806", "@openauthjs/openauth": "0.0.0-20250322224806",
"@opentui/core": "0.1.103",
"@opentui/solid": "0.1.103",
"@pierre/diffs": "1.1.0-beta.18", "@pierre/diffs": "1.1.0-beta.18",
"@playwright/test": "1.59.1", "@playwright/test": "1.59.1",
"@solid-primitives/storage": "4.3.3", "@solid-primitives/storage": "4.3.3",
@@ -687,13 +696,13 @@
"@tailwindcss/vite": "4.1.11", "@tailwindcss/vite": "4.1.11",
"@tsconfig/bun": "1.0.9", "@tsconfig/bun": "1.0.9",
"@tsconfig/node22": "22.0.2", "@tsconfig/node22": "22.0.2",
"@types/bun": "1.3.11", "@types/bun": "1.3.12",
"@types/cross-spawn": "6.0.6", "@types/cross-spawn": "6.0.6",
"@types/luxon": "3.7.1", "@types/luxon": "3.7.1",
"@types/node": "22.13.9", "@types/node": "22.13.9",
"@types/semver": "7.7.1", "@types/semver": "7.7.1",
"@typescript/native-preview": "7.0.0-dev.20251207.1", "@typescript/native-preview": "7.0.0-dev.20251207.1",
"ai": "6.0.158", "ai": "6.0.168",
"cross-spawn": "7.0.6", "cross-spawn": "7.0.6",
"diff": "8.0.2", "diff": "8.0.2",
"dompurify": "3.3.1", "dompurify": "3.3.1",
@@ -706,6 +715,7 @@
"luxon": "3.6.1", "luxon": "3.6.1",
"marked": "17.0.1", "marked": "17.0.1",
"marked-shiki": "1.2.1", "marked-shiki": "1.2.1",
"opentui-spinner": "0.0.6",
"remeda": "2.26.0", "remeda": "2.26.0",
"remend": "1.3.0", "remend": "1.3.0",
"semver": "7.7.4", "semver": "7.7.4",
@@ -741,7 +751,7 @@
"@ai-sdk/alibaba": ["@ai-sdk/alibaba@1.0.17", "", { "dependencies": { "@ai-sdk/openai-compatible": "2.0.41", "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-ZbE+U5bWz2JBc5DERLowx5+TKbjGBE93LqKZAWvuEn7HOSQMraxFMZuc0ST335QZJAyfBOzh7m1mPQ+y7EaaoA=="], "@ai-sdk/alibaba": ["@ai-sdk/alibaba@1.0.17", "", { "dependencies": { "@ai-sdk/openai-compatible": "2.0.41", "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-ZbE+U5bWz2JBc5DERLowx5+TKbjGBE93LqKZAWvuEn7HOSQMraxFMZuc0ST335QZJAyfBOzh7m1mPQ+y7EaaoA=="],
"@ai-sdk/amazon-bedrock": ["@ai-sdk/amazon-bedrock@4.0.93", "", { "dependencies": { "@ai-sdk/anthropic": "3.0.69", "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23", "@smithy/eventstream-codec": "^4.0.1", "@smithy/util-utf8": "^4.0.0", "aws4fetch": "^1.0.20" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-hcXDU8QDwpAzLVTuY932TQVlIij9+iaVTxc5mPGY6yb//JMAAC5hMVhg93IrxlrxWLvMgjezNgoZGwquR+SGnw=="], "@ai-sdk/amazon-bedrock": ["@ai-sdk/amazon-bedrock@4.0.96", "", { "dependencies": { "@ai-sdk/anthropic": "3.0.71", "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23", "@smithy/eventstream-codec": "^4.0.1", "@smithy/util-utf8": "^4.0.0", "aws4fetch": "^1.0.20" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-Mc4Ias2jRMD1jOB6xWtKNPdhECeuCZyIlbr9EAGfBnyBt++sS13ziZh9qv9TdyMCAZJ7xoQcpbchoRJcKwPdpA=="],
"@ai-sdk/anthropic": ["@ai-sdk/anthropic@3.0.64", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.21" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-rwLi/Rsuj2pYniQXIrvClHvXDzgM4UQHHnvHTWEF14efnlKclG/1ghpNC+adsRujAbCTr6gRsSbDE2vEqriV7g=="], "@ai-sdk/anthropic": ["@ai-sdk/anthropic@3.0.64", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.21" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-rwLi/Rsuj2pYniQXIrvClHvXDzgM4UQHHnvHTWEF14efnlKclG/1ghpNC+adsRujAbCTr6gRsSbDE2vEqriV7g=="],
@@ -761,11 +771,11 @@
"@ai-sdk/fireworks": ["@ai-sdk/fireworks@2.0.46", "", { "dependencies": { "@ai-sdk/openai-compatible": "2.0.41", "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-XRKR0zgRyegdmtK5CDUEjlyRp0Fo+XVCdoG+301U1SGtgRIAYG3ObVtgzVJBVpJdHFSLHuYeLTnNiQoUxD7+FQ=="], "@ai-sdk/fireworks": ["@ai-sdk/fireworks@2.0.46", "", { "dependencies": { "@ai-sdk/openai-compatible": "2.0.41", "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-XRKR0zgRyegdmtK5CDUEjlyRp0Fo+XVCdoG+301U1SGtgRIAYG3ObVtgzVJBVpJdHFSLHuYeLTnNiQoUxD7+FQ=="],
"@ai-sdk/gateway": ["@ai-sdk/gateway@3.0.97", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23", "@vercel/oidc": "3.1.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-ERHmVGX30YKTwxObuHQzNqoOf8Nb5WwYMDBn34e3TGGVn0vLEXwMimo7uRVTbhhi4gfu9WtwYTE4x1+csZok1w=="], "@ai-sdk/gateway": ["@ai-sdk/gateway@3.0.104", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23", "@vercel/oidc": "3.2.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-ZKX5n74io8VIRlhIMSLWVlvT3sXC8Z7cZ9GHuWBWZDVi96+62AIsWuLGvMfcBA1STYuSoDrp6rIziZmvrTq0TA=="],
"@ai-sdk/google": ["@ai-sdk/google@3.0.63", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-RfOZWVMYSPu2sPRfGajrauWAZ9BSaRopSn+AszkKWQ1MFj8nhaXvCqRHB5pBQUaHTfZKagvOmMpNfa/s3gPLgQ=="], "@ai-sdk/google": ["@ai-sdk/google@3.0.63", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-RfOZWVMYSPu2sPRfGajrauWAZ9BSaRopSn+AszkKWQ1MFj8nhaXvCqRHB5pBQUaHTfZKagvOmMpNfa/s3gPLgQ=="],
"@ai-sdk/google-vertex": ["@ai-sdk/google-vertex@4.0.109", "", { "dependencies": { "@ai-sdk/anthropic": "3.0.69", "@ai-sdk/google": "3.0.63", "@ai-sdk/openai-compatible": "2.0.41", "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23", "google-auth-library": "^10.5.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-QzQ+DgOoSYlkU4mK0H+iaCaW1bl5zOimH9X2E2oylcVyUtAdCuduQ959Uw1ygW3l09J2K/ceEDtK8OUPHyOA7g=="], "@ai-sdk/google-vertex": ["@ai-sdk/google-vertex@4.0.112", "", { "dependencies": { "@ai-sdk/anthropic": "3.0.71", "@ai-sdk/google": "3.0.64", "@ai-sdk/openai-compatible": "2.0.41", "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23", "google-auth-library": "^10.5.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-cSfHCkM+9ZrFtQWIN1WlV93JPD+isGSdFxKj7u1L9m2aLVZajlXdcE41GL9hMt7ld7bZYE4NnZ+4VLxBAHE+Eg=="],
"@ai-sdk/groq": ["@ai-sdk/groq@3.0.31", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.21" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-XbbugpnFmXGu2TlXiq8KUJskP6/VVbuFcnFIGDzDIB/Chg6XHsNnqrTF80Zxkh0Pd3+NvbM+2Uqrtsndk6bDAg=="], "@ai-sdk/groq": ["@ai-sdk/groq@3.0.31", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.21" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-XbbugpnFmXGu2TlXiq8KUJskP6/VVbuFcnFIGDzDIB/Chg6XHsNnqrTF80Zxkh0Pd3+NvbM+2Uqrtsndk6bDAg=="],
@@ -1469,6 +1479,8 @@
"@npmcli/arborist": ["@npmcli/arborist@9.4.0", "", { "dependencies": { "@isaacs/string-locale-compare": "^1.1.0", "@npmcli/fs": "^5.0.0", "@npmcli/installed-package-contents": "^4.0.0", "@npmcli/map-workspaces": "^5.0.0", "@npmcli/metavuln-calculator": "^9.0.2", "@npmcli/name-from-folder": "^4.0.0", "@npmcli/node-gyp": "^5.0.0", "@npmcli/package-json": "^7.0.0", "@npmcli/query": "^5.0.0", "@npmcli/redact": "^4.0.0", "@npmcli/run-script": "^10.0.0", "bin-links": "^6.0.0", "cacache": "^20.0.1", "common-ancestor-path": "^2.0.0", "hosted-git-info": "^9.0.0", "json-stringify-nice": "^1.1.4", "lru-cache": "^11.2.1", "minimatch": "^10.0.3", "nopt": "^9.0.0", "npm-install-checks": "^8.0.0", "npm-package-arg": "^13.0.0", "npm-pick-manifest": "^11.0.1", "npm-registry-fetch": "^19.0.0", "pacote": "^21.0.2", "parse-conflict-json": "^5.0.1", "proc-log": "^6.0.0", "proggy": "^4.0.0", "promise-all-reject-late": "^1.0.0", "promise-call-limit": "^3.0.1", "semver": "^7.3.7", "ssri": "^13.0.0", "treeverse": "^3.0.0", "walk-up-path": "^4.0.0" }, "bin": { "arborist": "bin/index.js" } }, "sha512-4Bm8hNixJG/sii1PMnag0V9i/sGOX9VRzFrUiZMSBJpGlLR38f+Btl85d07G9GL56xO0l0OZjvrGNYsDYp0xKA=="], "@npmcli/arborist": ["@npmcli/arborist@9.4.0", "", { "dependencies": { "@isaacs/string-locale-compare": "^1.1.0", "@npmcli/fs": "^5.0.0", "@npmcli/installed-package-contents": "^4.0.0", "@npmcli/map-workspaces": "^5.0.0", "@npmcli/metavuln-calculator": "^9.0.2", "@npmcli/name-from-folder": "^4.0.0", "@npmcli/node-gyp": "^5.0.0", "@npmcli/package-json": "^7.0.0", "@npmcli/query": "^5.0.0", "@npmcli/redact": "^4.0.0", "@npmcli/run-script": "^10.0.0", "bin-links": "^6.0.0", "cacache": "^20.0.1", "common-ancestor-path": "^2.0.0", "hosted-git-info": "^9.0.0", "json-stringify-nice": "^1.1.4", "lru-cache": "^11.2.1", "minimatch": "^10.0.3", "nopt": "^9.0.0", "npm-install-checks": "^8.0.0", "npm-package-arg": "^13.0.0", "npm-pick-manifest": "^11.0.1", "npm-registry-fetch": "^19.0.0", "pacote": "^21.0.2", "parse-conflict-json": "^5.0.1", "proc-log": "^6.0.0", "proggy": "^4.0.0", "promise-all-reject-late": "^1.0.0", "promise-call-limit": "^3.0.1", "semver": "^7.3.7", "ssri": "^13.0.0", "treeverse": "^3.0.0", "walk-up-path": "^4.0.0" }, "bin": { "arborist": "bin/index.js" } }, "sha512-4Bm8hNixJG/sii1PMnag0V9i/sGOX9VRzFrUiZMSBJpGlLR38f+Btl85d07G9GL56xO0l0OZjvrGNYsDYp0xKA=="],
"@npmcli/config": ["@npmcli/config@10.8.1", "", { "dependencies": { "@npmcli/map-workspaces": "^5.0.0", "@npmcli/package-json": "^7.0.0", "ci-info": "^4.0.0", "ini": "^6.0.0", "nopt": "^9.0.0", "proc-log": "^6.0.0", "semver": "^7.3.5", "walk-up-path": "^4.0.0" } }, "sha512-MAYk9IlIGiyC0c9fnjdBSQfIFPZT0g1MfeSiD1UXTq2zJOLX55jS9/sETJHqw/7LN18JjITrhYfgCfapbmZHiQ=="],
"@npmcli/fs": ["@npmcli/fs@5.0.0", "", { "dependencies": { "semver": "^7.3.5" } }, "sha512-7OsC1gNORBEawOa5+j2pXN9vsicaIOH5cPXxoR6fJOmH6/EXpJB2CajXOu1fPRFun2m1lktEFX11+P89hqO/og=="], "@npmcli/fs": ["@npmcli/fs@5.0.0", "", { "dependencies": { "semver": "^7.3.5" } }, "sha512-7OsC1gNORBEawOa5+j2pXN9vsicaIOH5cPXxoR6fJOmH6/EXpJB2CajXOu1fPRFun2m1lktEFX11+P89hqO/og=="],
"@npmcli/git": ["@npmcli/git@7.0.2", "", { "dependencies": { "@gar/promise-retry": "^1.0.0", "@npmcli/promise-spawn": "^9.0.0", "ini": "^6.0.0", "lru-cache": "^11.2.1", "npm-pick-manifest": "^11.0.1", "proc-log": "^6.0.0", "semver": "^7.3.5", "which": "^6.0.0" } }, "sha512-oeolHDjExNAJAnlYP2qzNjMX/Xi9bmu78C9dIGr4xjobrSKbuMYCph8lTzn4vnW3NjIqVmw/f8BCfouqyJXlRg=="], "@npmcli/git": ["@npmcli/git@7.0.2", "", { "dependencies": { "@gar/promise-retry": "^1.0.0", "@npmcli/promise-spawn": "^9.0.0", "ini": "^6.0.0", "lru-cache": "^11.2.1", "npm-pick-manifest": "^11.0.1", "proc-log": "^6.0.0", "semver": "^7.3.5", "which": "^6.0.0" } }, "sha512-oeolHDjExNAJAnlYP2qzNjMX/Xi9bmu78C9dIGr4xjobrSKbuMYCph8lTzn4vnW3NjIqVmw/f8BCfouqyJXlRg=="],
@@ -1549,6 +1561,8 @@
"@opencode-ai/console-resource": ["@opencode-ai/console-resource@workspace:packages/console/resource"], "@opencode-ai/console-resource": ["@opencode-ai/console-resource@workspace:packages/console/resource"],
"@opencode-ai/core": ["@opencode-ai/core@workspace:packages/core"],
"@opencode-ai/desktop": ["@opencode-ai/desktop@workspace:packages/desktop"], "@opencode-ai/desktop": ["@opencode-ai/desktop@workspace:packages/desktop"],
"@opencode-ai/desktop-electron": ["@opencode-ai/desktop-electron@workspace:packages/desktop-electron"], "@opencode-ai/desktop-electron": ["@opencode-ai/desktop-electron@workspace:packages/desktop-electron"],
@@ -1563,10 +1577,6 @@
"@opencode-ai/sdk": ["@opencode-ai/sdk@workspace:packages/sdk/js"], "@opencode-ai/sdk": ["@opencode-ai/sdk@workspace:packages/sdk/js"],
"@opencode-ai/server": ["@opencode-ai/server@workspace:packages/server"],
"@opencode-ai/shared": ["@opencode-ai/shared@workspace:packages/shared"],
"@opencode-ai/slack": ["@opencode-ai/slack@workspace:packages/slack"], "@opencode-ai/slack": ["@opencode-ai/slack@workspace:packages/slack"],
"@opencode-ai/storybook": ["@opencode-ai/storybook@workspace:packages/storybook"], "@opencode-ai/storybook": ["@opencode-ai/storybook@workspace:packages/storybook"],
@@ -1591,7 +1601,7 @@
"@opentelemetry/otlp-transformer": ["@opentelemetry/otlp-transformer@0.214.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.214.0", "@opentelemetry/core": "2.6.1", "@opentelemetry/resources": "2.6.1", "@opentelemetry/sdk-logs": "0.214.0", "@opentelemetry/sdk-metrics": "2.6.1", "@opentelemetry/sdk-trace-base": "2.6.1", "protobufjs": "^7.0.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-DSaYcuBRh6uozfsWN3R8HsN0yDhCuWP7tOFdkUOVaWD1KVJg8m4qiLUsg/tNhTLS9HUYUcwNpwL2eroLtsZZ/w=="], "@opentelemetry/otlp-transformer": ["@opentelemetry/otlp-transformer@0.214.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.214.0", "@opentelemetry/core": "2.6.1", "@opentelemetry/resources": "2.6.1", "@opentelemetry/sdk-logs": "0.214.0", "@opentelemetry/sdk-metrics": "2.6.1", "@opentelemetry/sdk-trace-base": "2.6.1", "protobufjs": "^7.0.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-DSaYcuBRh6uozfsWN3R8HsN0yDhCuWP7tOFdkUOVaWD1KVJg8m4qiLUsg/tNhTLS9HUYUcwNpwL2eroLtsZZ/w=="],
"@opentelemetry/resources": ["@opentelemetry/resources@2.6.1", "", { "dependencies": { "@opentelemetry/core": "2.6.1", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-lID/vxSuKWXM55XhAKNoYXu9Cutoq5hFdkbTdI/zDKQktXzcWBVhNsOkiZFTMU9UtEWuGRNe0HUgmsFldIdxVA=="], "@opentelemetry/resources": ["@opentelemetry/resources@2.2.0", "", { "dependencies": { "@opentelemetry/core": "2.2.0", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-1pNQf/JazQTMA0BiO5NINUzH0cbLbbl7mntLa4aJNmCCXSj0q03T5ZXXL0zw4G55TjdL9Tz32cznGClf+8zr5A=="],
"@opentelemetry/sdk-logs": ["@opentelemetry/sdk-logs@0.214.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.214.0", "@opentelemetry/core": "2.6.1", "@opentelemetry/resources": "2.6.1", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.4.0 <1.10.0" } }, "sha512-zf6acnScjhsaBUU22zXZ/sLWim1dfhUAbGXdMmHmNG3LfBnQ3DKsOCITb2IZwoUsNNMTogqFKBnlIPPftUgGwA=="], "@opentelemetry/sdk-logs": ["@opentelemetry/sdk-logs@0.214.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.214.0", "@opentelemetry/core": "2.6.1", "@opentelemetry/resources": "2.6.1", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.4.0 <1.10.0" } }, "sha512-zf6acnScjhsaBUU22zXZ/sLWim1dfhUAbGXdMmHmNG3LfBnQ3DKsOCITb2IZwoUsNNMTogqFKBnlIPPftUgGwA=="],
@@ -1603,21 +1613,21 @@
"@opentelemetry/semantic-conventions": ["@opentelemetry/semantic-conventions@1.40.0", "", {}, "sha512-cifvXDhcqMwwTlTK04GBNeIe7yyo28Mfby85QXFe1Yk8nmi36Ab/5UQwptOx84SsoGNRg+EVSjwzfSZMy6pmlw=="], "@opentelemetry/semantic-conventions": ["@opentelemetry/semantic-conventions@1.40.0", "", {}, "sha512-cifvXDhcqMwwTlTK04GBNeIe7yyo28Mfby85QXFe1Yk8nmi36Ab/5UQwptOx84SsoGNRg+EVSjwzfSZMy6pmlw=="],
"@opentui/core": ["@opentui/core@0.1.99", "", { "dependencies": { "bun-ffi-structs": "0.1.2", "diff": "8.0.2", "jimp": "1.6.0", "marked": "17.0.1", "yoga-layout": "3.2.1" }, "optionalDependencies": { "@dimforge/rapier2d-simd-compat": "^0.17.3", "@opentui/core-darwin-arm64": "0.1.99", "@opentui/core-darwin-x64": "0.1.99", "@opentui/core-linux-arm64": "0.1.99", "@opentui/core-linux-x64": "0.1.99", "@opentui/core-win32-arm64": "0.1.99", "@opentui/core-win32-x64": "0.1.99", "bun-webgpu": "0.1.5", "planck": "^1.4.2", "three": "0.177.0" }, "peerDependencies": { "web-tree-sitter": "0.25.10" } }, "sha512-I3+AEgGzqNWIpWX9g2WOscSPwtQDNOm4KlBjxBWCZjLxkF07u77heWXF7OiAdhKLtNUW6TFiyt6yznqAZPdG3A=="], "@opentui/core": ["@opentui/core@0.1.103", "", { "dependencies": { "bun-ffi-structs": "0.1.2", "diff": "8.0.2", "jimp": "1.6.0", "marked": "17.0.1", "yoga-layout": "3.2.1" }, "optionalDependencies": { "@dimforge/rapier2d-simd-compat": "^0.17.3", "@opentui/core-darwin-arm64": "0.1.103", "@opentui/core-darwin-x64": "0.1.103", "@opentui/core-linux-arm64": "0.1.103", "@opentui/core-linux-x64": "0.1.103", "@opentui/core-win32-arm64": "0.1.103", "@opentui/core-win32-x64": "0.1.103", "bun-webgpu": "0.1.5", "planck": "^1.4.2", "three": "0.177.0" }, "peerDependencies": { "web-tree-sitter": "0.25.10" } }, "sha512-PWVv/bDmlk1i6X1f0zXs+jSaTrQ/ByX8wFbP2WinOObTGf//UbcRP4dbWxPXvOyka9QlmRBG/7GbloQSIStyVw=="],
"@opentui/core-darwin-arm64": ["@opentui/core-darwin-arm64@0.1.99", "", { "os": "darwin", "cpu": "arm64" }, "sha512-bzVrqeX2vb5iWrc/ftOUOqeUY8XO+qSgoTwj5TXHuwagavgwD3Hpeyjx8+icnTTeM4pao0som1WR9xfye6/X5Q=="], "@opentui/core-darwin-arm64": ["@opentui/core-darwin-arm64@0.1.103", "", { "os": "darwin", "cpu": "arm64" }, "sha512-lxCyedDkcen12IgBtXjkJ7iY66xa7VC4nxRNKCUeLY2ZP9hUE1AsDtbyQzqY+BQadsI/ZME9STzaHDCUFg0TpA=="],
"@opentui/core-darwin-x64": ["@opentui/core-darwin-x64@0.1.99", "", { "os": "darwin", "cpu": "x64" }, "sha512-VE4FrXBYpkxnvkqcCV1a8aN9jyyMJMihVW+V2NLCtp+4yQsj0AapG5TiUSN76XnmSZRptxDy5rBmEempeoIZbg=="], "@opentui/core-darwin-x64": ["@opentui/core-darwin-x64@0.1.103", "", { "os": "darwin", "cpu": "x64" }, "sha512-QMYD+zUDGQliJ6m5nuNvA72jtluFeyVMoHkuA5m/Xmed/u8eLfahAKmDj3kY66ntUroPHWevcpbpvd7NCFEoFQ=="],
"@opentui/core-linux-arm64": ["@opentui/core-linux-arm64@0.1.99", "", { "os": "linux", "cpu": "arm64" }, "sha512-viXQsbpS7yHjYkl7+am32JdvG96QU9lvHh1UiZtpOxcNUUqiYmA2ZwZFPD2Bi54jNyj5l2hjH6YkD3DzE2FEWA=="], "@opentui/core-linux-arm64": ["@opentui/core-linux-arm64@0.1.103", "", { "os": "linux", "cpu": "arm64" }, "sha512-GzOvNr9dN6JaQ9qs7m8E75wLAHwT5CyxqkE6rEr1BO23/d2Ix7e3GYw/JRY5VnTge+eXrfDVbqNtPcQamUNiEA=="],
"@opentui/core-linux-x64": ["@opentui/core-linux-x64@0.1.99", "", { "os": "linux", "cpu": "x64" }, "sha512-WLoEFINOSp0tZSR9y4LUuGc7n4Y7H1wcpjUPzQ9vChkYDXrfZltEanzoDWbDcQ4kZQW5tHVC7LrZHpAsRLwFZg=="], "@opentui/core-linux-x64": ["@opentui/core-linux-x64@0.1.103", "", { "os": "linux", "cpu": "x64" }, "sha512-odywllco5zUKNc60uD3JKaCybK64u6BfmpScs4a8Qn89yH/yk23bzWXDRWaGgQdY65L2/VCbcGs1ezA1S/2YTw=="],
"@opentui/core-win32-arm64": ["@opentui/core-win32-arm64@0.1.99", "", { "os": "win32", "cpu": "arm64" }, "sha512-yWMOLWCEO8HdrctU1dMkgZC8qGkiO4Dwr4/e11tTvVpRmYhDsP/IR89ZjEEtOwnKwFOFuB/MxvflqaEWVQ2g5Q=="], "@opentui/core-win32-arm64": ["@opentui/core-win32-arm64@0.1.103", "", { "os": "win32", "cpu": "arm64" }, "sha512-tZL5w3Y0JnO7RkIvfuNDAzJn0j6+JIYl6M8DgPM5p8AQt+162S8LmbumzmqQLZl4cEev2eN7/tw72WIk6b+/CQ=="],
"@opentui/core-win32-x64": ["@opentui/core-win32-x64@0.1.99", "", { "os": "win32", "cpu": "x64" }, "sha512-aYRlsL2w8YRL6vPd7/hrqlNVkXU3QowWb01TOvAcHS8UAsXaGFUr47kSDyjxDi1wg1MzmVduCfsC7T3NoThV1w=="], "@opentui/core-win32-x64": ["@opentui/core-win32-x64@0.1.103", "", { "os": "win32", "cpu": "x64" }, "sha512-wqnibt/OE5ldSzVPxEbriA0TjI2B11CJl4uJoLxTZ47KDx7tAFIMdhBf9IRAGNCSbcDuZ8ZGEFhV+SLaftkrlw=="],
"@opentui/solid": ["@opentui/solid@0.1.99", "", { "dependencies": { "@babel/core": "7.28.0", "@babel/preset-typescript": "7.27.1", "@opentui/core": "0.1.99", "babel-plugin-module-resolver": "5.0.2", "babel-preset-solid": "1.9.10", "entities": "7.0.1", "s-js": "^0.4.9" }, "peerDependencies": { "solid-js": "1.9.11" } }, "sha512-DrqqO4h2V88FmeIP2cErYkMU0ZK5MrUsZw3w6IzZpoXyyiL4/9qpWzUq+CXx+r16VP2iGxDJwGKUmtFAzUch2Q=="], "@opentui/solid": ["@opentui/solid@0.1.103", "", { "dependencies": { "@babel/core": "7.28.0", "@babel/preset-typescript": "7.27.1", "@opentui/core": "0.1.103", "babel-plugin-module-resolver": "5.0.2", "babel-preset-solid": "1.9.10", "entities": "7.0.1", "s-js": "^0.4.9" }, "peerDependencies": { "solid-js": "1.9.11" } }, "sha512-L28WFBs17Z5JXkJhPagLy8tUamkttDaaQDdb2KEO01IQ9r81yLBRpYqD/lHp6UoSISXgwQVDQ9yNtxwR1BQZvQ=="],
"@oslojs/asn1": ["@oslojs/asn1@1.0.0", "", { "dependencies": { "@oslojs/binary": "1.0.0" } }, "sha512-zw/wn0sj0j0QKbIXfIlnEcTviaCzYOY3V5rAyjR6YtOByFtJiT574+8p9Wlach0lZH9fddD4yb9laEAIl4vXQA=="], "@oslojs/asn1": ["@oslojs/asn1@1.0.0", "", { "dependencies": { "@oslojs/binary": "1.0.0" } }, "sha512-zw/wn0sj0j0QKbIXfIlnEcTviaCzYOY3V5rAyjR6YtOByFtJiT574+8p9Wlach0lZH9fddD4yb9laEAIl4vXQA=="],
@@ -1689,6 +1699,56 @@
"@oxc-transform/binding-win32-x64-msvc": ["@oxc-transform/binding-win32-x64-msvc@0.96.0", "", { "os": "win32", "cpu": "x64" }, "sha512-0fI0P0W7bSO/GCP/N5dkmtB9vBqCA4ggo1WmXTnxNJVmFFOtcA1vYm1I9jl8fxo+sucW2WnlpnI4fjKdo3JKxA=="], "@oxc-transform/binding-win32-x64-msvc": ["@oxc-transform/binding-win32-x64-msvc@0.96.0", "", { "os": "win32", "cpu": "x64" }, "sha512-0fI0P0W7bSO/GCP/N5dkmtB9vBqCA4ggo1WmXTnxNJVmFFOtcA1vYm1I9jl8fxo+sucW2WnlpnI4fjKdo3JKxA=="],
"@oxlint-tsgolint/darwin-arm64": ["@oxlint-tsgolint/darwin-arm64@0.21.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-P20j3MLqfwIT+94qGU3htC7dWp4pXGZW1p1p7FRUzu1aopq7c9nPCgf0W/WjktqQ57+iuTq9mbSlwWinl6+H1A=="],
"@oxlint-tsgolint/darwin-x64": ["@oxlint-tsgolint/darwin-x64@0.21.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-81TmmuBcPedEA0MwRmObuQuXnCprS1UiHQWGe7pseqNAJzUWXeAPrayqKTACX92VpruJI+yvY0XJrFp11PpcTA=="],
"@oxlint-tsgolint/linux-arm64": ["@oxlint-tsgolint/linux-arm64@0.21.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-sbjBr6zDduX8rNO0PTjhf7VYLCPWqdijWiMPp8e10qu6Tam1GdaVLaLlX8QrNupTgglO1GvqqgY/jcacWL8a6g=="],
"@oxlint-tsgolint/linux-x64": ["@oxlint-tsgolint/linux-x64@0.21.0", "", { "os": "linux", "cpu": "x64" }, "sha512-jNrOcy53R5TJQfrK444Cm60bW9437xDoxPbm3AdvFSo/fhdFMllawc7uZC2Wzr+EAjTkW13K8R4QHzsUdBG9fQ=="],
"@oxlint-tsgolint/win32-arm64": ["@oxlint-tsgolint/win32-arm64@0.21.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-xWeRxJJILDE4b9UqHEWGBxcBc1TUS6zWHhxcyxTZMwf4q3wdKeu0OHYAcwLGJzoSjEIf6FTjyfPiRNil2oqsdg=="],
"@oxlint-tsgolint/win32-x64": ["@oxlint-tsgolint/win32-x64@0.21.0", "", { "os": "win32", "cpu": "x64" }, "sha512-Ob9AA9teI8ckPo1whV1smLr5NrqwgBv/8boDbK0YZG+fKgNGRwr1hBj1ORgFWOQaUBv+5njp5A0RAfJJjQ95QQ=="],
"@oxlint/binding-android-arm-eabi": ["@oxlint/binding-android-arm-eabi@1.60.0", "", { "os": "android", "cpu": "arm" }, "sha512-YdeJKaZckDQL1qa62a1aKq/goyq48aX3yOxaaWqWb4sau4Ee4IiLbamftNLU3zbePky6QsDj6thnSSzHRBjDfA=="],
"@oxlint/binding-android-arm64": ["@oxlint/binding-android-arm64@1.60.0", "", { "os": "android", "cpu": "arm64" }, "sha512-7ANS7PpXCfq84xZQ8E5WPs14gwcuPcl+/8TFNXfpSu0CQBXz3cUo2fDpHT8v8HJN+Ut02eacvMAzTnc9s6X4tw=="],
"@oxlint/binding-darwin-arm64": ["@oxlint/binding-darwin-arm64@1.60.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-pJsgd9AfplLGBm1fIr25V6V14vMrayhx4uIQvlfH7jWs2SZwSrvi3TfgfJySB8T+hvyEH8K2zXljQiUnkgUnfQ=="],
"@oxlint/binding-darwin-x64": ["@oxlint/binding-darwin-x64@1.60.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-Ue1aXHX49ivwflKqGJc7zcd/LeLgbhaTcDCQStgx5x06AXgjEAZmvrlMuIkWd4AL4FHQe6QJ9f33z04Cg448VQ=="],
"@oxlint/binding-freebsd-x64": ["@oxlint/binding-freebsd-x64@1.60.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-YCyQzsQtusQw+gNRW9rRTifSO+Dt/+dtCl2NHoDMZqJlRTEZ/Oht9YnuporI9yiTx7+cB+eqzX3MtHHVHGIWhg=="],
"@oxlint/binding-linux-arm-gnueabihf": ["@oxlint/binding-linux-arm-gnueabihf@1.60.0", "", { "os": "linux", "cpu": "arm" }, "sha512-c7dxM2Zksa45Qw16i2iGY3Fti2NirJ38FrsBsKw+qcJ0OtqTsBgKJLF0xV+yLG56UH01Z8WRPgsw31e0MoRoGQ=="],
"@oxlint/binding-linux-arm-musleabihf": ["@oxlint/binding-linux-arm-musleabihf@1.60.0", "", { "os": "linux", "cpu": "arm" }, "sha512-ZWALoA42UYqBEP1Tbw9OWURgFGS1nWj2AAvLdY6ZcGx/Gj93qVCBKjcvwXMupZibYwFbi9s/rzqkZseb/6gVtQ=="],
"@oxlint/binding-linux-arm64-gnu": ["@oxlint/binding-linux-arm64-gnu@1.60.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-tpy+1w4p9hN5CicMCxqNy6ymfRtV5ayE573vFNjp1k1TN/qhLFgflveZoE/0++RlkHikBz2vY545NWm/hp7big=="],
"@oxlint/binding-linux-arm64-musl": ["@oxlint/binding-linux-arm64-musl@1.60.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-eDYDXZGhQAXyn6GwtwiX/qcLS0HlOLPJ/+iiIY8RYr+3P8oKBmgKxADLlniL6FtWfE7pPk7IGN9/xvDEvDvFeg=="],
"@oxlint/binding-linux-ppc64-gnu": ["@oxlint/binding-linux-ppc64-gnu@1.60.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-nxehly5XYBHUWI9VJX1bqCf9j/B43DaK/aS/T1fcxCpX3PA4Rm9BB54nPD1CKayT8xg6REN1ao+01hSRNgy8OA=="],
"@oxlint/binding-linux-riscv64-gnu": ["@oxlint/binding-linux-riscv64-gnu@1.60.0", "", { "os": "linux", "cpu": "none" }, "sha512-j1qf/NaUfOWQutjeoooNG1Q0zsK0XGmSu1uDLq3cctquRF3j7t9Hxqf/76ehCc5GEUAanth2W4Fa+XT1RFg/nw=="],
"@oxlint/binding-linux-riscv64-musl": ["@oxlint/binding-linux-riscv64-musl@1.60.0", "", { "os": "linux", "cpu": "none" }, "sha512-YELKPRefQ/q/h3RUmeRfPCUhh2wBvgV1RyZ/F9M9u8cDyXsQW2ojv1DeWQTt466yczDITjZnIOg/s05pk7Ve2A=="],
"@oxlint/binding-linux-s390x-gnu": ["@oxlint/binding-linux-s390x-gnu@1.60.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-JkO3C6Gki7Y6h/MiIkFKvHFOz98/YWvQ4WYbK9DLXACMP2rjULzkeGyAzorJE5S1dzLQGFgeqvN779kSFwoV1g=="],
"@oxlint/binding-linux-x64-gnu": ["@oxlint/binding-linux-x64-gnu@1.60.0", "", { "os": "linux", "cpu": "x64" }, "sha512-XjKHdFVCpZZZSWBCKyyqCq65s2AKXykMXkjLoKYODrD+f5toLhlwsMESscu8FbgnJQ4Y/dpR/zdazsahmgBJIA=="],
"@oxlint/binding-linux-x64-musl": ["@oxlint/binding-linux-x64-musl@1.60.0", "", { "os": "linux", "cpu": "x64" }, "sha512-js29ZWIuPhNWzY8NC7KoffEMEeWG105vbmm+8EOJsC+T/jHBiKIJEUF78+F/IrgEWMMP9N0kRND4Pp75+xAhKg=="],
"@oxlint/binding-openharmony-arm64": ["@oxlint/binding-openharmony-arm64@1.60.0", "", { "os": "none", "cpu": "arm64" }, "sha512-H+PUITKHk04stFpWj3x3Kg08Afp/bcXSBi0EhasR5a0Vw7StXHTzdl655PUI0fB4qdh2Wsu6Dsi+3ACxPoyQnA=="],
"@oxlint/binding-win32-arm64-msvc": ["@oxlint/binding-win32-arm64-msvc@1.60.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-WA/yc7f7ZfCefBXVzNHn1Ztulb1EFwNBb4jMZ6pjML0zz6pHujlF3Q3jySluz3XHl/GNeMTntG1seUBWVMlMag=="],
"@oxlint/binding-win32-ia32-msvc": ["@oxlint/binding-win32-ia32-msvc@1.60.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-33YxL1sqwYNZXtn3MD/4dno6s0xeedXOJlT1WohkVD565WvohClZUr7vwKdAk954n4xiEWJkewiCr+zLeq7AeA=="],
"@oxlint/binding-win32-x64-msvc": ["@oxlint/binding-win32-x64-msvc@1.60.0", "", { "os": "win32", "cpu": "x64" }, "sha512-JOro4ZcfBLamJCyfURQmOQByoorgOdx3ZjAkSqnb/CyG/i+lN3KoV5LAgk5ZAW6DPq7/Cx7n23f8DuTWXTWgyQ=="],
"@pagefind/darwin-arm64": ["@pagefind/darwin-arm64@1.5.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-MXpI+7HsAdPkvJ0gk9xj9g541BCqBZOBbdwj9g6lB5LCj6kSV6nqDSjzcAJwvOsfu0fjwvC8hQU+ecfhp+MpiQ=="], "@pagefind/darwin-arm64": ["@pagefind/darwin-arm64@1.5.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-MXpI+7HsAdPkvJ0gk9xj9g541BCqBZOBbdwj9g6lB5LCj6kSV6nqDSjzcAJwvOsfu0fjwvC8hQU+ecfhp+MpiQ=="],
"@pagefind/darwin-x64": ["@pagefind/darwin-x64@1.5.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-IojxFWMEJe0RQ7PQ3KXQsPIImNsbpPYpoZ+QUDrL8fAl/O27IX+LVLs74/UzEZy5uA2LD8Nz1AiwKr72vrkZQw=="], "@pagefind/darwin-x64": ["@pagefind/darwin-x64@1.5.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-IojxFWMEJe0RQ7PQ3KXQsPIImNsbpPYpoZ+QUDrL8fAl/O27IX+LVLs74/UzEZy5uA2LD8Nz1AiwKr72vrkZQw=="],
@@ -2251,7 +2311,7 @@
"@types/braces": ["@types/braces@3.0.5", "", {}, "sha512-SQFof9H+LXeWNz8wDe7oN5zu7ket0qwMu5vZubW4GCJ8Kkeh6nBWUz87+KTz/G3Kqsrp0j/W253XJb3KMEeg3w=="], "@types/braces": ["@types/braces@3.0.5", "", {}, "sha512-SQFof9H+LXeWNz8wDe7oN5zu7ket0qwMu5vZubW4GCJ8Kkeh6nBWUz87+KTz/G3Kqsrp0j/W253XJb3KMEeg3w=="],
"@types/bun": ["@types/bun@1.3.11", "", { "dependencies": { "bun-types": "1.3.11" } }, "sha512-5vPne5QvtpjGpsGYXiFyycfpDF2ECyPcTSsFBMa0fraoxiQyMJ3SmuQIGhzPg2WJuWxVBoxWJ2kClYTcw/4fAg=="], "@types/bun": ["@types/bun@1.3.12", "", { "dependencies": { "bun-types": "1.3.12" } }, "sha512-DBv81elK+/VSwXHDlnH3Qduw+KxkTIWi7TXkAeh24zpi5l0B2kUg9Ga3tb4nJaPcOFswflgi/yAvMVBPrxMB+A=="],
"@types/cacache": ["@types/cacache@20.0.1", "", { "dependencies": { "@types/node": "*", "minipass": "*" } }, "sha512-QlKW3AFoFr/hvPHwFHMIVUH/ZCYeetBNou3PCmxu5LaNDvrtBlPJtIA6uhmU9JRt9oxj7IYoqoLcpxtzpPiTcw=="], "@types/cacache": ["@types/cacache@20.0.1", "", { "dependencies": { "@types/node": "*", "minipass": "*" } }, "sha512-QlKW3AFoFr/hvPHwFHMIVUH/ZCYeetBNou3PCmxu5LaNDvrtBlPJtIA6uhmU9JRt9oxj7IYoqoLcpxtzpPiTcw=="],
@@ -2409,7 +2469,7 @@
"@valibot/to-json-schema": ["@valibot/to-json-schema@1.6.0", "", { "peerDependencies": { "valibot": "^1.3.0" } }, "sha512-d6rYyK5KVa2XdqamWgZ4/Nr+cXhxjy7lmpe6Iajw15J/jmU+gyxl2IEd1Otg1d7Rl3gOQL5reulnSypzBtYy1A=="], "@valibot/to-json-schema": ["@valibot/to-json-schema@1.6.0", "", { "peerDependencies": { "valibot": "^1.3.0" } }, "sha512-d6rYyK5KVa2XdqamWgZ4/Nr+cXhxjy7lmpe6Iajw15J/jmU+gyxl2IEd1Otg1d7Rl3gOQL5reulnSypzBtYy1A=="],
"@vercel/oidc": ["@vercel/oidc@3.1.0", "", {}, "sha512-Fw28YZpRnA3cAHHDlkt7xQHiJ0fcL+NRcIqsocZQUSmbzeIKRpwttJjik5ZGanXP+vlA4SbTg+AbA3bP363l+w=="], "@vercel/oidc": ["@vercel/oidc@3.2.0", "", {}, "sha512-UycprH3T6n3jH0k44NHMa7pnFHGu/N05MjojYr+Mc6I7obkoLIJujSWwin1pCvdy/eOxrI/l3uDLQsmcrOb4ug=="],
"@vitejs/plugin-react": ["@vitejs/plugin-react@4.7.0", "", { "dependencies": { "@babel/core": "^7.28.0", "@babel/plugin-transform-react-jsx-self": "^7.27.1", "@babel/plugin-transform-react-jsx-source": "^7.27.1", "@rolldown/pluginutils": "1.0.0-beta.27", "@types/babel__core": "^7.20.5", "react-refresh": "^0.17.0" }, "peerDependencies": { "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" } }, "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA=="], "@vitejs/plugin-react": ["@vitejs/plugin-react@4.7.0", "", { "dependencies": { "@babel/core": "^7.28.0", "@babel/plugin-transform-react-jsx-self": "^7.27.1", "@babel/plugin-transform-react-jsx-source": "^7.27.1", "@rolldown/pluginutils": "1.0.0-beta.27", "@types/babel__core": "^7.20.5", "react-refresh": "^0.17.0" }, "peerDependencies": { "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" } }, "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA=="],
@@ -2469,7 +2529,7 @@
"agentkeepalive": ["agentkeepalive@4.6.0", "", { "dependencies": { "humanize-ms": "^1.2.1" } }, "sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ=="], "agentkeepalive": ["agentkeepalive@4.6.0", "", { "dependencies": { "humanize-ms": "^1.2.1" } }, "sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ=="],
"ai": ["ai@6.0.158", "", { "dependencies": { "@ai-sdk/gateway": "3.0.95", "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23", "@opentelemetry/api": "1.9.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-gLTp1UXFtMqKUi3XHs33K7UFglbvojkxF/aq337TxnLGOhHIW9+GyP2jwW4hYX87f1es+wId3VQoPRRu9zEStQ=="], "ai": ["ai@6.0.168", "", { "dependencies": { "@ai-sdk/gateway": "3.0.104", "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23", "@opentelemetry/api": "1.9.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-2HqCJuO+1V2aV7vfYs5LFEUfxbkGX+5oa54q/gCCTL7KLTdbxcCu5D7TdLA5kwsrs3Szgjah9q6D9tpjHM3hUQ=="],
"ai-gateway-provider": ["ai-gateway-provider@3.1.2", "", { "optionalDependencies": { "@ai-sdk/amazon-bedrock": "^4.0.62", "@ai-sdk/anthropic": "^3.0.46", "@ai-sdk/azure": "^3.0.31", "@ai-sdk/cerebras": "^2.0.34", "@ai-sdk/cohere": "^3.0.21", "@ai-sdk/deepgram": "^2.0.20", "@ai-sdk/deepseek": "^2.0.20", "@ai-sdk/elevenlabs": "^2.0.20", "@ai-sdk/fireworks": "^2.0.34", "@ai-sdk/google": "^3.0.30", "@ai-sdk/google-vertex": "^4.0.61", "@ai-sdk/groq": "^3.0.24", "@ai-sdk/mistral": "^3.0.20", "@ai-sdk/openai": "^3.0.30", "@ai-sdk/perplexity": "^3.0.19", "@ai-sdk/xai": "^3.0.57", "@openrouter/ai-sdk-provider": "^2.2.3" }, "peerDependencies": { "@ai-sdk/openai-compatible": "^2.0.0", "@ai-sdk/provider": "^3.0.0", "@ai-sdk/provider-utils": "^4.0.0", "ai": "^6.0.0" } }, "sha512-krGNnJSoO/gJ7Hbe5nQDlsBpDUGIBGtMQTRUaW7s1MylsfvLduba0TLWzQaGtOmNRkP0pGhtGlwsnS6FNQMlyw=="], "ai-gateway-provider": ["ai-gateway-provider@3.1.2", "", { "optionalDependencies": { "@ai-sdk/amazon-bedrock": "^4.0.62", "@ai-sdk/anthropic": "^3.0.46", "@ai-sdk/azure": "^3.0.31", "@ai-sdk/cerebras": "^2.0.34", "@ai-sdk/cohere": "^3.0.21", "@ai-sdk/deepgram": "^2.0.20", "@ai-sdk/deepseek": "^2.0.20", "@ai-sdk/elevenlabs": "^2.0.20", "@ai-sdk/fireworks": "^2.0.34", "@ai-sdk/google": "^3.0.30", "@ai-sdk/google-vertex": "^4.0.61", "@ai-sdk/groq": "^3.0.24", "@ai-sdk/mistral": "^3.0.20", "@ai-sdk/openai": "^3.0.30", "@ai-sdk/perplexity": "^3.0.19", "@ai-sdk/xai": "^3.0.57", "@openrouter/ai-sdk-provider": "^2.2.3" }, "peerDependencies": { "@ai-sdk/openai-compatible": "^2.0.0", "@ai-sdk/provider": "^3.0.0", "@ai-sdk/provider-utils": "^4.0.0", "ai": "^6.0.0" } }, "sha512-krGNnJSoO/gJ7Hbe5nQDlsBpDUGIBGtMQTRUaW7s1MylsfvLduba0TLWzQaGtOmNRkP0pGhtGlwsnS6FNQMlyw=="],
@@ -2669,7 +2729,7 @@
"bun-pty": ["bun-pty@0.4.8", "", {}, "sha512-rO70Mrbr13+jxHHHu2YBkk2pNqrJE5cJn29WE++PUr+GFA0hq/VgtQPZANJ8dJo6d7XImvBk37Innt8GM7O28w=="], "bun-pty": ["bun-pty@0.4.8", "", {}, "sha512-rO70Mrbr13+jxHHHu2YBkk2pNqrJE5cJn29WE++PUr+GFA0hq/VgtQPZANJ8dJo6d7XImvBk37Innt8GM7O28w=="],
"bun-types": ["bun-types@1.3.11", "", { "dependencies": { "@types/node": "*" } }, "sha512-1KGPpoxQWl9f6wcZh57LvrPIInQMn2TQ7jsgxqpRzg+l0QPOFvJVH7HmvHo/AiPgwXy+/Thf6Ov3EdVn1vOabg=="], "bun-types": ["bun-types@1.3.12", "", { "dependencies": { "@types/node": "*" } }, "sha512-HqOLj5PoFajAQciOMRiIZGNoKxDJSr6qigAttOX40vJuSp6DN/CxWp9s3C1Xwm4oH7ybueITwiaOcWXoYVoRkA=="],
"bun-webgpu": ["bun-webgpu@0.1.5", "", { "dependencies": { "@webgpu/types": "^0.1.60" }, "optionalDependencies": { "bun-webgpu-darwin-arm64": "^0.1.5", "bun-webgpu-darwin-x64": "^0.1.5", "bun-webgpu-linux-x64": "^0.1.5", "bun-webgpu-win32-x64": "^0.1.5" } }, "sha512-91/K6S5whZKX7CWAm9AylhyKrLGRz6BUiiPiM/kXadSnD4rffljCD/q9cNFftm5YXhx4MvLqw33yEilxogJvwA=="], "bun-webgpu": ["bun-webgpu@0.1.5", "", { "dependencies": { "@webgpu/types": "^0.1.60" }, "optionalDependencies": { "bun-webgpu-darwin-arm64": "^0.1.5", "bun-webgpu-darwin-x64": "^0.1.5", "bun-webgpu-linux-x64": "^0.1.5", "bun-webgpu-win32-x64": "^0.1.5" } }, "sha512-91/K6S5whZKX7CWAm9AylhyKrLGRz6BUiiPiM/kXadSnD4rffljCD/q9cNFftm5YXhx4MvLqw33yEilxogJvwA=="],
@@ -2979,7 +3039,7 @@
"ejs": ["ejs@3.1.10", "", { "dependencies": { "jake": "^10.8.5" }, "bin": { "ejs": "bin/cli.js" } }, "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA=="], "ejs": ["ejs@3.1.10", "", { "dependencies": { "jake": "^10.8.5" }, "bin": { "ejs": "bin/cli.js" } }, "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA=="],
"electron": ["electron@40.4.1", "", { "dependencies": { "@electron/get": "^2.0.0", "@types/node": "^24.9.0", "extract-zip": "^2.0.1" }, "bin": { "electron": "cli.js" } }, "sha512-N1ZXybQZL8kYemO8vAeh9nrk4mSvqlAO8xs0QCHkXIvRnuB/7VGwEehjvQbsU5/f4bmTKpG+2GQERe/zmKpudQ=="], "electron": ["electron@41.2.1", "", { "dependencies": { "@electron/get": "^2.0.0", "@types/node": "^24.9.0", "extract-zip": "^2.0.1" }, "bin": { "electron": "cli.js" } }, "sha512-teeRThiYGTPKf/2yOW7zZA1bhb91KEQ4yLBPOg7GxpmnkLFLugKgQaAKOrCgdzwsXh/5mFIfmkm+4+wACJKwaA=="],
"electron-builder": ["electron-builder@26.8.1", "", { "dependencies": { "app-builder-lib": "26.8.1", "builder-util": "26.8.1", "builder-util-runtime": "9.5.1", "chalk": "^4.1.2", "ci-info": "^4.2.0", "dmg-builder": "26.8.1", "fs-extra": "^10.1.0", "lazy-val": "^1.0.5", "simple-update-notifier": "2.0.0", "yargs": "^17.6.2" }, "bin": { "electron-builder": "cli.js", "install-app-deps": "install-app-deps.js" } }, "sha512-uWhx1r74NGpCagG0ULs/P9Nqv2nsoo+7eo4fLUOB8L8MdWltq9odW/uuLXMFCDGnPafknYLZgjNX0ZIFRzOQAw=="], "electron-builder": ["electron-builder@26.8.1", "", { "dependencies": { "app-builder-lib": "26.8.1", "builder-util": "26.8.1", "builder-util-runtime": "9.5.1", "chalk": "^4.1.2", "ci-info": "^4.2.0", "dmg-builder": "26.8.1", "fs-extra": "^10.1.0", "lazy-val": "^1.0.5", "simple-update-notifier": "2.0.0", "yargs": "^17.6.2" }, "bin": { "electron-builder": "cli.js", "install-app-deps": "install-app-deps.js" } }, "sha512-uWhx1r74NGpCagG0ULs/P9Nqv2nsoo+7eo4fLUOB8L8MdWltq9odW/uuLXMFCDGnPafknYLZgjNX0ZIFRzOQAw=="],
@@ -3259,7 +3319,7 @@
"get-tsconfig": ["get-tsconfig@4.13.8", "", { "dependencies": { "resolve-pkg-maps": "^1.0.0" } }, "sha512-J87BxkLXykmisLQ+KA4x2+O6rVf+PJrtFUO8lGyiRg4lyxJLJ8/v0sRAKdVZQOy6tR6lMRAF1NqzCf9BQijm0w=="], "get-tsconfig": ["get-tsconfig@4.13.8", "", { "dependencies": { "resolve-pkg-maps": "^1.0.0" } }, "sha512-J87BxkLXykmisLQ+KA4x2+O6rVf+PJrtFUO8lGyiRg4lyxJLJ8/v0sRAKdVZQOy6tR6lMRAF1NqzCf9BQijm0w=="],
"ghostty-web": ["ghostty-web@github:anomalyco/ghostty-web#4af877d", {}, "anomalyco-ghostty-web-4af877d", "sha512-fbEK8mtr7ar4ySsF+JUGjhaZrane7dKphanN+SxHt5XXI6yLMAh/Hpf6sNCOyyVa2UlGCd7YpXG/T2v2RUAX+A=="], "ghostty-web": ["ghostty-web@github:anomalyco/ghostty-web#20bd361", {}, "anomalyco-ghostty-web-20bd361", "sha512-dW0nwaiBBcun9y5WJSvm3HxDLe5o9V0xLCndQvWonRVubU8CS1PHxZpLffyPt1YujPWC13ez03aWxcuKBPYYGQ=="],
"gifwrap": ["gifwrap@0.10.1", "", { "dependencies": { "image-q": "^4.0.0", "omggif": "^1.0.10" } }, "sha512-2760b1vpJHNmLzZ/ubTtNnEx5WApN/PYWJvXvgS+tL1egTTthayFYIQQNi136FLEDcN/IyEY2EcGpIITD6eYUw=="], "gifwrap": ["gifwrap@0.10.1", "", { "dependencies": { "image-q": "^4.0.0", "omggif": "^1.0.10" } }, "sha512-2760b1vpJHNmLzZ/ubTtNnEx5WApN/PYWJvXvgS+tL1egTTthayFYIQQNi136FLEDcN/IyEY2EcGpIITD6eYUw=="],
@@ -3267,7 +3327,7 @@
"github-slugger": ["github-slugger@2.0.0", "", {}, "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw=="], "github-slugger": ["github-slugger@2.0.0", "", {}, "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw=="],
"gitlab-ai-provider": ["gitlab-ai-provider@6.4.2", "", { "dependencies": { "@anthropic-ai/sdk": "^0.71.0", "@anycable/core": "^0.9.2", "graphql-request": "^6.1.0", "isomorphic-ws": "^5.0.0", "openai": "^6.16.0", "socket.io-client": "^4.8.1", "vscode-jsonrpc": "^8.2.1", "zod": "^3.25.76" }, "peerDependencies": { "@ai-sdk/provider": ">=3.0.0", "@ai-sdk/provider-utils": ">=4.0.0" } }, "sha512-Wyw6uslCuipBOr/NYwAtpgXEUJj68iJY5aekad2DjePN99JetKVQBqkLgAy9PZp2EA4OuscfRQu9qKIBN/evNw=="], "gitlab-ai-provider": ["gitlab-ai-provider@6.6.0", "", { "dependencies": { "@anthropic-ai/sdk": "^0.71.0", "@anycable/core": "^0.9.2", "graphql-request": "^6.1.0", "isomorphic-ws": "^5.0.0", "openai": "^6.16.0", "socket.io-client": "^4.8.1", "vscode-jsonrpc": "^8.2.1", "zod": "^3.25.76" }, "peerDependencies": { "@ai-sdk/provider": ">=3.0.0", "@ai-sdk/provider-utils": ">=4.0.0" } }, "sha512-jUxYnKA4XQaPc3wxACDZ8bPDXO0Mzx7cZaBDxbT2uGgLqtGZmSi+9tVNIg7louSS+s/ioVra3SoUz3iOFVhKPA=="],
"glob": ["glob@13.0.5", "", { "dependencies": { "minimatch": "^10.2.1", "minipass": "^7.1.2", "path-scurry": "^2.0.0" } }, "sha512-BzXxZg24Ibra1pbQ/zE7Kys4Ua1ks7Bn6pKLkVPZ9FZe4JQS6/Q7ef3LG1H+k7lUf5l4T3PLSyYyYJVYUvfgTw=="], "glob": ["glob@13.0.5", "", { "dependencies": { "minimatch": "^10.2.1", "minipass": "^7.1.2", "path-scurry": "^2.0.0" } }, "sha512-BzXxZg24Ibra1pbQ/zE7Kys4Ua1ks7Bn6pKLkVPZ9FZe4JQS6/Q7ef3LG1H+k7lUf5l4T3PLSyYyYJVYUvfgTw=="],
@@ -4069,6 +4129,10 @@
"oxc-transform": ["oxc-transform@0.96.0", "", { "optionalDependencies": { "@oxc-transform/binding-android-arm64": "0.96.0", "@oxc-transform/binding-darwin-arm64": "0.96.0", "@oxc-transform/binding-darwin-x64": "0.96.0", "@oxc-transform/binding-freebsd-x64": "0.96.0", "@oxc-transform/binding-linux-arm-gnueabihf": "0.96.0", "@oxc-transform/binding-linux-arm-musleabihf": "0.96.0", "@oxc-transform/binding-linux-arm64-gnu": "0.96.0", "@oxc-transform/binding-linux-arm64-musl": "0.96.0", "@oxc-transform/binding-linux-riscv64-gnu": "0.96.0", "@oxc-transform/binding-linux-s390x-gnu": "0.96.0", "@oxc-transform/binding-linux-x64-gnu": "0.96.0", "@oxc-transform/binding-linux-x64-musl": "0.96.0", "@oxc-transform/binding-wasm32-wasi": "0.96.0", "@oxc-transform/binding-win32-arm64-msvc": "0.96.0", "@oxc-transform/binding-win32-x64-msvc": "0.96.0" } }, "sha512-dQPNIF+gHpSkmC0+Vg9IktNyhcn28Y8R3eTLyzn52UNymkasLicl3sFAtz7oEVuFmCpgGjaUTKkwk+jW2cHpDQ=="], "oxc-transform": ["oxc-transform@0.96.0", "", { "optionalDependencies": { "@oxc-transform/binding-android-arm64": "0.96.0", "@oxc-transform/binding-darwin-arm64": "0.96.0", "@oxc-transform/binding-darwin-x64": "0.96.0", "@oxc-transform/binding-freebsd-x64": "0.96.0", "@oxc-transform/binding-linux-arm-gnueabihf": "0.96.0", "@oxc-transform/binding-linux-arm-musleabihf": "0.96.0", "@oxc-transform/binding-linux-arm64-gnu": "0.96.0", "@oxc-transform/binding-linux-arm64-musl": "0.96.0", "@oxc-transform/binding-linux-riscv64-gnu": "0.96.0", "@oxc-transform/binding-linux-s390x-gnu": "0.96.0", "@oxc-transform/binding-linux-x64-gnu": "0.96.0", "@oxc-transform/binding-linux-x64-musl": "0.96.0", "@oxc-transform/binding-wasm32-wasi": "0.96.0", "@oxc-transform/binding-win32-arm64-msvc": "0.96.0", "@oxc-transform/binding-win32-x64-msvc": "0.96.0" } }, "sha512-dQPNIF+gHpSkmC0+Vg9IktNyhcn28Y8R3eTLyzn52UNymkasLicl3sFAtz7oEVuFmCpgGjaUTKkwk+jW2cHpDQ=="],
"oxlint": ["oxlint@1.60.0", "", { "optionalDependencies": { "@oxlint/binding-android-arm-eabi": "1.60.0", "@oxlint/binding-android-arm64": "1.60.0", "@oxlint/binding-darwin-arm64": "1.60.0", "@oxlint/binding-darwin-x64": "1.60.0", "@oxlint/binding-freebsd-x64": "1.60.0", "@oxlint/binding-linux-arm-gnueabihf": "1.60.0", "@oxlint/binding-linux-arm-musleabihf": "1.60.0", "@oxlint/binding-linux-arm64-gnu": "1.60.0", "@oxlint/binding-linux-arm64-musl": "1.60.0", "@oxlint/binding-linux-ppc64-gnu": "1.60.0", "@oxlint/binding-linux-riscv64-gnu": "1.60.0", "@oxlint/binding-linux-riscv64-musl": "1.60.0", "@oxlint/binding-linux-s390x-gnu": "1.60.0", "@oxlint/binding-linux-x64-gnu": "1.60.0", "@oxlint/binding-linux-x64-musl": "1.60.0", "@oxlint/binding-openharmony-arm64": "1.60.0", "@oxlint/binding-win32-arm64-msvc": "1.60.0", "@oxlint/binding-win32-ia32-msvc": "1.60.0", "@oxlint/binding-win32-x64-msvc": "1.60.0" }, "peerDependencies": { "oxlint-tsgolint": ">=0.18.0" }, "optionalPeers": ["oxlint-tsgolint"], "bin": { "oxlint": "bin/oxlint" } }, "sha512-tnRzTWiWJ9pg3ftRWnD0+Oqh78L6ZSwcEudvCZaER0PIqiAnNyXj5N1dPwjmNpDalkKS9m/WMLN1CTPUBPmsgw=="],
"oxlint-tsgolint": ["oxlint-tsgolint@0.21.0", "", { "optionalDependencies": { "@oxlint-tsgolint/darwin-arm64": "0.21.0", "@oxlint-tsgolint/darwin-x64": "0.21.0", "@oxlint-tsgolint/linux-arm64": "0.21.0", "@oxlint-tsgolint/linux-x64": "0.21.0", "@oxlint-tsgolint/win32-arm64": "0.21.0", "@oxlint-tsgolint/win32-x64": "0.21.0" }, "bin": { "tsgolint": "bin/tsgolint.js" } }, "sha512-HiWPhANwRnN1pZJQ2SgNB3WRR+1etLJHmRzQ/MJhyINsEIaOUCjxhlXJKbEaVUwdnyXwRWqo/P9Fx21lz0/mSg=="],
"p-cancelable": ["p-cancelable@2.1.1", "", {}, "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg=="], "p-cancelable": ["p-cancelable@2.1.1", "", {}, "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg=="],
"p-defer": ["p-defer@3.0.0", "", {}, "sha512-ugZxsxmtTln604yeYd29EGrNhazN2lywetzpKhfmQjW/VJmhpDmWbiX+h0zL8V91R0UXkhb3KtPmyq9PZw3aYw=="], "p-defer": ["p-defer@3.0.0", "", {}, "sha512-ugZxsxmtTln604yeYd29EGrNhazN2lywetzpKhfmQjW/VJmhpDmWbiX+h0zL8V91R0UXkhb3KtPmyq9PZw3aYw=="],
@@ -4431,8 +4495,6 @@
"rimraf": ["rimraf@2.6.3", "", { "dependencies": { "glob": "^7.1.3" }, "bin": { "rimraf": "./bin.js" } }, "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA=="], "rimraf": ["rimraf@2.6.3", "", { "dependencies": { "glob": "^7.1.3" }, "bin": { "rimraf": "./bin.js" } }, "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA=="],
"ripgrep": ["ripgrep@0.3.1", "", { "bin": { "rg": "lib/rg.mjs", "ripgrep": "lib/rg.mjs" } }, "sha512-6bDtNIBh1qPviVIU685/4uv0Ap5t8eS4wiJhy/tR2LdIeIey9CVasENlGS+ul3HnTmGANIp7AjnfsztsRmALfQ=="],
"roarr": ["roarr@2.15.4", "", { "dependencies": { "boolean": "^3.0.1", "detect-node": "^2.0.4", "globalthis": "^1.0.1", "json-stringify-safe": "^5.0.1", "semver-compare": "^1.0.0", "sprintf-js": "^1.1.2" } }, "sha512-CHhPh+UNHD2GTXNYhPWLnU8ONHdI+5DI+4EYIAOaiD63rHeYlZvyh8P+in5999TTSFgUYuKUAjzRI4mdh/p+2A=="], "roarr": ["roarr@2.15.4", "", { "dependencies": { "boolean": "^3.0.1", "detect-node": "^2.0.4", "globalthis": "^1.0.1", "json-stringify-safe": "^5.0.1", "semver-compare": "^1.0.0", "sprintf-js": "^1.1.2" } }, "sha512-CHhPh+UNHD2GTXNYhPWLnU8ONHdI+5DI+4EYIAOaiD63rHeYlZvyh8P+in5999TTSFgUYuKUAjzRI4mdh/p+2A=="],
"rollup": ["rollup@4.60.1", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.60.1", "@rollup/rollup-android-arm64": "4.60.1", "@rollup/rollup-darwin-arm64": "4.60.1", "@rollup/rollup-darwin-x64": "4.60.1", "@rollup/rollup-freebsd-arm64": "4.60.1", "@rollup/rollup-freebsd-x64": "4.60.1", "@rollup/rollup-linux-arm-gnueabihf": "4.60.1", "@rollup/rollup-linux-arm-musleabihf": "4.60.1", "@rollup/rollup-linux-arm64-gnu": "4.60.1", "@rollup/rollup-linux-arm64-musl": "4.60.1", "@rollup/rollup-linux-loong64-gnu": "4.60.1", "@rollup/rollup-linux-loong64-musl": "4.60.1", "@rollup/rollup-linux-ppc64-gnu": "4.60.1", "@rollup/rollup-linux-ppc64-musl": "4.60.1", "@rollup/rollup-linux-riscv64-gnu": "4.60.1", "@rollup/rollup-linux-riscv64-musl": "4.60.1", "@rollup/rollup-linux-s390x-gnu": "4.60.1", "@rollup/rollup-linux-x64-gnu": "4.60.1", "@rollup/rollup-linux-x64-musl": "4.60.1", "@rollup/rollup-openbsd-x64": "4.60.1", "@rollup/rollup-openharmony-arm64": "4.60.1", "@rollup/rollup-win32-arm64-msvc": "4.60.1", "@rollup/rollup-win32-ia32-msvc": "4.60.1", "@rollup/rollup-win32-x64-gnu": "4.60.1", "@rollup/rollup-win32-x64-msvc": "4.60.1", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-VmtB2rFU/GroZ4oL8+ZqXgSA38O6GR8KSIvWmEFv63pQ0G6KaBH9s07PO8XTXP4vI+3UJUEypOfjkGfmSBBR0w=="], "rollup": ["rollup@4.60.1", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.60.1", "@rollup/rollup-android-arm64": "4.60.1", "@rollup/rollup-darwin-arm64": "4.60.1", "@rollup/rollup-darwin-x64": "4.60.1", "@rollup/rollup-freebsd-arm64": "4.60.1", "@rollup/rollup-freebsd-x64": "4.60.1", "@rollup/rollup-linux-arm-gnueabihf": "4.60.1", "@rollup/rollup-linux-arm-musleabihf": "4.60.1", "@rollup/rollup-linux-arm64-gnu": "4.60.1", "@rollup/rollup-linux-arm64-musl": "4.60.1", "@rollup/rollup-linux-loong64-gnu": "4.60.1", "@rollup/rollup-linux-loong64-musl": "4.60.1", "@rollup/rollup-linux-ppc64-gnu": "4.60.1", "@rollup/rollup-linux-ppc64-musl": "4.60.1", "@rollup/rollup-linux-riscv64-gnu": "4.60.1", "@rollup/rollup-linux-riscv64-musl": "4.60.1", "@rollup/rollup-linux-s390x-gnu": "4.60.1", "@rollup/rollup-linux-x64-gnu": "4.60.1", "@rollup/rollup-linux-x64-musl": "4.60.1", "@rollup/rollup-openbsd-x64": "4.60.1", "@rollup/rollup-openharmony-arm64": "4.60.1", "@rollup/rollup-win32-arm64-msvc": "4.60.1", "@rollup/rollup-win32-ia32-msvc": "4.60.1", "@rollup/rollup-win32-x64-gnu": "4.60.1", "@rollup/rollup-win32-x64-msvc": "4.60.1", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-VmtB2rFU/GroZ4oL8+ZqXgSA38O6GR8KSIvWmEFv63pQ0G6KaBH9s07PO8XTXP4vI+3UJUEypOfjkGfmSBBR0w=="],
@@ -5103,7 +5165,11 @@
"@ai-sdk/alibaba/@ai-sdk/openai-compatible": ["@ai-sdk/openai-compatible@2.0.41", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-kNAGINk71AlOXx10Dq/PXw4t/9XjdK8uxfpVElRwtSFMdeSiLVt58p9TPx4/FJD+hxZuVhvxYj9r42osxWq79g=="], "@ai-sdk/alibaba/@ai-sdk/openai-compatible": ["@ai-sdk/openai-compatible@2.0.41", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-kNAGINk71AlOXx10Dq/PXw4t/9XjdK8uxfpVElRwtSFMdeSiLVt58p9TPx4/FJD+hxZuVhvxYj9r42osxWq79g=="],
"@ai-sdk/amazon-bedrock/@ai-sdk/anthropic": ["@ai-sdk/anthropic@3.0.69", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-LshR7X3pFugY0o41G2VKTmg1XoGpSl7uoYWfzk6zjVZLhCfeFiwgpOga+eTV4XY1VVpZwKVqRnkDbIL7K2eH5g=="], "@ai-sdk/amazon-bedrock/@ai-sdk/anthropic": ["@ai-sdk/anthropic@3.0.71", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-bUWOzrzR0gJKJO/PLGMR4uH2dqEgqGhrsCV+sSpk4KtOEnUQlfjZI/F7BFlqSvVpFbjdgYRRLysAeEZpJ6S1lg=="],
"@ai-sdk/amazon-bedrock/@smithy/eventstream-codec": ["@smithy/eventstream-codec@4.2.13", "", { "dependencies": { "@aws-crypto/crc32": "5.2.0", "@smithy/types": "^4.14.0", "@smithy/util-hex-encoding": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-vYahwBAtRaAcFbOmE9aLr12z7RiHYDSLcnogSdxfm7kKfsNa3wH+NU5r7vTeB5rKvLsWyPjVX8iH94brP7umiQ=="],
"@ai-sdk/amazon-bedrock/@smithy/util-utf8": ["@smithy/util-utf8@4.2.2", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-75MeYpjdWRe8M5E3AW0O4Cx3UadweS+cwdXjwYGBW5h/gxxnbeZ877sLPX/ZJA9GVTlL/qG0dXP29JWFCD1Ayw=="],
"@ai-sdk/anthropic/@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@4.0.21", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@standard-schema/spec": "^1.1.0", "eventsource-parser": "^3.0.6" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-MtFUYI1/8mgDvRmaBDjbLJPFFrMG777AvSgyIFQtZHIMzm88R/12vYBBpnk7pfiWLFE1DSZzY4WDYzGbKAcmiw=="], "@ai-sdk/anthropic/@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@4.0.21", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@standard-schema/spec": "^1.1.0", "eventsource-parser": "^3.0.6" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-MtFUYI1/8mgDvRmaBDjbLJPFFrMG777AvSgyIFQtZHIMzm88R/12vYBBpnk7pfiWLFE1DSZzY4WDYzGbKAcmiw=="],
@@ -5117,7 +5183,9 @@
"@ai-sdk/fireworks/@ai-sdk/openai-compatible": ["@ai-sdk/openai-compatible@2.0.41", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-kNAGINk71AlOXx10Dq/PXw4t/9XjdK8uxfpVElRwtSFMdeSiLVt58p9TPx4/FJD+hxZuVhvxYj9r42osxWq79g=="], "@ai-sdk/fireworks/@ai-sdk/openai-compatible": ["@ai-sdk/openai-compatible@2.0.41", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-kNAGINk71AlOXx10Dq/PXw4t/9XjdK8uxfpVElRwtSFMdeSiLVt58p9TPx4/FJD+hxZuVhvxYj9r42osxWq79g=="],
"@ai-sdk/google-vertex/@ai-sdk/anthropic": ["@ai-sdk/anthropic@3.0.69", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-LshR7X3pFugY0o41G2VKTmg1XoGpSl7uoYWfzk6zjVZLhCfeFiwgpOga+eTV4XY1VVpZwKVqRnkDbIL7K2eH5g=="], "@ai-sdk/google-vertex/@ai-sdk/anthropic": ["@ai-sdk/anthropic@3.0.71", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-bUWOzrzR0gJKJO/PLGMR4uH2dqEgqGhrsCV+sSpk4KtOEnUQlfjZI/F7BFlqSvVpFbjdgYRRLysAeEZpJ6S1lg=="],
"@ai-sdk/google-vertex/@ai-sdk/google": ["@ai-sdk/google@3.0.64", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-CbR82EgGPNrj/6q0HtclwuCqe0/pDShyv3nWDP/A9DroujzWXnLMlUJVrgPOsg4b40zQCwwVs2XSKCxvt/4QaA=="],
"@ai-sdk/google-vertex/@ai-sdk/openai-compatible": ["@ai-sdk/openai-compatible@2.0.41", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-kNAGINk71AlOXx10Dq/PXw4t/9XjdK8uxfpVElRwtSFMdeSiLVt58p9TPx4/FJD+hxZuVhvxYj9r42osxWq79g=="], "@ai-sdk/google-vertex/@ai-sdk/openai-compatible": ["@ai-sdk/openai-compatible@2.0.41", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-kNAGINk71AlOXx10Dq/PXw4t/9XjdK8uxfpVElRwtSFMdeSiLVt58p9TPx4/FJD+hxZuVhvxYj9r42osxWq79g=="],
@@ -5527,6 +5595,18 @@
"@opencode-ai/web/@shikijs/transformers": ["@shikijs/transformers@3.20.0", "", { "dependencies": { "@shikijs/core": "3.20.0", "@shikijs/types": "3.20.0" } }, "sha512-PrHHMRr3Q5W1qB/42kJW6laqFyWdhrPF2hNR9qjOm1xcSiAO3hAHo7HaVyHE6pMyevmy3i51O8kuGGXC78uK3g=="], "@opencode-ai/web/@shikijs/transformers": ["@shikijs/transformers@3.20.0", "", { "dependencies": { "@shikijs/core": "3.20.0", "@shikijs/types": "3.20.0" } }, "sha512-PrHHMRr3Q5W1qB/42kJW6laqFyWdhrPF2hNR9qjOm1xcSiAO3hAHo7HaVyHE6pMyevmy3i51O8kuGGXC78uK3g=="],
"@opentelemetry/exporter-trace-otlp-http/@opentelemetry/resources": ["@opentelemetry/resources@2.6.1", "", { "dependencies": { "@opentelemetry/core": "2.6.1", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-lID/vxSuKWXM55XhAKNoYXu9Cutoq5hFdkbTdI/zDKQktXzcWBVhNsOkiZFTMU9UtEWuGRNe0HUgmsFldIdxVA=="],
"@opentelemetry/otlp-transformer/@opentelemetry/resources": ["@opentelemetry/resources@2.6.1", "", { "dependencies": { "@opentelemetry/core": "2.6.1", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-lID/vxSuKWXM55XhAKNoYXu9Cutoq5hFdkbTdI/zDKQktXzcWBVhNsOkiZFTMU9UtEWuGRNe0HUgmsFldIdxVA=="],
"@opentelemetry/resources/@opentelemetry/core": ["@opentelemetry/core@2.2.0", "", { "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-FuabnnUm8LflnieVxs6eP7Z383hgQU4W1e3KJS6aOG3RxWxcHyBxH8fDMHNgu/gFx/M2jvTOW/4/PHhLz6bjWw=="],
"@opentelemetry/sdk-logs/@opentelemetry/resources": ["@opentelemetry/resources@2.6.1", "", { "dependencies": { "@opentelemetry/core": "2.6.1", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-lID/vxSuKWXM55XhAKNoYXu9Cutoq5hFdkbTdI/zDKQktXzcWBVhNsOkiZFTMU9UtEWuGRNe0HUgmsFldIdxVA=="],
"@opentelemetry/sdk-metrics/@opentelemetry/resources": ["@opentelemetry/resources@2.6.1", "", { "dependencies": { "@opentelemetry/core": "2.6.1", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-lID/vxSuKWXM55XhAKNoYXu9Cutoq5hFdkbTdI/zDKQktXzcWBVhNsOkiZFTMU9UtEWuGRNe0HUgmsFldIdxVA=="],
"@opentelemetry/sdk-trace-base/@opentelemetry/resources": ["@opentelemetry/resources@2.6.1", "", { "dependencies": { "@opentelemetry/core": "2.6.1", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-lID/vxSuKWXM55XhAKNoYXu9Cutoq5hFdkbTdI/zDKQktXzcWBVhNsOkiZFTMU9UtEWuGRNe0HUgmsFldIdxVA=="],
"@opentui/solid/@babel/core": ["@babel/core@7.28.0", "", { "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.0", "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-module-transforms": "^7.27.3", "@babel/helpers": "^7.27.6", "@babel/parser": "^7.28.0", "@babel/template": "^7.27.2", "@babel/traverse": "^7.28.0", "@babel/types": "^7.28.0", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.3", "semver": "^6.3.1" } }, "sha512-UlLAnTPrFdNGoFtbSXwcGFQBtQZJCNjaN6hQNP3UPvuNXT1i82N26KL3dZeIpNalWywr9IuQuncaAfUaS1g6sQ=="], "@opentui/solid/@babel/core": ["@babel/core@7.28.0", "", { "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.0", "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-module-transforms": "^7.27.3", "@babel/helpers": "^7.27.6", "@babel/parser": "^7.28.0", "@babel/template": "^7.27.2", "@babel/traverse": "^7.28.0", "@babel/types": "^7.28.0", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.3", "semver": "^6.3.1" } }, "sha512-UlLAnTPrFdNGoFtbSXwcGFQBtQZJCNjaN6hQNP3UPvuNXT1i82N26KL3dZeIpNalWywr9IuQuncaAfUaS1g6sQ=="],
"@opentui/solid/babel-preset-solid": ["babel-preset-solid@1.9.10", "", { "dependencies": { "babel-plugin-jsx-dom-expressions": "^0.40.3" }, "peerDependencies": { "@babel/core": "^7.0.0", "solid-js": "^1.9.10" }, "optionalPeers": ["solid-js"] }, "sha512-HCelrgua/Y+kqO8RyL04JBWS/cVdrtUv/h45GntgQY+cJl4eBcKkCDV3TdMjtKx1nXwRaR9QXslM/Npm1dxdZQ=="], "@opentui/solid/babel-preset-solid": ["babel-preset-solid@1.9.10", "", { "dependencies": { "babel-plugin-jsx-dom-expressions": "^0.40.3" }, "peerDependencies": { "@babel/core": "^7.0.0", "solid-js": "^1.9.10" }, "optionalPeers": ["solid-js"] }, "sha512-HCelrgua/Y+kqO8RyL04JBWS/cVdrtUv/h45GntgQY+cJl4eBcKkCDV3TdMjtKx1nXwRaR9QXslM/Npm1dxdZQ=="],
@@ -5633,7 +5713,7 @@
"accepts/negotiator": ["negotiator@0.6.3", "", {}, "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg=="], "accepts/negotiator": ["negotiator@0.6.3", "", {}, "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg=="],
"ai/@ai-sdk/gateway": ["@ai-sdk/gateway@3.0.95", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23", "@vercel/oidc": "3.1.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-ZmUNNbZl3V42xwQzPaNUi+s8eqR2lnrxf0bvB6YbLXpLjHYv0k2Y78t12cNOfY0bxGeuVVTLyk856uLuQIuXEQ=="], "ai-gateway-provider/@ai-sdk/amazon-bedrock": ["@ai-sdk/amazon-bedrock@4.0.93", "", { "dependencies": { "@ai-sdk/anthropic": "3.0.69", "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23", "@smithy/eventstream-codec": "^4.0.1", "@smithy/util-utf8": "^4.0.0", "aws4fetch": "^1.0.20" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-hcXDU8QDwpAzLVTuY932TQVlIij9+iaVTxc5mPGY6yb//JMAAC5hMVhg93IrxlrxWLvMgjezNgoZGwquR+SGnw=="],
"ai-gateway-provider/@ai-sdk/anthropic": ["@ai-sdk/anthropic@3.0.69", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-LshR7X3pFugY0o41G2VKTmg1XoGpSl7uoYWfzk6zjVZLhCfeFiwgpOga+eTV4XY1VVpZwKVqRnkDbIL7K2eH5g=="], "ai-gateway-provider/@ai-sdk/anthropic": ["@ai-sdk/anthropic@3.0.69", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-LshR7X3pFugY0o41G2VKTmg1XoGpSl7uoYWfzk6zjVZLhCfeFiwgpOga+eTV4XY1VVpZwKVqRnkDbIL7K2eH5g=="],
@@ -5851,7 +5931,7 @@
"nypm/tinyexec": ["tinyexec@1.1.1", "", {}, "sha512-VKS/ZaQhhkKFMANmAOhhXVoIfBXblQxGX1myCQ2faQrfmobMftXeJPcZGp0gS07ocvGJWDLZGyOZDadDBqYIJg=="], "nypm/tinyexec": ["tinyexec@1.1.1", "", {}, "sha512-VKS/ZaQhhkKFMANmAOhhXVoIfBXblQxGX1myCQ2faQrfmobMftXeJPcZGp0gS07ocvGJWDLZGyOZDadDBqYIJg=="],
"opencode/@ai-sdk/anthropic": ["@ai-sdk/anthropic@3.0.67", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-FFX4P5Fd6lcQJc2OLngZQkbbJHa0IDDZi087Edb8qRZx6h90krtM61ArbMUL8us/7ZUwojCXnyJ/wQ2Eflx2jQ=="], "opencode/@ai-sdk/anthropic": ["@ai-sdk/anthropic@3.0.71", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-bUWOzrzR0gJKJO/PLGMR4uH2dqEgqGhrsCV+sSpk4KtOEnUQlfjZI/F7BFlqSvVpFbjdgYRRLysAeEZpJ6S1lg=="],
"opencode/@ai-sdk/openai": ["@ai-sdk/openai@3.0.53", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-Wld+Rbc05KaUn08uBt06eEuwcgalcIFtIl32Yp+GxuZXUQwOb6YeAuq+C6da4ch6BurFoqEaLemJVwjBb7x+PQ=="], "opencode/@ai-sdk/openai": ["@ai-sdk/openai@3.0.53", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-Wld+Rbc05KaUn08uBt06eEuwcgalcIFtIl32Yp+GxuZXUQwOb6YeAuq+C6da4ch6BurFoqEaLemJVwjBb7x+PQ=="],
Generated
+3 -3
View File
@@ -2,11 +2,11 @@
"nodes": { "nodes": {
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1773909469, "lastModified": 1776683584,
"narHash": "sha256-vglVrLfHjFIzIdV9A27Ugul6rh3I1qHbbitGW7dk420=", "narHash": "sha256-NuTLMrr10Tng72hurYG8jYQ4XKK8wnpJmOGcPiis96g=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "7149c06513f335be57f26fcbbbe34afda923882b", "rev": "9dd5558b06dbdacbf635a3dd36dce1b1a7ee3a89",
"type": "github" "type": "github"
}, },
"original": { "original": {
+6 -6
View File
@@ -281,7 +281,7 @@ async function assertOpencodeConnected() {
}) })
connected = true connected = true
break break
} catch (e) {} } catch {}
await sleep(300) await sleep(300)
} while (retry++ < 30) } while (retry++ < 30)
@@ -513,7 +513,7 @@ async function subscribeSessionEvents() {
const decoder = new TextDecoder() const decoder = new TextDecoder()
let text = "" let text = ""
;(async () => { void (async () => {
while (true) { while (true) {
try { try {
const { done, value } = await reader.read() const { done, value } = await reader.read()
@@ -542,7 +542,7 @@ async function subscribeSessionEvents() {
? JSON.stringify(part.state.input) ? JSON.stringify(part.state.input)
: "Unknown" : "Unknown"
console.log() console.log()
console.log(color + `|`, "\x1b[0m\x1b[2m" + ` ${tool.padEnd(7, " ")}`, "", "\x1b[0m" + title) console.log(`${color}|`, `\x1b[0m\x1b[2m ${tool.padEnd(7, " ")}`, "", `\x1b[0m${title}`)
} }
if (part.type === "text") { if (part.type === "text") {
@@ -561,7 +561,7 @@ async function subscribeSessionEvents() {
if (evt.properties.info.id !== session.id) continue if (evt.properties.info.id !== session.id) continue
session = evt.properties.info session = evt.properties.info
} }
} catch (e) { } catch {
// Ignore parse errors // Ignore parse errors
} }
} }
@@ -576,7 +576,7 @@ async function subscribeSessionEvents() {
async function summarize(response: string) { async function summarize(response: string) {
try { try {
return await chat(`Summarize the following in less than 40 characters:\n\n${response}`) return await chat(`Summarize the following in less than 40 characters:\n\n${response}`)
} catch (e) { } catch {
if (isScheduleEvent()) { if (isScheduleEvent()) {
return "Scheduled task changes" return "Scheduled task changes"
} }
@@ -776,7 +776,7 @@ async function assertPermissions() {
console.log(` permission: ${permission}`) console.log(` permission: ${permission}`)
} catch (error) { } catch (error) {
console.error(`Failed to check permissions: ${error}`) console.error(`Failed to check permissions: ${error}`)
throw new Error(`Failed to check permissions for user ${actor}: ${error}`) throw new Error(`Failed to check permissions for user ${actor}: ${error}`, { cause: error })
} }
if (!["admin", "write"].includes(permission)) throw new Error(`User ${actor} does not have write permissions`) if (!["admin", "write"].includes(permission)) throw new Error(`User ${actor} does not have write permissions`)
-1
View File
@@ -236,7 +236,6 @@ new sst.cloudflare.x.SolidStart("Console", {
SALESFORCE_INSTANCE_URL, SALESFORCE_INSTANCE_URL,
ZEN_BLACK_PRICE, ZEN_BLACK_PRICE,
ZEN_LITE_PRICE, ZEN_LITE_PRICE,
new sst.Secret("ZEN_LITE_COUPON_FIRST_MONTH_100_INVITEES"),
new sst.Secret("ZEN_LIMITS"), new sst.Secret("ZEN_LIMITS"),
new sst.Secret("ZEN_SESSION_SECRET"), new sst.Secret("ZEN_SESSION_SECRET"),
...ZEN_MODELS, ...ZEN_MODELS,
+2 -2
View File
@@ -1,9 +1,9 @@
import { SECRET } from "./secret" import { SECRET } from "./secret"
import { domain, shortDomain } from "./stage" import { shortDomain } from "./stage"
const storage = new sst.cloudflare.Bucket("EnterpriseStorage") const storage = new sst.cloudflare.Bucket("EnterpriseStorage")
const teams = new sst.cloudflare.x.SolidStart("Teams", { new sst.cloudflare.x.SolidStart("Teams", {
domain: shortDomain, domain: shortDomain,
path: "packages/enterprise", path: "packages/enterprise",
buildCommand: "bun run build:cloudflare", buildCommand: "bun run build:cloudflare",
+4 -4
View File
@@ -1,8 +1,8 @@
{ {
"nodeModules": { "nodeModules": {
"x86_64-linux": "sha256-3kpnjBg7AQanyDGTOFdYBFvo9O9Rfnu0Wmi8bY5LpEI=", "x86_64-linux": "sha256-LpzWEZzURUEj7fcHGvh33gM7D9GNPE+XIvU0/hmdcQM=",
"aarch64-linux": "sha256-8rQ+SNUiSpA2Ea3NrYNGopHQsnY7Y8qBsXCqL6GMt24=", "aarch64-linux": "sha256-0zdO3zuj6g9cMZFEOsvQJcKKcPjGVZJ2DkJdDcb2VCM=",
"aarch64-darwin": "sha256-OASMkW5hnXucV6lSmxrQo73lGSEKN4MQPNGNV0i7jdo=", "aarch64-darwin": "sha256-dmT8R9Pmzh5tjO8NCCCtENiQpJQeifQpVdhaty1MXOs=",
"x86_64-darwin": "sha256-CmHqXlm8wnLcwSSK0ghxAf+DVurEltMaxrUbWh9/ZGE=" "x86_64-darwin": "sha256-Q6rAQRoC6WaMAQl++YHAZmbNuO303cWgGaYzXaRlzy4="
} }
} }
+1
View File
@@ -55,6 +55,7 @@ stdenvNoCC.mkDerivation {
--filter './packages/opencode' \ --filter './packages/opencode' \
--filter './packages/desktop' \ --filter './packages/desktop' \
--filter './packages/app' \ --filter './packages/app' \
--filter './packages/shared' \
--frozen-lockfile \ --frozen-lockfile \
--ignore-scripts \ --ignore-scripts \
--no-progress --no-progress
+10 -9
View File
@@ -7,6 +7,7 @@
sysctl, sysctl,
makeBinaryWrapper, makeBinaryWrapper,
models-dev, models-dev,
ripgrep,
installShellFiles, installShellFiles,
versionCheckHook, versionCheckHook,
writableTmpDirAsHomeHook, writableTmpDirAsHomeHook,
@@ -51,23 +52,23 @@ stdenvNoCC.mkDerivation (finalAttrs: {
runHook postBuild runHook postBuild
''; '';
installPhase = installPhase = ''
''
runHook preInstall runHook preInstall
install -Dm755 dist/opencode-*/bin/opencode $out/bin/opencode install -Dm755 dist/opencode-*/bin/opencode $out/bin/opencode
install -Dm644 schema.json $out/share/opencode/schema.json install -Dm644 schema.json $out/share/opencode/schema.json
''
# bun runs sysctl to detect if dunning on rosetta2
+ lib.optionalString stdenvNoCC.hostPlatform.isDarwin ''
wrapProgram $out/bin/opencode \ wrapProgram $out/bin/opencode \
--prefix PATH : ${ --prefix PATH : ${
lib.makeBinPath [ lib.makeBinPath (
sysctl [
ripgrep
] ]
# bun runs sysctl to detect if dunning on rosetta2
++ lib.optional stdenvNoCC.hostPlatform.isDarwin sysctl
)
} }
''
+ ''
runHook postInstall runHook postInstall
''; '';
+11 -4
View File
@@ -4,13 +4,14 @@
"description": "AI-powered development tool", "description": "AI-powered development tool",
"private": true, "private": true,
"type": "module", "type": "module",
"packageManager": "bun@1.3.11", "packageManager": "bun@1.3.13",
"scripts": { "scripts": {
"dev": "bun run --cwd packages/opencode --conditions=browser src/index.ts", "dev": "bun run --cwd packages/opencode --conditions=browser src/index.ts",
"dev:desktop": "bun --cwd packages/desktop tauri dev", "dev:desktop": "bun --cwd packages/desktop-electron dev",
"dev:web": "bun --cwd packages/app dev", "dev:web": "bun --cwd packages/app dev",
"dev:console": "ulimit -n 10240 2>/dev/null; bun run --cwd packages/console/app dev", "dev:console": "ulimit -n 10240 2>/dev/null; bun run --cwd packages/console/app dev",
"dev:storybook": "bun --cwd packages/storybook storybook", "dev:storybook": "bun --cwd packages/storybook storybook",
"lint": "oxlint",
"typecheck": "bun turbo typecheck", "typecheck": "bun turbo typecheck",
"postinstall": "bun run --cwd packages/opencode fix-node-pty", "postinstall": "bun run --cwd packages/opencode fix-node-pty",
"prepare": "husky", "prepare": "husky",
@@ -29,10 +30,12 @@
"@effect/opentelemetry": "4.0.0-beta.48", "@effect/opentelemetry": "4.0.0-beta.48",
"@effect/platform-node": "4.0.0-beta.48", "@effect/platform-node": "4.0.0-beta.48",
"@npmcli/arborist": "9.4.0", "@npmcli/arborist": "9.4.0",
"@types/bun": "1.3.11", "@types/bun": "1.3.12",
"@types/cross-spawn": "6.0.6", "@types/cross-spawn": "6.0.6",
"@octokit/rest": "22.0.0", "@octokit/rest": "22.0.0",
"@hono/zod-validator": "0.4.2", "@hono/zod-validator": "0.4.2",
"@opentui/core": "0.1.103",
"@opentui/solid": "0.1.103",
"ulid": "3.0.1", "ulid": "3.0.1",
"@kobalte/core": "0.13.11", "@kobalte/core": "0.13.11",
"@types/luxon": "3.7.1", "@types/luxon": "3.7.1",
@@ -43,6 +46,7 @@
"@cloudflare/workers-types": "4.20251008.0", "@cloudflare/workers-types": "4.20251008.0",
"@openauthjs/openauth": "0.0.0-20250322224806", "@openauthjs/openauth": "0.0.0-20250322224806",
"@pierre/diffs": "1.1.0-beta.18", "@pierre/diffs": "1.1.0-beta.18",
"opentui-spinner": "0.0.6",
"@solid-primitives/storage": "4.3.3", "@solid-primitives/storage": "4.3.3",
"@tailwindcss/vite": "4.1.11", "@tailwindcss/vite": "4.1.11",
"diff": "8.0.2", "diff": "8.0.2",
@@ -50,7 +54,7 @@
"drizzle-kit": "1.0.0-beta.19-d95b7a4", "drizzle-kit": "1.0.0-beta.19-d95b7a4",
"drizzle-orm": "1.0.0-beta.19-d95b7a4", "drizzle-orm": "1.0.0-beta.19-d95b7a4",
"effect": "4.0.0-beta.48", "effect": "4.0.0-beta.48",
"ai": "6.0.158", "ai": "6.0.168",
"cross-spawn": "7.0.6", "cross-spawn": "7.0.6",
"hono": "4.10.7", "hono": "4.10.7",
"hono-openapi": "1.1.2", "hono-openapi": "1.1.2",
@@ -85,6 +89,8 @@
"@typescript/native-preview": "catalog:", "@typescript/native-preview": "catalog:",
"glob": "13.0.5", "glob": "13.0.5",
"husky": "9.1.7", "husky": "9.1.7",
"oxlint": "1.60.0",
"oxlint-tsgolint": "0.21.0",
"prettier": "3.6.2", "prettier": "3.6.2",
"semver": "^7.6.0", "semver": "^7.6.0",
"sst": "3.18.10", "sst": "3.18.10",
@@ -122,6 +128,7 @@
"@types/node": "catalog:" "@types/node": "catalog:"
}, },
"patchedDependencies": { "patchedDependencies": {
"@npmcli/agent@4.0.0": "patches/@npmcli%2Fagent@4.0.0.patch",
"@standard-community/standard-openapi@0.2.9": "patches/@standard-community%2Fstandard-openapi@0.2.9.patch", "@standard-community/standard-openapi@0.2.9": "patches/@standard-community%2Fstandard-openapi@0.2.9.patch",
"solid-js@1.9.10": "patches/solid-js@1.9.10.patch" "solid-js@1.9.10": "patches/solid-js@1.9.10.patch"
} }
+2 -2
View File
@@ -1,6 +1,6 @@
{ {
"name": "@opencode-ai/app", "name": "@opencode-ai/app",
"version": "1.4.6", "version": "1.14.25",
"description": "", "description": "",
"type": "module", "type": "module",
"exports": { "exports": {
@@ -42,7 +42,7 @@
"@kobalte/core": "catalog:", "@kobalte/core": "catalog:",
"@opencode-ai/sdk": "workspace:*", "@opencode-ai/sdk": "workspace:*",
"@opencode-ai/ui": "workspace:*", "@opencode-ai/ui": "workspace:*",
"@opencode-ai/shared": "workspace:*", "@opencode-ai/core": "workspace:*",
"@shikijs/transformers": "3.9.2", "@shikijs/transformers": "3.9.2",
"@solid-primitives/active-element": "2.1.3", "@solid-primitives/active-element": "2.1.3",
"@solid-primitives/audio": "1.4.2", "@solid-primitives/audio": "1.4.2",
+2 -2
View File
@@ -180,8 +180,8 @@ describe("SerializeAddon", () => {
await writeAndWait(term, input) await writeAndWait(term, input)
const origLine = term.buffer.active.getLine(0) const origLine = term.buffer.active.getLine(0)
const origFg = origLine!.getCell(0)!.getFgColor() const _origFg = origLine!.getCell(0)!.getFgColor()
const origBg = origLine!.getCell(0)!.getBgColor() const _origBg = origLine!.getCell(0)!.getBgColor()
expect(origLine!.getCell(0)!.isBold()).toBe(1) expect(origLine!.getCell(0)!.isBold()).toBe(1)
const serialized = addon.serialize({ range: { start: 0, end: 0 } }) const serialized = addon.serialize({ range: { start: 0, end: 0 } })
+2 -2
View File
@@ -258,8 +258,8 @@ class StringSerializeHandler extends BaseSerializeHandler {
} }
protected _beforeSerialize(rows: number, start: number, _end: number): void { protected _beforeSerialize(rows: number, start: number, _end: number): void {
this._allRows = new Array<string>(rows) this._allRows = Array.from<string>({ length: rows })
this._allRowSeparators = new Array<string>(rows) this._allRowSeparators = Array.from<string>({ length: rows })
this._rowIndex = 0 this._rowIndex = 0
this._currentRow = "" this._currentRow = ""
+19 -15
View File
@@ -10,7 +10,7 @@ import { ThemeProvider } from "@opencode-ai/ui/theme/context"
import { MetaProvider } from "@solidjs/meta" import { MetaProvider } from "@solidjs/meta"
import { type BaseRouterProps, Navigate, Route, Router } from "@solidjs/router" import { type BaseRouterProps, Navigate, Route, Router } from "@solidjs/router"
import { QueryClient, QueryClientProvider } from "@tanstack/solid-query" import { QueryClient, QueryClientProvider } from "@tanstack/solid-query"
import { type Duration, Effect } from "effect" import { Effect } from "effect"
import { import {
type Component, type Component,
createMemo, createMemo,
@@ -121,10 +121,10 @@ function SessionProviders(props: ParentProps) {
function RouterRoot(props: ParentProps<{ appChildren?: JSX.Element }>) { function RouterRoot(props: ParentProps<{ appChildren?: JSX.Element }>) {
return ( return (
<AppShellProviders> <AppShellProviders>
<Suspense fallback={<Loading />}> {/*<Suspense fallback={<Loading />}>*/}
{props.appChildren} {props.appChildren}
{props.children} {props.children}
</Suspense> {/*</Suspense>*/}
</AppShellProviders> </AppShellProviders>
) )
} }
@@ -141,13 +141,11 @@ export function AppBaseProviders(props: ParentProps<{ locale?: Locale }>) {
<LanguageProvider locale={props.locale}> <LanguageProvider locale={props.locale}>
<UiI18nBridge> <UiI18nBridge>
<ErrorBoundary fallback={(error) => <ErrorPage error={error} />}> <ErrorBoundary fallback={(error) => <ErrorPage error={error} />}>
<QueryProvider>
<DialogProvider> <DialogProvider>
<MarkedProvider> <MarkedProvider>
<FileComponentProvider component={File}>{props.children}</FileComponentProvider> <FileComponentProvider component={File}>{props.children}</FileComponentProvider>
</MarkedProvider> </MarkedProvider>
</DialogProvider> </DialogProvider>
</QueryProvider>
</ErrorBoundary> </ErrorBoundary>
</UiI18nBridge> </UiI18nBridge>
</LanguageProvider> </LanguageProvider>
@@ -156,11 +154,6 @@ export function AppBaseProviders(props: ParentProps<{ locale?: Locale }>) {
) )
} }
const effectMinDuration =
(duration: Duration.Input) =>
<A, E, R>(e: Effect.Effect<A, E, R>) =>
Effect.all([e, Effect.sleep(duration)], { concurrency: "unbounded" }).pipe(Effect.map((v) => v[0]))
function ConnectionGate(props: ParentProps<{ disableHealthCheck?: boolean }>) { function ConnectionGate(props: ParentProps<{ disableHealthCheck?: boolean }>) {
const server = useServer() const server = useServer()
const checkServerHealth = useCheckServerHealth() const checkServerHealth = useCheckServerHealth()
@@ -189,32 +182,41 @@ function ConnectionGate(props: ParentProps<{ disableHealthCheck?: boolean }>) {
) )
return ( return (
<Show <Suspense
when={checkMode() === "blocking" ? !startupHealthCheck.loading : startupHealthCheck.state !== "pending"}
fallback={ fallback={
<div class="h-dvh w-screen flex flex-col items-center justify-center bg-background-base"> <div class="h-dvh w-screen flex flex-col items-center justify-center bg-background-base">
<Splash class="w-16 h-20 opacity-50 animate-pulse" /> <Splash class="w-16 h-20 opacity-50 animate-pulse" />
</div> </div>
} }
> >
{/*<Show
when={checkMode() === "blocking" ? !startupHealthCheck.loading : startupHealthCheck.state !== "pending"}
fallback={
<div class="h-dvh w-screen flex flex-col items-center justify-center bg-background-base">
<Splash class="w-16 h-20 opacity-50 animate-pulse" />
</div>
}
>*/}
{checkMode() === "blocking" ? startupHealthCheck() : startupHealthCheck.latest}
<Show <Show
when={startupHealthCheck()} when={startupHealthCheck()}
fallback={ fallback={
<ConnectionError <ConnectionError
onRetry={() => { onRetry={() => {
if (checkMode() === "background") healthCheckActions.refetch() if (checkMode() === "background") void healthCheckActions.refetch()
}} }}
onServerSelected={(key) => { onServerSelected={(key) => {
setCheckMode("blocking") setCheckMode("blocking")
server.setActive(key) server.setActive(key)
healthCheckActions.refetch() void healthCheckActions.refetch()
}} }}
/> />
} }
> >
{props.children} {props.children}
</Show> </Show>
</Show> {/*</Show>*/}
</Suspense>
) )
} }
@@ -289,6 +291,7 @@ export function AppInterface(props: {
> >
<ConnectionGate disableHealthCheck={props.disableHealthCheck}> <ConnectionGate disableHealthCheck={props.disableHealthCheck}>
<ServerKey> <ServerKey>
<QueryProvider>
<GlobalSDKProvider> <GlobalSDKProvider>
<GlobalSyncProvider> <GlobalSyncProvider>
<Dynamic <Dynamic
@@ -303,6 +306,7 @@ export function AppInterface(props: {
</Dynamic> </Dynamic>
</GlobalSyncProvider> </GlobalSyncProvider>
</GlobalSDKProvider> </GlobalSDKProvider>
</QueryProvider>
</ServerKey> </ServerKey>
</ConnectionGate> </ConnectionGate>
</ServerProvider> </ServerProvider>
@@ -327,7 +327,7 @@ export function DialogConnectProvider(props: { provider: string }) {
if (loading()) return if (loading()) return
if (methods().length === 1) { if (methods().length === 1) {
auto = true auto = true
selectMethod(0) void selectMethod(0)
} }
}) })
@@ -373,7 +373,7 @@ export function DialogConnectProvider(props: { provider: string }) {
key={(m) => m?.label} key={(m) => m?.label}
onSelect={async (selected, index) => { onSelect={async (selected, index) => {
if (!selected) return if (!selected) return
selectMethod(index) void selectMethod(index)
}} }}
> >
{(i) => ( {(i) => (
@@ -9,9 +9,10 @@ import { createStore } from "solid-js/store"
import { useGlobalSDK } from "@/context/global-sdk" import { useGlobalSDK } from "@/context/global-sdk"
import { useGlobalSync } from "@/context/global-sync" import { useGlobalSync } from "@/context/global-sync"
import { type LocalProject, getAvatarColors } from "@/context/layout" import { type LocalProject, getAvatarColors } from "@/context/layout"
import { getFilename } from "@opencode-ai/shared/util/path" import { getFilename } from "@opencode-ai/core/util/path"
import { Avatar } from "@opencode-ai/ui/avatar" import { Avatar } from "@opencode-ai/ui/avatar"
import { useLanguage } from "@/context/language" import { useLanguage } from "@/context/language"
import { getProjectAvatarSource } from "@/pages/layout/sidebar-items"
const AVATAR_COLOR_KEYS = ["pink", "mint", "orange", "purple", "cyan", "lime"] as const const AVATAR_COLOR_KEYS = ["pink", "mint", "orange", "purple", "cyan", "lime"] as const
@@ -26,8 +27,8 @@ export function DialogEditProject(props: { project: LocalProject }) {
const [store, setStore] = createStore({ const [store, setStore] = createStore({
name: defaultName(), name: defaultName(),
color: props.project.icon?.color || "pink", color: props.project.icon?.color,
iconUrl: props.project.icon?.override || "", iconOverride: props.project.icon?.override,
startup: props.project.commands?.start ?? "", startup: props.project.commands?.start ?? "",
dragOver: false, dragOver: false,
iconHover: false, iconHover: false,
@@ -39,7 +40,7 @@ export function DialogEditProject(props: { project: LocalProject }) {
if (!file.type.startsWith("image/")) return if (!file.type.startsWith("image/")) return
const reader = new FileReader() const reader = new FileReader()
reader.onload = (e) => { reader.onload = (e) => {
setStore("iconUrl", e.target?.result as string) setStore("iconOverride", e.target?.result as string)
setStore("iconHover", false) setStore("iconHover", false)
} }
reader.readAsDataURL(file) reader.readAsDataURL(file)
@@ -68,7 +69,7 @@ export function DialogEditProject(props: { project: LocalProject }) {
} }
function clearIcon() { function clearIcon() {
setStore("iconUrl", "") setStore("iconOverride", "")
} }
const saveMutation = useMutation(() => ({ const saveMutation = useMutation(() => ({
@@ -81,17 +82,17 @@ export function DialogEditProject(props: { project: LocalProject }) {
projectID: props.project.id, projectID: props.project.id,
directory: props.project.worktree, directory: props.project.worktree,
name, name,
icon: { color: store.color, override: store.iconUrl }, icon: { color: store.color || "", override: store.iconOverride || "" },
commands: { start }, commands: { start },
}) })
globalSync.project.icon(props.project.worktree, store.iconUrl || undefined) globalSync.project.icon(props.project.worktree, store.iconOverride || undefined)
dialog.close() dialog.close()
return return
} }
globalSync.project.meta(props.project.worktree, { globalSync.project.meta(props.project.worktree, {
name, name,
icon: { color: store.color, override: store.iconUrl || undefined }, icon: { color: store.color || undefined, override: store.iconOverride || undefined },
commands: { start: start || undefined }, commands: { start: start || undefined },
}) })
dialog.close() dialog.close()
@@ -130,13 +131,13 @@ export function DialogEditProject(props: { project: LocalProject }) {
classList={{ classList={{
"border-text-interactive-base bg-surface-info-base/20": store.dragOver, "border-text-interactive-base bg-surface-info-base/20": store.dragOver,
"border-border-base hover:border-border-strong": !store.dragOver, "border-border-base hover:border-border-strong": !store.dragOver,
"overflow-hidden": !!store.iconUrl, "overflow-hidden": !!store.iconOverride,
}} }}
onDrop={handleDrop} onDrop={handleDrop}
onDragOver={handleDragOver} onDragOver={handleDragOver}
onDragLeave={handleDragLeave} onDragLeave={handleDragLeave}
onClick={() => { onClick={() => {
if (store.iconUrl && store.iconHover) { if (store.iconOverride && store.iconHover) {
clearIcon() clearIcon()
} else { } else {
iconInput?.click() iconInput?.click()
@@ -144,7 +145,11 @@ export function DialogEditProject(props: { project: LocalProject }) {
}} }}
> >
<Show <Show
when={store.iconUrl} when={getProjectAvatarSource(props.project.id, {
color: store.color,
url: props.project.icon?.url,
override: store.iconOverride,
})}
fallback={ fallback={
<div class="size-full flex items-center justify-center"> <div class="size-full flex items-center justify-center">
<Avatar <Avatar
@@ -155,18 +160,20 @@ export function DialogEditProject(props: { project: LocalProject }) {
</div> </div>
} }
> >
{(src) => (
<img <img
src={store.iconUrl} src={src()}
alt={language.t("dialog.project.edit.icon.alt")} alt={language.t("dialog.project.edit.icon.alt")}
class="size-full object-cover" class="size-full object-cover"
/> />
)}
</Show> </Show>
</div> </div>
<div <div
class="absolute inset-0 size-16 bg-surface-raised-stronger-non-alpha/90 rounded-[6px] z-10 pointer-events-none flex items-center justify-center transition-opacity" class="absolute inset-0 size-16 bg-surface-raised-stronger-non-alpha/90 rounded-[6px] z-10 pointer-events-none flex items-center justify-center transition-opacity"
classList={{ classList={{
"opacity-100": store.iconHover && !store.iconUrl, "opacity-100": store.iconHover && !store.iconOverride,
"opacity-0": !(store.iconHover && !store.iconUrl), "opacity-0": !(store.iconHover && !store.iconOverride),
}} }}
> >
<Icon name="cloud-upload" size="large" class="text-icon-on-interactive-base drop-shadow-sm" /> <Icon name="cloud-upload" size="large" class="text-icon-on-interactive-base drop-shadow-sm" />
@@ -174,8 +181,8 @@ export function DialogEditProject(props: { project: LocalProject }) {
<div <div
class="absolute inset-0 size-16 bg-surface-raised-stronger-non-alpha/90 rounded-[6px] z-10 pointer-events-none flex items-center justify-center transition-opacity" class="absolute inset-0 size-16 bg-surface-raised-stronger-non-alpha/90 rounded-[6px] z-10 pointer-events-none flex items-center justify-center transition-opacity"
classList={{ classList={{
"opacity-100": store.iconHover && !!store.iconUrl, "opacity-100": store.iconHover && !!store.iconOverride,
"opacity-0": !(store.iconHover && !!store.iconUrl), "opacity-0": !(store.iconHover && !!store.iconOverride),
}} }}
> >
<Icon name="trash" size="large" class="text-icon-on-interactive-base drop-shadow-sm" /> <Icon name="trash" size="large" class="text-icon-on-interactive-base drop-shadow-sm" />
@@ -198,7 +205,7 @@ export function DialogEditProject(props: { project: LocalProject }) {
</div> </div>
</div> </div>
<Show when={!store.iconUrl}> <Show when={!store.iconOverride}>
<div class="flex flex-col gap-2"> <div class="flex flex-col gap-2">
<label class="text-12-medium text-text-weak">{language.t("dialog.project.edit.color")}</label> <label class="text-12-medium text-text-weak">{language.t("dialog.project.edit.color")}</label>
<div class="flex gap-1.5"> <div class="flex gap-1.5">
@@ -215,7 +222,10 @@ export function DialogEditProject(props: { project: LocalProject }) {
"bg-transparent border border-transparent hover:bg-surface-base-hover hover:border-border-weak-base": "bg-transparent border border-transparent hover:bg-surface-base-hover hover:border-border-weak-base":
store.color !== color, store.color !== color,
}} }}
onClick={() => setStore("color", color)} onClick={() => {
if (store.color === color && !props.project.icon?.url) return
setStore("color", store.color === color ? undefined : color)
}}
> >
<Avatar <Avatar
fallback={store.name || defaultName()} fallback={store.name || defaultName()}
+1 -1
View File
@@ -9,7 +9,7 @@ import { List } from "@opencode-ai/ui/list"
import { showToast } from "@opencode-ai/ui/toast" import { showToast } from "@opencode-ai/ui/toast"
import { extractPromptFromParts } from "@/utils/prompt" import { extractPromptFromParts } from "@/utils/prompt"
import type { TextPart as SDKTextPart } from "@opencode-ai/sdk/v2/client" import type { TextPart as SDKTextPart } from "@opencode-ai/sdk/v2/client"
import { base64Encode } from "@opencode-ai/shared/util/encode" import { base64Encode } from "@opencode-ai/core/util/encode"
import { useLanguage } from "@/context/language" import { useLanguage } from "@/context/language"
interface ForkableMessage { interface ForkableMessage {
@@ -3,7 +3,7 @@ import { Dialog } from "@opencode-ai/ui/dialog"
import { FileIcon } from "@opencode-ai/ui/file-icon" import { FileIcon } from "@opencode-ai/ui/file-icon"
import { List } from "@opencode-ai/ui/list" import { List } from "@opencode-ai/ui/list"
import type { ListRef } from "@opencode-ai/ui/list" import type { ListRef } from "@opencode-ai/ui/list"
import { getDirectory, getFilename } from "@opencode-ai/shared/util/path" import { getDirectory, getFilename } from "@opencode-ai/core/util/path"
import fuzzysort from "fuzzysort" import fuzzysort from "fuzzysort"
import { createMemo, createResource, createSignal } from "solid-js" import { createMemo, createResource, createSignal } from "solid-js"
import { useGlobalSDK } from "@/context/global-sdk" import { useGlobalSDK } from "@/context/global-sdk"
@@ -4,8 +4,8 @@ import { FileIcon } from "@opencode-ai/ui/file-icon"
import { Icon } from "@opencode-ai/ui/icon" import { Icon } from "@opencode-ai/ui/icon"
import { Keybind } from "@opencode-ai/ui/keybind" import { Keybind } from "@opencode-ai/ui/keybind"
import { List } from "@opencode-ai/ui/list" import { List } from "@opencode-ai/ui/list"
import { base64Encode } from "@opencode-ai/shared/util/encode" import { base64Encode } from "@opencode-ai/core/util/encode"
import { getDirectory, getFilename } from "@opencode-ai/shared/util/path" import { getDirectory, getFilename } from "@opencode-ai/core/util/path"
import { useNavigate } from "@solidjs/router" import { useNavigate } from "@solidjs/router"
import { createMemo, createSignal, Match, onCleanup, Show, Switch } from "solid-js" import { createMemo, createSignal, Match, onCleanup, Show, Switch } from "solid-js"
import { formatKeybind, useCommand, type CommandOption } from "@/context/command" import { formatKeybind, useCommand, type CommandOption } from "@/context/command"
@@ -348,8 +348,8 @@ export function DialogSelectFile(props: { mode?: DialogSelectFileMode; onOpenFil
const open = (path: string) => { const open = (path: string) => {
const value = file.tab(path) const value = file.tab(path)
tabs().open(value) void tabs().open(value)
file.load(path) void file.load(path)
if (!view().reviewPanel.opened()) view().reviewPanel.open() if (!view().reviewPanel.opened()) view().reviewPanel.open()
layout.fileTree.setTab("all") layout.fileTree.setTab("all")
props.onOpenFile?.(path) props.onOpenFile?.(path)
@@ -344,7 +344,7 @@ export function DialogSelectServer() {
createEffect(() => { createEffect(() => {
items() items()
refreshHealth() void refreshHealth()
const interval = setInterval(refreshHealth, 10_000) const interval = setInterval(refreshHealth, 10_000)
onCleanup(() => clearInterval(interval)) onCleanup(() => clearInterval(interval))
}) })
@@ -498,13 +498,13 @@ export function DialogSelectServer() {
async function handleRemove(url: ServerConnection.Key) { async function handleRemove(url: ServerConnection.Key) {
server.remove(url) server.remove(url)
if ((await platform.getDefaultServer?.()) === url) { if ((await platform.getDefaultServer?.()) === url) {
platform.setDefaultServer?.(null) void platform.setDefaultServer?.(null)
} }
} }
return ( return (
<Dialog title={formTitle()}> <Dialog title={formTitle()}>
<div class="flex flex-col gap-2"> <div class="flex flex-1 min-h-0 flex-col gap-2">
<Show <Show
when={!isFormMode()} when={!isFormMode()}
fallback={ fallback={
@@ -536,10 +536,10 @@ export function DialogSelectServer() {
items={sortedItems} items={sortedItems}
key={(x) => x.http.url} key={(x) => x.http.url}
onSelect={(x) => { onSelect={(x) => {
if (x) select(x) if (x) void select(x)
}} }}
divider={true} divider={true}
class="px-5 [&_[data-slot=list-search-wrapper]]:w-full [&_[data-slot=list-scroll]]h-[300px] [&_[data-slot=list-scroll]]:overflow-y-auto [&_[data-slot=list-items]]:bg-surface-base [&_[data-slot=list-items]]:rounded-md [&_[data-slot=list-item]]:min-h-14 [&_[data-slot=list-item]]:p-3 [&_[data-slot=list-item]]:!bg-transparent" class="flex-1 min-h-0 px-5 [&_[data-slot=list-search-wrapper]]:w-full [&_[data-slot=list-scroll]]:flex-1 [&_[data-slot=list-scroll]]:overflow-y-auto [&_[data-slot=list-items]]:bg-surface-base [&_[data-slot=list-items]]:rounded-md [&_[data-slot=list-item]]:min-h-14 [&_[data-slot=list-item]]:p-3 [&_[data-slot=list-item]]:!bg-transparent"
> >
{(i) => { {(i) => {
const key = ServerConnection.key(i) const key = ServerConnection.key(i)
@@ -619,7 +619,7 @@ export function DialogSelectServer() {
</List> </List>
</Show> </Show>
<div class="px-5 pb-5"> <div class="shrink-0 px-5 pb-5">
<Show <Show
when={isFormMode()} when={isFormMode()}
fallback={ fallback={
+1 -2
View File
@@ -14,7 +14,6 @@ import {
Switch, Switch,
untrack, untrack,
type ComponentProps, type ComponentProps,
type JSXElement,
type ParentProps, type ParentProps,
} from "solid-js" } from "solid-js"
import { Dynamic } from "solid-js/web" import { Dynamic } from "solid-js/web"
@@ -149,7 +148,7 @@ const FileTreeNode = (
classList={{ classList={{
"w-full min-w-0 h-6 flex items-center justify-start gap-x-1.5 rounded-md px-1.5 py-0 text-left hover:bg-surface-raised-base-hover active:bg-surface-base-active transition-colors cursor-pointer": true, "w-full min-w-0 h-6 flex items-center justify-start gap-x-1.5 rounded-md px-1.5 py-0 text-left hover:bg-surface-raised-base-hover active:bg-surface-base-active transition-colors cursor-pointer": true,
"bg-surface-base-active": local.node.path === local.active, "bg-surface-base-active": local.node.path === local.active,
...(local.classList ?? {}), ...local.classList,
[local.class ?? ""]: !!local.class, [local.class ?? ""]: !!local.class,
[local.nodeClass ?? ""]: !!local.nodeClass, [local.nodeClass ?? ""]: !!local.nodeClass,
}} }}
+62 -22
View File
@@ -1,6 +1,6 @@
import { useFilteredList } from "@opencode-ai/ui/hooks" import { useFilteredList } from "@opencode-ai/ui/hooks"
import { useSpring } from "@opencode-ai/ui/motion-spring" import { useSpring } from "@opencode-ai/ui/motion-spring"
import { createEffect, on, Component, Show, onCleanup, createMemo, createSignal } from "solid-js" import { createEffect, on, Component, Show, onCleanup, createMemo, createSignal, createResource } from "solid-js"
import { createStore } from "solid-js/store" import { createStore } from "solid-js/store"
import { useLocal } from "@/context/local" import { useLocal } from "@/context/local"
import { selectionFromLines, type SelectedLineRange, useFile } from "@/context/file" import { selectionFromLines, type SelectedLineRange, useFile } from "@/context/file"
@@ -54,6 +54,8 @@ import { PromptImageAttachments } from "./prompt-input/image-attachments"
import { PromptDragOverlay } from "./prompt-input/drag-overlay" import { PromptDragOverlay } from "./prompt-input/drag-overlay"
import { promptPlaceholder } from "./prompt-input/placeholder" import { promptPlaceholder } from "./prompt-input/placeholder"
import { ImagePreview } from "@opencode-ai/ui/image-preview" import { ImagePreview } from "@opencode-ai/ui/image-preview"
import { useQueries } from "@tanstack/solid-query"
import { loadAgentsQuery, loadProvidersQuery } from "@/context/global-sync/bootstrap"
interface PromptInputProps { interface PromptInputProps {
class?: string class?: string
@@ -100,6 +102,7 @@ const NON_EMPTY_TEXT = /[^\s\u200B]/
export const PromptInput: Component<PromptInputProps> = (props) => { export const PromptInput: Component<PromptInputProps> = (props) => {
const sdk = useSDK() const sdk = useSDK()
const sync = useSync() const sync = useSync()
const local = useLocal() const local = useLocal()
const files = useFile() const files = useFile()
@@ -212,9 +215,9 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
if (!view().reviewPanel.opened()) view().reviewPanel.open() if (!view().reviewPanel.opened()) view().reviewPanel.open()
layout.fileTree.setTab("all") layout.fileTree.setTab("all")
const tab = files.tab(item.path) const tab = files.tab(item.path)
tabs().open(tab) void tabs().open(tab)
tabs().setActive(tab) tabs().setActive(tab)
Promise.resolve(files.load(item.path)).finally(() => queueCommentFocus()) void Promise.resolve(files.load(item.path)).finally(() => queueCommentFocus())
} }
const recent = createMemo(() => { const recent = createMemo(() => {
@@ -267,7 +270,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
const buttonsSpring = useSpring(() => (store.mode === "normal" ? 1 : 0), { visualDuration: 0.2, bounce: 0 }) const buttonsSpring = useSpring(() => (store.mode === "normal" ? 1 : 0), { visualDuration: 0.2, bounce: 0 })
const motion = (value: number) => ({ const motion = (value: number) => ({
opacity: value, opacity: value,
transform: `scale(${0.95 + value * 0.05})`, transform: `scale(${0.98 + value * 0.02})`,
filter: `blur(${(1 - value) * 2}px)`, filter: `blur(${(1 - value) * 2}px)`,
"pointer-events": value > 0.5 ? ("auto" as const) : ("none" as const), "pointer-events": value > 0.5 ? ("auto" as const) : ("none" as const),
}) })
@@ -342,7 +345,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
promptPlaceholder({ promptPlaceholder({
mode: store.mode, mode: store.mode,
commentCount: commentCount(), commentCount: commentCount(),
example: suggest() ? language.t(EXAMPLES[store.placeholder]) : "", example: suggest() ? (store.mode === "shell" ? "git status" : language.t(EXAMPLES[store.placeholder])) : "",
suggest: suggest(), suggest: suggest(),
t: (key, params) => language.t(key as Parameters<typeof language.t>[0], params as never), t: (key, params) => language.t(key as Parameters<typeof language.t>[0], params as never),
}), }),
@@ -1139,7 +1142,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
} }
if (working()) { if (working()) {
abort() void abort()
event.preventDefault() event.preventDefault()
event.stopPropagation() event.stopPropagation()
return return
@@ -1205,7 +1208,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
return return
} }
if (working()) { if (working()) {
abort() void abort()
event.preventDefault() event.preventDefault()
} }
return return
@@ -1245,12 +1248,27 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
) { ) {
return return
} }
handleSubmit(event) void handleSubmit(event)
} }
} }
const [agentsQuery, globalProvidersQuery, providersQuery] = useQueries(() => ({
queries: [loadAgentsQuery(sdk.directory), loadProvidersQuery(null), loadProvidersQuery(sdk.directory)],
}))
const agentsLoading = () => agentsQuery.isLoading
const agentsShouldFadeIn = createMemo((prev) => prev ?? agentsLoading())
const providersLoading = () => agentsLoading() || providersQuery.isLoading || globalProvidersQuery.isLoading
const providersShouldFadeIn = createMemo((prev) => prev ?? providersLoading())
const [promptReady] = createResource(
() => prompt.ready().promise,
(p) => p,
)
return ( return (
<div class="relative size-full _max-h-[320px] flex flex-col gap-0"> <div class="relative size-full _max-h-[320px] flex flex-col gap-0">
{(promptReady(), null)}
<PromptPopover <PromptPopover
popover={store.popover} popover={store.popover}
setSlashPopoverRef={(el) => (slashPopoverRef = el)} setSlashPopoverRef={(el) => (slashPopoverRef = el)}
@@ -1347,15 +1365,13 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
}} }}
style={{ "padding-bottom": space }} style={{ "padding-bottom": space }}
/> />
<Show when={!prompt.dirty()}>
<div <div
class="absolute top-0 inset-x-0 pl-3 pr-2 pt-2 text-14-regular text-text-weak pointer-events-none whitespace-nowrap truncate" class="absolute top-0 inset-x-0 pl-3 pr-2 pt-2 text-14-regular text-text-weak pointer-events-none whitespace-nowrap truncate"
classList={{ "font-mono!": store.mode === "shell" }} classList={{ "font-mono!": store.mode === "shell" }}
style={{ "padding-bottom": space }} style={{ "padding-bottom": space, display: prompt.dirty() ? "none" : undefined }}
> >
{placeholder()} {placeholder()}
</div> </div>
</Show>
</div> </div>
<div <div
@@ -1387,12 +1403,11 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
<IconButton <IconButton
data-action="prompt-submit" data-action="prompt-submit"
type="submit" type="submit"
disabled={store.mode !== "normal" || (!working() && blank())} disabled={!working() && blank()}
tabIndex={store.mode === "normal" ? undefined : -1} tabIndex={store.mode === "normal" ? undefined : -1}
icon={stopping() ? "stop" : "arrow-up"} icon={stopping() ? "stop" : store.mode === "shell" ? "arrow-undo-down" : "arrow-up"}
variant="primary" variant="primary"
class="size-8" class="size-8"
style={buttons()}
aria-label={stopping() ? language.t("prompt.action.stop") : language.t("prompt.action.send")} aria-label={stopping() ? language.t("prompt.action.stop") : language.t("prompt.action.send")}
/> />
</Tooltip> </Tooltip>
@@ -1435,17 +1450,31 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
<div class="px-1.75 pt-5.5 pb-2 flex items-center gap-2 min-w-0"> <div class="px-1.75 pt-5.5 pb-2 flex items-center gap-2 min-w-0">
<div class="flex items-center gap-1.5 min-w-0 flex-1 relative"> <div class="flex items-center gap-1.5 min-w-0 flex-1 relative">
<div <div
class="h-7 flex items-center gap-1.5 max-w-[160px] min-w-0 absolute inset-y-0 left-0" class="h-7 flex items-center gap-1.5 min-w-0 absolute inset-0"
style={{ style={{
padding: "0 4px 0 8px", padding: "0 0px 0 8px",
...shell(), ...shell(),
}} }}
> >
<span class="truncate text-13-medium text-text-strong">{language.t("prompt.mode.shell")}</span> <Icon name="console" />
<div class="size-4 shrink-0" /> <span class="truncate text-13-medium text-text-base">{language.t("prompt.mode.shell")}</span>
<div class="flex-1" />
<Button
variant="ghost"
class="text-text-base"
onClick={() => {
setStore("mode", "normal")
}}
>
{language.t("common.cancel")}
</Button>
</div> </div>
<div class="flex items-center gap-1.5 min-w-0 flex-1"> <div class="flex items-center gap-1.5 min-w-0 flex-1 h-7">
<div data-component="prompt-agent-control"> <Show when={!agentsLoading()}>
<div
data-component="prompt-agent-control"
style={agentsShouldFadeIn() ? { animation: "fade-in 0.3s" } : undefined}
>
<TooltipKeybind <TooltipKeybind
placement="top" placement="top"
gutter={4} gutter={4}
@@ -1468,8 +1497,13 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
/> />
</TooltipKeybind> </TooltipKeybind>
</div> </div>
</Show>
<Show when={!providersLoading()}>
<Show when={store.mode !== "shell"}> <Show when={store.mode !== "shell"}>
<div data-component="prompt-model-control"> <div
data-component="prompt-model-control"
style={providersShouldFadeIn() ? { animation: "fade-in 0.3s" } : undefined}
>
<Show <Show
when={providers.paid().length > 0} when={providers.paid().length > 0}
fallback={ fallback={
@@ -1540,7 +1574,11 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
</TooltipKeybind> </TooltipKeybind>
</Show> </Show>
</div> </div>
<div data-component="prompt-variant-control"> <Show when={variants().length > 2}>
<div
data-component="prompt-variant-control"
style={providersShouldFadeIn() ? { animation: "fade-in 0.3s" } : undefined}
>
<TooltipKeybind <TooltipKeybind
placement="top" placement="top"
gutter={4} gutter={4}
@@ -1565,6 +1603,8 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
</TooltipKeybind> </TooltipKeybind>
</div> </div>
</Show> </Show>
</Show>
</Show>
</div> </div>
</div> </div>
</div> </div>
@@ -1,4 +1,4 @@
import { getFilename } from "@opencode-ai/shared/util/path" import { getFilename } from "@opencode-ai/core/util/path"
import { type AgentPartInput, type FilePartInput, type Part, type TextPartInput } from "@opencode-ai/sdk/v2/client" import { type AgentPartInput, type FilePartInput, type Part, type TextPartInput } from "@opencode-ai/sdk/v2/client"
import type { FileSelection } from "@/context/file" import type { FileSelection } from "@/context/file"
import { encodeFilePath } from "@/context/file/path" import { encodeFilePath } from "@/context/file/path"
@@ -2,7 +2,7 @@ import { Component, For, Show } from "solid-js"
import { FileIcon } from "@opencode-ai/ui/file-icon" import { FileIcon } from "@opencode-ai/ui/file-icon"
import { IconButton } from "@opencode-ai/ui/icon-button" import { IconButton } from "@opencode-ai/ui/icon-button"
import { Tooltip } from "@opencode-ai/ui/tooltip" import { Tooltip } from "@opencode-ai/ui/tooltip"
import { getDirectory, getFilename, getFilenameTruncated } from "@opencode-ai/shared/util/path" import { getDirectory, getFilename, getFilenameTruncated } from "@opencode-ai/core/util/path"
import type { ContextItem } from "@/context/prompt" import type { ContextItem } from "@/context/prompt"
type PromptContextItem = ContextItem & { key: string } type PromptContextItem = ContextItem & { key: string }
@@ -12,7 +12,7 @@ describe("promptPlaceholder", () => {
suggest: true, suggest: true,
t, t,
}) })
expect(value).toBe("prompt.placeholder.shell") expect(value).toBe("prompt.placeholder.shell:example")
}) })
test("returns summarize placeholders for comment context", () => { test("returns summarize placeholders for comment context", () => {
@@ -7,7 +7,7 @@ type PromptPlaceholderInput = {
} }
export function promptPlaceholder(input: PromptPlaceholderInput) { export function promptPlaceholder(input: PromptPlaceholderInput) {
if (input.mode === "shell") return input.t("prompt.placeholder.shell") if (input.mode === "shell") return input.t("prompt.placeholder.shell", { example: input.example })
if (input.commentCount > 1) return input.t("prompt.placeholder.summarizeComments") if (input.commentCount > 1) return input.t("prompt.placeholder.summarizeComments")
if (input.commentCount === 1) return input.t("prompt.placeholder.summarizeComment") if (input.commentCount === 1) return input.t("prompt.placeholder.summarizeComment")
if (!input.suggest) return input.t("prompt.placeholder.simple") if (!input.suggest) return input.t("prompt.placeholder.simple")
@@ -1,7 +1,7 @@
import { Component, For, Match, Show, Switch } from "solid-js" import { Component, For, Match, Show, Switch } from "solid-js"
import { FileIcon } from "@opencode-ai/ui/file-icon" import { FileIcon } from "@opencode-ai/ui/file-icon"
import { Icon } from "@opencode-ai/ui/icon" import { Icon } from "@opencode-ai/ui/icon"
import { getDirectory, getFilename } from "@opencode-ai/shared/util/path" import { getDirectory, getFilename } from "@opencode-ai/core/util/path"
export type AtOption = export type AtOption =
| { type: "agent"; name: string; display: string } | { type: "agent"; name: string; display: string }
@@ -74,7 +74,7 @@ beforeAll(async () => {
showToast: () => 0, showToast: () => 0,
})) }))
mock.module("@opencode-ai/shared/util/encode", () => ({ mock.module("@opencode-ai/core/util/encode", () => ({
base64Encode: (value: string) => value, base64Encode: (value: string) => value,
})) }))
@@ -1,7 +1,7 @@
import type { Message, Session } from "@opencode-ai/sdk/v2/client" import type { Message, Session } from "@opencode-ai/sdk/v2/client"
import { showToast } from "@opencode-ai/ui/toast" import { showToast } from "@opencode-ai/ui/toast"
import { base64Encode } from "@opencode-ai/shared/util/encode" import { base64Encode } from "@opencode-ai/core/util/encode"
import { Binary } from "@opencode-ai/shared/util/binary" import { Binary } from "@opencode-ai/core/util/binary"
import { useNavigate, useParams } from "@solidjs/router" import { useNavigate, useParams } from "@solidjs/router"
import { batch, type Accessor } from "solid-js" import { batch, type Accessor } from "solid-js"
import type { FileSelection } from "@/context/file" import type { FileSelection } from "@/context/file"
@@ -295,7 +295,7 @@ export function createPromptSubmit(input: PromptSubmitInput) {
const mode = input.mode() const mode = input.mode()
if (text.trim().length === 0 && images.length === 0 && input.commentCount() === 0) { if (text.trim().length === 0 && images.length === 0 && input.commentCount() === 0) {
if (input.working()) abort() if (input.working()) void abort()
return return
} }
@@ -24,7 +24,7 @@ function openSessionContext(args: {
}) { }) {
if (!args.view.reviewPanel.opened()) args.view.reviewPanel.open() if (!args.view.reviewPanel.opened()) args.view.reviewPanel.open()
if (args.layout.fileTree.opened() && args.layout.fileTree.tab() !== "all") args.layout.fileTree.setTab("all") if (args.layout.fileTree.opened() && args.layout.fileTree.tab() !== "all") args.layout.fileTree.setTab("all")
args.tabs.open("context") void args.tabs.open("context")
args.tabs.setActive("context") args.tabs.setActive("context")
} }
@@ -1,8 +1,8 @@
import { createMemo, createEffect, on, onCleanup, For, Show } from "solid-js" import { createMemo, createEffect, on, onCleanup, For, Show } from "solid-js"
import type { JSX } from "solid-js" import type { JSX } from "solid-js"
import { useSync } from "@/context/sync" import { useSync } from "@/context/sync"
import { checksum } from "@opencode-ai/shared/util/encode" import { checksum } from "@opencode-ai/core/util/encode"
import { findLast } from "@opencode-ai/shared/util/array" import { findLast } from "@opencode-ai/core/util/array"
import { same } from "@/utils/same" import { same } from "@/utils/same"
import { Icon } from "@opencode-ai/ui/icon" import { Icon } from "@opencode-ai/ui/icon"
import { Accordion } from "@opencode-ai/ui/accordion" import { Accordion } from "@opencode-ai/ui/accordion"
@@ -7,8 +7,8 @@ import { Keybind } from "@opencode-ai/ui/keybind"
import { Spinner } from "@opencode-ai/ui/spinner" import { Spinner } from "@opencode-ai/ui/spinner"
import { showToast } from "@opencode-ai/ui/toast" import { showToast } from "@opencode-ai/ui/toast"
import { Tooltip, TooltipKeybind } from "@opencode-ai/ui/tooltip" import { Tooltip, TooltipKeybind } from "@opencode-ai/ui/tooltip"
import { getFilename } from "@opencode-ai/shared/util/path" import { getFilename } from "@opencode-ai/core/util/path"
import { createEffect, createMemo, For, onCleanup, Show } from "solid-js" import { createEffect, createMemo, createSignal, For, onMount, Show } from "solid-js"
import { createStore } from "solid-js/store" import { createStore } from "solid-js/store"
import { Portal } from "solid-js/web" import { Portal } from "solid-js/web"
import { useCommand } from "@/context/command" import { useCommand } from "@/context/command"
@@ -16,6 +16,7 @@ import { useLanguage } from "@/context/language"
import { useLayout } from "@/context/layout" import { useLayout } from "@/context/layout"
import { usePlatform } from "@/context/platform" import { usePlatform } from "@/context/platform"
import { useServer } from "@/context/server" import { useServer } from "@/context/server"
import { useSettings } from "@/context/settings"
import { useSync } from "@/context/sync" import { useSync } from "@/context/sync"
import { useTerminal } from "@/context/terminal" import { useTerminal } from "@/context/terminal"
import { focusTerminalById } from "@/pages/session/helpers" import { focusTerminalById } from "@/pages/session/helpers"
@@ -134,6 +135,7 @@ export function SessionHeader() {
const server = useServer() const server = useServer()
const platform = usePlatform() const platform = usePlatform()
const language = useLanguage() const language = useLanguage()
const settings = useSettings()
const sync = useSync() const sync = useSync()
const terminal = useTerminal() const terminal = useTerminal()
const { params, view } = useSessionLayout() const { params, view } = useSessionLayout()
@@ -151,6 +153,11 @@ export function SessionHeader() {
}) })
const hotkey = createMemo(() => command.keybind("file.open")) const hotkey = createMemo(() => command.keybind("file.open"))
const os = createMemo(() => detectOS(platform)) const os = createMemo(() => detectOS(platform))
const isDesktopBeta = platform.platform === "desktop" && import.meta.env.VITE_OPENCODE_CHANNEL === "beta"
const search = createMemo(() => !isDesktopBeta || settings.general.showSearch())
const tree = createMemo(() => !isDesktopBeta || settings.general.showFileTree())
const term = createMemo(() => !isDesktopBeta || settings.general.showTerminal())
const status = createMemo(() => !isDesktopBeta || settings.general.showStatus())
const [exists, setExists] = createStore<Partial<Record<OpenApp, boolean>>>({ const [exists, setExists] = createStore<Partial<Record<OpenApp, boolean>>>({
finder: true, finder: true,
@@ -262,12 +269,16 @@ export function SessionHeader() {
.catch((err: unknown) => showRequestError(language, err)) .catch((err: unknown) => showRequestError(language, err))
} }
const centerMount = createMemo(() => document.getElementById("opencode-titlebar-center")) const [centerMount, setCenterMount] = createSignal<HTMLElement | null>(null)
const rightMount = createMemo(() => document.getElementById("opencode-titlebar-right")) const [rightMount, setRightMount] = createSignal<HTMLElement | null>(null)
onMount(() => {
setCenterMount(document.getElementById("opencode-titlebar-center"))
setRightMount(document.getElementById("opencode-titlebar-right"))
})
return ( return (
<> <>
<Show when={centerMount()}> <Show when={search() && centerMount()}>
{(mount) => ( {(mount) => (
<Portal mount={mount()}> <Portal mount={mount()}>
<Button <Button
@@ -415,9 +426,12 @@ export function SessionHeader() {
</div> </div>
</Show> </Show>
<div class="flex items-center gap-1"> <div class="flex items-center gap-1">
<Show when={status()}>
<Tooltip placement="bottom" value={language.t("status.popover.trigger")}> <Tooltip placement="bottom" value={language.t("status.popover.trigger")}>
<StatusPopover /> <StatusPopover />
</Tooltip> </Tooltip>
</Show>
<Show when={term()}>
<TooltipKeybind <TooltipKeybind
title={language.t("command.terminal.toggle")} title={language.t("command.terminal.toggle")}
keybind={command.keybind("terminal.toggle")} keybind={command.keybind("terminal.toggle")}
@@ -433,6 +447,7 @@ export function SessionHeader() {
<Icon size="small" name={view().terminal.opened() ? "terminal-active" : "terminal"} /> <Icon size="small" name={view().terminal.opened() ? "terminal-active" : "terminal"} />
</Button> </Button>
</TooltipKeybind> </TooltipKeybind>
</Show>
<div class="hidden md:flex items-center gap-1 shrink-0"> <div class="hidden md:flex items-center gap-1 shrink-0">
<TooltipKeybind <TooltipKeybind
@@ -451,6 +466,7 @@ export function SessionHeader() {
</Button> </Button>
</TooltipKeybind> </TooltipKeybind>
<Show when={tree()}>
<TooltipKeybind <TooltipKeybind
title={language.t("command.fileTree.toggle")} title={language.t("command.fileTree.toggle")}
keybind={command.keybind("fileTree.toggle")} keybind={command.keybind("fileTree.toggle")}
@@ -475,6 +491,7 @@ export function SessionHeader() {
</div> </div>
</Button> </Button>
</TooltipKeybind> </TooltipKeybind>
</Show>
</div> </div>
</div> </div>
</div> </div>
@@ -5,7 +5,7 @@ import { useSDK } from "@/context/sdk"
import { useLanguage } from "@/context/language" import { useLanguage } from "@/context/language"
import { Icon } from "@opencode-ai/ui/icon" import { Icon } from "@opencode-ai/ui/icon"
import { Mark } from "@opencode-ai/ui/logo" import { Mark } from "@opencode-ai/ui/logo"
import { getDirectory, getFilename } from "@opencode-ai/shared/util/path" import { getDirectory, getFilename } from "@opencode-ai/core/util/path"
const MAIN_WORKTREE = "main" const MAIN_WORKTREE = "main"
const CREATE_WORKTREE = "create" const CREATE_WORKTREE = "create"
@@ -5,7 +5,7 @@ import { FileIcon } from "@opencode-ai/ui/file-icon"
import { IconButton } from "@opencode-ai/ui/icon-button" import { IconButton } from "@opencode-ai/ui/icon-button"
import { TooltipKeybind } from "@opencode-ai/ui/tooltip" import { TooltipKeybind } from "@opencode-ai/ui/tooltip"
import { Tabs } from "@opencode-ai/ui/tabs" import { Tabs } from "@opencode-ai/ui/tabs"
import { getFilename } from "@opencode-ai/shared/util/path" import { getFilename } from "@opencode-ai/core/util/path"
import { useFile } from "@/context/file" import { useFile } from "@/context/file"
import { useLanguage } from "@/context/language" import { useLanguage } from "@/context/language"
import { useCommand } from "@/context/command" import { useCommand } from "@/context/command"
@@ -44,7 +44,7 @@ export function SortableTerminalTab(props: { terminal: LocalPTY; onClose?: () =>
const close = () => { const close = () => {
const count = terminal.all().length const count = terminal.all().length
terminal.close(props.terminal.id) void terminal.close(props.terminal.id)
if (count === 1) { if (count === 1) {
props.onClose?.() props.onClose?.()
} }
@@ -19,6 +19,9 @@ import {
sansDefault, sansDefault,
sansFontFamily, sansFontFamily,
sansInput, sansInput,
terminalDefault,
terminalFontFamily,
terminalInput,
useSettings, useSettings,
} from "@/context/settings" } from "@/context/settings"
import { decode64 } from "@/utils/base64" import { decode64 } from "@/utils/base64"
@@ -106,6 +109,7 @@ export const SettingsGeneral: Component = () => {
permission.disableAutoAccept(params.id, value) permission.disableAutoAccept(params.id, value)
} }
const desktop = createMemo(() => platform.platform === "desktop")
const check = () => { const check = () => {
if (!platform.checkUpdate) return if (!platform.checkUpdate) return
@@ -124,14 +128,12 @@ export const SettingsGeneral: Component = () => {
return return
} }
const actions = const actions = platform.updateAndRestart
platform.update && platform.restart
? [ ? [
{ {
label: language.t("toast.update.action.installRestart"), label: language.t("toast.update.action.installRestart"),
onClick: async () => { onClick: async () => {
await platform.update!() await platform.updateAndRestart!()
await platform.restart!()
}, },
}, },
{ {
@@ -180,6 +182,7 @@ export const SettingsGeneral: Component = () => {
const soundOptions = [noneSound, ...SOUND_OPTIONS] const soundOptions = [noneSound, ...SOUND_OPTIONS]
const mono = () => monoInput(settings.appearance.font()) const mono = () => monoInput(settings.appearance.font())
const sans = () => sansInput(settings.appearance.uiFont()) const sans = () => sansInput(settings.appearance.uiFont())
const terminal = () => terminalInput(settings.appearance.terminalFont())
const soundSelectProps = ( const soundSelectProps = (
enabled: () => boolean, enabled: () => boolean,
@@ -275,6 +278,86 @@ export const SettingsGeneral: Component = () => {
/> />
</div> </div>
</SettingsRow> </SettingsRow>
<SettingsRow
title={language.t("settings.general.row.showSessionProgressBar.title")}
description={language.t("settings.general.row.showSessionProgressBar.description")}
>
<div data-action="settings-show-session-progress-bar">
<Switch
checked={settings.general.showSessionProgressBar()}
onChange={(checked) => settings.general.setShowSessionProgressBar(checked)}
/>
</div>
</SettingsRow>
</SettingsList>
</div>
)
const AdvancedSection = () => (
<div class="flex flex-col gap-1">
<h3 class="text-14-medium text-text-strong pb-2">{language.t("settings.general.section.advanced")}</h3>
<SettingsList>
<SettingsRow
title={language.t("settings.general.row.showFileTree.title")}
description={language.t("settings.general.row.showFileTree.description")}
>
<div data-action="settings-show-file-tree">
<Switch
checked={settings.general.showFileTree()}
onChange={(checked) => settings.general.setShowFileTree(checked)}
/>
</div>
</SettingsRow>
<SettingsRow
title={language.t("settings.general.row.showNavigation.title")}
description={language.t("settings.general.row.showNavigation.description")}
>
<div data-action="settings-show-navigation">
<Switch
checked={settings.general.showNavigation()}
onChange={(checked) => settings.general.setShowNavigation(checked)}
/>
</div>
</SettingsRow>
<SettingsRow
title={language.t("settings.general.row.showSearch.title")}
description={language.t("settings.general.row.showSearch.description")}
>
<div data-action="settings-show-search">
<Switch
checked={settings.general.showSearch()}
onChange={(checked) => settings.general.setShowSearch(checked)}
/>
</div>
</SettingsRow>
<SettingsRow
title={language.t("settings.general.row.showTerminal.title")}
description={language.t("settings.general.row.showTerminal.description")}
>
<div data-action="settings-show-terminal">
<Switch
checked={settings.general.showTerminal()}
onChange={(checked) => settings.general.setShowTerminal(checked)}
/>
</div>
</SettingsRow>
<SettingsRow
title={language.t("settings.general.row.showStatus.title")}
description={language.t("settings.general.row.showStatus.description")}
>
<div data-action="settings-show-status">
<Switch
checked={settings.general.showStatus()}
onChange={(checked) => settings.general.setShowStatus(checked)}
/>
</div>
</SettingsRow>
</SettingsList> </SettingsList>
</div> </div>
) )
@@ -382,6 +465,29 @@ export const SettingsGeneral: Component = () => {
/> />
</div> </div>
</SettingsRow> </SettingsRow>
<SettingsRow
title={language.t("settings.general.row.terminalFont.title")}
description={language.t("settings.general.row.terminalFont.description")}
>
<div class="w-full sm:w-[220px]">
<TextField
data-action="settings-terminal-font"
label={language.t("settings.general.row.terminalFont.title")}
hideLabel
type="text"
value={terminal()}
onChange={(value) => settings.appearance.setTerminalFont(value)}
placeholder={terminalDefault}
spellcheck={false}
autocorrect="off"
autocomplete="off"
autocapitalize="off"
class="text-12-regular"
style={{ "font-family": terminalFontFamily(settings.appearance.terminalFont()) }}
/>
</div>
</SettingsRow>
</SettingsList> </SettingsList>
</div> </div>
) )
@@ -527,6 +633,7 @@ export const SettingsGeneral: Component = () => {
</div> </div>
) )
console.log(import.meta.env)
return ( return (
<div class="flex flex-col h-full overflow-y-auto no-scrollbar px-4 pb-10 sm:px-10 sm:pb-10"> <div class="flex flex-col h-full overflow-y-auto no-scrollbar px-4 pb-10 sm:px-10 sm:pb-10">
<div class="sticky top-0 z-10 bg-[linear-gradient(to_bottom,var(--surface-stronger-non-alpha)_calc(100%_-_24px),transparent)]"> <div class="sticky top-0 z-10 bg-[linear-gradient(to_bottom,var(--surface-stronger-non-alpha)_calc(100%_-_24px),transparent)]">
@@ -609,6 +716,10 @@ export const SettingsGeneral: Component = () => {
) )
}} }}
</Show> </Show>
<Show when={desktop() && import.meta.env.VITE_OPENCODE_CHANNEL === "beta"}>
<AdvancedSection />
</Show>
</div> </div>
</div> </div>
) )
+7 -7
View File
@@ -11,7 +11,7 @@ import { useLanguage } from "@/context/language"
import { usePlatform } from "@/context/platform" import { usePlatform } from "@/context/platform"
import { useSDK } from "@/context/sdk" import { useSDK } from "@/context/sdk"
import { useServer } from "@/context/server" import { useServer } from "@/context/server"
import { monoFontFamily, useSettings } from "@/context/settings" import { terminalFontFamily, useSettings } from "@/context/settings"
import type { LocalPTY } from "@/context/terminal" import type { LocalPTY } from "@/context/terminal"
import { disposeIfDisposable, getHoveredLinkText, setOptionIfSupported } from "@/utils/runtime-adapters" import { disposeIfDisposable, getHoveredLinkText, setOptionIfSupported } from "@/utils/runtime-adapters"
import { terminalWriter } from "@/utils/terminal-writer" import { terminalWriter } from "@/utils/terminal-writer"
@@ -191,7 +191,7 @@ export const Terminal = (props: TerminalProps) => {
const scrollY = typeof local.pty.scrollY === "number" ? local.pty.scrollY : undefined const scrollY = typeof local.pty.scrollY === "number" ? local.pty.scrollY : undefined
let ws: WebSocket | undefined let ws: WebSocket | undefined
let term: Term | undefined let term: Term | undefined
let ghostty: Ghostty let _ghostty: Ghostty
let serializeAddon: SerializeAddon let serializeAddon: SerializeAddon
let fitAddon: FitAddon let fitAddon: FitAddon
let handleResize: () => void let handleResize: () => void
@@ -300,7 +300,7 @@ export const Terminal = (props: TerminalProps) => {
}) })
createEffect(() => { createEffect(() => {
const font = monoFontFamily(settings.appearance.font()) const font = terminalFontFamily(settings.appearance.terminalFont())
if (!term) return if (!term) return
setOptionIfSupported(term, "fontFamily", font) setOptionIfSupported(term, "fontFamily", font)
scheduleFit() scheduleFit()
@@ -360,7 +360,7 @@ export const Terminal = (props: TerminalProps) => {
cols: restoreSize?.cols, cols: restoreSize?.cols,
rows: restoreSize?.rows, rows: restoreSize?.rows,
fontSize: 14, fontSize: 14,
fontFamily: monoFontFamily(settings.appearance.font()), fontFamily: terminalFontFamily(settings.appearance.terminalFont()),
allowTransparency: false, allowTransparency: false,
convertEol: false, convertEol: false,
theme: terminalColors(), theme: terminalColors(),
@@ -372,7 +372,7 @@ export const Terminal = (props: TerminalProps) => {
cleanup() cleanup()
return return
} }
ghostty = g _ghostty = g
term = t term = t
output = terminalWriter((data, done) => output = terminalWriter((data, done) =>
t.write(data, () => { t.write(data, () => {
@@ -415,7 +415,7 @@ export const Terminal = (props: TerminalProps) => {
if (local.autoFocus !== false) focusTerminal() if (local.autoFocus !== false) focusTerminal()
if (typeof document !== "undefined" && document.fonts) { if (typeof document !== "undefined" && document.fonts) {
document.fonts.ready.then(scheduleFit) void document.fonts.ready.then(scheduleFit)
} }
const onResize = t.onResize((size) => { const onResize = t.onResize((size) => {
@@ -634,7 +634,7 @@ export const Terminal = (props: TerminalProps) => {
tabIndex={-1} tabIndex={-1}
style={{ "background-color": terminalColors().background }} style={{ "background-color": terminalColors().background }}
classList={{ classList={{
...(local.classList ?? {}), ...local.classList,
"select-text": true, "select-text": true,
"size-full px-6 py-3 font-mono relative overflow-hidden": true, "size-full px-6 py-3 font-mono relative overflow-hidden": true,
[local.class ?? ""]: !!local.class, [local.class ?? ""]: !!local.class,
+16 -7
View File
@@ -1,4 +1,4 @@
import { createEffect, createMemo, onCleanup, Show, untrack } from "solid-js" import { createEffect, createMemo, Show, untrack } from "solid-js"
import { createStore } from "solid-js/store" import { createStore } from "solid-js/store"
import { useLocation, useNavigate, useParams } from "@solidjs/router" import { useLocation, useNavigate, useParams } from "@solidjs/router"
import { IconButton } from "@opencode-ai/ui/icon-button" import { IconButton } from "@opencode-ai/ui/icon-button"
@@ -11,6 +11,7 @@ import { useLayout } from "@/context/layout"
import { usePlatform } from "@/context/platform" import { usePlatform } from "@/context/platform"
import { useCommand } from "@/context/command" import { useCommand } from "@/context/command"
import { useLanguage } from "@/context/language" import { useLanguage } from "@/context/language"
import { useSettings } from "@/context/settings"
import { applyPath, backPath, forwardPath } from "./titlebar-history" import { applyPath, backPath, forwardPath } from "./titlebar-history"
type TauriDesktopWindow = { type TauriDesktopWindow = {
@@ -40,6 +41,7 @@ export function Titlebar() {
const platform = usePlatform() const platform = usePlatform()
const command = useCommand() const command = useCommand()
const language = useLanguage() const language = useLanguage()
const settings = useSettings()
const theme = useTheme() const theme = useTheme()
const navigate = useNavigate() const navigate = useNavigate()
const location = useLocation() const location = useLocation()
@@ -78,6 +80,7 @@ export function Titlebar() {
const canBack = createMemo(() => history.index > 0) const canBack = createMemo(() => history.index > 0)
const canForward = createMemo(() => history.index < history.stack.length - 1) const canForward = createMemo(() => history.index < history.stack.length - 1)
const hasProjects = createMemo(() => layout.projects.list().length > 0) const hasProjects = createMemo(() => layout.projects.list().length > 0)
const nav = createMemo(() => import.meta.env.VITE_OPENCODE_CHANNEL !== "beta" || settings.general.showNavigation())
const back = () => { const back = () => {
const next = backPath(history) const next = backPath(history)
@@ -252,16 +255,16 @@ export function Titlebar() {
</div> </div>
</div> </div>
</Show> </Show>
<Show when={hasProjects()}>
<div <div
class="flex items-center gap-0 transition-transform" class="flex items-center shrink-0"
classList={{ classList={{
"translate-x-0": !layout.sidebar.opened(), "-translate-x-[36px]": layout.sidebar.opened() && !!params.dir,
"-translate-x-[36px]": layout.sidebar.opened(),
"duration-180 ease-out": !layout.sidebar.opened(), "duration-180 ease-out": !layout.sidebar.opened(),
"duration-180 ease-in": layout.sidebar.opened(), "duration-180 ease-in": layout.sidebar.opened(),
}} }}
> >
<Show when={hasProjects() && nav()}>
<div class="flex items-center gap-0 transition-transform">
<Tooltip placement="bottom" value={language.t("common.goBack")} openDelay={2000}> <Tooltip placement="bottom" value={language.t("common.goBack")} openDelay={2000}>
<Button <Button
variant="ghost" variant="ghost"
@@ -284,9 +287,15 @@ export function Titlebar() {
</Tooltip> </Tooltip>
</div> </div>
</Show> </Show>
</div>
</div>
<div id="opencode-titlebar-left" class="flex items-center gap-3 min-w-0 px-2" /> <div id="opencode-titlebar-left" class="flex items-center gap-3 min-w-0 px-2" />
{["beta", "dev"].includes(import.meta.env.VITE_OPENCODE_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()}
</div>
)}
</div>
</div>
</div>
</div> </div>
<div class="min-w-0 flex items-center justify-center pointer-events-none"> <div class="min-w-0 flex items-center justify-center pointer-events-none">
+1 -1
View File
@@ -3,7 +3,7 @@ import { createStore, produce, reconcile } from "solid-js/store"
import { createSimpleContext } from "@opencode-ai/ui/context" import { createSimpleContext } from "@opencode-ai/ui/context"
import { showToast } from "@opencode-ai/ui/toast" import { showToast } from "@opencode-ai/ui/toast"
import { useParams } from "@solidjs/router" import { useParams } from "@solidjs/router"
import { getFilename } from "@opencode-ai/shared/util/path" import { getFilename } from "@opencode-ai/core/util/path"
import { useSDK } from "./sdk" import { useSDK } from "./sdk"
import { useSync } from "./sync" import { useSync } from "./sync"
import { useLanguage } from "@/context/language" import { useLanguage } from "@/context/language"
+1
View File
@@ -128,6 +128,7 @@ export const { use: useGlobalSDK, provider: GlobalSDKProvider } = createSimpleCo
if (started) return run if (started) return run
started = true started = true
run = (async () => { run = (async () => {
// oxlint-disable-next-line no-unmodified-loop-condition -- `started` is set to false by stop() which also aborts; both flags are checked to allow graceful exit
while (!abort.signal.aborted && started) { while (!abort.signal.aborted && started) {
attempt = new AbortController() attempt = new AbortController()
lastEventAt = Date.now() lastEventAt = Date.now()
+42 -49
View File
@@ -8,11 +8,10 @@ import type {
Todo, Todo,
} from "@opencode-ai/sdk/v2/client" } from "@opencode-ai/sdk/v2/client"
import { showToast } from "@opencode-ai/ui/toast" import { showToast } from "@opencode-ai/ui/toast"
import { getFilename } from "@opencode-ai/shared/util/path" import { getFilename } from "@opencode-ai/core/util/path"
import { createContext, getOwner, onCleanup, onMount, type ParentProps, untrack, useContext } from "solid-js" import { batch, createContext, getOwner, onCleanup, onMount, type ParentProps, untrack, useContext } from "solid-js"
import { createStore, produce, reconcile } from "solid-js/store" import { createStore, produce, reconcile } from "solid-js/store"
import { useLanguage } from "@/context/language" import { useLanguage } from "@/context/language"
import { Persist, persisted } from "@/utils/persist"
import type { InitError } from "../pages/error" import type { InitError } from "../pages/error"
import { useGlobalSDK } from "./global-sdk" import { useGlobalSDK } from "./global-sdk"
import { bootstrapDirectory, bootstrapGlobal, clearProviderRev } from "./global-sync/bootstrap" import { bootstrapDirectory, bootstrapGlobal, clearProviderRev } from "./global-sync/bootstrap"
@@ -24,8 +23,8 @@ import { estimateRootSessionTotal, loadRootSessionsWithFallback } from "./global
import { trimSessions } from "./global-sync/session-trim" import { trimSessions } from "./global-sync/session-trim"
import type { ProjectMeta } from "./global-sync/types" import type { ProjectMeta } from "./global-sync/types"
import { SESSION_RECENT_LIMIT } from "./global-sync/types" import { SESSION_RECENT_LIMIT } from "./global-sync/types"
import { sanitizeProject } from "./global-sync/utils"
import { formatServerError } from "@/utils/server-errors" import { formatServerError } from "@/utils/server-errors"
import { queryOptions, skipToken, useQueryClient } from "@tanstack/solid-query"
type GlobalStore = { type GlobalStore = {
ready: boolean ready: boolean
@@ -41,6 +40,9 @@ type GlobalStore = {
reload: undefined | "pending" | "complete" reload: undefined | "pending" | "complete"
} }
export const loadSessionsQuery = (directory: string) =>
queryOptions<null>({ queryKey: [directory, "loadSessions"], queryFn: skipToken })
function createGlobalSync() { function createGlobalSync() {
const globalSDK = useGlobalSDK() const globalSDK = useGlobalSDK()
const language = useLanguage() const language = useLanguage()
@@ -52,53 +54,30 @@ function createGlobalSync() {
const sessionLoads = new Map<string, Promise<void>>() const sessionLoads = new Map<string, Promise<void>>()
const sessionMeta = new Map<string, { limit: number }>() const sessionMeta = new Map<string, { limit: number }>()
const [projectCache, setProjectCache, projectInit] = persisted(
Persist.global("globalSync.project", ["globalSync.project.v1"]),
createStore({ value: [] as Project[] }),
)
const [globalStore, setGlobalStore] = createStore<GlobalStore>({ const [globalStore, setGlobalStore] = createStore<GlobalStore>({
ready: false, ready: false,
path: { state: "", config: "", worktree: "", directory: "", home: "" }, path: { state: "", config: "", worktree: "", directory: "", home: "" },
project: projectCache.value, project: [],
session_todo: {}, session_todo: {},
provider: { all: [], connected: [], default: {} }, provider: { all: [], connected: [], default: {} },
provider_auth: {}, provider_auth: {},
config: {}, config: {},
reload: undefined, reload: undefined,
}) })
const queryClient = useQueryClient()
let active = true
let projectWritten = false
let bootedAt = 0 let bootedAt = 0
let bootingRoot = false let bootingRoot = false
let eventFrame: number | undefined let eventFrame: number | undefined
let eventTimer: ReturnType<typeof setTimeout> | undefined let eventTimer: ReturnType<typeof setTimeout> | undefined
onCleanup(() => {
active = false
})
onCleanup(() => { onCleanup(() => {
if (eventFrame !== undefined) cancelAnimationFrame(eventFrame) if (eventFrame !== undefined) cancelAnimationFrame(eventFrame)
if (eventTimer !== undefined) clearTimeout(eventTimer) if (eventTimer !== undefined) clearTimeout(eventTimer)
}) })
const cacheProjects = () => { const setProjects = (next: Project[] | ((draft: Project[]) => Project[])) => {
setProjectCache(
"value",
untrack(() => globalStore.project.map(sanitizeProject)),
)
}
const setProjects = (next: Project[] | ((draft: Project[]) => void)) => {
projectWritten = true
if (typeof next === "function") {
setGlobalStore("project", produce(next))
cacheProjects()
return
}
setGlobalStore("project", next) setGlobalStore("project", next)
cacheProjects()
} }
const setBootStore = ((...input: unknown[]) => { const setBootStore = ((...input: unknown[]) => {
@@ -111,22 +90,12 @@ function createGlobalSync() {
const set = ((...input: unknown[]) => { const set = ((...input: unknown[]) => {
if (input[0] === "project" && (Array.isArray(input[1]) || typeof input[1] === "function")) { if (input[0] === "project" && (Array.isArray(input[1]) || typeof input[1] === "function")) {
setProjects(input[1] as Project[] | ((draft: Project[]) => void)) setProjects(input[1] as Project[] | ((draft: Project[]) => Project[]))
return input[1] return input[1]
} }
return (setGlobalStore as (...args: unknown[]) => unknown)(...input) return (setGlobalStore as (...args: unknown[]) => unknown)(...input)
}) as typeof setGlobalStore }) as typeof setGlobalStore
if (projectInit instanceof Promise) {
void projectInit.then(() => {
if (!active) return
if (projectWritten) return
const cached = projectCache.value
if (cached.length === 0) return
setGlobalStore("project", cached)
})
}
const setSessionTodo = (sessionID: string, todos: Todo[] | undefined) => { const setSessionTodo = (sessionID: string, todos: Todo[] | undefined) => {
if (!sessionID) return if (!sessionID) return
if (!todos) { if (!todos) {
@@ -198,7 +167,11 @@ function createGlobalSync() {
} }
const limit = Math.max(store.limit + SESSION_RECENT_LIMIT, SESSION_RECENT_LIMIT) const limit = Math.max(store.limit + SESSION_RECENT_LIMIT, SESSION_RECENT_LIMIT)
const promise = loadRootSessionsWithFallback({ const promise = queryClient
.fetchQuery({
...loadSessionsQuery(directory),
queryFn: () =>
loadRootSessionsWithFallback({
directory, directory,
limit, limit,
list: (query) => globalSDK.client.session.list(query), list: (query) => globalSDK.client.session.list(query),
@@ -214,6 +187,7 @@ function createGlobalSync() {
limit, limit,
permission: store.permission, permission: store.permission,
}) })
batch(() => {
setStore( setStore(
"sessionTotal", "sessionTotal",
estimateRootSessionTotal({ estimateRootSessionTotal({
@@ -224,6 +198,7 @@ function createGlobalSync() {
) )
setStore("session", reconcile(sessions, { key: "id" })) setStore("session", reconcile(sessions, { key: "id" }))
cleanupDroppedSessionCaches(store, setStore, sessions, setSessionTodo) cleanupDroppedSessionCaches(store, setStore, sessions, setSessionTodo)
})
sessionMeta.set(directory, { limit }) sessionMeta.set(directory, { limit })
}) })
.catch((err) => { .catch((err) => {
@@ -235,9 +210,12 @@ function createGlobalSync() {
description: formatServerError(err, language.t), description: formatServerError(err, language.t),
}) })
}) })
.then(() => null),
})
.then(() => {})
sessionLoads.set(directory, promise) sessionLoads.set(directory, promise)
promise.finally(() => { void promise.finally(() => {
sessionLoads.delete(directory) sessionLoads.delete(directory)
children.unpin(directory) children.unpin(directory)
}) })
@@ -250,7 +228,7 @@ function createGlobalSync() {
if (pending) return pending if (pending) return pending
children.pin(directory) children.pin(directory)
const promise = (async () => { const promise = Promise.resolve().then(async () => {
const child = children.ensureChild(directory) const child = children.ensureChild(directory)
const cache = children.vcsCache.get(directory) const cache = children.vcsCache.get(directory)
if (!cache) return if (!cache) return
@@ -269,11 +247,12 @@ function createGlobalSync() {
vcsCache: cache, vcsCache: cache,
loadSessions, loadSessions,
translate: language.t, translate: language.t,
queryClient,
})
}) })
})()
booting.set(directory, promise) booting.set(directory, promise)
promise.finally(() => { void promise.finally(() => {
booting.delete(directory) booting.delete(directory)
children.unpin(directory) children.unpin(directory)
}) })
@@ -285,6 +264,19 @@ function createGlobalSync() {
const event = e.details const event = e.details
const recent = bootingRoot || Date.now() - bootedAt < 1500 const recent = bootingRoot || Date.now() - bootedAt < 1500
if (event.type === "session.error") {
const error = event.properties.error
if (error?.name !== "MessageAbortedError") {
console.error("[global-sync] session error", {
scope: directory === "global" ? "global" : "workspace",
directory: directory === "global" ? undefined : directory,
project: directory === "global" ? undefined : getFilename(directory),
sessionID: event.properties.sessionID,
error,
})
}
}
if (directory === "global") { if (directory === "global") {
applyGlobalEvent({ applyGlobalEvent({
event, event,
@@ -317,7 +309,7 @@ function createGlobalSync() {
setSessionTodo, setSessionTodo,
vcsCache: children.vcsCache.get(directory), vcsCache: children.vcsCache.get(directory),
loadLsp: () => { loadLsp: () => {
sdkFor(directory) void sdkFor(directory)
.lsp.status() .lsp.status()
.then((x) => { .then((x) => {
setStore("lsp", x.data ?? []) setStore("lsp", x.data ?? [])
@@ -346,6 +338,7 @@ function createGlobalSync() {
translate: language.t, translate: language.t,
formatMoreCount: (count) => language.t("common.moreCountSuffix", { count }), formatMoreCount: (count) => language.t("common.moreCountSuffix", { count }),
setGlobalStore: setBootStore, setGlobalStore: setBootStore,
queryClient,
}) })
bootedAt = Date.now() bootedAt = Date.now()
} finally { } finally {
@@ -359,13 +352,13 @@ function createGlobalSync() {
eventFrame = undefined eventFrame = undefined
eventTimer = setTimeout(() => { eventTimer = setTimeout(() => {
eventTimer = undefined eventTimer = undefined
globalSDK.event.start() void globalSDK.event.start()
}, 0) }, 0)
}) })
} else { } else {
eventTimer = setTimeout(() => { eventTimer = setTimeout(() => {
eventTimer = undefined eventTimer = undefined
globalSDK.event.start() void globalSDK.event.start()
}, 0) }, 0)
} }
void bootstrap() void bootstrap()
@@ -11,13 +11,14 @@ import type {
Todo, Todo,
} from "@opencode-ai/sdk/v2/client" } from "@opencode-ai/sdk/v2/client"
import { showToast } from "@opencode-ai/ui/toast" import { showToast } from "@opencode-ai/ui/toast"
import { getFilename } from "@opencode-ai/shared/util/path" import { getFilename } from "@opencode-ai/core/util/path"
import { retry } from "@opencode-ai/shared/util/retry" import { retry } from "@opencode-ai/core/util/retry"
import { batch } from "solid-js" import { batch } from "solid-js"
import { reconcile, type SetStoreFunction, type Store } from "solid-js/store" import { reconcile, type SetStoreFunction, type Store } from "solid-js/store"
import type { State, VcsCache } from "./types" import type { State, VcsCache } from "./types"
import { cmp, normalizeAgentList, normalizeProviderList } from "./utils" import { cmp, normalizeAgentList, normalizeProviderList } from "./utils"
import { formatServerError } from "@/utils/server-errors" import { formatServerError } from "@/utils/server-errors"
import { QueryClient, queryOptions, skipToken } from "@tanstack/solid-query"
type GlobalStore = { type GlobalStore = {
ready: boolean ready: boolean
@@ -65,28 +66,13 @@ function runAll(list: Array<() => Promise<unknown>>) {
return Promise.allSettled(list.map((item) => item())) return Promise.allSettled(list.map((item) => item()))
} }
function showErrors(input: {
errors: unknown[]
title: string
translate: (key: string, vars?: Record<string, string | number>) => string
formatMoreCount: (count: number) => string
}) {
if (input.errors.length === 0) return
const message = formatServerError(input.errors[0], input.translate)
const more = input.errors.length > 1 ? input.formatMoreCount(input.errors.length - 1) : ""
showToast({
variant: "error",
title: input.title,
description: message + more,
})
}
export async function bootstrapGlobal(input: { export async function bootstrapGlobal(input: {
globalSDK: OpencodeClient globalSDK: OpencodeClient
requestFailedTitle: string requestFailedTitle: string
translate: (key: string, vars?: Record<string, string | number>) => string translate: (key: string, vars?: Record<string, string | number>) => string
formatMoreCount: (count: number) => string formatMoreCount: (count: number) => string
setGlobalStore: SetStoreFunction<GlobalStore> setGlobalStore: SetStoreFunction<GlobalStore>
queryClient: QueryClient
}) { }) {
const fast = [ const fast = [
() => () =>
@@ -95,15 +81,20 @@ export async function bootstrapGlobal(input: {
input.setGlobalStore("config", x.data!) input.setGlobalStore("config", x.data!)
}), }),
), ),
() =>
retry(() =>
input.globalSDK.provider.list().then((x) => {
input.setGlobalStore("provider", normalizeProviderList(x.data!))
}),
),
] ]
const slow = [ const slow = [
() =>
input.queryClient.fetchQuery({
...loadProvidersQuery(null),
queryFn: () =>
retry(() =>
input.globalSDK.provider.list().then((x) => {
input.setGlobalStore("provider", normalizeProviderList(x.data!))
return null
}),
),
}),
() => () =>
retry(() => retry(() =>
input.globalSDK.path.get().then((x) => { input.globalSDK.path.get().then((x) => {
@@ -188,6 +179,47 @@ function warmSessions(input: {
).then(() => undefined) ).then(() => undefined)
} }
export const loadProvidersQuery = (directory: string | null) =>
queryOptions<null>({ queryKey: [directory, "providers"], queryFn: skipToken })
export const loadAgentsQuery = (
directory: string | null,
sdk?: OpencodeClient,
transform?: (x: Awaited<ReturnType<OpencodeClient["app"]["agents"]>>) => void,
) =>
queryOptions<null>({
queryKey: [directory, "agents"],
queryFn:
sdk && transform
? () =>
retry(() =>
sdk.app
.agents()
.then(transform)
.then(() => null),
)
: skipToken,
})
export const loadPathQuery = (
directory: string | null,
sdk?: OpencodeClient,
transform?: (x: Awaited<ReturnType<OpencodeClient["path"]["get"]>>) => void,
) =>
queryOptions<Path>({
queryKey: [directory, "path"],
queryFn:
sdk && transform
? () =>
retry(() =>
sdk.path.get().then(async (x) => {
transform(x)
return x.data!
}),
)
: skipToken,
})
export async function bootstrapDirectory(input: { export async function bootstrapDirectory(input: {
directory: string directory: string
sdk: OpencodeClient sdk: OpencodeClient
@@ -202,6 +234,7 @@ export async function bootstrapDirectory(input: {
project: Project[] project: Project[]
provider: ProviderListResponse provider: ProviderListResponse
} }
queryClient: QueryClient
}) { }) {
const loading = input.store.status !== "complete" const loading = input.store.status !== "complete"
const seededProject = projectID(input.directory, input.global.project) const seededProject = projectID(input.directory, input.global.project)
@@ -223,27 +256,27 @@ export async function bootstrapDirectory(input: {
input.setStore("lsp", []) input.setStore("lsp", [])
if (loading) input.setStore("status", "partial") if (loading) input.setStore("status", "partial")
const fast = [ const rev = (providerRev.get(input.directory) ?? 0) + 1
() => retry(() => input.sdk.app.agents().then((x) => input.setStore("agent", normalizeAgentList(x.data)))), providerRev.set(input.directory, rev)
;(async () => {
const slow = [
() => Promise.resolve(input.loadSessions(input.directory)),
() =>
input.queryClient.ensureQueryData(
loadAgentsQuery(input.directory, input.sdk, (x) => input.setStore("agent", normalizeAgentList(x.data))),
),
() => retry(() => input.sdk.config.get().then((x) => input.setStore("config", x.data!))), () => retry(() => input.sdk.config.get().then((x) => input.setStore("config", x.data!))),
() => retry(() => input.sdk.session.status().then((x) => input.setStore("session_status", x.data!))), () => retry(() => input.sdk.session.status().then((x) => input.setStore("session_status", x.data!))),
] !seededProject &&
(() => retry(() => input.sdk.project.current()).then((x) => input.setStore("project", x.data!.id))),
const slow = [ !seededPath &&
() => (() =>
seededProject input.queryClient.ensureQueryData(
? Promise.resolve() loadPathQuery(input.directory, input.sdk, (x) => {
: retry(() => input.sdk.project.current()).then((x) => input.setStore("project", x.data!.id)),
() =>
seededPath
? Promise.resolve()
: retry(() =>
input.sdk.path.get().then((x) => {
input.setStore("path", x.data!)
const next = projectID(x.data?.directory ?? input.directory, input.global.project) const next = projectID(x.data?.directory ?? input.directory, input.global.project)
if (next) input.setStore("project", next) if (next) input.setStore("project", next)
}), }),
), )),
() => () =>
retry(() => retry(() =>
input.sdk.vcs.get().then((x) => { input.sdk.vcs.get().then((x) => {
@@ -313,18 +346,28 @@ export async function bootstrapDirectory(input: {
input.setStore("mcp_ready", true) input.setStore("mcp_ready", true)
}), }),
), ),
] () =>
input.queryClient.ensureQueryData({
const errs = errors(await runAll(fast)) ...loadProvidersQuery(input.directory),
if (errs.length > 0) { queryFn: () =>
console.error("Failed to bootstrap instance", errs[0]) retry(() => input.sdk.provider.list())
.then((x) => {
if (providerRev.get(input.directory) !== rev) return
input.setStore("provider", normalizeProviderList(x.data!))
input.setStore("provider_ready", true)
})
.catch((err) => {
if (providerRev.get(input.directory) !== rev) console.error("Failed to refresh provider list", err)
const project = getFilename(input.directory) const project = getFilename(input.directory)
showToast({ showToast({
variant: "error", variant: "error",
title: input.translate("toast.project.reloadFailed.title", { project }), title: input.translate("toast.project.reloadFailed.title", { project }),
description: formatServerError(errs[0], input.translate), description: formatServerError(err, input.translate),
}) })
} })
.then(() => null),
}),
].filter(Boolean) as (() => Promise<any>)[]
await waitForPaint() await waitForPaint()
const slowErrs = errors(await runAll(slow)) const slowErrs = errors(await runAll(slow))
@@ -338,24 +381,6 @@ export async function bootstrapDirectory(input: {
}) })
} }
if (loading && errs.length === 0 && slowErrs.length === 0) input.setStore("status", "complete") if (loading && slowErrs.length === 0) input.setStore("status", "complete")
})()
const rev = (providerRev.get(input.directory) ?? 0) + 1
providerRev.set(input.directory, rev)
void retry(() => input.sdk.provider.list())
.then((x) => {
if (providerRev.get(input.directory) !== rev) return
input.setStore("provider", normalizeProviderList(x.data!))
input.setStore("provider_ready", true)
})
.catch((err) => {
if (providerRev.get(input.directory) !== rev) return
console.error("Failed to refresh provider list", err)
const project = getFilename(input.directory)
showToast({
variant: "error",
title: input.translate("toast.project.reloadFailed.title", { project }),
description: formatServerError(err, input.translate),
})
})
} }
@@ -14,6 +14,8 @@ import {
type VcsCache, type VcsCache,
} from "./types" } from "./types"
import { canDisposeDirectory, pickDirectoriesToEvict } from "./eviction" import { canDisposeDirectory, pickDirectoriesToEvict } from "./eviction"
import { useQuery } from "@tanstack/solid-query"
import { loadPathQuery } from "./bootstrap"
export function createChildStoreManager(input: { export function createChildStoreManager(input: {
owner: Owner owner: Owner
@@ -154,16 +156,21 @@ export function createChildStoreManager(input: {
const init = () => const init = () =>
createRoot((dispose) => { createRoot((dispose) => {
const initialMeta = meta[0].value
const initialIcon = icon[0].value const initialIcon = icon[0].value
const pathQuery = useQuery(() => loadPathQuery(directory))
const child = createStore<State>({ const child = createStore<State>({
project: "", project: "",
projectMeta: initialMeta, projectMeta: undefined,
icon: initialIcon, icon: initialIcon,
provider_ready: false, provider_ready: false,
provider: { all: [], connected: [], default: {} }, provider: { all: [], connected: [], default: {} },
config: {}, config: {},
path: { state: "", config: "", worktree: "", directory: "", home: "" }, get path() {
if (pathQuery.isLoading || !pathQuery.data)
return { state: "", config: "", worktree: "", directory: "", home: "" }
return pathQuery.data
},
status: "loading" as const, status: "loading" as const,
agent: [], agent: [],
command: [], command: [],
@@ -200,11 +207,6 @@ export function createChildStoreManager(input: {
child[1]("vcs", (value) => value ?? cached) child[1]("vcs", (value) => value ?? cached)
}) })
onPersistedInit(meta[2], () => {
if (child[0].projectMeta !== initialMeta) return
child[1]("projectMeta", meta[0].value)
})
onPersistedInit(icon[2], () => { onPersistedInit(icon[2], () => {
if (child[0].icon !== initialIcon) return if (child[0].icon !== initialIcon) return
child[1]("icon", icon[0].value) child[1]("icon", icon[0].value)
@@ -243,8 +245,8 @@ export function createChildStoreManager(input: {
const cached = metaCache.get(directory) const cached = metaCache.get(directory)
if (!cached) return if (!cached) return
const previous = store.projectMeta ?? {} const previous = store.projectMeta ?? {}
const icon = patch.icon ? { ...(previous.icon ?? {}), ...patch.icon } : previous.icon const icon = patch.icon ? { ...previous.icon, ...patch.icon } : previous.icon
const commands = patch.commands ? { ...(previous.commands ?? {}), ...patch.commands } : previous.commands const commands = patch.commands ? { ...previous.commands, ...patch.commands } : previous.commands
const next = { const next = {
...previous, ...previous,
...patch, ...patch,
@@ -1,4 +1,4 @@
import { Binary } from "@opencode-ai/shared/util/binary" import { Binary } from "@opencode-ai/core/util/binary"
import { produce, reconcile, type SetStoreFunction, type Store } from "solid-js/store" import { produce, reconcile, type SetStoreFunction, type Store } from "solid-js/store"
import type { import type {
Message, Message,
@@ -21,7 +21,7 @@ const SKIP_PARTS = new Set(["patch", "step-start", "step-finish"])
export function applyGlobalEvent(input: { export function applyGlobalEvent(input: {
event: { type: string; properties?: unknown } event: { type: string; properties?: unknown }
project: Project[] project: Project[]
setGlobalProject: (next: Project[] | ((draft: Project[]) => void)) => void setGlobalProject: (next: Project[] | ((draft: Project[]) => Project[])) => void
refresh: () => void refresh: () => void
}) { }) {
if (input.event.type === "global.disposed" || input.event.type === "server.connected") { if (input.event.type === "global.disposed" || input.event.type === "server.connected") {
@@ -33,14 +33,18 @@ export function applyGlobalEvent(input: {
const properties = input.event.properties as Project const properties = input.event.properties as Project
const result = Binary.search(input.project, properties.id, (s) => s.id) const result = Binary.search(input.project, properties.id, (s) => s.id)
if (result.found) { if (result.found) {
input.setGlobalProject((draft) => { input.setGlobalProject(
produce((draft) => {
draft[result.index] = { ...draft[result.index], ...properties } draft[result.index] = { ...draft[result.index], ...properties }
}) }),
)
return return
} }
input.setGlobalProject((draft) => { input.setGlobalProject(
produce((draft) => {
draft.splice(result.index, 0, properties) draft.splice(result.index, 0, properties)
}) }),
)
} }
function cleanupSessionCaches( function cleanupSessionCaches(
@@ -63,6 +63,7 @@ export function createRefreshQueue(input: QueueInput) {
} }
} finally { } finally {
running = false running = false
// oxlint-disable-next-line no-unsafe-finally -- intentional: early return skips schedule() when paused
if (input.paused()) return if (input.paused()) return
if (root || queued.size) schedule() if (root || queued.size) schedule()
} }
@@ -8,7 +8,6 @@ import type {
Part, Part,
Path, Path,
PermissionRequest, PermissionRequest,
Project,
ProviderListResponse, ProviderListResponse,
QuestionRequest, QuestionRequest,
Session, Session,
+4 -34
View File
@@ -344,7 +344,7 @@ export const { use: useLayout, provider: LayoutProvider } = createSimpleContext(
return return
} }
setStore("sessionView", sessionKey, "scroll", (prev) => ({ ...(prev ?? {}), ...next })) setStore("sessionView", sessionKey, "scroll", (prev) => ({ ...prev, ...next }))
prune(keep) prune(keep)
}, },
}) })
@@ -391,37 +391,7 @@ export const { use: useLayout, provider: LayoutProvider } = createSimpleContext(
? globalSync.data.project.find((x) => x.id === projectID) ? globalSync.data.project.find((x) => x.id === projectID)
: globalSync.data.project.find((x) => x.worktree === project.worktree) : globalSync.data.project.find((x) => x.worktree === project.worktree)
const local = childStore.projectMeta return { ...metadata, ...project }
const localOverride =
local?.name !== undefined ||
local?.commands?.start !== undefined ||
local?.icon?.override !== undefined ||
local?.icon?.color !== undefined
const base = {
...(metadata ?? {}),
...project,
icon: {
url: metadata?.icon?.url,
override: metadata?.icon?.override ?? childStore.icon,
color: metadata?.icon?.color,
},
}
const isGlobal = projectID === "global" || (metadata?.id === undefined && localOverride)
if (!isGlobal) return base
return {
...base,
id: base.id ?? "global",
name: local?.name,
commands: local?.commands,
icon: {
url: base.icon?.url,
override: local?.icon?.override,
color: local?.icon?.color,
},
}
} }
const roots = createMemo(() => { const roots = createMemo(() => {
@@ -516,7 +486,7 @@ export const { use: useLayout, provider: LayoutProvider } = createSimpleContext(
} }
for (const project of projects) { for (const project of projects) {
if (project.icon?.color) continue if (project.icon?.color || project.icon?.override || project.icon?.url) continue
const worktree = project.worktree const worktree = project.worktree
const existing = colors[worktree] const existing = colors[worktree]
const color = existing ?? pickAvailableColor(used) const color = existing ?? pickAvailableColor(used)
@@ -582,7 +552,7 @@ export const { use: useLayout, provider: LayoutProvider } = createSimpleContext(
open(directory: string) { open(directory: string) {
const root = rootFor(directory) const root = rootFor(directory)
if (server.projects.list().find((x) => x.worktree === root)) return if (server.projects.list().find((x) => x.worktree === root)) return
globalSync.project.loadSessions(root) void globalSync.project.loadSessions(root)
server.projects.open(root) server.projects.open(root)
}, },
close(directory: string) { close(directory: string) {
+1 -1
View File
@@ -1,5 +1,5 @@
import { createSimpleContext } from "@opencode-ai/ui/context" import { createSimpleContext } from "@opencode-ai/ui/context"
import { base64Encode } from "@opencode-ai/shared/util/encode" import { base64Encode } from "@opencode-ai/core/util/encode"
import { useParams } from "@solidjs/router" import { useParams } from "@solidjs/router"
import { batch, createEffect, createMemo } from "solid-js" import { batch, createEffect, createMemo } from "solid-js"
import { createStore } from "solid-js/store" import { createStore } from "solid-js/store"
+2 -2
View File
@@ -7,8 +7,8 @@ import { useGlobalSync } from "./global-sync"
import { usePlatform } from "@/context/platform" import { usePlatform } from "@/context/platform"
import { useLanguage } from "@/context/language" import { useLanguage } from "@/context/language"
import { useSettings } from "@/context/settings" import { useSettings } from "@/context/settings"
import { Binary } from "@opencode-ai/shared/util/binary" import { Binary } from "@opencode-ai/core/util/binary"
import { base64Encode } from "@opencode-ai/shared/util/encode" import { base64Encode } from "@opencode-ai/core/util/encode"
import { decode64 } from "@/utils/base64" import { decode64 } from "@/utils/base64"
import { EventSessionError } from "@opencode-ai/sdk/v2" import { EventSessionError } from "@opencode-ai/sdk/v2"
import { Persist, persisted } from "@/utils/persist" import { Persist, persisted } from "@/utils/persist"
@@ -1,6 +1,6 @@
import { describe, expect, test } from "bun:test" import { describe, expect, test } from "bun:test"
import type { PermissionRequest, Session } from "@opencode-ai/sdk/v2/client" import type { PermissionRequest, Session } from "@opencode-ai/sdk/v2/client"
import { base64Encode } from "@opencode-ai/shared/util/encode" import { base64Encode } from "@opencode-ai/core/util/encode"
import { autoRespondsPermission, isDirectoryAutoAccepting } from "./permission-auto-respond" import { autoRespondsPermission, isDirectoryAutoAccepting } from "./permission-auto-respond"
const session = (input: { id: string; parentID?: string }) => const session = (input: { id: string; parentID?: string }) =>
@@ -1,4 +1,4 @@
import { base64Encode } from "@opencode-ai/shared/util/encode" import { base64Encode } from "@opencode-ai/core/util/encode"
export function acceptKey(sessionID: string, directory?: string) { export function acceptKey(sessionID: string, directory?: string) {
if (!directory) return sessionID if (!directory) return sessionID
+3 -3
View File
@@ -49,11 +49,11 @@ export type Platform = {
/** Storage mechanism, defaults to localStorage */ /** Storage mechanism, defaults to localStorage */
storage?: (name?: string) => SyncStorage | AsyncStorage storage?: (name?: string) => SyncStorage | AsyncStorage
/** Check for updates (Tauri only) */ /** Check for a downloadable desktop update */
checkUpdate?(): Promise<UpdateInfo> checkUpdate?(): Promise<UpdateInfo>
/** Install updates (Tauri only) */ /** Install the downloaded update using the platform restart flow */
update?(): Promise<void> updateAndRestart?(): Promise<void>
/** Fetch override */ /** Fetch override */
fetch?: typeof fetch fetch?: typeof fetch
+4 -4
View File
@@ -1,5 +1,5 @@
import { createSimpleContext } from "@opencode-ai/ui/context" import { createSimpleContext } from "@opencode-ai/ui/context"
import { checksum } from "@opencode-ai/shared/util/encode" import { checksum } from "@opencode-ai/core/util/encode"
import { useParams } from "@solidjs/router" import { useParams } from "@solidjs/router"
import { batch, createMemo, createRoot, getOwner, onCleanup } from "solid-js" import { batch, createMemo, createRoot, getOwner, onCleanup } from "solid-js"
import { createStore, type SetStoreFunction } from "solid-js/store" import { createStore, type SetStoreFunction } from "solid-js/store"
@@ -185,9 +185,9 @@ function createPromptSession(dir: string, id: string | undefined) {
return { return {
ready, ready,
current: createMemo(() => store.prompt), current: () => store.prompt,
cursor: createMemo(() => store.cursor), cursor: createMemo(() => store.cursor),
dirty: createMemo(() => !isPromptEqual(store.prompt, DEFAULT_PROMPT)), dirty: () => !isPromptEqual(store.prompt, DEFAULT_PROMPT),
context: { context: {
items: createMemo(() => store.context.items), items: createMemo(() => store.context.items),
add(item: ContextItem) { add(item: ContextItem) {
@@ -277,7 +277,7 @@ export const { use: usePrompt, provider: PromptProvider } = createSimpleContext(
const pick = (scope?: Scope) => (scope ? load(scope.dir, scope.id) : session()) const pick = (scope?: Scope) => (scope ? load(scope.dir, scope.id) : session())
return { return {
ready: () => session().ready(), ready: () => session().ready,
current: () => session().current(), current: () => session().current(),
cursor: () => session().cursor(), cursor: () => session().cursor(),
dirty: () => session().dirty(), dirty: () => session().dirty(),
+57
View File
@@ -23,9 +23,15 @@ export interface Settings {
autoSave: boolean autoSave: boolean
releaseNotes: boolean releaseNotes: boolean
followup: "queue" | "steer" followup: "queue" | "steer"
showFileTree: boolean
showNavigation: boolean
showSearch: boolean
showStatus: boolean
showTerminal: boolean
showReasoningSummaries: boolean showReasoningSummaries: boolean
shellToolPartsExpanded: boolean shellToolPartsExpanded: boolean
editToolPartsExpanded: boolean editToolPartsExpanded: boolean
showSessionProgressBar: boolean
} }
updates: { updates: {
startup: boolean startup: boolean
@@ -34,6 +40,7 @@ export interface Settings {
fontSize: number fontSize: number
mono: string mono: string
sans: string sans: string
terminal: string
} }
keybinds: Record<string, string> keybinds: Record<string, string>
permissions: { permissions: {
@@ -45,13 +52,17 @@ export interface Settings {
export const monoDefault = "System Mono" export const monoDefault = "System Mono"
export const sansDefault = "System Sans" export const sansDefault = "System Sans"
export const terminalDefault = "JetBrainsMono Nerd Font Mono"
const monoFallback = const monoFallback =
'ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace' 'ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace'
const sansFallback = 'ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif' const sansFallback = 'ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif'
const terminalFallback =
'"JetBrainsMono Nerd Font Mono", ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace'
const monoBase = monoFallback const monoBase = monoFallback
const sansBase = sansFallback const sansBase = sansFallback
const terminalBase = terminalFallback
function input(font: string | undefined) { function input(font: string | undefined) {
return font ?? "" return font ?? ""
@@ -84,14 +95,28 @@ export function sansFontFamily(font: string | undefined) {
return stack(font, sansBase) return stack(font, sansBase)
} }
export function terminalInput(font: string | undefined) {
return input(font)
}
export function terminalFontFamily(font: string | undefined) {
return stack(font, terminalBase)
}
const defaultSettings: Settings = { const defaultSettings: Settings = {
general: { general: {
autoSave: true, autoSave: true,
releaseNotes: true, releaseNotes: true,
followup: "steer", followup: "steer",
showFileTree: false,
showNavigation: false,
showSearch: false,
showStatus: false,
showTerminal: false,
showReasoningSummaries: false, showReasoningSummaries: false,
shellToolPartsExpanded: false, shellToolPartsExpanded: false,
editToolPartsExpanded: false, editToolPartsExpanded: false,
showSessionProgressBar: true,
}, },
updates: { updates: {
startup: true, startup: true,
@@ -100,6 +125,7 @@ const defaultSettings: Settings = {
fontSize: 14, fontSize: 14,
mono: "", mono: "",
sans: "", sans: "",
terminal: "",
}, },
keybinds: {}, keybinds: {},
permissions: { permissions: {
@@ -162,6 +188,26 @@ export const { use: useSettings, provider: SettingsProvider } = createSimpleCont
setFollowup(value: "queue" | "steer") { setFollowup(value: "queue" | "steer") {
setStore("general", "followup", value === "queue" ? "steer" : value) setStore("general", "followup", value === "queue" ? "steer" : value)
}, },
showFileTree: withFallback(() => store.general?.showFileTree, defaultSettings.general.showFileTree),
setShowFileTree(value: boolean) {
setStore("general", "showFileTree", value)
},
showNavigation: withFallback(() => store.general?.showNavigation, defaultSettings.general.showNavigation),
setShowNavigation(value: boolean) {
setStore("general", "showNavigation", value)
},
showSearch: withFallback(() => store.general?.showSearch, defaultSettings.general.showSearch),
setShowSearch(value: boolean) {
setStore("general", "showSearch", value)
},
showStatus: withFallback(() => store.general?.showStatus, defaultSettings.general.showStatus),
setShowStatus(value: boolean) {
setStore("general", "showStatus", value)
},
showTerminal: withFallback(() => store.general?.showTerminal, defaultSettings.general.showTerminal),
setShowTerminal(value: boolean) {
setStore("general", "showTerminal", value)
},
showReasoningSummaries: withFallback( showReasoningSummaries: withFallback(
() => store.general?.showReasoningSummaries, () => store.general?.showReasoningSummaries,
defaultSettings.general.showReasoningSummaries, defaultSettings.general.showReasoningSummaries,
@@ -183,6 +229,13 @@ export const { use: useSettings, provider: SettingsProvider } = createSimpleCont
setEditToolPartsExpanded(value: boolean) { setEditToolPartsExpanded(value: boolean) {
setStore("general", "editToolPartsExpanded", value) setStore("general", "editToolPartsExpanded", value)
}, },
showSessionProgressBar: withFallback(
() => store.general?.showSessionProgressBar,
defaultSettings.general.showSessionProgressBar,
),
setShowSessionProgressBar(value: boolean) {
setStore("general", "showSessionProgressBar", value)
},
}, },
updates: { updates: {
startup: withFallback(() => store.updates?.startup, defaultSettings.updates.startup), startup: withFallback(() => store.updates?.startup, defaultSettings.updates.startup),
@@ -203,6 +256,10 @@ export const { use: useSettings, provider: SettingsProvider } = createSimpleCont
setUIFont(value: string) { setUIFont(value: string) {
setStore("appearance", "sans", value.trim() ? value : "") setStore("appearance", "sans", value.trim() ? value : "")
}, },
terminalFont: withFallback(() => store.appearance?.terminal, defaultSettings.appearance.terminal),
setTerminalFont(value: string) {
setStore("appearance", "terminal", value.trim() ? value : "")
},
}, },
keybinds: { keybinds: {
get: (action: string) => store.keybinds?.[action], get: (action: string) => store.keybinds?.[action],
+2 -2
View File
@@ -1,7 +1,7 @@
import { batch, createMemo } from "solid-js" import { batch, createMemo } from "solid-js"
import { createStore, produce, reconcile } from "solid-js/store" import { createStore, produce, reconcile } from "solid-js/store"
import { Binary } from "@opencode-ai/shared/util/binary" import { Binary } from "@opencode-ai/core/util/binary"
import { retry } from "@opencode-ai/shared/util/retry" import { retry } from "@opencode-ai/core/util/retry"
import { createSimpleContext } from "@opencode-ai/ui/context" import { createSimpleContext } from "@opencode-ai/ui/context"
import { import {
clearSessionPrefetch, clearSessionPrefetch,
+2 -2
View File
@@ -117,7 +117,7 @@ export function clearWorkspaceTerminals(dir: string, sessionIDs?: string[], plat
entry?.value.clear() entry?.value.clear()
} }
removePersisted(Persist.workspace(dir, "terminal"), platform) void removePersisted(Persist.workspace(dir, "terminal"), platform)
const legacy = new Set(getLegacyTerminalStorageKeys(dir)) const legacy = new Set(getLegacyTerminalStorageKeys(dir))
for (const id of sessionIDs ?? []) { for (const id of sessionIDs ?? []) {
@@ -126,7 +126,7 @@ export function clearWorkspaceTerminals(dir: string, sessionIDs?: string[], plat
} }
} }
for (const key of legacy) { for (const key of legacy) {
removePersisted({ key }, platform) void removePersisted({ key }, platform)
} }
} }
+2 -3
View File
@@ -1,15 +1,14 @@
import "solid-js"
interface ImportMetaEnv { interface ImportMetaEnv {
readonly VITE_OPENCODE_SERVER_HOST: string readonly VITE_OPENCODE_SERVER_HOST: string
readonly VITE_OPENCODE_SERVER_PORT: string readonly VITE_OPENCODE_SERVER_PORT: string
readonly VITE_OPENCODE_CHANNEL?: "dev" | "beta" | "prod"
} }
interface ImportMeta { interface ImportMeta {
readonly env: ImportMetaEnv readonly env: ImportMetaEnv
} }
declare module "solid-js" { export declare module "solid-js" {
namespace JSX { namespace JSX {
interface Directives { interface Directives {
sortable: true sortable: true
+6 -2
View File
@@ -210,7 +210,7 @@ export const dict = {
"common.saving": "جارٍ الحفظ...", "common.saving": "جارٍ الحفظ...",
"common.default": "افتراضي", "common.default": "افتراضي",
"common.attachment": "مرفق", "common.attachment": "مرفق",
"prompt.placeholder.shell": "أدخل أمر shell...", "prompt.placeholder.shell": "أدخل أمر shell... {{example}}",
"prompt.placeholder.normal": 'اسأل أي شيء... "{{example}}"', "prompt.placeholder.normal": 'اسأل أي شيء... "{{example}}"',
"prompt.placeholder.simple": "اسأل أي شيء...", "prompt.placeholder.simple": "اسأل أي شيء...",
"prompt.placeholder.summarizeComments": "لخّص التعليقات…", "prompt.placeholder.summarizeComments": "لخّص التعليقات…",
@@ -565,7 +565,9 @@ export const dict = {
"settings.general.row.theme.title": "السمة", "settings.general.row.theme.title": "السمة",
"settings.general.row.theme.description": "تخصيص سمة OpenCode.", "settings.general.row.theme.description": "تخصيص سمة OpenCode.",
"settings.general.row.font.title": "خط الكود", "settings.general.row.font.title": "خط الكود",
"settings.general.row.font.description": "خصّص الخط المستخدم في كتل التعليمات البرمجية والطرفيات", "settings.general.row.font.description": "خصّص الخط المستخدم في كتل التعليمات البرمجية",
"settings.general.row.terminalFont.title": "Terminal Font",
"settings.general.row.terminalFont.description": "Customise the font used in the terminal",
"settings.general.row.uiFont.title": "خط الواجهة", "settings.general.row.uiFont.title": "خط الواجهة",
"settings.general.row.uiFont.description": "خصّص الخط المستخدم في الواجهة بأكملها", "settings.general.row.uiFont.description": "خصّص الخط المستخدم في الواجهة بأكملها",
"settings.general.row.followup.title": "سلوك المتابعة", "settings.general.row.followup.title": "سلوك المتابعة",
@@ -580,6 +582,8 @@ export const dict = {
"settings.general.row.editToolPartsExpanded.title": "توسيع أجزاء أداة edit", "settings.general.row.editToolPartsExpanded.title": "توسيع أجزاء أداة edit",
"settings.general.row.editToolPartsExpanded.description": "settings.general.row.editToolPartsExpanded.description":
"إظهار أجزاء أدوات edit و write و patch موسعة بشكل افتراضي في الشريط الزمني", "إظهار أجزاء أدوات edit و write و patch موسعة بشكل افتراضي في الشريط الزمني",
"settings.general.row.showSessionProgressBar.title": "إظهار شريط تقدم الجلسة",
"settings.general.row.showSessionProgressBar.description": "عرض شريط التقدم المتحرك أعلى الجلسة أثناء عمل الوكيل",
"settings.general.row.wayland.title": "استخدام Wayland الأصلي", "settings.general.row.wayland.title": "استخدام Wayland الأصلي",
"settings.general.row.wayland.description": "تعطيل التراجع إلى X11 على Wayland. يتطلب إعادة التشغيل.", "settings.general.row.wayland.description": "تعطيل التراجع إلى X11 على Wayland. يتطلب إعادة التشغيل.",
"settings.general.row.wayland.tooltip": "settings.general.row.wayland.tooltip":
+7 -2
View File
@@ -210,7 +210,7 @@ export const dict = {
"common.saving": "Salvando...", "common.saving": "Salvando...",
"common.default": "Padrão", "common.default": "Padrão",
"common.attachment": "anexo", "common.attachment": "anexo",
"prompt.placeholder.shell": "Digite comando do shell...", "prompt.placeholder.shell": "Digite comando do shell... {{example}}",
"prompt.placeholder.normal": 'Pergunte qualquer coisa... "{{example}}"', "prompt.placeholder.normal": 'Pergunte qualquer coisa... "{{example}}"',
"prompt.placeholder.simple": "Pergunte qualquer coisa...", "prompt.placeholder.simple": "Pergunte qualquer coisa...",
"prompt.placeholder.summarizeComments": "Resumir comentários…", "prompt.placeholder.summarizeComments": "Resumir comentários…",
@@ -572,7 +572,9 @@ export const dict = {
"settings.general.row.theme.title": "Tema", "settings.general.row.theme.title": "Tema",
"settings.general.row.theme.description": "Personalize como o OpenCode é tematizado.", "settings.general.row.theme.description": "Personalize como o OpenCode é tematizado.",
"settings.general.row.font.title": "Fonte de código", "settings.general.row.font.title": "Fonte de código",
"settings.general.row.font.description": "Personalize a fonte usada em blocos de código e terminais", "settings.general.row.font.description": "Personalize a fonte usada em blocos de código",
"settings.general.row.terminalFont.title": "Terminal Font",
"settings.general.row.terminalFont.description": "Customise the font used in the terminal",
"settings.general.row.uiFont.title": "Fonte da interface", "settings.general.row.uiFont.title": "Fonte da interface",
"settings.general.row.uiFont.description": "Personalize a fonte usada em toda a interface", "settings.general.row.uiFont.description": "Personalize a fonte usada em toda a interface",
"settings.general.row.followup.title": "Comportamento de acompanhamento", "settings.general.row.followup.title": "Comportamento de acompanhamento",
@@ -588,6 +590,9 @@ export const dict = {
"settings.general.row.editToolPartsExpanded.title": "Expandir partes da ferramenta de edição", "settings.general.row.editToolPartsExpanded.title": "Expandir partes da ferramenta de edição",
"settings.general.row.editToolPartsExpanded.description": "settings.general.row.editToolPartsExpanded.description":
"Mostrar partes das ferramentas de edição, escrita e patch expandidas por padrão na linha do tempo", "Mostrar partes das ferramentas de edição, escrita e patch expandidas por padrão na linha do tempo",
"settings.general.row.showSessionProgressBar.title": "Mostrar barra de progresso da sessão",
"settings.general.row.showSessionProgressBar.description":
"Exibir a barra de progresso animada no topo da sessão quando o agente estiver trabalhando",
"settings.general.row.wayland.title": "Usar Wayland nativo", "settings.general.row.wayland.title": "Usar Wayland nativo",
"settings.general.row.wayland.description": "Desabilitar fallback X11 no Wayland. Requer reinicialização.", "settings.general.row.wayland.description": "Desabilitar fallback X11 no Wayland. Requer reinicialização.",
"settings.general.row.wayland.tooltip": "settings.general.row.wayland.tooltip":
+7 -2
View File
@@ -228,7 +228,7 @@ export const dict = {
"common.default": "Podrazumijevano", "common.default": "Podrazumijevano",
"common.attachment": "prilog", "common.attachment": "prilog",
"prompt.placeholder.shell": "Unesi shell naredbu...", "prompt.placeholder.shell": "Unesi shell naredbu... {{example}}",
"prompt.placeholder.normal": 'Pitaj bilo šta... "{{example}}"', "prompt.placeholder.normal": 'Pitaj bilo šta... "{{example}}"',
"prompt.placeholder.simple": "Pitaj bilo šta...", "prompt.placeholder.simple": "Pitaj bilo šta...",
"prompt.placeholder.summarizeComments": "Sažmi komentare…", "prompt.placeholder.summarizeComments": "Sažmi komentare…",
@@ -637,7 +637,9 @@ export const dict = {
"settings.general.row.theme.title": "Tema", "settings.general.row.theme.title": "Tema",
"settings.general.row.theme.description": "Prilagodi temu OpenCode-a.", "settings.general.row.theme.description": "Prilagodi temu OpenCode-a.",
"settings.general.row.font.title": "Font za kod", "settings.general.row.font.title": "Font za kod",
"settings.general.row.font.description": "Prilagodi font koji se koristi u blokovima koda i terminalima", "settings.general.row.font.description": "Prilagodi font koji se koristi u blokovima koda",
"settings.general.row.terminalFont.title": "Terminal Font",
"settings.general.row.terminalFont.description": "Customise the font used in the terminal",
"settings.general.row.uiFont.title": "UI font", "settings.general.row.uiFont.title": "UI font",
"settings.general.row.uiFont.description": "Prilagodi font koji se koristi u cijelom interfejsu", "settings.general.row.uiFont.description": "Prilagodi font koji se koristi u cijelom interfejsu",
"settings.general.row.followup.title": "Ponašanje nadovezivanja", "settings.general.row.followup.title": "Ponašanje nadovezivanja",
@@ -653,6 +655,9 @@ export const dict = {
"settings.general.row.editToolPartsExpanded.title": "Proširi dijelove alata za uređivanje", "settings.general.row.editToolPartsExpanded.title": "Proširi dijelove alata za uređivanje",
"settings.general.row.editToolPartsExpanded.description": "settings.general.row.editToolPartsExpanded.description":
"Prikaži dijelove alata za uređivanje, pisanje i patch podrazumijevano proširene na vremenskoj traci", "Prikaži dijelove alata za uređivanje, pisanje i patch podrazumijevano proširene na vremenskoj traci",
"settings.general.row.showSessionProgressBar.title": "Prikaži traku napretka sesije",
"settings.general.row.showSessionProgressBar.description":
"Prikaži animiranu traku napretka na vrhu sesije kada agent radi",
"settings.general.row.wayland.title": "Koristi nativni Wayland", "settings.general.row.wayland.title": "Koristi nativni Wayland",
"settings.general.row.wayland.description": "Onemogući X11 fallback na Waylandu. Zahtijeva restart.", "settings.general.row.wayland.description": "Onemogući X11 fallback na Waylandu. Zahtijeva restart.",
"settings.general.row.wayland.tooltip": "settings.general.row.wayland.tooltip":
+7 -2
View File
@@ -226,7 +226,7 @@ export const dict = {
"common.default": "Standard", "common.default": "Standard",
"common.attachment": "vedhæftning", "common.attachment": "vedhæftning",
"prompt.placeholder.shell": "Indtast shell-kommando...", "prompt.placeholder.shell": "Indtast shell-kommando... {{example}}",
"prompt.placeholder.normal": 'Spørg om hvad som helst... "{{example}}"', "prompt.placeholder.normal": 'Spørg om hvad som helst... "{{example}}"',
"prompt.placeholder.simple": "Spørg om hvad som helst...", "prompt.placeholder.simple": "Spørg om hvad som helst...",
"prompt.placeholder.summarizeComments": "Opsummér kommentarer…", "prompt.placeholder.summarizeComments": "Opsummér kommentarer…",
@@ -632,7 +632,9 @@ export const dict = {
"settings.general.row.theme.title": "Tema", "settings.general.row.theme.title": "Tema",
"settings.general.row.theme.description": "Tilpas hvordan OpenCode er temabestemt.", "settings.general.row.theme.description": "Tilpas hvordan OpenCode er temabestemt.",
"settings.general.row.font.title": "Kode-skrifttype", "settings.general.row.font.title": "Kode-skrifttype",
"settings.general.row.font.description": "Tilpas skrifttypen, der bruges i kodeblokke og terminaler", "settings.general.row.font.description": "Tilpas skrifttypen, der bruges i kodeblokke",
"settings.general.row.terminalFont.title": "Terminal Font",
"settings.general.row.terminalFont.description": "Customise the font used in the terminal",
"settings.general.row.uiFont.title": "UI-skrifttype", "settings.general.row.uiFont.title": "UI-skrifttype",
"settings.general.row.uiFont.description": "Tilpas skrifttypen, der bruges i hele brugerfladen", "settings.general.row.uiFont.description": "Tilpas skrifttypen, der bruges i hele brugerfladen",
"settings.general.row.followup.title": "Opfølgningsadfærd", "settings.general.row.followup.title": "Opfølgningsadfærd",
@@ -647,6 +649,9 @@ export const dict = {
"settings.general.row.editToolPartsExpanded.title": "Udvid edit-værktøjsdele", "settings.general.row.editToolPartsExpanded.title": "Udvid edit-værktøjsdele",
"settings.general.row.editToolPartsExpanded.description": "settings.general.row.editToolPartsExpanded.description":
"Vis edit-, write- og patch-værktøjsdele udvidet som standard i tidslinjen", "Vis edit-, write- og patch-værktøjsdele udvidet som standard i tidslinjen",
"settings.general.row.showSessionProgressBar.title": "Vis sessionens fremdriftslinje",
"settings.general.row.showSessionProgressBar.description":
"Vis den animerede fremdriftslinje øverst i sessionen, når agenten arbejder",
"settings.general.row.wayland.title": "Brug native Wayland", "settings.general.row.wayland.title": "Brug native Wayland",
"settings.general.row.wayland.description": "Deaktiver X11-fallback på Wayland. Kræver genstart.", "settings.general.row.wayland.description": "Deaktiver X11-fallback på Wayland. Kræver genstart.",
"settings.general.row.wayland.tooltip": "settings.general.row.wayland.tooltip":
+7 -2
View File
@@ -215,7 +215,7 @@ export const dict = {
"common.saving": "Speichert...", "common.saving": "Speichert...",
"common.default": "Standard", "common.default": "Standard",
"common.attachment": "Anhang", "common.attachment": "Anhang",
"prompt.placeholder.shell": "Shell-Befehl eingeben...", "prompt.placeholder.shell": "Shell-Befehl eingeben... {{example}}",
"prompt.placeholder.normal": 'Fragen Sie alles... "{{example}}"', "prompt.placeholder.normal": 'Fragen Sie alles... "{{example}}"',
"prompt.placeholder.simple": "Fragen Sie alles...", "prompt.placeholder.simple": "Fragen Sie alles...",
"prompt.placeholder.summarizeComments": "Kommentare zusammenfassen…", "prompt.placeholder.summarizeComments": "Kommentare zusammenfassen…",
@@ -582,7 +582,9 @@ export const dict = {
"settings.general.row.theme.title": "Thema", "settings.general.row.theme.title": "Thema",
"settings.general.row.theme.description": "Das Thema von OpenCode anpassen.", "settings.general.row.theme.description": "Das Thema von OpenCode anpassen.",
"settings.general.row.font.title": "Code-Schriftart", "settings.general.row.font.title": "Code-Schriftart",
"settings.general.row.font.description": "Die in Codeblöcken und Terminals verwendete Schriftart anpassen", "settings.general.row.font.description": "Die in Codeblöcken verwendete Schriftart anpassen",
"settings.general.row.terminalFont.title": "Terminal Font",
"settings.general.row.terminalFont.description": "Customise the font used in the terminal",
"settings.general.row.uiFont.title": "UI-Schriftart", "settings.general.row.uiFont.title": "UI-Schriftart",
"settings.general.row.uiFont.description": "Die im gesamten Interface verwendete Schriftart anpassen", "settings.general.row.uiFont.description": "Die im gesamten Interface verwendete Schriftart anpassen",
"settings.general.row.followup.title": "Verhalten bei Folgefragen", "settings.general.row.followup.title": "Verhalten bei Folgefragen",
@@ -599,6 +601,9 @@ export const dict = {
"settings.general.row.editToolPartsExpanded.title": "Edit-Tool-Abschnitte ausklappen", "settings.general.row.editToolPartsExpanded.title": "Edit-Tool-Abschnitte ausklappen",
"settings.general.row.editToolPartsExpanded.description": "settings.general.row.editToolPartsExpanded.description":
"Edit-, Write- und Patch-Tool-Abschnitte standardmäßig in der Timeline ausgeklappt anzeigen", "Edit-, Write- und Patch-Tool-Abschnitte standardmäßig in der Timeline ausgeklappt anzeigen",
"settings.general.row.showSessionProgressBar.title": "Sitzungsfortschrittsleiste anzeigen",
"settings.general.row.showSessionProgressBar.description":
"Die animierte Fortschrittsleiste oben in der Sitzung anzeigen, wenn der Agent arbeitet",
"settings.general.row.wayland.title": "Natives Wayland verwenden", "settings.general.row.wayland.title": "Natives Wayland verwenden",
"settings.general.row.wayland.description": "X11-Fallback unter Wayland deaktivieren. Erfordert Neustart.", "settings.general.row.wayland.description": "X11-Fallback unter Wayland deaktivieren. Erfordert Neustart.",
"settings.general.row.wayland.tooltip": "settings.general.row.wayland.tooltip":
+18 -2
View File
@@ -230,7 +230,7 @@ export const dict = {
"common.default": "Default", "common.default": "Default",
"common.attachment": "attachment", "common.attachment": "attachment",
"prompt.placeholder.shell": "Enter shell command...", "prompt.placeholder.shell": "Enter shell command... {{example}}",
"prompt.placeholder.normal": 'Ask anything... "{{example}}"', "prompt.placeholder.normal": 'Ask anything... "{{example}}"',
"prompt.placeholder.simple": "Ask anything...", "prompt.placeholder.simple": "Ask anything...",
"prompt.placeholder.summarizeComments": "Summarize comments…", "prompt.placeholder.summarizeComments": "Summarize comments…",
@@ -719,6 +719,7 @@ export const dict = {
"settings.desktop.wsl.description": "Run the OpenCode server inside WSL on Windows.", "settings.desktop.wsl.description": "Run the OpenCode server inside WSL on Windows.",
"settings.general.section.appearance": "Appearance", "settings.general.section.appearance": "Appearance",
"settings.general.section.advanced": "Advanced",
"settings.general.section.notifications": "System notifications", "settings.general.section.notifications": "System notifications",
"settings.general.section.updates": "Updates", "settings.general.section.updates": "Updates",
"settings.general.section.sounds": "Sound effects", "settings.general.section.sounds": "Sound effects",
@@ -734,13 +735,25 @@ export const dict = {
"settings.general.row.theme.title": "Theme", "settings.general.row.theme.title": "Theme",
"settings.general.row.theme.description": "Customise how OpenCode is themed.", "settings.general.row.theme.description": "Customise how OpenCode is themed.",
"settings.general.row.font.title": "Code Font", "settings.general.row.font.title": "Code Font",
"settings.general.row.font.description": "Customise the font used in code blocks and terminals", "settings.general.row.font.description": "Customise the font used in code blocks",
"settings.general.row.terminalFont.title": "Terminal Font",
"settings.general.row.terminalFont.description": "Customise the font used in the terminal",
"settings.general.row.uiFont.title": "UI Font", "settings.general.row.uiFont.title": "UI Font",
"settings.general.row.uiFont.description": "Customise the font used throughout the interface", "settings.general.row.uiFont.description": "Customise the font used throughout the interface",
"settings.general.row.followup.title": "Follow-up behavior", "settings.general.row.followup.title": "Follow-up behavior",
"settings.general.row.followup.description": "Choose whether follow-up prompts steer immediately or wait in a queue", "settings.general.row.followup.description": "Choose whether follow-up prompts steer immediately or wait in a queue",
"settings.general.row.followup.option.queue": "Queue", "settings.general.row.followup.option.queue": "Queue",
"settings.general.row.followup.option.steer": "Steer", "settings.general.row.followup.option.steer": "Steer",
"settings.general.row.showFileTree.title": "File tree",
"settings.general.row.showFileTree.description": "Show the file tree toggle and panel in desktop sessions",
"settings.general.row.showNavigation.title": "Navigation controls",
"settings.general.row.showNavigation.description": "Show the back and forward buttons in the desktop title bar",
"settings.general.row.showSearch.title": "Command palette",
"settings.general.row.showSearch.description": "Show the search and command palette button in the desktop title bar",
"settings.general.row.showTerminal.title": "Terminal",
"settings.general.row.showTerminal.description": "Show the terminal button in the desktop title bar",
"settings.general.row.showStatus.title": "Server status",
"settings.general.row.showStatus.description": "Show the server status button in the desktop title bar",
"settings.general.row.reasoningSummaries.title": "Show reasoning summaries", "settings.general.row.reasoningSummaries.title": "Show reasoning summaries",
"settings.general.row.reasoningSummaries.description": "Display model reasoning summaries in the timeline", "settings.general.row.reasoningSummaries.description": "Display model reasoning summaries in the timeline",
"settings.general.row.shellToolPartsExpanded.title": "Expand shell tool parts", "settings.general.row.shellToolPartsExpanded.title": "Expand shell tool parts",
@@ -749,6 +762,9 @@ export const dict = {
"settings.general.row.editToolPartsExpanded.title": "Expand edit tool parts", "settings.general.row.editToolPartsExpanded.title": "Expand edit tool parts",
"settings.general.row.editToolPartsExpanded.description": "settings.general.row.editToolPartsExpanded.description":
"Show edit, write, and patch tool parts expanded by default in the timeline", "Show edit, write, and patch tool parts expanded by default in the timeline",
"settings.general.row.showSessionProgressBar.title": "Show session progress bar",
"settings.general.row.showSessionProgressBar.description":
"Display the animated progress bar at the top of the session when the agent is working",
"settings.general.row.wayland.title": "Use native Wayland", "settings.general.row.wayland.title": "Use native Wayland",
"settings.general.row.wayland.description": "Disable X11 fallback on Wayland. Requires restart.", "settings.general.row.wayland.description": "Disable X11 fallback on Wayland. Requires restart.",
+7 -2
View File
@@ -227,7 +227,7 @@ export const dict = {
"common.default": "Predeterminado", "common.default": "Predeterminado",
"common.attachment": "adjunto", "common.attachment": "adjunto",
"prompt.placeholder.shell": "Introduce comando de shell...", "prompt.placeholder.shell": "Introduce comando de shell... {{example}}",
"prompt.placeholder.normal": 'Pregunta cualquier cosa... "{{example}}"', "prompt.placeholder.normal": 'Pregunta cualquier cosa... "{{example}}"',
"prompt.placeholder.simple": "Pregunta cualquier cosa...", "prompt.placeholder.simple": "Pregunta cualquier cosa...",
"prompt.placeholder.summarizeComments": "Resumir comentarios…", "prompt.placeholder.summarizeComments": "Resumir comentarios…",
@@ -640,7 +640,9 @@ export const dict = {
"settings.general.row.theme.title": "Tema", "settings.general.row.theme.title": "Tema",
"settings.general.row.theme.description": "Personaliza el tema de OpenCode.", "settings.general.row.theme.description": "Personaliza el tema de OpenCode.",
"settings.general.row.font.title": "Fuente de código", "settings.general.row.font.title": "Fuente de código",
"settings.general.row.font.description": "Personaliza la fuente usada en bloques de código y terminales", "settings.general.row.font.description": "Personaliza la fuente usada en bloques de código",
"settings.general.row.terminalFont.title": "Terminal Font",
"settings.general.row.terminalFont.description": "Customise the font used in the terminal",
"settings.general.row.uiFont.title": "Fuente de la interfaz", "settings.general.row.uiFont.title": "Fuente de la interfaz",
"settings.general.row.uiFont.description": "Personaliza la fuente usada en toda la interfaz", "settings.general.row.uiFont.description": "Personaliza la fuente usada en toda la interfaz",
"settings.general.row.followup.title": "Comportamiento de seguimiento", "settings.general.row.followup.title": "Comportamiento de seguimiento",
@@ -657,6 +659,9 @@ export const dict = {
"settings.general.row.editToolPartsExpanded.title": "Expandir partes de la herramienta de edición", "settings.general.row.editToolPartsExpanded.title": "Expandir partes de la herramienta de edición",
"settings.general.row.editToolPartsExpanded.description": "settings.general.row.editToolPartsExpanded.description":
"Mostrar las partes de las herramientas de edición, escritura y parcheado expandidas por defecto en la línea de tiempo", "Mostrar las partes de las herramientas de edición, escritura y parcheado expandidas por defecto en la línea de tiempo",
"settings.general.row.showSessionProgressBar.title": "Mostrar barra de progreso de la sesión",
"settings.general.row.showSessionProgressBar.description":
"Mostrar la barra de progreso animada en la parte superior de la sesión cuando el agente esté trabajando",
"settings.general.row.wayland.title": "Usar Wayland nativo", "settings.general.row.wayland.title": "Usar Wayland nativo",
"settings.general.row.wayland.description": "Deshabilitar fallback a X11 en Wayland. Requiere reinicio.", "settings.general.row.wayland.description": "Deshabilitar fallback a X11 en Wayland. Requiere reinicio.",
"settings.general.row.wayland.tooltip": "settings.general.row.wayland.tooltip":
+7 -2
View File
@@ -210,7 +210,7 @@ export const dict = {
"common.saving": "Enregistrement...", "common.saving": "Enregistrement...",
"common.default": "Défaut", "common.default": "Défaut",
"common.attachment": "pièce jointe", "common.attachment": "pièce jointe",
"prompt.placeholder.shell": "Entrez une commande shell...", "prompt.placeholder.shell": "Entrez une commande shell... {{example}}",
"prompt.placeholder.normal": 'Demandez n\'importe quoi... "{{example}}"', "prompt.placeholder.normal": 'Demandez n\'importe quoi... "{{example}}"',
"prompt.placeholder.simple": "Demandez n'importe quoi...", "prompt.placeholder.simple": "Demandez n'importe quoi...",
"prompt.placeholder.summarizeComments": "Résumer les commentaires…", "prompt.placeholder.summarizeComments": "Résumer les commentaires…",
@@ -579,7 +579,9 @@ export const dict = {
"settings.general.row.theme.title": "Thème", "settings.general.row.theme.title": "Thème",
"settings.general.row.theme.description": "Personnaliser le thème d'OpenCode.", "settings.general.row.theme.description": "Personnaliser le thème d'OpenCode.",
"settings.general.row.font.title": "Police de code", "settings.general.row.font.title": "Police de code",
"settings.general.row.font.description": "Personnaliser la police utilisée dans les blocs de code et les terminaux", "settings.general.row.font.description": "Personnaliser la police utilisée dans les blocs de code",
"settings.general.row.terminalFont.title": "Terminal Font",
"settings.general.row.terminalFont.description": "Customise the font used in the terminal",
"settings.general.row.uiFont.title": "Police de l'interface", "settings.general.row.uiFont.title": "Police de l'interface",
"settings.general.row.uiFont.description": "Personnaliser la police utilisée dans toute l'interface", "settings.general.row.uiFont.description": "Personnaliser la police utilisée dans toute l'interface",
"settings.general.row.followup.title": "Comportement de suivi", "settings.general.row.followup.title": "Comportement de suivi",
@@ -596,6 +598,9 @@ export const dict = {
"settings.general.row.editToolPartsExpanded.title": "Développer les parties de l'outil edit", "settings.general.row.editToolPartsExpanded.title": "Développer les parties de l'outil edit",
"settings.general.row.editToolPartsExpanded.description": "settings.general.row.editToolPartsExpanded.description":
"Afficher les parties des outils edit, write et patch développées par défaut dans la chronologie", "Afficher les parties des outils edit, write et patch développées par défaut dans la chronologie",
"settings.general.row.showSessionProgressBar.title": "Afficher la barre de progression de la session",
"settings.general.row.showSessionProgressBar.description":
"Afficher la barre de progression animée en haut de la session lorsque l'agent travaille",
"settings.general.row.wayland.title": "Utiliser Wayland natif", "settings.general.row.wayland.title": "Utiliser Wayland natif",
"settings.general.row.wayland.description": "Désactiver le repli X11 sur Wayland. Nécessite un redémarrage.", "settings.general.row.wayland.description": "Désactiver le repli X11 sur Wayland. Nécessite un redémarrage.",
"settings.general.row.wayland.tooltip": "settings.general.row.wayland.tooltip":
+7 -2
View File
@@ -209,7 +209,7 @@ export const dict = {
"common.saving": "保存中...", "common.saving": "保存中...",
"common.default": "デフォルト", "common.default": "デフォルト",
"common.attachment": "添付ファイル", "common.attachment": "添付ファイル",
"prompt.placeholder.shell": "シェルコマンドを入力...", "prompt.placeholder.shell": "シェルコマンドを入力... {{example}}",
"prompt.placeholder.normal": '何でも聞いてください... "{{example}}"', "prompt.placeholder.normal": '何でも聞いてください... "{{example}}"',
"prompt.placeholder.simple": "何でも聞いてください...", "prompt.placeholder.simple": "何でも聞いてください...",
"prompt.placeholder.summarizeComments": "コメントを要約…", "prompt.placeholder.summarizeComments": "コメントを要約…",
@@ -569,7 +569,9 @@ export const dict = {
"settings.general.row.theme.title": "テーマ", "settings.general.row.theme.title": "テーマ",
"settings.general.row.theme.description": "OpenCodeのテーマをカスタマイズします。", "settings.general.row.theme.description": "OpenCodeのテーマをカスタマイズします。",
"settings.general.row.font.title": "コードフォント", "settings.general.row.font.title": "コードフォント",
"settings.general.row.font.description": "コードブロックとターミナルで使用するフォントをカスタマイズします", "settings.general.row.font.description": "コードブロックで使用するフォントをカスタマイズします",
"settings.general.row.terminalFont.title": "Terminal Font",
"settings.general.row.terminalFont.description": "Customise the font used in the terminal",
"settings.general.row.uiFont.title": "UIフォント", "settings.general.row.uiFont.title": "UIフォント",
"settings.general.row.uiFont.description": "インターフェース全体で使用するフォントをカスタマイズします", "settings.general.row.uiFont.description": "インターフェース全体で使用するフォントをカスタマイズします",
"settings.general.row.followup.title": "フォローアップの動作", "settings.general.row.followup.title": "フォローアップの動作",
@@ -585,6 +587,9 @@ export const dict = {
"settings.general.row.editToolPartsExpanded.title": "edit ツールパーツを展開", "settings.general.row.editToolPartsExpanded.title": "edit ツールパーツを展開",
"settings.general.row.editToolPartsExpanded.description": "settings.general.row.editToolPartsExpanded.description":
"タイムラインで edit、write、patch ツールパーツをデフォルトで展開して表示します", "タイムラインで edit、write、patch ツールパーツをデフォルトで展開して表示します",
"settings.general.row.showSessionProgressBar.title": "セッション進行状況バーを表示",
"settings.general.row.showSessionProgressBar.description":
"エージェントの作業中に、セッション上部にアニメーション付きの進行状況バーを表示します",
"settings.general.row.wayland.title": "ネイティブWaylandを使用", "settings.general.row.wayland.title": "ネイティブWaylandを使用",
"settings.general.row.wayland.description": "WaylandでのX11フォールバックを無効にします。再起動が必要です。", "settings.general.row.wayland.description": "WaylandでのX11フォールバックを無効にします。再起動が必要です。",
"settings.general.row.wayland.tooltip": "settings.general.row.wayland.tooltip":
+7 -6
View File
@@ -1,7 +1,3 @@
import { dict as en } from "./en"
type Keys = keyof typeof en
export const dict = { export const dict = {
"command.category.suggested": "추천", "command.category.suggested": "추천",
"command.category.view": "보기", "command.category.view": "보기",
@@ -213,7 +209,7 @@ export const dict = {
"common.saving": "저장 중...", "common.saving": "저장 중...",
"common.default": "기본값", "common.default": "기본값",
"common.attachment": "첨부 파일", "common.attachment": "첨부 파일",
"prompt.placeholder.shell": "셸 명령어 입력...", "prompt.placeholder.shell": "셸 명령어 입력... {{example}}",
"prompt.placeholder.normal": '무엇이든 물어보세요... "{{example}}"', "prompt.placeholder.normal": '무엇이든 물어보세요... "{{example}}"',
"prompt.placeholder.simple": "무엇이든 물어보세요...", "prompt.placeholder.simple": "무엇이든 물어보세요...",
"prompt.placeholder.summarizeComments": "댓글 요약…", "prompt.placeholder.summarizeComments": "댓글 요약…",
@@ -570,7 +566,9 @@ export const dict = {
"settings.general.row.theme.title": "테마", "settings.general.row.theme.title": "테마",
"settings.general.row.theme.description": "OpenCode 테마 사용자 지정", "settings.general.row.theme.description": "OpenCode 테마 사용자 지정",
"settings.general.row.font.title": "코드 글꼴", "settings.general.row.font.title": "코드 글꼴",
"settings.general.row.font.description": "코드 블록과 터미널에 사용되는 글꼴을 사용자 지정", "settings.general.row.font.description": "코드 블록에 사용되는 글꼴을 사용자 지정",
"settings.general.row.terminalFont.title": "Terminal Font",
"settings.general.row.terminalFont.description": "Customise the font used in the terminal",
"settings.general.row.uiFont.title": "UI 글꼴", "settings.general.row.uiFont.title": "UI 글꼴",
"settings.general.row.uiFont.description": "인터페이스 전반에 사용되는 글꼴을 사용자 지정", "settings.general.row.uiFont.description": "인터페이스 전반에 사용되는 글꼴을 사용자 지정",
"settings.general.row.followup.title": "후속 조치 동작", "settings.general.row.followup.title": "후속 조치 동작",
@@ -585,6 +583,9 @@ export const dict = {
"settings.general.row.editToolPartsExpanded.title": "edit 도구 파트 펼치기", "settings.general.row.editToolPartsExpanded.title": "edit 도구 파트 펼치기",
"settings.general.row.editToolPartsExpanded.description": "settings.general.row.editToolPartsExpanded.description":
"타임라인에서 기본적으로 edit, write, patch 도구 파트를 펼친 상태로 표시합니다", "타임라인에서 기본적으로 edit, write, patch 도구 파트를 펼친 상태로 표시합니다",
"settings.general.row.showSessionProgressBar.title": "세션 진행 표시줄 표시",
"settings.general.row.showSessionProgressBar.description":
"에이전트가 작업 중일 때 세션 상단에 애니메이션 진행 표시줄을 표시합니다",
"settings.general.row.wayland.title": "네이티브 Wayland 사용", "settings.general.row.wayland.title": "네이티브 Wayland 사용",
"settings.general.row.wayland.description": "Wayland에서 X11 폴백을 비활성화합니다. 다시 시작해야 합니다.", "settings.general.row.wayland.description": "Wayland에서 X11 폴백을 비활성화합니다. 다시 시작해야 합니다.",
"settings.general.row.wayland.tooltip": "settings.general.row.wayland.tooltip":
+7 -2
View File
@@ -230,7 +230,7 @@ export const dict = {
"common.default": "Standard", "common.default": "Standard",
"common.attachment": "vedlegg", "common.attachment": "vedlegg",
"prompt.placeholder.shell": "Skriv inn shell-kommando...", "prompt.placeholder.shell": "Skriv inn shell-kommando... {{example}}",
"prompt.placeholder.normal": 'Spør om hva som helst... "{{example}}"', "prompt.placeholder.normal": 'Spør om hva som helst... "{{example}}"',
"prompt.placeholder.simple": "Spør om hva som helst...", "prompt.placeholder.simple": "Spør om hva som helst...",
"prompt.placeholder.summarizeComments": "Oppsummer kommentarer…", "prompt.placeholder.summarizeComments": "Oppsummer kommentarer…",
@@ -640,7 +640,9 @@ export const dict = {
"settings.general.row.theme.title": "Tema", "settings.general.row.theme.title": "Tema",
"settings.general.row.theme.description": "Tilpass hvordan OpenCode er tematisert.", "settings.general.row.theme.description": "Tilpass hvordan OpenCode er tematisert.",
"settings.general.row.font.title": "Kodefont", "settings.general.row.font.title": "Kodefont",
"settings.general.row.font.description": "Tilpass skrifttypen som brukes i kodeblokker og terminaler", "settings.general.row.font.description": "Tilpass skrifttypen som brukes i kodeblokker",
"settings.general.row.terminalFont.title": "Terminal Font",
"settings.general.row.terminalFont.description": "Customise the font used in the terminal",
"settings.general.row.uiFont.title": "UI-skrift", "settings.general.row.uiFont.title": "UI-skrift",
"settings.general.row.uiFont.description": "Tilpass skrifttypen som brukes i hele grensesnittet", "settings.general.row.uiFont.description": "Tilpass skrifttypen som brukes i hele grensesnittet",
"settings.general.row.followup.title": "Oppfølgingsadferd", "settings.general.row.followup.title": "Oppfølgingsadferd",
@@ -654,6 +656,9 @@ export const dict = {
"settings.general.row.editToolPartsExpanded.title": "Utvid edit-verktøydeler", "settings.general.row.editToolPartsExpanded.title": "Utvid edit-verktøydeler",
"settings.general.row.editToolPartsExpanded.description": "settings.general.row.editToolPartsExpanded.description":
"Vis edit-, write- og patch-verktøydeler utvidet som standard i tidslinjen", "Vis edit-, write- og patch-verktøydeler utvidet som standard i tidslinjen",
"settings.general.row.showSessionProgressBar.title": "Vis fremdriftslinje for sesjonen",
"settings.general.row.showSessionProgressBar.description":
"Vis den animerte fremdriftslinjen øverst i sesjonen når agenten jobber",
"settings.general.row.wayland.title": "Bruk innebygd Wayland", "settings.general.row.wayland.title": "Bruk innebygd Wayland",
"settings.general.row.wayland.description": "Deaktiver X11-fallback på Wayland. Krever omstart.", "settings.general.row.wayland.description": "Deaktiver X11-fallback på Wayland. Krever omstart.",
"settings.general.row.wayland.tooltip": "settings.general.row.wayland.tooltip":
+7 -2
View File
@@ -211,7 +211,7 @@ export const dict = {
"common.saving": "Zapisywanie...", "common.saving": "Zapisywanie...",
"common.default": "Domyślny", "common.default": "Domyślny",
"common.attachment": "załącznik", "common.attachment": "załącznik",
"prompt.placeholder.shell": "Wpisz polecenie terminala...", "prompt.placeholder.shell": "Wpisz polecenie terminala... {{example}}",
"prompt.placeholder.normal": 'Zapytaj o cokolwiek... "{{example}}"', "prompt.placeholder.normal": 'Zapytaj o cokolwiek... "{{example}}"',
"prompt.placeholder.simple": "Zapytaj o cokolwiek...", "prompt.placeholder.simple": "Zapytaj o cokolwiek...",
"prompt.placeholder.summarizeComments": "Podsumuj komentarze…", "prompt.placeholder.summarizeComments": "Podsumuj komentarze…",
@@ -571,7 +571,9 @@ export const dict = {
"settings.general.row.theme.title": "Motyw", "settings.general.row.theme.title": "Motyw",
"settings.general.row.theme.description": "Dostosuj motyw OpenCode.", "settings.general.row.theme.description": "Dostosuj motyw OpenCode.",
"settings.general.row.font.title": "Czcionka kodu", "settings.general.row.font.title": "Czcionka kodu",
"settings.general.row.font.description": "Dostosuj czcionkę używaną w blokach kodu i terminalach", "settings.general.row.font.description": "Dostosuj czcionkę używaną w blokach kodu",
"settings.general.row.terminalFont.title": "Terminal Font",
"settings.general.row.terminalFont.description": "Customise the font used in the terminal",
"settings.general.row.uiFont.title": "Czcionka interfejsu", "settings.general.row.uiFont.title": "Czcionka interfejsu",
"settings.general.row.uiFont.description": "Dostosuj czcionkę używaną w całym interfejsie", "settings.general.row.uiFont.description": "Dostosuj czcionkę używaną w całym interfejsie",
"settings.general.row.followup.title": "Zachowanie kontynuacji", "settings.general.row.followup.title": "Zachowanie kontynuacji",
@@ -586,6 +588,9 @@ export const dict = {
"settings.general.row.editToolPartsExpanded.title": "Rozwijaj elementy narzędzia edit", "settings.general.row.editToolPartsExpanded.title": "Rozwijaj elementy narzędzia edit",
"settings.general.row.editToolPartsExpanded.description": "settings.general.row.editToolPartsExpanded.description":
"Domyślnie pokazuj rozwinięte elementy narzędzi edit, write i patch na osi czasu", "Domyślnie pokazuj rozwinięte elementy narzędzi edit, write i patch na osi czasu",
"settings.general.row.showSessionProgressBar.title": "Pokazuj pasek postępu sesji",
"settings.general.row.showSessionProgressBar.description":
"Wyświetlaj animowany pasek postępu u góry sesji, gdy agent pracuje",
"settings.general.row.wayland.title": "Użyj natywnego Wayland", "settings.general.row.wayland.title": "Użyj natywnego Wayland",
"settings.general.row.wayland.description": "Wyłącz fallback X11 na Wayland. Wymaga restartu.", "settings.general.row.wayland.description": "Wyłącz fallback X11 na Wayland. Wymaga restartu.",
"settings.general.row.wayland.tooltip": "settings.general.row.wayland.tooltip":
+7 -2
View File
@@ -227,7 +227,7 @@ export const dict = {
"common.default": "По умолчанию", "common.default": "По умолчанию",
"common.attachment": "вложение", "common.attachment": "вложение",
"prompt.placeholder.shell": "Введите команду оболочки...", "prompt.placeholder.shell": "Введите команду оболочки... {{example}}",
"prompt.placeholder.normal": 'Спросите что угодно... "{{example}}"', "prompt.placeholder.normal": 'Спросите что угодно... "{{example}}"',
"prompt.placeholder.simple": "Спросите что угодно...", "prompt.placeholder.simple": "Спросите что угодно...",
"prompt.placeholder.summarizeComments": "Суммировать комментарии…", "prompt.placeholder.summarizeComments": "Суммировать комментарии…",
@@ -637,7 +637,9 @@ export const dict = {
"settings.general.row.theme.title": "Тема", "settings.general.row.theme.title": "Тема",
"settings.general.row.theme.description": "Настройте оформление OpenCode.", "settings.general.row.theme.description": "Настройте оформление OpenCode.",
"settings.general.row.font.title": "Шрифт кода", "settings.general.row.font.title": "Шрифт кода",
"settings.general.row.font.description": "Настройте шрифт, используемый в блоках кода и терминалах", "settings.general.row.font.description": "Настройте шрифт, используемый в блоках кода",
"settings.general.row.terminalFont.title": "Terminal Font",
"settings.general.row.terminalFont.description": "Customise the font used in the terminal",
"settings.general.row.uiFont.title": "Шрифт интерфейса", "settings.general.row.uiFont.title": "Шрифт интерфейса",
"settings.general.row.uiFont.description": "Настройте шрифт, используемый во всем интерфейсе", "settings.general.row.uiFont.description": "Настройте шрифт, используемый во всем интерфейсе",
"settings.general.row.followup.title": "Поведение уточняющих вопросов", "settings.general.row.followup.title": "Поведение уточняющих вопросов",
@@ -654,6 +656,9 @@ export const dict = {
"settings.general.row.editToolPartsExpanded.title": "Разворачивать элементы инструмента edit", "settings.general.row.editToolPartsExpanded.title": "Разворачивать элементы инструмента edit",
"settings.general.row.editToolPartsExpanded.description": "settings.general.row.editToolPartsExpanded.description":
"Показывать элементы инструментов edit, write и patch в ленте развернутыми по умолчанию", "Показывать элементы инструментов edit, write и patch в ленте развернутыми по умолчанию",
"settings.general.row.showSessionProgressBar.title": "Показывать индикатор прогресса сессии",
"settings.general.row.showSessionProgressBar.description":
"Показывать анимированный индикатор прогресса вверху сессии, когда агент работает",
"settings.general.row.wayland.title": "Использовать нативный Wayland", "settings.general.row.wayland.title": "Использовать нативный Wayland",
"settings.general.row.wayland.description": "Отключить X11 fallback на Wayland. Требуется перезапуск.", "settings.general.row.wayland.description": "Отключить X11 fallback на Wayland. Требуется перезапуск.",
"settings.general.row.wayland.tooltip": "settings.general.row.wayland.tooltip":
+7 -2
View File
@@ -227,7 +227,7 @@ export const dict = {
"common.default": "ค่าเริ่มต้น", "common.default": "ค่าเริ่มต้น",
"common.attachment": "ไฟล์แนบ", "common.attachment": "ไฟล์แนบ",
"prompt.placeholder.shell": "ป้อนคำสั่งเชลล์...", "prompt.placeholder.shell": "ป้อนคำสั่งเชลล์... {{example}}",
"prompt.placeholder.normal": 'ถามอะไรก็ได้... "{{example}}"', "prompt.placeholder.normal": 'ถามอะไรก็ได้... "{{example}}"',
"prompt.placeholder.simple": "ถามอะไรก็ได้...", "prompt.placeholder.simple": "ถามอะไรก็ได้...",
"prompt.placeholder.summarizeComments": "สรุปความคิดเห็น…", "prompt.placeholder.summarizeComments": "สรุปความคิดเห็น…",
@@ -631,7 +631,9 @@ export const dict = {
"settings.general.row.theme.title": "ธีม", "settings.general.row.theme.title": "ธีม",
"settings.general.row.theme.description": "ปรับแต่งวิธีการที่ OpenCode มีธีม", "settings.general.row.theme.description": "ปรับแต่งวิธีการที่ OpenCode มีธีม",
"settings.general.row.font.title": "ฟอนต์โค้ด", "settings.general.row.font.title": "ฟอนต์โค้ด",
"settings.general.row.font.description": "ปรับแต่งฟอนต์ที่ใช้ในบล็อกโค้ดและเทอร์มินัล", "settings.general.row.font.description": "ปรับแต่งฟอนต์ที่ใช้ในบล็อกโค้ด",
"settings.general.row.terminalFont.title": "Terminal Font",
"settings.general.row.terminalFont.description": "Customise the font used in the terminal",
"settings.general.row.uiFont.title": "ฟอนต์ UI", "settings.general.row.uiFont.title": "ฟอนต์ UI",
"settings.general.row.uiFont.description": "ปรับแต่งฟอนต์ที่ใช้ทั่วทั้งอินเทอร์เฟซ", "settings.general.row.uiFont.description": "ปรับแต่งฟอนต์ที่ใช้ทั่วทั้งอินเทอร์เฟซ",
"settings.general.row.followup.title": "พฤติกรรมการติดตามผล", "settings.general.row.followup.title": "พฤติกรรมการติดตามผล",
@@ -645,6 +647,9 @@ export const dict = {
"settings.general.row.editToolPartsExpanded.title": "ขยายส่วนเครื่องมือ edit", "settings.general.row.editToolPartsExpanded.title": "ขยายส่วนเครื่องมือ edit",
"settings.general.row.editToolPartsExpanded.description": "settings.general.row.editToolPartsExpanded.description":
"แสดงส่วนเครื่องมือ edit, write และ patch แบบขยายตามค่าเริ่มต้นในไทม์ไลน์", "แสดงส่วนเครื่องมือ edit, write และ patch แบบขยายตามค่าเริ่มต้นในไทม์ไลน์",
"settings.general.row.showSessionProgressBar.title": "แสดงแถบความคืบหน้าของเซสชัน",
"settings.general.row.showSessionProgressBar.description":
"แสดงแถบความคืบหน้าแบบเคลื่อนไหวที่ด้านบนของเซสชันเมื่อเอเจนต์กำลังทำงาน",
"settings.general.row.wayland.title": "ใช้ Wayland แบบเนทีฟ", "settings.general.row.wayland.title": "ใช้ Wayland แบบเนทีฟ",
"settings.general.row.wayland.description": "ปิดใช้งาน X11 fallback บน Wayland ต้องรีสตาร์ท", "settings.general.row.wayland.description": "ปิดใช้งาน X11 fallback บน Wayland ต้องรีสตาร์ท",
"settings.general.row.wayland.tooltip": "บน Linux ที่มีจอภาพรีเฟรชเรตแบบผสม Wayland แบบเนทีฟอาจเสถียรกว่า", "settings.general.row.wayland.tooltip": "บน Linux ที่มีจอภาพรีเฟรชเรตแบบผสม Wayland แบบเนทีฟอาจเสถียรกว่า",
+8 -2
View File
@@ -232,7 +232,7 @@ export const dict = {
"common.default": "Varsayılan", "common.default": "Varsayılan",
"common.attachment": "ek", "common.attachment": "ek",
"prompt.placeholder.shell": "Kabuk komutu girin...", "prompt.placeholder.shell": "Kabuk komutu girin... {{example}}",
"prompt.placeholder.normal": 'Bir şeyler sorun... "{{example}}"', "prompt.placeholder.normal": 'Bir şeyler sorun... "{{example}}"',
"prompt.placeholder.simple": "Bir şeyler sorun...", "prompt.placeholder.simple": "Bir şeyler sorun...",
"prompt.placeholder.summarizeComments": "Yorumları özetle…", "prompt.placeholder.summarizeComments": "Yorumları özetle…",
@@ -644,7 +644,9 @@ export const dict = {
"settings.general.row.theme.title": "Tema", "settings.general.row.theme.title": "Tema",
"settings.general.row.theme.description": "OpenCode'un temasını özelleştirin.", "settings.general.row.theme.description": "OpenCode'un temasını özelleştirin.",
"settings.general.row.font.title": "Kod Yazı Tipi", "settings.general.row.font.title": "Kod Yazı Tipi",
"settings.general.row.font.description": "Kod bloklarında ve terminallerde kullanılan yazı tipini özelleştirin", "settings.general.row.font.description": "Kod bloklarında kullanılan yazı tipini özelleştirin",
"settings.general.row.terminalFont.title": "Terminal Font",
"settings.general.row.terminalFont.description": "Customise the font used in the terminal",
"settings.general.row.uiFont.title": "Arayüz Yazı Tipi", "settings.general.row.uiFont.title": "Arayüz Yazı Tipi",
"settings.general.row.uiFont.description": "Arayüz genelinde kullanılan yazı tipini özelleştirin", "settings.general.row.uiFont.description": "Arayüz genelinde kullanılan yazı tipini özelleştirin",
"settings.general.row.followup.title": "Takip davranışı", "settings.general.row.followup.title": "Takip davranışı",
@@ -661,6 +663,10 @@ export const dict = {
"settings.general.row.editToolPartsExpanded.description": "settings.general.row.editToolPartsExpanded.description":
"Zaman çizelgesinde düzenleme, yazma ve yama araç bileşenlerini varsayılan olarak genişletilmiş göster", "Zaman çizelgesinde düzenleme, yazma ve yama araç bileşenlerini varsayılan olarak genişletilmiş göster",
"settings.general.row.showSessionProgressBar.title": "Oturum ilerleme çubuğunu göster",
"settings.general.row.showSessionProgressBar.description":
"Ajan çalışırken oturumun üst kısmında animasyonlu ilerleme çubuğunu göster",
"settings.general.row.wayland.title": "Yerel Wayland kullan", "settings.general.row.wayland.title": "Yerel Wayland kullan",
"settings.general.row.wayland.description": "settings.general.row.wayland.description":
"Wayland'da X11 geri dönüşünü devre dışı bırak. Yeniden başlatma gerektirir.", "Wayland'da X11 geri dönüşünü devre dışı bırak. Yeniden başlatma gerektirir.",
+6 -2
View File
@@ -249,7 +249,7 @@ export const dict = {
"common.default": "默认", "common.default": "默认",
"common.attachment": "附件", "common.attachment": "附件",
"prompt.placeholder.shell": "输入 shell 命令...", "prompt.placeholder.shell": "输入 shell 命令... {{example}}",
"prompt.placeholder.normal": '随便问点什么... "{{example}}"', "prompt.placeholder.normal": '随便问点什么... "{{example}}"',
"prompt.placeholder.simple": "随便问点什么...", "prompt.placeholder.simple": "随便问点什么...",
"prompt.placeholder.summarizeComments": "总结评论…", "prompt.placeholder.summarizeComments": "总结评论…",
@@ -631,7 +631,9 @@ export const dict = {
"settings.general.row.theme.title": "主题", "settings.general.row.theme.title": "主题",
"settings.general.row.theme.description": "自定义 OpenCode 的主题。", "settings.general.row.theme.description": "自定义 OpenCode 的主题。",
"settings.general.row.font.title": "代码字体", "settings.general.row.font.title": "代码字体",
"settings.general.row.font.description": "自定义代码块和终端使用的字体", "settings.general.row.font.description": "自定义代码块使用的字体",
"settings.general.row.terminalFont.title": "Terminal Font",
"settings.general.row.terminalFont.description": "Customise the font used in the terminal",
"settings.general.row.uiFont.title": "界面字体", "settings.general.row.uiFont.title": "界面字体",
"settings.general.row.uiFont.description": "自定义整个界面使用的字体", "settings.general.row.uiFont.description": "自定义整个界面使用的字体",
"settings.general.row.followup.title": "跟进消息行为", "settings.general.row.followup.title": "跟进消息行为",
@@ -644,6 +646,8 @@ export const dict = {
"settings.general.row.shellToolPartsExpanded.description": "默认在时间线中展开 shell 工具部分", "settings.general.row.shellToolPartsExpanded.description": "默认在时间线中展开 shell 工具部分",
"settings.general.row.editToolPartsExpanded.title": "展开编辑工具部分", "settings.general.row.editToolPartsExpanded.title": "展开编辑工具部分",
"settings.general.row.editToolPartsExpanded.description": "默认在时间线中展开 edit、write 和 patch 工具部分", "settings.general.row.editToolPartsExpanded.description": "默认在时间线中展开 edit、write 和 patch 工具部分",
"settings.general.row.showSessionProgressBar.title": "显示会话进度条",
"settings.general.row.showSessionProgressBar.description": "当智能体正在工作时,在会话顶部显示动画进度条",
"settings.general.row.wayland.title": "使用原生 Wayland", "settings.general.row.wayland.title": "使用原生 Wayland",
"settings.general.row.wayland.description": "在 Wayland 上禁用 X11 回退。需要重启。", "settings.general.row.wayland.description": "在 Wayland 上禁用 X11 回退。需要重启。",
"settings.general.row.wayland.tooltip": "在混合刷新率显示器的 Linux 系统上,原生 Wayland 可能更稳定。", "settings.general.row.wayland.tooltip": "在混合刷新率显示器的 Linux 系统上,原生 Wayland 可能更稳定。",
+6 -2
View File
@@ -227,7 +227,7 @@ export const dict = {
"common.default": "預設", "common.default": "預設",
"common.attachment": "附件", "common.attachment": "附件",
"prompt.placeholder.shell": "輸入 shell 命令...", "prompt.placeholder.shell": "輸入 shell 命令... {{example}}",
"prompt.placeholder.normal": '隨便問點什麼... "{{example}}"', "prompt.placeholder.normal": '隨便問點什麼... "{{example}}"',
"prompt.placeholder.simple": "隨便問點什麼...", "prompt.placeholder.simple": "隨便問點什麼...",
"prompt.placeholder.summarizeComments": "摘要評論…", "prompt.placeholder.summarizeComments": "摘要評論…",
@@ -626,7 +626,9 @@ export const dict = {
"settings.general.row.theme.title": "主題", "settings.general.row.theme.title": "主題",
"settings.general.row.theme.description": "自訂 OpenCode 的主題。", "settings.general.row.theme.description": "自訂 OpenCode 的主題。",
"settings.general.row.font.title": "程式碼字型", "settings.general.row.font.title": "程式碼字型",
"settings.general.row.font.description": "自訂程式碼區塊和終端機使用的字型", "settings.general.row.font.description": "自訂程式碼區塊使用的字型",
"settings.general.row.terminalFont.title": "Terminal Font",
"settings.general.row.terminalFont.description": "Customise the font used in the terminal",
"settings.general.row.uiFont.title": "介面字型", "settings.general.row.uiFont.title": "介面字型",
"settings.general.row.uiFont.description": "自訂整個介面使用的字型", "settings.general.row.uiFont.description": "自訂整個介面使用的字型",
"settings.general.row.followup.title": "後續追問行為", "settings.general.row.followup.title": "後續追問行為",
@@ -640,6 +642,8 @@ export const dict = {
"settings.general.row.shellToolPartsExpanded.description": "在時間軸中預設展開 shell 工具區塊", "settings.general.row.shellToolPartsExpanded.description": "在時間軸中預設展開 shell 工具區塊",
"settings.general.row.editToolPartsExpanded.title": "展開 edit 工具區塊", "settings.general.row.editToolPartsExpanded.title": "展開 edit 工具區塊",
"settings.general.row.editToolPartsExpanded.description": "在時間軸中預設展開 edit、write 和 patch 工具區塊", "settings.general.row.editToolPartsExpanded.description": "在時間軸中預設展開 edit、write 和 patch 工具區塊",
"settings.general.row.showSessionProgressBar.title": "顯示工作階段進度列",
"settings.general.row.showSessionProgressBar.description": "當代理程式正在運作時,在工作階段頂部顯示動畫進度列",
"settings.general.row.wayland.title": "使用原生 Wayland", "settings.general.row.wayland.title": "使用原生 Wayland",
"settings.general.row.wayland.description": "在 Wayland 上停用 X11 後備模式。需要重新啟動。", "settings.general.row.wayland.description": "在 Wayland 上停用 X11 後備模式。需要重新啟動。",
"settings.general.row.wayland.tooltip": "在混合更新率螢幕的 Linux 系統上,原生 Wayland 可能更穩定。", "settings.general.row.wayland.tooltip": "在混合更新率螢幕的 Linux 系統上,原生 Wayland 可能更穩定。",
+16
View File
@@ -1,5 +1,12 @@
@import "@opencode-ai/ui/styles/tailwind"; @import "@opencode-ai/ui/styles/tailwind";
@font-face {
font-family: "JetBrainsMono Nerd Font Mono";
src: url("/assets/JetBrainsMonoNerdFontMono-Regular.woff2") format("woff2");
font-weight: normal;
font-style: normal;
}
@layer components { @layer components {
@keyframes session-progress-whip { @keyframes session-progress-whip {
0% { 0% {
@@ -66,4 +73,13 @@
width: auto; width: auto;
} }
} }
@keyframes fade-in {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
} }
+6 -7
View File
@@ -1,8 +1,8 @@
import { DataProvider } from "@opencode-ai/ui/context" import { DataProvider } from "@opencode-ai/ui/context"
import { showToast } from "@opencode-ai/ui/toast" import { showToast } from "@opencode-ai/ui/toast"
import { base64Encode } from "@opencode-ai/shared/util/encode" import { base64Encode } from "@opencode-ai/core/util/encode"
import { useLocation, useNavigate, useParams } from "@solidjs/router" import { useLocation, useNavigate, useParams } from "@solidjs/router"
import { createEffect, createMemo, type ParentProps, Show } from "solid-js" import { createEffect, createMemo, createResource, type ParentProps, Show } from "solid-js"
import { useLanguage } from "@/context/language" import { useLanguage } from "@/context/language"
import { LocalProvider } from "@/context/local" import { LocalProvider } from "@/context/local"
import { SDKProvider } from "@/context/sdk" import { SDKProvider } from "@/context/sdk"
@@ -23,11 +23,10 @@ function DirectoryDataProvider(props: ParentProps<{ directory: string }>) {
navigate(`/${base64Encode(next)}${path}${location.search}${location.hash}`, { replace: true }) navigate(`/${base64Encode(next)}${path}${location.search}${location.hash}`, { replace: true })
}) })
createEffect(() => { createResource(
const id = params.id () => params.id,
if (!id) return (id) => sync.session.sync(id),
void sync.session.sync(id) )
})
return ( return (
<DataProvider <DataProvider
+2 -3
View File
@@ -244,10 +244,9 @@ export const ErrorPage: Component<ErrorPageProps> = (props) => {
} }
async function installUpdate() { async function installUpdate() {
if (!platform.update || !platform.restart) return if (!platform.updateAndRestart) return
await platform await platform
.update() .updateAndRestart()
.then(() => platform.restart!())
.then(() => setStore("actionError", undefined)) .then(() => setStore("actionError", undefined))
.catch((err) => { .catch((err) => {
setStore("actionError", formatError(err, language.t)) setStore("actionError", formatError(err, language.t))
+1 -1
View File
@@ -3,7 +3,7 @@ import { Button } from "@opencode-ai/ui/button"
import { Logo } from "@opencode-ai/ui/logo" import { Logo } from "@opencode-ai/ui/logo"
import { useLayout } from "@/context/layout" import { useLayout } from "@/context/layout"
import { useNavigate } from "@solidjs/router" import { useNavigate } from "@solidjs/router"
import { base64Encode } from "@opencode-ai/shared/util/encode" import { base64Encode } from "@opencode-ai/core/util/encode"
import { Icon } from "@opencode-ai/ui/icon" import { Icon } from "@opencode-ai/ui/icon"
import { usePlatform } from "@/context/platform" import { usePlatform } from "@/context/platform"
import { DateTime } from "luxon" import { DateTime } from "luxon"
+27 -22
View File
@@ -13,11 +13,11 @@ import {
type Accessor, type Accessor,
} from "solid-js" } from "solid-js"
import { makeEventListener } from "@solid-primitives/event-listener" import { makeEventListener } from "@solid-primitives/event-listener"
import { useNavigate, useParams } from "@solidjs/router" import { useLocation, useNavigate, useParams } from "@solidjs/router"
import { useLayout, LocalProject } from "@/context/layout" import { useLayout, LocalProject } from "@/context/layout"
import { useGlobalSync } from "@/context/global-sync" import { useGlobalSync } from "@/context/global-sync"
import { Persist, persisted } from "@/utils/persist" import { Persist, persisted } from "@/utils/persist"
import { base64Encode } from "@opencode-ai/shared/util/encode" import { base64Encode } from "@opencode-ai/core/util/encode"
import { decode64 } from "@/utils/base64" import { decode64 } from "@/utils/base64"
import { ResizeHandle } from "@opencode-ai/ui/resize-handle" import { ResizeHandle } from "@opencode-ai/ui/resize-handle"
import { Button } from "@opencode-ai/ui/button" import { Button } from "@opencode-ai/ui/button"
@@ -25,7 +25,7 @@ import { IconButton } from "@opencode-ai/ui/icon-button"
import { Tooltip } from "@opencode-ai/ui/tooltip" import { Tooltip } from "@opencode-ai/ui/tooltip"
import { DropdownMenu } from "@opencode-ai/ui/dropdown-menu" import { DropdownMenu } from "@opencode-ai/ui/dropdown-menu"
import { Dialog } from "@opencode-ai/ui/dialog" import { Dialog } from "@opencode-ai/ui/dialog"
import { getFilename } from "@opencode-ai/shared/util/path" import { getFilename } from "@opencode-ai/core/util/path"
import { Session, type Message } from "@opencode-ai/sdk/v2/client" import { Session, type Message } from "@opencode-ai/sdk/v2/client"
import { usePlatform } from "@/context/platform" import { usePlatform } from "@/context/platform"
import { useSettings } from "@/context/settings" import { useSettings } from "@/context/settings"
@@ -48,8 +48,8 @@ import {
} from "@/context/global-sync/session-prefetch" } from "@/context/global-sync/session-prefetch"
import { useNotification } from "@/context/notification" import { useNotification } from "@/context/notification"
import { usePermission } from "@/context/permission" import { usePermission } from "@/context/permission"
import { Binary } from "@opencode-ai/shared/util/binary" import { Binary } from "@opencode-ai/core/util/binary"
import { retry } from "@opencode-ai/shared/util/retry" import { retry } from "@opencode-ai/core/util/retry"
import { playSoundById } from "@/utils/sound" import { playSoundById } from "@/utils/sound"
import { createAim } from "@/utils/aim" import { createAim } from "@/utils/aim"
import { setNavigate } from "@/utils/notification-click" import { setNavigate } from "@/utils/notification-click"
@@ -127,14 +127,17 @@ export default function Layout(props: ParentProps) {
const theme = useTheme() const theme = useTheme()
const language = useLanguage() const language = useLanguage()
const initialDirectory = decode64(params.dir) const initialDirectory = decode64(params.dir)
const location = useLocation()
const route = createMemo(() => { const route = createMemo(() => {
const slug = params.dir const slug = params.dir
if (!slug) return { slug, dir: "" } if (!slug) return { slug, dir: "" }
const dir = decode64(slug) const dir = decode64(slug)
if (!dir) return { slug, dir: "" } if (!dir) return { slug, dir: "" }
const store = globalSync.peek(dir, { bootstrap: false })
return { return {
slug, slug,
dir: globalSync.peek(dir, { bootstrap: false })[0].path.directory || dir, store,
dir: store[0].path.directory || dir,
} }
}) })
const availableThemeEntries = createMemo(() => theme.ids().map((id) => [id, theme.themes()[id]] as const)) const availableThemeEntries = createMemo(() => theme.ids().map((id) => [id, theme.themes()[id]] as const))
@@ -363,7 +366,7 @@ export default function Layout(props: ParentProps) {
const useUpdatePolling = () => const useUpdatePolling = () =>
onMount(() => { onMount(() => {
if (!platform.checkUpdate || !platform.update || !platform.restart) return if (!platform.checkUpdate || !platform.updateAndRestart) return
let toastId: number | undefined let toastId: number | undefined
let interval: ReturnType<typeof setInterval> | undefined let interval: ReturnType<typeof setInterval> | undefined
@@ -381,8 +384,7 @@ export default function Layout(props: ParentProps) {
{ {
label: language.t("toast.update.action.installRestart"), label: language.t("toast.update.action.installRestart"),
onClick: async () => { onClick: async () => {
await platform.update!() await platform.updateAndRestart!()
await platform.restart!()
}, },
}, },
{ {
@@ -704,7 +706,7 @@ export default function Layout(props: ParentProps) {
createEffect(() => { createEffect(() => {
const active = new Set(visibleSessionDirs()) const active = new Set(visibleSessionDirs())
for (const directory of [...prefetchedByDir.keys()]) { for (const directory of prefetchedByDir.keys()) {
if (active.has(directory)) continue if (active.has(directory)) continue
prefetchedByDir.delete(directory) prefetchedByDir.delete(directory)
} }
@@ -956,7 +958,7 @@ export default function Layout(props: ParentProps) {
// warm up child store to prevent flicker // warm up child store to prevent flicker
globalSync.child(target.worktree) globalSync.child(target.worktree)
openProject(target.worktree) void openProject(target.worktree)
} }
function navigateSessionByUnseen(offset: number) { function navigateSessionByUnseen(offset: number) {
@@ -1094,7 +1096,7 @@ export default function Layout(props: ParentProps) {
disabled: !params.dir || !params.id, disabled: !params.dir || !params.id,
onSelect: () => { onSelect: () => {
const session = currentSessions().find((s) => s.id === params.id) const session = currentSessions().find((s) => s.id === params.id)
if (session) archiveSession(session) if (session) void archiveSession(session)
}, },
}, },
{ {
@@ -1360,11 +1362,11 @@ export default function Layout(props: ParentProps) {
if (!server.isLocal()) return if (!server.isLocal()) return
for (const directory of collectOpenProjectDeepLinks(urls)) { for (const directory of collectOpenProjectDeepLinks(urls)) {
openProject(directory) void openProject(directory)
} }
for (const link of collectNewSessionDeepLinks(urls)) { for (const link of collectNewSessionDeepLinks(urls)) {
openProject(link.directory, false) void openProject(link.directory, false)
const slug = base64Encode(link.directory) const slug = base64Encode(link.directory)
if (link.prompt) { if (link.prompt) {
setSessionHandoff(slug, { prompt: link.prompt }) setSessionHandoff(slug, { prompt: link.prompt })
@@ -1453,11 +1455,11 @@ export default function Layout(props: ParentProps) {
function resolve(result: string | string[] | null) { function resolve(result: string | string[] | null) {
if (Array.isArray(result)) { if (Array.isArray(result)) {
for (const directory of result) { for (const directory of result) {
openProject(directory, false) void openProject(directory, false)
} }
navigateToProject(result[0]) void navigateToProject(result[0])
} else if (result) { } else if (result) {
openProject(result) void openProject(result)
} }
} }
@@ -1825,7 +1827,7 @@ export default function Layout(props: ParentProps) {
const next = new Set(dirs) const next = new Set(dirs)
for (const directory of next) { for (const directory of next) {
if (loadedSessionDirs.has(directory)) continue if (loadedSessionDirs.has(directory)) continue
globalSync.project.loadSessions(directory) void globalSync.project.loadSessions(directory)
} }
loadedSessionDirs.clear() loadedSessionDirs.clear()
@@ -2100,6 +2102,7 @@ export default function Layout(props: ParentProps) {
</Show> </Show>
} }
> >
{(project) => (
<> <>
<div class="shrink-0 pl-1 py-1"> <div class="shrink-0 pl-1 py-1">
<div class="group/project flex items-start justify-between gap-2 py-2 pl-2 pr-0"> <div class="group/project flex items-start justify-between gap-2 py-2 pl-2 pr-0">
@@ -2110,7 +2113,7 @@ export default function Layout(props: ParentProps) {
onSave={(next) => { onSave={(next) => {
const item = project() const item = project()
if (!item) return if (!item) return
renameProject(item, next) void renameProject(item, next)
}} }}
class="text-14-medium text-text-strong truncate" class="text-14-medium text-text-strong truncate"
displayClass="text-14-medium text-text-strong truncate" displayClass="text-14-medium text-text-strong truncate"
@@ -2225,7 +2228,7 @@ export default function Layout(props: ParentProps) {
<div class="flex-1 min-h-0"> <div class="flex-1 min-h-0">
<LocalWorkspace <LocalWorkspace
ctx={workspaceSidebarCtx} ctx={workspaceSidebarCtx}
project={project()!} project={project()}
sortNow={sortNow} sortNow={sortNow}
mobile={panelProps.mobile} mobile={panelProps.mobile}
/> />
@@ -2242,7 +2245,7 @@ export default function Layout(props: ParentProps) {
onClick={() => { onClick={() => {
const item = project() const item = project()
if (!item) return if (!item) return
createWorkspace(item) void createWorkspace(item)
}} }}
> >
{language.t("workspace.new")} {language.t("workspace.new")}
@@ -2269,7 +2272,7 @@ export default function Layout(props: ParentProps) {
<SortableWorkspace <SortableWorkspace
ctx={workspaceSidebarCtx} ctx={workspaceSidebarCtx}
directory={directory} directory={directory}
project={project()!} project={project()}
sortNow={sortNow} sortNow={sortNow}
mobile={panelProps.mobile} mobile={panelProps.mobile}
/> />
@@ -2290,6 +2293,7 @@ export default function Layout(props: ParentProps) {
</Show> </Show>
</div> </div>
</> </>
)}
</Show> </Show>
<div <div
@@ -2355,6 +2359,7 @@ export default function Layout(props: ParentProps) {
return ( 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"> <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 /> <Titlebar />
<div class="flex-1 min-h-0 min-w-0 flex"> <div class="flex-1 min-h-0 min-w-0 flex">
<div class="flex-1 min-h-0 relative"> <div class="flex-1 min-h-0 relative">
+2 -2
View File
@@ -1,4 +1,4 @@
import { getFilename } from "@opencode-ai/shared/util/path" import { getFilename } from "@opencode-ai/core/util/path"
import { type Session } from "@opencode-ai/sdk/v2/client" import { type Session } from "@opencode-ai/sdk/v2/client"
type SessionStore = { type SessionStore = {
@@ -31,7 +31,7 @@ function sortSessions(now: number) {
const isRootVisibleSession = (session: Session, directory: string) => const isRootVisibleSession = (session: Session, directory: string) =>
workspaceKey(session.directory) === workspaceKey(directory) && !session.parentID && !session.time?.archived workspaceKey(session.directory) === workspaceKey(directory) && !session.parentID && !session.time?.archived
const roots = (store: SessionStore) => export const roots = (store: SessionStore) =>
(store.session ?? []).filter((session) => isRootVisibleSession(session, store.path.directory)) (store.session ?? []).filter((session) => isRootVisibleSession(session, store.path.directory))
export const sortedRootSessions = (store: SessionStore, now: number) => roots(store).sort(sortSessions(now)) export const sortedRootSessions = (store: SessionStore, now: number) => roots(store).sort(sortSessions(now))
@@ -4,7 +4,7 @@ import { Icon } from "@opencode-ai/ui/icon"
import { IconButton } from "@opencode-ai/ui/icon-button" import { IconButton } from "@opencode-ai/ui/icon-button"
import { Spinner } from "@opencode-ai/ui/spinner" import { Spinner } from "@opencode-ai/ui/spinner"
import { Tooltip } from "@opencode-ai/ui/tooltip" import { Tooltip } from "@opencode-ai/ui/tooltip"
import { getFilename } from "@opencode-ai/shared/util/path" import { getFilename } from "@opencode-ai/core/util/path"
import { A, useParams } from "@solidjs/router" import { A, useParams } from "@solidjs/router"
import { type Accessor, createMemo, For, type JSX, Match, Show, Switch } from "solid-js" import { type Accessor, createMemo, For, type JSX, Match, Show, Switch } from "solid-js"
import { useGlobalSync } from "@/context/global-sync" import { useGlobalSync } from "@/context/global-sync"
@@ -19,6 +19,12 @@ import { childSessionOnPath, hasProjectPermissions } from "./helpers"
const OPENCODE_PROJECT_ID = "4b0ea68d7af9a6031a7ffda7ad66e0cb83315750" const OPENCODE_PROJECT_ID = "4b0ea68d7af9a6031a7ffda7ad66e0cb83315750"
export function getProjectAvatarSource(id?: string, icon?: { color?: string; url?: string; override?: string }) {
return id === OPENCODE_PROJECT_ID
? "https://opencode.ai/favicon.svg"
: (icon?.override ?? (icon?.color ? undefined : icon?.url))
}
export const ProjectIcon = (props: { project: LocalProject; class?: string; notify?: boolean }): JSX.Element => { export const ProjectIcon = (props: { project: LocalProject; class?: string; notify?: boolean }): JSX.Element => {
const globalSync = useGlobalSync() const globalSync = useGlobalSync()
const notification = useNotification() const notification = useNotification()
@@ -42,9 +48,7 @@ export const ProjectIcon = (props: { project: LocalProject; class?: string; noti
<div class="size-full rounded overflow-clip"> <div class="size-full rounded overflow-clip">
<Avatar <Avatar
fallback={name()} fallback={name()}
src={ src={getProjectAvatarSource(props.project.id, props.project.icon)}
props.project.id === OPENCODE_PROJECT_ID ? "https://opencode.ai/favicon.svg" : props.project.icon?.override
}
{...getAvatarColors(props.project.icon?.color)} {...getAvatarColors(props.project.icon?.color)}
class="size-full rounded" class="size-full rounded"
classList={{ "badge-mask": notify() }} classList={{ "badge-mask": notify() }}
@@ -263,10 +267,10 @@ export const SessionItem = (props: SessionItemProps): JSX.Element => {
</Show> </Show>
</div> </div>
</div> </div>
<Show when={currentChild()}> <Show when={currentChild()} keyed>
{(child) => ( {(child) => (
<div class="w-full"> <div class="w-full">
<SessionItem {...props} session={child()} level={(props.level ?? 0) + 1} /> <SessionItem {...props} session={child} level={(props.level ?? 0) + 1} />
</div> </div>
)} )}
</Show> </Show>
@@ -1,6 +1,6 @@
import { createMemo, For, Show, type Accessor, type JSX } from "solid-js" import { createMemo, For, Show, type Accessor, type JSX } from "solid-js"
import { createStore } from "solid-js/store" import { createStore } from "solid-js/store"
import { base64Encode } from "@opencode-ai/shared/util/encode" import { base64Encode } from "@opencode-ai/core/util/encode"
import { Button } from "@opencode-ai/ui/button" import { Button } from "@opencode-ai/ui/button"
import { ContextMenu } from "@opencode-ai/ui/context-menu" import { ContextMenu } from "@opencode-ai/ui/context-menu"
import { HoverCard } from "@opencode-ai/ui/hover-card" import { HoverCard } from "@opencode-ai/ui/hover-card"
@@ -3,8 +3,8 @@ import { createEffect, createMemo, For, Show, type Accessor, type JSX } from "so
import { createStore } from "solid-js/store" import { createStore } from "solid-js/store"
import { createSortable } from "@thisbeyond/solid-dnd" import { createSortable } from "@thisbeyond/solid-dnd"
import { createMediaQuery } from "@solid-primitives/media" import { createMediaQuery } from "@solid-primitives/media"
import { base64Encode } from "@opencode-ai/shared/util/encode" import { base64Encode } from "@opencode-ai/core/util/encode"
import { getFilename } from "@opencode-ai/shared/util/path" import { getFilename } from "@opencode-ai/core/util/path"
import { Button } from "@opencode-ai/ui/button" import { Button } from "@opencode-ai/ui/button"
import { Collapsible } from "@opencode-ai/ui/collapsible" import { Collapsible } from "@opencode-ai/ui/collapsible"
import { DropdownMenu } from "@opencode-ai/ui/dropdown-menu" import { DropdownMenu } from "@opencode-ai/ui/dropdown-menu"
@@ -14,10 +14,11 @@ import { Spinner } from "@opencode-ai/ui/spinner"
import { Tooltip } from "@opencode-ai/ui/tooltip" import { Tooltip } from "@opencode-ai/ui/tooltip"
import { type Session } from "@opencode-ai/sdk/v2/client" import { type Session } from "@opencode-ai/sdk/v2/client"
import { type LocalProject } from "@/context/layout" import { type LocalProject } from "@/context/layout"
import { useGlobalSync } from "@/context/global-sync" import { loadSessionsQuery, useGlobalSync } from "@/context/global-sync"
import { useLanguage } from "@/context/language" import { useLanguage } from "@/context/language"
import { NewSessionItem, SessionItem, SessionSkeleton } from "./sidebar-items" import { NewSessionItem, SessionItem, SessionSkeleton } from "./sidebar-items"
import { sortedRootSessions, workspaceKey } from "./helpers" import { sortedRootSessions, workspaceKey } from "./helpers"
import { useQuery } from "@tanstack/solid-query"
type InlineEditorComponent = (props: { type InlineEditorComponent = (props: {
id: string id: string
@@ -277,7 +278,7 @@ const WorkspaceSessionList = (props: {
class="flex w-full text-left justify-start text-14-regular text-text-weak pl-2 pr-10" class="flex w-full text-left justify-start text-14-regular text-text-weak pl-2 pr-10"
size="large" size="large"
onClick={(e: MouseEvent) => { onClick={(e: MouseEvent) => {
props.loadMore() void props.loadMore()
;(e.currentTarget as HTMLButtonElement).blur() ;(e.currentTarget as HTMLButtonElement).blur()
}} }}
> >
@@ -316,12 +317,11 @@ export const SortableWorkspace = (props: {
}) })
const open = createMemo(() => props.ctx.workspaceExpanded(props.directory, local())) const open = createMemo(() => props.ctx.workspaceExpanded(props.directory, local()))
const boot = createMemo(() => open() || active()) const boot = createMemo(() => open() || active())
const booted = createMemo((prev) => prev || workspaceStore.status === "complete", false)
const count = createMemo(() => sessions()?.length ?? 0) const count = createMemo(() => sessions()?.length ?? 0)
const hasMore = createMemo(() => workspaceStore.sessionTotal > count()) const hasMore = createMemo(() => workspaceStore.sessionTotal > count())
const query = useQuery(() => ({ ...loadSessionsQuery(props.project.worktree) }))
const busy = createMemo(() => props.ctx.isBusy(props.directory)) const busy = createMemo(() => props.ctx.isBusy(props.directory))
const wasBusy = createMemo((prev) => prev || busy(), false) const loading = () => query.isLoading && count() === 0
const loading = createMemo(() => open() && !booted() && count() === 0 && !wasBusy())
const touch = createMediaQuery("(hover: none)") const touch = createMediaQuery("(hover: none)")
const showNew = createMemo(() => !loading() && (touch() || count() === 0 || (active() && !params.id))) const showNew = createMemo(() => !loading() && (touch() || count() === 0 || (active() && !params.id)))
const loadMore = async () => { const loadMore = async () => {
@@ -426,7 +426,7 @@ export const SortableWorkspace = (props: {
mobile={props.mobile} mobile={props.mobile}
ctx={props.ctx} ctx={props.ctx}
showNew={showNew} showNew={showNew}
loading={loading} loading={() => query.isLoading && count() === 0}
sessions={sessions} sessions={sessions}
hasMore={hasMore} hasMore={hasMore}
loadMore={loadMore} loadMore={loadMore}
@@ -452,10 +452,10 @@ export const LocalWorkspace = (props: {
}) })
const slug = createMemo(() => base64Encode(props.project.worktree)) const slug = createMemo(() => base64Encode(props.project.worktree))
const sessions = createMemo(() => sortedRootSessions(workspace().store, props.sortNow())) const sessions = createMemo(() => sortedRootSessions(workspace().store, props.sortNow()))
const booted = createMemo((prev) => prev || workspace().store.status === "complete", false)
const count = createMemo(() => sessions()?.length ?? 0) const count = createMemo(() => sessions()?.length ?? 0)
const loading = createMemo(() => !booted() && count() === 0) const query = useQuery(() => ({ ...loadSessionsQuery(props.project.worktree) }))
const hasMore = createMemo(() => workspace().store.sessionTotal > count()) const hasMore = createMemo(() => workspace().store.sessionTotal > count())
const loading = () => query.isLoading && count() === 0
const loadMore = async () => { const loadMore = async () => {
workspace().setStore("limit", (limit) => (limit ?? 0) + 5) workspace().setStore("limit", (limit) => (limit ?? 0) + 5)
await globalSync.project.loadSessions(props.project.worktree) await globalSync.project.loadSessions(props.project.worktree)
+56 -146
View File
@@ -1,6 +1,6 @@
import type { Project, UserMessage, VcsFileDiff } from "@opencode-ai/sdk/v2" import type { Project, UserMessage } from "@opencode-ai/sdk/v2"
import { useDialog } from "@opencode-ai/ui/context/dialog" import { useDialog } from "@opencode-ai/ui/context/dialog"
import { useMutation } from "@tanstack/solid-query" import { createQuery, skipToken, useMutation, useQueryClient } from "@tanstack/solid-query"
import { import {
batch, batch,
onCleanup, onCleanup,
@@ -13,6 +13,7 @@ import {
on, on,
onMount, onMount,
untrack, untrack,
createResource,
} from "solid-js" } from "solid-js"
import { makeEventListener } from "@solid-primitives/event-listener" import { makeEventListener } from "@solid-primitives/event-listener"
import { createMediaQuery } from "@solid-primitives/media" import { createMediaQuery } from "@solid-primitives/media"
@@ -27,7 +28,7 @@ import { createAutoScroll } from "@opencode-ai/ui/hooks"
import { previewSelectedLines } from "@opencode-ai/ui/pierre/selection-bridge" import { previewSelectedLines } from "@opencode-ai/ui/pierre/selection-bridge"
import { Button } from "@opencode-ai/ui/button" import { Button } from "@opencode-ai/ui/button"
import { showToast } from "@opencode-ai/ui/toast" import { showToast } from "@opencode-ai/ui/toast"
import { checksum } from "@opencode-ai/shared/util/encode" import { checksum } from "@opencode-ai/core/util/encode"
import { useSearchParams } from "@solidjs/router" import { useSearchParams } from "@solidjs/router"
import { NewSessionView, SessionHeader } from "@/components/session" import { NewSessionView, SessionHeader } from "@/components/session"
import { useComments } from "@/context/comments" import { useComments } from "@/context/comments"
@@ -323,6 +324,7 @@ export default function Page() {
const local = useLocal() const local = useLocal()
const file = useFile() const file = useFile()
const sync = useSync() const sync = useSync()
const queryClient = useQueryClient()
const dialog = useDialog() const dialog = useDialog()
const language = useLanguage() const language = useLanguage()
const sdk = useSDK() const sdk = useSDK()
@@ -432,8 +434,6 @@ export default function Page() {
const info = createMemo(() => (params.id ? sync.session.get(params.id) : undefined)) const info = createMemo(() => (params.id ? sync.session.get(params.id) : undefined))
const isChildSession = createMemo(() => !!info()?.parentID) const isChildSession = createMemo(() => !!info()?.parentID)
const diffs = createMemo(() => (params.id ? list(sync.data.session_diff[params.id]) : [])) const diffs = createMemo(() => (params.id ? list(sync.data.session_diff[params.id]) : []))
const sessionCount = createMemo(() => Math.max(info()?.summary?.files ?? 0, diffs().length))
const hasSessionReview = createMemo(() => sessionCount() > 0)
const canReview = createMemo(() => !!sync.project) const canReview = createMemo(() => !!sync.project)
const reviewTab = createMemo(() => isDesktop()) const reviewTab = createMemo(() => isDesktop())
const tabState = createSessionTabs({ const tabState = createSessionTabs({
@@ -443,8 +443,6 @@ export default function Page() {
review: reviewTab, review: reviewTab,
hasReview: canReview, hasReview: canReview,
}) })
const contextOpen = tabState.contextOpen
const openedTabs = tabState.openedTabs
const activeTab = tabState.activeTab const activeTab = tabState.activeTab
const activeFileTab = tabState.activeFileTab const activeFileTab = tabState.activeFileTab
const revertMessageID = createMemo(() => info()?.revert?.messageID) const revertMessageID = createMemo(() => info()?.revert?.messageID)
@@ -487,7 +485,7 @@ export default function Page() {
if (!tab) return if (!tab) return
const path = file.pathFromTab(tab) const path = file.pathFromTab(tab)
if (path) file.load(path) if (path) void file.load(path)
}) })
createEffect( createEffect(
@@ -521,26 +519,6 @@ export default function Page() {
deferRender: false, deferRender: false,
}) })
const [vcs, setVcs] = createStore<{
diff: {
git: VcsFileDiff[]
branch: VcsFileDiff[]
}
ready: {
git: boolean
branch: boolean
}
}>({
diff: {
git: [] as VcsFileDiff[],
branch: [] as VcsFileDiff[],
},
ready: {
git: false,
branch: false,
},
})
const [followup, setFollowup] = persisted( const [followup, setFollowup] = persisted(
Persist.workspace(sdk.directory, "followup", ["followup.v1"]), Persist.workspace(sdk.directory, "followup", ["followup.v1"]),
createStore<{ createStore<{
@@ -574,68 +552,6 @@ export default function Page() {
let todoTimer: number | undefined let todoTimer: number | undefined
let diffFrame: number | undefined let diffFrame: number | undefined
let diffTimer: number | undefined let diffTimer: number | undefined
const vcsTask = new Map<VcsMode, Promise<void>>()
const vcsRun = new Map<VcsMode, number>()
const bumpVcs = (mode: VcsMode) => {
const next = (vcsRun.get(mode) ?? 0) + 1
vcsRun.set(mode, next)
return next
}
const resetVcs = (mode?: VcsMode) => {
const list = mode ? [mode] : (["git", "branch"] as const)
list.forEach((item) => {
bumpVcs(item)
vcsTask.delete(item)
setVcs("diff", item, [])
setVcs("ready", item, false)
})
}
const loadVcs = (mode: VcsMode, force = false) => {
if (sync.project?.vcs !== "git") return Promise.resolve()
if (!force && vcs.ready[mode]) return Promise.resolve()
if (force) {
if (vcsTask.has(mode)) bumpVcs(mode)
vcsTask.delete(mode)
setVcs("ready", mode, false)
}
const current = vcsTask.get(mode)
if (current) return current
const run = bumpVcs(mode)
const task = sdk.client.vcs
.diff({ mode })
.then((result) => {
if (vcsRun.get(mode) !== run) return
setVcs("diff", mode, list(result.data))
setVcs("ready", mode, true)
})
.catch((error) => {
if (vcsRun.get(mode) !== run) return
console.debug("[session-review] failed to load vcs diff", { mode, error })
setVcs("diff", mode, [])
setVcs("ready", mode, true)
})
.finally(() => {
if (vcsTask.get(mode) === task) vcsTask.delete(mode)
})
vcsTask.set(mode, task)
return task
}
const refreshVcs = () => {
resetVcs()
const mode = untrack(vcsMode)
if (!mode) return
if (!untrack(wantsReview)) return
void loadVcs(mode, true)
}
createComputed((prev) => { createComputed((prev) => {
const open = desktopReviewOpen() const open = desktopReviewOpen()
@@ -666,21 +582,52 @@ export default function Page() {
list.push("turn") list.push("turn")
return list return list
}) })
const mobileChanges = createMemo(() => !isDesktop() && store.mobileTab === "changes")
const wantsReview = createMemo(() =>
isDesktop()
? desktopFileTreeOpen() || (desktopReviewOpen() && activeTab() === "review")
: store.mobileTab === "changes",
)
const vcsMode = createMemo<VcsMode | undefined>(() => { const vcsMode = createMemo<VcsMode | undefined>(() => {
if (store.changes === "git" || store.changes === "branch") return store.changes if (store.changes === "git" || store.changes === "branch") return store.changes
}) })
const reviewDiffs = createMemo(() => { const vcsKey = createMemo(
if (store.changes === "git") return list(vcs.diff.git) () => ["session-vcs", sdk.directory, sync.data.vcs?.branch ?? "", sync.data.vcs?.default_branch ?? ""] as const,
if (store.changes === "branch") return list(vcs.diff.branch) )
const vcsQuery = createQuery(() => {
const mode = vcsMode()
const enabled = wantsReview() && sync.project?.vcs === "git"
return {
queryKey: [...vcsKey(), mode] as const,
enabled,
staleTime: Number.POSITIVE_INFINITY,
gcTime: 60 * 1000,
queryFn: mode
? () =>
sdk.client.vcs
.diff({ mode })
.then((result) => list(result.data))
.catch((error) => {
console.debug("[session-review] failed to load vcs diff", { mode, error })
return []
})
: skipToken,
}
})
const refreshVcs = () => void queryClient.invalidateQueries({ queryKey: vcsKey() })
const reviewDiffs = () => {
if (store.changes === "git" || store.changes === "branch")
// avoids suspense
return vcsQuery.isFetched ? (vcsQuery.data ?? []) : []
return turnDiffs() return turnDiffs()
}) }
const reviewCount = createMemo(() => reviewDiffs().length) const reviewCount = () => reviewDiffs().length
const hasReview = createMemo(() => reviewCount() > 0) const hasReview = () => reviewCount() > 0
const reviewReady = createMemo(() => { const reviewReady = () => {
if (store.changes === "git") return vcs.ready.git if (store.changes === "git" || store.changes === "branch") return !vcsQuery.isPending
if (store.changes === "branch") return vcs.ready.branch
return true return true
}) }
const newSessionWorktree = createMemo(() => { const newSessionWorktree = createMemo(() => {
if (store.newSessionWorktree === "create") return "create" if (store.newSessionWorktree === "create") return "create"
@@ -808,8 +755,9 @@ export default function Page() {
const hasScrollGesture = () => Date.now() - ui.scrollGesture < scrollGestureWindowMs const hasScrollGesture = () => Date.now() - ui.scrollGesture < scrollGestureWindowMs
createEffect( const [sessionSync] = createResource(
on([() => sdk.directory, () => params.id] as const, ([, id]) => { () => [sdk.directory, params.id] as const,
([directory, id]) => {
if (refreshFrame !== undefined) cancelAnimationFrame(refreshFrame) if (refreshFrame !== undefined) cancelAnimationFrame(refreshFrame)
if (refreshTimer !== undefined) window.clearTimeout(refreshTimer) if (refreshTimer !== undefined) window.clearTimeout(refreshTimer)
refreshFrame = undefined refreshFrame = undefined
@@ -820,13 +768,10 @@ export default function Page() {
const stale = !cached const stale = !cached
? false ? false
: (() => { : (() => {
const info = getSessionPrefetch(sdk.directory, id) const info = getSessionPrefetch(directory, id)
if (!info) return true if (!info) return true
return Date.now() - info.at > SESSION_PREFETCH_TTL return Date.now() - info.at > SESSION_PREFETCH_TTL
})() })()
untrack(() => {
void sync.session.sync(id)
})
refreshFrame = requestAnimationFrame(() => { refreshFrame = requestAnimationFrame(() => {
refreshFrame = undefined refreshFrame = undefined
@@ -838,7 +783,9 @@ export default function Page() {
}) })
}, 0) }, 0)
}) })
}),
return sync.session.sync(id)
},
) )
createEffect( createEffect(
@@ -900,27 +847,6 @@ export default function Page() {
), ),
) )
createEffect(
on(
() => sdk.directory,
() => {
resetVcs()
},
{ defer: true },
),
)
createEffect(
on(
() => [sync.data.vcs?.branch, sync.data.vcs?.default_branch] as const,
(next, prev) => {
if (prev === undefined || same(next, prev)) return
refreshVcs()
},
{ defer: true },
),
)
const stopVcs = sdk.event.listen((evt) => { const stopVcs = sdk.event.listen((evt) => {
if (evt.details.type !== "file.watcher.updated") return if (evt.details.type !== "file.watcher.updated") return
const props = const props =
@@ -1054,13 +980,6 @@ export default function Page() {
} }
} }
const mobileChanges = createMemo(() => !isDesktop() && store.mobileTab === "changes")
const wantsReview = createMemo(() =>
isDesktop()
? desktopFileTreeOpen() || (desktopReviewOpen() && activeTab() === "review")
: store.mobileTab === "changes",
)
createEffect(() => { createEffect(() => {
const list = changesOptions() const list = changesOptions()
if (list.includes(store.changes)) return if (list.includes(store.changes)) return
@@ -1069,22 +988,12 @@ export default function Page() {
setStore("changes", next) setStore("changes", next)
}) })
createEffect(() => {
const mode = vcsMode()
if (!mode) return
if (!wantsReview()) return
void loadVcs(mode)
})
createEffect( createEffect(
on( on(
() => sync.data.session_status[params.id ?? ""]?.type, () => sync.data.session_status[params.id ?? ""]?.type,
(next, prev) => { (next, prev) => {
const mode = vcsMode()
if (!mode) return
if (!wantsReview()) return
if (next !== "idle" || prev === undefined || prev === "idle") return if (next !== "idle" || prev === undefined || prev === "idle") return
void loadVcs(mode, true) refreshVcs()
}, },
{ defer: true }, { defer: true },
), ),
@@ -1885,6 +1794,7 @@ export default function Page() {
return ( return (
<div class="relative bg-background-base size-full overflow-hidden flex flex-col"> <div class="relative bg-background-base size-full overflow-hidden flex flex-col">
{sessionSync() ?? ""}
<SessionHeader /> <SessionHeader />
<div class="flex-1 min-h-0 flex flex-col md:flex-row"> <div class="flex-1 min-h-0 flex flex-col md:flex-row">
<Show when={!isDesktop() && !!params.id}> <Show when={!isDesktop() && !!params.id}>
+1 -7
View File
@@ -6,7 +6,7 @@ import type { FileSearchHandle } from "@opencode-ai/ui/file"
import { useFileComponent } from "@opencode-ai/ui/context/file" import { useFileComponent } from "@opencode-ai/ui/context/file"
import { cloneSelectedLineRange, previewSelectedLines } from "@opencode-ai/ui/pierre/selection-bridge" import { cloneSelectedLineRange, previewSelectedLines } from "@opencode-ai/ui/pierre/selection-bridge"
import { createLineCommentController } from "@opencode-ai/ui/line-comment-annotations" import { createLineCommentController } from "@opencode-ai/ui/line-comment-annotations"
import { sampledChecksum } from "@opencode-ai/shared/util/encode" import { sampledChecksum } from "@opencode-ai/core/util/encode"
import { DropdownMenu } from "@opencode-ai/ui/dropdown-menu" import { DropdownMenu } from "@opencode-ai/ui/dropdown-menu"
import { IconButton } from "@opencode-ai/ui/icon-button" import { IconButton } from "@opencode-ai/ui/icon-button"
import { Tabs } from "@opencode-ai/ui/tabs" import { Tabs } from "@opencode-ai/ui/tabs"
@@ -378,12 +378,6 @@ export function FileTabContent(props: { tab: string }) {
requestAnimationFrame(() => comments.clearFocus()) requestAnimationFrame(() => comments.clearFocus())
}) })
const cancelCommenting = () => {
const p = path()
if (p) file.setSelectedLines(p, null)
setNote("commenting", null)
}
let prev = { let prev = {
loaded: false, loaded: false,
ready: false, ready: false,
+1 -1
View File
@@ -117,7 +117,7 @@ export const createOpenReviewFile = (input: {
input.openTab(tab) input.openTab(tab)
input.setActive(tab) input.setActive(tab)
} }
if (maybePromise instanceof Promise) maybePromise.then(open) if (maybePromise instanceof Promise) void maybePromise.then(open)
else open() else open()
}) })
} }

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